diff --git a/cbits/coin/AbcCommon.hpp b/cbits/coin/AbcCommon.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/AbcCommon.hpp
@@ -0,0 +1,62 @@
+/* $Id: AbcCommon.hpp 1910 2013-01-27 02:00:13Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others, Copyright (C) 2012, FasterCoin.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef AbcCommon_H
+#define AbcCommon_H
+
+#include "ClpConfig.h"
+
+/*
+  0 - off
+  1 - build Abc serial but no inherit code
+  2 - build Abc serial and inherit code
+  3 - build Abc cilk parallel but no inherit code
+  4 - build Abc cilk parallel and inherit code
+ */
+#ifdef CLP_HAS_ABC
+#if CLP_HAS_ABC==1
+#ifndef ABC_PARALLEL
+#define ABC_PARALLEL 0
+#endif
+#ifndef ABC_USE_HOMEGROWN_LAPACK
+#define ABC_USE_HOMEGROWN_LAPACK 2
+#endif
+#elif CLP_HAS_ABC==2
+#ifndef ABC_PARALLEL
+#define ABC_PARALLEL 0
+#endif
+#ifndef ABC_USE_HOMEGROWN_LAPACK
+#define ABC_USE_HOMEGROWN_LAPACK 2
+#endif
+#ifndef ABC_INHERIT
+#define ABC_INHERIT
+#endif
+#elif CLP_HAS_ABC==3
+#ifndef ABC_PARALLEL
+#define ABC_PARALLEL 2
+#endif
+#ifndef ABC_USE_HOMEGROWN_LAPACK
+#define ABC_USE_HOMEGROWN_LAPACK 2
+#endif
+#elif CLP_HAS_ABC==4
+#ifndef ABC_PARALLEL
+#define ABC_PARALLEL 2
+#endif
+#ifndef ABC_USE_HOMEGROWN_LAPACK
+#define ABC_USE_HOMEGROWN_LAPACK 2
+#endif
+#ifndef ABC_INHERIT
+#define ABC_INHERIT
+#endif
+#else
+#error "Valid values for CLP_HAS_ABC are 0-4"
+#endif
+#endif
+#endif
diff --git a/cbits/coin/CbcBranchActual.hpp b/cbits/coin/CbcBranchActual.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchActual.hpp
@@ -0,0 +1,24 @@
+/* $Id: CbcBranchActual.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcBranchActual_H
+#define CbcBranchActual_H
+
+#include "CbcBranchBase.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CbcClique.hpp"
+#include "CbcSOS.hpp"
+#include "CbcSimpleInteger.hpp"
+#include "CbcNWay.hpp"
+#include "CbcSimpleIntegerPseudoCost.hpp"
+#include "CbcBranchDefaultDecision.hpp"
+#include "CbcFollowOn.hpp"
+#include "CbcFixVariable.hpp"
+#include "CbcDummyBranchingObject.hpp"
+#include "CbcGeneral.hpp"
+#include "CbcGeneralDepth.hpp"
+#include "CbcSubProblem.hpp"
+#endif
+
diff --git a/cbits/coin/CbcBranchAllDifferent.cpp b/cbits/coin/CbcBranchAllDifferent.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchAllDifferent.cpp
@@ -0,0 +1,156 @@
+// $Id: CbcBranchAllDifferent.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/13/2009-- carved out of CbcBranchCut
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchCut.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+#include "CbcBranchAllDifferent.hpp"
+
+/** Default Constructor
+*/
+CbcBranchAllDifferent::CbcBranchAllDifferent ()
+        : CbcBranchCut(),
+        numberInSet_(0),
+        which_(NULL)
+{
+}
+
+/* Useful constructor - passed set of variables
+*/
+CbcBranchAllDifferent::CbcBranchAllDifferent (CbcModel * model, int numberInSet,
+        const int * members)
+        : CbcBranchCut(model)
+{
+    numberInSet_ = numberInSet;
+    which_ = CoinCopyOfArray(members, numberInSet_);
+}
+// Copy constructor
+CbcBranchAllDifferent::CbcBranchAllDifferent ( const CbcBranchAllDifferent & rhs)
+        : CbcBranchCut(rhs)
+{
+    numberInSet_ = rhs.numberInSet_;
+    which_ = CoinCopyOfArray(rhs.which_, numberInSet_);
+}
+
+// Clone
+CbcObject *
+CbcBranchAllDifferent::clone() const
+{
+    return new CbcBranchAllDifferent(*this);
+}
+
+// Assignment operator
+CbcBranchAllDifferent &
+CbcBranchAllDifferent::operator=( const CbcBranchAllDifferent & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchCut::operator=(rhs);
+        delete [] which_;
+        numberInSet_ = rhs.numberInSet_;
+        which_ = CoinCopyOfArray(rhs.which_, numberInSet_);
+    }
+    return *this;
+}
+
+// Destructor
+CbcBranchAllDifferent::~CbcBranchAllDifferent ()
+{
+    delete [] which_;
+}
+CbcBranchingObject *
+CbcBranchAllDifferent::createCbcBranch(OsiSolverInterface * /*solver*/
+                                       , const OsiBranchingInformation * /*info*/,
+                                       int /*way*/)
+{
+    // by default way must be -1
+    //assert (way==-1);
+    const double * solution = model_->testSolution();
+    double * values = new double[numberInSet_];
+    int * which = new int[numberInSet_];
+    int i;
+    for (i = 0; i < numberInSet_; i++) {
+        int iColumn = which_[i];
+        values[i] = solution[iColumn];
+        which[i] = iColumn;
+    }
+    CoinSort_2(values, values + numberInSet_, which);
+    double last = -1.0;
+    double closest = 1.0;
+    int worst = -1;
+    for (i = 0; i < numberInSet_; i++) {
+        if (values[i] - last < closest) {
+            closest = values[i] - last;
+            worst = i - 1;
+        }
+        last = values[i];
+    }
+    assert (closest <= 0.99999);
+    OsiRowCut down;
+    down.setLb(-COIN_DBL_MAX);
+    down.setUb(-1.0);
+    int pair[2];
+    double elements[] = {1.0, -1.0};
+    pair[0] = which[worst];
+    pair[1] = which[worst+1];
+    delete [] values;
+    delete [] which;
+    down.setRow(2, pair, elements);
+    // up is same - just with rhs changed
+    OsiRowCut up = down;
+    up.setLb(1.0);
+    up.setUb(COIN_DBL_MAX);
+    // Say is not a fix type branch
+    CbcCutBranchingObject * newObject =
+        new CbcCutBranchingObject(model_, down, up, false);
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("creating cut in CbcBranchCut\n");
+    return newObject;
+}
+double
+CbcBranchAllDifferent::infeasibility(const OsiBranchingInformation * /*info*/,
+                                     int &preferredWay) const
+{
+    preferredWay = -1;
+    //OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    //const double * lower = solver->getColLower();
+    //const double * upper = solver->getColUpper();
+    double * values = new double[numberInSet_];
+    int i;
+    for (i = 0; i < numberInSet_; i++) {
+        int iColumn = which_[i];
+        values[i] = solution[iColumn];
+    }
+    std::sort(values, values + numberInSet_);
+    double last = -1.0;
+    double closest = 1.0;
+    for (i = 0; i < numberInSet_; i++) {
+        if (values[i] - last < closest) {
+            closest = values[i] - last;
+        }
+        last = values[i];
+    }
+    delete [] values;
+    if (closest > 0.99999)
+        return 0.0;
+    else
+        return 0.5*(1.0 - closest);
+}
+
diff --git a/cbits/coin/CbcBranchAllDifferent.hpp b/cbits/coin/CbcBranchAllDifferent.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchAllDifferent.hpp
@@ -0,0 +1,62 @@
+// $Id: CbcBranchAllDifferent.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/13/2009-- carved out of CbcBranchCut
+
+#ifndef CbcBranchAllDifferent_H
+#define CbcBranchAllDifferent_H
+
+#include "CbcBranchBase.hpp"
+#include "OsiRowCut.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CbcBranchCut.hpp"
+
+/** Define a branch class that branches so that it is only satsified if all
+    members have different values
+    So cut is x <= y-1 or x >= y+1
+*/
+
+
+class CbcBranchAllDifferent : public CbcBranchCut {
+
+public:
+
+    // Default Constructor
+    CbcBranchAllDifferent ();
+
+    /** Useful constructor - passed set of integer variables which must all be different
+    */
+    CbcBranchAllDifferent (CbcModel * model, int number, const int * which);
+
+    // Copy constructor
+    CbcBranchAllDifferent ( const CbcBranchAllDifferent &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcBranchAllDifferent & operator=( const CbcBranchAllDifferent& rhs);
+
+    // Destructor
+    ~CbcBranchAllDifferent ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+
+
+protected:
+    /// data
+
+    /// Number of entries
+    int numberInSet_;
+    /// Which variables
+    int * which_;
+};
+#endif
+
diff --git a/cbits/coin/CbcBranchBase.hpp b/cbits/coin/CbcBranchBase.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchBase.hpp
@@ -0,0 +1,78 @@
+/* $Id: CbcBranchBase.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcBranchBase_H
+#define CbcBranchBase_H
+
+#include <string>
+#include <vector>
+#include "OsiBranchingObject.hpp"
+
+enum CbcRangeCompare {
+    CbcRangeSame,
+    CbcRangeDisjoint,
+    CbcRangeSubset,
+    CbcRangeSuperset,
+    CbcRangeOverlap
+};
+
+#include "CbcObject.hpp"
+#include "CbcBranchingObject.hpp"
+#include "CbcBranchDecision.hpp"
+#include "CbcConsequence.hpp"
+#include "CbcObjectUpdateData.hpp"
+
+//##############################################################################
+
+/** Compare two ranges. The two bounds arrays are both of size two and
+    describe closed intervals. Return the appropriate CbcRangeCompare value
+    (first argument being the sub/superset if that's the case). In case of
+    overlap (and if \c replaceIfOverlap is true) replace the content of thisBd
+    with the intersection of the ranges.
+*/
+static inline CbcRangeCompare
+CbcCompareRanges(double* thisBd, const double* otherBd,
+                 const bool replaceIfOverlap)
+{
+    const double lbDiff = thisBd[0] - otherBd[0];
+    if (lbDiff < 0) { // lb of this < lb of other
+        if (thisBd[1] >= otherBd[1]) { // ub of this >= ub of other
+            return CbcRangeSuperset;
+        } else if (thisBd[1] < otherBd[0]) {
+            return CbcRangeDisjoint;
+        } else {
+            // overlap
+            if (replaceIfOverlap) {
+                thisBd[0] = otherBd[0];
+            }
+            return CbcRangeOverlap;
+        }
+    } else if (lbDiff > 0) { // lb of this > lb of other
+        if (thisBd[1] <= otherBd[1]) { // ub of this <= ub of other
+            return CbcRangeSubset;
+        } else if (thisBd[0] > otherBd[1]) {
+            return CbcRangeDisjoint;
+        } else {
+            // overlap
+            if (replaceIfOverlap) {
+                thisBd[1] = otherBd[1];
+            }
+            return CbcRangeOverlap;
+        }
+    } else { // lb of this == lb of other
+        if (thisBd[1] == otherBd[1]) {
+            return CbcRangeSame;
+        }
+        return thisBd[1] < otherBd[1] ? CbcRangeSubset : CbcRangeSuperset;
+    }
+
+    return CbcRangeSame; // fake return
+
+}
+
+//#############################################################################
+
+#endif
+
diff --git a/cbits/coin/CbcBranchCut.cpp b/cbits/coin/CbcBranchCut.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchCut.cpp
@@ -0,0 +1,345 @@
+/* $Id: CbcBranchCut.cpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchCut.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+
+/** Default Constructor
+
+*/
+CbcBranchCut::CbcBranchCut ()
+        : CbcObject()
+{
+}
+
+/* Constructor so model can be passed up
+*/
+CbcBranchCut::CbcBranchCut (CbcModel * model)
+        : CbcObject(model)
+{
+}
+// Copy constructor
+CbcBranchCut::CbcBranchCut ( const CbcBranchCut & rhs)
+        : CbcObject(rhs)
+
+{
+}
+
+// Clone
+CbcObject *
+CbcBranchCut::clone() const
+{
+    return new CbcBranchCut(*this);
+}
+
+// Assignment operator
+CbcBranchCut &
+CbcBranchCut::operator=( const CbcBranchCut& /*rhs*/)
+{
+    return *this;
+}
+
+// Destructor
+CbcBranchCut::~CbcBranchCut ()
+{
+}
+double
+CbcBranchCut::infeasibility(const OsiBranchingInformation * /*info*/,
+                            int &preferredWay) const
+{
+    throw CoinError("Use of base class", "infeasibility", "CbcBranchCut");
+    preferredWay = -1;
+    return 0.0;
+}
+
+// This looks at solution and sets bounds to contain solution
+/** More precisely: it first forces the variable within the existing
+    bounds, and then tightens the bounds to fix the variable at the
+    nearest integer value.
+*/
+void
+CbcBranchCut::feasibleRegion()
+{
+}
+/* Return true if branch created by object should fix variables
+ */
+bool
+CbcBranchCut::boundBranch() const
+{
+    return false;
+}
+CbcBranchingObject *
+CbcBranchCut::createCbcBranch(OsiSolverInterface * /*solver*/, const OsiBranchingInformation * /*info*/, int /*way*/)
+{
+    throw CoinError("Use of base class", "createCbcBranch", "CbcBranchCut");
+    return new CbcCutBranchingObject();
+}
+
+
+/* Given valid solution (i.e. satisfied) and reduced costs etc
+   returns a branching object which would give a new feasible
+   point in direction reduced cost says would be cheaper.
+   If no feasible point returns null
+*/
+CbcBranchingObject *
+CbcBranchCut::preferredNewFeasible() const
+{
+    throw CoinError("Use of base class", "preferredNewFeasible", "CbcBranchCut");
+    return new CbcCutBranchingObject();
+}
+
+/* Given valid solution (i.e. satisfied) and reduced costs etc
+   returns a branching object which would give a new feasible
+   point in direction opposite to one reduced cost says would be cheaper.
+   If no feasible point returns null
+*/
+CbcBranchingObject *
+CbcBranchCut::notPreferredNewFeasible() const
+{
+    throw CoinError("Use of base class", "notPreferredNewFeasible", "CbcBranchCut");
+    return new CbcCutBranchingObject();
+}
+
+/*
+  Bounds may be tightened, so it may be good to be able to refresh the local
+  copy of the original bounds.
+ */
+void
+CbcBranchCut::resetBounds()
+{
+}
+
+// Default Constructor
+CbcCutBranchingObject::CbcCutBranchingObject()
+        : CbcBranchingObject()
+{
+    down_ = OsiRowCut();
+    up_ = OsiRowCut();
+    canFix_ = false;
+}
+
+// Useful constructor
+CbcCutBranchingObject::CbcCutBranchingObject (CbcModel * model,
+        OsiRowCut & down,
+        OsiRowCut &up,
+        bool canFix)
+        : CbcBranchingObject(model, 0, -1, 0.0)
+{
+    down_ = down;
+    up_ = up;
+    canFix_ = canFix;
+}
+
+// Copy constructor
+CbcCutBranchingObject::CbcCutBranchingObject ( const CbcCutBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+    down_ = rhs.down_;
+    up_ = rhs.up_;
+    canFix_ = rhs.canFix_;
+}
+
+// Assignment operator
+CbcCutBranchingObject &
+CbcCutBranchingObject::operator=( const CbcCutBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        down_ = rhs.down_;
+        up_ = rhs.up_;
+        canFix_ = rhs.canFix_;
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcCutBranchingObject::clone() const
+{
+    return (new CbcCutBranchingObject(*this));
+}
+
+
+// Destructor
+CbcCutBranchingObject::~CbcCutBranchingObject ()
+{
+}
+
+/*
+  Perform a branch by adjusting bounds and/or adding a cut. Note
+  that each arm of the branch advances the object to the next arm by
+  advancing the value of way_.
+
+  Returns change in guessed objective on next branch
+*/
+double
+CbcCutBranchingObject::branch()
+{
+    decrementNumberBranchesLeft();
+    OsiRowCut * cut;
+    if (way_ < 0) {
+        cut = &down_;
+        way_ = 1;
+    } else {
+        cut = &up_;
+        way_ = -1;	  // Swap direction
+    }
+    printf("CUT %s ", (way_ == -1) ? "up" : "down");
+    cut->print();
+    // See if cut just fixes variables
+    double lb = cut->lb();
+    double ub = cut->ub();
+    int n = cut->row().getNumElements();
+    const int * column = cut->row().getIndices();
+    const double * element = cut->row().getElements();
+    OsiSolverInterface * solver = model_->solver();
+    const double * upper = solver->getColUpper();
+    const double * lower = solver->getColLower();
+    double low = 0.0;
+    double high = 0.0;
+    for (int i = 0; i < n; i++) {
+        int iColumn = column[i];
+        double value = element[i];
+        if (value > 0.0) {
+            high += upper[iColumn] * value;
+            low += lower[iColumn] * value;
+        } else {
+            high += lower[iColumn] * value;
+            low += upper[iColumn] * value;
+        }
+    }
+    // leave as cut
+    //model_->setNextRowCut(*cut);
+    //return 0.0;
+    // assume cut was cunningly constructed so we need not worry too much about tolerances
+    if (low + 1.0e-8 >= ub && canFix_) {
+        // fix
+        for (int i = 0; i < n; i++) {
+            int iColumn = column[i];
+            double value = element[i];
+            if (value > 0.0) {
+                solver->setColUpper(iColumn, lower[iColumn]);
+            } else {
+                solver->setColLower(iColumn, upper[iColumn]);
+            }
+        }
+    } else if (high - 1.0e-8 <= lb && canFix_) {
+        // fix
+        for (int i = 0; i < n; i++) {
+            int iColumn = column[i];
+            double value = element[i];
+            if (value > 0.0) {
+                solver->setColLower(iColumn, upper[iColumn]);
+            } else {
+                solver->setColUpper(iColumn, lower[iColumn]);
+            }
+        }
+    } else {
+        // leave as cut
+        model_->setNextRowCut(*cut);
+    }
+    return 0.0;
+}
+// Print what would happen
+void
+CbcCutBranchingObject::print()
+{
+    OsiRowCut * cut;
+    if (way_ < 0) {
+        cut = &down_;
+        printf("CbcCut would branch down");
+    } else {
+        cut = &up_;
+        printf("CbcCut would branch up");
+    }
+    double lb = cut->lb();
+    double ub = cut->ub();
+    int n = cut->row().getNumElements();
+    const int * column = cut->row().getIndices();
+    const double * element = cut->row().getElements();
+    if (n > 5) {
+        printf(" - %d elements, lo=%g, up=%g\n", n, lb, ub);
+    } else {
+        printf(" - %g <=", lb);
+        for (int i = 0; i < n; i++) {
+            int iColumn = column[i];
+            double value = element[i];
+            printf(" (%d,%g)", iColumn, value);
+        }
+        printf(" <= %g\n", ub);
+    }
+}
+
+// Return true if branch should fix variables
+bool
+CbcCutBranchingObject::boundBranch() const
+{
+    return false;
+}
+
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcCutBranchingObject::compareOriginalObject
+(const CbcBranchingObject* brObj) const
+{
+    const CbcCutBranchingObject* br =
+        dynamic_cast<const CbcCutBranchingObject*>(brObj);
+    assert(br);
+    const OsiRowCut& r0 = way_ == -1 ? down_ : up_;
+    const OsiRowCut& r1 = br->way_ == -1 ? br->down_ : br->up_;
+    return r0.row().compare(r1.row());
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+
+CbcRangeCompare
+CbcCutBranchingObject::compareBranchingObject
+(const CbcBranchingObject* brObj, const bool replaceIfOverlap)
+{
+    const CbcCutBranchingObject* br =
+        dynamic_cast<const CbcCutBranchingObject*>(brObj);
+    assert(br);
+    OsiRowCut& r0 = way_ == -1 ? down_ : up_;
+    const OsiRowCut& r1 = br->way_ == -1 ? br->down_ : br->up_;
+    double thisBd[2];
+    thisBd[0] = r0.lb();
+    thisBd[1] = r0.ub();
+    double otherBd[2];
+    otherBd[0] = r1.lb();
+    otherBd[1] = r1.ub();
+    CbcRangeCompare comp = CbcCompareRanges(thisBd, otherBd, replaceIfOverlap);
+    if (comp != CbcRangeOverlap || (comp == CbcRangeOverlap && !replaceIfOverlap)) {
+        return comp;
+    }
+    r0.setLb(thisBd[0]);
+    r0.setUb(thisBd[1]);
+    return comp;
+}
+
diff --git a/cbits/coin/CbcBranchCut.hpp b/cbits/coin/CbcBranchCut.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchCut.hpp
@@ -0,0 +1,183 @@
+/* $Id: CbcBranchCut.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcBranchCut_H
+#define CbcBranchCut_H
+
+#include "CbcBranchBase.hpp"
+#include "OsiRowCut.hpp"
+#include "CoinPackedMatrix.hpp"
+
+/** Define a cut branching class.
+    At present empty - all stuff in descendants
+*/
+
+class CbcBranchCut : public CbcObject {
+
+public:
+
+    // Default Constructor
+    CbcBranchCut ();
+
+    /** In to maintain normal methods
+    */
+    CbcBranchCut (CbcModel * model);
+    // Copy constructor
+    CbcBranchCut ( const CbcBranchCut &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcBranchCut & operator=( const CbcBranchCut& rhs);
+
+    // Destructor
+    ~CbcBranchCut ();
+
+    /// Infeasibility
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /** Set bounds to contain the current solution.
+
+      More precisely, for the variable associated with this object, take the
+      value given in the current solution, force it within the current bounds
+      if required, then set the bounds to fix the variable at the integer
+      nearest the solution value.
+
+      At present this will do nothing
+    */
+    virtual void feasibleRegion();
+
+    /** \brief Return true if branch created by object should fix variables
+    */
+    virtual bool boundBranch() const ;
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+
+    /** \brief Given a valid solution (with reduced costs, etc.),
+        return a branching object which would give a new feasible
+        point in the good direction.
+
+      The preferred branching object will force the variable to be +/-1 from
+      its current value, depending on the reduced cost and objective sense.  If
+      movement in the direction which improves the objective is impossible due
+      to bounds on the variable, the branching object will move in the other
+      direction.  If no movement is possible, the method returns NULL.
+
+      Only the bounds on this variable are considered when determining if the new
+      point is feasible.
+
+      At present this does nothing
+    */
+    virtual CbcBranchingObject * preferredNewFeasible() const;
+
+    /** \brief Given a valid solution (with reduced costs, etc.),
+        return a branching object which would give a new feasible
+        point in a bad direction.
+
+      As for preferredNewFeasible(), but the preferred branching object will
+      force movement in a direction that degrades the objective.
+
+      At present this does nothing
+    */
+    virtual CbcBranchingObject * notPreferredNewFeasible() const ;
+
+    using CbcObject::resetBounds ;
+    /** Reset original upper and lower bound values from the solver.
+
+      Handy for updating bounds held in this object after bounds held in the
+      solver have been tightened.
+     */
+    virtual void resetBounds();
+
+
+protected:
+    /// data
+
+};
+/** Cut branching object
+
+  This object can specify a two-way branch in terms of two cuts
+*/
+
+class CbcCutBranchingObject : public CbcBranchingObject {
+
+public:
+
+    /// Default constructor
+    CbcCutBranchingObject ();
+
+    /** Create a cut branching object
+
+        Cut down will applied on way=-1, up on way==1
+        Assumed down will be first so way_ set to -1
+    */
+    CbcCutBranchingObject (CbcModel * model, OsiRowCut & down, OsiRowCut &up, bool canFix);
+
+    /// Copy constructor
+    CbcCutBranchingObject ( const CbcCutBranchingObject &);
+
+    /// Assignment operator
+    CbcCutBranchingObject & operator= (const CbcCutBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    /// Destructor
+    virtual ~CbcCutBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /** \brief Sets the bounds for variables or adds a cut depending on the
+               current arm of the branch and advances the object state to the next arm.
+           Returns change in guessed objective on next branch
+    */
+    virtual double branch();
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+
+    /** \brief Return true if branch should fix variables
+    */
+    virtual bool boundBranch() const;
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return CutBranchingObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+protected:
+    /// Cut for the down arm (way_ = -1)
+    OsiRowCut down_;
+    /// Cut for the up arm (way_ = 1)
+    OsiRowCut up_;
+    /// True if one way can fix variables
+    bool canFix_;
+};
+#endif
diff --git a/cbits/coin/CbcBranchDecision.cpp b/cbits/coin/CbcBranchDecision.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchDecision.cpp
@@ -0,0 +1,89 @@
+// $Id: CbcBranchDecision.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "OsiChooseVariable.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchBase.hpp"
+#include "CbcBranchDecision.hpp"
+
+// Default Constructor
+CbcBranchDecision::CbcBranchDecision ()
+        : object_(NULL), model_(NULL), chooseMethod_(NULL)
+{
+}
+
+// Copy Constructor
+CbcBranchDecision::CbcBranchDecision (const CbcBranchDecision &rhs)
+        : object_(NULL), model_(rhs.model_), chooseMethod_(NULL)
+{
+    if (rhs.chooseMethod_)
+        chooseMethod_ = rhs.chooseMethod_->clone();
+}
+
+CbcBranchDecision::~CbcBranchDecision()
+{
+    delete object_;
+    delete chooseMethod_;
+}
+/* Compare N branching objects. Return index of best
+   and sets way of branching in chosen object.
+
+   This routine is used only after strong branching.
+   This is reccommended version as it can be more sophisticated
+*/
+
+int
+CbcBranchDecision::bestBranch (CbcBranchingObject ** objects, int numberObjects,
+                               int /*numberUnsatisfied*/,
+                               double * changeUp, int * numberInfeasibilitiesUp,
+                               double * changeDown, int * numberInfeasibilitiesDown,
+                               double /*objectiveValue*/)
+{
+    int bestWay = 0;
+    int whichObject = -1;
+    if (numberObjects) {
+        initialize(objects[0]->model());
+        CbcBranchingObject * bestObject = NULL;
+        for (int i = 0 ; i < numberObjects ; i++) {
+            int betterWay = betterBranch(objects[i],
+                                         bestObject,
+                                         changeUp[i],
+                                         numberInfeasibilitiesUp [i],
+                                         changeDown[i],
+                                         numberInfeasibilitiesDown[i] );
+            if (betterWay) {
+                bestObject = objects[i];
+                bestWay = betterWay;
+                whichObject = i;
+            }
+        }
+        // set way in best
+        if (whichObject >= 0)
+            objects[whichObject]->way(bestWay);
+    }
+    return whichObject;
+}
+// Set (clone) chooseMethod
+void
+CbcBranchDecision::setChooseMethod(const OsiChooseVariable & method)
+{
+    delete chooseMethod_;
+    chooseMethod_ = method.clone();
+}
+
diff --git a/cbits/coin/CbcBranchDecision.hpp b/cbits/coin/CbcBranchDecision.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchDecision.hpp
@@ -0,0 +1,129 @@
+// $Id: CbcBranchDecision.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#ifndef CbcBranchDecision_H
+#define CbcBranchDecision_H
+
+#include "CbcBranchBase.hpp"
+
+/** Abstract branching decision base class
+
+  In the abstract, an CbcBranchDecision object is expected to be able to
+  compare two possible branching choices.
+
+  The #betterBranch() method is the crucial routine. It is expected to be able
+  to compare two \link CbcBranchingObject CbcBranchingObjects \endlink.
+
+  See CbcObject for an overview of the three classes (CbcObject,
+  CbcBranchingObject, and CbcBranchDecision) which make up cbc's branching
+  model.
+*/
+class CbcModel;
+class OsiChooseVariable;
+
+class CbcBranchDecision {
+public:
+    /// Default Constructor
+    CbcBranchDecision ();
+
+    // Copy constructor
+    CbcBranchDecision ( const CbcBranchDecision &);
+
+    /// Destructor
+    virtual ~CbcBranchDecision();
+
+/// Clone
+    virtual CbcBranchDecision * clone() const = 0;
+
+    /// Initialize <i>e.g.</i> before starting to choose a branch at a node
+    virtual void initialize(CbcModel * model) = 0;
+
+    /** \brief Compare two branching objects. Return nonzero if branching
+           using \p thisOne is better than branching using \p bestSoFar.
+
+      If \p bestSoFar is NULL, the routine should return a nonzero value.
+      This routine is used only after strong branching.
+      Either this or bestBranch is used depending which user wants.
+
+    */
+
+    virtual int
+    betterBranch (CbcBranchingObject * thisOne,
+                  CbcBranchingObject * bestSoFar,
+                  double changeUp, int numberInfeasibilitiesUp,
+                  double changeDown, int numberInfeasibilitiesDown) = 0 ;
+
+    /** \brief Compare N branching objects. Return index of best
+        and sets way of branching in chosen object.
+
+      Either this or betterBranch is used depending which user wants.
+    */
+
+    virtual int
+    bestBranch (CbcBranchingObject ** objects, int numberObjects, int numberUnsatisfied,
+                double * changeUp, int * numberInfeasibilitiesUp,
+                double * changeDown, int * numberInfeasibilitiesDown,
+                double objectiveValue) ;
+
+    /** Says whether this method can handle both methods -
+        1 better, 2 best, 3 both */
+    virtual int whichMethod() {
+        return 2;
+    }
+
+    /** Saves a clone of current branching object.  Can be used to update
+        information on object causing branch - after branch */
+    virtual void saveBranchingObject(OsiBranchingObject * ) {}
+    /** Pass in information on branch just done.
+        assumes object can get information from solver */
+    virtual void updateInformation(OsiSolverInterface * ,
+                                   const CbcNode * ) {}
+    /** Sets or gets best criterion so far */
+    virtual void setBestCriterion(double ) {}
+    virtual double getBestCriterion() const {
+        return 0.0;
+    }
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+    /// Model
+    inline CbcModel * cbcModel() const {
+        return model_;
+    }
+    /* If chooseMethod_ id non-null then the rest is fairly pointless
+       as choosemethod_ will be doing all work
+     This comment makes more sense if you realise that there's a conversion in
+     process from the Cbc branching classes to Osi branching classes. The test
+     for use of the Osi branching classes is CbcModel::branchingMethod_
+     non-null (i.e., it points to one of these CbcBranchDecision objects) and
+     that branch decision object has an OsiChooseVariable method set. In which
+     case, we'll use it, rather than the choose[*]Variable methods defined in
+     CbcNode.
+	*/
+
+    OsiChooseVariable * chooseMethod() const {
+        return chooseMethod_;
+    }
+    /// Set (clone) chooseMethod
+    void setChooseMethod(const OsiChooseVariable & method);
+
+protected:
+
+    // Clone of branching object
+    CbcBranchingObject * object_;
+    /// Pointer to model
+    CbcModel * model_;
+    /* If chooseMethod_ id non-null then the rest is fairly pointless
+       as choosemethod_ will be doing all work
+    */
+    OsiChooseVariable * chooseMethod_;
+private:
+    /// Assignment is illegal
+    CbcBranchDecision & operator=(const CbcBranchDecision& rhs);
+
+};
+#endif
+
diff --git a/cbits/coin/CbcBranchDefaultDecision.cpp b/cbits/coin/CbcBranchDefaultDecision.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchDefaultDecision.cpp
@@ -0,0 +1,442 @@
+// $Id: CbcBranchDefaultDecision.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchDefaultDecision.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+//##############################################################################
+
+// Default Constructor
+CbcBranchDefaultDecision::CbcBranchDefaultDecision()
+        : CbcBranchDecision()
+{
+    bestCriterion_ = 0.0;
+    bestChangeUp_ = 0.0;
+    bestNumberUp_ = 0;
+    bestChangeDown_ = 0.0;
+    bestObject_ = NULL;
+    bestNumberDown_ = 0;
+}
+
+// Copy constructor
+CbcBranchDefaultDecision::CbcBranchDefaultDecision (
+    const CbcBranchDefaultDecision & rhs)
+        : CbcBranchDecision(rhs)
+{
+    bestCriterion_ = rhs.bestCriterion_;
+    bestChangeUp_ = rhs.bestChangeUp_;
+    bestNumberUp_ = rhs.bestNumberUp_;
+    bestChangeDown_ = rhs.bestChangeDown_;
+    bestNumberDown_ = rhs.bestNumberDown_;
+    bestObject_ = rhs.bestObject_;
+    model_ = rhs.model_;
+}
+
+CbcBranchDefaultDecision::~CbcBranchDefaultDecision()
+{
+}
+
+// Clone
+CbcBranchDecision *
+CbcBranchDefaultDecision::clone() const
+{
+    return new CbcBranchDefaultDecision(*this);
+}
+
+// Initialize i.e. before start of choosing at a node
+void
+CbcBranchDefaultDecision::initialize(CbcModel * model)
+{
+    bestCriterion_ = 0.0;
+    bestChangeUp_ = 0.0;
+    bestNumberUp_ = 0;
+    bestChangeDown_ = 0.0;
+    bestNumberDown_ = 0;
+    bestObject_ = NULL;
+    model_ = model;
+}
+
+
+/*
+  Simple default decision algorithm. Compare based on infeasibility (numInfUp,
+  numInfDn) until a solution is found by search, then switch to change in
+  objective (changeUp, changeDn). Note that bestSoFar is remembered in
+  bestObject_, so the parameter bestSoFar is unused.
+*/
+
+int
+CbcBranchDefaultDecision::betterBranch(CbcBranchingObject * thisOne,
+                                       CbcBranchingObject * /*bestSoFar*/,
+                                       double changeUp, int numInfUp,
+                                       double changeDn, int numInfDn)
+{
+    bool beforeSolution = cbcModel()->getSolutionCount() ==
+                          cbcModel()->getNumberHeuristicSolutions();;
+    int betterWay = 0;
+    if (beforeSolution) {
+        if (!bestObject_) {
+            bestNumberUp_ = COIN_INT_MAX;
+            bestNumberDown_ = COIN_INT_MAX;
+        }
+        // before solution - choose smallest number
+        // could add in depth as well
+        int bestNumber = CoinMin(bestNumberUp_, bestNumberDown_);
+        if (numInfUp < numInfDn) {
+            if (numInfUp < bestNumber) {
+                betterWay = 1;
+            } else if (numInfUp == bestNumber) {
+                if (changeUp < bestCriterion_)
+                    betterWay = 1;
+            }
+        } else if (numInfUp > numInfDn) {
+            if (numInfDn < bestNumber) {
+                betterWay = -1;
+            } else if (numInfDn == bestNumber) {
+                if (changeDn < bestCriterion_)
+                    betterWay = -1;
+            }
+        } else {
+            // up and down have same number
+            bool better = false;
+            if (numInfUp < bestNumber) {
+                better = true;
+            } else if (numInfUp == bestNumber) {
+                if (CoinMin(changeUp, changeDn) < bestCriterion_)
+                    better = true;;
+            }
+            if (better) {
+                // see which way
+                if (changeUp <= changeDn)
+                    betterWay = 1;
+                else
+                    betterWay = -1;
+            }
+        }
+    } else {
+        if (!bestObject_) {
+            bestCriterion_ = -1.0;
+        }
+        // got a solution
+        if (changeUp <= changeDn) {
+            if (changeUp > bestCriterion_)
+                betterWay = 1;
+        } else {
+            if (changeDn > bestCriterion_)
+                betterWay = -1;
+        }
+    }
+    if (betterWay) {
+        bestCriterion_ = CoinMin(changeUp, changeDn);
+        bestChangeUp_ = changeUp;
+        bestNumberUp_ = numInfUp;
+        bestChangeDown_ = changeDn;
+        bestNumberDown_ = numInfDn;
+        bestObject_ = thisOne;
+        // See if user is overriding way
+        if (thisOne->object() && thisOne->object()->preferredWay())
+            betterWay = thisOne->object()->preferredWay();
+    }
+    return betterWay;
+}
+/* Sets or gets best criterion so far */
+void
+CbcBranchDefaultDecision::setBestCriterion(double value)
+{
+    bestCriterion_ = value;
+}
+double
+CbcBranchDefaultDecision::getBestCriterion() const
+{
+    return bestCriterion_;
+}
+
+/* Compare N branching objects. Return index of best
+   and sets way of branching in chosen object.
+
+   This routine is used only after strong branching.
+*/
+
+int
+CbcBranchDefaultDecision::bestBranch (CbcBranchingObject ** objects, int numberObjects,
+                                      int numberUnsatisfied,
+                                      double * changeUp, int * numberInfeasibilitiesUp,
+                                      double * changeDown, int * numberInfeasibilitiesDown,
+                                      double objectiveValue)
+{
+
+    int bestWay = 0;
+    int whichObject = -1;
+    if (numberObjects) {
+        CbcModel * model = cbcModel();
+        // at continuous
+        //double continuousObjective = model->getContinuousObjective();
+        //int continuousInfeasibilities = model->getContinuousInfeasibilities();
+
+        // average cost to get rid of infeasibility
+        //double averageCostPerInfeasibility =
+        //(objectiveValue-continuousObjective)/
+        //(double) (abs(continuousInfeasibilities-numberUnsatisfied)+1);
+        /* beforeSolution is :
+           0 - before any solution
+           n - n heuristic solutions but no branched one
+           -1 - branched solution found
+        */
+        int numberSolutions = model->getSolutionCount();
+        double cutoff = model->getCutoff();
+        int method = 0;
+        int i;
+        if (numberSolutions) {
+            int numberHeuristic = model->getNumberHeuristicSolutions();
+            if (numberHeuristic < numberSolutions) {
+                method = 1;
+            } else {
+                method = 2;
+                // look further
+                for ( i = 0 ; i < numberObjects ; i++) {
+                    int numberNext = numberInfeasibilitiesUp[i];
+
+                    if (numberNext < numberUnsatisfied) {
+                        int numberUp = numberUnsatisfied - numberInfeasibilitiesUp[i];
+                        double perUnsatisfied = changeUp[i] / static_cast<double> (numberUp);
+                        double estimatedObjective = objectiveValue + numberUnsatisfied * perUnsatisfied;
+                        if (estimatedObjective < cutoff)
+                            method = 3;
+                    }
+                    numberNext = numberInfeasibilitiesDown[i];
+                    if (numberNext < numberUnsatisfied) {
+                        int numberDown = numberUnsatisfied - numberInfeasibilitiesDown[i];
+                        double perUnsatisfied = changeDown[i] / static_cast<double> (numberDown);
+                        double estimatedObjective = objectiveValue + numberUnsatisfied * perUnsatisfied;
+                        if (estimatedObjective < cutoff)
+                            method = 3;
+                    }
+                }
+            }
+            method = 2;
+        } else {
+            method = 0;
+        }
+        // Uncomment next to force method 4
+        //method=4;
+
+	// FIXME This should be an enum.  It will be easier to
+	// understand in the code than numbers.
+        /* Methods :
+           0 - fewest infeasibilities
+           1 - largest min change in objective
+           2 - as 1 but use sum of changes if min close
+           3 - predicted best solution
+           4 - take cheapest up branch if infeasibilities same
+        */
+        int bestNumber = COIN_INT_MAX;
+        double bestCriterion = -1.0e50;
+        double alternativeCriterion = -1.0;
+        double bestEstimate = 1.0e100;
+        switch (method) {
+        case 0:
+            // could add in depth as well
+            for ( i = 0 ; i < numberObjects ; i++) {
+                int thisNumber = CoinMin(numberInfeasibilitiesUp[i], numberInfeasibilitiesDown[i]);
+                if (thisNumber <= bestNumber) {
+                    int betterWay = 0;
+                    if (numberInfeasibilitiesUp[i] < numberInfeasibilitiesDown[i]) {
+                        if (numberInfeasibilitiesUp[i] < bestNumber) {
+                            betterWay = 1;
+                        } else {
+                            if (changeUp[i] < bestCriterion)
+                                betterWay = 1;
+                        }
+                    } else if (numberInfeasibilitiesUp[i] > numberInfeasibilitiesDown[i]) {
+                        if (numberInfeasibilitiesDown[i] < bestNumber) {
+                            betterWay = -1;
+                        } else {
+                            if (changeDown[i] < bestCriterion)
+                                betterWay = -1;
+                        }
+                    } else {
+                        // up and down have same number
+                        bool better = false;
+                        if (numberInfeasibilitiesUp[i] < bestNumber) {
+                            better = true;
+                        } else if (numberInfeasibilitiesUp[i] == bestNumber) {
+                            if (CoinMin(changeUp[i], changeDown[i]) < bestCriterion)
+                                better = true;;
+                        }
+                        if (better) {
+                            // see which way
+                            if (changeUp[i] <= changeDown[i])
+                                betterWay = 1;
+                            else
+                                betterWay = -1;
+                        }
+                    }
+                    if (betterWay) {
+                        bestCriterion = CoinMin(changeUp[i], changeDown[i]);
+                        bestNumber = thisNumber;
+                        whichObject = i;
+                        bestWay = betterWay;
+                    }
+                }
+            }
+            break;
+        case 1:
+            for ( i = 0 ; i < numberObjects ; i++) {
+                int betterWay = 0;
+                if (changeUp[i] <= changeDown[i]) {
+                    if (changeUp[i] > bestCriterion)
+                        betterWay = 1;
+                } else {
+                    if (changeDown[i] > bestCriterion)
+                        betterWay = -1;
+                }
+                if (betterWay) {
+                    bestCriterion = CoinMin(changeUp[i], changeDown[i]);
+                    whichObject = i;
+                    bestWay = betterWay;
+                }
+            }
+            break;
+        case 2:
+            for ( i = 0 ; i < numberObjects ; i++) {
+                double change = CoinMin(changeUp[i], changeDown[i]);
+                double sum = changeUp[i] + changeDown[i];
+                bool take = false;
+                if (change > 1.1*bestCriterion)
+                    take = true;
+                else if (change > 0.9*bestCriterion && sum + change > bestCriterion + alternativeCriterion)
+                    take = true;
+                if (take) {
+                    if (changeUp[i] <= changeDown[i]) {
+                        if (changeUp[i] > bestCriterion)
+                            bestWay = 1;
+                    } else {
+                        if (changeDown[i] > bestCriterion)
+                            bestWay = -1;
+                    }
+                    bestCriterion = change;
+                    alternativeCriterion = sum;
+                    whichObject = i;
+                }
+            }
+            break;
+        case 3:
+            for ( i = 0 ; i < numberObjects ; i++) {
+                int numberNext = numberInfeasibilitiesUp[i];
+
+                if (numberNext < numberUnsatisfied) {
+                    int numberUp = numberUnsatisfied - numberInfeasibilitiesUp[i];
+                    double perUnsatisfied = changeUp[i] / static_cast<double> (numberUp);
+                    double estimatedObjective = objectiveValue + numberUnsatisfied * perUnsatisfied;
+                    if (estimatedObjective < bestEstimate) {
+                        bestEstimate = estimatedObjective;
+                        bestWay = 1;
+                        whichObject = i;
+                    }
+                }
+                numberNext = numberInfeasibilitiesDown[i];
+                if (numberNext < numberUnsatisfied) {
+                    int numberDown = numberUnsatisfied - numberInfeasibilitiesDown[i];
+                    double perUnsatisfied = changeDown[i] / static_cast<double> (numberDown);
+                    double estimatedObjective = objectiveValue + numberUnsatisfied * perUnsatisfied;
+                    if (estimatedObjective < bestEstimate) {
+                        bestEstimate = estimatedObjective;
+                        bestWay = -1;
+                        whichObject = i;
+                    }
+                }
+            }
+            break;
+        case 4:
+            // if number infeas same then cheapest up
+            // first get best number or when going down
+            // now choose smallest change up amongst equal number infeas
+            for ( i = 0 ; i < numberObjects ; i++) {
+                int thisNumber = CoinMin(numberInfeasibilitiesUp[i], numberInfeasibilitiesDown[i]);
+                if (thisNumber <= bestNumber) {
+                    int betterWay = 0;
+                    if (numberInfeasibilitiesUp[i] < numberInfeasibilitiesDown[i]) {
+                        if (numberInfeasibilitiesUp[i] < bestNumber) {
+                            betterWay = 1;
+                        } else {
+                            if (changeUp[i] < bestCriterion)
+                                betterWay = 1;
+                        }
+                    } else if (numberInfeasibilitiesUp[i] > numberInfeasibilitiesDown[i]) {
+                        if (numberInfeasibilitiesDown[i] < bestNumber) {
+                            betterWay = -1;
+                        } else {
+                            if (changeDown[i] < bestCriterion)
+                                betterWay = -1;
+                        }
+                    } else {
+                        // up and down have same number
+                        bool better = false;
+                        if (numberInfeasibilitiesUp[i] < bestNumber) {
+                            better = true;
+                        } else if (numberInfeasibilitiesUp[i] == bestNumber) {
+                            if (CoinMin(changeUp[i], changeDown[i]) < bestCriterion)
+                                better = true;;
+                        }
+                        if (better) {
+                            // see which way
+                            if (changeUp[i] <= changeDown[i])
+                                betterWay = 1;
+                            else
+                                betterWay = -1;
+                        }
+                    }
+                    if (betterWay) {
+                        bestCriterion = CoinMin(changeUp[i], changeDown[i]);
+                        bestNumber = thisNumber;
+                        whichObject = i;
+                        bestWay = betterWay;
+                    }
+                }
+            }
+            bestCriterion = 1.0e50;
+            for ( i = 0 ; i < numberObjects ; i++) {
+                int thisNumber = numberInfeasibilitiesUp[i];
+                if (thisNumber == bestNumber && changeUp) {
+                    if (changeUp[i] < bestCriterion) {
+                        bestCriterion = changeUp[i];
+                        whichObject = i;
+                        bestWay = 1;
+                    }
+                }
+            }
+            break;
+        }
+        // set way in best
+        if (whichObject >= 0) {
+            CbcBranchingObject * bestObject = objects[whichObject];
+            if (bestObject->object() && bestObject->object()->preferredWay())
+                bestWay = bestObject->object()->preferredWay();
+            bestObject->way(bestWay);
+        } else {
+	  COIN_DETAIL_PRINT(printf("debug\n"));
+        }
+    }
+    return whichObject;
+}
+
diff --git a/cbits/coin/CbcBranchDefaultDecision.hpp b/cbits/coin/CbcBranchDefaultDecision.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchDefaultDecision.hpp
@@ -0,0 +1,100 @@
+// $Id: CbcBranchDefaultDecision.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#ifndef CbcBranchDefaultDecision_H
+#define CbcBranchDefaultDecision_H
+
+#include "CbcBranchBase.hpp"
+/** Branching decision default class
+
+  This class implements a simple default algorithm
+  (betterBranch()) for choosing a branching variable.
+*/
+
+class CbcBranchDefaultDecision : public CbcBranchDecision {
+public:
+    // Default Constructor
+    CbcBranchDefaultDecision ();
+
+    // Copy constructor
+    CbcBranchDefaultDecision ( const CbcBranchDefaultDecision &);
+
+    virtual ~CbcBranchDefaultDecision();
+
+    /// Clone
+    virtual CbcBranchDecision * clone() const;
+
+    /// Initialize, <i>e.g.</i> before the start of branch selection at a node
+    virtual void initialize(CbcModel * model);
+
+    /** \brief Compare two branching objects. Return nonzero if \p thisOne is
+           better than \p bestSoFar.
+
+      The routine compares branches using the values supplied in \p numInfUp and
+      \p numInfDn until a solution is found by search, after which it uses the
+      values supplied in \p changeUp and \p changeDn. The best branching object
+      seen so far and the associated parameter values are remembered in the
+      \c CbcBranchDefaultDecision object. The nonzero return value is +1 if the
+      up branch is preferred, -1 if the down branch is preferred.
+
+      As the names imply, the assumption is that the values supplied for
+      \p numInfUp and \p numInfDn will be the number of infeasibilities reported
+      by the branching object, and \p changeUp and \p changeDn will be the
+      estimated change in objective. Other measures can be used if desired.
+
+      Because an \c CbcBranchDefaultDecision object remembers the current best
+      branching candidate (#bestObject_) as well as the values used in the
+      comparison, the parameter \p bestSoFar is redundant, hence unused.
+    */
+    virtual int betterBranch(CbcBranchingObject * thisOne,
+                             CbcBranchingObject * bestSoFar,
+                             double changeUp, int numInfUp,
+                             double changeDn, int numInfDn);
+    /** Sets or gets best criterion so far */
+    virtual void setBestCriterion(double value);
+    virtual double getBestCriterion() const;
+
+    /** \brief Compare N branching objects. Return index of best
+        and sets way of branching in chosen object.
+
+      This routine is used only after strong branching.
+    */
+
+    virtual int
+    bestBranch (CbcBranchingObject ** objects, int numberObjects, int numberUnsatisfied,
+                double * changeUp, int * numberInfeasibilitiesUp,
+                double * changeDown, int * numberInfeasibilitiesDown,
+                double objectiveValue) ;
+private:
+
+    /// Illegal Assignment operator
+    CbcBranchDefaultDecision & operator=(const CbcBranchDefaultDecision& rhs);
+
+    /// data
+
+    /// "best" so far
+    double bestCriterion_;
+
+    /// Change up for best
+    double bestChangeUp_;
+
+    /// Number of infeasibilities for up
+    int bestNumberUp_;
+
+    /// Change down for best
+    double bestChangeDown_;
+
+    /// Pointer to best branching object
+    CbcBranchingObject * bestObject_;
+
+    /// Number of infeasibilities for down
+    int bestNumberDown_;
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcBranchDynamic.cpp b/cbits/coin/CbcBranchDynamic.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchDynamic.cpp
@@ -0,0 +1,793 @@
+/* $Id: CbcBranchDynamic.cpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+//#define TRACE_ONE 19
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+// Removing magic constants.
+
+// This is a very small number, added to something to make sure it's non-zero.
+// Useful, for example in denominators of ratios to avoid any possible division by zero
+# define nonZeroAmount 1.0e-30
+
+// Increasing the size of an array when it grows to the end of its alloted space.
+// In this file, only used for the history of the outcome of a branch.
+// New size is   size_scale_numerator* <old value> / size_scale_denominator + additive_size_increase.
+
+#define size_scale_numerator 3
+#define size_scale_denominator 2
+#define additive_size_increase 100
+
+// Explanation of options used in this file
+
+// TYPE2 defines a strategy for computing pseudocosts
+// 0 means to just use the absolute change in objective
+// 1 means use the relative change in objective
+// 2 means use a convex combination of absolute and relative objective changes
+
+// For option 2 (TYPE2 == 2), the specific combination is controlled by TYPERATIO
+// Includes a TYPERATIO fraction of the absolute change and (1 - TYPERATIO) fraction of
+// the relative change.  So should in general have 0 <= TYPERATIO <= 1.  But for the
+// equality cases, you're better off using the other strategy (TYPE2) options.
+
+#ifdef COIN_DEVELOP
+typedef struct {
+    double sumUp_;
+    double upEst_; // or change in obj in update
+    double sumDown_;
+    double downEst_; // or movement in value in update
+    int sequence_;
+    int numberUp_;
+    int numberUpInf_;
+    int numberDown_;
+    int numberDownInf_;
+    char where_;
+    char status_;
+} History;
+History * history = NULL;
+int numberHistory = 0;
+int maxHistory = 0;
+bool getHistoryStatistics_ = true;
+static void increaseHistory()
+{
+    if (numberHistory == maxHistory) {
+      // This was originally 3 * maxHistory/2 + 100
+        maxHistory = additive_size_increase + (size_scale_numerator * maxHistory) / size_scale_denominator;
+        History * temp = new History [maxHistory];
+        memcpy(temp, history, numberHistory*sizeof(History));
+        delete [] history;
+        history = temp;
+    }
+}
+static bool addRecord(History newOne)
+{
+    //if (!getHistoryStatistics_)
+    return false;
+    bool fromCompare = false;
+    int i;
+    for ( i = numberHistory - 1; i >= 0; i--) {
+        if (newOne.sequence_ != history[i].sequence_)
+            continue;
+        if (newOne.where_ != history[i].where_)
+            continue;
+        if (newOne.numberUp_ != history[i].numberUp_)
+            continue;
+        if (newOne.sumUp_ != history[i].sumUp_)
+            continue;
+        if (newOne.numberUpInf_ != history[i].numberUpInf_)
+            continue;
+        if (newOne.upEst_ != history[i].upEst_)
+            continue;
+        if (newOne.numberDown_ != history[i].numberDown_)
+            continue;
+        if (newOne.sumDown_ != history[i].sumDown_)
+            continue;
+        if (newOne.numberDownInf_ != history[i].numberDownInf_)
+            continue;
+        if (newOne.downEst_ != history[i].downEst_)
+            continue;
+        // If B knock out previous B
+        if (newOne.where_ == 'C') {
+            fromCompare = true;
+            if (newOne.status_ == 'B') {
+                int j;
+                for (j = i - 1; j >= 0; j--) {
+                    if (history[j].where_ == 'C') {
+                        if (history[j].status_ == 'I') {
+                            break;
+                        } else if (history[j].status_ == 'B') {
+                            history[j].status_ = ' ';
+                            break;
+                        }
+                    }
+                }
+            }
+            break;
+        }
+    }
+    if (i == -1 || fromCompare) {
+        //add
+        increaseHistory();
+        history[numberHistory++] = newOne;
+        return true;
+    } else {
+        return false;
+    }
+}
+#endif
+
+
+// Default Constructor
+CbcBranchDynamicDecision::CbcBranchDynamicDecision()
+        : CbcBranchDecision()
+{
+    bestCriterion_ = 0.0;
+    bestChangeUp_ = 0.0;
+    bestNumberUp_ = 0;
+    bestChangeDown_ = 0.0;
+    bestNumberDown_ = 0;
+    bestObject_ = NULL;
+}
+
+// Copy constructor
+CbcBranchDynamicDecision::CbcBranchDynamicDecision (
+    const CbcBranchDynamicDecision & rhs)
+        : CbcBranchDecision()
+{
+    bestCriterion_ = rhs.bestCriterion_;
+    bestChangeUp_ = rhs.bestChangeUp_;
+    bestNumberUp_ = rhs.bestNumberUp_;
+    bestChangeDown_ = rhs.bestChangeDown_;
+    bestNumberDown_ = rhs.bestNumberDown_;
+    bestObject_ = rhs.bestObject_;
+}
+
+CbcBranchDynamicDecision::~CbcBranchDynamicDecision()
+{
+}
+
+// Clone
+CbcBranchDecision *
+CbcBranchDynamicDecision::clone() const
+{
+    return new CbcBranchDynamicDecision(*this);
+}
+
+// Initialize i.e. before start of choosing at a node
+void
+CbcBranchDynamicDecision::initialize(CbcModel * /*model*/)
+{
+    bestCriterion_ = 0.0;
+    bestChangeUp_ = 0.0;
+    bestNumberUp_ = 0;
+    bestChangeDown_ = 0.0;
+    bestNumberDown_ = 0;
+    bestObject_ = NULL;
+#ifdef COIN_DEVELOP
+    History hist;
+    hist.where_ = 'C';
+    hist.status_ = 'I';
+    hist.sequence_ = 55555;
+    hist.numberUp_ = 0;
+    hist.numberUpInf_ = 0;
+    hist.sumUp_ = 0.0;
+    hist.upEst_ = 0.0;
+    hist.numberDown_ = 0;
+    hist.numberDownInf_ = 0;
+    hist.sumDown_ = 0.0;
+    hist.downEst_ = 0.0;
+    addRecord(hist);
+#endif
+}
+
+/* Saves a clone of current branching object.  Can be used to update
+      information on object causing branch - after branch */
+void
+CbcBranchDynamicDecision::saveBranchingObject(OsiBranchingObject * object)
+{
+    OsiBranchingObject * obj = object->clone();
+#ifndef NDEBUG
+    CbcBranchingObject * obj2 =
+        dynamic_cast<CbcBranchingObject *>(obj);
+    assert (obj2);
+#if COIN_DEVELOP>1
+    CbcDynamicPseudoCostBranchingObject * branchingObject =
+        dynamic_cast<CbcDynamicPseudoCostBranchingObject *>(obj);
+    if (!branchingObject)
+        printf("no dynamic branching object Dynamic Decision\n");
+#endif
+#else
+    CbcBranchingObject * obj2 =
+        static_cast<CbcBranchingObject *>(obj);
+#endif
+    //object_=branchingObject;
+    object_ = obj2;
+}
+/* Pass in information on branch just done.
+   assumes object can get information from solver */
+/*
+  The expectation is that this method will be called after the branch has been
+  imposed on the constraint system and resolve() has executed.
+
+  Note that the CbcBranchDecision is a property of the CbcModel. Note also that
+  this method is reaching right through the CbcBranchingObject to update
+  information in the underlying CbcObject. That's why we delete the
+  branchingObject at the end of the method --- the next time we're called,
+  the CbcObject will be different.
+*/
+void
+CbcBranchDynamicDecision::updateInformation(OsiSolverInterface * solver,
+        const CbcNode * node)
+{
+    assert (object_);
+    const CbcModel * model = object_->model();
+    double originalValue = node->objectiveValue();
+    int originalUnsatisfied = node->numberUnsatisfied();
+    double objectiveValue = solver->getObjValue() * model->getObjSense();
+    int unsatisfied = 0;
+    int i;
+    int numberIntegers = model->numberIntegers();;
+    const double * solution = solver->getColSolution();
+    //const double * lower = solver->getColLower();
+    //const double * upper = solver->getColUpper();
+	/*
+	 Gain access to the associated CbcBranchingObject and its underlying
+	 CbcObject.
+
+	 Seems like we'd want to distinguish between no branching object and a
+	 branching object of the wrong type. Just deleting an object of the wrong
+	 type hides many sins.
+
+	 Hmmm ... if we're using the OSI side of the hierarchy, is this indicated by a
+	 null object_? Nah, then we have an assert failure off the top.
+	*/
+
+    CbcDynamicPseudoCostBranchingObject * branchingObject =
+        dynamic_cast<CbcDynamicPseudoCostBranchingObject *>(object_);
+    if (!branchingObject) {
+        delete object_;
+        object_ = NULL;
+        return;
+    }
+    CbcSimpleIntegerDynamicPseudoCost *  object = branchingObject->object();
+    /*
+	change is the change in objective due to the branch we've just imposed. It's
+	possible we may have gone infeasible.
+	*/
+	double change = CoinMax(0.0, objectiveValue - originalValue);
+    // probably should also ignore if stopped
+	// FIXME. Could use enum to avoid numbers for iStatus (e.g. optimal, unknown, infeasible)
+    int iStatus;
+    if (solver->isProvenOptimal())
+        iStatus = 0; // optimal
+    else if (solver->isIterationLimitReached()
+             && !solver->isDualObjectiveLimitReached())
+        iStatus = 2; // unknown
+    else
+        iStatus = 1; // infeasible
+	/*
+	  If we're feasible according to the solver, evaluate integer feasibility.
+	*/
+    bool feasible = iStatus != 1;
+    if (feasible) {
+        double integerTolerance =
+            model->getDblParam(CbcModel::CbcIntegerTolerance);
+        const int * integerVariable = model->integerVariable();
+        for (i = 0; i < numberIntegers; i++) {
+            int j = integerVariable[i];
+            double value = solution[j];
+            double nearest = floor(value + 0.5);
+            if (fabs(value - nearest) > integerTolerance)
+                unsatisfied++;
+        }
+    }
+	/*
+	  Finally, update the object. Defaults (080104) are TYPE2 = 0, INFEAS = 1.
+
+	  Pseudocosts are at heart the average of actual costs for a branch. We just
+	  need to update the information used to calculate that average.
+	*/
+    int way = object_->way();
+    double value = object_->value();
+    //#define TYPE2 1
+    //#define TYPERATIO 0.9
+    if (way < 0) {
+        // down
+        if (feasible) {
+            double movement = value - floor(value);
+            movement = CoinMax(movement, MINIMUM_MOVEMENT);
+            //printf("(down change %g value down %g ",change,movement);
+            object->incrementNumberTimesDown();
+            object->addToSumDownChange(nonZeroAmount + movement);
+            object->addToSumDownDecrease(originalUnsatisfied - unsatisfied);
+#if TYPE2==0
+            object->addToSumDownCost(change / (nonZeroAmount + movement));
+            object->setDownDynamicPseudoCost(object->sumDownCost() /
+                                             static_cast<double> (object->numberTimesDown()));
+#elif TYPE2==1
+            object->addToSumDownCost(change);
+            object->setDownDynamicPseudoCost(object->sumDownCost() / object->sumDownChange());
+#elif TYPE2==2
+            object->addToSumDownCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (nonZeroAmount + movement));
+            object->setDownDynamicPseudoCost(object->sumDownCost()*(TYPERATIO / object->sumDownChange() + (1.0 - TYPERATIO) / (double) object->numberTimesDown()));
+#endif
+        } else {
+            //printf("(down infeasible value down %g ",change,movement);
+            object->incrementNumberTimesDown();
+            object->incrementNumberTimesDownInfeasible();
+#if INFEAS==2
+            double distanceToCutoff = 0.0;
+            double objectiveValue = model->getCurrentMinimizationObjValue();
+            distanceToCutoff =  model->getCutoff()  - originalValue;
+            if (distanceToCutoff < 1.0e20)
+                change = distanceToCutoff * 2.0;
+            else
+                change = object->downDynamicPseudoCost() * movement * 10.0;
+            change = CoinMax(1.0e-12 * (1.0 + fabs(originalValue)), change);
+            object->addToSumDownChange(nonZeroAmount + movement);
+            object->addToSumDownDecrease(originalUnsatisfied - unsatisfied);
+#if TYPE2==0
+            object->addToSumDownCost(change / (nonZeroAmount + movement));
+            object->setDownDynamicPseudoCost(object->sumDownCost() / (double) object->numberTimesDown());
+#elif TYPE2==1
+            object->addToSumDownCost(change);
+            object->setDownDynamicPseudoCost(object->sumDownCost() / object->sumDownChange());
+#elif TYPE2==2
+            object->addToSumDownCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (nonZeroAmount + movement));
+            object->setDownDynamicPseudoCost(object->sumDownCost()*(TYPERATIO / object->sumDownChange() + (1.0 - TYPERATIO) / (double) object->numberTimesDown()));
+#endif
+#endif
+        }
+    } else {
+        // up
+        if (feasible) {
+            double movement = ceil(value) - value;
+            movement = CoinMax(movement, MINIMUM_MOVEMENT);
+            //printf("(up change %g value down %g ",change,movement);
+            object->incrementNumberTimesUp();
+            object->addToSumUpChange(nonZeroAmount + movement);
+            object->addToSumUpDecrease(unsatisfied - originalUnsatisfied);
+#if TYPE2==0
+            object->addToSumUpCost(change / (nonZeroAmount + movement));
+            object->setUpDynamicPseudoCost(object->sumUpCost() /
+                                           static_cast<double> (object->numberTimesUp()));
+#elif TYPE2==1
+            object->addToSumUpCost(change);
+            object->setUpDynamicPseudoCost(object->sumUpCost() / object->sumUpChange());
+#elif TYPE2==2
+            object->addToSumUpCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (nonZeroAmount + movement));
+            object->setUpDynamicPseudoCost(object->sumUpCost()*(TYPERATIO / object->sumUpChange() + (1.0 - TYPERATIO) / (double) object->numberTimesUp()));
+#endif
+        } else {
+            //printf("(up infeasible value down %g ",change,movement);
+            object->incrementNumberTimesUp();
+            object->incrementNumberTimesUpInfeasible();
+#if INFEAS==2
+            double distanceToCutoff = 0.0;
+            double objectiveValue = model->getCurrentMinimizationObjValue();
+            distanceToCutoff =  model->getCutoff()  - originalValue;
+            if (distanceToCutoff < 1.0e20)
+                change = distanceToCutoff * 2.0;
+            else
+                change = object->upDynamicPseudoCost() * movement * 10.0;
+            change = CoinMax(1.0e-12 * (1.0 + fabs(originalValue)), change);
+            object->addToSumUpChange(nonZeroAmount + movement);
+            object->addToSumUpDecrease(unsatisfied - originalUnsatisfied);
+#if TYPE2==0
+            object->addToSumUpCost(change / (nonZeroAmount + movement));
+            object->setUpDynamicPseudoCost(object->sumUpCost() / (double) object->numberTimesUp());
+#elif TYPE2==1
+            object->addToSumUpCost(change);
+            object->setUpDynamicPseudoCost(object->sumUpCost() / object->sumUpChange());
+#elif TYPE2==2
+            object->addToSumUpCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (nonZeroAmount + movement));
+            object->setUpDynamicPseudoCost(object->sumUpCost()*(TYPERATIO / object->sumUpChange() + (1.0 - TYPERATIO) / (double) object->numberTimesUp()));
+#endif
+#endif
+        }
+    }
+    //object->print(1,0.5);
+    delete object_;
+    object_ = NULL;
+}
+
+/*
+  Simple dynamic decision algorithm. Compare based on infeasibility (numInfUp,
+  numInfDown) until a solution is found by search, then switch to change in
+  objective (changeUp, changeDown). Note that bestSoFar is remembered in
+  bestObject_, so the parameter bestSoFar is unused.
+*/
+
+int
+CbcBranchDynamicDecision::betterBranch(CbcBranchingObject * thisOne,
+                                       CbcBranchingObject * /*bestSoFar*/,
+                                       double changeUp, int numInfUp,
+                                       double changeDown, int numInfDown)
+{
+    CbcModel * model = thisOne->model();
+    int stateOfSearch = model->stateOfSearch() % 10;
+    int betterWay = 0;
+    double value = 0.0;
+    if (!bestObject_) {
+        bestCriterion_ = -1.0e30;
+        bestNumberUp_ = COIN_INT_MAX;
+        bestNumberDown_ = COIN_INT_MAX;
+    }
+    // maybe branch up more if no solution or not many nodes done?
+    if (stateOfSearch <= 2) {
+        //#define TRY_STUFF 1
+#ifdef TRY_STUFF
+        // before solution - choose smallest number
+        // could add in depth as well
+        int bestNumber = CoinMin(bestNumberUp_, bestNumberDown_);
+        if (numInfUp < numInfDown) {
+            if (numInfUp < bestNumber) {
+                betterWay = 1;
+            } else if (numInfUp == bestNumber) {
+                if (changeUp < bestChangeUp_)
+                    betterWay = 1;
+            }
+        } else if (numInfUp > numInfDown) {
+            if (numInfDown < bestNumber) {
+                betterWay = -1;
+            } else if (numInfDown == bestNumber) {
+                if (changeDown < bestChangeDown_)
+                    betterWay = -1;
+            }
+        } else {
+            // up and down have same number
+            bool better = false;
+            if (numInfUp < bestNumber) {
+                better = true;
+            } else if (numInfUp == bestNumber) {
+                if (CoinMin(changeUp, changeDown) < CoinMin(bestChangeUp_, bestChangeDown_) - 1.0e-5)
+                    better = true;;
+            }
+            if (better) {
+                // see which way
+                if (changeUp <= changeDown)
+                    betterWay = 1;
+                else
+                    betterWay = -1;
+            }
+        }
+        if (betterWay) {
+            value = CoinMin(numInfUp, numInfDown);
+        }
+#else
+        // use pseudo shadow prices modified by locks
+        // test testosi
+#ifndef JJF_ONE
+        double objectiveValue = model->getCurrentMinimizationObjValue();
+        double distanceToCutoff =  model->getCutoff()  - objectiveValue;
+        if (distanceToCutoff < 1.0e20)
+            distanceToCutoff *= 10.0;
+        else
+            distanceToCutoff = 1.0e2 + fabs(objectiveValue);
+        distanceToCutoff = CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(objectiveValue)));
+        double continuousObjective = model->getContinuousObjective();
+        double distanceToCutoffC =  model->getCutoff()  - continuousObjective;
+        if (distanceToCutoffC > 1.0e20)
+            distanceToCutoffC = 1.0e2 + fabs(objectiveValue);
+        distanceToCutoffC = CoinMax(distanceToCutoffC, 1.0e-12 * (1.0 + fabs(objectiveValue)));
+        int numberInfC = model->getContinuousInfeasibilities();
+        double perInf = distanceToCutoffC / static_cast<double> (numberInfC);
+        assert (perInf > 0.0);
+        //int numberIntegers = model->numberIntegers();
+        changeDown += perInf * numInfDown;
+        changeUp += perInf * numInfUp;
+#ifdef JJF_ZERO
+        if (numInfDown == 1) {
+            if (numInfUp == 1) {
+                changeUp += 1.0e6;
+                changeDown += 1.0e6;
+            } else if (changeDown <= 1.5*changeUp) {
+                changeUp += 1.0e6;
+            }
+        } else if (numInfUp == 1 && changeUp <= 1.5*changeDown) {
+            changeDown += 1.0e6;
+        }
+#endif
+#endif
+        double minValue = CoinMin(changeDown, changeUp);
+        double maxValue = CoinMax(changeDown, changeUp);
+        value = WEIGHT_BEFORE * minValue + (1.0 - WEIGHT_BEFORE) * maxValue;
+        if (value > bestCriterion_ + 1.0e-8) {
+            if (changeUp <= 1.5*changeDown) {
+                betterWay = 1;
+            } else {
+                betterWay = -1;
+            }
+        }
+#endif
+    } else {
+#define TRY_STUFF 2
+#if TRY_STUFF > 1
+        // Get current number of infeasibilities, cutoff and current objective
+        CbcNode * node = model->currentNode();
+        int numberUnsatisfied = node->numberUnsatisfied();
+        double cutoff = model->getCutoff();
+        double objectiveValue = node->objectiveValue();
+#endif
+        // got a solution
+        double minValue = CoinMin(changeDown, changeUp);
+        double maxValue = CoinMax(changeDown, changeUp);
+        // Reduce
+#ifdef TRY_STUFF
+        //maxValue = CoinMin(maxValue,minValue*4.0);
+#else
+        //maxValue = CoinMin(maxValue,minValue*2.0);
+#endif
+#ifndef WEIGHT_PRODUCT
+        value = WEIGHT_AFTER * minValue + (1.0 - WEIGHT_AFTER) * maxValue;
+#else
+        double minProductWeight = model->getDblParam(CbcModel::CbcSmallChange);
+        value = CoinMax(minValue, minProductWeight) * CoinMax(maxValue, minProductWeight);
+        //value += minProductWeight*minValue;
+#endif
+        double useValue = value;
+        double useBest = bestCriterion_;
+#if TRY_STUFF>1
+        int thisNumber = CoinMin(numInfUp, numInfDown);
+        int bestNumber = CoinMin(bestNumberUp_, bestNumberDown_);
+        double distance = cutoff - objectiveValue;
+        assert (distance >= 0.0);
+        if (useValue + 0.1*distance > useBest && useValue*1.1 > useBest &&
+                useBest + 0.1*distance > useValue && useBest*1.1 > useValue) {
+            // not much in it - look at unsatisfied
+            if (thisNumber < numberUnsatisfied || bestNumber < numberUnsatisfied) {
+                double perInteger = distance / (static_cast<double> (numberUnsatisfied));
+                useValue += thisNumber * perInteger;
+                useBest += bestNumber * perInteger;
+            }
+        }
+#endif
+        if (useValue > useBest + 1.0e-8) {
+            if (changeUp <= 1.5*changeDown) {
+                betterWay = 1;
+            } else {
+                betterWay = -1;
+            }
+        }
+    }
+#ifdef COIN_DEVELOP
+    History hist;
+    {
+        CbcDynamicPseudoCostBranchingObject * branchingObject =
+            dynamic_cast<CbcDynamicPseudoCostBranchingObject *>(thisOne);
+        if (branchingObject) {
+            CbcSimpleIntegerDynamicPseudoCost *  object = branchingObject->object();
+            assert (object);
+            hist.where_ = 'C';
+            hist.status_ = ' ';
+            hist.sequence_ = object->columnNumber();
+            hist.numberUp_ = object->numberTimesUp();
+            hist.numberUpInf_ = numInfUp;
+            hist.sumUp_ = object->sumUpCost();
+            hist.upEst_ = changeUp;
+            hist.numberDown_ = object->numberTimesDown();
+            hist.numberDownInf_ = numInfDown;
+            hist.sumDown_ = object->sumDownCost();
+            hist.downEst_ = changeDown;
+        }
+    }
+#endif
+    if (betterWay) {
+#ifdef COIN_DEVELOP
+        hist.status_ = 'B';
+#endif
+        // maybe change better way
+        CbcDynamicPseudoCostBranchingObject * branchingObject =
+            dynamic_cast<CbcDynamicPseudoCostBranchingObject *>(thisOne);
+        if (branchingObject) {
+            CbcSimpleIntegerDynamicPseudoCost *  object = branchingObject->object();
+            double separator = object->upDownSeparator();
+            if (separator > 0.0) {
+                const double * solution = thisOne->model()->testSolution();
+                double valueVariable = solution[object->columnNumber()];
+                betterWay = (valueVariable - floor(valueVariable) >= separator) ? 1 : -1;
+            }
+        }
+        bestCriterion_ = value;
+        bestChangeUp_ = changeUp;
+        bestNumberUp_ = numInfUp;
+        bestChangeDown_ = changeDown;
+        bestNumberDown_ = numInfDown;
+        bestObject_ = thisOne;
+        // See if user is overriding way
+        if (thisOne->object() && thisOne->object()->preferredWay())
+            betterWay = thisOne->object()->preferredWay();
+    }
+#ifdef COIN_DEVELOP
+    addRecord(hist);
+#endif
+    return betterWay;
+}
+/* Sets or gets best criterion so far */
+void
+CbcBranchDynamicDecision::setBestCriterion(double value)
+{
+    bestCriterion_ = value;
+}
+double
+CbcBranchDynamicDecision::getBestCriterion() const
+{
+    return bestCriterion_;
+}
+#ifdef COIN_DEVELOP
+void printHistory(const char * file)
+{
+    if (!numberHistory)
+        return;
+    FILE * fp = fopen(file, "w");
+    assert(fp);
+    int numberIntegers = 0;
+    int i;
+    for (i = 0; i < numberHistory; i++) {
+        if (history[i].where_ != 'C' || history[i].status_ != 'I')
+            numberIntegers = CoinMax(numberIntegers, history[i].sequence_);
+    }
+    numberIntegers++;
+    for (int iC = 0; iC < numberIntegers; iC++) {
+        int n = 0;
+        for (i = 0; i < numberHistory; i++) {
+            if (history[i].sequence_ == iC) {
+                if (!n)
+                    fprintf(fp, "XXX %d\n", iC);
+                n++;
+                fprintf(fp, "%c%c up %8d %8d %12.5f %12.5f down  %8d %8d %12.5f %12.5f\n",
+                        history[i].where_,
+                        history[i].status_,
+                        history[i].numberUp_,
+                        history[i].numberUpInf_,
+                        history[i].sumUp_,
+                        history[i].upEst_,
+                        history[i].numberDown_,
+                        history[i].numberDownInf_,
+                        history[i].sumDown_,
+                        history[i].downEst_);
+            }
+        }
+    }
+    fclose(fp);
+}
+#endif
+
+// Default Constructor
+CbcDynamicPseudoCostBranchingObject::CbcDynamicPseudoCostBranchingObject()
+        : CbcIntegerBranchingObject()
+{
+    changeInGuessed_ = 1.0e-5;
+    object_ = NULL;
+}
+
+// Useful constructor
+CbcDynamicPseudoCostBranchingObject::CbcDynamicPseudoCostBranchingObject (CbcModel * model,
+        int variable,
+        int way , double value,
+        CbcSimpleIntegerDynamicPseudoCost * object)
+        : CbcIntegerBranchingObject(model, variable, way, value)
+{
+    changeInGuessed_ = 1.0e-5;
+    object_ = object;
+}
+// Does part of work for constructor
+void
+CbcDynamicPseudoCostBranchingObject::fillPart (int variable,
+        int way , double value,
+        CbcSimpleIntegerDynamicPseudoCost * object)
+{
+    CbcIntegerBranchingObject::fillPart(variable, way, value);
+    changeInGuessed_ = 1.0e-5;
+    object_ = object;
+}
+// Useful constructor for fixing
+CbcDynamicPseudoCostBranchingObject::CbcDynamicPseudoCostBranchingObject (CbcModel * model,
+        int variable, int way,
+        double lowerValue,
+        double /*upperValue*/)
+        : CbcIntegerBranchingObject(model, variable, way, lowerValue)
+{
+    changeInGuessed_ = 1.0e100;
+    object_ = NULL;
+}
+
+
+// Copy constructor
+CbcDynamicPseudoCostBranchingObject::CbcDynamicPseudoCostBranchingObject (
+    const CbcDynamicPseudoCostBranchingObject & rhs)
+        : CbcIntegerBranchingObject(rhs)
+{
+    changeInGuessed_ = rhs.changeInGuessed_;
+    object_ = rhs.object_;
+}
+
+// Assignment operator
+CbcDynamicPseudoCostBranchingObject &
+CbcDynamicPseudoCostBranchingObject::operator=( const CbcDynamicPseudoCostBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcIntegerBranchingObject::operator=(rhs);
+        changeInGuessed_ = rhs.changeInGuessed_;
+        object_ = rhs.object_;
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcDynamicPseudoCostBranchingObject::clone() const
+{
+    return (new CbcDynamicPseudoCostBranchingObject(*this));
+}
+
+// Destructor
+CbcDynamicPseudoCostBranchingObject::~CbcDynamicPseudoCostBranchingObject ()
+{
+}
+
+/*
+  Perform a branch by adjusting the bounds of the specified variable. Note
+  that each arm of the branch advances the object to the next arm by
+  advancing the value of way_.
+
+  Providing new values for the variable's lower and upper bounds for each
+  branching direction gives a little bit of additional flexibility and will
+  be easily extensible to multi-way branching.
+  Returns change in guessed objective on next branch
+*/
+double
+CbcDynamicPseudoCostBranchingObject::branch()
+{
+    CbcIntegerBranchingObject::branch();
+    return changeInGuessed_;
+}
+/* Some branchingObjects may claim to be able to skip
+   strong branching.  If so they have to fill in CbcStrongInfo.
+   The object mention in incoming CbcStrongInfo must match.
+   Returns nonzero if skip is wanted */
+int
+CbcDynamicPseudoCostBranchingObject::fillStrongInfo( CbcStrongInfo & info)
+{
+    assert (object_);
+    assert (info.possibleBranch == this);
+    info.upMovement = object_->upDynamicPseudoCost() * (ceil(value_) - value_);
+    info.downMovement = object_->downDynamicPseudoCost() * (value_ - floor(value_));
+    info.numIntInfeasUp  -= static_cast<int> (object_->sumUpDecrease() /
+                            (1.0e-12 + static_cast<double> (object_->numberTimesUp())));
+    info.numIntInfeasUp = CoinMax(info.numIntInfeasUp, 0);
+    info.numObjInfeasUp = 0;
+    info.finishedUp = false;
+    info.numItersUp = 0;
+    info.numIntInfeasDown  -= static_cast<int> (object_->sumDownDecrease() /
+                              (1.0e-12 + static_cast<double> (object_->numberTimesDown())));
+    info.numIntInfeasDown = CoinMax(info.numIntInfeasDown, 0);
+    info.numObjInfeasDown = 0;
+    info.finishedDown = false;
+    info.numItersDown = 0;
+    info.fix = 0;
+    if (object_->numberTimesUp() < object_->numberBeforeTrust() +
+            2*object_->numberTimesUpInfeasible() ||
+            object_->numberTimesDown() < object_->numberBeforeTrust() +
+            2*object_->numberTimesDownInfeasible()) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
diff --git a/cbits/coin/CbcBranchDynamic.hpp b/cbits/coin/CbcBranchDynamic.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchDynamic.hpp
@@ -0,0 +1,206 @@
+/* $Id: CbcBranchDynamic.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcBranchDynamic_H
+#define CbcBranchDynamic_H
+
+#include "CoinPackedMatrix.hpp"
+#include "CbcSimpleIntegerDynamicPseudoCost.hpp"
+#include "CbcBranchActual.hpp"
+
+/** Branching decision dynamic class
+
+  This class implements a simple algorithm
+  (betterBranch()) for choosing a branching variable when dynamic pseudo costs.
+*/
+
+class CbcBranchDynamicDecision : public CbcBranchDecision {
+public:
+    // Default Constructor
+    CbcBranchDynamicDecision ();
+
+    // Copy constructor
+    CbcBranchDynamicDecision ( const CbcBranchDynamicDecision &);
+
+    virtual ~CbcBranchDynamicDecision();
+
+    /// Clone
+    virtual CbcBranchDecision * clone() const;
+
+    /// Initialize, <i>e.g.</i> before the start of branch selection at a node
+    virtual void initialize(CbcModel * model);
+
+    /** \brief Compare two branching objects. Return nonzero if \p thisOne is
+           better than \p bestSoFar.
+
+      The routine compares branches using the values supplied in \p numInfUp and
+      \p numInfDn until a solution is found by search, after which it uses the
+      values supplied in \p changeUp and \p changeDn. The best branching object
+      seen so far and the associated parameter values are remembered in the
+      \c CbcBranchDynamicDecision object. The nonzero return value is +1 if the
+      up branch is preferred, -1 if the down branch is preferred.
+
+      As the names imply, the assumption is that the values supplied for
+      \p numInfUp and \p numInfDn will be the number of infeasibilities reported
+      by the branching object, and \p changeUp and \p changeDn will be the
+      estimated change in objective. Other measures can be used if desired.
+
+      Because an \c CbcBranchDynamicDecision object remembers the current best
+      branching candidate (#bestObject_) as well as the values used in the
+      comparison, the parameter \p bestSoFar is redundant, hence unused.
+    */
+    virtual int betterBranch(CbcBranchingObject * thisOne,
+                             CbcBranchingObject * bestSoFar,
+                             double changeUp, int numInfUp,
+                             double changeDn, int numInfDn);
+    /** Sets or gets best criterion so far */
+    virtual void setBestCriterion(double value);
+    virtual double getBestCriterion() const;
+    /** Says whether this method can handle both methods -
+        1 better, 2 best, 3 both */
+    virtual int whichMethod() {
+        return 3;
+    }
+
+    /** Saves a clone of current branching object.  Can be used to update
+        information on object causing branch - after branch */
+    virtual void saveBranchingObject(OsiBranchingObject * object) ;
+    /** Pass in information on branch just done.
+        assumes object can get information from solver */
+    virtual void updateInformation(OsiSolverInterface * solver,
+                                   const CbcNode * node);
+
+
+private:
+
+    /// Illegal Assignment operator
+    CbcBranchDynamicDecision & operator=(const CbcBranchDynamicDecision& rhs);
+
+    /// data
+
+    /// "best" so far
+    double bestCriterion_;
+
+    /// Change up for best
+    double bestChangeUp_;
+
+    /// Number of infeasibilities for up
+    int bestNumberUp_;
+
+    /// Change down for best
+    double bestChangeDown_;
+
+    /// Number of infeasibilities for down
+    int bestNumberDown_;
+
+    /// Pointer to best branching object
+    CbcBranchingObject * bestObject_;
+};
+/** Simple branching object for an integer variable with pseudo costs
+
+  This object can specify a two-way branch on an integer variable. For each
+  arm of the branch, the upper and lower bounds on the variable can be
+  independently specified.
+
+  Variable_ holds the index of the integer variable in the integerVariable_
+  array of the model.
+*/
+
+class CbcDynamicPseudoCostBranchingObject : public CbcIntegerBranchingObject {
+
+public:
+
+    /// Default constructor
+    CbcDynamicPseudoCostBranchingObject ();
+
+    /** Create a standard floor/ceiling branch object
+
+      Specifies a simple two-way branch. Let \p value = x*. One arm of the
+      branch will be is lb <= x <= floor(x*), the other ceil(x*) <= x <= ub.
+      Specify way = -1 to set the object state to perform the down arm first,
+      way = 1 for the up arm.
+    */
+    CbcDynamicPseudoCostBranchingObject (CbcModel *model, int variable,
+                                         int way , double value,
+                                         CbcSimpleIntegerDynamicPseudoCost * object) ;
+
+    /** Create a degenerate branch object
+
+      Specifies a `one-way branch'. Calling branch() for this object will
+      always result in lowerValue <= x <= upperValue. Used to fix a variable
+      when lowerValue = upperValue.
+    */
+
+    CbcDynamicPseudoCostBranchingObject (CbcModel *model, int variable, int way,
+                                         double lowerValue, double upperValue) ;
+
+    /// Copy constructor
+    CbcDynamicPseudoCostBranchingObject ( const CbcDynamicPseudoCostBranchingObject &);
+
+    /// Assignment operator
+    CbcDynamicPseudoCostBranchingObject & operator= (const CbcDynamicPseudoCostBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    /// Destructor
+    virtual ~CbcDynamicPseudoCostBranchingObject ();
+
+    /// Does part of constructor
+    void fillPart (int variable,
+                   int way , double value,
+                   CbcSimpleIntegerDynamicPseudoCost * object) ;
+
+    using CbcBranchingObject::branch ;
+    /** \brief Sets the bounds for the variable according to the current arm
+           of the branch and advances the object state to the next arm.
+           This version also changes guessed objective value
+    */
+    virtual double branch();
+
+    /** Some branchingObjects may claim to be able to skip
+        strong branching.  If so they have to fill in CbcStrongInfo.
+        The object mention in incoming CbcStrongInfo must match.
+        Returns nonzero if skip is wanted */
+    virtual int fillStrongInfo( CbcStrongInfo & info);
+
+    /// Change in guessed
+    inline double changeInGuessed() const {
+        return changeInGuessed_;
+    }
+    /// Set change in guessed
+    inline void setChangeInGuessed(double value) {
+        changeInGuessed_ = value;
+    }
+    /// Return object
+    inline CbcSimpleIntegerDynamicPseudoCost * object() const {
+        return object_;
+    }
+    /// Set object
+    inline void setObject(CbcSimpleIntegerDynamicPseudoCost * object) {
+        object_ = object;
+    }
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return DynamicPseudoCostBranchObj;
+    }
+
+    // LL: compareOriginalObject and compareBranchingObject are inherited from
+    // CbcIntegerBranchingObject thus need not be declared/defined here. After
+    // all, this kind of branching object is simply using pseudocosts to make
+    // decisions, but once the decisions are made they are the same kind as in
+    // the underlying class.
+
+protected:
+    /// Change in guessed objective value for next branch
+    double changeInGuessed_;
+    /// Pointer back to object
+    CbcSimpleIntegerDynamicPseudoCost * object_;
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcBranchLotsize.cpp b/cbits/coin/CbcBranchLotsize.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchLotsize.cpp
@@ -0,0 +1,810 @@
+/* $Id: CbcBranchLotsize.cpp 1888 2013-04-06 20:52:59Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchLotsize.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+/*
+  CBC_PRINT 1 just does sanity checks - no printing
+  Larger values of CBC_PRINT set various printing levels.  Larger
+  values print more.
+*/
+//#define CBC_PRINT 1
+// First/last variable to print info on
+#if CBC_PRINT
+// preset does all - change to x,x to just do x
+static int firstPrint = 0;
+static int lastPrint = 1000000;
+static CbcModel * saveModel = NULL;
+#endif
+// Just for debug (CBC_PRINT defined in CbcBranchLotsize.cpp)
+void
+#if CBC_PRINT
+CbcLotsize::printLotsize(double value, bool condition, int type) const
+#else
+CbcLotsize::printLotsize(double , bool , int ) const
+#endif
+{
+#if CBC_PRINT
+    if (columnNumber_ >= firstPrint && columnNumber_ <= lastPrint) {
+        int printIt = CBC_PRINT - 1;
+        // Get details
+        OsiSolverInterface * solver = saveModel->solver();
+        double currentLower = solver->getColLower()[columnNumber_];
+        double currentUpper = solver->getColUpper()[columnNumber_];
+        int i;
+        // See if in a valid range (with two tolerances)
+        bool inRange = false;
+        bool inRange2 = false;
+        double integerTolerance =
+            model_->getDblParam(CbcModel::CbcIntegerTolerance);
+        // increase if type 2
+        if (type == 2) {
+            integerTolerance *= 100.0;
+            type = 0;
+            printIt = 2; // always print
+        }
+        // bounds should match some bound
+        int rangeL = -1;
+        int rangeU = -1;
+        if (rangeType_ == 1) {
+            for (i = 0; i < numberRanges_; i++) {
+                if (fabs(currentLower - bound_[i]) < 1.0e-12)
+                    rangeL = i;
+                if (fabs(currentUpper - bound_[i]) < 1.0e-12)
+                    rangeU = i;
+                if (fabs(value - bound_[i]) < integerTolerance)
+                    inRange = true;
+                if (fabs(value - bound_[i]) < 1.0e8)
+                    inRange2 = true;
+            }
+        } else {
+            for (i = 0; i < numberRanges_; i++) {
+                if (fabs(currentLower - bound_[2*i]) < 1.0e-12)
+                    rangeL = i;
+                if (fabs(currentUpper - bound_[2*i+1]) < 1.0e-12)
+                    rangeU = i;
+                if (value > bound_[2*i] - integerTolerance &&
+                        value < bound_[2*i+1] + integerTolerance)
+                    inRange = true;
+                if (value > bound_[2*i] - integerTolerance &&
+                        value < bound_[2*i+1] + integerTolerance)
+                    inRange = true;
+            }
+        }
+        assert (rangeL >= 0 && rangeU >= 0);
+        bool abortIt = false;
+        switch (type) {
+            // returning from findRange (fall through to just check)
+        case 0:
+            if (printIt) {
+                printf("findRange returns %s for column %d and value %g",
+                       condition ? "true" : "false", columnNumber_, value);
+                if (printIt > 1)
+                    printf(" LP bounds %g, %g", currentLower, currentUpper);
+                printf("\n");
+            }
+            // Should match
+        case 1:
+            if (inRange != condition) {
+                printIt = 2;
+                abortIt = true;
+            }
+            break;
+            //
+        case 2:
+            break;
+            //
+        case 3:
+            break;
+            //
+        case 4:
+            break;
+        }
+    }
+#endif
+}
+/** Default Constructor
+
+*/
+CbcLotsize::CbcLotsize ()
+        : CbcObject(),
+        columnNumber_(-1),
+        rangeType_(0),
+        numberRanges_(0),
+        largestGap_(0),
+        bound_(NULL),
+        range_(0)
+{
+}
+
+/** Useful constructor
+
+  Loads actual upper & lower bounds for the specified variable.
+*/
+CbcLotsize::CbcLotsize (CbcModel * model,
+                        int iColumn, int numberPoints,
+                        const double * points, bool range)
+        : CbcObject(model)
+{
+#if CBC_PRINT
+    if (!saveModel)
+        saveModel = model;
+#endif
+    assert (numberPoints > 0);
+    columnNumber_ = iColumn ;
+    // and set id so can be used for branching
+    id_ = iColumn;
+    // sort ranges
+    int * sort = new int[numberPoints];
+    double * weight = new double [numberPoints];
+    int i;
+    if (range) {
+        rangeType_ = 2;
+    } else {
+        rangeType_ = 1;
+    }
+    for (i = 0; i < numberPoints; i++) {
+        sort[i] = i;
+        weight[i] = points[i*rangeType_];
+    }
+    CoinSort_2(weight, weight + numberPoints, sort);
+    numberRanges_ = 1;
+    largestGap_ = 0;
+    if (rangeType_ == 1) {
+        bound_ = new double[numberPoints+1];
+        bound_[0] = weight[0];
+        for (i = 1; i < numberPoints; i++) {
+            if (weight[i] != weight[i-1])
+                bound_[numberRanges_++] = weight[i];
+        }
+        // and for safety
+        bound_[numberRanges_] = bound_[numberRanges_-1];
+        for (i = 1; i < numberRanges_; i++) {
+            largestGap_ = CoinMax(largestGap_, bound_[i] - bound_[i-1]);
+        }
+    } else {
+        bound_ = new double[2*numberPoints+2];
+        bound_[0] = points[sort[0] * 2];
+        bound_[1] = points[sort[0] * 2 + 1];
+        double hi = bound_[1];
+        assert (hi >= bound_[0]);
+        for (i = 1; i < numberPoints; i++) {
+            double thisLo = points[sort[i] * 2];
+            double thisHi = points[sort[i] * 2 + 1];
+            assert (thisHi >= thisLo);
+            if (thisLo > hi) {
+                bound_[2*numberRanges_] = thisLo;
+                bound_[2*numberRanges_+1] = thisHi;
+                numberRanges_++;
+                hi = thisHi;
+            } else {
+                //overlap
+                hi = CoinMax(hi, thisHi);
+                bound_[2*numberRanges_-1] = hi;
+            }
+        }
+        // and for safety
+        bound_[2*numberRanges_] = bound_[2*numberRanges_-2];
+        bound_[2*numberRanges_+1] = bound_[2*numberRanges_-1];
+        for (i = 1; i < numberRanges_; i++) {
+            largestGap_ = CoinMax(largestGap_, bound_[2*i] - bound_[2*i-1]);
+        }
+    }
+    delete [] sort;
+    delete [] weight;
+    range_ = 0;
+}
+
+// Copy constructor
+CbcLotsize::CbcLotsize ( const CbcLotsize & rhs)
+        : CbcObject(rhs)
+
+{
+    columnNumber_ = rhs.columnNumber_;
+    rangeType_ = rhs.rangeType_;
+    numberRanges_ = rhs.numberRanges_;
+    range_ = rhs.range_;
+    largestGap_ = rhs.largestGap_;
+    if (numberRanges_) {
+        assert (rangeType_ > 0 && rangeType_ < 3);
+        bound_ = new double [(numberRanges_+1)*rangeType_];
+        memcpy(bound_, rhs.bound_, (numberRanges_ + 1)*rangeType_*sizeof(double));
+    } else {
+        bound_ = NULL;
+    }
+}
+
+// Clone
+CbcObject *
+CbcLotsize::clone() const
+{
+    return new CbcLotsize(*this);
+}
+
+// Assignment operator
+CbcLotsize &
+CbcLotsize::operator=( const CbcLotsize & rhs)
+{
+    if (this != &rhs) {
+        CbcObject::operator=(rhs);
+        columnNumber_ = rhs.columnNumber_;
+        rangeType_ = rhs.rangeType_;
+        numberRanges_ = rhs.numberRanges_;
+        largestGap_ = rhs.largestGap_;
+        delete [] bound_;
+        range_ = rhs.range_;
+        if (numberRanges_) {
+            assert (rangeType_ > 0 && rangeType_ < 3);
+            bound_ = new double [(numberRanges_+1)*rangeType_];
+            memcpy(bound_, rhs.bound_, (numberRanges_ + 1)*rangeType_*sizeof(double));
+        } else {
+            bound_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Destructor
+CbcLotsize::~CbcLotsize ()
+{
+    delete [] bound_;
+}
+/* Finds range of interest so value is feasible in range range_ or infeasible
+   between hi[range_] and lo[range_+1].  Returns true if feasible.
+*/
+bool
+CbcLotsize::findRange(double value) const
+{
+    assert (range_ >= 0 && range_ < numberRanges_ + 1);
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    int iLo;
+    int iHi;
+    double infeasibility = 0.0;
+    if (rangeType_ == 1) {
+        if (value < bound_[range_] - integerTolerance) {
+            iLo = 0;
+            iHi = range_ - 1;
+        } else if (value < bound_[range_] + integerTolerance) {
+#if CBC_PRINT
+            printLotsize(value, true, 0);
+#endif
+            return true;
+        } else if (value < bound_[range_+1] - integerTolerance) {
+#ifdef CBC_PRINT
+            printLotsize(value, false, 0);
+#endif
+            return false;
+        } else {
+            iLo = range_ + 1;
+            iHi = numberRanges_ - 1;
+        }
+        // check lo and hi
+        bool found = false;
+        if (value > bound_[iLo] - integerTolerance && value < bound_[iLo+1] + integerTolerance) {
+            range_ = iLo;
+            found = true;
+        } else if (value > bound_[iHi] - integerTolerance && value < bound_[iHi+1] + integerTolerance) {
+            range_ = iHi;
+            found = true;
+        } else {
+            range_ = (iLo + iHi) >> 1;
+        }
+        //points
+        while (!found) {
+            if (value < bound_[range_]) {
+                if (value >= bound_[range_-1]) {
+                    // found
+                    range_--;
+                    break;
+                } else {
+                    iHi = range_;
+                }
+            } else {
+                if (value < bound_[range_+1]) {
+                    // found
+                    break;
+                } else {
+                    iLo = range_;
+                }
+            }
+            range_ = (iLo + iHi) >> 1;
+        }
+        if (value - bound_[range_] <= bound_[range_+1] - value) {
+            infeasibility = value - bound_[range_];
+        } else {
+            infeasibility = bound_[range_+1] - value;
+            if (infeasibility < integerTolerance)
+                range_++;
+        }
+#ifdef CBC_PRINT
+        printLotsize(value, (infeasibility < integerTolerance), 0);
+#endif
+        return (infeasibility < integerTolerance);
+    } else {
+        // ranges
+        if (value < bound_[2*range_] - integerTolerance) {
+            iLo = 0;
+            iHi = range_ - 1;
+        } else if (value < bound_[2*range_+1] + integerTolerance) {
+#ifdef CBC_PRINT
+            printLotsize(value, true, 0);
+#endif
+            return true;
+        } else if (value < bound_[2*range_+2] - integerTolerance) {
+#ifdef CBC_PRINT
+            printLotsize(value, false, 0);
+#endif
+            return false;
+        } else {
+            iLo = range_ + 1;
+            iHi = numberRanges_ - 1;
+        }
+        // check lo and hi
+        bool found = false;
+        if (value > bound_[2*iLo] - integerTolerance && value < bound_[2*iLo+2] - integerTolerance) {
+            range_ = iLo;
+            found = true;
+        } else if (value >= bound_[2*iHi] - integerTolerance) {
+            range_ = iHi;
+            found = true;
+        } else {
+            range_ = (iLo + iHi) >> 1;
+        }
+        //points
+        while (!found) {
+            if (value < bound_[2*range_]) {
+                if (value >= bound_[2*range_-2]) {
+                    // found
+                    range_--;
+                    break;
+                } else {
+                    iHi = range_;
+                }
+            } else {
+                if (value < bound_[2*range_+2]) {
+                    // found
+                    break;
+                } else {
+                    iLo = range_;
+                }
+            }
+            range_ = (iLo + iHi) >> 1;
+        }
+        if (value >= bound_[2*range_] - integerTolerance && value <= bound_[2*range_+1] + integerTolerance)
+            infeasibility = 0.0;
+        else if (value - bound_[2*range_+1] < bound_[2*range_+2] - value) {
+            infeasibility = value - bound_[2*range_+1];
+        } else {
+            infeasibility = bound_[2*range_+2] - value;
+        }
+#ifdef CBC_PRINT
+        printLotsize(value, (infeasibility < integerTolerance), 0);
+#endif
+        return (infeasibility < integerTolerance);
+    }
+}
+/* Returns floor and ceiling
+ */
+void
+CbcLotsize::floorCeiling(double & floorLotsize, double & ceilingLotsize, double value,
+                         double /*tolerance*/) const
+{
+    bool feasible = findRange(value);
+    if (rangeType_ == 1) {
+        floorLotsize = bound_[range_];
+        ceilingLotsize = bound_[range_+1];
+        // may be able to adjust
+        if (feasible && fabs(value - floorLotsize) > fabs(value - ceilingLotsize)) {
+            floorLotsize = bound_[range_+1];
+            ceilingLotsize = bound_[range_+2];
+        }
+    } else {
+        // ranges
+        assert (value >= bound_[2*range_+1]);
+        floorLotsize = bound_[2*range_+1];
+        ceilingLotsize = bound_[2*range_+2];
+    }
+}
+double
+CbcLotsize::infeasibility(const OsiBranchingInformation * /*info*/,
+                          int &preferredWay) const
+{
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    /*printf("%d %g %g %g %g\n",columnNumber_,value,lower[columnNumber_],
+      solution[columnNumber_],upper[columnNumber_]);*/
+    assert (value >= bound_[0] - integerTolerance
+            && value <= bound_[rangeType_*numberRanges_-1] + integerTolerance);
+    double infeasibility = 0.0;
+    bool feasible = findRange(value);
+    if (!feasible) {
+        if (rangeType_ == 1) {
+            if (value - bound_[range_] < bound_[range_+1] - value) {
+                preferredWay = -1;
+                infeasibility = value - bound_[range_];
+            } else {
+                preferredWay = 1;
+                infeasibility = bound_[range_+1] - value;
+            }
+        } else {
+            // ranges
+            if (value - bound_[2*range_+1] < bound_[2*range_+2] - value) {
+                preferredWay = -1;
+                infeasibility = value - bound_[2*range_+1];
+            } else {
+                preferredWay = 1;
+                infeasibility = bound_[2*range_+2] - value;
+            }
+        }
+    } else {
+        // always satisfied
+        preferredWay = -1;
+    }
+    if (infeasibility < integerTolerance)
+        infeasibility = 0.0;
+    else
+        infeasibility /= largestGap_;
+#ifdef CBC_PRINT
+    printLotsize(value, infeasibility, 1);
+#endif
+    return infeasibility;
+}
+/* Column number if single column object -1 otherwise,
+   so returns >= 0
+   Used by heuristics
+*/
+int
+CbcLotsize::columnNumber() const
+{
+    return columnNumber_;
+}
+// This looks at solution and sets bounds to contain solution
+/** More precisely: it first forces the variable within the existing
+    bounds, and then tightens the bounds to make sure the variable is feasible
+*/
+void
+CbcLotsize::feasibleRegion()
+{
+    OsiSolverInterface * solver = model_->solver();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    const double * solution = model_->testSolution();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    findRange(value);
+    double nearest;
+    if (rangeType_ == 1) {
+        nearest = bound_[range_];
+        solver->setColLower(columnNumber_, nearest);
+        solver->setColUpper(columnNumber_, nearest);
+    } else {
+        // ranges
+        solver->setColLower(columnNumber_, bound_[2*range_]);
+        solver->setColUpper(columnNumber_, bound_[2*range_+1]);
+        if (value > bound_[2*range_+1])
+            nearest = bound_[2*range_+1];
+        else if (value < bound_[2*range_])
+            nearest = bound_[2*range_];
+        else
+            nearest = value;
+    }
+#ifdef CBC_PRINT
+    // print details
+    printLotsize(value, true, 2);
+#endif
+    // Scaling may have moved it a bit
+    // Lotsizing variables could be a lot larger
+#ifndef NDEBUG
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    assert (fabs(value - nearest) <= (100.0 + 10.0*fabs(nearest))*integerTolerance);
+#endif
+}
+CbcBranchingObject *
+CbcLotsize::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int way)
+{
+    //OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    assert (!findRange(value));
+    return new CbcLotsizeBranchingObject(model_, columnNumber_, way,
+                                         value, this);
+}
+
+
+/* Given valid solution (i.e. satisfied) and reduced costs etc
+   returns a branching object which would give a new feasible
+   point in direction reduced cost says would be cheaper.
+   If no feasible point returns null
+*/
+CbcBranchingObject *
+CbcLotsize::preferredNewFeasible() const
+{
+    OsiSolverInterface * solver = model_->solver();
+
+    assert (findRange(model_->testSolution()[columnNumber_]));
+    double dj = solver->getObjSense() * solver->getReducedCost()[columnNumber_];
+    CbcLotsizeBranchingObject * object = NULL;
+    double lo, up;
+    if (dj >= 0.0) {
+        // can we go down
+        if (range_) {
+            // yes
+            if (rangeType_ == 1) {
+                lo = bound_[range_-1];
+                up = bound_[range_-1];
+            } else {
+                lo = bound_[2*range_-2];
+                up = bound_[2*range_-1];
+            }
+            object = new CbcLotsizeBranchingObject(model_, columnNumber_, -1,
+                                                   lo, up);
+        }
+    } else {
+        // can we go up
+        if (range_ < numberRanges_ - 1) {
+            // yes
+            if (rangeType_ == 1) {
+                lo = bound_[range_+1];
+                up = bound_[range_+1];
+            } else {
+                lo = bound_[2*range_+2];
+                up = bound_[2*range_+3];
+            }
+            object = new CbcLotsizeBranchingObject(model_, columnNumber_, -1,
+                                                   lo, up);
+        }
+    }
+    return object;
+}
+
+/* Given valid solution (i.e. satisfied) and reduced costs etc
+   returns a branching object which would give a new feasible
+   point in direction opposite to one reduced cost says would be cheaper.
+   If no feasible point returns null
+*/
+CbcBranchingObject *
+CbcLotsize::notPreferredNewFeasible() const
+{
+    OsiSolverInterface * solver = model_->solver();
+
+#ifndef NDEBUG
+    double value = model_->testSolution()[columnNumber_];
+    double nearest = floor(value + 0.5);
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    // Scaling may have moved it a bit
+    // Lotsizing variables could be a lot larger
+    assert (fabs(value - nearest) <= (10.0 + 10.0*fabs(nearest))*integerTolerance);
+#endif
+    double dj = solver->getObjSense() * solver->getReducedCost()[columnNumber_];
+    CbcLotsizeBranchingObject * object = NULL;
+    double lo, up;
+    if (dj <= 0.0) {
+        // can we go down
+        if (range_) {
+            // yes
+            if (rangeType_ == 1) {
+                lo = bound_[range_-1];
+                up = bound_[range_-1];
+            } else {
+                lo = bound_[2*range_-2];
+                up = bound_[2*range_-1];
+            }
+            object = new CbcLotsizeBranchingObject(model_, columnNumber_, -1,
+                                                   lo, up);
+        }
+    } else {
+        // can we go up
+        if (range_ < numberRanges_ - 1) {
+            // yes
+            if (rangeType_ == 1) {
+                lo = bound_[range_+1];
+                up = bound_[range_+1];
+            } else {
+                lo = bound_[2*range_+2];
+                up = bound_[2*range_+3];
+            }
+            object = new CbcLotsizeBranchingObject(model_, columnNumber_, -1,
+                                                   lo, up);
+        }
+    }
+    return object;
+}
+
+/*
+  Bounds may be tightened, so it may be good to be able to refresh the local
+  copy of the original bounds.
+ */
+void
+CbcLotsize::resetBounds(const OsiSolverInterface * /*solver*/)
+{
+}
+
+// Default Constructor
+CbcLotsizeBranchingObject::CbcLotsizeBranchingObject()
+        : CbcBranchingObject()
+{
+    down_[0] = 0.0;
+    down_[1] = 0.0;
+    up_[0] = 0.0;
+    up_[1] = 0.0;
+}
+
+// Useful constructor
+CbcLotsizeBranchingObject::CbcLotsizeBranchingObject (CbcModel * model,
+        int variable, int way , double value,
+        const CbcLotsize * lotsize)
+        : CbcBranchingObject(model, variable, way, value)
+{
+    int iColumn = lotsize->modelSequence();
+    assert (variable == iColumn);
+    down_[0] = model_->solver()->getColLower()[iColumn];
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    lotsize->floorCeiling(down_[1], up_[0], value, integerTolerance);
+    up_[1] = model->getColUpper()[iColumn];
+}
+// Useful constructor for fixing
+CbcLotsizeBranchingObject::CbcLotsizeBranchingObject (CbcModel * model,
+        int variable, int way,
+        double lowerValue,
+        double upperValue)
+        : CbcBranchingObject(model, variable, way, lowerValue)
+{
+    setNumberBranchesLeft(1);
+    down_[0] = lowerValue;
+    down_[1] = upperValue;
+    up_[0] = lowerValue;
+    up_[1] = upperValue;
+}
+
+
+// Copy constructor
+CbcLotsizeBranchingObject::CbcLotsizeBranchingObject ( const CbcLotsizeBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+    down_[0] = rhs.down_[0];
+    down_[1] = rhs.down_[1];
+    up_[0] = rhs.up_[0];
+    up_[1] = rhs.up_[1];
+}
+
+// Assignment operator
+CbcLotsizeBranchingObject &
+CbcLotsizeBranchingObject::operator=( const CbcLotsizeBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        down_[0] = rhs.down_[0];
+        down_[1] = rhs.down_[1];
+        up_[0] = rhs.up_[0];
+        up_[1] = rhs.up_[1];
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcLotsizeBranchingObject::clone() const
+{
+    return (new CbcLotsizeBranchingObject(*this));
+}
+
+
+// Destructor
+CbcLotsizeBranchingObject::~CbcLotsizeBranchingObject ()
+{
+}
+
+/*
+  Perform a branch by adjusting the bounds of the specified variable. Note
+  that each arm of the branch advances the object to the next arm by
+  advancing the value of way_.
+
+  Providing new values for the variable's lower and upper bounds for each
+  branching direction gives a little bit of additional flexibility and will
+  be easily extensible to multi-way branching.
+*/
+double
+CbcLotsizeBranchingObject::branch()
+{
+    decrementNumberBranchesLeft();
+    int iColumn = variable_;
+    if (way_ < 0) {
+#ifdef CBC_DEBUG
+        { double olb, oub ;
+            olb = model_->solver()->getColLower()[iColumn] ;
+            oub = model_->solver()->getColUpper()[iColumn] ;
+            printf("branching down on var %d: [%g,%g] => [%g,%g]\n",
+                   iColumn, olb, oub, down_[0], down_[1]) ;
+        }
+#endif
+        model_->solver()->setColLower(iColumn, down_[0]);
+        model_->solver()->setColUpper(iColumn, down_[1]);
+        way_ = 1;
+    } else {
+#ifdef CBC_DEBUG
+        { double olb, oub ;
+            olb = model_->solver()->getColLower()[iColumn] ;
+            oub = model_->solver()->getColUpper()[iColumn] ;
+            printf("branching up on var %d: [%g,%g] => [%g,%g]\n",
+                   iColumn, olb, oub, up_[0], up_[1]) ;
+        }
+#endif
+        model_->solver()->setColLower(iColumn, up_[0]);
+        model_->solver()->setColUpper(iColumn, up_[1]);
+        way_ = -1;	  // Swap direction
+    }
+    return 0.0;
+}
+// Print
+void
+CbcLotsizeBranchingObject::print()
+{
+    int iColumn = variable_;
+    if (way_ < 0) {
+        {
+            double olb, oub ;
+            olb = model_->solver()->getColLower()[iColumn] ;
+            oub = model_->solver()->getColUpper()[iColumn] ;
+            printf("branching down on var %d: [%g,%g] => [%g,%g]\n",
+                   iColumn, olb, oub, down_[0], down_[1]) ;
+        }
+    } else {
+        {
+            double olb, oub ;
+            olb = model_->solver()->getColLower()[iColumn] ;
+            oub = model_->solver()->getColUpper()[iColumn] ;
+            printf("branching up on var %d: [%g,%g] => [%g,%g]\n",
+                   iColumn, olb, oub, up_[0], up_[1]) ;
+        }
+    }
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcLotsizeBranchingObject::compareBranchingObject
+(const CbcBranchingObject* brObj, const bool replaceIfOverlap)
+{
+    const CbcLotsizeBranchingObject* br =
+        dynamic_cast<const CbcLotsizeBranchingObject*>(brObj);
+    assert(br);
+    double* thisBd = way_ == -1 ? down_ : up_;
+    const double* otherBd = br->way_ == -1 ? br->down_ : br->up_;
+    return CbcCompareRanges(thisBd, otherBd, replaceIfOverlap);
+}
+
diff --git a/cbits/coin/CbcBranchLotsize.hpp b/cbits/coin/CbcBranchLotsize.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchLotsize.hpp
@@ -0,0 +1,242 @@
+/* $Id: CbcBranchLotsize.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcBranchLotsize_H
+#define CbcBranchLotsize_H
+
+#include "CbcBranchBase.hpp"
+/** Lotsize class */
+
+
+class CbcLotsize : public CbcObject {
+
+public:
+
+    // Default Constructor
+    CbcLotsize ();
+
+    /* Useful constructor - passed model index.
+       Also passed valid values - if range then pairs
+    */
+    CbcLotsize (CbcModel * model, int iColumn,
+                int numberPoints, const double * points, bool range = false);
+
+    // Copy constructor
+    CbcLotsize ( const CbcLotsize &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcLotsize & operator=( const CbcLotsize& rhs);
+
+    // Destructor
+    ~CbcLotsize ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /** Set bounds to contain the current solution.
+
+      More precisely, for the variable associated with this object, take the
+      value given in the current solution, force it within the current bounds
+      if required, then set the bounds to fix the variable at the integer
+      nearest the solution value.
+    */
+    virtual void feasibleRegion();
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+
+    /** \brief Given a valid solution (with reduced costs, etc.),
+        return a branching object which would give a new feasible
+        point in the good direction.
+
+      The preferred branching object will force the variable to be +/-1 from
+      its current value, depending on the reduced cost and objective sense.  If
+      movement in the direction which improves the objective is impossible due
+      to bounds on the variable, the branching object will move in the other
+      direction.  If no movement is possible, the method returns NULL.
+
+      Only the bounds on this variable are considered when determining if the new
+      point is feasible.
+    */
+    virtual CbcBranchingObject * preferredNewFeasible() const;
+
+    /** \brief Given a valid solution (with reduced costs, etc.),
+        return a branching object which would give a new feasible
+        point in a bad direction.
+
+      As for preferredNewFeasible(), but the preferred branching object will
+      force movement in a direction that degrades the objective.
+    */
+    virtual CbcBranchingObject * notPreferredNewFeasible() const ;
+
+    /** Reset original upper and lower bound values from the solver.
+
+      Handy for updating bounds held in this object after bounds held in the
+      solver have been tightened.
+     */
+    virtual void resetBounds(const OsiSolverInterface * solver);
+
+    /** Finds range of interest so value is feasible in range range_ or infeasible
+        between hi[range_] and lo[range_+1].  Returns true if feasible.
+    */
+    bool findRange(double value) const;
+
+    /** Returns floor and ceiling
+    */
+    virtual void floorCeiling(double & floorLotsize, double & ceilingLotsize, double value,
+                              double tolerance) const;
+
+    /// Model column number
+    inline int modelSequence() const {
+        return columnNumber_;
+    }
+    /// Set model column number
+    inline void setModelSequence(int value) {
+        columnNumber_ = value;
+    }
+
+    /** Column number if single column object -1 otherwise,
+        so returns >= 0
+        Used by heuristics
+    */
+    virtual int columnNumber() const;
+    /// Original variable bounds
+    inline double originalLowerBound() const {
+        return bound_[0];
+    }
+    inline double originalUpperBound() const {
+        return bound_[rangeType_*numberRanges_-1];
+    }
+    /// Type - 1 points, 2 ranges
+    inline int rangeType() const {
+        return rangeType_;
+    }
+    /// Number of points
+    inline int numberRanges() const {
+        return numberRanges_;
+    }
+    /// Ranges
+    inline double * bound() const {
+        return bound_;
+    }
+    /** \brief Return true if object can take part in normal heuristics
+    */
+    virtual bool canDoHeuristics() const {
+        return false;
+    }
+
+private:
+    /// Just for debug (CBC_PRINT defined in CbcBranchLotsize.cpp)
+    void printLotsize(double value, bool condition, int type) const;
+
+private:
+    /// data
+
+    /// Column number in model
+    int columnNumber_;
+    /// Type - 1 points, 2 ranges
+    int rangeType_;
+    /// Number of points
+    int numberRanges_;
+    // largest gap
+    double largestGap_;
+    /// Ranges
+    double * bound_;
+    /// Current range
+    mutable int range_;
+};
+
+/** Lotsize branching object
+
+  This object can specify a two-way branch on an integer variable. For each
+  arm of the branch, the upper and lower bounds on the variable can be
+  independently specified.
+
+  Variable_ holds the index of the integer variable in the integerVariable_
+  array of the model.
+*/
+
+class CbcLotsizeBranchingObject : public CbcBranchingObject {
+
+public:
+
+    /// Default constructor
+    CbcLotsizeBranchingObject ();
+
+    /** Create a lotsize floor/ceiling branch object
+
+      Specifies a simple two-way branch. Let \p value = x*. One arm of the
+      branch will be is lb <= x <= valid range below(x*), the other valid range above(x*) <= x <= ub.
+      Specify way = -1 to set the object state to perform the down arm first,
+      way = 1 for the up arm.
+    */
+    CbcLotsizeBranchingObject (CbcModel *model, int variable,
+                               int way , double value, const CbcLotsize * lotsize) ;
+
+    /** Create a degenerate branch object
+
+      Specifies a `one-way branch'. Calling branch() for this object will
+      always result in lowerValue <= x <= upperValue. Used to fix in valid range
+    */
+
+    CbcLotsizeBranchingObject (CbcModel *model, int variable, int way,
+                               double lowerValue, double upperValue) ;
+
+    /// Copy constructor
+    CbcLotsizeBranchingObject ( const CbcLotsizeBranchingObject &);
+
+    /// Assignment operator
+    CbcLotsizeBranchingObject & operator= (const CbcLotsizeBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    /// Destructor
+    virtual ~CbcLotsizeBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /** \brief Sets the bounds for the variable according to the current arm
+           of the branch and advances the object state to the next arm.
+    */
+    virtual double branch();
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return LotsizeBranchObj;
+    }
+
+    // LL: compareOriginalObject can be inherited from the CbcBranchingObject
+    // since variable_ uniquely defines the lot sizing object.
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+protected:
+    /// Lower [0] and upper [1] bounds for the down arm (way_ = -1)
+    double down_[2];
+    /// Lower [0] and upper [1] bounds for the up arm (way_ = 1)
+    double up_[2];
+};
+
+#endif
+
diff --git a/cbits/coin/CbcBranchToFixLots.cpp b/cbits/coin/CbcBranchToFixLots.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchToFixLots.cpp
@@ -0,0 +1,571 @@
+// $Id: CbcBranchToFixLots.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/13/2009-- carved out of CbcBranchCut
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchCut.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+#include "CbcBranchToFixLots.hpp"
+
+/** Default Constructor
+
+  Equivalent to an unspecified binary variable.
+*/
+CbcBranchToFixLots::CbcBranchToFixLots ()
+        : CbcBranchCut(),
+        djTolerance_(COIN_DBL_MAX),
+        fractionFixed_(1.0),
+        mark_(NULL),
+        depth_(-1),
+        numberClean_(0),
+        alwaysCreate_(false)
+{
+}
+
+/* Useful constructor - passed reduced cost tolerance and fraction we would like fixed.
+   Also depth level to do at.
+   Also passed number of 1 rows which when clean triggers fix
+   Always does if all 1 rows cleaned up and number>0 or if fraction columns reached
+   Also whether to create branch if can't reach fraction.
+*/
+CbcBranchToFixLots::CbcBranchToFixLots (CbcModel * model, double djTolerance,
+                                        double fractionFixed, int depth,
+                                        int numberClean,
+                                        const char * mark, bool alwaysCreate)
+        : CbcBranchCut(model)
+{
+    djTolerance_ = djTolerance;
+    fractionFixed_ = fractionFixed;
+    if (mark) {
+        int numberColumns = model->getNumCols();
+        mark_ = new char[numberColumns];
+        memcpy(mark_, mark, numberColumns);
+    } else {
+        mark_ = NULL;
+    }
+    depth_ = depth;
+    assert (model);
+    OsiSolverInterface * solver = model_->solver();
+    matrixByRow_ = *solver->getMatrixByRow();
+    numberClean_ = numberClean;
+    alwaysCreate_ = alwaysCreate;
+}
+// Copy constructor
+CbcBranchToFixLots::CbcBranchToFixLots ( const CbcBranchToFixLots & rhs)
+        : CbcBranchCut(rhs)
+{
+    djTolerance_ = rhs.djTolerance_;
+    fractionFixed_ = rhs.fractionFixed_;
+    int numberColumns = model_->getNumCols();
+    mark_ = CoinCopyOfArray(rhs.mark_, numberColumns);
+    matrixByRow_ = rhs.matrixByRow_;
+    depth_ = rhs.depth_;
+    numberClean_ = rhs.numberClean_;
+    alwaysCreate_ = rhs.alwaysCreate_;
+}
+
+// Clone
+CbcObject *
+CbcBranchToFixLots::clone() const
+{
+    return new CbcBranchToFixLots(*this);
+}
+
+// Assignment operator
+CbcBranchToFixLots &
+CbcBranchToFixLots::operator=( const CbcBranchToFixLots & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchCut::operator=(rhs);
+        djTolerance_ = rhs.djTolerance_;
+        fractionFixed_ = rhs.fractionFixed_;
+        int numberColumns = model_->getNumCols();
+        delete [] mark_;
+        mark_ = CoinCopyOfArray(rhs.mark_, numberColumns);
+        matrixByRow_ = rhs.matrixByRow_;
+        depth_ = rhs.depth_;
+        numberClean_ = rhs.numberClean_;
+        alwaysCreate_ = rhs.alwaysCreate_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcBranchToFixLots::~CbcBranchToFixLots ()
+{
+    delete [] mark_;
+}
+CbcBranchingObject *
+CbcBranchToFixLots::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int /*way*/)
+{
+    // by default way must be -1
+    //assert (way==-1);
+    //OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    const double * dj = solver->getReducedCost();
+    int i;
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    // make smaller ?
+    double tolerance = CoinMin(1.0e-8, integerTolerance);
+    // How many fixed are we aiming at
+    int wantedFixed = static_cast<int> (static_cast<double>(numberIntegers) * fractionFixed_);
+    int nSort = 0;
+    int numberFixed = 0;
+    int numberColumns = solver->getNumCols();
+    int * sort = new int[numberColumns];
+    double * dsort = new double[numberColumns];
+    if (djTolerance_ != -1.234567) {
+        int type = shallWe();
+        assert (type);
+        // Take clean first
+        if (type == 1) {
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                if (upper[iColumn] > lower[iColumn]) {
+                    if (!mark_ || !mark_[iColumn]) {
+                        if (solution[iColumn] < lower[iColumn] + tolerance) {
+                            if (dj[iColumn] > djTolerance_) {
+                                dsort[nSort] = -dj[iColumn];
+                                sort[nSort++] = iColumn;
+                            }
+                        } else if (solution[iColumn] > upper[iColumn] - tolerance) {
+                            if (dj[iColumn] < -djTolerance_) {
+                                dsort[nSort] = dj[iColumn];
+                                sort[nSort++] = iColumn;
+                            }
+                        }
+                    }
+                } else {
+                    numberFixed++;
+                }
+            }
+            // sort
+            CoinSort_2(dsort, dsort + nSort, sort);
+            nSort = CoinMin(nSort, wantedFixed - numberFixed);
+        } else if (type < 10) {
+            int i;
+            //const double * rowLower = solver->getRowLower();
+            const double * rowUpper = solver->getRowUpper();
+            // Row copy
+            const double * elementByRow = matrixByRow_.getElements();
+            const int * column = matrixByRow_.getIndices();
+            const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+            const int * rowLength = matrixByRow_.getVectorLengths();
+            const double * columnLower = solver->getColLower();
+            const double * columnUpper = solver->getColUpper();
+            const double * solution = solver->getColSolution();
+            int numberColumns = solver->getNumCols();
+            int numberRows = solver->getNumRows();
+            for (i = 0; i < numberColumns; i++) {
+                sort[i] = i;
+                if (columnLower[i] != columnUpper[i]) {
+                    dsort[i] = 1.0e100;
+                } else {
+                    dsort[i] = 1.0e50;
+                    numberFixed++;
+                }
+            }
+            for (i = 0; i < numberRows; i++) {
+                double rhsValue = rowUpper[i];
+                bool oneRow = true;
+                // check elements
+                int numberUnsatisfied = 0;
+                for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                    int iColumn = column[j];
+                    double value = elementByRow[j];
+                    double solValue = solution[iColumn];
+                    if (columnLower[iColumn] != columnUpper[iColumn]) {
+                        if (solValue < 1.0 - integerTolerance && solValue > integerTolerance)
+                            numberUnsatisfied++;
+                        if (value != 1.0) {
+                            oneRow = false;
+                            break;
+                        }
+                    } else {
+                        rhsValue -= value * floor(solValue + 0.5);
+                    }
+                }
+                if (oneRow && rhsValue <= 1.0 + tolerance) {
+                    if (!numberUnsatisfied) {
+                        for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                            int iColumn = column[j];
+                            if (dsort[iColumn] > 1.0e50) {
+                                dsort[iColumn] = 0;
+                                nSort++;
+                            }
+                        }
+                    }
+                }
+            }
+            // sort
+            CoinSort_2(dsort, dsort + numberColumns, sort);
+        } else {
+            // new way
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                if (upper[iColumn] > lower[iColumn]) {
+                    if (!mark_ || !mark_[iColumn]) {
+                        double distanceDown = solution[iColumn] - lower[iColumn];
+                        double distanceUp = upper[iColumn] - solution[iColumn];
+                        double distance = CoinMin(distanceDown, distanceUp);
+                        if (distance > 0.001 && distance < 0.5) {
+                            dsort[nSort] = distance;
+                            sort[nSort++] = iColumn;
+                        }
+                    }
+                }
+            }
+            // sort
+            CoinSort_2(dsort, dsort + nSort, sort);
+            int n = 0;
+            double sum = 0.0;
+            for (int k = 0; k < nSort; k++) {
+                sum += dsort[k];
+                if (sum <= djTolerance_)
+                    n = k;
+                else
+                    break;
+            }
+            nSort = CoinMin(n, numberClean_ / 1000000);
+        }
+    } else {
+#define FIX_IF_LESS -0.1
+        // 3 in same row and sum <FIX_IF_LESS?
+        int numberRows = matrixByRow_.getNumRows();
+        const double * solution = model_->testSolution();
+        const int * column = matrixByRow_.getIndices();
+        const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+        const int * rowLength = matrixByRow_.getVectorLengths();
+        double bestSum = 1.0;
+        int nBest = -1;
+        int kRow = -1;
+        OsiSolverInterface * solver = model_->solver();
+        for (int i = 0; i < numberRows; i++) {
+            int numberUnsatisfied = 0;
+            double sum = 0.0;
+            for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                int iColumn = column[j];
+                if (solver->isInteger(iColumn)) {
+                    double solValue = solution[iColumn];
+                    if (solValue > 1.0e-5 && solValue < FIX_IF_LESS) {
+                        numberUnsatisfied++;
+                        sum += solValue;
+                    }
+                }
+            }
+            if (numberUnsatisfied >= 3 && sum < FIX_IF_LESS) {
+                // possible
+                if (numberUnsatisfied > nBest ||
+                        (numberUnsatisfied == nBest && sum < bestSum)) {
+                    nBest = numberUnsatisfied;
+                    bestSum = sum;
+                    kRow = i;
+                }
+            }
+        }
+        assert (nBest > 0);
+        for (int j = rowStart[kRow]; j < rowStart[kRow] + rowLength[kRow]; j++) {
+            int iColumn = column[j];
+            if (solver->isInteger(iColumn)) {
+                double solValue = solution[iColumn];
+                if (solValue > 1.0e-5 && solValue < FIX_IF_LESS) {
+                    sort[nSort++] = iColumn;
+                }
+            }
+        }
+    }
+    OsiRowCut down;
+    down.setLb(-COIN_DBL_MAX);
+    double rhs = 0.0;
+    for (i = 0; i < nSort; i++) {
+        int iColumn = sort[i];
+        double distanceDown = solution[iColumn] - lower[iColumn];
+        double distanceUp = upper[iColumn] - solution[iColumn];
+        if (distanceDown < distanceUp) {
+            rhs += lower[iColumn];
+            dsort[i] = 1.0;
+        } else {
+            rhs -= upper[iColumn];
+            dsort[i] = -1.0;
+        }
+    }
+    down.setUb(rhs);
+    down.setRow(nSort, sort, dsort);
+    down.setEffectiveness(COIN_DBL_MAX); // so will persist
+    delete [] sort;
+    delete [] dsort;
+    // up is same - just with rhs changed
+    OsiRowCut up = down;
+    up.setLb(rhs + 1.0);
+    up.setUb(COIN_DBL_MAX);
+    // Say can fix one way
+    CbcCutBranchingObject * newObject =
+        new CbcCutBranchingObject(model_, down, up, true);
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("creating cut in CbcBranchCut\n");
+    return newObject;
+}
+/* Does a lot of the work,
+   Returns 0 if no good, 1 if dj, 2 if clean, 3 if both
+   10 if branching on ones away from bound
+*/
+int
+CbcBranchToFixLots::shallWe() const
+{
+    int returnCode = 0;
+    OsiSolverInterface * solver = model_->solver();
+    int numberRows = matrixByRow_.getNumRows();
+    //if (numberRows!=solver->getNumRows())
+    //return 0;
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    const double * dj = solver->getReducedCost();
+    int i;
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    if (numberClean_ > 1000000) {
+        int wanted = numberClean_ % 1000000;
+        int * sort = new int[numberIntegers];
+        double * dsort = new double[numberIntegers];
+        int nSort = 0;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            if (upper[iColumn] > lower[iColumn]) {
+                if (!mark_ || !mark_[iColumn]) {
+                    double distanceDown = solution[iColumn] - lower[iColumn];
+                    double distanceUp = upper[iColumn] - solution[iColumn];
+                    double distance = CoinMin(distanceDown, distanceUp);
+                    if (distance > 0.001 && distance < 0.5) {
+                        dsort[nSort] = distance;
+                        sort[nSort++] = iColumn;
+                    }
+                }
+            }
+        }
+        // sort
+        CoinSort_2(dsort, dsort + nSort, sort);
+        int n = 0;
+        double sum = 0.0;
+        for (int k = 0; k < nSort; k++) {
+            sum += dsort[k];
+            if (sum <= djTolerance_)
+                n = k;
+            else
+                break;
+        }
+        delete [] sort;
+        delete [] dsort;
+        return (n >= wanted) ? 10 : 0;
+    }
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    // make smaller ?
+    double tolerance = CoinMin(1.0e-8, integerTolerance);
+    // How many fixed are we aiming at
+    int wantedFixed = static_cast<int> (static_cast<double>(numberIntegers) * fractionFixed_);
+    if (djTolerance_ < 1.0e10) {
+        int nSort = 0;
+        int numberFixed = 0;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            if (upper[iColumn] > lower[iColumn]) {
+                if (!mark_ || !mark_[iColumn]) {
+                    if (solution[iColumn] < lower[iColumn] + tolerance) {
+                        if (dj[iColumn] > djTolerance_) {
+                            nSort++;
+                        }
+                    } else if (solution[iColumn] > upper[iColumn] - tolerance) {
+                        if (dj[iColumn] < -djTolerance_) {
+                            nSort++;
+                        }
+                    }
+                }
+            } else {
+                numberFixed++;
+            }
+        }
+        if (numberFixed + nSort < wantedFixed && !alwaysCreate_) {
+            returnCode = 0;
+        } else if (numberFixed < wantedFixed) {
+            returnCode = 1;
+        } else {
+            returnCode = 0;
+        }
+    }
+    if (numberClean_) {
+        // see how many rows clean
+        int i;
+        //const double * rowLower = solver->getRowLower();
+        const double * rowUpper = solver->getRowUpper();
+        // Row copy
+        const double * elementByRow = matrixByRow_.getElements();
+        const int * column = matrixByRow_.getIndices();
+        const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+        const int * rowLength = matrixByRow_.getVectorLengths();
+        const double * columnLower = solver->getColLower();
+        const double * columnUpper = solver->getColUpper();
+        const double * solution = solver->getColSolution();
+        int numberClean = 0;
+        bool someToDoYet = false;
+        int numberColumns = solver->getNumCols();
+        char * mark = new char[numberColumns];
+        int numberFixed = 0;
+        for (i = 0; i < numberColumns; i++) {
+            if (columnLower[i] != columnUpper[i]) {
+                mark[i] = 0;
+            } else {
+                mark[i] = 1;
+                numberFixed++;
+            }
+        }
+        int numberNewFixed = 0;
+        for (i = 0; i < numberRows; i++) {
+            double rhsValue = rowUpper[i];
+            bool oneRow = true;
+            // check elements
+            int numberUnsatisfied = 0;
+            for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                int iColumn = column[j];
+                double value = elementByRow[j];
+                double solValue = solution[iColumn];
+                if (columnLower[iColumn] != columnUpper[iColumn]) {
+                    if (solValue < 1.0 - integerTolerance && solValue > integerTolerance)
+                        numberUnsatisfied++;
+                    if (value != 1.0) {
+                        oneRow = false;
+                        break;
+                    }
+                } else {
+                    rhsValue -= value * floor(solValue + 0.5);
+                }
+            }
+            if (oneRow && rhsValue <= 1.0 + tolerance) {
+                if (numberUnsatisfied) {
+                    someToDoYet = true;
+                } else {
+                    numberClean++;
+                    for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                        int iColumn = column[j];
+                        if (columnLower[iColumn] != columnUpper[iColumn] && !mark[iColumn]) {
+                            mark[iColumn] = 1;
+                            numberNewFixed++;
+                        }
+                    }
+                }
+            }
+        }
+        delete [] mark;
+        //printf("%d clean, %d old fixed, %d new fixed\n",
+        //   numberClean,numberFixed,numberNewFixed);
+        if (someToDoYet && numberClean < numberClean_
+                && numberNewFixed + numberFixed < wantedFixed) {
+        } else if (numberFixed < wantedFixed) {
+            returnCode |= 2;
+        } else {
+        }
+    }
+    return returnCode;
+}
+double
+CbcBranchToFixLots::infeasibility(const OsiBranchingInformation * /*info*/,
+                                  int &preferredWay) const
+{
+    preferredWay = -1;
+    CbcNode * node = model_->currentNode();
+    int depth;
+    if (node)
+        depth = CoinMax(node->depth(), 0);
+    else
+        return 0.0;
+    if (depth_ < 0) {
+        return 0.0;
+    } else if (depth_ > 0) {
+        if ((depth % depth_) != 0)
+            return 0.0;
+    }
+    if (djTolerance_ != -1.234567) {
+        if (!shallWe())
+            return 0.0;
+        else
+            return 1.0e20;
+    } else {
+        // See if 3 in same row and sum <FIX_IF_LESS?
+        int numberRows = matrixByRow_.getNumRows();
+        const double * solution = model_->testSolution();
+        const int * column = matrixByRow_.getIndices();
+        const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+        const int * rowLength = matrixByRow_.getVectorLengths();
+        double bestSum = 1.0;
+        int nBest = -1;
+        OsiSolverInterface * solver = model_->solver();
+        for (int i = 0; i < numberRows; i++) {
+            int numberUnsatisfied = 0;
+            double sum = 0.0;
+            for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                int iColumn = column[j];
+                if (solver->isInteger(iColumn)) {
+                    double solValue = solution[iColumn];
+                    if (solValue > 1.0e-5 && solValue < FIX_IF_LESS) {
+                        numberUnsatisfied++;
+                        sum += solValue;
+                    }
+                }
+            }
+            if (numberUnsatisfied >= 3 && sum < FIX_IF_LESS) {
+                // possible
+                if (numberUnsatisfied > nBest ||
+                        (numberUnsatisfied == nBest && sum < bestSum)) {
+                    nBest = numberUnsatisfied;
+                    bestSum = sum;
+                }
+            }
+        }
+        if (nBest > 0)
+            return 1.0e20;
+        else
+            return 0.0;
+    }
+}
+// Redoes data when sequence numbers change
+void
+CbcBranchToFixLots::redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns)
+{
+    model_ = model;
+    if (mark_) {
+        OsiSolverInterface * solver = model_->solver();
+        int numberColumnsNow = solver->getNumCols();
+        char * temp = new char[numberColumnsNow];
+        memset(temp, 0, numberColumnsNow);
+        for (int i = 0; i < numberColumns; i++) {
+            int j = originalColumns[i];
+            temp[i] = mark_[j];
+        }
+        delete [] mark_;
+        mark_ = temp;
+    }
+    OsiSolverInterface * solver = model_->solver();
+    matrixByRow_ = *solver->getMatrixByRow();
+}
+
diff --git a/cbits/coin/CbcBranchToFixLots.hpp b/cbits/coin/CbcBranchToFixLots.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchToFixLots.hpp
@@ -0,0 +1,94 @@
+// $Id: CbcBranchToFixLots.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/13/2009-- carved out of CbcBranchCut
+
+#ifndef CbcBranchToFixLots_H
+#define CbcBranchToFixLots_H
+
+#include "CbcBranchCut.hpp"
+#include "CbcBranchBase.hpp"
+#include "OsiRowCut.hpp"
+#include "CoinPackedMatrix.hpp"
+
+/** Define a branch class that branches so that one way variables are fixed
+    while the other way cuts off that solution.
+    a) On reduced cost
+    b) When enough ==1 or <=1 rows have been satisfied (not fixed - satisfied)
+*/
+
+
+class CbcBranchToFixLots : public CbcBranchCut {
+
+public:
+
+    // Default Constructor
+    CbcBranchToFixLots ();
+
+    /** Useful constructor - passed reduced cost tolerance and fraction we would like fixed.
+        Also depth level to do at.
+        Also passed number of 1 rows which when clean triggers fix
+        Always does if all 1 rows cleaned up and number>0 or if fraction columns reached
+        Also whether to create branch if can't reach fraction.
+    */
+    CbcBranchToFixLots (CbcModel * model, double djTolerance,
+                        double fractionFixed, int depth,
+                        int numberClean = 0,
+                        const char * mark = NULL,
+                        bool alwaysCreate = false);
+
+    // Copy constructor
+    CbcBranchToFixLots ( const CbcBranchToFixLots &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcBranchToFixLots & operator=( const CbcBranchToFixLots& rhs);
+
+    // Destructor
+    ~CbcBranchToFixLots ();
+
+    /** Does a lot of the work,
+        Returns 0 if no good, 1 if dj, 2 if clean, 3 if both
+	FIXME: should use enum or equivalent to make these numbers clearer.
+    */
+    int shallWe() const;
+
+    /// Infeasibility for an integer variable - large is 0.5, but also can be infinity when known infeasible.
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+    /** \brief Return true if object can take part in normal heuristics
+    */
+    virtual bool canDoHeuristics() const {
+        return true;
+    }
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+    /// Redoes data when sequence numbers change
+    virtual void redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns);
+
+
+protected:
+    /// data
+
+    /// Reduced cost tolerance i.e. dj has to be >= this before fixed
+    double djTolerance_;
+    /// We only need to make sure this fraction fixed
+    double fractionFixed_;
+    /// Never fix ones marked here
+    char * mark_;
+    /// Matrix by row
+    CoinPackedMatrix matrixByRow_;
+    /// Do if depth multiple of this
+    int depth_;
+    /// number of ==1 rows which need to be clean
+    int numberClean_;
+    /// If true then always create branch
+    bool alwaysCreate_;
+};
+#endif
+
diff --git a/cbits/coin/CbcBranchingObject.cpp b/cbits/coin/CbcBranchingObject.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchingObject.cpp
@@ -0,0 +1,74 @@
+// $Id: CbcBranchingObject.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "OsiChooseVariable.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchBase.hpp"
+
+
+// Default Constructor
+CbcBranchingObject::CbcBranchingObject()
+        : OsiBranchingObject()
+{
+    model_ = NULL;
+    originalCbcObject_ = NULL;
+    variable_ = -1;
+    way_ = 0;
+}
+
+// Useful constructor
+CbcBranchingObject::CbcBranchingObject (CbcModel * model, int variable, int way , double value)
+        : OsiBranchingObject(model->solver(), value)
+{
+    model_ = model;
+    originalCbcObject_ = NULL;
+    variable_ = variable;
+    way_ = way;
+}
+
+// Copy constructor
+CbcBranchingObject::CbcBranchingObject ( const CbcBranchingObject & rhs)
+        : OsiBranchingObject(rhs)
+{
+    model_ = rhs.model_;
+    originalCbcObject_ = rhs.originalCbcObject_;
+    variable_ = rhs.variable_;
+    way_ = rhs.way_;
+    value_ = rhs.value_;
+}
+
+// Assignment operator
+CbcBranchingObject &
+CbcBranchingObject::operator=( const CbcBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        OsiBranchingObject::operator=(rhs);
+        model_ = rhs.model_;
+        originalCbcObject_ = rhs.originalCbcObject_;
+        variable_ = rhs.variable_;
+        way_ = rhs.way_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcBranchingObject::~CbcBranchingObject ()
+{
+}
+
diff --git a/cbits/coin/CbcBranchingObject.hpp b/cbits/coin/CbcBranchingObject.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcBranchingObject.hpp
@@ -0,0 +1,236 @@
+// $Id: CbcBranchingObject.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#ifndef CbcBranchingObject_H
+#define CbcBranchingObject_H
+
+#include <string>
+#include <vector>
+#include "CbcBranchBase.hpp"
+#include "OsiBranchingObject.hpp"
+
+
+// The types of objects that will be derived from this class.
+enum CbcBranchObjType
+  {
+    SimpleIntegerBranchObj = 100,
+    SimpleIntegerDynamicPseudoCostBranchObj = 101,
+    CliqueBranchObj = 102,
+    LongCliqueBranchObj = 103,
+    SoSBranchObj = 104,
+    NWayBranchObj = 105,
+    FollowOnBranchObj = 106,
+    DummyBranchObj = 107,
+    GeneralDepthBranchObj = 108,
+    OneGeneralBranchingObj = 110,
+    CutBranchingObj = 200,
+    LotsizeBranchObj = 300,
+    DynamicPseudoCostBranchObj = 400
+  };
+
+/** \brief Abstract branching object base class
+    Now just difference with OsiBranchingObject
+
+  In the abstract, an CbcBranchingObject contains instructions for how to
+  branch. We want an abstract class so that we can describe how to branch on
+  simple objects (<i>e.g.</i>, integers) and more exotic objects
+  (<i>e.g.</i>, cliques or hyperplanes).
+
+  The #branch() method is the crucial routine: it is expected to be able to
+  step through a set of branch arms, executing the actions required to create
+  each subproblem in turn. The base class is primarily virtual to allow for
+  a wide range of problem modifications.
+
+  See CbcObject for an overview of the three classes (CbcObject,
+  CbcBranchingObject, and CbcBranchDecision) which make up cbc's branching
+  model.
+*/
+
+class CbcBranchingObject : public OsiBranchingObject {
+
+public:
+
+    /// Default Constructor
+    CbcBranchingObject ();
+
+    /// Constructor
+    CbcBranchingObject (CbcModel * model, int variable, int way , double value);
+
+    /// Copy constructor
+    CbcBranchingObject ( const CbcBranchingObject &);
+
+    /// Assignment operator
+    CbcBranchingObject & operator=( const CbcBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const = 0;
+
+    /// Destructor
+    virtual ~CbcBranchingObject ();
+
+    /** Some branchingObjects may claim to be able to skip
+        strong branching.  If so they have to fill in CbcStrongInfo.
+        The object mention in incoming CbcStrongInfo must match.
+        Returns nonzero if skip is wanted */
+    virtual int fillStrongInfo( CbcStrongInfo & ) {
+        return 0;
+    }
+    /// Reset number of branches left to original
+    inline void resetNumberBranchesLeft() {
+        branchIndex_ = 0;
+    }
+    /// Set number of branches to do
+    inline void setNumberBranches(int value) {
+        branchIndex_ = 0;
+        numberBranches_ = value;
+    }
+
+    /** \brief Execute the actions required to branch, as specified by the
+           current state of the branching object, and advance the object's
+           state.  Mainly for diagnostics, whether it is true branch or
+           strong branching is also passed.
+           Returns change in guessed objective on next branch
+    */
+    virtual double branch() = 0;
+    /** \brief Execute the actions required to branch, as specified by the
+           current state of the branching object, and advance the object's
+           state.  Mainly for diagnostics, whether it is true branch or
+           strong branching is also passed.
+           Returns change in guessed objective on next branch
+    */
+    virtual double branch(OsiSolverInterface * ) {
+        return branch();
+    }
+    /** Update bounds in solver as in 'branch' and update given bounds.
+        branchState is -1 for 'down' +1 for 'up' */
+    virtual void fix(OsiSolverInterface * ,
+                     double * , double * ,
+                     int ) const {}
+
+    /** Change (tighten) bounds in object to reflect bounds in solver.
+	Return true if now fixed */
+    virtual bool tighten(OsiSolverInterface * ) {return false;}
+
+    /** Reset every information so that the branching object appears to point to
+        the previous child. This method does not need to modify anything in any
+        solver. */
+    virtual void previousBranch() {
+        assert(branchIndex_ > 0);
+        branchIndex_--;
+        way_ = -way_;
+    }
+
+    using OsiBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print() const {}
+
+    /** \brief Index identifying the associated CbcObject within its class.
+
+      The name is misleading, and typically the index will <i>not</i> refer
+      directly to a variable.
+      Rather, it identifies an CbcObject within the class of similar
+      CbcObjects
+
+      <i>E.g.</i>, for an CbcSimpleInteger, variable() is the index of the
+      integer variable in the set of integer variables (<i>not</i> the index of
+      the variable in the set of all variables).
+    */
+    inline int variable() const {
+        return variable_;
+    }
+
+    /** Get the state of the branching object
+
+      Returns a code indicating the active arm of the branching object.
+      The precise meaning is defined in the derived class.
+
+      \sa #way_
+    */
+    inline int way() const {
+        return way_;
+    }
+
+    /** Set the state of the branching object.
+
+      See #way()
+    */
+    inline void way(int way) {
+        way_ = way;
+    }
+
+    /// update model
+    inline void setModel(CbcModel * model) {
+        model_ = model;
+    }
+    /// Return model
+    inline CbcModel * model() const {
+        return  model_;
+    }
+
+    /// Return pointer back to object which created
+    inline CbcObject * object() const {
+        return  originalCbcObject_;
+    }
+    /// Set pointer back to object which created
+    inline void setOriginalObject(CbcObject * object) {
+        originalCbcObject_ = object;
+    }
+
+    // Methods used in heuristics
+
+    /** Return the type (an integer identifier) of \c this.
+        See definition of CbcBranchObjType above for possibilities
+    */
+    
+    virtual CbcBranchObjType type() const = 0;
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const {
+        const CbcBranchingObject* br = dynamic_cast<const CbcBranchingObject*>(brObj);
+        return variable() - br->variable();
+    }
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be of the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false) = 0;
+
+protected:
+
+    /// The model that owns this branching object
+    CbcModel * model_;
+    /// Pointer back to object which created
+    CbcObject * originalCbcObject_;
+
+    /// Branching variable (0 is first integer)
+    int variable_;
+    // was - Way to branch - -1 down (first), 1 up, -2 down (second), 2 up (second)
+    /** The state of the branching object.
+
+      Specifies the active arm of the branching object. Coded as -1 to take
+      the `down' arm, +1 for the `up' arm. `Down' and `up' are defined based on
+      the natural meaning (floor and ceiling, respectively) for a simple integer.
+      The precise meaning is defined in the derived class.
+    */
+    int way_;
+
+};
+#endif
+
diff --git a/cbits/coin/CbcCbcParam.cpp b/cbits/coin/CbcCbcParam.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCbcParam.cpp
@@ -0,0 +1,11 @@
+/* $Id: CbcCbcParam.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CbcConfig.h"
+#ifndef COIN_HAS_CBC
+#define COIN_HAS_CBC
+#endif
+#include "CbcOrClpParam.cpp"
+
diff --git a/cbits/coin/CbcClique.cpp b/cbits/coin/CbcClique.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcClique.cpp
@@ -0,0 +1,874 @@
+// $Id: CbcClique.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/9/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcClique.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+//##############################################################################
+
+// Default Constructor
+CbcClique::CbcClique ()
+        : CbcObject(),
+        numberMembers_(0),
+        numberNonSOSMembers_(0),
+        members_(NULL),
+        type_(NULL),
+        cliqueType_(-1),
+        slack_(-1)
+{
+}
+
+// Useful constructor (which are integer indices)
+CbcClique::CbcClique (CbcModel * model, int cliqueType, int numberMembers,
+                      const int * which, const char * type, int identifier, int slack)
+        : CbcObject(model)
+{
+    id_ = identifier;
+    numberMembers_ = numberMembers;
+    if (numberMembers_) {
+        members_ = new int[numberMembers_];
+        memcpy(members_, which, numberMembers_*sizeof(int));
+        type_ = new char[numberMembers_];
+        if (type) {
+            memcpy(type_, type, numberMembers_*sizeof(char));
+        } else {
+            for (int i = 0; i < numberMembers_; i++)
+                type_[i] = 1;
+        }
+    } else {
+        members_ = NULL;
+        type_ = NULL;
+    }
+    // Find out how many non sos
+    int i;
+    numberNonSOSMembers_ = 0;
+    for (i = 0; i < numberMembers_; i++)
+        if (!type_[i])
+            numberNonSOSMembers_++;
+    cliqueType_ = cliqueType;
+    slack_ = slack;
+}
+
+// Copy constructor
+CbcClique::CbcClique ( const CbcClique & rhs)
+        : CbcObject(rhs)
+{
+    numberMembers_ = rhs.numberMembers_;
+    numberNonSOSMembers_ = rhs.numberNonSOSMembers_;
+    if (numberMembers_) {
+        members_ = new int[numberMembers_];
+        memcpy(members_, rhs.members_, numberMembers_*sizeof(int));
+        type_ = new char[numberMembers_];
+        memcpy(type_, rhs.type_, numberMembers_*sizeof(char));
+    } else {
+        members_ = NULL;
+        type_ = NULL;
+    }
+    cliqueType_ = rhs.cliqueType_;
+    slack_ = rhs.slack_;
+}
+
+// Clone
+CbcObject *
+CbcClique::clone() const
+{
+    return new CbcClique(*this);
+}
+
+// Assignment operator
+CbcClique &
+CbcClique::operator=( const CbcClique & rhs)
+{
+    if (this != &rhs) {
+        CbcObject::operator=(rhs);
+        delete [] members_;
+        delete [] type_;
+        numberMembers_ = rhs.numberMembers_;
+        numberNonSOSMembers_ = rhs.numberNonSOSMembers_;
+        if (numberMembers_) {
+            members_ = new int[numberMembers_];
+            memcpy(members_, rhs.members_, numberMembers_*sizeof(int));
+            type_ = new char[numberMembers_];
+            memcpy(type_, rhs.type_, numberMembers_*sizeof(char));
+        } else {
+            members_ = NULL;
+            type_ = NULL;
+        }
+        cliqueType_ = rhs.cliqueType_;
+        slack_ = rhs.slack_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcClique::~CbcClique ()
+{
+    delete [] members_;
+    delete [] type_;
+}
+/*
+  Unfortunately, that comment is untrue. And there are other issues. This
+  routine is clearly an unfinished work.
+*/
+double
+CbcClique::infeasibility(const OsiBranchingInformation * /*info*/,
+                         int &preferredWay) const
+{
+    int numberUnsatis = 0, numberFree = 0;
+    int j;
+    const int * integer = model_->integerVariable();
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double largestValue = 0.0;
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double * sort = new double[numberMembers_];
+    /*
+      Calculate integer infeasibility and fill an array. Pick off the infeasibility
+      of the slack and the max infeasibility while we're at it. You can see here
+      the conversion of `non-SOS' (strong value of 0, negative coefficient) to
+      `SOS' (strong value of 1, positive coefficient). Also count the number of
+      variables that have integral values but are not fixed.
+    */
+    double slackValue = 0.0;
+    for (j = 0; j < numberMembers_; j++) {
+        int sequence = members_[j];
+        int iColumn = integer[sequence];
+        double value = solution[iColumn];
+        value = CoinMax(value, lower[iColumn]);
+        value = CoinMin(value, upper[iColumn]);
+        double nearest = floor(value + 0.5);
+        double distance = fabs(value - nearest);
+        if (distance > integerTolerance) {
+            if (!type_[j])
+                value = 1.0 - value; // non SOS
+            // if slack then choose that
+            if (j == slack_ && value > 0.05)
+                slackValue = value;
+            largestValue = CoinMax(value, largestValue);
+            sort[numberUnsatis++] = -value;
+        } else if (upper[iColumn] > lower[iColumn]) {
+            numberFree++;
+        }
+    }
+    /*
+      preferredWay will not change. The calculation of otherWay is an expensive
+      noop --- value is ultimately unused. Same for the sort of sort. It looks like
+      there was some notion of branching by splitting the set using even and odd
+      indices (as opposed to first and second half).
+    */
+    preferredWay = 1;
+    double otherWay = 0.0;
+    if (numberUnsatis) {
+        // sort
+        std::sort(sort, sort + numberUnsatis);
+        for (j = 0; j < numberUnsatis; j++) {
+            if ((j&1) != 0)
+                otherWay += -sort[j];
+        }
+        // Need to think more
+        /*
+          Here we have the actual infeasibility calculation. Most previous work is
+          discarded, and we calculate a value using various counts, adjusted by the
+          max value and slack value. This is not scaled to [0, .5].
+        */
+
+        double value = 0.2 * numberUnsatis + 0.01 * (numberMembers_ - numberFree);
+        if (fabs(largestValue - 0.5) < 0.1) {
+            // close to half
+            value += 0.1;
+        }
+        if (slackValue) {
+            // branching on slack
+            value += slackValue;
+        }
+        // scale other way
+        otherWay *= value / (1.0 - otherWay);
+        delete [] sort;
+        return value;
+    } else {
+        delete [] sort;
+        return 0.0; // satisfied
+    }
+}
+
+// This looks at solution and sets bounds to contain solution
+void
+CbcClique::feasibleRegion()
+{
+    int j;
+    const int * integer = model_->integerVariable();
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+#ifndef NDEBUG
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+#endif
+    for (j = 0; j < numberMembers_; j++) {
+        int sequence = members_[j];
+        int iColumn = integer[sequence];
+        double value = solution[iColumn];
+        value = CoinMax(value, lower[iColumn]);
+        value = CoinMin(value, upper[iColumn]);
+        double nearest = floor(value + 0.5);
+#ifndef NDEBUG
+        double distance = fabs(value - nearest);
+        assert(distance <= integerTolerance);
+#endif
+        solver->setColLower(iColumn, nearest);
+        solver->setColUpper(iColumn, nearest);
+    }
+}
+// Redoes data when sequence numbers change
+void
+CbcClique::redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns)
+{
+    model_ = model;
+    int n2 = 0;
+    for (int j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        int i;
+        for (i = 0; i < numberColumns; i++) {
+            if (originalColumns[i] == iColumn)
+                break;
+        }
+        if (i < numberColumns) {
+            members_[n2] = i;
+            type_[n2++] = type_[j];
+        }
+    }
+    if (n2 < numberMembers_) {
+        //printf("** SOS number of members reduced from %d to %d!\n",numberMembers_,n2);
+        numberMembers_ = n2;
+    }
+    // Find out how many non sos
+    int i;
+    numberNonSOSMembers_ = 0;
+    for (i = 0; i < numberMembers_; i++)
+        if (!type_[i])
+            numberNonSOSMembers_++;
+}
+CbcBranchingObject *
+CbcClique::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int way)
+{
+    int numberUnsatis = 0;
+    int j;
+    int nUp = 0;
+    int nDown = 0;
+    int numberFree = numberMembers_;
+    const int * integer = model_->integerVariable();
+    //OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    int * upList = new int[numberMembers_];
+    int * downList = new int[numberMembers_];
+    double * sort = new double[numberMembers_];
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    double slackValue = 0.0;
+    for (j = 0; j < numberMembers_; j++) {
+        int sequence = members_[j];
+        int iColumn = integer[sequence];
+        double value = solution[iColumn];
+        value = CoinMax(value, lower[iColumn]);
+        value = CoinMin(value, upper[iColumn]);
+        double nearest = floor(value + 0.5);
+        double distance = fabs(value - nearest);
+        if (distance > integerTolerance) {
+            if (!type_[j])
+                value = 1.0 - value; // non SOS
+            // if slack then choose that
+            if (j == slack_ && value > 0.05)
+                slackValue = value;
+            value = -value; // for sort
+            upList[numberUnsatis] = j;
+            sort[numberUnsatis++] = value;
+        } else if (upper[iColumn] > lower[iColumn]) {
+            upList[--numberFree] = j;
+        }
+    }
+    assert (numberUnsatis);
+    if (!slackValue) {
+        // sort
+        CoinSort_2(sort, sort + numberUnsatis, upList);
+        // put first in up etc
+        int kWay = 1;
+        for (j = 0; j < numberUnsatis; j++) {
+            if (kWay > 0)
+                upList[nUp++] = upList[j];
+            else
+                downList[nDown++] = upList[j];
+            kWay = -kWay;
+        }
+        for (j = numberFree; j < numberMembers_; j++) {
+            if (kWay > 0)
+                upList[nUp++] = upList[j];
+            else
+                downList[nDown++] = upList[j];
+            kWay = -kWay;
+        }
+    } else {
+        // put slack to 0 in first way
+        nUp = 1;
+        upList[0] = slack_;
+        for (j = 0; j < numberUnsatis; j++) {
+            downList[nDown++] = upList[j];
+        }
+        for (j = numberFree; j < numberMembers_; j++) {
+            downList[nDown++] = upList[j];
+        }
+    }
+    // create object
+    CbcBranchingObject * branch;
+    if (numberMembers_ <= 64)
+        branch = new CbcCliqueBranchingObject(model_, this, way,
+                                              nDown, downList, nUp, upList);
+    else
+        branch = new CbcLongCliqueBranchingObject(model_, this, way,
+                nDown, downList, nUp, upList);
+    delete [] upList;
+    delete [] downList;
+    delete [] sort;
+    return branch;
+}
+
+// Default Constructor
+CbcCliqueBranchingObject::CbcCliqueBranchingObject()
+        : CbcBranchingObject()
+{
+    clique_ = NULL;
+    downMask_[0] = 0;
+    downMask_[1] = 0;
+    upMask_[0] = 0;
+    upMask_[1] = 0;
+}
+
+// Useful constructor
+CbcCliqueBranchingObject::CbcCliqueBranchingObject (CbcModel * model,
+        const CbcClique * clique,
+        int way ,
+        int numberOnDownSide, const int * down,
+        int numberOnUpSide, const int * up)
+        : CbcBranchingObject(model, clique->id(), way, 0.5)
+{
+    clique_ = clique;
+    downMask_[0] = 0;
+    downMask_[1] = 0;
+    upMask_[0] = 0;
+    upMask_[1] = 0;
+    int i;
+    for (i = 0; i < numberOnDownSide; i++) {
+        int sequence = down[i];
+        int iWord = sequence >> 5;
+        int iBit = sequence - 32 * iWord;
+        unsigned int k = 1 << iBit;
+        downMask_[iWord] |= k;
+    }
+    for (i = 0; i < numberOnUpSide; i++) {
+        int sequence = up[i];
+        int iWord = sequence >> 5;
+        int iBit = sequence - 32 * iWord;
+        unsigned int k = 1 << iBit;
+        upMask_[iWord] |= k;
+    }
+}
+
+// Copy constructor
+CbcCliqueBranchingObject::CbcCliqueBranchingObject ( const CbcCliqueBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+    clique_ = rhs.clique_;
+    downMask_[0] = rhs.downMask_[0];
+    downMask_[1] = rhs.downMask_[1];
+    upMask_[0] = rhs.upMask_[0];
+    upMask_[1] = rhs.upMask_[1];
+}
+
+// Assignment operator
+CbcCliqueBranchingObject &
+CbcCliqueBranchingObject::operator=( const CbcCliqueBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        clique_ = rhs.clique_;
+        downMask_[0] = rhs.downMask_[0];
+        downMask_[1] = rhs.downMask_[1];
+        upMask_[0] = rhs.upMask_[0];
+        upMask_[1] = rhs.upMask_[1];
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcCliqueBranchingObject::clone() const
+{
+    return (new CbcCliqueBranchingObject(*this));
+}
+
+
+// Destructor
+CbcCliqueBranchingObject::~CbcCliqueBranchingObject ()
+{
+}
+double
+CbcCliqueBranchingObject::branch()
+{
+    decrementNumberBranchesLeft();
+    int iWord;
+    int numberMembers = clique_->numberMembers();
+    const int * which = clique_->members();
+    const int * integerVariables = model_->integerVariable();
+    int numberWords = (numberMembers + 31) >> 5;
+    // *** for way - up means fix all those in down section
+    if (way_ < 0) {
+#ifdef FULL_PRINT
+        printf("Down Fix ");
+#endif
+        for (iWord = 0; iWord < numberWords; iWord++) {
+            int i;
+            for (i = 0; i < 32; i++) {
+                unsigned int k = 1 << i;
+                if ((upMask_[iWord]&k) != 0) {
+                    int iColumn = which[i+32*iWord];
+#ifdef FULL_PRINT
+                    printf("%d ", i + 32*iWord);
+#endif
+                    // fix weak way
+                    if (clique_->type(i + 32*iWord))
+                        model_->solver()->setColUpper(integerVariables[iColumn], 0.0);
+                    else
+                        model_->solver()->setColLower(integerVariables[iColumn], 1.0);
+                }
+            }
+        }
+        way_ = 1;	  // Swap direction
+    } else {
+#ifdef FULL_PRINT
+        printf("Up Fix ");
+#endif
+        for (iWord = 0; iWord < numberWords; iWord++) {
+            int i;
+            for (i = 0; i < 32; i++) {
+                unsigned int k = 1 << i;
+                if ((downMask_[iWord]&k) != 0) {
+                    int iColumn = which[i+32*iWord];
+#ifdef FULL_PRINT
+                    printf("%d ", i + 32*iWord);
+#endif
+                    // fix weak way
+                    if (clique_->type(i + 32*iWord))
+                        model_->solver()->setColUpper(integerVariables[iColumn], 0.0);
+                    else
+                        model_->solver()->setColLower(integerVariables[iColumn], 1.0);
+                }
+            }
+        }
+        way_ = -1;	  // Swap direction
+    }
+#ifdef FULL_PRINT
+    printf("\n");
+#endif
+    return 0.0;
+}
+// Print what would happen
+void
+CbcCliqueBranchingObject::print()
+{
+    int iWord;
+    int numberMembers = clique_->numberMembers();
+    const int * which = clique_->members();
+    const int * integerVariables = model_->integerVariable();
+    int numberWords = (numberMembers + 31) >> 5;
+    // *** for way - up means fix all those in down section
+    if (way_ < 0) {
+        printf("Clique - Down Fix ");
+        for (iWord = 0; iWord < numberWords; iWord++) {
+            int i;
+            for (i = 0; i < 32; i++) {
+                unsigned int k = 1 << i;
+                if ((upMask_[iWord]&k) != 0) {
+                    int iColumn = which[i+32*iWord];
+                    printf("%d ", integerVariables[iColumn]);
+                }
+            }
+        }
+    } else {
+        printf("Clique - Up Fix ");
+        for (iWord = 0; iWord < numberWords; iWord++) {
+            int i;
+            for (i = 0; i < 32; i++) {
+                unsigned int k = 1 << i;
+                if ((downMask_[iWord]&k) != 0) {
+                    int iColumn = which[i+32*iWord];
+                    printf("%d ", integerVariables[iColumn]);
+                }
+            }
+        }
+    }
+    printf("\n");
+}
+
+static inline int
+CbcCompareCliques(const CbcClique* cl0, const CbcClique* cl1)
+{
+    if (cl0->cliqueType() < cl1->cliqueType()) {
+        return -1;
+    }
+    if (cl0->cliqueType() > cl1->cliqueType()) {
+        return 1;
+    }
+    if (cl0->numberMembers() != cl1->numberMembers()) {
+        return cl0->numberMembers() - cl1->numberMembers();
+    }
+    if (cl0->numberNonSOSMembers() != cl1->numberNonSOSMembers()) {
+        return cl0->numberNonSOSMembers() - cl1->numberNonSOSMembers();
+    }
+    return memcmp(cl0->members(), cl1->members(),
+                  cl0->numberMembers() * sizeof(int));
+}
+
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcCliqueBranchingObject::compareOriginalObject
+(const CbcBranchingObject* brObj) const
+{
+    const CbcCliqueBranchingObject* br =
+        dynamic_cast<const CbcCliqueBranchingObject*>(brObj);
+    assert(br);
+    return CbcCompareCliques(clique_, br->clique_);
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcCliqueBranchingObject::compareBranchingObject
+(const CbcBranchingObject* brObj, const bool /*replaceIfOverlap*/)
+{
+    const CbcCliqueBranchingObject* br =
+        dynamic_cast<const CbcCliqueBranchingObject*>(brObj);
+    assert(br);
+    unsigned int* thisMask = way_ < 0 ? upMask_ : downMask_;
+    const unsigned int* otherMask = br->way_ < 0 ? br->upMask_ : br->downMask_;
+    const CoinUInt64 cl0 =
+        (static_cast<CoinUInt64>(thisMask[0]) << 32) | thisMask[1];
+    const CoinUInt64 cl1 =
+        (static_cast<CoinUInt64>(otherMask[0]) << 32) | otherMask[1];
+    if (cl0 == cl1) {
+        return CbcRangeSame;
+    }
+    const CoinUInt64 cl_intersection = (cl0 & cl1);
+    if (cl_intersection == cl0) {
+        return CbcRangeSuperset;
+    }
+    if (cl_intersection == cl1) {
+        return CbcRangeSubset;
+    }
+    const CoinUInt64 cl_xor = (cl0 ^ cl1);
+    if (cl_intersection == 0 && cl_xor == 0) {
+        return CbcRangeDisjoint;
+    }
+    const CoinUInt64 cl_union = (cl0 | cl1);
+    thisMask[0] = static_cast<unsigned int>(cl_union >> 32);
+    thisMask[1] = static_cast<unsigned int>(cl_union & 0xffffffff);
+    return CbcRangeOverlap;
+}
+
+//##############################################################################
+
+// Default Constructor
+CbcLongCliqueBranchingObject::CbcLongCliqueBranchingObject()
+        : CbcBranchingObject()
+{
+    clique_ = NULL;
+    downMask_ = NULL;
+    upMask_ = NULL;
+}
+
+// Useful constructor
+CbcLongCliqueBranchingObject::CbcLongCliqueBranchingObject (CbcModel * model,
+        const CbcClique * clique,
+        int way ,
+        int numberOnDownSide, const int * down,
+        int numberOnUpSide, const int * up)
+        : CbcBranchingObject(model, clique->id(), way, 0.5)
+{
+    clique_ = clique;
+    int numberMembers = clique_->numberMembers();
+    int numberWords = (numberMembers + 31) >> 5;
+    downMask_ = new unsigned int [numberWords];
+    upMask_ = new unsigned int [numberWords];
+    memset(downMask_, 0, numberWords*sizeof(unsigned int));
+    memset(upMask_, 0, numberWords*sizeof(unsigned int));
+    int i;
+    for (i = 0; i < numberOnDownSide; i++) {
+        int sequence = down[i];
+        int iWord = sequence >> 5;
+        int iBit = sequence - 32 * iWord;
+        unsigned int k = 1 << iBit;
+        downMask_[iWord] |= k;
+    }
+    for (i = 0; i < numberOnUpSide; i++) {
+        int sequence = up[i];
+        int iWord = sequence >> 5;
+        int iBit = sequence - 32 * iWord;
+        unsigned int k = 1 << iBit;
+        upMask_[iWord] |= k;
+    }
+}
+
+// Copy constructor
+CbcLongCliqueBranchingObject::CbcLongCliqueBranchingObject ( const CbcLongCliqueBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+    clique_ = rhs.clique_;
+    if (rhs.downMask_) {
+        int numberMembers = clique_->numberMembers();
+        int numberWords = (numberMembers + 31) >> 5;
+        downMask_ = new unsigned int [numberWords];
+        memcpy(downMask_, rhs.downMask_, numberWords*sizeof(unsigned int));
+        upMask_ = new unsigned int [numberWords];
+        memcpy(upMask_, rhs.upMask_, numberWords*sizeof(unsigned int));
+    } else {
+        downMask_ = NULL;
+        upMask_ = NULL;
+    }
+}
+
+// Assignment operator
+CbcLongCliqueBranchingObject &
+CbcLongCliqueBranchingObject::operator=( const CbcLongCliqueBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        clique_ = rhs.clique_;
+        delete [] downMask_;
+        delete [] upMask_;
+        if (rhs.downMask_) {
+            int numberMembers = clique_->numberMembers();
+            int numberWords = (numberMembers + 31) >> 5;
+            downMask_ = new unsigned int [numberWords];
+            memcpy(downMask_, rhs.downMask_, numberWords*sizeof(unsigned int));
+            upMask_ = new unsigned int [numberWords];
+            memcpy(upMask_, rhs.upMask_, numberWords*sizeof(unsigned int));
+        } else {
+            downMask_ = NULL;
+            upMask_ = NULL;
+        }
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcLongCliqueBranchingObject::clone() const
+{
+    return (new CbcLongCliqueBranchingObject(*this));
+}
+
+
+// Destructor
+CbcLongCliqueBranchingObject::~CbcLongCliqueBranchingObject ()
+{
+    delete [] downMask_;
+    delete [] upMask_;
+}
+double
+CbcLongCliqueBranchingObject::branch()
+{
+    decrementNumberBranchesLeft();
+    int iWord;
+    int numberMembers = clique_->numberMembers();
+    const int * which = clique_->members();
+    const int * integerVariables = model_->integerVariable();
+    int numberWords = (numberMembers + 31) >> 5;
+    // *** for way - up means fix all those in down section
+    if (way_ < 0) {
+#ifdef FULL_PRINT
+        printf("Down Fix ");
+#endif
+        for (iWord = 0; iWord < numberWords; iWord++) {
+            int i;
+            for (i = 0; i < 32; i++) {
+                unsigned int k = 1 << i;
+                if ((upMask_[iWord]&k) != 0) {
+                    int iColumn = which[i+32*iWord];
+#ifdef FULL_PRINT
+                    printf("%d ", i + 32*iWord);
+#endif
+                    // fix weak way
+                    if (clique_->type(i + 32*iWord))
+                        model_->solver()->setColUpper(integerVariables[iColumn], 0.0);
+                    else
+                        model_->solver()->setColLower(integerVariables[iColumn], 1.0);
+                }
+            }
+        }
+        way_ = 1;	  // Swap direction
+    } else {
+#ifdef FULL_PRINT
+        printf("Up Fix ");
+#endif
+        for (iWord = 0; iWord < numberWords; iWord++) {
+            int i;
+            for (i = 0; i < 32; i++) {
+                unsigned int k = 1 << i;
+                if ((downMask_[iWord]&k) != 0) {
+                    int iColumn = which[i+32*iWord];
+#ifdef FULL_PRINT
+                    printf("%d ", i + 32*iWord);
+#endif
+                    // fix weak way
+                    if (clique_->type(i + 32*iWord))
+                        model_->solver()->setColUpper(integerVariables[iColumn], 0.0);
+                    else
+                        model_->solver()->setColLower(integerVariables[iColumn], 1.0);
+                }
+            }
+        }
+        way_ = -1;	  // Swap direction
+    }
+#ifdef FULL_PRINT
+    printf("\n");
+#endif
+    return 0.0;
+}
+void
+CbcLongCliqueBranchingObject::print()
+{
+    int iWord;
+    int numberMembers = clique_->numberMembers();
+    const int * which = clique_->members();
+    const int * integerVariables = model_->integerVariable();
+    int numberWords = (numberMembers + 31) >> 5;
+    // *** for way - up means fix all those in down section
+    if (way_ < 0) {
+        printf("Clique - Down Fix ");
+        for (iWord = 0; iWord < numberWords; iWord++) {
+            int i;
+            for (i = 0; i < 32; i++) {
+                unsigned int k = 1 << i;
+                if ((upMask_[iWord]&k) != 0) {
+                    int iColumn = which[i+32*iWord];
+                    printf("%d ", integerVariables[iColumn]);
+                }
+            }
+        }
+    } else {
+        printf("Clique - Up Fix ");
+        for (iWord = 0; iWord < numberWords; iWord++) {
+            int i;
+            for (i = 0; i < 32; i++) {
+                unsigned int k = 1 << i;
+                if ((downMask_[iWord]&k) != 0) {
+                    int iColumn = which[i+32*iWord];
+                    printf("%d ", integerVariables[iColumn]);
+                }
+            }
+        }
+    }
+    printf("\n");
+}
+
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcLongCliqueBranchingObject::compareOriginalObject
+(const CbcBranchingObject* brObj) const
+{
+    const CbcLongCliqueBranchingObject* br =
+        dynamic_cast<const CbcLongCliqueBranchingObject*>(brObj);
+    assert(br);
+    return CbcCompareCliques(clique_, br->clique_);
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcLongCliqueBranchingObject::compareBranchingObject
+(const CbcBranchingObject* brObj, const bool /*replaceIfOverlap*/)
+{
+    const CbcLongCliqueBranchingObject* br =
+        dynamic_cast<const CbcLongCliqueBranchingObject*>(brObj);
+    assert(br);
+    const int numberMembers = clique_->numberMembers();
+    const int numberWords = (numberMembers + 31) >> 5;
+    unsigned int* thisMask = way_ < 0 ? upMask_ : downMask_;
+    const unsigned int* otherMask = br->way_ < 0 ? br->upMask_ : br->downMask_;
+
+    if (memcmp(thisMask, otherMask, numberWords * sizeof(unsigned int)) == 0) {
+        return CbcRangeSame;
+    }
+    bool canBeSuperset = true;
+    bool canBeSubset = true;
+    int i;
+    for (i = numberWords - 1; i >= 0 && (canBeSuperset || canBeSubset); --i) {
+        const unsigned int both = (thisMask[i] & otherMask[i]);
+        canBeSuperset &= (both == thisMask[i]);
+        canBeSubset &= (both == otherMask[i]);
+    }
+    if (canBeSuperset) {
+        return CbcRangeSuperset;
+    }
+    if (canBeSubset) {
+        return CbcRangeSubset;
+    }
+
+    for (i = numberWords - 1; i >= 0; --i) {
+        if ((thisMask[i] ^ otherMask[i]) != 0) {
+            break;
+        }
+    }
+    if (i == -1) { // complement
+        return CbcRangeDisjoint;
+    }
+    // must be overlap
+    for (i = numberWords - 1; i >= 0; --i) {
+        thisMask[i] |= otherMask[i];
+    }
+    return CbcRangeOverlap;
+}
+
diff --git a/cbits/coin/CbcClique.hpp b/cbits/coin/CbcClique.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcClique.hpp
@@ -0,0 +1,303 @@
+// $Id: CbcClique.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/9/2009-- carved out of CbcBranchActual
+
+#ifndef CbcClique_H
+#define CbcClique_H
+
+/** \brief Branching object for cliques
+
+  A clique is defined to be a set of binary variables where fixing any one
+  variable to its `strong' value fixes all other variables. An example is the
+  most common SOS1 construction: a set of binary variables x_j s.t.  SUM{j}
+  x_j = 1.  Setting any one variable to 1 forces all other variables to 0.
+  (See comments for CbcSOS below.)
+
+  Other configurations are possible, however: Consider x1-x2+x3 <= 0.
+  Setting x1 (x3) to 1 forces x2 to 1 and x3 (x1) to 0. Setting x2 to 0
+  forces x1 and x3 to 0.
+
+  The proper point of view to take when interpreting CbcClique is
+  `generalisation of SOS1 on binary variables.' To get into the proper frame
+  of mind, here's an example.
+  
+  Consider the following sequence, where x_j = (1-y_j):
+  \verbatim
+     x1 + x2 + x3 <=  1		all strong at 1
+     x1 - y2 + x3 <=  0		y2 strong at 0; x1, x3 strong at 1
+    -y1 - y2 + x3 <= -1		y1, y2 strong at 0, x3 strong at 1
+    -y1 - y2 - y3 <= -2		all strong at 0
+  \endverbatim
+  The first line is a standard SOS1 on binary variables.
+  
+  Variables with +1 coefficients are `SOS-style' and variables with -1
+  coefficients are `non-SOS-style'. So #numberNonSOSMembers_ simply tells you
+  how many variables have -1 coefficients. The implicit rhs for a clique is
+  1-numberNonSOSMembers_.
+*/
+class CbcClique : public CbcObject {
+
+public:
+
+    /// Default Constructor
+    CbcClique ();
+
+    /** Useful constructor (which are integer indices) slack can denote a slack
+	in set.  If type == NULL then as if 1
+    */
+    CbcClique (CbcModel * model, int cliqueType, int numberMembers,
+               const int * which, const char * type,
+               int identifier, int slack = -1);
+
+    /// Copy constructor
+    CbcClique ( const CbcClique &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    /// Assignment operator
+    CbcClique & operator=( const CbcClique& rhs);
+
+    /// Destructor
+    virtual ~CbcClique ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /// This looks at solution and sets bounds to contain solution
+    virtual void feasibleRegion();
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+    /// Number of members
+    inline int numberMembers() const {
+        return numberMembers_;
+    }
+    /** \brief Number of variables with -1 coefficient
+      
+      Number of non-SOS members, i.e., fixing to zero is strong.
+      See comments at head of class, and comments for #type_.
+    */
+    inline int numberNonSOSMembers() const {
+        return numberNonSOSMembers_;
+    }
+
+    /// Members (indices in range 0 ... numberIntegers_-1)
+    inline const int * members() const {
+        return members_;
+    }
+
+    /*! \brief Type of each member, i.e., which way is strong.
+  
+      This also specifies whether a variable has a +1 or -1 coefficient.
+	- 0 => -1 coefficient, 0 is strong value
+	- 1 => +1 coefficient, 1 is strong value
+      If unspecified, all coefficients are assumed to be positive.
+      
+      Indexed as 0 .. numberMembers_-1
+    */
+    inline char type(int index) const {
+        if (type_) return type_[index];
+        else return 1;
+    }
+
+    /// Clique type: 0 is <=, 1 is ==
+    inline int cliqueType() const {
+        return cliqueType_;
+    }
+    /// Redoes data when sequence numbers change
+    virtual void redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns);
+
+protected:
+    /// data
+    /// Number of members
+    int numberMembers_;
+
+    /// Number of Non SOS members i.e. fixing to zero is strong
+    int numberNonSOSMembers_;
+
+    /// Members (indices in range 0 ... numberIntegers_-1)
+    int * members_;
+
+    /** \brief Strong value for each member.
+
+      This also specifies whether a variable has a +1 or -1 coefficient.
+        - 0 => -1 coefficient, 0 is strong value
+        - 1 => +1 coefficient, 1 is strong value
+      If unspecified, all coefficients are assumed to be positive.
+    
+      Indexed as 0 .. numberMembers_-1
+    */
+    char * type_;
+
+    /** \brief Clique type
+
+      0 defines a <= relation, 1 an equality. The assumed value of the rhs is
+      numberNonSOSMembers_+1. (See comments for the class.)
+    */
+    int cliqueType_;
+
+    /** \brief Slack variable for the clique
+  
+      Identifies the slack variable for the clique (typically added to convert
+      a <= relation to an equality). Value is sequence number within clique
+      menbers.
+    */
+    int slack_;
+};
+
+/** Branching object for unordered cliques
+
+    Intended for cliques which are long enough to make it worthwhile
+    but <= 64 members.  There will also be ones for long cliques.
+
+    Variable_ is the clique id number (redundant, as the object also holds a
+    pointer to the clique.
+ */
+class CbcCliqueBranchingObject : public CbcBranchingObject {
+
+public:
+
+    // Default Constructor
+    CbcCliqueBranchingObject ();
+
+    // Useful constructor
+    CbcCliqueBranchingObject (CbcModel * model,  const CbcClique * clique,
+                              int way,
+                              int numberOnDownSide, const int * down,
+                              int numberOnUpSide, const int * up);
+
+    // Copy constructor
+    CbcCliqueBranchingObject ( const CbcCliqueBranchingObject &);
+
+    // Assignment operator
+    CbcCliqueBranchingObject & operator=( const CbcCliqueBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~CbcCliqueBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch();
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return CliqueBranchObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be of the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+private:
+    /// data
+    const CbcClique * clique_;
+    /// downMask - bit set to fix to weak bounds, not set to leave unfixed
+    unsigned int downMask_[2];
+    /// upMask - bit set to fix to weak bounds, not set to leave unfixed
+    unsigned int upMask_[2];
+};
+
+/** Unordered Clique Branching Object class.
+    These are for cliques which are > 64 members
+    Variable is number of clique.
+ */
+class CbcLongCliqueBranchingObject : public CbcBranchingObject {
+
+public:
+
+    // Default Constructor
+    CbcLongCliqueBranchingObject ();
+
+    // Useful constructor
+    CbcLongCliqueBranchingObject (CbcModel * model,  const CbcClique * clique,
+                                  int way,
+                                  int numberOnDownSide, const int * down,
+                                  int numberOnUpSide, const int * up);
+
+    // Copy constructor
+    CbcLongCliqueBranchingObject ( const CbcLongCliqueBranchingObject &);
+
+    // Assignment operator
+    CbcLongCliqueBranchingObject & operator=( const CbcLongCliqueBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~CbcLongCliqueBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch();
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return LongCliqueBranchObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+private:
+    /// data
+    const CbcClique * clique_;
+    /// downMask - bit set to fix to weak bounds, not set to leave unfixed
+    unsigned int * downMask_;
+    /// upMask - bit set to fix to weak bounds, not set to leave unfixed
+    unsigned int * upMask_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcCompare.hpp b/cbits/coin/CbcCompare.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompare.hpp
@@ -0,0 +1,39 @@
+/* $Id: CbcCompare.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcCompare_H
+#define CbcCompare_H
+
+class CbcCompareBase;
+
+class CbcCompare {
+public:
+    CbcCompareBase * test_;
+    // Default Constructor
+    CbcCompare () {
+        test_ = NULL;
+    }
+
+    virtual ~CbcCompare() {}
+
+    bool operator() (CbcNode * x, CbcNode * y) {
+        return test_->test(x, y);
+    }
+    bool compareNodes (CbcNode * x, CbcNode * y) {
+        return test_->test(x, y);
+    }
+    /// This is alternate test function
+    inline bool alternateTest (CbcNode * x, CbcNode * y) {
+        return test_->alternateTest(x, y);
+    }
+
+    /// return comparison object
+    inline CbcCompareBase * comparisonObject() const {
+        return test_;
+    }
+};
+
+#endif
+
diff --git a/cbits/coin/CbcCompareActual.hpp b/cbits/coin/CbcCompareActual.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareActual.hpp
@@ -0,0 +1,14 @@
+/* $Id: CbcCompareActual.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcCompareActual_H
+#define CbcCompareActual_H
+#include "CbcNode.hpp"
+#include "CbcCompareBase.hpp"
+#include "CbcCompare.hpp"
+#include "CbcCompareDepth.hpp"
+#include "CbcCompareDefault.hpp"
+#endif
+
diff --git a/cbits/coin/CbcCompareBase.hpp b/cbits/coin/CbcCompareBase.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareBase.hpp
@@ -0,0 +1,142 @@
+/* $Id: CbcCompareBase.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcCompareBase_H
+#define CbcCompareBase_H
+
+
+//#############################################################################
+/*  These are alternative strategies for node traversal.
+    They can take data etc for fine tuning
+
+    At present the node list is stored as a heap and the "test"
+    comparison function returns true if node y is better than node x.
+
+    This is rather inflexible so if the comparison functions wants
+    it can signal to use alternative criterion on a complete pass
+    throgh tree.
+
+*/
+#include "CbcNode.hpp"
+#include "CbcConfig.h"
+
+class CbcModel;
+class CbcTree;
+class CbcCompareBase {
+public:
+    // Default Constructor
+    CbcCompareBase () {
+        test_ = NULL;
+        threaded_ = false;
+    }
+
+    /*! \brief Reconsider behaviour after discovering a new solution.
+    
+      This allows any method to change its behaviour. It is called
+      after each solution.
+
+      The method should return true if changes are made which will
+      alter the evaluation criteria applied to a node. (So that in
+      cases where the search tree is sorted, it can be properly
+      rebuilt.)
+    */
+    virtual bool newSolution(CbcModel * ) { return (false) ; }
+
+    /*! \brief Reconsider behaviour after discovering a new solution.
+    
+      This allows any method to change its behaviour. It is called
+      after each solution.
+
+      The method should return true if changes are made which will
+      alter the evaluation criteria applied to a node. (So that in
+      cases where the search tree is sorted, it can be properly
+      rebuilt.)
+    */
+    virtual bool newSolution(CbcModel * ,
+                             double ,
+                             int ) { return (false) ; }
+
+    // This allows any method to change behavior as it is called
+    // after every 1000 nodes.
+    // Return true if want tree re-sorted
+    virtual bool every1000Nodes(CbcModel * , int ) {
+        return false;
+    }
+
+    /** Returns true if wants code to do scan with alternate criterion
+        NOTE - this is temporarily disabled
+    */
+    virtual bool fullScan() const {
+        return false;
+    }
+
+    virtual ~CbcCompareBase() {}
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+
+    // Copy constructor
+    CbcCompareBase ( const CbcCompareBase & rhs) {
+        test_ = rhs.test_;
+        threaded_ = rhs.threaded_;
+    }
+
+    // Assignment operator
+    CbcCompareBase & operator=( const CbcCompareBase& rhs) {
+        if (this != &rhs) {
+            test_ = rhs.test_;
+            threaded_ = rhs.threaded_;
+        }
+        return *this;
+    }
+
+    /// Clone
+    virtual CbcCompareBase * clone() const {
+        abort();
+        return NULL;
+    }
+
+    /// This is test function
+    virtual bool test (CbcNode * , CbcNode * ) {
+        return true;
+    }
+
+    /// This is alternate test function
+    virtual bool alternateTest (CbcNode * x, CbcNode * y) {
+        return test(x, y);
+    }
+
+    bool operator() (CbcNode * x, CbcNode * y) {
+        return test(x, y);
+    }
+    /// Further test if everything else equal
+    inline bool equalityTest (CbcNode * x, CbcNode * y) const {
+        assert (x);
+        assert (y);
+        if (!threaded_) {
+            CbcNodeInfo * infoX = x->nodeInfo();
+            assert (infoX);
+            int nodeNumberX = infoX->nodeNumber();
+            CbcNodeInfo * infoY = y->nodeInfo();
+            assert (infoY);
+            int nodeNumberY = infoY->nodeNumber();
+            assert (nodeNumberX != nodeNumberY);
+            return (nodeNumberX > nodeNumberY);
+        } else {
+            assert (x->nodeNumber() != y->nodeNumber());
+            return (x->nodeNumber() > y->nodeNumber());
+        }
+    }
+    /// Say threaded
+    inline void sayThreaded() {
+        threaded_ = true;
+    }
+protected:
+    CbcCompareBase * test_;
+    // If not threaded we can use better way to break ties
+    bool threaded_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcCompareDefault.cpp b/cbits/coin/CbcCompareDefault.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareDefault.cpp
@@ -0,0 +1,347 @@
+// $Id: CbcCompareDefault.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCompareActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CbcMessage.hpp"
+#include "CbcModel.hpp"
+#include "CbcTree.hpp"
+#include "CbcCompareActual.hpp"
+#include "CoinError.hpp"
+#include "CbcCompareDefault.hpp"
+/** Default Constructor
+
+*/
+CbcCompareDefault::CbcCompareDefault ()
+        : CbcCompareBase(),
+        weight_(-1.0),
+        saveWeight_(0.0),
+        cutoff_(COIN_DBL_MAX),
+        bestPossible_(-COIN_DBL_MAX),
+        numberSolutions_(0),
+        treeSize_(0),
+        breadthDepth_(5),
+        startNodeNumber_(-1),
+        afterNodeNumber_(-1),
+        setupForDiving_(false)
+{
+    test_ = this;
+}
+
+// Constructor with weight
+CbcCompareDefault::CbcCompareDefault (double weight)
+        : CbcCompareBase(),
+        weight_(weight) ,
+        saveWeight_(0.0),
+        cutoff_(COIN_DBL_MAX),
+        bestPossible_(-COIN_DBL_MAX),
+        numberSolutions_(0),
+        treeSize_(0),
+        breadthDepth_(5),
+        startNodeNumber_(-1),
+        afterNodeNumber_(-1),
+        setupForDiving_(false)
+{
+    test_ = this;
+}
+
+
+// Copy constructor
+CbcCompareDefault::CbcCompareDefault ( const CbcCompareDefault & rhs)
+        : CbcCompareBase(rhs)
+
+{
+    weight_ = rhs.weight_;
+    saveWeight_ = rhs.saveWeight_;
+    cutoff_ = rhs.cutoff_;
+    bestPossible_ = rhs.bestPossible_;
+    numberSolutions_ = rhs.numberSolutions_;
+    treeSize_ = rhs.treeSize_;
+    breadthDepth_ = rhs.breadthDepth_;
+    startNodeNumber_ = rhs.startNodeNumber_;
+    afterNodeNumber_ = rhs.afterNodeNumber_;
+    setupForDiving_ = rhs.setupForDiving_ ;
+}
+
+// Clone
+CbcCompareBase *
+CbcCompareDefault::clone() const
+{
+    return new CbcCompareDefault(*this);
+}
+
+// Assignment operator
+CbcCompareDefault &
+CbcCompareDefault::operator=( const CbcCompareDefault & rhs)
+{
+    if (this != &rhs) {
+        CbcCompareBase::operator=(rhs);
+        weight_ = rhs.weight_;
+        saveWeight_ = rhs.saveWeight_;
+        cutoff_ = rhs.cutoff_;
+        bestPossible_ = rhs.bestPossible_;
+        numberSolutions_ = rhs.numberSolutions_;
+        treeSize_ = rhs.treeSize_;
+        breadthDepth_ = rhs.breadthDepth_;
+        startNodeNumber_ = rhs.startNodeNumber_;
+        afterNodeNumber_ = rhs.afterNodeNumber_;
+        setupForDiving_ = rhs.setupForDiving_ ;
+    }
+    return *this;
+}
+
+// Destructor
+CbcCompareDefault::~CbcCompareDefault ()
+{
+}
+
+// Returns true if y better than x
+bool
+CbcCompareDefault::test (CbcNode * x, CbcNode * y)
+{
+    if (startNodeNumber_ >= 0) {
+        // Diving
+        int nX = x->nodeNumber();
+        int nY = y->nodeNumber();
+        if (nY == startNodeNumber_)
+            return true;
+        else if (nX == startNodeNumber_)
+            return false;
+        if (nX >= afterNodeNumber_ && nY < afterNodeNumber_)
+            return false;
+        else if (nY >= afterNodeNumber_ && nX < afterNodeNumber_)
+            return true;
+        // treat as depth first
+        int depthX = x->depth();
+        int depthY = y->depth();
+        if (depthX != depthY) {
+            return depthX < depthY;
+        } else {
+            double weight = CoinMax(weight_, 1.0e-9);
+            double testX =  x->objectiveValue() + weight * x->numberUnsatisfied();
+            double testY = y->objectiveValue() + weight * y->numberUnsatisfied();
+            if (testX != testY)
+                return testX > testY;
+            else
+                return equalityTest(x, y); // so ties will be broken in consistent manner
+        }
+    }
+    if (!weight_) {
+      double testX =  x->objectiveValue() + 1.0e-9 * x->numberUnsatisfied();
+      double testY = y->objectiveValue() + 1.0e-9 * y->numberUnsatisfied();
+      if (testX != testY)
+	return testX > testY;
+      else
+	return equalityTest(x, y); // so ties will be broken in consistent manner
+    }
+    //weight_=0.0;
+    if ((weight_ == -1.0 && (y->depth() > breadthDepth_ && x->depth() > breadthDepth_)) || weight_ == -3.0 || weight_ == -2.0) {
+        int adjust =  (weight_ == -3.0) ? 10000 : 0;
+        // before solution
+        /*printf("x %d %d %g, y %d %d %g\n",
+           x->numberUnsatisfied(),x->depth(),x->objectiveValue(),
+           y->numberUnsatisfied(),y->depth(),y->objectiveValue()); */
+        if (x->numberUnsatisfied() > y->numberUnsatisfied() + adjust) {
+            return true;
+        } else if (x->numberUnsatisfied() < y->numberUnsatisfied() - adjust) {
+            return false;
+        } else {
+            int depthX = x->depth();
+            int depthY = y->depth();
+            if (depthX != depthY)
+                return depthX < depthY;
+            else
+                return equalityTest(x, y); // so ties will be broken in consistent manner
+        }
+    } else {
+        // always choose *greatest* depth if both <= breadthDepth_ otherwise <= breadthDepth_ if just one
+        int depthX = x->depth();
+        int depthY = y->depth();
+        /*if ((depthX==4&&depthY==5)||(depthX==5&&depthY==4))
+          printf("X %x depth %d, Y %x depth %d, breadth %d\n",
+          x,depthX,y,depthY,breadthDepth_);*/
+        if (depthX <= breadthDepth_ || depthY <= breadthDepth_) {
+            if (depthX <= breadthDepth_ && depthY <= breadthDepth_) {
+                if (depthX != depthY) {
+                    return depthX < depthY;
+                }
+            } else {
+                assert (depthX != depthY) ;
+                return depthX < depthY;
+            }
+        }
+        // after solution ?
+#define THRESH2 0.999
+#define TRY_THIS 0
+#if TRY_THIS==0
+        double weight = CoinMax(weight_, 1.0e-9);
+        double testX =  x->objectiveValue() + weight * x->numberUnsatisfied();
+        double testY = y->objectiveValue() + weight * y->numberUnsatisfied();
+#elif TRY_THIS==1
+        /* compute what weight would have to be to hit target
+           then reverse sign as large weight good */
+        double target = (1.0 - THRESH2) * bestPossible_ + THRESH2 * cutoff_;
+        double weight;
+        weight = (target - x->objectiveValue()) /
+                 static_cast<double>(x->numberUnsatisfied());
+        double testX = - weight;
+        weight = (target - y->objectiveValue()) /
+                 static_cast<double>(y->numberUnsatisfied());
+        double testY = - weight;
+#elif TRY_THIS==2
+        // Use estimates
+        double testX = x->guessedObjectiveValue();
+        double testY = y->guessedObjectiveValue();
+#elif TRY_THIS==3
+#define THRESH 0.95
+        // Use estimates
+        double testX = x->guessedObjectiveValue();
+        double testY = y->guessedObjectiveValue();
+        if (x->objectiveValue() - bestPossible_ > THRESH*(cutoff_ - bestPossible_))
+            testX *= 2.0; // make worse
+        if (y->objectiveValue() - bestPossible_ > THRESH*(cutoff_ - bestPossible_))
+            testY *= 2.0; // make worse
+#endif
+        if (testX != testY)
+            return testX > testY;
+        else
+            return equalityTest(x, y); // so ties will be broken in consistent manner
+    }
+}
+/*
+  Change the weight attached to unsatisfied integer variables, unless it's
+  fairly early on in the search and all solutions to date are heuristic.
+*/
+bool
+CbcCompareDefault::newSolution(CbcModel * model,
+                               double objectiveAtContinuous,
+                               int numberInfeasibilitiesAtContinuous)
+{
+    cutoff_ = model->getCutoff();
+    if (model->getSolutionCount() == model->getNumberHeuristicSolutions() &&
+            model->getSolutionCount() < 5 && model->getNodeCount() < 500)
+        return (false) ; // solution was got by rounding
+    // set to get close to this solution
+    double costPerInteger =
+        (model->getObjValue() - objectiveAtContinuous) /
+        static_cast<double> (numberInfeasibilitiesAtContinuous);
+    weight_ = 0.95 * costPerInteger;
+    saveWeight_ = 0.95 * weight_;
+    numberSolutions_++;
+    //if (numberSolutions_>5)
+    //weight_ =0.0; // this searches on objective
+    return (true) ;
+}
+// This allows method to change behavior
+bool
+CbcCompareDefault::every1000Nodes(CbcModel * model, int numberNodes)
+{
+#ifdef JJF_ZERO
+    // was
+    if (numberNodes > 10000)
+        weight_ = 0.0; // this searches on objective
+    // get size of tree
+    treeSize_ = model->tree()->size();
+#else
+    double saveWeight = weight_;
+    int numberNodes1000 = numberNodes / 1000;
+    if (numberNodes > 10000) {
+        weight_ = 0.0; // this searches on objective
+        // but try a bit of other stuff
+        if ((numberNodes1000 % 4) == 1)
+            weight_ = saveWeight_;
+    } else if (numberNodes == 1000 && weight_ == -2.0) {
+        weight_ = -1.0; // Go to depth first
+    }
+    // get size of tree
+    treeSize_ = model->tree()->size();
+    if (treeSize_ > 10000) {
+        int n1 = model->solver()->getNumRows() + model->solver()->getNumCols();
+        int n2 = model->numberObjects();
+        double size = n1 * 0.1 + n2 * 2.0;
+        // set weight to reduce size most of time
+        if (treeSize_*(size + 100.0) > 5.0e7)
+            weight_ = -3.0;
+        else if ((numberNodes1000 % 4) == 0 && treeSize_*size > 1.0e6)
+            weight_ = -1.0;
+        else if ((numberNodes1000 % 4) == 1)
+            weight_ = 0.0;
+        else
+            weight_ = saveWeight_;
+    }
+#endif
+    //return numberNodes==11000; // resort if first time
+    return (weight_ != saveWeight);
+}
+// Start dive
+void
+CbcCompareDefault::startDive(CbcModel * model)
+{
+    // Get best - using ? criterion
+    double saveWeight = weight_;
+    weight_ = 0.5 * saveWeight_; //0.0;
+    // Switch off to get best
+    startNodeNumber_ = -1;
+    afterNodeNumber_ = -1;
+    CbcNode * best = model->tree()->bestAlternate();
+    startNodeNumber_ = best->nodeNumber();
+    // send signal to setComparison
+    setupForDiving_ = true ;
+    /*
+      TODO (review when fixing cleanDive and setComparison)
+      Both afterNodeNumber_ and weight_ must not change
+      after setComparison is invoked, as that will change
+      the behaviour of test(). I replaced the overload on
+      afterNodeNumber_ (magic number -2) with a boolean. Weight_
+      is more problematic. Either it's correct before calling
+      setComparison, or it needs to be cut from the tie-breaking
+      part of test() during a dive, or there needs to be a new
+      attribute to save and restore it around the dive. Otherwise
+      heap checks fail in debug builds with Visual Studio.
+      
+      Given that weight_ was restored immediately after the call
+      to setComparison, there should be no change in behaviour
+      in terms of calls to test().
+      -- lh, 100921 --
+    */
+    afterNodeNumber_ = model->tree()->maximumNodeNumber();
+    weight_ = saveWeight ;
+    // redo tree
+    model->tree()->setComparison(*this);
+    setupForDiving_ = false ;
+}
+// Clean up dive
+void
+CbcCompareDefault::cleanDive()
+{
+    if (setupForDiving_ == false) {
+        // switch off
+        startNodeNumber_ = -1;
+        afterNodeNumber_ = -1;
+    }
+}
+
+// Create C++ lines to get to current state
+void
+CbcCompareDefault::generateCpp( FILE * fp)
+{
+    CbcCompareDefault other;
+    fprintf(fp, "0#include \"CbcCompareActual.hpp\"\n");
+    fprintf(fp, "3  CbcCompareDefault compare;\n");
+    if (weight_ != other.weight_)
+        fprintf(fp, "3  compare.setWeight(%g);\n", weight_);
+    fprintf(fp, "3  cbcModel->setNodeComparison(compare);\n");
+}
+
diff --git a/cbits/coin/CbcCompareDefault.hpp b/cbits/coin/CbcCompareDefault.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareDefault.hpp
@@ -0,0 +1,120 @@
+// $Id: CbcCompareDefault.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCompareActual
+
+#ifndef CbcCompareDefault_H
+#define CbcCompareDefault_H
+
+
+//#############################################################################
+/*  These are alternative strategies for node traversal.
+    They can take data etc for fine tuning
+
+    At present the node list is stored as a heap and the "test"
+    comparison function returns true if node y is better than node x.
+
+*/
+#include "CbcNode.hpp"
+#include "CbcCompareBase.hpp"
+#include "CbcCompare.hpp"
+
+class CbcModel;
+
+/* This is an example of a more complex rule with data
+   It is default after first solution
+   If weight is 0.0 then it is computed to hit first solution
+   less 5%
+*/
+class CbcCompareDefault  : public CbcCompareBase {
+public:
+    /// Default Constructor
+    CbcCompareDefault () ;
+    /// Constructor with weight
+    CbcCompareDefault (double weight);
+
+    /// Copy constructor
+    CbcCompareDefault ( const CbcCompareDefault &rhs);
+
+    /// Assignment operator
+    CbcCompareDefault & operator=( const CbcCompareDefault& rhs);
+
+    /// Clone
+    virtual CbcCompareBase * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp);
+
+    ~CbcCompareDefault() ;
+    /* This returns true if weighted value of node y is less than
+       weighted value of node x */
+    virtual bool test (CbcNode * x, CbcNode * y) ;
+
+    using CbcCompareBase::newSolution ;
+    /// This allows method to change behavior as it is called
+    /// after each solution
+    virtual bool newSolution(CbcModel * model,
+                             double objectiveAtContinuous,
+                             int numberInfeasibilitiesAtContinuous) ;
+    /// This allows method to change behavior
+    /// Return true if want tree re-sorted
+    virtual bool every1000Nodes(CbcModel * model, int numberNodes);
+
+    /* if weight == -1.0 then fewest infeasibilities (before solution)
+       if -2.0 then do breadth first just for first 1000 nodes
+       if -3.0 then depth first before solution
+    */
+    inline double getWeight() const {
+        return weight_;
+    }
+    inline void setWeight(double weight) {
+        weight_ = weight;
+    }
+    /// Cutoff
+    inline double getCutoff() const {
+        return cutoff_;
+    }
+    inline void setCutoff(double cutoff) {
+        cutoff_ = cutoff;
+    }
+    /// Best possible solution
+    inline double getBestPossible() const {
+        return bestPossible_;
+    }
+    inline void setBestPossible(double bestPossible) {
+        bestPossible_ = bestPossible;
+    }
+    /// Depth above which want to explore first
+    inline void setBreadthDepth(int value) {
+        breadthDepth_ = value;
+    }
+    /// Start dive
+    void startDive(CbcModel * model);
+    /// Clean up diving (i.e. switch off or prepare)
+    void cleanDive();
+protected:
+    /// Weight for each infeasibility
+    double weight_;
+    /// Weight for each infeasibility - computed from solution
+    double saveWeight_;
+    /// Cutoff
+    double cutoff_;
+    /// Best possible solution
+    double bestPossible_;
+    /// Number of solutions
+    int numberSolutions_;
+    /// Tree size (at last check)
+    int treeSize_;
+    /// Depth above which want to explore first
+    int breadthDepth_;
+    /// Chosen node from estimated (-1 is off)
+    int startNodeNumber_;
+    /// Node number when dive started
+    int afterNodeNumber_;
+    /// Indicates doing setup for diving
+    bool setupForDiving_ ;
+};
+
+#endif //CbcCompareDefault_H
+
diff --git a/cbits/coin/CbcCompareDepth.cpp b/cbits/coin/CbcCompareDepth.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareDepth.cpp
@@ -0,0 +1,81 @@
+// $Id: CbcCompareDepth.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/24/09 carved out of CbcCompareActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CbcMessage.hpp"
+#include "CbcModel.hpp"
+#include "CbcTree.hpp"
+#include "CbcCompareActual.hpp"
+#include "CoinError.hpp"
+#include "CbcCompareDepth.hpp"
+/** Default Constructor
+
+*/
+CbcCompareDepth::CbcCompareDepth ()
+        : CbcCompareBase()
+{
+    test_ = this;
+}
+
+// Copy constructor
+CbcCompareDepth::CbcCompareDepth ( const CbcCompareDepth & rhs)
+        : CbcCompareBase(rhs)
+
+{
+}
+
+// Clone
+CbcCompareBase *
+CbcCompareDepth::clone() const
+{
+    return new CbcCompareDepth(*this);
+}
+
+// Assignment operator
+CbcCompareDepth &
+CbcCompareDepth::operator=( const CbcCompareDepth & rhs)
+{
+    if (this != &rhs) {
+        CbcCompareBase::operator=(rhs);
+    }
+    return *this;
+}
+
+// Destructor
+CbcCompareDepth::~CbcCompareDepth ()
+{
+}
+
+// Returns true if y better than x
+bool
+CbcCompareDepth::test (CbcNode * x, CbcNode * y)
+{
+    int testX = x->depth();
+    int testY = y->depth();
+    if (testX != testY)
+        return testX < testY;
+    else
+        return equalityTest(x, y); // so ties will be broken in consistent manner
+}
+// Create C++ lines to get to current state
+void
+CbcCompareDepth::generateCpp( FILE * fp)
+{
+    fprintf(fp, "0#include \"CbcCompareActual.hpp\"\n");
+    fprintf(fp, "3  CbcCompareDepth compare;\n");
+    fprintf(fp, "3  cbcModel->setNodeComparison(compare);\n");
+}
+
diff --git a/cbits/coin/CbcCompareDepth.hpp b/cbits/coin/CbcCompareDepth.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareDepth.hpp
@@ -0,0 +1,47 @@
+// $Id: CbcCompareDepth.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/24/09 carved out of CbcCompareActual
+
+#ifndef CbcCompareDepth_H
+#define CbcCompareDepth_H
+
+
+//#############################################################################
+/*  These are alternative strategies for node traversal.
+    They can take data etc for fine tuning
+
+    At present the node list is stored as a heap and the "test"
+    comparison function returns true if node y is better than node x.
+
+*/
+#include "CbcNode.hpp"
+#include "CbcCompareBase.hpp"
+#include "CbcCompare.hpp"
+class CbcModel;
+// This is default before first solution
+class CbcCompareDepth : public CbcCompareBase {
+public:
+    // Default Constructor
+    CbcCompareDepth () ;
+
+    ~CbcCompareDepth();
+    // Copy constructor
+    CbcCompareDepth ( const CbcCompareDepth &rhs);
+
+    // Assignment operator
+    CbcCompareDepth & operator=( const CbcCompareDepth& rhs);
+
+    /// Clone
+    virtual CbcCompareBase * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp);
+
+    // This returns true if the depth of node y is greater than depth of node x
+    virtual bool test (CbcNode * x, CbcNode * y);
+};
+
+#endif
+
diff --git a/cbits/coin/CbcCompareEstimate.cpp b/cbits/coin/CbcCompareEstimate.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareEstimate.cpp
@@ -0,0 +1,82 @@
+// $Id: CbcCompareEstimate.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCompareActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CbcMessage.hpp"
+#include "CbcModel.hpp"
+#include "CbcTree.hpp"
+#include "CbcCompareActual.hpp"
+#include "CoinError.hpp"
+#include "CbcCompareEstimate.hpp"
+/** Default Constructor
+
+*/
+CbcCompareEstimate::CbcCompareEstimate ()
+        : CbcCompareBase()
+{
+    test_ = this;
+}
+
+// Copy constructor
+CbcCompareEstimate::CbcCompareEstimate ( const CbcCompareEstimate & rhs)
+        : CbcCompareBase(rhs)
+
+{
+}
+
+// Clone
+CbcCompareBase *
+CbcCompareEstimate::clone() const
+{
+    return new CbcCompareEstimate(*this);
+}
+
+// Assignment operator
+CbcCompareEstimate &
+CbcCompareEstimate::operator=( const CbcCompareEstimate & rhs)
+{
+    if (this != &rhs) {
+        CbcCompareBase::operator=(rhs);
+    }
+    return *this;
+}
+
+// Destructor
+CbcCompareEstimate::~CbcCompareEstimate ()
+{
+}
+
+// Returns true if y better than x
+bool
+CbcCompareEstimate::test (CbcNode * x, CbcNode * y)
+{
+    double testX = x->guessedObjectiveValue();
+    double testY = y->guessedObjectiveValue();
+    if (testX != testY)
+        return testX > testY;
+    else
+        return equalityTest(x, y); // so ties will be broken in consistent manner
+}
+
+// Create C++ lines to get to current state
+void
+CbcCompareEstimate::generateCpp( FILE * fp)
+{
+    fprintf(fp, "0#include \"CbcCompareActual.hpp\"\n");
+    fprintf(fp, "3  CbcCompareEstimate compare;\n");
+    fprintf(fp, "3  cbcModel->setNodeComparison(compare);\n");
+}
+
diff --git a/cbits/coin/CbcCompareEstimate.hpp b/cbits/coin/CbcCompareEstimate.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareEstimate.hpp
@@ -0,0 +1,48 @@
+// $Id: CbcCompareEstimate.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCompareActual
+
+#ifndef CbcCompareEstimate_H
+#define CbcCompareEstimate_H
+
+
+//#############################################################################
+/*  These are alternative strategies for node traversal.
+    They can take data etc for fine tuning
+
+    At present the node list is stored as a heap and the "test"
+    comparison function returns true if node y is better than node x.
+
+*/
+#include "CbcNode.hpp"
+#include "CbcCompareBase.hpp"
+#include "CbcCompare.hpp"
+class CbcModel;
+
+/* This is when rounding is being done
+*/
+class CbcCompareEstimate  : public CbcCompareBase {
+public:
+    // Default Constructor
+    CbcCompareEstimate () ;
+    ~CbcCompareEstimate() ;
+    // Copy constructor
+    CbcCompareEstimate ( const CbcCompareEstimate &rhs);
+
+    // Assignment operator
+    CbcCompareEstimate & operator=( const CbcCompareEstimate& rhs);
+
+    /// Clone
+    virtual CbcCompareBase * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp);
+
+    virtual bool test (CbcNode * x, CbcNode * y) ;
+};
+
+
+#endif //CbcCompareEstimate_H
+
diff --git a/cbits/coin/CbcCompareObjective.cpp b/cbits/coin/CbcCompareObjective.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareObjective.cpp
@@ -0,0 +1,80 @@
+// $Id: CbcCompareObjective.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCompareActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CbcMessage.hpp"
+#include "CbcModel.hpp"
+#include "CbcTree.hpp"
+#include "CbcCompareActual.hpp"
+#include "CoinError.hpp"
+#include "CbcCompareObjective.hpp"
+/** Default Constructor
+
+*/
+CbcCompareObjective::CbcCompareObjective ()
+        : CbcCompareBase()
+{
+    test_ = this;
+}
+
+// Copy constructor
+CbcCompareObjective::CbcCompareObjective ( const CbcCompareObjective & rhs)
+        : CbcCompareBase(rhs)
+
+{
+}
+
+// Clone
+CbcCompareBase *
+CbcCompareObjective::clone() const
+{
+    return new CbcCompareObjective(*this);
+}
+
+// Assignment operator
+CbcCompareObjective &
+CbcCompareObjective::operator=( const CbcCompareObjective & rhs)
+{
+    if (this != &rhs) {
+        CbcCompareBase::operator=(rhs);
+    }
+    return *this;
+}
+
+// Destructor
+CbcCompareObjective::~CbcCompareObjective ()
+{
+}
+
+// Returns true if y better than x
+bool
+CbcCompareObjective::test (CbcNode * x, CbcNode * y)
+{
+    double testX = x->objectiveValue();
+    double testY = y->objectiveValue();
+    if (testX != testY)
+        return testX > testY;
+    else
+        return equalityTest(x, y); // so ties will be broken in consistent manner
+}
+// Create C++ lines to get to current state
+void
+CbcCompareObjective::generateCpp( FILE * fp)
+{
+    fprintf(fp, "0#include \"CbcCompareActual.hpp\"\n");
+    fprintf(fp, "3  CbcCompareObjective compare;\n");
+    fprintf(fp, "3  cbcModel->setNodeComparison(compare);\n");
+}
diff --git a/cbits/coin/CbcCompareObjective.hpp b/cbits/coin/CbcCompareObjective.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCompareObjective.hpp
@@ -0,0 +1,49 @@
+// $Id: CbcCompareObjective.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCompareActual
+
+#ifndef CbcCompareObjective_H
+#define CbcCompareObjective_H
+
+
+//#############################################################################
+/*  These are alternative strategies for node traversal.
+    They can take data etc for fine tuning
+
+    At present the node list is stored as a heap and the "test"
+    comparison function returns true if node y is better than node x.
+
+*/
+#include "CbcNode.hpp"
+#include "CbcCompareBase.hpp"
+#include "CbcCompare.hpp"
+
+class CbcModel;
+
+class CbcCompareObjective  : public CbcCompareBase {
+public:
+    // Default Constructor
+    CbcCompareObjective ();
+
+    virtual ~CbcCompareObjective();
+    // Copy constructor
+    CbcCompareObjective ( const CbcCompareObjective &rhs);
+
+    // Assignment operator
+    CbcCompareObjective & operator=( const CbcCompareObjective& rhs);
+
+    /// Clone
+    virtual CbcCompareBase * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp);
+
+    /* This returns true if objective value of node y is less than
+       objective value of node x */
+    virtual bool test (CbcNode * x, CbcNode * y);
+};
+
+#endif //CbcCompareObjective_H
+
diff --git a/cbits/coin/CbcConfig.h b/cbits/coin/CbcConfig.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcConfig.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2011
+ * All Rights Reserved.
+ * This code is published under the Eclipse Public License.
+ *
+ * $Id: CbcConfig.h 1854 2013-01-28 00:02:55Z stefan $
+ *
+ * Include file for the configuration of Cbc.
+ *
+ * On systems where the code is configured with the configure script
+ * (i.e., compilation is always done with HAVE_CONFIG_H defined), this
+ * header file includes the automatically generated header file, and
+ * undefines macros that might configure with other Config.h files.
+ *
+ * On systems that are compiled in other ways (e.g., with the
+ * Developer Studio), a header files is included to define those
+ * macros that depend on the operating system and the compiler.  The
+ * macros that define the configuration of the particular user setting
+ * (e.g., presence of other COIN-OR packages or third party code) are set
+ * by the files config_*default.h. The project maintainer needs to remember
+ * to update these file and choose reasonable defines.
+ * A user can modify the default setting by editing the config_*default.h files.
+ *
+ */
+
+#ifndef __CBCCONFIG_H__
+#define __CBCCONFIG_H__
+
+#ifdef HAVE_CONFIG_H
+#ifdef CBC_BUILD
+#include "config.h"
+#else
+#include "config_cbc.h"
+#endif
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef CBC_BUILD
+#include "config_default.h"
+#else
+#include "config_cbc_default.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+#endif /*__CBCCONFIG_H__*/
diff --git a/cbits/coin/CbcConsequence.cpp b/cbits/coin/CbcConsequence.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcConsequence.cpp
@@ -0,0 +1,43 @@
+// $Id: CbcConsequence.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "CbcConsequence.hpp"
+
+// Default constructor
+CbcConsequence::CbcConsequence()
+{
+}
+
+
+// Destructor
+CbcConsequence::~CbcConsequence ()
+{
+}
+
+// Copy constructor
+CbcConsequence::CbcConsequence ( const CbcConsequence & /*rhs*/)
+{
+}
+
+// Assignment operator
+CbcConsequence &
+CbcConsequence::operator=( const CbcConsequence & rhs)
+{
+    if (this != &rhs) {
+    }
+    return *this;
+}
+
diff --git a/cbits/coin/CbcConsequence.hpp b/cbits/coin/CbcConsequence.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcConsequence.hpp
@@ -0,0 +1,49 @@
+// $Id: CbcConsequence.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#ifndef CbcConsequence_H
+#define CbcConsequence_H
+
+class OsiSolverInterface;
+
+/** Abstract base class for consequent bounds.
+    When a variable is branched on it normally interacts with other variables by
+    means of equations.  There are cases where we want to step outside LP and do something
+    more directly e.g. fix bounds.  This class is for that.
+
+    At present it need not be virtual as only instance is CbcFixVariable, but ...
+
+ */
+
+class CbcConsequence {
+
+public:
+
+    // Default Constructor
+    CbcConsequence ();
+
+    // Copy constructor
+    CbcConsequence ( const CbcConsequence & rhs);
+
+    // Assignment operator
+    CbcConsequence & operator=( const CbcConsequence & rhs);
+
+    /// Clone
+    virtual CbcConsequence * clone() const = 0;
+
+    /// Destructor
+    virtual ~CbcConsequence ();
+
+    /** Apply to an LP solver.  Action depends on state
+     */
+    virtual void applyToSolver(OsiSolverInterface * solver, int state) const = 0;
+
+protected:
+};
+
+#endif
+
diff --git a/cbits/coin/CbcCountRowCut.cpp b/cbits/coin/CbcCountRowCut.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCountRowCut.cpp
@@ -0,0 +1,658 @@
+/* $Id: CbcCountRowCut.cpp 1883 2013-04-06 13:33:15Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+
+#include "OsiRowCut.hpp"
+#include "CbcModel.hpp"
+#include "CbcCountRowCut.hpp"
+#include "CbcNode.hpp"
+//#define CHECK_CUT_COUNTS
+// Default Constructor
+CbcCountRowCut::CbcCountRowCut ()
+        :
+        OsiRowCut(),
+        owner_(NULL),
+        ownerCut_(-1),
+        numberPointingToThis_(0),
+        whichCutGenerator_(-1)
+{
+#ifdef CHECK_CUT_COUNTS
+    printf("CbcCountRowCut default constructor %x\n", this);
+#endif
+}
+
+// Copy Constructor
+CbcCountRowCut::CbcCountRowCut (const OsiRowCut & rhs)
+        : OsiRowCut(rhs),
+        owner_(NULL),
+        ownerCut_(-1),
+        numberPointingToThis_(0),
+        whichCutGenerator_(-1)
+{
+#ifdef CHECK_CUT_COUNTS
+    printf("CbcCountRowCut constructor %x from RowCut\n", this);
+#endif
+}
+// Copy Constructor
+CbcCountRowCut::CbcCountRowCut (const OsiRowCut & rhs,
+                                CbcNodeInfo * info, int whichOne,
+                                int whichGenerator,
+                                int numberPointingToThis)
+        : OsiRowCut(rhs),
+        owner_(info),
+        ownerCut_(whichOne),
+        numberPointingToThis_(numberPointingToThis),
+        whichCutGenerator_(whichGenerator)
+{
+#ifdef CHECK_CUT_COUNTS
+    printf("CbcCountRowCut constructor %x from RowCut and info %d\n",
+           this, numberPointingToThis_);
+#endif
+    //assert (!numberPointingToThis||numberPointingToThis==1000000000);
+}
+CbcCountRowCut::~CbcCountRowCut()
+{
+#ifdef CHECK_CUT_COUNTS
+    printf("CbcCountRowCut destructor %x - references %d\n", this,
+           numberPointingToThis_);
+#endif
+    // Look at owner and delete
+    if (owner_)
+        owner_->deleteCut(ownerCut_);
+    ownerCut_ = -1234567;
+}
+// Increment number of references
+void
+CbcCountRowCut::increment(int change)
+{
+    assert(ownerCut_ != -1234567);
+    numberPointingToThis_ += change;
+}
+
+// Decrement number of references and return number left
+int
+CbcCountRowCut::decrement(int change)
+{
+    assert(ownerCut_ != -1234567);
+    // See if plausible number
+    if (change < 900000000) {
+        //assert(numberPointingToThis_>=change);
+        assert(numberPointingToThis_ >= 0);
+        if (numberPointingToThis_ < change) {
+            assert(numberPointingToThis_ > 0);
+            COIN_DETAIL_PRINT(printf("negative cut count %d - %d\n", numberPointingToThis_, change));
+            change = numberPointingToThis_;
+        }
+        numberPointingToThis_ -= change;
+    }
+    return numberPointingToThis_;
+}
+
+// Set information
+void
+CbcCountRowCut::setInfo(CbcNodeInfo * info, int whichOne)
+{
+    owner_ = info;
+    ownerCut_ = whichOne;
+}
+// Returns true if can drop cut if slack basic
+bool
+CbcCountRowCut::canDropCut(const OsiSolverInterface * solver, int iRow) const
+{
+    // keep if COIN_DBL_MAX otherwise keep if slack zero
+    if (effectiveness() < 1.0e20) {
+        return true;
+    } else if (effectiveness() != COIN_DBL_MAX) {
+        if (iRow >= solver->getNumRows())
+            return true;
+        const double * rowActivity = solver->getRowActivity();
+        const double * rowLower = solver->getRowLower();
+        const double * rowUpper = solver->getRowUpper();
+        double tolerance;
+        solver->getDblParam(OsiPrimalTolerance, tolerance) ;
+        double value = rowActivity[iRow];
+        if (value < rowLower[iRow] + tolerance ||
+                value > rowUpper[iRow] - tolerance)
+            return false;
+        else
+            return true;
+    } else {
+        return false;
+    }
+}
+static double multiplier[] = {1.23456789e2,-9.87654321};
+static int hashCut (const OsiRowCut2 & x, int size) 
+{
+  int xN =x.row().getNumElements();
+  double xLb = x.lb();
+  double xUb = x.ub();
+  const int * xIndices = x.row().getIndices();
+  const double * xElements = x.row().getElements();
+  unsigned int hashValue;
+  double value=1.0;
+  if (xLb>-1.0e10)
+    value += xLb*multiplier[0];
+  if (xUb<1.0e10)
+    value += xUb*multiplier[1];
+  for( int j=0;j<xN;j++) {
+    int xColumn = xIndices[j];
+    double xValue = xElements[j];
+    int k=(j&1);
+    value += (j+1)*multiplier[k]*(xColumn+1)*xValue;
+  }
+  // should be compile time but too lazy for now
+  if (sizeof(value)>sizeof(hashValue)) {
+    assert (sizeof(value)==2*sizeof(hashValue));
+    union { double d; int i[2]; } xx;
+    xx.d = value;
+    hashValue = (xx.i[0] + xx.i[1]);
+  } else {
+    assert (sizeof(value)==sizeof(hashValue));
+    union { double d; unsigned int i[2]; } xx;
+    xx.d = value;
+    hashValue = xx.i[0];
+  }
+  return hashValue%(size);
+}
+static int hashCut2 (const OsiRowCut2 & x, int size) 
+{
+  int xN =x.row().getNumElements();
+  double xLb = x.lb();
+  double xUb = x.ub();
+  const int * xIndices = x.row().getIndices();
+  const double * xElements = x.row().getElements();
+  unsigned int hashValue;
+  double value=1.0;
+  if (xLb>-1.0e10)
+    value += xLb*multiplier[0];
+  if (xUb<1.0e10)
+    value += xUb*multiplier[1];
+  for( int j=0;j<xN;j++) {
+    int xColumn = xIndices[j];
+    double xValue = xElements[j];
+    int k=(j&1);
+    value += (j+1)*multiplier[k]*(xColumn+1)*xValue;
+  }
+  // should be compile time but too lazy for now
+  if (sizeof(value)>sizeof(hashValue)) {
+    assert (sizeof(value)==2*sizeof(hashValue));
+    union { double d; int i[2]; } xx;
+    xx.d = value;
+    hashValue = (xx.i[0] + xx.i[1]);
+  } else {
+    assert (sizeof(value)==sizeof(hashValue));
+    union { double d; unsigned int i[2]; } xx;
+    xx.d = value;
+    hashValue = xx.i[0];
+  }
+  return hashValue%(size);
+}
+static bool same (const OsiRowCut2 & x, const OsiRowCut2 & y) 
+{
+  int xN =x.row().getNumElements();
+  int yN =y.row().getNumElements();
+  bool identical=false;
+  if (xN==yN) {
+    double xLb = x.lb();
+    double xUb = x.ub();
+    double yLb = y.lb();
+    double yUb = y.ub();
+    if (fabs(xLb-yLb)<1.0e-8&&fabs(xUb-yUb)<1.0e-8) {
+      const int * xIndices = x.row().getIndices();
+      const double * xElements = x.row().getElements();
+      const int * yIndices = y.row().getIndices();
+      const double * yElements = y.row().getElements();
+      int j;
+      for( j=0;j<xN;j++) {
+	if (xIndices[j]!=yIndices[j])
+	  break;
+	if (fabs(xElements[j]-yElements[j])>1.0e-12)
+	  break;
+      }
+      identical =  (j==xN);
+    }
+  }
+  return identical;
+}
+static bool same2 (const OsiRowCut2 & x, const OsiRowCut2 & y) 
+{
+  int xN =x.row().getNumElements();
+  int yN =y.row().getNumElements();
+  bool identical=false;
+  if (xN==yN) {
+    double xLb = x.lb();
+    double xUb = x.ub();
+    double yLb = y.lb();
+    double yUb = y.ub();
+    if (fabs(xLb-yLb)<1.0e-8&&fabs(xUb-yUb)<1.0e-8) {
+      const int * xIndices = x.row().getIndices();
+      const double * xElements = x.row().getElements();
+      const int * yIndices = y.row().getIndices();
+      const double * yElements = y.row().getElements();
+      int j;
+      for( j=0;j<xN;j++) {
+	if (xIndices[j]!=yIndices[j])
+	  break;
+	if (fabs(xElements[j]-yElements[j])>1.0e-12)
+	  break;
+      }
+      identical =  (j==xN);
+    }
+  }
+  return identical;
+}
+CbcRowCuts::CbcRowCuts(int initialMaxSize, int hashMultiplier)
+{
+  numberCuts_=0;
+  size_ = initialMaxSize;
+  hashMultiplier_ = hashMultiplier;
+  int hashSize=hashMultiplier_*size_;
+  if (size_) {
+    rowCut_ = new  OsiRowCut2 * [size_];
+    hash_ = new CoinHashLink[hashSize];
+  } else {
+    rowCut_ = NULL;
+    hash_ = NULL;
+  }
+  for (int i=0;i<hashSize;i++) {
+    hash_[i].index=-1;
+    hash_[i].next=-1;
+  }
+  lastHash_=-1;
+}
+CbcRowCuts::~CbcRowCuts()
+{
+  for (int i=0;i<numberCuts_;i++)
+    delete rowCut_[i];
+  delete [] rowCut_;
+  delete [] hash_;
+}
+CbcRowCuts::CbcRowCuts(const CbcRowCuts& rhs)
+{
+  numberCuts_=rhs.numberCuts_;
+  hashMultiplier_ = rhs.hashMultiplier_;
+  size_ = rhs.size_;
+  int hashSize= size_*hashMultiplier_;
+  lastHash_=rhs.lastHash_;
+  if (size_) {
+    rowCut_ = new  OsiRowCut2 * [size_];
+    hash_ = new CoinHashLink[hashSize];
+    for (int i=0;i<hashSize;i++) {
+      hash_[i] = rhs.hash_[i];
+    }
+    for (int i=0;i<numberCuts_;i++) {
+      if (rhs.rowCut_[i])
+	rowCut_[i]=new OsiRowCut2(*rhs.rowCut_[i]);
+      else
+	rowCut_[i]=NULL;
+    }
+  } else {
+    rowCut_ = NULL;
+    hash_ = NULL;
+  }
+}
+CbcRowCuts& 
+CbcRowCuts::operator=(const CbcRowCuts& rhs)
+{
+  if (this != &rhs) {
+    for (int i=0;i<numberCuts_;i++)
+      delete rowCut_[i];
+    delete [] rowCut_;
+    delete [] hash_;
+    numberCuts_=rhs.numberCuts_;
+    hashMultiplier_ = rhs.hashMultiplier_;
+    size_ = rhs.size_;
+    lastHash_=rhs.lastHash_;
+    if (size_) {
+      rowCut_ = new  OsiRowCut2 * [size_];
+      int hashSize= size_*hashMultiplier_;
+      hash_ = new CoinHashLink[hashSize];
+      for (int i=0;i<hashSize;i++) {
+	hash_[i] = rhs.hash_[i];
+      }
+      for (int i=0;i<numberCuts_;i++) {
+	if (rhs.rowCut_[i])
+	  rowCut_[i]=new OsiRowCut2(*rhs.rowCut_[i]);
+	else
+	  rowCut_[i]=NULL;
+      }
+    } else {
+      rowCut_ = NULL;
+      hash_ = NULL;
+    }
+  }
+  return *this;
+}
+void 
+CbcRowCuts::eraseRowCut(int sequence)
+{
+  // find
+  assert (sequence>=0&&sequence<numberCuts_);
+  OsiRowCut2 * cut = rowCut_[sequence];
+  int hashSize= size_*hashMultiplier_;
+  int ipos = hashCut(*cut,hashSize);
+  int found = -1;
+  while ( true ) {
+    int j1 = hash_[ipos].index;
+    if ( j1 >= 0 ) {
+      if (j1!=sequence) {
+	int k = hash_[ipos].next;
+	if ( k != -1 )
+	  ipos = k;
+	else
+	  break;
+      } else {
+	found = j1;
+	break;
+      }
+    } else {
+      break;
+    }
+  }
+  assert (found>=0);
+  assert (hash_[ipos].index==sequence);
+  // shuffle up
+  while (hash_[ipos].next>=0) {
+    int k = hash_[ipos].next;
+    hash_[ipos]=hash_[k];
+    ipos=k;
+  }
+  delete cut;
+  // move last to found
+  numberCuts_--;
+  if (numberCuts_) {
+    ipos = hashCut(*rowCut_[numberCuts_],hashSize);
+    while ( true ) {
+      int j1 = hash_[ipos].index;
+      if (j1!=numberCuts_) {
+	int k = hash_[ipos].next;
+	ipos = k;
+      } else {
+	// change
+	hash_[ipos].index=found;
+	rowCut_[found]=rowCut_[numberCuts_];
+	rowCut_[numberCuts_]=NULL;
+	break;
+      }
+    }
+  }
+  assert (!rowCut_[numberCuts_]);
+}
+// Return 0 if added, 1 if not, -1 if not added because of space
+int 
+CbcRowCuts::addCutIfNotDuplicate(const OsiRowCut & cut,int whichType)
+{
+  int hashSize= size_*hashMultiplier_;
+  if (numberCuts_==size_) {
+    size_ = 2*size_+100;
+    hashSize=hashMultiplier_*size_;
+    OsiRowCut2 ** temp = new  OsiRowCut2 * [size_];
+    delete [] hash_;
+    hash_ = new CoinHashLink[hashSize];
+    for (int i=0;i<hashSize;i++) {
+      hash_[i].index=-1;
+      hash_[i].next=-1;
+    }
+    for (int i=0;i<numberCuts_;i++) {
+      temp[i]=rowCut_[i];
+      int ipos = hashCut(*temp[i],hashSize);
+      int found = -1;
+      int jpos=ipos;
+      while ( true ) {
+	int j1 = hash_[ipos].index;
+	
+	if ( j1 >= 0 ) {
+	  if ( !same(*temp[i],*temp[j1]) ) {
+	    int k = hash_[ipos].next;
+	    if ( k != -1 )
+	      ipos = k;
+	    else
+	      break;
+	  } else {
+	    found = j1;
+	    break;
+	  }
+	} else {
+	  break;
+	}
+      }
+      if (found<0) {
+	assert (hash_[ipos].next==-1);
+	if (ipos==jpos) {
+	  // first
+	  hash_[ipos].index=i;
+	} else {
+	  // find next space 
+	  while ( true ) {
+	    ++lastHash_;
+	    assert (lastHash_<hashSize);
+	    if ( hash_[lastHash_].index == -1 ) 
+	      break;
+	  }
+	  hash_[ipos].next = lastHash_;
+	  hash_[lastHash_].index = i;
+	}
+      }
+    }
+    delete [] rowCut_;
+    rowCut_ = temp;
+  }
+  if (numberCuts_<size_) {
+    double newLb = cut.lb();
+    double newUb = cut.ub();
+    CoinPackedVector vector = cut.row();
+    int numberElements =vector.getNumElements();
+    int * newIndices = vector.getIndices();
+    double * newElements = vector.getElements();
+    CoinSort_2(newIndices,newIndices+numberElements,newElements);
+    int i;
+    bool bad=false;
+    for (i=0;i<numberElements;i++) {
+      double value = fabs(newElements[i]);
+      if (value<1.0e-12||value>1.0e12) 
+	bad=true;
+    }
+    if (bad)
+      return 1;
+    OsiRowCut2 newCut(whichType);
+    newCut.setLb(newLb);
+    newCut.setUb(newUb);
+    newCut.setRow(vector);
+    int ipos = hashCut(newCut,hashSize);
+    int found = -1;
+    int jpos=ipos;
+    while ( true ) {
+      int j1 = hash_[ipos].index;
+      
+      if ( j1 >= 0 ) {
+	if ( !same(newCut,*rowCut_[j1]) ) {
+	  int k = hash_[ipos].next;
+	  if ( k != -1 )
+	    ipos = k;
+	  else
+	    break;
+	} else {
+	  found = j1;
+	  break;
+	}
+      } else {
+	break;
+      }
+    }
+    if (found<0) {
+      assert (hash_[ipos].next==-1);
+      if (ipos==jpos) {
+	// first
+	hash_[ipos].index=numberCuts_;
+      } else {
+	// find next space 
+	while ( true ) {
+	  ++lastHash_;
+	  assert (lastHash_<hashSize);
+	  if ( hash_[lastHash_].index == -1 ) 
+	    break;
+	}
+	hash_[ipos].next = lastHash_;
+	hash_[lastHash_].index = numberCuts_;
+      }
+      OsiRowCut2 * newCutPtr = new OsiRowCut2(whichType);
+      newCutPtr->setLb(newLb);
+      newCutPtr->setUb(newUb);
+      newCutPtr->setRow(vector);
+      rowCut_[numberCuts_++]=newCutPtr;
+      return 0;
+    } else {
+      return 1;
+    }
+  } else {
+    return -1;
+  }
+}
+// Return 0 if added, 1 if not, -1 if not added because of space
+int 
+CbcRowCuts::addCutIfNotDuplicateWhenGreedy(const OsiRowCut & cut,int whichType)
+{
+  int hashSize= size_*hashMultiplier_;
+  if (numberCuts_==size_) {
+    size_ = 2*size_+100;
+    hashSize=hashMultiplier_*size_;
+    OsiRowCut2 ** temp = new  OsiRowCut2 * [size_];
+    delete [] hash_;
+    hash_ = new CoinHashLink[hashSize];
+    for (int i=0;i<hashSize;i++) {
+      hash_[i].index=-1;
+      hash_[i].next=-1;
+    }
+    for (int i=0;i<numberCuts_;i++) {
+      temp[i]=rowCut_[i];
+      int ipos = hashCut2(*temp[i],hashSize);
+      int found = -1;
+      int jpos=ipos;
+      while ( true ) {
+	int j1 = hash_[ipos].index;
+	
+	if ( j1 >= 0 ) {
+	  if ( !same2(*temp[i],*temp[j1]) ) {
+	    int k = hash_[ipos].next;
+	    if ( k != -1 )
+	      ipos = k;
+	    else
+	      break;
+	  } else {
+	    found = j1;
+	    break;
+	  }
+	} else {
+	  break;
+	}
+      }
+      if (found<0) {
+	assert (hash_[ipos].next==-1);
+	if (ipos==jpos) {
+	  // first
+	  hash_[ipos].index=i;
+	} else {
+	  // find next space 
+	  while ( true ) {
+	    ++lastHash_;
+	    assert (lastHash_<hashSize);
+	    if ( hash_[lastHash_].index == -1 ) 
+	      break;
+	  }
+	  hash_[ipos].next = lastHash_;
+	  hash_[lastHash_].index = i;
+	}
+      }
+    }
+    delete [] rowCut_;
+    rowCut_ = temp;
+  }
+  if (numberCuts_<size_) {
+    double newLb = cut.lb();
+    double newUb = cut.ub();
+    CoinPackedVector vector = cut.row();
+    int numberElements =vector.getNumElements();
+    int * newIndices = vector.getIndices();
+    double * newElements = vector.getElements();
+    CoinSort_2(newIndices,newIndices+numberElements,newElements);
+    int i;
+    bool bad=false;
+    for (i=0;i<numberElements;i++) {
+      double value = fabs(newElements[i]);
+      if (value<1.0e-12||value>1.0e12) 
+	bad=true;
+    }
+    if (bad)
+      return 1;
+    OsiRowCut2 newCut(whichType);
+    newCut.setLb(newLb);
+    newCut.setUb(newUb);
+    newCut.setRow(vector);
+    int ipos = hashCut2(newCut,hashSize);
+    int found = -1;
+    int jpos=ipos;
+    while ( true ) {
+      int j1 = hash_[ipos].index;
+      
+      if ( j1 >= 0 ) {
+	if ( !same2(newCut,*rowCut_[j1]) ) {
+	  int k = hash_[ipos].next;
+	  if ( k != -1 )
+	    ipos = k;
+	  else
+	    break;
+	} else {
+	  found = j1;
+	  break;
+	}
+      } else {
+	break;
+      }
+    }
+    if (found<0) {
+      assert (hash_[ipos].next==-1);
+      if (ipos==jpos) {
+	// first
+	hash_[ipos].index=numberCuts_;
+      } else {
+	// find next space 
+	while ( true ) {
+	  ++lastHash_;
+	  assert (lastHash_<hashSize);
+	  if ( hash_[lastHash_].index == -1 ) 
+	    break;
+	}
+	hash_[ipos].next = lastHash_;
+	hash_[lastHash_].index = numberCuts_;
+      }
+      OsiRowCut2 * newCutPtr = new OsiRowCut2(whichType);
+      newCutPtr->setLb(newLb);
+      newCutPtr->setUb(newUb);
+      newCutPtr->setRow(vector);
+      rowCut_[numberCuts_++]=newCutPtr;
+      return 0;
+    } else {
+      return 1;
+    }
+  } else {
+    return -1;
+  }
+}
+// Add in cuts as normal cuts and delete
+void 
+CbcRowCuts::addCuts(OsiCuts & cs)
+{
+  for (int i=0;i<numberCuts_;i++) {
+    cs.insert(*rowCut_[i]);
+    delete rowCut_[i] ;
+    rowCut_[i] = NULL ;
+  }
+  numberCuts_=0;
+}
diff --git a/cbits/coin/CbcCountRowCut.hpp b/cbits/coin/CbcCountRowCut.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCountRowCut.hpp
@@ -0,0 +1,166 @@
+/* $Id: CbcCountRowCut.hpp 1839 2013-01-16 18:41:25Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcCountRowCut_H
+#define CbcCountRowCut_H
+
+
+class OsiCuts;
+class OsiRowCut;
+class CbcNodeInfo;
+
+//#############################################################################
+/** \brief OsiRowCut augmented with bookkeeping
+
+  CbcCountRowCut is an OsiRowCut object augmented with bookkeeping
+  information: a reference count and information that specifies the
+  the generator that created the cut and the node to which it's associated.
+
+  The general principles for handling the reference count are as follows:
+  <ul>
+    <li> Once it's determined how the node will branch, increment the
+	 reference count under the assumption that all children will use
+         all cuts currently tight at the node and will survive to be placed
+	 in the search tree.
+    <li> As this assumption is proven incorrect (a cut becomes loose, or a
+	 child is fathomed), decrement the reference count accordingly.
+  </ul>
+  When all possible uses of a cut have been demonstrated to be unnecessary,
+  the reference count (#numberPointingToThis_) will fall to zero. The
+  CbcCountRowCut object (and its included OsiRowCut object) are then deleted.
+*/
+
+class CbcCountRowCut : public OsiRowCut {
+
+public:
+
+    /** @name Constructors & destructors */
+    //@{
+
+    /// Default Constructor
+    CbcCountRowCut ();
+
+    /// `Copy' constructor using an OsiRowCut
+    CbcCountRowCut ( const OsiRowCut &);
+
+    /// `Copy' constructor using an OsiRowCut and an CbcNodeInfo
+    CbcCountRowCut(const OsiRowCut &, CbcNodeInfo *, int whichOne,
+                   int whichGenerator = -1, int numberPointingToThis = 0);
+
+    /** Destructor
+
+      \note The destructor will reach out (via #owner_) and NULL the
+      reference to the cut in the owner's
+      \link CbcNodeInfo::cuts_ cuts_ \endlink list.
+    */
+    virtual ~CbcCountRowCut ();
+    //@}
+
+    /// Increment the number of references
+    void increment(int change = 1);
+
+    /// Decrement the number of references and return the number left.
+    int decrement(int change = 1);
+
+    /** \brief Set the information associating this cut with a node
+
+      An CbcNodeInfo object and an index in the cut set of the node.
+      For locally valid cuts, the node will be the  search tree node where the
+      cut was generated. For globally valid cuts, it's the node where the cut
+      was activated.
+    */
+    void setInfo(CbcNodeInfo *, int whichOne);
+
+    /// Number of other CbcNodeInfo objects pointing to this row cut
+    inline int numberPointingToThis() {
+        return numberPointingToThis_;
+    }
+
+    /// Which generator for cuts - as user order
+    inline int whichCutGenerator() const {
+        return whichCutGenerator_;
+    }
+
+    /// Returns true if can drop cut if slack basic
+    bool canDropCut(const OsiSolverInterface * solver, int row) const;
+
+#ifdef CHECK_CUT_COUNTS
+    // Just for printing sanity checks
+    int tempNumber_;
+#endif
+
+private:
+
+    /// Standard copy is illegal (reference counts would be incorrect)
+    CbcCountRowCut(const CbcCountRowCut &);
+
+    /// Standard assignment is illegal (reference counts would be incorrect)
+    CbcCountRowCut & operator=(const CbcCountRowCut& rhs);
+
+    /// Backward pointer to owning CbcNodeInfo
+    CbcNodeInfo * owner_;
+
+    /// Index of cut in owner's cut set
+    /// (\link CbcNodeInfo::cuts_ cuts_ \endlink).
+    int ownerCut_;
+
+    /// Number of other CbcNodeInfo objects pointing to this cut
+    int numberPointingToThis_;
+
+    /** Which generator created this cut 
+	(add 10000 if globally valid)
+	if -1 then from global cut pool
+	-2 cut branch
+        -3 unknown
+    */
+    int whichCutGenerator_;
+
+};
+/**
+   Really for Conflict cuts to -
+   a) stop duplicates
+   b) allow half baked cuts
+   The whichRow_ field in OsiRowCut2 is used for a type
+   0 - normal 
+   1 - processed cut
+   2 - unprocessed cut i.e. dual ray computation
+*/
+// for hashing
+typedef struct {
+  int index, next;
+} CoinHashLink;
+class CbcRowCuts {
+public:
+
+  CbcRowCuts(int initialMaxSize=0, int hashMultiplier=4 );
+  ~CbcRowCuts();
+  CbcRowCuts(const CbcRowCuts& rhs);
+  CbcRowCuts& operator=(const CbcRowCuts& rhs);
+  inline OsiRowCut2 * cut(int sequence) const
+  { return rowCut_[sequence];}
+  inline int numberCuts() const
+  { return numberCuts_;}
+  inline int sizeRowCuts() const
+  { return numberCuts_;}
+  inline OsiRowCut * rowCutPtr(int sequence)
+  { return rowCut_[sequence];}
+  void eraseRowCut(int sequence);
+  // Return 0 if added, 1 if not, -1 if not added because of space
+  int addCutIfNotDuplicate(const OsiRowCut & cut,int whichType=0);
+  // Return 0 if added, 1 if not, -1 if not added because of space
+  int addCutIfNotDuplicateWhenGreedy(const OsiRowCut & cut,int whichType=0);
+  // Add in cuts as normal cuts (and delete)
+  void addCuts(OsiCuts & cs);
+private:
+  OsiRowCut2 ** rowCut_;
+  /// Hash table
+  CoinHashLink *hash_;
+  int size_;
+  int hashMultiplier_;
+  int numberCuts_;
+  int lastHash_;
+};
+#endif
+
diff --git a/cbits/coin/CbcCutGenerator.cpp b/cbits/coin/CbcCutGenerator.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCutGenerator.cpp
@@ -0,0 +1,1274 @@
+/* $Id: CbcCutGenerator.cpp 1883 2013-04-06 13:33:15Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include "CbcConfig.h"
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#else
+#include "OsiSolverInterface.hpp"
+#endif
+//#define CGL_DEBUG 1
+#ifdef CGL_DEBUG
+#include "OsiRowCutDebugger.hpp"
+#endif
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcCutGenerator.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "CglProbing.hpp"
+#include "CoinTime.hpp"
+
+// Default Constructor
+CbcCutGenerator::CbcCutGenerator ()
+        : timeInCutGenerator_(0.0),
+        model_(NULL),
+        generator_(NULL),
+        generatorName_(NULL),
+        whenCutGenerator_(-1),
+        whenCutGeneratorInSub_(-100),
+        switchOffIfLessThan_(0),
+        depthCutGenerator_(-1),
+        depthCutGeneratorInSub_(-1),
+        inaccuracy_(0),
+        numberTimes_(0),
+        numberCuts_(0),
+        numberElements_(0),
+        numberColumnCuts_(0),
+        numberCutsActive_(0),
+        numberCutsAtRoot_(0),
+        numberActiveCutsAtRoot_(0),
+        numberShortCutsAtRoot_(0),
+	switches_(1),
+	maximumTries_(-1)
+{
+}
+// Normal constructor
+CbcCutGenerator::CbcCutGenerator(CbcModel * model, CglCutGenerator * generator,
+                                 int howOften, const char * name,
+                                 bool normal, bool atSolution,
+                                 bool infeasible, int howOftenInSub,
+                                 int whatDepth, int whatDepthInSub,
+                                 int switchOffIfLessThan)
+        :
+        timeInCutGenerator_(0.0),
+        depthCutGenerator_(whatDepth),
+        depthCutGeneratorInSub_(whatDepthInSub),
+        inaccuracy_(0),
+        numberTimes_(0),
+        numberCuts_(0),
+        numberElements_(0),
+        numberColumnCuts_(0),
+        numberCutsActive_(0),
+        numberCutsAtRoot_(0),
+        numberActiveCutsAtRoot_(0),
+        numberShortCutsAtRoot_(0),
+        switches_(1),
+	maximumTries_(-1)
+{
+    if (howOften < -1900) {
+        setGlobalCuts(true);
+        howOften += 2000;
+    } else if (howOften < -900) {
+        setGlobalCutsAtRoot(true);
+        howOften += 1000;
+    }
+    model_ = model;
+    generator_ = generator->clone();
+    generator_->refreshSolver(model_->solver());
+    setNeedsOptimalBasis(generator_->needsOptimalBasis());
+    whenCutGenerator_ = howOften;
+    whenCutGeneratorInSub_ = howOftenInSub;
+    switchOffIfLessThan_ = switchOffIfLessThan;
+    if (name)
+        generatorName_ = CoinStrdup(name);
+    else
+        generatorName_ = CoinStrdup("Unknown");
+    setNormal(normal);
+    setAtSolution(atSolution);
+    setWhenInfeasible(infeasible);
+}
+
+// Copy constructor
+CbcCutGenerator::CbcCutGenerator ( const CbcCutGenerator & rhs)
+{
+    model_ = rhs.model_;
+    generator_ = rhs.generator_->clone();
+    //generator_->refreshSolver(model_->solver());
+    whenCutGenerator_ = rhs.whenCutGenerator_;
+    whenCutGeneratorInSub_ = rhs.whenCutGeneratorInSub_;
+    switchOffIfLessThan_ = rhs.switchOffIfLessThan_;
+    depthCutGenerator_ = rhs.depthCutGenerator_;
+    depthCutGeneratorInSub_ = rhs.depthCutGeneratorInSub_;
+    generatorName_ = CoinStrdup(rhs.generatorName_);
+    switches_ = rhs.switches_;
+    maximumTries_ = rhs.maximumTries_;
+    timeInCutGenerator_ = rhs.timeInCutGenerator_;
+    savedCuts_ = rhs.savedCuts_;
+    inaccuracy_ = rhs.inaccuracy_;
+    numberTimes_ = rhs.numberTimes_;
+    numberCuts_ = rhs.numberCuts_;
+    numberElements_ = rhs.numberElements_;
+    numberColumnCuts_ = rhs.numberColumnCuts_;
+    numberCutsActive_ = rhs.numberCutsActive_;
+    numberCutsAtRoot_  = rhs.numberCutsAtRoot_;
+    numberActiveCutsAtRoot_ = rhs.numberActiveCutsAtRoot_;
+    numberShortCutsAtRoot_ = rhs.numberShortCutsAtRoot_;
+}
+
+// Assignment operator
+CbcCutGenerator &
+CbcCutGenerator::operator=( const CbcCutGenerator & rhs)
+{
+    if (this != &rhs) {
+        delete generator_;
+        free(generatorName_);
+        model_ = rhs.model_;
+        generator_ = rhs.generator_->clone();
+        generator_->refreshSolver(model_->solver());
+        whenCutGenerator_ = rhs.whenCutGenerator_;
+        whenCutGeneratorInSub_ = rhs.whenCutGeneratorInSub_;
+        switchOffIfLessThan_ = rhs.switchOffIfLessThan_;
+        depthCutGenerator_ = rhs.depthCutGenerator_;
+        depthCutGeneratorInSub_ = rhs.depthCutGeneratorInSub_;
+        generatorName_ = CoinStrdup(rhs.generatorName_);
+        switches_ = rhs.switches_;
+	maximumTries_ = rhs.maximumTries_;
+        timeInCutGenerator_ = rhs.timeInCutGenerator_;
+        savedCuts_ = rhs.savedCuts_;
+        inaccuracy_ = rhs.inaccuracy_;
+        numberTimes_ = rhs.numberTimes_;
+        numberCuts_ = rhs.numberCuts_;
+        numberElements_ = rhs.numberElements_;
+        numberColumnCuts_ = rhs.numberColumnCuts_;
+        numberCutsActive_ = rhs.numberCutsActive_;
+        numberCutsAtRoot_  = rhs.numberCutsAtRoot_;
+        numberActiveCutsAtRoot_ = rhs.numberActiveCutsAtRoot_;
+        numberShortCutsAtRoot_ = rhs.numberShortCutsAtRoot_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcCutGenerator::~CbcCutGenerator ()
+{
+    free(generatorName_);
+    delete generator_;
+}
+
+/* This is used to refresh any inforamtion.
+   It also refreshes the solver in the cut generator
+   in case generator wants to do some work
+*/
+void
+CbcCutGenerator::refreshModel(CbcModel * model)
+{
+    model_ = model;
+    generator_->refreshSolver(model_->solver());
+}
+/* Generate cuts for the model data contained in si.
+   The generated cuts are inserted into and returned in the
+   collection of cuts cs.
+*/
+bool
+CbcCutGenerator::generateCuts( OsiCuts & cs , int fullScan, OsiSolverInterface * solver, CbcNode * node)
+{
+    /*
+	  Make some decisions about whether we'll generate cuts. First convert
+	  whenCutGenerator_ to a set of canonical values for comparison to the node
+	  count.
+
+		 0 <	mod 1000000, with a result of 0 forced to 1
+	   -99 <= <= 0	convert to 1
+	  -100 =	Off, period
+	*/
+	int depth;
+    if (node)
+        depth = node->depth();
+    else
+        depth = 0;
+    int howOften = whenCutGenerator_;
+    if (dynamic_cast<CglProbing*>(generator_)) {
+        if (howOften == -100 && model_->doCutsNow(3)) {
+            howOften = 1; // do anyway
+        }
+    }
+    if (howOften == -100)
+        return false;
+    int pass = model_->getCurrentPassNumber() - 1;
+    if (maximumTries_>0) {
+      // howOften means what it says
+      if ((pass%howOften)!=0||depth)
+	return false;
+      else
+	howOften=1;
+    }
+    if (howOften > 0)
+        howOften = howOften % 1000000;
+    else
+        howOften = 1;
+    if (!howOften)
+        howOften = 1;
+    bool returnCode = false;
+    //OsiSolverInterface * solver = model_->solver();
+    // Reset cuts on first pass
+    if (!pass)
+        savedCuts_ = OsiCuts();
+    /*
+	  Determine if we should generate cuts based on node count.
+	*/
+	bool doThis = (model_->getNodeCount() % howOften) == 0;
+    /*
+	  If the user has provided a depth specification, it will override the node
+	  count specification.
+	*/
+	if (depthCutGenerator_ > 0) {
+        doThis = (depth % depthCutGenerator_) == 0;
+        if (depth < depthCutGenerator_)
+            doThis = true; // and also at top of tree
+    }
+	/*
+	  A few magic numbers ...
+
+	  The distinction between -100 and 100 for howOften is that we can override 100
+	  with fullScan. -100 means no cuts, period. As does the magic number -200 for
+	  whenCutGeneratorInSub_.
+	*/
+
+    // But turn off if 100
+    if (howOften == 100)
+        doThis = false;
+    // Switch off if special setting
+    if (whenCutGeneratorInSub_ == -200 && model_->parentModel()) {
+        fullScan = 0;
+        doThis = false;
+    }
+    if (fullScan || doThis) {
+        CoinThreadRandom * randomNumberGenerator = NULL;
+#ifdef COIN_HAS_CLP
+        {
+            OsiClpSolverInterface * clpSolver
+            = dynamic_cast<OsiClpSolverInterface *> (solver);
+            if (clpSolver)
+                randomNumberGenerator =
+                    clpSolver->getModelPtr()->randomNumberGenerator();
+        }
+#endif
+        double time1 = 0.0;
+        if (timing())
+            time1 = CoinCpuTime();
+        //#define CBC_DEBUG
+        int numberRowCutsBefore = cs.sizeRowCuts() ;
+        int numberColumnCutsBefore = cs.sizeColCuts() ;
+#ifdef JJF_ZERO
+        int cutsBefore = cs.sizeCuts();
+#endif
+        CglTreeInfo info;
+        info.level = depth;
+        info.pass = pass;
+        info.formulation_rows = model_->numberRowsAtContinuous();
+        info.inTree = node != NULL;
+        info.randomNumberGenerator = randomNumberGenerator;
+        info.options = (globalCutsAtRoot()) ? 8 : 0;
+        if (ineffectualCuts())
+            info.options |= 32;
+        if (globalCuts())
+            info.options |= 16;
+        if (fullScan < 0)
+            info.options |= 128;
+	if (whetherInMustCallAgainMode())
+	  info.options |= 1024;
+        // See if we want alternate set of cuts
+        if ((model_->moreSpecialOptions()&16384) != 0)
+            info.options |= 256;
+        if (model_->parentModel())
+            info.options |= 512;
+        // above had &&!model_->parentModel()&&depth<2)
+        incrementNumberTimesEntered();
+        CglProbing* generator =
+            dynamic_cast<CglProbing*>(generator_);
+	//if (!depth&&!pass)
+	//printf("Cut generator %s when %d\n",generatorName_,whenCutGenerator_);
+        if (!generator) {
+            // Pass across model information in case it could be useful
+            //void * saveData = solver->getApplicationData();
+            //solver->setApplicationData(model_);
+            generator_->generateCuts(*solver, cs, info);
+            //solver->setApplicationData(saveData);
+        } else {
+            // Probing - return tight column bounds
+            CglTreeProbingInfo * info2 = model_->probingInfo();
+            bool doCuts = false;
+            if (info2 && !depth) {
+                info2->options = (globalCutsAtRoot()) ? 8 : 0;
+                info2->level = depth;
+                info2->pass = pass;
+                info2->formulation_rows = model_->numberRowsAtContinuous();
+                info2->inTree = node != NULL;
+                info2->randomNumberGenerator = randomNumberGenerator;
+                generator->generateCutsAndModify(*solver, cs, info2);
+                doCuts = true;
+            } else if (depth) {
+                /* The idea behind this is that probing may work in a different
+                   way deep in tree.  So every now and then try various
+                   combinations to see what works.
+                */
+#define TRY_NOW_AND_THEN
+#ifdef TRY_NOW_AND_THEN
+                if ((numberTimes_ == 200 || (numberTimes_ > 200 && (numberTimes_ % 2000) == 0))
+                        && !model_->parentModel() && info.formulation_rows > 200) {
+                    /* In tree, every now and then try various combinations
+                       maxStack, maxProbe (last 5 digits)
+                       123 is special and means CglProbing will try and
+                       be intelligent.
+                    */
+                    int test[] = {
+                        100123,
+                        199999,
+                        200123,
+                        299999,
+                        500123,
+                        599999,
+                        1000123,
+                        1099999,
+                        2000123,
+                        2099999
+                    };
+                    int n = static_cast<int> (sizeof(test) / sizeof(int));
+                    int saveStack = generator->getMaxLook();
+                    int saveNumber = generator->getMaxProbe();
+                    int kr1 = 0;
+                    int kc1 = 0;
+                    int bestStackTree = -1;
+                    int bestNumberTree = -1;
+                    for (int i = 0; i < n; i++) {
+                        //OsiCuts cs2 = cs;
+                        int stack = test[i] / 100000;
+                        int number = test[i] - 100000 * stack;
+                        generator->setMaxLook(stack);
+                        generator->setMaxProbe(number);
+                        int numberRowCutsBefore = cs.sizeRowCuts() ;
+                        int numberColumnCutsBefore = cs.sizeColCuts() ;
+                        generator_->generateCuts(*solver, cs, info);
+                        int numberRowCuts = cs.sizeRowCuts() - numberRowCutsBefore ;
+                        int numberColumnCuts = cs.sizeColCuts() - numberColumnCutsBefore ;
+#ifdef CLP_INVESTIGATE
+                        if (numberRowCuts < kr1 || numberColumnCuts < kc1)
+                            printf("Odd ");
+#endif
+                        if (numberRowCuts > kr1 || numberColumnCuts > kc1) {
+#ifdef CLP_INVESTIGATE
+                            printf("*** ");
+#endif
+                            kr1 = numberRowCuts;
+                            kc1 = numberColumnCuts;
+                            bestStackTree = stack;
+                            bestNumberTree = number;
+                            doCuts = true;
+                        }
+#ifdef CLP_INVESTIGATE
+                        printf("maxStack %d number %d gives %d row cuts and %d column cuts\n",
+                               stack, number, numberRowCuts, numberColumnCuts);
+#endif
+                    }
+                    generator->setMaxLook(saveStack);
+                    generator->setMaxProbe(saveNumber);
+                    if (bestStackTree > 0) {
+                        generator->setMaxLook(bestStackTree);
+                        generator->setMaxProbe(bestNumberTree);
+#ifdef CLP_INVESTIGATE
+                        printf("RRNumber %d -> %d, stack %d -> %d\n",
+                               saveNumber, bestNumberTree, saveStack, bestStackTree);
+#endif
+                    } else {
+                        // no good
+                        generator->setMaxLook(0);
+#ifdef CLP_INVESTIGATE
+                        printf("RRSwitching off number %d -> %d, stack %d -> %d\n",
+                               saveNumber, saveNumber, saveStack, 1);
+#endif
+                    }
+                }
+#endif
+                if (generator->getMaxLook() > 0 && !doCuts) {
+                    generator->generateCutsAndModify(*solver, cs, &info);
+                    doCuts = true;
+                }
+            } else {
+                // at root - don't always do
+                if (pass < 15 || (pass&1) == 0) {
+                    generator->generateCutsAndModify(*solver, cs, &info);
+                    doCuts = true;
+                }
+            }
+            if (doCuts && generator->tightLower()) {
+                // probing may have tightened bounds - check
+                const double * tightLower = generator->tightLower();
+                const double * lower = solver->getColLower();
+                const double * tightUpper = generator->tightUpper();
+                const double * upper = solver->getColUpper();
+                const double * solution = solver->getColSolution();
+                int j;
+                int numberColumns = solver->getNumCols();
+                double primalTolerance = 1.0e-8;
+                const char * tightenBounds = generator->tightenBounds();
+#ifdef CGL_DEBUG
+                const OsiRowCutDebugger * debugger = solver->getRowCutDebugger();
+                if (debugger && debugger->onOptimalPath(*solver)) {
+                    printf("On optimal path CbcCut\n");
+                    int nCols = solver->getNumCols();
+                    int i;
+                    const double * optimal = debugger->optimalSolution();
+                    const double * objective = solver->getObjCoefficients();
+                    double objval1 = 0.0, objval2 = 0.0;
+                    for (i = 0; i < nCols; i++) {
+#if CGL_DEBUG>1
+                        printf("%d %g %g %g %g\n", i, lower[i], solution[i], upper[i], optimal[i]);
+#endif
+                        objval1 += solution[i] * objective[i];
+                        objval2 += optimal[i] * objective[i];
+                        assert(optimal[i] >= lower[i] - 1.0e-5 && optimal[i] <= upper[i] + 1.0e-5);
+                        assert(optimal[i] >= tightLower[i] - 1.0e-5 && optimal[i] <= tightUpper[i] + 1.0e-5);
+                    }
+                    printf("current obj %g, integer %g\n", objval1, objval2);
+                }
+#endif
+                bool feasible = true;
+                if ((model_->getThreadMode()&2) == 0) {
+                    for (j = 0; j < numberColumns; j++) {
+                        if (solver->isInteger(j)) {
+                            if (tightUpper[j] < upper[j]) {
+                                double nearest = floor(tightUpper[j] + 0.5);
+                                //assert (fabs(tightUpper[j]-nearest)<1.0e-5); may be infeasible
+                                solver->setColUpper(j, nearest);
+                                if (nearest < solution[j] - primalTolerance)
+                                    returnCode = true;
+                            }
+                            if (tightLower[j] > lower[j]) {
+                                double nearest = floor(tightLower[j] + 0.5);
+                                //assert (fabs(tightLower[j]-nearest)<1.0e-5); may be infeasible
+                                solver->setColLower(j, nearest);
+                                if (nearest > solution[j] + primalTolerance)
+                                    returnCode = true;
+                            }
+                        } else {
+                            if (upper[j] > lower[j]) {
+                                if (tightUpper[j] == tightLower[j]) {
+                                    // fix
+                                    //if (tightLower[j]!=lower[j])
+                                    solver->setColLower(j, tightLower[j]);
+                                    //if (tightUpper[j]!=upper[j])
+                                    solver->setColUpper(j, tightUpper[j]);
+                                    if (tightLower[j] > solution[j] + primalTolerance ||
+                                            tightUpper[j] < solution[j] - primalTolerance)
+                                        returnCode = true;
+                                } else if (tightenBounds && tightenBounds[j]) {
+                                    solver->setColLower(j, CoinMax(tightLower[j], lower[j]));
+                                    solver->setColUpper(j, CoinMin(tightUpper[j], upper[j]));
+                                    if (tightLower[j] > solution[j] + primalTolerance ||
+                                            tightUpper[j] < solution[j] - primalTolerance)
+                                        returnCode = true;
+                                }
+                            }
+                        }
+                        if (upper[j] < lower[j] - 1.0e-3) {
+                            feasible = false;
+                            break;
+                        }
+                    }
+                } else {
+                    CoinPackedVector lbs;
+                    CoinPackedVector ubs;
+                    int numberChanged = 0;
+                    bool ifCut = false;
+                    for (j = 0; j < numberColumns; j++) {
+                        if (solver->isInteger(j)) {
+                            if (tightUpper[j] < upper[j]) {
+                                double nearest = floor(tightUpper[j] + 0.5);
+                                //assert (fabs(tightUpper[j]-nearest)<1.0e-5); may be infeasible
+                                ubs.insert(j, nearest);
+                                numberChanged++;
+                                if (nearest < solution[j] - primalTolerance)
+                                    ifCut = true;
+                            }
+                            if (tightLower[j] > lower[j]) {
+                                double nearest = floor(tightLower[j] + 0.5);
+                                //assert (fabs(tightLower[j]-nearest)<1.0e-5); may be infeasible
+                                lbs.insert(j, nearest);
+                                numberChanged++;
+                                if (nearest > solution[j] + primalTolerance)
+                                    ifCut = true;
+                            }
+                        } else {
+                            if (upper[j] > lower[j]) {
+                                if (tightUpper[j] == tightLower[j]) {
+                                    // fix
+                                    lbs.insert(j, tightLower[j]);
+                                    ubs.insert(j, tightUpper[j]);
+                                    if (tightLower[j] > solution[j] + primalTolerance ||
+                                            tightUpper[j] < solution[j] - primalTolerance)
+                                        ifCut = true;
+                                } else if (tightenBounds && tightenBounds[j]) {
+                                    lbs.insert(j, CoinMax(tightLower[j], lower[j]));
+                                    ubs.insert(j, CoinMin(tightUpper[j], upper[j]));
+                                    if (tightLower[j] > solution[j] + primalTolerance ||
+                                            tightUpper[j] < solution[j] - primalTolerance)
+                                        ifCut = true;
+                                }
+                            }
+                        }
+                        if (upper[j] < lower[j] - 1.0e-3) {
+                            feasible = false;
+                            break;
+                        }
+                    }
+                    if (numberChanged) {
+                        OsiColCut cc;
+                        cc.setUbs(ubs);
+                        cc.setLbs(lbs);
+                        if (ifCut) {
+                            cc.setEffectiveness(100.0);
+                        } else {
+                            cc.setEffectiveness(1.0e-5);
+                        }
+                        cs.insert(cc);
+                    }
+                }
+                if (!feasible) {
+                    // not feasible -add infeasible cut
+                    OsiRowCut rc;
+                    rc.setLb(COIN_DBL_MAX);
+                    rc.setUb(0.0);
+                    cs.insert(rc);
+                }
+            }
+            //if (!solver->basisIsAvailable())
+	    //returnCode=true;
+	    if (!returnCode) {
+	      // bounds changed but still optimal
+#ifdef COIN_HAS_CLP
+	      OsiClpSolverInterface * clpSolver
+		= dynamic_cast<OsiClpSolverInterface *> (solver);
+	      if (clpSolver) {
+		clpSolver->setLastAlgorithm(2);
+	      }
+#endif
+	    }
+#ifdef JJF_ZERO
+            // Pass across info to pseudocosts
+            char * mark = new char[numberColumns];
+            memset(mark, 0, numberColumns);
+            int nLook = generator->numberThisTime();
+            const int * lookedAt = generator->lookedAt();
+            const int * fixedDown = generator->fixedDown();
+            const int * fixedUp = generator->fixedUp();
+            for (j = 0; j < nLook; j++)
+                mark[lookedAt[j]] = 1;
+            int numberObjects = model_->numberObjects();
+            for (int i = 0; i < numberObjects; i++) {
+                CbcSimpleIntegerDynamicPseudoCost * obj1 =
+                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(model_->modifiableObject(i)) ;
+                if (obj1) {
+                    int iColumn = obj1->columnNumber();
+                    if (mark[iColumn])
+                        obj1->setProbingInformation(fixedDown[iColumn], fixedUp[iColumn]);
+                }
+            }
+            delete [] mark;
+#endif
+        }
+        CbcCutModifier * modifier = model_->cutModifier();
+        if (modifier) {
+            int numberRowCutsAfter = cs.sizeRowCuts() ;
+            int k ;
+            int nOdd = 0;
+            //const OsiSolverInterface * solver = model_->solver();
+            for (k = numberRowCutsAfter - 1; k >= numberRowCutsBefore; k--) {
+                OsiRowCut & thisCut = cs.rowCut(k) ;
+                int returnCode = modifier->modify(solver, thisCut);
+                if (returnCode) {
+                    nOdd++;
+                    if (returnCode == 3)
+                        cs.eraseRowCut(k);
+                }
+            }
+            if (nOdd)
+                COIN_DETAIL_PRINT(printf("Cut generator %s produced %d cuts of which %d were modified\n",
+					 generatorName_, numberRowCutsAfter - numberRowCutsBefore, nOdd));
+        }
+        {
+            // make all row cuts without test for duplicate
+            int numberRowCutsAfter = cs.sizeRowCuts() ;
+            int k ;
+#ifdef CGL_DEBUG
+            const OsiRowCutDebugger * debugger = solver->getRowCutDebugger();
+#endif
+            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                OsiRowCut * thisCut = cs.rowCutPtr(k) ;
+#ifdef CGL_DEBUG
+                if (debugger && debugger->onOptimalPath(*solver))
+                    assert(!debugger->invalidCut(*thisCut));
+#endif
+                thisCut->mutableRow().setTestForDuplicateIndex(false);
+            }
+        }
+        // Add in saved cuts if violated
+        if (false && !depth) {
+            const double * solution = solver->getColSolution();
+            double primalTolerance = 1.0e-7;
+            int numberCuts = savedCuts_.sizeRowCuts() ;
+            for (int k = numberCuts - 1; k >= 0; k--) {
+                const OsiRowCut * thisCut = savedCuts_.rowCutPtr(k) ;
+                double sum = 0.0;
+                int n = thisCut->row().getNumElements();
+                const int * column = thisCut->row().getIndices();
+                const double * element = thisCut->row().getElements();
+                assert (n);
+                for (int i = 0; i < n; i++) {
+                    double value = element[i];
+                    sum += value * solution[column[i]];
+                }
+                if (sum > thisCut->ub() + primalTolerance) {
+                    sum = sum - thisCut->ub();
+                } else if (sum < thisCut->lb() - primalTolerance) {
+                    sum = thisCut->lb() - sum;
+                } else {
+                    sum = 0.0;
+                }
+                if (sum) {
+                    // add to candidates and take out here
+                    cs.insert(*thisCut);
+                    savedCuts_.eraseRowCut(k);
+                }
+            }
+        }
+        if (!atSolution()) {
+            int numberRowCutsAfter = cs.sizeRowCuts() ;
+            int k ;
+            int nEls = 0;
+            int nCuts = numberRowCutsAfter - numberRowCutsBefore;
+            // Remove NULL cuts!
+            int nNull = 0;
+            const double * solution = solver->getColSolution();
+            bool feasible = true;
+            double primalTolerance = 1.0e-7;
+            int shortCut = (depth) ? -1 : generator_->maximumLengthOfCutInTree();
+            for (k = numberRowCutsAfter - 1; k >= numberRowCutsBefore; k--) {
+                const OsiRowCut * thisCut = cs.rowCutPtr(k) ;
+                double sum = 0.0;
+                if (thisCut->lb() <= thisCut->ub()) {
+                    int n = thisCut->row().getNumElements();
+                    if (n <= shortCut)
+                        numberShortCutsAtRoot_++;
+                    const int * column = thisCut->row().getIndices();
+                    const double * element = thisCut->row().getElements();
+                    if (n <= 0) {
+                        // infeasible cut - give up
+                        feasible = false;
+                        break;
+                    }
+                    nEls += n;
+                    for (int i = 0; i < n; i++) {
+                        double value = element[i];
+                        sum += value * solution[column[i]];
+                    }
+                    if (sum > thisCut->ub() + primalTolerance) {
+                        sum = sum - thisCut->ub();
+                    } else if (sum < thisCut->lb() - primalTolerance) {
+                        sum = thisCut->lb() - sum;
+                    } else {
+                        sum = 0.0;
+                        cs.eraseRowCut(k);
+                        nNull++;
+                    }
+                }
+            }
+            //if (nNull)
+            //printf("%s has %d cuts and %d elements - %d null!\n",generatorName_,
+            //       nCuts,nEls,nNull);
+            numberRowCutsAfter = cs.sizeRowCuts() ;
+            nCuts = numberRowCutsAfter - numberRowCutsBefore;
+            nEls = 0;
+            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                const OsiRowCut * thisCut = cs.rowCutPtr(k) ;
+                int n = thisCut->row().getNumElements();
+                nEls += n;
+            }
+            //printf("%s has %d cuts and %d elements\n",generatorName_,
+            //     nCuts,nEls);
+            int nElsNow = solver->getMatrixByCol()->getNumElements();
+            int numberColumns = solver->getNumCols();
+            int numberRows = solver->getNumRows();
+            //double averagePerRow = static_cast<double>(nElsNow)/
+            //static_cast<double>(numberRows);
+            int nAdd;
+            int nAdd2;
+            int nReasonable;
+            if (!model_->parentModel() && depth < 2) {
+                if (inaccuracy_ < 3) {
+                    nAdd = 10000;
+                    if (pass > 0 && numberColumns > -500)
+                        nAdd = CoinMin(nAdd, nElsNow + 2 * numberRows);
+                } else {
+                    nAdd = 10000;
+                    if (pass > 0)
+                        nAdd = CoinMin(nAdd, nElsNow + 2 * numberRows);
+                }
+                nAdd2 = 5 * numberColumns;
+                nReasonable = CoinMax(nAdd2, nElsNow / 8 + nAdd);
+                if (!depth && !pass) {
+                    // allow more
+                    nAdd += nElsNow / 2;
+                    nAdd2 += nElsNow / 2;
+                    nReasonable += nElsNow / 2;
+                }
+                //if (!depth&&ineffectualCuts())
+                //nReasonable *= 2;
+            } else {
+                nAdd = 200;
+                nAdd2 = 2 * numberColumns;
+                nReasonable = CoinMax(nAdd2, nElsNow / 8 + nAdd);
+            }
+            //#define UNS_WEIGHT 0.1
+#ifdef UNS_WEIGHT
+            const double * colLower = solver->getColLower();
+            const double * colUpper = solver->getColUpper();
+#endif
+            if (/*nEls>CoinMax(nAdd2,nElsNow/8+nAdd)*/nCuts && feasible) {
+                //printf("need to remove cuts\n");
+                // just add most effective
+#ifndef JJF_ONE
+                int nDelete = nEls - nReasonable;
+
+                nElsNow = nEls;
+                double * sort = new double [nCuts];
+                int * which = new int [nCuts];
+                // For parallel cuts
+                double * element2 = new double [numberColumns];
+                //#define USE_OBJECTIVE 2
+#ifdef USE_OBJECTIVE
+                const double *objective = solver->getObjCoefficients() ;
+#if USE_OBJECTIVE>1
+                double objNorm = 0.0;
+                for (int i = 0; i < numberColumns; i++)
+                    objNorm += objective[i] * objective[i];
+                if (objNorm)
+                    objNorm = 1.0 / sqrt(objNorm);
+                else
+                    objNorm = 1.0;
+                objNorm *= 0.01; // downgrade
+#endif
+#endif
+                CoinZeroN(element2, numberColumns);
+                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                    const OsiRowCut * thisCut = cs.rowCutPtr(k) ;
+                    double sum = 0.0;
+                    if (thisCut->lb() <= thisCut->ub()) {
+                        int n = thisCut->row().getNumElements();
+                        const int * column = thisCut->row().getIndices();
+                        const double * element = thisCut->row().getElements();
+                        assert (n);
+#ifdef UNS_WEIGHT
+                        double normU = 0.0;
+                        double norm = 1.0e-3;
+                        int nU = 0;
+                        for (int i = 0; i < n; i++) {
+                            double value = element[i];
+                            int iColumn = column[i];
+                            double solValue = solution[iColumn];
+                            sum += value * solValue;
+                            value *= value;
+                            norm += value;
+                            if (solValue > colLower[iColumn] + 1.0e-6 &&
+                                    solValue < colUpper[iColumn] - 1.0e-6) {
+                                normU += value;
+                                nU++;
+                            }
+                        }
+#ifdef JJF_ZERO
+                        int nS = n - nU;
+                        if (numberColumns > 20000) {
+                            if (nS > 50) {
+                                double ratio = 50.0 / nS;
+                                normU /= ratio;
+                            }
+                        }
+#endif
+                        norm += UNS_WEIGHT * (normU - norm);
+#else
+                        double norm = 1.0e-3;
+#ifdef USE_OBJECTIVE
+                        double obj = 0.0;
+#endif
+                        for (int i = 0; i < n; i++) {
+                            int iColumn = column[i];
+                            double value = element[i];
+                            sum += value * solution[iColumn];
+                            norm += value * value;
+#ifdef USE_OBJECTIVE
+                            obj += value * objective[iColumn];
+#endif
+                        }
+#endif
+                        if (sum > thisCut->ub()) {
+                            sum = sum - thisCut->ub();
+                        } else if (sum < thisCut->lb()) {
+                            sum = thisCut->lb() - sum;
+                        } else {
+                            sum = 0.0;
+                        }
+#ifdef USE_OBJECTIVE
+                        if (sum) {
+#if USE_OBJECTIVE==1
+                            obj = CoinMax(1.0e-6, fabs(obj));
+                            norm = sqrt(obj * norm);
+                            //sum += fabs(obj)*invObjNorm;
+                            //printf("sum %g norm %g normobj %g invNorm %g mod %g\n",
+                            //     sum,norm,obj,invObjNorm,obj*invObjNorm);
+                            // normalize
+                            sum /= sqrt(norm);
+#else
+                            // normalize
+                            norm = 1.0 / sqrt(norm);
+                            sum = (sum + objNorm * obj) * norm;
+#endif
+                        }
+#else
+                        // normalize
+                        sum /= sqrt(norm);
+#endif
+                        //sum /= pow(norm,0.3);
+                        // adjust for length
+                        //sum /= pow(reinterpret_cast<double>(n),0.2);
+                        //sum /= sqrt((double) n);
+                        // randomize
+                        //double randomNumber =
+                        //model_->randomNumberGenerator()->randomDouble();
+                        //sum *= (0.5+randomNumber);
+                    } else {
+                        // keep
+                        sum = COIN_DBL_MAX;
+                    }
+                    sort[k-numberRowCutsBefore] = sum;
+                    which[k-numberRowCutsBefore] = k;
+                }
+                CoinSort_2(sort, sort + nCuts, which);
+                // Now see which ones are too similar
+                int nParallel = 0;
+                double testValue = (depth > 1) ? 0.99 : 0.999999;
+                for (k = 0; k < nCuts; k++) {
+                    int j = which[k];
+                    const OsiRowCut * thisCut = cs.rowCutPtr(j) ;
+                    if (thisCut->lb() > thisCut->ub())
+                        break; // cut is infeasible
+                    int n = thisCut->row().getNumElements();
+                    const int * column = thisCut->row().getIndices();
+                    const double * element = thisCut->row().getElements();
+                    assert (n);
+                    double norm = 0.0;
+                    double lb = thisCut->lb();
+                    double ub = thisCut->ub();
+                    for (int i = 0; i < n; i++) {
+                        double value = element[i];
+                        element2[column[i]] = value;
+                        norm += value * value;
+                    }
+                    int kkk = CoinMin(nCuts, k + 5);
+                    for (int kk = k + 1; kk < kkk; kk++) {
+                        int jj = which[kk];
+                        const OsiRowCut * thisCut2 = cs.rowCutPtr(jj) ;
+                        if (thisCut2->lb() > thisCut2->ub())
+                            break; // cut is infeasible
+                        int nB = thisCut2->row().getNumElements();
+                        const int * columnB = thisCut2->row().getIndices();
+                        const double * elementB = thisCut2->row().getElements();
+                        assert (nB);
+                        double normB = 0.0;
+                        double product = 0.0;
+                        for (int i = 0; i < nB; i++) {
+                            double value = elementB[i];
+                            normB += value * value;
+                            product += value * element2[columnB[i]];
+                        }
+                        if (product > 0.0 && product*product > testValue*norm*normB) {
+                            bool parallel = true;
+                            double lbB = thisCut2->lb();
+                            double ubB = thisCut2->ub();
+                            if ((lb < -1.0e20 && lbB > -1.0e20) ||
+                                    (lbB < -1.0e20 && lb > -1.0e20))
+                                parallel = false;
+                            double tolerance;
+                            tolerance = CoinMax(fabs(lb), fabs(lbB)) + 1.0e-6;
+                            if (fabs(lb - lbB) > tolerance)
+                                parallel = false;
+                            if ((ub > 1.0e20 && ubB < 1.0e20) ||
+                                    (ubB > 1.0e20 && ub < 1.0e20))
+                                parallel = false;
+                            tolerance = CoinMax(fabs(ub), fabs(ubB)) + 1.0e-6;
+                            if (fabs(ub - ubB) > tolerance)
+                                parallel = false;
+                            if (parallel) {
+                                nParallel++;
+                                sort[k] = 0.0;
+                                break;
+                            }
+                        }
+                    }
+                    for (int i = 0; i < n; i++) {
+                        element2[column[i]] = 0.0;
+                    }
+                }
+                delete [] element2;
+                CoinSort_2(sort, sort + nCuts, which);
+                k = 0;
+                while (nDelete > 0 || !sort[k]) {
+                    int iCut = which[k];
+                    const OsiRowCut * thisCut = cs.rowCutPtr(iCut) ;
+                    int n = thisCut->row().getNumElements();
+                    // may be best, just to save if short
+                    if (false && n && sort[k]) {
+                        // add to saved cuts
+                        savedCuts_.insert(*thisCut);
+                    }
+                    nDelete -= n;
+                    k++;
+                    if (k >= nCuts)
+                        break;
+                }
+                std::sort(which, which + k);
+                k--;
+                for (; k >= 0; k--) {
+                    cs.eraseRowCut(which[k]);
+                }
+                delete [] sort;
+                delete [] which;
+                numberRowCutsAfter = cs.sizeRowCuts() ;
+#else
+                double * norm = new double [nCuts];
+                int * which = new int [2*nCuts];
+                double * score = new double [nCuts];
+                double * ortho = new double [nCuts];
+                int nIn = 0;
+                int nOut = nCuts;
+                // For parallel cuts
+                double * element2 = new double [numberColumns];
+                const double *objective = solver->getObjCoefficients() ;
+                double objNorm = 0.0;
+                for (int i = 0; i < numberColumns; i++)
+                    objNorm += objective[i] * objective[i];
+                if (objNorm)
+                    objNorm = 1.0 / sqrt(objNorm);
+                else
+                    objNorm = 1.0;
+                objNorm *= 0.1; // weight of 0.1
+                CoinZeroN(element2, numberColumns);
+                int numberRowCuts = numberRowCutsAfter - numberRowCutsBefore;
+                int iBest = -1;
+                double best = 0.0;
+                int nPossible = 0;
+                double testValue = (depth > 1) ? 0.7 : 0.5;
+                for (k = 0; k < numberRowCuts; k++) {
+                    const OsiRowCut * thisCut = cs.rowCutPtr(k + numberRowCutsBefore) ;
+                    double sum = 0.0;
+                    if (thisCut->lb() <= thisCut->ub()) {
+                        int n = thisCut->row().getNumElements();
+                        const int * column = thisCut->row().getIndices();
+                        const double * element = thisCut->row().getElements();
+                        assert (n);
+                        double normThis = 1.0e-6;
+                        double obj = 0.0;
+                        for (int i = 0; i < n; i++) {
+                            int iColumn = column[i];
+                            double value = element[i];
+                            sum += value * solution[iColumn];
+                            normThis += value * value;
+                            obj += value * objective[iColumn];
+                        }
+                        if (sum > thisCut->ub()) {
+                            sum = sum - thisCut->ub();
+                        } else if (sum < thisCut->lb()) {
+                            sum = thisCut->lb() - sum;
+                        } else {
+                            sum = 0.0;
+                        }
+                        if (sum) {
+                            normThis = 1.0 / sqrt(normThis);
+                            norm[k] = normThis;
+                            sum *= normThis;
+                            obj *= normThis;
+                            score[k] = sum + obj * objNorm;
+                            ortho[k] = 1.0;
+                        }
+                    } else {
+                        // keep and discard others
+                        nIn = 1;
+                        which[0] = k;
+                        for (int j = 0; j < numberRowCuts; j++) {
+                            if (j != k)
+                                which[nOut++] = j;
+                        }
+                        iBest = -1;
+                        break;
+                    }
+                    if (sum) {
+                        if (score[k] > best) {
+                            best = score[k];
+                            iBest = nPossible;
+                        }
+                        which[nPossible++] = k;
+                    } else {
+                        which[nOut++] = k;
+                    }
+                }
+                while (iBest >= 0) {
+                    int kBest = which[iBest];
+                    int j = which[nIn];
+                    which[iBest] = j;
+                    which[nIn++] = kBest;
+                    const OsiRowCut * thisCut = cs.rowCutPtr(kBest + numberRowCutsBefore) ;
+                    int n = thisCut->row().getNumElements();
+                    nReasonable -= n;
+                    if (nReasonable <= 0) {
+                        for (k = nIn; k < nPossible; k++)
+                            which[nOut++] = which[k];
+                        break;
+                    }
+                    // Now see which ones are too similar and choose next
+                    iBest = -1;
+                    best = 0.0;
+                    int nOld = nPossible;
+                    nPossible = nIn;
+                    const int * column = thisCut->row().getIndices();
+                    const double * element = thisCut->row().getElements();
+                    assert (n);
+                    double normNew = norm[kBest];
+                    for (int i = 0; i < n; i++) {
+                        double value = element[i];
+                        element2[column[i]] = value;
+                    }
+                    for (int j = nIn; j < nOld; j++) {
+                        k = which[j];
+                        const OsiRowCut * thisCut2 = cs.rowCutPtr(k + numberRowCutsBefore) ;
+                        int nB = thisCut2->row().getNumElements();
+                        const int * columnB = thisCut2->row().getIndices();
+                        const double * elementB = thisCut2->row().getElements();
+                        assert (nB);
+                        double normB = norm[k];
+                        double product = 0.0;
+                        for (int i = 0; i < nB; i++) {
+                            double value = elementB[i];
+                            product += value * element2[columnB[i]];
+                        }
+                        double orthoScore = 1.0 - product * normNew * normB;
+                        if (orthoScore >= testValue) {
+                            ortho[k] = CoinMin(orthoScore, ortho[k]);
+                            double test = score[k] + ortho[k];
+                            if (test > best) {
+                                best = score[k];
+                                iBest = nPossible;
+                            }
+                            which[nPossible++] = k;
+                        } else {
+                            which[nOut++] = k;
+                        }
+                    }
+                    for (int i = 0; i < n; i++) {
+                        element2[column[i]] = 0.0;
+                    }
+                }
+                delete [] score;
+                delete [] ortho;
+                std::sort(which + nCuts, which + nOut);
+                k = nOut - 1;
+                for (; k >= nCuts; k--) {
+                    cs.eraseRowCut(which[k] + numberRowCutsBefore);
+                }
+                delete [] norm;
+                delete [] which;
+                numberRowCutsAfter = cs.sizeRowCuts() ;
+#endif
+            }
+        }
+#ifdef CBC_DEBUG
+        {
+            int numberRowCutsAfter = cs.sizeRowCuts() ;
+            int k ;
+            int nBad = 0;
+            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                OsiRowCut thisCut = cs.rowCut(k) ;
+                if (thisCut.lb() > thisCut.ub() ||
+                        thisCut.lb() > 1.0e8 ||
+                        thisCut.ub() < -1.0e8)
+                    printf("cut from %s has bounds %g and %g!\n",
+                           generatorName_, thisCut.lb(), thisCut.ub());
+                if (thisCut.lb() <= thisCut.ub()) {
+                    /* check size of elements.
+                       We can allow smaller but this helps debug generators as it
+                       is unsafe to have small elements */
+                    int n = thisCut.row().getNumElements();
+                    const int * column = thisCut.row().getIndices();
+                    const double * element = thisCut.row().getElements();
+                    assert (n);
+                    for (int i = 0; i < n; i++) {
+                        double value = element[i];
+                        if (fabs(value) <= 1.0e-12 || fabs(value) >= 1.0e20)
+                            nBad++;
+                    }
+                }
+                if (nBad)
+                    printf("Cut generator %s produced %d cuts of which %d had tiny or large elements\n",
+                           generatorName_, numberRowCutsAfter - numberRowCutsBefore, nBad);
+            }
+        }
+#endif
+	int numberRowCutsAfter = cs.sizeRowCuts() ;
+	int numberColumnCutsAfter = cs.sizeColCuts() ;
+        if (numberRowCutsBefore < numberRowCutsAfter) {
+            for (int k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                OsiRowCut thisCut = cs.rowCut(k) ;
+                int n = thisCut.row().getNumElements();
+                numberElements_ += n;
+            }
+#ifdef JJF_ZERO
+            printf("generator %s generated %d row cuts\n",
+                   generatorName_, numberRowCutsAfter - numberRowCutsBefore);
+#endif
+            numberCuts_ += numberRowCutsAfter - numberRowCutsBefore;
+        }
+        if (numberColumnCutsBefore < numberColumnCutsAfter) {
+#ifdef JJF_ZERO
+            printf("generator %s generated %d column cuts\n",
+                   generatorName_, numberColumnCutsAfter - numberColumnCutsBefore);
+#endif
+            numberColumnCuts_ += numberColumnCutsAfter - numberColumnCutsBefore;
+        }
+        if (timing())
+            timeInCutGenerator_ += CoinCpuTime() - time1;
+        // switch off if first time and no good
+        if (node == NULL && !pass ) {
+            if (numberRowCutsAfter - numberRowCutsBefore
+		< switchOffIfLessThan_ /*&& numberCuts_ < switchOffIfLessThan_*/) {
+	      // switch off
+	      maximumTries_ = 0;
+	      whenCutGenerator_=-100;
+	      //whenCutGenerator_ = -100;
+	      //whenCutGeneratorInSub_ = -200;
+            }
+        }
+	if (maximumTries_>0) {
+	  maximumTries_--;
+	  if (!maximumTries_) 
+	    whenCutGenerator_=-100;
+	}
+    }
+    return returnCode;
+}
+void
+CbcCutGenerator::setHowOften(int howOften)
+{
+
+    if (howOften >= 1000000) {
+        // leave Probing every SCANCUTS_PROBING
+        howOften = howOften % 1000000;
+        CglProbing* generator =
+            dynamic_cast<CglProbing*>(generator_);
+
+        if (generator && howOften > SCANCUTS_PROBING)
+            howOften = SCANCUTS_PROBING + 1000000;
+        else
+            howOften += 1000000;
+    }
+    whenCutGenerator_ = howOften;
+}
+void
+CbcCutGenerator::setWhatDepth(int value)
+{
+    depthCutGenerator_ = value;
+}
+void
+CbcCutGenerator::setWhatDepthInSub(int value)
+{
+    depthCutGeneratorInSub_ = value;
+}
+// Add in statistics from other
+void 
+CbcCutGenerator::addStatistics(const CbcCutGenerator * other)
+{
+  // Time in cut generator
+  timeInCutGenerator_ += other->timeInCutGenerator_;
+  // Number times cut generator entered
+  numberTimes_ += other->numberTimes_;
+  // Total number of cuts added
+  numberCuts_ += other->numberCuts_;
+  // Total number of elements added
+  numberElements_ += other->numberElements_;
+  // Total number of column cuts added
+  numberColumnCuts_ += other->numberColumnCuts_;
+  // Total number of cuts active after (at end of n cut passes at each node)
+  numberCutsActive_ += other->numberCutsActive_;
+  // Number of cuts generated at root
+  numberCutsAtRoot_ += other->numberCutsAtRoot_;
+  // Number of cuts active at root
+  numberActiveCutsAtRoot_ += other->numberActiveCutsAtRoot_;
+  // Number of short cuts at root
+  numberShortCutsAtRoot_ += other->numberShortCutsAtRoot_;
+}
+// Scale back statistics by factor
+void 
+CbcCutGenerator::scaleBackStatistics(int factor)
+{
+  // leave time
+  // Number times cut generator entered
+  numberTimes_ = (numberTimes_+factor-1)/factor;
+  // Total number of cuts added
+  numberCuts_ = (numberCuts_+factor-1)/factor;
+  // Total number of elements added
+  numberElements_ = (numberElements_+factor-1)/factor;
+  // Total number of column cuts added
+  numberColumnCuts_ = (numberColumnCuts_+factor-1)/factor;
+  // Total number of cuts active after (at end of n cut passes at each node)
+  numberCutsActive_ = (numberCutsActive_+factor-1)/factor;
+  // Number of cuts generated at root
+  numberCutsAtRoot_ = (numberCutsAtRoot_+factor-1)/factor;
+  // Number of cuts active at root
+  numberActiveCutsAtRoot_ = (numberActiveCutsAtRoot_+factor-1)/factor;
+  // Number of short cuts at root
+  numberShortCutsAtRoot_ = (numberShortCutsAtRoot_+factor-1)/factor;
+}
+// Create C++ lines to get to current state
+void
+CbcCutGenerator::generateTuning( FILE * fp)
+{
+    fprintf(fp, "// Cbc tuning for generator %s\n", generatorName_);
+    fprintf(fp, "   generator->setHowOften(%d);\n", whenCutGenerator_);
+    fprintf(fp, "   generator->setSwitchOffIfLessThan(%d);\n", switchOffIfLessThan_);
+    fprintf(fp, "   generator->setWhatDepth(%d);\n", depthCutGenerator_);
+    fprintf(fp, "   generator->setInaccuracy(%d);\n", inaccuracy_);
+    if (timing())
+        fprintf(fp, "   generator->setTiming(true);\n");
+    if (normal())
+        fprintf(fp, "   generator->setNormal(true);\n");
+    if (atSolution())
+        fprintf(fp, "   generator->setAtSolution(true);\n");
+    if (whenInfeasible())
+        fprintf(fp, "   generator->setWhenInfeasible(true);\n");
+    if (needsOptimalBasis())
+        fprintf(fp, "   generator->setNeedsOptimalBasis(true);\n");
+    if (mustCallAgain())
+        fprintf(fp, "   generator->setMustCallAgain(true);\n");
+    if (whetherToUse())
+        fprintf(fp, "   generator->setWhetherToUse(true);\n");
+}
+
+
+
diff --git a/cbits/coin/CbcCutGenerator.hpp b/cbits/coin/CbcCutGenerator.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCutGenerator.hpp
@@ -0,0 +1,469 @@
+/* $Id: CbcCutGenerator.hpp 1883 2013-04-06 13:33:15Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcCutGenerator_H
+#define CbcCutGenerator_H
+
+#include "OsiSolverInterface.hpp"
+#include "OsiCuts.hpp"
+#include "CglCutGenerator.hpp"
+#include "CbcCutModifier.hpp"
+
+class CbcModel;
+class OsiRowCut;
+class OsiRowCutDebugger;
+
+//#############################################################################
+
+/** Interface between Cbc and Cut Generation Library.
+
+  \c CbcCutGenerator is intended to provide an intelligent interface between
+  Cbc and the cutting plane algorithms in the CGL. A \c CbcCutGenerator is
+  bound to a \c CglCutGenerator and to an \c CbcModel. It contains parameters
+  which control when and how the \c generateCuts method of the
+  \c CglCutGenerator will be called.
+
+  The builtin decision criteria available to use when deciding whether to
+  generate cuts are limited: every <i>X</i> nodes, when a solution is found,
+  and when a subproblem is found to be infeasible. The idea is that the class
+  will grow more intelligent with time.
+
+  \todo Add a pointer to function member which will allow a client to install
+	their own decision algorithm to decide whether or not to call the CGL
+	\p generateCuts method. Create a default decision method that looks
+	at the builtin criteria.
+
+  \todo It strikes me as not good that generateCuts contains code specific to
+	individual CGL algorithms. Another set of pointer to function members,
+	so that the client can specify the cut generation method as well as
+	pre- and post-generation methods? Taken a bit further, should this
+	class contain a bunch of pointer to function members, one for each
+	of the places where the cut generator might be referenced?
+	Initialization, root node, search tree node, discovery of solution,
+	and termination all come to mind. Initialization and termination would
+	also be useful for instrumenting cbc.
+*/
+
+class CbcCutGenerator  {
+
+public:
+
+    /** \name Generate Cuts */
+    //@{
+    /** Generate cuts for the client model.
+
+      Evaluate the state of the client model and decide whether to generate cuts.
+      The generated cuts are inserted into and returned in the collection of cuts
+      \p cs.
+
+      If \p fullScan is !=0, the generator is obliged to call the CGL
+      \c generateCuts routine.  Otherwise, it is free to make a local decision.
+      Negative fullScan says things like at integer solution
+      The current implementation uses \c whenCutGenerator_ to decide.
+
+      The routine returns true if reoptimisation is needed (because the state of
+      the solver interface has been modified).
+
+      If node then can find out depth
+    */
+    bool generateCuts( OsiCuts &cs, int fullScan, OsiSolverInterface * solver,
+                       CbcNode * node);
+    //@}
+
+
+    /**@name Constructors and destructors */
+    //@{
+    /// Default constructor
+    CbcCutGenerator ();
+
+    /// Normal constructor
+    CbcCutGenerator(CbcModel * model, CglCutGenerator * generator,
+                    int howOften = 1, const char * name = NULL,
+                    bool normal = true, bool atSolution = false,
+                    bool infeasible = false, int howOftenInsub = -100,
+                    int whatDepth = -1, int whatDepthInSub = -1, int switchOffIfLessThan = 0);
+
+    /// Copy constructor
+    CbcCutGenerator (const CbcCutGenerator &);
+
+    /// Assignment operator
+    CbcCutGenerator & operator=(const CbcCutGenerator& rhs);
+
+    /// Destructor
+    ~CbcCutGenerator ();
+    //@}
+
+    /**@name Gets and sets */
+    //@{
+    /** Set the client model.
+
+      In addition to setting the client model, refreshModel also calls
+      the \c refreshSolver method of the CglCutGenerator object.
+    */
+    void refreshModel(CbcModel * model);
+
+    /// return name of generator
+    inline const char * cutGeneratorName() const {
+        return generatorName_;
+    }
+
+    /// Create C++ lines to show how to tune
+    void generateTuning( FILE * fp);
+    /** Set the cut generation interval
+
+      Set the number of nodes evaluated between calls to the Cgl object's
+      \p generateCuts routine.
+
+      If \p value is positive, cuts will always be generated at the specified
+      interval.
+      If \p value is negative, cuts will initially be generated at the specified
+      interval, but Cbc may adjust the value depending on the success of cuts
+      produced by this generator.
+
+      A value of -100 disables the generator, while a value of -99 means
+      just at root.
+    */
+    void setHowOften(int value) ;
+
+    /// Get the cut generation interval.
+    inline int howOften() const {
+        return whenCutGenerator_;
+    }
+    /// Get the cut generation interval.in sub tree
+    inline int howOftenInSub() const {
+        return whenCutGeneratorInSub_;
+    }
+    /// Get level of cut inaccuracy (0 means exact e.g. cliques)
+    inline int inaccuracy() const {
+        return inaccuracy_;
+    }
+    /// Set level of cut inaccuracy (0 means exact e.g. cliques)
+    inline void setInaccuracy(int level) {
+        inaccuracy_ = level;
+    }
+
+    /** Set the cut generation depth
+
+      Set the depth criterion for calls to the Cgl object's
+      \p generateCuts routine.  Only active if > 0.
+
+      If whenCutGenerator is positive and this is positive then this overrides.
+      If whenCutGenerator is -1 then this is used as criterion if any cuts
+      were generated at root node.
+      If whenCutGenerator is anything else this is ignored.
+    */
+    void setWhatDepth(int value) ;
+    /// Set the cut generation depth in sub tree
+    void setWhatDepthInSub(int value) ;
+    /// Get the cut generation depth criterion.
+    inline int whatDepth() const {
+        return depthCutGenerator_;
+    }
+    /// Get the cut generation depth criterion.in sub tree
+    inline int whatDepthInSub() const {
+        return depthCutGeneratorInSub_;
+    }
+    /// Set maximum number of times to enter
+    inline void setMaximumTries(int value)
+    { maximumTries_ = value;}
+    /// Get maximum number of times to enter
+    inline int maximumTries() const
+    { return maximumTries_;}
+
+    /// Get switches (for debug)
+    inline int switches() const {
+        return switches_;
+    }
+    /// Get whether the cut generator should be called in the normal place
+    inline bool normal() const {
+        return (switches_&1) != 0;
+    }
+    /// Set whether the cut generator should be called in the normal place
+    inline void setNormal(bool value) {
+        switches_ &= ~1;
+        switches_ |= value ? 1 : 0;
+    }
+    /// Get whether the cut generator should be called when a solution is found
+    inline bool atSolution() const {
+        return (switches_&2) != 0;
+    }
+    /// Set whether the cut generator should be called when a solution is found
+    inline void setAtSolution(bool value) {
+        switches_ &= ~2;
+        switches_ |= value ? 2 : 0;
+    }
+    /** Get whether the cut generator should be called when the subproblem is
+        found to be infeasible.
+    */
+    inline bool whenInfeasible() const {
+        return (switches_&4) != 0;
+    }
+    /** Set whether the cut generator should be called when the subproblem is
+        found to be infeasible.
+    */
+    inline void setWhenInfeasible(bool value) {
+        switches_ &= ~4;
+        switches_ |= value ? 4 : 0;
+    }
+    /// Get whether the cut generator is being timed
+    inline bool timing() const {
+        return (switches_&64) != 0;
+    }
+    /// Set whether the cut generator is being timed
+    inline void setTiming(bool value) {
+        switches_ &= ~64;
+        switches_ |= value ? 64 : 0;
+        timeInCutGenerator_ = 0.0;
+    }
+    /// Return time taken in cut generator
+    inline double timeInCutGenerator() const {
+        return timeInCutGenerator_;
+    }
+    inline void incrementTimeInCutGenerator(double value) {
+        timeInCutGenerator_ += value;
+    }
+    /// Get the \c CglCutGenerator corresponding to this \c CbcCutGenerator.
+    inline CglCutGenerator * generator() const {
+        return generator_;
+    }
+    /// Number times cut generator entered
+    inline int numberTimesEntered() const {
+        return numberTimes_;
+    }
+    inline void setNumberTimesEntered(int value) {
+        numberTimes_ = value;
+    }
+    inline void incrementNumberTimesEntered(int value = 1) {
+        numberTimes_ += value;
+    }
+    /// Total number of cuts added
+    inline int numberCutsInTotal() const {
+        return numberCuts_;
+    }
+    inline void setNumberCutsInTotal(int value) {
+        numberCuts_ = value;
+    }
+    inline void incrementNumberCutsInTotal(int value = 1) {
+        numberCuts_ += value;
+    }
+    /// Total number of elements added
+    inline int numberElementsInTotal() const {
+        return numberElements_;
+    }
+    inline void setNumberElementsInTotal(int value) {
+        numberElements_ = value;
+    }
+    inline void incrementNumberElementsInTotal(int value = 1) {
+        numberElements_ += value;
+    }
+    /// Total number of column cuts
+    inline int numberColumnCuts() const {
+        return numberColumnCuts_;
+    }
+    inline void setNumberColumnCuts(int value) {
+        numberColumnCuts_ = value;
+    }
+    inline void incrementNumberColumnCuts(int value = 1) {
+        numberColumnCuts_ += value;
+    }
+    /// Total number of cuts active after (at end of n cut passes at each node)
+    inline int numberCutsActive() const {
+        return numberCutsActive_;
+    }
+    inline void setNumberCutsActive(int value) {
+        numberCutsActive_ = value;
+    }
+    inline void incrementNumberCutsActive(int value = 1) {
+        numberCutsActive_ += value;
+    }
+    inline void setSwitchOffIfLessThan(int value) {
+        switchOffIfLessThan_ = value;
+    }
+    inline int switchOffIfLessThan() const {
+        return switchOffIfLessThan_;
+    }
+    /// Say if optimal basis needed
+    inline bool needsOptimalBasis() const {
+        return (switches_&128) != 0;
+    }
+    /// Set if optimal basis needed
+    inline void setNeedsOptimalBasis(bool yesNo) {
+        switches_ &= ~128;
+        switches_ |= yesNo ? 128 : 0;
+    }
+    /// Whether generator MUST be called again if any cuts (i.e. ignore break from loop)
+    inline bool mustCallAgain() const {
+        return (switches_&8) != 0;
+    }
+    /// Set whether generator MUST be called again if any cuts (i.e. ignore break from loop)
+    inline void setMustCallAgain(bool yesNo) {
+        switches_ &= ~8;
+        switches_ |= yesNo ? 8 : 0;
+    }
+    /// Whether generator switched off for moment
+    inline bool switchedOff() const {
+        return (switches_&16) != 0;
+    }
+    /// Set whether generator switched off for moment
+    inline void setSwitchedOff(bool yesNo) {
+        switches_ &= ~16;
+        switches_ |= yesNo ? 16 : 0;
+    }
+    /// Whether last round of cuts did little
+    inline bool ineffectualCuts() const {
+        return (switches_&512) != 0;
+    }
+    /// Set whether last round of cuts did little
+    inline void setIneffectualCuts(bool yesNo) {
+        switches_ &= ~512;
+        switches_ |= yesNo ? 512 : 0;
+    }
+    /// Whether to use if any cuts generated
+    inline bool whetherToUse() const {
+        return (switches_&1024) != 0;
+    }
+    /// Set whether to use if any cuts generated
+    inline void setWhetherToUse(bool yesNo) {
+        switches_ &= ~1024;
+        switches_ |= yesNo ? 1024 : 0;
+    }
+    /// Whether in must call again mode (or after others)
+    inline bool whetherInMustCallAgainMode() const {
+        return (switches_&2048) != 0;
+    }
+    /// Set whether in must call again mode (or after others)
+    inline void setWhetherInMustCallAgainMode(bool yesNo) {
+        switches_ &= ~2048;
+        switches_ |= yesNo ? 2048 : 0;
+    }
+    /// Whether to call at end
+    inline bool whetherCallAtEnd() const {
+        return (switches_&4096) != 0;
+    }
+    /// Set whether to call at end
+    inline void setWhetherCallAtEnd(bool yesNo) {
+        switches_ &= ~4096;
+        switches_ |= yesNo ? 4096 : 0;
+    }
+    /// Number of cuts generated at root
+    inline int numberCutsAtRoot() const {
+        return numberCutsAtRoot_;
+    }
+    inline void setNumberCutsAtRoot(int value) {
+        numberCutsAtRoot_ = value;
+    }
+    /// Number of cuts active at root
+    inline int numberActiveCutsAtRoot() const {
+        return numberActiveCutsAtRoot_;
+    }
+    inline void setNumberActiveCutsAtRoot(int value) {
+        numberActiveCutsAtRoot_ = value;
+    }
+    /// Number of short cuts at root
+    inline int numberShortCutsAtRoot() const {
+        return numberShortCutsAtRoot_;
+    }
+    inline void setNumberShortCutsAtRoot(int value) {
+        numberShortCutsAtRoot_ = value;
+    }
+    /// Set model
+    inline void setModel(CbcModel * model) {
+        model_ = model;
+    }
+    /// Whether global cuts at root
+    inline bool globalCutsAtRoot() const {
+        return (switches_&32) != 0;
+    }
+    /// Set whether global cuts at root
+    inline void setGlobalCutsAtRoot(bool yesNo) {
+        switches_ &= ~32;
+        switches_ |= yesNo ? 32 : 0;
+    }
+    /// Whether global cuts
+    inline bool globalCuts() const {
+        return (switches_&256) != 0;
+    }
+    /// Set whether global cuts
+    inline void setGlobalCuts(bool yesNo) {
+        switches_ &= ~256;
+        switches_ |= yesNo ? 256 : 0;
+    }
+    /// Add in statistics from other
+    void addStatistics(const CbcCutGenerator * other);
+    /// Scale back statistics by factor
+    void scaleBackStatistics(int factor);
+    //@}
+
+private:
+    /**@name Private gets and sets */
+    //@{
+    //@}
+    /// Saved cuts
+    OsiCuts savedCuts_;
+    /// Time in cut generator
+    double timeInCutGenerator_;
+    /// The client model
+    CbcModel *model_;
+
+    // The CglCutGenerator object
+    CglCutGenerator * generator_;
+
+    /// Name of generator
+    char * generatorName_;
+
+    /** Number of nodes between calls to the CglCutGenerator::generateCuts
+       routine.
+    */
+    int whenCutGenerator_;
+    /** Number of nodes between calls to the CglCutGenerator::generateCuts
+       routine in sub tree.
+    */
+    int whenCutGeneratorInSub_;
+    /** If first pass at root produces fewer than this cuts then switch off
+     */
+    int switchOffIfLessThan_;
+
+    /** Depth at which to call the CglCutGenerator::generateCuts
+       routine (If >0 then overrides when and is called if depth%depthCutGenerator==0).
+    */
+    int depthCutGenerator_;
+
+    /** Depth at which to call the CglCutGenerator::generateCuts
+       routine (If >0 then overrides when and is called if depth%depthCutGenerator==0).
+       In sub tree.
+    */
+    int depthCutGeneratorInSub_;
+
+    /// Level of cut inaccuracy (0 means exact e.g. cliques)
+    int inaccuracy_;
+    /// Number times cut generator entered
+    int numberTimes_;
+    /// Total number of cuts added
+    int numberCuts_;
+    /// Total number of elements added
+    int numberElements_;
+    /// Total number of column cuts added
+    int numberColumnCuts_;
+    /// Total number of cuts active after (at end of n cut passes at each node)
+    int numberCutsActive_;
+    /// Number of cuts generated at root
+    int numberCutsAtRoot_;
+    /// Number of cuts active at root
+    int numberActiveCutsAtRoot_;
+    /// Number of short cuts at root
+    int numberShortCutsAtRoot_;
+    /// Switches - see gets and sets
+    int switches_;
+    /// Maximum number of times to enter
+    int maximumTries_;
+};
+
+// How often to do if mostly switched off (A)
+# define SCANCUTS 1000
+// How often to do if mostly switched off (probing B)
+# define SCANCUTS_PROBING 1000
+
+#endif
+
diff --git a/cbits/coin/CbcCutModifier.cpp b/cbits/coin/CbcCutModifier.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCutModifier.cpp
@@ -0,0 +1,55 @@
+// $Id: CbcCutModifier.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCutGenerator
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include "CbcConfig.h"
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#else
+#include "OsiSolverInterface.hpp"
+#endif
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcCutGenerator.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "CglProbing.hpp"
+#include "CoinTime.hpp"
+#include "CbcCutModifier.hpp"
+
+// Default Constructor
+CbcCutModifier::CbcCutModifier()
+{
+}
+
+
+// Destructor
+CbcCutModifier::~CbcCutModifier ()
+{
+}
+
+// Copy constructor
+CbcCutModifier::CbcCutModifier ( const CbcCutModifier & /*rhs*/)
+{
+}
+
+// Assignment operator
+CbcCutModifier &
+CbcCutModifier::operator=( const CbcCutModifier & rhs)
+{
+    if (this != &rhs) {
+    }
+    return *this;
+}
+
diff --git a/cbits/coin/CbcCutModifier.hpp b/cbits/coin/CbcCutModifier.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCutModifier.hpp
@@ -0,0 +1,57 @@
+// $Id: CbcCutModifier.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCutGenerator
+
+#ifndef CbcCutModifier_H
+#define CbcCutModifier_H
+
+#include "OsiSolverInterface.hpp"
+#include "OsiCuts.hpp"
+#include "CglCutGenerator.hpp"
+
+class CbcModel;
+class OsiRowCut;
+class OsiRowCutDebugger;
+/** Abstract cut modifier base class
+
+    In exotic circumstances - cuts may need to be modified
+    a) strengthened - changed
+    b) weakened - changed
+    c) deleted - set to NULL
+    d) unchanged
+*/
+
+class CbcCutModifier {
+public:
+    /// Default Constructor
+    CbcCutModifier ();
+
+    // Copy constructor
+    CbcCutModifier ( const CbcCutModifier &);
+
+    /// Destructor
+    virtual ~CbcCutModifier();
+
+    /// Assignment
+    CbcCutModifier & operator=(const CbcCutModifier& rhs);
+/// Clone
+    virtual CbcCutModifier * clone() const = 0;
+
+    /** Returns
+        0 unchanged
+        1 strengthened
+        2 weakened
+        3 deleted
+    */
+    virtual int modify(const OsiSolverInterface * solver, OsiRowCut & cut) = 0;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+protected:
+
+};
+
+#endif //CbcCutModifier_H
+
diff --git a/cbits/coin/CbcCutSubsetModifier.cpp b/cbits/coin/CbcCutSubsetModifier.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCutSubsetModifier.cpp
@@ -0,0 +1,109 @@
+// $Id: CbcCutSubsetModifier.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCutGenerator
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include "CbcConfig.h"
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#else
+#include "OsiSolverInterface.hpp"
+#endif
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcCutGenerator.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "CglProbing.hpp"
+#include "CoinTime.hpp"
+#include "CbcCutSubsetModifier.hpp"
+
+// Default Constructor
+CbcCutSubsetModifier::CbcCutSubsetModifier ()
+        : CbcCutModifier(),
+        firstOdd_(COIN_INT_MAX)
+{
+}
+
+// Useful constructor
+CbcCutSubsetModifier::CbcCutSubsetModifier (int firstOdd)
+        : CbcCutModifier()
+{
+    firstOdd_ = firstOdd;
+}
+
+// Copy constructor
+CbcCutSubsetModifier::CbcCutSubsetModifier ( const CbcCutSubsetModifier & rhs)
+        : CbcCutModifier(rhs)
+{
+    firstOdd_ = rhs.firstOdd_;
+}
+
+// Clone
+CbcCutModifier *
+CbcCutSubsetModifier::clone() const
+{
+    return new CbcCutSubsetModifier(*this);
+}
+
+// Assignment operator
+CbcCutSubsetModifier &
+CbcCutSubsetModifier::operator=( const CbcCutSubsetModifier & rhs)
+{
+    if (this != &rhs) {
+        CbcCutModifier::operator=(rhs);
+        firstOdd_ = rhs.firstOdd_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcCutSubsetModifier::~CbcCutSubsetModifier ()
+{
+}
+/* Returns
+   0 unchanged
+   1 strengthened
+   2 weakened
+   3 deleted
+*/
+int
+CbcCutSubsetModifier::modify(const OsiSolverInterface * /*solver*/,
+                             OsiRowCut & cut)
+{
+    int n = cut.row().getNumElements();
+    if (!n)
+        return 0;
+    const int * column = cut.row().getIndices();
+    //const double * element = cut.row().getElements();
+    int returnCode = 0;
+    for (int i = 0; i < n; i++) {
+        if (column[i] >= firstOdd_) {
+            returnCode = 3;
+            break;
+        }
+    }
+#ifdef COIN_DETAIL
+    if (!returnCode) {
+        const double * element = cut.row().getElements();
+        printf("%g <= ", cut.lb());
+        for (int i = 0; i < n; i++) {
+            printf("%g*x%d ", element[i], column[i]);
+        }
+        printf("<= %g\n", cut.ub());
+    }
+#endif
+    //return 3;
+    return returnCode;
+}
+
diff --git a/cbits/coin/CbcCutSubsetModifier.hpp b/cbits/coin/CbcCutSubsetModifier.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcCutSubsetModifier.hpp
@@ -0,0 +1,66 @@
+// $Id: CbcCutSubsetModifier.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//Edwin 11/25/09 carved out of CbcCutGenerator
+
+#ifndef CbcCutSubsetModifier_H
+#define CbcCutSubsetModifier_H
+
+#include "OsiSolverInterface.hpp"
+#include "OsiCuts.hpp"
+#include "CglCutGenerator.hpp"
+#include "CbcCutModifier.hpp"
+
+class CbcModel;
+class OsiRowCut;
+class OsiRowCutDebugger;
+/** Simple cut modifier base class
+
+    In exotic circumstances - cuts may need to be modified
+    a) strengthened - changed
+    b) weakened - changed
+    c) deleted - set to NULL
+    d) unchanged
+
+    initially get rid of cuts with variables >= k
+    could weaken
+*/
+
+class CbcCutSubsetModifier  : public CbcCutModifier {
+public:
+    /// Default Constructor
+    CbcCutSubsetModifier ();
+
+    /// Useful Constructor
+    CbcCutSubsetModifier (int firstOdd);
+
+    // Copy constructor
+    CbcCutSubsetModifier ( const CbcCutSubsetModifier &);
+
+    /// Destructor
+    virtual ~CbcCutSubsetModifier();
+
+    /// Assignment
+    CbcCutSubsetModifier & operator=(const CbcCutSubsetModifier& rhs);
+/// Clone
+    virtual CbcCutModifier * clone() const ;
+
+    /** Returns
+        0 unchanged
+        1 strengthened
+        2 weakened
+        3 deleted
+    */
+    virtual int modify(const OsiSolverInterface * solver, OsiRowCut & cut) ;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+protected:
+    /// data
+    /// First odd variable
+    int firstOdd_;
+};
+
+#endif //CbcCutSubsetModifier_H
+
diff --git a/cbits/coin/CbcDummyBranchingObject.cpp b/cbits/coin/CbcDummyBranchingObject.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcDummyBranchingObject.cpp
@@ -0,0 +1,107 @@
+// $Id: CbcDummyBranchingObject.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcDummyBranchingObject.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+//##############################################################################
+
+// Default Constructor
+CbcDummyBranchingObject::CbcDummyBranchingObject(CbcModel * model)
+        : CbcBranchingObject(model, 0, 0, 0.5)
+{
+    setNumberBranchesLeft(1);
+}
+
+
+// Copy constructor
+CbcDummyBranchingObject::CbcDummyBranchingObject ( const CbcDummyBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+}
+
+// Assignment operator
+CbcDummyBranchingObject &
+CbcDummyBranchingObject::operator=( const CbcDummyBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcDummyBranchingObject::clone() const
+{
+    return (new CbcDummyBranchingObject(*this));
+}
+
+
+// Destructor
+CbcDummyBranchingObject::~CbcDummyBranchingObject ()
+{
+}
+
+/*
+  Perform a dummy branch
+*/
+double
+CbcDummyBranchingObject::branch()
+{
+    decrementNumberBranchesLeft();
+    return 0.0;
+}
+// Print what would happen
+void
+CbcDummyBranchingObject::print()
+{
+    printf("Dummy branch\n");
+}
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcDummyBranchingObject::compareOriginalObject
+(const CbcBranchingObject* /*brObj*/) const
+{
+    throw("must implement");
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcDummyBranchingObject::compareBranchingObject
+(const CbcBranchingObject* /*brObj*/, const bool /*replaceIfOverlap*/)
+{
+    throw("must implement");
+}
+
diff --git a/cbits/coin/CbcDummyBranchingObject.hpp b/cbits/coin/CbcDummyBranchingObject.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcDummyBranchingObject.hpp
@@ -0,0 +1,83 @@
+// $Id: CbcDummyBranchingObject.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#ifndef CbcDummyBranchingObject_H
+#define CbcDummyBranchingObject_H
+
+#include "CbcBranchBase.hpp"
+/** Dummy branching object
+
+  This object specifies a one-way dummy branch.
+  This is so one can carry on branching even when it looks feasible
+*/
+
+class CbcDummyBranchingObject : public CbcBranchingObject {
+
+public:
+
+    /// Default constructor
+    CbcDummyBranchingObject (CbcModel * model = NULL);
+
+    /// Copy constructor
+    CbcDummyBranchingObject ( const CbcDummyBranchingObject &);
+
+    /// Assignment operator
+    CbcDummyBranchingObject & operator= (const CbcDummyBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    /// Destructor
+    virtual ~CbcDummyBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /** \brief Dummy branch
+    */
+    virtual double branch();
+
+#ifdef JJF_ZERO
+    // No need to override. Default works fine.
+    /** Reset every information so that the branching object appears to point to
+        the previous child. This method does not need to modify anything in any
+        solver. */
+    virtual void previousBranch();
+#endif
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return DummyBranchObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcEventHandler.cpp b/cbits/coin/CbcEventHandler.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcEventHandler.cpp
@@ -0,0 +1,103 @@
+/* $Id: CbcEventHandler.cpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Shamelessly adapted from ClpEventHandler.
+
+#include "CoinPragma.hpp"
+
+#include "CbcEventHandler.hpp"
+
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+
+CbcEventHandler::CbcEventHandler (CbcModel *model)
+        : model_(model),
+        dfltAction_(CbcEventHandler::noAction),
+        eaMap_(0)
+{  /* nothing more required */ }
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+/*
+  Here we need to clone the event/action map, if it exists
+*/
+CbcEventHandler::CbcEventHandler (const CbcEventHandler & rhs)
+        : model_(rhs.model_),
+        dfltAction_(rhs.dfltAction_),
+        eaMap_(0)
+{
+    if (rhs.eaMap_ != 0) {
+        eaMap_ = new eaMapPair(*rhs.eaMap_) ;
+    }
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+CbcEventHandler&
+CbcEventHandler::operator=(const CbcEventHandler & rhs)
+{
+    if (this != &rhs) {
+        model_ = rhs.model_ ;
+        dfltAction_ = rhs.dfltAction_ ;
+        if (rhs.eaMap_ != 0) {
+            eaMap_ = new eaMapPair(*rhs.eaMap_) ;
+        } else {
+            eaMap_ = 0 ;
+        }
+    }
+    return (*this) ;
+}
+
+//----------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CbcEventHandler*
+CbcEventHandler::clone() const
+{
+    return (new CbcEventHandler(*this)) ;
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+/*
+  Take care to free the event/action map.
+*/
+CbcEventHandler::~CbcEventHandler ()
+{
+    if (eaMap_ != 0) delete eaMap_ ;
+}
+
+
+//-------------------------------------------------------------------
+// event() -- return the action for an event.
+//-------------------------------------------------------------------
+
+CbcEventHandler::CbcAction CbcEventHandler::event(CbcEvent event)
+/*
+  If an event/action map exists and contains an entry for the event, return it.
+  Otherwise return the default action.
+*/
+{
+    if (eaMap_ != 0) {
+        eaMapPair::iterator entry = eaMap_->find(event) ;
+        if (entry != eaMap_->end()) {
+            return (entry->second) ;
+        } else {
+            return (dfltAction_) ;
+        }
+    } else {
+        return (dfltAction_) ;
+    }
+}
+
diff --git a/cbits/coin/CbcEventHandler.hpp b/cbits/coin/CbcEventHandler.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcEventHandler.hpp
@@ -0,0 +1,228 @@
+/*
+  Copyright (C) 2006, International Business Machines Corporation and others.
+  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+
+  $Id: CbcEventHandler.hpp 1632 2011-03-29 14:40:46Z forrest $
+*/
+
+#ifndef CbcEventHandler_H
+#define CbcEventHandler_H
+
+/*! \file CbcEventHandler.hpp
+    \brief Event handling for cbc
+
+  This file contains the declaration of CbcEventHandler, used for event
+  handling in cbc.
+
+  The central method is CbcEventHandler::event(). The default semantics of
+  this call are `ask for the action to take in reponse to this event'. The
+  call is made at the point in the code where the event occurs (<i>e.g.</i>,
+  when a solution is found, or when a node is added to or removed from the
+  search tree). The return value specifies the action to perform in response
+  to the event (<i>e.g.</i>, continue, or stop).
+
+  This is a lazy class. Initially, it knows nothing about specific events,
+  and returns dfltAction_ for any event. This makes for a trivial constructor
+  and fast startup. The only place where the list of known events or actions
+  is hardwired is in the enum definitions for CbcEvent and CbcAction,
+  respectively.
+
+  At the first call to setAction, a map is created to hold (Event,Action)
+  pairs, and this map will be consulted ever after. Events not in the map
+  will still return the default value.
+
+  For serious extensions, derive a subclass and replace event() with a
+  function that suits you better.  The function has access to the CbcModel
+  via a pointer held in the CbcEventHandler object, and can do as much
+  thinking as it likes before returning an answer.  You can also print as
+  much information as you want. The model is held as a const, however, so
+  you can't alter reality.
+
+  The design of the class deliberately matches ClpEventHandler, so that other
+  solvers can participate in cbc without breaking the patterns set by
+  clp-specific code.
+
+*/
+
+#include <map>
+
+/* May well already be declared, but can't hurt. */
+
+class CbcModel ;
+
+/*
+  cvs/svn: $Id: CbcEventHandler.hpp 1632 2011-03-29 14:40:46Z forrest $
+*/
+
+/*! \class CbcEventHandler
+    \brief Base class for Cbc event handling.
+
+  Up front: We're not talking about unanticipated events here. We're talking
+  about anticipated events, in the sense that the code is going to make a call
+  to event() and is prepared to obey the return value that it receives.
+
+  The general pattern for usage is as follows:
+  <ol>
+    <li> Create a CbcEventHandler object. This will be initialised with a set
+	 of default actions for every recognised event.
+
+    <li> Attach the event handler to the CbcModel object.
+
+    <li> When execution reaches the point where an event occurs, call the
+	 event handler as CbcEventHandler::event(the event). The return value
+	 will specify what the code should do in response to the event.
+  </ol>
+
+  The return value associated with an event can be changed at any time.
+*/
+
+class CbcEventHandler {
+
+public:
+
+    /*! \brief Events known to cbc */
+
+    enum CbcEvent { /*! Processing of the current node is complete. */
+        node = 200,
+        /*! A tree status interval has arrived. */
+        treeStatus,
+        /*! A solution has been found. */
+        solution,
+        /*! A heuristic solution has been found. */
+        heuristicSolution,
+        /*! A solution will be found unless user takes action (first check). */
+        beforeSolution1,
+        /*! A solution will be found unless user takes action (thorough check). */
+        beforeSolution2,
+        /*! After failed heuristic. */
+        afterHeuristic,
+        /*! End of search. */
+        endSearch
+    } ;
+
+    /*! \brief Action codes returned by the event handler.
+
+        Specific values are chosen to match ClpEventHandler return codes.
+    */
+
+    enum CbcAction { /*! Continue --- no action required. */
+        noAction = -1,
+        /*! Stop --- abort the current run at the next opportunity. */
+        stop = 0,
+        /*! Restart --- restart branch-and-cut search; do not undo root node
+        processing.
+        */
+        restart,
+        /*! RestartRoot --- undo root node and start branch-and-cut afresh. */
+        restartRoot,
+        /*! Add special cuts. */
+        addCuts,
+        /*! Pretend solution never happened. */
+        killSolution
+
+    } ;
+
+    /*! \brief Data type for event/action pairs */
+
+    typedef std::map<CbcEvent, CbcAction> eaMapPair ;
+
+
+    /*! \name Event Processing */
+    //@{
+
+    /*! \brief Return the action to be taken for an event.
+
+      Return the action that should be taken in response to the event passed as
+      the parameter. The default implementation simply reads a return code
+      from a map.
+    */
+    virtual CbcAction event(CbcEvent whichEvent) ;
+
+    //@}
+
+
+    /*! \name Constructors and destructors */
+    //@{
+
+    /*! \brief Default constructor. */
+
+    CbcEventHandler(CbcModel *model = 0 /* was NULL but 4.6 complains */) ;
+
+    /*! \brief Copy constructor. */
+
+    CbcEventHandler(const CbcEventHandler &orig) ;
+
+    /*! \brief Assignment. */
+
+    CbcEventHandler& operator=(const CbcEventHandler &rhs) ;
+
+    /*! \brief Clone (virtual) constructor. */
+
+    virtual CbcEventHandler* clone() const ;
+
+    /*! \brief Destructor. */
+
+    virtual ~CbcEventHandler() ;
+
+    //@}
+
+    /*! \name Set/Get methods */
+    //@{
+
+    /*! \brief Set model. */
+
+    inline void setModel(CbcModel *model) {
+        model_ = model ;
+    }
+
+    /*! \brief Get model. */
+
+    inline const CbcModel* getModel() const {
+        return model_ ;
+    }
+
+    /*! \brief Set the default action */
+
+    inline void setDfltAction(CbcAction action) {
+        dfltAction_ = action ;
+    }
+
+    /*! \brief Set the action code associated with an event */
+
+    inline void setAction(CbcEvent event, CbcAction action) {
+        if (eaMap_ == 0) {
+            eaMap_ = new eaMapPair ;
+        }
+        (*eaMap_)[event] = action ;
+    }
+
+    //@}
+
+
+protected:
+
+    /*! \name Data members
+
+       Protected (as opposed to private) to allow access by derived classes.
+    */
+    //@{
+
+    /*! \brief Pointer to associated CbcModel */
+
+    CbcModel *model_ ;
+
+    /*! \brief Default action */
+
+    CbcAction dfltAction_ ;
+
+    /*! \brief Pointer to a map that holds non-default event/action pairs */
+
+    eaMapPair *eaMap_ ;
+
+    //@}
+} ;
+
+#endif
+
diff --git a/cbits/coin/CbcFathom.cpp b/cbits/coin/CbcFathom.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFathom.cpp
@@ -0,0 +1,109 @@
+/* $Id: CbcFathom.cpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcFathom.hpp"
+
+// Default Constructor
+CbcFathom::CbcFathom()
+        : model_(NULL),
+        possible_(false)
+{
+}
+
+// Constructor from model
+CbcFathom::CbcFathom(CbcModel & model)
+        :
+        model_(&model),
+        possible_(false)
+{
+}
+// Resets stuff if model changes
+void
+CbcFathom::resetModel(CbcModel * model)
+{
+    model_ = model;
+}
+
+// Destructor
+CbcFathom::~CbcFathom ()
+{
+}
+
+// update model
+void CbcFathom::setModel(CbcModel * model)
+{
+    model_ = model;
+}
+#ifdef COIN_HAS_CLP
+
+//#############################################################################
+// Constructors, destructors clone and assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+CbcOsiSolver::CbcOsiSolver ()
+        : OsiClpSolverInterface()
+{
+    cbcModel_ = NULL;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+OsiSolverInterface *
+CbcOsiSolver::clone(bool /*copyData*/) const
+{
+    //assert (copyData);
+    return new CbcOsiSolver(*this);
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+CbcOsiSolver::CbcOsiSolver (
+    const CbcOsiSolver & rhs)
+        : OsiSolverInterface(), // Should not be needed but get warning
+        OsiClpSolverInterface(rhs)
+{
+    cbcModel_ = rhs.cbcModel_;
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+CbcOsiSolver::~CbcOsiSolver ()
+{
+}
+
+//-------------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+CbcOsiSolver &
+CbcOsiSolver::operator=(const CbcOsiSolver & rhs)
+{
+    if (this != &rhs) {
+        OsiClpSolverInterface::operator=(rhs);
+        cbcModel_ = rhs.cbcModel_;
+    }
+    return *this;
+}
+#endif
+
diff --git a/cbits/coin/CbcFathom.hpp b/cbits/coin/CbcFathom.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFathom.hpp
@@ -0,0 +1,137 @@
+/* $Id: CbcFathom.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcFathom_H
+#define CbcFathom_H
+#include "CbcConfig.h"
+
+/*
+  This file contains two classes, CbcFathom and CbcOsiSolver. It's unclear why
+  they're in the same file. CbcOsiSolver is a base class for CbcLinked.
+
+  --lh, 071031 --
+*/
+
+
+class CbcModel;
+
+//#############################################################################
+/** Fathom base class.
+
+    The idea is that after some branching the problem will be effectively smaller than
+    the original problem and maybe there will be a more specialized technique which can completely
+    fathom this branch quickly.
+
+    One method is to presolve the problem to give a much smaller new problem and then do branch
+    and cut on that.  Another might be dynamic programming.
+
+ */
+
+class CbcFathom {
+public:
+    // Default Constructor
+    CbcFathom ();
+
+    // Constructor with model - assumed before cuts
+    CbcFathom (CbcModel & model);
+
+    virtual ~CbcFathom();
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    /// Clone
+    virtual CbcFathom * clone() const = 0;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model) = 0;
+
+    /** returns 0 if no fathoming attempted, 1 fully fathomed,
+        2 incomplete search, 3 incomplete search but treat as complete.
+        If solution then newSolution will not be NULL and
+        will be freed by CbcModel.  It is expected that the solution is better
+        than best so far but CbcModel will double check.
+
+        If returns 3 then of course there is no guarantee of global optimum
+    */
+    virtual int fathom(double *& newSolution) = 0;
+
+    // Is this method possible
+    inline bool possible() const {
+        return possible_;
+    }
+
+protected:
+
+    /// Model
+    CbcModel * model_;
+    /// Possible - if this method of fathoming can be used
+    bool possible_;
+private:
+
+    /// Illegal Assignment operator
+    CbcFathom & operator=(const CbcFathom& rhs);
+
+};
+
+#include "OsiClpSolverInterface.hpp"
+
+//#############################################################################
+
+/**
+
+This is for codes where solver needs to know about CbcModel
+  Seems to provide only one value-added feature, a CbcModel object.
+
+*/
+
+class CbcOsiSolver : public OsiClpSolverInterface {
+
+public:
+
+    /**@name Constructors and destructors */
+    //@{
+    /// Default Constructor
+    CbcOsiSolver ();
+
+    /// Clone
+    virtual OsiSolverInterface * clone(bool copyData = true) const;
+
+    /// Copy constructor
+    CbcOsiSolver (const CbcOsiSolver &);
+
+    /// Assignment operator
+    CbcOsiSolver & operator=(const CbcOsiSolver& rhs);
+
+    /// Destructor
+    virtual ~CbcOsiSolver ();
+
+    //@}
+
+
+    /**@name Sets and Gets */
+    //@{
+    /// Set Cbc Model
+    inline void setCbcModel(CbcModel * model) {
+        cbcModel_ = model;
+    }
+    /// Return Cbc Model
+    inline CbcModel * cbcModel() const {
+        return cbcModel_;
+    }
+    //@}
+
+    //---------------------------------------------------------------------------
+
+protected:
+
+
+    /**@name Private member data */
+    //@{
+    /// Pointer back to CbcModel
+    CbcModel * cbcModel_;
+    //@}
+};
+#endif
diff --git a/cbits/coin/CbcFathomDynamicProgramming.cpp b/cbits/coin/CbcFathomDynamicProgramming.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFathomDynamicProgramming.cpp
@@ -0,0 +1,1055 @@
+/*
+  $Id: CbcFathomDynamicProgramming.cpp 1888 2013-04-06 20:52:59Z stefan $
+*/
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcFathomDynamicProgramming.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinSort.hpp"
+// Default Constructor
+CbcFathomDynamicProgramming::CbcFathomDynamicProgramming()
+        : CbcFathom(),
+        size_(0),
+        type_(-1),
+        cost_(NULL),
+        back_(NULL),
+        lookup_(NULL),
+        indices_(NULL),
+        numberActive_(0),
+        maximumSizeAllowed_(1000000),
+        startBit_(NULL),
+        numberBits_(NULL),
+        rhs_(NULL),
+        coefficients_(NULL),
+        target_(0),
+        numberNonOne_(0),
+        bitPattern_(0),
+        algorithm_(-1)
+{
+
+}
+
+// Constructor from model
+CbcFathomDynamicProgramming::CbcFathomDynamicProgramming(CbcModel & model)
+        : CbcFathom(model),
+        cost_(NULL),
+        back_(NULL),
+        lookup_(NULL),
+        indices_(NULL),
+        numberActive_(0),
+        maximumSizeAllowed_(1000000),
+        startBit_(NULL),
+        numberBits_(NULL),
+        rhs_(NULL),
+        coefficients_(NULL),
+        target_(0),
+        numberNonOne_(0),
+        bitPattern_(0),
+        algorithm_(-1)
+{
+    type_ = checkPossible();
+}
+
+// Destructor
+CbcFathomDynamicProgramming::~CbcFathomDynamicProgramming ()
+{
+    gutsOfDelete();
+}
+// Does deleteions
+void
+CbcFathomDynamicProgramming::gutsOfDelete()
+{
+    delete [] cost_;
+    delete [] back_;
+    delete [] lookup_;
+    delete [] indices_;
+    delete [] startBit_;
+    delete [] numberBits_;
+    delete [] rhs_;
+    delete [] coefficients_;
+    cost_ = NULL;
+    back_ = NULL;
+    lookup_ = NULL;
+    indices_ = NULL;
+    startBit_ = NULL;
+    numberBits_ = NULL;
+    rhs_ = NULL;
+    coefficients_ = NULL;
+}
+// Clone
+CbcFathom *
+CbcFathomDynamicProgramming::clone() const
+{
+    return new CbcFathomDynamicProgramming(*this);
+}
+
+// Copy constructor
+CbcFathomDynamicProgramming::CbcFathomDynamicProgramming(const CbcFathomDynamicProgramming & rhs)
+        :
+        CbcFathom(rhs),
+        size_(rhs.size_),
+        type_(rhs.type_),
+        cost_(NULL),
+        back_(NULL),
+        lookup_(NULL),
+        indices_(NULL),
+        numberActive_(rhs.numberActive_),
+        maximumSizeAllowed_(rhs.maximumSizeAllowed_),
+        startBit_(NULL),
+        numberBits_(NULL),
+        rhs_(NULL),
+        coefficients_(NULL),
+        target_(rhs.target_),
+        numberNonOne_(rhs.numberNonOne_),
+        bitPattern_(rhs.bitPattern_),
+        algorithm_(rhs.algorithm_)
+{
+    if (size_) {
+        cost_ = CoinCopyOfArray(rhs.cost_, size_);
+        back_ = CoinCopyOfArray(rhs.back_, size_);
+        int numberRows = model_->getNumRows();
+        lookup_ = CoinCopyOfArray(rhs.lookup_, numberRows);
+        startBit_ = CoinCopyOfArray(rhs.startBit_, numberActive_);
+        indices_ = CoinCopyOfArray(rhs.indices_, numberActive_);
+        numberBits_ = CoinCopyOfArray(rhs.numberBits_, numberActive_);
+        rhs_ = CoinCopyOfArray(rhs.rhs_, numberActive_);
+        coefficients_ = CoinCopyOfArray(rhs.coefficients_, numberActive_);
+    }
+}
+// Returns type
+int
+CbcFathomDynamicProgramming::checkPossible(int allowableSize)
+{
+    algorithm_ = -1;
+    assert(model_->solver());
+    OsiSolverInterface * solver = model_->solver();
+    const CoinPackedMatrix * matrix = solver->getMatrixByCol();
+
+    int numberIntegers = model_->numberIntegers();
+    int numberColumns = solver->getNumCols();
+    size_ = 0;
+    if (numberIntegers != numberColumns)
+        return -1; // can't do dynamic programming
+
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    const double * rowUpper = solver->getRowUpper();
+
+    int numberRows = model_->getNumRows();
+    int i;
+
+    // First check columns to see if possible
+    double * rhs = new double [numberRows];
+    CoinCopyN(rowUpper, numberRows, rhs);
+
+    // Column copy
+    const double * element = matrix->getElements();
+    const int * row = matrix->getIndices();
+    const CoinBigIndex * columnStart = matrix->getVectorStarts();
+    const int * columnLength = matrix->getVectorLengths();
+    bool bad = false;
+    /* It is just possible that we could say okay as
+       variables may get fixed but seems unlikely */
+    for (i = 0; i < numberColumns; i++) {
+        int j;
+        double lowerValue = lower[i];
+        assert (lowerValue == floor(lowerValue));
+        for (j = columnStart[i];
+                j < columnStart[i] + columnLength[i]; j++) {
+            int iRow = row[j];
+            double value = element[j];
+            if (upper[i] > lowerValue && (value <= 0.0 || value != floor(value)))
+                bad = true;
+            if (lowerValue)
+                rhs[iRow] -= lowerValue * value;
+        }
+    }
+    // check possible (at present do not allow covering)
+    int numberActive = 0;
+    bool infeasible = false;
+    bool saveBad = bad;
+    for (i = 0; i < numberRows; i++) {
+        if (rhs[i] < 0)
+            infeasible = true;
+        else if (rhs[i] > 1.0e5 || fabs(rhs[i] - floor(rhs[i] + 0.5)) > 1.0e-7)
+            bad = true;
+        else if (rhs[i] > 0.0)
+            numberActive++;
+    }
+    if (bad || infeasible) {
+        delete [] rhs;
+        if (!saveBad && infeasible)
+            return -2;
+        else
+            return -1;
+    }
+    // check size of array needed
+    double size = 1.0;
+    double check = COIN_INT_MAX;
+    for (i = 0; i < numberRows; i++) {
+        int n = static_cast<int> (floor(rhs[i] + 0.5));
+        if (n) {
+            n++; // allow for 0,1... n
+            if (numberActive != 1) {
+                // power of 2
+                int iBit = 0;
+                int k = n;
+                k &= ~1;
+                while (k) {
+                    iBit++;
+                    k &= ~(1 << iBit);
+                }
+                // See if exact power
+                if (n != (1 << iBit)) {
+                    // round up to next power of 2
+                    n = 1 << (iBit + 1);
+                }
+                size *= n;
+                if (size >= check)
+                    break;
+            } else {
+                size = n; // just one constraint
+            }
+        }
+    }
+    // set size needed
+    if (size >= check)
+        size_ = COIN_INT_MAX;
+    else
+        size_ = static_cast<int> (size);
+
+    int n01 = 0;
+    int nbadcoeff = 0;
+    // See if we can tighten bounds
+    for (i = 0; i < numberColumns; i++) {
+        int j;
+        double lowerValue = lower[i];
+        double gap = upper[i] - lowerValue;
+        for (j = columnStart[i];
+                j < columnStart[i] + columnLength[i]; j++) {
+            int iRow = row[j];
+            double value = element[j];
+            if (value != 1.0)
+                nbadcoeff++;
+            if (gap*value > rhs[iRow] + 1.0e-8)
+                gap = rhs[iRow] / value;
+        }
+        gap = lowerValue + floor(gap + 1.0e-7);
+        if (gap < upper[i])
+            solver->setColUpper(i, gap);
+        if (gap <= 1.0)
+            n01++;
+    }
+    if (allowableSize && size_ <= allowableSize) {
+        if (n01 == numberColumns && !nbadcoeff)
+            algorithm_ = 0; // easiest
+        else
+            algorithm_ = 1;
+    }
+    if (allowableSize && size_ <= allowableSize) {
+        numberActive_ = numberActive;
+        indices_ = new int [numberActive_];
+        cost_ = new double [size_];
+        CoinFillN(cost_, size_, COIN_DBL_MAX);
+        // but do nothing is okay
+        cost_[0] = 0.0;
+        back_ = new int[size_];
+        CoinFillN(back_, size_, -1);
+        startBit_ = new int[numberActive_];
+        numberBits_ = new int[numberActive_];
+        lookup_ = new int [numberRows];
+        rhs_ = new int [numberActive_];
+        numberActive = 0;
+        int kBit = 0;
+        for (i = 0; i < numberRows; i++) {
+            int n = static_cast<int> (floor(rhs[i] + 0.5));
+            if (n) {
+                lookup_[i] = numberActive;
+                rhs_[numberActive] = n;
+                startBit_[numberActive] = kBit;
+                n++; // allow for 0,1... n
+                int iBit = 0;
+                // power of 2
+                int k = n;
+                k &= ~1;
+                while (k) {
+                    iBit++;
+                    k &= ~(1 << iBit);
+                }
+                // See if exact power
+                if (n != (1 << iBit)) {
+                    // round up to next power of 2
+                    iBit++;
+                }
+                if (numberActive != 1) {
+                    n = 1 << iBit;
+                    size *= n;
+                    if (size >= check)
+                        break;
+                } else {
+                    size = n; // just one constraint
+                }
+                numberBits_[numberActive++] = iBit;
+                kBit += iBit;
+            } else {
+                lookup_[i] = -1;
+            }
+        }
+        const double * rowLower = solver->getRowLower();
+        if (algorithm_ == 0) {
+            // rhs 1 and coefficients 1
+            // Get first possible solution for printing
+            target_ = -1;
+            int needed = 0;
+            int numberActive = 0;
+            for (i = 0; i < numberRows; i++) {
+                int newRow = lookup_[i];
+                if (newRow >= 0) {
+                    if (rowLower[i] == rowUpper[i]) {
+                        needed += 1 << numberActive;
+                        numberActive++;
+                    }
+                }
+            }
+            for (i = 0; i < size_; i++) {
+                if ((i&needed) == needed) {
+                    break;
+                }
+            }
+            target_ = i;
+        } else {
+            coefficients_ = new int[numberActive_];
+            // If not too many general rhs then we can be more efficient
+            numberNonOne_ = 0;
+            for (i = 0; i < numberActive_; i++) {
+                if (rhs_[i] != 1)
+                    numberNonOne_++;
+            }
+            if (numberNonOne_*2 < numberActive_) {
+                // put rhs >1 every second
+                int * permute = new int[numberActive_];
+                int * temp = new int[numberActive_];
+                // try different ways
+                int k = 0;
+                for (i = 0; i < numberRows; i++) {
+                    int newRow = lookup_[i];
+                    if (newRow >= 0 && rhs_[newRow] > 1) {
+                        permute[newRow] = k;
+                        k += 2;
+                    }
+                }
+                // adjust so k points to last
+                k -= 2;
+                // and now rest
+                int k1 = 1;
+                for (i = 0; i < numberRows; i++) {
+                    int newRow = lookup_[i];
+                    if (newRow >= 0 && rhs_[newRow] == 1) {
+                        permute[newRow] = k1;
+                        k1++;
+                        if (k1 <= k)
+                            k1++;
+                    }
+                }
+                for (i = 0; i < numberActive_; i++) {
+                    int put = permute[i];
+                    temp[put] = rhs_[i];
+                }
+                memcpy(rhs_, temp, numberActive_*sizeof(int));
+                for (i = 0; i < numberActive_; i++) {
+                    int put = permute[i];
+                    temp[put] = numberBits_[i];
+                }
+                memcpy(numberBits_, temp, numberActive_*sizeof(int));
+                k = 0;
+                for (i = 0; i < numberActive_; i++) {
+                    startBit_[i] = k;
+                    k += numberBits_[i];
+                }
+                for (i = 0; i < numberRows; i++) {
+                    int newRow = lookup_[i];
+                    if (newRow >= 0)
+                        lookup_[i] = permute[newRow];
+                }
+                delete [] permute;
+                delete [] temp;
+                // mark new method
+                algorithm_ = 2;
+            }
+            // Get first possible solution for printing
+            target_ = -1;
+            int needed = 0;
+            int * lower2 = new int[numberActive_];
+            for (i = 0; i < numberRows; i++) {
+                int newRow = lookup_[i];
+                if (newRow >= 0) {
+                    int gap = static_cast<int> (rowUpper[i] - CoinMax(0.0, rowLower[i]));
+                    lower2[newRow] = rhs_[newRow] - gap;
+                    int numberBits = numberBits_[newRow];
+                    int startBit = startBit_[newRow];
+                    if (numberBits == 1 && !gap) {
+                        needed |= 1 << startBit;
+                    }
+                }
+            }
+            for (i = 0; i < size_; i++) {
+                if ((i&needed) == needed) {
+                    // this one may do
+                    bool good = true;
+                    for (int kk = 0; kk < numberActive_; kk++) {
+                        int numberBits = numberBits_[kk];
+                        int startBit = startBit_[kk];
+                        int size = 1 << numberBits;
+                        int start = 1 << startBit;
+                        int mask = start * (size - 1);
+                        int level = (i & mask) >> startBit;
+                        if (level < lower2[kk]) {
+                            good = false;
+                            break;
+                        }
+                    }
+                    if (good) {
+                        break;
+                    }
+                }
+            }
+            delete [] lower2;
+            target_ = i;
+        }
+    }
+    delete [] rhs;
+    if (allowableSize && size_ > allowableSize) {
+      COIN_DETAIL_PRINT(printf("Too large - need %d entries x 8 bytes\n", size_));
+        return -1; // too big
+    } else {
+        return algorithm_;
+    }
+}
+
+// Resets stuff if model changes
+void
+CbcFathomDynamicProgramming::resetModel(CbcModel * model)
+{
+    model_ = model;
+    type_ = checkPossible();
+}
+int
+CbcFathomDynamicProgramming::fathom(double * & betterSolution)
+{
+    int returnCode = 0;
+    int type = checkPossible(maximumSizeAllowed_);
+    assert (type != -1);
+    if (type == -2) {
+        // infeasible (so complete search done)
+        return 1;
+    }
+    if (algorithm_ >= 0) {
+        OsiSolverInterface * solver = model_->solver();
+        const double * lower = solver->getColLower();
+        const double * upper = solver->getColUpper();
+        const double * objective = solver->getObjCoefficients();
+        double direction = solver->getObjSense();
+        const CoinPackedMatrix * matrix = solver->getMatrixByCol();
+        // Column copy
+        const double * element = matrix->getElements();
+        const int * row = matrix->getIndices();
+        const CoinBigIndex * columnStart = matrix->getVectorStarts();
+        const int * columnLength = matrix->getVectorLengths();
+        const double * rowLower = solver->getRowLower();
+        const double * rowUpper = solver->getRowUpper();
+        int numberRows = model_->getNumRows();
+
+        int numberColumns = solver->getNumCols();
+        double offset;
+        solver->getDblParam(OsiObjOffset, offset);
+        double fixedObj = -offset;
+        int i;
+        // may be possible
+        double bestAtTarget = COIN_DBL_MAX;
+        for (i = 0; i < numberColumns; i++) {
+            if (size_ > 10000000 && (i % 100) == 0)
+	      COIN_DETAIL_PRINT(printf("column %d\n", i));
+            double lowerValue = lower[i];
+            assert (lowerValue == floor(lowerValue));
+            double cost = direction * objective[i];
+            fixedObj += lowerValue * cost;
+            int gap = static_cast<int> (upper[i] - lowerValue);
+            CoinBigIndex start = columnStart[i];
+            tryColumn(columnLength[i], row + start, element + start, cost, gap);
+            if (cost_[target_] < bestAtTarget) {
+                if (model_->messageHandler()->logLevel() > 1)
+                    printf("At column %d new best objective of %g\n", i, cost_[target_]);
+                bestAtTarget = cost_[target_];
+            }
+        }
+        returnCode = 1;
+        int needed = 0;
+        double bestValue = COIN_DBL_MAX;
+        int iBest = -1;
+        if (algorithm_ == 0) {
+            int numberActive = 0;
+            for (i = 0; i < numberRows; i++) {
+                int newRow = lookup_[i];
+                if (newRow >= 0) {
+                    if (rowLower[i] == rowUpper[i]) {
+                        needed += 1 << numberActive;
+                        numberActive++;
+                    }
+                }
+            }
+            for (i = 0; i < size_; i++) {
+                if ((i&needed) == needed) {
+                    // this one will do
+                    if (cost_[i] < bestValue) {
+                        bestValue = cost_[i];
+                        iBest = i;
+                    }
+                }
+            }
+        } else {
+            int * lower = new int[numberActive_];
+            for (i = 0; i < numberRows; i++) {
+                int newRow = lookup_[i];
+                if (newRow >= 0) {
+                    int gap = static_cast<int> (rowUpper[i] - CoinMax(0.0, rowLower[i]));
+                    lower[newRow] = rhs_[newRow] - gap;
+                    int numberBits = numberBits_[newRow];
+                    int startBit = startBit_[newRow];
+                    if (numberBits == 1 && !gap) {
+                        needed |= 1 << startBit;
+                    }
+                }
+            }
+            for (i = 0; i < size_; i++) {
+                if ((i&needed) == needed) {
+                    // this one may do
+                    bool good = true;
+                    for (int kk = 0; kk < numberActive_; kk++) {
+                        int numberBits = numberBits_[kk];
+                        int startBit = startBit_[kk];
+                        int size = 1 << numberBits;
+                        int start = 1 << startBit;
+                        int mask = start * (size - 1);
+                        int level = (i & mask) >> startBit;
+                        if (level < lower[kk]) {
+                            good = false;
+                            break;
+                        }
+                    }
+                    if (good && cost_[i] < bestValue) {
+                        bestValue = cost_[i];
+                        iBest = i;
+                    }
+                }
+            }
+            delete [] lower;
+        }
+        if (bestValue < COIN_DBL_MAX) {
+            bestValue += fixedObj;
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("Can get solution of %g\n", bestValue);
+            if (bestValue < model_->getMinimizationObjValue()) {
+                // set up solution
+                betterSolution = new double[numberColumns];
+                memcpy(betterSolution, lower, numberColumns*sizeof(double));
+                while (iBest > 0) {
+                    int n = decodeBitPattern(iBest - back_[iBest], indices_, numberRows);
+                    // Search for cheapest
+                    double bestCost = COIN_DBL_MAX;
+                    int iColumn = -1;
+                    for (i = 0; i < numberColumns; i++) {
+                        if (n == columnLength[i]) {
+                            bool good = true;
+                            for (int j = columnStart[i];
+                                    j < columnStart[i] + columnLength[i]; j++) {
+                                int iRow = row[j];
+                                double value = element[j];
+                                int iValue = static_cast<int> (value);
+                                if (iValue != indices_[iRow]) {
+                                    good = false;
+                                    break;
+                                }
+                            }
+                            if (good && objective[i] < bestCost && betterSolution[i] < upper[i]) {
+                                bestCost = objective[i];
+                                iColumn = i;
+                            }
+                        }
+                    }
+                    assert (iColumn >= 0);
+                    betterSolution[iColumn]++;
+                    assert (betterSolution[iColumn] <= upper[iColumn]);
+                    iBest = back_[iBest];
+                }
+            }
+            // paranoid check
+            double * rowActivity = new double [numberRows];
+            memset(rowActivity, 0, numberRows*sizeof(double));
+            for (i = 0; i < numberColumns; i++) {
+                int j;
+                double value = betterSolution[i];
+                if (value) {
+                    for (j = columnStart[i];
+                            j < columnStart[i] + columnLength[i]; j++) {
+                        int iRow = row[j];
+                        rowActivity[iRow] += value * element[j];
+                    }
+                }
+            }
+            // check was feasible
+            bool feasible = true;
+            for (i = 0; i < numberRows; i++) {
+                if (rowActivity[i] < rowLower[i]) {
+                    if (rowActivity[i] < rowLower[i] - 1.0e-8)
+                        feasible = false;
+                } else if (rowActivity[i] > rowUpper[i]) {
+                    if (rowActivity[i] > rowUpper[i] + 1.0e-8)
+                        feasible = false;
+                }
+            }
+            if (feasible) {
+                if (model_->messageHandler()->logLevel() > 0)
+                    printf("** good solution of %g by dynamic programming\n", bestValue);
+            }
+            delete [] rowActivity;
+        }
+        gutsOfDelete();
+    }
+    return returnCode;
+}
+/* Tries a column
+   returns true if was used in making any changes.
+*/
+bool
+CbcFathomDynamicProgramming::tryColumn(int numberElements, const int * rows,
+                                       const double * coefficients, double cost,
+                                       int upper)
+{
+    bool touched = false;
+    int n = 0;
+    if (algorithm_ == 0) {
+        for (int j = 0; j < numberElements; j++) {
+            int iRow = rows[j];
+            double value = coefficients[j];
+            int newRow = lookup_[iRow];
+            if (newRow < 0 || value > rhs_[newRow]) {
+                n = 0;
+                break; //can't use
+            } else {
+                indices_[n++] = newRow;
+            }
+        }
+        if (n && upper) {
+            touched = addOneColumn0(n, indices_, cost);
+        }
+    } else {
+        for (int j = 0; j < numberElements; j++) {
+            int iRow = rows[j];
+            double value = coefficients[j];
+            int iValue = static_cast<int> (value);
+            int newRow = lookup_[iRow];
+            if (newRow < 0 || iValue > rhs_[newRow]) {
+                n = 0;
+                break; //can't use
+            } else {
+                coefficients_[n] = iValue;
+                indices_[n++] = newRow;
+                if (upper*iValue > rhs_[newRow]) {
+                    upper = rhs_[newRow] / iValue;
+                }
+            }
+        }
+        if (n) {
+            if (algorithm_ == 1) {
+                for (int k = 1; k <= upper; k++) {
+                    bool t = addOneColumn1(n, indices_, coefficients_, cost);
+                    if (t)
+                        touched = true;
+                }
+            } else {
+                CoinSort_2(indices_, indices_ + n, coefficients_);
+                for (int k = 1; k <= upper; k++) {
+                    bool t = addOneColumn1A(n, indices_, coefficients_, cost);
+                    if (t)
+                        touched = true;
+                }
+            }
+        }
+    }
+    return touched;
+}
+/* Adds one column if type 0,
+   returns true if was used in making any changes
+*/
+bool
+CbcFathomDynamicProgramming::addOneColumn0(int numberElements, const int * rows,
+        double cost)
+{
+    // build up mask
+    int mask = 0;
+    int i;
+    for (i = 0; i < numberElements; i++) {
+        int iRow = rows[i];
+        mask |= 1 << iRow;
+    }
+    bitPattern_ = mask;
+    i = size_ - 1 - mask;
+    bool touched = false;
+    while (i >= 0) {
+        int kMask = i & mask;
+        if (kMask == 0) {
+            double thisCost = cost_[i];
+            if (thisCost != COIN_DBL_MAX) {
+                // possible
+                double newCost = thisCost + cost;
+                int next = i + mask;
+                if (cost_[next] > newCost) {
+                    cost_[next] = newCost;
+                    back_[next] = i;
+                    touched = true;
+                }
+            }
+            i--;
+        } else {
+            // we can skip some
+            int k = (i&~mask);
+#ifdef CBC_DEBUG
+            for (int j = i - 1; j > k; j--) {
+                int jMask = j & mask;
+                assert (jMask != 0);
+            }
+#endif
+            i = k;
+        }
+    }
+    return touched;
+}
+/* Adds one attempt of one column of type 1,
+   returns true if was used in making any changes.
+   At present the user has to call it once for each possible value
+*/
+bool
+CbcFathomDynamicProgramming::addOneColumn1(int numberElements, const int * rows,
+        const int * coefficients, double cost)
+{
+    /* build up masks.
+       a) mask for 1 rhs
+       b) mask for addition
+       c) mask so adding will overflow
+       d) individual masks
+    */
+    int mask1 = 0;
+    int maskAdd = 0;
+    int mask2 = 0;
+    int i;
+    int n2 = 0;
+    int mask[40];
+    int adjust[40];
+    assert (numberElements <= 40);
+    for (i = 0; i < numberElements; i++) {
+        int iRow = rows[i];
+        int numberBits = numberBits_[iRow];
+        int startBit = startBit_[iRow];
+        if (numberBits == 1) {
+            mask1 |= 1 << startBit;
+            maskAdd |= 1 << startBit;
+            mask2 |= 1 << startBit;
+        } else {
+            int value = coefficients[i];
+            int size = 1 << numberBits;
+            int start = 1 << startBit;
+            assert (value < size);
+            maskAdd |= start * value;
+            int gap = size - rhs_[iRow] - 1;
+            assert (gap >= 0);
+            int hi2 = rhs_[iRow] - value;
+            if (hi2 < size - 1)
+                hi2++;
+            adjust[n2] = start * hi2;
+            mask2 += start * gap;
+            mask[n2++] = start * (size - 1);
+        }
+    }
+    bitPattern_ = maskAdd;
+    i = size_ - 1 - maskAdd;
+    bool touched = false;
+    while (i >= 0) {
+        int kMask = i & mask1;
+        if (kMask == 0) {
+            bool good = true;
+            for (int kk = n2 - 1; kk >= 0; kk--) {
+                int iMask = mask[kk];
+                int jMask = iMask & mask2;
+                int kkMask = iMask & i;
+                kkMask += jMask;
+                if (kkMask > iMask) {
+                    // we can skip some
+                    int k = (i&~iMask);
+                    k |= adjust[kk];
+#ifdef CBC_DEBUG
+                    for (int j = i - 1; j > k; j--) {
+                        int jMask = j & mask1;
+                        if (jMask == 0) {
+                            bool good = true;
+                            for (int kk = n2 - 1; kk >= 0; kk--) {
+                                int iMask = mask[kk];
+                                int jMask = iMask & mask2;
+                                int kkMask = iMask & i;
+                                kkMask += jMask;
+                                if (kkMask > iMask) {
+                                    good = false;
+                                    break;
+                                }
+                            }
+                            assert (!good);
+                        }
+                    }
+#endif
+                    i = k;
+                    good = false;
+                    break;
+                }
+            }
+            if (good) {
+                double thisCost = cost_[i];
+                if (thisCost != COIN_DBL_MAX) {
+                    // possible
+                    double newCost = thisCost + cost;
+                    int next = i + maskAdd;
+                    if (cost_[next] > newCost) {
+                        cost_[next] = newCost;
+                        back_[next] = i;
+                        touched = true;
+                    }
+                }
+            }
+            i--;
+        } else {
+            // we can skip some
+            // we can skip some
+            int k = (i&~mask1);
+#ifdef CBC_DEBUG
+            for (int j = i - 1; j > k; j--) {
+                int jMask = j & mask1;
+                assert (jMask != 0);
+            }
+#endif
+            i = k;
+        }
+    }
+    return touched;
+}
+/* Adds one attempt of one column of type 1,
+   returns true if was used in making any changes.
+   At present the user has to call it once for each possible value
+   This version is when there are enough 1 rhs to do faster
+*/
+bool
+CbcFathomDynamicProgramming::addOneColumn1A(int numberElements, const int * rows,
+        const int * coefficients, double cost)
+{
+    /* build up masks.
+       a) mask for 1 rhs
+       b) mask for addition
+       c) mask so adding will overflow
+       d) mask for non 1 rhs
+    */
+    int maskA = 0;
+    int maskAdd = 0;
+    int maskC = 0;
+    int maskD = 0;
+    int i;
+    for (i = 0; i < numberElements; i++) {
+        int iRow = rows[i];
+        int numberBits = numberBits_[iRow];
+        int startBit = startBit_[iRow];
+        if (numberBits == 1) {
+            maskA |= 1 << startBit;
+            maskAdd |= 1 << startBit;
+        } else {
+            int value = coefficients[i];
+            int size = 1 << numberBits;
+            int start = 1 << startBit;
+            assert (value < size);
+            maskAdd |= start * value;
+            int gap = size - rhs_[iRow] + value - 1;
+            assert (gap > 0 && gap <= size - 1);
+            maskC |= start * gap;
+            maskD |= start * (size - 1);
+        }
+    }
+    bitPattern_ = maskAdd;
+    int maskDiff = maskD - maskC;
+    i = size_ - 1 - maskAdd;
+    bool touched = false;
+    if (!maskD) {
+        // Just ones
+        while (i >= 0) {
+            int kMask = i & maskA;
+            if (kMask == 0) {
+                double thisCost = cost_[i];
+                if (thisCost != COIN_DBL_MAX) {
+                    // possible
+                    double newCost = thisCost + cost;
+                    int next = i + maskAdd;
+                    if (cost_[next] > newCost) {
+                        cost_[next] = newCost;
+                        back_[next] = i;
+                        touched = true;
+                    }
+                }
+                i--;
+            } else {
+                // we can skip some
+                int k = (i&~maskA);
+                i = k;
+            }
+        }
+    } else {
+        // More general
+        while (i >= 0) {
+            int kMask = i & maskA;
+            if (kMask == 0) {
+                int added = i & maskD; // just bits belonging to non 1 rhs
+                added += maskC; // will overflow mask if bad
+                added &= (~maskD);
+                if (added == 0) {
+                    double thisCost = cost_[i];
+                    if (thisCost != COIN_DBL_MAX) {
+                        // possible
+                        double newCost = thisCost + cost;
+                        int next = i + maskAdd;
+                        if (cost_[next] > newCost) {
+                            cost_[next] = newCost;
+                            back_[next] = i;
+                            touched = true;
+                        }
+                    }
+                    i--;
+                } else {
+                    // we can skip some
+                    int k = i & ~ maskD; // clear all
+                    // Put back enough - but only below where we are
+                    int kk = (numberNonOne_ << 1) - 2;
+                    assert (rhs_[kk] > 1);
+                    int iMask = 0;
+                    for (; kk >= 0; kk -= 2) {
+                        iMask = 1 << startBit_[kk+1];
+                        if ((added&iMask) != 0) {
+                            iMask--;
+                            break;
+                        }
+                    }
+                    assert (kk >= 0);
+                    iMask &= maskDiff;
+                    k |= iMask;
+                    assert (k < i);
+                    i = k;
+                }
+            } else {
+                // we can skip some
+                int k = (i&~maskA);
+                i = k;
+            }
+        }
+    }
+    return touched;
+}
+// update model
+void CbcFathomDynamicProgramming::setModel(CbcModel * model)
+{
+    model_ = model;
+    type_ = checkPossible();
+}
+// Gets bit pattern from original column
+int CbcFathomDynamicProgramming::bitPattern(int numberElements, const int * rows,
+        const int * coefficients)
+{
+    int i;
+    int mask = 0;
+    switch (algorithm_) {
+        // just ones
+    case 0:
+        for (i = 0; i < numberElements; i++) {
+            int iRow = rows[i];
+            iRow = lookup_[iRow];
+            if (iRow >= 0)
+                mask |= 1 << iRow;
+        }
+        break;
+        //
+    case 1:
+    case 2:
+        for (i = 0; i < numberElements; i++) {
+            int iRow = rows[i];
+            iRow = lookup_[iRow];
+            if (iRow >= 0) {
+                int startBit = startBit_[iRow];
+                int value = coefficients[i];
+                int start = 1 << startBit;
+                mask |= start * value;
+            }
+        }
+        break;
+    }
+    return mask;
+}
+// Fills in original column (dense) from bit pattern
+int CbcFathomDynamicProgramming::decodeBitPattern(int bitPattern,
+        int * values,
+        int numberRows)
+{
+    int i;
+    int n = 0;
+    switch (algorithm_) {
+        // just ones
+    case 0:
+        for (i = 0; i < numberRows; i++) {
+            values[i] = 0;
+            int iRow = lookup_[i];
+            if (iRow >= 0) {
+                if ((bitPattern&(1 << iRow)) != 0) {
+                    values[i] = 1;
+                    n++;
+                }
+            }
+        }
+        break;
+        //
+    case 1:
+    case 2:
+        for (i = 0; i < numberRows; i++) {
+            values[i] = 0;
+            int iRow = lookup_[i];
+            if (iRow >= 0) {
+                int startBit = startBit_[iRow];
+                int numberBits = numberBits_[iRow];
+                int iValue = bitPattern >> startBit;
+                iValue &= ((1 << numberBits) - 1);
+                if (iValue) {
+                    values[i] = iValue;
+                    n++;
+                }
+            }
+        }
+        break;
+    }
+    return n;
+}
+
+
diff --git a/cbits/coin/CbcFathomDynamicProgramming.hpp b/cbits/coin/CbcFathomDynamicProgramming.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFathomDynamicProgramming.hpp
@@ -0,0 +1,169 @@
+/* $Id: CbcFathomDynamicProgramming.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcFathomDynamicProgramming_H
+#define CbcFathomDynamicProgramming_H
+
+#include "CbcFathom.hpp"
+
+//#############################################################################
+/** FathomDynamicProgramming class.
+
+    The idea is that after some branching the problem will be effectively smaller than
+    the original problem and maybe there will be a more specialized technique which can completely
+    fathom this branch quickly.
+
+    This is a dynamic programming implementation which is very fast for some
+    specialized problems.  It expects small integral rhs, an all integer problem
+    and positive integral coefficients. At present it can not do general set covering
+    problems just set partitioning.  It can find multiple optima for various rhs
+    combinations.
+
+    The main limiting factor is size of state space.  Each 1 rhs doubles the size of the problem.
+    2 or 3 rhs quadruples, 4,5,6,7 by 8 etc.
+ */
+
+class CbcFathomDynamicProgramming : public CbcFathom {
+public:
+    // Default Constructor
+    CbcFathomDynamicProgramming ();
+
+    // Constructor with model - assumed before cuts
+    CbcFathomDynamicProgramming (CbcModel & model);
+    // Copy constructor
+    CbcFathomDynamicProgramming(const CbcFathomDynamicProgramming & rhs);
+
+    virtual ~CbcFathomDynamicProgramming();
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    /// Clone
+    virtual CbcFathom * clone() const;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /** returns 0 if no fathoming attempted, 1 fully fathomed ,
+        2 incomplete search, 3 incomplete search but treat as complete.
+        If solution then newSolution will not be NULL and
+        will be freed by CbcModel.  It is expected that the solution is better
+        than best so far but CbcModel will double check.
+
+        If returns 3 then of course there is no guarantee of global optimum
+    */
+    virtual int fathom(double *& newSolution);
+
+    /// Maximum size allowed
+    inline int maximumSize() const {
+        return maximumSizeAllowed_;
+    }
+    inline void setMaximumSize(int value) {
+        maximumSizeAllowed_ = value;
+    }
+    /// Returns type of algorithm and sets up arrays
+    int checkPossible(int allowableSize = 0);
+    // set algorithm
+    inline void setAlgorithm(int value) {
+        algorithm_ = value;
+    }
+    /** Tries a column
+        returns true if was used in making any changes.
+    */
+    bool tryColumn(int numberElements, const int * rows,
+                   const double * coefficients, double cost,
+                   int upper = COIN_INT_MAX);
+    /// Returns cost array
+    inline const double * cost() const {
+        return cost_;
+    }
+    /// Returns back array
+    inline const int * back() const {
+        return back_;
+    }
+    /// Gets bit pattern for target result
+    inline int target() const {
+        return target_;
+    }
+    /// Sets bit pattern for target result
+    inline void setTarget(int value) {
+        target_ = value;
+    }
+private:
+    /// Does deleteions
+    void gutsOfDelete();
+
+    /** Adds one attempt of one column of type 0,
+        returns true if was used in making any changes
+    */
+    bool addOneColumn0(int numberElements, const int * rows,
+                       double cost);
+    /** Adds one attempt of one column of type 1,
+        returns true if was used in making any changes.
+        At present the user has to call it once for each possible value
+    */
+    bool addOneColumn1(int numberElements, const int * rows,
+                       const int * coefficients, double cost);
+    /** Adds one attempt of one column of type 1,
+        returns true if was used in making any changes.
+        At present the user has to call it once for each possible value.
+        This version is when there are enough 1 rhs to do faster
+    */
+    bool addOneColumn1A(int numberElements, const int * rows,
+                        const int * coefficients, double cost);
+    /// Gets bit pattern from original column
+    int bitPattern(int numberElements, const int * rows,
+                   const int * coefficients);
+    /// Gets bit pattern from original column
+    int bitPattern(int numberElements, const int * rows,
+                   const double * coefficients);
+    /// Fills in original column (dense) from bit pattern - returning number nonzero
+    int decodeBitPattern(int bitPattern, int * values, int numberRows);
+
+protected:
+
+    /// Size of states (power of 2 unless just one constraint)
+    int size_;
+    /** Type - 0 coefficients and rhs all 1,
+        1 - coefficients > 1 or rhs > 1
+    */
+    int type_;
+    /// Space for states
+    double * cost_;
+    /// Which state produced this cheapest one
+    int * back_;
+    /// Some rows may be satisified so we need a lookup
+    int * lookup_;
+    /// Space for sorted indices
+    int * indices_;
+    /// Number of active rows
+    int numberActive_;
+    /// Maximum size allowed
+    int maximumSizeAllowed_;
+    /// Start bit for each active row
+    int * startBit_;
+    /// Number bits for each active row
+    int * numberBits_;
+    /// Effective rhs
+    int * rhs_;
+    /// Space for sorted coefficients
+    int * coefficients_;
+    /// Target pattern
+    int target_;
+    /// Number of Non 1 rhs
+    int numberNonOne_;
+    /// Current bit pattern
+    int bitPattern_;
+    /// Current algorithm
+    int algorithm_;
+private:
+
+    /// Illegal Assignment operator
+    CbcFathomDynamicProgramming & operator=(const CbcFathomDynamicProgramming& rhs);
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcFeasibilityBase.hpp b/cbits/coin/CbcFeasibilityBase.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFeasibilityBase.hpp
@@ -0,0 +1,56 @@
+/* $Id: CbcFeasibilityBase.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcFeasibilityBase_H
+#define CbcFeasibilityBase_H
+
+
+//#############################################################################
+/*  There are cases where the user wants to control how CBC sees the problems feasibility.
+    The user may want to examine the problem and say :
+    a) The default looks OK
+    b) Pretend this problem is Integer feasible
+    c) Pretend this problem is infeasible even though it looks feasible
+
+    This simple class allows user to do that.
+
+*/
+
+class CbcModel;
+class CbcFeasibilityBase {
+public:
+    // Default Constructor
+    CbcFeasibilityBase () {}
+
+    /**
+       On input mode:
+       0 - called after a solve but before any cuts
+       -1 - called after strong branching
+       Returns :
+       0 - no opinion
+       -1 pretend infeasible
+       1 pretend integer solution
+    */
+    virtual int feasible(CbcModel * , int ) {
+        return 0;
+    }
+
+    virtual ~CbcFeasibilityBase() {}
+
+    // Copy constructor
+    CbcFeasibilityBase ( const CbcFeasibilityBase & ) {}
+
+    // Assignment operator
+    CbcFeasibilityBase & operator=( const CbcFeasibilityBase& ) {
+        return *this;
+    }
+
+    /// Clone
+    virtual CbcFeasibilityBase * clone() const {
+        return new CbcFeasibilityBase(*this);
+    }
+};
+#endif
+
diff --git a/cbits/coin/CbcFixVariable.cpp b/cbits/coin/CbcFixVariable.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFixVariable.cpp
@@ -0,0 +1,196 @@
+// $Id: CbcFixVariable.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcFixVariable.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+
+//##############################################################################
+
+// Default Constructor
+CbcFixVariable::CbcFixVariable ()
+        : CbcConsequence(),
+        numberStates_(0),
+        states_(NULL),
+        startLower_(NULL),
+        startUpper_(NULL),
+        newBound_(NULL),
+        variable_(NULL)
+{
+}
+
+// One useful Constructor
+CbcFixVariable::CbcFixVariable (int numberStates, const int * states, const int * numberNewLower,
+                                const int ** newLowerValue,
+                                const int ** lowerColumn,
+                                const int * numberNewUpper, const int ** newUpperValue,
+                                const int ** upperColumn)
+        : CbcConsequence(),
+        states_(NULL),
+        startLower_(NULL),
+        startUpper_(NULL),
+        newBound_(NULL),
+        variable_(NULL)
+{
+    // How much space
+    numberStates_ = numberStates;
+    if (numberStates_) {
+        states_ = new int[numberStates_];
+        memcpy(states_, states, numberStates_*sizeof(int));
+        int i;
+        int n = 0;
+        startLower_ = new int[numberStates_+1];
+        startUpper_ = new int[numberStates_+1];
+        startLower_[0] = 0;
+        //count
+        for (i = 0; i < numberStates_; i++) {
+            n += numberNewLower[i];
+            startUpper_[i] = n;
+            n += numberNewUpper[i];
+            startLower_[i+1] = n;
+        }
+        newBound_ = new double [n];
+        variable_ = new int [n];
+        n = 0;
+        for (i = 0; i < numberStates_; i++) {
+            int j;
+            int k;
+            const int * bound;
+            const int * variable;
+            k = numberNewLower[i];
+            bound = newLowerValue[i];
+            variable = lowerColumn[i];
+            for (j = 0; j < k; j++) {
+                newBound_[n] = bound[j];
+                variable_[n++] = variable[j];
+            }
+            k = numberNewUpper[i];
+            bound = newUpperValue[i];
+            variable = upperColumn[i];
+            for (j = 0; j < k; j++) {
+                newBound_[n] = bound[j];
+                variable_[n++] = variable[j];
+            }
+        }
+    }
+}
+
+// Copy constructor
+CbcFixVariable::CbcFixVariable ( const CbcFixVariable & rhs)
+        : CbcConsequence(rhs)
+{
+    numberStates_ = rhs.numberStates_;
+    states_ = NULL;
+    startLower_ = NULL;
+    startUpper_ = NULL;
+    newBound_ = NULL;
+    variable_ = NULL;
+    if (numberStates_) {
+        states_ = CoinCopyOfArray(rhs.states_, numberStates_);
+        startLower_ = CoinCopyOfArray(rhs.startLower_, numberStates_ + 1);
+        startUpper_ = CoinCopyOfArray(rhs.startUpper_, numberStates_ + 1);
+        int n = startLower_[numberStates_];
+        newBound_ = CoinCopyOfArray(rhs.newBound_, n);
+        variable_ = CoinCopyOfArray(rhs.variable_, n);
+    }
+}
+
+// Clone
+CbcConsequence *
+CbcFixVariable::clone() const
+{
+    return new CbcFixVariable(*this);
+}
+
+// Assignment operator
+CbcFixVariable &
+CbcFixVariable::operator=( const CbcFixVariable & rhs)
+{
+    if (this != &rhs) {
+        CbcConsequence::operator=(rhs);
+        delete [] states_;
+        delete [] startLower_;
+        delete [] startUpper_;
+        delete [] newBound_;
+        delete [] variable_;
+        states_ = NULL;
+        startLower_ = NULL;
+        startUpper_ = NULL;
+        newBound_ = NULL;
+        variable_ = NULL;
+        numberStates_ = rhs.numberStates_;
+        if (numberStates_) {
+            states_ = CoinCopyOfArray(rhs.states_, numberStates_);
+            startLower_ = CoinCopyOfArray(rhs.startLower_, numberStates_ + 1);
+            startUpper_ = CoinCopyOfArray(rhs.startUpper_, numberStates_ + 1);
+            int n = startLower_[numberStates_];
+            newBound_ = CoinCopyOfArray(rhs.newBound_, n);
+            variable_ = CoinCopyOfArray(rhs.variable_, n);
+        }
+    }
+    return *this;
+}
+
+// Destructor
+CbcFixVariable::~CbcFixVariable ()
+{
+    delete [] states_;
+    delete [] startLower_;
+    delete [] startUpper_;
+    delete [] newBound_;
+    delete [] variable_;
+}
+// Set up a startLower for a single member
+void
+CbcFixVariable::applyToSolver(OsiSolverInterface * solver, int state) const
+{
+    assert (state == -9999 || state == 9999);
+    // Find state
+    int find;
+    for (find = 0; find < numberStates_; find++)
+        if (states_[find] == state)
+            break;
+    if (find == numberStates_)
+        return;
+    int i;
+    // Set new lower bounds
+    for (i = startLower_[find]; i < startUpper_[find]; i++) {
+        int iColumn = variable_[i];
+        double value = newBound_[i];
+        double oldValue = solver->getColLower()[iColumn];
+        //printf("for %d old lower bound %g, new %g",iColumn,oldValue,value);
+        solver->setColLower(iColumn, CoinMax(value, oldValue));
+        //printf(" => %g\n",solver->getColLower()[iColumn]);
+    }
+    // Set new upper bounds
+    for (i = startUpper_[find]; i < startLower_[find+1]; i++) {
+        int iColumn = variable_[i];
+        double value = newBound_[i];
+        double oldValue = solver->getColUpper()[iColumn];
+        //printf("for %d old upper bound %g, new %g",iColumn,oldValue,value);
+        solver->setColUpper(iColumn, CoinMin(value, oldValue));
+        //printf(" => %g\n",solver->getColUpper()[iColumn]);
+    }
+}
+
diff --git a/cbits/coin/CbcFixVariable.hpp b/cbits/coin/CbcFixVariable.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFixVariable.hpp
@@ -0,0 +1,67 @@
+// $Id: CbcFixVariable.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#ifndef CbcFixVariable_H
+#define CbcFixVariable_H
+
+#include "CbcBranchBase.hpp"
+/** Class for consequent bounds.
+    When a variable is branched on it normally interacts with other variables by
+    means of equations.  There are cases where we want to step outside LP and do something
+    more directly e.g. fix bounds.  This class is for that.
+
+    A state of -9999 means at LB, +9999 means at UB,
+    others mean if fixed to that value.
+
+ */
+
+class CbcFixVariable : public CbcConsequence {
+
+public:
+
+    // Default Constructor
+    CbcFixVariable ();
+
+    // One useful Constructor
+    CbcFixVariable (int numberStates, const int * states, const int * numberNewLower, const int ** newLowerValue,
+                    const int ** lowerColumn,
+                    const int * numberNewUpper, const int ** newUpperValue,
+                    const int ** upperColumn);
+
+    // Copy constructor
+    CbcFixVariable ( const CbcFixVariable & rhs);
+
+    // Assignment operator
+    CbcFixVariable & operator=( const CbcFixVariable & rhs);
+
+    /// Clone
+    virtual CbcConsequence * clone() const;
+
+    /// Destructor
+    virtual ~CbcFixVariable ();
+
+    /** Apply to an LP solver.  Action depends on state
+     */
+    virtual void applyToSolver(OsiSolverInterface * solver, int state) const;
+
+protected:
+    /// Number of states
+    int numberStates_;
+    /// Values of integers for various states
+    int * states_;
+    /// Start of information for each state (setting new lower)
+    int * startLower_;
+    /// Start of information for each state (setting new upper)
+    int * startUpper_;
+    /// For each variable new bounds
+    double * newBound_;
+    /// Variable
+    int * variable_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcFollowOn.cpp b/cbits/coin/CbcFollowOn.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFollowOn.cpp
@@ -0,0 +1,849 @@
+// $Id: CbcFollowOn.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcFollowOn.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcBranchCut.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+//##############################################################################
+
+// Default Constructor
+CbcFollowOn::CbcFollowOn ()
+        : CbcObject(),
+        rhs_(NULL)
+{
+}
+
+// Useful constructor
+CbcFollowOn::CbcFollowOn (CbcModel * model)
+        : CbcObject(model)
+{
+    assert (model);
+    OsiSolverInterface * solver = model_->solver();
+    matrix_ = *solver->getMatrixByCol();
+    matrix_.removeGaps();
+    matrix_.setExtraGap(0.0);
+    matrixByRow_ = *solver->getMatrixByRow();
+    int numberRows = matrix_.getNumRows();
+
+    rhs_ = new int[numberRows];
+    int i;
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    // Row copy
+    const double * elementByRow = matrixByRow_.getElements();
+    const int * column = matrixByRow_.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+    const int * rowLength = matrixByRow_.getVectorLengths();
+    for (i = 0; i < numberRows; i++) {
+        rhs_[i] = 0;
+        double value = rowLower[i];
+        if (value == rowUpper[i]) {
+            if (floor(value) == value && value >= 1.0 && value < 10.0) {
+                // check elements
+                bool good = true;
+                for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                    int iColumn = column[j];
+                    if (!solver->isBinary(iColumn))
+                        good = false;
+                    double elValue = elementByRow[j];
+                    if (floor(elValue) != elValue || value < 1.0)
+                        good = false;
+                }
+                if (good)
+                    rhs_[i] = static_cast<int> (value);
+            }
+        }
+    }
+}
+
+// Copy constructor
+CbcFollowOn::CbcFollowOn ( const CbcFollowOn & rhs)
+        : CbcObject(rhs),
+        matrix_(rhs.matrix_),
+        matrixByRow_(rhs.matrixByRow_)
+{
+    int numberRows = matrix_.getNumRows();
+    rhs_ = CoinCopyOfArray(rhs.rhs_, numberRows);
+}
+
+// Clone
+CbcObject *
+CbcFollowOn::clone() const
+{
+    return new CbcFollowOn(*this);
+}
+
+// Assignment operator
+CbcFollowOn &
+CbcFollowOn::operator=( const CbcFollowOn & rhs)
+{
+    if (this != &rhs) {
+        CbcObject::operator=(rhs);
+        delete [] rhs_;
+        matrix_ = rhs.matrix_;
+        matrixByRow_ = rhs.matrixByRow_;
+        int numberRows = matrix_.getNumRows();
+        rhs_ = CoinCopyOfArray(rhs.rhs_, numberRows);
+    }
+    return *this;
+}
+
+// Destructor
+CbcFollowOn::~CbcFollowOn ()
+{
+    delete [] rhs_;
+}
+// As some computation is needed in more than one place - returns row
+int
+CbcFollowOn::gutsOfFollowOn(int & otherRow, int & preferredWay) const
+{
+    int whichRow = -1;
+    otherRow = -1;
+    int numberRows = matrix_.getNumRows();
+
+    int i;
+    // For sorting
+    int * sort = new int [numberRows];
+    int * isort = new int [numberRows];
+    // Column copy
+    //const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+    // Row copy
+    const double * elementByRow = matrixByRow_.getElements();
+    const int * column = matrixByRow_.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+    const int * rowLength = matrixByRow_.getVectorLengths();
+    OsiSolverInterface * solver = model_->solver();
+    const double * columnLower = solver->getColLower();
+    const double * columnUpper = solver->getColUpper();
+    const double * solution = solver->getColSolution();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    int nSort = 0;
+    for (i = 0; i < numberRows; i++) {
+        if (rhs_[i]) {
+            // check elements
+            double smallest = 1.0e10;
+            double largest = 0.0;
+            int rhsValue = rhs_[i];
+            int number1 = 0;
+            int numberUnsatisfied = 0;
+            for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                int iColumn = column[j];
+                double value = elementByRow[j];
+                double solValue = solution[iColumn];
+                if (columnLower[iColumn] != columnUpper[iColumn]) {
+                    smallest = CoinMin(smallest, value);
+                    largest = CoinMax(largest, value);
+                    if (value == 1.0)
+                        number1++;
+                    if (solValue < 1.0 - integerTolerance && solValue > integerTolerance)
+                        numberUnsatisfied++;
+                } else {
+                    rhsValue -= static_cast<int>(value * floor(solValue + 0.5));
+                }
+            }
+            if (numberUnsatisfied > 1) {
+                if (smallest < largest) {
+                    // probably no good but check a few things
+                    assert (largest <= rhsValue);
+                    if (number1 == 1 && largest == rhsValue)
+                        printf("could fix\n");
+                } else if (largest == rhsValue) {
+                    sort[nSort] = i;
+                    isort[nSort++] = -numberUnsatisfied;
+                }
+            }
+        }
+    }
+    if (nSort > 1) {
+        CoinSort_2(isort, isort + nSort, sort);
+        CoinZeroN(isort, numberRows);
+        double * other = new double[numberRows];
+        CoinZeroN(other, numberRows);
+        int * which = new int[numberRows];
+        //#define COUNT
+#ifndef COUNT
+        bool beforeSolution = model_->getSolutionCount() == 0;
+#endif
+        for (int k = 0; k < nSort - 1; k++) {
+            i = sort[k];
+            int numberUnsatisfied = 0;
+            int n = 0;
+            int j;
+            for (j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+                int iColumn = column[j];
+                if (columnLower[iColumn] != columnUpper[iColumn]) {
+                    double solValue = solution[iColumn] - columnLower[iColumn];
+                    if (solValue < 1.0 - integerTolerance && solValue > integerTolerance) {
+                        numberUnsatisfied++;
+                        for (int jj = columnStart[iColumn]; jj < columnStart[iColumn] + columnLength[iColumn]; jj++) {
+                            int iRow = row[jj];
+                            if (rhs_[iRow]) {
+                                other[iRow] += solValue;
+                                if (isort[iRow]) {
+                                    isort[iRow]++;
+                                } else {
+                                    isort[iRow] = 1;
+                                    which[n++] = iRow;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            double total = 0.0;
+            // Take out row
+            double sumThis = other[i];
+            other[i] = 0.0;
+            assert (numberUnsatisfied == isort[i]);
+            // find one nearest half if solution, one if before solution
+            int iBest = -1;
+            double dtarget = 0.5 * total;
+#ifdef COUNT
+            int target = (numberUnsatisfied + 1) >> 1;
+            int best = numberUnsatisfied;
+#else
+            double best;
+            if (beforeSolution)
+                best = dtarget;
+            else
+                best = 1.0e30;
+#endif
+            for (j = 0; j < n; j++) {
+                int iRow = which[j];
+                double dvalue = other[iRow];
+                other[iRow] = 0.0;
+#ifdef COUNT
+                int value = isort[iRow];
+#endif
+                isort[iRow] = 0;
+                if (fabs(dvalue) < 1.0e-8 || fabs(sumThis - dvalue) < 1.0e-8)
+                    continue;
+                if (dvalue < integerTolerance || dvalue > 1.0 - integerTolerance)
+                    continue;
+#ifdef COUNT
+                if (abs(value - target) < best && value != numberUnsatisfied) {
+                    best = abs(value - target);
+                    iBest = iRow;
+                    if (dvalue < dtarget)
+                        preferredWay = 1;
+                    else
+                        preferredWay = -1;
+                }
+#else
+                if (beforeSolution) {
+                    if (fabs(dvalue - dtarget) > best) {
+                        best = fabs(dvalue - dtarget);
+                        iBest = iRow;
+                        if (dvalue < dtarget)
+                            preferredWay = 1;
+                        else
+                            preferredWay = -1;
+                    }
+                } else {
+                    if (fabs(dvalue - dtarget) < best) {
+                        best = fabs(dvalue - dtarget);
+                        iBest = iRow;
+                        if (dvalue < dtarget)
+                            preferredWay = 1;
+                        else
+                            preferredWay = -1;
+                    }
+                }
+#endif
+            }
+            if (iBest >= 0) {
+                whichRow = i;
+                otherRow = iBest;
+                break;
+            }
+        }
+        delete [] which;
+        delete [] other;
+    }
+    delete [] sort;
+    delete [] isort;
+    return whichRow;
+}
+double
+CbcFollowOn::infeasibility(const OsiBranchingInformation * /*info*/,
+                           int &preferredWay) const
+{
+    int otherRow = 0;
+    int whichRow = gutsOfFollowOn(otherRow, preferredWay);
+    if (whichRow < 0)
+        return 0.0;
+    else
+        return 2.0* model_->getDblParam(CbcModel::CbcIntegerTolerance);
+}
+
+// This looks at solution and sets bounds to contain solution
+void
+CbcFollowOn::feasibleRegion()
+{
+}
+
+CbcBranchingObject *
+CbcFollowOn::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int way)
+{
+    int otherRow = 0;
+    int preferredWay;
+    int whichRow = gutsOfFollowOn(otherRow, preferredWay);
+    assert(way == preferredWay);
+    assert (whichRow >= 0);
+    int numberColumns = matrix_.getNumCols();
+
+    // Column copy
+    //const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+    // Row copy
+    //const double * elementByRow = matrixByRow_.getElements();
+    const int * column = matrixByRow_.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+    const int * rowLength = matrixByRow_.getVectorLengths();
+    //OsiSolverInterface * solver = model_->solver();
+    const double * columnLower = solver->getColLower();
+    const double * columnUpper = solver->getColUpper();
+    //const double * solution = solver->getColSolution();
+    int nUp = 0;
+    int nDown = 0;
+    int * upList = new int[numberColumns];
+    int * downList = new int[numberColumns];
+    int j;
+    for (j = rowStart[whichRow]; j < rowStart[whichRow] + rowLength[whichRow]; j++) {
+        int iColumn = column[j];
+        if (columnLower[iColumn] != columnUpper[iColumn]) {
+            bool up = true;
+            for (int jj = columnStart[iColumn]; jj < columnStart[iColumn] + columnLength[iColumn]; jj++) {
+                int iRow = row[jj];
+                if (iRow == otherRow) {
+                    up = false;
+                    break;
+                }
+            }
+            if (up)
+                upList[nUp++] = iColumn;
+            else
+                downList[nDown++] = iColumn;
+        }
+    }
+    //printf("way %d\n",way);
+    // create object
+    //printf("would fix %d down and %d up\n",nDown,nUp);
+    CbcBranchingObject * branch
+    = new CbcFixingBranchingObject(model_, way,
+                                   nDown, downList, nUp, upList);
+    delete [] upList;
+    delete [] downList;
+    return branch;
+}
+
+//##############################################################################
+
+// Default Constructor
+CbcFixingBranchingObject::CbcFixingBranchingObject()
+        : CbcBranchingObject()
+{
+    numberDown_ = 0;
+    numberUp_ = 0;
+    downList_ = NULL;
+    upList_ = NULL;
+}
+
+// Useful constructor
+CbcFixingBranchingObject::CbcFixingBranchingObject (CbcModel * model,
+        int way ,
+        int numberOnDownSide, const int * down,
+        int numberOnUpSide, const int * up)
+        : CbcBranchingObject(model, 0, way, 0.5)
+{
+    numberDown_ = numberOnDownSide;
+    numberUp_ = numberOnUpSide;
+    downList_ = CoinCopyOfArray(down, numberDown_);
+    upList_ = CoinCopyOfArray(up, numberUp_);
+}
+
+// Copy constructor
+CbcFixingBranchingObject::CbcFixingBranchingObject ( const CbcFixingBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+    numberDown_ = rhs.numberDown_;
+    numberUp_ = rhs.numberUp_;
+    downList_ = CoinCopyOfArray(rhs.downList_, numberDown_);
+    upList_ = CoinCopyOfArray(rhs.upList_, numberUp_);
+}
+
+// Assignment operator
+CbcFixingBranchingObject &
+CbcFixingBranchingObject::operator=( const CbcFixingBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        delete [] downList_;
+        delete [] upList_;
+        numberDown_ = rhs.numberDown_;
+        numberUp_ = rhs.numberUp_;
+        downList_ = CoinCopyOfArray(rhs.downList_, numberDown_);
+        upList_ = CoinCopyOfArray(rhs.upList_, numberUp_);
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcFixingBranchingObject::clone() const
+{
+    return (new CbcFixingBranchingObject(*this));
+}
+
+
+// Destructor
+CbcFixingBranchingObject::~CbcFixingBranchingObject ()
+{
+    delete [] downList_;
+    delete [] upList_;
+}
+double
+CbcFixingBranchingObject::branch()
+{
+    decrementNumberBranchesLeft();
+    OsiSolverInterface * solver = model_->solver();
+    const double * columnLower = solver->getColLower();
+    int i;
+    // *** for way - up means fix all those in up section
+    if (way_ < 0) {
+#ifdef FULL_PRINT
+        printf("Down Fix ");
+#endif
+        //printf("Down Fix %d\n",numberDown_);
+        for (i = 0; i < numberDown_; i++) {
+            int iColumn = downList_[i];
+            model_->solver()->setColUpper(iColumn, columnLower[iColumn]);
+#ifdef FULL_PRINT
+            printf("Setting bound on %d to lower bound\n", iColumn);
+#endif
+        }
+        way_ = 1;	  // Swap direction
+    } else {
+#ifdef FULL_PRINT
+        printf("Up Fix ");
+#endif
+        //printf("Up Fix %d\n",numberUp_);
+        for (i = 0; i < numberUp_; i++) {
+            int iColumn = upList_[i];
+            model_->solver()->setColUpper(iColumn, columnLower[iColumn]);
+#ifdef FULL_PRINT
+            printf("Setting bound on %d to lower bound\n", iColumn);
+#endif
+        }
+        way_ = -1;	  // Swap direction
+    }
+#ifdef FULL_PRINT
+    printf("\n");
+#endif
+    return 0.0;
+}
+void
+CbcFixingBranchingObject::print()
+{
+    int i;
+    // *** for way - up means fix all those in up section
+    if (way_ < 0) {
+        printf("Down Fix ");
+        for (i = 0; i < numberDown_; i++) {
+            int iColumn = downList_[i];
+            printf("%d ", iColumn);
+        }
+    } else {
+        printf("Up Fix ");
+        for (i = 0; i < numberUp_; i++) {
+            int iColumn = upList_[i];
+            printf("%d ", iColumn);
+        }
+    }
+    printf("\n");
+}
+
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcFixingBranchingObject::compareOriginalObject
+(const CbcBranchingObject* /*brObj*/) const
+{
+    throw("must implement");
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+   */
+CbcRangeCompare
+CbcFixingBranchingObject::compareBranchingObject
+(const CbcBranchingObject* /*brObj*/, const bool /*replaceIfOverlap*/)
+{
+#ifdef JJF_ZERO //ndef NDEBUG
+    const CbcFixingBranchingObject* br =
+        dynamic_cast<const CbcFixingBranchingObject*>(brObj);
+    assert(br);
+#endif
+    // If two FixingBranchingObject's have the same base object then it's pretty
+    // much guaranteed
+    throw("must implement");
+}
+
+//##############################################################################
+
+//##############################################################################
+
+// Default Constructor
+CbcIdiotBranch::CbcIdiotBranch ()
+        : CbcObject()
+{
+  id_ = 1000000000 +  CutBranchingObj;
+}
+
+// Useful constructor
+CbcIdiotBranch::CbcIdiotBranch (CbcModel * model)
+        : CbcObject(model)
+{
+    assert (model);
+    id_ = 1000000000 +  CutBranchingObj;
+}
+
+// Copy constructor
+CbcIdiotBranch::CbcIdiotBranch ( const CbcIdiotBranch & rhs)
+  : CbcObject(rhs),
+    randomNumberGenerator_(rhs.randomNumberGenerator_),
+    savedRandomNumberGenerator_(rhs.savedRandomNumberGenerator_)
+{
+}
+
+// Clone
+CbcObject *
+CbcIdiotBranch::clone() const
+{
+    return new CbcIdiotBranch(*this);
+}
+
+// Assignment operator
+CbcIdiotBranch &
+CbcIdiotBranch::operator=( const CbcIdiotBranch & rhs)
+{
+    if (this != &rhs) {
+        CbcObject::operator=(rhs);
+        randomNumberGenerator_ = rhs.randomNumberGenerator_;
+        savedRandomNumberGenerator_ = rhs.savedRandomNumberGenerator_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcIdiotBranch::~CbcIdiotBranch ()
+{
+}
+double
+CbcIdiotBranch::infeasibility(const OsiBranchingInformation * info,
+                           int &preferredWay) const
+{
+  randomNumberGenerator_ = savedRandomNumberGenerator_;
+  double rhs = buildCut(info,0,preferredWay).ub();
+  double fraction = rhs-floor(rhs);
+  if (fraction>0.5)
+    fraction=1.0-fraction;
+  return fraction;
+}
+
+// This looks at solution and sets bounds to contain solution
+void
+CbcIdiotBranch::feasibleRegion()
+{
+}
+
+CbcBranchingObject *
+CbcIdiotBranch::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way)
+{
+  // down and up 
+  randomNumberGenerator_ = savedRandomNumberGenerator_;
+  int preferredWay;
+  OsiRowCut downCut = buildCut(info,0,preferredWay);
+  double rhs = downCut.ub();
+  assert(rhs == downCut.lb());
+  OsiRowCut upCut =downCut;
+  downCut.setUb(floor(rhs));
+  downCut.setLb(-COIN_DBL_MAX);
+  upCut.setLb(ceil(rhs));
+  upCut.setUb(COIN_DBL_MAX);
+  CbcBranchingObject * branch
+    = new CbcCutBranchingObject(model_, downCut,upCut,true);
+  return branch;
+}
+// Initialize for branching
+void 
+CbcIdiotBranch::initializeForBranching(CbcModel * )
+{
+  savedRandomNumberGenerator_ = randomNumberGenerator_;
+}
+// Build "cut"
+OsiRowCut 
+CbcIdiotBranch::buildCut(const OsiBranchingInformation * info,int /*type*/,int & preferredWay) const
+{
+  int numberIntegers = model_->numberIntegers();
+  const int * integerVariable = model_->integerVariable();
+  int * which = new int [numberIntegers];
+  double * away = new double [numberIntegers];
+  const double * solution = info->solution_;
+  const double * lower = info->lower_;
+  const double * upper = info->upper_;
+  double integerTolerance = model_->getIntegerTolerance();
+  //int nMax=CoinMin(4,numberIntegers/2);
+  int n=0;
+  for (int i=0;i<numberIntegers;i++) {
+    int iColumn=integerVariable[i];
+    double value = solution[iColumn];
+    value = CoinMax(value, lower[iColumn]);
+    value = CoinMin(value, upper[iColumn]);
+    //#define JUST_SMALL
+#ifndef JUST_SMALL
+    double nearest = floor(value + 0.5);
+    if (fabs(value-nearest)>integerTolerance) {
+      double random = 0.0; //0.25*randomNumberGenerator_.randomDouble();
+      away[n]=-fabs(value-nearest)*(1.0+random);
+      which[n++]=iColumn;
+    }
+#else
+    double distanceDown = value-floor(value);
+    if (distanceDown>10.0*integerTolerance&&distanceDown<0.1) {
+      double random = 0.0; //0.25*randomNumberGenerator_.randomDouble();
+      away[n]=distanceDown*(1.0+random);
+      which[n++]=iColumn;
+    }
+#endif
+  }
+  CoinSort_2(away,away+n,which);
+  OsiRowCut possibleCut;
+  possibleCut.setUb(0.0);
+  if (n>1) {
+    int nUse=0;
+    double useRhs=0.0;
+    double best=0.0;
+    double rhs = 0.0;
+    double scaleFactor=1.0;
+    /* should be able to be clever to find best cut
+       maybe don't do if away >0.45
+       maybe don't be random
+       maybe do complete enumeration on biggest k (where sum of k >= 1.0)
+       maybe allow +-1
+     */ 
+    for (int i=0;i<n;i++) {
+      int iColumn=which[i];
+      double value = solution[iColumn];
+      value = CoinMax(value, lower[iColumn]);
+      value = CoinMin(value, upper[iColumn]);
+#define PLUS_MINUS
+#ifndef PLUS_MINUS
+      away[i]=1.0;
+      rhs += value;
+#else
+      if (value-floor(value)<=0.5) {
+	away[i]=1.0;
+	rhs += value;
+      } else {
+	away[i]=-1.0;
+	rhs -= value;
+      }
+#endif
+      double nearest = floor(rhs + 0.5);
+      double distance=fabs(rhs-nearest);
+      // scale back
+      distance *= scaleFactor;
+      scaleFactor *= 0.95;
+      if (distance>best) {
+	nUse=i+1;
+	best=distance;
+	useRhs=rhs;
+      }
+    }
+    // create cut
+    if (nUse>1) {
+      possibleCut.setRow(nUse,which,away);
+      possibleCut.setLb(useRhs);
+      possibleCut.setUb(useRhs);
+    }
+  }
+  delete [] which;
+  delete [] away;
+  return possibleCut;
+} 
+#if 0
+//##############################################################################
+
+// Default Constructor
+CbcBoundingBranchingObject::CbcBoundingBranchingObject()
+        : CbcBranchingObject()
+{
+  branchCut_.setUb(0.0);
+}
+
+// Useful constructor
+CbcBoundingBranchingObject::CbcBoundingBranchingObject (CbcModel * model,
+							int way , const OsiRowCut * cut)
+        : CbcBranchingObject(model, 0, way, 0.5)
+{
+  branchCut_ = *cut;
+}
+
+// Copy constructor
+CbcBoundingBranchingObject::CbcBoundingBranchingObject ( const CbcBoundingBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+  branchCut_ = rhs.branchCut_;
+}
+
+// Assignment operator
+CbcBoundingBranchingObject &
+CbcBoundingBranchingObject::operator=( const CbcBoundingBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+	branchCut_ = rhs.branchCut_;
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcBoundingBranchingObject::clone() const
+{
+    return (new CbcBoundingBranchingObject(*this));
+}
+
+
+// Destructor
+CbcBoundingBranchingObject::~CbcBoundingBranchingObject ()
+{
+}
+double
+CbcBoundingBranchingObject::branch()
+{
+    decrementNumberBranchesLeft();
+    OsiSolverInterface * solver = model_->solver();
+    const double * columnLower = solver->getColLower();
+    int i;
+    // *** for way - up means bound all those in up section
+    if (way_ < 0) {
+#ifdef FULL_PRINT
+        printf("Down Bound ");
+#endif
+        //printf("Down Bound %d\n",numberDown_);
+        for (i = 0; i < numberDown_; i++) {
+            int iColumn = downList_[i];
+            model_->solver()->setColUpper(iColumn, columnLower[iColumn]);
+#ifdef FULL_PRINT
+            printf("Setting bound on %d to lower bound\n", iColumn);
+#endif
+        }
+        way_ = 1;	  // Swap direction
+    } else {
+#ifdef FULL_PRINT
+        printf("Up Bound ");
+#endif
+        //printf("Up Bound %d\n",numberUp_);
+        for (i = 0; i < numberUp_; i++) {
+            int iColumn = upList_[i];
+            model_->solver()->setColUpper(iColumn, columnLower[iColumn]);
+#ifdef FULL_PRINT
+            printf("Setting bound on %d to lower bound\n", iColumn);
+#endif
+        }
+        way_ = -1;	  // Swap direction
+    }
+#ifdef FULL_PRINT
+    printf("\n");
+#endif
+    return 0.0;
+}
+void
+CbcBoundingBranchingObject::print()
+{
+  OsiRowCut cut = branchCut_;
+  if (way_ < 0) {
+    printf("Down Fix ");
+    cut.setUb(floor(branchCut_.ub()));
+    cut.setLb(-COIN_DBL_MAX);
+  } else {
+    printf("Up Fix ");
+    cut.setLb(ceil(branchCut_.lb()));
+    cut.setUb(COIN_DBL_MAX);
+  }
+  printf("\n");
+  cut.print();
+}
+
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcBoundingBranchingObject::compareOriginalObject
+(const CbcBranchingObject* /*brObj*/) const
+{
+    throw("must implement");
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+   */
+CbcRangeCompare
+CbcBoundingBranchingObject::compareBranchingObject
+(const CbcBranchingObject* /*brObj*/, const bool /*replaceIfOverlap*/)
+{
+#ifdef JJF_ZERO //ndef NDEBUG
+    const CbcBoundingBranchingObject* br =
+        dynamic_cast<const CbcBoundingBranchingObject*>(brObj);
+    assert(br);
+#endif
+    // If two BoundingBranchingObject's have the same base object then it's pretty
+    // much guaranteed
+    throw("must implement");
+}
+
+//##############################################################################
+
+#endif
diff --git a/cbits/coin/CbcFollowOn.hpp b/cbits/coin/CbcFollowOn.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFollowOn.hpp
@@ -0,0 +1,207 @@
+// $Id: CbcFollowOn.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#ifndef CbcFollowOn_H
+#define CbcFollowOn_H
+
+#include "CbcBranchBase.hpp"
+#include "OsiRowCut.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+
+/** Define a follow on class.
+    The idea of this is that in air-crew scheduling problems crew may fly in on flight A
+    and out on flight B or on some other flight.  A useful branch is one which on one side
+    fixes all which go out on flight B to 0, while the other branch fixes all those that do NOT
+    go out on flight B to 0.
+
+    This branching rule should be in addition to normal rules and have a high priority.
+*/
+
+class CbcFollowOn : public CbcObject {
+
+public:
+
+    // Default Constructor
+    CbcFollowOn ();
+
+    /** Useful constructor
+    */
+    CbcFollowOn (CbcModel * model);
+
+    // Copy constructor
+    CbcFollowOn ( const CbcFollowOn &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcFollowOn & operator=( const CbcFollowOn& rhs);
+
+    // Destructor
+    ~CbcFollowOn ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /// This looks at solution and sets bounds to contain solution
+    virtual void feasibleRegion();
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+    /// As some computation is needed in more than one place - returns row
+    virtual int gutsOfFollowOn(int & otherRow, int & preferredWay) const;
+
+protected:
+    /// data
+    /// Matrix
+    CoinPackedMatrix matrix_;
+    /// Matrix by row
+    CoinPackedMatrix matrixByRow_;
+    /// Possible rhs (if 0 then not possible)
+    int * rhs_;
+};
+
+/** General Branching Object class.
+    Each way fixes some variables to lower bound
+ */
+class CbcFixingBranchingObject : public CbcBranchingObject {
+
+public:
+
+    // Default Constructor
+    CbcFixingBranchingObject ();
+
+    // Useful constructor
+    CbcFixingBranchingObject (CbcModel * model,
+                              int way,
+                              int numberOnDownSide, const int * down,
+                              int numberOnUpSide, const int * up);
+
+    // Copy constructor
+    CbcFixingBranchingObject ( const CbcFixingBranchingObject &);
+
+    // Assignment operator
+    CbcFixingBranchingObject & operator=( const CbcFixingBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~CbcFixingBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch();
+
+#ifdef JJF_ZERO
+    // No need to override. Default works fine.
+    /** Reset every information so that the branching object appears to point to
+        the previous child. This method does not need to modify anything in any
+        solver. */
+    virtual void previousBranch();
+#endif
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return FollowOnBranchObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+private:
+    /// data
+    /// Number on down list
+    int numberDown_;
+    /// Number on up list
+    int numberUp_;
+    /// downList - variables to fix to lb on down branch
+    int * downList_;
+    /// upList - variables to fix to lb on up branch
+    int * upList_;
+};
+
+/** Define an idiotic idea class.
+    The idea of this is that we take some integer variables away from integer and
+    sum them with some randomness to get signed sum close to 0.5.  We then can
+    branch to exclude that gap.
+
+    This branching rule should be in addition to normal rules and have a high priority.
+*/
+
+class CbcIdiotBranch : public CbcObject {
+
+public:
+
+    // Default Constructor
+    CbcIdiotBranch ();
+
+    /** Useful constructor
+    */
+    CbcIdiotBranch (CbcModel * model);
+
+    // Copy constructor
+    CbcIdiotBranch ( const CbcIdiotBranch &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcIdiotBranch & operator=( const CbcIdiotBranch& rhs);
+
+    // Destructor
+    ~CbcIdiotBranch ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /// This looks at solution and sets bounds to contain solution
+    virtual void feasibleRegion();
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+    /// Initialize for branching
+    virtual void initializeForBranching(CbcModel * );
+protected:
+    /// Build "cut"
+    OsiRowCut buildCut(const OsiBranchingInformation * info,int type,int & preferredWay) const; 
+    /// data
+    /// Thread specific random number generator
+    mutable CoinThreadRandom randomNumberGenerator_;
+    /// Saved version of thread specific random number generator
+    mutable CoinThreadRandom savedRandomNumberGenerator_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcFullNodeInfo.cpp b/cbits/coin/CbcFullNodeInfo.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFullNodeInfo.cpp
@@ -0,0 +1,200 @@
+// $Id: CbcFullNodeInfo.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/24/09 carved from CbcNode
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcConfig.h"
+
+#include <string>
+//#define CBC_DEBUG 1
+//#define CHECK_CUT_COUNTS
+//#define CHECK_NODE
+//#define CBC_CHECK_BASIS
+#include <cassert>
+#include <cfloat>
+#define CUTS
+#include "OsiSolverInterface.hpp"
+#include "OsiChooseVariable.hpp"
+#include "OsiAuxInfo.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinTime.hpp"
+#include "CbcModel.hpp"
+#include "CbcNode.hpp"
+#include "CbcStatistics.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "OsiCuts.hpp"
+#include "CbcCountRowCut.hpp"
+#include "CbcFeasibilityBase.hpp"
+#include "CbcMessage.hpp"
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#include "ClpSimplexOther.hpp"
+#endif
+using namespace std;
+#include "CglCutGenerator.hpp"
+
+CbcFullNodeInfo::CbcFullNodeInfo() :
+        CbcNodeInfo(),
+        basis_(),
+        numberIntegers_(0),
+        lower_(NULL),
+        upper_(NULL)
+{
+}
+CbcFullNodeInfo::CbcFullNodeInfo(CbcModel * model,
+                                 int numberRowsAtContinuous) :
+        CbcNodeInfo(NULL, model->currentNode())
+{
+    OsiSolverInterface * solver = model->solver();
+    numberRows_ = numberRowsAtContinuous;
+    numberIntegers_ = model->numberIntegers();
+    int numberColumns = model->getNumCols();
+    lower_ = new double [numberColumns];
+    upper_ = new double [numberColumns];
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    int i;
+
+    for (i = 0; i < numberColumns; i++) {
+        lower_[i] = lower[i];
+        upper_[i] = upper[i];
+    }
+
+    basis_ =  dynamic_cast<CoinWarmStartBasis*>(solver->getWarmStart());
+}
+
+CbcFullNodeInfo::CbcFullNodeInfo(const CbcFullNodeInfo & rhs) :
+        CbcNodeInfo(rhs)
+{
+    basis_ = dynamic_cast<CoinWarmStartBasis *>(rhs.basis_->clone()) ;
+    numberIntegers_ = rhs.numberIntegers_;
+    lower_ = NULL;
+    upper_ = NULL;
+    if (rhs.lower_ != NULL) {
+        int numberColumns = basis_->getNumStructural();
+        lower_ = new double [numberColumns];
+        upper_ = new double [numberColumns];
+        assert (upper_ != NULL);
+        memcpy(lower_, rhs.lower_, numberColumns*sizeof(double));
+        memcpy(upper_, rhs.upper_, numberColumns*sizeof(double));
+    }
+}
+
+CbcNodeInfo *
+CbcFullNodeInfo::clone() const
+{
+    return (new CbcFullNodeInfo(*this));
+}
+
+CbcFullNodeInfo::~CbcFullNodeInfo ()
+{
+    delete basis_ ;
+    delete [] lower_;
+    delete [] upper_;
+}
+
+/*
+  The basis supplied as a parameter is deleted and replaced with a new basis
+  appropriate for the node, and lower and upper bounds on variables are
+  reset according to the stored bounds arrays. Any cuts associated with this
+  node are added to the list in addCuts, but not actually added to the
+  constraint system in the model.
+
+  Why pass in a basis at all? The short answer is ``We need the parameter to
+  pass out a basis, so might as well use it to pass in the size.''
+
+  A longer answer is that in practice we take a memory allocation hit up in
+  addCuts1 (the only place applyToModel is called) when we setSize() the
+  basis that's passed in. It's immediately tossed here in favour of a clone
+  of the basis attached to this nodeInfo. This can probably be fixed, given
+  a bit of thought.
+*/
+
+void CbcFullNodeInfo::applyToModel (CbcModel *model,
+                                    CoinWarmStartBasis *&basis,
+                                    CbcCountRowCut **addCuts,
+                                    int &currentNumberCuts) const
+
+{
+    OsiSolverInterface *solver = model->solver() ;
+
+    // branch - do bounds
+    assert (active_ == 7 || active_ == 15);
+    int i;
+    solver->setColLower(lower_);
+    solver->setColUpper(upper_);
+    int numberColumns = model->getNumCols();
+    // move basis - but make sure size stays
+    // for bon-min - should not be needed int numberRows = model->getNumRows();
+    int numberRows = basis->getNumArtificial();
+    delete basis ;
+    if (basis_) {
+        basis = dynamic_cast<CoinWarmStartBasis *>(basis_->clone()) ;
+        basis->resize(numberRows, numberColumns);
+#ifdef CBC_CHECK_BASIS
+        std::cout << "Basis (after applying root " << this << ") " << std::endl ;
+        basis->print() ;
+#endif
+    } else {
+        // We have a solver without a basis
+        basis = NULL;
+    }
+    for (i = 0; i < numberCuts_; i++)
+        addCuts[currentNumberCuts+i] = cuts_[i];
+    currentNumberCuts += numberCuts_;
+    assert(!parent_);
+    return ;
+}
+// Just apply bounds to one variable (1=>infeasible)
+int
+CbcFullNodeInfo::applyBounds(int iColumn, double & lower, double & upper, int force)
+{
+    if ((force && 1) == 0) {
+      if (lower > lower_[iColumn])
+	COIN_DETAIL_PRINT(printf("%d odd lower going from %g to %g\n", iColumn, lower, lower_[iColumn]));
+        lower = lower_[iColumn];
+    } else {
+        lower_[iColumn] = lower;
+    }
+    if ((force && 2) == 0) {
+      if (upper < upper_[iColumn])
+	COIN_DETAIL_PRINT(printf("%d odd upper going from %g to %g\n", iColumn, upper, upper_[iColumn]));
+        upper = upper_[iColumn];
+    } else {
+        upper_[iColumn] = upper;
+    }
+    return (upper_[iColumn] >= lower_[iColumn]) ? 0 : 1;
+}
+
+/* Builds up row basis backwards (until original model).
+   Returns NULL or previous one to apply .
+   Depends on Free being 0 and impossible for cuts
+*/
+CbcNodeInfo *
+CbcFullNodeInfo::buildRowBasis(CoinWarmStartBasis & basis ) const
+{
+    const unsigned int * saved =
+        reinterpret_cast<const unsigned int *> (basis_->getArtificialStatus());
+    unsigned int * now =
+        reinterpret_cast<unsigned int *> (basis.getArtificialStatus());
+    int number = basis_->getNumArtificial() >> 4;;
+    int i;
+    for (i = 0; i < number; i++) {
+        if (!now[i])
+            now[i] = saved[i];
+    }
+    return NULL;
+}
+
diff --git a/cbits/coin/CbcFullNodeInfo.hpp b/cbits/coin/CbcFullNodeInfo.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcFullNodeInfo.hpp
@@ -0,0 +1,161 @@
+// $Id: CbcFullNodeInfo.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/24/09 carved from CbcNode
+
+#ifndef CbcFullNodeInfo_H
+#define CbcFullNodeInfo_H
+
+#include <string>
+#include <vector>
+
+#include "CoinWarmStartBasis.hpp"
+#include "CoinSearchTree.hpp"
+#include "CbcBranchBase.hpp"
+#include "CbcNodeInfo.hpp"
+
+class OsiSolverInterface;
+class OsiSolverBranch;
+
+class OsiCuts;
+class OsiRowCut;
+class OsiRowCutDebugger;
+class CoinWarmStartBasis;
+class CbcCountRowCut;
+class CbcModel;
+class CbcNode;
+class CbcSubProblem;
+class CbcGeneralBranchingObject;
+
+//#############################################################################
+/** Information required to recreate the subproblem at this node
+
+  When a subproblem is initially created, it is represented by a CbcNode
+  object and an attached CbcNodeInfo object.
+
+  The CbcNode contains information needed while the subproblem remains live.
+  The CbcNode is deleted when the last branch arm has been evaluated.
+
+  The CbcNodeInfo contains information required to maintain the branch-and-cut
+  search tree structure (links and reference counts) and to recreate the
+  subproblem for this node (basis, variable bounds, cutting planes). A
+  CbcNodeInfo object remains in existence until all nodes have been pruned from
+  the subtree rooted at this node.
+
+  The principle used to maintain the reference count is that the reference
+  count is always the sum of all potential and actual children of the node.
+  Specifically,
+  <ul>
+    <li> Once it's determined how the node will branch, the reference count
+	 is set to the number of potential children (<i>i.e.</i>, the number
+	 of arms of the branch).
+    <li> As each child is created by CbcNode::branch() (converting a potential
+	 child to the active subproblem), the reference count is decremented.
+    <li> If the child survives and will become a node in the search tree
+	 (converting the active subproblem into an actual child), increment the
+	 reference count.
+  </ul>
+  Notice that the active subproblem lives in a sort of limbo, neither a
+  potential or an actual node in the branch-and-cut tree.
+
+  CbcNodeInfo objects come in two flavours. A CbcFullNodeInfo object contains
+  a full record of the information required to recreate a subproblem.
+  A CbcPartialNodeInfo object expresses this information in terms of
+  differences from the parent.
+*/
+
+
+/** \brief Holds complete information for recreating a subproblem.
+
+  A CbcFullNodeInfo object contains all necessary information (bounds, basis,
+  and cuts) required to recreate a subproblem.
+
+  \todo While there's no explicit statement, the code often makes the implicit
+	assumption that an CbcFullNodeInfo structure will appear only at the
+	root node of the search tree. Things will break if this assumption
+	is violated.
+*/
+
+class CbcFullNodeInfo : public CbcNodeInfo {
+
+public:
+
+    /** \brief Modify model according to information at node
+
+        The routine modifies the model according to bound information at node,
+        creates a new basis according to information at node, but with the size
+        passed in through basis, and adds any cuts to the addCuts array.
+
+      \note The basis passed in via basis is solely a vehicle for passing in
+        the desired basis size. It will be deleted and a new basis returned.
+    */
+    virtual void applyToModel (CbcModel *model, CoinWarmStartBasis *&basis,
+                               CbcCountRowCut **addCuts,
+                               int &currentNumberCuts) const ;
+
+    /// Just apply bounds to one variable - force means overwrite by lower,upper (1=>infeasible)
+    virtual int applyBounds(int iColumn, double & lower, double & upper, int force) ;
+
+    /** Builds up row basis backwards (until original model).
+        Returns NULL or previous one to apply .
+        Depends on Free being 0 and impossible for cuts
+    */
+    virtual CbcNodeInfo * buildRowBasis(CoinWarmStartBasis & basis) const ;
+    // Default Constructor
+    CbcFullNodeInfo ();
+
+    /** Constructor from continuous or satisfied
+    */
+    CbcFullNodeInfo (CbcModel * model,
+                     int numberRowsAtContinuous);
+
+    // Copy constructor
+    CbcFullNodeInfo ( const CbcFullNodeInfo &);
+
+    // Destructor
+    ~CbcFullNodeInfo ();
+
+    /// Clone
+    virtual CbcNodeInfo * clone() const;
+    /// Lower bounds
+    inline const double * lower() const {
+        return lower_;
+    }
+    /// Set a bound
+    inline void setColLower(int sequence, double value)
+    { lower_[sequence]=value;}
+    /// Mutable lower bounds
+    inline double * mutableLower() const {
+        return lower_;
+    }
+    /// Upper bounds
+    inline const double * upper() const {
+        return upper_;
+    }
+    /// Set a bound
+    inline void setColUpper(int sequence, double value)
+    { upper_[sequence]=value;}
+    /// Mutable upper bounds
+    inline double * mutableUpper() const {
+        return upper_;
+    }
+protected:
+    // Data
+    /** Full basis
+
+      This MUST BE A POINTER to avoid cutting extra information in derived
+      warm start classes.
+    */
+    CoinWarmStartBasis *basis_;
+    int numberIntegers_;
+    // Bounds stored in full
+    double * lower_;
+    double * upper_;
+private:
+    /// Illegal Assignment operator
+    CbcFullNodeInfo & operator=(const CbcFullNodeInfo& rhs);
+};
+#endif //CbcFullNodeInfo_H
+
diff --git a/cbits/coin/CbcGeneral.cpp b/cbits/coin/CbcGeneral.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcGeneral.cpp
@@ -0,0 +1,80 @@
+// $Id: CbcGeneral.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcGeneral.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+// Default Constructor
+CbcGeneral::CbcGeneral()
+        : CbcObject()
+{
+}
+
+// Constructor from model
+CbcGeneral::CbcGeneral(CbcModel * model)
+        : CbcObject(model)
+{
+}
+
+
+// Destructor
+CbcGeneral::~CbcGeneral ()
+{
+}
+
+// Copy constructor
+CbcGeneral::CbcGeneral ( const CbcGeneral & rhs)
+        : CbcObject(rhs)
+{
+}
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "ClpNode.hpp"
+#include "CbcBranchDynamic.hpp"
+// Assignment operator
+CbcGeneral &
+CbcGeneral::operator=( const CbcGeneral & rhs)
+{
+    if (this != &rhs) {
+        CbcObject::operator=(rhs);
+    }
+    return *this;
+}
+// Infeasibility - large is 0.5
+double
+CbcGeneral::infeasibility(const OsiBranchingInformation * /*info*/,
+                          int &/*preferredWay*/) const
+{
+    abort();
+    return 0.0;
+}
+CbcBranchingObject *
+CbcGeneral::createCbcBranch(OsiSolverInterface * /*solver*/, const OsiBranchingInformation * /*info*/, int /*way*/)
+{
+    abort();
+    return NULL;
+}
+#endif
+
diff --git a/cbits/coin/CbcGeneral.hpp b/cbits/coin/CbcGeneral.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcGeneral.hpp
@@ -0,0 +1,60 @@
+// $Id: CbcGeneral.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#ifndef CbcGeneral_H
+#define CbcGeneral_H
+
+#include "CbcBranchBase.hpp"
+/** Define a catch all class.
+    This will create a list of subproblems
+*/
+
+
+class CbcGeneral : public CbcObject {
+
+public:
+
+    // Default Constructor
+    CbcGeneral ();
+
+    /** Useful constructor
+        Just needs to point to model.
+    */
+    CbcGeneral (CbcModel * model);
+
+    // Copy constructor
+    CbcGeneral ( const CbcGeneral &);
+
+    /// Clone
+    virtual CbcObject * clone() const = 0;
+
+    // Assignment operator
+    CbcGeneral & operator=( const CbcGeneral& rhs);
+
+    // Destructor
+    ~CbcGeneral ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /// This looks at solution and sets bounds to contain solution
+    virtual void feasibleRegion() = 0;
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+
+    /// Redoes data when sequence numbers change
+    virtual void redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns) = 0;
+
+protected:
+    /// data
+};
+
+#endif
+
diff --git a/cbits/coin/CbcGeneralDepth.cpp b/cbits/coin/CbcGeneralDepth.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcGeneralDepth.cpp
@@ -0,0 +1,771 @@
+// $Id: CbcGeneralDepth.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcGeneralDepth.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcHeuristicDive.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "ClpNode.hpp"
+#include "CbcBranchDynamic.hpp"
+// Default Constructor
+CbcGeneralDepth::CbcGeneralDepth ()
+        : CbcGeneral(),
+        maximumDepth_(0),
+        maximumNodes_(0),
+        whichSolution_(-1),
+        numberNodes_(0),
+        nodeInfo_(NULL)
+{
+}
+
+// Useful constructor (which are integer indices)
+CbcGeneralDepth::CbcGeneralDepth (CbcModel * model, int maximumDepth)
+        : CbcGeneral(model),
+        maximumDepth_(maximumDepth),
+        maximumNodes_(0),
+        whichSolution_(-1),
+        numberNodes_(0),
+        nodeInfo_(NULL)
+{
+    assert(maximumDepth_ < 1000000);
+    if (maximumDepth_ > 0)
+        maximumNodes_ = (1 << maximumDepth_) + 1 + maximumDepth_;
+    else if (maximumDepth_ < 0)
+        maximumNodes_ = 1 + 1 - maximumDepth_;
+    else
+        maximumNodes_ = 0;
+#define MAX_NODES 100
+    maximumNodes_ = CoinMin(maximumNodes_, 1 + maximumDepth_ + MAX_NODES);
+    if (maximumNodes_) {
+        nodeInfo_ = new ClpNodeStuff();
+        nodeInfo_->maximumNodes_ = maximumNodes_;
+        ClpNodeStuff * info = nodeInfo_;
+        // for reduced costs and duals
+        info->solverOptions_ |= 7;
+        if (maximumDepth_ > 0) {
+            info->nDepth_ = maximumDepth_;
+        } else {
+            info->nDepth_ = - maximumDepth_;
+            info->solverOptions_ |= 32;
+        }
+        ClpNode ** nodeInfo = new ClpNode * [maximumNodes_];
+        for (int i = 0; i < maximumNodes_; i++)
+            nodeInfo[i] = NULL;
+        info->nodeInfo_ = nodeInfo;
+    } else {
+        nodeInfo_ = NULL;
+    }
+}
+
+// Copy constructor
+CbcGeneralDepth::CbcGeneralDepth ( const CbcGeneralDepth & rhs)
+        : CbcGeneral(rhs)
+{
+    maximumDepth_ = rhs.maximumDepth_;
+    maximumNodes_ = rhs.maximumNodes_;
+    whichSolution_ = -1;
+    numberNodes_ = 0;
+    if (maximumNodes_) {
+        assert (rhs.nodeInfo_);
+        nodeInfo_ = new ClpNodeStuff(*rhs.nodeInfo_);
+        nodeInfo_->maximumNodes_ = maximumNodes_;
+        ClpNodeStuff * info = nodeInfo_;
+        if (maximumDepth_ > 0) {
+            info->nDepth_ = maximumDepth_;
+        } else {
+            info->nDepth_ = - maximumDepth_;
+            info->solverOptions_ |= 32;
+        }
+        if (!info->nodeInfo_) {
+            ClpNode ** nodeInfo = new ClpNode * [maximumNodes_];
+            for (int i = 0; i < maximumNodes_; i++)
+                nodeInfo[i] = NULL;
+            info->nodeInfo_ = nodeInfo;
+        }
+    } else {
+        nodeInfo_ = NULL;
+    }
+}
+
+// Clone
+CbcObject *
+CbcGeneralDepth::clone() const
+{
+    return new CbcGeneralDepth(*this);
+}
+
+// Assignment operator
+CbcGeneralDepth &
+CbcGeneralDepth::operator=( const CbcGeneralDepth & rhs)
+{
+    if (this != &rhs) {
+        CbcGeneral::operator=(rhs);
+        delete nodeInfo_;
+        maximumDepth_ = rhs.maximumDepth_;
+        maximumNodes_ = rhs.maximumNodes_;
+        whichSolution_ = -1;
+        numberNodes_ = 0;
+        if (maximumDepth_) {
+            assert (rhs.nodeInfo_);
+            nodeInfo_ = new ClpNodeStuff(*rhs.nodeInfo_);
+            nodeInfo_->maximumNodes_ = maximumNodes_;
+        } else {
+            nodeInfo_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Destructor
+CbcGeneralDepth::~CbcGeneralDepth ()
+{
+    delete nodeInfo_;
+}
+// Infeasibility - large is 0.5
+double
+CbcGeneralDepth::infeasibility(const OsiBranchingInformation * /*info*/,
+                               int &/*preferredWay*/) const
+{
+    whichSolution_ = -1;
+    // should use genuine OsiBranchingInformation usefulInfo = model_->usefulInformation();
+    // for now assume only called when correct
+    //if (usefulInfo.depth_>=4&&!model_->parentModel()
+    //     &&(usefulInfo.depth_%2)==0) {
+    if (true) {
+        OsiSolverInterface * solver = model_->solver();
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver);
+        if (clpSolver) {
+	  if ((model_->moreSpecialOptions()&33554432)==0) {
+            ClpNodeStuff * info = nodeInfo_;
+            info->integerTolerance_ = model_->getIntegerTolerance();
+            info->integerIncrement_ = model_->getCutoffIncrement();
+            info->numberBeforeTrust_ = model_->numberBeforeTrust();
+            info->stateOfSearch_ = model_->stateOfSearch();
+            // Compute "small" change in branch
+            int nBranches = model_->getIntParam(CbcModel::CbcNumberBranches);
+            if (nBranches) {
+                double average = model_->getDblParam(CbcModel::CbcSumChange) / static_cast<double>(nBranches);
+                info->smallChange_ =
+                    CoinMax(average * 1.0e-5, model_->getDblParam(CbcModel::CbcSmallestChange));
+                info->smallChange_ = CoinMax(info->smallChange_, 1.0e-8);
+            } else {
+                info->smallChange_ = 1.0e-8;
+            }
+            int numberIntegers = model_->numberIntegers();
+            double * down = new double[numberIntegers];
+            double * up = new double[numberIntegers];
+            int * priority = new int[numberIntegers];
+            int * numberDown = new int[numberIntegers];
+            int * numberUp = new int[numberIntegers];
+            int * numberDownInfeasible = new int[numberIntegers];
+            int * numberUpInfeasible = new int[numberIntegers];
+            model_->fillPseudoCosts(down, up, priority, numberDown, numberUp,
+                                    numberDownInfeasible, numberUpInfeasible);
+            info->fillPseudoCosts(down, up, priority, numberDown, numberUp,
+                                  numberDownInfeasible,
+                                  numberUpInfeasible, numberIntegers);
+            info->presolveType_ = 1;
+            delete [] down;
+            delete [] up;
+            delete [] numberDown;
+            delete [] numberUp;
+            delete [] numberDownInfeasible;
+            delete [] numberUpInfeasible;
+            bool takeHint;
+            OsiHintStrength strength;
+            solver->getHintParam(OsiDoReducePrint, takeHint, strength);
+            ClpSimplex * simplex = clpSolver->getModelPtr();
+            int saveLevel = simplex->logLevel();
+            if (strength != OsiHintIgnore && takeHint && saveLevel == 1)
+                simplex->setLogLevel(0);
+            clpSolver->setBasis();
+            whichSolution_ = simplex->fathomMany(info);
+            //printf("FAT %d nodes, %d iterations\n",
+            //info->numberNodesExplored_,info->numberIterations_);
+            //printf("CbcBranch %d rows, %d columns\n",clpSolver->getNumRows(),
+            //     clpSolver->getNumCols());
+            model_->incrementExtra(info->numberNodesExplored_,
+                                   info->numberIterations_);
+            // update pseudo costs
+            double smallest = 1.0e50;
+            double largest = -1.0;
+            OsiObject ** objects = model_->objects();
+#ifndef NDEBUG
+            const int * integerVariable = model_->integerVariable();
+#endif
+            for (int i = 0; i < numberIntegers; i++) {
+#ifndef NDEBUG
+                CbcSimpleIntegerDynamicPseudoCost * obj =
+                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(objects[i]) ;
+                assert (obj && obj->columnNumber() == integerVariable[i]);
+#else
+                CbcSimpleIntegerDynamicPseudoCost * obj =
+                    static_cast <CbcSimpleIntegerDynamicPseudoCost *>(objects[i]) ;
+#endif
+                if (info->numberUp_[i] > 0) {
+                    if (info->downPseudo_[i] > largest)
+                        largest = info->downPseudo_[i];
+                    if (info->downPseudo_[i] < smallest)
+                        smallest = info->downPseudo_[i];
+                    if (info->upPseudo_[i] > largest)
+                        largest = info->upPseudo_[i];
+                    if (info->upPseudo_[i] < smallest)
+                        smallest = info->upPseudo_[i];
+                    obj->updateAfterMini(info->numberDown_[i],
+                                         info->numberDownInfeasible_[i],
+                                         info->downPseudo_[i],
+                                         info->numberUp_[i],
+                                         info->numberUpInfeasible_[i],
+                                         info->upPseudo_[i]);
+                }
+            }
+            //printf("range of costs %g to %g\n",smallest,largest);
+            simplex->setLogLevel(saveLevel);
+            numberNodes_ = info->nNodes_;
+	  } else {
+	    // Try diving
+	    // See if any diving heuristics set to do dive+save
+	    CbcHeuristicDive * dive=NULL;
+	    for (int i = 0; i < model_->numberHeuristics(); i++) {
+	      CbcHeuristicDive * possible = dynamic_cast<CbcHeuristicDive *>(model_->heuristic(i));
+	      if (possible&&possible->maxSimplexIterations()==COIN_INT_MAX) {
+		// if more than one then rotate later?
+		//if (possible->canHeuristicRun()) {
+		dive=possible;
+		break;
+	      }
+	    }
+	    assert (dive); // otherwise moreSpecial should have been turned off
+	    CbcSubProblem ** nodes=NULL;
+	    int branchState=dive->fathom(model_,numberNodes_,nodes);
+	    if (branchState) {
+	      printf("new solution\n");
+	      whichSolution_=numberNodes_-1;
+	    } else {
+	      whichSolution_=-1;
+	    }
+#if 0
+	    if (0) {
+	      for (int iNode=0;iNode<numberNodes;iNode++) {
+		//tree_->push(nodes[iNode]) ;
+	      }
+	      assert (node->nodeInfo());
+	      if (node->nodeInfo()->numberBranchesLeft()) {
+		tree_->push(node) ;
+	      } else {
+		node->setActive(false);
+	      }
+	    }
+#endif
+	    //delete [] nodes;
+	    model_->setTemporaryPointer(reinterpret_cast<void *>(nodes));
+	    // end try diving
+	  }
+	  int numberDo = numberNodes_;
+	  if (numberDo > 0 || whichSolution_ >= 0) {
+	    return 0.5;
+	  } else {
+	    // no solution
+	    return COIN_DBL_MAX; // say infeasible
+	  }
+        } else {
+            return -1.0;
+        }
+    } else {
+        return -1.0;
+    }
+}
+
+// This looks at solution and sets bounds to contain solution
+void
+CbcGeneralDepth::feasibleRegion()
+{
+    // Other stuff should have done this
+}
+// Redoes data when sequence numbers change
+void
+CbcGeneralDepth::redoSequenceEtc(CbcModel * /*model*/,
+                                 int /*numberColumns*/,
+                                 const int * /*originalColumns*/)
+{
+}
+
+//#define CHECK_PATH
+#ifdef CHECK_PATH
+extern const double * debuggerSolution_Z;
+extern int numberColumns_Z;
+extern int gotGoodNode_Z;
+#endif
+CbcBranchingObject *
+CbcGeneralDepth::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int /*way*/)
+{
+    int numberDo = numberNodes_;
+    if (whichSolution_ >= 0 && (model_->moreSpecialOptions()&33554432)==0) 
+        numberDo--;
+    assert (numberDo > 0);
+    // create object
+    CbcGeneralBranchingObject * branch = new CbcGeneralBranchingObject(model_);
+    // skip solution
+    branch->numberSubProblems_ = numberDo;
+    // If parentBranch_ back in then will have to be 2*
+    branch->numberSubLeft_ = numberDo;
+    branch->setNumberBranches(numberDo);
+    CbcSubProblem * sub = new CbcSubProblem[numberDo];
+    int iProb = 0;
+    branch->subProblems_ = sub;
+    branch->numberRows_ = model_->solver()->getNumRows();
+    int iNode;
+    //OsiSolverInterface * solver = model_->solver();
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver);
+    assert (clpSolver);
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+    int numberColumns = simplex->numberColumns();
+    if ((model_->moreSpecialOptions()&33554432)==0) {
+      double * lowerBefore = CoinCopyOfArray(simplex->getColLower(),
+					     numberColumns);
+      double * upperBefore = CoinCopyOfArray(simplex->getColUpper(),
+					     numberColumns);
+      ClpNodeStuff * info = nodeInfo_;
+      double * weight = new double[numberNodes_];
+      int * whichNode = new int [numberNodes_];
+      // Sort
+      for (iNode = 0; iNode < numberNodes_; iNode++) {
+        if (iNode != whichSolution_) {
+	  double objectiveValue = info->nodeInfo_[iNode]->objectiveValue();
+	  double sumInfeasibilities = info->nodeInfo_[iNode]->sumInfeasibilities();
+	  int numberInfeasibilities = info->nodeInfo_[iNode]->numberInfeasibilities();
+	  double thisWeight = 0.0;
+#if 1
+	  // just closest
+	  thisWeight = 1.0e9 * numberInfeasibilities;
+	  thisWeight += sumInfeasibilities;
+	  thisWeight += 1.0e-7 * objectiveValue;
+	  // Try estimate
+	  thisWeight = info->nodeInfo_[iNode]->estimatedSolution();
+#else
+	  thisWeight = 1.0e-3 * numberInfeasibilities;
+	  thisWeight += 1.0e-5 * sumInfeasibilities;
+	  thisWeight += objectiveValue;
+#endif
+	  whichNode[iProb] = iNode;
+	  weight[iProb++] = thisWeight;
+        }
+      }
+      assert (iProb == numberDo);
+      CoinSort_2(weight, weight + numberDo, whichNode);
+      for (iProb = 0; iProb < numberDo; iProb++) {
+        iNode = whichNode[iProb];
+        ClpNode * node = info->nodeInfo_[iNode];
+        // move bounds
+        node->applyNode(simplex, 3);
+        // create subproblem
+        sub[iProb] = CbcSubProblem(clpSolver, lowerBefore, upperBefore,
+                                   node->statusArray(), node->depth());
+        sub[iProb].objectiveValue_ = node->objectiveValue();
+        sub[iProb].sumInfeasibilities_ = node->sumInfeasibilities();
+        sub[iProb].numberInfeasibilities_ = node->numberInfeasibilities();
+#ifdef CHECK_PATH
+        if (simplex->numberColumns() == numberColumns_Z) {
+	  bool onOptimal = true;
+	  const double * columnLower = simplex->columnLower();
+	  const double * columnUpper = simplex->columnUpper();
+	  for (int i = 0; i < numberColumns_Z; i++) {
+	    if (iNode == gotGoodNode_Z)
+	      printf("good %d %d %g %g\n", iNode, i, columnLower[i], columnUpper[i]);
+	    if (columnUpper[i] < debuggerSolution_Z[i] || columnLower[i] > debuggerSolution_Z[i] && simplex->isInteger(i)) {
+	      onOptimal = false;
+	      break;
+	    }
+	  }
+	  if (onOptimal) {
+	    printf("adding to node %x as %d - objs\n", this, iProb);
+	    for (int j = 0; j <= iProb; j++)
+	      printf("%d %g\n", j, sub[j].objectiveValue_);
+	  }
+        }
+#endif
+      }
+      delete [] weight;
+      delete [] whichNode;
+      const double * lower = solver->getColLower();
+      const double * upper = solver->getColUpper();
+      // restore bounds
+      for ( int j = 0; j < numberColumns; j++) {
+        if (lowerBefore[j] != lower[j])
+	  solver->setColLower(j, lowerBefore[j]);
+        if (upperBefore[j] != upper[j])
+	  solver->setColUpper(j, upperBefore[j]);
+      }
+      delete [] upperBefore;
+      delete [] lowerBefore;
+    } else {
+      // from diving
+      CbcSubProblem ** nodes = reinterpret_cast<CbcSubProblem **>
+	(model_->temporaryPointer());
+      assert (nodes);
+      int adjustDepth=info->depth_;
+      assert (numberDo);
+      numberNodes_=0;
+      for (iProb = 0; iProb < numberDo; iProb++) {
+	if ((nodes[iProb]->problemStatus_&2)==0) {
+	  // create subproblem (and swap way and/or make inactive)
+	  sub[numberNodes_].takeOver(*nodes[iProb],true);
+	  // but adjust depth
+	  sub[numberNodes_].depth_+=adjustDepth;
+	  numberNodes_++;
+	}
+	delete nodes[iProb];
+      }
+      branch->numberSubProblems_ = numberNodes_;
+      branch->numberSubLeft_ = numberNodes_;
+      branch->setNumberBranches(numberNodes_);
+      if (!numberNodes_) {
+	// infeasible
+	delete branch;
+	branch=NULL;
+      }
+      delete [] nodes;
+    }
+    return branch;
+}
+
+// Default Constructor
+CbcGeneralBranchingObject::CbcGeneralBranchingObject()
+        : CbcBranchingObject(),
+        subProblems_(NULL),
+        node_(NULL),
+        numberSubProblems_(0),
+        numberSubLeft_(0),
+        whichNode_(-1),
+        numberRows_(0)
+{
+    //  printf("CbcGeneral %x default constructor\n",this);
+}
+
+// Useful constructor
+CbcGeneralBranchingObject::CbcGeneralBranchingObject (CbcModel * model)
+        : CbcBranchingObject(model, -1, -1, 0.5),
+        subProblems_(NULL),
+        node_(NULL),
+        numberSubProblems_(0),
+        numberSubLeft_(0),
+        whichNode_(-1),
+        numberRows_(0)
+{
+    //printf("CbcGeneral %x useful constructor\n",this);
+}
+
+// Copy constructor
+CbcGeneralBranchingObject::CbcGeneralBranchingObject ( const CbcGeneralBranchingObject & rhs)
+        : CbcBranchingObject(rhs),
+        subProblems_(NULL),
+        node_(rhs.node_),
+        numberSubProblems_(rhs.numberSubProblems_),
+        numberSubLeft_(rhs.numberSubLeft_),
+        whichNode_(rhs.whichNode_),
+        numberRows_(rhs.numberRows_)
+{
+    abort();
+    if (numberSubProblems_) {
+        subProblems_ = new CbcSubProblem[numberSubProblems_];
+        for (int i = 0; i < numberSubProblems_; i++)
+            subProblems_[i] = rhs.subProblems_[i];
+    }
+}
+
+// Assignment operator
+CbcGeneralBranchingObject &
+CbcGeneralBranchingObject::operator=( const CbcGeneralBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        abort();
+        CbcBranchingObject::operator=(rhs);
+        delete [] subProblems_;
+        numberSubProblems_ = rhs.numberSubProblems_;
+        numberSubLeft_ = rhs.numberSubLeft_;
+        whichNode_ = rhs.whichNode_;
+        numberRows_ = rhs.numberRows_;
+        if (numberSubProblems_) {
+            subProblems_ = new CbcSubProblem[numberSubProblems_];
+            for (int i = 0; i < numberSubProblems_; i++)
+                subProblems_[i] = rhs.subProblems_[i];
+        } else {
+            subProblems_ = NULL;
+        }
+        node_ = rhs.node_;
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcGeneralBranchingObject::clone() const
+{
+    return (new CbcGeneralBranchingObject(*this));
+}
+
+
+// Destructor
+CbcGeneralBranchingObject::~CbcGeneralBranchingObject ()
+{
+    //printf("CbcGeneral %x destructor\n",this);
+    delete [] subProblems_;
+}
+bool doingDoneBranch = false;
+double
+CbcGeneralBranchingObject::branch()
+{
+    double cutoff = model_->getCutoff();
+    //printf("GenB %x whichNode %d numberLeft %d which %d\n",
+    // this,whichNode_,numberBranchesLeft(),branchIndex());
+    if (whichNode_ < 0) {
+        assert (node_);
+        bool applied = false;
+        while (numberBranchesLeft()) {
+            int which = branchIndex();
+            decrementNumberBranchesLeft();
+            CbcSubProblem * thisProb = subProblems_ + which;
+            if (thisProb->objectiveValue_ < cutoff) {
+                //printf("branch %x (sub %x) which now %d\n",this,
+                //     subProblems_,which);
+                OsiSolverInterface * solver = model_->solver();
+                thisProb->apply(solver);
+                OsiClpSolverInterface * clpSolver
+                = dynamic_cast<OsiClpSolverInterface *> (solver);
+                assert (clpSolver);
+                // Move status to basis
+                clpSolver->setWarmStart(NULL);
+                //ClpSimplex * simplex = clpSolver->getModelPtr();
+                node_->setObjectiveValue(thisProb->objectiveValue_);
+                node_->setSumInfeasibilities(thisProb->sumInfeasibilities_);
+                node_->setNumberUnsatisfied(thisProb->numberInfeasibilities_);
+                applied = true;
+                doingDoneBranch = true;
+                break;
+            } else if (numberBranchesLeft()) {
+                node_->nodeInfo()->branchedOn() ;
+            }
+        }
+        if (!applied) {
+            // no good one
+            node_->setObjectiveValue(cutoff + 1.0e20);
+            node_->setSumInfeasibilities(1.0);
+            node_->setNumberUnsatisfied(1);
+            assert (whichNode_ < 0);
+        }
+    } else {
+        decrementNumberBranchesLeft();
+        CbcSubProblem * thisProb = subProblems_ + whichNode_;
+        assert (thisProb->objectiveValue_ < cutoff);
+        OsiSolverInterface * solver = model_->solver();
+        thisProb->apply(solver);
+        //OsiClpSolverInterface * clpSolver
+        //= dynamic_cast<OsiClpSolverInterface *> (solver);
+        //assert (clpSolver);
+        // Move status to basis
+        //clpSolver->setWarmStart(NULL);
+    }
+    return 0.0;
+}
+/* Double checks in case node can change its mind!
+   Can change objective etc */
+void
+CbcGeneralBranchingObject::checkIsCutoff(double cutoff)
+{
+    assert (node_);
+    int first = branchIndex();
+    int last = first + numberBranchesLeft();
+    for (int which = first; which < last; which++) {
+        CbcSubProblem * thisProb = subProblems_ + which;
+        if (thisProb->objectiveValue_ < cutoff) {
+            node_->setObjectiveValue(thisProb->objectiveValue_);
+            node_->setSumInfeasibilities(thisProb->sumInfeasibilities_);
+            node_->setNumberUnsatisfied(thisProb->numberInfeasibilities_);
+            break;
+        }
+    }
+}
+// Print what would happen
+void
+CbcGeneralBranchingObject::print()
+{
+    //printf("CbcGeneralObject has %d subproblems\n",numberSubProblems_);
+}
+// Fill in current objective etc
+void
+CbcGeneralBranchingObject::state(double & objectiveValue,
+                                 double & sumInfeasibilities,
+                                 int & numberUnsatisfied, int which) const
+{
+    assert (which >= 0 && which < numberSubProblems_);
+    const CbcSubProblem * thisProb = subProblems_ + which;
+    objectiveValue = thisProb->objectiveValue_;
+    sumInfeasibilities = thisProb->sumInfeasibilities_;
+    numberUnsatisfied = thisProb->numberInfeasibilities_;
+}
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcGeneralBranchingObject::compareOriginalObject
+(const CbcBranchingObject* /*brObj*/) const
+{
+    throw("must implement");
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcGeneralBranchingObject::compareBranchingObject
+(const CbcBranchingObject* /*brObj*/, const bool /*replaceIfOverlap*/)
+{
+    throw("must implement");
+}
+
+// Default Constructor
+CbcOneGeneralBranchingObject::CbcOneGeneralBranchingObject()
+        : CbcBranchingObject(),
+        object_(NULL),
+        whichOne_(-1)
+{
+    //printf("CbcOneGeneral %x default constructor\n",this);
+}
+
+// Useful constructor
+CbcOneGeneralBranchingObject::CbcOneGeneralBranchingObject (CbcModel * model,
+        CbcGeneralBranchingObject * object,
+        int whichOne)
+        : CbcBranchingObject(model, -1, -1, 0.5),
+        object_(object),
+        whichOne_(whichOne)
+{
+    //printf("CbcOneGeneral %x useful constructor object %x %d left\n",this,
+    //	 object_,object_->numberSubLeft_);
+    numberBranches_ = 1;
+}
+
+// Copy constructor
+CbcOneGeneralBranchingObject::CbcOneGeneralBranchingObject ( const CbcOneGeneralBranchingObject & rhs)
+        : CbcBranchingObject(rhs),
+        object_(rhs.object_),
+        whichOne_(rhs.whichOne_)
+{
+}
+
+// Assignment operator
+CbcOneGeneralBranchingObject &
+CbcOneGeneralBranchingObject::operator=( const CbcOneGeneralBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        object_ = rhs.object_;
+        whichOne_ = rhs.whichOne_;
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcOneGeneralBranchingObject::clone() const
+{
+    return (new CbcOneGeneralBranchingObject(*this));
+}
+
+
+// Destructor
+CbcOneGeneralBranchingObject::~CbcOneGeneralBranchingObject ()
+{
+    //printf("CbcOneGeneral %x destructor object %x %d left\n",this,
+    // object_,object_->numberSubLeft_);
+    assert (object_->numberSubLeft_ > 0 &&
+            object_->numberSubLeft_ < 1000000);
+    if (!object_->decrementNumberLeft()) {
+        // printf("CbcGeneral %x yy destructor\n",object_);
+        delete object_;
+    }
+}
+double
+CbcOneGeneralBranchingObject::branch()
+{
+    assert (numberBranchesLeft());
+    decrementNumberBranchesLeft();
+    assert (!numberBranchesLeft());
+    object_->setWhichNode(whichOne_);
+    object_->branch();
+    return 0.0;
+}
+/* Double checks in case node can change its mind!
+   Can change objective etc */
+void
+CbcOneGeneralBranchingObject::checkIsCutoff(double /*cutoff*/)
+{
+    assert (numberBranchesLeft());
+}
+// Print what would happen
+void
+CbcOneGeneralBranchingObject::print()
+{
+    //printf("CbcOneGeneralObject has 1 subproblem\n");
+}
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcOneGeneralBranchingObject::compareOriginalObject
+(const CbcBranchingObject* /*brObj*/) const
+{
+    throw("must implement");
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcOneGeneralBranchingObject::compareBranchingObject
+(const CbcBranchingObject* /*brObj*/, const bool /*replaceIfOverlap*/)
+{
+    throw("must implement");
+}
+#endif
+
diff --git a/cbits/coin/CbcGeneralDepth.hpp b/cbits/coin/CbcGeneralDepth.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcGeneralDepth.hpp
@@ -0,0 +1,279 @@
+// $Id: CbcGeneralDepth.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#ifndef CbcGeneralDepth_H
+#define CbcGeneralDepth_H
+
+#include "CbcGeneral.hpp"
+#include "CbcBranchBase.hpp"
+#include "CbcSubProblem.hpp"
+
+#ifdef COIN_HAS_CLP
+
+/** Define a catch all class.
+    This will create a list of subproblems using partial evaluation
+*/
+#include "ClpSimplex.hpp"
+#include "ClpNode.hpp"
+
+
+class CbcGeneralDepth : public CbcGeneral {
+
+public:
+
+    // Default Constructor
+    CbcGeneralDepth ();
+
+    /** Useful constructor
+        Just needs to point to model.
+        Initial version does evaluation to depth N
+        This is stored in CbcModel but may be
+        better here
+    */
+    CbcGeneralDepth (CbcModel * model, int maximumDepth);
+
+    // Copy constructor
+    CbcGeneralDepth ( const CbcGeneralDepth &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcGeneralDepth & operator=( const CbcGeneralDepth& rhs);
+
+    // Destructor
+    ~CbcGeneralDepth ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /// This looks at solution and sets bounds to contain solution
+    virtual void feasibleRegion();
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+    /// Return maximum number of nodes
+    inline int maximumNodes() const {
+        return maximumNodes_;
+    }
+    /// Get maximum depth
+    inline int maximumDepth() const {
+        return maximumDepth_;
+    }
+    /// Set maximum depth
+    inline void setMaximumDepth(int value) {
+        maximumDepth_ = value;
+    }
+    /// Return number of nodes
+    inline int numberNodes() const {
+        return numberNodes_;
+    }
+    /// Get which solution
+    inline int whichSolution() const {
+        return whichSolution_;
+    }
+    /// Get ClpNode info
+    inline ClpNode * nodeInfo(int which) {
+        return nodeInfo_->nodeInfo_[which];
+    }
+
+    /// Redoes data when sequence numbers change
+    virtual void redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns);
+
+protected:
+    /// data
+    /// Maximum depth
+    int maximumDepth_;
+    /// Maximum nodes
+    int maximumNodes_;
+    /// Which node has solution (or -1)
+    mutable int whichSolution_;
+    /// Number of valid nodes (including whichSolution_)
+    mutable int numberNodes_;
+    /// For solving nodes
+    mutable ClpNodeStuff * nodeInfo_;
+};
+/** Branching object for general objects
+
+ */
+class CbcNode;
+class CbcGeneralBranchingObject : public CbcBranchingObject {
+
+public:
+
+    // Default Constructor
+    CbcGeneralBranchingObject ();
+
+    // Useful constructor
+    CbcGeneralBranchingObject (CbcModel * model);
+
+    // Copy constructor
+    CbcGeneralBranchingObject ( const CbcGeneralBranchingObject &);
+
+    // Assignment operator
+    CbcGeneralBranchingObject & operator=( const CbcGeneralBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~CbcGeneralBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch();
+    /** Double checks in case node can change its mind!
+        Can change objective etc */
+    virtual void checkIsCutoff(double cutoff);
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+    /// Fill in current objective etc
+    void state(double & objectiveValue, double & sumInfeasibilities,
+               int & numberUnsatisfied, int which) const;
+    /// Set CbcNode
+    inline void setNode(CbcNode * node) {
+        node_ = node;
+    }
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return GeneralDepthBranchObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+    /// Number of subproblems
+    inline int numberSubProblems() const {
+        return numberSubProblems_;
+    }
+    /// Decrement number left and return number
+    inline int decrementNumberLeft() {
+        numberSubLeft_--;
+        return numberSubLeft_;
+    }
+    /// Which node we want to use
+    inline int whichNode() const {
+        return whichNode_;
+    }
+    /// Set which node we want to use
+    inline void setWhichNode(int value) {
+        whichNode_ = value;
+    }
+    // Sub problem
+    const CbcSubProblem * subProblem(int which) const {
+        return subProblems_ + which;
+    }
+
+public:
+    /// data
+    // Sub problems
+    CbcSubProblem * subProblems_;
+    /// Node
+    CbcNode * node_;
+    /// Number of subproblems
+    int numberSubProblems_;
+    /// Number of subproblems left
+    int numberSubLeft_;
+    /// Which node we want to use (-1 for default)
+    int whichNode_;
+    /// Number of rows
+    int numberRows_;
+};
+/** Branching object for general objects - just one
+
+ */
+class CbcOneGeneralBranchingObject : public CbcBranchingObject {
+
+public:
+
+    // Default Constructor
+    CbcOneGeneralBranchingObject ();
+
+    // Useful constructor
+    CbcOneGeneralBranchingObject (CbcModel * model,
+                                  CbcGeneralBranchingObject * object,
+                                  int whichOne);
+
+    // Copy constructor
+    CbcOneGeneralBranchingObject ( const CbcOneGeneralBranchingObject &);
+
+    // Assignment operator
+    CbcOneGeneralBranchingObject & operator=( const CbcOneGeneralBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~CbcOneGeneralBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch();
+    /** Double checks in case node can change its mind!
+        Can change objective etc */
+    virtual void checkIsCutoff(double cutoff);
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return OneGeneralBranchingObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+public:
+    /// data
+    /// Object
+    CbcGeneralBranchingObject * object_;
+    /// Which one
+    int whichOne_;
+};
+#endif //COIN_HAS_CLP
+#endif
+
diff --git a/cbits/coin/CbcHeuristic.cpp b/cbits/coin/CbcHeuristic.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristic.cpp
@@ -0,0 +1,3025 @@
+/* $Id: CbcHeuristic.cpp 1888 2013-04-06 20:52:59Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcConfig.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+//#define PRINT_DEBUG
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcHeuristic.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcStrategy.hpp"
+#include "CglPreProcess.hpp"
+#include "CglGomory.hpp"
+#include "CglProbing.hpp"
+#include "OsiAuxInfo.hpp"
+#include "OsiPresolve.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcCutGenerator.hpp"
+//==============================================================================
+
+CbcHeuristicNode::CbcHeuristicNode(const CbcHeuristicNode& rhs)
+{
+    numObjects_ = rhs.numObjects_;
+    brObj_ = new CbcBranchingObject*[numObjects_];
+    for (int i = 0; i < numObjects_; ++i) {
+        brObj_[i] = rhs.brObj_[i]->clone();
+    }
+}
+
+void
+CbcHeuristicNodeList::gutsOfDelete()
+{
+    for (int i = (static_cast<int>(nodes_.size())) - 1; i >= 0; --i) {
+        delete nodes_[i];
+    }
+}
+
+void
+CbcHeuristicNodeList::gutsOfCopy(const CbcHeuristicNodeList& rhs)
+{
+    append(rhs);
+}
+
+CbcHeuristicNodeList::CbcHeuristicNodeList(const CbcHeuristicNodeList& rhs)
+{
+    gutsOfCopy(rhs);
+}
+
+CbcHeuristicNodeList& CbcHeuristicNodeList::operator=
+(const CbcHeuristicNodeList & rhs)
+{
+    if (this != &rhs) {
+        gutsOfDelete();
+        gutsOfCopy(rhs);
+    }
+    return *this;
+}
+
+CbcHeuristicNodeList::~CbcHeuristicNodeList()
+{
+    gutsOfDelete();
+}
+
+void
+CbcHeuristicNodeList::append(CbcHeuristicNode*& node)
+{
+    nodes_.push_back(node);
+    node = NULL;
+}
+
+void
+CbcHeuristicNodeList::append(const CbcHeuristicNodeList& nodes)
+{
+    nodes_.reserve(nodes_.size() + nodes.size());
+    for (int i = 0; i < nodes.size(); ++i) {
+        CbcHeuristicNode* node = new CbcHeuristicNode(*nodes.node(i));
+        append(node);
+    }
+}
+
+//==============================================================================
+#define DEFAULT_WHERE ((255-2-16)*(1+256))
+// Default Constructor
+CbcHeuristic::CbcHeuristic() :
+        model_(NULL),
+        when_(2),
+        numberNodes_(200),
+        feasibilityPumpOptions_(-1),
+        fractionSmall_(1.0),
+        heuristicName_("Unknown"),
+        howOften_(1),
+        decayFactor_(0.0),
+        switches_(0),
+        whereFrom_(DEFAULT_WHERE),
+        shallowDepth_(1),
+        howOftenShallow_(1),
+        numInvocationsInShallow_(0),
+        numInvocationsInDeep_(0),
+        lastRunDeep_(0),
+        numRuns_(0),
+        minDistanceToRun_(1),
+        runNodes_(),
+        numCouldRun_(0),
+        numberSolutionsFound_(0),
+        numberNodesDone_(0),
+        inputSolution_(NULL)
+{
+    // As CbcHeuristic virtual need to modify .cpp if above change
+}
+
+// Constructor from model
+CbcHeuristic::CbcHeuristic(CbcModel & model) :
+        model_(&model),
+        when_(2),
+        numberNodes_(200),
+        feasibilityPumpOptions_(-1),
+        fractionSmall_(1.0),
+        heuristicName_("Unknown"),
+        howOften_(1),
+        decayFactor_(0.0),
+        switches_(0),
+        whereFrom_(DEFAULT_WHERE),
+        shallowDepth_(1),
+        howOftenShallow_(1),
+        numInvocationsInShallow_(0),
+        numInvocationsInDeep_(0),
+        lastRunDeep_(0),
+        numRuns_(0),
+        minDistanceToRun_(1),
+        runNodes_(),
+        numCouldRun_(0),
+        numberSolutionsFound_(0),
+        numberNodesDone_(0),
+        inputSolution_(NULL)
+{}
+
+void
+CbcHeuristic::gutsOfCopy(const CbcHeuristic & rhs)
+{
+    model_ = rhs.model_;
+    when_ = rhs.when_;
+    numberNodes_ = rhs.numberNodes_;
+    feasibilityPumpOptions_ = rhs.feasibilityPumpOptions_;
+    fractionSmall_ = rhs.fractionSmall_;
+    randomNumberGenerator_ = rhs.randomNumberGenerator_;
+    heuristicName_ = rhs.heuristicName_;
+    howOften_ = rhs.howOften_;
+    decayFactor_ = rhs.decayFactor_;
+    switches_ = rhs.switches_;
+    whereFrom_ = rhs.whereFrom_;
+    shallowDepth_ = rhs.shallowDepth_;
+    howOftenShallow_ = rhs.howOftenShallow_;
+    numInvocationsInShallow_ = rhs.numInvocationsInShallow_;
+    numInvocationsInDeep_ = rhs.numInvocationsInDeep_;
+    lastRunDeep_ = rhs.lastRunDeep_;
+    numRuns_ = rhs.numRuns_;
+    numCouldRun_ = rhs.numCouldRun_;
+    minDistanceToRun_ = rhs.minDistanceToRun_;
+    runNodes_ = rhs.runNodes_;
+    numberSolutionsFound_ = rhs.numberSolutionsFound_;
+    numberNodesDone_ = rhs.numberNodesDone_;
+    if (rhs.inputSolution_) {
+        int numberColumns = model_->getNumCols();
+        setInputSolution(rhs.inputSolution_, rhs.inputSolution_[numberColumns]);
+    }
+}
+// Copy constructor
+CbcHeuristic::CbcHeuristic(const CbcHeuristic & rhs)
+{
+    inputSolution_ = NULL;
+    gutsOfCopy(rhs);
+}
+
+// Assignment operator
+CbcHeuristic &
+CbcHeuristic::operator=( const CbcHeuristic & rhs)
+{
+    if (this != &rhs) {
+        gutsOfDelete();
+        gutsOfCopy(rhs);
+    }
+    return *this;
+}
+
+void CbcHeurDebugNodes(CbcModel* model_)
+{
+    CbcNode* node = model_->currentNode();
+    CbcNodeInfo* nodeInfo = node->nodeInfo();
+    std::cout << "===============================================================\n";
+    while (nodeInfo) {
+        const CbcNode* node = nodeInfo->owner();
+        printf("nodeinfo: node %i\n", nodeInfo->nodeNumber());
+        {
+            const CbcIntegerBranchingObject* brPrint =
+                dynamic_cast<const CbcIntegerBranchingObject*>(nodeInfo->parentBranch());
+            if (!brPrint) {
+                printf("    parentBranch: NULL\n");
+            } else {
+                const double* downBounds = brPrint->downBounds();
+                const double* upBounds = brPrint->upBounds();
+                int variable = brPrint->variable();
+                int way = brPrint->way();
+                printf("   parentBranch: var %i downBd [%i,%i] upBd [%i,%i] way %i\n",
+                       variable, static_cast<int>(downBounds[0]), static_cast<int>(downBounds[1]),
+                       static_cast<int>(upBounds[0]), static_cast<int>(upBounds[1]), way);
+            }
+        }
+        if (! node) {
+            printf("    owner: NULL\n");
+        } else {
+            printf("    owner: node %i depth %i onTree %i active %i",
+                   node->nodeNumber(), node->depth(), node->onTree(), node->active());
+            const OsiBranchingObject* osibr =
+                nodeInfo->owner()->branchingObject();
+            const CbcBranchingObject* cbcbr =
+                dynamic_cast<const CbcBranchingObject*>(osibr);
+            const CbcIntegerBranchingObject* brPrint =
+                dynamic_cast<const CbcIntegerBranchingObject*>(cbcbr);
+            if (!brPrint) {
+                printf("        ownerBranch: NULL\n");
+            } else {
+                const double* downBounds = brPrint->downBounds();
+                const double* upBounds = brPrint->upBounds();
+                int variable = brPrint->variable();
+                int way = brPrint->way();
+                printf("        ownerbranch: var %i downBd [%i,%i] upBd [%i,%i] way %i\n",
+                       variable, static_cast<int>(downBounds[0]), static_cast<int>(downBounds[1]),
+                       static_cast<int>(upBounds[0]), static_cast<int>(upBounds[1]), way);
+            }
+        }
+        nodeInfo = nodeInfo->parent();
+    }
+}
+
+void
+CbcHeuristic::debugNodes()
+{
+    CbcHeurDebugNodes(model_);
+}
+
+void
+CbcHeuristic::printDistanceToNodes()
+{
+    const CbcNode* currentNode = model_->currentNode();
+    if (currentNode != NULL) {
+        CbcHeuristicNode* nodeDesc = new CbcHeuristicNode(*model_);
+        for (int i = runNodes_.size() - 1; i >= 0; --i) {
+            nodeDesc->distance(runNodes_.node(i));
+        }
+        runNodes_.append(nodeDesc);
+    }
+}
+
+bool
+CbcHeuristic::shouldHeurRun(int whereFrom)
+{
+    assert (whereFrom >= 0 && whereFrom < 16);
+    // take off 8 (code - likes new solution)
+    whereFrom &= 7;
+    if ((whereFrom_&(1 << whereFrom)) == 0)
+        return false;
+    // No longer used for original purpose - so use for ever run at all JJF
+#ifndef JJF_ONE
+    // Don't run if hot start
+    if (model_ && model_->hotstartSolution())
+        return false;
+    else
+        return true;
+#else
+#ifdef JJF_ZERO
+    const CbcNode* currentNode = model_->currentNode();
+    if (currentNode == NULL) {
+        return false;
+    }
+
+    debugNodes();
+//   return false;
+
+    const int depth = currentNode->depth();
+#else
+    int depth = model_->currentDepth();
+#endif
+
+    const int nodeCount = model_->getNodeCount();  // FIXME: check that this is
+    // correct in parallel
+
+    if (nodeCount == 0 || depth <= shallowDepth_) {
+        // what to do when we are in the shallow part of the tree
+        if (model_->getCurrentPassNumber() == 1) {
+            // first time in the node...
+            numInvocationsInShallow_ = 0;
+        }
+        ++numInvocationsInShallow_;
+        // Very large howOftenShallow_ will give the original test:
+        // (model_->getCurrentPassNumber() != 1)
+        //    if ((numInvocationsInShallow_ % howOftenShallow_) != 1) {
+        if ((numInvocationsInShallow_ % howOftenShallow_) != 0) {
+            return false;
+        }
+        // LL: should we save these nodes in the list of nodes where the heur was
+        // LL: run?
+#ifndef JJF_ONE
+        if (currentNode != NULL) {
+            // Get where we are and create the appropriate CbcHeuristicNode object
+            CbcHeuristicNode* nodeDesc = new CbcHeuristicNode(*model_);
+            runNodes_.append(nodeDesc);
+        }
+#endif
+    } else {
+        // deeper in the tree
+        if (model_->getCurrentPassNumber() == 1) {
+            // first time in the node...
+            ++numInvocationsInDeep_;
+        }
+        if (numInvocationsInDeep_ - lastRunDeep_ < howOften_) {
+            return false;
+        }
+        if (model_->getCurrentPassNumber() != 1) {
+            // Run the heuristic only when first entering the node.
+            // LL: I don't think this is right. It should run just before strong
+            // LL: branching, I believe.
+            return false;
+        }
+        // Get where we are and create the appropriate CbcHeuristicNode object
+        CbcHeuristicNode* nodeDesc = new CbcHeuristicNode(*model_);
+        //#ifdef PRINT_DEBUG
+#ifndef JJF_ONE
+        const double minDistanceToRun = 1.5 * log((double)depth) / log((double)2);
+#else
+    const double minDistanceToRun = minDistanceToRun_;
+#endif
+#ifdef PRINT_DEBUG
+        double minDistance = nodeDesc->minDistance(runNodes_);
+        std::cout << "minDistance = " << minDistance
+                  << ", minDistanceToRun = " << minDistanceToRun << std::endl;
+#endif
+        if (nodeDesc->minDistanceIsSmall(runNodes_, minDistanceToRun)) {
+            delete nodeDesc;
+            return false;
+        }
+        runNodes_.append(nodeDesc);
+        lastRunDeep_ = numInvocationsInDeep_;
+        //    ++lastRunDeep_;
+    }
+    ++numRuns_;
+    return true;
+#endif
+}
+
+bool
+CbcHeuristic::shouldHeurRun_randomChoice()
+{
+    if (!when_)
+        return false;
+    int depth = model_->currentDepth();
+    // when_ -999 is special marker to force to run
+    if (depth != 0 && when_ != -999) {
+        const double numerator = depth * depth;
+        const double denominator = exp(depth * log(2.0));
+        double probability = numerator / denominator;
+        double randomNumber = randomNumberGenerator_.randomDouble();
+        int when = when_ % 100;
+        if (when > 2 && when < 8) {
+            /* JJF adjustments
+            3 only at root and if no solution
+            4 only at root and if this heuristic has not got solution
+            5 as 3 but decay more
+            6 decay
+            7 run up to 2 times if solution found 4 otherwise
+            */
+            switch (when) {
+            case 3:
+            default:
+                if (model_->bestSolution())
+                    probability = -1.0;
+                break;
+            case 4:
+                if (numberSolutionsFound_)
+                    probability = -1.0;
+                break;
+            case 5:
+                assert (decayFactor_);
+                if (model_->bestSolution()) {
+                    probability = -1.0;
+                } else if (numCouldRun_ > 1000) {
+                    decayFactor_ *= 0.99;
+                    probability *= decayFactor_;
+                }
+                break;
+            case 6:
+                if (depth >= 3) {
+                    if ((numCouldRun_ % howOften_) == 0 &&
+                            numberSolutionsFound_*howOften_ < numCouldRun_) {
+#ifdef COIN_DEVELOP
+                        int old = howOften_;
+#endif
+                        howOften_ = CoinMin(CoinMax(static_cast<int> (howOften_ * 1.1), howOften_ + 1), 1000000);
+#ifdef COIN_DEVELOP
+                        printf("Howoften changed from %d to %d for %s\n",
+                               old, howOften_, heuristicName_.c_str());
+#endif
+                    }
+                    probability = 1.0 / howOften_;
+                    if (model_->bestSolution())
+                        probability *= 0.5;
+                }
+                break;
+            case 7:
+                if ((model_->bestSolution() && numRuns_ >= 2) || numRuns_ >= 4)
+                    probability = -1.0;
+                break;
+            }
+        }
+        if (randomNumber > probability)
+            return false;
+
+        if (model_->getCurrentPassNumber() > 1)
+            return false;
+#ifdef COIN_DEVELOP
+        printf("Running %s, random %g probability %g\n",
+               heuristicName_.c_str(), randomNumber, probability);
+#endif
+    } else {
+#ifdef COIN_DEVELOP
+        printf("Running %s, depth %d when %d\n",
+               heuristicName_.c_str(), depth, when_);
+#endif
+    }
+    ++numRuns_;
+    return true;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristic::resetModel(CbcModel * model)
+{
+    model_ = model;
+}
+// Set seed
+void
+CbcHeuristic::setSeed(int value)
+{
+    if (value==0) {
+      double time = fabs(CoinGetTimeOfDay());
+      while (time>=COIN_INT_MAX)
+	time *= 0.5;
+      value = static_cast<int>(time);
+      char printArray[100];
+      sprintf(printArray, "using time of day seed was changed from %d to %d",
+	      randomNumberGenerator_.getSeed(), value);
+      if (model_)
+	model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+	  << printArray
+	  << CoinMessageEol;
+    }
+    randomNumberGenerator_.setSeed(value);
+}
+// Get seed
+int
+CbcHeuristic::getSeed() const
+{
+  return randomNumberGenerator_.getSeed();
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristic::generateCpp( FILE * fp, const char * heuristic)
+{
+    // hard coded as CbcHeuristic virtual
+    if (when_ != 2)
+        fprintf(fp, "3  %s.setWhen(%d);\n", heuristic, when_);
+    else
+        fprintf(fp, "4  %s.setWhen(%d);\n", heuristic, when_);
+    if (numberNodes_ != 200)
+        fprintf(fp, "3  %s.setNumberNodes(%d);\n", heuristic, numberNodes_);
+    else
+        fprintf(fp, "4  %s.setNumberNodes(%d);\n", heuristic, numberNodes_);
+    if (feasibilityPumpOptions_ != -1)
+        fprintf(fp, "3  %s.setFeasibilityPumpOptions(%d);\n", heuristic, feasibilityPumpOptions_);
+    else
+        fprintf(fp, "4  %s.setFeasibilityPumpOptions(%d);\n", heuristic, feasibilityPumpOptions_);
+    if (fractionSmall_ != 1.0)
+        fprintf(fp, "3  %s.setFractionSmall(%g);\n", heuristic, fractionSmall_);
+    else
+        fprintf(fp, "4  %s.setFractionSmall(%g);\n", heuristic, fractionSmall_);
+    if (heuristicName_ != "Unknown")
+        fprintf(fp, "3  %s.setHeuristicName(\"%s\");\n",
+                heuristic, heuristicName_.c_str()) ;
+    else
+        fprintf(fp, "4  %s.setHeuristicName(\"%s\");\n",
+                heuristic, heuristicName_.c_str()) ;
+    if (decayFactor_ != 0.0)
+        fprintf(fp, "3  %s.setDecayFactor(%g);\n", heuristic, decayFactor_);
+    else
+        fprintf(fp, "4  %s.setDecayFactor(%g);\n", heuristic, decayFactor_);
+    if (switches_ != 0)
+        fprintf(fp, "3  %s.setSwitches(%d);\n", heuristic, switches_);
+    else
+        fprintf(fp, "4  %s.setSwitches(%d);\n", heuristic, switches_);
+    if (whereFrom_ != DEFAULT_WHERE)
+        fprintf(fp, "3  %s.setWhereFrom(%d);\n", heuristic, whereFrom_);
+    else
+        fprintf(fp, "4  %s.setWhereFrom(%d);\n", heuristic, whereFrom_);
+    if (shallowDepth_ != 1)
+        fprintf(fp, "3  %s.setShallowDepth(%d);\n", heuristic, shallowDepth_);
+    else
+        fprintf(fp, "4  %s.setShallowDepth(%d);\n", heuristic, shallowDepth_);
+    if (howOftenShallow_ != 1)
+        fprintf(fp, "3  %s.setHowOftenShallow(%d);\n", heuristic, howOftenShallow_);
+    else
+        fprintf(fp, "4  %s.setHowOftenShallow(%d);\n", heuristic, howOftenShallow_);
+    if (minDistanceToRun_ != 1)
+        fprintf(fp, "3  %s.setMinDistanceToRun(%d);\n", heuristic, minDistanceToRun_);
+    else
+        fprintf(fp, "4  %s.setMinDistanceToRun(%d);\n", heuristic, minDistanceToRun_);
+}
+// Destructor
+CbcHeuristic::~CbcHeuristic ()
+{
+    delete [] inputSolution_;
+}
+
+// update model
+void CbcHeuristic::setModel(CbcModel * model)
+{
+    model_ = model;
+}
+/* Clone but ..
+   type 0 clone solver, 1 clone continuous solver
+   Add 2 to say without integer variables which are at low priority
+   Add 4 to say quite likely infeasible so give up easily.*/
+OsiSolverInterface *
+CbcHeuristic::cloneBut(int type)
+{
+    OsiSolverInterface * solver;
+    if ((type&1) == 0 || !model_->continuousSolver())
+        solver = model_->solver()->clone();
+    else
+        solver = model_->continuousSolver()->clone();
+#ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver);
+#endif
+    if ((type&2) != 0) {
+        int n = model_->numberObjects();
+        int priority = model_->continuousPriority();
+        if (priority < COIN_INT_MAX) {
+            for (int i = 0; i < n; i++) {
+                const OsiObject * obj = model_->object(i);
+                const CbcSimpleInteger * thisOne =
+                    dynamic_cast <const CbcSimpleInteger *> (obj);
+                if (thisOne) {
+                    int iColumn = thisOne->columnNumber();
+                    if (thisOne->priority() >= priority)
+                        solver->setContinuous(iColumn);
+                }
+            }
+        }
+#ifdef COIN_HAS_CLP
+        if (clpSolver) {
+            for (int i = 0; i < n; i++) {
+                const OsiObject * obj = model_->object(i);
+                const CbcSimpleInteger * thisOne =
+                    dynamic_cast <const CbcSimpleInteger *> (obj);
+                if (thisOne) {
+                    int iColumn = thisOne->columnNumber();
+                    if (clpSolver->isOptionalInteger(iColumn))
+                        clpSolver->setContinuous(iColumn);
+                }
+            }
+        }
+#endif
+    }
+#ifdef COIN_HAS_CLP
+    if ((type&4) != 0 && clpSolver) {
+        int options = clpSolver->getModelPtr()->moreSpecialOptions();
+        clpSolver->getModelPtr()->setMoreSpecialOptions(options | 64);
+    }
+#endif
+    return solver;
+}
+// Whether to exit at once on gap
+bool
+CbcHeuristic::exitNow(double bestObjective) const
+{
+    if ((switches_&2048) != 0) {
+        // exit may be forced - but unset for next time
+        switches_ &= ~2048;
+        if ((switches_&1024) != 0)
+            return true;
+    } else if ((switches_&1) == 0) {
+        return false;
+    }
+    // See if can stop on gap
+    OsiSolverInterface * solver = model_->solver();
+    double bestPossibleObjective = solver->getObjValue() * solver->getObjSense();
+    double absGap = CoinMax(model_->getAllowableGap(),
+                            model_->getHeuristicGap());
+    double fracGap = CoinMax(model_->getAllowableFractionGap(),
+                             model_->getHeuristicFractionGap());
+    double testGap = CoinMax(absGap, fracGap *
+                             CoinMax(fabs(bestObjective),
+                                     fabs(bestPossibleObjective)));
+
+    if (bestObjective - bestPossibleObjective < testGap
+            && model_->getCutoffIncrement() >= 0.0) {
+        return true;
+    } else {
+        return false;
+    }
+}
+#ifdef HISTORY_STATISTICS
+extern bool getHistoryStatistics_;
+#endif
+static double sizeRatio(int numberRowsNow, int numberColumnsNow,
+                        int numberRowsStart, int numberColumnsStart)
+{
+    double valueNow;
+    if (numberRowsNow*10 > numberColumnsNow || numberColumnsNow < 200) {
+        valueNow = 2 * numberRowsNow + numberColumnsNow;
+    } else {
+        // long and thin - rows are more important
+        if (numberRowsNow*40 > numberColumnsNow)
+            valueNow = 10 * numberRowsNow + numberColumnsNow;
+        else
+            valueNow = 200 * numberRowsNow + numberColumnsNow;
+    }
+    double valueStart;
+    if (numberRowsStart*10 > numberColumnsStart || numberColumnsStart < 200) {
+        valueStart = 2 * numberRowsStart + numberColumnsStart;
+    } else {
+        // long and thin - rows are more important
+        if (numberRowsStart*40 > numberColumnsStart)
+            valueStart = 10 * numberRowsStart + numberColumnsStart;
+        else
+            valueStart = 200 * numberRowsStart + numberColumnsStart;
+    }
+    //printf("sizeProblem Now %g, %d rows, %d columns\nsizeProblem Start %g, %d rows, %d columns\n",
+    // valueNow,numberRowsNow,numberColumnsNow,
+    // valueStart,numberRowsStart,numberColumnsStart);
+    if (10*numberRowsNow < 8*numberRowsStart || 10*numberColumnsNow < 7*numberColumnsStart)
+        return valueNow / valueStart;
+    else if (10*numberRowsNow < 9*numberRowsStart)
+        return 1.1*(valueNow / valueStart);
+    else if (numberRowsNow < numberRowsStart)
+        return 1.5*(valueNow / valueStart);
+    else
+        return 2.0*(valueNow / valueStart);
+}
+
+
+// Do mini branch and bound (return 1 if solution)
+int
+CbcHeuristic::smallBranchAndBound(OsiSolverInterface * solver, int numberNodes,
+                                  double * newSolution, double & newSolutionValue,
+                                  double cutoff, std::string name) const
+{
+    // size before
+    int shiftRows = 0;
+    if (numberNodes < 0)
+        shiftRows = solver->getNumRows() - numberNodes_;
+    int numberRowsStart = solver->getNumRows() - shiftRows;
+    int numberColumnsStart = solver->getNumCols();
+#ifdef CLP_INVESTIGATE
+    printf("%s has %d rows, %d columns\n",
+           name.c_str(), solver->getNumRows(), solver->getNumCols());
+#endif
+    // Use this fraction
+    double fractionSmall = fractionSmall_;
+    double before = 2 * numberRowsStart + numberColumnsStart;
+    if (before > 40000.0) {
+        // fairly large - be more conservative
+        double multiplier = 1.0 - 0.3 * CoinMin(100000.0, before - 40000.0) / 100000.0;
+        if (multiplier < 1.0) {
+            fractionSmall *= multiplier;
+#ifdef CLP_INVESTIGATE
+            printf("changing fractionSmall from %g to %g for %s\n",
+                   fractionSmall_, fractionSmall, name.c_str());
+#endif
+        }
+    }
+#ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (solver);
+    if (osiclp && (osiclp->specialOptions()&65536) == 0) {
+        // go faster stripes
+        if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) {
+            osiclp->setupForRepeatedUse(2, 0);
+        } else {
+            osiclp->setupForRepeatedUse(0, 0);
+        }
+        // Turn this off if you get problems
+        // Used to be automatically set
+        osiclp->setSpecialOptions(osiclp->specialOptions() | (128 + 64 - 128));
+        ClpSimplex * lpSolver = osiclp->getModelPtr();
+        lpSolver->setSpecialOptions(lpSolver->specialOptions() | 0x01000000); // say is Cbc (and in branch and bound)
+        lpSolver->setSpecialOptions(lpSolver->specialOptions() |
+                                    (/*16384+*/4096 + 512 + 128));
+    }
+#endif
+#ifdef HISTORY_STATISTICS
+    getHistoryStatistics_ = false;
+#endif
+#ifdef COIN_DEVELOP
+    int status = 0;
+#endif
+    int logLevel = model_->logLevel();
+#define LEN_PRINT 250
+    char generalPrint[LEN_PRINT];
+    // Do presolve to see if possible
+    int numberColumns = solver->getNumCols();
+    char * reset = NULL;
+    int returnCode = 1;
+    int saveModelOptions = model_->specialOptions();
+    //assert ((saveModelOptions&2048) == 0);
+    model_->setSpecialOptions(saveModelOptions | 2048);
+    {
+        int saveLogLevel = solver->messageHandler()->logLevel();
+        if (saveLogLevel == 1) 
+            solver->messageHandler()->setLogLevel(0);
+        OsiPresolve * pinfo = new OsiPresolve();
+        int presolveActions = 0;
+        // Allow dual stuff on integers
+        presolveActions = 1;
+        // Do not allow all +1 to be tampered with
+        //if (allPlusOnes)
+        //presolveActions |= 2;
+        // allow transfer of costs
+        // presolveActions |= 4;
+        pinfo->setPresolveActions(presolveActions);
+        OsiSolverInterface * presolvedModel = pinfo->presolvedModel(*solver, 1.0e-8, true, 2);
+        delete pinfo;
+        // see if too big
+
+        if (presolvedModel) {
+            int afterRows = presolvedModel->getNumRows();
+            int afterCols = presolvedModel->getNumCols();
+            //#define COIN_DEVELOP
+#ifdef COIN_DEVELOP_z
+            if (numberNodes < 0) {
+                solver->writeMpsNative("before.mps", NULL, NULL, 2, 1);
+                presolvedModel->writeMpsNative("after1.mps", NULL, NULL, 2, 1);
+            }
+#endif
+            delete presolvedModel;
+            double ratio = sizeRatio(afterRows - shiftRows, afterCols,
+                                     numberRowsStart, numberColumnsStart);
+            double after = 2 * afterRows + afterCols;
+            if (ratio > fractionSmall && after > 300 && numberNodes >= 0) {
+                // Need code to try again to compress further using used
+                const int * used =  model_->usedInSolution();
+                int maxUsed = 0;
+                int iColumn;
+                const double * lower = solver->getColLower();
+                const double * upper = solver->getColUpper();
+                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (upper[iColumn] > lower[iColumn]) {
+                        if (solver->isBinary(iColumn))
+                            maxUsed = CoinMax(maxUsed, used[iColumn]);
+                    }
+                }
+                if (maxUsed) {
+                    reset = new char [numberColumns];
+                    int nFix = 0;
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        reset[iColumn] = 0;
+                        if (upper[iColumn] > lower[iColumn]) {
+                            if (solver->isBinary(iColumn) && used[iColumn] == maxUsed) {
+                                bool setValue = true;
+                                if (maxUsed == 1) {
+                                    double randomNumber = randomNumberGenerator_.randomDouble();
+                                    if (randomNumber > 0.3)
+                                        setValue = false;
+                                }
+                                if (setValue) {
+                                    reset[iColumn] = 1;
+                                    solver->setColLower(iColumn, 1.0);
+                                    nFix++;
+                                }
+                            }
+                        }
+                    }
+                    pinfo = new OsiPresolve();
+                    presolveActions = 0;
+                    // Allow dual stuff on integers
+                    presolveActions = 1;
+                    // Do not allow all +1 to be tampered with
+                    //if (allPlusOnes)
+                    //presolveActions |= 2;
+                    // allow transfer of costs
+                    // presolveActions |= 4;
+                    pinfo->setPresolveActions(presolveActions);
+                    presolvedModel = pinfo->presolvedModel(*solver, 1.0e-8, true, 2);
+                    delete pinfo;
+                    if (presolvedModel) {
+                        // see if too big
+                        int afterRows2 = presolvedModel->getNumRows();
+                        int afterCols2 = presolvedModel->getNumCols();
+                        delete presolvedModel;
+                        double ratio = sizeRatio(afterRows2 - shiftRows, afterCols2,
+                                                 numberRowsStart, numberColumnsStart);
+                        double after = 2 * afterRows2 + afterCols2;
+                        if (ratio > fractionSmall && (after > 300 || numberNodes < 0)) {
+                            sprintf(generalPrint, "Full problem %d rows %d columns, reduced to %d rows %d columns - %d fixed gives %d, %d - still too large",
+                                    solver->getNumRows(), solver->getNumCols(),
+                                    afterRows, afterCols, nFix, afterRows2, afterCols2);
+                            // If much too big - give up
+                            if (ratio > 0.75)
+                                returnCode = -1;
+                        } else {
+                            sprintf(generalPrint, "Full problem %d rows %d columns, reduced to %d rows %d columns - %d fixed gives %d, %d - ok now",
+                                    solver->getNumRows(), solver->getNumCols(),
+                                    afterRows, afterCols, nFix, afterRows2, afterCols2);
+                        }
+                        model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                        << generalPrint
+                        << CoinMessageEol;
+                    } else {
+                        returnCode = 2; // infeasible
+                    }
+                }
+            } else if (ratio > fractionSmall && after > 300 && numberNodes >=0) {
+                returnCode = -1;
+            }
+        } else {
+            returnCode = 2; // infeasible
+        }
+        solver->messageHandler()->setLogLevel(saveLogLevel);
+    }
+    if (returnCode == 2 || returnCode == -1) {
+        model_->setSpecialOptions(saveModelOptions);
+        delete [] reset;
+#ifdef HISTORY_STATISTICS
+        getHistoryStatistics_ = true;
+#endif
+        //printf("small no good\n");
+        return returnCode;
+    }
+    // Reduce printout
+    bool takeHint;
+    OsiHintStrength strength;
+    solver->getHintParam(OsiDoReducePrint, takeHint, strength);
+    solver->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+    solver->setHintParam(OsiDoPresolveInInitial, false, OsiHintTry);
+    double signedCutoff = cutoff*solver->getObjSense();
+    solver->setDblParam(OsiDualObjectiveLimit, signedCutoff);
+    solver->initialSolve();
+    if (solver->isProvenOptimal()) {
+        CglPreProcess process;
+	OsiSolverInterface * solver2 = NULL;
+	if ((model_->moreSpecialOptions()&65536)!=0)
+	  process.setOptions(2+4+8); // no cuts
+	/* Do not try and produce equality cliques and
+	   do up to 2 passes (normally) 5 if restart */
+	int numberPasses = 2;
+	if (numberNodes < 0) {
+	  numberPasses = 5;
+	  // Say some rows cuts
+	  int numberRows = solver->getNumRows();
+	  if (numberNodes_ < numberRows && true /* think */) {
+	    char * type = new char[numberRows];
+	    memset(type, 0, numberNodes_);
+	    memset(type + numberNodes_, 1, numberRows - numberNodes_);
+	    process.passInRowTypes(type, numberRows);
+	    delete [] type;
+	  }
+	}
+	if (logLevel <= 1)
+	  process.messageHandler()->setLogLevel(0);
+	if (!solver->defaultHandler()&&
+	    solver->messageHandler()->logLevel(0)!=-1000)
+	  process.passInMessageHandler(solver->messageHandler());
+	solver2 = process.preProcessNonDefault(*solver, false,
+					       numberPasses);
+	  if (!solver2) {
+            if (logLevel > 1)
+	      printf("Pre-processing says infeasible\n");
+            returnCode = 2; // so will be infeasible
+	  } else {
+#ifdef COIN_DEVELOP_z
+            if (numberNodes < 0) {
+	      solver2->writeMpsNative("after2.mps", NULL, NULL, 2, 1);
+            }
+#endif
+            // see if too big
+            double ratio = sizeRatio(solver2->getNumRows() - shiftRows, solver2->getNumCols(),
+                                     numberRowsStart, numberColumnsStart);
+            double after = 2 * solver2->getNumRows() + solver2->getNumCols();
+            if (ratio > fractionSmall && (after > 300 || numberNodes < 0)) {
+                sprintf(generalPrint, "Full problem %d rows %d columns, reduced to %d rows %d columns - too large",
+                        solver->getNumRows(), solver->getNumCols(),
+                        solver2->getNumRows(), solver2->getNumCols());
+                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                << generalPrint
+                << CoinMessageEol;
+                returnCode = -1;
+                //printf("small no good2\n");
+            } else {
+                sprintf(generalPrint, "Full problem %d rows %d columns, reduced to %d rows %d columns",
+                        solver->getNumRows(), solver->getNumCols(),
+                        solver2->getNumRows(), solver2->getNumCols());
+                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                << generalPrint
+                << CoinMessageEol;
+            }
+            if (returnCode == 1) {
+                solver2->resolve();
+                CbcModel model(*solver2);
+		// move seed across
+		model.randomNumberGenerator()->setSeed(model_->randomNumberGenerator()->getSeed());
+                if (numberNodes >= 0) {
+                    // normal
+                    model.setSpecialOptions(saveModelOptions | 2048);
+                    if (logLevel <= 1 && feasibilityPumpOptions_ != -3)
+                        model.setLogLevel(0);
+                    else
+                        model.setLogLevel(logLevel);
+                    // No small fathoming
+                    model.setFastNodeDepth(-1);
+                    model.setCutoff(signedCutoff);
+		    model.setStrongStrategy(0);
+		    // Don't do if original fraction > 1.0 and too large
+		    if (fractionSmall_>1.0 && fractionSmall_ < 1000000.0) {
+		      /* 1.4 means -1 nodes if >.4
+			 2.4 means -1 nodes if >.5 and 0 otherwise
+			 3.4 means -1 nodes if >.6 and 0 or 5
+			 4.4 means -1 nodes if >.7 and 0, 5 or 10
+		      */
+		      double fraction = fractionSmall_-floor(fractionSmall_);
+		      if (ratio>fraction) {
+			int type = static_cast<int>(floor(fractionSmall_*0.1));
+			int over = static_cast<int>(ceil(ratio-fraction));
+			int maxNodes[]={-1,0,5,10};
+			if (type>over)
+			  numberNodes=maxNodes[type-over];
+			else
+			  numberNodes=-1;
+		      }
+		    }
+                    model.setMaximumNodes(numberNodes);
+                    model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+		    if ((saveModelOptions&2048) == 0)
+		      model.setMoreSpecialOptions(model_->moreSpecialOptions());
+		    // off conflict analysis
+		    model.setMoreSpecialOptions(model.moreSpecialOptions()&~4194304);
+		    
+                    // Lightweight
+                    CbcStrategyDefaultSubTree strategy(model_, 1, 5, 1, 0);
+                    model.setStrategy(strategy);
+                    model.solver()->setIntParam(OsiMaxNumIterationHotStart, 10);
+                    model.setMaximumCutPassesAtRoot(CoinMin(20, CoinAbs(model_->getMaximumCutPassesAtRoot())));
+                    model.setMaximumCutPasses(CoinMin(10, model_->getMaximumCutPasses()));
+                } else {
+                    model.setSpecialOptions(saveModelOptions);
+                    model_->messageHandler()->message(CBC_RESTART, model_->messages())
+                    << solver2->getNumRows() << solver2->getNumCols()
+                    << CoinMessageEol;
+                    // going for full search and copy across more stuff
+                    model.gutsOfCopy(*model_, 2);
+		    assert (!model_->heuristicModel());
+		    model_->setHeuristicModel(&model);
+                    for (int i = 0; i < model.numberCutGenerators(); i++) {
+		        CbcCutGenerator * generator = model.cutGenerator(i);
+			CglGomory * gomory = dynamic_cast<CglGomory *>
+			  (generator->generator());
+			if (gomory&&gomory->originalSolver()) 
+			  gomory->passInOriginalSolver(model.solver());
+                        generator->setTiming(true);
+                        // Turn on if was turned on
+                        int iOften = model_->cutGenerator(i)->howOften();
+#ifdef CLP_INVESTIGATE
+                        printf("Gen %d often %d %d\n",
+                               i, generator->howOften(),
+                               iOften);
+#endif
+                        if (iOften > 0)
+                            generator->setHowOften(iOften % 1000000);
+                        if (model_->cutGenerator(i)->howOftenInSub() == -200)
+                            generator->setHowOften(-100);
+                    }
+                    model.setCutoff(signedCutoff);
+                    // make sure can't do nested search! but allow heuristics
+                    model.setSpecialOptions((model.specialOptions()&(~(512 + 2048))) | 1024);
+                    bool takeHint;
+                    OsiHintStrength strength;
+                    // Switch off printing if asked to
+                    model_->solver()->getHintParam(OsiDoReducePrint, takeHint, strength);
+                    model.solver()->setHintParam(OsiDoReducePrint, takeHint, strength);
+		    // no cut generators if none in parent
+                    CbcStrategyDefault 
+		      strategy(model_->numberCutGenerators() ? 1 : -1, 
+			       model_->numberStrong(),
+			       model_->numberBeforeTrust());
+                    // Set up pre-processing - no
+                    strategy.setupPreProcessing(0); // was (4);
+                    model.setStrategy(strategy);
+                    //model.solver()->writeMps("crunched");
+                    int numberCuts = process.cuts().sizeRowCuts();
+                    if (numberCuts) {
+                        // add in cuts
+                        CglStored cuts = process.cuts();
+                        model.addCutGenerator(&cuts, 1, "Stored from first");
+			model.cutGenerator(model.numberCutGenerators()-1)->setGlobalCuts(true);
+                    }
+                }
+                // Do search
+                if (logLevel > 1)
+                    model_->messageHandler()->message(CBC_START_SUB, model_->messages())
+                    << name
+                    << model.getMaximumNodes()
+                    << CoinMessageEol;
+                // probably faster to use a basis to get integer solutions
+                model.setSpecialOptions(model.specialOptions() | 2);
+#ifdef CBC_THREAD
+                if (model_->getNumberThreads() > 0 && (model_->getThreadMode()&4) != 0) {
+                    // See if at root node
+                    bool atRoot = model_->getNodeCount() == 0;
+                    int passNumber = model_->getCurrentPassNumber();
+                    if (atRoot && passNumber == 1)
+                        model.setNumberThreads(model_->getNumberThreads());
+                }
+#endif
+                model.setParentModel(*model_);
+		model.setMaximumSolutions(model_->getMaximumSolutions()); 
+		model.setOriginalColumns(process.originalColumns());
+                model.setSearchStrategy(-1);
+                // If no feasibility pump then insert a lightweight one
+                if (feasibilityPumpOptions_ >= 0 || feasibilityPumpOptions_ == -2) {
+		    CbcHeuristicFPump * fpump = NULL;
+                    for (int i = 0; i < model.numberHeuristics(); i++) {
+                        CbcHeuristicFPump* pump =
+                            dynamic_cast<CbcHeuristicFPump*>(model.heuristic(i));
+                        if (pump) {
+                            fpump = pump;
+                            break;
+			}
+                    }
+                    if (!fpump) {
+                        CbcHeuristicFPump heuristic4;
+			// use any cutoff
+			heuristic4.setFakeCutoff(0.5*COIN_DBL_MAX);
+			if (fractionSmall_<=1.0) 
+			  heuristic4.setMaximumPasses(10);
+                        int pumpTune = feasibilityPumpOptions_;
+			if (pumpTune==-2)
+			  pumpTune = 4; // proximity
+                        if (pumpTune > 0) {
+                            /*
+                            >=10000000 for using obj
+                            >=1000000 use as accumulate switch
+                            >=1000 use index+1 as number of large loops
+                            >=100 use 0.05 objvalue as increment
+                            %100 == 10,20 etc for experimentation
+                            1 == fix ints at bounds, 2 fix all integral ints, 3 and continuous at bounds
+                            4 and static continuous, 5 as 3 but no internal integers
+                            6 as 3 but all slack basis!
+                            */
+                            double value = solver2->getObjSense() * solver2->getObjValue();
+                            int w = pumpTune / 10;
+                            int ix = w % 10;
+                            w /= 10;
+                            int c = w % 10;
+                            w /= 10;
+                            int r = w;
+                            int accumulate = r / 1000;
+                            r -= 1000 * accumulate;
+                            if (accumulate >= 10) {
+                                int which = accumulate / 10;
+                                accumulate -= 10 * which;
+                                which--;
+                                // weights and factors
+                                double weight[] = {0.1, 0.1, 0.5, 0.5, 1.0, 1.0, 5.0, 5.0};
+                                double factor[] = {0.1, 0.5, 0.1, 0.5, 0.1, 0.5, 0.1, 0.5};
+                                heuristic4.setInitialWeight(weight[which]);
+                                heuristic4.setWeightFactor(factor[which]);
+                            }
+                            // fake cutoff
+                            if (c) {
+                                double cutoff;
+                                solver2->getDblParam(OsiDualObjectiveLimit, cutoff);
+                                cutoff = CoinMin(cutoff, value + 0.1 * fabs(value) * c);
+                                heuristic4.setFakeCutoff(cutoff);
+                            }
+                            if (r) {
+                                // also set increment
+                                //double increment = (0.01*i+0.005)*(fabs(value)+1.0e-12);
+                                double increment = 0.0;
+                                heuristic4.setAbsoluteIncrement(increment);
+                                heuristic4.setAccumulate(accumulate);
+                                heuristic4.setMaximumRetries(r + 1);
+                            }
+                            pumpTune = pumpTune % 100;
+                            if (pumpTune == 6)
+                                pumpTune = 13;
+                            if (pumpTune != 13)
+                                pumpTune = pumpTune % 10;
+                            heuristic4.setWhen(pumpTune);
+                            if (ix) {
+                                heuristic4.setFeasibilityPumpOptions(ix*10);
+                            }
+                        }
+                        model.addHeuristic(&heuristic4, "feasibility pump", 0);
+	
+                    }
+		} else if (feasibilityPumpOptions_==-3) {
+		  // add all (except this)
+		  for (int i = 0; i < model_->numberHeuristics(); i++) {
+		    if (strcmp(heuristicName(),model_->heuristic(i)->heuristicName()))
+		      model.addHeuristic(model_->heuristic(i)); 
+		  }
+		}
+                //printf("sol %x\n",inputSolution_);
+                if (inputSolution_) {
+                    // translate and add a serendipity heuristic
+                    int numberColumns = solver2->getNumCols();
+                    const int * which = process.originalColumns();
+                    OsiSolverInterface * solver3 = solver2->clone();
+                    for (int i = 0; i < numberColumns; i++) {
+                        if (solver3->isInteger(i)) {
+                            int k = which[i];
+                            double value = inputSolution_[k];
+                            //if (value)
+                            //printf("orig col %d now %d val %g\n",
+                            //       k,i,value);
+                            solver3->setColLower(i, value);
+                            solver3->setColUpper(i, value);
+                        }
+                    }
+                    solver3->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX);
+                    solver3->resolve();
+                    if (!solver3->isProvenOptimal()) {
+                        // Try just setting nonzeros
+                        OsiSolverInterface * solver4 = solver2->clone();
+                        for (int i = 0; i < numberColumns; i++) {
+                            if (solver4->isInteger(i)) {
+                                int k = which[i];
+                                double value = floor(inputSolution_[k] + 0.5);
+                                if (value) {
+                                    solver3->setColLower(i, value);
+                                    solver3->setColUpper(i, value);
+                                }
+                            }
+                        }
+                        solver4->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX);
+                        solver4->resolve();
+                        int nBad = -1;
+                        if (solver4->isProvenOptimal()) {
+                            nBad = 0;
+                            const double * solution = solver4->getColSolution();
+                            for (int i = 0; i < numberColumns; i++) {
+                                if (solver4->isInteger(i)) {
+                                    double value = floor(solution[i] + 0.5);
+                                    if (fabs(value - solution[i]) > 1.0e-6)
+                                        nBad++;
+                                }
+                            }
+                        }
+                        if (nBad) {
+                            delete solver4;
+                        } else {
+                            delete solver3;
+                            solver3 = solver4;
+                        }
+                    }
+                    if (solver3->isProvenOptimal()) {
+                        // good
+                        CbcSerendipity heuristic(model);
+                        double value = solver3->getObjSense() * solver3->getObjValue();
+                        heuristic.setInputSolution(solver3->getColSolution(), value);
+                        value = value + 1.0e-7*(1.0 + fabs(value));
+			value *= solver3->getObjSense();
+                        model.setCutoff(value);
+                        model.addHeuristic(&heuristic, "Previous solution", 0);
+                        //printf("added seren\n");
+                    } else {
+                        double value = model_->getMinimizationObjValue();
+                        value = value + 1.0e-7*(1.0 + fabs(value));
+			value *= solver3->getObjSense();
+                        model.setCutoff(value);
+#ifdef CLP_INVESTIGATE
+                        printf("NOT added seren\n");
+                        solver3->writeMps("bad_seren");
+                        solver->writeMps("orig_seren");
+#endif
+                    }
+                    delete solver3;
+                }
+                if (model_->searchStrategy() == 2) {
+                    model.setNumberStrong(5);
+                    model.setNumberBeforeTrust(5);
+                }
+                if (model.getNumCols()) {
+                    if (numberNodes >= 0) {
+                        setCutAndHeuristicOptions(model);
+                        // not too many iterations
+                        model.setMaximumNumberIterations(100*(numberNodes + 10));
+                        // Not fast stuff
+                        model.setFastNodeDepth(-1);
+                    } else if (model.fastNodeDepth() >= 1000000) {
+                        // already set
+                        model.setFastNodeDepth(model.fastNodeDepth() - 1000000);
+                    }
+                    model.setWhenCuts(999998);
+#define ALWAYS_DUAL
+#ifdef ALWAYS_DUAL
+		    OsiSolverInterface * solverD = model.solver();
+		    bool takeHint;
+		    OsiHintStrength strength;
+		    solverD->getHintParam(OsiDoDualInResolve, takeHint, strength);
+		    solverD->setHintParam(OsiDoDualInResolve, true, OsiHintDo);
+#endif
+		    model.passInEventHandler(model_->getEventHandler());
+		    // say model_ is sitting there
+		    int saveOptions = model_->specialOptions();
+		    model_->setSpecialOptions(saveOptions|1048576);
+                    model.branchAndBound();
+		    model_->setHeuristicModel(NULL);
+		    model_->setSpecialOptions(saveOptions);
+#ifdef ALWAYS_DUAL
+		    solverD = model.solver();
+		    solverD->setHintParam(OsiDoDualInResolve, takeHint, strength);
+#endif
+		    numberNodesDone_ = model.getNodeCount();
+#ifdef COIN_DEVELOP
+                    printf("sub branch %d nodes, %d iterations - max %d\n",
+                           model.getNodeCount(), model.getIterationCount(),
+                           100*(numberNodes + 10));
+#endif
+                    if (numberNodes < 0) {
+                        model_->incrementIterationCount(model.getIterationCount());
+                        model_->incrementNodeCount(model.getNodeCount());
+			// update best solution (in case ctrl-c)
+			// !!! not a good idea - think a bit harder
+			//model_->setMinimizationObjValue(model.getMinimizationObjValue());
+                        for (int iGenerator = 0; iGenerator < model.numberCutGenerators(); iGenerator++) {
+                            CbcCutGenerator * generator = model.cutGenerator(iGenerator);
+                            sprintf(generalPrint,
+                                    "%s was tried %d times and created %d cuts of which %d were active after adding rounds of cuts (%.3f seconds)",
+                                    generator->cutGeneratorName(),
+                                    generator->numberTimesEntered(),
+                                    generator->numberCutsInTotal() +
+                                    generator->numberColumnCuts(),
+                                    generator->numberCutsActive(),
+                                    generator->timeInCutGenerator());
+                            CglStored * stored = dynamic_cast<CglStored*>(generator->generator());
+                            if (stored && !generator->numberCutsInTotal())
+                                continue;
+#ifndef CLP_INVESTIGATE
+                            CglImplication * implication = dynamic_cast<CglImplication*>(generator->generator());
+                            if (implication)
+                                continue;
+#endif
+                            model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                            << generalPrint
+                            << CoinMessageEol;
+                        }
+                    }
+                } else {
+                    // empty model
+                    model.setMinimizationObjValue(model.solver()->getObjSense()*model.solver()->getObjValue());
+                }
+                if (logLevel > 1)
+                    model_->messageHandler()->message(CBC_END_SUB, model_->messages())
+                    << name
+                    << CoinMessageEol;
+                if (model.getMinimizationObjValue() < CoinMin(cutoff, 1.0e30)) {
+                    // solution
+                    if (model.getNumCols())
+                        returnCode = model.isProvenOptimal() ? 3 : 1;
+                    else
+                        returnCode = 3;
+                    // post process
+#ifdef COIN_HAS_CLP
+                    OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (model.solver());
+                    if (clpSolver) {
+                        ClpSimplex * lpSolver = clpSolver->getModelPtr();
+                        lpSolver->setSpecialOptions(lpSolver->specialOptions() | 0x01000000); // say is Cbc (and in branch and bound)
+                    }
+#endif
+		    //if (fractionSmall_ < 1000000.0) 
+		      process.postProcess(*model.solver());
+                    if (solver->isProvenOptimal() && solver->getObjValue()*solver->getObjSense() < cutoff) {
+                        // Solution now back in solver
+                        int numberColumns = solver->getNumCols();
+                        memcpy(newSolution, solver->getColSolution(),
+                               numberColumns*sizeof(double));
+                        newSolutionValue = model.getMinimizationObjValue();
+                    } else {
+                        // odd - but no good
+                        returnCode = 0; // so will be infeasible
+                    }
+                } else {
+                    // no good
+                    returnCode = model.isProvenInfeasible() ? 2 : 0; // so will be infeasible
+                }
+                int totalNumberIterations = model.getIterationCount() +
+                                            process.numberIterationsPre() +
+                                            process.numberIterationsPost();
+                if (totalNumberIterations > 100*(numberNodes + 10)
+		    && fractionSmall_ < 1000000.0) {
+                    // only allow smaller problems
+                    fractionSmall = fractionSmall_;
+                    fractionSmall_ *= 0.9;
+#ifdef CLP_INVESTIGATE
+                    printf("changing fractionSmall from %g to %g for %s as %d iterations\n",
+                           fractionSmall, fractionSmall_, name.c_str(), totalNumberIterations);
+#endif
+                }
+                if (model.status() == 5)
+                   model_->sayEventHappened();
+#ifdef COIN_DEVELOP
+                if (model.isProvenInfeasible())
+                    status = 1;
+                else if (model.isProvenOptimal())
+                    status = 2;
+#endif
+            }
+        }
+    } else {
+        returnCode = 2; // infeasible finished
+    }
+    model_->setSpecialOptions(saveModelOptions);
+    model_->setLogLevel(logLevel);
+    if (returnCode == 1 || returnCode == 2) {
+        OsiSolverInterface * solverC = model_->continuousSolver();
+        if (false && solverC) {
+            const double * lower = solver->getColLower();
+            const double * upper = solver->getColUpper();
+            const double * lowerC = solverC->getColLower();
+            const double * upperC = solverC->getColUpper();
+            bool good = true;
+            for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (solverC->isInteger(iColumn)) {
+                    if (lower[iColumn] > lowerC[iColumn] &&
+                            upper[iColumn] < upperC[iColumn]) {
+                        good = false;
+                        printf("CUT - can't add\n");
+                        break;
+                    }
+                }
+            }
+            if (good) {
+                double * cut = new double [numberColumns];
+                int * which = new int [numberColumns];
+                double rhs = -1.0;
+                int n = 0;
+                for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (solverC->isInteger(iColumn)) {
+                        if (lower[iColumn] == upperC[iColumn]) {
+                            rhs += lower[iColumn];
+                            cut[n] = 1.0;
+                            which[n++] = iColumn;
+                        } else if (upper[iColumn] == lowerC[iColumn]) {
+                            rhs -= upper[iColumn];
+                            cut[n] = -1.0;
+                            which[n++] = iColumn;
+                        }
+                    }
+                }
+                printf("CUT has %d entries\n", n);
+                OsiRowCut newCut;
+                newCut.setLb(-COIN_DBL_MAX);
+                newCut.setUb(rhs);
+                newCut.setRow(n, which, cut, false);
+                model_->makeGlobalCut(newCut);
+                delete [] cut;
+                delete [] which;
+            }
+        }
+#ifdef COIN_DEVELOP
+        if (status == 1)
+            printf("heuristic could add cut because infeasible (%s)\n", heuristicName_.c_str());
+        else if (status == 2)
+            printf("heuristic could add cut because optimal (%s)\n", heuristicName_.c_str());
+#endif
+    }
+    if (reset) {
+        for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (reset[iColumn])
+                solver->setColLower(iColumn, 0.0);
+        }
+        delete [] reset;
+    }
+#ifdef HISTORY_STATISTICS
+    getHistoryStatistics_ = true;
+#endif
+    solver->setHintParam(OsiDoReducePrint, takeHint, strength);
+    return returnCode;
+}
+// Set input solution
+void
+CbcHeuristic::setInputSolution(const double * solution, double objValue)
+{
+    delete [] inputSolution_;
+    inputSolution_ = NULL;
+    if (model_ && solution) {
+        int numberColumns = model_->getNumCols();
+        inputSolution_ = new double [numberColumns+1];
+        memcpy(inputSolution_, solution, numberColumns*sizeof(double));
+        inputSolution_[numberColumns] = objValue;
+    }
+}
+
+//##############################################################################
+
+inline int compare3BranchingObjects(const CbcBranchingObject* br0,
+                                    const CbcBranchingObject* br1)
+{
+    const int t0 = br0->type();
+    const int t1 = br1->type();
+    if (t0 < t1) {
+        return -1;
+    }
+    if (t0 > t1) {
+        return 1;
+    }
+    return br0->compareOriginalObject(br1);
+}
+
+//==============================================================================
+
+inline bool compareBranchingObjects(const CbcBranchingObject* br0,
+                                    const CbcBranchingObject* br1)
+{
+    return compare3BranchingObjects(br0, br1) < 0;
+}
+
+//==============================================================================
+
+void
+CbcHeuristicNode::gutsOfConstructor(CbcModel& model)
+{
+    //  CbcHeurDebugNodes(&model);
+    CbcNode* node = model.currentNode();
+    brObj_ = new CbcBranchingObject*[node->depth()];
+    CbcNodeInfo* nodeInfo = node->nodeInfo();
+    int cnt = 0;
+    while (nodeInfo->parentBranch() != NULL) {
+        const OsiBranchingObject* br = nodeInfo->parentBranch();
+        const CbcBranchingObject* cbcbr = dynamic_cast<const CbcBranchingObject*>(br);
+        if (! cbcbr) {
+            throw CoinError("CbcHeuristicNode can be used only with CbcBranchingObjects.\n",
+                            "gutsOfConstructor",
+                            "CbcHeuristicNode",
+                            __FILE__, __LINE__);
+        }
+        brObj_[cnt] = cbcbr->clone();
+        brObj_[cnt]->previousBranch();
+        ++cnt;
+        nodeInfo = nodeInfo->parent();
+    }
+    std::sort(brObj_, brObj_ + cnt, compareBranchingObjects);
+    if (cnt <= 1) {
+        numObjects_ = cnt;
+    } else {
+        numObjects_ = 0;
+        CbcBranchingObject* br = NULL; // What should this be?
+        for (int i = 1; i < cnt; ++i) {
+            if (compare3BranchingObjects(brObj_[numObjects_], brObj_[i]) == 0) {
+                int comp = brObj_[numObjects_]->compareBranchingObject(brObj_[i], br != 0);
+                switch (comp) {
+                case CbcRangeSame: // the same range
+                case CbcRangeDisjoint: // disjoint decisions
+                    // should not happen! we are on a chain!
+                    abort();
+                case CbcRangeSubset: // brObj_[numObjects_] is a subset of brObj_[i]
+                    delete brObj_[i];
+                    break;
+                case CbcRangeSuperset: // brObj_[i] is a subset of brObj_[numObjects_]
+                    delete brObj_[numObjects_];
+                    brObj_[numObjects_] = brObj_[i];
+                    break;
+                case CbcRangeOverlap: // overlap
+                    delete brObj_[i];
+                    delete brObj_[numObjects_];
+                    brObj_[numObjects_] = br;
+                    break;
+                }
+                continue;
+            } else {
+                brObj_[++numObjects_] = brObj_[i];
+            }
+        }
+        ++numObjects_;
+    }
+}
+
+//==============================================================================
+
+CbcHeuristicNode::CbcHeuristicNode(CbcModel& model)
+{
+    gutsOfConstructor(model);
+}
+
+//==============================================================================
+
+double
+CbcHeuristicNode::distance(const CbcHeuristicNode* node) const
+{
+
+    const double disjointWeight = 1;
+    const double overlapWeight = 0.4;
+    const double subsetWeight = 0.2;
+    int countDisjointWeight = 0;
+    int countOverlapWeight = 0;
+    int countSubsetWeight = 0;
+    int i = 0;
+    int j = 0;
+    double dist = 0.0;
+#ifdef PRINT_DEBUG
+    printf(" numObjects_ = %i, node->numObjects_ = %i\n",
+           numObjects_, node->numObjects_);
+#endif
+    while ( i < numObjects_ && j < node->numObjects_) {
+        CbcBranchingObject* br0 = brObj_[i];
+        const CbcBranchingObject* br1 = node->brObj_[j];
+#ifdef PRINT_DEBUG
+        const CbcIntegerBranchingObject* brPrint0 =
+            dynamic_cast<const CbcIntegerBranchingObject*>(br0);
+        const double* downBounds = brPrint0->downBounds();
+        const double* upBounds = brPrint0->upBounds();
+        int variable = brPrint0->variable();
+        int way = brPrint0->way();
+        printf("   br0: var %i downBd [%i,%i] upBd [%i,%i] way %i\n",
+               variable, static_cast<int>(downBounds[0]), static_cast<int>(downBounds[1]),
+               static_cast<int>(upBounds[0]), static_cast<int>(upBounds[1]), way);
+        const CbcIntegerBranchingObject* brPrint1 =
+            dynamic_cast<const CbcIntegerBranchingObject*>(br1);
+        downBounds = brPrint1->downBounds();
+        upBounds = brPrint1->upBounds();
+        variable = brPrint1->variable();
+        way = brPrint1->way();
+        printf("   br1: var %i downBd [%i,%i] upBd [%i,%i] way %i\n",
+               variable, static_cast<int>(downBounds[0]), static_cast<int>(downBounds[1]),
+               static_cast<int>(upBounds[0]), static_cast<int>(upBounds[1]), way);
+#endif
+        const int brComp = compare3BranchingObjects(br0, br1);
+        if (brComp < 0) {
+            dist += subsetWeight;
+            countSubsetWeight++;
+            ++i;
+        } else if (brComp > 0) {
+            dist += subsetWeight;
+            countSubsetWeight++;
+            ++j;
+        } else {
+            const int comp = br0->compareBranchingObject(br1, false);
+            switch (comp) {
+            case CbcRangeSame:
+                // do nothing
+                break;
+            case CbcRangeDisjoint: // disjoint decisions
+                dist += disjointWeight;
+                countDisjointWeight++;
+                break;
+            case CbcRangeSubset: // subset one way or another
+            case CbcRangeSuperset:
+                dist += subsetWeight;
+                countSubsetWeight++;
+                break;
+            case CbcRangeOverlap: // overlap
+                dist += overlapWeight;
+                countOverlapWeight++;
+                break;
+            }
+            ++i;
+            ++j;
+        }
+    }
+    dist += subsetWeight * (numObjects_ - i + node->numObjects_ - j);
+    countSubsetWeight += (numObjects_ - i + node->numObjects_ - j);
+    COIN_DETAIL_PRINT(printf("subset = %i, overlap = %i, disjoint = %i\n", countSubsetWeight,
+			     countOverlapWeight, countDisjointWeight));
+    return dist;
+}
+
+//==============================================================================
+
+CbcHeuristicNode::~CbcHeuristicNode()
+{
+    for (int i = 0; i < numObjects_; ++i) {
+        delete brObj_[i];
+    }
+    delete [] brObj_;
+}
+
+//==============================================================================
+
+double
+CbcHeuristicNode::minDistance(const CbcHeuristicNodeList& nodeList) const
+{
+    double minDist = COIN_DBL_MAX;
+    for (int i = nodeList.size() - 1; i >= 0; --i) {
+        minDist = CoinMin(minDist, distance(nodeList.node(i)));
+    }
+    return minDist;
+}
+
+//==============================================================================
+
+bool
+CbcHeuristicNode::minDistanceIsSmall(const CbcHeuristicNodeList& nodeList,
+                                     const double threshold) const
+{
+    for (int i = nodeList.size() - 1; i >= 0; --i) {
+        if (distance(nodeList.node(i)) >= threshold) {
+            continue;
+        } else {
+            return true;
+        }
+    }
+    return false;
+}
+
+//==============================================================================
+
+double
+CbcHeuristicNode::avgDistance(const CbcHeuristicNodeList& nodeList) const
+{
+    if (nodeList.size() == 0) {
+        return COIN_DBL_MAX;
+    }
+    double sumDist = 0;
+    for (int i = nodeList.size() - 1; i >= 0; --i) {
+        sumDist += distance(nodeList.node(i));
+    }
+    return sumDist / nodeList.size();
+}
+
+//##############################################################################
+
+// Default Constructor
+CbcRounding::CbcRounding()
+        : CbcHeuristic()
+{
+    // matrix and row copy will automatically be empty
+    seed_ = 7654321;
+    down_ = NULL;
+    up_ = NULL;
+    equal_ = NULL;
+    //whereFrom_ |= 16; // allow more often
+}
+
+// Constructor from model
+CbcRounding::CbcRounding(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    // Get a copy of original matrix (and by row for rounding);
+    assert(model.solver());
+    if (model.solver()->getNumRows()) {
+        matrix_ = *model.solver()->getMatrixByCol();
+        matrixByRow_ = *model.solver()->getMatrixByRow();
+        validate();
+    }
+    down_ = NULL;
+    up_ = NULL;
+    equal_ = NULL;
+    seed_ = 7654321;
+    //whereFrom_ |= 16; // allow more often
+}
+
+// Destructor
+CbcRounding::~CbcRounding ()
+{
+    delete [] down_;
+    delete [] up_;
+    delete [] equal_;
+}
+
+// Clone
+CbcHeuristic *
+CbcRounding::clone() const
+{
+    return new CbcRounding(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcRounding::generateCpp( FILE * fp)
+{
+    CbcRounding other;
+    fprintf(fp, "0#include \"CbcHeuristic.hpp\"\n");
+    fprintf(fp, "3  CbcRounding rounding(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "rounding");
+    if (seed_ != other.seed_)
+        fprintf(fp, "3  rounding.setSeed(%d);\n", seed_);
+    else
+        fprintf(fp, "4  rounding.setSeed(%d);\n", seed_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&rounding);\n");
+}
+//#define NEW_ROUNDING
+// Copy constructor
+CbcRounding::CbcRounding(const CbcRounding & rhs)
+        :
+        CbcHeuristic(rhs),
+        matrix_(rhs.matrix_),
+        matrixByRow_(rhs.matrixByRow_),
+        seed_(rhs.seed_)
+{
+#ifdef NEW_ROUNDING
+    int numberColumns = matrix_.getNumCols();
+    down_ = CoinCopyOfArray(rhs.down_, numberColumns);
+    up_ = CoinCopyOfArray(rhs.up_, numberColumns);
+    equal_ = CoinCopyOfArray(rhs.equal_, numberColumns);
+#else
+    down_ = NULL;
+    up_ = NULL;
+    equal_ = NULL;
+#endif
+}
+
+// Assignment operator
+CbcRounding &
+CbcRounding::operator=( const CbcRounding & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        matrix_ = rhs.matrix_;
+        matrixByRow_ = rhs.matrixByRow_;
+#ifdef NEW_ROUNDING
+        delete [] down_;
+        delete [] up_;
+        delete [] equal_;
+        int numberColumns = matrix_.getNumCols();
+        down_ = CoinCopyOfArray(rhs.down_, numberColumns);
+        up_ = CoinCopyOfArray(rhs.up_, numberColumns);
+        equal_ = CoinCopyOfArray(rhs.equal_, numberColumns);
+#else
+        down_ = NULL;
+        up_ = NULL;
+        equal_ = NULL;
+#endif
+        seed_ = rhs.seed_;
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcRounding::resetModel(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix (and by row for rounding);
+    assert(model_->solver());
+    matrix_ = *model_->solver()->getMatrixByCol();
+    matrixByRow_ = *model_->solver()->getMatrixByRow();
+    validate();
+}
+// See if rounding will give solution
+// Sets value of solution
+// Assumes rhs for original matrix still okay
+// At present only works with integers
+// Fix values if asked for
+// Returns 1 if solution, 0 if not
+int
+CbcRounding::solution(double & solutionValue,
+                      double * betterSolution)
+{
+
+    numCouldRun_++;
+    // See if to do
+    if (!when() || (when() % 10 == 1 && model_->phase() != 1) ||
+            (when() % 10 == 2 && (model_->phase() != 2 && model_->phase() != 3)))
+        return 0; // switched off
+    numRuns_++;
+    OsiSolverInterface * solver = model_->solver();
+    double direction = solver->getObjSense();
+    double newSolutionValue = direction * solver->getObjValue();
+    return solution(solutionValue, betterSolution, newSolutionValue);
+}
+// See if rounding will give solution
+// Sets value of solution
+// Assumes rhs for original matrix still okay
+// At present only works with integers
+// Fix values if asked for
+// Returns 1 if solution, 0 if not
+int
+CbcRounding::solution(double & solutionValue,
+                      double * betterSolution,
+                      double newSolutionValue)
+{
+
+    // See if to do
+    if (!when() || (when() % 10 == 1 && model_->phase() != 1) ||
+            (when() % 10 == 2 && (model_->phase() != 2 && model_->phase() != 3)))
+        return 0; // switched off
+    OsiSolverInterface * solver = model_->solver();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    const double * solution = solver->getColSolution();
+    const double * objective = solver->getObjCoefficients();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    int numberRows = matrix_.getNumRows();
+    assert (numberRows <= solver->getNumRows());
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    int i;
+    double direction = solver->getObjSense();
+    //double newSolutionValue = direction*solver->getObjValue();
+    int returnCode = 0;
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+    // Row copy
+    const double * elementByRow = matrixByRow_.getElements();
+    const int * column = matrixByRow_.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+    const int * rowLength = matrixByRow_.getVectorLengths();
+
+    // Get solution array for heuristic solution
+    int numberColumns = solver->getNumCols();
+    double * newSolution = new double [numberColumns];
+    memcpy(newSolution, solution, numberColumns*sizeof(double));
+
+    double * rowActivity = new double[numberRows];
+    memset(rowActivity, 0, numberRows*sizeof(double));
+    for (i = 0; i < numberColumns; i++) {
+        int j;
+        double value = newSolution[i];
+        if (value < lower[i]) {
+            value = lower[i];
+            newSolution[i] = value;
+        } else if (value > upper[i]) {
+            value = upper[i];
+            newSolution[i] = value;
+        }
+        if (value) {
+            for (j = columnStart[i];
+                    j < columnStart[i] + columnLength[i]; j++) {
+                int iRow = row[j];
+                rowActivity[iRow] += value * element[j];
+            }
+        }
+    }
+    // check was feasible - if not adjust (cleaning may move)
+    for (i = 0; i < numberRows; i++) {
+        if (rowActivity[i] < rowLower[i]) {
+            //assert (rowActivity[i]>rowLower[i]-1000.0*primalTolerance);
+            rowActivity[i] = rowLower[i];
+        } else if (rowActivity[i] > rowUpper[i]) {
+            //assert (rowActivity[i]<rowUpper[i]+1000.0*primalTolerance);
+            rowActivity[i] = rowUpper[i];
+        }
+    }
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = newSolution[iColumn];
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            double below = floor(value);
+            double newValue = newSolution[iColumn];
+            double cost = direction * objective[iColumn];
+            double move;
+            if (cost > 0.0) {
+                // try up
+                move = 1.0 - (value - below);
+            } else if (cost < 0.0) {
+                // try down
+                move = below - value;
+            } else {
+                // won't be able to move unless we can grab another variable
+                double randomNumber = randomNumberGenerator_.randomDouble();
+                // which way?
+                if (randomNumber < 0.5)
+                    move = below - value;
+                else
+                    move = 1.0 - (value - below);
+            }
+            newValue += move;
+            newSolution[iColumn] = newValue;
+            newSolutionValue += move * cost;
+            int j;
+            for (j = columnStart[iColumn];
+                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                int iRow = row[j];
+                rowActivity[iRow] += move * element[j];
+            }
+        }
+    }
+
+    double penalty = 0.0;
+    const char * integerType = model_->integerType();
+    // see if feasible - just using singletons
+    for (i = 0; i < numberRows; i++) {
+        double value = rowActivity[i];
+        double thisInfeasibility = 0.0;
+        if (value < rowLower[i] - primalTolerance)
+            thisInfeasibility = value - rowLower[i];
+        else if (value > rowUpper[i] + primalTolerance)
+            thisInfeasibility = value - rowUpper[i];
+        if (thisInfeasibility) {
+            // See if there are any slacks I can use to fix up
+            // maybe put in coding for multiple slacks?
+            double bestCost = 1.0e50;
+            int k;
+            int iBest = -1;
+            double addCost = 0.0;
+            double newValue = 0.0;
+            double changeRowActivity = 0.0;
+            double absInfeasibility = fabs(thisInfeasibility);
+            for (k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) {
+                int iColumn = column[k];
+                // See if all elements help
+                if (columnLength[iColumn] == 1) {
+                    double currentValue = newSolution[iColumn];
+                    double elementValue = elementByRow[k];
+                    double lowerValue = lower[iColumn];
+                    double upperValue = upper[iColumn];
+                    double gap = rowUpper[i] - rowLower[i];
+                    double absElement = fabs(elementValue);
+                    if (thisInfeasibility*elementValue > 0.0) {
+                        // we want to reduce
+                        if ((currentValue - lowerValue)*absElement >= absInfeasibility) {
+                            // possible - check if integer
+                            double distance = absInfeasibility / absElement;
+                            double thisCost = -direction * objective[iColumn] * distance;
+                            if (integerType[iColumn]) {
+                                distance = ceil(distance - primalTolerance);
+                                if (currentValue - distance >= lowerValue - primalTolerance) {
+                                    if (absInfeasibility - distance*absElement < -gap - primalTolerance)
+                                        thisCost = 1.0e100; // no good
+                                    else
+                                        thisCost = -direction * objective[iColumn] * distance;
+                                } else {
+                                    thisCost = 1.0e100; // no good
+                                }
+                            }
+                            if (thisCost < bestCost) {
+                                bestCost = thisCost;
+                                iBest = iColumn;
+                                addCost = thisCost;
+                                newValue = currentValue - distance;
+                                changeRowActivity = -distance * elementValue;
+                            }
+                        }
+                    } else {
+                        // we want to increase
+                        if ((upperValue - currentValue)*absElement >= absInfeasibility) {
+                            // possible - check if integer
+                            double distance = absInfeasibility / absElement;
+                            double thisCost = direction * objective[iColumn] * distance;
+                            if (integerType[iColumn]) {
+                                distance = ceil(distance - 1.0e-7);
+                                assert (currentValue - distance <= upperValue + primalTolerance);
+                                if (absInfeasibility - distance*absElement < -gap - primalTolerance)
+                                    thisCost = 1.0e100; // no good
+                                else
+                                    thisCost = direction * objective[iColumn] * distance;
+                            }
+                            if (thisCost < bestCost) {
+                                bestCost = thisCost;
+                                iBest = iColumn;
+                                addCost = thisCost;
+                                newValue = currentValue + distance;
+                                changeRowActivity = distance * elementValue;
+                            }
+                        }
+                    }
+                }
+            }
+            if (iBest >= 0) {
+                /*printf("Infeasibility of %g on row %d cost %g\n",
+                  thisInfeasibility,i,addCost);*/
+                newSolution[iBest] = newValue;
+                thisInfeasibility = 0.0;
+                newSolutionValue += addCost;
+                rowActivity[i] += changeRowActivity;
+            }
+            penalty += fabs(thisInfeasibility);
+        }
+    }
+    if (penalty) {
+        // see if feasible using any
+        // first continuous
+        double penaltyChange = 0.0;
+        int iColumn;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (integerType[iColumn])
+                continue;
+            double currentValue = newSolution[iColumn];
+            double lowerValue = lower[iColumn];
+            double upperValue = upper[iColumn];
+            int j;
+            int anyBadDown = 0;
+            int anyBadUp = 0;
+            double upImprovement = 0.0;
+            double downImprovement = 0.0;
+            for (j = columnStart[iColumn];
+                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                int iRow = row[j];
+                if (rowUpper[iRow] > rowLower[iRow]) {
+                    double value = element[j];
+                    if (rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
+                        // infeasible above
+                        downImprovement += value;
+                        upImprovement -= value;
+                        if (value > 0.0)
+                            anyBadUp++;
+                        else
+                            anyBadDown++;
+                    } else if (rowActivity[iRow] > rowUpper[iRow] - primalTolerance) {
+                        // feasible at ub
+                        if (value > 0.0) {
+                            upImprovement -= value;
+                            anyBadUp++;
+                        } else {
+                            downImprovement += value;
+                            anyBadDown++;
+                        }
+                    } else if (rowActivity[iRow] > rowLower[iRow] + primalTolerance) {
+                        // feasible in interior
+                    } else if (rowActivity[iRow] > rowLower[iRow] - primalTolerance) {
+                        // feasible at lb
+                        if (value < 0.0) {
+                            upImprovement += value;
+                            anyBadUp++;
+                        } else {
+                            downImprovement -= value;
+                            anyBadDown++;
+                        }
+                    } else {
+                        // infeasible below
+                        downImprovement -= value;
+                        upImprovement += value;
+                        if (value < 0.0)
+                            anyBadUp++;
+                        else
+                            anyBadDown++;
+                    }
+                } else {
+                    // equality row
+                    double value = element[j];
+                    if (rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
+                        // infeasible above
+                        downImprovement += value;
+                        upImprovement -= value;
+                        if (value > 0.0)
+                            anyBadUp++;
+                        else
+                            anyBadDown++;
+                    } else if (rowActivity[iRow] < rowLower[iRow] - primalTolerance) {
+                        // infeasible below
+                        downImprovement -= value;
+                        upImprovement += value;
+                        if (value < 0.0)
+                            anyBadUp++;
+                        else
+                            anyBadDown++;
+                    } else {
+                        // feasible - no good
+                        anyBadUp = -1;
+                        anyBadDown = -1;
+                        break;
+                    }
+                }
+            }
+            // could change tests for anyBad
+            if (anyBadUp)
+                upImprovement = 0.0;
+            if (anyBadDown)
+                downImprovement = 0.0;
+            double way = 0.0;
+            double improvement = 0.0;
+            if (downImprovement > 0.0 && currentValue > lowerValue) {
+                way = -1.0;
+                improvement = downImprovement;
+            } else if (upImprovement > 0.0 && currentValue < upperValue) {
+                way = 1.0;
+                improvement = upImprovement;
+            }
+            if (way) {
+                // can improve
+                double distance;
+                if (way > 0.0)
+                    distance = upperValue - currentValue;
+                else
+                    distance = currentValue - lowerValue;
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    double value = element[j] * way;
+                    if (rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
+                        // infeasible above
+                        assert (value < 0.0);
+                        double gap = rowActivity[iRow] - rowUpper[iRow];
+                        if (gap + value*distance < 0.0)
+                            distance = -gap / value;
+                    } else if (rowActivity[iRow] < rowLower[iRow] - primalTolerance) {
+                        // infeasible below
+                        assert (value > 0.0);
+                        double gap = rowActivity[iRow] - rowLower[iRow];
+                        if (gap + value*distance > 0.0)
+                            distance = -gap / value;
+                    } else {
+                        // feasible
+                        if (value > 0) {
+                            double gap = rowActivity[iRow] - rowUpper[iRow];
+                            if (gap + value*distance > 0.0)
+                                distance = -gap / value;
+                        } else {
+                            double gap = rowActivity[iRow] - rowLower[iRow];
+                            if (gap + value*distance < 0.0)
+                                distance = -gap / value;
+                        }
+                    }
+                }
+                //move
+                penaltyChange += improvement * distance;
+                distance *= way;
+                newSolution[iColumn] += distance;
+                newSolutionValue += direction * objective[iColumn] * distance;
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    double value = element[j];
+                    rowActivity[iRow] += distance * value;
+                }
+            }
+        }
+        // and now all if improving
+        double lastChange = penaltyChange ? 1.0 : 0.0;
+        while (lastChange > 1.0e-2) {
+            lastChange = 0;
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                bool isInteger = (integerType[iColumn] != 0);
+                double currentValue = newSolution[iColumn];
+                double lowerValue = lower[iColumn];
+                double upperValue = upper[iColumn];
+                int j;
+                int anyBadDown = 0;
+                int anyBadUp = 0;
+                double upImprovement = 0.0;
+                double downImprovement = 0.0;
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    double value = element[j];
+                    if (isInteger) {
+                        if (value > 0.0) {
+                            if (rowActivity[iRow] + value > rowUpper[iRow] + primalTolerance)
+                                anyBadUp++;
+                            if (rowActivity[iRow] - value < rowLower[iRow] - primalTolerance)
+                                anyBadDown++;
+                        } else {
+                            if (rowActivity[iRow] - value > rowUpper[iRow] + primalTolerance)
+                                anyBadDown++;
+                            if (rowActivity[iRow] + value < rowLower[iRow] - primalTolerance)
+                                anyBadUp++;
+                        }
+                    }
+                    if (rowUpper[iRow] > rowLower[iRow]) {
+                        if (rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
+                            // infeasible above
+                            downImprovement += value;
+                            upImprovement -= value;
+                            if (value > 0.0)
+                                anyBadUp++;
+                            else
+                                anyBadDown++;
+                        } else if (rowActivity[iRow] > rowUpper[iRow] - primalTolerance) {
+                            // feasible at ub
+                            if (value > 0.0) {
+                                upImprovement -= value;
+                                anyBadUp++;
+                            } else {
+                                downImprovement += value;
+                                anyBadDown++;
+                            }
+                        } else if (rowActivity[iRow] > rowLower[iRow] + primalTolerance) {
+                            // feasible in interior
+                        } else if (rowActivity[iRow] > rowLower[iRow] - primalTolerance) {
+                            // feasible at lb
+                            if (value < 0.0) {
+                                upImprovement += value;
+                                anyBadUp++;
+                            } else {
+                                downImprovement -= value;
+                                anyBadDown++;
+                            }
+                        } else {
+                            // infeasible below
+                            downImprovement -= value;
+                            upImprovement += value;
+                            if (value < 0.0)
+                                anyBadUp++;
+                            else
+                                anyBadDown++;
+                        }
+                    } else {
+                        // equality row
+                        if (rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
+                            // infeasible above
+                            downImprovement += value;
+                            upImprovement -= value;
+                            if (value > 0.0)
+                                anyBadUp++;
+                            else
+                                anyBadDown++;
+                        } else if (rowActivity[iRow] < rowLower[iRow] - primalTolerance) {
+                            // infeasible below
+                            downImprovement -= value;
+                            upImprovement += value;
+                            if (value < 0.0)
+                                anyBadUp++;
+                            else
+                                anyBadDown++;
+                        } else {
+                            // feasible - no good
+                            anyBadUp = -1;
+                            anyBadDown = -1;
+                            break;
+                        }
+                    }
+                }
+                // could change tests for anyBad
+                if (anyBadUp)
+                    upImprovement = 0.0;
+                if (anyBadDown)
+                    downImprovement = 0.0;
+                double way = 0.0;
+                double improvement = 0.0;
+                if (downImprovement > 0.0 && currentValue > lowerValue) {
+                    way = -1.0;
+                    improvement = downImprovement;
+                } else if (upImprovement > 0.0 && currentValue < upperValue) {
+                    way = 1.0;
+                    improvement = upImprovement;
+                }
+                if (way) {
+                    // can improve
+                    double distance = COIN_DBL_MAX;
+                    for (j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double value = element[j] * way;
+                        if (rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
+                            // infeasible above
+                            assert (value < 0.0);
+                            double gap = rowActivity[iRow] - rowUpper[iRow];
+                            if (gap + value*distance < 0.0) {
+                                // If integer then has to move by 1
+                                if (!isInteger)
+                                    distance = -gap / value;
+                                else
+                                    distance = CoinMax(-gap / value, 1.0);
+                            }
+                        } else if (rowActivity[iRow] < rowLower[iRow] - primalTolerance) {
+                            // infeasible below
+                            assert (value > 0.0);
+                            double gap = rowActivity[iRow] - rowLower[iRow];
+                            if (gap + value*distance > 0.0) {
+                                // If integer then has to move by 1
+                                if (!isInteger)
+                                    distance = -gap / value;
+                                else
+                                    distance = CoinMax(-gap / value, 1.0);
+                            }
+                        } else {
+                            // feasible
+                            if (value > 0) {
+                                double gap = rowActivity[iRow] - rowUpper[iRow];
+                                if (gap + value*distance > 0.0)
+                                    distance = -gap / value;
+                            } else {
+                                double gap = rowActivity[iRow] - rowLower[iRow];
+                                if (gap + value*distance < 0.0)
+                                    distance = -gap / value;
+                            }
+                        }
+                    }
+                    if (isInteger)
+                        distance = floor(distance + 1.05e-8);
+                    if (!distance) {
+                        // should never happen
+                        //printf("zero distance in CbcRounding - debug\n");
+                    }
+                    //move
+                    lastChange += improvement * distance;
+                    distance *= way;
+                    newSolution[iColumn] += distance;
+                    newSolutionValue += direction * objective[iColumn] * distance;
+                    for (j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double value = element[j];
+                        rowActivity[iRow] += distance * value;
+                    }
+                }
+            }
+            penaltyChange += lastChange;
+        }
+        penalty -= penaltyChange;
+        if (penalty < 1.0e-5*fabs(penaltyChange)) {
+            // recompute
+            penalty = 0.0;
+            for (i = 0; i < numberRows; i++) {
+                double value = rowActivity[i];
+                if (value < rowLower[i] - primalTolerance)
+                    penalty += rowLower[i] - value;
+                else if (value > rowUpper[i] + primalTolerance)
+                    penalty += value - rowUpper[i];
+            }
+        }
+    }
+
+    // Could also set SOS (using random) and repeat
+    if (!penalty) {
+        // See if we can do better
+        //seed_++;
+        //CoinSeedRandom(seed_);
+        // Random number between 0 and 1.
+        double randomNumber = randomNumberGenerator_.randomDouble();
+        int iPass;
+        int start[2];
+        int end[2];
+        int iRandom = static_cast<int> (randomNumber * (static_cast<double> (numberIntegers)));
+        start[0] = iRandom;
+        end[0] = numberIntegers;
+        start[1] = 0;
+        end[1] = iRandom;
+        for (iPass = 0; iPass < 2; iPass++) {
+            int i;
+            for (i = start[iPass]; i < end[iPass]; i++) {
+                int iColumn = integerVariable[i];
+#ifndef NDEBUG
+                double value = newSolution[iColumn];
+                assert (fabs(floor(value + 0.5) - value) < integerTolerance);
+#endif
+                double cost = direction * objective[iColumn];
+                double move = 0.0;
+                if (cost > 0.0)
+                    move = -1.0;
+                else if (cost < 0.0)
+                    move = 1.0;
+                while (move) {
+                    bool good = true;
+                    double newValue = newSolution[iColumn] + move;
+                    if (newValue < lower[iColumn] - primalTolerance ||
+                            newValue > upper[iColumn] + primalTolerance) {
+                        move = 0.0;
+                    } else {
+                        // see if we can move
+                        int j;
+                        for (j = columnStart[iColumn];
+                                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                            int iRow = row[j];
+                            double newActivity = rowActivity[iRow] + move * element[j];
+                            if (newActivity < rowLower[iRow] - primalTolerance ||
+                                    newActivity > rowUpper[iRow] + primalTolerance) {
+                                good = false;
+                                break;
+                            }
+                        }
+                        if (good) {
+                            newSolution[iColumn] = newValue;
+                            newSolutionValue += move * cost;
+                            int j;
+                            for (j = columnStart[iColumn];
+                                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                int iRow = row[j];
+                                rowActivity[iRow] += move * element[j];
+                            }
+                        } else {
+                            move = 0.0;
+                        }
+                    }
+                }
+            }
+        }
+        // Just in case of some stupidity
+        double objOffset = 0.0;
+        solver->getDblParam(OsiObjOffset, objOffset);
+        newSolutionValue = -objOffset;
+        for ( i = 0 ; i < numberColumns ; i++ )
+            newSolutionValue += objective[i] * newSolution[i];
+        newSolutionValue *= direction;
+        //printf("new solution value %g %g\n",newSolutionValue,solutionValue);
+        if (newSolutionValue < solutionValue) {
+            // paranoid check
+            memset(rowActivity, 0, numberRows*sizeof(double));
+            for (i = 0; i < numberColumns; i++) {
+                int j;
+                double value = newSolution[i];
+                if (value) {
+                    for (j = columnStart[i];
+                            j < columnStart[i] + columnLength[i]; j++) {
+                        int iRow = row[j];
+                        rowActivity[iRow] += value * element[j];
+                    }
+                }
+            }
+            // check was approximately feasible
+            bool feasible = true;
+            for (i = 0; i < numberRows; i++) {
+                if (rowActivity[i] < rowLower[i]) {
+                    if (rowActivity[i] < rowLower[i] - 1000.0*primalTolerance)
+                        feasible = false;
+                } else if (rowActivity[i] > rowUpper[i]) {
+                    if (rowActivity[i] > rowUpper[i] + 1000.0*primalTolerance)
+                        feasible = false;
+                }
+            }
+            if (feasible) {
+                // new solution
+                memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+                solutionValue = newSolutionValue;
+                //printf("** Solution of %g found by rounding\n",newSolutionValue);
+                returnCode = 1;
+            } else {
+                // Can easily happen
+                //printf("Debug CbcRounding giving bad solution\n");
+            }
+        }
+    }
+#ifdef NEW_ROUNDING
+    if (!returnCode) {
+#ifdef JJF_ZERO
+        // back to starting point
+        memcpy(newSolution, solution, numberColumns*sizeof(double));
+        memset(rowActivity, 0, numberRows*sizeof(double));
+        for (i = 0; i < numberColumns; i++) {
+            int j;
+            double value = newSolution[i];
+            if (value < lower[i]) {
+                value = lower[i];
+                newSolution[i] = value;
+            } else if (value > upper[i]) {
+                value = upper[i];
+                newSolution[i] = value;
+            }
+            if (value) {
+                for (j = columnStart[i];
+                        j < columnStart[i] + columnLength[i]; j++) {
+                    int iRow = row[j];
+                    rowActivity[iRow] += value * element[j];
+                }
+            }
+        }
+        // check was feasible - if not adjust (cleaning may move)
+        for (i = 0; i < numberRows; i++) {
+            if (rowActivity[i] < rowLower[i]) {
+                //assert (rowActivity[i]>rowLower[i]-1000.0*primalTolerance);
+                rowActivity[i] = rowLower[i];
+            } else if (rowActivity[i] > rowUpper[i]) {
+                //assert (rowActivity[i]<rowUpper[i]+1000.0*primalTolerance);
+                rowActivity[i] = rowUpper[i];
+            }
+        }
+#endif
+        int * candidate = new int [numberColumns];
+        int nCandidate = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            bool isInteger = (integerType[iColumn] != 0);
+            if (isInteger) {
+                double currentValue = newSolution[iColumn];
+                if (fabs(currentValue - floor(currentValue + 0.5)) > 1.0e-8)
+                    candidate[nCandidate++] = iColumn;
+            }
+        }
+        if (true) {
+            // Rounding as in Berthold
+            while (nCandidate) {
+                double infeasibility = 1.0e-7;
+                int iRow = -1;
+                for (i = 0; i < numberRows; i++) {
+                    double value = 0.0;
+                    if (rowActivity[i] < rowLower[i]) {
+                        value = rowLower[i] - rowActivity[i];
+                    } else if (rowActivity[i] > rowUpper[i]) {
+                        value = rowActivity[i] - rowUpper[i];
+                    }
+                    if (value > infeasibility) {
+                        infeasibility = value;
+                        iRow = i;
+                    }
+                }
+                if (iRow >= 0) {
+                    // infeasible
+                } else {
+                    // feasible
+                }
+            }
+        } else {
+            // Shifting as in Berthold
+        }
+        delete [] candidate;
+    }
+#endif
+    delete [] newSolution;
+    delete [] rowActivity;
+    return returnCode;
+}
+// update model
+void CbcRounding::setModel(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix (and by row for rounding);
+    assert(model_->solver());
+    if (model_->solver()->getNumRows()) {
+        matrix_ = *model_->solver()->getMatrixByCol();
+        matrixByRow_ = *model_->solver()->getMatrixByRow();
+        // make sure model okay for heuristic
+        validate();
+    }
+}
+// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+void
+CbcRounding::validate()
+{
+    if (model_ && (when() % 100) < 10) {
+        if (model_->numberIntegers() !=
+                model_->numberObjects() && (model_->numberObjects() ||
+                                            (model_->specialOptions()&1024) == 0)) {
+            int numberOdd = 0;
+            for (int i = 0; i < model_->numberObjects(); i++) {
+                if (!model_->object(i)->canDoHeuristics())
+                    numberOdd++;
+            }
+            if (numberOdd)
+                setWhen(0);
+        }
+    }
+#ifdef NEW_ROUNDING
+    int numberColumns = matrix_.getNumCols();
+    down_ = new unsigned short [numberColumns];
+    up_ = new unsigned short [numberColumns];
+    equal_ = new unsigned short [numberColumns];
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+    const double * rowLower = model.solver()->getRowLower();
+    const double * rowUpper = model.solver()->getRowUpper();
+    for (int i = 0; i < numberColumns; i++) {
+        int down = 0;
+        int up = 0;
+        int equal = 0;
+        if (columnLength[i] > 65535) {
+            equal[0] = 65535;
+            break; // unlikely to work
+        }
+        for (CoinBigIndex j = columnStart[i];
+                j < columnStart[i] + columnLength[i]; j++) {
+            int iRow = row[j];
+            if (rowLower[iRow] > -1.0e20 && rowUpper[iRow] < 1.0e20) {
+                equal++;
+            } else if (element[j] > 0.0) {
+                if (rowUpper[iRow] < 1.0e20)
+                    up++;
+                else
+                    down--;
+            } else {
+                if (rowLower[iRow] > -1.0e20)
+                    up++;
+                else
+                    down--;
+            }
+        }
+        down_[i] = (unsigned short) down;
+        up_[i] = (unsigned short) up;
+        equal_[i] = (unsigned short) equal;
+    }
+#else
+    down_ = NULL;
+    up_ = NULL;
+    equal_ = NULL;
+#endif
+}
+
+// Default Constructor
+CbcHeuristicPartial::CbcHeuristicPartial()
+        : CbcHeuristic()
+{
+    fixPriority_ = 10000;
+}
+
+// Constructor from model
+CbcHeuristicPartial::CbcHeuristicPartial(CbcModel & model, int fixPriority, int numberNodes)
+        : CbcHeuristic(model)
+{
+    fixPriority_ = fixPriority;
+    setNumberNodes(numberNodes);
+    validate();
+}
+
+// Destructor
+CbcHeuristicPartial::~CbcHeuristicPartial ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicPartial::clone() const
+{
+    return new CbcHeuristicPartial(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicPartial::generateCpp( FILE * fp)
+{
+    CbcHeuristicPartial other;
+    fprintf(fp, "0#include \"CbcHeuristic.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicPartial partial(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "partial");
+    if (fixPriority_ != other.fixPriority_)
+        fprintf(fp, "3  partial.setFixPriority(%d);\n", fixPriority_);
+    else
+        fprintf(fp, "4  partial.setFixPriority(%d);\n", fixPriority_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&partial);\n");
+}
+//#define NEW_PARTIAL
+// Copy constructor
+CbcHeuristicPartial::CbcHeuristicPartial(const CbcHeuristicPartial & rhs)
+        :
+        CbcHeuristic(rhs),
+        fixPriority_(rhs.fixPriority_)
+{
+}
+
+// Assignment operator
+CbcHeuristicPartial &
+CbcHeuristicPartial::operator=( const CbcHeuristicPartial & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        fixPriority_ = rhs.fixPriority_;
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicPartial::resetModel(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix (and by row for partial);
+    assert(model_->solver());
+    validate();
+}
+// See if partial will give solution
+// Sets value of solution
+// Assumes rhs for original matrix still okay
+// At present only works with integers
+// Fix values if asked for
+// Returns 1 if solution, 0 if not
+int
+CbcHeuristicPartial::solution(double & solutionValue,
+                              double * betterSolution)
+{
+    // Return if already done
+    if (fixPriority_ < 0)
+        return 0; // switched off
+    const double * hotstartSolution = model_->hotstartSolution();
+    const int * hotstartPriorities = model_->hotstartPriorities();
+    if (!hotstartSolution)
+        return 0;
+    OsiSolverInterface * solver = model_->solver();
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+
+    OsiSolverInterface * newSolver = model_->continuousSolver()->clone();
+    const double * colLower = newSolver->getColLower();
+    const double * colUpper = newSolver->getColUpper();
+
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    int i;
+    int numberFixed = 0;
+    int returnCode = 0;
+
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        if (abs(hotstartPriorities[iColumn]) <= fixPriority_) {
+            double value = hotstartSolution[iColumn];
+            double lower = colLower[iColumn];
+            double upper = colUpper[iColumn];
+            value = CoinMax(value, lower);
+            value = CoinMin(value, upper);
+            if (fabs(value - floor(value + 0.5)) < 1.0e-8) {
+                value = floor(value + 0.5);
+                newSolver->setColLower(iColumn, value);
+                newSolver->setColUpper(iColumn, value);
+                numberFixed++;
+            }
+        }
+    }
+    if (numberFixed > numberIntegers / 5 - 100000000) {
+#ifdef COIN_DEVELOP
+        printf("%d integers fixed\n", numberFixed);
+#endif
+        returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+                                         model_->getCutoff(), "CbcHeuristicPartial");
+        if (returnCode < 0)
+            returnCode = 0; // returned on size
+        //printf("return code %d",returnCode);
+        if ((returnCode&2) != 0) {
+            // could add cut
+            returnCode &= ~2;
+            //printf("could add cut with %d elements (if all 0-1)\n",nFix);
+        } else {
+            //printf("\n");
+        }
+    }
+    fixPriority_ = -1; // switch off
+
+    delete newSolver;
+    return returnCode;
+}
+// update model
+void CbcHeuristicPartial::setModel(CbcModel * model)
+{
+    model_ = model;
+    assert(model_->solver());
+    // make sure model okay for heuristic
+    validate();
+}
+// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+void
+CbcHeuristicPartial::validate()
+{
+    if (model_ && (when() % 100) < 10) {
+        if (model_->numberIntegers() !=
+                model_->numberObjects())
+            setWhen(0);
+    }
+}
+bool
+CbcHeuristicPartial::shouldHeurRun(int /*whereFrom*/)
+{
+    return true;
+}
+
+// Default Constructor
+CbcSerendipity::CbcSerendipity()
+        : CbcHeuristic()
+{
+}
+
+// Constructor from model
+CbcSerendipity::CbcSerendipity(CbcModel & model)
+        : CbcHeuristic(model)
+{
+}
+
+// Destructor
+CbcSerendipity::~CbcSerendipity ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcSerendipity::clone() const
+{
+    return new CbcSerendipity(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcSerendipity::generateCpp( FILE * fp)
+{
+    fprintf(fp, "0#include \"CbcHeuristic.hpp\"\n");
+    fprintf(fp, "3  CbcSerendipity serendipity(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "serendipity");
+    fprintf(fp, "3  cbcModel->addHeuristic(&serendipity);\n");
+}
+
+// Copy constructor
+CbcSerendipity::CbcSerendipity(const CbcSerendipity & rhs)
+        :
+        CbcHeuristic(rhs)
+{
+}
+
+// Assignment operator
+CbcSerendipity &
+CbcSerendipity::operator=( const CbcSerendipity & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+    }
+    return *this;
+}
+
+// Returns 1 if solution, 0 if not
+int
+CbcSerendipity::solution(double & solutionValue,
+                         double * betterSolution)
+{
+    if (!model_)
+        return 0;
+    if (!inputSolution_) {
+        // get information on solver type
+        OsiAuxInfo * auxInfo = model_->solver()->getAuxiliaryInfo();
+        OsiBabSolver * auxiliaryInfo = dynamic_cast< OsiBabSolver *> (auxInfo);
+        if (auxiliaryInfo) {
+            return auxiliaryInfo->solution(solutionValue, betterSolution, model_->solver()->getNumCols());
+        } else {
+            return 0;
+        }
+    } else {
+        int numberColumns = model_->getNumCols();
+        double value = inputSolution_[numberColumns];
+        int returnCode = 0;
+        if (value < solutionValue) {
+            solutionValue = value;
+            memcpy(betterSolution, inputSolution_, numberColumns*sizeof(double));
+            returnCode = 1;
+        }
+        delete [] inputSolution_;
+        inputSolution_ = NULL;
+        model_ = NULL; // switch off
+        return returnCode;
+    }
+}
+// update model
+void CbcSerendipity::setModel(CbcModel * model)
+{
+    model_ = model;
+}
+// Resets stuff if model changes
+void
+CbcSerendipity::resetModel(CbcModel * model)
+{
+    model_ = model;
+}
+
+
+// Default Constructor
+CbcHeuristicJustOne::CbcHeuristicJustOne()
+        : CbcHeuristic(),
+        probabilities_(NULL),
+        heuristic_(NULL),
+        numberHeuristics_(0)
+{
+}
+
+// Constructor from model
+CbcHeuristicJustOne::CbcHeuristicJustOne(CbcModel & model)
+        : CbcHeuristic(model),
+        probabilities_(NULL),
+        heuristic_(NULL),
+        numberHeuristics_(0)
+{
+}
+
+// Destructor
+CbcHeuristicJustOne::~CbcHeuristicJustOne ()
+{
+    for (int i = 0; i < numberHeuristics_; i++)
+        delete heuristic_[i];
+    delete [] heuristic_;
+    delete [] probabilities_;
+}
+
+// Clone
+CbcHeuristicJustOne *
+CbcHeuristicJustOne::clone() const
+{
+    return new CbcHeuristicJustOne(*this);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicJustOne::generateCpp( FILE * fp)
+{
+    CbcHeuristicJustOne other;
+    fprintf(fp, "0#include \"CbcHeuristicJustOne.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicJustOne heuristicJustOne(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicJustOne");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicJustOne);\n");
+}
+
+// Copy constructor
+CbcHeuristicJustOne::CbcHeuristicJustOne(const CbcHeuristicJustOne & rhs)
+        :
+        CbcHeuristic(rhs),
+        probabilities_(NULL),
+        heuristic_(NULL),
+        numberHeuristics_(rhs.numberHeuristics_)
+{
+    if (numberHeuristics_) {
+        probabilities_ = CoinCopyOfArray(rhs.probabilities_, numberHeuristics_);
+        heuristic_ = new CbcHeuristic * [numberHeuristics_];
+        for (int i = 0; i < numberHeuristics_; i++)
+            heuristic_[i] = rhs.heuristic_[i]->clone();
+    }
+}
+
+// Assignment operator
+CbcHeuristicJustOne &
+CbcHeuristicJustOne::operator=( const CbcHeuristicJustOne & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        for (int i = 0; i < numberHeuristics_; i++)
+            delete heuristic_[i];
+        delete [] heuristic_;
+        delete [] probabilities_;
+        probabilities_ = NULL;
+        heuristic_ = NULL;
+        numberHeuristics_ = rhs.numberHeuristics_;
+        if (numberHeuristics_) {
+            probabilities_ = CoinCopyOfArray(rhs.probabilities_, numberHeuristics_);
+            heuristic_ = new CbcHeuristic * [numberHeuristics_];
+            for (int i = 0; i < numberHeuristics_; i++)
+                heuristic_[i] = rhs.heuristic_[i]->clone();
+        }
+    }
+    return *this;
+}
+// Sets value of solution
+// Returns 1 if solution, 0 if not
+int
+CbcHeuristicJustOne::solution(double & solutionValue,
+                              double * betterSolution)
+{
+#ifdef DIVE_DEBUG
+    std::cout << "solutionValue = " << solutionValue << std::endl;
+#endif
+    ++numCouldRun_;
+
+    // test if the heuristic can run
+    if (!shouldHeurRun_randomChoice() || !numberHeuristics_)
+        return 0;
+    double randomNumber = randomNumberGenerator_.randomDouble();
+    int i;
+    for (i = 0; i < numberHeuristics_; i++) {
+        if (randomNumber < probabilities_[i])
+            break;
+    }
+    assert (i < numberHeuristics_);
+    int returnCode;
+    //model_->unsetDivingHasRun();
+#ifdef COIN_DEVELOP
+    printf("JustOne running %s\n",
+           heuristic_[i]->heuristicName());
+#endif
+    returnCode = heuristic_[i]->solution(solutionValue, betterSolution);
+#ifdef COIN_DEVELOP
+    if (returnCode)
+        printf("JustOne running %s found solution\n",
+               heuristic_[i]->heuristicName());
+#endif
+    return returnCode;
+}
+// Resets stuff if model changes
+void
+CbcHeuristicJustOne::resetModel(CbcModel * model)
+{
+    CbcHeuristic::resetModel(model);
+    for (int i = 0; i < numberHeuristics_; i++)
+        heuristic_[i]->resetModel(model);
+}
+// update model (This is needed if cliques update matrix etc)
+void
+CbcHeuristicJustOne::setModel(CbcModel * model)
+{
+    CbcHeuristic::setModel(model);
+    for (int i = 0; i < numberHeuristics_; i++)
+        heuristic_[i]->setModel(model);
+}
+// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+void
+CbcHeuristicJustOne::validate()
+{
+    CbcHeuristic::validate();
+    for (int i = 0; i < numberHeuristics_; i++)
+        heuristic_[i]->validate();
+}
+// Adds an heuristic with probability
+void
+CbcHeuristicJustOne::addHeuristic(const CbcHeuristic * heuristic, double probability)
+{
+    CbcHeuristic * thisOne = heuristic->clone();
+    thisOne->setWhen(-999);
+    CbcHeuristic ** tempH = CoinCopyOfArrayPartial(heuristic_, numberHeuristics_ + 1,
+                            numberHeuristics_);
+    delete [] heuristic_;
+    heuristic_ = tempH;
+    heuristic_[numberHeuristics_] = thisOne;
+    double * tempP = CoinCopyOfArrayPartial(probabilities_, numberHeuristics_ + 1,
+                                            numberHeuristics_);
+    delete [] probabilities_;
+    probabilities_ = tempP;
+    probabilities_[numberHeuristics_] = probability;
+    numberHeuristics_++;
+}
+// Normalize probabilities
+void
+CbcHeuristicJustOne::normalizeProbabilities()
+{
+    double sum = 0.0;
+    for (int i = 0; i < numberHeuristics_; i++)
+        sum += probabilities_[i];
+    double multiplier = 1.0 / sum;
+    sum = 0.0;
+    for (int i = 0; i < numberHeuristics_; i++) {
+        sum += probabilities_[i];
+        probabilities_[i] = sum * multiplier;
+    }
+    assert (fabs(probabilities_[numberHeuristics_-1] - 1.0) < 1.0e-5);
+    probabilities_[numberHeuristics_-1] = 1.000001;
+}
+
diff --git a/cbits/coin/CbcHeuristic.hpp b/cbits/coin/CbcHeuristic.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristic.hpp
@@ -0,0 +1,672 @@
+/* $Id: CbcHeuristic.hpp 1883 2013-04-06 13:33:15Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristic_H
+#define CbcHeuristic_H
+
+#include <string>
+#include <vector>
+#include "CoinPackedMatrix.hpp"
+#include "OsiCuts.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "OsiBranchingObject.hpp"
+
+class OsiSolverInterface;
+
+class CbcModel;
+
+//#############################################################################
+
+class CbcHeuristicNodeList;
+class CbcBranchingObject;
+
+/** A class describing the branching decisions that were made to get
+    to the node where a heuristic was invoked from */
+
+class CbcHeuristicNode {
+private:
+    void gutsOfConstructor(CbcModel& model);
+    CbcHeuristicNode();
+    CbcHeuristicNode& operator=(const CbcHeuristicNode&);
+private:
+    /// The number of branching decisions made
+    int numObjects_;
+    /** The indices of the branching objects. Note: an index may be
+        listed multiple times. E.g., a general integer variable that has
+        been branched on multiple times. */
+    CbcBranchingObject** brObj_;
+public:
+    CbcHeuristicNode(CbcModel& model);
+
+    CbcHeuristicNode(const CbcHeuristicNode& rhs);
+    ~CbcHeuristicNode();
+    double distance(const CbcHeuristicNode* node) const;
+    double minDistance(const CbcHeuristicNodeList& nodeList) const;
+    bool minDistanceIsSmall(const CbcHeuristicNodeList& nodeList,
+                            const double threshold) const;
+    double avgDistance(const CbcHeuristicNodeList& nodeList) const;
+};
+
+class CbcHeuristicNodeList {
+private:
+    void gutsOfDelete();
+    void gutsOfCopy(const CbcHeuristicNodeList& rhs);
+private:
+    std::vector<CbcHeuristicNode*> nodes_;
+public:
+    CbcHeuristicNodeList() {}
+    CbcHeuristicNodeList(const CbcHeuristicNodeList& rhs);
+    CbcHeuristicNodeList& operator=(const CbcHeuristicNodeList& rhs);
+    ~CbcHeuristicNodeList();
+
+    void append(CbcHeuristicNode*& node);
+    void append(const CbcHeuristicNodeList& nodes);
+    inline const CbcHeuristicNode* node(int i) const {
+        return nodes_[i];
+    }
+    inline int size() const {
+        return static_cast<int>(nodes_.size());
+    }
+};
+
+//#############################################################################
+/** Heuristic base class */
+
+class CbcHeuristic {
+private:
+    void gutsOfDelete() {}
+    void gutsOfCopy(const CbcHeuristic & rhs);
+
+public:
+    // Default Constructor
+    CbcHeuristic ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristic (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristic ( const CbcHeuristic &);
+
+    virtual ~CbcHeuristic();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const = 0;
+
+    /// Assignment operator
+    CbcHeuristic & operator=(const CbcHeuristic& rhs);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model) = 0;
+
+    /** returns 0 if no solution, 1 if valid solution
+        with better objective value than one passed in
+        Sets solution values if good, sets objective value
+        This is called after cuts have been added - so can not add cuts
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution) = 0;
+
+    /** returns 0 if no solution, 1 if valid solution, -1 if just
+        returning an estimate of best possible solution
+        with better objective value than one passed in
+        Sets solution values if good, sets objective value (only if nonzero code)
+        This is called at same time as cut generators - so can add cuts
+        Default is do nothing
+    */
+    virtual int solution2(double & /*objectiveValue*/,
+                          double * /*newSolution*/,
+                          OsiCuts & /*cs*/) {
+        return 0;
+    }
+
+    /// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+    virtual void validate() {}
+
+    /** Sets "when" flag - 0 off, 1 at root, 2 other than root, 3 always.
+        If 10 added then don't worry if validate says there are funny objects
+        as user knows it will be fine
+    */
+    inline void setWhen(int value) {
+        when_ = value;
+    }
+    /// Gets "when" flag - 0 off, 1 at root, 2 other than root, 3 always
+    inline int when() const {
+        return when_;
+    }
+
+    /// Sets number of nodes in subtree (default 200)
+    inline void setNumberNodes(int value) {
+        numberNodes_ = value;
+    }
+    /// Gets number of nodes in a subtree (default 200)
+    inline int numberNodes() const {
+        return numberNodes_;
+    }
+    /** Switches (does not apply equally to all heuristics)
+        1 bit - stop once allowable gap on objective reached
+        2 bit - always do given number of passes
+        4 bit - weaken cutoff by 5% every 50 passes?
+        8 bit - if has cutoff and suminf bobbling for 20 passes then
+                first try halving distance to best possible then
+                try keep halving distance to known cutoff
+        16 bit - needs new solution to run
+        1024 bit - stop all heuristics on max time
+    */
+    inline void setSwitches(int value) {
+        switches_ = value;
+    }
+    /** Switches (does not apply equally to all heuristics)
+        1 bit - stop once allowable gap on objective reached
+        2 bit - always do given number of passes
+        4 bit - weaken cutoff by 5% every 50 passes?
+        8 bit - if has cutoff and suminf bobbling for 20 passes then
+                first try halving distance to best possible then
+                try keep halving distance to known cutoff
+        16 bit - needs new solution to run
+        1024 bit - stop all heuristics on max time
+    */
+    inline int switches() const {
+        return switches_;
+    }
+    /// Whether to exit at once on gap
+    bool exitNow(double bestObjective) const;
+    /// Sets feasibility pump options (-1 is off)
+    inline void setFeasibilityPumpOptions(int value) {
+        feasibilityPumpOptions_ = value;
+    }
+    /// Gets feasibility pump options (-1 is off)
+    inline int feasibilityPumpOptions() const {
+        return feasibilityPumpOptions_;
+    }
+    /// Just set model - do not do anything else
+    inline void setModelOnly(CbcModel * model) {
+        model_ = model;
+    }
+
+
+    /// Sets fraction of new(rows+columns)/old(rows+columns) before doing small branch and bound (default 1.0)
+    inline void setFractionSmall(double value) {
+        fractionSmall_ = value;
+    }
+    /// Gets fraction of new(rows+columns)/old(rows+columns) before doing small branch and bound (default 1.0)
+    inline double fractionSmall() const {
+        return fractionSmall_;
+    }
+    /// Get how many solutions the heuristic thought it got
+    inline int numberSolutionsFound() const {
+        return numberSolutionsFound_;
+    }
+    /// Increment how many solutions the heuristic thought it got
+    inline void incrementNumberSolutionsFound() {
+        numberSolutionsFound_++;
+    }
+
+    /** Do mini branch and bound - return
+        0 not finished - no solution
+        1 not finished - solution
+        2 finished - no solution
+        3 finished - solution
+        (could add global cut if finished)
+        -1 returned on size
+        -2 time or user event
+    */
+    int smallBranchAndBound(OsiSolverInterface * solver, int numberNodes,
+                            double * newSolution, double & newSolutionValue,
+                            double cutoff , std::string name) const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+    /// Create C++ lines to get to current state - does work for base class
+    void generateCpp( FILE * fp, const char * heuristic) ;
+    /// Returns true if can deal with "odd" problems e.g. sos type 2
+    virtual bool canDealWithOdd() const {
+        return false;
+    }
+    /// return name of heuristic
+    inline const char *heuristicName() const {
+        return heuristicName_.c_str();
+    }
+    /// set name of heuristic
+    inline void setHeuristicName(const char *name) {
+        heuristicName_ = name;
+    }
+    /// Set random number generator seed
+    void setSeed(int value);
+    /// Get random number generator seed
+    int getSeed() const;
+    /// Sets decay factor (for howOften) on failure
+    inline void setDecayFactor(double value) {
+        decayFactor_ = value;
+    }
+    /// Set input solution
+    void setInputSolution(const double * solution, double objValue);
+    /* Runs if bit set
+        0 - before cuts at root node (or from doHeuristics)
+        1 - during cuts at root
+        2 - after root node cuts
+        3 - after cuts at other nodes
+        4 - during cuts at other nodes
+            8 added if previous heuristic in loop found solution
+     */
+    inline void setWhereFrom(int value) {
+        whereFrom_ = value;
+    }
+    inline int whereFrom() const {
+        return whereFrom_;
+    }
+    /** Upto this depth we call the tree shallow and the heuristic can be called
+        multiple times. That is, the test whether the current node is far from
+        the others where the jeuristic was invoked will not be done, only the
+        frequency will be tested. After that depth the heuristic will can be
+        invoked only once per node, right before branching. That's when it'll be
+        tested whether the heur should run at all. */
+    inline void setShallowDepth(int value) {
+        shallowDepth_ = value;
+    }
+    /** How often to invoke the heuristics in the shallow part of the tree */
+    inline void setHowOftenShallow(int value) {
+        howOftenShallow_ = value;
+    }
+    /** How "far" should this node be from every other where the heuristic was
+        run in order to allow the heuristic to run in this node, too. Currently
+        this is tested, but we may switch to avgDistanceToRun_ in the future. */
+    inline void setMinDistanceToRun(int value) {
+        minDistanceToRun_ = value;
+    }
+
+    /** Check whether the heuristic should run at all
+        0 - before cuts at root node (or from doHeuristics)
+        1 - during cuts at root
+        2 - after root node cuts
+        3 - after cuts at other nodes
+        4 - during cuts at other nodes
+            8 added if previous heuristic in loop found solution
+    */
+    virtual bool shouldHeurRun(int whereFrom);
+    /** Check whether the heuristic should run this time */
+    bool shouldHeurRun_randomChoice();
+    void debugNodes();
+    void printDistanceToNodes();
+    /// how many times the heuristic has actually run
+    inline int numRuns() const {
+        return numRuns_;
+    }
+
+    /// How many times the heuristic could run
+    inline int numCouldRun() const {
+        return numCouldRun_;
+    }
+    /*! \brief Clone, but ...
+
+      If type is
+	- 0 clone the solver for the model,
+	- 1 clone the continuous solver for the model
+        - Add 2 to say without integer variables which are at low priority
+        - Add 4 to say quite likely infeasible so give up easily (clp only).
+    */
+    OsiSolverInterface * cloneBut(int type);
+protected:
+
+    /// Model
+    CbcModel * model_;
+    /// When flag - 0 off, 1 at root, 2 other than root, 3 always
+    int when_;
+    /// Number of nodes in any sub tree
+    int numberNodes_;
+    /** Feasibility pump options , -1 is off
+	>=0 for feasibility pump itself
+        -2 quick proximity search
+        -3 longer proximity search
+    */
+    int feasibilityPumpOptions_;
+    /// Fraction of new(rows+columns)/old(rows+columns) before doing small branch and bound
+    mutable double fractionSmall_;
+    /// Thread specific random number generator
+    CoinThreadRandom randomNumberGenerator_;
+    /// Name for printing
+    std::string heuristicName_;
+
+    /// How often to do (code can change)
+    int howOften_;
+    /// How much to increase how often
+    double decayFactor_;
+    /** Switches (does not apply equally to all heuristics)
+        1 bit - stop once allowable gap on objective reached
+        2 bit - always do given number of passes
+        4 bit - weaken cutoff by 5% every 50 passes?
+        8 bit - if has cutoff and suminf bobbling for 20 passes then
+                first try halving distance to best possible then
+                try keep halving distance to known cutoff
+        16 bit - needs new solution to run
+        1024 bit - stop all heuristics on max time
+    */
+    mutable int switches_;
+    /* Runs if bit set
+        0 - before cuts at root node (or from doHeuristics)
+        1 - during cuts at root
+        2 - after root node cuts
+        3 - after cuts at other nodes
+        4 - during cuts at other nodes
+            8 added if previous heuristic in loop found solution
+     */
+    int whereFrom_;
+    /** Upto this depth we call the tree shallow and the heuristic can be called
+        multiple times. That is, the test whether the current node is far from
+        the others where the jeuristic was invoked will not be done, only the
+        frequency will be tested. After that depth the heuristic will can be
+        invoked only once per node, right before branching. That's when it'll be
+        tested whether the heur should run at all. */
+    int shallowDepth_;
+    /** How often to invoke the heuristics in the shallow part of the tree */
+    int howOftenShallow_;
+    /** How many invocations happened within the same node when in a shallow
+        part of the tree. */
+    int numInvocationsInShallow_;
+    /** How many invocations happened when in the deep part of the tree. For
+        every node we count only one invocation. */
+    int numInvocationsInDeep_;
+    /** After how many deep invocations was the heuristic run last time */
+    int lastRunDeep_;
+    /// how many times the heuristic has actually run
+    int numRuns_;
+    /** How "far" should this node be from every other where the heuristic was
+        run in order to allow the heuristic to run in this node, too. Currently
+        this is tested, but we may switch to avgDistanceToRun_ in the future. */
+    int minDistanceToRun_;
+
+    /// The description of the nodes where this heuristic has been applied
+    CbcHeuristicNodeList runNodes_;
+
+    /// How many times the heuristic could run
+    int numCouldRun_;
+
+    /// How many solutions the heuristic thought it got
+    int numberSolutionsFound_;
+
+    /// How many nodes the heuristic did this go
+    mutable int numberNodesDone_;
+
+    // Input solution - so can be used as seed
+    double * inputSolution_;
+
+
+#ifdef JJF_ZERO
+    /// Lower bounds of last node where the heuristic found a solution
+    double * lowerBoundLastNode_;
+    /// Upper bounds of last node where the heuristic found a solution
+    double * upperBoundLastNode_;
+#endif
+};
+/** Rounding class
+ */
+
+class CbcRounding : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcRounding ();
+
+    // Constructor with model - assumed before cuts
+    CbcRounding (CbcModel & model);
+
+    // Copy constructor
+    CbcRounding ( const CbcRounding &);
+
+    // Destructor
+    ~CbcRounding ();
+
+    /// Assignment operator
+    CbcRounding & operator=(const CbcRounding& rhs);
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution
+        with better objective value than one passed in
+        Sets solution values if good, sets objective value (only if good)
+        This is called after cuts have been added - so can not add cuts
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /** returns 0 if no solution, 1 if valid solution
+        with better objective value than one passed in
+        Sets solution values if good, sets objective value (only if good)
+        This is called after cuts have been added - so can not add cuts
+        Use solutionValue rather than solvers one
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution,
+                         double solutionValue);
+    /// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+    virtual void validate();
+
+
+    /// Set seed
+    void setSeed(int value) {
+        seed_ = value;
+    }
+
+protected:
+    // Data
+
+    // Original matrix by column
+    CoinPackedMatrix matrix_;
+
+    // Original matrix by
+    CoinPackedMatrix matrixByRow_;
+
+    // Down locks
+    unsigned short * down_;
+
+    // Up locks
+    unsigned short * up_;
+
+    // Equality locks
+    unsigned short * equal_;
+
+    // Seed for random stuff
+    int seed_;
+};
+
+/** Partial solution class
+    If user knows a partial solution this tries to get an integer solution
+    it uses hotstart information
+ */
+
+class CbcHeuristicPartial : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicPartial ();
+
+    /** Constructor with model - assumed before cuts
+        Fixes all variables with priority <= given
+        and does given number of nodes
+    */
+    CbcHeuristicPartial (CbcModel & model, int fixPriority = 10000, int numberNodes = 200);
+
+    // Copy constructor
+    CbcHeuristicPartial ( const CbcHeuristicPartial &);
+
+    // Destructor
+    ~CbcHeuristicPartial ();
+
+    /// Assignment operator
+    CbcHeuristicPartial & operator=(const CbcHeuristicPartial& rhs);
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution
+        with better objective value than one passed in
+        Sets solution values if good, sets objective value (only if good)
+        This is called after cuts have been added - so can not add cuts
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+    virtual void validate();
+
+
+    /// Set priority level
+    void setFixPriority(int value) {
+        fixPriority_ = value;
+    }
+
+    /** Check whether the heuristic should run at all */
+    virtual bool shouldHeurRun(int whereFrom);
+
+protected:
+    // Data
+
+    // All variables with abs priority <= this will be fixed
+    int fixPriority_;
+};
+
+/** heuristic - just picks up any good solution
+    found by solver - see OsiBabSolver
+ */
+
+class CbcSerendipity : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcSerendipity ();
+
+    /* Constructor with model
+    */
+    CbcSerendipity (CbcModel & model);
+
+    // Copy constructor
+    CbcSerendipity ( const CbcSerendipity &);
+
+    // Destructor
+    ~CbcSerendipity ();
+
+    /// Assignment operator
+    CbcSerendipity & operator=(const CbcSerendipity& rhs);
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// update model
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        We leave all variables which are at one at this node of the
+        tree to that value and will
+        initially set all others to zero.  We then sort all variables in order of their cost
+        divided by the number of entries in rows which are not yet covered.  We randomize that
+        value a bit so that ties will be broken in different ways on different runs of the heuristic.
+        We then choose the best one and set it to one and repeat the exercise.
+
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+protected:
+};
+
+/** Just One class - this chooses one at random
+ */
+
+class CbcHeuristicJustOne : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicJustOne ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicJustOne (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicJustOne ( const CbcHeuristicJustOne &);
+
+    // Destructor
+    ~CbcHeuristicJustOne ();
+
+    /// Clone
+    virtual CbcHeuristicJustOne * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicJustOne & operator=(const CbcHeuristicJustOne& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /** returns 0 if no solution, 1 if valid solution
+        with better objective value than one passed in
+        Sets solution values if good, sets objective value (only if good)
+        This is called after cuts have been added - so can not add cuts
+        This does Fractional Diving
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+    /// Selects the next variable to branch on
+    /** Returns true if all the fractional variables can be trivially
+        rounded. Returns false, if there is at least one fractional variable
+        that is not trivially roundable. In this case, the bestColumn
+        returned will not be trivially roundable.
+        This is dummy as never called
+    */
+    virtual bool selectVariableToBranch(OsiSolverInterface* /*solver*/,
+                                        const double* /*newSolution*/,
+                                        int& /*bestColumn*/,
+                                        int& /*bestRound*/) {
+        return true;
+    }
+    /// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+    virtual void validate();
+    /// Adds an heuristic with probability
+    void addHeuristic(const CbcHeuristic * heuristic, double probability);
+    /// Normalize probabilities
+    void normalizeProbabilities();
+protected:
+    // Data
+
+    // Probability of running a heuristic
+    double * probabilities_;
+
+    // Heuristics
+    CbcHeuristic ** heuristic_;
+
+    // Number of heuristics
+    int numberHeuristics_;
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicDINS.cpp b/cbits/coin/CbcHeuristicDINS.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDINS.cpp
@@ -0,0 +1,413 @@
+// $Id: CbcHeuristicDINS.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// edwin 12/5/09 carved out of CbcHeuristicRINS
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcHeuristicDINS.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcStrategy.hpp"
+#include "CglPreProcess.hpp"
+
+// Default Constructor
+CbcHeuristicDINS::CbcHeuristicDINS()
+        : CbcHeuristic()
+{
+    numberSolutions_ = 0;
+    numberSuccesses_ = 0;
+    numberTries_ = 0;
+    howOften_ = 100;
+    decayFactor_ = 0.5;
+    maximumKeepSolutions_ = 5;
+    numberKeptSolutions_ = 0;
+    numberIntegers_ = -1;
+    localSpace_ = 10;
+    values_ = NULL;
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicDINS::CbcHeuristicDINS(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    numberSolutions_ = 0;
+    numberSuccesses_ = 0;
+    numberTries_ = 0;
+    howOften_ = 100;
+    decayFactor_ = 0.5;
+    assert(model.solver());
+    maximumKeepSolutions_ = 5;
+    numberKeptSolutions_ = 0;
+    numberIntegers_ = -1;
+    localSpace_ = 10;
+    values_ = NULL;
+}
+
+// Destructor
+CbcHeuristicDINS::~CbcHeuristicDINS ()
+{
+    for (int i = 0; i < numberKeptSolutions_; i++)
+        delete [] values_[i];
+    delete [] values_;
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicDINS::clone() const
+{
+    return new CbcHeuristicDINS(*this);
+}
+
+// Assignment operator
+CbcHeuristicDINS &
+CbcHeuristicDINS::operator=( const CbcHeuristicDINS & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        numberSolutions_ = rhs.numberSolutions_;
+        howOften_ = rhs.howOften_;
+        numberSuccesses_ = rhs.numberSuccesses_;
+        numberTries_ = rhs.numberTries_;
+        for (int i = 0; i < numberKeptSolutions_; i++)
+            delete [] values_[i];
+        delete [] values_;
+        maximumKeepSolutions_ = rhs.maximumKeepSolutions_;
+        numberKeptSolutions_ = rhs.numberKeptSolutions_;
+        numberIntegers_ = rhs.numberIntegers_;
+        localSpace_ = rhs.localSpace_;
+        if (model_ && rhs.values_) {
+            assert (numberIntegers_ >= 0);
+            values_ = new int * [maximumKeepSolutions_];
+            for (int i = 0; i < maximumKeepSolutions_; i++)
+                values_[i] = CoinCopyOfArray(rhs.values_[i], numberIntegers_);
+        } else {
+            values_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicDINS::generateCpp( FILE * fp)
+{
+    CbcHeuristicDINS other;
+    fprintf(fp, "0#include \"CbcHeuristicDINS.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicDINS heuristicDINS(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicDINS");
+    if (howOften_ != other.howOften_)
+        fprintf(fp, "3  heuristicDINS.setHowOften(%d);\n", howOften_);
+    else
+        fprintf(fp, "4  heuristicDINS.setHowOften(%d);\n", howOften_);
+    if (maximumKeepSolutions_ != other.maximumKeepSolutions_)
+        fprintf(fp, "3  heuristicDINS.setMaximumKeep(%d);\n", maximumKeepSolutions_);
+    else
+        fprintf(fp, "4  heuristicDINS.setMaximumKeep(%d);\n", maximumKeepSolutions_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicDINS);\n");
+}
+
+// Copy constructor
+CbcHeuristicDINS::CbcHeuristicDINS(const CbcHeuristicDINS & rhs)
+        :
+        CbcHeuristic(rhs),
+        numberSolutions_(rhs.numberSolutions_),
+        howOften_(rhs.howOften_),
+        numberSuccesses_(rhs.numberSuccesses_),
+        numberTries_(rhs.numberTries_),
+        maximumKeepSolutions_(rhs.maximumKeepSolutions_),
+        numberKeptSolutions_(rhs.numberKeptSolutions_),
+        numberIntegers_(rhs.numberIntegers_),
+        localSpace_(rhs.localSpace_)
+{
+    if (model_ && rhs.values_) {
+        assert (numberIntegers_ >= 0);
+        values_ = new int * [maximumKeepSolutions_];
+        for (int i = 0; i < maximumKeepSolutions_; i++)
+            values_[i] = CoinCopyOfArray(rhs.values_[i], numberIntegers_);
+    } else {
+        values_ = NULL;
+    }
+}
+// Resets stuff if model changes
+void
+CbcHeuristicDINS::resetModel(CbcModel * )
+{
+    //CbcHeuristic::resetModel(model);
+    for (int i = 0; i < numberKeptSolutions_; i++)
+        delete [] values_[i];
+    delete [] values_;
+    numberKeptSolutions_ = 0;
+    numberIntegers_ = -1;
+    numberSolutions_ = 0;
+    values_ = NULL;
+}
+/*
+  First tries setting a variable to better value.  If feasible then
+  tries setting others.  If not feasible then tries swaps
+  Returns 1 if solution, 0 if not */
+int
+CbcHeuristicDINS::solution(double & solutionValue,
+                           double * betterSolution)
+{
+    numCouldRun_++;
+    int returnCode = 0;
+    const double * bestSolution = model_->bestSolution();
+    if (!bestSolution)
+        return 0; // No solution found yet
+    if (numberSolutions_ < model_->getSolutionCount()) {
+        // new solution - add info
+        numberSolutions_ = model_->getSolutionCount();
+
+        int numberIntegers = model_->numberIntegers();
+        const int * integerVariable = model_->integerVariable();
+        if (numberIntegers_ < 0) {
+            numberIntegers_ = numberIntegers;
+            assert (!values_);
+            values_ = new int * [maximumKeepSolutions_];
+            for (int i = 0; i < maximumKeepSolutions_; i++)
+                values_[i] = NULL;
+        } else {
+            assert (numberIntegers == numberIntegers_);
+        }
+        // move solutions (0 will be most recent)
+        {
+            int * temp = values_[maximumKeepSolutions_-1];
+            for (int i = maximumKeepSolutions_ - 1; i > 0; i--)
+                values_[i] = values_[i-1];
+            if (!temp)
+                temp = new int [numberIntegers_];
+            values_[0] = temp;
+        }
+        int i;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            double value = bestSolution[iColumn];
+            double nearest = floor(value + 0.5);
+            values_[0][i] = static_cast<int> (nearest);
+        }
+        numberKeptSolutions_ = CoinMin(numberKeptSolutions_ + 1, maximumKeepSolutions_);
+    }
+    int finalReturnCode = 0;
+    if (((model_->getNodeCount() % howOften_) == howOften_ / 2 || !model_->getNodeCount()) && (model_->getCurrentPassNumber() == 1 || model_->getCurrentPassNumber() == 999999)) {
+        OsiSolverInterface * solver = model_->solver();
+
+        int numberIntegers = model_->numberIntegers();
+        const int * integerVariable = model_->integerVariable();
+
+        const double * currentSolution = solver->getColSolution();
+        int localSpace = localSpace_;
+        // 0 means finished but no solution, 1 solution, 2 node limit
+        int status = -1;
+        double cutoff = model_->getCutoff();
+        while (status) {
+            status = 0;
+            OsiSolverInterface * newSolver = cloneBut(3); // was model_->continuousSolver()->clone();
+            const double * colLower = solver->getColLower();
+            const double * colUpper = solver->getColUpper();
+
+            double primalTolerance;
+            solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+            const double * continuousSolution = newSolver->getColSolution();
+            // Space for added constraint
+            double * element = new double [numberIntegers];
+            int * column = new int [numberIntegers];
+            int i;
+            int nFix = 0;
+            int nCouldFix = 0;
+            int nCouldFix2 = 0;
+            int nBound = 0;
+            int nEl = 0;
+            double bias = localSpace;
+            int okSame = numberKeptSolutions_ - 1;
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                const OsiObject * object = model_->object(i);
+                // get original bounds
+                double originalLower;
+                double originalUpper;
+                getIntegerInformation( object, originalLower, originalUpper);
+                double valueInt = bestSolution[iColumn];
+                if (valueInt < originalLower) {
+                    valueInt = originalLower;
+                } else if (valueInt > originalUpper) {
+                    valueInt = originalUpper;
+                }
+                int intValue = static_cast<int> (floor(valueInt + 0.5));
+                double currentValue = currentSolution[iColumn];
+                double currentLower = colLower[iColumn];
+                double currentUpper = colUpper[iColumn];
+                if (fabs(valueInt - currentValue) >= 0.5) {
+                    // Re-bound
+                    nBound++;
+                    if (intValue >= currentValue) {
+                        currentLower = CoinMax(currentLower, ceil(2 * currentValue - intValue));
+                        currentUpper = intValue;
+                    } else {
+                        currentLower = intValue;
+                        currentUpper = CoinMin(currentUpper, floor(2 * currentValue - intValue));
+                    }
+                    newSolver->setColLower(iColumn, currentLower);
+                    newSolver->setColUpper(iColumn, currentUpper);
+                } else {
+                    // See if can fix
+                    bool canFix = false;
+                    double continuousValue = continuousSolution[iColumn];
+                    if (fabs(currentValue - valueInt) < 10.0*primalTolerance) {
+                        if (currentUpper - currentLower > 1.0) {
+                            // General integer variable
+                            canFix = true;
+                        } else if (fabs(continuousValue - valueInt) < 10.0*primalTolerance) {
+                            int nSame = 1;
+                            //assert (intValue==values_[0][i]);
+                            for (int k = 1; k < numberKeptSolutions_; k++) {
+                                if (intValue == values_[k][i])
+                                    nSame++;
+                            }
+                            if (nSame >= okSame) {
+                                // can fix
+                                canFix = true;
+                            } else {
+                                nCouldFix++;
+                            }
+                        } else {
+                            nCouldFix2++;
+                        }
+                    }
+                    if (canFix) {
+                        newSolver->setColLower(iColumn, intValue);
+                        newSolver->setColUpper(iColumn, intValue);
+                        nFix++;
+                    } else {
+                        if (currentUpper - currentLower > 1.0) {
+                            // General integer variable
+                            currentLower = floor(currentValue);
+                            if (intValue >= currentLower && intValue <= currentLower + 1) {
+                                newSolver->setColLower(iColumn, currentLower);
+                                newSolver->setColUpper(iColumn, currentLower + 1.0);
+                            } else {
+                                // fix
+                                double value;
+                                if (intValue < currentLower)
+                                    value = currentLower;
+                                else
+                                    value = currentLower + 1;
+                                newSolver->setColLower(iColumn, value);
+                                newSolver->setColUpper(iColumn, value);
+                                nFix++;
+                            }
+                        } else {
+                            // 0-1 (ish)
+                            column[nEl] = iColumn;
+                            if (intValue == currentLower) {
+                                bias += currentLower;
+                                element[nEl++] = 1.0;
+                            } else if (intValue == currentUpper) {
+                                bias += currentUpper;
+                                element[nEl++] = -1.0;
+                            } else {
+                                printf("bad DINS logic\n");
+                                abort();
+                            }
+                        }
+                    }
+                }
+            }
+            char generalPrint[200];
+            sprintf(generalPrint,
+                    "%d fixed, %d same as cont/int, %d same as int - %d bounded %d in cut\n",
+                    nFix, nCouldFix, nCouldFix2, nBound, nEl);
+            model_->messageHandler()->message(CBC_FPUMP2, model_->messages())
+            << generalPrint
+            << CoinMessageEol;
+            if (nFix > numberIntegers / 10) {
+#ifdef JJF_ZERO
+                newSolver->initialSolve();
+                printf("obj %g\n", newSolver->getObjValue());
+                for (i = 0; i < numberIntegers; i++) {
+                    int iColumn = integerVariable[i];
+                    printf("%d new bounds %g %g - solutions %g %g\n",
+                           iColumn, newSolver->getColLower()[iColumn],
+                           newSolver->getColUpper()[iColumn],
+                           bestSolution[iColumn],
+                           currentSolution[iColumn]);
+                }
+#endif
+                if (nEl > 0)
+                    newSolver->addRow(nEl, column, element, -COIN_DBL_MAX, bias);
+                //printf("%d integers have same value\n",nFix);
+                returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+                                                 cutoff, "CbcHeuristicDINS");
+                if (returnCode < 0) {
+                    returnCode = 0; // returned on size
+                    status = 0;
+                } else {
+                    numRuns_++;
+                    if ((returnCode&2) != 0) {
+                        // could add cut as complete search
+                        returnCode &= ~2;
+                        if ((returnCode&1) != 0) {
+                            numberSuccesses_++;
+                            status = 1;
+                        } else {
+                            // no solution
+                            status = 0;
+                        }
+                    } else {
+                        if ((returnCode&1) != 0) {
+                            numberSuccesses_++;
+                            status = 1;
+                        } else {
+                            // no solution but node limit
+                            status = 2;
+                            if (nEl)
+                                localSpace -= 5;
+                            else
+                                localSpace = -1;
+                            if (localSpace < 0)
+                                status = 0;
+                        }
+                    }
+                    if ((returnCode&1) != 0) {
+                        cutoff = CoinMin(cutoff, solutionValue - model_->getCutoffIncrement());
+                        finalReturnCode = 1;
+                    }
+                }
+            }
+            delete [] element;
+            delete [] column;
+            delete newSolver;
+        }
+        numberTries_++;
+        if ((numberTries_ % 10) == 0 && numberSuccesses_*3 < numberTries_)
+            howOften_ += static_cast<int> (howOften_ * decayFactor_);
+    }
+    return finalReturnCode;
+}
+// update model
+void CbcHeuristicDINS::setModel(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix
+    assert(model_->solver());
+    for (int i = 0; i < numberKeptSolutions_; i++)
+        delete [] values_[i];
+    delete [] values_;
+    numberKeptSolutions_ = 0;
+    numberIntegers_ = -1;
+    numberSolutions_ = 0;
+    values_ = NULL;
+}
+
diff --git a/cbits/coin/CbcHeuristicDINS.hpp b/cbits/coin/CbcHeuristicDINS.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDINS.hpp
@@ -0,0 +1,96 @@
+// $Id: CbcHeuristicDINS.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// edwin 12/5/09 carved out of CbcHeuristicRINS
+
+#ifndef CbcHeuristicDINS_H
+#define CbcHeuristicDINS_H
+
+#include "CbcHeuristic.hpp"
+
+
+class CbcHeuristicDINS : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicDINS ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicDINS (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDINS ( const CbcHeuristicDINS &);
+
+    // Destructor
+    ~CbcHeuristicDINS ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+
+    /// Assignment operator
+    CbcHeuristicDINS & operator=(const CbcHeuristicDINS& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        This does Relaxation Induced Neighborhood Search
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// This version fixes stuff and does IP
+    int solutionFix(double & objectiveValue,
+                    double * newSolution,
+                    const int * keep);
+
+    /// Sets how often to do it
+    inline void setHowOften(int value) {
+        howOften_ = value;
+    }
+    /// Sets maximum number of solutions kept
+    inline void setMaximumKeep(int value) {
+        maximumKeepSolutions_ = value;
+    }
+    /// Sets tightness of extra constraint
+    inline void setConstraint(int value) {
+        localSpace_ = value;
+    }
+
+protected:
+    // Data
+
+    /// Number of solutions so we can do something at solution
+    int numberSolutions_;
+    /// How often to do (code can change)
+    int howOften_;
+    /// Number of successes
+    int numberSuccesses_;
+    /// Number of tries
+    int numberTries_;
+    /// Maximum number of solutions to keep
+    int maximumKeepSolutions_;
+    /// Number of solutions kept
+    int numberKeptSolutions_;
+    /// Number of integer variables
+    int numberIntegers_;
+    /// Local parameter
+    int localSpace_;
+    /// Values of integer variables
+    int ** values_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicDive.cpp b/cbits/coin/CbcHeuristicDive.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDive.cpp
@@ -0,0 +1,1338 @@
+/* $Id: CbcHeuristicDive.cpp 1912 2013-04-26 10:43:35Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcHeuristicDive.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcModel.hpp"
+#include "CbcSubProblem.hpp"
+#include "OsiAuxInfo.hpp"
+#include  "CoinTime.hpp"
+
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+
+//#define DIVE_FIX_BINARY_VARIABLES
+//#define DIVE_DEBUG
+
+// Default Constructor
+CbcHeuristicDive::CbcHeuristicDive()
+        : CbcHeuristic()
+{
+    // matrix and row copy will automatically be empty
+    downLocks_ = NULL;
+    upLocks_ = NULL;
+    downArray_ = NULL;
+    upArray_ = NULL;
+    percentageToFix_ = 0.2;
+    maxIterations_ = 100;
+    maxSimplexIterations_ = 10000;
+    maxSimplexIterationsAtRoot_ = 1000000;
+    maxTime_ = 600;
+    whereFrom_ = 255 - 2 - 16 + 256;
+    decayFactor_ = 1.0;
+}
+
+// Constructor from model
+CbcHeuristicDive::CbcHeuristicDive(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    downLocks_ = NULL;
+    upLocks_ = NULL;
+    downArray_ = NULL;
+    upArray_ = NULL;
+    // Get a copy of original matrix
+    assert(model.solver());
+    // model may have empty matrix - wait until setModel
+    const CoinPackedMatrix * matrix = model.solver()->getMatrixByCol();
+    if (matrix) {
+        matrix_ = *matrix;
+        matrixByRow_ = *model.solver()->getMatrixByRow();
+        validate();
+    }
+    percentageToFix_ = 0.2;
+    maxIterations_ = 100;
+    maxSimplexIterations_ = 10000;
+    maxSimplexIterationsAtRoot_ = 1000000;
+    maxTime_ = 600;
+    whereFrom_ = 255 - 2 - 16 + 256;
+    decayFactor_ = 1.0;
+}
+
+// Destructor
+CbcHeuristicDive::~CbcHeuristicDive ()
+{
+    delete [] downLocks_;
+    delete [] upLocks_;
+    assert (!downArray_);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicDive::generateCpp( FILE * fp, const char * heuristic)
+{
+    // hard coded as CbcHeuristic virtual
+    CbcHeuristic::generateCpp(fp, heuristic);
+    if (percentageToFix_ != 0.2)
+        fprintf(fp, "3  %s.setPercentageToFix(%.f);\n", heuristic, percentageToFix_);
+    else
+        fprintf(fp, "4  %s.setPercentageToFix(%.f);\n", heuristic, percentageToFix_);
+    if (maxIterations_ != 100)
+        fprintf(fp, "3  %s.setMaxIterations(%d);\n", heuristic, maxIterations_);
+    else
+        fprintf(fp, "4  %s.setMaxIterations(%d);\n", heuristic, maxIterations_);
+    if (maxSimplexIterations_ != 10000)
+        fprintf(fp, "3  %s.setMaxSimplexIterations(%d);\n", heuristic, maxSimplexIterations_);
+    else
+        fprintf(fp, "4  %s.setMaxSimplexIterations(%d);\n", heuristic, maxSimplexIterations_);
+    if (maxTime_ != 600)
+        fprintf(fp, "3  %s.setMaxTime(%.2f);\n", heuristic, maxTime_);
+    else
+        fprintf(fp, "4  %s.setMaxTime(%.2f);\n", heuristic, maxTime_);
+}
+
+// Copy constructor
+CbcHeuristicDive::CbcHeuristicDive(const CbcHeuristicDive & rhs)
+        :
+        CbcHeuristic(rhs),
+        matrix_(rhs.matrix_),
+        matrixByRow_(rhs.matrixByRow_),
+        percentageToFix_(rhs.percentageToFix_),
+        maxIterations_(rhs.maxIterations_),
+        maxSimplexIterations_(rhs.maxSimplexIterations_),
+        maxSimplexIterationsAtRoot_(rhs.maxSimplexIterationsAtRoot_),
+        maxTime_(rhs.maxTime_)
+{
+    downArray_ = NULL;
+    upArray_ = NULL;
+    if (rhs.downLocks_) {
+        int numberIntegers = model_->numberIntegers();
+        downLocks_ = CoinCopyOfArray(rhs.downLocks_, numberIntegers);
+        upLocks_ = CoinCopyOfArray(rhs.upLocks_, numberIntegers);
+    } else {
+        downLocks_ = NULL;
+        upLocks_ = NULL;
+    }
+}
+
+// Assignment operator
+CbcHeuristicDive &
+CbcHeuristicDive::operator=( const CbcHeuristicDive & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        matrix_ = rhs.matrix_;
+        matrixByRow_ = rhs.matrixByRow_;
+        percentageToFix_ = rhs.percentageToFix_;
+        maxIterations_ = rhs.maxIterations_;
+        maxSimplexIterations_ = rhs.maxSimplexIterations_;
+        maxSimplexIterationsAtRoot_ = rhs.maxSimplexIterationsAtRoot_;
+        maxTime_ = rhs.maxTime_;
+        delete [] downLocks_;
+        delete [] upLocks_;
+        if (rhs.downLocks_) {
+            int numberIntegers = model_->numberIntegers();
+            downLocks_ = CoinCopyOfArray(rhs.downLocks_, numberIntegers);
+            upLocks_ = CoinCopyOfArray(rhs.upLocks_, numberIntegers);
+        } else {
+            downLocks_ = NULL;
+            upLocks_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicDive::resetModel(CbcModel * model)
+{
+    model_ = model;
+    assert(model_->solver());
+    // Get a copy of original matrix
+    const CoinPackedMatrix * matrix = model_->solver()->getMatrixByCol();
+    // model may have empty matrix - wait until setModel
+    if (matrix) {
+        matrix_ = *matrix;
+        matrixByRow_ = *model->solver()->getMatrixByRow();
+        validate();
+    }
+}
+
+// update model
+void CbcHeuristicDive::setModel(CbcModel * model)
+{
+    model_ = model;
+    assert(model_->solver());
+    // Get a copy of original matrix
+    const CoinPackedMatrix * matrix = model_->solver()->getMatrixByCol();
+    if (matrix) {
+        matrix_ = *matrix;
+        matrixByRow_ = *model->solver()->getMatrixByRow();
+        // make sure model okay for heuristic
+        validate();
+    }
+}
+
+bool CbcHeuristicDive::canHeuristicRun()
+{
+    return shouldHeurRun_randomChoice();
+}
+
+inline bool compareBinaryVars(const PseudoReducedCost obj1,
+                              const PseudoReducedCost obj2)
+{
+    return obj1.pseudoRedCost > obj2.pseudoRedCost;
+}
+
+// inner part of dive
+int 
+CbcHeuristicDive::solution(double & solutionValue, int & numberNodes,
+			   int & numberCuts, OsiRowCut ** cuts,
+			   CbcSubProblem ** & nodes,
+			   double * newSolution)
+{
+#ifdef DIVE_DEBUG
+    int nRoundInfeasible = 0;
+    int nRoundFeasible = 0;
+#endif
+    int reasonToStop = 0;
+    double time1 = CoinCpuTime();
+    int numberSimplexIterations = 0;
+    int maxSimplexIterations = (model_->getNodeCount()) ? maxSimplexIterations_
+                               : maxSimplexIterationsAtRoot_;
+    // but can't be exactly coin_int_max
+    maxSimplexIterations = CoinMin(maxSimplexIterations,COIN_INT_MAX>>3);
+    OsiSolverInterface * solver = cloneBut(6); // was model_->solver()->clone();
+# ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver);
+    if (clpSolver) {
+      ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+      int oneSolveIts = clpSimplex->maximumIterations();
+      oneSolveIts = CoinMin(1000+2*(clpSimplex->numberRows()+clpSimplex->numberColumns()),oneSolveIts);
+      clpSimplex->setMaximumIterations(oneSolveIts);
+      if (!nodes) {
+        // say give up easily
+        clpSimplex->setMoreSpecialOptions(clpSimplex->moreSpecialOptions() | 64);
+      } else {
+	// get ray
+	int specialOptions = clpSimplex->specialOptions();
+	specialOptions &= ~0x3100000;
+	specialOptions |= 32;
+        clpSimplex->setSpecialOptions(specialOptions);
+        clpSolver->setSpecialOptions(clpSolver->specialOptions() | 1048576);
+	if ((model_->moreSpecialOptions()&16777216)!=0) {
+	  // cutoff is constraint
+	  clpSolver->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX);
+	}
+      }
+    }
+# endif
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    const double * solution = solver->getColSolution();
+    const double * objective = solver->getObjCoefficients();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    int numberRows = matrix_.getNumRows();
+    assert (numberRows <= solver->getNumRows());
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    double direction = solver->getObjSense(); // 1 for min, -1 for max
+    double newSolutionValue = direction * solver->getObjValue();
+    int returnCode = 0;
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+#ifdef DIVE_FIX_BINARY_VARIABLES
+    // Row copy
+    const double * elementByRow = matrixByRow_.getElements();
+    const int * column = matrixByRow_.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+    const int * rowLength = matrixByRow_.getVectorLengths();
+#endif
+
+    // Get solution array for heuristic solution
+    int numberColumns = solver->getNumCols();
+    memcpy(newSolution, solution, numberColumns*sizeof(double));
+
+    // vectors to store the latest variables fixed at their bounds
+    int* columnFixed = new int [numberIntegers];
+    double* originalBound = new double [numberIntegers+2*numberColumns];
+    double * lowerBefore = originalBound+numberIntegers;
+    double * upperBefore = lowerBefore+numberColumns;
+    memcpy(lowerBefore,lower,numberColumns*sizeof(double));
+    memcpy(upperBefore,upper,numberColumns*sizeof(double));
+    double * lastDjs=newSolution+numberColumns;
+    bool * fixedAtLowerBound = new bool [numberIntegers];
+    PseudoReducedCost * candidate = new PseudoReducedCost [numberIntegers];
+    double * random = new double [numberIntegers];
+
+    int maxNumberAtBoundToFix = static_cast<int> (floor(percentageToFix_ * numberIntegers));
+    assert (!maxNumberAtBoundToFix||!nodes);
+
+    // count how many fractional variables
+    int numberFractionalVariables = 0;
+    for (int i = 0; i < numberIntegers; i++) {
+        random[i] = randomNumberGenerator_.randomDouble() + 0.3;
+        int iColumn = integerVariable[i];
+        double value = newSolution[iColumn];
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            numberFractionalVariables++;
+        }
+    }
+
+    const double* reducedCost = NULL;
+    // See if not NLP
+    if (model_->solverCharacteristics()->reducedCostsAccurate())
+        reducedCost = solver->getReducedCost();
+
+    int iteration = 0;
+    while (numberFractionalVariables) {
+        iteration++;
+
+        // initialize any data
+        initializeData();
+
+        // select a fractional variable to bound
+        int bestColumn = -1;
+        int bestRound; // -1 rounds down, +1 rounds up
+        bool canRound = selectVariableToBranch(solver, newSolution,
+                                               bestColumn, bestRound);
+        // if the solution is not trivially roundable, we don't try to round;
+        // if the solution is trivially roundable, we try to round. However,
+        // if the rounded solution is worse than the current incumbent,
+        // then we don't round and proceed normally. In this case, the
+        // bestColumn will be a trivially roundable variable
+        if (canRound) {
+            // check if by rounding all fractional variables
+            // we get a solution with an objective value
+            // better than the current best integer solution
+            double delta = 0.0;
+            for (int i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                double value = newSolution[iColumn];
+                if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+                    assert(downLocks_[i] == 0 || upLocks_[i] == 0);
+                    double obj = objective[iColumn];
+                    if (downLocks_[i] == 0 && upLocks_[i] == 0) {
+                        if (direction * obj >= 0.0)
+                            delta += (floor(value) - value) * obj;
+                        else
+                            delta += (ceil(value) - value) * obj;
+                    } else if (downLocks_[i] == 0)
+                        delta += (floor(value) - value) * obj;
+                    else
+                        delta += (ceil(value) - value) * obj;
+                }
+            }
+            if (direction*(solver->getObjValue() + delta) < solutionValue) {
+#ifdef DIVE_DEBUG
+                nRoundFeasible++;
+#endif
+		if (!nodes||bestColumn<0) {
+		  // Round all the fractional variables
+		  for (int i = 0; i < numberIntegers; i++) {
+                    int iColumn = integerVariable[i];
+                    double value = newSolution[iColumn];
+                    if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+		      assert(downLocks_[i] == 0 || upLocks_[i] == 0);
+		      if (downLocks_[i] == 0 && upLocks_[i] == 0) {
+			if (direction * objective[iColumn] >= 0.0)
+			  newSolution[iColumn] = floor(value);
+			else
+			  newSolution[iColumn] = ceil(value);
+		      } else if (downLocks_[i] == 0)
+			newSolution[iColumn] = floor(value);
+		      else
+			newSolution[iColumn] = ceil(value);
+                    }
+		  }
+		  break;
+		} else {
+		  // can't round if going to use in branching
+		  int i;
+		  for (i = 0; i < numberIntegers; i++) {
+		    int iColumn = integerVariable[i];
+		    double value = newSolution[bestColumn];
+		    if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+		      if (iColumn==bestColumn) {
+			assert(downLocks_[i] == 0 || upLocks_[i] == 0);
+			double obj = objective[bestColumn];
+			if (downLocks_[i] == 0 && upLocks_[i] == 0) {
+			  if (direction * obj >= 0.0)
+                            bestRound=-1;
+			  else
+                            bestRound=1;
+			} else if (downLocks_[i] == 0)
+			  bestRound=-1;
+			else
+			  bestRound=1;
+			break;
+		      }
+		    }
+		  }
+		}
+	    }
+#ifdef DIVE_DEBUG
+            else
+                nRoundInfeasible++;
+#endif
+        }
+
+        // do reduced cost fixing
+#ifdef DIVE_DEBUG
+        int numberFixed = reducedCostFix(solver);
+        std::cout << "numberReducedCostFixed = " << numberFixed << std::endl;
+#else
+        reducedCostFix(solver);
+#endif
+
+        int numberAtBoundFixed = 0;
+#ifdef DIVE_FIX_BINARY_VARIABLES
+        // fix binary variables based on pseudo reduced cost
+        if (binVarIndex_.size()) {
+            int cnt = 0;
+            int n = static_cast<int>(binVarIndex_.size());
+            for (int j = 0; j < n; j++) {
+                int iColumn1 = binVarIndex_[j];
+                double value = newSolution[iColumn1];
+                if (fabs(value) <= integerTolerance &&
+                        lower[iColumn1] != upper[iColumn1]) {
+                    double maxPseudoReducedCost = 0.0;
+#ifdef DIVE_DEBUG
+                    std::cout << "iColumn1 = " << iColumn1 << ", value = " << value << std::endl;
+#endif
+                    int iRow = vbRowIndex_[j];
+                    double chosenValue = 0.0;
+                    for (int k = rowStart[iRow]; k < rowStart[iRow] + rowLength[iRow]; k++) {
+                        int iColumn2 = column[k];
+#ifdef DIVE_DEBUG
+                        std::cout << "iColumn2 = " << iColumn2 << std::endl;
+#endif
+                        if (iColumn1 != iColumn2) {
+                            double pseudoReducedCost = fabs(reducedCost[iColumn2] *
+                                                            elementByRow[k]);
+#ifdef DIVE_DEBUG
+                            int k2;
+                            for (k2 = rowStart[iRow]; k2 < rowStart[iRow] + rowLength[iRow]; k2++) {
+                                if (column[k2] == iColumn1)
+                                    break;
+                            }
+                            std::cout << "reducedCost[" << iColumn2 << "] = "
+                                      << reducedCost[iColumn2]
+                                      << ", elementByRow[" << iColumn2 << "] = " << elementByRow[k]
+                                      << ", elementByRow[" << iColumn1 << "] = " << elementByRow[k2]
+                                      << ", pseudoRedCost = " << pseudoReducedCost
+                                      << std::endl;
+#endif
+                            if (pseudoReducedCost > maxPseudoReducedCost)
+                                maxPseudoReducedCost = pseudoReducedCost;
+                        } else {
+                            // save value
+                            chosenValue = fabs(elementByRow[k]);
+                        }
+                    }
+                    assert (chosenValue);
+                    maxPseudoReducedCost /= chosenValue;
+#ifdef DIVE_DEBUG
+                    std::cout << ", maxPseudoRedCost = " << maxPseudoReducedCost << std::endl;
+#endif
+                    candidate[cnt].var = iColumn1;
+                    candidate[cnt++].pseudoRedCost = maxPseudoReducedCost;
+                }
+            }
+#ifdef DIVE_DEBUG
+            std::cout << "candidates for rounding = " << cnt << std::endl;
+#endif
+            std::sort(candidate, candidate + cnt, compareBinaryVars);
+            for (int i = 0; i < cnt; i++) {
+                int iColumn = candidate[i].var;
+                if (numberAtBoundFixed < maxNumberAtBoundToFix) {
+                    columnFixed[numberAtBoundFixed] = iColumn;
+                    originalBound[numberAtBoundFixed] = upper[iColumn];
+                    fixedAtLowerBound[numberAtBoundFixed] = true;
+                    solver->setColUpper(iColumn, lower[iColumn]);
+                    numberAtBoundFixed++;
+                    if (numberAtBoundFixed == maxNumberAtBoundToFix)
+                        break;
+                }
+            }
+        }
+#endif
+
+        // fix other integer variables that are at their bounds
+        int cnt = 0;
+#ifdef GAP
+        double gap = 1.0e30;
+#endif
+        if (reducedCost && true) {
+#ifndef JJF_ONE
+            cnt = fixOtherVariables(solver, solution, candidate, random);
+#else
+#ifdef GAP
+            double cutoff = model_->getCutoff() ;
+            if (cutoff < 1.0e20 && false) {
+                double direction = solver->getObjSense() ;
+                gap = cutoff - solver->getObjValue() * direction ;
+                gap *= 0.1; // Fix more if plausible
+                double tolerance;
+                solver->getDblParam(OsiDualTolerance, tolerance) ;
+                if (gap <= 0.0)
+                    gap = tolerance;
+                gap += 100.0 * tolerance;
+            }
+            int nOverGap = 0;
+#endif
+            int numberFree = 0;
+            int numberFixed = 0;
+            for (int i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                if (upper[iColumn] > lower[iColumn]) {
+                    numberFree++;
+                    double value = newSolution[iColumn];
+                    if (fabs(floor(value + 0.5) - value) <= integerTolerance) {
+                        candidate[cnt].var = iColumn;
+                        candidate[cnt++].pseudoRedCost =
+                            fabs(reducedCost[iColumn] * random[i]);
+#ifdef GAP
+                        if (fabs(reducedCost[iColumn]) > gap)
+                            nOverGap++;
+#endif
+                    }
+                } else {
+                    numberFixed++;
+                }
+            }
+#ifdef GAP
+            int nLeft = maxNumberAtBoundToFix - numberAtBoundFixed;
+#ifdef CLP_INVESTIGATE4
+            printf("cutoff %g obj %g nover %d - %d free, %d fixed\n",
+                   cutoff, solver->getObjValue(), nOverGap, numberFree, numberFixed);
+#endif
+            if (nOverGap > nLeft && true) {
+                nOverGap = CoinMin(nOverGap, nLeft + maxNumberAtBoundToFix / 2);
+                maxNumberAtBoundToFix += nOverGap - nLeft;
+            }
+#else
+#ifdef CLP_INVESTIGATE4
+            printf("cutoff %g obj %g - %d free, %d fixed\n",
+                   model_->getCutoff(), solver->getObjValue(), numberFree, numberFixed);
+#endif
+#endif
+#endif
+        } else {
+            for (int i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                if (upper[iColumn] > lower[iColumn]) {
+                    double value = newSolution[iColumn];
+                    if (fabs(floor(value + 0.5) - value) <= integerTolerance) {
+                        candidate[cnt].var = iColumn;
+                        candidate[cnt++].pseudoRedCost = numberIntegers - i;
+                    }
+                }
+            }
+        }
+        std::sort(candidate, candidate + cnt, compareBinaryVars);
+        for (int i = 0; i < cnt; i++) {
+            int iColumn = candidate[i].var;
+            if (upper[iColumn] > lower[iColumn]) {
+                double value = newSolution[iColumn];
+                if (fabs(floor(value + 0.5) - value) <= integerTolerance &&
+                        numberAtBoundFixed < maxNumberAtBoundToFix) {
+                    // fix the variable at one of its bounds
+                    if (fabs(lower[iColumn] - value) <= integerTolerance) {
+                        columnFixed[numberAtBoundFixed] = iColumn;
+                        originalBound[numberAtBoundFixed] = upper[iColumn];
+                        fixedAtLowerBound[numberAtBoundFixed] = true;
+                        solver->setColUpper(iColumn, lower[iColumn]);
+                        numberAtBoundFixed++;
+                    } else if (fabs(upper[iColumn] - value) <= integerTolerance) {
+                        columnFixed[numberAtBoundFixed] = iColumn;
+                        originalBound[numberAtBoundFixed] = lower[iColumn];
+                        fixedAtLowerBound[numberAtBoundFixed] = false;
+                        solver->setColLower(iColumn, upper[iColumn]);
+                        numberAtBoundFixed++;
+                    }
+                    if (numberAtBoundFixed == maxNumberAtBoundToFix)
+                        break;
+                }
+            }
+        }
+#ifdef DIVE_DEBUG
+        std::cout << "numberAtBoundFixed = " << numberAtBoundFixed << std::endl;
+#endif
+
+        double originalBoundBestColumn;
+        double bestColumnValue;
+	int whichWay;
+        if (bestColumn >= 0) {
+	    bestColumnValue = newSolution[bestColumn];
+            if (bestRound < 0) {
+                originalBoundBestColumn = upper[bestColumn];
+                solver->setColUpper(bestColumn, floor(bestColumnValue));
+		whichWay=0;
+            } else {
+                originalBoundBestColumn = lower[bestColumn];
+                solver->setColLower(bestColumn, ceil(bestColumnValue));
+		whichWay=1;
+            }
+        } else {
+            break;
+        }
+        int originalBestRound = bestRound;
+        int saveModelOptions = model_->specialOptions();
+	
+        while (1) {
+
+            model_->setSpecialOptions(saveModelOptions | 2048);
+            solver->resolve();
+            model_->setSpecialOptions(saveModelOptions);
+            if (!solver->isAbandoned()&&!solver->isIterationLimitReached()) {
+                numberSimplexIterations += solver->getIterationCount();
+            } else {
+                numberSimplexIterations = maxSimplexIterations + 1;
+		reasonToStop += 100;
+                break;
+            }
+
+            if (!solver->isProvenOptimal()) {
+	        if (nodes) {
+		  if (solver->isProvenPrimalInfeasible()) {
+		    if (maxSimplexIterationsAtRoot_!=COIN_INT_MAX) {
+		      // stop now
+		      printf("stopping on first infeasibility\n");
+		      break;
+		    } else if (cuts) {
+		      // can do conflict cut
+		      printf("could do intermediate conflict cut\n");
+		      bool localCut;
+		      OsiRowCut * cut = model_->conflictCut(solver,localCut);
+		      if (cut) {
+			if (!localCut) {
+			  model_->makePartialCut(cut,solver);
+			  cuts[numberCuts++]=cut;
+			} else {
+			  delete cut;
+			}
+		      }
+		    }
+		  } else {
+		    reasonToStop += 10;
+		    break;
+		  }
+		}
+                if (numberAtBoundFixed > 0) {
+                    // Remove the bound fix for variables that were at bounds
+                    for (int i = 0; i < numberAtBoundFixed; i++) {
+                        int iColFixed = columnFixed[i];
+                        if (fixedAtLowerBound[i])
+                            solver->setColUpper(iColFixed, originalBound[i]);
+                        else
+                            solver->setColLower(iColFixed, originalBound[i]);
+                    }
+                    numberAtBoundFixed = 0;
+                } else if (bestRound == originalBestRound) {
+                    bestRound *= (-1);
+		    whichWay |=2;
+                    if (bestRound < 0) {
+                        solver->setColLower(bestColumn, originalBoundBestColumn);
+                        solver->setColUpper(bestColumn, floor(bestColumnValue));
+                    } else {
+                        solver->setColLower(bestColumn, ceil(bestColumnValue));
+                        solver->setColUpper(bestColumn, originalBoundBestColumn);
+                    }
+                } else
+                    break;
+            } else
+                break;
+        }
+
+        if (!solver->isProvenOptimal() ||
+                direction*solver->getObjValue() >= solutionValue) {
+            reasonToStop += 1;
+        } else if (iteration > maxIterations_) {
+            reasonToStop += 2;
+        } else if (CoinCpuTime() - time1 > maxTime_) {
+            reasonToStop += 3;
+        } else if (numberSimplexIterations > maxSimplexIterations) {
+            reasonToStop += 4;
+            // also switch off
+#ifdef CLP_INVESTIGATE
+            printf("switching off diving as too many iterations %d, %d allowed\n",
+                   numberSimplexIterations, maxSimplexIterations);
+#endif
+            when_ = 0;
+        } else if (solver->getIterationCount() > 1000 && iteration > 3 && !nodes) {
+            reasonToStop += 5;
+            // also switch off
+#ifdef CLP_INVESTIGATE
+            printf("switching off diving one iteration took %d iterations (total %d)\n",
+                   solver->getIterationCount(), numberSimplexIterations);
+#endif
+            when_ = 0;
+        }
+
+        memcpy(newSolution, solution, numberColumns*sizeof(double));
+        numberFractionalVariables = 0;
+	double sumFractionalVariables=0.0;
+        for (int i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            double value = newSolution[iColumn];
+	    double away = fabs(floor(value + 0.5) - value);
+            if (away > integerTolerance) {
+                numberFractionalVariables++;
+		sumFractionalVariables += away;
+            }
+        }
+	if (nodes) {
+	  // save information
+	  //branchValues[numberNodes]=bestColumnValue;
+	  //statuses[numberNodes]=whichWay+(bestColumn<<2);
+	  //bases[numberNodes]=solver->getWarmStart();
+	  ClpSimplex * simplex = clpSolver->getModelPtr();
+	  CbcSubProblem * sub =
+	    new CbcSubProblem(clpSolver,lowerBefore,upperBefore,
+			  simplex->statusArray(),numberNodes);
+	  nodes[numberNodes]=sub;
+	  // other stuff
+	  sub->branchValue_=bestColumnValue;
+	  sub->problemStatus_=whichWay;
+	  sub->branchVariable_=bestColumn;
+	  sub->objectiveValue_ = simplex->objectiveValue();
+	  sub->sumInfeasibilities_ = sumFractionalVariables;
+	  sub->numberInfeasibilities_ = numberFractionalVariables;
+	  printf("DiveNode %d column %d way %d bvalue %g obj %g\n",
+		 numberNodes,sub->branchVariable_,sub->problemStatus_,
+		 sub->branchValue_,sub->objectiveValue_);
+	  numberNodes++;
+	  if (solver->isProvenOptimal()) {
+	    memcpy(lastDjs,solver->getReducedCost(),numberColumns*sizeof(double));
+	    memcpy(lowerBefore,lower,numberColumns*sizeof(double));
+	    memcpy(upperBefore,upper,numberColumns*sizeof(double));
+	  }
+	}
+	if (!numberFractionalVariables||reasonToStop)
+	  break;
+    }
+    if (nodes) {
+      printf("Exiting dive for reason %d\n",reasonToStop);
+      if (reasonToStop>1) {
+	printf("problems in diving\n");
+	int whichWay=nodes[numberNodes-1]->problemStatus_;
+	CbcSubProblem * sub;
+	if ((whichWay&2)==0) {
+	  // leave both ways
+	  sub = new CbcSubProblem(*nodes[numberNodes-1]);
+	  nodes[numberNodes++]=sub;
+	} else {
+	  sub = nodes[numberNodes-1];
+	}
+	if ((whichWay&1)==0)
+	  sub->problemStatus_=whichWay|1;
+	else
+	  sub->problemStatus_=whichWay&~1;
+      }
+      if (!numberNodes) {
+	// was good at start! - create fake
+	clpSolver->resolve();
+	ClpSimplex * simplex = clpSolver->getModelPtr();
+	CbcSubProblem * sub =
+	  new CbcSubProblem(clpSolver,lowerBefore,upperBefore,
+			    simplex->statusArray(),numberNodes);
+	nodes[numberNodes]=sub;
+	// other stuff
+	sub->branchValue_=0.0;
+	sub->problemStatus_=0;
+	sub->branchVariable_=-1;
+	sub->objectiveValue_ = simplex->objectiveValue();
+	sub->sumInfeasibilities_ = 0.0;
+	sub->numberInfeasibilities_ = 0;
+	printf("DiveNode %d column %d way %d bvalue %g obj %g\n",
+	       numberNodes,sub->branchVariable_,sub->problemStatus_,
+	       sub->branchValue_,sub->objectiveValue_);
+	numberNodes++;
+	assert (solver->isProvenOptimal());
+      }
+      nodes[numberNodes-1]->problemStatus_ |= 256*reasonToStop;
+      // use djs as well
+      if (solver->isProvenPrimalInfeasible()&&cuts) {
+	// can do conflict cut and re-order
+	printf("could do final conflict cut\n");
+	bool localCut;
+	OsiRowCut * cut = model_->conflictCut(solver,localCut);
+	if (cut) {
+	  printf("cut - need to use conflict and previous djs\n");
+	  if (!localCut) {
+	    model_->makePartialCut(cut,solver);
+	    cuts[numberCuts++]=cut;
+	  } else {
+	    delete cut;
+	  }
+	} else {
+	  printf("bad conflict - just use previous djs\n");
+	}
+      }
+    }
+    
+    // re-compute new solution value
+    double objOffset = 0.0;
+    solver->getDblParam(OsiObjOffset, objOffset);
+    newSolutionValue = -objOffset;
+    for (int i = 0 ; i < numberColumns ; i++ )
+      newSolutionValue += objective[i] * newSolution[i];
+    newSolutionValue *= direction;
+    //printf("new solution value %g %g\n",newSolutionValue,solutionValue);
+    if (newSolutionValue < solutionValue && !reasonToStop) {
+      double * rowActivity = new double[numberRows];
+      memset(rowActivity, 0, numberRows*sizeof(double));
+      // paranoid check
+      memset(rowActivity, 0, numberRows*sizeof(double));
+      for (int i = 0; i < numberColumns; i++) {
+	int j;
+	double value = newSolution[i];
+	if (value) {
+	  for (j = columnStart[i];
+	       j < columnStart[i] + columnLength[i]; j++) {
+	    int iRow = row[j];
+	    rowActivity[iRow] += value * element[j];
+	  }
+	}
+      }
+      // check was approximately feasible
+      bool feasible = true;
+      for (int i = 0; i < numberRows; i++) {
+	if (rowActivity[i] < rowLower[i]) {
+	  if (rowActivity[i] < rowLower[i] - 1000.0*primalTolerance)
+	    feasible = false;
+	} else if (rowActivity[i] > rowUpper[i]) {
+	  if (rowActivity[i] > rowUpper[i] + 1000.0*primalTolerance)
+	    feasible = false;
+	}
+      }
+      for (int i = 0; i < numberIntegers; i++) {
+	int iColumn = integerVariable[i];
+	double value = newSolution[iColumn];
+	if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+	  feasible = false;
+	  break;
+	}
+      }
+      if (feasible) {
+	// new solution
+	solutionValue = newSolutionValue;
+	//printf("** Solution of %g found by CbcHeuristicDive\n",newSolutionValue);
+	//if (cuts)
+	//clpSolver->getModelPtr()->writeMps("good8.mps", 2);
+	returnCode = 1;
+      } else {
+	// Can easily happen
+	//printf("Debug CbcHeuristicDive giving bad solution\n");
+      }
+      delete [] rowActivity;
+    }
+
+#ifdef DIVE_DEBUG
+    std::cout << "nRoundInfeasible = " << nRoundInfeasible
+              << ", nRoundFeasible = " << nRoundFeasible
+              << ", returnCode = " << returnCode
+              << ", reasonToStop = " << reasonToStop
+              << ", simplexIts = " << numberSimplexIterations
+              << ", iterations = " << iteration << std::endl;
+#endif
+
+    delete [] columnFixed;
+    delete [] originalBound;
+    delete [] fixedAtLowerBound;
+    delete [] candidate;
+    delete [] random;
+    delete [] downArray_;
+    downArray_ = NULL;
+    delete [] upArray_;
+    upArray_ = NULL;
+    delete solver;
+    return returnCode;
+}
+// See if diving will give better solution
+// Sets value of solution
+// Returns 1 if solution, 0 if not
+int
+CbcHeuristicDive::solution(double & solutionValue,
+                           double * betterSolution)
+{
+    int nodeCount = model_->getNodeCount();
+    if (feasibilityPumpOptions_>0 && (nodeCount % feasibilityPumpOptions_) != 0)
+        return 0;
+#ifdef DIVE_DEBUG
+    std::cout << "solutionValue = " << solutionValue << std::endl;
+#endif
+    ++numCouldRun_;
+
+    // test if the heuristic can run
+    if (!canHeuristicRun())
+        return 0;
+
+#ifdef JJF_ZERO
+    // See if to do
+    if (!when() || (when() % 10 == 1 && model_->phase() != 1) ||
+            (when() % 10 == 2 && (model_->phase() != 2 && model_->phase() != 3)))
+        return 0; // switched off
+#endif
+    // Get solution array for heuristic solution
+    int numberColumns = model_->solver()->getNumCols();
+    double * newSolution = new double [numberColumns];
+    int numberCuts=0;
+    int numberNodes=-1;
+    CbcSubProblem ** nodes=NULL;
+    int returnCode=solution(solutionValue,numberNodes,numberCuts,
+			    NULL,nodes,
+			    newSolution);
+  if (returnCode==1) 
+    memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+
+    delete [] newSolution;
+    return returnCode;
+}
+/* returns 0 if no solution, 1 if valid solution
+   with better objective value than one passed in
+   also returns list of nodes
+   This does Fractional Diving
+*/
+int 
+CbcHeuristicDive::fathom(CbcModel * model, int & numberNodes, 
+			 CbcSubProblem ** & nodes)
+{
+  double solutionValue = model->getCutoff();
+  numberNodes=0;
+  // Get solution array for heuristic solution
+  int numberColumns = model_->solver()->getNumCols();
+  double * newSolution = new double [4*numberColumns];
+  double * lastDjs = newSolution+numberColumns;
+  double * originalLower = lastDjs+numberColumns;
+  double * originalUpper = originalLower+numberColumns;
+  memcpy(originalLower,model_->solver()->getColLower(),
+	 numberColumns*sizeof(double));
+  memcpy(originalUpper,model_->solver()->getColUpper(),
+	 numberColumns*sizeof(double));
+  int numberCuts=0;
+  OsiRowCut ** cuts = NULL; //new OsiRowCut * [maxIterations_];
+  nodes=new CbcSubProblem * [maxIterations_+2];
+  int returnCode=solution(solutionValue,numberNodes,numberCuts,
+			  cuts,nodes,
+			  newSolution);
+
+  if (returnCode==1) {
+    // copy to best solution ? or put in solver
+    printf("Solution from heuristic fathom\n");
+  }
+  int numberFeasibleNodes=numberNodes;
+  if (returnCode!=1)
+    numberFeasibleNodes--;
+  if (numberFeasibleNodes>0) {
+    CoinWarmStartBasis * basis = nodes[numberFeasibleNodes-1]->status_;
+    //double * sort = new double [numberFeasibleNodes];
+    //int * whichNode = new int [numberFeasibleNodes];
+    //int numberNodesNew=0;
+    // use djs on previous unless feasible
+    for (int iNode=0;iNode<numberFeasibleNodes;iNode++) {
+      CbcSubProblem * sub = nodes[iNode];
+      double branchValue = sub->branchValue_;
+      int iStatus=sub->problemStatus_;
+      int iColumn = sub->branchVariable_;
+      bool secondBranch = (iStatus&2)!=0;
+      bool branchUp;
+      if (!secondBranch)
+	branchUp = (iStatus&1)!=0;
+      else
+	branchUp = (iStatus&1)==0;
+      double djValue=lastDjs[iColumn];
+      sub->djValue_=fabs(djValue);
+      if (!branchUp&&floor(branchValue)==originalLower[iColumn]
+	  &&basis->getStructStatus(iColumn) == CoinWarmStartBasis::atLowerBound) {
+	if (djValue>0.0) {
+	  // naturally goes to LB
+	  printf("ignoring branch down on %d (node %d) from value of %g - branch was %s - dj %g\n",
+		 iColumn,iNode,branchValue,secondBranch ? "second" : "first",
+		 djValue);
+	  sub->problemStatus_ |= 4;
+	  //} else {
+	  // put on list
+	  //sort[numberNodesNew]=djValue;
+	  //whichNode[numberNodesNew++]=iNode;
+	}
+      } else if (branchUp&&ceil(branchValue)==originalUpper[iColumn]
+	  &&basis->getStructStatus(iColumn) == CoinWarmStartBasis::atUpperBound) {
+	if (djValue<0.0) {
+	  // naturally goes to UB
+	  printf("ignoring branch up on %d (node %d) from value of %g - branch was %s - dj %g\n",
+		 iColumn,iNode,branchValue,secondBranch ? "second" : "first",
+		 djValue);
+	  sub->problemStatus_ |= 4;
+	  //} else {
+	  // put on list
+	  //sort[numberNodesNew]=-djValue;
+	  //whichNode[numberNodesNew++]=iNode;
+	}
+      }
+    }
+    // use conflict to order nodes
+    for (int iCut=0;iCut<numberCuts;iCut++) {
+    }
+    //CoinSort_2(sort,sort+numberNodesNew,whichNode);
+    // create nodes
+    // last node will have one way already done
+  }
+  for (int iCut=0;iCut<numberCuts;iCut++) {
+    delete cuts[iCut];
+  }
+  delete [] cuts;
+  delete [] newSolution;
+  return returnCode;
+}
+
+// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+void
+CbcHeuristicDive::validate()
+{
+    if (model_ && (when() % 100) < 10) {
+        if (model_->numberIntegers() !=
+                model_->numberObjects() && (model_->numberObjects() ||
+                                            (model_->specialOptions()&1024) == 0)) {
+            int numberOdd = 0;
+            for (int i = 0; i < model_->numberObjects(); i++) {
+                if (!model_->object(i)->canDoHeuristics())
+                    numberOdd++;
+            }
+            if (numberOdd)
+                setWhen(0);
+        }
+    }
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    delete [] downLocks_;
+    delete [] upLocks_;
+    downLocks_ = new unsigned short [numberIntegers];
+    upLocks_ = new unsigned short [numberIntegers];
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+    const double * rowLower = model_->solver()->getRowLower();
+    const double * rowUpper = model_->solver()->getRowUpper();
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        int down = 0;
+        int up = 0;
+        if (columnLength[iColumn] > 65535) {
+            setWhen(0);
+            break; // unlikely to work
+        }
+        for (CoinBigIndex j = columnStart[iColumn];
+                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+            int iRow = row[j];
+            if (rowLower[iRow] > -1.0e20 && rowUpper[iRow] < 1.0e20) {
+                up++;
+                down++;
+            } else if (element[j] > 0.0) {
+                if (rowUpper[iRow] < 1.0e20)
+                    up++;
+                else
+                    down++;
+            } else {
+                if (rowLower[iRow] > -1.0e20)
+                    up++;
+                else
+                    down++;
+            }
+        }
+        downLocks_[i] = static_cast<unsigned short> (down);
+        upLocks_[i] = static_cast<unsigned short> (up);
+    }
+
+#ifdef DIVE_FIX_BINARY_VARIABLES
+    selectBinaryVariables();
+#endif
+}
+
+// Select candidate binary variables for fixing
+void
+CbcHeuristicDive::selectBinaryVariables()
+{
+    // Row copy
+    const double * elementByRow = matrixByRow_.getElements();
+    const int * column = matrixByRow_.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+    const int * rowLength = matrixByRow_.getVectorLengths();
+
+    const int numberRows = matrixByRow_.getNumRows();
+    const int numberCols = matrixByRow_.getNumCols();
+
+    const double * lower = model_->solver()->getColLower();
+    const double * upper = model_->solver()->getColUpper();
+    const double * rowLower = model_->solver()->getRowLower();
+    const double * rowUpper = model_->solver()->getRowUpper();
+
+    //  const char * integerType = model_->integerType();
+
+
+    //  const int numberIntegers = model_->numberIntegers();
+    //  const int * integerVariable = model_->integerVariable();
+    const double * objective = model_->solver()->getObjCoefficients();
+
+    // vector to store the row number of variable bound rows
+    int* rowIndexes = new int [numberCols];
+    memset(rowIndexes, -1, numberCols*sizeof(int));
+
+    for (int i = 0; i < numberRows; i++) {
+        int positiveBinary = -1;
+        int negativeBinary = -1;
+        int nPositiveOther = 0;
+        int nNegativeOther = 0;
+        for (int k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) {
+            int iColumn = column[k];
+            if (model_->solver()->isInteger(iColumn) &&
+                    lower[iColumn] == 0.0 && upper[iColumn] == 1.0 &&
+                    objective[iColumn] == 0.0 &&
+                    elementByRow[k] > 0.0 &&
+                    positiveBinary < 0)
+                positiveBinary = iColumn;
+            else if (model_->solver()->isInteger(iColumn) &&
+                     lower[iColumn] == 0.0 && upper[iColumn] == 1.0 &&
+                     objective[iColumn] == 0.0 &&
+                     elementByRow[k] < 0.0 &&
+                     negativeBinary < 0)
+                negativeBinary = iColumn;
+            else if ((elementByRow[k] > 0.0 &&
+                      lower[iColumn] >= 0.0) ||
+                     (elementByRow[k] < 0.0 &&
+                      upper[iColumn] <= 0.0))
+                nPositiveOther++;
+            else if ((elementByRow[k] > 0.0 &&
+                      lower[iColumn] <= 0.0) ||
+                     (elementByRow[k] < 0.0 &&
+                      upper[iColumn] >= 0.0))
+                nNegativeOther++;
+            if (nPositiveOther > 0 && nNegativeOther > 0)
+                break;
+        }
+        int binVar = -1;
+        if (positiveBinary >= 0 &&
+                (negativeBinary >= 0 || nNegativeOther > 0) &&
+                nPositiveOther == 0 &&
+                rowLower[i] == 0.0 &&
+                rowUpper[i] > 0.0)
+            binVar = positiveBinary;
+        else if (negativeBinary >= 0 &&
+                 (positiveBinary >= 0 || nPositiveOther > 0) &&
+                 nNegativeOther == 0 &&
+                 rowLower[i] < 0.0 &&
+                 rowUpper[i] == 0.0)
+            binVar = negativeBinary;
+        if (binVar >= 0) {
+            if (rowIndexes[binVar] == -1)
+                rowIndexes[binVar] = i;
+            else if (rowIndexes[binVar] >= 0)
+                rowIndexes[binVar] = -2;
+        }
+    }
+
+    for (int j = 0; j < numberCols; j++) {
+        if (rowIndexes[j] >= 0) {
+            binVarIndex_.push_back(j);
+            vbRowIndex_.push_back(rowIndexes[j]);
+        }
+    }
+
+#ifdef DIVE_DEBUG
+    std::cout << "number vub Binary = " << binVarIndex_.size() << std::endl;
+#endif
+
+    delete [] rowIndexes;
+
+}
+
+/*
+  Perform reduced cost fixing on integer variables.
+
+  The variables in question are already nonbasic at bound. We're just nailing
+  down the current situation.
+*/
+
+int CbcHeuristicDive::reducedCostFix (OsiSolverInterface* solver)
+
+{
+    //return 0; // temp
+#ifndef JJF_ONE
+    if (!model_->solverCharacteristics()->reducedCostsAccurate())
+        return 0; //NLP
+#endif
+    double cutoff = model_->getCutoff() ;
+    if (cutoff > 1.0e20)
+        return 0;
+#ifdef DIVE_DEBUG
+    std::cout << "cutoff = " << cutoff << std::endl;
+#endif
+    double direction = solver->getObjSense() ;
+    double gap = cutoff - solver->getObjValue() * direction ;
+    gap *= 0.5; // Fix more
+    double tolerance;
+    solver->getDblParam(OsiDualTolerance, tolerance) ;
+    if (gap <= 0.0)
+        gap = tolerance; //return 0;
+    gap += 100.0 * tolerance;
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    const double *lower = solver->getColLower() ;
+    const double *upper = solver->getColUpper() ;
+    const double *solution = solver->getColSolution() ;
+    const double *reducedCost = solver->getReducedCost() ;
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+
+    int numberFixed = 0 ;
+
+# ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver);
+    ClpSimplex * clpSimplex = NULL;
+    if (clpSolver)
+        clpSimplex = clpSolver->getModelPtr();
+# endif
+    for (int i = 0 ; i < numberIntegers ; i++) {
+        int iColumn = integerVariable[i] ;
+        double djValue = direction * reducedCost[iColumn] ;
+        if (upper[iColumn] - lower[iColumn] > integerTolerance) {
+            if (solution[iColumn] < lower[iColumn] + integerTolerance && djValue > gap) {
+#ifdef COIN_HAS_CLP
+                // may just have been fixed before
+                if (clpSimplex) {
+                    if (clpSimplex->getColumnStatus(iColumn) == ClpSimplex::basic) {
+#ifdef COIN_DEVELOP
+                        printf("DJfix %d has status of %d, dj of %g gap %g, bounds %g %g\n",
+                               iColumn, clpSimplex->getColumnStatus(iColumn),
+                               djValue, gap, lower[iColumn], upper[iColumn]);
+#endif
+                    } else {
+                        assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atLowerBound ||
+                               clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+                    }
+                }
+#endif
+                solver->setColUpper(iColumn, lower[iColumn]) ;
+                numberFixed++ ;
+            } else if (solution[iColumn] > upper[iColumn] - integerTolerance && -djValue > gap) {
+#ifdef COIN_HAS_CLP
+                // may just have been fixed before
+                if (clpSimplex) {
+                    if (clpSimplex->getColumnStatus(iColumn) == ClpSimplex::basic) {
+#ifdef COIN_DEVELOP
+                        printf("DJfix %d has status of %d, dj of %g gap %g, bounds %g %g\n",
+                               iColumn, clpSimplex->getColumnStatus(iColumn),
+                               djValue, gap, lower[iColumn], upper[iColumn]);
+#endif
+                    } else {
+                        assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atUpperBound ||
+                               clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+                    }
+                }
+#endif
+                solver->setColLower(iColumn, upper[iColumn]) ;
+                numberFixed++ ;
+            }
+        }
+    }
+    return numberFixed;
+}
+// Fix other variables at bounds
+int
+CbcHeuristicDive::fixOtherVariables(OsiSolverInterface * solver,
+                                    const double * solution,
+                                    PseudoReducedCost * candidate,
+                                    const double * random)
+{
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    const double* reducedCost = solver->getReducedCost();
+    // fix other integer variables that are at their bounds
+    int cnt = 0;
+#ifdef GAP
+    double direction = solver->getObjSense(); // 1 for min, -1 for max
+    double gap = 1.0e30;
+#endif
+#ifdef GAP
+    double cutoff = model_->getCutoff() ;
+    if (cutoff < 1.0e20 && false) {
+        double direction = solver->getObjSense() ;
+        gap = cutoff - solver->getObjValue() * direction ;
+        gap *= 0.1; // Fix more if plausible
+        double tolerance;
+        solver->getDblParam(OsiDualTolerance, tolerance) ;
+        if (gap <= 0.0)
+            gap = tolerance;
+        gap += 100.0 * tolerance;
+    }
+    int nOverGap = 0;
+#endif
+    int numberFree = 0;
+    int numberFixedAlready = 0;
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        if (upper[iColumn] > lower[iColumn]) {
+            numberFree++;
+            double value = solution[iColumn];
+            if (fabs(floor(value + 0.5) - value) <= integerTolerance) {
+                candidate[cnt].var = iColumn;
+                candidate[cnt++].pseudoRedCost =
+                    fabs(reducedCost[iColumn] * random[i]);
+#ifdef GAP
+                if (fabs(reducedCost[iColumn]) > gap)
+                    nOverGap++;
+#endif
+            }
+        } else {
+            numberFixedAlready++;
+        }
+    }
+#ifdef GAP
+    int nLeft = maxNumberToFix - numberFixedAlready;
+#ifdef CLP_INVESTIGATE4
+    printf("cutoff %g obj %g nover %d - %d free, %d fixed\n",
+           cutoff, solver->getObjValue(), nOverGap, numberFree,
+           numberFixedAlready);
+#endif
+    if (nOverGap > nLeft && true) {
+        nOverGap = CoinMin(nOverGap, nLeft + maxNumberToFix / 2);
+        maxNumberToFix += nOverGap - nLeft;
+    }
+#else
+#ifdef CLP_INVESTIGATE4
+    printf("cutoff %g obj %g - %d free, %d fixed\n",
+           model_->getCutoff(), solver->getObjValue(), numberFree,
+           numberFixedAlready);
+#endif
+#endif
+    return cnt;
+}
+
diff --git a/cbits/coin/CbcHeuristicDive.hpp b/cbits/coin/CbcHeuristicDive.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDive.hpp
@@ -0,0 +1,180 @@
+/* $Id: CbcHeuristicDive.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicDive_H
+#define CbcHeuristicDive_H
+
+#include "CbcHeuristic.hpp"
+class CbcSubProblem;
+class OsiRowCut;
+struct PseudoReducedCost {
+    int var;
+    double pseudoRedCost;
+};
+
+
+/** Dive class
+ */
+
+class CbcHeuristicDive : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicDive ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicDive (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDive ( const CbcHeuristicDive &);
+
+    // Destructor
+    ~CbcHeuristicDive ();
+
+    /// Clone
+    virtual CbcHeuristicDive * clone() const = 0;
+
+    /// Assignment operator
+    CbcHeuristicDive & operator=(const CbcHeuristicDive& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+
+    /// Create C++ lines to get to current state - does work for base class
+    void generateCpp( FILE * fp, const char * heuristic);
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    //  REMLOVE using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution
+        with better objective value than one passed in
+        Sets solution values if good, sets objective value (only if good)
+        This is called after cuts have been added - so can not add cuts
+        This does Fractional Diving
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// inner part of dive
+  int solution(double & objectiveValue, int & numberNodes,
+		 int & numberCuts, OsiRowCut ** cuts,
+		 CbcSubProblem ** & nodes,
+		 double * newSolution);
+    /** returns 0 if no solution, 1 if valid solution
+        with better objective value than one passed in
+	also returns list of nodes
+        This does Fractional Diving
+    */
+    int fathom(CbcModel * model, int & numberNodes,CbcSubProblem ** & nodes);
+
+    /// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+    virtual void validate();
+
+    /// Select candidate binary variables for fixing
+    void selectBinaryVariables();
+
+    /// Set percentage of integer variables to fix at bounds
+    void setPercentageToFix(double value) {
+        percentageToFix_ = value;
+    }
+
+    /// Set maximum number of iterations
+    void setMaxIterations(int value) {
+        maxIterations_ = value;
+    }
+
+    /// Set maximum number of simplex iterations
+    void setMaxSimplexIterations(int value) {
+        maxSimplexIterations_ = value;
+    }
+    /// Get maximum number of simplex iterations
+    inline int maxSimplexIterations() const {
+        return maxSimplexIterations_;
+    }
+
+    /// Set maximum number of simplex iterations at root node
+    void setMaxSimplexIterationsAtRoot(int value) {
+        maxSimplexIterationsAtRoot_ = value;
+    }
+
+    /// Set maximum time allowed
+    void setMaxTime(double value) {
+        maxTime_ = value;
+    }
+
+    /// Tests if the heuristic can run
+    virtual bool canHeuristicRun();
+
+    /** Selects the next variable to branch on
+        Returns true if all the fractional variables can be trivially
+        rounded. Returns false, if there is at least one fractional variable
+        that is not trivially roundable. In this case, the bestColumn
+        returned will not be trivially roundable.
+    */
+    virtual bool selectVariableToBranch(OsiSolverInterface* solver,
+                                        const double* newSolution,
+                                        int& bestColumn,
+                                        int& bestRound) = 0;
+    /** Initializes any data which is going to be used repeatedly
+        in selectVariableToBranch */
+    virtual void initializeData() {}
+
+    /// Perform reduced cost fixing on integer variables
+    int reducedCostFix (OsiSolverInterface* solver);
+    /// Fix other variables at bounds
+    virtual int fixOtherVariables(OsiSolverInterface * solver,
+                                  const double * solution,
+                                  PseudoReducedCost * candidate,
+                                  const double * random);
+
+protected:
+    // Data
+
+    // Original matrix by column
+    CoinPackedMatrix matrix_;
+
+    // Original matrix by
+    CoinPackedMatrix matrixByRow_;
+
+    // Down locks
+    unsigned short * downLocks_;
+
+    // Up locks
+    unsigned short * upLocks_;
+
+    /// Extra down array (number Integers long)
+    double * downArray_;
+
+    /// Extra up array (number Integers long)
+    double * upArray_;
+
+    // Indexes of binary variables with 0 objective coefficient
+    // and in variable bound constraints
+    std::vector<int> binVarIndex_;
+
+    // Indexes of variable bound rows for each binary variable
+    std::vector<int> vbRowIndex_;
+
+    // Percentage of integer variables to fix at bounds
+    double percentageToFix_;
+
+    // Maximum number of major iterations
+    int maxIterations_;
+
+    // Maximum number of simplex iterations
+    int maxSimplexIterations_;
+
+    // Maximum number of simplex iterations at root node
+    int maxSimplexIterationsAtRoot_;
+
+    // Maximum time allowed
+    double maxTime_;
+
+};
+#endif
+
diff --git a/cbits/coin/CbcHeuristicDiveCoefficient.cpp b/cbits/coin/CbcHeuristicDiveCoefficient.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveCoefficient.cpp
@@ -0,0 +1,131 @@
+/* $Id: CbcHeuristicDiveCoefficient.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+//#define PRINT_DEBUG
+
+#include "CbcHeuristicDiveCoefficient.hpp"
+#include "CbcStrategy.hpp"
+
+// Default Constructor
+CbcHeuristicDiveCoefficient::CbcHeuristicDiveCoefficient()
+        : CbcHeuristicDive()
+{
+}
+
+// Constructor from model
+CbcHeuristicDiveCoefficient::CbcHeuristicDiveCoefficient(CbcModel & model)
+        : CbcHeuristicDive(model)
+{
+}
+
+// Destructor
+CbcHeuristicDiveCoefficient::~CbcHeuristicDiveCoefficient ()
+{
+}
+
+// Clone
+CbcHeuristicDiveCoefficient *
+CbcHeuristicDiveCoefficient::clone() const
+{
+    return new CbcHeuristicDiveCoefficient(*this);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicDiveCoefficient::generateCpp( FILE * fp)
+{
+    CbcHeuristicDiveCoefficient other;
+    fprintf(fp, "0#include \"CbcHeuristicDiveCoefficient.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicDiveCoefficient heuristicDiveCoefficient(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicDiveCoefficient");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicDiveCoefficient);\n");
+}
+
+// Copy constructor
+CbcHeuristicDiveCoefficient::CbcHeuristicDiveCoefficient(const CbcHeuristicDiveCoefficient & rhs)
+        :
+        CbcHeuristicDive(rhs)
+{
+}
+
+// Assignment operator
+CbcHeuristicDiveCoefficient &
+CbcHeuristicDiveCoefficient::operator=( const CbcHeuristicDiveCoefficient & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristicDive::operator=(rhs);
+    }
+    return *this;
+}
+
+bool
+CbcHeuristicDiveCoefficient::selectVariableToBranch(OsiSolverInterface* solver,
+        const double* newSolution,
+        int& bestColumn,
+        int& bestRound)
+{
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    bestColumn = -1;
+    bestRound = -1; // -1 rounds down, +1 rounds up
+    double bestFraction = COIN_DBL_MAX;
+    int bestLocks = COIN_INT_MAX;
+    bool allTriviallyRoundableSoFar = true;
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = newSolution[iColumn];
+        double fraction = value - floor(value);
+        int round = 0;
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            int nDownLocks = downLocks_[i];
+            int nUpLocks = upLocks_[i];
+            if (allTriviallyRoundableSoFar || (nDownLocks > 0 && nUpLocks > 0)) {
+
+                if (allTriviallyRoundableSoFar && nDownLocks > 0 && nUpLocks > 0) {
+                    allTriviallyRoundableSoFar = false;
+                    bestFraction = COIN_DBL_MAX;
+                    bestLocks = COIN_INT_MAX;
+                }
+
+                // the variable cannot be rounded
+                int nLocks = nDownLocks;
+                if (nDownLocks < nUpLocks)
+                    round = -1;
+                else if (nDownLocks > nUpLocks) {
+                    round = 1;
+                    fraction = 1.0 - fraction;
+                    nLocks = nUpLocks;
+                } else if (fraction < 0.5)
+                    round = -1;
+                else {
+                    round = 1;
+                    fraction = 1.0 - fraction;
+                    nLocks = nUpLocks;
+                }
+
+                // if variable is not binary, penalize it
+                if (!solver->isBinary(iColumn))
+                    fraction *= 1000.0;
+
+                if (nLocks < bestLocks || (nLocks == bestLocks &&
+                                           fraction < bestFraction)) {
+                    bestColumn = iColumn;
+                    bestLocks = nLocks;
+                    bestFraction = fraction;
+                    bestRound = round;
+                }
+            }
+        }
+    }
+    return allTriviallyRoundableSoFar;
+}
+
diff --git a/cbits/coin/CbcHeuristicDiveCoefficient.hpp b/cbits/coin/CbcHeuristicDiveCoefficient.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveCoefficient.hpp
@@ -0,0 +1,52 @@
+/* $Id: CbcHeuristicDiveCoefficient.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicDiveCoefficient_H
+#define CbcHeuristicDiveCoefficient_H
+
+#include "CbcHeuristicDive.hpp"
+
+/** DiveCoefficient class
+ */
+
+class CbcHeuristicDiveCoefficient : public CbcHeuristicDive {
+public:
+
+    // Default Constructor
+    CbcHeuristicDiveCoefficient ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicDiveCoefficient (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDiveCoefficient ( const CbcHeuristicDiveCoefficient &);
+
+    // Destructor
+    ~CbcHeuristicDiveCoefficient ();
+
+    /// Clone
+    virtual CbcHeuristicDiveCoefficient * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicDiveCoefficient & operator=(const CbcHeuristicDiveCoefficient& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Selects the next variable to branch on
+    /** Returns true if all the fractional variables can be trivially
+        rounded. Returns false, if there is at least one fractional variable
+        that is not trivially roundable. In this case, the bestColumn
+        returned will not be trivially roundable.
+    */
+    virtual bool selectVariableToBranch(OsiSolverInterface* solver,
+                                        const double* newSolution,
+                                        int& bestColumn,
+                                        int& bestRound);
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicDiveFractional.cpp b/cbits/coin/CbcHeuristicDiveFractional.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveFractional.cpp
@@ -0,0 +1,115 @@
+/* $Id: CbcHeuristicDiveFractional.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcHeuristicDiveFractional.hpp"
+#include "CbcStrategy.hpp"
+
+// Default Constructor
+CbcHeuristicDiveFractional::CbcHeuristicDiveFractional()
+        : CbcHeuristicDive()
+{
+}
+
+// Constructor from model
+CbcHeuristicDiveFractional::CbcHeuristicDiveFractional(CbcModel & model)
+        : CbcHeuristicDive(model)
+{
+}
+
+// Destructor
+CbcHeuristicDiveFractional::~CbcHeuristicDiveFractional ()
+{
+}
+
+// Clone
+CbcHeuristicDiveFractional *
+CbcHeuristicDiveFractional::clone() const
+{
+    return new CbcHeuristicDiveFractional(*this);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicDiveFractional::generateCpp( FILE * fp)
+{
+    CbcHeuristicDiveFractional other;
+    fprintf(fp, "0#include \"CbcHeuristicDiveFractional.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicDiveFractional heuristicDiveFractional(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicDiveFractional");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicDiveFractional);\n");
+}
+
+// Copy constructor
+CbcHeuristicDiveFractional::CbcHeuristicDiveFractional(const CbcHeuristicDiveFractional & rhs)
+        :
+        CbcHeuristicDive(rhs)
+{
+}
+
+// Assignment operator
+CbcHeuristicDiveFractional &
+CbcHeuristicDiveFractional::operator=( const CbcHeuristicDiveFractional & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristicDive::operator=(rhs);
+    }
+    return *this;
+}
+
+bool
+CbcHeuristicDiveFractional::selectVariableToBranch(OsiSolverInterface* solver,
+        const double* newSolution,
+        int& bestColumn,
+        int& bestRound)
+{
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    bestColumn = -1;
+    bestRound = -1; // -1 rounds down, +1 rounds up
+    double bestFraction = COIN_DBL_MAX;
+    bool allTriviallyRoundableSoFar = true;
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = newSolution[iColumn];
+        double fraction = value - floor(value);
+        int round = 0;
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            if (allTriviallyRoundableSoFar || (downLocks_[i] > 0 && upLocks_[i] > 0)) {
+
+                if (allTriviallyRoundableSoFar && downLocks_[i] > 0 && upLocks_[i] > 0) {
+                    allTriviallyRoundableSoFar = false;
+                    bestFraction = COIN_DBL_MAX;
+                }
+
+                // the variable cannot be rounded
+                if (fraction < 0.5)
+                    round = -1;
+                else {
+                    round = 1;
+                    fraction = 1.0 - fraction;
+                }
+
+                // if variable is not binary, penalize it
+                if (!solver->isBinary(iColumn))
+                    fraction *= 1000.0;
+
+                if (fraction < bestFraction) {
+                    bestColumn = iColumn;
+                    bestFraction = fraction;
+                    bestRound = round;
+                }
+            }
+        }
+    }
+    return allTriviallyRoundableSoFar;
+}
+
diff --git a/cbits/coin/CbcHeuristicDiveFractional.hpp b/cbits/coin/CbcHeuristicDiveFractional.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveFractional.hpp
@@ -0,0 +1,52 @@
+/* $Id: CbcHeuristicDiveFractional.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicDiveFractional_H
+#define CbcHeuristicDiveFractional_H
+
+#include "CbcHeuristicDive.hpp"
+
+/** DiveFractional class
+ */
+
+class CbcHeuristicDiveFractional : public CbcHeuristicDive {
+public:
+
+    // Default Constructor
+    CbcHeuristicDiveFractional ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicDiveFractional (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDiveFractional ( const CbcHeuristicDiveFractional &);
+
+    // Destructor
+    ~CbcHeuristicDiveFractional ();
+
+    /// Clone
+    virtual CbcHeuristicDiveFractional * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicDiveFractional & operator=(const CbcHeuristicDiveFractional& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Selects the next variable to branch on
+    /** Returns true if all the fractional variables can be trivially
+        rounded. Returns false, if there is at least one fractional variable
+        that is not trivially roundable. In this case, the bestColumn
+        returned will not be trivially roundable.
+    */
+    virtual bool selectVariableToBranch(OsiSolverInterface* solver,
+                                        const double* newSolution,
+                                        int& bestColumn,
+                                        int& bestRound);
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicDiveGuided.cpp b/cbits/coin/CbcHeuristicDiveGuided.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveGuided.cpp
@@ -0,0 +1,126 @@
+/* $Id: CbcHeuristicDiveGuided.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcHeuristicDiveGuided.hpp"
+#include "CbcStrategy.hpp"
+
+// Default Constructor
+CbcHeuristicDiveGuided::CbcHeuristicDiveGuided()
+        : CbcHeuristicDive()
+{
+}
+
+// Constructor from model
+CbcHeuristicDiveGuided::CbcHeuristicDiveGuided(CbcModel & model)
+        : CbcHeuristicDive(model)
+{
+}
+
+// Destructor
+CbcHeuristicDiveGuided::~CbcHeuristicDiveGuided ()
+{
+}
+
+// Clone
+CbcHeuristicDiveGuided *
+CbcHeuristicDiveGuided::clone() const
+{
+    return new CbcHeuristicDiveGuided(*this);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicDiveGuided::generateCpp( FILE * fp)
+{
+    CbcHeuristicDiveGuided other;
+    fprintf(fp, "0#include \"CbcHeuristicDiveGuided.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicDiveGuided heuristicDiveGuided(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicDiveGuided");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicDiveGuided);\n");
+}
+
+// Copy constructor
+CbcHeuristicDiveGuided::CbcHeuristicDiveGuided(const CbcHeuristicDiveGuided & rhs)
+        :
+        CbcHeuristicDive(rhs)
+{
+}
+
+// Assignment operator
+CbcHeuristicDiveGuided &
+CbcHeuristicDiveGuided::operator=( const CbcHeuristicDiveGuided & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristicDive::operator=(rhs);
+    }
+    return *this;
+}
+
+bool
+CbcHeuristicDiveGuided::canHeuristicRun()
+{
+    double* bestIntegerSolution = model_->bestSolution();
+    if (bestIntegerSolution == NULL)
+        return false; // no integer solution available. Switch off heuristic
+
+    return CbcHeuristicDive::canHeuristicRun();
+}
+
+bool
+CbcHeuristicDiveGuided::selectVariableToBranch(OsiSolverInterface* solver,
+        const double* newSolution,
+        int& bestColumn,
+        int& bestRound)
+{
+    double* bestIntegerSolution = model_->bestSolution();
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    bestColumn = -1;
+    bestRound = -1; // -1 rounds down, +1 rounds up
+    double bestFraction = COIN_DBL_MAX;
+    bool allTriviallyRoundableSoFar = true;
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = newSolution[iColumn];
+        double fraction = value - floor(value);
+        int round = 0;
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            if (allTriviallyRoundableSoFar || (downLocks_[i] > 0 && upLocks_[i] > 0)) {
+
+                if (allTriviallyRoundableSoFar && downLocks_[i] > 0 && upLocks_[i] > 0) {
+                    allTriviallyRoundableSoFar = false;
+                    bestFraction = COIN_DBL_MAX;
+                }
+
+                if (value >= bestIntegerSolution[iColumn])
+                    round = -1;
+                else {
+                    round = 1;
+                    fraction = 1.0 - fraction;
+                }
+
+                // if variable is not binary, penalize it
+                if (!solver->isBinary(iColumn))
+                    fraction *= 1000.0;
+
+                if (fraction < bestFraction) {
+                    bestColumn = iColumn;
+                    bestFraction = fraction;
+                    bestRound = round;
+                }
+            }
+        }
+    }
+    return allTriviallyRoundableSoFar;
+}
+
diff --git a/cbits/coin/CbcHeuristicDiveGuided.hpp b/cbits/coin/CbcHeuristicDiveGuided.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveGuided.hpp
@@ -0,0 +1,55 @@
+/* $Id: CbcHeuristicDiveGuided.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicDiveGuided_H
+#define CbcHeuristicDiveGuided_H
+
+#include "CbcHeuristicDive.hpp"
+
+/** DiveGuided class
+ */
+
+class CbcHeuristicDiveGuided : public CbcHeuristicDive {
+public:
+
+    // Default Constructor
+    CbcHeuristicDiveGuided ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicDiveGuided (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDiveGuided ( const CbcHeuristicDiveGuided &);
+
+    // Destructor
+    ~CbcHeuristicDiveGuided ();
+
+    /// Clone
+    virtual CbcHeuristicDiveGuided * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicDiveGuided & operator=(const CbcHeuristicDiveGuided& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Tests if the heuristic can run
+    virtual bool canHeuristicRun();
+
+    /// Selects the next variable to branch on
+    /** Returns true if all the fractional variables can be trivially
+        rounded. Returns false, if there is at least one fractional variable
+        that is not trivially roundable. In this case, the bestColumn
+        returned will not be trivially roundable.
+    */
+    virtual bool selectVariableToBranch(OsiSolverInterface* solver,
+                                        const double* newSolution,
+                                        int& bestColumn,
+                                        int& bestRound);
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicDiveLineSearch.cpp b/cbits/coin/CbcHeuristicDiveLineSearch.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveLineSearch.cpp
@@ -0,0 +1,123 @@
+/* $Id: CbcHeuristicDiveLineSearch.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcHeuristicDiveLineSearch.hpp"
+#include "CbcStrategy.hpp"
+
+// Default Constructor
+CbcHeuristicDiveLineSearch::CbcHeuristicDiveLineSearch()
+        : CbcHeuristicDive()
+{
+}
+
+// Constructor from model
+CbcHeuristicDiveLineSearch::CbcHeuristicDiveLineSearch(CbcModel & model)
+        : CbcHeuristicDive(model)
+{
+}
+
+// Destructor
+CbcHeuristicDiveLineSearch::~CbcHeuristicDiveLineSearch ()
+{
+}
+
+// Clone
+CbcHeuristicDiveLineSearch *
+CbcHeuristicDiveLineSearch::clone() const
+{
+    return new CbcHeuristicDiveLineSearch(*this);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicDiveLineSearch::generateCpp( FILE * fp)
+{
+    CbcHeuristicDiveLineSearch other;
+    fprintf(fp, "0#include \"CbcHeuristicDiveLineSearch.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicDiveLineSearch heuristicDiveLineSearch(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicDiveLineSearch");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicDiveLineSearch);\n");
+}
+
+// Copy constructor
+CbcHeuristicDiveLineSearch::CbcHeuristicDiveLineSearch(const CbcHeuristicDiveLineSearch & rhs)
+        :
+        CbcHeuristicDive(rhs)
+{
+}
+
+// Assignment operator
+CbcHeuristicDiveLineSearch &
+CbcHeuristicDiveLineSearch::operator=( const CbcHeuristicDiveLineSearch & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristicDive::operator=(rhs);
+    }
+    return *this;
+}
+
+bool
+CbcHeuristicDiveLineSearch::selectVariableToBranch(OsiSolverInterface* solver,
+        const double* newSolution,
+        int& bestColumn,
+        int& bestRound)
+{
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    // get the LP relaxation solution at the root node
+    double * rootNodeLPSol = model_->continuousSolution();
+
+    bestColumn = -1;
+    bestRound = -1; // -1 rounds down, +1 rounds up
+    double bestRelDistance = COIN_DBL_MAX;
+    bool allTriviallyRoundableSoFar = true;
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double rootValue = rootNodeLPSol[iColumn];
+        double value = newSolution[iColumn];
+        double fraction = value - floor(value);
+        int round = 0;
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            if (allTriviallyRoundableSoFar || (downLocks_[i] > 0 && upLocks_[i] > 0)) {
+
+                if (allTriviallyRoundableSoFar && downLocks_[i] > 0 && upLocks_[i] > 0) {
+                    allTriviallyRoundableSoFar = false;
+                    bestRelDistance = COIN_DBL_MAX;
+                }
+
+                double relDistance;
+                if (value < rootValue) {
+                    round = -1;
+                    relDistance = fraction / (rootValue - value);
+                } else if (value > rootValue) {
+                    round = 1;
+                    relDistance = (1.0 - fraction) / (value - rootValue);
+                } else {
+                    round = -1;
+                    relDistance = COIN_DBL_MAX;
+                }
+
+                // if variable is not binary, penalize it
+                if (!solver->isBinary(iColumn))
+                    relDistance *= 1000.0;
+
+                if (relDistance < bestRelDistance) {
+                    bestColumn = iColumn;
+                    bestRelDistance = relDistance;
+                    bestRound = round;
+                }
+            }
+        }
+    }
+    return allTriviallyRoundableSoFar;
+}
+
diff --git a/cbits/coin/CbcHeuristicDiveLineSearch.hpp b/cbits/coin/CbcHeuristicDiveLineSearch.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveLineSearch.hpp
@@ -0,0 +1,52 @@
+/* $Id: CbcHeuristicDiveLineSearch.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicDiveLineSearch_H
+#define CbcHeuristicDiveLineSearch_H
+
+#include "CbcHeuristicDive.hpp"
+
+/** DiveLineSearch class
+ */
+
+class CbcHeuristicDiveLineSearch : public CbcHeuristicDive {
+public:
+
+    // Default Constructor
+    CbcHeuristicDiveLineSearch ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicDiveLineSearch (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDiveLineSearch ( const CbcHeuristicDiveLineSearch &);
+
+    // Destructor
+    ~CbcHeuristicDiveLineSearch ();
+
+    /// Clone
+    virtual CbcHeuristicDiveLineSearch * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicDiveLineSearch & operator=(const CbcHeuristicDiveLineSearch& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Selects the next variable to branch on
+    /** Returns true if all the fractional variables can be trivially
+        rounded. Returns false, if there is at least one fractional variable
+        that is not trivially roundable. In this case, the bestColumn
+        returned will not be trivially roundable.
+    */
+    virtual bool selectVariableToBranch(OsiSolverInterface* solver,
+                                        const double* newSolution,
+                                        int& bestColumn,
+                                        int& bestRound);
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicDivePseudoCost.cpp b/cbits/coin/CbcHeuristicDivePseudoCost.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDivePseudoCost.cpp
@@ -0,0 +1,231 @@
+/* $Id: CbcHeuristicDivePseudoCost.cpp 1922 2013-05-16 07:35:51Z forrest $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcHeuristicDivePseudoCost.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcBranchDynamic.hpp"
+
+// Default Constructor
+CbcHeuristicDivePseudoCost::CbcHeuristicDivePseudoCost()
+        : CbcHeuristicDive()
+{
+}
+
+// Constructor from model
+CbcHeuristicDivePseudoCost::CbcHeuristicDivePseudoCost(CbcModel & model)
+        : CbcHeuristicDive(model)
+{
+}
+
+// Destructor
+CbcHeuristicDivePseudoCost::~CbcHeuristicDivePseudoCost ()
+{
+}
+
+// Clone
+CbcHeuristicDivePseudoCost *
+CbcHeuristicDivePseudoCost::clone() const
+{
+    return new CbcHeuristicDivePseudoCost(*this);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicDivePseudoCost::generateCpp( FILE * fp)
+{
+    CbcHeuristicDivePseudoCost other;
+    fprintf(fp, "0#include \"CbcHeuristicDivePseudoCost.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicDivePseudoCost heuristicDivePseudoCost(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicDivePseudoCost");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicDivePseudoCost);\n");
+}
+
+// Copy constructor
+CbcHeuristicDivePseudoCost::CbcHeuristicDivePseudoCost(const CbcHeuristicDivePseudoCost & rhs)
+        :
+        CbcHeuristicDive(rhs)
+{
+}
+
+// Assignment operator
+CbcHeuristicDivePseudoCost &
+CbcHeuristicDivePseudoCost::operator=( const CbcHeuristicDivePseudoCost & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristicDive::operator=(rhs);
+    }
+    return *this;
+}
+
+bool
+CbcHeuristicDivePseudoCost::selectVariableToBranch(OsiSolverInterface* solver,
+        const double* newSolution,
+        int& bestColumn,
+        int& bestRound)
+{
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    // get the LP relaxation solution at the root node
+    double * rootNodeLPSol = model_->continuousSolution();
+
+    // get pseudo costs
+    double * pseudoCostDown = downArray_;
+    double * pseudoCostUp = upArray_;
+
+    bestColumn = -1;
+    bestRound = -1; // -1 rounds down, +1 rounds up
+    double bestScore = -1.0;
+    bool allTriviallyRoundableSoFar = true;
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double rootValue = rootNodeLPSol[iColumn];
+        double value = newSolution[iColumn];
+        double fraction = value - floor(value);
+        int round = 0;
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            if (allTriviallyRoundableSoFar || (downLocks_[i] > 0 && upLocks_[i] > 0)) {
+
+                if (allTriviallyRoundableSoFar && downLocks_[i] > 0 && upLocks_[i] > 0) {
+                    allTriviallyRoundableSoFar = false;
+                    bestScore = -1.0;
+                }
+
+                double pCostDown = pseudoCostDown[i];
+                double pCostUp = pseudoCostUp[i];
+                assert(pCostDown >= 0.0 && pCostUp >= 0.0);
+
+                if (allTriviallyRoundableSoFar && downLocks_[i] == 0 && upLocks_[i] > 0)
+                    round = 1;
+                else if (allTriviallyRoundableSoFar && downLocks_[i] > 0 && upLocks_[i] == 0)
+                    round = -1;
+                else if (value - rootValue < -0.4)
+                    round = -1;
+                else if (value - rootValue > 0.4)
+                    round = 1;
+                else if (fraction < 0.3)
+                    round = -1;
+                else if (fraction > 0.7)
+                    round = 1;
+                else if (pCostDown < pCostUp)
+                    round = -1;
+                else
+                    round = 1;
+
+                // calculate score
+                double score;
+                if (round == 1)
+                    score = fraction * (pCostDown + 1.0) / (pCostUp + 1.0);
+                else
+                    score = (1.0 - fraction) * (pCostUp + 1.0) / (pCostDown + 1.0);
+
+                // if variable is binary, increase its chance of being selected
+                if (solver->isBinary(iColumn))
+                    score *= 1000.0;
+
+                if (score > bestScore) {
+                    bestColumn = iColumn;
+                    bestScore = score;
+                    bestRound = round;
+                }
+            }
+        }
+    }
+
+    return allTriviallyRoundableSoFar;
+}
+void
+CbcHeuristicDivePseudoCost::initializeData()
+{
+    int numberIntegers = model_->numberIntegers();
+    if (!downArray_) {
+        downArray_ = new double [numberIntegers];
+        upArray_ = new double [numberIntegers];
+    }
+    // get pseudo costs
+    model_->fillPseudoCosts(downArray_, upArray_);
+    // allow for -999 -> force to run
+    int diveOptions = (when_>0) ? when_ / 100 : 0;
+    if (diveOptions) {
+        // pseudo shadow prices
+        int k = diveOptions % 100;
+        if (diveOptions >= 100)
+            k += 32;
+        model_->pseudoShadow(k - 1);
+        int numberInts = CoinMin(model_->numberObjects(), numberIntegers);
+        OsiObject ** objects = model_->objects();
+        for (int i = 0; i < numberInts; i++) {
+            CbcSimpleIntegerDynamicPseudoCost * obj1 =
+                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(objects[i]) ;
+            if (obj1) {
+                //int iColumn = obj1->columnNumber();
+                double downPseudoCost = 1.0e-2 * obj1->downDynamicPseudoCost();
+                double downShadow = obj1->downShadowPrice();
+                double upPseudoCost = 1.0e-2 * obj1->upDynamicPseudoCost();
+                double upShadow = obj1->upShadowPrice();
+                downPseudoCost = CoinMax(downPseudoCost, downShadow);
+                downPseudoCost = CoinMax(downPseudoCost, 0.001 * upShadow);
+                downArray_[i] = downPseudoCost;
+                upPseudoCost = CoinMax(upPseudoCost, upShadow);
+                upPseudoCost = CoinMax(upPseudoCost, 0.001 * downShadow);
+                upArray_[i] = upPseudoCost;
+            }
+        }
+    }
+}
+// Fix other variables at bounds
+int
+CbcHeuristicDivePseudoCost::fixOtherVariables(OsiSolverInterface * solver,
+        const double * solution,
+        PseudoReducedCost * candidate,
+        const double * random)
+{
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    const double* reducedCost = solver->getReducedCost();
+    // fix other integer variables that are at their bounds
+    int cnt = 0;
+    int numberFree = 0;
+    int numberFixedAlready = 0;
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        if (upper[iColumn] > lower[iColumn]) {
+            numberFree++;
+            double value = solution[iColumn];
+            if (value - lower[iColumn] <= integerTolerance) {
+                candidate[cnt].var = iColumn;
+                candidate[cnt++].pseudoRedCost = CoinMax(1.0e-2 * reducedCost[iColumn],
+                                                 downArray_[i]) * random[i];
+            } else if (upper[iColumn] - value <= integerTolerance) {
+                candidate[cnt].var = iColumn;
+                candidate[cnt++].pseudoRedCost = CoinMax(-1.0e-2 * reducedCost[iColumn],
+                                                 downArray_[i]) * random[i];
+            }
+        } else {
+            numberFixedAlready++;
+        }
+    }
+#ifdef CLP_INVESTIGATE
+    printf("cutoff %g obj %g - %d free, %d fixed\n",
+           model_->getCutoff(), solver->getObjValue(), numberFree,
+           numberFixedAlready);
+#endif
+    return cnt;
+    //return CbcHeuristicDive::fixOtherVariables(solver, solution,
+    //				     candidate, random);
+}
+
diff --git a/cbits/coin/CbcHeuristicDivePseudoCost.hpp b/cbits/coin/CbcHeuristicDivePseudoCost.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDivePseudoCost.hpp
@@ -0,0 +1,60 @@
+/* $Id: CbcHeuristicDivePseudoCost.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicDivePseudoCost_H
+#define CbcHeuristicDivePseudoCost_H
+
+#include "CbcHeuristicDive.hpp"
+
+/** DivePseudoCost class
+ */
+
+class CbcHeuristicDivePseudoCost : public CbcHeuristicDive {
+public:
+
+    // Default Constructor
+    CbcHeuristicDivePseudoCost ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicDivePseudoCost (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDivePseudoCost ( const CbcHeuristicDivePseudoCost &);
+
+    // Destructor
+    ~CbcHeuristicDivePseudoCost ();
+
+    /// Clone
+    virtual CbcHeuristicDivePseudoCost * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicDivePseudoCost & operator=(const CbcHeuristicDivePseudoCost& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Selects the next variable to branch on
+    /** Returns true if all the fractional variables can be trivially
+        rounded. Returns false, if there is at least one fractional variable
+        that is not trivially roundable. In this case, the bestColumn
+        returned will not be trivially roundable.
+    */
+    virtual bool selectVariableToBranch(OsiSolverInterface* solver,
+                                        const double* newSolution,
+                                        int& bestColumn,
+                                        int& bestRound);
+    /** Initializes any data which is going to be used repeatedly
+        in selectVariableToBranch */
+    virtual void initializeData() ;
+    /// Fix other variables at bounds
+    virtual int fixOtherVariables(OsiSolverInterface * solver,
+                                  const double * solution,
+                                  PseudoReducedCost * candidate,
+                                  const double * random);
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicDiveVectorLength.cpp b/cbits/coin/CbcHeuristicDiveVectorLength.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveVectorLength.cpp
@@ -0,0 +1,126 @@
+/* $Id: CbcHeuristicDiveVectorLength.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcHeuristicDiveVectorLength.hpp"
+#include "CbcStrategy.hpp"
+
+// Default Constructor
+CbcHeuristicDiveVectorLength::CbcHeuristicDiveVectorLength()
+        : CbcHeuristicDive()
+{
+}
+
+// Constructor from model
+CbcHeuristicDiveVectorLength::CbcHeuristicDiveVectorLength(CbcModel & model)
+        : CbcHeuristicDive(model)
+{
+}
+
+// Destructor
+CbcHeuristicDiveVectorLength::~CbcHeuristicDiveVectorLength ()
+{
+}
+
+// Clone
+CbcHeuristicDiveVectorLength *
+CbcHeuristicDiveVectorLength::clone() const
+{
+    return new CbcHeuristicDiveVectorLength(*this);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicDiveVectorLength::generateCpp( FILE * fp)
+{
+    CbcHeuristicDiveVectorLength other;
+    fprintf(fp, "0#include \"CbcHeuristicDiveVectorLength.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicDiveVectorLength heuristicDiveVectorLength(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicDiveVectorLength");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicDiveVectorLength);\n");
+}
+
+// Copy constructor
+CbcHeuristicDiveVectorLength::CbcHeuristicDiveVectorLength(const CbcHeuristicDiveVectorLength & rhs)
+        :
+        CbcHeuristicDive(rhs)
+{
+}
+
+// Assignment operator
+CbcHeuristicDiveVectorLength &
+CbcHeuristicDiveVectorLength::operator=( const CbcHeuristicDiveVectorLength & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristicDive::operator=(rhs);
+    }
+    return *this;
+}
+
+bool
+CbcHeuristicDiveVectorLength::selectVariableToBranch(OsiSolverInterface* solver,
+        const double* newSolution,
+        int& bestColumn,
+        int& bestRound)
+{
+    const double * objective = solver->getObjCoefficients();
+    double direction = solver->getObjSense(); // 1 for min, -1 for max
+
+    const int * columnLength = matrix_.getVectorLengths();
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    bestColumn = -1;
+    bestRound = -1; // -1 rounds down, +1 rounds up
+    double bestScore = COIN_DBL_MAX;
+    bool allTriviallyRoundableSoFar = true;
+    for (int i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = newSolution[iColumn];
+        double fraction = value - floor(value);
+        int round = 0;
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            if (allTriviallyRoundableSoFar || (downLocks_[i] > 0 && upLocks_[i] > 0)) {
+
+                if (allTriviallyRoundableSoFar && downLocks_[i] > 0 && upLocks_[i] > 0) {
+                    allTriviallyRoundableSoFar = false;
+                    bestScore = COIN_DBL_MAX;
+                }
+
+                // the variable cannot be rounded
+                double obj = direction * objective[iColumn];
+                if (obj >= 0.0)
+                    round = 1; // round up
+                else
+                    round = -1; // round down
+                double objDelta;
+                if (round == 1)
+                    objDelta = (1.0 - fraction) * obj;
+                else
+                    objDelta = - fraction * obj;
+
+                // we want the smaller score
+                double score = objDelta / (static_cast<double> (columnLength[iColumn]) + 1.0);
+
+                // if variable is not binary, penalize it
+                if (!solver->isBinary(iColumn))
+                    score *= 1000.0;
+
+                if (score < bestScore) {
+                    bestColumn = iColumn;
+                    bestScore = score;
+                    bestRound = round;
+                }
+            }
+        }
+    }
+    return allTriviallyRoundableSoFar;
+}
+
diff --git a/cbits/coin/CbcHeuristicDiveVectorLength.hpp b/cbits/coin/CbcHeuristicDiveVectorLength.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicDiveVectorLength.hpp
@@ -0,0 +1,52 @@
+/* $Id: CbcHeuristicDiveVectorLength.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicDiveVectorLength_H
+#define CbcHeuristicDiveVectorLength_H
+
+#include "CbcHeuristicDive.hpp"
+
+/** DiveVectorLength class
+ */
+
+class CbcHeuristicDiveVectorLength : public CbcHeuristicDive {
+public:
+
+    // Default Constructor
+    CbcHeuristicDiveVectorLength ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicDiveVectorLength (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDiveVectorLength ( const CbcHeuristicDiveVectorLength &);
+
+    // Destructor
+    ~CbcHeuristicDiveVectorLength ();
+
+    /// Clone
+    virtual CbcHeuristicDiveVectorLength * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicDiveVectorLength & operator=(const CbcHeuristicDiveVectorLength& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Selects the next variable to branch on
+    /** Returns true if all the fractional variables can be trivially
+        rounded. Returns false, if there is at least one fractional variable
+        that is not trivially roundable. In this case, the bestColumn
+        returned will not be trivially roundable.
+    */
+    virtual bool selectVariableToBranch(OsiSolverInterface* solver,
+                                        const double* newSolution,
+                                        int& bestColumn,
+                                        int& bestRound);
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicFPump.cpp b/cbits/coin/CbcHeuristicFPump.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicFPump.cpp
@@ -0,0 +1,2900 @@
+/* $Id: CbcHeuristicFPump.cpp 1883 2013-04-06 13:33:15Z stefan $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+#include "CbcMessage.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinTime.hpp"
+#include "CbcEventHandler.hpp"
+
+
+// Default Constructor
+CbcHeuristicFPump::CbcHeuristicFPump()
+        : CbcHeuristic(),
+        startTime_(0.0),
+        maximumTime_(0.0),
+        fakeCutoff_(COIN_DBL_MAX),
+        absoluteIncrement_(0.0),
+        relativeIncrement_(0.0),
+        defaultRounding_(0.49999),
+        initialWeight_(0.0),
+        weightFactor_(0.1),
+        artificialCost_(COIN_DBL_MAX),
+        iterationRatio_(0.0),
+        reducedCostMultiplier_(1.0),
+        maximumPasses_(100),
+        maximumRetries_(1),
+        accumulate_(0),
+        fixOnReducedCosts_(1),
+        roundExpensive_(false)
+{
+    setWhen(1);
+}
+
+// Constructor from model
+CbcHeuristicFPump::CbcHeuristicFPump(CbcModel & model,
+                                     double downValue, bool roundExpensive)
+        : CbcHeuristic(model),
+        startTime_(0.0),
+        maximumTime_(0.0),
+        fakeCutoff_(COIN_DBL_MAX),
+        absoluteIncrement_(0.0),
+        relativeIncrement_(0.0),
+        defaultRounding_(downValue),
+        initialWeight_(0.0),
+        weightFactor_(0.1),
+        artificialCost_(COIN_DBL_MAX),
+        iterationRatio_(0.0),
+        reducedCostMultiplier_(1.0),
+        maximumPasses_(100),
+        maximumRetries_(1),
+        accumulate_(0),
+        fixOnReducedCosts_(1),
+        roundExpensive_(roundExpensive)
+{
+    setWhen(1);
+}
+
+// Destructor
+CbcHeuristicFPump::~CbcHeuristicFPump ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicFPump::clone() const
+{
+    return new CbcHeuristicFPump(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicFPump::generateCpp( FILE * fp)
+{
+    CbcHeuristicFPump other;
+    fprintf(fp, "0#include \"CbcHeuristicFPump.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicFPump heuristicFPump(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicFPump");
+    if (maximumPasses_ != other.maximumPasses_)
+        fprintf(fp, "3  heuristicFPump.setMaximumPasses(%d);\n", maximumPasses_);
+    else
+        fprintf(fp, "4  heuristicFPump.setMaximumPasses(%d);\n", maximumPasses_);
+    if (maximumRetries_ != other.maximumRetries_)
+        fprintf(fp, "3  heuristicFPump.setMaximumRetries(%d);\n", maximumRetries_);
+    else
+        fprintf(fp, "4  heuristicFPump.setMaximumRetries(%d);\n", maximumRetries_);
+    if (accumulate_ != other.accumulate_)
+        fprintf(fp, "3  heuristicFPump.setAccumulate(%d);\n", accumulate_);
+    else
+        fprintf(fp, "4  heuristicFPump.setAccumulate(%d);\n", accumulate_);
+    if (fixOnReducedCosts_ != other.fixOnReducedCosts_)
+        fprintf(fp, "3  heuristicFPump.setFixOnReducedCosts(%d);\n", fixOnReducedCosts_);
+    else
+        fprintf(fp, "4  heuristicFPump.setFixOnReducedCosts(%d);\n", fixOnReducedCosts_);
+    if (maximumTime_ != other.maximumTime_)
+        fprintf(fp, "3  heuristicFPump.setMaximumTime(%g);\n", maximumTime_);
+    else
+        fprintf(fp, "4  heuristicFPump.setMaximumTime(%g);\n", maximumTime_);
+    if (fakeCutoff_ != other.fakeCutoff_)
+        fprintf(fp, "3  heuristicFPump.setFakeCutoff(%g);\n", fakeCutoff_);
+    else
+        fprintf(fp, "4  heuristicFPump.setFakeCutoff(%g);\n", fakeCutoff_);
+    if (absoluteIncrement_ != other.absoluteIncrement_)
+        fprintf(fp, "3  heuristicFPump.setAbsoluteIncrement(%g);\n", absoluteIncrement_);
+    else
+        fprintf(fp, "4  heuristicFPump.setAbsoluteIncrement(%g);\n", absoluteIncrement_);
+    if (relativeIncrement_ != other.relativeIncrement_)
+        fprintf(fp, "3  heuristicFPump.setRelativeIncrement(%g);\n", relativeIncrement_);
+    else
+        fprintf(fp, "4  heuristicFPump.setRelativeIncrement(%g);\n", relativeIncrement_);
+    if (defaultRounding_ != other.defaultRounding_)
+        fprintf(fp, "3  heuristicFPump.setDefaultRounding(%g);\n", defaultRounding_);
+    else
+        fprintf(fp, "4  heuristicFPump.setDefaultRounding(%g);\n", defaultRounding_);
+    if (initialWeight_ != other.initialWeight_)
+        fprintf(fp, "3  heuristicFPump.setInitialWeight(%g);\n", initialWeight_);
+    else
+        fprintf(fp, "4  heuristicFPump.setInitialWeight(%g);\n", initialWeight_);
+    if (weightFactor_ != other.weightFactor_)
+        fprintf(fp, "3  heuristicFPump.setWeightFactor(%g);\n", weightFactor_);
+    else
+        fprintf(fp, "4  heuristicFPump.setWeightFactor(%g);\n", weightFactor_);
+    if (artificialCost_ != other.artificialCost_)
+        fprintf(fp, "3  heuristicFPump.setArtificialCost(%g);\n", artificialCost_);
+    else
+        fprintf(fp, "4  heuristicFPump.setArtificialCost(%g);\n", artificialCost_);
+    if (iterationRatio_ != other.iterationRatio_)
+        fprintf(fp, "3  heuristicFPump.setIterationRatio(%g);\n", iterationRatio_);
+    else
+        fprintf(fp, "4  heuristicFPump.setIterationRatio(%g);\n", iterationRatio_);
+    if (reducedCostMultiplier_ != other.reducedCostMultiplier_)
+        fprintf(fp, "3  heuristicFPump.setReducedCostMultiplier(%g);\n", reducedCostMultiplier_);
+    else
+        fprintf(fp, "4  heuristicFPump.setReducedCostMultiplier(%g);\n", reducedCostMultiplier_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicFPump);\n");
+}
+
+// Copy constructor
+CbcHeuristicFPump::CbcHeuristicFPump(const CbcHeuristicFPump & rhs)
+        :
+        CbcHeuristic(rhs),
+        startTime_(rhs.startTime_),
+        maximumTime_(rhs.maximumTime_),
+        fakeCutoff_(rhs.fakeCutoff_),
+        absoluteIncrement_(rhs.absoluteIncrement_),
+        relativeIncrement_(rhs.relativeIncrement_),
+        defaultRounding_(rhs.defaultRounding_),
+        initialWeight_(rhs.initialWeight_),
+        weightFactor_(rhs.weightFactor_),
+        artificialCost_(rhs.artificialCost_),
+        iterationRatio_(rhs.iterationRatio_),
+        reducedCostMultiplier_(rhs.reducedCostMultiplier_),
+        maximumPasses_(rhs.maximumPasses_),
+        maximumRetries_(rhs.maximumRetries_),
+        accumulate_(rhs.accumulate_),
+        fixOnReducedCosts_(rhs.fixOnReducedCosts_),
+        roundExpensive_(rhs.roundExpensive_)
+{
+}
+
+// Assignment operator
+CbcHeuristicFPump &
+CbcHeuristicFPump::operator=( const CbcHeuristicFPump & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        startTime_ = rhs.startTime_;
+        maximumTime_ = rhs.maximumTime_;
+        fakeCutoff_ = rhs.fakeCutoff_;
+        absoluteIncrement_ = rhs.absoluteIncrement_;
+        relativeIncrement_ = rhs.relativeIncrement_;
+        defaultRounding_ = rhs.defaultRounding_;
+        initialWeight_ = rhs.initialWeight_;
+        weightFactor_ = rhs.weightFactor_;
+        artificialCost_ = rhs.artificialCost_;
+        iterationRatio_ = rhs.iterationRatio_;
+        reducedCostMultiplier_ = rhs.reducedCostMultiplier_;
+        maximumPasses_ = rhs.maximumPasses_;
+        maximumRetries_ = rhs.maximumRetries_;
+        accumulate_ = rhs.accumulate_;
+        fixOnReducedCosts_ = rhs.fixOnReducedCosts_;
+        roundExpensive_ = rhs.roundExpensive_;
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicFPump::resetModel(CbcModel * )
+{
+}
+
+/**************************BEGIN MAIN PROCEDURE ***********************************/
+
+// See if feasibility pump will give better solution
+// Sets value of solution
+// Returns 1 if solution, 0 if not
+int
+CbcHeuristicFPump::solution(double & solutionValue,
+                            double * betterSolution)
+{
+    startTime_ = CoinCpuTime();
+    numCouldRun_++;
+    double incomingObjective = solutionValue;
+#define LEN_PRINT 200
+    char pumpPrint[LEN_PRINT];
+    pumpPrint[0] = '\0';
+/*
+  Decide if we want to run. Standard values for when are described in
+  CbcHeuristic.hpp. If we're off, or running only at root and this isn't the
+  root, bail out.
+
+  The double test (against phase, then atRoot and passNumber) has a fair bit
+  of redundancy, but the results will differ depending on whether we're
+  actually at the root of the main search tree or at the root of a small tree
+  (recursive call to branchAndBound).
+
+  FPump also supports some exotic values (11 -- 15) for when, described in
+  CbcHeuristicFPump.hpp.
+*/
+    if (!when() || (when() == 1 && model_->phase() != 1))
+        return 0; // switched off
+    // See if at root node
+    bool atRoot = model_->getNodeCount() == 0;
+    int passNumber = model_->getCurrentPassNumber();
+    // just do once
+    if (!atRoot)
+        return 0;
+    int options = feasibilityPumpOptions_;
+    if ((options % 1000000) > 0) {
+        int kOption = options / 1000000;
+        options = options % 1000000;
+        /*
+          Add 10 to do even if solution
+          1 - do after cuts
+          2 - do after cuts (not before)
+          3 - not used do after every cut round (and after cuts)
+          k not used do after every (k-2)th round
+        */
+        if (kOption < 10 && model_->getSolutionCount())
+            return 0;
+        if (model_->getSolutionCount())
+            kOption = kOption % 10;
+        bool good;
+        if (kOption == 1) {
+            good = (passNumber == 999999);
+        } else if (kOption == 2) {
+            good = (passNumber == 999999);
+            passNumber = 2; // so won't run before
+            //} else if (kOption==3) {
+            //good = true;
+        } else {
+            //good = (((passNumber-1)%(kOption-2))==0);
+            good = false;
+        }
+        if (passNumber != 1 && !good)
+            return 0;
+    } else {
+        if (passNumber != 1)
+            return 0;
+    }
+    // loop round doing repeated pumps
+    double cutoff;
+    model_->solver()->getDblParam(OsiDualObjectiveLimit, cutoff);
+    double direction = model_->solver()->getObjSense();
+    cutoff *= direction;
+    int numberBandBsolutions = 0;
+    double firstCutoff = fabs(cutoff);
+    cutoff = CoinMin(cutoff, solutionValue);
+    // check plausible and space for rounded solution
+    int numberColumns = model_->getNumCols();
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariableOrig = model_->integerVariable();
+    double iterationLimit = -1.0;
+    //iterationRatio_=1.0;
+    if (iterationRatio_ > 0.0)
+        iterationLimit = (2 * model_->solver()->getNumRows() + 2 * numberColumns) *
+                         iterationRatio_;
+    int totalNumberIterations = 0;
+    int averageIterationsPerTry = -1;
+    int numberIterationsLastPass = 0;
+    // 1. initially check 0-1
+/*
+  I'm skeptical of the above comment, but it's likely accurate as the default.
+  Bit 4 or bit 8 needs to be set in order to consider working with general
+  integers.
+*/
+    int i, j;
+    int general = 0;
+    int * integerVariable = new int[numberIntegers];
+    const double * lower = model_->solver()->getColLower();
+    const double * upper = model_->solver()->getColUpper();
+    bool doGeneral = (accumulate_ & 4) != 0;
+    j = 0;
+/*
+  Scan the objects, recording the columns and counting general integers.
+
+  Seems like the NDEBUG tests could be made into an applicability test. If
+  a scan of the objects reveals complex objects, just clean up and return
+  failure.
+*/
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariableOrig[i];
+#ifndef NDEBUG
+        const OsiObject * object = model_->object(i);
+        const CbcSimpleInteger * integerObject =
+            dynamic_cast<const  CbcSimpleInteger *> (object);
+        const OsiSimpleInteger * integerObject2 =
+            dynamic_cast<const  OsiSimpleInteger *> (object);
+        assert(integerObject || integerObject2);
+#endif
+        if (upper[iColumn] - lower[iColumn] > 1.000001) {
+            general++;
+            if (doGeneral)
+                integerVariable[j++] = iColumn;
+        } else {
+            integerVariable[j++] = iColumn;
+        }
+    }
+/*
+  If 2/3 of integers are general integers, and we're not going to work with
+  them, might as well go home.
+
+  The else case is unclear to me. We reach it if general integers are less than
+  2/3 of the total, or if either of bit 4 or 8 is set. But only bit 8 is used
+  in the decision. (Let manyGen = 1 if more than 2/3 of integers are general
+  integers. Then a k-map on manyGen, bit4, and bit8 shows it clearly.)
+
+  So there's something odd here. In the case where bit4 = 1 and bit8 = 0,
+  we've included general integers in integerVariable, but we're not going to
+  process them.
+*/
+    if (general*3 > 2*numberIntegers && !doGeneral) {
+        delete [] integerVariable;
+        return 0;
+    } else if ((accumulate_&4) == 0) {
+        doGeneral = false;
+        j = 0;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariableOrig[i];
+            if (upper[iColumn] - lower[iColumn] < 1.000001)
+                integerVariable[j++] = iColumn;
+        }
+    }
+    if (!general)
+        doGeneral = false;
+#ifdef CLP_INVESTIGATE
+    if (doGeneral)
+        printf("DOing general with %d out of %d\n", general, numberIntegers);
+#endif
+/*
+  This `closest solution' will satisfy integrality, but violate some other
+  constraints?
+*/
+    // For solution closest to feasible if none found
+    int * closestSolution = general ? NULL : new int[numberIntegers];
+    double closestObjectiveValue = COIN_DBL_MAX;
+
+    int numberIntegersOrig = numberIntegers;
+    numberIntegers = j;
+    double * newSolution = new double [numberColumns];
+    double newSolutionValue = COIN_DBL_MAX;
+    int maxSolutions = model_->getMaximumSolutions();
+    int numberSolutions=0;
+    bool solutionFound = false;
+    int * usedColumn = NULL;
+    double * lastSolution = NULL;
+    int fixContinuous = 0;
+    bool fixInternal = false;
+    bool allSlack = false;
+    if (when_ >= 21 && when_ <= 25) {
+        when_ -= 10;
+        allSlack = true;
+    }
+    double time1 = CoinCpuTime();
+/*
+  Obtain a relaxed lp solution.
+*/
+    model_->solver()->resolve();
+    if (!model_->solver()->isProvenOptimal()) {
+        // presumably max time or some such
+        return 0;
+    }
+    numRuns_++;
+    if (cutoff < 1.0e50 && false) {
+        // Fix on djs
+        double direction = model_->solver()->getObjSense() ;
+        double gap = cutoff - model_->solver()->getObjValue() * direction ;
+        double tolerance;
+        model_->solver()->getDblParam(OsiDualTolerance, tolerance) ;
+        if (gap > 0.0) {
+            gap += 100.0 * tolerance;
+            int nFix = model_->solver()->reducedCostFix(gap);
+            printf("dj fixing fixed %d variables\n", nFix);
+        }
+    }
+/*
+  I have no idea why we're doing this, except perhaps that saveBasis will be
+  automagically deleted on exit from the routine.
+*/
+    CoinWarmStartBasis saveBasis;
+    CoinWarmStartBasis * basis =
+        dynamic_cast<CoinWarmStartBasis *>(model_->solver()->getWarmStart()) ;
+    if (basis) {
+        saveBasis = * basis;
+        delete basis;
+    }
+    double continuousObjectiveValue = model_->solver()->getObjValue() * model_->solver()->getObjSense();
+    double * firstPerturbedObjective = NULL;
+    double * firstPerturbedSolution = NULL;
+    double firstPerturbedValue = COIN_DBL_MAX;
+    if (when_ >= 11 && when_ <= 15) {
+        fixInternal = when_ > 11 && when_ < 15;
+        if (when_ < 13)
+            fixContinuous = 0;
+        else if (when_ != 14)
+            fixContinuous = 1;
+        else
+            fixContinuous = 2;
+        when_ = 1;
+        if ((accumulate_&1) != 0) {
+            usedColumn = new int [numberColumns];
+            for (int i = 0; i < numberColumns; i++)
+                usedColumn[i] = -1;
+        }
+        lastSolution = CoinCopyOfArray(model_->solver()->getColSolution(), numberColumns);
+    }
+    int finalReturnCode = 0;
+    int totalNumberPasses = 0;
+    int numberTries = 0;
+    CoinWarmStartBasis bestBasis;
+    bool exitAll = false;
+    //double saveBestObjective = model_->getMinimizationObjValue();
+    OsiSolverInterface * solver = NULL;
+    double artificialFactor = 0.00001;
+    // also try rounding!
+    double * roundingSolution = new double[numberColumns];
+    double roundingObjective = solutionValue;
+    CbcRounding roundingHeuristic(*model_);
+    int dualPass = 0;
+    int secondPassOpt = 0;
+#define RAND_RAND
+#ifdef RAND_RAND
+    int offRandom = 0;
+#endif
+    int maximumAllowed = -1;
+    bool moreIterations = false;
+    if (options > 0) {
+        if (options >= 1000)
+            maximumAllowed = options / 1000;
+        int options2 = (options % 1000) / 100;
+#ifdef RAND_RAND
+        offRandom = options2 & 1;
+#endif
+        moreIterations = (options2 & 2) != 0;
+        secondPassOpt = (options / 10) % 10;
+        /* 1 to 7 - re-use solution
+           8 use dual and current solution(ish)
+           9 use dual and allslack
+           1 - primal and mod obj
+           2 - dual and mod obj
+           3 - primal and no mod obj
+           add 3 to redo current solution
+        */
+        if (secondPassOpt >= 8) {
+            dualPass = secondPassOpt - 7;
+            secondPassOpt = 0;
+        }
+    }
+    // Number of passes to do
+    int maximumPasses = maximumPasses_;
+#ifdef COIN_HAS_CLP
+    {
+      OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (model_->solver());
+      if (clpSolver ) {
+	if (maximumPasses == 30) {
+	  if (clpSolver->fakeObjective())
+            maximumPasses = 100; // feasibility problem?
+	}
+	randomNumberGenerator_.randomize();
+	if (model_->getRandomSeed()!=-1)
+	  clpSolver->getModelPtr()->setRandomSeed(randomNumberGenerator_.getSeed());
+	clpSolver->getModelPtr()->randomNumberGenerator()->randomize();
+      }
+    }
+#endif
+#ifdef RAND_RAND
+    double * randomFactor = new double [numberColumns];
+    for (int i = 0; i < numberColumns; i++) {
+        double value = floor(1.0e3 * randomNumberGenerator_.randomDouble());
+        randomFactor[i] = 1.0 + value * 1.0e-4;
+    }
+#endif
+    // guess exact multiple of objective
+    double exactMultiple = model_->getCutoffIncrement();
+    exactMultiple *= 2520;
+    if (fabs(exactMultiple / 0.999 - floor(exactMultiple / 0.999 + 0.5)) < 1.0e-9)
+        exactMultiple /= 2520.0 * 0.999;
+    else if (fabs(exactMultiple - floor(exactMultiple + 0.5)) < 1.0e-9)
+        exactMultiple /= 2520.0;
+    else
+        exactMultiple = 0.0;
+    // check for rounding errors (only for integral case)
+    if (fabs(exactMultiple - floor(exactMultiple + 0.5)) < 1.0e-8)
+        exactMultiple = floor(exactMultiple + 0.5);
+    //printf("exact multiple %g\n",exactMultiple);
+    // Clone solver for rounding
+    OsiSolverInterface * clonedSolver = cloneBut(2); // wasmodel_->solver()->clone();
+    while (!exitAll) {
+        // Cutoff rhs
+        double useRhs = COIN_DBL_MAX;
+        double useOffset = 0.0;
+        int numberPasses = 0;
+        artificialFactor *= 10.0;
+        int lastMove = (!numberTries) ? -10 : 1000000;
+        double lastSumInfeas = COIN_DBL_MAX;
+        numberTries++;
+        // Clone solver - otherwise annoys root node computations
+        solver = cloneBut(2); // was model_->solver()->clone();
+#ifdef COIN_HAS_CLP
+        {
+            OsiClpSolverInterface * clpSolver
+            = dynamic_cast<OsiClpSolverInterface *> (solver);
+            if (clpSolver) {
+                // better to clean up using primal?
+                ClpSimplex * lp = clpSolver->getModelPtr();
+                int options = lp->specialOptions();
+                lp->setSpecialOptions(options | 8192);
+                //lp->setSpecialOptions(options|0x01000000);
+#ifdef CLP_INVESTIGATE
+                clpSolver->setHintParam(OsiDoReducePrint, false, OsiHintTry);
+                lp->setLogLevel(CoinMax(1, lp->logLevel()));
+#endif
+            }
+        }
+#endif
+        if (CoinMin(fakeCutoff_, cutoff) < 1.0e50) {
+            // Fix on djs
+            double direction = solver->getObjSense() ;
+            double gap = CoinMin(fakeCutoff_, cutoff) - solver->getObjValue() * direction ;
+            double tolerance;
+            solver->getDblParam(OsiDualTolerance, tolerance) ;
+            if (gap > 0.0 && (fixOnReducedCosts_ == 1 || (numberTries == 1 && fixOnReducedCosts_ == 2))) {
+                gap += 100.0 * tolerance;
+                gap *= reducedCostMultiplier_;
+                int nFix = solver->reducedCostFix(gap);
+                if (nFix) {
+                    sprintf(pumpPrint, "Reduced cost fixing fixed %d variables on major pass %d", nFix, numberTries);
+                    model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                    << pumpPrint
+                    << CoinMessageEol;
+                    //pumpPrint[0]='\0';
+                }
+            }
+        }
+        // if cutoff exists then add constraint
+        bool useCutoff = (fabs(cutoff) < 1.0e20 && (fakeCutoff_ != COIN_DBL_MAX || numberTries > 1));
+        // but there may be a close one
+        if (firstCutoff < 2.0*solutionValue && numberTries == 1 && CoinMin(cutoff, fakeCutoff_) < 1.0e20)
+            useCutoff = true;
+        if (useCutoff) {
+            double rhs = CoinMin(cutoff, fakeCutoff_);
+            const double * objective = solver->getObjCoefficients();
+            int numberColumns = solver->getNumCols();
+            int * which = new int[numberColumns];
+            double * els = new double[numberColumns];
+            int nel = 0;
+            for (int i = 0; i < numberColumns; i++) {
+                double value = objective[i];
+                if (value) {
+                    which[nel] = i;
+                    els[nel++] = direction * value;
+                }
+            }
+            solver->getDblParam(OsiObjOffset, useOffset);
+#ifdef COIN_DEVELOP
+            if (useOffset)
+                printf("CbcHeuristicFPump obj offset %g\n", useOffset);
+#endif
+            useOffset *= direction;
+            // Tweak rhs and save
+            useRhs = rhs;
+#ifdef JJF_ZERO
+            double tempValue = 60.0 * useRhs;
+            if (fabs(tempValue - floor(tempValue + 0.5)) < 1.0e-7 && rhs != fakeCutoff_) {
+                // add a little
+                useRhs += 1.0e-5;
+            }
+#endif
+            solver->addRow(nel, which, els, -COIN_DBL_MAX, useRhs + useOffset);
+            delete [] which;
+            delete [] els;
+            bool takeHint;
+            OsiHintStrength strength;
+            solver->getHintParam(OsiDoDualInResolve, takeHint, strength);
+            solver->setHintParam(OsiDoDualInResolve, true, OsiHintDo);
+            solver->resolve();
+            solver->setHintParam(OsiDoDualInResolve, takeHint, strength);
+            if (!solver->isProvenOptimal()) {
+                // presumably max time or some such
+                exitAll = true;
+                break;
+            }
+        }
+        solver->setDblParam(OsiDualObjectiveLimit, 1.0e50);
+        solver->resolve();
+        // Solver may not be feasible
+        if (!solver->isProvenOptimal()) {
+            exitAll = true;
+            break;
+        }
+        const double * lower = solver->getColLower();
+        const double * upper = solver->getColUpper();
+        const double * solution = solver->getColSolution();
+        if (lastSolution)
+            memcpy(lastSolution, solution, numberColumns*sizeof(double));
+        double primalTolerance;
+        solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+        // 2 space for last rounded solutions
+#define NUMBER_OLD 4
+        double ** oldSolution = new double * [NUMBER_OLD];
+        for (j = 0; j < NUMBER_OLD; j++) {
+            oldSolution[j] = new double[numberColumns];
+            for (i = 0; i < numberColumns; i++) oldSolution[j][i] = -COIN_DBL_MAX;
+        }
+
+        // 3. Replace objective with an initial 0-valued objective
+        double * saveObjective = new double [numberColumns];
+        memcpy(saveObjective, solver->getObjCoefficients(), numberColumns*sizeof(double));
+        for (i = 0; i < numberColumns; i++) {
+            solver->setObjCoeff(i, 0.0);
+        }
+        bool finished = false;
+        double direction = solver->getObjSense();
+        int returnCode = 0;
+        bool takeHint;
+        OsiHintStrength strength;
+        solver->getHintParam(OsiDoDualInResolve, takeHint, strength);
+        solver->setHintParam(OsiDoDualInResolve, false);
+        //solver->messageHandler()->setLogLevel(0);
+
+        // 4. Save objective offset so we can see progress
+        double saveOffset;
+        solver->getDblParam(OsiObjOffset, saveOffset);
+        // Get amount for original objective
+        double scaleFactor = 0.0;
+#ifdef COIN_DEVELOP
+        double largestCost = 0.0;
+        int nArtificial = 0;
+#endif
+        for (i = 0; i < numberColumns; i++) {
+            double value = saveObjective[i];
+            scaleFactor += value * value;
+#ifdef COIN_DEVELOP
+            largestCost = CoinMax(largestCost, fabs(value));
+            if (value*direction >= artificialCost_)
+                nArtificial++;
+#endif
+        }
+        if (scaleFactor)
+            scaleFactor = (initialWeight_ * sqrt(static_cast<double> (numberIntegers))) / sqrt(scaleFactor);
+#ifdef CLP_INVESTIGATE
+#ifdef COIN_DEVELOP
+        if (scaleFactor || nArtificial)
+            printf("Using %g fraction of original objective (decay %g) - largest %g - %d artificials\n", scaleFactor, weightFactor_,
+                   largestCost, nArtificial);
+#else
+        if (scaleFactor)
+            printf("Using %g fraction of original objective (decay %g)\n",
+                   scaleFactor, weightFactor_);
+#endif
+#endif
+        // This is an array of sums of infeasibilities so can see if "bobbling"
+#define SIZE_BOBBLE 20
+        double saveSumInf[SIZE_BOBBLE];
+        CoinFillN(saveSumInf, SIZE_BOBBLE, COIN_DBL_MAX);
+        // 0 before doing anything
+        int bobbleMode = 0;
+        // 5. MAIN WHILE LOOP
+        //bool newLineNeeded=false;
+/*
+  finished occurs exactly twice in this routine: immediately above, where it's
+  set to false, and here in the loop condition.
+*/
+        while (!finished) {
+            double newTrueSolutionValue = 0.0;
+            double newSumInfeas = 0.0;
+            int newNumberInfeas = 0;
+            returnCode = 0;
+            if (model_->maximumSecondsReached()) {
+                exitAll = true;
+                break;
+            }
+            // see what changed
+            if (usedColumn) {
+                for (i = 0; i < numberColumns; i++) {
+                    if (fabs(solution[i] - lastSolution[i]) > 1.0e-8)
+                        usedColumn[i] = numberPasses;
+                    lastSolution[i] = solution[i];
+                }
+            }
+            if (averageIterationsPerTry >= 0) {
+                int n = totalNumberIterations - numberIterationsLastPass;
+                double perPass = totalNumberIterations /
+                                 (totalNumberPasses + numberPasses + 1.0e-5);
+                perPass /= (solver->getNumRows() + numberColumns);
+                double test = moreIterations ? 0.3 : 0.05;
+                if (n > CoinMax(20000, 3*averageIterationsPerTry)
+                        && (switches_&2) == 0 && maximumPasses<200 && perPass>test) {
+                    exitAll = true;
+                }
+            }
+            // Exit on exact total number if maximumPasses large
+            if ((maximumPasses >= 200 || (switches_&2) != 0)
+                    && numberPasses + totalNumberPasses >=
+                    maximumPasses)
+                exitAll = true;
+            bool exitThis = false;
+            if (iterationLimit < 0.0) {
+                if (numberPasses >= maximumPasses) {
+                    // If going well then keep going if maximumPasses small
+                    if (lastMove < numberPasses - 4 || lastMove == 1000000)
+                        exitThis = true;
+                    if (maximumPasses > 20 || numberPasses >= 40)
+                        exitThis = true;
+                }
+            }
+            if (iterationLimit > 0.0 && totalNumberIterations > iterationLimit
+                    && numberPasses > 15) {
+                // exiting on iteration count
+                exitAll = true;
+            } else if (maximumPasses<30 && numberPasses>100) {
+                // too many passes anyway
+                exitAll = true;
+            }
+            if (maximumTime_ > 0.0 && CoinCpuTime() >= startTime_ + maximumTime_) {
+                exitAll = true;
+                // force exit
+                switches_ |= 2048;
+            }
+            if (exitAll || exitThis)
+                break;
+            memcpy(newSolution, solution, numberColumns*sizeof(double));
+            int flip;
+            if (numberPasses == 0 && false) {
+                // always use same seed
+                randomNumberGenerator_.setSeed(987654321);
+            }
+            returnCode = rounds(solver, newSolution,/*saveObjective,*/
+                                numberIntegers, integerVariable,
+                                /*pumpPrint,*/numberPasses,
+                                /*roundExpensive_,*/defaultRounding_, &flip);
+            if (numberPasses == 0 && false) {
+                // Make sure random will be different
+                for (i = 1; i < numberTries; i++)
+                    randomNumberGenerator_.randomDouble();
+            }
+            numberPasses++;
+            if (returnCode) {
+                // SOLUTION IS INTEGER
+                // Put back correct objective
+                for (i = 0; i < numberColumns; i++)
+                    solver->setObjCoeff(i, saveObjective[i]);
+
+                // solution - but may not be better
+                // Compute using dot product
+                solver->setDblParam(OsiObjOffset, saveOffset);
+                newSolutionValue = -saveOffset;
+                for (  i = 0 ; i < numberColumns ; i++ )
+                    newSolutionValue += saveObjective[i] * newSolution[i];
+                newSolutionValue *= direction;
+                sprintf(pumpPrint, "Solution found of %g", newSolutionValue);
+                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                << pumpPrint
+                << CoinMessageEol;
+                //newLineNeeded=false;
+                if (newSolutionValue < solutionValue) {
+                    double saveValue = solutionValue;
+                    if (!doGeneral) {
+                        int numberLeft = 0;
+                        for (i = 0; i < numberIntegersOrig; i++) {
+                            int iColumn = integerVariableOrig[i];
+                            double value = floor(newSolution[iColumn] + 0.5);
+                            if (solver->isBinary(iColumn)) {
+                                solver->setColLower(iColumn, value);
+                                solver->setColUpper(iColumn, value);
+                            } else {
+                                if (fabs(value - newSolution[iColumn]) > 1.0e-7)
+                                    numberLeft++;
+                            }
+                        }
+                        if (numberLeft) {
+                            sprintf(pumpPrint, "Branch and bound needed to clear up %d general integers", numberLeft);
+                            model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                            << pumpPrint
+                            << CoinMessageEol;
+                            returnCode = smallBranchAndBound(solver, numberNodes_, newSolution, newSolutionValue,
+                                                             solutionValue, "CbcHeuristicFpump");
+                            if (returnCode < 0) {
+                                if (returnCode == -2)
+                                    exitAll = true;
+                                returnCode = 0; // returned on size or event
+                            }
+                            if ((returnCode&2) != 0) {
+                                // could add cut
+                                returnCode &= ~2;
+                            }
+                            if (returnCode != 1)
+                                newSolutionValue = saveValue;
+                            if (returnCode && newSolutionValue < saveValue)
+                                numberBandBsolutions++;
+                        }
+                    }
+                    if (returnCode && newSolutionValue < saveValue) {
+                        memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+                        solutionFound = true;
+                        if (exitNow(newSolutionValue))
+                            exitAll = true;
+                        CoinWarmStartBasis * basis =
+                            dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+                        if (basis) {
+                            bestBasis = * basis;
+                            delete basis;
+                            int action = model_->dealWithEventHandler(CbcEventHandler::heuristicSolution, newSolutionValue, betterSolution);
+                            if (action == 0) {
+                                double * saveOldSolution = CoinCopyOfArray(model_->bestSolution(), numberColumns);
+                                double saveObjectiveValue = model_->getMinimizationObjValue();
+                                model_->setBestSolution(betterSolution, numberColumns, newSolutionValue);
+                                if (saveOldSolution && saveObjectiveValue < model_->getMinimizationObjValue())
+                                    model_->setBestSolution(saveOldSolution, numberColumns, saveObjectiveValue);
+                                delete [] saveOldSolution;
+                            }
+                            if (action == 0 || model_->maximumSecondsReached()) {
+                                exitAll = true; // exit
+                                break;
+                            }
+                        }
+                        if ((accumulate_&1) != 0) {
+                            model_->incrementUsed(betterSolution); // for local search
+                        }
+                        solutionValue = newSolutionValue;
+                        solutionFound = true;
+			numberSolutions++;
+			if (numberSolutions>=maxSolutions)
+			  exitAll = true;
+                        if (general && saveValue != newSolutionValue) {
+                            sprintf(pumpPrint, "Cleaned solution of %g", solutionValue);
+                            model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                            << pumpPrint
+                            << CoinMessageEol;
+                        }
+                        if (exitNow(newSolutionValue))
+                            exitAll = true;
+                    } else {
+                        sprintf(pumpPrint, "Mini branch and bound could not fix general integers");
+                        model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                        << pumpPrint
+                        << CoinMessageEol;
+                    }
+                } else {
+                    sprintf(pumpPrint, "After further testing solution no better than previous of %g", solutionValue);
+                    model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                    << pumpPrint
+                    << CoinMessageEol;
+                    //newLineNeeded=false;
+                    returnCode = 0;
+                }
+                break;
+            } else {
+                // SOLUTION IS not INTEGER
+                // 1. check for loop
+                bool matched;
+                for (int k = NUMBER_OLD - 1; k > 0; k--) {
+                    double * b = oldSolution[k];
+                    matched = true;
+                    for (i = 0; i < numberIntegers; i++) {
+                        int iColumn = integerVariable[i];
+                        if (newSolution[iColumn] != b[iColumn]) {
+                            matched = false;
+                            break;
+                        }
+                    }
+                    if (matched) break;
+                }
+                int numberPerturbed = 0;
+                if (matched || numberPasses % 100 == 0) {
+                    // perturbation
+                    //sprintf(pumpPrint+strlen(pumpPrint)," perturbation applied");
+                    //newLineNeeded=true;
+                    double factorX[10] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
+                    double factor = 1.0;
+                    double target = -1.0;
+                    double * randomX = new double [numberIntegers];
+                    for (i = 0; i < numberIntegers; i++)
+                        randomX[i] = CoinMax(0.0, randomNumberGenerator_.randomDouble() - 0.3);
+                    for (int k = 0; k < 10; k++) {
+#ifdef COIN_DEVELOP_x
+                        printf("kpass %d\n", k);
+#endif
+                        int numberX[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+                        for (i = 0; i < numberIntegers; i++) {
+                            int iColumn = integerVariable[i];
+                            double value = randomX[i];
+                            double difference = fabs(solution[iColumn] - newSolution[iColumn]);
+                            for (int j = 0; j < 10; j++) {
+                                if (difference + value*factorX[j] > 0.5)
+                                    numberX[j]++;
+                            }
+                        }
+                        if (target < 0.0) {
+                            if (numberX[9] <= 200)
+                                break; // not very many changes
+                            target = CoinMax(200.0, CoinMin(0.05 * numberX[9], 1000.0));
+                        }
+                        int iX = -1;
+                        int iBand = -1;
+                        for (i = 0; i < 10; i++) {
+#ifdef COIN_DEVELOP_x
+                            printf("** %d changed at %g\n", numberX[i], factorX[i]);
+#endif
+                            if (numberX[i] >= target && numberX[i] < 2.0*target && iX < 0)
+                                iX = i;
+                            if (iBand<0 && numberX[i]>target) {
+                                iBand = i;
+                                factor = factorX[i];
+                            }
+                        }
+                        if (iX >= 0) {
+                            factor = factorX[iX];
+                            break;
+                        } else {
+                            assert (iBand >= 0);
+                            double hi = factor;
+                            double lo = (iBand > 0) ? factorX[iBand-1] : 0.0;
+                            double diff = (hi - lo) / 9.0;
+                            for (i = 0; i < 10; i++) {
+                                factorX[i] = lo;
+                                lo += diff;
+                            }
+                        }
+                    }
+                    for (i = 0; i < numberIntegers; i++) {
+                        int iColumn = integerVariable[i];
+                        double value = randomX[i];
+                        double difference = fabs(solution[iColumn] - newSolution[iColumn]);
+                        if (difference + value*factor > 0.5) {
+                            numberPerturbed++;
+                            if (newSolution[iColumn] < lower[iColumn] + primalTolerance) {
+                                newSolution[iColumn] += 1.0;
+                            } else if (newSolution[iColumn] > upper[iColumn] - primalTolerance) {
+                                newSolution[iColumn] -= 1.0;
+                            } else {
+                                // general integer
+                                if (difference + value > 0.75)
+                                    newSolution[iColumn] += 1.0;
+                                else
+                                    newSolution[iColumn] -= 1.0;
+                            }
+                        }
+                    }
+                    delete [] randomX;
+                } else {
+                    for (j = NUMBER_OLD - 1; j > 0; j--) {
+                        for (i = 0; i < numberColumns; i++) oldSolution[j][i] = oldSolution[j-1][i];
+                    }
+                    for (j = 0; j < numberColumns; j++) oldSolution[0][j] = newSolution[j];
+                }
+
+                // 2. update the objective function based on the new rounded solution
+                double offset = 0.0;
+                double costValue = (1.0 - scaleFactor) * solver->getObjSense();
+                int numberChanged = 0;
+                const double * oldObjective = solver->getObjCoefficients();
+                for (i = 0; i < numberColumns; i++) {
+                    // below so we can keep original code and allow for objective
+                    int iColumn = i;
+                    // Special code for "artificials"
+                    if (direction*saveObjective[iColumn] >= artificialCost_) {
+                        //solver->setObjCoeff(iColumn,scaleFactor*saveObjective[iColumn]);
+                        solver->setObjCoeff(iColumn, (artificialFactor*saveObjective[iColumn]) / artificialCost_);
+                    }
+                    if (!solver->isBinary(iColumn) && !doGeneral)
+                        continue;
+                    // deal with fixed variables (i.e., upper=lower)
+                    if (fabs(lower[iColumn] - upper[iColumn]) < primalTolerance || !solver->isInteger(iColumn)) {
+                        //if (lower[iColumn] > 1. - primalTolerance) solver->setObjCoeff(iColumn,-costValue);
+                        //else                                       solver->setObjCoeff(iColumn,costValue);
+                        continue;
+                    }
+                    double newValue = 0.0;
+                    if (newSolution[iColumn] < lower[iColumn] + primalTolerance) {
+                        newValue = costValue + scaleFactor * saveObjective[iColumn];
+                    } else {
+                        if (newSolution[iColumn] > upper[iColumn] - primalTolerance) {
+                            newValue = -costValue + scaleFactor * saveObjective[iColumn];
+                        }
+                    }
+#ifdef RAND_RAND
+                    if (!offRandom)
+                        newValue *= randomFactor[iColumn];
+#endif
+                    if (newValue != oldObjective[iColumn]) {
+                        numberChanged++;
+                    }
+                    solver->setObjCoeff(iColumn, newValue);
+                    offset += costValue * newSolution[iColumn];
+                }
+		if (numberPasses==1 && !totalNumberPasses && (model_->specialOptions()&8388608)!=0) {
+		  // doing multiple solvers - make a real difference - flip 5%
+		  for (i = 0; i < numberIntegers; i++) {
+		    int iColumn = integerVariable[i];
+		    double value = floor(newSolution[iColumn]+0.5);
+		    if (fabs(value-solution[iColumn])>primalTolerance) {
+		      value = randomNumberGenerator_.randomDouble();
+		      if(value<0.05) {
+			//printf("Flipping %d - random %g\n",iColumn,value);
+			solver->setObjCoeff(iColumn,-solver->getObjCoefficients()[iColumn]);
+		      }
+		    }
+		  }
+		}
+                solver->setDblParam(OsiObjOffset, -offset);
+                if (!general && false) {
+                    // Solve in two goes - first keep satisfied ones fixed
+                    double * saveLower = new double [numberIntegers];
+                    double * saveUpper = new double [numberIntegers];
+                    for (i = 0; i < numberIntegers; i++) {
+                        int iColumn = integerVariable[i];
+                        saveLower[i] = COIN_DBL_MAX;
+                        saveUpper[i] = -COIN_DBL_MAX;
+                        if (solution[iColumn] < lower[iColumn] + primalTolerance) {
+                            saveUpper[i] = upper[iColumn];
+                            solver->setColUpper(iColumn, lower[iColumn]);
+                        } else if (solution[iColumn] > upper[iColumn] - primalTolerance) {
+                            saveLower[i] = lower[iColumn];
+                            solver->setColLower(iColumn, upper[iColumn]);
+                        }
+                    }
+                    solver->resolve();
+                    if (!solver->isProvenOptimal()) {
+                        // presumably max time or some such
+                        exitAll = true;
+                        break;
+                    }
+                    for (i = 0; i < numberIntegers; i++) {
+                        int iColumn = integerVariable[i];
+                        if (saveLower[i] != COIN_DBL_MAX)
+                            solver->setColLower(iColumn, saveLower[i]);
+                        if (saveUpper[i] != -COIN_DBL_MAX)
+                            solver->setColUpper(iColumn, saveUpper[i]);
+                        saveUpper[i] = -COIN_DBL_MAX;
+                    }
+                    memcpy(newSolution, solution, numberColumns*sizeof(double));
+                    int flip;
+                    returnCode = rounds(solver, newSolution,/*saveObjective,*/
+                                        numberIntegers, integerVariable,
+                                        /*pumpPrint,*/numberPasses,
+                                        /*roundExpensive_,*/defaultRounding_, &flip);
+                    numberPasses++;
+                    if (returnCode) {
+                        // solution - but may not be better
+                        // Compute using dot product
+                        double newSolutionValue = -saveOffset;
+                        for (  i = 0 ; i < numberColumns ; i++ )
+                            newSolutionValue += saveObjective[i] * newSolution[i];
+                        newSolutionValue *= direction;
+                        sprintf(pumpPrint, "Intermediate solution found of %g", newSolutionValue);
+                        model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                        << pumpPrint
+                        << CoinMessageEol;
+                        if (newSolutionValue < solutionValue) {
+                            memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+                            CoinWarmStartBasis * basis =
+                                dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+                            solutionFound = true;
+			    numberSolutions++;
+			    if (numberSolutions>=maxSolutions)
+			      exitAll = true;
+                            if (exitNow(newSolutionValue))
+                                exitAll = true;
+                            if (basis) {
+                                bestBasis = * basis;
+                                delete basis;
+                                int action = model_->dealWithEventHandler(CbcEventHandler::heuristicSolution, newSolutionValue, betterSolution);
+                                if (!action) {
+                                    double * saveOldSolution = CoinCopyOfArray(model_->bestSolution(), numberColumns);
+                                    double saveObjectiveValue = model_->getMinimizationObjValue();
+                                    model_->setBestSolution(betterSolution, numberColumns, newSolutionValue);
+                                    if (saveOldSolution && saveObjectiveValue < model_->getMinimizationObjValue())
+                                        model_->setBestSolution(saveOldSolution, numberColumns, saveObjectiveValue);
+                                    delete [] saveOldSolution;
+                                }
+                                if (!action || model_->maximumSecondsReached()) {
+                                    exitAll = true; // exit
+                                    break;
+                                }
+                            }
+                            if ((accumulate_&1) != 0) {
+                                model_->incrementUsed(betterSolution); // for local search
+                            }
+                            solutionValue = newSolutionValue;
+                            solutionFound = true;
+			    numberSolutions++;
+			    if (numberSolutions>=maxSolutions)
+			      exitAll = true;
+                            if (exitNow(newSolutionValue))
+                                exitAll = true;
+                        } else {
+                            returnCode = 0;
+                        }
+                    }
+                }
+                int numberIterations = 0;
+                if (!doGeneral) {
+                    // faster to do from all slack!!!!
+                    if (allSlack) {
+                        CoinWarmStartBasis dummy;
+                        solver->setWarmStart(&dummy);
+                    }
+#ifdef COIN_DEVELOP
+                    printf("%d perturbed out of %d columns (%d changed)\n", numberPerturbed, numberColumns, numberChanged);
+#endif
+                    bool takeHint;
+                    OsiHintStrength strength;
+                    solver->getHintParam(OsiDoDualInResolve, takeHint, strength);
+                    if (dualPass && numberChanged > 2) {
+                        solver->setHintParam(OsiDoDualInResolve, true); // dual may be better
+                        if (dualPass == 1 && 2*numberChanged < numberColumns &&
+                                (numberChanged < 5000 || 6*numberChanged < numberColumns)) {
+                            // but we need to make infeasible
+                            CoinWarmStartBasis * basis =
+                                dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+                            if (basis) {
+                                // modify
+                                const double * lower = solver->getColLower();
+                                const double * upper = solver->getColUpper();
+                                double * solution = CoinCopyOfArray(solver->getColSolution(),
+                                                                    numberColumns);
+                                const double * objective = solver->getObjCoefficients();
+                                int nChanged = 0;
+                                for (i = 0; i < numberIntegersOrig; i++) {
+                                    int iColumn = integerVariableOrig[i];
+#ifdef RAND_RAND
+                                    if (nChanged > numberChanged)
+                                        break;
+#endif
+                                    if (objective[iColumn] > 0.0) {
+                                        if (basis->getStructStatus(iColumn) ==
+                                                CoinWarmStartBasis::atUpperBound) {
+                                            solution[iColumn] = lower[iColumn];
+                                            basis->setStructStatus(iColumn, CoinWarmStartBasis::atLowerBound);
+                                            nChanged++;
+                                        }
+                                    } else if (objective[iColumn] < 0.0) {
+                                        if (basis->getStructStatus(iColumn) ==
+                                                CoinWarmStartBasis::atLowerBound) {
+                                            solution[iColumn] = upper[iColumn];
+                                            basis->setStructStatus(iColumn, CoinWarmStartBasis::atUpperBound);
+                                            nChanged++;
+                                        }
+                                    }
+                                }
+                                if (!nChanged) {
+                                    for (i = 0; i < numberIntegersOrig; i++) {
+                                        int iColumn = integerVariableOrig[i];
+                                        if (objective[iColumn] > 0.0) {
+                                            if (basis->getStructStatus(iColumn) ==
+                                                    CoinWarmStartBasis::basic) {
+                                                solution[iColumn] = lower[iColumn];
+                                                basis->setStructStatus(iColumn, CoinWarmStartBasis::atLowerBound);
+                                                break;
+                                            }
+                                        } else if (objective[iColumn] < 0.0) {
+                                            if (basis->getStructStatus(iColumn) ==
+                                                    CoinWarmStartBasis::basic) {
+                                                solution[iColumn] = upper[iColumn];
+                                                basis->setStructStatus(iColumn, CoinWarmStartBasis::atUpperBound);
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+                                solver->setColSolution(solution);
+                                delete [] solution;
+                                solver->setWarmStart(basis);
+                                delete basis;
+                            }
+                        } else {
+                            // faster to do from all slack!!!! ???
+                            CoinWarmStartBasis dummy;
+                            solver->setWarmStart(&dummy);
+                        }
+                    }
+                    if (numberTries > 1 && numberPasses == 1 && firstPerturbedObjective) {
+                        // Modify to use convex combination
+                        // use basis from first time
+                        solver->setWarmStart(&saveBasis);
+                        // and objective
+                        if (secondPassOpt < 3 || (secondPassOpt >= 4 && secondPassOpt < 6))
+                            solver->setObjective(firstPerturbedObjective);
+                        // and solution
+                        solver->setColSolution(firstPerturbedSolution);
+                        //if (secondPassOpt==2||secondPassOpt==5||
+                        if (firstPerturbedValue > cutoff)
+                            solver->setHintParam(OsiDoDualInResolve, true); // dual may be better
+                    }
+                    solver->resolve();
+                    if (!solver->isProvenOptimal()) {
+                        // presumably max time or some such
+                        exitAll = true;
+                        break;
+                    }
+                    solver->setHintParam(OsiDoDualInResolve, takeHint);
+                    newTrueSolutionValue = -saveOffset;
+                    newSumInfeas = 0.0;
+                    newNumberInfeas = 0;
+                    {
+                        const double * newSolution = solver->getColSolution();
+                        for (  i = 0 ; i < numberColumns ; i++ ) {
+                            if (solver->isInteger(i)) {
+                                double value = newSolution[i];
+                                double nearest = floor(value + 0.5);
+                                newSumInfeas += fabs(value - nearest);
+                                if (fabs(value - nearest) > 1.0e-6)
+                                    newNumberInfeas++;
+                            }
+                            newTrueSolutionValue += saveObjective[i] * newSolution[i];
+                        }
+                        newTrueSolutionValue *= direction;
+                        if (numberPasses == 1 && secondPassOpt) {
+                            if (numberTries == 1 || secondPassOpt > 3) {
+                                // save basis
+                                CoinWarmStartBasis * basis =
+                                    dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+                                if (basis) {
+                                    saveBasis = * basis;
+                                    delete basis;
+                                }
+                                delete [] firstPerturbedObjective;
+                                delete [] firstPerturbedSolution;
+                                firstPerturbedObjective = CoinCopyOfArray(solver->getObjCoefficients(), numberColumns);
+                                firstPerturbedSolution = CoinCopyOfArray(solver->getColSolution(), numberColumns);
+                                firstPerturbedValue = newTrueSolutionValue;
+                            }
+                        }
+                        if (newNumberInfeas && newNumberInfeas < 15) {
+#ifdef JJF_ZERO
+                            roundingObjective = solutionValue;
+                            OsiSolverInterface * saveSolver = model_->swapSolver(solver);
+                            double * currentObjective =
+                                CoinCopyOfArray(solver->getObjCoefficients(), numberColumns);
+                            solver->setObjective(saveObjective);
+                            double saveOffset2;
+                            solver->getDblParam(OsiObjOffset, saveOffset2);
+                            solver->setDblParam(OsiObjOffset, saveOffset);
+                            int ifSol = roundingHeuristic.solution(roundingObjective, roundingSolution);
+                            solver->setObjective(currentObjective);
+                            solver->setDblParam(OsiObjOffset, saveOffset2);
+                            delete [] currentObjective;
+                            model_->swapSolver(saveSolver);
+                            if (ifSol > 0)
+                                abort();
+#endif
+                            int numberRows = solver->getNumRows();
+                            double * rowActivity = new double[numberRows];
+                            memset(rowActivity, 0, numberRows*sizeof(double));
+                            int * which = new int[newNumberInfeas];
+                            int * stack = new int[newNumberInfeas+1];
+                            double * baseValue = new double[newNumberInfeas];
+                            int * whichRow = new int[numberRows];
+                            double * rowValue = new double[numberRows];
+                            memset(rowValue, 0, numberRows*sizeof(double));
+                            int nRow = 0;
+                            // Column copy
+                            const double * element = solver->getMatrixByCol()->getElements();
+                            const int * row = solver->getMatrixByCol()->getIndices();
+                            const CoinBigIndex * columnStart = solver->getMatrixByCol()->getVectorStarts();
+                            const int * columnLength = solver->getMatrixByCol()->getVectorLengths();
+                            int n = 0;
+                            double contrib = 0.0;
+                            for (  i = 0 ; i < numberColumns ; i++ ) {
+                                double value = newSolution[i];
+                                if (solver->isInteger(i)) {
+                                    double nearest = floor(value + 0.5);
+                                    if (fabs(value - nearest) > 1.0e-6) {
+                                        //printf("Column %d value %g\n",i,value);
+                                        for (CoinBigIndex j = columnStart[i];
+                                                j < columnStart[i] + columnLength[i]; j++) {
+                                            int iRow = row[j];
+                                            //printf("row %d element %g\n",iRow,element[j]);
+                                            if (!rowValue[iRow]) {
+                                                rowValue[iRow] = 1.0;
+                                                whichRow[nRow++] = iRow;
+                                            }
+                                        }
+                                        baseValue[n] = floor(value);
+                                        contrib += saveObjective[i] * value;
+                                        value = 0.0;
+                                        stack[n] = 0;
+                                        which[n++] = i;
+                                    }
+                                }
+                                for (CoinBigIndex j = columnStart[i];
+                                        j < columnStart[i] + columnLength[i]; j++) {
+                                    int iRow = row[j];
+                                    rowActivity[iRow] += value * element[j];
+                                }
+                            }
+                            if (newNumberInfeas < 15) {
+                                stack[n] = newNumberInfeas + 100;
+                                int iStack = n;
+                                memset(rowValue, 0, numberRows*sizeof(double));
+                                const double * rowLower = solver->getRowLower();
+                                const double * rowUpper = solver->getRowUpper();
+                                while (iStack >= 0) {
+                                    double contrib2 = 0.0;
+                                    // Could do faster
+                                    for (int k = 0 ; k < n ; k++ ) {
+                                        i = which[k];
+                                        double value = baseValue[k] + stack[k];
+                                        contrib2 += saveObjective[i] * value;
+                                        for (CoinBigIndex j = columnStart[i];
+                                                j < columnStart[i] + columnLength[i]; j++) {
+                                            int iRow = row[j];
+                                            rowValue[iRow] += value * element[j];
+                                        }
+                                    }
+                                    // check if feasible
+                                    bool feasible = true;
+                                    for (int k = 0; k < nRow; k++) {
+                                        i = whichRow[k];
+                                        double value = rowValue[i] + rowActivity[i];
+                                        rowValue[i] = 0.0;
+                                        if (value < rowLower[i] - 1.0e-7 ||
+                                                value > rowUpper[i] + 1.0e-7)
+                                            feasible = false;
+                                    }
+                                    if (feasible) {
+                                        double newObj = newTrueSolutionValue * direction;
+                                        newObj += contrib2 - contrib;
+                                        newObj *= direction;
+#ifdef COIN_DEVELOP
+                                        printf("FFFeasible! - obj %g\n", newObj);
+#endif
+                                        if (newObj < roundingObjective - 1.0e-6) {
+#ifdef COIN_DEVELOP
+                                            printf("FBetter\n");
+#endif
+                                            roundingObjective = newObj;
+                                            memcpy(roundingSolution, newSolution, numberColumns*sizeof(double));
+                                            for (int k = 0 ; k < n ; k++ ) {
+                                                i = which[k];
+                                                double value = baseValue[k] + stack[k];
+                                                roundingSolution[i] = value;
+                                            }
+                                        }
+                                    }
+                                    while (iStack >= 0 && stack[iStack]) {
+                                        stack[iStack]--;
+                                        iStack--;
+                                    }
+                                    if (iStack >= 0) {
+                                        stack[iStack] = 1;
+                                        iStack = n;
+                                        stack[n] = 1;
+                                    }
+                                }
+                            }
+                            delete [] rowActivity;
+                            delete [] which;
+                            delete [] stack;
+                            delete [] baseValue;
+                            delete [] whichRow;
+                            delete [] rowValue;
+                        }
+                    }
+                    if (true) {
+                        OsiSolverInterface * saveSolver = model_->swapSolver(clonedSolver);
+                        clonedSolver->setColSolution(solver->getColSolution());
+                        CbcRounding heuristic1(*model_);
+                        heuristic1.setHeuristicName("rounding in feaspump!");
+                        heuristic1.setWhen(1);
+                        roundingObjective = CoinMin(roundingObjective, solutionValue);
+                        double testSolutionValue = newTrueSolutionValue;
+                        int returnCode = heuristic1.solution(roundingObjective,
+                                                             roundingSolution,
+                                                             testSolutionValue) ;
+                        if (returnCode == 1) {
+#ifdef COIN_DEVELOP
+                            printf("rounding obj of %g?\n", roundingObjective);
+#endif
+                            //roundingObjective = newSolutionValue;
+                            //} else {
+                            //roundingObjective = COIN_DBL_MAX;
+                        }
+                        model_->swapSolver(saveSolver);
+                    }
+                    if (!solver->isProvenOptimal()) {
+                        // presumably max time or some such
+                        exitAll = true;
+                        break;
+                    }
+                    // in case very dubious solver
+                    lower = solver->getColLower();
+                    upper = solver->getColUpper();
+                    solution = solver->getColSolution();
+                    numberIterations = solver->getIterationCount();
+                } else {
+                    int * addStart = new int[2*general+1];
+                    int * addIndex = new int[4*general];
+                    double * addElement = new double[4*general];
+                    double * addLower = new double[2*general];
+                    double * addUpper = new double[2*general];
+                    double * obj = new double[general];
+                    int nAdd = 0;
+                    for (i = 0; i < numberIntegers; i++) {
+                        int iColumn = integerVariable[i];
+                        if (newSolution[iColumn] > lower[iColumn] + primalTolerance &&
+                                newSolution[iColumn] < upper[iColumn] - primalTolerance) {
+                            assert (upper[iColumn] - lower[iColumn] > 1.00001);
+                            obj[nAdd] = 1.0;
+                            addLower[nAdd] = 0.0;
+                            addUpper[nAdd] = COIN_DBL_MAX;
+                            nAdd++;
+                        }
+                    }
+                    OsiSolverInterface * solver2 = solver;
+                    if (nAdd) {
+                        CoinZeroN(addStart, nAdd + 1);
+                        solver2 = solver->clone();
+                        solver2->addCols(nAdd, addStart, NULL, NULL, addLower, addUpper, obj);
+                        // feasible solution
+                        double * sol = new double[nAdd+numberColumns];
+                        memcpy(sol, solution, numberColumns*sizeof(double));
+                        // now rows
+                        int nAdd = 0;
+                        int nEl = 0;
+                        int nAddRow = 0;
+                        for (i = 0; i < numberIntegers; i++) {
+                            int iColumn = integerVariable[i];
+                            if (newSolution[iColumn] > lower[iColumn] + primalTolerance &&
+                                    newSolution[iColumn] < upper[iColumn] - primalTolerance) {
+                                addLower[nAddRow] = -newSolution[iColumn];;
+                                addUpper[nAddRow] = COIN_DBL_MAX;
+                                addIndex[nEl] = iColumn;
+                                addElement[nEl++] = -1.0;
+                                addIndex[nEl] = numberColumns + nAdd;
+                                addElement[nEl++] = 1.0;
+                                nAddRow++;
+                                addStart[nAddRow] = nEl;
+                                addLower[nAddRow] = newSolution[iColumn];;
+                                addUpper[nAddRow] = COIN_DBL_MAX;
+                                addIndex[nEl] = iColumn;
+                                addElement[nEl++] = 1.0;
+                                addIndex[nEl] = numberColumns + nAdd;
+                                addElement[nEl++] = 1.0;
+                                nAddRow++;
+                                addStart[nAddRow] = nEl;
+                                sol[nAdd+numberColumns] = fabs(sol[iColumn] - newSolution[iColumn]);
+                                nAdd++;
+                            }
+                        }
+                        solver2->setColSolution(sol);
+                        delete [] sol;
+                        solver2->addRows(nAddRow, addStart, addIndex, addElement, addLower, addUpper);
+                    }
+                    delete [] addStart;
+                    delete [] addIndex;
+                    delete [] addElement;
+                    delete [] addLower;
+                    delete [] addUpper;
+                    delete [] obj;
+                    solver2->resolve();
+                    if (!solver2->isProvenOptimal()) {
+                        // presumably max time or some such
+                        exitAll = true;
+                        break;
+                    }
+                    //assert (solver2->isProvenOptimal());
+                    if (nAdd) {
+                        solver->setColSolution(solver2->getColSolution());
+                        numberIterations = solver2->getIterationCount();
+                        delete solver2;
+                    } else {
+                        numberIterations = solver->getIterationCount();
+                    }
+                    lower = solver->getColLower();
+                    upper = solver->getColUpper();
+                    solution = solver->getColSolution();
+                    newTrueSolutionValue = -saveOffset;
+                    newSumInfeas = 0.0;
+                    newNumberInfeas = 0;
+                    {
+                        const double * newSolution = solver->getColSolution();
+                        for (  i = 0 ; i < numberColumns ; i++ ) {
+                            if (solver->isInteger(i)) {
+                                double value = newSolution[i];
+                                double nearest = floor(value + 0.5);
+                                newSumInfeas += fabs(value - nearest);
+                                if (fabs(value - nearest) > 1.0e-6)
+                                    newNumberInfeas++;
+                            }
+                            newTrueSolutionValue += saveObjective[i] * newSolution[i];
+                        }
+                        newTrueSolutionValue *= direction;
+                    }
+                }
+                if (lastMove != 1000000) {
+                    if (newSumInfeas < lastSumInfeas) {
+                        lastMove = numberPasses;
+                        lastSumInfeas = newSumInfeas;
+                    } else if (newSumInfeas > lastSumInfeas + 1.0e-5) {
+                        lastMove = 1000000; // going up
+                    }
+                }
+                totalNumberIterations += numberIterations;
+                if (solver->getNumRows() < 3000)
+                    sprintf(pumpPrint, "Pass %3d: suminf. %10.5f (%d) obj. %g iterations %d",
+                            numberPasses + totalNumberPasses,
+                            newSumInfeas, newNumberInfeas,
+                            newTrueSolutionValue, numberIterations);
+                else
+                    sprintf(pumpPrint, "Pass %3d: (%.2f seconds) suminf. %10.5f (%d) obj. %g iterations %d", numberPasses + totalNumberPasses,
+                            model_->getCurrentSeconds(), newSumInfeas, newNumberInfeas,
+                            newTrueSolutionValue, numberIterations);
+                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                << pumpPrint
+                << CoinMessageEol;
+                if (closestSolution && solver->getObjValue() < closestObjectiveValue) {
+                    int i;
+                    const double * objective = solver->getObjCoefficients();
+                    for (i = 0; i < numberIntegersOrig; i++) {
+                        int iColumn = integerVariableOrig[i];
+                        if (objective[iColumn] > 0.0)
+                            closestSolution[i] = 0;
+                        else
+                            closestSolution[i] = 1;
+                    }
+                    closestObjectiveValue = solver->getObjValue();
+                }
+                // See if we need to think about changing rhs
+                if ((switches_&12) != 0 && useRhs < 1.0e50) {
+                    double oldRhs = useRhs;
+                    bool trying = false;
+                    if ((switches_&4) != 0 && numberPasses && (numberPasses % 50) == 0) {
+                        if (solutionValue > 1.0e20) {
+                            // only if no genuine solution
+                            double gap = useRhs - continuousObjectiveValue;
+                            useRhs += 0.1 * gap;
+                            if (exactMultiple) {
+                                useRhs = exactMultiple * ceil(useRhs / exactMultiple);
+                                useRhs = CoinMax(useRhs, oldRhs + exactMultiple);
+                            }
+                            trying = true;
+                        }
+                    }
+                    if ((switches_&8) != 0) {
+                        // Put in new suminf and check
+                        double largest = newSumInfeas;
+                        double smallest = newSumInfeas;
+                        for (int i = 0; i < SIZE_BOBBLE - 1; i++) {
+                            double value = saveSumInf[i+1];
+                            saveSumInf[i] = value;
+                            largest = CoinMax(largest, value);
+                            smallest = CoinMin(smallest, value);
+                        }
+                        saveSumInf[SIZE_BOBBLE-1] = newSumInfeas;
+                        if (smallest*1.5 > largest && smallest > 2.0) {
+                            if (bobbleMode == 0) {
+                                // go closer
+                                double gap = oldRhs - continuousObjectiveValue;
+                                useRhs -= 0.4 * gap;
+                                if (exactMultiple) {
+                                    double value = floor(useRhs / exactMultiple);
+                                    useRhs = CoinMin(value * exactMultiple, oldRhs - exactMultiple);
+                                }
+                                if (useRhs < continuousObjectiveValue) {
+                                    // skip decrease
+                                    bobbleMode = 1;
+                                    useRhs = oldRhs;
+                                }
+                            }
+                            if (bobbleMode) {
+                                trying = true;
+                                // weaken
+                                if (solutionValue < 1.0e20) {
+                                    double gap = solutionValue - oldRhs;
+                                    useRhs += 0.3 * gap;
+                                } else {
+                                    double gap = oldRhs - continuousObjectiveValue;
+                                    useRhs += 0.05 * gap;
+                                }
+                                if (exactMultiple) {
+                                    double value = ceil(useRhs / exactMultiple);
+                                    useRhs = CoinMin(value * exactMultiple,
+                                                     solutionValue - exactMultiple);
+                                }
+                            }
+                            bobbleMode++;
+                            // reset
+                            CoinFillN(saveSumInf, SIZE_BOBBLE, COIN_DBL_MAX);
+                        }
+                    }
+                    if (useRhs != oldRhs) {
+                        // tidy up
+                        if (exactMultiple) {
+                            double value = floor(useRhs / exactMultiple);
+                            double bestPossible = ceil(continuousObjectiveValue / exactMultiple);
+                            useRhs = CoinMax(value, bestPossible) * exactMultiple;
+                        } else {
+                            useRhs = CoinMax(useRhs, continuousObjectiveValue);
+                        }
+                        int k = solver->getNumRows() - 1;
+                        solver->setRowUpper(k, useRhs + useOffset);
+                        bool takeHint;
+                        OsiHintStrength strength;
+                        solver->getHintParam(OsiDoDualInResolve, takeHint, strength);
+                        if (useRhs < oldRhs) {
+                            solver->setHintParam(OsiDoDualInResolve, true);
+                            solver->resolve();
+                        } else if (useRhs > oldRhs) {
+                            solver->setHintParam(OsiDoDualInResolve, false);
+                            solver->resolve();
+                        }
+                        solver->setHintParam(OsiDoDualInResolve, takeHint);
+                        if (!solver->isProvenOptimal()) {
+                            // presumably max time or some such
+                            exitAll = true;
+                            break;
+                        }
+                    } else if (trying) {
+                        // doesn't look good
+                        break;
+                    }
+                }
+            }
+            // reduce scale factor
+            scaleFactor *= weightFactor_;
+        } // END WHILE
+        // see if rounding worked!
+        if (roundingObjective < solutionValue) {
+            if (roundingObjective < solutionValue - 1.0e-6*fabs(roundingObjective)) {
+                sprintf(pumpPrint, "Rounding solution of %g is better than previous of %g\n",
+                        roundingObjective, solutionValue);
+                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                << pumpPrint
+                << CoinMessageEol;
+            }
+            solutionValue = roundingObjective;
+            newSolutionValue = solutionValue;
+            memcpy(betterSolution, roundingSolution, numberColumns*sizeof(double));
+            solutionFound = true;
+	    numberSolutions++;
+	    if (numberSolutions>=maxSolutions)
+	      exitAll = true;
+            if (exitNow(roundingObjective))
+                exitAll = true;
+        }
+        if (!solutionFound) {
+            sprintf(pumpPrint, "No solution found this major pass");
+            model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+            << pumpPrint
+            << CoinMessageEol;
+        }
+        //}
+        delete solver;
+        solver = NULL;
+        for ( j = 0; j < NUMBER_OLD; j++)
+            delete [] oldSolution[j];
+        delete [] oldSolution;
+        delete [] saveObjective;
+        if (usedColumn && !exitAll) {
+            OsiSolverInterface * newSolver = cloneBut(3); // was model_->continuousSolver()->clone();
+#if 0 //def COIN_HAS_CLP
+	    OsiClpSolverInterface * clpSolver
+	      = dynamic_cast<OsiClpSolverInterface *> (newSolver);
+	    if (clpSolver) {
+	      ClpSimplex * simplex = clpSolver->getModelPtr();
+	      simplex->writeMps("start.mps",2,1);
+	    }
+#endif
+            const double * colLower = newSolver->getColLower();
+            const double * colUpper = newSolver->getColUpper();
+            bool stopBAB = false;
+            int allowedPass = -1;
+            if (maximumAllowed > 0)
+                allowedPass = CoinMax(numberPasses - maximumAllowed, -1);
+            while (!stopBAB) {
+                stopBAB = true;
+                int i;
+                int nFix = 0;
+                int nFixI = 0;
+                int nFixC = 0;
+                int nFixC2 = 0;
+                for (i = 0; i < numberIntegersOrig; i++) {
+                    int iColumn = integerVariableOrig[i];
+                    //const OsiObject * object = model_->object(i);
+                    //double originalLower;
+                    //double originalUpper;
+                    //getIntegerInformation( object,originalLower, originalUpper);
+                    //assert(colLower[iColumn]==originalLower);
+                    //newSolver->setColLower(iColumn,CoinMax(colLower[iColumn],originalLower));
+                    newSolver->setColLower(iColumn, colLower[iColumn]);
+                    //assert(colUpper[iColumn]==originalUpper);
+                    //newSolver->setColUpper(iColumn,CoinMin(colUpper[iColumn],originalUpper));
+                    newSolver->setColUpper(iColumn, colUpper[iColumn]);
+                    if (usedColumn[iColumn] <= allowedPass) {
+                        double value = lastSolution[iColumn];
+                        double nearest = floor(value + 0.5);
+                        if (fabs(value - nearest) < 1.0e-7) {
+                            if (nearest == colLower[iColumn]) {
+                                newSolver->setColUpper(iColumn, colLower[iColumn]);
+                                nFix++;
+                            } else if (nearest == colUpper[iColumn]) {
+                                newSolver->setColLower(iColumn, colUpper[iColumn]);
+                                nFix++;
+                            } else if (fixInternal) {
+                                newSolver->setColLower(iColumn, nearest);
+                                newSolver->setColUpper(iColumn, nearest);
+                                nFix++;
+                                nFixI++;
+                            }
+                        }
+                    }
+                }
+                if (fixContinuous) {
+                    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        if (!newSolver->isInteger(iColumn) && usedColumn[iColumn] <= allowedPass) {
+                            double value = lastSolution[iColumn];
+                            if (value < colLower[iColumn] + 1.0e-8) {
+                                newSolver->setColUpper(iColumn, colLower[iColumn]);
+                                nFixC++;
+                            } else if (value > colUpper[iColumn] - 1.0e-8) {
+                                newSolver->setColLower(iColumn, colUpper[iColumn]);
+                                nFixC++;
+                            } else if (fixContinuous == 2) {
+                                newSolver->setColLower(iColumn, value);
+                                newSolver->setColUpper(iColumn, value);
+                                nFixC++;
+                                nFixC2++;
+                            }
+                        }
+                    }
+                }
+                newSolver->initialSolve();
+                if (!newSolver->isProvenOptimal()) {
+                    //newSolver->writeMps("bad.mps");
+                    //assert (newSolver->isProvenOptimal());
+                    exitAll = true;
+                    break;
+                }
+                sprintf(pumpPrint, "Before mini branch and bound, %d integers at bound fixed and %d continuous",
+                        nFix, nFixC);
+                if (nFixC2 + nFixI != 0)
+                    sprintf(pumpPrint + strlen(pumpPrint), " of which %d were internal integer and %d internal continuous",
+                            nFixI, nFixC2);
+                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                << pumpPrint
+                << CoinMessageEol;
+                double saveValue = newSolutionValue;
+                if (newSolutionValue - model_->getCutoffIncrement()
+                        > continuousObjectiveValue - 1.0e-7) {
+                    double saveFraction = fractionSmall_;
+                    if (numberTries > 1 && !numberBandBsolutions)
+                        fractionSmall_ *= 0.5;
+                    // Give branch and bound a bit more freedom
+                    double cutoff2 = newSolutionValue +
+                                     CoinMax(model_->getCutoffIncrement(), 1.0e-3);
+#if 0
+		      {
+                        OsiClpSolverInterface * clpSolver
+                        = dynamic_cast<OsiClpSolverInterface *> (newSolver);
+                        if (clpSolver) {
+                            ClpSimplex * simplex = clpSolver->getModelPtr();
+                            simplex->writeMps("testA.mps",2,1);
+			}
+		      }
+#endif
+                    int returnCode2 = smallBranchAndBound(newSolver, numberNodes_, newSolution, newSolutionValue,
+                                                          cutoff2, "CbcHeuristicLocalAfterFPump");
+                    fractionSmall_ = saveFraction;
+                    if (returnCode2 < 0) {
+                        if (returnCode2 == -2) {
+                            exitAll = true;
+                            returnCode = 0;
+                        } else {
+                            returnCode2 = 0; // returned on size - try changing
+                            //#define ROUND_AGAIN
+#ifdef ROUND_AGAIN
+                            if (numberTries == 1 && numberPasses > 20 && allowedPass < numberPasses - 1) {
+                                allowedPass = (numberPasses + allowedPass) >> 1;
+                                sprintf(pumpPrint,
+                                        "Fixing all variables which were last changed on pass %d and trying again",
+                                        allowedPass);
+                                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                                << pumpPrint
+                                << CoinMessageEol;
+                                stopBAB = false;
+                                continue;
+                            }
+#endif
+                        }
+                    }
+                    if ((returnCode2&2) != 0) {
+                        // could add cut
+                        returnCode2 &= ~2;
+                    }
+                    if (returnCode2) {
+                        numberBandBsolutions++;
+			// may not have got solution earlier
+			returnCode |= 1;
+		    }
+                } else {
+                    // no need
+                    exitAll = true;
+                    //returnCode=0;
+                }
+                // recompute solution value
+                if (returnCode && true) {
+#if 0
+		      {
+                        OsiClpSolverInterface * clpSolver
+                        = dynamic_cast<OsiClpSolverInterface *> (newSolver);
+                        if (clpSolver) {
+                            ClpSimplex * simplex = clpSolver->getModelPtr();
+                            simplex->writeMps("testB.mps",2,1);
+			}
+		      }
+#endif
+                    delete newSolver;
+                    newSolver = cloneBut(3); // was model_->continuousSolver()->clone();
+                    newSolutionValue = -saveOffset;
+                    double newSumInfeas = 0.0;
+                    const double * obj = newSolver->getObjCoefficients();
+                    for (int i = 0 ; i < numberColumns ; i++ ) {
+                        if (newSolver->isInteger(i)) {
+                            double value = newSolution[i];
+                            double nearest = floor(value + 0.5);
+                            newSumInfeas += fabs(value - nearest);
+                        }
+                        newSolutionValue += obj[i] * newSolution[i];
+                    }
+                    newSolutionValue *= direction;
+                }
+                bool gotSolution = false;
+                if (returnCode && newSolutionValue < saveValue) {
+                    sprintf(pumpPrint, "Mini branch and bound improved solution from %g to %g (%.2f seconds)",
+                            saveValue, newSolutionValue, model_->getCurrentSeconds());
+                    model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                    << pumpPrint
+                    << CoinMessageEol;
+                    memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+                    gotSolution = true;
+                    if (fixContinuous && nFixC + nFixC2 > 0) {
+                        // may be able to do even better
+                        int nFixed = 0;
+                        const double * lower = model_->solver()->getColLower();
+                        const double * upper = model_->solver()->getColUpper();
+                        for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                            double value = newSolution[iColumn];
+                            if (newSolver->isInteger(iColumn)) {
+                                value = floor(newSolution[iColumn] + 0.5);
+                                newSolver->setColLower(iColumn, value);
+                                newSolver->setColUpper(iColumn, value);
+                                nFixed++;
+                            } else {
+                                newSolver->setColLower(iColumn, lower[iColumn]);
+                                newSolver->setColUpper(iColumn, upper[iColumn]);
+                                if (value < lower[iColumn])
+                                    value = lower[iColumn];
+                                else if (value > upper[iColumn])
+                                    value = upper[iColumn];
+
+                            }
+                            newSolution[iColumn] = value;
+                        }
+                        newSolver->setColSolution(newSolution);
+                        //#define CLP_INVESTIGATE2
+#ifdef CLP_INVESTIGATE2
+                        {
+                            // check
+                            // get row activities
+                            int numberRows = newSolver->getNumRows();
+                            double * rowActivity = new double[numberRows];
+                            memset(rowActivity, 0, numberRows*sizeof(double));
+                            newSolver->getMatrixByCol()->times(newSolution, rowActivity) ;
+                            double largestInfeasibility = primalTolerance;
+                            double sumInfeasibility = 0.0;
+                            int numberBadRows = 0;
+                            const double * rowLower = newSolver->getRowLower();
+                            const double * rowUpper = newSolver->getRowUpper();
+                            for (i = 0 ; i < numberRows ; i++) {
+                                double value;
+                                value = rowLower[i] - rowActivity[i];
+                                if (value > primalTolerance) {
+                                    numberBadRows++;
+                                    largestInfeasibility = CoinMax(largestInfeasibility, value);
+                                    sumInfeasibility += value;
+                                }
+                                value = rowActivity[i] - rowUpper[i];
+                                if (value > primalTolerance) {
+                                    numberBadRows++;
+                                    largestInfeasibility = CoinMax(largestInfeasibility, value);
+                                    sumInfeasibility += value;
+                                }
+                            }
+                            printf("%d bad rows, largest inf %g sum %g\n",
+                                   numberBadRows, largestInfeasibility, sumInfeasibility);
+                            delete [] rowActivity;
+                        }
+#endif
+#ifdef COIN_HAS_CLP
+                        OsiClpSolverInterface * clpSolver
+                        = dynamic_cast<OsiClpSolverInterface *> (newSolver);
+                        if (clpSolver) {
+                            ClpSimplex * simplex = clpSolver->getModelPtr();
+                            //simplex->writeBasis("test.bas",true,2);
+                            //simplex->writeMps("test.mps",2,1);
+                            if (nFixed*3 > numberColumns*2)
+                                simplex->allSlackBasis(); // may as well go from all slack
+                            simplex->primal(1);
+                            clpSolver->setWarmStart(NULL);
+                        }
+#endif
+                        newSolver->initialSolve();
+                        if (newSolver->isProvenOptimal()) {
+                            double value = newSolver->getObjValue() * newSolver->getObjSense();
+                            if (value < newSolutionValue) {
+                                //newSolver->writeMps("query","mps");
+#ifdef JJF_ZERO
+                                {
+                                    double saveOffset;
+                                    newSolver->getDblParam(OsiObjOffset, saveOffset);
+                                    const double * obj = newSolver->getObjCoefficients();
+                                    double newTrueSolutionValue = -saveOffset;
+                                    double newSumInfeas = 0.0;
+                                    int numberColumns = newSolver->getNumCols();
+                                    const double * solution = newSolver->getColSolution();
+                                    for (int  i = 0 ; i < numberColumns ; i++ ) {
+                                        if (newSolver->isInteger(i)) {
+                                            double value = solution[i];
+                                            double nearest = floor(value + 0.5);
+                                            newSumInfeas += fabs(value - nearest);
+                                        }
+                                        if (solution[i])
+                                            printf("%d obj %g val %g - total %g\n", i, obj[i], solution[i],
+                                                   newTrueSolutionValue);
+                                        newTrueSolutionValue += obj[i] * solution[i];
+                                    }
+                                    printf("obj %g - inf %g\n", newTrueSolutionValue,
+                                           newSumInfeas);
+                                }
+#endif
+                                sprintf(pumpPrint, "Freeing continuous variables gives a solution of %g", value);
+                                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                                << pumpPrint
+                                << CoinMessageEol;
+                                newSolutionValue = value;
+                                memcpy(betterSolution, newSolver->getColSolution(), numberColumns*sizeof(double));
+                            }
+                        } else {
+                            //newSolver->writeMps("bad3.mps");
+			  sprintf(pumpPrint, "On closer inspection solution is not valid");
+			  model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+			    << pumpPrint
+			    << CoinMessageEol;
+                            exitAll = true;
+                            break;
+                        }
+                    }
+                } else {
+                    sprintf(pumpPrint, "Mini branch and bound did not improve solution (%.2f seconds)",
+                            model_->getCurrentSeconds());
+                    model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                    << pumpPrint
+                    << CoinMessageEol;
+                    if (returnCode && newSolutionValue < saveValue + 1.0e-3 && nFixC + nFixC2) {
+                        // may be able to do better
+                        const double * lower = model_->solver()->getColLower();
+                        const double * upper = model_->solver()->getColUpper();
+                        for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                            if (newSolver->isInteger(iColumn)) {
+                                double value = floor(newSolution[iColumn] + 0.5);
+                                newSolver->setColLower(iColumn, value);
+                                newSolver->setColUpper(iColumn, value);
+                            } else {
+                                newSolver->setColLower(iColumn, lower[iColumn]);
+                                newSolver->setColUpper(iColumn, upper[iColumn]);
+                            }
+                        }
+                        newSolver->initialSolve();
+                        if (newSolver->isProvenOptimal()) {
+                            double value = newSolver->getObjValue() * newSolver->getObjSense();
+                            if (value < saveValue) {
+                                sprintf(pumpPrint, "Freeing continuous variables gives a solution of %g", value);
+                                model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+                                << pumpPrint
+                                << CoinMessageEol;
+                                newSolutionValue = value;
+                                memcpy(betterSolution, newSolver->getColSolution(), numberColumns*sizeof(double));
+                                gotSolution = true;
+                            }
+                        }
+                    }
+                }
+                if (gotSolution) {
+                    if ((accumulate_&1) != 0) {
+                        model_->incrementUsed(betterSolution); // for local search
+                    }
+                    solutionValue = newSolutionValue;
+                    solutionFound = true;
+		    numberSolutions++;
+		    if (numberSolutions>=maxSolutions)
+		      exitAll = true;
+                    if (exitNow(newSolutionValue))
+                        exitAll = true;
+                    CoinWarmStartBasis * basis =
+                        dynamic_cast<CoinWarmStartBasis *>(newSolver->getWarmStart()) ;
+                    if (basis) {
+                        bestBasis = * basis;
+                        delete basis;
+                        int action = model_->dealWithEventHandler(CbcEventHandler::heuristicSolution, newSolutionValue, betterSolution);
+                        if (action == 0) {
+                            double * saveOldSolution = CoinCopyOfArray(model_->bestSolution(), numberColumns);
+                            double saveObjectiveValue = model_->getMinimizationObjValue();
+                            model_->setBestSolution(betterSolution, numberColumns, newSolutionValue);
+                            if (saveOldSolution && saveObjectiveValue < model_->getMinimizationObjValue())
+                                model_->setBestSolution(saveOldSolution, numberColumns, saveObjectiveValue);
+                            delete [] saveOldSolution;
+                        }
+                        if (!action || model_->getCurrentSeconds() > model_->getMaximumSeconds()) {
+                            exitAll = true; // exit
+                            break;
+                        }
+                    }
+                }
+            } // end stopBAB while
+            delete newSolver;
+        }
+        if (solutionFound) finalReturnCode = 1;
+        cutoff = CoinMin(cutoff, solutionValue - model_->getCutoffIncrement());
+        if (numberTries >= maximumRetries_ || !solutionFound || exitAll || cutoff < continuousObjectiveValue + 1.0e-7) {
+            break;
+        } else {
+            solutionFound = false;
+            if (absoluteIncrement_ > 0.0 || relativeIncrement_ > 0.0) {
+                double gap = relativeIncrement_ * fabs(solutionValue);
+                double change = CoinMax(gap, absoluteIncrement_);
+                cutoff = CoinMin(cutoff, solutionValue - change);
+            } else {
+                //double weights[10]={0.1,0.1,0.2,0.2,0.2,0.3,0.3,0.3,0.4,0.5};
+                double weights[10] = {0.1, 0.2, 0.3, 0.3, 0.4, 0.4, 0.4, 0.5, 0.5, 0.6};
+                cutoff -= weights[CoinMin(numberTries-1, 9)] * (cutoff - continuousObjectiveValue);
+            }
+            // But round down
+            if (exactMultiple)
+                cutoff = exactMultiple * floor(cutoff / exactMultiple);
+            if (cutoff < continuousObjectiveValue)
+                break;
+            sprintf(pumpPrint, "Round again with cutoff of %g", cutoff);
+            model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+            << pumpPrint
+            << CoinMessageEol;
+            if ((accumulate_&3) < 2 && usedColumn) {
+                for (int i = 0; i < numberColumns; i++)
+                    usedColumn[i] = -1;
+            }
+            averageIterationsPerTry = totalNumberIterations / numberTries;
+            numberIterationsLastPass =  totalNumberIterations;
+            totalNumberPasses += numberPasses - 1;
+        }
+    }
+/*
+  End of the `exitAll' loop.
+*/
+#ifdef RAND_RAND
+    delete [] randomFactor;
+#endif
+    delete solver; // probably NULL but do anyway
+    if (!finalReturnCode && closestSolution && closestObjectiveValue <= 10.0 &&
+            usedColumn && !model_->maximumSecondsReached()) {
+        // try a bit of branch and bound
+        OsiSolverInterface * newSolver = cloneBut(1); // was model_->continuousSolver()->clone();
+        const double * colLower = newSolver->getColLower();
+        const double * colUpper = newSolver->getColUpper();
+        int i;
+        double rhs = 0.0;
+        for (i = 0; i < numberIntegersOrig; i++) {
+            int iColumn = integerVariableOrig[i];
+            int direction = closestSolution[i];
+            closestSolution[i] = iColumn;
+            if (direction == 0) {
+                // keep close to LB
+                rhs += colLower[iColumn];
+                lastSolution[i] = 1.0;
+            } else {
+                // keep close to UB
+                rhs -= colUpper[iColumn];
+                lastSolution[i] = -1.0;
+            }
+        }
+        newSolver->addRow(numberIntegersOrig, closestSolution,
+                          lastSolution, -COIN_DBL_MAX, rhs + 10.0);
+        //double saveValue = newSolutionValue;
+        //newSolver->writeMps("sub");
+        int returnCode = smallBranchAndBound(newSolver, numberNodes_, newSolution, newSolutionValue,
+                                             newSolutionValue, "CbcHeuristicLocalAfterFPump");
+        if (returnCode < 0)
+            returnCode = 0; // returned on size
+        if ((returnCode&2) != 0) {
+            // could add cut
+            returnCode &= ~2;
+        }
+        if (returnCode) {
+            //printf("old sol of %g new of %g\n",saveValue,newSolutionValue);
+            memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+            //abort();
+            solutionValue = newSolutionValue;
+            solutionFound = true;
+	    numberSolutions++;
+	    if (numberSolutions>=maxSolutions)
+	      exitAll = true;
+            if (exitNow(newSolutionValue))
+                exitAll = true;
+        }
+        delete newSolver;
+    }
+    delete clonedSolver;
+    delete [] roundingSolution;
+    delete [] usedColumn;
+    delete [] lastSolution;
+    delete [] newSolution;
+    delete [] closestSolution;
+    delete [] integerVariable;
+    delete [] firstPerturbedObjective;
+    delete [] firstPerturbedSolution;
+    if (solutionValue == incomingObjective)
+        sprintf(pumpPrint, "After %.2f seconds - Feasibility pump exiting - took %.2f seconds",
+                model_->getCurrentSeconds(), CoinCpuTime() - time1);
+    else if (numberSolutions < maxSolutions)
+      sprintf(pumpPrint, "After %.2f seconds - Feasibility pump exiting with objective of %g - took %.2f seconds",
+	      model_->getCurrentSeconds(), solutionValue, CoinCpuTime() - time1);
+    else 
+        sprintf(pumpPrint, "After %.2f seconds - Feasibility pump exiting with objective of %g (stopping after %d solutions) - took %.2f seconds",
+                model_->getCurrentSeconds(), solutionValue, 
+		numberSolutions,CoinCpuTime() - time1);
+    model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+      << pumpPrint
+      << CoinMessageEol;
+    if (bestBasis.getNumStructural())
+        model_->setBestSolutionBasis(bestBasis);
+    //model_->setMinimizationObjValue(saveBestObjective);
+    if ((accumulate_&1) != 0 && numberSolutions > 1 && !model_->getSolutionCount()) {
+        model_->setSolutionCount(1); // for local search
+        model_->setNumberHeuristicSolutions(1);
+    }
+#ifdef COIN_DEVELOP
+    {
+        double ncol = model_->solver()->getNumCols();
+        double nrow = model_->solver()->getNumRows();
+        printf("XXX total iterations %d ratios - %g %g %g\n",
+               totalNumberIterations,
+               static_cast<double> (totalNumberIterations) / nrow,
+               static_cast<double> (totalNumberIterations) / ncol,
+               static_cast<double> (totalNumberIterations) / (2*nrow + 2*ncol));
+    }
+#endif
+    return finalReturnCode;
+}
+
+/**************************END MAIN PROCEDURE ***********************************/
+
+// update model
+void CbcHeuristicFPump::setModel(CbcModel * model)
+{
+    model_ = model;
+}
+
+/* Rounds solution - down if < downValue
+   returns 1 if current is a feasible solution
+*/
+int
+CbcHeuristicFPump::rounds(OsiSolverInterface * solver, double * solution,
+                          //const double * objective,
+                          int numberIntegers, const int * integerVariable,
+                          /*char * pumpPrint,*/ int iter,
+                          /*bool roundExpensive,*/ double downValue, int *flip)
+{
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance ;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance) ;
+
+    int i;
+
+    const double * cost = solver->getObjCoefficients();
+    int flip_up = 0;
+    int flip_down  = 0;
+    double  v = randomNumberGenerator_.randomDouble() * 20.0;
+    int nn = 10 + static_cast<int> (v);
+    int nnv = 0;
+    int * list = new int [nn];
+    double * val = new double [nn];
+    for (i = 0; i < nn; i++) val[i] = .001;
+
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    int numberRows = solver->getNumRows();
+    if (false && (iter&1) != 0) {
+        // Do set covering variables
+        const CoinPackedMatrix * matrixByRow = solver->getMatrixByRow();
+        const double * elementByRow = matrixByRow->getElements();
+        const int * column = matrixByRow->getIndices();
+        const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+        const int * rowLength = matrixByRow->getVectorLengths();
+        for (i = 0; i < numberRows; i++) {
+            if (rowLower[i] == 1.0 && rowUpper[i] == 1.0) {
+                bool cover = true;
+                double largest = 0.0;
+                int jColumn = -1;
+                for (CoinBigIndex k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) {
+                    int iColumn = column[k];
+                    if (elementByRow[k] != 1.0 || !solver->isInteger(iColumn)) {
+                        cover = false;
+                        break;
+                    } else {
+                        if (solution[iColumn]) {
+                            double value = solution[iColumn] *
+                                           (randomNumberGenerator_.randomDouble() + 5.0);
+                            if (value > largest) {
+                                largest = value;
+                                jColumn = iColumn;
+                            }
+                        }
+                    }
+                }
+                if (cover) {
+                    for (CoinBigIndex k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) {
+                        int iColumn = column[k];
+                        if (iColumn == jColumn)
+                            solution[iColumn] = 1.0;
+                        else
+                            solution[iColumn] = 0.0;
+                    }
+                }
+            }
+        }
+    }
+    int numberColumns = solver->getNumCols();
+#ifdef JJF_ZERO
+    // Do set covering variables
+    const CoinPackedMatrix * matrixByRow = solver->getMatrixByRow();
+    const double * elementByRow = matrixByRow->getElements();
+    const int * column = matrixByRow->getIndices();
+    const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+    const int * rowLength = matrixByRow->getVectorLengths();
+    double * sortTemp = new double[numberColumns];
+    int * whichTemp = new int [numberColumns];
+    char * rowTemp = new char [numberRows];
+    memset(rowTemp, 0, numberRows);
+    for (i = 0; i < numberColumns; i++)
+        whichTemp[i] = -1;
+    int nSOS = 0;
+    for (i = 0; i < numberRows; i++) {
+        if (rowLower[i] == 1.0 && rowUpper[i] == 1.0) {
+            bool cover = true;
+            for (CoinBigIndex k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) {
+                int iColumn = column[k];
+                if (elementByRow[k] != 1.0 || !solver->isInteger(iColumn)) {
+                    cover = false;
+                    break;
+                }
+            }
+            if (cover) {
+                rowTemp[i] = 1;
+                nSOS++;
+                for (CoinBigIndex k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) {
+                    int iColumn = column[k];
+                    double value = solution[iColumn];
+                    whichTemp[iColumn] = iColumn;
+                }
+            }
+        }
+    }
+    if (nSOS) {
+        // Column copy
+        const CoinPackedMatrix * matrixByColumn = solver->getMatrixByCol();
+        //const double * element = matrixByColumn->getElements();
+        const int * row = matrixByColumn->getIndices();
+        const CoinBigIndex * columnStart = matrixByColumn->getVectorStarts();
+        const int * columnLength = matrixByColumn->getVectorLengths();
+        int nLook = 0;
+        for (i = 0; i < numberColumns; i++) {
+            if (whichTemp[i] >= 0) {
+                whichTemp[nLook] = i;
+                double value = solution[i];
+                if (value < 0.5)
+                    value *= (0.1 * randomNumberGenerator_.randomDouble() + 0.3);
+                sortTemp[nLook++] = -value;
+            }
+        }
+        CoinSort_2(sortTemp, sortTemp + nLook, whichTemp);
+        double smallest = 1.0;
+        int nFix = 0;
+        int nOne = 0;
+        for (int j = 0; j < nLook; j++) {
+            int jColumn = whichTemp[j];
+            double thisValue = solution[jColumn];
+            if (!thisValue)
+                continue;
+            if (thisValue == 1.0)
+                nOne++;
+            smallest = CoinMin(smallest, thisValue);
+            solution[jColumn] = 1.0;
+            double largest = 0.0;
+            for (CoinBigIndex jEl = columnStart[jColumn];
+                    jEl < columnStart[jColumn] + columnLength[jColumn]; jEl++) {
+                int jRow = row[jEl];
+                if (rowTemp[jRow]) {
+                    for (CoinBigIndex k = rowStart[jRow]; k < rowStart[jRow] + rowLength[jRow]; k++) {
+                        int iColumn = column[k];
+                        if (solution[iColumn]) {
+                            if (iColumn != jColumn) {
+                                double value = solution[iColumn];
+                                if (value > largest)
+                                    largest = value;
+                                solution[iColumn] = 0.0;
+                            }
+                        }
+                    }
+                }
+            }
+            if (largest > thisValue)
+                printf("%d was at %g - chosen over a value of %g\n",
+                       jColumn, thisValue, largest);
+            nFix++;
+        }
+        printf("%d fixed out of %d (%d at one already)\n",
+               nFix, nLook, nOne);
+    }
+    delete [] sortTemp;
+    delete [] whichTemp;
+    delete [] rowTemp;
+#endif
+    const double * columnLower = solver->getColLower();
+    const double * columnUpper = solver->getColUpper();
+    // Check if valid with current solution (allow for 0.99999999s)
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = solution[iColumn];
+        double round = floor(value + 0.5);
+        if (fabs(value - round) > primalTolerance)
+            break;
+    }
+    if (i == numberIntegers) {
+        // may be able to use solution even if 0.99999's
+        double * saveLower = CoinCopyOfArray(columnLower, numberColumns);
+        double * saveUpper = CoinCopyOfArray(columnUpper, numberColumns);
+        double * saveSolution = CoinCopyOfArray(solution, numberColumns);
+        double * tempSolution = CoinCopyOfArray(solution, numberColumns);
+        CoinWarmStartBasis  * saveBasis =
+            dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            double value = solution[iColumn];
+            double round = floor(value + 0.5);
+            solver->setColLower(iColumn, round);
+            solver->setColUpper(iColumn, round);
+            tempSolution[iColumn] = round;
+        }
+        solver->setColSolution(tempSolution);
+        delete [] tempSolution;
+        solver->resolve();
+        solver->setColLower(saveLower);
+        solver->setColUpper(saveUpper);
+        solver->setWarmStart(saveBasis);
+        delete [] saveLower;
+        delete [] saveUpper;
+        delete saveBasis;
+        if (!solver->isProvenOptimal()) {
+            solver->setColSolution(saveSolution);
+        }
+        delete [] saveSolution;
+        if (solver->isProvenOptimal()) {
+            // feasible
+            delete [] list;
+            delete [] val;
+            return 1;
+        }
+    }
+    //double * saveSolution = CoinCopyOfArray(solution,numberColumns);
+    // return rounded solution
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = solution[iColumn];
+        double round = floor(value + primalTolerance);
+        if (value - round > downValue) round += 1.;
+#ifndef JJF_ONE
+        if (round < integerTolerance && cost[iColumn] < -1. + integerTolerance) flip_down++;
+        if (round > 1. - integerTolerance && cost[iColumn] > 1. - integerTolerance) flip_up++;
+#else
+        if (round < columnLower[iColumn] + integerTolerance && cost[iColumn] < -1. + integerTolerance) flip_down++;
+        if (round > columnUpper[iColumn] - integerTolerance && cost[iColumn] > 1. - integerTolerance) flip_up++;
+#endif
+        if (flip_up + flip_down == 0) {
+            for (int k = 0; k < nn; k++) {
+                if (fabs(value - round) > val[k]) {
+                    nnv++;
+                    for (int j = nn - 2; j >= k; j--) {
+                        val[j+1] = val[j];
+                        list[j+1] = list[j];
+                    }
+                    val[k] = fabs(value - round);
+                    list[k] = iColumn;
+                    break;
+                }
+            }
+        }
+        solution[iColumn] = round;
+    }
+
+    if (nnv > nn) nnv = nn;
+    //if (iter != 0)
+    //sprintf(pumpPrint+strlen(pumpPrint),"up = %5d , down = %5d", flip_up, flip_down);
+    *flip = flip_up + flip_down;
+
+    if (*flip == 0 && iter != 0) {
+        //sprintf(pumpPrint+strlen(pumpPrint)," -- rand = %4d (%4d) ", nnv, nn);
+        for (i = 0; i < nnv; i++) {
+            // was solution[list[i]] = 1. - solution[list[i]]; but does that work for 7>=x>=6
+            int index = list[i];
+            double value = solution[index];
+            if (value <= 1.0) {
+                solution[index] = 1.0 - value;
+            } else if (value < columnLower[index] + integerTolerance) {
+                solution[index] = value + 1.0;
+            } else if (value > columnUpper[index] - integerTolerance) {
+                solution[index] = value - 1.0;
+            } else {
+                solution[index] = value - 1.0;
+            }
+        }
+        *flip = nnv;
+    } else {
+        //sprintf(pumpPrint+strlen(pumpPrint)," ");
+    }
+    delete [] list;
+    delete [] val;
+    //iter++;
+
+    // get row activities
+    double * rowActivity = new double[numberRows];
+    memset(rowActivity, 0, numberRows*sizeof(double));
+    solver->getMatrixByCol()->times(solution, rowActivity) ;
+    double largestInfeasibility = primalTolerance;
+    double sumInfeasibility = 0.0;
+    int numberBadRows = 0;
+    for (i = 0 ; i < numberRows ; i++) {
+        double value;
+        value = rowLower[i] - rowActivity[i];
+        if (value > primalTolerance) {
+            numberBadRows++;
+            largestInfeasibility = CoinMax(largestInfeasibility, value);
+            sumInfeasibility += value;
+        }
+        value = rowActivity[i] - rowUpper[i];
+        if (value > primalTolerance) {
+            numberBadRows++;
+            largestInfeasibility = CoinMax(largestInfeasibility, value);
+            sumInfeasibility += value;
+        }
+    }
+#ifdef JJF_ZERO
+    if (largestInfeasibility > primalTolerance && numberBadRows*10 < numberRows) {
+        // Can we improve by flipping
+        for (int iPass = 0; iPass < 10; iPass++) {
+            int numberColumns = solver->getNumCols();
+            const CoinPackedMatrix * matrixByCol = solver->getMatrixByCol();
+            const double * element = matrixByCol->getElements();
+            const int * row = matrixByCol->getIndices();
+            const CoinBigIndex * columnStart = matrixByCol->getVectorStarts();
+            const int * columnLength = matrixByCol->getVectorLengths();
+            double oldSum = sumInfeasibility;
+            // First improve by moving continuous ones
+            for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (!solver->isInteger(iColumn)) {
+                    double solValue = solution[iColumn];
+                    double thetaUp = columnUpper[iColumn] - solValue;
+                    double improvementUp = 0.0;
+                    if (thetaUp > primalTolerance) {
+                        // can go up
+                        for (CoinBigIndex j = columnStart[iColumn];
+                                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                            int iRow = row[j];
+                            double distanceUp = rowUpper[iRow] - rowActivity[iRow];
+                            double distanceDown = rowLower[iRow] - rowActivity[iRow];
+                            double el = element[j];
+                            if (el > 0.0) {
+                                // positive element
+                                if (distanceUp > 0.0) {
+                                    if (thetaUp*el > distanceUp)
+                                        thetaUp = distanceUp / el;
+                                } else {
+                                    improvementUp -= el;
+                                }
+                                if (distanceDown > 0.0) {
+                                    if (thetaUp*el > distanceDown)
+                                        thetaUp = distanceDown / el;
+                                    improvementUp += el;
+                                }
+                            } else {
+                                // negative element
+                                if (distanceDown < 0.0) {
+                                    if (thetaUp*el < distanceDown)
+                                        thetaUp = distanceDown / el;
+                                } else {
+                                    improvementUp += el;
+                                }
+                                if (distanceUp < 0.0) {
+                                    if (thetaUp*el < distanceUp)
+                                        thetaUp = distanceUp / el;
+                                    improvementUp -= el;
+                                }
+                            }
+                        }
+                    }
+                    double thetaDown = solValue - columnLower[iColumn];
+                    double improvementDown = 0.0;
+                    if (thetaDown > primalTolerance) {
+                        // can go down
+                        for (CoinBigIndex j = columnStart[iColumn];
+                                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                            int iRow = row[j];
+                            double distanceUp = rowUpper[iRow] - rowActivity[iRow];
+                            double distanceDown = rowLower[iRow] - rowActivity[iRow];
+                            double el = -element[j]; // not change in sign form up
+                            if (el > 0.0) {
+                                // positive element
+                                if (distanceUp > 0.0) {
+                                    if (thetaDown*el > distanceUp)
+                                        thetaDown = distanceUp / el;
+                                } else {
+                                    improvementDown -= el;
+                                }
+                                if (distanceDown > 0.0) {
+                                    if (thetaDown*el > distanceDown)
+                                        thetaDown = distanceDown / el;
+                                    improvementDown += el;
+                                }
+                            } else {
+                                // negative element
+                                if (distanceDown < 0.0) {
+                                    if (thetaDown*el < distanceDown)
+                                        thetaDown = distanceDown / el;
+                                } else {
+                                    improvementDown += el;
+                                }
+                                if (distanceUp < 0.0) {
+                                    if (thetaDown*el < distanceUp)
+                                        thetaDown = distanceUp / el;
+                                    improvementDown -= el;
+                                }
+                            }
+                        }
+                        if (thetaUp < 1.0e-8)
+                            improvementUp = 0.0;
+                        if (thetaDown < 1.0e-8)
+                            improvementDown = 0.0;
+                        double theta;
+                        if (improvementUp >= improvementDown) {
+                            theta = thetaUp;
+                        } else {
+                            improvementUp = improvementDown;
+                            theta = -thetaDown;
+                        }
+                        if (improvementUp > 1.0e-8 && fabs(theta) > 1.0e-8) {
+                            // Could move
+                            double oldSum = 0.0;
+                            double newSum = 0.0;
+                            solution[iColumn] += theta;
+                            for (CoinBigIndex j = columnStart[iColumn];
+                                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                int iRow = row[j];
+                                double lower = rowLower[iRow];
+                                double upper = rowUpper[iRow];
+                                double value = rowActivity[iRow];
+                                if (value > upper)
+                                    oldSum += value - upper;
+                                else if (value < lower)
+                                    oldSum += lower - value;
+                                value += theta * element[j];
+                                rowActivity[iRow] = value;
+                                if (value > upper)
+                                    newSum += value - upper;
+                                else if (value < lower)
+                                    newSum += lower - value;
+                            }
+                            assert (newSum <= oldSum);
+                            sumInfeasibility += newSum - oldSum;
+                        }
+                    }
+                }
+            }
+            // Now flip some integers?
+#ifdef JJF_ZERO
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                double solValue = solution[iColumn];
+                assert (fabs(solValue - floor(solValue + 0.5)) < 1.0e-8);
+                double improvementUp = 0.0;
+                if (columnUpper[iColumn] >= solValue + 1.0) {
+                    // can go up
+                    double oldSum = 0.0;
+                    double newSum = 0.0;
+                    for (CoinBigIndex j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double lower = rowLower[iRow];
+                        double upper = rowUpper[iRow];
+                        double value = rowActivity[iRow];
+                        if (value > upper)
+                            oldSum += value - upper;
+                        else if (value < lower)
+                            oldSum += lower - value;
+                        value += element[j];
+                        if (value > upper)
+                            newSum += value - upper;
+                        else if (value < lower)
+                            newSum += lower - value;
+                    }
+                    improvementUp = oldSum - newSum;
+                }
+                double improvementDown = 0.0;
+                if (columnLower[iColumn] <= solValue - 1.0) {
+                    // can go down
+                    double oldSum = 0.0;
+                    double newSum = 0.0;
+                    for (CoinBigIndex j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double lower = rowLower[iRow];
+                        double upper = rowUpper[iRow];
+                        double value = rowActivity[iRow];
+                        if (value > upper)
+                            oldSum += value - upper;
+                        else if (value < lower)
+                            oldSum += lower - value;
+                        value -= element[j];
+                        if (value > upper)
+                            newSum += value - upper;
+                        else if (value < lower)
+                            newSum += lower - value;
+                    }
+                    improvementDown = oldSum - newSum;
+                }
+                double theta;
+                if (improvementUp >= improvementDown) {
+                    theta = 1.0;
+                } else {
+                    improvementUp = improvementDown;
+                    theta = -1.0;
+                }
+                if (improvementUp > 1.0e-8 && fabs(theta) > 1.0e-8) {
+                    // Could move
+                    double oldSum = 0.0;
+                    double newSum = 0.0;
+                    solution[iColumn] += theta;
+                    for (CoinBigIndex j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double lower = rowLower[iRow];
+                        double upper = rowUpper[iRow];
+                        double value = rowActivity[iRow];
+                        if (value > upper)
+                            oldSum += value - upper;
+                        else if (value < lower)
+                            oldSum += lower - value;
+                        value += theta * element[j];
+                        rowActivity[iRow] = value;
+                        if (value > upper)
+                            newSum += value - upper;
+                        else if (value < lower)
+                            newSum += lower - value;
+                    }
+                    assert (newSum <= oldSum);
+                    sumInfeasibility += newSum - oldSum;
+                }
+            }
+#else
+            int bestColumn = -1;
+            double bestImprovement = primalTolerance;
+            double theta = 0.0;
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                double solValue = solution[iColumn];
+                assert (fabs(solValue - floor(solValue + 0.5)) < 1.0e-8);
+                double improvementUp = 0.0;
+                if (columnUpper[iColumn] >= solValue + 1.0) {
+                    // can go up
+                    double oldSum = 0.0;
+                    double newSum = 0.0;
+                    for (CoinBigIndex j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double lower = rowLower[iRow];
+                        double upper = rowUpper[iRow];
+                        double value = rowActivity[iRow];
+                        if (value > upper)
+                            oldSum += value - upper;
+                        else if (value < lower)
+                            oldSum += lower - value;
+                        value += element[j];
+                        if (value > upper)
+                            newSum += value - upper;
+                        else if (value < lower)
+                            newSum += lower - value;
+                    }
+                    improvementUp = oldSum - newSum;
+                }
+                double improvementDown = 0.0;
+                if (columnLower[iColumn] <= solValue - 1.0) {
+                    // can go down
+                    double oldSum = 0.0;
+                    double newSum = 0.0;
+                    for (CoinBigIndex j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double lower = rowLower[iRow];
+                        double upper = rowUpper[iRow];
+                        double value = rowActivity[iRow];
+                        if (value > upper)
+                            oldSum += value - upper;
+                        else if (value < lower)
+                            oldSum += lower - value;
+                        value -= element[j];
+                        if (value > upper)
+                            newSum += value - upper;
+                        else if (value < lower)
+                            newSum += lower - value;
+                    }
+                    improvementDown = oldSum - newSum;
+                }
+                double improvement = CoinMax(improvementUp, improvementDown);
+                if (improvement > bestImprovement) {
+                    bestImprovement = improvement;
+                    bestColumn = iColumn;
+                    if (improvementUp > improvementDown)
+                        theta = 1.0;
+                    else
+                        theta = -1.0;
+                }
+            }
+            if (bestColumn >= 0) {
+                // Could move
+                int iColumn = bestColumn;
+                double oldSum = 0.0;
+                double newSum = 0.0;
+                solution[iColumn] += theta;
+                for (CoinBigIndex j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    double lower = rowLower[iRow];
+                    double upper = rowUpper[iRow];
+                    double value = rowActivity[iRow];
+                    if (value > upper)
+                        oldSum += value - upper;
+                    else if (value < lower)
+                        oldSum += lower - value;
+                    value += theta * element[j];
+                    rowActivity[iRow] = value;
+                    if (value > upper)
+                        newSum += value - upper;
+                    else if (value < lower)
+                        newSum += lower - value;
+                }
+                assert (newSum <= oldSum);
+                sumInfeasibility += newSum - oldSum;
+            }
+#endif
+            if (oldSum <= sumInfeasibility + primalTolerance)
+                break; // no good
+        }
+    }
+    //delete [] saveSolution;
+#endif
+    delete [] rowActivity;
+    return (largestInfeasibility > primalTolerance) ? 0 : 1;
+}
+// Set maximum Time (default off) - also sets starttime to current
+void
+CbcHeuristicFPump::setMaximumTime(double value)
+{
+    startTime_ = CoinCpuTime();
+    maximumTime_ = value;
+}
+
+# ifdef COIN_HAS_CLP
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+CbcDisasterHandler::CbcDisasterHandler (CbcModel * model)
+        : OsiClpDisasterHandler(),
+        cbcModel_(model)
+{
+    if (model) {
+        osiModel_
+        = dynamic_cast<OsiClpSolverInterface *> (model->solver());
+        if (osiModel_)
+            setSimplex(osiModel_->getModelPtr());
+    }
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+CbcDisasterHandler::CbcDisasterHandler (const CbcDisasterHandler & rhs)
+        : OsiClpDisasterHandler(rhs),
+        cbcModel_(rhs.cbcModel_)
+{
+}
+
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+CbcDisasterHandler::~CbcDisasterHandler ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+CbcDisasterHandler &
+CbcDisasterHandler::operator=(const CbcDisasterHandler & rhs)
+{
+    if (this != &rhs) {
+        OsiClpDisasterHandler::operator=(rhs);
+        cbcModel_ = rhs.cbcModel_;
+    }
+    return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpDisasterHandler * CbcDisasterHandler::clone() const
+{
+    return new CbcDisasterHandler(*this);
+}
+// Type of disaster 0 can fix, 1 abort
+int
+CbcDisasterHandler::typeOfDisaster()
+{
+    if (!cbcModel_->parentModel() &&
+            (cbcModel_->specialOptions()&2048) == 0) {
+        return 0;
+    } else {
+        if (cbcModel_->parentModel())
+            cbcModel_->setMaximumNodes(0);
+        return 1;
+    }
+}
+/* set model. */
+void
+CbcDisasterHandler::setCbcModel(CbcModel * model)
+{
+    cbcModel_ = model;
+    if (model) {
+        osiModel_
+        = dynamic_cast<OsiClpSolverInterface *> (model->solver());
+        if (osiModel_)
+            setSimplex(osiModel_->getModelPtr());
+        else
+            setSimplex(NULL);
+    }
+}
+#endif
+
diff --git a/cbits/coin/CbcHeuristicFPump.hpp b/cbits/coin/CbcHeuristicFPump.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicFPump.hpp
@@ -0,0 +1,340 @@
+/* $Id: CbcHeuristicFPump.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicFeasibilityPump_H
+#define CbcHeuristicFeasibilityPump_H
+
+#include "CbcHeuristic.hpp"
+#include "OsiClpSolverInterface.hpp"
+
+/** Feasibility Pump class
+ */
+
+class CbcHeuristicFPump : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicFPump ();
+
+    // Constructor with model - assumed before cuts
+    CbcHeuristicFPump (CbcModel & model,
+                       double downValue = 0.5, bool roundExpensive = false);
+
+    // Copy constructor
+    CbcHeuristicFPump ( const CbcHeuristicFPump &);
+
+    // Destructor
+    ~CbcHeuristicFPump ();
+
+    /// Assignment operator
+    CbcHeuristicFPump & operator=(const CbcHeuristicFPump& rhs);
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution
+        with better objective value than one passed in
+        Sets solution values if good, sets objective value (only if good)
+        This is called after cuts have been added - so can not add cuts.
+
+        It may make sense for user to call this outside Branch and Cut to
+        get solution.  Or normally is just at root node.
+
+        * new meanings for when_ - on first try then set back to 1
+          11 - at end fix all integers at same bound throughout
+          12 - also fix all integers staying at same internal integral value throughout
+          13 - also fix all continuous variables staying at same bound throughout
+          14 - also fix all continuous variables staying at same internal value throughout
+          15 - as 13 but no internal integers
+      And beyond that, it's apparently possible for the range to be between 21
+      and 25, in which case it's reduced on entry to solution() to be between
+      11 and 15 and allSlack is set to true. Then, if we're not processing
+      general integers, we'll use an all-slack basis to solve ... what? Don't
+      see that yet.
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+
+    /// Set maximum Time (default off) - also sets starttime to current
+    void setMaximumTime(double value);
+    /// Get maximum Time (default 0.0 == time limit off)
+    inline double maximumTime() const {
+        return maximumTime_;
+    }
+    /// Set fake cutoff (default COIN_DBL_MAX == off)
+    inline void setFakeCutoff(double value) {
+        fakeCutoff_ = value;
+    }
+    /// Get fake cutoff (default 0.0 == off)
+    inline double fakeCutoff() const {
+        return fakeCutoff_;
+    }
+    /// Set absolute increment (default 0.0 == off)
+    inline void setAbsoluteIncrement(double value) {
+        absoluteIncrement_ = value;
+    }
+    /// Get absolute increment (default 0.0 == off)
+    inline double absoluteIncrement() const {
+        return absoluteIncrement_;
+    }
+    /// Set relative increment (default 0.0 == off)
+    inline void setRelativeIncrement(double value) {
+        relativeIncrement_ = value;
+    }
+    /// Get relative increment (default 0.0 == off)
+    inline double relativeIncrement() const {
+        return relativeIncrement_;
+    }
+    /// Set default rounding (default 0.5)
+    inline void setDefaultRounding(double value) {
+        defaultRounding_ = value;
+    }
+    /// Get default rounding (default 0.5)
+    inline double defaultRounding() const {
+        return defaultRounding_;
+    }
+    /// Set initial weight (default 0.0 == off)
+    inline void setInitialWeight(double value) {
+        initialWeight_ = value;
+    }
+    /// Get initial weight (default 0.0 == off)
+    inline double initialWeight() const {
+        return initialWeight_;
+    }
+    /// Set weight factor (default 0.1)
+    inline void setWeightFactor(double value) {
+        weightFactor_ = value;
+    }
+    /// Get weight factor (default 0.1)
+    inline double weightFactor() const {
+        return weightFactor_;
+    }
+    /// Set threshold cost for using original cost - even on continuous (default infinity)
+    inline void setArtificialCost(double value) {
+        artificialCost_ = value;
+    }
+    /// Get threshold cost for using original cost - even on continuous (default infinity)
+    inline double artificialCost() const {
+        return artificialCost_;
+    }
+    /// Get iteration to size ratio
+    inline double iterationRatio() const {
+        return iterationRatio_;
+    }
+    /// Set iteration to size ratio
+    inline void setIterationRatio(double value) {
+        iterationRatio_ = value;
+    }
+    /// Set maximum passes (default 100)
+    inline void setMaximumPasses(int value) {
+        maximumPasses_ = value;
+    }
+    /// Get maximum passes (default 100)
+    inline int maximumPasses() const {
+        return maximumPasses_;
+    }
+    /// Set maximum retries (default 1)
+    inline void setMaximumRetries(int value) {
+        maximumRetries_ = value;
+    }
+    /// Get maximum retries (default 1)
+    inline int maximumRetries() const {
+        return maximumRetries_;
+    }
+    /**  Set use of multiple solutions and solves
+         0 - do not reuse solves, do not accumulate integer solutions for local search
+         1 - do not reuse solves, accumulate integer solutions for local search
+         2 - reuse solves, do not accumulate integer solutions for local search
+         3 - reuse solves, accumulate integer solutions for local search
+         If we add 4 then use second form of problem (with extra rows and variables for general integers)
+       At some point (date?), I added
+
+       And then there are a few bit fields:
+       4 - something about general integers
+       So my (lh) guess for 4 was at least in the ballpark, but I'll have to
+       rethink 8 entirely (and it may well not mean the same thing as it did
+       when I added that comment.
+       8 - determines whether we process general integers
+
+       And on 090831, John added
+
+       If we add 4 then use second form of problem (with extra rows and
+       variables for general integers)
+         If we add 8 then can run after initial cuts (if no solution)
+    */
+    inline void setAccumulate(int value) {
+        accumulate_ = value;
+    }
+    /// Get accumulation option
+    inline int accumulate() const {
+        return accumulate_;
+    }
+    /**  Set whether to fix variables on known solution
+         0 - do not fix
+         1 - fix integers on reduced costs
+         2 - fix integers on reduced costs but only on entry
+    */
+    inline void setFixOnReducedCosts(int value) {
+        fixOnReducedCosts_ = value;
+    }
+    /// Get reduced cost option
+    inline int fixOnReducedCosts() const {
+        return fixOnReducedCosts_;
+    }
+    /**  Set reduced cost multiplier
+         1.0 as normal
+         <1.0 (x) - pretend gap is x* actual gap - just for fixing
+    */
+    inline void setReducedCostMultiplier(double value) {
+        reducedCostMultiplier_ = value;
+    }
+    /// Get reduced cost multiplier
+    inline double reducedCostMultiplier() const {
+        return reducedCostMultiplier_;
+    }
+
+protected:
+    // Data
+    /// Start time
+    double startTime_;
+    /// Maximum Cpu seconds
+    double maximumTime_;
+    /** Fake cutoff value.
+        If set then better of real cutoff and this used to add a constraint
+    */
+    double fakeCutoff_;
+    /// If positive carry on after solution expecting gain of at least this
+    double absoluteIncrement_;
+    /// If positive carry on after solution expecting gain of at least this times objective
+    double relativeIncrement_;
+    /// Default is round up if > this
+    double defaultRounding_;
+    /// Initial weight for true objective
+    double initialWeight_;
+    /// Factor for decreasing weight
+    double weightFactor_;
+    /// Threshold cost for using original cost - even on continuous
+    double artificialCost_;
+    /** If iterationRatio >0 use instead of maximumPasses_
+        test is iterations > ratio*(2*nrow+ncol) */
+    double iterationRatio_;
+    /**  Reduced cost multiplier
+         1.0 as normal
+         <1.0 (x) - pretend gap is x* actual gap - just for fixing
+    */
+    double reducedCostMultiplier_;
+    /// Maximum number of passes
+    int maximumPasses_;
+    /** Maximum number of retries if we find a solution.
+        If negative we clean out used array
+    */
+    int maximumRetries_;
+    /**  Set use of multiple solutions and solves
+         0 - do not reuse solves, do not accumulate integer solutions for local search
+         1 - do not reuse solves, accumulate integer solutions for local search
+         2 - reuse solves, do not accumulate integer solutions for local search
+         3 - reuse solves, accumulate integer solutions for local search
+         If we add 4 then use second form of problem (with extra rows and variables for general integers)
+         If we do not accumulate solutions then no mini branch and bounds will be done
+         reuse - refers to initial solve after adding in new "cut"
+         If we add 8 then can run after initial cuts (if no solution)
+    */
+    int accumulate_;
+    /**  Set whether to fix variables on known solution
+         0 - do not fix
+         1 - fix integers on reduced costs
+         2 - fix integers on reduced costs but only on entry
+    */
+    int fixOnReducedCosts_;
+    /// If true round to expensive
+    bool roundExpensive_;
+
+private:
+    /** Rounds solution - down if < downValue
+        If roundExpensive then always to more expnsive.
+        returns 0 if current is solution
+    */
+    int rounds(OsiSolverInterface * solver, double * solution,
+               /*const double * objective, */
+               int numberIntegers, const int * integerVariable,
+               /*char * pumpPrint,*/int passNumber,
+               /*bool roundExpensive=false,*/
+               double downValue = 0.5, int *flip = 0);
+    /* note for eagle eyed readers.
+       when_ can now be exotic -
+       <=10 normal
+    */
+};
+
+# ifdef COIN_HAS_CLP
+
+class CbcDisasterHandler : public OsiClpDisasterHandler {
+public:
+    /**@name Virtual methods that the derived classe should provide.
+    */
+    //@{
+#ifdef JJF_ZERO
+    /// Into simplex
+    virtual void intoSimplex();
+    /// Checks if disaster
+    virtual bool check() const ;
+    /// saves information for next attempt
+    virtual void saveInfo();
+#endif
+    /// Type of disaster 0 can fix, 1 abort
+    virtual int typeOfDisaster();
+    //@}
+
+
+    /**@name Constructors, destructor */
+
+    //@{
+    /** Default constructor. */
+    CbcDisasterHandler(CbcModel * model = NULL);
+    /** Destructor */
+    virtual ~CbcDisasterHandler();
+    // Copy
+    CbcDisasterHandler(const CbcDisasterHandler&);
+    // Assignment
+    CbcDisasterHandler& operator=(const CbcDisasterHandler&);
+    /// Clone
+    virtual ClpDisasterHandler * clone() const;
+
+    //@}
+
+    /**@name Sets/gets */
+
+    //@{
+    /** set model. */
+    void setCbcModel(CbcModel * model);
+    /// Get model
+    inline CbcModel * cbcModel() const {
+        return cbcModel_;
+    }
+
+    //@}
+
+
+protected:
+    /**@name Data members
+       The data members are protected to allow access for derived classes. */
+    //@{
+    /// Pointer to model
+    CbcModel * cbcModel_;
+
+    //@}
+};
+#endif
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicGreedy.cpp b/cbits/coin/CbcHeuristicGreedy.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicGreedy.cpp
@@ -0,0 +1,1870 @@
+/* $Id: CbcHeuristicGreedy.cpp 1888 2013-04-06 20:52:59Z stefan $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcHeuristicGreedy.hpp"
+#include "CoinSort.hpp"
+#include "CglPreProcess.hpp"
+// Default Constructor
+CbcHeuristicGreedyCover::CbcHeuristicGreedyCover()
+        : CbcHeuristic()
+{
+    // matrix  will automatically be empty
+    originalNumberRows_ = 0;
+    algorithm_ = 0;
+    numberTimes_ = 100;
+}
+
+// Constructor from model
+CbcHeuristicGreedyCover::CbcHeuristicGreedyCover(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    gutsOfConstructor(&model);
+    algorithm_ = 0;
+    numberTimes_ = 100;
+    whereFrom_ = 1;
+}
+
+// Destructor
+CbcHeuristicGreedyCover::~CbcHeuristicGreedyCover ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicGreedyCover::clone() const
+{
+    return new CbcHeuristicGreedyCover(*this);
+}
+// Guts of constructor from a CbcModel
+void
+CbcHeuristicGreedyCover::gutsOfConstructor(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix
+    assert(model->solver());
+    if (model->solver()->getNumRows()) {
+        matrix_ = *model->solver()->getMatrixByCol();
+    }
+    originalNumberRows_ = model->solver()->getNumRows();
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicGreedyCover::generateCpp( FILE * fp)
+{
+    CbcHeuristicGreedyCover other;
+    fprintf(fp, "0#include \"CbcHeuristicGreedy.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicGreedyCover heuristicGreedyCover(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicGreedyCover");
+    if (algorithm_ != other.algorithm_)
+        fprintf(fp, "3  heuristicGreedyCover.setAlgorithm(%d);\n", algorithm_);
+    else
+        fprintf(fp, "4  heuristicGreedyCover.setAlgorithm(%d);\n", algorithm_);
+    if (numberTimes_ != other.numberTimes_)
+        fprintf(fp, "3  heuristicGreedyCover.setNumberTimes(%d);\n", numberTimes_);
+    else
+        fprintf(fp, "4  heuristicGreedyCover.setNumberTimes(%d);\n", numberTimes_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicGreedyCover);\n");
+}
+
+// Copy constructor
+CbcHeuristicGreedyCover::CbcHeuristicGreedyCover(const CbcHeuristicGreedyCover & rhs)
+        :
+        CbcHeuristic(rhs),
+        matrix_(rhs.matrix_),
+        originalNumberRows_(rhs.originalNumberRows_),
+        algorithm_(rhs.algorithm_),
+        numberTimes_(rhs.numberTimes_)
+{
+}
+
+// Assignment operator
+CbcHeuristicGreedyCover &
+CbcHeuristicGreedyCover::operator=( const CbcHeuristicGreedyCover & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        matrix_ = rhs.matrix_;
+        originalNumberRows_ = rhs.originalNumberRows_;
+        algorithm_ = rhs.algorithm_;
+        numberTimes_ = rhs.numberTimes_;
+    }
+    return *this;
+}
+// Returns 1 if solution, 0 if not
+int
+CbcHeuristicGreedyCover::solution(double & solutionValue,
+                                  double * betterSolution)
+{
+    numCouldRun_++;
+    if (!model_)
+        return 0;
+    // See if to do
+    if (!when() || (when() == 1 && model_->phase() != 1))
+        return 0; // switched off
+    if (model_->getNodeCount() > numberTimes_)
+        return 0;
+    // See if at root node
+    bool atRoot = model_->getNodeCount() == 0;
+    int passNumber = model_->getCurrentPassNumber();
+    if (atRoot && passNumber != 1)
+        return 0;
+    OsiSolverInterface * solver = model_->solver();
+    const double * columnLower = solver->getColLower();
+    const double * columnUpper = solver->getColUpper();
+    // And original upper bounds in case we want to use them
+    const double * originalUpper = model_->continuousSolver()->getColUpper();
+    // But not if algorithm says so
+    if ((algorithm_ % 10) == 0)
+        originalUpper = columnUpper;
+    const double * rowLower = solver->getRowLower();
+    const double * solution = solver->getColSolution();
+    const double * objective = solver->getObjCoefficients();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    // This is number of rows when matrix was passed in
+    int numberRows = originalNumberRows_;
+    if (!numberRows)
+        return 0; // switched off
+
+    numRuns_++;
+    assert (numberRows == matrix_.getNumRows());
+    int iRow, iColumn;
+    double direction = solver->getObjSense();
+    double offset;
+    solver->getDblParam(OsiObjOffset, offset);
+    double newSolutionValue = -offset;
+    int returnCode = 0;
+
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+
+    // Get solution array for heuristic solution
+    int numberColumns = solver->getNumCols();
+    double * newSolution = new double [numberColumns];
+    double * rowActivity = new double[numberRows];
+    memset(rowActivity, 0, numberRows*sizeof(double));
+    bool allOnes = true;
+    // Get rounded down solution
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        CoinBigIndex j;
+        double value = solution[iColumn];
+        if (solver->isInteger(iColumn)) {
+            // Round down integer
+            if (fabs(floor(value + 0.5) - value) < integerTolerance) {
+                value = floor(CoinMax(value + 1.0e-3, columnLower[iColumn]));
+            } else {
+                value = CoinMax(floor(value), columnLower[iColumn]);
+            }
+        }
+        // make sure clean
+        value = CoinMin(value, columnUpper[iColumn]);
+        value = CoinMax(value, columnLower[iColumn]);
+        newSolution[iColumn] = value;
+        double cost = direction * objective[iColumn];
+        newSolutionValue += value * cost;
+        for (j = columnStart[iColumn];
+                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+            int iRow = row[j];
+            rowActivity[iRow] += value * element[j];
+            if (element[j] != 1.0)
+                allOnes = false;
+        }
+    }
+    // See if we round up
+    bool roundup = ((algorithm_ % 100) != 0);
+    if (roundup && allOnes) {
+        // Get rounded up solution
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            CoinBigIndex j;
+            double value = solution[iColumn];
+            if (solver->isInteger(iColumn)) {
+                // but round up if no activity
+                if (roundup && value >= 0.499999 && !newSolution[iColumn]) {
+                    bool choose = true;
+                    for (j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        if (rowActivity[iRow]) {
+                            choose = false;
+                            break;
+                        }
+                    }
+                    if (choose) {
+                        newSolution[iColumn] = 1.0;
+                        double cost = direction * objective[iColumn];
+                        newSolutionValue += cost;
+                        for (j = columnStart[iColumn];
+                                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                            int iRow = row[j];
+                            rowActivity[iRow] += 1.0;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    // Get initial list
+    int * which = new int [numberColumns];
+    for (iColumn = 0; iColumn < numberColumns; iColumn++)
+        which[iColumn] = iColumn;
+    int numberLook = numberColumns;
+    // See if we want to perturb more
+    double perturb = ((algorithm_ % 10) == 0) ? 0.1 : 0.25;
+    // Keep going round until a solution
+    while (true) {
+        // Get column with best ratio
+        int bestColumn = -1;
+        double bestRatio = COIN_DBL_MAX;
+        double bestStepSize = 0.0;
+        int newNumber = 0;
+        for (int jColumn = 0; jColumn < numberLook; jColumn++) {
+            int iColumn = which[jColumn];
+            CoinBigIndex j;
+            double value = newSolution[iColumn];
+            double cost = direction * objective[iColumn];
+            if (solver->isInteger(iColumn)) {
+                // use current upper or original upper
+                if (value + 0.99 < originalUpper[iColumn]) {
+                    double sum = 0.0;
+                    int numberExact = 0;
+                    for (j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double gap = rowLower[iRow] - rowActivity[iRow];
+                        double elementValue = allOnes ? 1.0 : element[j];
+                        if (gap > 1.0e-7) {
+                            sum += CoinMin(elementValue, gap);
+                            if (fabs(elementValue - gap) < 1.0e-7)
+                                numberExact++;
+                        }
+                    }
+                    // could bias if exact
+                    if (sum > 0.0) {
+                        // add to next time
+                        which[newNumber++] = iColumn;
+                        double ratio = (cost / sum) * (1.0 + perturb * randomNumberGenerator_.randomDouble());
+                        // If at root choose first
+                        if (atRoot)
+                            ratio = iColumn;
+                        if (ratio < bestRatio) {
+                            bestRatio = ratio;
+                            bestColumn = iColumn;
+                            bestStepSize = 1.0;
+                        }
+                    }
+                }
+            } else {
+                // continuous
+                if (value < columnUpper[iColumn]) {
+                    // Go through twice - first to get step length
+                    double step = 1.0e50;
+                    for (j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        if (rowActivity[iRow] < rowLower[iRow] - 1.0e-10 &&
+                                element[j]*step + rowActivity[iRow] >= rowLower[iRow]) {
+                            step = (rowLower[iRow] - rowActivity[iRow]) / element[j];;
+                        }
+                    }
+                    // now ratio
+                    if (step < 1.0e50) {
+                        // add to next time
+                        which[newNumber++] = iColumn;
+                        assert (step > 0.0);
+                        double sum = 0.0;
+                        for (j = columnStart[iColumn];
+                                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                            int iRow = row[j];
+                            double newActivity = element[j] * step + rowActivity[iRow];
+                            if (rowActivity[iRow] < rowLower[iRow] - 1.0e-10 &&
+                                    newActivity >= rowLower[iRow] - 1.0e-12) {
+                                sum += element[j];
+                            }
+                        }
+                        assert (sum > 0.0);
+                        double ratio = (cost / sum) * (1.0 + perturb * randomNumberGenerator_.randomDouble());
+                        if (ratio < bestRatio) {
+                            bestRatio = ratio;
+                            bestColumn = iColumn;
+                            bestStepSize = step;
+                        }
+                    }
+                }
+            }
+        }
+        if (bestColumn < 0)
+            break; // we have finished
+        // Increase chosen column
+        newSolution[bestColumn] += bestStepSize;
+        double cost = direction * objective[bestColumn];
+        newSolutionValue += bestStepSize * cost;
+        for (CoinBigIndex j = columnStart[bestColumn];
+                j < columnStart[bestColumn] + columnLength[bestColumn]; j++) {
+            int iRow = row[j];
+            rowActivity[iRow] += bestStepSize * element[j];
+        }
+    }
+    delete [] which;
+    if (newSolutionValue < solutionValue) {
+        // check feasible
+        memset(rowActivity, 0, numberRows*sizeof(double));
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            CoinBigIndex j;
+            double value = newSolution[iColumn];
+            if (value) {
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    rowActivity[iRow] += value * element[j];
+                }
+            }
+        }
+        // check was approximately feasible
+        bool feasible = true;
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            if (rowActivity[iRow] < rowLower[iRow]) {
+                if (rowActivity[iRow] < rowLower[iRow] - 10.0*primalTolerance)
+                    feasible = false;
+            }
+        }
+        if (feasible) {
+            // new solution
+            memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+            solutionValue = newSolutionValue;
+            //printf("** Solution of %g found by rounding\n",newSolutionValue);
+            returnCode = 1;
+        } else {
+            // Can easily happen
+            //printf("Debug CbcHeuristicGreedyCover giving bad solution\n");
+        }
+    }
+    delete [] newSolution;
+    delete [] rowActivity;
+    return returnCode;
+}
+// update model
+void CbcHeuristicGreedyCover::setModel(CbcModel * model)
+{
+    gutsOfConstructor(model);
+    validate();
+}
+// Resets stuff if model changes
+void
+CbcHeuristicGreedyCover::resetModel(CbcModel * model)
+{
+    gutsOfConstructor(model);
+}
+// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+void
+CbcHeuristicGreedyCover::validate()
+{
+    if (model_ && when() < 10) {
+        if (model_->numberIntegers() !=
+                model_->numberObjects() && (model_->numberObjects() ||
+                                            (model_->specialOptions()&1024) == 0)) {
+            int numberOdd = 0;
+            for (int i = 0; i < model_->numberObjects(); i++) {
+                if (!model_->object(i)->canDoHeuristics())
+                    numberOdd++;
+            }
+            if (numberOdd)
+                setWhen(0);
+        }
+        // Only works if costs positive, coefficients positive and all rows G
+        OsiSolverInterface * solver = model_->solver();
+        const double * columnLower = solver->getColLower();
+        const double * rowUpper = solver->getRowUpper();
+        const double * objective = solver->getObjCoefficients();
+        double direction = solver->getObjSense();
+
+        int numberRows = solver->getNumRows();
+        int numberColumns = solver->getNumCols();
+        // Column copy
+	matrix_.setDimensions(numberRows,numberColumns);
+        const double * element = matrix_.getElements();
+        const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+        const int * columnLength = matrix_.getVectorLengths();
+        bool good = true;
+        for (int iRow = 0; iRow < numberRows; iRow++) {
+            if (rowUpper[iRow] < 1.0e30)
+                good = false;
+        }
+        for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (objective[iColumn]*direction < 0.0)
+                good = false;
+            if (columnLower[iColumn] < 0.0)
+                good = false;
+            CoinBigIndex j;
+            for (j = columnStart[iColumn];
+                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                if (element[j] < 0.0)
+                    good = false;
+            }
+        }
+        if (!good)
+            setWhen(0); // switch off
+    }
+}
+// Default Constructor
+CbcHeuristicGreedyEquality::CbcHeuristicGreedyEquality()
+        : CbcHeuristic()
+{
+    // matrix  will automatically be empty
+    fraction_ = 1.0; // no branch and bound
+    originalNumberRows_ = 0;
+    algorithm_ = 0;
+    numberTimes_ = 100;
+    whereFrom_ = 1;
+}
+
+// Constructor from model
+CbcHeuristicGreedyEquality::CbcHeuristicGreedyEquality(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    // Get a copy of original matrix
+    gutsOfConstructor(&model);
+    fraction_ = 1.0; // no branch and bound
+    algorithm_ = 0;
+    numberTimes_ = 100;
+    whereFrom_ = 1;
+}
+
+// Destructor
+CbcHeuristicGreedyEquality::~CbcHeuristicGreedyEquality ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicGreedyEquality::clone() const
+{
+    return new CbcHeuristicGreedyEquality(*this);
+}
+// Guts of constructor from a CbcModel
+void
+CbcHeuristicGreedyEquality::gutsOfConstructor(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix
+    assert(model->solver());
+    if (model->solver()->getNumRows()) {
+        matrix_ = *model->solver()->getMatrixByCol();
+    }
+    originalNumberRows_ = model->solver()->getNumRows();
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicGreedyEquality::generateCpp( FILE * fp)
+{
+    CbcHeuristicGreedyEquality other;
+    fprintf(fp, "0#include \"CbcHeuristicGreedy.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicGreedyEquality heuristicGreedyEquality(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicGreedyEquality");
+    if (algorithm_ != other.algorithm_)
+        fprintf(fp, "3  heuristicGreedyEquality.setAlgorithm(%d);\n", algorithm_);
+    else
+        fprintf(fp, "4  heuristicGreedyEquality.setAlgorithm(%d);\n", algorithm_);
+    if (fraction_ != other.fraction_)
+        fprintf(fp, "3  heuristicGreedyEquality.setFraction(%g);\n", fraction_);
+    else
+        fprintf(fp, "4  heuristicGreedyEquality.setFraction(%g);\n", fraction_);
+    if (numberTimes_ != other.numberTimes_)
+        fprintf(fp, "3  heuristicGreedyEquality.setNumberTimes(%d);\n", numberTimes_);
+    else
+        fprintf(fp, "4  heuristicGreedyEquality.setNumberTimes(%d);\n", numberTimes_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicGreedyEquality);\n");
+}
+
+// Copy constructor
+CbcHeuristicGreedyEquality::CbcHeuristicGreedyEquality(const CbcHeuristicGreedyEquality & rhs)
+        :
+        CbcHeuristic(rhs),
+        matrix_(rhs.matrix_),
+        fraction_(rhs.fraction_),
+        originalNumberRows_(rhs.originalNumberRows_),
+        algorithm_(rhs.algorithm_),
+        numberTimes_(rhs.numberTimes_)
+{
+}
+
+// Assignment operator
+CbcHeuristicGreedyEquality &
+CbcHeuristicGreedyEquality::operator=( const CbcHeuristicGreedyEquality & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        matrix_ = rhs.matrix_;
+        fraction_ = rhs.fraction_;
+        originalNumberRows_ = rhs.originalNumberRows_;
+        algorithm_ = rhs.algorithm_;
+        numberTimes_ = rhs.numberTimes_;
+    }
+    return *this;
+}
+// Returns 1 if solution, 0 if not
+int
+CbcHeuristicGreedyEquality::solution(double & solutionValue,
+                                     double * betterSolution)
+{
+    numCouldRun_++;
+    if (!model_)
+        return 0;
+    // See if to do
+    if (!when() || (when() == 1 && model_->phase() != 1))
+        return 0; // switched off
+    if (model_->getNodeCount() > numberTimes_)
+        return 0;
+    // See if at root node
+    bool atRoot = model_->getNodeCount() == 0;
+    int passNumber = model_->getCurrentPassNumber();
+    if (atRoot && passNumber != 1)
+        return 0;
+    OsiSolverInterface * solver = model_->solver();
+    const double * columnLower = solver->getColLower();
+    const double * columnUpper = solver->getColUpper();
+    // And original upper bounds in case we want to use them
+    const double * originalUpper = model_->continuousSolver()->getColUpper();
+    // But not if algorithm says so
+    if ((algorithm_ % 10) == 0)
+        originalUpper = columnUpper;
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    const double * solution = solver->getColSolution();
+    const double * objective = solver->getObjCoefficients();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    // This is number of rows when matrix was passed in
+    int numberRows = originalNumberRows_;
+    if (!numberRows)
+        return 0; // switched off
+    numRuns_++;
+
+    assert (numberRows == matrix_.getNumRows());
+    int iRow, iColumn;
+    double direction = solver->getObjSense();
+    double offset;
+    solver->getDblParam(OsiObjOffset, offset);
+    double newSolutionValue = -offset;
+    int returnCode = 0;
+
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+
+    // Get solution array for heuristic solution
+    int numberColumns = solver->getNumCols();
+    double * newSolution = new double [numberColumns];
+    double * rowActivity = new double[numberRows];
+    memset(rowActivity, 0, numberRows*sizeof(double));
+    double rhsNeeded = 0;
+    for (iRow = 0; iRow < numberRows; iRow++)
+        rhsNeeded += rowUpper[iRow];
+    rhsNeeded *= fraction_;
+    bool allOnes = true;
+    // Get rounded down solution
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        CoinBigIndex j;
+        double value = solution[iColumn];
+        if (solver->isInteger(iColumn)) {
+            // Round down integer
+            if (fabs(floor(value + 0.5) - value) < integerTolerance) {
+                value = floor(CoinMax(value + 1.0e-3, columnLower[iColumn]));
+            } else {
+                value = CoinMax(floor(value), columnLower[iColumn]);
+            }
+        }
+        // make sure clean
+        value = CoinMin(value, columnUpper[iColumn]);
+        value = CoinMax(value, columnLower[iColumn]);
+        newSolution[iColumn] = value;
+        double cost = direction * objective[iColumn];
+        newSolutionValue += value * cost;
+        for (j = columnStart[iColumn];
+                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+            int iRow = row[j];
+            rowActivity[iRow] += value * element[j];
+            rhsNeeded -= value * element[j];
+            if (element[j] != 1.0)
+                allOnes = false;
+        }
+    }
+    // See if we round up
+    bool roundup = ((algorithm_ % 100) != 0);
+    if (roundup && allOnes) {
+        // Get rounded up solution
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            CoinBigIndex j;
+            double value = solution[iColumn];
+            if (solver->isInteger(iColumn)) {
+                // but round up if no activity
+                if (roundup && value >= 0.6 && !newSolution[iColumn]) {
+                    bool choose = true;
+                    for (j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        if (rowActivity[iRow]) {
+                            choose = false;
+                            break;
+                        }
+                    }
+                    if (choose) {
+                        newSolution[iColumn] = 1.0;
+                        double cost = direction * objective[iColumn];
+                        newSolutionValue += cost;
+                        for (j = columnStart[iColumn];
+                                j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                            int iRow = row[j];
+                            rowActivity[iRow] += 1.0;
+                            rhsNeeded -= 1.0;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    // Get initial list
+    int * which = new int [numberColumns];
+    for (iColumn = 0; iColumn < numberColumns; iColumn++)
+        which[iColumn] = iColumn;
+    int numberLook = numberColumns;
+    // See if we want to perturb more
+    double perturb = ((algorithm_ % 10) == 0) ? 0.1 : 0.25;
+    // Keep going round until a solution
+    while (true) {
+        // Get column with best ratio
+        int bestColumn = -1;
+        double bestRatio = COIN_DBL_MAX;
+        double bestStepSize = 0.0;
+        int newNumber = 0;
+        for (int jColumn = 0; jColumn < numberLook; jColumn++) {
+            int iColumn = which[jColumn];
+            CoinBigIndex j;
+            double value = newSolution[iColumn];
+            double cost = direction * objective[iColumn];
+            if (solver->isInteger(iColumn)) {
+                // use current upper or original upper
+                if (value + 0.9999 < originalUpper[iColumn]) {
+                    double movement = 1.0;
+                    double sum = 0.0;
+                    for (j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        double gap = rowUpper[iRow] - rowActivity[iRow];
+                        double elementValue = allOnes ? 1.0 : element[j];
+                        sum += elementValue;
+                        if (movement*elementValue > gap) {
+                            movement = gap / elementValue;
+                        }
+                    }
+                    if (movement > 0.999999) {
+                        // add to next time
+                        which[newNumber++] = iColumn;
+                        double ratio = (cost / sum) * (1.0 + perturb * randomNumberGenerator_.randomDouble());
+                        // If at root
+                        if (atRoot) {
+                            if (fraction_ == 1.0)
+                                ratio = iColumn; // choose first
+                            else
+                                ratio = - solution[iColumn]; // choose largest
+                        }
+                        if (ratio < bestRatio) {
+                            bestRatio = ratio;
+                            bestColumn = iColumn;
+                            bestStepSize = 1.0;
+                        }
+                    }
+                }
+            } else {
+                // continuous
+                if (value < columnUpper[iColumn]) {
+                    double movement = 1.0e50;
+                    double sum = 0.0;
+                    for (j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        if (element[j]*movement + rowActivity[iRow] > rowUpper[iRow]) {
+                            movement = (rowUpper[iRow] - rowActivity[iRow]) / element[j];;
+                        }
+                        sum += element[j];
+                    }
+                    // now ratio
+                    if (movement > 1.0e-7) {
+                        // add to next time
+                        which[newNumber++] = iColumn;
+                        double ratio = (cost / sum) * (1.0 + perturb * randomNumberGenerator_.randomDouble());
+                        if (ratio < bestRatio) {
+                            bestRatio = ratio;
+                            bestColumn = iColumn;
+                            bestStepSize = movement;
+                        }
+                    }
+                }
+            }
+        }
+        if (bestColumn < 0)
+            break; // we have finished
+        // Increase chosen column
+        newSolution[bestColumn] += bestStepSize;
+        double cost = direction * objective[bestColumn];
+        newSolutionValue += bestStepSize * cost;
+        for (CoinBigIndex j = columnStart[bestColumn];
+                j < columnStart[bestColumn] + columnLength[bestColumn]; j++) {
+            int iRow = row[j];
+            rowActivity[iRow] += bestStepSize * element[j];
+            rhsNeeded -= bestStepSize * element[j];
+        }
+        if (rhsNeeded < 1.0e-8)
+            break;
+    }
+    delete [] which;
+    if (fraction_ < 1.0 && rhsNeeded < 1.0e-8 && newSolutionValue < solutionValue) {
+        // do branch and cut
+        // fix all nonzero
+        OsiSolverInterface * newSolver = model_->continuousSolver()->clone();
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (newSolver->isInteger(iColumn))
+                newSolver->setColLower(iColumn, newSolution[iColumn]);
+        }
+        int returnCode = smallBranchAndBound(newSolver, 200, newSolution, newSolutionValue,
+                                             solutionValue, "CbcHeuristicGreedy");
+        if (returnCode < 0)
+            returnCode = 0; // returned on size
+        if ((returnCode&2) != 0) {
+            // could add cut
+            returnCode &= ~2;
+        }
+        rhsNeeded = 1.0 - returnCode;
+        delete newSolver;
+    }
+    if (newSolutionValue < solutionValue && rhsNeeded < 1.0e-8) {
+        // check feasible
+        memset(rowActivity, 0, numberRows*sizeof(double));
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            CoinBigIndex j;
+            double value = newSolution[iColumn];
+            if (value) {
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    rowActivity[iRow] += value * element[j];
+                }
+            }
+        }
+        // check was approximately feasible
+        bool feasible = true;
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            if (rowActivity[iRow] < rowLower[iRow]) {
+                if (rowActivity[iRow] < rowLower[iRow] - 10.0*primalTolerance)
+                    feasible = false;
+            }
+        }
+        if (feasible) {
+            // new solution
+            memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+            solutionValue = newSolutionValue;
+            returnCode = 1;
+        }
+    }
+    delete [] newSolution;
+    delete [] rowActivity;
+    if (atRoot && fraction_ == 1.0) {
+        // try quick search
+        fraction_ = 0.4;
+        int newCode = this->solution(solutionValue, betterSolution);
+        if (newCode)
+            returnCode = 1;
+        fraction_ = 1.0;
+    }
+    return returnCode;
+}
+// update model
+void CbcHeuristicGreedyEquality::setModel(CbcModel * model)
+{
+    gutsOfConstructor(model);
+    validate();
+}
+// Resets stuff if model changes
+void
+CbcHeuristicGreedyEquality::resetModel(CbcModel * model)
+{
+    gutsOfConstructor(model);
+}
+// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+void
+CbcHeuristicGreedyEquality::validate()
+{
+    if (model_ && when() < 10) {
+        if (model_->numberIntegers() !=
+                model_->numberObjects())
+            setWhen(0);
+        // Only works if costs positive, coefficients positive and all rows E or L
+        // And if values are integer
+        OsiSolverInterface * solver = model_->solver();
+        const double * columnLower = solver->getColLower();
+        const double * rowUpper = solver->getRowUpper();
+        const double * rowLower = solver->getRowLower();
+        const double * objective = solver->getObjCoefficients();
+        double direction = solver->getObjSense();
+
+        int numberRows = solver->getNumRows();
+        int numberColumns = solver->getNumCols();
+	matrix_.setDimensions(numberRows,numberColumns);
+        // Column copy
+        const double * element = matrix_.getElements();
+        const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+        const int * columnLength = matrix_.getVectorLengths();
+        bool good = true;
+        for (int iRow = 0; iRow < numberRows; iRow++) {
+            if (rowUpper[iRow] > 1.0e30)
+                good = false;
+            if (rowLower[iRow] > 0.0 && rowLower[iRow] != rowUpper[iRow])
+                good = false;
+            if (floor(rowUpper[iRow] + 0.5) != rowUpper[iRow])
+                good = false;
+        }
+        for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (objective[iColumn]*direction < 0.0)
+                good = false;
+            if (columnLower[iColumn] < 0.0)
+                good = false;
+            CoinBigIndex j;
+            for (j = columnStart[iColumn];
+                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                if (element[j] < 0.0)
+                    good = false;
+                if (floor(element[j] + 0.5) != element[j])
+                    good = false;
+            }
+        }
+        if (!good)
+            setWhen(0); // switch off
+    }
+}
+
+// Default Constructor
+CbcHeuristicGreedySOS::CbcHeuristicGreedySOS()
+        : CbcHeuristic()
+{
+    originalRhs_ = NULL;
+    // matrix  will automatically be empty
+    originalNumberRows_ = 0;
+    algorithm_ = 0;
+    numberTimes_ = 100;
+}
+
+// Constructor from model
+CbcHeuristicGreedySOS::CbcHeuristicGreedySOS(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    gutsOfConstructor(&model);
+    algorithm_ = 2;
+    numberTimes_ = 100;
+    whereFrom_ = 1;
+}
+
+// Destructor
+CbcHeuristicGreedySOS::~CbcHeuristicGreedySOS ()
+{
+  delete [] originalRhs_;
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicGreedySOS::clone() const
+{
+    return new CbcHeuristicGreedySOS(*this);
+}
+// Guts of constructor from a CbcModel
+void
+CbcHeuristicGreedySOS::gutsOfConstructor(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix
+    assert(model->solver());
+    if (model->solver()->getNumRows()) {
+        matrix_ = *model->solver()->getMatrixByCol();
+    }
+    originalNumberRows_ = model->solver()->getNumRows();
+    originalRhs_ = new double [originalNumberRows_];
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicGreedySOS::generateCpp( FILE * fp)
+{
+    CbcHeuristicGreedySOS other;
+    fprintf(fp, "0#include \"CbcHeuristicGreedy.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicGreedySOS heuristicGreedySOS(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicGreedySOS");
+    if (algorithm_ != other.algorithm_)
+        fprintf(fp, "3  heuristicGreedySOS.setAlgorithm(%d);\n", algorithm_);
+    else
+        fprintf(fp, "4  heuristicGreedySOS.setAlgorithm(%d);\n", algorithm_);
+    if (numberTimes_ != other.numberTimes_)
+        fprintf(fp, "3  heuristicGreedySOS.setNumberTimes(%d);\n", numberTimes_);
+    else
+        fprintf(fp, "4  heuristicGreedySOS.setNumberTimes(%d);\n", numberTimes_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicGreedySOS);\n");
+}
+
+// Copy constructor
+CbcHeuristicGreedySOS::CbcHeuristicGreedySOS(const CbcHeuristicGreedySOS & rhs)
+        :
+        CbcHeuristic(rhs),
+        matrix_(rhs.matrix_),
+        originalNumberRows_(rhs.originalNumberRows_),
+        algorithm_(rhs.algorithm_),
+        numberTimes_(rhs.numberTimes_)
+{
+  originalRhs_ = CoinCopyOfArray(rhs.originalRhs_,originalNumberRows_);
+}
+
+// Assignment operator
+CbcHeuristicGreedySOS &
+CbcHeuristicGreedySOS::operator=( const CbcHeuristicGreedySOS & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        matrix_ = rhs.matrix_;
+        originalNumberRows_ = rhs.originalNumberRows_;
+        algorithm_ = rhs.algorithm_;
+        numberTimes_ = rhs.numberTimes_;
+	delete [] originalRhs_;
+	originalRhs_ = CoinCopyOfArray(rhs.originalRhs_,originalNumberRows_);
+    }
+    return *this;
+}
+// Returns 1 if solution, 0 if not
+int
+CbcHeuristicGreedySOS::solution(double & solutionValue,
+                                  double * betterSolution)
+{
+    numCouldRun_++;
+    if (!model_)
+        return 0;
+    // See if to do
+    if (!when() || (when() == 1 && model_->phase() != 1))
+        return 0; // switched off
+    if (model_->getNodeCount() > numberTimes_)
+        return 0;
+    // See if at root node
+    bool atRoot = model_->getNodeCount() == 0;
+    int passNumber = model_->getCurrentPassNumber();
+    if (atRoot && passNumber != 1)
+        return 0;
+    OsiSolverInterface * solver = model_->solver();
+    int numberColumns = solver->getNumCols();
+    // This is number of rows when matrix was passed in
+    int numberRows = originalNumberRows_;
+    if (!numberRows)
+        return 0; // switched off
+
+    const double * columnLower = solver->getColLower();
+    const double * columnUpper = solver->getColUpper();
+    // modified rhs
+    double * rhs = CoinCopyOfArray(originalRhs_,numberRows);
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+    int * sosRow = new int [numberColumns];
+    int nonSOS=0;
+    // If bit set then use current
+    if ((algorithm_&1)!=0) {
+      const CoinPackedMatrix * matrix = solver->getMatrixByCol();
+      element = matrix->getElements();
+      row = matrix->getIndices();
+      columnStart = matrix->getVectorStarts();
+      columnLength = matrix->getVectorLengths();
+      //rhs = new double [numberRows];
+      const double * rowLower = solver->getRowLower();
+      const double * rowUpper = solver->getRowUpper();
+      bool good = true;
+      for (int iRow = 0; iRow < numberRows; iRow++) {
+	if (rowLower[iRow] == 1.0 && rowUpper[iRow] == 1.0) {
+	  // SOS
+	  rhs[iRow]=-1.0;
+	} else if (rowLower[iRow] > 0.0 && rowUpper[iRow] < 1.0e10) {
+	  good = false;
+	} else if (rowUpper[iRow] < 0.0) {
+	  good = false;
+	} else if (rowUpper[iRow] < 1.0e10) {
+	  rhs[iRow]=rowUpper[iRow];
+	} else {
+	  rhs[iRow]=rowLower[iRow];
+	}
+      }
+      for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	if (!columnLength[iColumn])
+	  continue;
+	if (columnLower[iColumn] < 0.0 || columnUpper[iColumn] > 1.0)
+	  good = false;
+	CoinBigIndex j;
+	int nSOS=0;
+	int iSOS=-1;
+	if (!solver->isInteger(iColumn))
+	  good = false;
+	for (j = columnStart[iColumn];
+	     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	  if (element[j] < 0.0)
+	    good = false;
+	  int iRow = row[j];
+	  if (rhs[iRow]==-1.0) {
+	    if (element[j] != 1.0)
+	      good = false;
+	    iSOS=iRow;
+	    nSOS++;
+	  }
+	}
+	if (nSOS>1)
+	  good = false;
+	else if (!nSOS)
+	  nonSOS++;
+	sosRow[iColumn] = iSOS;
+      }
+      if (!good) {
+	delete [] sosRow;
+	delete [] rhs;
+	setWhen(0); // switch off
+	return 0;
+      }
+    } else {
+      abort(); // not allowed yet
+    }
+    const double * solution = solver->getColSolution();
+    const double * objective = solver->getObjCoefficients();
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    numRuns_++;
+    assert (numberRows == matrix_.getNumRows());
+    // set up linked list for sets
+    int * firstGub = new int [numberRows];
+    int * nextGub = new int [numberColumns];
+    int iRow, iColumn;
+    double direction = solver->getObjSense();
+    double * slackCost = new double [numberRows];
+    double * modifiedCost = CoinCopyOfArray(objective,numberColumns);
+    for (int iRow = 0;iRow < numberRows; iRow++) {
+      slackCost[iRow]=1.0e30;
+      firstGub[iRow]=-1;
+    }
+    // Take off cost of gub slack
+    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+      nextGub[iColumn]=-1;
+      int iRow = sosRow[iColumn];
+      if (columnLength[iColumn] == 1&&iRow>=0) {
+	// SOS slack
+	double cost = direction*objective[iColumn];
+	assert (rhs[iRow]<0.0);
+	slackCost[iRow]=CoinMin(slackCost[iRow],cost);
+      }
+    }
+    double offset2 = 0.0;
+    char * sos = new char [numberRows];
+    for (int iRow = 0;iRow < numberRows; iRow++) {
+      sos[iRow]=0;
+      if (rhs[iRow]<0.0) {
+	sos[iRow]=1;
+	rhs[iRow]=1.0;
+      } else if (rhs[iRow] != rowUpper[iRow]) {
+	// G row
+	sos[iRow]=-1;
+      }
+      if( slackCost[iRow] == 1.0e30) {
+	slackCost[iRow]=0.0;
+      } else {
+	offset2 += slackCost[iRow];
+	sos[iRow] = 2;
+      }
+    }
+    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+      double cost = direction * modifiedCost[iColumn];
+      CoinBigIndex j;
+      for (j = columnStart[iColumn];
+	   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	int iRow = row[j];
+	if (sos[iRow]>0) {
+	  cost -= slackCost[iRow];
+	  if (firstGub[iRow]<0) {
+	    firstGub[iRow]=iColumn;
+	  } else {
+	    int jColumn = firstGub[iRow];
+	    while (nextGub[jColumn]>=0)
+	      jColumn=nextGub[jColumn];
+	    nextGub[jColumn]=iColumn;
+	  }
+	  // Only in one sos
+	  break;
+	}
+      }
+      modifiedCost[iColumn] = cost;
+    }
+    delete [] slackCost;
+    double offset;
+    solver->getDblParam(OsiObjOffset, offset);
+    double newSolutionValue = -offset+offset2;
+    int returnCode = 0;
+
+
+    // Get solution array for heuristic solution
+    double * newSolution = new double [numberColumns];
+    double * rowActivity = new double[numberRows];
+    double * contribution = new double [numberColumns];
+    int * which = new int [numberColumns];
+    double * newSolution0 = new double [numberColumns];
+    if ((algorithm_&(2|4))==0) {
+      // get solution as small as possible
+      for (iColumn = 0; iColumn < numberColumns; iColumn++) 
+	newSolution0[iColumn] = columnLower[iColumn];
+    } else {
+      // Get rounded down solution
+      for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+	double value = solution[iColumn];
+	// Round down integer
+	if (fabs(floor(value + 0.5) - value) < integerTolerance) {
+	  value = floor(CoinMax(value + 1.0e-3, columnLower[iColumn]));
+	} else {
+	  value = CoinMax(floor(value), columnLower[iColumn]);
+	}
+	// make sure clean
+	value = CoinMin(value, columnUpper[iColumn]);
+	value = CoinMax(value, columnLower[iColumn]);
+	newSolution0[iColumn] = value;
+      }
+    }
+    double * rowWeight = new double [numberRows];
+    for (int i=0;i<numberRows;i++)
+      rowWeight[i]=1.0;
+    double costBias = 0.0;
+    int nPass = ((algorithm_&4)!=0) ? 1 : 10;
+    for (int iPass=0;iPass<nPass;iPass++) {
+      newSolutionValue = -offset+offset2;
+      memcpy(newSolution,newSolution0,numberColumns*sizeof(double));
+      // get row activity
+      memset(rowActivity, 0, numberRows*sizeof(double));
+      for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+	CoinBigIndex j;
+	double value = newSolution[iColumn];
+	for (j = columnStart[iColumn];
+	     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	  int iRow = row[j];
+	  rowActivity[iRow] += value * element[j];
+	}
+      }
+      if (!rowWeight) {
+	rowWeight = CoinCopyOfArray(rowActivity,numberRows);
+      }
+      for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+	CoinBigIndex j;
+	double value = newSolution[iColumn];
+	double cost =  modifiedCost[iColumn];
+	double forSort = 1.0e-24;
+	bool hasSlack=false;
+	bool willFit=true;
+	bool gRow=false;
+	newSolutionValue += value * cost;
+	cost += 1.0e-12;
+	for (j = columnStart[iColumn];
+	     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	  int iRow = row[j];
+	  int type = sos[iRow];
+	  double gap = rhs[iRow] - rowActivity[iRow]+1.0e-8;
+	  switch (type) {
+	  case -1:
+	    // G row
+	    gRow = true;
+#if 0
+	    if (rhs[iRow]>rowWeight[iRow]||(algorithm_&(2|4))!=0)
+	      forSort += element[j];
+	    else
+	      forSort += 0.1*element[j];
+#else
+	    forSort += rowWeight[iRow]*element[j];
+#endif
+	    break;
+	  case 0:
+	    // L row
+	    if (gap<element[j]) {
+	      willFit = false;
+	    } else {
+	      forSort += element[j];
+	    }
+	    break;
+	  case 1:
+	    // SOS without slack
+	    if (gap<element[j]) {
+	      willFit = false;
+	    }
+	    break;
+	  case 2:
+	    // SOS with slack
+	    hasSlack = true;
+	    if (gap<element[j]) {
+	      willFit = false;
+	    }
+	    break;
+	  }
+	}
+	bool isSlack = hasSlack && (columnLength[iColumn]==1);
+	if (forSort<1.0e-24)
+	  forSort = 1.0e-12;
+	if ((algorithm_&4)!=0 && forSort > 1.0e-24) 
+	  forSort=1.0;
+	// Use smallest cost if will fit
+	if (willFit && (hasSlack||gRow) && 
+	    value == 0.0 && columnUpper[iColumn]) {
+	  if (hasSlack && !gRow) {
+	    if (cost>1.0e-12) {
+	      forSort = 2.0e30;
+	    } else if (cost==1.0e-12) {
+	      if (!isSlack)
+		forSort = 1.0e29;
+	      else
+		forSort = 1.0e28;
+	    } else {
+	      forSort = cost/forSort;
+	    }
+	  } else {
+	    if (!gRow||true)
+	      forSort = (cost+costBias)/forSort;
+	    else
+	      forSort = 1.0e-12/forSort;
+	  }
+	} else {
+	  // put at end
+	  forSort = 1.0e30;
+	}
+	which[iColumn]=iColumn;
+	contribution[iColumn]= forSort;
+      }
+      CoinSort_2(contribution,contribution+numberColumns,which);
+      // Go through columns
+      int nAdded=0;
+      int nSlacks=0;
+      for (int jColumn = 0; jColumn < numberColumns; jColumn++) {
+	if (contribution[jColumn]>=1.0e30)
+	  break;
+	int iColumn = which[jColumn];
+	double value = newSolution[iColumn];
+	if (value)
+	  continue;
+	bool possible = true;
+	CoinBigIndex j;
+	for (j = columnStart[iColumn];
+	     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	  int iRow = row[j];
+	  if (sos[iRow]>0&&rowActivity[iRow]) {
+	    possible = false;
+	  } else {
+	    double gap = rhs[iRow] - rowActivity[iRow]+1.0e-8;
+	    if (gap<element[j]&&sos[iRow]>=0)
+	      possible = false;
+	  }
+	}
+	if (possible) {
+	  //#define REPORT 1
+#ifdef REPORT
+	  if ((nAdded%1000)==0) {
+	    double gap=0.0;
+	    for (int i=0;i<numberRows;i++) {
+	      if (rowUpper[i]>1.0e20)
+		gap += CoinMax(rowLower[i]-rowActivity[i],0.0);
+	    }
+	    if (gap)
+	      printf("after %d added gap %g - %d slacks\n",
+		     nAdded,gap,nSlacks);
+	  }
+#endif
+	  nAdded++;
+	  if (columnLength[iColumn]==1)
+	    nSlacks++;
+	  // Increase chosen column
+	  newSolution[iColumn] = 1.0;
+	  double cost =  modifiedCost[iColumn];
+	  newSolutionValue += cost;
+	  for (CoinBigIndex j = columnStart[iColumn];
+	       j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	    int iRow = row[j];
+	    rowActivity[iRow] += element[j];
+	  }
+	}
+      }
+#ifdef REPORT
+      {
+	double under=0.0;
+	double over=0.0;
+	double gap = 0.0;
+	int nUnder=0;
+	int nOver=0;
+	int nGap=0;
+	for (iRow = 0; iRow < numberRows; iRow++) {
+	  if (rowActivity[iRow] < rowLower[iRow] - 10.0*primalTolerance) {
+	    double value = rowLower[iRow]-rowActivity[iRow];
+#if REPORT>1
+	    printf("below on %d is %g - activity %g lower %g\n",
+		   iRow,value,rowActivity[iRow],rowLower[iRow]);
+#endif
+	    under += value;
+	    nUnder++;
+	  } else if (rowActivity[iRow] > rowUpper[iRow] + 10.0*primalTolerance) {
+	    double value = rowActivity[iRow]-rowUpper[iRow];
+#if REPORT>1
+	    printf("above on %d is %g - activity %g upper %g\n",
+		   iRow,value,rowActivity[iRow],rowUpper[iRow]);
+#endif
+	    over += value;
+	    nOver++;
+	  } else {
+	    double value = rowActivity[iRow]-rowLower[iRow];
+	    if (value && value < 1.0e20) {
+#if REPORT>1
+	      printf("gap on %d is %g - activity %g lower %g\n",
+		     iRow,value,rowActivity[iRow],rowLower[iRow]);
+#endif
+	      gap += value;
+	      nGap++;
+	    }
+	  }
+	}
+	printf("final under %g (%d) - over %g (%d) - free %g (%d) - %d added - solvalue %g\n",
+	       under,nUnder,over,nOver,gap,nGap,nAdded,newSolutionValue);
+      }
+#endif
+      double gap = 0.0;
+      double over = 0.0;
+      int nL=0;
+      int nG=0;
+      int nUnder=0;
+      for (iRow = 0; iRow < numberRows; iRow++) {
+	if (rowLower[iRow]<-1.0e20)
+	  nL++;
+	if (rowUpper[iRow]>1.0e20)
+	  nG++;
+	if (rowActivity[iRow] < rowLower[iRow] - 10.0*primalTolerance) {
+	  gap += rowLower[iRow]-rowActivity[iRow];
+	  nUnder++;
+	  rowWeight[iRow] *= 1.1;
+	} else if (rowActivity[iRow] > rowUpper[iRow] + 10.0*primalTolerance) {
+	  gap += rowActivity[iRow]-rowUpper[iRow];
+	} else {
+	  over += rowActivity[iRow]-rowLower[iRow];
+	  //rowWeight[iRow] *= 0.9;
+	}
+      }
+      if (nG&&!nL) {
+	// can we fix
+	// get list of columns which can go down without making
+	// things much worse
+	int nPossible=0;
+	int nEasyDown=0;
+	int nSlackDown=0;
+	for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+	  if (newSolution[iColumn]&&
+	      columnUpper[iColumn]>columnLower[iColumn]) {
+	    bool canGoDown=true;
+	    bool under = false;
+	    int iSos=-1;
+	    for (CoinBigIndex j = columnStart[iColumn];
+		 j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	      int iRow = row[j];
+	      if (sos[iRow]<0) {
+		double over = rowActivity[iRow]-rowLower[iRow];
+		if (over>=0.0&&element[j]>over+1.0e-12) {
+		  canGoDown=false;
+		  break;
+		} else if (over<0.0) {
+		  under = true;
+		}
+	      } else {
+		iSos=iRow;
+	      }
+	    }
+	    if (canGoDown) { 
+	      if (!under) {
+		if (iSos>=0) {
+		  // find cheapest
+		  double cheapest=modifiedCost[iColumn];
+		  int iCheapest = -1;
+		  int jColumn = firstGub[iSos];
+		  assert (jColumn>=0);
+		  while (jColumn>=0) {
+		    if (modifiedCost[jColumn]<cheapest) {
+		      cheapest=modifiedCost[jColumn];
+		      iCheapest=jColumn;
+		    }
+		    jColumn = nextGub[jColumn];
+		  }
+		  if (iCheapest>=0) {
+		    // Decrease column
+		    newSolution[iColumn] = 0.0;
+		    newSolutionValue -= modifiedCost[iColumn];
+		    for (CoinBigIndex j = columnStart[iColumn];
+			 j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		      int iRow = row[j];
+		      rowActivity[iRow] -= element[j];
+		    }
+		    // Increase chosen column
+		    newSolution[iCheapest] = 1.0;
+		    newSolutionValue += modifiedCost[iCheapest]; 
+		    for (CoinBigIndex j = columnStart[iCheapest];
+			 j < columnStart[iCheapest] + columnLength[iCheapest]; j++) {
+		      int iRow = row[j];
+		      rowActivity[iRow] += element[j];
+		    }
+		    nEasyDown++;
+		    if (columnLength[iColumn]>1) {
+		      //printf("%d is easy down\n",iColumn);
+		    } else {
+		      nSlackDown++;
+		    }
+		  }
+		} else if (modifiedCost[iColumn]>0.0) {
+		  // easy down
+		  // Decrease column
+		  newSolution[iColumn] = 0.0;
+		  newSolutionValue -= modifiedCost[iColumn];
+		  for (CoinBigIndex j = columnStart[iColumn];
+		       j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		    int iRow = row[j];
+		    rowActivity[iRow] -= element[j];
+		  }
+		  nEasyDown++;
+		}
+	      } else {
+		which[nPossible++]=iColumn;
+	      }
+	    }
+	  }
+	}
+#ifdef REPORT
+	printf("%d possible down, %d easy down of which %d are slacks\n",
+	       nPossible,nEasyDown,nSlackDown);
+#endif
+	double * needed = new double [numberRows];
+	for (int i=0;i<numberRows;i++) {
+	  double value = rowLower[i] - rowActivity[i];
+	  if (value<1.0e-8)
+	    value=0.0;
+	  needed[i]=value;
+	}
+	if (gap && /*nUnder==1 &&*/ nonSOS) {
+	  double * weight = new double [numberColumns];
+	  int * sort = new int [numberColumns];
+	  // look at ones not in set
+	  int nPossible=0;
+	  for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+	    if (!newSolution[iColumn]&&
+		columnUpper[iColumn]>columnLower[iColumn]) {
+	      int iSos=-1;
+	      double value=0.0;
+	      for (CoinBigIndex j = columnStart[iColumn];
+		   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		int iRow = row[j];
+		if (sos[iRow]<0) {
+		  if (needed[iRow])
+		    value += CoinMin(element[j]/needed[iRow],1.0);
+		} else {
+		  iSos=iRow;
+		}
+	      }
+	      if (value && iSos<0) {
+		weight[nPossible]=-value;
+		sort[nPossible++]=iColumn;
+	      }
+	    }
+	  }
+	  CoinSort_2(weight,weight+nPossible,sort);
+	  for (int i=0;i<nPossible;i++) {
+	    int iColumn = sort[i];
+	    double helps=0.0;
+	    for (CoinBigIndex j = columnStart[iColumn];
+		 j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	      int iRow = row[j];
+	      if (needed[iRow]) 
+		helps += CoinMin(needed[iRow],element[j]);
+	    }
+	    if (helps) {
+	      newSolution[iColumn] = 1.0;
+	      newSolutionValue += modifiedCost[iColumn];
+	      for (CoinBigIndex j = columnStart[iColumn];
+		   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		int iRow = row[j];
+		rowActivity[iRow] += element[j];
+		if (needed[iRow]) {
+		  needed[iRow] -= element[j];
+		  if (needed[iRow]<1.0e-8)
+		    needed[iRow]=0.0;
+		}
+	      }
+	      gap -= helps;
+#ifdef REPORT
+	      {
+		double gap2 = 0.0;
+		for (iRow = 0; iRow < numberRows; iRow++) {
+		  if (rowActivity[iRow] < rowLower[iRow] - 10.0*primalTolerance) {
+		    gap2 += rowLower[iRow]-rowActivity[iRow];
+		  }
+		}
+		printf("estimated gap (nonsos) %g - computed %g\n",
+		       gap,gap2);
+	      }
+#endif
+	      if (gap<1.0e-12)
+		break;
+	    }
+	  }
+	  delete [] weight;
+	  delete [] sort;
+	}
+	if (gap&&nPossible/*&&nUnder==1*/&&true&&model_->bestSolution()) {
+	  double * weight = new double [numberColumns];
+	  int * sort = new int [numberColumns];
+	  // look at ones in sets
+	  const double * goodSolution = model_->bestSolution();
+	  int nPossible=0;
+	  double largestWeight=0.0;
+	  for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+	    if (!newSolution[iColumn]&&goodSolution[iColumn]&&
+		columnUpper[iColumn]>columnLower[iColumn]) {
+	      int iSos=-1;
+	      double value=0.0;
+	      for (CoinBigIndex j = columnStart[iColumn];
+		   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		int iRow = row[j];
+		if (sos[iRow]<0) {
+		  if (needed[iRow]) 
+		    value += CoinMin(element[j]/needed[iRow],1.0);
+		} else {
+		  iSos=iRow;
+		}
+	      }
+	      if (value&&iSos>=0) {
+		// see if value bigger than current
+		int jColumn = firstGub[iSos];
+		assert (jColumn>=0);
+		while (jColumn>=0) {
+		  if (newSolution[jColumn]) 
+		    break;
+		  jColumn = nextGub[jColumn];
+		}
+		assert (jColumn>=0);
+		double value2=0.0;
+		for (CoinBigIndex j = columnStart[jColumn];
+		     j < columnStart[jColumn] + columnLength[jColumn]; j++) {
+		  int iRow = row[j];
+		  if (needed[iRow]) 
+		    value2 += CoinMin(element[j]/needed[iRow],1.0);
+		}
+		if (value>value2) {
+		  weight[nPossible]=-(value-value2);
+		  largestWeight = CoinMax(largestWeight,(value-value2));
+		  sort[nPossible++]=iColumn;
+		}
+	      }
+	    }
+	  }
+	  if (nPossible) {
+	    double * temp = new double [numberRows];
+	    int * which2 = new int [numberRows];
+	    memset(temp,0,numberRows*sizeof(double));
+	    // modify so ones just more than gap best
+	    if (largestWeight>gap&&nUnder==1) {
+	      double offset = 4*largestWeight;
+	      for (int i=0;i<nPossible;i++) {
+		double value = -weight[i];
+		if (value>gap-1.0e-12)
+		  weight[i] = -(offset-(value-gap));
+	      }
+	    }
+	    CoinSort_2(weight,weight+nPossible,sort);
+	    for (int i=0;i<nPossible;i++) {
+	      int iColumn = sort[i];
+	      int n=0;
+	      // find jColumn
+	      int iSos=-1;
+	      for (CoinBigIndex j = columnStart[iColumn];
+		   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		int iRow = row[j];
+		temp[iRow]=element[j];
+		which2[n++]=iRow;
+		if (sos[iRow]>=0) {
+		  iSos=iRow;
+		}
+	      }
+	      int jColumn = firstGub[iSos];
+	      assert (jColumn>=0);
+	      while (jColumn>=0) {
+		if (newSolution[jColumn]) 
+		  break;
+		jColumn = nextGub[jColumn];
+	      }
+	      assert (jColumn>=0);
+	      for (CoinBigIndex j = columnStart[jColumn];
+		   j < columnStart[jColumn] + columnLength[jColumn]; j++) {
+		int iRow = row[j];
+		if (!temp[iRow])
+		  which2[n++]=iRow;
+		temp[iRow] -= element[j];
+	      }
+	      double helps = 0.0;
+	      for (int i=0;i<n;i++) {
+		int iRow = which2[i];
+		double newValue = rowActivity[iRow]+temp[iRow];
+		if (temp[iRow]>1.0e-8) {
+		  if (rowActivity[iRow]<rowLower[iRow]-1.0e-8) {
+		    helps += CoinMin(temp[iRow],
+				     rowLower[iRow]-rowActivity[iRow]);
+		  }
+		} else if (temp[iRow]<-1.0e-8) {
+		  if (newValue<rowLower[iRow]-1.0e-12) { 
+		    helps -= CoinMin(-temp[iRow],
+				     1.0*(rowLower[iRow]-newValue));
+		  }
+		}
+	      }
+	      if (helps>0.0) {
+		newSolution[iColumn]=1.0;
+		newSolution[jColumn]=0.0;
+		newSolutionValue += modifiedCost[iColumn]-modifiedCost[jColumn];
+		for (int i=0;i<n;i++) {
+		  int iRow = which2[i];
+		  double newValue = rowActivity[iRow]+temp[iRow];
+		  rowActivity[iRow] = newValue;
+		  temp[iRow]=0.0;
+		}
+		gap -= helps;
+#ifdef REPORT
+		{
+		  double gap2 = 0.0;
+		  for (iRow = 0; iRow < numberRows; iRow++) {
+		    if (rowActivity[iRow] < rowLower[iRow] - 10.0*primalTolerance) {
+		      gap2 += rowLower[iRow]-rowActivity[iRow];
+		    }
+		  }
+		  printf("estimated gap %g - computed %g\n",
+			 gap,gap2);
+		}
+#endif
+		if (gap<1.0e-8)
+		  break;
+	      } else {
+		for (int i=0;i<n;i++) 
+		  temp[which2[i]]=0.0;
+	      }
+	    }
+	    delete [] which2;
+	    delete [] temp;
+	  }
+	  delete [] weight;
+	  delete [] sort;
+	}
+	delete [] needed;
+      }
+#ifdef REPORT
+      {
+	double gap=0.0;
+	double over = 0.0;
+	for (iRow = 0; iRow < numberRows; iRow++) {
+	  if (rowActivity[iRow] < rowLower[iRow] - 10.0*primalTolerance) {
+	    double value = rowLower[iRow]-rowActivity[iRow];
+#if REPORT>1
+	    printf("below on %d is %g - activity %g lower %g\n",
+		   iRow,value,rowActivity[iRow],rowLower[iRow]);
+#endif
+	    gap += value;
+	  } else if (rowActivity[iRow] > rowUpper[iRow] + 10.0*primalTolerance) {
+	    double value = rowActivity[iRow]-rowUpper[iRow];
+#if REPORT>1
+	    printf("above on %d is %g - activity %g upper %g\n",
+		   iRow,value,rowActivity[iRow],rowUpper[iRow]);
+#endif
+	    gap += value;
+	  } else {
+	    double value = rowActivity[iRow]-rowLower[iRow];
+	    if (value) {
+#if REPORT>1
+	      printf("over on %d is %g - activity %g lower %g\n",
+		     iRow,value,rowActivity[iRow],rowLower[iRow]);
+#endif
+	      over += value;
+	    }
+	  }
+	}
+	printf("modified final gap %g - over %g - %d added - solvalue %g\n",
+	       gap,over,nAdded,newSolutionValue);
+      }
+#endif
+      if (!gap) {
+	break;
+      } else {
+	if (iPass==0) {
+	  costBias = 10.0*newSolutionValue/static_cast<double>(nAdded);
+	} else {
+	  costBias *= 10.0;
+	}
+      }
+    }
+    delete [] newSolution0;
+    delete [] rowWeight;
+    delete [] sos;
+    delete [] firstGub;
+    delete [] nextGub;
+    if (newSolutionValue < solutionValue) {
+        // check feasible
+      memset(rowActivity, 0, numberRows*sizeof(double));
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            CoinBigIndex j;
+            double value = newSolution[iColumn];
+            if (value) {
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    rowActivity[iRow] += value * element[j];
+                }
+            }
+        }
+        // check was approximately feasible
+        bool feasible = true;
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            if (rowActivity[iRow] < rowLower[iRow]) {
+                if (rowActivity[iRow] < rowLower[iRow] - 10.0*primalTolerance)
+                    feasible = false;
+            } else if (rowActivity[iRow] > rowUpper[iRow]) {
+                if (rowActivity[iRow] > rowUpper[iRow] + 10.0*primalTolerance)
+                    feasible = false;
+            }
+        }
+        if (feasible) {
+            // new solution
+            memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+            solutionValue = newSolutionValue;
+            //printf("** Solution of %g found by rounding\n",newSolutionValue);
+            returnCode = 1;
+        } else {
+            // Can easily happen
+            //printf("Debug CbcHeuristicGreedySOS giving bad solution\n");
+        }
+    }
+    delete [] sosRow;
+    delete [] newSolution;
+    delete [] rowActivity;
+    delete [] modifiedCost;
+    delete [] contribution;
+    delete [] which;
+    delete [] rhs;
+    return returnCode;
+}
+// update model
+void CbcHeuristicGreedySOS::setModel(CbcModel * model)
+{
+    delete [] originalRhs_;
+    gutsOfConstructor(model);
+    validate();
+}
+// Resets stuff if model changes
+void
+CbcHeuristicGreedySOS::resetModel(CbcModel * model)
+{
+    delete [] originalRhs_;
+    gutsOfConstructor(model);
+}
+// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+void
+CbcHeuristicGreedySOS::validate()
+{
+    if (model_ && when() < 10) {
+        if (model_->numberIntegers() !=
+                model_->numberObjects() && (model_->numberObjects() ||
+                                            (model_->specialOptions()&1024) == 0)) {
+            int numberOdd = 0;
+            for (int i = 0; i < model_->numberObjects(); i++) {
+                if (!model_->object(i)->canDoHeuristics())
+                    numberOdd++;
+            }
+            if (numberOdd)
+                setWhen(0);
+        }
+        // Only works if coefficients positive and all rows L/G or SOS
+        OsiSolverInterface * solver = model_->solver();
+        const double * columnUpper = solver->getColUpper();
+        const double * columnLower = solver->getColLower();
+        const double * rowLower = solver->getRowLower();
+        const double * rowUpper = solver->getRowUpper();
+
+        int numberRows = solver->getNumRows();
+        // Column copy
+        const double * element = matrix_.getElements();
+	const int * row = matrix_.getIndices();
+        const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+        const int * columnLength = matrix_.getVectorLengths();
+        bool good = true;
+	assert (originalRhs_);
+        for (int iRow = 0; iRow < numberRows; iRow++) {
+	  if (rowLower[iRow] == 1.0 && rowUpper[iRow] == 1.0) {
+	    // SOS
+	    originalRhs_[iRow]=-1.0;
+	  } else if (rowLower[iRow] > 0.0 && rowUpper[iRow] < 1.0e10) {
+                good = false;
+	  } else if (rowUpper[iRow] < 0.0) {
+                good = false;
+	  } else if (rowUpper[iRow] < 1.0e10) {
+	    originalRhs_[iRow]=rowUpper[iRow];
+	  } else {
+	    originalRhs_[iRow]=rowLower[iRow];
+	  }
+        }
+        int numberColumns = solver->getNumCols();
+        for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	  if (!columnLength[iColumn])
+	    continue;
+            if (columnLower[iColumn] < 0.0 || columnUpper[iColumn] > 1.0)
+                good = false;
+            CoinBigIndex j;
+	    int nSOS=0;
+	    if (!solver->isInteger(iColumn))
+	      good = false;
+            for (j = columnStart[iColumn];
+                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                if (element[j] < 0.0)
+                    good = false;
+		int iRow = row[j];
+		if (originalRhs_[iRow]==-1.0) {
+		  if (element[j] != 1.0)
+		    good = false;
+		  nSOS++;
+		}
+            }
+	    if (nSOS > 1)
+	      good = false;
+        }
+        if (!good)
+            setWhen(0); // switch off
+    }
+}
diff --git a/cbits/coin/CbcHeuristicGreedy.hpp b/cbits/coin/CbcHeuristicGreedy.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicGreedy.hpp
@@ -0,0 +1,280 @@
+/* $Id: CbcHeuristicGreedy.hpp 1585 2011-01-11 19:04:34Z forrest $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicGreedy_H
+#define CbcHeuristicGreedy_H
+
+#include "CbcHeuristic.hpp"
+/** Greedy heuristic classes
+ */
+
+class CbcHeuristicGreedyCover : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicGreedyCover ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicGreedyCover (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicGreedyCover ( const CbcHeuristicGreedyCover &);
+
+    // Destructor
+    ~CbcHeuristicGreedyCover ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+    /// Assignment operator
+    CbcHeuristicGreedyCover & operator=(const CbcHeuristicGreedyCover& rhs);
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        We leave all variables which are at one at this node of the
+        tree to that value and will
+        initially set all others to zero.  We then sort all variables in order of their cost
+        divided by the number of entries in rows which are not yet covered.  We randomize that
+        value a bit so that ties will be broken in different ways on different runs of the heuristic.
+        We then choose the best one and set it to one and repeat the exercise.
+
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+    virtual void validate() ;
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+    /* Algorithm
+       0 - use current upper bounds
+       1 - use original upper bounds
+       If 10 added perturb ratios more
+       if 100 added round up all >=0.5
+    */
+    inline int algorithm() const {
+        return algorithm_;
+    }
+    inline void setAlgorithm(int value) {
+        algorithm_ = value;
+    }
+    // Only do this many times
+    inline int numberTimes() const {
+        return numberTimes_;
+    }
+    inline void setNumberTimes(int value) {
+        numberTimes_ = value;
+    }
+
+protected:
+    /// Guts of constructor from a CbcModel
+    void gutsOfConstructor(CbcModel * model);
+    // Data
+
+    // Original matrix by column
+    CoinPackedMatrix matrix_;
+    // original number of rows
+    int originalNumberRows_;
+    /* Algorithm
+       0 - use current upper bounds
+       1 - use original upper bounds
+       If 10 added perturb ratios more
+    */
+    int algorithm_;
+    /// Do this many times
+    int numberTimes_;
+
+};
+
+
+class CbcHeuristicGreedyEquality : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicGreedyEquality ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicGreedyEquality (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicGreedyEquality ( const CbcHeuristicGreedyEquality &);
+
+    // Destructor
+    ~CbcHeuristicGreedyEquality ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+    /// Assignment operator
+    CbcHeuristicGreedyEquality & operator=(const CbcHeuristicGreedyEquality& rhs);
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        We leave all variables which are at one at this node of the
+        tree to that value and will
+        initially set all others to zero.  We then sort all variables in order of their cost
+        divided by the number of entries in rows which are not yet covered.  We randomize that
+        value a bit so that ties will be broken in different ways on different runs of the heuristic.
+        We then choose the best one and set it to one and repeat the exercise.
+
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+    virtual void validate() ;
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+    /* Algorithm
+       0 - use current upper bounds
+       1 - use original upper bounds
+       If 10 added perturb ratios more
+       if 100 added round up all >=0.5
+    */
+    inline int algorithm() const {
+        return algorithm_;
+    }
+    inline void setAlgorithm(int value) {
+        algorithm_ = value;
+    }
+    // Fraction of rhs to cover before branch and cut
+    inline void setFraction(double value) {
+        fraction_ = value;
+    }
+    inline double fraction() const {
+        return fraction_;
+    }
+    // Only do this many times
+    inline int numberTimes() const {
+        return numberTimes_;
+    }
+    inline void setNumberTimes(int value) {
+        numberTimes_ = value;
+    }
+protected:
+    /// Guts of constructor from a CbcModel
+    void gutsOfConstructor(CbcModel * model);
+    // Data
+
+    // Original matrix by column
+    CoinPackedMatrix matrix_;
+    // Fraction of rhs to cover before branch and cut
+    double fraction_;
+    // original number of rows
+    int originalNumberRows_;
+    /* Algorithm
+       0 - use current upper bounds
+       1 - use original upper bounds
+       If 10 added perturb ratios more
+    */
+    int algorithm_;
+    /// Do this many times
+    int numberTimes_;
+
+};
+
+/** Greedy heuristic for SOS and L rows (and positive elements)
+ */
+
+class CbcHeuristicGreedySOS : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicGreedySOS ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicGreedySOS (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicGreedySOS ( const CbcHeuristicGreedySOS &);
+
+    // Destructor
+    ~CbcHeuristicGreedySOS ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+    /// Assignment operator
+    CbcHeuristicGreedySOS & operator=(const CbcHeuristicGreedySOS& rhs);
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        We leave all variables which are at one at this node of the
+        tree to that value and will
+        initially set all others to zero.  We then sort all variables in order of their cost
+        divided by the number of entries in rows which are not yet covered.  We randomize that
+        value a bit so that ties will be broken in different ways on different runs of the heuristic.
+        We then choose the best one and set it to one and repeat the exercise.
+
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// Validate model i.e. sets when_ to 0 if necessary (may be NULL)
+    virtual void validate() ;
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+    /* Algorithm
+       Bits
+       1 bit - use current model, otherwise original
+       2 - use current solution as starting point, otherwise pure greedy
+       4 - as 2 but use merit not merit/size
+       8 - use duals to modify greedy
+       16 - use duals on GUB/SOS in special way
+    */
+    inline int algorithm() const {
+        return algorithm_;
+    }
+    inline void setAlgorithm(int value) {
+        algorithm_ = value;
+    }
+    // Only do this many times
+    inline int numberTimes() const {
+        return numberTimes_;
+    }
+    inline void setNumberTimes(int value) {
+        numberTimes_ = value;
+    }
+
+protected:
+    /// Guts of constructor from a CbcModel
+    void gutsOfConstructor(CbcModel * model);
+    // Data
+
+    // Original RHS - if -1.0 then SOS otherwise <= value
+    double * originalRhs_;
+    // Original matrix by column
+    CoinPackedMatrix matrix_;
+    // original number of rows
+    int originalNumberRows_;
+    /* Algorithm
+    */
+    int algorithm_;
+    /// Do this many times
+    int numberTimes_;
+
+};
+
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicLocal.cpp b/cbits/coin/CbcHeuristicLocal.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicLocal.cpp
@@ -0,0 +1,1644 @@
+/* $Id: CbcHeuristicLocal.cpp 1839 2013-01-16 18:41:25Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcHeuristicLocal.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcStrategy.hpp"
+#include "CglPreProcess.hpp"
+
+// Default Constructor
+CbcHeuristicLocal::CbcHeuristicLocal()
+        : CbcHeuristic()
+{
+    numberSolutions_ = 0;
+    swap_ = 0;
+    used_ = NULL;
+    lastRunDeep_ = -1000000;
+    switches_ |= 16; // needs a new solution
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicLocal::CbcHeuristicLocal(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    numberSolutions_ = 0;
+    swap_ = 0;
+    lastRunDeep_ = -1000000;
+    switches_ |= 16; // needs a new solution
+    // Get a copy of original matrix
+    assert(model.solver());
+    if (model.solver()->getNumRows()) {
+        matrix_ = *model.solver()->getMatrixByCol();
+    }
+    int numberColumns = model.solver()->getNumCols();
+    used_ = new int[numberColumns];
+    memset(used_, 0, numberColumns*sizeof(int));
+}
+
+// Destructor
+CbcHeuristicLocal::~CbcHeuristicLocal ()
+{
+    delete [] used_;
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicLocal::clone() const
+{
+    return new CbcHeuristicLocal(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicLocal::generateCpp( FILE * fp)
+{
+    CbcHeuristicLocal other;
+    fprintf(fp, "0#include \"CbcHeuristicLocal.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicLocal heuristicLocal(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicLocal");
+    if (swap_ != other.swap_)
+        fprintf(fp, "3  heuristicLocal.setSearchType(%d);\n", swap_);
+    else
+        fprintf(fp, "4  heuristicLocal.setSearchType(%d);\n", swap_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicLocal);\n");
+}
+
+// Copy constructor
+CbcHeuristicLocal::CbcHeuristicLocal(const CbcHeuristicLocal & rhs)
+        :
+        CbcHeuristic(rhs),
+        matrix_(rhs.matrix_),
+        numberSolutions_(rhs.numberSolutions_),
+        swap_(rhs.swap_)
+{
+    if (model_ && rhs.used_) {
+        int numberColumns = model_->solver()->getNumCols();
+        used_ = CoinCopyOfArray(rhs.used_, numberColumns);
+    } else {
+        used_ = NULL;
+    }
+}
+
+// Assignment operator
+CbcHeuristicLocal &
+CbcHeuristicLocal::operator=( const CbcHeuristicLocal & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        matrix_ = rhs.matrix_;
+        numberSolutions_ = rhs.numberSolutions_;
+        swap_ = rhs.swap_;
+        delete [] used_;
+        if (model_ && rhs.used_) {
+            int numberColumns = model_->solver()->getNumCols();
+            used_ = CoinCopyOfArray(rhs.used_, numberColumns);
+        } else {
+            used_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicLocal::resetModel(CbcModel * /*model*/)
+{
+    //CbcHeuristic::resetModel(model);
+    delete [] used_;
+    if (model_ && used_) {
+        int numberColumns = model_->solver()->getNumCols();
+        used_ = new int[numberColumns];
+        memset(used_, 0, numberColumns*sizeof(int));
+    } else {
+        used_ = NULL;
+    }
+}
+/*
+  Run a mini-BaB search after fixing all variables not marked as used by
+  solution(). (See comments there for semantics.)
+
+  Return values are:
+    1: smallBranchAndBound found a solution
+    0: everything else
+
+  The degree of overload as return codes from smallBranchAndBound are folded
+  into 0 is such that it's impossible to distinguish return codes that really
+  require attention from a simple `nothing of interest'.
+*/
+// This version fixes stuff and does IP
+int
+CbcHeuristicLocal::solutionFix(double & objectiveValue,
+                               double * newSolution,
+                               const int * /*keep*/)
+{
+/*
+  If when is set to off (0), or set to root (1) and we're not at the root,
+  return. If this heuristic discovered the current solution, don't continue.
+*/
+
+    numCouldRun_++;
+    // See if to do
+    if (!when() || (when() == 1 && model_->phase() != 1))
+        return 0; // switched off
+    // Don't do if it was this heuristic which found solution!
+    if (this == model_->lastHeuristic())
+        return 0;
+/*
+  Load up a new solver with the solution.
+
+  Why continuousSolver(), as opposed to solver()?
+*/
+    OsiSolverInterface * newSolver = model_->continuousSolver()->clone();
+    const double * colLower = newSolver->getColLower();
+    //const double * colUpper = newSolver->getColUpper();
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+/*
+  The net effect here is that anything that hasn't moved from its lower bound
+  will be fixed at lower bound.
+
+  See comments in solution() w.r.t. asymmetric treatment of upper and lower
+  bounds.
+*/
+
+    int i;
+    int nFix = 0;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        const OsiObject * object = model_->object(i);
+        // get original bounds
+        double originalLower;
+        double originalUpper;
+        getIntegerInformation( object, originalLower, originalUpper);
+        newSolver->setColLower(iColumn, CoinMax(colLower[iColumn], originalLower));
+        if (!used_[iColumn]) {
+            newSolver->setColUpper(iColumn, colLower[iColumn]);
+            nFix++;
+        }
+    }
+/*
+  Try a `small' branch-and-bound search. The notion here is that we've fixed a
+  lot of variables and reduced the amount of `free' problem to a point where a
+  small BaB search will suffice to fully explore the remaining problem. This
+  routine will execute integer presolve, then call branchAndBound to do the
+  actual search.
+*/
+    int returnCode = 0;
+#ifdef CLP_INVESTIGATE2
+    printf("Fixing %d out of %d (%d continuous)\n",
+           nFix, numberIntegers, newSolver->getNumCols() - numberIntegers);
+#endif
+    if (nFix*10 <= numberIntegers) {
+        // see if we can fix more
+        int * which = new int [2*(numberIntegers-nFix)];
+        int * sort = which + (numberIntegers - nFix);
+        int n = 0;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            if (used_[iColumn]) {
+                which[n] = iColumn;
+                sort[n++] = used_[iColumn];
+            }
+        }
+        CoinSort_2(sort, sort + n, which);
+        // only half fixed in total
+        n = CoinMin(n, numberIntegers / 2 - nFix);
+        int allow = CoinMax(numberSolutions_ - 2, sort[0]);
+        int nFix2 = 0;
+        for (i = 0; i < n; i++) {
+            int iColumn = integerVariable[i];
+            if (used_[iColumn] <= allow) {
+                newSolver->setColUpper(iColumn, colLower[iColumn]);
+                nFix2++;
+            } else {
+                break;
+            }
+        }
+        delete [] which;
+        nFix += nFix2;
+#ifdef CLP_INVESTIGATE2
+        printf("Number fixed increased from %d to %d\n",
+               nFix - nFix2, nFix);
+#endif
+    }
+    if (nFix*10 > numberIntegers) {
+        returnCode = smallBranchAndBound(newSolver, numberNodes_, newSolution, objectiveValue,
+                                         objectiveValue, "CbcHeuristicLocal");
+ /*
+  -2 is return due to user event, and -1 is overloaded with what look to be
+  two contradictory meanings.
+*/
+       if (returnCode < 0) {
+            returnCode = 0; // returned on size
+            int numberColumns = newSolver->getNumCols();
+            int numberContinuous = numberColumns - numberIntegers;
+            if (numberContinuous > 2*numberIntegers &&
+                    nFix*10 < numberColumns) {
+#define LOCAL_FIX_CONTINUOUS
+#ifdef LOCAL_FIX_CONTINUOUS
+                //const double * colUpper = newSolver->getColUpper();
+                const double * colLower = newSolver->getColLower();
+                int nAtLb = 0;
+                //double sumDj=0.0;
+                const double * dj = newSolver->getReducedCost();
+                double direction = newSolver->getObjSense();
+                for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (!newSolver->isInteger(iColumn)) {
+                        if (!used_[iColumn]) {
+                            //double djValue = dj[iColumn]*direction;
+                            nAtLb++;
+                            //sumDj += djValue;
+                        }
+                    }
+                }
+                if (nAtLb) {
+                    // fix some continuous
+                    double * sort = new double[nAtLb];
+                    int * which = new int [nAtLb];
+                    //double threshold = CoinMax((0.01*sumDj)/static_cast<double>(nAtLb),1.0e-6);
+                    int nFix2 = 0;
+                    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        if (!newSolver->isInteger(iColumn)) {
+                            if (!used_[iColumn]) {
+                                double djValue = dj[iColumn] * direction;
+                                if (djValue > 1.0e-6) {
+                                    sort[nFix2] = -djValue;
+                                    which[nFix2++] = iColumn;
+                                }
+                            }
+                        }
+                    }
+                    CoinSort_2(sort, sort + nFix2, which);
+                    int divisor = 2;
+                    nFix2 = CoinMin(nFix2, (numberColumns - nFix) / divisor);
+                    for (int i = 0; i < nFix2; i++) {
+                        int iColumn = which[i];
+                        newSolver->setColUpper(iColumn, colLower[iColumn]);
+                    }
+                    delete [] sort;
+                    delete [] which;
+#ifdef CLP_INVESTIGATE2
+                    printf("%d integers have zero value, and %d continuous fixed at lb\n",
+                           nFix, nFix2);
+#endif
+                    returnCode = smallBranchAndBound(newSolver,
+                                                     numberNodes_, newSolution,
+                                                     objectiveValue,
+                                                     objectiveValue, "CbcHeuristicLocal");
+                    if (returnCode < 0)
+                        returnCode = 0; // returned on size
+                }
+#endif
+            }
+        }
+    }
+/*
+  If the result is complete exploration with a solution (3) or proven
+  infeasibility (2), we could generate a cut (the AI folks would call it a
+  nogood) to prevent us from going down this route in the future.
+*/
+    if ((returnCode&2) != 0) {
+        // could add cut
+        returnCode &= ~2;
+    }
+
+    delete newSolver;
+    return returnCode;
+}
+/*
+  First tries setting a variable to better value.  If feasible then
+  tries setting others.  If not feasible then tries swaps
+  Returns 1 if solution, 0 if not 
+  The main body of this routine implements an O((q^2)/2) brute force search
+  around the current solution, for q = number of integer variables. Call this
+  the inc/dec heuristic.  For each integer variable x<i>, first decrement the
+  value. Then, for integer variables x<i+1>, ..., x<q-1>, try increment and
+  decrement. If one of these permutations produces a better solution,
+  remember it.  Then repeat, with x<i> incremented. If we find a better
+  solution, update our notion of current solution and continue.
+
+  The net effect is a greedy walk: As each improving pair is found, the
+  current solution is updated and the search continues from this updated
+  solution.
+
+  Way down at the end, we call solutionFix, which will create a drastically
+  restricted problem based on variables marked as used, then do mini-BaC on
+  the restricted problem. This can occur even if we don't try the inc/dec
+  heuristic. This would be more obvious if the inc/dec heuristic were broken
+  out as a separate routine and solutionFix had a name that reflected where
+  it was headed.
+
+  The return code of 0 is grossly overloaded, because it maps to a return
+  code of 0 from solutionFix, which is itself grossly overloaded. See
+  comments in solutionFix and in CbcHeuristic::smallBranchAndBound.
+  */
+int
+CbcHeuristicLocal::solution(double & solutionValue,
+                            double * betterSolution)
+{
+/*
+  Execute only if a new solution has been discovered since the last time we
+  were called.
+*/
+
+    numCouldRun_++;
+    // See if frequency kills off idea
+    int swap = swap_%100;
+    int skip = swap_/100;
+    int nodeCount = model_->getNodeCount();
+    if (nodeCount<lastRunDeep_+skip && nodeCount != lastRunDeep_+1) 
+      return 0;
+    if (numberSolutions_ == model_->getSolutionCount() &&
+	(numberSolutions_ == howOftenShallow_ ||
+	 nodeCount < lastRunDeep_+2*skip))
+        return 0;
+    howOftenShallow_ = numberSolutions_;
+    numberSolutions_ = model_->getSolutionCount();
+    if (nodeCount<lastRunDeep_+skip ) 
+      return 0;
+    lastRunDeep_ = nodeCount;
+    howOftenShallow_ = numberSolutions_;
+
+    if ((swap%10) == 2) {
+        // try merge
+        return solutionFix( solutionValue, betterSolution, NULL);
+    }
+/*
+  Exclude long (column), thin (row) systems.
+
+  Given the n^2 nature of the search, more than 100,000 columns could get
+  expensive. But I don't yet see the rationale for the second part of the
+  condition (cols > 10*rows). And cost is proportional to number of integer
+  variables --- shouldn't we use that?
+
+  Why wait until we have more than one solution?
+*/
+    if ((model_->getNumCols() > 100000 && model_->getNumCols() >
+            10*model_->getNumRows()) || numberSolutions_ <= 1)
+        return 0; // probably not worth it
+    // worth trying
+
+    OsiSolverInterface * solver = model_->solver();
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    const double * solution = model_->bestSolution();
+/*
+  Shouldn't this test be redundant if we've already checked that
+  numberSolutions_ > 1? Stronger: shouldn't this be an assertion?
+*/
+    if (!solution)
+        return 0; // No solution found yet
+    const double * objective = solver->getObjCoefficients();
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    int numberRows = matrix_.getNumRows();
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+
+    int i;
+    double direction = solver->getObjSense();
+    double newSolutionValue = model_->getObjValue() * direction;
+    int returnCode = 0;
+    numRuns_++;
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    const int * columnLength = matrix_.getVectorLengths();
+
+    // Get solution array for heuristic solution
+    int numberColumns = solver->getNumCols();
+    double * newSolution = new double [numberColumns];
+    memcpy(newSolution, solution, numberColumns*sizeof(double));
+#ifdef LOCAL_FIX_CONTINUOUS
+    // mark continuous used
+    const double * columnLower = solver->getColLower();
+    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+        if (!solver->isInteger(iColumn)) {
+            if (solution[iColumn] > columnLower[iColumn] + 1.0e-8)
+                used_[iColumn] = numberSolutions_;
+        }
+    }
+#endif
+
+    // way is 1 if down possible, 2 if up possible, 3 if both possible
+    char * way = new char[numberIntegers];
+    // corrected costs
+    double * cost = new double[numberIntegers];
+    // for array to mark infeasible rows after iColumn branch
+    char * mark = new char[numberRows];
+    memset(mark, 0, numberRows);
+    // space to save values so we don't introduce rounding errors
+    double * save = new double[numberRows];
+/*
+  Force variables within their original bounds, then to the nearest integer.
+  Overall, we seem to be prepared to cope with noninteger bounds. Is this
+  necessary? Seems like we'd be better off to force the bounds to integrality
+  as part of preprocessing.  More generally, why do we need to do this? This
+  solution should have been cleaned and checked when it was accepted as a
+  solution!
+
+  Once the value is set, decide whether we can move up or down.
+
+  The only place that used_ is used is in solutionFix; if a variable is not
+  flagged as used, it will be fixed (at lower bound). Why the asymmetric
+  treatment? This makes some sense for binary variables (for which there are
+  only two options). But for general integer variables, why not make a similar
+  test against the original upper bound?
+*/
+
+    // clean solution
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        const OsiObject * object = model_->object(i);
+        // get original bounds
+        double originalLower;
+        double originalUpper;
+        getIntegerInformation( object, originalLower, originalUpper);
+        double value = newSolution[iColumn];
+        if (value < originalLower) {
+            value = originalLower;
+            newSolution[iColumn] = value;
+        } else if (value > originalUpper) {
+            value = originalUpper;
+            newSolution[iColumn] = value;
+        }
+        double nearest = floor(value + 0.5);
+        //assert(fabs(value-nearest)<10.0*primalTolerance);
+        value = nearest;
+        newSolution[iColumn] = nearest;
+        // if away from lower bound mark that fact
+        if (nearest > originalLower) {
+            used_[iColumn] = numberSolutions_;
+        }
+        cost[i] = direction * objective[iColumn];
+/*
+  Given previous computation we're checking that value is at least 1 away
+  from the original bounds.
+*/
+        int iway = 0;
+
+        if (value > originalLower + 0.5)
+            iway = 1;
+        if (value < originalUpper - 0.5)
+            iway |= 2;
+        way[i] = static_cast<char>(iway);
+    }
+/*
+  Calculate lhs of each constraint for groomed solution.
+*/
+    // get row activities
+    double * rowActivity = new double[numberRows];
+    memset(rowActivity, 0, numberRows*sizeof(double));
+
+    for (i = 0; i < numberColumns; i++) {
+        int j;
+        double value = newSolution[i];
+        if (value) {
+            for (j = columnStart[i];
+                    j < columnStart[i] + columnLength[i]; j++) {
+                int iRow = row[j];
+                rowActivity[iRow] += value * element[j];
+            }
+        }
+    }
+/*
+  Check that constraints are satisfied. For small infeasibility, force the
+  activity within bound. Again, why is this necessary if the current solution
+  was accepted as a valid solution?
+
+  Why are we scanning past the first unacceptable constraint?
+*/
+    // check was feasible - if not adjust (cleaning may move)
+    // if very infeasible then give up
+    bool tryHeuristic = true;
+    for (i = 0; i < numberRows; i++) {
+        if (rowActivity[i] < rowLower[i]) {
+            if (rowActivity[i] < rowLower[i] - 10.0*primalTolerance)
+                tryHeuristic = false;
+            rowActivity[i] = rowLower[i];
+        } else if (rowActivity[i] > rowUpper[i]) {
+            if (rowActivity[i] < rowUpper[i] + 10.0*primalTolerance)
+                tryHeuristic = false;
+            rowActivity[i] = rowUpper[i];
+        }
+    }
+/*
+  This bit of code is not quite totally redundant: it'll bail at 10,000
+  instead of 100,000. Potentially we can do a lot of work to get here, only
+  to abandon it.
+*/
+    // Switch off if may take too long
+    if (model_->getNumCols() > 10000 && model_->getNumCols() >
+            10*model_->getNumRows())
+        tryHeuristic = false;
+/*
+  Try the inc/dec heuristic?
+*/
+    if (tryHeuristic) {
+
+        // total change in objective
+        double totalChange = 0.0;
+        // local best change in objective
+        double bestChange = 0.0;
+	// maybe just do 1000
+	int maxIntegers = numberIntegers;
+	if (((swap/10) &1) != 0) {
+	  maxIntegers = CoinMin(1000,numberIntegers);
+	}
+/*
+  Outer loop to walk integer variables. Call the current variable x<i>. At the
+  end of this loop, bestChange will contain the best (negative) change in the
+  objective for any single pair.
+
+  The trouble is, we're limited to monotonically increasing improvement.
+  Suppose we discover an improvement of 10 for some pair. If, later in the
+  search, we discover an improvement of 9 for some other pair, we will not use
+  it. That seems wasteful.
+*/
+
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+	    bestChange = 0.0;
+	    int endInner = CoinMin(numberIntegers,i+maxIntegers);
+
+            double objectiveCoefficient = cost[i];
+            int k;
+            int j;
+            int goodK = -1;
+            int wayK = -1, wayI = -1;
+/*
+  Try decrementing x<i>.
+*/
+            if ((way[i]&1) != 0) {
+                int numberInfeasible = 0;
+/*
+  Adjust row activities where x<i> has a nonzero coefficient. Save the old
+  values for restoration. Mark any rows that become infeasible as a result
+  of the decrement.
+*/
+                // save row activities and adjust
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    save[iRow] = rowActivity[iRow];
+                    rowActivity[iRow] -= element[j];
+                    if (rowActivity[iRow] < rowLower[iRow] - primalTolerance ||
+                            rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
+                        // mark row
+                        mark[iRow] = 1;
+                        numberInfeasible++;
+                    }
+                }
+  /*
+  Run through the remaining integer variables. Try increment and decrement on
+  each one. If the potential objective change is better than anything we've
+  seen so far, do a full evaluation of x<k> in that direction.  If we can
+  repair all infeasibilities introduced by pushing x<i> down, we have a
+  winner. Remember the best variable, and the direction for x<i> and x<k>.
+*/
+              // try down
+                for (k = i + 1; k < endInner; k++) {
+                    if ((way[k]&1) != 0) {
+                        // try down
+                        if (-objectiveCoefficient - cost[k] < bestChange) {
+                            // see if feasible down
+                            bool good = true;
+                            int numberMarked = 0;
+                            int kColumn = integerVariable[k];
+                            for (j = columnStart[kColumn];
+                                    j < columnStart[kColumn] + columnLength[kColumn]; j++) {
+                                int iRow = row[j];
+                                double newValue = rowActivity[iRow] - element[j];
+                                if (newValue < rowLower[iRow] - primalTolerance ||
+                                        newValue > rowUpper[iRow] + primalTolerance) {
+                                    good = false;
+                                    break;
+                                } else if (mark[iRow]) {
+                                    // made feasible
+                                    numberMarked++;
+                                }
+                            }
+                            if (good && numberMarked == numberInfeasible) {
+                                // better solution
+                                goodK = k;
+                                wayK = -1;
+                                wayI = -1;
+                                bestChange = -objectiveCoefficient - cost[k];
+                            }
+                        }
+                    }
+                    if ((way[k]&2) != 0) {
+                        // try up
+                        if (-objectiveCoefficient + cost[k] < bestChange) {
+                            // see if feasible up
+                            bool good = true;
+                            int numberMarked = 0;
+                            int kColumn = integerVariable[k];
+                            for (j = columnStart[kColumn];
+                                    j < columnStart[kColumn] + columnLength[kColumn]; j++) {
+                                int iRow = row[j];
+                                double newValue = rowActivity[iRow] + element[j];
+                                if (newValue < rowLower[iRow] - primalTolerance ||
+                                        newValue > rowUpper[iRow] + primalTolerance) {
+                                    good = false;
+                                    break;
+                                } else if (mark[iRow]) {
+                                    // made feasible
+                                    numberMarked++;
+                                }
+                            }
+                            if (good && numberMarked == numberInfeasible) {
+                                // better solution
+                                goodK = k;
+                                wayK = 1;
+                                wayI = -1;
+                                bestChange = -objectiveCoefficient + cost[k];
+                            }
+                        }
+                    }
+                }
+/*
+  Remove effect of decrementing x<i> by restoring original lhs values.
+*/
+                // restore row activities
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    rowActivity[iRow] = save[iRow];
+                    mark[iRow] = 0;
+                }
+            }
+/*
+  Try to increment x<i>. Actions as for decrement.
+*/
+            if ((way[i]&2) != 0) {
+                int numberInfeasible = 0;
+                // save row activities and adjust
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    save[iRow] = rowActivity[iRow];
+                    rowActivity[iRow] += element[j];
+                    if (rowActivity[iRow] < rowLower[iRow] - primalTolerance ||
+                            rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
+                        // mark row
+                        mark[iRow] = 1;
+                        numberInfeasible++;
+                    }
+                }
+                // try up
+                for (k = i + 1; k < endInner; k++) {
+                    if ((way[k]&1) != 0) {
+                        // try down
+                        if (objectiveCoefficient - cost[k] < bestChange) {
+                            // see if feasible down
+                            bool good = true;
+                            int numberMarked = 0;
+                            int kColumn = integerVariable[k];
+                            for (j = columnStart[kColumn];
+                                    j < columnStart[kColumn] + columnLength[kColumn]; j++) {
+                                int iRow = row[j];
+                                double newValue = rowActivity[iRow] - element[j];
+                                if (newValue < rowLower[iRow] - primalTolerance ||
+                                        newValue > rowUpper[iRow] + primalTolerance) {
+                                    good = false;
+                                    break;
+                                } else if (mark[iRow]) {
+                                    // made feasible
+                                    numberMarked++;
+                                }
+                            }
+                            if (good && numberMarked == numberInfeasible) {
+                                // better solution
+                                goodK = k;
+                                wayK = -1;
+                                wayI = 1;
+                                bestChange = objectiveCoefficient - cost[k];
+                            }
+                        }
+                    }
+                    if ((way[k]&2) != 0) {
+                        // try up
+                        if (objectiveCoefficient + cost[k] < bestChange) {
+                            // see if feasible up
+                            bool good = true;
+                            int numberMarked = 0;
+                            int kColumn = integerVariable[k];
+                            for (j = columnStart[kColumn];
+                                    j < columnStart[kColumn] + columnLength[kColumn]; j++) {
+                                int iRow = row[j];
+                                double newValue = rowActivity[iRow] + element[j];
+                                if (newValue < rowLower[iRow] - primalTolerance ||
+                                        newValue > rowUpper[iRow] + primalTolerance) {
+                                    good = false;
+                                    break;
+                                } else if (mark[iRow]) {
+                                    // made feasible
+                                    numberMarked++;
+                                }
+                            }
+                            if (good && numberMarked == numberInfeasible) {
+                                // better solution
+                                goodK = k;
+                                wayK = 1;
+                                wayI = 1;
+                                bestChange = objectiveCoefficient + cost[k];
+                            }
+                        }
+                    }
+                }
+                // restore row activities
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    rowActivity[iRow] = save[iRow];
+                    mark[iRow] = 0;
+                }
+            }
+/*
+  We've found a pair x<i> and x<k> which produce a better solution. Update our
+  notion of current solution to match.
+
+  Why does this not update newSolutionValue?
+*/
+            if (goodK >= 0) {
+                // we found something - update solution
+                for (j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    rowActivity[iRow]  += wayI * element[j];
+                }
+                newSolution[iColumn] += wayI;
+                int kColumn = integerVariable[goodK];
+                for (j = columnStart[kColumn];
+                        j < columnStart[kColumn] + columnLength[kColumn]; j++) {
+                    int iRow = row[j];
+                    rowActivity[iRow]  += wayK * element[j];
+                }
+                newSolution[kColumn] += wayK;
+/*
+  Adjust motion range for x<k>. We may have banged up against a bound with that
+  last move.
+*/
+               // See if k can go further ?
+                const OsiObject * object = model_->object(goodK);
+                // get original bounds
+                double originalLower;
+                double originalUpper;
+                getIntegerInformation( object, originalLower, originalUpper);
+
+                double value = newSolution[kColumn];
+                int iway = 0;
+
+                if (value > originalLower + 0.5)
+                    iway = 1;
+                if (value < originalUpper - 0.5)
+                    iway |= 2;
+                way[goodK] = static_cast<char>(iway);
+		totalChange += bestChange;
+            }
+        }
+/*
+  End of loop to try increment/decrement of integer variables.
+
+  newSolutionValue does not necessarily match the current newSolution, and
+  bestChange simply reflects the best single change. Still, that's sufficient
+  to indicate that there's been at least one change. Check that we really do
+  have a valid solution.
+*/
+        if (totalChange + newSolutionValue < solutionValue) {
+            // paranoid check
+            memset(rowActivity, 0, numberRows*sizeof(double));
+
+            for (i = 0; i < numberColumns; i++) {
+                int j;
+                double value = newSolution[i];
+                if (value) {
+                    for (j = columnStart[i];
+                            j < columnStart[i] + columnLength[i]; j++) {
+                        int iRow = row[j];
+                        rowActivity[iRow] += value * element[j];
+                    }
+                }
+            }
+            int numberBad = 0;
+            double sumBad = 0.0;
+            // check was approximately feasible
+            for (i = 0; i < numberRows; i++) {
+                if (rowActivity[i] < rowLower[i]) {
+                    sumBad += rowLower[i] - rowActivity[i];
+                    if (rowActivity[i] < rowLower[i] - 10.0*primalTolerance)
+                        numberBad++;
+                } else if (rowActivity[i] > rowUpper[i]) {
+                    sumBad += rowUpper[i] - rowActivity[i];
+                    if (rowActivity[i] > rowUpper[i] + 10.0*primalTolerance)
+                        numberBad++;
+                }
+            }
+            if (!numberBad) {
+                for (i = 0; i < numberIntegers; i++) {
+                    int iColumn = integerVariable[i];
+                    const OsiObject * object = model_->object(i);
+                    // get original bounds
+                    double originalLower;
+                    double originalUpper;
+                    getIntegerInformation( object, originalLower, originalUpper);
+
+                    double value = newSolution[iColumn];
+                    // if away from lower bound mark that fact
+                    if (value > originalLower) {
+                        used_[iColumn] = numberSolutions_;
+                    }
+                }
+/*
+  Copy the solution to the array returned to the client. Grab a basis from
+  the solver (which, if it exists, is almost certainly infeasible, but it
+  should be ok for a dual start). The value returned as solutionValue is
+  conservative because of handling of newSolutionValue and bestChange, as
+  described above.
+*/
+                // new solution
+                memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
+                CoinWarmStartBasis * basis =
+                    dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+                if (basis) {
+                    model_->setBestSolutionBasis(* basis);
+                    delete basis;
+                }
+                returnCode = 1;
+                solutionValue = newSolutionValue + bestChange;
+            } else {
+                // bad solution - should not happen so debug if see message
+                COIN_DETAIL_PRINT(printf("Local search got bad solution with %d infeasibilities summing to %g\n",
+					 numberBad, sumBad));
+            }
+        }
+    }
+/*
+  We're done. Clean up.
+*/
+    delete [] newSolution;
+    delete [] rowActivity;
+    delete [] way;
+    delete [] cost;
+    delete [] save;
+    delete [] mark;
+/*
+  Do we want to try swapping values between solutions?
+  swap_ is set elsewhere; it's not adjusted during heuristic execution.
+
+  Again, redundant test. We shouldn't be here if numberSolutions_ = 1.
+*/
+    if (numberSolutions_ > 1 && (swap%10) == 1) {
+        // try merge
+        int returnCode2 = solutionFix( solutionValue, betterSolution, NULL);
+        if (returnCode2)
+            returnCode = 1;
+    }
+    return returnCode;
+}
+// update model
+void CbcHeuristicLocal::setModel(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix
+    assert(model_->solver());
+    if (model_->solver()->getNumRows()) {
+        matrix_ = *model_->solver()->getMatrixByCol();
+    }
+    delete [] used_;
+    int numberColumns = model->solver()->getNumCols();
+    used_ = new int[numberColumns];
+    memset(used_, 0, numberColumns*sizeof(int));
+}
+
+// Default Constructor
+CbcHeuristicProximity::CbcHeuristicProximity()
+        : CbcHeuristic()
+{
+    feasibilityPump_ = NULL;
+    numberSolutions_ = 0;
+    used_ = NULL;
+    lastRunDeep_ = -1000000;
+    switches_ |= 16; // needs a new solution
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicProximity::CbcHeuristicProximity(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    feasibilityPump_ = NULL;
+    numberSolutions_ = 0;
+    lastRunDeep_ = -1000000;
+    switches_ |= 16; // needs a new solution
+    int numberColumns = model.solver()->getNumCols();
+    used_ = new int[numberColumns];
+    memset(used_, 0, numberColumns*sizeof(int));
+}
+
+// Destructor
+CbcHeuristicProximity::~CbcHeuristicProximity ()
+{
+    delete feasibilityPump_;
+    delete [] used_;
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicProximity::clone() const
+{
+    return new CbcHeuristicProximity(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicProximity::generateCpp( FILE * fp)
+{
+    CbcHeuristicProximity other;
+    fprintf(fp, "0#include \"CbcHeuristicProximity.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicProximity heuristicProximity(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicProximity");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicProximity);\n");
+}
+
+// Copy constructor
+CbcHeuristicProximity::CbcHeuristicProximity(const CbcHeuristicProximity & rhs)
+  :
+  CbcHeuristic(rhs),
+  numberSolutions_(rhs.numberSolutions_)
+{
+    feasibilityPump_ = NULL;
+    if (model_ && rhs.used_) {
+        int numberColumns = model_->solver()->getNumCols();
+        used_ = CoinCopyOfArray(rhs.used_, numberColumns);
+	if (rhs.feasibilityPump_)
+	  feasibilityPump_ = new CbcHeuristicFPump(*rhs.feasibilityPump_);
+    } else {
+        used_ = NULL;
+    }
+}
+
+// Assignment operator
+CbcHeuristicProximity &
+CbcHeuristicProximity::operator=( const CbcHeuristicProximity & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        numberSolutions_ = rhs.numberSolutions_;
+        delete [] used_;
+        delete feasibilityPump_;
+	feasibilityPump_ = NULL;
+	if (model_ && rhs.used_) {
+            int numberColumns = model_->solver()->getNumCols();
+            used_ = CoinCopyOfArray(rhs.used_, numberColumns);
+	    if (rhs.feasibilityPump_)
+	      feasibilityPump_ = new CbcHeuristicFPump(*rhs.feasibilityPump_);
+        } else {
+            used_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicProximity::resetModel(CbcModel * /*model*/)
+{
+    //CbcHeuristic::resetModel(model);
+    delete [] used_;
+    if (model_ && used_) {
+        int numberColumns = model_->solver()->getNumCols();
+        used_ = new int[numberColumns];
+        memset(used_, 0, numberColumns*sizeof(int));
+    } else {
+        used_ = NULL;
+    }
+}
+/*
+  Run a mini-BaB search after changing objective
+
+  Return values are:
+    1: smallBranchAndBound found a solution
+    0: everything else
+
+  The degree of overload as return codes from smallBranchAndBound are folded
+  into 0 is such that it's impossible to distinguish return codes that really
+  require attention from a simple `nothing of interest'.
+*/
+int
+CbcHeuristicProximity::solution(double & solutionValue,
+                            double * betterSolution)
+{
+  if (feasibilityPumpOptions_ == -3 && numCouldRun_==0 &&
+      !feasibilityPump_ ) {
+    // clone feasibility pump
+    for (int i = 0; i < model_->numberHeuristics(); i++) {
+      const CbcHeuristicFPump* pump =
+	dynamic_cast<const CbcHeuristicFPump*>(model_->heuristic(i));
+      if (pump) {
+	feasibilityPump_ = new CbcHeuristicFPump(*pump);
+	break;
+      }
+    }
+  }
+/*
+  Execute only if a new solution has been discovered since the last time we
+  were called.
+*/
+
+  numCouldRun_++;
+  int nodeCount = model_->getNodeCount();
+  if (numberSolutions_ == model_->getSolutionCount())
+    return 0;
+  if (!model_->bestSolution())
+    return 0; // odd - because in parallel mode
+  numberSolutions_ = model_->getSolutionCount();
+  lastRunDeep_ = nodeCount;
+  numRuns_++;
+  //howOftenShallow_ = numberSolutions_;
+  
+/*
+  Load up a new solver with the solution.
+
+  Why continuousSolver(), as opposed to solver()?
+*/
+  OsiSolverInterface * newSolver = model_->continuousSolver()->clone();
+  int numberColumns=newSolver->getNumCols();
+  double * obj = CoinCopyOfArray(newSolver->getObjCoefficients(),numberColumns);
+  int * indices = new int [numberColumns];
+  int n=0;
+  for (int i=0;i<numberColumns;i++) {
+    if (obj[i]) {
+      indices[n]=i;
+      obj[n++]=obj[i];
+    }
+  }
+  double cutoff=model_->getCutoff();
+  assert (cutoff<1.0e20);
+  if (model_->getCutoffIncrement()<1.0e-4)
+    cutoff -= 0.01;
+  double offset;
+  newSolver->getDblParam(OsiObjOffset, offset);
+  newSolver->setDblParam(OsiObjOffset, 0.0);
+  newSolver->addRow(n,indices,obj,-COIN_DBL_MAX,cutoff+offset);
+  delete [] indices;
+  memset(obj,0,numberColumns*sizeof(double));
+  newSolver->setDblParam(OsiDualObjectiveLimit, 1.0e20);
+  int numberIntegers = model_->numberIntegers();
+  const int * integerVariable = model_->integerVariable();
+  const double * solutionIn = model_->bestSolution();
+  for (int i = 0; i < numberIntegers; i++) {
+    int iColumn = integerVariable[i];
+    if (fabs(solutionIn[iColumn])<1.0e-5) 
+      obj[iColumn]=1.0;
+    else if (fabs(solutionIn[iColumn]-1.0)<1.0e-5) 
+      obj[iColumn]=-1.0;
+  }
+  newSolver->setObjective(obj);
+  delete [] obj;
+  //newSolver->writeMps("xxxx");
+  int maxSolutions = model_->getMaximumSolutions();
+  model_->setMaximumSolutions(1); 
+  bool pumpAdded = false;
+  if (feasibilityPumpOptions_ == -3 && feasibilityPump_) {
+    // add back feasibility pump
+    pumpAdded = true;
+    for (int i = 0; i < model_->numberHeuristics(); i++) {
+      const CbcHeuristicFPump* pump =
+	dynamic_cast<const CbcHeuristicFPump*>(model_->heuristic(i));
+      if (pump) {
+	pumpAdded = false;
+	break;
+      }
+    }
+    if (pumpAdded) 
+      model_->addHeuristic(feasibilityPump_);
+  }
+  int returnCode = 
+    smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+			1.0e20, "CbcHeuristicProximity");
+  if (pumpAdded) {
+    // take off feasibility pump
+    int lastHeuristic = model_->numberHeuristics()-1;
+    model_->setNumberHeuristics(lastHeuristic);
+    delete model_->heuristic(lastHeuristic);
+  }
+  model_->setMaximumSolutions(maxSolutions); 
+ /*
+  -2 is return due to user event, and -1 is overloaded with what look to be
+  two contradictory meanings.
+*/
+  if (returnCode < 0) {
+    returnCode = 0; 
+  }
+/*
+  If the result is complete exploration with a solution (3) or proven
+  infeasibility (2), we could generate a cut (the AI folks would call it a
+  nogood) to prevent us from going down this route in the future.
+*/
+  if ((returnCode&2) != 0) {
+    // could add cut
+    returnCode &= ~2;
+  }
+  char proxPrint[200];
+  if ((returnCode&1) != 0) {
+    // redo objective
+    const double * obj = model_->continuousSolver()->getObjCoefficients();
+    solutionValue = - offset;
+    int sumIncrease=0.0;
+    int sumDecrease=0.0;
+    int numberIncrease=0;
+    int numberDecrease=0;
+    for (int i=0;i<numberColumns;i++) {
+      solutionValue += obj[i]*betterSolution[i];
+      if (model_->isInteger(i)) {
+	int change=static_cast<int>(floor(solutionIn[i]-betterSolution[i]+0.5));
+	if (change>0) {
+	  numberIncrease++;
+	  sumIncrease+=change;
+	} else if (change<0) {
+	  numberDecrease++;
+	  sumDecrease-=change;
+	}
+      }
+    }
+    sprintf(proxPrint,"Proximity search ran %d nodes (out of %d) - in new solution %d increased (%d), %d decreased (%d)",
+	    numberNodesDone_,numberNodes_,
+	    numberIncrease,sumIncrease,numberDecrease,sumDecrease);
+  } else {
+    sprintf(proxPrint,"Proximity search ran %d nodes - no new solution",
+	    numberNodesDone_);
+  }
+  model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+    << proxPrint
+    << CoinMessageEol;
+  
+  delete newSolver;
+  return returnCode;
+}
+// update model
+void CbcHeuristicProximity::setModel(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix
+    assert(model_->solver());
+    delete [] used_;
+    int numberColumns = model->solver()->getNumCols();
+    used_ = new int[numberColumns];
+    memset(used_, 0, numberColumns*sizeof(int));
+}
+
+// Default Constructor
+CbcHeuristicNaive::CbcHeuristicNaive()
+        : CbcHeuristic()
+{
+    large_ = 1.0e6;
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicNaive::CbcHeuristicNaive(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    large_ = 1.0e6;
+}
+
+// Destructor
+CbcHeuristicNaive::~CbcHeuristicNaive ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicNaive::clone() const
+{
+    return new CbcHeuristicNaive(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicNaive::generateCpp( FILE * fp)
+{
+    CbcHeuristicNaive other;
+    fprintf(fp, "0#include \"CbcHeuristicProximity.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicNaive naive(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "naive");
+    if (large_ != other.large_)
+        fprintf(fp, "3  naive.setLarge(%g);\n", large_);
+    else
+        fprintf(fp, "4  naive.setLarge(%g);\n", large_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&naive);\n");
+}
+
+// Copy constructor
+CbcHeuristicNaive::CbcHeuristicNaive(const CbcHeuristicNaive & rhs)
+        :
+        CbcHeuristic(rhs),
+        large_(rhs.large_)
+{
+}
+
+// Assignment operator
+CbcHeuristicNaive &
+CbcHeuristicNaive::operator=( const CbcHeuristicNaive & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        large_ = rhs.large_;
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicNaive::resetModel(CbcModel * model)
+{
+    CbcHeuristic::resetModel(model);
+}
+int
+CbcHeuristicNaive::solution(double & solutionValue,
+                            double * betterSolution)
+{
+    numCouldRun_++;
+    // See if to do
+    bool atRoot = model_->getNodeCount() == 0;
+    int passNumber = model_->getCurrentPassNumber();
+    if (!when() || (when() == 1 && model_->phase() != 1) || !atRoot || passNumber != 1)
+        return 0; // switched off
+    // Don't do if it was this heuristic which found solution!
+    if (this == model_->lastHeuristic())
+        return 0;
+    numRuns_++;
+    double cutoff;
+    model_->solver()->getDblParam(OsiDualObjectiveLimit, cutoff);
+    double direction = model_->solver()->getObjSense();
+    cutoff *= direction;
+    cutoff = CoinMin(cutoff, solutionValue);
+    OsiSolverInterface * solver = model_->continuousSolver();
+    if (!solver)
+        solver = model_->solver();
+    const double * colLower = solver->getColLower();
+    const double * colUpper = solver->getColUpper();
+    const double * objective = solver->getObjCoefficients();
+
+    int numberColumns = model_->getNumCols();
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+
+    int i;
+    bool solutionFound = false;
+    CoinWarmStartBasis saveBasis;
+    CoinWarmStartBasis * basis =
+        dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+    if (basis) {
+        saveBasis = * basis;
+        delete basis;
+    }
+    // First just fix all integers as close to zero as possible
+    OsiSolverInterface * newSolver = cloneBut(7); // wassolver->clone();
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double lower = colLower[iColumn];
+        double upper = colUpper[iColumn];
+        double value;
+        if (lower > 0.0)
+            value = lower;
+        else if (upper < 0.0)
+            value = upper;
+        else
+            value = 0.0;
+        newSolver->setColLower(iColumn, value);
+        newSolver->setColUpper(iColumn, value);
+    }
+    newSolver->initialSolve();
+    if (newSolver->isProvenOptimal()) {
+        double solValue = newSolver->getObjValue() * direction ;
+        if (solValue < cutoff) {
+            // we have a solution
+            solutionFound = true;
+            solutionValue = solValue;
+            memcpy(betterSolution, newSolver->getColSolution(),
+                   numberColumns*sizeof(double));
+            COIN_DETAIL_PRINT(printf("Naive fixing close to zero gave solution of %g\n", solutionValue));
+            cutoff = solValue - model_->getCutoffIncrement();
+        }
+    }
+    // Now fix all integers as close to zero if not zero or large cost
+    int nFix = 0;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double lower = colLower[iColumn];
+        double upper = colUpper[iColumn];
+        double value;
+        if (fabs(objective[i]) > 0.0 && fabs(objective[i]) < large_) {
+            nFix++;
+            if (lower > 0.0)
+                value = lower;
+            else if (upper < 0.0)
+                value = upper;
+            else
+                value = 0.0;
+            newSolver->setColLower(iColumn, value);
+            newSolver->setColUpper(iColumn, value);
+        } else {
+            // set back to original
+            newSolver->setColLower(iColumn, lower);
+            newSolver->setColUpper(iColumn, upper);
+        }
+    }
+    const double * solution = solver->getColSolution();
+    if (nFix) {
+        newSolver->setWarmStart(&saveBasis);
+        newSolver->setColSolution(solution);
+        newSolver->initialSolve();
+        if (newSolver->isProvenOptimal()) {
+            double solValue = newSolver->getObjValue() * direction ;
+            if (solValue < cutoff) {
+                // try branch and bound
+                double * newSolution = new double [numberColumns];
+                COIN_DETAIL_PRINT(printf("%d fixed after fixing costs\n", nFix));
+                int returnCode = smallBranchAndBound(newSolver,
+                                                     numberNodes_, newSolution,
+                                                     solutionValue,
+                                                     solutionValue, "CbcHeuristicNaive1");
+                if (returnCode < 0)
+                    returnCode = 0; // returned on size
+                if ((returnCode&2) != 0) {
+                    // could add cut
+                    returnCode &= ~2;
+                }
+                if (returnCode == 1) {
+                    // solution
+                    solutionFound = true;
+                    memcpy(betterSolution, newSolution,
+                           numberColumns*sizeof(double));
+                    COIN_DETAIL_PRINT(printf("Naive fixing zeros gave solution of %g\n", solutionValue));
+                    cutoff = solutionValue - model_->getCutoffIncrement();
+                }
+                delete [] newSolution;
+            }
+        }
+    }
+#if 1
+    newSolver->setObjSense(-direction); // maximize
+    newSolver->setWarmStart(&saveBasis);
+    newSolver->setColSolution(solution);
+    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+        double value = solution[iColumn];
+        double lower = colLower[iColumn];
+        double upper = colUpper[iColumn];
+        double newLower;
+        double newUpper;
+        if (newSolver->isInteger(iColumn)) {
+            newLower = CoinMax(lower, floor(value) - 2.0);
+            newUpper = CoinMin(upper, ceil(value) + 2.0);
+        } else {
+            newLower = CoinMax(lower, value - 1.0e5);
+            newUpper = CoinMin(upper, value + 1.0e-5);
+        }
+        newSolver->setColLower(iColumn, newLower);
+        newSolver->setColUpper(iColumn, newUpper);
+    }
+    newSolver->initialSolve();
+    if (newSolver->isProvenOptimal()) {
+        double solValue = newSolver->getObjValue() * direction ;
+        if (solValue < cutoff) {
+            nFix = 0;
+            newSolver->setObjSense(direction); // correct direction
+            //const double * thisSolution = newSolver->getColSolution();
+            for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                double value = solution[iColumn];
+                double lower = colLower[iColumn];
+                double upper = colUpper[iColumn];
+                double newLower = lower;
+                double newUpper = upper;
+                if (newSolver->isInteger(iColumn)) {
+                    if (value < lower + 1.0e-6) {
+                        nFix++;
+                        newUpper = lower;
+                    } else if (value > upper - 1.0e-6) {
+                        nFix++;
+                        newLower = upper;
+                    } else {
+                        newLower = CoinMax(lower, floor(value) - 2.0);
+                        newUpper = CoinMin(upper, ceil(value) + 2.0);
+                    }
+                }
+                newSolver->setColLower(iColumn, newLower);
+                newSolver->setColUpper(iColumn, newUpper);
+            }
+            // try branch and bound
+            double * newSolution = new double [numberColumns];
+            COIN_DETAIL_PRINT(printf("%d fixed after maximizing\n", nFix));
+            int returnCode = smallBranchAndBound(newSolver,
+                                                 numberNodes_, newSolution,
+                                                 solutionValue,
+                                                 solutionValue, "CbcHeuristicNaive1");
+            if (returnCode < 0)
+                returnCode = 0; // returned on size
+            if ((returnCode&2) != 0) {
+                // could add cut
+                returnCode &= ~2;
+            }
+            if (returnCode == 1) {
+                // solution
+                solutionFound = true;
+                memcpy(betterSolution, newSolution,
+                       numberColumns*sizeof(double));
+                COIN_DETAIL_PRINT(printf("Naive maximizing gave solution of %g\n", solutionValue));
+                cutoff = solutionValue - model_->getCutoffIncrement();
+            }
+            delete [] newSolution;
+        }
+    }
+#endif
+    delete newSolver;
+    return solutionFound ? 1 : 0;
+}
+// update model
+void CbcHeuristicNaive::setModel(CbcModel * model)
+{
+    model_ = model;
+}
+// Default Constructor
+CbcHeuristicCrossover::CbcHeuristicCrossover()
+        : CbcHeuristic(),
+        numberSolutions_(0),
+        useNumber_(3)
+{
+    setWhen(1);
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicCrossover::CbcHeuristicCrossover(CbcModel & model)
+        : CbcHeuristic(model),
+        numberSolutions_(0),
+        useNumber_(3)
+{
+    setWhen(1);
+    for (int i = 0; i < 10; i++)
+        random_[i] = model.randomNumberGenerator()->randomDouble();
+}
+
+// Destructor
+CbcHeuristicCrossover::~CbcHeuristicCrossover ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicCrossover::clone() const
+{
+    return new CbcHeuristicCrossover(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicCrossover::generateCpp( FILE * fp)
+{
+    CbcHeuristicCrossover other;
+    fprintf(fp, "0#include \"CbcHeuristicProximity.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicCrossover crossover(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "crossover");
+    if (useNumber_ != other.useNumber_)
+        fprintf(fp, "3  crossover.setNumberSolutions(%d);\n", useNumber_);
+    else
+        fprintf(fp, "4  crossover.setNumberSolutions(%d);\n", useNumber_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&crossover);\n");
+}
+
+// Copy constructor
+CbcHeuristicCrossover::CbcHeuristicCrossover(const CbcHeuristicCrossover & rhs)
+        :
+        CbcHeuristic(rhs),
+        attempts_(rhs.attempts_),
+        numberSolutions_(rhs.numberSolutions_),
+        useNumber_(rhs.useNumber_)
+{
+    memcpy(random_, rhs.random_, 10*sizeof(double));
+}
+
+// Assignment operator
+CbcHeuristicCrossover &
+CbcHeuristicCrossover::operator=( const CbcHeuristicCrossover & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        useNumber_ = rhs.useNumber_;
+        attempts_ = rhs.attempts_;
+        numberSolutions_ = rhs.numberSolutions_;
+        memcpy(random_, rhs.random_, 10*sizeof(double));
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicCrossover::resetModel(CbcModel * model)
+{
+    CbcHeuristic::resetModel(model);
+}
+int
+CbcHeuristicCrossover::solution(double & solutionValue,
+                                double * betterSolution)
+{
+    if (when_ == 0)
+        return 0;
+    numCouldRun_++;
+    bool useBest = (numberSolutions_ != model_->getSolutionCount());
+    if (!useBest && (when_ % 10) == 1)
+        return 0;
+    numberSolutions_ = model_->getSolutionCount();
+    OsiSolverInterface * continuousSolver = model_->continuousSolver();
+    int useNumber = CoinMin(model_->numberSavedSolutions(), useNumber_);
+    if (useNumber < 2 || !continuousSolver)
+        return 0;
+    // Fix later
+    if (!useBest)
+        abort();
+    numRuns_++;
+    double cutoff;
+    model_->solver()->getDblParam(OsiDualObjectiveLimit, cutoff);
+    double direction = model_->solver()->getObjSense();
+    cutoff *= direction;
+    cutoff = CoinMin(cutoff, solutionValue);
+    OsiSolverInterface * solver = cloneBut(2);
+    // But reset bounds
+    solver->setColLower(continuousSolver->getColLower());
+    solver->setColUpper(continuousSolver->getColUpper());
+    int numberColumns = solver->getNumCols();
+    // Fixed
+    double * fixed = new double [numberColumns];
+    for (int i = 0; i < numberColumns; i++)
+        fixed[i] = -COIN_DBL_MAX;
+    int whichSolution[10];
+    for (int i = 0; i < useNumber; i++)
+        whichSolution[i] = i;
+    for (int i = 0; i < useNumber; i++) {
+        int k = whichSolution[i];
+        const double * solution = model_->savedSolution(k);
+        for (int j = 0; j < numberColumns; j++) {
+            if (solver->isInteger(j)) {
+                if (fixed[j] == -COIN_DBL_MAX)
+                    fixed[j] = floor(solution[j] + 0.5);
+                else if (fabs(fixed[j] - solution[j]) > 1.0e-7)
+                    fixed[j] = COIN_DBL_MAX;
+            }
+        }
+    }
+    const double * colLower = solver->getColLower();
+    for (int i = 0; i < numberColumns; i++) {
+        if (solver->isInteger(i)) {
+            double value = fixed[i];
+            if (value != COIN_DBL_MAX) {
+                if (when_ < 10) {
+                    solver->setColLower(i, value);
+                    solver->setColUpper(i, value);
+                } else if (value == colLower[i]) {
+                    solver->setColUpper(i, value);
+                }
+            }
+        }
+    }
+    int returnCode = smallBranchAndBound(solver, numberNodes_, betterSolution,
+                                         solutionValue,
+                                         solutionValue, "CbcHeuristicCrossover");
+    if (returnCode < 0)
+        returnCode = 0; // returned on size
+    if ((returnCode&2) != 0) {
+        // could add cut
+        returnCode &= ~2;
+    }
+
+    delete solver;
+    return returnCode;
+}
+// update model
+void CbcHeuristicCrossover::setModel(CbcModel * model)
+{
+    model_ = model;
+    if (model) {
+        for (int i = 0; i < 10; i++)
+            random_[i] = model->randomNumberGenerator()->randomDouble();
+    }
+}
+
+
diff --git a/cbits/coin/CbcHeuristicLocal.hpp b/cbits/coin/CbcHeuristicLocal.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicLocal.hpp
@@ -0,0 +1,267 @@
+/* $Id: CbcHeuristicLocal.hpp 1802 2012-11-21 09:38:56Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicLocal_H
+#define CbcHeuristicLocal_H
+
+#include "CbcHeuristic.hpp"
+/** LocalSearch class
+ */
+
+class CbcHeuristicLocal : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicLocal ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicLocal (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicLocal ( const CbcHeuristicLocal &);
+
+    // Destructor
+    ~CbcHeuristicLocal ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicLocal & operator=(const CbcHeuristicLocal& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        This is called after cuts have been added - so can not add cuts
+        First tries setting a variable to better value.  If feasible then
+        tries setting others.  If not feasible then tries swaps
+
+        ********
+
+        This first version does not do LP's and does swaps of two integer
+        variables.  Later versions could do Lps.
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// This version fixes stuff and does IP
+    int solutionFix(double & objectiveValue,
+                    double * newSolution,
+                    const int * keep);
+
+    /// Sets type of search
+    inline void setSearchType(int value) {
+        swap_ = value;
+    }
+    /// Used array so we can set
+    inline int * used() const {
+        return used_;
+    }
+
+protected:
+    // Data
+
+    // Original matrix by column
+    CoinPackedMatrix matrix_;
+
+    // Number of solutions so we only do after new solution
+    int numberSolutions_;
+    // Type of search 0=normal, 1=BAB
+    int swap_;
+    /// Whether a variable has been in a solution (also when)
+    int * used_;
+};
+
+/** Proximity Search class
+ */
+class CbcHeuristicFPump;
+class CbcHeuristicProximity : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicProximity ();
+
+    /* Constructor with model - assumed before cuts
+    */
+    CbcHeuristicProximity (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicProximity ( const CbcHeuristicProximity &);
+
+    // Destructor
+    ~CbcHeuristicProximity ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicProximity & operator=(const CbcHeuristicProximity& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+
+    /// Used array so we can set
+    inline int * used() const {
+        return used_;
+    }
+
+protected:
+    // Data
+    // Copy of Feasibility pump
+    CbcHeuristicFPump * feasibilityPump_;
+    // Number of solutions so we only do after new solution
+    int numberSolutions_;
+    /// Whether a variable has been in a solution (also when)
+    int * used_;
+};
+
+
+/** Naive class
+    a) Fix all ints as close to zero as possible
+    b) Fix all ints with nonzero costs and < large to zero
+    c) Put bounds round continuous and UIs and maximize
+ */
+
+class CbcHeuristicNaive : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicNaive ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicNaive (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicNaive ( const CbcHeuristicNaive &);
+
+    // Destructor
+    ~CbcHeuristicNaive ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicNaive & operator=(const CbcHeuristicNaive& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+
+    /// Sets large cost value
+    inline void setLargeValue(double value) {
+        large_ = value;
+    }
+    /// Gets large cost value
+    inline double largeValue() const {
+        return large_;
+    }
+
+protected:
+    /// Data
+    /// Large value
+    double large_;
+};
+
+/** Crossover Search class
+ */
+
+class CbcHeuristicCrossover : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicCrossover ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicCrossover (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicCrossover ( const CbcHeuristicCrossover &);
+
+    // Destructor
+    ~CbcHeuristicCrossover ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicCrossover & operator=(const CbcHeuristicCrossover& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Fix variables if agree in useNumber_ solutions
+        when_ 0 off, 1 only at new solutions, 2 also every now and then
+        add 10 to make only if agree at lower bound
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+
+    /// Sets number of solutions to use
+    inline void setNumberSolutions(int value) {
+        if (value > 0 && value <= 10)
+            useNumber_ = value;
+    }
+
+protected:
+    // Data
+    /// Attempts
+    std::vector <double> attempts_;
+    /// Random numbers to stop same search happening
+    double random_[10];
+    /// Number of solutions so we only do after new solution
+    int numberSolutions_;
+    /// Number of solutions to use
+    int useNumber_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicPivotAndFix.cpp b/cbits/coin/CbcHeuristicPivotAndFix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicPivotAndFix.cpp
@@ -0,0 +1,543 @@
+/* $Id: CbcHeuristicPivotAndFix.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+#include <vector>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcHeuristicPivotAndFix.hpp"
+#include "OsiClpSolverInterface.hpp"
+#include  "CoinTime.hpp"
+
+//#define FORNOW
+
+// Default Constructor
+CbcHeuristicPivotAndFix::CbcHeuristicPivotAndFix()
+        : CbcHeuristic()
+{
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicPivotAndFix::CbcHeuristicPivotAndFix(CbcModel & model)
+        : CbcHeuristic(model)
+{
+}
+
+// Destructor
+CbcHeuristicPivotAndFix::~CbcHeuristicPivotAndFix ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicPivotAndFix::clone() const
+{
+    return new CbcHeuristicPivotAndFix(*this);
+}
+// Create C++ lines to get to current state
+void
+CbcHeuristicPivotAndFix::generateCpp( FILE * fp)
+{
+    CbcHeuristicPivotAndFix other;
+    fprintf(fp, "0#include \"CbcHeuristicPivotAndFix.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicPivotAndFix heuristicPFX(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicPFX");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicPFX);\n");
+}
+
+// Copy constructor
+CbcHeuristicPivotAndFix::CbcHeuristicPivotAndFix(const CbcHeuristicPivotAndFix & rhs)
+        :
+        CbcHeuristic(rhs)
+{
+}
+
+// Assignment operator
+CbcHeuristicPivotAndFix &
+CbcHeuristicPivotAndFix::operator=( const CbcHeuristicPivotAndFix & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicPivotAndFix::resetModel(CbcModel * /*model*/)
+{
+    //CbcHeuristic::resetModel(model);
+}
+/*
+  Comments needed
+  Returns 1 if solution, 0 if not */
+int
+CbcHeuristicPivotAndFix::solution(double & /*solutionValue*/,
+                                  double * /*betterSolution*/)
+{
+
+    numCouldRun_++; // Todo: Ask JJHF what this for.
+    std::cout << "Entering Pivot-and-Fix Heuristic" << std::endl;
+
+#ifdef FORNOW
+    std::cout << "Lucky you! You're in the Pivot-and-Fix Heuristic" << std::endl;
+    // The struct should be moved to member data
+
+
+
+    typedef struct {
+        int numberSolutions;
+        int maximumSolutions;
+        int numberColumns;
+        double ** solution;
+        int * numberUnsatisfied;
+    } clpSolution;
+
+    double start = CoinCpuTime();
+
+    OsiClpSolverInterface * clpSolverOriginal
+    = dynamic_cast<OsiClpSolverInterface *> (model_->solver());
+    assert (clpSolverOriginal);
+    OsiClpSolverInterface *clpSolver(clpSolverOriginal);
+
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+
+    // Initialize the structure holding the solutions
+    clpSolution solutions;
+    // Set typeStruct field of ClpTrustedData struct to one.
+    // This tells Clp it's "Mahdi!"
+    ClpTrustedData trustedSolutions;
+    trustedSolutions.typeStruct = 1;
+    trustedSolutions.data = &solutions;
+    solutions.numberSolutions = 0;
+    solutions.maximumSolutions = 0;
+    solutions.numberColumns = simplex->numberColumns();
+    solutions.solution = NULL;
+    solutions.numberUnsatisfied = NULL;
+    simplex->setTrustedUserPointer(&trustedSolutions);
+
+    // Solve from all slack to get some points
+    simplex->allSlackBasis();
+    simplex->primal();
+
+    // -------------------------------------------------
+    // Get the problem information
+    // - get the number of cols and rows
+    int numCols = clpSolver->getNumCols();
+    int numRows = clpSolver->getNumRows();
+
+    // - get the right hand side of the rows
+    const double * rhs = clpSolver->getRightHandSide();
+
+    // - find the integer variables
+    bool * varClassInt = new bool[numCols];
+    int numInt = 0;
+    for (int i = 0; i < numCols; i++) {
+        if (clpSolver->isContinuous(i))
+            varClassInt[i] = 0;
+        else {
+            varClassInt[i] = 1;
+            numInt++;
+        }
+    }
+
+    // -Get the rows sense
+    const char * rowSense;
+    rowSense = clpSolver->getRowSense();
+
+    // -Get the objective coefficients
+    const double *objCoefficients = clpSolver->getObjCoefficients();
+    double *originalObjCoeff = new double [numCols];
+    for (int i = 0; i < numCols; i++)
+        originalObjCoeff[i] = objCoefficients[i];
+
+    // -Get the matrix of the problem
+    double ** matrix = new double * [numRows];
+    for (int i = 0; i < numRows; i++) {
+        matrix[i] = new double[numCols];
+        for (int j = 0; j < numCols; j++)
+            matrix[i][j] = 0;
+    }
+    const CoinPackedMatrix* matrixByRow = clpSolver->getMatrixByRow();
+    const double * matrixElements = matrixByRow->getElements();
+    const int * matrixIndices = matrixByRow->getIndices();
+    const int * matrixStarts = matrixByRow->getVectorStarts();
+    for (int j = 0; j < numRows; j++) {
+        for (int i = matrixStarts[j]; i < matrixStarts[j+1]; i++) {
+            matrix[j][matrixIndices[i]] = matrixElements[i];
+        }
+    }
+
+    // The newObj is the randomly perturbed constraint used to find new
+    // corner points
+    double * newObj = new double [numCols];
+
+    // Set the random seed
+    srand ( time(NULL) + 1);
+    int randNum;
+
+    // We're going to add a new row to the LP formulation
+    // after finding each new solution.
+    // Adding a new row requires the new elements and the new indices.
+    // The elements are original objective function coefficients.
+    // The indicies are the (dense) columns indices stored in addRowIndex.
+    // The rhs is the value of the new solution stored in solutionValue.
+    int * addRowIndex = new int[numCols];
+    for (int i = 0; i < numCols; i++)
+        addRowIndex[i] = i;
+
+    // The number of feasible solutions found by the PF heuristic.
+    // This controls the return code of the solution() method.
+    int numFeasibles = 0;
+
+    // Shuffle the rows
+    int * index = new int [numRows];
+    for (int i = 0; i < numRows; i++)
+        index[i] = i;
+    for (int i = 0; i < numRows; i++) {
+        int temp = index[i];
+        int randNumTemp = i + (rand() % (numRows - i));
+        index[i] = index[randNumTemp];
+        index[randNumTemp] = temp;
+    }
+
+    // In the clpSolution struct, we store a lot of column solutions.
+    // For each perturb objective, we store the solution from each
+    // iteration of the LP solve.
+    // For each perturb objective, we look at the collection of
+    // solutions to do something extremly intelligent :-)
+    // We could (and should..and will :-) wipe out the block of
+    // solutions when we're done with them. But for now, we just move on
+    // and store the next block of solutions for the next (perturbed)
+    // objective.
+    // The variable startIndex tells us where the new block begins.
+    int startIndex = 0;
+
+    // At most "fixThreshold" number of integer variables can be unsatisfied
+    // for calling smallBranchAndBound().
+    // The PF Heuristic only fixes fixThreshold number of variables to
+    // their integer values. Not more. Not less. The reason is to give
+    // the smallBB some opportunity to find better solutions. If we fix
+    // everything it might be too many (leading the heuristic to come up
+    // with infeasibility rather than a useful result).
+    // (This is an important paramater. And it is dynamically set.)
+    double fixThreshold;
+    /*
+        if(numInt > 400)
+        fixThreshold = 17*sqrt(numInt);
+        if(numInt<=400 && numInt>100)
+        fixThreshold = 5*sqrt(numInt);
+        if(numInt<=100)
+        fixThreshold = 4*sqrt(numInt);
+    */
+    // Initialize fixThreshold based on the number of integer
+    // variables
+    if (numInt <= 100)
+        fixThreshold = .35 * numInt;
+    if (numInt > 100 && numInt < 1000)
+        fixThreshold = .85 * numInt;
+    if (numInt >= 1000)
+        fixThreshold = .1 * numInt;
+
+    // Whenever the dynamic system for changing fixThreshold
+    // kicks in, it changes the parameter by the
+    // fixThresholdChange amount.
+    // (The 25% should be member data and tuned. Another paper!)
+    double fixThresholdChange = 0.25 * fixThreshold;
+
+    // maxNode is the maximum number of nodes we allow smallBB to
+    // search. It's initialized to 400 and changed dynamically.
+    // The 400 should be member data, if we become virtuous.
+    int maxNode = 400;
+
+    // We control the decision to change maxNode through the boolean
+    // variable  changeMaxNode. The boolean variable is initialized to
+    // true and gets set to false under a condition (and is never true
+    // again.)
+    // It's flipped off and stays off (in the current incarnation of PF)
+    bool changeMaxNode = 1;
+
+    // The sumReturnCode is used for the dynamic system that sets
+    // fixThreshold and changeMaxNode.
+    //
+    // We track what's happening in sumReturnCode. There are 8 switches.
+    // The first 5 switches corresponds to a return code for smallBB.
+    //
+    // We want to know how many times we consecutively get the same
+    // return code.
+    //
+    // If "good" return codes are happening often enough, we're happy.
+    //
+    // If a "bad" returncodes happen consecutively, we want to
+    // change something.
+    //
+    // The switch 5 is the number of times PF didn't call smallBB
+    // becuase the number of integer variables that took integer values
+    // was less than fixThreshold.
+    //
+    // The swicth 6 was added for a brilliant idea...to be announced
+    // later (another paper!)
+    //
+    // The switch 7 is the one that changes the max node. Read the
+    // code. (Todo: Verbalize the brilliant idea for the masses.)
+    //
+    int sumReturnCode[8];
+    /*
+      sumReturnCode[0] ~ -1 --> problem too big for smallBB
+      sumReturnCode[1] ~ 0  --> smallBB not finshed and no soln
+      sumReturnCode[2] ~ 1  --> smallBB not finshed and there is a soln
+      sumReturnCode[3] ~ 2  --> smallBB finished and no soln
+      sumReturnCode[4] ~ 3  --> smallBB finished and there is a soln
+      sumReturnCode[5] ~ didn't call smallBranchAndBound too few to fix
+      sumReturnCode[6] ~ didn't call smallBranchAndBound too many unsatisfied
+      sumReturnCode[7] ~ the same as sumReturnCode[1] but becomes zero just if the returnCode is not 0
+    */
+
+    for (int i = 0; i < 8; i++)
+        sumReturnCode[i] = 0;
+    int * colIndex = new int[numCols];
+    for (int i = 0; i < numCols; i++)
+        colIndex[i] = i;
+    double cutoff = COIN_DBL_MAX;
+    bool didMiniBB;
+
+    // Main loop
+    for (int i = 0; i < numRows; i++) {
+        // track the number of mini-bb for the dynamic threshold setting
+        didMiniBB = 0;
+
+        for (int k = startIndex; k < solutions.numberSolutions; k++)
+            //if the point has 0 unsatisfied variables; make sure it is
+            //feasible. Check integer feasiblity and constraints.
+            if (solutions.numberUnsatisfied[k] == 0) {
+                double feasibility = 1;
+                //check integer feasibility
+                for (int icol = 0; icol < numCols; icol++) {
+                    double closest = floor(solutions.solution[k][icol] + 0.5);
+                    if (varClassInt[icol] && (fabs(solutions.solution[k][icol] - closest) > 1e-6)) {
+                        feasibility = 0;
+                        break;
+                    }
+                }
+                //check if the solution satisfies the constraints
+                for (int irow = 0; irow < numRows; irow++) {
+                    double lhs = 0;
+                    for (int j = 0; j < numCols; j++)
+                        lhs += matrix[irow][j] * solutions.solution[k][j];
+                    if (rowSense[irow] == 'L' && lhs > rhs[irow] + 1e-6) {
+                        feasibility = 0;
+                        break;
+                    }
+                    if (rowSense[irow] == 'G' && lhs < rhs[irow] - 1e-6) {
+                        feasibility = 0;
+                        break;
+                    }
+                    if (rowSense[irow] == 'E' && (lhs - rhs[irow] > 1e-6 || lhs - rhs[irow] < -1e-6)) {
+                        feasibility = 0;
+                        break;
+                    }
+                }
+
+                //if feasible, find the objective value and set the cutoff
+                // for the smallBB and add a new constraint to the LP
+                // (and update the best solution found so far for the
+                // return arguments)
+                if (feasibility) {
+                    double objectiveValue = 0;
+                    for (int j = 0; j < numCols; j++)
+                        objectiveValue += solutions.solution[k][j] * originalObjCoeff[j];
+                    cutoff = objectiveValue;
+                    clpSolver->addRow(numCols, addRowIndex, originalObjCoeff, -COIN_DBL_MAX, cutoff);
+
+                    // Todo: pick up the best solution in the block (not
+                    // the last).
+                    solutionValue = objectiveValue;
+                    for (int m = 0; m < numCols; m++)
+                        betterSolution[m] = solutions.solution[k][m];
+                    numFeasibles++;
+                }
+            }
+
+        // Go through the block of solution and decide if to call smallBB
+        for (int k = startIndex; k < solutions.numberSolutions; k++) {
+            if (solutions.numberUnsatisfied[k] <= fixThreshold) {
+                // get new copy
+                OsiSolverInterface * newSolver;
+                newSolver = new OsiClpSolverInterface(*clpSolver);
+                newSolver->setObjSense(1);
+                newSolver->setObjective(originalObjCoeff);
+                int numberColumns = newSolver->getNumCols();
+                int numFixed = 0;
+
+                // Fix the first fixThreshold number of integer vars
+                // that are satisfied
+                for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+                    if (newSolver->isInteger(iColumn)) {
+                        double value = solutions.solution[k][iColumn];
+                        double intValue = floor(value + 0.5);
+                        if (fabs(value - intValue) < 1.0e-5) {
+                            newSolver->setColLower(iColumn, intValue);
+                            newSolver->setColUpper(iColumn, intValue);
+                            numFixed++;
+                            if (numFixed > numInt - fixThreshold)
+                                break;
+                        }
+                    }
+                }
+                COIN_DETAIL_PRINT(printf("numFixed: %d\n", numFixed));
+                COIN_DETAIL_PRINT(printf("fixThreshold: %f\n", fixThreshold));
+		COIN_DETAIL_PRINT(printf("numInt: %d\n", numInt));
+                double *newSolution = new double[numCols];
+                double newSolutionValue;
+
+                // Call smallBB on the modified problem
+                int returnCode = smallBranchAndBound(newSolver, maxNode, newSolution,
+                                                     newSolutionValue, cutoff, "mini");
+
+                // If smallBB found a solution, update the better
+                // solution and solutionValue (we gave smallBB our
+                // cutoff, so it only finds improving solutions)
+                if (returnCode == 1 || returnCode == 3) {
+                    numFeasibles ++;
+                    solutionValue = newSolutionValue;
+                    for (int m = 0; m < numCols; m++)
+                        betterSolution[m] = newSolution[m];
+                    COIN_DETAIL_PRINT(printf("cutoff: %f\n", newSolutionValue));
+                    COIN_DETAIL_PRINT(printf("time: %.2lf\n", CoinCpuTime() - start));
+                }
+                didMiniBB = 1;
+                COIN_DETAIL_PRINT(printf("returnCode: %d\n", returnCode));
+
+                //Update sumReturnCode array
+                for (int iRC = 0; iRC < 6; iRC++) {
+                    if (iRC == returnCode + 1)
+                        sumReturnCode[iRC]++;
+                    else
+                        sumReturnCode[iRC] = 0;
+                }
+                if (returnCode != 0)
+                    sumReturnCode[7] = 0;
+                else
+                    sumReturnCode[7]++;
+                if (returnCode == 1 || returnCode == 3) {
+                    cutoff = newSolutionValue;
+                    clpSolver->addRow(numCols, addRowIndex, originalObjCoeff, -COIN_DBL_MAX, cutoff);
+                    COIN_DETAIL_PRINT(printf("******************\n\n*****************\n"));
+                }
+                break;
+            }
+        }
+
+        if (!didMiniBB && solutions.numberSolutions - startIndex > 0) {
+            sumReturnCode[5]++;
+            for (int iRC = 0; iRC < 5; iRC++)
+                sumReturnCode[iRC] = 0;
+        }
+
+        //Change "fixThreshold" if needed
+        // using the data we've recorded in sumReturnCode
+        if (sumReturnCode[1] >= 3)
+            fixThreshold -= fixThresholdChange;
+        if (sumReturnCode[7] >= 3 && changeMaxNode) {
+            maxNode *= 5;
+            changeMaxNode = 0;
+        }
+        if (sumReturnCode[3] >= 3 && fixThreshold < 0.95 * numInt)
+            fixThreshold += fixThresholdChange;
+        if (sumReturnCode[5] >= 4)
+            fixThreshold += fixThresholdChange;
+        if (sumReturnCode[0] > 3)
+            fixThreshold -= fixThresholdChange;
+
+        startIndex = solutions.numberSolutions;
+
+        //Check if the maximum iterations limit is reached
+        // rlh: Ask John how this is working with the change to trustedUserPtr.
+        if (solutions.numberSolutions > 20000)
+            break;
+
+        // The first time in this loop PF solves orig LP.
+
+        //Generate the random objective function
+        randNum = rand() % 10 + 1;
+        randNum = fmod(randNum, 2);
+        for (int j = 0; j < numCols; j++) {
+            if (randNum == 1)
+                if (fabs(matrix[index[i]][j]) < 1e-6)
+                    newObj[j] = 0.1;
+                else
+                    newObj[j] = matrix[index[i]][j] * 1.1;
+            else if (fabs(matrix[index[i]][j]) < 1e-6)
+                newObj[j] = -0.1;
+            else
+                newObj[j] = matrix[index[i]][j] * 0.9;
+        }
+        clpSolver->setObjective(newObj);
+        if (rowSense[i] == 'L')
+            clpSolver->setObjSense(-1);
+        else
+            // Todo #1: We don't need to solve the LPs to optimality.
+            // We just need corner points.
+            // There's a problem in stopping Clp that needs to be looked
+            // into. So for now, we solve optimality.
+            clpSolver->setObjSense(1);
+        //	  simplex->setMaximumIterations(100);
+        clpSolver->getModelPtr()->primal(1);
+        //	  simplex->setMaximumIterations(100000);
+#ifdef COIN_DETAIL
+        printf("cutoff: %f\n", cutoff);
+        printf("time: %.2f\n", CoinCpuTime() - start);
+        for (int iRC = 0; iRC < 8; iRC++)
+            printf("%d ", sumReturnCode[iRC]);
+        printf("\nfixThreshold: %f\n", fixThreshold);
+        printf("numInt: %d\n", numInt);
+        printf("\n---------------------------------------------------------------- %d\n", i);
+#endif
+
+        //temp:
+        if (i > 3) break;
+
+    }
+
+    COIN_DETAIL_PRINT(printf("Best Feasible Found: %f\n", cutoff));
+    COIN_DETAIL_PRINT(printf("Total time: %.2f\n", CoinCpuTime() - start));
+
+    if (numFeasibles == 0) {
+        return 0;
+    }
+
+
+
+    // We found something better
+    std::cout << "See you soon! You're leaving the Pivot-and-Fix Heuristic" << std::endl;
+    std::cout << std::endl;
+
+    return 1;
+#endif
+
+    return 0;
+
+}
+
+
+
+
+// update model
+void CbcHeuristicPivotAndFix::setModel(CbcModel * )
+{
+    // probably same as resetModel
+}
+
+
diff --git a/cbits/coin/CbcHeuristicPivotAndFix.hpp b/cbits/coin/CbcHeuristicPivotAndFix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicPivotAndFix.hpp
@@ -0,0 +1,58 @@
+/* $Id: CbcHeuristicPivotAndFix.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicPivotAndFix_H
+#define CbcHeuristicPivotAndFix_H
+
+#include "CbcHeuristic.hpp"
+/** LocalSearch class
+ */
+
+class CbcHeuristicPivotAndFix : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicPivotAndFix ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicPivotAndFix (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicPivotAndFix ( const CbcHeuristicPivotAndFix &);
+
+    // Destructor
+    ~CbcHeuristicPivotAndFix ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicPivotAndFix & operator=(const CbcHeuristicPivotAndFix& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        needs comments
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+
+protected:
+};
+
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicRENS.cpp b/cbits/coin/CbcHeuristicRENS.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicRENS.cpp
@@ -0,0 +1,1018 @@
+// $Id: CbcHeuristicRENS.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// edwin 12/5/09 carved out of CbcHeuristicRINS
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcHeuristicRENS.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinSort.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcStrategy.hpp"
+#include "CglPreProcess.hpp"
+
+// Default Constructor
+CbcHeuristicRENS::CbcHeuristicRENS()
+        : CbcHeuristic()
+{
+    numberTries_ = 0;
+    rensType_ = 0;
+    whereFrom_ = 256 + 1;
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicRENS::CbcHeuristicRENS(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    numberTries_ = 0;
+    rensType_ = 0;
+    whereFrom_ = 256 + 1;
+}
+
+// Destructor
+CbcHeuristicRENS::~CbcHeuristicRENS ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicRENS::clone() const
+{
+    return new CbcHeuristicRENS(*this);
+}
+
+// Assignment operator
+CbcHeuristicRENS &
+CbcHeuristicRENS::operator=( const CbcHeuristicRENS & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        numberTries_ = rhs.numberTries_;
+	rensType_ = rhs.rensType_;
+    }
+    return *this;
+}
+
+// Copy constructor
+CbcHeuristicRENS::CbcHeuristicRENS(const CbcHeuristicRENS & rhs)
+        :
+        CbcHeuristic(rhs),
+        numberTries_(rhs.numberTries_),
+	rensType_(rhs.rensType_)
+{
+}
+// Resets stuff if model changes
+void
+CbcHeuristicRENS::resetModel(CbcModel * )
+{
+}
+int
+CbcHeuristicRENS::solution(double & solutionValue,
+                           double * betterSolution)
+{
+    int returnCode = 0;
+    const double * bestSolution = model_->bestSolution();
+    if ((numberTries_&&(rensType_&16)==0) || numberTries_>1 || (when() < 2 && bestSolution))
+        return 0;
+    numberTries_++;
+    double saveFractionSmall=fractionSmall_;
+    OsiSolverInterface * solver = model_->solver();
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+
+    OsiSolverInterface * newSolver = cloneBut(3); // was model_->continuousSolver()->clone();
+    const double * currentSolution = newSolver->getColSolution();
+    int type = rensType_&15;
+    if (type<12)
+      newSolver->resolve();
+    double direction = newSolver->getObjSense();
+    double cutoff=model_->getCutoff();
+    newSolver->setDblParam(OsiDualObjectiveLimit, 1.0e100);
+    //cutoff *= direction;
+    double gap = cutoff - newSolver->getObjValue() * direction ;
+    double tolerance;
+    newSolver->getDblParam(OsiDualTolerance, tolerance) ;
+    if ((gap > 0.0 || !newSolver->isProvenOptimal())&&type<12) {
+      gap += 100.0 * tolerance;
+      int nFix = newSolver->reducedCostFix(gap);
+      if (nFix) {
+	char line [200];
+	sprintf(line, "Reduced cost fixing fixed %d variables", nFix);
+	model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+	  << line
+	  << CoinMessageEol;
+      }
+    } else if (type<12) {
+      return 0; // finished?
+    }
+    int numberColumns = solver->getNumCols();
+    double * dj = CoinCopyOfArray(solver->getReducedCost(),numberColumns);
+    double djTolerance = (type!=1) ? -1.0e30 : 1.0e-4;
+    const double * colLower = newSolver->getColLower();
+    const double * colUpper = newSolver->getColUpper();
+    double * contribution = NULL;
+    int numberFixed = 0;
+    if (type==3) {
+      double total=0.0;
+      int n=0;
+      CoinWarmStartBasis * basis =
+	dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+      if (basis&&basis->getNumArtificial()) {
+	for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	  if (colUpper[iColumn]>colLower[iColumn]&&
+	      basis->getStructStatus(iColumn) !=
+	      CoinWarmStartBasis::basic) {
+	    n++;
+	    total += fabs(dj[iColumn]);
+	  }
+	}
+	if (n)
+	  djTolerance = (0.01*total)/static_cast<double>(n);
+	delete basis;
+      }
+    } else if (type>=5&&type<=12) {
+      /* 5 fix sets at one
+	 6 fix on dj but leave unfixed SOS slacks
+	 7 fix sets at one but use pi
+	 8 fix all at zero but leave unfixed SOS slacks
+	 9 as 8 but only fix all at zero if just one in set nonzero
+	 10 fix all "stable" ones
+	 11 fix all "stable" ones - approach 2
+	 12 layered approach
+      */
+      // SOS type fixing
+      bool fixSets = (type==5)||(type==7)||(type==10)||(type==11);
+      CoinWarmStartBasis * basis =
+	dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
+      if (basis&&basis->getNumArtificial()) {
+	//const double * rowLower = solver->getRowLower();
+	const double * rowUpper = solver->getRowUpper();
+	
+	int numberRows = solver->getNumRows();
+	// Column copy
+	const CoinPackedMatrix * matrix = solver->getMatrixByCol();
+	const double * element = matrix->getElements();
+	const int * row = matrix->getIndices();
+	const CoinBigIndex * columnStart = matrix->getVectorStarts();
+	const int * columnLength = matrix->getVectorLengths();
+	double * bestDj = new double [numberRows];
+	for (int i=0;i<numberRows;i++) {
+	  if (rowUpper[i]==1.0)
+	    bestDj[i]=1.0e20;
+	  else
+	    bestDj[i]=1.0e30;
+	}
+	for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	  if (colUpper[iColumn]>colLower[iColumn]) {
+	    CoinBigIndex j;
+	    if (currentSolution[iColumn]>1.0e-6&&
+		currentSolution[iColumn]<0.999999) {
+	      for (j = columnStart[iColumn];
+		   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		int iRow = row[j];
+		if (bestDj[iRow]<1.0e30) {
+		  if (element[j] != 1.0)
+		    bestDj[iRow]=1.0e30;
+		  else
+		    bestDj[iRow]=1.0e25;
+		}
+	      }
+	    } else if ( basis->getStructStatus(iColumn) !=
+	      CoinWarmStartBasis::basic) {
+	      for (j = columnStart[iColumn];
+		   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		int iRow = row[j];
+		if (bestDj[iRow]<1.0e25) {
+		  if (element[j] != 1.0)
+		    bestDj[iRow]=1.0e30;
+		  else
+		    bestDj[iRow]=CoinMin(fabs(dj[iColumn]),bestDj[iRow]);
+		}
+	      }
+	    }
+	  }
+	}
+	// Just leave one slack in each set
+	{
+	  const double * objective = newSolver->getObjCoefficients();
+	  int * best = new int [numberRows];
+	  double * cheapest = new double[numberRows];
+	  for (int i=0;i<numberRows;i++) {
+	    best[i]=-1;
+	    cheapest[i]=COIN_DBL_MAX;
+	  }
+	  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	    if (colUpper[iColumn]>colLower[iColumn]) {
+	      if (columnLength[iColumn]==1) {
+		CoinBigIndex j = columnStart[iColumn];
+		int iRow = row[j];
+		if (bestDj[iRow]<1.0e30) {
+		  double obj = direction*objective[iColumn];
+		  if (obj<cheapest[iRow]) {
+		    cheapest[iRow]=obj;
+		    best[iRow]=iColumn;
+		  }
+		}
+	      }
+	    }
+	  }
+	  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	    if (colUpper[iColumn]>colLower[iColumn]) {
+	      if (columnLength[iColumn]==1) {
+		CoinBigIndex j = columnStart[iColumn];
+		int iRow = row[j];
+		if (bestDj[iRow]<1.0e30) {
+		  if (best[iRow]!=-1&&iColumn!=best[iRow]) {
+		    newSolver->setColUpper(iColumn,0.0);
+		  }
+		}
+	      }
+	    }
+	  }
+	  delete [] best;
+	  delete [] cheapest;
+	}
+	int nSOS=0;
+	double * sort = new double [numberRows];
+	const double * pi = newSolver->getRowPrice();
+	if (type==12) {
+	  contribution = new double [numberRows];
+	  for (int i=0;i<numberRows;i++) {
+	    if (bestDj[i]<1.0e30) 
+	      contribution[i]=0.0;
+	    else
+	      contribution[i]=-1.0;
+	  }
+	}
+	for (int i=0;i<numberRows;i++) {
+	  if (bestDj[i]<1.0e30) {
+	    if (type==5)
+	      sort[nSOS++]=bestDj[i];
+	    else if (type==7)
+	      sort[nSOS++]=-fabs(pi[i]);
+	    else
+	      sort[nSOS++]=fabs(pi[i]);
+	  }
+	}
+	if (10*nSOS>8*numberRows) {
+	  if (type<10) {
+	    std::sort(sort,sort+nSOS);
+	    int last = static_cast<int>(nSOS*0.9*fractionSmall_);
+	    double tolerance = sort[last];
+	    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	      if (colUpper[iColumn]>colLower[iColumn]) {
+		CoinBigIndex j;
+		if (currentSolution[iColumn]<=1.0e-6||
+		    currentSolution[iColumn]>=0.999999) {
+		  if (fixSets) {
+		    for (j = columnStart[iColumn];
+			 j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		      int iRow = row[j];
+		      double useDj;
+		      if (type==5) 
+			useDj = bestDj[iRow];
+		      else if (type==7)
+			useDj= -fabs(pi[iRow]);
+		      else
+			useDj= fabs(pi[iRow]);
+		      if (bestDj[iRow]<1.0e30&&useDj>=tolerance) {
+			numberFixed++;
+			if (currentSolution[iColumn]<=1.0e-6)
+			  newSolver->setColUpper(iColumn,0.0);
+			else if (currentSolution[iColumn]>=0.999999) 
+			  newSolver->setColLower(iColumn,1.0);
+		      }
+		    }
+		  } else if (columnLength[iColumn]==1) {
+		    // leave more slacks
+		    int iRow = row[columnStart[iColumn]];
+		    if (bestDj[iRow]<1.0e30) {
+		      // fake dj
+		      dj[iColumn] *= 0.000001;
+		    }
+		  } else if (type==8||type==9) {
+		    if (currentSolution[iColumn]<=1.0e-6) {
+		      if (type==8) {
+			dj[iColumn] *= 1.0e6;
+		      } else {
+			bool fix=false;
+			for (j = columnStart[iColumn];
+			     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+			  int iRow = row[j];
+			  if (bestDj[iRow]<1.0e25) {
+			    fix=true;
+			    break;
+			  }
+			}
+			if (fix) {
+			  dj[iColumn] *= 1.0e6;
+			}
+		      }
+		    } else {
+		      dj[iColumn] *= 0.000001;
+		    }
+		  }
+		}
+	      }
+	    }
+	    if (fixSets)
+	      djTolerance = 1.0e30;
+	  } else if (type==10) {
+	    double * saveUpper = new double [numberRows];
+	    memset(saveUpper,0,numberRows*sizeof(double));
+	    char * mark = new char [numberColumns];
+	    char * nonzero = new char [numberColumns];
+	    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	      if (colUpper[iColumn]>colLower[iColumn]) {
+		CoinBigIndex j;
+		for (j = columnStart[iColumn];
+		     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		  int iRow = row[j];
+		  saveUpper[iRow] += element[j];
+		}
+	      }
+	    }
+	    double sum=0.0;
+	    double sumRhs=0.0;
+	    const double * rowUpper = newSolver->getRowUpper();
+	    for (int i=0;i<numberRows;i++) {
+	      if (bestDj[i]>=1.0e30) {
+		sum += saveUpper[i];
+		sumRhs += rowUpper[i];
+	      }
+	    }
+	    double averagePerSet = sum/static_cast<double>(numberRows);
+	    // allow this extra
+	    double factor = averagePerSet*fractionSmall_*numberRows;
+	    factor = 1.0+factor/sumRhs;
+	    fractionSmall_ = 0.5;
+	    memcpy(saveUpper,rowUpper,numberRows*sizeof(double));
+	    // loosen up
+	    for (int i=0;i<numberRows;i++) {
+	      if (bestDj[i]>=1.0e30) {
+		newSolver->setRowUpper(i,factor*saveUpper[i]);
+	      }
+	    }
+	    newSolver->resolve();
+	    const double * solution = newSolver->getColSolution();
+	    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	      mark[iColumn]=0;
+	      nonzero[iColumn]=0;
+	      if (colUpper[iColumn]>colLower[iColumn]&&
+		  solution[iColumn]>0.9999)
+		mark[iColumn]=1;
+	      else if (solution[iColumn]>0.00001)
+		nonzero[iColumn]=1;
+	    }
+	    // slightly small
+	    for (int i=0;i<numberRows;i++) {
+	      if (bestDj[i]>=1.0e30) {
+		newSolver->setRowUpper(i,saveUpper[i]*0.9999);
+	      }
+	    }
+	    newSolver->resolve();
+	    int nCheck=2;
+	    if (newSolver->isProvenOptimal()) {
+	      for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+		if (colUpper[iColumn]>colLower[iColumn]&&
+		    solution[iColumn]>0.9999)
+		  mark[iColumn]++;
+		else if (solution[iColumn]>0.00001)
+		  nonzero[iColumn]=1;
+	      }
+	    } else {
+	      nCheck=1;
+	    }
+	    // correct values
+	    for (int i=0;i<numberRows;i++) {
+	      if (bestDj[i]>=1.0e30) {
+		newSolver->setRowUpper(i,saveUpper[i]);
+	      }
+	    }
+	    newSolver->resolve();
+	    int nFixed=0;
+	    int nFixedToZero=0;
+	    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	      if (colUpper[iColumn]>colLower[iColumn]) {
+		if (solution[iColumn]>0.9999&&mark[iColumn]==nCheck) {
+		  newSolver->setColLower(iColumn,1.0);
+		  nFixed++;
+		} else if (!mark[iColumn]&&!nonzero[iColumn]&&
+			   columnLength[iColumn]>1&&solution[iColumn]<0.00001) {
+		  newSolver->setColUpper(iColumn,0.0);
+		  nFixedToZero++;
+		}
+	      }
+	    }
+	    char line[100];
+	    sprintf(line,"Heuristic %s fixed %d to one (and %d to zero)",
+		    heuristicName(),
+		    nFixed,nFixedToZero);
+	    model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+	      << line
+	      << CoinMessageEol;
+	    delete [] mark;
+	    delete []nonzero;
+	    delete [] saveUpper;
+	    numberFixed=numberColumns;
+	    djTolerance = 1.0e30;
+	  } else if (type==11) {
+	    double * saveUpper = CoinCopyOfArray(newSolver->getRowUpper(),numberRows);
+	    char * mark = new char [numberColumns];
+	    char * nonzero = new char [numberColumns];
+	    // save basis and solution
+	    CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis*>(newSolver->getWarmStart()) ;
+	    assert(basis != NULL);
+	    double * saveSolution = 
+	      CoinCopyOfArray(newSolver->getColSolution(), 
+			      numberColumns);
+	    double factors[] = {1.1,1.05,1.01,0.98};
+	    int nPass = (sizeof(factors)/sizeof(double))-1;
+	    double factor=factors[0];
+	    double proportion = fractionSmall_;
+	    fractionSmall_ = 0.5;
+	    // loosen up
+	    for (int i=0;i<numberRows;i++) {
+	      if (bestDj[i]>=1.0e30) {
+		newSolver->setRowUpper(i,factor*saveUpper[i]);
+	      }
+	    }
+            bool takeHint;
+            OsiHintStrength strength;
+            newSolver->getHintParam(OsiDoDualInResolve, takeHint, strength);
+            newSolver->setHintParam(OsiDoDualInResolve, false, OsiHintDo);
+            newSolver->resolve();
+            newSolver->setHintParam(OsiDoDualInResolve, true, OsiHintDo);
+	    const double * solution = newSolver->getColSolution();
+	    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	      mark[iColumn]=0;
+	      nonzero[iColumn]=0;
+	      if (colUpper[iColumn]>colLower[iColumn]&&
+		  solution[iColumn]>0.9999)
+		mark[iColumn]=1;
+	      else if (solution[iColumn]>0.00001)
+		nonzero[iColumn]=1;
+	    }
+	    int nCheck=2;
+	    for (int iPass=0;iPass<nPass;iPass++) {
+	      // smaller
+	      factor = factors[iPass+1];
+	      for (int i=0;i<numberRows;i++) {
+		if (bestDj[i]>=1.0e30) {
+		  newSolver->setRowUpper(i,saveUpper[i]*factor);
+		}
+	      }
+	      newSolver->resolve();
+	      if (newSolver->isProvenOptimal()) {
+		nCheck++;
+		for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+		  if (colUpper[iColumn]>colLower[iColumn]&&
+		      solution[iColumn]>0.9999)
+		    mark[iColumn]++;
+		  else if (solution[iColumn]>0.00001)
+		    nonzero[iColumn]++;
+		}
+	      }
+	    }
+	    // correct values
+	    for (int i=0;i<numberRows;i++) {
+	      if (bestDj[i]>=1.0e30) {
+		newSolver->setRowUpper(i,saveUpper[i]);
+	      }
+	    }
+	    newSolver->setColSolution(saveSolution);
+	    delete [] saveSolution;
+	    newSolver->setWarmStart(basis);
+	    delete basis ;
+            newSolver->setHintParam(OsiDoDualInResolve, takeHint, strength);
+	    newSolver->resolve();
+	    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	      if (colUpper[iColumn]>colLower[iColumn]&&
+		  solution[iColumn]>0.9999)
+		mark[iColumn]++;
+	      else if (solution[iColumn]>0.00001)
+		nonzero[iColumn]++;
+	    }
+	    int nFixed=0;
+	    int numberSetsToFix = static_cast<int>(nSOS*(1.0-proportion));
+	    int * mixed = new int[numberRows];
+	    memset(mixed,0,numberRows*sizeof(int));
+	    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	      if (colUpper[iColumn]>colLower[iColumn]) {
+		int iSOS=-1;
+		for (CoinBigIndex j = columnStart[iColumn];
+		     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		  int iRow = row[j];
+		  if (bestDj[iRow]<1.0e25) {
+		    iSOS=iRow;
+		    break;
+		  }
+		}
+		if (iSOS>=0) {
+		  int numberTimesAtOne = mark[iColumn];
+		  int numberTimesNonZero = nonzero[iColumn]+
+		    numberTimesAtOne;
+		  if (numberTimesAtOne<nCheck&&
+		      numberTimesNonZero) {
+		    mixed[iSOS]+=
+		      CoinMin(numberTimesNonZero,
+			      nCheck-numberTimesNonZero);
+		  } 
+		}
+	      }
+	    }
+	    int nFix=0;
+	    for (int i=0;i<numberRows;i++) {
+	      if (bestDj[i]<1.0e25) {
+		sort[nFix] = -bestDj[i]+1.0e8*mixed[i];
+		mixed[nFix++]=i;
+	      }
+	    }
+	    CoinSort_2(sort,sort+nFix,mixed);
+	    nFix = CoinMin(nFix,numberSetsToFix);
+	    memset(sort,0,sizeof(double)*numberRows);
+	    for (int i=0;i<nFix;i++)
+	      sort[mixed[i]]=1.0;
+	    delete [] mixed;
+	    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	      if (colUpper[iColumn]>colLower[iColumn]) {
+		if (solution[iColumn]>0.9999) {
+		  int iSOS=-1;
+		  for (CoinBigIndex j = columnStart[iColumn];
+		       j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		    int iRow = row[j];
+		    if (bestDj[iRow]<1.0e25) {
+		      iSOS=iRow;
+		      break;
+		    }
+		  }
+		  if (iSOS>=0&&sort[iSOS]) {
+		    newSolver->setColLower(iColumn,1.0);
+		    nFixed++;
+		  }
+		}
+	      }
+	    }
+	    char line[100];
+	    sprintf(line,"Heuristic %s fixed %d to one (%d sets)",
+		    heuristicName(),
+		    nFixed,nSOS);
+	    model_->messageHandler()->message(CBC_FPUMP1, model_->messages())
+	      << line
+	      << CoinMessageEol;
+	    delete [] mark;
+	    delete [] nonzero;
+	    delete [] saveUpper;
+	    numberFixed=numberColumns;
+	    djTolerance = 1.0e30;
+	  }
+	}
+	delete basis;
+	delete [] sort;
+	delete [] bestDj;
+	if (10*nSOS<=8*numberRows) {
+	  // give up
+	  delete [] contribution;
+	  delete newSolver;
+	  return 0;
+	}
+      }
+    }
+    // Do dj to get right number
+    if (type==4||type==6||(type>7&&type<10)) {
+      double * sort = new double [numberColumns];
+      for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	sort[iColumn]=1.0e30;
+	if (colUpper[iColumn]>colLower[iColumn]) {
+	  sort[iColumn] = fabs(dj[iColumn]);
+	}
+      }
+      std::sort(sort,sort+numberColumns);
+      int last = static_cast<int>(numberColumns*fractionSmall_);
+      djTolerance = CoinMax(sort[last],1.0e-5);
+      delete [] sort;
+    } else if (type==12) {
+      // Do layered in a different way
+      int numberRows = solver->getNumRows();
+      // Column copy
+      const CoinPackedMatrix * matrix = newSolver->getMatrixByCol();
+      const double * element = matrix->getElements();
+      const int * row = matrix->getIndices();
+      const CoinBigIndex * columnStart = matrix->getVectorStarts();
+      const int * columnLength = matrix->getVectorLengths();
+      int * whichRow = new int[numberRows];
+      int * whichSet = new int [numberColumns];
+      int nSOS=0;
+      for (int i=0;i<numberRows;i++) {
+	whichRow[i]=0;
+	if (!contribution[i])
+	  nSOS++;
+      }
+      for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	whichSet[iColumn]=-2;
+	if (colUpper[iColumn]>colLower[iColumn]) {
+	  CoinBigIndex j;
+	  double sum=0.0;
+	  int iSOS=-1;
+	  int n=0;
+	  for (j = columnStart[iColumn];
+	       j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	    int iRow = row[j];
+	    if (contribution[iRow]>=0.0) {
+	      iSOS=iRow;
+	      n++;
+	    } else {
+	      sum += fabs(element[j]);
+	    }
+	  }
+	  if (n>1)
+	    COIN_DETAIL_PRINT(printf("Too many SOS entries (%d) for column %d\n",
+				     n,iColumn));
+	  if (sum) {
+	    assert (iSOS>=0);
+	    contribution[iSOS] += sum;
+	    whichRow[iSOS]++;
+	    whichSet[iColumn]=iSOS;
+	  } else {
+	    whichSet[iColumn]=iSOS+numberRows;
+	  }
+	}
+      }
+      int * chunk = new int [numberRows];
+      for (int i=0;i<numberRows;i++) {
+	chunk[i]=-1;
+	if (whichRow[i]) {
+	  contribution[i]= - contribution[i]/static_cast<double>(whichRow[i]);
+	} else {
+	  contribution[i] = COIN_DBL_MAX;
+	}
+	whichRow[i]=i;
+      }
+      newSolver->setDblParam(OsiDualObjectiveLimit, 1.0e100);
+      double * saveLower = CoinCopyOfArray(colLower,numberColumns);
+      double * saveUpper = CoinCopyOfArray(colUpper,numberColumns);
+      CoinSort_2(contribution,contribution+numberRows,whichRow);
+      // Set do nothing solution
+      for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	if(whichSet[iColumn]>=numberRows)
+	  newSolver->setColLower(iColumn,1.0);
+      }
+      newSolver->resolve();
+      int nChunk = (nSOS+9)/10;
+      int nPass=0;
+      int inChunk=0;
+      for (int i=0;i<nSOS;i++) {
+	chunk[whichRow[i]]=nPass;
+	inChunk++;
+	if (inChunk==nChunk) {
+	  inChunk=0;
+	  // last two together
+	  if (i+nChunk<nSOS)
+	    nPass++;
+	}
+      }
+      // adjust
+      nPass++;
+      for (int iPass=0;iPass<nPass;iPass++) {
+	// fix last chunk and unfix this chunk
+	for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+	  int iSOS = whichSet[iColumn];
+	  if (iSOS>=0) {
+	    if (iSOS>=numberRows)
+	      iSOS-=numberRows;
+	    if (chunk[iSOS]==iPass-1&&betterSolution[iColumn]>0.9999) {
+	      newSolver->setColLower(iColumn,1.0);
+	    } else if (chunk[iSOS]==iPass) {
+	      newSolver->setColLower(iColumn,saveLower[iColumn]);
+	      newSolver->setColUpper(iColumn,saveUpper[iColumn]);
+	    }
+	  }
+	}
+	// solve
+        returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+                                         model_->getCutoff(), "CbcHeuristicRENS");
+        if (returnCode < 0) {
+            returnCode = 0; // returned on size
+	    break;
+	} else if ((returnCode&1)==0) {
+	  // no good
+	  break;
+	}
+      }
+      if ((returnCode&2) != 0) {
+	// could add cut
+	returnCode &= ~2;
+      }
+      delete [] chunk;
+      delete [] saveLower;
+      delete [] saveUpper;
+      delete [] whichRow;
+      delete [] whichSet;
+      delete [] contribution;
+      delete newSolver;
+      return returnCode;
+    }
+    
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    int i;
+    int numberTightened = 0;
+    int numberAtBound = 0;
+    int numberContinuous = numberColumns - numberIntegers;
+
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = currentSolution[iColumn];
+        double lower = colLower[iColumn];
+        double upper = colUpper[iColumn];
+        value = CoinMax(value, lower);
+        value = CoinMin(value, upper);
+	double djValue=dj[iColumn]*direction;
+#define RENS_FIX_ONLY_LOWER
+#ifndef RENS_FIX_ONLY_LOWER
+        if (fabs(value - floor(value + 0.5)) < 1.0e-8) {
+            value = floor(value + 0.5);
+            if (value == lower || value == upper)
+                numberAtBound++;
+            newSolver->setColLower(iColumn, value);
+            newSolver->setColUpper(iColumn, value);
+            numberFixed++;
+        } else if (colUpper[iColumn] - colLower[iColumn] >= 2.0) {
+            numberTightened++;
+            newSolver->setColLower(iColumn, floor(value));
+            newSolver->setColUpper(iColumn, ceil(value));
+        }
+#else
+        if (fabs(value - floor(value + 0.5)) < 1.0e-8 &&
+                floor(value + 0.5) == lower &&
+	    djValue > djTolerance ) {
+	  value = floor(value + 0.5);
+	  numberAtBound++;
+	  newSolver->setColLower(iColumn, value);
+	  newSolver->setColUpper(iColumn, value);
+	  numberFixed++;
+        } else if (fabs(value - floor(value + 0.5)) < 1.0e-8 &&
+                floor(value + 0.5) == upper &&
+		   -djValue > djTolerance && (djTolerance > 0.0||type==2)) {
+	  value = floor(value + 0.5);
+	  numberAtBound++;
+	  newSolver->setColLower(iColumn, value);
+	  newSolver->setColUpper(iColumn, value);
+	  numberFixed++;
+        } else if (colUpper[iColumn] - colLower[iColumn] >= 2.0 &&
+		   djTolerance <0.0) {
+            numberTightened++;
+            if (fabs(value - floor(value + 0.5)) < 1.0e-8) {
+                value = floor(value + 0.5);
+                if (value < upper) {
+                    newSolver->setColLower(iColumn, CoinMax(value - 1.0, lower));
+                    newSolver->setColUpper(iColumn, CoinMin(value + 1.0, upper));
+                } else {
+                    newSolver->setColLower(iColumn, upper - 1.0);
+                }
+            } else {
+                newSolver->setColLower(iColumn, floor(value));
+                newSolver->setColUpper(iColumn, ceil(value));
+            }
+        }
+#endif
+    }
+    delete [] dj;
+    if (numberFixed > numberIntegers / 5) {
+        if ( numberFixed < numberColumns / 5) {
+#define RENS_FIX_CONTINUOUS
+#ifdef RENS_FIX_CONTINUOUS
+            const double * colLower = newSolver->getColLower();
+            //const double * colUpper = newSolver->getColUpper();
+            int nAtLb = 0;
+            double sumDj = 0.0;
+            const double * dj = newSolver->getReducedCost();
+            for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (!newSolver->isInteger(iColumn)) {
+                    double value = currentSolution[iColumn];
+                    if (value < colLower[iColumn] + 1.0e-8) {
+                        double djValue = dj[iColumn] * direction;
+                        nAtLb++;
+                        sumDj += djValue;
+                    }
+                }
+            }
+            if (nAtLb) {
+                // fix some continuous
+                double * sort = new double[nAtLb];
+                int * which = new int [nAtLb];
+                double threshold = CoinMax((0.01 * sumDj) / static_cast<double>(nAtLb), 1.0e-6);
+                int nFix2 = 0;
+                for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (!newSolver->isInteger(iColumn)) {
+                        double value = currentSolution[iColumn];
+                        if (value < colLower[iColumn] + 1.0e-8) {
+                            double djValue = dj[iColumn] * direction;
+                            if (djValue > threshold) {
+                                sort[nFix2] = -djValue;
+                                which[nFix2++] = iColumn;
+                            }
+                        }
+                    }
+                }
+                CoinSort_2(sort, sort + nFix2, which);
+                nFix2 = CoinMin(nFix2, (numberColumns - numberFixed) / 2);
+                for (int i = 0; i < nFix2; i++) {
+                    int iColumn = which[i];
+                    newSolver->setColUpper(iColumn, colLower[iColumn]);
+                }
+                delete [] sort;
+                delete [] which;
+#ifdef CLP_INVESTIGATE2
+                printf("%d integers fixed (%d tightened) (%d at bound), and %d continuous fixed at lb\n",
+                       numberFixed, numberTightened, numberAtBound, nFix2);
+#endif
+            }
+#endif
+        }
+#ifdef COIN_DEVELOP
+        printf("%d integers fixed and %d tightened\n", numberFixed, numberTightened);
+#endif
+        returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+                                         model_->getCutoff(), "CbcHeuristicRENS");
+        if (returnCode < 0 || returnCode == 0) {
+#ifdef RENS_FIX_CONTINUOUS
+            if (numberContinuous > numberIntegers && numberFixed >= numberColumns / 5) {
+                const double * colLower = newSolver->getColLower();
+                //const double * colUpper = newSolver->getColUpper();
+                int nAtLb = 0;
+                double sumDj = 0.0;
+                const double * dj = newSolver->getReducedCost();
+                double direction = newSolver->getObjSense();
+                for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (!newSolver->isInteger(iColumn)) {
+                        double value = currentSolution[iColumn];
+                        if (value < colLower[iColumn] + 1.0e-8) {
+                            double djValue = dj[iColumn] * direction;
+                            nAtLb++;
+                            sumDj += djValue;
+                        }
+                    }
+                }
+                if (nAtLb) {
+                    // fix some continuous
+                    double * sort = new double[nAtLb];
+                    int * which = new int [nAtLb];
+                    double threshold = CoinMax((0.01 * sumDj) / static_cast<double>(nAtLb), 1.0e-6);
+                    int nFix2 = 0;
+                    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        if (!newSolver->isInteger(iColumn)) {
+                            double value = currentSolution[iColumn];
+                            if (value < colLower[iColumn] + 1.0e-8) {
+                                double djValue = dj[iColumn] * direction;
+                                if (djValue > threshold) {
+                                    sort[nFix2] = -djValue;
+                                    which[nFix2++] = iColumn;
+                                }
+                            }
+                        }
+                    }
+                    CoinSort_2(sort, sort + nFix2, which);
+                    nFix2 = CoinMin(nFix2, (numberColumns - numberFixed) / 2);
+                    for (int i = 0; i < nFix2; i++) {
+                        int iColumn = which[i];
+                        newSolver->setColUpper(iColumn, colLower[iColumn]);
+                    }
+                    delete [] sort;
+                    delete [] which;
+#ifdef CLP_INVESTIGATE2
+                    printf("%d integers fixed (%d tightened) (%d at bound), and %d continuous fixed at lb\n",
+                           numberFixed, numberTightened, numberAtBound, nFix2);
+#endif
+                }
+                returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+                                                 model_->getCutoff(), "CbcHeuristicRENS");
+	    }
+#endif
+	    if (returnCode < 0 || returnCode == 0) {
+		// Do passes fixing up those >0.9 and
+		// down those < 0.05
+#define RENS_PASS 3
+	      //#define KEEP_GOING
+#ifdef KEEP_GOING
+ 	        double * saveLower = CoinCopyOfArray(colLower,numberColumns);
+	        double * saveUpper = CoinCopyOfArray(colUpper,numberColumns);
+		bool badPass=false;
+		int nSolved=0;
+#endif
+		for (int iPass=0;iPass<RENS_PASS;iPass++) {
+		  int nFixed=0;
+		  int nFixedAlready=0;
+		  int nFixedContinuous=0;
+		  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+		    if (colUpper[iColumn]>colLower[iColumn]) {
+		      if (newSolver->isInteger(iColumn)) {
+			double value = currentSolution[iColumn];
+			double fixTo = floor(value+0.1);
+			if (fixTo>value || value-fixTo < 0.05) {
+			  // above 0.9 or below 0.05
+			  nFixed++;
+			  newSolver->setColLower(iColumn, fixTo);
+			  newSolver->setColUpper(iColumn, fixTo);
+			}
+		      }
+		    } else if (newSolver->isInteger(iColumn)) {
+		      nFixedAlready++;
+		    } else {
+		      nFixedContinuous++;
+		    }
+		  }
+#ifdef CLP_INVESTIGATE2
+		  printf("%d more integers fixed (total %d) plus %d continuous\n",
+			 nFixed,nFixed+nFixedAlready,nFixedContinuous);
+#endif
+#ifdef KEEP_GOING
+		  if (nFixed) {
+		    newSolver->resolve();
+		    if (!newSolver->isProvenOptimal()) {
+		      badPass=true;
+		      break;
+		    } else {
+		      nSolved++;
+		      memcpy(saveLower,colLower,numberColumns*sizeof(double));
+		      memcpy(saveUpper,colUpper,numberColumns*sizeof(double));
+		    }
+		  } else {
+		    break;
+		  }
+#else
+		  if (nFixed) {
+		    newSolver->resolve();
+		    if (!newSolver->isProvenOptimal()) {
+		      returnCode=0;
+		      break;
+		    }
+		    returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+						     model_->getCutoff(), "CbcHeuristicRENS");
+		  } else {
+		    returnCode=0;
+		  }
+		  if (returnCode>=0)
+		    break;
+		}
+		if (returnCode < 0) 
+                returnCode = 0; // returned on size
+#endif
+	    }
+#ifdef KEEP_GOING
+	    if (badPass) {
+	      newSolver->setColLower(saveLower);
+	      newSolver->setColUpper(saveUpper);
+	      newSolver->resolve();
+	    }
+	    delete [] saveLower;
+	    delete [] saveUpper;
+	    if (nSolved)
+	      returnCode = 
+		smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+				    model_->getCutoff(), "CbcHeuristicRENS");
+	    else
+	      returnCode=0;
+	}
+#endif
+        }
+        //printf("return code %d",returnCode);
+        if ((returnCode&2) != 0) {
+            // could add cut
+            returnCode &= ~2;
+#ifdef COIN_DEVELOP
+            if (!numberTightened && numberFixed == numberAtBound)
+                printf("could add cut with %d elements\n", numberFixed);
+#endif
+        } else {
+            //printf("\n");
+        }
+    }
+    //delete [] whichRow;
+    //delete [] contribution;
+    delete newSolver;
+    fractionSmall_ = saveFractionSmall;
+    return returnCode;
+}
+// update model
+void CbcHeuristicRENS::setModel(CbcModel * model)
+{
+    model_ = model;
+}
+
diff --git a/cbits/coin/CbcHeuristicRENS.hpp b/cbits/coin/CbcHeuristicRENS.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicRENS.hpp
@@ -0,0 +1,74 @@
+// $Id: CbcHeuristicRENS.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// edwin 12/5/09 carved out of CbcHeuristicRINS
+
+#ifndef CbcHeuristicRENS_H
+#define CbcHeuristicRENS_H
+
+#include "CbcHeuristic.hpp"
+
+/** LocalSearch class
+ */
+
+class CbcHeuristicRENS : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicRENS ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicRENS (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicRENS ( const CbcHeuristicRENS &);
+
+    // Destructor
+    ~CbcHeuristicRENS ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+
+    /// Assignment operator
+    CbcHeuristicRENS & operator=(const CbcHeuristicRENS& rhs);
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        This does Relaxation Extension Neighborhood Search
+        Does not run if when_<2 and a solution exists
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+
+    /// Set type
+    inline void setRensType(int value)
+    { rensType_ = value;}
+
+protected:
+    // Data
+    /// Number of tries
+    int numberTries_;
+    /** Type
+        0 - fix at LB
+        1 - fix on dj
+        2 - fix at UB as well
+	3 - fix on 0.01*average dj
+	add 16 to allow two tries
+    */
+    int rensType_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicRINS.cpp b/cbits/coin/CbcHeuristicRINS.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicRINS.cpp
@@ -0,0 +1,375 @@
+/* $Id: CbcHeuristicRINS.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcHeuristicRINS.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcStrategy.hpp"
+#include "CglPreProcess.hpp"
+
+// Default Constructor
+CbcHeuristicRINS::CbcHeuristicRINS()
+        : CbcHeuristic()
+{
+    numberSolutions_ = 0;
+    numberSuccesses_ = 0;
+    numberTries_ = 0;
+    stateOfFixing_ = 0;
+    shallowDepth_ = 0;
+    lastNode_ = -999999;
+    howOften_ = 100;
+    decayFactor_ = 0.5;
+    used_ = NULL;
+    whereFrom_ = 1 + 8 + 16 + 255 * 256;
+    whereFrom_ = 1 + 8 + 255 * 256;
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicRINS::CbcHeuristicRINS(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    numberSolutions_ = 0;
+    numberSuccesses_ = 0;
+    numberTries_ = 0;
+    stateOfFixing_ = 0;
+    shallowDepth_ = 0;
+    lastNode_ = -999999;
+    howOften_ = 100;
+    decayFactor_ = 0.5;
+    assert(model.solver());
+    int numberColumns = model.solver()->getNumCols();
+    used_ = new char[numberColumns];
+    memset(used_, 0, numberColumns);
+    whereFrom_ = 1 + 8 + 16 + 255 * 256;
+    whereFrom_ = 1 + 8 + 255 * 256;
+}
+
+// Destructor
+CbcHeuristicRINS::~CbcHeuristicRINS ()
+{
+    delete [] used_;
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicRINS::clone() const
+{
+    return new CbcHeuristicRINS(*this);
+}
+
+// Assignment operator
+CbcHeuristicRINS &
+CbcHeuristicRINS::operator=( const CbcHeuristicRINS & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        numberSolutions_ = rhs.numberSolutions_;
+        howOften_ = rhs.howOften_;
+        numberSuccesses_ = rhs.numberSuccesses_;
+        numberTries_ = rhs.numberTries_;
+        stateOfFixing_ = rhs.stateOfFixing_;
+        lastNode_ = rhs.lastNode_;
+        delete [] used_;
+        if (model_ && rhs.used_) {
+            int numberColumns = model_->solver()->getNumCols();
+            used_ = new char[numberColumns];
+            memcpy(used_, rhs.used_, numberColumns);
+        } else {
+            used_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicRINS::generateCpp( FILE * fp)
+{
+    CbcHeuristicRINS other;
+    fprintf(fp, "0#include \"CbcHeuristicRINS.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicRINS heuristicRINS(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicRINS");
+    if (howOften_ != other.howOften_)
+        fprintf(fp, "3  heuristicRINS.setHowOften(%d);\n", howOften_);
+    else
+        fprintf(fp, "4  heuristicRINS.setHowOften(%d);\n", howOften_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicRINS);\n");
+}
+
+// Copy constructor
+CbcHeuristicRINS::CbcHeuristicRINS(const CbcHeuristicRINS & rhs)
+        :
+        CbcHeuristic(rhs),
+        numberSolutions_(rhs.numberSolutions_),
+        howOften_(rhs.howOften_),
+        numberSuccesses_(rhs.numberSuccesses_),
+        numberTries_(rhs.numberTries_),
+        stateOfFixing_(rhs.stateOfFixing_),
+        lastNode_(rhs.lastNode_)
+{
+    if (model_ && rhs.used_) {
+        int numberColumns = model_->solver()->getNumCols();
+        used_ = new char[numberColumns];
+        memcpy(used_, rhs.used_, numberColumns);
+    } else {
+        used_ = NULL;
+    }
+}
+// Resets stuff if model changes
+void
+CbcHeuristicRINS::resetModel(CbcModel * /*model*/)
+{
+    //CbcHeuristic::resetModel(model);
+    delete [] used_;
+    stateOfFixing_ = 0;
+    if (model_ && used_) {
+        int numberColumns = model_->solver()->getNumCols();
+        used_ = new char[numberColumns];
+        memset(used_, 0, numberColumns);
+    } else {
+        used_ = NULL;
+    }
+}
+/*
+  First tries setting a variable to better value.  If feasible then
+  tries setting others.  If not feasible then tries swaps
+  Returns 1 if solution, 0 if not */
+int
+CbcHeuristicRINS::solution(double & solutionValue,
+                           double * betterSolution)
+{
+    numCouldRun_++;
+    int returnCode = 0;
+    const double * bestSolution = model_->bestSolution();
+    if (!bestSolution)
+        return 0; // No solution found yet
+    if (numberSolutions_ < model_->getSolutionCount()) {
+        // new solution - add info
+        numberSolutions_ = model_->getSolutionCount();
+
+        int numberIntegers = model_->numberIntegers();
+        const int * integerVariable = model_->integerVariable();
+
+        int i;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            const OsiObject * object = model_->object(i);
+            // get original bounds
+            double originalLower;
+            double originalUpper;
+            getIntegerInformation( object, originalLower, originalUpper);
+            double value = bestSolution[iColumn];
+            if (value < originalLower) {
+                value = originalLower;
+            } else if (value > originalUpper) {
+                value = originalUpper;
+            }
+            double nearest = floor(value + 0.5);
+            // if away from lower bound mark that fact
+            if (nearest > originalLower) {
+                used_[iColumn] = 1;
+            }
+        }
+    }
+    int numberNodes = model_->getNodeCount();
+    if (howOften_ == 100) {
+        if (numberNodes < lastNode_ + 12)
+            return 0;
+        // Do at 50 and 100
+        if ((numberNodes > 40 && numberNodes <= 50) || (numberNodes > 90 && numberNodes < 100))
+            numberNodes = howOften_;
+    }
+    // Allow for infeasible nodes - so do anyway after a bit
+    if (howOften_ >= 100 && numberNodes >= lastNode_ + 2*howOften_) {
+        numberNodes = howOften_;
+    }
+    if ((numberNodes % howOften_) == 0 && (model_->getCurrentPassNumber() == 1 ||
+                                           model_->getCurrentPassNumber() == 999999)) {
+        lastNode_ = model_->getNodeCount();
+        OsiSolverInterface * solver = model_->solver();
+
+        int numberIntegers = model_->numberIntegers();
+        const int * integerVariable = model_->integerVariable();
+
+        const double * currentSolution = solver->getColSolution();
+	const int * used = model_->usedInSolution();
+        OsiSolverInterface * newSolver = cloneBut(3); // was model_->continuousSolver()->clone();
+        int numberColumns = newSolver->getNumCols();
+        int numberContinuous = numberColumns - numberIntegers;
+
+        double primalTolerance;
+        solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+        int i;
+        int nFix = 0;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            const OsiObject * object = model_->object(i);
+            // get original bounds
+            double originalLower;
+            double originalUpper;
+            getIntegerInformation( object, originalLower, originalUpper);
+            double valueInt = bestSolution[iColumn];
+            if (valueInt < originalLower) {
+                valueInt = originalLower;
+            } else if (valueInt > originalUpper) {
+                valueInt = originalUpper;
+            }
+            if (fabs(currentSolution[iColumn] - valueInt) < 10.0*primalTolerance) {
+                double nearest = floor(valueInt + 0.5);
+		/*
+		  shallowDepth_
+		  0 - normal
+		  1 - only fix if at lb
+		  2 - only fix if not at lb
+		  3 - only fix if at lb and !used
+		*/
+		bool fix=false;
+		switch (shallowDepth_) {
+		case 0:
+		  fix = true;
+		  break;
+		case 1:
+		if (nearest==originalLower) 
+		  fix = true;
+		  break;
+		case 2:
+		if (nearest!=originalLower) 
+		  fix = true;
+		  break;
+		case 3:
+		if (nearest==originalLower && !used[iColumn]) 
+		  fix = true;
+		  break;
+		}
+		if (fix) {
+		  newSolver->setColLower(iColumn, nearest);
+		  newSolver->setColUpper(iColumn, nearest);
+		  nFix++;
+		}
+            }
+        }
+        int divisor = 0;
+        if (5*nFix > numberIntegers) {
+            if (numberContinuous > 2*numberIntegers && ((nFix*10 < numberColumns &&
+                    !numRuns_ && numberTries_ > 2) ||
+                    stateOfFixing_)) {
+#define RINS_FIX_CONTINUOUS
+#ifdef RINS_FIX_CONTINUOUS
+                const double * colLower = newSolver->getColLower();
+                //const double * colUpper = newSolver->getColUpper();
+                int nAtLb = 0;
+                //double sumDj=0.0;
+                const double * dj = newSolver->getReducedCost();
+                double direction = newSolver->getObjSense();
+                for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (!newSolver->isInteger(iColumn)) {
+                        double value = bestSolution[iColumn];
+                        if (value < colLower[iColumn] + 1.0e-8) {
+                            //double djValue = dj[iColumn]*direction;
+                            nAtLb++;
+                            //sumDj += djValue;
+                        }
+                    }
+                }
+                if (nAtLb) {
+                    // fix some continuous
+                    double * sort = new double[nAtLb];
+                    int * which = new int [nAtLb];
+                    //double threshold = CoinMax((0.01*sumDj)/static_cast<double>(nAtLb),1.0e-6);
+                    int nFix2 = 0;
+                    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        if (!newSolver->isInteger(iColumn)) {
+                            double value = bestSolution[iColumn];
+                            if (value < colLower[iColumn] + 1.0e-8) {
+                                double djValue = dj[iColumn] * direction;
+                                if (djValue > 1.0e-6) {
+                                    sort[nFix2] = -djValue;
+                                    which[nFix2++] = iColumn;
+                                }
+                            }
+                        }
+                    }
+                    CoinSort_2(sort, sort + nFix2, which);
+                    divisor = 4;
+                    if (stateOfFixing_ > 0)
+                        divisor = stateOfFixing_;
+                    else if (stateOfFixing_ < -1)
+                        divisor = (-stateOfFixing_) - 1;
+                    nFix2 = CoinMin(nFix2, (numberColumns - nFix) / divisor);
+                    for (int i = 0; i < nFix2; i++) {
+                        int iColumn = which[i];
+                        newSolver->setColUpper(iColumn, colLower[iColumn]);
+                    }
+                    delete [] sort;
+                    delete [] which;
+#ifdef CLP_INVESTIGATE2
+                    printf("%d integers have same value, and %d continuous fixed at lb\n",
+                           nFix, nFix2);
+#endif
+                }
+#endif
+            }
+            //printf("%d integers have same value\n",nFix);
+            returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+                                             model_->getCutoff(), "CbcHeuristicRINS");
+            if (returnCode < 0) {
+                returnCode = 0; // returned on size
+                if (divisor) {
+                    stateOfFixing_ = - divisor; // say failed
+                } else if (numberContinuous > 2*numberIntegers &&
+                           !numRuns_ && numberTries_ > 2) {
+                    stateOfFixing_ = -4; //start fixing
+                }
+            } else {
+                numRuns_++;
+                if (divisor)
+                    stateOfFixing_ =  divisor; // say small enough
+            }
+            if ((returnCode&1) != 0)
+                numberSuccesses_++;
+            //printf("return code %d",returnCode);
+            if ((returnCode&2) != 0) {
+                // could add cut
+                returnCode &= ~2;
+                //printf("could add cut with %d elements (if all 0-1)\n",nFix);
+            } else {
+                //printf("\n");
+            }
+        }
+
+        numberTries_++;
+        if ((numberTries_ % 10) == 0 && numberSuccesses_*3 < numberTries_)
+            howOften_ += static_cast<int> (howOften_ * decayFactor_);
+        delete newSolver;
+    }
+    return returnCode;
+}
+// update model
+void CbcHeuristicRINS::setModel(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix
+    assert(model_->solver());
+    delete [] used_;
+    int numberColumns = model->solver()->getNumCols();
+    used_ = new char[numberColumns];
+    memset(used_, 0, numberColumns);
+}
+
+
+
diff --git a/cbits/coin/CbcHeuristicRINS.hpp b/cbits/coin/CbcHeuristicRINS.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicRINS.hpp
@@ -0,0 +1,98 @@
+/* $Id: CbcHeuristicRINS.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicRINS_H
+#define CbcHeuristicRINS_H
+
+#include "CbcHeuristic.hpp"
+// for backward compatibility include 3 other headers
+#include "CbcHeuristicRENS.hpp"
+#include "CbcHeuristicDINS.hpp"
+#include "CbcHeuristicVND.hpp"
+/** LocalSearch class
+ */
+
+class CbcHeuristicRINS : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicRINS ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicRINS (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicRINS ( const CbcHeuristicRINS &);
+
+    // Destructor
+    ~CbcHeuristicRINS ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+
+    /// Assignment operator
+    CbcHeuristicRINS & operator=(const CbcHeuristicRINS& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        This does Relaxation Induced Neighborhood Search
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// This version fixes stuff and does IP
+    int solutionFix(double & objectiveValue,
+                    double * newSolution,
+                    const int * keep);
+
+    /// Sets how often to do it
+    inline void setHowOften(int value) {
+        howOften_ = value;
+    }
+    /// Used array so we can set
+    inline char * used() const {
+        return used_;
+    }
+    /// Resets lastNode
+    inline void setLastNode(int value) {
+        lastNode_ = value;
+    }
+
+protected:
+    // Data
+
+    /// Number of solutions so we can do something at solution
+    int numberSolutions_;
+    /// How often to do (code can change)
+    int howOften_;
+    /// Number of successes
+    int numberSuccesses_;
+    /// Number of tries
+    int numberTries_;
+    /** State of fixing continuous variables -
+        0 - not tried
+        +n - this divisor makes small enough
+        -n - this divisor still not small enough
+    */
+    int stateOfFixing_;
+    /// Node when last done
+    int lastNode_;
+    /// Whether a variable has been in a solution
+    char * used_;
+};
+#endif
+
diff --git a/cbits/coin/CbcHeuristicRandRound.cpp b/cbits/coin/CbcHeuristicRandRound.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicRandRound.cpp
@@ -0,0 +1,518 @@
+/* $Id: CbcHeuristicRandRound.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+#include <vector>
+
+#include "CoinHelperFunctions.hpp"
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcHeuristicRandRound.hpp"
+#include "OsiClpSolverInterface.hpp"
+#include  "CoinTime.hpp"
+
+static inline int intRand(const int range)
+{
+    return static_cast<int> (floor(CoinDrand48() * range));
+}
+
+// Default Constructor
+CbcHeuristicRandRound::CbcHeuristicRandRound()
+        : CbcHeuristic()
+{
+}
+
+// Constructor with model - assumed before cuts
+CbcHeuristicRandRound::CbcHeuristicRandRound(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    model_ = &model;
+    setWhen(1);
+}
+
+// Destructor
+CbcHeuristicRandRound::~CbcHeuristicRandRound ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicRandRound::clone() const
+{
+    return new CbcHeuristicRandRound(*this);
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicRandRound::generateCpp( FILE * fp)
+{
+    CbcHeuristicRandRound other;
+    fprintf(fp, "0#include \"CbcHeuristicRandRound.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicRandRound heuristicPFX(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicPFX");
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicPFX);\n");
+}
+
+// Copy constructor
+CbcHeuristicRandRound::CbcHeuristicRandRound(const CbcHeuristicRandRound & rhs)
+        :
+        CbcHeuristic(rhs)
+{
+}
+
+// Assignment operator
+CbcHeuristicRandRound &
+CbcHeuristicRandRound::operator=( const CbcHeuristicRandRound & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+    }
+    return *this;
+}
+
+// Resets stuff if model changes
+void
+CbcHeuristicRandRound::resetModel(CbcModel * model)
+{
+    CbcHeuristic::resetModel(model);
+}
+
+/*
+  Randomized Rounding Heuristic
+  Returns 1 if solution, 0 if not
+*/
+int
+CbcHeuristicRandRound::solution(double & solutionValue,
+                                double * betterSolution)
+{
+    // rlh: Todo: Memory Cleanup
+
+    //  std::cout << "Entering the Randomized Rounding Heuristic" << std::endl;
+
+    setWhen(1);  // setWhen(1) didn't have the effect I expected (e.g., run once).
+
+    // Run only once.
+    //
+    //    See if at root node
+    bool atRoot = model_->getNodeCount() == 0;
+    int passNumber = model_->getCurrentPassNumber();
+    //    Just do once
+    if (!atRoot || passNumber != 1) {
+        // std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl;
+        return 0;
+    }
+
+    std::cout << "Entering the Randomized Rounding Heuristic" << std::endl;
+    typedef struct {
+        int numberSolutions;
+        int maximumSolutions;
+        int numberColumns;
+        double ** solution;
+        int * numberUnsatisfied;
+    } clpSolution;
+
+    double start = CoinCpuTime();
+    numCouldRun_++; //
+    // Todo: Ask JJHF what "number of times
+    // the heuristic could run" means.
+
+    OsiSolverInterface * solver = model_->solver()->clone();
+    double primalTolerance ;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance) ;
+    OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver);
+    assert (clpSolver);
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+
+    // Initialize the structure holding the solutions for the Simplex iterations
+    clpSolution solutions;
+    // Set typeStruct field of ClpTrustedData struct to 1 to indicate
+    // desired behavior for  RandRound heuristic (which is what?)
+    ClpTrustedData trustedSolutions;
+    trustedSolutions.typeStruct = 1;
+    trustedSolutions.data = &solutions;
+    solutions.numberSolutions = 0;
+    solutions.maximumSolutions = 0;
+    solutions.numberColumns = simplex->numberColumns();
+    solutions.solution = NULL;
+    solutions.numberUnsatisfied = NULL;
+    simplex->setTrustedUserPointer(&trustedSolutions);
+
+    // Solve from all slack to get some points
+    simplex->allSlackBasis();
+
+    // Calling primal() invalidates pointers to some rim vectors,
+    // like...row sense (!)
+    simplex->primal();
+
+    // 1. Okay - so a workaround would be to copy the data I want BEFORE
+    // calling primal.
+    // 2. Another approach is to ask the simplex solvers NOT to mess up my
+    // rims.
+    // 3. See freeCachedResults() for what is getting
+    // deleted. Everything else points into the structure.
+    // ...or use collower and colupper rather than rowsense.
+    // ..store address of where one of these
+
+    // Store the basic problem information
+    // -Get the number of columns, rows and rhs vector
+    int numCols = clpSolver->getNumCols();
+    int numRows = clpSolver->getNumRows();
+
+    // Find the integer variables (use columnType(?))
+    // One if not continuous, that is binary or general integer)
+    // columnType() = 0 continuous
+    //              = 1 binary
+    //              = 2 general integer
+    bool * varClassInt = new bool[numCols];
+    const char* columnType = clpSolver->columnType();
+    int numGenInt = 0;
+    for (int i = 0; i < numCols; i++) {
+        if (clpSolver->isContinuous(i))
+            varClassInt[i] = 0;
+        else
+            varClassInt[i] = 1;
+        if (columnType[i] == 2) numGenInt++;
+    }
+
+    // Heuristic is for problems with general integer variables.
+    // If there are none, quit.
+    if (numGenInt++ < 1) {
+        delete [] varClassInt ;
+        std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl;
+        return 0;
+    }
+
+
+    // -Get the rows sense
+    const char * rowSense;
+    rowSense = clpSolver->getRowSense();
+
+    // -Get the objective coefficients
+    double *originalObjCoeff = CoinCopyOfArray(clpSolver->getObjCoefficients(), numCols);
+
+    // -Get the matrix of the problem
+    // rlh: look at using sparse representation
+    double ** matrix = new double * [numRows];
+    for (int i = 0; i < numRows; i++) {
+        matrix[i] = new double[numCols];
+        for (int j = 0; j < numCols; j++)
+            matrix[i][j] = 0;
+    }
+
+    const CoinPackedMatrix* matrixByRow = clpSolver->getMatrixByRow();
+    const double * matrixElements = matrixByRow->getElements();
+    const int * matrixIndices = matrixByRow->getIndices();
+    const int * matrixStarts = matrixByRow->getVectorStarts();
+    for (int j = 0; j < numRows; j++) {
+        for (int i = matrixStarts[j]; i < matrixStarts[j+1]; i++) {
+            matrix[j][matrixIndices[i]] = matrixElements[i];
+        }
+    }
+
+    double * newObj = new double [numCols];
+    srand ( static_cast<unsigned int>(time(NULL) + 1));
+    int randNum;
+
+    // Shuffle the rows:
+    // Put the rows in a random order
+    // so that the optimal solution is a different corner point than the
+    // starting point.
+    int * index = new int [numRows];
+    for (int i = 0; i < numRows; i++)
+        index[i] = i;
+    for (int i = 0; i < numRows; i++) {
+        int temp = index[i];
+        int randNumTemp = i + intRand(numRows - i);
+        index[i] = index[randNumTemp];
+        index[randNumTemp] = temp;
+    }
+
+    // Start finding corner points by iteratively doing the following:
+    // - contruct a randomly tilted objective
+    // - solve
+    for (int i = 0; i < numRows; i++) {
+        // TODO: that 10,000 could be a param in the member data
+        if (solutions.numberSolutions  > 10000)
+            break;
+        randNum = intRand(2);
+        for (int j = 0; j < numCols; j++) {
+            // for row i and column j vary the coefficient "a bit"
+            if (randNum == 1)
+                // if the element is zero, then set the new obj
+                // coefficient to 0.1 (i.e., round up)
+                if (fabs(matrix[index[i]][j]) < primalTolerance)
+                    newObj[j] = 0.1;
+                else
+                    // if the element is nonzero, then increase the new obj
+                    // coefficient "a bit"
+                    newObj[j] = matrix[index[i]][j] * 1.1;
+            else
+                // if randnum is 2, then
+                // if the element is zero, then set the new obj coeffient
+                // to NEGATIVE 0.1 (i.e., round down)
+                if (fabs(matrix[index[i]][j]) < primalTolerance)
+                    newObj[j] = -0.1;
+                else
+                    // if the element is nonzero, then DEcrease the new obj coeffienct "a bit"
+                    newObj[j] = matrix[index[i]][j] * 0.9;
+        }
+        // Use the new "tilted" objective
+        clpSolver->setObjective(newObj);
+
+        // Based on the row sense, we decide whether to max or min
+        if (rowSense[i] == 'L')
+            clpSolver->setObjSense(-1);
+        else
+            clpSolver->setObjSense(1);
+
+        // Solve with primal simplex
+        simplex->primal(1);
+        // rlh+ll: This was the original code. But we already have the
+        // model pointer (it's in simplex). And, calling getModelPtr()
+        // invalidates the cached data in the OsiClpSolverInterface
+        // object, which means our precious rowsens is lost. So let's
+        // not use the line below...
+        /******* clpSolver->getModelPtr()->primal(1); */
+        printf("---------------------------------------------------------------- %d\n", i);
+    }
+    // Iteratively do this process until...
+    // either you reach the max number of corner points (aka 10K)
+    // or all the rows have been used as an objective.
+
+    // Look at solutions
+    int numberSolutions = solutions.numberSolutions;
+    //const char * integerInfo = simplex->integerInformation();
+    //const double * columnLower = simplex->columnLower();
+    //const double * columnUpper = simplex->columnUpper();
+    printf("there are %d solutions\n", numberSolutions);
+
+    // Up to here we have all the corner points
+    // Now we need to do the random walks and roundings
+
+    double ** cornerPoints = new double * [numberSolutions];
+    for (int j = 0; j < numberSolutions; j++)
+        cornerPoints[j] = solutions.solution[j];
+
+    bool feasibility = 1;
+    // rlh: use some COIN max instead of 1e30 (?)
+    double bestObj = 1e30;
+    std::vector< std::vector <double> > feasibles;
+    int numFeasibles = 0;
+
+    // Check the feasibility of the corner points
+    int numCornerPoints = numberSolutions;
+
+    const double * rhs = clpSolver->getRightHandSide();
+    // rlh: row sense hasn't changed. why a fresh copy?
+    // Delete next line.
+    rowSense = clpSolver->getRowSense();
+
+    for (int i = 0; i < numCornerPoints; i++) {
+        //get the objective value for this this point
+        double objValue = 0;
+        for (int k = 0; k < numCols; k++)
+            objValue += cornerPoints[i][k] * originalObjCoeff[k];
+
+        if (objValue < bestObj) {
+            // check integer feasibility
+            feasibility = 1;
+            for (int j = 0; j < numCols; j++) {
+                if (varClassInt[j]) {
+                    double closest = floor(cornerPoints[i][j] + 0.5);
+                    if (fabs(cornerPoints[i][j] - closest) > primalTolerance) {
+                        feasibility = 0;
+                        break;
+                    }
+                }
+            }
+            // check all constraints satisfied
+            if (feasibility) {
+                for (int irow = 0; irow < numRows; irow++) {
+                    double lhs = 0;
+                    for (int j = 0; j < numCols; j++) {
+                        lhs += matrix[irow][j] * cornerPoints[i][j];
+                    }
+                    if (rowSense[irow] == 'L' && lhs > rhs[irow] + primalTolerance) {
+                        feasibility = 0;
+                        break;
+                    }
+                    if (rowSense[irow] == 'G' && lhs < rhs[irow] - primalTolerance) {
+                        feasibility = 0;
+                        break;
+                    }
+                    if (rowSense[irow] == 'E' && (lhs - rhs[irow] > primalTolerance || lhs - rhs[irow] < -primalTolerance)) {
+                        feasibility = 0;
+                        break;
+                    }
+                }
+            }
+
+            if (feasibility) {
+                numFeasibles++;
+                feasibles.push_back(std::vector <double> (numCols));
+                for (int k = 0; k < numCols; k++)
+                    feasibles[numFeasibles-1][k] = cornerPoints[i][k];
+                printf("obj: %f\n", objValue);
+                if (objValue < bestObj)
+                    bestObj = objValue;
+            }
+        }
+    }
+    int numFeasibleCorners;
+    numFeasibleCorners = numFeasibles;
+    //find the center of gravity of the corner points as the first random point
+    double * rp = new double[numCols];
+    for (int i = 0; i < numCols; i++) {
+        rp[i] = 0;
+        for (int j = 0; j < numCornerPoints; j++) {
+            rp[i] += cornerPoints[j][i];
+        }
+        rp[i] = rp[i] / numCornerPoints;
+    }
+
+    //-------------------------------------------
+    //main loop:
+    // -generate the next random point
+    // -round the random point
+    // -check the feasibility of the random point
+    //-------------------------------------------
+
+    srand ( static_cast<unsigned int>(time(NULL) + 1));
+    int numRandomPoints = 0;
+    while (numRandomPoints < 50000) {
+        numRandomPoints++;
+        //generate the next random point
+        int randomIndex = intRand(numCornerPoints);
+        double random = CoinDrand48();
+        for (int i = 0; i < numCols; i++) {
+            rp[i] = (random * (cornerPoints[randomIndex][i] - rp[i])) + rp[i];
+        }
+
+        //CRISP ROUNDING
+        //round the random point just generated
+        double * roundRp = new double[numCols];
+        for (int i = 0; i < numCols; i++) {
+            roundRp[i] = rp[i];
+            if (varClassInt[i]) {
+                if (rp[i] >= 0) {
+                    if (fmod(rp[i], 1) > 0.5)
+                        roundRp[i] = floor(rp[i]) + 1;
+                    else
+                        roundRp[i] = floor(rp[i]);
+                } else {
+                    if (fabs(fmod(rp[i], 1)) > 0.5)
+                        roundRp[i] = floor(rp[i]);
+                    else
+                        roundRp[i] = floor(rp[i]) + 1;
+
+                }
+            }
+        }
+
+
+        //SOFT ROUNDING
+        // Look at original files for the "how to" on soft rounding;
+        // Soft rounding omitted here.
+
+        //Check the feasibility of the rounded random point
+        // -Check the feasibility
+        // -Get the rows sense
+        rowSense = clpSolver->getRowSense();
+        rhs = clpSolver->getRightHandSide();
+
+        //get the objective value for this feasible point
+        double objValue = 0;
+        for (int i = 0; i < numCols; i++)
+            objValue += roundRp[i] * originalObjCoeff[i];
+
+        if (objValue < bestObj) {
+            feasibility = 1;
+            for (int i = 0; i < numRows; i++) {
+                double lhs = 0;
+                for (int j = 0; j < numCols; j++) {
+                    lhs += matrix[i][j] * roundRp[j];
+                }
+                if (rowSense[i] == 'L' && lhs > rhs[i] + primalTolerance) {
+                    feasibility = 0;
+                    break;
+                }
+                if (rowSense[i] == 'G' && lhs < rhs[i] - primalTolerance) {
+                    feasibility = 0;
+                    break;
+                }
+                if (rowSense[i] == 'E' && (lhs - rhs[i] > primalTolerance || lhs - rhs[i] < -primalTolerance)) {
+                    feasibility = 0;
+                    break;
+                }
+            }
+            if (feasibility) {
+                printf("Feasible Found.\n");
+                printf("%.2f\n", CoinCpuTime() - start);
+                numFeasibles++;
+                feasibles.push_back(std::vector <double> (numCols));
+                for (int i = 0; i < numCols; i++)
+                    feasibles[numFeasibles-1][i] = roundRp[i];
+                printf("obj: %f\n", objValue);
+                if (objValue < bestObj)
+                    bestObj = objValue;
+            }
+        }
+        delete [] roundRp;
+    }
+    printf("Number of Feasible Corners: %d\n", numFeasibleCorners);
+    printf("Number of Feasibles Found: %d\n", numFeasibles);
+    if (numFeasibles > 0)
+        printf("Best Objective: %f\n", bestObj);
+    printf("time: %.2f\n", CoinCpuTime() - start);
+
+    if (numFeasibles == 0) {
+        // cleanup
+        delete [] varClassInt;
+        for (int i = 0; i < numRows; i++)
+            delete matrix[i];
+        delete [] matrix;
+        delete [] newObj;
+        delete [] index;
+        for (int i = 0; i < numberSolutions; i++)
+            delete cornerPoints[i];
+        delete [] cornerPoints;
+        delete [] rp;
+        return 0;
+    }
+
+    // We found something better
+    solutionValue = bestObj;
+    for (int k = 0; k < numCols; k++) {
+        betterSolution[k] =  feasibles[numFeasibles-1][k];
+    }
+    delete [] varClassInt;
+    for (int i = 0; i < numRows; i++)
+        delete matrix[i];
+    delete [] matrix;
+    delete [] newObj;
+    delete [] index;
+    for (int i = 0; i < numberSolutions; i++)
+        delete cornerPoints[i];
+    delete [] cornerPoints;
+    delete [] rp;
+    std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl;
+    return 1;
+
+}
+// update model
+void CbcHeuristicRandRound::setModel(CbcModel * model)
+{
+    CbcHeuristic::setModel(model);
+}
+
+
diff --git a/cbits/coin/CbcHeuristicRandRound.hpp b/cbits/coin/CbcHeuristicRandRound.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicRandRound.hpp
@@ -0,0 +1,58 @@
+/* $Id: CbcHeuristicRandRound.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcHeuristicRandRound_H
+#define CbcHeuristicRandRound_H
+
+#include "CbcHeuristic.hpp"
+/** LocalSearch class
+ */
+
+class CbcHeuristicRandRound : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicRandRound ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicRandRound (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicRandRound ( const CbcHeuristicRandRound &);
+
+    // Destructor
+    ~CbcHeuristicRandRound ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+    /// Assignment operator
+    CbcHeuristicRandRound & operator=(const CbcHeuristicRandRound& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        needs comments
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+
+protected:
+};
+
+
+#endif
+
diff --git a/cbits/coin/CbcHeuristicVND.cpp b/cbits/coin/CbcHeuristicVND.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicVND.cpp
@@ -0,0 +1,306 @@
+// $Id: CbcHeuristicVND.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// edwin 12/5/09 carved out of CbcHeuristicRINS
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcHeuristicVND.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcStrategy.hpp"
+#include "CglPreProcess.hpp"
+
+
+// Default Constructor
+CbcHeuristicVND::CbcHeuristicVND()
+        : CbcHeuristic()
+{
+    numberSolutions_ = 0;
+    numberSuccesses_ = 0;
+    numberTries_ = 0;
+    lastNode_ = -999999;
+    howOften_ = 100;
+    decayFactor_ = 0.5;
+    baseSolution_ = NULL;
+    whereFrom_ = 1 + 8 + 255 * 256;
+    stepSize_ = 0;
+    k_ = 0;
+    kmax_ = 0;
+    nDifferent_ = 0;
+}
+
+// Constructor with model - assumed before cuts
+
+CbcHeuristicVND::CbcHeuristicVND(CbcModel & model)
+        : CbcHeuristic(model)
+{
+    numberSolutions_ = 0;
+    numberSuccesses_ = 0;
+    numberTries_ = 0;
+    lastNode_ = -999999;
+    howOften_ = 100;
+    decayFactor_ = 0.5;
+    assert(model.solver());
+    int numberColumns = model.solver()->getNumCols();
+    baseSolution_ = new double [numberColumns];
+    memset(baseSolution_, 0, numberColumns*sizeof(double));
+    whereFrom_ = 1 + 8 + 255 * 256;
+    stepSize_ = 0;
+    k_ = 0;
+    kmax_ = 0;
+    nDifferent_ = 0;
+}
+
+// Destructor
+CbcHeuristicVND::~CbcHeuristicVND ()
+{
+    delete [] baseSolution_;
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicVND::clone() const
+{
+    return new CbcHeuristicVND(*this);
+}
+
+// Assignment operator
+CbcHeuristicVND &
+CbcHeuristicVND::operator=( const CbcHeuristicVND & rhs)
+{
+    if (this != &rhs) {
+        CbcHeuristic::operator=(rhs);
+        numberSolutions_ = rhs.numberSolutions_;
+        howOften_ = rhs.howOften_;
+        numberSuccesses_ = rhs.numberSuccesses_;
+        numberTries_ = rhs.numberTries_;
+        lastNode_ = rhs.lastNode_;
+        delete [] baseSolution_;
+        if (model_ && rhs.baseSolution_) {
+            int numberColumns = model_->solver()->getNumCols();
+            baseSolution_ = new double [numberColumns];
+            memcpy(baseSolution_, rhs.baseSolution_, numberColumns*sizeof(double));
+        } else {
+            baseSolution_ = NULL;
+        }
+        stepSize_ = rhs.stepSize_;
+        k_ = rhs.k_;
+        kmax_ = rhs.kmax_;
+        nDifferent_ = rhs.nDifferent_;
+    }
+    return *this;
+}
+
+// Create C++ lines to get to current state
+void
+CbcHeuristicVND::generateCpp( FILE * fp)
+{
+    CbcHeuristicVND other;
+    fprintf(fp, "0#include \"CbcHeuristicVND.hpp\"\n");
+    fprintf(fp, "3  CbcHeuristicVND heuristicVND(*cbcModel);\n");
+    CbcHeuristic::generateCpp(fp, "heuristicVND");
+    if (howOften_ != other.howOften_)
+        fprintf(fp, "3  heuristicVND.setHowOften(%d);\n", howOften_);
+    else
+        fprintf(fp, "4  heuristicVND.setHowOften(%d);\n", howOften_);
+    fprintf(fp, "3  cbcModel->addHeuristic(&heuristicVND);\n");
+}
+
+// Copy constructor
+CbcHeuristicVND::CbcHeuristicVND(const CbcHeuristicVND & rhs)
+        :
+        CbcHeuristic(rhs),
+        numberSolutions_(rhs.numberSolutions_),
+        howOften_(rhs.howOften_),
+        numberSuccesses_(rhs.numberSuccesses_),
+        numberTries_(rhs.numberTries_),
+        lastNode_(rhs.lastNode_)
+{
+    if (model_ && rhs.baseSolution_) {
+        int numberColumns = model_->solver()->getNumCols();
+        baseSolution_ = new double [numberColumns];
+        memcpy(baseSolution_, rhs.baseSolution_, numberColumns*sizeof(double));
+    } else {
+        baseSolution_ = NULL;
+    }
+    stepSize_ = rhs.stepSize_;
+    k_ = rhs.k_;
+    kmax_ = rhs.kmax_;
+    nDifferent_ = rhs.nDifferent_;
+}
+// Resets stuff if model changes
+void
+CbcHeuristicVND::resetModel(CbcModel * /*model*/)
+{
+    //CbcHeuristic::resetModel(model);
+    delete [] baseSolution_;
+    if (model_ && baseSolution_) {
+        int numberColumns = model_->solver()->getNumCols();
+        baseSolution_ = new double [numberColumns];
+        memset(baseSolution_, 0, numberColumns*sizeof(double));
+    } else {
+        baseSolution_ = NULL;
+    }
+}
+/*
+  First tries setting a variable to better value.  If feasible then
+  tries setting others.  If not feasible then tries swaps
+  Returns 1 if solution, 0 if not */
+int
+CbcHeuristicVND::solution(double & solutionValue,
+                          double * betterSolution)
+{
+    numCouldRun_++;
+    int returnCode = 0;
+    const double * bestSolution = model_->bestSolution();
+    if (!bestSolution)
+        return 0; // No solution found yet
+    if (numberSolutions_ < model_->getSolutionCount()) {
+        // new solution - add info
+        numberSolutions_ = model_->getSolutionCount();
+
+        int numberIntegers = model_->numberIntegers();
+        const int * integerVariable = model_->integerVariable();
+
+        int i;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            const OsiObject * object = model_->object(i);
+            // get original bounds
+            double originalLower;
+            double originalUpper;
+            getIntegerInformation( object, originalLower, originalUpper);
+            double value = bestSolution[iColumn];
+            if (value < originalLower) {
+                value = originalLower;
+            } else if (value > originalUpper) {
+                value = originalUpper;
+            }
+        }
+    }
+    int numberNodes = model_->getNodeCount();
+    if (howOften_ == 100) {
+        if (numberNodes < lastNode_ + 12)
+            return 0;
+        // Do at 50 and 100
+        if ((numberNodes > 40 && numberNodes <= 50) || (numberNodes > 90 && numberNodes < 100))
+            numberNodes = howOften_;
+    }
+    if ((numberNodes % howOften_) == 0 && (model_->getCurrentPassNumber() == 1 ||
+                                           model_->getCurrentPassNumber() == 999999)) {
+        lastNode_ = model_->getNodeCount();
+        OsiSolverInterface * solver = model_->solver();
+
+        int numberIntegers = model_->numberIntegers();
+        const int * integerVariable = model_->integerVariable();
+
+        const double * currentSolution = solver->getColSolution();
+        OsiSolverInterface * newSolver = cloneBut(3); // was model_->continuousSolver()->clone();
+        //const double * colLower = newSolver->getColLower();
+        //const double * colUpper = newSolver->getColUpper();
+
+        double primalTolerance;
+        solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+        // Sort on distance
+        double * distance = new double [numberIntegers];
+        int * which = new int [numberIntegers];
+
+        int i;
+        int nFix = 0;
+        double tolerance = 10.0 * primalTolerance;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            const OsiObject * object = model_->object(i);
+            // get original bounds
+            double originalLower;
+            double originalUpper;
+            getIntegerInformation( object, originalLower, originalUpper);
+            double valueInt = bestSolution[iColumn];
+            if (valueInt < originalLower) {
+                valueInt = originalLower;
+            } else if (valueInt > originalUpper) {
+                valueInt = originalUpper;
+            }
+            baseSolution_[iColumn] = currentSolution[iColumn];
+            distance[i] = fabs(currentSolution[iColumn] - valueInt);
+            which[i] = i;
+            if (fabs(currentSolution[iColumn] - valueInt) < tolerance)
+                nFix++;
+        }
+        CoinSort_2(distance, distance + numberIntegers, which);
+        nDifferent_ = numberIntegers - nFix;
+        stepSize_ = nDifferent_ / 10;
+        k_ = stepSize_;
+        //nFix = numberIntegers-stepSize_;
+        for (i = 0; i < nFix; i++) {
+            int j = which[i];
+            int iColumn = integerVariable[j];
+            const OsiObject * object = model_->object(i);
+            // get original bounds
+            double originalLower;
+            double originalUpper;
+            getIntegerInformation( object, originalLower, originalUpper);
+            double valueInt = bestSolution[iColumn];
+            if (valueInt < originalLower) {
+                valueInt = originalLower;
+            } else if (valueInt > originalUpper) {
+                valueInt = originalUpper;
+            }
+            double nearest = floor(valueInt + 0.5);
+            newSolver->setColLower(iColumn, nearest);
+            newSolver->setColUpper(iColumn, nearest);
+        }
+        delete [] distance;
+        delete [] which;
+        if (nFix > numberIntegers / 5) {
+            //printf("%d integers have samish value\n",nFix);
+            returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
+                                             model_->getCutoff(), "CbcHeuristicVND");
+            if (returnCode < 0)
+                returnCode = 0; // returned on size
+            else
+                numRuns_++;
+            if ((returnCode&1) != 0)
+                numberSuccesses_++;
+            //printf("return code %d",returnCode);
+            if ((returnCode&2) != 0) {
+                // could add cut
+                returnCode &= ~2;
+                //printf("could add cut with %d elements (if all 0-1)\n",nFix);
+            } else {
+                //printf("\n");
+            }
+            numberTries_++;
+            if ((numberTries_ % 10) == 0 && numberSuccesses_*3 < numberTries_)
+                howOften_ += static_cast<int> (howOften_ * decayFactor_);
+        }
+
+        delete newSolver;
+    }
+    return returnCode;
+}
+// update model
+void CbcHeuristicVND::setModel(CbcModel * model)
+{
+    model_ = model;
+    // Get a copy of original matrix
+    assert(model_->solver());
+    delete [] baseSolution_;
+    int numberColumns = model->solver()->getNumCols();
+    baseSolution_ = new double [numberColumns];
+    memset(baseSolution_, 0, numberColumns*sizeof(double));
+}
+
diff --git a/cbits/coin/CbcHeuristicVND.hpp b/cbits/coin/CbcHeuristicVND.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcHeuristicVND.hpp
@@ -0,0 +1,94 @@
+// $Id: CbcHeuristicVND.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// edwin 12/5/09 carved out of CbcHeuristicRINS
+
+#ifndef CbcHeuristicVND_H
+#define CbcHeuristicVND_H
+
+#include "CbcHeuristic.hpp"
+
+
+/** LocalSearch class
+ */
+
+class CbcHeuristicVND : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicVND ();
+
+    /* Constructor with model - assumed before cuts
+       Initial version does not do Lps
+    */
+    CbcHeuristicVND (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicVND ( const CbcHeuristicVND &);
+
+    // Destructor
+    ~CbcHeuristicVND ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+
+    /// Assignment operator
+    CbcHeuristicVND & operator=(const CbcHeuristicVND& rhs);
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+
+    /// update model (This is needed if cliques update matrix etc)
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        This does Relaxation Induced Neighborhood Search
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// This version fixes stuff and does IP
+    int solutionFix(double & objectiveValue,
+                    double * newSolution,
+                    const int * keep);
+
+    /// Sets how often to do it
+    inline void setHowOften(int value) {
+        howOften_ = value;
+    }
+    /// base solution array so we can set
+    inline double * baseSolution() const {
+        return baseSolution_;
+    }
+
+protected:
+    // Data
+
+    /// Number of solutions so we can do something at solution
+    int numberSolutions_;
+    /// How often to do (code can change)
+    int howOften_;
+    /// Number of successes
+    int numberSuccesses_;
+    /// Number of tries
+    int numberTries_;
+    /// Node when last done
+    int lastNode_;
+    /// Step size for decomposition
+    int stepSize_;
+    int k_;
+    int kmax_;
+    int nDifferent_;
+    /// Base solution
+    double * baseSolution_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcLinked.cpp b/cbits/coin/CbcLinked.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcLinked.cpp
@@ -0,0 +1,8285 @@
+/* $Id: CbcLinked.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CbcConfig.h"
+
+#include "CoinTime.hpp"
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinModel.hpp"
+#include "ClpSimplex.hpp"
+// returns jColumn (-2 if linear term, -1 if unknown) and coefficient
+static
+int decodeBit(char * phrase, char * & nextPhrase, double & coefficient, bool ifFirst, const CoinModel & model)
+{
+    char * pos = phrase;
+    // may be leading - (or +)
+    char * pos2 = pos;
+    double value = 1.0;
+    if (*pos2 == '-' || *pos2 == '+')
+        pos2++;
+    // next terminator * or + or -
+    while (*pos2) {
+        if (*pos2 == '*') {
+            break;
+        } else if (*pos2 == '-' || *pos2 == '+') {
+            if (pos2 == pos || *(pos2 - 1) != 'e')
+                break;
+        }
+        pos2++;
+    }
+    // if * must be number otherwise must be name
+    if (*pos2 == '*') {
+        char * pos3 = pos;
+        while (pos3 != pos2) {
+            pos3++;
+#ifndef NDEBUG
+            char x = *(pos3 - 1);
+            assert ((x >= '0' && x <= '9') || x == '.' || x == '+' || x == '-' || x == 'e');
+#endif
+        }
+        char saved = *pos2;
+        *pos2 = '\0';
+        value = atof(pos);
+        *pos2 = saved;
+        // and down to next
+        pos2++;
+        pos = pos2;
+        while (*pos2) {
+            if (*pos2 == '-' || *pos2 == '+')
+                break;
+            pos2++;
+        }
+    }
+    char saved = *pos2;
+    *pos2 = '\0';
+    // now name
+    // might have + or -
+    if (*pos == '+') {
+        pos++;
+    } else if (*pos == '-') {
+        pos++;
+        assert (value == 1.0);
+        value = - value;
+    }
+    int jColumn = model.column(pos);
+    // must be column unless first when may be linear term
+    if (jColumn < 0) {
+        if (ifFirst) {
+            char * pos3 = pos;
+            while (pos3 != pos2) {
+                pos3++;
+#ifndef NDEBUG
+                char x = *(pos3 - 1);
+                assert ((x >= '0' && x <= '9') || x == '.' || x == '+' || x == '-' || x == 'e');
+#endif
+            }
+            assert(*pos2 == '\0');
+            // keep possible -
+            value = value * atof(pos);
+            jColumn = -2;
+        } else {
+            // bad
+            *pos2 = saved;
+            printf("bad nonlinear term %s\n", phrase);
+            abort();
+        }
+    }
+    *pos2 = saved;
+    pos = pos2;
+    coefficient = value;
+    nextPhrase = pos;
+    return jColumn;
+}
+#include "ClpQuadraticObjective.hpp"
+#include <cassert>
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include "CbcLinked.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinMpsIO.hpp"
+//#include "OsiSolverLink.hpp"
+//#include "OsiBranchLink.hpp"
+#include "ClpPackedMatrix.hpp"
+#include "CoinTime.hpp"
+#include "CbcModel.hpp"
+#include "CbcCutGenerator.hpp"
+#include "CglStored.hpp"
+#include "CglPreProcess.hpp"
+#include "CglGomory.hpp"
+#include "CglProbing.hpp"
+#include "CglKnapsackCover.hpp"
+#include "CglRedSplit.hpp"
+#include "CglClique.hpp"
+#include "CglFlowCover.hpp"
+#include "CglMixedIntegerRounding2.hpp"
+#include "CglTwomir.hpp"
+#include "CglDuplicateRow.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcHeuristic.hpp"
+#include "CbcHeuristicLocal.hpp"
+#include "CbcHeuristicGreedy.hpp"
+#include "ClpLinearObjective.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcCompareActual.hpp"
+//#############################################################################
+// Solve methods
+//#############################################################################
+void OsiSolverLink::initialSolve()
+{
+    //writeMps("yy");
+    //exit(77);
+    specialOptions_ = 0;
+    modelPtr_->setWhatsChanged(0);
+    if (numberVariables_) {
+        CoinPackedMatrix * temp = new CoinPackedMatrix(*matrix_);
+        // update all bounds before coefficients
+        for (int i = 0; i < numberVariables_; i++ ) {
+            info_[i].updateBounds(modelPtr_);
+        }
+        int updated = updateCoefficients(modelPtr_, temp);
+        if (updated || 1) {
+            temp->removeGaps(1.0e-14);
+            ClpMatrixBase * save = modelPtr_->clpMatrix();
+            ClpPackedMatrix * clpMatrix = dynamic_cast<ClpPackedMatrix *> (save);
+            assert (clpMatrix);
+            if (save->getNumRows() > temp->getNumRows()) {
+                // add in cuts
+                int numberRows = temp->getNumRows();
+                int * which = new int[numberRows];
+                for (int i = 0; i < numberRows; i++)
+                    which[i] = i;
+                save->deleteRows(numberRows, which);
+                delete [] which;
+                temp->bottomAppendPackedMatrix(*clpMatrix->matrix());
+            }
+            modelPtr_->replaceMatrix(temp, true);
+        } else {
+            delete temp;
+        }
+    }
+    if (0) {
+        const double * lower = getColLower();
+        const double * upper = getColUpper();
+        int n = 0;
+        for (int i = 84; i < 84 + 16; i++) {
+            if (lower[i] + 0.01 < upper[i]) {
+                n++;
+            }
+        }
+        if (!n)
+            writeMps("sol_query");
+
+    }
+    //static int iPass=0;
+    //char temp[50];
+    //iPass++;
+    //sprintf(temp,"cc%d",iPass);
+    //writeMps(temp);
+    //writeMps("tight");
+    //exit(33);
+    //printf("wrote cc%d\n",iPass);
+    OsiClpSolverInterface::initialSolve();
+    int secondaryStatus = modelPtr_->secondaryStatus();
+    if (modelPtr_->status() == 0 && (secondaryStatus == 2 || secondaryStatus == 4))
+        modelPtr_->cleanup(1);
+    //if (!isProvenOptimal())
+    //writeMps("yy");
+    if (isProvenOptimal() && quadraticModel_ && modelPtr_->numberColumns() == quadraticModel_->numberColumns()) {
+        // see if qp can get better solution
+        const double * solution = modelPtr_->primalColumnSolution();
+        int numberColumns = modelPtr_->numberColumns();
+        bool satisfied = true;
+        for (int i = 0; i < numberColumns; i++) {
+            if (isInteger(i)) {
+                double value = solution[i];
+                if (fabs(value - floor(value + 0.5)) > 1.0e-6) {
+                    satisfied = false;
+                    break;
+                }
+            }
+        }
+        if (satisfied) {
+            ClpSimplex qpTemp(*quadraticModel_);
+            double * lower = qpTemp.columnLower();
+            double * upper = qpTemp.columnUpper();
+            double * lower2 = modelPtr_->columnLower();
+            double * upper2 = modelPtr_->columnUpper();
+            for (int i = 0; i < numberColumns; i++) {
+                if (isInteger(i)) {
+                    double value = floor(solution[i] + 0.5);
+                    lower[i] = value;
+                    upper[i] = value;
+                } else {
+                    lower[i] = lower2[i];
+                    upper[i] = upper2[i];
+                }
+            }
+            //qpTemp.writeMps("bad.mps");
+            //modelPtr_->writeMps("bad2.mps");
+            //qpTemp.objectiveAsObject()->setActivated(0);
+            //qpTemp.primal();
+            //qpTemp.objectiveAsObject()->setActivated(1);
+            qpTemp.primal();
+            //assert (!qpTemp.problemStatus());
+            if (qpTemp.objectiveValue() < bestObjectiveValue_ - 1.0e-3 && !qpTemp.problemStatus()) {
+                delete [] bestSolution_;
+                bestSolution_ = CoinCopyOfArray(qpTemp.primalColumnSolution(), numberColumns);
+                bestObjectiveValue_ = qpTemp.objectiveValue();
+                printf("better qp objective of %g\n", bestObjectiveValue_);
+                // If model has stored then add cut (if convex)
+                if (cbcModel_ && (specialOptions2_&4) != 0) {
+                    int numberGenerators = cbcModel_->numberCutGenerators();
+                    int iGenerator;
+                    cbcModel_->lockThread();
+                    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+                        CbcCutGenerator * generator = cbcModel_->cutGenerator(iGenerator);
+                        CglCutGenerator * gen = generator->generator();
+                        CglStored * gen2 = dynamic_cast<CglStored *> (gen);
+                        if (gen2) {
+                            // add OA cut
+                            double offset;
+                            double * gradient = new double [numberColumns+1];
+                            memcpy(gradient, qpTemp.objectiveAsObject()->gradient(&qpTemp, bestSolution_, offset, true, 2),
+                                   numberColumns*sizeof(double));
+                            // assume convex
+                            double rhs = 0.0;
+                            int * column = new int[numberColumns+1];
+                            int n = 0;
+                            for (int i = 0; i < numberColumns; i++) {
+                                double value = gradient[i];
+                                if (fabs(value) > 1.0e-12) {
+                                    gradient[n] = value;
+                                    rhs += value * solution[i];
+                                    column[n++] = i;
+                                }
+                            }
+                            gradient[n] = -1.0;
+                            column[n++] = objectiveVariable_;
+                            gen2->addCut(-COIN_DBL_MAX, offset + 1.0e-7, n, column, gradient);
+                            delete [] gradient;
+                            delete [] column;
+                            break;
+                        }
+                    }
+                    cbcModel_->unlockThread();
+                }
+            }
+        }
+    }
+}
+//#define WRITE_MATRIX
+#ifdef WRITE_MATRIX
+static int xxxxxx = 0;
+#endif
+//-----------------------------------------------------------------------------
+void OsiSolverLink::resolve()
+{
+    if (false) {
+        bool takeHint;
+        OsiHintStrength strength;
+        // Switch off printing if asked to
+        getHintParam(OsiDoReducePrint, takeHint, strength);
+        if (strength != OsiHintIgnore && takeHint) {
+            printf("no printing\n");
+        } else {
+            printf("printing\n");
+        }
+    }
+    specialOptions_ = 0;
+    modelPtr_->setWhatsChanged(0);
+    bool allFixed = numberFix_ > 0;
+    bool feasible = true;
+    if (numberVariables_) {
+        CoinPackedMatrix * temp = new CoinPackedMatrix(*matrix_);
+        //bool best=true;
+        const double * lower = modelPtr_->columnLower();
+        const double * upper = modelPtr_->columnUpper();
+        // update all bounds before coefficients
+        for (int i = 0; i < numberVariables_; i++ ) {
+            info_[i].updateBounds(modelPtr_);
+            int iColumn = info_[i].variable();
+            double lo = lower[iColumn];
+            double up = upper[iColumn];
+            if (up < lo)
+                feasible = false;
+        }
+        int updated = updateCoefficients(modelPtr_, temp);
+        if (updated) {
+            temp->removeGaps(1.0e-14);
+            ClpMatrixBase * save = modelPtr_->clpMatrix();
+            ClpPackedMatrix * clpMatrix = dynamic_cast<ClpPackedMatrix *> (save);
+            assert (clpMatrix);
+            if (save->getNumRows() > temp->getNumRows()) {
+                // add in cuts
+                int numberRows = temp->getNumRows();
+                int * which = new int[numberRows];
+                for (int i = 0; i < numberRows; i++)
+                    which[i] = i;
+                CoinPackedMatrix * mat = clpMatrix->matrix();
+                // for debug
+                //mat = new CoinPackedMatrix(*mat);
+                mat->deleteRows(numberRows, which);
+                delete [] which;
+                temp->bottomAppendPackedMatrix(*mat);
+                temp->removeGaps(1.0e-14);
+            }
+            modelPtr_->replaceMatrix(temp, true);
+	    modelPtr_->setNewRowCopy(NULL);
+	    modelPtr_->setClpScaledMatrix(NULL);
+        } else {
+            delete temp;
+        }
+    }
+#ifdef WRITE_MATRIX
+    {
+        xxxxxx++;
+        char temp[50];
+        sprintf(temp, "bb%d", xxxxxx);
+        writeMps(temp);
+        printf("wrote bb%d\n", xxxxxx);
+    }
+#endif
+    if (0) {
+        const double * lower = getColLower();
+        const double * upper = getColUpper();
+        int n = 0;
+        for (int i = 60; i < 64; i++) {
+            if (lower[i]) {
+                printf("%d bounds %g %g\n", i, lower[i], upper[i]);
+                n++;
+            }
+        }
+        if (n == 1)
+            printf("just one?\n");
+    }
+    // check feasible
+    {
+        const double * lower = getColLower();
+        const double * upper = getColUpper();
+        int numberColumns = getNumCols();
+        for (int i = 0; i < numberColumns; i++) {
+            if (lower[i] > upper[i] + 1.0e-12) {
+                feasible = false;
+                break;
+            }
+        }
+    }
+    if (!feasible)
+        allFixed = false;
+    if ((specialOptions2_&1) == 0)
+        allFixed = false;
+    int returnCode = -1;
+    // See if in strong branching
+    int maxIts = modelPtr_->maximumIterations();
+    if (feasible) {
+        if (maxIts > 10000) {
+            // may do lots of work
+            if ((specialOptions2_&1) != 0) {
+                // see if fixed
+                const double * lower = modelPtr_->columnLower();
+                const double * upper = modelPtr_->columnUpper();
+                for (int i = 0; i < numberFix_; i++ ) {
+                    int iColumn = fixVariables_[i];
+                    double lo = lower[iColumn];
+                    double up = upper[iColumn];
+                    if (up > lo) {
+                        allFixed = false;
+                        break;
+                    }
+                }
+                returnCode = allFixed ? fathom(allFixed) : 0;
+            } else {
+                returnCode = 0;
+            }
+        } else {
+            returnCode = 0;
+        }
+    }
+    if (returnCode >= 0) {
+        if (returnCode == 0)
+            OsiClpSolverInterface::resolve();
+        int satisfied = 2;
+        const double * solution = getColSolution();
+        const double * lower = getColLower();
+        const double * upper = getColUpper();
+        int numberColumns2 = coinModel_.numberColumns();
+        for (int i = 0; i < numberColumns2; i++) {
+            if (isInteger(i)) {
+                double value = solution[i];
+                if (fabs(value - floor(value + 0.5)) > 1.0e-6) {
+                    satisfied = 0;
+                    break;
+                } else if (upper[i] > lower[i]) {
+                    satisfied = 1;
+                }
+            }
+        }
+        if (isProvenOptimal()) {
+            //if (satisfied==2)
+            //printf("satisfied %d\n",satisfied);
+            if (satisfied && (specialOptions2_&2) != 0) {
+                assert (quadraticModel_);
+                // look at true objective
+#ifndef NDEBUG
+                double direction = modelPtr_->optimizationDirection();
+                assert (direction == 1.0);
+#endif
+                double value = - quadraticModel_->objectiveOffset();
+                const double * objective = quadraticModel_->objective();
+                int i;
+                for ( i = 0; i < numberColumns2; i++)
+                    value += solution[i] * objective[i];
+                // and now rest
+                for ( i = 0; i < numberObjects_; i++) {
+                    OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+                    if (obj) {
+                        value += obj->xyCoefficient(solution);
+                    }
+                }
+                if (value < bestObjectiveValue_ - 1.0e-3) {
+                    printf("obj of %g\n", value);
+                    //modelPtr_->setDualObjectiveLimit(value);
+                    delete [] bestSolution_;
+                    bestSolution_ = CoinCopyOfArray(modelPtr_->getColSolution(), modelPtr_->getNumCols());
+                    bestObjectiveValue_ = value;
+                    if (maxIts <= 10000 && cbcModel_) {
+                        OsiSolverLink * solver2 = dynamic_cast<OsiSolverLink *> (cbcModel_->solver());
+                        assert (solver2);
+                        if (solver2 != this) {
+                            // in strong branching - need to store in original solver
+                            if (value < solver2->bestObjectiveValue_ - 1.0e-3) {
+                                delete [] solver2->bestSolution_;
+                                solver2->bestSolution_ = CoinCopyOfArray(bestSolution_, modelPtr_->getNumCols());
+                                solver2->bestObjectiveValue_ = value;
+                            }
+                        }
+                    }
+                    // If model has stored then add cut (if convex)
+                    if (cbcModel_ && (specialOptions2_&4) != 0 && quadraticModel_) {
+                        int numberGenerators = cbcModel_->numberCutGenerators();
+                        int iGenerator;
+                        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+                            CbcCutGenerator * generator = cbcModel_->cutGenerator(iGenerator);
+                            CglCutGenerator * gen = generator->generator();
+                            CglStored * gen2 = dynamic_cast<CglStored *> (gen);
+                            if (gen2) {
+                                cbcModel_->lockThread();
+                                // add OA cut
+                                double offset = 0.0;
+                                int numberColumns = quadraticModel_->numberColumns();
+                                double * gradient = new double [numberColumns+1];
+                                // gradient from bilinear
+                                int i;
+                                CoinZeroN(gradient, numberColumns + 1);
+                                //const double * objective = modelPtr_->objective();
+                                assert (objectiveRow_ >= 0);
+                                const double * element = originalRowCopy_->getElements();
+                                const int * column2 = originalRowCopy_->getIndices();
+                                const CoinBigIndex * rowStart = originalRowCopy_->getVectorStarts();
+                                //const int * rowLength = originalRowCopy_->getVectorLengths();
+                                //int numberColumns2 = coinModel_.numberColumns();
+                                for ( i = rowStart[objectiveRow_]; i < rowStart[objectiveRow_+1]; i++)
+                                    gradient[column2[i]] = element[i];
+                                for ( i = 0; i < numberObjects_; i++) {
+                                    OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+                                    if (obj) {
+                                        int xColumn = obj->xColumn();
+                                        int yColumn = obj->yColumn();
+                                        if (xColumn != yColumn) {
+                                            double coefficient = /* 2.0* */obj->coefficient();
+                                            gradient[xColumn] += coefficient * solution[yColumn];
+                                            gradient[yColumn] += coefficient * solution[xColumn];
+                                            offset += coefficient * solution[xColumn] * solution[yColumn];
+                                        } else {
+                                            double coefficient = obj->coefficient();
+                                            gradient[xColumn] += 2.0 * coefficient * solution[yColumn];
+                                            offset += coefficient * solution[xColumn] * solution[yColumn];
+                                        }
+                                    }
+                                }
+                                // assume convex
+                                double rhs = 0.0;
+                                int * column = new int[numberColumns+1];
+                                int n = 0;
+                                for (int i = 0; i < numberColumns; i++) {
+                                    double value = gradient[i];
+                                    if (fabs(value) > 1.0e-12) {
+                                        gradient[n] = value;
+                                        rhs += value * solution[i];
+                                        column[n++] = i;
+                                    }
+                                }
+                                gradient[n] = -1.0;
+                                column[n++] = objectiveVariable_;
+                                gen2->addCut(-COIN_DBL_MAX, offset + 1.0e-4, n, column, gradient);
+                                delete [] gradient;
+                                delete [] column;
+                                cbcModel_->unlockThread();
+                                break;
+                            }
+                        }
+                    }
+                }
+            } else if (satisfied == 2) {
+                // is there anything left to do?
+                int i;
+                int numberContinuous = 0;
+                double gap = 0.0;
+                for ( i = 0; i < numberObjects_; i++) {
+                    OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+                    if (obj) {
+                        if (obj->xMeshSize() < 1.0 && obj->yMeshSize() < 1.0) {
+                            numberContinuous++;
+                            int xColumn = obj->xColumn();
+                            double gapX = upper[xColumn] - lower[xColumn];
+                            int yColumn = obj->yColumn();
+                            double gapY = upper[yColumn] - lower[yColumn];
+                            gap = CoinMax(gap, CoinMax(gapX, gapY));
+                        }
+                    }
+                }
+                if (numberContinuous && 0) {
+                    // iterate to get solution and fathom node
+                    int numberColumns2 = coinModel_.numberColumns();
+                    double * lower2 = CoinCopyOfArray(getColLower(), numberColumns2);
+                    double * upper2 = CoinCopyOfArray(getColUpper(), numberColumns2);
+                    while (gap > defaultMeshSize_) {
+                        gap *= 0.9;
+                        const double * solution = getColSolution();
+                        double newGap = 0.0;
+                        for ( i = 0; i < numberObjects_; i++) {
+                            OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+                            if (obj && (obj->branchingStrategy()&8) == 0) {
+                                if (obj->xMeshSize() < 1.0 && obj->yMeshSize() < 1.0) {
+                                    numberContinuous++;
+                                    // need to make sure new xy value in range
+                                    double xB[3];
+                                    double yB[3];
+                                    double xybar[4];
+                                    obj->getCoefficients(this, xB, yB, xybar);
+                                    //double xyTrue = obj->xyCoefficient(solution);
+                                    double xyLambda = 0.0;
+                                    int firstLambda = obj->firstLambda();
+                                    for (int j = 0; j < 4; j++) {
+                                        xyLambda += solution[firstLambda+j] * xybar[j];
+                                    }
+                                    //printf ("x %d, y %d - true %g lambda %g\n",obj->xColumn(),obj->yColumn(),
+                                    //  xyTrue,xyLambda);
+                                    int xColumn = obj->xColumn();
+                                    double gapX = upper[xColumn] - lower[xColumn];
+                                    int yColumn = obj->yColumn();
+                                    if (gapX > gap) {
+                                        double value = solution[xColumn];
+                                        double newLower = CoinMax(lower2[xColumn], value - 0.5 * gap);
+                                        double newUpper = CoinMin(upper2[xColumn], value + 0.5 * gap);
+                                        if (newUpper - newLower < 0.99*gap) {
+                                            if (newLower == lower2[xColumn])
+                                                newUpper = CoinMin(upper2[xColumn], newLower + gap);
+                                            else if (newUpper == upper2[xColumn])
+                                                newLower = CoinMax(lower2[xColumn], newUpper - gap);
+                                        }
+                                        // see if problem
+#ifndef NDEBUG
+                                        double lambda[4];
+#endif
+                                        xB[0] = newLower;
+                                        xB[1] = newUpper;
+                                        xB[2] = value;
+                                        yB[2] = solution[yColumn];
+                                        xybar[0] = xB[0] * yB[0];
+                                        xybar[1] = xB[0] * yB[1];
+                                        xybar[2] = xB[1] * yB[0];
+                                        xybar[3] = xB[1] * yB[1];
+#ifndef NDEBUG
+                                        double infeasibility = obj->computeLambdas(xB, yB, xybar, lambda);
+                                        assert (infeasibility < 1.0e-9);
+#endif
+                                        setColLower(xColumn, newLower);
+                                        setColUpper(xColumn, newUpper);
+                                    }
+                                    double gapY = upper[yColumn] - lower[yColumn];
+                                    if (gapY > gap) {
+                                        double value = solution[yColumn];
+                                        double newLower = CoinMax(lower2[yColumn], value - 0.5 * gap);
+                                        double newUpper = CoinMin(upper2[yColumn], value + 0.5 * gap);
+                                        if (newUpper - newLower < 0.99*gap) {
+                                            if (newLower == lower2[yColumn])
+                                                newUpper = CoinMin(upper2[yColumn], newLower + gap);
+                                            else if (newUpper == upper2[yColumn])
+                                                newLower = CoinMax(lower2[yColumn], newUpper - gap);
+                                        }
+                                        // see if problem
+#ifndef NDEBUG
+                                        double lambda[4];
+#endif
+                                        yB[0] = newLower;
+                                        yB[1] = newUpper;
+                                        xybar[0] = xB[0] * yB[0];
+                                        xybar[1] = xB[0] * yB[1];
+                                        xybar[2] = xB[1] * yB[0];
+                                        xybar[3] = xB[1] * yB[1];
+#ifndef NDEBUG
+                                        double infeasibility = obj->computeLambdas(xB, yB, xybar, lambda);
+                                        assert (infeasibility < 1.0e-9);
+#endif
+                                        setColLower(yColumn, newLower);
+                                        setColUpper(yColumn, newUpper);
+                                    }
+                                    newGap = CoinMax(newGap, CoinMax(gapX, gapY));
+                                }
+                            }
+                        }
+                        printf("solving with gap of %g\n", gap);
+                        //OsiClpSolverInterface::resolve();
+                        initialSolve();
+                        if (!isProvenOptimal())
+                            break;
+                    }
+                    delete [] lower2;
+                    delete [] upper2;
+                    //if (isProvenOptimal())
+                    //writeMps("zz");
+                }
+            }
+            // ???  - try
+            // But skip if strong branching
+            CbcModel * cbcModel = (modelPtr_->maximumIterations() > 10000) ? cbcModel_ : NULL;
+            if ((specialOptions2_&2) != 0) {
+                // If model has stored then add cut (if convex)
+                // off until I work out problem with ibell3a
+                if (cbcModel && (specialOptions2_&4) != 0 && quadraticModel_) {
+                    int numberGenerators = cbcModel_->numberCutGenerators();
+                    int iGenerator;
+                    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+                        CbcCutGenerator * generator = cbcModel_->cutGenerator(iGenerator);
+                        CglCutGenerator * gen = generator->generator();
+                        CglTemporary * gen2 = dynamic_cast<CglTemporary *> (gen);
+                        if (gen2) {
+                            double * solution2 = NULL;
+                            int numberColumns = quadraticModel_->numberColumns();
+                            int depth = cbcModel_->currentNode() ? cbcModel_->currentNode()->depth() : 0;
+                            if (depth < 5) {
+                                ClpSimplex qpTemp(*quadraticModel_);
+                                double * lower = qpTemp.columnLower();
+                                double * upper = qpTemp.columnUpper();
+                                double * lower2 = modelPtr_->columnLower();
+                                double * upper2 = modelPtr_->columnUpper();
+                                for (int i = 0; i < numberColumns; i++) {
+                                    lower[i] = lower2[i];
+                                    upper[i] = upper2[i];
+                                }
+                                qpTemp.setLogLevel(modelPtr_->logLevel());
+                                qpTemp.primal();
+                                assert (!qpTemp.problemStatus());
+                                if (qpTemp.objectiveValue() < bestObjectiveValue_ - 1.0e-3 && !qpTemp.problemStatus()) {
+                                    solution2 = CoinCopyOfArray(qpTemp.primalColumnSolution(), numberColumns);
+                                } else {
+                                    printf("QP says expensive - kill\n");
+                                    modelPtr_->setProblemStatus(1);
+                                    modelPtr_->setObjectiveValue(COIN_DBL_MAX);
+                                    break;
+                                }
+                            }
+                            const double * solution = getColSolution();
+                            // add OA cut
+                            doAOCuts(gen2, solution, solution);
+                            if (solution2) {
+                                doAOCuts(gen2, solution, solution2);
+                                delete [] solution2;
+                            }
+                            break;
+                        }
+                    }
+                }
+            } else if (cbcModel && (specialOptions2_&8) == 8) {
+                // convex and nonlinear in constraints
+                int numberGenerators = cbcModel_->numberCutGenerators();
+                int iGenerator;
+                for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+                    CbcCutGenerator * generator = cbcModel_->cutGenerator(iGenerator);
+                    CglCutGenerator * gen = generator->generator();
+                    CglTemporary * gen2 = dynamic_cast<CglTemporary *> (gen);
+                    if (gen2) {
+                        const double * solution = getColSolution();
+                        const double * rowUpper = getRowUpper();
+                        const double * rowLower = getRowLower();
+                        const double * element = originalRowCopy_->getElements();
+                        const int * column2 = originalRowCopy_->getIndices();
+                        const CoinBigIndex * rowStart = originalRowCopy_->getVectorStarts();
+                        //const int * rowLength = originalRowCopy_->getVectorLengths();
+                        int numberColumns2 = CoinMax(coinModel_.numberColumns(), objectiveVariable_ + 1);
+                        double * gradient = new double [numberColumns2];
+                        int * column = new int[numberColumns2];
+                        //const double * columnLower = modelPtr_->columnLower();
+                        //const double * columnUpper = modelPtr_->columnUpper();
+                        cbcModel_->lockThread();
+                        for (int iNon = 0; iNon < numberNonLinearRows_; iNon++) {
+                            int iRow = rowNonLinear_[iNon];
+                            bool convex = convex_[iNon] > 0;
+                            if (!convex_[iNon])
+                                continue; // can't use this row
+                            // add OA cuts
+                            double offset = 0.0;
+                            // gradient from bilinear
+                            int i;
+                            CoinZeroN(gradient, numberColumns2);
+                            //const double * objective = modelPtr_->objective();
+                            for ( i = rowStart[iRow]; i < rowStart[iRow+1]; i++)
+                                gradient[column2[i]] = element[i];
+                            for ( i = startNonLinear_[iNon]; i < startNonLinear_[iNon+1]; i++) {
+                                OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[whichNonLinear_[i]]);
+                                assert (obj);
+                                int xColumn = obj->xColumn();
+                                int yColumn = obj->yColumn();
+                                if (xColumn != yColumn) {
+                                    double coefficient = /* 2.0* */obj->coefficient();
+                                    gradient[xColumn] += coefficient * solution[yColumn];
+                                    gradient[yColumn] += coefficient * solution[xColumn];
+                                    offset += coefficient * solution[xColumn] * solution[yColumn];
+                                } else {
+                                    double coefficient = obj->coefficient();
+                                    gradient[xColumn] += 2.0 * coefficient * solution[yColumn];
+                                    offset += coefficient * solution[xColumn] * solution[yColumn];
+                                }
+                            }
+                            // assume convex
+                            double rhs = 0.0;
+                            int n = 0;
+                            for (int i = 0; i < numberColumns2; i++) {
+                                double value = gradient[i];
+                                if (fabs(value) > 1.0e-12) {
+                                    gradient[n] = value;
+                                    rhs += value * solution[i];
+                                    column[n++] = i;
+                                }
+                            }
+                            if (iRow == objectiveRow_) {
+                                gradient[n] = -1.0;
+                                assert (objectiveVariable_ >= 0);
+                                rhs -= solution[objectiveVariable_];
+                                column[n++] = objectiveVariable_;
+                                assert (convex);
+                            } else if (convex) {
+                                offset += rowUpper[iRow];
+                            } else if (!convex) {
+                                offset += rowLower[iRow];
+                            }
+                            if (convex && rhs > offset + 1.0e-5)
+                                gen2->addCut(-COIN_DBL_MAX, offset + 1.0e-7, n, column, gradient);
+                            else if (!convex && rhs < offset - 1.0e-5)
+                                gen2->addCut(offset - 1.0e-7, COIN_DBL_MAX, n, column, gradient);
+                        }
+                        cbcModel_->unlockThread();
+                        delete [] gradient;
+                        delete [] column;
+                        break;
+                    }
+                }
+            }
+        }
+    } else {
+        modelPtr_->setProblemStatus(1);
+        modelPtr_->setObjectiveValue(COIN_DBL_MAX);
+    }
+}
+// Do OA cuts
+int
+OsiSolverLink::doAOCuts(CglTemporary * cutGen, const double * solution, const double * solution2)
+{
+    cbcModel_->lockThread();
+    // add OA cut
+    double offset = 0.0;
+    int numberColumns = quadraticModel_->numberColumns();
+    double * gradient = new double [numberColumns+1];
+    // gradient from bilinear
+    int i;
+    CoinZeroN(gradient, numberColumns + 1);
+    //const double * objective = modelPtr_->objective();
+    assert (objectiveRow_ >= 0);
+    const double * element = originalRowCopy_->getElements();
+    const int * column2 = originalRowCopy_->getIndices();
+    const CoinBigIndex * rowStart = originalRowCopy_->getVectorStarts();
+    //const int * rowLength = originalRowCopy_->getVectorLengths();
+    //int numberColumns2 = coinModel_.numberColumns();
+    for ( i = rowStart[objectiveRow_]; i < rowStart[objectiveRow_+1]; i++)
+        gradient[column2[i]] = element[i];
+    //const double * columnLower = modelPtr_->columnLower();
+    //const double * columnUpper = modelPtr_->columnUpper();
+    for ( i = 0; i < numberObjects_; i++) {
+        OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+        if (obj) {
+            int xColumn = obj->xColumn();
+            int yColumn = obj->yColumn();
+            if (xColumn != yColumn) {
+                double coefficient = /* 2.0* */obj->coefficient();
+                gradient[xColumn] += coefficient * solution2[yColumn];
+                gradient[yColumn] += coefficient * solution2[xColumn];
+                offset += coefficient * solution2[xColumn] * solution2[yColumn];
+            } else {
+                double coefficient = obj->coefficient();
+                gradient[xColumn] += 2.0 * coefficient * solution2[yColumn];
+                offset += coefficient * solution2[xColumn] * solution2[yColumn];
+            }
+        }
+    }
+    // assume convex
+    double rhs = 0.0;
+    int * column = new int[numberColumns+1];
+    int n = 0;
+    for (int i = 0; i < numberColumns; i++) {
+        double value = gradient[i];
+        if (fabs(value) > 1.0e-12) {
+            gradient[n] = value;
+            rhs += value * solution[i];
+            column[n++] = i;
+        }
+    }
+    gradient[n] = -1.0;
+    assert (objectiveVariable_ >= 0);
+    rhs -= solution[objectiveVariable_];
+    column[n++] = objectiveVariable_;
+    int returnCode = 0;
+    if (rhs > offset + 1.0e-5) {
+        cutGen->addCut(-COIN_DBL_MAX, offset + 1.0e-7, n, column, gradient);
+        //printf("added cut with %d elements\n",n);
+        returnCode = 1;
+    }
+    delete [] gradient;
+    delete [] column;
+    cbcModel_->unlockThread();
+    return returnCode;
+}
+
+//#############################################################################
+// Constructors, destructors clone and assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+OsiSolverLink::OsiSolverLink ()
+        : CbcOsiSolver()
+{
+    gutsOfDestructor(true);
+}
+#ifdef JJF_ZERO
+/* returns
+   sequence of nonlinear or
+   -1 numeric
+   -2 not found
+   -3 too many terms
+*/
+static int getVariable(const CoinModel & model, char * expression,
+                       int & linear)
+{
+    int non = -1;
+    linear = -1;
+    if (strcmp(expression, "Numeric")) {
+        // function
+        char * first = strchr(expression, '*');
+        int numberColumns = model.numberColumns();
+        int j;
+        if (first) {
+            *first = '\0';
+            for (j = 0; j < numberColumns; j++) {
+                if (!strcmp(expression, model.columnName(j))) {
+                    linear = j;
+                    memmove(expression, first + 1, strlen(first + 1) + 1);
+                    break;
+                }
+            }
+        }
+        // find nonlinear
+        for (j = 0; j < numberColumns; j++) {
+            const char * name = model.columnName(j);
+            first = strstr(expression, name);
+            if (first) {
+                if (first != expression && isalnum(*(first - 1)))
+                    continue; // not real match
+                first += strlen(name);
+                if (!isalnum(*first)) {
+                    // match
+                    non = j;
+                    // but check no others
+                    j++;
+                    for (; j < numberColumns; j++) {
+                        const char * name = model.columnName(j);
+                        first = strstr(expression, name);
+                        if (first) {
+                            if (isalnum(*(first - 1)))
+                                continue; // not real match
+                            first += strlen(name);
+                            if (!isalnum(*first)) {
+                                // match - ouch
+                                non = -3;
+                                break;
+                            }
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+        if (non == -1)
+            non = -2;
+    }
+    return non;
+}
+#endif
+/* This creates from a coinModel object
+
+   if errors.then number of sets is -1
+
+   This creates linked ordered sets information.  It assumes -
+
+   for product terms syntax is yy*f(zz)
+   also just f(zz) is allowed
+   and even a constant
+
+   modelObject not const as may be changed as part of process.
+*/
+OsiSolverLink::OsiSolverLink ( CoinModel & coinModel)
+        : CbcOsiSolver()
+{
+    gutsOfDestructor(true);
+    load(coinModel);
+}
+// need bounds
+static void fakeBounds(OsiSolverInterface * solver, int column, double maximumValue,
+                       CoinModel * model1, CoinModel * model2)
+{
+    double lo = solver->getColLower()[column];
+    if (lo < -maximumValue) {
+        solver->setColLower(column, -maximumValue);
+        if (model1)
+            model1->setColLower(column, -maximumValue);
+        if (model2)
+            model2->setColLower(column, -maximumValue);
+    }
+    double up = solver->getColUpper()[column];
+    if (up > maximumValue) {
+        solver->setColUpper(column, maximumValue);
+        if (model1)
+            model1->setColUpper(column, maximumValue);
+        if (model2)
+            model2->setColUpper(column, maximumValue);
+    }
+}
+void OsiSolverLink::load ( CoinModel & coinModelOriginal, bool tightenBounds, int logLevel)
+{
+    // first check and set up arrays
+    int numberColumns = coinModelOriginal.numberColumns();
+    int numberRows = coinModelOriginal.numberRows();
+    // List of nonlinear entries
+    int * which = new int[numberColumns];
+    numberVariables_ = 0;
+    //specialOptions2_=0;
+    int iColumn;
+    int numberErrors = 0;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        CoinModelLink triple = coinModelOriginal.firstInColumn(iColumn);
+        bool linear = true;
+        int n = 0;
+        // See if quadratic objective
+        const char * expr = coinModelOriginal.getColumnObjectiveAsString(iColumn);
+        if (strcmp(expr, "Numeric")) {
+            linear = false;
+        }
+        while (triple.row() >= 0) {
+            int iRow = triple.row();
+            const char * expr = coinModelOriginal.getElementAsString(iRow, iColumn);
+            if (strcmp(expr, "Numeric")) {
+                linear = false;
+            }
+            triple = coinModelOriginal.next(triple);
+            n++;
+        }
+        if (!linear) {
+            which[numberVariables_++] = iColumn;
+        }
+    }
+    // return if nothing
+    if (!numberVariables_) {
+        delete [] which;
+        coinModel_ = coinModelOriginal;
+        int nInt = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (coinModel_.isInteger(iColumn))
+                nInt++;
+        }
+        printf("There are %d integers\n", nInt);
+        loadFromCoinModel(coinModelOriginal, true);
+        OsiObject ** objects = new OsiObject * [nInt];
+        nInt = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (coinModel_.isInteger(iColumn)) {
+                objects[nInt] = new OsiSimpleInteger(this, iColumn);
+                objects[nInt]->setPriority(integerPriority_);
+                nInt++;
+            }
+        }
+        addObjects(nInt, objects);
+        int i;
+        for (i = 0; i < nInt; i++)
+            delete objects[i];
+        delete [] objects;
+        return;
+    } else {
+        coinModel_ = coinModelOriginal;
+        // arrays for tightening bounds
+        int * freeRow = new int [numberRows];
+        CoinZeroN(freeRow, numberRows);
+        int * tryColumn = new int [numberColumns];
+        CoinZeroN(tryColumn, numberColumns);
+        int nBi = 0;
+        int numberQuadratic = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            // See if quadratic objective
+            const char * expr = coinModel_.getColumnObjectiveAsString(iColumn);
+            if (strcmp(expr, "Numeric")) {
+                // check if value*x+-value*y....
+                assert (strlen(expr) < 20000);
+                tryColumn[iColumn] = 1;
+                char temp[20000];
+                strcpy(temp, expr);
+                char * pos = temp;
+                bool ifFirst = true;
+                double linearTerm = 0.0;
+                while (*pos) {
+                    double value;
+                    int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel_);
+                    // must be column unless first when may be linear term
+                    if (jColumn >= 0) {
+                        tryColumn[jColumn] = 1;
+                        numberQuadratic++;
+                        nBi++;
+                    } else if (jColumn == -2) {
+                        linearTerm = value;
+                    } else {
+                        printf("bad nonlinear term %s\n", temp);
+                        abort();
+                    }
+                    ifFirst = false;
+                }
+                coinModelOriginal.setObjective(iColumn, linearTerm);
+            }
+        }
+        int iRow;
+        int saveNBi = nBi;
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            CoinModelLink triple = coinModel_.firstInRow(iRow);
+            while (triple.column() >= 0) {
+                int iColumn = triple.column();
+                const char *  el = coinModel_.getElementAsString(iRow, iColumn);
+                if (strcmp("Numeric", el)) {
+                    // check if value*x+-value*y....
+                    assert (strlen(el) < 20000);
+                    char temp[20000];
+                    strcpy(temp, el);
+                    char * pos = temp;
+                    bool ifFirst = true;
+                    double linearTerm = 0.0;
+                    tryColumn[iColumn] = 1;
+                    freeRow[iRow] = 1;
+                    while (*pos) {
+                        double value;
+                        int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel_);
+                        // must be column unless first when may be linear term
+                        if (jColumn >= 0) {
+                            tryColumn[jColumn] = 1;
+                            nBi++;
+                        } else if (jColumn == -2) {
+                            linearTerm = value;
+                        } else {
+                            printf("bad nonlinear term %s\n", temp);
+                            abort();
+                        }
+                        ifFirst = false;
+                    }
+                    coinModelOriginal.setElement(iRow, iColumn, linearTerm);
+                }
+                triple = coinModel_.next(triple);
+            }
+        }
+        if (!nBi)
+            exit(1);
+        bool quadraticObjective = false;
+        int nInt = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (coinModel_.isInteger(iColumn))
+                nInt++;
+        }
+        printf("There are %d bilinear and %d integers\n", nBi, nInt);
+        loadFromCoinModel(coinModelOriginal, true);
+        CoinModel coinModel = coinModelOriginal;
+        if (tightenBounds && numberColumns < 100) {
+            // first fake bounds
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (tryColumn[iColumn]) {
+                    fakeBounds(this, iColumn, defaultBound_, &coinModel, &coinModel_);
+                }
+            }
+            ClpSimplex tempModel(*modelPtr_);
+            int nDelete = 0;
+            for (iRow = 0; iRow < numberRows; iRow++) {
+                if (freeRow[iRow])
+                    freeRow[nDelete++] = iRow;
+            }
+            tempModel.deleteRows(nDelete, freeRow);
+            tempModel.setOptimizationDirection(1.0);
+            if (logLevel < 3) {
+                tempModel.setLogLevel(0);
+                tempModel.setSpecialOptions(32768);
+            }
+            double * objective = tempModel.objective();
+            CoinZeroN(objective, numberColumns);
+            // now up and down
+            double * columnLower = modelPtr_->columnLower();
+            double * columnUpper = modelPtr_->columnUpper();
+            const double * solution = tempModel.primalColumnSolution();
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (tryColumn[iColumn]) {
+                    objective[iColumn] = 1.0;
+                    tempModel.primal(1);
+                    if (solution[iColumn] > columnLower[iColumn] + 1.0e-3) {
+                        double value = solution[iColumn];
+                        if (coinModel_.isInteger(iColumn))
+                            value = ceil(value - 0.9e-3);
+                        if (logLevel > 1)
+                            printf("lower bound on %d changed from %g to %g\n", iColumn, columnLower[iColumn], value);
+                        columnLower[iColumn] = value;
+                        coinModel_.setColumnLower(iColumn, value);
+                        coinModel.setColumnLower(iColumn, value);
+                    }
+                    objective[iColumn] = -1.0;
+                    tempModel.primal(1);
+                    if (solution[iColumn] < columnUpper[iColumn] - 1.0e-3) {
+                        double value = solution[iColumn];
+                        if (coinModel_.isInteger(iColumn))
+                            value = floor(value + 0.9e-3);
+                        if (logLevel > 1)
+                            printf("upper bound on %d changed from %g to %g\n", iColumn, columnUpper[iColumn], value);
+                        columnUpper[iColumn] = value;
+                        coinModel_.setColumnUpper(iColumn, value);
+                        coinModel.setColumnUpper(iColumn, value);
+                    }
+                    objective[iColumn] = 0.0;
+                }
+            }
+        }
+        delete [] freeRow;
+        delete [] tryColumn;
+        CoinBigIndex * startQuadratic = NULL;
+        int * columnQuadratic = NULL;
+        double * elementQuadratic = NULL;
+        if ( saveNBi == nBi) {
+            printf("all bilinearity in objective\n");
+            specialOptions2_ |= 2;
+            quadraticObjective = true;
+            // save copy as quadratic model
+            quadraticModel_ = new ClpSimplex(*modelPtr_);
+            startQuadratic = new CoinBigIndex [numberColumns+1];
+            columnQuadratic = new int [numberQuadratic];
+            elementQuadratic = new double [numberQuadratic];
+            numberQuadratic = 0;
+        }
+        //if (quadraticObjective||((specialOptions2_&8)!=0&&saveNBi)) {
+        if (saveNBi) {
+            // add in objective as constraint
+            objectiveVariable_ = numberColumns;
+            objectiveRow_ = coinModel.numberRows();
+            coinModel.addColumn(0, NULL, NULL, -COIN_DBL_MAX, COIN_DBL_MAX, 1.0);
+            int * column = new int[numberColumns+1];
+            double * element = new double[numberColumns+1];
+            double * objective = coinModel.objectiveArray();
+            int n = 0;
+            for (int i = 0; i < numberColumns; i++) {
+                if (objective[i]) {
+                    column[n] = i;
+                    element[n++] = objective[i];
+                    objective[i] = 0.0;
+                }
+            }
+            column[n] = objectiveVariable_;
+            element[n++] = -1.0;
+            double offset = - coinModel.objectiveOffset();
+            //assert (!offset); // get sign right if happens
+            printf("***** offset %g\n", offset);
+            coinModel.setObjectiveOffset(0.0);
+            double lowerBound = -COIN_DBL_MAX;
+            coinModel.addRow(n, column, element, lowerBound, offset);
+            delete [] column;
+            delete [] element;
+        }
+        OsiObject ** objects = new OsiObject * [nBi+nInt];
+        char * marked = new char [numberColumns];
+        memset(marked, 0, numberColumns);
+        // statistics I-I I-x x-x
+        int stats[3] = {0, 0, 0};
+        double * sort = new double [nBi];
+        nBi = nInt;
+        const OsiObject ** justBi = const_cast<const OsiObject **> (objects + nInt);
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (quadraticObjective)
+                startQuadratic[iColumn] = numberQuadratic;
+            // See if quadratic objective
+            const char * expr = coinModel_.getColumnObjectiveAsString(iColumn);
+            if (strcmp(expr, "Numeric")) {
+                // need bounds
+                fakeBounds(this, iColumn, defaultBound_, &coinModel, &coinModel_);
+                // value*x*y
+                char temp[20000];
+                strcpy(temp, expr);
+                char * pos = temp;
+                bool ifFirst = true;
+                while (*pos) {
+                    double value;
+                    int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel_);
+                    // must be column unless first when may be linear term
+                    if (jColumn >= 0) {
+                        if (quadraticObjective) {
+                            columnQuadratic[numberQuadratic] = jColumn;
+                            if (jColumn == iColumn)
+                                elementQuadratic[numberQuadratic++] = 2.0 * value; // convention
+                            else
+                                elementQuadratic[numberQuadratic++] = 1.0 * value; // convention
+                        }
+                        // need bounds
+                        fakeBounds(this, jColumn, defaultBound_, &coinModel, &coinModel_);
+                        double meshI = coinModel_.isInteger(iColumn) ? 1.0 : 0.0;
+                        if (meshI)
+                            marked[iColumn] = 1;
+                        double meshJ = coinModel_.isInteger(jColumn) ? 1.0 : 0.0;
+                        if (meshJ)
+                            marked[jColumn] = 1;
+                        // stats etc
+                        if (meshI) {
+                            if (meshJ)
+                                stats[0]++;
+                            else
+                                stats[1]++;
+                        } else {
+                            if (meshJ)
+                                stats[1]++;
+                            else
+                                stats[2]++;
+                        }
+                        if (iColumn <= jColumn)
+                            sort[nBi-nInt] = iColumn + numberColumns * jColumn;
+                        else
+                            sort[nBi-nInt] = jColumn + numberColumns * iColumn;
+                        if (!meshJ && !meshI) {
+                            meshI = defaultMeshSize_;
+                            meshJ = 0.0;
+                        }
+                        OsiBiLinear * newObj = new OsiBiLinear(&coinModel, iColumn, jColumn, objectiveRow_, value, meshI, meshJ,
+                                                               nBi - nInt, justBi);
+                        newObj->setPriority(biLinearPriority_);
+                        objects[nBi++] = newObj;
+                    } else if (jColumn == -2) {
+                    } else {
+                        printf("bad nonlinear term %s\n", temp);
+                        abort();
+                    }
+                    ifFirst = false;
+                }
+            }
+        }
+        // stats
+        printf("There were %d I-I, %d I-x and %d x-x bilinear in objective\n",
+               stats[0], stats[1], stats[2]);
+        if (quadraticObjective) {
+            startQuadratic[numberColumns] = numberQuadratic;
+            quadraticModel_->loadQuadraticObjective(numberColumns, startQuadratic,
+                                                    columnQuadratic, elementQuadratic);
+            delete [] startQuadratic;
+            delete [] columnQuadratic;
+            delete [] elementQuadratic;
+        }
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            CoinModelLink triple = coinModel_.firstInRow(iRow);
+            while (triple.column() >= 0) {
+                int iColumn = triple.column();
+                const char *  el = coinModel_.getElementAsString(iRow, iColumn);
+                if (strcmp("Numeric", el)) {
+                    // need bounds
+                    fakeBounds(this, iColumn, defaultBound_, &coinModel, &coinModel_);
+                    // value*x*y
+                    char temp[20000];
+                    strcpy(temp, el);
+                    char * pos = temp;
+                    bool ifFirst = true;
+                    while (*pos) {
+                        double value;
+                        int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel_);
+                        // must be column unless first when may be linear term
+                        if (jColumn >= 0) {
+                            // need bounds
+                            fakeBounds(this, jColumn, defaultBound_, &coinModel, &coinModel_);
+                            double meshI = coinModel_.isInteger(iColumn) ? 1.0 : 0.0;
+                            if (meshI)
+                                marked[iColumn] = 1;
+                            double meshJ = coinModel_.isInteger(jColumn) ? 1.0 : 0.0;
+                            if (meshJ)
+                                marked[jColumn] = 1;
+                            // stats etc
+                            if (meshI) {
+                                if (meshJ)
+                                    stats[0]++;
+                                else
+                                    stats[1]++;
+                            } else {
+                                if (meshJ)
+                                    stats[1]++;
+                                else
+                                    stats[2]++;
+                            }
+                            if (iColumn <= jColumn)
+                                sort[nBi-nInt] = iColumn + numberColumns * jColumn;
+                            else
+                                sort[nBi-nInt] = jColumn + numberColumns * iColumn;
+                            if (!meshJ && !meshI) {
+                                meshI = defaultMeshSize_;
+                                meshJ = 0.0;
+                            }
+                            OsiBiLinear * newObj = new OsiBiLinear(&coinModel, iColumn, jColumn, iRow, value, meshI, meshJ,
+                                                                   nBi - nInt, justBi);
+                            newObj->setPriority(biLinearPriority_);
+                            objects[nBi++] = newObj;
+                        } else if (jColumn == -2) {
+                        } else {
+                            printf("bad nonlinear term %s\n", temp);
+                            abort();
+                        }
+                        ifFirst = false;
+                    }
+                }
+                triple = coinModel_.next(triple);
+            }
+        }
+        {
+            // stats
+            std::sort(sort, sort + nBi - nInt);
+            int nDiff = 0;
+            double last = -1.0;
+            for (int i = 0; i < nBi - nInt; i++) {
+                if (sort[i] != last)
+                    nDiff++;
+                last = sort[i];
+            }
+            delete [] sort;
+            printf("There were %d I-I, %d I-x and %d x-x bilinear in total of which %d were duplicates\n",
+                   stats[0], stats[1], stats[2], nBi - nInt - nDiff);
+        }
+        // reload with all bilinear stuff
+        loadFromCoinModel(coinModel, true);
+        //exit(77);
+        nInt = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (coinModel_.isInteger(iColumn)) {
+                objects[nInt] = new OsiSimpleInteger(this, iColumn);
+                if (marked[iColumn])
+                    objects[nInt]->setPriority(integerPriority_);
+                else
+                    objects[nInt]->setPriority(integerPriority_);
+                nInt++;
+            }
+        }
+        nInt = nBi;
+        delete [] marked;
+        if (numberErrors) {
+            // errors
+            gutsOfDestructor();
+            numberVariables_ = -1;
+        } else {
+            addObjects(nInt, objects);
+            int i;
+            for (i = 0; i < nInt; i++)
+                delete objects[i];
+            delete [] objects;
+            // Now do dummy bound stuff
+            matrix_ = new CoinPackedMatrix(*getMatrixByCol());
+            info_ = new OsiLinkedBound [numberVariables_];
+            for ( i = 0; i < numberVariables_; i++) {
+                info_[i] = OsiLinkedBound(this, which[i], 0, NULL, NULL, NULL);
+            }
+            // Do row copy but just part
+            int numberRows2 = objectiveRow_ >= 0 ? numberRows + 1 : numberRows;
+            int * whichRows = new int [numberRows2];
+            int * whichColumns = new int [numberColumns];
+            CoinIotaN(whichRows, numberRows2, 0);
+            CoinIotaN(whichColumns, numberColumns, 0);
+            originalRowCopy_ = new CoinPackedMatrix(*getMatrixByRow(),
+                                                    numberRows2, whichRows,
+                                                    numberColumns, whichColumns);
+            delete [] whichColumns;
+            numberNonLinearRows_ = 0;
+            CoinZeroN(whichRows, numberRows2);
+            for ( i = 0; i < numberObjects_; i++) {
+                OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+                if (obj) {
+                    int xyRow = obj->xyRow();
+                    assert (xyRow >= 0 && xyRow < numberRows2); // even if obj we should move
+                    whichRows[xyRow]++;
+                }
+            }
+            int * pos = new int [numberRows2];
+            int n = 0;
+            for (i = 0; i < numberRows2; i++) {
+                if (whichRows[i]) {
+                    pos[numberNonLinearRows_] = n;
+                    n += whichRows[i];
+                    whichRows[i] = numberNonLinearRows_;
+                    numberNonLinearRows_++;
+                } else {
+                    whichRows[i] = -1;
+                }
+            }
+            startNonLinear_ = new int [numberNonLinearRows_+1];
+            memcpy(startNonLinear_, pos, numberNonLinearRows_*sizeof(int));
+            startNonLinear_[numberNonLinearRows_] = n;
+            rowNonLinear_ = new int [numberNonLinearRows_];
+            convex_ = new int [numberNonLinearRows_];
+            // do row numbers now
+            numberNonLinearRows_ = 0;
+            for (i = 0; i < numberRows2; i++) {
+                if (whichRows[i] >= 0) {
+                    rowNonLinear_[numberNonLinearRows_++] = i;
+                }
+            }
+            whichNonLinear_ = new int [n];
+            for ( i = 0; i < numberObjects_; i++) {
+                OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+                if (obj) {
+                    int xyRow = obj->xyRow();
+                    int k = whichRows[xyRow];
+                    int put = pos[k];
+                    pos[k]++;
+                    whichNonLinear_[put] = i;
+                }
+            }
+            delete [] pos;
+            delete [] whichRows;
+            analyzeObjects();
+        }
+    }
+    // See if there are any quadratic bounds
+    int nQ = 0;
+    const CoinPackedMatrix * rowCopy = getMatrixByRow();
+    //const double * element = rowCopy->getElements();
+    //const int * column = rowCopy->getIndices();
+    //const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+    const int * rowLength = rowCopy->getVectorLengths();
+    const double * rowLower = getRowLower();
+    const double * rowUpper = getRowUpper();
+    for (int iObject = 0; iObject < numberObjects_; iObject++) {
+        OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[iObject]);
+        if (obj) {
+            int xyRow = obj->xyRow();
+            if (rowLength[xyRow] == 4 && false) {
+                // we have simple bound
+                nQ++;
+                double coefficient = obj->coefficient();
+                double lo = rowLower[xyRow];
+                double up = rowUpper[xyRow];
+                if (coefficient != 1.0) {
+                    printf("*** double check code here\n");
+                    if (coefficient < 0.0) {
+                        double temp = lo;
+                        lo = - up;
+                        up = - temp;
+                        coefficient = - coefficient;
+                    }
+                    if (lo > -1.0e20)
+                        lo /= coefficient;
+                    if (up < 1.0e20)
+                        up /= coefficient;
+                    setRowLower(xyRow, lo);
+                    setRowUpper(xyRow, up);
+                    // we also need to change elements in matrix_
+                }
+                int type = 0;
+                if (lo == up) {
+                    // good news
+                    type = 3;
+                    coefficient = lo;
+                } else if (lo < -1.0e20) {
+                    assert (up < 1.0e20);
+                    coefficient = up;
+                    type = 1;
+                    // can we make equality?
+                } else if (up > 1.0e20) {
+                    coefficient = lo;
+                    type = 2;
+                    // can we make equality?
+                } else {
+                    // we would need extra code
+                    abort();
+                }
+                obj->setBoundType(type);
+                obj->setCoefficient(coefficient);
+                // can do better if integer?
+                assert (!isInteger(obj->xColumn()));
+                assert (!isInteger(obj->yColumn()));
+            }
+        }
+    }
+    delete [] which;
+    if ((specialOptions2_&16) != 0)
+        addTighterConstraints();
+}
+// Add reformulated bilinear constraints
+void
+OsiSolverLink::addTighterConstraints()
+{
+    // This is first attempt - for now get working on trimloss
+    int numberW = 0;
+    int * xW = new int[numberObjects_];
+    int * yW = new int[numberObjects_];
+    // Points to firstlambda
+    int * wW = new int[numberObjects_];
+    // Coefficient
+    double * alphaW = new double[numberObjects_];
+    // Objects
+    OsiBiLinear ** objW = new OsiBiLinear * [numberObjects_];
+    int numberColumns = getNumCols();
+    int firstLambda = numberColumns;
+    // set up list (better to rethink and do properly as column ordered)
+    int * list = new int[numberColumns];
+    memset(list, 0, numberColumns*sizeof(int));
+    int i;
+    for ( i = 0; i < numberObjects_; i++) {
+        OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+        if (obj) {
+            //obj->setBranchingStrategy(4); // ***** temp
+            objW[numberW] = obj;
+            xW[numberW] = obj->xColumn();
+            yW[numberW] = obj->yColumn();
+            list[xW[numberW]] = 1;
+            list[yW[numberW]] = 1;
+            wW[numberW] = obj->firstLambda();
+            firstLambda = CoinMin(firstLambda, obj->firstLambda());
+            alphaW[numberW] = obj->coefficient();
+            //assert (alphaW[numberW]==1.0); // fix when occurs
+            numberW++;
+        }
+    }
+    int nList = 0;
+    for (i = 0; i < numberColumns; i++) {
+        if (list[i])
+            list[nList++] = i;
+    }
+    // set up mark array
+    char * mark = new char [firstLambda*firstLambda];
+    memset(mark, 0, firstLambda*firstLambda);
+    for (i = 0; i < numberW; i++) {
+        int x = xW[i];
+        int y = yW[i];
+        mark[x*firstLambda+y] = 1;
+        mark[y*firstLambda+x] = 1;
+    }
+    int numberRows2 = originalRowCopy_->getNumRows();
+    int * addColumn = new int [numberColumns];
+    double * addElement = new double [numberColumns];
+    int * addW = new int [numberColumns];
+    assert (objectiveRow_ < 0); // fix when occurs
+    for (int iRow = 0; iRow < numberRows2; iRow++) {
+        for (int iList = 0; iList < nList; iList++) {
+            int kColumn = list[iList];
+#ifndef NDEBUG
+            const double * columnLower = getColLower();
+#endif
+            //const double * columnUpper = getColUpper();
+            const double * rowLower = getRowLower();
+            const double * rowUpper = getRowUpper();
+            const CoinPackedMatrix * rowCopy = getMatrixByRow();
+            const double * element = rowCopy->getElements();
+            const int * column = rowCopy->getIndices();
+            const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+            const int * rowLength = rowCopy->getVectorLengths();
+            CoinBigIndex j;
+            int numberElements = rowLength[iRow];
+            int n = 0;
+            for (j = rowStart[iRow]; j < rowStart[iRow] + numberElements; j++) {
+                int iColumn = column[j];
+                if (iColumn >= firstLambda) {
+                    // no good
+                    n = -1;
+                    break;
+                }
+                if (mark[iColumn*firstLambda+kColumn])
+                    n++;
+            }
+            if (n == numberElements) {
+                printf("can add row %d\n", iRow);
+                assert (columnLower[kColumn] >= 0); // might be able to fix
+                n = 0;
+                for (j = rowStart[iRow]; j < rowStart[iRow] + numberElements; j++) {
+                    int xColumn = kColumn;
+                    int yColumn = column[j];
+                    int k;
+                    for (k = 0; k < numberW; k++) {
+                        if ((xW[k] == yColumn && yW[k] == xColumn) ||
+                                (yW[k] == yColumn && xW[k] == xColumn))
+                            break;
+                    }
+                    assert (k < numberW);
+                    if (xW[k] != xColumn) {
+                        int temp = xColumn;
+                        xColumn = yColumn;
+                        yColumn = temp;
+                    }
+                    addW[n/4] = k;
+                    int start = wW[k];
+                    double value = element[j];
+                    for (int kk = 0; kk < 4; kk++) {
+                        // Dummy value
+                        addElement[n] = value;
+                        addColumn[n++] = start + kk;
+                    }
+                }
+                addColumn[n++] = kColumn;
+                double lo = rowLower[iRow];
+                double up = rowUpper[iRow];
+                if (lo > -1.0e20) {
+                    // and tell object
+                    for (j = 0; j < n - 1; j += 4) {
+                        int iObject = addW[j/4];
+                        objW[iObject]->addExtraRow(matrix_->getNumRows(), addElement[j]);
+                    }
+                    addElement[n-1] = -lo;
+                    if (lo == up)
+                        addRow(n, addColumn, addElement, 0.0, 0.0);
+                    else
+                        addRow(n, addColumn, addElement, 0.0, COIN_DBL_MAX);
+                    matrix_->appendRow(n, addColumn, addElement);
+                }
+                if (up<1.0e20 && up>lo) {
+                    // and tell object
+                    for (j = 0; j < n - 1; j += 4) {
+                        int iObject = addW[j/4];
+                        objW[iObject]->addExtraRow(matrix_->getNumRows(), addElement[j]);
+                    }
+                    addElement[n-1] = -up;
+                    addRow(n, addColumn, addElement, -COIN_DBL_MAX, 0.0);
+                    matrix_->appendRow(n, addColumn, addElement);
+                }
+            }
+        }
+    }
+#ifdef JJF_ZERO
+    // possibly do bounds
+    for (int iColumn = 0; iColumn < firstLambda; iColumn++) {
+        for (int iList = 0; iList < nList; iList++) {
+            int kColumn = list[iList];
+            const double * columnLower = getColLower();
+            const double * columnUpper = getColUpper();
+            if (mark[iColumn*firstLambda+kColumn]) {
+                printf("can add column %d\n", iColumn);
+                assert (columnLower[kColumn] >= 0); // might be able to fix
+                int xColumn = kColumn;
+                int yColumn = iColumn;
+                int k;
+                for (k = 0; k < numberW; k++) {
+                    if ((xW[k] == yColumn && yW[k] == xColumn) ||
+                            (yW[k] == yColumn && xW[k] == xColumn))
+                        break;
+                }
+                assert (k < numberW);
+                if (xW[k] != xColumn) {
+                    int temp = xColumn;
+                    xColumn = yColumn;
+                    yColumn = temp;
+                }
+                int start = wW[k];
+                int n = 0;
+                for (int kk = 0; kk < 4; kk++) {
+                    // Dummy value
+                    addElement[n] = 1.0e-19;
+                    addColumn[n++] = start + kk;
+                }
+                // Tell object about this
+                objW[k]->addExtraRow(matrix_->getNumRows(), 1.0);
+                addColumn[n++] = kColumn;
+                double lo = columnLower[iColumn];
+                double up = columnUpper[iColumn];
+                if (lo > -1.0e20) {
+                    addElement[n-1] = -lo;
+                    if (lo == up)
+                        addRow(n, addColumn, addElement, 0.0, 0.0);
+                    else
+                        addRow(n, addColumn, addElement, 0.0, COIN_DBL_MAX);
+                    matrix_->appendRow(n, addColumn, addElement);
+                }
+                if (up<1.0e20 && up>lo) {
+                    addElement[n-1] = -up;
+                    addRow(n, addColumn, addElement, -COIN_DBL_MAX, 0.0);
+                    matrix_->appendRow(n, addColumn, addElement);
+                }
+            }
+        }
+    }
+#endif
+    delete [] xW;
+    delete [] yW;
+    delete [] wW;
+    delete [] alphaW;
+    delete [] addColumn;
+    delete [] addElement;
+    delete [] addW;
+    delete [] mark;
+    delete [] list;
+    delete [] objW;
+}
+// Set all biLinear priorities on x-x variables
+void
+OsiSolverLink::setBiLinearPriorities(int value, double meshSize)
+{
+    OsiObject ** newObject = new OsiObject * [numberObjects_];
+    int numberOdd = 0;
+    int i;
+    for ( i = 0; i < numberObjects_; i++) {
+        OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+        if (obj) {
+            if (obj->xMeshSize() < 1.0 && obj->yMeshSize() < 1.0) {
+                double oldSatisfied = CoinMax(obj->xSatisfied(),
+                                              obj->ySatisfied());
+                OsiBiLinear * objNew = new OsiBiLinear(*obj);
+                newObject[numberOdd++] = objNew;
+                objNew->setXSatisfied(0.5*meshSize);
+                obj->setXOtherSatisfied(0.5*meshSize);
+                objNew->setXOtherSatisfied(oldSatisfied);
+                objNew->setXMeshSize(meshSize);
+                objNew->setYSatisfied(0.5*meshSize);
+                obj->setYOtherSatisfied(0.5*meshSize);
+                objNew->setYOtherSatisfied(oldSatisfied);
+                objNew->setYMeshSize(meshSize);
+                objNew->setXYSatisfied(0.25*meshSize);
+                objNew->setPriority(value);
+                objNew->setBranchingStrategy(8);
+            }
+        }
+    }
+    addObjects(numberOdd, newObject);
+    for (i = 0; i < numberOdd; i++)
+        delete newObject[i];
+    delete [] newObject;
+}
+/* Set options and priority on all or some biLinear variables
+   1 - on I-I
+   2 - on I-x
+   4 - on x-x
+      or combinations.
+      -1 means leave (for priority value and strategy value)
+*/
+void
+OsiSolverLink::setBranchingStrategyOnVariables(int strategyValue, int priorityValue,
+        int mode)
+{
+    int i;
+    for ( i = 0; i < numberObjects_; i++) {
+        OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+        if (obj) {
+            bool change = false;
+            if (obj->xMeshSize() < 1.0 && obj->yMeshSize() < 1.0 && (mode&4) != 0)
+                change = true;
+            else if (((obj->xMeshSize() == 1.0 && obj->yMeshSize() < 1.0) ||
+                      (obj->xMeshSize() < 1.0 && obj->yMeshSize() == 1.0)) && (mode&2) != 0)
+                change = true;
+            else if (obj->xMeshSize() == 1.0 && obj->yMeshSize() == 1.0 && (mode&1) != 0)
+                change = true;
+            else if (obj->xMeshSize() > 1.0 || obj->yMeshSize() > 1.0)
+                abort();
+            if (change) {
+                if (strategyValue >= 0)
+                    obj->setBranchingStrategy(strategyValue);
+                if (priorityValue >= 0)
+                    obj->setPriority(priorityValue);
+            }
+        }
+    }
+}
+
+// Say convex (should work it out)
+void
+OsiSolverLink::sayConvex(bool convex)
+{
+    specialOptions2_ |= 4;
+    if (convex_) {
+        for (int iNon = 0; iNon < numberNonLinearRows_; iNon++) {
+            convex_[iNon] = convex ? 1 : -1;
+        }
+    }
+}
+// Set all mesh sizes on x-x variables
+void
+OsiSolverLink::setMeshSizes(double value)
+{
+    int i;
+    for ( i = 0; i < numberObjects_; i++) {
+        OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[i]);
+        if (obj) {
+            if (obj->xMeshSize() < 1.0 && obj->yMeshSize() < 1.0) {
+#ifdef JJF_ZERO
+                numberContinuous++;
+                int xColumn = obj->xColumn();
+                double gapX = upper[xColumn] - lower[xColumn];
+                int yColumn = obj->yColumn();
+                double gapY = upper[yColumn] - lower[yColumn];
+                gap = CoinMax(gap, CoinMax(gapX, gapY));
+#endif
+                obj->setMeshSizes(this, value, value);
+            }
+        }
+    }
+}
+/* Solves nonlinear problem from CoinModel using SLP - may be used as crash
+   for other algorithms when number of iterations small.
+   Also exits if all problematical variables are changing
+   less than deltaTolerance
+   Returns solution array
+*/
+double *
+OsiSolverLink::nonlinearSLP(int numberPasses, double deltaTolerance)
+{
+    if (!coinModel_.numberRows()) {
+        printf("Model not set up or nonlinear arrays not created!\n");
+        return NULL;
+    }
+    // first check and set up arrays
+    int numberColumns = coinModel_.numberColumns();
+    int numberRows = coinModel_.numberRows();
+    char * markNonlinear = new char [numberColumns+numberRows];
+    CoinZeroN(markNonlinear, numberColumns + numberRows);
+    // List of nonlinear entries
+    int * listNonLinearColumn = new int[numberColumns];
+    // List of nonlinear constraints
+    int * whichRow = new int [numberRows];
+    CoinZeroN(whichRow, numberRows);
+    int numberNonLinearColumns = 0;
+    int iColumn;
+    CoinModel coinModel = coinModel_;
+    //const CoinModelHash * stringArray = coinModel.stringArray();
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        CoinModelLink triple = coinModel.firstInColumn(iColumn);
+        bool linear = true;
+        int n = 0;
+        // See if nonlinear objective
+        const char * expr = coinModel.getColumnObjectiveAsString(iColumn);
+        if (strcmp(expr, "Numeric")) {
+            linear = false;
+            // try and see which columns
+            assert (strlen(expr) < 20000);
+            char temp[20000];
+            strcpy(temp, expr);
+            char * pos = temp;
+            bool ifFirst = true;
+            while (*pos) {
+                double value;
+                int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel_);
+                // must be column unless first when may be linear term
+                if (jColumn >= 0) {
+                    markNonlinear[jColumn] = 1;
+                } else if (jColumn != -2) {
+                    printf("bad nonlinear term %s\n", temp);
+                    abort();
+                }
+                ifFirst = false;
+            }
+        }
+        while (triple.row() >= 0) {
+            int iRow = triple.row();
+            const char * expr = coinModel.getElementAsString(iRow, iColumn);
+            if (strcmp(expr, "Numeric")) {
+                linear = false;
+                whichRow[iRow]++;
+                // try and see which columns
+                assert (strlen(expr) < 20000);
+                char temp[20000];
+                strcpy(temp, expr);
+                char * pos = temp;
+                bool ifFirst = true;
+                while (*pos) {
+                    double value;
+                    int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel_);
+                    // must be column unless first when may be linear term
+                    if (jColumn >= 0) {
+                        markNonlinear[jColumn] = 1;
+                    } else if (jColumn != -2) {
+                        printf("bad nonlinear term %s\n", temp);
+                        abort();
+                    }
+                    ifFirst = false;
+                }
+            }
+            triple = coinModel.next(triple);
+            n++;
+        }
+        if (!linear) {
+            markNonlinear[iColumn] = 1;
+        }
+    }
+    //int xxxx[]={3,2,0,4,3,0};
+    //double initialSolution[6];
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        if (markNonlinear[iColumn]) {
+            // put in something
+            double lower = coinModel.columnLower(iColumn);
+            double upper = CoinMin(coinModel.columnUpper(iColumn), lower + 1000.0);
+            coinModel.associateElement(coinModel.columnName(iColumn), 0.5*(lower + upper));
+            //coinModel.associateElement(coinModel.columnName(iColumn),xxxx[iColumn]);
+            listNonLinearColumn[numberNonLinearColumns++] = iColumn;
+            //initialSolution[iColumn]=xxxx[iColumn];
+        }
+    }
+    // if nothing just solve
+    if (!numberNonLinearColumns) {
+        delete [] listNonLinearColumn;
+        delete [] whichRow;
+        delete [] markNonlinear;
+        ClpSimplex tempModel;
+        tempModel.loadProblem(coinModel, true);
+        tempModel.initialSolve();
+        double * solution = CoinCopyOfArray(tempModel.getColSolution(), numberColumns);
+        return solution;
+    }
+    // Create artificials
+    ClpSimplex tempModel;
+    tempModel.loadProblem(coinModel, true);
+    const double * rowLower = tempModel.rowLower();
+    const double * rowUpper = tempModel.rowUpper();
+    bool takeAll = false;
+    int iRow;
+    int numberArtificials = 0;
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        if (whichRow[iRow] || takeAll) {
+            if (rowLower[iRow] > -1.0e30)
+                numberArtificials++;
+            if (rowUpper[iRow] < 1.0e30)
+                numberArtificials++;
+        }
+    }
+    CoinBigIndex * startArtificial = new CoinBigIndex [numberArtificials+1];
+    int * rowArtificial = new int [numberArtificials];
+    double * elementArtificial = new double [numberArtificials];
+    double * objectiveArtificial = new double [numberArtificials];
+    numberArtificials = 0;
+    startArtificial[0] = 0;
+    double artificialCost = 1.0e9;
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        if (whichRow[iRow] || takeAll) {
+            if (rowLower[iRow] > -1.0e30) {
+                rowArtificial[numberArtificials] = iRow;
+                elementArtificial[numberArtificials] = 1.0;
+                objectiveArtificial[numberArtificials] = artificialCost;
+                numberArtificials++;
+                startArtificial[numberArtificials] = numberArtificials;
+            }
+            if (rowUpper[iRow] < 1.0e30) {
+                rowArtificial[numberArtificials] = iRow;
+                elementArtificial[numberArtificials] = -1.0;
+                objectiveArtificial[numberArtificials] = artificialCost;
+                numberArtificials++;
+                startArtificial[numberArtificials] = numberArtificials;
+            }
+        }
+    }
+    // Get first solution
+    int numberColumnsSmall = numberColumns;
+    ClpSimplex model;
+    model.loadProblem(coinModel, true);
+    model.addColumns(numberArtificials, NULL, NULL, objectiveArtificial,
+                     startArtificial, rowArtificial, elementArtificial);
+    double * columnLower = model.columnLower();
+    double * columnUpper = model.columnUpper();
+    double * trueLower = new double[numberNonLinearColumns];
+    double * trueUpper = new double[numberNonLinearColumns];
+    int jNon;
+    for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+        iColumn = listNonLinearColumn[jNon];
+        trueLower[jNon] = columnLower[iColumn];
+        trueUpper[jNon] = columnUpper[iColumn];
+        //columnLower[iColumn]=initialSolution[iColumn];
+        //columnUpper[iColumn]=initialSolution[iColumn];
+    }
+    model.initialSolve();
+    //model.writeMps("bad.mps");
+    // redo number of columns
+    numberColumns = model.numberColumns();
+    int * last[3];
+    double * solution = model.primalColumnSolution();
+
+    double * trust = new double[numberNonLinearColumns];
+    for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+        iColumn = listNonLinearColumn[jNon];
+        trust[jNon] = 0.5;
+        if (solution[iColumn] < trueLower[jNon])
+            solution[iColumn] = trueLower[jNon];
+        else if (solution[iColumn] > trueUpper[jNon])
+            solution[iColumn] = trueUpper[jNon];
+    }
+    int iPass;
+    double lastObjective = 1.0e31;
+    double * saveSolution = new double [numberColumns];
+    double * saveRowSolution = new double [numberRows];
+    memset(saveRowSolution, 0, numberRows*sizeof(double));
+    double * savePi = new double [numberRows];
+    double * safeSolution = new double [numberColumns];
+    unsigned char * saveStatus = new unsigned char[numberRows+numberColumns];
+    double targetDrop = 1.0e31;
+    //double objectiveOffset;
+    //model.getDblParam(ClpObjOffset,objectiveOffset);
+    // 1 bound up, 2 up, -1 bound down, -2 down, 0 no change
+    for (iPass = 0; iPass < 3; iPass++) {
+        last[iPass] = new int[numberNonLinearColumns];
+        for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+            last[iPass][jNon] = 0;
+    }
+    // goodMove +1 yes, 0 no, -1 last was bad - just halve gaps, -2 do nothing
+    int goodMove = -2;
+    char * statusCheck = new char[numberColumns];
+    double * changeRegion = new double [numberColumns];
+    int logLevel = 63;
+    double dualTolerance = model.dualTolerance();
+    double primalTolerance = model.primalTolerance();
+    int lastGoodMove = 1;
+    for (iPass = 0; iPass < numberPasses; iPass++) {
+        lastGoodMove = goodMove;
+        columnLower = model.columnLower();
+        columnUpper = model.columnUpper();
+        solution = model.primalColumnSolution();
+        double * rowActivity = model.primalRowSolution();
+        // redo objective
+        ClpSimplex tempModel;
+        // load new values
+        for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+            iColumn = listNonLinearColumn[jNon];
+            coinModel.associateElement(coinModel.columnName(iColumn), solution[iColumn]);
+        }
+        tempModel.loadProblem(coinModel);
+        double objectiveOffset;
+        tempModel.getDblParam(ClpObjOffset, objectiveOffset);
+        double objValue = -objectiveOffset;
+        const double * objective = tempModel.objective();
+        for (iColumn = 0; iColumn < numberColumnsSmall; iColumn++)
+            objValue += solution[iColumn] * objective[iColumn];
+        double * rowActivity2 = tempModel.primalRowSolution();
+        const double * rowLower2 = tempModel.rowLower();
+        const double * rowUpper2 = tempModel.rowUpper();
+        memset(rowActivity2, 0, numberRows*sizeof(double));
+        tempModel.times(1.0, solution, rowActivity2);
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            if (rowActivity2[iRow] < rowLower2[iRow] - primalTolerance)
+                objValue += (rowLower2[iRow] - rowActivity2[iRow] - primalTolerance) * artificialCost;
+            else if (rowActivity2[iRow] > rowUpper2[iRow] + primalTolerance)
+                objValue -= (rowUpper2[iRow] - rowActivity2[iRow] + primalTolerance) * artificialCost;
+        }
+        double theta = -1.0;
+        double maxTheta = COIN_DBL_MAX;
+        if (objValue <= lastObjective + 1.0e-15*fabs(lastObjective) || !iPass)
+            goodMove = 1;
+        else
+            goodMove = -1;
+        //maxTheta=1.0;
+        if (iPass) {
+            int jNon = 0;
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                changeRegion[iColumn] = solution[iColumn] - saveSolution[iColumn];
+                double alpha = changeRegion[iColumn];
+                double oldValue = saveSolution[iColumn];
+                if (markNonlinear[iColumn] == 0) {
+                    // linear
+                    if (alpha < -1.0e-15) {
+                        // variable going towards lower bound
+                        double bound = columnLower[iColumn];
+                        oldValue -= bound;
+                        if (oldValue + maxTheta*alpha < 0.0) {
+                            maxTheta = CoinMax(0.0, oldValue / (-alpha));
+                        }
+                    } else if (alpha > 1.0e-15) {
+                        // variable going towards upper bound
+                        double bound = columnUpper[iColumn];
+                        oldValue = bound - oldValue;
+                        if (oldValue - maxTheta*alpha < 0.0) {
+                            maxTheta = CoinMax(0.0, oldValue / alpha);
+                        }
+                    }
+                } else {
+                    // nonlinear
+                    if (alpha < -1.0e-15) {
+                        // variable going towards lower bound
+                        double bound = trueLower[jNon];
+                        oldValue -= bound;
+                        if (oldValue + maxTheta*alpha < 0.0) {
+                            maxTheta = CoinMax(0.0, oldValue / (-alpha));
+                        }
+                    } else if (alpha > 1.0e-15) {
+                        // variable going towards upper bound
+                        double bound = trueUpper[jNon];
+                        oldValue = bound - oldValue;
+                        if (oldValue - maxTheta*alpha < 0.0) {
+                            maxTheta = CoinMax(0.0, oldValue / alpha);
+                        }
+                    }
+                    jNon++;
+                }
+            }
+            // make sure both accurate
+            memset(rowActivity, 0, numberRows*sizeof(double));
+            model.times(1.0, solution, rowActivity);
+            memset(saveRowSolution, 0, numberRows*sizeof(double));
+            model.times(1.0, saveSolution, saveRowSolution);
+            for (int iRow = 0; iRow < numberRows; iRow++) {
+                double alpha = rowActivity[iRow] - saveRowSolution[iRow];
+                double oldValue = saveRowSolution[iRow];
+                if (alpha < -1.0e-15) {
+                    // variable going towards lower bound
+                    double bound = rowLower[iRow];
+                    oldValue -= bound;
+                    if (oldValue + maxTheta*alpha < 0.0) {
+                        maxTheta = CoinMax(0.0, oldValue / (-alpha));
+                    }
+                } else if (alpha > 1.0e-15) {
+                    // variable going towards upper bound
+                    double bound = rowUpper[iRow];
+                    oldValue = bound - oldValue;
+                    if (oldValue - maxTheta*alpha < 0.0) {
+                        maxTheta = CoinMax(0.0, oldValue / alpha);
+                    }
+                }
+            }
+        } else {
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                changeRegion[iColumn] = 0.0;
+                saveSolution[iColumn] = solution[iColumn];
+            }
+            memcpy(saveRowSolution, rowActivity, numberRows*sizeof(double));
+        }
+        if (goodMove >= 0) {
+            //theta = CoinMin(theta2,maxTheta);
+            theta = maxTheta;
+            if (theta > 0.0 && theta <= 1.0) {
+                // update solution
+                double lambda = 1.0 - theta;
+                for (iColumn = 0; iColumn < numberColumns; iColumn++)
+                    solution[iColumn] = lambda * saveSolution[iColumn]
+                                        + theta * solution[iColumn];
+                memset(rowActivity, 0, numberRows*sizeof(double));
+                model.times(1.0, solution, rowActivity);
+                if (lambda > 0.999) {
+                    memcpy(model.dualRowSolution(), savePi, numberRows*sizeof(double));
+                    memcpy(model.statusArray(), saveStatus, numberRows + numberColumns);
+                }
+                // redo rowActivity
+                memset(rowActivity, 0, numberRows*sizeof(double));
+                model.times(1.0, solution, rowActivity);
+            }
+        }
+        // load new values
+        for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+            iColumn = listNonLinearColumn[jNon];
+            coinModel.associateElement(coinModel.columnName(iColumn), solution[iColumn]);
+        }
+        double * sol2 = CoinCopyOfArray(model.primalColumnSolution(), numberColumns);
+        unsigned char * status2 = CoinCopyOfArray(model.statusArray(), numberColumns);
+        model.loadProblem(coinModel);
+        model.addColumns(numberArtificials, NULL, NULL, objectiveArtificial,
+                         startArtificial, rowArtificial, elementArtificial);
+        memcpy(model.primalColumnSolution(), sol2, numberColumns*sizeof(double));
+        memcpy(model.statusArray(), status2, numberColumns);
+        delete [] sol2;
+        delete [] status2;
+        columnLower = model.columnLower();
+        columnUpper = model.columnUpper();
+        solution = model.primalColumnSolution();
+        rowActivity = model.primalRowSolution();
+        int * temp = last[2];
+        last[2] = last[1];
+        last[1] = last[0];
+        last[0] = temp;
+        for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+            iColumn = listNonLinearColumn[jNon];
+            double change = solution[iColumn] - saveSolution[iColumn];
+            if (change < -1.0e-5) {
+                if (fabs(change + trust[jNon]) < 1.0e-5)
+                    temp[jNon] = -1;
+                else
+                    temp[jNon] = -2;
+            } else if (change > 1.0e-5) {
+                if (fabs(change - trust[jNon]) < 1.0e-5)
+                    temp[jNon] = 1;
+                else
+                    temp[jNon] = 2;
+            } else {
+                temp[jNon] = 0;
+            }
+        }
+        // goodMove +1 yes, 0 no, -1 last was bad - just halve gaps, -2 do nothing
+        double maxDelta = 0.0;
+        if (goodMove >= 0) {
+            if (objValue <= lastObjective + 1.0e-15*fabs(lastObjective))
+                goodMove = 1;
+            else
+                goodMove = 0;
+        } else {
+            maxDelta = 1.0e10;
+        }
+        double maxGap = 0.0;
+        int numberSmaller = 0;
+        int numberSmaller2 = 0;
+        int numberLarger = 0;
+        for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+            iColumn = listNonLinearColumn[jNon];
+            maxDelta = CoinMax(maxDelta,
+                               fabs(solution[iColumn] - saveSolution[iColumn]));
+            if (goodMove > 0) {
+                if (last[0][jNon]*last[1][jNon] < 0) {
+                    // halve
+                    trust[jNon] *= 0.5;
+                    numberSmaller2++;
+                } else {
+                    if (last[0][jNon] == last[1][jNon] &&
+                            last[0][jNon] == last[2][jNon])
+                        trust[jNon] = CoinMin(1.5 * trust[jNon], 1.0e6);
+                    numberLarger++;
+                }
+            } else if (goodMove != -2 && trust[jNon] > 10.0*deltaTolerance) {
+                trust[jNon] *= 0.2;
+                numberSmaller++;
+            }
+            maxGap = CoinMax(maxGap, trust[jNon]);
+        }
+#ifdef CLP_DEBUG
+        if (logLevel&32)
+            std::cout << "largest gap is " << maxGap << " "
+                      << numberSmaller + numberSmaller2 << " reduced ("
+                      << numberSmaller << " badMove ), "
+                      << numberLarger << " increased" << std::endl;
+#endif
+        if (iPass > 10000) {
+            for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+                trust[jNon] *= 0.0001;
+        }
+        printf("last good %d goodMove %d\n", lastGoodMove, goodMove);
+        if (goodMove > 0) {
+            double drop = lastObjective - objValue;
+            printf("Pass %d, objective %g - drop %g maxDelta %g\n", iPass, objValue, drop, maxDelta);
+            if (iPass > 20 && drop < 1.0e-12*fabs(objValue) && lastGoodMove > 0)
+                drop = 0.999e-4; // so will exit
+            if (maxDelta < deltaTolerance && drop < 1.0e-4 && goodMove && theta<0.99999 && lastGoodMove>0) {
+                if (logLevel > 1)
+                    std::cout << "Exiting as maxDelta < tolerance and small drop" << std::endl;
+                break;
+            }
+        } else if (!numberSmaller && iPass > 1) {
+            if (logLevel > 1)
+                std::cout << "Exiting as all gaps small" << std::endl;
+            break;
+        }
+        if (!iPass)
+            goodMove = 1;
+        targetDrop = 0.0;
+        double * r = model.dualColumnSolution();
+        for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+            iColumn = listNonLinearColumn[jNon];
+            columnLower[iColumn] = CoinMax(solution[iColumn]
+                                           - trust[jNon],
+                                           trueLower[jNon]);
+            columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                           + trust[jNon],
+                                           trueUpper[jNon]);
+        }
+        if (iPass) {
+            // get reduced costs
+            model.matrix()->transposeTimes(savePi,
+                                           model.dualColumnSolution());
+            const double * objective = model.objective();
+            for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                iColumn = listNonLinearColumn[jNon];
+                double dj = objective[iColumn] - r[iColumn];
+                r[iColumn] = dj;
+                if (dj < -dualTolerance)
+                    targetDrop -= dj * (columnUpper[iColumn] - solution[iColumn]);
+                else if (dj > dualTolerance)
+                    targetDrop -= dj * (columnLower[iColumn] - solution[iColumn]);
+            }
+        } else {
+            memset(r, 0, numberColumns*sizeof(double));
+        }
+#ifdef JJF_ZERO
+        for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+            iColumn = listNonLinearColumn[jNon];
+            if (statusCheck[iColumn] == 'L' && r[iColumn] < -1.0e-4) {
+                columnLower[iColumn] = CoinMax(solution[iColumn],
+                                               trueLower[jNon]);
+                columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                               + trust[jNon],
+                                               trueUpper[jNon]);
+            } else if (statusCheck[iColumn] == 'U' && r[iColumn] > 1.0e-4) {
+                columnLower[iColumn] = CoinMax(solution[iColumn]
+                                               - trust[jNon],
+                                               trueLower[jNon]);
+                columnUpper[iColumn] = CoinMin(solution[iColumn],
+                                               trueUpper[jNon]);
+            } else {
+                columnLower[iColumn] = CoinMax(solution[iColumn]
+                                               - trust[jNon],
+                                               trueLower[jNon]);
+                columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                               + trust[jNon],
+                                               trueUpper[jNon]);
+            }
+        }
+#endif
+        if (goodMove > 0) {
+            memcpy(saveSolution, solution, numberColumns*sizeof(double));
+            memcpy(saveRowSolution, rowActivity, numberRows*sizeof(double));
+            memcpy(savePi, model.dualRowSolution(), numberRows*sizeof(double));
+            memcpy(saveStatus, model.statusArray(), numberRows + numberColumns);
+
+#ifdef CLP_DEBUG
+            if (logLevel&32)
+                std::cout << "Pass - " << iPass
+                          << ", target drop is " << targetDrop
+                          << std::endl;
+#endif
+            lastObjective = objValue;
+            if (targetDrop < CoinMax(1.0e-8, CoinMin(1.0e-6, 1.0e-6*fabs(objValue))) && lastGoodMove && iPass > 3) {
+                if (logLevel > 1)
+                    printf("Exiting on target drop %g\n", targetDrop);
+                break;
+            }
+#ifdef CLP_DEBUG
+            {
+                double * r = model.dualColumnSolution();
+                for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                    iColumn = listNonLinearColumn[jNon];
+                    if (logLevel&32)
+                        printf("Trust %d %g - solution %d %g obj %g dj %g state %c - bounds %g %g\n",
+                               jNon, trust[jNon], iColumn, solution[iColumn], objective[iColumn],
+                               r[iColumn], statusCheck[iColumn], columnLower[iColumn],
+                               columnUpper[iColumn]);
+                }
+            }
+#endif
+            model.scaling(false);
+            model.primal(1);
+            for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                iColumn = listNonLinearColumn[jNon];
+                printf("%d bounds etc %g %g %g\n", iColumn, columnLower[iColumn], solution[iColumn], columnUpper[iColumn]);
+            }
+            char temp[20];
+            sprintf(temp, "pass%d.mps", iPass);
+            //model.writeMps(temp);
+#ifdef CLP_DEBUG
+            if (model.status()) {
+                model.writeMps("xx.mps");
+            }
+#endif
+            if (model.status() == 1) {
+                // not feasible ! - backtrack and exit
+                // use safe solution
+                memcpy(solution, safeSolution, numberColumns*sizeof(double));
+                memcpy(saveSolution, solution, numberColumns*sizeof(double));
+                memset(rowActivity, 0, numberRows*sizeof(double));
+                model.times(1.0, solution, rowActivity);
+                memcpy(saveRowSolution, rowActivity, numberRows*sizeof(double));
+                memcpy(model.dualRowSolution(), savePi, numberRows*sizeof(double));
+                memcpy(model.statusArray(), saveStatus, numberRows + numberColumns);
+                for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                    iColumn = listNonLinearColumn[jNon];
+                    columnLower[iColumn] = CoinMax(solution[iColumn]
+                                                   - trust[jNon],
+                                                   trueLower[jNon]);
+                    columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                                   + trust[jNon],
+                                                   trueUpper[jNon]);
+                }
+                break;
+            } else {
+                // save in case problems
+                memcpy(safeSolution, solution, numberColumns*sizeof(double));
+            }
+            goodMove = 1;
+        } else {
+            // bad pass - restore solution
+#ifdef CLP_DEBUG
+            if (logLevel&32)
+                printf("Backtracking\n");
+#endif
+            // load old values
+            for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                iColumn = listNonLinearColumn[jNon];
+                coinModel.associateElement(coinModel.columnName(iColumn), saveSolution[iColumn]);
+            }
+            model.loadProblem(coinModel);
+            model.addColumns(numberArtificials, NULL, NULL, objectiveArtificial,
+                             startArtificial, rowArtificial, elementArtificial);
+            solution = model.primalColumnSolution();
+            rowActivity = model.primalRowSolution();
+            memcpy(solution, saveSolution, numberColumns*sizeof(double));
+            memcpy(rowActivity, saveRowSolution, numberRows*sizeof(double));
+            memcpy(model.dualRowSolution(), savePi, numberRows*sizeof(double));
+            memcpy(model.statusArray(), saveStatus, numberRows + numberColumns);
+            columnLower = model.columnLower();
+            columnUpper = model.columnUpper();
+            for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                iColumn = listNonLinearColumn[jNon];
+                columnLower[iColumn] = solution[iColumn];
+                columnUpper[iColumn] = solution[iColumn];
+            }
+            model.primal(1);
+            //model.writeMps("xx.mps");
+            iPass--;
+            goodMove = -1;
+        }
+    }
+    // restore solution
+    memcpy(solution, saveSolution, numberColumns*sizeof(double));
+    delete [] statusCheck;
+    delete [] savePi;
+    delete [] saveStatus;
+    // load new values
+    for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+        iColumn = listNonLinearColumn[jNon];
+        coinModel.associateElement(coinModel.columnName(iColumn), solution[iColumn]);
+    }
+    double * sol2 = CoinCopyOfArray(model.primalColumnSolution(), numberColumns);
+    unsigned char * status2 = CoinCopyOfArray(model.statusArray(), numberColumns);
+    model.loadProblem(coinModel);
+    model.addColumns(numberArtificials, NULL, NULL, objectiveArtificial,
+                     startArtificial, rowArtificial, elementArtificial);
+    memcpy(model.primalColumnSolution(), sol2, numberColumns*sizeof(double));
+    memcpy(model.statusArray(), status2, numberColumns);
+    delete [] sol2;
+    delete [] status2;
+    columnLower = model.columnLower();
+    columnUpper = model.columnUpper();
+    solution = model.primalColumnSolution();
+    for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+        iColumn = listNonLinearColumn[jNon];
+        columnLower[iColumn] = CoinMax(solution[iColumn],
+                                       trueLower[jNon]);
+        columnUpper[iColumn] = CoinMin(solution[iColumn],
+                                       trueUpper[jNon]);
+    }
+    model.primal(1);
+    for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+        iColumn = listNonLinearColumn[jNon];
+        columnLower[iColumn] = trueLower[jNon];
+        columnUpper[iColumn] = trueUpper[jNon];
+    }
+    delete [] saveSolution;
+    delete [] safeSolution;
+    delete [] saveRowSolution;
+    for (iPass = 0; iPass < 3; iPass++)
+        delete [] last[iPass];
+    delete [] trust;
+    delete [] trueUpper;
+    delete [] trueLower;
+    delete [] changeRegion;
+    delete [] startArtificial;
+    delete [] rowArtificial;
+    delete [] elementArtificial;
+    delete [] objectiveArtificial;
+    delete [] listNonLinearColumn;
+    delete [] whichRow;
+    delete [] markNonlinear;
+    return CoinCopyOfArray(solution, coinModel.numberColumns());
+}
+/* Solve linearized quadratic objective branch and bound.
+   Return cutoff and OA cut
+*/
+double
+OsiSolverLink::linearizedBAB(CglStored * cut)
+{
+    double bestObjectiveValue = COIN_DBL_MAX;
+    if (quadraticModel_) {
+        ClpSimplex * qp = new ClpSimplex(*quadraticModel_);
+        // bounds
+        int numberColumns = qp->numberColumns();
+        double * lower = qp->columnLower();
+        double * upper = qp->columnUpper();
+        const double * lower2 = getColLower();
+        const double * upper2 = getColUpper();
+        for (int i = 0; i < numberColumns; i++) {
+            lower[i] = CoinMax(lower[i], lower2[i]);
+            upper[i] = CoinMin(upper[i], upper2[i]);
+        }
+        qp->nonlinearSLP(20, 1.0e-5);
+        qp->primal();
+        OsiSolverLinearizedQuadratic solver2(qp);
+        const double * solution = NULL;
+        // Reduce printout
+        solver2.setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        CbcModel model2(solver2);
+        // Now do requested saves and modifications
+        CbcModel * cbcModel = & model2;
+        OsiSolverInterface * osiModel = model2.solver();
+        OsiClpSolverInterface * osiclpModel = dynamic_cast< OsiClpSolverInterface*> (osiModel);
+        ClpSimplex * clpModel = osiclpModel->getModelPtr();
+
+        // Set changed values
+
+        CglProbing probing;
+        probing.setMaxProbe(10);
+        probing.setMaxLook(10);
+        probing.setMaxElements(200);
+        probing.setMaxProbeRoot(50);
+        probing.setMaxLookRoot(10);
+        probing.setRowCuts(3);
+        probing.setUsingObjective(true);
+        cbcModel->addCutGenerator(&probing, -1, "Probing", true, false, false, -100, -1, -1);
+        cbcModel->cutGenerator(0)->setTiming(true);
+
+        CglGomory gomory;
+        gomory.setLimitAtRoot(512);
+        cbcModel->addCutGenerator(&gomory, -98, "Gomory", true, false, false, -100, -1, -1);
+        cbcModel->cutGenerator(1)->setTiming(true);
+
+        CglKnapsackCover knapsackCover;
+        cbcModel->addCutGenerator(&knapsackCover, -98, "KnapsackCover", true, false, false, -100, -1, -1);
+        cbcModel->cutGenerator(2)->setTiming(true);
+
+        CglClique clique;
+        clique.setStarCliqueReport(false);
+        clique.setRowCliqueReport(false);
+        clique.setMinViolation(0.1);
+        cbcModel->addCutGenerator(&clique, -98, "Clique", true, false, false, -100, -1, -1);
+        cbcModel->cutGenerator(3)->setTiming(true);
+
+        CglMixedIntegerRounding2 mixedIntegerRounding2;
+        cbcModel->addCutGenerator(&mixedIntegerRounding2, -98, "MixedIntegerRounding2", true, false, false, -100, -1, -1);
+        cbcModel->cutGenerator(4)->setTiming(true);
+
+        CglFlowCover flowCover;
+        cbcModel->addCutGenerator(&flowCover, -98, "FlowCover", true, false, false, -100, -1, -1);
+        cbcModel->cutGenerator(5)->setTiming(true);
+
+        CglTwomir twomir;
+        twomir.setMaxElements(250);
+        cbcModel->addCutGenerator(&twomir, -99, "Twomir", true, false, false, -100, -1, -1);
+        cbcModel->cutGenerator(6)->setTiming(true);
+        // For now - switch off most heuristics (because CglPreProcess is bad with QP)
+#ifndef JJF_ONE
+        CbcHeuristicFPump heuristicFPump(*cbcModel);
+        heuristicFPump.setWhen(13);
+        heuristicFPump.setMaximumPasses(20);
+        heuristicFPump.setMaximumRetries(7);
+        heuristicFPump.setAbsoluteIncrement(4332.64);
+        cbcModel->addHeuristic(&heuristicFPump);
+        heuristicFPump.setInitialWeight(1);
+
+        CbcHeuristicLocal heuristicLocal(*cbcModel);
+        heuristicLocal.setSearchType(1);
+        cbcModel->addHeuristic(&heuristicLocal);
+
+        CbcHeuristicGreedyCover heuristicGreedyCover(*cbcModel);
+        cbcModel->addHeuristic(&heuristicGreedyCover);
+
+        CbcHeuristicGreedyEquality heuristicGreedyEquality(*cbcModel);
+        cbcModel->addHeuristic(&heuristicGreedyEquality);
+#endif
+
+        CbcRounding rounding(*cbcModel);
+        rounding.setHeuristicName("rounding");
+        cbcModel->addHeuristic(&rounding);
+
+        cbcModel->setNumberBeforeTrust(5);
+        cbcModel->setSpecialOptions(2);
+        cbcModel->messageHandler()->setLogLevel(1);
+        cbcModel->setMaximumCutPassesAtRoot(-100);
+        cbcModel->setMaximumCutPasses(1);
+        cbcModel->setMinimumDrop(0.05);
+        // For branchAndBound this may help
+        clpModel->defaultFactorizationFrequency();
+        clpModel->setDualBound(1.0001e+08);
+        clpModel->setPerturbation(50);
+        osiclpModel->setSpecialOptions(193);
+        osiclpModel->messageHandler()->setLogLevel(0);
+        osiclpModel->setIntParam(OsiMaxNumIterationHotStart, 100);
+        osiclpModel->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        // You can save some time by switching off message building
+        // clpModel->messagesPointer()->setDetailMessages(100,10000,(int *) NULL);
+
+        // Solve
+
+        cbcModel->initialSolve();
+        if (clpModel->tightenPrimalBounds() != 0) {
+            std::cout << "Problem is infeasible - tightenPrimalBounds!" << std::endl;
+            delete qp;
+            return COIN_DBL_MAX;
+        }
+        clpModel->dual();  // clean up
+        cbcModel->initialSolve();
+        cbcModel->branchAndBound();
+        OsiSolverLinearizedQuadratic * solver3 = dynamic_cast<OsiSolverLinearizedQuadratic *> (model2.solver());
+        assert (solver3);
+        solution = solver3->bestSolution();
+        bestObjectiveValue = solver3->bestObjectiveValue();
+        setBestObjectiveValue(bestObjectiveValue);
+        setBestSolution(solution, solver3->getNumCols());
+        // if convex
+        if ((specialOptions2()&4) != 0) {
+            if (cbcModel_)
+                cbcModel_->lockThread();
+            // add OA cut
+            double offset;
+            double * gradient = new double [numberColumns+1];
+            memcpy(gradient, qp->objectiveAsObject()->gradient(qp, solution, offset, true, 2),
+                   numberColumns*sizeof(double));
+            double rhs = 0.0;
+            int * column = new int[numberColumns+1];
+            int n = 0;
+            for (int i = 0; i < numberColumns; i++) {
+                double value = gradient[i];
+                if (fabs(value) > 1.0e-12) {
+                    gradient[n] = value;
+                    rhs += value * solution[i];
+                    column[n++] = i;
+                }
+            }
+            gradient[n] = -1.0;
+            column[n++] = numberColumns;
+            cut->addCut(-COIN_DBL_MAX, offset + 1.0e-7, n, column, gradient);
+            delete [] gradient;
+            delete [] column;
+            if (cbcModel_)
+                cbcModel_->unlockThread();
+        }
+        delete qp;
+        printf("obj %g\n", bestObjectiveValue);
+    }
+    return bestObjectiveValue;
+}
+/* Solves nonlinear problem from CoinModel using SLP - and then tries to get
+   heuristic solution
+   Returns solution array
+*/
+double *
+OsiSolverLink::heuristicSolution(int numberPasses, double deltaTolerance, int mode)
+{
+    // get a solution
+    CoinModel tempModel = coinModel_;
+    ClpSimplex * temp = approximateSolution(tempModel, numberPasses, deltaTolerance);
+    int numberColumns = coinModel_.numberColumns();
+    double * solution = CoinCopyOfArray(temp->primalColumnSolution(), numberColumns);
+    delete temp;
+    if (mode == 0) {
+        return solution;
+    } else if (mode == 2) {
+        const double * lower = getColLower();
+        const double * upper = getColUpper();
+        for (int iObject = 0; iObject < numberObjects_; iObject++) {
+            OsiSimpleInteger * obj = dynamic_cast<OsiSimpleInteger *> (object_[iObject]);
+            if (obj && (obj->priority() < biLinearPriority_ || biLinearPriority_ <= 0)) {
+                int iColumn = obj->columnNumber();
+                double value = solution[iColumn];
+                value = floor(value + 0.5);
+                if (fabs(value - solution[iColumn]) > 0.01) {
+                    setColLower(iColumn, CoinMax(lower[iColumn], value - CoinMax(defaultBound_, 0.0)));
+                    setColUpper(iColumn, CoinMin(upper[iColumn], value + CoinMax(defaultBound_, 1.0)));
+                } else {
+                    // could fix to integer
+                    setColLower(iColumn, CoinMax(lower[iColumn], value - CoinMax(defaultBound_, 0.0)));
+                    setColUpper(iColumn, CoinMin(upper[iColumn], value + CoinMax(defaultBound_, 0.0)));
+                }
+            }
+        }
+        return solution;
+    }
+    OsiClpSolverInterface newSolver;
+    if (mode == 1) {
+        // round all with priority < biLinearPriority_
+        setFixedPriority(biLinearPriority_);
+        // ? should we save and restore coin model
+        tempModel = coinModel_;
+        // solve modified problem
+        char * mark = new char[numberColumns];
+        memset(mark, 0, numberColumns);
+        for (int iObject = 0; iObject < numberObjects_; iObject++) {
+            OsiSimpleInteger * obj = dynamic_cast<OsiSimpleInteger *> (object_[iObject]);
+            if (obj && obj->priority() < biLinearPriority_) {
+                int iColumn = obj->columnNumber();
+                double value = solution[iColumn];
+                value = ceil(value - 1.0e-7);
+                tempModel.associateElement(coinModel_.columnName(iColumn), value);
+                mark[iColumn] = 1;
+            }
+            OsiBiLinear * objB = dynamic_cast<OsiBiLinear *> (object_[iObject]);
+            if (objB) {
+                // if one or both continuous then fix one
+                if (objB->xMeshSize() < 1.0) {
+                    int xColumn = objB->xColumn();
+                    double value = solution[xColumn];
+                    tempModel.associateElement(coinModel_.columnName(xColumn), value);
+                    mark[xColumn] = 1;
+                } else if (objB->yMeshSize() < 1.0) {
+                    int yColumn = objB->yColumn();
+                    double value = solution[yColumn];
+                    tempModel.associateElement(coinModel_.columnName(yColumn), value);
+                    mark[yColumn] = 1;
+                }
+            }
+        }
+        CoinModel * reOrdered = tempModel.reorder(mark);
+        assert (reOrdered);
+        tempModel = *reOrdered;
+        delete reOrdered;
+        delete [] mark;
+        newSolver.loadFromCoinModel(tempModel, true);
+        for (int iObject = 0; iObject < numberObjects_; iObject++) {
+            OsiSimpleInteger * obj = dynamic_cast<OsiSimpleInteger *> (object_[iObject]);
+            if (obj && obj->priority() < biLinearPriority_) {
+                int iColumn = obj->columnNumber();
+                double value = solution[iColumn];
+                value = ceil(value - 1.0e-7);
+                newSolver.setColLower(iColumn, value);
+                newSolver.setColUpper(iColumn, value);
+            }
+            OsiBiLinear * objB = dynamic_cast<OsiBiLinear *> (object_[iObject]);
+            if (objB) {
+                // if one or both continuous then fix one
+                if (objB->xMeshSize() < 1.0) {
+                    int xColumn = objB->xColumn();
+                    double value = solution[xColumn];
+                    newSolver.setColLower(xColumn, value);
+                    newSolver.setColUpper(xColumn, value);
+                } else if (objB->yMeshSize() < 1.0) {
+                    int yColumn = objB->yColumn();
+                    double value = solution[yColumn];
+                    newSolver.setColLower(yColumn, value);
+                    newSolver.setColUpper(yColumn, value);
+                }
+            }
+        }
+    }
+    CbcModel model(newSolver);
+    // Now do requested saves and modifications
+    CbcModel * cbcModel = & model;
+    OsiSolverInterface * osiModel = model.solver();
+    OsiClpSolverInterface * osiclpModel = dynamic_cast< OsiClpSolverInterface*> (osiModel);
+    ClpSimplex * clpModel = osiclpModel->getModelPtr();
+    CglProbing probing;
+    probing.setMaxProbe(10);
+    probing.setMaxLook(10);
+    probing.setMaxElements(200);
+    probing.setMaxProbeRoot(50);
+    probing.setMaxLookRoot(10);
+    probing.setRowCuts(3);
+    probing.setRowCuts(0);
+    probing.setUsingObjective(true);
+    cbcModel->addCutGenerator(&probing, -1, "Probing", true, false, false, -100, -1, -1);
+
+    CglGomory gomory;
+    gomory.setLimitAtRoot(512);
+    cbcModel->addCutGenerator(&gomory, -98, "Gomory", true, false, false, -100, -1, -1);
+
+    CglKnapsackCover knapsackCover;
+    cbcModel->addCutGenerator(&knapsackCover, -98, "KnapsackCover", true, false, false, -100, -1, -1);
+
+    CglClique clique;
+    clique.setStarCliqueReport(false);
+    clique.setRowCliqueReport(false);
+    clique.setMinViolation(0.1);
+    cbcModel->addCutGenerator(&clique, -98, "Clique", true, false, false, -100, -1, -1);
+    CglMixedIntegerRounding2 mixedIntegerRounding2;
+    cbcModel->addCutGenerator(&mixedIntegerRounding2, -98, "MixedIntegerRounding2", true, false, false, -100, -1, -1);
+
+    CglFlowCover flowCover;
+    cbcModel->addCutGenerator(&flowCover, -98, "FlowCover", true, false, false, -100, -1, -1);
+
+    CglTwomir twomir;
+    twomir.setMaxElements(250);
+    cbcModel->addCutGenerator(&twomir, -99, "Twomir", true, false, false, -100, -1, -1);
+    cbcModel->cutGenerator(6)->setTiming(true);
+
+    CbcHeuristicFPump heuristicFPump(*cbcModel);
+    heuristicFPump.setWhen(1);
+    heuristicFPump.setMaximumPasses(20);
+    heuristicFPump.setDefaultRounding(0.5);
+    cbcModel->addHeuristic(&heuristicFPump);
+
+    CbcRounding rounding(*cbcModel);
+    cbcModel->addHeuristic(&rounding);
+
+    CbcHeuristicLocal heuristicLocal(*cbcModel);
+    heuristicLocal.setSearchType(1);
+    cbcModel->addHeuristic(&heuristicLocal);
+
+    CbcHeuristicGreedyCover heuristicGreedyCover(*cbcModel);
+    cbcModel->addHeuristic(&heuristicGreedyCover);
+
+    CbcHeuristicGreedyEquality heuristicGreedyEquality(*cbcModel);
+    cbcModel->addHeuristic(&heuristicGreedyEquality);
+
+    CbcCompareDefault compare;
+    cbcModel->setNodeComparison(compare);
+    cbcModel->setNumberBeforeTrust(5);
+    cbcModel->setSpecialOptions(2);
+    cbcModel->messageHandler()->setLogLevel(1);
+    cbcModel->setMaximumCutPassesAtRoot(-100);
+    cbcModel->setMaximumCutPasses(1);
+    cbcModel->setMinimumDrop(0.05);
+    clpModel->setNumberIterations(1);
+    // For branchAndBound this may help
+    clpModel->defaultFactorizationFrequency();
+    clpModel->setDualBound(6.71523e+07);
+    clpModel->setPerturbation(50);
+    osiclpModel->setSpecialOptions(193);
+    osiclpModel->messageHandler()->setLogLevel(0);
+    osiclpModel->setIntParam(OsiMaxNumIterationHotStart, 100);
+    osiclpModel->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+    // You can save some time by switching off message building
+    // clpModel->messagesPointer()->setDetailMessages(100,10000,(int *) NULL);
+    // Solve
+
+    cbcModel->initialSolve();
+    //double cutoff = model_->getCutoff();
+    if (!cbcModel_)
+        cbcModel->setCutoff(1.0e50);
+    else
+        cbcModel->setCutoff(cbcModel_->getCutoff());
+    int saveLogLevel = clpModel->logLevel();
+    clpModel->setLogLevel(0);
+#ifndef NDEBUG
+    int returnCode = 0;
+#endif
+    if (clpModel->tightenPrimalBounds() != 0) {
+        clpModel->setLogLevel(saveLogLevel);
+#ifndef NDEBUG
+        returnCode = -1; // infeasible//std::cout<<"Problem is infeasible - tightenPrimalBounds!"<<std::endl;
+#endif
+        //clpModel->writeMps("infeas2.mps");
+    } else {
+        clpModel->setLogLevel(saveLogLevel);
+        clpModel->dual();  // clean up
+        // compute some things using problem size
+        cbcModel->setMinimumDrop(CoinMin(5.0e-2,
+                                         fabs(cbcModel->getMinimizationObjValue())*1.0e-3 + 1.0e-4));
+        if (cbcModel->getNumCols() < 500)
+            cbcModel->setMaximumCutPassesAtRoot(-100); // always do 100 if possible
+        else if (cbcModel->getNumCols() < 5000)
+            cbcModel->setMaximumCutPassesAtRoot(100); // use minimum drop
+        else
+            cbcModel->setMaximumCutPassesAtRoot(20);
+        cbcModel->setMaximumCutPasses(1);
+        // Hand coded preprocessing
+        CglPreProcess process;
+        OsiSolverInterface * saveSolver = cbcModel->solver()->clone();
+        // Tell solver we are in Branch and Cut
+        saveSolver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ;
+        // Default set of cut generators
+        CglProbing generator1;
+        generator1.setUsingObjective(true);
+        generator1.setMaxPass(3);
+        generator1.setMaxProbeRoot(saveSolver->getNumCols());
+        generator1.setMaxElements(100);
+        generator1.setMaxLookRoot(50);
+        generator1.setRowCuts(3);
+        // Add in generators
+        process.addCutGenerator(&generator1);
+        process.messageHandler()->setLogLevel(cbcModel->logLevel());
+        OsiSolverInterface * solver2 =
+            process.preProcessNonDefault(*saveSolver, 0, 10);
+        // Tell solver we are not in Branch and Cut
+        saveSolver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+        if (solver2)
+            solver2->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+        if (!solver2) {
+            std::cout << "Pre-processing says infeasible!" << std::endl;
+            delete saveSolver;
+#ifndef NDEBUG
+            returnCode = -1;
+#endif
+        } else {
+            std::cout << "processed model has " << solver2->getNumRows()
+                      << " rows, " << solver2->getNumCols()
+                      << " and " << solver2->getNumElements() << std::endl;
+            // we have to keep solver2 so pass clone
+            solver2 = solver2->clone();
+            //solver2->writeMps("intmodel");
+            cbcModel->assignSolver(solver2);
+            cbcModel->initialSolve();
+            cbcModel->branchAndBound();
+            // For best solution
+            int numberColumns = newSolver.getNumCols();
+            if (cbcModel->getMinimizationObjValue() < 1.0e50) {
+                // post process
+                process.postProcess(*cbcModel->solver());
+                // Solution now back in saveSolver
+                cbcModel->assignSolver(saveSolver);
+                memcpy(cbcModel->bestSolution(), cbcModel->solver()->getColSolution(),
+                       numberColumns*sizeof(double));
+                // put back in original solver
+                newSolver.setColSolution(cbcModel->bestSolution());
+            } else {
+                delete saveSolver;
+            }
+        }
+    }
+    assert (!returnCode);
+    abort();
+    return solution;
+}
+// Analyze constraints to see which are convex (quadratic)
+void
+OsiSolverLink::analyzeObjects()
+{
+    // space for starts
+    int numberColumns = coinModel_.numberColumns();
+    int * start = new int [numberColumns+1];
+    const double * rowLower = getRowLower();
+    const double * rowUpper = getRowUpper();
+    for (int iNon = 0; iNon < numberNonLinearRows_; iNon++) {
+        int iRow = rowNonLinear_[iNon];
+        int numberElements = startNonLinear_[iNon+1] - startNonLinear_[iNon];
+        // triplet arrays
+        int * iColumn = new int [2*numberElements+1];
+        int * jColumn = new int [2*numberElements];
+        double * element = new double [2*numberElements];
+        int i;
+        int n = 0;
+        for ( i = startNonLinear_[iNon]; i < startNonLinear_[iNon+1]; i++) {
+            OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[whichNonLinear_[i]]);
+            assert (obj);
+            int xColumn = obj->xColumn();
+            int yColumn = obj->yColumn();
+            double coefficient = obj->coefficient();
+            if (xColumn != yColumn) {
+                iColumn[n] = xColumn;
+                jColumn[n] = yColumn;
+                element[n++] = coefficient;
+                iColumn[n] = yColumn;
+                jColumn[n] = xColumn;
+                element[n++] = coefficient;
+            } else {
+                iColumn[n] = xColumn;
+                jColumn[n] = xColumn;
+                element[n++] = coefficient;
+            }
+        }
+        // First sort in column order
+        CoinSort_3(iColumn, iColumn + n, jColumn, element);
+        // marker at end
+        iColumn[n] = numberColumns;
+        int lastI = iColumn[0];
+        // compute starts
+        start[0] = 0;
+        for (i = 1; i < n + 1; i++) {
+            if (iColumn[i] != lastI) {
+                while (lastI < iColumn[i]) {
+                    start[lastI+1] = i;
+                    lastI++;
+                }
+                lastI = iColumn[i];
+            }
+        }
+        // -1 unknown, 0 convex, 1 nonconvex
+        int status = -1;
+        int statusNegative = -1;
+        int numberLong = 0; // number with >2 elements
+        for (int k = 0; k < numberColumns; k++) {
+            int first = start[k];
+            int last = start[k+1];
+            if (last > first) {
+                int j;
+                double diagonal = 0.0;
+                int whichK = -1;
+                for (j = first; j < last; j++) {
+                    if (jColumn[j] == k) {
+                        diagonal = element[j];
+                        status = diagonal > 0 ? 0 : 1;
+                        statusNegative = diagonal < 0 ? 0 : 1;
+                        whichK = (j == first) ? j + 1 : j - 1;
+                        break;
+                    }
+                }
+                if (last == first + 1) {
+                    // just one entry
+                    if (!diagonal) {
+                        // one off diagonal - not positive semi definite
+                        status = 1;
+                        statusNegative = 1;
+                    }
+                } else if (diagonal) {
+                    if (last == first + 2) {
+                        // other column and element
+                        double otherElement = element[whichK];;
+                        int otherColumn = jColumn[whichK];
+                        double otherDiagonal = 0.0;
+                        // check 2x2 determinant - unless past and 2 long
+                        if (otherColumn > i || start[otherColumn+1] > start[otherColumn] + 2) {
+                            for (j = start[otherColumn]; j < start[otherColumn+1]; j++) {
+                                if (jColumn[j] == otherColumn) {
+                                    otherDiagonal = element[j];
+                                    break;
+                                }
+                            }
+                            // determinant
+                            double determinant = diagonal * otherDiagonal - otherElement * otherElement;
+                            if (determinant < -1.0e-12) {
+                                // not positive semi definite
+                                status = 1;
+                                statusNegative = 1;
+                            } else if (start[otherColumn+1] > start[otherColumn] + 2 && determinant < 1.0e-12) {
+                                // not positive semi definite
+                                status = 1;
+                                statusNegative = 1;
+                            }
+                        }
+                    } else {
+                        numberLong++;
+                    }
+                }
+            }
+        }
+        if ((status == 0 || statusNegative == 0) && numberLong) {
+            // need to do more work
+            //printf("Needs more work\n");
+        }
+        assert (status > 0 || statusNegative > 0);
+        if (!status) {
+            convex_[iNon] = 1;
+            // equality may be ok
+            if (rowUpper[iRow] < 1.0e20)
+                specialOptions2_ |= 8;
+            else
+                convex_[iNon] = 0;
+        } else if (!statusNegative) {
+            convex_[iNon] = -1;
+            // equality may be ok
+            if (rowLower[iRow] > -1.0e20)
+                specialOptions2_ |= 8;
+            else
+                convex_[iNon] = 0;
+        } else {
+            convex_[iNon] = 0;
+        }
+        //printf("Convexity of row %d is %d\n",iRow,convex_[iNon]);
+        delete [] iColumn;
+        delete [] jColumn;
+        delete [] element;
+    }
+    delete [] start;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+OsiSolverInterface *
+OsiSolverLink::clone(bool /*copyData*/) const
+{
+    //assert (copyData);
+    OsiSolverLink * newModel = new OsiSolverLink(*this);
+    return newModel;
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+OsiSolverLink::OsiSolverLink (
+    const OsiSolverLink & rhs)
+        : OsiSolverInterface(rhs),
+        CbcOsiSolver(rhs)
+{
+    gutsOfDestructor(true);
+    gutsOfCopy(rhs);
+    // something odd happens - try this
+    OsiSolverInterface::operator=(rhs);
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+OsiSolverLink::~OsiSolverLink ()
+{
+    gutsOfDestructor();
+}
+
+//-------------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+OsiSolverLink &
+OsiSolverLink::operator=(const OsiSolverLink & rhs)
+{
+    if (this != &rhs) {
+        gutsOfDestructor();
+        CbcOsiSolver::operator=(rhs);
+        gutsOfCopy(rhs);
+    }
+    return *this;
+}
+void
+OsiSolverLink::gutsOfDestructor(bool justNullify)
+{
+    if (!justNullify) {
+        delete matrix_;
+        delete originalRowCopy_;
+        delete [] info_;
+        delete [] bestSolution_;
+        delete quadraticModel_;
+        delete [] startNonLinear_;
+        delete [] rowNonLinear_;
+        delete [] convex_;
+        delete [] whichNonLinear_;
+        delete [] fixVariables_;
+    }
+    matrix_ = NULL;
+    originalRowCopy_ = NULL;
+    quadraticModel_ = NULL;
+    numberNonLinearRows_ = 0;
+    startNonLinear_ = NULL;
+    rowNonLinear_ = NULL;
+    convex_ = NULL;
+    whichNonLinear_ = NULL;
+    info_ = NULL;
+    fixVariables_ = NULL;
+    numberVariables_ = 0;
+    specialOptions2_ = 0;
+    objectiveRow_ = -1;
+    objectiveVariable_ = -1;
+    bestSolution_ = NULL;
+    bestObjectiveValue_ = 1.0e100;
+    defaultMeshSize_ = 1.0e-4;
+    defaultBound_ = 1.0e5;
+    integerPriority_ = 1000;
+    biLinearPriority_ = 10000;
+    numberFix_ = 0;
+}
+void
+OsiSolverLink::gutsOfCopy(const OsiSolverLink & rhs)
+{
+    coinModel_ = rhs.coinModel_;
+    numberVariables_ = rhs.numberVariables_;
+    numberNonLinearRows_ = rhs.numberNonLinearRows_;
+    specialOptions2_ = rhs.specialOptions2_;
+    objectiveRow_ = rhs.objectiveRow_;
+    objectiveVariable_ = rhs.objectiveVariable_;
+    bestObjectiveValue_ = rhs.bestObjectiveValue_;
+    defaultMeshSize_ = rhs.defaultMeshSize_;
+    defaultBound_ = rhs.defaultBound_;
+    integerPriority_ = rhs.integerPriority_;
+    biLinearPriority_ = rhs.biLinearPriority_;
+    numberFix_ = rhs.numberFix_;
+    if (numberVariables_) {
+        if (rhs.matrix_)
+            matrix_ = new CoinPackedMatrix(*rhs.matrix_);
+        else
+            matrix_ = NULL;
+        if (rhs.originalRowCopy_)
+            originalRowCopy_ = new CoinPackedMatrix(*rhs.originalRowCopy_);
+        else
+            originalRowCopy_ = NULL;
+        info_ = new OsiLinkedBound [numberVariables_];
+        for (int i = 0; i < numberVariables_; i++) {
+            info_[i] = OsiLinkedBound(rhs.info_[i]);
+        }
+        if (rhs.bestSolution_) {
+            bestSolution_ = CoinCopyOfArray(rhs.bestSolution_, modelPtr_->getNumCols());
+        } else {
+            bestSolution_ = NULL;
+        }
+    }
+    if (numberNonLinearRows_) {
+        startNonLinear_ = CoinCopyOfArray(rhs.startNonLinear_, numberNonLinearRows_ + 1);
+        rowNonLinear_ = CoinCopyOfArray(rhs.rowNonLinear_, numberNonLinearRows_);
+        convex_ = CoinCopyOfArray(rhs.convex_, numberNonLinearRows_);
+        int numberEntries = startNonLinear_[numberNonLinearRows_];
+        whichNonLinear_ = CoinCopyOfArray(rhs.whichNonLinear_, numberEntries);
+    }
+    if (rhs.quadraticModel_) {
+        quadraticModel_ = new ClpSimplex(*rhs.quadraticModel_);
+    } else {
+        quadraticModel_ = NULL;
+    }
+    fixVariables_ = CoinCopyOfArray(rhs.fixVariables_, numberFix_);
+}
+// Add a bound modifier
+void
+OsiSolverLink::addBoundModifier(bool upperBoundAffected, bool useUpperBound, int whichVariable, int whichVariableAffected,
+                                double multiplier)
+{
+    bool found = false;
+    int i;
+    for ( i = 0; i < numberVariables_; i++) {
+        if (info_[i].variable() == whichVariable) {
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        // add in
+        OsiLinkedBound * temp = new OsiLinkedBound [numberVariables_+1];
+        for (int i = 0; i < numberVariables_; i++)
+            temp[i] = info_[i];
+        delete [] info_;
+        info_ = temp;
+        info_[numberVariables_++] = OsiLinkedBound(this, whichVariable, 0, NULL, NULL, NULL);
+    }
+    info_[i].addBoundModifier(upperBoundAffected, useUpperBound, whichVariableAffected, multiplier);
+}
+// Update coefficients
+int
+OsiSolverLink::updateCoefficients(ClpSimplex * solver, CoinPackedMatrix * matrix)
+{
+    double * lower = solver->columnLower();
+    double * upper = solver->columnUpper();
+    double * objective = solver->objective();
+    int numberChanged = 0;
+    for (int iObject = 0; iObject < numberObjects_; iObject++) {
+        OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (object_[iObject]);
+        if (obj) {
+            numberChanged += obj->updateCoefficients(lower, upper, objective, matrix, &basis_);
+        }
+    }
+    return numberChanged;
+}
+// Set best solution found internally
+void
+OsiSolverLink::setBestSolution(const double * solution, int numberColumns)
+{
+    delete [] bestSolution_;
+    int numberColumnsThis = modelPtr_->numberColumns();
+    bestSolution_ = new double [numberColumnsThis];
+    CoinZeroN(bestSolution_, numberColumnsThis);
+    memcpy(bestSolution_, solution, CoinMin(numberColumns, numberColumnsThis)*sizeof(double));
+}
+/* Two tier integer problem where when set of variables with priority
+   less than this are fixed the problem becomes an easier integer problem
+*/
+void
+OsiSolverLink::setFixedPriority(int priorityValue)
+{
+    delete [] fixVariables_;
+    fixVariables_ = NULL;
+    numberFix_ = 0;
+    int i;
+    for ( i = 0; i < numberObjects_; i++) {
+        OsiSimpleInteger * obj = dynamic_cast<OsiSimpleInteger *> (object_[i]);
+        if (obj) {
+#ifndef NDEBUG
+            int iColumn = obj->columnNumber();
+            assert (iColumn >= 0);
+#endif
+            if (obj->priority() < priorityValue)
+                numberFix_++;
+        }
+    }
+    if (numberFix_) {
+        specialOptions2_ |= 1;
+        fixVariables_ = new int [numberFix_];
+        numberFix_ = 0;
+        // need to make sure coinModel_ is correct
+        int numberColumns = coinModel_.numberColumns();
+        char * highPriority = new char [numberColumns];
+        CoinZeroN(highPriority, numberColumns);
+        for ( i = 0; i < numberObjects_; i++) {
+            OsiSimpleInteger * obj = dynamic_cast<OsiSimpleInteger *> (object_[i]);
+            if (obj) {
+                int iColumn = obj->columnNumber();
+                assert (iColumn >= 0);
+                if (iColumn < numberColumns) {
+                    if (obj->priority() < priorityValue) {
+                        object_[i] = new OsiSimpleFixedInteger(*obj);
+                        delete obj;
+                        fixVariables_[numberFix_++] = iColumn;
+                        highPriority[iColumn] = 1;
+                    }
+                }
+            }
+        }
+        CoinModel * newModel = coinModel_.reorder(highPriority);
+        if (newModel) {
+            coinModel_ = * newModel;
+        } else {
+            printf("Unable to use priorities\n");
+            delete [] fixVariables_;
+            fixVariables_ = NULL;
+            numberFix_ = 0;
+        }
+        delete newModel;
+        delete [] highPriority;
+    }
+}
+// Gets correct form for a quadratic row - user to delete
+CoinPackedMatrix *
+OsiSolverLink::quadraticRow(int rowNumber, double * linearRow) const
+{
+    int numberColumns = coinModel_.numberColumns();
+    CoinZeroN(linearRow, numberColumns);
+    int numberElements = 0;
+#ifndef NDEBUG
+    int numberRows = coinModel_.numberRows();
+    assert (rowNumber >= 0 && rowNumber < numberRows);
+#endif
+    CoinModelLink triple = coinModel_.firstInRow(rowNumber);
+    while (triple.column() >= 0) {
+        int iColumn = triple.column();
+        const char * expr = coinModel_.getElementAsString(rowNumber, iColumn);
+        if (strcmp(expr, "Numeric")) {
+            // try and see which columns
+            assert (strlen(expr) < 20000);
+            char temp[20000];
+            strcpy(temp, expr);
+            char * pos = temp;
+            bool ifFirst = true;
+            while (*pos) {
+                double value;
+                int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel_);
+                // must be column unless first when may be linear term
+                if (jColumn >= 0) {
+                    numberElements++;
+                } else if (jColumn == -2) {
+                    linearRow[iColumn] = value;
+                } else {
+                    printf("bad nonlinear term %s\n", temp);
+                    abort();
+                }
+                ifFirst = false;
+            }
+        } else {
+            linearRow[iColumn] = coinModel_.getElement(rowNumber, iColumn);
+        }
+        triple = coinModel_.next(triple);
+    }
+    if (!numberElements) {
+        return NULL;
+    } else {
+        int * column = new int[numberElements];
+        int * column2 = new int[numberElements];
+        double * element = new double[numberElements];
+        numberElements = 0;
+        CoinModelLink triple = coinModel_.firstInRow(rowNumber);
+        while (triple.column() >= 0) {
+            int iColumn = triple.column();
+            const char * expr = coinModel_.getElementAsString(rowNumber, iColumn);
+            if (strcmp(expr, "Numeric")) {
+                // try and see which columns
+                assert (strlen(expr) < 20000);
+                char temp[20000];
+                strcpy(temp, expr);
+                char * pos = temp;
+                bool ifFirst = true;
+                while (*pos) {
+                    double value;
+                    int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel_);
+                    // must be column unless first when may be linear term
+                    if (jColumn >= 0) {
+                        column[numberElements] = iColumn;
+                        column2[numberElements] = jColumn;
+                        element[numberElements++] = value;
+                    } else if (jColumn != -2) {
+                        printf("bad nonlinear term %s\n", temp);
+                        abort();
+                    }
+                    ifFirst = false;
+                }
+            }
+            triple = coinModel_.next(triple);
+        }
+        return new CoinPackedMatrix(true, column2, column, element, numberElements);
+    }
+}
+/*
+  Problem specific
+  Returns -1 if node fathomed and no solution
+  0 if did nothing
+  1 if node fathomed and solution
+  allFixed is true if all LinkedBound variables are fixed
+*/
+int
+OsiSolverLink::fathom(bool allFixed)
+{
+    int returnCode = 0;
+    if (allFixed) {
+        // solve anyway
+        OsiClpSolverInterface::resolve();
+        if (!isProvenOptimal()) {
+            printf("cutoff before fathoming\n");
+            return -1;
+        }
+        // all fixed so we can reformulate
+        OsiClpSolverInterface newSolver;
+        // set values
+        const double * lower = modelPtr_->columnLower();
+        const double * upper = modelPtr_->columnUpper();
+        int i;
+        for (i = 0; i < numberFix_; i++ ) {
+            int iColumn = fixVariables_[i];
+            double lo = lower[iColumn];
+#ifndef NDEBUG
+            double up = upper[iColumn];
+            assert (lo == up);
+#endif
+            //printf("column %d fixed to %g\n",iColumn,lo);
+            coinModel_.associateElement(coinModel_.columnName(iColumn), lo);
+        }
+        newSolver.loadFromCoinModel(coinModel_, true);
+        for (i = 0; i < numberFix_; i++ ) {
+            int iColumn = fixVariables_[i];
+            newSolver.setColLower(iColumn, lower[iColumn]);
+            newSolver.setColUpper(iColumn, lower[iColumn]);
+        }
+        // see if everything with objective fixed
+        const double * objective = modelPtr_->objective();
+        int numberColumns = newSolver.getNumCols();
+        bool zeroObjective = true;
+        double sum = 0.0;
+        for (i = 0; i < numberColumns; i++) {
+            if (upper[i] > lower[i] && objective[i]) {
+                zeroObjective = false;
+                break;
+            } else {
+                sum += lower[i] * objective[i];
+            }
+        }
+        int fake[] = {5, 4, 3, 2, 0, 0, 0};
+        bool onOptimalPath = true;
+        for (i = 0; i < 7; i++) {
+            if (static_cast<int> (upper[i]) != fake[i])
+                onOptimalPath = false;
+        }
+        if (onOptimalPath)
+            printf("possible\n");
+        if (zeroObjective) {
+            // randomize objective
+            ClpSimplex * clpModel = newSolver.getModelPtr();
+            const double * element = clpModel->matrix()->getMutableElements();
+            //const int * row = clpModel->matrix()->getIndices();
+            const CoinBigIndex * columnStart = clpModel->matrix()->getVectorStarts();
+            const int * columnLength = clpModel->matrix()->getVectorLengths();
+            double * objective = clpModel->objective();
+            for (i = 0; i < numberColumns; i++) {
+                if (clpModel->isInteger(i)) {
+                    double value = 0.0;
+                    for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                        value += fabs(element[j]);
+                    }
+                    objective[i] = value;
+                }
+            }
+        }
+        //newSolver.writeMps("xx");
+        CbcModel model(newSolver);
+        // Now do requested saves and modifications
+        CbcModel * cbcModel = & model;
+        OsiSolverInterface * osiModel = model.solver();
+        OsiClpSolverInterface * osiclpModel = dynamic_cast< OsiClpSolverInterface*> (osiModel);
+        ClpSimplex * clpModel = osiclpModel->getModelPtr();
+        CglProbing probing;
+        probing.setMaxProbe(10);
+        probing.setMaxLook(10);
+        probing.setMaxElements(200);
+        probing.setMaxProbeRoot(50);
+        probing.setMaxLookRoot(10);
+        probing.setRowCuts(3);
+        probing.setRowCuts(0);
+        probing.setUsingObjective(true);
+        cbcModel->addCutGenerator(&probing, -1, "Probing", true, false, false, -100, -1, -1);
+
+        CglGomory gomory;
+        gomory.setLimitAtRoot(512);
+        cbcModel->addCutGenerator(&gomory, -98, "Gomory", true, false, false, -100, -1, -1);
+
+        CglKnapsackCover knapsackCover;
+        cbcModel->addCutGenerator(&knapsackCover, -98, "KnapsackCover", true, false, false, -100, -1, -1);
+
+        CglClique clique;
+        clique.setStarCliqueReport(false);
+        clique.setRowCliqueReport(false);
+        clique.setMinViolation(0.1);
+        cbcModel->addCutGenerator(&clique, -98, "Clique", true, false, false, -100, -1, -1);
+        CglMixedIntegerRounding2 mixedIntegerRounding2;
+        cbcModel->addCutGenerator(&mixedIntegerRounding2, -98, "MixedIntegerRounding2", true, false, false, -100, -1, -1);
+
+        CglFlowCover flowCover;
+        cbcModel->addCutGenerator(&flowCover, -98, "FlowCover", true, false, false, -100, -1, -1);
+
+        CglTwomir twomir;
+        twomir.setMaxElements(250);
+        cbcModel->addCutGenerator(&twomir, -99, "Twomir", true, false, false, -100, -1, -1);
+        cbcModel->cutGenerator(6)->setTiming(true);
+
+        CbcHeuristicFPump heuristicFPump(*cbcModel);
+        heuristicFPump.setWhen(1);
+        heuristicFPump.setMaximumPasses(20);
+        heuristicFPump.setDefaultRounding(0.5);
+        cbcModel->addHeuristic(&heuristicFPump);
+
+        CbcRounding rounding(*cbcModel);
+        cbcModel->addHeuristic(&rounding);
+
+        CbcHeuristicLocal heuristicLocal(*cbcModel);
+        heuristicLocal.setSearchType(1);
+        cbcModel->addHeuristic(&heuristicLocal);
+
+        CbcHeuristicGreedyCover heuristicGreedyCover(*cbcModel);
+        cbcModel->addHeuristic(&heuristicGreedyCover);
+
+        CbcHeuristicGreedyEquality heuristicGreedyEquality(*cbcModel);
+        cbcModel->addHeuristic(&heuristicGreedyEquality);
+
+        CbcCompareDefault compare;
+        cbcModel->setNodeComparison(compare);
+        cbcModel->setNumberBeforeTrust(5);
+        cbcModel->setSpecialOptions(2);
+        cbcModel->messageHandler()->setLogLevel(1);
+        cbcModel->setMaximumCutPassesAtRoot(-100);
+        cbcModel->setMaximumCutPasses(1);
+        cbcModel->setMinimumDrop(0.05);
+        clpModel->setNumberIterations(1);
+        // For branchAndBound this may help
+        clpModel->defaultFactorizationFrequency();
+        clpModel->setDualBound(6.71523e+07);
+        clpModel->setPerturbation(50);
+        osiclpModel->setSpecialOptions(193);
+        osiclpModel->messageHandler()->setLogLevel(0);
+        osiclpModel->setIntParam(OsiMaxNumIterationHotStart, 100);
+        osiclpModel->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        // You can save some time by switching off message building
+        // clpModel->messagesPointer()->setDetailMessages(100,10000,(int *) NULL);
+        // Solve
+
+        cbcModel->initialSolve();
+        //double cutoff = model_->getCutoff();
+        if (zeroObjective || !cbcModel_)
+            cbcModel->setCutoff(1.0e50);
+        else
+            cbcModel->setCutoff(cbcModel_->getCutoff());
+        // to change exits
+        bool isFeasible = false;
+        int saveLogLevel = clpModel->logLevel();
+        clpModel->setLogLevel(0);
+        if (clpModel->tightenPrimalBounds() != 0) {
+            clpModel->setLogLevel(saveLogLevel);
+            returnCode = -1; // infeasible//std::cout<<"Problem is infeasible - tightenPrimalBounds!"<<std::endl;
+        } else {
+            clpModel->setLogLevel(saveLogLevel);
+            clpModel->dual();  // clean up
+            // compute some things using problem size
+            cbcModel->setMinimumDrop(CoinMin(5.0e-2,
+                                             fabs(cbcModel->getMinimizationObjValue())*1.0e-3 + 1.0e-4));
+            if (cbcModel->getNumCols() < 500)
+                cbcModel->setMaximumCutPassesAtRoot(-100); // always do 100 if possible
+            else if (cbcModel->getNumCols() < 5000)
+                cbcModel->setMaximumCutPassesAtRoot(100); // use minimum drop
+            else
+                cbcModel->setMaximumCutPassesAtRoot(20);
+            cbcModel->setMaximumCutPasses(1);
+            // Hand coded preprocessing
+            CglPreProcess process;
+            OsiSolverInterface * saveSolver = cbcModel->solver()->clone();
+            // Tell solver we are in Branch and Cut
+            saveSolver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ;
+            // Default set of cut generators
+            CglProbing generator1;
+            generator1.setUsingObjective(true);
+            generator1.setMaxPass(3);
+            generator1.setMaxProbeRoot(saveSolver->getNumCols());
+            generator1.setMaxElements(100);
+            generator1.setMaxLookRoot(50);
+            generator1.setRowCuts(3);
+            // Add in generators
+            process.addCutGenerator(&generator1);
+            process.messageHandler()->setLogLevel(cbcModel->logLevel());
+            OsiSolverInterface * solver2 =
+                process.preProcessNonDefault(*saveSolver, 0, 10);
+            // Tell solver we are not in Branch and Cut
+            saveSolver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+            if (solver2)
+                solver2->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+            if (!solver2) {
+                std::cout << "Pre-processing says infeasible!" << std::endl;
+                delete saveSolver;
+                returnCode = -1;
+            } else {
+                std::cout << "processed model has " << solver2->getNumRows()
+                          << " rows, " << solver2->getNumCols()
+                          << " and " << solver2->getNumElements() << std::endl;
+                // we have to keep solver2 so pass clone
+                solver2 = solver2->clone();
+                //solver2->writeMps("intmodel");
+                cbcModel->assignSolver(solver2);
+                cbcModel->initialSolve();
+                if (zeroObjective) {
+                    cbcModel->setMaximumSolutions(1); // just getting a solution
+#ifdef JJF_ZERO
+                    OsiClpSolverInterface * osiclpModel = dynamic_cast< OsiClpSolverInterface*> (cbcModel->solver());
+                    ClpSimplex * clpModel = osiclpModel->getModelPtr();
+                    const double * element = clpModel->matrix()->getMutableElements();
+                    //const int * row = clpModel->matrix()->getIndices();
+                    const CoinBigIndex * columnStart = clpModel->matrix()->getVectorStarts();
+                    const int * columnLength = clpModel->matrix()->getVectorLengths();
+                    int n = clpModel->numberColumns();
+                    int * sort2 = new int[n];
+                    int * pri = new int[n];
+                    double * sort = new double[n];
+                    int i;
+                    int nint = 0;
+                    for (i = 0; i < n; i++) {
+                        if (clpModel->isInteger(i)) {
+                            double largest = 0.0;
+                            for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                                largest = CoinMax(largest, fabs(element[j]));
+                            }
+                            sort2[nint] = nint;
+                            sort[nint++] = -largest;
+                        }
+                    }
+                    CoinSort_2(sort, sort + nint, sort2);
+                    int kpri = 1;
+                    double last = sort[0];
+                    for (i = 0; i < nint; i++) {
+                        if (sort[i] != last) {
+                            kpri++;
+                            last = sort[i];
+                        }
+                        pri[sort2[i]] = kpri;
+                    }
+                    cbcModel->passInPriorities(pri, false);
+                    delete [] sort;
+                    delete [] sort2;
+                    delete [] pri;
+#endif
+                }
+                cbcModel->branchAndBound();
+                // For best solution
+                int numberColumns = newSolver.getNumCols();
+                if (cbcModel->getMinimizationObjValue() < 1.0e50) {
+                    // post process
+                    process.postProcess(*cbcModel->solver());
+                    // Solution now back in saveSolver
+                    cbcModel->assignSolver(saveSolver);
+                    memcpy(cbcModel->bestSolution(), cbcModel->solver()->getColSolution(),
+                           numberColumns*sizeof(double));
+                    // put back in original solver
+                    newSolver.setColSolution(cbcModel->bestSolution());
+                    isFeasible = true;
+                } else {
+                    delete saveSolver;
+                }
+            }
+            //const double * solution = newSolver.getColSolution();
+            if (isFeasible && cbcModel->getMinimizationObjValue() < 1.0e50) {
+                int numberColumns = this->getNumCols();
+                int i;
+                const double * solution = cbcModel->bestSolution();
+                int numberColumns2 = newSolver.getNumCols();
+                for (i = 0; i < numberColumns2; i++) {
+                    double value = solution[i];
+                    assert (fabs(value - floor(value + 0.5)) < 0.0001);
+                    value = floor(value + 0.5);
+                    this->setColLower(i, value);
+                    this->setColUpper(i, value);
+                }
+                for (; i < numberColumns; i++) {
+                    this->setColLower(i, 0.0);
+                    this->setColUpper(i, 1.1);
+                }
+                // but take off cuts
+                int numberRows = getNumRows();
+                int numberRows2 = cbcModel_->continuousSolver()->getNumRows();
+
+                for (i = numberRows2; i < numberRows; i++)
+                    setRowBounds(i, -COIN_DBL_MAX, COIN_DBL_MAX);
+                initialSolve();
+                //if (!isProvenOptimal())
+                //getModelPtr()->writeMps("bad.mps");
+                if (isProvenOptimal()) {
+                    delete [] bestSolution_;
+                    bestSolution_ = CoinCopyOfArray(modelPtr_->getColSolution(), modelPtr_->getNumCols());
+                    bestObjectiveValue_ = modelPtr_->objectiveValue();
+                    printf("BB best value %g\n", bestObjectiveValue_);
+                    returnCode = 1;
+                } else {
+                    printf("*** WHY BAD SOL\n");
+                    returnCode = -1;
+                }
+            } else {
+                modelPtr_->setProblemStatus(1);
+                modelPtr_->setObjectiveValue(COIN_DBL_MAX);
+                returnCode = -1;
+            }
+        }
+    }
+    return returnCode;
+}
+//#############################################################################
+// Constructors, destructors  and assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+OsiLinkedBound::OsiLinkedBound ()
+{
+    model_ = NULL;
+    variable_ = -1;
+    numberAffected_ = 0;
+    maximumAffected_ = numberAffected_;
+    affected_ = NULL;
+}
+// Useful Constructor
+OsiLinkedBound::OsiLinkedBound(OsiSolverInterface * model, int variable,
+                               int numberAffected, const int * positionL,
+                               const int * positionU, const double * multiplier)
+{
+    model_ = model;
+    variable_ = variable;
+    numberAffected_ = 2 * numberAffected;
+    maximumAffected_ = numberAffected_;
+    if (numberAffected_) {
+        affected_ = new boundElementAction[numberAffected_];
+        int n = 0;
+        for (int i = 0; i < numberAffected; i++) {
+            // LB
+            boundElementAction action;
+            action.affect = 2;
+            action.ubUsed = 0;
+            action.type = 0;
+            action.affected = positionL[i];
+            action.multiplier = multiplier[i];
+            affected_[n++] = action;
+            // UB
+            action.affect = 2;
+            action.ubUsed = 1;
+            action.type = 0;
+            action.affected = positionU[i];
+            action.multiplier = multiplier[i];
+            affected_[n++] = action;
+        }
+    } else {
+        affected_ = NULL;
+    }
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+OsiLinkedBound::OsiLinkedBound (
+    const OsiLinkedBound & rhs)
+{
+    model_ = rhs.model_;
+    variable_ = rhs.variable_;
+    numberAffected_ = rhs.numberAffected_;
+    maximumAffected_ = rhs.maximumAffected_;
+    if (numberAffected_) {
+        affected_ = new boundElementAction[maximumAffected_];
+        memcpy(affected_, rhs.affected_, numberAffected_*sizeof(boundElementAction));
+    } else {
+        affected_ = NULL;
+    }
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+OsiLinkedBound::~OsiLinkedBound ()
+{
+    delete [] affected_;
+}
+
+//-------------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+OsiLinkedBound &
+OsiLinkedBound::operator=(const OsiLinkedBound & rhs)
+{
+    if (this != &rhs) {
+        delete [] affected_;
+        model_ = rhs.model_;
+        variable_ = rhs.variable_;
+        numberAffected_ = rhs.numberAffected_;
+        maximumAffected_ = rhs.maximumAffected_;
+        if (numberAffected_) {
+            affected_ = new boundElementAction[maximumAffected_];
+            memcpy(affected_, rhs.affected_, numberAffected_*sizeof(boundElementAction));
+        } else {
+            affected_ = NULL;
+        }
+    }
+    return *this;
+}
+// Add a bound modifier
+void
+OsiLinkedBound::addBoundModifier(bool upperBoundAffected, bool useUpperBound, int whichVariable,
+                                 double multiplier)
+{
+    if (numberAffected_ == maximumAffected_) {
+        maximumAffected_ = maximumAffected_ + 10 + maximumAffected_ / 4;
+        boundElementAction * temp = new boundElementAction[maximumAffected_];
+        memcpy(temp, affected_, numberAffected_*sizeof(boundElementAction));
+        delete [] affected_;
+        affected_ = temp;
+    }
+    boundElementAction action;
+    action.affect = static_cast<unsigned char>(upperBoundAffected ? 1 : 0);
+    action.ubUsed = static_cast<unsigned char>(useUpperBound ? 1 : 0);
+    action.type = 2;
+    action.affected = static_cast<short int>(whichVariable);
+    action.multiplier = multiplier;
+    affected_[numberAffected_++] = action;
+
+}
+// Update other bounds
+void
+OsiLinkedBound::updateBounds(ClpSimplex * solver)
+{
+    double * lower = solver->columnLower();
+    double * upper = solver->columnUpper();
+    double lo = lower[variable_];
+    double up = upper[variable_];
+    // printf("bounds for %d are %g and %g\n",variable_,lo,up);
+    for (int j = 0; j < numberAffected_; j++) {
+        if (affected_[j].affect < 2) {
+            double multiplier = affected_[j].multiplier;
+            assert (affected_[j].type == 2);
+            int iColumn = affected_[j].affected;
+            double useValue = (affected_[j].ubUsed) ? up : lo;
+            if (affected_[j].affect == 0)
+                lower[iColumn] = CoinMin(upper[iColumn], CoinMax(lower[iColumn], multiplier * useValue));
+            else
+                upper[iColumn] = CoinMax(lower[iColumn], CoinMin(upper[iColumn], multiplier * useValue));
+        }
+    }
+}
+#ifdef JJF_ZERO
+// Add an element modifier
+void
+OsiLinkedBound::addCoefficientModifier(bool useUpperBound, int position,
+                                       double multiplier)
+{
+    if (numberAffected_ == maximumAffected_) {
+        maximumAffected_ = maximumAffected_ + 10 + maximumAffected_ / 4;
+        boundElementAction * temp = new boundElementAction[maximumAffected_];
+        memcpy(temp, affected_, numberAffected_*sizeof(boundElementAction));
+        delete [] affected_;
+        affected_ = temp;
+    }
+    boundElementAction action;
+    action.affect = 2;
+    action.ubUsed = useUpperBound ? 1 : 0;
+    action.type = 0;
+    action.affected = position;
+    action.multiplier = multiplier;
+    affected_[numberAffected_++] = action;
+
+}
+// Update coefficients
+void
+OsiLinkedBound::updateCoefficients(ClpSimplex * solver, CoinPackedMatrix * matrix)
+{
+    double * lower = solver->columnLower();
+    double * upper = solver->columnUpper();
+    double * element = matrix->getMutableElements();
+    double lo = lower[variable_];
+    double up = upper[variable_];
+    // printf("bounds for %d are %g and %g\n",variable_,lo,up);
+    for (int j = 0; j < numberAffected_; j++) {
+        if (affected_[j].affect == 2) {
+            double multiplier = affected_[j].multiplier;
+            assert (affected_[j].type == 0);
+            int position = affected_[j].affected;
+            //double old = element[position];
+            if (affected_[j].ubUsed)
+                element[position] = multiplier * up;
+            else
+                element[position] = multiplier * lo;
+            //if ( old != element[position])
+            //printf("change at %d from %g to %g\n",position,old,element[position]);
+        }
+    }
+}
+#endif
+// Default Constructor
+CbcHeuristicDynamic3::CbcHeuristicDynamic3()
+        : CbcHeuristic()
+{
+}
+
+// Constructor from model
+CbcHeuristicDynamic3::CbcHeuristicDynamic3(CbcModel & model)
+        : CbcHeuristic(model)
+{
+}
+
+// Destructor
+CbcHeuristicDynamic3::~CbcHeuristicDynamic3 ()
+{
+}
+
+// Clone
+CbcHeuristic *
+CbcHeuristicDynamic3::clone() const
+{
+    return new CbcHeuristicDynamic3(*this);
+}
+
+// Copy constructor
+CbcHeuristicDynamic3::CbcHeuristicDynamic3(const CbcHeuristicDynamic3 & rhs)
+        :
+        CbcHeuristic(rhs)
+{
+}
+
+// Returns 1 if solution, 0 if not
+int
+CbcHeuristicDynamic3::solution(double & solutionValue,
+                               double * betterSolution)
+{
+    if (!model_)
+        return 0;
+    OsiSolverLink * clpSolver
+    = dynamic_cast<OsiSolverLink *> (model_->solver());
+    assert (clpSolver);
+    double newSolutionValue = clpSolver->bestObjectiveValue();
+    const double * solution = clpSolver->bestSolution();
+    if (newSolutionValue < solutionValue && solution) {
+        int numberColumns = clpSolver->getNumCols();
+        // new solution
+        memcpy(betterSolution, solution, numberColumns*sizeof(double));
+        solutionValue = newSolutionValue;
+        return 1;
+    } else {
+        return 0;
+    }
+}
+// update model
+void CbcHeuristicDynamic3::setModel(CbcModel * model)
+{
+    model_ = model;
+}
+// Resets stuff if model changes
+void
+CbcHeuristicDynamic3::resetModel(CbcModel * model)
+{
+    model_ = model;
+}
+#include <cassert>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "OsiSolverInterface.hpp"
+//#include "OsiBranchLink.hpp"
+#include "CoinError.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinWarmStartBasis.hpp"
+
+// Default Constructor
+OsiOldLink::OsiOldLink ()
+        : OsiSOS(),
+        numberLinks_(0)
+{
+}
+
+// Useful constructor (which are indices)
+OsiOldLink::OsiOldLink (const OsiSolverInterface * /*solver*/,  int numberMembers,
+                        int numberLinks, int first , const double * weights, int /*identifier*/)
+        : OsiSOS(),
+        numberLinks_(numberLinks)
+{
+    numberMembers_ = numberMembers;
+    members_ = NULL;
+    sosType_ = 1;
+    if (numberMembers_) {
+        weights_ = new double[numberMembers_];
+        members_ = new int[numberMembers_*numberLinks_];
+        if (weights) {
+            memcpy(weights_, weights, numberMembers_*sizeof(double));
+        } else {
+            for (int i = 0; i < numberMembers_; i++)
+                weights_[i] = i;
+        }
+        // weights must be increasing
+        int i;
+#ifndef NDEBUG
+        for (i = 1; i < numberMembers_; i++)
+            assert (weights_[i] > weights_[i-1] + 1.0e-12);
+#endif
+        for (i = 0; i < numberMembers_*numberLinks_; i++) {
+            members_[i] = first + i;
+        }
+    } else {
+        weights_ = NULL;
+    }
+}
+
+// Useful constructor (which are indices)
+OsiOldLink::OsiOldLink (const OsiSolverInterface * /*solver*/,  int numberMembers,
+                        int numberLinks, int /*sosType*/, const int * which ,
+                        const double * weights, int /*identifier*/)
+        : OsiSOS(),
+        numberLinks_(numberLinks)
+{
+    numberMembers_ = numberMembers;
+    members_ = NULL;
+    sosType_ = 1;
+    if (numberMembers_) {
+        weights_ = new double[numberMembers_];
+        members_ = new int[numberMembers_*numberLinks_];
+        if (weights) {
+            memcpy(weights_, weights, numberMembers_*sizeof(double));
+        } else {
+            for (int i = 0; i < numberMembers_; i++)
+                weights_[i] = i;
+        }
+        // weights must be increasing
+        int i;
+#ifndef NDEBUG
+        for (i = 1; i < numberMembers_; i++)
+            assert (weights_[i] > weights_[i-1] + 1.0e-12);
+#endif
+        for (i = 0; i < numberMembers_*numberLinks_; i++) {
+            members_[i] = which[i];
+        }
+    } else {
+        weights_ = NULL;
+    }
+}
+
+// Copy constructor
+OsiOldLink::OsiOldLink ( const OsiOldLink & rhs)
+        : OsiSOS(rhs)
+{
+    numberLinks_ = rhs.numberLinks_;
+    if (numberMembers_) {
+        delete [] members_;
+        members_ = CoinCopyOfArray(rhs.members_, numberMembers_ * numberLinks_);
+    }
+}
+
+// Clone
+OsiObject *
+OsiOldLink::clone() const
+{
+    return new OsiOldLink(*this);
+}
+
+// Assignment operator
+OsiOldLink &
+OsiOldLink::operator=( const OsiOldLink & rhs)
+{
+    if (this != &rhs) {
+        OsiSOS::operator=(rhs);
+        delete [] members_;
+        numberLinks_ = rhs.numberLinks_;
+        if (numberMembers_) {
+            members_ = CoinCopyOfArray(rhs.members_, numberMembers_ * numberLinks_);
+        } else {
+            members_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Destructor
+OsiOldLink::~OsiOldLink ()
+{
+}
+
+// Infeasibility - large is 0.5
+double
+OsiOldLink::infeasibility(const OsiBranchingInformation * info, int & whichWay) const
+{
+    int j;
+    int firstNonZero = -1;
+    int lastNonZero = -1;
+    const double * solution = info->solution_;
+    //const double * lower = info->lower_;
+    const double * upper = info->upper_;
+    double integerTolerance = info->integerTolerance_;
+    double weight = 0.0;
+    double sum = 0.0;
+
+    // check bounds etc
+    double lastWeight = -1.0e100;
+    int base = 0;
+    for (j = 0; j < numberMembers_; j++) {
+        for (int k = 0; k < numberLinks_; k++) {
+            int iColumn = members_[base+k];
+            if (lastWeight >= weights_[j] - 1.0e-7)
+                throw CoinError("Weights too close together in OsiLink", "infeasibility", "OsiLink");
+            lastWeight = weights_[j];
+            double value = CoinMax(0.0, solution[iColumn]);
+            sum += value;
+            if (value > integerTolerance && upper[iColumn]) {
+                // Possibly due to scaling a fixed variable might slip through
+                if (value > upper[iColumn] + 1.0e-8) {
+#ifdef OSI_DEBUG
+                    printf("** Variable %d (%d) has value %g and upper bound of %g\n",
+                           iColumn, j, value, upper[iColumn]);
+#endif
+                }
+                value = CoinMin(value, upper[iColumn]);
+                weight += weights_[j] * value;
+                if (firstNonZero < 0)
+                    firstNonZero = j;
+                lastNonZero = j;
+            }
+        }
+        base += numberLinks_;
+    }
+    double valueInfeasibility;
+    whichWay = 1;
+    whichWay_ = 1;
+    if (lastNonZero - firstNonZero >= sosType_) {
+        // find where to branch
+        assert (sum > 0.0);
+        weight /= sum;
+        valueInfeasibility = lastNonZero - firstNonZero + 1;
+        valueInfeasibility *= 0.5 / static_cast<double> (numberMembers_);
+        //#define DISTANCE
+#ifdef DISTANCE
+        assert (sosType_ == 1); // code up
+        /* may still be satisfied.
+           For LOS type 2 we might wish to move coding around
+           and keep initial info in model_ for speed
+        */
+        int iWhere;
+        bool possible = false;
+        for (iWhere = firstNonZero; iWhere <= lastNonZero; iWhere++) {
+            if (fabs(weight - weights_[iWhere]) < 1.0e-8) {
+                possible = true;
+                break;
+            }
+        }
+        if (possible) {
+            // One could move some of this (+ arrays) into model_
+            const CoinPackedMatrix * matrix = solver->getMatrixByCol();
+            const double * element = matrix->getMutableElements();
+            const int * row = matrix->getIndices();
+            const CoinBigIndex * columnStart = matrix->getVectorStarts();
+            const int * columnLength = matrix->getVectorLengths();
+            const double * rowSolution = solver->getRowActivity();
+            const double * rowLower = solver->getRowLower();
+            const double * rowUpper = solver->getRowUpper();
+            int numberRows = matrix->getNumRows();
+            double * array = new double [numberRows];
+            CoinZeroN(array, numberRows);
+            int * which = new int [numberRows];
+            int n = 0;
+            int base = numberLinks_ * firstNonZero;
+            for (j = firstNonZero; j <= lastNonZero; j++) {
+                for (int k = 0; k < numberLinks_; k++) {
+                    int iColumn = members_[base+k];
+                    double value = CoinMax(0.0, solution[iColumn]);
+                    if (value > integerTolerance && upper[iColumn]) {
+                        value = CoinMin(value, upper[iColumn]);
+                        for (int j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                            int iRow = row[j];
+                            double a = array[iRow];
+                            if (a) {
+                                a += value * element[j];
+                                if (!a)
+                                    a = 1.0e-100;
+                            } else {
+                                which[n++] = iRow;
+                                a = value * element[j];
+                                assert (a);
+                            }
+                            array[iRow] = a;
+                        }
+                    }
+                }
+                base += numberLinks_;
+            }
+            base = numberLinks_ * iWhere;
+            for (int k = 0; k < numberLinks_; k++) {
+                int iColumn = members_[base+k];
+                const double value = 1.0;
+                for (int j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    double a = array[iRow];
+                    if (a) {
+                        a -= value * element[j];
+                        if (!a)
+                            a = 1.0e-100;
+                    } else {
+                        which[n++] = iRow;
+                        a = -value * element[j];
+                        assert (a);
+                    }
+                    array[iRow] = a;
+                }
+            }
+            for (j = 0; j < n; j++) {
+                int iRow = which[j];
+                // moving to point will increase row solution by this
+                double distance = array[iRow];
+                if (distance > 1.0e-8) {
+                    if (distance + rowSolution[iRow] > rowUpper[iRow] + 1.0e-8) {
+                        possible = false;
+                        break;
+                    }
+                } else if (distance < -1.0e-8) {
+                    if (distance + rowSolution[iRow] < rowLower[iRow] - 1.0e-8) {
+                        possible = false;
+                        break;
+                    }
+                }
+            }
+            for (j = 0; j < n; j++)
+                array[which[j]] = 0.0;
+            delete [] array;
+            delete [] which;
+            if (possible) {
+                valueInfeasibility = 0.0;
+                printf("possible %d %d %d\n", firstNonZero, lastNonZero, iWhere);
+            }
+        }
+#endif
+    } else {
+        valueInfeasibility = 0.0; // satisfied
+    }
+    infeasibility_ = valueInfeasibility;
+    otherInfeasibility_ = 1.0 - valueInfeasibility;
+    return valueInfeasibility;
+}
+
+// This looks at solution and sets bounds to contain solution
+double
+OsiOldLink::feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const
+{
+    int j;
+    int firstNonZero = -1;
+    int lastNonZero = -1;
+    const double * solution = info->solution_;
+    const double * upper = info->upper_;
+    double integerTolerance = info->integerTolerance_;
+    double weight = 0.0;
+    double sum = 0.0;
+
+    int base = 0;
+    for (j = 0; j < numberMembers_; j++) {
+        for (int k = 0; k < numberLinks_; k++) {
+            int iColumn = members_[base+k];
+            double value = CoinMax(0.0, solution[iColumn]);
+            sum += value;
+            if (value > integerTolerance && upper[iColumn]) {
+                weight += weights_[j] * value;
+                if (firstNonZero < 0)
+                    firstNonZero = j;
+                lastNonZero = j;
+            }
+        }
+        base += numberLinks_;
+    }
+#ifdef DISTANCE
+    if (lastNonZero - firstNonZero > sosType_ - 1) {
+        /* may still be satisfied.
+           For LOS type 2 we might wish to move coding around
+           and keep initial info in model_ for speed
+        */
+        int iWhere;
+        bool possible = false;
+        for (iWhere = firstNonZero; iWhere <= lastNonZero; iWhere++) {
+            if (fabs(weight - weights_[iWhere]) < 1.0e-8) {
+                possible = true;
+                break;
+            }
+        }
+        if (possible) {
+            // One could move some of this (+ arrays) into model_
+            const CoinPackedMatrix * matrix = solver->getMatrixByCol();
+            const double * element = matrix->getMutableElements();
+            const int * row = matrix->getIndices();
+            const CoinBigIndex * columnStart = matrix->getVectorStarts();
+            const int * columnLength = matrix->getVectorLengths();
+            const double * rowSolution = solver->getRowActivity();
+            const double * rowLower = solver->getRowLower();
+            const double * rowUpper = solver->getRowUpper();
+            int numberRows = matrix->getNumRows();
+            double * array = new double [numberRows];
+            CoinZeroN(array, numberRows);
+            int * which = new int [numberRows];
+            int n = 0;
+            int base = numberLinks_ * firstNonZero;
+            for (j = firstNonZero; j <= lastNonZero; j++) {
+                for (int k = 0; k < numberLinks_; k++) {
+                    int iColumn = members_[base+k];
+                    double value = CoinMax(0.0, solution[iColumn]);
+                    if (value > integerTolerance && upper[iColumn]) {
+                        value = CoinMin(value, upper[iColumn]);
+                        for (int j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                            int iRow = row[j];
+                            double a = array[iRow];
+                            if (a) {
+                                a += value * element[j];
+                                if (!a)
+                                    a = 1.0e-100;
+                            } else {
+                                which[n++] = iRow;
+                                a = value * element[j];
+                                assert (a);
+                            }
+                            array[iRow] = a;
+                        }
+                    }
+                }
+                base += numberLinks_;
+            }
+            base = numberLinks_ * iWhere;
+            for (int k = 0; k < numberLinks_; k++) {
+                int iColumn = members_[base+k];
+                const double value = 1.0;
+                for (int j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    double a = array[iRow];
+                    if (a) {
+                        a -= value * element[j];
+                        if (!a)
+                            a = 1.0e-100;
+                    } else {
+                        which[n++] = iRow;
+                        a = -value * element[j];
+                        assert (a);
+                    }
+                    array[iRow] = a;
+                }
+            }
+            for (j = 0; j < n; j++) {
+                int iRow = which[j];
+                // moving to point will increase row solution by this
+                double distance = array[iRow];
+                if (distance > 1.0e-8) {
+                    if (distance + rowSolution[iRow] > rowUpper[iRow] + 1.0e-8) {
+                        possible = false;
+                        break;
+                    }
+                } else if (distance < -1.0e-8) {
+                    if (distance + rowSolution[iRow] < rowLower[iRow] - 1.0e-8) {
+                        possible = false;
+                        break;
+                    }
+                }
+            }
+            for (j = 0; j < n; j++)
+                array[which[j]] = 0.0;
+            delete [] array;
+            delete [] which;
+            if (possible) {
+                printf("possible feas region %d %d %d\n", firstNonZero, lastNonZero, iWhere);
+                firstNonZero = iWhere;
+                lastNonZero = iWhere;
+            }
+        }
+    }
+#else
+    assert (lastNonZero - firstNonZero < sosType_) ;
+#endif
+    base = 0;
+    for (j = 0; j < firstNonZero; j++) {
+        for (int k = 0; k < numberLinks_; k++) {
+            int iColumn = members_[base+k];
+            solver->setColUpper(iColumn, 0.0);
+        }
+        base += numberLinks_;
+    }
+    // skip
+    base += numberLinks_;
+    for (j = lastNonZero + 1; j < numberMembers_; j++) {
+        for (int k = 0; k < numberLinks_; k++) {
+            int iColumn = members_[base+k];
+            solver->setColUpper(iColumn, 0.0);
+        }
+        base += numberLinks_;
+    }
+    // go to coding as in OsiSOS
+    abort();
+    return -1.0;
+}
+
+// Redoes data when sequence numbers change
+void
+OsiOldLink::resetSequenceEtc(int numberColumns, const int * originalColumns)
+{
+    int n2 = 0;
+    for (int j = 0; j < numberMembers_*numberLinks_; j++) {
+        int iColumn = members_[j];
+        int i;
+#ifdef JJF_ZERO
+        for (i = 0; i < numberColumns; i++) {
+            if (originalColumns[i] == iColumn)
+                break;
+        }
+#else
+        i = originalColumns[iColumn];
+#endif
+        if (i >= 0 && i < numberColumns) {
+            members_[n2] = i;
+            weights_[n2++] = weights_[j];
+        }
+    }
+    if (n2 < numberMembers_) {
+        printf("** SOS number of members reduced from %d to %d!\n", numberMembers_, n2 / numberLinks_);
+        numberMembers_ = n2 / numberLinks_;
+    }
+}
+
+// Creates a branching object
+OsiBranchingObject *
+OsiOldLink::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const
+{
+    int j;
+    const double * solution = info->solution_;
+    double tolerance = info->primalTolerance_;
+    const double * upper = info->upper_;
+    int firstNonFixed = -1;
+    int lastNonFixed = -1;
+    int firstNonZero = -1;
+    int lastNonZero = -1;
+    double weight = 0.0;
+    double sum = 0.0;
+    int base = 0;
+    for (j = 0; j < numberMembers_; j++) {
+        for (int k = 0; k < numberLinks_; k++) {
+            int iColumn = members_[base+k];
+            if (upper[iColumn]) {
+                double value = CoinMax(0.0, solution[iColumn]);
+                sum += value;
+                if (firstNonFixed < 0)
+                    firstNonFixed = j;
+                lastNonFixed = j;
+                if (value > tolerance) {
+                    weight += weights_[j] * value;
+                    if (firstNonZero < 0)
+                        firstNonZero = j;
+                    lastNonZero = j;
+                }
+            }
+        }
+        base += numberLinks_;
+    }
+    assert (lastNonZero - firstNonZero >= sosType_) ;
+    // find where to branch
+    assert (sum > 0.0);
+    weight /= sum;
+    int iWhere;
+    double separator = 0.0;
+    for (iWhere = firstNonZero; iWhere < lastNonZero; iWhere++)
+        if (weight < weights_[iWhere+1])
+            break;
+    if (sosType_ == 1) {
+        // SOS 1
+        separator = 0.5 * (weights_[iWhere] + weights_[iWhere+1]);
+    } else {
+        // SOS 2
+        if (iWhere == firstNonFixed)
+            iWhere++;;
+        if (iWhere == lastNonFixed - 1)
+            iWhere = lastNonFixed - 2;
+        separator = weights_[iWhere+1];
+    }
+    // create object
+    OsiBranchingObject * branch;
+    branch = new OsiOldLinkBranchingObject(solver, this, way, separator);
+    return branch;
+}
+OsiOldLinkBranchingObject::OsiOldLinkBranchingObject()
+        : OsiSOSBranchingObject()
+{
+}
+
+// Useful constructor
+OsiOldLinkBranchingObject::OsiOldLinkBranchingObject (OsiSolverInterface * solver,
+        const OsiOldLink * set,
+        int way ,
+        double separator)
+        : OsiSOSBranchingObject(solver, set, way, separator)
+{
+}
+
+// Copy constructor
+OsiOldLinkBranchingObject::OsiOldLinkBranchingObject ( const OsiOldLinkBranchingObject & rhs) : OsiSOSBranchingObject(rhs)
+{
+}
+
+// Assignment operator
+OsiOldLinkBranchingObject &
+OsiOldLinkBranchingObject::operator=( const OsiOldLinkBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        OsiSOSBranchingObject::operator=(rhs);
+    }
+    return *this;
+}
+OsiBranchingObject *
+OsiOldLinkBranchingObject::clone() const
+{
+    return (new OsiOldLinkBranchingObject(*this));
+}
+
+
+// Destructor
+OsiOldLinkBranchingObject::~OsiOldLinkBranchingObject ()
+{
+}
+double
+OsiOldLinkBranchingObject::branch(OsiSolverInterface * solver)
+{
+    const OsiOldLink * set =
+        dynamic_cast <const OsiOldLink *>(originalObject_) ;
+    assert (set);
+    int way = (!branchIndex_) ? (2 * firstBranch_ - 1) : -(2 * firstBranch_ - 1);
+    branchIndex_++;
+    int numberMembers = set->numberMembers();
+    const int * which = set->members();
+    const double * weights = set->weights();
+    int numberLinks = set->numberLinks();
+    //const double * lower = info->lower_;
+    //const double * upper = solver->getColUpper();
+    // *** for way - up means fix all those in down section
+    if (way < 0) {
+        int i;
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] > value_)
+                break;
+        }
+        assert (i < numberMembers);
+        int base = i * numberLinks;;
+        for (; i < numberMembers; i++) {
+            for (int k = 0; k < numberLinks; k++) {
+                int iColumn = which[base+k];
+                solver->setColUpper(iColumn, 0.0);
+            }
+            base += numberLinks;
+        }
+    } else {
+        int i;
+        int base = 0;
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] >= value_) {
+                break;
+            } else {
+                for (int k = 0; k < numberLinks; k++) {
+                    int iColumn = which[base+k];
+                    solver->setColUpper(iColumn, 0.0);
+                }
+                base += numberLinks;
+            }
+        }
+        assert (i < numberMembers);
+    }
+    return 0.0;
+}
+// Print what would happen
+void
+OsiOldLinkBranchingObject::print(const OsiSolverInterface * solver)
+{
+    const OsiOldLink * set =
+        dynamic_cast <const OsiOldLink *>(originalObject_) ;
+    assert (set);
+    int way = (!branchIndex_) ? (2 * firstBranch_ - 1) : -(2 * firstBranch_ - 1);
+    int numberMembers = set->numberMembers();
+    int numberLinks = set->numberLinks();
+    const double * weights = set->weights();
+    const int * which = set->members();
+    const double * upper = solver->getColUpper();
+    int first = numberMembers;
+    int last = -1;
+    int numberFixed = 0;
+    int numberOther = 0;
+    int i;
+    int base = 0;
+    for ( i = 0; i < numberMembers; i++) {
+        for (int k = 0; k < numberLinks; k++) {
+            int iColumn = which[base+k];
+            double bound = upper[iColumn];
+            if (bound) {
+                first = CoinMin(first, i);
+                last = CoinMax(last, i);
+            }
+        }
+        base += numberLinks;
+    }
+    // *** for way - up means fix all those in down section
+    base = 0;
+    if (way < 0) {
+        printf("SOS Down");
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] > value_)
+                break;
+            for (int k = 0; k < numberLinks; k++) {
+                int iColumn = which[base+k];
+                double bound = upper[iColumn];
+                if (bound)
+                    numberOther++;
+            }
+            base += numberLinks;
+        }
+        assert (i < numberMembers);
+        for (; i < numberMembers; i++) {
+            for (int k = 0; k < numberLinks; k++) {
+                int iColumn = which[base+k];
+                double bound = upper[iColumn];
+                if (bound)
+                    numberFixed++;
+            }
+            base += numberLinks;
+        }
+    } else {
+        printf("SOS Up");
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] >= value_)
+                break;
+            for (int k = 0; k < numberLinks; k++) {
+                int iColumn = which[base+k];
+                double bound = upper[iColumn];
+                if (bound)
+                    numberFixed++;
+            }
+            base += numberLinks;
+        }
+        assert (i < numberMembers);
+        for (; i < numberMembers; i++) {
+            for (int k = 0; k < numberLinks; k++) {
+                int iColumn = which[base+k];
+                double bound = upper[iColumn];
+                if (bound)
+                    numberOther++;
+            }
+            base += numberLinks;
+        }
+    }
+    assert ((numberFixed % numberLinks) == 0);
+    assert ((numberOther % numberLinks) == 0);
+    printf(" - at %g, free range %d (%g) => %d (%g), %d would be fixed, %d other way\n",
+           value_, first, weights[first], last, weights[last], numberFixed / numberLinks,
+           numberOther / numberLinks);
+}
+// Default Constructor
+OsiBiLinear::OsiBiLinear ()
+        : OsiObject2(),
+        coefficient_(0.0),
+        xMeshSize_(0.0),
+        yMeshSize_(0.0),
+        xSatisfied_(1.0e-6),
+        ySatisfied_(1.0e-6),
+        xOtherSatisfied_(0.0),
+        yOtherSatisfied_(0.0),
+        xySatisfied_(1.0e-6),
+        xyBranchValue_(0.0),
+        xColumn_(-1),
+        yColumn_(-1),
+        firstLambda_(-1),
+        branchingStrategy_(0),
+        boundType_(0),
+        xRow_(-1),
+        yRow_(-1),
+        xyRow_(-1),
+        convexity_(-1),
+        numberExtraRows_(0),
+        multiplier_(NULL),
+        extraRow_(NULL),
+        chosen_(-1)
+{
+}
+
+// Useful constructor
+OsiBiLinear::OsiBiLinear (OsiSolverInterface * solver, int xColumn,
+                          int yColumn, int xyRow, double coefficient,
+                          double xMesh, double yMesh,
+                          int numberExistingObjects, const OsiObject ** objects )
+        : OsiObject2(),
+        coefficient_(coefficient),
+        xMeshSize_(xMesh),
+        yMeshSize_(yMesh),
+        xSatisfied_(1.0e-6),
+        ySatisfied_(1.0e-6),
+        xOtherSatisfied_(0.0),
+        yOtherSatisfied_(0.0),
+        xySatisfied_(1.0e-6),
+        xyBranchValue_(0.0),
+        xColumn_(xColumn),
+        yColumn_(yColumn),
+        firstLambda_(-1),
+        branchingStrategy_(0),
+        boundType_(0),
+        xRow_(-1),
+        yRow_(-1),
+        xyRow_(xyRow),
+        convexity_(-1),
+        numberExtraRows_(0),
+        multiplier_(NULL),
+        extraRow_(NULL),
+        chosen_(-1)
+{
+    double columnLower[4];
+    double columnUpper[4];
+    double objective[4];
+    double rowLower[3];
+    double rowUpper[3];
+    CoinBigIndex starts[5];
+    int index[16];
+    double element[16];
+    int i;
+    starts[0] = 0;
+    // rows
+    int numberRows = solver->getNumRows();
+    // convexity
+    rowLower[0] = 1.0;
+    rowUpper[0] = 1.0;
+    convexity_ = numberRows;
+    starts[1] = 0;
+    // x
+    rowLower[1] = 0.0;
+    rowUpper[1] = 0.0;
+    index[0] = xColumn_;
+    element[0] = -1.0;
+    xRow_ = numberRows + 1;
+    starts[2] = 1;
+    int nAdd = 2;
+    if (xColumn_ != yColumn_) {
+        rowLower[2] = 0.0;
+        rowUpper[2] = 0.0;
+        index[1] = yColumn;
+        element[1] = -1.0;
+        nAdd = 3;
+        yRow_ = numberRows + 2;
+        starts[3] = 2;
+    } else {
+        yRow_ = -1;
+        branchingStrategy_ = 1;
+    }
+    // may be objective
+    assert (xyRow_ >= -1);
+    solver->addRows(nAdd, starts, index, element, rowLower, rowUpper);
+    int n = 0;
+    // order is LxLy, LxUy, UxLy and UxUy
+    firstLambda_ = solver->getNumCols();
+    // bit sloppy as theoretically could be infeasible but otherwise need to do more work
+    double xB[2];
+    double yB[2];
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    xB[0] = lower[xColumn_];
+    xB[1] = upper[xColumn_];
+    yB[0] = lower[yColumn_];
+    yB[1] = upper[yColumn_];
+    if (xMeshSize_ != floor(xMeshSize_)) {
+        // not integral
+        xSatisfied_ = CoinMax(xSatisfied_, 0.51 * xMeshSize_);
+        if (!yMeshSize_) {
+            xySatisfied_ = CoinMax(xySatisfied_, xSatisfied_ * CoinMax(fabs(yB[0]), fabs(yB[1])));
+        }
+    }
+    if (yMeshSize_ != floor(yMeshSize_)) {
+        // not integral
+        ySatisfied_ = CoinMax(ySatisfied_, 0.51 * yMeshSize_);
+        if (!xMeshSize_) {
+            xySatisfied_ = CoinMax(xySatisfied_, ySatisfied_ * CoinMax(fabs(xB[0]), fabs(xB[1])));
+        }
+    }
+    // adjust
+    double distance;
+    double steps;
+    if (xMeshSize_) {
+        distance = xB[1] - xB[0];
+        steps = floor ((distance + 0.5 * xMeshSize_) / xMeshSize_);
+        distance = xB[0] + xMeshSize_ * steps;
+        if (fabs(xB[1] - distance) > xSatisfied_) {
+            printf("bad x mesh %g %g %g -> %g\n", xB[0], xMeshSize_, xB[1], distance);
+            //double newValue = CoinMax(fabs(xB[1]-distance),xMeshSize_);
+            //printf("xSatisfied increased to %g\n",newValue);
+            //xSatisfied_ = newValue;
+            //xB[1]=distance;
+            //solver->setColUpper(xColumn_,distance);
+        }
+    }
+    if (yMeshSize_) {
+        distance = yB[1] - yB[0];
+        steps = floor ((distance + 0.5 * yMeshSize_) / yMeshSize_);
+        distance = yB[0] + yMeshSize_ * steps;
+        if (fabs(yB[1] - distance) > ySatisfied_) {
+            printf("bad y mesh %g %g %g -> %g\n", yB[0], yMeshSize_, yB[1], distance);
+            //double newValue = CoinMax(fabs(yB[1]-distance),yMeshSize_);
+            //printf("ySatisfied increased to %g\n",newValue);
+            //ySatisfied_ = newValue;
+            //yB[1]=distance;
+            //solver->setColUpper(yColumn_,distance);
+        }
+    }
+    for (i = 0; i < 4; i++) {
+        double x = (i < 2) ? xB[0] : xB[1];
+        double y = ((i & 1) == 0) ? yB[0] : yB[1];
+        columnLower[i] = 0.0;
+        columnUpper[i] = 2.0;
+        objective[i] = 0.0;
+        double value;
+        // xy
+        value = coefficient_ * x * y;
+        if (xyRow_ >= 0) {
+            if (fabs(value) < 1.0e-19)
+                value = 1.0e-19;
+            element[n] = value;
+            index[n++] = xyRow_;
+        } else {
+            objective[i] = value;
+        }
+        // convexity
+        value = 1.0;
+        element[n] = value;
+        index[n++] = 0 + numberRows;
+        // x
+        value = x;
+        if (fabs(value) < 1.0e-19)
+            value = 1.0e-19;
+        element[n] = value;
+        index[n++] = 1 + numberRows;
+        if (xColumn_ != yColumn_) {
+            // y
+            value = y;
+            if (fabs(value) < 1.0e-19)
+                value = 1.0e-19;
+            element[n] = value;
+            index[n++] = 2 + numberRows;
+        }
+        starts[i+1] = n;
+    }
+    solver->addCols(4, starts, index, element, columnLower, columnUpper, objective);
+    // At least one has to have a mesh
+    if (!xMeshSize_ && (!yMeshSize_ || yRow_ < 0)) {
+        printf("one of x and y must have a mesh size\n");
+        abort();
+    } else if (yRow_ >= 0) {
+        if (!xMeshSize_)
+            branchingStrategy_ = 2;
+        else if (!yMeshSize_)
+            branchingStrategy_ = 1;
+    }
+    // Now add constraints to link in x and or y to existing ones.
+    bool xDone = false;
+    bool yDone = false;
+    // order is LxLy, LxUy, UxLy and UxUy
+    for (i = numberExistingObjects - 1; i >= 0; i--) {
+        const OsiObject * obj = objects[i];
+        const OsiBiLinear * obj2 =
+            dynamic_cast <const OsiBiLinear *>(obj) ;
+        if (obj2) {
+            if (xColumn_ == obj2->xColumn_ && !xDone) {
+                // make sure y equal
+                double rhs = 0.0;
+                CoinBigIndex starts[2];
+                int index[4];
+                double element[4] = {1.0, 1.0, -1.0, -1.0};
+                starts[0] = 0;
+                starts[1] = 4;
+                index[0] = firstLambda_ + 0;
+                index[1] = firstLambda_ + 1;
+                index[2] = obj2->firstLambda_ + 0;
+                index[3] = obj2->firstLambda_ + 1;
+                solver->addRows(1, starts, index, element, &rhs, &rhs);
+                xDone = true;
+            }
+            if (yColumn_ == obj2->yColumn_ && yRow_ >= 0 && !yDone) {
+                // make sure x equal
+                double rhs = 0.0;
+                CoinBigIndex starts[2];
+                int index[4];
+                double element[4] = {1.0, 1.0, -1.0, -1.0};
+                starts[0] = 0;
+                starts[1] = 4;
+                index[0] = firstLambda_ + 0;
+                index[1] = firstLambda_ + 2;
+                index[2] = obj2->firstLambda_ + 0;
+                index[3] = obj2->firstLambda_ + 2;
+                solver->addRows(1, starts, index, element, &rhs, &rhs);
+                yDone = true;
+            }
+        }
+    }
+}
+// Set sizes and other stuff
+void
+OsiBiLinear::setMeshSizes(const OsiSolverInterface * solver, double x, double y)
+{
+    xMeshSize_ = x;
+    yMeshSize_ = y;
+    double xB[2];
+    double yB[2];
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    xB[0] = lower[xColumn_];
+    xB[1] = upper[xColumn_];
+    yB[0] = lower[yColumn_];
+    yB[1] = upper[yColumn_];
+    if (xMeshSize_ != floor(xMeshSize_)) {
+        // not integral
+        xSatisfied_ = CoinMax(xSatisfied_, 0.51 * xMeshSize_);
+        if (!yMeshSize_) {
+            xySatisfied_ = CoinMax(xySatisfied_, xSatisfied_ * CoinMax(fabs(yB[0]), fabs(yB[1])));
+        }
+    }
+    if (yMeshSize_ != floor(yMeshSize_)) {
+        // not integral
+        ySatisfied_ = CoinMax(ySatisfied_, 0.51 * yMeshSize_);
+        if (!xMeshSize_) {
+            xySatisfied_ = CoinMax(xySatisfied_, ySatisfied_ * CoinMax(fabs(xB[0]), fabs(xB[1])));
+        }
+    }
+}
+// Useful constructor
+OsiBiLinear::OsiBiLinear (CoinModel * coinModel, int xColumn,
+                          int yColumn, int xyRow, double coefficient,
+                          double xMesh, double yMesh,
+                          int numberExistingObjects, const OsiObject ** objects )
+        : OsiObject2(),
+        coefficient_(coefficient),
+        xMeshSize_(xMesh),
+        yMeshSize_(yMesh),
+        xSatisfied_(1.0e-6),
+        ySatisfied_(1.0e-6),
+        xOtherSatisfied_(0.0),
+        yOtherSatisfied_(0.0),
+        xySatisfied_(1.0e-6),
+        xyBranchValue_(0.0),
+        xColumn_(xColumn),
+        yColumn_(yColumn),
+        firstLambda_(-1),
+        branchingStrategy_(0),
+        boundType_(0),
+        xRow_(-1),
+        yRow_(-1),
+        xyRow_(xyRow),
+        convexity_(-1),
+        numberExtraRows_(0),
+        multiplier_(NULL),
+        extraRow_(NULL),
+        chosen_(-1)
+{
+    double columnLower[4];
+    double columnUpper[4];
+    double objective[4];
+    double rowLower[3];
+    double rowUpper[3];
+    CoinBigIndex starts[5];
+    int index[16];
+    double element[16];
+    int i;
+    starts[0] = 0;
+    // rows
+    int numberRows = coinModel->numberRows();
+    // convexity
+    rowLower[0] = 1.0;
+    rowUpper[0] = 1.0;
+    convexity_ = numberRows;
+    starts[1] = 0;
+    // x
+    rowLower[1] = 0.0;
+    rowUpper[1] = 0.0;
+    index[0] = xColumn_;
+    element[0] = -1.0;
+    xRow_ = numberRows + 1;
+    starts[2] = 1;
+    int nAdd = 2;
+    if (xColumn_ != yColumn_) {
+        rowLower[2] = 0.0;
+        rowUpper[2] = 0.0;
+        index[1] = yColumn;
+        element[1] = -1.0;
+        nAdd = 3;
+        yRow_ = numberRows + 2;
+        starts[3] = 2;
+    } else {
+        yRow_ = -1;
+        branchingStrategy_ = 1;
+    }
+    // may be objective
+    assert (xyRow_ >= -1);
+    for (i = 0; i < nAdd; i++) {
+        CoinBigIndex iStart = starts[i];
+        coinModel->addRow(starts[i+1] - iStart, index + iStart, element + iStart, rowLower[i], rowUpper[i]);
+    }
+    int n = 0;
+    // order is LxLy, LxUy, UxLy and UxUy
+    firstLambda_ = coinModel->numberColumns();
+    // bit sloppy as theoretically could be infeasible but otherwise need to do more work
+    double xB[2];
+    double yB[2];
+    const double * lower = coinModel->columnLowerArray();
+    const double * upper = coinModel->columnUpperArray();
+    xB[0] = lower[xColumn_];
+    xB[1] = upper[xColumn_];
+    yB[0] = lower[yColumn_];
+    yB[1] = upper[yColumn_];
+    if (xMeshSize_ != floor(xMeshSize_)) {
+        // not integral
+        xSatisfied_ = CoinMax(xSatisfied_, 0.51 * xMeshSize_);
+        if (!yMeshSize_) {
+            xySatisfied_ = CoinMax(xySatisfied_, xSatisfied_ * CoinMax(fabs(yB[0]), fabs(yB[1])));
+        }
+    }
+    if (yMeshSize_ != floor(yMeshSize_)) {
+        // not integral
+        ySatisfied_ = CoinMax(ySatisfied_, 0.51 * yMeshSize_);
+        if (!xMeshSize_) {
+            xySatisfied_ = CoinMax(xySatisfied_, ySatisfied_ * CoinMax(fabs(xB[0]), fabs(xB[1])));
+        }
+    }
+    // adjust
+    double distance;
+    double steps;
+    if (xMeshSize_) {
+        distance = xB[1] - xB[0];
+        steps = floor ((distance + 0.5 * xMeshSize_) / xMeshSize_);
+        distance = xB[0] + xMeshSize_ * steps;
+        if (fabs(xB[1] - distance) > xSatisfied_) {
+            printf("bad x mesh %g %g %g -> %g\n", xB[0], xMeshSize_, xB[1], distance);
+            //double newValue = CoinMax(fabs(xB[1]-distance),xMeshSize_);
+            //printf("xSatisfied increased to %g\n",newValue);
+            //xSatisfied_ = newValue;
+            //xB[1]=distance;
+            //coinModel->setColUpper(xColumn_,distance);
+        }
+    }
+    if (yMeshSize_) {
+        distance = yB[1] - yB[0];
+        steps = floor ((distance + 0.5 * yMeshSize_) / yMeshSize_);
+        distance = yB[0] + yMeshSize_ * steps;
+        if (fabs(yB[1] - distance) > ySatisfied_) {
+            printf("bad y mesh %g %g %g -> %g\n", yB[0], yMeshSize_, yB[1], distance);
+            //double newValue = CoinMax(fabs(yB[1]-distance),yMeshSize_);
+            //printf("ySatisfied increased to %g\n",newValue);
+            //ySatisfied_ = newValue;
+            //yB[1]=distance;
+            //coinModel->setColUpper(yColumn_,distance);
+        }
+    }
+    for (i = 0; i < 4; i++) {
+        double x = (i < 2) ? xB[0] : xB[1];
+        double y = ((i & 1) == 0) ? yB[0] : yB[1];
+        columnLower[i] = 0.0;
+        columnUpper[i] = 2.0;
+        objective[i] = 0.0;
+        double value;
+        // xy
+        value = coefficient_ * x * y;
+        if (xyRow_ >= 0) {
+            if (fabs(value) < 1.0e-19)
+                value = 1.0e-19;
+            element[n] = value;
+            index[n++] = xyRow_;
+        } else {
+            objective[i] = value;
+        }
+        // convexity
+        value = 1.0;
+        element[n] = value;
+        index[n++] = 0 + numberRows;
+        // x
+        value = x;
+        if (fabs(value) < 1.0e-19)
+            value = 1.0e-19;
+        element[n] = value;
+        index[n++] = 1 + numberRows;
+        if (xColumn_ != yColumn_) {
+            // y
+            value = y;
+            if (fabs(value) < 1.0e-19)
+                value = 1.0e-19;
+            element[n] = value;
+            index[n++] = 2 + numberRows;
+        }
+        starts[i+1] = n;
+    }
+    for (i = 0; i < 4; i++) {
+        CoinBigIndex iStart = starts[i];
+        coinModel->addColumn(starts[i+1] - iStart, index + iStart, element + iStart, columnLower[i],
+                             columnUpper[i], objective[i]);
+    }
+    // At least one has to have a mesh
+    if (!xMeshSize_ && (!yMeshSize_ || yRow_ < 0)) {
+        printf("one of x and y must have a mesh size\n");
+        abort();
+    } else if (yRow_ >= 0) {
+        if (!xMeshSize_)
+            branchingStrategy_ = 2;
+        else if (!yMeshSize_)
+            branchingStrategy_ = 1;
+    }
+    // Now add constraints to link in x and or y to existing ones.
+    bool xDone = false;
+    bool yDone = false;
+    // order is LxLy, LxUy, UxLy and UxUy
+    for (i = numberExistingObjects - 1; i >= 0; i--) {
+        const OsiObject * obj = objects[i];
+        const OsiBiLinear * obj2 =
+            dynamic_cast <const OsiBiLinear *>(obj) ;
+        if (obj2) {
+            if (xColumn_ == obj2->xColumn_ && !xDone) {
+                // make sure y equal
+                double rhs = 0.0;
+                int index[4];
+                double element[4] = {1.0, 1.0, -1.0, -1.0};
+                index[0] = firstLambda_ + 0;
+                index[1] = firstLambda_ + 1;
+                index[2] = obj2->firstLambda_ + 0;
+                index[3] = obj2->firstLambda_ + 1;
+                coinModel->addRow(4, index, element, rhs, rhs);
+                xDone = true;
+            }
+            if (yColumn_ == obj2->yColumn_ && yRow_ >= 0 && !yDone) {
+                // make sure x equal
+                double rhs = 0.0;
+                int index[4];
+                double element[4] = {1.0, 1.0, -1.0, -1.0};
+                index[0] = firstLambda_ + 0;
+                index[1] = firstLambda_ + 2;
+                index[2] = obj2->firstLambda_ + 0;
+                index[3] = obj2->firstLambda_ + 2;
+                coinModel->addRow(4, index, element, rhs, rhs);
+                yDone = true;
+            }
+        }
+    }
+}
+
+// Copy constructor
+OsiBiLinear::OsiBiLinear ( const OsiBiLinear & rhs)
+        : OsiObject2(rhs),
+        coefficient_(rhs.coefficient_),
+        xMeshSize_(rhs.xMeshSize_),
+        yMeshSize_(rhs.yMeshSize_),
+        xSatisfied_(rhs.xSatisfied_),
+        ySatisfied_(rhs.ySatisfied_),
+        xOtherSatisfied_(rhs.xOtherSatisfied_),
+        yOtherSatisfied_(rhs.yOtherSatisfied_),
+        xySatisfied_(rhs.xySatisfied_),
+        xyBranchValue_(rhs.xyBranchValue_),
+        xColumn_(rhs.xColumn_),
+        yColumn_(rhs.yColumn_),
+        firstLambda_(rhs.firstLambda_),
+        branchingStrategy_(rhs.branchingStrategy_),
+        boundType_(rhs.boundType_),
+        xRow_(rhs.xRow_),
+        yRow_(rhs.yRow_),
+        xyRow_(rhs.xyRow_),
+        convexity_(rhs.convexity_),
+        numberExtraRows_(rhs.numberExtraRows_),
+        multiplier_(NULL),
+        extraRow_(NULL),
+        chosen_(rhs.chosen_)
+{
+    if (numberExtraRows_) {
+        multiplier_ = CoinCopyOfArray(rhs.multiplier_, numberExtraRows_);
+        extraRow_ = CoinCopyOfArray(rhs.extraRow_, numberExtraRows_);
+    }
+}
+
+// Clone
+OsiObject *
+OsiBiLinear::clone() const
+{
+    return new OsiBiLinear(*this);
+}
+
+// Assignment operator
+OsiBiLinear &
+OsiBiLinear::operator=( const OsiBiLinear & rhs)
+{
+    if (this != &rhs) {
+        OsiObject2::operator=(rhs);
+        coefficient_ = rhs.coefficient_;
+        xMeshSize_ = rhs.xMeshSize_;
+        yMeshSize_ = rhs.yMeshSize_;
+        xSatisfied_ = rhs.xSatisfied_;
+        ySatisfied_ = rhs.ySatisfied_;
+        xOtherSatisfied_ = rhs.xOtherSatisfied_;
+        yOtherSatisfied_ = rhs.yOtherSatisfied_;
+        xySatisfied_ = rhs.xySatisfied_;
+        xyBranchValue_ = rhs.xyBranchValue_;
+        xColumn_ = rhs.xColumn_;
+        yColumn_ = rhs.yColumn_;
+        firstLambda_ = rhs.firstLambda_;
+        branchingStrategy_ = rhs.branchingStrategy_;
+        boundType_ = rhs.boundType_;
+        xRow_ = rhs.xRow_;
+        yRow_ = rhs.yRow_;
+        xyRow_ = rhs.xyRow_;
+        convexity_ = rhs.convexity_;
+        numberExtraRows_ = rhs.numberExtraRows_;
+        delete [] multiplier_;
+        delete [] extraRow_;
+        if (numberExtraRows_) {
+            multiplier_ = CoinCopyOfArray(rhs.multiplier_, numberExtraRows_);
+            extraRow_ = CoinCopyOfArray(rhs.extraRow_, numberExtraRows_);
+        } else {
+            multiplier_ = NULL;
+            extraRow_ = NULL;
+        }
+        chosen_ = rhs.chosen_;
+    }
+    return *this;
+}
+
+// Destructor
+OsiBiLinear::~OsiBiLinear ()
+{
+    delete [] multiplier_;
+    delete [] extraRow_;
+}
+// Adds in data for extra row with variable coefficients
+void
+OsiBiLinear::addExtraRow(int row, double multiplier)
+{
+    int * tempI = new int [numberExtraRows_+1];
+    double * tempD = new double [numberExtraRows_+1];
+    memcpy(tempI, extraRow_, numberExtraRows_*sizeof(int));
+    memcpy(tempD, multiplier_, numberExtraRows_*sizeof(double));
+    tempI[numberExtraRows_] = row;
+    tempD[numberExtraRows_] = multiplier;
+    if (numberExtraRows_)
+        assert (row > tempI[numberExtraRows_-1]);
+    numberExtraRows_++;
+    delete [] extraRow_;
+    extraRow_ = tempI;
+    delete [] multiplier_;
+    multiplier_ = tempD;
+}
+static bool testCoarse = true;
+// Infeasibility - large is 0.5
+double
+OsiBiLinear::infeasibility(const OsiBranchingInformation * info, int & whichWay) const
+{
+    // order is LxLy, LxUy, UxLy and UxUy
+    double xB[2];
+    double yB[2];
+    xB[0] = info->lower_[xColumn_];
+    xB[1] = info->upper_[xColumn_];
+    yB[0] = info->lower_[yColumn_];
+    yB[1] = info->upper_[yColumn_];
+#ifdef JJF_ZERO
+    if (info->lower_[1] <= 43.0 && info->upper_[1] >= 43.0) {
+        if (info->lower_[4] <= 49.0 && info->upper_[4] >= 49.0) {
+            if (info->lower_[2] <= 16.0 && info->upper_[2] >= 16.0) {
+                if (info->lower_[3] <= 19.0 && info->upper_[3] >= 19.0) {
+                    printf("feas %g %g %g %g  p %g t %g\n",
+                           info->solution_[1],
+                           info->solution_[2],
+                           info->solution_[3],
+                           info->solution_[4],
+                           info->solution_[0],
+                           info->solution_[5]);
+                }
+            }
+        }
+    }
+#endif
+    double x = info->solution_[xColumn_];
+    x = CoinMax(x, xB[0]);
+    x = CoinMin(x, xB[1]);
+    double y = info->solution_[yColumn_];
+    y = CoinMax(y, yB[0]);
+    y = CoinMin(y, yB[1]);
+    int j;
+#ifndef NDEBUG
+    double xLambda = 0.0;
+    double yLambda = 0.0;
+    if ((branchingStrategy_&4) == 0) {
+        for (j = 0; j < 4; j++) {
+            int iX = j >> 1;
+            int iY = j & 1;
+            xLambda += xB[iX] * info->solution_[firstLambda_+j];
+            if (yRow_ >= 0)
+                yLambda += yB[iY] * info->solution_[firstLambda_+j];
+        }
+    } else {
+        const double * element = info->elementByColumn_;
+        const int * row = info->row_;
+        const CoinBigIndex * columnStart = info->columnStart_;
+        const int * columnLength = info->columnLength_;
+        for (j = 0; j < 4; j++) {
+            int iColumn = firstLambda_ + j;
+            int iStart = columnStart[iColumn];
+            int iEnd = iStart + columnLength[iColumn];
+            int k = iStart;
+            double sol = info->solution_[iColumn];
+            for (; k < iEnd; k++) {
+                if (xRow_ == row[k])
+                    xLambda += element[k] * sol;
+                if (yRow_ == row[k])
+                    yLambda += element[k] * sol;
+            }
+        }
+    }
+    assert (fabs(x - xLambda) < 1.0e-1);
+    if (yRow_ >= 0)
+        assert (fabs(y - yLambda) < 1.0e-1);
+#endif
+    // If x or y not satisfied then branch on that
+    double distance;
+    double steps;
+    bool xSatisfied;
+    double xNew = xB[0];
+    if (xMeshSize_) {
+        if (x < 0.5*(xB[0] + xB[1])) {
+            distance = x - xB[0];
+            steps = floor ((distance + 0.5 * xMeshSize_) / xMeshSize_);
+            xNew = xB[0] + steps * xMeshSize_;
+            assert (xNew <= xB[1] + xSatisfied_);
+            xSatisfied =  (fabs(xNew - x) < xSatisfied_);
+        } else {
+            distance = xB[1] - x;
+            steps = floor ((distance + 0.5 * xMeshSize_) / xMeshSize_);
+            xNew = xB[1] - steps * xMeshSize_;
+            assert (xNew >= xB[0] - xSatisfied_);
+            xSatisfied =  (fabs(xNew - x) < xSatisfied_);
+        }
+        // but if first coarse grid then only if gap small
+        if (testCoarse && (branchingStrategy_&8) != 0 && xSatisfied &&
+                xB[1] - xB[0] >= xMeshSize_) {
+            // but allow if fine grid would allow
+            if (fabs(xNew - x) >= xOtherSatisfied_ && fabs(yB[0] - y) > yOtherSatisfied_
+                    && fabs(yB[1] - y) > yOtherSatisfied_) {
+                xNew = 0.5 * (xB[0] + xB[1]);
+                x = xNew;
+                xSatisfied = false;
+            }
+        }
+    } else {
+        xSatisfied = true;
+    }
+    bool ySatisfied;
+    double yNew = yB[0];
+    if (yMeshSize_) {
+        if (y < 0.5*(yB[0] + yB[1])) {
+            distance = y - yB[0];
+            steps = floor ((distance + 0.5 * yMeshSize_) / yMeshSize_);
+            yNew = yB[0] + steps * yMeshSize_;
+            assert (yNew <= yB[1] + ySatisfied_);
+            ySatisfied =  (fabs(yNew - y) < ySatisfied_);
+        } else {
+            distance = yB[1] - y;
+            steps = floor ((distance + 0.5 * yMeshSize_) / yMeshSize_);
+            yNew = yB[1] - steps * yMeshSize_;
+            assert (yNew >= yB[0] - ySatisfied_);
+            ySatisfied =  (fabs(yNew - y) < ySatisfied_);
+        }
+        // but if first coarse grid then only if gap small
+        if (testCoarse && (branchingStrategy_&8) != 0 && ySatisfied &&
+                yB[1] - yB[0] >= yMeshSize_) {
+            // but allow if fine grid would allow
+            if (fabs(yNew - y) >= yOtherSatisfied_ && fabs(xB[0] - x) > xOtherSatisfied_
+                    && fabs(xB[1] - x) > xOtherSatisfied_) {
+                yNew = 0.5 * (yB[0] + yB[1]);
+                y = yNew;
+                ySatisfied = false;
+            }
+        }
+    } else {
+        ySatisfied = true;
+    }
+    /* There are several possibilities
+       1 - one or both are unsatisfied and branching strategy tells us what to do
+       2 - both are unsatisfied and branching strategy is 0
+       3 - both are satisfied but xy is not
+           3a one has bounds within satisfied_ - other does not
+       (or neither have but branching strategy tells us what to do)
+       3b neither do - and branching strategy does not tell us
+       3c both do - treat as feasible knowing another copy of object will fix
+       4 - both are satisfied and xy is satisfied - as 3c
+    */
+    chosen_ = -1;
+    xyBranchValue_ = COIN_DBL_MAX;
+    whichWay_ = 0;
+    double xyTrue = x * y;
+    double xyLambda = 0.0;
+    if ((branchingStrategy_&4) == 0) {
+        for (j = 0; j < 4; j++) {
+            int iX = j >> 1;
+            int iY = j & 1;
+            xyLambda += xB[iX] * yB[iY] * info->solution_[firstLambda_+j];
+        }
+    } else {
+        if (xyRow_ >= 0) {
+            const double * element = info->elementByColumn_;
+            const int * row = info->row_;
+            const CoinBigIndex * columnStart = info->columnStart_;
+            const int * columnLength = info->columnLength_;
+            for (j = 0; j < 4; j++) {
+                int iColumn = firstLambda_ + j;
+                int iStart = columnStart[iColumn];
+                int iEnd = iStart + columnLength[iColumn];
+                int k = iStart;
+                double sol = info->solution_[iColumn];
+                for (; k < iEnd; k++) {
+                    if (xyRow_ == row[k])
+                        xyLambda += element[k] * sol;
+                }
+            }
+        } else {
+            // objective
+            const double * objective = info->objective_;
+            for (j = 0; j < 4; j++) {
+                int iColumn = firstLambda_ + j;
+                double sol = info->solution_[iColumn];
+                xyLambda += objective[iColumn] * sol;
+            }
+        }
+        xyLambda /= coefficient_;
+    }
+    if (0) {
+        // only true with positive values
+        // see if all convexification constraints OK with true
+        assert (xyTrue + 1.0e-5 > xB[0]*y + yB[0]*x - xB[0]*yB[0]);
+        assert (xyTrue + 1.0e-5 > xB[1]*y + yB[1]*x - xB[1]*yB[1]);
+        assert (xyTrue - 1.0e-5 < xB[1]*y + yB[0]*x - xB[1]*yB[0]);
+        assert (xyTrue - 1.0e-5 < xB[0]*y + yB[1]*x - xB[0]*yB[1]);
+        // see if all convexification constraints OK with lambda version
+#ifndef JJF_ONE
+        assert (xyLambda + 1.0e-5 > xB[0]*y + yB[0]*x - xB[0]*yB[0]);
+        assert (xyLambda + 1.0e-5 > xB[1]*y + yB[1]*x - xB[1]*yB[1]);
+        assert (xyLambda - 1.0e-5 < xB[1]*y + yB[0]*x - xB[1]*yB[0]);
+        assert (xyLambda - 1.0e-5 < xB[0]*y + yB[1]*x - xB[0]*yB[1]);
+#endif
+        // see if other bound stuff true
+        assert (xyLambda + 1.0e-5 > xB[0]*y);
+        assert (xyLambda + 1.0e-5 > yB[0]*x);
+        assert (xyLambda - 1.0e-5 < xB[1]*y);
+        assert (xyLambda - 1.0e-5 < yB[1]*x);
+#define SIZE 2
+        if (yColumn_ == xColumn_ + SIZE) {
+#if SIZE==6
+            double bMax = 2200.0;
+            double bMin = bMax - 100.0;
+            double b[] = {330.0, 360.0, 380.0, 430.0, 490.0, 530.0};
+#elif SIZE==2
+            double bMax = 1900.0;
+            double bMin = bMax - 200.0;
+            double b[] = {460.0, 570.0};
+#else
+            abort();
+#endif
+            double sum = 0.0;
+            double sum2 = 0.0;
+            int m = xColumn_;
+            double x = info->solution_[m];
+            double xB[2];
+            double yB[2];
+            xB[0] = info->lower_[m];
+            xB[1] = info->upper_[m];
+            for (int i = 0; i < SIZE*SIZE; i += SIZE) {
+                int n = i + SIZE + m;
+                double y = info->solution_[n];
+                yB[0] = info->lower_[n];
+                yB[1] = info->upper_[n];
+                int firstLambda = SIZE * SIZE + 2 * SIZE + 4 * i + 4 * m;
+                double xyLambda = 0.0;
+                for (int j = 0; j < 4; j++) {
+                    int iX = j >> 1;
+                    int iY = j & 1;
+                    xyLambda += xB[iX] * yB[iY] * info->solution_[firstLambda+j];
+                }
+                sum += xyLambda * b[i/SIZE];
+                double xyTrue = x * y;
+                sum2 += xyTrue * b[i/SIZE];
+            }
+            if (sum > bMax*x + 1.0e-5 || sum < bMin*x - 1.0e-5) {
+                //if (sum<bMax*x+1.0e-5&&sum>bMin*x-1.0e-5) {
+                printf("bmin*x %g b*w %g bmax*x %g (true) %g\n", bMin*x, sum, bMax*x, sum2);
+                printf("m %d lb %g value %g up %g\n",
+                       m, xB[0], x, xB[1]);
+                sum = 0.0;
+                for (int i = 0; i < SIZE*SIZE; i += SIZE) {
+                    int n = i + SIZE + m;
+                    double y = info->solution_[n];
+                    yB[0] = info->lower_[n];
+                    yB[1] = info->upper_[n];
+                    printf("n %d lb %g value %g up %g\n",
+                           n, yB[0], y, yB[1]);
+                    int firstLambda = SIZE * SIZE + 2 * SIZE + 4 * i + m * 4;
+                    double xyLambda = 0.0;
+                    for (int j = 0; j < 4; j++) {
+                        int iX = j >> 1;
+                        int iY = j & 1;
+                        xyLambda += xB[iX] * yB[iY] * info->solution_[firstLambda+j];
+                        printf("j %d l %d new xylambda %g ", j, firstLambda + j, xyLambda);
+                    }
+                    sum += xyLambda * b[i/SIZE];
+                    printf(" - sum now %g\n", sum);
+                }
+            }
+            if (sum2 > bMax*x + 1.0e-5 || sum2 < bMin*x - 1.0e-5) {
+                printf("bmin*x %g b*x*y %g bmax*x %g (estimate) %g\n", bMin*x, sum2, bMax*x, sum);
+                printf("m %d lb %g value %g up %g\n",
+                       m, xB[0], x, xB[1]);
+                sum2 = 0.0;
+                for (int i = 0; i < SIZE*SIZE; i += SIZE) {
+                    int n = i + SIZE + m;
+                    double y = info->solution_[n];
+                    yB[0] = info->lower_[n];
+                    yB[1] = info->upper_[n];
+                    printf("n %d lb %g value %g up %g\n",
+                           n, yB[0], y, yB[1]);
+                    double xyTrue = x * y;
+                    sum2 += xyTrue * b[i/SIZE];
+                    printf("xyTrue %g - sum now %g\n", xyTrue, sum2);
+                }
+            }
+        }
+    }
+    // If pseudo shadow prices then see what would happen
+    //double pseudoEstimate = 0.0;
+    if (info->defaultDual_ >= 0.0) {
+        // If we move to xy then we move by coefficient * (xyTrue-xyLambda) on row xyRow_
+        double move = xyTrue - xyLambda;
+        assert (xyRow_ >= 0);
+        if (boundType_ == 0) {
+            move *= coefficient_;
+            move *= info->pi_[xyRow_];
+            move = CoinMax(move, 0.0);
+        } else if (boundType_ == 1) {
+            // if OK then say satisfied
+        } else if (boundType_ == 2) {
+        } else {
+            // == row so move x and y not xy
+        }
+    }
+    if ((branchingStrategy_&16) != 0) {
+        // always treat as satisfied!!
+        xSatisfied = true;
+        ySatisfied = true;
+        xyTrue = xyLambda;
+    }
+    if ( !xSatisfied) {
+        if (!ySatisfied) {
+            if ((branchingStrategy_&3) == 0) {
+                // If pseudo shadow prices then see what would happen
+                if (info->defaultDual_ >= 0.0) {
+                    // need coding here
+                    if (fabs(x - xNew) > fabs(y - yNew)) {
+                        chosen_ = 0;
+                        xyBranchValue_ = x;
+                    } else {
+                        chosen_ = 1;
+                        xyBranchValue_ = y;
+                    }
+                } else {
+                    if (fabs(x - xNew) > fabs(y - yNew)) {
+                        chosen_ = 0;
+                        xyBranchValue_ = x;
+                    } else {
+                        chosen_ = 1;
+                        xyBranchValue_ = y;
+                    }
+                }
+            } else if ((branchingStrategy_&3) == 1) {
+                chosen_ = 0;
+                xyBranchValue_ = x;
+            } else {
+                chosen_ = 1;
+                xyBranchValue_ = y;
+            }
+        } else {
+            // y satisfied
+            chosen_ = 0;
+            xyBranchValue_ = x;
+        }
+    } else {
+        // x satisfied
+        if (!ySatisfied) {
+            chosen_ = 1;
+            xyBranchValue_ = y;
+        } else {
+            /*
+            3 - both are satisfied but xy is not
+            3a one has bounds within satisfied_ - other does not
+            (or neither have but branching strategy tells us what to do)
+            3b neither do - and branching strategy does not tell us
+            3c both do - treat as feasible knowing another copy of object will fix
+              4 - both are satisfied and xy is satisfied - as 3c
+            */
+            if (fabs(xyLambda - xyTrue) < xySatisfied_ || (xB[0] == xB[1] && yB[0] == yB[1])) {
+                // satisfied
+#ifdef JJF_ZERO
+                printf("all satisfied true %g lambda %g\n",
+                       xyTrue, xyLambda);
+                printf("x %d (%g,%g,%g) y %d (%g,%g,%g)\n",
+                       xColumn_, xB[0], x, xB[1],
+                       yColumn_, yB[0], y, yB[1]);
+#endif
+            } else {
+                // May be infeasible - check
+                bool feasible = true;
+                if (xB[0] == xB[1] && yB[0] == yB[1]) {
+                    double lambda[4];
+                    computeLambdas(info->solver_, lambda);
+                    for (int j = 0; j < 4; j++) {
+                        int iColumn = firstLambda_ + j;
+                        if (info->lower_[iColumn] > lambda[j] + 1.0e-5 ||
+                                info->upper_[iColumn] < lambda[j] - 1.0e-5)
+                            feasible = false;
+                    }
+                }
+                if (testCoarse && (branchingStrategy_&8) != 0 && xB[1] - xB[0] < 1.0001*xSatisfied_ &&
+                        yB[1] - yB[0] < 1.0001*ySatisfied_)
+                    feasible = true;
+                if (feasible) {
+                    if (xB[1] - xB[0] >= xSatisfied_ && xMeshSize_) {
+                        if (yB[1] - yB[0] >= ySatisfied_ && yMeshSize_) {
+                            if ((branchingStrategy_&3) == 0) {
+                                // If pseudo shadow prices then see what would happen
+                                if (info->defaultDual_ >= 0.0) {
+                                    // need coding here
+                                    if (xB[1] - xB[0] > yB[1] - yB[0]) {
+                                        chosen_ = 0;
+                                        xyBranchValue_ = 0.5 * (xB[0] + xB[1]);
+                                    } else {
+                                        chosen_ = 1;
+                                        xyBranchValue_ = 0.5 * (yB[0] + yB[1]);
+                                    }
+                                } else {
+                                    if (xB[1] - xB[0] > yB[1] - yB[0]) {
+                                        chosen_ = 0;
+                                        xyBranchValue_ = 0.5 * (xB[0] + xB[1]);
+                                    } else {
+                                        chosen_ = 1;
+                                        xyBranchValue_ = 0.5 * (yB[0] + yB[1]);
+                                    }
+                                }
+                            } else if ((branchingStrategy_&3) == 1) {
+                                chosen_ = 0;
+                                xyBranchValue_ = 0.5 * (xB[0] + xB[1]);
+                            } else {
+                                chosen_ = 1;
+                                xyBranchValue_ = 0.5 * (yB[0] + yB[1]);
+                            }
+                        } else {
+                            // y satisfied
+                            chosen_ = 0;
+                            xyBranchValue_ = 0.5 * (xB[0] + xB[1]);
+                        }
+                    } else if (yB[1] - yB[0] >= ySatisfied_ && yMeshSize_) {
+                        chosen_ = 1;
+                        xyBranchValue_ = 0.5 * (yB[0] + yB[1]);
+                    } else {
+                        // treat as satisfied unless no coefficient tightening
+                        if ((branchingStrategy_&4) != 0) {
+                            chosen_ = 0; // fix up in branch
+                            xyBranchValue_ = x;
+                        }
+                    }
+                } else {
+                    // node not feasible!!!
+                    chosen_ = 0;
+                    infeasibility_ = COIN_DBL_MAX;
+                    otherInfeasibility_ = COIN_DBL_MAX;
+                    whichWay = whichWay_;
+                    return infeasibility_;
+                }
+            }
+        }
+    }
+    if (chosen_ == -1) {
+        infeasibility_ = 0.0;
+    } else if (chosen_ == 0) {
+        infeasibility_ = CoinMax(fabs(xyBranchValue_ - x), 1.0e-12);
+        //assert (xyBranchValue_>=info->lower_[xColumn_]&&xyBranchValue_<=info->upper_[xColumn_]);
+    } else {
+        infeasibility_ = CoinMax(fabs(xyBranchValue_ - y), 1.0e-12);
+        //assert (xyBranchValue_>=info->lower_[yColumn_]&&xyBranchValue_<=info->upper_[yColumn_]);
+    }
+    if (info->defaultDual_ < 0.0) {
+        // not using pseudo shadow prices
+        otherInfeasibility_ = 1.0 - infeasibility_;
+    } else {
+        abort();
+    }
+    if (infeasibility_) {
+        bool fixed = true;
+        for (int j = 0; j < 4; j++) {
+            int iColumn = firstLambda_ + j;
+            //if (info->lower_[iColumn]) printf("lower of %g on %d\n",info->lower_[iColumn],iColumn);
+            if (info->lower_[iColumn] < info->upper_[iColumn])
+                fixed = false;
+        }
+        if (fixed) {
+            //printf("must be tolerance problem - xy true %g lambda %g\n",xyTrue,xyLambda);
+            chosen_ = -1;
+            infeasibility_ = 0.0;
+        }
+    }
+    whichWay = whichWay_;
+    //if (infeasibility_&&priority_==10)
+    //printf("x %d %g %g %g, y %d %g %g %g\n",xColumn_,xB[0],x,xB[1],yColumn_,yB[0],y,yB[1]);
+    return infeasibility_;
+}
+// Sets infeasibility and other when pseudo shadow prices
+void
+OsiBiLinear::getPseudoShadow(const OsiBranchingInformation * info)
+{
+    // order is LxLy, LxUy, UxLy and UxUy
+    double xB[2];
+    double yB[2];
+    xB[0] = info->lower_[xColumn_];
+    xB[1] = info->upper_[xColumn_];
+    yB[0] = info->lower_[yColumn_];
+    yB[1] = info->upper_[yColumn_];
+    double x = info->solution_[xColumn_];
+    x = CoinMax(x, xB[0]);
+    x = CoinMin(x, xB[1]);
+    double y = info->solution_[yColumn_];
+    y = CoinMax(y, yB[0]);
+    y = CoinMin(y, yB[1]);
+    int j;
+    double xyTrue = x * y;
+    double xyLambda = 0.0;
+    if ((branchingStrategy_&4) == 0) {
+        for (j = 0; j < 4; j++) {
+            int iX = j >> 1;
+            int iY = j & 1;
+            xyLambda += xB[iX] * yB[iY] * info->solution_[firstLambda_+j];
+        }
+    } else {
+        if (xyRow_ >= 0) {
+            const double * element = info->elementByColumn_;
+            const int * row = info->row_;
+            const CoinBigIndex * columnStart = info->columnStart_;
+            const int * columnLength = info->columnLength_;
+            for (j = 0; j < 4; j++) {
+                int iColumn = firstLambda_ + j;
+                int iStart = columnStart[iColumn];
+                int iEnd = iStart + columnLength[iColumn];
+                int k = iStart;
+                double sol = info->solution_[iColumn];
+                for (; k < iEnd; k++) {
+                    if (xyRow_ == row[k])
+                        xyLambda += element[k] * sol;
+                }
+            }
+        } else {
+            // objective
+            const double * objective = info->objective_;
+            for (j = 0; j < 4; j++) {
+                int iColumn = firstLambda_ + j;
+                double sol = info->solution_[iColumn];
+                xyLambda += objective[iColumn] * sol;
+            }
+        }
+        xyLambda /= coefficient_;
+    }
+    assert (info->defaultDual_ >= 0.0);
+    // If we move to xy then we move by coefficient * (xyTrue-xyLambda) on row xyRow_
+    double movement = xyTrue - xyLambda;
+    infeasibility_ = 0.0;
+    const double * pi = info->pi_;
+    const double * activity = info->rowActivity_;
+    const double * lower = info->rowLower_;
+    const double * upper = info->rowUpper_;
+    double tolerance = info->primalTolerance_;
+    double direction = info->direction_;
+    bool infeasible = false;
+    if (xyRow_ >= 0) {
+        assert (!boundType_);
+        if (lower[xyRow_] < -1.0e20)
+            assert (pi[xyRow_] <= 1.0e-3);
+        if (upper[xyRow_] > 1.0e20)
+            assert (pi[xyRow_] >= -1.0e-3);
+        double valueP = pi[xyRow_] * direction;
+        // if move makes infeasible then make at least default
+        double newValue = activity[xyRow_] + movement * coefficient_;
+        if (newValue > upper[xyRow_] + tolerance || newValue < lower[xyRow_] - tolerance) {
+            infeasibility_ += fabs(movement * coefficient_) * CoinMax(fabs(valueP), info->defaultDual_);
+            infeasible = true;
+        }
+    } else {
+        // objective
+        assert (movement > -1.0e-7);
+        infeasibility_ += movement;
+    }
+    for (int i = 0; i < numberExtraRows_; i++) {
+        int iRow = extraRow_[i];
+        if (lower[iRow] < -1.0e20)
+            assert (pi[iRow] <= 1.0e-3);
+        if (upper[iRow] > 1.0e20)
+            assert (pi[iRow] >= -1.0e-3);
+        double valueP = pi[iRow] * direction;
+        // if move makes infeasible then make at least default
+        double newValue = activity[iRow] + movement * multiplier_[i];
+        if (newValue > upper[iRow] + tolerance || newValue < lower[iRow] - tolerance) {
+            infeasibility_ += fabs(movement * multiplier_[i]) * CoinMax(fabs(valueP), info->defaultDual_);
+            infeasible = true;
+        }
+    }
+    if (infeasibility_ < info->integerTolerance_) {
+        if (!infeasible)
+            infeasibility_ = 0.0;
+        else
+            infeasibility_ = info->integerTolerance_;
+    }
+    otherInfeasibility_ = CoinMax(1.0e-12, infeasibility_ * 10.0);
+}
+// Gets sum of movements to correct value
+double
+OsiBiLinear::getMovement(const OsiBranchingInformation * info)
+{
+    // order is LxLy, LxUy, UxLy and UxUy
+    double xB[2];
+    double yB[2];
+    xB[0] = info->lower_[xColumn_];
+    xB[1] = info->upper_[xColumn_];
+    yB[0] = info->lower_[yColumn_];
+    yB[1] = info->upper_[yColumn_];
+    double x = info->solution_[xColumn_];
+    x = CoinMax(x, xB[0]);
+    x = CoinMin(x, xB[1]);
+    double y = info->solution_[yColumn_];
+    y = CoinMax(y, yB[0]);
+    y = CoinMin(y, yB[1]);
+    int j;
+    double xyTrue = x * y;
+    double xyLambda = 0.0;
+    if ((branchingStrategy_&4) == 0) {
+        for (j = 0; j < 4; j++) {
+            int iX = j >> 1;
+            int iY = j & 1;
+            xyLambda += xB[iX] * yB[iY] * info->solution_[firstLambda_+j];
+        }
+    } else {
+        if (xyRow_ >= 0) {
+            const double * element = info->elementByColumn_;
+            const int * row = info->row_;
+            const CoinBigIndex * columnStart = info->columnStart_;
+            const int * columnLength = info->columnLength_;
+            for (j = 0; j < 4; j++) {
+                int iColumn = firstLambda_ + j;
+                int iStart = columnStart[iColumn];
+                int iEnd = iStart + columnLength[iColumn];
+                int k = iStart;
+                double sol = info->solution_[iColumn];
+                for (; k < iEnd; k++) {
+                    if (xyRow_ == row[k])
+                        xyLambda += element[k] * sol;
+                }
+            }
+        } else {
+            // objective
+            const double * objective = info->objective_;
+            for (j = 0; j < 4; j++) {
+                int iColumn = firstLambda_ + j;
+                double sol = info->solution_[iColumn];
+                xyLambda += objective[iColumn] * sol;
+            }
+        }
+        xyLambda /= coefficient_;
+    }
+    // If we move to xy then we move by coefficient * (xyTrue-xyLambda) on row xyRow_
+    double movement = xyTrue - xyLambda;
+    double mesh = CoinMax(xMeshSize_, yMeshSize_);
+    if (fabs(movement) < xySatisfied_ && (xB[1] - xB[0] < mesh || yB[1] - yB[0] < mesh))
+        return 0.0; // say feasible
+    const double * activity = info->rowActivity_;
+    const double * lower = info->rowLower_;
+    const double * upper = info->rowUpper_;
+    double tolerance = info->primalTolerance_;
+    double  infeasibility = 0.0;
+    if (xyRow_ >= 0) {
+        assert (!boundType_);
+        // if move makes infeasible
+        double newValue = activity[xyRow_] + movement * coefficient_;
+        if (newValue > upper[xyRow_] + tolerance)
+            infeasibility += newValue - upper[xyRow_];
+        else if (newValue < lower[xyRow_] - tolerance)
+            infeasibility += lower[xyRow_] - newValue;
+    } else {
+        // objective
+        assert (movement > -1.0e-7);
+        infeasibility += movement;
+    }
+    for (int i = 0; i < numberExtraRows_; i++) {
+        int iRow = extraRow_[i];
+        // if move makes infeasible
+        double newValue = activity[iRow] + movement * multiplier_[i];
+        if (newValue > upper[iRow] + tolerance)
+            infeasibility += newValue - upper[iRow];
+        else if (newValue < lower[iRow] - tolerance)
+            infeasibility += lower[iRow] - newValue;
+    }
+    return infeasibility;
+}
+// This looks at solution and sets bounds to contain solution
+double
+OsiBiLinear::feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const
+{
+    // If another object has finer mesh ignore this
+    if ((branchingStrategy_&8) != 0)
+        return 0.0;
+    // order is LxLy, LxUy, UxLy and UxUy
+    double xB[2];
+    double yB[2];
+    xB[0] = info->lower_[xColumn_];
+    xB[1] = info->upper_[xColumn_];
+    yB[0] = info->lower_[yColumn_];
+    yB[1] = info->upper_[yColumn_];
+    double x = info->solution_[xColumn_];
+    double y = info->solution_[yColumn_];
+    int j;
+#ifndef NDEBUG
+    double xLambda = 0.0;
+    double yLambda = 0.0;
+    if ((branchingStrategy_&4) == 0) {
+        for (j = 0; j < 4; j++) {
+            int iX = j >> 1;
+            int iY = j & 1;
+            xLambda += xB[iX] * info->solution_[firstLambda_+j];
+            if (yRow_ >= 0)
+                yLambda += yB[iY] * info->solution_[firstLambda_+j];
+        }
+    } else {
+        const double * element = info->elementByColumn_;
+        const int * row = info->row_;
+        const CoinBigIndex * columnStart = info->columnStart_;
+        const int * columnLength = info->columnLength_;
+        for (j = 0; j < 4; j++) {
+            int iColumn = firstLambda_ + j;
+            int iStart = columnStart[iColumn];
+            int iEnd = iStart + columnLength[iColumn];
+            int k = iStart;
+            double sol = info->solution_[iColumn];
+            for (; k < iEnd; k++) {
+                if (xRow_ == row[k])
+                    xLambda += element[k] * sol;
+                if (yRow_ == row[k])
+                    yLambda += element[k] * sol;
+            }
+        }
+    }
+    if (yRow_ < 0)
+        yLambda = xLambda;
+#ifdef JJF_ZERO
+    if (fabs(x - xLambda) > 1.0e-4 ||
+            fabs(y - yLambda) > 1.0e-4)
+        printf("feasibleregion x %d given %g lambda %g y %d given %g lambda %g\n",
+               xColumn_, x, xLambda,
+               yColumn_, y, yLambda);
+#endif
+#endif
+    double infeasibility = 0.0;
+    double distance;
+    double steps;
+    double xNew = x;
+    if (xMeshSize_) {
+        distance = x - xB[0];
+        if (x < 0.5*(xB[0] + xB[1])) {
+            distance = x - xB[0];
+            steps = floor ((distance + 0.5 * xMeshSize_) / xMeshSize_);
+            xNew = xB[0] + steps * xMeshSize_;
+            assert (xNew <= xB[1] + xSatisfied_);
+        } else {
+            distance = xB[1] - x;
+            steps = floor ((distance + 0.5 * xMeshSize_) / xMeshSize_);
+            xNew = xB[1] - steps * xMeshSize_;
+            assert (xNew >= xB[0] - xSatisfied_);
+        }
+        if (xMeshSize_ < 1.0 && fabs(xNew - x) <= xSatisfied_) {
+            double lo = CoinMax(xB[0], x - 0.5 * xSatisfied_);
+            double up = CoinMin(xB[1], x + 0.5 * xSatisfied_);
+            solver->setColLower(xColumn_, lo);
+            solver->setColUpper(xColumn_, up);
+        } else {
+            infeasibility +=  fabs(xNew - x);
+            solver->setColLower(xColumn_, xNew);
+            solver->setColUpper(xColumn_, xNew);
+        }
+    }
+    double yNew = y;
+    if (yMeshSize_) {
+        distance = y - yB[0];
+        if (y < 0.5*(yB[0] + yB[1])) {
+            distance = y - yB[0];
+            steps = floor ((distance + 0.5 * yMeshSize_) / yMeshSize_);
+            yNew = yB[0] + steps * yMeshSize_;
+            assert (yNew <= yB[1] + ySatisfied_);
+        } else {
+            distance = yB[1] - y;
+            steps = floor ((distance + 0.5 * yMeshSize_) / yMeshSize_);
+            yNew = yB[1] - steps * yMeshSize_;
+            assert (yNew >= yB[0] - ySatisfied_);
+        }
+        if (yMeshSize_ < 1.0 && fabs(yNew - y) <= ySatisfied_) {
+            double lo = CoinMax(yB[0], y - 0.5 * ySatisfied_);
+            double up = CoinMin(yB[1], y + 0.5 * ySatisfied_);
+            solver->setColLower(yColumn_, lo);
+            solver->setColUpper(yColumn_, up);
+        } else {
+            infeasibility +=  fabs(yNew - y);
+            solver->setColLower(yColumn_, yNew);
+            solver->setColUpper(yColumn_, yNew);
+        }
+    }
+    if (0) {
+        // temp
+        solver->setColLower(xColumn_, x);
+        solver->setColUpper(xColumn_, x);
+        solver->setColLower(yColumn_, y);
+        solver->setColUpper(yColumn_, y);
+    }
+    if ((branchingStrategy_&4)) {
+        // fake to make correct
+        double lambda[4];
+        computeLambdas(solver, lambda);
+        for (int j = 0; j < 4; j++) {
+            int iColumn = firstLambda_ + j;
+            double value = lambda[j];
+            solver->setColLower(iColumn, value);
+            solver->setColUpper(iColumn, value);
+        }
+    }
+    double xyTrue = xNew * yNew;
+    double xyLambda = 0.0;
+    for (j = 0; j < 4; j++) {
+        int iX = j >> 1;
+        int iY = j & 1;
+        xyLambda += xB[iX] * yB[iY] * info->solution_[firstLambda_+j];
+    }
+    infeasibility += fabs(xyTrue - xyLambda);
+    return infeasibility;
+}
+// Returns true value of single xyRow coefficient
+double
+OsiBiLinear::xyCoefficient(const double * solution) const
+{
+    // If another object has finer mesh ignore this
+    if ((branchingStrategy_&8) != 0)
+        return 0.0;
+    double x = solution[xColumn_];
+    double y = solution[yColumn_];
+    //printf("x (%d,%g) y (%d,%g) x*y*coefficient %g\n",
+    // xColumn_,x,yColumn_,y,x*y*coefficient_);
+    return x*y*coefficient_;
+}
+
+// Redoes data when sequence numbers change
+void
+OsiBiLinear::resetSequenceEtc(int numberColumns, const int * originalColumns)
+{
+    int i;
+#ifdef JJF_ZERO
+    for (i = 0; i < numberColumns; i++) {
+        if (originalColumns[i] == firstLambda_)
+            break;
+    }
+#else
+    i = originalColumns[firstLambda_];
+#endif
+    if (i >= 0 && i < numberColumns) {
+        firstLambda_ = i;
+        for (int j = 0; j < 4; j++) {
+            assert (originalColumns[j+i] - firstLambda_ == j);
+        }
+    } else {
+        printf("lost set\n");
+        abort();
+    }
+    // rows will be out anyway
+    abort();
+}
+
+// Creates a branching object
+OsiBranchingObject *
+OsiBiLinear::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int way) const
+{
+    // create object
+    OsiBranchingObject * branch;
+    assert (chosen_ == 0 || chosen_ == 1);
+    //if (chosen_==0)
+    //assert (xyBranchValue_>=info->lower_[xColumn_]&&xyBranchValue_<=info->upper_[xColumn_]);
+    //else
+    //assert (xyBranchValue_>=info->lower_[yColumn_]&&xyBranchValue_<=info->upper_[yColumn_]);
+    branch = new OsiBiLinearBranchingObject(solver, this, way, xyBranchValue_, chosen_);
+    return branch;
+}
+// Does work of branching
+void
+OsiBiLinear::newBounds(OsiSolverInterface * solver, int way, short xOrY, double separator) const
+{
+    int iColumn;
+    double mesh;
+    double satisfied;
+    if (xOrY == 0) {
+        iColumn = xColumn_;
+        mesh = xMeshSize_;
+        satisfied = xSatisfied_;
+    } else {
+        iColumn = yColumn_;
+        mesh = yMeshSize_;
+        satisfied = ySatisfied_;
+    }
+    const double * columnLower = solver->getColLower();
+    const double * columnUpper = solver->getColUpper();
+    double lower = columnLower[iColumn];
+    double distance;
+    double steps;
+    double zNew = separator;
+    distance = separator - lower;
+    assert (mesh);
+    steps = floor ((distance + 0.5 * mesh) / mesh);
+    if (mesh < 1.0)
+        zNew = lower + steps * mesh;
+    if (zNew > columnUpper[iColumn] - satisfied)
+        zNew = 0.5 * (columnUpper[iColumn] - lower);
+    double oldUpper = columnUpper[iColumn] ;
+    double oldLower = columnLower[iColumn] ;
+#ifndef NDEBUG
+    int nullChange = 0;
+#endif
+    if (way < 0) {
+        if (zNew > separator && mesh < 1.0)
+            zNew -= mesh;
+        double oldUpper = columnUpper[iColumn] ;
+        if (zNew + satisfied >= oldUpper)
+            zNew = 0.5 * (oldUpper + oldLower);
+        if (mesh == 1.0)
+            zNew = floor(separator);
+#ifndef NDEBUG
+        if (oldUpper < zNew + 1.0e-8)
+            nullChange = -1;
+#endif
+        solver->setColUpper(iColumn, zNew);
+    } else {
+        if (zNew < separator && mesh < 1.0)
+            zNew += mesh;
+        if (zNew - satisfied <= oldLower)
+            zNew = 0.5 * (oldUpper + oldLower);
+        if (mesh == 1.0)
+            zNew = ceil(separator);
+#ifndef NDEBUG
+        if (oldLower > zNew - 1.0e-8)
+            nullChange = 1;
+#endif
+        solver->setColLower(iColumn, zNew);
+    }
+    if ((branchingStrategy_&4) != 0
+            && columnLower[xColumn_] == columnUpper[xColumn_]
+            && columnLower[yColumn_] == columnUpper[yColumn_]) {
+        // fake to make correct
+        double lambda[4];
+        computeLambdas(solver, lambda);
+        for (int j = 0; j < 4; j++) {
+            int iColumn = firstLambda_ + j;
+            double value = lambda[j];
+#ifndef NDEBUG
+            if (fabs(value - columnLower[iColumn]) > 1.0e-5 ||
+                    fabs(value - columnUpper[iColumn]) > 1.0e-5)
+                nullChange = 0;
+#endif
+            solver->setColLower(iColumn, value);
+            solver->setColUpper(iColumn, value);
+        }
+    }
+#ifndef NDEBUG
+    if (nullChange)
+        printf("null change on column%s %d - bounds %g,%g\n", nullChange > 0 ? "Lower" : "Upper",
+               iColumn, oldLower, oldUpper);
+#endif
+#ifdef JJF_ZERO
+    // always free up lambda
+    for (int i = firstLambda_; i < firstLambda_ + 4; i++) {
+        solver->setColLower(i, 0.0);
+        solver->setColUpper(i, 2.0);
+    }
+#endif
+    double xB[3];
+    xB[0] = columnLower[xColumn_];
+    xB[1] = columnUpper[xColumn_];
+    double yB[3];
+    yB[0] = columnLower[yColumn_];
+    yB[1] = columnUpper[yColumn_];
+    if (false && (branchingStrategy_&4) != 0 && yRow_ >= 0 &&
+            xMeshSize_ == 1.0 && yMeshSize_ == 1.0) {
+        if ((xB[1] - xB[0])*(yB[1] - yB[0]) < 40) {
+            // try looking at all solutions
+            double lower[4];
+            double upper[4];
+            double lambda[4];
+            int i;
+            double lowerLambda[4];
+            double upperLambda[4];
+            for (i = 0; i < 4; i++) {
+                lower[i] = CoinMax(0.0, columnLower[firstLambda_+i]);
+                upper[i] = CoinMin(1.0, columnUpper[firstLambda_+i]);
+                lowerLambda[i] = 1.0;
+                upperLambda[i] = 0.0;
+            }
+            // get coefficients
+            double xybar[4];
+            getCoefficients(solver, xB, yB, xybar);
+            double x, y;
+            for (x = xB[0]; x <= xB[1]; x++) {
+                xB[2] = x;
+                for (y = yB[0]; y <= yB[1]; y++) {
+                    yB[2] = y;
+                    computeLambdas(xB, yB, xybar, lambda);
+                    for (i = 0; i < 4; i++) {
+                        lowerLambda[i] = CoinMin(lowerLambda[i], lambda[i]);
+                        upperLambda[i] = CoinMax(upperLambda[i], lambda[i]);
+                    }
+                }
+            }
+            double change = 0.0;;
+            for (i = 0; i < 4; i++) {
+                if (lowerLambda[i] > lower[i] + 1.0e-12) {
+                    solver->setColLower(firstLambda_ + i, lowerLambda[i]);
+                    change += lowerLambda[i] - lower[i];
+                }
+                if (upperLambda[i] < upper[i] - 1.0e-12) {
+                    solver->setColUpper(firstLambda_ + i, upperLambda[i]);
+                    change -= upperLambda[i] - upper[i];
+                }
+            }
+            if (change > 1.0e-5)
+                printf("change of %g\n", change);
+        }
+    }
+    if (boundType_) {
+        assert (!xMeshSize_ || !yMeshSize_);
+        if (xMeshSize_) {
+            // can tighten bounds on y
+            if ((boundType_&1) != 0) {
+                if (xB[0]*yB[1] > coefficient_) {
+                    // tighten upper bound on y
+                    solver->setColUpper(yColumn_, coefficient_ / xB[0]);
+                }
+            }
+            if ((boundType_&2) != 0) {
+                if (xB[1]*yB[0] < coefficient_) {
+                    // tighten lower bound on y
+                    solver->setColLower(yColumn_, coefficient_ / xB[1]);
+                }
+            }
+        } else {
+            // can tighten bounds on x
+            if ((boundType_&1) != 0) {
+                if (yB[0]*xB[1] > coefficient_) {
+                    // tighten upper bound on x
+                    solver->setColUpper(xColumn_, coefficient_ / yB[0]);
+                }
+            }
+            if ((boundType_&2) != 0) {
+                if (yB[1]*xB[0] < coefficient_) {
+                    // tighten lower bound on x
+                    solver->setColLower(xColumn_, coefficient_ / yB[1]);
+                }
+            }
+        }
+    }
+}
+// Compute lambdas if coefficients not changing
+void
+OsiBiLinear::computeLambdas(const OsiSolverInterface * solver, double lambda[4]) const
+{
+    // fix so correct
+    double xB[3], yB[3];
+    double xybar[4];
+    getCoefficients(solver, xB, yB, xybar);
+    double x, y;
+    x = solver->getColLower()[xColumn_];
+    assert(x == solver->getColUpper()[xColumn_]);
+    xB[2] = x;
+    y = solver->getColLower()[yColumn_];
+    assert(y == solver->getColUpper()[yColumn_]);
+    yB[2] = y;
+    computeLambdas(xB, yB, xybar, lambda);
+    assert (xyRow_ >= 0);
+}
+// Get LU coefficients from matrix
+void
+OsiBiLinear::getCoefficients(const OsiSolverInterface * solver, double xB[2], double yB[2],
+                             double xybar[4]) const
+{
+    const CoinPackedMatrix * matrix = solver->getMatrixByCol();
+    const double * element = matrix->getElements();
+    const double * objective = solver->getObjCoefficients();
+    const int * row = matrix->getIndices();
+    const CoinBigIndex * columnStart = matrix->getVectorStarts();
+    const int * columnLength = matrix->getVectorLengths();
+    // order is LxLy, LxUy, UxLy and UxUy
+    int j;
+    double multiplier = (boundType_ == 0) ? 1.0 / coefficient_ : 1.0;
+    if (yRow_ >= 0) {
+        for (j = 0; j < 4; j++) {
+            int iColumn = firstLambda_ + j;
+            int iStart = columnStart[iColumn];
+            int iEnd = iStart + columnLength[iColumn];
+            int k = iStart;
+            double x = 0.0;
+            double y = 0.0;
+            xybar[j] = 0.0;
+            for (; k < iEnd; k++) {
+                if (xRow_ == row[k])
+                    x = element[k];
+                if (yRow_ == row[k])
+                    y = element[k];
+                if (xyRow_ == row[k])
+                    xybar[j] = element[k] * multiplier;
+            }
+            if (xyRow_ < 0)
+                xybar[j] = objective[iColumn] * multiplier;
+            if (j == 0)
+                xB[0] = x;
+            else if (j == 1)
+                yB[1] = y;
+            else if (j == 2)
+                yB[0] = y;
+            else if (j == 3)
+                xB[1] = x;
+            assert (fabs(xybar[j] - x*y) < 1.0e-4);
+        }
+    } else {
+        // x==y
+        for (j = 0; j < 4; j++) {
+            int iColumn = firstLambda_ + j;
+            int iStart = columnStart[iColumn];
+            int iEnd = iStart + columnLength[iColumn];
+            int k = iStart;
+            double x = 0.0;
+            xybar[j] = 0.0;
+            for (; k < iEnd; k++) {
+                if (xRow_ == row[k])
+                    x = element[k];
+                if (xyRow_ == row[k])
+                    xybar[j] = element[k] * multiplier;
+            }
+            if (xyRow_ < 0)
+                xybar[j] = objective[iColumn] * multiplier;
+            if (j == 0) {
+                xB[0] = x;
+                yB[0] = x;
+            } else if (j == 2) {
+                xB[1] = x;
+                yB[1] = x;
+            }
+        }
+        assert (fabs(xybar[0] - xB[0]*yB[0]) < 1.0e-4);
+        assert (fabs(xybar[1] - xB[0]*yB[1]) < 1.0e-4);
+        assert (fabs(xybar[2] - xB[1]*yB[0]) < 1.0e-4);
+        assert (fabs(xybar[3] - xB[1]*yB[1]) < 1.0e-4);
+    }
+}
+// Compute lambdas (third entry in each .B is current value)
+double
+OsiBiLinear::computeLambdas(const double xB[3], const double yB[3], const double xybar[4], double lambda[4]) const
+{
+    // fake to make correct
+    double x = xB[2];
+    double y = yB[2];
+    // order is LxLy, LxUy, UxLy and UxUy
+    // l0 + l1 = this
+    double rhs1 = (xB[1] - x) / (xB[1] - xB[0]);
+    // l0 + l2 = this
+    double rhs2 = (yB[1] - y) / (yB[1] - yB[0]);
+    // For xy (taking out l3)
+    double rhs3 = xB[1] * yB[1] - x * y;
+    double a0 = xB[1] * yB[1] - xB[0] * yB[0];
+    double a1 = xB[1] * yB[1] - xB[0] * yB[1];
+    double a2 = xB[1] * yB[1] - xB[1] * yB[0];
+    // divide through to get l0 coefficient
+    rhs3 /= a0;
+    a1 /= a0;
+    a2 /= a0;
+    // subtract out l0
+    double b[2][2];
+    double rhs[2];
+    // first for l1 and l2
+    b[0][0] = 1.0 - a1;
+    b[0][1] = -a2;
+    rhs[0] = rhs1 - rhs3;
+    // second
+    b[1][0] = -a1;
+    b[1][1] = 1.0 - a2;
+    rhs[1] = rhs2 - rhs3;
+    if (fabs(b[0][0]) > fabs(b[0][1])) {
+        double sub = b[1][0] / b[0][0];
+        b[1][1] -= sub * b[0][1];
+        rhs[1] -= sub * rhs[0];
+        assert (fabs(b[1][1]) > 1.0e-12);
+        lambda[2] = rhs[1] / b[1][1];
+        lambda[0] = rhs2 - lambda[2];
+        lambda[1] = rhs1 - lambda[0];
+    } else {
+        double sub = b[1][1] / b[0][1];
+        b[1][0] -= sub * b[0][0];
+        rhs[1] -= sub * rhs[0];
+        assert (fabs(b[1][0]) > 1.0e-12);
+        lambda[1] = rhs[1] / b[1][0];
+        lambda[0] = rhs1 - lambda[1];
+        lambda[2] = rhs2 - lambda[0];
+    }
+    lambda[3] = 1.0 - (lambda[0] + lambda[1] + lambda[2]);
+    double infeasibility = 0.0;
+    double xy = 0.0;
+    for (int j = 0; j < 4; j++) {
+        double value = lambda[j];
+        if (value > 1.0) {
+            infeasibility += value - 1.0;
+            value = 1.0;
+        }
+        if (value < 0.0) {
+            infeasibility -= value;
+            value = 0.0;
+        }
+        lambda[j] = value;
+        xy += xybar[j] * value;
+    }
+    assert (fabs(xy - x*y) < 1.0e-4);
+    return infeasibility;
+}
+// Updates coefficients
+int
+OsiBiLinear::updateCoefficients(const double * lower, const double * upper, double * objective,
+                                CoinPackedMatrix * matrix, CoinWarmStartBasis * basis) const
+{
+    // Return if no updates
+    if ((branchingStrategy_&4) != 0)
+        return 0;
+    int numberUpdated = 0;
+    double * element = matrix->getMutableElements();
+    const int * row = matrix->getIndices();
+    const CoinBigIndex * columnStart = matrix->getVectorStarts();
+    const int * columnLength = matrix->getVectorLengths();
+    // order is LxLy, LxUy, UxLy and UxUy
+    double xB[2];
+    double yB[2];
+    xB[0] = lower[xColumn_];
+    xB[1] = upper[xColumn_];
+    yB[0] = lower[yColumn_];
+    yB[1] = upper[yColumn_];
+    //printf("x %d (%g,%g) y %d (%g,%g)\n",
+    // xColumn_,xB[0],xB[1],
+    // yColumn_,yB[0],yB[1]);
+    CoinWarmStartBasis::Status status[4];
+    int numStruct = basis ? basis->getNumStructural() - firstLambda_ : 0;
+    double coefficient = (boundType_ == 0) ? coefficient_ : 1.0;
+    for (int j = 0; j < 4; j++) {
+        status[j] = (j < numStruct) ? basis->getStructStatus(j + firstLambda_) : CoinWarmStartBasis::atLowerBound;
+        int iX = j >> 1;
+        double x = xB[iX];
+        int iY = j & 1;
+        double y = yB[iY];
+        CoinBigIndex k = columnStart[j+firstLambda_];
+        CoinBigIndex last = k + columnLength[j+firstLambda_];
+        double value;
+        // xy
+        value = coefficient * x * y;
+        if (xyRow_ >= 0) {
+            assert (row[k] == xyRow_);
+#if BI_PRINT > 1
+            printf("j %d xy (%d,%d) coeff from %g to %g\n", j, xColumn_, yColumn_, element[k], value);
+#endif
+            element[k++] = value;
+        } else {
+            // objective
+            objective[j+firstLambda_] = value;
+        }
+        numberUpdated++;
+        // convexity
+        assert (row[k] == convexity_);
+        k++;
+        // x
+        value = x;
+#if BI_PRINT > 1
+        printf("j %d x (%d) coeff from %g to %g\n", j, xColumn_, element[k], value);
+#endif
+        assert (row[k] == xRow_);
+        element[k++] = value;
+        numberUpdated++;
+        if (yRow_ >= 0) {
+            // y
+            value = y;
+#if BI_PRINT > 1
+            printf("j %d y (%d) coeff from %g to %g\n", j, yColumn_, element[k], value);
+#endif
+            assert (row[k] == yRow_);
+            element[k++] = value;
+            numberUpdated++;
+        }
+        // Do extra rows
+        for (int i = 0; i < numberExtraRows_; i++) {
+            int iRow = extraRow_[i];
+            for (; k < last; k++) {
+                if (row[k] == iRow)
+                    break;
+            }
+            assert (k < last);
+            element[k++] = x * y * multiplier_[i];
+        }
+    }
+
+    if (xB[0] == xB[1]) {
+        if (yB[0] == yB[1]) {
+            // only one basic
+            bool first = true;
+            for (int j = 0; j < 4; j++) {
+                if (status[j] == CoinWarmStartBasis::basic) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        basis->setStructStatus(j + firstLambda_, CoinWarmStartBasis::atLowerBound);
+#if BI_PRINT
+                        printf("zapping %d (x=%d,y=%d)\n", j, xColumn_, yColumn_);
+#endif
+                    }
+                }
+            }
+        } else {
+            if (status[0] == CoinWarmStartBasis::basic &&
+                    status[2] == CoinWarmStartBasis::basic) {
+                basis->setStructStatus(2 + firstLambda_, CoinWarmStartBasis::atLowerBound);
+#if BI_PRINT
+                printf("zapping %d (x=%d,y=%d)\n", 2, xColumn_, yColumn_);
+#endif
+            }
+            if (status[1] == CoinWarmStartBasis::basic &&
+                    status[3] == CoinWarmStartBasis::basic) {
+                basis->setStructStatus(3 + firstLambda_, CoinWarmStartBasis::atLowerBound);
+#if BI_PRINT
+                printf("zapping %d (x=%d,y=%d)\n", 3, xColumn_, yColumn_);
+#endif
+            }
+        }
+    } else if (yB[0] == yB[1]) {
+        if (status[0] == CoinWarmStartBasis::basic &&
+                status[1] == CoinWarmStartBasis::basic) {
+            basis->setStructStatus(1 + firstLambda_, CoinWarmStartBasis::atLowerBound);
+#if BI_PRINT
+            printf("zapping %d (x=%d,y=%d)\n", 1, xColumn_, yColumn_);
+#endif
+        }
+        if (status[2] == CoinWarmStartBasis::basic &&
+                status[3] == CoinWarmStartBasis::basic) {
+            basis->setStructStatus(3 + firstLambda_, CoinWarmStartBasis::atLowerBound);
+#if BI_PRINT
+            printf("zapping %d (x=%d,y=%d)\n", 3, xColumn_, yColumn_);
+#endif
+        }
+    }
+    return numberUpdated;
+}
+// This does NOT set mutable stuff
+double
+OsiBiLinear::checkInfeasibility(const OsiBranchingInformation * info) const
+{
+    // If another object has finer mesh ignore this
+    if ((branchingStrategy_&8) != 0)
+        return 0.0;
+    int way;
+    double saveInfeasibility = infeasibility_;
+    short int saveWhichWay = whichWay_;
+    double saveXyBranchValue = xyBranchValue_;
+    short saveChosen = chosen_;
+    double value = infeasibility(info, way);
+    infeasibility_ = saveInfeasibility;
+    whichWay_ = saveWhichWay;
+    xyBranchValue_ = saveXyBranchValue;
+    chosen_ = saveChosen;
+    return value;
+}
+OsiBiLinearBranchingObject::OsiBiLinearBranchingObject()
+        : OsiTwoWayBranchingObject(),
+        chosen_(0)
+{
+}
+
+// Useful constructor
+OsiBiLinearBranchingObject::OsiBiLinearBranchingObject (OsiSolverInterface * solver,
+        const OsiBiLinear * set,
+        int way ,
+        double separator,
+        int chosen)
+        : OsiTwoWayBranchingObject(solver, set, way, separator),
+        chosen_(static_cast<short int>(chosen))
+{
+    assert (chosen_ >= 0 && chosen_ < 2);
+}
+
+// Copy constructor
+OsiBiLinearBranchingObject::OsiBiLinearBranchingObject ( const OsiBiLinearBranchingObject & rhs)
+        : OsiTwoWayBranchingObject(rhs),
+        chosen_(rhs.chosen_)
+{
+}
+
+// Assignment operator
+OsiBiLinearBranchingObject &
+OsiBiLinearBranchingObject::operator=( const OsiBiLinearBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        OsiTwoWayBranchingObject::operator=(rhs);
+        chosen_ = rhs.chosen_;
+    }
+    return *this;
+}
+OsiBranchingObject *
+OsiBiLinearBranchingObject::clone() const
+{
+    return (new OsiBiLinearBranchingObject(*this));
+}
+
+
+// Destructor
+OsiBiLinearBranchingObject::~OsiBiLinearBranchingObject ()
+{
+}
+double
+OsiBiLinearBranchingObject::branch(OsiSolverInterface * solver)
+{
+    const OsiBiLinear * set =
+        dynamic_cast <const OsiBiLinear *>(originalObject_) ;
+    assert (set);
+    int way = (!branchIndex_) ? (2 * firstBranch_ - 1) : -(2 * firstBranch_ - 1);
+    branchIndex_++;
+    set->newBounds(solver, way, chosen_, value_);
+    return 0.0;
+}
+/* Return true if branch should only bound variables
+ */
+bool
+OsiBiLinearBranchingObject::boundBranch() const
+{
+    const OsiBiLinear * set =
+        dynamic_cast <const OsiBiLinear *>(originalObject_) ;
+    assert (set);
+    return (set->branchingStrategy()&4) != 0;
+}
+// Print what would happen
+void
+OsiBiLinearBranchingObject::print(const OsiSolverInterface * /*solver*/)
+{
+    const OsiBiLinear * set =
+        dynamic_cast <const OsiBiLinear *>(originalObject_) ;
+    assert (set);
+    int way = (!branchIndex_) ? (2 * firstBranch_ - 1) : -(2 * firstBranch_ - 1);
+    int iColumn = (chosen_ == 1) ? set->xColumn() : set->yColumn();
+    printf("OsiBiLinear would branch %s on %c variable %d from value %g\n",
+           (way < 0) ? "down" : "up",
+           (chosen_ == 0) ? 'X' : 'Y', iColumn, value_);
+}
+// Default Constructor
+OsiBiLinearEquality::OsiBiLinearEquality ()
+        : OsiBiLinear(),
+        numberPoints_(0)
+{
+}
+
+// Useful constructor
+OsiBiLinearEquality::OsiBiLinearEquality (OsiSolverInterface * solver, int xColumn,
+        int yColumn, int xyRow, double rhs,
+        double xMesh)
+        : OsiBiLinear(),
+        numberPoints_(0)
+{
+    double xB[2];
+    double yB[2];
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    xColumn_ = xColumn;
+    yColumn_ = yColumn;
+    xyRow_ = xyRow;
+    coefficient_ = rhs;
+    xB[0] = lower[xColumn_];
+    xB[1] = upper[xColumn_];
+    yB[0] = lower[yColumn_];
+    yB[1] = upper[yColumn_];
+    if (xB[1]*yB[1] < coefficient_ + 1.0e-12 ||
+            xB[0]*yB[0] > coefficient_ - 1.0e-12) {
+        printf("infeasible row - reformulate\n");
+        abort();
+    }
+    // reduce range of x if possible
+    if (yB[0]*xB[1] > coefficient_ + 1.0e12) {
+        xB[1] = coefficient_ / yB[0];
+        solver->setColUpper(xColumn_, xB[1]);
+    }
+    if (yB[1]*xB[0] < coefficient_ - 1.0e12) {
+        xB[0] = coefficient_ / yB[1];
+        solver->setColLower(xColumn_, xB[0]);
+    }
+    // See how many points
+    numberPoints_ = static_cast<int> ((xB[1] - xB[0] + 0.5 * xMesh) / xMesh);
+    // redo exactly
+    xMeshSize_ = (xB[1] - xB[0]) / static_cast<double> (numberPoints_);
+    numberPoints_++;
+    //#define KEEPXY
+#ifndef KEEPXY
+    // Take out xyRow
+    solver->setRowLower(xyRow_, 0.0);
+    solver->setRowUpper(xyRow_, 0.0);
+#else
+    // make >=
+    solver->setRowLower(xyRow_, coefficient_ - 0.05);
+    solver->setRowUpper(xyRow_, COIN_DBL_MAX);
+#endif
+    double rowLower[3];
+    double rowUpper[3];
+#ifndef KEEPXY
+    double * columnLower = new double [numberPoints_];
+    double * columnUpper = new double [numberPoints_];
+    double * objective = new double [numberPoints_];
+    CoinBigIndex *starts = new CoinBigIndex[numberPoints_+1];
+    int * index = new int[3*numberPoints_];
+    double * element = new double [3*numberPoints_];
+#else
+    double * columnLower = new double [numberPoints_+2];
+    double * columnUpper = new double [numberPoints_+2];
+    double * objective = new double [numberPoints_+2];
+    CoinBigIndex *starts = new CoinBigIndex[numberPoints_+3];
+    int * index = new int[4*numberPoints_+2];
+    double * element = new double [4*numberPoints_+2];
+#endif
+    int i;
+    starts[0] = 0;
+    // rows
+    int numberRows = solver->getNumRows();
+    // convexity
+    rowLower[0] = 1.0;
+    rowUpper[0] = 1.0;
+    convexity_ = numberRows;
+    starts[1] = 0;
+    // x
+    rowLower[1] = 0.0;
+    rowUpper[1] = 0.0;
+    index[0] = xColumn_;
+    element[0] = -1.0;
+    xRow_ = numberRows + 1;
+    starts[2] = 1;
+    rowLower[2] = 0.0;
+    rowUpper[2] = 0.0;
+    index[1] = yColumn;
+    element[1] = -1.0;
+    yRow_ = numberRows + 2;
+    starts[3] = 2;
+    solver->addRows(3, starts, index, element, rowLower, rowUpper);
+    int n = 0;
+    firstLambda_ = solver->getNumCols();
+    double x = xB[0];
+    assert(xColumn_ != yColumn_);
+    for (i = 0; i < numberPoints_; i++) {
+        double y = coefficient_ / x;
+        columnLower[i] = 0.0;
+        columnUpper[i] = 2.0;
+        objective[i] = 0.0;
+        double value;
+#ifdef KEEPXY
+        // xy
+        value = coefficient_;
+        element[n] = value;
+        index[n++] = xyRow_;
+#endif
+        // convexity
+        value = 1.0;
+        element[n] = value;
+        index[n++] = 0 + numberRows;
+        // x
+        value = x;
+        if (fabs(value) < 1.0e-19)
+            value = 1.0e-19;
+        element[n] = value;
+        index[n++] = 1 + numberRows;
+        // y
+        value = y;
+        if (fabs(value) < 1.0e-19)
+            value = 1.0e-19;
+        element[n] = value;
+        index[n++] = 2 + numberRows;
+        starts[i+1] = n;
+        x += xMeshSize_;
+    }
+#ifdef KEEPXY
+    // costed slacks
+    columnLower[numberPoints_] = 0.0;
+    columnUpper[numberPoints_] = xMeshSize_;
+    objective[numberPoints_] = 1.0e3;;
+    // convexity
+    element[n] = 1.0;
+    index[n++] = 0 + numberRows;
+    starts[numberPoints_+1] = n;
+    columnLower[numberPoints_+1] = 0.0;
+    columnUpper[numberPoints_+1] = xMeshSize_;
+    objective[numberPoints_+1] = 1.0e3;;
+    // convexity
+    element[n] = -1.0;
+    index[n++] = 0 + numberRows;
+    starts[numberPoints_+2] = n;
+    solver->addCols(numberPoints_ + 2, starts, index, element, columnLower, columnUpper, objective);
+#else
+    solver->addCols(numberPoints_, starts, index, element, columnLower, columnUpper, objective);
+#endif
+    delete [] columnLower;
+    delete [] columnUpper;
+    delete [] objective;
+    delete [] starts;
+    delete [] index;
+    delete [] element;
+}
+
+// Copy constructor
+OsiBiLinearEquality::OsiBiLinearEquality ( const OsiBiLinearEquality & rhs)
+        : OsiBiLinear(rhs),
+        numberPoints_(rhs.numberPoints_)
+{
+}
+
+// Clone
+OsiObject *
+OsiBiLinearEquality::clone() const
+{
+    return new OsiBiLinearEquality(*this);
+}
+
+// Assignment operator
+OsiBiLinearEquality &
+OsiBiLinearEquality::operator=( const OsiBiLinearEquality & rhs)
+{
+    if (this != &rhs) {
+        OsiBiLinear::operator=(rhs);
+        numberPoints_ = rhs.numberPoints_;
+    }
+    return *this;
+}
+
+// Destructor
+OsiBiLinearEquality::~OsiBiLinearEquality ()
+{
+}
+// Possible improvement
+double
+OsiBiLinearEquality::improvement(const OsiSolverInterface * solver) const
+{
+    const double * pi = solver->getRowPrice();
+    int i;
+    const double * solution = solver->getColSolution();
+    printf(" for x %d y %d - pi %g %g\n", xColumn_, yColumn_, pi[xRow_], pi[yRow_]);
+    for (i = 0; i < numberPoints_; i++) {
+        if (fabs(solution[i+firstLambda_]) > 1.0e-7)
+            printf("(%d %g) ", i, solution[i+firstLambda_]);
+    }
+    printf("\n");
+    return 0.0;
+}
+/* change grid
+   if type 0 then use solution and make finer
+   if 1 then back to original
+*/
+double
+OsiBiLinearEquality::newGrid(OsiSolverInterface * solver, int type) const
+{
+    CoinPackedMatrix * matrix = solver->getMutableMatrixByCol();
+    if (!matrix) {
+        printf("Unable to modify matrix\n");
+        abort();
+    }
+    double * element = matrix->getMutableElements();
+#ifndef NDEBUG
+    const int * row = matrix->getIndices();
+#endif
+    const CoinBigIndex * columnStart = matrix->getVectorStarts();
+    //const int * columnLength = matrix->getVectorLengths();
+    // get original bounds
+    double xB[2];
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    xB[0] = lower[xColumn_];
+    xB[1] = upper[xColumn_];
+    assert (fabs((xB[1] - xB[0]) - xMeshSize_*(numberPoints_ - 1)) < 1.0e-7);
+    double mesh = 0.0;
+    int i;
+    if (type == 0) {
+        const double * solution = solver->getColSolution();
+        int first = -1;
+        int last = -1;
+        double xValue = 0.0;
+        double step = 0.0;
+        for (i = 0; i < numberPoints_; i++) {
+            int iColumn = i + firstLambda_;
+            if (fabs(solution[iColumn]) > 1.0e-7) {
+                int k = columnStart[iColumn] + 1;
+                xValue += element[k] * solution[iColumn];
+                if (first == -1) {
+                    first = i;
+                    step = -element[k];
+                } else {
+                    step += element[k];
+                }
+                last = i;
+            }
+        }
+        if (last > first + 1) {
+            printf("not adjacent - presuming small djs\n");
+        }
+        // new step size
+        assert (numberPoints_ > 2);
+        step = CoinMax((1.5 * step) / static_cast<double> (numberPoints_ - 1), 0.5 * step);
+        xB[0] = CoinMax(xB[0], xValue - 0.5 * step);
+        xB[1] = CoinMin(xB[1], xValue + 0.5 * step);
+        // and now divide these
+        mesh = (xB[1] - xB[0]) / static_cast<double> (numberPoints_ - 1);
+    } else {
+        // back to original
+        mesh = xMeshSize_;
+    }
+    double x = xB[0];
+    for (i = 0; i < numberPoints_; i++) {
+        int iColumn = i + firstLambda_;
+        double y = coefficient_ / x;
+        //assert (columnLength[iColumn]==3); - could have cuts
+        int k = columnStart[iColumn];
+#ifdef KEEPXY
+        // xy
+        assert (row[k] == xyRow_);
+        k++;
+#endif
+        assert (row[k] == convexity_);
+        k++;
+        double value;
+        // x
+        value = x;
+        assert (row[k] == xRow_);
+        assert (fabs(value) > 1.0e-10);
+        element[k++] = value;
+        // y
+        value = y;
+        assert (row[k] == yRow_);
+        assert (fabs(value) > 1.0e-10);
+        element[k++] = value;
+        x += mesh;
+    }
+    return mesh;
+}
+/** Default Constructor
+
+  Equivalent to an unspecified binary variable.
+*/
+OsiSimpleFixedInteger::OsiSimpleFixedInteger ()
+        : OsiSimpleInteger()
+{
+}
+
+/** Useful constructor
+
+  Loads actual upper & lower bounds for the specified variable.
+*/
+OsiSimpleFixedInteger::OsiSimpleFixedInteger (const OsiSolverInterface * solver, int iColumn)
+        : OsiSimpleInteger(solver, iColumn)
+{
+}
+
+
+// Useful constructor - passed solver index and original bounds
+OsiSimpleFixedInteger::OsiSimpleFixedInteger ( int iColumn, double lower, double upper)
+        : OsiSimpleInteger(iColumn, lower, upper)
+{
+}
+
+// Useful constructor - passed simple integer
+OsiSimpleFixedInteger::OsiSimpleFixedInteger ( const OsiSimpleInteger &rhs)
+        : OsiSimpleInteger(rhs)
+{
+}
+
+// Copy constructor
+OsiSimpleFixedInteger::OsiSimpleFixedInteger ( const OsiSimpleFixedInteger & rhs)
+        : OsiSimpleInteger(rhs)
+
+{
+}
+
+// Clone
+OsiObject *
+OsiSimpleFixedInteger::clone() const
+{
+    return new OsiSimpleFixedInteger(*this);
+}
+
+// Assignment operator
+OsiSimpleFixedInteger &
+OsiSimpleFixedInteger::operator=( const OsiSimpleFixedInteger & rhs)
+{
+    if (this != &rhs) {
+        OsiSimpleInteger::operator=(rhs);
+    }
+    return *this;
+}
+
+// Destructor
+OsiSimpleFixedInteger::~OsiSimpleFixedInteger ()
+{
+}
+// Infeasibility - large is 0.5
+double
+OsiSimpleFixedInteger::infeasibility(const OsiBranchingInformation * info, int & whichWay) const
+{
+    double value = info->solution_[columnNumber_];
+    value = CoinMax(value, info->lower_[columnNumber_]);
+    value = CoinMin(value, info->upper_[columnNumber_]);
+    double nearest = floor(value + (1.0 - 0.5));
+    if (nearest > value) {
+        whichWay = 1;
+    } else {
+        whichWay = 0;
+    }
+    infeasibility_ = fabs(value - nearest);
+    bool satisfied = false;
+    if (infeasibility_ <= info->integerTolerance_) {
+        otherInfeasibility_ = 1.0;
+        satisfied = true;
+        if (info->lower_[columnNumber_] != info->upper_[columnNumber_])
+            infeasibility_ = 1.0e-5;
+        else
+            infeasibility_ = 0.0;
+    } else if (info->defaultDual_ < 0.0) {
+        otherInfeasibility_ = 1.0 - infeasibility_;
+    } else {
+        const double * pi = info->pi_;
+        const double * activity = info->rowActivity_;
+        const double * lower = info->rowLower_;
+        const double * upper = info->rowUpper_;
+        const double * element = info->elementByColumn_;
+        const int * row = info->row_;
+        const CoinBigIndex * columnStart = info->columnStart_;
+        const int * columnLength = info->columnLength_;
+        double direction = info->direction_;
+        double downMovement = value - floor(value);
+        double upMovement = 1.0 - downMovement;
+        double valueP = info->objective_[columnNumber_] * direction;
+        CoinBigIndex start = columnStart[columnNumber_];
+        CoinBigIndex end = start + columnLength[columnNumber_];
+        double upEstimate = 0.0;
+        double downEstimate = 0.0;
+        if (valueP > 0.0)
+            upEstimate = valueP * upMovement;
+        else
+            downEstimate -= valueP * downMovement;
+        double tolerance = info->primalTolerance_;
+        for (CoinBigIndex j = start; j < end; j++) {
+            int iRow = row[j];
+            if (lower[iRow] < -1.0e20)
+                assert (pi[iRow] <= 1.0e-3);
+            if (upper[iRow] > 1.0e20)
+                assert (pi[iRow] >= -1.0e-3);
+            valueP = pi[iRow] * direction;
+            double el2 = element[j];
+            double value2 = valueP * el2;
+            double u = 0.0;
+            double d = 0.0;
+            if (value2 > 0.0)
+                u = value2;
+            else
+                d = -value2;
+            // if up makes infeasible then make at least default
+            double newUp = activity[iRow] + upMovement * el2;
+            if (newUp > upper[iRow] + tolerance || newUp < lower[iRow] - tolerance)
+                u = CoinMax(u, info->defaultDual_);
+            upEstimate += u * upMovement * fabs(el2);
+            // if down makes infeasible then make at least default
+            double newDown = activity[iRow] - downMovement * el2;
+            if (newDown > upper[iRow] + tolerance || newDown < lower[iRow] - tolerance)
+                d = CoinMax(d, info->defaultDual_);
+            downEstimate += d * downMovement * fabs(el2);
+        }
+        if (downEstimate >= upEstimate) {
+            infeasibility_ = CoinMax(1.0e-12, upEstimate);
+            otherInfeasibility_ = CoinMax(1.0e-12, downEstimate);
+            whichWay = 1;
+        } else {
+            infeasibility_ = CoinMax(1.0e-12, downEstimate);
+            otherInfeasibility_ = CoinMax(1.0e-12, upEstimate);
+            whichWay = 0;
+        }
+    }
+    if (preferredWay_ >= 0 && !satisfied)
+        whichWay = preferredWay_;
+    whichWay_ = static_cast<short int>(whichWay);
+    return infeasibility_;
+}
+// Creates a branching object
+OsiBranchingObject *
+OsiSimpleFixedInteger::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const
+{
+    double value = info->solution_[columnNumber_];
+    value = CoinMax(value, info->lower_[columnNumber_]);
+    value = CoinMin(value, info->upper_[columnNumber_]);
+    assert (info->upper_[columnNumber_] > info->lower_[columnNumber_]);
+    double nearest = floor(value + 0.5);
+    double integerTolerance = info->integerTolerance_;
+    if (fabs(value - nearest) < integerTolerance) {
+        // adjust value
+        if (nearest != info->upper_[columnNumber_])
+            value = nearest + 2.0 * integerTolerance;
+        else
+            value = nearest - 2.0 * integerTolerance;
+    }
+    OsiBranchingObject * branch = new OsiIntegerBranchingObject(solver, this, way,
+            value);
+    return branch;
+}
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+//#define CGL_DEBUG 2
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CoinWarmStartBasis.hpp"
+//#include "CglTemporary.hpp"
+#include "CoinFinite.hpp"
+//-------------------------------------------------------------------
+// Generate Stored cuts
+//-------------------------------------------------------------------
+void
+CglTemporary::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+                           const CglTreeInfo /*info*/)
+{
+    // Get basic problem information
+    const double * solution = si.getColSolution();
+    int numberRowCuts = cuts_.sizeRowCuts();
+    for (int i = 0; i < numberRowCuts; i++) {
+        const OsiRowCut * rowCutPointer = cuts_.rowCutPtr(i);
+        double violation = rowCutPointer->violated(solution);
+        if (violation >= requiredViolation_)
+            cs.insert(*rowCutPointer);
+    }
+    // delete
+    cuts_ = OsiCuts();
+}
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+CglTemporary::CglTemporary ()
+        :
+        CglStored()
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+CglTemporary::CglTemporary (const CglTemporary & source) :
+        CglStored(source)
+{
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglTemporary::clone() const
+{
+    return new CglTemporary(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+CglTemporary::~CglTemporary ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+CglTemporary &
+CglTemporary::operator=(const CglTemporary & rhs)
+{
+    if (this != &rhs) {
+        CglStored::operator=(rhs);
+    }
+    return *this;
+}
+void checkQP(ClpSimplex * /*model*/)
+{
+#ifdef JJF_ZERO
+    printf("Checking quadratic model %x\n", model);
+    if (model) {
+        ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(model->objectiveAsObject()));
+        assert (quadraticObj);
+        CoinPackedMatrix * quadraticObjective = quadraticObj->quadraticObjective();
+        int numberColumns = quadraticObj->numberColumns();
+        const int * columnQuadratic = quadraticObjective->getIndices();
+        const CoinBigIndex * columnQuadraticStart = quadraticObjective->getVectorStarts();
+        const int * columnQuadraticLength = quadraticObjective->getVectorLengths();
+        //const double * quadraticElement = quadraticObjective->getElements();
+        for (int i = 0; i < numberColumns; i++) {
+            for (int j = columnQuadraticStart[i]; j < columnQuadraticStart[i] + columnQuadraticLength[i]; j++)
+                assert (columnQuadratic[j] >= 0 && columnQuadratic[j] < 1000);
+        }
+    }
+#endif
+}
+//#############################################################################
+// Solve methods
+//#############################################################################
+void OsiSolverLinearizedQuadratic::initialSolve()
+{
+    OsiClpSolverInterface::initialSolve();
+    int secondaryStatus = modelPtr_->secondaryStatus();
+    if (modelPtr_->status() == 0 && (secondaryStatus == 2 || secondaryStatus == 4))
+        modelPtr_->cleanup(1);
+    if (isProvenOptimal() && modelPtr_->numberColumns() == quadraticModel_->numberColumns()) {
+        // see if qp can get better solution
+        const double * solution = modelPtr_->primalColumnSolution();
+        int numberColumns = modelPtr_->numberColumns();
+        bool satisfied = true;
+        for (int i = 0; i < numberColumns; i++) {
+            if (isInteger(i)) {
+                double value = solution[i];
+                if (fabs(value - floor(value + 0.5)) > 1.0e-6) {
+                    satisfied = false;
+                    break;
+                }
+            }
+        }
+        if (satisfied) {
+            checkQP(quadraticModel_);
+            ClpSimplex qpTemp(*quadraticModel_);
+            checkQP(&qpTemp);
+            double * lower = qpTemp.columnLower();
+            double * upper = qpTemp.columnUpper();
+            double * lower2 = modelPtr_->columnLower();
+            double * upper2 = modelPtr_->columnUpper();
+            for (int i = 0; i < numberColumns; i++) {
+                if (isInteger(i)) {
+                    double value = floor(solution[i] + 0.5);
+                    lower[i] = value;
+                    upper[i] = value;
+                } else {
+                    lower[i] = lower2[i];
+                    upper[i] = upper2[i];
+                }
+            }
+            //qpTemp.writeMps("bad.mps");
+            //modelPtr_->writeMps("bad2.mps");
+            //qpTemp.objectiveAsObject()->setActivated(0);
+            //qpTemp.primal();
+            //qpTemp.objectiveAsObject()->setActivated(1);
+            qpTemp.primal();
+            //assert (!qpTemp.problemStatus());
+            if (qpTemp.objectiveValue() < bestObjectiveValue_ && !qpTemp.problemStatus()) {
+                delete [] bestSolution_;
+                bestSolution_ = CoinCopyOfArray(qpTemp.primalColumnSolution(), numberColumns);
+                bestObjectiveValue_ = qpTemp.objectiveValue();
+                printf("better qp objective of %g\n", bestObjectiveValue_);
+            }
+        }
+    }
+}
+//#############################################################################
+// Constructors, destructors clone and assignment
+//#############################################################################
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+OsiSolverLinearizedQuadratic::OsiSolverLinearizedQuadratic ()
+        : OsiClpSolverInterface()
+{
+    bestObjectiveValue_ = COIN_DBL_MAX;
+    bestSolution_ = NULL;
+    specialOptions3_ = 0;
+    quadraticModel_ = NULL;
+}
+OsiSolverLinearizedQuadratic::OsiSolverLinearizedQuadratic ( ClpSimplex * quadraticModel)
+        : OsiClpSolverInterface(new ClpSimplex(*quadraticModel), true)
+{
+    bestObjectiveValue_ = COIN_DBL_MAX;
+    bestSolution_ = NULL;
+    specialOptions3_ = 0;
+    quadraticModel_ = new ClpSimplex(*quadraticModel);
+    // linearize
+    int numberColumns = modelPtr_->numberColumns();
+    const double * solution = modelPtr_->primalColumnSolution();
+    // Replace objective
+    ClpObjective * trueObjective = modelPtr_->objectiveAsObject();
+    ClpObjective * objective = new ClpLinearObjective(NULL, numberColumns);
+    modelPtr_->setObjectivePointer(objective);
+    double offset;
+    double saveOffset = modelPtr_->objectiveOffset();
+    memcpy(modelPtr_->objective(), trueObjective->gradient(modelPtr_, solution, offset, true, 2),
+           numberColumns*sizeof(double));
+    modelPtr_->setObjectiveOffset(saveOffset + offset);
+    delete trueObjective;
+    checkQP(quadraticModel_);
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+OsiSolverInterface *
+OsiSolverLinearizedQuadratic::clone(bool /*copyData*/) const
+{
+    //assert (copyData);
+    return new OsiSolverLinearizedQuadratic(*this);
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+OsiSolverLinearizedQuadratic::OsiSolverLinearizedQuadratic (
+    const OsiSolverLinearizedQuadratic & rhs)
+        : OsiSolverInterface(rhs)
+        , OsiClpSolverInterface(rhs)
+{
+    bestObjectiveValue_ = rhs.bestObjectiveValue_;
+    if (rhs.bestSolution_) {
+        bestSolution_ = CoinCopyOfArray(rhs.bestSolution_, modelPtr_->numberColumns());
+    } else {
+        bestSolution_ = NULL;
+    }
+    specialOptions3_ = rhs.specialOptions3_;
+    if (rhs.quadraticModel_) {
+        quadraticModel_ = new ClpSimplex(*rhs.quadraticModel_);
+    } else {
+        quadraticModel_ = NULL;
+    }
+    checkQP(rhs.quadraticModel_);
+    checkQP(quadraticModel_);
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+OsiSolverLinearizedQuadratic::~OsiSolverLinearizedQuadratic ()
+{
+    delete [] bestSolution_;
+    delete quadraticModel_;
+}
+
+//-------------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+OsiSolverLinearizedQuadratic &
+OsiSolverLinearizedQuadratic::operator=(const OsiSolverLinearizedQuadratic & rhs)
+{
+    if (this != &rhs) {
+        delete [] bestSolution_;
+        delete quadraticModel_;
+        OsiClpSolverInterface::operator=(rhs);
+        bestObjectiveValue_ = rhs.bestObjectiveValue_;
+        if (rhs.bestSolution_) {
+            bestSolution_ = CoinCopyOfArray(rhs.bestSolution_, modelPtr_->numberColumns());
+        } else {
+            bestSolution_ = NULL;
+        }
+        specialOptions3_ = rhs.specialOptions3_;
+        if (rhs.quadraticModel_) {
+            quadraticModel_ = new ClpSimplex(*rhs.quadraticModel_);
+        } else {
+            quadraticModel_ = NULL;
+        }
+        checkQP(rhs.quadraticModel_);
+        checkQP(quadraticModel_);
+    }
+    return *this;
+}
+/* Expands out all possible combinations for a knapsack
+   If buildObj NULL then just computes space needed - returns number elements
+   On entry numberOutput is maximum allowed, on exit it is number needed or
+   -1 (as will be number elements) if maximum exceeded.  numberOutput will have at
+   least space to return values which reconstruct input.
+   Rows returned will be original rows but no entries will be returned for
+   any rows all of whose entries are in knapsack.  So up to user to allow for this.
+   If reConstruct >=0 then returns number of entrie which make up item "reConstruct"
+   in expanded knapsack.  Values in buildRow and buildElement;
+*/
+int
+CoinModel::expandKnapsack(int knapsackRow, int & numberOutput, double * buildObj, CoinBigIndex * buildStart,
+                          int * buildRow, double * buildElement, int reConstruct) const
+{
+    /* mark rows
+       -2 in knapsack and other variables
+       -1 not involved
+       0 only in knapsack
+    */
+    int * markRow = new int [numberRows_];
+    int iRow;
+    int iColumn;
+    int * whichColumn = new int [numberColumns_];
+    for (iColumn = 0; iColumn < numberColumns_; iColumn++)
+        whichColumn[iColumn] = -1;
+    int numJ = 0;
+    for (iRow = 0; iRow < numberRows_; iRow++)
+        markRow[iRow] = -1;
+    CoinModelLink triple;
+    triple = firstInRow(knapsackRow);
+    while (triple.column() >= 0) {
+        int iColumn = triple.column();
+#ifndef NDEBUG
+        const char *  el = getElementAsString(knapsackRow, iColumn);
+        assert (!strcmp("Numeric", el));
+#endif
+        whichColumn[iColumn] = numJ;
+        numJ++;
+        triple = next(triple);
+    }
+    for (iRow = 0; iRow < numberRows_; iRow++) {
+        triple = firstInRow(iRow);
+        int type = -3;
+        while (triple.column() >= 0) {
+            int iColumn = triple.column();
+            if (whichColumn[iColumn] >= 0) {
+                if (type == -3)
+                    type = 0;
+                else if (type != 0)
+                    type = -2;
+            } else {
+                if (type == -3)
+                    type = -1;
+                else if (type == 0)
+                    type = -2;
+            }
+            triple = next(triple);
+        }
+        if (type == -3)
+            type = -1;
+        markRow[iRow] = type;
+    }
+    int * bound = new int [numberColumns_+1];
+    int * whichRow = new int [numberRows_];
+    ClpSimplex tempModel;
+    CoinModel tempModel2(*this);
+    tempModel.loadProblem(tempModel2);
+    int * stack = new int [numberColumns_+1];
+    double * size = new double [numberColumns_+1];
+    double * rhsOffset = new double[numberRows_];
+    int * build = new int[numberColumns_];
+    int maxNumber = numberOutput;
+    numJ = 0;
+    double minSize = getRowLower(knapsackRow);
+    double maxSize = getRowUpper(knapsackRow);
+    double offset = 0.0;
+    triple = firstInRow(knapsackRow);
+    while (triple.column() >= 0) {
+        iColumn = triple.column();
+        double lowerColumn = columnLower(iColumn);
+        double upperColumn = columnUpper(iColumn);
+        double gap = upperColumn - lowerColumn;
+        if (gap > 1.0e8)
+            gap = 1.0e8;
+        assert (fabs(floor(gap + 0.5) - gap) < 1.0e-5);
+        whichColumn[numJ] = iColumn;
+        bound[numJ] = static_cast<int> (gap);
+        size[numJ++] = triple.value();
+        offset += triple.value() * lowerColumn;
+        triple = next(triple);
+    }
+    int jRow;
+    for (iRow = 0; iRow < numberRows_; iRow++)
+        whichRow[iRow] = iRow;
+    ClpSimplex smallModel(&tempModel, numberRows_, whichRow, numJ, whichColumn, true, true, true);
+    // modify rhs to allow for nonzero lower bounds
+    double * rowLower = smallModel.rowLower();
+    double * rowUpper = smallModel.rowUpper();
+    const double * columnLower = smallModel.columnLower();
+    //const double * columnUpper = smallModel.columnUpper();
+    const CoinPackedMatrix * matrix = smallModel.matrix();
+    const double * element = matrix->getElements();
+    const int * row = matrix->getIndices();
+    const CoinBigIndex * columnStart = matrix->getVectorStarts();
+    const int * columnLength = matrix->getVectorLengths();
+    const double * objective = smallModel.objective();
+    double objectiveOffset = 0.0;
+    CoinZeroN(rhsOffset, numberRows_);
+    for (iColumn = 0; iColumn < numJ; iColumn++) {
+        double lower = columnLower[iColumn];
+        if (lower) {
+            objectiveOffset += objective[iColumn];
+            for (CoinBigIndex j = columnStart[iColumn];
+                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                double value = element[j] * lower;
+                int kRow = row[j];
+                rhsOffset[kRow] += value;
+                if (rowLower[kRow] > -1.0e20)
+                    rowLower[kRow] -= value;
+                if (rowUpper[kRow] < 1.0e20)
+                    rowUpper[kRow] -= value;
+            }
+        }
+    }
+    // relax
+    for (jRow = 0; jRow < numberRows_; jRow++) {
+        if (markRow[jRow] == 0 && knapsackRow != jRow) {
+            if (rowLower[jRow] > -1.0e20)
+                rowLower[jRow] -= 1.0e-7;
+            if (rowUpper[jRow] < 1.0e20)
+                rowUpper[jRow] += 1.0e-7;
+        } else {
+            rowLower[jRow] = -COIN_DBL_MAX;
+            rowUpper[jRow] = COIN_DBL_MAX;
+        }
+    }
+    double * rowActivity = smallModel.primalRowSolution();
+    CoinZeroN(rowActivity, numberRows_);
+    maxSize -= offset;
+    minSize -= offset;
+    // now generate
+    int i;
+    int iStack = numJ;
+    for (i = 0; i < numJ; i++) {
+        stack[i] = 0;
+    }
+    double tooMuch = 10.0 * maxSize;
+    stack[numJ] = 1;
+    size[numJ] = tooMuch;
+    bound[numJ] = 0;
+    double sum = tooMuch;
+    numberOutput = 0;
+    int nelCreate = 0;
+    /* typeRun is - 0 for initial sizes
+                    1 for build
+      	  2 for reconstruct
+    */
+    int typeRun = buildObj ? 1 : 0;
+    if (reConstruct >= 0) {
+        assert (buildRow && buildElement);
+        typeRun = 2;
+    }
+    if (typeRun == 1)
+        buildStart[0] = 0;
+    while (iStack >= 0) {
+        if (sum >= minSize && sum <= maxSize) {
+            double checkSize = 0.0;
+            bool good = true;
+            int nRow = 0;
+            double obj = objectiveOffset;
+            // nRow is zero? CoinZeroN(rowActivity,nRow);
+            for (iColumn = 0; iColumn < numJ; iColumn++) {
+                int iValue = stack[iColumn];
+                if (iValue > bound[iColumn]) {
+                    good = false;
+                    break;
+                } else if (iValue) {
+                    obj += objective[iColumn] * iValue;
+                    for (CoinBigIndex j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        double value = element[j] * iValue;
+                        int kRow = row[j];
+                        if (rowActivity[kRow]) {
+                            rowActivity[kRow] += value;
+                            if (!rowActivity[kRow])
+                                rowActivity[kRow] = 1.0e-100;
+                        } else {
+                            build[nRow++] = kRow;
+                            rowActivity[kRow] = value;
+                        }
+                    }
+                }
+            }
+            if (good) {
+                for (jRow = 0; jRow < nRow; jRow++) {
+                    int kRow = build[jRow];
+                    double value = rowActivity[kRow];
+                    if (value > rowUpper[kRow] || value < rowLower[kRow]) {
+                        good = false;
+                        break;
+                    }
+                }
+            }
+            if (good) {
+                if (typeRun == 1) {
+                    buildObj[numberOutput] = obj;
+                    for (jRow = 0; jRow < nRow; jRow++) {
+                        int kRow = build[jRow];
+                        double value = rowActivity[kRow];
+                        if (markRow[kRow] < 0 && fabs(value) > 1.0e-13) {
+                            buildElement[nelCreate] = value;
+                            buildRow[nelCreate++] = kRow;
+                        }
+                    }
+                    buildStart[numberOutput+1] = nelCreate;
+                } else if (!typeRun) {
+                    for (jRow = 0; jRow < nRow; jRow++) {
+                        int kRow = build[jRow];
+                        double value = rowActivity[kRow];
+                        if (markRow[kRow] < 0 && fabs(value) > 1.0e-13) {
+                            nelCreate++;
+                        }
+                    }
+                }
+                if (typeRun == 2 && reConstruct == numberOutput) {
+                    // build and exit
+                    nelCreate = 0;
+                    for (iColumn = 0; iColumn < numJ; iColumn++) {
+                        int iValue = stack[iColumn];
+                        if (iValue) {
+                            buildRow[nelCreate] = whichColumn[iColumn];
+                            buildElement[nelCreate++] = iValue;
+                        }
+                    }
+                    numberOutput = 1;
+                    for (i = 0; i < numJ; i++) {
+                        bound[i] = 0;
+                    }
+                    break;
+                }
+                numberOutput++;
+                if (numberOutput > maxNumber) {
+                    nelCreate = -1;
+                    numberOutput = -1;
+                    for (i = 0; i < numJ; i++) {
+                        bound[i] = 0;
+                    }
+                    break;
+                } else if (typeRun == 1 && numberOutput == maxNumber) {
+                    // On second run
+                    for (i = 0; i < numJ; i++) {
+                        bound[i] = 0;
+                    }
+                    break;
+                }
+                for (int j = 0; j < numJ; j++) {
+                    checkSize += stack[j] * size[j];
+                }
+                assert (fabs(sum - checkSize) < 1.0e-3);
+            }
+            for (jRow = 0; jRow < nRow; jRow++) {
+                int kRow = build[jRow];
+                rowActivity[kRow] = 0.0;
+            }
+        }
+        if (sum > maxSize || stack[iStack] > bound[iStack]) {
+            sum -= size[iStack] * stack[iStack];
+            stack[iStack--] = 0;
+            if (iStack >= 0) {
+                stack[iStack] ++;
+                sum += size[iStack];
+            }
+        } else {
+            // must be less
+            // add to last possible
+            iStack = numJ - 1;
+            sum += size[iStack];
+            stack[iStack]++;
+        }
+    }
+    //printf("%d will be created\n",numberOutput);
+    delete [] whichColumn;
+    delete [] whichRow;
+    delete [] bound;
+    delete [] stack;
+    delete [] size;
+    delete [] rhsOffset;
+    delete [] build;
+    delete [] markRow;
+    return nelCreate;
+}
+#include "ClpConstraint.hpp"
+#include "ClpConstraintLinear.hpp"
+#include "ClpConstraintQuadratic.hpp"
+#ifdef COIN_HAS_ASL
+//#include "ClpAmplObjective.hpp"
+#endif
+/* Return an approximate solution to a CoinModel.
+    Lots of bounds may be odd to force a solution.
+    mode = 0 just tries to get a continuous solution
+*/
+ClpSimplex *
+approximateSolution(CoinModel & coinModel,
+                    int numberPasses, double deltaTolerance,
+                    int /*mode*/)
+{
+#ifndef JJF_ONE
+    //#ifdef COIN_HAS_ASL
+    // matrix etc will be changed
+    CoinModel coinModel2 = coinModel;
+    if (coinModel2.moreInfo()) {
+        // for now just ampl objective
+        ClpSimplex * model = new ClpSimplex();
+        model->loadProblem(coinModel2);
+        int numberConstraints;
+        ClpConstraint ** constraints = NULL;
+        int type = model->loadNonLinear(coinModel2.moreInfo(),
+                                        numberConstraints, constraints);
+        if (type == 1 || type == 3) {
+            model->nonlinearSLP(numberPasses, deltaTolerance);
+        } else if (type == 2 || type == 4) {
+            model->nonlinearSLP(numberConstraints, constraints,
+                                numberPasses, deltaTolerance);
+        } else {
+            printf("error or linear - fix %d\n", type);
+        }
+        //exit(66);
+        return model;
+    }
+    // first check and set up arrays
+    int numberColumns = coinModel.numberColumns();
+    int numberRows = coinModel.numberRows();
+    // List of nonlinear rows
+    int * which = new int[numberRows];
+    bool testLinear = false;
+    int numberConstraints = 0;
+    int iColumn;
+    bool linearObjective = true;
+    int maximumQuadraticElements = 0;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        // See if quadratic objective
+        const char * expr = coinModel.getColumnObjectiveAsString(iColumn);
+        if (strcmp(expr, "Numeric")) {
+            linearObjective = false;
+            // check if value*x+-value*y....
+            assert (strlen(expr) < 20000);
+            char temp[20000];
+            strcpy(temp, expr);
+            char * pos = temp;
+            bool ifFirst = true;
+            while (*pos) {
+                double value;
+                int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel);
+                // must be column unless first when may be linear term
+                if (jColumn >= 0) {
+                    maximumQuadraticElements++;
+                } else if (jColumn != -2) {
+                    printf("bad nonlinear term %s\n", temp);
+                    abort();
+                }
+                ifFirst = false;
+            }
+        }
+    }
+    if (!linearObjective) {
+        // zero objective
+        for (iColumn = 0; iColumn < numberColumns; iColumn++)
+            coinModel2.setObjective(iColumn, 0.0);
+    }
+    int iRow;
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        int numberQuadratic = 0;
+        bool linear = true;
+        CoinModelLink triple = coinModel.firstInRow(iRow);
+        while (triple.column() >= 0) {
+            int iColumn = triple.column();
+            const char *  expr = coinModel.getElementAsString(iRow, iColumn);
+            if (strcmp("Numeric", expr)) {
+                linear = false;
+                // check if value*x+-value*y....
+                assert (strlen(expr) < 20000);
+                char temp[20000];
+                strcpy(temp, expr);
+                char * pos = temp;
+                bool ifFirst = true;
+                while (*pos) {
+                    double value;
+                    int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel);
+                    // must be column unless first when may be linear term
+                    if (jColumn >= 0) {
+                        numberQuadratic++;
+                    } else if (jColumn != -2) {
+                        printf("bad nonlinear term %s\n", temp);
+                        abort();
+                    }
+                    ifFirst = false;
+                }
+            }
+            triple = coinModel.next(triple);
+        }
+        if (!linear || testLinear) {
+            CoinModelLink triple = coinModel.firstInRow(iRow);
+            while (triple.column() >= 0) {
+                int iColumn = triple.column();
+                coinModel2.setElement(iRow, iColumn, 0.0);
+                triple = coinModel.next(triple);
+            }
+            which[numberConstraints++] = iRow;
+            maximumQuadraticElements = CoinMax(maximumQuadraticElements, numberQuadratic);
+        }
+    }
+    ClpSimplex * model = new ClpSimplex();
+    // return if nothing
+    if (!numberConstraints && linearObjective) {
+        delete [] which;
+        model->loadProblem(coinModel);
+        model->dual();
+        return model;
+    }
+    // space for quadratic
+    // allow for linear term
+    maximumQuadraticElements += numberColumns;
+    CoinBigIndex * startQuadratic = new CoinBigIndex [numberColumns+1];
+    int * columnQuadratic = new int [maximumQuadraticElements];
+    double * elementQuadratic = new double [maximumQuadraticElements];
+    ClpConstraint ** constraints = new ClpConstraint * [numberConstraints];
+    double * linearTerm = new double [numberColumns];
+    int saveNumber = numberConstraints;
+    numberConstraints = 0;
+    ClpQuadraticObjective * quadObj = NULL;
+    if (!linearObjective) {
+        int numberQuadratic = 0;
+        CoinZeroN(linearTerm, numberColumns);
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            startQuadratic[iColumn] = numberQuadratic;
+            // See if quadratic objective
+            const char * expr = coinModel.getColumnObjectiveAsString(iColumn);
+            if (strcmp(expr, "Numeric")) {
+                // value*x*y
+                char temp[20000];
+                strcpy(temp, expr);
+                char * pos = temp;
+                bool ifFirst = true;
+                while (*pos) {
+                    double value;
+                    int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel);
+                    // must be column unless first when may be linear term
+                    if (jColumn >= 0) {
+                        columnQuadratic[numberQuadratic] = jColumn;
+                        if (jColumn != iColumn)
+                            elementQuadratic[numberQuadratic++] = 1.0 * value; // convention
+                        else if (jColumn == iColumn)
+                            elementQuadratic[numberQuadratic++] = 2.0 * value; // convention
+                    } else if (jColumn == -2) {
+                        linearTerm[iColumn] = value;
+                    } else {
+                        printf("bad nonlinear term %s\n", temp);
+                        abort();
+                    }
+                    ifFirst = false;
+                }
+            } else {
+                // linear part
+                linearTerm[iColumn] = coinModel.getColumnObjective(iColumn);
+            }
+        }
+        startQuadratic[numberColumns] = numberQuadratic;
+        quadObj = new ClpQuadraticObjective(linearTerm, numberColumns,
+                                            startQuadratic, columnQuadratic, elementQuadratic);
+    }
+    int iConstraint;
+    for (iConstraint = 0; iConstraint < saveNumber; iConstraint++) {
+        iRow = which[iConstraint];
+        if (iRow >= 0) {
+            int numberQuadratic = 0;
+            int lastColumn = -1;
+            int largestColumn = -1;
+            CoinZeroN(linearTerm, numberColumns);
+            CoinModelLink triple = coinModel.firstInRow(iRow);
+            while (triple.column() >= 0) {
+                int iColumn = triple.column();
+                while (lastColumn < iColumn) {
+                    startQuadratic[lastColumn+1] = numberQuadratic;
+                    lastColumn++;
+                }
+                const char *  expr = coinModel.getElementAsString(iRow, iColumn);
+                if (strcmp("Numeric", expr)) {
+                    largestColumn = CoinMax(largestColumn, iColumn);
+                    // value*x*y
+                    char temp[20000];
+                    strcpy(temp, expr);
+                    char * pos = temp;
+                    bool ifFirst = true;
+                    while (*pos) {
+                        double value;
+                        int jColumn = decodeBit(pos, pos, value, ifFirst, coinModel);
+                        // must be column unless first when may be linear term
+                        if (jColumn >= 0) {
+                            columnQuadratic[numberQuadratic] = jColumn;
+                            if (jColumn == iColumn)
+                                elementQuadratic[numberQuadratic++] = 2.0 * value; // convention
+                            else
+                                elementQuadratic[numberQuadratic++] = 1.0 * value; // convention
+                            largestColumn = CoinMax(largestColumn, jColumn);
+                        } else if (jColumn == -2) {
+                            linearTerm[iColumn] = value;
+                            // and put in as row -1
+                            columnQuadratic[numberQuadratic] = -1;
+                            if (jColumn == iColumn)
+                                elementQuadratic[numberQuadratic++] = 2.0 * value; // convention
+                            else
+                                elementQuadratic[numberQuadratic++] = 1.0 * value; // convention
+                            largestColumn = CoinMax(largestColumn, iColumn);
+                        } else {
+                            printf("bad nonlinear term %s\n", temp);
+                            abort();
+                        }
+                        ifFirst = false;
+                    }
+                } else {
+                    // linear part
+                    linearTerm[iColumn] = coinModel.getElement(iRow, iColumn);
+                    // and put in as row -1
+                    columnQuadratic[numberQuadratic] = -1;
+                    elementQuadratic[numberQuadratic++] = linearTerm[iColumn];
+                    if (linearTerm[iColumn])
+                        largestColumn = CoinMax(largestColumn, iColumn);
+                }
+                triple = coinModel.next(triple);
+            }
+            while (lastColumn < numberColumns) {
+                startQuadratic[lastColumn+1] = numberQuadratic;
+                lastColumn++;
+            }
+            // here we create ClpConstraint
+            if (testLinear) {
+                int n = 0;
+                int * indices = new int[numberColumns];
+                for (int j = 0; j < numberColumns; j++) {
+                    if (linearTerm[j]) {
+                        linearTerm[n] = linearTerm[j];
+                        indices[n++] = j;
+                    }
+                }
+                /// Constructor from constraint
+                constraints[numberConstraints++] = new ClpConstraintLinear(iRow, n, numberColumns,
+                        indices, linearTerm);
+                delete [] indices;
+            } else {
+                constraints[numberConstraints++] = new ClpConstraintQuadratic(iRow, largestColumn + 1, numberColumns,
+                        startQuadratic, columnQuadratic, elementQuadratic);
+            }
+        }
+    }
+    delete [] startQuadratic;
+    delete [] columnQuadratic;
+    delete [] elementQuadratic;
+    delete [] linearTerm;
+    delete [] which;
+    model->loadProblem(coinModel2);
+    if (quadObj)
+        model->setObjective(quadObj);
+    delete quadObj;
+#ifndef NDEBUG
+    int returnCode;
+    if (numberConstraints) {
+        returnCode = model->nonlinearSLP(numberConstraints, constraints,
+                                         numberPasses, deltaTolerance);
+        for (iConstraint = 0; iConstraint < saveNumber; iConstraint++)
+            delete constraints[iConstraint];
+    } else {
+        returnCode = model->nonlinearSLP(numberPasses, deltaTolerance);
+    }
+    assert (!returnCode);
+#else
+    if (numberConstraints) {
+        model->nonlinearSLP(numberConstraints, constraints, numberPasses, deltaTolerance);
+        for (iConstraint = 0; iConstraint < saveNumber; iConstraint++)
+            delete constraints[iConstraint];
+    } else {
+        model->nonlinearSLP(numberPasses, deltaTolerance);
+    }
+#endif
+    delete [] constraints;
+    return model;
+#else
+    printf("loadNonLinear needs ampl\n");
+    abort();
+    return NULL;
+#endif
+}
+OsiChooseStrongSubset::OsiChooseStrongSubset() :
+        OsiChooseStrong(),
+        numberObjectsToUse_(0)
+{
+}
+
+OsiChooseStrongSubset::OsiChooseStrongSubset(const OsiSolverInterface * solver) :
+        OsiChooseStrong(solver),
+        numberObjectsToUse_(-1)
+{
+}
+
+OsiChooseStrongSubset::OsiChooseStrongSubset(const OsiChooseStrongSubset & rhs)
+        : OsiChooseStrong(rhs)
+{
+    numberObjectsToUse_ = -1;
+}
+
+OsiChooseStrongSubset &
+OsiChooseStrongSubset::operator=(const OsiChooseStrongSubset & rhs)
+{
+    if (this != &rhs) {
+        OsiChooseStrong::operator=(rhs);
+        numberObjectsToUse_ = -1;
+    }
+    return *this;
+}
+
+
+OsiChooseStrongSubset::~OsiChooseStrongSubset ()
+{
+}
+
+// Clone
+OsiChooseVariable *
+OsiChooseStrongSubset::clone() const
+{
+    return new OsiChooseStrongSubset(*this);
+}
+// Initialize
+int
+OsiChooseStrongSubset::setupList ( OsiBranchingInformation *info, bool initialize)
+{
+    assert (solver_ == info->solver_);
+    // Only has to work with Clp
+    OsiSolverInterface * solverA = const_cast<OsiSolverInterface *> (solver_);
+    OsiSolverLink * solver = dynamic_cast<OsiSolverLink *> (solverA);
+    assert (solver);
+    int numberObjects = solver->numberObjects();
+    if (numberObjects > pseudoCosts_.numberObjects()) {
+        // redo useful arrays
+        pseudoCosts_.initialize(numberObjects);
+    }
+    int numObj = numberObjects;
+    if (numberObjectsToUse_ < 0) {
+        // Sort objects so bilinear at end
+        OsiObject ** sorted = new OsiObject * [numberObjects];
+        OsiObject ** objects = solver->objects();
+        numObj = 0;
+        int numberBiLinear = 0;
+        int i;
+        for (i = 0; i < numberObjects; i++) {
+            OsiObject * obj = objects[i];
+            OsiBiLinear * objB = dynamic_cast<OsiBiLinear *> (obj);
+            if (!objB)
+                objects[numObj++] = obj;
+            else
+                sorted[numberBiLinear++] = obj;
+        }
+        numberObjectsToUse_ = numObj;
+        for (i = 0; i < numberBiLinear; i++)
+            objects[numObj++] = sorted[i];
+        delete [] sorted;
+        // See if any master objects
+        for (i = 0; i < numberObjectsToUse_; i++) {
+            OsiUsesBiLinear * obj = dynamic_cast<OsiUsesBiLinear *> (objects[i]);
+            if (obj)
+                obj->addBiLinearObjects(solver);
+        }
+    }
+    solver->setNumberObjects(numberObjectsToUse_);
+    numObj = numberObjectsToUse_;
+    // Use shadow prices
+    //info->defaultDual_=0.0;
+    int numberUnsatisfied = OsiChooseStrong::setupList ( info, initialize);
+    solver->setNumberObjects(numberObjects);
+    numObj = numberObjects;
+    return numberUnsatisfied;
+}
+/* Choose a variable
+   Returns -
+   -1 Node is infeasible
+   0  Normal termination - we have a candidate
+   1  All looks satisfied - no candidate
+   2  We can change the bound on a variable - but we also have a strong branching candidate
+   3  We can change the bound on a variable - but we have a non-strong branching candidate
+   4  We can change the bound on a variable - no other candidates
+   We can pick up branch from whichObject() and whichWay()
+   We can pick up a forced branch (can change bound) from whichForcedObject() and whichForcedWay()
+   If we have a solution then we can pick up from goodObjectiveValue() and goodSolution()
+*/
+int
+OsiChooseStrongSubset::chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *info, bool fixVariables)
+{
+    //int numberObjects = solver->numberObjects();
+    //solver->setNumberObjects(numberObjectsToUse_);
+    //numberObjects_=numberObjectsToUse_;
+    // Use shadow prices
+    //info->defaultDual_=0.0;
+    int returnCode = OsiChooseStrong::chooseVariable(solver, info, fixVariables);
+    //solver->setNumberObjects(numberObjects);
+    //numberObjects_=numberObjects;
+    return returnCode;
+}
+/** Default Constructor
+
+  Equivalent to an unspecified binary variable.
+*/
+OsiUsesBiLinear::OsiUsesBiLinear ()
+        : OsiSimpleInteger(),
+        numberBiLinear_(0),
+        type_(0),
+        objects_(NULL)
+{
+}
+
+/** Useful constructor
+
+  Loads actual upper & lower bounds for the specified variable.
+*/
+OsiUsesBiLinear::OsiUsesBiLinear (const OsiSolverInterface * solver, int iColumn, int type)
+        : OsiSimpleInteger(solver, iColumn),
+        numberBiLinear_(0),
+        type_(type),
+        objects_(NULL)
+{
+    if (type_) {
+        assert(originalLower_ == floor(originalLower_ + 0.5));
+        assert(originalUpper_ == floor(originalUpper_ + 0.5));
+    }
+}
+
+
+// Useful constructor - passed solver index and original bounds
+OsiUsesBiLinear::OsiUsesBiLinear ( int iColumn, double lower, double upper, int type)
+        : OsiSimpleInteger(iColumn, lower, upper),
+        numberBiLinear_(0),
+        type_(type),
+        objects_(NULL)
+{
+    if (type_) {
+        assert(originalLower_ == floor(originalLower_ + 0.5));
+        assert(originalUpper_ == floor(originalUpper_ + 0.5));
+    }
+}
+
+// Useful constructor - passed simple integer
+OsiUsesBiLinear::OsiUsesBiLinear ( const OsiSimpleInteger &rhs, int type)
+        : OsiSimpleInteger(rhs),
+        numberBiLinear_(0),
+        type_(type),
+        objects_(NULL)
+{
+    if (type_) {
+        assert(originalLower_ == floor(originalLower_ + 0.5));
+        assert(originalUpper_ == floor(originalUpper_ + 0.5));
+    }
+}
+
+// Copy constructor
+OsiUsesBiLinear::OsiUsesBiLinear ( const OsiUsesBiLinear & rhs)
+        : OsiSimpleInteger(rhs),
+        numberBiLinear_(0),
+        type_(rhs.type_),
+        objects_(NULL)
+
+{
+}
+
+// Clone
+OsiObject *
+OsiUsesBiLinear::clone() const
+{
+    return new OsiUsesBiLinear(*this);
+}
+
+// Assignment operator
+OsiUsesBiLinear &
+OsiUsesBiLinear::operator=( const OsiUsesBiLinear & rhs)
+{
+    if (this != &rhs) {
+        OsiSimpleInteger::operator=(rhs);
+        delete [] objects_;
+        numberBiLinear_ = 0;
+        type_ = rhs.type_;
+        objects_ = NULL;
+    }
+    return *this;
+}
+
+// Destructor
+OsiUsesBiLinear::~OsiUsesBiLinear ()
+{
+    delete [] objects_;
+}
+// Infeasibility - large is 0.5
+double
+OsiUsesBiLinear::infeasibility(const OsiBranchingInformation * info, int & whichWay) const
+{
+    assert (type_ == 0); // just continuous for now
+    double value = info->solution_[columnNumber_];
+    value = CoinMax(value, info->lower_[columnNumber_]);
+    value = CoinMin(value, info->upper_[columnNumber_]);
+    infeasibility_ = 0.0;
+    for (int i = 0; i < numberBiLinear_; i++) {
+        OsiBiLinear * obj = dynamic_cast<OsiBiLinear *> (objects_[i]);
+        assert (obj);
+        //obj->getPseudoShadow(info);
+        //infeasibility_ += objects_[i]->infeasibility(info,whichWay);
+        infeasibility_ += obj->getMovement(info);
+    }
+    bool satisfied = false;
+    whichWay = -1;
+    if (!infeasibility_) {
+        otherInfeasibility_ = 1.0;
+        satisfied = true;
+        infeasibility_ = 0.0;
+    } else {
+        otherInfeasibility_ = 10.0 * infeasibility_;
+        if (value - info->lower_[columnNumber_] >
+                info->upper_[columnNumber_] - value)
+            whichWay = 1;
+        else
+            whichWay = -1;
+    }
+    if (preferredWay_ >= 0 && !satisfied)
+        whichWay = preferredWay_;
+    whichWay_ = static_cast<short int>(whichWay);
+    return infeasibility_;
+}
+// Creates a branching object
+OsiBranchingObject *
+OsiUsesBiLinear::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const
+{
+    double value = info->solution_[columnNumber_];
+    value = CoinMax(value, info->lower_[columnNumber_]);
+    value = CoinMin(value, info->upper_[columnNumber_]);
+    assert (info->upper_[columnNumber_] > info->lower_[columnNumber_]);
+    double nearest = floor(value + 0.5);
+    double integerTolerance = info->integerTolerance_;
+    if (fabs(value - nearest) < integerTolerance) {
+        // adjust value
+        if (nearest != info->upper_[columnNumber_])
+            value = nearest + 2.0 * integerTolerance;
+        else
+            value = nearest - 2.0 * integerTolerance;
+    }
+    OsiBranchingObject * branch = new OsiIntegerBranchingObject(solver, this, way,
+            value, value, value);
+    return branch;
+}
+// This looks at solution and sets bounds to contain solution
+/** More precisely: it first forces the variable within the existing
+    bounds, and then tightens the bounds to fix the variable at the
+    nearest integer value.
+*/
+double
+OsiUsesBiLinear::feasibleRegion(OsiSolverInterface * solver,
+                                const OsiBranchingInformation * info) const
+{
+    double value = info->solution_[columnNumber_];
+    double newValue = CoinMax(value, info->lower_[columnNumber_]);
+    newValue = CoinMin(newValue, info->upper_[columnNumber_]);
+    solver->setColLower(columnNumber_, newValue);
+    solver->setColUpper(columnNumber_, newValue);
+    return fabs(value - newValue);
+}
+// Add all bi-linear objects
+void
+OsiUsesBiLinear::addBiLinearObjects(OsiSolverLink * solver)
+{
+    delete [] objects_;
+    numberBiLinear_ = 0;
+    OsiObject ** objects = solver->objects();
+    int i;
+    int numberObjects = solver->numberObjects();
+    for (i = 0; i < numberObjects; i++) {
+        OsiObject * obj = objects[i];
+        OsiBiLinear * objB = dynamic_cast<OsiBiLinear *> (obj);
+        if (objB) {
+            if (objB->xColumn() == columnNumber_ || objB->yColumn() == columnNumber_)
+                numberBiLinear_++;
+        }
+    }
+    if (numberBiLinear_) {
+        objects_ = new OsiObject * [numberBiLinear_];
+        numberBiLinear_ = 0;
+        for (i = 0; i < numberObjects; i++) {
+            OsiObject * obj = objects[i];
+            OsiBiLinear * objB = dynamic_cast<OsiBiLinear *> (obj);
+            if (objB) {
+                if (objB->xColumn() == columnNumber_ || objB->yColumn() == columnNumber_)
+                    objects_[numberBiLinear_++] = obj;;
+            }
+        }
+    } else {
+        objects_ = NULL;
+    }
+}
+
diff --git a/cbits/coin/CbcLinked.hpp b/cbits/coin/CbcLinked.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcLinked.hpp
@@ -0,0 +1,1406 @@
+/* $Id: CbcLinked.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglLinked_H
+#define CglLinked_H
+/* THIS CONTAINS STUFF THAT SHOULD BE IN
+   OsiSolverLink
+   OsiBranchLink
+   CglTemporary
+*/
+#include "CoinModel.hpp"
+#include "OsiClpSolverInterface.hpp"
+#include "OsiChooseVariable.hpp"
+#include "CbcFathom.hpp"
+class CbcModel;
+class CoinPackedMatrix;
+class OsiLinkedBound;
+class OsiObject;
+class CglStored;
+class CglTemporary;
+/**
+
+This is to allow the user to replace initialSolve and resolve
+This version changes coefficients
+*/
+
+class OsiSolverLink : public CbcOsiSolver {
+
+public:
+    //---------------------------------------------------------------------------
+    /**@name Solve methods */
+    //@{
+    /// Solve initial LP relaxation
+    virtual void initialSolve();
+
+    /// Resolve an LP relaxation after problem modification
+    virtual void resolve();
+
+    /**
+       Problem specific
+       Returns -1 if node fathomed and no solution
+                0 if did nothing
+            1 if node fathomed and solution
+       allFixed is true if all LinkedBound variables are fixed
+    */
+    virtual int fathom(bool allFixed) ;
+    /** Solves nonlinear problem from CoinModel using SLP - may be used as crash
+        for other algorithms when number of iterations small.
+        Also exits if all problematical variables are changing
+        less than deltaTolerance
+        Returns solution array
+    */
+    double * nonlinearSLP(int numberPasses, double deltaTolerance);
+    /** Solve linearized quadratic objective branch and bound.
+        Return cutoff and OA cut
+    */
+    double linearizedBAB(CglStored * cut) ;
+    /** Solves nonlinear problem from CoinModel using SLP - and then tries to get
+        heuristic solution
+        Returns solution array
+        mode -
+        0 just get continuous
+        1 round and try normal bab
+        2 use defaultBound_ to bound integer variables near current solution
+    */
+    double * heuristicSolution(int numberPasses, double deltaTolerance, int mode);
+
+    /// Do OA cuts
+    int doAOCuts(CglTemporary * cutGen, const double * solution, const double * solution2);
+    //@}
+
+
+    /**@name Constructors and destructors */
+    //@{
+    /// Default Constructor
+    OsiSolverLink ();
+
+    /** This creates from a coinModel object
+
+        if errors.then number of sets is -1
+
+        This creates linked ordered sets information.  It assumes -
+
+        for product terms syntax is yy*f(zz)
+        also just f(zz) is allowed
+        and even a constant
+
+        modelObject not const as may be changed as part of process.
+    */
+    OsiSolverLink(  CoinModel & modelObject);
+    // Other way with existing object
+    void load(  CoinModel & modelObject, bool tightenBounds = false, int logLevel = 1);
+    /// Clone
+    virtual OsiSolverInterface * clone(bool copyData = true) const;
+
+    /// Copy constructor
+    OsiSolverLink (const OsiSolverLink &);
+
+    /// Assignment operator
+    OsiSolverLink & operator=(const OsiSolverLink& rhs);
+
+    /// Destructor
+    virtual ~OsiSolverLink ();
+
+    //@}
+
+
+    /**@name Sets and Gets */
+    //@{
+    /// Add a bound modifier
+    void addBoundModifier(bool upperBoundAffected, bool useUpperBound, int whichVariable, int whichVariableAffected,
+                          double multiplier = 1.0);
+    /// Update coefficients - returns number updated if in updating mode
+    int updateCoefficients(ClpSimplex * solver, CoinPackedMatrix * matrix);
+    /// Analyze constraints to see which are convex (quadratic)
+    void analyzeObjects();
+    /// Add reformulated bilinear constraints
+    void addTighterConstraints();
+    /// Objective value of best solution found internally
+    inline double bestObjectiveValue() const {
+        return bestObjectiveValue_;
+    }
+    /// Set objective value of best solution found internally
+    inline void setBestObjectiveValue(double value) {
+        bestObjectiveValue_ = value;
+    }
+    /// Best solution found internally
+    inline const double * bestSolution() const {
+        return bestSolution_;
+    }
+    /// Set best solution found internally
+    void setBestSolution(const double * solution, int numberColumns);
+    /// Set special options
+    inline void setSpecialOptions2(int value) {
+        specialOptions2_ = value;
+    }
+    /// Say convex (should work it out) - if convex false then strictly concave
+    void sayConvex(bool convex);
+    /// Get special options
+    inline int specialOptions2() const {
+        return specialOptions2_;
+    }
+    /** Clean copy of matrix
+        So we can add rows
+    */
+    CoinPackedMatrix * cleanMatrix() const {
+        return matrix_;
+    }
+    /** Row copy of matrix
+        Just genuine columns and rows
+        Linear part
+    */
+    CoinPackedMatrix * originalRowCopy() const {
+        return originalRowCopy_;
+    }
+    /// Copy of quadratic model if one
+    ClpSimplex * quadraticModel() const {
+        return quadraticModel_;
+    }
+    /// Gets correct form for a quadratic row - user to delete
+    CoinPackedMatrix * quadraticRow(int rowNumber, double * linear) const;
+    /// Default meshSize
+    inline double defaultMeshSize() const {
+        return defaultMeshSize_;
+    }
+    inline void setDefaultMeshSize(double value) {
+        defaultMeshSize_ = value;
+    }
+    /// Default maximumbound
+    inline double defaultBound() const {
+        return defaultBound_;
+    }
+    inline void setDefaultBound(double value) {
+        defaultBound_ = value;
+    }
+    /// Set integer priority
+    inline void setIntegerPriority(int value) {
+        integerPriority_ = value;
+    }
+    /// Get integer priority
+    inline int integerPriority() const {
+        return integerPriority_;
+    }
+    /// Objective transfer variable if one
+    inline int objectiveVariable() const {
+        return objectiveVariable_;
+    }
+    /// Set biLinear priority
+    inline void setBiLinearPriority(int value) {
+        biLinearPriority_ = value;
+    }
+    /// Get biLinear priority
+    inline int biLinearPriority() const {
+        return biLinearPriority_;
+    }
+    /// Return CoinModel
+    inline const CoinModel * coinModel() const {
+        return &coinModel_;
+    }
+    /// Set all biLinear priorities on x-x variables
+    void setBiLinearPriorities(int value, double meshSize = 1.0);
+    /** Set options and priority on all or some biLinear variables
+        1 - on I-I
+        2 - on I-x
+        4 - on x-x
+        or combinations.
+        -1 means leave (for priority value and strategy value)
+    */
+    void setBranchingStrategyOnVariables(int strategyValue, int priorityValue = -1,
+                                         int mode = 7);
+    /// Set all mesh sizes on x-x variables
+    void setMeshSizes(double value);
+    /** Two tier integer problem where when set of variables with priority
+        less than this are fixed the problem becomes an easier integer problem
+    */
+    void setFixedPriority(int priorityValue);
+    //@}
+
+    //---------------------------------------------------------------------------
+
+protected:
+
+
+    /**@name functions */
+    //@{
+    /// Do real work of initialize
+    //void initialize(ClpSimplex * & solver, OsiObject ** & object) const;
+    /// Do real work of delete
+    void gutsOfDestructor(bool justNullify = false);
+    /// Do real work of copy
+    void gutsOfCopy(const OsiSolverLink & rhs) ;
+    //@}
+
+    /**@name Private member data */
+    //@{
+    /** Clean copy of matrix
+        Marked coefficients will be multiplied by L or U
+    */
+    CoinPackedMatrix * matrix_;
+    /** Row copy of matrix
+        Just genuine columns and rows
+    */
+    CoinPackedMatrix * originalRowCopy_;
+    /// Copy of quadratic model if one
+    ClpSimplex * quadraticModel_;
+    /// Number of rows with nonLinearities
+    int numberNonLinearRows_;
+    /// Starts of lists
+    int * startNonLinear_;
+    /// Row number for a list
+    int * rowNonLinear_;
+    /** Indicator whether is convex, concave or neither
+        -1 concave, 0 neither, +1 convex
+    */
+    int * convex_;
+    /// Indices in a list/row
+    int * whichNonLinear_;
+    /// Model in CoinModel format
+    CoinModel coinModel_;
+    /// Number of variables in tightening phase
+    int numberVariables_;
+    /// Information
+    OsiLinkedBound * info_;
+    /**
+       0 bit (1) - call fathom (may do mini B&B)
+       1 bit (2) - quadratic only in objective (add OA cuts)
+       2 bit (4) - convex
+       3 bit (8) - try adding OA cuts
+       4 bit (16) - add linearized constraints
+    */
+    int specialOptions2_;
+    /// Objective transfer row if one
+    int objectiveRow_;
+    /// Objective transfer variable if one
+    int objectiveVariable_;
+    /// Objective value of best solution found internally
+    double bestObjectiveValue_;
+    /// Default mesh
+    double defaultMeshSize_;
+    /// Default maximum bound
+    double defaultBound_;
+    /// Best solution found internally
+    double * bestSolution_;
+    /// Priority for integers
+    int integerPriority_;
+    /// Priority for bilinear
+    int biLinearPriority_;
+    /// Number of variables which when fixed help
+    int numberFix_;
+    /// list of fixed variables
+    int * fixVariables_;
+    //@}
+};
+/**
+   List of bounds which depend on other bounds
+*/
+
+class OsiLinkedBound {
+
+public:
+    //---------------------------------------------------------------------------
+    /**@name Action methods */
+    //@{
+    /// Update other bounds
+    void updateBounds(ClpSimplex * solver);
+    //@}
+
+
+    /**@name Constructors and destructors */
+    //@{
+    /// Default Constructor
+    OsiLinkedBound ();
+    /// Useful Constructor
+    OsiLinkedBound(OsiSolverInterface * model, int variable,
+                   int numberAffected, const int * positionL,
+                   const int * positionU, const double * multiplier);
+
+    /// Copy constructor
+    OsiLinkedBound (const OsiLinkedBound &);
+
+    /// Assignment operator
+    OsiLinkedBound & operator=(const OsiLinkedBound& rhs);
+
+    /// Destructor
+    ~OsiLinkedBound ();
+
+    //@}
+
+    /**@name Sets and Gets */
+    //@{
+    /// Get variable
+    inline int variable() const {
+        return variable_;
+    }
+    /// Add a bound modifier
+    void addBoundModifier(bool upperBoundAffected, bool useUpperBound, int whichVariable,
+                          double multiplier = 1.0);
+    //@}
+
+private:
+    typedef struct {
+        double multiplier; // to use in computation
+        int affected; // variable or element affected
+        /*
+          0 - LB of variable affected
+          1 - UB of variable affected
+          2 - element in position (affected) affected
+        */
+        unsigned char affect;
+        unsigned char ubUsed; // nonzero if UB of this variable is used
+        /*
+           0 - use x*multiplier
+           1 - use multiplier/x
+           2 - if UB use min of current upper and x*multiplier, if LB use max of current lower and x*multiplier
+        */
+        unsigned char type; // type of computation
+    } boundElementAction;
+
+    /**@name Private member data */
+    //@{
+    /// Pointer back to model
+    OsiSolverInterface * model_;
+    /// Variable
+    int variable_;
+    /// Number of variables/elements affected
+    int numberAffected_;
+    /// Maximum number of variables/elements affected
+    int maximumAffected_;
+    /// Actions
+    boundElementAction * affected_;
+    //@}
+};
+#include "CbcHeuristic.hpp"
+/** heuristic - just picks up any good solution
+ */
+
+class CbcHeuristicDynamic3 : public CbcHeuristic {
+public:
+
+    // Default Constructor
+    CbcHeuristicDynamic3 ();
+
+    /* Constructor with model
+     */
+    CbcHeuristicDynamic3 (CbcModel & model);
+
+    // Copy constructor
+    CbcHeuristicDynamic3 ( const CbcHeuristicDynamic3 &);
+
+    // Destructor
+    ~CbcHeuristicDynamic3 ();
+
+    /// Clone
+    virtual CbcHeuristic * clone() const;
+
+    /// update model
+    virtual void setModel(CbcModel * model);
+
+    using CbcHeuristic::solution ;
+    /** returns 0 if no solution, 1 if valid solution.
+        Sets solution values if good, sets objective value (only if good)
+        We leave all variables which are at one at this node of the
+        tree to that value and will
+        initially set all others to zero.  We then sort all variables in order of their cost
+        divided by the number of entries in rows which are not yet covered.  We randomize that
+        value a bit so that ties will be broken in different ways on different runs of the heuristic.
+        We then choose the best one and set it to one and repeat the exercise.
+
+    */
+    virtual int solution(double & objectiveValue,
+                         double * newSolution);
+    /// Resets stuff if model changes
+    virtual void resetModel(CbcModel * model);
+    /// Returns true if can deal with "odd" problems e.g. sos type 2
+    virtual bool canDealWithOdd() const {
+        return true;
+    }
+
+protected:
+private:
+    /// Illegal Assignment operator
+    CbcHeuristicDynamic3 & operator=(const CbcHeuristicDynamic3& rhs);
+};
+
+#include "OsiBranchingObject.hpp"
+
+/** Define Special Linked Ordered Sets.
+
+*/
+class CoinWarmStartBasis;
+
+class OsiOldLink : public OsiSOS {
+
+public:
+
+    // Default Constructor
+    OsiOldLink ();
+
+    /** Useful constructor - A valid solution is if all variables are zero
+        apart from k*numberLink to (k+1)*numberLink-1 where k is 0 through
+        numberInSet-1.  The length of weights array is numberInSet.
+        For this constructor the variables in matrix are the numberInSet*numberLink
+        starting at first. If weights null then 0,1,2..
+    */
+    OsiOldLink (const OsiSolverInterface * solver, int numberMembers,
+                int numberLinks, int first,
+                const double * weights, int setNumber);
+    /** Useful constructor - A valid solution is if all variables are zero
+        apart from k*numberLink to (k+1)*numberLink-1 where k is 0 through
+        numberInSet-1.  The length of weights array is numberInSet.
+        For this constructor the variables are given by list - grouped.
+        If weights null then 0,1,2..
+    */
+    OsiOldLink (const OsiSolverInterface * solver, int numberMembers,
+                int numberLinks, int typeSOS, const int * which,
+                const double * weights, int setNumber);
+
+    // Copy constructor
+    OsiOldLink ( const OsiOldLink &);
+
+    /// Clone
+    virtual OsiObject * clone() const;
+
+    // Assignment operator
+    OsiOldLink & operator=( const OsiOldLink& rhs);
+
+    // Destructor
+    virtual ~OsiOldLink ();
+
+    using OsiObject::infeasibility ;
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info, int & whichWay) const;
+
+    using OsiObject::feasibleRegion ;
+    /** Set bounds to fix the variable at the current (integer) value.
+
+      Given an integer value, set the lower and upper bounds to fix the
+      variable. Returns amount it had to move variable.
+    */
+    virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+    /** Creates a branching object
+
+      The preferred direction is set by \p way, 0 for down, 1 for up.
+    */
+    virtual OsiBranchingObject * createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+
+    /// Redoes data when sequence numbers change
+    virtual void resetSequenceEtc(int numberColumns, const int * originalColumns);
+
+    /// Number of links for each member
+    inline int numberLinks() const {
+        return numberLinks_;
+    }
+
+    /** \brief Return true if object can take part in normal heuristics
+    */
+    virtual bool canDoHeuristics() const {
+        return false;
+    }
+    /** \brief Return true if branch should only bound variables
+    */
+    virtual bool boundBranch() const {
+        return false;
+    }
+
+private:
+    /// data
+
+    /// Number of links
+    int numberLinks_;
+};
+/** Branching object for Linked ordered sets
+
+ */
+class OsiOldLinkBranchingObject : public OsiSOSBranchingObject {
+
+public:
+
+    // Default Constructor
+    OsiOldLinkBranchingObject ();
+
+    // Useful constructor
+    OsiOldLinkBranchingObject (OsiSolverInterface * solver,  const OsiOldLink * originalObject,
+                               int way,
+                               double separator);
+
+    // Copy constructor
+    OsiOldLinkBranchingObject ( const OsiOldLinkBranchingObject &);
+
+    // Assignment operator
+    OsiOldLinkBranchingObject & operator=( const OsiOldLinkBranchingObject& rhs);
+
+    /// Clone
+    virtual OsiBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~OsiOldLinkBranchingObject ();
+
+    using OsiBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch(OsiSolverInterface * solver);
+
+    using OsiBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print(const OsiSolverInterface * solver = NULL);
+private:
+    /// data
+};
+/** Define data for one link
+
+*/
+
+
+class OsiOneLink {
+
+public:
+
+    // Default Constructor
+    OsiOneLink ();
+
+    /** Useful constructor -
+
+    */
+    OsiOneLink (const OsiSolverInterface * solver, int xRow, int xColumn, int xyRow,
+                const char * functionString);
+
+    // Copy constructor
+    OsiOneLink ( const OsiOneLink &);
+
+    // Assignment operator
+    OsiOneLink & operator=( const OsiOneLink& rhs);
+
+    // Destructor
+    virtual ~OsiOneLink ();
+
+    /// data
+
+    /// Row which defines x (if -1 then no x)
+    int xRow_;
+    /// Column which defines x
+    int xColumn_;
+    /// Output row
+    int xyRow;
+    /// Function
+    std::string function_;
+};
+/** Define Special Linked Ordered Sets. New style
+
+    members and weights may be stored in SOS object
+
+    This is for y and x*f(y) and z*g(y) etc
+
+*/
+
+
+class OsiLink : public OsiSOS {
+
+public:
+
+    // Default Constructor
+    OsiLink ();
+
+    /** Useful constructor -
+
+    */
+    OsiLink (const OsiSolverInterface * solver, int yRow,
+             int yColumn, double meshSize);
+
+    // Copy constructor
+    OsiLink ( const OsiLink &);
+
+    /// Clone
+    virtual OsiObject * clone() const;
+
+    // Assignment operator
+    OsiLink & operator=( const OsiLink& rhs);
+
+    // Destructor
+    virtual ~OsiLink ();
+
+    using OsiObject::infeasibility ;
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info, int & whichWay) const;
+
+    using OsiObject::feasibleRegion ;
+    /** Set bounds to fix the variable at the current (integer) value.
+
+      Given an integer value, set the lower and upper bounds to fix the
+      variable. Returns amount it had to move variable.
+    */
+    virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+    /** Creates a branching object
+
+      The preferred direction is set by \p way, 0 for down, 1 for up.
+    */
+    virtual OsiBranchingObject * createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+
+    /// Redoes data when sequence numbers change
+    virtual void resetSequenceEtc(int numberColumns, const int * originalColumns);
+
+    /// Number of links for each member
+    inline int numberLinks() const {
+        return numberLinks_;
+    }
+
+    /** \brief Return true if object can take part in normal heuristics
+    */
+    virtual bool canDoHeuristics() const {
+        return false;
+    }
+    /** \brief Return true if branch should only bound variables
+    */
+    virtual bool boundBranch() const {
+        return false;
+    }
+
+private:
+    /// data
+    /// Current increment for y points
+    double meshSize_;
+    /// Links
+    OsiOneLink * data_;
+    /// Number of links
+    int numberLinks_;
+    /// Row which defines y
+    int yRow_;
+    /// Column which defines y
+    int yColumn_;
+};
+/** Branching object for Linked ordered sets
+
+ */
+class OsiLinkBranchingObject : public OsiTwoWayBranchingObject {
+
+public:
+
+    // Default Constructor
+    OsiLinkBranchingObject ();
+
+    // Useful constructor
+    OsiLinkBranchingObject (OsiSolverInterface * solver,  const OsiLink * originalObject,
+                            int way,
+                            double separator);
+
+    // Copy constructor
+    OsiLinkBranchingObject ( const OsiLinkBranchingObject &);
+
+    // Assignment operator
+    OsiLinkBranchingObject & operator=( const OsiLinkBranchingObject& rhs);
+
+    /// Clone
+    virtual OsiBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~OsiLinkBranchingObject ();
+
+    using OsiBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch(OsiSolverInterface * solver);
+
+    using OsiBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print(const OsiSolverInterface * solver = NULL);
+private:
+    /// data
+};
+/** Define BiLinear objects
+
+    This models x*y where one or both are integer
+
+*/
+
+
+class OsiBiLinear : public OsiObject2 {
+
+public:
+
+    // Default Constructor
+    OsiBiLinear ();
+
+    /** Useful constructor -
+        This Adds in rows and variables to construct valid Linked Ordered Set
+        Adds extra constraints to match other x/y
+        So note not const solver
+    */
+    OsiBiLinear (OsiSolverInterface * solver, int xColumn,
+                 int yColumn, int xyRow, double coefficient,
+                 double xMesh, double yMesh,
+                 int numberExistingObjects = 0, const OsiObject ** objects = NULL );
+
+    /** Useful constructor -
+        This Adds in rows and variables to construct valid Linked Ordered Set
+        Adds extra constraints to match other x/y
+        So note not const model
+    */
+    OsiBiLinear (CoinModel * coinModel, int xColumn,
+                 int yColumn, int xyRow, double coefficient,
+                 double xMesh, double yMesh,
+                 int numberExistingObjects = 0, const OsiObject ** objects = NULL );
+
+    // Copy constructor
+    OsiBiLinear ( const OsiBiLinear &);
+
+    /// Clone
+    virtual OsiObject * clone() const;
+
+    // Assignment operator
+    OsiBiLinear & operator=( const OsiBiLinear& rhs);
+
+    // Destructor
+    virtual ~OsiBiLinear ();
+
+    using OsiObject::infeasibility ;
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info, int & whichWay) const;
+
+    using OsiObject::feasibleRegion ;
+    /** Set bounds to fix the variable at the current (integer) value.
+
+      Given an integer value, set the lower and upper bounds to fix the
+      variable. Returns amount it had to move variable.
+    */
+    virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+    /** Creates a branching object
+
+      The preferred direction is set by \p way, 0 for down, 1 for up.
+    */
+    virtual OsiBranchingObject * createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+
+    /// Redoes data when sequence numbers change
+    virtual void resetSequenceEtc(int numberColumns, const int * originalColumns);
+
+    // This does NOT set mutable stuff
+    virtual double checkInfeasibility(const OsiBranchingInformation * info) const;
+
+    /** \brief Return true if object can take part in normal heuristics
+    */
+    virtual bool canDoHeuristics() const {
+        return false;
+    }
+    /** \brief Return true if branch should only bound variables
+    */
+    virtual bool boundBranch() const {
+        return (branchingStrategy_&4) != 0;
+    }
+    /// X column
+    inline int xColumn() const {
+        return xColumn_;
+    }
+    /// Y column
+    inline int yColumn() const {
+        return yColumn_;
+    }
+    /// X row
+    inline int xRow() const {
+        return xRow_;
+    }
+    /// Y row
+    inline int yRow() const {
+        return yRow_;
+    }
+    /// XY row
+    inline int xyRow() const {
+        return xyRow_;
+    }
+    /// Coefficient
+    inline double coefficient() const {
+        return coefficient_;
+    }
+    /// Set coefficient
+    inline void setCoefficient(double value) {
+        coefficient_ = value;
+    }
+    /// First lambda (of 4)
+    inline int firstLambda() const {
+        return firstLambda_;
+    }
+    /// X satisfied if less than this away from mesh
+    inline double xSatisfied() const {
+        return xSatisfied_;
+    }
+    inline void setXSatisfied(double value) {
+        xSatisfied_ = value;
+    }
+    /// Y satisfied if less than this away from mesh
+    inline double ySatisfied() const {
+        return ySatisfied_;
+    }
+    inline void setYSatisfied(double value) {
+        ySatisfied_ = value;
+    }
+    /// X other satisfied if less than this away from mesh
+    inline double xOtherSatisfied() const {
+        return xOtherSatisfied_;
+    }
+    inline void setXOtherSatisfied(double value) {
+        xOtherSatisfied_ = value;
+    }
+    /// Y other satisfied if less than this away from mesh
+    inline double yOtherSatisfied() const {
+        return yOtherSatisfied_;
+    }
+    inline void setYOtherSatisfied(double value) {
+        yOtherSatisfied_ = value;
+    }
+    /// X meshSize
+    inline double xMeshSize() const {
+        return xMeshSize_;
+    }
+    inline void setXMeshSize(double value) {
+        xMeshSize_ = value;
+    }
+    /// Y meshSize
+    inline double yMeshSize() const {
+        return yMeshSize_;
+    }
+    inline void setYMeshSize(double value) {
+        yMeshSize_ = value;
+    }
+    /// XY satisfied if two version differ by less than this
+    inline double xySatisfied() const {
+        return xySatisfied_;
+    }
+    inline void setXYSatisfied(double value) {
+        xySatisfied_ = value;
+    }
+    /// Set sizes and other stuff
+    void setMeshSizes(const OsiSolverInterface * solver, double x, double y);
+    /** branching strategy etc
+        bottom 2 bits
+        0 branch on either, 1 branch on x, 2 branch on y
+        next bit
+        4 set to say don't update coefficients
+        next bit
+        8 set to say don't use in feasible region
+        next bit
+        16 set to say - Always satisfied !!
+    */
+    inline int branchingStrategy() const {
+        return branchingStrategy_;
+    }
+    inline void setBranchingStrategy(int value) {
+        branchingStrategy_ = value;
+    }
+    /** Simple quadratic bound marker.
+        0 no
+        1 L if coefficient pos, G if negative i.e. value is ub on xy
+        2 G if coefficient pos, L if negative i.e. value is lb on xy
+        3 E
+        If bound then real coefficient is 1.0 and coefficient_ is bound
+    */
+    inline int boundType() const {
+        return boundType_;
+    }
+    inline void setBoundType(int value) {
+        boundType_ = value;
+    }
+    /// Does work of branching
+    void newBounds(OsiSolverInterface * solver, int way, short xOrY, double separator) const;
+    /// Updates coefficients - returns number updated
+    int updateCoefficients(const double * lower, const double * upper, double * objective,
+                           CoinPackedMatrix * matrix, CoinWarmStartBasis * basis) const;
+    /// Returns true value of single xyRow coefficient
+    double xyCoefficient(const double * solution) const;
+    /// Get LU coefficients from matrix
+    void getCoefficients(const OsiSolverInterface * solver, double xB[2], double yB[2], double xybar[4]) const;
+    /// Compute lambdas (third entry in each .B is current value) (nonzero if bad)
+    double computeLambdas(const double xB[3], const double yB[3], const double xybar[4], double lambda[4]) const;
+    /// Adds in data for extra row with variable coefficients
+    void addExtraRow(int row, double multiplier);
+    /// Sets infeasibility and other when pseudo shadow prices
+    void getPseudoShadow(const OsiBranchingInformation * info);
+    /// Gets sum of movements to correct value
+    double getMovement(const OsiBranchingInformation * info);
+
+protected:
+    /// Compute lambdas if coefficients not changing
+    void computeLambdas(const OsiSolverInterface * solver, double lambda[4]) const;
+    /// data
+
+    /// Coefficient
+    double coefficient_;
+    /// x mesh
+    double xMeshSize_;
+    /// y mesh
+    double yMeshSize_;
+    /// x satisfied if less than this away from mesh
+    double xSatisfied_;
+    /// y satisfied if less than this away from mesh
+    double ySatisfied_;
+    /// X other satisfied if less than this away from mesh
+    double xOtherSatisfied_;
+    /// Y other satisfied if less than this away from mesh
+    double yOtherSatisfied_;
+    /// xy satisfied if less than this away from true
+    double xySatisfied_;
+    /// value of x or y to branch about
+    mutable double xyBranchValue_;
+    /// x column
+    int xColumn_;
+    /// y column
+    int yColumn_;
+    /// First lambda (of 4)
+    int firstLambda_;
+    /** branching strategy etc
+        bottom 2 bits
+        0 branch on either, 1 branch on x, 2 branch on y
+        next bit
+        4 set to say don't update coefficients
+        next bit
+        8 set to say don't use in feasible region
+        next bit
+        16 set to say - Always satisfied !!
+    */
+    int branchingStrategy_;
+    /** Simple quadratic bound marker.
+        0 no
+        1 L if coefficient pos, G if negative i.e. value is ub on xy
+        2 G if coefficient pos, L if negative i.e. value is lb on xy
+        3 E
+        If bound then real coefficient is 1.0 and coefficient_ is bound
+    */
+    int boundType_;
+    /// x row
+    int xRow_;
+    /// y row (-1 if x*x)
+    int yRow_;
+    /// Output row
+    int xyRow_;
+    /// Convexity row
+    int convexity_;
+    /// Number of extra rows (coefficients to be modified)
+    int numberExtraRows_;
+    /// Multiplier for coefficient on row
+    double * multiplier_;
+    /// Row number
+    int * extraRow_;
+    /// Which chosen -1 none, 0 x, 1 y
+    mutable short chosen_;
+};
+/** Branching object for BiLinear objects
+
+ */
+class OsiBiLinearBranchingObject : public OsiTwoWayBranchingObject {
+
+public:
+
+    // Default Constructor
+    OsiBiLinearBranchingObject ();
+
+    // Useful constructor
+    OsiBiLinearBranchingObject (OsiSolverInterface * solver,  const OsiBiLinear * originalObject,
+                                int way,
+                                double separator, int chosen);
+
+    // Copy constructor
+    OsiBiLinearBranchingObject ( const OsiBiLinearBranchingObject &);
+
+    // Assignment operator
+    OsiBiLinearBranchingObject & operator=( const OsiBiLinearBranchingObject& rhs);
+
+    /// Clone
+    virtual OsiBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~OsiBiLinearBranchingObject ();
+
+    using OsiBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch(OsiSolverInterface * solver);
+
+    using OsiBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print(const OsiSolverInterface * solver = NULL);
+    /** \brief Return true if branch should only bound variables
+    */
+    virtual bool boundBranch() const;
+private:
+    /// data
+    /// 1 means branch on x, 2 branch on y
+    short chosen_;
+};
+/** Define Continuous BiLinear objects for an == bound
+
+    This models x*y = b where both are continuous
+
+*/
+
+
+class OsiBiLinearEquality : public OsiBiLinear {
+
+public:
+
+    // Default Constructor
+    OsiBiLinearEquality ();
+
+    /** Useful constructor -
+        This Adds in rows and variables to construct Ordered Set
+        for x*y = b
+        So note not const solver
+    */
+    OsiBiLinearEquality (OsiSolverInterface * solver, int xColumn,
+                         int yColumn, int xyRow, double rhs,
+                         double xMesh);
+
+    // Copy constructor
+    OsiBiLinearEquality ( const OsiBiLinearEquality &);
+
+    /// Clone
+    virtual OsiObject * clone() const;
+
+    // Assignment operator
+    OsiBiLinearEquality & operator=( const OsiBiLinearEquality& rhs);
+
+    // Destructor
+    virtual ~OsiBiLinearEquality ();
+
+    /// Possible improvement
+    virtual double improvement(const OsiSolverInterface * solver) const;
+    /** change grid
+        if type 0 then use solution and make finer
+        if 1 then back to original
+        returns mesh size
+    */
+    double newGrid(OsiSolverInterface * solver, int type) const;
+    /// Number of points
+    inline int numberPoints() const {
+        return numberPoints_;
+    }
+    inline void setNumberPoints(int value) {
+        numberPoints_ = value;
+    }
+
+private:
+    /// Number of points
+    int numberPoints_;
+};
+/// Define a single integer class - but one where you keep branching until fixed even if satisfied
+
+
+class OsiSimpleFixedInteger : public OsiSimpleInteger {
+
+public:
+
+    /// Default Constructor
+    OsiSimpleFixedInteger ();
+
+    /// Useful constructor - passed solver index
+    OsiSimpleFixedInteger (const OsiSolverInterface * solver, int iColumn);
+
+    /// Useful constructor - passed solver index and original bounds
+    OsiSimpleFixedInteger (int iColumn, double lower, double upper);
+
+    /// Useful constructor - passed simple integer
+    OsiSimpleFixedInteger (const OsiSimpleInteger &);
+
+    /// Copy constructor
+    OsiSimpleFixedInteger ( const OsiSimpleFixedInteger &);
+
+    /// Clone
+    virtual OsiObject * clone() const;
+
+    /// Assignment operator
+    OsiSimpleFixedInteger & operator=( const OsiSimpleFixedInteger& rhs);
+
+    /// Destructor
+    virtual ~OsiSimpleFixedInteger ();
+
+    using OsiObject::infeasibility ;
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info, int & whichWay) const;
+
+    /** Creates a branching object
+
+      The preferred direction is set by \p way, 0 for down, 1 for up.
+    */
+    virtual OsiBranchingObject * createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+protected:
+    /// data
+
+};
+/** Define a single variable class which is involved with OsiBiLinear objects.
+    This is used so can make better decision on where to branch as it can look at
+    all objects.
+
+    This version sees if it can re-use code from OsiSimpleInteger
+    even if not an integer variable.  If not then need to duplicate code.
+*/
+
+
+class OsiUsesBiLinear : public OsiSimpleInteger {
+
+public:
+
+    /// Default Constructor
+    OsiUsesBiLinear ();
+
+    /// Useful constructor - passed solver index
+    OsiUsesBiLinear (const OsiSolverInterface * solver, int iColumn, int type);
+
+    /// Useful constructor - passed solver index and original bounds
+    OsiUsesBiLinear (int iColumn, double lower, double upper, int type);
+
+    /// Useful constructor - passed simple integer
+    OsiUsesBiLinear (const OsiSimpleInteger & rhs, int type);
+
+    /// Copy constructor
+    OsiUsesBiLinear ( const OsiUsesBiLinear & rhs);
+
+    /// Clone
+    virtual OsiObject * clone() const;
+
+    /// Assignment operator
+    OsiUsesBiLinear & operator=( const OsiUsesBiLinear& rhs);
+
+    /// Destructor
+    virtual ~OsiUsesBiLinear ();
+
+    using OsiObject::infeasibility ;
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info, int & whichWay) const;
+
+    /** Creates a branching object
+
+      The preferred direction is set by \p way, 0 for down, 1 for up.
+    */
+    virtual OsiBranchingObject * createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+
+    using OsiObject::feasibleRegion ;
+    /** Set bounds to fix the variable at the current value.
+
+      Given an current value, set the lower and upper bounds to fix the
+      variable. Returns amount it had to move variable.
+    */
+    virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+    /// Add all bi-linear objects
+    void addBiLinearObjects(OsiSolverLink * solver);
+protected:
+    /// data
+    /// Number of bilinear objects (maybe could be more general)
+    int numberBiLinear_;
+    /// Type of variable - 0 continuous, 1 integer
+    int type_;
+    /// Objects
+    OsiObject ** objects_;
+};
+/** This class chooses a variable to branch on
+
+    This is just as OsiChooseStrong but it fakes it so only
+    first so many are looked at in this phase
+
+*/
+
+class OsiChooseStrongSubset  : public OsiChooseStrong {
+
+public:
+
+    /// Default Constructor
+    OsiChooseStrongSubset ();
+
+    /// Constructor from solver (so we can set up arrays etc)
+    OsiChooseStrongSubset (const OsiSolverInterface * solver);
+
+    /// Copy constructor
+    OsiChooseStrongSubset (const OsiChooseStrongSubset &);
+
+    /// Assignment operator
+    OsiChooseStrongSubset & operator= (const OsiChooseStrongSubset& rhs);
+
+    /// Clone
+    virtual OsiChooseVariable * clone() const;
+
+    /// Destructor
+    virtual ~OsiChooseStrongSubset ();
+
+    /** Sets up strong list and clears all if initialize is true.
+        Returns number of infeasibilities.
+        If returns -1 then has worked out node is infeasible!
+    */
+    virtual int setupList ( OsiBranchingInformation *info, bool initialize);
+    /** Choose a variable
+        Returns -
+       -1 Node is infeasible
+       0  Normal termination - we have a candidate
+       1  All looks satisfied - no candidate
+       2  We can change the bound on a variable - but we also have a strong branching candidate
+       3  We can change the bound on a variable - but we have a non-strong branching candidate
+       4  We can change the bound on a variable - no other candidates
+       We can pick up branch from bestObjectIndex() and bestWhichWay()
+       We can pick up a forced branch (can change bound) from firstForcedObjectIndex() and firstForcedWhichWay()
+       If we have a solution then we can pick up from goodObjectiveValue() and goodSolution()
+       If fixVariables is true then 2,3,4 are all really same as problem changed
+    */
+    virtual int chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *info, bool fixVariables);
+
+    /// Number of objects to use
+    inline int numberObjectsToUse() const {
+        return numberObjectsToUse_;
+    }
+    /// Set number of objects to use
+    inline void setNumberObjectsToUse(int value) {
+        numberObjectsToUse_ = value;
+    }
+
+protected:
+    // Data
+    /// Number of objects to be used (and set in solver)
+    int numberObjectsToUse_;
+};
+
+#include <string>
+
+#include "CglStored.hpp"
+
+class CoinWarmStartBasis;
+/** Stored Temporary Cut Generator Class - destroyed after first use */
+class CglTemporary : public CglStored {
+
+public:
+
+
+    /**@name Generate Cuts */
+    //@{
+    /** Generate Mixed Integer Stored cuts for the model of the
+        solver interface, si.
+
+        Insert the generated cuts into OsiCut, cs.
+
+        This generator just looks at previously stored cuts
+        and inserts any that are violated by enough
+    */
+    virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+                               const CglTreeInfo info = CglTreeInfo());
+    //@}
+
+    /**@name Constructors and destructors */
+    //@{
+    /// Default constructor
+    CglTemporary ();
+
+    /// Copy constructor
+    CglTemporary (const CglTemporary & rhs);
+
+    /// Clone
+    virtual CglCutGenerator * clone() const;
+
+    /// Assignment operator
+    CglTemporary &
+    operator=(const CglTemporary& rhs);
+
+    /// Destructor
+    virtual
+    ~CglTemporary ();
+    //@}
+
+private:
+
+// Private member methods
+
+    // Private member data
+};
+//#############################################################################
+
+/**
+
+This is to allow the user to replace initialSolve and resolve
+*/
+
+class OsiSolverLinearizedQuadratic : public OsiClpSolverInterface {
+
+public:
+    //---------------------------------------------------------------------------
+    /**@name Solve methods */
+    //@{
+    /// Solve initial LP relaxation
+    virtual void initialSolve();
+    //@}
+
+
+    /**@name Constructors and destructors */
+    //@{
+    /// Default Constructor
+    OsiSolverLinearizedQuadratic ();
+    /// Useful constructor (solution should be good)
+    OsiSolverLinearizedQuadratic(  ClpSimplex * quadraticModel);
+    /// Clone
+    virtual OsiSolverInterface * clone(bool copyData = true) const;
+
+    /// Copy constructor
+    OsiSolverLinearizedQuadratic (const OsiSolverLinearizedQuadratic &);
+
+    /// Assignment operator
+    OsiSolverLinearizedQuadratic & operator=(const OsiSolverLinearizedQuadratic& rhs);
+
+    /// Destructor
+    virtual ~OsiSolverLinearizedQuadratic ();
+
+    //@}
+
+
+    /**@name Sets and Gets */
+    //@{
+    /// Objective value of best solution found internally
+    inline double bestObjectiveValue() const {
+        return bestObjectiveValue_;
+    }
+    /// Best solution found internally
+    const double * bestSolution() const {
+        return bestSolution_;
+    }
+    /// Set special options
+    inline void setSpecialOptions3(int value) {
+        specialOptions3_ = value;
+    }
+    /// Get special options
+    inline int specialOptions3() const {
+        return specialOptions3_;
+    }
+    /// Copy of quadratic model if one
+    ClpSimplex * quadraticModel() const {
+        return quadraticModel_;
+    }
+    //@}
+
+    //---------------------------------------------------------------------------
+
+protected:
+
+
+    /**@name functions */
+    //@{
+
+    /**@name Private member data */
+    //@{
+    /// Objective value of best solution found internally
+    double bestObjectiveValue_;
+    /// Copy of quadratic model if one
+    ClpSimplex * quadraticModel_;
+    /// Best solution found internally
+    double * bestSolution_;
+    /**
+       0 bit (1) - don't do mini B&B
+       1 bit (2) - quadratic only in objective
+    */
+    int specialOptions3_;
+    //@}
+};
+class ClpSimplex;
+/** Return an approximate solution to a CoinModel.
+    Lots of bounds may be odd to force a solution.
+    mode = 0 just tries to get a continuous solution
+*/
+ClpSimplex * approximateSolution(CoinModel & coinModel,
+                                 int numberPasses, double deltaTolerance,
+                                 int mode = 0);
+#endif
+
diff --git a/cbits/coin/CbcLinkedUtils.cpp b/cbits/coin/CbcLinkedUtils.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcLinkedUtils.cpp
@@ -0,0 +1,832 @@
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/* $Id: CbcLinkedUtils.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+
+/*! \file CbcAugmentClpSimplex.cpp
+    \brief Hooks to Ampl (for CbcLinked)
+
+    This code is a condensation of ClpAmplStuff.cpp, renamed to better
+    reflect its current place in cbc.
+
+  The code here had ties to NEW_STYLE_SOLVER code. During the 091209 Watson
+  meeting, NEW_STYLE_SOLVER code was eliminated. The code here was condensed
+  from ClpAmplStuff.cpp. The hook into CbcLinked is loadNonLinear. Once you
+  bring that in, all the rest follows. Still, we're down about 400 lines of
+  code. In the process, it appears that ClpAmplObjective.cpp was never needed
+  here; the code was hooked into ClpAmplStuff.cpp.  --lh, 091209 --
+*/
+
+#include "ClpConfig.h"
+#include "CbcConfig.h"
+#ifdef COIN_HAS_ASL
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpAmplObjective.hpp"
+#include "ClpConstraintAmpl.hpp"
+#include "ClpMessage.hpp"
+#include "CoinUtilsConfig.h"
+#include "CoinHelperFunctions.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "OsiSolverInterface.hpp"
+#include "Cbc_ampl.h"
+#include "CoinTime.hpp"
+#include "CglStored.hpp"
+#include "CoinModel.hpp"
+#include "CbcLinked.hpp"
+
+extern "C" {
+    //# include "getstub.h"
+# include "asl_pfgh.h"
+}
+
+// stolen from IPopt with changes
+typedef struct {
+    double obj_sign_;
+    ASL_pfgh * asl_;
+    double * non_const_x_;
+    int * column_; // for jacobian
+    int * rowStart_;
+    double * gradient_;
+    double * constraintValues_;
+    int nz_h_full_; // number of nonzeros in hessian
+    int nerror_;
+    bool objval_called_with_current_x_;
+    bool conval_called_with_current_x_;
+    bool jacval_called_with_current_x_;
+} CbcAmplInfo;
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpAmplObjective::ClpAmplObjective ()
+        : ClpObjective()
+{
+    type_ = 12;
+    objective_ = NULL;
+    amplObjective_ = NULL;
+    gradient_ = NULL;
+    offset_ = 0.0;
+}
+
+bool get_constraints_linearity(void * amplInfo, int  n,
+                               int * const_types)
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo;
+    ASL_pfgh* asl = info->asl_;
+    //check that n is good
+    assert(n == n_con);
+    // check that there are no network constraints
+    assert(nlnc == 0 && lnc == 0);
+    //the first nlc constraints are non linear the rest is linear
+    int i;
+    for (i = 0; i < nlc; i++) {
+        const_types[i] = 1;
+    }
+    // the rest is linear
+    for (i = nlc; i < n_con; i++)
+        const_types[i] = 0;
+    return true;
+}
+static bool internal_objval(CbcAmplInfo * info , double & obj_val)
+{
+    ASL_pfgh* asl = info->asl_;
+    info->objval_called_with_current_x_ = false; // in case the call below fails
+
+    if (n_obj == 0) {
+        obj_val = 0;
+        info->objval_called_with_current_x_ = true;
+        return true;
+    }  else {
+        double  retval = objval(0, info->non_const_x_, (fint*)&info->nerror_);
+        if (!info->nerror_) {
+            obj_val = info->obj_sign_ * retval;
+            info->objval_called_with_current_x_ = true;
+            return true;
+        } else {
+            abort();
+        }
+    }
+
+    return false;
+}
+
+static bool internal_conval(CbcAmplInfo * info , double * g)
+{
+    ASL_pfgh* asl = info->asl_;
+    info->conval_called_with_current_x_ = false; // in case the call below fails
+    assert (g);
+
+    conval(info->non_const_x_, g, (fint*)&info->nerror_);
+
+    if (!info->nerror_) {
+        info->conval_called_with_current_x_ = true;
+        return true;
+    } else {
+        abort();
+    }
+    return false;
+}
+
+static bool apply_new_x(CbcAmplInfo * info  , bool new_x, int  n, const double * x)
+{
+    ASL_pfgh* asl = info->asl_;
+
+    if (new_x) {
+        // update the flags so these methods are called
+        // before evaluating the hessian
+        info->conval_called_with_current_x_ = false;
+        info->objval_called_with_current_x_ = false;
+        info->jacval_called_with_current_x_ = false;
+
+        //copy the data to the non_const_x_
+        if (!info->non_const_x_) {
+            info->non_const_x_ = new double [n];
+        }
+
+        for (int  i = 0; i < n; i++) {
+            info->non_const_x_[i] = x[i];
+        }
+
+        // tell ampl that we have a new x
+        xknowne(info->non_const_x_, (fint*)&info->nerror_);
+        return info->nerror_ ? false : true;
+    }
+
+    return true;
+}
+
+static bool eval_f(void * amplInfo, int  n, const double * x, bool new_x, double & obj_value)
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo;
+    if (!apply_new_x(info, new_x, n, x)) {
+        return false;
+    }
+
+    return internal_objval(info, obj_value);
+}
+
+static bool eval_grad_f(void * amplInfo, int  n, const double * x, bool new_x, double * grad_f)
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo;
+    ASL_pfgh* asl = info->asl_;
+    if (!apply_new_x(info, new_x, n, x)) {
+        return false;
+    }
+    int i;
+
+    if (n_obj == 0) {
+        for (i = 0; i < n; i++) {
+            grad_f[i] = 0.;
+        }
+    } else {
+        objgrd(0, info->non_const_x_, grad_f, (fint*)&info->nerror_);
+        if (info->nerror_) {
+            return false;
+        }
+
+        if (info->obj_sign_ == -1) {
+            for (i = 0; i < n; i++) {
+                grad_f[i] = -grad_f[i];
+            }
+        }
+    }
+    return true;
+}
+
+static bool eval_g(void * amplInfo, int  n, const double * x, bool new_x, double * g)
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo;
+#ifndef NDEBUG
+    ASL_pfgh* asl = info->asl_;
+#endif
+    // warning: n_var is a macro that assumes we have a variable called asl
+    assert(n == n_var);
+
+    if (!apply_new_x(info, new_x, n, x)) {
+        return false;
+    }
+
+    return internal_conval(info, g);
+}
+
+static bool eval_jac_g(void * amplInfo, int  n, const double * x, bool new_x,
+                       double * values)
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo;
+    ASL_pfgh* asl = info->asl_;
+    assert(n == n_var);
+
+    assert (values);
+    if (!apply_new_x(info, new_x, n, x)) {
+        return false;
+    }
+
+    jacval(info->non_const_x_, values, (fint*)&info->nerror_);
+    if (!info->nerror_) {
+        return true;
+    } else {
+        abort();
+    }
+    return false;
+}
+//-------------------------------------------------------------------
+// Useful Constructor
+//-------------------------------------------------------------------
+ClpAmplObjective::ClpAmplObjective (void * amplInfo)
+        : ClpObjective()
+{
+    type_ = 12;
+    activated_ = 1;
+    gradient_ = NULL;
+    objective_ = NULL;
+    offset_ = 0.0;
+    amplObjective_ = amplInfo;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpAmplObjective::ClpAmplObjective (const ClpAmplObjective & rhs)
+        : ClpObjective(rhs)
+{
+    amplObjective_ = rhs.amplObjective_;
+    offset_ = rhs.offset_;
+    type_ = rhs.type_;
+    if (!amplObjective_) {
+        objective_ = NULL;
+        gradient_ = NULL;
+    } else {
+        CbcAmplInfo * info = (CbcAmplInfo *) amplObjective_;
+        ASL_pfgh* asl = info->asl_;
+
+        int numberColumns = n_var;;
+        if (rhs.objective_) {
+            objective_ = new double [numberColumns];
+            memcpy(objective_, rhs.objective_, numberColumns*sizeof(double));
+        } else {
+            objective_ = NULL;
+        }
+        if (rhs.gradient_) {
+            gradient_ = new double [numberColumns];
+            memcpy(gradient_, rhs.gradient_, numberColumns*sizeof(double));
+        } else {
+            gradient_ = NULL;
+        }
+    }
+}
+
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpAmplObjective::~ClpAmplObjective ()
+{
+    delete [] objective_;
+    delete [] gradient_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpAmplObjective &
+ClpAmplObjective::operator=(const ClpAmplObjective & rhs)
+{
+    if (this != &rhs) {
+        delete [] objective_;
+        delete [] gradient_;
+        amplObjective_ = rhs.amplObjective_;
+        offset_ = rhs.offset_;
+        type_ = rhs.type_;
+        if (!amplObjective_) {
+            objective_ = NULL;
+            gradient_ = NULL;
+        } else {
+            CbcAmplInfo * info = (CbcAmplInfo *) amplObjective_;
+            ASL_pfgh* asl = info->asl_;
+
+            int numberColumns = n_var;;
+            if (rhs.objective_) {
+                objective_ = new double [numberColumns];
+                memcpy(objective_, rhs.objective_, numberColumns*sizeof(double));
+            } else {
+                objective_ = NULL;
+            }
+            if (rhs.gradient_) {
+                gradient_ = new double [numberColumns];
+                memcpy(gradient_, rhs.gradient_, numberColumns*sizeof(double));
+            } else {
+                gradient_ = NULL;
+            }
+        }
+    }
+    return *this;
+}
+
+// Returns gradient
+double *
+ClpAmplObjective::gradient(const ClpSimplex * model,
+                           const double * solution, double & offset, bool refresh,
+                           int includeLinear)
+{
+    if (model)
+        assert (model->optimizationDirection() == 1.0);
+#ifndef NDEBUG
+    bool scaling = model && (model->rowScale() || model->objectiveScale() != 1.0 || model->optimizationDirection() != 1.0);
+#endif
+    const double * cost = NULL;
+    if (model)
+        cost = model->costRegion();
+    if (!cost) {
+        // not in solve
+        cost = objective_;
+#ifndef NDEBUG
+        scaling = false;
+#endif
+    }
+    assert (!scaling);
+    if (!amplObjective_ || !solution || !activated_) {
+        offset = offset_;
+        return objective_;
+    } else {
+        if (refresh || !gradient_) {
+            CbcAmplInfo * info = (CbcAmplInfo *) amplObjective_;
+            ASL_pfgh* asl = info->asl_;
+            int numberColumns = n_var;;
+
+            if (!gradient_)
+                gradient_ = new double[numberColumns];
+            assert (solution);
+            eval_grad_f(amplObjective_, numberColumns, solution, true, gradient_);
+            // Is this best way?
+            double objValue = 0.0;
+            eval_f(amplObjective_, numberColumns, solution, false, objValue);
+            double objValue2 = 0.0;
+            for (int i = 0; i < numberColumns; i++)
+                objValue2 += gradient_[i] * solution[i];
+            offset_ = objValue2 - objValue; // or other way???
+            if (model && model->optimizationDirection() != 1.0) {
+                offset *= model->optimizationDirection();
+                for (int i = 0; i < numberColumns; i++)
+                    gradient_[i] *= -1.0;
+            }
+        }
+        offset = offset_;
+        return gradient_;
+    }
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpObjective * ClpAmplObjective::clone() const
+{
+    return new ClpAmplObjective(*this);
+}
+// Resize objective
+void
+ClpAmplObjective::resize(int newNumberColumns)
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplObjective_;
+    ASL_pfgh* asl = info->asl_;
+    int numberColumns = n_var;;
+    if (numberColumns != newNumberColumns) {
+        abort();
+    }
+
+}
+// Delete columns in  objective
+void
+ClpAmplObjective::deleteSome(int numberToDelete, const int * which)
+{
+    if (numberToDelete)
+        abort();
+}
+/* Returns reduced gradient.Returns an offset (to be added to current one).
+ */
+double
+ClpAmplObjective::reducedGradient(ClpSimplex * model, double * region,
+                                  bool useFeasibleCosts)
+{
+    int numberRows = model->numberRows();
+    int numberColumns = model->numberColumns();
+
+    //work space
+    CoinIndexedVector  * workSpace = model->rowArray(0);
+
+    CoinIndexedVector arrayVector;
+    arrayVector.reserve(numberRows + 1);
+
+    int iRow;
+#ifdef CLP_DEBUG
+    workSpace->checkClear();
+#endif
+    double * array = arrayVector.denseVector();
+    int * index = arrayVector.getIndices();
+    int number = 0;
+    const double * costNow = gradient(model, model->solutionRegion(), offset_,
+                                      true, useFeasibleCosts ? 2 : 1);
+    double * cost = model->costRegion();
+    const int * pivotVariable = model->pivotVariable();
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        int iPivot = pivotVariable[iRow];
+        double value;
+        if (iPivot < numberColumns)
+            value = costNow[iPivot];
+        else if (!useFeasibleCosts)
+            value = cost[iPivot];
+        else
+            value = 0.0;
+        if (value) {
+            array[iRow] = value;
+            index[number++] = iRow;
+        }
+    }
+    arrayVector.setNumElements(number);
+
+    // Btran basic costs
+    model->factorization()->updateColumnTranspose(workSpace, &arrayVector);
+    double * work = workSpace->denseVector();
+    ClpFillN(work, numberRows, 0.0);
+    // now look at dual solution
+    double * rowReducedCost = region + numberColumns;
+    double * dual = rowReducedCost;
+    const double * rowCost = cost + numberColumns;
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        dual[iRow] = array[iRow];
+    }
+    double * dj = region;
+    ClpDisjointCopyN(costNow, numberColumns, dj);
+
+    model->transposeTimes(-1.0, dual, dj);
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        // slack
+        double value = dual[iRow];
+        value += rowCost[iRow];
+        rowReducedCost[iRow] = value;
+    }
+    return offset_;
+}
+/* Returns step length which gives minimum of objective for
+   solution + theta * change vector up to maximum theta.
+
+   arrays are numberColumns+numberRows
+*/
+double
+ClpAmplObjective::stepLength(ClpSimplex * model,
+                             const double * solution,
+                             const double * change,
+                             double maximumTheta,
+                             double & currentObj,
+                             double & predictedObj,
+                             double & thetaObj)
+{
+    // Assume convex
+    CbcAmplInfo * info = (CbcAmplInfo *) amplObjective_;
+    ASL_pfgh* asl = info->asl_;
+
+    int numberColumns = n_var;;
+    double * tempSolution = new double [numberColumns];
+    double * tempGradient = new double [numberColumns];
+    // current
+    eval_f(amplObjective_, numberColumns, solution, true, currentObj);
+    double objA = currentObj;
+    double thetaA = 0.0;
+    // at maximum
+    int i;
+    for (i = 0; i < numberColumns; i++)
+        tempSolution[i] = solution[i] + maximumTheta * change[i];
+    eval_f(amplObjective_, numberColumns, tempSolution, true, thetaObj);
+    double objC = thetaObj;
+    double thetaC = maximumTheta;
+    double objB = 0.5 * (objA + objC);
+    double thetaB = 0.5 * maximumTheta;
+    double gradientNorm = 1.0e6;
+    while (gradientNorm > 1.0e-6 && thetaC - thetaA > 1.0e-8) {
+        for (i = 0; i < numberColumns; i++)
+            tempSolution[i] = solution[i] + thetaB * change[i];
+        eval_grad_f(amplObjective_, numberColumns, tempSolution, true, tempGradient);
+        eval_f(amplObjective_, numberColumns, tempSolution, false, objB);
+        double changeObj = 0.0;
+        gradientNorm = 0.0;
+        for (i = 0; i < numberColumns; i++) {
+            changeObj += tempGradient[i] * change[i];
+            gradientNorm += tempGradient[i] * tempGradient[i];
+        }
+        gradientNorm = fabs(changeObj) / sqrt(gradientNorm);
+        // Should try and get quadratic convergence by interpolation
+        if (changeObj < 0.0) {
+            // increasing is good
+            thetaA = thetaB;
+        } else {
+            // decreasing is good
+            thetaC = thetaB;
+        }
+        thetaB = 0.5 * (thetaA + thetaC);
+    }
+    delete [] tempSolution;
+    delete [] tempGradient;
+    predictedObj = objB;
+    return thetaB;
+}
+// Return objective value (without any ClpModel offset) (model may be NULL)
+double
+ClpAmplObjective::objectiveValue(const ClpSimplex * model, const double * solution) const
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplObjective_;
+    ASL_pfgh* asl = info->asl_;
+
+    int numberColumns = n_var;;
+    // current
+    double currentObj = 0.0;
+    eval_f(amplObjective_, numberColumns, solution, true, currentObj);
+    return currentObj;
+}
+// Scale objective
+void
+ClpAmplObjective::reallyScale(const double * columnScale)
+{
+    abort();
+}
+/* Given a zeroed array sets nonlinear columns to 1.
+   Returns number of nonlinear columns
+*/
+int
+ClpAmplObjective::markNonlinear(char * which)
+{
+    int iColumn;
+    CbcAmplInfo * info = (CbcAmplInfo *) amplObjective_;
+    ASL_pfgh* asl = info->asl_;
+    int nonLinear = CoinMax(nlvc, nlvo);
+    for (iColumn = 0; iColumn < nonLinear; iColumn++) {
+        which[iColumn] = 1;
+    }
+    int numberNonLinearColumns = 0;
+    int numberColumns = n_var;;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        if (which[iColumn])
+            numberNonLinearColumns++;
+    }
+    return numberNonLinearColumns;
+}
+// Say we have new primal solution - so may need to recompute
+void
+ClpAmplObjective::newXValues()
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplObjective_;
+    info->conval_called_with_current_x_ = false;
+    info->objval_called_with_current_x_ = false;
+    info->jacval_called_with_current_x_ = false;
+}
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpConstraintAmpl::ClpConstraintAmpl ()
+        : ClpConstraint()
+{
+    type_ = 3;
+    column_ = NULL;
+    coefficient_ = NULL;
+    numberCoefficients_ = 0;
+    amplInfo_ = NULL;
+}
+
+//-------------------------------------------------------------------
+// Useful Constructor
+//-------------------------------------------------------------------
+ClpConstraintAmpl::ClpConstraintAmpl (int row, void * amplInfo)
+        : ClpConstraint()
+{
+    type_ = 3;
+    rowNumber_ = row;
+    amplInfo_ = amplInfo;
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo_;
+#ifndef NDEBUG
+    ASL_pfgh* asl = info->asl_;
+#endif
+    // warning: nlc is a macro that assumes we have a variable called asl
+    assert (rowNumber_ < nlc);
+    numberCoefficients_ = info->rowStart_[rowNumber_+1] - info->rowStart_[rowNumber_];
+    column_ = CoinCopyOfArray(info->column_ + info->rowStart_[rowNumber_], numberCoefficients_);
+    coefficient_ = new double [numberCoefficients_];;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpConstraintAmpl::ClpConstraintAmpl (const ClpConstraintAmpl & rhs)
+        : ClpConstraint(rhs)
+{
+    numberCoefficients_ = rhs.numberCoefficients_;
+    column_ = CoinCopyOfArray(rhs.column_, numberCoefficients_);
+    coefficient_ = CoinCopyOfArray(rhs.coefficient_, numberCoefficients_);
+}
+
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpConstraintAmpl::~ClpConstraintAmpl ()
+{
+    delete [] column_;
+    delete [] coefficient_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpConstraintAmpl &
+ClpConstraintAmpl::operator=(const ClpConstraintAmpl & rhs)
+{
+    if (this != &rhs) {
+        delete [] column_;
+        delete [] coefficient_;
+        numberCoefficients_ = rhs.numberCoefficients_;
+        column_ = CoinCopyOfArray(rhs.column_, numberCoefficients_);
+        coefficient_ = CoinCopyOfArray(rhs.coefficient_, numberCoefficients_);
+    }
+    return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpConstraint * ClpConstraintAmpl::clone() const
+{
+    return new ClpConstraintAmpl(*this);
+}
+
+// Returns gradient
+int
+ClpConstraintAmpl::gradient(const ClpSimplex * model,
+                            const double * solution,
+                            double * gradient,
+                            double & functionValue,
+                            double & offset,
+                            bool useScaling,
+                            bool refresh) const
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo_;
+    ASL_pfgh* asl = info->asl_;
+    int numberColumns = n_var;;
+    // If not done then do all
+    if (!info->jacval_called_with_current_x_) {
+        bool getStuff = eval_g(amplInfo_, numberColumns, solution, true, info->constraintValues_);
+        assert (getStuff);
+        getStuff = eval_jac_g(amplInfo_, numberColumns, solution, false, info->gradient_);
+        assert (getStuff);
+        info->jacval_called_with_current_x_ = getStuff;
+    }
+    if (refresh || !lastGradient_) {
+        functionValue_ = info->constraintValues_[rowNumber_];
+        offset_ = functionValue_; // sign??
+        if (!lastGradient_)
+            lastGradient_ = new double[numberColumns];
+        CoinZeroN(lastGradient_, numberColumns);
+        assert (!(model && model->rowScale() && useScaling));
+        int i;
+        int start = info->rowStart_[rowNumber_];
+        assert (numberCoefficients_ == info->rowStart_[rowNumber_+1] - start);
+        for (i = 0; i < numberCoefficients_; i++) {
+            int iColumn = column_[i];
+            double valueS = solution[iColumn];
+            double valueG = info->gradient_[start+i];
+            lastGradient_[iColumn] = valueG;
+            offset_ -= valueS * valueG;
+        }
+    }
+    functionValue = functionValue_;
+    offset = offset_;
+    memcpy(gradient, lastGradient_, numberColumns*sizeof(double));
+    return 0;
+}
+// Resize constraint
+void
+ClpConstraintAmpl::resize(int newNumberColumns)
+{
+    abort();
+}
+// Delete columns in  constraint
+void
+ClpConstraintAmpl::deleteSome(int numberToDelete, const int * which)
+{
+    if (numberToDelete) {
+        abort();
+    }
+}
+// Scale constraint
+void
+ClpConstraintAmpl::reallyScale(const double * columnScale)
+{
+    abort();
+}
+/* Given a zeroed array sets nonlinear columns to 1.
+   Returns number of nonlinear columns
+*/
+int
+ClpConstraintAmpl::markNonlinear(char * which) const
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo_;
+    ASL_pfgh* asl = info->asl_;
+    int iColumn;
+    int numberNon = 0;
+    int nonLinear = CoinMax(nlvc, nlvo);
+    for (iColumn = 0; iColumn < numberCoefficients_; iColumn++) {
+        int jColumn = column_[iColumn];
+        if (jColumn < nonLinear) {
+            which[jColumn] = 1;
+            numberNon++;
+        }
+    }
+    return numberNon;
+}
+/* Given a zeroed array sets possible nonzero coefficients to 1.
+   Returns number of nonzeros
+*/
+int
+ClpConstraintAmpl::markNonzero(char * which) const
+{
+    int iColumn;
+    for (iColumn = 0; iColumn < numberCoefficients_; iColumn++) {
+        which[column_[iColumn]] = 1;
+    }
+    return numberCoefficients_;
+}
+// Number of coefficients
+int
+ClpConstraintAmpl::numberCoefficients() const
+{
+    return numberCoefficients_;
+}
+// Say we have new primal solution - so may need to recompute
+void
+ClpConstraintAmpl::newXValues()
+{
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo_;
+    info->conval_called_with_current_x_ = false;
+    info->objval_called_with_current_x_ = false;
+    info->jacval_called_with_current_x_ = false;
+}
+
+/* Load nonlinear part of problem from AMPL info
+   Returns 0 if linear
+   1 if quadratic objective
+   2 if quadratic constraints
+   3 if nonlinear objective
+   4 if nonlinear constraints
+   -1 on failure
+*/
+int
+ClpSimplex::loadNonLinear(void * amplInfo, int & numberConstraints,
+                          ClpConstraint ** & constraints)
+{
+    numberConstraints = 0;
+    constraints = NULL;
+    CbcAmplInfo * info = (CbcAmplInfo *) amplInfo;
+    ASL_pfgh* asl = info->asl_;
+    // For moment don't say quadratic
+    int type = 0;
+    if (nlo + nlc) {
+        // nonlinear
+        if (!nlc) {
+            type = 3;
+            delete objective_;
+            objective_ = new ClpAmplObjective(amplInfo);
+        } else {
+            type = 4;
+            numberConstraints = nlc;
+            constraints = new ClpConstraint * [numberConstraints];
+            if (nlo) {
+                delete objective_;
+                objective_ = new ClpAmplObjective(amplInfo);
+            }
+            for (int i = 0; i < numberConstraints; i++) {
+                constraints[i] = new ClpConstraintAmpl(i, amplInfo);
+            }
+        }
+    }
+    return type;
+}
+#else
+#include "ClpSimplex.hpp"
+#include "ClpConstraint.hpp"
+int
+ClpSimplex::loadNonLinear(void * , int & ,
+                          ClpConstraint ** & )
+{
+    abort();
+    return 0;
+}
+#endif
+
diff --git a/cbits/coin/CbcMessage.cpp b/cbits/coin/CbcMessage.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcMessage.cpp
@@ -0,0 +1,111 @@
+/* $Id: CbcMessage.cpp 1916 2013-04-26 16:21:11Z tkr $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcMessage.hpp"
+#include <cstring>
+
+typedef struct {
+    CBC_Message internalNumber;
+    int externalNumber; // or continuation
+    char detail;
+    const char * message;
+} Cbc_message;
+static Cbc_message us_english[] = {
+    {CBC_END_GOOD, 1, 1, "Search completed - best objective %.16g, took %d iterations and %d nodes (%.2f seconds)"},
+    {CBC_MAXNODES, 3, 1, "Exiting on maximum nodes"},
+    {CBC_SOLUTION, 4, 1, "Integer solution of %g found after %d iterations and %d nodes (%.2f seconds)"},
+    {CBC_END, 5, 1, "Partial search - best objective %g (best possible %g), took %d iterations and %d nodes (%.2f seconds)"},
+    {CBC_INFEAS, 6, 1, "The LP relaxation is infeasible or too expensive"},
+    {CBC_STRONG, 7, 4, "Strong branching on %d (%d), down %g (%d) up %g (%d) value %g"},
+    {CBC_SOLINDIVIDUAL, 8, 2, "%d has value %g"},
+    {CBC_INTEGERINCREMENT, 9, 3, "Objective coefficients multiple of %g"},
+    {CBC_STATUS, 10, 1, "After %d nodes, %d on tree, %g best solution, best possible %g (%.2f seconds)"},
+    {CBC_GAP, 11, 1, "Exiting as integer gap of %g less than %g or %g%%"},
+    {CBC_ROUNDING, 12, 1, "Integer solution of %g found by %s after %d iterations and %d nodes (%.2f seconds)"},
+    {CBC_ROOT, 13, 1, "At root node, %d cuts changed objective from %g to %g in %d passes"},
+    {CBC_GENERATOR, 14, 1, "Cut generator %d (%s) - %d row cuts average %.1f elements, %d column cuts (%d active) %? in %.3f seconds - new frequency is %d"},
+    {CBC_BRANCH, 15, 3, "Node %d Obj %g Unsat %d depth %d"},
+    {CBC_STRONGSOL, 16, 1, "Integer solution of %g found by strong branching after %d iterations and %d nodes (%.2f seconds)"},
+    {CBC_VUB_PASS, 17, 1, "%d solved, %d variables fixed, %d tightened"},
+    {CBC_VUB_END, 18, 1, "After tightenVubs, %d variables fixed, %d tightened"},
+    {CBC_MAXSOLS, 19, 1, "Exiting on maximum solutions"},
+    {CBC_MAXTIME, 20, 1, "Exiting on maximum time"},
+    {CBC_NOTFEAS1, 21, 2, "On closer inspection node is infeasible"},
+    {CBC_NOTFEAS2, 22, 2, "On closer inspection objective value of %g above cutoff of %g"},
+    {CBC_NOTFEAS3, 23, 2, "Allowing solution, even though largest row infeasibility is %g"},
+    {CBC_TREE_SOL, 24, 1, "Integer solution of %g found by subtree after %d iterations and %d nodes (%.2f seconds)"},
+    {CBC_ITERATE_STRONG, 25, 3, "%d cleanup iterations before strong branching"},
+    {CBC_PRIORITY, 26, 1, "Setting priorities for objects %d to %d inclusive (out of %d)"},
+    {CBC_EVENT, 27, 1, "Exiting on user event"},
+    {CBC_START_SUB, 28, 1, "Starting sub-tree for %s - maximum nodes %d"},
+    {CBC_END_SUB, 29, 1, "Ending sub-tree for %s"},
+    {CBC_THREAD_STATS, 30, 1, "%s%? %d used %d times,  waiting to start %g, %?%g cpu time,%? %g waiting for threads, %? %d locks, %g locked, %g waiting for locks"},
+    {CBC_CUTS_STATS, 31, 1, "%d added rows had average density of %g"},
+    {CBC_STRONG_STATS, 32, 1, "Strong branching done %d times (%d iterations), fathomed %d nodes and fixed %d variables"},
+    {CBC_SOLUTION2, 33, 1, "Integer solution of %g found (by alternate solver) after %d iterations and %d nodes (%.2f seconds)"},
+    {CBC_UNBOUNDED, 34, 1, "The LP relaxation is unbounded!"},
+    {CBC_OTHER_STATS, 35, 1, "Maximum depth %d, %g variables fixed on reduced cost"},
+    {CBC_HEURISTICS_OFF, 36, 1, "Heuristics switched off as %d branching objects are of wrong type"},
+    {CBC_STATUS2, 37, 1, "%d nodes, %d on tree, best %g - possible %g depth %d unsat %d its %d (%.2f seconds)"},
+    {CBC_FPUMP1, 38, 1, "%s"},
+    {CBC_FPUMP2, 39, 2, "%s"},
+    {CBC_STATUS3, 40, 1, "%d nodes (+%d), %d on tree, best %g - possible %g depth %d unsat %d its %d (+%d) (%.2f seconds)"},
+    {CBC_OTHER_STATS2, 41, 1, "Maximum depth %d, %g variables fixed on reduced cost (%d nodes in complete fathoming taking %d iterations)"},
+    {CBC_RELAXED1, 42, 1, "Possible objective of %.18g but variable %d is %g from integer value, integer tolerance %g"},
+    {CBC_RELAXED2, 43, 2, "Possible objective of %.18g but had to fudge solution with tolerance of %g - check scaling of problem?"},
+    {CBC_RESTART, 44, 1, "Reduced cost fixing - %d rows, %d columns - restarting search"},
+    {CBC_GENERAL, 45, 1, "%s"},
+    {CBC_ROOT_DETAIL, 46, 2, "Root node pass %d, %d rows, %d total tight cuts  -  objective %g"},
+    {CBC_CUTOFF_WARNING1, 47, 1, "Cutoff set to %g - equivalent to best solution of %g"},
+    {CBC_END_SOLUTION, 48, 2, "Final check on integer solution of %g found after %d iterations and %d nodes (%.2f seconds)"},
+#ifndef NO_FATHOM_PRINT
+    {CBC_FATHOM_CHANGE, 49, 1, "Complete fathoming at depth >= %d"},
+#endif
+    {CBC_MAXITERS, 50, 1, "Exiting on maximum number of iterations"},
+    {CBC_NOINT, 3007, 1, "No integer variables - nothing to do"},
+    {CBC_WARNING_STRONG, 3008, 1, "Strong branching is fixing too many variables, too expensively!"},
+    {CBC_DUMMY_END, 999999, 0, ""}
+};
+/* Constructor */
+CbcMessage::CbcMessage(Language language) :
+        CoinMessages(sizeof(us_english) / sizeof(Cbc_message))
+{
+    language_ = language;
+    strcpy(source_, "Cbc");
+    class_ = 0; // branch and bound
+    Cbc_message * message = us_english;
+
+    while (message->internalNumber != CBC_DUMMY_END) {
+        CoinOneMessage oneMessage(message->externalNumber, message->detail,
+                                  message->message);
+        addMessage(message->internalNumber, oneMessage);
+        message ++;
+    }
+    // Put into compact form
+    toCompact();
+
+    // now override any language ones
+
+    //switch (language) {
+
+    //default:
+    message = NULL;
+    //  break;
+    //}
+
+    // replace if any found
+    if (message) {
+        while (message->internalNumber != CBC_DUMMY_END) {
+            replaceMessage(message->internalNumber, message->message);
+            message ++;
+        }
+    }
+}
+
diff --git a/cbits/coin/CbcMessage.hpp b/cbits/coin/CbcMessage.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcMessage.hpp
@@ -0,0 +1,94 @@
+/* $Id: CbcMessage.hpp 1791 2012-06-08 15:15:10Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcMessage_H
+#define CbcMessage_H
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+/** This deals with Cbc messages (as against Clp messages etc).
+    CoinMessageHandler.hpp is the general part of message handling.
+    All it has are enum's for the various messages.
+    CbcMessage.cpp has text in various languages.
+
+    It is trivial to use the .hpp and .cpp file as a basis for
+    messages for other components.
+ */
+
+#include "CoinMessageHandler.hpp"
+enum CBC_Message {
+    CBC_END_GOOD,
+    CBC_MAXNODES,
+    CBC_MAXTIME,
+    CBC_MAXSOLS,
+    CBC_EVENT,
+    CBC_MAXITERS,
+    CBC_SOLUTION,
+    CBC_END_SOLUTION,
+    CBC_SOLUTION2,
+    CBC_END,
+    CBC_INFEAS,
+    CBC_STRONG,
+    CBC_SOLINDIVIDUAL,
+    CBC_INTEGERINCREMENT,
+    CBC_STATUS,
+    CBC_GAP,
+    CBC_ROUNDING,
+    CBC_TREE_SOL,
+    CBC_ROOT,
+    CBC_GENERATOR,
+    CBC_BRANCH,
+    CBC_STRONGSOL,
+    CBC_NOINT,
+    CBC_VUB_PASS,
+    CBC_VUB_END,
+    CBC_NOTFEAS1,
+    CBC_NOTFEAS2,
+    CBC_NOTFEAS3,
+    CBC_CUTOFF_WARNING1,
+    CBC_ITERATE_STRONG,
+    CBC_PRIORITY,
+    CBC_WARNING_STRONG,
+    CBC_START_SUB,
+    CBC_END_SUB,
+    CBC_THREAD_STATS,
+    CBC_CUTS_STATS,
+    CBC_STRONG_STATS,
+    CBC_UNBOUNDED,
+    CBC_OTHER_STATS,
+    CBC_HEURISTICS_OFF,
+    CBC_STATUS2,
+    CBC_FPUMP1,
+    CBC_FPUMP2,
+    CBC_STATUS3,
+    CBC_OTHER_STATS2,
+    CBC_RELAXED1,
+    CBC_RELAXED2,
+    CBC_RESTART,
+    CBC_GENERAL,
+    CBC_ROOT_DETAIL,
+#ifndef NO_FATHOM_PRINT
+    CBC_FATHOM_CHANGE,
+#endif
+    CBC_DUMMY_END
+};
+
+class CbcMessage : public CoinMessages {
+
+public:
+
+    /**@name Constructors etc */
+    //@{
+    /** Constructor */
+    CbcMessage(Language language = us_en);
+    //@}
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcMipStartIO.cpp b/cbits/coin/CbcMipStartIO.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcMipStartIO.cpp
@@ -0,0 +1,216 @@
+#include <cstdlib>
+#include <cmath>
+#include <ctime>
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <map>
+#include <OsiSolverInterface.hpp>
+#include "CbcMessage.hpp"
+#include <CbcModel.hpp>
+#include "CbcMipStartIO.hpp"
+#include "CoinTime.hpp"
+
+using namespace std;
+
+
+bool isNumericStr( const char *str )
+{
+   const size_t l = strlen(str);
+
+   for ( size_t i=0 ; i<l ; ++i )
+      if (!(isdigit(str[i])||(str[i]=='.')))
+         return false;
+
+   return true;
+}
+
+int readMIPStart( CbcModel * model, const char *fileName,
+                  vector< pair< string, double > > &colValues,
+                  double &/*solObj*/ )
+{
+#define STR_SIZE 256
+   FILE *f = fopen( fileName, "r" );
+   if (!f)
+      return 1;
+   char line[STR_SIZE];
+
+   int nLine = 0;
+   char printLine[STR_SIZE];
+   while (fgets( line, STR_SIZE, f ))
+   {
+      ++nLine;
+      char col[4][STR_SIZE];
+      int nread = sscanf( line, "%s %s %s %s", col[0], col[1], col[2], col[3] );
+      if (!nread)
+         continue;
+      /* line with variable value */
+      if (strlen(col[0])&&isdigit(col[0][0])&&(nread>=3))
+      {
+         if (!isNumericStr(col[0]))
+         {
+            sprintf( printLine, "Reading: %s, line %d - first column in mipstart file should be numeric, ignoring.", fileName, nLine );
+	    model->messageHandler()->message(CBC_GENERAL, model->messages())
+	      << printLine << CoinMessageEol;
+            continue;
+         }
+         if (!isNumericStr(col[2]))
+         {
+            sprintf( printLine, "Reading: %s, line %d - Third column in mipstart file should be numeric, ignoring.", fileName, nLine  );
+	    model->messageHandler()->message(CBC_GENERAL, model->messages())
+	      << printLine << CoinMessageEol;
+            continue;
+         }
+
+         //int idx = atoi( col[0] );
+         char *name = col[1];
+         double value = atof( col[2] );
+         //double obj = 0.0;
+//         if (nread >= 4)
+//            obj = atof( col[3] );
+
+         colValues.push_back( pair<string, double>(string(name),value) );
+      }
+   }
+
+   if (colValues.size()) {
+      sprintf( printLine,"mipstart values read for %d variables.", (int)colValues.size());
+      model->messageHandler()->message(CBC_GENERAL, model->messages())
+	<< printLine << CoinMessageEol;
+   } else
+   {
+      sprintf( printLine, "No mipstart solution read from %s", fileName );
+      model->messageHandler()->message(CBC_GENERAL, model->messages())
+	<< printLine << CoinMessageEol;
+      return 1;
+   }
+
+   fclose(f);
+   return 0;
+}
+
+int computeCompleteSolution( CbcModel * model,
+                             const vector< string > colNames,
+                             const std::vector< std::pair< std::string, double > > &colValues,
+                             double *sol, double &obj )
+{
+   int status = 0;
+   double compObj = COIN_DBL_MAX;
+   bool foundIntegerSol = false;
+   OsiSolverInterface *lp = model->solver()->clone();
+   map< string, int > colIdx;
+   assert( ((int)colNames.size()) == lp->getNumCols() );
+
+   /* for fast search of column names */
+   for ( int i=0 ; (i<(int)colNames.size()) ; ++i )
+      colIdx[colNames[i]] = i;
+
+   char printLine[STR_SIZE];
+   int fixed = 0;
+   int notFound = 0;
+   char colNotFound[256] = "";
+   for ( int i=0 ; (i<(int)colValues.size()) ; ++i )
+   {
+      map< string, int >::const_iterator mIt = colIdx.find( colValues[i].first );
+      if ( mIt == colIdx.end() )
+      {
+         if (!notFound)
+            strcpy( colNotFound, colValues[i].first.c_str() );
+         notFound++;
+      }
+      else
+      {
+         const int idx = mIt->second;
+         double v = colValues[i].second;
+         if (v<1e-8)
+            v = 0.0;
+         if (lp->isInteger(idx))  // just to avoid small
+            v = floor( v+0.5 );   // fractional garbage
+         lp->setColBounds( idx, v, v );
+         ++fixed;
+      }
+   }
+
+   if (!fixed)
+   {
+      model->messageHandler()->message(CBC_GENERAL, model->messages())
+	<< "Warning: MIPstart solution is not valid, ignoring it."
+	<< CoinMessageEol;
+      goto TERMINATE;
+   }
+
+   if ( notFound >= ( ((double)colNames.size()) * 0.5 ) ) {
+      sprintf( printLine, "Warning: %d column names were not found (e.g. %s) while filling solution.", notFound, colNotFound );
+      model->messageHandler()->message(CBC_GENERAL, model->messages())
+	<< printLine << CoinMessageEol;
+   }
+
+   lp->initialSolve();
+   if (!lp->isProvenOptimal())
+   {
+      model->messageHandler()->message(CBC_GENERAL, model->messages())
+	<< "Warning: mipstart values could not be used to build a solution." << CoinMessageEol;
+      status = 1;
+      goto TERMINATE;
+   }
+
+   /* some additional effort is needed to provide an integer solution */
+   if ( lp->getFractionalIndices().size() > 0 )
+   {
+      sprintf( printLine,"MIPStart solution provided values for %d of %d integer variables, %d variables are still fractional.", fixed, lp->getNumIntegers(), (int)lp->getFractionalIndices().size() );
+      model->messageHandler()->message(CBC_GENERAL, model->messages())
+	<< printLine << CoinMessageEol;
+      double start = CoinCpuTime();
+      CbcModel babModel( *lp );
+      babModel.setLogLevel( 0 );
+      babModel.setMaximumNodes( 500 );
+      babModel.setMaximumSeconds( 60 );
+      babModel.branchAndBound();
+      if (babModel.bestSolution())
+      {
+         sprintf( printLine,"Mini branch and bound defined values for remaining variables in %.2f seconds.", 
+		  CoinCpuTime()-start);
+	 model->messageHandler()->message(CBC_GENERAL, model->messages())
+	   << printLine << CoinMessageEol;
+         copy( babModel.bestSolution(), babModel.bestSolution()+babModel.getNumCols(), sol );
+         foundIntegerSol = true;
+         obj = compObj = babModel.getObjValue();
+      }
+      else
+      {
+	 model->messageHandler()->message(CBC_GENERAL, model->messages())
+	   << "Warning: mipstart values could not be used to build a solution." << CoinMessageEol;
+         status = 1;
+         goto TERMINATE;
+      }
+   }
+   else
+   {
+      foundIntegerSol = true;
+      obj = compObj = lp->getObjValue();
+      copy( lp->getColSolution(), lp->getColSolution()+lp->getNumCols(), sol );
+   }
+
+   if ( foundIntegerSol )
+   {
+      sprintf( printLine,"mipstart provided solution with cost %g", compObj);
+      model->messageHandler()->message(CBC_GENERAL, model->messages())
+	<< printLine << CoinMessageEol;
+      for ( int i=0 ; (i<lp->getNumCols()) ; ++i )
+      {
+         if (sol[i]<1e-8)
+            sol[i] = 0.0;
+         else
+            if (lp->isInteger(i))
+               sol[i] = floor( sol[i]+0.5 );
+      }
+   }
+
+TERMINATE:
+   delete lp;
+   return status;
+}
+#undef STR_SIZE
diff --git a/cbits/coin/CbcMipStartIO.hpp b/cbits/coin/CbcMipStartIO.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcMipStartIO.hpp
@@ -0,0 +1,26 @@
+#ifndef MIPSTARTIO_HPP_INCLUDED
+#define MIPSTARTIO_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <utility>
+class CbcModel;
+
+class OsiSolverInterface;
+
+/* tries to read mipstart (solution file) from
+   fileName, filling colValues and obj
+   returns 0 with success,
+   1 otherwise */
+int readMIPStart( CbcModel * model, const char *fileName,
+                  std::vector< std::pair< std::string, double > > &colValues,
+                  double &solObj );
+
+/* from a partial list of variables tries to fill the
+   remaining variable values */
+int computeCompleteSolution( CbcModel * model, 
+                             const std::vector< std::string > colNames,
+                             const std::vector< std::pair< std::string, double > > &colValues,
+                             double *sol, double &obj );
+
+#endif // MIPSTARTIO_HPP_INCLUDED
diff --git a/cbits/coin/CbcModel.cpp b/cbits/coin/CbcModel.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcModel.cpp
@@ -0,0 +1,17938 @@
+/* $Id: CbcModel.cpp 1973 2013-10-19 15:59:44Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcConfig.h"
+
+#include <string>
+//#define CBC_DEBUG 1
+//#define CHECK_CUT_COUNTS
+//#define CHECK_NODE
+//#define CHECK_NODE_FULL
+//#define NODE_LOG
+//#define GLOBAL_CUTS_JUST_POINTERS
+#ifdef CGL_DEBUG_GOMORY
+extern int gomory_try;
+#endif
+#include <cassert>
+#include <cmath>
+#include <cfloat>
+#ifdef COIN_HAS_CLP
+// include Presolve from Clp
+#include "ClpPresolve.hpp"
+#include "OsiClpSolverInterface.hpp"
+#include "ClpNode.hpp"
+#include "ClpDualRowDantzig.hpp"
+#include "ClpSimplexPrimal.hpp"
+#endif
+
+#include "CbcEventHandler.hpp"
+
+#include "OsiSolverInterface.hpp"
+#include "OsiAuxInfo.hpp"
+#include "OsiSolverBranch.hpp"
+#include "OsiChooseVariable.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "CbcHeuristic.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcHeuristicRINS.hpp"
+#include "CbcHeuristicDive.hpp"
+#include "CbcModel.hpp"
+#include "CbcTreeLocal.hpp"
+#include "CbcStatistics.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcMessage.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiColCut.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "OsiCuts.hpp"
+#include "CbcCountRowCut.hpp"
+#include "CbcCutGenerator.hpp"
+#include "CbcFeasibilityBase.hpp"
+#include "CbcFathom.hpp"
+#include "CbcFullNodeInfo.hpp"
+// include Probing
+#include "CglProbing.hpp"
+#include "CglGomory.hpp"
+#include "CglTwomir.hpp"
+// include preprocessing
+#include "CglPreProcess.hpp"
+#include "CglDuplicateRow.hpp"
+#include "CglStored.hpp"
+#include "CglClique.hpp"
+
+#include "CoinTime.hpp"
+#include "CoinMpsIO.hpp"
+
+#include "CbcCompareActual.hpp"
+#include "CbcTree.hpp"
+// This may be dummy
+#include "CbcThread.hpp"
+/* Various functions local to CbcModel.cpp */
+
+static void * doRootCbcThread(void * voidInfo);
+
+namespace {
+
+//-------------------------------------------------------------------
+// Returns the greatest common denominator of two
+// positive integers, a and b, found using Euclid's algorithm
+//-------------------------------------------------------------------
+static int gcd(int a, int b)
+{
+    int remainder = -1;
+    // make sure a<=b (will always remain so)
+    if (a > b) {
+        // Swap a and b
+        int temp = a;
+        a = b;
+        b = temp;
+    }
+    // if zero then gcd is nonzero (zero may occur in rhs of packed)
+    if (!a) {
+        if (b) {
+            return b;
+        } else {
+            printf("**** gcd given two zeros!!\n");
+            abort();
+        }
+    }
+    while (remainder) {
+        remainder = b % a;
+        b = a;
+        a = remainder;
+    }
+    return b;
+}
+
+
+
+#ifdef CHECK_NODE_FULL
+
+/*
+  Routine to verify that tree linkage is correct. The invariant that is tested
+  is
+
+  reference count = (number of actual references) + (number of branches left)
+
+  The routine builds a set of paired arrays, info and count, by traversing the
+  tree. Each CbcNodeInfo is recorded in info, and the number of times it is
+  referenced (via the parent field) is recorded in count. Then a final check is
+  made to see if the numberPointingToThis_ field agrees.
+*/
+
+void verifyTreeNodes (const CbcTree * branchingTree, const CbcModel &model)
+
+{
+    if (model.getNodeCount() == 661) return;
+    printf("*** CHECKING tree after %d nodes\n", model.getNodeCount()) ;
+
+    int j ;
+    int nNodes = branchingTree->size() ;
+# define MAXINFO 1000
+    int *count = new int [MAXINFO] ;
+    CbcNodeInfo **info = new CbcNodeInfo*[MAXINFO] ;
+    int nInfo = 0 ;
+    /*
+      Collect all CbcNodeInfo objects in info, by starting from each live node and
+      traversing back to the root. Nodes in the live set should have unexplored
+      branches remaining.
+
+      TODO: The `while (nodeInfo)' loop could be made to break on reaching a
+    	common ancester (nodeInfo is found in info[k]). Alternatively, the
+    	check could change to signal an error if nodeInfo is not found above a
+    	common ancestor.
+    */
+    for (j = 0 ; j < nNodes ; j++) {
+        CbcNode *node = branchingTree->nodePointer(j) ;
+        if (!node)
+            continue;
+        CbcNodeInfo *nodeInfo = node->nodeInfo() ;
+        int change = node->nodeInfo()->numberBranchesLeft() ;
+        assert(change) ;
+        while (nodeInfo) {
+            int k ;
+            for (k = 0 ; k < nInfo ; k++) {
+                if (nodeInfo == info[k]) break ;
+            }
+            if (k == nInfo) {
+                assert(nInfo < MAXINFO) ;
+                nInfo++ ;
+                info[k] = nodeInfo ;
+                count[k] = 0 ;
+            }
+            nodeInfo = nodeInfo->parent() ;
+        }
+    }
+    /*
+      Walk the info array. For each nodeInfo, look up its parent in info and
+      increment the corresponding count.
+    */
+    for (j = 0 ; j < nInfo ; j++) {
+        CbcNodeInfo *nodeInfo = info[j] ;
+        nodeInfo = nodeInfo->parent() ;
+        if (nodeInfo) {
+            int k ;
+            for (k = 0 ; k < nInfo ; k++) {
+                if (nodeInfo == info[k]) break ;
+            }
+            assert (k < nInfo) ;
+            count[k]++ ;
+        }
+    }
+    /*
+      Walk the info array one more time and check that the invariant holds. The
+      number of references (numberPointingToThis()) should equal the sum of the
+      number of actual references (held in count[]) plus the number of potential
+      references (unexplored branches, numberBranchesLeft()).
+    */
+    for (j = 0; j < nInfo; j++) {
+        CbcNodeInfo * nodeInfo = info[j] ;
+        if (nodeInfo) {
+            int k ;
+            for (k = 0; k < nInfo; k++)
+                if (nodeInfo == info[k])
+                    break ;
+            printf("Nodeinfo %x - %d left, %d count\n",
+                   nodeInfo,
+                   nodeInfo->numberBranchesLeft(),
+                   nodeInfo->numberPointingToThis()) ;
+            assert(nodeInfo->numberPointingToThis() ==
+                   count[k] + nodeInfo->numberBranchesLeft()) ;
+        }
+    }
+
+    delete [] count ;
+    delete [] info ;
+
+    return ;
+}
+
+#endif	/* CHECK_NODE_FULL */
+
+
+
+#ifdef CHECK_CUT_COUNTS
+
+/*
+  Routine to verify that cut reference counts are correct.
+*/
+void verifyCutCounts (const CbcTree * branchingTree, CbcModel &model)
+
+{
+    printf("*** CHECKING cuts after %d nodes\n", model.getNodeCount()) ;
+
+    int j ;
+    int nNodes = branchingTree->size() ;
+
+    /*
+      cut.tempNumber_ exists for the purpose of doing this verification. Clear it
+      in all cuts. We traverse the tree by starting from each live node and working
+      back to the root. At each CbcNodeInfo, check for cuts.
+    */
+    for (j = 0 ; j < nNodes ; j++) {
+        CbcNode *node = branchingTree->nodePointer(j) ;
+        CbcNodeInfo * nodeInfo = node->nodeInfo() ;
+        assert (node->nodeInfo()->numberBranchesLeft()) ;
+        while (nodeInfo) {
+            int k ;
+            for (k = 0 ; k < nodeInfo->numberCuts() ; k++) {
+                CbcCountRowCut *cut = nodeInfo->cuts()[k] ;
+                if (cut) cut->tempNumber_ = 0;
+            }
+            nodeInfo = nodeInfo->parent() ;
+        }
+    }
+    /*
+      Walk the live set again, this time collecting the list of cuts in use at each
+      node. addCuts1 will collect the cuts in model.addedCuts_. Take into account
+      that when we recreate the basis for a node, we compress out the slack cuts.
+    */
+    for (j = 0 ; j < nNodes ; j++) {
+        CoinWarmStartBasis *debugws = model.getEmptyBasis() ;
+        CbcNode *node = branchingTree->nodePointer(j) ;
+        CbcNodeInfo *nodeInfo = node->nodeInfo();
+        int change = node->nodeInfo()->numberBranchesLeft() ;
+        printf("Node %d %x (info %x) var %d way %d obj %g", j, node,
+               node->nodeInfo(), node->columnNumber(), node->way(),
+               node->objectiveValue()) ;
+
+        model.addCuts1(node, debugws) ;
+
+        int i ;
+        int numberRowsAtContinuous = model.numberRowsAtContinuous() ;
+        CbcCountRowCut **addedCuts = model.addedCuts() ;
+        for (i = 0 ; i < model.currentNumberCuts() ; i++) {
+            CoinWarmStartBasis::Status status =
+                debugws->getArtifStatus(i + numberRowsAtContinuous) ;
+            if (status != CoinWarmStartBasis::basic && addedCuts[i]) {
+                addedCuts[i]->tempNumber_ += change ;
+            }
+        }
+
+        while (nodeInfo) {
+            nodeInfo = nodeInfo->parent() ;
+            if (nodeInfo) printf(" -> %x", nodeInfo);
+        }
+        printf("\n") ;
+        delete debugws ;
+    }
+    /*
+      The moment of truth: We've tallied up the references by direct scan of the  search tree. Check for agreement with the count in the cut.
+
+      TODO: Rewrite to check and print mismatch only when tempNumber_ == 0?
+    */
+    for (j = 0 ; j < nNodes ; j++) {
+        CbcNode *node = branchingTree->nodePointer(j) ;
+        CbcNodeInfo *nodeInfo = node->nodeInfo();
+        while (nodeInfo) {
+            int k ;
+            for (k = 0 ; k < nodeInfo->numberCuts() ; k++) {
+                CbcCountRowCut *cut = nodeInfo->cuts()[k] ;
+                if (cut && cut->tempNumber_ >= 0) {
+                    if (cut->tempNumber_ != cut->numberPointingToThis())
+                        printf("mismatch %x %d %x %d %d\n", nodeInfo, k,
+                               cut, cut->tempNumber_, cut->numberPointingToThis()) ;
+                    else
+                        printf("   match %x %d %x %d %d\n", nodeInfo, k,
+                               cut, cut->tempNumber_, cut->numberPointingToThis()) ;
+                    cut->tempNumber_ = -1 ;
+                }
+            }
+            nodeInfo = nodeInfo->parent() ;
+        }
+    }
+
+    return ;
+}
+
+#endif /* CHECK_CUT_COUNTS */
+
+
+#ifdef CHECK_CUT_SIZE
+
+/*
+  Routine to verify that cut reference counts are correct.
+*/
+void verifyCutSize (const CbcTree * branchingTree, CbcModel &model)
+{
+
+    int j ;
+    int nNodes = branchingTree->size() ;
+    int totalCuts = 0;
+
+    /*
+      cut.tempNumber_ exists for the purpose of doing this verification. Clear it
+      in all cuts. We traverse the tree by starting from each live node and working
+      back to the root. At each CbcNodeInfo, check for cuts.
+    */
+    for (j = 0 ; j < nNodes ; j++) {
+        CbcNode *node = branchingTree->nodePointer(j) ;
+        CbcNodeInfo * nodeInfo = node->nodeInfo() ;
+        assert (node->nodeInfo()->numberBranchesLeft()) ;
+        while (nodeInfo) {
+            totalCuts += nodeInfo->numberCuts();
+            nodeInfo = nodeInfo->parent() ;
+        }
+    }
+    printf("*** CHECKING cuts (size) after %d nodes - %d cuts\n", model.getNodeCount(), totalCuts) ;
+    return ;
+}
+
+#endif /* CHECK_CUT_SIZE */
+
+}
+
+/* End unnamed namespace for CbcModel.cpp */
+
+
+void
+CbcModel::analyzeObjective ()
+/*
+  Try to find a minimum change in the objective function. The first scan
+  checks that there are no continuous variables with non-zero coefficients,
+  and grabs the largest objective coefficient associated with an unfixed
+  integer variable. The second scan attempts to scale up the objective
+  coefficients to a point where they are sufficiently close to integer that
+  we can pretend they are integer, and calculate a gcd over the coefficients
+  of interest. This will be the minimum increment for the scaled coefficients.
+  The final action is to scale the increment back for the original coefficients
+  and install it, if it's better than the existing value.
+
+  John's note: We could do better than this.
+
+  John's second note - apologies for changing s to z
+*/
+{
+    const double *objective = getObjCoefficients() ;
+    const double *lower = getColLower() ;
+    const double *upper = getColUpper() ;
+    /*
+      Scan continuous and integer variables to see if continuous
+      are cover or network with integral rhs.
+    */
+    double continuousMultiplier = 1.0;
+    double * coeffMultiplier = NULL;
+    double largestObj = 0.0;
+    double smallestObj = COIN_DBL_MAX;
+    {
+        const double *rowLower = getRowLower() ;
+        const double *rowUpper = getRowUpper() ;
+        int numberRows = solver_->getNumRows() ;
+        double * rhs = new double [numberRows];
+        memset(rhs, 0, numberRows*sizeof(double));
+        int iColumn;
+        int numberColumns = solver_->getNumCols() ;
+        // Column copy of matrix
+        int problemType = -1;
+        const double * element = solver_->getMatrixByCol()->getElements();
+        const int * row = solver_->getMatrixByCol()->getIndices();
+        const CoinBigIndex * columnStart = solver_->getMatrixByCol()->getVectorStarts();
+        const int * columnLength = solver_->getMatrixByCol()->getVectorLengths();
+        int numberInteger = 0;
+        int numberIntegerObj = 0;
+        int numberGeneralIntegerObj = 0;
+        int numberIntegerWeight = 0;
+        int numberContinuousObj = 0;
+        double cost = COIN_DBL_MAX;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (upper[iColumn] == lower[iColumn]) {
+                CoinBigIndex start = columnStart[iColumn];
+                CoinBigIndex end = start + columnLength[iColumn];
+                for (CoinBigIndex j = start; j < end; j++) {
+                    int iRow = row[j];
+                    rhs[iRow] += lower[iColumn] * element[j];
+                }
+            } else {
+                double objValue = objective[iColumn];
+                if (solver_->isInteger(iColumn))
+                    numberInteger++;
+                if (objValue) {
+                    if (!solver_->isInteger(iColumn)) {
+                        numberContinuousObj++;
+                    } else {
+                        largestObj = CoinMax(largestObj, fabs(objValue));
+                        smallestObj = CoinMin(smallestObj, fabs(objValue));
+                        numberIntegerObj++;
+                        if (cost == COIN_DBL_MAX)
+                            cost = objValue;
+                        else if (cost != objValue)
+                            cost = -COIN_DBL_MAX;
+                        int gap = static_cast<int> (upper[iColumn] - lower[iColumn]);
+                        if (gap > 1) {
+                            numberGeneralIntegerObj++;
+                            numberIntegerWeight += gap;
+                        }
+                    }
+                }
+            }
+        }
+        int iType = 0;
+        if (!numberContinuousObj && numberIntegerObj <= 5 && numberIntegerWeight <= 100 &&
+                numberIntegerObj*3 < numberObjects_ && !parentModel_ && solver_->getNumRows() > 100)
+	  iType = 1 + 4 + ((moreSpecialOptions_&536870912)==0) ? 2 : 0;
+        else if (!numberContinuousObj && numberIntegerObj <= 100 &&
+                 numberIntegerObj*5 < numberObjects_ && numberIntegerWeight <= 100 &&
+                 !parentModel_ &&
+                 solver_->getNumRows() > 100 && cost != -COIN_DBL_MAX)
+	  iType = 4 + ((moreSpecialOptions_&536870912)==0) ? 2 : 0;
+        else if (!numberContinuousObj && numberIntegerObj <= 100 &&
+                 numberIntegerObj*5 < numberObjects_ &&
+                 !parentModel_ &&
+                 solver_->getNumRows() > 100 && cost != -COIN_DBL_MAX)
+            iType = 8;
+        int iTest = getMaximumNodes();
+        if (iTest >= 987654320 && iTest < 987654330 && numberObjects_ && !parentModel_) {
+            iType = iTest - 987654320;
+            printf("Testing %d integer variables out of %d objects (%d integer) have cost of %g - %d continuous\n",
+                   numberIntegerObj, numberObjects_, numberInteger, cost, numberContinuousObj);
+            if (iType == 9)
+                exit(77);
+            if (numberContinuousObj)
+                iType = 0;
+        }
+
+        //if (!numberContinuousObj&&(numberIntegerObj<=5||cost!=-COIN_DBL_MAX)&&
+        //numberIntegerObj*3<numberObjects_&&!parentModel_&&solver_->getNumRows()>100) {
+        if (iType) {
+            /*
+            A) put high priority on (if none)
+            B) create artificial objective (if clp)
+            */
+            int iPriority = -1;
+            for (int i = 0; i < numberObjects_; i++) {
+                int k = object_[i]->priority();
+                if (iPriority == -1)
+                    iPriority = k;
+                else if (iPriority != k)
+                    iPriority = -2;
+            }
+            bool branchOnSatisfied = ((iType & 1) != 0);
+            bool createFake = ((iType & 2) != 0);
+            bool randomCost = ((iType & 4) != 0);
+            if (iPriority >= 0) {
+                char general[200];
+                if (cost == -COIN_DBL_MAX) {
+                    sprintf(general, "%d integer variables out of %d objects (%d integer) have costs - high priority",
+                            numberIntegerObj, numberObjects_, numberInteger);
+                } else if (cost == COIN_DBL_MAX) {
+                    sprintf(general, "No integer variables out of %d objects (%d integer) have costs",
+                            numberObjects_, numberInteger);
+                    branchOnSatisfied = false;
+                } else {
+                    sprintf(general, "%d integer variables out of %d objects (%d integer) have cost of %g - high priority",
+                            numberIntegerObj, numberObjects_, numberInteger, cost);
+                }
+                messageHandler()->message(CBC_GENERAL,
+                                          messages())
+                << general << CoinMessageEol ;
+                sprintf(general, "branch on satisfied %c create fake objective %c random cost %c",
+                        branchOnSatisfied ? 'Y' : 'N',
+                        createFake ? 'Y' : 'N',
+                        randomCost ? 'Y' : 'N');
+                messageHandler()->message(CBC_GENERAL,
+                                          messages())
+                << general << CoinMessageEol ;
+                // switch off clp type branching
+                // no ? fastNodeDepth_ = -1;
+                int highPriority = (branchOnSatisfied) ? -999 : 100;
+                for (int i = 0; i < numberObjects_; i++) {
+                    CbcSimpleInteger * thisOne = dynamic_cast <CbcSimpleInteger *> (object_[i]);
+                    object_[i]->setPriority(1000);
+                    if (thisOne) {
+                        int iColumn = thisOne->columnNumber();
+                        if (objective[iColumn])
+                            thisOne->setPriority(highPriority);
+                    }
+                }
+            }
+#ifdef COIN_HAS_CLP
+            OsiClpSolverInterface * clpSolver
+            = dynamic_cast<OsiClpSolverInterface *> (solver_);
+            if (clpSolver && createFake) {
+                // Create artificial objective to be used when all else fixed
+                int numberColumns = clpSolver->getNumCols();
+                double * fakeObj = new double [numberColumns];
+                // Column copy
+                const CoinPackedMatrix  * matrixByCol = clpSolver->getMatrixByCol();
+                //const double * element = matrixByCol.getElements();
+                //const int * row = matrixByCol.getIndices();
+                //const CoinBigIndex * columnStart = matrixByCol.getVectorStarts();
+                const int * columnLength = matrixByCol->getVectorLengths();
+                const double * solution = clpSolver->getColSolution();
+#ifdef JJF_ZERO
+                int nAtBound = 0;
+                for (int i = 0; i < numberColumns; i++) {
+                    double lowerValue = lower[i];
+                    double upperValue = upper[i];
+                    if (clpSolver->isInteger(i)) {
+                        double lowerValue = lower[i];
+                        double upperValue = upper[i];
+                        double value = solution[i];
+                        if (value < lowerValue + 1.0e-6 ||
+                                value > upperValue - 1.0e-6)
+                            nAtBound++;
+                    }
+                }
+#endif
+                /*
+                  Generate a random objective function for problems where the given objective
+                  function is not terribly useful. (Nearly feasible, single integer variable,
+                  that sort of thing.
+                */
+                CoinDrand48(true, 1234567);
+                for (int i = 0; i < numberColumns; i++) {
+                    double lowerValue = lower[i];
+                    double upperValue = upper[i];
+                    double value = (randomCost) ? ceil((CoinDrand48() + 0.5) * 1000)
+                                   : i + 1 + columnLength[i] * 1000;
+                    value *= 0.001;
+                    //value += columnLength[i];
+                    if (lowerValue > -1.0e5 || upperValue < 1.0e5) {
+                        if (fabs(lowerValue) > fabs(upperValue))
+                            value = - value;
+                        if (clpSolver->isInteger(i)) {
+                            double solValue = solution[i];
+                            // Better to add in 0.5 or 1.0??
+                            if (solValue < lowerValue + 1.0e-6)
+                                value = fabs(value) + 0.5; //fabs(value*1.5);
+                            else if (solValue > upperValue - 1.0e-6)
+                                value = -fabs(value) - 0.5; //-fabs(value*1.5);
+                        }
+                    } else {
+                        value = 0.0;
+                    }
+                    fakeObj[i] = value;
+                }
+                // pass to solver
+                clpSolver->setFakeObjective(fakeObj);
+                delete [] fakeObj;
+            }
+#endif
+        } else if (largestObj < smallestObj*5.0 && !parentModel_ &&
+                   !numberContinuousObj &&
+                   !numberGeneralIntegerObj &&
+                   numberIntegerObj*2 < numberColumns) {
+            // up priorities on costed
+            int iPriority = -1;
+            for (int i = 0; i < numberObjects_; i++) {
+                int k = object_[i]->priority();
+                if (iPriority == -1)
+                    iPriority = k;
+                else if (iPriority != k)
+                    iPriority = -2;
+            }
+            if (iPriority >= 100) {
+#ifdef CLP_INVESTIGATE
+                printf("Setting variables with obj to high priority\n");
+#endif
+                for (int i = 0; i < numberObjects_; i++) {
+                    CbcSimpleInteger * obj =
+                        dynamic_cast <CbcSimpleInteger *>(object_[i]) ;
+                    if (obj) {
+                        int iColumn = obj->columnNumber();
+                        if (objective[iColumn])
+                            object_[i]->setPriority(iPriority - 1);
+                    }
+                }
+            }
+        }
+        int iRow;
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            if (rowLower[iRow] > -1.0e20 &&
+                    fabs(rowLower[iRow] - rhs[iRow] - floor(rowLower[iRow] - rhs[iRow] + 0.5)) > 1.0e-10) {
+                continuousMultiplier = 0.0;
+                break;
+            }
+            if (rowUpper[iRow] < 1.0e20 &&
+                    fabs(rowUpper[iRow] - rhs[iRow] - floor(rowUpper[iRow] - rhs[iRow] + 0.5)) > 1.0e-10) {
+                continuousMultiplier = 0.0;
+                break;
+            }
+            // set rhs to limiting value
+            if (rowLower[iRow] != rowUpper[iRow]) {
+                if (rowLower[iRow] > -1.0e20) {
+                    if (rowUpper[iRow] < 1.0e20) {
+                        // no good
+                        continuousMultiplier = 0.0;
+                        break;
+                    } else {
+                        rhs[iRow] = rowLower[iRow] - rhs[iRow];
+                        if (problemType < 0)
+                            problemType = 3; // set cover
+                        else if (problemType != 3)
+                            problemType = 4;
+                    }
+                } else {
+                    rhs[iRow] = rowUpper[iRow] - rhs[iRow];
+                    if (problemType < 0)
+                        problemType = 1; // set partitioning <=
+                    else if (problemType != 1)
+                        problemType = 4;
+                }
+            } else {
+                rhs[iRow] = rowUpper[iRow] - rhs[iRow];
+                if (problemType < 0)
+                    problemType = 3; // set partitioning ==
+                else if (problemType != 2)
+                    problemType = 2;
+            }
+            if (fabs(rhs[iRow] - 1.0) > 1.0e-12)
+                problemType = 4;
+        }
+        if (continuousMultiplier) {
+            // 1 network, 2 cover, 4 negative cover
+            int possible = 7;
+            bool unitRhs = true;
+            // See which rows could be set cover
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (upper[iColumn] > lower[iColumn] + 1.0e-8) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = start + columnLength[iColumn];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                        double value = element[j];
+                        if (value == 1.0) {
+                        } else if (value == -1.0) {
+                            rhs[row[j]] = -0.5;
+                        } else {
+                            rhs[row[j]] = -COIN_DBL_MAX;
+                        }
+                    }
+                }
+            }
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (upper[iColumn] > lower[iColumn] + 1.0e-8) {
+                    if (!isInteger(iColumn)) {
+                        CoinBigIndex start = columnStart[iColumn];
+                        CoinBigIndex end = start + columnLength[iColumn];
+                        double rhsValue = 0.0;
+                        // 1 all ones, -1 all -1s, 2 all +- 1, 3 no good
+                        int type = 0;
+                        for (CoinBigIndex j = start; j < end; j++) {
+                            double value = element[j];
+                            if (fabs(value) != 1.0) {
+                                type = 3;
+                                break;
+                            } else if (value == 1.0) {
+                                if (!type)
+                                    type = 1;
+                                else if (type != 1)
+                                    type = 2;
+                            } else {
+                                if (!type)
+                                    type = -1;
+                                else if (type != -1)
+                                    type = 2;
+                            }
+                            int iRow = row[j];
+                            if (rhs[iRow] == -COIN_DBL_MAX) {
+                                type = 3;
+                                break;
+                            } else if (rhs[iRow] == -0.5) {
+                                // different values
+                                unitRhs = false;
+                            } else if (rhsValue) {
+                                if (rhsValue != rhs[iRow])
+                                    unitRhs = false;
+                            } else {
+                                rhsValue = rhs[iRow];
+                            }
+                        }
+                        // if no elements OK
+                        if (type == 3) {
+                            // no good
+                            possible = 0;
+                            break;
+                        } else if (type == 2) {
+                            if (end - start > 2) {
+                                // no good
+                                possible = 0;
+                                break;
+                            } else {
+                                // only network
+                                possible &= 1;
+                                if (!possible)
+                                    break;
+                            }
+                        } else if (type == 1) {
+                            // only cover
+                            possible &= 2;
+                            if (!possible)
+                                break;
+                        } else if (type == -1) {
+                            // only negative cover
+                            possible &= 4;
+                            if (!possible)
+                                break;
+                        }
+                    }
+                }
+            }
+            if ((possible == 2 || possible == 4) && !unitRhs) {
+#if COIN_DEVELOP>1
+                printf("XXXXXX Continuous all +1 but different rhs\n");
+#endif
+                possible = 0;
+            }
+            // may be all integer
+            if (possible != 7) {
+                if (!possible)
+                    continuousMultiplier = 0.0;
+                else if (possible == 1)
+                    continuousMultiplier = 1.0;
+                else
+                    continuousMultiplier = 0.0; // 0.5 was incorrect;
+#if COIN_DEVELOP>1
+                if (continuousMultiplier)
+                    printf("XXXXXX multiplier of %g\n", continuousMultiplier);
+#endif
+                if (continuousMultiplier == 0.5) {
+                    coeffMultiplier = new double [numberColumns];
+                    bool allOne = true;
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        coeffMultiplier[iColumn] = 1.0;
+                        if (upper[iColumn] > lower[iColumn] + 1.0e-8) {
+                            if (!isInteger(iColumn)) {
+                                CoinBigIndex start = columnStart[iColumn];
+                                int iRow = row[start];
+                                double value = rhs[iRow];
+                                assert (value >= 0.0);
+                                if (value != 0.0 && value != 1.0)
+                                    allOne = false;
+                                coeffMultiplier[iColumn] = 0.5 * value;
+                            }
+                        }
+                    }
+                    if (allOne) {
+                        // back to old way
+                        delete [] coeffMultiplier;
+                        coeffMultiplier = NULL;
+                    }
+                }
+            } else {
+                // all integer
+                problemType_ = problemType;
+#if COIN_DEVELOP>1
+                printf("Problem type is %d\n", problemType_);
+#endif
+            }
+        }
+
+        // But try again
+        if (continuousMultiplier < 1.0) {
+            memset(rhs, 0, numberRows*sizeof(double));
+            int * count = new int [numberRows];
+            memset(count, 0, numberRows*sizeof(int));
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                CoinBigIndex start = columnStart[iColumn];
+                CoinBigIndex end = start + columnLength[iColumn];
+                if (upper[iColumn] == lower[iColumn]) {
+                    for (CoinBigIndex j = start; j < end; j++) {
+                        int iRow = row[j];
+                        rhs[iRow] += lower[iColumn] * element[j];
+                    }
+                } else if (solver_->isInteger(iColumn)) {
+                    for (CoinBigIndex j = start; j < end; j++) {
+                        int iRow = row[j];
+                        if (fabs(element[j] - floor(element[j] + 0.5)) > 1.0e-10)
+                            rhs[iRow]  = COIN_DBL_MAX;
+                    }
+                } else {
+                    for (CoinBigIndex j = start; j < end; j++) {
+                        int iRow = row[j];
+                        count[iRow]++;
+                        if (fabs(element[j]) != 1.0)
+                            rhs[iRow]  = COIN_DBL_MAX;
+                    }
+                }
+            }
+            // now look at continuous
+            bool allGood = true;
+            double direction = solver_->getObjSense() ;
+            int numberObj = 0;
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (upper[iColumn] > lower[iColumn]) {
+                    double objValue = objective[iColumn] * direction;
+                    if (objValue && !solver_->isInteger(iColumn)) {
+                        numberObj++;
+                        CoinBigIndex start = columnStart[iColumn];
+                        CoinBigIndex end = start + columnLength[iColumn];
+                        if (objValue > 0.0) {
+                            // wants to be as low as possible
+                            if (lower[iColumn] < -1.0e10 || fabs(lower[iColumn] - floor(lower[iColumn] + 0.5)) > 1.0e-10) {
+                                allGood = false;
+                                break;
+                            } else if (upper[iColumn] < 1.0e10 && fabs(upper[iColumn] - floor(upper[iColumn] + 0.5)) > 1.0e-10) {
+                                allGood = false;
+                                break;
+                            }
+                            bool singletonRow = true;
+                            bool equality = false;
+                            for (CoinBigIndex j = start; j < end; j++) {
+                                int iRow = row[j];
+                                if (count[iRow] > 1)
+                                    singletonRow = false;
+                                else if (rowLower[iRow] == rowUpper[iRow])
+                                    equality = true;
+                                double rhsValue = rhs[iRow];
+                                double lowerValue = rowLower[iRow];
+                                double upperValue = rowUpper[iRow];
+                                if (rhsValue < 1.0e20) {
+                                    if (lowerValue > -1.0e20)
+                                        lowerValue -= rhsValue;
+                                    if (upperValue < 1.0e20)
+                                        upperValue -= rhsValue;
+                                }
+                                if (fabs(rhsValue) > 1.0e20 || fabs(rhsValue - floor(rhsValue + 0.5)) > 1.0e-10
+                                        || fabs(element[j]) != 1.0) {
+                                    // no good
+                                    allGood = false;
+                                    break;
+                                }
+                                if (element[j] > 0.0) {
+                                    if (lowerValue > -1.0e20 && fabs(lowerValue - floor(lowerValue + 0.5)) > 1.0e-10) {
+                                        // no good
+                                        allGood = false;
+                                        break;
+                                    }
+                                } else {
+                                    if (upperValue < 1.0e20 && fabs(upperValue - floor(upperValue + 0.5)) > 1.0e-10) {
+                                        // no good
+                                        allGood = false;
+                                        break;
+                                    }
+                                }
+                            }
+                            if (!singletonRow && end > start + 1 && !equality)
+                                allGood = false;
+                            if (!allGood)
+                                break;
+                        } else {
+                            // wants to be as high as possible
+                            if (upper[iColumn] > 1.0e10 || fabs(upper[iColumn] - floor(upper[iColumn] + 0.5)) > 1.0e-10) {
+                                allGood = false;
+                                break;
+                            } else if (lower[iColumn] > -1.0e10 && fabs(lower[iColumn] - floor(lower[iColumn] + 0.5)) > 1.0e-10) {
+                                allGood = false;
+                                break;
+                            }
+                            bool singletonRow = true;
+                            bool equality = false;
+                            for (CoinBigIndex j = start; j < end; j++) {
+                                int iRow = row[j];
+                                if (count[iRow] > 1)
+                                    singletonRow = false;
+                                else if (rowLower[iRow] == rowUpper[iRow])
+                                    equality = true;
+                                double rhsValue = rhs[iRow];
+                                double lowerValue = rowLower[iRow];
+                                double upperValue = rowUpper[iRow];
+                                if (rhsValue < 1.0e20) {
+                                    if (lowerValue > -1.0e20)
+                                        lowerValue -= rhsValue;
+                                    if (upperValue < 1.0e20)
+                                        upperValue -= rhsValue;
+                                }
+                                if (fabs(rhsValue) > 1.0e20 || fabs(rhsValue - floor(rhsValue + 0.5)) > 1.0e-10
+                                        || fabs(element[j]) != 1.0) {
+                                    // no good
+                                    allGood = false;
+                                    break;
+                                }
+                                if (element[j] < 0.0) {
+                                    if (lowerValue > -1.0e20 && fabs(lowerValue - floor(lowerValue + 0.5)) > 1.0e-10) {
+                                        // no good
+                                        allGood = false;
+                                        break;
+                                    }
+                                } else {
+                                    if (upperValue < 1.0e20 && fabs(upperValue - floor(upperValue + 0.5)) > 1.0e-10) {
+                                        // no good
+                                        allGood = false;
+                                        break;
+                                    }
+                                }
+                            }
+                            if (!singletonRow && end > start + 1 && !equality)
+                                allGood = false;
+                            if (!allGood)
+                                break;
+                        }
+                    }
+                }
+            }
+            delete [] count;
+            if (allGood) {
+#if COIN_DEVELOP>1
+                if (numberObj)
+                    printf("YYYY analysis says all continuous with costs will be integer\n");
+#endif
+                continuousMultiplier = 1.0;
+            }
+        }
+        delete [] rhs;
+    }
+    /*
+      Take a first scan to see if there are unfixed continuous variables in the
+      objective.  If so, the minimum objective change could be arbitrarily small.
+      Also pick off the maximum coefficient of an unfixed integer variable.
+
+      If the objective is found to contain only integer variables, set the
+      fathoming discipline to strict.
+    */
+    double maximumCost = 0.0 ;
+    //double trueIncrement=0.0;
+    int iColumn ;
+    int numberColumns = getNumCols() ;
+    double scaleFactor = 1.0; // due to rhs etc
+    /*
+      Original model did not have integer bounds.
+    */
+    if ((specialOptions_&65536) == 0) {
+        /* be on safe side (later look carefully as may be able to
+           to get 0.5 say if bounds are multiples of 0.5 */
+        for (iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+            if (upper[iColumn] > lower[iColumn] + 1.0e-8) {
+                double value;
+                value = fabs(lower[iColumn]);
+                if (floor(value + 0.5) != value) {
+                    scaleFactor = CoinMin(scaleFactor, 0.5);
+                    if (floor(2.0*value + 0.5) != 2.0*value) {
+                        scaleFactor = CoinMin(scaleFactor, 0.25);
+                        if (floor(4.0*value + 0.5) != 4.0*value) {
+                            scaleFactor = 0.0;
+                        }
+                    }
+                }
+                value = fabs(upper[iColumn]);
+                if (floor(value + 0.5) != value) {
+                    scaleFactor = CoinMin(scaleFactor, 0.5);
+                    if (floor(2.0*value + 0.5) != 2.0*value) {
+                        scaleFactor = CoinMin(scaleFactor, 0.25);
+                        if (floor(4.0*value + 0.5) != 4.0*value) {
+                            scaleFactor = 0.0;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    bool possibleMultiple = continuousMultiplier != 0.0 && scaleFactor != 0.0 ;
+    if (possibleMultiple) {
+        for (iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+            if (upper[iColumn] > lower[iColumn] + 1.0e-8) {
+                maximumCost = CoinMax(maximumCost, fabs(objective[iColumn])) ;
+            }
+        }
+    }
+    setIntParam(CbcModel::CbcFathomDiscipline, possibleMultiple) ;
+    /*
+      If a nontrivial increment is possible, try and figure it out. We're looking
+      for gcd(c<j>) for all c<j> that are coefficients of unfixed integer
+      variables. Since the c<j> might not be integers, try and inflate them
+      sufficiently that they look like integers (and we'll deflate the gcd
+      later).
+
+      2520.0 is used as it is a nice multiple of 2,3,5,7
+    */
+    if (possibleMultiple && maximumCost) {
+        int increment = 0 ;
+        double multiplier = 2520.0 ;
+        while (10.0*multiplier*maximumCost < 1.0e8)
+            multiplier *= 10.0 ;
+        int bigIntegers = 0; // Count of large costs which are integer
+        for (iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+            if (upper[iColumn] > lower[iColumn] + 1.0e-8) {
+                double objValue = fabs(objective[iColumn]);
+                if (!isInteger(iColumn)) {
+                    if (!coeffMultiplier)
+                        objValue *= continuousMultiplier;
+                    else
+                        objValue *= coeffMultiplier[iColumn];
+                }
+                if (objValue) {
+                    double value = objValue * multiplier ;
+                    if (value < 2.1e9) {
+                        int nearest = static_cast<int> (floor(value + 0.5)) ;
+                        if (fabs(value - floor(value + 0.5)) > 1.0e-8) {
+                            increment = 0 ;
+                            break ;
+                        } else if (!increment) {
+                            increment = nearest ;
+                        } else {
+                            increment = gcd(increment, nearest) ;
+                        }
+                    } else {
+                        // large value - may still be multiple of 1.0
+                        if (fabs(objValue - floor(objValue + 0.5)) > 1.0e-8) {
+                            increment = 0;
+                            break;
+                        } else {
+                            bigIntegers++;
+                        }
+                    }
+                }
+            }
+        }
+        delete [] coeffMultiplier;
+        /*
+          If the increment beats the current value for objective change, install it.
+        */
+        if (increment) {
+            double value = increment ;
+            double cutoff = getDblParam(CbcModel::CbcCutoffIncrement) ;
+            if (bigIntegers) {
+                // allow for 1.0
+                increment = gcd(increment, static_cast<int> (multiplier));
+                value = increment;
+            }
+            value /= multiplier ;
+            value *= scaleFactor;
+            //trueIncrement=CoinMax(cutoff,value);;
+            if (value*0.999 > cutoff) {
+                messageHandler()->message(CBC_INTEGERINCREMENT,
+                                          messages())
+                << value << CoinMessageEol ;
+                setDblParam(CbcModel::CbcCutoffIncrement, CoinMax(value*0.999,value-1.0e-4)) ;
+            }
+        }
+    }
+
+    return ;
+}
+
+/*
+saveModel called (carved out of) BranchandBound
+*/
+void CbcModel::saveModel(OsiSolverInterface * saveSolver, double * checkCutoffForRestart, bool * feasible)
+{
+    if (saveSolver && (specialOptions_&32768) != 0) {
+        // See if worth trying reduction
+        *checkCutoffForRestart = getCutoff();
+        bool tryNewSearch = solverCharacteristics_->reducedCostsAccurate() &&
+                            (*checkCutoffForRestart < 1.0e20);
+        int numberColumns = getNumCols();
+        if (tryNewSearch) {
+#ifdef CLP_INVESTIGATE
+            printf("after %d nodes, cutoff %g - looking\n",
+                   numberNodes_, getCutoff());
+#endif
+            saveSolver->resolve();
+            double direction = saveSolver->getObjSense() ;
+            double gap = *checkCutoffForRestart - saveSolver->getObjValue() * direction ;
+            double tolerance;
+            saveSolver->getDblParam(OsiDualTolerance, tolerance) ;
+            if (gap <= 0.0)
+                gap = tolerance;
+            gap += 100.0 * tolerance;
+            double integerTolerance = getDblParam(CbcIntegerTolerance) ;
+
+            const double *lower = saveSolver->getColLower() ;
+            const double *upper = saveSolver->getColUpper() ;
+            const double *solution = saveSolver->getColSolution() ;
+            const double *reducedCost = saveSolver->getReducedCost() ;
+
+            int numberFixed = 0 ;
+            int numberFixed2 = 0;
+            for (int i = 0 ; i < numberIntegers_ ; i++) {
+                int iColumn = integerVariable_[i] ;
+                double djValue = direction * reducedCost[iColumn] ;
+                if (upper[iColumn] - lower[iColumn] > integerTolerance) {
+                    if (solution[iColumn] < lower[iColumn] + integerTolerance && djValue > gap) {
+                        saveSolver->setColUpper(iColumn, lower[iColumn]) ;
+                        numberFixed++ ;
+                    } else if (solution[iColumn] > upper[iColumn] - integerTolerance && -djValue > gap) {
+                        saveSolver->setColLower(iColumn, upper[iColumn]) ;
+                        numberFixed++ ;
+                    }
+                } else {
+                    numberFixed2++;
+                }
+            }
+#ifdef COIN_DEVELOP
+            /*
+              We're debugging. (specialOptions 1)
+            */
+            if ((specialOptions_&1) != 0) {
+                const OsiRowCutDebugger *debugger = saveSolver->getRowCutDebugger() ;
+                if (debugger) {
+                    printf("Contains optimal\n") ;
+                    OsiSolverInterface * temp = saveSolver->clone();
+                    const double * solution = debugger->optimalSolution();
+                    const double *lower = temp->getColLower() ;
+                    const double *upper = temp->getColUpper() ;
+                    int n = temp->getNumCols();
+                    for (int i = 0; i < n; i++) {
+                        if (temp->isInteger(i)) {
+                            double value = floor(solution[i] + 0.5);
+                            assert (value >= lower[i] && value <= upper[i]);
+                            temp->setColLower(i, value);
+                            temp->setColUpper(i, value);
+                        }
+                    }
+                    temp->writeMps("reduced_fix");
+                    delete temp;
+                    saveSolver->writeMps("reduced");
+                } else {
+                    abort();
+                }
+            }
+            printf("Restart could fix %d integers (%d already fixed)\n",
+                   numberFixed + numberFixed2, numberFixed2);
+#endif
+            numberFixed += numberFixed2;
+            if (numberFixed*20 < numberColumns)
+                tryNewSearch = false;
+        }
+        if (tryNewSearch) {
+            // back to solver without cuts?
+            OsiSolverInterface * solver2 = continuousSolver_->clone();
+            const double *lower = saveSolver->getColLower() ;
+            const double *upper = saveSolver->getColUpper() ;
+            for (int i = 0 ; i < numberIntegers_ ; i++) {
+                int iColumn = integerVariable_[i] ;
+                solver2->setColLower(iColumn, lower[iColumn]);
+                solver2->setColUpper(iColumn, upper[iColumn]);
+            }
+            // swap
+            delete saveSolver;
+            saveSolver = solver2;
+            double * newSolution = new double[numberColumns];
+            double objectiveValue = *checkCutoffForRestart;
+            CbcSerendipity heuristic(*this);
+            if (bestSolution_)
+                heuristic.setInputSolution(bestSolution_, bestObjective_);
+            heuristic.setFractionSmall(0.9);
+            heuristic.setFeasibilityPumpOptions(1008013);
+            // Use numberNodes to say how many are original rows
+            heuristic.setNumberNodes(continuousSolver_->getNumRows());
+#ifdef COIN_DEVELOP
+            if (continuousSolver_->getNumRows() <
+                    saveSolver->getNumRows())
+                printf("%d rows added ZZZZZ\n",
+                       solver_->getNumRows() - continuousSolver_->getNumRows());
+#endif
+            int returnCode = heuristic.smallBranchAndBound(saveSolver,
+                             -1, newSolution,
+                             objectiveValue,
+                             *checkCutoffForRestart, "Reduce");
+            if (returnCode < 0) {
+#ifdef COIN_DEVELOP
+                printf("Restart - not small enough to do search after fixing\n");
+#endif
+                delete [] newSolution;
+            } else {
+                if ((returnCode&1) != 0) {
+                    // increment number of solutions so other heuristics can test
+                    numberSolutions_++;
+                    numberHeuristicSolutions_++;
+                    lastHeuristic_ = NULL;
+                    setBestSolution(CBC_ROUNDING, objectiveValue, newSolution) ;
+                }
+                delete [] newSolution;
+                *feasible = false; // stop search
+            }
+#if 0 // probably not needed def CBC_THREAD
+            if (master_) {
+                lockThread();
+                if (parallelMode() > 0) {
+                    while (master_->waitForThreadsInTree(0)) {
+                        lockThread();
+                        double dummyBest;
+                        tree_->cleanTree(this, -COIN_DBL_MAX, dummyBest) ;
+                        //unlockThread();
+                    }
+                }
+                master_->waitForThreadsInTree(2);
+                delete master_;
+                master_ = NULL;
+                masterThread_ = NULL;
+            }
+#endif
+        }
+    }
+}
+/*
+Adds integers, called from BranchandBound()
+*/
+void CbcModel::AddIntegers()
+{
+    int numberColumns = continuousSolver_->getNumCols();
+    int numberRows = continuousSolver_->getNumRows();
+    int * del = new int [CoinMax(numberColumns, numberRows)];
+    int * original = new int [numberColumns];
+    char * possibleRow = new char [numberRows];
+    {
+        const CoinPackedMatrix * rowCopy = continuousSolver_->getMatrixByRow();
+        const int * column = rowCopy->getIndices();
+        const int * rowLength = rowCopy->getVectorLengths();
+        const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+        const double * rowLower = continuousSolver_->getRowLower();
+        const double * rowUpper = continuousSolver_->getRowUpper();
+        const double * element = rowCopy->getElements();
+        for (int i = 0; i < numberRows; i++) {
+            int nLeft = 0;
+            bool possible = false;
+            if (rowLower[i] < -1.0e20) {
+                double value = rowUpper[i];
+                if (fabs(value - floor(value + 0.5)) < 1.0e-8)
+                    possible = true;
+            } else if (rowUpper[i] > 1.0e20) {
+                double value = rowLower[i];
+                if (fabs(value - floor(value + 0.5)) < 1.0e-8)
+                    possible = true;
+            } else {
+                double value = rowUpper[i];
+                if (rowLower[i] == rowUpper[i] &&
+                        fabs(value - floor(value + 0.5)) < 1.0e-8)
+                    possible = true;
+            }
+	    double allSame = (possible) ? 0.0 : -1.0;
+            for (CoinBigIndex j = rowStart[i];
+                    j < rowStart[i] + rowLength[i]; j++) {
+                int iColumn = column[j];
+                if (continuousSolver_->isInteger(iColumn)) {
+                    if (fabs(element[j]) != 1.0)
+                        possible = false;
+                } else {
+                    nLeft++;
+		    if (!allSame) {
+		      allSame = fabs(element[j]);
+		    } else if (allSame>0.0) {
+		      if (allSame!=fabs(element[j]))
+			allSame = -1.0;
+		    }
+                }
+            }
+	    if (nLeft == rowLength[i] && allSame > 0.0)
+                possibleRow[i] = 2;
+            else if (possible || !nLeft)
+                possibleRow[i] = 1;
+            else
+                possibleRow[i] = 0;
+        }
+    }
+    int nDel = 0;
+    for (int i = 0; i < numberColumns; i++) {
+        original[i] = i;
+        if (continuousSolver_->isInteger(i))
+            del[nDel++] = i;
+    }
+    int nExtra = 0;
+    OsiSolverInterface * copy1 = continuousSolver_->clone();
+    int nPass = 0;
+    while (nDel && nPass < 10) {
+        nPass++;
+        OsiSolverInterface * copy2 = copy1->clone();
+        int nLeft = 0;
+        for (int i = 0; i < nDel; i++)
+            original[del[i]] = -1;
+        for (int i = 0; i < numberColumns; i++) {
+            int kOrig = original[i];
+            if (kOrig >= 0)
+                original[nLeft++] = kOrig;
+        }
+        assert (nLeft == numberColumns - nDel);
+        copy2->deleteCols(nDel, del);
+        numberColumns = copy2->getNumCols();
+        const CoinPackedMatrix * rowCopy = copy2->getMatrixByRow();
+        numberRows = rowCopy->getNumRows();
+        const int * column = rowCopy->getIndices();
+        const int * rowLength = rowCopy->getVectorLengths();
+        const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+        const double * rowLower = copy2->getRowLower();
+        const double * rowUpper = copy2->getRowUpper();
+        const double * element = rowCopy->getElements();
+        const CoinPackedMatrix * columnCopy = copy2->getMatrixByCol();
+        const int * columnLength = columnCopy->getVectorLengths();
+        nDel = 0;
+        // Could do gcd stuff on ones with costs
+        for (int i = 0; i < numberRows; i++) {
+            if (!rowLength[i]) {
+                del[nDel++] = i;
+            } else if (possibleRow[i]) {
+                if (rowLength[i] == 1) {
+                    int k = rowStart[i];
+                    int iColumn = column[k];
+                    if (!copy2->isInteger(iColumn)) {
+                        double mult = 1.0 / fabs(element[k]);
+                        if (rowLower[i] < -1.0e20) {
+			    // treat rhs as multiple of 1 unless elements all same
+			    double value = ((possibleRow[i]==2) ? rowUpper[i] : 1.0) * mult;
+                            if (fabs(value - floor(value + 0.5)) < 1.0e-8) {
+                                del[nDel++] = i;
+                                if (columnLength[iColumn] == 1) {
+                                    copy2->setInteger(iColumn);
+                                    int kOrig = original[iColumn];
+                                    setOptionalInteger(kOrig);
+                                }
+                            }
+                        } else if (rowUpper[i] > 1.0e20) {
+			    // treat rhs as multiple of 1 unless elements all same
+			    double value = ((possibleRow[i]==2) ? rowLower[i] : 1.0) * mult;
+                            if (fabs(value - floor(value + 0.5)) < 1.0e-8) {
+                                del[nDel++] = i;
+                                if (columnLength[iColumn] == 1) {
+                                    copy2->setInteger(iColumn);
+                                    int kOrig = original[iColumn];
+                                    setOptionalInteger(kOrig);
+                                }
+                            }
+                        } else {
+			    // treat rhs as multiple of 1 unless elements all same
+			    double value = ((possibleRow[i]==2) ? rowUpper[i] : 1.0) * mult;
+                            if (rowLower[i] == rowUpper[i] &&
+                                    fabs(value - floor(value + 0.5)) < 1.0e-8) {
+                                del[nDel++] = i;
+                                copy2->setInteger(iColumn);
+                                int kOrig = original[iColumn];
+                                setOptionalInteger(kOrig);
+                            }
+                        }
+                    }
+                } else {
+                    // only if all singletons
+                    bool possible = false;
+                    if (rowLower[i] < -1.0e20) {
+                        double value = rowUpper[i];
+                        if (fabs(value - floor(value + 0.5)) < 1.0e-8)
+                            possible = true;
+                    } else if (rowUpper[i] > 1.0e20) {
+                        double value = rowLower[i];
+                        if (fabs(value - floor(value + 0.5)) < 1.0e-8)
+                            possible = true;
+                    } else {
+                        double value = rowUpper[i];
+                        if (rowLower[i] == rowUpper[i] &&
+                                fabs(value - floor(value + 0.5)) < 1.0e-8)
+                            possible = true;
+                    }
+                    if (possible) {
+                        for (CoinBigIndex j = rowStart[i];
+                                j < rowStart[i] + rowLength[i]; j++) {
+                            int iColumn = column[j];
+                            if (columnLength[iColumn] != 1 || fabs(element[j]) != 1.0) {
+                                possible = false;
+                                break;
+                            }
+                        }
+                        if (possible) {
+                            for (CoinBigIndex j = rowStart[i];
+                                    j < rowStart[i] + rowLength[i]; j++) {
+                                int iColumn = column[j];
+                                if (!copy2->isInteger(iColumn)) {
+                                    copy2->setInteger(iColumn);
+                                    int kOrig = original[iColumn];
+                                    setOptionalInteger(kOrig);
+                                }
+                            }
+                            del[nDel++] = i;
+                        }
+                    }
+                }
+            }
+        }
+        if (nDel) {
+            copy2->deleteRows(nDel, del);
+	    // pack down possible
+	    int n=0;
+	    for (int i=0;i<nDel;i++)
+	      possibleRow[del[i]]=-1;
+	    for (int i=0;i<numberRows;i++) {
+	      if (possibleRow[i]>=0) 
+		possibleRow[n++]=possibleRow[i];
+	    }
+        }
+        if (nDel != numberRows) {
+            nDel = 0;
+            for (int i = 0; i < numberColumns; i++) {
+                if (copy2->isInteger(i)) {
+                    del[nDel++] = i;
+                    nExtra++;
+                }
+            }
+        } else {
+            nDel = 0;
+        }
+        delete copy1;
+        copy1 = copy2->clone();
+        delete copy2;
+    }
+    // See if what's left is a network
+    bool couldBeNetwork = false;
+    if (copy1->getNumRows() && copy1->getNumCols()) {
+#ifdef COIN_HAS_CLP
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (copy1);
+        if (false && clpSolver) {
+            numberRows = clpSolver->getNumRows();
+            char * rotate = new char[numberRows];
+            int n = clpSolver->getModelPtr()->findNetwork(rotate, 1.0);
+            delete [] rotate;
+#ifdef CLP_INVESTIGATE
+            printf("INTA network %d rows out of %d\n", n, numberRows);
+#endif
+            if (CoinAbs(n) == numberRows) {
+                couldBeNetwork = true;
+                for (int i = 0; i < numberRows; i++) {
+                    if (!possibleRow[i]) {
+                        couldBeNetwork = false;
+#ifdef CLP_INVESTIGATE
+                        printf("but row %d is bad\n", i);
+#endif
+                        break;
+                    }
+                }
+            }
+        } else
+#endif
+        {
+            numberColumns = copy1->getNumCols();
+            numberRows = copy1->getNumRows();
+            const double * rowLower = copy1->getRowLower();
+            const double * rowUpper = copy1->getRowUpper();
+            couldBeNetwork = true;
+            for (int i = 0; i < numberRows; i++) {
+                if (rowLower[i] > -1.0e20 && fabs(rowLower[i] - floor(rowLower[i] + 0.5)) > 1.0e-12) {
+                    couldBeNetwork = false;
+                    break;
+                }
+                if (rowUpper[i] < 1.0e20 && fabs(rowUpper[i] - floor(rowUpper[i] + 0.5)) > 1.0e-12) {
+                    couldBeNetwork = false;
+                    break;
+                }
+		if (possibleRow[i]==0) {
+                    couldBeNetwork = false;
+                    break;
+		}
+            }
+            if (couldBeNetwork) {
+                const CoinPackedMatrix  * matrixByCol = copy1->getMatrixByCol();
+                const double * element = matrixByCol->getElements();
+                //const int * row = matrixByCol->getIndices();
+                const CoinBigIndex * columnStart = matrixByCol->getVectorStarts();
+                const int * columnLength = matrixByCol->getVectorLengths();
+                for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = start + columnLength[iColumn];
+                    if (end > start + 2) {
+                        couldBeNetwork = false;
+                        break;
+                    }
+                    int type = 0;
+                    for (CoinBigIndex j = start; j < end; j++) {
+                        double value = element[j];
+                        if (fabs(value) != 1.0) {
+                            couldBeNetwork = false;
+                            break;
+                        } else if (value == 1.0) {
+                            if ((type&1) == 0)
+                                type |= 1;
+                            else
+                                type = 7;
+                        } else if (value == -1.0) {
+                            if ((type&2) == 0)
+                                type |= 2;
+                            else
+                                type = 7;
+                        }
+                    }
+                    if (type > 3) {
+                        couldBeNetwork = false;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    if (couldBeNetwork) {
+        for (int i = 0; i < numberColumns; i++)
+            setOptionalInteger(original[i]);
+    }
+    if (nExtra || couldBeNetwork) {
+        numberColumns = copy1->getNumCols();
+        numberRows = copy1->getNumRows();
+        if (!numberColumns || !numberRows) {
+            int numberColumns = solver_->getNumCols();
+            for (int i = 0; i < numberColumns; i++)
+                assert(solver_->isInteger(i));
+        }
+#ifdef CLP_INVESTIGATE
+        if (couldBeNetwork || nExtra)
+            printf("INTA %d extra integers, %d left%s\n", nExtra,
+                   numberColumns,
+                   couldBeNetwork ? ", all network" : "");
+#endif
+        findIntegers(true, 2);
+        convertToDynamic();
+    }
+#ifdef CLP_INVESTIGATE
+    if (!couldBeNetwork && copy1->getNumCols() &&
+            copy1->getNumRows()) {
+        printf("INTA %d rows and %d columns remain\n",
+               copy1->getNumRows(), copy1->getNumCols());
+        if (copy1->getNumCols() < 200) {
+            copy1->writeMps("moreint");
+            printf("INTA Written remainder to moreint.mps.gz %d rows %d cols\n",
+                   copy1->getNumRows(), copy1->getNumCols());
+        }
+    }
+#endif
+    delete copy1;
+    delete [] del;
+    delete [] original;
+    delete [] possibleRow;
+    // double check increment
+    analyzeObjective();
+}
+/**
+  \todo
+  Normally, it looks like we enter here from command dispatch in the main
+  routine, after calling the solver for an initial solution
+  (CbcModel::initialSolve, which simply calls the solver's initialSolve
+  routine.) The first thing we do is call resolve. Presumably there are
+  circumstances where this is nontrivial? There's also a call from
+  CbcModel::originalModel (tied up with integer presolve), which should be
+  checked.
+
+*/
+
+/*
+  The overall flow can be divided into three stages:
+    * Prep: Check that the lp relaxation remains feasible at the root. If so,
+      do all the setup for B&C.
+    * Process the root node: Generate cuts, apply heuristics, and in general do
+      the best we can to resolve the problem without B&C.
+    * Do B&C search until we hit a limit or exhaust the search tree.
+
+  Keep in mind that in general there is no node in the search tree that
+  corresponds to the active subproblem. The active subproblem is represented
+  by the current state of the model,  of the solver, and of the constraint
+  system held by the solver.
+*/
+#ifdef COIN_HAS_CPX
+#include "OsiCpxSolverInterface.hpp"
+#include "cplex.h"
+#endif
+void CbcModel::branchAndBound(int doStatistics)
+
+{
+  if (!parentModel_)
+    /*
+      Capture a time stamp before we start (unless set).
+    */
+    if (!dblParam_[CbcStartSeconds]) {
+      if (!useElapsedTime())
+	dblParam_[CbcStartSeconds] = CoinCpuTime();
+      else
+	dblParam_[CbcStartSeconds] = CoinGetTimeOfDay();
+    }
+    dblParam_[CbcSmallestChange] = COIN_DBL_MAX;
+    dblParam_[CbcSumChange] = 0.0;
+    dblParam_[CbcLargestChange] = 0.0;
+    intParam_[CbcNumberBranches] = 0;
+    // Force minimization !!!!
+    bool flipObjective = (solver_->getObjSense()<0.0);
+    if (flipObjective)
+      flipModel();
+    dblParam_[CbcOptimizationDirection] = 1.0; // was solver_->getObjSense();
+    strongInfo_[0] = 0;
+    strongInfo_[1] = 0;
+    strongInfo_[2] = 0;
+    strongInfo_[3] = 0;
+    strongInfo_[4] = 0;
+    strongInfo_[5] = 0;
+    strongInfo_[6] = 0;
+    numberStrongIterations_ = 0;
+    currentNode_ = NULL;
+    // See if should do cuts old way
+    if (parallelMode() < 0) {
+        specialOptions_ |= 4096 + 8192;
+    } else if (parallelMode() > 0) {
+        specialOptions_ |= 4096;
+    }
+    int saveMoreSpecialOptions = moreSpecialOptions_;
+    if (dynamic_cast<CbcTreeLocal *> (tree_))
+        specialOptions_ |= 4096 + 8192;
+#ifdef COIN_HAS_CLP
+    {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver) {
+            // pass in disaster handler
+            CbcDisasterHandler handler(this);
+            clpSolver->passInDisasterHandler(&handler);
+            // Initialise solvers seed (unless users says not)
+	    if ((specialOptions_&4194304)==0)
+	      clpSolver->getModelPtr()->setRandomSeed(1234567);
+#ifdef JJF_ZERO
+            // reduce factorization frequency
+            int frequency = clpSolver->getModelPtr()->factorizationFrequency();
+            clpSolver->getModelPtr()->setFactorizationFrequency(CoinMin(frequency, 120));
+#endif
+        }
+    }
+#endif
+    // original solver (only set if pre-processing)
+    OsiSolverInterface * originalSolver = NULL;
+    int numberOriginalObjects = numberObjects_;
+    OsiObject ** originalObject = NULL;
+    // Save whether there were any objects
+    bool noObjects = (numberObjects_ == 0);
+    // Set up strategies
+    /*
+      See if the user has supplied a strategy object and deal with it if present.
+      The call to setupOther will set numberStrong_ and numberBeforeTrust_, and
+      perform integer preprocessing, if requested.
+
+      We need to hang on to a pointer to solver_. setupOther will assign a
+      preprocessed solver to model, but will instruct assignSolver not to trash the
+      existing one.
+    */
+    if (strategy_) {
+        // May do preprocessing
+        originalSolver = solver_;
+        strategy_->setupOther(*this);
+        if (strategy_->preProcessState()) {
+            // pre-processing done
+            if (strategy_->preProcessState() < 0) {
+                // infeasible (or unbounded)
+                status_ = 0 ;
+		if (!solver_->isProvenDualInfeasible()) {
+		  handler_->message(CBC_INFEAS, messages_) << CoinMessageEol ;
+		  secondaryStatus_ = 1;
+		} else {
+		  handler_->message(CBC_UNBOUNDED, 
+				    messages_) << CoinMessageEol ;
+		  secondaryStatus_ = 7;
+		}
+                originalContinuousObjective_ = COIN_DBL_MAX;
+		if (flipObjective)
+		  flipModel();
+                return ;
+            } else if (numberObjects_ && object_) {
+                numberOriginalObjects = numberObjects_;
+                // redo sequence
+                numberIntegers_ = 0;
+                int numberColumns = getNumCols();
+                int nOrig = originalSolver->getNumCols();
+                CglPreProcess * process = strategy_->process();
+                assert (process);
+                const int * originalColumns = process->originalColumns();
+                // allow for cliques etc
+                nOrig = CoinMax(nOrig, originalColumns[numberColumns-1] + 1);
+                // try and redo debugger
+                OsiRowCutDebugger * debugger = const_cast<OsiRowCutDebugger *> (solver_->getRowCutDebuggerAlways());
+                if (debugger) {
+		  if (numberColumns<=debugger->numberColumns())
+                    debugger->redoSolution(numberColumns, originalColumns);
+		  else
+		    debugger=NULL; // no idea how to handle (SOS?)
+		}
+                // User-provided solution might have been best. Synchronise.
+                if (bestSolution_) {
+                    // need to redo - in case no better found in BAB
+                    // just get integer part right
+                    for (int i = 0; i < numberColumns; i++) {
+                        int jColumn = originalColumns[i];
+                        bestSolution_[i] = bestSolution_[jColumn];
+                    }
+                }
+                originalObject = object_;
+                // object number or -1
+                int * temp = new int[nOrig];
+                int iColumn;
+                for (iColumn = 0; iColumn < nOrig; iColumn++)
+                    temp[iColumn] = -1;
+                int iObject;
+                int nNonInt = 0;
+                for (iObject = 0; iObject < numberOriginalObjects; iObject++) {
+                    iColumn = originalObject[iObject]->columnNumber();
+                    if (iColumn < 0) {
+                        nNonInt++;
+                    } else {
+                        temp[iColumn] = iObject;
+                    }
+                }
+                int numberNewIntegers = 0;
+                int numberOldIntegers = 0;
+                int numberOldOther = 0;
+                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    int jColumn = originalColumns[iColumn];
+                    if (temp[jColumn] >= 0) {
+                        int iObject = temp[jColumn];
+                        CbcSimpleInteger * obj =
+                            dynamic_cast <CbcSimpleInteger *>(originalObject[iObject]) ;
+                        if (obj)
+                            numberOldIntegers++;
+                        else
+                            numberOldOther++;
+                    } else if (isInteger(iColumn)) {
+                        numberNewIntegers++;
+                    }
+                }
+                /*
+                  Allocate an array to hold the indices of the integer variables.
+                  Make a large enough array for all objects
+                */
+                numberObjects_ = numberNewIntegers + numberOldIntegers + numberOldOther + nNonInt;
+                object_ = new OsiObject * [numberObjects_];
+                delete [] integerVariable_;
+                integerVariable_ = new int [numberNewIntegers+numberOldIntegers];
+                /*
+                  Walk the variables again, filling in the indices and creating objects for
+                  the integer variables. Initially, the objects hold the index and upper &
+                  lower bounds.
+                */
+                numberIntegers_ = 0;
+                int n = originalColumns[numberColumns-1] + 1;
+                int * backward = new int[n];
+                int i;
+                for ( i = 0; i < n; i++)
+                    backward[i] = -1;
+                for (i = 0; i < numberColumns; i++)
+                    backward[originalColumns[i]] = i;
+                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    int jColumn = originalColumns[iColumn];
+                    if (temp[jColumn] >= 0) {
+                        int iObject = temp[jColumn];
+                        CbcSimpleInteger * obj =
+                            dynamic_cast <CbcSimpleInteger *>(originalObject[iObject]) ;
+                        if (obj) {
+                            object_[numberIntegers_] = originalObject[iObject]->clone();
+                            // redo ids etc
+                            //object_[numberIntegers_]->resetSequenceEtc(numberColumns,originalColumns);
+                            object_[numberIntegers_]->resetSequenceEtc(numberColumns, backward);
+                            integerVariable_[numberIntegers_++] = iColumn;
+                        }
+                    } else if (isInteger(iColumn)) {
+                        object_[numberIntegers_] =
+                            new CbcSimpleInteger(this, iColumn);
+                        integerVariable_[numberIntegers_++] = iColumn;
+                    }
+                }
+                delete [] backward;
+                numberObjects_ = numberIntegers_;
+                // Now append other column stuff
+                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    int jColumn = originalColumns[iColumn];
+                    if (temp[jColumn] >= 0) {
+                        int iObject = temp[jColumn];
+                        CbcSimpleInteger * obj =
+                            dynamic_cast <CbcSimpleInteger *>(originalObject[iObject]) ;
+                        if (!obj) {
+                            object_[numberObjects_] = originalObject[iObject]->clone();
+                            // redo ids etc
+                            CbcObject * obj =
+                                dynamic_cast <CbcObject *>(object_[numberObjects_]) ;
+                            assert (obj);
+                            obj->redoSequenceEtc(this, numberColumns, originalColumns);
+                            numberObjects_++;
+                        }
+                    }
+                }
+                // now append non column stuff
+                for (iObject = 0; iObject < numberOriginalObjects; iObject++) {
+                    iColumn = originalObject[iObject]->columnNumber();
+                    if (iColumn < 0) {
+                        // already has column numbers changed
+                        object_[numberObjects_] = originalObject[iObject]->clone();
+#ifdef JJF_ZERO
+                        // redo ids etc
+                        CbcObject * obj =
+                            dynamic_cast <CbcObject *>(object_[numberObjects_]) ;
+                        assert (obj);
+                        obj->redoSequenceEtc(this, numberColumns, originalColumns);
+#endif
+                        numberObjects_++;
+                    }
+                }
+                delete [] temp;
+                if (!numberObjects_)
+                    handler_->message(CBC_NOINT, messages_) << CoinMessageEol ;
+            } else {
+                int numberColumns = getNumCols();
+                CglPreProcess * process = strategy_->process();
+                assert (process);
+                const int * originalColumns = process->originalColumns();
+                // try and redo debugger
+                OsiRowCutDebugger * debugger = const_cast<OsiRowCutDebugger *> (solver_->getRowCutDebuggerAlways());
+                if (debugger)
+                    debugger->redoSolution(numberColumns, originalColumns);
+            }
+        } else {
+            //no preprocessing
+            originalSolver = NULL;
+        }
+        strategy_->setupCutGenerators(*this);
+        strategy_->setupHeuristics(*this);
+        // Set strategy print level to models
+        strategy_->setupPrinting(*this, handler_->logLevel());
+    }
+    eventHappened_ = false;
+    CbcEventHandler *eventHandler = getEventHandler() ;
+    if (eventHandler)
+        eventHandler->setModel(this);
+#define CLIQUE_ANALYSIS
+#ifdef CLIQUE_ANALYSIS
+    // set up for probing
+    // If we're doing clever stuff with cliques, additional info here.
+    if (!parentModel_)
+        probingInfo_ = new CglTreeProbingInfo(solver_);
+    else
+        probingInfo_ = NULL;
+#else
+    probingInfo_ = NULL;
+#endif
+
+    // Try for dominated columns
+    if ((specialOptions_&64) != 0) {
+        CglDuplicateRow dupcuts(solver_);
+        dupcuts.setMode(2);
+        CglStored * storedCuts = dupcuts.outDuplicates(solver_);
+        if (storedCuts) {
+	  COIN_DETAIL_PRINT(printf("adding dup cuts\n"));
+            addCutGenerator(storedCuts, 1, "StoredCuts from dominated",
+                            true, false, false, -200);
+        }
+    }
+    if (!nodeCompare_)
+        nodeCompare_ = new CbcCompareDefault();;
+    // See if hot start wanted
+    CbcCompareBase * saveCompare = NULL;
+    // User supplied hotstart. Adapt for preprocessing.
+    if (hotstartSolution_) {
+        if (strategy_ && strategy_->preProcessState() > 0) {
+            CglPreProcess * process = strategy_->process();
+            assert (process);
+            int n = solver_->getNumCols();
+            const int * originalColumns = process->originalColumns();
+            // columns should be in order ... but
+            double * tempS = new double[n];
+            for (int i = 0; i < n; i++) {
+                int iColumn = originalColumns[i];
+                tempS[i] = hotstartSolution_[iColumn];
+            }
+            delete [] hotstartSolution_;
+            hotstartSolution_ = tempS;
+            if (hotstartPriorities_) {
+                int * tempP = new int [n];
+                for (int i = 0; i < n; i++) {
+                    int iColumn = originalColumns[i];
+                    tempP[i] = hotstartPriorities_[iColumn];
+                }
+                delete [] hotstartPriorities_;
+                hotstartPriorities_ = tempP;
+            }
+        }
+        saveCompare = nodeCompare_;
+        // depth first
+        nodeCompare_ = new CbcCompareDepth();
+    }
+    if (!problemFeasibility_)
+        problemFeasibility_ = new CbcFeasibilityBase();
+# ifdef CBC_DEBUG
+    std::string problemName ;
+    solver_->getStrParam(OsiProbName, problemName) ;
+    printf("Problem name - %s\n", problemName.c_str()) ;
+    solver_->setHintParam(OsiDoReducePrint, false, OsiHintDo, 0) ;
+# endif
+    /*
+      Assume we're done, and see if we're proven wrong.
+    */
+    status_ = 0 ;
+    secondaryStatus_ = 0;
+    phase_ = 0;
+    /*
+      Scan the variables, noting the integer variables. Create an
+      CbcSimpleInteger object for each integer variable.
+    */
+    findIntegers(false) ;
+    // Say not dynamic pseudo costs
+    ownership_ &= ~0x40000000;
+    // If dynamic pseudo costs then do
+    if (numberBeforeTrust_)
+        convertToDynamic();
+    // Set up char array to say if integer (speed)
+    delete [] integerInfo_;
+    {
+        int n = solver_->getNumCols();
+        integerInfo_ = new char [n];
+        for (int i = 0; i < n; i++) {
+            if (solver_->isInteger(i))
+                integerInfo_[i] = 1;
+            else
+                integerInfo_[i] = 0;
+        }
+    }
+    if (preferredWay_) {
+        // set all unset ones
+        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
+            CbcObject * obj =
+                dynamic_cast <CbcObject *>(object_[iObject]) ;
+            if (obj && !obj->preferredWay())
+                obj->setPreferredWay(preferredWay_);
+        }
+    }
+    /*
+      Ensure that objects on the lists of OsiObjects, heuristics, and cut
+      generators attached to this model all refer to this model.
+    */
+    synchronizeModel() ;
+    if (!solverCharacteristics_) {
+        OsiBabSolver * solverCharacteristics = dynamic_cast<OsiBabSolver *> (solver_->getAuxiliaryInfo());
+        if (solverCharacteristics) {
+            solverCharacteristics_ = solverCharacteristics;
+        } else {
+            // replace in solver
+            OsiBabSolver defaultC;
+            solver_->setAuxiliaryInfo(&defaultC);
+            solverCharacteristics_ = dynamic_cast<OsiBabSolver *> (solver_->getAuxiliaryInfo());
+        }
+    }
+
+    solverCharacteristics_->setSolver(solver_);
+    // Set so we can tell we are in initial phase in resolve
+    continuousObjective_ = -COIN_DBL_MAX ;
+    /*
+      Solve the relaxation.
+
+      Apparently there are circumstances where this will be non-trivial --- i.e.,
+      we've done something since initialSolve that's trashed the solution to the
+      continuous relaxation.
+    */
+    /* Tell solver we are in Branch and Cut
+       Could use last parameter for subtle differences */
+    solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+#ifdef COIN_HAS_CLP
+    {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver) {
+            ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+            if ((specialOptions_&32) == 0) {
+                // take off names
+                clpSimplex->dropNames();
+            }
+            // no crunch if mostly continuous
+            if ((clpSolver->specialOptions()&(1 + 8)) != (1 + 8)) {
+                int numberColumns = solver_->getNumCols();
+                if (numberColumns > 1000 && numberIntegers_*4 < numberColumns)
+                    clpSolver->setSpecialOptions(clpSolver->specialOptions()&(~1));
+            }
+            //#define NO_CRUNCH
+#ifdef NO_CRUNCH
+            printf("TEMP switching off crunch\n");
+            int iOpt = clpSolver->specialOptions();
+            iOpt &= ~1;
+            iOpt |= 65536;
+            clpSolver->setSpecialOptions(iOpt);
+#endif
+        }
+    }
+#endif
+    bool feasible;
+    numberSolves_ = 0 ;
+    // If NLP then we assume already solved outside branchAndbound
+    if (!solverCharacteristics_->solverType() || solverCharacteristics_->solverType() == 4) {
+        feasible = resolve(NULL, 0) != 0 ;
+    } else {
+        // pick up given status
+        feasible = (solver_->isProvenOptimal() &&
+                    !solver_->isDualObjectiveLimitReached()) ;
+    }
+    if (problemFeasibility_->feasible(this, 0) < 0) {
+        feasible = false; // pretend infeasible
+    }
+    numberSavedSolutions_ = 0;
+    int saveNumberStrong = numberStrong_;
+    int saveNumberBeforeTrust = numberBeforeTrust_;
+    /*
+      If the linear relaxation of the root is infeasible, bail out now. Otherwise,
+      continue with processing the root node.
+    */
+    if (!feasible) {
+        status_ = 0 ;
+        if (!solver_->isProvenDualInfeasible()) {
+            handler_->message(CBC_INFEAS, messages_) << CoinMessageEol ;
+            secondaryStatus_ = 1;
+        } else {
+            handler_->message(CBC_UNBOUNDED, messages_) << CoinMessageEol ;
+            secondaryStatus_ = 7;
+        }
+        originalContinuousObjective_ = COIN_DBL_MAX;
+        solverCharacteristics_ = NULL;
+	if (flipObjective)
+	  flipModel();
+        return ;
+    } else if (!numberObjects_ && (!strategy_ || strategy_->preProcessState() <= 0)) {
+        // nothing to do
+        if (flipObjective)
+	  flipModel();
+        solverCharacteristics_ = NULL;
+        bestObjective_ = solver_->getObjValue() * solver_->getObjSense();
+        int numberColumns = solver_->getNumCols();
+        delete [] bestSolution_;
+        bestSolution_ = new double[numberColumns];
+        CoinCopyN(solver_->getColSolution(), numberColumns, bestSolution_);
+        return ;
+    }
+    /*
+      See if we're using the Osi side of the branching hierarchy. If so, either
+      convert existing CbcObjects to OsiObjects, or generate them fresh. In the
+      first case, CbcModel owns the objects on the object_ list. In the second
+      case, the solver holds the objects and object_ simply points to the
+      solver's list.
+
+      080417 The conversion code here (the block protected by `if (obj)') cannot
+      possibly be correct. On the Osi side, descent is OsiObject -> OsiObject2 ->
+      all other Osi object classes. On the Cbc side, it's OsiObject -> CbcObject
+      -> all other Cbc object classes. It's structurally impossible for any Osi
+      object to descend from CbcObject. The only thing I can see is that this is
+      really dead code, and object detection is now handled from the Osi side.
+    */
+    // Convert to Osi if wanted
+    //OsiBranchingInformation * persistentInfo = NULL;
+    if (branchingMethod_ && branchingMethod_->chooseMethod()) {
+        //persistentInfo = new OsiBranchingInformation(solver_);
+        if (numberOriginalObjects) {
+            for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
+                CbcObject * obj =
+                    dynamic_cast <CbcObject *>(object_[iObject]) ;
+                if (obj) {
+                    CbcSimpleInteger * obj2 =
+                        dynamic_cast <CbcSimpleInteger *>(obj) ;
+                    if (obj2) {
+                        // back to Osi land
+                        object_[iObject] = obj2->osiObject();
+                        delete obj;
+                    } else {
+                        OsiSimpleInteger * obj3 =
+                            dynamic_cast <OsiSimpleInteger *>(obj) ;
+                        if (!obj3) {
+                            OsiSOS * obj4 =
+                                dynamic_cast <OsiSOS *>(obj) ;
+                            if (!obj4) {
+                                CbcSOS * obj5 =
+                                    dynamic_cast <CbcSOS *>(obj) ;
+                                if (obj5) {
+                                    // back to Osi land
+                                    object_[iObject] = obj5->osiObject(solver_);
+                                } else {
+                                    printf("Code up CbcObject type in Osi land\n");
+                                    abort();
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            // and add to solver
+            //if (!solver_->numberObjects()) {
+            solver_->addObjects(numberObjects_, object_);
+            //} else {
+            //if (solver_->numberObjects()!=numberOriginalObjects) {
+            //printf("should have trapped that solver has objects before\n");
+            //abort();
+            //}
+            //}
+        } else {
+            /*
+              As of 080104, findIntegersAndSOS is misleading --- the default OSI
+              implementation finds only integers.
+            */
+            // do from solver
+            deleteObjects(false);
+            solver_->findIntegersAndSOS(false);
+            numberObjects_ = solver_->numberObjects();
+            object_ = solver_->objects();
+            ownObjects_ = false;
+        }
+        branchingMethod_->chooseMethod()->setSolver(solver_);
+    }
+    // take off heuristics if have to (some do not work with SOS, for example)
+    // object should know what's safe.
+    {
+        int numberOdd = 0;
+        int numberSOS = 0;
+        for (int i = 0; i < numberObjects_; i++) {
+            if (!object_[i]->canDoHeuristics())
+                numberOdd++;
+            CbcSOS * obj =
+                dynamic_cast <CbcSOS *>(object_[i]) ;
+            if (obj)
+                numberSOS++;
+        }
+        if (numberOdd) {
+            if (numberHeuristics_) {
+                int k = 0;
+                for (int i = 0; i < numberHeuristics_; i++) {
+                    if (!heuristic_[i]->canDealWithOdd())
+                        delete heuristic_[i];
+                    else
+                        heuristic_[k++] = heuristic_[i];
+                }
+                if (!k) {
+                    delete [] heuristic_;
+                    heuristic_ = NULL;
+                }
+                numberHeuristics_ = k;
+                handler_->message(CBC_HEURISTICS_OFF, messages_) << numberOdd << CoinMessageEol ;
+            }
+	    // If odd switch off AddIntegers
+	    specialOptions_ &= ~65536;
+        } else if (numberSOS) {
+            specialOptions_ |= 128; // say can do SOS in dynamic mode
+            // switch off fast nodes for now
+            fastNodeDepth_ = -1;
+	    moreSpecialOptions_ &= ~33554432; // no diving
+        }
+        if (numberThreads_ > 0) {
+            // switch off fast nodes for now
+            fastNodeDepth_ = -1;
+        }
+    }
+    // Save objective (just so user can access it)
+    originalContinuousObjective_ = solver_->getObjValue()* solver_->getObjSense();
+    bestPossibleObjective_ = originalContinuousObjective_;
+    sumChangeObjective1_ = 0.0;
+    sumChangeObjective2_ = 0.0;
+    /*
+      OsiRowCutDebugger knows an optimal answer for a subset of MIP problems.
+      Assuming it recognises the problem, when called upon it will check a cut to
+      see if it cuts off the optimal answer.
+    */
+    // If debugger exists set specialOptions_ bit
+    if (solver_->getRowCutDebuggerAlways()) {
+        specialOptions_ |= 1;
+    }
+
+# ifdef CBC_DEBUG
+    if ((specialOptions_&1) == 0)
+        solver_->activateRowCutDebugger(problemName.c_str()) ;
+    if (solver_->getRowCutDebuggerAlways())
+        specialOptions_ |= 1;
+# endif
+
+    /*
+      Begin setup to process a feasible root node.
+    */
+    bestObjective_ = CoinMin(bestObjective_, 1.0e50) ;
+    if (!bestSolution_) {
+        numberSolutions_ = 0 ;
+        numberHeuristicSolutions_ = 0 ;
+    }
+    stateOfSearch_ = 0;
+    // Everything is minimization
+    {
+        // needed to sync cutoffs
+        double value ;
+        solver_->getDblParam(OsiDualObjectiveLimit, value) ;
+        dblParam_[CbcCurrentCutoff] = value * solver_->getObjSense();
+    }
+    double cutoff = getCutoff() ;
+    double direction = solver_->getObjSense() ;
+    dblParam_[CbcOptimizationDirection] = direction;
+    if (cutoff < 1.0e20 && direction < 0.0)
+        messageHandler()->message(CBC_CUTOFF_WARNING1,
+                                  messages())
+        << cutoff << -cutoff << CoinMessageEol ;
+    if (cutoff > bestObjective_)
+        cutoff = bestObjective_ ;
+    setCutoff(cutoff) ;
+    /*
+      We probably already have a current solution, but just in case ...
+    */
+    int numberColumns = getNumCols() ;
+    if (!currentSolution_)
+        currentSolution_ = new double[numberColumns] ;
+    testSolution_ = currentSolution_;
+    /*
+      Create a copy of the solver, thus capturing the original (root node)
+      constraint system (aka the continuous system).
+    */
+    continuousSolver_ = solver_->clone() ;
+
+    // add cutoff as constraint if wanted
+    if (cutoffRowNumber_==-2) {
+      if (!parentModel_) {
+	int numberColumns=solver_->getNumCols();
+	double * obj = CoinCopyOfArray(solver_->getObjCoefficients(),numberColumns);
+	int * indices = new int [numberColumns];
+	int n=0;
+	for (int i=0;i<numberColumns;i++) {
+	  if (obj[i]) {
+	    indices[n]=i;
+	    obj[n++]=obj[i];
+	  }
+	}
+	if (n) {
+	  double cutoff=getCutoff();
+	  // relax a little bit
+	  cutoff += 1.0e-4;
+	  double offset;
+	  solver_->getDblParam(OsiObjOffset, offset);
+	  cutoffRowNumber_ = solver_->getNumRows();
+	  solver_->addRow(n,indices,obj,-COIN_DBL_MAX,CoinMin(cutoff,1.0e25)+offset);
+	} else {
+	  // no objective!
+	  cutoffRowNumber_ = -1;
+	}
+	delete [] indices;
+	delete [] obj;
+      } else {
+	// switch off
+	cutoffRowNumber_ = -1;
+      }
+    }
+    numberRowsAtContinuous_ = getNumRows() ;
+    solver_->saveBaseModel();
+    /*
+      Check the objective to see if we can deduce a nontrivial increment. If
+      it's better than the current value for CbcCutoffIncrement, it'll be
+      installed.
+    */
+    if (solverCharacteristics_->reducedCostsAccurate())
+        analyzeObjective() ;
+    {
+        // may be able to change cutoff now
+        double cutoff = getCutoff();
+        double increment = getDblParam(CbcModel::CbcCutoffIncrement) ;
+        if (cutoff > bestObjective_ - increment) {
+            cutoff = bestObjective_ - increment ;
+            setCutoff(cutoff) ;
+        }
+    }
+#ifdef COIN_HAS_CLP
+    // Possible save of pivot method
+    ClpDualRowPivot * savePivotMethod = NULL;
+    {
+        // pass tolerance and increment to solver
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver)
+            clpSolver->setStuff(getIntegerTolerance(), getCutoffIncrement());
+#ifdef CLP_RESOLVE
+	if ((moreSpecialOptions_&1048576)!=0&&!parentModel_&&clpSolver) {
+	  resolveClp(clpSolver,0);
+	}
+#endif
+    }
+#endif
+    /*
+      Set up for cut generation. addedCuts_ holds the cuts which are relevant for
+      the active subproblem. whichGenerator will be used to record the generator
+      that produced a given cut.
+    */
+    maximumWhich_ = 1000 ;
+    delete [] whichGenerator_;
+    whichGenerator_ = new int[maximumWhich_] ;
+    memset(whichGenerator_, 0, maximumWhich_*sizeof(int));
+    maximumNumberCuts_ = 0 ;
+    currentNumberCuts_ = 0 ;
+    delete [] addedCuts_ ;
+    addedCuts_ = NULL ;
+    OsiObject ** saveObjects = NULL;
+    maximumRows_ = numberRowsAtContinuous_;
+    currentDepth_ = 0;
+    workingBasis_.resize(maximumRows_, numberColumns);
+    /*
+      Set up an empty heap and associated data structures to hold the live set
+      (problems which require further exploration).
+    */
+    CbcCompareDefault * compareActual
+    = dynamic_cast<CbcCompareDefault *> (nodeCompare_);
+    if (compareActual) {
+        compareActual->setBestPossible(direction*solver_->getObjValue());
+        compareActual->setCutoff(getCutoff());
+#ifdef JJF_ZERO
+        if (false && !numberThreads_ && !parentModel_) {
+            printf("CbcTreeArray ? threads ? parentArray\n");
+            // Setup new style tree
+            delete tree_;
+            tree_ = new CbcTreeArray();
+        }
+#endif
+    }
+    tree_->setComparison(*nodeCompare_) ;
+    /*
+      Used to record the path from a node to the root of the search tree, so that
+      we can then traverse from the root to the node when restoring a subproblem.
+    */
+    maximumDepth_ = 10 ;
+    delete [] walkback_ ;
+    walkback_ = new CbcNodeInfo * [maximumDepth_] ;
+    lastDepth_ = 0;
+    delete [] lastNodeInfo_ ;
+    lastNodeInfo_ = new CbcNodeInfo * [maximumDepth_] ;
+    delete [] lastNumberCuts_ ;
+    lastNumberCuts_ = new int [maximumDepth_] ;
+    maximumCuts_ = 100;
+    lastNumberCuts2_ = 0;
+    delete [] lastCut_;
+    lastCut_ = new const OsiRowCut * [maximumCuts_];
+    /*
+      Used to generate bound edits for CbcPartialNodeInfo.
+    */
+    double * lowerBefore = new double [numberColumns] ;
+    double * upperBefore = new double [numberColumns] ;
+    /*
+    Set up to run heuristics and generate cuts at the root node. The heavy
+    lifting is hidden inside the calls to doHeuristicsAtRoot and solveWithCuts.
+
+    To start, tell cut generators they can be a bit more aggressive at the
+    root node.
+
+    QUESTION: phase_ = 0 is documented as `initial solve', phase = 1 as `solve
+        with cuts at root'. Is phase_ = 1 the correct indication when
+        doHeurisiticsAtRoot is called to run heuristics outside of the main
+        cut / heurisitc / reoptimise loop in solveWithCuts?
+
+      Generate cuts at the root node and reoptimise. solveWithCuts does the heavy
+      lifting. It will iterate a generate/reoptimise loop (including reduced cost
+      fixing) until no cuts are generated, the change in objective falls off,  or
+      the limit on the number of rounds of cut generation is exceeded.
+
+      At the end of all this, any cuts will be recorded in cuts and also
+      installed in the solver's constraint system. We'll have reoptimised, and
+      removed any slack cuts (numberOldActiveCuts_ and numberNewCuts_ have been
+      adjusted accordingly).
+
+      Tell cut generators they can be a bit more aggressive at root node
+
+      TODO: Why don't we make a copy of the solution after solveWithCuts?
+      TODO: If numberUnsatisfied == 0, don't we have a solution?
+    */
+    phase_ = 1;
+    int iCutGenerator;
+    for (iCutGenerator = 0; iCutGenerator < numberCutGenerators_; iCutGenerator++) {
+        // If parallel switch off global cuts
+        if (numberThreads_) {
+            generator_[iCutGenerator]->setGlobalCuts(false);
+            generator_[iCutGenerator]->setGlobalCutsAtRoot(false);
+        }
+        CglCutGenerator * generator = generator_[iCutGenerator]->generator();
+        generator->setAggressiveness(generator->getAggressiveness() + 100);
+	if (!generator->canDoGlobalCuts())
+	  generator->setGlobalCuts(false);
+    }
+    OsiCuts cuts ;
+    int anyAction = -1 ;
+    numberOldActiveCuts_ = 0 ;
+    numberNewCuts_ = 0 ;
+    // Array to mark solution
+    delete [] usedInSolution_;
+    usedInSolution_ = new int[numberColumns];
+    CoinZeroN(usedInSolution_, numberColumns);
+    /*
+      For printing totals and for CbcNode (numberNodes_)
+    */
+    numberIterations_ = 0 ;
+    numberNodes_ = 0 ;
+    numberNodes2_ = 0 ;
+    maximumStatistics_ = 0;
+    maximumDepthActual_ = 0;
+    numberDJFixed_ = 0.0;
+    if (!parentModel_) {
+        if ((specialOptions_&262144) != 0) {
+            // create empty stored cuts
+            //storedRowCuts_ = new CglStored(solver_->getNumCols());
+        } else if ((specialOptions_&524288) != 0 && storedRowCuts_) {
+            // tighten and set best solution
+            // A) tight bounds on integer variables
+            /*
+                storedRowCuts_ are coming in from outside, probably for nonlinear.
+              John was unsure about origin.
+            */
+            const double * lower = solver_->getColLower();
+            const double * upper = solver_->getColUpper();
+            const double * tightLower = storedRowCuts_->tightLower();
+            const double * tightUpper = storedRowCuts_->tightUpper();
+            int nTightened = 0;
+            for (int i = 0; i < numberIntegers_; i++) {
+                int iColumn = integerVariable_[i];
+                if (tightLower[iColumn] > lower[iColumn]) {
+                    nTightened++;
+                    solver_->setColLower(iColumn, tightLower[iColumn]);
+                }
+                if (tightUpper[iColumn] < upper[iColumn]) {
+                    nTightened++;
+                    solver_->setColUpper(iColumn, tightUpper[iColumn]);
+                }
+            }
+            if (nTightened)
+	      COIN_DETAIL_PRINT(printf("%d tightened by alternate cuts\n", nTightened));
+            if (storedRowCuts_->bestObjective() < bestObjective_) {
+                // B) best solution
+                double objValue = storedRowCuts_->bestObjective();
+                setBestSolution(CBC_SOLUTION, objValue,
+                                storedRowCuts_->bestSolution()) ;
+                // Do heuristics
+                // Allow RINS
+                for (int i = 0; i < numberHeuristics_; i++) {
+                    CbcHeuristicRINS * rins
+                    = dynamic_cast<CbcHeuristicRINS *> (heuristic_[i]);
+                    if (rins) {
+                        rins->setLastNode(-100);
+                    }
+                }
+            }
+        }
+    }
+    /*
+      Run heuristics at the root. This is the only opportunity to run FPump; it
+      will be removed from the heuristics list by doHeuristicsAtRoot.
+    */
+    // See if multiple runs wanted
+    CbcModel ** rootModels=NULL;
+    if (!parentModel_&&multipleRootTries_%100) {
+      double rootTimeCpu=CoinCpuTime();
+      double startTimeRoot=CoinGetTimeOfDay();
+      int numberRootThreads=1;
+      /* undocumented fine tuning
+	 aabbcc where cc is number of tries
+	 bb if nonzero is number of threads
+	 aa if nonzero just do heuristics
+      */
+      int numberModels = multipleRootTries_%100;
+#ifdef CBC_THREAD
+      numberRootThreads = (multipleRootTries_/100)%100;
+      if (!numberRootThreads)
+	numberRootThreads=numberModels;
+#endif
+      int otherOptions = (multipleRootTries_/10000)%100;
+      rootModels = new CbcModel * [numberModels];
+      unsigned int newSeed = randomSeed_;
+      if (newSeed==0) {
+	double time = fabs(CoinGetTimeOfDay());
+	while (time>=COIN_INT_MAX)
+	  time *= 0.5;
+	newSeed = static_cast<unsigned int>(time);
+      } else if (newSeed<0) {
+	newSeed = 123456789;
+#ifdef COIN_HAS_CLP
+	OsiClpSolverInterface * clpSolver
+	  = dynamic_cast<OsiClpSolverInterface *> (solver_);
+	if (clpSolver) {
+	  newSeed += clpSolver->getModelPtr()->randomNumberGenerator()->getSeed();
+	}
+#endif
+      }
+      CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (solver_->getEmptyWarmStart());
+      int numberIterations=0;
+      for (int i=0;i<numberModels;i++) { 
+	rootModels[i]=new CbcModel(*this);
+	rootModels[i]->setNumberThreads(0);
+	rootModels[i]->setMaximumNodes(otherOptions ? -1 : 0);
+	rootModels[i]->setRandomSeed(newSeed+10000000*i);
+	rootModels[i]->randomNumberGenerator()->setSeed(newSeed+50000000*i);
+	rootModels[i]->setMultipleRootTries(0);
+	// use seed
+	rootModels[i]->setSpecialOptions(specialOptions_ |(4194304|8388608));
+	rootModels[i]->setMoreSpecialOptions(moreSpecialOptions_ & 
+					     (~134217728));
+	rootModels[i]->solver_->setWarmStart(basis);
+#ifdef COIN_HAS_CLP
+	OsiClpSolverInterface * clpSolver
+	  = dynamic_cast<OsiClpSolverInterface *> (rootModels[i]->solver_);
+	if (clpSolver) {
+	  ClpSimplex * simplex = clpSolver->getModelPtr();
+	  if (defaultHandler_)
+	    simplex->setDefaultMessageHandler();
+	  simplex->setRandomSeed(newSeed+20000000*i);
+	  simplex->allSlackBasis();
+	  int logLevel=simplex->logLevel();
+	  if (logLevel==1)
+	    simplex->setLogLevel(0);
+	  if (i!=0) {
+	    double random = simplex->randomNumberGenerator()->randomDouble();
+	    int bias = static_cast<int>(random*(numberIterations/4));
+	    simplex->setMaximumIterations(numberIterations/2+bias);
+	    simplex->primal();
+	    simplex->setMaximumIterations(COIN_INT_MAX);
+	    simplex->dual();
+	  } else {
+	    simplex->primal();
+	    numberIterations=simplex->numberIterations();
+	  }
+	  simplex->setLogLevel(logLevel);
+	  clpSolver->setWarmStart(NULL);
+	}
+#endif
+	for (int j=0;j<numberHeuristics_;j++)
+	  rootModels[i]->heuristic_[j]->setSeed(rootModels[i]->heuristic_[j]->getSeed()+100000000*i);
+	for (int j=0;j<numberCutGenerators_;j++)
+	  rootModels[i]->generator_[j]->generator()->refreshSolver(rootModels[i]->solver_);
+      }
+      delete basis;
+#ifdef CBC_THREAD
+      if (numberRootThreads==1) {
+#endif
+	for (int iModel=0;iModel<numberModels;iModel++) {
+	  doRootCbcThread(rootModels[iModel]);
+	  // see if solved at root node
+	  if (rootModels[iModel]->getMaximumNodes()) {
+	    feasible=false;
+	    break;
+	  }
+	}
+#ifdef CBC_THREAD
+      } else {
+	Coin_pthread_t * threadId = new Coin_pthread_t [numberRootThreads];
+	for (int kModel=0;kModel<numberModels;kModel+=numberRootThreads) {
+	  bool finished=false;
+	  for (int iModel=kModel;iModel<CoinMin(numberModels,kModel+numberRootThreads);iModel++) {
+	    pthread_create(&(threadId[iModel-kModel].thr), NULL, 
+			   doRootCbcThread,
+			   rootModels[iModel]);
+	  }
+	  // wait
+	  for (int iModel=kModel;iModel<CoinMin(numberModels,kModel+numberRootThreads);iModel++) {
+	    pthread_join(threadId[iModel-kModel].thr, NULL);
+	  }
+	  // see if solved at root node
+	  for (int iModel=kModel;iModel<CoinMin(numberModels,kModel+numberRootThreads);iModel++) {
+	    if (rootModels[iModel]->getMaximumNodes())
+	      finished=true;
+	  }
+	  if (finished) {
+	    feasible=false;
+	    break;
+	  }
+	}
+	delete [] threadId;
+      }
+#endif
+      // sort solutions
+      int * which = new int [numberModels];
+      double * value = new double [numberModels];
+      int numberSolutions=0;
+      for (int iModel=0;iModel<numberModels;iModel++) {
+	if (rootModels[iModel]->bestSolution()) {
+	  which[numberSolutions]=iModel;
+	  value[numberSolutions++]=
+	    -rootModels[iModel]->getMinimizationObjValue();
+	}
+      }
+      char general[100];
+      rootTimeCpu=CoinCpuTime()-rootTimeCpu;
+      if (numberRootThreads==1)
+	sprintf(general,"Multiple root solvers took a total of %.2f seconds\n",
+		rootTimeCpu);
+      else
+	sprintf(general,"Multiple root solvers took a total of %.2f seconds (%.2f elapsed)\n",
+		rootTimeCpu,CoinGetTimeOfDay()-startTimeRoot);
+      messageHandler()->message(CBC_GENERAL,
+				messages())
+	<< general << CoinMessageEol ;
+      CoinSort_2(value,value+numberSolutions,which);
+      // to get name
+      CbcHeuristicRINS dummyHeuristic;
+      dummyHeuristic.setHeuristicName("Multiple root solvers");
+      lastHeuristic_=&dummyHeuristic;
+      for (int i=0;i<numberSolutions;i++) {
+	double objValue = - value[i];
+	if (objValue<getCutoff()) {
+	  int iModel=which[i];
+	  setBestSolution(CBC_ROUNDING,objValue,
+			  rootModels[iModel]->bestSolution());
+	}
+      }
+      lastHeuristic_=NULL;
+      delete [] which;
+      delete [] value;
+    }
+    // Do heuristics
+    if (numberObjects_&&!rootModels)
+        doHeuristicsAtRoot();
+    if (solverCharacteristics_->solutionAddsCuts()) {
+      // With some heuristics solver needs a resolve here 
+      solver_->resolve();
+      if(!isProvenOptimal()){
+	solver_->initialSolve();
+      }
+    }
+    /*
+      Grepping through the code, it would appear that this is a command line
+      debugging hook.  There's no obvious place in the code where this is set to
+      a negative value.
+
+      User hook, says John.
+    */
+    if ( intParam_[CbcMaxNumNode] < 0
+      ||numberSolutions_>=getMaximumSolutions())
+      eventHappened_ = true; // stop as fast as possible
+    stoppedOnGap_ = false ;
+    // See if can stop on gap
+    bestPossibleObjective_ = solver_->getObjValue() * solver_->getObjSense();
+    if(canStopOnGap()) {
+        if (bestPossibleObjective_ < getCutoff())
+            stoppedOnGap_ = true ;
+        feasible = false;
+        //eventHappened_=true; // stop as fast as possible
+    }
+    /*
+      Set up for statistics collection, if requested. Standard values are
+      documented in CbcModel.hpp. The magic number 100 will trigger a dump of
+      CbcSimpleIntegerDynamicPseudoCost objects (no others). Looks like another
+      command line debugging hook.
+    */
+    statistics_ = NULL;
+    // Do on switch
+    if (doStatistics > 0 && doStatistics <= 100) {
+        maximumStatistics_ = 10000;
+        statistics_ = new CbcStatistics * [maximumStatistics_];
+        memset(statistics_, 0, maximumStatistics_*sizeof(CbcStatistics *));
+    }
+    // See if we can add integers
+    if (noObjects && numberIntegers_ < solver_->getNumCols() && (specialOptions_&65536) != 0 && !parentModel_)
+        AddIntegers();
+    /*
+      Do an initial round of cut generation for the root node. Depending on the
+      type of underlying solver, we may want to do this even if the initial query
+      to the objects indicates they're satisfied.
+
+      solveWithCuts does the heavy lifting. It will iterate a generate/reoptimise
+      loop (including reduced cost fixing) until no cuts are generated, the
+      change in objective falls off,  or the limit on the number of rounds of cut
+      generation is exceeded.
+
+      At the end of all this, any cuts will be recorded in cuts and also
+      installed in the solver's constraint system. We'll have reoptimised, and
+      removed any slack cuts (numberOldActiveCuts_ and numberNewCuts_ have been
+      adjusted accordingly).
+    */
+    int iObject ;
+    int preferredWay ;
+    int numberUnsatisfied = 0 ;
+    delete [] currentSolution_;
+    currentSolution_ = new double [numberColumns];
+    testSolution_ = currentSolution_;
+    memcpy(currentSolution_, solver_->getColSolution(),
+           numberColumns*sizeof(double)) ;
+    // point to useful information
+    OsiBranchingInformation usefulInfo = usefulInformation();
+
+    for (iObject = 0 ; iObject < numberObjects_ ; iObject++) {
+        double infeasibility =
+            object_[iObject]->infeasibility(&usefulInfo, preferredWay) ;
+        if (infeasibility ) numberUnsatisfied++ ;
+    }
+    // replace solverType
+    double * tightBounds = NULL;
+    if (solverCharacteristics_->tryCuts())  {
+
+        if (numberUnsatisfied)   {
+            // User event
+            if (!eventHappened_ && feasible) {
+	        if (rootModels) {
+		  // for fixings
+		  int numberColumns=solver_->getNumCols();
+		  tightBounds = new double [2*numberColumns];
+		  {
+		    const double * lower = solver_->getColLower();
+		    const double * upper = solver_->getColUpper();
+		    for (int i=0;i<numberColumns;i++) {
+		      tightBounds[2*i+0]=lower[i];
+		      tightBounds[2*i+1]=upper[i];
+		    }
+		  }
+		  int numberModels = multipleRootTries_%100;
+		  const OsiSolverInterface ** solvers = new 
+		    const OsiSolverInterface * [numberModels];
+		  int numberRows=continuousSolver_->getNumRows();
+		  int maxCuts=0;
+		  for (int i=0;i<numberModels;i++) {
+		    solvers[i]=rootModels[i]->solver();
+		    const double * lower = solvers[i]->getColLower();
+		    const double * upper = solvers[i]->getColUpper();
+		    for (int j=0;j<numberColumns;j++) {
+		      tightBounds[2*j+0]=CoinMax(lower[j],tightBounds[2*j+0]);
+		      tightBounds[2*j+1]=CoinMin(upper[j],tightBounds[2*j+1]);
+		    }
+		    int numberRows2=solvers[i]->getNumRows();
+		    assert (numberRows2>=numberRows);
+		    maxCuts += numberRows2-numberRows;
+		    // accumulate statistics
+		    for (int j=0;j<numberCutGenerators_;j++) {
+		      generator_[j]->addStatistics(rootModels[i]->cutGenerator(j));
+		    }
+		  }
+		  for (int j=0;j<numberCutGenerators_;j++) {
+		    generator_[j]->scaleBackStatistics(numberModels);
+		  }
+		  //CbcRowCuts rowCut(maxCuts);
+		  const OsiRowCutDebugger *debugger = NULL;
+		  if ((specialOptions_&1) != 0) 
+		    debugger = solver_->getRowCutDebugger() ;
+		  for (int iModel=0;iModel<numberModels;iModel++) {
+		    int numberRows2=solvers[iModel]->getNumRows();
+		    const CoinPackedMatrix * rowCopy = solvers[iModel]->getMatrixByRow();
+		    const int * rowLength = rowCopy->getVectorLengths(); 
+		    const double * elements = rowCopy->getElements();
+		    const int * column = rowCopy->getIndices();
+		    const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+		    const double * rowLower = solvers[iModel]->getRowLower();
+		    const double * rowUpper = solvers[iModel]->getRowUpper();
+		    for (int iRow=numberRows;iRow<numberRows2;iRow++) {
+		      OsiRowCut rc;
+		      rc.setLb(rowLower[iRow]);
+		      rc.setUb(rowUpper[iRow]);
+		      CoinBigIndex start = rowStart[iRow];
+		      rc.setRow(rowLength[iRow],column+start,elements+start,false);
+		      if (debugger)
+			CoinAssert (!debugger->invalidCut(rc));
+		      globalCuts_.addCutIfNotDuplicate(rc);
+		    }
+		    //int cutsAdded=globalCuts_.numberCuts()-numberCuts;
+		    //numberCuts += cutsAdded;
+		    //printf("Model %d gave %d cuts (out of %d possible)\n",
+		    //	   iModel,cutsAdded,numberRows2-numberRows);
+		  }
+		  // normally replace global cuts
+		  //if (!globalCuts_.())
+		  //globalCuts_=rowCutrowCut.addCuts(globalCuts_);
+		  //rowCut.addCuts(globalCuts_);
+		  int nTightened=0;
+		  bool feasible=true;
+		  {
+		    double tolerance=1.0e-5;
+		    const double * lower = solver_->getColLower();
+		    const double * upper = solver_->getColUpper();
+		    for (int i=0;i<numberColumns;i++) {
+		      if (tightBounds[2*i+0]>tightBounds[2*i+1]) {
+			feasible=false;
+			printf("Bad bounds on %d %g,%g was %g,%g\n",
+			       i,tightBounds[2*i+0],tightBounds[2*i+1],
+			       lower[i],upper[i]);
+		      }
+		      //int k=0;
+		      double oldLower=lower[i];
+		      double oldUpper=upper[i];
+		      if (tightBounds[2*i+0]>oldLower+tolerance) {
+			nTightened++;
+			//k++;
+			solver_->setColLower(i,tightBounds[2*i+0]);
+		      }
+		      if (tightBounds[2*i+1]<oldUpper-tolerance) {
+			nTightened++;
+			//k++;
+			solver_->setColUpper(i,tightBounds[2*i+1]);
+		      }
+		      //if (k)
+		      //printf("new bounds on %d %g,%g was %g,%g\n",
+		      //       i,tightBounds[2*i+0],tightBounds[2*i+1],
+		      //       oldLower,oldUpper);
+		    }
+		    if (!feasible)
+		      abort(); // deal with later
+		  }
+		  delete [] tightBounds;
+		  tightBounds=NULL;
+		  char printBuffer[200];
+		  sprintf(printBuffer,"%d solvers added %d different cuts out of pool of %d",
+			  numberModels,globalCuts_.sizeRowCuts(),maxCuts);
+		  messageHandler()->message(CBC_GENERAL, messages())
+		    << printBuffer << CoinMessageEol ;
+		  if (nTightened) {
+		    sprintf(printBuffer,"%d bounds were tightened",
+			  nTightened);
+		    messageHandler()->message(CBC_GENERAL, messages())
+		      << printBuffer << CoinMessageEol ;
+		  }
+		  delete [] solvers;
+		}
+		if (!parentModel_&&(moreSpecialOptions_&67108864) != 0) {
+		  // load cuts from file
+		  FILE * fp = fopen("global.cuts","rb");
+		  if (fp) {
+		    size_t nRead;
+		    int numberColumns=solver_->getNumCols();
+		    int numCols;
+		    nRead = fread(&numCols, sizeof(int), 1, fp);
+		    if (nRead != 1)
+		      throw("Error in fread");
+		    if (numberColumns!=numCols) {
+		      printf("Mismatch on columns %d %d\n",numberColumns,numCols);
+		      fclose(fp);
+		    } else {
+		      // If rootModel just do some
+		      double threshold=-1.0;
+		      if (!multipleRootTries_)
+			threshold=0.5;
+		      int initialCuts=0;
+		      int initialGlobal = globalCuts_.sizeRowCuts();
+		      double * elements = new double [numberColumns+2];
+		      int * indices = new int [numberColumns];
+		      int numberEntries=1;
+		      while (numberEntries>0) {
+			nRead = fread(&numberEntries, sizeof(int), 1, fp);
+			if (nRead != 1)
+			  throw("Error in fread");
+			double randomNumber=randomNumberGenerator_.randomDouble();
+			if (numberEntries>0) {
+			  initialCuts++;
+			  nRead = fread(elements, sizeof(double), numberEntries+2, fp);
+			  if (nRead != static_cast<size_t>(numberEntries+2))
+			    throw("Error in fread");
+			  nRead = fread(indices, sizeof(int), numberEntries, fp);
+			  if (nRead != static_cast<size_t>(numberEntries))
+			    throw("Error in fread");
+			  if (randomNumber>threshold) {
+			    OsiRowCut rc;
+			    rc.setLb(elements[numberEntries]);
+			    rc.setUb(elements[numberEntries+1]);
+			    rc.setRow(numberEntries,indices,elements,
+				      false);
+			    rc.setGloballyValidAsInteger(2);
+			    globalCuts_.addCutIfNotDuplicate(rc) ;
+			  } 
+			}
+		      }
+		      fclose(fp);
+		      // fixes
+		      int nTightened=0;
+		      fp = fopen("global.fix","rb");
+		      if (fp) {
+			nRead = fread(indices, sizeof(int), 2, fp);
+			if (nRead != 2)
+			  throw("Error in fread");
+			if (numberColumns!=indices[0]) {
+			  printf("Mismatch on columns %d %d\n",numberColumns,
+				 indices[0]);
+			} else {
+			  indices[0]=1;
+			  while (indices[0]>=0) {
+			    nRead = fread(indices, sizeof(int), 2, fp);
+			    if (nRead != 2)
+			      throw("Error in fread");
+			    int iColumn=indices[0];
+			    if (iColumn>=0) {
+			      nTightened++;
+			      nRead = fread(elements, sizeof(double), 4, fp);
+			      if (nRead != 4)
+				throw("Error in fread");
+			      solver_->setColLower(iColumn,elements[0]);
+			      solver_->setColUpper(iColumn,elements[1]);
+			    } 
+			  }
+			}
+		      }
+		      if (fp)
+			fclose(fp);
+		      char printBuffer[200];
+		      sprintf(printBuffer,"%d cuts read in of which %d were unique, %d bounds tightened",
+			     initialCuts,
+			     globalCuts_.sizeRowCuts()-initialGlobal,nTightened); 
+		      messageHandler()->message(CBC_GENERAL, messages())
+			<< printBuffer << CoinMessageEol ;
+		      delete [] elements;
+		      delete [] indices;
+		    }
+		  }
+		}
+                feasible = solveWithCuts(cuts, maximumCutPassesAtRoot_,
+                                         NULL);
+		if (multipleRootTries_&&
+		    (moreSpecialOptions_&134217728)!=0) {
+		  FILE * fp=NULL;
+		  size_t nRead;
+		  int numberColumns=solver_->getNumCols();
+		  int initialCuts=0;
+		  if ((moreSpecialOptions_&134217728)!=0) {
+		    // append so go down to end
+		    fp = fopen("global.cuts","r+b");
+		    if (fp) {
+		      int numCols;
+		      nRead = fread(&numCols, sizeof(int), 1, fp);
+		      if (nRead != 1)
+			throw("Error in fread");
+		      if (numberColumns!=numCols) {
+			printf("Mismatch on columns %d %d\n",numberColumns,numCols);
+			fclose(fp);
+			fp=NULL;
+		      }
+		    }
+		  }
+		  double * elements = new double [numberColumns+2];
+		  int * indices = new int [numberColumns];
+		  if (fp) {
+		    int numberEntries=1;
+		    while (numberEntries>0) {
+		      fpos_t position;
+		      fgetpos(fp, &position);
+		      nRead = fread(&numberEntries, sizeof(int), 1, fp);
+		      if (nRead != 1)
+			throw("Error in fread");
+		      if (numberEntries>0) {
+			initialCuts++;
+			nRead = fread(elements, sizeof(double), numberEntries+2, fp);
+			if (nRead != static_cast<size_t>(numberEntries+2))
+			  throw("Error in fread");
+			nRead = fread(indices, sizeof(int), numberEntries, fp);
+			if (nRead != static_cast<size_t>(numberEntries))
+			  throw("Error in fread");
+		      } else {
+			// end
+			fsetpos(fp, &position);
+		      }
+		    }
+		  } else {
+		    fp = fopen("global.cuts","wb");
+		    size_t nWrite;
+		    nWrite=fwrite(&numberColumns,sizeof(int),1,fp);
+		    if (nWrite != 1)
+		      throw("Error in fwrite");
+		  }
+		  size_t nWrite;
+		  // now append binding cuts
+		  int numberC=continuousSolver_->getNumRows();
+		  int numberRows=solver_->getNumRows();
+		  printf("Saving %d cuts (up from %d)\n",
+			 initialCuts+numberRows-numberC,initialCuts);
+		  const double * rowLower = solver_->getRowLower();
+		  const double * rowUpper = solver_->getRowUpper();
+		  // Row copy
+		  CoinPackedMatrix matrixByRow(*solver_->getMatrixByRow());
+		  const double * elementByRow = matrixByRow.getElements();
+		  const int * column = matrixByRow.getIndices();
+		  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+		  const int * rowLength = matrixByRow.getVectorLengths();
+		  for (int iRow=numberC;iRow<numberRows;iRow++) {
+		    int n=rowLength[iRow];
+		    assert (n);
+		    CoinBigIndex start=rowStart[iRow];
+		    memcpy(elements,elementByRow+start,n*sizeof(double));
+		    memcpy(indices,column+start,n*sizeof(int));
+		    elements[n]=rowLower[iRow];
+		    elements[n+1]=rowUpper[iRow];
+		    nWrite=fwrite(&n,sizeof(int),1,fp);
+		    if (nWrite != 1)
+		      throw("Error in fwrite");
+		    nWrite=fwrite(elements,sizeof(double),n+2,fp);
+		    if (nWrite != static_cast<size_t>(n+2))
+		      throw("Error in fwrite");
+		    nWrite=fwrite(indices,sizeof(int),n,fp);
+		    if (nWrite != static_cast<size_t>(n))
+		      throw("Error in fwrite");
+		  }
+		  // eof marker
+		  int eofMarker=-1;
+		  nWrite=fwrite(&eofMarker,sizeof(int),1,fp);
+		  if (nWrite != 1)
+		    throw("Error in fwrite");
+		  fclose(fp);
+		  // do tighter bounds (? later extra to original columns)
+		  int nTightened=0;
+		  const double * lower = solver_->getColLower();
+		  const double * upper = solver_->getColUpper();
+		  const double * originalLower = continuousSolver_->getColLower();
+		  const double * originalUpper = continuousSolver_->getColUpper();
+		  double tolerance=1.0e-5;
+		  for (int i=0;i<numberColumns;i++) {
+		    if (lower[i]>originalLower[i]+tolerance) {
+		      nTightened++;
+		    }
+		    if (upper[i]<originalUpper[i]-tolerance) {
+		      nTightened++;
+		    }
+		  }
+		  if (nTightened) {
+		    fp = fopen("global.fix","wb");
+		    size_t nWrite;
+		    indices[0]=numberColumns;
+		    if (originalColumns_)
+		      indices[1]=COIN_INT_MAX;
+		    else
+		      indices[1]=-1;
+		    nWrite=fwrite(indices,sizeof(int),2,fp);
+		    if (nWrite != 2)
+		      throw("Error in fwrite");
+		    for (int i=0;i<numberColumns;i++) {
+		      int nTightened=0;
+		      if (lower[i]>originalLower[i]+tolerance) {
+			nTightened++;
+		      }
+		      if (upper[i]<originalUpper[i]-tolerance) {
+			nTightened++;
+		      }
+		      if (nTightened) {
+			indices[0]=i;
+			if (originalColumns_)
+			  indices[1]=originalColumns_[i];
+			elements[0]=lower[i];
+			elements[1]=upper[i];
+			elements[2]=originalLower[i];
+			elements[3]=originalUpper[i];
+			nWrite=fwrite(indices,sizeof(int),2,fp);
+			if (nWrite != 2)
+			  throw("Error in fwrite");
+			nWrite=fwrite(elements,sizeof(double),4,fp);
+			if (nWrite != 4)
+			  throw("Error in fwrite");
+		      }
+		    }
+		    // eof marker
+		    indices[0]=-1;
+		    nWrite=fwrite(indices,sizeof(int),2,fp);
+		    if (nWrite != 2)
+		      throw("Error in fwrite");
+		    fclose(fp);
+		  }
+		  delete [] elements;
+		  delete [] indices;
+		}
+                if ((specialOptions_&524288) != 0 && !parentModel_
+                        && storedRowCuts_) {
+                    if (feasible) {
+                        /* pick up stuff and try again
+                        add cuts, maybe keep around
+                        do best solution and if so new heuristics
+                        obviously tighten bounds
+                        */
+                        // A and B probably done on entry
+                        // A) tight bounds on integer variables
+                        const double * lower = solver_->getColLower();
+                        const double * upper = solver_->getColUpper();
+                        const double * tightLower = storedRowCuts_->tightLower();
+                        const double * tightUpper = storedRowCuts_->tightUpper();
+                        int nTightened = 0;
+                        for (int i = 0; i < numberIntegers_; i++) {
+                            int iColumn = integerVariable_[i];
+                            if (tightLower[iColumn] > lower[iColumn]) {
+                                nTightened++;
+                                solver_->setColLower(iColumn, tightLower[iColumn]);
+                            }
+                            if (tightUpper[iColumn] < upper[iColumn]) {
+                                nTightened++;
+                                solver_->setColUpper(iColumn, tightUpper[iColumn]);
+                            }
+                        }
+                        if (nTightened)
+			  COIN_DETAIL_PRINT(printf("%d tightened by alternate cuts\n", nTightened));
+                        if (storedRowCuts_->bestObjective() < bestObjective_) {
+                            // B) best solution
+                            double objValue = storedRowCuts_->bestObjective();
+                            setBestSolution(CBC_SOLUTION, objValue,
+                                            storedRowCuts_->bestSolution()) ;
+                            // Do heuristics
+                            // Allow RINS
+                            for (int i = 0; i < numberHeuristics_; i++) {
+                                CbcHeuristicRINS * rins
+                                = dynamic_cast<CbcHeuristicRINS *> (heuristic_[i]);
+                                if (rins) {
+                                    rins->setLastNode(-100);
+                                }
+                            }
+                            doHeuristicsAtRoot();
+                        }
+#ifdef JJF_ZERO
+                        int nCuts = storedRowCuts_->sizeRowCuts();
+                        // add to global list
+                        for (int i = 0; i < nCuts; i++) {
+                            OsiRowCut newCut(*storedRowCuts_->rowCutPointer(i));
+                            newCut.setGloballyValidAsInteger(2);
+                            newCut.mutableRow().setTestForDuplicateIndex(false);
+                            globalCuts_.insert(newCut) ;
+                        }
+#else
+                        addCutGenerator(storedRowCuts_, -99, "Stored from previous run",
+                                        true, false, false, -200);
+#endif
+                        // Set cuts as active
+                        delete [] addedCuts_ ;
+                        maximumNumberCuts_ = cuts.sizeRowCuts();
+                        if (maximumNumberCuts_) {
+                            addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
+                        } else {
+                            addedCuts_ = NULL;
+                        }
+                        for (int i = 0; i < maximumNumberCuts_; i++)
+                            addedCuts_[i] = new CbcCountRowCut(*cuts.rowCutPtr(i),
+                                                               NULL, -1, -1, 2);
+                        COIN_DETAIL_PRINT(printf("size %d\n", cuts.sizeRowCuts()));
+                        cuts = OsiCuts();
+                        currentNumberCuts_ = maximumNumberCuts_;
+                        feasible = solveWithCuts(cuts, maximumCutPassesAtRoot_,
+                                                 NULL);
+                        for (int i = 0; i < maximumNumberCuts_; i++)
+                            delete addedCuts_[i];
+                    }
+                    delete storedRowCuts_;
+                    storedRowCuts_ = NULL;
+                }
+            } else {
+                feasible = false;
+            }
+        }	else if (solverCharacteristics_->solutionAddsCuts() ||
+                   solverCharacteristics_->alwaysTryCutsAtRootNode()) {
+            // may generate cuts and turn the solution
+            //to an infeasible one
+            feasible = solveWithCuts(cuts, 2,
+                                     NULL);
+        }
+    }
+    if (rootModels) {
+      int numberModels = multipleRootTries_%100;
+      for (int i=0;i<numberModels;i++)
+	delete rootModels[i];
+      delete [] rootModels;
+    }
+    // check extra info on feasibility
+    if (!solverCharacteristics_->mipFeasible())
+        feasible = false;
+    // If max nodes==0 - don't do strong branching
+    if (!getMaximumNodes()) {
+      if (feasible)
+	feasible=false;
+      else
+	setMaximumNodes(1); //allow to stop on success
+    }
+    topOfTree_=NULL;
+#ifdef CLP_RESOLVE
+    if ((moreSpecialOptions_&2097152)!=0&&!parentModel_&&feasible) {
+      OsiClpSolverInterface * clpSolver
+	= dynamic_cast<OsiClpSolverInterface *> (solver_);
+      if (clpSolver)
+	resolveClp(clpSolver,0);
+    }
+#endif
+    // make cut generators less aggressive
+    for (iCutGenerator = 0; iCutGenerator < numberCutGenerators_; iCutGenerator++) {
+        CglCutGenerator * generator = generator_[iCutGenerator]->generator();
+        generator->setAggressiveness(generator->getAggressiveness() - 100);
+    }
+    currentNumberCuts_ = numberNewCuts_ ;
+    if (solverCharacteristics_->solutionAddsCuts()) {
+      // With some heuristics solver needs a resolve here (don't know if this is bug in heuristics)
+      solver_->resolve();
+      if(!isProvenOptimal()){
+	solver_->initialSolve();
+      }
+    }
+    // See if can stop on gap
+    bestPossibleObjective_ = solver_->getObjValue() * solver_->getObjSense();
+    if(canStopOnGap()) {
+        if (bestPossibleObjective_ < getCutoff())
+            stoppedOnGap_ = true ;
+        feasible = false;
+    }
+    // User event
+    if (eventHappened_)
+        feasible = false;
+#if defined(COIN_HAS_CLP)&&defined(COIN_HAS_CPX)
+    /*
+      This is the notion of using Cbc stuff to get going, then calling cplex to
+      finish off.
+    */
+    if (feasible && (specialOptions_&16384) != 0 && fastNodeDepth_ == -2 && !parentModel_) {
+        // Use Cplex to do search!
+        double time1 = CoinCpuTime();
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        OsiCpxSolverInterface cpxSolver;
+        double direction = clpSolver->getObjSense();
+        cpxSolver.setObjSense(direction);
+        // load up cplex
+        const CoinPackedMatrix * matrix = continuousSolver_->getMatrixByCol();
+        const double * rowLower = continuousSolver_->getRowLower();
+        const double * rowUpper = continuousSolver_->getRowUpper();
+        const double * columnLower = continuousSolver_->getColLower();
+        const double * columnUpper = continuousSolver_->getColUpper();
+        const double * objective = continuousSolver_->getObjCoefficients();
+        cpxSolver.loadProblem(*matrix, columnLower, columnUpper,
+                              objective, rowLower, rowUpper);
+        double * setSol = new double [numberIntegers_];
+        int * setVar = new int [numberIntegers_];
+        // cplex doesn't know about objective offset
+        double offset = clpSolver->getModelPtr()->objectiveOffset();
+        for (int i = 0; i < numberIntegers_; i++) {
+            int iColumn = integerVariable_[i];
+            cpxSolver.setInteger(iColumn);
+            if (bestSolution_) {
+                setSol[i] = bestSolution_[iColumn];
+                setVar[i] = iColumn;
+            }
+        }
+        CPXENVptr env = cpxSolver.getEnvironmentPtr();
+        CPXLPptr lpPtr = cpxSolver.getLpPtr(OsiCpxSolverInterface::KEEPCACHED_ALL);
+        cpxSolver.switchToMIP();
+        if (bestSolution_) {
+            CPXcopymipstart(env, lpPtr, numberIntegers_, setVar, setSol);
+        }
+        if (clpSolver->getNumRows() > continuousSolver_->getNumRows() && false) {
+            // add cuts
+            const CoinPackedMatrix * matrix = clpSolver->getMatrixByRow();
+            const double * rhs = clpSolver->getRightHandSide();
+            const char * rowSense = clpSolver->getRowSense();
+            const double * elementByRow = matrix->getElements();
+            const int * column = matrix->getIndices();
+            const CoinBigIndex * rowStart = matrix->getVectorStarts();
+            const int * rowLength = matrix->getVectorLengths();
+            int nStart = continuousSolver_->getNumRows();
+            int nRows = clpSolver->getNumRows();
+            int size = rowStart[nRows-1] + rowLength[nRows-1] -
+                       rowStart[nStart];
+            int nAdd = 0;
+            double * rmatval = new double [size];
+            int * rmatind = new int [size];
+            int * rmatbeg = new int [nRows-nStart+1];
+            size = 0;
+            rmatbeg[0] = 0;
+            for (int i = nStart; i < nRows; i++) {
+                for (int k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) {
+                    rmatind[size] = column[k];
+                    rmatval[size++] = elementByRow[k];
+                }
+                nAdd++;
+                rmatbeg[nAdd] = size;
+            }
+            CPXaddlazyconstraints(env, lpPtr, nAdd, size,
+                                  rhs, rowSense, rmatbeg,
+                                  rmatind, rmatval, NULL);
+            CPXsetintparam( env, CPX_PARAM_REDUCE,
+                            // CPX_PREREDUCE_NOPRIMALORDUAL (0)
+                            CPX_PREREDUCE_PRIMALONLY);
+        }
+        if (getCutoff() < 1.0e50) {
+            double useCutoff = getCutoff() + offset;
+            if (bestObjective_ < 1.0e50)
+                useCutoff = bestObjective_ + offset + 1.0e-7;
+            cpxSolver.setDblParam(OsiDualObjectiveLimit, useCutoff*
+                                  direction);
+            if ( direction > 0.0 )
+                CPXsetdblparam( env, CPX_PARAM_CUTUP, useCutoff ) ; // min
+            else
+                CPXsetdblparam( env, CPX_PARAM_CUTLO, useCutoff ) ; // max
+        }
+        CPXsetdblparam(env, CPX_PARAM_EPGAP, dblParam_[CbcAllowableFractionGap]);
+        delete [] setSol;
+        delete [] setVar;
+        char printBuffer[200];
+        if (offset) {
+            sprintf(printBuffer, "Add %g to all Cplex messages for true objective",
+                    -offset);
+            messageHandler()->message(CBC_GENERAL, messages())
+            << printBuffer << CoinMessageEol ;
+            cpxSolver.setDblParam(OsiObjOffset, offset);
+        }
+        cpxSolver.branchAndBound();
+        double timeTaken = CoinCpuTime() - time1;
+        sprintf(printBuffer, "Cplex took %g seconds",
+                timeTaken);
+        messageHandler()->message(CBC_GENERAL, messages())
+        << printBuffer << CoinMessageEol ;
+        numberExtraNodes_ = CPXgetnodecnt(env, lpPtr);
+        numberExtraIterations_ = CPXgetmipitcnt(env, lpPtr);
+        double value = cpxSolver.getObjValue() * direction;
+        if (cpxSolver.isProvenOptimal() && value <= getCutoff()) {
+            feasible = true;
+            clpSolver->setWarmStart(NULL);
+            // try and do solution
+            double * newSolution =
+                CoinCopyOfArray(cpxSolver.getColSolution(),
+                                getNumCols());
+            setBestSolution(CBC_STRONGSOL, value, newSolution) ;
+            delete [] newSolution;
+        }
+        feasible = false;
+    }
+#endif
+    if (!parentModel_&&(moreSpecialOptions_&268435456) != 0) {
+      // try idiotic idea
+      CbcObject * obj = new CbcIdiotBranch(this);
+      obj->setPriority(1); // temp
+      addObjects(1, &obj);
+      delete obj;
+    }
+    
+    /*
+      A hook to use clp to quickly explore some part of the tree.
+    */
+    if (fastNodeDepth_ == 1000 &&/*!parentModel_*/(specialOptions_&2048) == 0) {
+        fastNodeDepth_ = -1;
+        CbcObject * obj =
+            new CbcFollowOn(this);
+        obj->setPriority(1);
+        addObjects(1, &obj);
+	delete obj;
+    }
+    int saveNumberSolves = numberSolves_;
+    int saveNumberIterations = numberIterations_;
+    if ((fastNodeDepth_ >= 0||(moreSpecialOptions_&33554432)!=0)
+	&&/*!parentModel_*/(specialOptions_&2048) == 0) {
+        // add in a general depth object doClp
+        int type = (fastNodeDepth_ <= 100) ? fastNodeDepth_ : -(fastNodeDepth_ - 100);
+	if ((moreSpecialOptions_&33554432)!=0)
+	  type=12;
+	else
+	  fastNodeDepth_ += 1000000;     // mark as done
+        CbcObject * obj =
+            new CbcGeneralDepth(this, type);
+        addObjects(1, &obj);
+        delete obj;
+        // fake number of objects
+        numberObjects_--;
+        if (parallelMode() < -1) {
+            // But make sure position is correct
+            OsiObject * obj2 = object_[numberObjects_];
+            obj = dynamic_cast<CbcObject *> (obj2);
+            assert (obj);
+            obj->setPosition(numberObjects_);
+        }
+    }
+#ifdef COIN_HAS_CLP
+#ifdef NO_CRUNCH
+    if (true) {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver && !parentModel_) {
+            ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+            clpSimplex->setSpecialOptions(clpSimplex->specialOptions() | 131072);
+            //clpSimplex->startPermanentArrays();
+            clpSimplex->setPersistenceFlag(2);
+        }
+    }
+#endif
+#endif
+// Save copy of solver
+    OsiSolverInterface * saveSolver = NULL;
+    if (!parentModel_ && (specialOptions_&(512 + 32768)) != 0)
+        saveSolver = solver_->clone();
+    double checkCutoffForRestart = 1.0e100;
+    saveModel(saveSolver, &checkCutoffForRestart, &feasible);
+    if ((specialOptions_&262144) != 0 && !parentModel_) {
+        // Save stuff and return!
+        storedRowCuts_->saveStuff(bestObjective_, bestSolution_,
+                                  solver_->getColLower(),
+                                  solver_->getColUpper());
+        delete [] lowerBefore;
+        delete [] upperBefore;
+        delete saveSolver;
+	if (flipObjective)
+	  flipModel();
+        return;
+    }
+    /*
+      We've taken the continuous relaxation as far as we can. Time to branch.
+      The first order of business is to actually create a node. chooseBranch
+      currently uses strong branching to evaluate branch object candidates,
+      unless forced back to simple branching. If chooseBranch concludes that a
+      branching candidate is monotone (anyAction == -1) or infeasible (anyAction
+      == -2) when forced to integer values, it returns here immediately.
+
+      Monotone variables trigger a call to resolve(). If the problem remains
+      feasible, try again to choose a branching variable. At the end of the loop,
+      resolved == true indicates that some variables were fixed.
+
+      Loss of feasibility will result in the deletion of newNode.
+    */
+
+    bool resolved = false ;
+    CbcNode *newNode = NULL ;
+    numberFixedAtRoot_ = 0;
+    numberFixedNow_ = 0;
+    int numberIterationsAtContinuous = numberIterations_;
+    //solverCharacteristics_->setSolver(solver_);
+    if (feasible) {
+#define HOTSTART -1
+#if HOTSTART<0
+        if (bestSolution_ && !parentModel_ && !hotstartSolution_ &&
+                (moreSpecialOptions_&1024) != 0) {
+            // Set priorities so only branch on ones we need to
+            // use djs and see if only few branches needed
+#ifndef NDEBUG
+            double integerTolerance = getIntegerTolerance() ;
+#endif
+            bool possible = true;
+            const double * saveLower = continuousSolver_->getColLower();
+            const double * saveUpper = continuousSolver_->getColUpper();
+            for (int i = 0; i < numberObjects_; i++) {
+                const CbcSimpleInteger * thisOne = dynamic_cast <const CbcSimpleInteger *> (object_[i]);
+                if (thisOne) {
+                    int iColumn = thisOne->columnNumber();
+                    if (saveUpper[iColumn] > saveLower[iColumn] + 1.5) {
+                        possible = false;
+                        break;
+                    }
+                } else {
+                    possible = false;
+                    break;
+                }
+            }
+            if (possible) {
+                OsiSolverInterface * solver = continuousSolver_->clone();
+                int numberColumns = solver->getNumCols();
+                for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+                    double value = bestSolution_[iColumn] ;
+                    value = CoinMax(value, saveLower[iColumn]) ;
+                    value = CoinMin(value, saveUpper[iColumn]) ;
+                    value = floor(value + 0.5);
+                    if (solver->isInteger(iColumn)) {
+                        solver->setColLower(iColumn, value);
+                        solver->setColUpper(iColumn, value);
+                    }
+                }
+                solver->setHintParam(OsiDoDualInResolve, false, OsiHintTry);
+                // objlim and all slack
+                double direction = solver->getObjSense();
+                solver->setDblParam(OsiDualObjectiveLimit, 1.0e50*direction);
+                CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (solver->getEmptyWarmStart());
+                solver->setWarmStart(basis);
+                delete basis;
+                bool changed = true;
+                hotstartPriorities_ = new int [numberColumns];
+                for (int iColumn = 0; iColumn < numberColumns; iColumn++)
+                    hotstartPriorities_[iColumn] = 1;
+                while (changed) {
+                    changed = false;
+                    solver->resolve();
+                    if (!solver->isProvenOptimal()) {
+                        possible = false;
+                        break;
+                    }
+                    const double * dj = solver->getReducedCost();
+                    const double * colLower = solver->getColLower();
+                    const double * colUpper = solver->getColUpper();
+                    const double * solution = solver->getColSolution();
+                    int nAtLbNatural = 0;
+                    int nAtUbNatural = 0;
+                    int nZeroDj = 0;
+                    int nForced = 0;
+                    for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+                        double value = solution[iColumn] ;
+                        value = CoinMax(value, saveLower[iColumn]) ;
+                        value = CoinMin(value, saveUpper[iColumn]) ;
+                        if (solver->isInteger(iColumn)) {
+                            assert(fabs(value - solution[iColumn]) <= integerTolerance) ;
+                            if (hotstartPriorities_[iColumn] == 1) {
+                                if (dj[iColumn] < -1.0e-6) {
+                                    // negative dj
+                                    if (saveUpper[iColumn] == colUpper[iColumn]) {
+                                        nAtUbNatural++;
+                                        hotstartPriorities_[iColumn] = 2;
+                                        solver->setColLower(iColumn, saveLower[iColumn]);
+                                        solver->setColUpper(iColumn, saveUpper[iColumn]);
+                                    } else {
+                                        nForced++;
+                                    }
+                                } else if (dj[iColumn] > 1.0e-6) {
+                                    // positive dj
+                                    if (saveLower[iColumn] == colLower[iColumn]) {
+                                        nAtLbNatural++;
+                                        hotstartPriorities_[iColumn] = 2;
+                                        solver->setColLower(iColumn, saveLower[iColumn]);
+                                        solver->setColUpper(iColumn, saveUpper[iColumn]);
+                                    } else {
+                                        nForced++;
+                                    }
+                                } else {
+                                    // zero dj
+                                    nZeroDj++;
+                                }
+                            }
+                        }
+                    }
+#ifdef CLP_INVESTIGATE
+                    printf("%d forced, %d naturally at lower, %d at upper - %d zero dj\n",
+                           nForced, nAtLbNatural, nAtUbNatural, nZeroDj);
+#endif
+                    if (nAtLbNatural || nAtUbNatural) {
+                        changed = true;
+                    } else {
+                        if (nForced + nZeroDj > 5000 ||
+                                (nForced + nZeroDj)*2 > numberIntegers_)
+                            possible = false;
+                    }
+                }
+                delete solver;
+            }
+            if (possible) {
+                setHotstartSolution(bestSolution_);
+                if (!saveCompare) {
+                    // create depth first comparison
+                    saveCompare = nodeCompare_;
+                    // depth first
+                    nodeCompare_ = new CbcCompareDepth();
+                    tree_->setComparison(*nodeCompare_) ;
+                }
+            } else {
+                delete [] hotstartPriorities_;
+                hotstartPriorities_ = NULL;
+            }
+        }
+#endif
+#if HOTSTART>0
+        if (hotstartSolution_ && !hotstartPriorities_) {
+            // Set up hot start
+            OsiSolverInterface * solver = solver_->clone();
+            double direction = solver_->getObjSense() ;
+            int numberColumns = solver->getNumCols();
+            double * saveLower = CoinCopyOfArray(solver->getColLower(), numberColumns);
+            double * saveUpper = CoinCopyOfArray(solver->getColUpper(), numberColumns);
+            // move solution
+            solver->setColSolution(hotstartSolution_);
+            // point to useful information
+            const double * saveSolution = testSolution_;
+            testSolution_ = solver->getColSolution();
+            OsiBranchingInformation usefulInfo = usefulInformation();
+            testSolution_ = saveSolution;
+            /*
+            Run through the objects and use feasibleRegion() to set variable bounds
+            so as to fix the variables specified in the objects at their value in this
+            solution. Since the object list contains (at least) one object for every
+            integer variable, this has the effect of fixing all integer variables.
+            */
+            for (int i = 0; i < numberObjects_; i++)
+                object_[i]->feasibleRegion(solver, &usefulInfo);
+            solver->resolve();
+            assert (solver->isProvenOptimal());
+            double gap = CoinMax((solver->getObjValue() - solver_->getObjValue()) * direction, 0.0) ;
+            const double * dj = solver->getReducedCost();
+            const double * colLower = solver->getColLower();
+            const double * colUpper = solver->getColUpper();
+            const double * solution = solver->getColSolution();
+            int nAtLbNatural = 0;
+            int nAtUbNatural = 0;
+            int nAtLbNaturalZero = 0;
+            int nAtUbNaturalZero = 0;
+            int nAtLbFixed = 0;
+            int nAtUbFixed = 0;
+            int nAtOther = 0;
+            int nAtOtherNatural = 0;
+            int nNotNeeded = 0;
+            delete [] hotstartSolution_;
+            hotstartSolution_ = new double [numberColumns];
+            delete [] hotstartPriorities_;
+            hotstartPriorities_ = new int [numberColumns];
+            int * order = (int *) saveUpper;
+            int nFix = 0;
+            double bestRatio = COIN_DBL_MAX;
+            for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+                double value = solution[iColumn] ;
+                value = CoinMax(value, saveLower[iColumn]) ;
+                value = CoinMin(value, saveUpper[iColumn]) ;
+                double sortValue = COIN_DBL_MAX;
+                if (solver->isInteger(iColumn)) {
+                    assert(fabs(value - solution[iColumn]) <= 1.0e-5) ;
+                    double value2 = floor(value + 0.5);
+                    if (dj[iColumn] < -1.0e-6) {
+                        // negative dj
+                        //assert (value2==colUpper[iColumn]);
+                        if (saveUpper[iColumn] == colUpper[iColumn]) {
+                            nAtUbNatural++;
+                            sortValue = 0.0;
+                            double value = -dj[iColumn];
+                            if (value > gap)
+                                nFix++;
+                            else if (gap < value*bestRatio)
+                                bestRatio = gap / value;
+                            if (saveLower[iColumn] != colLower[iColumn]) {
+                                nNotNeeded++;
+                                sortValue = 1.0e20;
+                            }
+                        } else if (saveLower[iColumn] == colUpper[iColumn]) {
+                            nAtLbFixed++;
+                            sortValue = dj[iColumn];
+                        } else {
+                            nAtOther++;
+                            sortValue = 0.0;
+                            if (saveLower[iColumn] != colLower[iColumn] &&
+                                    saveUpper[iColumn] != colUpper[iColumn]) {
+                                nNotNeeded++;
+                                sortValue = 1.0e20;
+                            }
+                        }
+                    } else if (dj[iColumn] > 1.0e-6) {
+                        // positive dj
+                        //assert (value2==colLower[iColumn]);
+                        if (saveLower[iColumn] == colLower[iColumn]) {
+                            nAtLbNatural++;
+                            sortValue = 0.0;
+                            double value = dj[iColumn];
+                            if (value > gap)
+                                nFix++;
+                            else if (gap < value*bestRatio)
+                                bestRatio = gap / value;
+                            if (saveUpper[iColumn] != colUpper[iColumn]) {
+                                nNotNeeded++;
+                                sortValue = 1.0e20;
+                            }
+                        } else if (saveUpper[iColumn] == colLower[iColumn]) {
+                            nAtUbFixed++;
+                            sortValue = -dj[iColumn];
+                        } else {
+                            nAtOther++;
+                            sortValue = 0.0;
+                            if (saveLower[iColumn] != colLower[iColumn] &&
+                                    saveUpper[iColumn] != colUpper[iColumn]) {
+                                nNotNeeded++;
+                                sortValue = 1.0e20;
+                            }
+                        }
+                    } else {
+                        // zero dj
+                        if (value2 == saveUpper[iColumn]) {
+                            nAtUbNaturalZero++;
+                            sortValue = 0.0;
+                            if (saveLower[iColumn] != colLower[iColumn]) {
+                                nNotNeeded++;
+                                sortValue = 1.0e20;
+                            }
+                        } else if (value2 == saveLower[iColumn]) {
+                            nAtLbNaturalZero++;
+                            sortValue = 0.0;
+                        } else {
+                            nAtOtherNatural++;
+                            sortValue = 0.0;
+                            if (saveLower[iColumn] != colLower[iColumn] &&
+                                    saveUpper[iColumn] != colUpper[iColumn]) {
+                                nNotNeeded++;
+                                sortValue = 1.0e20;
+                            }
+                        }
+                    }
+#if HOTSTART==3
+                    sortValue = -fabs(dj[iColumn]);
+#endif
+                }
+                hotstartSolution_[iColumn] = value ;
+                saveLower[iColumn] = sortValue;
+                order[iColumn] = iColumn;
+            }
+            COIN_DETAIL_PRINT(printf("** can fix %d columns - best ratio for others is %g on gap of %g\n",
+				     nFix, bestRatio, gap));
+            int nNeg = 0;
+            CoinSort_2(saveLower, saveLower + numberColumns, order);
+            for (int i = 0; i < numberColumns; i++) {
+                if (saveLower[i] < 0.0) {
+                    nNeg++;
+#if HOTSTART==2||HOTSTART==3
+                    // swap sign ?
+                    saveLower[i] = -saveLower[i];
+#endif
+                }
+            }
+            CoinSort_2(saveLower, saveLower + nNeg, order);
+            for (int i = 0; i < numberColumns; i++) {
+#if HOTSTART==1
+                hotstartPriorities_[order[i]] = 100;
+#else
+                hotstartPriorities_[order[i]] = -(i + 1);
+#endif
+            }
+            COIN_DETAIL_PRINT(printf("nAtLbNat %d,nAtUbNat %d,nAtLbNatZero %d,nAtUbNatZero %d,nAtLbFixed %d,nAtUbFixed %d,nAtOther %d,nAtOtherNat %d, useless %d %d\n",
+                   nAtLbNatural,
+                   nAtUbNatural,
+                   nAtLbNaturalZero,
+                   nAtUbNaturalZero,
+                   nAtLbFixed,
+                   nAtUbFixed,
+                   nAtOther,
+				     nAtOtherNatural, nNotNeeded, nNeg));
+            delete [] saveLower;
+            delete [] saveUpper;
+            if (!saveCompare) {
+                // create depth first comparison
+                saveCompare = nodeCompare_;
+                // depth first
+                nodeCompare_ = new CbcCompareDepth();
+                tree_->setComparison(*nodeCompare_) ;
+            }
+        }
+#endif
+        newNode = new CbcNode ;
+        // Set objective value (not so obvious if NLP etc)
+        setObjectiveValue(newNode, NULL);
+        anyAction = -1 ;
+        // To make depth available we may need a fake node
+        CbcNode fakeNode;
+        if (!currentNode_) {
+            // Not true if sub trees assert (!numberNodes_);
+            currentNode_ = &fakeNode;
+        }
+        phase_ = 3;
+        // only allow 1000 passes
+        int numberPassesLeft = 1000;
+        // This is first crude step
+        if (numberAnalyzeIterations_) {
+            delete [] analyzeResults_;
+            analyzeResults_ = new double [4*numberIntegers_];
+            numberFixedAtRoot_ = newNode->analyze(this, analyzeResults_);
+            if (numberFixedAtRoot_ > 0) {
+	      COIN_DETAIL_PRINT(printf("%d fixed by analysis\n", numberFixedAtRoot_));
+                setPointers(solver_);
+                numberFixedNow_ = numberFixedAtRoot_;
+            } else if (numberFixedAtRoot_ < 0) {
+	      COIN_DETAIL_PRINT(printf("analysis found to be infeasible\n"));
+                anyAction = -2;
+                delete newNode ;
+                newNode = NULL ;
+                feasible = false ;
+            }
+        }
+        OsiSolverBranch * branches = NULL;
+        anyAction = chooseBranch(newNode, numberPassesLeft, NULL, cuts, resolved,
+                                 NULL, NULL, NULL, branches);
+        if (anyAction == -2 || newNode->objectiveValue() >= cutoff) {
+            if (anyAction != -2) {
+                // zap parent nodeInfo
+#ifdef COIN_DEVELOP
+                printf("zapping CbcNodeInfo %x\n", reinterpret_cast<int>(newNode->nodeInfo()->parent()));
+#endif
+                if (newNode->nodeInfo())
+                    newNode->nodeInfo()->nullParent();
+            }
+            delete newNode ;
+            newNode = NULL ;
+            feasible = false ;
+        }
+    }
+    if (newNode && probingInfo_) {
+        int number01 = probingInfo_->numberIntegers();
+        //const fixEntry * entry = probingInfo_->fixEntries();
+        const int * toZero = probingInfo_->toZero();
+        //const int * toOne = probingInfo_->toOne();
+        //const int * integerVariable = probingInfo_->integerVariable();
+        if (toZero[number01]) {
+            CglTreeProbingInfo info(*probingInfo_);
+#ifdef JJF_ZERO
+            /*
+              Marginal idea. Further exploration probably good. Build some extra
+              cliques from probing info. Not quite worth the effort?
+            */
+            OsiSolverInterface * fake = info.analyze(*solver_, 1);
+            if (fake) {
+                fake->writeMps("fake");
+                CglFakeClique cliqueGen(fake);
+                cliqueGen.setStarCliqueReport(false);
+                cliqueGen.setRowCliqueReport(false);
+                cliqueGen.setMinViolation(0.1);
+                addCutGenerator(&cliqueGen, 1, "Fake cliques", true, false, false, -200);
+                generator_[numberCutGenerators_-1]->setTiming(true);
+            }
+#endif
+            if (probingInfo_->packDown()) {
+#ifdef CLP_INVESTIGATE
+                printf("%d implications on %d 0-1\n", toZero[number01], number01);
+#endif
+                // Create a cut generator that remembers implications discovered at root.
+                CglImplication implication(probingInfo_);
+                addCutGenerator(&implication, 1, "ImplicationCuts", true, false, false, -200);
+		generator_[numberCutGenerators_-1]->setGlobalCuts(true);
+            } else {
+                delete probingInfo_;
+                probingInfo_ = NULL;
+            }
+        } else {
+            delete probingInfo_;
+
+            probingInfo_ = NULL;
+        }
+    }
+    /*
+      At this point, the root subproblem is infeasible or fathomed by bound
+      (newNode == NULL), or we're live with an objective value that satisfies the
+      current objective cutoff.
+    */
+    assert (!newNode || newNode->objectiveValue() <= cutoff) ;
+    // Save address of root node as we don't want to delete it
+    // initialize for print out
+    int lastDepth = 0;
+    int lastUnsatisfied = 0;
+    if (newNode)
+        lastUnsatisfied = newNode->numberUnsatisfied();
+    /*
+      The common case is that the lp relaxation is feasible but doesn't satisfy
+      integrality (i.e., newNode->branchingObject(), indicating we've been able to
+      select a branching variable). Remove any cuts that have gone slack due to
+      forcing monotone variables. Then tack on an CbcFullNodeInfo object and full
+      basis (via createInfo()) and stash the new cuts in the nodeInfo (via
+      addCuts()). If, by some miracle, we have an integral solution at the root
+      (newNode->branchingObject() is NULL), takeOffCuts() will ensure that the solver holds
+      a valid solution for use by setBestSolution().
+    */
+    CoinWarmStartBasis *lastws = NULL ;
+    if (feasible && newNode->branchingObject()) {
+        if (resolved) {
+            takeOffCuts(cuts, false, NULL) ;
+#     ifdef CHECK_CUT_COUNTS
+            { printf("Number of rows after chooseBranch fix (root)"
+                         "(active only) %d\n",
+                         numberRowsAtContinuous_ + numberNewCuts_ + numberOldActiveCuts_) ;
+                const CoinWarmStartBasis* debugws =
+                    dynamic_cast <const CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+                debugws->print() ;
+                delete debugws ;
+            }
+#     endif
+        }
+        //newNode->createInfo(this,NULL,NULL,NULL,NULL,0,0) ;
+        //newNode->nodeInfo()->addCuts(cuts,
+        //			 newNode->numberBranches(),whichGenerator_) ;
+        if (lastws) delete lastws ;
+        lastws = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+    }
+    /*
+      Continuous data to be used later
+    */
+    continuousObjective_ = solver_->getObjValue() * solver_->getObjSense();
+    continuousInfeasibilities_ = 0 ;
+    if (newNode) {
+        continuousObjective_ = newNode->objectiveValue() ;
+        delete [] continuousSolution_;
+        continuousSolution_ = CoinCopyOfArray(solver_->getColSolution(),
+                                              numberColumns);
+        continuousInfeasibilities_ = newNode->numberUnsatisfied() ;
+    }
+    /*
+      Bound may have changed so reset in objects
+    */
+    {
+        int i ;
+        for (i = 0; i < numberObjects_; i++)
+            object_[i]->resetBounds(solver_) ;
+    }
+    /*
+      Feasible? Then we should have either a live node prepped for future
+      expansion (indicated by variable() >= 0), or (miracle of miracles) an
+      integral solution at the root node.
+
+      initializeInfo sets the reference counts in the nodeInfo object.  Since
+      this node is still live, push it onto the heap that holds the live set.
+    */
+    if (newNode) {
+        if (newNode->branchingObject()) {
+            newNode->initializeInfo() ;
+            tree_->push(newNode) ;
+	    // save pointer to root node - so can pick up bounds
+	    if (!topOfTree_)
+	      topOfTree_ = dynamic_cast<CbcFullNodeInfo *>(newNode->nodeInfo()) ;
+            if (statistics_) {
+                if (numberNodes2_ == maximumStatistics_) {
+                    maximumStatistics_ = 2 * maximumStatistics_;
+                    CbcStatistics ** temp = new CbcStatistics * [maximumStatistics_];
+                    memset(temp, 0, maximumStatistics_*sizeof(CbcStatistics *));
+                    memcpy(temp, statistics_, numberNodes2_*sizeof(CbcStatistics *));
+                    delete [] statistics_;
+                    statistics_ = temp;
+                }
+                assert (!statistics_[numberNodes2_]);
+                statistics_[numberNodes2_] = new CbcStatistics(newNode, this);
+            }
+            numberNodes2_++;
+#     ifdef CHECK_NODE
+            printf("Node %x on tree\n", newNode) ;
+#     endif
+        } else {
+            // continuous is integer
+            double objectiveValue = newNode->objectiveValue();
+            setBestSolution(CBC_SOLUTION, objectiveValue,
+                            solver_->getColSolution()) ;
+            if (eventHandler) {
+	      // we are stopping anyway so no need to test return code
+	      eventHandler->event(CbcEventHandler::solution);
+            }
+            delete newNode ;
+            newNode = NULL ;
+        }
+    }
+
+    if (printFrequency_ <= 0) {
+        printFrequency_ = 1000 ;
+        if (getNumCols() > 2000)
+            printFrequency_ = 100 ;
+    }
+    /*
+      It is possible that strong branching fixes one variable and then the code goes round
+      again and again.  This can take too long.  So we need to warn user - just once.
+    */
+    numberLongStrong_ = 0;
+    CbcNode * createdNode = NULL;
+#ifdef CBC_THREAD
+    if ((specialOptions_&2048) != 0)
+        numberThreads_ = 0;
+    if (numberThreads_ ) {
+        nodeCompare_->sayThreaded(); // need to use addresses
+        master_ = new CbcBaseModel(*this,
+                                   (parallelMode() < -1) ? 1 : 0);
+        masterThread_ = master_->masterThread();
+    }
+#endif
+#ifdef COIN_HAS_CLP
+    {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver && !parentModel_) {
+            clpSolver->computeLargestAway();
+        }
+    }
+#endif
+    /*
+      At last, the actual branch-and-cut search loop, which will iterate until
+      the live set is empty or we hit some limit (integrality gap, time, node
+      count, etc.). The overall flow is to rebuild a subproblem, reoptimise using
+      solveWithCuts(), choose a branching pattern with chooseBranch(), and finally
+      add the node to the live set.
+
+      The first action is to winnow the live set to remove nodes which are worse
+      than the current objective cutoff.
+    */
+    if (solver_->getRowCutDebuggerAlways()) {
+        OsiRowCutDebugger * debuggerX = const_cast<OsiRowCutDebugger *> (solver_->getRowCutDebuggerAlways());
+        const OsiRowCutDebugger *debugger = solver_->getRowCutDebugger() ;
+        if (!debugger) {
+            // infeasible!!
+            printf("before search\n");
+            const double * lower = solver_->getColLower();
+            const double * upper = solver_->getColUpper();
+            const double * solution = debuggerX->optimalSolution();
+            int numberColumns = solver_->getNumCols();
+            for (int i = 0; i < numberColumns; i++) {
+                if (solver_->isInteger(i)) {
+                    if (solution[i] < lower[i] - 1.0e-6 || solution[i] > upper[i] + 1.0e-6)
+                        printf("**** ");
+                    printf("%d %g <= %g <= %g\n",
+                           i, lower[i], solution[i], upper[i]);
+                }
+            }
+            //abort();
+        }
+    }
+    {
+        // may be able to change cutoff now
+        double cutoff = getCutoff();
+        double increment = getDblParam(CbcModel::CbcCutoffIncrement) ;
+        if (cutoff > bestObjective_ - increment) {
+            cutoff = bestObjective_ - increment ;
+            setCutoff(cutoff) ;
+        }
+    }
+#ifdef CBC_THREAD
+    bool goneParallel = false;
+#endif
+#define MAX_DEL_NODE 1
+    CbcNode * delNode[MAX_DEL_NODE+1];
+    int nDeleteNode = 0;
+    // For Printing etc when parallel
+    int lastEvery1000 = 0;
+    int lastPrintEvery = 0;
+    int numberConsecutiveInfeasible = 0;
+#define PERTURB_IN_FATHOM
+#ifdef PERTURB_IN_FATHOM
+    // allow in fathom
+    if ((moreSpecialOptions_& 262144) != 0)
+      specialOptions_ |= 131072;
+#endif
+    while (true) {
+        lockThread();
+#ifdef COIN_HAS_CLP
+        // See if we want dantzig row choice
+        goToDantzig(100, savePivotMethod);
+#endif
+        if (tree_->empty()) {
+#ifdef CBC_THREAD
+            if (parallelMode() > 0 && master_) {
+                int anyLeft = master_->waitForThreadsInTree(0);
+                if (!anyLeft) {
+                    master_->stopThreads(-1);
+                    break;
+                }
+            } else {
+                break;
+            }
+#else
+            break;
+#endif
+        } else {
+            unlockThread();
+        }
+        // If done 100 nodes see if worth trying reduction
+        if (numberNodes_ == 50 || numberNodes_ == 100) {
+#ifdef COIN_HAS_CLP
+            OsiClpSolverInterface * clpSolver
+            = dynamic_cast<OsiClpSolverInterface *> (solver_);
+            if (clpSolver && ((specialOptions_&131072) == 0) && true) {
+                ClpSimplex * simplex = clpSolver->getModelPtr();
+                int perturbation = simplex->perturbation();
+#ifdef CLP_INVESTIGATE
+                printf("Testing its n,s %d %d solves n,s %d %d - pert %d\n",
+                       numberIterations_, saveNumberIterations,
+                       numberSolves_, saveNumberSolves, perturbation);
+#endif
+                if (perturbation == 50 && (numberIterations_ - saveNumberIterations) <
+                        8*(numberSolves_ - saveNumberSolves)) {
+                    // switch off perturbation
+                    simplex->setPerturbation(100);
+#ifdef CLP_INVESTIGATE
+                    printf("Perturbation switched off\n");
+#endif
+                }
+            }
+#endif
+            /*
+              Decide if we want to do a restart.
+            */
+            if (saveSolver && (specialOptions_&(512 + 32768)) != 0) {
+                bool tryNewSearch = solverCharacteristics_->reducedCostsAccurate() &&
+                                    (getCutoff() < 1.0e20 && getCutoff() < checkCutoffForRestart);
+                int numberColumns = getNumCols();
+                if (tryNewSearch) {
+                    checkCutoffForRestart = getCutoff() ;
+#ifdef CLP_INVESTIGATE
+                    printf("after %d nodes, cutoff %g - looking\n",
+                           numberNodes_, getCutoff());
+#endif
+                    saveSolver->resolve();
+                    double direction = saveSolver->getObjSense() ;
+                    double gap = checkCutoffForRestart - saveSolver->getObjValue() * direction ;
+                    double tolerance;
+                    saveSolver->getDblParam(OsiDualTolerance, tolerance) ;
+                    if (gap <= 0.0)
+                        gap = tolerance;
+                    gap += 100.0 * tolerance;
+                    double integerTolerance = getDblParam(CbcIntegerTolerance) ;
+
+                    const double *lower = saveSolver->getColLower() ;
+                    const double *upper = saveSolver->getColUpper() ;
+                    const double *solution = saveSolver->getColSolution() ;
+                    const double *reducedCost = saveSolver->getReducedCost() ;
+
+                    int numberFixed = 0 ;
+                    int numberFixed2 = 0;
+#ifdef COIN_DEVELOP
+                    printf("gap %g\n", gap);
+#endif
+                    for (int i = 0 ; i < numberIntegers_ ; i++) {
+                        int iColumn = integerVariable_[i] ;
+                        double djValue = direction * reducedCost[iColumn] ;
+                        if (upper[iColumn] - lower[iColumn] > integerTolerance) {
+                            if (solution[iColumn] < lower[iColumn] + integerTolerance && djValue > gap) {
+                                //printf("%d to lb on dj of %g - bounds %g %g\n",
+                                //     iColumn,djValue,lower[iColumn],upper[iColumn]);
+                                saveSolver->setColUpper(iColumn, lower[iColumn]) ;
+                                numberFixed++ ;
+                            } else if (solution[iColumn] > upper[iColumn] - integerTolerance && -djValue > gap) {
+                                //printf("%d to ub on dj of %g - bounds %g %g\n",
+                                //     iColumn,djValue,lower[iColumn],upper[iColumn]);
+                                saveSolver->setColLower(iColumn, upper[iColumn]) ;
+                                numberFixed++ ;
+                            }
+                        } else {
+                            //printf("%d has dj of %g - already fixed to %g\n",
+                            //     iColumn,djValue,lower[iColumn]);
+                            numberFixed2++;
+                        }
+                    }
+#ifdef COIN_DEVELOP
+                    if ((specialOptions_&1) != 0) {
+                        const OsiRowCutDebugger *debugger = saveSolver->getRowCutDebugger() ;
+                        if (debugger) {
+                            printf("Contains optimal\n") ;
+                            OsiSolverInterface * temp = saveSolver->clone();
+                            const double * solution = debugger->optimalSolution();
+                            const double *lower = temp->getColLower() ;
+                            const double *upper = temp->getColUpper() ;
+                            int n = temp->getNumCols();
+                            for (int i = 0; i < n; i++) {
+                                if (temp->isInteger(i)) {
+                                    double value = floor(solution[i] + 0.5);
+                                    assert (value >= lower[i] && value <= upper[i]);
+                                    temp->setColLower(i, value);
+                                    temp->setColUpper(i, value);
+                                }
+                            }
+                            temp->writeMps("reduced_fix");
+                            delete temp;
+                            saveSolver->writeMps("reduced");
+                        } else {
+                            abort();
+                        }
+                    }
+                    printf("Restart could fix %d integers (%d already fixed)\n",
+                           numberFixed + numberFixed2, numberFixed2);
+#endif
+                    numberFixed += numberFixed2;
+                    if (numberFixed*10 < numberColumns && numberFixed*4 < numberIntegers_)
+                        tryNewSearch = false;
+                }
+                if (tryNewSearch) {
+                    // back to solver without cuts?
+                    OsiSolverInterface * solver2 = saveSolver->clone();
+                    const double *lower = saveSolver->getColLower() ;
+                    const double *upper = saveSolver->getColUpper() ;
+                    for (int i = 0 ; i < numberIntegers_ ; i++) {
+                        int iColumn = integerVariable_[i] ;
+                        solver2->setColLower(iColumn, lower[iColumn]);
+                        solver2->setColUpper(iColumn, upper[iColumn]);
+                    }
+                    // swap
+                    delete saveSolver;
+                    saveSolver = solver2;
+                    double * newSolution = new double[numberColumns];
+                    double objectiveValue = checkCutoffForRestart;
+                    // Save the best solution so far.
+                    CbcSerendipity heuristic(*this);
+                    if (bestSolution_)
+                        heuristic.setInputSolution(bestSolution_, bestObjective_);
+                    // Magic number
+                    heuristic.setFractionSmall(0.8);
+                    // `pumpTune' to stand-alone solver for explanations.
+                    heuristic.setFeasibilityPumpOptions(1008013);
+                    // Use numberNodes to say how many are original rows
+                    heuristic.setNumberNodes(continuousSolver_->getNumRows());
+#ifdef COIN_DEVELOP
+                    if (continuousSolver_->getNumRows() <
+                            solver_->getNumRows())
+                        printf("%d rows added ZZZZZ\n",
+                               solver_->getNumRows() - continuousSolver_->getNumRows());
+#endif
+                    int returnCode = heuristic.smallBranchAndBound(saveSolver,
+                                     -1, newSolution,
+                                     objectiveValue,
+                                     checkCutoffForRestart, "Reduce");
+                    if (returnCode < 0) {
+#ifdef COIN_DEVELOP
+                        printf("Restart - not small enough to do search after fixing\n");
+#endif
+                        delete [] newSolution;
+                    } else {
+                        // 1 for sol'n, 2 for finished, 3 for both
+                        if ((returnCode&1) != 0) {
+                            // increment number of solutions so other heuristics can test
+                            numberSolutions_++;
+                            numberHeuristicSolutions_++;
+                            lastHeuristic_ = NULL;
+                            setBestSolution(CBC_ROUNDING, objectiveValue, newSolution) ;
+                        }
+                        delete [] newSolution;
+#ifdef CBC_THREAD
+                        if (master_) {
+                            lockThread();
+                            if (parallelMode() > 0) {
+                                while (master_->waitForThreadsInTree(0)) {
+                                    lockThread();
+                                    double dummyBest;
+                                    tree_->cleanTree(this, -COIN_DBL_MAX, dummyBest) ;
+                                    //unlockThread();
+                                }
+                            } else {
+                                double dummyBest;
+                                tree_->cleanTree(this, -COIN_DBL_MAX, dummyBest) ;
+			    }
+                            master_->waitForThreadsInTree(2);
+                            delete master_;
+                            master_ = NULL;
+                            masterThread_ = NULL;
+                        }
+#endif
+                        if (tree_->size()) {
+                            double dummyBest;
+                            tree_->cleanTree(this, -COIN_DBL_MAX, dummyBest) ;
+                        }
+                        break;
+                    }
+                }
+                delete saveSolver;
+                saveSolver = NULL;
+            }
+        }
+        /*
+          Check for abort on limits: node count, solution count, time, integrality gap.
+        */
+        if (!(numberNodes_ < intParam_[CbcMaxNumNode] &&
+                numberSolutions_ < intParam_[CbcMaxNumSol] &&
+                !maximumSecondsReached() &&
+                !stoppedOnGap_ && !eventHappened_ && (maximumNumberIterations_ < 0 ||
+                                                      numberIterations_ < maximumNumberIterations_))) {
+            // out of loop
+            break;
+        }
+#ifdef BONMIN
+        assert(!solverCharacteristics_->solutionAddsCuts() || solverCharacteristics_->mipFeasible());
+#endif
+// Sets percentage of time when we try diving. Diving requires a bit of heap reorganisation, because
+// we need to replace the comparison function to dive, and that requires reordering to retain the
+// heap property.
+#define DIVE_WHEN 1000
+#define DIVE_STOP 2000
+        int kNode = numberNodes_ % 4000;
+        if (numberNodes_<100000 && kNode>DIVE_WHEN && kNode <= DIVE_STOP) {
+            if (!parallelMode()) {
+                if (kNode == DIVE_WHEN + 1 || numberConsecutiveInfeasible > 1) {
+                    CbcCompareDefault * compare = dynamic_cast<CbcCompareDefault *>
+                                                  (nodeCompare_);
+                    // Don't interfere if user has replaced the compare function.
+                    if (compare) {
+                        //printf("Redoing tree\n");
+                        compare->startDive(this);
+                        numberConsecutiveInfeasible = 0;
+                    }
+                }
+            }
+        }
+        // replace current cutoff?
+        if (cutoff > getCutoff()) {
+            double newCutoff = getCutoff();
+            if (analyzeResults_) {
+                // see if we could fix any (more)
+                int n = 0;
+                double * newLower = analyzeResults_;
+                double * objLower = newLower + numberIntegers_;
+                double * newUpper = objLower + numberIntegers_;
+                double * objUpper = newUpper + numberIntegers_;
+                for (int i = 0; i < numberIntegers_; i++) {
+                    if (objLower[i] > newCutoff) {
+                        n++;
+                        if (objUpper[i] > newCutoff) {
+                            newCutoff = -COIN_DBL_MAX;
+                            break;
+                        }
+                    } else if (objUpper[i] > newCutoff) {
+                        n++;
+                    }
+                }
+                if (newCutoff == -COIN_DBL_MAX) {
+		  COIN_DETAIL_PRINT(printf("Root analysis says finished\n"));
+                } else if (n > numberFixedNow_) {
+		  COIN_DETAIL_PRINT(printf("%d more fixed by analysis - now %d\n", n - numberFixedNow_, n));
+                    numberFixedNow_ = n;
+                }
+            }
+            if (eventHandler) {
+                if (!eventHandler->event(CbcEventHandler::solution)) {
+                    eventHappened_ = true; // exit
+                }
+                newCutoff = getCutoff();
+            }
+            lockThread();
+            /*
+              Clean the tree to reflect the new solution, then see if the
+              node comparison predicate wants to make any changes. If so,
+              call setComparison for the side effect of rebuilding the heap.
+            */
+            tree_->cleanTree(this,newCutoff,bestPossibleObjective_) ;
+            if (nodeCompare_->newSolution(this) ||
+                nodeCompare_->newSolution(this,continuousObjective_,
+                                          continuousInfeasibilities_)) {
+              tree_->setComparison(*nodeCompare_) ;
+            }
+            if (tree_->empty()) {
+                continue;
+            }
+            unlockThread();
+        }
+        cutoff = getCutoff() ;
+        /*
+            Periodic activities: Opportunities to
+            + tweak the nodeCompare criteria,
+            + check if we've closed the integrality gap enough to quit,
+            + print a summary line to let the user know we're working
+        */
+        if (numberNodes_ >= lastEvery1000) {
+            lockThread();
+#ifdef COIN_HAS_CLP
+            // See if we want dantzig row choice
+            goToDantzig(1000, savePivotMethod);
+#endif
+            lastEvery1000 = numberNodes_ + 1000;
+            bool redoTree = nodeCompare_->every1000Nodes(this, numberNodes_) ;
+#ifdef CHECK_CUT_SIZE
+            verifyCutSize (tree_, *this);
+#endif
+            // redo tree if requested
+            if (redoTree)
+                tree_->setComparison(*nodeCompare_) ;
+            unlockThread();
+        }
+        // Had hotstart before, now switched off
+        if (saveCompare && !hotstartSolution_) {
+            // hotstart switched off
+            delete nodeCompare_; // off depth first
+            nodeCompare_ = saveCompare;
+            saveCompare = NULL;
+            // redo tree
+            lockThread();
+            tree_->setComparison(*nodeCompare_) ;
+            unlockThread();
+        }
+        if (numberNodes_ >= lastPrintEvery) {
+            lastPrintEvery = numberNodes_ + printFrequency_;
+            lockThread();
+            int nNodes = tree_->size() ;
+
+            //MODIF PIERRE
+            bestPossibleObjective_ = tree_->getBestPossibleObjective();
+            unlockThread();
+#ifdef CLP_INVESTIGATE
+            if (getCutoff() < 1.0e20) {
+                if (fabs(getCutoff() - (bestObjective_ - getCutoffIncrement())) > 1.0e-6 &&
+                        !parentModel_)
+                    printf("model cutoff in status %g, best %g, increment %g\n",
+                           getCutoff(), bestObjective_, getCutoffIncrement());
+                assert (getCutoff() < bestObjective_ - getCutoffIncrement() +
+                        1.0e-6 + 1.0e-10*fabs(bestObjective_));
+            }
+#endif
+            if (!intParam_[CbcPrinting]) {
+                messageHandler()->message(CBC_STATUS, messages())
+                << numberNodes_ << nNodes << bestObjective_ << bestPossibleObjective_
+                << getCurrentSeconds()
+                << CoinMessageEol ;
+            } else if (intParam_[CbcPrinting] == 1) {
+                messageHandler()->message(CBC_STATUS2, messages())
+                << numberNodes_ << nNodes << bestObjective_ << bestPossibleObjective_
+                << lastDepth << lastUnsatisfied << numberIterations_
+                << getCurrentSeconds()
+                << CoinMessageEol ;
+            } else if (!numberExtraIterations_) {
+                messageHandler()->message(CBC_STATUS2, messages())
+                << numberNodes_ << nNodes << bestObjective_ << bestPossibleObjective_
+                << lastDepth << lastUnsatisfied << numberIterations_
+                << getCurrentSeconds()
+                << CoinMessageEol ;
+            } else {
+                messageHandler()->message(CBC_STATUS3, messages())
+                << numberNodes_ << numberExtraNodes_ << nNodes << bestObjective_ << bestPossibleObjective_
+                << lastDepth << lastUnsatisfied << numberIterations_ << numberExtraIterations_
+                << getCurrentSeconds()
+                << CoinMessageEol ;
+            }
+            if (eventHandler && !eventHandler->event(CbcEventHandler::treeStatus)) {
+                eventHappened_ = true; // exit
+            }
+        }
+        // See if can stop on gap
+	if(canStopOnGap()) {
+            stoppedOnGap_ = true ;
+        }
+
+#ifdef CHECK_NODE_FULL
+        verifyTreeNodes(tree_, *this) ;
+#   endif
+#   ifdef CHECK_CUT_COUNTS
+        verifyCutCounts(tree_, *this) ;
+#   endif
+        /*
+          Now we come to the meat of the loop. To create the active subproblem, we'll
+          pop the most promising node in the live set, rebuild the subproblem it
+          represents, and then execute the current arm of the branch to create the
+          active subproblem.
+        */
+        CbcNode * node = NULL;
+#ifdef CBC_THREAD
+        if (!parallelMode() || parallelMode() == -1) {
+#endif
+            node = tree_->bestNode(cutoff) ;
+            // Possible one on tree worse than cutoff
+            // Weird comparison function can leave ineligible nodes on tree
+            if (!node || node->objectiveValue() > cutoff)
+                continue;
+	    // Do main work of solving node here
+	    doOneNode(this, node, createdNode);
+#ifdef JJF_ZERO
+	    if (node) {
+	      if (createdNode) {
+		printf("Node %d depth %d, created %d depth %d\n",
+		       node->nodeNumber(), node->depth(),
+		       createdNode->nodeNumber(), createdNode->depth());
+	      } else {
+		printf("Node %d depth %d,  no created node\n",
+		       node->nodeNumber(), node->depth());
+	      }
+	    } else if (createdNode) {
+	      printf("Node exhausted, created %d depth %d\n",
+		     createdNode->nodeNumber(), createdNode->depth());
+	    } else {
+	      printf("Node exhausted,  no created node\n");
+	      numberConsecutiveInfeasible = 2;
+	    }
+#endif
+            //if (createdNode)
+            //numberConsecutiveInfeasible=0;
+            //else
+            //numberConsecutiveInfeasible++;
+#ifdef CBC_THREAD
+        } else if (parallelMode() > 0) {
+            //lockThread();
+            //node = tree_->bestNode(cutoff) ;
+            // Possible one on tree worse than cutoff
+            if (true || !node || node->objectiveValue() > cutoff) {
+                assert (master_);
+                if (master_) {
+                    int anyLeft = master_->waitForThreadsInTree(1);
+                    // may need to go round again
+                    if (anyLeft) {
+                        continue;
+                    } else {
+                        master_->stopThreads(-1);
+                    }
+                }
+            }
+            //unlockThread();
+        } else {
+            // Deterministic parallel
+            if (tree_->size() < CoinMax(numberThreads_, 8) && !goneParallel) {
+                node = tree_->bestNode(cutoff) ;
+                // Possible one on tree worse than cutoff
+                if (!node || node->objectiveValue() > cutoff)
+                    continue;
+                // Do main work of solving node here
+                doOneNode(this, node, createdNode);
+                assert (createdNode);
+                if (!createdNode->active()) {
+                    delete createdNode;
+                    createdNode = NULL;
+                } else {
+                    // Say one more pointing to this
+                    node->nodeInfo()->increment() ;
+                    tree_->push(createdNode) ;
+                }
+                if (node->active()) {
+                    assert (node->nodeInfo());
+                    if (node->nodeInfo()->numberBranchesLeft()) {
+                        tree_->push(node) ;
+                    } else {
+                        node->setActive(false);
+                    }
+                } else {
+                    if (node->nodeInfo()) {
+                        if (!node->nodeInfo()->numberBranchesLeft())
+                            node->nodeInfo()->allBranchesGone(); // can clean up
+                        // So will delete underlying stuff
+                        node->setActive(true);
+                    }
+                    delNode[nDeleteNode++] = node;
+                    node = NULL;
+                }
+                if (nDeleteNode >= MAX_DEL_NODE) {
+                    for (int i = 0; i < nDeleteNode; i++) {
+                        //printf("trying to del %d %x\n",i,delNode[i]);
+                        delete delNode[i];
+                        //printf("done to del %d %x\n",i,delNode[i]);
+                    }
+                    nDeleteNode = 0;
+                }
+            } else {
+                // Split and solve
+                master_->deterministicParallel();
+                goneParallel = true;
+            }
+        }
+#endif
+    }
+    if (nDeleteNode) {
+        for (int i = 0; i < nDeleteNode; i++) {
+            delete delNode[i];
+        }
+        nDeleteNode = 0;
+    }
+#ifdef CBC_THREAD
+    if (master_) {
+        master_->stopThreads(-1);
+        master_->waitForThreadsInTree(2);
+        delete master_;
+        master_ = NULL;
+        masterThread_ = NULL;
+        // adjust time to allow for children on some systems
+        //dblParam_[CbcStartSeconds] -= CoinCpuTimeJustChildren();
+    }
+#endif
+    /*
+      End of the non-abort actions. The next block of code is executed if we've
+      aborted because we hit one of the limits. Clean up by deleting the live set
+      and break out of the node processing loop. Note that on an abort, node may
+      have been pushed back onto the tree for further processing, in which case
+      it'll be deleted in cleanTree. We need to check.
+    */
+    if (!(numberNodes_ < intParam_[CbcMaxNumNode] &&
+          numberSolutions_ < intParam_[CbcMaxNumSol] &&
+          !maximumSecondsReached() &&
+          !stoppedOnGap_ &&
+          !eventHappened_ &&
+          (maximumNumberIterations_ < 0 || numberIterations_ < maximumNumberIterations_))
+         ) {
+        if (tree_->size()) {
+            double dummyBest;
+            tree_->cleanTree(this, -COIN_DBL_MAX, dummyBest) ;
+        }
+        delete nextRowCut_;
+        /* order is important here:
+         * maximumSecondsReached() should be checked before eventHappened_ and
+         * isNodeLimitReached() should be checked after eventHappened_
+         * reason is, that at timelimit, eventHappened_ is set to true to make Cbc stop fast
+         *   and if Ctrl+C is hit, then the nodelimit is set to -1 to make Cbc stop
+         */
+        if (stoppedOnGap_) {
+            messageHandler()->message(CBC_GAP, messages())
+            << bestObjective_ - bestPossibleObjective_
+            << dblParam_[CbcAllowableGap]
+            << dblParam_[CbcAllowableFractionGap]*100.0
+            << CoinMessageEol ;
+            secondaryStatus_ = 2;
+            status_ = 0 ;
+        } else if (maximumSecondsReached()) {
+            handler_->message(CBC_MAXTIME, messages_) << CoinMessageEol ;
+            secondaryStatus_ = 4;
+            status_ = 1 ;
+        } else if (numberSolutions_ >= intParam_[CbcMaxNumSol]) {
+            handler_->message(CBC_MAXSOLS, messages_) << CoinMessageEol ;
+            secondaryStatus_ = 6;
+            status_ = 1 ;
+        } else if (isNodeLimitReached()) {
+            handler_->message(CBC_MAXNODES, messages_) << CoinMessageEol ;
+            secondaryStatus_ = 3;
+            status_ = 1 ;
+        } else if (maximumNumberIterations_ >= 0 && numberIterations_ >= maximumNumberIterations_) {
+            handler_->message(CBC_MAXITERS, messages_) << CoinMessageEol ;
+            secondaryStatus_ = 8;
+            status_ = 1 ;
+        } else {
+            handler_->message(CBC_EVENT, messages_) << CoinMessageEol ;
+            secondaryStatus_ = 5;
+            status_ = 5 ;
+        }
+    }
+    /*
+      That's it, we've exhausted the search tree, or broken out of the loop because
+      we hit some limit on evaluation.
+
+      We may have got an intelligent tree so give it one more chance
+    */
+    // Tell solver we are not in Branch and Cut
+    solver_->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo, NULL) ;
+    tree_->endSearch();
+    //  If we did any sub trees - did we give up on any?
+    if ( numberStoppedSubTrees_)
+        status_ = 1;
+    numberNodes_ += numberExtraNodes_;
+    numberIterations_ += numberExtraIterations_;
+    if (eventHandler) {
+        eventHandler->event(CbcEventHandler::endSearch);
+    }
+    if (!status_) {
+        // Set best possible unless stopped on gap
+        if (secondaryStatus_ != 2)
+            bestPossibleObjective_ = bestObjective_;
+        handler_->message(CBC_END_GOOD, messages_)
+        << bestObjective_ << numberIterations_ << numberNodes_ << getCurrentSeconds()
+        << CoinMessageEol ;
+    } else {
+        handler_->message(CBC_END, messages_)
+        << bestObjective_ << bestPossibleObjective_
+        << numberIterations_ << numberNodes_ << getCurrentSeconds()
+        << CoinMessageEol ;
+    }
+    if (numberStrongIterations_)
+        handler_->message(CBC_STRONG_STATS, messages_)
+        << strongInfo_[0] << numberStrongIterations_ << strongInfo_[2]
+        << strongInfo_[1] << CoinMessageEol ;
+    if (!numberExtraNodes_)
+        handler_->message(CBC_OTHER_STATS, messages_)
+        << maximumDepthActual_
+        << numberDJFixed_ << CoinMessageEol ;
+    else
+        handler_->message(CBC_OTHER_STATS2, messages_)
+        << maximumDepthActual_
+        << numberDJFixed_ << numberExtraNodes_ << numberExtraIterations_
+        << CoinMessageEol ;
+    if (doStatistics == 100) {
+        for (int i = 0; i < numberObjects_; i++) {
+            CbcSimpleIntegerDynamicPseudoCost * obj =
+                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[i]) ;
+            if (obj)
+                obj->print();
+        }
+    }
+    if (statistics_) {
+        // report in some way
+        int * lookup = new int[numberObjects_];
+        int i;
+        for (i = 0; i < numberObjects_; i++)
+            lookup[i] = -1;
+        bool goodIds = false; //true;
+        for (i = 0; i < numberObjects_; i++) {
+            int iColumn = object_[i]->columnNumber();
+            if (iColumn >= 0 && iColumn < numberColumns) {
+                if (lookup[i] == -1) {
+                    lookup[i] = iColumn;
+                } else {
+                    goodIds = false;
+                    break;
+                }
+            } else {
+                goodIds = false;
+                break;
+            }
+        }
+        if (!goodIds) {
+            delete [] lookup;
+            lookup = NULL;
+        }
+        if (doStatistics >= 3) {
+            printf("  node parent depth column   value                    obj      inf\n");
+            for ( i = 0; i < numberNodes2_; i++) {
+                statistics_[i]->print(lookup);
+            }
+        }
+        if (doStatistics > 1) {
+            // Find last solution
+            int k;
+            for (k = numberNodes2_ - 1; k >= 0; k--) {
+                if (statistics_[k]->endingObjective() != COIN_DBL_MAX &&
+                        !statistics_[k]->endingInfeasibility())
+                    break;
+            }
+            if (k >= 0) {
+                int depth = statistics_[k]->depth();
+                int * which = new int[depth+1];
+                for (i = depth; i >= 0; i--) {
+                    which[i] = k;
+                    k = statistics_[k]->parentNode();
+                }
+                printf("  node parent depth column   value                    obj      inf\n");
+                for (i = 0; i <= depth; i++) {
+                    statistics_[which[i]]->print(lookup);
+                }
+                delete [] which;
+            }
+        }
+        // now summary
+        int maxDepth = 0;
+        double averageSolutionDepth = 0.0;
+        int numberSolutions = 0;
+        double averageCutoffDepth = 0.0;
+        double averageSolvedDepth = 0.0;
+        int numberCutoff = 0;
+        int numberDown = 0;
+        int numberFirstDown = 0;
+        double averageInfDown = 0.0;
+        double averageObjDown = 0.0;
+        int numberCutoffDown = 0;
+        int numberUp = 0;
+        int numberFirstUp = 0;
+        double averageInfUp = 0.0;
+        double averageObjUp = 0.0;
+        int numberCutoffUp = 0;
+        double averageNumberIterations1 = 0.0;
+        double averageValue = 0.0;
+        for ( i = 0; i < numberNodes2_; i++) {
+            int depth =  statistics_[i]->depth();
+            int way =  statistics_[i]->way();
+            double value = statistics_[i]->value();
+            double startingObjective =  statistics_[i]->startingObjective();
+            int startingInfeasibility = statistics_[i]->startingInfeasibility();
+            double endingObjective = statistics_[i]->endingObjective();
+            int endingInfeasibility = statistics_[i]->endingInfeasibility();
+            maxDepth = CoinMax(depth, maxDepth);
+            // Only for completed
+            averageNumberIterations1 += statistics_[i]->numberIterations();
+            averageValue += value;
+            if (endingObjective != COIN_DBL_MAX && !endingInfeasibility) {
+                numberSolutions++;
+                averageSolutionDepth += depth;
+            }
+            if (endingObjective == COIN_DBL_MAX) {
+                numberCutoff++;
+                averageCutoffDepth += depth;
+                if (way < 0) {
+                    numberDown++;
+                    numberCutoffDown++;
+                    if (way == -1)
+                        numberFirstDown++;
+                } else {
+                    numberUp++;
+                    numberCutoffUp++;
+                    if (way == 1)
+                        numberFirstUp++;
+                }
+            } else {
+                averageSolvedDepth += depth;
+                if (way < 0) {
+                    numberDown++;
+                    averageInfDown += startingInfeasibility - endingInfeasibility;
+                    averageObjDown += endingObjective - startingObjective;
+                    if (way == -1)
+                        numberFirstDown++;
+                } else {
+                    numberUp++;
+                    averageInfUp += startingInfeasibility - endingInfeasibility;
+                    averageObjUp += endingObjective - startingObjective;
+                    if (way == 1)
+                        numberFirstUp++;
+                }
+            }
+        }
+        // Now print
+        if (numberSolutions)
+            averageSolutionDepth /= static_cast<double> (numberSolutions);
+        int numberSolved = numberNodes2_ - numberCutoff;
+        double averageNumberIterations2 = numberIterations_ - averageNumberIterations1
+                                          - numberIterationsAtContinuous;
+        if (numberCutoff) {
+            averageCutoffDepth /= static_cast<double> (numberCutoff);
+            averageNumberIterations2 /= static_cast<double> (numberCutoff);
+        }
+        if (numberNodes2_)
+            averageValue /= static_cast<double> (numberNodes2_);
+        if (numberSolved) {
+            averageNumberIterations1 /= static_cast<double> (numberSolved);
+            averageSolvedDepth /= static_cast<double> (numberSolved);
+        }
+        printf("%d solution(s) were found (by branching) at an average depth of %g\n",
+               numberSolutions, averageSolutionDepth);
+        printf("average value of variable being branched on was %g\n",
+               averageValue);
+        printf("%d nodes were cutoff at an average depth of %g with iteration count of %g\n",
+               numberCutoff, averageCutoffDepth, averageNumberIterations2);
+        printf("%d nodes were solved at an average depth of %g with iteration count of %g\n",
+               numberSolved, averageSolvedDepth, averageNumberIterations1);
+        if (numberDown) {
+            averageInfDown /= static_cast<double> (numberDown);
+            averageObjDown /= static_cast<double> (numberDown);
+        }
+        printf("Down %d nodes (%d first, %d second) - %d cutoff, rest decrease numinf %g increase obj %g\n",
+               numberDown, numberFirstDown, numberDown - numberFirstDown, numberCutoffDown,
+               averageInfDown, averageObjDown);
+        if (numberUp) {
+            averageInfUp /= static_cast<double> (numberUp);
+            averageObjUp /= static_cast<double> (numberUp);
+        }
+        printf("Up %d nodes (%d first, %d second) - %d cutoff, rest decrease numinf %g increase obj %g\n",
+               numberUp, numberFirstUp, numberUp - numberFirstUp, numberCutoffUp,
+               averageInfUp, averageObjUp);
+        for ( i = 0; i < numberNodes2_; i++)
+            delete statistics_[i];
+        delete [] statistics_;
+        statistics_ = NULL;
+        maximumStatistics_ = 0;
+        delete [] lookup;
+    }
+    /*
+      If we think we have a solution, restore and confirm it with a call to
+      setBestSolution().  We need to reset the cutoff value so as not to fathom
+      the solution on bounds.  Note that calling setBestSolution( ..., true)
+      leaves the continuousSolver_ bounds vectors fixed at the solution value.
+
+      Running resolve() here is a failsafe --- setBestSolution has already
+      reoptimised using the continuousSolver_. If for some reason we fail to
+      prove optimality, run the problem again after instructing the solver to
+      tell us more.
+
+      If all looks good, replace solver_ with continuousSolver_, so that the
+      outside world will be able to obtain information about the solution using
+      public methods.
+
+      Don't replace if we are trying to save cuts
+    */
+    if (bestSolution_ && (solverCharacteristics_->solverType() < 2 || solverCharacteristics_->solverType() == 4) && 
+	((specialOptions_&8388608)==0||(specialOptions_&2048)!=0)) {
+        setCutoff(1.0e50) ; // As best solution should be worse than cutoff
+	// change cutoff as constraint if wanted
+	if (cutoffRowNumber_>=0) {
+	  if (solver_->getNumRows()>cutoffRowNumber_)
+	    solver_->setRowUpper(cutoffRowNumber_,1.0e50);
+	}
+	// also in continuousSolver_
+	if (continuousSolver_) {
+	  // Solvers know about direction
+	  double direction = solver_->getObjSense();
+	  continuousSolver_->setDblParam(OsiDualObjectiveLimit, 1.0e50*direction);
+	}
+        phase_ = 5;
+        double increment = getDblParam(CbcModel::CbcCutoffIncrement) ;
+        if ((specialOptions_&4) == 0)
+            bestObjective_ += 100.0 * increment + 1.0e-3; // only set if we are going to solve
+        setBestSolution(CBC_END_SOLUTION, bestObjective_, bestSolution_, 1) ;
+        continuousSolver_->resolve() ;
+        if (!continuousSolver_->isProvenOptimal()) {
+            continuousSolver_->messageHandler()->setLogLevel(2) ;
+            continuousSolver_->initialSolve() ;
+        }
+        delete solver_ ;
+        // above deletes solverCharacteristics_
+        solverCharacteristics_ = NULL;
+        solver_ = continuousSolver_ ;
+        setPointers(solver_);
+        continuousSolver_ = NULL ;
+    }
+    /*
+      Clean up dangling objects. continuousSolver_ may already be toast.
+    */
+    delete lastws ;
+    if (saveObjects) {
+        for (int i = 0; i < numberObjects_; i++)
+            delete saveObjects[i];
+        delete [] saveObjects;
+    }
+    numberStrong_ = saveNumberStrong;
+    numberBeforeTrust_ = saveNumberBeforeTrust;
+    delete [] whichGenerator_ ;
+    whichGenerator_ = NULL;
+    delete [] lowerBefore ;
+    delete [] upperBefore ;
+    delete [] walkback_ ;
+    walkback_ = NULL ;
+    delete [] lastNodeInfo_ ;
+    lastNodeInfo_ = NULL;
+    delete [] lastNumberCuts_ ;
+    lastNumberCuts_ = NULL;
+    delete [] lastCut_;
+    lastCut_ = NULL;
+    delete [] addedCuts_ ;
+    addedCuts_ = NULL ;
+    //delete persistentInfo;
+    // Get rid of characteristics
+    solverCharacteristics_ = NULL;
+    if (continuousSolver_) {
+        delete continuousSolver_ ;
+        continuousSolver_ = NULL ;
+    }
+    /*
+      Destroy global cuts by replacing with an empty OsiCuts object.
+    */
+    globalCuts_ = CbcRowCuts() ;
+    delete globalConflictCuts_;
+    globalConflictCuts_=NULL;
+    if (!bestSolution_ && (specialOptions_&8388608)==0) {
+        // make sure lp solver is infeasible
+        int numberColumns = solver_->getNumCols();
+        const double * columnLower = solver_->getColLower();
+        int iColumn;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (solver_->isInteger(iColumn))
+                solver_->setColUpper(iColumn, columnLower[iColumn]);
+        }
+        solver_->initialSolve();
+    }
+#ifdef COIN_HAS_CLP
+    {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver) {
+            // Possible restore of pivot method
+            if (savePivotMethod) {
+                // model may have changed
+                savePivotMethod->setModel(NULL);
+                clpSolver->getModelPtr()->setDualRowPivotAlgorithm(*savePivotMethod);
+                delete savePivotMethod;
+            }
+            clpSolver->setLargestAway(-1.0);
+        }
+    }
+#endif
+    if ((fastNodeDepth_ >= 1000000 || (moreSpecialOptions_&33554432)!=0)
+	 && !parentModel_) {
+      // delete object off end
+      delete object_[numberObjects_];
+      if ((moreSpecialOptions_&33554432)==0)
+        fastNodeDepth_ -= 1000000;
+    }
+    delete saveSolver;
+    // Undo preprocessing performed during BaB.
+    if (strategy_ && strategy_->preProcessState() > 0) {
+        // undo preprocessing
+        CglPreProcess * process = strategy_->process();
+        assert (process);
+        int n = originalSolver->getNumCols();
+        if (bestSolution_) {
+            delete [] bestSolution_;
+            bestSolution_ = new double [n];
+            process->postProcess(*solver_);
+        }
+        strategy_->deletePreProcess();
+        // Solution now back in originalSolver
+        delete solver_;
+        solver_ = originalSolver;
+        if (bestSolution_) {
+            bestObjective_ = solver_->getObjValue() * solver_->getObjSense();
+            memcpy(bestSolution_, solver_->getColSolution(), n*sizeof(double));
+        }
+        // put back original objects if there were any
+        if (originalObject) {
+            int iColumn;
+            assert (ownObjects_);
+            for (iColumn = 0; iColumn < numberObjects_; iColumn++)
+                delete object_[iColumn];
+            delete [] object_;
+            numberObjects_ = numberOriginalObjects;
+            object_ = originalObject;
+            delete [] integerVariable_;
+            numberIntegers_ = 0;
+            for (iColumn = 0; iColumn < n; iColumn++) {
+                if (solver_->isInteger(iColumn))
+                    numberIntegers_++;
+            }
+            integerVariable_ = new int[numberIntegers_];
+            numberIntegers_ = 0;
+            for (iColumn = 0; iColumn < n; iColumn++) {
+                if (solver_->isInteger(iColumn))
+                    integerVariable_[numberIntegers_++] = iColumn;
+            }
+        }
+    }
+    if (flipObjective)
+      flipModel();
+#ifdef COIN_HAS_CLP
+    {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver)
+            clpSolver->setFakeObjective(reinterpret_cast<double *> (NULL));
+    }
+#endif
+    moreSpecialOptions_ = saveMoreSpecialOptions;
+    return ;
+}
+
+
+// Solve the initial LP relaxation
+void
+CbcModel::initialSolve()
+{
+    assert (solver_);
+    // Double check optimization directions line up
+    dblParam_[CbcOptimizationDirection] = solver_->getObjSense();
+    // Check if bounds are all integral (as may get messed up later)
+    checkModel();
+    if (!solverCharacteristics_) {
+        OsiBabSolver * solverCharacteristics = dynamic_cast<OsiBabSolver *> (solver_->getAuxiliaryInfo());
+        if (solverCharacteristics) {
+            solverCharacteristics_ = solverCharacteristics;
+        } else {
+            // replace in solver
+            OsiBabSolver defaultC;
+            solver_->setAuxiliaryInfo(&defaultC);
+            solverCharacteristics_ = dynamic_cast<OsiBabSolver *> (solver_->getAuxiliaryInfo());
+        }
+    }
+    solverCharacteristics_->setSolver(solver_);
+    solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+    solver_->initialSolve();
+    solver_->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo, NULL) ;
+    if (!solver_->isProvenOptimal())
+        solver_->resolve();
+    // But set up so Jon Lee will be happy
+    status_ = -1;
+    secondaryStatus_ = -1;
+    originalContinuousObjective_ = solver_->getObjValue() * solver_->getObjSense();
+    bestPossibleObjective_ = originalContinuousObjective_;
+    delete [] continuousSolution_;
+    continuousSolution_ = CoinCopyOfArray(solver_->getColSolution(),
+                                          solver_->getNumCols());
+    setPointers(solver_);
+    solverCharacteristics_ = NULL;
+}
+
+/*! \brief Get an empty basis object
+
+  Return an empty CoinWarmStartBasis object with the requested capacity,
+  appropriate for the current solver. The object is cloned from the object
+  cached as emptyWarmStart_. If there is no cached object, the routine
+  queries the solver for a warm start object, empties it, and caches the
+  result.
+*/
+
+CoinWarmStartBasis *CbcModel::getEmptyBasis (int ns, int na) const
+
+{
+    CoinWarmStartBasis *emptyBasis ;
+    /*
+      Acquire an empty basis object, if we don't yet have one.
+    */
+    if (emptyWarmStart_ == 0) {
+        if (solver_ == 0) {
+            throw CoinError("Cannot construct basis without solver!",
+                            "getEmptyBasis", "CbcModel") ;
+        }
+        emptyBasis =
+            dynamic_cast<CoinWarmStartBasis *>(solver_->getEmptyWarmStart()) ;
+        if (emptyBasis == 0) {
+            throw CoinError(
+                "Solver does not appear to use a basis-oriented warm start.",
+                "getEmptyBasis", "CbcModel") ;
+        }
+        emptyBasis->setSize(0, 0) ;
+        emptyWarmStart_ = dynamic_cast<CoinWarmStart *>(emptyBasis) ;
+    }
+    /*
+      Clone the empty basis object, resize it as requested, and return.
+    */
+    emptyBasis = dynamic_cast<CoinWarmStartBasis *>(emptyWarmStart_->clone()) ;
+    assert(emptyBasis) ;
+    if (ns != 0 || na != 0) emptyBasis->setSize(ns, na) ;
+
+    return (emptyBasis) ;
+}
+
+
+/** Default Constructor
+
+  Creates an empty model without an associated solver.
+*/
+CbcModel::CbcModel()
+
+        :
+        solver_(NULL),
+        ownership_(0x80000000),
+        continuousSolver_(NULL),
+        referenceSolver_(NULL),
+        defaultHandler_(true),
+        emptyWarmStart_(NULL),
+        bestObjective_(COIN_DBL_MAX),
+        bestPossibleObjective_(COIN_DBL_MAX),
+        sumChangeObjective1_(0.0),
+        sumChangeObjective2_(0.0),
+        bestSolution_(NULL),
+        savedSolutions_(NULL),
+        currentSolution_(NULL),
+        testSolution_(NULL),
+	globalConflictCuts_(NULL),
+        minimumDrop_(1.0e-4),
+        numberSolutions_(0),
+        numberSavedSolutions_(0),
+        maximumSavedSolutions_(0),
+        stateOfSearch_(0),
+        whenCuts_(-1),
+        hotstartSolution_(NULL),
+        hotstartPriorities_(NULL),
+        numberHeuristicSolutions_(0),
+        numberNodes_(0),
+        numberNodes2_(0),
+        numberIterations_(0),
+        numberSolves_(0),
+        status_(-1),
+        secondaryStatus_(-1),
+        numberIntegers_(0),
+        numberRowsAtContinuous_(0),
+	cutoffRowNumber_(-1),
+        maximumNumberCuts_(0),
+        phase_(0),
+        currentNumberCuts_(0),
+        maximumDepth_(0),
+        walkback_(NULL),
+        lastNodeInfo_(NULL),
+        lastCut_(NULL),
+        lastDepth_(0),
+        lastNumberCuts2_(0),
+        maximumCuts_(0),
+        lastNumberCuts_(NULL),
+        addedCuts_(NULL),
+        nextRowCut_(NULL),
+        currentNode_(NULL),
+        integerVariable_(NULL),
+        integerInfo_(NULL),
+        continuousSolution_(NULL),
+        usedInSolution_(NULL),
+        specialOptions_(0),
+        moreSpecialOptions_(0),
+	topOfTree_(NULL),
+        subTreeModel_(NULL),
+	heuristicModel_(NULL),
+        numberStoppedSubTrees_(0),
+        presolve_(0),
+        numberStrong_(5),
+        numberBeforeTrust_(10),
+        numberPenalties_(20),
+        stopNumberIterations_(-1),
+        penaltyScaleFactor_(3.0),
+        numberAnalyzeIterations_(0),
+        analyzeResults_(NULL),
+        numberInfeasibleNodes_(0),
+        problemType_(0),
+        printFrequency_(0),
+        numberCutGenerators_(0),
+        generator_(NULL),
+        virginGenerator_(NULL),
+        numberHeuristics_(0),
+        heuristic_(NULL),
+        lastHeuristic_(NULL),
+        fastNodeDepth_(-1),
+        eventHandler_(NULL),
+        numberObjects_(0),
+        object_(NULL),
+        ownObjects_(true),
+        originalColumns_(NULL),
+        howOftenGlobalScan_(3),
+        numberGlobalViolations_(0),
+        numberExtraIterations_(0),
+        numberExtraNodes_(0),
+        continuousObjective_(COIN_DBL_MAX),
+        originalContinuousObjective_(COIN_DBL_MAX),
+        continuousInfeasibilities_(COIN_INT_MAX),
+        maximumCutPassesAtRoot_(20),
+        maximumCutPasses_(10),
+        preferredWay_(0),
+        currentPassNumber_(0),
+        maximumWhich_(1000),
+        maximumRows_(0),
+	randomSeed_(-1),
+	multipleRootTries_(0),
+        currentDepth_(0),
+        whichGenerator_(NULL),
+        maximumStatistics_(0),
+        statistics_(NULL),
+        maximumDepthActual_(0),
+        numberDJFixed_(0.0),
+        probingInfo_(NULL),
+        numberFixedAtRoot_(0),
+        numberFixedNow_(0),
+        stoppedOnGap_(false),
+        eventHappened_(false),
+        numberLongStrong_(0),
+        numberOldActiveCuts_(0),
+        numberNewCuts_(0),
+        searchStrategy_(-1),
+	strongStrategy_(0),
+        numberStrongIterations_(0),
+        resolveAfterTakeOffCuts_(true),
+        maximumNumberIterations_(-1),
+        continuousPriority_(COIN_INT_MAX),
+        numberUpdateItems_(0),
+        maximumNumberUpdateItems_(0),
+        updateItems_(NULL),
+        storedRowCuts_(NULL),
+        numberThreads_(0),
+        threadMode_(0),
+        master_(NULL),
+        masterThread_(NULL)
+{
+    memset(intParam_, 0, sizeof(intParam_));
+    intParam_[CbcMaxNumNode] = 2147483647;
+    intParam_[CbcMaxNumSol] = 9999999;
+
+    memset(dblParam_, 0, sizeof(dblParam_));
+    dblParam_[CbcIntegerTolerance] = 1e-6;
+    dblParam_[CbcCutoffIncrement] = 1e-5;
+    dblParam_[CbcAllowableGap] = 1.0e-10;
+    dblParam_[CbcMaximumSeconds] = 1.0e100;
+    dblParam_[CbcCurrentCutoff] = 1.0e100;
+    dblParam_[CbcOptimizationDirection] = 1.0;
+    dblParam_[CbcCurrentObjectiveValue] = 1.0e100;
+    dblParam_[CbcCurrentMinimizationObjectiveValue] = 1.0e100;
+    strongInfo_[0] = 0;
+    strongInfo_[1] = 0;
+    strongInfo_[2] = 0;
+    strongInfo_[3] = 0;
+    strongInfo_[4] = 0;
+    strongInfo_[5] = 0;
+    strongInfo_[6] = 0;
+    solverCharacteristics_ = NULL;
+    nodeCompare_ = new CbcCompareDefault();;
+    problemFeasibility_ = new CbcFeasibilityBase();
+    tree_ = new CbcTree();
+    branchingMethod_ = NULL;
+    cutModifier_ = NULL;
+    strategy_ = NULL;
+    parentModel_ = NULL;
+    cbcColLower_ = NULL;
+    cbcColUpper_ = NULL;
+    cbcRowLower_ = NULL;
+    cbcRowUpper_ = NULL;
+    cbcColSolution_ = NULL;
+    cbcRowPrice_ = NULL;
+    cbcReducedCost_ = NULL;
+    cbcRowActivity_ = NULL;
+    appData_ = NULL;
+    handler_ = new CoinMessageHandler();
+    handler_->setLogLevel(2);
+    messages_ = CbcMessage();
+    //eventHandler_ = new CbcEventHandler() ;
+}
+
+/** Constructor from solver.
+
+  Creates a model complete with a clone of the solver passed as a parameter.
+*/
+
+CbcModel::CbcModel(const OsiSolverInterface &rhs)
+        :
+        continuousSolver_(NULL),
+        referenceSolver_(NULL),
+        defaultHandler_(true),
+        emptyWarmStart_(NULL),
+        bestObjective_(COIN_DBL_MAX),
+        bestPossibleObjective_(COIN_DBL_MAX),
+        sumChangeObjective1_(0.0),
+        sumChangeObjective2_(0.0),
+	globalConflictCuts_(NULL),
+        minimumDrop_(1.0e-4),
+        numberSolutions_(0),
+        numberSavedSolutions_(0),
+        maximumSavedSolutions_(0),
+        stateOfSearch_(0),
+        whenCuts_(-1),
+        hotstartSolution_(NULL),
+        hotstartPriorities_(NULL),
+        numberHeuristicSolutions_(0),
+        numberNodes_(0),
+        numberNodes2_(0),
+        numberIterations_(0),
+        numberSolves_(0),
+        status_(-1),
+        secondaryStatus_(-1),
+        numberRowsAtContinuous_(0),
+	cutoffRowNumber_(-1),
+        maximumNumberCuts_(0),
+        phase_(0),
+        currentNumberCuts_(0),
+        maximumDepth_(0),
+        walkback_(NULL),
+        lastNodeInfo_(NULL),
+        lastCut_(NULL),
+        lastDepth_(0),
+        lastNumberCuts2_(0),
+        maximumCuts_(0),
+        lastNumberCuts_(NULL),
+        addedCuts_(NULL),
+        nextRowCut_(NULL),
+        currentNode_(NULL),
+        integerInfo_(NULL),
+        specialOptions_(0),
+        moreSpecialOptions_(0),
+	topOfTree_(NULL),
+        subTreeModel_(NULL),
+	heuristicModel_(NULL),
+        numberStoppedSubTrees_(0),
+        presolve_(0),
+        numberStrong_(5),
+        numberBeforeTrust_(10),
+        numberPenalties_(20),
+        stopNumberIterations_(-1),
+        penaltyScaleFactor_(3.0),
+        numberAnalyzeIterations_(0),
+        analyzeResults_(NULL),
+        numberInfeasibleNodes_(0),
+        problemType_(0),
+        printFrequency_(0),
+        numberCutGenerators_(0),
+        generator_(NULL),
+        virginGenerator_(NULL),
+        numberHeuristics_(0),
+        heuristic_(NULL),
+        lastHeuristic_(NULL),
+        fastNodeDepth_(-1),
+        eventHandler_(NULL),
+        numberObjects_(0),
+        object_(NULL),
+        ownObjects_(true),
+        originalColumns_(NULL),
+        howOftenGlobalScan_(3),
+        numberGlobalViolations_(0),
+        numberExtraIterations_(0),
+        numberExtraNodes_(0),
+        continuousObjective_(COIN_DBL_MAX),
+        originalContinuousObjective_(COIN_DBL_MAX),
+        continuousInfeasibilities_(COIN_INT_MAX),
+        maximumCutPassesAtRoot_(20),
+        maximumCutPasses_(10),
+        preferredWay_(0),
+        currentPassNumber_(0),
+        maximumWhich_(1000),
+        maximumRows_(0),
+	randomSeed_(-1),
+	multipleRootTries_(0),
+        currentDepth_(0),
+        whichGenerator_(NULL),
+        maximumStatistics_(0),
+        statistics_(NULL),
+        maximumDepthActual_(0),
+        numberDJFixed_(0.0),
+        probingInfo_(NULL),
+        numberFixedAtRoot_(0),
+        numberFixedNow_(0),
+        stoppedOnGap_(false),
+        eventHappened_(false),
+        numberLongStrong_(0),
+        numberOldActiveCuts_(0),
+        numberNewCuts_(0),
+        searchStrategy_(-1),
+	strongStrategy_(0),
+        numberStrongIterations_(0),
+        resolveAfterTakeOffCuts_(true),
+        maximumNumberIterations_(-1),
+        continuousPriority_(COIN_INT_MAX),
+        numberUpdateItems_(0),
+        maximumNumberUpdateItems_(0),
+        updateItems_(NULL),
+        storedRowCuts_(NULL),
+        numberThreads_(0),
+        threadMode_(0),
+        master_(NULL),
+        masterThread_(NULL)
+{
+    memset(intParam_, 0, sizeof(intParam_));
+    intParam_[CbcMaxNumNode] = 2147483647;
+    intParam_[CbcMaxNumSol] = 9999999;
+
+    memset(dblParam_, 0, sizeof(dblParam_));
+    dblParam_[CbcIntegerTolerance] = 1e-6;
+    dblParam_[CbcCutoffIncrement] = 1e-5;
+    dblParam_[CbcAllowableGap] = 1.0e-10;
+    dblParam_[CbcMaximumSeconds] = 1.0e100;
+    dblParam_[CbcCurrentCutoff] = 1.0e100;
+    dblParam_[CbcOptimizationDirection] = 1.0;
+    dblParam_[CbcCurrentObjectiveValue] = 1.0e100;
+    dblParam_[CbcCurrentMinimizationObjectiveValue] = 1.0e100;
+    strongInfo_[0] = 0;
+    strongInfo_[1] = 0;
+    strongInfo_[2] = 0;
+    strongInfo_[3] = 0;
+    strongInfo_[4] = 0;
+    strongInfo_[5] = 0;
+    strongInfo_[6] = 0;
+    solverCharacteristics_ = NULL;
+    nodeCompare_ = new CbcCompareDefault();;
+    problemFeasibility_ = new CbcFeasibilityBase();
+    tree_ = new CbcTree();
+    branchingMethod_ = NULL;
+    cutModifier_ = NULL;
+    strategy_ = NULL;
+    parentModel_ = NULL;
+    appData_ = NULL;
+    solver_ = rhs.clone();
+    handler_ = new CoinMessageHandler();
+    if (!solver_->defaultHandler()&&
+	solver_->messageHandler()->logLevel(0)!=-1000)
+      passInMessageHandler(solver_->messageHandler());
+    handler_->setLogLevel(2);
+    messages_ = CbcMessage();
+    //eventHandler_ = new CbcEventHandler() ;
+    referenceSolver_ = solver_->clone();
+    ownership_ = 0x80000000;
+    cbcColLower_ = NULL;
+    cbcColUpper_ = NULL;
+    cbcRowLower_ = NULL;
+    cbcRowUpper_ = NULL;
+    cbcColSolution_ = NULL;
+    cbcRowPrice_ = NULL;
+    cbcReducedCost_ = NULL;
+    cbcRowActivity_ = NULL;
+
+    // Initialize solution and integer variable vectors
+    bestSolution_ = NULL; // to say no solution found
+    savedSolutions_ = NULL;
+    numberIntegers_ = 0;
+    int numberColumns = solver_->getNumCols();
+    int iColumn;
+    if (numberColumns) {
+        // Space for current solution
+        currentSolution_ = new double[numberColumns];
+        continuousSolution_ = new double[numberColumns];
+        usedInSolution_ = new int[numberColumns];
+        CoinZeroN(usedInSolution_, numberColumns);
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if ( solver_->isInteger(iColumn))
+                numberIntegers_++;
+        }
+    } else {
+        // empty model
+        currentSolution_ = NULL;
+        continuousSolution_ = NULL;
+        usedInSolution_ = NULL;
+    }
+    testSolution_ = currentSolution_;
+    if (numberIntegers_) {
+        integerVariable_ = new int [numberIntegers_];
+        numberIntegers_ = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if ( solver_->isInteger(iColumn))
+                integerVariable_[numberIntegers_++] = iColumn;
+        }
+    } else {
+        integerVariable_ = NULL;
+    }
+}
+
+static int * resizeInt(int * array,int oldLength, int newLength)
+{
+  if (!array)
+    return NULL;
+  assert (newLength>oldLength);
+  int * newArray = new int [newLength];
+  memcpy(newArray,array,oldLength*sizeof(int));
+  delete [] array;
+  memset(newArray+oldLength,0,(newLength-oldLength)*sizeof(int));
+  return newArray;
+}
+static double * resizeDouble(double * array,int oldLength, int newLength)
+{
+  if (!array)
+    return NULL;
+  assert (newLength>oldLength);
+  double * newArray = new double [newLength];
+  memcpy(newArray,array,oldLength*sizeof(double));
+  delete [] array;
+  memset(newArray+oldLength,0,(newLength-oldLength)*sizeof(double));
+  return newArray;
+}
+/*
+  Assign a solver to the model (model assumes ownership)
+
+  The integer variable vector is initialized if it's not already present.
+  If deleteSolver then current solver deleted (if model owned)
+
+  Assuming ownership matches usage in OsiSolverInterface
+  (cf. assignProblem, loadProblem).
+
+  TODO: What to do about solver parameters? A simple copy likely won't do it,
+	because the SI must push the settings into the underlying solver. In
+	the context of switching solvers in cbc, this means that command line
+	settings will get lost. Stash the command line somewhere and reread it
+	here, maybe?
+
+  TODO: More generally, how much state should be transferred from the old
+	solver to the new solver? Best perhaps to see how usage develops.
+	What's done here mimics the CbcModel(OsiSolverInterface) constructor.
+*/
+void
+CbcModel::assignSolver(OsiSolverInterface *&solver, bool deleteSolver)
+
+{
+    // resize stuff if exists
+    if (solver && solver_) {
+        int nOld = solver_->getNumCols();
+        int nNew = solver->getNumCols();
+        if (nNew > nOld) {
+	  originalColumns_ = resizeInt(originalColumns_,nOld,nNew);
+	  usedInSolution_ = resizeInt(usedInSolution_,nOld,nNew);
+	  continuousSolution_ = resizeDouble(continuousSolution_,nOld,nNew);
+	  hotstartSolution_ = resizeDouble(hotstartSolution_,nOld,nNew);
+	  bestSolution_ = resizeDouble(bestSolution_,nOld,nNew);
+	  currentSolution_ = resizeDouble(currentSolution_,nOld,nNew);
+	  if (savedSolutions_) {
+	    for (int i = 0; i < maximumSavedSolutions_; i++)
+	      savedSolutions_[i] = resizeDouble(savedSolutions_[i],nOld,nNew);
+	  }
+        }
+    }
+    // Keep the current message level for solver (if solver exists)
+    if (solver_)
+        solver->messageHandler()->setLogLevel(solver_->messageHandler()->logLevel()) ;
+
+    if (modelOwnsSolver() && deleteSolver) {
+        solverCharacteristics_ = NULL;
+        delete solver_ ;
+    }
+    solver_ = solver;
+    solver = NULL ;
+    setModelOwnsSolver(true) ;
+    /*
+      Basis information is solver-specific.
+    */
+    if (emptyWarmStart_) {
+        delete emptyWarmStart_  ;
+        emptyWarmStart_ = 0 ;
+    }
+    bestSolutionBasis_ = CoinWarmStartBasis();
+    /*
+      Initialize integer variable vector.
+    */
+    numberIntegers_ = 0;
+    int numberColumns = solver_->getNumCols();
+    int iColumn;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        if ( solver_->isInteger(iColumn))
+            numberIntegers_++;
+    }
+    delete [] integerVariable_;
+    if (numberIntegers_) {
+        integerVariable_ = new int [numberIntegers_];
+        numberIntegers_ = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if ( solver_->isInteger(iColumn))
+                integerVariable_[numberIntegers_++] = iColumn;
+        }
+    } else {
+        integerVariable_ = NULL;
+    }
+
+    return ;
+}
+
+// Cloning method
+
+CbcModel *CbcModel::clone (bool cloneHandler) {
+  return new CbcModel (*this, cloneHandler);
+}
+
+
+// Copy constructor.
+
+CbcModel::CbcModel(const CbcModel & rhs, bool cloneHandler)
+        :
+        continuousSolver_(NULL),
+        referenceSolver_(NULL),
+        defaultHandler_(rhs.defaultHandler_),
+        emptyWarmStart_(NULL),
+        bestObjective_(rhs.bestObjective_),
+        bestPossibleObjective_(rhs.bestPossibleObjective_),
+        sumChangeObjective1_(rhs.sumChangeObjective1_),
+        sumChangeObjective2_(rhs.sumChangeObjective2_),
+	globalConflictCuts_(NULL),
+        minimumDrop_(rhs.minimumDrop_),
+        numberSolutions_(rhs.numberSolutions_),
+        numberSavedSolutions_(rhs.numberSavedSolutions_),
+        maximumSavedSolutions_(rhs.maximumSavedSolutions_),
+        stateOfSearch_(rhs.stateOfSearch_),
+        whenCuts_(rhs.whenCuts_),
+        numberHeuristicSolutions_(rhs.numberHeuristicSolutions_),
+        numberNodes_(rhs.numberNodes_),
+        numberNodes2_(rhs.numberNodes2_),
+        numberIterations_(rhs.numberIterations_),
+        numberSolves_(rhs.numberSolves_),
+        status_(rhs.status_),
+        secondaryStatus_(rhs.secondaryStatus_),
+        specialOptions_(rhs.specialOptions_),
+        moreSpecialOptions_(rhs.moreSpecialOptions_),
+	topOfTree_(NULL),
+        subTreeModel_(rhs.subTreeModel_),
+	heuristicModel_(NULL),
+        numberStoppedSubTrees_(rhs.numberStoppedSubTrees_),
+        presolve_(rhs.presolve_),
+        numberStrong_(rhs.numberStrong_),
+        numberBeforeTrust_(rhs.numberBeforeTrust_),
+        numberPenalties_(rhs.numberPenalties_),
+        stopNumberIterations_(rhs.stopNumberIterations_),
+        penaltyScaleFactor_(rhs.penaltyScaleFactor_),
+        numberAnalyzeIterations_(rhs.numberAnalyzeIterations_),
+        analyzeResults_(NULL),
+        numberInfeasibleNodes_(rhs.numberInfeasibleNodes_),
+        problemType_(rhs.problemType_),
+        printFrequency_(rhs.printFrequency_),
+        fastNodeDepth_(rhs.fastNodeDepth_),
+        howOftenGlobalScan_(rhs.howOftenGlobalScan_),
+        numberGlobalViolations_(rhs.numberGlobalViolations_),
+        numberExtraIterations_(rhs.numberExtraIterations_),
+        numberExtraNodes_(rhs.numberExtraNodes_),
+        continuousObjective_(rhs.continuousObjective_),
+        originalContinuousObjective_(rhs.originalContinuousObjective_),
+        continuousInfeasibilities_(rhs.continuousInfeasibilities_),
+        maximumCutPassesAtRoot_(rhs.maximumCutPassesAtRoot_),
+        maximumCutPasses_( rhs.maximumCutPasses_),
+        preferredWay_(rhs.preferredWay_),
+        currentPassNumber_(rhs.currentPassNumber_),
+        maximumWhich_(rhs.maximumWhich_),
+        maximumRows_(0),
+	randomSeed_(rhs.randomSeed_),
+	multipleRootTries_(rhs.multipleRootTries_),
+        currentDepth_(0),
+        whichGenerator_(NULL),
+        maximumStatistics_(0),
+        statistics_(NULL),
+        maximumDepthActual_(0),
+        numberDJFixed_(0.0),
+        probingInfo_(NULL),
+        numberFixedAtRoot_(rhs.numberFixedAtRoot_),
+        numberFixedNow_(rhs.numberFixedNow_),
+        stoppedOnGap_(rhs.stoppedOnGap_),
+        eventHappened_(rhs.eventHappened_),
+        numberLongStrong_(rhs.numberLongStrong_),
+        numberOldActiveCuts_(rhs.numberOldActiveCuts_),
+        numberNewCuts_(rhs.numberNewCuts_),
+        searchStrategy_(rhs.searchStrategy_),
+	strongStrategy_(rhs.strongStrategy_),
+        numberStrongIterations_(rhs.numberStrongIterations_),
+        resolveAfterTakeOffCuts_(rhs.resolveAfterTakeOffCuts_),
+        maximumNumberIterations_(rhs.maximumNumberIterations_),
+        continuousPriority_(rhs.continuousPriority_),
+        numberUpdateItems_(rhs.numberUpdateItems_),
+        maximumNumberUpdateItems_(rhs.maximumNumberUpdateItems_),
+        updateItems_(NULL),
+        storedRowCuts_(NULL),
+        numberThreads_(rhs.numberThreads_),
+        threadMode_(rhs.threadMode_),
+        master_(NULL),
+        masterThread_(NULL)
+{
+    memcpy(intParam_, rhs.intParam_, sizeof(intParam_));
+    memcpy(dblParam_, rhs.dblParam_, sizeof(dblParam_));
+    strongInfo_[0] = rhs.strongInfo_[0];
+    strongInfo_[1] = rhs.strongInfo_[1];
+    strongInfo_[2] = rhs.strongInfo_[2];
+    strongInfo_[3] = rhs.strongInfo_[3];
+    strongInfo_[4] = rhs.strongInfo_[4];
+    strongInfo_[5] = rhs.strongInfo_[5];
+    strongInfo_[6] = rhs.strongInfo_[6];
+    solverCharacteristics_ = NULL;
+    if (rhs.emptyWarmStart_) emptyWarmStart_ = rhs.emptyWarmStart_->clone() ;
+    if (defaultHandler_ || cloneHandler) {
+        handler_ = new CoinMessageHandler();
+        handler_->setLogLevel(2);
+    } else {
+        handler_ = rhs.handler_;
+    }
+    messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
+    numberCutGenerators_ = rhs.numberCutGenerators_;
+    if (numberCutGenerators_) {
+        generator_ = new CbcCutGenerator * [numberCutGenerators_];
+        virginGenerator_ = new CbcCutGenerator * [numberCutGenerators_];
+        int i;
+        for (i = 0; i < numberCutGenerators_; i++) {
+            generator_[i] = new CbcCutGenerator(*rhs.generator_[i]);
+            virginGenerator_[i] = new CbcCutGenerator(*rhs.virginGenerator_[i]);
+        }
+    } else {
+        generator_ = NULL;
+        virginGenerator_ = NULL;
+    }
+    globalCuts_ = rhs.globalCuts_;
+    numberHeuristics_ = rhs.numberHeuristics_;
+    if (numberHeuristics_) {
+        heuristic_ = new CbcHeuristic * [numberHeuristics_];
+        int i;
+        for (i = 0; i < numberHeuristics_; i++) {
+            heuristic_[i] = rhs.heuristic_[i]->clone();
+        }
+    } else {
+        heuristic_ = NULL;
+    }
+    lastHeuristic_ = NULL;
+    if (rhs.eventHandler_) {
+        eventHandler_ = rhs.eventHandler_->clone() ;
+    } else {
+        eventHandler_ = NULL ;
+    }
+    ownObjects_ = rhs.ownObjects_;
+    if (ownObjects_) {
+        numberObjects_ = rhs.numberObjects_;
+        if (numberObjects_) {
+            object_ = new OsiObject * [numberObjects_];
+            int i;
+            for (i = 0; i < numberObjects_; i++) {
+                object_[i] = (rhs.object_[i])->clone();
+                CbcObject * obj = dynamic_cast <CbcObject *>(object_[i]) ;
+                // Could be OsiObjects
+                if (obj)
+                    obj->setModel(this);
+            }
+        } else {
+            object_ = NULL;
+        }
+    } else {
+        // assume will be redone
+        numberObjects_ = 0;
+        object_ = NULL;
+    }
+    if (rhs.referenceSolver_)
+        referenceSolver_ = rhs.referenceSolver_->clone();
+    else
+        referenceSolver_ = NULL;
+    solver_ = rhs.solver_->clone();
+    if (rhs.originalColumns_) {
+        int numberColumns = solver_->getNumCols();
+        originalColumns_ = new int [numberColumns];
+        memcpy(originalColumns_, rhs.originalColumns_, numberColumns*sizeof(int));
+    } else {
+        originalColumns_ = NULL;
+    }
+    if (maximumNumberUpdateItems_) {
+        updateItems_ = new CbcObjectUpdateData [maximumNumberUpdateItems_];
+        for (int i = 0; i < maximumNumberUpdateItems_; i++)
+            updateItems_[i] = rhs.updateItems_[i];
+    }
+    if (maximumWhich_ && rhs.whichGenerator_)
+        whichGenerator_ = CoinCopyOfArray(rhs.whichGenerator_, maximumWhich_);
+    nodeCompare_ = rhs.nodeCompare_->clone();
+    problemFeasibility_ = rhs.problemFeasibility_->clone();
+    tree_ = rhs.tree_->clone();
+    if (rhs.branchingMethod_)
+        branchingMethod_ = rhs.branchingMethod_->clone();
+    else
+        branchingMethod_ = NULL;
+    if (rhs.cutModifier_)
+        cutModifier_ = rhs.cutModifier_->clone();
+    else
+        cutModifier_ = NULL;
+    cbcColLower_ = NULL;
+    cbcColUpper_ = NULL;
+    cbcRowLower_ = NULL;
+    cbcRowUpper_ = NULL;
+    cbcColSolution_ = NULL;
+    cbcRowPrice_ = NULL;
+    cbcReducedCost_ = NULL;
+    cbcRowActivity_ = NULL;
+    if (rhs.strategy_)
+        strategy_ = rhs.strategy_->clone();
+    else
+        strategy_ = NULL;
+    parentModel_ = rhs.parentModel_;
+    appData_ = rhs.appData_;
+    messages_ = rhs.messages_;
+    ownership_ = rhs.ownership_ | 0x80000000;
+    messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
+    numberIntegers_ = rhs.numberIntegers_;
+    randomNumberGenerator_ = rhs.randomNumberGenerator_;
+    if (numberIntegers_) {
+        integerVariable_ = new int [numberIntegers_];
+        memcpy(integerVariable_, rhs.integerVariable_, numberIntegers_*sizeof(int));
+        integerInfo_ = CoinCopyOfArray(rhs.integerInfo_, solver_->getNumCols());
+    } else {
+        integerVariable_ = NULL;
+        integerInfo_ = NULL;
+    }
+    if (rhs.hotstartSolution_) {
+        int numberColumns = solver_->getNumCols();
+        hotstartSolution_ = CoinCopyOfArray(rhs.hotstartSolution_, numberColumns);
+        hotstartPriorities_ = CoinCopyOfArray(rhs.hotstartPriorities_, numberColumns);
+    } else {
+        hotstartSolution_ = NULL;
+        hotstartPriorities_ = NULL;
+    }
+    if (rhs.bestSolution_) {
+        int numberColumns = solver_->getNumCols();
+        bestSolution_ = new double[numberColumns];
+        memcpy(bestSolution_, rhs.bestSolution_, numberColumns*sizeof(double));
+    } else {
+        bestSolution_ = NULL;
+    }
+    int numberColumns = solver_->getNumCols();
+    if (maximumSavedSolutions_ && rhs.savedSolutions_) {
+        savedSolutions_ = new double * [maximumSavedSolutions_];
+        for (int i = 0; i < maximumSavedSolutions_; i++)
+            savedSolutions_[i] = CoinCopyOfArray(rhs.savedSolutions_[i], numberColumns + 2);
+    } else {
+        savedSolutions_ = NULL;
+    }
+    // Space for current solution
+    currentSolution_ = new double[numberColumns];
+    continuousSolution_ = new double[numberColumns];
+    usedInSolution_ = new int[numberColumns];
+    CoinZeroN(usedInSolution_, numberColumns);
+    testSolution_ = currentSolution_;
+    numberRowsAtContinuous_ = rhs.numberRowsAtContinuous_;
+    cutoffRowNumber_ = rhs.cutoffRowNumber_;
+    maximumNumberCuts_ = rhs.maximumNumberCuts_;
+    phase_ = rhs.phase_;
+    currentNumberCuts_ = rhs.currentNumberCuts_;
+    maximumDepth_ = rhs.maximumDepth_;
+    // These are only used as temporary arrays so need not be filled
+    if (maximumNumberCuts_) {
+        addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
+    } else {
+        addedCuts_ = NULL;
+    }
+    bestSolutionBasis_ = rhs.bestSolutionBasis_;
+    nextRowCut_ = NULL;
+    currentNode_ = NULL;
+    if (maximumDepth_) {
+        walkback_ = new CbcNodeInfo * [maximumDepth_];
+        lastNodeInfo_ = new CbcNodeInfo * [maximumDepth_] ;
+        lastNumberCuts_ = new int [maximumDepth_] ;
+    } else {
+        walkback_ = NULL;
+        lastNodeInfo_ = NULL;
+        lastNumberCuts_ = NULL;
+    }
+    maximumCuts_ = rhs.maximumCuts_;
+    if (maximumCuts_) {
+        lastCut_ = new const OsiRowCut * [maximumCuts_] ;
+    } else {
+        lastCut_ = NULL;
+    }
+    synchronizeModel();
+    if (cloneHandler && !defaultHandler_) {
+        delete handler_;
+        CoinMessageHandler * handler = rhs.handler_->clone();
+        passInMessageHandler(handler);
+    }
+}
+
+// Assignment operator
+CbcModel &
+CbcModel::operator=(const CbcModel & rhs)
+{
+    if (this != &rhs) {
+        if (modelOwnsSolver()) {
+            solverCharacteristics_ = NULL;
+            delete solver_;
+            solver_ = NULL;
+        }
+        gutsOfDestructor();
+        if (defaultHandler_) {
+            delete handler_;
+            handler_ = NULL;
+        }
+        defaultHandler_ = rhs.defaultHandler_;
+        if (defaultHandler_) {
+            handler_ = new CoinMessageHandler();
+            handler_->setLogLevel(2);
+        } else {
+            handler_ = rhs.handler_;
+        }
+        messages_ = rhs.messages_;
+        messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
+        if (rhs.solver_) {
+            solver_ = rhs.solver_->clone() ;
+        } else {
+            solver_ = 0 ;
+        }
+        ownership_ = 0x80000000;
+        delete continuousSolver_ ;
+        if (rhs.continuousSolver_) {
+            continuousSolver_ = rhs.continuousSolver_->clone() ;
+        } else {
+            continuousSolver_ = 0 ;
+        }
+        delete referenceSolver_;
+        if (rhs.referenceSolver_) {
+            referenceSolver_ = rhs.referenceSolver_->clone() ;
+        } else {
+            referenceSolver_ = NULL ;
+        }
+
+        delete emptyWarmStart_ ;
+        if (rhs.emptyWarmStart_) {
+            emptyWarmStart_ = rhs.emptyWarmStart_->clone() ;
+        } else {
+            emptyWarmStart_ = 0 ;
+        }
+
+        bestObjective_ = rhs.bestObjective_;
+        bestPossibleObjective_ = rhs.bestPossibleObjective_;
+        sumChangeObjective1_ = rhs.sumChangeObjective1_;
+        sumChangeObjective2_ = rhs.sumChangeObjective2_;
+        delete [] bestSolution_;
+        if (rhs.bestSolution_) {
+            int numberColumns = rhs.getNumCols();
+            bestSolution_ = new double[numberColumns];
+            memcpy(bestSolution_, rhs.bestSolution_, numberColumns*sizeof(double));
+        } else {
+            bestSolution_ = NULL;
+        }
+        for (int i = 0; i < maximumSavedSolutions_; i++)
+            delete [] savedSolutions_[i];
+        delete [] savedSolutions_;
+        savedSolutions_ = NULL;
+        int numberColumns = rhs.getNumCols();
+        if (numberColumns) {
+            // Space for current solution
+            currentSolution_ = new double[numberColumns];
+            continuousSolution_ = new double[numberColumns];
+            usedInSolution_ = new int[numberColumns];
+            CoinZeroN(usedInSolution_, numberColumns);
+        } else {
+            currentSolution_ = NULL;
+            continuousSolution_ = NULL;
+            usedInSolution_ = NULL;
+        }
+        if (maximumSavedSolutions_) {
+            savedSolutions_ = new double * [maximumSavedSolutions_];
+            for (int i = 0; i < maximumSavedSolutions_; i++)
+                savedSolutions_[i] = CoinCopyOfArray(rhs.savedSolutions_[i], numberColumns + 2);
+        } else {
+            savedSolutions_ = NULL;
+        }
+        testSolution_ = currentSolution_;
+        minimumDrop_ = rhs.minimumDrop_;
+        numberSolutions_ = rhs.numberSolutions_;
+        numberSavedSolutions_ = rhs.numberSavedSolutions_;
+        maximumSavedSolutions_ = rhs.maximumSavedSolutions_;
+        stateOfSearch_ = rhs.stateOfSearch_;
+        whenCuts_ = rhs.whenCuts_;
+        numberHeuristicSolutions_ = rhs.numberHeuristicSolutions_;
+        numberNodes_ = rhs.numberNodes_;
+        numberNodes2_ = rhs.numberNodes2_;
+        numberIterations_ = rhs.numberIterations_;
+        numberSolves_ = rhs.numberSolves_;
+        status_ = rhs.status_;
+        secondaryStatus_ = rhs.secondaryStatus_;
+        specialOptions_ = rhs.specialOptions_;
+        moreSpecialOptions_ = rhs.moreSpecialOptions_;
+        subTreeModel_ = rhs.subTreeModel_;
+	heuristicModel_ = NULL;
+        numberStoppedSubTrees_ = rhs.numberStoppedSubTrees_;
+        presolve_ = rhs.presolve_;
+        numberStrong_ = rhs.numberStrong_;
+        numberBeforeTrust_ = rhs.numberBeforeTrust_;
+        numberPenalties_ = rhs.numberPenalties_;
+        stopNumberIterations_ = rhs.stopNumberIterations_;
+        penaltyScaleFactor_ = rhs.penaltyScaleFactor_;
+        numberAnalyzeIterations_ = rhs.numberAnalyzeIterations_;
+        delete [] analyzeResults_;
+        analyzeResults_ = NULL;
+        numberInfeasibleNodes_ = rhs.numberInfeasibleNodes_;
+        problemType_ = rhs.problemType_;
+        printFrequency_ = rhs.printFrequency_;
+        howOftenGlobalScan_ = rhs.howOftenGlobalScan_;
+        numberGlobalViolations_ = rhs.numberGlobalViolations_;
+        numberExtraIterations_ = rhs.numberExtraIterations_;
+        numberExtraNodes_ = rhs.numberExtraNodes_;
+        continuousObjective_ = rhs.continuousObjective_;
+        originalContinuousObjective_ = rhs.originalContinuousObjective_;
+        continuousInfeasibilities_ = rhs.continuousInfeasibilities_;
+        maximumCutPassesAtRoot_ = rhs.maximumCutPassesAtRoot_;
+        maximumCutPasses_ = rhs.maximumCutPasses_;
+	randomSeed_ = rhs.randomSeed_;
+	multipleRootTries_ = rhs.multipleRootTries_;
+        preferredWay_ = rhs.preferredWay_;
+        currentPassNumber_ = rhs.currentPassNumber_;
+        memcpy(intParam_, rhs.intParam_, sizeof(intParam_));
+        memcpy(dblParam_, rhs.dblParam_, sizeof(dblParam_));
+        globalCuts_ = rhs.globalCuts_;
+	delete globalConflictCuts_;
+	globalConflictCuts_=NULL;
+        int i;
+        for (i = 0; i < numberCutGenerators_; i++) {
+            delete generator_[i];
+            delete virginGenerator_[i];
+        }
+        delete [] generator_;
+        delete [] virginGenerator_;
+        delete [] heuristic_;
+        maximumWhich_ = rhs.maximumWhich_;
+        delete [] whichGenerator_;
+        whichGenerator_ = NULL;
+        if (maximumWhich_ && rhs.whichGenerator_)
+            whichGenerator_ = CoinCopyOfArray(rhs.whichGenerator_, maximumWhich_);
+        maximumRows_ = 0;
+        currentDepth_ = 0;
+        randomNumberGenerator_ = rhs.randomNumberGenerator_;
+        workingBasis_ = CoinWarmStartBasis();
+        for (i = 0; i < maximumStatistics_; i++)
+            delete statistics_[i];
+        delete [] statistics_;
+        maximumStatistics_ = 0;
+        statistics_ = NULL;
+        delete probingInfo_;
+        probingInfo_ = NULL;
+        numberFixedAtRoot_ = rhs.numberFixedAtRoot_;
+        numberFixedNow_ = rhs.numberFixedNow_;
+        stoppedOnGap_ = rhs.stoppedOnGap_;
+        eventHappened_ = rhs.eventHappened_;
+        numberLongStrong_ = rhs.numberLongStrong_;
+        numberOldActiveCuts_ = rhs.numberOldActiveCuts_;
+        numberNewCuts_ = rhs.numberNewCuts_;
+        resolveAfterTakeOffCuts_ = rhs.resolveAfterTakeOffCuts_;
+        maximumNumberIterations_ = rhs.maximumNumberIterations_;
+        continuousPriority_ = rhs.continuousPriority_;
+        numberUpdateItems_ = rhs.numberUpdateItems_;
+        maximumNumberUpdateItems_ = rhs.maximumNumberUpdateItems_;
+        delete [] updateItems_;
+        if (maximumNumberUpdateItems_) {
+            updateItems_ = new CbcObjectUpdateData [maximumNumberUpdateItems_];
+            for (i = 0; i < maximumNumberUpdateItems_; i++)
+                updateItems_[i] = rhs.updateItems_[i];
+        } else {
+            updateItems_ = NULL;
+        }
+        numberThreads_ = rhs.numberThreads_;
+        threadMode_ = rhs.threadMode_;
+        delete master_;
+        master_ = NULL;
+        masterThread_ = NULL;
+        searchStrategy_ = rhs.searchStrategy_;
+	strongStrategy_ = rhs.strongStrategy_;
+        numberStrongIterations_ = rhs.numberStrongIterations_;
+        strongInfo_[0] = rhs.strongInfo_[0];
+        strongInfo_[1] = rhs.strongInfo_[1];
+        strongInfo_[2] = rhs.strongInfo_[2];
+        strongInfo_[3] = rhs.strongInfo_[3];
+        strongInfo_[4] = rhs.strongInfo_[4];
+        strongInfo_[5] = rhs.strongInfo_[5];
+        strongInfo_[6] = rhs.strongInfo_[6];
+        solverCharacteristics_ = NULL;
+        lastHeuristic_ = NULL;
+        numberCutGenerators_ = rhs.numberCutGenerators_;
+        if (numberCutGenerators_) {
+            generator_ = new CbcCutGenerator * [numberCutGenerators_];
+            virginGenerator_ = new CbcCutGenerator * [numberCutGenerators_];
+            int i;
+            for (i = 0; i < numberCutGenerators_; i++) {
+                generator_[i] = new CbcCutGenerator(*rhs.generator_[i]);
+                virginGenerator_[i] = new CbcCutGenerator(*rhs.virginGenerator_[i]);
+            }
+        } else {
+            generator_ = NULL;
+            virginGenerator_ = NULL;
+        }
+        numberHeuristics_ = rhs.numberHeuristics_;
+        if (numberHeuristics_) {
+            heuristic_ = new CbcHeuristic * [numberHeuristics_];
+            memcpy(heuristic_, rhs.heuristic_,
+                   numberHeuristics_*sizeof(CbcHeuristic *));
+        } else {
+            heuristic_ = NULL;
+        }
+        lastHeuristic_ = NULL;
+        if (eventHandler_)
+            delete eventHandler_ ;
+        if (rhs.eventHandler_) {
+            eventHandler_ = rhs.eventHandler_->clone() ;
+        } else {
+            eventHandler_ = NULL ;
+        }
+        fastNodeDepth_ = rhs.fastNodeDepth_;
+        if (ownObjects_) {
+            for (i = 0; i < numberObjects_; i++)
+                delete object_[i];
+            delete [] object_;
+            numberObjects_ = rhs.numberObjects_;
+            if (numberObjects_) {
+                object_ = new OsiObject * [numberObjects_];
+                int i;
+                for (i = 0; i < numberObjects_; i++)
+                    object_[i] = (rhs.object_[i])->clone();
+            } else {
+                object_ = NULL;
+            }
+        } else {
+            // assume will be redone
+            numberObjects_ = 0;
+            object_ = NULL;
+        }
+        delete [] originalColumns_;
+        if (rhs.originalColumns_) {
+            int numberColumns = rhs.getNumCols();
+            originalColumns_ = new int [numberColumns];
+            memcpy(originalColumns_, rhs.originalColumns_, numberColumns*sizeof(int));
+        } else {
+            originalColumns_ = NULL;
+        }
+        nodeCompare_ = rhs.nodeCompare_->clone();
+        problemFeasibility_ = rhs.problemFeasibility_->clone();
+        delete tree_;
+        tree_ = rhs.tree_->clone();
+        if (rhs.branchingMethod_)
+            branchingMethod_ = rhs.branchingMethod_->clone();
+        else
+            branchingMethod_ = NULL;
+        if (rhs.cutModifier_)
+            cutModifier_ = rhs.cutModifier_->clone();
+        else
+            cutModifier_ = NULL;
+        delete strategy_;
+        if (rhs.strategy_)
+            strategy_ = rhs.strategy_->clone();
+        else
+            strategy_ = NULL;
+        parentModel_ = rhs.parentModel_;
+        appData_ = rhs.appData_;
+
+        delete [] integerVariable_;
+        numberIntegers_ = rhs.numberIntegers_;
+        if (numberIntegers_) {
+            integerVariable_ = new int [numberIntegers_];
+            memcpy(integerVariable_, rhs.integerVariable_,
+                   numberIntegers_*sizeof(int));
+            integerInfo_ = CoinCopyOfArray(rhs.integerInfo_, rhs.getNumCols());
+        } else {
+            integerVariable_ = NULL;
+            integerInfo_ = NULL;
+        }
+        if (rhs.hotstartSolution_) {
+            int numberColumns = solver_->getNumCols();
+            hotstartSolution_ = CoinCopyOfArray(rhs.hotstartSolution_, numberColumns);
+            hotstartPriorities_ = CoinCopyOfArray(rhs.hotstartPriorities_, numberColumns);
+        } else {
+            hotstartSolution_ = NULL;
+            hotstartPriorities_ = NULL;
+        }
+        numberRowsAtContinuous_ = rhs.numberRowsAtContinuous_;
+	cutoffRowNumber_ = rhs.cutoffRowNumber_;
+        maximumNumberCuts_ = rhs.maximumNumberCuts_;
+        phase_ = rhs.phase_;
+        currentNumberCuts_ = rhs.currentNumberCuts_;
+        maximumDepth_ = rhs.maximumDepth_;
+        delete [] addedCuts_;
+        delete [] walkback_;
+        // These are only used as temporary arrays so need not be filled
+        if (maximumNumberCuts_) {
+            addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
+        } else {
+            addedCuts_ = NULL;
+        }
+        delete [] lastNodeInfo_ ;
+        delete [] lastNumberCuts_ ;
+        delete [] lastCut_;
+        bestSolutionBasis_ = rhs.bestSolutionBasis_;
+        nextRowCut_ = NULL;
+        currentNode_ = NULL;
+        if (maximumDepth_) {
+            walkback_ = new CbcNodeInfo * [maximumDepth_];
+            lastNodeInfo_ = new CbcNodeInfo * [maximumDepth_] ;
+            lastNumberCuts_ = new int [maximumDepth_] ;
+        } else {
+            walkback_ = NULL;
+            lastNodeInfo_ = NULL;
+            lastNumberCuts_ = NULL;
+        }
+        maximumCuts_ = rhs.maximumCuts_;
+        if (maximumCuts_) {
+            lastCut_ = new const OsiRowCut * [maximumCuts_] ;
+        } else {
+            lastCut_ = NULL;
+        }
+        synchronizeModel();
+        cbcColLower_ = NULL;
+        cbcColUpper_ = NULL;
+        cbcRowLower_ = NULL;
+        cbcRowUpper_ = NULL;
+        cbcColSolution_ = NULL;
+        cbcRowPrice_ = NULL;
+        cbcReducedCost_ = NULL;
+        cbcRowActivity_ = NULL;
+    }
+    return *this;
+}
+// Destructor
+CbcModel::~CbcModel ()
+{
+    if (defaultHandler_) {
+        delete handler_;
+        handler_ = NULL;
+    }
+    delete tree_;
+    tree_ = NULL;
+    if (modelOwnsSolver()) {
+        delete solver_;
+        solver_ = NULL;
+    }
+    gutsOfDestructor();
+    delete eventHandler_ ;
+    eventHandler_ = NULL ;
+#ifdef CBC_THREAD
+    // Get rid of all threaded stuff
+    delete master_;
+#endif
+}
+// Clears out as much as possible (except solver)
+void
+CbcModel::gutsOfDestructor()
+{
+    delete referenceSolver_;
+    referenceSolver_ = NULL;
+    int i;
+    for (i = 0; i < numberCutGenerators_; i++) {
+        delete generator_[i];
+        delete virginGenerator_[i];
+    }
+    delete [] generator_;
+    delete [] virginGenerator_;
+    generator_ = NULL;
+    virginGenerator_ = NULL;
+    for (i = 0; i < numberHeuristics_; i++)
+        delete heuristic_[i];
+    delete [] heuristic_;
+    heuristic_ = NULL;
+    delete nodeCompare_;
+    nodeCompare_ = NULL;
+    delete problemFeasibility_;
+    problemFeasibility_ = NULL;
+    delete [] originalColumns_;
+    originalColumns_ = NULL;
+    delete strategy_;
+    delete [] updateItems_;
+    updateItems_ = NULL;
+    numberUpdateItems_ = 0;
+    maximumNumberUpdateItems_ = 0;
+    gutsOfDestructor2();
+}
+// Clears out enough to reset CbcModel
+void
+CbcModel::gutsOfDestructor2()
+{
+    delete [] integerInfo_;
+    integerInfo_ = NULL;
+    delete [] integerVariable_;
+    integerVariable_ = NULL;
+    int i;
+    if (ownObjects_) {
+        for (i = 0; i < numberObjects_; i++)
+            delete object_[i];
+        delete [] object_;
+    }
+    ownObjects_ = true;
+    object_ = NULL;
+    numberIntegers_ = 0;
+    numberObjects_ = 0;
+    // Below here is whatever consensus is
+    ownership_ = 0x80000000;
+    delete branchingMethod_;
+    branchingMethod_ = NULL;
+    delete cutModifier_;
+    cutModifier_ = NULL;
+    topOfTree_ = NULL;
+    resetModel();
+}
+// Clears out enough to reset CbcModel
+void
+CbcModel::resetModel()
+{
+    delete emptyWarmStart_ ;
+    emptyWarmStart_ = NULL;
+    delete continuousSolver_;
+    continuousSolver_ = NULL;
+    numberSavedSolutions_ = 0;
+    delete [] bestSolution_;
+    bestSolution_ = NULL;
+    if (savedSolutions_) {
+        for (int i = 0; i < maximumSavedSolutions_; i++)
+            delete [] savedSolutions_[i];
+        delete [] savedSolutions_;
+        savedSolutions_ = NULL;
+    }
+    delete [] currentSolution_;
+    currentSolution_ = NULL;
+    delete [] continuousSolution_;
+    continuousSolution_ = NULL;
+    solverCharacteristics_ = NULL;
+    delete [] usedInSolution_;
+    usedInSolution_ = NULL;
+    testSolution_ = NULL;
+    lastHeuristic_ = NULL;
+    delete [] addedCuts_;
+    addedCuts_ = NULL;
+    nextRowCut_ = NULL;
+    currentNode_ = NULL;
+    delete [] walkback_;
+    walkback_ = NULL;
+    delete [] lastNodeInfo_ ;
+    lastNodeInfo_ = NULL;
+    delete [] lastNumberCuts_ ;
+    lastNumberCuts_ = NULL;
+    delete [] lastCut_;
+    lastCut_ = NULL;
+    delete [] whichGenerator_;
+    whichGenerator_ = NULL;
+    for (int i = 0; i < maximumStatistics_; i++)
+        delete statistics_[i];
+    delete [] statistics_;
+    statistics_ = NULL;
+    maximumDepthActual_ = 0;
+    numberDJFixed_ = 0.0;
+    if (probingInfo_) {
+      delete probingInfo_;
+      probingInfo_ = NULL;
+      if (!generator_)
+	numberCutGenerators_=0;
+      // also get rid of cut generator
+      int n=0;
+      for (int i = 0; i < numberCutGenerators_; i++) {
+	CglImplication * cutGen;
+	cutGen = dynamic_cast<CglImplication *>(generator_[i]->generator());
+	if (!cutGen) {
+	  generator_[n]=generator_[i];
+	  virginGenerator_[n]=virginGenerator_[i];
+	  n++;
+	} else {
+	  cutGen->setProbingInfo(NULL);
+	  delete generator_[i];
+	  cutGen = dynamic_cast<CglImplication *>(virginGenerator_[i]->generator());
+	  assert (cutGen);
+	  cutGen->setProbingInfo(NULL);
+	  delete virginGenerator_[i];
+	}
+      }
+      numberCutGenerators_=n;
+    }
+    maximumStatistics_ = 0;
+    delete [] analyzeResults_;
+    analyzeResults_ = NULL;
+    bestObjective_ = COIN_DBL_MAX;
+    bestPossibleObjective_ = COIN_DBL_MAX;
+    sumChangeObjective1_ = 0.0;
+    sumChangeObjective2_ = 0.0;
+    numberSolutions_ = 0;
+    stateOfSearch_ = 0;
+    delete [] hotstartSolution_;
+    hotstartSolution_ = NULL;
+    delete [] hotstartPriorities_;
+    hotstartPriorities_ = NULL;
+    numberHeuristicSolutions_ = 0;
+    numberNodes_ = 0;
+    numberNodes2_ = 0;
+    numberIterations_ = 0;
+    numberSolves_ = 0;
+    status_ = -1;
+    secondaryStatus_ = -1;
+    maximumNumberCuts_ = 0;
+    phase_ = 0;
+    currentNumberCuts_ = 0;
+    maximumDepth_ = 0;
+    nextRowCut_ = NULL;
+    currentNode_ = NULL;
+    // clear out tree
+    if (tree_ && tree_->size())
+        tree_->cleanTree(this, -1.0e100, bestPossibleObjective_) ;
+    subTreeModel_ = NULL;
+    heuristicModel_ = NULL;
+    numberStoppedSubTrees_ = 0;
+    numberInfeasibleNodes_ = 0;
+    numberGlobalViolations_ = 0;
+    numberExtraIterations_ = 0;
+    numberExtraNodes_ = 0;
+    continuousObjective_ = 0.0;
+    originalContinuousObjective_ = 0.0;
+    continuousInfeasibilities_ = 0;
+    numberFixedAtRoot_ = 0;
+    numberFixedNow_ = 0;
+    stoppedOnGap_ = false;
+    eventHappened_ = false;
+    numberLongStrong_ = 0;
+    numberOldActiveCuts_ = 0;
+    numberNewCuts_ = 0;
+    searchStrategy_ = -1;
+    strongStrategy_ = 0;
+    numberStrongIterations_ = 0;
+    // Parameters which need to be reset
+    setCutoff(COIN_DBL_MAX);
+    dblParam_[CbcCutoffIncrement] = 1e-5;
+    dblParam_[CbcCurrentCutoff] = 1.0e100;
+    dblParam_[CbcCurrentObjectiveValue] = 1.0e100;
+    dblParam_[CbcCurrentMinimizationObjectiveValue] = 1.0e100;
+    delete globalConflictCuts_;
+    globalConflictCuts_=NULL;
+}
+/* Most of copy constructor
+      mode - 0 copy but don't delete before
+             1 copy and delete before
+	     2 copy and delete before (but use virgin generators)
+*/
+void
+CbcModel::gutsOfCopy(const CbcModel & rhs, int mode)
+{
+    minimumDrop_ = rhs.minimumDrop_;
+    specialOptions_ = rhs.specialOptions_;
+    moreSpecialOptions_ = rhs.moreSpecialOptions_;
+    numberStrong_ = rhs.numberStrong_;
+    numberBeforeTrust_ = rhs.numberBeforeTrust_;
+    numberPenalties_ = rhs.numberPenalties_;
+    printFrequency_ = rhs.printFrequency_;
+    fastNodeDepth_ = rhs.fastNodeDepth_;
+    howOftenGlobalScan_ = rhs.howOftenGlobalScan_;
+    maximumCutPassesAtRoot_ = rhs.maximumCutPassesAtRoot_;
+    maximumCutPasses_ =  rhs.maximumCutPasses_;
+    randomSeed_ = rhs.randomSeed_;
+    multipleRootTries_ = rhs.multipleRootTries_;
+    preferredWay_ = rhs.preferredWay_;
+    resolveAfterTakeOffCuts_ = rhs.resolveAfterTakeOffCuts_;
+    maximumNumberIterations_ = rhs.maximumNumberIterations_;
+    numberSavedSolutions_ = rhs.numberSavedSolutions_;
+    maximumSavedSolutions_ = rhs.maximumSavedSolutions_;
+    if (maximumSavedSolutions_) {
+        int n = solver_->getNumCols();
+        savedSolutions_ = new double * [maximumSavedSolutions_];
+        for (int i = 0; i < maximumSavedSolutions_; i++)
+            savedSolutions_[i] = CoinCopyOfArray(rhs.savedSolutions_[i], n + 2);
+    }
+    continuousPriority_ = rhs.continuousPriority_;
+    numberThreads_ = rhs.numberThreads_;
+    threadMode_ = rhs.threadMode_;
+    delete master_;
+    master_ = NULL;
+    masterThread_ = NULL;
+    memcpy(intParam_, rhs.intParam_, sizeof(intParam_));
+    memcpy(dblParam_, rhs.dblParam_, sizeof(dblParam_));
+    int i;
+    if (mode) {
+        for (i = 0; i < numberCutGenerators_; i++) {
+            delete generator_[i];
+            delete virginGenerator_[i];
+        }
+        delete [] generator_;
+        delete [] virginGenerator_;
+        for (i = 0; i < numberHeuristics_; i++) {
+            delete heuristic_[i];
+        }
+        delete [] heuristic_;
+        delete eventHandler_;
+        delete branchingMethod_;
+    }
+    numberCutGenerators_ = rhs.numberCutGenerators_;
+    if (numberCutGenerators_) {
+        generator_ = new CbcCutGenerator * [numberCutGenerators_];
+        virginGenerator_ = new CbcCutGenerator * [numberCutGenerators_];
+        int i;
+        for (i = 0; i < numberCutGenerators_; i++) {
+	    if (mode < 2) {
+                generator_[i] = new CbcCutGenerator(*rhs.generator_[i]);
+	    } else {
+                generator_[i] = new CbcCutGenerator(*rhs.virginGenerator_[i]);
+		// But copy across maximumTries
+                generator_[i]->setMaximumTries(rhs.generator_[i]->maximumTries());
+	    }
+            virginGenerator_[i] = new CbcCutGenerator(*rhs.virginGenerator_[i]);
+        }
+    } else {
+        generator_ = NULL;
+        virginGenerator_ = NULL;
+    }
+    numberHeuristics_ = rhs.numberHeuristics_;
+    if (numberHeuristics_) {
+        heuristic_ = new CbcHeuristic * [numberHeuristics_];
+        int i;
+        for (i = 0; i < numberHeuristics_; i++) {
+            heuristic_[i] = rhs.heuristic_[i]->clone();
+        }
+    } else {
+        heuristic_ = NULL;
+    }
+    if (rhs.eventHandler_)
+        eventHandler_ = rhs.eventHandler_->clone() ;
+    else
+        eventHandler_ = NULL ;
+    if (rhs.branchingMethod_)
+        branchingMethod_ = rhs.branchingMethod_->clone();
+    else
+        branchingMethod_ = NULL;
+    messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
+    whenCuts_ = rhs.whenCuts_;
+    synchronizeModel();
+}
+// Move status, nodes etc etc across
+void
+CbcModel::moveInfo(const CbcModel & rhs)
+{
+    bestObjective_ = rhs.bestObjective_;
+    bestPossibleObjective_ = rhs.bestPossibleObjective_;
+    numberSolutions_ = rhs.numberSolutions_;
+    numberHeuristicSolutions_ = rhs.numberHeuristicSolutions_;
+    numberNodes_ = rhs.numberNodes_;
+    numberNodes2_ = rhs.numberNodes2_;
+    numberIterations_ = rhs.numberIterations_;
+    numberSolves_ = rhs.numberSolves_;
+    status_ = rhs.status_;
+    secondaryStatus_ = rhs.secondaryStatus_;
+    numberStoppedSubTrees_ = rhs.numberStoppedSubTrees_;
+    numberInfeasibleNodes_ = rhs.numberInfeasibleNodes_;
+    continuousObjective_ = rhs.continuousObjective_;
+    originalContinuousObjective_ = rhs.originalContinuousObjective_;
+    continuousInfeasibilities_ = rhs.continuousInfeasibilities_;
+    numberFixedAtRoot_ = rhs.numberFixedAtRoot_;
+    numberFixedNow_ = rhs.numberFixedNow_;
+    stoppedOnGap_ = rhs.stoppedOnGap_;
+    eventHappened_ = rhs.eventHappened_;
+    numberLongStrong_ = rhs.numberLongStrong_;
+    numberStrongIterations_ = rhs.numberStrongIterations_;
+    strongInfo_[0] = rhs.strongInfo_[0];
+    strongInfo_[1] = rhs.strongInfo_[1];
+    strongInfo_[2] = rhs.strongInfo_[2];
+    strongInfo_[3] = rhs.strongInfo_[3];
+    strongInfo_[4] = rhs.strongInfo_[4];
+    strongInfo_[5] = rhs.strongInfo_[5];
+    strongInfo_[6] = rhs.strongInfo_[6];
+    numberRowsAtContinuous_ = rhs.numberRowsAtContinuous_;
+    cutoffRowNumber_ = rhs.cutoffRowNumber_;
+    maximumDepth_ = rhs.maximumDepth_;
+}
+// Save a copy of the current solver so can be reset to
+void
+CbcModel::saveReferenceSolver()
+{
+    delete referenceSolver_;
+    referenceSolver_ = solver_->clone();
+}
+
+// Uses a copy of reference solver to be current solver
+void
+CbcModel::resetToReferenceSolver()
+{
+    delete solver_;
+    solver_ = referenceSolver_->clone();
+    // clear many things
+    gutsOfDestructor2();
+    // Reset cutoff
+    // Solvers know about direction
+    double direction = solver_->getObjSense();
+    double value;
+    solver_->getDblParam(OsiDualObjectiveLimit, value);
+    setCutoff(value*direction);
+}
+
+// Are there a numerical difficulties?
+bool
+CbcModel::isAbandoned() const
+{
+    return status_ == 2;
+}
+// Is optimality proven?
+bool
+CbcModel::isProvenOptimal() const
+{
+    if (!status_ && bestObjective_ < 1.0e30)
+        return true;
+    else
+        return false;
+}
+// Is  infeasiblity proven (or none better than cutoff)?
+bool
+CbcModel::isProvenInfeasible() const
+{
+    if (!status_ && bestObjective_ >= 1.0e30)
+        return true;
+    else
+        return false;
+}
+// Was continuous solution unbounded
+bool
+CbcModel::isContinuousUnbounded() const
+{
+    if (!status_ && secondaryStatus_ == 7)
+        return true;
+    else
+        return false;
+}
+// Was continuous solution unbounded
+bool
+CbcModel::isProvenDualInfeasible() const
+{
+    if (!status_ && secondaryStatus_ == 7)
+        return true;
+    else
+        return false;
+}
+// Node limit reached?
+bool
+CbcModel::isNodeLimitReached() const
+{
+    return numberNodes_ >= intParam_[CbcMaxNumNode];
+}
+// Time limit reached?
+bool
+CbcModel::isSecondsLimitReached() const
+{
+    if (status_ == 1 && secondaryStatus_ == 4)
+        return true;
+    else
+        return false;
+}
+// Solution limit reached?
+bool
+CbcModel::isSolutionLimitReached() const
+{
+    return numberSolutions_ >= intParam_[CbcMaxNumSol];
+}
+// Set language
+void
+CbcModel::newLanguage(CoinMessages::Language language)
+{
+    messages_ = CbcMessage(language);
+}
+void
+CbcModel::setNumberStrong(int number)
+{
+    if (number < 0)
+        numberStrong_ = 0;
+    else
+        numberStrong_ = number;
+}
+void
+CbcModel::setNumberBeforeTrust(int number)
+{
+    if (number < -3) {
+        numberBeforeTrust_ = 0;
+    } else {
+        numberBeforeTrust_ = number;
+        //numberStrong_ = CoinMax(numberStrong_,1);
+    }
+}
+void
+CbcModel::setNumberPenalties(int number)
+{
+    if (number <= 0) {
+        numberPenalties_ = 0;
+    } else {
+        numberPenalties_ = number;
+    }
+}
+void
+CbcModel::setPenaltyScaleFactor(double value)
+{
+    if (value <= 0) {
+        penaltyScaleFactor_ = 3.0;
+    } else {
+        penaltyScaleFactor_ = value;
+    }
+}
+void
+CbcModel::setHowOftenGlobalScan(int number)
+{
+    if (number < -1)
+        howOftenGlobalScan_ = 0;
+    else
+        howOftenGlobalScan_ = number;
+}
+
+// Add one generator
+void
+CbcModel::addCutGenerator(CglCutGenerator * generator,
+                          int howOften, const char * name,
+                          bool normal, bool atSolution,
+                          bool whenInfeasible, int howOftenInSub,
+                          int whatDepth, int whatDepthInSub)
+{
+    CbcCutGenerator ** temp = generator_;
+    generator_ = new CbcCutGenerator * [numberCutGenerators_+1];
+    memcpy(generator_, temp, numberCutGenerators_*sizeof(CbcCutGenerator *));
+    delete[] temp ;
+    generator_[numberCutGenerators_] =
+        new CbcCutGenerator(this, generator, howOften, name,
+                            normal, atSolution, whenInfeasible, howOftenInSub,
+                            whatDepth, whatDepthInSub);
+    // and before any changes
+    temp = virginGenerator_;
+    virginGenerator_ = new CbcCutGenerator * [numberCutGenerators_+1];
+    memcpy(virginGenerator_, temp, numberCutGenerators_*sizeof(CbcCutGenerator *));
+    delete[] temp ;
+    virginGenerator_[numberCutGenerators_++] =
+        new CbcCutGenerator(this, generator, howOften, name,
+                            normal, atSolution, whenInfeasible, howOftenInSub,
+                            whatDepth, whatDepthInSub);
+
+}
+// Add one heuristic
+void
+CbcModel::addHeuristic(CbcHeuristic * generator, const char *name,
+                       int before)
+{
+    CbcHeuristic ** temp = heuristic_;
+    heuristic_ = new CbcHeuristic * [numberHeuristics_+1];
+    memcpy(heuristic_, temp, numberHeuristics_*sizeof(CbcHeuristic *));
+    delete [] temp;
+    int where;
+    if (before < 0 || before >= numberHeuristics_) {
+        where = numberHeuristics_;
+    } else {
+        // move up
+        for (int i = numberHeuristics_; i > before; i--)
+            heuristic_[i] = heuristic_[i-1];
+        where = before;
+    }
+    heuristic_[where] = generator->clone();
+    if (name)
+        heuristic_[where]->setHeuristicName(name) ;
+    heuristic_[where]->setSeed(987654321 + where);
+    numberHeuristics_++ ;
+}
+
+/*
+  The last subproblem handled by the solver is not necessarily related to the
+  one being recreated, so the first action is to remove all cuts from the
+  constraint system.  Next, traverse the tree from node to the root to
+  determine the basis size required for this subproblem and create an empty
+  basis with the right capacity.  Finally, traverse the tree from root to
+  node, adjusting bounds in the constraint system, adjusting the basis, and
+  collecting the cuts that must be added to the constraint system.
+  applyToModel does the heavy lifting.
+
+  addCuts1 is used in contexts where all that's desired is the list of cuts:
+  the node is already fathomed, and we're collecting cuts so that we can
+  adjust reference counts as we prune nodes. Arguably the two functions
+  should be separated. The culprit is applyToModel, which performs cut
+  collection and model adjustment.
+
+  Certainly in the contexts where all we need is a list of cuts, there's no
+  point in passing in a valid basis --- an empty basis will do just fine.
+*/
+bool CbcModel::addCuts1 (CbcNode * node, CoinWarmStartBasis *&lastws)
+{
+    int nNode = 0;
+    CbcNodeInfo * nodeInfo = node->nodeInfo();
+    int numberColumns = getNumCols();
+
+    /*
+      Accumulate the path from node to the root in walkback_, and accumulate a
+      cut count in currentNumberCuts.
+
+      original comment: when working then just unwind until where new node joins
+      old node (for cuts?)
+    */
+    int currentNumberCuts = 0;
+    while (nodeInfo) {
+        //printf("nNode = %d, nodeInfo = %x\n",nNode,nodeInfo);
+        walkback_[nNode++] = nodeInfo;
+        currentNumberCuts += nodeInfo->numberCuts() ;
+        nodeInfo = nodeInfo->parent() ;
+        if (nNode == maximumDepth_) {
+            redoWalkBack();
+        }
+    }
+    currentNumberCuts_ = currentNumberCuts;
+    if (currentNumberCuts > maximumNumberCuts_) {
+        maximumNumberCuts_ = currentNumberCuts;
+        delete [] addedCuts_;
+        addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
+    }
+    /*
+      This last bit of code traverses the path collected in walkback_ from the
+      root back to node. At the end of the loop,
+       * lastws will be an appropriate basis for node;
+       * variable bounds in the constraint system will be set to be correct for
+         node; and
+       * addedCuts_ will be set to a list of cuts that need to be added to the
+         constraint system at node.
+      applyToModel does all the heavy lifting.
+    */
+    bool sameProblem = false;
+    if ((specialOptions_&4096) == 0) {
+#if 0
+        {
+            int n1 = numberRowsAtContinuous_;
+            for (int i = 0; i < lastDepth_; i++)
+                n1 += lastNumberCuts_[i];
+            int n2 = numberRowsAtContinuous_;
+            for (int i = 0; i < nNode; i++)
+                n2 += walkback_[i]->numberCuts();
+            //printf("ROWS a %d - old thinks %d new %d\n",solver_->getNumRows(),n1,n2);
+        }
+#endif
+        int nDel = 0;
+        int nAdd = 0;
+        int n = CoinMin(lastDepth_, nNode);
+        int i;
+        int difference = lastDepth_ - nNode;
+        int iZ = lastDepth_;
+        int iN = 0;
+        // Last is reversed to minimize copying
+        if (difference > 0) {
+            for (i = 0; i < difference; i++) {
+                // delete rows
+                nDel += lastNumberCuts_[--iZ];
+            }
+        } else if (difference < 0) {
+            for (i = 0; i < -difference; i++) {
+                // add rows
+                nAdd += walkback_[i]->numberCuts();
+            }
+            iN = -difference;
+        }
+        for (i = 0; i < n; i++) {
+            iZ--;
+            if (lastNodeInfo_[iZ] == walkback_[iN]) {
+                break;
+            } else {
+                // delete rows
+                nDel += lastNumberCuts_[iZ];
+                // add rows
+                nAdd += walkback_[iN++]->numberCuts();
+            }
+        }
+        assert (i < n || lastDepth_ == 0);
+        //printf("lastDepth %d thisDepth %d match at %d, rows+-= %d %d\n",
+        //   lastDepth_,nNode,n-i,nAdd,nDel);
+        sameProblem = (!nAdd) && (!nDel);
+        if (lastDepth_) {
+            while (iN >= 0) {
+                lastNumberCuts_[iZ] = walkback_[iN]->numberCuts();
+                lastNodeInfo_[iZ++] = walkback_[iN--];
+            }
+        } else {
+            lastNumberCuts_[0] = walkback_[0]->numberCuts();
+            lastNodeInfo_[0] = walkback_[0];
+        }
+        lastDepth_ = nNode;
+    }
+    currentDepth_ = nNode;
+    /*
+      Remove all cuts from the constraint system.
+      (original comment includes ``see note below for later efficiency'', but
+      the reference isn't clear to me).
+    */
+    /*
+      Create an empty basis with sufficient capacity for the constraint system
+      we'll construct: original system plus cuts. Make sure we have capacity to
+      record those cuts in addedCuts_.
+
+      The method of adjusting the basis at a FullNodeInfo object (the root, for
+      example) is to use a copy constructor to duplicate the basis held in the
+      nodeInfo, then resize it and return the new basis object. Guaranteed,
+      lastws will point to a different basis when it returns. We pass in a basis
+      because we need the parameter to return the allocated basis, and it's an
+      easy way to pass in the size. But we take a hit for memory allocation.
+    */
+    lastws->setSize(numberColumns, numberRowsAtContinuous_ + currentNumberCuts);
+    currentNumberCuts = 0;
+    while (nNode) {
+        --nNode;
+        walkback_[nNode]->applyToModel(this, lastws,
+                                       addedCuts_, currentNumberCuts);
+    }
+#ifndef NDEBUG
+    if (!lastws->fullBasis()) {
+#ifdef COIN_DEVELOP
+        printf("******* bad basis\n");
+#endif
+        int numberRows = lastws->getNumArtificial();
+        int i;
+        for (i = 0; i < numberRows; i++)
+            lastws->setArtifStatus(i, CoinWarmStartBasis::basic);
+        int numberColumns = lastws->getNumStructural();
+        for (i = 0; i < numberColumns; i++) {
+            if (lastws->getStructStatus(i) == CoinWarmStartBasis::basic)
+                lastws->setStructStatus(i, CoinWarmStartBasis::atLowerBound);
+        }
+    }
+#endif
+    return sameProblem;
+}
+
+/*
+  adjustCuts might be a better name: If the node is feasible, we sift through
+  the cuts collected by addCuts1, add the ones that are tight and omit the
+  ones that are loose. If the node is infeasible, we just adjust the
+  reference counts to reflect that we're about to prune this node and its
+  descendants.
+*/
+int CbcModel::addCuts (CbcNode *node, CoinWarmStartBasis *&lastws, bool canFix)
+{
+    /*
+      addCuts1 performs step 1 of restoring the subproblem at this node; see the
+      comments there.
+    */
+    bool sameProblem =
+        addCuts1(node, lastws);
+    int i;
+    int numberColumns = getNumCols();
+    if (solver_->getNumRows() > maximumRows_) {
+        maximumRows_ = solver_->getNumRows();
+        workingBasis_.resize(maximumRows_, numberColumns);
+    }
+    CbcNodeInfo * nodeInfo = node->nodeInfo();
+    double cutoff = getCutoff() ;
+    int currentNumberCuts = currentNumberCuts_;
+    if (canFix) {
+        bool feasible = true;
+        const double *lower = solver_->getColLower() ;
+        const double *upper = solver_->getColUpper() ;
+        double * newLower = analyzeResults_;
+        double * objLower = newLower + numberIntegers_;
+        double * newUpper = objLower + numberIntegers_;
+        double * objUpper = newUpper + numberIntegers_;
+        int n = 0;
+        for (i = 0; i < numberIntegers_; i++) {
+            int iColumn = integerVariable_[i];
+            bool changed = false;
+            double lo = 0.0;
+            double up = 0.0;
+            if (objLower[i] > cutoff) {
+                lo = lower[iColumn];
+                up = upper[iColumn];
+                if (lo < newLower[i]) {
+                    lo = newLower[i];
+                    solver_->setColLower(iColumn, lo);
+                    changed = true;
+                    n++;
+                }
+                if (objUpper[i] > cutoff) {
+                    if (up > newUpper[i]) {
+                        up = newUpper[i];
+                        solver_->setColUpper(iColumn, up);
+                        changed = true;
+                        n++;
+                    }
+                }
+            } else if (objUpper[i] > cutoff) {
+                lo = lower[iColumn];
+                up = upper[iColumn];
+                if (up > newUpper[i]) {
+                    up = newUpper[i];
+                    solver_->setColUpper(iColumn, up);
+                    changed = true;
+                    n++;
+                }
+            }
+            if (changed && lo > up) {
+                feasible = false;
+                break;
+            }
+        }
+        if (!feasible) {
+	  COIN_DETAIL_PRINT(printf("analysis says node infeas\n"));
+            cutoff = -COIN_DBL_MAX;
+        }
+    }
+    /*
+      If the node can't be fathomed by bound, reinstall tight cuts in the
+      constraint system. Even if there are no cuts, we'll want to set the
+      reconstructed basis in the solver.
+    */
+    if (node->objectiveValue() < cutoff || numberThreads_) {
+        //#   define CBC_CHECK_BASIS
+#   ifdef CBC_CHECK_BASIS
+        printf("addCuts: expanded basis; rows %d+%d\n",
+               numberRowsAtContinuous_, currentNumberCuts);
+        lastws->print();
+#   endif
+        /*
+          Adjust the basis and constraint system so that we retain only active cuts.
+          There are three steps:
+            1) Scan the basis. Sort the cuts into effective cuts to be kept and
+               loose cuts to be dropped.
+            2) Drop the loose cuts and resize the basis to fit.
+            3) Install the tight cuts in the constraint system (applyRowCuts) and
+               and install the basis (setWarmStart).
+          Use of compressRows conveys we're compressing the basis and not just
+          tweaking the artificialStatus_ array.
+        */
+        if (currentNumberCuts > 0) {
+            int numberToAdd = 0;
+            const OsiRowCut **addCuts;
+            int numberToDrop = 0 ;
+            int *cutsToDrop ;
+            addCuts = new const OsiRowCut* [currentNumberCuts];
+            cutsToDrop = new int[currentNumberCuts] ;
+            assert (currentNumberCuts + numberRowsAtContinuous_ <= lastws->getNumArtificial());
+            for (i = 0; i < currentNumberCuts; i++) {
+                CoinWarmStartBasis::Status status =
+                    lastws->getArtifStatus(i + numberRowsAtContinuous_);
+                if (addedCuts_[i] &&
+                        (status != CoinWarmStartBasis::basic ||
+                         (addedCuts_[i]->effectiveness() > 1.0e10 &&
+                          !addedCuts_[i]->canDropCut(solver_, i + numberRowsAtContinuous_)))) {
+#	  ifdef CHECK_CUT_COUNTS
+                    printf("Using cut %d %x as row %d\n", i, addedCuts_[i],
+                           numberRowsAtContinuous_ + numberToAdd);
+#	  endif
+                    addCuts[numberToAdd++] = addedCuts_[i];
+#if 1
+		    if ((specialOptions_&1) != 0) {
+		      const OsiRowCutDebugger * debugger = solver_->getRowCutDebugger() ;
+		      if (debugger)
+			CoinAssert (!debugger->invalidCut(*addedCuts_[i]));
+		    }
+#endif
+                } else {
+#	  ifdef CHECK_CUT_COUNTS
+                    printf("Dropping cut %d %x\n", i, addedCuts_[i]);
+#	  endif
+                    addedCuts_[i] = NULL;
+                    cutsToDrop[numberToDrop++] = numberRowsAtContinuous_ + i ;
+                }
+            }
+            assert (lastws->fullBasis());
+            int numberRowsNow = numberRowsAtContinuous_ + numberToAdd;
+            lastws->compressRows(numberToDrop, cutsToDrop) ;
+            lastws->resize(numberRowsNow, numberColumns);
+            // Take out as local search can give bad basisassert (lastws->fullBasis());
+            bool canMissStuff = false;
+            if ((specialOptions_&4096) == 0) {
+                bool redoCuts = true;
+                if (CoinAbs(lastNumberCuts2_ - numberToAdd) < 5) {
+                    int numberToCheck = CoinMin(lastNumberCuts2_, numberToAdd);
+                    int i1 = 0;
+                    int i2 = 0;
+                    int nDiff = 0;
+                    int nSame = 0;
+                    if (lastNumberCuts2_ == numberToAdd) {
+                        for (int i = 0; i < numberToCheck; i++) {
+                            if (lastCut_[i1++] != addCuts[i2++]) {
+                                nDiff++;
+                            } else {
+                                nSame++;
+                            }
+                        }
+                    } else if (lastNumberCuts2_ > numberToAdd) {
+                        int nDiff2 = lastNumberCuts2_ - numberToAdd;
+                        for (int i = 0; i < numberToCheck; i++) {
+                            if (lastCut_[i1] != addCuts[i2]) {
+                                nDiff++;
+                                while (nDiff2) {
+                                    i1++;
+                                    nDiff2--;
+                                    if (lastCut_[i1] == addCuts[i2]) {
+                                        nSame++;
+                                        break;
+                                    } else {
+                                        nDiff++;
+                                    }
+                                }
+                            } else {
+                                nSame++;
+                            }
+                        }
+                        nDiff += nDiff2;
+                    } else {
+                        int nDiff2 = numberToAdd - lastNumberCuts2_;
+                        for (int i = 0; i < numberToCheck; i++) {
+                            if (lastCut_[i1] != addCuts[i2]) {
+                                nDiff++;
+                                while (nDiff2) {
+                                    i2++;
+                                    nDiff2--;
+                                    if (lastCut_[i1] == addCuts[i2]) {
+                                        nSame++;
+                                        break;
+                                    } else {
+                                        nDiff++;
+                                    }
+                                }
+                            } else {
+                                nSame++;
+                            }
+                        }
+                        nDiff += nDiff2;
+                    }
+                    canMissStuff = !nDiff && sameProblem;
+                    // But only if number of rows looks OK
+                    if (numberRowsAtContinuous_ + numberToAdd != solver_->getNumRows())
+                        canMissStuff = false;
+                } else {
+                    //printf("add now %d add last %d NO2\n",numberToAdd,lastNumberCuts2_);
+                }
+                assert (lastws->fullBasis() &&
+                        numberRowsAtContinuous_ + numberToAdd == numberRowsNow);
+                if (redoCuts) {
+                    if (numberToAdd > maximumCuts_) {
+                        delete [] lastCut_;
+                        maximumCuts_ = 2 * numberToAdd + 10;
+                        lastCut_ = new const OsiRowCut * [maximumCuts_];
+                    }
+                    lastNumberCuts2_ = numberToAdd;
+                    for (int i = 0; i < numberToAdd; i++)
+                        lastCut_[i] = addCuts[i];
+                }
+            }
+            if (!canMissStuff) {
+                //if (canMissStuff)
+                //solver_->writeMps("before");
+                //printf("Not Skipped\n");
+                //int n1=solver_->getNumRows();
+                if ((specialOptions_&4096) == 0) {
+                    solver_->restoreBaseModel(numberRowsAtContinuous_);
+                } else {
+                    // *** Fix later
+                    int numberCuts = solver_->getNumRows() - numberRowsAtContinuous_;
+                    int *which = new int[numberCuts];
+                    for (i = 0 ; i < numberCuts ; i++)
+                        which[i] = i + numberRowsAtContinuous_;
+                    solver_->deleteRows(numberCuts, which);
+                    delete [] which;
+                }
+		//#define CHECK_DEBUGGER
+#ifdef CHECK_DEBUGGER
+		if ((specialOptions_&1) != 0 ) {
+		  const OsiRowCutDebugger * debugger = 
+		    solver_->getRowCutDebugger();
+		  if (debugger) {
+		    for (int j=0;j<numberToAdd;j++)
+		      CoinAssert (!debugger->invalidCut(*addCuts[j]));
+		    //addCuts[j]->print();
+		  }
+		}
+#endif
+                //int n2=solver_->getNumRows();
+                //for (int j=0;j<numberToAdd;j++)
+                //addCuts[j]->print();
+                solver_->applyRowCuts(numberToAdd, addCuts);
+                //int n3=solver_->getNumRows();
+                //printf("NBefore %d, after del %d, now %d\n",n1,n2,n3);
+            }
+#     ifdef CBC_CHECK_BASIS
+            printf("addCuts: stripped basis; rows %d + %d\n",
+                   numberRowsAtContinuous_, numberToAdd);
+            lastws->print();
+#     endif
+            //for (i=0;i<numberToAdd;i++)
+            //delete addCuts[i];
+            delete [] addCuts;
+            delete [] cutsToDrop ;
+        }
+        /*
+          Set the basis in the solver.
+        */
+        solver_->setWarmStart(lastws);
+        /*
+          Clean up and we're out of here.
+        */
+        numberNodes_++;
+        return 0;
+    }
+    /*
+      This node has been fathomed by bound as we try to revive it out of the live
+      set. Adjust the cut reference counts to reflect that we no longer need to
+      explore the remaining branch arms, hence they will no longer reference any
+      cuts. Cuts whose reference count falls to zero are deleted.
+    */
+    else {
+        int i;
+        if (currentNumberCuts) {
+            lockThread();
+            int numberLeft = nodeInfo->numberBranchesLeft();
+            for (i = 0 ; i < currentNumberCuts ; i++) {
+                if (addedCuts_[i]) {
+                    if (!addedCuts_[i]->decrement(numberLeft)) {
+                        delete addedCuts_[i];
+                        addedCuts_[i] = NULL;
+                    }
+                }
+            }
+            unlockThread();
+        }
+        return 1 ;
+    }
+}
+/* Makes all handlers same.  If makeDefault 1 then makes top level
+   default and rest point to that.  If 2 then each is copy
+*/
+void
+CbcModel::synchronizeHandlers(int /*makeDefault*/)
+{
+    bool defaultHandler = defaultHandler_;
+    if (!defaultHandler_) {
+        // Must have clone
+        handler_ = handler_->clone();
+        defaultHandler_ = true;
+    }
+#ifdef COIN_HAS_CLP
+    if (!defaultHandler) {
+      OsiClpSolverInterface * solver;
+      solver = dynamic_cast<OsiClpSolverInterface *>(solver_) ;
+      if (solver) {
+        solver->passInMessageHandler(handler_);
+        solver->getModelPtr()->passInMessageHandler(handler_);
+      }
+      solver = dynamic_cast<OsiClpSolverInterface *>(continuousSolver_) ;
+      if (solver) {
+        solver->passInMessageHandler(handler_);
+        solver->getModelPtr()->passInMessageHandler(handler_);
+      }
+    }
+#endif
+}
+
+
+/*
+  Perform reduced cost fixing on integer variables.
+
+  The variables in question are already nonbasic at bound. We're just nailing
+  down the current situation.
+*/
+int CbcModel::reducedCostFix ()
+
+{
+    if (!solverCharacteristics_->reducedCostsAccurate())
+        return 0; //NLP
+    double cutoff = getCutoff() ;
+    double direction = solver_->getObjSense() ;
+    double gap = cutoff - solver_->getObjValue() * direction ;
+    double tolerance;
+    solver_->getDblParam(OsiDualTolerance, tolerance) ;
+    if (gap <= 0.0)
+        gap = tolerance; //return 0;
+    gap += 100.0 * tolerance;
+    double integerTolerance = getDblParam(CbcIntegerTolerance) ;
+
+    const double *lower = solver_->getColLower() ;
+    const double *upper = solver_->getColUpper() ;
+    const double *solution = solver_->getColSolution() ;
+    const double *reducedCost = solver_->getReducedCost() ;
+
+    int numberFixed = 0 ;
+    int numberTightened = 0 ;
+
+# ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver_);
+    ClpSimplex * clpSimplex = NULL;
+    if (clpSolver)
+        clpSimplex = clpSolver->getModelPtr();
+# endif
+    for (int i = 0 ; i < numberIntegers_ ; i++) {
+        int iColumn = integerVariable_[i] ;
+        double djValue = direction * reducedCost[iColumn] ;
+        double boundGap = upper[iColumn] - lower[iColumn];
+        if (boundGap > integerTolerance) {
+            if (solution[iColumn] < lower[iColumn] + integerTolerance
+                    && djValue*boundGap > gap) {
+#ifdef COIN_HAS_CLP
+                // may just have been fixed before
+                if (clpSimplex) {
+                    if (clpSimplex->getColumnStatus(iColumn) == ClpSimplex::basic) {
+#ifdef COIN_DEVELOP
+                        printf("DJfix %d has status of %d, dj of %g gap %g, bounds %g %g\n",
+                               iColumn, clpSimplex->getColumnStatus(iColumn),
+                               djValue, gap, lower[iColumn], upper[iColumn]);
+#endif
+                    } else {
+                        assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atLowerBound ||
+                               clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+                    }
+                }
+#endif
+                double newBound = lower[iColumn];
+                if (boundGap > 1.99) {
+                    boundGap = gap / djValue + 1.0e-4 * boundGap;
+                    newBound = lower[iColumn] + floor(boundGap);
+                    numberTightened++;
+                    //if (newBound)
+                    //printf("tighter - gap %g dj %g newBound %g\n",
+                    //   gap,djValue,newBound);
+                }
+                solver_->setColUpper(iColumn, newBound) ;
+                numberFixed++ ;
+            } else if (solution[iColumn] > upper[iColumn] - integerTolerance && -djValue > boundGap*gap) {
+#ifdef COIN_HAS_CLP
+                // may just have been fixed before
+                if (clpSimplex) {
+                    if (clpSimplex->getColumnStatus(iColumn) == ClpSimplex::basic) {
+#ifdef COIN_DEVELOP
+                        printf("DJfix %d has status of %d, dj of %g gap %g, bounds %g %g\n",
+                               iColumn, clpSimplex->getColumnStatus(iColumn),
+                               djValue, gap, lower[iColumn], upper[iColumn]);
+#endif
+                    } else {
+                        assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atUpperBound ||
+                               clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+                    }
+                }
+#endif
+                double newBound = upper[iColumn];
+                if (boundGap > 1.99) {
+                    boundGap = -gap / djValue + 1.0e-4 * boundGap;
+                    newBound = upper[iColumn] - floor(boundGap);
+                    //if (newBound)
+                    //printf("tighter - gap %g dj %g newBound %g\n",
+                    //   gap,djValue,newBound);
+                    numberTightened++;
+                }
+                solver_->setColLower(iColumn, newBound) ;
+                numberFixed++ ;
+            }
+        }
+    }
+    numberDJFixed_ += numberFixed - numberTightened;
+    return numberFixed;
+}
+// Collect coding to replace whichGenerator
+void
+CbcModel::resizeWhichGenerator(int numberNow, int numberAfter)
+{
+    if (numberAfter > maximumWhich_) {
+        maximumWhich_ = CoinMax(maximumWhich_ * 2 + 100, numberAfter) ;
+        int * temp = new int[2*maximumWhich_] ;
+        memcpy(temp, whichGenerator_, numberNow*sizeof(int)) ;
+        delete [] whichGenerator_ ;
+        whichGenerator_ = temp ;
+        memset(whichGenerator_ + numberNow, 0, (maximumWhich_ - numberNow)*sizeof(int));
+    }
+}
+
+/** Solve the model using cuts
+
+  This version takes off redundant cuts from node.
+  Returns true if feasible.
+
+  \todo
+  Why do I need to resolve the problem? What has been done between the last
+  relaxation and calling solveWithCuts?
+
+  If numberTries == 0 then user did not want any cuts.
+*/
+
+bool
+CbcModel::solveWithCuts (OsiCuts &cuts, int numberTries, CbcNode *node)
+/*
+  Parameters:
+    numberTries: (i) the maximum number of iterations for this round of cut
+		     generation; if negative then we don't mind if drop is tiny.
+
+    cuts:	(o) all cuts generated in this round of cut generation
+
+    node: (i)     So we can update dynamic pseudo costs
+*/
+
+
+{
+#ifdef JJF_ZERO
+    if (node && numberTries > 1) {
+        if (currentDepth_ < 5)
+            numberTries *= 4; // boost
+        else if (currentDepth_ < 10)
+            numberTries *= 2; // boost
+    }
+#endif
+#define CUT_HISTORY 7
+    double cut_obj[CUT_HISTORY];
+    for (int j = 0; j < CUT_HISTORY; j++)
+        cut_obj[j] = -COIN_DBL_MAX;
+# ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver_);
+    int saveClpOptions = 0;
+    if (clpSolver)
+        saveClpOptions = clpSolver->specialOptions();
+# endif
+    //solver_->writeMps("saved");
+#ifdef CBC_THREAD
+    /*
+      Thread mode makes a difference here only when it specifies using separate
+      threads to generate cuts at the root (bit 2^1 set in threadMode_). In which
+      case we'll create an array of empty CbcModels (!). Solvers will be cloned
+      later.
+
+      Don't start up threads here if we're already threaded.
+    */
+    CbcBaseModel * master = NULL;
+    if (numberThreads_ && (threadMode_&2) != 0 && !numberNodes_) {
+        master = new CbcBaseModel(*this, -1);
+    }
+#endif
+    bool feasible = true ;
+    int violated = 0 ;
+    int numberRowsAtStart = solver_->getNumRows() ;
+    //printf("solver had %d rows\n",numberRowsAtStart);
+    int numberColumns = solver_->getNumCols() ;
+    CoinBigIndex numberElementsAtStart = solver_->getNumElements();
+
+    numberOldActiveCuts_ = numberRowsAtStart - numberRowsAtContinuous_ ;
+    numberNewCuts_ = cuts.sizeRowCuts();
+    int lastNumberCuts = numberNewCuts_ ;
+    if (numberNewCuts_) {
+      // from multiple root passes
+      const OsiRowCut **addCuts = new const OsiRowCut* [numberNewCuts_];
+      for (int i = 0; i < numberNewCuts_; i++) {
+	addCuts[i] = cuts.rowCutPtr(i);
+      }
+      solver_->applyRowCuts(numberNewCuts_, addCuts);
+      delete [] addCuts;
+    }
+
+    bool onOptimalPath = false ;
+    const OsiRowCutDebugger *debugger = NULL;
+    if ((specialOptions_&1) != 0) {
+        /*
+          See OsiRowCutDebugger for details. In a nutshell, make sure that current
+          variable values do not conflict with a known optimal solution. (Obviously
+          this can be fooled when there are multiple solutions.)
+        */
+        debugger = solver_->getRowCutDebugger() ;
+        if (debugger)
+            onOptimalPath = (debugger->onOptimalPath(*solver_)) ;
+    }
+    /*
+      As the final action in each round of cut generation (the numberTries loop),
+      we'll call takeOffCuts to remove slack cuts. These are saved into slackCuts
+      and rechecked immediately after the cut generation phase of the loop.
+    */
+    OsiCuts slackCuts;
+    /*
+    lh:
+      Resolve the problem
+
+    The resolve will also refresh cached copies of the solver solution
+    (cbcColLower_, ...) held by CbcModel.
+    This resolve looks like the best point to capture a warm start for use in
+    the case where cut generation proves ineffective and we need to back out
+    a few tight cuts.
+    I've always maintained that this resolve is unnecessary. Let's put in a hook
+    to report if it's every nontrivial. -lh
+
+    Resolve the problem. If we've lost feasibility, might as well bail out right
+      after the debug stuff. The resolve will also refresh cached copies of the
+      solver solution (cbcColLower_, ...) held by CbcModel.
+    */
+    double objectiveValue = solver_->getObjValue() * solver_->getObjSense();
+    if (node) {
+        objectiveValue = node->objectiveValue();
+    }
+    int save = moreSpecialOptions_;
+    if ((moreSpecialOptions_&4194304)!=0)
+      moreSpecialOptions_ |= 8388608;
+    int returnCode = resolve(node ? node->nodeInfo() : NULL, 1);
+    moreSpecialOptions_=save;
+#ifdef CONFLICT_CUTS
+#ifdef COIN_HAS_CLP
+    // if infeasible conflict analysis
+    if (solver_->isProvenPrimalInfeasible()&&!parentModel_&&
+	(moreSpecialOptions_&4194304)!=0&&clpSolver) {
+      //printf("infeasible - do conflict analysis\n");
+      assert (topOfTree_);
+      int iType=1;
+      OsiRowCut * cut = clpSolver->modelCut(topOfTree_->lower(),
+					    topOfTree_->upper(),
+					    numberRowsAtContinuous_,whichGenerator_,iType);
+      if (cut) {
+	printf("XXXXXX cut\n");
+	//cut->print();
+	if (!iType) {
+	  makeGlobalCut(cut) ;
+	  if ((specialOptions_&1) != 0) {
+	    debugger = continuousSolver_->getRowCutDebugger() ;
+	    if (debugger) {
+	      if (debugger->invalidCut(*cut)) {
+		continuousSolver_->applyRowCuts(1,cut);
+		continuousSolver_->writeMps("bad");
+	      }
+	      CoinAssert (!debugger->invalidCut(*cut));
+	    }
+	  }
+	} else {
+	  makePartialCut(cut);
+	}
+	delete cut;
+      }
+    }
+    if ((moreSpecialOptions_&4194304)!=0&&solver_->isProvenPrimalInfeasible()
+	&&clpSolver&&clpSolver->lastAlgorithm()==2&&
+	clpSolver->getModelPtr()->infeasibilityRay()&&
+	!parentModel_) {
+      printf("ray exists\n");
+    }
+#endif
+#endif    
+#if COIN_DEVELOP>1
+    //if (!solver_->getIterationCount()&&solver_->isProvenOptimal())
+    //printf("zero iterations on first solve of branch\n");
+#endif
+    double lastObjective = solver_->getObjValue() * solver_->getObjSense();
+    cut_obj[CUT_HISTORY-1] = lastObjective;
+    //double firstObjective = lastObjective+1.0e-8+1.0e-12*fabs(lastObjective);
+    /*
+      Contemplate the result of the resolve.
+        - CbcModel::resolve() has a hook that calls CbcStrategy::status to look
+          over the solution. The net result is that resolve can return
+          0 (infeasible), 1 (feasible), or -1 (feasible, but do no further work).
+        - CbcFeasbililityBase::feasible() can return 0 (no comment),
+          1 (pretend this is an integer solution), or -1 (pretend this is
+          infeasible). As of 080104, this seems to be a stub to allow overrides,
+          with a default implementation that always returns 0.
+
+      Setting numberTries = 0 for `do no more work' is problematic. The main cut
+      generation loop will still execute once, so we do not observe the `no
+      further work' semantics.
+
+      As best I can see, allBranchesGone is a null function as of 071220.
+    */
+    if (node && node->nodeInfo() && !node->nodeInfo()->numberBranchesLeft())
+        node->nodeInfo()->allBranchesGone(); // can clean up
+    feasible = returnCode  != 0 ;
+    if (returnCode < 0)
+        numberTries = 0;
+    if (problemFeasibility_->feasible(this, 0) < 0) {
+        feasible = false; // pretend infeasible
+    }
+    /*
+      NEW_UPDATE_OBJECT is defined to 0 when unthreaded (CBC_THREAD undefined), 2
+      when threaded. No sign of 1 as of 071220.
+
+      At present, there are two sets of hierarchies for branching classes. Call
+      them CbcHier and OsiHier. For example, we have OsiBranchingObject, with
+      children CbcBranchingObject and OsiTwoWayBranchingObject. All
+      specialisations descend from one of these two children. Similarly, there is
+      OsiObject, with children CbcObject and OsiObject2.
+
+      In the original setup, there's a single CbcBranchDecision object attached
+      to CbcModel (branchingMethod_). It has a field to hold the current CbcHier
+      branching object, and the updateInformation routine reaches through the
+      branching object to update the underlying CbcHier object.
+
+      NEW_UPDATE_OBJECT = 0 would seem to assume the original setup. But,
+      if we're using the OSI hierarchy for objects and branching, a call to a
+      nontrivial branchingMethod_->updateInformation would have no effect (it
+      would expect a CbcObject to work on) or perhaps crash.  For the
+      default CbcBranchDefaultDecision, updateInformation is a noop (actually
+      defined in the base CbcBranchDecision class).
+
+      NEW_UPDATE_OBJECT = 2 looks like it's prepared to cope with either CbcHier or
+      OsiHier, but it'll be executed only when threads are activated. See the
+      comments below. The setup is scary.
+
+      But ... if the OsiHier update actually reaches right through to the object
+      list in the solver, it should work just fine in unthreaded mode. It would
+      seem that the appropriate thing to do in unthreaded mode would be to choose
+      between the existing code for NEW_UPDATE_OBJECT = 0 and the OsiHier code for
+      NEW_UPDATE_OBJECT = 2. But I'm going to let John hash that out. The worst
+      that can happen is inefficiency because I'm not properly updating an object.
+    */
+
+    // Update branching information if wanted
+    if (node && branchingMethod_) {
+        OsiBranchingObject * bobj = node->modifiableBranchingObject();
+        CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
+        if (cbcobj && cbcobj->object()) {
+            CbcObject * object = cbcobj->object();
+            CbcObjectUpdateData update = object->createUpdateInformation(solver_, node, cbcobj);
+            // have to compute object number as not saved
+            CbcSimpleInteger * simpleObject =
+                static_cast <CbcSimpleInteger *>(object) ;
+            int iObject = simpleObject->position();
+#ifndef NDEBUG
+            int iColumn = simpleObject->columnNumber();
+            int jObject;
+            for (jObject = 0 ; jObject < numberObjects_ ; jObject++) {
+                simpleObject =
+                    static_cast <CbcSimpleInteger *>(object_[jObject]) ;
+                if (simpleObject->columnNumber() == iColumn)
+                    break;
+            }
+            assert (jObject < numberObjects_ && iObject == jObject);
+#else
+#ifdef CBCMODEL_TIGHTEN_BOUNDS
+            int iColumn = simpleObject->columnNumber();
+#endif
+#endif
+            update.objectNumber_ = iObject;
+            // Care! We must be careful not to update the same variable in parallel threads.
+            addUpdateInformation(update);
+            //#define CBCMODEL_TIGHTEN_BOUNDS
+#ifdef CBCMODEL_TIGHTEN_BOUNDS
+            double cutoff = getCutoff() ;
+            if (feasible && cutoff < 1.0e20) {
+                int way = cbcobj->way();
+                // way is what will be taken next
+                way = -way;
+                double value = cbcobj->value();
+                //const double * lower = solver_->getColLower();
+                //const double * upper = solver_->getColUpper();
+                double objectiveChange = lastObjective - objectiveValue;
+                if (objectiveChange > 1.0e-5) {
+                    CbcIntegerBranchingObject * branch = dynamic_cast <CbcIntegerBranchingObject *>(cbcobj) ;
+                    assert (branch);
+                    if (way < 0) {
+                        double down = value - floor(value);
+                        double changePer = objectiveChange / (down + 1.0e-7);
+                        double distance = (cutoff - objectiveValue) / changePer;
+                        distance += 1.0e-3;
+                        if (distance < 5.0) {
+                            double newLower = ceil(value - distance);
+                            const double * downBounds = branch->downBounds();
+                            if (newLower > downBounds[0]) {
+                                //printf("%d way %d bounds %g %g value %g\n",
+                                //     iColumn,way,lower[iColumn],upper[iColumn],value);
+                                //printf("B Could increase lower bound on %d from %g to %g\n",
+                                //     iColumn,downBounds[0],newLower);
+                                solver_->setColLower(iColumn, newLower);
+                            }
+                        }
+                    } else {
+                        double up = ceil(value) - value;
+                        double changePer = objectiveChange / (up + 1.0e-7);
+                        double distance = (cutoff - objectiveValue) / changePer;
+                        distance += 1.0e-3;
+                        if (distance < 5.0) {
+                            double newUpper = floor(value + distance);
+                            const double * upBounds = branch->upBounds();
+                            if (newUpper < upBounds[1]) {
+                                //printf("%d way %d bounds %g %g value %g\n",
+                                //     iColumn,way,lower[iColumn],upper[iColumn],value);
+                                //printf("B Could decrease upper bound on %d from %g to %g\n",
+                                //     iColumn,upBounds[1],newUpper);
+                                solver_->setColUpper(iColumn, newUpper);
+                            }
+                        }
+                    }
+                }
+            }
+#endif
+        } else {
+            OsiIntegerBranchingObject * obj = dynamic_cast<OsiIntegerBranchingObject *> (bobj);
+            if (obj) {
+                const OsiObject * object = obj->originalObject();
+                // have to compute object number as not saved
+                int iObject;
+                int iColumn = object->columnNumber();
+                for (iObject = 0 ; iObject < numberObjects_ ; iObject++) {
+                    if (object_[iObject]->columnNumber() == iColumn)
+                        break;
+                }
+                assert (iObject < numberObjects_);
+                int branch = obj->firstBranch();
+                if (obj->branchIndex() == 2)
+                    branch = 1 - branch;
+                assert (branch == 0 || branch == 1);
+                double originalValue = node->objectiveValue();
+                double objectiveValue = solver_->getObjValue() * solver_->getObjSense();
+                double changeInObjective = CoinMax(0.0, objectiveValue - originalValue);
+                int iStatus = (feasible) ? 0 : 0;
+                double value = obj->value();
+                double movement;
+                if (branch)
+                    movement = ceil(value) - value;
+                else
+                    movement = value - floor(value);
+                branchingMethod_->chooseMethod()->updateInformation(iObject, branch, changeInObjective,
+                        movement, iStatus);
+            }
+        }
+    }
+
+#ifdef CBC_DEBUG
+    if (feasible) {
+        printf("Obj value %g (%s) %d rows\n", solver_->getObjValue(),
+               (solver_->isProvenOptimal()) ? "proven" : "unproven",
+               solver_->getNumRows()) ;
+    }
+
+    else {
+        printf("Infeasible %d rows\n", solver_->getNumRows()) ;
+    }
+#endif
+    if ((specialOptions_&1) != 0) {
+        /*
+          If the RowCutDebugger said we were compatible with the optimal solution,
+          and now we're suddenly infeasible, we might be confused. Then again, we
+          may have fathomed by bound, heading for a rediscovery of an optimal solution.
+        */
+        if (onOptimalPath && !solver_->isDualObjectiveLimitReached()) {
+            if (!feasible) {
+                solver_->writeMpsNative("infeas.mps", NULL, NULL, 2);
+                solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
+                CoinWarmStartBasis *slack =
+                    dynamic_cast<CoinWarmStartBasis *>(solver_->getEmptyWarmStart()) ;
+                solver_->setWarmStart(slack);
+                delete slack ;
+                solver_->setHintParam(OsiDoReducePrint, false, OsiHintDo, 0) ;
+                solver_->initialSolve();
+            }
+            assert(feasible) ;
+        }
+    }
+
+    if (!feasible) {
+        numberInfeasibleNodes_++;
+# ifdef COIN_HAS_CLP
+        if (clpSolver)
+            clpSolver->setSpecialOptions(saveClpOptions);
+# endif
+        return (false) ;
+    }
+    double change = lastObjective - objectiveValue;
+    if (change > 1.0e-10) {
+        dblParam_[CbcSmallestChange] = CoinMin(dblParam_[CbcSmallestChange], change);
+        dblParam_[CbcSumChange] += change;
+        dblParam_[CbcLargestChange] = CoinMax(dblParam_[CbcLargestChange], change);
+        intParam_[CbcNumberBranches]++;
+    }
+    sumChangeObjective1_ += solver_->getObjValue() * solver_->getObjSense()
+                            - objectiveValue ;
+    if ( maximumSecondsReached() )
+        numberTries = 0; // exit
+    //if ((numberNodes_%100)==0)
+    //printf("XXa sum obj changed by %g\n",sumChangeObjective1_);
+    objectiveValue = solver_->getObjValue() * solver_->getObjSense();
+    // Return at once if numberTries zero
+    if (!numberTries) {
+        cuts = OsiCuts();
+        numberNewCuts_ = 0;
+# ifdef COIN_HAS_CLP
+        if (clpSolver)
+            clpSolver->setSpecialOptions(saveClpOptions);
+# endif
+        setPointers(solver_);
+        return true;
+    }
+    /*
+      Do reduced cost fixing.
+    */
+    int xxxxxx = 0;
+    if (xxxxxx)
+        solver_->resolve();
+    reducedCostFix() ;
+    /*
+      Set up for at most numberTries rounds of cut generation. If numberTries is
+      negative, we'll ignore the minimumDrop_ cutoff and keep generating cuts for
+      the specified number of rounds.
+    */
+    double minimumDrop = minimumDrop_ ;
+    bool allowZeroIterations = false;
+    int maximumBadPasses = 0;
+    if (numberTries < 0) {
+        numberTries = -numberTries ;
+        // minimumDrop *= 1.0e-5 ;
+        // if (numberTries >= -1000000) {
+        //numberTries=100;
+        minimumDrop = -1.0;
+        // }
+        //numberTries=CoinMax(numberTries,100);
+        allowZeroIterations = true;
+    }
+    int saveNumberTries=numberTries;
+    /*
+      Is it time to scan the cuts in order to remove redundant cuts? If so, set
+      up to do it.
+    */
+    int fullScan = 0 ;
+    if ((numberNodes_ % SCANCUTS) == 0 || (specialOptions_&256) != 0) {
+        fullScan = 1 ;
+        if (!numberNodes_ || (specialOptions_&256) != 0)
+            fullScan = 2;
+        specialOptions_ &= ~256; // mark as full scan done
+    }
+
+    double direction = solver_->getObjSense() ;
+    double startObjective = solver_->getObjValue() * direction ;
+
+    currentPassNumber_ = 0 ;
+    // Really primalIntegerTolerance; relates to an illposed problem with various
+    // integer solutions depending on integer tolerance.
+    //double primalTolerance = 1.0e-7 ;
+    // We may need to keep going on
+    bool keepGoing = false;
+    // Say we have not tried one last time
+    int numberLastAttempts = 0;
+    /* Get experimental option as to when to stop adding cuts
+       0 - old style
+       1 - new style
+       2 - new style plus don't break if zero cuts first time
+       3 - as 2 but last drop has to be >0.1*min to say OK
+    */
+    int experimentBreak = (moreSpecialOptions_ >> 11) & 3;
+    // Whether to increase minimum drop
+    bool increaseDrop = (moreSpecialOptions_ & 8192) != 0;
+    for (int i = 0; i < numberCutGenerators_; i++) 
+      generator_[i]->setWhetherInMustCallAgainMode(false);
+    /*
+      Begin cut generation loop. Cuts generated during each iteration are
+      collected in theseCuts. The loop can be divided into four phases:
+       1) Prep: Fix variables using reduced cost. In the first iteration only,
+          consider scanning globalCuts_ and activating any applicable cuts.
+       2) Cut Generation: Call each generator and heuristic registered in the
+          generator_ and heuristic_ arrays. Newly generated global cuts are
+          copied to globalCuts_ at this time.
+       3) Cut Installation and Reoptimisation: Install column and row cuts in
+          the solver. Copy row cuts to cuts (parameter). Reoptimise.
+       4) Cut Purging: takeOffCuts() removes inactive cuts from the solver, and
+          does the necessary bookkeeping in the model.
+    */
+    do {
+        currentPassNumber_++ ;
+        numberTries-- ;
+        if (numberTries < 0 && keepGoing) {
+            // switch off all normal generators (by the generator's opinion of normal)
+            // Intended for situations where the primal problem really isn't complete,
+            // and there are `not normal' cut generators that will augment.
+            for (int i = 0; i < numberCutGenerators_; i++) {
+                if (!generator_[i]->mustCallAgain())
+                    generator_[i]->setSwitchedOff(true);
+		else
+		  generator_[i]->setWhetherInMustCallAgainMode(true);
+            }
+        }
+        keepGoing = false;
+        OsiCuts theseCuts ;
+        /*
+          Scan previously generated global column and row cuts to see if any are
+          useful.
+        */
+        int numberViolated = 0;
+        if ((currentPassNumber_ == 1 ||!numberNodes_) && howOftenGlobalScan_ > 0 &&
+                (numberNodes_ % howOftenGlobalScan_) == 0 &&
+                (doCutsNow(1) || true)) {
+	    // global column cuts now done in node at top of tree
+	    int numberCuts = numberCutGenerators_ ? globalCuts_.sizeRowCuts() : 0;
+	    if (numberCuts) {
+	      // possibly extend whichGenerator
+	      resizeWhichGenerator(numberViolated, numberViolated + numberCuts);
+	      // only add new cuts up to 10% of current elements
+	      int numberElements = solver_->getNumElements();
+	      int numberColumns = solver_->getNumCols();
+	      int maximumAdd = CoinMax(numberElements/10,2*numberColumns)+100;
+	      double * violations = new double[numberCuts];
+	      int * which = new int[numberCuts];
+	      int numberPossible=0;
+	      for (int i = 0; i < numberCuts; i++) {
+                OsiRowCut * thisCut = globalCuts_.rowCutPtr(i) ;
+                double violation = thisCut->violated(cbcColSolution_);
+		if(thisCut->effectiveness() == COIN_DBL_MAX) {
+		  // see if already there
+		  int j;
+		  for (j = 0; j < currentNumberCuts_; j++) {
+		    if (addedCuts_[j]==thisCut)
+		      break;
+		  }
+		  if (j==currentNumberCuts_)
+		    violation = COIN_DBL_MAX;
+		  //else
+		  //printf("already done??\n");
+		}
+		if (violation > 0.005) {
+		  violations[numberPossible]=-violation;
+		  which[numberPossible++]=i;
+		}
+	      }
+	      CoinSort_2(violations,violations+numberPossible,which);
+	      for (int i = 0; i < numberPossible; i++) {
+		int k=which[i];
+		OsiRowCut * thisCut = globalCuts_.rowCutPtr(k) ;
+		assert (thisCut->violated(cbcColSolution_) > 0.005/*primalTolerance*/ ||
+			thisCut->effectiveness() == COIN_DBL_MAX);
+#define CHECK_DEBUGGER
+#ifdef CHECK_DEBUGGER
+		if ((specialOptions_&1) != 0 ) {
+		  CoinAssert (!solver_->getRowCutDebuggerAlways()->invalidCut(*thisCut));
+		}
+#endif
+#if 0 //ndef NDEBUG
+		printf("Global cut added - violation %g\n",
+		       thisCut->violated(cbcColSolution_)) ;
+#endif
+		whichGenerator_[numberViolated++] = -1;
+#ifndef GLOBAL_CUTS_JUST_POINTERS
+		theseCuts.insert(*thisCut) ;
+#else
+		theseCuts.insert(thisCut) ;
+#endif
+		if (violations[i]!=-COIN_DBL_MAX)
+		  maximumAdd -= thisCut->row().getNumElements();
+		if (maximumAdd<0)
+		  break;
+	      }
+	      delete [] which;
+	      delete [] violations;
+	      numberGlobalViolations_ += numberViolated;
+	    }
+        }
+        /*
+          Generate new cuts (global and/or local) and/or apply heuristics.  If
+          CglProbing is used, then it should be first as it can fix continuous
+          variables.
+
+          At present, CglProbing is the only case where generateCuts will return
+          true. generateCuts actually modifies variable bounds in the solver when
+          CglProbing indicates that it can fix a variable. Reoptimisation is required
+          to take full advantage.
+
+          The need to resolve here should only happen after a heuristic solution.
+        optimalBasisIsAvailable resolves to basisIsAvailable, which seems to be part
+        of the old OsiSimplex API. Doc'n says `Returns true if a basis is available
+        and the problem is optimal. Should be used to see if the BinvARow type
+        operations are possible and meaningful.' Which means any solver other the clp
+        is probably doing a lot of unnecessary resolves right here.
+          (Note default OSI implementation of optimalBasisIsAvailable always returns
+          false.)
+        */
+        if (solverCharacteristics_->warmStart() &&
+                !solver_->optimalBasisIsAvailable()) {
+            //printf("XXXXYY no opt basis\n");
+#ifdef JJF_ZERO//def COIN_HAS_CLP
+            //OsiClpSolverInterface * clpSolver
+            //= dynamic_cast<OsiClpSolverInterface *> (solver_);
+            int save = 0;
+            if (clpSolver) {
+                save = clpSolver->specialOptions();
+                clpSolver->setSpecialOptions(save | 2048/*4096*/); // Bonmin <something>
+            }
+#endif
+            resolve(node ? node->nodeInfo() : NULL, 3);
+#ifdef JJF_ZERO//def COIN_HAS_CLP
+            if (clpSolver)
+                clpSolver->setSpecialOptions(save);
+#ifdef CLP_INVESTIGATE
+            if (clpSolver->getModelPtr()->numberIterations())
+                printf("ITS %d pass %d\n",
+                       clpSolver->getModelPtr()->numberIterations(),
+                       currentPassNumber_);
+#endif
+#endif
+        }
+        if (nextRowCut_) {
+            // branch was a cut - add it
+            theseCuts.insert(*nextRowCut_);
+            if (handler_->logLevel() > 1)
+                nextRowCut_->print();
+            const OsiRowCut * cut = nextRowCut_;
+            double lb = cut->lb();
+            double ub = cut->ub();
+            int n = cut->row().getNumElements();
+            const int * column = cut->row().getIndices();
+            const double * element = cut->row().getElements();
+            double sum = 0.0;
+            for (int i = 0; i < n; i++) {
+                int iColumn = column[i];
+                double value = element[i];
+                //if (cbcColSolution_[iColumn]>1.0e-7)
+                //printf("value of %d is %g\n",iColumn,cbcColSolution_[iColumn]);
+                sum += value * cbcColSolution_[iColumn];
+            }
+            delete nextRowCut_;
+            nextRowCut_ = NULL;
+            if (handler_->logLevel() > 1)
+                printf("applying branch cut, sum is %g, bounds %g %g\n", sum, lb, ub);
+            // possibly extend whichGenerator
+            resizeWhichGenerator(numberViolated, numberViolated + 1);
+            // set whichgenerator (also serves as marker to say don't delete0
+            whichGenerator_[numberViolated++] = -2;
+        }
+
+        // reset probing info
+        //if (probingInfo_)
+        //probingInfo_->initializeFixing();
+        int i;
+        // If necessary make cut generators work harder
+        bool strongCuts =  (!node && cut_obj[CUT_HISTORY-1] != -COIN_DBL_MAX &&
+                            fabs(cut_obj[CUT_HISTORY-1] - cut_obj[CUT_HISTORY-2]) < 1.0e-7 +
+                            1.0e-6 * fabs(cut_obj[CUT_HISTORY-1]));
+        for (i = 0; i < numberCutGenerators_; i++)
+            generator_[i]->setIneffectualCuts(strongCuts);
+        // Print details
+        if (!node) {
+            handler_->message(CBC_ROOT_DETAIL, messages_)
+            << currentPassNumber_
+            << solver_->getNumRows()
+            << solver_->getNumRows() - numberRowsAtContinuous_
+            << solver_->getObjValue()
+            << CoinMessageEol ;
+        }
+	//Is Necessary for Bonmin? Always keepGoing if cuts have been generated in last iteration (taken from similar code in Cbc-2.4)
+        if (solverCharacteristics_->solutionAddsCuts()&&numberViolated) { 
+          for (i = 0;i<numberCutGenerators_;i++) { 
+            if (generator_[i]->mustCallAgain()) { 
+              keepGoing=true; // say must go round 
+              break; 
+            } 
+          } 
+        } 
+        if(!keepGoing){
+        // Status for single pass of cut generation
+        int status = 0;
+        /*
+          threadMode with bit 2^1 set indicates we should use threads for root cut
+          generation.
+        */
+        if ((threadMode_&2) == 0 || numberNodes_) {
+            status = serialCuts(theseCuts, node, slackCuts, lastNumberCuts);
+        } else {
+            // do cuts independently
+#ifdef CBC_THREAD
+            status = parallelCuts(master, theseCuts, node, slackCuts, lastNumberCuts);
+#endif
+        }
+        // Do we need feasible and violated?
+        feasible = (status >= 0);
+        if (status == 1)
+            keepGoing = true;
+        else if (status == 2)
+            numberTries = 0;
+        if (!feasible)
+            violated = -2;
+        }
+        //if (!feasible)
+        //break;
+        /*
+          End of the loop to exercise each generator - try heuristics
+          - unless at root node and first pass
+        */
+        if ((numberNodes_ || currentPassNumber_ != 1) && true) {
+            double * newSolution = new double [numberColumns] ;
+            double heuristicValue = getCutoff() ;
+            int found = -1; // no solution found
+            int whereFrom = numberNodes_ ? 4 : 1;
+            for (i = 0; i < numberHeuristics_; i++) {
+                // skip if can't run here
+                if (!heuristic_[i]->shouldHeurRun(whereFrom))
+                    continue;
+                // see if heuristic will do anything
+                double saveValue = heuristicValue ;
+                int ifSol =
+                    heuristic_[i]->solution(heuristicValue,
+                                            newSolution);
+                //theseCuts) ;
+                if (ifSol > 0) {
+                    // better solution found
+                    heuristic_[i]->incrementNumberSolutionsFound();
+                    found = i ;
+                    incrementUsed(newSolution);
+                    lastHeuristic_ = heuristic_[found];
+#ifdef CLP_INVESTIGATE
+                    printf("HEUR %s where %d A\n",
+                           lastHeuristic_->heuristicName(), whereFrom);
+#endif
+                    // CBC_ROUNDING is symbolic; just says found by heuristic
+                    setBestSolution(CBC_ROUNDING, heuristicValue, newSolution) ;
+                    whereFrom |= 8; // say solution found
+                } else if (ifSol < 0) {
+                    heuristicValue = saveValue ;
+                }
+            }
+            /*
+              Did any of the heuristics turn up a new solution? Record it before we free
+              the vector.
+            */
+            if (found >= 0) {
+                phase_ = 4;
+                CbcTreeLocal * tree
+                = dynamic_cast<CbcTreeLocal *> (tree_);
+                if (tree)
+                    tree->passInSolution(bestSolution_, heuristicValue);
+            }
+            delete [] newSolution ;
+        }
+
+#ifdef JJF_ZERO
+        // switch on to get all cuts printed
+        theseCuts.printCuts() ;
+#endif
+        int numberColumnCuts = theseCuts.sizeColCuts() ;
+        int numberRowCuts = theseCuts.sizeRowCuts() ;
+        if (violated >= 0)
+            violated = numberRowCuts + numberColumnCuts ;
+        /*
+          Apply column cuts (aka bound tightening). This may be partially redundant
+          for column cuts returned by CglProbing, as generateCuts installs bounds
+          from CglProbing when it determines it can fix a variable.
+
+          TODO: Looks like the use of violated has evolved. The value set above is
+        	completely ignored. All that's left is violated == -1 indicates some
+        	cut is violated, violated == -2 indicates infeasibility. Only
+        	infeasibility warrants exceptional action.
+
+          TODO: Strikes me that this code will fail to detect infeasibility, because
+        	the breaks escape the inner loops but the outer loop keeps going.
+        	Infeasibility in an early cut will be overwritten if a later cut is
+        	merely violated.
+        */
+        if (numberColumnCuts) {
+
+#ifdef CBC_DEBUG
+            double * oldLower = new double [numberColumns] ;
+            double * oldUpper = new double [numberColumns] ;
+            memcpy(oldLower, cbcColLower_, numberColumns*sizeof(double)) ;
+            memcpy(oldUpper, cbcColUpper_, numberColumns*sizeof(double)) ;
+#endif
+
+            double integerTolerance = getDblParam(CbcIntegerTolerance) ;
+            for (int i = 0; i < numberColumnCuts; i++) {
+                const OsiColCut * thisCut = theseCuts.colCutPtr(i) ;
+                const CoinPackedVector & lbs = thisCut->lbs() ;
+                const CoinPackedVector & ubs = thisCut->ubs() ;
+                int j ;
+                int n ;
+                const int * which ;
+                const double * values ;
+                n = lbs.getNumElements() ;
+                which = lbs.getIndices() ;
+                values = lbs.getElements() ;
+                for (j = 0; j < n; j++) {
+                    int iColumn = which[j] ;
+                    double value = cbcColSolution_[iColumn] ;
+#if CBC_DEBUG>1
+                    printf("%d %g %g %g %g\n", iColumn, oldLower[iColumn],
+                           cbcColSolution_[iColumn], oldUpper[iColumn], values[j]) ;
+#endif
+                    solver_->setColLower(iColumn, values[j]) ;
+                    if (value < values[j] - integerTolerance)
+                        violated = -1 ;
+                    if (values[j] > cbcColUpper_[iColumn] + integerTolerance) {
+                        // infeasible
+                        violated = -2 ;
+                        break ;
+                    }
+                }
+                n = ubs.getNumElements() ;
+                which = ubs.getIndices() ;
+                values = ubs.getElements() ;
+                for (j = 0; j < n; j++) {
+                    int iColumn = which[j] ;
+                    double value = cbcColSolution_[iColumn] ;
+#if CBC_DEBUG>1
+                    printf("%d %g %g %g %g\n", iColumn, oldLower[iColumn],
+                           cbcColSolution_[iColumn], oldUpper[iColumn], values[j]) ;
+#endif
+                    solver_->setColUpper(iColumn, values[j]) ;
+                    if (value > values[j] + integerTolerance)
+                        violated = -1 ;
+                    if (values[j] < cbcColLower_[iColumn] - integerTolerance) {
+                        // infeasible
+                        violated = -2 ;
+                        break ;
+                    }
+                }
+            }
+#ifdef CBC_DEBUG
+            delete [] oldLower ;
+            delete [] oldUpper ;
+#endif
+        }
+        /*
+          End installation of column cuts. The break here escapes the numberTries
+          loop.
+        */
+        if (violated == -2 || !feasible) {
+            // infeasible
+            feasible = false ;
+            violated = -2;
+            if (!numberNodes_)
+                messageHandler()->message(CBC_INFEAS,
+                                          messages())
+                << CoinMessageEol ;
+            break ;
+        }
+        /*
+          Now apply the row (constraint) cuts. This is a bit more work because we need
+          to obtain and augment the current basis.
+
+          TODO: Why do this work, if there are no row cuts? The current basis will do
+        	just fine.
+        */
+        int numberRowsNow = solver_->getNumRows() ;
+#ifndef NDEBUG
+        assert(numberRowsNow == numberRowsAtStart + lastNumberCuts) ;
+#else
+        // ? maybe clue to threaded problems
+        if (numberRowsNow != numberRowsAtStart + lastNumberCuts) {
+            fprintf(stderr, "*** threaded error - numberRowsNow(%d) != numberRowsAtStart(%d)+lastNumberCuts(%d)\n",
+                    numberRowsNow, numberRowsAtStart, lastNumberCuts);
+            fprintf(stdout, "*** threaded error - numberRowsNow(%d) != numberRowsAtStart(%d)+lastNumberCuts(%d)\n",
+                    numberRowsNow, numberRowsAtStart, lastNumberCuts);
+            abort();
+        }
+#endif
+        int numberToAdd = theseCuts.sizeRowCuts() ;
+        numberNewCuts_ = lastNumberCuts + numberToAdd ;
+        /*
+          Now actually add the row cuts and reoptimise.
+
+          Install the cuts in the solver using applyRowCuts and
+          augment the basis with the corresponding slack. We also add each row cut to
+          the set of row cuts (cuts.insert()) supplied as a parameter. The new basis
+          must be set with setWarmStart().
+
+          TODO: Seems to me the original code could allocate addCuts with size 0, if
+        	numberRowCuts was 0 and numberColumnCuts was nonzero. That might
+        	explain the memory fault noted in the comment by AJK.  Unfortunately,
+        	just commenting out the delete[] results in massive memory leaks. Try
+        	a revision to separate the row cut case. Why do we need addCuts at
+        	all? A typing issue, apparently: OsiCut vs. OsiRowCut.
+
+          TODO: It looks to me as if numberToAdd and numberRowCuts are identical at
+        	this point. Confirm & get rid of one of them.
+
+          TODO: Any reason why the three loops can't be consolidated?
+        */
+        const OsiRowCut ** addCuts = NULL;
+        if (numberRowCuts > 0 || numberColumnCuts > 0) {
+            if (numberToAdd > 0) {
+                int i ;
+                // Faster to add all at once
+                addCuts = new const OsiRowCut * [numberToAdd] ;
+                for (i = 0 ; i < numberToAdd ; i++) {
+                    addCuts[i] = &theseCuts.rowCut(i) ;
+                }
+                if ((specialOptions_&262144) != 0 && !parentModel_) {
+                    //save
+                    for (i = 0 ; i < numberToAdd ; i++)
+                        storedRowCuts_->addCut(*addCuts[i]);
+                }
+                solver_->applyRowCuts(numberToAdd, addCuts) ;
+                CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+                assert(basis != NULL); // make sure not volume
+                /* dylp bug
+
+                  Consistent size used by OsiDylp as sanity check. Implicit resize seen
+                  as an error. Hence this call to resize is necessary.
+                */
+                basis->resize(numberRowsAtStart + numberNewCuts_, numberColumns) ;
+                for (i = 0 ; i < numberToAdd ; i++) {
+                    basis->setArtifStatus(numberRowsNow + i,
+                                          CoinWarmStartBasis::basic) ;
+                }
+                if (solver_->setWarmStart(basis) == false) {
+                    throw CoinError("Fail setWarmStart() after cut installation.",
+                                    "solveWithCuts", "CbcModel") ;
+                }
+                delete basis;
+            }
+            //solver_->setHintParam(OsiDoDualInResolve,false,OsiHintTry);
+            feasible = ( resolve(node ? node->nodeInfo() : NULL, 2) != 0) ;
+            //solver_->setHintParam(OsiDoDualInResolve,true,OsiHintTry);
+            if ( maximumSecondsReached() ) {
+                numberTries = -1000; // exit
+		feasible = false;
+                break;
+            }
+#     ifdef CBC_DEBUG
+            printf("Obj value after cuts %g %d rows\n", solver_->getObjValue(),
+                   solver_->getNumRows()) ;
+            if (onOptimalPath && !solver_->isDualObjectiveLimitReached())
+                assert(feasible) ;
+#     endif
+        }
+        /*
+          No cuts. Cut short the cut generation (numberTries) loop.
+        */
+        else if (numberLastAttempts > 2 || experimentBreak < 2) {
+            numberTries = 0 ;
+        }
+        /*
+          If the problem is still feasible, first, call takeOffCuts() to remove cuts
+          that are now slack. takeOffCuts() will call the solver to reoptimise if
+          that's needed to restore a valid solution.
+
+          Next, see if we should quit due to diminishing returns:
+            * we've tried three rounds of cut generation and we're getting
+              insufficient improvement in the objective; or
+            * we generated no cuts; or
+            * the solver declared optimality with 0 iterations after we added the
+              cuts generated in this round.
+          If we decide to keep going, prep for the next iteration.
+
+          It just seems more safe to tell takeOffCuts() to call resolve(), even if
+          we're not continuing cut generation. Otherwise code executed between here
+          and final disposition of the node will need to be careful not to access the
+          lp solution. It can happen that we lose feasibility in takeOffCuts ---
+          numerical jitters when the cutoff bound is epsilon less than the current
+          best, and we're evaluating an alternative optimum.
+
+          TODO: After successive rounds of code motion, there seems no need to
+        	distinguish between the two checks for aborting the cut generation
+        	loop. Confirm and clean up.
+        */
+        if (feasible) {
+            int cutIterations = solver_->getIterationCount() ;
+            if (numberOldActiveCuts_ + numberNewCuts_
+                    && (numberNewCuts_ || doCutsNow(1))
+               ) {
+                OsiCuts * saveCuts = node ? NULL : &slackCuts;
+                int nDel = takeOffCuts(cuts, resolveAfterTakeOffCuts_, saveCuts, numberToAdd, addCuts) ;
+                if (nDel)
+                    lastNumberCuts2_ = 0;
+                if (solver_->isDualObjectiveLimitReached() && resolveAfterTakeOffCuts_) {
+                    feasible = false ;
+#	ifdef CBC_DEBUG
+                    double z = solver_->getObjValue() ;
+                    double cut = getCutoff() ;
+                    printf("Lost feasibility by %g in takeOffCuts; z = %g, cutoff = %g\n",
+                           z - cut, z, cut) ;
+#	endif
+                }
+            }
+            delete [] addCuts ;
+            if (feasible) {
+                numberRowsAtStart = numberOldActiveCuts_ + numberRowsAtContinuous_ ;
+                lastNumberCuts = numberNewCuts_ ;
+                double thisObj = direction * solver_->getObjValue();
+                bool badObj = (allowZeroIterations) ? thisObj < cut_obj[0] + minimumDrop
+                              : thisObj < cut_obj[CUT_HISTORY-1] + minimumDrop;
+#ifdef JJF_ZERO // probably not a good idea
+                if (!badObj)
+                    numberLastAttempts = CoinMax(0, numberLastAttempts - 1);
+#endif
+                // Compute maximum number of bad passes
+                if (minimumDrop > 0.0) {
+                    if (increaseDrop) {
+                        // slowly increase minimumDrop; breakpoints are rule-of-thumb
+                        if (currentPassNumber_ == 13)
+                            minimumDrop = CoinMax(1.5 * minimumDrop, 1.0e-5 * fabs(thisObj));
+                        else if (currentPassNumber_ > 20 && (currentPassNumber_ % 5) == 0)
+                            minimumDrop = CoinMax(1.1 * minimumDrop, 1.0e-5 * fabs(thisObj));
+                        else if (currentPassNumber_ > 50)
+                            minimumDrop = CoinMax(1.1 * minimumDrop, 1.0e-5 * fabs(thisObj));
+                    }
+                    int nBadPasses = 0;
+                    // The standard way of determining escape
+                    if (!experimentBreak) {
+                        double test = 0.01 * minimumDrop;
+                        double goodDrop = COIN_DBL_MAX;
+                        for (int j = CUT_HISTORY - 1; j >= 0; j--) {
+                            if (thisObj - cut_obj[j] < test) {
+                                nBadPasses++;
+                            } else {
+                                goodDrop = (thisObj - cut_obj[j]) / static_cast<double>(nBadPasses + 1);
+                                break;
+                            }
+                        }
+                        maximumBadPasses = CoinMax(maximumBadPasses, nBadPasses);
+                        if (nBadPasses < maximumBadPasses &&
+                                goodDrop > minimumDrop)
+                            badObj = false; // carry on
+                    } else {
+                        // Experimental escape calculations
+                        //if (currentPassNumber_==13||currentPassNumber_>50)
+                        //minimumDrop = CoinMax(1.5*minimumDrop,1.0e-5*fabs(thisObj));
+                        double test = 0.1 * minimumDrop;
+                        double goodDrop = (thisObj - cut_obj[0]) / static_cast<double>(CUT_HISTORY);
+                        double objValue = thisObj;
+                        for (int j = CUT_HISTORY - 1; j >= 0; j--) {
+                            if (objValue - cut_obj[j] < test) {
+                                nBadPasses++;
+                                objValue = cut_obj[j];
+                            } else {
+                                break;
+                            }
+                        }
+#ifdef CLP_INVESTIGATE2
+                        if (!parentModel_ && !numberNodes_)
+                            printf("badObj %s nBad %d maxBad %d goodDrop %g minDrop %g thisDrop %g obj %g\n",
+                                   badObj ? "true" : "false",
+                                   nBadPasses, maximumBadPasses, goodDrop, minimumDrop,
+                                   thisObj - cut_obj[CUT_HISTORY-1],
+                                   solver_->getObjValue());
+#endif
+                        maximumBadPasses = CoinMax(maximumBadPasses, nBadPasses);
+                        if (nBadPasses < 2 || goodDrop > 2.0*minimumDrop) {
+                            if (experimentBreak <= 2 || goodDrop > 0.1*minimumDrop)
+                                badObj = false; // carry on
+                        }
+                        if (experimentBreak > 1 && goodDrop < minimumDrop)
+                            numberLastAttempts++;
+                    }
+                }
+                // magic numbers, they seemed reasonable; there's a possibility here of going more than
+                // nominal number of passes if we're doing really well.
+                if (numberTries == 1 && currentDepth_ < 12 && currentPassNumber_ < 10) {
+                    double drop[12] = {1.0, 2.0, 3.0, 10.0, 10.0, 10.0, 10.0, 20.0, 100.0, 100.0, 1000.0, 1000.0};
+                    if (thisObj - lastObjective > drop[currentDepth_]*minimumDrop) {
+                        numberTries++;
+#ifdef CLP_INVESTIGATE
+                        //printf("drop %g %g %d\n",thisObj,lastObjective,currentPassNumber_);
+#endif
+                    }
+                }
+                for (int j = 0; j < CUT_HISTORY - 1; j++)
+                    cut_obj[j] = cut_obj[j+1];
+                cut_obj[CUT_HISTORY-1] = thisObj;
+                bool allowEarlyTermination = currentPassNumber_ >= 10;
+                if (currentDepth_ > 10 || (currentDepth_ > 5 && numberColumns > 200))
+                    allowEarlyTermination = true;
+                //if (badObj && (currentPassNumber_ >= 10 || (currentDepth_>10))
+                if (badObj && allowEarlyTermination
+                        //&&(currentPassNumber_>=10||lastObjective>firstObjective)
+                        && !keepGoing) {
+                    numberTries = 0 ;
+                }
+                if (numberRowCuts + numberColumnCuts == 0 ||
+                        (cutIterations == 0 && !allowZeroIterations) ) {
+                    // maybe give it one more try
+                    if (numberLastAttempts > 2 || currentDepth_ || experimentBreak < 2)
+                        numberTries=0 ;
+                    else
+                        numberLastAttempts++;
+                }
+                if (numberTries > 0) {
+                    reducedCostFix() ;
+                    lastObjective = direction * solver_->getObjValue() ;
+                }
+            }
+        } else {
+            // not feasible
+            delete [] addCuts ;
+        }
+        /*
+          We've lost feasibility --- this node won't be referencing the cuts we've
+          been collecting, so decrement the reference counts.
+        */
+        if (!feasible) {
+            int i ;
+            if (currentNumberCuts_) {
+                lockThread();
+                for (i = 0; i < currentNumberCuts_; i++) {
+                    // take off node
+                    if (addedCuts_[i]) {
+                        if (!addedCuts_[i]->decrement())
+                            delete addedCuts_[i] ;
+                        addedCuts_[i] = NULL ;
+                    }
+                }
+                unlockThread();
+            }
+            numberTries = 0 ;
+	    keepGoing=false;
+        }
+	if (numberTries ==0 && feasible && !keepGoing && !parentModel_ && !numberNodes_) {
+	  for (int i = 0; i < numberCutGenerators_; i++) {
+	    if (generator_[i]->whetherCallAtEnd()
+		&&!generator_[i]->whetherInMustCallAgainMode()) {
+	      // give it some goes and switch off
+	      numberTries=(saveNumberTries+4)/5;
+	      generator_[i]->setWhetherCallAtEnd(false);
+            }
+	  }
+	}
+    } while (numberTries > 0 || keepGoing) ;
+    /*
+      End cut generation loop.
+    */
+    {
+        // switch on
+        for (int i = 0; i < numberCutGenerators_; i++)
+            generator_[i]->setSwitchedOff(false);
+    }
+    //check feasibility.
+    //If solution seems to be integer feasible calling setBestSolution
+    //will eventually add extra global cuts which we need to install at
+    //the nodes
+
+
+    if (feasible && solverCharacteristics_->solutionAddsCuts()) { //check integer feasibility
+        bool integerFeasible = true;
+        const double * save = testSolution_;
+        testSolution_ = solver_->getColSolution();
+        // point to useful information
+        OsiBranchingInformation usefulInfo = usefulInformation();
+        for (int i = 0; i < numberObjects_ && integerFeasible; i++) {
+            int preferredWay;
+            double infeasibility = object_[i]->infeasibility(&usefulInfo, preferredWay);
+            if (infeasibility)
+                integerFeasible = false;
+        }
+        testSolution_ = save;
+        // Consider the possibility that some alternatives here only make sense in context
+        // of bonmin.
+        if (integerFeasible) { //update
+            double objValue = solver_->getObjValue();
+            int numberGlobalBefore = globalCuts_.sizeRowCuts();
+            // SOLUTION2 so won't up cutoff or print message
+            setBestSolution(CBC_SOLUTION2, objValue,
+                            solver_->getColSolution(), 0);
+            int numberGlobalAfter = globalCuts_.sizeRowCuts();
+            int numberToAdd = numberGlobalAfter - numberGlobalBefore;
+            if (numberToAdd > 0)
+                //We have added some cuts say they are tight at that node
+                //Basis and lp should already have been updated
+            {
+                feasible = (solver_->isProvenOptimal() &&
+                            !solver_->isDualObjectiveLimitReached()) ;
+                if (feasible) {
+                    int numberCuts = numberNewCuts_ = cuts.sizeRowCuts();
+                    // possibly extend whichGenerator
+                    resizeWhichGenerator(numberCuts, numberToAdd + numberCuts);
+
+                    for (int i = numberGlobalBefore ; i < numberGlobalAfter ; i++) {
+                        whichGenerator_[numberNewCuts_++] = -1;
+#ifndef GLOBAL_CUTS_JUST_POINTERS
+                        cuts.insert(*globalCuts_.rowCutPtr(i)) ;
+#else
+                        OsiRowCut * rowCutPointer = globalCuts_.rowCutPtr(i);
+                        cuts.insert(rowCutPointer) ;
+#endif
+                    }
+                    numberNewCuts_ = lastNumberCuts + numberToAdd;
+                    //now take off the cuts which are not tight anymore
+                    takeOffCuts(cuts, resolveAfterTakeOffCuts_, NULL) ;
+                    if (solver_->isDualObjectiveLimitReached() && resolveAfterTakeOffCuts_) {
+                        feasible = false ;
+                    }
+                }
+                if (!feasible) { //node will be fathomed
+		    lockThread();
+                    for (int i = 0; i < currentNumberCuts_; i++) {
+                        // take off node
+                        if (addedCuts_[i]) {
+                            if (!addedCuts_[i]->decrement())
+                                delete addedCuts_[i] ;
+                            addedCuts_[i] = NULL ;
+                        }
+                    }
+		    unlockThread();
+                }
+            }
+        }
+    }
+    /*
+    End of code block to check for a solution, when cuts may be added as a result
+    of a feasible solution.
+
+      Reduced cost fix at end. Must also check feasible, in case we've popped out
+      because a generator indicated we're infeasible.
+    */
+    if (feasible && solver_->isProvenOptimal())
+        reducedCostFix() ;
+    // If at root node do heuristics
+    if (!numberNodes_ && !maximumSecondsReached()) {
+        // First see if any cuts are slack
+        int numberRows = solver_->getNumRows();
+        int numberAdded = numberRows - numberRowsAtContinuous_;
+        if (numberAdded) {
+            CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+            assert(basis != NULL);
+            int * added = new int[numberAdded];
+            int nDelete = 0;
+            for (int j = numberRowsAtContinuous_; j < numberRows; j++) {
+                if (basis->getArtifStatus(j) == CoinWarmStartBasis::basic) {
+                    //printf("%d slack!\n",j);
+                    added[nDelete++] = j;
+                }
+            }
+            if (nDelete) {
+                solver_->deleteRows(nDelete, added);
+            }
+            delete [] added;
+            delete basis ;
+        }
+        // mark so heuristics can tell
+        int savePass = currentPassNumber_;
+        currentPassNumber_ = 999999;
+        double * newSolution = new double [numberColumns] ;
+        double heuristicValue = getCutoff() ;
+        int found = -1; // no solution found
+        if (feasible) {
+            int whereFrom = node ? 3 : 2;
+            for (int i = 0; i < numberHeuristics_; i++) {
+                // skip if can't run here
+                if (!heuristic_[i]->shouldHeurRun(whereFrom))
+                    continue;
+                // see if heuristic will do anything
+                double saveValue = heuristicValue ;
+                int ifSol = heuristic_[i]->solution(heuristicValue,
+                                                    newSolution);
+                if (ifSol > 0) {
+                    // better solution found
+                    heuristic_[i]->incrementNumberSolutionsFound();
+                    found = i ;
+                    incrementUsed(newSolution);
+                    lastHeuristic_ = heuristic_[found];
+#ifdef CLP_INVESTIGATE
+                    printf("HEUR %s where %d B\n",
+                           lastHeuristic_->heuristicName(), whereFrom);
+#endif
+                    setBestSolution(CBC_ROUNDING, heuristicValue, newSolution) ;
+                    whereFrom |= 8; // say solution found
+                } else {
+                    heuristicValue = saveValue ;
+                }
+            }
+        }
+        currentPassNumber_ = savePass;
+        if (found >= 0) {
+            phase_ = 4;
+        }
+        delete [] newSolution ;
+    }
+    // Up change due to cuts
+    if (feasible)
+        sumChangeObjective2_ += solver_->getObjValue() * solver_->getObjSense()
+                                - objectiveValue ;
+    //if ((numberNodes_%100)==0)
+    //printf("XXb sum obj changed by %g\n",sumChangeObjective2_);
+    /*
+      End of cut generation loop.
+
+      Now, consider if we want to disable or adjust the frequency of use for any
+      of the cut generators. If the client specified a positive number for
+      howOften, it will never change. If the original value was negative, it'll
+      be converted to 1000000+|howOften|, and this value will be adjusted each
+      time fullScan is true. Actual cut generation is performed every
+      howOften%1000000 nodes; the 1000000 offset is just a convenient way to
+      specify that the frequency is adjustable.
+
+      During cut generation, we recorded the number of cuts produced by each
+      generator for this node. For all cuts, whichGenerator records the generator
+      that produced a cut.
+
+      TODO: All this should probably be hidden in a method of the CbcCutGenerator
+      class.
+    lh:
+    TODO: Can the loop that scans over whichGenerator to accumulate per
+    generator counts be replaced by values in countRowCuts and
+    countColumnCuts?
+
+    << I think the answer is yes, but not the other way 'round. Row and
+       column cuts are block interleaved in whichGenerator. >>
+
+    The root is automatically a full scan interval. At the root, decide if
+    we're going to do cuts in the tree, and whether we should keep the cuts we
+    have.
+
+    Codes for willBeCutsInTree:
+    -1: no cuts in tree and currently active cuts seem ineffective; delete
+    them
+     0: no cuts in tree but currently active cuts seem effective; make them
+    into architecturals (faster than treating them as cuts)
+     1: cuts will be generated in the tree; currently active cuts remain as
+    cuts
+    -lh
+    */
+#ifdef NODE_LOG
+    int fatherNum = (node == NULL) ? -1 : node->nodeNumber();
+    double value =  (node == NULL) ? -1 : node->branchingObject()->value();
+    string bigOne = (solver_->getIterationCount() > 30) ? "*******" : "";
+    string way = (node == NULL) ? "" : (node->branchingObject()->way()) == 1 ? "Down" : "Up";
+    std::cout << "Node " << numberNodes_ << ", father " << fatherNum << ", #iterations " << solver_->getIterationCount() << ", sol value : " << solver_->getObjValue() << std::endl;
+#endif
+    if (fullScan && numberCutGenerators_) {
+        /* If cuts just at root node then it will probably be faster to
+           update matrix and leave all in */
+        int willBeCutsInTree = 0;
+        double thisObjective = solver_->getObjValue() * direction ;
+        // get sizes
+        int numberRowsAdded = solver_->getNumRows() - numberRowsAtStart;
+        CoinBigIndex numberElementsAdded =  solver_->getNumElements() - numberElementsAtStart ;
+        double densityOld = static_cast<double> (numberElementsAtStart) / static_cast<double> (numberRowsAtStart);
+        double densityNew = numberRowsAdded ? (static_cast<double> (numberElementsAdded)) / static_cast<double> (numberRowsAdded)
+                            : 0.0;
+        /*
+          If we're at the root, and we added cuts, and the cuts haven't changed the
+          objective, and the cuts resulted in a significant increase (> 20%) in nonzero
+          coefficients, do no cuts in the tree and ditch the current cuts. They're not
+          cost-effective.
+        */
+        if (!numberNodes_) {
+	  if (!parentModel_) {
+	    //printf("%d global cuts\n",globalCuts_.sizeRowCuts()) ;
+	    if ((specialOptions_&1) != 0) {
+	      //specialOptions_ &= ~1;
+	      int numberCuts = globalCuts_.sizeRowCuts();
+	      const OsiRowCutDebugger *debugger = 
+		continuousSolver_->getRowCutDebugger() ;
+	      if (debugger) {
+		for (int i = 0; i < numberCuts; i++) {
+		  OsiRowCut * cut = globalCuts_.rowCutPtr(i) ;
+		  if (debugger->invalidCut(*cut)) {
+		    continuousSolver_->applyRowCuts(1,cut);
+		    continuousSolver_->writeMps("bad");
+		    printf("BAD cut\n");
+		  }
+		  //CoinAssert (!debugger->invalidCut(*cut));
+		}
+	      }
+	    }
+	  }
+	  //solver_->writeMps("second");
+            if (numberRowsAdded)
+                handler_->message(CBC_CUTS_STATS, messages_)
+                << numberRowsAdded
+                << densityNew
+                << CoinMessageEol ;
+            if (thisObjective - startObjective < 1.0e-5 && numberElementsAdded > 0.2*numberElementsAtStart)
+                willBeCutsInTree = -1;
+            int whenC = whenCuts_;
+            if (whenC == 999999 || whenC == 999998) {
+                int size = continuousSolver_->getNumRows() + continuousSolver_->getNumCols();
+                bool smallProblem = size <= 550;
+                smallProblem = false;
+#ifdef CLP_INVESTIGATE
+                int maxPass = maximumCutPasses_;
+#endif
+                if (thisObjective - startObjective < 1.0e-5) {
+                    // No change in objective function
+                    if (numberElementsAdded > 0.2*numberElementsAtStart) {
+                        if (whenCuts_ == 999999) {
+                            whenCuts_ = 5000010;
+                            if (!smallProblem)
+                                maximumCutPasses_ = CoinMax(maximumCutPasses_ >> 1, 1);
+                        } else if (whenCuts_ == 999998) {
+                            whenCuts_ = 5000010;
+                            if (!smallProblem)
+                                maximumCutPasses_ = CoinMax(maximumCutPasses_ >> 1, 1);
+                        }
+#ifdef JJF_ZERO
+                    } else if (currentPassNumber_ < CoinMin(CoinAbs(maximumCutPassesAtRoot_), 8)) {
+                        if (whenCuts_ == 999999) {
+                            whenCuts_ = 8000008;
+                            maximumCutPasses_ = 1;
+                        } else if (whenCuts_ == 999998) {
+                            whenCuts_ = 10000008;
+                            maximumCutPasses_ = 1;
+                        }
+                    } else if (currentPassNumber_ < CoinMin(CoinAbs(maximumCutPassesAtRoot_), 50)) {
+                        if (whenCuts_ == 999999) {
+                            whenCuts_ = 8000008;
+                            maximumCutPasses_ = 1;
+                        } else if (whenCuts_ == 999998) {
+                            whenCuts_ = 10000006;
+                            maximumCutPasses_ = 1;
+                        }
+                    } else if (currentPassNumber_ < CoinAbs(maximumCutPassesAtRoot_)) {
+                        if (whenCuts_ == 999999) {
+                            whenCuts_ = 8000008;
+                            maximumCutPasses_ = 1;
+                        } else if (whenCuts_ == 999998) {
+                            whenCuts_ = 10000004;
+                            maximumCutPasses_ = 1;
+                        }
+#endif
+                    } else {
+                        if (whenCuts_ == 999999) {
+                            whenCuts_ = 8000008;
+                            if (!smallProblem)
+                                maximumCutPasses_ = CoinMax(maximumCutPasses_ >> 1, 1);
+                        } else if (whenCuts_ == 999998) {
+                            whenCuts_ = 10000004;
+                            if (!smallProblem)
+                                maximumCutPasses_ = CoinMax(maximumCutPasses_ >> 1, 1);
+                        }
+                    }
+                } else {
+                    // Objective changed
+#ifdef JJF_ZERO
+                    if (currentPassNumber_ < CoinMin(CoinAbs(maximumCutPassesAtRoot_), 8)) {
+                        if (whenCuts_ == 999999) {
+                            whenCuts_ = 8000008;
+                            maximumCutPasses_ = 1;
+                        } else if (whenCuts_ == 999998) {
+                            whenCuts_ = 10000008;
+                            maximumCutPasses_ = 1;
+                        }
+                    } else if (currentPassNumber_ < CoinMin(CoinAbs(maximumCutPassesAtRoot_), 50)) {
+                        if (whenCuts_ == 999999) {
+                            whenCuts_ = 8000008;
+                            maximumCutPasses_ = 1;
+                        } else if (whenCuts_ == 999998) {
+                            whenCuts_ = 10000004;
+                            maximumCutPasses_ = 1;
+                        }
+                    } else
+#endif
+                        if (currentPassNumber_ < CoinAbs(maximumCutPassesAtRoot_)) {
+                            if (whenCuts_ == 999999) {
+                                whenCuts_ = 8000008;
+                                if (!smallProblem)
+                                    maximumCutPasses_ = CoinMax(maximumCutPasses_ >> 1, 1);
+                            } else if (whenCuts_ == 999998) {
+                                whenCuts_ = 10000004;
+                                if (!smallProblem)
+                                    maximumCutPasses_ = CoinMax(maximumCutPasses_ >> 1, 1);
+                            }
+                        } else {
+                            if (whenCuts_ == 999999) {
+                                whenCuts_ = 10000004;
+                                maximumCutPasses_ = CoinMax(maximumCutPasses_, 2);
+                            } else if (whenCuts_ == 999998) {
+                                whenCuts_ = 11000002;
+                                maximumCutPasses_ = CoinMax(maximumCutPasses_, 2);
+                            }
+                        }
+                }
+                // Set bit to say don't try too hard if seems reasonable
+                if (maximumCutPasses_ <= 5)
+                    whenCuts_ += 100000;
+                //// end
+#ifdef CLP_INVESTIGATE
+                printf("changing whenCuts from %d to %d and cutPasses from %d to %d objchange %g\n",
+                       whenC, whenCuts_, maxPass, maximumCutPasses_, thisObjective - startObjective);
+#endif
+            }
+        }
+        /*
+          Noop block 071219.
+        */
+        if ((numberRowsAdded > 100 + 0.5*numberRowsAtStart
+                || numberElementsAdded > 0.5*numberElementsAtStart)
+                && (densityNew > 200.0 && numberRowsAdded > 100 && densityNew > 2.0*densityOld)) {
+            // much bigger
+            //if (thisObjective-startObjective<0.1*fabs(startObjective)+1.0e-5)
+            //willBeCutsInTree=-1;
+            //printf("Cuts will be taken off , %d rows added with density %g\n",
+            //     numberRowsAdded,densityNew);
+        }
+        /*
+          Noop block 071219.
+        */
+        if (densityNew > 100.0 && numberRowsAdded > 2 && densityNew > 2.0*densityOld) {
+            //if (thisObjective-startObjective<0.1*fabs(startObjective)+1.0e-5)
+            //willBeCutsInTree=-2;
+            //printf("Density says no cuts ? , %d rows added with density %g\n",
+            //     numberRowsAdded,densityNew);
+        }
+        // Root node or every so often - see what to turn off
+        /*
+          Hmmm ... > -90 for any generator will overrule previous decision to do no
+          cuts in tree and delete existing cuts.
+        */
+        int i ;
+        for (i = 0; i < numberCutGenerators_; i++) {
+            int howOften = generator_[i]->howOften() ;
+            if (howOften > -90)
+                willBeCutsInTree = 0;
+        }
+        if (!numberNodes_) {
+            handler_->message(CBC_ROOT, messages_)
+            << numberNewCuts_
+            << startObjective << thisObjective
+            << currentPassNumber_
+            << CoinMessageEol ;
+	}
+        /*
+          Count the number of cuts produced by each cut generator on this call. Not
+          clear to me that the accounting is equivalent here. whichGenerator_ records
+          the generator for column and row cuts. So unless numberNewCuts is row cuts
+          only, we're double counting for JUST_ACTIVE. Note too the multiplier applied
+          to column cuts.
+        */
+        if (!numberNodes_) {
+            double value = CoinMax(minimumDrop_, 0.005 * (thisObjective - startObjective) /
+                                   static_cast<double> (currentPassNumber_));
+            if (numberColumns < 200)
+                value = CoinMax(minimumDrop_, 0.1 * value);
+#ifdef CLP_INVESTIGATE
+            printf("Minimum drop for cuts was %g, now is %g\n", minimumDrop_, value);
+#endif
+            minimumDrop_ = value;
+        }
+        int * count = new int[numberCutGenerators_] ;
+        memset(count, 0, numberCutGenerators_*sizeof(int)) ;
+        int numberActiveGenerators = 0;
+        for (i = 0; i < numberNewCuts_; i++) {
+            int iGenerator = whichGenerator_[i];
+	    if (iGenerator>=0)
+	      iGenerator=iGenerator%10000;
+            if (iGenerator >= 0 && iGenerator < numberCutGenerators_)
+                count[iGenerator]++ ;
+        }
+	// add in any active cuts if at root node (for multiple solvers)
+	if (!numberNodes_) {
+	  for (i = 0; i < numberCutGenerators_; i++) 
+	    count[i] += generator_[i]->numberCutsActive();
+	}
+        double totalCuts = 0.0 ;
+        //#define JUST_ACTIVE
+        for (i = 0; i < numberCutGenerators_; i++) {
+            if (generator_[i]->numberCutsInTotal() || generator_[i]->numberColumnCuts())
+                numberActiveGenerators++;
+#ifdef JUST_ACTIVE
+            double value = count[i] ;
+#else
+            double value = generator_[i]->numberCutsInTotal() ;
+#endif
+            totalCuts += value;
+        }
+        /*
+          Open up a loop to step through the cut generators and decide what (if any)
+          adjustment should be made for calling frequency.
+        */
+        int iProbing = -1;
+        double smallProblem = (0.2 * totalCuts) /
+                              static_cast<double> (numberActiveGenerators) ;
+        for (i = 0; i < numberCutGenerators_; i++) {
+            int howOften = generator_[i]->howOften() ;
+            /*  Probing can be set to just do column cuts in treee.
+            But if doing good then leave as on
+            Ok, let me try to explain this. rowCuts = 3 says do disaggregation (1<<0) and
+            coefficient (1<<1) cuts. But if the value is negative, there's code at the
+            entry to generateCuts, and generateCutsAndModify, that temporarily changes
+            the value to 4 (1<<2) if we're in a search tree.
+
+            Which does nothing to explain this next bit. We set a boolean, convert
+            howOften to the code for `generate while objective is improving', and change
+            over to `do everywhere'. Hmmm ... now I write it out, this makes sense in the
+            context of the original comment. If we're doing well (objective improving)
+            we'll keep probing fully active.
+
+            */
+            bool probingWasOnBut = false;
+            CglProbing * probing = dynamic_cast<CglProbing*>(generator_[i]->generator());
+            if (probing && !numberNodes_) {
+                if (generator_[i]->numberCutsInTotal()) {
+                    // If large number of probing - can be biased
+                    smallProblem = (0.2 * (totalCuts - generator_[i]->numberCutsInTotal())) /
+                                   static_cast<double> (numberActiveGenerators - 1) ;
+                }
+                iProbing = i;
+                if (probing->rowCuts() == -3) {
+                    probingWasOnBut = true;
+                    howOften = -98;
+                    probing->setRowCuts(3);
+                }
+            }
+            /*
+              Convert `as long as objective is improving' into `only at root' if we've
+              decided cuts just aren't worth it.
+            */
+            if (willBeCutsInTree < 0 && howOften == -98)
+                howOften = -99;
+            /*
+              And check to see if the objective is improving. But don't do the check if
+              the user has specified some minimum number of cuts.
+
+              This exclusion seems bogus, or at least counterintuitive. Why would a user
+              suspect that setting a minimum cut limit would invalidate the objective
+              check? Nor do I see the point in comparing the number of rows and columns
+              in the second test.
+            */
+            if (!probing && howOften == -98 && !generator_[i]->numberShortCutsAtRoot() &&
+                    generator_[i]->numberCutsInTotal()) {
+                // switch off as no short cuts generated
+                //printf("Switch off %s?\n",generator_[i]->cutGeneratorName());
+                howOften = -99;
+            }
+            if (howOften == -98 && generator_[i]->switchOffIfLessThan() > 0) {
+                if (thisObjective - startObjective < 0.005*fabs(startObjective) + 1.0e-5)
+                    howOften = -99; // switch off
+                if (thisObjective - startObjective < 0.1*fabs(startObjective) + 1.0e-5
+                        && 5*solver_->getNumRows() < solver_->getNumCols())
+                    howOften = -99; // switch off
+            }
+	    if (generator_[i]->maximumTries()!=-1)
+	        howOften = CoinMin(howOften,-99); // switch off
+            /*
+              Below -99, this generator is switched off. There's no need to consider
+              further. Then again, there was no point in persisting this far!
+            */
+            if (howOften < -99) {
+	      // may have been switched off - report
+	      if (!numberNodes_) {
+		int n = generator_[i]->numberCutsInTotal();
+		if (n) {
+		  double average = 0.0;
+		  average = generator_[i]->numberElementsInTotal();
+		  average /= n;
+		  handler_->message(CBC_GENERATOR, messages_)
+		    << i
+		    << generator_[i]->cutGeneratorName()
+		    << n
+		    << average
+		    << generator_[i]->numberColumnCuts()
+		    << generator_[i]->numberCutsActive()
+		    + generator_[i]->numberColumnCuts();
+		  handler_->printing(generator_[i]->timing())
+		    << generator_[i]->timeInCutGenerator();
+		  handler_->message()
+		    << -100
+		    << CoinMessageEol ;
+		}
+	      }
+	      continue ;
+	    }
+            /*
+              Adjust, if howOften is adjustable.
+            */
+            if (howOften < 0 || howOften >= 1000000) {
+                if ( !numberNodes_) {
+                    /*
+                      If root only, or objective improvement but no cuts generated, switch off. If
+                      it's just that the generator found no cuts at the root, give it one more
+                      chance.
+                    */
+                    // If small number switch mostly off
+#ifdef JUST_ACTIVE
+                    double thisCuts = count[i] + 5.0 * generator_[i]->numberColumnCuts() ;
+#else
+                    double thisCuts = generator_[i]->numberCutsInTotal() + 5.0 * generator_[i]->numberColumnCuts() ;
+#endif
+                    // Allow on smaller number if <-1
+                    if (generator_[i]->switchOffIfLessThan() < 0) {
+                        double multiplier[] = {2.0, 5.0};
+                        int iSwitch = -generator_[i]->switchOffIfLessThan() - 1;
+                        assert (iSwitch >= 0 && iSwitch < 2);
+                        thisCuts *= multiplier[iSwitch];
+                    }
+                    if (!thisCuts || howOften == -99) {
+                        if (howOften == -99 || howOften == -98) {
+                            howOften = -100 ;
+                        } else {
+                            howOften = 1000000 + SCANCUTS; // wait until next time
+                            if (probing) {
+                                // not quite so drastic
+                                howOften = 1000000 + 1;
+                                probing->setMaxLook(1);
+                                probing->setMaxProbe(123);
+                            }
+                        }
+                        /*
+                          Not productive, but not zero either.
+                        */
+                    } else if ((thisCuts + generator_[i]->numberColumnCuts() < smallProblem)
+                               && !generator_[i] ->whetherToUse()) {
+                        /*
+                          Not unadjustable every node, and not strong probing.
+                        */
+                        if (howOften != 1 && !probingWasOnBut) {
+                            /*
+                              No depth spec, or not adjustable every node.
+                            */
+                            if (generator_[i]->whatDepth() < 0 || howOften != -1) {
+                                int k = static_cast<int> (sqrt(smallProblem / thisCuts)) ;
+                                /*
+                                  Not objective improvement, set to new frequency, otherwise turn off.
+                                */
+                                if (howOften != -98)
+                                    howOften = k + 1000000 ;
+                                else
+                                    howOften = -100;
+                                /*
+                                  Depth spec, or adjustable every node. Force to unadjustable every node.
+                                */
+                            } else {
+                                howOften = 1;
+                            }
+                            /*
+                              Unadjustable every node, or strong probing. Force unadjustable every node and
+                              force not strong probing? I don't understand.
+                            */
+                        } else {
+                            howOften = 1;
+                            // allow cuts
+                            probingWasOnBut = false;
+                        }
+                        /*
+                          Productive cut generator. Say we'll do it every node, adjustable. But if the
+                          objective isn't improving, restrict that to every fifth depth level
+                          (whatDepth overrides howOften in generateCuts).
+                        */
+                    } else {
+                        if (thisObjective - startObjective < 0.1*fabs(startObjective) + 1.0e-5 && generator_[i]->whatDepth() < 0)
+                            generator_[i]->setWhatDepth(5);
+                        howOften = 1 + 1000000 ;
+                    }
+                }
+                /*
+                  End root actions.
+
+                  sumChangeObjective2_ is the objective change due to cuts. If we're getting
+                  much better results from branching over a large number of nodes, switch off
+                  cuts.
+
+                  Except it doesn't, really --- it just puts off the decision 'til the
+                  next full scan, when it'll put it off again unless cuts look better.
+                */
+                // If cuts useless switch off
+                if (numberNodes_ >= 100000 && sumChangeObjective1_ > 2.0e2*(sumChangeObjective2_ + 1.0e-12)) {
+                    howOften = 1000000 + SCANCUTS; // wait until next time
+                    //printf("switch off cut %d due to lack of use\n",i);
+                }
+            }
+            /*
+              Ok, that's the frequency adjustment bit.
+
+              Now, if we're at the root, force probing back on at every node, for column
+              cuts at least, even if it looks useless for row cuts. Notice that if it
+              looked useful, the values set above mean we'll be doing strong probing in
+              the tree subject to objective improvement.
+            */
+            if (!numberNodes_) {
+                if (probingWasOnBut && howOften == -100) {
+                    probing->setRowCuts(-3);
+                    howOften = 1;
+                }
+                if (howOften == 1)
+                    generator_[i]->setWhatDepth(1);
+
+                if (howOften >= 0 && generator_[i]->generator()->mayGenerateRowCutsInTree())
+                    willBeCutsInTree = 1;
+            }
+            /*
+              Set the new frequency in the generator. If this is an adjustable frequency,
+              use the value to set whatDepth.
+
+              Hey! Seems like this could override the user's depth setting.
+            */
+            generator_[i]->setHowOften(howOften) ;
+            if (howOften >= 1000000 && howOften < 2000000 && 0) {
+                // Go to depth
+                int bias = 1;
+                if (howOften == 1 + 1000000)
+                    generator_[i]->setWhatDepth(bias + 1);
+                else if (howOften <= 10 + 1000000)
+                    generator_[i]->setWhatDepth(bias + 2);
+                else
+                    generator_[i]->setWhatDepth(bias + 1000);
+            }
+            int newFrequency = generator_[i]->howOften() % 1000000 ;
+            // increment cut counts
+            generator_[i]->incrementNumberCutsActive(count[i]);
+            CglStored * stored = dynamic_cast<CglStored*>(generator_[i]->generator());
+            if (stored && !generator_[i]->numberCutsInTotal())
+                continue;
+            double average = 0.0;
+            int n = generator_[i]->numberCutsInTotal();
+            if (n) {
+                average = generator_[i]->numberElementsInTotal();
+                average /= n;
+            }
+            if (handler_->logLevel() > 1 || !numberNodes_) {
+                handler_->message(CBC_GENERATOR, messages_)
+                << i
+                << generator_[i]->cutGeneratorName()
+                //<<generator_[i]->numberCutsInTotal()<<count[i]
+                << n
+                << average
+                << generator_[i]->numberColumnCuts()
+                << generator_[i]->numberCutsActive()
+                + generator_[i]->numberColumnCuts();
+                handler_->printing(!numberNodes_ && generator_[i]->timing())
+                << generator_[i]->timeInCutGenerator();
+                handler_->message()
+                << newFrequency
+                << CoinMessageEol ;
+            }
+        }
+        /*
+          End loop to adjust cut generator frequency of use.
+        */
+        delete [] count ;
+        if ( !numberNodes_) {
+            // save statistics
+            for (i = 0; i < numberCutGenerators_; i++) {
+                generator_[i]->setNumberCutsAtRoot(generator_[i]->numberCutsInTotal());
+                generator_[i]->setNumberActiveCutsAtRoot(generator_[i]->numberCutsActive());
+            }
+            /*
+              Garbage code 071219
+            */
+            // decide on pseudo cost strategy
+            int howOften = iProbing >= 0 ? generator_[iProbing]->howOften() : 0;
+            if ((howOften % 1000000) != 1)
+                howOften = 0;
+            //if (howOften) {
+            //CglProbing * probing = dynamic_cast<CglProbing*>(generator_[iProbing]->generator());
+            //}
+            howOften = 0;
+            if (howOften) {
+	      COIN_DETAIL_PRINT(printf("** method 1\n"));
+                //CglProbing * probing = dynamic_cast<CglProbing*>(generator_[iProbing]->generator());
+                generator_[iProbing]->setWhatDepth(1);
+                // could set no row cuts
+                //if (thisObjective-startObjective<0.001*fabs(startObjective)+1.0e-5)
+                // probing->setRowCuts(0);
+                for (int i = 0; i < numberObjects_; i++) {
+                    CbcSimpleIntegerDynamicPseudoCost * obj =
+                        dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[i]) ;
+                    if (obj)
+                        obj->setMethod(1);
+                }
+            }
+            if (willBeCutsInTree == -2)
+                willBeCutsInTree = 0;
+            /*
+              End garbage code.
+
+              Now I've reached the problem area. This is a problem only at the root node,
+              so that should simplify the issue of finding a workable basis? Or maybe not.
+            */
+            if ( willBeCutsInTree <= 0) {
+                // Take off cuts
+                cuts = OsiCuts();
+                numberNewCuts_ = 0;
+                if (!willBeCutsInTree) {
+                    // update size of problem
+                    numberRowsAtContinuous_ = solver_->getNumRows() ;
+                } else {
+                    // take off cuts
+                    int numberRows = solver_->getNumRows();
+                    int numberAdded = numberRows - numberRowsAtContinuous_;
+                    if (numberAdded) {
+                        int * added = new int[numberAdded];
+                        for (int i = 0; i < numberAdded; i++)
+                            added[i] = i + numberRowsAtContinuous_;
+                        solver_->deleteRows(numberAdded, added);
+                        delete [] added;
+                        // resolve so optimal
+                        resolve(solver_);
+                    }
+                }
+#ifdef COIN_HAS_CLP
+                OsiClpSolverInterface * clpSolver
+                = dynamic_cast<OsiClpSolverInterface *> (solver_);
+                if (clpSolver) {
+                    // Maybe solver might like to know only column bounds will change
+                    //int options = clpSolver->specialOptions();
+                    //clpSolver->setSpecialOptions(options|128);
+                    clpSolver->synchronizeModel();
+                }
+#endif
+            } else {
+#ifdef COIN_HAS_CLP
+                OsiClpSolverInterface * clpSolver
+                = dynamic_cast<OsiClpSolverInterface *> (solver_);
+                if (clpSolver) {
+                    // make sure factorization can't carry over
+                    int options = clpSolver->specialOptions();
+                    clpSolver->setSpecialOptions(options&(~8));
+                }
+#endif
+            }
+        }
+    } else {
+#ifdef COIN_HAS_CLP
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver) {
+            // Maybe solver might like to know only column bounds will change
+            //int options = clpSolver->specialOptions();
+            //clpSolver->setSpecialOptions(options|128);
+            clpSolver->synchronizeModel();
+        }
+#endif
+        if (numberCutGenerators_) {
+            int i;
+            // What if not feasible as cuts may have helped
+            if (feasible) {
+                for (i = 0; i < numberNewCuts_; i++) {
+                    int iGenerator = whichGenerator_[i];
+		    if (iGenerator>=0)
+		      iGenerator=iGenerator%10000;
+                    if (iGenerator >= 0)
+                        generator_[iGenerator]->incrementNumberCutsActive();
+                }
+            }
+        }
+    }
+
+
+#ifdef CHECK_CUT_COUNTS
+    if (feasible) {
+        CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+        printf("solveWithCuts: Number of rows at end (only active cuts) %d\n",
+               numberRowsAtContinuous_ + numberNewCuts_ + numberOldActiveCuts_) ;
+        basis->print() ;
+        delete basis;
+    }
+#endif
+#ifdef CBC_DEBUG
+    if (onOptimalPath && !solver_->isDualObjectiveLimitReached())
+        assert(feasible) ;
+#endif
+# ifdef COIN_HAS_CLP
+    if (clpSolver)
+        clpSolver->setSpecialOptions(saveClpOptions);
+# endif
+#ifdef CBC_THREAD
+    // Get rid of all threaded stuff
+    if (master) {
+        master->stopThreads(0);
+        delete master;
+    }
+#endif
+    // make sure pointers are up to date
+    setPointers(solver_);
+
+    return feasible ;
+}
+
+// Generate one round of cuts - serial mode
+int
+CbcModel::serialCuts(OsiCuts & theseCuts, CbcNode * node, OsiCuts & slackCuts, int lastNumberCuts)
+{
+    /*
+      Is it time to scan the cuts in order to remove redundant cuts? If so, set
+      up to do it.
+    */
+    int fullScan = 0 ;
+    if ((numberNodes_ % SCANCUTS) == 0 || (specialOptions_&256) != 0) {
+        fullScan = 1 ;
+        if (!numberNodes_ || (specialOptions_&256) != 0)
+            fullScan = 2;
+        specialOptions_ &= ~256; // mark as full scan done
+    }
+# if 0 //def COIN_HAS_CLP
+    // check basis
+    OsiClpSolverInterface * clpSolver
+      = dynamic_cast<OsiClpSolverInterface *> (solver_);
+    if (clpSolver) {
+      ClpSimplex * simplex = clpSolver->getModelPtr();
+      int numberTotal=simplex->numberRows()+simplex->numberColumns();
+      int superbasic=0;
+      for (int i=0;i<numberTotal;i++) {
+	if (simplex->getStatus(i)==ClpSimplex::superBasic)
+	  superbasic++;
+      }
+      if (superbasic) {
+	printf("%d superbasic!\n",superbasic);
+	clpSolver->resolve();
+	superbasic=0;
+	for (int i=0;i<numberTotal;i++) {
+	  if (simplex->getStatus(i)==ClpSimplex::superBasic)
+	    superbasic++;
+	}
+	assert (!superbasic);
+      }
+    }
+# endif
+    int switchOff = (!doCutsNow(1) && !fullScan) ? 1 : 0;
+    int status = 0;
+    int i;
+    for (i = 0; i < numberCutGenerators_; i++) {
+        int numberRowCutsBefore = theseCuts.sizeRowCuts() ;
+        int numberColumnCutsBefore = theseCuts.sizeColCuts() ;
+        int numberRowCutsAfter = numberRowCutsBefore;
+        int numberColumnCutsAfter = numberColumnCutsBefore;
+	/*printf("GEN %d %s switches %d\n",
+	       i,generator_[i]->cutGeneratorName(),
+	       generator_[i]->switches());*/
+        bool generate = generator_[i]->normal();
+        // skip if not optimal and should be (maybe a cut generator has fixed variables)
+        if (generator_[i]->howOften() == -100 ||
+                (generator_[i]->needsOptimalBasis() && !solver_->basisIsAvailable())
+                || generator_[i]->switchedOff())
+            generate = false;
+        if (switchOff&&!generator_[i]->mustCallAgain()) {
+            // switch off if default
+            if (generator_[i]->howOften() == 1 && generator_[i]->whatDepth() < 0) {
+                generate = false;
+            } else if (currentDepth_ > -10 && switchOff == 2) {
+                generate = false;
+            }
+        }
+	if (generator_[i]->whetherCallAtEnd())
+	  generate=false;
+        const OsiRowCutDebugger * debugger = NULL;
+        bool onOptimalPath = false;
+        if (generate) {
+            bool mustResolve =
+                generator_[i]->generateCuts(theseCuts, fullScan, solver_, node) ;
+            numberRowCutsAfter = theseCuts.sizeRowCuts() ;
+            if (fullScan && generator_[i]->howOften() == 1000000 + SCANCUTS_PROBING) {
+                CglProbing * probing =
+                    dynamic_cast<CglProbing*>(generator_[i]->generator());
+                if (probing && (numberRowCutsBefore < numberRowCutsAfter ||
+                                numberColumnCutsBefore < theseCuts.sizeColCuts())) {
+                    // switch on
+                    generator_[i]->setHowOften(1);
+                }
+            }
+            if (numberRowCutsBefore < numberRowCutsAfter &&
+		generator_[i]->mustCallAgain() && status >= 0)
+	      /*printf("%s before %d after %d must %c atend %c off %c endmode %c\n",
+		   generator_[i]->cutGeneratorName(),
+		   numberRowCutsBefore,numberRowCutsAfter,
+		   generator_[i]->mustCallAgain() ? 'Y': 'N',
+		   generator_[i]->whetherCallAtEnd() ? 'Y': 'N',
+		   generator_[i]->switchedOff() ? 'Y': 'N',
+		   generator_[i]->whetherInMustCallAgainMode() ? 'Y': 'N');*/
+            if (numberRowCutsBefore < numberRowCutsAfter &&
+		generator_[i]->mustCallAgain() && status >= 0)
+                status = 1 ; // say must go round
+            // Check last cut to see if infeasible
+            /*
+            The convention is that if the generator proves infeasibility, it should
+            return as its last cut something with lb > ub.
+            */
+            if (numberRowCutsBefore < numberRowCutsAfter) {
+                const OsiRowCut * thisCut = theseCuts.rowCutPtr(numberRowCutsAfter - 1) ;
+                if (thisCut->lb() > thisCut->ub()) {
+                    status = -1; // sub-problem is infeasible
+                    break;
+                }
+            }
+#ifdef CBC_DEBUG
+            {
+                int k ;
+                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                    OsiRowCut thisCut = theseCuts.rowCut(k) ;
+                    /* check size of elements.
+                       We can allow smaller but this helps debug generators as it
+                       is unsafe to have small elements */
+                    int n = thisCut.row().getNumElements();
+                    const int * column = thisCut.row().getIndices();
+                    const double * element = thisCut.row().getElements();
+                    //assert (n);
+                    for (int i = 0; i < n; i++) {
+                        double value = element[i];
+                        assert(fabs(value) > 1.0e-12 && fabs(value) < 1.0e20);
+                    }
+                }
+            }
+#endif
+            if (mustResolve || (specialOptions_&1) != 0) {
+                int returnCode = resolve(node ? node->nodeInfo() : NULL, 2);
+                if (returnCode  == 0)
+                    status = -1;
+                if (returnCode < 0 && !status)
+                    status = 2;
+                if ((specialOptions_&1) != 0) {
+                    debugger = solver_->getRowCutDebugger() ;
+                    if (debugger)
+                        onOptimalPath = (debugger->onOptimalPath(*solver_)) ;
+                    else
+                        onOptimalPath = false;
+                    if (onOptimalPath && !solver_->isDualObjectiveLimitReached())
+                        assert(status >= 0) ;
+                }
+                if (status < 0)
+                    break ;
+            }
+        }
+        numberRowCutsAfter = theseCuts.sizeRowCuts() ;
+        numberColumnCutsAfter = theseCuts.sizeColCuts() ;
+        if ((specialOptions_&1) != 0) {
+            if (onOptimalPath) {
+                int k ;
+                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                    OsiRowCut thisCut = theseCuts.rowCut(k) ;
+                    if (debugger->invalidCut(thisCut)) {
+                        solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
+                        solver_->writeMpsNative("badCut.mps", NULL, NULL, 2);
+                        printf("Cut generator %d (%s) produced invalid cut (%dth in this go)\n",
+                               i, generator_[i]->cutGeneratorName(), k - numberRowCutsBefore);
+                        const double *lower = getColLower() ;
+                        const double *upper = getColUpper() ;
+                        int numberColumns = solver_->getNumCols();
+                        if (numberColumns < 200) {
+                            for (int i = 0; i < numberColumns; i++)
+                                printf("%d bounds %g,%g\n", i, lower[i], upper[i]);
+                        }
+                        abort();
+                    }
+                    assert(!debugger->invalidCut(thisCut)) ;
+                }
+            }
+        }
+        /*
+          The cut generator has done its thing, and maybe it generated some
+          cuts.  Do a bit of bookkeeping: load
+          whichGenerator[i] with the index of the generator responsible for a cut,
+          and place cuts flagged as global in the global cut pool for the model.
+
+          lastNumberCuts is the sum of cuts added in previous iterations; it's the
+          offset to the proper starting position in whichGenerator.
+        */
+        int numberBefore =
+            numberRowCutsBefore + lastNumberCuts ;
+        int numberAfter =
+            numberRowCutsAfter + lastNumberCuts ;
+        // possibly extend whichGenerator
+        resizeWhichGenerator(numberBefore, numberAfter);
+        int j ;
+
+        /*
+          Look for numerically unacceptable cuts.
+        */
+        bool dodgyCuts = false;
+        for (j = numberRowCutsBefore; j < numberRowCutsAfter; j++) {
+            const OsiRowCut * thisCut = theseCuts.rowCutPtr(j) ;
+            if (thisCut->lb() > 1.0e10 || thisCut->ub() < -1.0e10) {
+                dodgyCuts = true;
+                break;
+            }
+            whichGenerator_[numberBefore++] = i ;
+	    if (!numberNodes_||generator_[i]->globalCuts())
+	      whichGenerator_[numberBefore-1]=i+10000;
+            if (thisCut->lb() > thisCut->ub())
+                status = -1; // sub-problem is infeasible
+            if (thisCut->globallyValid()||!numberNodes_) {
+                // add to global list
+                OsiRowCut newCut(*thisCut);
+                newCut.setGloballyValid(true);
+                newCut.mutableRow().setTestForDuplicateIndex(false);
+                globalCuts_.addCutIfNotDuplicate(newCut) ;
+		whichGenerator_[numberBefore-1] = i+10000 ;
+            }
+        }
+        if (dodgyCuts) {
+            for (int k = numberRowCutsAfter - 1; k >= j; k--) {
+                const OsiRowCut * thisCut = theseCuts.rowCutPtr(k) ;
+                if (thisCut->lb() > thisCut->ub())
+                    status = -1; // sub-problem is infeasible
+                if (thisCut->lb() > 1.0e10 || thisCut->ub() < -1.0e10)
+                    theseCuts.eraseRowCut(k);
+            }
+            numberRowCutsAfter = theseCuts.sizeRowCuts() ;
+            for (; j < numberRowCutsAfter; j++) {
+                const OsiRowCut * thisCut = theseCuts.rowCutPtr(j) ;
+                whichGenerator_[numberBefore++] = i ;
+		if (!numberNodes_||generator_[i]->globalCuts())
+		  whichGenerator_[numberBefore-1]=i+10000;
+                if (thisCut->globallyValid()) {
+                    // add to global list
+                    OsiRowCut newCut(*thisCut);
+                    newCut.setGloballyValid(true);
+                    newCut.mutableRow().setTestForDuplicateIndex(false);
+                    globalCuts_.addCutIfNotDuplicate(newCut) ;
+		    whichGenerator_[numberBefore-1]=i+10000;
+                }
+            }
+        }
+        for (j = numberColumnCutsBefore; j < numberColumnCutsAfter; j++) {
+            //whichGenerator_[numberBefore++] = i ;
+            const OsiColCut * thisCut = theseCuts.colCutPtr(j) ;
+            if (thisCut->globallyValid()) {
+                // fix
+	        makeGlobalCut(thisCut);
+            }
+        }
+    }
+    /*
+      End of loop to run each cut generator.
+    */
+    if (status >= 0) {
+        // delete null cuts
+        int nCuts = theseCuts.sizeRowCuts() ;
+        int k ;
+        for (k = nCuts - 1; k >= 0; k--) {
+            const OsiRowCut * thisCut = theseCuts.rowCutPtr(k) ;
+            int n = thisCut->row().getNumElements();
+            if (!n)
+                theseCuts.eraseRowCut(k);
+        }
+    }
+    // Add in any violated saved cuts
+    if (!theseCuts.sizeRowCuts() && !theseCuts.sizeColCuts()) {
+        int numberOld = theseCuts.sizeRowCuts() + lastNumberCuts;
+        int numberCuts = slackCuts.sizeRowCuts() ;
+        int i;
+        // possibly extend whichGenerator
+        resizeWhichGenerator(numberOld, numberOld + numberCuts);
+        double primalTolerance;
+        solver_->getDblParam(OsiPrimalTolerance, primalTolerance) ;
+        for ( i = 0; i < numberCuts; i++) {
+            const OsiRowCut * thisCut = slackCuts.rowCutPtr(i) ;
+            if (thisCut->violated(cbcColSolution_) > 100.0*primalTolerance) {
+                if (messageHandler()->logLevel() > 2)
+                    printf("Old cut added - violation %g\n",
+                           thisCut->violated(cbcColSolution_)) ;
+                whichGenerator_[numberOld++] = -3;
+                theseCuts.insert(*thisCut) ;
+            }
+        }
+    }
+    return status;
+}
+
+/*
+  Remove slack cuts. We obtain a basis and scan it. Cuts with basic slacks
+  are purged. If any cuts are purged, resolve() is called to restore the
+  solution held in the solver.	If resolve() pivots, there's the possibility
+  that a slack may be pivoted in (trust me :-), so the process iterates.
+  Setting allowResolve to false will suppress reoptimisation (but see note
+  below).
+
+  At the level of the solver's constraint system, loose cuts are really
+  deleted.  There's an implicit assumption that deleteRows will also update
+  the active basis in the solver.
+
+  At the level of nodes and models, it's more complicated.
+
+  New cuts exist only in the collection of cuts passed as a parameter. They
+  are deleted from the collection and that's the end of them.
+
+  Older cuts have made it into addedCuts_. Two separate actions are needed.
+  The reference count for the CbcCountRowCut object is decremented. If this
+  count falls to 0, the node which owns the cut is located, the reference to
+  the cut is removed, and then the cut object is destroyed (courtesy of the
+  CbcCountRowCut destructor). We also need to set the addedCuts_ entry to
+  NULL. This is important so that when it comes time to generate basis edits
+  we can tell this cut was dropped from the basis during processing of the
+  node.
+
+  NOTE: In general, it's necessary to call resolve() after purging slack
+	cuts.  Deleting constraints constitutes a change in the problem, and
+	an OSI is not required to maintain a valid solution when the problem
+	is changed. But ... it's really useful to maintain the active basis,
+	and the OSI is supposed to do that. (Yes, it's splitting hairs.) In
+	some places, it's possible to know that the solution will never be
+	consulted after this call, only the basis.  (E.g., this routine is
+	called as a last act before generating info to place the node in the
+	live set.) For such use, set allowResolve to false.
+
+  TODO: No real harm would be done if we just ignored the rare occasion when
+	the call to resolve() pivoted a slack back into the basis. It's a
+	minor inefficiency, at worst. But it does break assertions which
+	check that there are no loose cuts in the basis. It might be better
+	to remove the assertions.
+*/
+
+int
+CbcModel::takeOffCuts (OsiCuts &newCuts,
+                       bool allowResolve, OsiCuts * saveCuts,
+                       int numberNewCuts, const OsiRowCut ** addedCuts)
+
+{ // int resolveIterations = 0 ;
+    int numberDropped = 0;
+    int firstOldCut = numberRowsAtContinuous_ ;
+    int totalNumberCuts = numberNewCuts_ + numberOldActiveCuts_ ;
+    int *solverCutIndices = new int[totalNumberCuts] ;
+    int *newCutIndices = new int[numberNewCuts_] ;
+    const CoinWarmStartBasis* ws ;
+    CoinWarmStartBasis::Status status ;
+    bool needPurge = true ;
+    /*
+      The outer loop allows repetition of purge in the event that reoptimisation
+      changes the basis. To start an iteration, clear the deletion counts and grab
+      the current basis.
+    */
+    while (needPurge) {
+        int numberNewToDelete = 0 ;
+        int numberOldToDelete = 0 ;
+        int i ;
+        ws = dynamic_cast<const CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+        /*
+          Scan the basis entries of the old cuts generated prior to this round of cut
+          generation.  Loose cuts are `removed' by decrementing their reference count
+          and setting the addedCuts_ entry to NULL. (If the reference count falls to
+          0, they're really deleted.  See CbcModel and CbcCountRowCut doc'n for
+          principles of cut handling.)
+        */
+        int oldCutIndex = 0 ;
+        if (numberOldActiveCuts_) {
+            lockThread();
+            for (i = 0 ; i < numberOldActiveCuts_ ; i++) {
+                status = ws->getArtifStatus(i + firstOldCut) ;
+                while (!addedCuts_[oldCutIndex]) oldCutIndex++ ;
+                assert(oldCutIndex < currentNumberCuts_) ;
+                // always leave if from nextRowCut_
+                if (status == CoinWarmStartBasis::basic &&
+                        (addedCuts_[oldCutIndex]->effectiveness() <= 1.0e10 ||
+                         addedCuts_[oldCutIndex]->canDropCut(solver_, i + firstOldCut))) {
+                    solverCutIndices[numberOldToDelete++] = i + firstOldCut ;
+                    if (saveCuts) {
+                        // send to cut pool
+                        OsiRowCut * slackCut = addedCuts_[oldCutIndex];
+                        if (slackCut->effectiveness() != -1.234) {
+                            slackCut->setEffectiveness(-1.234);
+                            saveCuts->insert(*slackCut);
+                        }
+                    }
+                    if (addedCuts_[oldCutIndex]->decrement() == 0)
+                        delete addedCuts_[oldCutIndex] ;
+                    addedCuts_[oldCutIndex] = NULL ;
+                    oldCutIndex++ ;
+                } else {
+                    oldCutIndex++ ;
+                }
+            }
+            unlockThread();
+        }
+        /*
+          Scan the basis entries of the new cuts generated with this round of cut
+          generation.  At this point, newCuts is the only record of the new cuts, so
+          when we delete loose cuts from newCuts, they're really gone. newCuts is a
+          vector, so it's most efficient to compress it (eraseRowCut) from back to
+          front.
+        */
+        int firstNewCut = firstOldCut + numberOldActiveCuts_ ;
+        int k = 0 ;
+        int nCuts = newCuts.sizeRowCuts();
+        for (i = 0 ; i < nCuts ; i++) {
+            status = ws->getArtifStatus(i + firstNewCut) ;
+            if (status == CoinWarmStartBasis::basic &&
+                    /*whichGenerator_[i]!=-2*/newCuts.rowCutPtr(i)->effectiveness() < 1.0e20) {
+                solverCutIndices[numberNewToDelete+numberOldToDelete] = i + firstNewCut ;
+                newCutIndices[numberNewToDelete++] = i ;
+            } else { // save which generator did it
+                // -2 means branch cut! assert (whichGenerator_[i]!=-2); // ?? what if it is - memory leak?
+                whichGenerator_[k++] = whichGenerator_[i] ;
+            }
+        }
+        int baseRow = firstNewCut + nCuts;
+        //OsiRowCut ** mutableAdded = const_cast<OsiRowCut **>(addedCuts);
+        int numberTotalToDelete = numberNewToDelete + numberOldToDelete;
+        for (i = 0 ; i < numberNewCuts ; i++) {
+            status = ws->getArtifStatus(i + baseRow) ;
+            if (status != CoinWarmStartBasis::basic ||
+                    /*whichGenerator_[i+nCuts]==-2*/addedCuts[i]->effectiveness() >= 1.0e20) {
+                newCuts.insert(*addedCuts[i]) ;
+                //newCuts.insert(mutableAdded[i]) ;
+                //mutableAdded[i]=NULL;
+                //if (status == CoinWarmStartBasis::basic&&whichGenerator_[i]!=-2) {
+                // save which generator did it
+                //whichGenerator_[k++] = whichGenerator_[i+nCuts] ;
+                //}
+            } else {
+                solverCutIndices[numberTotalToDelete++] = i + baseRow ;
+            }
+        }
+        numberNewCuts = 0;
+        numberNewCuts_ = newCuts.sizeRowCuts();
+        delete ws ;
+        for (i = numberNewToDelete - 1 ; i >= 0 ; i--) {
+            int iCut = newCutIndices[i] ;
+            if (saveCuts) {
+                // send to cut pool
+                OsiRowCut * slackCut = newCuts.rowCutPtrAndZap(iCut);
+                if (slackCut->effectiveness() != -1.234) {
+                    slackCut->setEffectiveness(-1.234);
+                    saveCuts->insert(slackCut);
+                } else {
+                    delete slackCut;
+                }
+            } else {
+                newCuts.eraseRowCut(iCut) ;
+            }
+        }
+        /*
+          Did we delete anything? If so, delete the cuts from the constraint system
+          held in the solver and reoptimise unless we're forbidden to do so. If the
+          call to resolve() results in pivots, there's the possibility we again have
+          basic slacks. Repeat the purging loop.
+        */
+        if (numberTotalToDelete > 0 ) {
+            solver_->deleteRows(numberTotalToDelete,
+                                solverCutIndices) ;
+            numberDropped += numberTotalToDelete;
+            numberNewCuts_ -= numberNewToDelete ;
+            assert (numberNewCuts_ == newCuts.sizeRowCuts());
+            numberOldActiveCuts_ -= numberOldToDelete ;
+#     ifdef CBC_DEBUG
+            printf("takeOffCuts: purged %d+%d cuts\n", numberOldToDelete,
+                   numberNewToDelete );
+#     endif
+            if (allowResolve) {
+                phase_ = 3;
+                // can do quick optimality check
+                int easy = 2;
+                solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, &easy) ;
+                resolve(solver_) ;
+                setPointers(solver_);
+                solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+                if (solver_->getIterationCount() == 0) {
+                    needPurge = false ;
+                }
+#	ifdef CBC_DEBUG
+                else {
+                    printf( "Repeating purging loop. %d iters.\n",
+                            solver_->getIterationCount());
+                }
+#	endif
+            } else {
+                needPurge = false ;
+            }
+        } else {
+            needPurge = false ;
+        }
+    }
+    /*
+      Clean up and return.
+    */
+    delete [] solverCutIndices ;
+    delete [] newCutIndices ;
+    return numberDropped;
+}
+/*
+  Return values:
+    1:	feasible
+    0:	infeasible
+   -1:	feasible and finished (do no more work on this subproblem)
+*/
+int
+CbcModel::resolve(CbcNodeInfo * parent, int whereFrom,
+                  double * saveSolution,
+                  double * saveLower,
+                  double * saveUpper)
+{
+#ifdef CBC_STATISTICS
+    void cbc_resolve_check(const OsiSolverInterface * solver);
+    cbc_resolve_check(solver_);
+#endif
+    // We may have deliberately added in violated cuts - check to avoid message
+    int iRow;
+    int numberRows = solver_->getNumRows();
+    const double * rowLower = solver_->getRowLower();
+    const double * rowUpper = solver_->getRowUpper();
+    bool feasible = true;
+    for (iRow = numberRowsAtContinuous_; iRow < numberRows; iRow++) {
+        if (rowLower[iRow] > rowUpper[iRow] + 1.0e-8)
+            feasible = false;
+    }
+    // Can't happen if strong branching as would have been found before
+    if (!numberStrong_ && numberObjects_ > numberIntegers_) {
+        int iColumn;
+        int numberColumns = solver_->getNumCols();
+        const double * columnLower = solver_->getColLower();
+        const double * columnUpper = solver_->getColUpper();
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (columnLower[iColumn] > columnUpper[iColumn] + 1.0e-5)
+                feasible = false;
+        }
+    }
+  #ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver_);
+#endif
+    /*
+      Reoptimize. Consider the possibility that we should fathom on bounds. But be
+      careful --- where the objective takes on integral values, we may want to keep
+      a solution where the objective is right on the cutoff.
+    */
+    if (feasible) {
+        bool onOptimalPath = false;
+        if ((specialOptions_&1) != 0) {
+            const OsiRowCutDebugger *debugger = solver_->getRowCutDebugger() ;
+            if (debugger) {
+                onOptimalPath = true;
+                printf("On optimal path d\n") ;
+            }
+        }
+        int nTightened = 0;
+#ifdef COIN_HAS_CLP
+        // Pierre pointed out that this is not valid for all solvers
+        // so just do if Clp
+        if ((specialOptions_&1) != 0 && onOptimalPath) {
+            solver_->writeMpsNative("before-tighten.mps", NULL, NULL, 2);
+        }
+        if (clpSolver && (!currentNode_ || (currentNode_->depth()&2) != 0) &&
+                !solverCharacteristics_->solutionAddsCuts())
+            nTightened = clpSolver->tightenBounds();
+        if (nTightened) {
+            //printf("%d bounds tightened\n",nTightened);
+            if ((specialOptions_&1) != 0 && onOptimalPath) {
+                const OsiRowCutDebugger *debugger = solver_->getRowCutDebugger() ;
+                if (!debugger) {
+                    // tighten did something???
+                    solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
+                    solver_->writeMpsNative("infeas4.mps", NULL, NULL, 2);
+                    printf("Not on optimalpath aaaa\n");
+                    //abort();
+                    onOptimalPath = false;
+                }
+            }
+        }
+#endif
+        if (nTightened >= 0) {
+            resolve(solver_) ;
+            numberIterations_ += solver_->getIterationCount() ;
+            feasible = (solver_->isProvenOptimal() &&
+                        !solver_->isDualObjectiveLimitReached()) ;
+            if (feasible) {
+                // double check
+                double testValue = solver_->getObjSense() *
+                                   solver_->getObjValue();
+                //double cutoff = getCutoff();
+                if (bestObjective_ - getCutoffIncrement() < testValue) {
+#ifdef CLP_INVESTIGATE
+                    double value ;
+                    solver_->getDblParam(OsiDualObjectiveLimit, value) ;
+                    printf("Should cutoff as obj %.18g, best %.18g, inc %.18g - solver cutoff %.18g model cutoff %.18g\n",
+                           testValue, bestObjective_, getCutoffIncrement(),
+                           value, getCutoff());
+#endif
+                    feasible = false;
+                }
+            } else if (solver_->isAbandoned()) {
+                setMaximumSeconds(-COIN_DBL_MAX);
+            }
+#ifdef COIN_HAS_CLP
+            if (clpSolver && feasible && !numberNodes_ && false) {
+                double direction = solver_->getObjSense() ;
+                double tolerance;
+                solver_->getDblParam(OsiDualTolerance, tolerance) ;
+                double primalTolerance;
+                solver_->getDblParam(OsiPrimalTolerance, primalTolerance) ;
+
+                const double *lower = solver_->getColLower() ;
+                const double *upper = solver_->getColUpper() ;
+                const double *solution = solver_->getColSolution() ;
+                const double *reducedCost = solver_->getReducedCost() ;
+                ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+                double * rowLower = clpSimplex->rowLower();
+                double * rowUpper = clpSimplex->rowUpper();
+                int numberRows = clpSimplex->numberRows();
+                double * saveRowLower = CoinCopyOfArray(rowLower, numberRows);
+                double * saveRowUpper = CoinCopyOfArray(rowUpper, numberRows);
+                {
+                    const double * dual = clpSimplex->dualRowSolution();
+                    const double * rowActivity = clpSimplex->primalRowSolution();
+                    for (int iRow = 0 ; iRow < numberRows ; iRow++) {
+                        double djValue = direction * dual[iRow] ;
+                        double lowerValue = rowLower[iRow];
+                        double upperValue = rowUpper[iRow];
+                        if (rowActivity[iRow] < lowerValue + primalTolerance && djValue > tolerance) {
+                            rowUpper[iRow] = lowerValue;
+                            assert (clpSimplex->getRowStatus(iRow) != ClpSimplex::basic);
+                        } else if (rowActivity[iRow] > upperValue - primalTolerance && djValue < -tolerance) {
+                            rowLower[iRow] = upperValue;
+                            assert (clpSimplex->getRowStatus(iRow) != ClpSimplex::basic);
+                        }
+                    }
+                }
+                int numberColumns = solver_->getNumCols();
+                double * objective = clpSimplex->objective();
+                double * saveObj = CoinCopyOfArray(objective, numberColumns);
+                double objValue = 0.01;
+                bool someFree = false;
+                for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+                    double djValue = direction * reducedCost[iColumn] ;
+                    double lowerValue = lower[iColumn];
+                    double upperValue = upper[iColumn];
+                    if (solution[iColumn] < lowerValue + primalTolerance && djValue > tolerance) {
+                        objective[iColumn] = 1.0e8 * direction;
+                        assert (clpSimplex->getColumnStatus(iColumn) != ClpSimplex::basic);
+                    } else if (solution[iColumn] > upperValue - primalTolerance && djValue < -tolerance) {
+                        objective[iColumn] = -1.0e8 * direction;
+                        assert (clpSimplex->getColumnStatus(iColumn) != ClpSimplex::basic);
+                    } else if (lowerValue > -1.0e20 || upperValue < 1.0e20) {
+                        assert (fabs(djValue) <= tolerance);
+                        if (fabs(lowerValue) < fabs(upperValue))
+                            objective[iColumn] = objValue * direction;
+                        else
+                            objective[iColumn] = -objValue * direction;
+                        objValue += 0.01;
+                    } else {
+                        objective[iColumn] = 0.0;
+                        someFree = true;
+                    }
+                }
+                if (!someFree)
+                    clpSimplex->primal(1);
+                memcpy(objective, saveObj, numberColumns*sizeof(double));
+                delete [] saveObj;
+                memcpy(rowLower, saveRowLower, numberRows*sizeof(double));
+                delete [] saveRowLower;
+                memcpy(rowUpper, saveRowUpper, numberRows*sizeof(double));
+                delete [] saveRowUpper;
+                if (!someFree) {
+                    clpSimplex->primal(1);
+                    //assert (clpSimplex->numberIterations()<10);
+                }
+                //clpSimplex->writeMps("xx");
+                //clpSimplex->primal(1);
+                clpSolver->setWarmStart(NULL);
+            }
+#endif
+            if ((specialOptions_&1) != 0 && onOptimalPath) {
+                if (!solver_->getRowCutDebugger()) {
+                    // tighten did something???
+                    solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
+                    solver_->writeMpsNative("infeas4.mps", NULL, NULL, 2);
+                    //assert (solver_->getRowCutDebugger()) ;
+                    printf("Not on optimalpath e\n");
+                    //abort();
+                }
+            }
+        } else {
+            feasible = false;
+        }
+    }
+    if (0 && feasible) {
+        const double * lb = solver_->getColLower();
+        const double * ub = solver_->getColUpper();
+        const double * x = solver_->getColSolution();
+        const double * dj = solver_->getReducedCost();
+        int numberColumns = solver_->getNumCols();
+        for (int i = 0; i < numberColumns; i++) {
+            if (dj[i] > 1.0e-4 && ub[i] - lb[i] > 1.0e-4 && x[i] > lb[i] + 1.0e-4)
+                printf("error %d %g %g %g %g\n", i, dj[i], lb[i], x[i], ub[i]);
+            if (dj[i] < -1.0e-4 && ub[i] - lb[i] > 1.0e-4 && x[i] < ub[i] - 1.0e-4)
+                printf("error %d %g %g %g %g\n", i, dj[i], lb[i], x[i], ub[i]);
+        }
+    }
+    if (false && !feasible && continuousObjective_ < -1.0e30) {
+        // at root node - double double check
+        bool saveTakeHint;
+        OsiHintStrength saveStrength;
+        solver_->getHintParam(OsiDoDualInResolve, saveTakeHint, saveStrength);
+        if (saveTakeHint || saveStrength == OsiHintIgnore) {
+            solver_->setHintParam(OsiDoDualInResolve, false, OsiHintDo) ;
+            resolve(solver_);
+            solver_->setHintParam(OsiDoDualInResolve, saveTakeHint, saveStrength);
+            numberIterations_ += solver_->getIterationCount() ;
+            feasible = solver_->isProvenOptimal();
+            //      solver_->writeMps("infeas");
+        }
+    }
+#ifdef JJF_ZERO
+    if (cutModifier_ && feasible && !solverCharacteristics_->solutionAddsCuts()) {
+        //double increment = getDblParam(CbcModel::CbcCutoffIncrement) ;
+        double cutoff ;
+        solver_->getDblParam(OsiDualObjectiveLimit, cutoff) ;
+        double distance = fabs(cutoff - solver_->getObjValue());
+        if (distance < 10.0*trueIncrement) {
+            double offset;
+            solver_->getDblParam(OsiObjOffset, offset);
+            double objFixedValue = -offset;
+            double objValue = 0.0;
+            double direction = solver_->getObjSense();
+            const double * solution = solver_->getColSolution();
+            const double * objective = solver_->getObjCoefficients();
+            const double * columnLower = solver_->getColLower();
+            const double * columnUpper = solver_->getColUpper();
+            int numberColumns = solver_->getNumCols();
+            int increment = 0 ;
+            double multiplier = 1.0 / trueIncrement;
+            int bigIntegers = 0; // Count of large costs which are integer
+            for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                double value = solution[iColumn];
+                // make sure clean
+                value = CoinMin(value, columnUpper[iColumn]);
+                value = CoinMax(value, columnLower[iColumn]);
+                double cost = direction * objective[iColumn];
+                if (cost) {
+                    if (columnLower[iColumn] < columnUpper[iColumn]) {
+                        objValue += value * cost;
+                        value = fabs(cost) * multiplier ;
+                        if (value < 2.1e9) {
+                            int nearest = static_cast<int> (floor(value + 0.5)) ;
+                            assert (fabs(value - floor(value + 0.5)) < 1.0e-8);
+                            if (!increment)
+                                increment = nearest ;
+                            else
+                                increment = gcd(increment, nearest) ;
+                        } else {
+                            // large value - may still be multiple of 1.0
+                            value = fabs(objective[iColumn]);
+                            assert(fabs(value - floor(value + 0.5)) < 1.0e-8);
+                            bigIntegers++;
+                        }
+                    } else {
+                        // fixed
+                        objFixedValue += value * cost;
+                    }
+                }
+            }
+            if (increment) {
+                double value = increment ;
+                value /= multiplier ;
+                if (value > trueIncrement) {
+                    double x = objValue / value;
+                    x = ceil(x - 1.0e-5);
+                    x *= value;
+                    //printf("fixed %g, variable %g -> %g, sum %g - cutoff %g\n",
+                    // objFixedValue,objValue,x,x+objFixedValue,cutoff);
+                    x += objFixedValue;
+                    if (x > cutoff + 1.0e-5*fabs(cutoff) + 1.0e-5) {
+                        //printf("Node cutoff\n");
+                        feasible = false;
+                    }
+                } else {
+                    value = trueIncrement;
+                    double x = objValue / value;
+                    x = ceil(x - 1.0e-5);
+                    x *= value;
+                    x += objFixedValue;
+                    if (x > cutoff + 1.0e-5*fabs(cutoff) + 1.0e-5) {
+                        //printf("Node cutoff\n");
+                        feasible = false;
+                    }
+                }
+            }
+        }
+    }
+#endif
+
+    setPointers(solver_);
+    if (feasible && saveSolution) {
+        // called from CbcNode
+        assert (saveLower);
+        assert (saveUpper);
+        int numberColumns = solver_->getNumCols();
+        memcpy(saveSolution, solver_->getColSolution(), numberColumns*sizeof(double));
+        reserveCurrentSolution(saveSolution);
+        memcpy(saveLower, solver_->getColLower(), numberColumns*sizeof(double));
+        memcpy(saveUpper, solver_->getColUpper(), numberColumns*sizeof(double));
+    }
+#ifdef COIN_HAS_CLP
+    if (clpSolver && !feasible) {
+      // make sure marked infeasible
+      if (!clpSolver->isProvenDualInfeasible())
+        clpSolver->getModelPtr()->setProblemStatus(1);
+    }
+#endif
+    int returnStatus = feasible ? 1 : 0;
+    if (strategy_) {
+        /*
+          Possible returns from status:
+            -1:	no recommendation
+             0: treat as optimal
+             1: treat as optimal and finished (no more resolves, cuts, etc.)
+             2: treat as infeasible.
+        */
+        // user can play clever tricks here
+        int status = strategy_->status(this, parent, whereFrom);
+        if (status >= 0) {
+            if (status == 0)
+                returnStatus = 1;
+            else if (status == 1)
+                returnStatus = -1;
+            else
+                returnStatus = 0;
+        }
+    }
+    return returnStatus ;
+}
+
+
+/* Set up objects.  Only do ones whose length is in range.
+   If makeEquality true then a new model may be returned if
+   modifications had to be made, otherwise "this" is returned.
+
+   Could use Probing at continuous to extend objects
+*/
+CbcModel *
+CbcModel::findCliques(bool makeEquality,
+                      int atLeastThisMany, int lessThanThis,
+                      int /*defaultValue*/)
+{
+    // No objects are allowed to exist
+    assert(numberObjects_ == numberIntegers_ || !numberObjects_);
+    CoinPackedMatrix matrixByRow(*solver_->getMatrixByRow());
+    int numberRows = solver_->getNumRows();
+    int numberColumns = solver_->getNumCols();
+
+    // We may want to add columns
+    int numberSlacks = 0;
+    int * rows = new int[numberRows];
+    double * element = new double[numberRows];
+
+    int iRow;
+
+    findIntegers(true);
+    numberObjects_ = numberIntegers_;
+
+    int numberCliques = 0;
+    OsiObject ** object = new OsiObject * [numberRows];
+    int * which = new int[numberIntegers_];
+    char * type = new char[numberIntegers_];
+    int * lookup = new int[numberColumns];
+    int i;
+    for (i = 0; i < numberColumns; i++)
+        lookup[i] = -1;
+    for (i = 0; i < numberIntegers_; i++)
+        lookup[integerVariable_[i]] = i;
+
+    // Statistics
+    int totalP1 = 0, totalM1 = 0;
+    int numberBig = 0, totalBig = 0;
+    int numberFixed = 0;
+
+    // Row copy
+    const double * elementByRow = matrixByRow.getElements();
+    const int * column = matrixByRow.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+    const int * rowLength = matrixByRow.getVectorLengths();
+
+    // Column lengths for slacks
+    const int * columnLength = solver_->getMatrixByCol()->getVectorLengths();
+
+    const double * lower = getColLower();
+    const double * upper = getColUpper();
+    const double * rowLower = getRowLower();
+    const double * rowUpper = getRowUpper();
+    /*
+      Scan the rows, looking for individual rows that are clique constraints.
+    */
+
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        int numberP1 = 0, numberM1 = 0;
+        int j;
+        double upperValue = rowUpper[iRow];
+        double lowerValue = rowLower[iRow];
+        bool good = true;
+        int slack = -1;
+        /*
+          Does this row qualify? All variables must be binary and all coefficients
+          +/- 1.0. Variables with positive coefficients are recorded at the low end of
+          which, variables with negative coefficients the high end.
+        */
+        for (j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+            int iColumn = column[j];
+            int iInteger = lookup[iColumn];
+            if (upper[iColumn] - lower[iColumn] < 1.0e-8) {
+                // fixed
+                upperValue -= lower[iColumn] * elementByRow[j];
+                lowerValue -= lower[iColumn] * elementByRow[j];
+                continue;
+            } else if (upper[iColumn] != 1.0 || lower[iColumn] != 0.0) {
+                good = false;
+                break;
+            } else if (iInteger < 0) {
+                good = false;
+                break;
+            } else {
+                if (columnLength[iColumn] == 1)
+                    slack = iInteger;
+            }
+            if (fabs(elementByRow[j]) != 1.0) {
+                good = false;
+                break;
+            } else if (elementByRow[j] > 0.0) {
+                which[numberP1++] = iInteger;
+            } else {
+                numberM1++;
+                which[numberIntegers_-numberM1] = iInteger;
+            }
+        }
+        int iUpper = static_cast<int> (floor(upperValue + 1.0e-5));
+        int iLower = static_cast<int> (ceil(lowerValue - 1.0e-5));
+        /*
+          What do we have? If the row upper bound is greater than 1-numberM1, this
+          isn't a clique. If the row upper bound is 1-numberM1, we have the classic
+          clique (an SOS1 on binary variables, if numberM1 = 0). If the upper bound
+          equals numberM1, we can fix all variables. If the upper bound is less than
+          numberM1, we're infeasible.
+
+          A similar analysis applies using numberP1 against the lower bound.
+        */
+        int state = 0;
+        if (upperValue < 1.0e6) {
+            if (iUpper == 1 - numberM1)
+                state = 1;
+            else if (iUpper == -numberM1)
+                state = 2;
+            else if (iUpper < -numberM1)
+                state = 3;
+        }
+        if (!state && lowerValue > -1.0e6) {
+            if (-iLower == 1 - numberP1)
+                state = -1;
+            else if (-iLower == -numberP1)
+                state = -2;
+            else if (-iLower < -numberP1)
+                state = -3;
+        }
+        /*
+        What to do? If we learned nothing, move on to the next iteration. If we're
+        infeasible, we're outta here. If we decided we can fix variables, do it.
+        */
+        if (good && state) {
+            if (abs(state) == 3) {
+                // infeasible
+                numberObjects_ = -1;
+                break;
+            } else if (abs(state) == 2) {
+                // we can fix all
+                numberFixed += numberP1 + numberM1;
+                if (state > 0) {
+                    // fix all +1 at 0, -1 at 1
+                    for (i = 0; i < numberP1; i++)
+                        solver_->setColUpper(integerVariable_[which[i]], 0.0);
+                    for (i = 0; i < numberM1; i++)
+                        solver_->setColLower(integerVariable_[which[numberIntegers_-i-1]],
+                                             1.0);
+                } else {
+                    // fix all +1 at 1, -1 at 0
+                    for (i = 0; i < numberP1; i++)
+                        solver_->setColLower(integerVariable_[which[i]], 1.0);
+                    for (i = 0; i < numberM1; i++)
+                        solver_->setColUpper(integerVariable_[which[numberIntegers_-i-1]],
+                                             0.0);
+                }
+            } else {
+                /*
+                  And the final case: we have a clique constraint. If it's within the allowed
+                  size range, make a clique object.
+                */
+                int length = numberP1 + numberM1;
+                if (length >= atLeastThisMany && length < lessThanThis) {
+                    // create object
+                    bool addOne = false;
+                    int objectType;
+                    /*
+                      Choose equality (type 1) or inequality (type 0). If we're forcing equalities,
+                      add a slack.
+                    */
+                    if (iLower == iUpper) {
+                        objectType = 1;
+                    } else {
+                        if (makeEquality) {
+                            objectType = 1;
+                            element[numberSlacks] = state;
+                            rows[numberSlacks++] = iRow;
+                            addOne = true;
+                        } else {
+                            objectType = 0;
+                        }
+                    }
+                    /*
+                      Record the strong values for the variables. Variables with positive
+                      coefficients force all others when set to 1; variables with negative
+                      coefficients force when set to 0. If the clique is formed against the row
+                      lower bound, convert to the canonical form of a clique against the row
+                      upper bound.
+                    */
+                    if (state > 0) {
+                        totalP1 += numberP1;
+                        totalM1 += numberM1;
+                        for (i = 0; i < numberP1; i++)
+                            type[i] = 1;
+                        for (i = 0; i < numberM1; i++) {
+                            which[numberP1] = which[numberIntegers_-i-1];
+                            type[numberP1++] = 0;
+                        }
+                    } else {
+                        totalP1 += numberM1;
+                        totalM1 += numberP1;
+                        for (i = 0; i < numberP1; i++)
+                            type[i] = 0;
+                        for (i = 0; i < numberM1; i++) {
+                            which[numberP1] = which[numberIntegers_-i-1];
+                            type[numberP1++] = 1;
+                        }
+                    }
+                    if (addOne) {
+                        // add in slack
+                        which[numberP1] = numberIntegers_ + numberSlacks - 1;
+                        slack = numberP1;
+                        type[numberP1++] = 1;
+                    } else if (slack >= 0) {
+                        for (i = 0; i < numberP1; i++) {
+                            if (which[i] == slack) {
+                                slack = i;
+                            }
+                        }
+                    }
+                    object[numberCliques] = new CbcClique(this, objectType, numberP1,
+                                                          which, type,
+                                                          1000000 + numberCliques, slack);
+                    numberCliques++;
+                } else if (numberP1 + numberM1 >= lessThanThis) {
+                    // too big
+                    numberBig++;
+                    totalBig += numberP1 + numberM1;
+                }
+            }
+        }
+    }
+    delete [] which;
+    delete [] type;
+    delete [] lookup;
+#if COIN_DEVELOP>1
+    if (numberCliques < 0) {
+        printf("*** Problem infeasible\n");
+    } else {
+        if (numberCliques)
+            printf("%d cliques of average size %g found, %d P1, %d M1\n",
+                   numberCliques,
+                   (static_cast<double>(totalP1 + totalM1)) / (static_cast<double> numberCliques),
+                   totalP1, totalM1);
+        else
+            printf("No cliques found\n");
+        if (numberBig)
+            printf("%d large cliques ( >= %d) found, total %d\n",
+                   numberBig, lessThanThis, totalBig);
+        if (numberFixed)
+            printf("%d variables fixed\n", numberFixed);
+    }
+#endif
+    /*
+      If required, augment the constraint matrix with clique slacks. Seems like we
+      should be able to add the necessary integer objects without a complete
+      rebuild of existing integer objects, but I'd need to look further to confirm
+      that (lh, 071219). Finally, add the clique objects.
+    */
+    if (numberCliques > 0 && numberSlacks && makeEquality) {
+      COIN_DETAIL_PRINT(printf("adding %d integer slacks\n", numberSlacks));
+        // add variables to make equality rows
+        int * temp = new int[numberIntegers_+numberSlacks];
+        memcpy(temp, integerVariable_, numberIntegers_*sizeof(int));
+        // Get new model
+        CbcModel * newModel = new CbcModel(*this);
+        OsiSolverInterface * newSolver = newModel->solver();
+        for (i = 0; i < numberSlacks; i++) {
+            temp[i+numberIntegers_] = i + numberColumns;
+            int iRow = rows[i];
+            double value = element[i];
+            double lowerValue = 0.0;
+            double upperValue = 1.0;
+            double objValue  = 0.0;
+            CoinPackedVector column(1, &iRow, &value);
+            newSolver->addCol(column, lowerValue, upperValue, objValue);
+            // set integer
+            newSolver->setInteger(numberColumns + i);
+            if (value > 0)
+                newSolver->setRowLower(iRow, rowUpper[iRow]);
+            else
+                newSolver->setRowUpper(iRow, rowLower[iRow]);
+        }
+        // replace list of integers
+        for (i = 0; i < newModel->numberObjects_; i++)
+            delete newModel->object_[i];
+        newModel->numberObjects_ = 0;
+        delete [] newModel->object_;
+        newModel->object_ = NULL;
+        newModel->findIntegers(true); //Set up all integer objects
+        for (i = 0; i < numberIntegers_; i++) {
+            newModel->modifiableObject(i)->setPriority(object_[i]->priority());
+        }
+        if (originalColumns_) {
+            // old model had originalColumns
+            delete [] newModel->originalColumns_;
+            newModel->originalColumns_ = new int[numberColumns+numberSlacks];
+            memcpy(newModel->originalColumns_, originalColumns_, numberColumns*sizeof(int));
+            // mark as not in previous model
+            for (i = numberColumns; i < numberColumns + numberSlacks; i++)
+                newModel->originalColumns_[i] = -1;
+        }
+        delete [] rows;
+        delete [] element;
+        newModel->addObjects(numberCliques, object);
+        assert (ownObjects_);
+        for (; i < numberCliques; i++)
+            delete object[i];
+        delete [] object;
+        newModel->synchronizeModel();
+        return newModel;
+    } else {
+        assert (ownObjects_);
+        if (numberCliques > 0) {
+            addObjects(numberCliques, object);
+            for (; i < numberCliques; i++)
+                delete object[i];
+            synchronizeModel();
+        }
+        delete [] object;
+        delete [] rows;
+        delete [] element;
+        return this;
+    }
+}
+// Fill in useful estimates
+void
+CbcModel::pseudoShadow(int iActive)
+{
+    assert (iActive<2*8*32 && iActive> -3);
+    if (iActive == -1) {
+        if (numberNodes_) {
+            // zero out
+            for (int i = 0; i < numberObjects_; i++) {
+                CbcSimpleIntegerDynamicPseudoCost * obj1 =
+                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[i]) ;
+                if (obj1) {
+                    //assert (obj1->downShadowPrice()>0.0);
+#define P_FACTOR 1.0
+#ifndef JJF_ONE
+                    obj1->setDownShadowPrice(-P_FACTOR*obj1->downShadowPrice());
+                    obj1->setUpShadowPrice(-P_FACTOR*obj1->upShadowPrice());
+#else
+                    double pCost;
+                    double sCost;
+                    pCost = obj1->downDynamicPseudoCost();
+                    sCost = P_FACTOR * obj1->downShadowPrice();
+                    if (!obj1->numberTimesDown() || sCost > pCost)
+                        obj1->updateDownDynamicPseudoCost(sCost);
+                    obj1->setDownShadowPrice(0.0);
+                    pCost = obj1->upDynamicPseudoCost();
+                    sCost = P_FACTOR * obj1->upShadowPrice();
+                    if (!obj1->numberTimesUp() || sCost > pCost)
+                        obj1->updateUpDynamicPseudoCost(sCost);
+                    obj1->setUpShadowPrice(0.0);
+#endif
+                }
+            }
+        }
+        return;
+    }
+    bool doShadow = false;
+    if (!iActive || iActive >= 32) {
+        doShadow = true;
+        if (iActive >= 32)
+            iActive -= 32;
+    }
+    double * rowWeight = NULL;
+    double * columnWeight = NULL;
+    int numberColumns = solver_->getNumCols() ;
+    int numberRows = solver_->getNumRows() ;
+    // Column copy of matrix
+    const double * element = solver_->getMatrixByCol()->getElements();
+    const int * row = solver_->getMatrixByCol()->getIndices();
+    const CoinBigIndex * columnStart = solver_->getMatrixByCol()->getVectorStarts();
+    const int * columnLength = solver_->getMatrixByCol()->getVectorLengths();
+    const double * dual = solver_->getRowPrice();
+    const double * solution = solver_->getColSolution();
+    const double * dj = solver_->getReducedCost();
+    bool useMax = false;
+    bool useAlpha = false;
+    if (iActive) {
+        // Use Patel and Chinneck ideas
+        rowWeight = new double [numberRows];
+        columnWeight = new double [numberColumns];
+        // add in active constraints
+        double tolerance = 1.0e-5;
+        const double *rowLower = getRowLower() ;
+        const double *rowUpper = getRowUpper() ;
+        const double *rowActivity = solver_->getRowActivity();
+        const double * lower = getColLower();
+        const double * upper = getColUpper();
+        CoinZeroN(rowWeight, numberRows);
+        /* 1 A weight 1
+           2 B weight 1/sum alpha
+           3 L weight 1/number integer
+           4 M weight 1/number active integer
+           7 O weight 1/number integer and use alpha
+           8 P weight 1/number active integer and use alpha
+           9 up subtract 8 and use maximum
+        */
+        if (iActive > 8) {
+            iActive -= 8;
+            useMax = true;
+        }
+        if (iActive > 4) {
+            iActive -= 4;
+            useAlpha = true;
+        }
+        switch (iActive) {
+            // A
+        case 1:
+            for (int iRow = 0; iRow < numberRows; iRow++) {
+                if (rowActivity[iRow] > rowUpper[iRow] - tolerance ||
+                        rowActivity[iRow] < rowLower[iRow] + tolerance) {
+                    rowWeight[iRow] = 1.0;
+                }
+            }
+            break;
+            // B
+        case 2:
+            for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (upper[iColumn] > lower[iColumn]) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = start + columnLength[iColumn];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                        int iRow = row[j];
+                        rowWeight[iRow] += fabs(element[j]);
+                    }
+                }
+            }
+            for (int iRow = 0; iRow < numberRows; iRow++) {
+                if (rowWeight[iRow])
+                    rowWeight[iRow] = 1.0 / rowWeight[iRow];
+            }
+            break;
+            // L
+        case 3:
+            for (int jColumn = 0; jColumn < numberIntegers_; jColumn++) {
+                int iColumn = integerVariable_[jColumn];
+                if (upper[iColumn] > lower[iColumn]) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = start + columnLength[iColumn];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                        int iRow = row[j];
+                        rowWeight[iRow]++;
+                    }
+                }
+            }
+            for (int iRow = 0; iRow < numberRows; iRow++) {
+                if (rowWeight[iRow])
+                    rowWeight[iRow] = 1.0 / rowWeight[iRow];
+            }
+            break;
+            // M
+        case 4:
+            for (int jColumn = 0; jColumn < numberIntegers_; jColumn++) {
+                int iColumn = integerVariable_[jColumn];
+                double value = solution[iColumn];
+                if (fabs(value - floor(value + 0.5)) > 1.0e-5) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = start + columnLength[iColumn];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                        int iRow = row[j];
+                        rowWeight[iRow]++;
+                    }
+                }
+            }
+            for (int iRow = 0; iRow < numberRows; iRow++) {
+                if (rowWeight[iRow])
+                    rowWeight[iRow] = 1.0 / rowWeight[iRow];
+            }
+            break;
+        }
+        if (doShadow) {
+            for (int iRow = 0; iRow < numberRows; iRow++) {
+                rowWeight[iRow] *= dual[iRow];
+            }
+        }
+        dual = rowWeight;
+    }
+    const double *objective = solver_->getObjCoefficients() ;
+    double direction = solver_->getObjSense();
+    double * down = new double[numberColumns];
+    double * up = new double[numberColumns];
+    double upSum = 1.0e-20;
+    double downSum = 1.0e-20;
+    int numberIntegers = 0;
+    if (doShadow) {
+        // shadow prices
+        if (!useMax) {
+            for (int jColumn = 0; jColumn < numberIntegers_; jColumn++) {
+                int iColumn = integerVariable_[jColumn];
+                CoinBigIndex start = columnStart[iColumn];
+                CoinBigIndex end = start + columnLength[iColumn];
+                double upValue = 0.0;
+                double downValue = 0.0;
+                double value = direction * objective[iColumn];
+                if (value) {
+                    if (value > 0.0)
+                        upValue += value;
+                    else
+                        downValue -= value;
+                }
+                for (CoinBigIndex j = start; j < end; j++) {
+                    int iRow = row[j];
+                    value = -dual[iRow];
+                    assert (fabs(dual[iRow]) < 1.0e50);
+                    if (value) {
+                        value *= element[j];
+                        if (value > 0.0)
+                            upValue += value;
+                        else
+                            downValue -= value;
+                    }
+                }
+                up[iColumn] = upValue;
+                down[iColumn] = downValue;
+                if (solver_->isInteger(iColumn)) {
+                    if (!numberNodes_ && handler_->logLevel() > 1)
+                        printf("%d - up %g down %g cost %g\n",
+                               iColumn, upValue, downValue, objective[iColumn]);
+                    upSum += upValue;
+                    downSum += downValue;
+                    numberIntegers++;
+                }
+            }
+        } else {
+            for (int jColumn = 0; jColumn < numberIntegers_; jColumn++) {
+                int iColumn = integerVariable_[jColumn];
+                CoinBigIndex start = columnStart[iColumn];
+                CoinBigIndex end = start + columnLength[iColumn];
+                double upValue = 0.0;
+                double downValue = 0.0;
+                double value = direction * objective[iColumn];
+                if (value) {
+                    if (value > 0.0)
+                        upValue += value;
+                    else
+                        downValue -= value;
+                }
+                for (CoinBigIndex j = start; j < end; j++) {
+                    int iRow = row[j];
+                    value = -dual[iRow];
+                    if (value) {
+                        value *= element[j];
+                        if (value > 0.0)
+                            upValue = CoinMax(upValue, value);
+                        else
+                            downValue = CoinMax(downValue, -value);
+                    }
+                }
+                up[iColumn] = upValue;
+                down[iColumn] = downValue;
+                if (solver_->isInteger(iColumn)) {
+                    if (!numberNodes_ && handler_->logLevel() > 1)
+                        printf("%d - up %g down %g cost %g\n",
+                               iColumn, upValue, downValue, objective[iColumn]);
+                    upSum += upValue;
+                    downSum += downValue;
+                    numberIntegers++;
+                }
+            }
+        }
+    } else {
+        for (int jColumn = 0; jColumn < numberIntegers_; jColumn++) {
+            int iColumn = integerVariable_[jColumn];
+            CoinBigIndex start = columnStart[iColumn];
+            CoinBigIndex end = start + columnLength[iColumn];
+            double upValue = 0.0;
+            double downValue = 0.0;
+            double value = direction * objective[iColumn];
+            if (value) {
+                if (value > 0.0)
+                    upValue += value;
+                else
+                    downValue -= value;
+            }
+            double weight = 0.0;
+            for (CoinBigIndex j = start; j < end; j++) {
+                int iRow = row[j];
+                value = -dual[iRow];
+                double thisWeight = rowWeight[iRow];
+                if (useAlpha)
+                    thisWeight *= fabs(element[j]);
+                if (!useMax)
+                    weight += thisWeight;
+                else
+                    weight = CoinMax(weight, thisWeight);
+                if (value) {
+                    value *= element[j];
+                    if (value > 0.0)
+                        upValue += value;
+                    else
+                        downValue -= value;
+                }
+            }
+            columnWeight[iColumn] = weight;
+            // use dj if bigger
+            double djValue = dj[iColumn];
+            upValue = CoinMax(upValue, djValue);
+            downValue = CoinMax(downValue, -djValue);
+            up[iColumn] = upValue;
+            down[iColumn] = downValue;
+            if (solver_->isInteger(iColumn)) {
+                if (!numberNodes_ && handler_->logLevel() > 1)
+                    printf("%d - dj %g up %g down %g cost %g\n",
+                           iColumn, djValue, upValue, downValue, objective[iColumn]);
+                upSum += upValue;
+                downSum += downValue;
+                numberIntegers++;
+            }
+        }
+        if (numberIntegers) {
+            double averagePrice = (0.5 * (upSum + downSum)) / static_cast<double>(numberIntegers);
+            //averagePrice *= 0.1;
+            averagePrice *= 100.0;
+            for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                double weight = columnWeight[iColumn];
+                up[iColumn] += averagePrice * weight;
+                down[iColumn] += averagePrice * weight;
+            }
+        }
+    }
+    delete [] rowWeight;
+    delete [] columnWeight;
+    if (numberIntegers) {
+        double smallDown = 0.0001 * (downSum / static_cast<double> (numberIntegers));
+        double smallUp = 0.0001 * (upSum / static_cast<double> (numberIntegers));
+#define PSEUDO_FACTOR 5.0e-1
+        double pseudoFactor = PSEUDO_FACTOR;
+        //if (!numberNodes_)
+        //pseudoFactor=0.0;
+        for (int i = 0; i < numberObjects_; i++) {
+            CbcSimpleIntegerDynamicPseudoCost * obj1 =
+                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[i]) ;
+            if (obj1 && obj1->upShadowPrice() >= 0.0) {
+                int iColumn = obj1->columnNumber();
+                double upPseudoCost = obj1->upDynamicPseudoCost();
+                double saveUp = upPseudoCost;
+                upPseudoCost = CoinMax(pseudoFactor * upPseudoCost, smallUp);
+                upPseudoCost = CoinMax(upPseudoCost, up[iColumn]);
+                upPseudoCost = CoinMax(upPseudoCost, 0.001 * down[iColumn]);
+                obj1->setUpShadowPrice(upPseudoCost);
+                if (upPseudoCost > saveUp && !numberNodes_ && handler_->logLevel() > 1)
+                    printf("For %d up went from %g to %g\n",
+                           iColumn, saveUp, upPseudoCost);
+                double downPseudoCost = obj1->downDynamicPseudoCost();
+                double saveDown = downPseudoCost;
+                downPseudoCost = CoinMax(pseudoFactor * downPseudoCost, smallDown);
+                downPseudoCost = CoinMax(downPseudoCost, down[iColumn]);
+                downPseudoCost = CoinMax(downPseudoCost, 0.001 * up[iColumn]);
+                obj1->setDownShadowPrice(downPseudoCost);
+                if (downPseudoCost > saveDown && !numberNodes_ && handler_->logLevel() > 1)
+                    printf("For %d down went from %g to %g\n",
+                           iColumn, saveDown, downPseudoCost);
+            }
+        }
+    }
+    delete [] down;
+    delete [] up;
+}
+
+/*
+  Set branching priorities.
+
+  Setting integer priorities looks pretty robust; the call to findIntegers
+  makes sure that SimpleInteger objects are in place. Setting priorities for
+  other objects is entirely dependent on their existence, and the routine may
+  quietly fail in several directions.
+*/
+
+void
+CbcModel::passInPriorities (const int * priorities,
+                            bool ifObject)
+{
+    findIntegers(false);
+    int i;
+    if (priorities) {
+        int i0 = 0;
+        int i1 = numberObjects_ - 1;
+        if (ifObject) {
+            for (i = numberIntegers_; i < numberObjects_; i++) {
+                object_[i]->setPriority(priorities[i-numberIntegers_]);
+            }
+            i0 = numberIntegers_;
+        } else {
+            for (i = 0; i < numberIntegers_; i++) {
+                object_[i]->setPriority(priorities[i]);
+            }
+            i1 = numberIntegers_ - 1;
+        }
+        messageHandler()->message(CBC_PRIORITY,
+                                  messages())
+        << i0 << i1 << numberObjects_ << CoinMessageEol ;
+    }
+}
+
+// Delete all object information
+void
+CbcModel::deleteObjects(bool getIntegers)
+{
+    if (ownObjects_) {
+        int i;
+        for (i = 0; i < numberObjects_; i++)
+            delete object_[i];
+        delete [] object_;
+    }
+    object_ = NULL;
+    numberObjects_ = 0;
+    if (getIntegers && ownObjects_)
+        findIntegers(true);
+}
+
+/*!
+  Ensure all attached objects (OsiObjects, heuristics, and cut
+  generators) point to this model.
+*/
+void CbcModel::synchronizeModel()
+{
+    int i;
+    for (i = 0; i < numberHeuristics_; i++)
+        heuristic_[i]->setModel(this);
+    for (i = 0; i < numberObjects_; i++) {
+        CbcObject * obj =
+            dynamic_cast <CbcObject *>(object_[i]) ;
+        if (obj) {
+            obj->setModel(this);
+            obj->setPosition(i);
+        }
+    }
+    for (i = 0; i < numberCutGenerators_; i++)
+        generator_[i]->refreshModel(this);
+
+    if (!solverCharacteristics_) {
+        OsiBabSolver * solverCharacteristics = dynamic_cast<OsiBabSolver *> (solver_->getAuxiliaryInfo());
+        if (solverCharacteristics) {
+            solverCharacteristics_ = solverCharacteristics;
+        } else {
+            // replace in solver
+            OsiBabSolver defaultC;
+            solver_->setAuxiliaryInfo(&defaultC);
+            solverCharacteristics_ = dynamic_cast<OsiBabSolver *> (solver_->getAuxiliaryInfo());
+        }
+    }
+
+    solverCharacteristics_->setSolver(solver_);
+}
+
+// Fill in integers and create objects
+
+/**
+  The routine first does a scan to count the number of integer variables.
+  It then creates an array, integerVariable_, to store the indices of the
+  integer variables, and an array of `objects', one for each variable.
+
+  The scan is repeated, this time recording the index of each integer
+  variable in integerVariable_, and creating an CbcSimpleInteger object that
+  contains information about the integer variable. Initially, this is just
+  the index and upper & lower bounds.
+
+  \todo
+  Note the assumption in cbc that the first numberIntegers_ objects are
+  CbcSimpleInteger. In particular, the code which handles the startAgain
+  case assumes that if the object_ array exists it can simply replace the first
+  numberInteger_ objects. This is arguably unsafe.
+
+  I am going to re-order if necessary
+*/
+
+void
+CbcModel::findIntegers(bool startAgain, int type)
+{
+    assert(solver_);
+    /*
+      No need to do this if we have previous information, unless forced to start
+      over.
+    */
+    if (numberIntegers_ && !startAgain && object_)
+        return;
+    /*
+      Clear out the old integer variable list, then count the number of integer
+      variables.
+    */
+    delete [] integerVariable_;
+    integerVariable_ = NULL;
+    numberIntegers_ = 0;
+    int numberColumns = getNumCols();
+    int iColumn;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        if (isInteger(iColumn))
+            numberIntegers_++;
+    }
+    // Find out how many old non-integer objects there are
+    int nObjects = 0;
+    OsiObject ** oldObject = object_;
+    int iObject;
+    // also see where old ones were
+    char * mark = new char[numberColumns];
+    CoinZeroN(mark, numberColumns);
+    int iPriority = -100000;
+    for (iObject = 0; iObject < numberObjects_; iObject++) {
+        iPriority = CoinMax(iPriority, object_[iObject]->priority());
+        CbcSimpleInteger * obj =
+            dynamic_cast <CbcSimpleInteger *>(oldObject[iObject]) ;
+        if (obj) {
+            int iColumn = obj->columnNumber();
+            if (iColumn >= 0 && iColumn < numberColumns)
+                mark[iColumn] = 1;
+            delete oldObject[iObject];
+        } else {
+            oldObject[nObjects++] = oldObject[iObject];
+        }
+    }
+    // See if there any SOS
+#ifdef COIN_HAS_CLP
+    if (!nObjects) {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver && (clpSolver->numberSOS() || clpSolver->numberObjects())) {
+            // deal with sos
+            const CoinSet * setInfo = clpSolver->setInfo();
+            int numberSOS = clpSolver->numberSOS();
+            if (numberSOS) {
+                nObjects = 0;
+                delete [] oldObject;
+                oldObject = new OsiObject * [numberSOS];
+                for (int i = 0; i < numberSOS; i++) {
+                    int type = setInfo[i].setType();
+                    int n = setInfo[i].numberEntries();
+                    const int * which = setInfo[i].which();
+                    const double * weights = setInfo[i].weights();
+                    oldObject[nObjects++] = new CbcSOS(this, n, which, weights, i, type);
+                }
+            } else {
+                // objects - only works with SOS at present
+                int numberObjects = clpSolver->numberObjects();
+                nObjects = 0;
+                delete [] oldObject;
+                oldObject = new OsiObject * [numberObjects];
+                OsiObject ** osiObjects = clpSolver->objects();
+                for (int i = 0; i < numberObjects; i++) {
+                    OsiSOS * obj =
+                        dynamic_cast <OsiSOS *>(osiObjects[i]) ;
+                    if (obj) {
+                        int type = obj->setType();
+                        int n = obj->numberMembers();
+                        const int * which = obj->members();
+                        const double * weights = obj->weights();
+                        oldObject[nObjects++] = new CbcSOS(this, n, which, weights, i, type);
+                    }
+                }
+            }
+        }
+    }
+#endif
+
+    /*
+      Found any? Allocate an array to hold the indices of the integer variables.
+      Make a large enough array for all objects
+    */
+    delete [] integerVariable_;
+    object_ = new OsiObject * [numberIntegers_+nObjects];
+    numberObjects_ = numberIntegers_ + nObjects;
+    integerVariable_ = new int [numberIntegers_];
+    /*
+      Walk the variables again, filling in the indices and creating objects for
+      the integer variables. Initially, the objects hold the index and upper &
+      lower bounds.
+    */
+    numberIntegers_ = 0;
+    if (type == 2)
+        continuousPriority_ = iPriority + 1;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        if (isInteger(iColumn)) {
+            if (!type) {
+                object_[numberIntegers_] =
+                    new CbcSimpleInteger(this, iColumn);
+            } else if (type == 1) {
+                object_[numberIntegers_] =
+                    new CbcSimpleIntegerPseudoCost(this, iColumn, 0.3);
+            } else if (type == 2) {
+                object_[numberIntegers_] =
+                    new CbcSimpleInteger(this, iColumn);
+                if (mark[iColumn]) {
+                    // could up priority on costs if all costs same??
+                } else {
+                    object_[numberIntegers_]->setPriority(iPriority + 1);
+                }
+            }
+            integerVariable_[numberIntegers_++] = iColumn;
+        }
+    }
+    delete [] mark;
+    // Now append other objects
+    memcpy(object_ + numberIntegers_, oldObject, nObjects*sizeof(OsiObject *));
+    // Delete old array (just array)
+    delete [] oldObject;
+
+    if (!numberObjects_)
+        handler_->message(CBC_NOINT, messages_) << CoinMessageEol ;
+}
+/* If numberBeforeTrust >0 then we are going to use CbcBranchDynamic.
+   Scan and convert CbcSimpleInteger objects
+*/
+void
+CbcModel::convertToDynamic()
+{
+    int iObject;
+    const double * cost = solver_->getObjCoefficients();
+    bool allDynamic = true;
+    for (iObject = 0; iObject < numberObjects_; iObject++) {
+        CbcSimpleInteger * obj1 =
+            dynamic_cast <CbcSimpleInteger *>(object_[iObject]) ;
+        CbcSimpleIntegerPseudoCost * obj1a =
+            dynamic_cast <CbcSimpleIntegerPseudoCost *>(object_[iObject]) ;
+        CbcSimpleIntegerDynamicPseudoCost * obj2 =
+            dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[iObject]) ;
+        if (obj1 && !obj2) {
+            // replace
+            int iColumn = obj1->columnNumber();
+            int priority = obj1->priority();
+            int preferredWay = obj1->preferredWay();
+            double costValue = CoinMax(1.0e-5, fabs(cost[iColumn]));
+            // treat as if will cost what it says up
+            double upCost = costValue;
+            // and balance at breakeven of 0.3
+            double downCost = (0.7 * upCost) / 0.3;
+            if (obj1a) {
+                upCost = obj1a->upPseudoCost();
+                downCost = obj1a->downPseudoCost();
+            }
+            delete object_[iObject];
+            CbcSimpleIntegerDynamicPseudoCost * newObject =
+                new CbcSimpleIntegerDynamicPseudoCost(this, iColumn, 1.0e0*downCost, 1.0e0*upCost);
+            //newObject->setNumberBeforeTrust(numberBeforeTrust_);
+            newObject->setPriority(priority);
+            newObject->setPosition(iObject);
+            newObject->setPreferredWay(preferredWay);
+            object_[iObject] = newObject;
+        } else if (!obj2) {
+            CbcObject * obj3 =
+                dynamic_cast <CbcObject *>(object_[iObject]) ;
+            if (!obj3 || !obj3->optionalObject())
+                allDynamic = false;
+        } else {
+            // synchronize trust
+            //obj2->setNumberBeforeTrust(numberBeforeTrust_);
+        }
+    }
+    if (branchingMethod_) {
+        if ((branchingMethod_->whichMethod()&1) == 0 && !branchingMethod_->chooseMethod()) {
+            // Need a method which can do better
+            delete branchingMethod_;
+            branchingMethod_ = NULL;
+        }
+    }
+    if (allDynamic)
+        ownership_ |= 0x40000000;
+    if (!branchingMethod_ && allDynamic) {
+        // create one
+        branchingMethod_ = new CbcBranchDynamicDecision();
+    }
+    synchronizeNumberBeforeTrust();
+}
+// Set numberBeforeTrust in all objects
+void
+CbcModel::synchronizeNumberBeforeTrust(int type)
+{
+    int iObject;
+    for (iObject = 0; iObject < numberObjects_; iObject++) {
+        CbcSimpleIntegerDynamicPseudoCost * obj2 =
+            dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[iObject]) ;
+        if (obj2) {
+            // synchronize trust
+            if (!type) {
+                obj2->setNumberBeforeTrust(numberBeforeTrust_);
+            } else if (type == 1) {
+                int value = obj2->numberBeforeTrust();
+                value = (value * 11) / 10 + 1;
+                value = CoinMax(numberBeforeTrust_, value);
+                obj2->setNumberBeforeTrust(value);
+            } else {
+                assert (type == 2);
+                int value = obj2->numberBeforeTrust();
+                int n = CoinMax(obj2->numberTimesDown(),
+                                obj2->numberTimesUp());
+                if (n >= value) {
+		  value = CoinMin(CoinMin(n+1,3*(value+1)/2),5*numberBeforeTrust_);
+		  obj2->setNumberBeforeTrust(value);
+		}
+            }
+        }
+    }
+}
+
+/* Add in any object information (objects are cloned - owner can delete
+   originals */
+void
+CbcModel::addObjects(int numberObjects, CbcObject ** objects)
+{
+// If integers but not enough objects fudge
+    if (numberIntegers_ > numberObjects_ || !numberObjects_)
+        findIntegers(true);
+    /* But if incoming objects inherit from simple integer we just want
+       to replace */
+    int numberColumns = solver_->getNumCols();
+    /** mark is -1 if not integer, >=0 if using existing simple integer and
+        >=numberColumns if using new integer */
+    int * mark = new int[numberColumns];
+    int i;
+    for (i = 0; i < numberColumns; i++)
+        mark[i] = -1;
+    int newNumberObjects = numberObjects;
+    int newIntegers = 0;
+    for (i = 0; i < numberObjects; i++) {
+        CbcSimpleInteger * obj =
+            dynamic_cast <CbcSimpleInteger *>(objects[i]) ;
+        if (obj) {
+            int iColumn = obj->columnNumber();
+            assert (iColumn >= 0);
+            mark[iColumn] = i + numberColumns;
+            newIntegers++;
+        }
+    }
+    // and existing
+    for (i = 0; i < numberObjects_; i++) {
+        CbcSimpleInteger * obj =
+            dynamic_cast <CbcSimpleInteger *>(object_[i]) ;
+        if (obj) {
+            int iColumn = obj->columnNumber();
+            if (mark[iColumn] < 0) {
+                newIntegers++;
+                newNumberObjects++;
+                mark[iColumn] = i;
+            }
+        } else {
+            // some other object - keep
+            newNumberObjects++;
+        }
+    }
+    delete [] integerVariable_;
+    integerVariable_ = NULL;
+#if COIN_DEVELOP>1
+    if (newIntegers != numberIntegers_)
+        printf("changing number of integers from %d to %d\n",
+               numberIntegers_, newIntegers);
+#endif
+    numberIntegers_ = newIntegers;
+    integerVariable_ = new int [numberIntegers_];
+    OsiObject ** temp  = new OsiObject * [newNumberObjects];
+    // Put integers first
+    newIntegers = 0;
+    numberIntegers_ = 0;
+    for (i = 0; i < numberColumns; i++) {
+        int which = mark[i];
+        if (which >= 0) {
+            if (!isInteger(i)) {
+                newIntegers++;
+                solver_->setInteger(i);
+            }
+            if (which < numberColumns) {
+                temp[numberIntegers_] = object_[which];
+                object_[which] = NULL;
+            } else {
+                temp[numberIntegers_] = objects[which-numberColumns]->clone();
+            }
+            integerVariable_[numberIntegers_++] = i;
+        }
+    }
+#if COIN_DEVELOP>1
+    if (newIntegers)
+        printf("%d variables were declared integer\n", newIntegers);
+#endif
+    int n = numberIntegers_;
+    // Now rest of old
+    for (i = 0; i < numberObjects_; i++) {
+        if (object_[i]) {
+            CbcSimpleInteger * obj =
+                dynamic_cast <CbcSimpleInteger *>(object_[i]) ;
+            if (obj) {
+                delete object_[i];
+            } else {
+                temp[n++] = object_[i];
+            }
+        }
+    }
+    // and rest of new
+    for (i = 0; i < numberObjects; i++) {
+        CbcSimpleInteger * obj =
+            dynamic_cast <CbcSimpleInteger *>(objects[i]) ;
+        if (!obj) {
+            temp[n] = objects[i]->clone();
+            CbcObject * obj =
+                dynamic_cast <CbcObject *>(temp[n]) ;
+            if (obj)
+                obj->setModel(this);
+            n++;
+        }
+    }
+    delete [] mark;
+    assert (ownObjects_);
+    delete [] object_;
+    object_ = temp;
+    assert (n == newNumberObjects);
+    numberObjects_ = newNumberObjects;
+}
+/* Add in any object information (objects are cloned - owner can delete
+   originals */
+void
+CbcModel::addObjects(int numberObjects, OsiObject ** objects)
+{
+    // If integers but not enough objects fudge
+    if (numberIntegers_ > numberObjects_)
+        findIntegers(true);
+    /* But if incoming objects inherit from simple integer we just want
+       to replace */
+    int numberColumns = solver_->getNumCols();
+    /** mark is -1 if not integer, >=0 if using existing simple integer and
+        >=numberColumns if using new integer */
+    int * mark = new int[numberColumns];
+    int i;
+    for (i = 0; i < numberColumns; i++)
+        mark[i] = -1;
+    int newNumberObjects = numberObjects;
+    int newIntegers = 0;
+    for (i = 0; i < numberObjects; i++) {
+        CbcSimpleInteger * obj =
+            dynamic_cast <CbcSimpleInteger *>(objects[i]) ;
+        if (obj) {
+            int iColumn = obj->columnNumber();
+            mark[iColumn] = i + numberColumns;
+            newIntegers++;
+        } else {
+            OsiSimpleInteger * obj2 =
+                dynamic_cast <OsiSimpleInteger *>(objects[i]) ;
+            if (obj2) {
+                // Osi takes precedence
+                int iColumn = obj2->columnNumber();
+                mark[iColumn] = i + numberColumns;
+                newIntegers++;
+            }
+        }
+    }
+    // and existing
+    for (i = 0; i < numberObjects_; i++) {
+        CbcSimpleInteger * obj =
+            dynamic_cast <CbcSimpleInteger *>(object_[i]) ;
+        if (obj) {
+            int iColumn = obj->columnNumber();
+            if (mark[iColumn] < 0) {
+                newIntegers++;
+                newNumberObjects++;
+                mark[iColumn] = i;
+            }
+        }
+    }
+    delete [] integerVariable_;
+    integerVariable_ = NULL;
+#if COIN_DEVELOP>1
+    if (newIntegers != numberIntegers_)
+        printf("changing number of integers from %d to %d\n",
+               numberIntegers_, newIntegers);
+#endif
+    numberIntegers_ = newIntegers;
+    integerVariable_ = new int [numberIntegers_];
+    OsiObject ** temp  = new OsiObject * [newNumberObjects];
+    // Put integers first
+    newIntegers = 0;
+    numberIntegers_ = 0;
+    for (i = 0; i < numberColumns; i++) {
+        int which = mark[i];
+        if (which >= 0) {
+            if (!isInteger(i)) {
+                newIntegers++;
+                solver_->setInteger(i);
+            }
+            if (which < numberColumns) {
+                temp[numberIntegers_] = object_[which];
+                object_[which] = NULL;
+            } else {
+                temp[numberIntegers_] = objects[which-numberColumns]->clone();
+            }
+            integerVariable_[numberIntegers_++] = i;
+        }
+    }
+#if COIN_DEVELOP>1
+    if (newIntegers)
+        printf("%d variables were declared integer\n", newIntegers);
+#endif
+    int n = numberIntegers_;
+    // Now rest of old
+    for (i = 0; i < numberObjects_; i++) {
+        if (object_[i]) {
+            CbcSimpleInteger * obj =
+                dynamic_cast <CbcSimpleInteger *>(object_[i]) ;
+            if (obj) {
+                delete object_[i];
+            } else {
+                temp[n++] = object_[i];
+            }
+        }
+    }
+    // and rest of new
+    for (i = 0; i < numberObjects; i++) {
+        CbcSimpleInteger * obj =
+            dynamic_cast <CbcSimpleInteger *>(objects[i]) ;
+        OsiSimpleInteger * obj2 =
+            dynamic_cast <OsiSimpleInteger *>(objects[i]) ;
+        if (!obj && !obj2) {
+            temp[n] = objects[i]->clone();
+            CbcObject * obj =
+                dynamic_cast <CbcObject *>(temp[n]) ;
+            if (obj)
+                obj->setModel(this);
+            n++;
+        }
+    }
+    delete [] mark;
+    assert (ownObjects_);
+    delete [] object_;
+    object_ = temp;
+    assert (n == newNumberObjects);
+    numberObjects_ = newNumberObjects;
+}
+
+/**
+  This routine sets the objective cutoff value used for fathoming and
+  determining monotonic variables.
+
+  If the fathoming discipline is strict, a small tolerance is added to the
+  new cutoff. This avoids problems due to roundoff when the target value
+  is exact. The common example would be an IP with only integer variables in
+  the objective. If the target is set to the exact value z of the optimum,
+  it's possible to end up fathoming an ancestor of the solution because the
+  solver returns z+epsilon.
+
+  Determining if strict fathoming is needed is best done by analysis.
+  In cbc, that's analyseObjective. The default is false.
+
+  In cbc we always minimize so add epsilon
+*/
+
+void CbcModel::setCutoff (double value)
+
+{
+#ifdef JJF_ZERO
+    double tol = 0 ;
+    int fathomStrict = getIntParam(CbcFathomDiscipline) ;
+    if (fathomStrict == 1) {
+        solver_->getDblParam(OsiDualTolerance, tol) ;
+        tol = tol * (1 + fabs(value)) ;
+
+        value += tol ;
+    }
+#endif
+    dblParam_[CbcCurrentCutoff] = value;
+    if (solver_) {
+        // Solvers know about direction
+        double direction = solver_->getObjSense();
+        solver_->setDblParam(OsiDualObjectiveLimit, value*direction);
+    }
+}
+
+
+
+/*
+  Call this to really test if a valid solution can be feasible. The cutoff is
+  passed in as a parameter so that we don't need to worry here after swapping
+  solvers.  The solution is assumed to be numberColumns in size.  If
+  fixVariables is true then the bounds of the continuous solver are updated.
+  The routine returns the objective value determined by reoptimizing from
+  scratch. If the solution is rejected, this will be worse than the cutoff.
+
+  TODO: There's an issue with getting the correct cutoff value: We update the
+	cutoff in the regular solver, but not in continuousSolver_. But our only
+	use for continuousSolver_ is verifying candidate solutions. Would it
+	make sense to update the cutoff? Then we wouldn't need to step around
+	isDualObjectiveLimitReached().
+*/
+double
+CbcModel::checkSolution (double cutoff, double *solution,
+                         int fixVariables, double objectiveValue)
+
+{
+    if (!solverCharacteristics_->solutionAddsCuts()) {
+        // Can trust solution
+        int numberColumns = solver_->getNumCols();
+
+        /*
+          Grab the continuous solver (the pristine copy of the problem, made before
+          starting to work on the root node). Save the bounds on the variables.
+          Install the solution passed as a parameter, and copy it to the model's
+          currentSolution_.
+
+          TODO: This is a belt-and-suspenders approach. Once the code has settled
+          a bit, we can cast a critical eye here.
+        */
+        OsiSolverInterface * saveSolver = solver_;
+        if (continuousSolver_)
+            solver_ = continuousSolver_;
+        // save basis and solution
+        CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+        assert(basis != NULL);
+	double * saveSolution = CoinCopyOfArray(solver_->getColSolution(), 
+						solver_->getNumCols());
+        // move solution to continuous copy
+        solver_->setColSolution(solution);
+        // Put current solution in safe place
+        // Point to current solution
+        const double * save = testSolution_;
+        // Safe as will be const inside infeasibility()
+        testSolution_ = solver_->getColSolution();
+        //memcpy(currentSolution_,solver_->getColSolution(),
+        // numberColumns*sizeof(double));
+        //solver_->messageHandler()->setLogLevel(4);
+
+        // save original bounds
+        double * saveUpper = new double[numberColumns];
+        double * saveLower = new double[numberColumns];
+        memcpy(saveUpper, getColUpper(), numberColumns*sizeof(double));
+        memcpy(saveLower, getColLower(), numberColumns*sizeof(double));
+        // point to useful information
+        OsiBranchingInformation usefulInfo = usefulInformation();
+
+        /*
+          Run through the objects and use feasibleRegion() to set variable bounds
+          so as to fix the variables specified in the objects at their value in this
+          solution. Since the object list contains (at least) one object for every
+          integer variable, this has the effect of fixing all integer variables.
+        */
+        int i;
+        for (i = 0; i < numberObjects_; i++)
+            object_[i]->feasibleRegion(solver_, &usefulInfo);
+        // If relaxed then leave bounds on basic variables
+        if (fixVariables == -1 && (specialOptions_&16) == 0) {
+            CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis*>(saveSolver->getWarmStart()) ;
+            assert(basis != NULL);
+#ifdef JJF_ZERO //ndef CBC_OTHER_SOLVER
+            for (i = 0; i < numberObjects_; i++) {
+                CbcSimpleInteger * obj =
+                    dynamic_cast <CbcSimpleInteger *>(object_[i]) ;
+                if (obj) {
+                    int iColumn = obj->columnNumber();
+                    if (basis->getStructStatus(iColumn) == CoinWarmStartBasis::basic) {
+                        solver_->setColLower(iColumn, saveLower[iColumn]);
+                        solver_->setColUpper(iColumn, saveUpper[iColumn]);
+                    }
+                }
+            }
+#endif
+            delete basis;
+        }
+        // We can switch off check
+        if ((specialOptions_&4) == 0) {
+            if ((specialOptions_&2) == 0 && solverCharacteristics_->warmStart()) {
+                /*
+                  Remove any existing warm start information to be sure there is no
+                  residual influence on initialSolve().
+                */
+                CoinWarmStartBasis *slack =
+                    dynamic_cast<CoinWarmStartBasis *>(solver_->getEmptyWarmStart()) ;
+                solver_->setWarmStart(slack);
+                delete slack ;
+            } else {
+                if (bestSolutionBasis_.getNumStructural() == solver_->getNumCols() &&
+                        bestSolutionBasis_.getNumArtificial() == solver_->getNumRows())
+                    solver_->setWarmStart(&bestSolutionBasis_);
+            }
+            // Give a hint to do dual
+            bool saveTakeHint;
+            OsiHintStrength saveStrength;
+#ifndef NDEBUG
+            bool gotHint = (solver_->getHintParam(OsiDoDualInInitial, saveTakeHint, saveStrength));
+            assert (gotHint);
+#else
+            (solver_->getHintParam(OsiDoDualInInitial, saveTakeHint, saveStrength));
+#endif
+            solver_->setHintParam(OsiDoDualInInitial, true, OsiHintTry);
+            solver_->initialSolve();
+#ifdef JJF_ZERO
+            if (solver_->isProvenOptimal()) {
+                solver_->writeMps("feasible");
+                printf("XXXXXXXXXXXX - saving feasible\n");
+            }
+#endif
+            if (!solver_->isProvenOptimal()) {
+#if COIN_DEVELOP>1
+                printf("checkSolution infeas! Retrying with primal.\n");
+#endif
+                //bool saveTakeHint;
+                //OsiHintStrength saveStrength;
+                //bool savePrintHint;
+                //solver_->writeMps("infeas");
+                //bool gotHint = (solver_->getHintParam(OsiDoReducePrint,savePrintHint,saveStrength));
+                //gotHint = (solver_->getHintParam(OsiDoScale,saveTakeHint,saveStrength));
+                //solver_->setHintParam(OsiDoScale,false,OsiHintTry);
+                //solver_->setHintParam(OsiDoReducePrint,false,OsiHintTry) ;
+                solver_->setHintParam(OsiDoDualInInitial, false, OsiHintTry);
+                solver_->initialSolve();
+                //solver_->setHintParam(OsiDoScale,saveTakeHint,saveStrength);
+                //solver_->setHintParam(OsiDoReducePrint,savePrintHint,OsiHintTry) ;
+                // go from all slack now
+                specialOptions_ &= ~2;
+                if (!solver_->isProvenOptimal()) {
+                    CoinWarmStartBasis *slack =
+                        dynamic_cast<CoinWarmStartBasis *>(solver_->getEmptyWarmStart()) ;
+                    solver_->setWarmStart(slack);
+                    delete slack ;
+#if COIN_DEVELOP>1
+                    printf("checkSolution infeas! Retrying wihout basis and with primal.\n");
+#endif
+                    solver_->initialSolve();
+#if COIN_DEVELOP>1
+                    if (!solver_->isProvenOptimal()) {
+                        printf("checkSolution still infeas!\n");
+                    }
+#endif
+                }
+            }
+            //assert(solver_->isProvenOptimal());
+            solver_->setHintParam(OsiDoDualInInitial, saveTakeHint, saveStrength);
+            objectiveValue = solver_->getObjValue() * solver_->getObjSense();
+        }
+        bestSolutionBasis_ = CoinWarmStartBasis();
+
+        /*
+          Check that the solution still beats the objective cutoff.
+
+          If it passes, make a copy of the primal variable values and do some
+          cleanup and checks:
+          + Values of all variables are are within original bounds and values of
+          all integer variables are within tolerance of integral.
+          + There are no constraint violations.
+          There really should be no need for the check against original bounds.
+          Perhaps an opportunity for a sanity check?
+        */
+        if (objectiveValue > cutoff && objectiveValue < cutoff + 1.0e-8 + 1.0e-8*fabs(cutoff))
+            cutoff = objectiveValue; // relax
+        if ((solver_->isProvenOptimal() || (specialOptions_&4) != 0) && objectiveValue <= cutoff) {
+            memcpy(solution , solver_->getColSolution(), numberColumns*sizeof(double)) ;
+            int iColumn;
+#ifndef NDEBUG
+            double integerTolerance = getIntegerTolerance() ;
+#endif
+#if COIN_DEVELOP>1
+            const double * dj = solver_->getReducedCost();
+            const double * colLower = saveSolver->getColLower();
+            const double * colUpper = saveSolver->getColUpper();
+            int nAtLbNatural = 0;
+            int nAtUbNatural = 0;
+            int nAtLbNaturalZero = 0;
+            int nAtUbNaturalZero = 0;
+            int nAtLbFixed = 0;
+            int nAtUbFixed = 0;
+            int nAtOther = 0;
+            int nAtOtherNatural = 0;
+            int nNotNeeded = 0;
+#endif
+            for (iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+                double value = solution[iColumn] ;
+                value = CoinMax(value, saveLower[iColumn]) ;
+                value = CoinMin(value, saveUpper[iColumn]) ;
+                if (solver_->isInteger(iColumn)) {
+                    assert(fabs(value - solution[iColumn]) <= 100.0*integerTolerance) ;
+#if COIN_DEVELOP>1
+                    double value2 = floor(value + 0.5);
+                    if (dj[iColumn] < -1.0e-6) {
+                        // negative dj
+                        //assert (value2==colUpper[iColumn]);
+                        if (saveUpper[iColumn] == colUpper[iColumn]) {
+                            nAtUbNatural++;
+                            if (saveLower[iColumn] != colLower[iColumn])
+                                nNotNeeded++;
+                        } else if (saveLower[iColumn] == colUpper[iColumn]) {
+                            nAtLbFixed++;
+                        } else {
+                            nAtOther++;
+                            if (saveLower[iColumn] != colLower[iColumn] &&
+                                    saveUpper[iColumn] != colUpper[iColumn])
+                                nNotNeeded++;
+                        }
+                    } else if (dj[iColumn] > 1.0e-6) {
+                        // positive dj
+                        //assert (value2==colLower[iColumn]);
+                        if (saveLower[iColumn] == colLower[iColumn]) {
+                            nAtLbNatural++;
+                            if (saveUpper[iColumn] != colUpper[iColumn])
+                                nNotNeeded++;
+                        } else if (saveUpper[iColumn] == colLower[iColumn]) {
+                            nAtUbFixed++;
+                        } else {
+                            nAtOther++;
+                            if (saveLower[iColumn] != colLower[iColumn] &&
+                                    saveUpper[iColumn] != colUpper[iColumn])
+                                nNotNeeded++;
+                        }
+                    } else {
+                        // zero dj
+                        if (value2 == saveUpper[iColumn]) {
+                            nAtUbNaturalZero++;
+                            if (saveLower[iColumn] != colLower[iColumn])
+                                nNotNeeded++;
+                        } else if (value2 == saveLower[iColumn]) {
+                            nAtLbNaturalZero++;
+                        } else {
+                            nAtOtherNatural++;
+                            if (saveLower[iColumn] != colLower[iColumn] &&
+                                    saveUpper[iColumn] != colUpper[iColumn])
+                                nNotNeeded++;
+                        }
+                    }
+#endif
+                }
+                solution[iColumn] = value ;
+            }
+#if COIN_DEVELOP>1
+            printf("nAtLbNat %d,nAtUbNat %d,nAtLbNatZero %d,nAtUbNatZero %d,nAtLbFixed %d,nAtUbFixed %d,nAtOther %d,nAtOtherNat %d, useless %d\n",
+                   nAtLbNatural,
+                   nAtUbNatural,
+                   nAtLbNaturalZero,
+                   nAtUbNaturalZero,
+                   nAtLbFixed,
+                   nAtUbFixed,
+                   nAtOther,
+                   nAtOtherNatural, nNotNeeded);
+            //if (currentNode_)
+            //printf(" SOL at depth %d\n",currentNode_->depth());
+            //else
+            //printf(" SOL at unknown depth\n");
+#endif
+            if ((specialOptions_&16) == 0) {
+#ifdef JJF_ZERO
+                // check without scaling
+                bool saveTakeHint;
+                OsiHintStrength saveStrength;
+                solver_->getHintParam(OsiDoScale, saveTakeHint, saveStrength);
+                solver_->setHintParam(OsiDoScale, false, OsiHintTry);
+                solver_->resolve();
+                solver_->setHintParam(OsiDoScale, saveTakeHint, saveStrength);
+#endif
+                double largestInfeasibility = 0.0;
+                double primalTolerance ;
+                solver_->getDblParam(OsiPrimalTolerance, primalTolerance) ;
+                const double * rowLower = solver_->getRowLower() ;
+                const double * rowUpper = solver_->getRowUpper() ;
+                int numberRows = solver_->getNumRows() ;
+                double *rowActivity = new double[numberRows] ;
+                memset(rowActivity, 0, numberRows*sizeof(double)) ;
+                double *rowSum = new double[numberRows] ;
+                memset(rowSum, 0, numberRows*sizeof(double)) ;
+                const double * element = solver_->getMatrixByCol()->getElements();
+                const int * row = solver_->getMatrixByCol()->getIndices();
+                const CoinBigIndex * columnStart = solver_->getMatrixByCol()->getVectorStarts();
+                const int * columnLength = solver_->getMatrixByCol()->getVectorLengths();
+                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    double value = solution[iColumn];
+                    if (value) {
+                        CoinBigIndex start = columnStart[iColumn];
+                        CoinBigIndex end = start + columnLength[iColumn];
+                        for (CoinBigIndex j = start; j < end; j++) {
+                            int iRow = row[j];
+                            rowActivity[iRow] += value * element[j];
+                            rowSum[iRow] += fabs(value * element[j]);
+                        }
+                    }
+                }
+                for (i = 0 ; i < numberRows ; i++) {
+#ifdef CLP_INVESTIGATE
+                    double inf;
+                    inf = rowLower[i] - rowActivity[i];
+                    if (inf > primalTolerance)
+                        printf("Row %d inf %g sum %g %g <= %g <= %g\n",
+                               i, inf, rowSum[i], rowLower[i], rowActivity[i], rowUpper[i]);
+                    inf = rowActivity[i] - rowUpper[i];
+                    if (inf > primalTolerance)
+                        printf("Row %d inf %g sum %g %g <= %g <= %g\n",
+                               i, inf, rowSum[i], rowLower[i], rowActivity[i], rowUpper[i]);
+#endif
+                    double infeasibility = CoinMax(rowActivity[i]-rowUpper[i],
+                                                   rowLower[i]-rowActivity[i]);
+		    // but allow for errors
+		    double factor = CoinMax(1.0,rowSum[i]*1.0e-3);
+		    if (infeasibility>largestInfeasibility*factor)
+		      largestInfeasibility = infeasibility/factor;
+                }
+                delete [] rowActivity ;
+                delete [] rowSum;
+#ifdef CLP_INVESTIGATE
+                if (largestInfeasibility > 10.0*primalTolerance)
+                    printf("largest infeasibility is %g\n", largestInfeasibility);
+#endif
+                if (largestInfeasibility > 1000.0*primalTolerance) {
+                    handler_->message(CBC_NOTFEAS3, messages_)
+                    << largestInfeasibility << CoinMessageEol ;
+                    objectiveValue = 1.0e50 ;
+                }
+            }
+        } else {
+            objectiveValue = 1.0e50 ;
+        }
+        /*
+          Regardless of what we think of the solution, we may need to restore the
+          original bounds of the continuous solver. Unfortunately, const'ness
+          prevents us from simply reversing the memcpy used to make these snapshots.
+        */
+        if (fixVariables <= 0) {
+            for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+                solver_->setColLower(iColumn, saveLower[iColumn]) ;
+                solver_->setColUpper(iColumn, saveUpper[iColumn]) ;
+            }
+        }
+        delete [] saveLower;
+        delete [] saveUpper;
+
+	solver_->setColSolution(saveSolution);
+	delete [] saveSolution;
+	solver_->setWarmStart(basis);
+        delete basis ;
+        /*
+          Restore the usual solver.
+        */
+        solver_ = saveSolver;
+        testSolution_ = save;
+        return objectiveValue;
+    } else {
+        // Outer approximation or similar
+        //If this is true then the solution comes from the nlp we don't need to resolve the same nlp with ipopt
+        //solverCharacteristics_->setSolver(solver_);
+        bool solutionComesFromNlp = solverCharacteristics_->bestObjectiveValue() < cutoff;
+        double objectiveValue;
+        int numberColumns = solver_->getNumCols();
+        double *saveLower = NULL;
+        double * saveUpper = NULL;
+
+        if (! solutionComesFromNlp) { //Otherwise solution already comes from ipopt and cuts are known
+            if (fixVariables > 0) { //Will temporarily fix all integer valued var
+                // save original bounds
+                saveUpper = new double[numberColumns];
+                saveLower = new double[numberColumns];
+                memcpy(saveUpper, solver_->getColUpper(), numberColumns*sizeof(double));
+                memcpy(saveLower, solver_->getColLower(), numberColumns*sizeof(double));
+                //in any case solution should be already loaded into solver_
+                /*
+                  Run through the objects and use feasibleRegion() to set variable bounds
+                  so as to fix the variables specified in the objects at their value in this
+                  solution. Since the object list contains (at least) one object for every
+                  integer variable, this has the effect of fixing all integer variables.
+                */
+                const double * save = testSolution_;
+                testSolution_ = solution;
+                // point to useful information
+                OsiBranchingInformation usefulInfo = usefulInformation();
+                for (int i = 0; i < numberObjects_; i++)
+                    object_[i]->feasibleRegion(solver_, &usefulInfo);
+                testSolution_ = save;
+                resolve(solver_);
+            }
+
+            /*
+              Now step through the cut generators and see if any of them are flagged to
+              run when a new solution is discovered. Only global cuts are useful.
+              (The solution being evaluated may not correspond to the current location in the
+              search tree --- discovered by heuristic, for example.)
+            */
+            OsiCuts theseCuts;
+            int i;
+            int lastNumberCuts = 0;
+            // reset probing info
+            //if (probingInfo_)
+            //probingInfo_->initializeFixing();
+            for (i = 0; i < numberCutGenerators_; i++) {
+                if (generator_[i]->atSolution()) {
+                    generator_[i]->generateCuts(theseCuts, 1, solver_, NULL);
+                    int numberCuts = theseCuts.sizeRowCuts();
+                    for (int j = lastNumberCuts; j < numberCuts; j++) {
+                        const OsiRowCut * thisCut = theseCuts.rowCutPtr(j);
+                        if (thisCut->globallyValid()) {
+                            //           if ((specialOptions_&1)!=0)
+                            //           {
+                            //             /* As these are global cuts -
+                            //             a) Always get debugger object
+                            // b) Not fatal error to cutoff optimal (if we have just got optimal)
+                            // */
+                            //             const OsiRowCutDebugger *debugger = solver_->getRowCutDebuggerAlways() ;
+                            //             if (debugger)
+                            //             {
+                            //               if(debugger->invalidCut(*thisCut))
+                            //                 printf("ZZZZ Global cut - cuts off optimal solution!\n");
+                            //             }
+                            //           }
+                            // add to global list
+                            OsiRowCut newCut(*thisCut);
+                            newCut.setGloballyValid(true);
+                            newCut.mutableRow().setTestForDuplicateIndex(false);
+                            globalCuts_.addCutIfNotDuplicate(newCut) ;
+                        } else {
+                            // obviously wrong
+                            if (handler_->logLevel() > 1)
+                                printf("Cut generator %s set to run on new solution but NOT globally valid!!\n",
+                                       generator_[i]->cutGeneratorName());
+                        }
+                    }
+                }
+            }
+            //   int numberCuts = theseCuts.sizeColCuts();
+            //   for (i=0;i<numberCuts;i++) {
+            //     const OsiColCut * thisCut = theseCuts.colCutPtr(i);
+            //     if (thisCut->globallyValid()) {
+            //       // add to global list
+            //       globalCuts_.insert(*thisCut);
+            //     }
+            //   }
+            //have to retrieve the solution and its value from the nlp
+        }
+        double newObjectiveValue = cutoff;
+        if (solverCharacteristics_->solution(newObjectiveValue,
+                                             const_cast<double *> (solution),
+                                             numberColumns)) {
+            objectiveValue = newObjectiveValue;
+        } else {
+            objectiveValue = 2e50;
+        }
+        if (!solutionComesFromNlp && fixVariables > 0) {
+            for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+                solver_->setColLower(iColumn, saveLower[iColumn]) ;
+                solver_->setColUpper(iColumn, saveUpper[iColumn]) ;
+            }
+            delete [] saveLower;
+            delete [] saveUpper;
+            solver_->resolve();
+        }
+        //If the variables were fixed the cutting plane procedure may have believed that the node could be fathomed
+        //re-establish truth.- should do no harm for non nlp
+        if (!solutionComesFromNlp && fixVariables > 0)
+            solverCharacteristics_->setMipBound(-COIN_DBL_MAX);
+        return objectiveValue;
+    }
+}
+
+/*
+  Call this routine from anywhere when a solution is found. The solution
+  vector is assumed to contain one value for each structural variable.
+
+  The first action is to run checkSolution() to confirm the objective and
+  feasibility. If this check causes the solution to be rejected, we're done.
+  If fixVariables = true, the variable bounds held by the continuous solver
+  will be left fixed to the values in the solution; otherwise they are
+  restored to the original values.
+
+  If the solution is accepted, install it as the best solution.
+
+  The routine also contains a hook to run any cut generators that are flagged
+  to run when a new solution is discovered. There's a potential hazard because
+  the cut generators see the continuous solver >after< possible restoration of
+  original bounds (which may well invalidate the solution).
+*/
+
+void
+CbcModel::setBestSolution (CBC_Message how,
+                           double & objectiveValue, const double *solutionIn,
+                           int fixVariables)
+
+{
+    double * solution = CoinCopyOfArray(solutionIn, solver_->getNumCols());
+#ifdef JJF_ZERO
+    {
+        double saveOffset;
+        solver_->getDblParam(OsiObjOffset, saveOffset);
+        const double * obj = solver_->getObjCoefficients();
+        double newTrueSolutionValue = -saveOffset;
+        double newSumInfeas = 0.0;
+        int numberColumns = solver_->getNumCols();
+        for (int  i = 0 ; i < numberColumns ; i++ ) {
+            if (solver_->isInteger(i)) {
+                double value = solution[i];
+                double nearest = floor(value + 0.5);
+                newSumInfeas += fabs(value - nearest);
+            }
+            if (solution[i])
+                printf("%d obj %g val %g - total %g true\n", i, obj[i], solution[i],
+                       newTrueSolutionValue);
+            newTrueSolutionValue += obj[i] * solution[i];
+        }
+        printf("obj %g\n", newTrueSolutionValue);
+    }
+#endif
+    if (!solverCharacteristics_->solutionAddsCuts()) {
+        // Can trust solution
+        double cutoff = getCutoff();
+        if (cutoff < 1.0e30)
+            cutoff = CoinMin(cutoff, bestObjective_) ;
+
+        /*
+          Double check the solution to catch pretenders.
+        */
+        double saveObjectiveValue = objectiveValue;
+        // save basis
+        CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+        assert(basis != NULL);
+        objectiveValue = checkSolution(cutoff, solution, fixVariables, objectiveValue);
+        if (saveObjectiveValue + 1.0e-3 < objectiveValue) {
+#if COIN_DEVELOP>1
+            printf("First try at solution had objective %.16g, rechecked as %.16g\n",
+                   saveObjectiveValue, objectiveValue);
+#endif
+            // try again with basic variables with original bounds
+            // save basis
+            CoinWarmStartBasis * basis2 =
+                dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+            assert(basis2 != NULL);
+            solver_->setWarmStart(basis);
+            int numberColumns = solver_->getNumCols();
+            double * solution2 = CoinCopyOfArray(solutionIn, numberColumns);
+            double objectiveValue2 = saveObjectiveValue;
+            objectiveValue2 = checkSolution(cutoff, solution2, -1, objectiveValue2);
+#if COIN_DEVELOP>1
+            printf("Relaxed second try had objective of %.16g\n",
+                   objectiveValue2);
+#endif
+            if (objectiveValue2 + 1.0e-7 < objectiveValue) {
+                // Now check tolerances
+                double integerTolerance = dblParam_[CbcIntegerTolerance];
+                double tolerance;
+                solver_->getDblParam(OsiPrimalTolerance, tolerance) ;
+                double largestAway = 0.0;
+                int iAway = -1;
+                double largestInfeasibility = tolerance;
+#if COIN_DEVELOP>1
+                int iInfeas = -1;
+#endif
+                const double * columnLower = continuousSolver_->getColLower();
+                const double * columnUpper = continuousSolver_->getColUpper();
+                int i;
+                for (i = 0; i < numberColumns; i++) {
+                    double value = solution2[i];
+                    if (value > columnUpper[i] + largestInfeasibility) {
+#if COIN_DEVELOP>1
+                        iInfeas = i;
+#endif
+                        largestInfeasibility = value - columnUpper[i];
+                    } else if (value < columnLower[i] - largestInfeasibility) {
+#if COIN_DEVELOP>1
+                        iInfeas = i;
+#endif
+                        largestInfeasibility = columnLower[i] - value;
+                    }
+                }
+                for (i = 0; i < numberObjects_; i++) {
+                    CbcSimpleInteger * obj =
+                        dynamic_cast <CbcSimpleInteger *>(object_[i]) ;
+                    if (obj) {
+                        int iColumn = obj->columnNumber();
+                        double value = solution2[iColumn];
+                        value = fabs(floor(value + 0.5) - value);
+                        if (value > largestAway) {
+                            iAway = iColumn;
+                            largestAway = value;
+                        }
+                    }
+                }
+#if COIN_DEVELOP>1
+                if (iInfeas >= 0)
+                    printf("Largest infeasibility of %g on column %d - tolerance %g\n",
+                           largestInfeasibility, iInfeas, tolerance);
+#endif
+                if (largestAway > integerTolerance) {
+                    handler_->message(CBC_RELAXED1, messages_)
+                    << objectiveValue2
+                    << iAway
+                    << largestAway
+                    << integerTolerance
+                    << CoinMessageEol ;
+                } else {
+                    handler_->message(CBC_RELAXED2, messages_)
+                    << objectiveValue2
+                    << integerTolerance
+                    << CoinMessageEol ;
+                    // take
+                    CoinCopyN(solution2, numberColumns, solution);
+                    objectiveValue = objectiveValue2;
+                }
+            }
+            delete [] solution2;
+            solver_->setWarmStart(basis2);
+            delete basis2 ;
+        }
+        delete basis ;
+        if (objectiveValue > cutoff && objectiveValue < cutoff + 1.0e-8 + 1.0e-8*fabs(cutoff))
+            cutoff = objectiveValue; // relax
+        CbcEventHandler::CbcAction action =
+            dealWithEventHandler(CbcEventHandler::beforeSolution2,
+                                 objectiveValue, solution);
+        if (action == CbcEventHandler::killSolution) {
+            // Pretend solution never happened
+            objectiveValue = cutoff + 1.0e30;
+        }
+        if (objectiveValue > cutoff || objectiveValue > 1.0e30) {
+            if (objectiveValue > 1.0e30)
+                handler_->message(CBC_NOTFEAS1, messages_) << CoinMessageEol ;
+            else
+                handler_->message(CBC_NOTFEAS2, messages_)
+                << objectiveValue << cutoff << CoinMessageEol ;
+        } else if (objectiveValue < bestObjective_) {
+            /*
+              We have a winner. Install it as the new incumbent.
+              Bump the objective cutoff value and solution counts. Give the user the
+              good news.
+            */
+            specialOptions_ |= 256; // mark as full cut scan should be done
+            saveBestSolution(solution, objectiveValue);
+            //bestObjective_ = objectiveValue;
+            //int numberColumns = solver_->getNumCols();
+            //if (!bestSolution_)
+            //bestSolution_ = new double[numberColumns];
+            //CoinCopyN(solution,numberColumns,bestSolution_);
+
+            cutoff = bestObjective_ - dblParam_[CbcCutoffIncrement];
+            // But allow for rounding errors
+            if (dblParam_[CbcCutoffIncrement] == 1e-5) {
+#if COIN_DEVELOP>5
+                if (saveObjectiveValue + 1.0e-7 < bestObjective_)
+                    printf("First try at solution had objective %.16g, rechecked as %.16g\n",
+                           saveObjectiveValue, bestObjective_);
+#endif
+                saveObjectiveValue = CoinMax(saveObjectiveValue, bestObjective_ - 0.0000001 * fabs(bestObjective_));
+                cutoff = CoinMin(bestObjective_, saveObjectiveValue) - 1.0e-5;
+                if (fabs(cutoff + 1.0e-5 - floor(cutoff + 0.5)) < 1.0e-8)
+                    cutoff -= 2.0e-5;
+            }
+            // This is not correct - that way cutoff can go up if maximization
+            //double direction = solver_->getObjSense();
+            //setCutoff(cutoff*direction);
+            setCutoff(cutoff);
+	    // change cutoff as constraint if wanted
+	    if (cutoffRowNumber_>=0) {
+	      if (solver_->getNumRows()>cutoffRowNumber_) {
+		double offset;
+		solver_->getDblParam(OsiObjOffset, offset);
+		solver_->setRowUpper(cutoffRowNumber_,cutoff+offset);
+	      }
+	    }
+
+            if (how == CBC_ROUNDING)
+                numberHeuristicSolutions_++;
+            numberSolutions_++;
+
+            if (how != CBC_ROUNDING) {
+                handler_->message(how, messages_)
+                << bestObjective_ << numberIterations_
+                << numberNodes_ << getCurrentSeconds()
+                << CoinMessageEol;
+            } else {
+                const char * name ;
+                if (lastHeuristic_)
+                    name = lastHeuristic_->heuristicName();
+                else
+                    name = "Reduced search";
+                handler_->message(CBC_ROUNDING, messages_)
+                << bestObjective_
+                << name
+                << numberIterations_
+                << numberNodes_ << getCurrentSeconds()
+                << CoinMessageEol;
+		dealWithEventHandler(CbcEventHandler::heuristicSolution,
+				     objectiveValue, solution);
+            }
+            /*
+              Now step through the cut generators and see if any of them are flagged to
+              run when a new solution is discovered. Only global cuts are useful. (The
+              solution being evaluated may not correspond to the current location in the
+              search tree --- discovered by heuristic, for example.)
+            */
+            OsiCuts theseCuts;
+            int i;
+            int lastNumberCuts = 0;
+            // reset probing info
+            //if (probingInfo_)
+            //probingInfo_->initializeFixing();
+            for (i = 0; i < numberCutGenerators_; i++) {
+                bool generate = generator_[i]->atSolution();
+                // skip if not optimal and should be (maybe a cut generator has fixed variables)
+                if (generator_[i]->needsOptimalBasis() && !solver_->basisIsAvailable())
+                    generate = false;
+                if (generate) {
+                    generator_[i]->generateCuts(theseCuts, 1, solver_, NULL);
+                    int numberCuts = theseCuts.sizeRowCuts();
+                    for (int j = lastNumberCuts; j < numberCuts; j++) {
+                        const OsiRowCut * thisCut = theseCuts.rowCutPtr(j);
+                        if (thisCut->globallyValid()) {
+                            if ((specialOptions_&1) != 0) {
+                                /* As these are global cuts -
+                                   a) Always get debugger object
+                                   b) Not fatal error to cutoff optimal (if we have just got optimal)
+                                */
+                                const OsiRowCutDebugger *debugger = solver_->getRowCutDebuggerAlways() ;
+                                if (debugger) {
+                                    if (debugger->invalidCut(*thisCut))
+                                        printf("ZZZZ Global cut - cuts off optimal solution!\n");
+                                }
+                            }
+                            // add to global list
+                            OsiRowCut newCut(*thisCut);
+                            newCut.setGloballyValid(true);
+                            newCut.mutableRow().setTestForDuplicateIndex(false);
+                            globalCuts_.addCutIfNotDuplicate(newCut) ;
+                            generator_[i]->incrementNumberCutsInTotal();
+                        }
+                    }
+                }
+            }
+            int numberCuts = theseCuts.sizeColCuts();
+            for (i = 0; i < numberCuts; i++) {
+                const OsiColCut * thisCut = theseCuts.colCutPtr(i);
+                if (thisCut->globallyValid()) {
+                    // fix
+		    makeGlobalCut(thisCut);
+                }
+            }
+        }
+    } else {
+        // Outer approximation or similar
+        double cutoff = getCutoff() ;
+
+        /*
+          Double check the solution to catch pretenders.
+        */
+
+        int numberRowBefore = solver_->getNumRows();
+        int numberColBefore = solver_->getNumCols();
+        double *saveColSol = NULL;
+
+        CoinWarmStart * saveWs = NULL;
+        // if(how!=CBC_SOLUTION) return;
+        if (how == CBC_ROUNDING)//We don't want to make any change to solver_
+            //take a snapshot of current state
+        {
+            //save solution
+            saveColSol = new double[numberColBefore];
+            CoinCopyN(solver_->getColSolution(), numberColBefore, saveColSol);
+            //save warm start
+            saveWs = solver_->getWarmStart();
+        }
+
+        //run check solution this will eventually generate cuts
+        //if in strongBranching or heuristic will do only one cut generation iteration
+        // by fixing variables.
+        if (!fixVariables && ((how == CBC_ROUNDING) || (how == CBC_STRONGSOL)))
+            fixVariables = 1;
+        double * candidate = new double[numberColBefore];
+        CoinCopyN(solution, numberColBefore, candidate);
+        objectiveValue = checkSolution(cutoff, candidate, fixVariables, objectiveValue);
+
+        //If it was an heuristic solution we have to clean up the solver
+        if (how == CBC_ROUNDING) {
+            //delete the cuts
+            int currentNumberRowCuts = solver_->getNumRows() - numberRowBefore;
+            int currentNumberColCuts = solver_->getNumCols() - numberColBefore;
+            if (CoinMax(currentNumberColCuts, currentNumberRowCuts) > 0) {
+                int *which = new int[CoinMax(currentNumberColCuts, currentNumberRowCuts)];
+                if (currentNumberRowCuts) {
+                    for (int i = 0 ; i < currentNumberRowCuts ; i++)
+                        which[i] = i + numberRowBefore;
+
+                    solver_->deleteRows(currentNumberRowCuts, which);
+                }
+                if (currentNumberColCuts) {
+                    for (int i = 0 ; i < currentNumberColCuts ; i++)
+                        which[i] = i + numberColBefore;
+                    solver_->deleteCols(currentNumberColCuts, which);
+                }
+                delete [] which;
+            }
+            // Reset solution and warm start info
+            solver_->setColSolution(saveColSol);
+            solver_->setWarmStart(saveWs);
+            delete [] saveColSol;
+            delete saveWs;
+        }
+
+        if (objectiveValue > cutoff) {
+	    // message only for solution
+	    if (how == CBC_SOLUTION) {
+                if (!solverCharacteristics_->solutionAddsCuts()) {
+                    if (objectiveValue > 1.0e30)
+                        handler_->message(CBC_NOTFEAS1, messages_) << CoinMessageEol ;
+                    else
+                        handler_->message(CBC_NOTFEAS2, messages_)
+                        << objectiveValue << cutoff << CoinMessageEol ;
+		}
+            }
+        } else {
+            /*
+              We have a winner. Install it as the new incumbent.
+              Bump the objective cutoff value and solution counts. Give the user the
+              good news.
+              NB - Not all of this if from solve with cuts
+            */
+            saveBestSolution(candidate, objectiveValue);
+            //bestObjective_ = objectiveValue;
+            //int numberColumns = solver_->getNumCols();
+            //if (!bestSolution_)
+            //bestSolution_ = new double[numberColumns];
+            //CoinCopyN(candidate,numberColumns,bestSolution_);
+
+            // don't update if from solveWithCuts
+            if (how != CBC_SOLUTION2) {
+                if (how == CBC_ROUNDING)
+                    numberHeuristicSolutions_++;
+                cutoff = bestObjective_ - dblParam_[CbcCutoffIncrement];
+                // This is not correct - that way cutoff can go up if maximization
+                //double direction = solver_->getObjSense();
+                //setCutoff(cutoff*direction);
+                setCutoff(cutoff);
+		// change cutoff as constraint if wanted
+		if (cutoffRowNumber_>=0) {
+		  if (solver_->getNumRows()>cutoffRowNumber_) {
+		    double offset;
+		    solver_->getDblParam(OsiObjOffset, offset);
+		    solver_->setRowUpper(cutoffRowNumber_,cutoff+offset);
+		  }
+		}
+
+                numberSolutions_++;
+
+                if (how != CBC_ROUNDING) {
+                    handler_->message(how, messages_)
+                    << bestObjective_ << numberIterations_
+                    << numberNodes_ << getCurrentSeconds()
+                    << CoinMessageEol;
+                } else {
+                    assert (lastHeuristic_);
+                    const char * name = lastHeuristic_->heuristicName();
+                    handler_->message(CBC_ROUNDING, messages_)
+                    << bestObjective_
+                    << name
+                    << numberIterations_
+                    << numberNodes_ << getCurrentSeconds()
+                    << CoinMessageEol;
+                }
+            }
+        }
+        delete [] candidate;
+    }
+    delete [] solution;
+    return ;
+}
+// Deals with event handler and solution
+CbcEventHandler::CbcAction
+CbcModel::dealWithEventHandler(CbcEventHandler::CbcEvent event,
+                               double objValue,
+                               const double * solution)
+{
+    CbcEventHandler *eventHandler = getEventHandler() ;
+    if (eventHandler) {
+        // Temporarily put in best
+        double saveObj = bestObjective_;
+        int numberColumns = solver_->getNumCols();
+        double * saveSol = CoinCopyOfArray(bestSolution_, numberColumns);
+        if (!saveSol)
+            bestSolution_ = new double [numberColumns];
+        bestObjective_ = objValue;
+        memcpy(bestSolution_, solution, numberColumns*sizeof(double));
+        CbcEventHandler::CbcAction action =
+            eventHandler->event(event);
+        bestObjective_ = saveObj;
+        if (saveSol) {
+            memcpy(bestSolution_, saveSol, numberColumns*sizeof(double));
+            delete [] saveSol;
+        } else {
+            delete [] bestSolution_;
+            bestSolution_ = NULL;
+        }
+        return action;
+    } else {
+        return CbcEventHandler::noAction;
+    }
+}
+
+/* Test the current solution for feasibility.
+
+   Calculate the number of standard integer infeasibilities, then scan the
+   remaining objects to see if any of them report infeasibilities.
+
+   Currently (2003.08) the only object besides SimpleInteger is Clique, hence
+   the comments about `odd ones' infeasibilities.
+*/
+bool
+CbcModel::feasibleSolution(int & numberIntegerInfeasibilities,
+                           int & numberObjectInfeasibilities) const
+{
+    int numberUnsatisfied = 0;
+    //double sumUnsatisfied=0.0;
+    int preferredWay;
+    int j;
+    // Point to current solution
+    const double * save = testSolution_;
+    // Safe as will be const inside infeasibility()
+    testSolution_ = solver_->getColSolution();
+    // Put current solution in safe place
+    //memcpy(currentSolution_,solver_->getColSolution(),
+    // solver_->getNumCols()*sizeof(double));
+    // point to useful information
+    OsiBranchingInformation usefulInfo = usefulInformation();
+#define SIMPLE_INTEGER
+#ifdef SIMPLE_INTEGER
+    const double * solution = usefulInfo.solution_;
+    const double * lower = usefulInfo.lower_;
+    const double * upper = usefulInfo.upper_;
+    double tolerance = usefulInfo.integerTolerance_;
+#endif
+    for (j = 0; j < numberIntegers_; j++) {
+#ifndef SIMPLE_INTEGER
+        const OsiObject * object = object_[j];
+        double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+        if (infeasibility) {
+            assert (infeasibility > 0);
+            numberUnsatisfied++;
+            //sumUnsatisfied += infeasibility;
+        }
+#else
+        int iColumn = integerVariable_[j];
+        double value = solution[iColumn];
+        value = CoinMax(value, lower[iColumn]);
+        value = CoinMin(value, upper[iColumn]);
+        double nearest = floor(value + 0.5);
+        if (fabs(value - nearest) > tolerance) {
+            numberUnsatisfied++;
+        }
+#endif
+    }
+    numberIntegerInfeasibilities = numberUnsatisfied;
+    for (; j < numberObjects_; j++) {
+        const OsiObject * object = object_[j];
+        double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+        if (infeasibility) {
+            assert (infeasibility > 0);
+            numberUnsatisfied++;
+            //sumUnsatisfied += infeasibility;
+        }
+    }
+    // and restore
+    testSolution_ = save;
+    numberObjectInfeasibilities = numberUnsatisfied - numberIntegerInfeasibilities;
+    return (!numberUnsatisfied);
+}
+
+/* For all vubs see if we can tighten bounds by solving Lp's
+   type - 0 just vubs
+   1 all (could be very slow)
+   -1 just vubs where variable away from bound
+   Returns false if not feasible
+*/
+bool
+CbcModel::tightenVubs(int type, bool allowMultipleBinary, double useCutoff)
+{
+
+    CoinPackedMatrix matrixByRow(*solver_->getMatrixByRow());
+    int numberRows = solver_->getNumRows();
+    int numberColumns = solver_->getNumCols();
+
+    int iRow, iColumn;
+
+    // Row copy
+    //const double * elementByRow = matrixByRow.getElements();
+    const int * column = matrixByRow.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+    const int * rowLength = matrixByRow.getVectorLengths();
+
+    const double * colUpper = solver_->getColUpper();
+    const double * colLower = solver_->getColLower();
+    //const double * rowUpper = solver_->getRowUpper();
+    //const double * rowLower = solver_->getRowLower();
+
+    const double * objective = solver_->getObjCoefficients();
+    //double direction = solver_->getObjSense();
+    const double * colsol = solver_->getColSolution();
+
+    int numberVub = 0;
+    int * continuous = new int[numberColumns];
+    if (type >= 0) {
+        double * sort = new double[numberColumns];
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            int j;
+            int numberBinary = 0;
+            int numberUnsatisfiedBinary = 0;
+            int numberContinuous = 0;
+            int iCont = -1;
+            double weight = 1.0e30;
+            for (j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+                int iColumn = column[j];
+                if (colUpper[iColumn] - colLower[iColumn] > 1.0e-8) {
+                    if (solver_->isFreeBinary(iColumn)) {
+                        numberBinary++;
+                        /* For sort I make naive assumption:
+                           x - a * delta <=0 or
+                           -x + a * delta >= 0
+                        */
+                        if (colsol[iColumn] > colLower[iColumn] + 1.0e-6 &&
+                                colsol[iColumn] < colUpper[iColumn] - 1.0e-6) {
+                            numberUnsatisfiedBinary++;
+                            weight = CoinMin(weight, fabs(objective[iColumn]));
+                        }
+                    } else {
+                        numberContinuous++;
+                        iCont = iColumn;
+                    }
+                }
+            }
+            if (numberContinuous == 1 && numberBinary) {
+                if (numberBinary == 1 || allowMultipleBinary) {
+                    // treat as vub
+                    if (!numberUnsatisfiedBinary)
+                        weight = -1.0; // at end
+                    sort[numberVub] = -weight;
+                    continuous[numberVub++] = iCont;
+                }
+            }
+        }
+        if (type > 0) {
+            // take so many
+            CoinSort_2(sort, sort + numberVub, continuous);
+            numberVub = CoinMin(numberVub, type);
+        }
+        delete [] sort;
+    } else {
+        for (iColumn = 0; iColumn < numberColumns; iColumn++)
+            continuous[iColumn] = iColumn;
+        numberVub = numberColumns;
+    }
+    bool feasible = tightenVubs(numberVub, continuous, useCutoff);
+    delete [] continuous;
+
+    return feasible;
+}
+// This version is just handed a list of variables
+bool
+CbcModel::tightenVubs(int numberSolves, const int * which,
+                      double useCutoff)
+{
+
+    int numberColumns = solver_->getNumCols();
+
+    int iColumn;
+
+    OsiSolverInterface * solver = solver_;
+    double saveCutoff = getCutoff() ;
+
+    double * objective = new double[numberColumns];
+    memcpy(objective, solver_->getObjCoefficients(), numberColumns*sizeof(double));
+    double direction = solver_->getObjSense();
+
+    // add in objective if there is a cutoff
+    if (useCutoff < 1.0e30) {
+        // get new version of model
+        solver = solver_->clone();
+        CoinPackedVector newRow;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            solver->setObjCoeff(iColumn, 0.0); // zero out in new model
+            if (objective[iColumn])
+                newRow.insert(iColumn, direction * objective[iColumn]);
+
+        }
+        solver->addRow(newRow, -COIN_DBL_MAX, useCutoff);
+        // signal no objective
+        delete [] objective;
+        objective = NULL;
+    }
+    setCutoff(COIN_DBL_MAX);
+
+
+    bool * vub = new bool [numberColumns];
+    int iVub;
+
+    // mark vub columns
+    for (iColumn = 0; iColumn < numberColumns; iColumn++)
+        vub[iColumn] = false;
+    for (iVub = 0; iVub < numberSolves; iVub++)
+        vub[which[iVub]] = true;
+    OsiCuts cuts;
+    // First tighten bounds anyway if CglProbing there
+    CglProbing* generator = NULL;
+    int iGen;
+    // reset probing info
+    //if (probingInfo_)
+    //probingInfo_->initializeFixing();
+    for (iGen = 0; iGen < numberCutGenerators_; iGen++) {
+        generator = dynamic_cast<CglProbing*>(generator_[iGen]->generator());
+        if (generator)
+            break;
+    }
+    int numberFixed = 0;
+    int numberTightened = 0;
+    int numberFixedByProbing = 0;
+    int numberTightenedByProbing = 0;
+    int printFrequency = (numberSolves + 19) / 20; // up to 20 messages
+    int save[4] = {0, 0, 0, 0};
+    if (generator) {
+        // set to cheaper and then restore at end
+        save[0] = generator->getMaxPass();
+        save[1] = generator->getMaxProbe();
+        save[2] = generator->getMaxLook();
+        save[3] = generator->rowCuts();
+        generator->setMaxPass(1);
+        generator->setMaxProbe(10);
+        generator->setMaxLook(50);
+        generator->setRowCuts(0);
+
+        // Probing - return tight column bounds
+        CglTreeInfo info;
+        generator->generateCutsAndModify(*solver, cuts, &info);
+        const double * tightLower = generator->tightLower();
+        const double * lower = solver->getColLower();
+        const double * tightUpper = generator->tightUpper();
+        const double * upper = solver->getColUpper();
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            double newUpper = tightUpper[iColumn];
+            double newLower = tightLower[iColumn];
+            if (newUpper < upper[iColumn] - 1.0e-8*(fabs(upper[iColumn]) + 1) ||
+                    newLower > lower[iColumn] + 1.0e-8*(fabs(lower[iColumn]) + 1)) {
+                if (newUpper < newLower) {
+                    fprintf(stderr, "Problem is infeasible\n");
+                    return false;
+                }
+                if (newUpper == newLower) {
+                    numberFixed++;
+                    numberFixedByProbing++;
+                    solver->setColLower(iColumn, newLower);
+                    solver->setColUpper(iColumn, newUpper);
+                    COIN_DETAIL_PRINT(printf("Column %d, new bounds %g %g\n", iColumn,
+					     newLower, newUpper));
+                } else if (vub[iColumn]) {
+                    numberTightened++;
+                    numberTightenedByProbing++;
+                    if (!solver->isInteger(iColumn)) {
+                        // relax
+                        newLower = CoinMax(lower[iColumn],
+                                           newLower
+                                           - 1.0e-5 * (fabs(lower[iColumn]) + 1));
+                        newUpper = CoinMin(upper[iColumn],
+                                           newUpper
+                                           + 1.0e-5 * (fabs(upper[iColumn]) + 1));
+                    }
+                    solver->setColLower(iColumn, newLower);
+                    solver->setColUpper(iColumn, newUpper);
+                }
+            }
+        }
+    }
+    CoinWarmStart * ws = solver->getWarmStart();
+    double * solution = new double [numberColumns];
+    memcpy(solution, solver->getColSolution(), numberColumns*sizeof(double));
+    for (iColumn = 0; iColumn < numberColumns; iColumn++)
+        solver->setObjCoeff(iColumn, 0.0);
+    //solver->messageHandler()->setLogLevel(2);
+    for (iVub = 0; iVub < numberSolves; iVub++) {
+        iColumn = which[iVub];
+        int iTry;
+        for (iTry = 0; iTry < 2; iTry++) {
+            double saveUpper = solver->getColUpper()[iColumn];
+            double saveLower = solver->getColLower()[iColumn];
+            double value;
+            if (iTry == 1) {
+                // try all way up
+                solver->setObjCoeff(iColumn, -1.0);
+            } else {
+                // try all way down
+                solver->setObjCoeff(iColumn, 1.0);
+            }
+            solver->initialSolve();
+            setPointers(continuousSolver_);
+            value = solver->getColSolution()[iColumn];
+            bool change = false;
+            if (iTry == 1) {
+                if (value < saveUpper - 1.0e-4) {
+                    if (solver->isInteger(iColumn)) {
+                        value = floor(value + 0.00001);
+                    } else {
+                        // relax a bit
+                        value = CoinMin(saveUpper, value + 1.0e-5 * (fabs(saveUpper) + 1));
+                    }
+                    if (value - saveLower < 1.0e-7)
+                        value = saveLower; // make sure exactly same
+                    solver->setColUpper(iColumn, value);
+                    saveUpper = value;
+                    change = true;
+                }
+            } else {
+                if (value > saveLower + 1.0e-4) {
+                    if (solver->isInteger(iColumn)) {
+                        value = ceil(value - 0.00001);
+                    } else {
+                        // relax a bit
+                        value = CoinMax(saveLower, value - 1.0e-5 * (fabs(saveLower) + 1));
+                    }
+                    if (saveUpper - value < 1.0e-7)
+                        value = saveUpper; // make sure exactly same
+                    solver->setColLower(iColumn, value);
+                    saveLower = value;
+                    change = true;
+                }
+            }
+            solver->setObjCoeff(iColumn, 0.0);
+            if (change) {
+                if (saveUpper == saveLower)
+                    numberFixed++;
+                else
+                    numberTightened++;
+                int saveFixed = numberFixed;
+
+                int jColumn;
+                if (generator) {
+                    // Probing - return tight column bounds
+                    cuts = OsiCuts();
+                    CglTreeInfo info;
+                    generator->generateCutsAndModify(*solver, cuts, &info);
+                    const double * tightLower = generator->tightLower();
+                    const double * lower = solver->getColLower();
+                    const double * tightUpper = generator->tightUpper();
+                    const double * upper = solver->getColUpper();
+                    for (jColumn = 0; jColumn < numberColumns; jColumn++) {
+                        double newUpper = tightUpper[jColumn];
+                        double newLower = tightLower[jColumn];
+                        if (newUpper < upper[jColumn] - 1.0e-8*(fabs(upper[jColumn]) + 1) ||
+                                newLower > lower[jColumn] + 1.0e-8*(fabs(lower[jColumn]) + 1)) {
+                            if (newUpper < newLower) {
+                                fprintf(stderr, "Problem is infeasible\n");
+                                return false;
+                            }
+                            if (newUpper == newLower) {
+                                numberFixed++;
+                                numberFixedByProbing++;
+                                solver->setColLower(jColumn, newLower);
+                                solver->setColUpper(jColumn, newUpper);
+                            } else if (vub[jColumn]) {
+                                numberTightened++;
+                                numberTightenedByProbing++;
+                                if (!solver->isInteger(jColumn)) {
+                                    // relax
+                                    newLower = CoinMax(lower[jColumn],
+                                                       newLower
+                                                       - 1.0e-5 * (fabs(lower[jColumn]) + 1));
+                                    newUpper = CoinMin(upper[jColumn],
+                                                       newUpper
+                                                       + 1.0e-5 * (fabs(upper[jColumn]) + 1));
+                                }
+                                solver->setColLower(jColumn, newLower);
+                                solver->setColUpper(jColumn, newUpper);
+                            }
+                        }
+                    }
+                }
+                if (numberFixed > saveFixed) {
+                    // original solution may not be feasible
+                    // go back to true costs to solve if exists
+                    if (objective) {
+                        for (jColumn = 0; jColumn < numberColumns; jColumn++)
+                            solver->setObjCoeff(jColumn, objective[jColumn]);
+                    }
+                    solver->setColSolution(solution);
+                    solver->setWarmStart(ws);
+                    solver->resolve();
+                    if (!solver->isProvenOptimal()) {
+                        fprintf(stderr, "Problem is infeasible\n");
+                        return false;
+                    }
+                    delete ws;
+                    ws = solver->getWarmStart();
+                    memcpy(solution, solver->getColSolution(),
+                           numberColumns*sizeof(double));
+                    for (jColumn = 0; jColumn < numberColumns; jColumn++)
+                        solver->setObjCoeff(jColumn, 0.0);
+                }
+            }
+            solver->setColSolution(solution);
+            solver->setWarmStart(ws);
+        }
+        if (iVub % printFrequency == 0)
+            handler_->message(CBC_VUB_PASS, messages_)
+            << iVub + 1 << numberFixed << numberTightened
+            << CoinMessageEol;
+    }
+    handler_->message(CBC_VUB_END, messages_)
+    << numberFixed << numberTightened
+    << CoinMessageEol;
+    delete ws;
+    delete [] solution;
+    // go back to true costs to solve if exists
+    if (objective) {
+        for (iColumn = 0; iColumn < numberColumns; iColumn++)
+            solver_->setObjCoeff(iColumn, objective[iColumn]);
+        delete [] objective;
+    }
+    delete [] vub;
+    if (generator) {
+        /*printf("Probing fixed %d and tightened %d\n",
+           numberFixedByProbing,
+           numberTightenedByProbing);*/
+        if (generator_[iGen]->howOften() == -1 &&
+                (numberFixedByProbing + numberTightenedByProbing)*5 >
+                (numberFixed + numberTightened))
+            generator_[iGen]->setHowOften(1000000 + 1);
+        generator->setMaxPass(save[0]);
+        generator->setMaxProbe(save[1]);
+        generator->setMaxLook(save[2]);
+        generator->setRowCuts(save[3]);
+    }
+
+    if (solver != solver_) {
+        // move bounds across
+        const double * lower = solver->getColLower();
+        const double * upper = solver->getColUpper();
+        const double * lowerOrig = solver_->getColLower();
+        const double * upperOrig = solver_->getColUpper();
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            solver_->setColLower(iColumn, CoinMax(lower[iColumn], lowerOrig[iColumn]));
+            solver_->setColUpper(iColumn, CoinMin(upper[iColumn], upperOrig[iColumn]));
+        }
+        delete solver;
+    }
+    setCutoff(saveCutoff);
+    return true;
+}
+// Pass in Message handler (not deleted at end)
+void
+CbcModel::passInMessageHandler(CoinMessageHandler * handler)
+{
+    if (defaultHandler_) {
+        delete handler_;
+        handler_ = NULL;
+    }
+    defaultHandler_ = false;
+    handler_ = handler;
+    if (solver_)
+        solver_->passInMessageHandler(handler);
+    if (continuousSolver_)
+        continuousSolver_->passInMessageHandler(handler);
+    if (referenceSolver_)
+        referenceSolver_->passInMessageHandler(handler);
+}
+void
+CbcModel::passInTreeHandler(CbcTree & tree)
+{
+    delete tree_;
+    tree_ = tree.clone();
+}
+// Make sure region there
+void
+CbcModel::reserveCurrentSolution(const double * solution)
+{
+    int numberColumns = getNumCols() ;
+    if (!currentSolution_)
+        currentSolution_ = new double[numberColumns] ;
+    testSolution_ = currentSolution_;
+    if (solution)
+        memcpy(currentSolution_, solution, numberColumns*sizeof(double));
+}
+/* For passing in an CbcModel to do a sub Tree (with derived tree handlers).
+   Passed in model must exist for duration of branch and bound
+*/
+void
+CbcModel::passInSubTreeModel(CbcModel & model)
+{
+    subTreeModel_ = &model;
+}
+// For retrieving a copy of subtree model with given OsiSolver or NULL
+CbcModel *
+CbcModel::subTreeModel(OsiSolverInterface * solver) const
+{
+    const CbcModel * subModel = subTreeModel_;
+    if (!subModel)
+        subModel = this;
+    // Get new copy
+    CbcModel * newModel = new CbcModel(*subModel);
+    if (solver)
+        newModel->assignSolver(solver);
+    return newModel;
+}
+//#############################################################################
+// Set/Get Application Data
+// This is a pointer that the application can store into and retrieve
+// from the solverInterface.
+// This field is the application to optionally define and use.
+//#############################################################################
+
+void CbcModel::setApplicationData(void * appData)
+{
+    appData_ = appData;
+}
+//-----------------------------------------------------------------------------
+void * CbcModel::getApplicationData() const
+{
+    return appData_;
+}
+// Set a pointer to a row cut which will be added instead of normal branching.
+void
+CbcModel::setNextRowCut(const OsiRowCut & cut)
+{
+    nextRowCut_ = new OsiRowCut(cut);
+    nextRowCut_->setEffectiveness(COIN_DBL_MAX); // mark so will always stay
+}
+// Just update objectiveValue
+void CbcModel::setBestObjectiveValue( double objectiveValue)
+{
+    bestObjective_ = objectiveValue;
+}
+double
+CbcModel::getBestPossibleObjValue() const
+{
+    return CoinMin(bestPossibleObjective_, bestObjective_) * solver_->getObjSense() ;
+}
+// Make given rows (L or G) into global cuts and remove from lp
+void
+CbcModel::makeGlobalCuts(int number, const int * which)
+{
+    const double * rowLower = solver_->getRowLower();
+    const double * rowUpper = solver_->getRowUpper();
+
+    int numberRows = solver_->getNumRows();
+
+    // Row copy
+    const double * elementByRow = solver_->getMatrixByRow()->getElements();
+    const int * column = solver_->getMatrixByRow()->getIndices();
+    const CoinBigIndex * rowStart = solver_->getMatrixByRow()->getVectorStarts();
+    const int * rowLength = solver_->getMatrixByRow()->getVectorLengths();
+
+    // Not all rows may be good so we need new array
+    int * whichDelete = new int[numberRows];
+    int nDelete = 0;
+    for (int i = 0; i < number; i++) {
+        int iRow = which[i];
+        if (iRow >= 0 && iRow < numberRows) {
+            if (rowLower[iRow] < -1.0e20 || rowUpper[iRow] > 1.0e20) {
+                whichDelete[nDelete++] = iRow;
+                OsiRowCut  thisCut;
+                thisCut.setLb(rowLower[iRow]);
+                thisCut.setUb(rowUpper[iRow]);
+                int start = rowStart[iRow];
+                thisCut.setRow(rowLength[iRow], column + start, elementByRow + start, false);
+                thisCut.setGloballyValid(true);
+                globalCuts_.addCutIfNotDuplicate(thisCut) ;
+            }
+        }
+    }
+    if (nDelete)
+        solver_->deleteRows(nDelete, whichDelete);
+    delete [] whichDelete;
+}
+// Make given cut into a global cut
+void
+CbcModel::makeGlobalCut(const OsiRowCut * cut)
+{
+    OsiRowCut newCut(*cut);
+    newCut.setGloballyValidAsInteger(2);
+    newCut.mutableRow().setTestForDuplicateIndex(false);
+    globalCuts_.addCutIfNotDuplicate(newCut) ;
+}
+// Make given cut into a global cut
+void
+CbcModel::makeGlobalCut(const OsiRowCut & cut)
+{
+    OsiRowCut newCut(cut);
+    newCut.setGloballyValid(true);
+    newCut.mutableRow().setTestForDuplicateIndex(false);
+    globalCuts_.addCutIfNotDuplicate(newCut) ;
+}
+// Make given column cut into a global cut
+void
+CbcModel::makeGlobalCut(const OsiColCut * cut)
+{
+  const double * lower;
+  const double * upper;
+  if (topOfTree_) {
+    lower = topOfTree_->lower();
+    upper = topOfTree_->upper();
+  } else {
+    lower = solver_->getColLower();
+    upper = solver_->getColUpper();
+  }
+  int nLower=cut->lbs().getNumElements();
+  const int * indexLower=cut->lbs().getIndices();
+  const double * boundLower=cut->lbs().getElements();
+  for (int i=0;i<nLower;i++) {
+    int iColumn=indexLower[i];
+    double newValue=CoinMax(lower[iColumn],boundLower[iColumn]);
+    if (topOfTree_)
+      topOfTree_->setColLower(iColumn,newValue);
+    else
+      solver_->setColLower(iColumn,newValue);
+  }
+  int nUpper=cut->ubs().getNumElements();
+  const int * indexUpper=cut->ubs().getIndices();
+  const double * boundUpper=cut->ubs().getElements();
+  for (int i=0;i<nUpper;i++) {
+    int iColumn=indexUpper[i];
+    double newValue=CoinMin(upper[iColumn],boundUpper[iColumn]);
+    if (topOfTree_)
+      topOfTree_->setColUpper(iColumn,newValue);
+    else
+      solver_->setColUpper(iColumn,newValue);
+  }
+}
+// Make given column cut into a global cut
+void
+CbcModel::makeGlobalCut(const OsiColCut & cut)
+{
+  const double * lower;
+  const double * upper;
+  if (topOfTree_) {
+    lower = topOfTree_->lower();
+    upper = topOfTree_->upper();
+  } else {
+    lower = solver_->getColLower();
+    upper = solver_->getColUpper();
+  }
+  int nLower=cut.lbs().getNumElements();
+  const int * indexLower=cut.lbs().getIndices();
+  const double * boundLower=cut.lbs().getElements();
+  for (int i=0;i<nLower;i++) {
+    int iColumn=indexLower[i];
+    double newValue=CoinMax(lower[iColumn],boundLower[iColumn]);
+    if (topOfTree_)
+      topOfTree_->setColLower(iColumn,newValue);
+    else
+      solver_->setColLower(iColumn,newValue);
+  }
+  int nUpper=cut.ubs().getNumElements();
+  const int * indexUpper=cut.ubs().getIndices();
+  const double * boundUpper=cut.ubs().getElements();
+  for (int i=0;i<nUpper;i++) {
+    int iColumn=indexUpper[i];
+    double newValue=CoinMin(upper[iColumn],boundUpper[iColumn]);
+    if (topOfTree_)
+      topOfTree_->setColUpper(iColumn,newValue);
+    else
+      solver_->setColUpper(iColumn,newValue);
+  }
+}
+// Make partial cut into a global cut and save
+void 
+CbcModel::makePartialCut(const OsiRowCut * partialCut,
+			 const OsiSolverInterface * solver)
+{
+  // get greedy cut
+  double bSum = partialCut->lb();
+  assert (bSum<0.0);
+  if (!solver)
+    solver=solver_;
+  int nConflict = partialCut->row().getNumElements();
+  const int * column = partialCut->row().getIndices();
+  const double * element = partialCut->row().getElements();
+  double * originalLower = topOfTree_->mutableLower();
+  const double * columnLower = solver->getColLower();
+  double * originalUpper = topOfTree_->mutableUpper();
+  const double * columnUpper = solver->getColUpper();
+  int nC=nConflict;
+  while (nConflict) {
+    int iColumn = column[nConflict-1];
+    double farkasValue = element[nConflict-1];
+    double change;
+    if (farkasValue>0.0) {
+      change=farkasValue*(originalUpper[iColumn]-columnUpper[iColumn]);
+    } else {
+      change=farkasValue*(originalLower[iColumn]-columnLower[iColumn]);
+    }
+    if (bSum+change>-1.0e-4)
+      break;
+    nConflict--;
+    bSum += change;
+  }
+  OsiRowCut newCut;
+  newCut.setUb(COIN_DBL_MAX);
+  double lo=1.0;
+  double * values = new double[nConflict];
+  for (int i=0;i<nConflict;i++) {
+    int iColumn = column[i];
+    if (originalLower[iColumn]==columnLower[iColumn]) {
+      // must be at least one higher
+      values[i]=1.0;
+      lo += originalLower[iColumn];
+    } else {
+      // must be at least one lower
+      values[i]=-1.0;
+      lo -= originalUpper[iColumn];
+    }
+  }
+  newCut.setLb(lo);
+  newCut.setRow(nConflict,column,values);
+  printf("CUTa has %d (started at %d) - final bSum %g\n",nConflict,nC,bSum);
+  if (nConflict>1) {
+    if ((specialOptions_&1) != 0) {
+      const OsiRowCutDebugger *debugger = continuousSolver_->getRowCutDebugger() ;
+      if (debugger) {
+	if (debugger->invalidCut(newCut)) {
+	  continuousSolver_->applyRowCuts(1,&newCut);
+	  continuousSolver_->writeMps("bad");
+	}
+	CoinAssert (!debugger->invalidCut(newCut));
+      }
+    }
+    newCut.setGloballyValidAsInteger(2);
+    newCut.mutableRow().setTestForDuplicateIndex(false);
+    globalCuts_.addCutIfNotDuplicate(newCut) ;
+  } else {
+    // change bounds
+    int iColumn=column[0];
+    if (values[0]<0.0) {
+      // change upper bound
+      double newUpper = -lo;
+      assert (newUpper<originalUpper[iColumn]);
+      printf("Changing upper bound on %d from %g to %g\n",
+	     iColumn,originalUpper[iColumn],newUpper);
+      originalUpper[iColumn]=newUpper;
+    } else {
+      // change lower bound
+      double newLower = lo;
+      assert (newLower>originalLower[iColumn]);
+      printf("Changing lower bound on %d from %g to %g\n",
+	     iColumn,originalLower[iColumn],newLower);
+      originalLower[iColumn]=newLower;
+    }
+  }
+  // add to partial cuts
+  if (globalConflictCuts_) {
+    globalConflictCuts_->addCutIfNotDuplicateWhenGreedy(*partialCut,2);
+  }
+  delete [] values;
+}
+// Make partial cuts into global cuts
+void 
+CbcModel::makeGlobalCuts()
+{
+}
+void
+CbcModel::setNodeComparison(CbcCompareBase * compare)
+{
+    delete nodeCompare_;
+    nodeCompare_ = compare->clone();
+}
+void
+CbcModel::setNodeComparison(CbcCompareBase & compare)
+{
+    delete nodeCompare_;
+    nodeCompare_ = compare.clone();
+}
+void
+CbcModel::setProblemFeasibility(CbcFeasibilityBase * feasibility)
+{
+    delete problemFeasibility_;
+    problemFeasibility_ = feasibility->clone();
+}
+void
+CbcModel::setProblemFeasibility(CbcFeasibilityBase & feasibility)
+{
+    delete problemFeasibility_;
+    problemFeasibility_ = feasibility.clone();
+}
+// Set the strategy. Clones
+void
+CbcModel::setStrategy(CbcStrategy & strategy)
+{
+    delete strategy_;
+    strategy_ = strategy.clone();
+}
+// Increases usedInSolution for nonzeros
+void
+CbcModel::incrementUsed(const double * solution)
+{
+    // might as well mark all including continuous
+    int numberColumns = solver_->getNumCols();
+    for (int i = 0; i < numberColumns; i++) {
+        if (solution[i])
+            usedInSolution_[i]++;
+    }
+}
+// Are there numerical difficulties (for initialSolve) ?
+bool
+CbcModel::isInitialSolveAbandoned() const
+{
+    if (status_ != -1) {
+        return false;
+    } else {
+        return solver_->isAbandoned();
+    }
+}
+// Is optimality proven (for initialSolve) ?
+bool
+CbcModel::isInitialSolveProvenOptimal() const
+{
+    if (status_ != -1) {
+        return originalContinuousObjective_ < 1.0e50;
+    } else {
+        return solver_->isProvenOptimal();
+    }
+}
+// Is primal infeasiblity proven (for initialSolve) ?
+bool
+CbcModel::isInitialSolveProvenPrimalInfeasible() const
+{
+    if (status_ != -1) {
+        if (status_ == 0 && secondaryStatus_ == 7)
+            return false;
+        else
+            return originalContinuousObjective_ >= 1.0e50;
+    } else {
+        return solver_->isProvenPrimalInfeasible();
+    }
+}
+// Is dual infeasiblity proven (for initialSolve) ?
+bool
+CbcModel::isInitialSolveProvenDualInfeasible() const
+{
+    if (status_ != -1) {
+        if (status_ == 0 && secondaryStatus_ == 7)
+            return true;
+        else
+            return false;
+    } else {
+        return solver_->isProvenDualInfeasible();
+    }
+}
+// Set pointers for speed
+void
+CbcModel::setPointers(const OsiSolverInterface * solver)
+{
+    /// Pointer to array[getNumCols()] (for speed) of column lower bounds
+    cbcColLower_ = solver_->getColLower();
+    /// Pointer to array[getNumCols()] (for speed) of column upper bounds
+    cbcColUpper_ = solver_->getColUpper();
+    /// Pointer to array[getNumRows()] (for speed) of row lower bounds
+    cbcRowLower_ = solver_->getRowLower();
+    /// Pointer to array[getNumRows()] (for speed) of row upper bounds
+    cbcRowUpper_ = solver_->getRowUpper();
+    /// Pointer to array[getNumCols()] (for speed) of primal solution vector
+    cbcColSolution_ = solver_->getColSolution();
+    /// Pointer to array[getNumRows()] (for speed) of dual prices
+    cbcRowPrice_ = solver_->getRowPrice();
+    /// Get a pointer to array[getNumCols()] (for speed) of reduced costs
+    if (solverCharacteristics_ && solverCharacteristics_->reducedCostsAccurate())
+        cbcReducedCost_ = solver_->getReducedCost();
+    else
+        cbcReducedCost_ = NULL;
+    /// Pointer to array[getNumRows()] (for speed) of row activity levels.
+    cbcRowActivity_ = solver_->getRowActivity();
+    dblParam_[CbcCurrentObjectiveValue] = solver->getObjValue();
+    dblParam_[CbcCurrentMinimizationObjectiveValue] =
+        dblParam_[CbcCurrentObjectiveValue] *
+        dblParam_[CbcOptimizationDirection];
+}
+
+/*
+  Delete any existing handler and create a clone of the one supplied.
+*/
+void CbcModel::passInEventHandler (const CbcEventHandler *eventHandler)
+{
+    delete eventHandler_;
+    eventHandler_ = NULL ;
+    if (eventHandler) {
+        eventHandler_ = eventHandler->clone();
+	eventHandler_->setModel(this);
+    }
+}
+
+/*
+  CbcEventHandler* CbcModel::eventHandler is inlined in CbcModel.hpp.
+*/
+
+// Encapsulates solver resolve
+int
+CbcModel::resolve(OsiSolverInterface * solver)
+{
+    numberSolves_++;
+#ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver);
+#endif
+#ifdef CLIQUE_ANALYSIS
+    if (probingInfo_ && currentDepth_ > 0) {
+        int nFix = probingInfo_->fixColumns(*solver);
+        if (nFix < 0) {
+#ifdef COIN_HAS_CLP
+            if (clpSolver)
+                clpSolver->getModelPtr()->setProblemStatus(1);
+#endif
+            return 0;
+        }
+    }
+#endif
+#ifdef COIN_HAS_CLP
+    if (clpSolver) {
+        /*bool takeHint;
+        OsiHintStrength strength;
+        bool gotHint = (clpSolver->getHintParam(OsiDoDualInResolve,takeHint,strength));
+        assert (gotHint);
+        int algorithm=-1;
+        if (strength!=OsiHintIgnore)
+          algorithm = takeHint ? -1 : 1;
+          assert (algorithm==-1);*/
+        //clpSolver->setHintParam(OsiDoDualInResolve,true,OsiHintTry);
+        ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+        int save = clpSimplex->specialOptions();
+	if ((moreSpecialOptions_&8388608)==0)
+	  clpSimplex->setSpecialOptions(save | 0x11000000); // say is Cbc (and in branch and bound)
+	else
+	  clpSimplex->setSpecialOptions(save | 0x11200000); // say is Cbc (and in branch and bound - but save ray)
+        int save2 = clpSolver->specialOptions();
+        if (false && (save2&2048) == 0) {
+            // see if worthwhile crunching
+            int nFixed = 0;
+            const double * columnLower = clpSimplex->columnLower();
+            const double * columnUpper = clpSimplex->columnUpper();
+            for (int i = 0; i < numberIntegers_; i++) {
+                int iColumn = integerVariable_[i];
+                if (columnLower[iColumn] == columnUpper[iColumn])
+                    nFixed++;
+            }
+            if (nFixed*20 < clpSimplex->numberColumns()) {
+                double d = nFixed;
+                printf("%d fixed out of %d - ratio %g\n",
+                       nFixed,
+                       clpSimplex->numberColumns(),
+                       d / clpSimplex->numberColumns());
+                clpSolver->setSpecialOptions(save2 | 2048);
+            }
+        }
+        clpSolver->resolve();
+        if (!numberNodes_) {
+            double error = CoinMax(clpSimplex->largestDualError(),
+                                   clpSimplex->largestPrimalError());
+            if (error > 1.0e-2 || !clpSolver->isProvenOptimal()) {
+#ifdef CLP_INVESTIGATE
+                printf("Problem was %s largest dual error %g largest primal %g - safer cuts\n",
+                       clpSolver->isProvenOptimal() ? "optimal" : "!infeasible",
+                       clpSimplex->largestDualError(),
+                       clpSimplex->largestPrimalError());
+#endif
+                if (!clpSolver->isProvenOptimal()) {
+                    clpSolver->setSpecialOptions(save2 | 2048);
+                    clpSimplex->allSlackBasis(true);
+		    clpSolver->resolve();
+		    if (!clpSolver->isProvenOptimal()) {
+		         bool takeHint;
+			 OsiHintStrength strength;
+			 clpSolver->getHintParam(OsiDoDualInResolve, takeHint, strength);
+			 clpSolver->setHintParam(OsiDoDualInResolve, false, OsiHintDo);
+			 clpSolver->resolve();
+			 clpSolver->setHintParam(OsiDoDualInResolve, takeHint, strength);
+		    }
+                }
+                // make cuts safer
+                for (int iCutGenerator = 0; iCutGenerator < numberCutGenerators_; iCutGenerator++) {
+                    CglCutGenerator * generator = generator_[iCutGenerator]->generator();
+                    CglGomory * cgl1 = dynamic_cast<CglGomory *>(generator);
+                    if (cgl1) {
+                        cgl1->setLimitAtRoot(cgl1->getLimit());
+                    }
+                    CglTwomir * cgl2 = dynamic_cast<CglTwomir *>(generator);
+                    if (cgl2) {
+                        generator_[iCutGenerator]->setHowOften(-100);
+                    }
+                }
+            }
+        }
+        clpSolver->setSpecialOptions(save2);
+#ifdef CLP_INVESTIGATE
+        if (clpSimplex->numberIterations() > 1000)
+            printf("node %d took %d iterations\n", numberNodes_, clpSimplex->numberIterations());
+#endif
+        clpSimplex->setSpecialOptions(save);
+	if (clpSimplex->status()==4)
+	    clpSimplex->setProblemStatus(1);
+    } else {
+        solver->resolve();
+    }
+#else
+    solver->resolve();
+#endif
+    return solver->isProvenOptimal() ? 1 : 0;
+}
+#ifdef CLP_RESOLVE
+// Special purpose resolve
+int 
+CbcModel::resolveClp(OsiClpSolverInterface * clpSolver, int type)
+{
+    numberSolves_++;
+    ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+    int save = clpSimplex->specialOptions();
+    clpSimplex->setSpecialOptions(save | 0x11000000); // say is Cbc (and in branch and bound)
+    int save2 = clpSolver->specialOptions();
+    clpSolver->resolve();
+    if (!numberNodes_) {
+      double error = CoinMax(clpSimplex->largestDualError(),
+			     clpSimplex->largestPrimalError());
+      if (error > 1.0e-2 || !clpSolver->isProvenOptimal()) {
+#ifdef CLP_INVESTIGATE
+	printf("Problem was %s largest dual error %g largest primal %g - safer cuts\n",
+	       clpSolver->isProvenOptimal() ? "optimal" : "!infeasible",
+	       clpSimplex->largestDualError(),
+	       clpSimplex->largestPrimalError());
+#endif
+	if (!clpSolver->isProvenOptimal()) {
+	  clpSolver->setSpecialOptions(save2 | 2048);
+	  clpSimplex->allSlackBasis(true);
+	  clpSolver->resolve();
+	  if (!clpSolver->isProvenOptimal()) {
+	    bool takeHint;
+	    OsiHintStrength strength;
+	    clpSolver->getHintParam(OsiDoDualInResolve, takeHint, strength);
+	    clpSolver->setHintParam(OsiDoDualInResolve, false, OsiHintDo);
+	    clpSolver->resolve();
+	    clpSolver->setHintParam(OsiDoDualInResolve, takeHint, strength);
+	  }
+	}
+	// make cuts safer
+	for (int iCutGenerator = 0; iCutGenerator < numberCutGenerators_; iCutGenerator++) {
+	  CglCutGenerator * generator = generator_[iCutGenerator]->generator();
+	  CglGomory * cgl1 = dynamic_cast<CglGomory *>(generator);
+	  if (cgl1) {
+	    cgl1->setLimitAtRoot(cgl1->getLimit());
+	  }
+	  CglTwomir * cgl2 = dynamic_cast<CglTwomir *>(generator);
+	  if (cgl2) {
+	    generator_[iCutGenerator]->setHowOften(-100);
+	  }
+	}
+      }
+    }
+    clpSolver->setSpecialOptions(save2);
+#ifdef CLP_INVESTIGATE
+    if (clpSimplex->numberIterations() > 1000)
+      printf("node %d took %d iterations\n", numberNodes_, clpSimplex->numberIterations());
+#endif
+    if (type==0 && clpSolver->isProvenOptimal()) {
+      ClpSimplex newModel(*clpSimplex);
+      newModel.primal();
+      int numberColumns = newModel.numberColumns();
+      int numberRows = newModel.numberRows();
+      double * obj = new double [numberColumns];
+      int * which = new int [numberColumns];
+      const double * solution = clpSimplex->primalColumnSolution();
+      double rhs=1.0e-8;
+      int numberObj=0;
+      double integerTolerance = getDblParam(CbcIntegerTolerance) ;
+      double * objective = newModel.objective();
+      for (int i=0;i<numberColumns;i++) {
+	if (objective[i]) {
+	  rhs += objective[i]*solution[i];
+	  obj[numberObj]=objective[i];
+	  which[numberObj++]=i;
+	  objective[i]=0.0;
+	}
+      }
+      if (numberObj) {
+	newModel.addRow(numberObj,which,obj,-COIN_DBL_MAX,rhs);
+      }
+      delete [] obj;
+      delete [] which;
+      double * lower = newModel.columnLower();
+      double * upper = newModel.columnUpper();
+      int numberInf = 0;
+      int numberLb = 0;
+      int numberUb = 0;
+      int numberInt = 0;
+      double sumInf=0.0;
+      for (int i=0;i<numberIntegers_;i++) {
+	int iSequence = integerVariable_[i];
+	double value = solution[iSequence];
+	value = CoinMax(value, lower[iSequence]);
+	value = CoinMin(value, upper[iSequence]);
+	double nearest = floor(value + 0.5);
+	if (value<lower[iSequence]+integerTolerance) {
+	  objective[iSequence]=1.0;
+	  numberLb++;
+	} else if (value>upper[iSequence]-integerTolerance) {
+	  objective[iSequence]=-1.0;
+	  numberUb++;
+	} else if (fabs(value - nearest) <= integerTolerance) {
+	  // fix??
+	  lower[iSequence]=nearest;
+	  upper[iSequence]=nearest;
+	  numberInt++;
+	} else {
+	  lower[iSequence]=floor(value);
+	  upper[iSequence]=ceil(value);
+	  if (value>nearest) {
+	    objective[iSequence]=1.0;
+	    sumInf += value-nearest;
+	  } else {
+	    objective[iSequence]=-1.0;
+	    sumInf -= value-nearest;
+	  }
+	  numberInf++;
+	}
+      }
+      printf("XX %d inf (sum %g), %d at lb %d at ub %d other integer\n",
+	     numberInf,sumInf,numberLb,numberUb,numberInt);
+      if (numberInf) {
+	newModel.primal(1);
+	if (!newModel.isProvenOptimal()) {
+	  printf("not optimal - scaling issue - switch off\n");
+	  clpSimplex->setSpecialOptions(save);
+	  if (clpSimplex->status()==4)
+	    clpSimplex->setProblemStatus(1);
+	  return clpSolver->isProvenOptimal() ? 1 : 0;
+	}
+	//newModel.writeMps("bad.mps");
+	//assert (newModel.isProvenOptimal());
+	printf("%d iterations\n",newModel.numberIterations());
+	int numberInf2 = 0;
+	int numberLb2 = 0;
+	int numberUb2 = 0;
+	int numberInt2 = 0;
+	double sumInf2=0.0;
+	const double * solution = newModel.primalColumnSolution();
+	const double * lower = clpSimplex->columnLower();
+	const double * upper = clpSimplex->columnUpper();
+	for (int i=0;i<numberIntegers_;i++) {
+	  int iSequence = integerVariable_[i];
+	  double value = solution[iSequence];
+	  value = CoinMax(value, lower[iSequence]);
+	  value = CoinMin(value, upper[iSequence]);
+	  double nearest = floor(value + 0.5);
+	  if (value<lower[iSequence]+integerTolerance) {
+	    numberLb2++;
+	  } else if (value>upper[iSequence]-integerTolerance) {
+	    numberUb2++;
+	  } else if (fabs(value - nearest) <= integerTolerance) {
+	    numberInt2++;
+	  } else {
+	    if (value>nearest) {
+	      sumInf2 += value-nearest;
+	    } else {
+	      sumInf2 -= value-nearest;
+	    }
+	    numberInf2++;
+	  }
+	}
+	printf("XXX %d inf (sum %g), %d at lb %d at ub %d other integer\n",
+	       numberInf2,sumInf2,numberLb2,numberUb2,numberInt2);
+	if (sumInf2<sumInf*0.95) {
+	  printf("XXXX suminf reduced from %g (%d) to %g (%d)\n",
+		 sumInf,numberInf,sumInf2,numberInf2);
+	  if (numberObj) {
+	    newModel.deleteRows(1,&numberRows);
+	  }
+	  memcpy(newModel.objective(),
+		 clpSimplex->objective(),
+		 numberColumns*sizeof(double));
+	  memcpy(newModel.columnLower(),
+		 clpSimplex->columnLower(),
+		 numberColumns*sizeof(double));
+	  memcpy(newModel.columnUpper(),
+		 clpSimplex->columnUpper(),
+		 numberColumns*sizeof(double));
+	  newModel.setClpScaledMatrix(NULL);
+	  newModel.primal(1);
+	  printf("%d iterations\n",newModel.numberIterations());
+	  int numberInf3 = 0;
+	  int numberLb3 = 0;
+	  int numberUb3 = 0;
+	  int numberInt3 = 0;
+	  double sumInf3=0.0;
+	  const double * solution = newModel.primalColumnSolution();
+	  const double * lower = clpSimplex->columnLower();
+	  const double * upper = clpSimplex->columnUpper();
+	  for (int i=0;i<numberIntegers_;i++) {
+	    int iSequence = integerVariable_[i];
+	    double value = solution[iSequence];
+	    value = CoinMax(value, lower[iSequence]);
+	    value = CoinMin(value, upper[iSequence]);
+	    double nearest = floor(value + 0.5);
+	    if (value<lower[iSequence]+integerTolerance) {
+	      numberLb3++;
+	    } else if (value>upper[iSequence]-integerTolerance) {
+	      numberUb3++;
+	    } else if (fabs(value - nearest) <= integerTolerance) {
+	      numberInt3++;
+	    } else {
+	      if (value>nearest) {
+		sumInf3 += value-nearest;
+	      } else {
+		sumInf3 -= value-nearest;
+	      }
+	      numberInf3++;
+	    }
+	  }
+	  printf("XXXXX %d inf (sum %g), %d at lb %d at ub %d other integer\n",
+		 numberInf3,sumInf3,numberLb3,numberUb3,numberInt3);
+	  if (sumInf3<sumInf*0.95) {
+	    memcpy(clpSimplex->primalColumnSolution(),
+		   newModel.primalColumnSolution(),
+		   numberColumns*sizeof(double));
+	    memcpy(clpSimplex->dualColumnSolution(),
+		   newModel.dualColumnSolution(),
+		   numberColumns*sizeof(double));
+	    memcpy(clpSimplex->primalRowSolution(),
+		   newModel.primalRowSolution(),
+		   numberRows*sizeof(double));
+	    memcpy(clpSimplex->dualRowSolution(),
+		   newModel.dualRowSolution(),
+		   numberRows*sizeof(double));
+	    memcpy(clpSimplex->statusArray(),
+		   newModel.statusArray(),
+		   (numberColumns+numberRows)*sizeof(unsigned char));
+	    clpSolver->setWarmStart(NULL);
+	  }
+	}
+      }
+    }
+    clpSimplex->setSpecialOptions(save);
+    if (clpSimplex->status()==4)
+      clpSimplex->setProblemStatus(1);
+    return clpSolver->isProvenOptimal() ? 1 : 0;
+}
+#endif
+/*!
+    \todo It'd be really nice if there were an overload for this method that
+	  allowed a separate value for the underlying solver's log level. The
+	  overload could be coded to allow an increase in the log level of the
+	  underlying solver.
+
+	  It's worth contemplating whether OSI should have a setLogLevel method
+	  that's more specific than the hint mechanism.
+*/
+
+// Set log level
+void
+CbcModel::setLogLevel(int value)
+{
+    handler_->setLogLevel(value);
+    // Reduce print out in Osi
+    if (solver_) {
+        int oldLevel = solver_->messageHandler()->logLevel();
+        if (value < oldLevel)
+            solver_->messageHandler()->setLogLevel(value);
+#ifdef COIN_HAS_CLP
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver) {
+            ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+            oldLevel = clpSimplex->logLevel();
+            if (value < oldLevel)
+                clpSimplex->setLogLevel(value);
+        }
+#else		// COIN_HAS_CLP
+        /*
+          For generic OSI solvers, if the new log level is 0, try the
+          DoReducePrint hint for emphasis.
+        */
+        if (value == 0) {
+            solver_->setHintParam(OsiDoReducePrint, true, OsiHintDo) ;
+        }
+#endif		// COIN_HAS_CLP
+    }
+}
+
+/* Pass in target solution and optional priorities.
+   If priorities then >0 means only branch if incorrect
+   while <0 means branch even if correct. +1 or -1 are
+   highest priority */
+void
+CbcModel::setHotstartSolution(const double * solution, const int * priorities)
+{
+    if (solution == NULL) {
+        delete [] hotstartSolution_;
+        hotstartSolution_ = NULL;
+        delete [] hotstartPriorities_;
+        hotstartPriorities_ = NULL;
+    } else {
+        int numberColumns = solver_->getNumCols();
+        hotstartSolution_ = CoinCopyOfArray(solution, numberColumns);
+        hotstartPriorities_ = CoinCopyOfArray(priorities, numberColumns);
+        for (int i = 0; i < numberColumns; i++) {
+            if (hotstartSolution_[i] == -COIN_DBL_MAX) {
+                hotstartSolution_[i] = 0.0;
+                hotstartPriorities_[i] += 10000;
+            }
+            if (solver_->isInteger(i))
+                hotstartSolution_[i] = floor(hotstartSolution_[i] + 0.5);
+        }
+    }
+}
+// Increment strong info
+void
+CbcModel::incrementStrongInfo(int numberTimes, int numberIterations,
+                              int numberFixed, bool ifInfeasible)
+{
+    strongInfo_[0] += numberTimes;
+    numberStrongIterations_ += numberIterations;
+    strongInfo_[1] += numberFixed;
+    if (ifInfeasible)
+        strongInfo_[2] ++;
+}
+/* Set objective value in a node.  This is separated out so that
+   odd solvers can use.  It may look at extra information in
+   solverCharacteriscs_ and will also use bound from parent node
+*/
+void
+CbcModel::setObjectiveValue(CbcNode * thisNode, const CbcNode * parentNode) const
+{
+    double newObjValue = solver_->getObjSense() * solver_->getObjValue();
+    // If odd solver take its bound
+    if (solverCharacteristics_) {
+        newObjValue = CoinMax(newObjValue, solverCharacteristics_->mipBound());
+        // Reset bound anyway (no harm if not odd)
+        solverCharacteristics_->setMipBound(-COIN_DBL_MAX);
+    }
+    // If not root then use max of this and parent
+    if (parentNode)
+        newObjValue = CoinMax(newObjValue, parentNode->objectiveValue());
+    thisNode->setObjectiveValue(newObjValue);
+}
+// Current time since start of branchAndbound
+double
+CbcModel::getCurrentSeconds() const
+{
+    if (!useElapsedTime())
+      return CoinCpuTime() - getDblParam(CbcStartSeconds);
+    else
+      return CoinGetTimeOfDay() - getDblParam(CbcStartSeconds);
+}
+/* Encapsulates choosing a variable -
+   anyAction: -2 infeasible
+	      -1 round again
+	       0 done
+
+   At the point where chooseBranch is called, we've decided that this problem
+   will need to be placed in the live set and we need to choose a branching
+   variable.
+
+   Parameters:
+     newNode:	the node just created for the active subproblem.
+     oldNode:	newNode's parent.
+     lastws:	oldNode's basis
+     lowerBefore, upperBefore: column bound arrays for oldNode
+     cuts:	list of cuts added to newNode.
+
+     resolved:	(o)  set to true if newNode is resolved during processing
+     branches:	(o) will be filled in with ... ? Null on entry
+*/
+int
+CbcModel::chooseBranch(CbcNode * &newNode, int numberPassesLeft,
+                       CbcNode * oldNode, OsiCuts & cuts,
+                       bool & resolved, CoinWarmStartBasis *lastws,
+                       const double * lowerBefore, const double * upperBefore,
+                       OsiSolverBranch * & branches)
+{
+    // Set state of search
+    /*
+      0 - outside CbcNode
+      1 - no solutions
+      2 - all heuristic solutions
+      3 - a solution reached by branching (could be strong)
+      4 - no solution but many nodes
+         add 10 if depth >= K
+    K is currently hardcoded to 8, a few lines below.
+
+    CBCMODEL_DEBUG: Seems like stateOfSearch_ should be 2 if
+           numberHeuristicSolutions_ == numberSolutions_.
+
+    */
+    stateOfSearch_ = 1;
+    if (numberSolutions_ > 0) {
+        if (numberHeuristicSolutions_ == numberSolutions_)
+            stateOfSearch_ = 3;
+        else
+            stateOfSearch_ = 3;
+    }
+    if (numberNodes_ > 2*numberObjects_ + 1000) {
+        stateOfSearch_ = 4;
+    }
+    //stateOfSearch_=3;
+    if (currentNode_ && currentNode_->depth() >= 8)
+        stateOfSearch_ += 10;
+    //printf("STate %d, %d nodes - parent %c - sol %d %d\n",
+    // stateOfSearch_,numberNodes_,parentModel_ ? 'Y' :'N',
+    // numberSolutions_,numberHeuristicSolutions_);
+    int anyAction = -1 ;
+    resolved = false ;
+    if (newNode->objectiveValue() >= getCutoff())
+        anyAction = -2;
+    branches = NULL;
+    bool feasible = true;
+    int branchingState = -1;
+    // Compute "small" change in branch
+    int nBranches = intParam_[CbcNumberBranches];
+    if (nBranches) {
+        double average = dblParam_[CbcSumChange] / static_cast<double>(nBranches);
+        dblParam_[CbcSmallChange] =
+            CoinMax(average * 1.0e-5, dblParam_[CbcSmallestChange]);
+        dblParam_[CbcSmallChange] = CoinMax(dblParam_[CbcSmallChange], 1.0e-8);
+    } else {
+        dblParam_[CbcSmallChange] = 1.0e-8;
+    }
+#ifdef JJF_ZERO
+    // Say not on optimal path
+    bool onOptimalPath = false;
+    if ((specialOptions_&1) != 0) {
+        /*
+          This doesn't work as intended --- getRowCutDebugger will return null
+          unless the current feasible solution region includes the optimal solution
+          that RowCutDebugger knows. There's no way to tell inactive from off the
+          optimal path.
+        */
+        const OsiRowCutDebugger *debugger = solver_->getRowCutDebugger() ;
+        if (debugger) {
+            onOptimalPath = true;
+            printf("On optimal path - choose\n") ;
+        }
+    }
+#endif
+    currentNode_ = newNode; // so can be used elsewhere
+// Remember number of rows to restore at the end of the loop
+    int saveNumberRows=solver_->getNumRows();
+    /*
+      Enough preparation. Get down to the business of choosing a branching
+      variable.
+    */
+    while (anyAction == -1) {
+        // Set objective value (not so obvious if NLP etc)
+        setObjectiveValue(newNode, oldNode);
+        //if (numberPassesLeft<=0)
+        //branchingState=1;
+        /*
+          Is there a CbcBranchDecision object installed? Does it specify a
+          chooseVariable method? If not, we're using the old (Cbc) side of the branch
+          decision hierarchy.  In quick summary, CbcNode::chooseBranch uses strong
+          branching on any objects, while CbcNode::chooseDynamicBranch uses dynamic
+          branching, but only on simple integers (-3 is the code for punt due to
+          complex objects). Serious bugs remain on the Cbc side, particularly in
+          chooseDynamicBranch.
+        */
+        if (!branchingMethod_ || !branchingMethod_->chooseMethod()) {
+#ifdef COIN_HAS_CLP
+            bool doClp = oldNode && (oldNode->depth() % 2) == 1;
+            if (!doCutsNow(1))
+                doClp = true;
+            //doClp = true;
+            int testDepth = 5;
+            // Don't do if many iterations per node
+            int totalNodes = numberNodes_ + numberExtraNodes_;
+            int totalIterations = numberIterations_ + numberExtraIterations_;
+	    bool diving=false;
+	    if ((moreSpecialOptions_&33554432)!=0) {
+	      testDepth=COIN_INT_MAX;
+	      if (oldNode&&(oldNode->depth()==-2||oldNode->depth()==4))
+		diving=true;
+	    }
+            if (totalNodes*40 < totalIterations || numberNodes_ < 1000) {
+                doClp = false;
+                //} else if (oldNode&&fastNodeDepth_>=0&&oldNode->depth()>=testDepth&&(specialOptions_&2048)==0) {
+                //printf("size %d %d - cuts %d - nodes %d its %d %c\n",solver_->getNumRows(),
+                //     solver_->getNumCols(),cuts.sizeRowCuts(),
+                //     totalNodes,totalIterations,doClp ? 'Y' : 'N');
+            }
+            if (oldNode && 
+		((fastNodeDepth_ >= 0 && oldNode->depth() >= testDepth && doClp)||diving) &&/*!parentModel_*/(specialOptions_&2048) == 0
+		&& !cuts.sizeRowCuts()) {
+                OsiClpSolverInterface * clpSolver
+                = dynamic_cast<OsiClpSolverInterface *> (solver_);
+                if (clpSolver) {
+                    anyAction = newNode->chooseClpBranch(this, oldNode) ;
+                    if (anyAction != -1)
+                        break;
+                }
+            }
+#endif
+#ifdef COIN_HAS_CLP
+	    int save=0;
+	    OsiClpSolverInterface * clpSolver
+	      = dynamic_cast<OsiClpSolverInterface *> (solver_);
+	    if (clpSolver&&(moreSpecialOptions_&4194304)!=0) {
+	      ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+	      save=clpSimplex->specialOptions();
+	      clpSimplex->setSpecialOptions(save | 0x11200000); // say is Cbc (and in branch and bound - but save ray)
+	    }
+#endif
+            if (numberBeforeTrust_ == 0 ) {
+                anyAction = newNode->chooseBranch(this, oldNode, numberPassesLeft) ;
+            } else {
+                anyAction = newNode->chooseDynamicBranch(this, oldNode, branches, numberPassesLeft) ;
+                if (anyAction == -3)
+                    anyAction = newNode->chooseBranch(this, oldNode, numberPassesLeft) ; // dynamic did nothing
+            }
+#ifdef COIN_HAS_CLP
+	    if (clpSolver&&(moreSpecialOptions_&4194304)!=0) {
+	      ClpSimplex * clpSimplex = clpSolver->getModelPtr();
+	      clpSimplex->setSpecialOptions(save); 
+	    }
+#endif
+            /*
+              We're on the new (Osi) side of the branching hierarchy.
+            */
+        } else {
+            OsiBranchingInformation usefulInfo = usefulInformation();
+            anyAction = newNode->chooseOsiBranch(this, oldNode, &usefulInfo, branchingState) ;; // Osi method
+            //branchingState=0;
+        }
+        if (!oldNode) {
+            if (numberUpdateItems_) {
+                for (int i = 0; i < numberUpdateItems_; i++) {
+                    CbcObjectUpdateData * update = updateItems_ + i;
+                    CbcObject * object = dynamic_cast<CbcObject *> (update->object_);
+#ifndef NDEBUG
+                    bool found = false;
+                    for (int j = 0; j < numberObjects_; j++) {
+                        if (update->object_ == object_[j]) {
+                            found = true;
+                            break;
+                        }
+                    }
+                    assert (found);
+#endif
+                    //if (object)
+                    //assert (object==object_[update->objectNumber_]);
+                    if (object)
+                        object->updateInformation(*update);
+                }
+                numberUpdateItems_ = 0;
+            }
+        }
+        if (solverCharacteristics_ &&
+                solverCharacteristics_->solutionAddsCuts() && // we are in some OA based bab
+                feasible && (newNode->numberUnsatisfied() == 0) //solution has become integer feasible during strong branching
+           ) {
+            //in the present case we need to check here integer infeasibility if the node is not fathomed we will have to do the loop
+            // again
+            //std::cout<<solver_<<std::endl;
+            resolve(solver_);
+            double objval = solver_->getObjValue();
+            lastHeuristic_ = NULL;
+            setBestSolution(CBC_SOLUTION, objval,
+                            solver_->getColSolution()) ;
+            int easy = 2;
+            if (!solverCharacteristics_->mipFeasible())//did we prove that the node could be pruned?
+                feasible = false;
+            // Reset the bound now
+            solverCharacteristics_->setMipBound(-COIN_DBL_MAX);
+
+
+            solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, &easy) ;
+            feasible &= resolve(oldNode ? oldNode->nodeInfo() : NULL, 11) != 0 ;
+            solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+            resolved = true ;
+            if (problemFeasibility_->feasible(this, 0) < 0) {
+                feasible = false; // pretend infeasible
+            }
+            if (feasible)
+                anyAction = -1;
+            else
+                anyAction = -2;
+        }
+        /*
+          Yep, false positives for sure. And no easy way to distinguish honest
+          infeasibility from `found a solution and tightened objective target.'
+
+          if (onOptimalPath)
+          assert (anyAction!=-2); // can be useful but gives false positives on strong
+          */
+        numberPassesLeft--;
+        if (numberPassesLeft <= -1) {
+            if (!numberLongStrong_ && !numberThreads_)
+                messageHandler()->message(CBC_WARNING_STRONG,
+                                          messages()) << CoinMessageEol ;
+            numberLongStrong_++;
+        }
+        if (anyAction == -1) {
+            // can do quick optimality check
+            int easy = 2;
+            solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, &easy) ;
+            feasible = resolve(oldNode ? oldNode->nodeInfo() : NULL, 11) != 0 ;
+            solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+            resolved = true ;
+            if (problemFeasibility_->feasible(this, 0) < 0) {
+                feasible = false; // pretend infeasible
+            }
+            if (feasible) {
+                // Set objective value (not so obvious if NLP etc)
+                setObjectiveValue(newNode, oldNode);
+                reducedCostFix() ;
+                if (newNode->objectiveValue() >= getCutoff())
+                    anyAction = -2;
+            } else {
+                anyAction = -2 ;
+            }
+        }
+    }
+    //A candidate has been found; restore the subproblem.
+    if( saveNumberRows<solver_->getNumRows()) {
+        // delete rows - but leave solution
+        int n = solver_->getNumRows();
+        int * del = new int [n-saveNumberRows];
+        for (int i=saveNumberRows;i<n;i++)
+            del[i-saveNumberRows]=i;
+        solver_->deleteRows(n-saveNumberRows,del);
+        delete [] del;
+    }
+    /*
+      End main loop to choose a branching variable.
+    */
+    if (anyAction >= 0) {
+        if (resolved) {
+            /*
+              Used to be that when the node was not fathomed (branching object present)
+              the solution was not needed. But that's no longer the case --- heuristics
+              are applied, and they may want the solution.
+            */
+            // bool needValidSolution = (newNode->branchingObject() == NULL) ;
+            bool needValidSolution = true ;
+            takeOffCuts(cuts, needValidSolution , NULL) ;
+#	      ifdef CHECK_CUT_COUNTS
+            {
+                printf("Number of rows after chooseBranch fix (node)"
+                "(active only) %d\n",
+                numberRowsAtContinuous_ + numberNewCuts_ +
+                numberOldActiveCuts_) ;
+                const CoinWarmStartBasis* debugws =
+                    dynamic_cast<const CoinWarmStartBasis*>
+                    (solver_->getWarmStart()) ;
+                debugws->print() ;
+                delete debugws ;
+            }
+#	      endif
+        }
+        {
+            OsiBranchingObject * branchingObject =
+                newNode->modifiableBranchingObject();
+            CbcGeneralBranchingObject * generalBranch =
+                dynamic_cast <CbcGeneralBranchingObject *> (branchingObject);
+            if (generalBranch && false) {
+                int numberProblems = generalBranch->numberSubProblems();
+                for (int i = 0; i < numberProblems; i++) {
+                    double objectiveValue;
+                    double sumInfeasibilities;
+                    int numberUnsatisfied;
+                    generalBranch->state(objectiveValue, sumInfeasibilities,
+                                         numberUnsatisfied, i);
+                    printf("node %d obj %g sumI %g numI %i rel depth %d\n",
+                           i, objectiveValue, sumInfeasibilities, numberUnsatisfied,
+                           generalBranch->subProblem(i)->depth_);
+                }
+            }
+            if (generalBranch) {
+                int numberProblems = generalBranch->numberSubProblems();
+                newNode->setBranchingObject(NULL);
+                CbcNode * newNode2 = NULL;
+                assert (numberProblems);
+                int nProbMinus1 = numberProblems - 1;
+		lockThread();
+                for (int i = 0; i < currentNumberCuts_; i++) {
+                    if (addedCuts_[i])
+                        addedCuts_[i]->increment(nProbMinus1) ;
+                }
+		unlockThread();
+                for (int i = 0; i < numberProblems; i++) {
+                    double objectiveValue;
+                    double sumInfeasibilities;
+                    int numberUnsatisfied;
+                    generalBranch->state(objectiveValue, sumInfeasibilities,
+                                         numberUnsatisfied, i);
+                    //printf("node %d obj %g sumI %g numI %i rel depth %d\n",
+                    // i,objectiveValue,sumInfeasibilities,numberUnsatisfied,
+                    // generalBranch->subProblem(i)->depth_);
+                    newNode2 = new CbcNode();
+                    newNode2->setDepth(generalBranch->subProblem(i)->depth_ + currentDepth_);
+                    generalBranch->subProblem(i)->apply(solver_, 8); // basis
+                    newNode2->setNumberUnsatisfied(numberUnsatisfied);
+                    newNode2->setSumInfeasibilities(sumInfeasibilities);
+                    newNode2->setGuessedObjectiveValue(objectiveValue);
+                    newNode2->setObjectiveValue(objectiveValue);
+                    CbcOneGeneralBranchingObject * object =
+                        new CbcOneGeneralBranchingObject(this, generalBranch, i);
+                    newNode2->setBranchingObject(object);
+                    assert (lastws->fullBasis());
+                    newNode2->createInfo(this, oldNode, lastws,
+                                         lowerBefore, upperBefore,
+                                         numberOldActiveCuts_, numberNewCuts_) ;
+                    newNode2->nodeInfo()->setNumberBranchesLeft(1);
+                    //newNode2->nodeInfo()->unsetParentBasedData();
+                    if (i < nProbMinus1) {
+                        //OsiBranchingObject * object = oldNode->modifiableBranchingObject();
+                        CbcNodeInfo * nodeInfo = oldNode->nodeInfo();
+                        //object->incrementNumberBranchesLeft();
+                        nodeInfo->incrementNumberPointingToThis();
+                        newNode2->nodeInfo()->setNodeNumber(numberNodes2_);
+                        //newNode2->nodeInfo()->setNumberBranchesLeft(1);
+                        newNode2->initializeInfo();
+                        numberNodes2_++;
+                        tree_->push(newNode2);
+                    }
+                }
+                delete newNode;
+                newNode = newNode2;
+            } else {
+                if (lastws) {
+                    if (parallelMode() < -1) {
+                        lastws->fixFullBasis();
+                    } else {
+                        if ((specialOptions_&8192) == 0)
+                            assert (lastws->fullBasis());
+                        else
+                            lastws->fixFullBasis();
+                    }
+                }
+                newNode->createInfo(this, oldNode, lastws, lowerBefore, upperBefore,
+                                    numberOldActiveCuts_, numberNewCuts_) ;
+            }
+        }
+        if (newNode->numberUnsatisfied()) {
+            maximumDepthActual_ = CoinMax(maximumDepthActual_, newNode->depth());
+            // Number of branches is in oldNode!
+            newNode->initializeInfo() ;
+            if (cuts.sizeRowCuts()) {
+                int initialNumber = ((threadMode_ & 1) == 0) ? 0 : 1000000000;
+                lockThread();
+                newNode->nodeInfo()->addCuts(cuts, newNode->numberBranches(),
+                                             //whichGenerator_,
+                                             initialNumber) ;
+                unlockThread();
+            }
+        }
+    } else {
+        anyAction = -2 ;
+        // Reset bound anyway (no harm if not odd)
+        solverCharacteristics_->setMipBound(-COIN_DBL_MAX);
+    }
+    // May have slipped through i.e. anyAction == 0 and objective above cutoff
+    // I think this will screw up cut reference counts if executed.
+    // We executed addCuts just above. (lh)
+    if ( anyAction >= 0 ) {
+        assert (newNode);
+        if (newNode->objectiveValue() >= getCutoff()) {
+            anyAction = -2; // say bad after all
+            // zap parent nodeInfo
+#ifdef COIN_DEVELOP
+            printf("zapping3 CbcNodeInfo %x\n", reinterpret_cast<int>(newNode->nodeInfo()->parent()));
+#endif
+            if (newNode->nodeInfo())
+                newNode->nodeInfo()->nullParent();
+        }
+    }
+    stateOfSearch_ = 0; // outside chooseBranch
+#ifdef JJF_ZERO
+    if (onOptimalPath) {
+        const OsiRowCutDebugger *debugger = solver_->getRowCutDebugger() ;
+        if (!debugger) {
+            printf("NOT On optimal path - choose\n") ;
+            abort();
+        } else {
+            printf("Still On optimal path - choose\n") ;
+            if (anyAction == -2) {
+                printf("anyAction 2!!\n");
+                abort();
+            }
+        }
+    }
+#endif
+    return anyAction;
+}
+
+/*
+   For advanced applications you may wish to modify the behavior of Cbc
+   e.g. if the solver is a NLP solver then you may not have an exact
+   optimum solution at each step.  Information could be built into
+   OsiSolverInterface but this is an alternative so that that interface
+   does not have to be changed.  If something similar is useful to
+   enough solvers then it could be migrated.
+   You can also pass in by using solver->setAuxiliaryInfo.
+   You should do that if solver is odd - if solver is normal simplex
+   then use this
+*/
+void
+CbcModel::passInSolverCharacteristics(OsiBabSolver * solverCharacteristics)
+{
+    solverCharacteristics_ = solverCharacteristics;
+}
+// Generate an OsiBranchingInformation object
+OsiBranchingInformation
+CbcModel::usefulInformation() const
+{
+    OsiBranchingInformation usefulInfo(solver_, normalSolver(), false);
+    // and modify
+    usefulInfo.solution_ = testSolution_;
+    usefulInfo.integerTolerance_ = dblParam_[CbcIntegerTolerance] ;
+    usefulInfo.hotstartSolution_ = hotstartSolution_;
+    usefulInfo.numberSolutions_ = numberSolutions_;
+    usefulInfo.numberBranchingSolutions_ = numberSolutions_ - numberHeuristicSolutions_;
+    usefulInfo.depth_ = -1;
+    return usefulInfo;
+}
+void
+CbcModel::setBestSolution(const double * solution, int numberColumns,
+                          double objectiveValue, bool checkSolution)
+{
+    // May be odd discontinuities - so only check if asked
+    if (checkSolution) {
+        assert (numberColumns == solver_->getNumCols());
+        double * saveLower = CoinCopyOfArray(solver_->getColLower(), numberColumns);
+        double * saveUpper = CoinCopyOfArray(solver_->getColUpper(), numberColumns);
+        // Fix integers
+        int numberAway = 0;
+        for (int i = 0; i < numberColumns; i++) {
+            if (solver_->isInteger(i)) {
+                double value = solution[i];
+                double intValue = floor(value + 0.5);
+                if (fabs(value - intValue) > 1.0e-4)
+                    numberAway++;
+                solver_->setColLower(i, intValue);
+                solver_->setColUpper(i, intValue);
+            }
+        }
+        // Save basis
+        CoinWarmStart * saveBasis = solver_->getWarmStart();
+        // Solve
+        solver_->initialSolve();
+        char printBuffer[200];
+        if (numberAway) {
+            sprintf(printBuffer, "Warning %d integer variables were more than 1.0e-4 away from integer", numberAway);
+            messageHandler()->message(CBC_GENERAL, messages())
+            << printBuffer << CoinMessageEol ;
+        }
+        bool looksGood = solver_->isProvenOptimal();
+        if (looksGood) {
+            double direction = solver_->getObjSense() ;
+            double objValue = direction * solver_->getObjValue();
+            if (objValue > objectiveValue + 1.0e-8*(1.0 + fabs(objectiveValue))) {
+                sprintf(printBuffer, "Given objective value %g, computed %g",
+                        objectiveValue, objValue);
+                messageHandler()->message(CBC_GENERAL, messages())
+                << printBuffer << CoinMessageEol ;
+            }
+            // Use this as objective value and solution
+            objectiveValue = objValue;
+            solution = solver_->getColSolution();
+            // Save current basis
+            CoinWarmStartBasis* ws =
+                dynamic_cast <CoinWarmStartBasis*>(solver_->getWarmStart()) ;
+            assert(ws);
+            setBestSolutionBasis(*ws);
+            delete ws;
+        }
+        // Restore basis
+        solver_->setWarmStart(saveBasis);
+        delete saveBasis;
+        // Restore bounds
+        solver_->setColLower(saveLower);
+        delete [] saveLower;
+        solver_->setColUpper(saveUpper);
+        delete [] saveUpper;
+        // Return if no good
+        if (!looksGood) {
+            messageHandler()->message(CBC_GENERAL, messages())
+            << "Error solution not saved as not feasible" << CoinMessageEol ;
+            return;
+        } else {
+            // message
+            sprintf(printBuffer, "Solution with objective value %g saved",
+                    objectiveValue);
+            messageHandler()->message(CBC_GENERAL, messages())
+            << printBuffer << CoinMessageEol ;
+        }
+    }
+    if (bestSolution_)
+        saveExtraSolution(bestSolution_, bestObjective_);
+    bestObjective_ = objectiveValue;
+    // may be able to change cutoff now
+    double cutoff = getCutoff();
+    double increment = getDblParam(CbcModel::CbcCutoffIncrement) ;
+    if (cutoff > objectiveValue - increment) {
+        cutoff = objectiveValue - increment ;
+        setCutoff(cutoff) ;
+	// change cutoff as constraint if wanted
+	if (cutoffRowNumber_>=0) {
+	  if (solver_->getNumRows()>cutoffRowNumber_) {
+	    double offset;
+	    solver_->getDblParam(OsiObjOffset, offset);
+	    solver_->setRowUpper(cutoffRowNumber_,cutoff+offset);
+	  }
+	}
+    }
+    int n = CoinMax(numberColumns, solver_->getNumCols());
+    delete [] bestSolution_;
+    bestSolution_ = new double [n];
+    memset(bestSolution_, 0, n*sizeof(double));
+    memcpy(bestSolution_, solution, numberColumns*sizeof(double));
+}
+/* Do heuristics at root.
+   0 - don't delete
+   1 - delete
+      2 - just delete - don't even use
+  Parameter of 2 means what it says --- the routine will do nothing except
+  delete the existing heuristics. A feasibility pump is always deleted,
+  independent of the parameter value, as it's only useful at the root.
+
+  The routine is called from branchAndBound to process the root node. But it
+  will also be called when we've recursed into branchAndBound via smallBaB.
+*/
+void
+CbcModel::doHeuristicsAtRoot(int deleteHeuristicsAfterwards)
+{
+
+    int numberColumns = getNumCols() ;
+    double * newSolution = new double [numberColumns] ;
+    int i;
+    if (deleteHeuristicsAfterwards != 2) {
+        /*
+          If mode == 1, we delete and recreate here, then delete at the bottom. The
+          create/delete part makes sense, but why delete the existing array? Seems like
+          it should be preserved and restored.
+        */
+        if (deleteHeuristicsAfterwards) {
+            delete [] usedInSolution_;
+            usedInSolution_ = new int [numberColumns];
+            CoinZeroN(usedInSolution_, numberColumns);
+        }
+        double heuristicValue = getCutoff() ;
+        int found = -1; // no solution found
+        CbcEventHandler *eventHandler = getEventHandler() ;
+        if (eventHandler)
+            eventHandler->setModel(this);
+        /*
+          currentPassNumber_ is described as `cut pass number'. Again, seems a bit
+          cavalier to just change it.
+
+          Whether this has any effect is determined by individual heuristics. Typically
+          there will be a check at the front of the solution() routine that determines
+          whether it will run or simply return. Root heuristics are characterised by
+          node count of 0. In addition, currentPassNumber_ can be checked to to limit
+          execution in terms of passes through cut generation / heuristic execution in
+          solveWithCuts.
+        */
+
+        currentPassNumber_ = 1; // so root heuristics will run
+        /*
+          A loop to run the heuristics. incrementUsed will mark entries in
+          usedInSolution corresponding to variables that are nonzero in the solution.
+          CBC_ROUNDING just identifies a message template, not the heuristic.
+        */
+        // Modify based on size etc
+        adjustHeuristics();
+        // See if already within allowable gap
+        bool exitNow = false;
+        for (i = 0; i < numberHeuristics_; i++) {
+            if (heuristic_[i]->exitNow(bestObjective_))
+                exitNow = true;
+        }
+        if (!exitNow) {
+	  /** -1 first time otherwise number of solutions last time */
+	  int lastSolutionCount = -1;
+	  while (lastSolutionCount) {
+	    int thisSolutionCount=0;
+#ifdef CBC_THREAD
+            if ((threadMode_&4) != 0) {
+                typedef struct {
+                    double solutionValue;
+                    CbcModel * model;
+                    double * solution;
+                    int foundSol;
+                } argBundle;
+                int chunk;
+                if (!numberThreads_)
+                    chunk = numberHeuristics_;
+                else
+                    chunk = numberThreads_;
+                for (int iChunk = 0; iChunk < numberHeuristics_; iChunk += chunk) {
+                    argBundle * parameters = new argBundle [chunk];
+                    for (int i = 0; i < chunk; i++)
+                        parameters[i].model = NULL;
+                    int nThisTime = CoinMin(numberHeuristics_ - iChunk, chunk);
+                    for (int i = iChunk; i < iChunk + nThisTime; i++) {
+                        // skip if can't run here
+                        if (!heuristic_[i]->shouldHeurRun(0))
+                            continue;
+			if (lastSolutionCount>0&&
+			    (heuristic_[i]->switches()&16)==0)
+			  continue; // no point
+                        parameters[i-iChunk].solutionValue = heuristicValue;
+                        // Don't want a strategy object
+                        CbcStrategy * saveStrategy = strategy_;
+                        strategy_ = NULL;
+                        CbcModel * newModel = new CbcModel(*this);
+                        strategy_ = saveStrategy;
+                        assert (!newModel->continuousSolver_);
+                        if (continuousSolver_)
+                            newModel->continuousSolver_ = continuousSolver_->clone();
+                        else
+                            newModel->continuousSolver_ = solver_->clone();
+                        parameters[i-iChunk].model = newModel;
+                        parameters[i-iChunk].solution = new double [numberColumns];;
+                        parameters[i-iChunk].foundSol = 0;
+                        //newModel->gutsOfCopy(*this,-1);
+                        for (int j = 0; j < numberHeuristics_; j++)
+                            delete newModel->heuristic_[j];
+                        //newModel->heuristic_ = new CbcHeuristic * [1];
+                        newModel->heuristic_[0] = heuristic_[i]->clone();
+                        newModel->heuristic_[0]->setModel(newModel);
+                        newModel->heuristic_[0]->resetModel(newModel);
+                        newModel->numberHeuristics_ = 1;
+                    }
+                    void
+                    parallelHeuristics (int numberThreads,
+                                        int sizeOfData,
+                                        void * argBundle);
+                    parallelHeuristics(nThisTime,
+                                       static_cast<int>(sizeof(argBundle)),
+                                       parameters);
+                    double cutoff = heuristicValue;
+                    for (int i = 0; i < chunk; i++) {
+                        if (parameters[i].model) {
+                            if (parameters[i].foundSol > 0 &&
+                                    parameters[i].solutionValue < heuristicValue) {
+                                memcpy(newSolution, parameters[i].solution,
+                                       numberColumns*sizeof(double));
+                                lastHeuristic_ = heuristic_[i+iChunk];
+                                double value = parameters[i].solutionValue;
+                                setBestSolution(CBC_ROUNDING, value, newSolution) ;
+                                // Double check valid
+                                if (getCutoff() < cutoff) {
+                                    cutoff = getCutoff();
+                                    heuristicValue = value;
+                                    heuristic_[i+iChunk]->incrementNumberSolutionsFound();
+                                    incrementUsed(newSolution);
+                                    // increment number of solutions so other heuristics can test
+				    thisSolutionCount++;
+                                    numberHeuristicSolutions_++;
+                                    found = i + iChunk ;
+                                }
+                            }
+                            if (heuristic_[i+iChunk]->exitNow(bestObjective_) ||
+                                    (parameters[i].model->heuristic(0)->switches()&(1024 + 2048))
+                                    == (1024 + 2048))
+                                exitNow = true;
+                            delete [] parameters[i].solution;
+                            delete parameters[i].model;
+                        }
+                    }
+                    delete [] parameters;
+                    if (exitNow)
+                        break;
+                }
+            } else {
+#endif
+                int whereFrom = 0;
+                for (i = 0; i < numberHeuristics_; i++) {
+                    // skip if can't run here
+                    if (!heuristic_[i]->shouldHeurRun(whereFrom))
+                        continue;
+		    if (lastSolutionCount>0&&
+			(heuristic_[i]->switches()&16)==0)
+		      continue; // no point
+                    if (maximumSecondsReached()) {
+		        thisSolutionCount=-1000000;
+                        break;
+		    }
+                    // see if heuristic will do anything
+                    double saveValue = heuristicValue ;
+		    double before = getCurrentSeconds();
+                    int ifSol = heuristic_[i]->solution(heuristicValue,
+                                                        newSolution);
+		    if (handler_->logLevel()>1) {
+		      char line[100];
+		      sprintf(line,"Heuristic %s took %g seconds (%s)",
+			      heuristic_[i]->heuristicName(),
+			      getCurrentSeconds()-before,
+			      ifSol ? "good" : "no good");
+		      handler_->message(CBC_GENERAL, messages_) << 
+			line << CoinMessageEol ;
+		    }
+                    if (ifSol > 0) {
+                        // better solution found
+                        double currentObjective = bestObjective_;
+                        CbcHeuristic * saveHeuristic = lastHeuristic_;
+                        lastHeuristic_ = heuristic_[i];
+                        setBestSolution(CBC_ROUNDING, heuristicValue, newSolution) ;
+                        if (bestObjective_ < currentObjective) {
+			    thisSolutionCount++;
+                            heuristic_[i]->incrementNumberSolutionsFound();
+                            found = i ;
+                            incrementUsed(newSolution);
+                            // increment number of solutions so other heuristics can test
+			    //                            numberSolutions_++;
+                            numberHeuristicSolutions_++;
+#ifdef CLP_INVESTIGATE
+                            printf("HEUR %s where %d C\n",
+                                   lastHeuristic_->heuristicName(), whereFrom);
+#endif
+                            whereFrom |= 8; // say solution found
+                            if (heuristic_[i]->exitNow(bestObjective_)
+				||numberSolutions_>=getMaximumSolutions()) {
+			      thisSolutionCount=-1000000;
+                                break;
+			    }
+			    if (eventHandler) {
+			      if (!eventHandler->event(CbcEventHandler::heuristicSolution)) {
+				eventHappened_ = true; // exit
+				thisSolutionCount=-1000000;
+				break;
+			      }
+			    }
+			    double testGap = CoinMax(dblParam_[CbcAllowableGap],
+						     CoinMax(fabs(bestObjective_), fabs(bestPossibleObjective_))
+						     * dblParam_[CbcAllowableFractionGap]);
+			    if (bestObjective_ - bestPossibleObjective_ < testGap && getCutoffIncrement() >= 0.0 &&bestPossibleObjective_ < 1.0e30) {
+			      if (bestPossibleObjective_ < getCutoff())
+				stoppedOnGap_ = true ;
+			      //eventHappened_=true; // stop as fast as possible
+			      thisSolutionCount=-1000000;
+			      break;
+			    }
+			    reducedCostFix();
+                        } else {
+                            // NOT better solution
+#ifdef CLP_INVESTIGATE
+                            printf("HEUR %s where %d REJECTED i==%d\n",
+                                   heuristic_[i]->heuristicName(), whereFrom, i);
+#endif
+                            lastHeuristic_ = saveHeuristic;
+                            heuristicValue = saveValue ;
+                        }
+                    } else {
+                        heuristicValue = saveValue ;
+                    }
+		    if (eventHandler) {
+		      if (!eventHandler->event(CbcEventHandler::afterHeuristic)) {
+			eventHappened_ = true; // exit
+		        thisSolutionCount=-1000000;
+			break;
+		      }
+		    }
+                }
+#ifdef CBC_THREAD
+            }
+#endif
+	    if (thisSolutionCount<=0)
+	      break;
+	    lastSolutionCount=thisSolutionCount;
+	  }
+        }
+        currentPassNumber_ = 0;
+        /*
+          Did any of the heuristics turn up a new solution? Record it before we free
+        the vector. tree_ will not necessarily be a CbcTreeLocal; the main model gets
+        a CbcTree by default. CbcTreeLocal actually implements a k-neighbourhood
+        search heuristic. This initialises it with a solution and creates the
+        k-neighbourhood cut.
+        */
+        if (found >= 0) {
+            CbcTreeLocal * tree
+            = dynamic_cast<CbcTreeLocal *> (tree_);
+            if (tree)
+                tree->passInSolution(bestSolution_, heuristicValue);
+            if (eventHandler) {
+                if (!eventHandler->event(CbcEventHandler::solution)) {
+                    eventHappened_ = true; // exit
+                }
+            }
+        }
+    }
+    /*
+      Cleanup. The feasibility pump heuristic is a root heuristic to look for an
+      initial feasible solution. It's had its chance; remove it.
+
+      For modes 1 and 2, all the heuristics are deleted.
+    */
+    if (!deleteHeuristicsAfterwards) {
+        for (i = 0; i < numberHeuristics_; i++) {
+            // delete FPump
+            CbcHeuristicFPump * pump
+            = dynamic_cast<CbcHeuristicFPump *> (heuristic_[i]);
+            if (pump && pump->feasibilityPumpOptions() < 1000000) {
+                delete pump;
+                numberHeuristics_ --;
+                for (int j = i; j < numberHeuristics_; j++)
+                    heuristic_[j] = heuristic_[j+1];
+            }
+        }
+    } else {
+        // delete all
+        for (i = 0; i < numberHeuristics_; i++)
+            delete heuristic_[i];
+        numberHeuristics_ = 0;
+        delete [] heuristic_;
+        heuristic_ = NULL;
+        delete [] usedInSolution_;
+        usedInSolution_ = NULL;
+    }
+    delete [] newSolution ;
+}
+// Zap integer information in problem (may leave object info)
+void
+CbcModel::zapIntegerInformation(bool leaveObjects)
+{
+    numberIntegers_ = 0;
+    delete [] integerVariable_;
+    integerVariable_ = NULL;
+    if (!leaveObjects && ownObjects_) {
+        int i;
+        for (i = 0; i < numberObjects_; i++)
+            delete object_[i];
+        delete [] object_;
+        numberObjects_ = 0;
+        object_ = NULL;
+    }
+}
+// Create C++ lines to get to current state
+void
+CbcModel::generateCpp( FILE * fp, int /*options*/)
+{
+    // Do cut generators
+    int i;
+    for (i = 0; i < numberCutGenerators_; i++) {
+        CglCutGenerator * generator = generator_[i]->generator();
+        std::string name = generator->generateCpp(fp);
+        int howOften = generator_[i]->howOften();
+        int howOftenInSub = generator_[i]->howOftenInSub();
+        int whatDepth = generator_[i]->whatDepth();
+        int whatDepthInSub = generator_[i]->whatDepthInSub();
+        bool normal = generator_[i]->normal();
+        bool atSolution = generator_[i]->atSolution();
+        bool whenInfeasible = generator_[i]->whenInfeasible();
+        bool timing = generator_[i]->timing();
+        fprintf(fp, "3  cbcModel->addCutGenerator(&%s,%d,",
+                name.c_str(), howOften);
+        // change name
+        name[0] = static_cast<char>(toupper(name[0]));
+        fprintf(fp, "\"%s\",%s,%s,%s,%d,%d,%d);\n",
+                name.c_str(), normal ? "true" : "false",
+                atSolution ? "true" : "false",
+                whenInfeasible ? "true" : "false",
+                howOftenInSub, whatDepth, whatDepthInSub);
+        fprintf(fp, "3  cbcModel->cutGenerator(%d)->setTiming(%s);\n",
+                i, timing ? "true" : "false");
+        fprintf(fp, "3  \n");
+    }
+    for (i = 0; i < numberHeuristics_; i++) {
+        CbcHeuristic * heuristic = heuristic_[i];
+        heuristic->generateCpp(fp);
+        fprintf(fp, "3  \n");
+    }
+    if (nodeCompare_)
+        nodeCompare_->generateCpp(fp);
+    tree_->generateCpp(fp);
+    CbcModel defaultModel;
+    CbcModel * other = &defaultModel;
+    int iValue1, iValue2;
+    double dValue1, dValue2;
+    iValue1 = this->getMaximumNodes();
+    iValue2 = other->getMaximumNodes();
+    fprintf(fp, "%d  int save_getMaximumNodes = cbcModel->getMaximumNodes();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setMaximumNodes(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setMaximumNodes(save_getMaximumNodes);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->getMaximumSolutions();
+    iValue2 = other->getMaximumSolutions();
+    fprintf(fp, "%d  int save_getMaximumSolutions = cbcModel->getMaximumSolutions();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setMaximumSolutions(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setMaximumSolutions(save_getMaximumSolutions);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->numberStrong();
+    iValue2 = other->numberStrong();
+    fprintf(fp, "%d  int save_numberStrong = cbcModel->numberStrong();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setNumberStrong(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setNumberStrong(save_numberStrong);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->numberBeforeTrust();
+    iValue2 = other->numberBeforeTrust();
+    fprintf(fp, "%d  int save_numberBeforeTrust = cbcModel->numberBeforeTrust();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setNumberBeforeTrust(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setNumberBeforeTrust(save_numberBeforeTrust);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->numberPenalties();
+    iValue2 = other->numberPenalties();
+    fprintf(fp, "%d  int save_numberPenalties = cbcModel->numberPenalties();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setNumberPenalties(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setNumberPenalties(save_numberPenalties);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->howOftenGlobalScan();
+    iValue2 = other->howOftenGlobalScan();
+    fprintf(fp, "%d  int save_howOftenGlobalScan = cbcModel->howOftenGlobalScan();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setHowOftenGlobalScan(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setHowOftenGlobalScan(save_howOftenGlobalScan);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->printFrequency();
+    iValue2 = other->printFrequency();
+    fprintf(fp, "%d  int save_printFrequency = cbcModel->printFrequency();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setPrintFrequency(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setPrintFrequency(save_printFrequency);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->getPrintingMode();
+    iValue2 = other->getPrintingMode();
+    fprintf(fp, "%d  int save_printingMode = cbcModel->getPrintingMode();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setPrintingMode(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setPrintingMode(save_printingMode);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->searchStrategy();
+    iValue2 = other->searchStrategy();
+    fprintf(fp, "%d  int save_searchStrategy = cbcModel->searchStrategy();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setSearchStrategy(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setSearchStrategy(save_searchStrategy);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->specialOptions();
+    iValue2 = other->specialOptions();
+    fprintf(fp, "%d  int save_cbcSpecialOptions = cbcModel->specialOptions();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setSpecialOptions(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setSpecialOptions(save_cbcSpecialOptions);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->messageHandler()->logLevel();
+    iValue2 = other->messageHandler()->logLevel();
+    fprintf(fp, "%d  int save_cbcMessageLevel = cbcModel->messageHandler()->logLevel();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->messageHandler()->setLogLevel(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->messageHandler()->setLogLevel(save_cbcMessageLevel);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->getMaximumCutPassesAtRoot();
+    iValue2 = other->getMaximumCutPassesAtRoot();
+    fprintf(fp, "%d  int save_getMaximumCutPassesAtRoot = cbcModel->getMaximumCutPassesAtRoot();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setMaximumCutPassesAtRoot(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setMaximumCutPassesAtRoot(save_getMaximumCutPassesAtRoot);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->getMaximumCutPasses();
+    iValue2 = other->getMaximumCutPasses();
+    fprintf(fp, "%d  int save_getMaximumCutPasses = cbcModel->getMaximumCutPasses();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setMaximumCutPasses(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setMaximumCutPasses(save_getMaximumCutPasses);\n", iValue1 == iValue2 ? 7 : 6);
+    iValue1 = this->getPreferredWay();
+    iValue2 = other->getPreferredWay();
+    fprintf(fp, "%d  int save_getPreferredWay = cbcModel->getPreferredWay();\n", iValue1 == iValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setPreferredWay(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+    fprintf(fp, "%d  cbcModel->setPreferredWay(save_getPreferredWay);\n", iValue1 == iValue2 ? 7 : 6);
+    dValue1 = this->getMinimumDrop();
+    dValue2 = other->getMinimumDrop();
+    fprintf(fp, "%d  double save_getMinimumDrop = cbcModel->getMinimumDrop();\n", dValue1 == dValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setMinimumDrop(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+    fprintf(fp, "%d  cbcModel->setMinimumDrop(save_getMinimumDrop);\n", dValue1 == dValue2 ? 7 : 6);
+    dValue1 = this->getIntegerTolerance();
+    dValue2 = other->getIntegerTolerance();
+    fprintf(fp, "%d  double save_getIntegerTolerance = cbcModel->getIntegerTolerance();\n", dValue1 == dValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setIntegerTolerance(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+    fprintf(fp, "%d  cbcModel->setIntegerTolerance(save_getIntegerTolerance);\n", dValue1 == dValue2 ? 7 : 6);
+    dValue1 = this->getInfeasibilityWeight();
+    dValue2 = other->getInfeasibilityWeight();
+    fprintf(fp, "%d  double save_getInfeasibilityWeight = cbcModel->getInfeasibilityWeight();\n", dValue1 == dValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setInfeasibilityWeight(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+    fprintf(fp, "%d  cbcModel->setInfeasibilityWeight(save_getInfeasibilityWeight);\n", dValue1 == dValue2 ? 7 : 6);
+    dValue1 = this->getCutoffIncrement();
+    dValue2 = other->getCutoffIncrement();
+    fprintf(fp, "%d  double save_getCutoffIncrement = cbcModel->getCutoffIncrement();\n", dValue1 == dValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setCutoffIncrement(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+    fprintf(fp, "%d  cbcModel->setCutoffIncrement(save_getCutoffIncrement);\n", dValue1 == dValue2 ? 7 : 6);
+    dValue1 = this->getAllowableGap();
+    dValue2 = other->getAllowableGap();
+    fprintf(fp, "%d  double save_getAllowableGap = cbcModel->getAllowableGap();\n", dValue1 == dValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setAllowableGap(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+    fprintf(fp, "%d  cbcModel->setAllowableGap(save_getAllowableGap);\n", dValue1 == dValue2 ? 7 : 6);
+    dValue1 = this->getAllowableFractionGap();
+    dValue2 = other->getAllowableFractionGap();
+    fprintf(fp, "%d  double save_getAllowableFractionGap = cbcModel->getAllowableFractionGap();\n", dValue1 == dValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setAllowableFractionGap(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+    fprintf(fp, "%d  cbcModel->setAllowableFractionGap(save_getAllowableFractionGap);\n", dValue1 == dValue2 ? 7 : 6);
+    dValue1 = this->getMaximumSeconds();
+    dValue2 = other->getMaximumSeconds();
+    fprintf(fp, "%d  double save_cbcMaximumSeconds = cbcModel->getMaximumSeconds();\n", dValue1 == dValue2 ? 2 : 1);
+    fprintf(fp, "%d  cbcModel->setMaximumSeconds(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+    fprintf(fp, "%d  cbcModel->setMaximumSeconds(save_cbcMaximumSeconds);\n", dValue1 == dValue2 ? 7 : 6);
+}
+// So we can use osiObject or CbcObject during transition
+void getIntegerInformation(const OsiObject * object, double & originalLower,
+                           double & originalUpper)
+{
+    const CbcSimpleInteger * integerObject =
+        dynamic_cast<const  CbcSimpleInteger *> (object);
+    if (integerObject) {
+        // get original bounds
+        originalLower = integerObject->originalLowerBound();
+        originalUpper = integerObject->originalUpperBound();
+    } else {
+        const OsiSimpleInteger * integerObject =
+            dynamic_cast<const  OsiSimpleInteger *> (object);
+        assert (integerObject);
+        // get original bounds
+        originalLower = integerObject->originalLowerBound();
+        originalUpper = integerObject->originalUpperBound();
+    }
+}
+// Set original columns as created by preprocessing
+void
+CbcModel::setOriginalColumns(const int * originalColumns,int numberGood)
+{
+    int numberColumns = getNumCols();
+    delete [] originalColumns_;
+    originalColumns_ = new int [numberColumns];
+    int numberCopy=CoinMin(numberColumns,numberGood);
+    memcpy(originalColumns_,originalColumns,numberCopy*sizeof(int));
+    for (int i=numberCopy;i<numberColumns;i++)
+      originalColumns_[i]=-1;
+}
+// Set the cut modifier method
+void
+CbcModel::setCutModifier(CbcCutModifier * modifier)
+{
+    delete cutModifier_;
+    cutModifier_ = modifier->clone();
+}
+/* Set the cut modifier method
+ */
+void
+CbcModel::setCutModifier(CbcCutModifier & modifier)
+{
+    delete cutModifier_;
+    cutModifier_ = modifier.clone();
+}
+/* Do one node - broken out for clarity?
+   also for parallel (when baseModel!=this)
+   Returns 1 if solution found
+   node NULL on return if no branches left
+   newNode NULL if no new node created
+*/
+int
+CbcModel::doOneNode(CbcModel * baseModel, CbcNode * & node, CbcNode * & newNode)
+{
+    int foundSolution = 0;
+    int saveNumberCutGenerators=numberCutGenerators_;
+    if ((moreSpecialOptions_&33554432)!=0 && (specialOptions_&2048)==0) {
+      if (node&&(node->depth()==-2||node->depth()==4))
+	numberCutGenerators_=0; // so can dive and branch
+    }
+    currentNode_ = node; // so can be accessed elsewhere
+    double bestObjective = bestObjective_;
+    numberUpdateItems_ = 0;
+    // Say not on optimal path
+    bool onOptimalPath = false;
+#   ifdef CHECK_NODE
+    printf("Node %x popped from tree - %d left, %d count\n", node,
+           node->nodeInfo()->numberBranchesLeft(),
+           node->nodeInfo()->numberPointingToThis()) ;
+    printf("\tdepth = %d, z =  %g, unsat = %d\n", //var = %d.\n",
+           node->depth(), node->objectiveValue(),
+           node->numberUnsatisfied());
+    //node->columnNumber()) ;
+#   endif
+
+    /*
+      Rebuild the subproblem for this node:	 Call addCuts() to adjust the model
+      to recreate the subproblem for this node (set proper variable bounds, add
+      cuts, create a basis).  This may result in the problem being fathomed by
+      bound or infeasibility. Returns 1 if node is fathomed.
+      Execute the current arm of the branch: If the problem survives, save the
+      resulting variable bounds and call branch() to modify variable bounds
+      according to the current arm of the branching object. If we're processing
+      the final arm of the branching object, flag the node for removal from the
+      live set.
+    */
+    /*
+      Used to generate bound edits for CbcPartialNodeInfo.
+    */
+    int numberColumns = getNumCols() ;
+    double * lowerBefore = new double [numberColumns] ;
+    double * upperBefore = new double [numberColumns] ;
+    if (parallelMode() >= 0)
+        newNode = NULL ;
+    else
+        newNode = new CbcNode();
+    bool feasible = true;
+    CoinWarmStartBasis *lastws = new CoinWarmStartBasis();
+    lockThread();
+    // point to genuine ones
+    //int save1 = maximumNumberCuts_;
+    //maximumNumberCuts_ = baseModel->maximumNumberCuts_;
+    //addedCuts_ = baseModel->addedCuts_;
+    if (parallelMode() >= 0) {
+        maximumDepth_ = baseModel->maximumDepth_;
+        walkback_ = baseModel->walkback_;
+        lastNodeInfo_ = baseModel->lastNodeInfo_;
+        lastNumberCuts_ = baseModel->lastNumberCuts_;
+        lastCut_ = baseModel->lastCut_;
+        lastNumberCuts2_ = baseModel->lastNumberCuts2_;
+    }
+    int save2 = maximumDepth_;
+    int retCode = addCuts(node, lastws, numberFixedNow_ > numberFixedAtRoot_);
+    //if (save1<maximumNumberCuts_) {
+    // increased
+    //baseModel->maximumNumberCuts_ = maximumNumberCuts_;
+    //baseModel->addedCuts_ = addedCuts_;
+    //}
+    if (parallelMode() >= 0 && save2 < maximumDepth_) {
+        // increased
+        baseModel->maximumDepth_ = maximumDepth_;
+        baseModel->walkback_ = walkback_;
+        baseModel->lastNodeInfo_ = lastNodeInfo_;
+        baseModel->lastNumberCuts_ = lastNumberCuts_;
+        baseModel->lastCut_ = lastCut_;
+        baseModel->lastNumberCuts2_ = lastNumberCuts2_;
+    }
+    int branchesLeft = 0;
+    if (!retCode) {
+        unlockThread();
+        int i ;
+        const double * lower = getColLower() ;
+        const double * upper = getColUpper() ;
+        for (i = 0 ; i < numberColumns ; i++) {
+            lowerBefore[i] = lower[i] ;
+            upperBefore[i] = upper[i] ;
+        }
+        if ((solverCharacteristics_->extraCharacteristics()&2) != 0) {
+            solverCharacteristics_->setBeforeLower(lowerBefore);
+            solverCharacteristics_->setBeforeUpper(upperBefore);
+        }
+        lockThread();
+        assert (node->objectiveValue() < 1.0e200);
+        if (messageHandler()->logLevel() > 2)
+            node->modifiableBranchingObject()->print();
+        if (branchingMethod_ && branchingMethod_->chooseMethod()) {
+            branchesLeft = node->branch(solver_); // new way
+        } else {
+            // old way so need to cheat
+            OsiBranchingObject * branch2 = node->modifiableBranchingObject();
+#ifndef NDEBUG
+            CbcBranchingObject * branch = dynamic_cast <CbcBranchingObject *>(branch2) ;
+            assert (branch);
+#else
+            CbcBranchingObject * branch = static_cast <CbcBranchingObject *>(branch2) ;
+#endif
+#if 1
+            branch->setModel(this);
+            branchesLeft = node->branch(NULL); // old way
+#else
+            branchesLeft = node->branch(solver_);
+#endif
+            if (parallelMode() >= 0)
+                branch->setModel(baseModel);
+        }
+        assert (branchesLeft == node->nodeInfo()->numberBranchesLeft());
+        if (parallelMode() > 0) {
+            assert(masterThread_);
+            assert (node->nodeInfo());
+            node->nodeInfo()->increment() ;
+            unlockThread();
+        }
+        if ((specialOptions_&1) != 0) {
+            /*
+            This doesn't work as intended --- getRowCutDebugger will return null
+            unless the current feasible solution region includes the optimal solution
+            that RowCutDebugger knows. There's no way to tell inactive from off the
+            optimal path.
+            */
+            const OsiRowCutDebugger *debugger = solver_->getRowCutDebugger() ;
+            if (debugger) {
+                onOptimalPath = true;
+                printf("On optimal path\n") ;
+            }
+        }
+
+        /*
+          Reoptimize, possibly generating cuts and/or using heuristics to find
+          solutions.  Cut reference counts are unaffected unless we lose feasibility,
+          in which case solveWithCuts() will make the adjustment.
+        */
+        phase_ = 2;
+        OsiCuts cuts ;
+        int saveNumber = numberIterations_;
+        if (solverCharacteristics_->solutionAddsCuts()) {
+            int returnCode = resolve(node ? node->nodeInfo() : NULL, 1);
+            feasible = returnCode != 0;
+            if (feasible) {
+                int iObject ;
+                int preferredWay ;
+                int numberUnsatisfied = 0 ;
+                memcpy(currentSolution_, solver_->getColSolution(),
+                       numberColumns*sizeof(double)) ;
+                // point to useful information
+                OsiBranchingInformation usefulInfo = usefulInformation();
+
+                for (iObject = 0 ; iObject < numberObjects_ ; iObject++) {
+                    double infeasibility =
+                        object_[iObject]->infeasibility(&usefulInfo, preferredWay) ;
+                    if (infeasibility ) numberUnsatisfied++ ;
+                }
+                if (returnCode > 0) {
+                    if (numberUnsatisfied)   {
+                        feasible = solveWithCuts(cuts, maximumCutPasses_, node);
+                    } else {
+                        // may generate cuts and turn the solution
+                        //to an infeasible one
+                        feasible = solveWithCuts(cuts, 1,
+                                                 node);
+                    }
+                }
+                // check extra info on feasibility
+                if (!solverCharacteristics_->mipFeasible()) {
+                    feasible = false;
+                    solverCharacteristics_->setMipBound(-COIN_DBL_MAX);
+                }
+            }
+        } else {
+            // normal
+            if (false) {
+                const double * lower = solver_->getColLower();
+                const double * upper = solver_->getColUpper();
+                printf("STATE before solve\n");
+                for (int i = 0; i < 100; i++)
+                    if (lower[i] || !upper[i])
+                        printf("%d fixed to %g\n", i, lower[i]);
+            }
+#ifdef COIN_HAS_CLP
+            bool fathomDone = false;
+            OsiClpSolverInterface * clpSolver
+            = dynamic_cast<OsiClpSolverInterface *> (solver_);
+            if ((clpSolver || (specialOptions_&16384) != 0) && fastNodeDepth_ < -1
+		&& (specialOptions_&2048) == 0) {
+#define FATHOM_BIAS -2
+                if (numberNodes_ == 1) {
+                    int numberNodesBeforeFathom = 500;
+                    if (fastNodeDepth_ < -1000001) {
+                        numberNodesBeforeFathom = (-fastNodeDepth_) / 1000000;
+                        numberNodesBeforeFathom = 250 * numberNodesBeforeFathom;
+                    }
+#ifdef COIN_DEVELOP
+                    int fastNodeDepth1 = -fastNodeDepth_ % 1000000;
+                    printf("initial depth %d after %d nodes\n",
+                           FATHOM_BIAS + fastNodeDepth1, numberNodesBeforeFathom);
+#endif
+                }
+                //#endif
+                ClpNodeStuff stuff;
+                ClpNodeStuff * info = &stuff;
+                /*
+                  Used to generate bound edits for CbcPartialNodeInfo.
+                */
+                //double * lowerBefore = NULL;
+                //double * upperBefore = NULL;
+                int fastNodeDepth1 = -fastNodeDepth_ % 1000000;
+                int numberNodesBeforeFathom = 500;
+                if (fastNodeDepth_ < -1000001) {
+                    numberNodesBeforeFathom = (-fastNodeDepth_) / 1000000;
+                    numberNodesBeforeFathom = 100 * numberNodesBeforeFathom;
+                }
+                int go_fathom = FATHOM_BIAS + fastNodeDepth1;
+                if ((specialOptions_&16384) != 0)
+                    numberNodesBeforeFathom = 0;
+                if (node->depth() >= go_fathom && (specialOptions_&2048) == 0
+                        //if (node->depth()>=FATHOM_BIAS-fastNodeDepth_&&!parentModel_
+                        && numberNodes_ >= numberNodesBeforeFathom && !hotstartSolution_) {
+#ifndef COIN_HAS_CPX
+                    specialOptions_ &= ~16384;
+#endif
+                    if ((specialOptions_&16384) == 0) {
+                        info->integerTolerance_ = getIntegerTolerance();
+                        info->integerIncrement_ = getCutoffIncrement();
+                        info->numberBeforeTrust_ = numberBeforeTrust_;
+                        info->stateOfSearch_ = 1;
+                        if (numberSolutions_ > 0) {
+                            info->stateOfSearch_ = 3;
+                        }
+                        if (numberNodes_ > 2*numberObjects_ + 1000) {
+                            info->stateOfSearch_ = 4;
+                        }
+                        // Compute "small" change in branch
+                        int nBranches = intParam_[CbcNumberBranches];
+                        if (nBranches) {
+                            double average = dblParam_[CbcSumChange] / static_cast<double>(nBranches);
+                            info->smallChange_ =
+                                CoinMax(average * 1.0e-5, dblParam_[CbcSmallestChange]);
+                            info->smallChange_ = CoinMax(info->smallChange_, 1.0e-8);
+                        } else {
+                            info->smallChange_ = 1.0e-8;
+                        }
+                        double * down = new double[numberIntegers_];
+                        double * up = new double[numberIntegers_];
+                        int * priority = new int[numberIntegers_];
+                        int * numberDown = new int[numberIntegers_];
+                        int * numberUp = new int[numberIntegers_];
+                        int * numberDownInfeasible = new int[numberIntegers_];
+                        int * numberUpInfeasible = new int[numberIntegers_];
+                        fillPseudoCosts(down, up, priority, numberDown, numberUp,
+                                        numberDownInfeasible, numberUpInfeasible);
+                        // See if all priorities same
+                        bool allSame = true;
+                        int kPriority = priority[0];
+                        for (int i = 1; i < numberIntegers_; i++) {
+                            if (kPriority != priority[i]) {
+                                allSame = false;
+                                break;
+                            }
+                        }
+                        ClpSimplex * simplex = clpSolver->getModelPtr();
+                        if (allSame && false) {
+                            // change priorities on general
+                            const double * lower = simplex->columnLower();
+                            const double * upper = simplex->columnUpper();
+                            for (int i = 0; i < numberIntegers_; i++) {
+                                int iColumn = integerVariable_[i];
+                                if (upper[iColumn] > lower[iColumn] + 1.1)
+                                    priority[i] = kPriority + 1;
+                            }
+                        }
+                        info->fillPseudoCosts(down, up, priority, numberDown, numberUp,
+                                              numberDownInfeasible,
+                                              numberUpInfeasible, numberIntegers_);
+                        info->presolveType_ = 1;
+                        // for reduced costs and duals
+                        info->solverOptions_ |= 7;
+                        delete [] down;
+                        delete [] up;
+                        delete [] numberDown;
+                        delete [] priority;
+                        delete [] numberUp;
+                        delete [] numberDownInfeasible;
+                        delete [] numberUpInfeasible;
+                        bool takeHint;
+                        OsiHintStrength strength;
+                        solver_->getHintParam(OsiDoReducePrint, takeHint, strength);
+                        //printf("mod cutoff %g solver %g offset %g\n",
+                        //   getCutoff(),simplex->dualObjectiveLimit(),simplex->objectiveOffset());
+                        int saveLevel = simplex->logLevel();
+                        if (strength != OsiHintIgnore && takeHint && saveLevel == 1)
+                            simplex->setLogLevel(0);
+                        clpSolver->setBasis();
+                        int perturbation = simplex->perturbation();
+                        if ((specialOptions_&131072) != 0) {
+			    //assert (perturbation == 100);
+                            simplex->setPerturbation(50);
+                        }
+			int saveMoreOptions = simplex->moreSpecialOptions();
+			int flags = (moreSpecialOptions_>>18)&3;
+			simplex->setMoreSpecialOptions(saveMoreOptions|flags<<11);
+#ifndef NO_FATHOM_PRINT
+			info->startingDepth_ = node->depth();
+			info->nodeCalled_ = numberNodes_;
+			info->handler_ = handler_;
+#endif
+                        feasible = simplex->fathom(info) != 0;
+			simplex->setMoreSpecialOptions(saveMoreOptions);
+                        simplex->setPerturbation(perturbation);
+                        numberExtraNodes_ += info->numberNodesExplored_;
+                        numberExtraIterations_ += info->numberIterations_;
+			char general[200];
+			int fathomStatus=info->nNodes_;
+			if (feasible)
+			  fathomStatus=1;
+			sprintf(general, "fathom took %d nodes, %d iterations - status %d",
+				info->numberNodesExplored_,
+				info->numberIterations_,fathomStatus);
+			messageHandler()->message(CBC_FPUMP2,
+                                          messages())
+			  << general << CoinMessageEol ;
+                        if (info->numberNodesExplored_ > 10000 /* && !feasible */ 
+			    && (moreSpecialOptions_&524288) == 0  && info->nNodes_>=0) {
+                            fastNodeDepth_ --;
+#ifndef NO_FATHOM_PRINT
+			    if ((moreSpecialOptions_&262144) != 0)
+			      handler_->message(CBC_FATHOM_CHANGE, messages_) << 
+				FATHOM_BIAS - fastNodeDepth_ << CoinMessageEol ;
+#endif
+#ifdef CLP_INVESTIGATE
+                            printf(">10000 - depth now %d so at depth >= %d\n",
+                                   fastNodeDepth_, FATHOM_BIAS - fastNodeDepth_);
+#endif
+                        }
+                        if (info->nNodes_ < 0) {
+                            // we gave up
+                            //abort();
+                            fastNodeDepth_ -= 3;
+#ifndef NO_FATHOM_PRINT
+			  if ((moreSpecialOptions_&262144) != 0)
+			    handler_->message(CBC_FATHOM_CHANGE, messages_) << 
+			      FATHOM_BIAS - fastNodeDepth_ << CoinMessageEol ;
+#endif
+#ifdef CLP_INVESTIGATE
+                            printf("fastNodeDepth now %d - so at depth >= %d\n",
+                                   fastNodeDepth_, FATHOM_BIAS - fastNodeDepth_);
+#endif
+                            if (feasible) {
+                                // Save bounds round bestSolution
+                                //double * saveLower = CoinCopyOfArray(solver_->getColLower(),
+                                //			     numberColumns);
+                                //double * saveUpper = CoinCopyOfArray(solver_->getColUpper(),
+                                //			     numberColumns);
+                                clpSolver->setWarmStart(NULL);
+                                // try and do solution
+                                double value = simplex->objectiveValue() *
+                                               simplex->optimizationDirection();
+                                double * newSolution =
+                                    CoinCopyOfArray(simplex->primalColumnSolution(),
+                                                    numberColumns);
+                                setBestSolution(CBC_STRONGSOL, value, newSolution) ;
+                                delete [] newSolution;
+                                //solver_->setColLower(saveLower);
+                                //solver_->setColUpper(saveUpper);
+                                //delete [] saveLower;
+                                //delete [] saveUpper;
+                            }
+                            // say feasible so will redo node
+                            feasible = true;
+                        } else {
+                            if (feasible) {
+                                clpSolver->setWarmStart(NULL);
+                                // try and do solution
+                                double value = simplex->objectiveValue() *
+                                               simplex->optimizationDirection();
+                                double * newSolution =
+                                    CoinCopyOfArray(simplex->primalColumnSolution(),
+                                                    numberColumns);
+                                setBestSolution(CBC_STRONGSOL, value, newSolution) ;
+                                delete [] newSolution;
+                            }
+                            // update pseudo costs
+                            double smallest = 1.0e50;
+                            double largest = -1.0;
+                            for (int i = 0; i < numberIntegers_; i++) {
+                                CbcSimpleIntegerDynamicPseudoCost * obj =
+                                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[i]) ;
+                                if (!obj)
+                                    continue;
+                                assert (obj->columnNumber() == integerVariable_[i]);
+                                if (info->numberUp_[i] > 0) {
+                                    if (info->downPseudo_[i] > largest)
+                                        largest = info->downPseudo_[i];
+                                    if (info->downPseudo_[i] < smallest)
+                                        smallest = info->downPseudo_[i];
+                                    if (info->upPseudo_[i] > largest)
+                                        largest = info->upPseudo_[i];
+                                    if (info->upPseudo_[i] < smallest)
+                                        smallest = info->upPseudo_[i];
+                                    obj->updateAfterMini(info->numberDown_[i],
+                                                         info->numberDownInfeasible_[i],
+                                                         info->downPseudo_[i],
+                                                         info->numberUp_[i],
+                                                         info->numberUpInfeasible_[i],
+                                                         info->upPseudo_[i]);
+                                }
+                            }
+                            //printf("range of costs %g to %g\n",smallest,largest);
+                            // If value of objective borderline then may not be feasible
+                            double value = simplex->objectiveValue() * simplex->optimizationDirection();
+                            if (value - getCutoff() < -1.0e-1)
+                                fathomDone = true;
+                        }
+                        simplex->setLogLevel(saveLevel);
+#ifdef COIN_HAS_CPX
+                    } else {
+                        // try cplex
+                        OsiCpxSolverInterface cpxSolver;
+                        double direction = clpSolver->getObjSense();
+                        cpxSolver.setObjSense(direction);
+                        // load up cplex
+                        const CoinPackedMatrix * matrix = clpSolver->getMatrixByCol();
+                        const double * rowLower = clpSolver->getRowLower();
+                        const double * rowUpper = clpSolver->getRowUpper();
+                        const double * columnLower = clpSolver->getColLower();
+                        const double * columnUpper = clpSolver->getColUpper();
+                        const double * objective = clpSolver->getObjCoefficients();
+                        cpxSolver.loadProblem(*matrix, columnLower, columnUpper,
+                                              objective, rowLower, rowUpper);
+                        double * setSol = new double [numberIntegers_];
+                        int * setVar = new int [numberIntegers_];
+                        // cplex doesn't know about objective offset
+                        double offset = clpSolver->getModelPtr()->objectiveOffset();
+                        for (int i = 0; i < numberIntegers_; i++) {
+                            int iColumn = integerVariable_[i];
+                            cpxSolver.setInteger(iColumn);
+                            if (bestSolution_) {
+                                setSol[i] = bestSolution_[iColumn];
+                                setVar[i] = iColumn;
+                            }
+                        }
+                        CPXENVptr env = cpxSolver.getEnvironmentPtr();
+                        CPXLPptr lpPtr = cpxSolver.getLpPtr(OsiCpxSolverInterface::KEEPCACHED_ALL);
+                        cpxSolver.switchToMIP();
+                        if (bestSolution_) {
+                            CPXcopymipstart(env, lpPtr, numberIntegers_, setVar, setSol);
+                        }
+                        if (getCutoff() < 1.0e50) {
+                            double useCutoff = getCutoff() + offset;
+                            if (bestObjective_ < 1.0e50)
+                                useCutoff = bestObjective_ + offset + 1.0e-7;
+                            cpxSolver.setDblParam(OsiDualObjectiveLimit, useCutoff*
+                                                  direction);
+                            if ( direction > 0.0 )
+                                CPXsetdblparam( env, CPX_PARAM_CUTUP, useCutoff ) ; // min
+                            else
+                                CPXsetdblparam( env, CPX_PARAM_CUTLO, useCutoff ) ; // max
+                        }
+                        CPXsetdblparam(env, CPX_PARAM_EPGAP, dblParam_[CbcAllowableFractionGap]);
+                        delete [] setSol;
+                        delete [] setVar;
+                        if (offset) {
+                            char printBuffer[200];
+                            sprintf(printBuffer, "Add %g to all Cplex messages for true objective",
+                                    -offset);
+                            messageHandler()->message(CBC_GENERAL, messages())
+                            << printBuffer << CoinMessageEol ;
+                            cpxSolver.setDblParam(OsiObjOffset, offset);
+                        }
+                        cpxSolver.branchAndBound();
+                        numberExtraNodes_ += CPXgetnodecnt(env, lpPtr);
+                        numberExtraIterations_ += CPXgetmipitcnt(env, lpPtr);
+                        double value = cpxSolver.getObjValue() * direction;
+                        if (cpxSolver.isProvenOptimal() && value <= getCutoff()) {
+                            feasible = true;
+                            clpSolver->setWarmStart(NULL);
+                            // try and do solution
+                            double * newSolution =
+                                CoinCopyOfArray(cpxSolver.getColSolution(),
+                                                getNumCols());
+                            setBestSolution(CBC_STRONGSOL, value, newSolution) ;
+                            delete [] newSolution;
+                            fathomDone = true;
+                        } else {
+                            feasible = false;
+                        }
+#endif
+                    }
+                }
+            }
+            if (feasible) {
+                //int numberPasses = doCutsNow(1) ? maximumCutPasses_ : 0;
+                int numberPasses = /*doCutsNow(1) ?*/ maximumCutPasses_ /*: 0*/;
+                feasible = solveWithCuts(cuts, numberPasses, node);
+                if (fathomDone)
+                    assert (feasible);
+            }
+#else
+            feasible = solveWithCuts(cuts, maximumCutPasses_, node);
+#endif
+        }
+        if ((specialOptions_&1) != 0 && onOptimalPath) {
+	    if(solver_->getRowCutDebuggerAlways()->optimalValue()<getCutoff()) {
+	        if (!solver_->getRowCutDebugger() || !feasible) {
+		  // dj fix did something???
+		  solver_->writeMpsNative("infeas2.mps", NULL, NULL, 2);
+		  solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
+#ifndef NDEBUG
+		  const OsiRowCutDebugger * debugger = solver_->getRowCutDebugger() ;
+#endif
+		  assert (debugger) ;
+		  int numberRows0=continuousSolver_->getNumRows();
+		  int numberRows=solver_->getNumRows();
+		  const CoinPackedMatrix * rowCopy = solver_->getMatrixByRow();
+		  const int * rowLength = rowCopy->getVectorLengths(); 
+		  const double * elements = rowCopy->getElements();
+		  const int * column = rowCopy->getIndices();
+		  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+		  const double * rowLower = solver_->getRowLower();
+		  const double * rowUpper = solver_->getRowUpper();
+		  for (int iRow=numberRows0;iRow<numberRows;iRow++) {
+		    OsiRowCut rc;
+		    rc.setLb(rowLower[iRow]);
+		    rc.setUb(rowUpper[iRow]);
+		    CoinBigIndex start = rowStart[iRow];
+		    rc.setRow(rowLength[iRow],column+start,elements+start,false);
+		    CoinAssert (!debugger->invalidCut(rc));
+		  }
+		  assert (feasible);
+		}
+            }
+        }
+        if (statistics_) {
+            assert (numberNodes2_);
+            assert (statistics_[numberNodes2_-1]);
+            assert (statistics_[numberNodes2_-1]->node() == numberNodes2_ - 1);
+            statistics_[numberNodes2_-1]->endOfBranch(numberIterations_ - saveNumber,
+                    feasible ? solver_->getObjValue()
+                    : COIN_DBL_MAX);
+        }
+        /*
+          Are we still feasible? If so, create a node and do the work to attach a
+          branching object, reoptimising as needed if chooseBranch() identifies
+          monotone objects.
+
+          Finally, attach a partial nodeInfo object and store away any cuts that we
+          created back in solveWithCuts. addCuts() will initialise the reference
+          counts for these new cuts.
+
+          This next test can be problematic if we've discovered an
+          alternate equivalent answer and subsequently fathom the solution
+          known to the row cut debugger due to bounds.
+        */
+        if (onOptimalPath) {
+            bool objLim = solver_->isDualObjectiveLimitReached() ;
+            if (!feasible && !objLim) {
+	      if(solver_->getRowCutDebuggerAlways()->optimalValue()<getCutoff()) {
+                printf("infeas2\n");
+                solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
+                solver_->writeMpsNative("infeas.mps", NULL, NULL, 2);
+                CoinWarmStartBasis *slack =
+                    dynamic_cast<CoinWarmStartBasis *>(solver_->getEmptyWarmStart()) ;
+                solver_->setWarmStart(slack);
+                delete slack ;
+                solver_->setHintParam(OsiDoReducePrint, false, OsiHintDo, 0) ;
+                solver_->initialSolve();
+                assert (!solver_->isProvenOptimal());
+		assert (feasible || objLim);
+	      }
+            }
+        }
+        bool checkingNode = false;
+        if (feasible) {
+#ifdef FUNNY_BRANCHING2
+            // Far too clever
+            if ((numberThreads_ == -10 || true) && node->numberBranches() == 2) {
+                // see if any parent branches redundant
+                // Look at state of "node"
+                CbcNodeInfo * nodeInfo = node->nodeInfo();
+                if (nodeInfo) {
+                    // See if any branched variables off bounds
+                    const double * dj = solver_->getReducedCost();
+                    const double * lower = solver_->getColLower();
+                    const double * upper = solver_->getColUpper();
+                    const double * solution = solver_->getColSolution();
+                    int numberColumns = solver_->getNumCols();
+                    double * currentLower = CoinCopyOfArray(lower, numberColumns);
+                    double * currentUpper = CoinCopyOfArray(upper, numberColumns);
+                    char * touched = new char[numberColumns];
+                    memset(touched, 0, numberColumns);
+                    double direction = solver_->getObjSense() ;
+                    bool canDelete = nodeInfo->numberBranchesLeft() > 0;
+                    //int numberBounds = nodeInfo->numberChangedBounds();
+                    //const int * which = nodeInfo->variables();
+                    //const double * bounds = nodeInfo->newBounds();
+                    const OsiBranchingObject * obj = node->branchingObject();
+                    const CbcIntegerBranchingObject * objectI = dynamic_cast<const CbcIntegerBranchingObject *> (obj);
+                    if (objectI) {
+                        const CbcSimpleInteger * object1 = dynamic_cast<const CbcSimpleInteger *> (objectI->object());
+                        int iColumn1 = -1;
+                        int way1 = 0;
+                        const double * bounds1 = NULL;
+                        bool zeroOne1 = false;
+                        if (object1) {
+                            iColumn1 = object1->columnNumber();
+                            double originalLower1 = object1->originalLowerBound();
+                            double originalUpper1 = object1->originalUpperBound();
+                            // Unset all bounds from parents
+                            CbcPartialNodeInfo * partial =
+                                dynamic_cast<CbcPartialNodeInfo *>(nodeInfo);
+                            touched[iColumn1] = 1;
+                            if (partial) {
+                                /* maybe don't do if obj hasn't changed
+                                as then you might get loop
+                                at present just 0-1
+                                as need to know original bound
+                                */
+                                int n = partial->numberChangedBounds();
+                                const int * which = partial->variables();
+                                const double * values = partial->newBounds();
+                                for (int i = 0; i < n; i++) {
+                                    int variable = which[i];
+                                    int k = variable & 0x3fffffff;
+                                    assert (k != iColumn1);
+                                    if (!touched[k]) {
+                                        if ((variable&0x80000000) == 0) {
+                                            // lower bound changing
+                                            assert (currentLower[k] == 1.0);
+                                            currentLower[k] = 0.0;
+                                        } else {
+                                            // upper bound changing
+                                            assert (currentUpper[k] == 0.0);
+                                            currentUpper[k] = 1.0;
+                                        }
+                                    }
+                                }
+                            }
+                            zeroOne1 = originalLower1 == 0.0 && originalUpper1 == 1.0;
+                            way1 = objectI->way();
+                            assert (way1 == -1 || way1 == 1);
+                            int kWay = way1;
+                            //way1 = -way1; // what last branch did
+                            // work out using bounds
+                            if (objectI->downBounds()[1] >= upper[iColumn1] &&
+                                    objectI->downBounds()[0] <= lower[iColumn1])
+                                way1 = -1;
+                            else
+                                way1 = 1;
+                            assert (kWay == -way1);
+                            if (way1 < 0) {
+                                // must have been down branch
+                                bounds1 = objectI->downBounds();
+                            } else {
+                                // must have been up branch
+                                bounds1 = objectI->upBounds();
+                            }
+                            // double check bounds
+                            assert (bounds1[0] <= lower[iColumn1] && bounds1[1] >= upper[iColumn1]);
+                        }
+                        bool inBetween = false;
+#ifdef CBC_PRINT2
+                        printf("%d (way %d) with down bounds %g, %g and up bounds %g, %g current bounds %g, %g solution %g dj %g (bleft %d)\n",
+                               iColumn1, way1, objectI->downBounds()[0], objectI->downBounds()[1],
+                               objectI->upBounds()[0], objectI->upBounds()[1],
+                               lower[iColumn1], upper[iColumn1], solution[iColumn1],
+                               dj[iColumn1], nodeInfo->numberBranchesLeft());
+#endif
+                        while (nodeInfo->parent()) {
+                            nodeInfo = nodeInfo->parent();
+                            CbcNode * nodeLook = nodeInfo->mutableOwner();
+                            if (!nodeLook || nodeLook->objectiveValue() == 0.5*COIN_DBL_MAX)
+                                continue;
+                            OsiBranchingObject * obj = nodeLook->modifiableBranchingObject();
+                            CbcIntegerBranchingObject * objectI = dynamic_cast<CbcIntegerBranchingObject *> (obj);
+                            //const OsiObject * object2a = obj->originalObject();
+                            //assert (object2a);
+                            const CbcSimpleInteger * object2 = dynamic_cast<const CbcSimpleInteger *> (objectI->object());
+                            if (nodeInfo->numberBranchesLeft() && object2) {
+                                int iColumn2 = object2->columnNumber();
+                                double originalLower = object2->originalLowerBound();
+                                double originalUpper = object2->originalUpperBound();
+                                bool zeroOne2 = originalLower == 0.0 && originalUpper == 1.0;
+                                zeroOne1 = true; // temp
+                                double newUpper = originalUpper;
+                                double newLower = originalLower;
+                                //double value = solution[iColumn2];
+                                double djValue = dj[iColumn2] * direction;
+                                int way = objectI->way();
+                                assert (way == -1 || way == 1);
+                                way = -way; // what last branch did
+#ifdef CBC_PRINT2
+                                printf("%d (way %d) with down bounds %g, %g and up bounds %g, %g current bounds %g, %g solution %g dj %g (bleft %d)\n",
+                                       iColumn2, way, objectI->downBounds()[0], objectI->downBounds()[1],
+                                       objectI->upBounds()[0], objectI->upBounds()[1],
+                                       lower[iColumn2], upper[iColumn2], solution[iColumn2],
+                                       djValue, nodeInfo->numberBranchesLeft());
+#endif
+                                /*if (objectI->downBounds()[0]==0&&objectI->downBounds()[1]==1&&
+                                    objectI->upBounds()[0]==0&&objectI->upBounds()[1]==1)
+                                    assert(lower[iColumn2]<upper[iColumn2]);*/
+                                if (way < 0) {
+                                    // must have been down branch
+                                    const double * bounds = objectI->downBounds();
+                                    if (djValue > 1.0e-3 || solution[iColumn2] < upper[iColumn2] - 1.0e-5) {
+                                        if (canDelete) {
+                                            //nRedundantDown++;
+#ifndef JJF_ONE
+                                            COIN_DETAIL_PRINT(printf("%d redundant branch down with bounds %g, %g current upper %g solution %g dj %g\n",
+								     iColumn2, bounds[0], bounds[1], upper[iColumn2], solution[iColumn2], djValue));
+#endif
+                                            if (bounds[0] == bounds[1] || zeroOne2 || (bounds[0] == lower[iColumn2] && false)) {
+                                                {
+                                                    // get rid of node as far as branching
+                                                    nodeLook->setObjectiveValue(0.5*COIN_DBL_MAX);
+                                                    objectI->deactivate();
+                                                }
+                                                previousBounds(node, nodeInfo, iColumn2, newLower, newUpper, 2);
+                                                solver_->setColUpper(iColumn2, newUpper);
+                                                assert (newLower == lower[iColumn2]);
+                                            } else {
+					      COIN_DETAIL_PRINT(printf("SKipping\n"));
+                                            }
+                                        } else if (iColumn1 >= 0 && iColumn1 != iColumn2 && (!inBetween || true) && zeroOne1 && zeroOne2 && false) {
+#ifndef JJF_ONE
+                                            if (true) {
+                                                // add in bounds
+                                                newLower = bounds1[0];
+                                                newUpper = bounds1[1];
+                                                COIN_DETAIL_PRINT(printf("setting bounds of %g and %g (column %d) on other branch for column %d\n",
+									 newLower, newUpper, iColumn1, iColumn2));
+                                                int infeasible = objectI->applyExtraBounds(iColumn1, newLower, newUpper, objectI->way());
+                                                if (infeasible) {
+						  COIN_DETAIL_PRINT(printf("infeasa!\n"));
+                                                    // get rid of node as far as branching
+                                                    nodeLook->setObjectiveValue(0.5*COIN_DBL_MAX);
+                                                }
+                                            }
+#endif
+                                        }
+                                        //break;
+                                    } else {
+                                        inBetween = true;
+                                    }
+                                } else {
+                                    // must have been up branch
+                                    const double * bounds = objectI->upBounds();
+                                    if (djValue < -1.0e-3 || solution[iColumn2] > lower[iColumn2] + 1.0e-5) {
+                                        if (canDelete) {
+                                            //nRedundantUp++;
+#ifndef JJF_ONE
+                                            COIN_DETAIL_PRINT(printf("%d redundant branch up with bounds %g, %g current lower %g solution %g dj %g\n",
+								     iColumn2, bounds[0], bounds[1], lower[iColumn2], solution[iColumn2], djValue));
+#endif
+                                            if (bounds[0] == bounds[1] || zeroOne2 || (bounds[1] == upper[iColumn2] && false)) {
+                                                {
+                                                    // get rid of node as far as branching
+                                                    nodeLook->setObjectiveValue(0.5*COIN_DBL_MAX);
+                                                    objectI->deactivate();
+                                                }
+                                                previousBounds(node, nodeInfo, iColumn2, newLower, newUpper, 1);
+                                                solver_->setColLower(iColumn2, newLower);
+                                                assert (newUpper == upper[iColumn2]);
+                                            } else {
+					      COIN_DETAIL_PRINT(printf("SKipping\n"));
+                                            }
+                                        } else if (iColumn1 >= 0 && iColumn1 != iColumn2 && (!inBetween || true) && zeroOne1 && zeroOne2 && false) {
+#ifndef JJF_ONE
+                                            // add in bounds
+                                            newLower = bounds1[0];
+                                            newUpper = bounds1[1];
+                                            COIN_DETAIL_PRINT(printf("setting bounds of %g and %g (column %d) on other branch for column %d\n",
+                                                   newLower, newUpper, iColumn1, iColumn2));
+                                            int infeasible = objectI->applyExtraBounds(iColumn1, newLower, newUpper, objectI->way());
+                                            if (infeasible) {
+					      COIN_DETAIL_PRINT(printf("infeasb!\n"));
+                                                // get rid of node as far as branching
+                                                nodeLook->setObjectiveValue(0.5*COIN_DBL_MAX);
+                                            }
+#endif
+                                        }
+                                        // break;
+                                    } else {
+                                        inBetween = true;
+                                    }
+                                }
+                            } else {
+                                // odd
+                                break;
+                            }
+                        }
+                    }
+                    delete [] currentLower;
+                    delete [] currentUpper;
+                }
+            }
+#endif
+            if (parallelMode() >= 0)
+                newNode = new CbcNode() ;
+#if 0
+	    // Try diving
+            if (parallelMode() >= 0 && (specialOptions_&2048) == 0) {
+	      // See if any diving heuristics set to do dive+save
+	      CbcHeuristicDive * dive=NULL;
+	      for (int i = 0; i < numberHeuristics_; i++) {
+		CbcHeuristicDive * possible = dynamic_cast<CbcHeuristicDive *>(heuristic_[i]);
+		if (possible&&possible->maxSimplexIterations()==COIN_INT_MAX) {
+		  // if more than one then rotate later?
+		  //if (possible->canHeuristicRun()) {
+		  if (node->depth()==0||node->depth()==5) {
+		    dive=possible;
+		    break;
+		  }
+		}
+	      }
+	      if (dive) {
+		int numberNodes;
+		CbcSubProblem ** nodes=NULL;
+		int branchState=dive->fathom(this,numberNodes,nodes);
+		if (branchState) {
+		  printf("new solution\n");
+		}
+		if (0) {
+		  for (int iNode=0;iNode<numberNodes;iNode++) {
+		    //tree_->push(nodes[iNode]) ;
+		  }
+		  assert (node->nodeInfo());
+		  if (node->nodeInfo()->numberBranchesLeft()) {
+		    tree_->push(node) ;
+		  } else {
+		    node->setActive(false);
+		  }
+		}
+		delete [] nodes;
+	      }
+	    }
+	    // end try diving
+#endif
+            // Set objective value (not so obvious if NLP etc)
+            setObjectiveValue(newNode, node);
+            int anyAction = -1 ;
+            bool resolved = false ;
+            if (newNode->objectiveValue() >= getCutoff()) {
+                anyAction = -2;
+            } else {// only allow at most a few passes
+                int numberPassesLeft = 5;
+                checkingNode = true;
+                OsiSolverBranch * branches = NULL;
+                // point to useful information
+                anyAction = chooseBranch(newNode, numberPassesLeft, node, cuts, resolved,
+                                         lastws, lowerBefore, upperBefore, branches);
+            }
+            /*
+            If we end up infeasible, we can delete the new node immediately. Since this
+            node won't be needing the cuts we collected, decrement the reference counts.
+            If we are feasible, then we'll be placing this node into the live set, so
+            increment the reference count in the current (parent) nodeInfo.
+            */
+            lockThread();
+            if (anyAction == -2) {
+                if (parallelMode() > 0) {
+                    assert (masterThread_);
+                    assert (node->nodeInfo());
+                    node->nodeInfo()->decrement() ;
+                    delete newNode ;
+                    assert (node->nodeInfo());
+                    node->nodeInfo()->increment() ;
+                    newNode = NULL ;
+                } else if (parallelMode() == 0) {
+                    delete newNode ;
+                    newNode = NULL ;
+                } else {
+                    //assert (newNode->active());
+                    newNode->setActive(false);
+                }
+                // say strong doing well
+                if (checkingNode)
+                    setSpecialOptions(specialOptions_ | 8);
+                for (i = 0 ; i < currentNumberCuts_ ; i++) {
+                    if (addedCuts_[i]) {
+                        if (!addedCuts_[i]->decrement(1)) {
+                            delete addedCuts_[i] ;
+                        }
+                        addedCuts_[i] = NULL;
+                        //}
+                    }
+                }
+            }	else {
+                assert (node->nodeInfo());
+                if (parallelMode() >= 0)
+                    node->nodeInfo()->increment() ;
+                if ((numberNodes_ % 20) == 0) {
+                    // say strong not doing as well
+                    setSpecialOptions(specialOptions_&~8);
+                }
+            }
+            unlockThread();
+        }
+        /*
+          At this point, there are three possibilities:
+          * newNode is live and will require further branching to resolve
+          (variable() >= 0). Increment the cut reference counts by
+          numberBranches() to allow for use by children of this node, and
+          decrement by 1 because we've executed one arm of the branch of our
+          parent (consuming one reference). Before we push newNode onto the
+          search tree, try for a heuristic solution.
+          * We have a solution, in which case newNode is non-null but we have no
+          branching variable. Decrement the cut counts and save the solution.
+          * The node was found to be infeasible, in which case it's already been
+          deleted, and newNode is null.
+        */
+        if (eventHandler_ && !eventHandler_->event(CbcEventHandler::node)) {
+            eventHappened_ = true; // exit
+        }
+        if (parallelMode() >= 0)
+            assert (!newNode || newNode->objectiveValue() <= getCutoff()) ;
+        else
+            assert (!newNode->active() || newNode->objectiveValue() <= getCutoff()) ;
+        if (statistics_) {
+            assert (numberNodes2_);
+            assert (statistics_[numberNodes2_-1]);
+            assert (statistics_[numberNodes2_-1]->node() == numberNodes2_ - 1);
+            if (newNode && newNode->active())
+                statistics_[numberNodes2_-1]->updateInfeasibility(newNode->numberUnsatisfied());
+            else
+                statistics_[numberNodes2_-1]->sayInfeasible();
+        }
+        lockThread();
+        bool locked = true;
+        if (parallelMode() <= 0) {
+            if (numberUpdateItems_) {
+                for (i = 0; i < numberUpdateItems_; i++) {
+                    CbcObjectUpdateData * update = updateItems_ + i;
+                    CbcObject * object = dynamic_cast<CbcObject *> (update->object_);
+#ifndef NDEBUG
+                    bool found = false;
+                    for (int j = 0; j < numberObjects_; j++) {
+                        if (update->object_ == object_[j]) {
+                            found = true;
+                            break;
+                        }
+                    }
+                    assert (found);
+#endif
+                    //if (object)
+                    //assert (object==object_[update->objectNumber_]);
+                    if (object)
+                        object->updateInformation(*update);
+                }
+                numberUpdateItems_ = 0;
+            }
+        }
+        if (newNode)
+            if (newNode && newNode->active()) {
+                if (newNode->branchingObject() == NULL) {
+                    const double * solution = solver_->getColSolution();
+                    CbcEventHandler::CbcAction action =
+                        dealWithEventHandler(CbcEventHandler::beforeSolution1,
+                                             getSolverObjValue(), solution);
+                    if (action == CbcEventHandler::addCuts ||
+                            solverCharacteristics_->solverType() == 4) {
+                        // need to check if any cuts would do anything
+                        OsiCuts theseCuts;
+                        // reset probing info
+                        //if (probingInfo_)
+                        //probingInfo_->initializeFixing(solver_);
+                        for (int i = 0; i < numberCutGenerators_; i++) {
+                            bool generate = generator_[i]->normal();
+                            // skip if not optimal and should be (maybe a cut generator has fixed variables)
+                            if (generator_[i]->needsOptimalBasis() && !solver_->basisIsAvailable())
+                                generate = false;
+                            if (!generator_[i]->mustCallAgain())
+                                generate = false; // only special cuts
+                            if (generate) {
+                                generator_[i]->generateCuts(theseCuts, -1, solver_, NULL) ;
+                                int numberRowCutsAfter = theseCuts.sizeRowCuts() ;
+                                if (numberRowCutsAfter)
+                                    break;
+                            }
+                        }
+                        int numberRowCutsAfter = theseCuts.sizeRowCuts() ;
+                        if (numberRowCutsAfter ||
+                                action == CbcEventHandler::addCuts) {
+                            // need dummy branch
+                            newNode->setBranchingObject(new CbcDummyBranchingObject(this));
+                            newNode->nodeInfo()->initializeInfo(1);
+                        }
+                    }
+                }
+                if (newNode->branchingObject()) {
+                    handler_->message(CBC_BRANCH, messages_)
+                    << numberNodes_ << newNode->objectiveValue()
+                    << newNode->numberUnsatisfied() << newNode->depth()
+                    << CoinMessageEol ;
+                    // Increment cut counts (taking off current)
+                    int numberLeft = newNode->numberBranches() ;
+                    for (i = 0; i < currentNumberCuts_; i++) {
+                        if (addedCuts_[i]) {
+#		ifdef CHECK_CUT_COUNTS
+                            printf("Count on cut %x increased by %d\n", addedCuts_[i],
+                                   numberLeft - 1) ;
+#		endif
+                            addedCuts_[i]->increment(numberLeft - 1) ;
+                        }
+                    }
+                    unlockThread();
+                    locked = false;
+                    double estValue = newNode->guessedObjectiveValue() ;
+                    int found = -1 ;
+                    double * newSolution = new double [numberColumns] ;
+                    double heurValue = getCutoff() ;
+                    int iHeur ;
+                    int whereFrom = 3;
+                    for (iHeur = 0 ; iHeur < numberHeuristics_ ; iHeur++) {
+                        // skip if can't run here
+                        if (!heuristic_[iHeur]->shouldHeurRun(whereFrom))
+                            continue;
+                        double saveValue = heurValue ;
+                        int ifSol = heuristic_[iHeur]->solution(heurValue, newSolution) ;
+                        if (ifSol > 0) {
+                            // new solution found
+                            heuristic_[iHeur]->incrementNumberSolutionsFound();
+                            found = iHeur ;
+                            if (parallelMode() > 0) {
+                                lockThread();
+                                baseModel->incrementUsed(newSolution);
+                                unlockThread();
+                            } else {
+                                lastHeuristic_ = heuristic_[found];
+#ifdef CLP_INVESTIGATE
+                                printf("HEUR %s where %d D\n",
+                                       lastHeuristic_->heuristicName(), whereFrom);
+#endif
+                                setBestSolution(CBC_ROUNDING, heurValue, newSolution) ;
+                                foundSolution = 1;
+                                whereFrom |= 8; // say solution found
+                            }
+                        } else if (ifSol < 0)	{ // just returning an estimate
+                            estValue = CoinMin(heurValue, estValue) ;
+                            heurValue = saveValue ;
+                        }
+                    }
+                    if (found >= 0 && parallelMode() > 0) {
+                        lastHeuristic_ = heuristic_[found];
+#ifdef CLP_INVESTIGATE
+                        printf("HEUR %s where %d D\n",
+                               lastHeuristic_->heuristicName(), whereFrom);
+#endif
+                        setBestSolution(CBC_ROUNDING, heurValue, newSolution) ;
+                        foundSolution = 1;
+                    }
+                    delete [] newSolution ;
+                    newNode->setGuessedObjectiveValue(estValue) ;
+                    if (parallelMode() >= 0) {
+                        if (!masterThread_) // only if serial
+                            tree_->push(newNode) ;
+                    }
+                    if (statistics_) {
+                        if (numberNodes2_ == maximumStatistics_) {
+                            maximumStatistics_ = 2 * maximumStatistics_;
+                            CbcStatistics ** temp = new CbcStatistics * [maximumStatistics_];
+                            memset(temp, 0, maximumStatistics_*sizeof(CbcStatistics *));
+                            memcpy(temp, statistics_, numberNodes2_*sizeof(CbcStatistics *));
+                            delete [] statistics_;
+                            statistics_ = temp;
+                        }
+                        assert (!statistics_[numberNodes2_]);
+                        statistics_[numberNodes2_] = new CbcStatistics(newNode, this);
+                    }
+                    numberNodes2_++;
+#	    ifdef CHECK_NODE
+                    printf("Node %x pushed on tree c\n", newNode) ;
+#	    endif
+                } else {
+                    if (solverCharacteristics_ && //we may be in a non standard bab
+                            solverCharacteristics_->solutionAddsCuts()// we are in some kind of OA based bab.
+                       ) {
+
+                        std::cerr << "You should never get here" << std::endl;
+                        throw CoinError("Nodes should not be fathomed on integer infeasibility in this setting",
+                                        "branchAndBound", "CbcModel") ;
+                    }
+                    for (i = 0 ; i < currentNumberCuts_ ; i++) {
+                        if (addedCuts_[i]) {
+                            if (!addedCuts_[i]->decrement(1)) {
+                                delete addedCuts_[i] ;
+                                addedCuts_[i] = NULL;
+                            }
+                        }
+                    }
+                    double objectiveValue = newNode->objectiveValue();
+                    lastHeuristic_ = NULL;
+                    // Just possible solver did not know about a solution from another thread!
+                    if (objectiveValue < getCutoff()) {
+                        incrementUsed(solver_->getColSolution());
+                        setBestSolution(CBC_SOLUTION, objectiveValue,
+                                        solver_->getColSolution()) ;
+                        // Check if was found
+                        if (bestObjective_ < getCutoff())
+                            foundSolution = 1;
+                    }
+                    //assert(nodeInfo->numberPointingToThis() <= 2) ;
+                    if (parallelMode() >= 0) {
+                        // avoid accidental pruning, if newNode was final branch arm
+                        node->nodeInfo()->increment();
+                        delete newNode ;
+                        newNode = NULL;
+                        node->nodeInfo()->decrement() ;
+                    } else {
+                        newNode->setActive(false);
+                    }
+                }
+            }
+        if (branchesLeft) {
+            // set nodenumber correctly
+            if (node->nodeInfo())
+                node->nodeInfo()->setNodeNumber(numberNodes2_);
+            if (parallelMode() >= 0) {
+                if (!masterThread_) // only if serial
+                    tree_->push(node) ;
+            }
+            if (statistics_) {
+                if (numberNodes2_ == maximumStatistics_) {
+                    maximumStatistics_ = 2 * maximumStatistics_;
+                    CbcStatistics ** temp = new CbcStatistics * [maximumStatistics_];
+                    memset(temp, 0, maximumStatistics_*sizeof(CbcStatistics *));
+                    memcpy(temp, statistics_, numberNodes2_*sizeof(CbcStatistics *));
+                    delete [] statistics_;
+                    statistics_ = temp;
+                }
+                assert (!statistics_[numberNodes2_]);
+                statistics_[numberNodes2_] = new CbcStatistics(node, this);
+            }
+            numberNodes2_++;
+            //nodeOnTree=true; // back on tree
+            //deleteNode = false ;
+#	ifdef CHECK_NODE
+            printf("Node %x pushed back on tree - %d left, %d count\n", node,
+                   node->nodeInfo()->numberBranchesLeft(),
+                   node->nodeInfo()->numberPointingToThis()) ;
+#	endif
+            if (parallelMode() > 0) {
+                assert (node->nodeInfo());
+                node->nodeInfo()->decrement() ;
+            }
+        } else {
+            /*
+              This node has been completely expanded and can be removed from the live
+              set.
+            */
+            if (parallelMode() > 0) {
+                assert (masterThread_) ;
+                assert (node->nodeInfo());
+                node->nodeInfo()->decrement() ;
+            }
+            assert (node->nodeInfo());
+            if (parallelMode() >= 0) {
+                if (!node->nodeInfo()->numberBranchesLeft())
+                    node->nodeInfo()->allBranchesGone(); // can clean up
+                delete node ;
+                node = NULL;
+            } else {
+                node->setActive(false);
+            }
+        }
+        if (locked)
+            unlockThread();
+    } else {
+        // add cuts found to be infeasible (on bound)!
+        COIN_DETAIL_PRINT(printf("found to be infeas! - branches left %d - cutoff %g\n", node->nodeInfo()->numberBranchesLeft(),
+               getCutoff()));
+#ifdef COIN_DETAIL
+        node->print();
+#endif
+        //abort();
+        assert (node->nodeInfo());
+        if (parallelMode() >= 0) {
+            if (!node->nodeInfo()->numberBranchesLeft())
+                node->nodeInfo()->allBranchesGone(); // can clean up
+            delete node;
+            node = NULL;
+        } else {
+            node->setActive(false);
+        }
+    }
+    /*
+      Delete cuts to get back to the original system.
+
+      I'm thinking this is redundant --- the call to addCuts that conditions entry
+      to this code block also performs this action.
+    */
+#ifndef JJF_ONE
+    //if (numberThreads_)
+    {
+        int numberToDelete = getNumRows() - numberRowsAtContinuous_ ;
+        if (numberToDelete) {
+            int * delRows = new int[numberToDelete] ;
+            int i ;
+            for (i = 0 ; i < numberToDelete ; i++)
+                delRows[i] = i + numberRowsAtContinuous_ ;
+            solver_->deleteRows(numberToDelete, delRows) ;
+            delete [] delRows ;
+        }
+    }
+#endif
+    delete lastws ;
+    delete [] lowerBefore ;
+    delete [] upperBefore ;
+    if (bestObjective > bestObjective_)
+        foundSolution = 2;
+    if (parallelMode() > 0 && foundSolution) {
+        lockThread();
+        // might as well mark all including continuous
+        int numberColumns = solver_->getNumCols();
+        for (int i = 0; i < numberColumns; i++) {
+            baseModel->usedInSolution_[i] += usedInSolution_[i];
+            usedInSolution_[i] = 0;
+        }
+        baseModel->numberSolutions_++;
+        if (bestObjective_ < baseModel->bestObjective_ && bestObjective_ < baseModel->getCutoff()) {
+            baseModel->bestObjective_ = bestObjective_ ;
+            int numberColumns = solver_->getNumCols();
+            if (!baseModel->bestSolution_)
+                baseModel->bestSolution_ = new double[numberColumns];
+            CoinCopyN(bestSolution_, numberColumns, baseModel->bestSolution_);
+            baseModel->setCutoff(getCutoff());
+        }
+        unlockThread();
+    }
+    numberCutGenerators_=saveNumberCutGenerators;
+    return foundSolution;
+}
+// Adds an update information object
+void
+CbcModel::addUpdateInformation(const CbcObjectUpdateData & data)
+{
+    if (numberUpdateItems_ == maximumNumberUpdateItems_) {
+        maximumNumberUpdateItems_ += 10;
+        CbcObjectUpdateData * temp = new CbcObjectUpdateData [maximumNumberUpdateItems_];
+        for (int i = 0; i < maximumNumberUpdateItems_ - 10; i++)
+            temp[i] = updateItems_[i];
+        delete [] updateItems_;
+        updateItems_ = temp;
+    }
+    updateItems_[numberUpdateItems_++] = data;
+}
+// Returns bounds just before where - initially original bounds - also sets bounds
+void CbcModel::previousBounds (CbcNode * node, CbcNodeInfo * where, int iColumn,
+                               double & lower, double & upper, int force)
+{
+    int i;
+    int nNode = 0;
+    CbcNodeInfo * nodeInfo = node->nodeInfo();
+    int nWhere = -1;
+
+    /*
+      Accumulate the path from node to the root in walkback_
+    */
+    while (nodeInfo) {
+        //printf("nNode = %d, nodeInfo = %x\n",nNode,nodeInfo);
+        walkback_[nNode++] = nodeInfo;
+        nodeInfo = nodeInfo->parent() ;
+        if (nNode == maximumDepth_) {
+            redoWalkBack();
+        }
+        if (nodeInfo == where)
+            nWhere = nNode;
+    }
+    assert (nWhere >= 0);
+    nWhere = nNode - nWhere;
+    for (i = 0; i < nWhere; i++) {
+        --nNode;
+        walkback_[nNode]->applyBounds(iColumn, lower, upper, 0);
+    }
+    // correct bounds
+    walkback_[nNode]->applyBounds(iColumn, lower, upper, 3);
+    CbcNode * nodeLook = walkback_[nNode]->mutableOwner();
+    if (nodeLook) {
+        OsiBranchingObject * obj = nodeLook->modifiableBranchingObject();
+        CbcIntegerBranchingObject * objectI = dynamic_cast<CbcIntegerBranchingObject *> (obj);
+        //const OsiObject * object2 = obj->orig
+#ifndef NDEBUG
+        const CbcSimpleInteger * object2 = dynamic_cast<const CbcSimpleInteger *> (objectI->object());
+        assert (object2);
+        assert (iColumn == object2->columnNumber());
+#endif
+        double bounds[2];
+        bounds[0] = lower;
+        bounds[1] = upper;
+        objectI->setDownBounds(bounds);
+        objectI->setUpBounds(bounds);
+    }
+    while (nNode) {
+        --nNode;
+        walkback_[nNode]->applyBounds(iColumn, lower, upper, force);
+#ifdef JJF_ZERO
+        CbcNode * nodeLook = walkback_[nNode]->mutableOwner();
+        if (nodeLook) {
+            const OsiBranchingObject * obj = nodeLook->branchingObject();
+            const CbcIntegerBranchingObject * objectI = dynamic_cast<const CbcIntegerBranchingObject *> (obj);
+            //const OsiObject * object2 = obj->orig
+            const CbcSimpleInteger * object2 = dynamic_cast<const CbcSimpleInteger *> (objectI->object());
+            assert (object2);
+            int iColumn2 = object2->columnNumber();
+            assert (iColumn != iColumn2);
+        }
+#endif
+    }
+}
+/* Return pseudo costs
+   If not all integers or not pseudo costs - returns all zero
+   Length of arrays are numberIntegers() and entries
+      correspond to integerVariable()[i]
+      User must allocate arrays before call
+*/
+void
+CbcModel::fillPseudoCosts(double * downCosts, double * upCosts,
+                          int * priority,
+                          int * numberDown, int * numberUp,
+                          int * numberDownInfeasible,
+                          int * numberUpInfeasible) const
+{
+    CoinFillN(downCosts, numberIntegers_, 1.0);
+    CoinFillN(upCosts, numberIntegers_, 1.0);
+    if (priority) {
+        CoinFillN(priority, numberIntegers_, 1000000);
+    }
+    if (numberDown) {
+        CoinFillN(numberDown, numberIntegers_, 1);
+        CoinFillN(numberUp, numberIntegers_, 1);
+    }
+    if (numberDownInfeasible) {
+        CoinZeroN(numberDownInfeasible, numberIntegers_);
+        CoinZeroN(numberUpInfeasible, numberIntegers_);
+    }
+    int numberColumns = getNumCols();
+    int * back = new int[numberColumns];
+    int i;
+    for (i = 0; i < numberColumns; i++)
+        back[i] = -1;
+    for (i = 0; i < numberIntegers_; i++)
+        back[integerVariable_[i]] = i;
+#ifdef CLP_INVESTIGATE
+    int numberNot = 0;
+#endif
+    for ( i = 0; i < numberObjects_; i++) {
+        CbcSimpleIntegerDynamicPseudoCost * obj =
+            dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[i]) ;
+        if (!obj)
+            continue;
+#ifdef CLP_INVESTIGATE
+        if (obj->numberTimesDown() < numberBeforeTrust_ ||
+                obj->numberTimesUp() < numberBeforeTrust_)
+            numberNot++;
+#endif
+        int iColumn = obj->columnNumber();
+        iColumn = back[iColumn];
+        assert (iColumn >= 0);
+        if (priority)
+            priority[iColumn] = obj->priority();
+        downCosts[iColumn] = obj->downDynamicPseudoCost();
+        upCosts[iColumn] = obj->upDynamicPseudoCost();
+        if (numberDown) {
+            numberDown[iColumn] = obj->numberTimesDown();
+            numberUp[iColumn] = obj->numberTimesUp();
+        }
+        if (numberDownInfeasible) {
+            numberDownInfeasible[iColumn] = obj->numberTimesDownInfeasible();
+            numberUpInfeasible[iColumn] = obj->numberTimesUpInfeasible();
+        }
+    }
+#ifdef CLP_INVESTIGATE4
+    if (priority)
+        printf("Before fathom %d not trusted out of %d\n",
+               numberNot, numberIntegers_);
+#endif
+    delete [] back;
+}
+// Redo walkback arrays
+void
+CbcModel::redoWalkBack()
+{
+    int nNode = maximumDepth_;
+    maximumDepth_ *= 2;
+    CbcNodeInfo ** temp = new CbcNodeInfo * [maximumDepth_];
+    CbcNodeInfo ** temp2 = new CbcNodeInfo * [maximumDepth_];
+    int * temp3 = new int [maximumDepth_];
+    for (int i = 0; i < nNode; i++) {
+        temp[i] = walkback_[i];
+        temp2[i] = lastNodeInfo_[i];
+        temp3[i] = lastNumberCuts_[i];
+    }
+    delete [] walkback_;
+    walkback_ = temp;
+    delete [] lastNodeInfo_ ;
+    lastNodeInfo_ = temp2;
+    delete [] lastNumberCuts_ ;
+    lastNumberCuts_ = temp3;
+}
+/* Return true if we want to do cuts
+   If allowForTopOfTree zero then just does on multiples of depth
+   if 1 then allows for doing at top of tree
+   if 2 then says if cuts allowed anywhere apart from root
+   if 3 then gives smallest valid depth >shallow
+*/
+bool
+CbcModel::doCutsNow(int allowForTopOfTree) const
+{
+    int whenCutsUse = whenCuts_;
+    int alwaysReturnAt10 = whenCutsUse % 100000;
+    if (whenCutsUse > 0 && alwaysReturnAt10) {
+        whenCutsUse -= alwaysReturnAt10;
+        if (currentDepth_ > 10)
+            return false;
+    }
+    //if (currentDepth_>10)
+    //return false;
+#define TRY_IDEA1 2
+    int size = continuousSolver_->getNumRows() + continuousSolver_->getNumCols();
+
+    if (true && (whenCutsUse < 0 || (size <= 500 - 500*TRY_IDEA1 && allowForTopOfTree != 3))) {
+        int whenCuts = (size <= 500) ? -1 : 1;
+        //whenCuts = (size<=500) ? 1 :1;
+        if (parentModel_)
+            whenCuts = 1;
+        //int nodeDepth = currentDepth_-1;
+        bool doCuts2 =  !(currentDepth_ > 11 && (currentDepth_ & 1) == whenCuts);
+        if (fastNodeDepth_ > 0 && currentDepth_ > 10)
+            doCuts2 = false;
+        //printf("when %d node %d depth %d size %d doing cuts %s\n",whenCutsUse,
+        //   numberNodes_,currentDepth_,size,doCuts2 ? "yes" : "no");
+        return doCuts2;
+    }
+    //if (!parentModel_&&currentDepth_==7)
+    //printf("q\n");
+    int top = whenCutsUse / 1000000;
+    int shallow = top ? (top - 1) : 9;
+    int when = whenCutsUse - 1000000 * top;
+#if TRY_IDEA1
+    if (when<15 && when>1 && size <= 500)
+        when /= 2;
+#endif
+    if ((when > 15 || (top && top < 5)) && currentDepth_ > when)
+        when = 100000; // off
+    bool doCuts = when ? ((currentDepth_ % when) == 0) || (when == 1) : false;
+    if (allowForTopOfTree == 1 && currentDepth_ <= shallow) {
+        doCuts = true;
+    } else if (allowForTopOfTree == 2 && shallow >= 1) {
+        doCuts = true;
+#if TRY_IDEA1<2
+    } else if (allowForTopOfTree == 3 && doCuts) {
+        // only if first
+        if (currentDepth_ <= shallow || currentDepth_ - when > shallow)
+            doCuts = false;
+#else
+    } else if (allowForTopOfTree == 3) {
+        // only exactly at 10
+        doCuts = (currentDepth_ == 10);
+#endif
+    }
+    //if (!doCuts&&currentDepth_&&!parentModel_)
+    //printf("zzz\n");
+    return doCuts;
+}
+// See if can stop on gap
+bool 
+CbcModel::canStopOnGap() const
+{
+  bool returnCode=false;
+  if (bestObjective_<1.0e50) {
+    double testGap = CoinMax(dblParam_[CbcAllowableGap],
+			     CoinMax(fabs(bestObjective_), fabs(bestPossibleObjective_))
+			     * dblParam_[CbcAllowableFractionGap]);
+    returnCode = (bestObjective_ - bestPossibleObjective_ < testGap && getCutoffIncrement() >= 0.0);
+  } 
+  return returnCode;
+}
+// Adjust heuristics based on model
+void
+CbcModel::adjustHeuristics()
+{
+    int numberRows = solver_->getNumRows();
+    int numberColumns = solver_->getNumCols();
+    int nTree = CoinMax(10000, 2 * numberRows + numberColumns);
+    int nRoot = CoinMax(40000, 8 * numberRows + 4 * numberColumns);
+    for (int i = 0; i < numberHeuristics_; i++) {
+        CbcHeuristicDive * heuristic = dynamic_cast<CbcHeuristicDive *> (heuristic_[i]);
+        if (heuristic && heuristic->maxSimplexIterations()!=COIN_INT_MAX) {
+            heuristic->setMaxSimplexIterations(nTree);
+            heuristic->setMaxSimplexIterationsAtRoot(nRoot);
+        }
+    }
+}
+// Number of saved solutions (including best)
+int
+CbcModel::numberSavedSolutions() const
+{
+    if (!bestSolution_)
+        return 0;
+    else
+        return numberSavedSolutions_ + 1;
+}
+// Set maximum number of extra saved solutions
+void
+CbcModel::setMaximumSavedSolutions(int value)
+{
+    if (value < maximumSavedSolutions_) {
+        for (int i = value; i < maximumSavedSolutions_; i++)
+            delete [] savedSolutions_[i];
+        maximumSavedSolutions_ = value;
+        numberSavedSolutions_ = CoinMin(numberSavedSolutions_,
+                                        maximumSavedSolutions_);
+        if (!maximumSavedSolutions_)
+            delete [] savedSolutions_;
+    } else if (value > maximumSavedSolutions_) {
+        double ** temp = new double * [value];
+        int i;
+        for ( i = 0; i < maximumSavedSolutions_; i++)
+            temp[i] = savedSolutions_[i];
+        for ( ; i < value; i++)
+            temp[i] = NULL;
+        delete [] savedSolutions_;
+        maximumSavedSolutions_ = value;
+        savedSolutions_ = temp;
+    }
+}
+// Return a saved solution objective (0==best) - COIN_DBL_MAX if off end
+double
+CbcModel::savedSolutionObjective(int which) const
+{
+    if (which == 0) {
+        return bestObjective_;
+    } else if (which <= numberSavedSolutions_) {
+        double * sol = savedSolutions_[which-1];
+        assert (static_cast<int>(sol[0]) == solver_->getNumCols());
+        return sol[1];
+    } else {
+        return COIN_DBL_MAX;
+    }
+}
+// Return a saved solution (0==best) - NULL if off end
+const double *
+CbcModel::savedSolution(int which) const
+{
+    if (which == 0) {
+        return bestSolution_;
+    } else if (which <= numberSavedSolutions_) {
+        double * sol = savedSolutions_[which-1];
+        assert (static_cast<int>(sol[0]) == solver_->getNumCols());
+        return sol + 2;
+    } else {
+        return NULL;
+    }
+}
+// Save a solution
+void
+CbcModel::saveExtraSolution(const double * solution, double objectiveValue)
+{
+    double * save = NULL;
+    if (maximumSavedSolutions_) {
+        if (!savedSolutions_) {
+            savedSolutions_ = new double * [maximumSavedSolutions_];
+            for (int i = 0; i < maximumSavedSolutions_; i++)
+                savedSolutions_[i] = NULL;
+        }
+        int n = solver_->getNumCols();
+        int k;
+        for (k = numberSavedSolutions_ - 1; k >= 0; k--) {
+            double * sol = savedSolutions_[k];
+            assert (static_cast<int>(sol[0]) == n);
+            if (objectiveValue > sol[1])
+                break;
+        }
+        k++; // where to put
+        if (k < maximumSavedSolutions_) {
+            if (numberSavedSolutions_ == maximumSavedSolutions_) {
+                save = savedSolutions_[numberSavedSolutions_-1];
+            } else {
+                save = new double [n+2];
+                numberSavedSolutions_++;
+            }
+            // move up
+            for (int j = maximumSavedSolutions_ - 1; j > k; j--)
+                savedSolutions_[j] = savedSolutions_[j-1];
+            savedSolutions_[k] = save;
+            save[0] = n;
+            save[1] = objectiveValue;
+            memcpy(save + 2, solution, n*sizeof(double));
+        }
+    }
+}
+// Save a solution to best and move current to saved
+void
+CbcModel::saveBestSolution(const double * solution, double objectiveValue)
+{
+    int n = solver_->getNumCols();
+    if (bestSolution_)
+        saveExtraSolution(bestSolution_, bestObjective_);
+    else
+        bestSolution_ = new double [n];
+    bestObjective_ = objectiveValue;
+    memcpy(bestSolution_, solution, n*sizeof(double));
+}
+// Delete best and saved solutions
+void
+CbcModel::deleteSolutions()
+{
+    delete [] bestSolution_;
+    bestSolution_ = NULL;
+    for (int i = 0; i < maximumSavedSolutions_; i++) {
+        delete [] savedSolutions_[i];
+        savedSolutions_[i] = NULL;
+    }
+    numberSavedSolutions_ = 0;
+}
+// Delete a saved solution and move others up
+void 
+CbcModel::deleteSavedSolution(int which)
+{
+  if (which >0 && which <= numberSavedSolutions_) {
+    delete [] savedSolutions_[which-1];
+    // move up
+    numberSavedSolutions_--;
+    for (int j =  which-1; j <numberSavedSolutions_; j++) {
+      savedSolutions_[j] = savedSolutions_[j+1];
+    }
+    savedSolutions_[numberSavedSolutions_]=NULL;
+  }
+}
+#ifdef COIN_HAS_CLP
+void
+CbcModel::goToDantzig(int numberNodes, ClpDualRowPivot *& savePivotMethod)
+{
+    // Possible change of pivot method
+    if (!savePivotMethod && !parentModel_) {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        if (clpSolver && numberNodes_ >= numberNodes && numberNodes_ < 2*numberNodes) {
+            if (numberIterations_ < (numberSolves_ + numberNodes_)*10) {
+                //if (numberIterations_<numberNodes_*20) {
+                ClpSimplex * simplex = clpSolver->getModelPtr();
+                ClpDualRowPivot * pivotMethod = simplex->dualRowPivot();
+                ClpDualRowDantzig * pivot =
+                    dynamic_cast< ClpDualRowDantzig*>(pivotMethod);
+                if (!pivot) {
+                    savePivotMethod = pivotMethod->clone(true);
+                    ClpDualRowDantzig dantzig;
+                    simplex->setDualRowPivotAlgorithm(dantzig);
+#ifdef COIN_DEVELOP
+                    printf("%d node, %d iterations ->Dantzig\n", numberNodes_,
+                           numberIterations_);
+#endif
+#ifdef CBC_THREAD
+                    if (master_)
+                        master_->setDantzigState();
+#endif
+                }
+            }
+        }
+    }
+}
+#else
+CbcModel::goToDantzig(int numberNodes, ClpDualRowPivot *& savePivotMethod)
+{
+   printf("Need Clp to go to Dantzig\n");
+   abort();
+}
+#endif
+// Below this is deprecated or at least fairly deprecated
+/*
+   Do Integer Presolve. Returns new model.
+   I have to work out cleanest way of getting solution to
+   original problem at end.  So this is very preliminary.
+*/
+CbcModel *
+CbcModel::integerPresolve(bool weak)
+{
+    status_ = 0;
+    // solve LP
+    //solver_->writeMps("bad");
+    bool feasible = (resolve(NULL, 3) != 0);
+
+    CbcModel * newModel = NULL;
+    if (feasible) {
+
+        // get a new model
+        newModel = new CbcModel(*this);
+        newModel->messageHandler()->setLogLevel(messageHandler()->logLevel());
+
+        feasible = newModel->integerPresolveThisModel(solver_, weak);
+    }
+    if (!feasible) {
+        handler_->message(CBC_INFEAS, messages_)
+        << CoinMessageEol;
+        status_ = 0;
+        secondaryStatus_ = 1;
+        delete newModel;
+        return NULL;
+    } else {
+        newModel->synchronizeModel(); // make sure everything that needs solver has it
+        return newModel;
+    }
+}
+/*
+   Do Integer Presolve - destroying current model
+*/
+bool
+CbcModel::integerPresolveThisModel(OsiSolverInterface * originalSolver,
+                                   bool weak)
+{
+    printf("DEPRECATED\n");
+    status_ = 0;
+    // solve LP
+    bool feasible = (resolve(NULL, 3) != 0);
+
+    bestObjective_ = 1.0e50;
+    numberSolutions_ = 0;
+    numberHeuristicSolutions_ = 0;
+    double cutoff = getCutoff() ;
+    double direction = solver_->getObjSense();
+    if (cutoff < 1.0e20 && direction < 0.0)
+        messageHandler()->message(CBC_CUTOFF_WARNING1,
+                                  messages())
+        << cutoff << -cutoff << CoinMessageEol ;
+    if (cutoff > bestObjective_)
+        cutoff = bestObjective_ ;
+    setCutoff(cutoff) ;
+    int iColumn;
+    int numberColumns = getNumCols();
+    int originalNumberColumns = numberColumns;
+    currentPassNumber_ = 0;
+    synchronizeModel(); // make sure everything that needs solver has it
+    if (!solverCharacteristics_) {
+        OsiBabSolver * solverCharacteristics = dynamic_cast<OsiBabSolver *> (solver_->getAuxiliaryInfo());
+        if (solverCharacteristics) {
+            solverCharacteristics_ = solverCharacteristics;
+        } else {
+            // replace in solver
+            OsiBabSolver defaultC;
+            solver_->setAuxiliaryInfo(&defaultC);
+            solverCharacteristics_ = dynamic_cast<OsiBabSolver *> (solver_->getAuxiliaryInfo());
+        }
+    }
+    solverCharacteristics_->setSolver(solver_);
+    // just point to solver_
+    delete continuousSolver_;
+    continuousSolver_ = solver_;
+    // get a copy of original so we can fix bounds
+    OsiSolverInterface * cleanModel = originalSolver->clone();
+#ifdef CBC_DEBUG
+    std::string problemName;
+    cleanModel->getStrParam(OsiProbName, problemName);
+    printf("Problem name - %s\n", problemName.c_str());
+    cleanModel->activateRowCutDebugger(problemName.c_str());
+    const OsiRowCutDebugger * debugger = cleanModel->getRowCutDebugger();
+#endif
+
+    // array which points from original columns to presolved
+    int * original = new int[numberColumns];
+    // arrays giving bounds - only ones found by probing
+    // rest will be found by presolve
+    double * originalLower = new double[numberColumns];
+    double * originalUpper = new double[numberColumns];
+    {
+        const double * lower = getColLower();
+        const double * upper = getColUpper();
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            original[iColumn] = iColumn;
+            originalLower[iColumn] = lower[iColumn];
+            originalUpper[iColumn] = upper[iColumn];
+        }
+    }
+    findIntegers(true);
+    // save original integers
+    int * originalIntegers = new int[numberIntegers_];
+    int originalNumberIntegers = numberIntegers_;
+    memcpy(originalIntegers, integerVariable_, numberIntegers_*sizeof(int));
+
+    int todo = 20;
+    if (weak)
+        todo = 1;
+    while (currentPassNumber_ < todo) {
+
+        currentPassNumber_++;
+        numberSolutions_ = 0;
+        // this will be set false to break out of loop with presolved problem
+        bool doIntegerPresolve = (currentPassNumber_ != 20);
+
+        // Current number of free integer variables
+        // Get increment in solutions
+        {
+            const double * objective = cleanModel->getObjCoefficients();
+            const double * lower = cleanModel->getColLower();
+            const double * upper = cleanModel->getColUpper();
+            double maximumCost = 0.0;
+            bool possibleMultiple = true;
+            int numberChanged = 0;
+            for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) {
+                if (originalUpper[iColumn] > originalLower[iColumn]) {
+                    if ( cleanModel->isInteger(iColumn)) {
+                        maximumCost = CoinMax(maximumCost, fabs(objective[iColumn]));
+                    } else if (objective[iColumn]) {
+                        possibleMultiple = false;
+                    }
+                }
+                if (originalUpper[iColumn] < upper[iColumn]) {
+#ifdef CBC_DEBUG
+                    printf("Changing upper bound on %d from %g to %g\n",
+                           iColumn, upper[iColumn], originalUpper[iColumn]);
+#endif
+                    cleanModel->setColUpper(iColumn, originalUpper[iColumn]);
+                    numberChanged++;
+                }
+                if (originalLower[iColumn] > lower[iColumn]) {
+#ifdef CBC_DEBUG
+                    printf("Changing lower bound on %d from %g to %g\n",
+                           iColumn, lower[iColumn], originalLower[iColumn]);
+#endif
+                    cleanModel->setColLower(iColumn, originalLower[iColumn]);
+                    numberChanged++;
+                }
+            }
+            // if first pass - always try
+            if (currentPassNumber_ == 1)
+                numberChanged += 1;
+            if (possibleMultiple && maximumCost) {
+                int increment = 0;
+                double multiplier = 2520.0;
+                while (10.0*multiplier*maximumCost < 1.0e8)
+                    multiplier *= 10.0;
+                for (int j = 0; j < originalNumberIntegers; j++) {
+                    iColumn = originalIntegers[j];
+                    if (originalUpper[iColumn] > originalLower[iColumn]) {
+                        if (objective[iColumn]) {
+                            double value = fabs(objective[iColumn]) * multiplier;
+                            int nearest = static_cast<int> (floor(value + 0.5));
+                            if (fabs(value - floor(value + 0.5)) > 1.0e-8 || value > 2.1e9) {
+                                increment = 0;
+                                break; // no good
+                            } else if (!increment) {
+                                // first
+                                increment = nearest;
+                            } else {
+                                increment = gcd(increment, nearest);
+                            }
+                        }
+                    }
+                }
+                if (increment) {
+                    double value = increment;
+                    value /= multiplier;
+                    if (value*0.999 > dblParam_[CbcCutoffIncrement]) {
+                        messageHandler()->message(CBC_INTEGERINCREMENT, messages())
+                        << value
+                        << CoinMessageEol;
+                        dblParam_[CbcCutoffIncrement] = value * 0.999;
+                    }
+                }
+            }
+            if (!numberChanged) {
+                doIntegerPresolve = false; // not doing any better
+            }
+        }
+#ifdef CBC_DEBUG
+        if (debugger)
+            assert(debugger->onOptimalPath(*cleanModel));
+#endif
+#ifdef COIN_HAS_CLP
+        // do presolve - for now just clp but easy to get osi interface
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (cleanModel);
+        if (clpSolver) {
+            ClpSimplex * clp = clpSolver->getModelPtr();
+            clp->messageHandler()->setLogLevel(cleanModel->messageHandler()->logLevel());
+            ClpPresolve pinfo;
+            //printf("integerPresolve - temp switch off doubletons\n");
+            //pinfo.setPresolveActions(4);
+            ClpSimplex * model2 = pinfo.presolvedModel(*clp, 1.0e-8);
+            if (!model2) {
+                // presolve found to be infeasible
+                feasible = false;
+            } else {
+                // update original array
+                const int * originalColumns = pinfo.originalColumns();
+                // just slot in new solver
+                OsiClpSolverInterface * temp = new OsiClpSolverInterface(model2, true);
+                numberColumns = temp->getNumCols();
+                for (iColumn = 0; iColumn < originalNumberColumns; iColumn++)
+                    original[iColumn] = -1;
+                for (iColumn = 0; iColumn < numberColumns; iColumn++)
+                    original[originalColumns[iColumn]] = iColumn;
+                // copy parameters
+                temp->copyParameters(*solver_);
+                // and specialized ones
+                temp->setSpecialOptions(clpSolver->specialOptions());
+                delete solver_;
+                solver_ = temp;
+                setCutoff(cutoff);
+                deleteObjects();
+                if (!numberObjects_) {
+                    // Nothing left
+                    doIntegerPresolve = false;
+                    weak = true;
+                    break;
+                }
+                synchronizeModel(); // make sure everything that needs solver has it
+                // just point to solver_
+                continuousSolver_ = solver_;
+                feasible = (resolve(NULL, 3) != 0);
+                if (!feasible || !doIntegerPresolve || weak) break;
+                // see if we can get solution by heuristics
+                int found = -1;
+                int iHeuristic;
+                double * newSolution = new double [numberColumns];
+                double heuristicValue = getCutoff();
+                int whereFrom = 0;
+                for (iHeuristic = 0; iHeuristic < numberHeuristics_; iHeuristic++) {
+                    // skip if can't run here
+                    if (!heuristic_[iHeuristic]->shouldHeurRun(whereFrom))
+                        continue;
+                    double saveValue = heuristicValue;
+                    int ifSol = heuristic_[iHeuristic]->solution(heuristicValue,
+                                newSolution);
+                    if (ifSol > 0) {
+                        // better solution found
+                        heuristic_[iHeuristic]->incrementNumberSolutionsFound();
+                        found = iHeuristic;
+                        incrementUsed(newSolution);
+                        whereFrom |= 8; // say solution found
+                    } else if (ifSol < 0) {
+                        heuristicValue = saveValue;
+                    }
+                }
+                if (found >= 0) {
+                    // We probably already have a current solution, but just in case ...
+                    int numberColumns = getNumCols() ;
+                    if (!currentSolution_)
+                        currentSolution_ = new double[numberColumns] ;
+                    testSolution_ = currentSolution_;
+                    // better solution save
+                    lastHeuristic_ = heuristic_[found];
+#ifdef CLP_INVESTIGATE
+                    printf("HEUR %s where %d oddE\n",
+                           lastHeuristic_->heuristicName(), whereFrom);
+#endif
+                    setBestSolution(CBC_ROUNDING, heuristicValue,
+                                    newSolution);
+                    // update cutoff
+                    cutoff = getCutoff();
+                }
+                delete [] newSolution;
+                // Space for type of cuts
+                maximumWhich_ = 1000;
+                delete [] whichGenerator_ ;
+                whichGenerator_ = new int[maximumWhich_];
+                // save number of rows
+                numberRowsAtContinuous_ = getNumRows();
+                maximumNumberCuts_ = 0;
+                currentNumberCuts_ = 0;
+                delete [] addedCuts_;
+                addedCuts_ = NULL;
+
+                // maximum depth for tree walkback
+                maximumDepth_ = 10;
+                delete [] walkback_;
+                walkback_ = new CbcNodeInfo * [maximumDepth_];
+                lastDepth_ = 0;
+                delete [] lastNodeInfo_ ;
+                lastNodeInfo_ = new CbcNodeInfo * [maximumDepth_] ;
+                delete [] lastNumberCuts_ ;
+                lastNumberCuts_ = new int [maximumDepth_] ;
+                maximumCuts_ = 100;
+                delete [] lastCut_;
+                lastCut_ = new const OsiRowCut * [maximumCuts_];
+
+                OsiCuts cuts;
+                numberOldActiveCuts_ = 0;
+                numberNewCuts_ = 0;
+                feasible = solveWithCuts(cuts, maximumCutPassesAtRoot_, NULL);
+                currentNumberCuts_ = numberNewCuts_;
+                delete [] whichGenerator_;
+                whichGenerator_ = NULL;
+                delete [] walkback_;
+                walkback_ = NULL;
+                delete [] addedCuts_;
+                addedCuts_ = NULL;
+                if (feasible) {
+                    // fix anything in original which integer presolve fixed
+                    // for now just integers
+                    const double * lower = solver_->getColLower();
+                    const double * upper = solver_->getColUpper();
+                    int i;
+                    for (i = 0; i < originalNumberIntegers; i++) {
+                        iColumn = originalIntegers[i];
+                        int jColumn = original[iColumn];
+                        if (jColumn >= 0) {
+                            if (upper[jColumn] < originalUpper[iColumn])
+                                originalUpper[iColumn]	= upper[jColumn];
+                            if (lower[jColumn] > originalLower[iColumn])
+                                originalLower[iColumn]	= lower[jColumn];
+                        }
+                    }
+                }
+            }
+        }
+#endif
+        if (!feasible || !doIntegerPresolve) {
+            break;
+        }
+    }
+    //solver_->writeMps("xx");
+    delete cleanModel;
+    delete [] originalIntegers;
+    numberColumns = getNumCols();
+    delete [] originalColumns_;
+    originalColumns_ = new int[numberColumns];
+    numberColumns = 0;
+    for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) {
+        int jColumn = original[iColumn];
+        if (jColumn >= 0)
+            originalColumns_[numberColumns++] = iColumn;
+    }
+    delete [] original;
+    delete [] originalLower;
+    delete [] originalUpper;
+
+    deleteObjects();
+    synchronizeModel(); // make sure everything that needs solver has it
+    continuousSolver_ = NULL;
+    currentNumberCuts_ = 0;
+    return feasible;
+}
+// Put back information into original model - after integerpresolve
+void
+CbcModel::originalModel(CbcModel * presolvedModel, bool weak)
+{
+    solver_->copyParameters(*(presolvedModel->solver_));
+    bestObjective_ = presolvedModel->bestObjective_;
+    delete [] bestSolution_;
+    findIntegers(true);
+    if (presolvedModel->bestSolution_) {
+        int numberColumns = getNumCols();
+        int numberOtherColumns = presolvedModel->getNumCols();
+        //bestSolution_ = new double[numberColumns];
+        // set up map
+        int * back = new int[numberColumns];
+        int i;
+        for (i = 0; i < numberColumns; i++)
+            back[i] = -1;
+        for (i = 0; i < numberOtherColumns; i++)
+            back[presolvedModel->originalColumns_[i]] = i;
+        int iColumn;
+        // set ones in presolved model to values
+        double * otherSolution = presolvedModel->bestSolution_;
+        //const double * lower = getColLower();
+        for (i = 0; i < numberIntegers_; i++) {
+            iColumn = integerVariable_[i];
+            int jColumn = back[iColumn];
+            //bestSolution_[iColumn]=lower[iColumn];
+            if (jColumn >= 0) {
+                double value = floor(otherSolution[jColumn] + 0.5);
+                solver_->setColLower(iColumn, value);
+                solver_->setColUpper(iColumn, value);
+                //bestSolution_[iColumn]=value;
+            }
+        }
+        delete [] back;
+#ifdef JJF_ZERO
+        // ** looks as if presolve needs more intelligence
+        // do presolve - for now just clp but easy to get osi interface
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver_);
+        assert (clpSolver);
+        ClpSimplex * clp = clpSolver->getModelPtr();
+        Presolve pinfo;
+        ClpSimplex * model2 = pinfo.presolvedModel(*clp, 1.0e-8);
+        model2->primal(1);
+        pinfo.postsolve(true);
+        const double * solution = solver_->getColSolution();
+        for (i = 0; i < numberIntegers_; i++) {
+            iColumn = integerVariable_[i];
+            double value = floor(solution[iColumn] + 0.5);
+            solver_->setColLower(iColumn, value);
+            solver_->setColUpper(iColumn, value);
+        }
+#else
+        if (!weak) {
+            // for now give up
+            int save = numberCutGenerators_;
+            numberCutGenerators_ = 0;
+            bestObjective_ = 1.0e100;
+            branchAndBound();
+            numberCutGenerators_ = save;
+        }
+#endif
+        if (bestSolution_) {
+            // solve problem
+            resolve(NULL, 3);
+            // should be feasible
+            if (!currentSolution_)
+                currentSolution_ = new double[numberColumns] ;
+            testSolution_ = currentSolution_;
+#ifndef NDEBUG
+            int numberIntegerInfeasibilities;
+            int numberObjectInfeasibilities;
+            assert(feasibleSolution(numberIntegerInfeasibilities,
+                                    numberObjectInfeasibilities));
+#endif
+        }
+    } else {
+        bestSolution_ = NULL;
+    }
+    numberSolutions_ = presolvedModel->numberSolutions_;
+    numberHeuristicSolutions_ = presolvedModel->numberHeuristicSolutions_;
+    numberNodes_ = presolvedModel->numberNodes_;
+    numberIterations_ = presolvedModel->numberIterations_;
+    status_ = presolvedModel->status_;
+    secondaryStatus_ = presolvedModel->secondaryStatus_;
+    synchronizeModel();
+}
+void
+CbcModel::setOptionalInteger(int index)
+{
+#ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver_);
+    if (clpSolver)
+        clpSolver->setOptionalInteger(index);
+    else
+#endif
+        solver_->setInteger(index);
+}
+// Return true if maximum time reached
+bool
+CbcModel::maximumSecondsReached() const
+{
+    double totalTime = getCurrentSeconds() ;
+    double maxSeconds = getMaximumSeconds();
+    bool hitMaxTime = (totalTime >= maxSeconds);
+    if (parentModel_ && !hitMaxTime) {
+        // In a sub tree so need to add both times
+        totalTime += parentModel_->getCurrentSeconds();
+        maxSeconds = parentModel_->getMaximumSeconds();
+        hitMaxTime = (totalTime >= maxSeconds);
+    }
+    if (hitMaxTime) {
+        // Set eventHappened_ so will by-pass as much stuff as possible
+        eventHappened_ = true;
+    }
+    return hitMaxTime;
+}
+// Check original model before it gets messed up
+void
+CbcModel::checkModel()
+{
+    int iColumn ;
+    int numberColumns = getNumCols() ;
+    const double *lower = getColLower() ;
+    const double *upper = getColUpper() ;
+    int setFlag = 65536;
+    for (iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+        if (upper[iColumn] > lower[iColumn] + 1.0e-8) {
+            double value;
+            value = fabs(lower[iColumn]);
+            if (floor(value + 0.5) != value) {
+                setFlag = 0;
+                break;
+            }
+            value = fabs(upper[iColumn]);
+            if (floor(value + 0.5) != value) {
+                setFlag = 0;
+                break;
+            }
+        }
+    }
+    specialOptions_ |= setFlag;
+}
+static void flipSolver(OsiSolverInterface * solver, double newCutoff)
+{
+  if (solver) {
+    double objValue = solver->getObjValue();
+    double objectiveOffset;
+    solver->setObjSense(-solver->getObjSense());
+    solver->getDblParam(OsiObjOffset,objectiveOffset);
+    solver->setDblParam(OsiObjOffset,-objectiveOffset);
+    int numberColumns = solver->getNumCols();
+    double * array = CoinCopyOfArray(solver->getObjCoefficients(),numberColumns);
+    for (int i=0;i<numberColumns;i++)
+      array[i] = - array[i];
+    solver->setObjective(array);
+    delete [] array;
+    solver->setDblParam(OsiDualObjectiveLimit,newCutoff);
+#ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+      = dynamic_cast<OsiClpSolverInterface *> (solver);
+    if (clpSolver) {
+      double * dj = clpSolver->getModelPtr()->dualColumnSolution();
+      for (int i=0;i<numberColumns;i++)
+	dj[i] = - dj[i];
+      int numberRows=clpSolver->getNumRows();
+      double * pi = clpSolver->getModelPtr()->dualRowSolution();
+      for (int i=0;i<numberRows;i++)
+	pi[i] = - pi[i];
+      clpSolver->getModelPtr()->setObjectiveValue(-objValue);
+    } else {
+#endif
+      // update values
+      solver->resolve();
+#ifdef COIN_HAS_CLP
+    }
+#endif
+  }
+}
+/*
+  Flip direction of optimization on all models
+*/
+void 
+CbcModel::flipModel()
+{
+  if (parentModel_)
+    return;
+  // I think cutoff is always minimization
+  double cutoff=getCutoff();
+  flipSolver(referenceSolver_,cutoff);
+  flipSolver(continuousSolver_,cutoff);
+  flipSolver(solver_,cutoff);
+}
+#ifdef CBC_KEEP_DEPRECATED
+/* preProcess problem - replacing solver
+   If makeEquality true then <= cliques converted to ==.
+   Presolve will be done numberPasses times.
+
+   Returns NULL if infeasible
+
+   If makeEquality is 1 add slacks to get cliques,
+   if 2 add slacks to get sos (but only if looks plausible) and keep sos info
+*/
+CglPreProcess *
+CbcModel::preProcess( int makeEquality, int numberPasses, int tuning)
+{
+    CglPreProcess * process = new CglPreProcess();
+    // Default set of cut generators
+    CglProbing generator1;
+    generator1.setUsingObjective(true);
+    generator1.setMaxPass(3);
+    generator1.setMaxProbeRoot(solver_->getNumCols());
+    generator1.setMaxElements(100);
+    generator1.setMaxLookRoot(50);
+    generator1.setRowCuts(3);
+    // Add in generators
+    process->addCutGenerator(&generator1);
+    process->messageHandler()->setLogLevel(this->logLevel());
+    /* model may not have created objects
+       If none then create
+    */
+    if (!numberIntegers_ || !numberObjects_) {
+        this->findIntegers(true, 1);
+    }
+    // Do SOS
+    int i;
+    int numberSOS2 = 0;
+    for (i = 0; i < numberObjects_; i++) {
+        CbcSOS * objSOS =
+            dynamic_cast <CbcSOS *>(object_[i]) ;
+        if (objSOS) {
+            int type = objSOS->sosType();
+            if (type == 2)
+                numberSOS2++;
+        }
+    }
+    if (numberSOS2) {
+        // SOS
+        int numberColumns = solver_->getNumCols();
+        char * prohibited = new char[numberColumns];
+        memset(prohibited, 0, numberColumns);
+        for (i = 0; i < numberObjects_; i++) {
+            CbcSOS * objSOS =
+                dynamic_cast <CbcSOS *>(object_[i]) ;
+            if (objSOS) {
+                int type = objSOS->sosType();
+                if (type == 2) {
+                    int n = objSOS->numberMembers();
+                    const int * which = objSOS->members();
+                    for (int j = 0; j < n; j++) {
+                        int iColumn = which[j];
+                        prohibited[iColumn] = 1;
+                    }
+                }
+            }
+        }
+        process->passInProhibited(prohibited, numberColumns);
+        delete [] prohibited;
+    }
+    // Tell solver we are not in Branch and Cut
+    solver_->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ;
+    OsiSolverInterface * newSolver = process->preProcessNonDefault(*solver_, makeEquality,
+                                     numberPasses, tuning);
+    // Tell solver we are not in Branch and Cut
+    solver_->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+    if (newSolver) {
+        int numberOriginalObjects = numberObjects_;
+        OsiSolverInterface * originalSolver = solver_;
+        solver_ = newSolver->clone(); // clone as process owns solver
+        // redo sequence
+        numberIntegers_ = 0;
+        int numberColumns = solver_->getNumCols();
+        int nOrig = originalSolver->getNumCols();
+        const int * originalColumns = process->originalColumns();
+        // allow for cliques etc
+        nOrig = CoinMax(nOrig, originalColumns[numberColumns-1] + 1);
+        OsiObject ** originalObject = object_;
+        // object number or -1
+        int * temp = new int[nOrig];
+        int iColumn;
+        for (iColumn = 0; iColumn < nOrig; iColumn++)
+            temp[iColumn] = -1;
+        int iObject;
+        numberObjects_ = 0;
+        int nNonInt = 0;
+        for (iObject = 0; iObject < numberOriginalObjects; iObject++) {
+            iColumn = originalObject[iObject]->columnNumber();
+            if (iColumn < 0) {
+                nNonInt++;
+            } else {
+                temp[iColumn] = iObject;
+            }
+        }
+        int numberNewIntegers = 0;
+        int numberOldIntegers = 0;
+        int numberOldOther = 0;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            int jColumn = originalColumns[iColumn];
+            if (temp[jColumn] >= 0) {
+                int iObject = temp[jColumn];
+                CbcSimpleInteger * obj =
+                    dynamic_cast <CbcSimpleInteger *>(originalObject[iObject]) ;
+                if (obj)
+                    numberOldIntegers++;
+                else
+                    numberOldOther++;
+            } else if (isInteger(iColumn)) {
+                numberNewIntegers++;
+            }
+        }
+        /*
+          Allocate an array to hold the indices of the integer variables.
+          Make a large enough array for all objects
+        */
+        numberObjects_ = numberNewIntegers + numberOldIntegers + numberOldOther + nNonInt;
+        object_ = new OsiObject * [numberObjects_];
+        delete [] integerVariable_;
+        integerVariable_ = new int [numberNewIntegers+numberOldIntegers];
+        /*
+          Walk the variables again, filling in the indices and creating objects for
+          the integer variables. Initially, the objects hold the index and upper &
+          lower bounds.
+        */
+        numberIntegers_ = 0;
+        int n = originalColumns[numberColumns-1] + 1;
+        int * backward = new int[n];
+        int i;
+        for ( i = 0; i < n; i++)
+            backward[i] = -1;
+        for (i = 0; i < numberColumns; i++)
+            backward[originalColumns[i]] = i;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            int jColumn = originalColumns[iColumn];
+            if (temp[jColumn] >= 0) {
+                int iObject = temp[jColumn];
+                CbcSimpleInteger * obj =
+                    dynamic_cast <CbcSimpleInteger *>(originalObject[iObject]) ;
+                if (obj) {
+                    object_[numberIntegers_] = originalObject[iObject]->clone();
+                    // redo ids etc
+                    //object_[numberIntegers_]->resetSequenceEtc(numberColumns,originalColumns);
+                    object_[numberIntegers_]->resetSequenceEtc(numberColumns, backward);
+                    integerVariable_[numberIntegers_++] = iColumn;
+                }
+            } else if (isInteger(iColumn)) {
+                object_[numberIntegers_] =
+                    new CbcSimpleInteger(this, iColumn);
+                integerVariable_[numberIntegers_++] = iColumn;
+            }
+        }
+        delete [] backward;
+        numberObjects_ = numberIntegers_;
+        // Now append other column stuff
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            int jColumn = originalColumns[iColumn];
+            if (temp[jColumn] >= 0) {
+                int iObject = temp[jColumn];
+                CbcSimpleInteger * obj =
+                    dynamic_cast <CbcSimpleInteger *>(originalObject[iObject]) ;
+                if (!obj) {
+                    object_[numberObjects_] = originalObject[iObject]->clone();
+                    // redo ids etc
+                    CbcObject * obj =
+                        dynamic_cast <CbcObject *>(object_[numberObjects_]) ;
+                    assert (obj);
+                    obj->redoSequenceEtc(this, numberColumns, originalColumns);
+                    numberObjects_++;
+                }
+            }
+        }
+        // now append non column stuff
+        for (iObject = 0; iObject < numberOriginalObjects; iObject++) {
+            iColumn = originalObject[iObject]->columnNumber();
+            if (iColumn < 0) {
+                object_[numberObjects_] = originalObject[iObject]->clone();
+                // redo ids etc
+                CbcObject * obj =
+                    static_cast <CbcObject *>(object_[numberObjects_]) ;
+                assert (obj);
+                obj->redoSequenceEtc(this, numberColumns, originalColumns);
+                numberObjects_++;
+            }
+            delete originalObject[iObject];
+        }
+        delete [] originalObject;
+        delete [] temp;
+        if (!numberObjects_)
+            handler_->message(CBC_NOINT, messages_) << CoinMessageEol ;
+        return process;
+    } else {
+        // infeasible
+        delete process;
+        return NULL;
+    }
+
+}
+/* Does postprocessing - original solver back.
+   User has to delete process */
+void
+CbcModel::postProcess(CglPreProcess * process)
+{
+    process->postProcess(*solver_);
+    delete solver_;
+    solver_ = process->originalModel();
+}
+/* Process root node and return a strengthened model
+
+The method assumes that initialSolve() has been called to solve the
+LP relaxation. It processes the root node and then returns a pointer
+to the strengthened model (or NULL if infeasible)
+*/
+OsiSolverInterface *
+CbcModel::strengthenedModel()
+{
+    /*
+      Switch off heuristics
+    */
+    int saveNumberHeuristics = numberHeuristics_;
+    numberHeuristics_ = 0;
+    /*
+      Scan the variables, noting the integer variables. Create an
+      CbcSimpleInteger object for each integer variable.
+    */
+    findIntegers(false) ;
+    /*
+      Ensure that objects on the lists of OsiObjects, heuristics, and cut
+      generators attached to this model all refer to this model.
+    */
+    synchronizeModel() ;
+
+    // Set so we can tell we are in initial phase in resolve
+    continuousObjective_ = -COIN_DBL_MAX ;
+    /*
+      Solve the relaxation.
+
+      Apparently there are circumstances where this will be non-trivial --- i.e.,
+      we've done something since initialSolve that's trashed the solution to the
+      continuous relaxation.
+    */
+    bool feasible = resolve(NULL, 0) != 0 ;
+    /*
+      If the linear relaxation of the root is infeasible, bail out now. Otherwise,
+      continue with processing the root node.
+    */
+    if (!feasible) {
+        handler_->message(CBC_INFEAS, messages_) << CoinMessageEol ;
+        return NULL;
+    }
+    // Save objective (just so user can access it)
+    originalContinuousObjective_ = solver_->getObjValue();
+
+    /*
+      Begin setup to process a feasible root node.
+    */
+    bestObjective_ = CoinMin(bestObjective_, 1.0e50) ;
+    numberSolutions_ = 0 ;
+    numberHeuristicSolutions_ = 0 ;
+    // Everything is minimization
+    double cutoff = getCutoff() ;
+    double direction = solver_->getObjSense() ;
+    if (cutoff < 1.0e20 && direction < 0.0)
+        messageHandler()->message(CBC_CUTOFF_WARNING1,
+                                  messages())
+        << cutoff << -cutoff << CoinMessageEol ;
+    if (cutoff > bestObjective_)
+        cutoff = bestObjective_ ;
+    setCutoff(cutoff) ;
+    /*
+      We probably already have a current solution, but just in case ...
+    */
+    int numberColumns = getNumCols() ;
+    if (!currentSolution_)
+        currentSolution_ = new double[numberColumns] ;
+    testSolution_ = currentSolution_;
+    /*
+      Create a copy of the solver, thus capturing the original (root node)
+      constraint system (aka the continuous system).
+    */
+    continuousSolver_ = solver_->clone() ;
+    numberRowsAtContinuous_ = getNumRows() ;
+    /*
+      Check the objective to see if we can deduce a nontrivial increment. If
+      it's better than the current value for CbcCutoffIncrement, it'll be
+      installed.
+    */
+    analyzeObjective() ;
+    /*
+      Set up for cut generation. addedCuts_ holds the cuts which are relevant for
+      the active subproblem. whichGenerator will be used to record the generator
+      that produced a given cut.
+    */
+    maximumWhich_ = 1000 ;
+    delete [] whichGenerator_ ;
+    whichGenerator_ = new int[maximumWhich_] ;
+    maximumNumberCuts_ = 0 ;
+    currentNumberCuts_ = 0 ;
+    delete [] addedCuts_ ;
+    addedCuts_ = NULL ;
+    /*
+    Generate cuts at the root node and reoptimise. solveWithCuts does the heavy
+    lifting. It will iterate a generate/reoptimise loop (including reduced cost
+    fixing) until no cuts are generated, the change in objective falls off,  or
+    the limit on the number of rounds of cut generation is exceeded.
+
+    At the end of all this, any cuts will be recorded in cuts and also
+    installed in the solver's constraint system. We'll have reoptimised, and
+    removed any slack cuts (numberOldActiveCuts_ and numberNewCuts_ have been
+    adjusted accordingly).
+
+    Tell cut generators they can be a bit more aggressive at root node
+
+    */
+    int iCutGenerator;
+    for (iCutGenerator = 0; iCutGenerator < numberCutGenerators_; iCutGenerator++) {
+        CglCutGenerator * generator = generator_[iCutGenerator]->generator();
+        generator->setAggressiveness(generator->getAggressiveness() + 100);
+    }
+    OsiCuts cuts ;
+    numberOldActiveCuts_ = 0 ;
+    numberNewCuts_ = 0 ;
+    {
+        int iObject ;
+        int preferredWay ;
+        int numberUnsatisfied = 0 ;
+        memcpy(currentSolution_, solver_->getColSolution(),
+               numberColumns*sizeof(double)) ;
+
+        // point to useful information
+        OsiBranchingInformation usefulInfo = usefulInformation();
+        for (iObject = 0 ; iObject < numberObjects_ ; iObject++) {
+            double infeasibility =
+                object_[iObject]->infeasibility(&usefulInfo, preferredWay) ;
+            if (infeasibility) numberUnsatisfied++ ;
+        }
+        if (numberUnsatisfied) {
+            feasible = solveWithCuts(cuts, maximumCutPassesAtRoot_,
+                                     NULL) ;
+        }
+    }
+    /*
+      We've taken the continuous relaxation as far as we can.
+    */
+
+    OsiSolverInterface * newSolver = NULL;
+    if (feasible) {
+        // make copy of current solver
+        newSolver = solver_->clone();
+    }
+    /*
+      Clean up dangling objects. continuousSolver_ may already be toast.
+    */
+    delete [] whichGenerator_ ;
+    whichGenerator_ = NULL;
+    delete [] walkback_ ;
+    walkback_ = NULL ;
+    delete [] lastNodeInfo_ ;
+    lastNodeInfo_ = NULL;
+    delete [] lastNumberCuts_ ;
+    lastNumberCuts_ = NULL;
+    delete [] lastCut_;
+    lastCut_ = NULL;
+    delete [] addedCuts_ ;
+    addedCuts_ = NULL ;
+    if (continuousSolver_) {
+        delete continuousSolver_ ;
+        continuousSolver_ = NULL ;
+    }
+    /*
+      Destroy global cuts by replacing with an empty OsiCuts object.
+    */
+    globalCuts_ = OsiCuts() ;
+    delete globalConflictCuts_;
+    globalConflictCuts_=NULL;
+    numberHeuristics_ = saveNumberHeuristics;
+
+    return newSolver;
+}
+/*  create a submodel from partially fixed problem
+
+The method creates a new clean model with given bounds.
+*/
+CbcModel *
+CbcModel::cleanModel(const double * lower, const double * upper)
+{
+    OsiSolverInterface * solver = continuousSolver_->clone();
+
+    int numberIntegers = numberIntegers_;
+    const int * integerVariable = integerVariable_;
+
+    int i;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        const OsiObject * object = object_[i];
+#ifndef NDEBUG
+        const CbcSimpleInteger * integerObject =
+            dynamic_cast<const  CbcSimpleInteger *> (object);
+        assert(integerObject);
+#else
+        const CbcSimpleInteger * integerObject =
+            static_cast<const  CbcSimpleInteger *> (object);
+#endif
+        // get original bounds
+        double originalLower = integerObject->originalLowerBound();
+        double originalUpper = integerObject->originalUpperBound();
+        solver->setColLower(iColumn, CoinMax(lower[iColumn], originalLower));
+        solver->setColUpper(iColumn, CoinMin(upper[iColumn], originalUpper));
+    }
+    CbcModel * model = new CbcModel(*solver);
+    // off some messages
+    if (handler_->logLevel() <= 1) {
+        model->messagesPointer()->setDetailMessage(3, 9);
+        model->messagesPointer()->setDetailMessage(3, 6);
+        model->messagesPointer()->setDetailMessage(3, 4);
+        model->messagesPointer()->setDetailMessage(3, 1);
+        model->messagesPointer()->setDetailMessage(3, 13);
+        model->messagesPointer()->setDetailMessage(3, 14);
+        model->messagesPointer()->setDetailMessage(3, 3007);
+    }
+    // Cuts
+    for ( i = 0; i < numberCutGenerators_; i++) {
+        int howOften = generator_[i]->howOftenInSub();
+        if (howOften > -100) {
+            CbcCutGenerator * generator = virginGenerator_[i];
+            CglCutGenerator * cglGenerator = generator->generator();
+            model->addCutGenerator(cglGenerator, howOften,
+                                   generator->cutGeneratorName(),
+                                   generator->normal(),
+                                   generator->atSolution(),
+                                   generator->whenInfeasible(),
+                                   -100, generator->whatDepthInSub(), -1);
+        }
+    }
+    double cutoff = getCutoff();
+    model->setCutoff(cutoff);
+    return model;
+}
+/* Invoke the branch & cut algorithm on partially fixed problem
+
+   The method uses a subModel created by cleanModel. The search
+   ends when the tree is exhausted or maximum nodes is reached.
+
+   If better solution found then it is saved.
+
+   Returns 0 if search completed and solution, 1 if not completed and solution,
+   2 if completed and no solution, 3 if not completed and no solution.
+
+   Normally okay to do subModel immediately followed by subBranchandBound
+   (== other form of subBranchAndBound)
+   but may need to get at model for advanced features.
+
+   Deletes model
+
+*/
+
+int
+CbcModel::subBranchAndBound(CbcModel * model,
+                            CbcModel * presolvedModel,
+                            int maximumNodes)
+{
+    int i;
+    double cutoff = model->getCutoff();
+    CbcModel * model2;
+    if (presolvedModel)
+        model2 = presolvedModel;
+    else
+        model2 = model;
+    // Do complete search
+
+    for (i = 0; i < numberHeuristics_; i++) {
+        model2->addHeuristic(heuristic_[i]);
+        model2->heuristic(i)->resetModel(model2);
+    }
+    // Definition of node choice
+    model2->setNodeComparison(nodeCompare_->clone());
+    //model2->solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry);
+    model2->messageHandler()->setLogLevel(CoinMax(0, handler_->logLevel() - 1));
+    //model2->solver()->messageHandler()->setLogLevel(2);
+    model2->setMaximumCutPassesAtRoot(maximumCutPassesAtRoot_);
+    model2->setPrintFrequency(50);
+    model2->setIntParam(CbcModel::CbcMaxNumNode, maximumNodes);
+    model2->branchAndBound();
+    delete model2->nodeComparison();
+    if (model2->getMinimizationObjValue() > cutoff) {
+        // no good
+        if (model != model2)
+            delete model2;
+        delete model;
+        return 2;
+    }
+    if (model != model2) {
+        // get back solution
+        model->originalModel(model2, false);
+        delete model2;
+    }
+    int status;
+    if (model->getMinimizationObjValue() < cutoff && model->bestSolution()) {
+        double objValue = model->getObjValue();
+        const double * solution = model->bestSolution();
+        setBestSolution(CBC_TREE_SOL, objValue, solution);
+        status = 0;
+    } else {
+        status = 2;
+    }
+    if (model->status())
+        status ++ ; // not finished search
+    delete model;
+    return status;
+}
+/* Invoke the branch & cut algorithm on partially fixed problem
+
+The method creates a new model with given bounds, presolves it
+then proceeds to explore the branch & cut search tree. The search
+ends when the tree is exhausted or maximum nodes is reached.
+Returns 0 if search completed and solution, 1 if not completed and solution,
+2 if completed and no solution, 3 if not completed and no solution.
+*/
+int
+CbcModel::subBranchAndBound(const double * lower, const double * upper,
+                            int maximumNodes)
+{
+    OsiSolverInterface * solver = continuousSolver_->clone();
+
+    int numberIntegers = numberIntegers_;
+    const int * integerVariable = integerVariable_;
+
+    int i;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        const OsiObject * object = object_[i];
+#ifndef NDEBUG
+        const CbcSimpleInteger * integerObject =
+            dynamic_cast<const  CbcSimpleInteger *> (object);
+        assert(integerObject);
+#else
+        const CbcSimpleInteger * integerObject =
+            static_cast<const  CbcSimpleInteger *> (object);
+#endif
+        // get original bounds
+        double originalLower = integerObject->originalLowerBound();
+        double originalUpper = integerObject->originalUpperBound();
+        solver->setColLower(iColumn, CoinMax(lower[iColumn], originalLower));
+        solver->setColUpper(iColumn, CoinMin(upper[iColumn], originalUpper));
+    }
+    CbcModel model(*solver);
+    // off some messages
+    if (handler_->logLevel() <= 1) {
+        model.messagesPointer()->setDetailMessage(3, 9);
+        model.messagesPointer()->setDetailMessage(3, 6);
+        model.messagesPointer()->setDetailMessage(3, 4);
+        model.messagesPointer()->setDetailMessage(3, 1);
+        model.messagesPointer()->setDetailMessage(3, 3007);
+    }
+    double cutoff = getCutoff();
+    model.setCutoff(cutoff);
+    // integer presolve
+    CbcModel * model2 = model.integerPresolve(false);
+    if (!model2 || !model2->getNumRows()) {
+        delete model2;
+        delete solver;
+        return 2;
+    }
+    if (handler_->logLevel() > 1)
+        printf("Reduced model has %d rows and %d columns\n",
+               model2->getNumRows(), model2->getNumCols());
+    // Do complete search
+
+    // Cuts
+    for ( i = 0; i < numberCutGenerators_; i++) {
+        int howOften = generator_[i]->howOftenInSub();
+        if (howOften > -100) {
+            CbcCutGenerator * generator = virginGenerator_[i];
+            CglCutGenerator * cglGenerator = generator->generator();
+            model2->addCutGenerator(cglGenerator, howOften,
+                                    generator->cutGeneratorName(),
+                                    generator->normal(),
+                                    generator->atSolution(),
+                                    generator->whenInfeasible(),
+                                    -100, generator->whatDepthInSub(), -1);
+        }
+    }
+    for (i = 0; i < numberHeuristics_; i++) {
+        model2->addHeuristic(heuristic_[i]);
+        model2->heuristic(i)->resetModel(model2);
+    }
+    // Definition of node choice
+    model2->setNodeComparison(nodeCompare_->clone());
+    //model2->solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry);
+    model2->messageHandler()->setLogLevel(CoinMax(0, handler_->logLevel() - 1));
+    //model2->solver()->messageHandler()->setLogLevel(2);
+    model2->setMaximumCutPassesAtRoot(maximumCutPassesAtRoot_);
+    model2->setPrintFrequency(50);
+    model2->setIntParam(CbcModel::CbcMaxNumNode, maximumNodes);
+    model2->branchAndBound();
+    delete model2->nodeComparison();
+    if (model2->getMinimizationObjValue() > cutoff) {
+        // no good
+        delete model2;
+        delete solver;
+        return 2;
+    }
+    // get back solution
+    model.originalModel(model2, false);
+    delete model2;
+    int status;
+    if (model.getMinimizationObjValue() < cutoff && model.bestSolution()) {
+        double objValue = model.getObjValue();
+        const double * solution = model.bestSolution();
+        setBestSolution(CBC_TREE_SOL, objValue, solution);
+        status = 0;
+    } else {
+        status = 2;
+    }
+    if (model.status())
+        status ++ ; // not finished search
+    delete solver;
+    return status;
+}
+#endif
+
+static void * doRootCbcThread(void * voidInfo)
+{
+    CbcModel * model = reinterpret_cast<CbcModel *> (voidInfo);
+#ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * clpSolver
+      = dynamic_cast<OsiClpSolverInterface *> (model->solver());
+    char general[200];
+    if (clpSolver) {
+      clpSolver->getModelPtr()->dual(); // probably not needed
+      clpSolver->setWarmStart(NULL);
+      sprintf(general,"Starting multiple root solver");
+    } else {
+#endif
+#ifdef COIN_HAS_CLP
+      model->initialSolve();
+      sprintf(general,"Solver did %d iterations in initialSolve\n",
+	     model->solver()->getIterationCount());
+    }
+#endif
+    model->messageHandler()->message(CBC_GENERAL,
+			      model->messages())
+      << general << CoinMessageEol ;
+    model->branchAndBound();
+    sprintf(general,"Ending multiple root solver");
+    model->messageHandler()->message(CBC_GENERAL,
+			      model->messages())
+      << general << CoinMessageEol ;
+    return NULL;
+}
+OsiRowCut *
+CbcModel::conflictCut(const OsiSolverInterface * solver, bool & localCuts)
+{
+  OsiRowCut * cut=NULL;
+  localCuts=false;
+# ifdef COIN_HAS_CLP
+  const OsiClpSolverInterface * clpSolver
+    = dynamic_cast<const OsiClpSolverInterface *> (solver);
+  if (clpSolver&&topOfTree_) {
+    int debugMode=0;
+    const double * originalLower = topOfTree_->lower();
+    const double * originalUpper = topOfTree_->upper();
+    int typeCut = 1;
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+    assert(simplex->status()==1);
+    if(simplex->ray()) {
+      {
+	int numberRows=simplex->numberRows();
+	double * saveRay=CoinCopyOfArray(simplex->ray(),numberRows);
+#define SAFE_RAY
+#ifdef SAFE_RAY
+	ClpSimplex & tempSimplex=*simplex;
+#else
+	ClpSimplex tempSimplex=*simplex;
+#endif
+	int logLevel=simplex->logLevel();
+	tempSimplex.setLogLevel(63);
+	tempSimplex.scaling(0);
+	tempSimplex.dual();
+	tempSimplex.setLogLevel(logLevel);
+	if (!tempSimplex.numberIterations()) {
+	  double * ray = tempSimplex.ray();
+	  int nBad=0;
+	  for (int i=0;i<numberRows;i++) {
+	    if (fabs(ray[i]-saveRay[i])>1.0e-3) {
+	      if (debugMode)
+		printf("row %d true %g bad %g - diff %g\n",
+		       i,ray[i],saveRay[i],ray[i]-saveRay[i]);
+	      nBad++;
+	    }
+	  }
+	  if (nBad)
+	    printf("%d mismatch crunch ray values\n",nBad);
+	}
+	delete [] saveRay;
+      }
+     // make sure we use non-scaled versions
+      ClpPackedMatrix * saveMatrix = simplex->swapScaledMatrix(NULL);
+      double * saveScale = simplex->swapRowScale(NULL);
+      //printf("Could do normal cut\n");
+      // could use existing arrays
+      int numberRows=simplex->numberRows();
+      int numberColumns=simplex->numberColumns();
+      double * farkas = new double [2*numberColumns+numberRows];
+      double * bound = farkas + numberColumns;
+      double * effectiveRhs = bound + numberColumns;
+      // sign as internally for dual - so swap if primal
+      /*const*/ double * ray = simplex->ray();
+      // have to get rid of local cut rows
+      if (whichGenerator_) {
+	const int * whichGenerator = whichGenerator_ - numberRowsAtContinuous_;
+	int badRows=0;
+	for (int iRow=numberRowsAtContinuous_;iRow<numberRows;iRow++) {
+	  int iType=whichGenerator[iRow];
+	  if ((iType>=0&&iType<10000)||iType<-1) {
+	    if (fabs(ray[iRow])>1.0e-10) {
+	      badRows++;
+	    } else {
+	      ray[iRow]=0.0;
+	    }
+	  }
+	}
+	if (badRows) {
+	  if ((debugMode&1)!=0) 
+	    printf("%d rows from local cuts\n",badRows);
+	  localCuts=true;
+	}
+      }
+      // get farkas row
+      memset(farkas,0,(2*numberColumns+numberRows)*sizeof(double));
+      simplex->transposeTimes(-1.0,ray,farkas);
+      //const char * integerInformation = simplex->integerType_;
+      //assert (integerInformation);
+
+      int sequenceOut = simplex->sequenceOut();
+      // Put nonzero bounds in bound
+      const double * columnLower = simplex->columnLower();
+      const double * columnUpper = simplex->columnUpper();
+      int numberBad=0;
+      for (int i=0;i<numberColumns;i++) {
+	double value = farkas[i];
+	double boundValue=0.0;
+	if (simplex->getStatus(i)==ClpSimplex::basic) {
+	  // treat as zero if small
+	  if (fabs(value)<1.0e-8) {
+	    value=0.0;
+	    farkas[i]=0.0;
+	  }
+	  if (value) {
+	    //printf("basic %d direction %d farkas %g\n",
+	    //	   i,simplex->directionOut(),value);
+	    if (value<0.0) 
+	      boundValue=columnLower[i];
+	    else
+	      boundValue=columnUpper[i];
+	  }
+	} else if (fabs(value)>1.0e-10) {
+	  if (value<0.0) 
+	    boundValue=columnLower[i];
+	  else
+	    boundValue=columnUpper[i];
+	}
+	bound[i]=boundValue;
+	if (fabs(boundValue)>1.0e10)
+	  numberBad++;
+      }
+      const double * rowLower = simplex->rowLower();
+      const double * rowUpper = simplex->rowUpper();
+      //int pivotRow = simplex->spareIntArray_[3];
+      //bool badPivot=pivotRow<0;
+      for (int i=0;i<numberRows;i++) {
+	double value = ray[i];
+	double rhsValue=0.0;
+	if (simplex->getRowStatus(i)==ClpSimplex::basic) {
+	  // treat as zero if small
+	  if (fabs(value)<1.0e-8) {
+	    value=0.0;
+	    ray[i]=0.0;
+	  }
+	  if (value) {
+	    //printf("row basic %d direction %d ray %g\n",
+	    //	   i,simplex->directionOut(),value);
+	    if (value<0.0) 
+	      rhsValue=rowLower[i];
+	    else
+	      rhsValue=rowUpper[i];
+	  }
+	} else if (fabs(value)>1.0e-10) {
+	  if (value<0.0) 
+	    rhsValue=rowLower[i];
+	  else
+	      rhsValue=rowUpper[i];
+	}
+	effectiveRhs[i]=rhsValue;
+      }
+      simplex->times(-1.0,bound,effectiveRhs);
+      simplex->swapRowScale(saveScale);
+      simplex->swapScaledMatrix(saveMatrix);
+      double bSum=0.0;
+      for (int i=0;i<numberRows;i++) {
+	bSum += effectiveRhs[i]*ray[i];
+      }
+      if (numberBad||bSum>-1.0e-4) {
+#ifndef NDEBUG
+	printf("bad BOUND bSum %g  - %d bad\n",
+	       bSum,numberBad);
+#endif
+      } else {
+	const char * integerInformation = simplex->integerInformation();
+	assert (integerInformation);
+	int * conflict = new int[numberColumns];
+	double * sort = new double [numberColumns];
+	double relax=0.0;
+	int nConflict=0;
+	int nOriginal=0;
+	int nFixed=0;
+	for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+	  if (integerInformation[iColumn]) {
+	    if ((debugMode&1)!=0)
+	    printf("%d status %d %g <= %g <=%g (orig %g, %g) farkas %g\n",
+		   iColumn,simplex->getStatus(iColumn),columnLower[iColumn],
+		   simplex->primalColumnSolution()[iColumn],columnUpper[iColumn],
+		   originalLower[iColumn],originalUpper[iColumn],
+		   farkas[iColumn]);
+	    double gap = originalUpper[iColumn]-originalLower[iColumn];
+	    if (!gap) 
+	      continue;
+	    if (gap==columnUpper[iColumn]-columnLower[iColumn])
+	      nOriginal++;
+	    if (columnUpper[iColumn]==columnLower[iColumn])
+	      nFixed++;
+	    if (fabs(farkas[iColumn])<1.0e-15) {
+	      farkas[iColumn]=0.0;
+	      continue;
+	    }
+	    // temp
+	    if (gap>=20000.0&&false) {
+	      // can't use
+	      if (farkas[iColumn]<0.0) {
+		assert(originalLower[iColumn]-columnLower[iColumn]<=0.0);
+		// farkas is negative - relax lower bound all way 
+		relax += 
+		  farkas[iColumn]*(originalLower[iColumn]-columnLower[iColumn]);
+	      } else {
+		assert(originalUpper[iColumn]-columnUpper[iColumn]>=0.0);
+		// farkas is positive - relax upper bound all way 
+		relax += 
+		  farkas[iColumn]*(originalUpper[iColumn]-columnUpper[iColumn]);
+	      }
+	      continue;
+	    }
+	    if (originalLower[iColumn]==columnLower[iColumn]) {
+	      if (farkas[iColumn]>0.0&&(simplex->getStatus(iColumn)==ClpSimplex::atUpperBound
+					||simplex->getStatus(iColumn)==ClpSimplex::isFixed
+					||iColumn==sequenceOut)) {
+		// farkas is positive - add to list
+		gap=originalUpper[iColumn]-columnUpper[iColumn];
+		if (gap) {
+		  sort[nConflict]=-farkas[iColumn]*gap;
+		  conflict[nConflict++]=iColumn;
+		}
+		//assert (gap>columnUpper[iColumn]-columnLower[iColumn]);
+	      }
+	    } else if (originalUpper[iColumn]==columnUpper[iColumn]) {
+	      if (farkas[iColumn]<0.0&&(simplex->getStatus(iColumn)==ClpSimplex::atLowerBound
+					||simplex->getStatus(iColumn)==ClpSimplex::isFixed
+					||iColumn==sequenceOut)) {
+		// farkas is negative - add to list
+		gap=columnLower[iColumn]-originalLower[iColumn];
+		if (gap) {
+		  sort[nConflict]=farkas[iColumn]*gap;
+		  conflict[nConflict++]=iColumn;
+		}
+		//assert (gap>columnUpper[iColumn]-columnLower[iColumn]);
+	      }
+	    } else {
+	      // can't use
+	      if (farkas[iColumn]<0.0) {
+		assert(originalLower[iColumn]-columnLower[iColumn]<=0.0);
+		// farkas is negative - relax lower bound all way 
+		relax += 
+		  farkas[iColumn]*(originalLower[iColumn]-columnLower[iColumn]);
+	      } else {
+		assert(originalUpper[iColumn]-columnUpper[iColumn]>=0.0);
+		// farkas is positive - relax upper bound all way 
+		relax += 
+		  farkas[iColumn]*(originalUpper[iColumn]-columnUpper[iColumn]);
+	      }
+	    }
+	    assert(relax>=0.0);
+	  } else {
+	    // not integer - but may have been got at
+	    double gap = originalUpper[iColumn]-originalLower[iColumn];
+	    if (gap>columnUpper[iColumn]-columnLower[iColumn]) {
+	      // can't use
+	      if (farkas[iColumn]<0.0) {
+		assert(originalLower[iColumn]-columnLower[iColumn]<=0.0);
+		// farkas is negative - relax lower bound all way 
+		relax += 
+		  farkas[iColumn]*(originalLower[iColumn]-columnLower[iColumn]);
+	      } else {
+		assert(originalUpper[iColumn]-columnUpper[iColumn]>=0.0);
+		// farkas is positive - relax upper bound all way 
+		relax += 
+		  farkas[iColumn]*(originalUpper[iColumn]-columnUpper[iColumn]);
+	      }
+	    }
+	  }
+	}
+	if (relax+bSum>-1.0e-4||!nConflict) {
+	  if (relax+bSum>-1.0e-4) {
+#ifndef NDEBUG
+	    printf("General integers relax bSum to %g\n",relax+bSum);
+#endif
+	  } else {
+	    printf("All variables relaxed and still infeasible - what does this mean?\n");
+	    int nR=0;
+	    for (int i=0;i<numberRows;i++) {
+	      if (fabs(ray[i])>1.0e-10)
+		nR++;
+	      else
+		ray[i]=0.0;
+	    }
+	    int nC=0;
+	    for (int i=0;i<numberColumns;i++) {
+	      if (fabs(farkas[i])>1.0e-10)
+		nC++;
+	      else
+		farkas[i]=0.0;
+	    }
+	    if (nR<3&&nC<5) {
+	      printf("BAD %d nonzero rows, %d nonzero columns\n",nR,nC);
+	    }
+	  }
+	} else {
+	  printf("BOUNDS violation bSum %g (relaxed %g) - %d at original bounds, %d fixed - %d in conflict\n",bSum,
+		 relax+bSum,nOriginal,nFixed,nConflict);
+	  CoinSort_2(sort,sort+nConflict,conflict);
+	  int nC=nConflict;
+	  bSum+=relax;
+	  double saveBsum = bSum;
+	  while (nConflict) {
+	    //int iColumn=conflict[nConflict-1];
+	    double change=-sort[nConflict-1];
+	    if (bSum+change>-1.0e-4)
+	      break;
+	    nConflict--;
+	    bSum += change;
+	  }
+	  if (!nConflict) {
+	    int nR=0;
+	    for (int i=0;i<numberRows;i++) {
+	      if (fabs(ray[i])>1.0e-10)
+		nR++;
+	      else
+		ray[i]=0.0;
+	    }
+	    int nC=0;
+	    for (int i=0;i<numberColumns;i++) {
+	      if (fabs(farkas[i])>1.0e-10)
+		nC++;
+	      else
+		farkas[i]=0.0;
+	    }
+	    if (nR<3&&nC<5) {
+	      printf("BAD2 %d nonzero rows, %d nonzero columns\n",nR,nC);
+	    }
+	  }
+	  // no point doing if no reduction (or big?) ?
+	  if (nConflict<nC+1&&nConflict<500) {
+	    cut=new OsiRowCut();
+	    cut->setUb(COIN_DBL_MAX);
+	    if (!typeCut) {
+	      double lo=1.0;
+	      for (int i=0;i<nConflict;i++) {
+		int iColumn = conflict[i];
+		if (originalLower[iColumn]==columnLower[iColumn]) {
+		  // must be at least one higher
+		  sort[i]=1.0;
+		  lo += originalLower[iColumn];
+		} else {
+		  // must be at least one lower
+		  sort[i]=-1.0;
+		  lo -= originalUpper[iColumn];
+		}
+	      }
+	      cut->setLb(lo);
+	      cut->setRow(nConflict,conflict,sort);
+	      printf("CUT has %d (started at %d) - final bSum %g\n",nConflict,nC,bSum);
+	    } else {
+	      // just save for use later
+	      // first take off small
+	      int nC2=nC;
+	      while (nC2) {
+		//int iColumn=conflict[nConflict-1];
+		double change=-sort[nC2-1];
+		if (saveBsum+change>-1.0e-4||change>1.0e-4)
+		  break;
+		nC2--;
+		saveBsum += change;
+	      }
+	      cut->setLb(saveBsum);
+	      for (int i=0;i<nC2;i++) {
+		int iColumn = conflict[i];
+		sort[i]=farkas[iColumn];
+	      }
+	      cut->setRow(nC2,conflict,sort);
+	      printf("Stem CUT has %d (greedy %d - with small %d) - saved bSum %g final greedy bSum %g\n",
+		     nC2,nConflict,nC,saveBsum,bSum);
+	    }
+	  }
+	}
+	delete [] conflict;
+	delete [] sort;
+      }
+      delete [] farkas;
+    } else {
+      printf("No dual ray\n");
+    }
+  }
+#endif
+  return cut;
+}
+
diff --git a/cbits/coin/CbcModel.hpp b/cbits/coin/CbcModel.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcModel.hpp
@@ -0,0 +1,2858 @@
+/* $Id: CbcModel.hpp 1973 2013-10-19 15:59:44Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcModel_H
+#define CbcModel_H
+#include <string>
+#include <vector>
+#include "CoinMessageHandler.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiBranchingObject.hpp"
+#include "OsiCuts.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CbcCompareBase.hpp"
+#include "CbcCountRowCut.hpp"
+#include "CbcMessage.hpp"
+#include "CbcEventHandler.hpp"
+#include "ClpDualRowPivot.hpp"
+
+
+class CbcCutGenerator;
+class CbcBaseModel;
+class OsiRowCut;
+class OsiBabSolver;
+class OsiRowCutDebugger;
+class CglCutGenerator;
+class CglStored;
+class CbcCutModifier;
+class CglTreeProbingInfo;
+class CbcHeuristic;
+class OsiObject;
+class CbcThread;
+class CbcTree;
+class CbcStrategy;
+class CbcFeasibilityBase;
+class CbcStatistics;
+class CbcFullNodeInfo;
+class CbcEventHandler ;
+class CglPreProcess;
+class OsiClpSolverInterface;
+class ClpNodeStuff;
+
+// #define CBC_CHECK_BASIS 1
+
+//#############################################################################
+
+/** Simple Branch and bound class
+
+  The initialSolve() method solves the initial LP relaxation of the MIP
+  problem. The branchAndBound() method can then be called to finish using
+  a branch and cut algorithm.
+
+  <h3>Search Tree Traversal</h3>
+
+  Subproblems (aka nodes) requiring additional evaluation are stored using
+  the CbcNode and CbcNodeInfo objects. Ancestry linkage is maintained in the
+  CbcNodeInfo object. Evaluation of a subproblem within branchAndBound()
+  proceeds as follows:
+  <ul>
+    <li> The node representing the most promising parent subproblem is popped
+	 from the heap which holds the set of subproblems requiring further
+	 evaluation.
+    <li> Using branching instructions stored in the node, and information in
+	 its ancestors, the model and solver are adjusted to create the
+	 active subproblem.
+    <li> If the parent subproblem will require further evaluation
+	 (<i>i.e.</i>, there are branches remaining) its node is pushed back
+	 on the heap. Otherwise, the node is deleted.  This may trigger
+	 recursive deletion of ancestors.
+    <li> The newly created subproblem is evaluated.
+    <li> If the subproblem requires further evaluation, a node is created.
+	 All information needed to recreate the subproblem (branching
+	 information, row and column cuts) is placed in the node and the node
+	 is added to the set of subproblems awaiting further evaluation.
+  </ul>
+  Note that there is never a node representing the active subproblem; the model
+  and solver represent the active subproblem.
+
+  <h3>Row (Constraint) Cut Handling</h3>
+
+  For a typical subproblem, the sequence of events is as follows:
+  <ul>
+    <li> The subproblem is rebuilt for further evaluation: One result of a
+	 call to addCuts() is a traversal of ancestors, leaving a list of all
+	 cuts used in the ancestors in #addedCuts_. This list is then scanned
+	 to construct a basis that includes only tight cuts. Entries for
+	 loose cuts are set to NULL.
+    <li> The subproblem is evaluated: One result of a call to solveWithCuts()
+         is the return of a set of newly generated cuts for the subproblem.
+	 #addedCuts_ is also kept up-to-date as old cuts become loose.
+    <li> The subproblem is stored for further processing: A call to
+	 CbcNodeInfo::addCuts() adds the newly generated cuts to the
+	 CbcNodeInfo object associated with this node.
+  </ul>
+  See CbcCountRowCut for details of the bookkeeping associated with cut
+  management.
+*/
+
+class CbcModel  {
+
+public:
+
+    enum CbcIntParam {
+        /** The maximum number of nodes before terminating */
+        CbcMaxNumNode = 0,
+        /** The maximum number of solutions before terminating */
+        CbcMaxNumSol,
+        /** Fathoming discipline
+
+          Controls objective function comparisons for purposes of fathoming by bound
+          or determining monotonic variables.
+
+          If 1, action is taken only when the current objective is strictly worse
+          than the target. Implementation is handled by adding a small tolerance to
+          the target.
+        */
+        CbcFathomDiscipline,
+        /** Adjusts printout
+            1 does different node message with number unsatisfied on last branch
+        */
+        CbcPrinting,
+        /** Number of branches (may be more than number of nodes as may
+            include strong branching) */
+        CbcNumberBranches,
+        /** Just a marker, so that a static sized array can store parameters. */
+        CbcLastIntParam
+    };
+
+    enum CbcDblParam {
+        /** The maximum amount the value of an integer variable can vary from
+            integer and still be considered feasible. */
+        CbcIntegerTolerance = 0,
+        /** The objective is assumed to worsen by this amount for each
+            integer infeasibility. */
+        CbcInfeasibilityWeight,
+        /** The amount by which to tighten the objective function cutoff when
+            a new solution is discovered. */
+        CbcCutoffIncrement,
+        /** Stop when the gap between the objective value of the best known solution
+          and the best bound on the objective of any solution is less than this.
+
+          This is an absolute value. Conversion from a percentage is left to the
+          client.
+        */
+        CbcAllowableGap,
+        /** Stop when the gap between the objective value of the best known solution
+          and the best bound on the objective of any solution is less than this
+          fraction of of the absolute value of best known solution.
+
+          Code stops if either this test or CbcAllowableGap test succeeds
+        */
+        CbcAllowableFractionGap,
+        /** \brief The maximum number of seconds before terminating.
+               A double should be adequate! */
+        CbcMaximumSeconds,
+        /// Cutoff - stored for speed
+        CbcCurrentCutoff,
+        /// Optimization direction - stored for speed
+        CbcOptimizationDirection,
+        /// Current objective value
+        CbcCurrentObjectiveValue,
+        /// Current minimization objective value
+        CbcCurrentMinimizationObjectiveValue,
+        /** \brief The time at start of model.
+               So that other pieces of code can access */
+        CbcStartSeconds,
+        /** Stop doing heuristics when the gap between the objective value of the
+            best known solution and the best bound on the objective of any solution
+            is less than this.
+
+          This is an absolute value. Conversion from a percentage is left to the
+          client.
+        */
+        CbcHeuristicGap,
+        /** Stop doing heuristics when the gap between the objective value of the
+            best known solution and the best bound on the objective of any solution
+            is less than this fraction of of the absolute value of best known
+            solution.
+
+          Code stops if either this test or CbcAllowableGap test succeeds
+        */
+        CbcHeuristicFractionGap,
+        /// Smallest non-zero change on a branch
+        CbcSmallestChange,
+        /// Sum of non-zero changes on a branch
+        CbcSumChange,
+        /// Largest non-zero change on a branch
+        CbcLargestChange,
+        /// Small non-zero change on a branch to be used as guess
+        CbcSmallChange,
+        /** Just a marker, so that a static sized array can store parameters. */
+        CbcLastDblParam
+    };
+
+    //---------------------------------------------------------------------------
+
+public:
+    ///@name Solve methods
+    //@{
+    /** \brief Solve the initial LP relaxation
+
+      Invoke the solver's %initialSolve() method.
+    */
+    void initialSolve();
+
+    /** \brief Invoke the branch \& cut algorithm
+
+      The method assumes that initialSolve() has been called to solve the
+      LP relaxation. It processes the root node, then proceeds to explore the
+      branch & cut search tree. The search ends when the tree is exhausted or
+      one of several execution limits is reached.
+      If doStatistics is 1 summary statistics are printed
+      if 2 then also the path to best solution (if found by branching)
+      if 3 then also one line per node
+    */
+    void branchAndBound(int doStatistics = 0);
+private:
+
+    /** \brief Evaluate a subproblem using cutting planes and heuristics
+
+      The method invokes a main loop which generates cuts, applies heuristics,
+      and reoptimises using the solver's native %resolve() method.
+      It returns true if the subproblem remains feasible at the end of the
+      evaluation.
+    */
+    bool solveWithCuts(OsiCuts & cuts, int numberTries, CbcNode * node);
+    /** Generate one round of cuts - serial mode
+      returns -
+      0 - normal
+      1 - must keep going
+      2 - set numberTries to zero
+      -1 - infeasible
+    */
+    int serialCuts(OsiCuts & cuts, CbcNode * node, OsiCuts & slackCuts, int lastNumberCuts);
+    /** Generate one round of cuts - parallel mode
+        returns -
+        0 - normal
+        1 - must keep going
+        2 - set numberTries to zero
+        -1 - infeasible
+    */
+    int parallelCuts(CbcBaseModel * master, OsiCuts & cuts, CbcNode * node, OsiCuts & slackCuts, int lastNumberCuts);
+    /** Input one node output N nodes to put on tree and optional solution update
+        This should be able to operate in parallel so is given a solver and is const(ish)
+        However we will need to keep an array of solver_ and bases and more
+        status is 0 for normal, 1 if solution
+        Calling code should always push nodes back on tree
+    */
+    CbcNode ** solveOneNode(int whichSolver, CbcNode * node,
+                            int & numberNodesOutput, int & status) ;
+    /// Update size of whichGenerator
+    void resizeWhichGenerator(int numberNow, int numberAfter);
+public:
+#ifdef CBC_KEEP_DEPRECATED
+    // See if anyone is using these any more!!
+    /** \brief create a clean model from partially fixed problem
+
+      The method creates a new model with given bounds and with no tree.
+    */
+    CbcModel *  cleanModel(const double * lower, const double * upper);
+    /** \brief Invoke the branch \& cut algorithm on partially fixed problem
+
+      The method presolves the given model and does branch and cut. The search
+      ends when the tree is exhausted or maximum nodes is reached.
+
+      If better solution found then it is saved.
+
+      Returns 0 if search completed and solution, 1 if not completed and solution,
+      2 if completed and no solution, 3 if not completed and no solution.
+
+      Normally okay to do cleanModel immediately followed by subBranchandBound
+      (== other form of subBranchAndBound)
+      but may need to get at model for advanced features.
+
+      Deletes model2
+    */
+    int subBranchAndBound(CbcModel * model2,
+                          CbcModel * presolvedModel,
+                          int maximumNodes);
+    /** \brief Invoke the branch \& cut algorithm on partially fixed problem
+
+      The method creates a new model with given bounds, presolves it
+      then proceeds to explore the branch & cut search tree. The search
+      ends when the tree is exhausted or maximum nodes is reached.
+
+      If better solution found then it is saved.
+
+      Returns 0 if search completed and solution, 1 if not completed and solution,
+      2 if completed and no solution, 3 if not completed and no solution.
+
+      This is just subModel immediately followed by other version of
+      subBranchandBound.
+
+    */
+    int subBranchAndBound(const double * lower, const double * upper,
+                          int maximumNodes);
+
+    /** \brief Process root node and return a strengthened model
+
+      The method assumes that initialSolve() has been called to solve the
+      LP relaxation. It processes the root node and then returns a pointer
+      to the strengthened model (or NULL if infeasible)
+    */
+    OsiSolverInterface *  strengthenedModel();
+    /** preProcess problem - replacing solver
+        If makeEquality true then <= cliques converted to ==.
+        Presolve will be done numberPasses times.
+
+        Returns NULL if infeasible
+
+        If makeEquality is 1 add slacks to get cliques,
+        if 2 add slacks to get sos (but only if looks plausible) and keep sos info
+    */
+    CglPreProcess * preProcess( int makeEquality = 0, int numberPasses = 5,
+                                int tuning = 5);
+    /** Does postprocessing - original solver back.
+        User has to delete process */
+    void postProcess(CglPreProcess * process);
+#endif
+    /// Adds an update information object
+    void addUpdateInformation(const CbcObjectUpdateData & data);
+    /** Do one node - broken out for clarity?
+        also for parallel (when baseModel!=this)
+        Returns 1 if solution found
+        node NULL on return if no branches left
+        newNode NULL if no new node created
+    */
+    int doOneNode(CbcModel * baseModel, CbcNode * & node, CbcNode * & newNode);
+
+public:
+    /** \brief Reoptimise an LP relaxation
+
+      Invoke the solver's %resolve() method.
+      whereFrom -
+      0 - initial continuous
+      1 - resolve on branch (before new cuts)
+      2 - after new cuts
+      3  - obsolete code or something modified problem in unexpected way
+      10 - after strong branching has fixed variables at root
+      11 - after strong branching has fixed variables in tree
+
+      returns 1 feasible, 0 infeasible, -1 feasible but skip cuts
+    */
+    int resolve(CbcNodeInfo * parent, int whereFrom,
+                double * saveSolution = NULL,
+                double * saveLower = NULL,
+                double * saveUpper = NULL);
+    /// Make given rows (L or G) into global cuts and remove from lp
+    void makeGlobalCuts(int numberRows, const int * which);
+    /// Make given cut into a global cut
+    void makeGlobalCut(const OsiRowCut * cut);
+    /// Make given cut into a global cut
+    void makeGlobalCut(const OsiRowCut & cut);
+    /// Make given column cut into a global cut
+    void makeGlobalCut(const OsiColCut * cut);
+    /// Make given column cut into a global cut
+    void makeGlobalCut(const OsiColCut & cut);
+    /// Make partial cut into a global cut and save
+  void makePartialCut(const OsiRowCut * cut, const OsiSolverInterface * solver=NULL);
+    /// Make partial cuts into global cuts
+    void makeGlobalCuts();
+    /// Which cut generator generated this cut
+    inline const int * whichGenerator() const
+    { return whichGenerator_;}
+    //@}
+
+    /** \name Presolve methods */
+    //@{
+
+    /** Identify cliques and construct corresponding objects.
+
+        Find cliques with size in the range
+        [\p atLeastThisMany, \p lessThanThis] and construct corresponding
+        CbcClique objects.
+        If \p makeEquality is true then a new model may be returned if
+        modifications had to be made, otherwise \c this is returned.
+        If the problem is infeasible #numberObjects_ is set to -1.
+        A client must use deleteObjects() before a second call to findCliques().
+        If priorities exist, clique priority is set to the default.
+    */
+    CbcModel * findCliques(bool makeEquality, int atLeastThisMany,
+                           int lessThanThis, int defaultValue = 1000);
+
+    /** Do integer presolve, creating a new (presolved) model.
+
+      Returns the new model, or NULL if feasibility is lost.
+      If weak is true then just does a normal presolve
+
+      \todo It remains to work out the cleanest way of getting a solution to
+            the original problem at the end. So this is very preliminary.
+     */
+    CbcModel * integerPresolve(bool weak = false);
+
+    /** Do integer presolve, modifying the current model.
+
+        Returns true if the model remains feasible after presolve.
+    */
+    bool integerPresolveThisModel(OsiSolverInterface * originalSolver, bool weak = false);
+
+
+    /// Put back information into the original model after integer presolve.
+    void originalModel(CbcModel * presolvedModel, bool weak);
+
+    /** \brief For variables involved in VUB constraints, see if we can tighten
+           bounds by solving lp's
+
+        Returns false if feasibility is lost.
+        If CglProbing is available, it will be tried as well to see if it can
+        tighten bounds.
+        This routine is just a front end for tightenVubs(int,const int*,double).
+
+        If <tt>type = -1</tt> all variables are processed (could be very slow).
+        If <tt>type = 0</tt> only variables involved in VUBs are processed.
+        If <tt>type = n > 0</tt>, only the n most expensive VUB variables
+        are processed, where it is assumed that x is at its maximum so delta
+        would have to go to 1 (if x not at bound).
+
+        If \p allowMultipleBinary is true, then a VUB constraint is a row with
+        one continuous variable and any number of binary variables.
+
+        If <tt>useCutoff < 1.0e30</tt>, the original objective is installed as a
+        constraint with \p useCutoff as a bound.
+    */
+    bool tightenVubs(int type, bool allowMultipleBinary = false,
+                     double useCutoff = 1.0e50);
+
+    /** \brief For variables involved in VUB constraints, see if we can tighten
+           bounds by solving lp's
+
+      This version is just handed a list of variables to be processed.
+    */
+    bool tightenVubs(int numberVubs, const int * which,
+                     double useCutoff = 1.0e50);
+    /**
+      Analyze problem to find a minimum change in the objective function.
+    */
+    void analyzeObjective();
+
+    /**
+      Add additional integers.
+    */
+    void AddIntegers();
+    /**
+      Save copy of the model.
+    */
+    void saveModel(OsiSolverInterface * saveSolver, double * checkCutoffForRestart, bool * feasible);
+    /**
+      Flip direction of optimization on all models
+    */
+    void flipModel();
+
+    //@}
+
+    /** \name Object manipulation routines
+
+      See OsiObject for an explanation of `object' in the context of CbcModel.
+    */
+    //@{
+
+    /// Get the number of objects
+    inline int numberObjects() const {
+        return numberObjects_;
+    }
+    /// Set the number of objects
+    inline void setNumberObjects(int number) {
+        numberObjects_ = number;
+    }
+
+    /// Get the array of objects
+    inline OsiObject ** objects() const {
+        return object_;
+    }
+
+    /// Get the specified object
+    const inline OsiObject * object(int which) const {
+        return object_[which];
+    }
+    /// Get the specified object
+    inline OsiObject * modifiableObject(int which) const {
+        return object_[which];
+    }
+
+    void setOptionalInteger(int index);
+
+    /// Delete all object information (and just back to integers if true)
+    void deleteObjects(bool findIntegers = true);
+
+    /** Add in object information.
+
+      Objects are cloned; the owner can delete the originals.
+    */
+    void addObjects(int numberObjects, OsiObject ** objects);
+
+    /** Add in object information.
+
+      Objects are cloned; the owner can delete the originals.
+    */
+    void addObjects(int numberObjects, CbcObject ** objects);
+
+    /// Ensure attached objects point to this model.
+    void synchronizeModel() ;
+
+    /** \brief Identify integer variables and create corresponding objects.
+
+      Record integer variables and create an CbcSimpleInteger object for each
+      one.
+      If \p startAgain is true, a new scan is forced, overwriting any existing
+      integer variable information.
+      If type > 0 then 1==PseudoCost, 2 new ones low priority
+    */
+
+    void findIntegers(bool startAgain, int type = 0);
+
+    //@}
+
+    //---------------------------------------------------------------------------
+
+    /**@name Parameter set/get methods
+
+       The set methods return true if the parameter was set to the given value,
+       false if the value of the parameter is out of range.
+
+       The get methods return the value of the parameter.
+
+    */
+    //@{
+    /// Set an integer parameter
+    inline bool setIntParam(CbcIntParam key, int value) {
+        intParam_[key] = value;
+        return true;
+    }
+    /// Set a double parameter
+    inline bool setDblParam(CbcDblParam key, double value) {
+        dblParam_[key] = value;
+        return true;
+    }
+    /// Get an integer parameter
+    inline int getIntParam(CbcIntParam key) const {
+        return intParam_[key];
+    }
+    /// Get a double parameter
+    inline double getDblParam(CbcDblParam key) const {
+        return dblParam_[key];
+    }
+    /*! \brief Set cutoff bound on the objective function.
+
+      When using strict comparison, the bound is adjusted by a tolerance to
+      avoid accidentally cutting off the optimal solution.
+    */
+    void setCutoff(double value) ;
+
+    /// Get the cutoff bound on the objective function - always as minimize
+    inline double getCutoff() const { //double value ;
+        //solver_->getDblParam(OsiDualObjectiveLimit,value) ;
+        //assert( dblParam_[CbcCurrentCutoff]== value * solver_->getObjSense());
+        return dblParam_[CbcCurrentCutoff];
+    }
+
+    /// Set the \link CbcModel::CbcMaxNumNode maximum node limit \endlink
+    inline bool setMaximumNodes( int value) {
+        return setIntParam(CbcMaxNumNode, value);
+    }
+
+    /// Get the \link CbcModel::CbcMaxNumNode maximum node limit \endlink
+    inline int getMaximumNodes() const {
+        return getIntParam(CbcMaxNumNode);
+    }
+
+    /** Set the
+        \link CbcModel::CbcMaxNumSol maximum number of solutions \endlink
+        desired.
+    */
+    inline bool setMaximumSolutions( int value) {
+        return setIntParam(CbcMaxNumSol, value);
+    }
+    /** Get the
+        \link CbcModel::CbcMaxNumSol maximum number of solutions \endlink
+        desired.
+    */
+    inline int getMaximumSolutions() const {
+        return getIntParam(CbcMaxNumSol);
+    }
+    /// Set the printing mode
+    inline bool setPrintingMode( int value) {
+        return setIntParam(CbcPrinting, value);
+    }
+
+    /// Get the printing mode
+    inline int getPrintingMode() const {
+        return getIntParam(CbcPrinting);
+    }
+
+    /** Set the
+        \link CbcModel::CbcMaximumSeconds maximum number of seconds \endlink
+        desired.
+    */
+    inline bool setMaximumSeconds( double value) {
+        return setDblParam(CbcMaximumSeconds, value);
+    }
+    /** Get the
+        \link CbcModel::CbcMaximumSeconds maximum number of seconds \endlink
+        desired.
+    */
+    inline double getMaximumSeconds() const {
+        return getDblParam(CbcMaximumSeconds);
+    }
+    /// Current time since start of branchAndbound
+    double getCurrentSeconds() const ;
+
+    /// Return true if maximum time reached
+    bool maximumSecondsReached() const ;
+
+    /** Set the
+      \link CbcModel::CbcIntegerTolerance integrality tolerance \endlink
+    */
+    inline bool setIntegerTolerance( double value) {
+        return setDblParam(CbcIntegerTolerance, value);
+    }
+    /** Get the
+      \link CbcModel::CbcIntegerTolerance integrality tolerance \endlink
+    */
+    inline double getIntegerTolerance() const {
+        return getDblParam(CbcIntegerTolerance);
+    }
+
+    /** Set the
+        \link CbcModel::CbcInfeasibilityWeight
+          weight per integer infeasibility \endlink
+    */
+    inline bool setInfeasibilityWeight( double value) {
+        return setDblParam(CbcInfeasibilityWeight, value);
+    }
+    /** Get the
+        \link CbcModel::CbcInfeasibilityWeight
+          weight per integer infeasibility \endlink
+    */
+    inline double getInfeasibilityWeight() const {
+        return getDblParam(CbcInfeasibilityWeight);
+    }
+
+    /** Set the \link CbcModel::CbcAllowableGap allowable gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline bool setAllowableGap( double value) {
+        return setDblParam(CbcAllowableGap, value);
+    }
+    /** Get the \link CbcModel::CbcAllowableGap allowable gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline double getAllowableGap() const {
+        return getDblParam(CbcAllowableGap);
+    }
+
+    /** Set the \link CbcModel::CbcAllowableFractionGap fraction allowable gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline bool setAllowableFractionGap( double value) {
+        return setDblParam(CbcAllowableFractionGap, value);
+    }
+    /** Get the \link CbcModel::CbcAllowableFractionGap fraction allowable gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline double getAllowableFractionGap() const {
+        return getDblParam(CbcAllowableFractionGap);
+    }
+    /** Set the \link CbcModel::CbcAllowableFractionGap percentage allowable gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline bool setAllowablePercentageGap( double value) {
+        return setDblParam(CbcAllowableFractionGap, value*0.01);
+    }
+    /** Get the \link CbcModel::CbcAllowableFractionGap percentage allowable gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline double getAllowablePercentageGap() const {
+        return 100.0*getDblParam(CbcAllowableFractionGap);
+    }
+    /** Set the \link CbcModel::CbcHeuristicGap heuristic gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline bool setHeuristicGap( double value) {
+        return setDblParam(CbcHeuristicGap, value);
+    }
+    /** Get the \link CbcModel::CbcHeuristicGap heuristic gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline double getHeuristicGap() const {
+        return getDblParam(CbcHeuristicGap);
+    }
+
+    /** Set the \link CbcModel::CbcHeuristicFractionGap fraction heuristic gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline bool setHeuristicFractionGap( double value) {
+        return setDblParam(CbcHeuristicFractionGap, value);
+    }
+    /** Get the \link CbcModel::CbcHeuristicFractionGap fraction heuristic gap \endlink
+        between the best known solution and the best possible solution.
+    */
+    inline double getHeuristicFractionGap() const {
+        return getDblParam(CbcHeuristicFractionGap);
+    }
+    /** Set the
+        \link CbcModel::CbcCutoffIncrement  \endlink
+        desired.
+    */
+    inline bool setCutoffIncrement( double value) {
+        return setDblParam(CbcCutoffIncrement, value);
+    }
+    /** Get the
+        \link CbcModel::CbcCutoffIncrement  \endlink
+        desired.
+    */
+    inline double getCutoffIncrement() const {
+        return getDblParam(CbcCutoffIncrement);
+    }
+    /// See if can stop on gap
+    bool canStopOnGap() const;
+
+    /** Pass in target solution and optional priorities.
+        If priorities then >0 means only branch if incorrect
+        while <0 means branch even if correct. +1 or -1 are
+        highest priority */
+    void setHotstartSolution(const double * solution, const int * priorities = NULL) ;
+
+    /// Set the minimum drop to continue cuts
+    inline void setMinimumDrop(double value) {
+        minimumDrop_ = value;
+    }
+    /// Get the minimum drop to continue cuts
+    inline double getMinimumDrop() const {
+        return minimumDrop_;
+    }
+
+    /** Set the maximum number of cut passes at root node (default 20)
+        Minimum drop can also be used for fine tuning */
+    inline void setMaximumCutPassesAtRoot(int value) {
+        maximumCutPassesAtRoot_ = value;
+    }
+    /** Get the maximum number of cut passes at root node */
+    inline int getMaximumCutPassesAtRoot() const {
+        return maximumCutPassesAtRoot_;
+    }
+
+    /** Set the maximum number of cut passes at other nodes (default 10)
+        Minimum drop can also be used for fine tuning */
+    inline void setMaximumCutPasses(int value) {
+        maximumCutPasses_ = value;
+    }
+    /** Get the maximum number of cut passes at other nodes (default 10) */
+    inline int getMaximumCutPasses() const {
+        return maximumCutPasses_;
+    }
+    /** Get current cut pass number in this round of cuts.
+        (1 is first pass) */
+    inline int getCurrentPassNumber() const {
+        return currentPassNumber_;
+    }
+
+    /** Set the maximum number of candidates to be evaluated for strong
+      branching.
+
+      A value of 0 disables strong branching.
+    */
+    void setNumberStrong(int number);
+    /** Get the maximum number of candidates to be evaluated for strong
+      branching.
+    */
+    inline int numberStrong() const {
+        return numberStrong_;
+    }
+    /** Set global preferred way to branch
+        -1 down, +1 up, 0 no preference */
+    inline void setPreferredWay(int value) {
+        preferredWay_ = value;
+    }
+    /** Get the preferred way to branch (default 0) */
+    inline int getPreferredWay() const {
+        return preferredWay_;
+    }
+    /// Get at which depths to do cuts
+    inline int whenCuts() const {
+        return whenCuts_;
+    }
+    /// Set at which depths to do cuts
+    inline void setWhenCuts(int value) {
+        whenCuts_ = value;
+    }
+    /** Return true if we want to do cuts
+        If allowForTopOfTree zero then just does on multiples of depth
+        if 1 then allows for doing at top of tree
+        if 2 then says if cuts allowed anywhere apart from root
+    */
+    bool doCutsNow(int allowForTopOfTree) const;
+
+    /** Set the number of branches before pseudo costs believed
+        in dynamic strong branching.
+
+      A value of 0 disables dynamic strong branching.
+    */
+    void setNumberBeforeTrust(int number);
+    /** get the number of branches before pseudo costs believed
+        in dynamic strong branching. */
+    inline int numberBeforeTrust() const {
+        return numberBeforeTrust_;
+    }
+    /** Set the number of variables for which to compute penalties
+        in dynamic strong branching.
+
+      A value of 0 disables penalties.
+    */
+    void setNumberPenalties(int number);
+    /** get the number of variables for which to compute penalties
+        in dynamic strong branching. */
+    inline int numberPenalties() const {
+        return numberPenalties_;
+    }
+    /// Pointer to top of tree
+    inline const CbcFullNodeInfo * topOfTree() const
+    { return topOfTree_;}
+    /// Number of analyze iterations to do
+    inline void setNumberAnalyzeIterations(int number) {
+        numberAnalyzeIterations_ = number;
+    }
+    inline int numberAnalyzeIterations() const {
+        return numberAnalyzeIterations_;
+    }
+    /** Get scale factor to make penalties match strong.
+        Should/will be computed */
+    inline double penaltyScaleFactor() const {
+        return penaltyScaleFactor_;
+    }
+    /** Set scale factor to make penalties match strong.
+        Should/will be computed */
+    void setPenaltyScaleFactor(double value);
+    /** Problem type as set by user or found by analysis.  This will be extended
+        0 - not known
+        1 - Set partitioning <=
+        2 - Set partitioning ==
+        3 - Set covering
+        4 - all +- 1 or all +1 and odd
+    */
+    void inline setProblemType(int number) {
+        problemType_ = number;
+    }
+    inline int problemType() const {
+        return problemType_;
+    }
+    /// Current depth
+    inline int currentDepth() const {
+        return currentDepth_;
+    }
+
+    /// Set how often to scan global cuts
+    void setHowOftenGlobalScan(int number);
+    /// Get how often to scan global cuts
+    inline int howOftenGlobalScan() const {
+        return howOftenGlobalScan_;
+    }
+    /// Original columns as created by integerPresolve or preprocessing
+    inline int * originalColumns() const {
+        return originalColumns_;
+    }
+    /// Set original columns as created by preprocessing
+    void setOriginalColumns(const int * originalColumns,
+			    int numberGood=COIN_INT_MAX) ;
+    /// Create conflict cut (well - most of)
+    OsiRowCut * conflictCut(const OsiSolverInterface * solver, bool & localCuts);
+
+    /** Set the print frequency.
+
+      Controls the number of nodes evaluated between status prints.
+      If <tt>number <=0</tt> the print frequency is set to 100 nodes for large
+      problems, 1000 for small problems.
+      Print frequency has very slight overhead if small.
+    */
+    inline void setPrintFrequency(int number) {
+        printFrequency_ = number;
+    }
+    /// Get the print frequency
+    inline int printFrequency() const {
+        return printFrequency_;
+    }
+    //@}
+
+    //---------------------------------------------------------------------------
+    ///@name Methods returning info on how the solution process terminated
+    //@{
+    /// Are there a numerical difficulties?
+    bool isAbandoned() const;
+    /// Is optimality proven?
+    bool isProvenOptimal() const;
+    /// Is  infeasiblity proven (or none better than cutoff)?
+    bool isProvenInfeasible() const;
+    /// Was continuous solution unbounded
+    bool isContinuousUnbounded() const;
+    /// Was continuous solution unbounded
+    bool isProvenDualInfeasible() const;
+    /// Node limit reached?
+    bool isNodeLimitReached() const;
+    /// Time limit reached?
+    bool isSecondsLimitReached() const;
+    /// Solution limit reached?
+    bool isSolutionLimitReached() const;
+    /// Get how many iterations it took to solve the problem.
+    inline int getIterationCount() const {
+        return numberIterations_;
+    }
+    /// Increment how many iterations it took to solve the problem.
+    inline void incrementIterationCount(int value) {
+        numberIterations_ += value;
+    }
+    /// Get how many Nodes it took to solve the problem (including those in complete fathoming B&B inside CLP).
+    inline int getNodeCount() const {
+        return numberNodes_;
+    }
+    /// Increment how many nodes it took to solve the problem.
+    inline void incrementNodeCount(int value) {
+        numberNodes_ += value;
+    }
+    /// Get how many Nodes were enumerated in complete fathoming B&B inside CLP
+    inline int getExtraNodeCount() const {
+       return numberExtraNodes_;
+    }
+    /** Final status of problem
+        Some of these can be found out by is...... functions
+        -1 before branchAndBound
+        0 finished - check isProvenOptimal or isProvenInfeasible to see if solution found
+        (or check value of best solution)
+        1 stopped - on maxnodes, maxsols, maxtime
+        2 difficulties so run was abandoned
+        (5 event user programmed event occurred)
+    */
+    inline int status() const {
+        return status_;
+    }
+    inline void setProblemStatus(int value) {
+        status_ = value;
+    }
+    /** Secondary status of problem
+        -1 unset (status_ will also be -1)
+        0 search completed with solution
+        1 linear relaxation not feasible (or worse than cutoff)
+        2 stopped on gap
+        3 stopped on nodes
+        4 stopped on time
+        5 stopped on user event
+        6 stopped on solutions
+        7 linear relaxation unbounded
+        8 stopped on iteration limit
+    */
+    inline int secondaryStatus() const {
+        return secondaryStatus_;
+    }
+    inline void setSecondaryStatus(int value) {
+        secondaryStatus_ = value;
+    }
+    /// Are there numerical difficulties (for initialSolve) ?
+    bool isInitialSolveAbandoned() const ;
+    /// Is optimality proven (for initialSolve) ?
+    bool isInitialSolveProvenOptimal() const ;
+    /// Is primal infeasiblity proven (for initialSolve) ?
+    bool isInitialSolveProvenPrimalInfeasible() const ;
+    /// Is dual infeasiblity proven (for initialSolve) ?
+    bool isInitialSolveProvenDualInfeasible() const ;
+
+    //@}
+
+    //---------------------------------------------------------------------------
+    /**@name Problem information methods
+
+       These methods call the solver's query routines to return
+       information about the problem referred to by the current object.
+       Querying a problem that has no data associated with it result in
+       zeros for the number of rows and columns, and NULL pointers from
+       the methods that return vectors.
+
+       Const pointers returned from any data-query method are valid as
+       long as the data is unchanged and the solver is not called.
+    */
+    //@{
+    /// Number of rows in continuous (root) problem.
+    inline int numberRowsAtContinuous() const {
+        return numberRowsAtContinuous_;
+    }
+
+    /// Get number of columns
+    inline int getNumCols() const {
+        return solver_->getNumCols();
+    }
+
+    /// Get number of rows
+    inline int getNumRows() const {
+        return solver_->getNumRows();
+    }
+
+    /// Get number of nonzero elements
+    inline CoinBigIndex getNumElements() const {
+        return solver_->getNumElements();
+    }
+
+    /// Number of integers in problem
+    inline int numberIntegers() const {
+        return numberIntegers_;
+    }
+    // Integer variables
+    inline const int * integerVariable() const {
+        return integerVariable_;
+    }
+    /// Whether or not integer
+    inline char integerType(int i) const {
+        assert (integerInfo_);
+        assert (integerInfo_[i] == 0 || integerInfo_[i] == 1);
+        return integerInfo_[i];
+    }
+    /// Whether or not integer
+    inline const char * integerType() const {
+        return integerInfo_;
+    }
+
+    /// Get pointer to array[getNumCols()] of column lower bounds
+    inline const double * getColLower() const {
+        return solver_->getColLower();
+    }
+
+    /// Get pointer to array[getNumCols()] of column upper bounds
+    inline const double * getColUpper() const {
+        return solver_->getColUpper();
+    }
+
+    /** Get pointer to array[getNumRows()] of row constraint senses.
+        <ul>
+        <li>'L': <= constraint
+        <li>'E': =  constraint
+        <li>'G': >= constraint
+        <li>'R': ranged constraint
+        <li>'N': free constraint
+        </ul>
+    */
+    inline const char * getRowSense() const {
+        return solver_->getRowSense();
+    }
+
+    /** Get pointer to array[getNumRows()] of rows right-hand sides
+        <ul>
+        <li> if rowsense()[i] == 'L' then rhs()[i] == rowupper()[i]
+        <li> if rowsense()[i] == 'G' then rhs()[i] == rowlower()[i]
+        <li> if rowsense()[i] == 'R' then rhs()[i] == rowupper()[i]
+        <li> if rowsense()[i] == 'N' then rhs()[i] == 0.0
+        </ul>
+    */
+    inline const double * getRightHandSide() const {
+        return solver_->getRightHandSide();
+    }
+
+    /** Get pointer to array[getNumRows()] of row ranges.
+        <ul>
+        <li> if rowsense()[i] == 'R' then
+        rowrange()[i] == rowupper()[i] - rowlower()[i]
+        <li> if rowsense()[i] != 'R' then
+        rowrange()[i] is 0.0
+        </ul>
+    */
+    inline const double * getRowRange() const {
+        return solver_->getRowRange();
+    }
+
+    /// Get pointer to array[getNumRows()] of row lower bounds
+    inline const double * getRowLower() const {
+        return solver_->getRowLower();
+    }
+
+    /// Get pointer to array[getNumRows()] of row upper bounds
+    inline const double * getRowUpper() const {
+        return solver_->getRowUpper();
+    }
+
+    /// Get pointer to array[getNumCols()] of objective function coefficients
+    inline const double * getObjCoefficients() const {
+        return solver_->getObjCoefficients();
+    }
+
+    /// Get objective function sense (1 for min (default), -1 for max)
+    inline double getObjSense() const {
+        //assert (dblParam_[CbcOptimizationDirection]== solver_->getObjSense());
+        return dblParam_[CbcOptimizationDirection];
+    }
+
+    /// Return true if variable is continuous
+    inline bool isContinuous(int colIndex) const {
+        return solver_->isContinuous(colIndex);
+    }
+
+    /// Return true if variable is binary
+    inline bool isBinary(int colIndex) const {
+        return solver_->isBinary(colIndex);
+    }
+
+    /** Return true if column is integer.
+        Note: This function returns true if the the column
+        is binary or a general integer.
+    */
+    inline bool isInteger(int colIndex) const {
+        return solver_->isInteger(colIndex);
+    }
+
+    /// Return true if variable is general integer
+    inline bool isIntegerNonBinary(int colIndex) const {
+        return solver_->isIntegerNonBinary(colIndex);
+    }
+
+    /// Return true if variable is binary and not fixed at either bound
+    inline bool isFreeBinary(int colIndex) const {
+        return solver_->isFreeBinary(colIndex) ;
+    }
+
+    /// Get pointer to row-wise copy of matrix
+    inline const CoinPackedMatrix * getMatrixByRow() const {
+        return solver_->getMatrixByRow();
+    }
+
+    /// Get pointer to column-wise copy of matrix
+    inline const CoinPackedMatrix * getMatrixByCol() const {
+        return solver_->getMatrixByCol();
+    }
+
+    /// Get solver's value for infinity
+    inline double getInfinity() const {
+        return solver_->getInfinity();
+    }
+    /// Get pointer to array[getNumCols()] (for speed) of column lower bounds
+    inline const double * getCbcColLower() const {
+        return cbcColLower_;
+    }
+    /// Get pointer to array[getNumCols()] (for speed) of column upper bounds
+    inline const double * getCbcColUpper() const {
+        return cbcColUpper_;
+    }
+    /// Get pointer to array[getNumRows()] (for speed) of row lower bounds
+    inline const double * getCbcRowLower() const {
+        return cbcRowLower_;
+    }
+    /// Get pointer to array[getNumRows()] (for speed) of row upper bounds
+    inline const double * getCbcRowUpper() const {
+        return cbcRowUpper_;
+    }
+    /// Get pointer to array[getNumCols()] (for speed) of primal solution vector
+    inline const double * getCbcColSolution() const {
+        return cbcColSolution_;
+    }
+    /// Get pointer to array[getNumRows()] (for speed) of dual prices
+    inline const double * getCbcRowPrice() const {
+        return cbcRowPrice_;
+    }
+    /// Get a pointer to array[getNumCols()] (for speed) of reduced costs
+    inline const double * getCbcReducedCost() const {
+        return cbcReducedCost_;
+    }
+    /// Get pointer to array[getNumRows()] (for speed) of row activity levels.
+    inline const double * getCbcRowActivity() const {
+        return cbcRowActivity_;
+    }
+    //@}
+
+
+    /**@name Methods related to querying the solution */
+    //@{
+    /// Holds solution at continuous (after cuts if branchAndBound called)
+    inline double * continuousSolution() const {
+        return continuousSolution_;
+    }
+    /** Array marked whenever a solution is found if non-zero.
+        Code marks if heuristic returns better so heuristic
+        need only mark if it wants to on solutions which
+        are worse than current */
+    inline int * usedInSolution() const {
+        return usedInSolution_;
+    }
+    /// Increases usedInSolution for nonzeros
+    void incrementUsed(const double * solution);
+    /// Record a new incumbent solution and update objectiveValue
+    void setBestSolution(CBC_Message how,
+                         double & objectiveValue, const double *solution,
+                         int fixVariables = 0);
+    /// Just update objectiveValue
+    void setBestObjectiveValue( double objectiveValue);
+    /// Deals with event handler and solution
+    CbcEventHandler::CbcAction dealWithEventHandler(CbcEventHandler::CbcEvent event,
+            double objValue,
+            const double * solution);
+
+    /** Call this to really test if a valid solution can be feasible
+        Solution is number columns in size.
+        If fixVariables true then bounds of continuous solver updated.
+        Returns objective value (worse than cutoff if not feasible)
+        Previously computed objective value is now passed in (in case user does not do solve)
+	virtual so user can override
+    */
+    virtual double checkSolution(double cutoff, double * solution,
+                         int fixVariables, double originalObjValue);
+    /** Test the current solution for feasiblility.
+
+      Scan all objects for indications of infeasibility. This is broken down
+      into simple integer infeasibility (\p numberIntegerInfeasibilities)
+      and all other reports of infeasibility (\p numberObjectInfeasibilities).
+    */
+    bool feasibleSolution(int & numberIntegerInfeasibilities,
+                          int & numberObjectInfeasibilities) const;
+
+    /** Solution to the most recent lp relaxation.
+
+      The solver's solution to the most recent lp relaxation.
+    */
+
+    inline double * currentSolution() const {
+        return currentSolution_;
+    }
+    /** For testing infeasibilities - will point to
+        currentSolution_ or solver-->getColSolution()
+    */
+    inline const double * testSolution() const {
+        return testSolution_;
+    }
+    inline void setTestSolution(const double * solution) {
+        testSolution_ = solution;
+    }
+    /// Make sure region there and optionally copy solution
+    void reserveCurrentSolution(const double * solution = NULL);
+
+    /// Get pointer to array[getNumCols()] of primal solution vector
+    inline const double * getColSolution() const {
+        return solver_->getColSolution();
+    }
+
+    /// Get pointer to array[getNumRows()] of dual prices
+    inline const double * getRowPrice() const {
+        return solver_->getRowPrice();
+    }
+
+    /// Get a pointer to array[getNumCols()] of reduced costs
+    inline const double * getReducedCost() const {
+        return solver_->getReducedCost();
+    }
+
+    /// Get pointer to array[getNumRows()] of row activity levels.
+    inline const double * getRowActivity() const {
+        return solver_->getRowActivity();
+    }
+
+    /// Get current objective function value
+    inline double getCurrentObjValue() const {
+        return dblParam_[CbcCurrentObjectiveValue];
+    }
+    /// Get current minimization objective function value
+    inline double getCurrentMinimizationObjValue() const {
+        return dblParam_[CbcCurrentMinimizationObjectiveValue];
+    }
+
+    /// Get best objective function value as minimization
+    inline double getMinimizationObjValue() const {
+        return bestObjective_;
+    }
+    /// Set best objective function value as minimization
+    inline void setMinimizationObjValue(double value) {
+        bestObjective_ = value;
+    }
+
+    /// Get best objective function value
+    inline double getObjValue() const {
+        return bestObjective_ * solver_->getObjSense() ;
+    }
+    /** Get best possible objective function value.
+        This is better of best possible left on tree
+        and best solution found.
+        If called from within branch and cut may be optimistic.
+    */
+    double getBestPossibleObjValue() const;
+    /// Set best objective function value
+    inline void setObjValue(double value) {
+        bestObjective_ = value * solver_->getObjSense() ;
+    }
+    /// Get solver objective function value (as minimization)
+    inline double getSolverObjValue() const {
+        return solver_->getObjValue() * solver_->getObjSense() ;
+    }
+
+    /** The best solution to the integer programming problem.
+
+      The best solution to the integer programming problem found during
+      the search. If no solution is found, the method returns null.
+    */
+
+    inline double * bestSolution() const {
+        return bestSolution_;
+    }
+    /** User callable setBestSolution.
+        If check false does not check valid
+        If true then sees if feasible and warns if objective value
+        worse than given (so just set to COIN_DBL_MAX if you don't care).
+        If check true then does not save solution if not feasible
+    */
+    void setBestSolution(const double * solution, int numberColumns,
+                         double objectiveValue, bool check = false);
+
+    /// Get number of solutions
+    inline int getSolutionCount() const {
+        return numberSolutions_;
+    }
+
+    /// Set number of solutions (so heuristics will be different)
+    inline void setSolutionCount(int value) {
+        numberSolutions_ = value;
+    }
+    /// Number of saved solutions (including best)
+    int numberSavedSolutions() const;
+    /// Maximum number of extra saved solutions
+    inline int maximumSavedSolutions() const {
+        return maximumSavedSolutions_;
+    }
+    /// Set maximum number of extra saved solutions
+    void setMaximumSavedSolutions(int value);
+    /// Return a saved solution (0==best) - NULL if off end
+    const double * savedSolution(int which) const;
+    /// Return a saved solution objective (0==best) - COIN_DBL_MAX if off end
+    double savedSolutionObjective(int which) const;
+    /// Delete a saved solution and move others up
+    void deleteSavedSolution(int which);
+
+    /** Current phase (so heuristics etc etc can find out).
+        0 - initial solve
+        1 - solve with cuts at root
+        2 - solve with cuts
+        3 - other e.g. strong branching
+        4 - trying to validate a solution
+        5 - at end of search
+    */
+    inline int phase() const {
+        return phase_;
+    }
+
+    /// Get number of heuristic solutions
+    inline int getNumberHeuristicSolutions() const {
+        return numberHeuristicSolutions_;
+    }
+    /// Set number of heuristic solutions
+    inline void setNumberHeuristicSolutions(int value) {
+        numberHeuristicSolutions_ = value;
+    }
+
+    /// Set objective function sense (1 for min (default), -1 for max,)
+    inline void setObjSense(double s) {
+        dblParam_[CbcOptimizationDirection] = s;
+        solver_->setObjSense(s);
+    }
+
+    /// Value of objective at continuous
+    inline double getContinuousObjective() const {
+        return originalContinuousObjective_;
+    }
+    inline void setContinuousObjective(double value) {
+        originalContinuousObjective_ = value;
+    }
+    /// Number of infeasibilities at continuous
+    inline int getContinuousInfeasibilities() const {
+        return continuousInfeasibilities_;
+    }
+    inline void setContinuousInfeasibilities(int value) {
+        continuousInfeasibilities_ = value;
+    }
+    /// Value of objective after root node cuts added
+    inline double rootObjectiveAfterCuts() const {
+        return continuousObjective_;
+    }
+    /// Sum of Changes to objective by first solve
+    inline double sumChangeObjective() const {
+        return sumChangeObjective1_;
+    }
+    /** Number of times global cuts violated.  When global cut pool then this
+        should be kept for each cut and type of cut */
+    inline int numberGlobalViolations() const {
+        return numberGlobalViolations_;
+    }
+    inline void clearNumberGlobalViolations() {
+        numberGlobalViolations_ = 0;
+    }
+    /// Whether to force a resolve after takeOffCuts
+    inline bool resolveAfterTakeOffCuts() const {
+        return resolveAfterTakeOffCuts_;
+    }
+    inline void setResolveAfterTakeOffCuts(bool yesNo) {
+        resolveAfterTakeOffCuts_ = yesNo;
+    }
+    /// Maximum number of rows
+    inline int maximumRows() const {
+        return maximumRows_;
+    }
+    /// Work basis for temporary use
+    inline CoinWarmStartBasis & workingBasis() {
+        return workingBasis_;
+    }
+    /// Get number of "iterations" to stop after
+    inline int getStopNumberIterations() const {
+        return stopNumberIterations_;
+    }
+    /// Set number of "iterations" to stop after
+    inline void setStopNumberIterations(int value) {
+        stopNumberIterations_ = value;
+    }
+    /// A pointer to model from CbcHeuristic
+    inline CbcModel * heuristicModel() const
+    { return heuristicModel_;}
+    /// Set a pointer to model from CbcHeuristic
+    inline void setHeuristicModel(CbcModel * model)
+    { heuristicModel_ = model;}
+    //@}
+
+    /** \name Node selection */
+    //@{
+    // Comparison functions (which may be overridden by inheritance)
+    inline CbcCompareBase * nodeComparison() const {
+        return nodeCompare_;
+    }
+    void setNodeComparison(CbcCompareBase * compare);
+    void setNodeComparison(CbcCompareBase & compare);
+    //@}
+
+    /** \name Problem feasibility checking */
+    //@{
+    // Feasibility functions (which may be overridden by inheritance)
+    inline CbcFeasibilityBase * problemFeasibility() const {
+        return problemFeasibility_;
+    }
+    void setProblemFeasibility(CbcFeasibilityBase * feasibility);
+    void setProblemFeasibility(CbcFeasibilityBase & feasibility);
+    //@}
+
+    /** \name Tree methods and subtree methods */
+    //@{
+    /// Tree method e.g. heap (which may be overridden by inheritance)
+    inline CbcTree * tree() const {
+        return tree_;
+    }
+    /// For modifying tree handling (original is cloned)
+    void passInTreeHandler(CbcTree & tree);
+    /** For passing in an CbcModel to do a sub Tree (with derived tree handlers).
+        Passed in model must exist for duration of branch and bound
+    */
+    void passInSubTreeModel(CbcModel & model);
+    /** For retrieving a copy of subtree model with given OsiSolver.
+        If no subtree model will use self (up to user to reset cutoff etc).
+        If solver NULL uses current
+    */
+    CbcModel * subTreeModel(OsiSolverInterface * solver = NULL) const;
+    /// Returns number of times any subtree stopped on nodes, time etc
+    inline int numberStoppedSubTrees() const {
+        return numberStoppedSubTrees_;
+    }
+    /// Says a sub tree was stopped
+    inline void incrementSubTreeStopped() {
+        numberStoppedSubTrees_++;
+    }
+    /** Whether to automatically do presolve before branch and bound (subTrees).
+        0 - no
+        1 - ordinary presolve
+        2 - integer presolve (dodgy)
+    */
+    inline int typePresolve() const {
+        return presolve_;
+    }
+    inline void setTypePresolve(int value) {
+        presolve_ = value;
+    }
+
+    //@}
+
+    /** \name Branching Decisions
+
+      See the CbcBranchDecision class for additional information.
+    */
+    //@{
+
+    /// Get the current branching decision method.
+    inline CbcBranchDecision * branchingMethod() const {
+        return branchingMethod_;
+    }
+    /// Set the branching decision method.
+    inline void setBranchingMethod(CbcBranchDecision * method) {
+        delete branchingMethod_;
+        branchingMethod_ = method->clone();
+    }
+    /** Set the branching method
+
+      \overload
+    */
+    inline void setBranchingMethod(CbcBranchDecision & method) {
+        delete branchingMethod_;
+        branchingMethod_ = method.clone();
+    }
+    /// Get the current cut modifier method
+    inline CbcCutModifier * cutModifier() const {
+        return cutModifier_;
+    }
+    /// Set the cut modifier method
+    void setCutModifier(CbcCutModifier * modifier);
+    /** Set the cut modifier method
+
+      \overload
+    */
+    void setCutModifier(CbcCutModifier & modifier);
+    //@}
+
+    /** \name Row (constraint) and Column (variable) cut generation */
+    //@{
+
+    /** State of search
+        0 - no solution
+        1 - only heuristic solutions
+        2 - branched to a solution
+        3 - no solution but many nodes
+    */
+    inline int stateOfSearch() const {
+        return stateOfSearch_;
+    }
+    inline void setStateOfSearch(int state) {
+        stateOfSearch_ = state;
+    }
+    /// Strategy worked out - mainly at root node for use by CbcNode
+    inline int searchStrategy() const {
+        return searchStrategy_;
+    }
+    /// Set strategy worked out - mainly at root node for use by CbcNode
+    inline void setSearchStrategy(int value) {
+        searchStrategy_ = value;
+    }
+    /// Stong branching strategy
+    inline int strongStrategy() const {
+        return strongStrategy_;
+    }
+    /// Set strong branching strategy
+    inline void setStrongStrategy(int value) {
+        strongStrategy_ = value;
+    }
+
+    /// Get the number of cut generators
+    inline int numberCutGenerators() const {
+        return numberCutGenerators_;
+    }
+    /// Get the list of cut generators
+    inline CbcCutGenerator ** cutGenerators() const {
+        return generator_;
+    }
+    ///Get the specified cut generator
+    inline CbcCutGenerator * cutGenerator(int i) const {
+        return generator_[i];
+    }
+    ///Get the specified cut generator before any changes
+    inline CbcCutGenerator * virginCutGenerator(int i) const {
+        return virginGenerator_[i];
+    }
+    /** Add one generator - up to user to delete generators.
+        howoften affects how generator is used. 0 or 1 means always,
+        >1 means every that number of nodes.  Negative values have same
+        meaning as positive but they may be switched off (-> -100) by code if
+        not many cuts generated at continuous.  -99 is just done at root.
+        Name is just for printout.
+        If depth >0 overrides how often generator is called (if howOften==-1 or >0).
+    */
+    void addCutGenerator(CglCutGenerator * generator,
+                         int howOften = 1, const char * name = NULL,
+                         bool normal = true, bool atSolution = false,
+                         bool infeasible = false, int howOftenInSub = -100,
+                         int whatDepth = -1, int whatDepthInSub = -1);
+//@}
+    /** \name Strategy and sub models
+
+      See the CbcStrategy class for additional information.
+    */
+    //@{
+
+    /// Get the current strategy
+    inline CbcStrategy * strategy() const {
+        return strategy_;
+    }
+    /// Set the strategy. Clones
+    void setStrategy(CbcStrategy & strategy);
+    /// Set the strategy. assigns
+    inline void setStrategy(CbcStrategy * strategy) {
+        strategy_ = strategy;
+    }
+    /// Get the current parent model
+    inline CbcModel * parentModel() const {
+        return parentModel_;
+    }
+    /// Set the parent model
+    inline void setParentModel(CbcModel & parentModel) {
+        parentModel_ = &parentModel;
+    }
+    //@}
+
+
+    /** \name Heuristics and priorities */
+    //@{
+    /*! \brief Add one heuristic - up to user to delete
+
+      The name is just used for print messages.
+    */
+    void addHeuristic(CbcHeuristic * generator, const char *name = NULL,
+                      int before = -1);
+    ///Get the specified heuristic
+    inline CbcHeuristic * heuristic(int i) const {
+        return heuristic_[i];
+    }
+    /// Get the number of heuristics
+    inline int numberHeuristics() const {
+        return numberHeuristics_;
+    }
+    /// Set the number of heuristics
+    inline void setNumberHeuristics(int value) {
+        numberHeuristics_ = value;
+    }
+    /// Pointer to heuristic solver which found last solution (or NULL)
+    inline CbcHeuristic * lastHeuristic() const {
+        return lastHeuristic_;
+    }
+    /// set last heuristic which found a solution
+    inline void setLastHeuristic(CbcHeuristic * last) {
+        lastHeuristic_ = last;
+    }
+
+    /** Pass in branching priorities.
+
+        If ifClique then priorities are on cliques otherwise priorities are
+        on integer variables.
+        Other type (if exists set to default)
+        1 is highest priority. (well actually -INT_MAX is but that's ugly)
+        If hotstart > 0 then branches are created to force
+        the variable to the value given by best solution.  This enables a
+        sort of hot start.  The node choice should be greatest depth
+        and hotstart should normally be switched off after a solution.
+
+        If ifNotSimpleIntegers true then appended to normal integers
+
+        This is now deprecated except for simple usage.  If user
+        creates Cbcobjects then set priority in them
+
+        \internal Added for Kurt Spielberg.
+    */
+    void passInPriorities(const int * priorities, bool ifNotSimpleIntegers);
+
+    /// Returns priority level for an object (or 1000 if no priorities exist)
+    inline int priority(int sequence) const {
+        return object_[sequence]->priority();
+    }
+
+    /*! \brief Set an event handler
+
+      A clone of the handler passed as a parameter is stored in CbcModel.
+    */
+    void passInEventHandler(const CbcEventHandler *eventHandler) ;
+
+    /*! \brief Retrieve a pointer to the event handler */
+    inline CbcEventHandler* getEventHandler() const {
+        return (eventHandler_) ;
+    }
+
+    //@}
+
+    /**@name Setting/Accessing application data */
+    //@{
+    /** Set application data.
+
+    This is a pointer that the application can store into and
+    retrieve from the solver interface.
+    This field is available for the application to optionally
+    define and use.
+    */
+    void setApplicationData (void * appData);
+
+    /// Get application data
+    void * getApplicationData() const;
+    /**
+        For advanced applications you may wish to modify the behavior of Cbc
+        e.g. if the solver is a NLP solver then you may not have an exact
+        optimum solution at each step.  Information could be built into
+        OsiSolverInterface but this is an alternative so that that interface
+        does not have to be changed.  If something similar is useful to
+        enough solvers then it could be migrated
+        You can also pass in by using solver->setAuxiliaryInfo.
+        You should do that if solver is odd - if solver is normal simplex
+        then use this.
+        NOTE - characteristics are not cloned
+    */
+    void passInSolverCharacteristics(OsiBabSolver * solverCharacteristics);
+    /// Get solver characteristics
+    inline const OsiBabSolver * solverCharacteristics() const {
+        return solverCharacteristics_;
+    }
+    //@}
+
+    //---------------------------------------------------------------------------
+
+    /**@name Message handling etc */
+    //@{
+    /// Pass in Message handler (not deleted at end)
+    void passInMessageHandler(CoinMessageHandler * handler);
+    /// Set language
+    void newLanguage(CoinMessages::Language language);
+    inline void setLanguage(CoinMessages::Language language) {
+        newLanguage(language);
+    }
+    /// Return handler
+    inline CoinMessageHandler * messageHandler() const {
+        return handler_;
+    }
+    /// Return messages
+    inline CoinMessages & messages() {
+        return messages_;
+    }
+    /// Return pointer to messages
+    inline CoinMessages * messagesPointer() {
+        return &messages_;
+    }
+    /// Set log level
+    void setLogLevel(int value);
+    /// Get log level
+    inline int logLevel() const {
+        return handler_->logLevel();
+    }
+    /** Set flag to say if handler_ is the default handler.
+
+      The default handler is deleted when the model is deleted. Other
+      handlers (supplied by the client) will not be deleted.
+    */
+    inline void setDefaultHandler(bool yesNo) {
+        defaultHandler_ = yesNo;
+    }
+    /// Check default handler
+    inline bool defaultHandler() const {
+        return defaultHandler_;
+    }
+    //@}
+    //---------------------------------------------------------------------------
+    ///@name Specialized
+    //@{
+
+    /**
+        Set special options
+        0 bit (1) - check if cuts valid (if on debugger list)
+        1 bit (2) - use current basis to check integer solution (rather than all slack)
+        2 bit (4) - don't check integer solution (by solving LP)
+        3 bit (8) - fast analyze
+        4 bit (16) - non-linear model - so no well defined CoinPackedMatrix
+        5 bit (32) - keep names
+        6 bit (64) - try for dominated columns
+        7 bit (128) - SOS type 1 but all declared integer
+        8 bit (256) - Set to say solution just found, unset by doing cuts
+        9 bit (512) - Try reduced model after 100 nodes
+        10 bit (1024) - Switch on some heuristics even if seems unlikely
+        11 bit (2048) - Mark as in small branch and bound
+        12 bit (4096) - Funny cuts so do slow way (in some places)
+        13 bit (8192) - Funny cuts so do slow way (in other places)
+        14 bit (16384) - Use Cplex! for fathoming
+        15 bit (32768) - Try reduced model after 0 nodes
+        16 bit (65536) - Original model had integer bounds
+        17 bit (131072) - Perturbation switched off
+        18 bit (262144) - donor CbcModel
+        19 bit (524288) - recipient CbcModel
+        20 bit (1048576) - waiting for sub model to return
+	22 bit (4194304) - do not initialize random seed in solver (user has)
+	23 bit (8388608) - leave solver_ with cuts
+    */
+    inline void setSpecialOptions(int value) {
+        specialOptions_ = value;
+    }
+    /// Get special options
+    inline int specialOptions() const {
+        return specialOptions_;
+    }
+    /// Set random seed
+    inline void setRandomSeed(int value) {
+        randomSeed_ = value;
+    }
+    /// Get random seed
+    inline int getRandomSeed() const {
+        return randomSeed_;
+    }
+    /// Set multiple root tries
+    inline void setMultipleRootTries(int value) {
+        multipleRootTries_ = value;
+    }
+    /// Get multiple root tries
+    inline int getMultipleRootTries() const {
+        return multipleRootTries_;
+    }
+    /// Tell model to stop on event
+    inline void sayEventHappened()
+    { eventHappened_=true;}
+    /// Says if normal solver i.e. has well defined CoinPackedMatrix
+    inline bool normalSolver() const {
+        return (specialOptions_&16) == 0;
+    }
+    /** Says if model is sitting there waiting for mini branch and bound to finish
+	This is because an event handler may only have access to parent model in
+	mini branch and bound
+    */
+    inline bool waitingForMiniBranchAndBound() const {
+        return (specialOptions_&1048576) != 0;
+    }
+    /** Set more special options
+        at present bottom 6 bits used for shadow price mode
+        1024 for experimental hotstart
+        2048,4096 breaking out of cuts
+        8192 slowly increase minimum drop
+        16384 gomory
+	32768 more heuristics in sub trees
+	65536 no cuts in preprocessing
+        131072 Time limits elapsed
+        18 bit (262144) - Perturb fathom nodes
+        19 bit (524288) - No limit on fathom nodes
+        20 bit (1048576) - Reduce sum of infeasibilities before cuts
+        21 bit (2097152) - Reduce sum of infeasibilities after cuts
+	22 bit (4194304) - Conflict analysis
+	23 bit (8388608) - Conflict analysis - temporary bit
+	24 bit (16777216) - Add cutoff as LP constraint (out)
+	25 bit (33554432) - diving/reordering
+	26 bit (67108864) - load global cuts from file
+	27 bit (134217728) - append binding global cuts to file
+	28 bit (268435456) - idiot branching
+        29 bit (536870912) - don't make fake objective
+    */
+    inline void setMoreSpecialOptions(int value) {
+        moreSpecialOptions_ = value;
+    }
+    /// Get more special options
+    inline int moreSpecialOptions() const {
+        return moreSpecialOptions_;
+    }
+    /// Set cutoff as constraint
+    inline void setCutoffAsConstraint(bool yesNo) {
+      cutoffRowNumber_ = (yesNo) ? -2 : -1;
+    }
+    /// Set time method
+    inline void setUseElapsedTime(bool yesNo) {
+        if (yesNo)
+  	  moreSpecialOptions_ |= 131072;
+	else
+	  moreSpecialOptions_ &= ~131072;
+    }
+    /// Get time method
+    inline bool useElapsedTime() const {
+        return (moreSpecialOptions_&131072)!=0;
+    }
+    /// Get useful temporary pointer
+    inline void * temporaryPointer() const
+    { return temporaryPointer_;}
+    /// Set useful temporary pointer
+    inline void setTemporaryPointer(void * pointer)
+    { temporaryPointer_=pointer;}
+    /// Go to dantzig pivot selection if easy problem (clp only)
+    void goToDantzig(int numberNodes, ClpDualRowPivot *& savePivotMethod);
+    /// Now we may not own objects - just point to solver's objects
+    inline bool ownObjects() const {
+        return ownObjects_;
+    }
+    /// Check original model before it gets messed up
+    void checkModel();
+    //@}
+    //---------------------------------------------------------------------------
+
+    ///@name Constructors and destructors etc
+    //@{
+    /// Default Constructor
+    CbcModel();
+
+    /// Constructor from solver
+    CbcModel(const OsiSolverInterface &);
+
+    /** Assign a solver to the model (model assumes ownership)
+
+      On return, \p solver will be NULL.
+      If deleteSolver then current solver deleted (if model owned)
+
+      \note Parameter settings in the outgoing solver are not inherited by
+        the incoming solver.
+    */
+    void assignSolver(OsiSolverInterface *&solver, bool deleteSolver = true);
+
+    /** \brief Set ownership of solver
+
+      A parameter of false tells CbcModel it does not own the solver and
+      should not delete it. Once you claim ownership of the solver, you're
+      responsible for eventually deleting it. Note that CbcModel clones
+      solvers with abandon.  Unless you have a deep understanding of the
+      workings of CbcModel, the only time you want to claim ownership is when
+      you're about to delete the CbcModel object but want the solver to
+      continue to exist (as, for example, when branchAndBound has finished
+      and you want to hang on to the answer).
+    */
+    inline void setModelOwnsSolver (bool ourSolver) {
+        ownership_ = ourSolver ? (ownership_ | 0x80000000) : (ownership_ & (~0x80000000)) ;
+    }
+
+    /*! \brief Get ownership of solver
+
+      A return value of true means that CbcModel owns the solver and will
+      take responsibility for deleting it when that becomes necessary.
+    */
+    inline bool modelOwnsSolver () {
+        return ((ownership_&0x80000000) != 0) ;
+    }
+
+    /** Copy constructor .
+      If cloneHandler is true then message handler is cloned
+    */
+    CbcModel(const CbcModel & rhs, bool cloneHandler = false);
+
+    /** Clone */
+    virtual CbcModel *clone (bool cloneHandler);
+
+    /// Assignment operator
+    CbcModel & operator=(const CbcModel& rhs);
+
+    /// Destructor
+    virtual ~CbcModel ();
+
+    /// Returns solver - has current state
+    inline OsiSolverInterface * solver() const {
+        return solver_;
+    }
+
+    /// Returns current solver - sets new one
+    inline OsiSolverInterface * swapSolver(OsiSolverInterface * solver) {
+        OsiSolverInterface * returnSolver = solver_;
+        solver_ = solver;
+        return returnSolver;
+    }
+
+    /// Returns solver with continuous state
+    inline OsiSolverInterface * continuousSolver() const {
+        return continuousSolver_;
+    }
+
+    /// Create solver with continuous state
+    inline void createContinuousSolver() {
+        continuousSolver_ = solver_->clone();
+    }
+    /// Clear solver with continuous state
+    inline void clearContinuousSolver() {
+        delete continuousSolver_;
+        continuousSolver_ = NULL;
+    }
+
+    /// A copy of the solver, taken at constructor or by saveReferenceSolver
+    inline OsiSolverInterface * referenceSolver() const {
+        return referenceSolver_;
+    }
+
+    /// Save a copy of the current solver so can be reset to
+    void saveReferenceSolver();
+
+    /** Uses a copy of reference solver to be current solver.
+        Because of possible mismatches all exotic integer information is loat
+        (apart from normal information in OsiSolverInterface)
+        so SOS etc and priorities will have to be redone
+    */
+    void resetToReferenceSolver();
+
+    /// Clears out as much as possible (except solver)
+    void gutsOfDestructor();
+    /** Clears out enough to reset CbcModel as if no branch and bound done
+     */
+    void gutsOfDestructor2();
+    /** Clears out enough to reset CbcModel cutoff etc
+     */
+    void resetModel();
+    /** Most of copy constructor
+        mode - 0 copy but don't delete before
+               1 copy and delete before
+           2 copy and delete before (but use virgin generators)
+    */
+    void gutsOfCopy(const CbcModel & rhs, int mode = 0);
+    /// Move status, nodes etc etc across
+    void moveInfo(const CbcModel & rhs);
+    //@}
+
+    ///@name Multithreading
+    //@{
+    /// Indicates whether Cbc library has been compiled with multithreading support
+    static bool haveMultiThreadSupport();
+    /// Get pointer to masterthread
+    CbcThread * masterThread() const {
+        return masterThread_;
+    }
+    /// Get pointer to walkback
+    CbcNodeInfo ** walkback() const {
+        return walkback_;
+    }
+    /// Get number of threads
+    inline int getNumberThreads() const {
+        return numberThreads_;
+    }
+    /// Set number of threads
+    inline void setNumberThreads(int value) {
+        numberThreads_ = value;
+    }
+    /// Get thread mode
+    inline int getThreadMode() const {
+        return threadMode_;
+    }
+    /** Set thread mode
+        always use numberThreads for branching
+        1 set then deterministic
+        2 set then use numberThreads for root cuts
+        4 set then use numberThreads in root mini branch and bound
+        8 set and numberThreads - do heuristics numberThreads at a time
+        8 set and numberThreads==0 do all heuristics at once
+        default is 0
+    */
+    inline void setThreadMode(int value) {
+        threadMode_ = value;
+    }
+    /** Return
+        -2 if deterministic threaded and main thread
+        -1 if deterministic threaded and serial thread
+        0 if serial
+        1 if opportunistic threaded
+    */
+    inline int parallelMode() const {
+        if (!numberThreads_) {
+            if ((threadMode_&1) == 0)
+                return 0;
+            else
+                return -1;
+            return 0;
+        } else {
+            if ((threadMode_&1) == 0)
+                return 1;
+            else
+                return -2;
+        }
+    }
+    /// From here to end of section - code in CbcThread.cpp until class changed
+    /// Returns true if locked
+    bool isLocked() const;
+#ifdef CBC_THREAD
+    /**
+       Locks a thread if parallel so that stuff like cut pool
+       can be updated and/or used.
+    */
+    void lockThread();
+    /**
+       Unlocks a thread if parallel to say cut pool stuff not needed
+    */
+    void unlockThread();
+#else
+    inline void lockThread() {}
+    inline void unlockThread() {}
+#endif
+    /** Set information in a child
+        -3 pass pointer to child thread info
+        -2 just stop
+        -1 delete simple child stuff
+        0 delete opportunistic child stuff
+        1 delete deterministic child stuff
+    */
+    void setInfoInChild(int type, CbcThread * info);
+    /** Move/copy information from one model to another
+        -1 - initialization
+        0 - from base model
+        1 - to base model (and reset)
+        2 - add in final statistics etc (and reset so can do clean destruction)
+    */
+    void moveToModel(CbcModel * baseModel, int mode);
+    /// Split up nodes
+    int splitModel(int numberModels, CbcModel ** model,
+                   int numberNodes);
+    /// Start threads
+    void startSplitModel(int numberIterations);
+    /// Merge models
+    void mergeModels(int numberModel, CbcModel ** model,
+                     int numberNodes);
+    //@}
+
+    ///@name semi-private i.e. users should not use
+    //@{
+    /// Get how many Nodes it took to solve the problem.
+    int getNodeCount2() const {
+        return numberNodes2_;
+    }
+    /// Set pointers for speed
+    void setPointers(const OsiSolverInterface * solver);
+    /** Perform reduced cost fixing
+
+      Fixes integer variables at their current value based on reduced cost
+      penalties.  Returns number fixed
+    */
+    int reducedCostFix() ;
+    /** Makes all handlers same.  If makeDefault 1 then makes top level
+        default and rest point to that.  If 2 then each is copy
+    */
+    void synchronizeHandlers(int makeDefault);
+    /// Save a solution to saved list
+    void saveExtraSolution(const double * solution, double objectiveValue);
+    /// Save a solution to best and move current to saved
+    void saveBestSolution(const double * solution, double objectiveValue);
+    /// Delete best and saved solutions
+    void deleteSolutions();
+    /// Encapsulates solver resolve
+    int resolve(OsiSolverInterface * solver);
+#ifdef CLP_RESOLVE
+    /// Special purpose resolve
+    int resolveClp(OsiClpSolverInterface * solver, int type);
+#endif
+
+    /** Encapsulates choosing a variable -
+        anyAction -2, infeasible (-1 round again), 0 done
+    */
+    int chooseBranch(CbcNode * & newNode, int numberPassesLeft,
+                     CbcNode * oldNode, OsiCuts & cuts,
+                     bool & resolved, CoinWarmStartBasis *lastws,
+                     const double * lowerBefore, const double * upperBefore,
+                     OsiSolverBranch * & branches);
+    int chooseBranch(CbcNode * newNode, int numberPassesLeft, bool & resolved);
+
+    /** Return an empty basis object of the specified size
+
+      A useful utility when constructing a basis for a subproblem from scratch.
+      The object returned will be of the requested capacity and appropriate for
+      the solver attached to the model.
+    */
+    CoinWarmStartBasis *getEmptyBasis(int ns = 0, int na = 0) const ;
+
+    /** Remove inactive cuts from the model
+
+      An OsiSolverInterface is expected to maintain a valid basis, but not a
+      valid solution, when loose cuts are deleted. Restoring a valid solution
+      requires calling the solver to reoptimise. If it's certain the solution
+      will not be required, set allowResolve to false to suppress
+      reoptimisation.
+      If saveCuts then slack cuts will be saved
+      On input current cuts are cuts and newCuts
+      on exit current cuts will be correct.  Returns number dropped
+    */
+    int takeOffCuts(OsiCuts &cuts,
+                    bool allowResolve, OsiCuts * saveCuts,
+                    int numberNewCuts = 0, const OsiRowCut ** newCuts = NULL) ;
+
+    /** Determine and install the active cuts that need to be added for
+      the current subproblem
+
+      The whole truth is a bit more complicated. The first action is a call to
+      addCuts1(). addCuts() then sorts through the list, installs the tight
+      cuts in the model, and does bookkeeping (adjusts reference counts).
+      The basis returned from addCuts1() is adjusted accordingly.
+
+      If it turns out that the node should really be fathomed by bound,
+      addCuts() simply treats all the cuts as loose as it does the bookkeeping.
+
+      canFix true if extra information being passed
+    */
+    int addCuts(CbcNode * node, CoinWarmStartBasis *&lastws, bool canFix);
+
+    /** Traverse the tree from node to root and prep the model
+
+      addCuts1() begins the job of prepping the model to match the current
+      subproblem. The model is stripped of all cuts, and the search tree is
+      traversed from node to root to determine the changes required. Appropriate
+      bounds changes are installed, a list of cuts is collected but not
+      installed, and an appropriate basis (minus the cuts, but big enough to
+      accommodate them) is constructed.
+
+      Returns true if new problem similar to old
+
+      \todo addCuts1() is called in contexts where it's known in advance that
+        all that's desired is to determine a list of cuts and do the
+        bookkeeping (adjust the reference counts). The work of installing
+        bounds and building a basis goes to waste.
+    */
+    bool addCuts1(CbcNode * node, CoinWarmStartBasis *&lastws);
+    /** Returns bounds just before where - initially original bounds.
+        Also sets downstream nodes (lower if force 1, upper if 2)
+    */
+    void previousBounds (CbcNode * node, CbcNodeInfo * where, int iColumn,
+                         double & lower, double & upper, int force);
+    /** Set objective value in a node.  This is separated out so that
+       odd solvers can use.  It may look at extra information in
+       solverCharacteriscs_ and will also use bound from parent node
+    */
+    void setObjectiveValue(CbcNode * thisNode, const CbcNode * parentNode) const;
+
+    /** If numberBeforeTrust >0 then we are going to use CbcBranchDynamic.
+        Scan and convert CbcSimpleInteger objects
+    */
+    void convertToDynamic();
+    /// Set numberBeforeTrust in all objects
+    void synchronizeNumberBeforeTrust(int type = 0);
+    /// Zap integer information in problem (may leave object info)
+    void zapIntegerInformation(bool leaveObjects = true);
+    /// Use cliques for pseudocost information - return nonzero if infeasible
+    int cliquePseudoCosts(int doStatistics);
+    /// Fill in useful estimates
+    void pseudoShadow(int type);
+    /** Return pseudo costs
+        If not all integers or not pseudo costs - returns all zero
+        Length of arrays are numberIntegers() and entries
+        correspond to integerVariable()[i]
+        User must allocate arrays before call
+    */
+    void fillPseudoCosts(double * downCosts, double * upCosts,
+                         int * priority = NULL,
+                         int * numberDown = NULL, int * numberUp = NULL,
+                         int * numberDownInfeasible = NULL,
+                         int * numberUpInfeasible = NULL) const;
+    /** Do heuristics at root.
+        0 - don't delete
+        1 - delete
+        2 - just delete - don't even use
+    */
+    void doHeuristicsAtRoot(int deleteHeuristicsAfterwards = 0);
+    /// Adjust heuristics based on model
+    void adjustHeuristics();
+    /// Get the hotstart solution
+    inline const double * hotstartSolution() const {
+        return hotstartSolution_;
+    }
+    /// Get the hotstart priorities
+    inline const int * hotstartPriorities() const {
+        return hotstartPriorities_;
+    }
+
+    /// Return the list of cuts initially collected for this subproblem
+    inline CbcCountRowCut ** addedCuts() const {
+        return addedCuts_;
+    }
+    /// Number of entries in the list returned by #addedCuts()
+    inline int currentNumberCuts() const {
+        return currentNumberCuts_;
+    }
+    /// Global cuts
+    inline CbcRowCuts * globalCuts() {
+        return &globalCuts_;
+    }
+    /// Copy and set a pointer to a row cut which will be added instead of normal branching.
+    void setNextRowCut(const OsiRowCut & cut);
+    /// Get a pointer to current node (be careful)
+    inline CbcNode * currentNode() const {
+        return currentNode_;
+    }
+    /// Get a pointer to probing info
+    inline CglTreeProbingInfo * probingInfo() const {
+        return probingInfo_;
+    }
+    /// Thread specific random number generator
+    inline CoinThreadRandom * randomNumberGenerator() {
+        return &randomNumberGenerator_;
+    }
+    /// Set the number of iterations done in strong branching.
+    inline void setNumberStrongIterations(int number) {
+        numberStrongIterations_ = number;
+    }
+    /// Get the number of iterations done in strong branching.
+    inline int numberStrongIterations() const {
+        return numberStrongIterations_;
+    }
+    /// Get maximum number of iterations (designed to be used in heuristics)
+    inline int maximumNumberIterations() const {
+        return maximumNumberIterations_;
+    }
+    /// Set maximum number of iterations (designed to be used in heuristics)
+    inline void setMaximumNumberIterations(int value) {
+        maximumNumberIterations_ = value;
+    }
+    /// Set depth for fast nodes
+    inline void setFastNodeDepth(int value) {
+        fastNodeDepth_ = value;
+    }
+    /// Get depth for fast nodes
+    inline int fastNodeDepth() const {
+        return fastNodeDepth_;
+    }
+    /// Get anything with priority >= this can be treated as continuous
+    inline int continuousPriority() const {
+        return continuousPriority_;
+    }
+    /// Set anything with priority >= this can be treated as continuous
+    inline void setContinuousPriority(int value) {
+        continuousPriority_ = value;
+    }
+    inline void incrementExtra(int nodes, int iterations) {
+        numberExtraNodes_ += nodes;
+        numberExtraIterations_ += iterations;
+    }
+    /// Number of extra iterations
+    inline int numberExtraIterations() const {
+        return numberExtraIterations_;
+    }
+    /// Increment strong info
+    void incrementStrongInfo(int numberTimes, int numberIterations,
+                             int numberFixed, bool ifInfeasible);
+    /// Return strong info
+    inline const int * strongInfo() const {
+        return strongInfo_;
+    }
+
+    /// Return mutable strong info
+    inline int * mutableStrongInfo() {
+        return strongInfo_;
+    }
+    /// Get stored row cuts for donor/recipient CbcModel
+    CglStored * storedRowCuts() const {
+        return storedRowCuts_;
+    }
+    /// Set stored row cuts for donor/recipient CbcModel
+    void setStoredRowCuts(CglStored * cuts) {
+        storedRowCuts_ = cuts;
+    }
+    /// Says whether all dynamic integers
+    inline bool allDynamic () const {
+        return ((ownership_&0x40000000) != 0) ;
+    }
+    /// Create C++ lines to get to current state
+    void generateCpp( FILE * fp, int options);
+    /// Generate an OsiBranchingInformation object
+    OsiBranchingInformation usefulInformation() const;
+    /** Warm start object produced by heuristic or strong branching
+
+        If get a valid integer solution outside branch and bound then it can take
+        a reasonable time to solve LP which produces clean solution.  If this object has
+        any size then it will be used in solve.
+    */
+    inline void setBestSolutionBasis(const CoinWarmStartBasis & bestSolutionBasis) {
+        bestSolutionBasis_ = bestSolutionBasis;
+    }
+    /// Redo walkback arrays
+    void redoWalkBack();
+    //@}
+
+//---------------------------------------------------------------------------
+
+private:
+    ///@name Private member data
+    //@{
+
+    /// The solver associated with this model.
+    OsiSolverInterface * solver_;
+
+    /** Ownership of objects and other stuff
+
+        0x80000000 model owns solver
+        0x40000000 all variables CbcDynamicPseudoCost
+    */
+    unsigned int ownership_ ;
+
+    /// A copy of the solver, taken at the continuous (root) node.
+    OsiSolverInterface * continuousSolver_;
+
+    /// A copy of the solver, taken at constructor or by saveReferenceSolver
+    OsiSolverInterface * referenceSolver_;
+
+    /// Message handler
+    CoinMessageHandler * handler_;
+
+    /** Flag to say if handler_ is the default handler.
+
+      The default handler is deleted when the model is deleted. Other
+      handlers (supplied by the client) will not be deleted.
+    */
+    bool defaultHandler_;
+
+    /// Cbc messages
+    CoinMessages messages_;
+
+    /// Array for integer parameters
+    int intParam_[CbcLastIntParam];
+
+    /// Array for double parameters
+    double dblParam_[CbcLastDblParam];
+
+    /** Pointer to an empty warm start object
+
+      It turns out to be useful to have this available as a base from
+      which to build custom warm start objects. This is typed as CoinWarmStart
+      rather than CoinWarmStartBasis to allow for the possibility that a
+      client might want to apply a solver that doesn't use a basis-based warm
+      start. See getEmptyBasis for an example of how this field can be used.
+    */
+    mutable CoinWarmStart *emptyWarmStart_ ;
+
+    /// Best objective
+    double bestObjective_;
+    /// Best possible objective
+    double bestPossibleObjective_;
+    /// Sum of Changes to objective by first solve
+    double sumChangeObjective1_;
+    /// Sum of Changes to objective by subsequent solves
+    double sumChangeObjective2_;
+
+    /// Array holding the incumbent (best) solution.
+    double * bestSolution_;
+    /// Arrays holding other solutions.
+    double ** savedSolutions_;
+
+    /** Array holding the current solution.
+
+      This array is used more as a temporary.
+    */
+    double * currentSolution_;
+    /** For testing infeasibilities - will point to
+        currentSolution_ or solver-->getColSolution()
+    */
+    mutable const double * testSolution_;
+    /** Warm start object produced by heuristic or strong branching
+
+        If get a valid integer solution outside branch and bound then it can take
+        a reasonable time to solve LP which produces clean solution.  If this object has
+        any size then it will be used in solve.
+    */
+    CoinWarmStartBasis bestSolutionBasis_ ;
+    /// Global cuts
+    CbcRowCuts globalCuts_;
+    /// Global conflict cuts
+    CbcRowCuts * globalConflictCuts_;
+
+    /// Minimum degradation in objective value to continue cut generation
+    double minimumDrop_;
+    /// Number of solutions
+    int numberSolutions_;
+    /// Number of saved solutions
+    int numberSavedSolutions_;
+    /// Maximum number of saved solutions
+    int maximumSavedSolutions_;
+    /** State of search
+        0 - no solution
+        1 - only heuristic solutions
+        2 - branched to a solution
+        3 - no solution but many nodes
+    */
+    int stateOfSearch_;
+    /// At which depths to do cuts
+    int whenCuts_;
+    /// Hotstart solution
+    double * hotstartSolution_;
+    /// Hotstart priorities
+    int * hotstartPriorities_;
+    /// Number of heuristic solutions
+    int numberHeuristicSolutions_;
+    /// Cumulative number of nodes
+    int numberNodes_;
+    /** Cumulative number of nodes for statistics.
+        Must fix to match up
+    */
+    int numberNodes2_;
+    /// Cumulative number of iterations
+    int numberIterations_;
+    /// Cumulative number of solves
+    int numberSolves_;
+    /// Status of problem - 0 finished, 1 stopped, 2 difficulties
+    int status_;
+    /** Secondary status of problem
+        -1 unset (status_ will also be -1)
+        0 search completed with solution
+        1 linear relaxation not feasible (or worse than cutoff)
+        2 stopped on gap
+        3 stopped on nodes
+        4 stopped on time
+        5 stopped on user event
+        6 stopped on solutions
+     */
+    int secondaryStatus_;
+    /// Number of integers in problem
+    int numberIntegers_;
+    /// Number of rows at continuous
+    int numberRowsAtContinuous_;
+    /**
+       -1 - cutoff as constraint not activated
+       -2 - waiting to activate
+       >=0 - activated
+     */
+    int cutoffRowNumber_;
+    /// Maximum number of cuts
+    int maximumNumberCuts_;
+    /** Current phase (so heuristics etc etc can find out).
+        0 - initial solve
+        1 - solve with cuts at root
+        2 - solve with cuts
+        3 - other e.g. strong branching
+        4 - trying to validate a solution
+        5 - at end of search
+    */
+    int phase_;
+
+    /// Number of entries in #addedCuts_
+    int currentNumberCuts_;
+
+    /** Current limit on search tree depth
+
+      The allocated size of #walkback_. Increased as needed.
+    */
+    int maximumDepth_;
+    /** Array used to assemble the path between a node and the search tree root
+
+      The array is resized when necessary. #maximumDepth_  is the current
+      allocated size.
+    */
+    CbcNodeInfo ** walkback_;
+    CbcNodeInfo ** lastNodeInfo_;
+    const OsiRowCut ** lastCut_;
+    int lastDepth_;
+    int lastNumberCuts2_;
+    int maximumCuts_;
+    int * lastNumberCuts_;
+
+    /** The list of cuts initially collected for this subproblem
+
+      When the subproblem at this node is rebuilt, a set of cuts is collected
+      for inclusion in the constraint system. If any of these cuts are
+      subsequently removed because they have become loose, the corresponding
+      entry is set to NULL.
+    */
+    CbcCountRowCut ** addedCuts_;
+
+    /** A pointer to a row cut which will be added instead of normal branching.
+        After use it should be set to NULL.
+    */
+    OsiRowCut * nextRowCut_;
+
+    /// Current node so can be used elsewhere
+    CbcNode * currentNode_;
+
+    /// Indices of integer variables
+    int * integerVariable_;
+    /// Whether of not integer
+    char * integerInfo_;
+    /// Holds solution at continuous (after cuts)
+    double * continuousSolution_;
+    /// Array marked whenever a solution is found if non-zero
+    int * usedInSolution_;
+    /**
+        Special options
+        0 bit (1) - check if cuts valid (if on debugger list)
+        1 bit (2) - use current basis to check integer solution (rather than all slack)
+        2 bit (4) - don't check integer solution (by solving LP)
+        3 bit (8) - fast analyze
+        4 bit (16) - non-linear model - so no well defined CoinPackedMatrix
+        5 bit (32) - keep names
+        6 bit (64) - try for dominated columns
+        7 bit (128) - SOS type 1 but all declared integer
+        8 bit (256) - Set to say solution just found, unset by doing cuts
+        9 bit (512) - Try reduced model after 100 nodes
+        10 bit (1024) - Switch on some heuristics even if seems unlikely
+        11 bit (2048) - Mark as in small branch and bound
+        12 bit (4096) - Funny cuts so do slow way (in some places)
+        13 bit (8192) - Funny cuts so do slow way (in other places)
+        14 bit (16384) - Use Cplex! for fathoming
+        15 bit (32768) - Try reduced model after 0 nodes
+        16 bit (65536) - Original model had integer bounds
+        17 bit (131072) - Perturbation switched off
+        18 bit (262144) - donor CbcModel
+        19 bit (524288) - recipient CbcModel
+    */
+    int specialOptions_;
+    /** More special options
+        at present bottom 6 bits used for shadow price mode
+        1024 for experimental hotstart
+        2048,4096 breaking out of cuts
+        8192 slowly increase minimum drop
+        16384 gomory
+	32768 more heuristics in sub trees
+	65536 no cuts in preprocessing
+        131072 Time limits elapsed
+        18 bit (262144) - Perturb fathom nodes
+        19 bit (524288) - No limit on fathom nodes
+        20 bit (1048576) - Reduce sum of infeasibilities before cuts
+        21 bit (2097152) - Reduce sum of infeasibilities after cuts
+    */
+    int moreSpecialOptions_;
+    /// User node comparison function
+    CbcCompareBase * nodeCompare_;
+    /// User feasibility function (see CbcFeasibleBase.hpp)
+    CbcFeasibilityBase * problemFeasibility_;
+    /// Tree
+    CbcTree * tree_;
+    /// Pointer to top of tree
+    CbcFullNodeInfo * topOfTree_;
+    /// A pointer to model to be used for subtrees
+    CbcModel * subTreeModel_;
+    /// A pointer to model from CbcHeuristic
+    CbcModel * heuristicModel_;
+    /// Number of times any subtree stopped on nodes, time etc
+    int numberStoppedSubTrees_;
+    /// Variable selection function
+    CbcBranchDecision * branchingMethod_;
+    /// Cut modifier function
+    CbcCutModifier * cutModifier_;
+    /// Strategy
+    CbcStrategy * strategy_;
+    /// Parent model
+    CbcModel * parentModel_;
+    /** Whether to automatically do presolve before branch and bound.
+        0 - no
+        1 - ordinary presolve
+        2 - integer presolve (dodgy)
+    */
+    /// Pointer to array[getNumCols()] (for speed) of column lower bounds
+    const double * cbcColLower_;
+    /// Pointer to array[getNumCols()] (for speed) of column upper bounds
+    const double * cbcColUpper_;
+    /// Pointer to array[getNumRows()] (for speed) of row lower bounds
+    const double * cbcRowLower_;
+    /// Pointer to array[getNumRows()] (for speed) of row upper bounds
+    const double * cbcRowUpper_;
+    /// Pointer to array[getNumCols()] (for speed) of primal solution vector
+    const double * cbcColSolution_;
+    /// Pointer to array[getNumRows()] (for speed) of dual prices
+    const double * cbcRowPrice_;
+    /// Get a pointer to array[getNumCols()] (for speed) of reduced costs
+    const double * cbcReducedCost_;
+    /// Pointer to array[getNumRows()] (for speed) of row activity levels.
+    const double * cbcRowActivity_;
+    /// Pointer to user-defined data structure
+    void * appData_;
+    /// Presolve for CbcTreeLocal
+    int presolve_;
+    /** Maximum number of candidates to consider for strong branching.
+      To disable strong branching, set this to 0.
+    */
+    int numberStrong_;
+    /** \brief The number of branches before pseudo costs believed
+           in dynamic strong branching.
+
+      A value of 0 is  off.
+    */
+    int numberBeforeTrust_;
+    /** \brief The number of variables for which to compute penalties
+           in dynamic strong branching.
+    */
+    int numberPenalties_;
+    /// For threads - stop after this many "iterations"
+    int stopNumberIterations_;
+    /** Scale factor to make penalties match strong.
+        Should/will be computed */
+    double penaltyScaleFactor_;
+    /// Number of analyze iterations to do
+    int numberAnalyzeIterations_;
+    /// Arrays with analysis results
+    double * analyzeResults_;
+    /// Useful temporary pointer
+    void * temporaryPointer_;
+    /// Number of nodes infeasible by normal branching (before cuts)
+    int numberInfeasibleNodes_;
+    /** Problem type as set by user or found by analysis.  This will be extended
+        0 - not known
+        1 - Set partitioning <=
+        2 - Set partitioning ==
+        3 - Set covering
+    */
+    int problemType_;
+    /// Print frequency
+    int printFrequency_;
+    /// Number of cut generators
+    int numberCutGenerators_;
+    // Cut generators
+    CbcCutGenerator ** generator_;
+    // Cut generators before any changes
+    CbcCutGenerator ** virginGenerator_;
+    /// Number of heuristics
+    int numberHeuristics_;
+    /// Heuristic solvers
+    CbcHeuristic ** heuristic_;
+    /// Pointer to heuristic solver which found last solution (or NULL)
+    CbcHeuristic * lastHeuristic_;
+    /// Depth for fast nodes
+    int fastNodeDepth_;
+    /*! Pointer to the event handler */
+# ifdef CBC_ONLY_CLP
+    ClpEventHandler *eventHandler_ ;
+# else
+    CbcEventHandler *eventHandler_ ;
+# endif
+
+    /// Total number of objects
+    int numberObjects_;
+
+    /** \brief Integer and Clique and ... information
+
+      \note The code assumes that the first objects on the list will be
+        SimpleInteger objects for each integer variable, followed by
+        Clique objects. Portions of the code that understand Clique objects
+        will fail if they do not immediately follow the SimpleIntegers.
+        Large chunks of the code will fail if the first objects are not
+        SimpleInteger. As of 2003.08, SimpleIntegers and Cliques are the only
+        objects.
+    */
+    OsiObject ** object_;
+    /// Now we may not own objects - just point to solver's objects
+    bool ownObjects_;
+
+    /// Original columns as created by integerPresolve or preprocessing
+    int * originalColumns_;
+    /// How often to scan global cuts
+    int howOftenGlobalScan_;
+    /** Number of times global cuts violated.  When global cut pool then this
+        should be kept for each cut and type of cut */
+    int numberGlobalViolations_;
+    /// Number of extra iterations in fast lp
+    int numberExtraIterations_;
+    /// Number of extra nodes in fast lp
+    int numberExtraNodes_;
+    /** Value of objective at continuous
+        (Well actually after initial round of cuts)
+    */
+    double continuousObjective_;
+    /** Value of objective before root node cuts added
+    */
+    double originalContinuousObjective_;
+    /// Number of infeasibilities at continuous
+    int continuousInfeasibilities_;
+    /// Maximum number of cut passes at root
+    int maximumCutPassesAtRoot_;
+    /// Maximum number of cut passes
+    int maximumCutPasses_;
+    /// Preferred way of branching
+    int preferredWay_;
+    /// Current cut pass number
+    int currentPassNumber_;
+    /// Maximum number of cuts (for whichGenerator_)
+    int maximumWhich_;
+    /// Maximum number of rows
+    int maximumRows_;
+    /// Random seed
+    int randomSeed_;
+    /// Multiple root tries
+    int multipleRootTries_;
+    /// Current depth
+    int currentDepth_;
+    /// Thread specific random number generator
+    mutable CoinThreadRandom randomNumberGenerator_;
+    /// Work basis for temporary use
+    CoinWarmStartBasis workingBasis_;
+    /// Which cut generator generated this cut
+    int * whichGenerator_;
+    /// Maximum number of statistics
+    int maximumStatistics_;
+    /// statistics
+    CbcStatistics ** statistics_;
+    /// Maximum depth reached
+    int maximumDepthActual_;
+    /// Number of reduced cost fixings
+    double numberDJFixed_;
+    /// Probing info
+    CglTreeProbingInfo * probingInfo_;
+    /// Number of fixed by analyze at root
+    int numberFixedAtRoot_;
+    /// Number fixed by analyze so far
+    int numberFixedNow_;
+    /// Whether stopping on gap
+    bool stoppedOnGap_;
+    /// Whether event happened
+    mutable bool eventHappened_;
+    /// Number of long strong goes
+    int numberLongStrong_;
+    /// Number of old active cuts
+    int numberOldActiveCuts_;
+    /// Number of new cuts
+    int numberNewCuts_;
+    /// Strategy worked out - mainly at root node
+    int searchStrategy_;
+    /** Strategy for strong branching
+	0 - normal
+	when to do all fractional
+	1 - root node
+	2 - depth less than modifier
+	4 - if objective == best possible
+	6 - as 2+4 
+	when to do all including satisfied
+	10 - root node etc.
+	If >=100 then do when depth <= strategy/100 (otherwise 5)
+     */
+    int strongStrategy_;
+    /// Number of iterations in strong branching
+    int numberStrongIterations_;
+    /** 0 - number times strong branching done, 1 - number fixed, 2 - number infeasible
+        Second group of three is a snapshot at node [6] */
+    int strongInfo_[7];
+    /**
+        For advanced applications you may wish to modify the behavior of Cbc
+        e.g. if the solver is a NLP solver then you may not have an exact
+        optimum solution at each step.  This gives characteristics - just for one BAB.
+        For actually saving/restoring a solution you need the actual solver one.
+    */
+    OsiBabSolver * solverCharacteristics_;
+    /// Whether to force a resolve after takeOffCuts
+    bool resolveAfterTakeOffCuts_;
+    /// Maximum number of iterations (designed to be used in heuristics)
+    int maximumNumberIterations_;
+    /// Anything with priority >= this can be treated as continuous
+    int continuousPriority_;
+    /// Number of outstanding update information items
+    int numberUpdateItems_;
+    /// Maximum number of outstanding update information items
+    int maximumNumberUpdateItems_;
+    /// Update items
+    CbcObjectUpdateData * updateItems_;
+    /// Stored row cuts for donor/recipient CbcModel
+    CglStored * storedRowCuts_;
+    /**
+       Parallel
+       0 - off
+       1 - testing
+       2-99 threads
+       other special meanings
+    */
+    int numberThreads_;
+    /** thread mode
+        always use numberThreads for branching
+        1 set then deterministic
+        2 set then use numberThreads for root cuts
+        4 set then use numberThreads in root mini branch and bound
+        default is 0
+    */
+    int threadMode_;
+    /// Thread stuff for master
+    CbcBaseModel * master_;
+    /// Pointer to masterthread
+    CbcThread * masterThread_;
+//@}
+};
+/// So we can use osiObject or CbcObject during transition
+void getIntegerInformation(const OsiObject * object, double & originalLower,
+                           double & originalUpper) ;
+// So we can call from other programs
+// Real main program
+class OsiClpSolverInterface;
+int CbcMain (int argc, const char *argv[], OsiClpSolverInterface & solver, CbcModel ** babSolver);
+int CbcMain (int argc, const char *argv[], CbcModel & babSolver);
+// four ways of calling
+int callCbc(const char * input2, OsiClpSolverInterface& solver1);
+int callCbc(const char * input2);
+int callCbc(const std::string input2, OsiClpSolverInterface& solver1);
+int callCbc(const std::string input2) ;
+// When we want to load up CbcModel with options first
+void CbcMain0 (CbcModel & babSolver);
+int CbcMain1 (int argc, const char *argv[], CbcModel & babSolver);
+// two ways of calling
+int callCbc(const char * input2, CbcModel & babSolver);
+int callCbc(const std::string input2, CbcModel & babSolver);
+// And when CbcMain0 already called to initialize
+int callCbc1(const char * input2, CbcModel & babSolver);
+int callCbc1(const std::string input2, CbcModel & babSolver);
+// And when CbcMain0 already called to initialize (with call back) (see CbcMain1 for whereFrom)
+int callCbc1(const char * input2, CbcModel & babSolver, int (CbcModel * currentSolver, int whereFrom));
+int callCbc1(const std::string input2, CbcModel & babSolver, int (CbcModel * currentSolver, int whereFrom));
+int CbcMain1 (int argc, const char *argv[], CbcModel & babSolver, int (CbcModel * currentSolver, int whereFrom));
+// For uniform setting of cut and heuristic options
+void setCutAndHeuristicOptions(CbcModel & model);
+#endif
+
diff --git a/cbits/coin/CbcNWay.cpp b/cbits/coin/CbcNWay.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcNWay.cpp
@@ -0,0 +1,425 @@
+// $Id: CbcNWay.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/9/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcNWay.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+//##############################################################################
+
+// Default Constructor
+CbcNWay::CbcNWay ()
+        : CbcObject(),
+        numberMembers_(0),
+        members_(NULL),
+        consequence_(NULL)
+{
+}
+
+// Useful constructor (which are integer indices)
+CbcNWay::CbcNWay (CbcModel * model, int numberMembers,
+                  const int * which, int identifier)
+        : CbcObject(model)
+{
+    id_ = identifier;
+    numberMembers_ = numberMembers;
+    if (numberMembers_) {
+        members_ = new int[numberMembers_];
+        memcpy(members_, which, numberMembers_*sizeof(int));
+    } else {
+        members_ = NULL;
+    }
+    consequence_ = NULL;
+}
+
+// Copy constructor
+CbcNWay::CbcNWay ( const CbcNWay & rhs)
+        : CbcObject(rhs)
+{
+    numberMembers_ = rhs.numberMembers_;
+    consequence_ = NULL;
+    if (numberMembers_) {
+        members_ = new int[numberMembers_];
+        memcpy(members_, rhs.members_, numberMembers_*sizeof(int));
+        if (rhs.consequence_) {
+            consequence_ = new CbcConsequence * [numberMembers_];
+            for (int i = 0; i < numberMembers_; i++) {
+                if (rhs.consequence_[i])
+                    consequence_[i] = rhs.consequence_[i]->clone();
+                else
+                    consequence_[i] = NULL;
+            }
+        }
+    } else {
+        members_ = NULL;
+    }
+}
+
+// Clone
+CbcObject *
+CbcNWay::clone() const
+{
+    return new CbcNWay(*this);
+}
+
+// Assignment operator
+CbcNWay &
+CbcNWay::operator=( const CbcNWay & rhs)
+{
+    if (this != &rhs) {
+        CbcObject::operator=(rhs);
+        delete [] members_;
+        numberMembers_ = rhs.numberMembers_;
+        if (consequence_) {
+            for (int i = 0; i < numberMembers_; i++)
+                delete consequence_[i];
+            delete [] consequence_;
+            consequence_ = NULL;
+        }
+        if (numberMembers_) {
+            members_ = new int[numberMembers_];
+            memcpy(members_, rhs.members_, numberMembers_*sizeof(int));
+        } else {
+            members_ = NULL;
+        }
+        if (rhs.consequence_) {
+            consequence_ = new CbcConsequence * [numberMembers_];
+            for (int i = 0; i < numberMembers_; i++) {
+                if (rhs.consequence_[i])
+                    consequence_[i] = rhs.consequence_[i]->clone();
+                else
+                    consequence_[i] = NULL;
+            }
+        }
+    }
+    return *this;
+}
+
+// Destructor
+CbcNWay::~CbcNWay ()
+{
+    delete [] members_;
+    if (consequence_) {
+        for (int i = 0; i < numberMembers_; i++)
+            delete consequence_[i];
+        delete [] consequence_;
+    }
+}
+// Set up a consequence for a single member
+void
+CbcNWay::setConsequence(int iColumn, const CbcConsequence & consequence)
+{
+    if (!consequence_) {
+        consequence_ = new CbcConsequence * [numberMembers_];
+        for (int i = 0; i < numberMembers_; i++)
+            consequence_[i] = NULL;
+    }
+    for (int i = 0; i < numberMembers_; i++) {
+        if (members_[i] == iColumn) {
+            consequence_[i] = consequence.clone();
+            break;
+        }
+    }
+}
+
+// Applies a consequence for a single member
+void
+CbcNWay::applyConsequence(int iSequence, int state) const
+{
+    assert (state == -9999 || state == 9999);
+    if (consequence_) {
+        CbcConsequence * consequence = consequence_[iSequence];
+        if (consequence)
+            consequence->applyToSolver(model_->solver(), state);
+    }
+}
+double
+CbcNWay::infeasibility(const OsiBranchingInformation * /*info*/,
+                       int &preferredWay) const
+{
+    int numberUnsatis = 0;
+    int j;
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double largestValue = 0.0;
+
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+
+    for (j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        double value = solution[iColumn];
+        value = CoinMax(value, lower[iColumn]);
+        value = CoinMin(value, upper[iColumn]);
+        double distance = CoinMin(value - lower[iColumn], upper[iColumn] - value);
+        if (distance > integerTolerance) {
+            numberUnsatis++;
+            largestValue = CoinMax(distance, largestValue);
+        }
+    }
+    preferredWay = 1;
+    if (numberUnsatis) {
+        return largestValue;
+    } else {
+        return 0.0; // satisfied
+    }
+}
+
+// This looks at solution and sets bounds to contain solution
+void
+CbcNWay::feasibleRegion()
+{
+    int j;
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    for (j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        double value = solution[iColumn];
+        value = CoinMax(value, lower[iColumn]);
+        value = CoinMin(value, upper[iColumn]);
+        if (value >= upper[iColumn] - integerTolerance) {
+            solver->setColLower(iColumn, upper[iColumn]);
+        } else {
+            assert (value <= lower[iColumn] + integerTolerance);
+            solver->setColUpper(iColumn, lower[iColumn]);
+        }
+    }
+}
+// Redoes data when sequence numbers change
+void
+CbcNWay::redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns)
+{
+    model_ = model;
+    int n2 = 0;
+    for (int j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        int i;
+        for (i = 0; i < numberColumns; i++) {
+            if (originalColumns[i] == iColumn)
+                break;
+        }
+        if (i < numberColumns) {
+            members_[n2] = i;
+            consequence_[n2++] = consequence_[j];
+        } else {
+            delete consequence_[j];
+        }
+    }
+    if (n2 < numberMembers_) {
+        printf("** NWay number of members reduced from %d to %d!\n", numberMembers_, n2);
+        numberMembers_ = n2;
+    }
+}
+CbcBranchingObject *
+CbcNWay::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int /*way*/)
+{
+    int numberFree = 0;
+    int j;
+
+    //OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    int * list = new int[numberMembers_];
+    double * sort = new double[numberMembers_];
+
+    for (j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        double value = solution[iColumn];
+        value = CoinMax(value, lower[iColumn]);
+        value = CoinMin(value, upper[iColumn]);
+        if (upper[iColumn] > lower[iColumn]) {
+            double distance = upper[iColumn] - value;
+            list[numberFree] = j;
+            sort[numberFree++] = distance;
+        }
+    }
+    assert (numberFree);
+    // sort
+    CoinSort_2(sort, sort + numberFree, list);
+    // create object
+    CbcBranchingObject * branch;
+    branch = new CbcNWayBranchingObject(model_, this, numberFree, list);
+    branch->setOriginalObject(this);
+    delete [] list;
+    delete [] sort;
+    return branch;
+}
+
+// Default Constructor
+CbcNWayBranchingObject::CbcNWayBranchingObject()
+        : CbcBranchingObject()
+{
+    order_ = NULL;
+    object_ = NULL;
+    numberInSet_ = 0;
+    way_ = 0;
+}
+
+// Useful constructor
+CbcNWayBranchingObject::CbcNWayBranchingObject (CbcModel * model,
+        const CbcNWay * nway,
+        int number, const int * order)
+        : CbcBranchingObject(model, nway->id(), -1, 0.5)
+{
+    numberBranches_ = number;
+    order_ = new int [number];
+    object_ = nway;
+    numberInSet_ = number;
+    memcpy(order_, order, number*sizeof(int));
+}
+
+// Copy constructor
+CbcNWayBranchingObject::CbcNWayBranchingObject ( const CbcNWayBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+    numberInSet_ = rhs.numberInSet_;
+    object_ = rhs.object_;
+    if (numberInSet_) {
+        order_ = new int [numberInSet_];
+        memcpy(order_, rhs.order_, numberInSet_*sizeof(int));
+    } else {
+        order_ = NULL;
+    }
+}
+
+// Assignment operator
+CbcNWayBranchingObject &
+CbcNWayBranchingObject::operator=( const CbcNWayBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        object_ = rhs.object_;
+        delete [] order_;
+        numberInSet_ = rhs.numberInSet_;
+        if (numberInSet_) {
+            order_ = new int [numberInSet_];
+            memcpy(order_, rhs.order_, numberInSet_*sizeof(int));
+        } else {
+            order_ = NULL;
+        }
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcNWayBranchingObject::clone() const
+{
+    return (new CbcNWayBranchingObject(*this));
+}
+
+
+// Destructor
+CbcNWayBranchingObject::~CbcNWayBranchingObject ()
+{
+    delete [] order_;
+}
+double
+CbcNWayBranchingObject::branch()
+{
+    int which = branchIndex_;
+    branchIndex_++;
+    assert (numberBranchesLeft() >= 0);
+    if (which == 0) {
+        // first branch so way_ may mean something
+        assert (way_ == -1 || way_ == 1);
+        if (way_ == -1)
+            which++;
+    } else if (which == 1) {
+        // second branch so way_ may mean something
+        assert (way_ == -1 || way_ == 1);
+        if (way_ == -1)
+            which--;
+        // switch way off
+        way_ = 0;
+    }
+    const double * lower = model_->solver()->getColLower();
+    const double * upper = model_->solver()->getColUpper();
+    const int * members = object_->members();
+    for (int j = 0; j < numberInSet_; j++) {
+        int iSequence = order_[j];
+        int iColumn = members[iSequence];
+        if (j != which) {
+            model_->solver()->setColUpper(iColumn, lower[iColumn]);
+            //model_->solver()->setColLower(iColumn,lower[iColumn]);
+            assert (lower[iColumn] > -1.0e20);
+            // apply any consequences
+            object_->applyConsequence(iSequence, -9999);
+        } else {
+            model_->solver()->setColLower(iColumn, upper[iColumn]);
+            //model_->solver()->setColUpper(iColumn,upper[iColumn]);
+#ifdef FULL_PRINT
+            printf("Up Fix %d to %g\n", iColumn, upper[iColumn]);
+#endif
+            assert (upper[iColumn] < 1.0e20);
+            // apply any consequences
+            object_->applyConsequence(iSequence, 9999);
+        }
+    }
+    return 0.0;
+}
+void
+CbcNWayBranchingObject::print()
+{
+    printf("NWay - Up Fix ");
+    const int * members = object_->members();
+    for (int j = 0; j < way_; j++) {
+        int iColumn = members[order_[j]];
+        printf("%d ", iColumn);
+    }
+    printf("\n");
+}
+
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcNWayBranchingObject::compareOriginalObject
+(const CbcBranchingObject* /*brObj*/) const
+{
+    throw("must implement");
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcNWayBranchingObject::compareBranchingObject
+(const CbcBranchingObject* /*brObj*/, const bool /*replaceIfOverlap*/)
+{
+    throw("must implement");
+}
+
diff --git a/cbits/coin/CbcNWay.hpp b/cbits/coin/CbcNWay.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcNWay.hpp
@@ -0,0 +1,166 @@
+// $Id: CbcNWay.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/9/2009-- carved out of CbcBranchActual
+
+/** Define an n-way class for variables.
+    Only valid value is one at UB others at LB
+    Normally 0-1
+*/
+#ifndef CbcNWay_H
+#define CbcNWay_H
+
+class CbcNWay : public CbcObject {
+
+public:
+
+    // Default Constructor
+    CbcNWay ();
+
+    /** Useful constructor (which are matrix indices)
+    */
+    CbcNWay (CbcModel * model, int numberMembers,
+             const int * which, int identifier);
+
+    // Copy constructor
+    CbcNWay ( const CbcNWay &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    /// Assignment operator
+    CbcNWay & operator=( const CbcNWay& rhs);
+
+    /// Destructor
+    virtual ~CbcNWay ();
+
+    /// Set up a consequence for a single member
+    void setConsequence(int iColumn, const CbcConsequence & consequence);
+
+    /// Applies a consequence for a single member
+    void applyConsequence(int iSequence, int state) const;
+
+    /// Infeasibility - large is 0.5 (and 0.5 will give this)
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /// This looks at solution and sets bounds to contain solution
+    virtual void feasibleRegion();
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+
+    /// Number of members
+    inline int numberMembers() const {
+        return numberMembers_;
+    }
+
+    /// Members (indices in range 0 ... numberColumns-1)
+    inline const int * members() const {
+        return members_;
+    }
+    /// Redoes data when sequence numbers change
+    virtual void redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns);
+
+protected:
+    /// data
+    /// Number of members
+    int numberMembers_;
+
+    /// Members (indices in range 0 ... numberColumns-1)
+    int * members_;
+    /// Consequences (normally NULL)
+    CbcConsequence ** consequence_;
+};
+/** N way branching Object class.
+    Variable is number of set.
+ */
+class CbcNWayBranchingObject : public CbcBranchingObject {
+
+public:
+
+    // Default Constructor
+    CbcNWayBranchingObject ();
+
+    /** Useful constructor - order had matrix indices
+        way_ -1 corresponds to setting first, +1 to second, +3 etc.
+        this is so -1 and +1 have similarity to normal
+    */
+    CbcNWayBranchingObject (CbcModel * model,  const CbcNWay * nway,
+                            int numberBranches, const int * order);
+
+    // Copy constructor
+    CbcNWayBranchingObject ( const CbcNWayBranchingObject &);
+
+    // Assignment operator
+    CbcNWayBranchingObject & operator=( const CbcNWayBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~CbcNWayBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch();
+
+#ifdef JJF_ZERO
+    // FIXME: what do we need to do here?
+    /** Reset every information so that the branching object appears to point to
+        the previous child. This method does not need to modify anything in any
+        solver. */
+    virtual void previousBranch();
+#endif
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+    /** The number of branch arms created for this branching object
+    */
+    virtual int numberBranches() const {
+        return numberInSet_;
+    }
+    /// Is this a two way object (-1 down, +1 up)
+    virtual bool twoWay() const {
+        return false;
+    }
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return NWayBranchObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+private:
+    /// order of branching - points back to CbcNWay
+    int * order_;
+    /// Points back to object
+    const CbcNWay * object_;
+    /// Number in set
+    int numberInSet_;
+};
+#endif
diff --git a/cbits/coin/CbcNode.cpp b/cbits/coin/CbcNode.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcNode.cpp
@@ -0,0 +1,4647 @@
+/* $Id: CbcNode.cpp 1888 2013-04-06 20:52:59Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcConfig.h"
+//#define DEBUG_SOLUTION
+#ifdef DEBUG_SOLUTION
+#define COIN_DETAIL
+#endif
+#include <string>
+//#define CBC_DEBUG 1
+//#define CHECK_CUT_COUNTS
+//#define CHECK_NODE
+//#define CBC_CHECK_BASIS
+#include <cassert>
+#include <cfloat>
+#define CUTS
+#include "OsiSolverInterface.hpp"
+#include "OsiChooseVariable.hpp"
+#include "OsiAuxInfo.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinTime.hpp"
+#include "CbcModel.hpp"
+#include "CbcNode.hpp"
+#include "CbcStatistics.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "OsiCuts.hpp"
+#include "CbcCountRowCut.hpp"
+#include "CbcFeasibilityBase.hpp"
+#include "CbcMessage.hpp"
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#include "ClpSimplexOther.hpp"
+#endif
+using namespace std;
+#include "CglCutGenerator.hpp"
+
+
+CbcNode::CbcNode() :
+        nodeInfo_(NULL),
+        objectiveValue_(1.0e100),
+        guessedObjectiveValue_(1.0e100),
+        sumInfeasibilities_(0.0),
+        branch_(NULL),
+        depth_(-1),
+        numberUnsatisfied_(0),
+        nodeNumber_(-1),
+        state_(0)
+{
+#ifdef CHECK_NODE
+    printf("CbcNode %x Constructor\n", this);
+#endif
+}
+// Print
+void
+CbcNode::print() const
+{
+    printf("number %d obj %g depth %d sumun %g nunsat %d state %d\n",
+           nodeNumber_, objectiveValue_, depth_, sumInfeasibilities_, numberUnsatisfied_, state_);
+}
+CbcNode::CbcNode(CbcModel * model,
+                 CbcNode * lastNode) :
+        nodeInfo_(NULL),
+        objectiveValue_(1.0e100),
+        guessedObjectiveValue_(1.0e100),
+        sumInfeasibilities_(0.0),
+        branch_(NULL),
+        depth_(-1),
+        numberUnsatisfied_(0),
+        nodeNumber_(-1),
+        state_(0)
+{
+#ifdef CHECK_NODE
+    printf("CbcNode %x Constructor from model\n", this);
+#endif
+    model->setObjectiveValue(this, lastNode);
+
+    if (lastNode) {
+        if (lastNode->nodeInfo_) {
+            lastNode->nodeInfo_->increment();
+        }
+    }
+    nodeNumber_ = model->getNodeCount();
+}
+
+#define CBC_NEW_CREATEINFO
+#ifdef CBC_NEW_CREATEINFO
+
+/*
+  New createInfo, with basis manipulation hidden inside mergeBasis. Allows
+  solvers to override and carry over all information from one basis to
+  another.
+*/
+
+void
+CbcNode::createInfo (CbcModel *model,
+                     CbcNode *lastNode,
+                     const CoinWarmStartBasis *lastws,
+                     const double *lastLower, const double *lastUpper,
+                     int numberOldActiveCuts, int numberNewCuts)
+
+{
+    OsiSolverInterface *solver = model->solver();
+    CbcStrategy *strategy = model->strategy();
+    /*
+      The root --- no parent. Create full basis and bounds information.
+    */
+    if (!lastNode) {
+        if (!strategy)
+            nodeInfo_ = new CbcFullNodeInfo(model, solver->getNumRows());
+        else
+            nodeInfo_ = strategy->fullNodeInfo(model, solver->getNumRows());
+    } else {
+        /*
+          Not the root. Create an edit from the parent's basis & bound information.
+          This is not quite as straightforward as it seems. We need to reintroduce
+          cuts we may have dropped out of the basis, in the correct position, because
+          this whole process is strictly positional. Start by grabbing the current
+          basis.
+        */
+        bool mustDeleteBasis;
+        const CoinWarmStartBasis *ws =
+            dynamic_cast<const CoinWarmStartBasis*>(solver->getPointerToWarmStart(mustDeleteBasis));
+        assert(ws != NULL); // make sure not volume
+        //int numberArtificials = lastws->getNumArtificial();
+        int numberColumns = solver->getNumCols();
+        int numberRowsAtContinuous = model->numberRowsAtContinuous();
+        int currentNumberCuts = model->currentNumberCuts();
+#   ifdef CBC_CHECK_BASIS
+        std::cout
+            << "Before expansion: orig " << numberRowsAtContinuous
+            << ", old " << numberOldActiveCuts
+            << ", new " << numberNewCuts
+            << ", current " << currentNumberCuts << "." << std::endl ;
+        ws->print();
+#   endif
+        /*
+          Clone the basis and resize it to hold the structural constraints, plus
+          all the cuts: old cuts, both active and inactive (currentNumberCuts),
+          and new cuts (numberNewCuts). This will become the expanded basis.
+        */
+        CoinWarmStartBasis *expanded =
+            dynamic_cast<CoinWarmStartBasis *>(ws->clone()) ;
+        int iCompact = numberRowsAtContinuous + numberOldActiveCuts + numberNewCuts ;
+        // int nPartial = numberRowsAtContinuous+currentNumberCuts;
+        int iFull = numberRowsAtContinuous + currentNumberCuts + numberNewCuts;
+        // int maxBasisLength = ((iFull+15)>>4)+((numberColumns+15)>>4);
+        // printf("l %d full %d\n",maxBasisLength,iFull);
+        expanded->resize(iFull, numberColumns);
+#   ifdef CBC_CHECK_BASIS
+        std::cout
+            << "\tFull basis " << iFull << " rows, "
+            << numberColumns << " columns; compact "
+            << iCompact << " rows." << std::endl ;
+#   endif
+        /*
+          Now flesh out the expanded basis. The clone already has the
+          correct status information for the variables and for the structural
+          (numberRowsAtContinuous) constraints. Any indices beyond nPartial must be
+          cuts created while processing this node --- they can be copied en bloc
+          into the correct position in the expanded basis. The space reserved for
+          xferRows is a gross overestimate.
+        */
+        CoinWarmStartBasis::XferVec xferRows ;
+        xferRows.reserve(iFull - numberRowsAtContinuous + 1) ;
+        if (numberNewCuts) {
+            xferRows.push_back(
+                CoinWarmStartBasis::XferEntry(iCompact - numberNewCuts,
+                                              iFull - numberNewCuts, numberNewCuts)) ;
+        }
+        /*
+          From nPartial down, record the entries we want to copy from the current
+          basis (the entries for the active cuts; non-zero in the list returned
+          by addedCuts). Fill the expanded basis with entries showing a status of
+          basic for the deactivated (loose) cuts.
+        */
+        CbcCountRowCut **cut = model->addedCuts();
+        iFull -= (numberNewCuts + 1) ;
+        iCompact -= (numberNewCuts + 1) ;
+        int runLen = 0 ;
+        CoinWarmStartBasis::XferEntry entry(-1, -1, -1) ;
+        while (iFull >= numberRowsAtContinuous) {
+            for ( ; iFull >= numberRowsAtContinuous &&
+                    cut[iFull-numberRowsAtContinuous] ; iFull--)
+                runLen++ ;
+            if (runLen) {
+                iCompact -= runLen ;
+                entry.first = iCompact + 1 ;
+                entry.second = iFull + 1 ;
+                entry.third = runLen ;
+                runLen = 0 ;
+                xferRows.push_back(entry) ;
+            }
+            for ( ; iFull >= numberRowsAtContinuous &&
+                    !cut[iFull-numberRowsAtContinuous] ; iFull--)
+                expanded->setArtifStatus(iFull, CoinWarmStartBasis::basic);
+        }
+        /*
+          Finally, call mergeBasis to copy over entries from the current basis to
+          the expanded basis. Since we cloned the expanded basis from the active basis
+          and haven't changed the number of variables, only row status entries need
+          to be copied.
+        */
+        expanded->mergeBasis(ws, &xferRows, 0) ;
+
+#ifdef CBC_CHECK_BASIS
+        std::cout << "Expanded basis:" << std::endl ;
+        expanded->print() ;
+        std::cout << "Diffing against:" << std::endl ;
+        lastws->print() ;
+#endif
+        assert (expanded->getNumArtificial() >= lastws->getNumArtificial());
+#ifdef CLP_INVESTIGATE
+        if (!expanded->fullBasis()) {
+            int iFull = numberRowsAtContinuous + currentNumberCuts + numberNewCuts;
+            printf("cont %d old %d new %d current %d full inc %d full %d\n",
+                   numberRowsAtContinuous, numberOldActiveCuts, numberNewCuts,
+                   currentNumberCuts, iFull, iFull - numberNewCuts);
+        }
+#endif
+
+        /*
+          Now that we have two bases in proper positional correspondence, creating
+          the actual diff is dead easy.
+
+          Note that we're going to compare the expanded basis here to the stripped
+          basis (lastws) produced by addCuts. It doesn't affect the correctness (the
+          diff process has no knowledge of the meaning of an entry) but it does
+          mean that we'll always generate a whack of diff entries because the expanded
+          basis is considerably larger than the stripped basis.
+        */
+        CoinWarmStartDiff *basisDiff = expanded->generateDiff(lastws) ;
+
+        /*
+          Diff the bound vectors. It's assumed the number of structural variables
+          is not changing. For branching objects that change bounds on integer
+          variables, we should see at least one bound change as a consequence
+          of applying the branch that generated this subproblem from its parent.
+          This need not hold for other types of branching objects (hyperplane
+          branches, for example).
+        */
+        const double * lower = solver->getColLower();
+        const double * upper = solver->getColUpper();
+
+        double *boundChanges = new double [2*numberColumns] ;
+        int *variables = new int [2*numberColumns] ;
+        int numberChangedBounds = 0;
+
+        int i;
+        for (i = 0; i < numberColumns; i++) {
+            if (lower[i] != lastLower[i]) {
+                variables[numberChangedBounds] = i;
+                boundChanges[numberChangedBounds++] = lower[i];
+            }
+            if (upper[i] != lastUpper[i]) {
+                variables[numberChangedBounds] = i | 0x80000000;
+                boundChanges[numberChangedBounds++] = upper[i];
+            }
+#ifdef CBC_DEBUG
+            if (lower[i] != lastLower[i]) {
+                std::cout
+                    << "lower on " << i << " changed from "
+                    << lastLower[i] << " to " << lower[i] << std::endl ;
+            }
+            if (upper[i] != lastUpper[i]) {
+                std::cout
+                    << "upper on " << i << " changed from "
+                    << lastUpper[i] << " to " << upper[i] << std::endl ;
+            }
+#endif
+        }
+#ifdef CBC_DEBUG
+        std::cout << numberChangedBounds << " changed bounds." << std::endl ;
+#endif
+        //if (lastNode->branchingObject()->boundBranch())
+        //assert (numberChangedBounds);
+        /*
+          Hand the lot over to the CbcPartialNodeInfo constructor, then clean up and
+          return.
+        */
+        if (!strategy)
+            nodeInfo_ =
+                new CbcPartialNodeInfo(lastNode->nodeInfo_, this, numberChangedBounds,
+                                       variables, boundChanges, basisDiff) ;
+        else
+            nodeInfo_ =
+                strategy->partialNodeInfo(model, lastNode->nodeInfo_, this,
+                                          numberChangedBounds, variables, boundChanges,
+                                          basisDiff) ;
+        delete basisDiff ;
+        delete [] boundChanges;
+        delete [] variables;
+        delete expanded ;
+        if  (mustDeleteBasis)
+            delete ws;
+    }
+    // Set node number
+    nodeInfo_->setNodeNumber(model->getNodeCount2());
+    state_ |= 2; // say active
+}
+
+#else	// CBC_NEW_CREATEINFO
+
+/*
+  Original createInfo, with bare manipulation of basis vectors. Fails if solver
+  maintains additional information in basis.
+*/
+
+void
+CbcNode::createInfo (CbcModel *model,
+                     CbcNode *lastNode,
+                     const CoinWarmStartBasis *lastws,
+                     const double *lastLower, const double *lastUpper,
+                     int numberOldActiveCuts, int numberNewCuts)
+{
+    OsiSolverInterface * solver = model->solver();
+    CbcStrategy * strategy = model->strategy();
+    /*
+      The root --- no parent. Create full basis and bounds information.
+    */
+    if (!lastNode) {
+        if (!strategy)
+            nodeInfo_ = new CbcFullNodeInfo(model, solver->getNumRows());
+        else
+            nodeInfo_ = strategy->fullNodeInfo(model, solver->getNumRows());
+    }
+    /*
+      Not the root. Create an edit from the parent's basis & bound information.
+      This is not quite as straightforward as it seems. We need to reintroduce
+      cuts we may have dropped out of the basis, in the correct position, because
+      this whole process is strictly positional. Start by grabbing the current
+      basis.
+    */
+    else {
+        bool mustDeleteBasis;
+        const CoinWarmStartBasis* ws =
+            dynamic_cast<const CoinWarmStartBasis*>(solver->getPointerToWarmStart(mustDeleteBasis));
+        assert(ws != NULL); // make sure not volume
+        //int numberArtificials = lastws->getNumArtificial();
+        int numberColumns = solver->getNumCols();
+
+        const double * lower = solver->getColLower();
+        const double * upper = solver->getColUpper();
+
+        int i;
+        /*
+        Create a clone and resize it to hold all the structural constraints, plus
+        all the cuts: old cuts, both active and inactive (currentNumberCuts), and
+        new cuts (numberNewCuts).
+
+        TODO: You'd think that the set of constraints (logicals) in the expanded
+        basis should match the set represented in lastws. At least, that's
+        what I thought. But at the point I first looked hard at this bit of
+        code, it turned out that lastws was the stripped basis produced at
+        the end of addCuts(), rather than the raw basis handed back by
+        addCuts1(). The expanded basis here is equivalent to the raw basis of
+        addCuts1(). I said ``whoa, that's not good, I must have introduced a
+        bug'' and went back to John's code to see where I'd gone wrong.
+        And discovered the same `error' in his code.
+
+        After a bit of thought, my conclusion is that correctness is not
+        affected by whether lastws is the stripped or raw basis. The diffs
+        have no semantics --- just a set of changes that need to be made
+        to convert lastws into expanded. I think the only effect is that we
+        store a lot more diffs (everything in expanded that's not covered by
+        the stripped basis). But I need to give this more thought. There
+        may well be some subtle error cases.
+
+        In the mean time, I've twiddled addCuts() to set lastws to the raw
+        basis. Makes me (Lou) less nervous to compare apples to apples.
+        */
+        CoinWarmStartBasis *expanded =
+            dynamic_cast<CoinWarmStartBasis *>(ws->clone()) ;
+        int numberRowsAtContinuous = model->numberRowsAtContinuous();
+        int iFull = numberRowsAtContinuous + model->currentNumberCuts() +
+                    numberNewCuts;
+        //int numberArtificialsNow = iFull;
+        //int maxBasisLength = ((iFull+15)>>4)+((numberColumns+15)>>4);
+        //printf("l %d full %d\n",maxBasisLength,iFull);
+        if (expanded)
+            expanded->resize(iFull, numberColumns);
+#ifdef CBC_CHECK_BASIS
+        printf("Before expansion: orig %d, old %d, new %d, current %d\n",
+               numberRowsAtContinuous, numberOldActiveCuts, numberNewCuts,
+               model->currentNumberCuts()) ;
+        ws->print();
+#endif
+        /*
+        Now fill in the expanded basis. Any indices beyond nPartial must
+        be cuts created while processing this node --- they can be copied directly
+        into the expanded basis. From nPartial down, pull the status of active cuts
+        from ws, interleaving with a B entry for the deactivated (loose) cuts.
+        */
+        int numberDropped = model->currentNumberCuts() - numberOldActiveCuts;
+        int iCompact = iFull - numberDropped;
+        CbcCountRowCut ** cut = model->addedCuts();
+        int nPartial = model->currentNumberCuts() + numberRowsAtContinuous;
+        iFull--;
+        for (; iFull >= nPartial; iFull--) {
+            CoinWarmStartBasis::Status status = ws->getArtifStatus(--iCompact);
+            //assert (status != CoinWarmStartBasis::basic); // may be permanent cut
+            expanded->setArtifStatus(iFull, status);
+        }
+        for (; iFull >= numberRowsAtContinuous; iFull--) {
+            if (cut[iFull-numberRowsAtContinuous]) {
+                CoinWarmStartBasis::Status status = ws->getArtifStatus(--iCompact);
+                // If no cut generator being used then we may have basic variables
+                //if (model->getMaximumCutPasses()&&
+                //  status == CoinWarmStartBasis::basic)
+                //printf("cut basic\n");
+                expanded->setArtifStatus(iFull, status);
+            } else {
+                expanded->setArtifStatus(iFull, CoinWarmStartBasis::basic);
+            }
+        }
+#ifdef CBC_CHECK_BASIS
+        printf("Expanded basis\n");
+        expanded->print() ;
+        printf("Diffing against\n") ;
+        lastws->print() ;
+#endif
+        /*
+        Now that we have two bases in proper positional correspondence, creating
+        the actual diff is dead easy.
+        */
+
+        CoinWarmStartDiff *basisDiff = expanded->generateDiff(lastws) ;
+        /*
+        Diff the bound vectors. It's assumed the number of structural variables is
+        not changing. Assuming that branching objects all involve integer variables,
+        we should see at least one bound change as a consequence of processing this
+        subproblem. Different types of branching objects could break this assertion.
+        Not true at all - we have not applied current branch - JJF.
+        */
+        double *boundChanges = new double [2*numberColumns] ;
+        int *variables = new int [2*numberColumns] ;
+        int numberChangedBounds = 0;
+        for (i = 0; i < numberColumns; i++) {
+            if (lower[i] != lastLower[i]) {
+                variables[numberChangedBounds] = i;
+                boundChanges[numberChangedBounds++] = lower[i];
+            }
+            if (upper[i] != lastUpper[i]) {
+                variables[numberChangedBounds] = i | 0x80000000;
+                boundChanges[numberChangedBounds++] = upper[i];
+            }
+#ifdef CBC_DEBUG
+            if (lower[i] != lastLower[i])
+                printf("lower on %d changed from %g to %g\n",
+                       i, lastLower[i], lower[i]);
+            if (upper[i] != lastUpper[i])
+                printf("upper on %d changed from %g to %g\n",
+                       i, lastUpper[i], upper[i]);
+#endif
+        }
+#ifdef CBC_DEBUG
+        printf("%d changed bounds\n", numberChangedBounds) ;
+#endif
+        //if (lastNode->branchingObject()->boundBranch())
+        //assert (numberChangedBounds);
+        /*
+        Hand the lot over to the CbcPartialNodeInfo constructor, then clean up and
+        return.
+        */
+        if (!strategy)
+            nodeInfo_ =
+                new CbcPartialNodeInfo(lastNode->nodeInfo_, this, numberChangedBounds,
+                                       variables, boundChanges, basisDiff) ;
+        else
+            nodeInfo_ = strategy->partialNodeInfo(model, lastNode->nodeInfo_, this, numberChangedBounds,
+                                                  variables, boundChanges, basisDiff) ;
+        delete basisDiff ;
+        delete [] boundChanges;
+        delete [] variables;
+        delete expanded ;
+        if  (mustDeleteBasis)
+            delete ws;
+    }
+    // Set node number
+    nodeInfo_->setNodeNumber(model->getNodeCount2());
+    state_ |= 2; // say active
+}
+
+#endif	// CBC_NEW_CREATEINFO
+/*
+  The routine scans through the object list of the model looking for objects
+  that indicate infeasibility. It tests each object using strong branching
+  and selects the one with the least objective degradation.  A corresponding
+  branching object is left attached to lastNode.
+
+  If strong branching is disabled, a candidate object is chosen essentially
+  at random (whatever object ends up in pos'n 0 of the candidate array).
+
+  If a branching candidate is found to be monotone, bounds are set to fix the
+  variable and the routine immediately returns (the caller is expected to
+  reoptimize).
+
+  If a branching candidate is found to result in infeasibility in both
+  directions, the routine immediately returns an indication of infeasibility.
+
+  Returns:  0	both branch directions are feasible
+  -1	branching variable is monotone
+  -2	infeasible
+
+  Original comments:
+  Here could go cuts etc etc
+  For now just fix on objective from strong branching.
+*/
+
+int CbcNode::chooseBranch (CbcModel *model, CbcNode *lastNode, int numberPassesLeft)
+
+{
+    if (lastNode)
+        depth_ = lastNode->depth_ + 1;
+    else
+        depth_ = 0;
+    delete branch_;
+    branch_ = NULL;
+    OsiSolverInterface * solver = model->solver();
+# ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (solver);
+    int saveClpOptions = 0;
+    if (osiclp) {
+        // for faster hot start
+        saveClpOptions = osiclp->specialOptions();
+        osiclp->setSpecialOptions(saveClpOptions | 8192);
+    }
+# else
+    OsiSolverInterface *osiclp = NULL ;
+# endif
+    double saveObjectiveValue = solver->getObjValue();
+    double objectiveValue = CoinMax(solver->getObjSense() * saveObjectiveValue, objectiveValue_);
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    // See what user thinks
+    int anyAction = model->problemFeasibility()->feasible(model, 0);
+    if (anyAction) {
+        // will return -2 if infeasible , 0 if treat as integer
+        return anyAction - 1;
+    }
+    double integerTolerance =
+        model->getDblParam(CbcModel::CbcIntegerTolerance);
+    // point to useful information
+    OsiBranchingInformation usefulInfo = model->usefulInformation();
+    // and modify
+    usefulInfo.depth_ = depth_;
+    int i;
+    bool beforeSolution = model->getSolutionCount() == 0;
+    int numberStrong = model->numberStrong();
+    // switch off strong if hotstart
+    const double * hotstartSolution = model->hotstartSolution();
+    const int * hotstartPriorities = model->hotstartPriorities();
+    int numberObjects = model->numberObjects();
+    int numberColumns = model->getNumCols();
+    double * saveUpper = new double[numberColumns];
+    double * saveLower = new double[numberColumns];
+    for (i = 0; i < numberColumns; i++) {
+        saveLower[i] = lower[i];
+        saveUpper[i] = upper[i];
+    }
+
+    // Save solution in case heuristics need good solution later
+
+    double * saveSolution = new double[numberColumns];
+    memcpy(saveSolution, solver->getColSolution(), numberColumns*sizeof(double));
+    model->reserveCurrentSolution(saveSolution);
+    if (hotstartSolution) {
+        numberStrong = 0;
+        if ((model->moreSpecialOptions()&1024) != 0) {
+            int nBad = 0;
+            int nUnsat = 0;
+            int nDiff = 0;
+            for (int i = 0; i < numberObjects; i++) {
+                OsiObject * object = model->modifiableObject(i);
+                const CbcSimpleInteger * thisOne = dynamic_cast <const CbcSimpleInteger *> (object);
+                if (thisOne) {
+                    int iColumn = thisOne->columnNumber();
+                    double targetValue = hotstartSolution[iColumn];
+                    double value = saveSolution[iColumn];
+                    if (fabs(value - floor(value + 0.5)) > 1.0e-6) {
+                        nUnsat++;
+#ifdef CLP_INVESTIGATE
+                        printf("H %d is %g target %g\n", iColumn, value, targetValue);
+#endif
+                    } else if (fabs(targetValue - value) > 1.0e-6) {
+                        nDiff++;
+                    }
+                    if (targetValue < saveLower[iColumn] ||
+                            targetValue > saveUpper[iColumn]) {
+#ifdef CLP_INVESTIGATE
+                        printf("%d has target %g and current bounds %g and %g\n",
+                               iColumn, targetValue, saveLower[iColumn], saveUpper[iColumn]);
+#endif
+                        nBad++;
+                    }
+                }
+            }
+#ifdef CLP_INVESTIGATE
+            printf("Hot %d unsatisfied, %d outside limits, %d different\n",
+                   nUnsat, nBad, nDiff);
+#endif
+            if (nBad) {
+                // switch off as not possible
+                hotstartSolution = NULL;
+                model->setHotstartSolution(NULL, NULL);
+                usefulInfo.hotstartSolution_ = NULL;
+            }
+        }
+    }
+    int numberStrongDone = 0;
+    int numberUnfinished = 0;
+    int numberStrongInfeasible = 0;
+    int numberStrongIterations = 0;
+    int saveNumberStrong = numberStrong;
+    bool checkFeasibility = numberObjects > model->numberIntegers();
+    int maximumStrong = CoinMax(CoinMin(numberStrong, numberObjects), 1);
+    /*
+      Get a branching decision object. Use the default decision criteria unless
+      the user has loaded a decision method into the model.
+    */
+    CbcBranchDecision *decision = model->branchingMethod();
+    CbcDynamicPseudoCostBranchingObject * dynamicBranchingObject =
+        dynamic_cast<CbcDynamicPseudoCostBranchingObject *>(decision);
+    if (!decision || dynamicBranchingObject)
+        decision = new CbcBranchDefaultDecision();
+    decision->initialize(model);
+    CbcStrongInfo * choice = new CbcStrongInfo[maximumStrong];
+    // May go round twice if strong branching fixes all local candidates
+    bool finished = false;
+    double estimatedDegradation = 0.0;
+    while (!finished) {
+        finished = true;
+        // Some objects may compute an estimate of best solution from here
+        estimatedDegradation = 0.0;
+        //int numberIntegerInfeasibilities=0; // without odd ones
+        numberStrongDone = 0;
+        numberUnfinished = 0;
+        numberStrongInfeasible = 0;
+        numberStrongIterations = 0;
+
+        // We may go round this loop twice (only if we think we have solution)
+        for (int iPass = 0; iPass < 2; iPass++) {
+
+            // compute current state
+            //int numberObjectInfeasibilities; // just odd ones
+            //model->feasibleSolution(
+            //                      numberIntegerInfeasibilities,
+            //                      numberObjectInfeasibilities);
+            // Some objects may compute an estimate of best solution from here
+            estimatedDegradation = 0.0;
+            numberUnsatisfied_ = 0;
+            // initialize sum of "infeasibilities"
+            sumInfeasibilities_ = 0.0;
+            int bestPriority = COIN_INT_MAX;
+            /*
+              Scan for branching objects that indicate infeasibility. Choose the best
+              maximumStrong candidates, using priority as the first criteria, then
+              integer infeasibility.
+
+              The algorithm is to fill the choice array with a set of good candidates (by
+              infeasibility) with priority bestPriority.  Finding a candidate with
+              priority better (less) than bestPriority flushes the choice array. (This
+              serves as initialization when the first candidate is found.)
+
+              A new candidate is added to choices only if its infeasibility exceeds the
+              current max infeasibility (mostAway). When a candidate is added, it
+              replaces the candidate with the smallest infeasibility (tracked by
+              iSmallest).
+            */
+            int iSmallest = 0;
+            double mostAway = 1.0e-100;
+            for (i = 0 ; i < maximumStrong ; i++)
+                choice[i].possibleBranch = NULL ;
+            numberStrong = 0;
+            bool canDoOneHot = false;
+            for (i = 0; i < numberObjects; i++) {
+                OsiObject * object = model->modifiableObject(i);
+                int preferredWay;
+                double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+                int priorityLevel = object->priority();
+                if (hotstartSolution) {
+                    // we are doing hot start
+                    const CbcSimpleInteger * thisOne = dynamic_cast <const CbcSimpleInteger *> (object);
+                    if (thisOne) {
+                        int iColumn = thisOne->columnNumber();
+                        bool canDoThisHot = true;
+                        double targetValue = hotstartSolution[iColumn];
+                        if (saveUpper[iColumn] > saveLower[iColumn]) {
+                            double value = saveSolution[iColumn];
+                            if (hotstartPriorities)
+                                priorityLevel = hotstartPriorities[iColumn];
+                            //double originalLower = thisOne->originalLower();
+                            //double originalUpper = thisOne->originalUpper();
+                            // switch off if not possible
+                            if (targetValue >= saveLower[iColumn] && targetValue <= saveUpper[iColumn]) {
+                                /* priority outranks rest always if negative
+                                   otherwise can be downgraded if at correct level.
+                                   Infeasibility may be increased to choose 1.0 values first.
+                                   choose one near wanted value
+                                */
+                                if (fabs(value - targetValue) > integerTolerance) {
+                                    //if (infeasibility>0.01)
+                                    //infeasibility = fabs(1.0e6-fabs(value-targetValue));
+                                    //else
+                                    infeasibility = fabs(value - targetValue);
+                                    //if (targetValue==1.0)
+                                    //infeasibility += 1.0;
+                                    if (value > targetValue) {
+                                        preferredWay = -1;
+                                    } else {
+                                        preferredWay = 1;
+                                    }
+                                    priorityLevel = CoinAbs(priorityLevel);
+                                } else if (priorityLevel < 0) {
+                                    priorityLevel = CoinAbs(priorityLevel);
+                                    if (targetValue == saveLower[iColumn]) {
+                                        infeasibility = integerTolerance + 1.0e-12;
+                                        preferredWay = -1;
+                                    } else if (targetValue == saveUpper[iColumn]) {
+                                        infeasibility = integerTolerance + 1.0e-12;
+                                        preferredWay = 1;
+                                    } else {
+                                        // can't
+                                        priorityLevel += 10000000;
+                                        canDoThisHot = false;
+                                    }
+                                } else {
+                                    priorityLevel += 10000000;
+                                    canDoThisHot = false;
+                                }
+                            } else {
+                                // switch off if not possible
+                                canDoThisHot = false;
+                            }
+                            if (canDoThisHot)
+                                canDoOneHot = true;
+                        } else if (targetValue < saveLower[iColumn] || targetValue > saveUpper[iColumn]) {
+                        }
+                    } else {
+                        priorityLevel += 10000000;
+                    }
+                }
+                if (infeasibility) {
+                    // Increase estimated degradation to solution
+                    estimatedDegradation += CoinMin(object->upEstimate(), object->downEstimate());
+                    numberUnsatisfied_++;
+                    sumInfeasibilities_ += infeasibility;
+                    // Better priority? Flush choices.
+                    if (priorityLevel < bestPriority) {
+                        int j;
+                        iSmallest = 0;
+                        for (j = 0; j < maximumStrong; j++) {
+                            choice[j].upMovement = 0.0;
+                            delete choice[j].possibleBranch;
+                            choice[j].possibleBranch = NULL;
+                        }
+                        bestPriority = priorityLevel;
+                        mostAway = 1.0e-100;
+                        numberStrong = 0;
+                    } else if (priorityLevel > bestPriority) {
+                        continue;
+                    }
+                    // Check for suitability based on infeasibility.
+                    if (infeasibility > mostAway) {
+                        //add to list
+                        choice[iSmallest].upMovement = infeasibility;
+                        delete choice[iSmallest].possibleBranch;
+                        CbcObject * obj =
+                            dynamic_cast <CbcObject *>(object) ;
+                        assert (obj);
+                        choice[iSmallest].possibleBranch = obj->createCbcBranch(solver, &usefulInfo, preferredWay);
+                        numberStrong = CoinMax(numberStrong, iSmallest + 1);
+                        // Save which object it was
+                        choice[iSmallest].objectNumber = i;
+                        int j;
+                        iSmallest = -1;
+                        mostAway = 1.0e50;
+                        for (j = 0; j < maximumStrong; j++) {
+                            if (choice[j].upMovement < mostAway) {
+                                mostAway = choice[j].upMovement;
+                                iSmallest = j;
+                            }
+                        }
+                    }
+                }
+            }
+            if (!canDoOneHot && hotstartSolution) {
+                // switch off as not possible
+                hotstartSolution = NULL;
+                model->setHotstartSolution(NULL, NULL);
+                usefulInfo.hotstartSolution_ = NULL;
+            }
+            if (numberUnsatisfied_) {
+                // some infeasibilities - go to next steps
+#ifdef CLP_INVESTIGATE
+                if (hotstartSolution) {
+                    int k = choice[0].objectNumber;
+                    OsiObject * object = model->modifiableObject(k);
+                    const CbcSimpleInteger * thisOne = dynamic_cast <const CbcSimpleInteger *> (object);
+                    assert (thisOne);
+                    int iColumn = thisOne->columnNumber();
+                    double targetValue = hotstartSolution[iColumn];
+                    double value = saveSolution[iColumn];
+                    printf("Branch on %d has target %g (value %g) and current bounds %g and %g\n",
+                           iColumn, targetValue, value, saveLower[iColumn], saveUpper[iColumn]);
+                }
+#endif
+                break;
+            } else if (!iPass) {
+                // looks like a solution - get paranoid
+                bool roundAgain = false;
+                // get basis
+                CoinWarmStartBasis * ws = dynamic_cast<CoinWarmStartBasis*>(solver->getWarmStart());
+                if (!ws)
+                    break;
+                for (i = 0; i < numberColumns; i++) {
+                    double value = saveSolution[i];
+                    if (value < lower[i]) {
+                        saveSolution[i] = lower[i];
+                        roundAgain = true;
+                        ws->setStructStatus(i, CoinWarmStartBasis::atLowerBound);
+                    } else if (value > upper[i]) {
+                        saveSolution[i] = upper[i];
+                        roundAgain = true;
+                        ws->setStructStatus(i, CoinWarmStartBasis::atUpperBound);
+                    }
+                }
+                if (roundAgain && saveNumberStrong) {
+                    // restore basis
+                    solver->setWarmStart(ws);
+                    delete ws;
+                    solver->resolve();
+                    memcpy(saveSolution, solver->getColSolution(), numberColumns*sizeof(double));
+                    model->reserveCurrentSolution(saveSolution);
+                    if (!solver->isProvenOptimal()) {
+                        // infeasible
+                        anyAction = -2;
+                        break;
+                    }
+                } else {
+                    delete ws;
+                    break;
+                }
+            }
+        }
+        /* Some solvers can do the strong branching calculations faster if
+           they do them all at once.  At present only Clp does for ordinary
+           integers but I think this coding would be easy to modify
+        */
+        bool allNormal = true; // to say if we can do fast strong branching
+        // Say which one will be best
+        int bestChoice = 0;
+        double worstInfeasibility = 0.0;
+        for (i = 0; i < numberStrong; i++) {
+            choice[i].numIntInfeasUp = numberUnsatisfied_;
+            choice[i].numIntInfeasDown = numberUnsatisfied_;
+            choice[i].fix = 0; // say not fixed
+            if (!dynamic_cast <const CbcSimpleInteger *> (model->object(choice[i].objectNumber)))
+                allNormal = false; // Something odd so lets skip clever fast branching
+            if ( !model->object(choice[i].objectNumber)->boundBranch())
+                numberStrong = 0; // switch off
+            if ( choice[i].possibleBranch->numberBranches() > 2)
+                numberStrong = 0; // switch off
+            // Do best choice in case switched off
+            if (choice[i].upMovement > worstInfeasibility) {
+                worstInfeasibility = choice[i].upMovement;
+                bestChoice = i;
+            }
+        }
+        // If we have hit max time don't do strong branching
+        bool hitMaxTime = (model->getCurrentSeconds() >
+                            model->getDblParam(CbcModel::CbcMaximumSeconds));
+        // also give up if we are looping round too much
+        if (hitMaxTime || numberPassesLeft <= 0)
+            numberStrong = 0;
+        /*
+          Is strong branching enabled? If so, set up and do it. Otherwise, we'll
+          fall through to simple branching.
+
+          Setup for strong branching involves saving the current basis (for restoration
+          afterwards) and setting up for hot starts.
+        */
+        if (numberStrong && saveNumberStrong) {
+
+            bool solveAll = false; // set true to say look at all even if some fixed (experiment)
+            solveAll = true;
+            // worth trying if too many times
+            // Save basis
+            CoinWarmStart * ws = solver->getWarmStart();
+            // save limit
+            int saveLimit;
+            solver->getIntParam(OsiMaxNumIterationHotStart, saveLimit);
+            if (beforeSolution && saveLimit < 100)
+                solver->setIntParam(OsiMaxNumIterationHotStart, 100); // go to end
+#     ifdef COIN_HAS_CLP
+            /* If we are doing all strong branching in one go then we create new arrays
+               to store information.  If clp NULL then doing old way.
+               Going down -
+               outputSolution[2*i] is final solution.
+               outputStuff[2*i] is status (0 - finished, 1 infeas, other unknown
+               outputStuff[2*i+numberStrong] is number iterations
+               On entry newUpper[i] is new upper bound, on exit obj change
+               Going up -
+               outputSolution[2*i+1] is final solution.
+               outputStuff[2*i+1] is status (0 - finished, 1 infeas, other unknown
+               outputStuff[2*i+1+numberStrong] is number iterations
+            On entry newLower[i] is new lower bound, on exit obj change
+            */
+            ClpSimplex * clp = NULL;
+            double * newLower = NULL;
+            double * newUpper = NULL;
+            double ** outputSolution = NULL;
+            int * outputStuff = NULL;
+            // Go back to normal way if user wants it
+            if (osiclp && (osiclp->specialOptions()&16) != 0 && osiclp->specialOptions() > 0)
+                allNormal = false;
+            if (osiclp && !allNormal) {
+                // say do fast
+                int easy = 1;
+                osiclp->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, &easy) ;
+            }
+            if (osiclp && allNormal) {
+                clp = osiclp->getModelPtr();
+                // Clp - do a different way
+                newLower = new double[numberStrong];
+                newUpper = new double[numberStrong];
+                outputSolution = new double * [2*numberStrong];
+                outputStuff = new int [4*numberStrong];
+                int * which = new int[numberStrong];
+                int startFinishOptions;
+                int specialOptions = osiclp->specialOptions();
+                int clpOptions = clp->specialOptions();
+                int returnCode = 0;
+#define CRUNCH
+#ifdef CRUNCH
+                // Crunch down problem
+                int numberRows = clp->numberRows();
+                // Use dual region
+                double * rhs = clp->dualRowSolution();
+                int * whichRow = new int[3*numberRows];
+                int * whichColumn = new int[2*numberColumns];
+                int nBound;
+                ClpSimplex * small = static_cast<ClpSimplexOther *> (clp)->crunch(rhs, whichRow, whichColumn, nBound, true);
+                if (!small) {
+                    anyAction = -2;
+                    //printf("XXXX Inf by inspection\n");
+                    delete [] whichColumn;
+                    whichColumn = NULL;
+                    delete [] whichRow;
+                    whichRow = NULL;
+                    break;
+                } else {
+                    clp = small;
+                }
+#else
+                int saveLogLevel = clp->logLevel();
+                int saveMaxIts = clp->maximumIterations();
+#endif
+                clp->setLogLevel(0);
+                if ((specialOptions&1) == 0) {
+                    startFinishOptions = 0;
+                    clp->setSpecialOptions(clpOptions | (64 | 1024));
+                } else {
+                    startFinishOptions = 1 + 2 + 4;
+                    //startFinishOptions=1+4; // for moment re-factorize
+                    if ((specialOptions&4) == 0)
+                        clp->setSpecialOptions(clpOptions | (64 | 128 | 512 | 1024 | 4096));
+                    else
+                        clp->setSpecialOptions(clpOptions | (64 | 128 | 512 | 1024 | 2048 | 4096));
+                }
+                // User may want to clean up before strong branching
+                if ((clp->specialOptions()&32) != 0) {
+                    clp->primal(1);
+                    if (clp->numberIterations())
+                        model->messageHandler()->message(CBC_ITERATE_STRONG, *model->messagesPointer())
+                        << clp->numberIterations()
+                        << CoinMessageEol;
+                }
+                clp->setMaximumIterations(saveLimit);
+#ifdef CRUNCH
+                int * backColumn = whichColumn + numberColumns;
+#endif
+                for (i = 0; i < numberStrong; i++) {
+                    int iObject = choice[i].objectNumber;
+                    const OsiObject * object = model->object(iObject);
+                    const CbcSimpleInteger * simple = static_cast <const CbcSimpleInteger *> (object);
+                    int iSequence = simple->columnNumber();
+                    newLower[i] = ceil(saveSolution[iSequence]);
+                    newUpper[i] = floor(saveSolution[iSequence]);
+#ifdef CRUNCH
+                    iSequence = backColumn[iSequence];
+                    assert (iSequence >= 0);
+#endif
+                    which[i] = iSequence;
+                    outputSolution[2*i] = new double [numberColumns];
+                    outputSolution[2*i+1] = new double [numberColumns];
+                }
+                //clp->writeMps("bad");
+                returnCode = clp->strongBranching(numberStrong, which,
+                                                  newLower, newUpper, outputSolution,
+                                                  outputStuff, outputStuff + 2 * numberStrong, !solveAll, false,
+                                                  startFinishOptions);
+#ifndef CRUNCH
+                clp->setSpecialOptions(clpOptions); // restore
+                clp->setMaximumIterations(saveMaxIts);
+                clp->setLogLevel(saveLogLevel);
+#endif
+                if (returnCode == -2) {
+                    // bad factorization!!!
+                    // Doing normal way
+                    // Mark hot start
+                    solver->markHotStart();
+                    clp = NULL;
+                } else {
+#ifdef CRUNCH
+                    // extract solution
+                    //bool checkSol=true;
+                    for (i = 0; i < numberStrong; i++) {
+                        int iObject = choice[i].objectNumber;
+                        const OsiObject * object = model->object(iObject);
+                        const CbcSimpleInteger * simple = static_cast <const CbcSimpleInteger *> (object);
+                        int iSequence = simple->columnNumber();
+                        which[i] = iSequence;
+                        double * sol = outputSolution[2*i];
+                        double * sol2 = outputSolution[2*i+1];
+                        //bool x=true;
+                        //bool x2=true;
+                        for (int iColumn = numberColumns - 1; iColumn >= 0; iColumn--) {
+                            int jColumn = backColumn[iColumn];
+                            if (jColumn >= 0) {
+                                sol[iColumn] = sol[jColumn];
+                                sol2[iColumn] = sol2[jColumn];
+                            } else {
+                                sol[iColumn] = saveSolution[iColumn];
+                                sol2[iColumn] = saveSolution[iColumn];
+                            }
+                        }
+                    }
+#endif
+                }
+#ifdef CRUNCH
+                delete [] whichColumn;
+                delete [] whichRow;
+                delete small;
+#endif
+                delete [] which;
+            } else {
+                // Doing normal way
+                // Mark hot start
+                solver->markHotStart();
+            }
+#     else	/* COIN_HAS_CLP */
+
+            OsiSolverInterface *clp = NULL ;
+            double **outputSolution = NULL ;
+            int *outputStuff = NULL ;
+            double * newLower = NULL ;
+            double * newUpper = NULL ;
+
+            solver->markHotStart();
+
+#     endif	/* COIN_HAS_CLP */
+            /*
+              Open a loop to do the strong branching LPs. For each candidate variable,
+              solve an LP with the variable forced down, then up. If a direction turns
+              out to be infeasible or monotonic (i.e., over the dual objective cutoff),
+              force the objective change to be big (1.0e100). If we determine the problem
+              is infeasible, or find a monotone variable, escape the loop.
+
+              TODO: The `restore bounds' part might be better encapsulated as an
+            unbranch() method. Branching objects more exotic than simple integers
+            or cliques might not restrict themselves to variable bounds.
+
+              TODO: Virtuous solvers invalidate the current solution (or give bogus
+            results :-) when the bounds are changed out from under them. So we
+            need to do all the work associated with finding a new solution before
+            restoring the bounds.
+            */
+            for (i = 0 ; i < numberStrong ; i++) {
+                double objectiveChange ;
+                double newObjectiveValue = 1.0e100;
+                // status is 0 finished, 1 infeasible and other
+                int iStatus;
+                /*
+                  Try the down direction first. (Specify the initial branching alternative as
+                  down with a call to way(-1). Each subsequent call to branch() performs the
+                  specified branch and advances the branch object state to the next branch
+                  alternative.)
+                */
+                if (!clp) {
+                    choice[i].possibleBranch->way(-1) ;
+                    choice[i].possibleBranch->branch() ;
+                    bool feasible = true;
+                    if (checkFeasibility) {
+                        // check branching did not make infeasible
+                        int iColumn;
+                        int numberColumns = solver->getNumCols();
+                        const double * columnLower = solver->getColLower();
+                        const double * columnUpper = solver->getColUpper();
+                        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                            if (columnLower[iColumn] > columnUpper[iColumn] + 1.0e-5)
+                                feasible = false;
+                        }
+                    }
+                    if (feasible) {
+                        solver->solveFromHotStart() ;
+                        numberStrongDone++;
+                        numberStrongIterations += solver->getIterationCount();
+                        /*
+                        We now have an estimate of objective degradation that we can use for strong
+                        branching. If we're over the cutoff, the variable is monotone up.
+                        If we actually made it to optimality, check for a solution, and if we have
+                        a good one, call setBestSolution to process it. Note that this may reduce the
+                        cutoff, so we check again to see if we can declare this variable monotone.
+                        */
+                        if (solver->isProvenOptimal())
+                            iStatus = 0; // optimal
+                        else if (solver->isIterationLimitReached()
+                                 && !solver->isDualObjectiveLimitReached())
+                            iStatus = 2; // unknown
+                        else
+                            iStatus = 1; // infeasible
+                        newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+                        choice[i].numItersDown = solver->getIterationCount();
+                    } else {
+                        iStatus = 1; // infeasible
+                        newObjectiveValue = 1.0e100;
+                        choice[i].numItersDown = 0;
+                    }
+                } else {
+                    iStatus = outputStuff[2*i];
+                    choice[i].numItersDown = outputStuff[2*numberStrong+2*i];
+                    numberStrongDone++;
+                    numberStrongIterations += choice[i].numItersDown;
+                    newObjectiveValue = objectiveValue + newUpper[i];
+                    solver->setColSolution(outputSolution[2*i]);
+                }
+                objectiveChange = CoinMax(newObjectiveValue  - objectiveValue_, 0.0);
+                if (!iStatus) {
+                    choice[i].finishedDown = true ;
+                    if (newObjectiveValue >= model->getCutoff()) {
+                        objectiveChange = 1.0e100; // say infeasible
+                        numberStrongInfeasible++;
+                    } else {
+                        // See if integer solution
+                        if (model->feasibleSolution(choice[i].numIntInfeasDown,
+                                                    choice[i].numObjInfeasDown)
+                                && model->problemFeasibility()->feasible(model, -1) >= 0) {
+                            model->setBestSolution(CBC_STRONGSOL,
+                                                   newObjectiveValue,
+                                                   solver->getColSolution()) ;
+                            // only needed for odd solvers
+                            newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+                            objectiveChange = CoinMax(newObjectiveValue - objectiveValue_, 0.0) ;
+                            model->setLastHeuristic(NULL);
+                            model->incrementUsed(solver->getColSolution());
+                            if (newObjectiveValue >= model->getCutoff()) {	//  *new* cutoff
+                                objectiveChange = 1.0e100 ;
+                                numberStrongInfeasible++;
+                            }
+                        }
+                    }
+                } else if (iStatus == 1) {
+                    objectiveChange = 1.0e100 ;
+                    numberStrongInfeasible++;
+                } else {
+                    // Can't say much as we did not finish
+                    choice[i].finishedDown = false ;
+                    numberUnfinished++;
+                }
+                choice[i].downMovement = objectiveChange ;
+
+                // restore bounds
+                if (!clp) {
+                    for (int j = 0; j < numberColumns; j++) {
+                        if (saveLower[j] != lower[j])
+                            solver->setColLower(j, saveLower[j]);
+                        if (saveUpper[j] != upper[j])
+                            solver->setColUpper(j, saveUpper[j]);
+                    }
+                }
+                //printf("Down on %d, status is %d, obj %g its %d cost %g finished %d inf %d infobj %d\n",
+                //     choice[i].objectNumber,iStatus,newObjectiveValue,choice[i].numItersDown,
+                //     choice[i].downMovement,choice[i].finishedDown,choice[i].numIntInfeasDown,
+                //     choice[i].numObjInfeasDown);
+
+                // repeat the whole exercise, forcing the variable up
+                if (!clp) {
+                    bool feasible = true;
+                    // If odd branching then maybe just one possibility
+                    if (choice[i].possibleBranch->numberBranchesLeft() > 0) {
+                        choice[i].possibleBranch->branch();
+                        if (checkFeasibility) {
+                            // check branching did not make infeasible
+                            int iColumn;
+                            int numberColumns = solver->getNumCols();
+                            const double * columnLower = solver->getColLower();
+                            const double * columnUpper = solver->getColUpper();
+                            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                if (columnLower[iColumn] > columnUpper[iColumn] + 1.0e-5)
+                                    feasible = false;
+                            }
+                        }
+                    } else {
+                        // second branch infeasible
+                        feasible = false;
+                    }
+                    if (feasible) {
+                        solver->solveFromHotStart() ;
+                        numberStrongDone++;
+                        numberStrongIterations += solver->getIterationCount();
+                        /*
+                        We now have an estimate of objective degradation that we can use for strong
+                        branching. If we're over the cutoff, the variable is monotone up.
+                        If we actually made it to optimality, check for a solution, and if we have
+                        a good one, call setBestSolution to process it. Note that this may reduce the
+                        cutoff, so we check again to see if we can declare this variable monotone.
+                        */
+                        if (solver->isProvenOptimal())
+                            iStatus = 0; // optimal
+                        else if (solver->isIterationLimitReached()
+                                 && !solver->isDualObjectiveLimitReached())
+                            iStatus = 2; // unknown
+                        else
+                            iStatus = 1; // infeasible
+                        newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+                        choice[i].numItersUp = solver->getIterationCount();
+                    } else {
+                        iStatus = 1; // infeasible
+                        newObjectiveValue = 1.0e100;
+                        choice[i].numItersDown = 0;
+                    }
+                } else {
+                    iStatus = outputStuff[2*i+1];
+                    choice[i].numItersUp = outputStuff[2*numberStrong+2*i+1];
+                    numberStrongDone++;
+                    numberStrongIterations += choice[i].numItersUp;
+                    newObjectiveValue = objectiveValue + newLower[i];
+                    solver->setColSolution(outputSolution[2*i+1]);
+                }
+                objectiveChange = CoinMax(newObjectiveValue  - objectiveValue_, 0.0);
+                if (!iStatus) {
+                    choice[i].finishedUp = true ;
+                    if (newObjectiveValue >= model->getCutoff()) {
+                        objectiveChange = 1.0e100; // say infeasible
+                        numberStrongInfeasible++;
+                    } else {
+                        // See if integer solution
+                        if (model->feasibleSolution(choice[i].numIntInfeasUp,
+                                                    choice[i].numObjInfeasUp)
+                                && model->problemFeasibility()->feasible(model, -1) >= 0) {
+                            model->setBestSolution(CBC_STRONGSOL,
+                                                   newObjectiveValue,
+                                                   solver->getColSolution()) ;
+                            // only needed for odd solvers
+                            newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+                            objectiveChange = CoinMax(newObjectiveValue - objectiveValue_, 0.0) ;
+                            model->setLastHeuristic(NULL);
+                            model->incrementUsed(solver->getColSolution());
+                            if (newObjectiveValue >= model->getCutoff()) {	//  *new* cutoff
+                                objectiveChange = 1.0e100 ;
+                                numberStrongInfeasible++;
+                            }
+                        }
+                    }
+                } else if (iStatus == 1) {
+                    objectiveChange = 1.0e100 ;
+                    numberStrongInfeasible++;
+                } else {
+                    // Can't say much as we did not finish
+                    choice[i].finishedUp = false ;
+                    numberUnfinished++;
+                }
+                choice[i].upMovement = objectiveChange ;
+
+                // restore bounds
+                if (!clp) {
+                    for (int j = 0; j < numberColumns; j++) {
+                        if (saveLower[j] != lower[j])
+                            solver->setColLower(j, saveLower[j]);
+                        if (saveUpper[j] != upper[j])
+                            solver->setColUpper(j, saveUpper[j]);
+                    }
+                }
+
+                //printf("Up on %d, status is %d, obj %g its %d cost %g finished %d inf %d infobj %d\n",
+                //     choice[i].objectNumber,iStatus,newObjectiveValue,choice[i].numItersUp,
+                //     choice[i].upMovement,choice[i].finishedUp,choice[i].numIntInfeasUp,
+                //     choice[i].numObjInfeasUp);
+
+                /*
+                  End of evaluation for this candidate variable. Possibilities are:
+                  * Both sides below cutoff; this variable is a candidate for branching.
+                  * Both sides infeasible or above the objective cutoff: no further action
+                  here. Break from the evaluation loop and assume the node will be purged
+                  by the caller.
+                  * One side below cutoff: Install the branch (i.e., fix the variable). Break
+                  from the evaluation loop and assume the node will be reoptimised by the
+                  caller.
+                */
+                // reset
+                choice[i].possibleBranch->resetNumberBranchesLeft();
+                if (choice[i].upMovement < 1.0e100) {
+                    if (choice[i].downMovement < 1.0e100) {
+                        // feasible - no action
+                    } else {
+                        // up feasible, down infeasible
+                        anyAction = -1;
+                        //printf("Down infeasible for choice %d sequence %d\n",i,
+                        // model->object(choice[i].objectNumber)->columnNumber());
+                        if (!solveAll) {
+                            choice[i].possibleBranch->way(1);
+                            choice[i].possibleBranch->branch();
+                            break;
+                        } else {
+                            choice[i].fix = 1;
+                        }
+                    }
+                } else {
+                    if (choice[i].downMovement < 1.0e100) {
+                        // down feasible, up infeasible
+                        anyAction = -1;
+                        //printf("Up infeasible for choice %d sequence %d\n",i,
+                        // model->object(choice[i].objectNumber)->columnNumber());
+                        if (!solveAll) {
+                            choice[i].possibleBranch->way(-1);
+                            choice[i].possibleBranch->branch();
+                            break;
+                        } else {
+                            choice[i].fix = -1;
+                        }
+                    } else {
+                        // neither side feasible
+                        anyAction = -2;
+                        //printf("Both infeasible for choice %d sequence %d\n",i,
+                        // model->object(choice[i].objectNumber)->columnNumber());
+                        break;
+                    }
+                }
+		bool hitMaxTime = (model->getCurrentSeconds() >
+                                    model->getDblParam(CbcModel::CbcMaximumSeconds));
+                if (hitMaxTime) {
+                    numberStrong = i + 1;
+                    break;
+                }
+            }
+            if (!clp) {
+                // Delete the snapshot
+                solver->unmarkHotStart();
+            } else {
+                delete [] newLower;
+                delete [] newUpper;
+                delete [] outputStuff;
+                int i;
+                for (i = 0; i < 2*numberStrong; i++)
+                    delete [] outputSolution[i];
+                delete [] outputSolution;
+            }
+            solver->setIntParam(OsiMaxNumIterationHotStart, saveLimit);
+            // restore basis
+            solver->setWarmStart(ws);
+            // Unless infeasible we will carry on
+            // But we could fix anyway
+            if (anyAction == -1 && solveAll) {
+                // apply and take off
+                for (i = 0 ; i < numberStrong ; i++) {
+                    if (choice[i].fix) {
+                        choice[i].possibleBranch->way(choice[i].fix) ;
+                        choice[i].possibleBranch->branch() ;
+                    }
+                }
+                bool feasible = true;
+                if (checkFeasibility) {
+                    // check branching did not make infeasible
+                    int iColumn;
+                    int numberColumns = solver->getNumCols();
+                    const double * columnLower = solver->getColLower();
+                    const double * columnUpper = solver->getColUpper();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        if (columnLower[iColumn] > columnUpper[iColumn] + 1.0e-5)
+                            feasible = false;
+                    }
+                }
+                if (feasible) {
+                    // can do quick optimality check
+                    int easy = 2;
+                    solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, &easy) ;
+                    solver->resolve() ;
+                    solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+                    feasible = solver->isProvenOptimal();
+                }
+                if (feasible) {
+                    memcpy(saveSolution, solver->getColSolution(), numberColumns*sizeof(double));
+                    model->reserveCurrentSolution(saveSolution);
+                    memcpy(saveLower, solver->getColLower(), numberColumns*sizeof(double));
+                    memcpy(saveUpper, solver->getColUpper(), numberColumns*sizeof(double));
+                    // Clean up all candidates whih are fixed
+                    int numberLeft = 0;
+                    for (i = 0 ; i < numberStrong ; i++) {
+                        CbcStrongInfo thisChoice = choice[i];
+                        choice[i].possibleBranch = NULL;
+                        const OsiObject * object = model->object(thisChoice.objectNumber);
+                        int preferredWay;
+                        double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+                        if (!infeasibility) {
+                            // take out
+                            delete thisChoice.possibleBranch;
+                        } else {
+                            choice[numberLeft++] = thisChoice;
+                        }
+                    }
+                    numberStrong = numberLeft;
+                    for (; i < maximumStrong; i++) {
+                        delete choice[i].possibleBranch;
+                        choice[i].possibleBranch = NULL;
+                    }
+                    // If all fixed then round again
+                    if (!numberLeft) {
+                        finished = false;
+                        numberStrong = 0;
+                        saveNumberStrong = 0;
+                        maximumStrong = 1;
+                    } else {
+                        anyAction = 0;
+                    }
+                    // If these two uncommented then different action
+                    anyAction = -1;
+                    finished = true;
+                    //printf("some fixed but continuing %d left\n",numberLeft);
+                } else {
+                    anyAction = -2; // say infeasible
+                }
+            }
+            delete ws;
+            //int numberNodes = model->getNodeCount();
+            // update number of strong iterations etc
+            model->incrementStrongInfo(numberStrongDone, numberStrongIterations,
+                                       anyAction == -2 ? 0 : numberStrongInfeasible, anyAction == -2);
+
+            /*
+              anyAction >= 0 indicates that strong branching didn't produce any monotone
+              variables. Sift through the candidates for the best one.
+
+              QUERY: Setting numberNodes looks to be a distributed noop. numberNodes is
+              local to this code block. Perhaps should be numberNodes_ from model?
+              Unclear what this calculation is doing.
+            */
+            if (anyAction >= 0) {
+
+                // get average cost per iteration and assume stopped ones
+                // would stop after 50% more iterations at average cost??? !!! ???
+                double averageCostPerIteration = 0.0;
+                double totalNumberIterations = 1.0;
+                int smallestNumberInfeasibilities = COIN_INT_MAX;
+                for (i = 0; i < numberStrong; i++) {
+                    totalNumberIterations += choice[i].numItersDown +
+                                             choice[i].numItersUp ;
+                    averageCostPerIteration += choice[i].downMovement +
+                                               choice[i].upMovement;
+                    smallestNumberInfeasibilities =
+                        CoinMin(CoinMin(choice[i].numIntInfeasDown ,
+                                        choice[i].numIntInfeasUp ),
+                                smallestNumberInfeasibilities);
+                }
+                //if (smallestNumberInfeasibilities>=numberIntegerInfeasibilities)
+                //numberNodes=1000000; // switch off search for better solution
+                averageCostPerIteration /= totalNumberIterations;
+                // all feasible - choose best bet
+
+                // New method does all at once so it can be more sophisticated
+                // in deciding how to balance actions.
+                // But it does need arrays
+                double * changeUp = new double [numberStrong];
+                int * numberInfeasibilitiesUp = new int [numberStrong];
+                double * changeDown = new double [numberStrong];
+                int * numberInfeasibilitiesDown = new int [numberStrong];
+                CbcBranchingObject ** objects = new CbcBranchingObject * [ numberStrong];
+                for (i = 0 ; i < numberStrong ; i++) {
+                    int iColumn = choice[i].possibleBranch->variable() ;
+                    model->messageHandler()->message(CBC_STRONG, *model->messagesPointer())
+                    << i << iColumn
+                    << choice[i].downMovement << choice[i].numIntInfeasDown
+                    << choice[i].upMovement << choice[i].numIntInfeasUp
+                    << choice[i].possibleBranch->value()
+                    << CoinMessageEol;
+                    changeUp[i] = choice[i].upMovement;
+                    numberInfeasibilitiesUp[i] = choice[i].numIntInfeasUp;
+                    changeDown[i] = choice[i].downMovement;
+                    numberInfeasibilitiesDown[i] = choice[i].numIntInfeasDown;
+                    objects[i] = choice[i].possibleBranch;
+                }
+                int whichObject = decision->bestBranch(objects, numberStrong, numberUnsatisfied_,
+                                                       changeUp, numberInfeasibilitiesUp,
+                                                       changeDown, numberInfeasibilitiesDown,
+                                                       objectiveValue_);
+                // move branching object and make sure it will not be deleted
+                if (whichObject >= 0) {
+                    branch_ = objects[whichObject];
+                    if (model->messageHandler()->logLevel() > 3)
+                        printf("Choosing column %d\n", choice[whichObject].possibleBranch->variable()) ;
+                    choice[whichObject].possibleBranch = NULL;
+                }
+                delete [] changeUp;
+                delete [] numberInfeasibilitiesUp;
+                delete [] changeDown;
+                delete [] numberInfeasibilitiesDown;
+                delete [] objects;
+            }
+#     ifdef COIN_HAS_CLP
+            if (osiclp && !allNormal) {
+                // back to normal
+                osiclp->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+            }
+#     endif
+        }
+        /*
+          Simple branching. Probably just one, but we may have got here
+          because of an odd branch e.g. a cut
+        */
+        else {
+            // not strong
+            // C) create branching object
+            branch_ = choice[bestChoice].possibleBranch;
+            choice[bestChoice].possibleBranch = NULL;
+        }
+    }
+    // Set guessed solution value
+    guessedObjectiveValue_ = objectiveValue_ + estimatedDegradation;
+    /*
+      Cleanup, then we're outta here.
+    */
+    if (!model->branchingMethod() || dynamicBranchingObject)
+        delete decision;
+
+    for (i = 0; i < maximumStrong; i++)
+        delete choice[i].possibleBranch;
+    delete [] choice;
+    delete [] saveLower;
+    delete [] saveUpper;
+
+    // restore solution
+    solver->setColSolution(saveSolution);
+    delete [] saveSolution;
+# ifdef COIN_HAS_CLP
+    if (osiclp)
+        osiclp->setSpecialOptions(saveClpOptions);
+# endif
+    return anyAction;
+}
+
+/*
+  Version for dynamic pseudo costs.
+
+  **** For now just return if anything odd
+  later allow even if odd
+
+  The routine scans through the object list of the model looking for objects
+  that indicate infeasibility. It tests each object using strong branching
+  and selects the one with the least objective degradation.  A corresponding
+  branching object is left attached to lastNode.
+  This version gives preference in evaluation to variables which
+  have not been evaluated many times.  It also uses numberStrong
+  to say give up if last few tries have not changed incumbent.
+  See Achterberg, Koch and Martin.
+
+  If strong branching is disabled, a candidate object is chosen essentially
+  at random (whatever object ends up in pos'n 0 of the candidate array).
+
+  If a branching candidate is found to be monotone, bounds are set to fix the
+  variable and the routine immediately returns (the caller is expected to
+  reoptimize).
+
+  If a branching candidate is found to result in infeasibility in both
+  directions, the routine immediately returns an indication of infeasibility.
+
+  Returns:  0	both branch directions are feasible
+  -1	branching variable is monotone
+  -2	infeasible
+  -3   Use another method
+
+  For now just fix on objective from strong branching.
+*/
+
+int CbcNode::chooseDynamicBranch (CbcModel *model, CbcNode *lastNode,
+                                  OsiSolverBranch * & /*branches*/,
+                                  int numberPassesLeft)
+
+{
+    if (lastNode)
+        depth_ = lastNode->depth_ + 1;
+    else
+        depth_ = 0;
+    // Go to other choose if hot start
+    if (model->hotstartSolution() &&
+            (((model->moreSpecialOptions()&1024) == 0) || false))
+        return -3;
+    delete branch_;
+    branch_ = NULL;
+    OsiSolverInterface * solver = model->solver();
+    // get information on solver type
+    const OsiAuxInfo * auxInfo = solver->getAuxiliaryInfo();
+    const OsiBabSolver * auxiliaryInfo = dynamic_cast<const OsiBabSolver *> (auxInfo);
+    if (!auxiliaryInfo) {
+        // use one from CbcModel
+        auxiliaryInfo = model->solverCharacteristics();
+    }
+    int numberObjects = model->numberObjects();
+    // If very odd set of objects then use older chooseBranch
+    bool useOldWay = false;
+    // point to useful information
+    OsiBranchingInformation usefulInfo = model->usefulInformation();
+    if (numberObjects > model->numberIntegers()) {
+        for (int i = model->numberIntegers(); i < numberObjects; i++) {
+            OsiObject * object = model->modifiableObject(i);
+            CbcObject * obj =	dynamic_cast <CbcObject *>(object) ;
+            if (!obj || !obj->optionalObject()) {
+                int preferredWay;
+                double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+                if (infeasibility) {
+                    useOldWay = true;
+                    break;
+                }
+            } else {
+	      obj->initializeForBranching(model);
+	    }
+        }
+    }
+    if ((model->specialOptions()&128) != 0)
+        useOldWay = false; // allow
+    // For now return if not simple
+    if (useOldWay)
+        return -3;
+    // Modify useful info
+    usefulInfo.depth_ = depth_;
+    if ((model->specialOptions()&128) != 0) {
+        // SOS - shadow prices
+        int numberRows = solver->getNumRows();
+        const double * pi = usefulInfo.pi_;
+        double sumPi = 0.0;
+        for (int i = 0; i < numberRows; i++)
+            sumPi += fabs(pi[i]);
+        sumPi /= static_cast<double> (numberRows);
+        // and scale back
+        sumPi *= 0.01;
+        usefulInfo.defaultDual_ = sumPi; // switch on
+        int numberColumns = solver->getNumCols();
+        int size = CoinMax(numberColumns, 2 * numberRows);
+        usefulInfo.usefulRegion_ = new double [size];
+        CoinZeroN(usefulInfo.usefulRegion_, size);
+        usefulInfo.indexRegion_ = new int [size];
+        // pi may change
+        usefulInfo.pi_ = CoinCopyOfArray(usefulInfo.pi_, numberRows);
+    }
+    assert (auxiliaryInfo);
+    double cutoff = model->getCutoff();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    // See if user thinks infeasible
+    int anyAction = model->problemFeasibility()->feasible(model, 0);
+    if (anyAction) {
+        // will return -2 if infeasible , 0 if treat as integer
+        return anyAction - 1;
+    }
+    int i;
+    int saveStateOfSearch = model->stateOfSearch() % 10;
+    int numberStrong = model->numberStrong();
+    /* Ranging is switched off.
+       The idea is that you can find out the effect of one iteration
+       on each unsatisfied variable cheaply.  Then use this
+       if you have not got much else to go on.
+    */
+    //#define RANGING
+#ifdef RANGING
+    // must have clp
+#ifndef COIN_HAS_CLP
+#  warning("Ranging switched off as not Clp");
+#undef RANGING
+#endif
+    // Pass number
+    int kPass = 0;
+    int numberRows = solver->getNumRows();
+#endif
+    int numberColumns = model->getNumCols();
+    double * saveUpper = new double[numberColumns];
+    double * saveLower = new double[numberColumns];
+    for (i = 0; i < numberColumns; i++) {
+        saveLower[i] = lower[i];
+        saveUpper[i] = upper[i];
+    }
+
+    // Save solution in case heuristics need good solution later
+
+    double * saveSolution = new double[numberColumns];
+    memcpy(saveSolution, solver->getColSolution(), numberColumns*sizeof(double));
+    model->reserveCurrentSolution(saveSolution);
+    const double * hotstartSolution = model->hotstartSolution();
+    const int * hotstartPriorities = model->hotstartPriorities();
+    double integerTolerance =
+        model->getDblParam(CbcModel::CbcIntegerTolerance);
+    if (hotstartSolution) {
+        if ((model->moreSpecialOptions()&1024) != 0) {
+            int nBad = 0;
+            int nUnsat = 0;
+            int nDiff = 0;
+            for (int i = 0; i < numberObjects; i++) {
+                OsiObject * object = model->modifiableObject(i);
+                const CbcSimpleInteger * thisOne = dynamic_cast <const CbcSimpleInteger *> (object);
+                if (thisOne) {
+                    int iColumn = thisOne->columnNumber();
+                    double targetValue = hotstartSolution[iColumn];
+                    double value = saveSolution[iColumn];
+                    if (fabs(value - floor(value + 0.5)) > 1.0e-6) {
+                        nUnsat++;
+#ifdef CLP_INVESTIGATE
+                        printf("H %d is %g target %g\n", iColumn, value, targetValue);
+#endif
+                    } else if (fabs(targetValue - value) > 1.0e-6) {
+                        nDiff++;
+                    }
+                    if (targetValue < saveLower[iColumn] ||
+                            targetValue > saveUpper[iColumn]) {
+#ifdef CLP_INVESTIGATE
+                        printf("%d has target %g and current bounds %g and %g\n",
+                               iColumn, targetValue, saveLower[iColumn], saveUpper[iColumn]);
+#endif
+                        nBad++;
+                    }
+                }
+            }
+#ifdef CLP_INVESTIGATE
+            printf("Hot %d unsatisfied, %d outside limits, %d different\n",
+                   nUnsat, nBad, nDiff);
+#endif
+            if (nBad) {
+                // switch off as not possible
+                hotstartSolution = NULL;
+                model->setHotstartSolution(NULL, NULL);
+                usefulInfo.hotstartSolution_ = NULL;
+            }
+        }
+    }
+    /*
+      Get a branching decision object. Use the default dynamic decision criteria unless
+      the user has loaded a decision method into the model.
+    */
+    CbcBranchDecision *decision = model->branchingMethod();
+    if (!decision)
+        decision = new CbcBranchDynamicDecision();
+    int xMark = 0;
+    // Get arrays to sort
+    double * sort = new double[numberObjects];
+    int * whichObject = new int[numberObjects];
+#ifdef RANGING
+    int xPen = 0;
+    int * objectMark = new int[2*numberObjects+1];
+#endif
+    // Arrays with movements
+    double * upEstimate = new double[numberObjects];
+    double * downEstimate = new double[numberObjects];
+    double estimatedDegradation = 0.0;
+    int numberNodes = model->getNodeCount();
+    int saveLogLevel = model->logLevel();
+#ifdef JJF_ZERO
+    if ((numberNodes % 500) == 0) {
+        model->setLogLevel(6);
+        // Get average up and down costs
+        double averageUp = 0.0;
+        double averageDown = 0.0;
+        int numberUp = 0;
+        int numberDown = 0;
+        int i;
+        for ( i = 0; i < numberObjects; i++) {
+            OsiObject * object = model->modifiableObject(i);
+            CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+            assert(dynamicObject);
+            int  numberUp2 = 0;
+            int numberDown2 = 0;
+            double up = 0.0;
+            double down = 0.0;
+            if (dynamicObject->numberTimesUp()) {
+                numberUp++;
+                averageUp += dynamicObject->upDynamicPseudoCost();
+                numberUp2 += dynamicObject->numberTimesUp();
+                up = dynamicObject->upDynamicPseudoCost();
+            }
+            if (dynamicObject->numberTimesDown()) {
+                numberDown++;
+                averageDown += dynamicObject->downDynamicPseudoCost();
+                numberDown2 += dynamicObject->numberTimesDown();
+                down = dynamicObject->downDynamicPseudoCost();
+            }
+            if (numberUp2 || numberDown2)
+                printf("col %d - up %d times cost %g, - down %d times cost %g\n",
+                       dynamicObject->columnNumber(), numberUp2, up, numberDown2, down);
+        }
+        if (numberUp)
+            averageUp /= static_cast<double> (numberUp);
+        else
+            averageUp = 1.0;
+        if (numberDown)
+            averageDown /= static_cast<double> (numberDown);
+        else
+            averageDown = 1.0;
+        printf("total - up %d vars average %g, - down %d vars average %g\n",
+               numberUp, averageUp, numberDown, averageDown);
+    }
+#endif
+    int numberBeforeTrust = model->numberBeforeTrust();
+    // May go round twice if strong branching fixes all local candidates
+    bool finished = false;
+    int numberToFix = 0;
+# ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (solver);
+    int saveClpOptions = 0;
+    if (osiclp) {
+        // for faster hot start
+        saveClpOptions = osiclp->specialOptions();
+        osiclp->setSpecialOptions(saveClpOptions | 8192);
+    }
+# else
+    OsiSolverInterface *osiclp = NULL ;
+# endif
+    //const CglTreeProbingInfo * probingInfo = NULL; //model->probingInfo();
+    // Old code left in with DEPRECATED_STRATEGY
+    assert (model->searchStrategy() == -1 ||
+            model->searchStrategy() == 1 ||
+            model->searchStrategy() == 2);
+#ifdef DEPRECATED_STRATEGY
+    int saveSearchStrategy2 = model->searchStrategy();
+#endif
+    // Get average up and down costs
+    {
+        double averageUp = 0.0;
+        double averageDown = 0.0;
+        int numberUp = 0;
+        int numberDown = 0;
+        int i;
+        for ( i = 0; i < numberObjects; i++) {
+            OsiObject * object = model->modifiableObject(i);
+            CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+            if (dynamicObject) {
+                if (dynamicObject->numberTimesUp()) {
+                    numberUp++;
+                    averageUp += dynamicObject->upDynamicPseudoCost();
+                }
+                if (dynamicObject->numberTimesDown()) {
+                    numberDown++;
+                    averageDown += dynamicObject->downDynamicPseudoCost();
+                }
+            }
+        }
+        if (numberUp)
+            averageUp /= static_cast<double> (numberUp);
+        else
+            averageUp = 1.0;
+        if (numberDown)
+            averageDown /= static_cast<double> (numberDown);
+        else
+            averageDown = 1.0;
+        for ( i = 0; i < numberObjects; i++) {
+            OsiObject * object = model->modifiableObject(i);
+            CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+            if (dynamicObject) {
+                if (!dynamicObject->numberTimesUp())
+                    dynamicObject->setUpDynamicPseudoCost(averageUp);
+                if (!dynamicObject->numberTimesDown())
+                    dynamicObject->setDownDynamicPseudoCost(averageDown);
+            }
+        }
+    }
+    /*
+      1 strong
+      2 no strong
+      3 strong just before solution
+      4 no strong just before solution
+      5 strong first time or before solution
+      6 strong first time
+    */
+    int useShadow = model->moreSpecialOptions() & 7;
+    if (useShadow > 2) {
+        if (model->getSolutionCount()) {
+            if (numberNodes || useShadow < 5) {
+                useShadow = 0;
+                // zap pseudo shadow prices
+                model->pseudoShadow(-1);
+                // and switch off
+                model->setMoreSpecialOptions(model->moreSpecialOptions()&(~1023));
+            } else {
+                useShadow = 1;
+            }
+        } else if (useShadow < 5) {
+            useShadow -= 2;
+        } else {
+            useShadow = 1;
+        }
+    }
+    if (useShadow) {
+        // pseudo shadow prices
+        model->pseudoShadow((model->moreSpecialOptions() >> 3)&63);
+    }
+#ifdef DEPRECATED_STRATEGY
+    { // in for tabbing
+    } else if (saveSearchStrategy2 < 1999) {
+        // pseudo shadow prices
+        model->pseudoShadow(NULL, NULL);
+    } else if (saveSearchStrategy2 < 2999) {
+        // leave old ones
+    } else if (saveSearchStrategy2 < 3999) {
+        // pseudo shadow prices at root
+        if (!numberNodes)
+            model->pseudoShadow(NULL, NULL);
+    } else {
+        abort();
+    }
+    if (saveSearchStrategy2 >= 0)
+        saveSearchStrategy2 = saveSearchStrategy2 % 1000;
+    if (saveSearchStrategy2 == 999)
+        saveSearchStrategy2 = -1;
+    int saveSearchStrategy = saveSearchStrategy2 < 99 ? saveSearchStrategy2 : saveSearchStrategy2 - 100;
+#endif //DEPRECATED_STRATEGY
+    int numberNotTrusted = 0;
+    int numberStrongDone = 0;
+    int numberUnfinished = 0;
+    int numberStrongInfeasible = 0;
+    int numberStrongIterations = 0;
+    int strongType=0;
+#define DO_ALL_AT_ROOT
+#ifdef DO_ALL_AT_ROOT
+    int saveSatisfiedVariables=0;
+    int saveNumberToDo=0;
+#endif
+    // so we can save lots of stuff
+    CbcStrongInfo choice;
+    CbcDynamicPseudoCostBranchingObject * choiceObject = NULL;
+    if (model->allDynamic()) {
+        CbcSimpleIntegerDynamicPseudoCost * object = NULL;
+        choiceObject = new CbcDynamicPseudoCostBranchingObject(model, 0, -1, 0.5, object);
+    }
+    choice.possibleBranch = choiceObject;
+    numberPassesLeft = CoinMax(numberPassesLeft, 2);
+    //#define DEBUG_SOLUTION
+#ifdef DEBUG_SOLUTION
+    bool onOptimalPath=false;
+    if ((model->specialOptions()&1) != 0) {
+      const OsiRowCutDebugger *debugger = model->continuousSolver()->getRowCutDebugger() ;
+      if (debugger) {
+	const OsiRowCutDebugger *debugger2 = model->solver()->getRowCutDebugger() ;
+	printf("On optimal in CbcNode %s\n",debugger2 ? "" : "but bad cuts");
+	onOptimalPath=true;
+      }
+    }
+#endif
+    while (!finished) {
+        numberPassesLeft--;
+        finished = true;
+        decision->initialize(model);
+        // Some objects may compute an estimate of best solution from here
+        estimatedDegradation = 0.0;
+        numberToFix = 0;
+        int numberToDo = 0;
+        int iBestNot = -1;
+        int iBestGot = -1;
+        double best = 0.0;
+        numberNotTrusted = 0;
+        numberStrongDone = 0;
+        numberUnfinished = 0;
+        numberStrongInfeasible = 0;
+        numberStrongIterations = 0;
+#ifdef RANGING
+        int * which = objectMark + numberObjects + 1;
+        int neededPenalties;
+        int optionalPenalties;
+#endif
+        // We may go round this loop three times (only if we think we have solution)
+        for (int iPass = 0; iPass < 3; iPass++) {
+
+            // Some objects may compute an estimate of best solution from here
+            estimatedDegradation = 0.0;
+            numberUnsatisfied_ = 0;
+            // initialize sum of "infeasibilities"
+            sumInfeasibilities_ = 0.0;
+            int bestPriority = COIN_INT_MAX;
+#ifdef JJF_ZERO
+            int number01 = 0;
+            const cliqueEntry * entry = NULL;
+            const int * toZero = NULL;
+            const int * toOne = NULL;
+            const int * backward = NULL;
+            int numberUnsatisProbed = 0;
+            int numberUnsatisNotProbed = 0; // 0-1
+            if (probingInfo) {
+                number01 = probingInfo->numberIntegers();
+                entry = probingInfo->fixEntries();
+                toZero = probingInfo->toZero();
+                toOne = probingInfo->toOne();
+                backward = probingInfo->backward();
+                if (!toZero[number01] || number01 < numberObjects || true) {
+                    // no info
+                    probingInfo = NULL;
+                }
+            }
+#endif
+            /*
+              Scan for branching objects that indicate infeasibility. Choose candidates
+              using priority as the first criteria, then integer infeasibility.
+
+              The algorithm is to fill the array with a set of good candidates (by
+              infeasibility) with priority bestPriority.  Finding a candidate with
+              priority better (less) than bestPriority flushes the choice array. (This
+              serves as initialization when the first candidate is found.)
+
+            */
+            numberToDo = 0;
+#ifdef RANGING
+            neededPenalties = 0;
+            optionalPenalties = numberObjects;
+#endif
+            iBestNot = -1;
+            double bestNot = 0.0;
+            iBestGot = -1;
+            best = 0.0;
+            /* Problem type as set by user or found by analysis.  This will be extended
+            0 - not known
+            1 - Set partitioning <=
+            2 - Set partitioning ==
+            3 - Set covering
+            4 - all +- 1 or all +1 and odd
+            */
+            int problemType = model->problemType();
+            bool canDoOneHot = false;
+            for (i = 0; i < numberObjects; i++) {
+                OsiObject * object = model->modifiableObject(i);
+                CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+                int preferredWay;
+                double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+                int priorityLevel = object->priority();
+                if (hotstartSolution) {
+                    // we are doing hot start
+                    const CbcSimpleInteger * thisOne = dynamic_cast <const CbcSimpleInteger *> (object);
+                    if (thisOne) {
+                        int iColumn = thisOne->columnNumber();
+                        bool canDoThisHot = true;
+                        double targetValue = hotstartSolution[iColumn];
+                        if (saveUpper[iColumn] > saveLower[iColumn]) {
+                            double value = saveSolution[iColumn];
+                            if (hotstartPriorities)
+                                priorityLevel = hotstartPriorities[iColumn];
+                            //double originalLower = thisOne->originalLower();
+                            //double originalUpper = thisOne->originalUpper();
+                            // switch off if not possible
+                            if (targetValue >= saveLower[iColumn] && targetValue <= saveUpper[iColumn]) {
+                                /* priority outranks rest always if negative
+                                   otherwise can be downgraded if at correct level.
+                                   Infeasibility may be increased to choose 1.0 values first.
+                                   choose one near wanted value
+                                */
+                                if (fabs(value - targetValue) > integerTolerance) {
+                                    //if (infeasibility>0.01)
+                                    //infeasibility = fabs(1.0e6-fabs(value-targetValue));
+                                    //else
+                                    infeasibility = fabs(value - targetValue);
+                                    //if (targetValue==1.0)
+                                    //infeasibility += 1.0;
+                                    if (value > targetValue) {
+                                        preferredWay = -1;
+                                    } else {
+                                        preferredWay = 1;
+                                    }
+                                    priorityLevel = CoinAbs(priorityLevel);
+                                } else if (priorityLevel < 0) {
+                                    priorityLevel = CoinAbs(priorityLevel);
+                                    if (targetValue == saveLower[iColumn]) {
+                                        infeasibility = integerTolerance + 1.0e-12;
+                                        preferredWay = -1;
+                                    } else if (targetValue == saveUpper[iColumn]) {
+                                        infeasibility = integerTolerance + 1.0e-12;
+                                        preferredWay = 1;
+                                    } else {
+                                        // can't
+                                        priorityLevel += 10000000;
+                                        canDoThisHot = false;
+                                    }
+                                } else {
+                                    priorityLevel += 10000000;
+                                    canDoThisHot = false;
+                                }
+                            } else {
+                                // switch off if not possible
+                                canDoThisHot = false;
+                            }
+                            if (canDoThisHot)
+                                canDoOneHot = true;
+                        } else if (targetValue < saveLower[iColumn] || targetValue > saveUpper[iColumn]) {
+                        }
+                    } else {
+                        priorityLevel += 10000000;
+                    }
+                }
+#define ZERO_ONE 0
+#define ZERO_FAKE 1.0e20;
+#if ZERO_ONE==1
+                // branch on 0-1 first (temp)
+                if (fabs(saveSolution[dynamicObject->columnNumber()]) < 1.0)
+                    priorityLevel--;
+#endif
+#if ZERO_ONE==2
+                if (fabs(saveSolution[dynamicObject->columnNumber()]) < 1.0)
+                    infeasibility *= ZERO_FAKE;
+#endif
+                if (infeasibility) {
+                    int iColumn = numberColumns + i;
+                    bool gotDown = false;
+                    int numberThisDown = 0;
+                    bool gotUp = false;
+                    int numberThisUp = 0;
+                    double downGuess = object->downEstimate();
+                    double upGuess = object->upEstimate();
+                    if (dynamicObject) {
+                        // Use this object's numberBeforeTrust
+                        int numberBeforeTrustThis = dynamicObject->numberBeforeTrust();
+                        iColumn = dynamicObject->columnNumber();
+                        gotDown = false;
+                        numberThisDown = dynamicObject->numberTimesDown();
+                        if (numberThisDown >= numberBeforeTrustThis)
+                            gotDown = true;
+                        gotUp = false;
+                        numberThisUp = dynamicObject->numberTimesUp();
+                        if (numberThisUp >= numberBeforeTrustThis)
+                            gotUp = true;
+                        if (!depth_ && false) {
+                            // try closest to 0.5
+                            double part = saveSolution[iColumn] - floor(saveSolution[iColumn]);
+                            infeasibility = fabs(0.5 - part);
+                        }
+                        if (problemType > 0 && problemType < 4 && false) {
+                            // try closest to 0.5
+                            double part = saveSolution[iColumn] - floor(saveSolution[iColumn]);
+                            infeasibility = 0.5 - fabs(0.5 - part);
+                        }
+#ifdef JJF_ZERO
+                        if (probingInfo) {
+                            int iSeq = backward[iColumn];
+                            assert (iSeq >= 0);
+                            infeasibility = 1.0 + (toZero[iSeq+1] - toZero[iSeq]) +
+                                            5.0 * CoinMin(toOne[iSeq] - toZero[iSeq], toZero[iSeq+1] - toOne[iSeq]);
+                            if (toZero[iSeq+1] > toZero[iSeq]) {
+                                numberUnsatisProbed++;
+                            } else {
+                                numberUnsatisNotProbed++;
+                            }
+                        }
+#endif
+                    } else {
+                        // see if SOS
+                        CbcSOS * sosObject =
+                            dynamic_cast <CbcSOS *>(object) ;
+                        if (sosObject) {
+                            gotDown = false;
+                            numberThisDown = sosObject->numberTimesDown();
+                            if (numberThisDown >= numberBeforeTrust)
+                                gotDown = true;
+                            gotUp = false;
+                            numberThisUp = sosObject->numberTimesUp();
+                            if (numberThisUp >= numberBeforeTrust)
+                                gotUp = true;
+                        } else {
+                            gotDown = true;
+                            numberThisDown = 999999;
+                            downGuess = 1.0e20;
+                            gotUp = true;
+                            numberThisUp = 999999;
+                            upGuess = 1.0e20;
+                            numberPassesLeft = 0;
+                        }
+                    }
+                    // Increase estimated degradation to solution
+                    estimatedDegradation += CoinMin(downGuess, upGuess);
+                    downEstimate[i] = downGuess;
+                    upEstimate[i] = upGuess;
+                    numberUnsatisfied_++;
+                    sumInfeasibilities_ += infeasibility;
+                    // Better priority? Flush choices.
+                    if (priorityLevel < bestPriority) {
+                        numberToDo = 0;
+                        bestPriority = priorityLevel;
+                        iBestGot = -1;
+                        best = 0.0;
+                        numberNotTrusted = 0;
+#ifdef RANGING
+                        neededPenalties = 0;
+                        optionalPenalties = numberObjects;
+#endif
+                    } else if (priorityLevel > bestPriority) {
+                        continue;
+                    }
+                    if (!gotUp || !gotDown)
+                        numberNotTrusted++;
+                    // Check for suitability based on infeasibility.
+                    if ((gotDown && gotUp) && numberStrong > 0) {
+                        sort[numberToDo] = -infeasibility;
+                        if (infeasibility > best) {
+                            best = infeasibility;
+                            iBestGot = numberToDo;
+                        }
+#ifdef RANGING
+                        if (dynamicObject) {
+                            objectMark[--optionalPenalties] = numberToDo;
+                            which[optionalPenalties] = iColumn;
+                        }
+#endif
+                    } else {
+#ifdef RANGING
+                        if (dynamicObject) {
+                            objectMark[neededPenalties] = numberToDo;
+                            which[neededPenalties++] = iColumn;
+                        }
+#endif
+                        sort[numberToDo] = -10.0 * infeasibility;
+                        if (!(numberThisUp + numberThisDown))
+                            sort[numberToDo] *= 100.0; // make even more likely
+                        if (iColumn < numberColumns) {
+                            double part = saveSolution[iColumn] - floor(saveSolution[iColumn]);
+                            if (1.0 - fabs(part - 0.5) > bestNot) {
+                                iBestNot = numberToDo;
+                                bestNot = 1.0 - fabs(part - 0.5);
+                            }
+                        } else {
+                            // SOS
+                            if (-sort[numberToDo] > bestNot) {
+                                iBestNot = numberToDo;
+                                bestNot = -sort[numberToDo];
+                            }
+                        }
+                    }
+                    if (model->messageHandler()->logLevel() > 3) {
+                        printf("%d (%d) down %d %g up %d %g - infeas %g - sort %g solution %g\n",
+                               i, iColumn, numberThisDown, object->downEstimate(), numberThisUp, object->upEstimate(),
+                               infeasibility, sort[numberToDo], saveSolution[iColumn]);
+                    }
+                    whichObject[numberToDo++] = i;
+                } else {
+                    // for debug
+                    downEstimate[i] = -1.0;
+                    upEstimate[i] = -1.0;
+                }
+            }
+            if (numberUnsatisfied_) {
+                //if (probingInfo&&false)
+                //printf("nunsat %d, %d probed, %d other 0-1\n",numberUnsatisfied_,
+                // numberUnsatisProbed,numberUnsatisNotProbed);
+                // some infeasibilities - go to next steps
+                if (!canDoOneHot && hotstartSolution) {
+                    // switch off as not possible
+                    hotstartSolution = NULL;
+                    model->setHotstartSolution(NULL, NULL);
+                    usefulInfo.hotstartSolution_ = NULL;
+                }
+                break;
+            } else if (!iPass) {
+                // may just need resolve
+                model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                double newObjValue = solver->getObjSense()*solver->getObjValue();
+                objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                if (!solver->isProvenOptimal()) {
+                    // infeasible
+                    anyAction = -2;
+                    break;
+                }
+                // Double check looks OK - just look at rows with all integers
+                if (model->allDynamic()) {
+                    double * solution = CoinCopyOfArray(saveSolution, numberColumns);
+                    for (int i = 0; i < numberColumns; i++) {
+                        if (model->isInteger(i))
+                            solution[i] = floor(solution[i] + 0.5);
+                    }
+                    int numberRows = solver->getNumRows();
+                    double * rowActivity = new double [numberRows];
+                    CoinZeroN(rowActivity, numberRows);
+                    solver->getMatrixByCol()->times(solution, rowActivity);
+                    //const double * element = model->solver()->getMatrixByCol()->getElements();
+                    const int * row = model->solver()->getMatrixByCol()->getIndices();
+                    const CoinBigIndex * columnStart = model->solver()->getMatrixByCol()->getVectorStarts();
+                    const int * columnLength = model->solver()->getMatrixByCol()->getVectorLengths();
+                    int nFree = 0;
+                    int nFreeNon = 0;
+                    int nFixedNon = 0;
+                    double mostAway = 0.0;
+                    int whichAway = -1;
+                    const double * columnLower = solver->getColLower();
+                    const double * columnUpper = solver->getColUpper();
+                    for (int i = 0; i < numberColumns; i++) {
+                        if (!model->isInteger(i)) {
+                            // mark rows as flexible
+                            CoinBigIndex start = columnStart[i];
+                            CoinBigIndex end = start + columnLength[i];
+                            for (CoinBigIndex j = start; j < end; j++) {
+                                int iRow = row[j];
+                                rowActivity[iRow] = COIN_DBL_MAX;
+                            }
+                        } else if (columnLower[i] < columnUpper[i]) {
+			    if (fabs(solution[i] - saveSolution[i]) > 
+				integerTolerance) {
+                                nFreeNon++;
+                                if (fabs(solution[i] - saveSolution[i]) > mostAway) {
+                                    mostAway = fabs(solution[i] - saveSolution[i]);
+                                    whichAway = i;
+                                }
+                            } else {
+                                nFree++;
+                            }
+                        } else if (solution[i] != saveSolution[i]) {
+                            nFixedNon++;
+                        }
+                    }
+                    const double * lower = solver->getRowLower();
+                    const double * upper = solver->getRowUpper();
+                    bool satisfied = true;
+                    for (int i = 0; i < numberRows; i++) {
+                        double value = rowActivity[i];
+                        if (value != COIN_DBL_MAX) {
+                            if (value > upper[i] + 1.0e-5 || value < lower[i] - 1.0e-5) {
+                                satisfied = false;
+                            }
+                        }
+                    }
+                    delete [] rowActivity;
+                    delete [] solution;
+                    if (!satisfied) {
+#ifdef CLP_INVESTIGATE
+                        printf("%d free ok %d free off target %d fixed off target\n",
+                               nFree, nFreeNon, nFixedNon);
+#endif
+                        if (nFreeNon) {
+                            // try branching on these
+                            delete branch_;
+                            for (int i = 0; i < numberObjects; i++) {
+                                OsiObject * object = model->modifiableObject(i);
+                                CbcSimpleIntegerDynamicPseudoCost * obj =
+                                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+                                assert (obj);
+                                int iColumn = obj->columnNumber();
+                                if (iColumn == whichAway) {
+                                    int preferredWay = (saveSolution[iColumn] > solution[iColumn])
+                                                       ? -1 : +1;
+                                    usefulInfo.integerTolerance_ = 0.0;
+                                    branch_ = obj->createCbcBranch(solver, &usefulInfo, preferredWay);
+                                    break;
+                                }
+                            }
+                            anyAction = 0;
+                            break;
+                        }
+                    }
+                }
+            } else if (iPass == 1) {
+                // looks like a solution - get paranoid
+                bool roundAgain = false;
+                // get basis
+                CoinWarmStartBasis * ws = dynamic_cast<CoinWarmStartBasis*>(solver->getWarmStart());
+                if (!ws)
+                    break;
+                double tolerance;
+                solver->getDblParam(OsiPrimalTolerance, tolerance);
+                for (i = 0; i < numberColumns; i++) {
+                    double value = saveSolution[i];
+                    if (value < lower[i] - tolerance) {
+                        saveSolution[i] = lower[i];
+                        roundAgain = true;
+                        ws->setStructStatus(i, CoinWarmStartBasis::atLowerBound);
+                    } else if (value > upper[i] + tolerance) {
+                        saveSolution[i] = upper[i];
+                        roundAgain = true;
+                        ws->setStructStatus(i, CoinWarmStartBasis::atUpperBound);
+                    }
+                }
+                if (roundAgain) {
+                    // restore basis
+                    solver->setWarmStart(ws);
+                    solver->setColSolution(saveSolution);
+                    delete ws;
+                    bool takeHint;
+                    OsiHintStrength strength;
+                    solver->getHintParam(OsiDoDualInResolve, takeHint, strength);
+                    solver->setHintParam(OsiDoDualInResolve, false, OsiHintDo) ;
+                    model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                    double newObjValue = solver->getObjSense()*solver->getObjValue();
+                    objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                    solver->setHintParam(OsiDoDualInResolve, takeHint, strength) ;
+                    if (!solver->isProvenOptimal()) {
+                        // infeasible
+                        anyAction = -2;
+                        break;
+                    }
+                } else {
+                    delete ws;
+                    break;
+                }
+            }
+        }
+        if (anyAction == -2) {
+            break;
+        }
+        // skip if solution
+        if (!numberUnsatisfied_)
+            break;
+        int skipAll = (numberNotTrusted == 0 || numberToDo == 1) ? 1 : 0;
+        bool doneHotStart = false;
+        //DEPRECATED_STRATEGYint searchStrategy = saveSearchStrategy>=0 ? (saveSearchStrategy%10) : -1;
+        int searchStrategy = model->searchStrategy();
+        // But adjust depending on ratio of iterations
+        if (searchStrategy > 0) {
+	  if (numberBeforeTrust >= /*5*/ 10 && numberBeforeTrust <= 10) {
+                if (searchStrategy != 2) {
+                    assert (searchStrategy == 1);
+                    if (depth_ > 5) {
+                        int numberIterations = model->getIterationCount();
+                        int numberStrongIterations = model->numberStrongIterations();
+                        if (numberStrongIterations > numberIterations + 10000) {
+                            searchStrategy = 2;
+                            skipAll = 1;
+                        } else if (numberStrongIterations*4 + 1000 < numberIterations) {
+                            searchStrategy = 3;
+                            skipAll = 0;
+                        }
+                    } else {
+                        searchStrategy = 3;
+                        skipAll = 0;
+                    }
+                }
+            }
+        }
+        // worth trying if too many times
+        // Save basis
+        CoinWarmStart * ws = NULL;
+        // save limit
+        int saveLimit = 0;
+        solver->getIntParam(OsiMaxNumIterationHotStart, saveLimit);
+        if (!numberPassesLeft)
+            skipAll = 1;
+        if (!skipAll) {
+            ws = solver->getWarmStart();
+            int limit = 100;
+            if (!saveStateOfSearch && saveLimit < limit && saveLimit == 100)
+                solver->setIntParam(OsiMaxNumIterationHotStart, limit);
+        }
+        // Say which one will be best
+        int whichChoice = 0;
+        int bestChoice;
+        if (iBestGot >= 0)
+            bestChoice = iBestGot;
+        else
+            bestChoice = iBestNot;
+        assert (bestChoice >= 0);
+        // If we have hit max time don't do strong branching
+	bool hitMaxTime = (model->getCurrentSeconds() >
+                            model->getDblParam(CbcModel::CbcMaximumSeconds));
+        // also give up if we are looping round too much
+        if (hitMaxTime || numberPassesLeft <= 0 || useShadow == 2) {
+            int iObject = whichObject[bestChoice];
+            OsiObject * object = model->modifiableObject(iObject);
+            int preferredWay;
+            object->infeasibility(&usefulInfo, preferredWay);
+            CbcObject * obj =
+                dynamic_cast <CbcObject *>(object) ;
+            assert (obj);
+            branch_ = obj->createCbcBranch(solver, &usefulInfo, preferredWay);
+            {
+                CbcBranchingObject * branchObj =
+                    dynamic_cast <CbcBranchingObject *>(branch_) ;
+                assert (branchObj);
+                branchObj->way(preferredWay);
+            }
+            delete ws;
+            ws = NULL;
+            break;
+        } else {
+            // say do fast
+            int easy = 1;
+            if (!skipAll)
+                solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, &easy) ;
+            int iDo;
+#define RESET_BOUNDS
+#ifdef RANGING
+            bool useRanging = model->allDynamic() && !skipAll;
+            if (useRanging) {
+                double currentObjective = solver->getObjValue() * solver->getObjSense();
+                double gap = cutoff - currentObjective;
+                // relax a bit
+                gap *= 1.0000001;
+                gap = CoinMax(1.0e-5, gap);
+                // off penalties if too much
+                double needed = neededPenalties;
+                needed *= numberRows;
+                if (numberNodes) {
+                    if (needed > 1.0e6) {
+                        neededPenalties = 0;
+                    } else if (gap < 1.0e5) {
+                        // maybe allow some not needed
+                        int extra = static_cast<int> ((1.0e6 - needed) / numberRows);
+                        int nStored = numberObjects - optionalPenalties;
+                        extra = CoinMin(extra, nStored);
+                        for (int i = 0; i < extra; i++) {
+                            objectMark[neededPenalties] = objectMark[optionalPenalties+i];
+                            which[neededPenalties++] = which[optionalPenalties+i];;
+                        }
+                    }
+                }
+                if (osiclp && neededPenalties) {
+                    assert (!doneHotStart);
+                    xPen += neededPenalties;
+                    which--;
+                    which[0] = neededPenalties;
+                    osiclp->passInRanges(which);
+                    // Mark hot start and get ranges
+                    if (kPass) {
+                        // until can work out why solution can go funny
+                        int save = osiclp->specialOptions();
+                        osiclp->setSpecialOptions(save | 256);
+                        solver->markHotStart();
+#ifdef RESET_BOUNDS
+			memcpy(saveLower,solver->getColLower(),solver->getNumCols()*sizeof(double));
+			memcpy(saveUpper,solver->getColUpper(),solver->getNumCols()*sizeof(double));
+#endif
+                        osiclp->setSpecialOptions(save);
+                    } else {
+                        solver->markHotStart();
+#ifdef RESET_BOUNDS
+			memcpy(saveLower,solver->getColLower(),solver->getNumCols()*sizeof(double));
+			memcpy(saveUpper,solver->getColUpper(),solver->getNumCols()*sizeof(double));
+#endif
+                    }
+                    doneHotStart = true;
+                    xMark++;
+                    kPass++;
+                    osiclp->passInRanges(NULL);
+                    const double * downCost = osiclp->upRange();
+                    const double * upCost = osiclp->downRange();
+                    bool problemFeasible = true;
+                    int numberFixed = 0;
+                    for (int i = 0; i < neededPenalties; i++) {
+                        int j = objectMark[i];
+                        int iObject = whichObject[j];
+                        OsiObject * object = model->modifiableObject(iObject);
+                        CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                            dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+                        // Use this object's numberBeforeTrust
+                        int numberBeforeTrustThis = dynamicObject->numberBeforeTrust();
+                        int iSequence = dynamicObject->columnNumber();
+                        double value = saveSolution[iSequence];
+                        value -= floor(value);
+                        double upPenalty = CoinMin(upCost[i], 1.0e110) * (1.0 - value);
+                        double downPenalty = CoinMin(downCost[i], 1.0e110) * value;
+                        int numberThisDown = dynamicObject->numberTimesDown();
+                        int numberThisUp = dynamicObject->numberTimesUp();
+                        if (!numberBeforeTrustThis) {
+                            // override
+                            downEstimate[iObject] = downPenalty;
+                            upEstimate[iObject] = upPenalty;
+                            double min1 = CoinMin(downEstimate[iObject],
+                                                  upEstimate[iObject]);
+                            double max1 = CoinMax(downEstimate[iObject],
+                                                  upEstimate[iObject]);
+                            min1 = 0.8 * min1 + 0.2 * max1;
+                            sort[j] = - min1;
+                        } else if (numberThisDown < numberBeforeTrustThis ||
+                                   numberThisUp < numberBeforeTrustThis) {
+                            double invTrust = 1.0 / static_cast<double> (numberBeforeTrustThis);
+                            if (numberThisDown < numberBeforeTrustThis) {
+                                double fraction = numberThisDown * invTrust;
+                                downEstimate[iObject] = fraction * downEstimate[iObject] + (1.0 - fraction) * downPenalty;
+                            }
+                            if (numberThisUp < numberBeforeTrustThis) {
+                                double fraction = numberThisUp * invTrust;
+                                upEstimate[iObject] = fraction * upEstimate[iObject] + (1.0 - fraction) * upPenalty;
+                            }
+                            double min1 = CoinMin(downEstimate[iObject],
+                                                  upEstimate[iObject]);
+                            double max1 = CoinMax(downEstimate[iObject],
+                                                  upEstimate[iObject]);
+                            min1 = 0.8 * min1 + 0.2 * max1;
+                            min1 *= 10.0;
+                            if (!(numberThisDown + numberThisUp))
+                                min1 *= 100.0;
+                            sort[j] = - min1;
+                        }
+			// seems unreliable
+                        if (false&&CoinMax(downPenalty, upPenalty) > gap) {
+                            COIN_DETAIL_PRINT(printf("gap %g object %d has down range %g, up %g\n",
+						     gap, i, downPenalty, upPenalty));
+                            //sort[j] -= 1.0e50; // make more likely to be chosen
+                            int number;
+                            if (downPenalty > gap) {
+                                number = dynamicObject->numberTimesDown();
+                                if (upPenalty > gap)
+                                    problemFeasible = false;
+                                CbcBranchingObject * branch = dynamicObject->createCbcBranch(solver, &usefulInfo, 1);
+                                //branch->fix(solver,saveLower,saveUpper,1);
+                                delete branch;
+                            } else {
+                                number = dynamicObject->numberTimesUp();
+                                CbcBranchingObject * branch = dynamicObject->createCbcBranch(solver, &usefulInfo, 1);
+                                //branch->fix(solver,saveLower,saveUpper,-1);
+                                delete branch;
+                            }
+                            if (number >= numberBeforeTrustThis)
+			      dynamicObject->setNumberBeforeTrust(CoinMin(number + 1,5*numberBeforeTrust));
+                            numberFixed++;
+                        }
+                        if (!numberNodes)
+                            COIN_DETAIL_PRINT(printf("%d pen down ps %g -> %g up ps %g -> %g\n",
+						     iObject, downPenalty, downPenalty, upPenalty, upPenalty));
+                    }
+                    if (numberFixed && problemFeasible) {
+                        assert(doneHotStart);
+                        solver->unmarkHotStart();
+                        model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                        double newObjValue = solver->getObjSense()*solver->getObjValue();
+                        objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                        solver->markHotStart();
+#ifdef RESET_BOUNDS
+			memcpy(saveLower,solver->getColLower(),solver->getNumCols()*sizeof(double));
+			memcpy(saveUpper,solver->getColUpper(),solver->getNumCols()*sizeof(double));
+#endif
+                        problemFeasible = solver->isProvenOptimal();
+                    }
+                    if (!problemFeasible) {
+		      COIN_DETAIL_PRINT(fprintf(stdout, "both ways infeas on ranging - code needed\n"));
+                        anyAction = -2;
+                        if (!choiceObject) {
+                            delete choice.possibleBranch;
+                            choice.possibleBranch = NULL;
+                        }
+                        //printf("Both infeasible for choice %d sequence %d\n",i,
+                        // model->object(choice.objectNumber)->columnNumber());
+                        // Delete the snapshot
+                        solver->unmarkHotStart();
+                        // back to normal
+                        solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+                        // restore basis
+                        solver->setWarmStart(ws);
+                        doneHotStart = false;
+                        delete ws;
+                        ws = NULL;
+                        break;
+                    }
+                }
+            }
+#endif		/* RANGING */
+            {
+                int numberIterations = model->getIterationCount();
+                //numberIterations += (model->numberExtraIterations()>>2);
+                const int * strongInfo = model->strongInfo();
+                //int numberDone = strongInfo[0]-strongInfo[3];
+                int numberFixed = strongInfo[1] - strongInfo[4];
+                int numberInfeasible = strongInfo[2] - strongInfo[5];
+                assert (!strongInfo[3]);
+                assert (!strongInfo[4]);
+                assert (!strongInfo[5]);
+                int numberStrongIterations = model->numberStrongIterations();
+                int numberRows = solver->getNumRows();
+                if (numberStrongIterations > numberIterations + CoinMin(100, 10*numberRows) && depth_ >= 4 && numberNodes > 100) {
+                    if (20*numberInfeasible + 4*numberFixed < numberNodes) {
+                        // Say never do
+		        if (numberBeforeTrust == 5)
+			  skipAll = -1;
+                    }
+                }
+            }
+            // make sure best will be first
+            if (iBestGot >= 0)
+                sort[iBestGot] = -COIN_DBL_MAX;
+            // Actions 0 - exit for repeat, 1 resolve and try old choice,2 exit for continue
+            if (anyAction)
+                numberToDo = 0; // skip as we will be trying again
+            // Sort
+            CoinSort_2(sort, sort + numberToDo, whichObject);
+            // Change in objective opposite infeasible
+            double worstFeasible = 0.0;
+            // Just first if strong off
+            if (!numberStrong)
+                numberToDo = CoinMin(numberToDo, 1);
+            if (searchStrategy == 2)
+                numberToDo = CoinMin(numberToDo, 20);
+            iDo = 0;
+            int saveLimit2;
+            solver->getIntParam(OsiMaxNumIterationHotStart, saveLimit2);
+            int numberTest = numberNotTrusted > 0 ? numberStrong : (numberStrong + 1) / 2;
+            if (searchStrategy == 3) {
+                // Previously decided we need strong
+                numberTest = numberStrong;
+            }
+            // Try nearly always off
+            if (skipAll >= 0) {
+                if (searchStrategy < 2) {
+                    //if ((numberNodes%20)!=0) {
+                    if ((model->specialOptions()&8) == 0) {
+                        numberTest = 0;
+                    }
+                    //} else {
+                    //numberTest=2*numberStrong;
+                    //skipAll=0;
+                    //}
+                }
+            } else {
+                // Just take first
+                numberTest = 1;
+            }
+            int testDepth = (skipAll >= 0) ? 8 : 4;
+            if (depth_ < testDepth && numberStrong) {
+                if (searchStrategy != 2) {
+                    int numberRows = solver->getNumRows();
+                    // whether to do this or not is important - think
+                    if (numberRows < 300 || numberRows + numberColumns < 2500) {
+                        if (depth_ < 7)
+                            numberStrong = CoinMin(3 * numberStrong, numberToDo);
+                        if (!depth_)
+                            numberStrong = CoinMin(6 * numberStrong, numberToDo);
+                    }
+                    numberTest = numberStrong;
+                    skipAll = 0;
+                }
+            }
+            // Do at least 5 strong
+            if (numberColumns < 1000 && (depth_ < 15 || numberNodes < 1000000))
+                numberTest = CoinMax(numberTest, 5);
+            if ((model->specialOptions()&8) == 0) {
+                if (skipAll) {
+                    numberTest = 0;
+                }
+            } else {
+                // do 5 as strong is fixing
+                numberTest = CoinMax(numberTest, 5);
+            }
+            // see if switched off
+            if (skipAll < 0) {
+                numberTest = 0;
+            }
+            int realMaxHotIterations = 999999;
+            if (skipAll < 0)
+                numberToDo = 1;
+	    strongType=0;
+#ifdef DO_ALL_AT_ROOT
+	    if (model->strongStrategy()) {
+	      int iStrategy=model->strongStrategy();
+	      int kDepth = iStrategy/100;
+	      if (kDepth)
+		iStrategy -= 100*kDepth;
+	      else
+		kDepth=5;
+	      double objValue = solver->getObjSense()*solver->getObjValue();
+	      double bestPossible = model->getBestPossibleObjValue();
+	      bestPossible += 1.0e-7*(1.0+fabs(bestPossible));
+	      int jStrategy = iStrategy/10;
+	      if (jStrategy) {
+		if ((jStrategy&1)!=0&&!depth_)
+		  strongType=2;
+		else if ((jStrategy&2)!=0&&depth_<=kDepth)
+		  strongType=2;
+		else if ((jStrategy&4)!=0&&objValue<bestPossible)
+		  strongType=2;
+		iStrategy-=10*jStrategy;
+	      }
+	      if (!strongType) {
+		if ((iStrategy&1)!=0&&!depth_)
+		  strongType=1;
+		else if ((iStrategy&2)!=0&&depth_<=kDepth)
+		  strongType=1;
+		else if ((iStrategy&4)!=0&&objValue<bestPossible)
+		  strongType=1;
+	      }
+	      saveNumberToDo=numberToDo;
+	      if (strongType==2) {
+		// add in satisfied
+		const int * integerVariable = model->integerVariable();
+		int numberIntegers = model->numberIntegers();
+		if (numberIntegers==numberObjects) {
+		  numberToDo=0;
+		  for (int i=0;i<numberIntegers;i++) {
+		    int iColumn=integerVariable[i];
+		    if (saveUpper[iColumn]>saveLower[iColumn]) {
+		      whichObject [numberToDo++]=i;
+		    }
+		  }
+		  saveSatisfiedVariables=numberToDo-saveNumberToDo;
+		} else {
+		  strongType=1;
+		}
+	      }
+	      if (strongType) {
+                numberTest = numberToDo;
+		numberStrong=numberToDo;
+		skipAll=0;
+		searchStrategy=0;
+		solver->setIntParam(OsiMaxNumIterationHotStart, 100000);
+		//printf("Strong branching type %d\n",strongType);
+	      }
+	    }
+#endif
+            for ( iDo = 0; iDo < numberToDo; iDo++) {
+                int iObject = whichObject[iDo];
+                OsiObject * object = model->modifiableObject(iObject);
+                CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+                int iColumn = dynamicObject ? dynamicObject->columnNumber() : numberColumns + iObject;
+                int preferredWay;
+                double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+                // may have become feasible
+                if (!infeasibility) {
+		  if(strongType!=2||solver->getColLower()[iColumn]==solver->getColUpper()[iColumn])
+                    continue;
+		}
+#ifndef NDEBUG
+                if (iColumn < numberColumns) {
+                    const double * solution = model->testSolution();
+                    assert (saveSolution[iColumn] == solution[iColumn]);
+                }
+#endif
+                CbcSimpleInteger * obj =
+                    dynamic_cast <CbcSimpleInteger *>(object) ;
+                if (obj) {
+                    if (choiceObject) {
+                        obj->fillCreateBranch(choiceObject, &usefulInfo, preferredWay);
+                        choiceObject->setObject(dynamicObject);
+                    } else {
+                        choice.possibleBranch = obj->createCbcBranch(solver, &usefulInfo, preferredWay);
+                    }
+                } else {
+                    CbcObject * obj =
+                        dynamic_cast <CbcObject *>(object) ;
+                    assert (obj);
+                    choice.possibleBranch = obj->createCbcBranch(solver, &usefulInfo, preferredWay);
+                }
+                // Save which object it was
+                choice.objectNumber = iObject;
+                choice.numIntInfeasUp = numberUnsatisfied_;
+                choice.numIntInfeasDown = numberUnsatisfied_;
+		if (strongType!=2) {
+		  choice.upMovement = upEstimate[iObject];
+		  choice.downMovement = downEstimate[iObject];
+		} else {
+		  choice.upMovement = 0.1;
+		  choice.downMovement = 0.1;
+		}
+		  assert (choice.upMovement >= 0.0);
+		  assert (choice.downMovement >= 0.0);
+                choice.fix = 0; // say not fixed
+                // see if can skip strong branching
+                int canSkip = choice.possibleBranch->fillStrongInfo(choice);
+                if ((numberTest <= 0 || skipAll)) {
+                    if (iDo > 20) {
+                        if (!choiceObject) {
+                            delete choice.possibleBranch;
+                            choice.possibleBranch = NULL;
+                        }
+                        break; // give up anyway
+                    }
+                }
+                if (model->messageHandler()->logLevel() > 3 && numberBeforeTrust && dynamicObject)
+                    dynamicObject->print(1, choice.possibleBranch->value());
+		if (strongType)
+		  canSkip=0;
+                if (skipAll < 0)
+                    canSkip = 1;
+                if (!canSkip) {
+                    if (!doneHotStart) {
+                        // Mark hot start
+                        doneHotStart = true;
+                        solver->markHotStart();
+#ifdef RESET_BOUNDS
+			memcpy(saveLower,solver->getColLower(),solver->getNumCols()*sizeof(double));
+			memcpy(saveUpper,solver->getColUpper(),solver->getNumCols()*sizeof(double));
+#endif
+			if (!solver->isProvenOptimal()) {
+			  skipAll=-2;
+			  canSkip = 1;
+			}
+                        xMark++;
+                    }
+		}
+                if (!canSkip) {
+                    numberTest--;
+                    // just do a few
+                    if (searchStrategy == 2)
+                        solver->setIntParam(OsiMaxNumIterationHotStart, 10);
+                    double objectiveChange ;
+                    double newObjectiveValue = 1.0e100;
+                    int j;
+                    // status is 0 finished, 1 infeasible and other
+                    int iStatus;
+                    /*
+                      Try the down direction first. (Specify the initial branching alternative as
+                      down with a call to way(-1). Each subsequent call to branch() performs the
+                      specified branch and advances the branch object state to the next branch
+                      alternative.)
+                    */
+                    choice.possibleBranch->way(-1) ;
+                    choice.possibleBranch->branch() ;
+                    solver->solveFromHotStart() ;
+                    bool needHotStartUpdate = false;
+                    numberStrongDone++;
+                    numberStrongIterations += solver->getIterationCount();
+                    /*
+                      We now have an estimate of objective degradation that we can use for strong
+                      branching. If we're over the cutoff, the variable is monotone up.
+                      If we actually made it to optimality, check for a solution, and if we have
+                      a good one, call setBestSolution to process it. Note that this may reduce the
+                      cutoff, so we check again to see if we can declare this variable monotone.
+                    */
+                    if (solver->isProvenOptimal())
+                        iStatus = 0; // optimal
+                    else if (solver->isIterationLimitReached() 
+                             && !solver->isDualObjectiveLimitReached()) {
+                        iStatus = 2; // unknown
+                    } else {
+                        iStatus = 1; // infeasible
+#ifdef CONFLICT_CUTS
+# ifdef COIN_HAS_CLP
+			if (osiclp&&(model->moreSpecialOptions()&4194304)!=0) {
+			  const CbcFullNodeInfo * topOfTree =
+			    model->topOfTree();
+			  if (topOfTree) {
+			    OsiRowCut * cut = osiclp->smallModelCut(topOfTree->lower(),
+								    topOfTree->upper(),
+								    model->numberRowsAtContinuous(),
+								    model->whichGenerator());
+			    if (cut) {
+			      printf("XXXXXX found conflict cut in strong branching\n");
+			      //cut->print();
+			      if ((model->specialOptions()&1) != 0) {
+				const OsiRowCutDebugger *debugger = model->continuousSolver()->getRowCutDebugger() ;
+				if (debugger) {
+				  if (debugger->invalidCut(*cut)) {
+				    model->continuousSolver()->applyRowCuts(1,cut);
+				    model->continuousSolver()->writeMps("bad");
+				  }
+				  CoinAssert (!debugger->invalidCut(*cut));
+				}
+			      }
+			      model->makeGlobalCut(cut) ;
+			    }
+			  }
+			}
+#endif
+#endif
+		    }
+                    if (iStatus != 2 && solver->getIterationCount() >
+                            realMaxHotIterations)
+                        numberUnfinished++;
+                    newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+                    choice.numItersDown = solver->getIterationCount();
+                    objectiveChange = CoinMax(newObjectiveValue  - objectiveValue_, 0.0);
+                    // Update branching information if wanted
+                    CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (choice.possibleBranch);
+                    if (cbcobj) {
+                        CbcObject * object = cbcobj->object();
+                        assert (object) ;
+                        CbcObjectUpdateData update = object->createUpdateInformation(solver, this, cbcobj);
+                        update.objectNumber_ = choice.objectNumber;
+                        model->addUpdateInformation(update);
+                    } else {
+                        decision->updateInformation( solver, this);
+                    }
+                    if (!iStatus) {
+                        choice.finishedDown = true ;
+                        if (newObjectiveValue >= cutoff) {
+                            objectiveChange = 1.0e100; // say infeasible
+                            numberStrongInfeasible++;
+                        } else {
+#define CBCNODE_TIGHTEN_BOUNDS
+#ifdef CBCNODE_TIGHTEN_BOUNDS
+                            // Can we tighten bounds?
+                            if (iColumn < numberColumns && cutoff < 1.0e20
+                                    && objectiveChange > 1.0e-5) {
+                                double value = saveSolution[iColumn];
+                                double down = value - floor(value-integerTolerance);
+                                double changePer = objectiveChange / (down + 1.0e-7);
+                                double distance = (cutoff - objectiveValue_) / changePer;
+                                distance += 1.0e-3;
+                                if (distance < 5.0) {
+                                    double newLower = ceil(value - distance);
+                                    if (newLower > saveLower[iColumn]) {
+                                        //printf("Could increase lower bound on %d from %g to %g\n",
+                                        //   iColumn,saveLower[iColumn],newLower);
+                                        saveLower[iColumn] = newLower;
+                                        solver->setColLower(iColumn, newLower);
+                                    }
+                                }
+                            }
+#endif
+                            // See if integer solution
+                            if (model->feasibleSolution(choice.numIntInfeasDown,
+                                                        choice.numObjInfeasDown)
+                                    && model->problemFeasibility()->feasible(model, -1) >= 0) {
+                                if (auxiliaryInfo->solutionAddsCuts()) {
+                                    needHotStartUpdate = true;
+                                    solver->unmarkHotStart();
+                                }
+                                model->setLogLevel(saveLogLevel);
+                                model->setBestSolution(CBC_STRONGSOL,
+                                                       newObjectiveValue,
+                                                       solver->getColSolution()) ;
+                                if (needHotStartUpdate) {
+                                    model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                                    newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+                                    objectiveValue_ = CoinMax(objectiveValue_,newObjectiveValue);
+                                    objectiveChange = CoinMax(newObjectiveValue  - objectiveValue_, 0.0);
+                                    model->feasibleSolution(choice.numIntInfeasDown,
+                                                            choice.numObjInfeasDown);
+                                }
+                                model->setLastHeuristic(NULL);
+                                model->incrementUsed(solver->getColSolution());
+                                cutoff = model->getCutoff();
+                                if (newObjectiveValue >= cutoff) {	//  *new* cutoff
+                                    objectiveChange = 1.0e100 ;
+                                    numberStrongInfeasible++;
+                                }
+                            }
+                        }
+                    } else if (iStatus == 1) {
+                        objectiveChange = 1.0e100 ;
+                        numberStrongInfeasible++;
+                    } else {
+                        // Can't say much as we did not finish
+                        choice.finishedDown = false ;
+                        numberUnfinished++;
+                    }
+                    choice.downMovement = objectiveChange ;
+
+                    // restore bounds
+                    for ( j = 0; j < numberColumns; j++) {
+                        if (saveLower[j] != lower[j])
+                            solver->setColLower(j, saveLower[j]);
+                        if (saveUpper[j] != upper[j])
+                            solver->setColUpper(j, saveUpper[j]);
+                    }
+                    if (needHotStartUpdate) {
+                        needHotStartUpdate = false;
+                        model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                        double newObjValue = solver->getObjSense()*solver->getObjValue();
+                        objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                        //we may again have an integer feasible solution
+                        int numberIntegerInfeasibilities;
+                        int numberObjectInfeasibilities;
+                        if (model->feasibleSolution(
+                                    numberIntegerInfeasibilities,
+                                    numberObjectInfeasibilities)) {
+#ifdef BONMIN
+                            //In this case node has become integer feasible, let us exit the loop
+                            std::cout << "Node has become integer feasible" << std::endl;
+                            numberUnsatisfied_ = 0;
+                            break;
+#endif
+                            double objValue = solver->getObjValue();
+                            model->setLogLevel(saveLogLevel);
+                            model->setBestSolution(CBC_STRONGSOL,
+                                                   objValue,
+                                                   solver->getColSolution()) ;
+                            model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                            double newObjValue = solver->getObjSense()*solver->getObjValue();
+                            objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                            cutoff = model->getCutoff();
+                        }
+                        solver->markHotStart();
+#ifdef RESET_BOUNDS
+			memcpy(saveLower,solver->getColLower(),solver->getNumCols()*sizeof(double));
+			memcpy(saveUpper,solver->getColUpper(),solver->getNumCols()*sizeof(double));
+#endif
+			if (!solver->isProvenOptimal()) {
+			  skipAll=-2;
+			  canSkip = 1;
+			}
+                        xMark++;
+                    }
+#if 0 //def DO_ALL_AT_ROOT
+                    if (strongType)
+                        printf("Down on %d, status is %d, obj %g its %d cost %g finished %d inf %d infobj %d\n",
+                               choice.objectNumber, iStatus, newObjectiveValue, choice.numItersDown,
+                               choice.downMovement, choice.finishedDown, choice.numIntInfeasDown,
+                               choice.numObjInfeasDown);
+#endif
+
+                    // repeat the whole exercise, forcing the variable up
+                    choice.possibleBranch->branch();
+                    solver->solveFromHotStart() ;
+                    numberStrongDone++;
+                    numberStrongIterations += solver->getIterationCount();
+                    /*
+                      We now have an estimate of objective degradation that we can use for strong
+                      branching. If we're over the cutoff, the variable is monotone up.
+                      If we actually made it to optimality, check for a solution, and if we have
+                      a good one, call setBestSolution to process it. Note that this may reduce the
+                      cutoff, so we check again to see if we can declare this variable monotone.
+                    */
+                    if (solver->isProvenOptimal())
+                        iStatus = 0; // optimal
+                    else if (solver->isIterationLimitReached()
+                             && !solver->isDualObjectiveLimitReached()) {
+                        iStatus = 2; // unknown
+                    } else {
+                        iStatus = 1; // infeasible
+#ifdef CONFLICT_CUTS
+# ifdef COIN_HAS_CLP
+			if (osiclp&&(model->moreSpecialOptions()&4194304)!=0) {
+			  const CbcFullNodeInfo * topOfTree =
+			    model->topOfTree();
+			  if (topOfTree) {
+			    OsiRowCut * cut = osiclp->smallModelCut(topOfTree->lower(),
+								    topOfTree->upper(),
+								    model->numberRowsAtContinuous(),
+								    model->whichGenerator());
+			    if (cut) {
+			      printf("XXXXXX found conflict cut in strong branching\n");
+			      //cut->print();
+			      if ((model->specialOptions()&1) != 0) {
+				const OsiRowCutDebugger *debugger = model->continuousSolver()->getRowCutDebugger() ;
+				if (debugger) {
+				  if (debugger->invalidCut(*cut)) {
+				    model->continuousSolver()->applyRowCuts(1,cut);
+				    model->continuousSolver()->writeMps("bad");
+				  }
+				  CoinAssert (!debugger->invalidCut(*cut));
+				}
+			      }
+			      model->makeGlobalCut(cut) ;
+			    }
+			  }
+			}
+#endif
+#endif
+		    }
+                    if (iStatus != 2 && solver->getIterationCount() >
+                            realMaxHotIterations)
+                        numberUnfinished++;
+                    newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+                    choice.numItersUp = solver->getIterationCount();
+                    objectiveChange = CoinMax(newObjectiveValue  - objectiveValue_, 0.0);
+                    // Update branching information if wanted
+                    cbcobj = dynamic_cast<CbcBranchingObject *> (choice.possibleBranch);
+                    if (cbcobj) {
+                        CbcObject * object = cbcobj->object();
+                        assert (object) ;
+                        CbcObjectUpdateData update = object->createUpdateInformation(solver, this, cbcobj);
+                        update.objectNumber_ = choice.objectNumber;
+                        model->addUpdateInformation(update);
+                    } else {
+                        decision->updateInformation( solver, this);
+                    }
+                    if (!iStatus) {
+                        choice.finishedUp = true ;
+                        if (newObjectiveValue >= cutoff) {
+                            objectiveChange = 1.0e100; // say infeasible
+                            numberStrongInfeasible++;
+                        } else {
+#ifdef CBCNODE_TIGHTEN_BOUNDS
+                            // Can we tighten bounds?
+                            if (iColumn < numberColumns && cutoff < 1.0e20
+                                    && objectiveChange > 1.0e-5) {
+                                double value = saveSolution[iColumn];
+                                double up = ceil(value+integerTolerance) - value;
+                                double changePer = objectiveChange / (up + 1.0e-7);
+                                double distance = (cutoff - objectiveValue_) / changePer;
+                                distance += 1.0e-3;
+                                if (distance < 5.0) {
+                                    double newUpper = floor(value + distance);
+                                    if (newUpper < saveUpper[iColumn]) {
+                                        //printf("Could decrease upper bound on %d from %g to %g\n",
+                                        //   iColumn,saveUpper[iColumn],newUpper);
+                                        saveUpper[iColumn] = newUpper;
+                                        solver->setColUpper(iColumn, newUpper);
+                                    }
+                                }
+                            }
+#endif
+                            // See if integer solution
+                            if (model->feasibleSolution(choice.numIntInfeasUp,
+                                                        choice.numObjInfeasUp)
+                                    && model->problemFeasibility()->feasible(model, -1) >= 0) {
+#ifdef BONMIN
+                                std::cout << "Node has become integer feasible" << std::endl;
+                                numberUnsatisfied_ = 0;
+                                break;
+#endif
+                                if (auxiliaryInfo->solutionAddsCuts()) {
+                                    needHotStartUpdate = true;
+                                    solver->unmarkHotStart();
+                                }
+                                model->setLogLevel(saveLogLevel);
+                                model->setBestSolution(CBC_STRONGSOL,
+                                                       newObjectiveValue,
+                                                       solver->getColSolution()) ;
+				if (choice.finishedDown) {
+				  double cutoff = model->getCutoff();
+				  double downObj = objectiveValue_
+				    + choice.downMovement ;
+				  if (downObj >= cutoff) {	
+                                    choice.downMovement = 1.0e100 ;
+                                    numberStrongInfeasible++;
+                                }
+
+				}
+                                if (needHotStartUpdate) {
+                                    model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                                    newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+                                    objectiveValue_ = CoinMax(objectiveValue_,newObjectiveValue);
+                                    objectiveChange = CoinMax(newObjectiveValue  - objectiveValue_, 0.0);
+                                    model->feasibleSolution(choice.numIntInfeasDown,
+                                                            choice.numObjInfeasDown);
+                                }
+                                model->setLastHeuristic(NULL);
+                                model->incrementUsed(solver->getColSolution());
+                                cutoff = model->getCutoff();
+                                if (newObjectiveValue >= cutoff) {	//  *new* cutoff
+                                    objectiveChange = 1.0e100 ;
+                                    numberStrongInfeasible++;
+                                }
+                            }
+                        }
+                    } else if (iStatus == 1) {
+                        objectiveChange = 1.0e100 ;
+                        numberStrongInfeasible++;
+                    } else {
+                        // Can't say much as we did not finish
+                        choice.finishedUp = false ;
+                        numberUnfinished++;
+                    }
+                    choice.upMovement = objectiveChange ;
+
+                    // restore bounds
+                    for ( j = 0; j < numberColumns; j++) {
+                        if (saveLower[j] != lower[j])
+                            solver->setColLower(j, saveLower[j]);
+                        if (saveUpper[j] != upper[j])
+                            solver->setColUpper(j, saveUpper[j]);
+                    }
+                    if (needHotStartUpdate) {
+                        needHotStartUpdate = false;
+                        model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                        double newObjValue = solver->getObjSense()*solver->getObjValue();
+                        objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                        //we may again have an integer feasible solution
+                        int numberIntegerInfeasibilities;
+                        int numberObjectInfeasibilities;
+                        if (model->feasibleSolution(
+                                    numberIntegerInfeasibilities,
+                                    numberObjectInfeasibilities)) {
+                            double objValue = solver->getObjValue();
+                            model->setLogLevel(saveLogLevel);
+                            model->setBestSolution(CBC_STRONGSOL,
+                                                   objValue,
+                                                   solver->getColSolution()) ;
+                            model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                            double newObjValue = solver->getObjSense()*solver->getObjValue();
+                            objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                            cutoff = model->getCutoff();
+                        }
+                        solver->markHotStart();
+#ifdef RESET_BOUNDS
+			memcpy(saveLower,solver->getColLower(),solver->getNumCols()*sizeof(double));
+			memcpy(saveUpper,solver->getColUpper(),solver->getNumCols()*sizeof(double));
+#endif
+			if (!solver->isProvenOptimal()) {
+			  skipAll=-2;
+			  canSkip = 1;
+			}
+                        xMark++;
+                    }
+
+#if 0 //def DO_ALL_AT_ROOT
+                    if (strongType)
+                        printf("Up on %d, status is %d, obj %g its %d cost %g finished %d inf %d infobj %d\n",
+                               choice.objectNumber, iStatus, newObjectiveValue, choice.numItersUp,
+                               choice.upMovement, choice.finishedUp, choice.numIntInfeasUp,
+                               choice.numObjInfeasUp);
+#endif
+                }
+
+                solver->setIntParam(OsiMaxNumIterationHotStart, saveLimit2);
+                /*
+                  End of evaluation for this candidate variable. Possibilities are:
+                  * Both sides below cutoff; this variable is a candidate for branching.
+                  * Both sides infeasible or above the objective cutoff: no further action
+                  here. Break from the evaluation loop and assume the node will be purged
+                  by the caller.
+                  * One side below cutoff: Install the branch (i.e., fix the variable). Break
+                  from the evaluation loop and assume the node will be reoptimised by the
+                  caller.
+                */
+                // reset
+                choice.possibleBranch->resetNumberBranchesLeft();
+                if (choice.upMovement < 1.0e100) {
+                    if (choice.downMovement < 1.0e100) {
+                        // In case solution coming in was odd
+                        choice.upMovement = CoinMax(0.0, choice.upMovement);
+                        choice.downMovement = CoinMax(0.0, choice.downMovement);
+#if ZERO_ONE==2
+                        // branch on 0-1 first (temp)
+                        if (fabs(choice.possibleBranch->value()) < 1.0) {
+                            choice.upMovement *= ZERO_FAKE;
+                            choice.downMovement *= ZERO_FAKE;
+                        }
+#endif
+                        // feasible - see which best
+                        if (!canSkip) {
+                            if (model->messageHandler()->logLevel() > 3)
+                                printf("sort %g downest %g upest %g ", sort[iDo], downEstimate[iObject],
+                                       upEstimate[iObject]);
+                            model->messageHandler()->message(CBC_STRONG, *model->messagesPointer())
+                            << iObject << iColumn
+                            << choice.downMovement << choice.numIntInfeasDown
+                            << choice.upMovement << choice.numIntInfeasUp
+                            << choice.possibleBranch->value()
+                            << CoinMessageEol;
+                        }
+                        int betterWay=0;
+			// If was feasible (extra strong branching) skip
+                        if (infeasibility) {
+                            CbcBranchingObject * branchObj =
+                                dynamic_cast <CbcBranchingObject *>(branch_) ;
+                            if (branch_)
+                                assert (branchObj);
+                            betterWay = decision->betterBranch(choice.possibleBranch,
+                                                               branchObj,
+                                                               choice.upMovement,
+                                                               choice.numIntInfeasUp ,
+                                                               choice.downMovement,
+                                                               choice.numIntInfeasDown );
+                        }
+                        if (betterWay) {
+                            // C) create branching object
+                            if (choiceObject) {
+                                delete branch_;
+                                branch_ = choice.possibleBranch->clone();
+                            } else {
+                                delete branch_;
+                                branch_ = choice.possibleBranch;
+                                choice.possibleBranch = NULL;
+                            }
+                            {
+                                CbcBranchingObject * branchObj =
+                                    dynamic_cast <CbcBranchingObject *>(branch_) ;
+                                assert (branchObj);
+                                //branchObj->way(preferredWay);
+                                branchObj->way(betterWay);
+                            }
+                            bestChoice = choice.objectNumber;
+                            whichChoice = iDo;
+                            if (numberStrong <= 1) {
+                                delete ws;
+                                ws = NULL;
+                                break;
+                            }
+                        } else {
+                            if (!choiceObject) {
+                                delete choice.possibleBranch;
+                                choice.possibleBranch = NULL;
+                            }
+                            if (iDo >= 2*numberStrong) {
+                                delete ws;
+                                ws = NULL;
+                                break;
+                            }
+                            if (!dynamicObject || dynamicObject->numberTimesUp() > 1) {
+                                if (iDo - whichChoice >= numberStrong) {
+                                    if (!choiceObject) {
+                                        delete choice.possibleBranch;
+                                        choice.possibleBranch = NULL;
+                                    }
+                                    break; // give up
+                                }
+                            } else {
+                                if (iDo - whichChoice >= 2*numberStrong) {
+                                    delete ws;
+                                    ws = NULL;
+                                    if (!choiceObject) {
+                                        delete choice.possibleBranch;
+                                        choice.possibleBranch = NULL;
+                                    }
+                                    break; // give up
+                                }
+                            }
+                        }
+                    } else {
+                        // up feasible, down infeasible
+                        anyAction = -1;
+                        worstFeasible = CoinMax(worstFeasible, choice.upMovement);
+                        model->messageHandler()->message(CBC_STRONG, *model->messagesPointer())
+                        << iObject << iColumn
+                        << choice.downMovement << choice.numIntInfeasDown
+                        << choice.upMovement << choice.numIntInfeasUp
+                        << choice.possibleBranch->value()
+                        << CoinMessageEol;
+                        //printf("Down infeasible for choice %d sequence %d\n",i,
+                        // model->object(choice.objectNumber)->columnNumber());
+                        choice.fix = 1;
+                        numberToFix++;
+                        choice.possibleBranch->fix(solver, saveLower, saveUpper, 1);
+                        if (!choiceObject) {
+                            delete choice.possibleBranch;
+                            choice.possibleBranch = NULL;
+                        } else {
+                            //choiceObject = new CbcDynamicPseudoCostBranchingObject(*choiceObject);
+                            choice.possibleBranch = choiceObject;
+                        }
+                        assert(doneHotStart);
+                        solver->unmarkHotStart();
+                        model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                        double newObjValue = solver->getObjSense()*solver->getObjValue();
+                        objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                        bool goneInfeasible = (!solver->isProvenOptimal()||solver->isDualObjectiveLimitReached());
+                        solver->markHotStart();
+#ifdef RESET_BOUNDS
+			memcpy(saveLower,solver->getColLower(),solver->getNumCols()*sizeof(double));
+			memcpy(saveUpper,solver->getColUpper(),solver->getNumCols()*sizeof(double));
+#endif
+			if (!solver->isProvenOptimal()) {
+			  skipAll=-2;
+			  canSkip = 1;
+			}
+                        xMark++;
+                        // may be infeasible (if other way stopped on iterations)
+                        if (goneInfeasible) {
+                            // neither side feasible
+                            anyAction = -2;
+                            if (!choiceObject) {
+                                delete choice.possibleBranch;
+                                choice.possibleBranch = NULL;
+                            }
+                            //printf("Both infeasible for choice %d sequence %d\n",i,
+                            // model->object(choice.objectNumber)->columnNumber());
+                            delete ws;
+                            ws = NULL;
+                            break;
+                        }
+                    }
+                } else {
+                    if (choice.downMovement < 1.0e100) {
+                        // down feasible, up infeasible
+                        anyAction = -1;
+                        worstFeasible = CoinMax(worstFeasible, choice.downMovement);
+                        model->messageHandler()->message(CBC_STRONG, *model->messagesPointer())
+                        << iObject << iColumn
+                        << choice.downMovement << choice.numIntInfeasDown
+                        << choice.upMovement << choice.numIntInfeasUp
+                        << choice.possibleBranch->value()
+                        << CoinMessageEol;
+                        choice.fix = -1;
+                        numberToFix++;
+                        choice.possibleBranch->fix(solver, saveLower, saveUpper, -1);
+                        if (!choiceObject) {
+                            delete choice.possibleBranch;
+                            choice.possibleBranch = NULL;
+                        } else {
+                            //choiceObject = new CbcDynamicPseudoCostBranchingObject(*choiceObject);
+                            choice.possibleBranch = choiceObject;
+                        }
+                        assert(doneHotStart);
+                        solver->unmarkHotStart();
+                        model->resolve(NULL, 11, saveSolution, saveLower, saveUpper);
+                        double newObjValue = solver->getObjSense()*solver->getObjValue();
+                        objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                        bool goneInfeasible = (!solver->isProvenOptimal()||solver->isDualObjectiveLimitReached());
+                        solver->markHotStart();
+#ifdef RESET_BOUNDS
+			memcpy(saveLower,solver->getColLower(),solver->getNumCols()*sizeof(double));
+			memcpy(saveUpper,solver->getColUpper(),solver->getNumCols()*sizeof(double));
+#endif
+			if (!solver->isProvenOptimal()) {
+			  skipAll=-2;
+			  canSkip = 1;
+			}
+                        xMark++;
+                        // may be infeasible (if other way stopped on iterations)
+                        if (goneInfeasible) {
+                            // neither side feasible
+                            anyAction = -2;
+                            if (!choiceObject) {
+                                delete choice.possibleBranch;
+                                choice.possibleBranch = NULL;
+                            }
+                            delete ws;
+                            ws = NULL;
+                            break;
+                        }
+                    } else {
+                        // neither side feasible
+                        anyAction = -2;
+                        if (!choiceObject) {
+                            delete choice.possibleBranch;
+                            choice.possibleBranch = NULL;
+                        }
+                        delete ws;
+                        ws = NULL;
+                        break;
+                    }
+                }
+                // Check max time
+		hitMaxTime = (model->getCurrentSeconds() >
+                               model->getDblParam(CbcModel::CbcMaximumSeconds));
+                if (hitMaxTime) {
+                    // make sure rest are fast
+                    for ( int jDo = iDo + 1; jDo < numberToDo; jDo++) {
+                        int iObject = whichObject[iDo];
+                        OsiObject * object = model->modifiableObject(iObject);
+                        CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                            dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+                        if (dynamicObject)
+                            dynamicObject->setNumberBeforeTrust(0);
+                    }
+                    numberTest = 0;
+                }
+                if (!choiceObject) {
+                    delete choice.possibleBranch;
+                }
+            }
+            if (model->messageHandler()->logLevel() > 3) {
+                if (anyAction == -2) {
+                    printf("infeasible\n");
+                } else if (anyAction == -1) {
+                    printf("%d fixed AND choosing %d iDo %d iChosenWhen %d numberToDo %d\n", numberToFix, bestChoice,
+                           iDo, whichChoice, numberToDo);
+                } else {
+                    int iObject = whichObject[whichChoice];
+                    OsiObject * object = model->modifiableObject(iObject);
+                    CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                        dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+                    if (dynamicObject) {
+                        int iColumn = dynamicObject->columnNumber();
+                        printf("choosing %d (column %d) iChosenWhen %d numberToDo %d\n", bestChoice,
+                               iColumn, whichChoice, numberToDo);
+                    }
+                }
+            }
+            if (doneHotStart) {
+                // Delete the snapshot
+                solver->unmarkHotStart();
+                // back to normal
+                solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+                // restore basis
+                solver->setWarmStart(ws);
+            }
+            solver->setIntParam(OsiMaxNumIterationHotStart, saveLimit);
+            // Unless infeasible we will carry on
+            // But we could fix anyway
+            if (numberToFix && !hitMaxTime) {
+                if (anyAction != -2) {
+                    // apply and take off
+                    bool feasible = true;
+                    // can do quick optimality check
+                    int easy = 2;
+                    solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, &easy) ;
+                    model->resolve(NULL, 11, saveSolution, saveLower, saveUpper) ;
+                    double newObjValue = solver->getObjSense()*solver->getObjValue();
+                    objectiveValue_ = CoinMax(objectiveValue_,newObjValue);
+                    solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+                    feasible = solver->isProvenOptimal();
+                    if (feasible) {
+                        anyAction = 0;
+                    } else {
+                        anyAction = -2;
+                        finished = true;
+                    }
+                }
+            }
+            // If  fixed then round again
+	    // See if candidate still possible
+	    if (branch_) {
+	         const OsiObject * object = model->object(bestChoice);
+		 int preferredWay;
+		 double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+		 if (!infeasibility) {
+		   // take out
+		   delete branch_;
+		   branch_ = NULL;
+		 } else {
+		   CbcBranchingObject * branchObj =
+		     dynamic_cast <CbcBranchingObject *>(branch_) ;
+		   assert (branchObj);
+		   branchObj->way(preferredWay);
+#ifdef CBCNODE_TIGHTEN_BOUNDS
+		   bool fixed = branchObj->tighten(solver);
+		   if (fixed) {
+		     //printf("Variable now fixed!\n");
+		     // take out
+		     delete branch_;
+		     branch_ = NULL;
+		   }
+#endif
+		 }
+	    }
+            if (!branch_ && anyAction != -2 && !hitMaxTime) {
+                finished = false;
+            }
+            delete ws;
+        }
+    }
+    // update number of strong iterations etc
+    model->incrementStrongInfo(numberStrongDone, numberStrongIterations,
+                               anyAction == -2 ? 0 : numberToFix, anyAction == -2);
+    if (model->searchStrategy() == -1) {
+#ifndef COIN_DEVELOP
+        if (solver->messageHandler()->logLevel() > 1)
+#endif
+            printf("%d strong, %d iters, %d inf, %d not finished, %d not trusted\n",
+                   numberStrongDone, numberStrongIterations, numberStrongInfeasible, numberUnfinished,
+                   numberNotTrusted);
+        // decide what to do
+        int strategy = 1;
+        if (((numberUnfinished*4 > numberStrongDone &&
+                numberStrongInfeasible*40 < numberStrongDone) ||
+                numberStrongInfeasible < 0) && model->numberStrong() < 10 && model->numberBeforeTrust() <= 20 && model->numberObjects() > CoinMax(1000, solver->getNumRows())) {
+            strategy = 2;
+#ifdef COIN_DEVELOP
+            //if (model->logLevel()>1)
+            printf("going to strategy 2\n");
+#endif
+            // Weaken
+            model->setNumberStrong(2);
+            model->setNumberBeforeTrust(1);
+            model->synchronizeNumberBeforeTrust();
+        }
+        if (numberNodes)
+            strategy = 1;  // should only happen after hot start
+        model->setSearchStrategy(strategy);
+    } else if (numberStrongDone) {
+        //printf("%d strongB, %d iters, %d inf, %d not finished, %d not trusted\n",
+        //   numberStrongDone,numberStrongIterations,numberStrongInfeasible,numberUnfinished,
+        //   numberNotTrusted);
+    }
+    if (model->searchStrategy() == 1 && numberNodes > 500 && numberNodes < -510) {
+#ifndef COIN_DEVELOP
+        if (solver->messageHandler()->logLevel() > 1)
+#endif
+            printf("after %d nodes - %d strong, %d iters, %d inf, %d not finished, %d not trusted\n",
+                   numberNodes, numberStrongDone, numberStrongIterations, numberStrongInfeasible, numberUnfinished,
+                   numberNotTrusted);
+        // decide what to do
+        if (numberUnfinished*10 > numberStrongDone + 1 ||
+                !numberStrongInfeasible) {
+	  COIN_DETAIL_PRINT(printf("going to strategy 2\n"));
+            // Weaken
+            model->setNumberStrong(2);
+            model->setNumberBeforeTrust(1);
+            model->synchronizeNumberBeforeTrust();
+            model->setSearchStrategy(2);
+        }
+    }
+    if (numberUnfinished*10 < numberStrongDone &&
+	model->numberStrongIterations()*20 < model->getIterationCount()&&
+                                !auxiliaryInfo->solutionAddsCuts()) {
+        //printf("increasing trust\n");
+        model->synchronizeNumberBeforeTrust(2);
+    }
+
+    // Set guessed solution value
+    guessedObjectiveValue_ = objectiveValue_ + estimatedDegradation;
+#ifdef DO_ALL_AT_ROOT
+    if (strongType) {
+      char general[200];
+      if (strongType==1)
+	sprintf(general,"Strong branching on all %d unsatisfied, %d iterations (depth %d)\n",
+		saveNumberToDo,numberStrongIterations,depth_);
+      else
+	sprintf(general,"Strong branching on all %d unfixed variables (%d unsatisfied), %d iterations (depth %d)\n",
+		saveNumberToDo+saveSatisfiedVariables,saveNumberToDo,numberStrongIterations,depth_);
+      model->messageHandler()->message(CBC_FPUMP2,model->messages())
+	<< general << CoinMessageEol ;
+    }
+#endif
+#ifdef DEBUG_SOLUTION
+    if(onOptimalPath&&anyAction==-2) {
+      printf("Gone off optimal path in CbcNode\n");
+      assert(!onOptimalPath||anyAction!=-2);
+    }
+#endif
+    /*
+      Cleanup, then we're finished
+    */
+    if (!model->branchingMethod())
+        delete decision;
+
+    delete choiceObject;
+    delete [] sort;
+    delete [] whichObject;
+#ifdef RANGING
+    delete [] objectMark;
+#endif
+    delete [] saveLower;
+    delete [] saveUpper;
+    delete [] upEstimate;
+    delete [] downEstimate;
+# ifdef COIN_HAS_CLP
+    if (osiclp) {
+        osiclp->setSpecialOptions(saveClpOptions);
+    }
+# endif
+    // restore solution
+    solver->setColSolution(saveSolution);
+    model->reserveCurrentSolution(saveSolution);
+    delete [] saveSolution;
+    model->setStateOfSearch(saveStateOfSearch);
+    model->setLogLevel(saveLogLevel);
+    // delete extra regions
+    if (usefulInfo.usefulRegion_) {
+        delete [] usefulInfo.usefulRegion_;
+        delete [] usefulInfo.indexRegion_;
+        delete [] usefulInfo.pi_;
+        usefulInfo.usefulRegion_ = NULL;
+        usefulInfo.indexRegion_ = NULL;
+        usefulInfo.pi_ = NULL;
+    }
+    useShadow = model->moreSpecialOptions() & 7;
+    if ((useShadow == 5 && model->getSolutionCount()) || useShadow == 6) {
+        // zap pseudo shadow prices
+        model->pseudoShadow(-1);
+        // and switch off
+        model->setMoreSpecialOptions(model->moreSpecialOptions()&(~1023));
+    }
+    return anyAction;
+}
+int CbcNode::analyze (CbcModel *model, double * results)
+{
+    int i;
+    int numberIterationsAllowed = model->numberAnalyzeIterations();
+    OsiSolverInterface * solver = model->solver();
+    objectiveValue_ = solver->getObjSense() * solver->getObjValue();
+    double cutoff = model->getCutoff();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    const double * dj = solver->getReducedCost();
+    int numberObjects = model->numberObjects();
+    int numberColumns = model->getNumCols();
+    // Initialize arrays
+    int numberIntegers = model->numberIntegers();
+    int * back = new int[numberColumns];
+    const int * integerVariable = model->integerVariable();
+    for (i = 0; i < numberColumns; i++)
+        back[i] = -1;
+    // What results is
+    double * newLower = results;
+    double * objLower = newLower + numberIntegers;
+    double * newUpper = objLower + numberIntegers;
+    double * objUpper = newUpper + numberIntegers;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        back[iColumn] = i;
+        newLower[i] = 0.0;
+        objLower[i] = -COIN_DBL_MAX;
+        newUpper[i] = 0.0;
+        objUpper[i] = -COIN_DBL_MAX;
+    }
+    double * saveUpper = new double[numberColumns];
+    double * saveLower = new double[numberColumns];
+    // Save solution in case heuristics need good solution later
+
+    double * saveSolution = new double[numberColumns];
+    memcpy(saveSolution, solver->getColSolution(), numberColumns*sizeof(double));
+    model->reserveCurrentSolution(saveSolution);
+    for (i = 0; i < numberColumns; i++) {
+        saveLower[i] = lower[i];
+        saveUpper[i] = upper[i];
+    }
+    // Get arrays to sort
+    double * sort = new double[numberObjects];
+    int * whichObject = new int[numberObjects];
+    int numberToFix = 0;
+    int numberToDo = 0;
+    double integerTolerance =
+        model->getDblParam(CbcModel::CbcIntegerTolerance);
+    // point to useful information
+    OsiBranchingInformation usefulInfo = model->usefulInformation();
+    // and modify
+    usefulInfo.depth_ = depth_;
+
+    // compute current state
+    int numberObjectInfeasibilities; // just odd ones
+    int numberIntegerInfeasibilities;
+    model->feasibleSolution(
+        numberIntegerInfeasibilities,
+        numberObjectInfeasibilities);
+# ifdef COIN_HAS_CLP
+    OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (solver);
+    int saveClpOptions = 0;
+    bool fastIterations = (model->specialOptions() & 8) != 0;
+    if (osiclp && fastIterations) {
+        // for faster hot start
+        saveClpOptions = osiclp->specialOptions();
+        osiclp->setSpecialOptions(saveClpOptions | 8192);
+    }
+# else
+    bool fastIterations = false ;
+# endif
+    /*
+      Scan for branching objects that indicate infeasibility. Choose candidates
+      using priority as the first criteria, then integer infeasibility.
+
+      The algorithm is to fill the array with a set of good candidates (by
+      infeasibility) with priority bestPriority.  Finding a candidate with
+      priority better (less) than bestPriority flushes the choice array. (This
+      serves as initialization when the first candidate is found.)
+
+    */
+    numberToDo = 0;
+    for (i = 0; i < numberObjects; i++) {
+        OsiObject * object = model->modifiableObject(i);
+        CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+            dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+        if (!dynamicObject)
+            continue;
+        int preferredWay;
+        double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+        int iColumn = dynamicObject->columnNumber();
+        if (saveUpper[iColumn] == saveLower[iColumn])
+            continue;
+        if (infeasibility)
+            sort[numberToDo] = -1.0e10 - infeasibility;
+        else
+            sort[numberToDo] = -fabs(dj[iColumn]);
+        whichObject[numberToDo++] = i;
+    }
+    // Save basis
+    CoinWarmStart * ws = solver->getWarmStart();
+    int saveLimit;
+    solver->getIntParam(OsiMaxNumIterationHotStart, saveLimit);
+    int targetIterations = CoinMax(500, numberIterationsAllowed / numberObjects);
+    if (saveLimit < targetIterations)
+        solver->setIntParam(OsiMaxNumIterationHotStart, targetIterations);
+    // Mark hot start
+    solver->markHotStart();
+    // Sort
+    CoinSort_2(sort, sort + numberToDo, whichObject);
+    double * currentSolution = model->currentSolution();
+    double objMin = 1.0e50;
+    double objMax = -1.0e50;
+    bool needResolve = false;
+    /*
+      Now calculate the cost forcing the variable up and down.
+    */
+    int iDo;
+    for (iDo = 0; iDo < numberToDo; iDo++) {
+        CbcStrongInfo choice;
+        int iObject = whichObject[iDo];
+        OsiObject * object = model->modifiableObject(iObject);
+        CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+            dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object) ;
+        if (!dynamicObject)
+            continue;
+        int iColumn = dynamicObject->columnNumber();
+        int preferredWay;
+        /*
+          Update the information held in the object.
+        */
+        object->infeasibility(&usefulInfo, preferredWay);
+        double value = currentSolution[iColumn];
+        double nearest = floor(value + 0.5);
+        double lowerValue = floor(value);
+        bool satisfied = false;
+        if (fabs(value - nearest) <= integerTolerance || value < saveLower[iColumn] || value > saveUpper[iColumn]) {
+            satisfied = true;
+            double newValue;
+            if (nearest < saveUpper[iColumn]) {
+                newValue = nearest + 1.0001 * integerTolerance;
+                lowerValue = nearest;
+            } else {
+                newValue = nearest - 1.0001 * integerTolerance;
+                lowerValue = nearest - 1;
+            }
+            currentSolution[iColumn] = newValue;
+        }
+        double upperValue = lowerValue + 1.0;
+        //CbcSimpleInteger * obj =
+        //dynamic_cast <CbcSimpleInteger *>(object) ;
+        //if (obj) {
+        //choice.possibleBranch=obj->createCbcBranch(solver,&usefulInfo,preferredWay);
+        //} else {
+        CbcObject * obj =
+            dynamic_cast <CbcObject *>(object) ;
+        assert (obj);
+        choice.possibleBranch = obj->createCbcBranch(solver, &usefulInfo, preferredWay);
+        //}
+        currentSolution[iColumn] = value;
+        // Save which object it was
+        choice.objectNumber = iObject;
+        choice.numIntInfeasUp = numberUnsatisfied_;
+        choice.numIntInfeasDown = numberUnsatisfied_;
+        choice.downMovement = 0.0;
+        choice.upMovement = 0.0;
+        choice.numItersDown = 0;
+        choice.numItersUp = 0;
+        choice.fix = 0; // say not fixed
+        double objectiveChange ;
+        double newObjectiveValue = 1.0e100;
+        int j;
+        // status is 0 finished, 1 infeasible and other
+        int iStatus;
+        /*
+          Try the down direction first. (Specify the initial branching alternative as
+          down with a call to way(-1). Each subsequent call to branch() performs the
+          specified branch and advances the branch object state to the next branch
+          alternative.)
+        */
+        choice.possibleBranch->way(-1) ;
+        choice.possibleBranch->branch() ;
+        if (fabs(value - lowerValue) > integerTolerance) {
+            solver->solveFromHotStart() ;
+            /*
+              We now have an estimate of objective degradation that we can use for strong
+              branching. If we're over the cutoff, the variable is monotone up.
+              If we actually made it to optimality, check for a solution, and if we have
+              a good one, call setBestSolution to process it. Note that this may reduce the
+              cutoff, so we check again to see if we can declare this variable monotone.
+            */
+            if (solver->isProvenOptimal())
+                iStatus = 0; // optimal
+            else if (solver->isIterationLimitReached()
+                     && !solver->isDualObjectiveLimitReached())
+                iStatus = 2; // unknown
+            else
+                iStatus = 1; // infeasible
+            newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+            choice.numItersDown = solver->getIterationCount();
+            numberIterationsAllowed -= choice.numItersDown;
+            objectiveChange = newObjectiveValue  - objectiveValue_;
+            if (!iStatus) {
+                choice.finishedDown = true ;
+                if (newObjectiveValue >= cutoff) {
+                    objectiveChange = 1.0e100; // say infeasible
+                } else {
+                    // See if integer solution
+                    if (model->feasibleSolution(choice.numIntInfeasDown,
+                                                choice.numObjInfeasDown)
+                            && model->problemFeasibility()->feasible(model, -1) >= 0) {
+                        model->setBestSolution(CBC_STRONGSOL,
+                                               newObjectiveValue,
+                                               solver->getColSolution()) ;
+                        model->setLastHeuristic(NULL);
+                        model->incrementUsed(solver->getColSolution());
+                        cutoff = model->getCutoff();
+                        if (newObjectiveValue >= cutoff)	//  *new* cutoff
+                            objectiveChange = 1.0e100 ;
+                    }
+                }
+            } else if (iStatus == 1) {
+                objectiveChange = 1.0e100 ;
+            } else {
+                // Can't say much as we did not finish
+                choice.finishedDown = false ;
+            }
+            choice.downMovement = objectiveChange ;
+        }
+        // restore bounds
+        for ( j = 0; j < numberColumns; j++) {
+            if (saveLower[j] != lower[j])
+                solver->setColLower(j, saveLower[j]);
+            if (saveUpper[j] != upper[j])
+                solver->setColUpper(j, saveUpper[j]);
+        }
+        // repeat the whole exercise, forcing the variable up
+        choice.possibleBranch->branch();
+        if (fabs(value - upperValue) > integerTolerance) {
+            solver->solveFromHotStart() ;
+            /*
+              We now have an estimate of objective degradation that we can use for strong
+              branching. If we're over the cutoff, the variable is monotone up.
+              If we actually made it to optimality, check for a solution, and if we have
+              a good one, call setBestSolution to process it. Note that this may reduce the
+              cutoff, so we check again to see if we can declare this variable monotone.
+            */
+            if (solver->isProvenOptimal())
+                iStatus = 0; // optimal
+            else if (solver->isIterationLimitReached()
+                     && !solver->isDualObjectiveLimitReached())
+                iStatus = 2; // unknown
+            else
+                iStatus = 1; // infeasible
+            newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+            choice.numItersUp = solver->getIterationCount();
+            numberIterationsAllowed -= choice.numItersUp;
+            objectiveChange = newObjectiveValue  - objectiveValue_;
+            if (!iStatus) {
+                choice.finishedUp = true ;
+                if (newObjectiveValue >= cutoff) {
+                    objectiveChange = 1.0e100; // say infeasible
+                } else {
+                    // See if integer solution
+                    if (model->feasibleSolution(choice.numIntInfeasUp,
+                                                choice.numObjInfeasUp)
+                            && model->problemFeasibility()->feasible(model, -1) >= 0) {
+                        model->setBestSolution(CBC_STRONGSOL,
+                                               newObjectiveValue,
+                                               solver->getColSolution()) ;
+                        model->setLastHeuristic(NULL);
+                        model->incrementUsed(solver->getColSolution());
+                        cutoff = model->getCutoff();
+                        if (newObjectiveValue >= cutoff)	//  *new* cutoff
+                            objectiveChange = 1.0e100 ;
+                    }
+                }
+            } else if (iStatus == 1) {
+                objectiveChange = 1.0e100 ;
+            } else {
+                // Can't say much as we did not finish
+                choice.finishedUp = false ;
+            }
+            choice.upMovement = objectiveChange ;
+
+            // restore bounds
+            for ( j = 0; j < numberColumns; j++) {
+                if (saveLower[j] != lower[j])
+                    solver->setColLower(j, saveLower[j]);
+                if (saveUpper[j] != upper[j])
+                    solver->setColUpper(j, saveUpper[j]);
+            }
+        }
+        // If objective goes above certain amount we can set bound
+        int jInt = back[iColumn];
+        newLower[jInt] = upperValue;
+        if (choice.finishedDown)
+            objLower[jInt] = choice.downMovement + objectiveValue_;
+        else
+            objLower[jInt] = objectiveValue_;
+        newUpper[jInt] = lowerValue;
+        if (choice.finishedUp)
+            objUpper[jInt] = choice.upMovement + objectiveValue_;
+        else
+            objUpper[jInt] = objectiveValue_;
+        objMin = CoinMin(CoinMin(objLower[jInt], objUpper[jInt]), objMin);
+        /*
+          End of evaluation for this candidate variable. Possibilities are:
+          * Both sides below cutoff; this variable is a candidate for branching.
+          * Both sides infeasible or above the objective cutoff: no further action
+          here. Break from the evaluation loop and assume the node will be purged
+          by the caller.
+          * One side below cutoff: Install the branch (i.e., fix the variable). Break
+          from the evaluation loop and assume the node will be reoptimised by the
+          caller.
+        */
+        if (choice.upMovement < 1.0e100) {
+            if (choice.downMovement < 1.0e100) {
+                objMax = CoinMax(CoinMax(objLower[jInt], objUpper[jInt]), objMax);
+                // In case solution coming in was odd
+                choice.upMovement = CoinMax(0.0, choice.upMovement);
+                choice.downMovement = CoinMax(0.0, choice.downMovement);
+                // feasible -
+                model->messageHandler()->message(CBC_STRONG, *model->messagesPointer())
+                << iObject << iColumn
+                << choice.downMovement << choice.numIntInfeasDown
+                << choice.upMovement << choice.numIntInfeasUp
+                << value
+                << CoinMessageEol;
+            } else {
+                // up feasible, down infeasible
+                if (!satisfied)
+                    needResolve = true;
+                choice.fix = 1;
+                numberToFix++;
+                saveLower[iColumn] = upperValue;
+                solver->setColLower(iColumn, upperValue);
+            }
+        } else {
+            if (choice.downMovement < 1.0e100) {
+                // down feasible, up infeasible
+                if (!satisfied)
+                    needResolve = true;
+                choice.fix = -1;
+                numberToFix++;
+                saveUpper[iColumn] = lowerValue;
+                solver->setColUpper(iColumn, lowerValue);
+            } else {
+                // neither side feasible
+                COIN_DETAIL_PRINT(printf("Both infeasible for choice %d sequence %d\n", i,
+					 model->object(choice.objectNumber)->columnNumber()));
+                delete ws;
+                ws = NULL;
+                //solver->writeMps("bad");
+                numberToFix = -1;
+                delete choice.possibleBranch;
+                choice.possibleBranch = NULL;
+                break;
+            }
+        }
+        delete choice.possibleBranch;
+        if (numberIterationsAllowed <= 0)
+            break;
+        //printf("obj %d, col %d, down %g up %g value %g\n",iObject,iColumn,
+        //     choice.downMovement,choice.upMovement,value);
+    }
+    COIN_DETAIL_PRINT(printf("Best possible solution %g, can fix more if solution of %g found - looked at %d variables in %d iterations\n",
+			     objMin, objMax, iDo, model->numberAnalyzeIterations() - numberIterationsAllowed));
+    model->setNumberAnalyzeIterations(numberIterationsAllowed);
+    // Delete the snapshot
+    solver->unmarkHotStart();
+    // back to normal
+    solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo, NULL) ;
+    solver->setIntParam(OsiMaxNumIterationHotStart, saveLimit);
+    // restore basis
+    solver->setWarmStart(ws);
+    delete ws;
+
+    delete [] sort;
+    delete [] whichObject;
+    delete [] saveLower;
+    delete [] saveUpper;
+    delete [] back;
+    // restore solution
+    solver->setColSolution(saveSolution);
+# ifdef COIN_HAS_CLP
+    if (osiclp)
+        osiclp->setSpecialOptions(saveClpOptions);
+# endif
+    model->reserveCurrentSolution(saveSolution);
+    delete [] saveSolution;
+    if (needResolve)
+        solver->resolve();
+    return numberToFix;
+}
+
+
+CbcNode::CbcNode(const CbcNode & rhs)
+        : CoinTreeNode(rhs)
+{
+#ifdef CHECK_NODE
+    printf("CbcNode %x Constructor from rhs %x\n", this, &rhs);
+#endif
+    if (rhs.nodeInfo_)
+        nodeInfo_ = rhs.nodeInfo_->clone();
+    else
+        nodeInfo_ = NULL;
+    objectiveValue_ = rhs.objectiveValue_;
+    guessedObjectiveValue_ = rhs.guessedObjectiveValue_;
+    sumInfeasibilities_ = rhs.sumInfeasibilities_;
+    if (rhs.branch_)
+        branch_ = rhs.branch_->clone();
+    else
+        branch_ = NULL;
+    depth_ = rhs.depth_;
+    numberUnsatisfied_ = rhs.numberUnsatisfied_;
+    nodeNumber_ = rhs.nodeNumber_;
+    state_ = rhs.state_;
+    if (nodeInfo_)
+        assert ((state_&2) != 0);
+    else
+        assert ((state_&2) == 0);
+}
+
+CbcNode &
+CbcNode::operator=(const CbcNode & rhs)
+{
+    if (this != &rhs) {
+        delete nodeInfo_;
+        if (rhs.nodeInfo_)
+            nodeInfo_ = rhs.nodeInfo_->clone();
+        else
+            nodeInfo_ = NULL;
+        objectiveValue_ = rhs.objectiveValue_;
+        guessedObjectiveValue_ = rhs.guessedObjectiveValue_;
+        sumInfeasibilities_ = rhs.sumInfeasibilities_;
+        if (rhs.branch_)
+            branch_ = rhs.branch_->clone();
+        else
+            branch_ = NULL,
+                      depth_ = rhs.depth_;
+        numberUnsatisfied_ = rhs.numberUnsatisfied_;
+        nodeNumber_ = rhs.nodeNumber_;
+        state_ = rhs.state_;
+        if (nodeInfo_)
+            assert ((state_&2) != 0);
+        else
+            assert ((state_&2) == 0);
+    }
+    return *this;
+}
+CbcNode::~CbcNode ()
+{
+#ifdef CHECK_NODE
+    if (nodeInfo_) {
+        printf("CbcNode %x Destructor nodeInfo %x (%d)\n",
+               this, nodeInfo_, nodeInfo_->numberPointingToThis());
+        //assert(nodeInfo_->numberPointingToThis()>=0);
+    } else {
+        printf("CbcNode %x Destructor nodeInfo %x (?)\n",
+               this, nodeInfo_);
+    }
+#endif
+    if (nodeInfo_) {
+        // was if (nodeInfo_&&(state_&2)!=0) {
+        nodeInfo_->nullOwner();
+        int numberToDelete = nodeInfo_->numberBranchesLeft();
+        //    CbcNodeInfo * parent = nodeInfo_->parent();
+        //assert (nodeInfo_->numberPointingToThis()>0);
+        if (nodeInfo_->decrement(numberToDelete) == 0 || (state_&2) == 0) {
+            if ((state_&2) == 0)
+                nodeInfo_->nullParent();
+            delete nodeInfo_;
+        } else {
+            //printf("node %x nodeinfo %x parent %x\n",this,nodeInfo_,nodeInfo_->parent());
+            // anyway decrement parent
+            //if (parent)
+            ///parent->decrement(1);
+        }
+    }
+    delete branch_;
+}
+// Decrement  active cut counts
+void
+CbcNode::decrementCuts(int change)
+{
+    if (nodeInfo_)
+        assert ((state_&2) != 0);
+    else
+        assert ((state_&2) == 0);
+    if (nodeInfo_) {
+        nodeInfo_->decrementCuts(change);
+    }
+}
+void
+CbcNode::decrementParentCuts(CbcModel * model, int change)
+{
+    if (nodeInfo_)
+        assert ((state_&2) != 0);
+    else
+        assert ((state_&2) == 0);
+    if (nodeInfo_) {
+        nodeInfo_->decrementParentCuts(model, change);
+    }
+}
+
+/*
+  Initialize reference counts (numberPointingToThis, numberBranchesLeft_)
+  in the attached nodeInfo_.
+*/
+void
+CbcNode::initializeInfo()
+{
+    assert(nodeInfo_ && branch_) ;
+    nodeInfo_->initializeInfo(branch_->numberBranches());
+    assert ((state_&2) != 0);
+    assert (nodeInfo_->numberBranchesLeft() ==
+            branch_->numberBranchesLeft());
+}
+// Nulls out node info
+void
+CbcNode::nullNodeInfo()
+{
+    nodeInfo_ = NULL;
+    // say not active
+    state_ &= ~2;
+}
+
+int
+CbcNode::branch(OsiSolverInterface * solver)
+{
+    double changeInGuessed;
+    assert (nodeInfo_->numberBranchesLeft() ==
+            branch_->numberBranchesLeft());
+    if (!solver)
+        changeInGuessed = branch_->branch();
+    else
+        changeInGuessed = branch_->branch(solver);
+    guessedObjectiveValue_ += changeInGuessed;
+    //#define PRINTIT
+#ifdef PRINTIT
+    int numberLeft = nodeInfo_->numberBranchesLeft();
+    CbcNodeInfo * parent = nodeInfo_->parent();
+    int parentNodeNumber = -1;
+    CbcBranchingObject * object1 =
+        dynamic_cast<CbcBranchingObject *>(branch_) ;
+    //OsiObject * object = object1->
+    //int sequence = object->columnNumber);
+    int id = -1;
+    double value = 0.0;
+    if (object1) {
+        id = object1->variable();
+        value = object1->value();
+    }
+    printf("id %d value %g objvalue %g\n", id, value, objectiveValue_);
+    if (parent)
+        parentNodeNumber = parent->nodeNumber();
+    printf("Node number %d, %s, way %d, depth %d, parent node number %d\n",
+           nodeInfo_->nodeNumber(), (numberLeft == 2) ? "leftBranch" : "rightBranch",
+           way(), depth_, parentNodeNumber);
+    assert (parentNodeNumber != nodeInfo_->nodeNumber());
+#endif
+    return nodeInfo_->branchedOn();
+}
+/* Active arm of the attached OsiBranchingObject.
+
+   In the simplest instance, coded -1 for the down arm of the branch, +1 for
+   the up arm. But see OsiBranchingObject::way()
+   Use nodeInfo--.numberBranchesLeft_ to see how active
+
+   Except that there is no OsiBranchingObject::way(), and this'll fail in any
+   event because we have various OsiXXXBranchingObjects which aren't descended
+   from CbcBranchingObjects. I think branchIndex() is the appropriate
+   equivalent, but could be wrong. (lh, 061220)
+
+   071212: I'm finally getting back to cbc-generic and rescuing a lot of my
+   annotation from branches/devel (which was killed in summer). I'm going to
+   put back an assert(obj) just to see what happens. It's still present as of
+   the most recent change to CbcNode (r833).
+
+   080104: Yep, we can arrive here with an OsiBranchingObject. Removed the
+   assert, it's served its purpose.
+
+   080226: John finally noticed this problem and added a way() method to the
+   OsiBranchingObject hierarchy. Removing my workaround.
+
+*/
+int
+CbcNode::way() const
+{
+    if (branch_) {
+        CbcBranchingObject * obj =
+            dynamic_cast <CbcBranchingObject *>(branch_) ;
+        if (obj) {
+            return obj->way();
+        } else {
+            OsiTwoWayBranchingObject * obj2 =
+                dynamic_cast <OsiTwoWayBranchingObject *>(branch_) ;
+            assert (obj2);
+            return obj2->way();
+        }
+    } else {
+        return 0;
+    }
+}
+/* Create a branching object for the node
+
+   The routine scans the object list of the model and selects a set of
+   unsatisfied objects as candidates for branching. The candidates are
+   evaluated, and an appropriate branch object is installed.
+
+   The numberPassesLeft is decremented to stop fixing one variable each time
+   and going on and on (e.g. for stock cutting, air crew scheduling)
+
+   If evaluation determines that an object is monotone or infeasible,
+   the routine returns immediately. In the case of a monotone object,
+   the branch object has already been called to modify the model.
+
+   Return value:
+   <ul>
+   <li>  0: A branching object has been installed
+   <li> -1: A monotone object was discovered
+   <li> -2: An infeasible object was discovered
+   </ul>
+   Branch state:
+   <ul>
+   <li> -1: start
+   <li> -1: A monotone object was discovered
+   <li> -2: An infeasible object was discovered
+   </ul>
+*/
+int
+CbcNode::chooseOsiBranch (CbcModel * model,
+                          CbcNode * lastNode,
+                          OsiBranchingInformation * usefulInfo,
+                          int branchState)
+{
+    int returnStatus = 0;
+    if (lastNode)
+        depth_ = lastNode->depth_ + 1;
+    else
+        depth_ = 0;
+    OsiSolverInterface * solver = model->solver();
+    objectiveValue_ = solver->getObjValue() * solver->getObjSense();
+    usefulInfo->objectiveValue_ = objectiveValue_;
+    usefulInfo->depth_ = depth_;
+    const double * saveInfoSol = usefulInfo->solution_;
+    double * saveSolution = new double[solver->getNumCols()];
+    memcpy(saveSolution, solver->getColSolution(), solver->getNumCols()*sizeof(double));
+    usefulInfo->solution_ = saveSolution;
+    OsiChooseVariable * choose = model->branchingMethod()->chooseMethod();
+    int numberUnsatisfied = -1;
+    if (branchState < 0) {
+        // initialize
+        // initialize sum of "infeasibilities"
+        sumInfeasibilities_ = 0.0;
+        numberUnsatisfied = choose->setupList(usefulInfo, true);
+        numberUnsatisfied_ = numberUnsatisfied;
+        branchState = 0;
+        if (numberUnsatisfied_ < 0) {
+            // infeasible
+            delete [] saveSolution;
+            return -2;
+        }
+    }
+    // unset best
+    int best = -1;
+    choose->setBestObjectIndex(-1);
+    if (numberUnsatisfied) {
+        if (branchState > 0 || !choose->numberOnList()) {
+            // we need to return at once - don't do strong branching or anything
+            if (choose->numberOnList() || !choose->numberStrong()) {
+                best = choose->candidates()[0];
+                choose->setBestObjectIndex(best);
+            } else {
+                // nothing on list - need to try again - keep any solution
+                numberUnsatisfied = choose->setupList(usefulInfo, false);
+                numberUnsatisfied_ = numberUnsatisfied;
+                if (numberUnsatisfied) {
+                    best = choose->candidates()[0];
+                    choose->setBestObjectIndex(best);
+                }
+            }
+        } else {
+            // carry on with strong branching or whatever
+            int returnCode = choose->chooseVariable(solver, usefulInfo, true);
+            // update number of strong iterations etc
+            model->incrementStrongInfo(choose->numberStrongDone(), choose->numberStrongIterations(),
+                                       returnCode == -1 ? 0 : choose->numberStrongFixed(), returnCode == -1);
+            if (returnCode > 1) {
+                // has fixed some
+                returnStatus = -1;
+            } else if (returnCode == -1) {
+                // infeasible
+                returnStatus = -2;
+            } else if (returnCode == 0) {
+                // normal
+                returnStatus = 0;
+                numberUnsatisfied = 1;
+            } else {
+                // ones on list satisfied - double check
+                numberUnsatisfied = choose->setupList(usefulInfo, false);
+                numberUnsatisfied_ = numberUnsatisfied;
+                if (numberUnsatisfied) {
+                    best = choose->candidates()[0];
+                    choose->setBestObjectIndex(best);
+                }
+            }
+        }
+    }
+    delete branch_;
+    branch_ = NULL;
+    guessedObjectiveValue_ = COIN_DBL_MAX;//objectiveValue_; // for now
+    if (!returnStatus) {
+        if (numberUnsatisfied) {
+            // create branching object
+            const OsiObject * obj = model->solver()->object(choose->bestObjectIndex());
+            //const OsiSolverInterface * solver = usefulInfo->solver_;
+            branch_ = obj->createBranch(model->solver(), usefulInfo, obj->whichWay());
+        }
+    }
+    usefulInfo->solution_ = saveInfoSol;
+    delete [] saveSolution;
+    // may have got solution
+    if (choose->goodSolution()
+            && model->problemFeasibility()->feasible(model, -1) >= 0) {
+        // yes
+        double objValue = choose->goodObjectiveValue();
+        model->setBestSolution(CBC_STRONGSOL,
+                               objValue,
+                               choose->goodSolution()) ;
+        model->setLastHeuristic(NULL);
+        model->incrementUsed(choose->goodSolution());
+        choose->clearGoodSolution();
+    }
+    return returnStatus;
+}
+int
+CbcNode::chooseClpBranch (CbcModel * model,
+                          CbcNode * lastNode)
+{
+    assert(lastNode);
+    depth_ = lastNode->depth_ + 1;
+    delete branch_;
+    branch_ = NULL;
+    OsiSolverInterface * solver = model->solver();
+    //double saveObjectiveValue = solver->getObjValue();
+    //double objectiveValue = CoinMax(solver->getObjSense()*saveObjectiveValue,objectiveValue_);
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    // point to useful information
+    OsiBranchingInformation usefulInfo = model->usefulInformation();
+    // and modify
+    usefulInfo.depth_ = depth_;
+    int i;
+    //bool beforeSolution = model->getSolutionCount()==0;
+    int numberObjects = model->numberObjects();
+    int numberColumns = model->getNumCols();
+    double * saveUpper = new double[numberColumns];
+    double * saveLower = new double[numberColumns];
+
+    // Save solution in case heuristics need good solution later
+
+    double * saveSolution = new double[numberColumns];
+    memcpy(saveSolution, solver->getColSolution(), numberColumns*sizeof(double));
+    model->reserveCurrentSolution(saveSolution);
+    for (i = 0; i < numberColumns; i++) {
+        saveLower[i] = lower[i];
+        saveUpper[i] = upper[i];
+    }
+    // Save basis
+    CoinWarmStart * ws = solver->getWarmStart();
+    numberUnsatisfied_ = 0;
+    // initialize sum of "infeasibilities"
+    sumInfeasibilities_ = 0.0;
+    // Note looks as if off end (hidden one)
+    OsiObject * object = model->modifiableObject(numberObjects);
+    CbcGeneralDepth * thisOne = dynamic_cast <CbcGeneralDepth *> (object);
+    assert (thisOne);
+    OsiClpSolverInterface * clpSolver
+    = dynamic_cast<OsiClpSolverInterface *> (solver);
+    assert (clpSolver);
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+    int preferredWay;
+    double infeasibility = object->infeasibility(&usefulInfo, preferredWay);
+    if (thisOne->whichSolution() >= 0) {
+        ClpNode * nodeInfo=NULL;
+        if ((model->moreSpecialOptions()&33554432)==0) {
+	  nodeInfo = thisOne->nodeInfo(thisOne->whichSolution());
+	  nodeInfo->applyNode(simplex, 2);
+	} else {
+	  // from diving
+	  CbcSubProblem ** nodes = reinterpret_cast<CbcSubProblem **>
+	    (model->temporaryPointer());
+	  assert (nodes);
+	  int numberDo=thisOne->numberNodes()-1;
+	  for (int iNode=0;iNode<numberDo;iNode++)
+	    nodes[iNode]->apply(solver,1);
+	  nodes[numberDo]->apply(solver,9+16);
+	}
+        int saveLogLevel = simplex->logLevel();
+        simplex->setLogLevel(0);
+        simplex->dual();
+        simplex->setLogLevel(saveLogLevel);
+        double cutoff = model->getCutoff();
+        bool goodSolution = true;
+        if (simplex->status()) {
+            //simplex->writeMps("bad7.mps",2);
+	    if (nodeInfo) {
+	      if (nodeInfo->objectiveValue() > cutoff - 1.0e-2)
+                goodSolution = false;
+	      else
+                assert (!simplex->status());
+	    } else {
+	      // debug diving
+	      assert (!simplex->status());
+	    }
+        }
+        if (goodSolution) {
+            double newObjectiveValue = solver->getObjSense() * solver->getObjValue();
+            // See if integer solution
+            int numInf;
+            int numInf2;
+            bool gotSol = model->feasibleSolution(numInf, numInf2);
+            if (!gotSol) {
+	      COIN_DETAIL_PRINT(printf("numinf %d\n", numInf));
+                double * sol = simplex->primalColumnSolution();
+                for (int i = 0; i < numberColumns; i++) {
+                    if (simplex->isInteger(i)) {
+                        double value = floor(sol[i] + 0.5);
+                        if (fabs(value - sol[i]) > 1.0e-7) {
+			  COIN_DETAIL_PRINT(printf("%d value %g\n", i, sol[i]));
+                            if (fabs(value - sol[i]) < 1.0e-3) {
+                                sol[i] = value;
+                            }
+                        }
+                    }
+                }
+                simplex->writeMps("bad8.mps", 2);
+                bool gotSol = model->feasibleSolution(numInf, numInf2);
+                if (!gotSol)
+                    assert (gotSol);
+            }
+            model->setBestSolution(CBC_STRONGSOL,
+                                   newObjectiveValue,
+                                   solver->getColSolution()) ;
+            model->setLastHeuristic(NULL);
+            model->incrementUsed(solver->getColSolution());
+        }
+    }
+    // restore bounds
+    {
+        for (int j = 0; j < numberColumns; j++) {
+            if (saveLower[j] != lower[j])
+                solver->setColLower(j, saveLower[j]);
+            if (saveUpper[j] != upper[j])
+                solver->setColUpper(j, saveUpper[j]);
+        }
+    }
+    // restore basis
+    solver->setWarmStart(ws);
+    delete ws;
+    int anyAction;
+    //#define CHECK_PATH
+#ifdef CHECK_PATH
+    extern int gotGoodNode_Z;
+    if (gotGoodNode_Z >= 0)
+        printf("good node %d %g\n", gotGoodNode_Z, infeasibility);
+#endif
+    if (infeasibility > 0.0) {
+        if (infeasibility == COIN_DBL_MAX) {
+            anyAction = -2; // infeasible
+        } else {
+            branch_ = thisOne->createCbcBranch(solver, &usefulInfo, preferredWay);
+	    if (branch_) {
+	      // Set to first one (and change when re-pushing)
+	      CbcGeneralBranchingObject * branch =
+                dynamic_cast <CbcGeneralBranchingObject *> (branch_);
+	      branch->state(objectiveValue_, sumInfeasibilities_,
+			    numberUnsatisfied_, 0);
+	      branch->setNode(this);
+	      anyAction = 0;
+	    } else {
+	      anyAction = -2; // mark as infeasible
+	    }
+        }
+    } else {
+        anyAction = -1;
+    }
+#ifdef CHECK_PATH
+    gotGoodNode_Z = -1;
+#endif
+    // Set guessed solution value
+    guessedObjectiveValue_ = objectiveValue_ + 1.0e-5;
+    delete [] saveLower;
+    delete [] saveUpper;
+
+    // restore solution
+    solver->setColSolution(saveSolution);
+    delete [] saveSolution;
+    return anyAction;
+}
+/* Double checks in case node can change its mind!
+   Returns objective value
+   Can change objective etc */
+double
+CbcNode::checkIsCutoff(double cutoff)
+{
+    branch_->checkIsCutoff(cutoff);
+    return objectiveValue_;
+}
+
diff --git a/cbits/coin/CbcNode.hpp b/cbits/coin/CbcNode.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcNode.hpp
@@ -0,0 +1,345 @@
+/* $Id: CbcNode.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcNode_H
+#define CbcNode_H
+
+#include <string>
+#include <vector>
+
+#include "CoinWarmStartBasis.hpp"
+#include "CoinSearchTree.hpp"
+#include "CbcBranchBase.hpp"
+#include "CbcNodeInfo.hpp"
+#include "CbcFullNodeInfo.hpp"
+#include "CbcPartialNodeInfo.hpp"
+
+class OsiSolverInterface;
+class OsiSolverBranch;
+
+class OsiCuts;
+class OsiRowCut;
+class OsiRowCutDebugger;
+class CoinWarmStartBasis;
+class CbcCountRowCut;
+class CbcModel;
+class CbcNode;
+class CbcSubProblem;
+class CbcGeneralBranchingObject;
+
+/** Information required while the node is live
+
+  When a subproblem is initially created, it is represented by an CbcNode
+  object and an attached CbcNodeInfo object.
+
+  The CbcNode contains information (depth, branching instructions), that's
+  needed while the subproblem remains `live', <i>i.e.</i>, while the
+  subproblem is not fathomed and there are branch arms still be be
+  evaluated.  The CbcNode is deleted when the last branch arm has been
+  evaluated.
+
+  The CbcNodeInfo object contains the information needed to maintain the
+  search tree and recreate the subproblem for the node. It remains in
+  existence until there are no nodes remaining in the subtree rooted at this
+  node.
+*/
+
+class CbcNode : public CoinTreeNode {
+
+public:
+
+    /// Default Constructor
+    CbcNode ();
+
+    /// Construct and increment parent reference count
+    CbcNode (CbcModel * model, CbcNode * lastNode);
+
+    /// Copy constructor
+    CbcNode (const CbcNode &);
+
+    /// Assignment operator
+    CbcNode & operator= (const CbcNode& rhs);
+
+    /// Destructor
+    ~CbcNode ();
+
+    /** Create a description of the subproblem at this node
+
+      The CbcNodeInfo structure holds the information (basis & variable bounds)
+      required to recreate the subproblem for this node. It also links the node
+      to its parent (via the parent's CbcNodeInfo object).
+
+      If lastNode == NULL, a CbcFullNodeInfo object will be created. All
+      parameters except \p model are unused.
+
+      If lastNode != NULL, a CbcPartialNodeInfo object will be created. Basis and
+      bounds information will be stored in the form of differences between the
+      parent subproblem and this subproblem.
+      (More precisely, \p lastws, \p lastUpper, \p lastLower,
+      \p numberOldActiveCuts, and \p numberNewCuts are used.)
+    */
+    void
+    createInfo(CbcModel * model,
+               CbcNode * lastNode,
+               const CoinWarmStartBasis *lastws,
+               const double * lastLower, const double * lastUpper,
+               int numberOldActiveCuts, int numberNewCuts);
+
+    /** Create a branching object for the node
+
+      The routine scans the object list of the model and selects a set of
+      unsatisfied objects as candidates for branching. The candidates are
+      evaluated, and an appropriate branch object is installed.
+
+      The numberPassesLeft is decremented to stop fixing one variable each time
+      and going on and on (e.g. for stock cutting, air crew scheduling)
+
+      If evaluation determines that an object is monotone or infeasible,
+      the routine returns immediately. In the case of a monotone object,
+      the branch object has already been called to modify the model.
+
+      Return value:
+      <ul>
+        <li>  0: A branching object has been installed
+        <li> -1: A monotone object was discovered
+        <li> -2: An infeasible object was discovered
+      </ul>
+    */
+    int chooseBranch (CbcModel * model,
+                      CbcNode * lastNode,
+                      int numberPassesLeft);
+    /** Create a branching object for the node - when dynamic pseudo costs
+
+      The routine scans the object list of the model and selects a set of
+      unsatisfied objects as candidates for branching. The candidates are
+      evaluated, and an appropriate branch object is installed.
+      This version gives preference in evaluation to variables which
+      have not been evaluated many times.  It also uses numberStrong
+      to say give up if last few tries have not changed incumbent.
+      See Achterberg, Koch and Martin.
+
+      The numberPassesLeft is decremented to stop fixing one variable each time
+      and going on and on (e.g. for stock cutting, air crew scheduling)
+
+      If evaluation determines that an object is monotone or infeasible,
+      the routine returns immediately. In the case of a monotone object,
+      the branch object has already been called to modify the model.
+
+      Return value:
+      <ul>
+        <li>  0: A branching object has been installed
+        <li> -1: A monotone object was discovered
+        <li> -2: An infeasible object was discovered
+        <li> >0: Number of quich branching objects (and branches will be non NULL)
+      </ul>
+    */
+    int chooseDynamicBranch (CbcModel * model,
+                             CbcNode * lastNode,
+                             OsiSolverBranch * & branches,
+                             int numberPassesLeft);
+    /** Create a branching object for the node
+
+      The routine scans the object list of the model and selects a set of
+      unsatisfied objects as candidates for branching. The candidates are
+      evaluated, and an appropriate branch object is installed.
+
+      The numberPassesLeft is decremented to stop fixing one variable each time
+      and going on and on (e.g. for stock cutting, air crew scheduling)
+
+      If evaluation determines that an object is monotone or infeasible,
+      the routine returns immediately. In the case of a monotone object,
+      the branch object has already been called to modify the model.
+
+      Return value:
+      <ul>
+        <li>  0: A branching object has been installed
+        <li> -1: A monotone object was discovered
+        <li> -2: An infeasible object was discovered
+      </ul>
+      Branch state:
+      <ul>
+        <li> -1: start
+        <li> -1: A monotone object was discovered
+        <li> -2: An infeasible object was discovered
+      </ul>
+    */
+    int chooseOsiBranch (CbcModel * model,
+                         CbcNode * lastNode,
+                         OsiBranchingInformation * usefulInfo,
+                         int branchState);
+    /** Create a branching object for the node
+
+      The routine scans the object list of the model and selects a set of
+      unsatisfied objects as candidates for branching. It then solves a
+      series of problems and a CbcGeneral branch object is installed.
+
+      If evaluation determines that an object is infeasible,
+      the routine returns immediately.
+
+      Return value:
+      <ul>
+        <li>  0: A branching object has been installed
+        <li> -2: An infeasible object was discovered
+      </ul>
+    */
+    int chooseClpBranch (CbcModel * model,
+                         CbcNode * lastNode);
+    int analyze(CbcModel * model, double * results);
+    /// Decrement active cut counts
+    void decrementCuts(int change = 1);
+
+    /// Decrement all active cut counts in chain starting at parent
+    void decrementParentCuts(CbcModel * model, int change = 1);
+
+    /// Nulls out node info
+    void nullNodeInfo();
+    /** Initialize reference counts in attached CbcNodeInfo
+
+      This is a convenience routine, which will initialize the reference counts
+      in the attached CbcNodeInfo object based on the attached
+      OsiBranchingObject.
+
+      \sa CbcNodeInfo::initializeInfo(int).
+    */
+    void initializeInfo();
+
+    /// Does next branch and updates state
+    int branch(OsiSolverInterface * solver);
+
+    /** Double checks in case node can change its mind!
+        Returns objective value
+        Can change objective etc */
+    double checkIsCutoff(double cutoff);
+    // Information to make basis and bounds
+    inline CbcNodeInfo * nodeInfo() const {
+        return nodeInfo_;
+    }
+
+    // Objective value
+    inline double objectiveValue() const {
+        return objectiveValue_;
+    }
+    inline void setObjectiveValue(double value) {
+        objectiveValue_ = value;
+    }
+    /// Number of arms defined for the attached OsiBranchingObject.
+    inline int numberBranches() const {
+        if (branch_)
+            return (branch_->numberBranches()) ;
+        else
+            return (-1) ;
+    }
+
+    /* Active arm of the attached OsiBranchingObject.
+
+     In the simplest instance, coded -1 for the down arm of the branch, +1 for
+     the up arm. But see OsiBranchingObject::way()
+       Use nodeInfo--.numberBranchesLeft_ to see how active
+    */
+    int way() const;
+    /// Depth in branch-and-cut search tree
+    inline int depth() const {
+        return depth_;
+    }
+    /// Set depth in branch-and-cut search tree
+    inline void setDepth(int value) {
+        depth_ = value;
+    }
+    /// Get the number of objects unsatisfied at this node.
+    inline int numberUnsatisfied() const {
+        return numberUnsatisfied_;
+    }
+    /// Set the number of objects unsatisfied at this node.
+    inline void setNumberUnsatisfied(int value) {
+        numberUnsatisfied_ = value;
+    }
+    /// Get sum of "infeasibilities" reported by each object
+    inline double sumInfeasibilities() const {
+        return sumInfeasibilities_;
+    }
+    /// Set sum of "infeasibilities" reported by each object
+    inline void setSumInfeasibilities(double value) {
+        sumInfeasibilities_ = value;
+    }
+    // Guessed objective value (for solution)
+    inline double guessedObjectiveValue() const {
+        return guessedObjectiveValue_;
+    }
+    inline void setGuessedObjectiveValue(double value) {
+        guessedObjectiveValue_ = value;
+    }
+    /// Branching object for this node
+    inline const OsiBranchingObject * branchingObject() const {
+        return branch_;
+    }
+    /// Modifiable branching object for this node
+    inline OsiBranchingObject * modifiableBranchingObject() const {
+        return branch_;
+    }
+    /// Set branching object for this node (takes ownership)
+    inline void setBranchingObject(OsiBranchingObject * branchingObject) {
+        branch_ = branchingObject;
+    }
+    /// The node number
+    inline int nodeNumber() const {
+        return nodeNumber_;
+    }
+    inline void setNodeNumber(int node) {
+        nodeNumber_ = node;
+    }
+    /// Returns true if on tree
+    inline bool onTree() const {
+        return (state_&1) != 0;
+    }
+    /// Sets true if on tree
+    inline void setOnTree(bool yesNo) {
+        if (yesNo) state_ |= 1;
+        else state_ &= ~1;
+    }
+    /// Returns true if active
+    inline bool active() const {
+        return (state_&2) != 0;
+    }
+    /// Sets true if active
+    inline void setActive(bool yesNo) {
+        if (yesNo) state_ |= 2;
+        else state_ &= ~2;
+    }
+    /// Print
+    void print() const;
+    /// Debug
+    inline void checkInfo() const {
+        assert (nodeInfo_->numberBranchesLeft() ==
+                branch_->numberBranchesLeft());
+    }
+
+private:
+    // Data
+    /// Information to make basis and bounds
+    CbcNodeInfo * nodeInfo_;
+    /// Objective value
+    double objectiveValue_;
+    /// Guessed satisfied Objective value
+    double guessedObjectiveValue_;
+    /// Sum of "infeasibilities" reported by each object
+    double sumInfeasibilities_;
+    /// Branching object for this node
+    OsiBranchingObject * branch_;
+    /// Depth of the node in the search tree
+    int depth_;
+    /// The number of objects unsatisfied at this node.
+    int numberUnsatisfied_;
+    /// The node number
+    int nodeNumber_;
+    /** State
+        1 - on tree
+        2 - active
+    */
+    int state_;
+};
+
+
+#endif
+
diff --git a/cbits/coin/CbcNodeInfo.cpp b/cbits/coin/CbcNodeInfo.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcNodeInfo.cpp
@@ -0,0 +1,510 @@
+// $Id: CbcNodeInfo.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/24/09 carved from CbcNode
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcConfig.h"
+
+#include <string>
+//#define CBC_DEBUG 1
+//#define CHECK_CUT_COUNTS
+//#define CHECK_NODE
+//#define CBC_CHECK_BASIS
+#include <cassert>
+#include <cfloat>
+#define CUTS
+#include "OsiSolverInterface.hpp"
+#include "OsiChooseVariable.hpp"
+#include "OsiAuxInfo.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinTime.hpp"
+#include "CbcModel.hpp"
+#include "CbcNode.hpp"
+#include "CbcStatistics.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "OsiCuts.hpp"
+#include "CbcCountRowCut.hpp"
+#include "CbcFeasibilityBase.hpp"
+#include "CbcMessage.hpp"
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#include "ClpSimplexOther.hpp"
+#endif
+using namespace std;
+#include "CglCutGenerator.hpp"
+#include "CbcNodeInfo.hpp"
+
+// Default Constructor
+CbcNodeInfo::CbcNodeInfo ()
+        :
+        numberPointingToThis_(0),
+        parent_(NULL),
+        parentBranch_(NULL),
+        owner_(NULL),
+        numberCuts_(0),
+        nodeNumber_(0),
+        cuts_(NULL),
+        numberRows_(0),
+        numberBranchesLeft_(0),
+        active_(7)
+{
+#ifdef CHECK_NODE
+    printf("CbcNodeInfo %x Constructor\n", this);
+#endif
+}
+
+void
+CbcNodeInfo::setParentBasedData()
+{
+    if (parent_) {
+        numberRows_ = parent_->numberRows_ + parent_->numberCuts_;
+        //parent_->increment();
+        if (parent_->owner()) {
+            const OsiBranchingObject* br = parent_->owner()->branchingObject();
+            assert(br);
+            parentBranch_ = br->clone();
+        }
+    }
+}
+
+void
+CbcNodeInfo::unsetParentBasedData()
+{
+    if (parent_) {
+        numberRows_ = 0;
+        if (parent_->owner()) {
+            delete parentBranch_;
+            parentBranch_ = NULL;
+        }
+    }
+}
+
+#ifdef JJF_ZERO
+// Constructor given parent
+CbcNodeInfo::CbcNodeInfo (CbcNodeInfo * parent)
+        :
+        numberPointingToThis_(2),
+        parent_(parent),
+        parentBranch_(NULL),
+        owner_(NULL),
+        numberCuts_(0),
+        nodeNumber_(0),
+        cuts_(NULL),
+        numberRows_(0),
+        numberBranchesLeft_(2),
+        active_(7)
+{
+#ifdef CHECK_NODE
+    printf("CbcNodeInfo %x Constructor from parent %x\n", this, parent_);
+#endif
+    //setParentBasedData();
+}
+#endif
+
+// Copy Constructor
+CbcNodeInfo::CbcNodeInfo (const CbcNodeInfo & rhs)
+        :
+        numberPointingToThis_(rhs.numberPointingToThis_),
+        parent_(rhs.parent_),
+        parentBranch_(NULL),
+        owner_(rhs.owner_),
+        numberCuts_(rhs.numberCuts_),
+        nodeNumber_(rhs.nodeNumber_),
+        cuts_(NULL),
+        numberRows_(rhs.numberRows_),
+        numberBranchesLeft_(rhs.numberBranchesLeft_),
+        active_(rhs.active_)
+{
+#ifdef CHECK_NODE
+    printf("CbcNodeInfo %x Copy constructor\n", this);
+#endif
+    if (numberCuts_) {
+        cuts_ = new CbcCountRowCut * [numberCuts_];
+        int n = 0;
+        for (int i = 0; i < numberCuts_; i++) {
+            CbcCountRowCut * thisCut = rhs.cuts_[i];
+            if (thisCut) {
+                // I think this is correct - new one should take priority
+                thisCut->setInfo(this, n);
+                thisCut->increment(numberBranchesLeft_);
+                cuts_[n++] = thisCut;
+            }
+        }
+        numberCuts_ = n;
+    }
+    if (rhs.parentBranch_) {
+        parentBranch_ = rhs.parentBranch_->clone();
+    }
+}
+// Constructor given parent and owner
+CbcNodeInfo::CbcNodeInfo (CbcNodeInfo * parent, CbcNode * owner)
+        :
+        numberPointingToThis_(2),
+        parent_(parent),
+        parentBranch_(NULL),
+        owner_(owner),
+        numberCuts_(0),
+        nodeNumber_(0),
+        cuts_(NULL),
+        numberRows_(0),
+        numberBranchesLeft_(2),
+        active_(7)
+{
+#ifdef CHECK_NODE
+    printf("CbcNodeInfo %x Constructor from parent %x\n", this, parent_);
+#endif
+    //setParentBasedData();
+}
+
+/**
+   Take care to detach from the owning CbcNode and decrement the reference
+   count in the parent.  If this is the last nodeInfo object pointing to the
+   parent, make a recursive call to delete the parent.
+*/
+CbcNodeInfo::~CbcNodeInfo()
+{
+#ifdef CHECK_NODE
+    printf("CbcNodeInfo %x Destructor parent %x\n", this, parent_);
+#endif
+
+    assert(!numberPointingToThis_);
+    // But there may be some left (max nodes?)
+    for (int i = 0; i < numberCuts_; i++) {
+        if (cuts_[i]) {
+#ifndef GLOBAL_CUTS_JUST_POINTERS
+            delete cuts_[i];
+#else
+            if (cuts_[i]->globallyValidAsInteger() != 2)
+                delete cuts_[i];
+#endif
+        }
+    }
+    delete [] cuts_;
+    if (owner_)
+        owner_->nullNodeInfo();
+    if (parent_) {
+        int numberLinks = parent_->decrement();
+        if (!numberLinks) delete parent_;
+    }
+    delete parentBranch_;
+}
+
+
+//#define ALLCUTS
+void
+CbcNodeInfo::decrementCuts(int change)
+{
+    int i;
+    // get rid of all remaining if negative
+    int changeThis;
+    if (change < 0)
+        changeThis = numberBranchesLeft_;
+    else
+        changeThis = change;
+    // decrement cut counts
+    for (i = 0; i < numberCuts_; i++) {
+        if (cuts_[i]) {
+            int number = cuts_[i]->decrement(changeThis);
+            if (!number) {
+                //printf("info %x del cut %d %x\n",this,i,cuts_[i]);
+#ifndef GLOBAL_CUTS_JUST_POINTERS
+                delete cuts_[i];
+#else
+                if (cuts_[i]->globallyValidAsInteger() != 2)
+                    delete cuts_[i];
+#endif
+                cuts_[i] = NULL;
+            }
+        }
+    }
+}
+void
+CbcNodeInfo::incrementCuts(int change)
+{
+    int i;
+    assert (change > 0);
+    // increment cut counts
+    for (i = 0; i < numberCuts_; i++) {
+        if (cuts_[i])
+            cuts_[i]->increment(change);
+    }
+}
+void
+CbcNodeInfo::decrementParentCuts(CbcModel * model, int change)
+{
+    if (parent_) {
+        // get rid of all remaining if negative
+        int changeThis;
+        if (change < 0)
+            changeThis = numberBranchesLeft_;
+        else
+            changeThis = change;
+        int i;
+        // Get over-estimate of space needed for basis
+        CoinWarmStartBasis & dummy = model->workingBasis();
+        dummy.setSize(0, numberRows_ + numberCuts_);
+        buildRowBasis(dummy);
+        /* everything is zero (i.e. free) so we can use to see
+           if latest basis */
+        CbcNodeInfo * thisInfo = parent_;
+        while (thisInfo)
+            thisInfo = thisInfo->buildRowBasis(dummy);
+        // decrement cut counts
+        thisInfo = parent_;
+        int numberRows = numberRows_;
+        while (thisInfo) {
+            for (i = thisInfo->numberCuts_ - 1; i >= 0; i--) {
+                CoinWarmStartBasis::Status status = dummy.getArtifStatus(--numberRows);
+#ifdef ALLCUTS
+                status = CoinWarmStartBasis::isFree;
+#endif
+                if (thisInfo->cuts_[i]) {
+                    int number = 1;
+                    if (status != CoinWarmStartBasis::basic) {
+                        // tight - drop 1 or 2
+                        if (change < 0)
+                            number = thisInfo->cuts_[i]->decrement(changeThis);
+                        else
+                            number = thisInfo->cuts_[i]->decrement(change);
+                    }
+                    if (!number) {
+#ifndef GLOBAL_CUTS_JUST_POINTERS
+                        delete thisInfo->cuts_[i];
+#else
+                        if (thisInfo->cuts_[i]->globallyValidAsInteger() != 2)
+                            delete thisInfo->cuts_[i];
+#endif
+                        thisInfo->cuts_[i] = NULL;
+                    }
+                }
+            }
+            thisInfo = thisInfo->parent_;
+        }
+    }
+}
+#ifdef JJF_ZERO
+void
+CbcNodeInfo::incrementParentCuts(CbcModel * model, int change)
+{
+    if (parent_) {
+        int i;
+        // Get over-estimate of space needed for basis
+        CoinWarmStartBasis & dummy = model->workingBasis();
+        dummy.setSize(0, numberRows_ + numberCuts_);
+        /* everything is zero (i.e. free) so we can use to see
+           if latest basis */
+        buildRowBasis(dummy);
+        CbcNodeInfo * thisInfo = parent_;
+        while (thisInfo)
+            thisInfo = thisInfo->buildRowBasis(dummy);
+        // increment cut counts
+        thisInfo = parent_;
+        int numberRows = numberRows_;
+        while (thisInfo) {
+            for (i = thisInfo->numberCuts_ - 1; i >= 0; i--) {
+                CoinWarmStartBasis::Status status = dummy.getArtifStatus(--numberRows);
+#ifdef ALLCUTS
+                status = CoinWarmStartBasis::isFree;
+#endif
+                if (thisInfo->cuts_[i] && status != CoinWarmStartBasis::basic) {
+                    thisInfo->cuts_[i]->increment(change);
+                }
+            }
+            thisInfo = thisInfo->parent_;
+        }
+    }
+}
+#endif
+/*
+  Append cuts to the cuts_ array in a nodeInfo. The initial reference count
+  is set to numberToBranchOn, which will normally be the number of arms
+  defined for the CbcBranchingObject attached to the CbcNode that owns this
+  CbcNodeInfo.
+*/
+void
+CbcNodeInfo::addCuts (OsiCuts & cuts, int numberToBranchOn,
+                      /*int * whichGenerator,*/int numberPointingToThis)
+{
+    int numberCuts = cuts.sizeRowCuts();
+    if (numberCuts) {
+        int i;
+        if (!numberCuts_) {
+            cuts_ = new CbcCountRowCut * [numberCuts];
+        } else {
+            CbcCountRowCut ** temp = new CbcCountRowCut * [numberCuts+numberCuts_];
+            memcpy(temp, cuts_, numberCuts_*sizeof(CbcCountRowCut *));
+            delete [] cuts_;
+            cuts_ = temp;
+        }
+        for (i = 0; i < numberCuts; i++) {
+            CbcCountRowCut * thisCut = new CbcCountRowCut(*cuts.rowCutPtr(i),
+                    this, numberCuts_,
+                    -1, numberPointingToThis);
+            thisCut->increment(numberToBranchOn);
+            cuts_[numberCuts_++] = thisCut;
+#ifdef CBC_DEBUG
+#if CBC_DEBUG>1
+            int n = thisCut->row().getNumElements();
+            printf("Cut %d has %d entries, rhs %g %g =>", i, n, thisCut->lb(),
+                   thisCut->ub());
+            int j;
+            const int * index = thisCut->row().getIndices();
+            const double * element = thisCut->row().getElements();
+            for (j = 0; j < n; j++) {
+                printf(" (%d,%g)", index[j], element[j]);
+                assert(fabs(element[j]) > 1.00e-12);
+            }
+            printf("\n");
+#else
+            int n = thisCut->row().getNumElements();
+            int j;
+            const double * element = thisCut->row().getElements();
+            for (j = 0; j < n; j++) {
+                assert(fabs(element[j]) > 1.00e-12);
+            }
+#endif
+#endif
+        }
+    }
+}
+
+void
+CbcNodeInfo::addCuts(int numberCuts, CbcCountRowCut ** cut,
+                     int numberToBranchOn)
+{
+    if (numberCuts) {
+        int i;
+        if (!numberCuts_) {
+            cuts_ = new CbcCountRowCut * [numberCuts];
+        } else {
+            CbcCountRowCut ** temp = new CbcCountRowCut * [numberCuts+numberCuts_];
+            memcpy(temp, cuts_, numberCuts_*sizeof(CbcCountRowCut *));
+            delete [] cuts_;
+            cuts_ = temp;
+        }
+        for (i = 0; i < numberCuts; i++) {
+            CbcCountRowCut * thisCut = cut[i];
+            thisCut->setInfo(this, numberCuts_);
+            //printf("info %x cut %d %x\n",this,i,thisCut);
+            thisCut->increment(numberToBranchOn);
+            cuts_[numberCuts_++] = thisCut;
+#ifdef CBC_DEBUG
+            int n = thisCut->row().getNumElements();
+#if CBC_DEBUG>1
+            printf("Cut %d has %d entries, rhs %g %g =>", i, n, thisCut->lb(),
+                   thisCut->ub());
+#endif
+            int j;
+#if CBC_DEBUG>1
+            const int * index = thisCut->row().getIndices();
+#endif
+            const double * element = thisCut->row().getElements();
+            for (j = 0; j < n; j++) {
+#if CBC_DEBUG>1
+                printf(" (%d,%g)", index[j], element[j]);
+#endif
+                assert(fabs(element[j]) > 1.00e-12);
+            }
+            printf("\n");
+#endif
+        }
+    }
+}
+
+// delete cuts
+void
+CbcNodeInfo::deleteCuts(int numberToDelete, CbcCountRowCut ** cuts)
+{
+    int i;
+    int j;
+    int last = -1;
+    for (i = 0; i < numberToDelete; i++) {
+        CbcCountRowCut * next = cuts[i];
+        for (j = last + 1; j < numberCuts_; j++) {
+            if (next == cuts_[j])
+                break;
+        }
+        if (j == numberCuts_) {
+            // start from beginning
+            for (j = 0; j < last; j++) {
+                if (next == cuts_[j])
+                    break;
+            }
+            assert(j < last);
+        }
+        last = j;
+        int number = cuts_[j]->decrement();
+        if (!number) {
+#ifndef GLOBAL_CUTS_JUST_POINTERS
+            delete cuts_[j];
+#else
+            if (cuts_[j]->globallyValidAsInteger() != 2)
+                delete cuts_[j];
+#endif
+        }
+        cuts_[j] = NULL;
+    }
+    j = 0;
+    for (i = 0; i < numberCuts_; i++) {
+        if (cuts_[i])
+            cuts_[j++] = cuts_[i];
+    }
+    numberCuts_ = j;
+}
+
+// delete cuts
+void
+CbcNodeInfo::deleteCuts(int numberToDelete, int * which)
+{
+    int i;
+    for (i = 0; i < numberToDelete; i++) {
+        int iCut = which[i];
+        int number = cuts_[iCut]->decrement();
+        if (!number) {
+#ifndef GLOBAL_CUTS_JUST_POINTERS
+            delete cuts_[iCut];
+#else
+            if (cuts_[iCut]->globallyValidAsInteger() != 2)
+                delete cuts_[iCut];
+#endif
+        }
+        cuts_[iCut] = NULL;
+    }
+    int j = 0;
+    for (i = 0; i < numberCuts_; i++) {
+        if (cuts_[i])
+            cuts_[j++] = cuts_[i];
+    }
+    numberCuts_ = j;
+}
+
+// Really delete a cut
+void
+CbcNodeInfo::deleteCut(int whichOne)
+{
+    assert(whichOne < numberCuts_);
+    cuts_[whichOne] = NULL;
+}
+/* Deactivate node information.
+   1 - bounds
+   2 - cuts
+   4 - basis!
+*/
+void
+CbcNodeInfo::deactivate(int mode)
+{
+    active_ &= (~mode);
+}
+
diff --git a/cbits/coin/CbcNodeInfo.hpp b/cbits/coin/CbcNodeInfo.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcNodeInfo.hpp
@@ -0,0 +1,341 @@
+// $Id: CbcNodeInfo.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/24/09 carved from CbcNode
+
+#ifndef CbcNodeInfo_H
+#define CbcNodeInfo_H
+
+#include <string>
+#include <vector>
+
+#include "CoinWarmStartBasis.hpp"
+#include "CoinSearchTree.hpp"
+#include "CbcBranchBase.hpp"
+
+class OsiSolverInterface;
+class OsiSolverBranch;
+
+class OsiCuts;
+class OsiRowCut;
+class OsiRowCutDebugger;
+class CoinWarmStartBasis;
+class CbcCountRowCut;
+class CbcModel;
+class CbcNode;
+class CbcSubProblem;
+class CbcGeneralBranchingObject;
+
+//#############################################################################
+/** Information required to recreate the subproblem at this node
+
+  When a subproblem is initially created, it is represented by a CbcNode
+  object and an attached CbcNodeInfo object.
+
+  The CbcNode contains information needed while the subproblem remains live.
+  The CbcNode is deleted when the last branch arm has been evaluated.
+
+  The CbcNodeInfo contains information required to maintain the branch-and-cut
+  search tree structure (links and reference counts) and to recreate the
+  subproblem for this node (basis, variable bounds, cutting planes). A
+  CbcNodeInfo object remains in existence until all nodes have been pruned from
+  the subtree rooted at this node.
+
+  The principle used to maintain the reference count is that the reference
+  count is always the sum of all potential and actual children of the node.
+  Specifically,
+  <ul>
+    <li> Once it's determined how the node will branch, the reference count
+	 is set to the number of potential children (<i>i.e.</i>, the number
+	 of arms of the branch).
+    <li> As each child is created by CbcNode::branch() (converting a potential
+	 child to the active subproblem), the reference count is decremented.
+    <li> If the child survives and will become a node in the search tree
+	 (converting the active subproblem into an actual child), increment the
+	 reference count.
+  </ul>
+  Notice that the active subproblem lives in a sort of limbo, neither a
+  potential or an actual node in the branch-and-cut tree.
+
+  CbcNodeInfo objects come in two flavours. A CbcFullNodeInfo object contains
+  a full record of the information required to recreate a subproblem.
+  A CbcPartialNodeInfo object expresses this information in terms of
+  differences from the parent.
+*/
+
+class CbcNodeInfo {
+
+public:
+
+    /** \name Constructors & destructors */
+//@{
+    /** Default Constructor
+
+      Creates an empty NodeInfo object.
+    */
+    CbcNodeInfo ();
+
+    /// Copy constructor
+    CbcNodeInfo ( const CbcNodeInfo &);
+
+#ifdef JJF_ZERO
+    /** Construct with parent
+
+      Creates a NodeInfo object which knows its parent and assumes it will
+      in turn have two children.
+    */
+    CbcNodeInfo (CbcNodeInfo * parent);
+#endif
+
+    /** Construct with parent and owner
+
+      As for `construct with parent', and attached to \p owner.
+    */
+    CbcNodeInfo (CbcNodeInfo * parent, CbcNode * owner);
+
+    /** Destructor
+
+      Note that the destructor will recursively delete the parent if this
+      nodeInfo is the last child.
+    */
+    virtual ~CbcNodeInfo();
+//@}
+
+
+    /** \brief Modify model according to information at node
+
+        The routine modifies the model according to bound and basis
+        information at node and adds any cuts to the addCuts array.
+    */
+    virtual void applyToModel (CbcModel *model, CoinWarmStartBasis *&basis,
+                               CbcCountRowCut **addCuts,
+                               int &currentNumberCuts) const = 0 ;
+    /// Just apply bounds to one variable - force means overwrite by lower,upper (1=>infeasible)
+    virtual int applyBounds(int iColumn, double & lower, double & upper, int force) = 0;
+
+    /** Builds up row basis backwards (until original model).
+        Returns NULL or previous one to apply .
+        Depends on Free being 0 and impossible for cuts
+    */
+    virtual CbcNodeInfo * buildRowBasis(CoinWarmStartBasis & basis) const = 0;
+    /// Clone
+    virtual CbcNodeInfo * clone() const = 0;
+    /// Called when number branches left down to zero
+    virtual void allBranchesGone() {}
+#ifndef JJF_ONE
+    /// Increment number of references
+    inline void increment(int amount = 1) {
+        numberPointingToThis_ += amount;/*printf("CbcNodeInfo %x incremented by %d to %d\n",this,amount,numberPointingToThis_);*/
+    }
+
+    /// Decrement number of references and return number left
+    inline int decrement(int amount = 1) {
+        numberPointingToThis_ -= amount;/*printf("CbcNodeInfo %x decremented by %d to %d\n",this,amount,numberPointingToThis_);*/
+        return numberPointingToThis_;
+    }
+#else
+    /// Increment number of references
+    void increment(int amount = 1);
+    /// Decrement number of references and return number left
+    int decrement(int amount = 1);
+#endif
+    /** Initialize reference counts
+
+      Initialize the reference counts used for tree maintenance.
+    */
+
+    inline void initializeInfo(int number) {
+        numberPointingToThis_ = number;
+        numberBranchesLeft_ = number;
+    }
+
+    /// Return number of branches left in object
+    inline int numberBranchesLeft() const {
+        return numberBranchesLeft_;
+    }
+
+    /// Set number of branches left in object
+    inline void setNumberBranchesLeft(int value) {
+        numberBranchesLeft_ = value;
+    }
+
+    /// Return number of objects pointing to this
+    inline int numberPointingToThis() const {
+        return numberPointingToThis_;
+    }
+
+    /// Set number of objects pointing to this
+    inline void setNumberPointingToThis(int number) {
+        numberPointingToThis_ = number;
+    }
+
+    /// Increment number of objects pointing to this
+    inline void incrementNumberPointingToThis() {
+        numberPointingToThis_ ++;
+    }
+
+    /// Say one branch taken
+    inline int branchedOn() {
+        numberPointingToThis_--;
+        numberBranchesLeft_--;
+        return numberBranchesLeft_;
+    }
+
+    /// Say thrown away
+    inline void throwAway() {
+        numberPointingToThis_ -= numberBranchesLeft_;
+        numberBranchesLeft_ = 0;
+    }
+
+    /// Parent of this
+    CbcNodeInfo * parent() const {
+        return parent_;
+    }
+    /// Set parent null
+    inline void nullParent() {
+        parent_ = NULL;
+    }
+
+    void addCuts(OsiCuts & cuts, int numberToBranch, //int * whichGenerator,
+                 int numberPointingToThis);
+    void addCuts(int numberCuts, CbcCountRowCut ** cuts, int numberToBranch);
+    /** Delete cuts (decrements counts)
+        Slow unless cuts in same order as saved
+    */
+    void deleteCuts(int numberToDelete, CbcCountRowCut ** cuts);
+    void deleteCuts(int numberToDelete, int * which);
+
+    /// Really delete a cut
+    void deleteCut(int whichOne);
+
+    /// Decrement active cut counts
+    void decrementCuts(int change = 1);
+
+    /// Increment active cut counts
+    void incrementCuts(int change = 1);
+
+    /// Decrement all active cut counts in chain starting at parent
+    void decrementParentCuts(CbcModel * model, int change = 1);
+
+    /// Increment all active cut counts in parent chain
+    void incrementParentCuts(CbcModel * model, int change = 1);
+
+    /// Array of pointers to cuts
+    inline CbcCountRowCut ** cuts() const {
+        return cuts_;
+    }
+
+    /// Number of row cuts (this node)
+    inline int numberCuts() const {
+        return numberCuts_;
+    }
+    inline void setNumberCuts(int value) {
+        numberCuts_ = value;
+    }
+
+    /// Set owner null
+    inline void nullOwner() {
+        owner_ = NULL;
+    }
+    const inline CbcNode * owner() const {
+        return owner_;
+    }
+    inline CbcNode * mutableOwner() const {
+        return owner_;
+    }
+    /// The node number
+    inline int nodeNumber() const {
+        return nodeNumber_;
+    }
+    inline void setNodeNumber(int node) {
+        nodeNumber_ = node;
+    }
+    /** Deactivate node information.
+        1 - bounds
+        2 - cuts
+        4 - basis!
+    */
+    void deactivate(int mode = 3);
+    /// Say if normal
+    inline bool allActivated() const {
+        return (active_ == 7);
+    }
+    /// Say if marked
+    inline bool marked() const {
+        return ((active_&8) != 0);
+    }
+    /// Mark
+    inline void mark() {
+        active_ |= 8;
+    }
+    /// Unmark
+    inline void unmark() {
+        active_ &= ~8;
+    }
+
+    /// Branching object for the parent
+    inline const OsiBranchingObject * parentBranch() const {
+        return parentBranch_;
+    }
+    /// If we need to take off parent based data
+    void unsetParentBasedData();
+protected:
+
+    /** Number of other nodes pointing to this node.
+
+      Number of existing and potential search tree nodes pointing to this node.
+      `Existing' means referenced by #parent_ of some other CbcNodeInfo.
+      `Potential' means children still to be created (#numberBranchesLeft_ of
+      this CbcNodeInfo).
+    */
+    int numberPointingToThis_;
+
+    /// parent
+    CbcNodeInfo * parent_;
+
+    /// Copy of the branching object of the parent when the node is created
+    OsiBranchingObject * parentBranch_;
+
+    /// Owner
+    CbcNode * owner_;
+
+    /// Number of row cuts (this node)
+    int numberCuts_;
+
+    /// The node number
+    int nodeNumber_;
+
+    /// Array of pointers to cuts
+    CbcCountRowCut ** cuts_;
+
+    /** Number of rows in problem (before these cuts).  This
+        means that for top of chain it must be rows at continuous */
+    int numberRows_;
+
+    /** Number of branch arms left to explore at this node
+
+      \todo There seems to be redundancy between this field and
+        CbcBranchingObject::numberBranchesLeft_. It'd be good to sort out if
+        both are necessary.
+    */
+    int numberBranchesLeft_;
+    /** Active node information.
+        1 - bounds
+        2 - cuts
+        4 - basis!
+    */
+    int active_;
+
+private:
+
+    /// Illegal Assignment operator
+    CbcNodeInfo & operator=(const CbcNodeInfo& rhs);
+
+    /// routine common to constructors
+    void setParentBasedData();
+};
+
+#endif // CbcNodeInfo_H
+
diff --git a/cbits/coin/CbcObject.cpp b/cbits/coin/CbcObject.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcObject.cpp
@@ -0,0 +1,147 @@
+// $Id: CbcObject.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "OsiChooseVariable.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchBase.hpp"
+
+
+// Default Constructor
+CbcObject::CbcObject()
+        : OsiObject(),
+        model_(NULL),
+        id_(-1),
+        position_(-1),
+        preferredWay_(0)
+{
+}
+
+// Constructor from model
+CbcObject::CbcObject(CbcModel * model)
+        : OsiObject(),
+        model_(model),
+        id_(-1),
+        position_(-1),
+        preferredWay_(0)
+{
+}
+
+
+// Destructor
+CbcObject::~CbcObject ()
+{
+}
+
+// Copy constructor
+CbcObject::CbcObject ( const CbcObject & rhs)
+        : OsiObject(rhs)
+{
+    model_ = rhs.model_;
+    id_ = rhs.id_;
+    position_ = rhs.position_;
+    preferredWay_ = rhs.preferredWay_;
+}
+
+// Assignment operator
+CbcObject &
+CbcObject::operator=( const CbcObject & rhs)
+{
+    if (this != &rhs) {
+        OsiObject::operator=(rhs);
+        model_ = rhs.model_;
+        id_ = rhs.id_;
+        position_ = rhs.position_;
+        preferredWay_ = rhs.preferredWay_;
+    }
+    return *this;
+}
+
+/* Returns floor and ceiling i.e. closest valid points
+ */
+void
+CbcObject::floorCeiling(double & floorValue, double & ceilingValue, double value,
+                        double tolerance) const
+{
+    if (fabs(floor(value + 0.5) - value) > tolerance) {
+        floorValue = floor(value);
+    } else {
+        floorValue = floor(value + 0.5);
+    }
+    ceilingValue = floorValue + 1.0;
+}
+/* For the variable(s) referenced by the object,
+      look at the current solution and set bounds to match the solution.
+      Returns measure of how much it had to move solution to make feasible
+*/
+double
+CbcObject::feasibleRegion(OsiSolverInterface * /*solver*/) const
+{
+    //assert (solver==model_->solver());
+    CbcObject * fudge = const_cast<CbcObject *>(this);
+    fudge->feasibleRegion();
+    return 0.0;
+}
+
+/* For the variable(s) referenced by the object,
+      look at the current solution and set bounds to match the solution.
+      Returns measure of how much it had to move solution to make feasible
+*/
+double
+CbcObject::feasibleRegion(OsiSolverInterface * /*solver*/,
+                          const OsiBranchingInformation * /*info*/) const
+{
+    //assert (solver==model_->solver());
+    CbcObject * fudge = const_cast<CbcObject *>(this);
+    fudge->feasibleRegion();
+    return 0.0;
+}
+/* Create a branching object and indicate which way to branch first.
+
+      The branching object has to know how to create branches (fix
+      variables, etc.)
+*/
+OsiBranchingObject *
+CbcObject::createOsiBranch(OsiSolverInterface * solver,
+                           const OsiBranchingInformation * info,
+                           int way) const
+{
+    //assert (solver==model_->solver());
+    CbcObject * fudge = const_cast<CbcObject *>(this);
+    return fudge->createBranch(solver, info, way);
+}
+/* Create an OsiSolverBranch object
+
+This returns NULL if branch not represented by bound changes
+*/
+OsiSolverBranch *
+CbcObject::solverBranch() const
+{
+    return NULL;
+}
+/* Pass in information on branch just done and create CbcObjectUpdateData instance.
+   If object does not need data then backward pointer will be NULL.
+   Assumes can get information from solver */
+CbcObjectUpdateData
+CbcObject::createUpdateInformation(const OsiSolverInterface * /*solver*/,
+                                   const CbcNode * /*node*/,
+                                   const CbcBranchingObject * /*branchingObject*/)
+{
+    return CbcObjectUpdateData();
+}
+
diff --git a/cbits/coin/CbcObject.hpp b/cbits/coin/CbcObject.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcObject.hpp
@@ -0,0 +1,272 @@
+// $Id: CbcObject.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#ifndef CbcObject_H
+#define CbcObject_H
+
+#include <string>
+#include <vector>
+#include "OsiBranchingObject.hpp"
+class OsiSolverInterface;
+class OsiSolverBranch;
+
+class CbcModel;
+class CbcNode;
+class CbcNodeInfo;
+class CbcBranchingObject;
+class OsiChooseVariable;
+class CbcObjectUpdateData;
+//#############################################################################
+
+/** Abstract base class for `objects'.
+    It now just has stuff that OsiObject does not have
+
+  The branching model used in Cbc is based on the idea of an <i>object</i>.
+  In the abstract, an object is something that has a feasible region, can be
+  evaluated for infeasibility, can be branched on (<i>i.e.</i>, there's some
+  constructive action to be taken to move toward feasibility), and allows
+  comparison of the effect of branching.
+
+  This class (CbcObject) is the base class for an object. To round out the
+  branching model, the class CbcBranchingObject describes how to perform a
+  branch, and the class CbcBranchDecision describes how to compare two
+  CbcBranchingObjects.
+
+  To create a new type of object you need to provide three methods:
+  #infeasibility(), #feasibleRegion(), and #createCbcBranch(), described below.
+
+  This base class is primarily virtual to allow for any form of structure.
+  Any form of discontinuity is allowed.
+
+  \todo The notion that all branches are binary (two arms) is wired into the
+	implementation of CbcObject, CbcBranchingObject, and
+	CbcBranchDecision. Changing this will require a moderate amount of
+	recoding.
+ */
+// This can be used if object wants to skip strong branching
+typedef struct {
+    CbcBranchingObject * possibleBranch; // what a branch would do
+    double upMovement; // cost going up (and initial away from feasible)
+    double downMovement; // cost going down
+    int numIntInfeasUp ; // without odd ones
+    int numObjInfeasUp ; // just odd ones
+    bool finishedUp; // true if solver finished
+    int numItersUp ; // number of iterations in solver
+    int numIntInfeasDown ; // without odd ones
+    int numObjInfeasDown ; // just odd ones
+    bool finishedDown; // true if solver finished
+    int numItersDown; // number of iterations in solver
+    int objectNumber; // Which object it is
+    int fix; // 0 if no fix, 1 if we can fix up, -1 if we can fix down
+} CbcStrongInfo;
+
+class CbcObject : public OsiObject {
+
+public:
+
+    // Default Constructor
+    CbcObject ();
+
+    // Useful constructor
+    CbcObject (CbcModel * model);
+
+    // Copy constructor
+    CbcObject ( const CbcObject &);
+
+    // Assignment operator
+    CbcObject & operator=( const CbcObject& rhs);
+
+    /// Clone
+    virtual CbcObject * clone() const = 0;
+
+    /// Destructor
+    virtual ~CbcObject ();
+
+    /** Infeasibility of the object
+
+        This is some measure of the infeasibility of the object. It should be
+        scaled to be in the range [0.0, 0.5], with 0.0 indicating the object
+        is satisfied.
+
+        The preferred branching direction is returned in preferredWay,
+
+        This is used to prepare for strong branching but should also think of
+        case when no strong branching
+
+        The object may also compute an estimate of cost of going "up" or "down".
+        This will probably be based on pseudo-cost ideas
+    */
+#ifdef CBC_NEW_STYLE_BRANCH
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const = 0;
+#else
+    virtual double infeasibility(const OsiBranchingInformation * /*info*/,
+                                 int &preferredWay) const {
+        return infeasibility(preferredWay);
+    }
+    virtual double infeasibility(int &/*preferredWay*/) const {
+        throw CoinError("Need code", "infeasibility", "CbcBranchBase");
+    }
+#endif
+
+    /** For the variable(s) referenced by the object,
+        look at the current solution and set bounds to match the solution.
+    */
+    virtual void feasibleRegion() = 0;
+    /// Dummy one for compatibility
+    virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+    /** For the variable(s) referenced by the object,
+        look at the current solution and set bounds to match the solution.
+        Returns measure of how much it had to move solution to make feasible
+    */
+    virtual double feasibleRegion(OsiSolverInterface * solver) const ;
+
+    /** Create a branching object and indicate which way to branch first.
+
+        The branching object has to know how to create branches (fix
+        variables, etc.)
+    */
+#ifdef CBC_NEW_STYLE_BRANCH
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) = 0;
+#else
+  virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface *
+                                               /* solver */,
+                                               const OsiBranchingInformation *
+                                               /* info */, int /* way */) {
+        // return createBranch(solver, info, way);
+      return NULL;
+    }
+    virtual OsiBranchingObject * createBranch(OsiSolverInterface * /*solver*/,
+            const OsiBranchingInformation * /*info*/, int /*way*/) const {
+        throw CoinError("Need code", "createBranch", "CbcBranchBase");
+    }
+#endif
+    /** Create an Osibranching object and indicate which way to branch first.
+
+        The branching object has to know how to create branches (fix
+        variables, etc.)
+    */
+    virtual OsiBranchingObject * createOsiBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+    /** Create an OsiSolverBranch object
+
+        This returns NULL if branch not represented by bound changes
+    */
+    virtual OsiSolverBranch * solverBranch() const;
+
+    /** \brief Given a valid solution (with reduced costs, etc.),
+        return a branching object which would give a new feasible
+        point in a good direction.
+
+        If the method cannot generate a feasible point (because there aren't
+        any, or because it isn't bright enough to find one), it should
+        return null.
+    */
+    virtual CbcBranchingObject * preferredNewFeasible() const {
+        return NULL;
+    }
+
+    /** \brief Given a valid solution (with reduced costs, etc.),
+        return a branching object which would give a new feasible
+        point in a bad direction.
+
+        If the method cannot generate a feasible point (because there aren't
+        any, or because it isn't bright enough to find one), it should
+        return null.
+    */
+    virtual CbcBranchingObject * notPreferredNewFeasible() const {
+        return NULL;
+    }
+
+    /** Reset variable bounds to their original values.
+
+      Bounds may be tightened, so it may be good to be able to set this info in object.
+     */
+    virtual void resetBounds(const OsiSolverInterface * ) {}
+
+    /** Returns floor and ceiling i.e. closest valid points
+    */
+    virtual void floorCeiling(double & floorValue, double & ceilingValue, double value,
+                              double tolerance) const;
+
+    /** Pass in information on branch just done and create CbcObjectUpdateData instance.
+        If object does not need data then backward pointer will be NULL.
+        Assumes can get information from solver */
+    virtual CbcObjectUpdateData createUpdateInformation(const OsiSolverInterface * solver,
+            const CbcNode * node,
+            const CbcBranchingObject * branchingObject);
+
+    /// Update object by CbcObjectUpdateData
+    virtual void updateInformation(const CbcObjectUpdateData & ) {}
+
+    /// Identifier (normally column number in matrix)
+    inline int id() const {
+        return id_;
+    }
+
+    /** Set identifier (normally column number in matrix)
+        but 1000000000 to 1100000000 means optional branching object
+        i.e. code would work without it */
+    inline void setId(int value) {
+        id_ = value;
+    }
+
+    /** Return true if optional branching object
+        i.e. code would work without it */
+    inline bool optionalObject() const {
+        return (id_ >= 1000000000 && id_ < 1100000000);
+    }
+
+    /// Get position in object_ list
+    inline int position() const {
+        return position_;
+    }
+
+    /// Set position in object_ list
+    inline void setPosition(int position) {
+        position_ = position;
+    }
+
+    /// update model
+    inline void setModel(CbcModel * model) {
+        model_ = model;
+    }
+
+    /// Return model
+    inline CbcModel * model() const {
+        return  model_;
+    }
+
+    /// If -1 down always chosen first, +1 up always, 0 normal
+    inline int preferredWay() const {
+        return preferredWay_;
+    }
+    /// Set -1 down always chosen first, +1 up always, 0 normal
+    inline void setPreferredWay(int value) {
+        preferredWay_ = value;
+    }
+    /// Redoes data when sequence numbers change
+    virtual void redoSequenceEtc(CbcModel * , int , const int * ) {}
+    /// Initialize for branching
+    virtual void initializeForBranching(CbcModel * ) {}
+
+protected:
+    /// data
+
+    /// Model
+    CbcModel * model_;
+    /// Identifier (normally column number in matrix)
+    int id_;
+    /// Position in object list
+    int position_;
+    /// If -1 down always chosen first, +1 up always, 0 normal
+    int preferredWay_;
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcObjectUpdateData.cpp b/cbits/coin/CbcObjectUpdateData.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcObjectUpdateData.cpp
@@ -0,0 +1,94 @@
+// $Id: CbcObjectUpdateData.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "OsiChooseVariable.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchBase.hpp"
+#include "CbcObjectUpdateData.hpp"
+
+// Default constructor
+CbcObjectUpdateData::CbcObjectUpdateData()
+        : object_(NULL),
+        way_(0),
+        objectNumber_(-1),
+        change_(0.0),
+        status_(0),
+        intDecrease_(0),
+        branchingValue_(0.0),
+        originalObjective_(COIN_DBL_MAX),
+        cutoff_(COIN_DBL_MAX)
+{
+}
+
+// Useful constructor
+CbcObjectUpdateData::CbcObjectUpdateData (CbcObject * object,
+        int way,
+        double change,
+        int status,
+        int intDecrease,
+        double branchingValue)
+        : object_(object),
+        way_(way),
+        objectNumber_(-1),
+        change_(change),
+        status_(status),
+        intDecrease_(intDecrease),
+        branchingValue_(branchingValue),
+        originalObjective_(COIN_DBL_MAX),
+        cutoff_(COIN_DBL_MAX)
+{
+}
+
+// Destructor
+CbcObjectUpdateData::~CbcObjectUpdateData ()
+{
+}
+
+// Copy constructor
+CbcObjectUpdateData::CbcObjectUpdateData ( const CbcObjectUpdateData & rhs)
+        : object_(rhs.object_),
+        way_(rhs.way_),
+        objectNumber_(rhs.objectNumber_),
+        change_(rhs.change_),
+        status_(rhs.status_),
+        intDecrease_(rhs.intDecrease_),
+        branchingValue_(rhs.branchingValue_),
+        originalObjective_(rhs.originalObjective_),
+        cutoff_(rhs.cutoff_)
+{
+}
+
+// Assignment operator
+CbcObjectUpdateData &
+CbcObjectUpdateData::operator=( const CbcObjectUpdateData & rhs)
+{
+    if (this != &rhs) {
+        object_ = rhs.object_;
+        way_ = rhs.way_;
+        objectNumber_ = rhs.objectNumber_;
+        change_ = rhs.change_;
+        status_ = rhs.status_;
+        intDecrease_ = rhs.intDecrease_;
+        branchingValue_ = rhs.branchingValue_;
+        originalObjective_ = rhs.originalObjective_;
+        cutoff_ = rhs.cutoff_;
+    }
+    return *this;
+}
+
diff --git a/cbits/coin/CbcObjectUpdateData.hpp b/cbits/coin/CbcObjectUpdateData.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcObjectUpdateData.hpp
@@ -0,0 +1,64 @@
+// $Id: CbcObjectUpdateData.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/12/2009 carved from CbcBranchBase
+
+#ifndef CbcObjectUpdateData_H
+#define CbcObjectUpdateData_H
+
+#include "CbcObject.hpp"
+/*  This stores data so an object can be updated
+ */
+class CbcObjectUpdateData {
+
+public:
+
+    /// Default Constructor
+    CbcObjectUpdateData ();
+
+    /// Useful constructor
+    CbcObjectUpdateData (CbcObject * object,
+                         int way,
+                         double change,
+                         int status,
+                         int intDecrease_,
+                         double branchingValue);
+
+    /// Copy constructor
+    CbcObjectUpdateData ( const CbcObjectUpdateData &);
+
+    /// Assignment operator
+    CbcObjectUpdateData & operator=( const CbcObjectUpdateData& rhs);
+
+    /// Destructor
+    virtual ~CbcObjectUpdateData ();
+
+
+public:
+    /// data
+
+    /// Object
+    CbcObject * object_;
+    /// Branch as defined by instance of CbcObject
+    int way_;
+    /// Object number
+    int objectNumber_;
+    /// Change in objective
+    double change_;
+    /// Status 0 Optimal, 1 infeasible, 2 unknown
+    int status_;
+    /// Decrease in number unsatisfied
+    int intDecrease_;
+    /// Branching value
+    double branchingValue_;
+    /// Objective value before branching
+    double originalObjective_;
+    /// Current cutoff
+    double cutoff_;
+
+};
+
+#endif
+
diff --git a/cbits/coin/CbcOrClpParam.cpp b/cbits/coin/CbcOrClpParam.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcOrClpParam.cpp
@@ -0,0 +1,3879 @@
+/* $Id: CbcOrClpParam.cpp 1989 2013-11-11 17:27:32Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "CoinTime.hpp"
+#include "CbcOrClpParam.hpp"
+
+#include <string>
+#include <iostream>
+#include <cassert>
+
+#ifdef COIN_HAS_CBC
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#include "ClpSimplex.hpp"
+#endif
+#include "CbcModel.hpp"
+#endif
+#include "CoinHelperFunctions.hpp"
+#ifdef COIN_HAS_CLP
+#include "ClpSimplex.hpp"
+#include "ClpFactorization.hpp"
+#endif
+#ifdef COIN_HAS_READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+#ifdef COIN_HAS_CBC
+// from CoinSolve
+static char coin_prompt[] = "Coin:";
+#else
+static char coin_prompt[] = "Clp:";
+#endif
+#ifdef CLP_CILK
+#ifndef CBC_THREAD
+#define CBC_THREAD
+#endif
+#endif
+#if defined(COIN_HAS_WSMP) && ! defined(USE_EKKWSSMP)
+#ifndef CBC_THREAD
+#define CBC_THREAD
+#endif
+#endif
+#include "ClpConfig.h"
+#ifdef CLP_HAS_ABC
+#include "AbcCommon.hpp"
+#endif
+static bool doPrinting = true;
+std::string afterEquals = "";
+static char printArray[200];
+void setCbcOrClpPrinting(bool yesNo)
+{
+     doPrinting = yesNo;
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+CbcOrClpParam::CbcOrClpParam ()
+     : type_(CBC_PARAM_NOTUSED_INVALID),
+       lowerDoubleValue_(0.0),
+       upperDoubleValue_(0.0),
+       lowerIntValue_(0),
+       upperIntValue_(0),
+       lengthName_(0),
+       lengthMatch_(0),
+       definedKeyWords_(),
+       name_(),
+       shortHelp_(),
+       longHelp_(),
+       action_(CBC_PARAM_NOTUSED_INVALID),
+       currentKeyWord_(-1),
+       display_(0),
+       intValue_(-1),
+       doubleValue_(-1.0),
+       stringValue_(""),
+       whereUsed_(7)
+{
+}
+// Other constructors
+CbcOrClpParam::CbcOrClpParam (std::string name, std::string help,
+                              double lower, double upper, CbcOrClpParameterType type,
+                              int display)
+     : type_(type),
+       lowerIntValue_(0),
+       upperIntValue_(0),
+       definedKeyWords_(),
+       name_(name),
+       shortHelp_(help),
+       longHelp_(),
+       action_(type),
+       currentKeyWord_(-1),
+       display_(display),
+       intValue_(-1),
+       doubleValue_(-1.0),
+       stringValue_(""),
+       whereUsed_(7)
+{
+     lowerDoubleValue_ = lower;
+     upperDoubleValue_ = upper;
+     gutsOfConstructor();
+}
+CbcOrClpParam::CbcOrClpParam (std::string name, std::string help,
+                              int lower, int upper, CbcOrClpParameterType type,
+                              int display)
+     : type_(type),
+       lowerDoubleValue_(0.0),
+       upperDoubleValue_(0.0),
+       definedKeyWords_(),
+       name_(name),
+       shortHelp_(help),
+       longHelp_(),
+       action_(type),
+       currentKeyWord_(-1),
+       display_(display),
+       intValue_(-1),
+       doubleValue_(-1.0),
+       stringValue_(""),
+       whereUsed_(7)
+{
+     gutsOfConstructor();
+     lowerIntValue_ = lower;
+     upperIntValue_ = upper;
+}
+// Other strings will be added by append
+CbcOrClpParam::CbcOrClpParam (std::string name, std::string help,
+                              std::string firstValue,
+                              CbcOrClpParameterType type, int whereUsed,
+                              int display)
+     : type_(type),
+       lowerDoubleValue_(0.0),
+       upperDoubleValue_(0.0),
+       lowerIntValue_(0),
+       upperIntValue_(0),
+       definedKeyWords_(),
+       name_(name),
+       shortHelp_(help),
+       longHelp_(),
+       action_(type),
+       currentKeyWord_(0),
+       display_(display),
+       intValue_(-1),
+       doubleValue_(-1.0),
+       stringValue_(""),
+       whereUsed_(whereUsed)
+{
+     gutsOfConstructor();
+     definedKeyWords_.push_back(firstValue);
+}
+// Action
+CbcOrClpParam::CbcOrClpParam (std::string name, std::string help,
+                              CbcOrClpParameterType type, int whereUsed,
+                              int display)
+     : type_(type),
+       lowerDoubleValue_(0.0),
+       upperDoubleValue_(0.0),
+       lowerIntValue_(0),
+       upperIntValue_(0),
+       definedKeyWords_(),
+       name_(name),
+       shortHelp_(help),
+       longHelp_(),
+       action_(type),
+       currentKeyWord_(-1),
+       display_(display),
+       intValue_(-1),
+       doubleValue_(-1.0),
+       stringValue_("")
+{
+     whereUsed_ = whereUsed;
+     gutsOfConstructor();
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+CbcOrClpParam::CbcOrClpParam (const CbcOrClpParam & rhs)
+{
+     type_ = rhs.type_;
+     lowerDoubleValue_ = rhs.lowerDoubleValue_;
+     upperDoubleValue_ = rhs.upperDoubleValue_;
+     lowerIntValue_ = rhs.lowerIntValue_;
+     upperIntValue_ = rhs.upperIntValue_;
+     lengthName_ = rhs.lengthName_;
+     lengthMatch_ = rhs.lengthMatch_;
+     definedKeyWords_ = rhs.definedKeyWords_;
+     name_ = rhs.name_;
+     shortHelp_ = rhs.shortHelp_;
+     longHelp_ = rhs.longHelp_;
+     action_ = rhs.action_;
+     currentKeyWord_ = rhs.currentKeyWord_;
+     display_ = rhs.display_;
+     intValue_ = rhs.intValue_;
+     doubleValue_ = rhs.doubleValue_;
+     stringValue_ = rhs.stringValue_;
+     whereUsed_ = rhs.whereUsed_;
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+CbcOrClpParam::~CbcOrClpParam ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+CbcOrClpParam &
+CbcOrClpParam::operator=(const CbcOrClpParam & rhs)
+{
+     if (this != &rhs) {
+          type_ = rhs.type_;
+          lowerDoubleValue_ = rhs.lowerDoubleValue_;
+          upperDoubleValue_ = rhs.upperDoubleValue_;
+          lowerIntValue_ = rhs.lowerIntValue_;
+          upperIntValue_ = rhs.upperIntValue_;
+          lengthName_ = rhs.lengthName_;
+          lengthMatch_ = rhs.lengthMatch_;
+          definedKeyWords_ = rhs.definedKeyWords_;
+          name_ = rhs.name_;
+          shortHelp_ = rhs.shortHelp_;
+          longHelp_ = rhs.longHelp_;
+          action_ = rhs.action_;
+          currentKeyWord_ = rhs.currentKeyWord_;
+          display_ = rhs.display_;
+          intValue_ = rhs.intValue_;
+          doubleValue_ = rhs.doubleValue_;
+          stringValue_ = rhs.stringValue_;
+          whereUsed_ = rhs.whereUsed_;
+     }
+     return *this;
+}
+void
+CbcOrClpParam::gutsOfConstructor()
+{
+     std::string::size_type  shriekPos = name_.find('!');
+     lengthName_ = static_cast<unsigned int>(name_.length());
+     if ( shriekPos == std::string::npos ) {
+          //does not contain '!'
+          lengthMatch_ = lengthName_;
+     } else {
+          lengthMatch_ = static_cast<unsigned int>(shriekPos);
+          name_ = name_.substr(0, shriekPos) + name_.substr(shriekPos + 1);
+          lengthName_--;
+     }
+}
+// Returns length of name for printing
+int
+CbcOrClpParam::lengthMatchName (  ) const
+{
+     if (lengthName_ == lengthMatch_)
+          return lengthName_;
+     else
+          return lengthName_ + 2;
+}
+// Insert string (only valid for keywords)
+void
+CbcOrClpParam::append(std::string keyWord)
+{
+     definedKeyWords_.push_back(keyWord);
+}
+
+int
+CbcOrClpParam::matches (std::string input) const
+{
+     // look up strings to do more elegantly
+     if (input.length() > lengthName_) {
+          return 0;
+     } else {
+          unsigned int i;
+          for (i = 0; i < input.length(); i++) {
+               if (tolower(name_[i]) != tolower(input[i]))
+                    break;
+          }
+          if (i < input.length()) {
+               return 0;
+          } else if (i >= lengthMatch_) {
+               return 1;
+          } else {
+               // matched but too short
+               return 2;
+          }
+     }
+}
+// Returns name which could match
+std::string
+CbcOrClpParam::matchName (  ) const
+{
+     if (lengthMatch_ == lengthName_)
+          return name_;
+     else
+          return name_.substr(0, lengthMatch_) + "(" + name_.substr(lengthMatch_) + ")";
+}
+
+// Returns parameter option which matches (-1 if none)
+int
+CbcOrClpParam::parameterOption ( std::string check ) const
+{
+     int numberItems = static_cast<int>(definedKeyWords_.size());
+     if (!numberItems) {
+          return -1;
+     } else {
+          int whichItem = 0;
+          unsigned int it;
+          for (it = 0; it < definedKeyWords_.size(); it++) {
+               std::string thisOne = definedKeyWords_[it];
+               std::string::size_type  shriekPos = thisOne.find('!');
+               size_t length1 = thisOne.length();
+               size_t length2 = length1;
+               if ( shriekPos != std::string::npos ) {
+                    //contains '!'
+                    length2 = shriekPos;
+                    thisOne = thisOne.substr(0, shriekPos) +
+                              thisOne.substr(shriekPos + 1);
+                    length1 = thisOne.length();
+               }
+               if (check.length() <= length1 && length2 <= check.length()) {
+                    unsigned int i;
+                    for (i = 0; i < check.length(); i++) {
+                         if (tolower(thisOne[i]) != tolower(check[i]))
+                              break;
+                    }
+                    if (i < check.length()) {
+                         whichItem++;
+                    } else if (i >= length2) {
+                         break;
+                    }
+               } else {
+                    whichItem++;
+               }
+          }
+          if (whichItem < numberItems)
+               return whichItem;
+          else
+               return -1;
+     }
+}
+// Prints parameter options
+void
+CbcOrClpParam::printOptions (  ) const
+{
+     std::cout << "<Possible options for " << name_ << " are:";
+     unsigned int it;
+     for (it = 0; it < definedKeyWords_.size(); it++) {
+          std::string thisOne = definedKeyWords_[it];
+          std::string::size_type  shriekPos = thisOne.find('!');
+          if ( shriekPos != std::string::npos ) {
+               //contains '!'
+               thisOne = thisOne.substr(0, shriekPos) +
+                         "(" + thisOne.substr(shriekPos + 1) + ")";
+          }
+          std::cout << " " << thisOne;
+     }
+     assert (currentKeyWord_ >= 0 && currentKeyWord_ < static_cast<int>(definedKeyWords_.size()));
+     std::string current = definedKeyWords_[currentKeyWord_];
+     std::string::size_type  shriekPos = current.find('!');
+     if ( shriekPos != std::string::npos ) {
+          //contains '!'
+          current = current.substr(0, shriekPos) +
+                    "(" + current.substr(shriekPos + 1) + ")";
+     }
+     std::cout << ";\n\tcurrent  " << current << ">" << std::endl;
+}
+// Print action and string
+void
+CbcOrClpParam::printString() const
+{
+     if (name_ == "directory")
+          std::cout << "Current working directory is " << stringValue_ << std::endl;
+     else if (name_.substr(0, 6) == "printM")
+          std::cout << "Current value of printMask is " << stringValue_ << std::endl;
+     else
+          std::cout << "Current default (if $ as parameter) for " << name_
+                    << " is " << stringValue_ << std::endl;
+}
+void CoinReadPrintit(const char * input)
+{
+     int length = static_cast<int>(strlen(input));
+     char temp[101];
+     int i;
+     int n = 0;
+     for (i = 0; i < length; i++) {
+          if (input[i] == '\n') {
+               temp[n] = '\0';
+               std::cout << temp << std::endl;
+               n = 0;
+          } else if (n >= 65 && input[i] == ' ') {
+               temp[n] = '\0';
+               std::cout << temp << std::endl;
+               n = 0;
+          } else if (n || input[i] != ' ') {
+               temp[n++] = input[i];
+          }
+     }
+     if (n) {
+          temp[n] = '\0';
+          std::cout << temp << std::endl;
+     }
+}
+// Print Long help
+void
+CbcOrClpParam::printLongHelp() const
+{
+     if (type_ >= 1 && type_ < 400) {
+          CoinReadPrintit(longHelp_.c_str());
+          if (type_ < CLP_PARAM_INT_SOLVERLOGLEVEL) {
+               printf("<Range of values is %g to %g;\n\tcurrent %g>\n", lowerDoubleValue_, upperDoubleValue_, doubleValue_);
+               assert (upperDoubleValue_ > lowerDoubleValue_);
+          } else if (type_ < CLP_PARAM_STR_DIRECTION) {
+               printf("<Range of values is %d to %d;\n\tcurrent %d>\n", lowerIntValue_, upperIntValue_, intValue_);
+               assert (upperIntValue_ > lowerIntValue_);
+          } else if (type_ < CLP_PARAM_ACTION_DIRECTORY) {
+               printOptions();
+          }
+     }
+}
+#ifdef COIN_HAS_CBC
+int
+CbcOrClpParam::setDoubleParameter (OsiSolverInterface * model, double value)
+{
+     int returnCode;
+     setDoubleParameterWithMessage(model, value, returnCode);
+     if (doPrinting && strlen(printArray))
+          std::cout << printArray << std::endl;
+     return returnCode;
+}
+// Sets double parameter and returns printable string and error code
+const char *
+CbcOrClpParam::setDoubleParameterWithMessage ( OsiSolverInterface * model, double  value , int & returnCode)
+{
+     if (value < lowerDoubleValue_ || value > upperDoubleValue_) {
+          sprintf(printArray, "%g was provided for %s - valid range is %g to %g",
+                  value, name_.c_str(), lowerDoubleValue_, upperDoubleValue_);
+          std::cout << value << " was provided for " << name_ <<
+                    " - valid range is " << lowerDoubleValue_ << " to " <<
+                    upperDoubleValue_ << std::endl;
+          returnCode = 1;
+     } else {
+          double oldValue = doubleValue_;
+          doubleValue_ = value;
+          switch (type_) {
+          case CLP_PARAM_DBL_DUALTOLERANCE:
+               model->getDblParam(OsiDualTolerance, oldValue);
+               model->setDblParam(OsiDualTolerance, value);
+               break;
+          case CLP_PARAM_DBL_PRIMALTOLERANCE:
+               model->getDblParam(OsiPrimalTolerance, oldValue);
+               model->setDblParam(OsiPrimalTolerance, value);
+               break;
+          default:
+               break;
+          }
+          sprintf(printArray, "%s was changed from %g to %g",
+                  name_.c_str(), oldValue, value);
+          returnCode = 0;
+     }
+     return printArray;
+}
+#endif
+#ifdef COIN_HAS_CLP
+int
+CbcOrClpParam::setDoubleParameter (ClpSimplex * model, double value)
+{
+     int returnCode;
+     setDoubleParameterWithMessage(model, value, returnCode);
+     if (doPrinting && strlen(printArray))
+          std::cout << printArray << std::endl;
+     return returnCode;
+}
+// Sets int parameter and returns printable string and error code
+const char *
+CbcOrClpParam::setDoubleParameterWithMessage ( ClpSimplex * model, double value , int & returnCode)
+{
+     double oldValue = doubleValue_;
+     if (value < lowerDoubleValue_ || value > upperDoubleValue_) {
+          sprintf(printArray, "%g was provided for %s - valid range is %g to %g",
+                  value, name_.c_str(), lowerDoubleValue_, upperDoubleValue_);
+          returnCode = 1;
+     } else {
+          sprintf(printArray, "%s was changed from %g to %g",
+                  name_.c_str(), oldValue, value);
+          returnCode = 0;
+          doubleValue_ = value;
+          switch (type_) {
+          case CLP_PARAM_DBL_DUALTOLERANCE:
+               model->setDualTolerance(value);
+               break;
+          case CLP_PARAM_DBL_PRIMALTOLERANCE:
+               model->setPrimalTolerance(value);
+               break;
+          case CLP_PARAM_DBL_ZEROTOLERANCE:
+               model->setSmallElementValue(value);
+               break;
+          case CLP_PARAM_DBL_DUALBOUND:
+               model->setDualBound(value);
+               break;
+          case CLP_PARAM_DBL_PRIMALWEIGHT:
+               model->setInfeasibilityCost(value);
+               break;
+#ifndef COIN_HAS_CBC
+          case CLP_PARAM_DBL_TIMELIMIT:
+               model->setMaximumSeconds(value);
+               break;
+#endif
+          case CLP_PARAM_DBL_OBJSCALE:
+               model->setObjectiveScale(value);
+               break;
+          case CLP_PARAM_DBL_RHSSCALE:
+               model->setRhsScale(value);
+               break;
+          case CLP_PARAM_DBL_PRESOLVETOLERANCE:
+               model->setDblParam(ClpPresolveTolerance, value);
+               break;
+          default:
+               break;
+          }
+     }
+     return printArray;
+}
+double
+CbcOrClpParam::doubleParameter (ClpSimplex * model) const
+{
+     double value;
+     switch (type_) {
+#ifndef COIN_HAS_CBC
+     case CLP_PARAM_DBL_DUALTOLERANCE:
+          value = model->dualTolerance();
+          break;
+     case CLP_PARAM_DBL_PRIMALTOLERANCE:
+          value = model->primalTolerance();
+          break;
+#endif
+     case CLP_PARAM_DBL_ZEROTOLERANCE:
+          value = model->getSmallElementValue();
+          break;
+     case CLP_PARAM_DBL_DUALBOUND:
+          value = model->dualBound();
+          break;
+     case CLP_PARAM_DBL_PRIMALWEIGHT:
+          value = model->infeasibilityCost();
+          break;
+#ifndef COIN_HAS_CBC
+     case CLP_PARAM_DBL_TIMELIMIT:
+          value = model->maximumSeconds();
+          break;
+#endif
+     case CLP_PARAM_DBL_OBJSCALE:
+          value = model->objectiveScale();
+          break;
+     case CLP_PARAM_DBL_RHSSCALE:
+          value = model->rhsScale();
+          break;
+     default:
+          value = doubleValue_;
+          break;
+     }
+     return value;
+}
+int
+CbcOrClpParam::setIntParameter (ClpSimplex * model, int value)
+{
+     int returnCode;
+     setIntParameterWithMessage(model, value, returnCode);
+     if (doPrinting && strlen(printArray))
+          std::cout << printArray << std::endl;
+     return returnCode;
+}
+// Sets int parameter and returns printable string and error code
+const char *
+CbcOrClpParam::setIntParameterWithMessage ( ClpSimplex * model, int value , int & returnCode)
+{
+     int oldValue = intValue_;
+     if (value < lowerIntValue_ || value > upperIntValue_) {
+          sprintf(printArray, "%d was provided for %s - valid range is %d to %d",
+                  value, name_.c_str(), lowerIntValue_, upperIntValue_);
+          returnCode = 1;
+     } else {
+          intValue_ = value;
+          sprintf(printArray, "%s was changed from %d to %d",
+                  name_.c_str(), oldValue, value);
+          returnCode = 0;
+          switch (type_) {
+          case CLP_PARAM_INT_SOLVERLOGLEVEL:
+               model->setLogLevel(value);
+               if (value > 2)
+                    model->factorization()->messageLevel(8);
+               else
+                    model->factorization()->messageLevel(0);
+               break;
+          case CLP_PARAM_INT_MAXFACTOR:
+               model->factorization()->maximumPivots(value);
+               break;
+          case CLP_PARAM_INT_PERTVALUE:
+               model->setPerturbation(value);
+               break;
+          case CLP_PARAM_INT_MAXITERATION:
+               model->setMaximumIterations(value);
+               break;
+          case CLP_PARAM_INT_SPECIALOPTIONS:
+               model->setSpecialOptions(value);
+               break;
+          case CLP_PARAM_INT_RANDOMSEED:
+	    {
+	      if (value==0) {
+		double time = fabs(CoinGetTimeOfDay());
+		while (time>=COIN_INT_MAX)
+		  time *= 0.5;
+		value = static_cast<int>(time);
+		sprintf(printArray, "using time of day %s was changed from %d to %d",
+                  name_.c_str(), oldValue, value);
+	      }
+	      model->setRandomSeed(value);
+	    }
+               break;
+          case CLP_PARAM_INT_MORESPECIALOPTIONS:
+               model->setMoreSpecialOptions(value);
+	       break;
+#ifndef COIN_HAS_CBC
+#ifdef CBC_THREAD
+          case CBC_PARAM_INT_THREADS:
+               model->setNumberThreads(value);
+               break;
+#endif
+#endif
+          default:
+               break;
+          }
+     }
+     return printArray;
+}
+int
+CbcOrClpParam::intParameter (ClpSimplex * model) const
+{
+     int value;
+     switch (type_) {
+#ifndef COIN_HAS_CBC
+     case CLP_PARAM_INT_SOLVERLOGLEVEL:
+          value = model->logLevel();
+          break;
+#endif
+     case CLP_PARAM_INT_MAXFACTOR:
+          value = model->factorization()->maximumPivots();
+          break;
+          break;
+     case CLP_PARAM_INT_PERTVALUE:
+          value = model->perturbation();
+          break;
+     case CLP_PARAM_INT_MAXITERATION:
+          value = model->maximumIterations();
+          break;
+     case CLP_PARAM_INT_SPECIALOPTIONS:
+          value = model->specialOptions();
+          break;
+     case CLP_PARAM_INT_RANDOMSEED:
+          value = model->randomNumberGenerator()->getSeed();
+          break;
+     case CLP_PARAM_INT_MORESPECIALOPTIONS:
+          value = model->moreSpecialOptions();
+          break;
+#ifndef COIN_HAS_CBC
+#ifdef CBC_THREAD
+     case CBC_PARAM_INT_THREADS:
+          value = model->numberThreads();
+	  break;
+#endif
+#endif
+     default:
+          value = intValue_;
+          break;
+     }
+     return value;
+}
+#endif
+int
+CbcOrClpParam::checkDoubleParameter (double value) const
+{
+     if (value < lowerDoubleValue_ || value > upperDoubleValue_) {
+          std::cout << value << " was provided for " << name_ <<
+                    " - valid range is " << lowerDoubleValue_ << " to " <<
+                    upperDoubleValue_ << std::endl;
+          return 1;
+     } else {
+          return 0;
+     }
+}
+#ifdef COIN_HAS_CBC
+double
+CbcOrClpParam::doubleParameter (OsiSolverInterface *
+#ifndef NDEBUG
+                                model
+#endif
+                               ) const
+{
+     double value = 0.0;
+     switch (type_) {
+     case CLP_PARAM_DBL_DUALTOLERANCE:
+          assert(model->getDblParam(OsiDualTolerance, value));
+          break;
+     case CLP_PARAM_DBL_PRIMALTOLERANCE:
+          assert(model->getDblParam(OsiPrimalTolerance, value));
+          break;
+     default:
+          return doubleValue_;
+          break;
+     }
+     return value;
+}
+int
+CbcOrClpParam::setIntParameter (OsiSolverInterface * model, int value)
+{
+     int returnCode;
+     setIntParameterWithMessage(model, value, returnCode);
+     if (doPrinting && strlen(printArray))
+          std::cout << printArray << std::endl;
+     return returnCode;
+}
+// Sets int parameter and returns printable string and error code
+const char *
+CbcOrClpParam::setIntParameterWithMessage ( OsiSolverInterface * model, int  value , int & returnCode)
+{
+     if (value < lowerIntValue_ || value > upperIntValue_) {
+          sprintf(printArray, "%d was provided for %s - valid range is %d to %d",
+                  value, name_.c_str(), lowerIntValue_, upperIntValue_);
+          returnCode = 1;
+     } else {
+          int oldValue = intValue_;
+          intValue_ = oldValue;
+          switch (type_) {
+          case CLP_PARAM_INT_SOLVERLOGLEVEL:
+               model->messageHandler()->setLogLevel(value);
+               break;
+          default:
+               break;
+          }
+          sprintf(printArray, "%s was changed from %d to %d",
+                  name_.c_str(), oldValue, value);
+          returnCode = 0;
+     }
+     return printArray;
+}
+int
+CbcOrClpParam::intParameter (OsiSolverInterface * model) const
+{
+     int value = 0;
+     switch (type_) {
+     case CLP_PARAM_INT_SOLVERLOGLEVEL:
+          value = model->messageHandler()->logLevel();
+          break;
+     default:
+          value = intValue_;
+          break;
+     }
+     return value;
+}
+int
+CbcOrClpParam::setDoubleParameter (CbcModel &model, double value)
+{
+     int returnCode;
+     setDoubleParameterWithMessage(model, value, returnCode);
+     if (doPrinting && strlen(printArray))
+          std::cout << printArray << std::endl;
+     return returnCode;
+}
+// Sets double parameter and returns printable string and error code
+const char *
+CbcOrClpParam::setDoubleParameterWithMessage ( CbcModel & model, double  value , int & returnCode)
+{
+     if (value < lowerDoubleValue_ || value > upperDoubleValue_) {
+          sprintf(printArray, "%g was provided for %s - valid range is %g to %g",
+                  value, name_.c_str(), lowerDoubleValue_, upperDoubleValue_);
+          returnCode = 1;
+     } else {
+          double oldValue = doubleValue_;
+          doubleValue_ = value;
+          switch (type_) {
+          case CBC_PARAM_DBL_INFEASIBILITYWEIGHT:
+               oldValue = model.getDblParam(CbcModel::CbcInfeasibilityWeight);
+               model.setDblParam(CbcModel::CbcInfeasibilityWeight, value);
+               break;
+          case CBC_PARAM_DBL_INTEGERTOLERANCE:
+               oldValue = model.getDblParam(CbcModel::CbcIntegerTolerance);
+               model.setDblParam(CbcModel::CbcIntegerTolerance, value);
+               break;
+          case CBC_PARAM_DBL_INCREMENT:
+               oldValue = model.getDblParam(CbcModel::CbcCutoffIncrement);
+               model.setDblParam(CbcModel::CbcCutoffIncrement, value);
+          case CBC_PARAM_DBL_ALLOWABLEGAP:
+               oldValue = model.getDblParam(CbcModel::CbcAllowableGap);
+               model.setDblParam(CbcModel::CbcAllowableGap, value);
+               break;
+          case CBC_PARAM_DBL_GAPRATIO:
+               oldValue = model.getDblParam(CbcModel::CbcAllowableFractionGap);
+               model.setDblParam(CbcModel::CbcAllowableFractionGap, value);
+               break;
+          case CBC_PARAM_DBL_CUTOFF:
+               oldValue = model.getCutoff();
+               model.setCutoff(value);
+               break;
+          case CBC_PARAM_DBL_TIMELIMIT_BAB:
+               oldValue = model.getDblParam(CbcModel::CbcMaximumSeconds) ;
+               {
+                    //OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (model.solver());
+                    //ClpSimplex * lpSolver = clpSolver->getModelPtr();
+                    //lpSolver->setMaximumSeconds(value);
+                    model.setDblParam(CbcModel::CbcMaximumSeconds, value) ;
+               }
+               break ;
+          case CLP_PARAM_DBL_DUALTOLERANCE:
+          case CLP_PARAM_DBL_PRIMALTOLERANCE:
+               setDoubleParameter(model.solver(), value);
+               return 0; // to avoid message
+          default:
+               break;
+          }
+          sprintf(printArray, "%s was changed from %g to %g",
+                  name_.c_str(), oldValue, value);
+          returnCode = 0;
+     }
+     return printArray;
+}
+double
+CbcOrClpParam::doubleParameter (CbcModel &model) const
+{
+     double value;
+     switch (type_) {
+     case CBC_PARAM_DBL_INFEASIBILITYWEIGHT:
+          value = model.getDblParam(CbcModel::CbcInfeasibilityWeight);
+          break;
+     case CBC_PARAM_DBL_INTEGERTOLERANCE:
+          value = model.getDblParam(CbcModel::CbcIntegerTolerance);
+          break;
+     case CBC_PARAM_DBL_INCREMENT:
+          value = model.getDblParam(CbcModel::CbcCutoffIncrement);
+          break;
+     case CBC_PARAM_DBL_ALLOWABLEGAP:
+          value = model.getDblParam(CbcModel::CbcAllowableGap);
+          break;
+     case CBC_PARAM_DBL_GAPRATIO:
+          value = model.getDblParam(CbcModel::CbcAllowableFractionGap);
+          break;
+     case CBC_PARAM_DBL_CUTOFF:
+          value = model.getCutoff();
+          break;
+     case CBC_PARAM_DBL_TIMELIMIT_BAB:
+          value = model.getDblParam(CbcModel::CbcMaximumSeconds) ;
+          break ;
+     case CLP_PARAM_DBL_DUALTOLERANCE:
+     case CLP_PARAM_DBL_PRIMALTOLERANCE:
+          value = doubleParameter(model.solver());
+          break;
+     default:
+          value = doubleValue_;
+          break;
+     }
+     return value;
+}
+int
+CbcOrClpParam::setIntParameter (CbcModel &model, int value)
+{
+     int returnCode;
+     setIntParameterWithMessage(model, value, returnCode);
+     if (doPrinting && strlen(printArray))
+          std::cout << printArray << std::endl;
+     return returnCode;
+}
+// Sets int parameter and returns printable string and error code
+const char *
+CbcOrClpParam::setIntParameterWithMessage ( CbcModel & model, int value , int & returnCode)
+{
+     if (value < lowerIntValue_ || value > upperIntValue_) {
+          sprintf(printArray, "%d was provided for %s - valid range is %d to %d",
+                  value, name_.c_str(), lowerIntValue_, upperIntValue_);
+          returnCode = 1;
+     } else {
+          int oldValue = intValue_;
+          intValue_ = value;
+          switch (type_) {
+          case CLP_PARAM_INT_LOGLEVEL:
+               oldValue = model.messageHandler()->logLevel();
+               model.messageHandler()->setLogLevel(CoinAbs(value));
+               break;
+          case CLP_PARAM_INT_SOLVERLOGLEVEL:
+               oldValue = model.solver()->messageHandler()->logLevel();
+               model.solver()->messageHandler()->setLogLevel(value);
+               break;
+          case CBC_PARAM_INT_MAXNODES:
+               oldValue = model.getIntParam(CbcModel::CbcMaxNumNode);
+               model.setIntParam(CbcModel::CbcMaxNumNode, value);
+               break;
+          case CBC_PARAM_INT_MAXSOLS:
+               oldValue = model.getIntParam(CbcModel::CbcMaxNumSol);
+               model.setIntParam(CbcModel::CbcMaxNumSol, value);
+               break;
+          case CBC_PARAM_INT_MAXSAVEDSOLS:
+               oldValue = model.maximumSavedSolutions();
+               model.setMaximumSavedSolutions(value);
+               break;
+          case CBC_PARAM_INT_STRONGBRANCHING:
+               oldValue = model.numberStrong();
+               model.setNumberStrong(value);
+               break;
+          case CBC_PARAM_INT_NUMBERBEFORE:
+               oldValue = model.numberBeforeTrust();
+               model.setNumberBeforeTrust(value);
+               break;
+          case CBC_PARAM_INT_NUMBERANALYZE:
+               oldValue = model.numberAnalyzeIterations();
+               model.setNumberAnalyzeIterations(value);
+               break;
+          case CBC_PARAM_INT_CUTPASSINTREE:
+               oldValue = model.getMaximumCutPasses();
+               model.setMaximumCutPasses(value);
+               break;
+          case CBC_PARAM_INT_CUTPASS:
+               oldValue = model.getMaximumCutPassesAtRoot();
+               model.setMaximumCutPassesAtRoot(value);
+               break;
+#ifdef COIN_HAS_CBC
+#ifdef CBC_THREAD
+          case CBC_PARAM_INT_THREADS:
+               oldValue = model.getNumberThreads();
+               model.setNumberThreads(value);
+               break;
+#endif
+          case CBC_PARAM_INT_RANDOMSEED:
+               oldValue = model.getRandomSeed();
+               model.setRandomSeed(value);
+               break;
+#endif
+          default:
+               break;
+          }
+          sprintf(printArray, "%s was changed from %d to %d",
+                  name_.c_str(), oldValue, value);
+          returnCode = 0;
+     }
+     return printArray;
+}
+int
+CbcOrClpParam::intParameter (CbcModel &model) const
+{
+     int value;
+     switch (type_) {
+     case CLP_PARAM_INT_LOGLEVEL:
+          value = model.messageHandler()->logLevel();
+          break;
+     case CLP_PARAM_INT_SOLVERLOGLEVEL:
+          value = model.solver()->messageHandler()->logLevel();
+          break;
+     case CBC_PARAM_INT_MAXNODES:
+          value = model.getIntParam(CbcModel::CbcMaxNumNode);
+          break;
+     case CBC_PARAM_INT_MAXSOLS:
+          value = model.getIntParam(CbcModel::CbcMaxNumSol);
+          break;
+     case CBC_PARAM_INT_MAXSAVEDSOLS:
+          value = model.maximumSavedSolutions();
+	  break;
+     case CBC_PARAM_INT_STRONGBRANCHING:
+          value = model.numberStrong();
+          break;
+     case CBC_PARAM_INT_NUMBERBEFORE:
+          value = model.numberBeforeTrust();
+          break;
+     case CBC_PARAM_INT_NUMBERANALYZE:
+          value = model.numberAnalyzeIterations();
+          break;
+     case CBC_PARAM_INT_CUTPASSINTREE:
+          value = model.getMaximumCutPasses();
+          break;
+     case CBC_PARAM_INT_CUTPASS:
+          value = model.getMaximumCutPassesAtRoot();
+          break;
+#ifdef COIN_HAS_CBC
+#ifdef CBC_THREAD
+     case CBC_PARAM_INT_THREADS:
+          value = model.getNumberThreads();
+#endif
+     case CBC_PARAM_INT_RANDOMSEED:
+          value = model.getRandomSeed();
+          break;
+#endif
+     default:
+          value = intValue_;
+          break;
+     }
+     return value;
+}
+#endif
+// Sets current parameter option using string
+void
+CbcOrClpParam::setCurrentOption ( const std::string value )
+{
+     int action = parameterOption(value);
+     if (action >= 0)
+          currentKeyWord_ = action;
+}
+// Sets current parameter option
+void
+CbcOrClpParam::setCurrentOption ( int value , bool printIt)
+{
+     if (printIt && value != currentKeyWord_)
+          std::cout << "Option for " << name_ << " changed from "
+                    << definedKeyWords_[currentKeyWord_] << " to "
+                    << definedKeyWords_[value] << std::endl;
+
+     currentKeyWord_ = value;
+}
+// Sets current parameter option and returns printable string
+const char *
+CbcOrClpParam::setCurrentOptionWithMessage ( int value )
+{
+     if (value != currentKeyWord_) {
+          sprintf(printArray, "Option for %s changed from %s to %s",
+                  name_.c_str(), definedKeyWords_[currentKeyWord_].c_str(),
+                  definedKeyWords_[value].c_str());
+
+          currentKeyWord_ = value;
+     } else {
+          printArray[0] = '\0';
+     }
+     return printArray;
+}
+void
+CbcOrClpParam::setIntValue ( int value )
+{
+     if (value < lowerIntValue_ || value > upperIntValue_) {
+          std::cout << value << " was provided for " << name_ <<
+                    " - valid range is " << lowerIntValue_ << " to " <<
+                    upperIntValue_ << std::endl;
+     } else {
+          intValue_ = value;
+     }
+}
+void
+CbcOrClpParam::setDoubleValue ( double value )
+{
+     if (value < lowerDoubleValue_ || value > upperDoubleValue_) {
+          std::cout << value << " was provided for " << name_ <<
+                    " - valid range is " << lowerDoubleValue_ << " to " <<
+                    upperDoubleValue_ << std::endl;
+     } else {
+          doubleValue_ = value;
+     }
+}
+void
+CbcOrClpParam::setStringValue ( std::string value )
+{
+     stringValue_ = value;
+}
+static char line[1000];
+static char * where = NULL;
+extern int CbcOrClpRead_mode;
+int CbcOrClpEnvironmentIndex = -1;
+static size_t fillEnv()
+{
+#if defined(_MSC_VER) || defined(__MSVCRT__)
+     return 0;
+#else
+     // Don't think it will work on Windows
+     char * environ = getenv("CBC_CLP_ENVIRONMENT");
+     size_t length = 0;
+     if (environ) {
+          length = strlen(environ);
+          if (CbcOrClpEnvironmentIndex < static_cast<int>(length)) {
+               // find next non blank
+               char * whereEnv = environ + CbcOrClpEnvironmentIndex;
+               // munch white space
+               while (*whereEnv == ' ' || *whereEnv == '\t' || *whereEnv < ' ')
+                    whereEnv++;
+               // copy
+               char * put = line;
+               while ( *whereEnv != '\0' ) {
+                    if ( *whereEnv == ' ' || *whereEnv == '\t' || *whereEnv < ' ' ) {
+                         break;
+                    }
+                    *put = *whereEnv;
+                    put++;
+                    assert (put - line < 1000);
+                    whereEnv++;
+               }
+               CbcOrClpEnvironmentIndex = static_cast<int>(whereEnv - environ);
+               *put = '\0';
+               length = strlen(line);
+          } else {
+               length = 0;
+          }
+     }
+     if (!length)
+          CbcOrClpEnvironmentIndex = -1;
+     return length;
+#endif
+}
+extern FILE * CbcOrClpReadCommand;
+// Simple read stuff
+std::string
+CoinReadNextField()
+{
+     std::string field;
+     if (!where) {
+          // need new line
+#ifdef COIN_HAS_READLINE
+          if (CbcOrClpReadCommand == stdin) {
+               // Get a line from the user.
+               where = readline (coin_prompt);
+
+               // If the line has any text in it, save it on the history.
+               if (where) {
+                    if ( *where)
+                         add_history (where);
+                    strcpy(line, where);
+                    free(where);
+               }
+          } else {
+               where = fgets(line, 1000, CbcOrClpReadCommand);
+          }
+#else
+          if (CbcOrClpReadCommand == stdin) {
+	       fputs(coin_prompt,stdout);
+               fflush(stdout);
+          }
+          where = fgets(line, 1000, CbcOrClpReadCommand);
+#endif
+          if (!where)
+               return field; // EOF
+          where = line;
+          // clean image
+          char * lastNonBlank = line - 1;
+          while ( *where != '\0' ) {
+               if ( *where != '\t' && *where < ' ' ) {
+                    break;
+               } else if ( *where != '\t' && *where != ' ') {
+                    lastNonBlank = where;
+               }
+               where++;
+          }
+          where = line;
+          *(lastNonBlank + 1) = '\0';
+     }
+     // munch white space
+     while (*where == ' ' || *where == '\t')
+          where++;
+     char * saveWhere = where;
+     while (*where != ' ' && *where != '\t' && *where != '\0')
+          where++;
+     if (where != saveWhere) {
+          char save = *where;
+          *where = '\0';
+          //convert to string
+          field = saveWhere;
+          *where = save;
+     } else {
+          where = NULL;
+          field = "EOL";
+     }
+     return field;
+}
+
+std::string
+CoinReadGetCommand(int argc, const char *argv[])
+{
+     std::string field = "EOL";
+     // say no =
+     afterEquals = "";
+     while (field == "EOL") {
+          if (CbcOrClpRead_mode > 0) {
+               if ((CbcOrClpRead_mode < argc && argv[CbcOrClpRead_mode]) ||
+                         CbcOrClpEnvironmentIndex >= 0) {
+                    if (CbcOrClpEnvironmentIndex < 0) {
+                         field = argv[CbcOrClpRead_mode++];
+                    } else {
+                         if (fillEnv()) {
+                              field = line;
+                         } else {
+                              // not there
+                              continue;
+                         }
+                    }
+                    if (field == "-") {
+                         std::cout << "Switching to line mode" << std::endl;
+                         CbcOrClpRead_mode = -1;
+                         field = CoinReadNextField();
+                    } else if (field[0] != '-') {
+                         if (CbcOrClpRead_mode != 2) {
+                              // now allow std::cout<<"skipping non-command "<<field<<std::endl;
+                              // field="EOL"; // skip
+                         } else if (CbcOrClpEnvironmentIndex < 0) {
+                              // special dispensation - taken as -import name
+                              CbcOrClpRead_mode--;
+                              field = "import";
+                         }
+                    } else {
+                         if (field != "--") {
+                              // take off -
+                              field = field.substr(1);
+                         } else {
+                              // special dispensation - taken as -import --
+                              CbcOrClpRead_mode--;
+                              field = "import";
+                         }
+                    }
+               } else {
+                    field = "";
+               }
+          } else {
+               field = CoinReadNextField();
+          }
+     }
+     // if = then modify and save
+     std::string::size_type found = field.find('=');
+     if (found != std::string::npos) {
+          afterEquals = field.substr(found + 1);
+          field = field.substr(0, found);
+     }
+     //std::cout<<field<<std::endl;
+     return field;
+}
+std::string
+CoinReadGetString(int argc, const char *argv[])
+{
+     std::string field = "EOL";
+     if (afterEquals == "") {
+          if (CbcOrClpRead_mode > 0) {
+               if (CbcOrClpRead_mode < argc || CbcOrClpEnvironmentIndex >= 0) {
+                    if (CbcOrClpEnvironmentIndex < 0) {
+                         if (argv[CbcOrClpRead_mode][0] != '-') {
+                              field = argv[CbcOrClpRead_mode++];
+                         } else if (!strcmp(argv[CbcOrClpRead_mode], "--")) {
+                              field = argv[CbcOrClpRead_mode++];
+                              // -- means import from stdin
+                              field = "-";
+                         }
+                    } else {
+                         fillEnv();
+                         field = line;
+                    }
+               }
+          } else {
+               field = CoinReadNextField();
+          }
+     } else {
+          field = afterEquals;
+          afterEquals = "";
+     }
+     //std::cout<<field<<std::endl;
+     return field;
+}
+// valid 0 - okay, 1 bad, 2 not there
+int
+CoinReadGetIntField(int argc, const char *argv[], int * valid)
+{
+     std::string field = "EOL";
+     if (afterEquals == "") {
+          if (CbcOrClpRead_mode > 0) {
+               if (CbcOrClpRead_mode < argc || CbcOrClpEnvironmentIndex >= 0) {
+                    if (CbcOrClpEnvironmentIndex < 0) {
+                         // may be negative value so do not check for -
+                         field = argv[CbcOrClpRead_mode++];
+                    } else {
+                         fillEnv();
+                         field = line;
+                    }
+               }
+          } else {
+               field = CoinReadNextField();
+          }
+     } else {
+          field = afterEquals;
+          afterEquals = "";
+     }
+     long int value = 0;
+     //std::cout<<field<<std::endl;
+     if (field != "EOL") {
+          const char * start = field.c_str();
+          char * endPointer = NULL;
+          // check valid
+          value =  strtol(start, &endPointer, 10);
+          if (*endPointer == '\0') {
+               *valid = 0;
+          } else {
+               *valid = 1;
+               std::cout << "String of " << field;
+          }
+     } else {
+          *valid = 2;
+     }
+     return static_cast<int>(value);
+}
+double
+CoinReadGetDoubleField(int argc, const char *argv[], int * valid)
+{
+     std::string field = "EOL";
+     if (afterEquals == "") {
+          if (CbcOrClpRead_mode > 0) {
+               if (CbcOrClpRead_mode < argc || CbcOrClpEnvironmentIndex >= 0) {
+                    if (CbcOrClpEnvironmentIndex < 0) {
+                         // may be negative value so do not check for -
+                         field = argv[CbcOrClpRead_mode++];
+                    } else {
+                         fillEnv();
+                         field = line;
+                    }
+               }
+          } else {
+               field = CoinReadNextField();
+          }
+     } else {
+          field = afterEquals;
+          afterEquals = "";
+     }
+     double value = 0.0;
+     //std::cout<<field<<std::endl;
+     if (field != "EOL") {
+          const char * start = field.c_str();
+          char * endPointer = NULL;
+          // check valid
+          value =  strtod(start, &endPointer);
+          if (*endPointer == '\0') {
+               *valid = 0;
+          } else {
+               *valid = 1;
+               std::cout << "String of " << field;
+          }
+     } else {
+          *valid = 2;
+     }
+     return value;
+}
+/*
+  Subroutine to establish the cbc parameter array. See the description of
+  class CbcOrClpParam for details. Pulled from C..Main() for clarity.
+*/
+void
+establishParams (int &numberParameters, CbcOrClpParam *const parameters)
+{
+     numberParameters = 0;
+     parameters[numberParameters++] =
+          CbcOrClpParam("?", "For help", CBC_PARAM_GENERALQUERY, 7, 0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("???", "For help", CBC_PARAM_FULLGENERALQUERY, 7, 0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("-", "From stdin",
+                        CLP_PARAM_ACTION_STDIN, 3, 0);
+#ifdef ABC_INHERIT
+      parameters[numberParameters++] =
+          CbcOrClpParam("abc", "Whether to visit Aboca",
+                        "off", CLP_PARAM_STR_ABCWANTED, 7, 0);
+     parameters[numberParameters-1].append("one");
+     parameters[numberParameters-1].append("two");
+     parameters[numberParameters-1].append("three");
+     parameters[numberParameters-1].append("four");
+     parameters[numberParameters-1].append("five");
+     parameters[numberParameters-1].append("six");
+     parameters[numberParameters-1].append("seven");
+     parameters[numberParameters-1].append("eight");
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("decide");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Decide whether to use A Basic Optimization Code (Accelerated?) \
+and whether to try going parallel!"
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("allC!ommands", "Whether to print less used commands",
+                        "no", CLP_PARAM_STR_ALLCOMMANDS);
+     parameters[numberParameters-1].append("more");
+     parameters[numberParameters-1].append("all");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "For the sake of your sanity, only the more useful and simple commands \
+are printed out on ?."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("allow!ableGap", "Stop when gap between best possible and \
+best less than this",
+                        0.0, 1.0e20, CBC_PARAM_DBL_ALLOWABLEGAP);
+     parameters[numberParameters-1].setDoubleValue(0.0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If the gap between best solution and best possible solution is less than this \
+then the search will be terminated.  Also see ratioGap."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("allS!lack", "Set basis back to all slack and reset solution",
+                        CLP_PARAM_ACTION_ALLSLACK, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Mainly useful for tuning purposes.  Normally the first dual or primal will be using an all slack \
+basis anyway."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("artif!icialCost", "Costs >= this treated as artificials in feasibility pump",
+                        0.0, COIN_DBL_MAX, CBC_PARAM_DBL_ARTIFICIALCOST, 1);
+     parameters[numberParameters-1].setDoubleValue(0.0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "0.0 off - otherwise variables with costs >= this are treated as artificials and fixed to lower bound in feasibility pump"
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("auto!Scale", "Whether to scale objective, rhs and bounds of problem if they look odd",
+                        "off", CLP_PARAM_STR_AUTOSCALE, 7, 0);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If you think you may get odd objective values or large equality rows etc then\
+ it may be worth setting this true.  It is still experimental and you may prefer\
+ to use objective!Scale and rhs!Scale."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("barr!ier", "Solve using primal dual predictor corrector algorithm",
+                        CLP_PARAM_ACTION_BARRIER);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This command solves the current model using the  primal dual predictor \
+corrector algorithm.  You may want to link in an alternative \
+ordering and factorization.  It will also solve models \
+with quadratic objectives."
+
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("basisI!n", "Import basis from bas file",
+                        CLP_PARAM_ACTION_BASISIN, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will read an MPS format basis file from the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to '', i.e. it must be set.  If you have libz then it can read compressed\
+ files 'xxxxxxxx.gz' or xxxxxxxx.bz2."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("basisO!ut", "Export basis as bas file",
+                        CLP_PARAM_ACTION_BASISOUT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will write an MPS format basis file to the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to 'default.bas'."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("biasLU", "Whether factorization biased towards U",
+                        "UU", CLP_PARAM_STR_BIASLU, 2, 0);
+     parameters[numberParameters-1].append("UX");
+     parameters[numberParameters-1].append("LX");
+     parameters[numberParameters-1].append("LL");
+     parameters[numberParameters-1].setCurrentOption("LX");
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("branch!AndCut", "Do Branch and Cut",
+                        CBC_PARAM_ACTION_BAB);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This does branch and cut.  There are many parameters which can affect the performance.  \
+First just try with default settings and look carefully at the log file.  Did cuts help?  Did they take too long?  \
+Look at output to see which cuts were effective and then do some tuning.  You will see that the \
+options for cuts are off, on, root and ifmove, forceon.  Off is \
+obvious, on means that this cut generator will be tried in the branch and cut tree (you can fine tune using \
+'depth').  Root means just at the root node while 'ifmove' means that cuts will be used in the tree if they \
+look as if they are doing some good and moving the objective value.  Forceon is same as on but forces code to use \
+cut generator at every node.  For probing forceonbut just does fixing probing in tree - not strengthening etc.  \
+If pre-processing reduced the size of the \
+problem or strengthened many coefficients then it is probably wise to leave it on.  Switch off heuristics \
+which did not provide solutions.  The other major area to look at is the search.  Hopefully good solutions \
+were obtained fairly early in the search so the important point is to select the best variable to branch on.  \
+See whether strong branching did a good job - or did it just take a lot of iterations.  Adjust the strongBranching \
+and trustPseudoCosts parameters.  If cuts did a good job, then you may wish to \
+have more rounds of cuts - see passC!uts and passT!ree."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("bscale", "Whether to scale in barrier (and ordering speed)",
+                        "off", CLP_PARAM_STR_BARRIERSCALE, 7, 0);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("off1");
+     parameters[numberParameters-1].append("on1");
+     parameters[numberParameters-1].append("off2");
+     parameters[numberParameters-1].append("on2");
+     parameters[numberParameters++] =
+          CbcOrClpParam("chol!esky", "Which cholesky algorithm",
+                        "native", CLP_PARAM_STR_CHOLESKY, 7);
+     parameters[numberParameters-1].append("dense");
+     //#ifdef FOREIGN_BARRIER
+#ifdef COIN_HAS_WSMP
+     parameters[numberParameters-1].append("fudge!Long");
+     parameters[numberParameters-1].append("wssmp");
+#else
+     parameters[numberParameters-1].append("fudge!Long_dummy");
+     parameters[numberParameters-1].append("wssmp_dummy");
+#endif
+#if defined(COIN_HAS_AMD) || defined(COIN_HAS_CHOLMOD) || defined(COIN_HAS_GLPK)
+     parameters[numberParameters-1].append("Uni!versityOfFlorida");
+#else
+     parameters[numberParameters-1].append("Uni!versityOfFlorida_dummy");
+#endif
+#ifdef TAUCS_BARRIER
+     parameters[numberParameters-1].append("Taucs");
+#else
+     parameters[numberParameters-1].append("Taucs_dummy");
+#endif
+#ifdef COIN_HAS_MUMPS
+     parameters[numberParameters-1].append("Mumps");
+#else
+     parameters[numberParameters-1].append("Mumps_dummy");
+#endif
+     parameters[numberParameters-1].setLonghelp
+     (
+          "For a barrier code to be effective it needs a good Cholesky ordering and factorization.  \
+The native ordering and factorization is not state of the art, although acceptable.  \
+You may want to link in one from another source.  See Makefile.locations for some \
+possibilities."
+     );
+     //#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("clique!Cuts", "Whether to use Clique cuts",
+                        "off", CBC_PARAM_STR_CLIQUECUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("onglobal");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on clique cuts (either at root or in entire tree) \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("combine!Solutions", "Whether to use combine solution heuristic",
+                        "off", CBC_PARAM_STR_COMBINE);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on a heuristic which does branch and cut on the problem given by just \
+using variables which have appeared in one or more solutions. \
+It obviously only tries after two or more solutions. \
+See Rounding for meaning of on,both,before"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("combine2!Solutions", "Whether to use crossover solution heuristic",
+                        "off", CBC_PARAM_STR_CROSSOVER2);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on a heuristic which does branch and cut on the problem given by \
+fixing variables which have same value in two or more solutions. \
+It obviously only tries after two or more solutions. \
+See Rounding for meaning of on,both,before"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("constraint!fromCutoff", "Whether to use cutoff as constraint",
+                        "off", CBC_PARAM_STR_CUTOFF_CONSTRAINT);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This adds the objective as a constraint with best solution as RHS"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("cost!Strategy", "How to use costs as priorities",
+                        "off", CBC_PARAM_STR_COSTSTRATEGY);
+     parameters[numberParameters-1].append("pri!orities");
+     parameters[numberParameters-1].append("column!Order?");
+     parameters[numberParameters-1].append("01f!irst?");
+     parameters[numberParameters-1].append("01l!ast?");
+     parameters[numberParameters-1].append("length!?");
+     parameters[numberParameters-1].append("singletons");
+     parameters[numberParameters-1].append("nonzero");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This orders the variables in order of their absolute costs - with largest cost ones being branched on \
+first.  This primitive strategy can be surprsingly effective.  The column order\
+ option is obviously not on costs but easy to code here."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("cplex!Use", "Whether to use Cplex!",
+                        "off", CBC_PARAM_STR_CPX);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          " If the user has Cplex, but wants to use some of Cbc's heuristics \
+then you can!  If this is on, then Cbc will get to the root node and then \
+hand over to Cplex.  If heuristics find a solution this can be significantly \
+quicker.  You will probably want to switch off Cbc's cuts as Cplex thinks \
+they are genuine constraints.  It is also probable that you want to switch \
+off preprocessing, although for difficult problems it is worth trying \
+both."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("cpp!Generate", "Generates C++ code",
+                        -1, 50000, CLP_PARAM_INT_CPP, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Once you like what the stand-alone solver does then this allows \
+you to generate user_driver.cpp which approximates the code.  \
+0 gives simplest driver, 1 generates saves and restores, 2 \
+generates saves and restores even for variables at default value. \
+4 bit in cbc generates size dependent code rather than computed values.  \
+This is now deprecated as you can call stand-alone solver - see \
+Cbc/examples/driver4.cpp."
+     );
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("crash", "Whether to create basis for problem",
+                        "off", CLP_PARAM_STR_CRASH);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("so!low_halim");
+     parameters[numberParameters-1].append("lots");
+#ifdef ABC_INHERIT
+     parameters[numberParameters-1].append("dual");
+     parameters[numberParameters-1].append("dw");
+     parameters[numberParameters-1].append("idiot");
+#endif
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If crash is set on and there is an all slack basis then Clp will flip or put structural\
+ variables into basis with the aim of getting dual feasible.  On the whole dual seems to be\
+ better without it and there are alternative types of 'crash' for primal e.g. 'idiot' or 'sprint'. \
+I have also added a variant due to Solow and Halim which is as on but just flip.");
+     parameters[numberParameters++] =
+          CbcOrClpParam("cross!over", "Whether to get a basic solution after barrier",
+                        "on", CLP_PARAM_STR_CROSSOVER);
+     parameters[numberParameters-1].append("off");
+     parameters[numberParameters-1].append("maybe");
+     parameters[numberParameters-1].append("presolve");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Interior point algorithms do not obtain a basic solution (and \
+the feasibility criterion is a bit suspect (JJF)).  This option will crossover \
+to a basic solution suitable for ranging or branch and cut.  With the current state \
+of quadratic it may be a good idea to switch off crossover for quadratic (and maybe \
+presolve as well) - the option maybe does this."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("csv!Statistics", "Create one line of statistics",
+                        CLP_PARAM_ACTION_CSVSTATISTICS, 2, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This appends statistics to given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to '', i.e. it must be set.  Adds header if file empty or does not exist."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("cutD!epth", "Depth in tree at which to do cuts",
+                        -1, 999999, CBC_PARAM_INT_CUTDEPTH);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Cut generators may be - off, on only at root, on if they look possible \
+and on.  If they are done every node then that is that, but it may be worth doing them \
+every so often.  The original method was every so many nodes but it is more logical \
+to do it whenever depth in tree is a multiple of K.  This option does that and defaults \
+to -1 (off -> code decides)."
+     );
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("cutL!ength", "Length of a cut",
+                        -1, COIN_INT_MAX, CBC_PARAM_INT_CUTLENGTH);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "At present this only applies to Gomory cuts. -1 (default) leaves as is. \
+Any value >0 says that all cuts <= this length can be generated both at \
+root node and in tree. 0 says to use some dynamic lengths.  If value >=10,000,000 \
+then the length in tree is value%10000000 - so 10000100 means unlimited length \
+at root and 100 in tree."
+     );
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("cuto!ff", "All solutions must be better than this",
+                        -1.0e60, 1.0e60, CBC_PARAM_DBL_CUTOFF);
+     parameters[numberParameters-1].setDoubleValue(1.0e50);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "All solutions must be better than this value (in a minimization sense).  \
+This is also set by code whenever it obtains a solution and is set to value of \
+objective for solution minus cutoff increment."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("cuts!OnOff", "Switches all cuts on or off",
+                        "off", CBC_PARAM_STR_CUTSSTRATEGY);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This can be used to switch on or off all cuts (apart from Reduce and Split).  Then you can do \
+individual ones off or on \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("debug!In", "read valid solution from file",
+                        CLP_PARAM_ACTION_DEBUG, 7, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will read a solution file from the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to '', i.e. it must be set.\n\n\
+If set to create it will create a file called debug.file  after search.\n\n\
+The idea is that if you suspect a bad cut generator \
+you can do a good run with debug set to 'create' and then switch on the cuts you suspect and \
+re-run with debug set to 'debug.file'  The create case has same effect as saveSolution."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+#if CLP_MULTIPLE_FACTORIZATIONS >0
+     parameters[numberParameters++] =
+          CbcOrClpParam("dense!Threshold", "Whether to use dense factorization",
+                        -1, 10000, CBC_PARAM_INT_DENSE, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If processed problem <= this use dense factorization"
+     );
+     parameters[numberParameters-1].setIntValue(-1);
+#endif
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("depth!MiniBab", "Depth at which to try mini BAB",
+                        -COIN_INT_MAX, COIN_INT_MAX, CBC_PARAM_INT_DEPTHMINIBAB);
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Rather a complicated parameter but can be useful. -1 means off for large problems but on as if -12 for problems where rows+columns<500, -2 \
+means use Cplex if it is linked in.  Otherwise if negative then go into depth first complete search fast branch and bound when depth>= -value-2 (so -3 will use this at depth>=1).  This mode is only switched on after 500 nodes.  If you really want to switch it off for small problems then set this to -999.  If >=0 the value doesn't matter very much.  The code will do approximately 100 nodes of fast branch and bound every now and then at depth>=5.  The actual logic is too twisted to describe here."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("dextra3", "Extra double parameter 3",
+                        -COIN_DBL_MAX, COIN_DBL_MAX, CBC_PARAM_DBL_DEXTRA3, 0);
+     parameters[numberParameters-1].setDoubleValue(0.0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("dextra4", "Extra double parameter 4",
+                        -COIN_DBL_MAX, COIN_DBL_MAX, CBC_PARAM_DBL_DEXTRA4, 0);
+     parameters[numberParameters-1].setDoubleValue(0.0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("dextra5", "Extra double parameter 5",
+                        -COIN_DBL_MAX, COIN_DBL_MAX, CBC_PARAM_DBL_DEXTRA5, 0);
+     parameters[numberParameters-1].setDoubleValue(0.0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("Dins", "Whether to try Distance Induced Neighborhood Search",
+                        "off", CBC_PARAM_STR_DINS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].append("often");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on Distance induced neighborhood Search. \
+See Rounding for meaning of on,both,before"
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("direction", "Minimize or Maximize",
+                        "min!imize", CLP_PARAM_STR_DIRECTION);
+     parameters[numberParameters-1].append("max!imize");
+     parameters[numberParameters-1].append("zero");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The default is minimize - use 'direction maximize' for maximization.\n\
+You can also use the parameters 'maximize' or 'minimize'."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("directory", "Set Default directory for import etc.",
+                        CLP_PARAM_ACTION_DIRECTORY);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This sets the directory which import, export, saveModel, restoreModel etc will use.\
+  It is initialized to './'"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("dirSample", "Set directory where the COIN-OR sample problems are.",
+                        CLP_PARAM_ACTION_DIRSAMPLE, 7, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This sets the directory where the COIN-OR sample problems reside. It is\
+ used only when -unitTest is passed to clp. clp will pick up the test problems\
+ from this directory.\
+ It is initialized to '../../Data/Sample'"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("dirNetlib", "Set directory where the netlib problems are.",
+                        CLP_PARAM_ACTION_DIRNETLIB, 7, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This sets the directory where the netlib problems reside. One can get\
+ the netlib problems from COIN-OR or from the main netlib site. This\
+ parameter is used only when -netlib is passed to clp. clp will pick up the\
+ netlib problems from this directory. If clp is built without zlib support\
+ then the problems must be uncompressed.\
+ It is initialized to '../../Data/Netlib'"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("dirMiplib", "Set directory where the miplib 2003 problems are.",
+                        CBC_PARAM_ACTION_DIRMIPLIB, 7, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This sets the directory where the miplib 2003 problems reside. One can\
+ get the miplib problems from COIN-OR or from the main miplib site. This\
+ parameter is used only when -miplib is passed to cbc. cbc will pick up the\
+ miplib problems from this directory. If cbc is built without zlib support\
+ then the problems must be uncompressed.\
+ It is initialized to '../../Data/miplib3'"
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("diveO!pt", "Diving options",
+                        -1, 200000, CBC_PARAM_INT_DIVEOPT, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If >2 && <8 then modify diving options - \
+	 \n\t3 only at root and if no solution,  \
+	 \n\t4 only at root and if this heuristic has not got solution, \
+	 \n\t5 only at depth <4, \
+	 \n\t6 decay, \
+	 \n\t7 run up to 2 times if solution found 4 otherwise."
+     );
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("DivingS!ome", "Whether to try Diving heuristics",
+                        "off", CBC_PARAM_STR_DIVINGS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on a random diving heuristic at various times. \
+C - Coefficient, F - Fractional, G - Guided, L - LineSearch, P - PseudoCost, V - VectorLength. \
+You may prefer to use individual on/off \
+See Rounding for meaning of on,both,before"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("DivingC!oefficient", "Whether to try DiveCoefficient",
+                        "off", CBC_PARAM_STR_DIVINGC);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters++] =
+          CbcOrClpParam("DivingF!ractional", "Whether to try DiveFractional",
+                        "off", CBC_PARAM_STR_DIVINGF);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters++] =
+          CbcOrClpParam("DivingG!uided", "Whether to try DiveGuided",
+                        "off", CBC_PARAM_STR_DIVINGG);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters++] =
+          CbcOrClpParam("DivingL!ineSearch", "Whether to try DiveLineSearch",
+                        "off", CBC_PARAM_STR_DIVINGL);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters++] =
+          CbcOrClpParam("DivingP!seudoCost", "Whether to try DivePseudoCost",
+                        "off", CBC_PARAM_STR_DIVINGP);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters++] =
+          CbcOrClpParam("DivingV!ectorLength", "Whether to try DiveVectorLength",
+                        "off", CBC_PARAM_STR_DIVINGV);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters++] =
+          CbcOrClpParam("doH!euristic", "Do heuristics before any preprocessing",
+                        CBC_PARAM_ACTION_DOHEURISTIC, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Normally heuristics are done in branch and bound.  It may be useful to do them outside. \
+Only those heuristics with 'both' or 'before' set will run.  \
+Doing this may also set cutoff, which can help with preprocessing."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("dualB!ound", "Initially algorithm acts as if no \
+gap between bounds exceeds this value",
+                        1.0e-20, 1.0e12, CLP_PARAM_DBL_DUALBOUND);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The dual algorithm in Clp is a single phase algorithm as opposed to a two phase\
+ algorithm where you first get feasible then optimal.  If a problem has both upper and\
+ lower bounds then it is trivial to get dual feasible by setting non basic variables\
+ to correct bound.  If the gap between the upper and lower bounds of a variable is more\
+ than the value of dualBound Clp introduces fake bounds so that it can make the problem\
+ dual feasible.  This has the same effect as a composite objective function in the\
+ primal algorithm.  Too high a value may mean more iterations, while too low a bound means\
+ the code may go all the way and then have to increase the bounds.  OSL had a heuristic to\
+ adjust bounds, maybe we need that here."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("dualize", "Solves dual reformulation",
+                        0, 4, CLP_PARAM_INT_DUALIZE, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Don't even think about it."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("dualP!ivot", "Dual pivot choice algorithm",
+                        "auto!matic", CLP_PARAM_STR_DUALPIVOT, 7, 1);
+     parameters[numberParameters-1].append("dant!zig");
+     parameters[numberParameters-1].append("partial");
+     parameters[numberParameters-1].append("steep!est");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Clp can use any pivot selection algorithm which the user codes as long as it\
+ implements the features in the abstract pivot base class.  The Dantzig method is implemented\
+ to show a simple method but its use is deprecated.  Steepest is the method of choice and there\
+ are two variants which keep all weights updated but only scan a subset each iteration.\
+ Partial switches this on while automatic decides at each iteration based on information\
+ about the factorization."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("dualS!implex", "Do dual simplex algorithm",
+                        CLP_PARAM_ACTION_DUALSIMPLEX);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This command solves the continuous relaxation of the current model using the dual steepest edge algorithm.\
+The time and iterations may be affected by settings such as presolve, scaling, crash\
+ and also by dual pivot method, fake bound on variables and dual and primal tolerances."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("dualT!olerance", "For an optimal solution \
+no dual infeasibility may exceed this value",
+                        1.0e-20, 1.0e12, CLP_PARAM_DBL_DUALTOLERANCE);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Normally the default tolerance is fine, but you may want to increase it a\
+ bit if a dual run seems to be having a hard time.  One method which can be faster is \
+to use a large tolerance e.g. 1.0e-4 and dual and then clean up problem using primal and the \
+correct tolerance (remembering to switch off presolve for this final short clean up phase)."
+     );
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("either!Simplex", "Do dual or primal simplex algorithm",
+                        CLP_PARAM_ACTION_EITHERSIMPLEX);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This command solves the continuous relaxation of the current model using the dual or primal algorithm,\
+ based on a dubious analysis of model."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("end", "Stops clp execution",
+                        CLP_PARAM_ACTION_EXIT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This stops execution ; end, exit, quit and stop are synonyms"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("environ!ment", "Read commands from environment",
+                        CLP_PARAM_ACTION_ENVIRONMENT, 7, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This starts reading from environment variable CBC_CLP_ENVIRONMENT."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("error!sAllowed", "Whether to allow import errors",
+                        "off", CLP_PARAM_STR_ERRORSALLOWED, 3);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The default is not to use any model which had errors when reading the mps file.\
+  Setting this to 'on' will allow all errors from which the code can recover\
+ simply by ignoring the error.  There are some errors from which the code can not recover \
+e.g. no ENDATA.  This has to be set before import i.e. -errorsAllowed on -import xxxxxx.mps."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("exit", "Stops clp execution",
+                        CLP_PARAM_ACTION_EXIT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This stops the execution of Clp, end, exit, quit and stop are synonyms"
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("exper!iment", "Whether to use testing features",
+                        -1, 200, CBC_PARAM_INT_EXPERIMENT, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Defines how adventurous you want to be in using new ideas. \
+0 then no new ideas, 1 fairly sensible, 2 a bit dubious, 3 you are on your own!"
+     );
+     parameters[numberParameters-1].setIntValue(0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("expensive!Strong", "Whether to do even more strong branching",
+                        0, COIN_INT_MAX, CBC_PARAM_INT_STRONG_STRATEGY, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+      "Strategy for extra strong branching \n\
+\n\t0 - normal\n\
+\n\twhen to do all fractional\n\
+\n\t1 - root node\n\
+\n\t2 - depth less than modifier\n\
+\n\t4 - if objective == best possible\n\
+\n\t6 - as 2+4\n\
+\n\twhen to do all including satisfied\n\
+\n\t10 - root node etc.\n\
+\n\tIf >=100 then do when depth <= strategy/100 (otherwise 5)"
+     );
+     parameters[numberParameters-1].setIntValue(0);
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("export", "Export model as mps file",
+                        CLP_PARAM_ACTION_EXPORT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will write an MPS format file to the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to 'default.mps'.  \
+It can be useful to get rid of the original names and go over to using Rnnnnnnn and Cnnnnnnn.  This can be done by setting 'keepnames' off before importing mps file."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("extra1", "Extra integer parameter 1",
+                        -COIN_INT_MAX, COIN_INT_MAX, CBC_PARAM_INT_EXTRA1, 0);
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("extra2", "Extra integer parameter 2",
+                        -100, COIN_INT_MAX, CBC_PARAM_INT_EXTRA2, 0);
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("extra3", "Extra integer parameter 3",
+                        -1, COIN_INT_MAX, CBC_PARAM_INT_EXTRA3, 0);
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("extra4", "Extra integer parameter 4",
+                        -1, COIN_INT_MAX, CBC_PARAM_INT_EXTRA4, 0);
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on yet more special options!! \
+The bottom digit is a strategy when to used shadow price stuff e.g. 3 \
+means use until a solution is found.  The next two digits say what sort \
+of dual information to use.  After that it goes back to powers of 2 so -\n\
+\n\t1000 - switches on experimental hotstart\n\
+\n\t2,4,6000 - switches on experimental methods of stopping cuts\n\
+\n\t8000 - increase minimum drop gradually\n\
+\n\t16000 - switches on alternate gomory criterion"
+     );
+     parameters[numberParameters++] =
+       CbcOrClpParam("extraV!ariables", "Allow creation of extra integer variables",
+		     -COIN_INT_MAX, COIN_INT_MAX, CBC_PARAM_INT_EXTRA_VARIABLES, 0);
+     parameters[numberParameters-1].setIntValue(0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on creation of extra integer variables \
+to gather all variables with same cost."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("fact!orization", "Which factorization to use",
+                        "normal", CLP_PARAM_STR_FACTORIZATION);
+     parameters[numberParameters-1].append("dense");
+     parameters[numberParameters-1].append("simple");
+     parameters[numberParameters-1].append("osl");
+     parameters[numberParameters-1].setLonghelp
+     (
+#ifndef ABC_INHERIT
+          "The default is to use the normal CoinFactorization, but \
+other choices are a dense one, osl's or one designed for small problems."
+#else
+          "Normally the default is to use the normal CoinFactorization, but \
+other choices are a dense one, osl's or one designed for small problems. \
+However if at Aboca then the default is CoinAbcFactorization and other choices are \
+a dense one, one designed for small problems or if enabled a long factorization."
+#endif
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("fakeB!ound", "All bounds <= this value - DEBUG",
+                        1.0, 1.0e15, CLP_PARAM_ACTION_FAKEBOUND, 0);
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("feas!ibilityPump", "Whether to try Feasibility Pump",
+                        "off", CBC_PARAM_STR_FPUMP);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on feasibility pump heuristic at root. This is due to Fischetti, Lodi and Glover \
+and uses a sequence of Lps to try and get an integer feasible solution. \
+Some fine tuning is available by passFeasibilityPump and also pumpTune. \
+See Rounding for meaning of on,both,before"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("fix!OnDj", "Try heuristic based on fixing variables with \
+reduced costs greater than this",
+                        -1.0e20, 1.0e20, CBC_PARAM_DBL_DJFIX, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If this is set integer variables with reduced costs greater than this will be fixed \
+before branch and bound - use with extreme caution!"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("flow!CoverCuts", "Whether to use Flow Cover cuts",
+                        "off", CBC_PARAM_STR_FLOWCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("onglobal");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on flow cover cuts (either at root or in entire tree) \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("force!Solution", "Whether to use given solution as crash for BAB",
+                        -1, 20000000, CLP_PARAM_INT_USESOLUTION);
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "-1 off.  If 1 then tries to branch to solution given by AMPL or priorities file. \
+If 0 then just tries to set as best solution \
+If >1 then also does that many nodes on fixed problem."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("fraction!forBAB", "Fraction in feasibility pump",
+                        1.0e-5, 1.1, CBC_PARAM_DBL_SMALLBAB, 1);
+     parameters[numberParameters-1].setDoubleValue(0.5);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "After a pass in feasibility pump, variables which have not moved \
+about are fixed and if the preprocessed model is small enough a few nodes \
+of branch and bound are done on reduced problem.  Small problem has to be less than this fraction of original."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("gamma!(Delta)", "Whether to regularize barrier",
+                        "off", CLP_PARAM_STR_GAMMA, 7, 1);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("gamma");
+     parameters[numberParameters-1].append("delta");
+     parameters[numberParameters-1].append("onstrong");
+     parameters[numberParameters-1].append("gammastrong");
+     parameters[numberParameters-1].append("deltastrong");
+#endif
+#ifdef COIN_HAS_CBC
+      parameters[numberParameters++] =
+          CbcOrClpParam("GMI!Cuts", "Whether to use alternative Gomory cuts",
+                        "off", CBC_PARAM_STR_GMICUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("endonly");
+     parameters[numberParameters-1].append("long");
+     parameters[numberParameters-1].append("longroot");
+     parameters[numberParameters-1].append("longifmove");
+     parameters[numberParameters-1].append("forceLongOn");
+     parameters[numberParameters-1].append("longendonly");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on an alternative Gomory cut generator (either at root or in entire tree) \
+This version is by Giacomo Nannicini and may be more robust \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("GMI!Cuts", "Whether to use alternative Gomory cuts",
+                        "off", CBC_PARAM_STR_GMICUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("endonly");
+     parameters[numberParameters-1].append("long");
+     parameters[numberParameters-1].append("longroot");
+     parameters[numberParameters-1].append("longifmove");
+     parameters[numberParameters-1].append("forceLongOn");
+     parameters[numberParameters-1].append("longendonly");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on an alternative Gomory cut generator (either at root or in entire tree) \
+This version is by Giacomo Nannicini and may be more robust \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("gomory!Cuts", "Whether to use Gomory cuts",
+                        "off", CBC_PARAM_STR_GOMORYCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("onglobal");
+     parameters[numberParameters-1].append("forceandglobal");
+     parameters[numberParameters-1].append("forceLongOn");
+     parameters[numberParameters-1].append("long");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The original cuts - beware of imitations!  Having gone out of favor, they are now more \
+fashionable as LP solvers are more robust and they interact well with other cuts.  They will almost always \
+give cuts (although in this executable they are limited as to number of variables in cut).  \
+However the cuts may be dense so it is worth experimenting (Long allows any length). \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("greedy!Heuristic", "Whether to use a greedy heuristic",
+                        "off", CBC_PARAM_STR_GREEDY);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     //parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Switches on a greedy heuristic which will try and obtain a solution.  It may just fix a \
+percentage of variables and then try a small branch and cut run. \
+See Rounding for meaning of on,both,before"
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("gsolu!tion", "Puts glpk solution to file",
+                        CLP_PARAM_ACTION_GMPL_SOLUTION);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Will write a glpk solution file to the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to 'stdout' (this defaults to ordinary solution if stdout). \
+If problem created from gmpl model - will do any reports."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("heur!isticsOnOff", "Switches most heuristics on or off",
+                        "off", CBC_PARAM_STR_HEURISTICSTRATEGY);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This can be used to switch on or off all heuristics.  Then you can do \
+individual ones off or on.  CbcTreeLocal is not included as it dramatically \
+alters search."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("help", "Print out version, non-standard options and some help",
+                        CLP_PARAM_ACTION_HELP, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This prints out some help to get user started.  If you have printed this then \
+you should be past that stage:-)"
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("hOp!tions", "Heuristic options",
+                        -9999999, 9999999, CBC_PARAM_INT_HOPTIONS, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "1 says stop heuristic immediately allowable gap reached. \
+Others are for feasibility pump - \
+2 says do exact number of passes given, \
+4 only applies if initial cutoff given and says relax after 50 passes, \
+while 8 will adapt cutoff rhs after first solution if it looks as if code is stalling."
+     );
+     parameters[numberParameters-1].setIntValue(0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("hot!StartMaxIts", "Maximum iterations on hot start",
+                        0, COIN_INT_MAX, CBC_PARAM_INT_MAXHOTITS);
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("idiot!Crash", "Whether to try idiot crash",
+                        -1, 99999999, CLP_PARAM_INT_IDIOT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This is a type of 'crash' which works well on some homogeneous problems.\
+ It works best on problems with unit elements and rhs but will do something to any model.  It should only be\
+ used before primal.  It can be set to -1 when the code decides for itself whether to use it,\
+ 0 to switch off or n > 0 to do n passes."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("import", "Import model from mps file",
+                        CLP_PARAM_ACTION_IMPORT, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will read an MPS format file from the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to '', i.e. it must be set.  If you have libgz then it can read compressed\
+ files 'xxxxxxxx.gz' or 'xxxxxxxx.bz2'.  \
+If 'keepnames' is off, then names are dropped -> Rnnnnnnn and Cnnnnnnn."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("inc!rement", "A valid solution must be at least this \
+much better than last integer solution",
+                        -1.0e20, 1.0e20, CBC_PARAM_DBL_INCREMENT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Whenever a solution is found the bound on solutions is set to solution (in a minimization\
+sense) plus this.  If it is not set then the code will try and work one out e.g. if \
+all objective coefficients are multiples of 0.01 and only integer variables have entries in \
+objective then this can be set to 0.01.  Be careful if you set this negative!"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("inf!easibilityWeight", "Each integer infeasibility is expected \
+to cost this much",
+                        0.0, 1.0e20, CBC_PARAM_DBL_INFEASIBILITYWEIGHT, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "A primitive way of deciding which node to explore next.  Satisfying each integer infeasibility is \
+expected to cost this much."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("initialS!olve", "Solve to continuous",
+                        CLP_PARAM_ACTION_SOLVECONTINUOUS);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This just solves the problem to continuous - without adding any cuts"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("integerT!olerance", "For an optimal solution \
+no integer variable may be this away from an integer value",
+                        1.0e-20, 0.5, CBC_PARAM_DBL_INTEGERTOLERANCE);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Beware of setting this smaller than the primal tolerance."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("keepN!ames", "Whether to keep names from import",
+                        "on", CLP_PARAM_STR_KEEPNAMES);
+     parameters[numberParameters-1].append("off");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "It saves space to get rid of names so if you need to you can set this to off.  \
+This needs to be set before the import of model - so -keepnames off -import xxxxx.mps."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("KKT", "Whether to use KKT factorization",
+                        "off", CLP_PARAM_STR_KKT, 7, 1);
+     parameters[numberParameters-1].append("on");
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("knapsack!Cuts", "Whether to use Knapsack cuts",
+                        "off", CBC_PARAM_STR_KNAPSACKCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("onglobal");
+     parameters[numberParameters-1].append("forceandglobal");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on knapsack cuts (either at root or in entire tree) \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("lagomory!Cuts", "Whether to use Lagrangean Gomory cuts",
+                        "off", CBC_PARAM_STR_LAGOMORYCUTS);
+     parameters[numberParameters-1].append("endonlyroot");
+     parameters[numberParameters-1].append("endcleanroot");
+     parameters[numberParameters-1].append("endbothroot");
+     parameters[numberParameters-1].append("endonly");
+     parameters[numberParameters-1].append("endclean");
+     parameters[numberParameters-1].append("endboth");
+     parameters[numberParameters-1].append("onlyaswell");
+     parameters[numberParameters-1].append("cleanaswell");
+     parameters[numberParameters-1].append("bothaswell");
+     parameters[numberParameters-1].append("onlyinstead");
+     parameters[numberParameters-1].append("cleaninstead");
+     parameters[numberParameters-1].append("bothinstead");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This is a gross simplification of 'A Relax-and-Cut Framework for Gomory's Mixed-Integer Cuts' \
+by Matteo Fischetti & Domenico Salvagnin.  This simplification \
+just uses original constraints while modifying objective using other cuts. \
+So you don't use messy constraints generated by Gomory etc. \
+A variant is to allow non messy cuts e.g. clique cuts. \
+So 'only' does this while clean also allows integral valued cuts.  \
+'End' is recommended which waits until other cuts have finished and then \
+does a few passes. \
+The length options for gomory cuts are used."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("latwomir!Cuts", "Whether to use Lagrangean TwoMir cuts",
+                        "off", CBC_PARAM_STR_LATWOMIRCUTS);
+     parameters[numberParameters-1].append("endonlyroot");
+     parameters[numberParameters-1].append("endcleanroot");
+     parameters[numberParameters-1].append("endbothroot");
+     parameters[numberParameters-1].append("endonly");
+     parameters[numberParameters-1].append("endclean");
+     parameters[numberParameters-1].append("endboth");
+     parameters[numberParameters-1].append("onlyaswell");
+     parameters[numberParameters-1].append("cleanaswell");
+     parameters[numberParameters-1].append("bothaswell");
+     parameters[numberParameters-1].append("onlyinstead");
+     parameters[numberParameters-1].append("cleaninstead");
+     parameters[numberParameters-1].append("bothinstead");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This is a lagrangean relaxation for TwoMir cuts.  See \
+lagomoryCuts for description of options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("lift!AndProjectCuts", "Whether to use Lift and Project cuts",
+                        "off", CBC_PARAM_STR_LANDPCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Lift and project cuts. \
+May be slow \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("local!TreeSearch", "Whether to use local treesearch",
+                        "off", CBC_PARAM_STR_LOCALTREE);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on a local search algorithm when a solution is found.  This is from \
+Fischetti and Lodi and is not really a heuristic although it can be used as one. \
+When used from Coin solve it has limited functionality.  It is not switched on when \
+heuristics are switched on."
+     );
+#endif
+#ifndef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("log!Level", "Level of detail in Solver output",
+                        -1, 999999, CLP_PARAM_INT_SOLVERLOGLEVEL);
+#else
+     parameters[numberParameters++] =
+          CbcOrClpParam("log!Level", "Level of detail in Coin branch and Cut output",
+                        -63, 63, CLP_PARAM_INT_LOGLEVEL);
+     parameters[numberParameters-1].setIntValue(1);
+#endif
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If 0 then there should be no output in normal circumstances.  1 is probably the best\
+ value for most uses, while 2 and 3 give more information."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("max!imize", "Set optimization direction to maximize",
+                        CLP_PARAM_ACTION_MAXIMIZE, 7);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The default is minimize - use 'maximize' for maximization.\n\
+You can also use the parameters 'direction maximize'."
+     );
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("maxF!actor", "Maximum number of iterations between \
+refactorizations",
+                        1, 999999, CLP_PARAM_INT_MAXFACTOR);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If this is at its initial value of 200 then in this executable clp will guess at a\
+ value to use.  Otherwise the user can set a value.  The code may decide to re-factorize\
+ earlier for accuracy."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("maxIt!erations", "Maximum number of iterations before \
+stopping",
+                        0, 2147483647, CLP_PARAM_INT_MAXITERATION);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This can be used for testing purposes.  The corresponding library call\n\
+      \tsetMaximumIterations(value)\n can be useful.  If the code stops on\
+ seconds or by an interrupt this will be treated as stopping on maximum iterations.  This is ignored in branchAndCut - use maxN!odes."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("maxN!odes", "Maximum number of nodes to do",
+                        -1, 2147483647, CBC_PARAM_INT_MAXNODES);
+     parameters[numberParameters-1].setLonghelp 
+     (
+          "This is a repeatable way to limit search.  Normally using time is easier \
+but then the results may not be repeatable."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("maxSaved!Solutions", "Maximum number of solutions to save",
+                        0, 2147483647, CBC_PARAM_INT_MAXSAVEDSOLS);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Number of solutions to save."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("maxSo!lutions", "Maximum number of solutions to get",
+                        1, 2147483647, CBC_PARAM_INT_MAXSOLS);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "You may want to stop after (say) two solutions or an hour.  \
+This is checked every node in tree, so it is possible to get more solutions from heuristics."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("min!imize", "Set optimization direction to minimize",
+                        CLP_PARAM_ACTION_MINIMIZE, 7);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The default is minimize - use 'maximize' for maximization.\n\
+This should only be necessary if you have previously set maximization \
+You can also use the parameters 'direction minimize'."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("mipO!ptions", "Dubious options for mip",
+                        0, COIN_INT_MAX, CBC_PARAM_INT_MIPOPTIONS, 0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("more!MipOptions", "More dubious options for mip",
+                        -1, COIN_INT_MAX, CBC_PARAM_INT_MOREMIPOPTIONS, 0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("mixed!IntegerRoundingCuts", "Whether to use Mixed Integer Rounding cuts",
+                        "off", CBC_PARAM_STR_MIXEDCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("onglobal");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on mixed integer rounding cuts (either at root or in entire tree) \
+See branchAndCut for information on options."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("mess!ages", "Controls if Clpnnnn is printed",
+                        "off", CLP_PARAM_STR_MESSAGES);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     ("The default behavior is to put out messages such as:\n\
+   Clp0005 2261  Objective 109.024 Primal infeas 944413 (758)\n\
+but this program turns this off to make it look more friendly.  It can be useful\
+ to turn them back on if you want to be able to 'grep' for particular messages or if\
+ you intend to override the behavior of a particular message.  This only affects Clp not Cbc."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("miplib", "Do some of miplib test set",
+                        CBC_PARAM_ACTION_MIPLIB, 3, 1);
+#ifdef COIN_HAS_CBC
+      parameters[numberParameters++] =
+          CbcOrClpParam("mips!tart", "reads an initial feasible solution from file",
+                        CBC_PARAM_ACTION_MIPSTART);
+     parameters[numberParameters-1].setLonghelp
+     ("\
+The MIPStart allows one to enter an initial integer feasible solution \
+to CBC. Values of the main decision variables which are active (have \
+non-zero values) in this solution are specified in a text  file. The \
+text file format used is the same of the solutions saved by CBC, but \
+not all fields are required to be filled. First line may contain the \
+solution status and will be ignored, remaining lines contain column \
+indexes, names and values as in this example:\n\
+\n\
+Stopped on iterations - objective value 57597.00000000\n\
+      0  x(1,1,2,2)               1 \n\
+      1  x(3,1,3,2)               1 \n\
+      5  v(5,1)                   2 \n\
+      33 x(8,1,5,2)               1 \n\
+      ...\n\
+\n\
+Column indexes are also ignored since pre-processing can change them. \
+There is no need to include values for continuous or integer auxiliary \
+variables, since they can be computed based on main decision variables. \
+Starting CBC with an integer feasible solution can dramatically improve \
+its performance: several MIP heuristics (e.g. RINS) rely on having at \
+least one feasible solution available and can start immediately if the \
+user provides one. Feasibility Pump (FP) is a heuristic which tries to \
+overcome the problem of taking too long to find feasible solution (or \
+not finding at all), but it not always succeeds. If you provide one \
+starting solution you will probably save some time by disabling FP. \
+\n\n\
+Knowledge specific to your problem can be considered to write an \
+external module to quickly produce an initial feasible solution - some \
+alternatives are the implementation of simple greedy heuristics or the \
+solution (by CBC for example) of a simpler model created just to find \
+a feasible solution. \
+\n\n\
+Question and suggestions regarding MIPStart can be directed to\n\
+haroldo.santos@gmail.com.\
+");
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("moreS!pecialOptions", "Yet more dubious options for Simplex - see ClpSimplex.hpp",
+                        0, COIN_INT_MAX, CLP_PARAM_INT_MORESPECIALOPTIONS, 0);
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("moreT!une", "Yet more dubious ideas for feasibility pump",
+                        0, 100000000, CBC_PARAM_INT_FPUMPTUNE2, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Yet more ideas for Feasibility Pump \n\
+\t/100000 == 1 use box constraints and original obj in cleanup\n\
+\t/1000 == 1 Pump will run twice if no solution found\n\
+\t/1000 == 2 Pump will only run after root cuts if no solution found\n\
+\t/1000 >10 as above but even if solution found\n\
+\t/100 == 1,3.. exact 1.0 for objective values\n\
+\t/100 == 2,3.. allow more iterations per pass\n\
+\t n fix if value of variable same for last n iterations."
+     );
+     parameters[numberParameters-1].setIntValue(0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("multiple!RootPasses", "Do multiple root passes to collect cuts and solutions",
+                        0, 100000000, CBC_PARAM_INT_MULTIPLEROOTS, 0);
+     parameters[numberParameters-1].setIntValue(0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Do (in parallel if threads enabled) the root phase this number of times \
+ and collect all solutions and cuts generated.  The actual format is aabbcc \
+where aa is number of extra passes, if bb is non zero \
+then it is number of threads to use (otherwise uses threads setting) and \
+cc is number of times to do root phase.  Yet another one from the Italian idea factory \
+(This time - Andrea Lodi , Matteo Fischetti , Michele Monaci , Domenico Salvagnin , \
+and Andrea Tramontani). \
+The solvers do not interact with each other.  However if extra passes are specified \
+then cuts are collected and used in later passes - so there is interaction there." 
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("naive!Heuristics", "Whether to try some stupid heuristic",
+                        "off", CBC_PARAM_STR_NAIVE, 7, 1);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Really silly stuff e.g. fix all integers with costs to zero!. \
+Doh option does heuristic before preprocessing"     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("netlib", "Solve entire netlib test set",
+                        CLP_PARAM_ACTION_NETLIB_EITHER, 3, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This exercises the unit test for clp and then solves the netlib test set using dual or primal.\
+The user can set options before e.g. clp -presolve off -netlib"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("netlibB!arrier", "Solve entire netlib test set with barrier",
+                        CLP_PARAM_ACTION_NETLIB_BARRIER, 3, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This exercises the unit test for clp and then solves the netlib test set using barrier.\
+The user can set options before e.g. clp -kkt on -netlib"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("netlibD!ual", "Solve entire netlib test set (dual)",
+                        CLP_PARAM_ACTION_NETLIB_DUAL, 3, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This exercises the unit test for clp and then solves the netlib test set using dual.\
+The user can set options before e.g. clp -presolve off -netlib"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("netlibP!rimal", "Solve entire netlib test set (primal)",
+                        CLP_PARAM_ACTION_NETLIB_PRIMAL, 3, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This exercises the unit test for clp and then solves the netlib test set using primal.\
+The user can set options before e.g. clp -presolve off -netlibp"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("netlibT!une", "Solve entire netlib test set with 'best' algorithm",
+                        CLP_PARAM_ACTION_NETLIB_TUNE, 3, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This exercises the unit test for clp and then solves the netlib test set using whatever \
+works best.  I know this is cheating but it also stresses the code better by doing a \
+mixture of stuff.  The best algorithm was chosen on a Linux ThinkPad using native cholesky \
+with University of Florida ordering."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("network", "Tries to make network matrix",
+                        CLP_PARAM_ACTION_NETWORK, 7, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Clp will go faster if the matrix can be converted to a network.  The matrix\
+ operations may be a bit faster with more efficient storage, but the main advantage\
+ comes from using a network factorization.  It will probably not be as fast as a \
+specialized network code."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("nextB!estSolution", "Prints next best saved solution to file",
+                        CLP_PARAM_ACTION_NEXTBESTSOLUTION);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "To write best solution, just use solution.  This prints next best (if exists) \
+ and then deletes it. \
+ This will write a primitive solution file to the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to 'stdout'.  The amount of output can be varied using printi!ngOptions or printMask."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("node!Strategy", "What strategy to use to select nodes",
+                        "hybrid", CBC_PARAM_STR_NODESTRATEGY);
+     parameters[numberParameters-1].append("fewest");
+     parameters[numberParameters-1].append("depth");
+     parameters[numberParameters-1].append("upfewest");
+     parameters[numberParameters-1].append("downfewest");
+     parameters[numberParameters-1].append("updepth");
+     parameters[numberParameters-1].append("downdepth");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Normally before a solution the code will choose node with fewest infeasibilities. \
+You can choose depth as the criterion.  You can also say if up or down branch must \
+be done first (the up down choice will carry on after solution). \
+Default has now been changed to hybrid which is breadth first on small depth nodes then fewest."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("numberA!nalyze", "Number of analysis iterations",
+                        -COIN_INT_MAX, COIN_INT_MAX, CBC_PARAM_INT_NUMBERANALYZE, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This says how many iterations to spend at root node analyzing problem. \
+This is a first try and will hopefully become more sophisticated."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("objective!Scale", "Scale factor to apply to objective",
+                        -1.0e20, 1.0e20, CLP_PARAM_DBL_OBJSCALE, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If the objective function has some very large values, you may wish to scale them\
+ internally by this amount.  It can also be set by autoscale.  It is applied after scaling.  You are unlikely to need this."
+     );
+     parameters[numberParameters-1].setDoubleValue(1.0);
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("outDup!licates", "takes duplicate rows etc out of integer model",
+                        CLP_PARAM_ACTION_OUTDUPROWS, 7, 0);
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("output!Format", "Which output format to use",
+                        1, 6, CLP_PARAM_INT_OUTPUTFORMAT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Normally export will be done using normal representation for numbers and two values\
+ per line.  You may want to do just one per line (for grep or suchlike) and you may wish\
+ to save with absolute accuracy using a coded version of the IEEE value. A value of 2 is normal.\
+ otherwise odd values gives one value per line, even two.  Values 1,2 give normal format, 3,4\
+ gives greater precision, while 5,6 give IEEE values.  When used for exporting a basis 1 does not save \
+values, 2 saves values, 3 with greater accuracy and 4 in IEEE."
+     );
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("para!metrics", "Import data from file and do parametrics",
+                        CLP_PARAM_ACTION_PARAMETRICS, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will read a file with parametric data from the given file name \
+and then do parametrics.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to '', i.e. it must be set.  This can not read from compressed files. \
+File is in modified csv format - a line ROWS will be followed by rows data \
+while a line COLUMNS will be followed by column data.  The last line \
+should be ENDATA. The ROWS line must exist and is in the format \
+ROWS, inital theta, final theta, interval theta, n where n is 0 to get \
+CLPI0062 message at interval or at each change of theta \
+and 1 to get CLPI0063 message at each iteration.  If interval theta is 0.0 \
+or >= final theta then no interval reporting.  n may be missed out when it is \
+taken as 0.  If there is Row data then \
+there is a headings line with allowed headings - name, number, \
+lower(rhs change), upper(rhs change), rhs(change).  Either the lower and upper \
+fields should be given or the rhs field. \
+The optional COLUMNS line is followed by a headings line with allowed \
+headings - name, number, objective(change), lower(change), upper(change). \
+ Exactly one of name and number must be given for either section and \
+missing ones have value 0.0."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("passC!uts", "Number of cut passes at root node",
+                        -9999999, 9999999, CBC_PARAM_INT_CUTPASS);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The default is 100 passes if less than 500 columns, 100 passes (but \
+stop if drop small if less than 5000 columns, 20 otherwise"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("passF!easibilityPump", "How many passes in feasibility pump",
+                        0, 10000, CBC_PARAM_INT_FPUMPITS);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This fine tunes Feasibility Pump by doing more or fewer passes."
+     );
+     parameters[numberParameters-1].setIntValue(20);
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("passP!resolve", "How many passes in presolve",
+                        -200, 100, CLP_PARAM_INT_PRESOLVEPASS, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Normally Presolve does 5 passes but you may want to do less to make it\
+ more lightweight or do more if improvements are still being made.  As Presolve will return\
+ if nothing is being taken out, you should not normally need to use this fine tuning."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("passT!reeCuts", "Number of cut passes in tree",
+                        -9999999, 9999999, CBC_PARAM_INT_CUTPASSINTREE);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The default is one pass"
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("pertV!alue", "Method of perturbation",
+                        -5000, 102, CLP_PARAM_INT_PERTVALUE, 1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("perturb!ation", "Whether to perturb problem",
+                        "on", CLP_PARAM_STR_PERTURBATION);
+     parameters[numberParameters-1].append("off");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Perturbation helps to stop cycling, but Clp uses other measures for this.\
+  However large problems and especially ones with unit elements and unit rhs or costs\
+ benefit from perturbation.  Normally Clp tries to be intelligent, but you can switch this off.\
+  The Clp library has this off by default.  This program has it on by default."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("PFI", "Whether to use Product Form of Inverse in simplex",
+                        "off", CLP_PARAM_STR_PFI, 7, 0);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "By default clp uses Forrest-Tomlin L-U update.  If you are masochistic you can switch it off."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("pivotAndC!omplement", "Whether to try Pivot and Complement heuristic",
+                        "off", CBC_PARAM_STR_PIVOTANDCOMPLEMENT);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "stuff needed. \
+Doh option does heuristic before preprocessing"     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("pivotAndF!ix", "Whether to try Pivot and Fix heuristic",
+                        "off", CBC_PARAM_STR_PIVOTANDFIX);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "stuff needed. \
+Doh option does heuristic before preprocessing"     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("plus!Minus", "Tries to make +- 1 matrix",
+                        CLP_PARAM_ACTION_PLUSMINUS, 7, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Clp will go slightly faster if the matrix can be converted so that the elements are\
+ not stored and are known to be unit.  The main advantage is memory use.  Clp may automatically\
+ see if it can convert the problem so you should not need to use this."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("pO!ptions", "Dubious print options",
+                        0, COIN_INT_MAX, CLP_PARAM_INT_PRINTOPTIONS, 1);
+     parameters[numberParameters-1].setIntValue(0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If this is > 0 then presolve will give more information and branch and cut will give statistics"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("preO!pt", "Presolve options",
+                        0, COIN_INT_MAX, CLP_PARAM_INT_PRESOLVEOPTIONS, 0);
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("presolve", "Whether to presolve problem",
+                        "on", CLP_PARAM_STR_PRESOLVE);
+     parameters[numberParameters-1].append("off");
+     parameters[numberParameters-1].append("more");
+     parameters[numberParameters-1].append("file");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Presolve analyzes the model to find such things as redundant equations, equations\
+ which fix some variables, equations which can be transformed into bounds etc etc.  For the\
+ initial solve of any problem this is worth doing unless you know that it will have no effect.  \
+on will normally do 5 passes while using 'more' will do 10.  If the problem is very large you may need \
+to write the original to file using 'file'."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("preprocess", "Whether to use integer preprocessing",
+                        "off", CBC_PARAM_STR_PREPROCESS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("save");
+     parameters[numberParameters-1].append("equal");
+     parameters[numberParameters-1].append("sos");
+     parameters[numberParameters-1].append("trysos");
+     parameters[numberParameters-1].append("equalall");
+     parameters[numberParameters-1].append("strategy");
+     parameters[numberParameters-1].append("aggregate");
+     parameters[numberParameters-1].append("forcesos");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This tries to reduce size of model in a similar way to presolve and \
+it also tries to strengthen the model - this can be very useful and is worth trying. \
+ Save option saves on file presolved.mps.  equal will turn <= cliques into \
+==.  sos will create sos sets if all 0-1 in sets (well one extra is allowed) \
+and no overlaps.  trysos is same but allows any number extra.  equalall will turn all \
+valid inequalities into equalities with integer slacks.  strategy is as \
+on but uses CbcStrategy."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("preT!olerance", "Tolerance to use in presolve",
+                        1.0e-20, 1.0e12, CLP_PARAM_DBL_PRESOLVETOLERANCE);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The default is 1.0e-8 - you may wish to try 1.0e-7 if presolve says the problem is \
+infeasible and you have awkward numbers and you are sure the problem is really feasible."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("primalP!ivot", "Primal pivot choice algorithm",
+                        "auto!matic", CLP_PARAM_STR_PRIMALPIVOT, 7, 1);
+     parameters[numberParameters-1].append("exa!ct");
+     parameters[numberParameters-1].append("dant!zig");
+     parameters[numberParameters-1].append("part!ial");
+     parameters[numberParameters-1].append("steep!est");
+     parameters[numberParameters-1].append("change");
+     parameters[numberParameters-1].append("sprint");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Clp can use any pivot selection algorithm which the user codes as long as it\
+ implements the features in the abstract pivot base class.  The Dantzig method is implemented\
+ to show a simple method but its use is deprecated.  Exact devex is the method of choice and there\
+ are two variants which keep all weights updated but only scan a subset each iteration.\
+ Partial switches this on while change initially does dantzig until the factorization\
+ becomes denser.  This is still a work in progress."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("primalS!implex", "Do primal simplex algorithm",
+                        CLP_PARAM_ACTION_PRIMALSIMPLEX);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This command solves the continuous relaxation of the current model using the primal algorithm.\
+  The default is to use exact devex.\
+ The time and iterations may be affected by settings such as presolve, scaling, crash\
+ and also by column selection  method, infeasibility weight and dual and primal tolerances."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("primalT!olerance", "For an optimal solution \
+no primal infeasibility may exceed this value",
+                        1.0e-20, 1.0e12, CLP_PARAM_DBL_PRIMALTOLERANCE);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Normally the default tolerance is fine, but you may want to increase it a\
+ bit if a primal run seems to be having a hard time"
+     );
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("primalW!eight", "Initially algorithm acts as if it \
+costs this much to be infeasible",
+                        1.0e-20, 1.0e20, CLP_PARAM_DBL_PRIMALWEIGHT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "The primal algorithm in Clp is a single phase algorithm as opposed to a two phase\
+ algorithm where you first get feasible then optimal.  So Clp is minimizing this weight times\
+ the sum of primal infeasibilities plus the true objective function (in minimization sense).\
+  Too high a value may mean more iterations, while too low a bound means\
+ the code may go all the way and then have to increase the weight in order to get feasible.\
+  OSL had a heuristic to\
+ adjust bounds, maybe we need that here."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("printi!ngOptions", "Print options",
+                        "normal", CLP_PARAM_STR_INTPRINT, 3);
+     parameters[numberParameters-1].append("integer");
+     parameters[numberParameters-1].append("special");
+     parameters[numberParameters-1].append("rows");
+     parameters[numberParameters-1].append("all");
+     parameters[numberParameters-1].append("csv");
+     parameters[numberParameters-1].append("bound!ranging");
+     parameters[numberParameters-1].append("rhs!ranging");
+     parameters[numberParameters-1].append("objective!ranging");
+     parameters[numberParameters-1].append("stats");
+     parameters[numberParameters-1].append("boundsint");
+     parameters[numberParameters-1].append("boundsall");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This changes the amount and format of printing a solution:\nnormal - nonzero column variables \n\
+integer - nonzero integer column variables\n\
+special - in format suitable for OsiRowCutDebugger\n\
+rows - nonzero column variables and row activities\n\
+all - all column variables and row activities.\n\
+\nFor non-integer problems 'integer' and 'special' act like 'normal'.  \
+Also see printMask for controlling output."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("printM!ask", "Control printing of solution on a  mask",
+                        CLP_PARAM_ACTION_PRINTMASK, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If set then only those names which match mask are printed in a solution. \
+'?' matches any character and '*' matches any set of characters. \
+ The default is '' i.e. unset so all variables are printed. \
+This is only active if model has names."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("prio!rityIn", "Import priorities etc from file",
+                        CBC_PARAM_ACTION_PRIORITYIN, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will read a file with priorities from the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to '', i.e. it must be set.  This can not read from compressed files. \
+File is in csv format with allowed headings - name, number, priority, direction, up, down, solution.  Exactly one of\
+ name and number must be given."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("probing!Cuts", "Whether to use Probing cuts",
+                        "off", CBC_PARAM_STR_PROBINGCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("onglobal");
+     parameters[numberParameters-1].append("forceonglobal");
+     parameters[numberParameters-1].append("forceOnBut");
+     parameters[numberParameters-1].append("forceOnStrong");
+     parameters[numberParameters-1].append("forceOnButStrong");
+     parameters[numberParameters-1].append("strongRoot");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on probing cuts (either at root or in entire tree) \
+See branchAndCut for information on options. \
+but strong options do more probing"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("proximity!Search", "Whether to do proximity search heuristic",
+                        "off", CBC_PARAM_STR_PROXIMITY);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].append("10");
+     parameters[numberParameters-1].append("100");
+     parameters[numberParameters-1].append("300");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on a heuristic which looks for a solution close \
+to incumbent solution (Fischetti and Monaci). \
+See Rounding for meaning of on,both,before. \
+The ones at end have different maxNode settings (and are 'on'(on==30))."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("pumpC!utoff", "Fake cutoff for use in feasibility pump",
+                        -COIN_DBL_MAX, COIN_DBL_MAX, CBC_PARAM_DBL_FAKECUTOFF);
+     parameters[numberParameters-1].setDoubleValue(0.0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "0.0 off - otherwise add a constraint forcing objective below this value\
+ in feasibility pump"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("pumpI!ncrement", "Fake increment for use in feasibility pump",
+                        -COIN_DBL_MAX, COIN_DBL_MAX, CBC_PARAM_DBL_FAKEINCREMENT, 1);
+     parameters[numberParameters-1].setDoubleValue(0.0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "0.0 off - otherwise use as absolute increment to cutoff \
+when solution found in feasibility pump"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("pumpT!une", "Dubious ideas for feasibility pump",
+                        0, 100000000, CBC_PARAM_INT_FPUMPTUNE);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This fine tunes Feasibility Pump \n\
+\t>=10000000 use as objective weight switch\n\
+\t>=1000000 use as accumulate switch\n\
+\t>=1000 use index+1 as number of large loops\n\
+\t==100 use objvalue +0.05*fabs(objvalue) as cutoff OR fakeCutoff if set\n\
+\t%100 == 10,20 affects how each solve is done\n\
+\t1 == fix ints at bounds, 2 fix all integral ints, 3 and continuous at bounds. \
+If accumulate is on then after a major pass, variables which have not moved \
+are fixed and a small branch and bound is tried."
+     );
+     parameters[numberParameters-1].setIntValue(0);
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("quit", "Stops clp execution",
+                        CLP_PARAM_ACTION_EXIT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This stops the execution of Clp, end, exit, quit and stop are synonyms"
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("randomC!bcSeed", "Random seed for Cbc",
+                        -1, COIN_INT_MAX, CBC_PARAM_INT_RANDOMSEED);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This sets a random seed for Cbc \
+- 0 says use time of day, -1 is as now."
+     );
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("randomi!zedRounding", "Whether to try randomized rounding heuristic",
+                        "off", CBC_PARAM_STR_RANDROUND);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "stuff needed. \
+Doh option does heuristic before preprocessing"     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("randomS!eed", "Random seed for Clp",
+                        0, COIN_INT_MAX, CLP_PARAM_INT_RANDOMSEED);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This sets a random seed for Clp \
+- 0 says use time of day."
+     );
+     parameters[numberParameters-1].setIntValue(1234567);
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("ratio!Gap", "Stop when gap between best possible and \
+best less than this fraction of larger of two",
+                        0.0, 1.0e20, CBC_PARAM_DBL_GAPRATIO);
+     parameters[numberParameters-1].setDoubleValue(0.0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If the gap between best solution and best possible solution is less than this fraction \
+of the objective value at the root node then the search will terminate.  See 'allowableGap' for a \
+way of using absolute value rather than fraction."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("readS!tored", "Import stored cuts from file",
+                        CLP_PARAM_ACTION_STOREDFILE, 3, 0);
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("reallyO!bjectiveScale", "Scale factor to apply to objective in place",
+                        -1.0e20, 1.0e20, CLP_PARAM_DBL_OBJSCALE2, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "You can set this to -1.0 to test maximization or other to stress code"
+     );
+     parameters[numberParameters-1].setDoubleValue(1.0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("reallyS!cale", "Scales model in place",
+                        CLP_PARAM_ACTION_REALLY_SCALE, 7, 0);
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("reduce!AndSplitCuts", "Whether to use Reduce-and-Split cuts",
+                        "off", CBC_PARAM_STR_REDSPLITCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on reduce and split  cuts (either at root or in entire tree). \
+May be slow \
+See branchAndCut for information on options."
+     );
+      parameters[numberParameters++] =
+          CbcOrClpParam("reduce2!AndSplitCuts", "Whether to use Reduce-and-Split cuts - style 2",
+                        "off", CBC_PARAM_STR_REDSPLIT2CUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("longOn");
+     parameters[numberParameters-1].append("longRoot");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on reduce and split  cuts (either at root or in entire tree) \
+This version is by Giacomo Nannicini based on Francois Margot's version \
+Standard setting only uses rows in tableau <=256, long uses all \
+May be slow \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("reduce2!AndSplitCuts", "Whether to use Reduce-and-Split cuts - style 2",
+                        "off", CBC_PARAM_STR_REDSPLIT2CUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("longOn");
+     parameters[numberParameters-1].append("longRoot");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on reduce and split  cuts (either at root or in entire tree) \
+This version is by Giacomo Nannicini based on Francois Margot's version \
+Standard setting only uses rows in tableau <=256, long uses all \
+See branchAndCut for information on options."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("residual!CapacityCuts", "Whether to use Residual Capacity cuts",
+                        "off", CBC_PARAM_STR_RESIDCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Residual capacity cuts. \
+See branchAndCut for information on options."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("restore!Model", "Restore model from binary file",
+                        CLP_PARAM_ACTION_RESTORE, 7, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This reads data save by saveModel from the given file.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to 'default.prob'."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("reverse", "Reverses sign of objective",
+                        CLP_PARAM_ACTION_REVERSE, 7, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Useful for testing if maximization works correctly"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("rhs!Scale", "Scale factor to apply to rhs and bounds",
+                        -1.0e20, 1.0e20, CLP_PARAM_DBL_RHSSCALE, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If the rhs or bounds have some very large meaningful values, you may wish to scale them\
+ internally by this amount.  It can also be set by autoscale.  This should not be needed."
+     );
+     parameters[numberParameters-1].setDoubleValue(1.0);
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("Rens", "Whether to try Relaxation Enforced Neighborhood Search",
+                        "off", CBC_PARAM_STR_RENS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].append("200");
+     parameters[numberParameters-1].append("1000");
+     parameters[numberParameters-1].append("10000");
+     parameters[numberParameters-1].append("dj");
+     parameters[numberParameters-1].append("djbefore");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on Relaxation enforced neighborhood Search. \
+on just does 50 nodes \
+200 or 1000 does that many nodes. \
+Doh option does heuristic before preprocessing"     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("Rins", "Whether to try Relaxed Induced Neighborhood Search",
+                        "off", CBC_PARAM_STR_RINS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].append("often");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on Relaxed induced neighborhood Search. \
+Doh option does heuristic before preprocessing"     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("round!ingHeuristic", "Whether to use Rounding heuristic",
+                        "off", CBC_PARAM_STR_ROUNDING);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on a simple (but effective) rounding heuristic at each node of tree.  \
+On means do in solve i.e. after preprocessing, \
+Before means do if doHeuristics used, off otherwise, \
+and both means do if doHeuristics and in solve."
+     );
+
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("saveM!odel", "Save model to binary file",
+                        CLP_PARAM_ACTION_SAVE, 7, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will save the problem to the given file name for future use\
+ by restoreModel.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to 'default.prob'."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("saveS!olution", "saves solution to file",
+                        CLP_PARAM_ACTION_SAVESOL);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will write a binary solution file to the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to 'solution.file'.  To read the file use fread(int) twice to pick up number of rows \
+and columns, then fread(double) to pick up objective value, then pick up row activities, row duals, column \
+activities and reduced costs - see bottom of CbcOrClpParam.cpp for code that reads or writes file. \
+If name contains '_fix_read_' then does not write but reads and will fix all variables"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("scal!ing", "Whether to scale problem",
+                        "off", CLP_PARAM_STR_SCALING);
+     parameters[numberParameters-1].append("equi!librium");
+     parameters[numberParameters-1].append("geo!metric");
+     parameters[numberParameters-1].append("auto!matic");
+     parameters[numberParameters-1].append("dynamic");
+     parameters[numberParameters-1].append("rows!only");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Scaling can help in solving problems which might otherwise fail because of lack of\
+ accuracy.  It can also reduce the number of iterations.  It is not applied if the range\
+ of elements is small.  When unscaled it is possible that there may be small primal and/or\
+ infeasibilities."
+     );
+     parameters[numberParameters-1].setCurrentOption(3); // say auto
+#ifndef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("sec!onds", "Maximum seconds",
+                        -1.0, 1.0e12, CLP_PARAM_DBL_TIMELIMIT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "After this many seconds clp will act as if maximum iterations had been reached \
+(if value >=0)."
+     );
+#else
+     parameters[numberParameters++] =
+          CbcOrClpParam("sec!onds", "maximum seconds",
+                        -1.0, 1.0e12, CBC_PARAM_DBL_TIMELIMIT_BAB);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "After this many seconds coin solver will act as if maximum nodes had been reached."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("sleep", "for debug",
+                        CLP_PARAM_ACTION_DUMMY, 7, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If passed to solver fom ampl, then ampl will wait so that you can copy .nl file for debug."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("slow!cutpasses", "Maximum number of tries for slower cuts",
+                        -1, COIN_INT_MAX, CBC_PARAM_INT_MAX_SLOW_CUTS);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Some cut generators are fairly slow - this limits the number of times they are tried."
+     );
+     parameters[numberParameters-1].setIntValue(10);
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("slp!Value", "Number of slp passes before primal",
+                        -1, 50000, CLP_PARAM_INT_SLPVALUE, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If you are solving a quadratic problem using primal then it may be helpful to do some \
+sequential Lps to get a good approximate solution."
+     );
+#if CLP_MULTIPLE_FACTORIZATIONS > 0
+     parameters[numberParameters++] =
+          CbcOrClpParam("small!Factorization", "Whether to use small factorization",
+                        -1, 10000, CBC_PARAM_INT_SMALLFACT, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If processed problem <= this use small factorization"
+     );
+     parameters[numberParameters-1].setIntValue(-1);
+#endif
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("solu!tion", "Prints solution to file",
+                        CLP_PARAM_ACTION_SOLUTION);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This will write a primitive solution file to the given file name.  It will use the default\
+ directory given by 'directory'.  A name of '$' will use the previous value for the name.  This\
+ is initialized to 'stdout'.  The amount of output can be varied using printi!ngOptions or printMask."
+     );
+#ifdef COIN_HAS_CLP
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("solv!e", "Solve problem",
+                        CBC_PARAM_ACTION_BAB);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If there are no integer variables then this just solves LP.  If there are integer variables \
+this does branch and cut."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("sos!Options", "Whether to use SOS from AMPL",
+                        "off", CBC_PARAM_STR_SOS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setCurrentOption("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Normally if AMPL says there are SOS variables they should be used, but sometime sthey should\
+ be turned off - this does so."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("slog!Level", "Level of detail in (LP) Solver output",
+                        -1, 63, CLP_PARAM_INT_SOLVERLOGLEVEL);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If 0 then there should be no output in normal circumstances.  1 is probably the best\
+ value for most uses, while 2 and 3 give more information.  This parameter is only used inside MIP - for Clp use 'log'"
+     );
+#else
+     // allow solve as synonym for possible dual
+     parameters[numberParameters++] =
+       CbcOrClpParam("solv!e", "Solve problem using dual simplex (probably)",
+                        CLP_PARAM_ACTION_EITHERSIMPLEX);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Just so can use solve for clp as well as in cbc"
+     );
+#endif
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("spars!eFactor", "Whether factorization treated as sparse",
+                        "on", CLP_PARAM_STR_SPARSEFACTOR, 7, 0);
+     parameters[numberParameters-1].append("off");
+     parameters[numberParameters++] =
+          CbcOrClpParam("special!Options", "Dubious options for Simplex - see ClpSimplex.hpp",
+                        0, COIN_INT_MAX, CLP_PARAM_INT_SPECIALOPTIONS, 0);
+     parameters[numberParameters++] =
+          CbcOrClpParam("sprint!Crash", "Whether to try sprint crash",
+                        -1, 5000000, CLP_PARAM_INT_SPRINT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "For long and thin problems this program may solve a series of small problems\
+ created by taking a subset of the columns.  I introduced the idea as 'Sprint' after\
+ an LP code of that name of the 60's which tried the same tactic (not totally successfully).\
+  Cplex calls it 'sifting'.  -1 is automatic choice, 0 is off, n is number of passes"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("stat!istics", "Print some statistics",
+                        CLP_PARAM_ACTION_STATISTICS);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This command prints some statistics for the current model.\
+ If log level >1 then more is printed.\
+ These are for presolved model if presolve on (and unscaled)."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("stop", "Stops clp execution",
+                        CLP_PARAM_ACTION_EXIT);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This stops the execution of Clp, end, exit, quit and stop are synonyms"
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("strat!egy", "Switches on groups of features",
+                        0, 2, CBC_PARAM_INT_STRATEGY);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This turns on newer features. \
+Use 0 for easy problems, 1 is default, 2 is aggressive. \
+1 uses Gomory cuts using tolerance of 0.01 at root, \
+does a possible restart after 100 nodes if can fix many \
+and activates a diving and RINS heuristic and makes feasibility pump \
+more aggressive. \
+This does not apply to unit tests (where 'experiment' may have similar effects)."
+     );
+     parameters[numberParameters-1].setIntValue(1);
+#ifdef CBC_KEEP_DEPRECATED
+     parameters[numberParameters++] =
+          CbcOrClpParam("strengthen", "Create strengthened problem",
+                        CBC_PARAM_ACTION_STRENGTHEN, 3);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This creates a new problem by applying the root node cuts.  All tight constraints \
+will be in resulting problem"
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("strong!Branching", "Number of variables to look at in strong branching",
+                        0, COIN_INT_MAX, CBC_PARAM_INT_STRONGBRANCHING);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "In order to decide which variable to branch on, the code will choose up to this number \
+of unsatisfied variables to do mini up and down branches on.  Then the most effective one is chosen. \
+If a variable is branched on many times then the previous average up and down costs may be used - \
+see number before trust."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("subs!titution", "How long a column to substitute for in presolve",
+                        0, 10000, CLP_PARAM_INT_SUBSTITUTION, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Normally Presolve gets rid of 'free' variables when there are no more than 3 \
+ variables in column.  If you increase this the number of rows may decrease but number of \
+ elements may increase."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("testO!si", "Test OsiObject stuff",
+                        -1, COIN_INT_MAX, CBC_PARAM_INT_TESTOSI, 0);
+#endif
+#ifdef CBC_THREAD
+     parameters[numberParameters++] =
+          CbcOrClpParam("thread!s", "Number of threads to try and use",
+                        -100, 100000, CBC_PARAM_INT_THREADS, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "To use multiple threads, set threads to number wanted.  It may be better \
+to use one or two more than number of cpus available.  If 100+n then n threads and \
+search is repeatable (maybe be somewhat slower), \
+if 200+n use threads for root cuts, 400+n threads used in sub-trees."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("tighten!Factor", "Tighten bounds using this times largest \
+activity at continuous solution",
+                        1.0e-3, 1.0e20, CBC_PARAM_DBL_TIGHTENFACTOR, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This sleazy trick can help on some problems."
+     );
+#endif
+#ifdef COIN_HAS_CLP
+     parameters[numberParameters++] =
+          CbcOrClpParam("tightLP", "Poor person's preSolve for now",
+                        CLP_PARAM_ACTION_TIGHTEN, 7, 0);
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("timeM!ode", "Whether to use CPU or elapsed time",
+                        "cpu", CLP_PARAM_STR_TIME_MODE);
+     parameters[numberParameters-1].append("elapsed");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "cpu uses CPU time for stopping, while elapsed uses elapsed time. \
+(On Windows, elapsed time is always used)."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("trust!PseudoCosts", "Number of branches before we trust pseudocosts",
+                        -3, 2000000000, CBC_PARAM_INT_NUMBERBEFORE);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Using strong branching computes pseudo-costs.  After this many times for a variable we just \
+trust the pseudo costs and do not do any more strong branching."
+     );
+#endif
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("tune!PreProcess", "Dubious tuning parameters",
+                        0, 20000000, CLP_PARAM_INT_PROCESSTUNE, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "For making equality cliques this is minimumsize.  Also for adding \
+integer slacks.  May be used for more later \
+If <10000 that is what it does.  If <1000000 - numberPasses is (value/10000)-1 and tune is tune %10000. \
+If >= 1000000! - numberPasses is (value/1000000)-1 and tune is tune %1000000.  In this case if tune is now still >=10000 \
+numberPassesPerInnerLoop is changed from 10 to (tune-10000)-1 and tune becomes tune % 10000!!!!! - happy? - \
+so to keep normal limit on cliques of 5, do 3 major passes (include presolves) but only doing one tightening pass per major pass - \
+you would use 3010005 (I think)"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("two!MirCuts", "Whether to use Two phase Mixed Integer Rounding cuts",
+                        "off", CBC_PARAM_STR_TWOMIRCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("onglobal");
+     parameters[numberParameters-1].append("forceandglobal");
+     parameters[numberParameters-1].append("forceLongOn");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on two phase mixed integer rounding  cuts (either at root or in entire tree) \
+See branchAndCut for information on options."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("unitTest", "Do unit test",
+                        CLP_PARAM_ACTION_UNITTEST, 3, 1);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This exercises the unit test for clp"
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("userClp", "Hand coded Clp stuff",
+                        CLP_PARAM_ACTION_USERCLP, 0, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "There are times e.g. when using AMPL interface when you may wish to do something unusual.  \
+Look for USERCLP in main driver and modify sample code."
+     );
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("userCbc", "Hand coded Cbc stuff",
+                        CBC_PARAM_ACTION_USERCBC, 0, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "There are times e.g. when using AMPL interface when you may wish to do something unusual.  \
+Look for USERCBC in main driver and modify sample code. \
+It is possible you can get same effect by using example driver4.cpp."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("Vnd!VariableNeighborhoodSearch", "Whether to try Variable Neighborhood Search",
+                        "off", CBC_PARAM_STR_VND);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("both");
+     parameters[numberParameters-1].append("before");
+     parameters[numberParameters-1].append("intree");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on variable neighborhood Search. \
+Doh option does heuristic before preprocessing"     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("vector", "Whether to use vector? Form of matrix in simplex",
+                        "off", CLP_PARAM_STR_VECTOR, 7, 0);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If this is on ClpPackedMatrix uses extra column copy in odd format."
+     );
+     parameters[numberParameters++] =
+          CbcOrClpParam("verbose", "Switches on longer help on single ?",
+                        0, 31, CLP_PARAM_INT_VERBOSE, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "Set to 1 to get short help with ? list, 2 to get long help, 3 for both.  (add 4 to just get ampl ones)."
+     );
+     parameters[numberParameters-1].setIntValue(0);
+#ifdef COIN_HAS_CBC
+     parameters[numberParameters++] =
+          CbcOrClpParam("vub!heuristic", "Type of vub heuristic",
+                        -2, 20, CBC_PARAM_INT_VUBTRY, 0);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "If set will try and fix some integer variables"
+     );
+     parameters[numberParameters-1].setIntValue(-1);
+     parameters[numberParameters++] =
+          CbcOrClpParam("zero!HalfCuts", "Whether to use zero half cuts",
+                        "off", CBC_PARAM_STR_ZEROHALFCUTS);
+     parameters[numberParameters-1].append("on");
+     parameters[numberParameters-1].append("root");
+     parameters[numberParameters-1].append("ifmove");
+     parameters[numberParameters-1].append("forceOn");
+     parameters[numberParameters-1].append("onglobal");
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This switches on zero-half cuts (either at root or in entire tree) \
+See branchAndCut for information on options.  This implementation was written by \
+Alberto Caprara."
+     );
+#endif
+     parameters[numberParameters++] =
+          CbcOrClpParam("zeroT!olerance", "Kill all coefficients \
+whose absolute value is less than this value",
+                        1.0e-100, 1.0e-5, CLP_PARAM_DBL_ZEROTOLERANCE);
+     parameters[numberParameters-1].setLonghelp
+     (
+          "This applies to reading mps files (and also lp files \
+if KILL_ZERO_READLP defined)"
+     );
+     parameters[numberParameters-1].setDoubleValue(1.0e-20);
+     assert(numberParameters < CBCMAXPARAMETERS);
+}
+// Given a parameter type - returns its number in list
+int whichParam (CbcOrClpParameterType name,
+                int numberParameters, CbcOrClpParam *const parameters)
+{
+     int i;
+     for (i = 0; i < numberParameters; i++) {
+          if (parameters[i].type() == name)
+               break;
+     }
+     assert (i < numberParameters);
+     return i;
+}
+#ifdef COIN_HAS_CLP
+/* Restore a solution from file.
+   mode 0 normal, 1 swap rows and columns and primal and dual
+   if 2 set then also change signs
+*/
+void restoreSolution(ClpSimplex * lpSolver, std::string fileName, int mode)
+{
+     FILE * fp = fopen(fileName.c_str(), "rb");
+     if (fp) {
+          int numberRows = lpSolver->numberRows();
+          int numberColumns = lpSolver->numberColumns();
+          int numberRowsFile;
+          int numberColumnsFile;
+          double objectiveValue;
+          size_t nRead;
+          nRead = fread(&numberRowsFile, sizeof(int), 1, fp);
+          if (nRead != 1)
+               throw("Error in fread");
+          nRead = fread(&numberColumnsFile, sizeof(int), 1, fp);
+          if (nRead != 1)
+               throw("Error in fread");
+          nRead = fread(&objectiveValue, sizeof(double), 1, fp);
+          if (nRead != 1)
+               throw("Error in fread");
+          double * dualRowSolution = lpSolver->dualRowSolution();
+          double * primalRowSolution = lpSolver->primalRowSolution();
+          double * dualColumnSolution = lpSolver->dualColumnSolution();
+          double * primalColumnSolution = lpSolver->primalColumnSolution();
+          if (mode) {
+               // swap
+               int k = numberRows;
+               numberRows = numberColumns;
+               numberColumns = k;
+               double * temp;
+               temp = dualRowSolution;
+               dualRowSolution = primalColumnSolution;
+               primalColumnSolution = temp;
+               temp = dualColumnSolution;
+               dualColumnSolution = primalRowSolution;
+               primalRowSolution = temp;
+          }
+          if (numberRows > numberRowsFile || numberColumns > numberColumnsFile) {
+               std::cout << "Mismatch on rows and/or columns - giving up" << std::endl;
+          } else {
+               lpSolver->setObjectiveValue(objectiveValue);
+               if (numberRows == numberRowsFile && numberColumns == numberColumnsFile) {
+                    nRead = fread(primalRowSolution, sizeof(double), numberRows, fp);
+                    if (nRead != static_cast<size_t>(numberRows))
+                         throw("Error in fread");
+                    nRead = fread(dualRowSolution, sizeof(double), numberRows, fp);
+                    if (nRead != static_cast<size_t>(numberRows))
+                         throw("Error in fread");
+                    nRead = fread(primalColumnSolution, sizeof(double), numberColumns, fp);
+                    if (nRead != static_cast<size_t>(numberColumns))
+                         throw("Error in fread");
+                    nRead = fread(dualColumnSolution, sizeof(double), numberColumns, fp);
+                    if (nRead != static_cast<size_t>(numberColumns))
+                         throw("Error in fread");
+               } else {
+                    std::cout << "Mismatch on rows and/or columns - truncating" << std::endl;
+                    double * temp = new double [CoinMax(numberRowsFile, numberColumnsFile)];
+                    nRead = fread(temp, sizeof(double), numberRowsFile, fp);
+                    if (nRead != static_cast<size_t>(numberRowsFile))
+                         throw("Error in fread");
+                    CoinMemcpyN(temp, numberRows, primalRowSolution);
+                    nRead = fread(temp, sizeof(double), numberRowsFile, fp);
+                    if (nRead != static_cast<size_t>(numberRowsFile))
+                         throw("Error in fread");
+                    CoinMemcpyN(temp, numberRows, dualRowSolution);
+                    nRead = fread(temp, sizeof(double), numberColumnsFile, fp);
+                    if (nRead != static_cast<size_t>(numberColumnsFile))
+                         throw("Error in fread");
+                    CoinMemcpyN(temp, numberColumns, primalColumnSolution);
+                    nRead = fread(temp, sizeof(double), numberColumnsFile, fp);
+                    if (nRead != static_cast<size_t>(numberColumnsFile))
+                         throw("Error in fread");
+                    CoinMemcpyN(temp, numberColumns, dualColumnSolution);
+                    delete [] temp;
+			   }
+               if (mode == 3) {
+                    int i;
+                    for (i = 0; i < numberRows; i++) {
+                         primalRowSolution[i] = -primalRowSolution[i];
+                         dualRowSolution[i] = -dualRowSolution[i];
+                    }
+                    for (i = 0; i < numberColumns; i++) {
+                         primalColumnSolution[i] = -primalColumnSolution[i];
+                         dualColumnSolution[i] = -dualColumnSolution[i];
+                    }
+               }
+          }
+          fclose(fp);
+     } else {
+          std::cout << "Unable to open file " << fileName << std::endl;
+     }
+}
+// Dump a solution to file
+void saveSolution(const ClpSimplex * lpSolver, std::string fileName)
+{
+     if (strstr(fileName.c_str(), "_fix_read_")) {
+          FILE * fp = fopen(fileName.c_str(), "rb");
+          if (fp) {
+               ClpSimplex * solver = const_cast<ClpSimplex *>(lpSolver);
+               restoreSolution(solver, fileName, 0);
+               // fix all
+               int logLevel = solver->logLevel();
+               int iColumn;
+               int numberColumns = solver->numberColumns();
+               double * primalColumnSolution =
+                    solver->primalColumnSolution();
+               double * columnLower = solver->columnLower();
+               double * columnUpper = solver->columnUpper();
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    double value = primalColumnSolution[iColumn];
+                    if (value > columnUpper[iColumn]) {
+                         if (value > columnUpper[iColumn] + 1.0e-6 && logLevel > 1)
+                              printf("%d value of %g - bounds %g %g\n",
+                                     iColumn, value, columnLower[iColumn], columnUpper[iColumn]);
+                         value = columnUpper[iColumn];
+                    } else if (value < columnLower[iColumn]) {
+                         if (value < columnLower[iColumn] - 1.0e-6 && logLevel > 1)
+                              printf("%d value of %g - bounds %g %g\n",
+                                     iColumn, value, columnLower[iColumn], columnUpper[iColumn]);
+                         value = columnLower[iColumn];
+                    }
+                    columnLower[iColumn] = value;
+                    columnUpper[iColumn] = value;
+               }
+               return;
+          }
+     }
+     FILE * fp = fopen(fileName.c_str(), "wb");
+     if (fp) {
+          int numberRows = lpSolver->numberRows();
+          int numberColumns = lpSolver->numberColumns();
+          double objectiveValue = lpSolver->objectiveValue();
+          size_t nWrite;
+          nWrite = fwrite(&numberRows, sizeof(int), 1, fp);
+          if (nWrite != 1)
+               throw("Error in fwrite");
+          nWrite = fwrite(&numberColumns, sizeof(int), 1, fp);
+          if (nWrite != 1)
+               throw("Error in fwrite");
+          nWrite = fwrite(&objectiveValue, sizeof(double), 1, fp);
+          if (nWrite != 1)
+               throw("Error in fwrite");
+          double * dualRowSolution = lpSolver->dualRowSolution();
+          double * primalRowSolution = lpSolver->primalRowSolution();
+          nWrite = fwrite(primalRowSolution, sizeof(double), numberRows, fp);
+          if (nWrite != static_cast<size_t>(numberRows))
+               throw("Error in fwrite");
+          nWrite = fwrite(dualRowSolution, sizeof(double), numberRows, fp);
+          if (nWrite != static_cast<size_t>(numberRows))
+               throw("Error in fwrite");
+          double * dualColumnSolution = lpSolver->dualColumnSolution();
+          double * primalColumnSolution = lpSolver->primalColumnSolution();
+          nWrite = fwrite(primalColumnSolution, sizeof(double), numberColumns, fp);
+          if (nWrite != static_cast<size_t>(numberColumns))
+               throw("Error in fwrite");
+          nWrite = fwrite(dualColumnSolution, sizeof(double), numberColumns, fp);
+          if (nWrite != static_cast<size_t>(numberColumns))
+               throw("Error in fwrite");
+          fclose(fp);
+     } else {
+          std::cout << "Unable to open file " << fileName << std::endl;
+     }
+}
+#endif
diff --git a/cbits/coin/CbcOrClpParam.hpp b/cbits/coin/CbcOrClpParam.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcOrClpParam.hpp
@@ -0,0 +1,500 @@
+
+/* $Id: CbcOrClpParam.hpp 1928 2013-04-06 12:54:16Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifdef USE_CBCCONFIG
+# include "CbcConfig.h"
+#else
+# include "ClpConfig.h"
+#endif
+
+#ifndef CbcOrClpParam_H
+#define CbcOrClpParam_H
+/**
+   This has parameter handling stuff which can be shared between Cbc and Clp (and Dylp etc).
+
+   This (and .cpp) should be copied so that it is the same in Cbc/Test and Clp/Test.
+   I know this is not elegant but it seems simplest.
+
+   It uses COIN_HAS_CBC for parameters wanted by CBC
+   It uses COIN_HAS_CLP for parameters wanted by CLP (or CBC using CLP)
+   It could use COIN_HAS_DYLP for parameters wanted by DYLP
+   It could use COIN_HAS_DYLP_OR_CLP for parameters wanted by DYLP or CLP etc etc
+
+ */
+class OsiSolverInterface;
+class CbcModel;
+class ClpSimplex;
+/*! \brief Parameter codes
+
+  Parameter type ranges are allocated as follows
+  <ul>
+    <li>   1 -- 100	double parameters
+    <li> 101 -- 200	integer parameters
+    <li> 201 -- 250	string parameters
+    <li> 251 -- 300	cuts etc(string but broken out for clarity)
+    <li> 301 -- 400	`actions'
+  </ul>
+
+  `Actions' do not necessarily invoke an immediate action; it's just that they
+  don't fit neatly into the parameters array.
+
+  This coding scheme is in flux.
+*/
+
+enum CbcOrClpParameterType
+
+{
+     CBC_PARAM_GENERALQUERY = -100,
+     CBC_PARAM_FULLGENERALQUERY,
+
+     CLP_PARAM_DBL_PRIMALTOLERANCE = 1,
+     CLP_PARAM_DBL_DUALTOLERANCE,
+     CLP_PARAM_DBL_TIMELIMIT,
+     CLP_PARAM_DBL_DUALBOUND,
+     CLP_PARAM_DBL_PRIMALWEIGHT,
+     CLP_PARAM_DBL_OBJSCALE,
+     CLP_PARAM_DBL_RHSSCALE,
+     CLP_PARAM_DBL_ZEROTOLERANCE,
+
+     CBC_PARAM_DBL_INFEASIBILITYWEIGHT = 51,
+     CBC_PARAM_DBL_CUTOFF,
+     CBC_PARAM_DBL_INTEGERTOLERANCE,
+     CBC_PARAM_DBL_INCREMENT,
+     CBC_PARAM_DBL_ALLOWABLEGAP,
+     CBC_PARAM_DBL_TIMELIMIT_BAB,
+     CBC_PARAM_DBL_GAPRATIO,
+
+     CBC_PARAM_DBL_DJFIX = 81,
+     CBC_PARAM_DBL_TIGHTENFACTOR,
+     CLP_PARAM_DBL_PRESOLVETOLERANCE,
+     CLP_PARAM_DBL_OBJSCALE2,
+     CBC_PARAM_DBL_FAKEINCREMENT,
+     CBC_PARAM_DBL_FAKECUTOFF,
+     CBC_PARAM_DBL_ARTIFICIALCOST,
+     CBC_PARAM_DBL_DEXTRA3,
+     CBC_PARAM_DBL_SMALLBAB,
+     CBC_PARAM_DBL_DEXTRA4,
+     CBC_PARAM_DBL_DEXTRA5,
+
+     CLP_PARAM_INT_SOLVERLOGLEVEL = 101,
+#ifndef COIN_HAS_CBC
+     CLP_PARAM_INT_LOGLEVEL = 101,
+#endif
+     CLP_PARAM_INT_MAXFACTOR,
+     CLP_PARAM_INT_PERTVALUE,
+     CLP_PARAM_INT_MAXITERATION,
+     CLP_PARAM_INT_PRESOLVEPASS,
+     CLP_PARAM_INT_IDIOT,
+     CLP_PARAM_INT_SPRINT,
+     CLP_PARAM_INT_OUTPUTFORMAT,
+     CLP_PARAM_INT_SLPVALUE,
+     CLP_PARAM_INT_PRESOLVEOPTIONS,
+     CLP_PARAM_INT_PRINTOPTIONS,
+     CLP_PARAM_INT_SPECIALOPTIONS,
+     CLP_PARAM_INT_SUBSTITUTION,
+     CLP_PARAM_INT_DUALIZE,
+     CLP_PARAM_INT_VERBOSE,
+     CLP_PARAM_INT_CPP,
+     CLP_PARAM_INT_PROCESSTUNE,
+     CLP_PARAM_INT_USESOLUTION,
+     CLP_PARAM_INT_RANDOMSEED,
+     CLP_PARAM_INT_MORESPECIALOPTIONS,
+
+     CBC_PARAM_INT_STRONGBRANCHING = 151,
+     CBC_PARAM_INT_CUTDEPTH,
+     CBC_PARAM_INT_MAXNODES,
+     CBC_PARAM_INT_NUMBERBEFORE,
+     CBC_PARAM_INT_NUMBERANALYZE,
+     CBC_PARAM_INT_MIPOPTIONS,
+     CBC_PARAM_INT_MOREMIPOPTIONS,
+     CBC_PARAM_INT_MAXHOTITS,
+     CBC_PARAM_INT_FPUMPITS,
+     CBC_PARAM_INT_MAXSOLS,
+     CBC_PARAM_INT_FPUMPTUNE,
+     CBC_PARAM_INT_TESTOSI,
+     CBC_PARAM_INT_EXTRA1,
+     CBC_PARAM_INT_EXTRA2,
+     CBC_PARAM_INT_EXTRA3,
+     CBC_PARAM_INT_EXTRA4,
+     CBC_PARAM_INT_DEPTHMINIBAB,
+     CBC_PARAM_INT_CUTPASSINTREE,
+     CBC_PARAM_INT_THREADS,
+     CBC_PARAM_INT_CUTPASS,
+     CBC_PARAM_INT_VUBTRY,
+     CBC_PARAM_INT_DENSE,
+     CBC_PARAM_INT_EXPERIMENT,
+     CBC_PARAM_INT_DIVEOPT,
+     CBC_PARAM_INT_STRATEGY,
+     CBC_PARAM_INT_SMALLFACT,
+     CBC_PARAM_INT_HOPTIONS,
+     CBC_PARAM_INT_CUTLENGTH,
+     CBC_PARAM_INT_FPUMPTUNE2,
+#ifdef COIN_HAS_CBC
+     CLP_PARAM_INT_LOGLEVEL ,
+#endif
+     CBC_PARAM_INT_MAXSAVEDSOLS,
+     CBC_PARAM_INT_RANDOMSEED,
+     CBC_PARAM_INT_MULTIPLEROOTS,
+     CBC_PARAM_INT_STRONG_STRATEGY,
+     CBC_PARAM_INT_EXTRA_VARIABLES,
+     CBC_PARAM_INT_MAX_SLOW_CUTS,
+
+     CLP_PARAM_STR_DIRECTION = 201,
+     CLP_PARAM_STR_DUALPIVOT,
+     CLP_PARAM_STR_SCALING,
+     CLP_PARAM_STR_ERRORSALLOWED,
+     CLP_PARAM_STR_KEEPNAMES,
+     CLP_PARAM_STR_SPARSEFACTOR,
+     CLP_PARAM_STR_PRIMALPIVOT,
+     CLP_PARAM_STR_PRESOLVE,
+     CLP_PARAM_STR_CRASH,
+     CLP_PARAM_STR_BIASLU,
+     CLP_PARAM_STR_PERTURBATION,
+     CLP_PARAM_STR_MESSAGES,
+     CLP_PARAM_STR_AUTOSCALE,
+     CLP_PARAM_STR_CHOLESKY,
+     CLP_PARAM_STR_KKT,
+     CLP_PARAM_STR_BARRIERSCALE,
+     CLP_PARAM_STR_GAMMA,
+     CLP_PARAM_STR_CROSSOVER,
+     CLP_PARAM_STR_PFI,
+     CLP_PARAM_STR_INTPRINT,
+     CLP_PARAM_STR_VECTOR,
+     CLP_PARAM_STR_FACTORIZATION,
+     CLP_PARAM_STR_ALLCOMMANDS,
+     CLP_PARAM_STR_TIME_MODE,
+     CLP_PARAM_STR_ABCWANTED,
+
+     CBC_PARAM_STR_NODESTRATEGY = 251,
+     CBC_PARAM_STR_BRANCHSTRATEGY,
+     CBC_PARAM_STR_CUTSSTRATEGY,
+     CBC_PARAM_STR_HEURISTICSTRATEGY,
+     CBC_PARAM_STR_GOMORYCUTS,
+     CBC_PARAM_STR_PROBINGCUTS,
+     CBC_PARAM_STR_KNAPSACKCUTS,
+     CBC_PARAM_STR_REDSPLITCUTS,
+     CBC_PARAM_STR_ROUNDING,
+     CBC_PARAM_STR_SOLVER,
+     CBC_PARAM_STR_CLIQUECUTS,
+     CBC_PARAM_STR_COSTSTRATEGY,
+     CBC_PARAM_STR_FLOWCUTS,
+     CBC_PARAM_STR_MIXEDCUTS,
+     CBC_PARAM_STR_TWOMIRCUTS,
+     CBC_PARAM_STR_PREPROCESS,
+     CBC_PARAM_STR_FPUMP,
+     CBC_PARAM_STR_GREEDY,
+     CBC_PARAM_STR_COMBINE,
+     CBC_PARAM_STR_PROXIMITY,
+     CBC_PARAM_STR_LOCALTREE,
+     CBC_PARAM_STR_SOS,
+     CBC_PARAM_STR_LANDPCUTS,
+     CBC_PARAM_STR_RINS,
+     CBC_PARAM_STR_RESIDCUTS,
+     CBC_PARAM_STR_RENS,
+     CBC_PARAM_STR_DIVINGS,
+     CBC_PARAM_STR_DIVINGC,
+     CBC_PARAM_STR_DIVINGF,
+     CBC_PARAM_STR_DIVINGG,
+     CBC_PARAM_STR_DIVINGL,
+     CBC_PARAM_STR_DIVINGP,
+     CBC_PARAM_STR_DIVINGV,
+     CBC_PARAM_STR_DINS,
+     CBC_PARAM_STR_PIVOTANDFIX,
+     CBC_PARAM_STR_RANDROUND,
+     CBC_PARAM_STR_NAIVE,
+     CBC_PARAM_STR_ZEROHALFCUTS,
+     CBC_PARAM_STR_CPX,
+     CBC_PARAM_STR_CROSSOVER2,
+     CBC_PARAM_STR_PIVOTANDCOMPLEMENT,
+     CBC_PARAM_STR_VND,
+     CBC_PARAM_STR_LAGOMORYCUTS,
+     CBC_PARAM_STR_LATWOMIRCUTS,
+     CBC_PARAM_STR_REDSPLIT2CUTS,
+     CBC_PARAM_STR_GMICUTS,
+     CBC_PARAM_STR_CUTOFF_CONSTRAINT,
+
+     CLP_PARAM_ACTION_DIRECTORY = 301,
+     CLP_PARAM_ACTION_DIRSAMPLE,
+     CLP_PARAM_ACTION_DIRNETLIB,
+     CBC_PARAM_ACTION_DIRMIPLIB,
+     CLP_PARAM_ACTION_IMPORT,
+     CLP_PARAM_ACTION_EXPORT,
+     CLP_PARAM_ACTION_RESTORE,
+     CLP_PARAM_ACTION_SAVE,
+     CLP_PARAM_ACTION_DUALSIMPLEX,
+     CLP_PARAM_ACTION_PRIMALSIMPLEX,
+     CLP_PARAM_ACTION_EITHERSIMPLEX,
+     CLP_PARAM_ACTION_MAXIMIZE,
+     CLP_PARAM_ACTION_MINIMIZE,
+     CLP_PARAM_ACTION_EXIT,
+     CLP_PARAM_ACTION_STDIN,
+     CLP_PARAM_ACTION_UNITTEST,
+     CLP_PARAM_ACTION_NETLIB_EITHER,
+     CLP_PARAM_ACTION_NETLIB_DUAL,
+     CLP_PARAM_ACTION_NETLIB_PRIMAL,
+     CLP_PARAM_ACTION_SOLUTION,
+     CLP_PARAM_ACTION_SAVESOL,
+     CLP_PARAM_ACTION_TIGHTEN,
+     CLP_PARAM_ACTION_FAKEBOUND,
+     CLP_PARAM_ACTION_HELP,
+     CLP_PARAM_ACTION_PLUSMINUS,
+     CLP_PARAM_ACTION_NETWORK,
+     CLP_PARAM_ACTION_ALLSLACK,
+     CLP_PARAM_ACTION_REVERSE,
+     CLP_PARAM_ACTION_BARRIER,
+     CLP_PARAM_ACTION_NETLIB_BARRIER,
+     CLP_PARAM_ACTION_NETLIB_TUNE,
+     CLP_PARAM_ACTION_REALLY_SCALE,
+     CLP_PARAM_ACTION_BASISIN,
+     CLP_PARAM_ACTION_BASISOUT,
+     CLP_PARAM_ACTION_SOLVECONTINUOUS,
+     CLP_PARAM_ACTION_CLEARCUTS,
+     CLP_PARAM_ACTION_VERSION,
+     CLP_PARAM_ACTION_STATISTICS,
+     CLP_PARAM_ACTION_DEBUG,
+     CLP_PARAM_ACTION_DUMMY,
+     CLP_PARAM_ACTION_PRINTMASK,
+     CLP_PARAM_ACTION_OUTDUPROWS,
+     CLP_PARAM_ACTION_USERCLP,
+     CLP_PARAM_ACTION_MODELIN,
+     CLP_PARAM_ACTION_CSVSTATISTICS,
+     CLP_PARAM_ACTION_STOREDFILE,
+     CLP_PARAM_ACTION_ENVIRONMENT,
+     CLP_PARAM_ACTION_PARAMETRICS,
+     CLP_PARAM_ACTION_GMPL_SOLUTION,
+
+     CBC_PARAM_ACTION_BAB = 351,
+     CBC_PARAM_ACTION_MIPLIB,
+     CBC_PARAM_ACTION_STRENGTHEN,
+     CBC_PARAM_ACTION_PRIORITYIN,
+     CBC_PARAM_ACTION_MIPSTART,
+     CBC_PARAM_ACTION_USERCBC,
+     CBC_PARAM_ACTION_DOHEURISTIC,
+     CLP_PARAM_ACTION_NEXTBESTSOLUTION,
+
+     CBC_PARAM_NOTUSED_OSLSTUFF = 401,
+     CBC_PARAM_NOTUSED_CBCSTUFF,
+
+     CBC_PARAM_NOTUSED_INVALID = 1000
+} ;
+#include <vector>
+#include <string>
+
+/// Very simple class for setting parameters
+
+class CbcOrClpParam {
+public:
+     /**@name Constructor and destructor */
+     //@{
+     /// Constructors
+     CbcOrClpParam (  );
+     CbcOrClpParam (std::string name, std::string help,
+                    double lower, double upper, CbcOrClpParameterType type, int display = 2);
+     CbcOrClpParam (std::string name, std::string help,
+                    int lower, int upper, CbcOrClpParameterType type, int display = 2);
+     // Other strings will be added by insert
+     CbcOrClpParam (std::string name, std::string help, std::string firstValue,
+                    CbcOrClpParameterType type, int whereUsed = 7, int display = 2);
+     // Action
+     CbcOrClpParam (std::string name, std::string help,
+                    CbcOrClpParameterType type, int whereUsed = 7, int display = 2);
+     /// Copy constructor.
+     CbcOrClpParam(const CbcOrClpParam &);
+     /// Assignment operator. This copies the data
+     CbcOrClpParam & operator=(const CbcOrClpParam & rhs);
+     /// Destructor
+     ~CbcOrClpParam (  );
+     //@}
+
+     /**@name stuff */
+     //@{
+     /// Insert string (only valid for keywords)
+     void append(std::string keyWord);
+     /// Adds one help line
+     void addHelp(std::string keyWord);
+     /// Returns name
+     inline std::string  name(  ) const {
+          return name_;
+     }
+     /// Returns short help
+     inline std::string  shortHelp(  ) const {
+          return shortHelp_;
+     }
+     /// Sets a double parameter (nonzero code if error)
+     int setDoubleParameter(CbcModel & model, double value) ;
+     /// Sets double parameter and returns printable string and error code
+     const char * setDoubleParameterWithMessage ( CbcModel & model, double  value , int & returnCode);
+     /// Gets a double parameter
+     double doubleParameter(CbcModel & model) const;
+     /// Sets a int parameter (nonzero code if error)
+     int setIntParameter(CbcModel & model, int value) ;
+     /// Sets int parameter and returns printable string and error code
+     const char * setIntParameterWithMessage ( CbcModel & model, int value , int & returnCode);
+     /// Gets a int parameter
+     int intParameter(CbcModel & model) const;
+     /// Sets a double parameter (nonzero code if error)
+     int setDoubleParameter(ClpSimplex * model, double value) ;
+     /// Gets a double parameter
+     double doubleParameter(ClpSimplex * model) const;
+     /// Sets double parameter and returns printable string and error code
+     const char * setDoubleParameterWithMessage ( ClpSimplex * model, double  value , int & returnCode);
+     /// Sets a int parameter (nonzero code if error)
+     int setIntParameter(ClpSimplex * model, int value) ;
+     /// Sets int parameter and returns printable string and error code
+     const char * setIntParameterWithMessage ( ClpSimplex * model, int  value , int & returnCode);
+     /// Gets a int parameter
+     int intParameter(ClpSimplex * model) const;
+     /// Sets a double parameter (nonzero code if error)
+     int setDoubleParameter(OsiSolverInterface * model, double value) ;
+     /// Sets double parameter and returns printable string and error code
+     const char * setDoubleParameterWithMessage ( OsiSolverInterface * model, double  value , int & returnCode);
+     /// Gets a double parameter
+     double doubleParameter(OsiSolverInterface * model) const;
+     /// Sets a int parameter (nonzero code if error)
+     int setIntParameter(OsiSolverInterface * model, int value) ;
+     /// Sets int parameter and returns printable string and error code
+     const char * setIntParameterWithMessage ( OsiSolverInterface * model, int  value , int & returnCode);
+     /// Gets a int parameter
+     int intParameter(OsiSolverInterface * model) const;
+     /// Checks a double parameter (nonzero code if error)
+     int checkDoubleParameter(double value) const;
+     /// Returns name which could match
+     std::string matchName (  ) const;
+     /// Returns length of name for ptinting
+     int lengthMatchName (  ) const;
+     /// Returns parameter option which matches (-1 if none)
+     int parameterOption ( std::string check ) const;
+     /// Prints parameter options
+     void printOptions (  ) const;
+     /// Returns current parameter option
+     inline std::string currentOption (  ) const {
+          return definedKeyWords_[currentKeyWord_];
+     }
+     /// Sets current parameter option
+     void setCurrentOption ( int value , bool printIt = false);
+     /// Sets current parameter option and returns printable string
+     const char * setCurrentOptionWithMessage ( int value );
+     /// Sets current parameter option using string
+     void setCurrentOption (const std::string value );
+     /// Returns current parameter option position
+     inline int currentOptionAsInteger (  ) const {
+          return currentKeyWord_;
+     }
+     /// Sets int value
+     void setIntValue ( int value );
+     inline int intValue () const {
+          return intValue_;
+     }
+     /// Sets double value
+     void setDoubleValue ( double value );
+     inline double doubleValue () const {
+          return doubleValue_;
+     }
+     /// Sets string value
+     void setStringValue ( std::string value );
+     inline std::string stringValue () const {
+          return stringValue_;
+     }
+     /// Returns 1 if matches minimum, 2 if matches less, 0 if not matched
+     int matches (std::string input) const;
+     /// type
+     inline CbcOrClpParameterType type() const {
+          return type_;
+     }
+     /// whether to display
+     inline int displayThis() const {
+          return display_;
+     }
+     /// Set Long help
+     inline void setLonghelp(const std::string help) {
+          longHelp_ = help;
+     }
+     /// Print Long help
+     void printLongHelp() const;
+     /// Print action and string
+     void printString() const;
+     /** 7 if used everywhere,
+         1 - used by clp
+         2 - used by cbc
+         4 - used by ampl
+     */
+     inline int whereUsed() const {
+          return whereUsed_;
+     }
+
+private:
+     /// gutsOfConstructor
+     void gutsOfConstructor();
+     //@}
+////////////////// data //////////////////
+private:
+
+     /**@name data
+      We might as well throw all type data in - could derive?
+     */
+     //@{
+     // Type see CbcOrClpParameterType
+     CbcOrClpParameterType type_;
+     /// If double == okay
+     double lowerDoubleValue_;
+     double upperDoubleValue_;
+     /// If int == okay
+     int lowerIntValue_;
+     int upperIntValue_;
+     // Length of name
+     unsigned int lengthName_;
+     // Minimum match
+     unsigned int lengthMatch_;
+     /// set of valid strings
+     std::vector<std::string> definedKeyWords_;
+     /// Name
+     std::string name_;
+     /// Short help
+     std::string shortHelp_;
+     /// Long help
+     std::string longHelp_;
+     /// Action
+     CbcOrClpParameterType action_;
+     /// Current keyWord (if a keyword parameter)
+     int currentKeyWord_;
+     /// Display on ?
+     int display_;
+     /// Integer parameter - current value
+     int intValue_;
+     /// Double parameter - current value
+     double doubleValue_;
+     /// String parameter - current value
+     std::string stringValue_;
+     /** 7 if used everywhere,
+         1 - used by clp
+         2 - used by cbc
+         4 - used by ampl
+     */
+     int whereUsed_;
+     //@}
+};
+/// Simple read stuff
+std::string CoinReadNextField();
+
+std::string CoinReadGetCommand(int argc, const char *argv[]);
+std::string CoinReadGetString(int argc, const char *argv[]);
+// valid 0 - okay, 1 bad, 2 not there
+int CoinReadGetIntField(int argc, const char *argv[], int * valid);
+double CoinReadGetDoubleField(int argc, const char *argv[], int * valid);
+void CoinReadPrintit(const char * input);
+void setCbcOrClpPrinting(bool yesNo);
+#define CBCMAXPARAMETERS 250
+/*
+  Subroutine to establish the cbc parameter array. See the description of
+  class CbcOrClpParam for details. Pulled from C..Main() for clarity.
+*/
+void establishParams (int &numberParameters, CbcOrClpParam *const parameters);
+// Given a parameter type - returns its number in list
+int whichParam (CbcOrClpParameterType name,
+                int numberParameters, CbcOrClpParam *const parameters);
+// Dump a solution to file
+void saveSolution(const ClpSimplex * lpSolver, std::string fileName);
+#endif	/* CbcOrClpParam_H */
diff --git a/cbits/coin/CbcPartialNodeInfo.cpp b/cbits/coin/CbcPartialNodeInfo.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcPartialNodeInfo.cpp
@@ -0,0 +1,286 @@
+// $Id: CbcPartialNodeInfo.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/24/09 carved from CbcNode
+
+#include "CbcConfig.h"
+
+#include <string>
+//#define CBC_DEBUG 1
+//#define CHECK_CUT_COUNTS
+//#define CHECK_NODE
+//#define CBC_CHECK_BASIS
+#include <cassert>
+#include <cfloat>
+#define CUTS
+#include "CoinPragma.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiChooseVariable.hpp"
+#include "OsiAuxInfo.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinTime.hpp"
+#include "CbcModel.hpp"
+#include "CbcNode.hpp"
+#include "CbcStatistics.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "OsiCuts.hpp"
+#include "CbcCountRowCut.hpp"
+#include "CbcFeasibilityBase.hpp"
+#include "CbcMessage.hpp"
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#include "ClpSimplexOther.hpp"
+#endif
+using namespace std;
+#include "CglCutGenerator.hpp"
+
+// Default constructor
+CbcPartialNodeInfo::CbcPartialNodeInfo()
+
+        : CbcNodeInfo(),
+        basisDiff_(NULL),
+        variables_(NULL),
+        newBounds_(NULL),
+        numberChangedBounds_(0)
+
+{ /* this space intentionally left blank */ }
+
+// Constructor from current state
+CbcPartialNodeInfo::CbcPartialNodeInfo (CbcNodeInfo *parent, CbcNode *owner,
+                                        int numberChangedBounds,
+                                        const int *variables,
+                                        const double *boundChanges,
+                                        const CoinWarmStartDiff *basisDiff)
+        : CbcNodeInfo(parent, owner)
+{
+    basisDiff_ = basisDiff->clone() ;
+#ifdef CBC_CHECK_BASIS
+    std::cout << "Constructor (" << this << ") " << std::endl ;
+#endif
+
+    numberChangedBounds_ = numberChangedBounds;
+    size_t size = numberChangedBounds_ * (sizeof(double) + sizeof(int));
+    char * temp = new char [size];
+    newBounds_ = reinterpret_cast<double *> (temp);
+    variables_ = reinterpret_cast<int *> (newBounds_ + numberChangedBounds_);
+
+    int i ;
+    for (i = 0; i < numberChangedBounds_; i++) {
+        variables_[i] = variables[i];
+        newBounds_[i] = boundChanges[i];
+    }
+}
+
+CbcPartialNodeInfo::CbcPartialNodeInfo (const CbcPartialNodeInfo & rhs)
+
+        : CbcNodeInfo(rhs)
+
+{
+    basisDiff_ = rhs.basisDiff_->clone() ;
+
+#ifdef CBC_CHECK_BASIS
+    std::cout << "Copy constructor (" << this << ") from " << this << std::endl ;
+#endif
+    numberChangedBounds_ = rhs.numberChangedBounds_;
+    size_t size = numberChangedBounds_ * (sizeof(double) + sizeof(int));
+    char * temp = new char [size];
+    newBounds_ = reinterpret_cast<double *> (temp);
+    variables_ = reinterpret_cast<int *> (newBounds_ + numberChangedBounds_);
+
+    int i ;
+    for (i = 0; i < numberChangedBounds_; i++) {
+        variables_[i] = rhs.variables_[i];
+        newBounds_[i] = rhs.newBounds_[i];
+    }
+}
+
+CbcNodeInfo *
+CbcPartialNodeInfo::clone() const
+{
+    return (new CbcPartialNodeInfo(*this));
+}
+
+
+CbcPartialNodeInfo::~CbcPartialNodeInfo ()
+{
+    delete basisDiff_ ;
+    delete [] newBounds_;
+}
+
+
+/**
+   The basis supplied as a parameter is incrementally modified, and lower and
+   upper bounds on variables in the model are incrementally modified. Any
+   cuts associated with this node are added to the list in addCuts.
+*/
+
+void CbcPartialNodeInfo::applyToModel (CbcModel *model,
+                                       CoinWarmStartBasis *&basis,
+                                       CbcCountRowCut **addCuts,
+                                       int &currentNumberCuts) const
+
+{
+    OsiSolverInterface *solver = model->solver();
+    if ((active_&4) != 0) {
+        basis->applyDiff(basisDiff_) ;
+#ifdef CBC_CHECK_BASIS
+        std::cout << "Basis (after applying " << this << ") " << std::endl ;
+        basis->print() ;
+#endif
+    }
+
+    // branch - do bounds
+    int i;
+    if ((active_&1) != 0) {
+        for (i = 0; i < numberChangedBounds_; i++) {
+            int variable = variables_[i];
+            int k = variable & 0x3fffffff;
+            if ((variable&0x80000000) == 0) {
+                // lower bound changing
+	      //#define CBC_PRINT2
+#ifdef CBC_PRINT2
+                if (solver->getColLower()[k] != newBounds_[i])
+                    printf("lower change for column %d - from %g to %g\n", k, solver->getColLower()[k], newBounds_[i]);
+#endif
+#ifndef NDEBUG
+                if ((variable&0x40000000) == 0 && false) {
+                    double oldValue = solver->getColLower()[k];
+                    assert (newBounds_[i] > oldValue - 1.0e-8);
+                    if (newBounds_[i] < oldValue + 1.0e-8)
+                        printf("bad null lower change for column %d - bound %g\n", k, oldValue);
+                }
+#endif
+                solver->setColLower(k, newBounds_[i]);
+            } else {
+                // upper bound changing
+#ifdef CBC_PRINT2
+                if (solver->getColUpper()[k] != newBounds_[i])
+                    printf("upper change for column %d - from %g to %g\n", k, solver->getColUpper()[k], newBounds_[i]);
+#endif
+#ifndef NDEBUG
+                if ((variable&0x40000000) == 0 && false) {
+                    double oldValue = solver->getColUpper()[k];
+                    assert (newBounds_[i] < oldValue + 1.0e-8);
+                    if (newBounds_[i] > oldValue - 1.0e-8)
+                        printf("bad null upper change for column %d - bound %g\n", k, oldValue);
+                }
+#endif
+                solver->setColUpper(k, newBounds_[i]);
+            }
+        }
+    }
+    if ((active_&2) != 0) {
+        for (i = 0; i < numberCuts_; i++) {
+            addCuts[currentNumberCuts+i] = cuts_[i];
+            if (cuts_[i] && model->messageHandler()->logLevel() > 4) {
+                cuts_[i]->print();
+            }
+        }
+
+        currentNumberCuts += numberCuts_;
+    }
+    return ;
+}
+// Just apply bounds to one variable (1=>infeasible)
+int
+CbcPartialNodeInfo::applyBounds(int iColumn, double & lower, double & upper, int force)
+{
+    // branch - do bounds
+    int i;
+    int found = 0;
+    double newLower = -COIN_DBL_MAX;
+    double newUpper = COIN_DBL_MAX;
+    for (i = 0; i < numberChangedBounds_; i++) {
+        int variable = variables_[i];
+        int k = variable & 0x3fffffff;
+        if (k == iColumn) {
+            if ((variable&0x80000000) == 0) {
+                // lower bound changing
+                found |= 1;
+                newLower = CoinMax(newLower, newBounds_[i]);
+                if ((force&1) == 0) {
+                    if (lower > newBounds_[i])
+		      COIN_DETAIL_PRINT(printf("%d odd lower going from %g to %g\n", iColumn, lower, newBounds_[i]));
+                    lower = newBounds_[i];
+                } else {
+                    newBounds_[i] = lower;
+                    variables_[i] |= 0x40000000; // say can go odd way
+                }
+            } else {
+                // upper bound changing
+                found |= 2;
+                newUpper = CoinMin(newUpper, newBounds_[i]);
+                if ((force&2) == 0) {
+                    if (upper < newBounds_[i])
+		      COIN_DETAIL_PRINT(printf("%d odd upper going from %g to %g\n", iColumn, upper, newBounds_[i]));
+                    upper = newBounds_[i];
+                } else {
+                    newBounds_[i] = upper;
+                    variables_[i] |= 0x40000000; // say can go odd way
+                }
+            }
+        }
+    }
+    newLower = CoinMax(newLower, lower);
+    newUpper = CoinMin(newUpper, upper);
+    int nAdd = 0;
+    if ((force&2) != 0 && (found&2) == 0) {
+        // need to add new upper
+        nAdd++;
+    }
+    if ((force&1) != 0 && (found&1) == 0) {
+        // need to add new lower
+        nAdd++;
+    }
+    if (nAdd) {
+        size_t size = (numberChangedBounds_ + nAdd) * (sizeof(double) + sizeof(int));
+        char * temp = new char [size];
+        double * newBounds = reinterpret_cast<double *> (temp);
+        int * variables = reinterpret_cast<int *> (newBounds + numberChangedBounds_ + nAdd);
+
+        int i ;
+        for (i = 0; i < numberChangedBounds_; i++) {
+            variables[i] = variables_[i];
+            newBounds[i] = newBounds_[i];
+        }
+        delete [] newBounds_;
+        newBounds_ = newBounds;
+        variables_ = variables;
+        if ((force&2) != 0 && (found&2) == 0) {
+            // need to add new upper
+            int variable = iColumn | 0x80000000;
+            variables_[numberChangedBounds_] = variable;
+            newBounds_[numberChangedBounds_++] = newUpper;
+        }
+        if ((force&1) != 0 && (found&1) == 0) {
+            // need to add new lower
+            int variable = iColumn;
+            variables_[numberChangedBounds_] = variable;
+            newBounds_[numberChangedBounds_++] = newLower;
+        }
+    }
+
+    return (newUpper >= newLower) ? 0 : 1;
+}
+
+/* Builds up row basis backwards (until original model).
+   Returns NULL or previous one to apply .
+   Depends on Free being 0 and impossible for cuts
+*/
+
+CbcNodeInfo *
+CbcPartialNodeInfo::buildRowBasis(CoinWarmStartBasis & basis ) const
+
+{
+    basis.applyDiff(basisDiff_) ;
+
+    return parent_ ;
+}
+
diff --git a/cbits/coin/CbcPartialNodeInfo.hpp b/cbits/coin/CbcPartialNodeInfo.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcPartialNodeInfo.hpp
@@ -0,0 +1,110 @@
+// $Id: CbcPartialNodeInfo.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/24/09 carved from CbcNode
+
+#ifndef CbcPartialNodeInfo_H
+#define CbcPartialNodeInfo_H
+
+#include <string>
+#include <vector>
+
+#include "CoinWarmStartBasis.hpp"
+#include "CoinSearchTree.hpp"
+#include "CbcBranchBase.hpp"
+#include "CbcNodeInfo.hpp"
+
+class OsiSolverInterface;
+class OsiSolverBranch;
+
+class OsiCuts;
+class OsiRowCut;
+class OsiRowCutDebugger;
+class CoinWarmStartBasis;
+class CbcCountRowCut;
+class CbcModel;
+class CbcNode;
+class CbcSubProblem;
+class CbcGeneralBranchingObject;
+/** \brief Holds information for recreating a subproblem by incremental change
+	   from the parent.
+
+  A CbcPartialNodeInfo object contains changes to the bounds and basis, and
+  additional cuts, required to recreate a subproblem by modifying and
+  augmenting the parent subproblem.
+*/
+
+class CbcPartialNodeInfo : public CbcNodeInfo {
+
+public:
+
+    /** \brief Modify model according to information at node
+
+        The routine modifies the model according to bound and basis change
+        information at node and adds any cuts to the addCuts array.
+    */
+    virtual void applyToModel (CbcModel *model, CoinWarmStartBasis *&basis,
+                               CbcCountRowCut **addCuts,
+                               int &currentNumberCuts) const ;
+
+    /// Just apply bounds to one variable - force means overwrite by lower,upper (1=>infeasible)
+    virtual int applyBounds(int iColumn, double & lower, double & upper, int force) ;
+    /** Builds up row basis backwards (until original model).
+        Returns NULL or previous one to apply .
+        Depends on Free being 0 and impossible for cuts
+    */
+    virtual CbcNodeInfo * buildRowBasis(CoinWarmStartBasis & basis ) const ;
+    // Default Constructor
+    CbcPartialNodeInfo ();
+
+    // Constructor from current state
+    CbcPartialNodeInfo (CbcNodeInfo * parent, CbcNode * owner,
+                        int numberChangedBounds, const int * variables,
+                        const double * boundChanges,
+                        const CoinWarmStartDiff *basisDiff) ;
+
+    // Copy constructor
+    CbcPartialNodeInfo ( const CbcPartialNodeInfo &);
+
+    // Destructor
+    ~CbcPartialNodeInfo ();
+
+    /// Clone
+    virtual CbcNodeInfo * clone() const;
+    /// Basis diff information
+    inline const CoinWarmStartDiff *basisDiff() const {
+        return basisDiff_ ;
+    }
+    /// Which variable (top bit if upper bound changing)
+    inline const int * variables() const {
+        return variables_;
+    }
+    // New bound
+    inline const double * newBounds() const {
+        return newBounds_;
+    }
+    /// Number of bound changes
+    inline int numberChangedBounds() const {
+        return numberChangedBounds_;
+    }
+protected:
+    /* Data values */
+
+    /// Basis diff information
+    CoinWarmStartDiff *basisDiff_ ;
+    /// Which variable (top bit if upper bound changing)
+    int * variables_;
+    // New bound
+    double * newBounds_;
+    /// Number of bound changes
+    int numberChangedBounds_;
+private:
+
+    /// Illegal Assignment operator
+    CbcPartialNodeInfo & operator=(const CbcPartialNodeInfo& rhs);
+};
+
+#endif //CbcPartialNodeInfo_H
+
diff --git a/cbits/coin/CbcSOS.cpp b/cbits/coin/CbcSOS.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSOS.cpp
@@ -0,0 +1,1038 @@
+// $Id: CbcSOS.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/9/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcSOS.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+//##############################################################################
+
+// Default Constructor
+CbcSOS::CbcSOS ()
+        : CbcObject(),
+        members_(NULL),
+        weights_(NULL),
+        shadowEstimateDown_(1.0),
+        shadowEstimateUp_(1.0),
+        downDynamicPseudoRatio_(0.0),
+        upDynamicPseudoRatio_(0.0),
+        numberTimesDown_(0),
+        numberTimesUp_(0),
+        numberMembers_(0),
+        sosType_(-1),
+        integerValued_(false)
+{
+}
+
+// Useful constructor (which are indices)
+CbcSOS::CbcSOS (CbcModel * model,  int numberMembers,
+                const int * which, const double * weights, int identifier, int type)
+        : CbcObject(model),
+        shadowEstimateDown_(1.0),
+        shadowEstimateUp_(1.0),
+        downDynamicPseudoRatio_(0.0),
+        upDynamicPseudoRatio_(0.0),
+        numberTimesDown_(0),
+        numberTimesUp_(0),
+        numberMembers_(numberMembers),
+        sosType_(type)
+{
+    id_ = identifier;
+    integerValued_ = type == 1;
+    if (integerValued_) {
+        // check all members integer
+        OsiSolverInterface * solver = model->solver();
+        if (solver) {
+            for (int i = 0; i < numberMembers_; i++) {
+                if (!solver->isInteger(which[i]))
+                    integerValued_ = false;
+            }
+        } else {
+            // can't tell
+            integerValued_ = false;
+        }
+    }
+    if (numberMembers_) {
+        members_ = new int[numberMembers_];
+        weights_ = new double[numberMembers_];
+        memcpy(members_, which, numberMembers_*sizeof(int));
+        if (weights) {
+            memcpy(weights_, weights, numberMembers_*sizeof(double));
+        } else {
+            for (int i = 0; i < numberMembers_; i++)
+                weights_[i] = i;
+        }
+        // sort so weights increasing
+        CoinSort_2(weights_, weights_ + numberMembers_, members_);
+        /*
+          Force all weights to be distinct; note that the separation enforced here
+          (1.0e-10) is not sufficien to pass the test in infeasibility().
+        */
+
+        double last = -COIN_DBL_MAX;
+        int i;
+        for (i = 0; i < numberMembers_; i++) {
+            double possible = CoinMax(last + 1.0e-10, weights_[i]);
+            weights_[i] = possible;
+            last = possible;
+        }
+    } else {
+        members_ = NULL;
+        weights_ = NULL;
+    }
+    assert (sosType_ > 0 && sosType_ < 3);
+}
+
+// Copy constructor
+CbcSOS::CbcSOS ( const CbcSOS & rhs)
+        : CbcObject(rhs)
+{
+    shadowEstimateDown_ = rhs.shadowEstimateDown_;
+    shadowEstimateUp_ = rhs.shadowEstimateUp_;
+    downDynamicPseudoRatio_ = rhs.downDynamicPseudoRatio_;
+    upDynamicPseudoRatio_ = rhs.upDynamicPseudoRatio_;
+    numberTimesDown_ = rhs.numberTimesDown_;
+    numberTimesUp_ = rhs.numberTimesUp_;
+    numberMembers_ = rhs.numberMembers_;
+    sosType_ = rhs.sosType_;
+    integerValued_ = rhs.integerValued_;
+    if (numberMembers_) {
+        members_ = new int[numberMembers_];
+        weights_ = new double[numberMembers_];
+        memcpy(members_, rhs.members_, numberMembers_*sizeof(int));
+        memcpy(weights_, rhs.weights_, numberMembers_*sizeof(double));
+    } else {
+        members_ = NULL;
+        weights_ = NULL;
+    }
+}
+
+// Clone
+CbcObject *
+CbcSOS::clone() const
+{
+    return new CbcSOS(*this);
+}
+
+// Assignment operator
+CbcSOS &
+CbcSOS::operator=( const CbcSOS & rhs)
+{
+    if (this != &rhs) {
+        CbcObject::operator=(rhs);
+        delete [] members_;
+        delete [] weights_;
+        shadowEstimateDown_ = rhs.shadowEstimateDown_;
+        shadowEstimateUp_ = rhs.shadowEstimateUp_;
+        downDynamicPseudoRatio_ = rhs.downDynamicPseudoRatio_;
+        upDynamicPseudoRatio_ = rhs.upDynamicPseudoRatio_;
+        numberTimesDown_ = rhs.numberTimesDown_;
+        numberTimesUp_ = rhs.numberTimesUp_;
+        numberMembers_ = rhs.numberMembers_;
+        sosType_ = rhs.sosType_;
+        integerValued_ = rhs.integerValued_;
+        if (numberMembers_) {
+            members_ = new int[numberMembers_];
+            weights_ = new double[numberMembers_];
+            memcpy(members_, rhs.members_, numberMembers_*sizeof(int));
+            memcpy(weights_, rhs.weights_, numberMembers_*sizeof(double));
+        } else {
+            members_ = NULL;
+            weights_ = NULL;
+        }
+    }
+    return *this;
+}
+
+// Destructor
+CbcSOS::~CbcSOS ()
+{
+    delete [] members_;
+    delete [] weights_;
+}
+/*
+  Routine to calculate standard infeasibility of an SOS set and return a
+  preferred branching direction. This routine looks to have undergone
+  incomplete revision. There is vestigial code. preferredWay is unconditionally
+  set to 1. There used to be a comment `large is 0.5' but John removed it
+  at some point. Have to check to see if it no longer applies or if John
+  thought it provided too much information.
+*/
+double
+CbcSOS::infeasibility(const OsiBranchingInformation * info,
+                      int &preferredWay) const
+{
+    int j;
+    int firstNonZero = -1;
+    int lastNonZero = -1;
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    //const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    //double largestValue=0.0;
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double weight = 0.0;
+    double sum = 0.0;
+
+    // check bounds etc
+    double lastWeight = -1.0e100;
+    for (j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        /*
+          The value used here (1.0e-7) is larger than the value enforced in the
+          constructor.
+        */
+
+        if (lastWeight >= weights_[j] - 1.0e-7)
+            throw CoinError("Weights too close together in SOS", "infeasibility", "CbcSOS");
+        double value = CoinMax(0.0, solution[iColumn]);
+        sum += value;
+        /*
+          If we're not making assumptions about integrality, why check integerTolerance
+          here? Convenient tolerance? Why not just check against the upper bound?
+
+          The calculation of weight looks to be a relic --- in the end, the value isn't
+          used to calculate either the return value or preferredWay.
+        */
+        if (value > integerTolerance && upper[iColumn]) {
+            // Possibly due to scaling a fixed variable might slip through
+            if (value > upper[iColumn]) {
+                value = upper[iColumn];
+                // Could change to #ifdef CBC_DEBUG
+#ifndef NDEBUG
+                if (model_->messageHandler()->logLevel() > 2 &&
+		    value > upper[iColumn] + integerTolerance)
+                    printf("** Variable %d (%d) has value %g and upper bound of %g\n",
+                           iColumn, j, value, upper[iColumn]);
+#endif
+            }
+            weight += weights_[j] * value;
+            if (firstNonZero < 0)
+                firstNonZero = j;
+            lastNonZero = j;
+        }
+    }
+	/* ?? */
+    preferredWay = 1;
+/*
+  SOS1 allows one nonzero; SOS2 allows two consecutive nonzeros. Infeasibility
+  is calculated as (.5)(range of nonzero values)/(number of members). So if
+  the first and last elements of the set are nonzero, we have maximum
+  infeasibility.
+*/
+    if (lastNonZero - firstNonZero >= sosType_) {
+        // find where to branch
+        assert (sum > 0.0);
+        weight /= sum;
+        if (info->defaultDual_ >= 0.0 && info->usefulRegion_ && info->columnStart_) {
+            assert (sosType_ == 1);
+            int iWhere;
+            for (iWhere = firstNonZero; iWhere < lastNonZero - 1; iWhere++) {
+                if (weight < weights_[iWhere+1]) {
+                    break;
+                }
+            }
+            int jColumnDown = members_[iWhere];
+            int jColumnUp = members_[iWhere+1];
+            int n = 0;
+            CoinBigIndex j;
+            double objMove = info->objective_[jColumnDown];
+            for (j = info->columnStart_[jColumnDown];
+                    j < info->columnStart_[jColumnDown] + info->columnLength_[jColumnDown]; j++) {
+                double value = info->elementByColumn_[j];
+                int iRow = info->row_[j];
+                info->indexRegion_[n++] = iRow;
+                info->usefulRegion_[iRow] = value;
+            }
+            for (iWhere = firstNonZero; iWhere < lastNonZero; iWhere++) {
+                int jColumn = members_[iWhere];
+                double solValue = info->solution_[jColumn];
+                if (!solValue)
+                    continue;
+                objMove -= info->objective_[jColumn] * solValue;
+                for (j = info->columnStart_[jColumn];
+                        j < info->columnStart_[jColumn] + info->columnLength_[jColumn]; j++) {
+                    double value = -info->elementByColumn_[j] * solValue;
+                    int iRow = info->row_[j];
+                    double oldValue = info->usefulRegion_[iRow];
+                    if (!oldValue) {
+                        info->indexRegion_[n++] = iRow;
+                    } else {
+                        value += oldValue;
+                        if (!value)
+                            value = 1.0e-100;
+                    }
+                    info->usefulRegion_[iRow] = value;
+                }
+            }
+            const double * pi = info->pi_;
+            const double * activity = info->rowActivity_;
+            const double * lower = info->rowLower_;
+            const double * upper = info->rowUpper_;
+            double tolerance = info->primalTolerance_;
+            double direction = info->direction_;
+            shadowEstimateDown_ = objMove * direction;
+            bool infeasible = false;
+            for (int k = 0; k < n; k++) {
+                int iRow = info->indexRegion_[k];
+                double movement = info->usefulRegion_[iRow];
+                // not this time info->usefulRegion_[iRow]=0.0;
+#if 0
+                if (lower[iRow] < -1.0e20) {
+		  if (pi[iRow] > 1.0e-3) {
+		    printf("Bad pi on row %d of %g\n",iRow,pi[iRow]);
+		  }
+		}
+                if (upper[iRow] >1.0e20) {
+		  if (pi[iRow] < -1.0e-3) {
+		    printf("Bad pi on row %d of %g\n",iRow,pi[iRow]);
+		  }
+		}
+#endif
+                double valueP = pi[iRow] * direction;
+                // if move makes infeasible then make at least default
+                double newValue = activity[iRow] + movement;
+                if (newValue > upper[iRow] + tolerance || newValue < lower[iRow] - tolerance) {
+                    shadowEstimateDown_ += fabs(movement) * CoinMax(fabs(valueP), info->defaultDual_);
+                    infeasible = true;
+                }
+            }
+            if (shadowEstimateDown_ < info->integerTolerance_) {
+                if (!infeasible) {
+                    shadowEstimateDown_ = 1.0e-10;
+#ifdef COIN_DEVELOP
+                    printf("zero pseudoShadowPrice\n");
+#endif
+                } else
+                    shadowEstimateDown_ = info->integerTolerance_;
+            }
+            // And other way
+            // take off
+            objMove -= info->objective_[jColumnDown];
+            for (j = info->columnStart_[jColumnDown];
+                    j < info->columnStart_[jColumnDown] + info->columnLength_[jColumnDown]; j++) {
+                double value = -info->elementByColumn_[j];
+                int iRow = info->row_[j];
+                double oldValue = info->usefulRegion_[iRow];
+                if (!oldValue) {
+                    info->indexRegion_[n++] = iRow;
+                } else {
+                    value += oldValue;
+                    if (!value)
+                        value = 1.0e-100;
+                }
+                info->usefulRegion_[iRow] = value;
+            }
+            // add on
+            objMove += info->objective_[jColumnUp];
+            for (j = info->columnStart_[jColumnUp];
+                    j < info->columnStart_[jColumnUp] + info->columnLength_[jColumnUp]; j++) {
+                double value = info->elementByColumn_[j];
+                int iRow = info->row_[j];
+                double oldValue = info->usefulRegion_[iRow];
+                if (!oldValue) {
+                    info->indexRegion_[n++] = iRow;
+                } else {
+                    value += oldValue;
+                    if (!value)
+                        value = 1.0e-100;
+                }
+                info->usefulRegion_[iRow] = value;
+            }
+            shadowEstimateUp_ = objMove * direction;
+            infeasible = false;
+            for (int k = 0; k < n; k++) {
+                int iRow = info->indexRegion_[k];
+                double movement = info->usefulRegion_[iRow];
+                info->usefulRegion_[iRow] = 0.0;
+#if 0
+                if (lower[iRow] < -1.0e20) {
+		  if (pi[iRow] > 1.0e-3) {
+		    printf("Bad pi on row %d of %g\n",iRow,pi[iRow]);
+		  }
+		}
+                if (upper[iRow] >1.0e20) {
+		  if (pi[iRow] < -1.0e-3) {
+		    printf("Bad pi on row %d of %g\n",iRow,pi[iRow]);
+		  }
+		}
+#endif
+                double valueP = pi[iRow] * direction;
+                // if move makes infeasible then make at least default
+                double newValue = activity[iRow] + movement;
+                if (newValue > upper[iRow] + tolerance || newValue < lower[iRow] - tolerance) {
+                    shadowEstimateUp_ += fabs(movement) * CoinMax(fabs(valueP), info->defaultDual_);
+                    infeasible = true;
+                }
+            }
+            if (shadowEstimateUp_ < info->integerTolerance_) {
+                if (!infeasible) {
+                    shadowEstimateUp_ = 1.0e-10;
+#ifdef COIN_DEVELOP
+                    printf("zero pseudoShadowPrice\n");
+#endif
+                } else
+                    shadowEstimateUp_ = info->integerTolerance_;
+            }
+            // adjust
+            double downCost = shadowEstimateDown_;
+            double upCost = shadowEstimateUp_;
+            if (numberTimesDown_)
+                downCost *= downDynamicPseudoRatio_ /
+                            static_cast<double> (numberTimesDown_);
+            if (numberTimesUp_)
+                upCost *= upDynamicPseudoRatio_ /
+                          static_cast<double> (numberTimesUp_);
+#define WEIGHT_AFTER 0.7
+#define WEIGHT_BEFORE 0.1
+            int stateOfSearch = model_->stateOfSearch() % 10;
+            double returnValue = 0.0;
+            double minValue = CoinMin(downCost, upCost);
+            double maxValue = CoinMax(downCost, upCost);
+            if (stateOfSearch <= 2) {
+                // no branching solution
+                returnValue = WEIGHT_BEFORE * minValue + (1.0 - WEIGHT_BEFORE) * maxValue;
+            } else {
+                returnValue = WEIGHT_AFTER * minValue + (1.0 - WEIGHT_AFTER) * maxValue;
+            }
+#ifdef PRINT_SHADOW
+            printf("%d id - down %d %g up %d %g shadow %g, %g returned %g\n",
+                   id_, numberTimesDown_, downDynamicPseudoRatio_,
+                   numberTimesUp_, upDynamicPseudoRatio_, shadowEstimateDown_,
+                   shadowEstimateUp_, returnValue);
+#endif
+            return returnValue;
+        } else {
+            double value = lastNonZero - firstNonZero + 1;
+            value *= 0.5 / static_cast<double> (numberMembers_);
+            return value;
+        }
+    } else {
+        return 0.0; // satisfied
+    }
+}
+
+// This looks at solution and sets bounds to contain solution
+void
+CbcSOS::feasibleRegion()
+{
+    int j;
+    int firstNonZero = -1;
+    int lastNonZero = -1;
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    //const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double weight = 0.0;
+    double sum = 0.0;
+
+    for (j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        double value = CoinMax(0.0, solution[iColumn]);
+        sum += value;
+        if (value > integerTolerance && upper[iColumn]) {
+            weight += weights_[j] * value;
+            if (firstNonZero < 0)
+                firstNonZero = j;
+            lastNonZero = j;
+        }
+    }
+    assert (lastNonZero - firstNonZero < sosType_) ;
+    for (j = 0; j < firstNonZero; j++) {
+        int iColumn = members_[j];
+        solver->setColUpper(iColumn, 0.0);
+    }
+    for (j = lastNonZero + 1; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        solver->setColUpper(iColumn, 0.0);
+    }
+}
+// Redoes data when sequence numbers change
+void
+CbcSOS::redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns)
+{
+    model_ = model;
+    int n2 = 0;
+    for (int j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        int i;
+        for (i = 0; i < numberColumns; i++) {
+            if (originalColumns[i] == iColumn)
+                break;
+        }
+        if (i < numberColumns) {
+            members_[n2] = i;
+            weights_[n2++] = weights_[j];
+        }
+    }
+    if (n2 < numberMembers_) {
+      COIN_DETAIL_PRINT(printf("** SOS number of members reduced from %d to %d!\n",numberMembers_,n2));
+        numberMembers_ = n2;
+    }
+}
+CbcBranchingObject *
+CbcSOS::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int way)
+{
+    int j;
+    const double * solution = model_->testSolution();
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    //OsiSolverInterface * solver = model_->solver();
+    const double * upper = solver->getColUpper();
+    int firstNonFixed = -1;
+    int lastNonFixed = -1;
+    int firstNonZero = -1;
+    int lastNonZero = -1;
+    double weight = 0.0;
+    double sum = 0.0;
+    for (j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        if (upper[iColumn]) {
+            double value = CoinMax(0.0, solution[iColumn]);
+            sum += value;
+            if (firstNonFixed < 0)
+                firstNonFixed = j;
+            lastNonFixed = j;
+            if (value > integerTolerance) {
+                weight += weights_[j] * value;
+                if (firstNonZero < 0)
+                    firstNonZero = j;
+                lastNonZero = j;
+            }
+        }
+    }
+    assert (lastNonZero - firstNonZero >= sosType_) ;
+    // find where to branch
+    assert (sum > 0.0);
+    weight /= sum;
+    int iWhere;
+    double separator = 0.0;
+    for (iWhere = firstNonZero; iWhere < lastNonZero; iWhere++)
+        if (weight < weights_[iWhere+1])
+            break;
+    if (sosType_ == 1) {
+        // SOS 1
+        separator = 0.5 * (weights_[iWhere] + weights_[iWhere+1]);
+    } else {
+        // SOS 2
+        if (iWhere == firstNonFixed)
+            iWhere++;;
+        if (iWhere == lastNonFixed - 1)
+            iWhere = lastNonFixed - 2;
+        separator = weights_[iWhere+1];
+    }
+    // create object
+    CbcBranchingObject * branch;
+    branch = new CbcSOSBranchingObject(model_, this, way, separator);
+    branch->setOriginalObject(this);
+    return branch;
+}
+/* Pass in information on branch just done and create CbcObjectUpdateData instance.
+   If object does not need data then backward pointer will be NULL.
+   Assumes can get information from solver */
+CbcObjectUpdateData
+CbcSOS::createUpdateInformation(const OsiSolverInterface * solver,
+                                const CbcNode * node,
+                                const CbcBranchingObject * branchingObject)
+{
+    double originalValue = node->objectiveValue();
+    int originalUnsatisfied = node->numberUnsatisfied();
+    double objectiveValue = solver->getObjValue() * solver->getObjSense();
+    int unsatisfied = 0;
+    int i;
+    //might be base model - doesn't matter
+    int numberIntegers = model_->numberIntegers();;
+    const double * solution = solver->getColSolution();
+    //const double * lower = solver->getColLower();
+    //const double * upper = solver->getColUpper();
+    double change = CoinMax(0.0, objectiveValue - originalValue);
+    int iStatus;
+    if (solver->isProvenOptimal())
+        iStatus = 0; // optimal
+    else if (solver->isIterationLimitReached()
+             && !solver->isDualObjectiveLimitReached())
+        iStatus = 2; // unknown
+    else
+        iStatus = 1; // infeasible
+
+    bool feasible = iStatus != 1;
+    if (feasible) {
+        double integerTolerance =
+            model_->getDblParam(CbcModel::CbcIntegerTolerance);
+        const int * integerVariable = model_->integerVariable();
+        for (i = 0; i < numberIntegers; i++) {
+            int j = integerVariable[i];
+            double value = solution[j];
+            double nearest = floor(value + 0.5);
+            if (fabs(value - nearest) > integerTolerance)
+                unsatisfied++;
+        }
+    }
+    int way = branchingObject->way();
+    way = - way; // because after branch so moved on
+    double value = branchingObject->value();
+    CbcObjectUpdateData newData (this, way,
+                                 change, iStatus,
+                                 originalUnsatisfied - unsatisfied, value);
+    newData.originalObjective_ = originalValue;
+    // Solvers know about direction
+    double direction = solver->getObjSense();
+    solver->getDblParam(OsiDualObjectiveLimit, newData.cutoff_);
+    newData.cutoff_ *= direction;
+    return newData;
+}
+// Update object by CbcObjectUpdateData
+void
+CbcSOS::updateInformation(const CbcObjectUpdateData & data)
+{
+    bool feasible = data.status_ != 1;
+    int way = data.way_;
+    //double value = data.branchingValue_;
+    double originalValue = data.originalObjective_;
+    double change = data.change_;
+    if (way < 0) {
+        // down
+        if (!feasible) {
+            double distanceToCutoff = 0.0;
+            //double objectiveValue = model_->getCurrentMinimizationObjValue();
+            distanceToCutoff =  model_->getCutoff()  - originalValue;
+            if (distanceToCutoff < 1.0e20)
+                change = distanceToCutoff * 2.0;
+            else
+                change = (downDynamicPseudoRatio_ * shadowEstimateDown_ + 1.0e-3) * 10.0;
+        }
+        change = CoinMax(1.0e-12 * (1.0 + fabs(originalValue)), change);
+#ifdef PRINT_SHADOW
+        if (numberTimesDown_)
+            printf("Updating id %d - down change %g (true %g) - ndown %d estimated change %g - raw shadow estimate %g\n",
+                   id_, change, data.change_, numberTimesDown_, shadowEstimateDown_*
+                   (downDynamicPseudoRatio_ / ((double) numberTimesDown_)),
+                   shadowEstimateDown_);
+        else
+            printf("Updating id %d - down change %g (true %g) - shadow estimate %g\n",
+                   id_, change, data.change_, shadowEstimateDown_);
+#endif
+        numberTimesDown_++;
+        downDynamicPseudoRatio_ += change / shadowEstimateDown_;
+    } else {
+        // up
+        if (!feasible) {
+            double distanceToCutoff = 0.0;
+            //double objectiveValue = model_->getCurrentMinimizationObjValue();
+            distanceToCutoff =  model_->getCutoff()  - originalValue;
+            if (distanceToCutoff < 1.0e20)
+                change = distanceToCutoff * 2.0;
+            else
+                change = (upDynamicPseudoRatio_ * shadowEstimateUp_ + 1.0e-3) * 10.0;
+        }
+        change = CoinMax(1.0e-12 * (1.0 + fabs(originalValue)), change);
+#ifdef PRINT_SHADOW
+        if (numberTimesUp_)
+            printf("Updating id %d - up change %g (true %g) - nup %d estimated change %g - raw shadow estimate %g\n",
+                   id_, change, data.change_, numberTimesUp_, shadowEstimateUp_*
+                   (upDynamicPseudoRatio_ / ((double) numberTimesUp_)),
+                   shadowEstimateUp_);
+        else
+            printf("Updating id %d - up change %g (true %g) - shadow estimate %g\n",
+                   id_, change, data.change_, shadowEstimateUp_);
+#endif
+        numberTimesUp_++;
+        upDynamicPseudoRatio_ += change / shadowEstimateUp_;
+    }
+}
+
+/* Create an OsiSolverBranch object
+
+This returns NULL if branch not represented by bound changes
+*/
+OsiSolverBranch *
+CbcSOS::solverBranch() const
+{
+    int j;
+    const double * solution = model_->testSolution();
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    OsiSolverInterface * solver = model_->solver();
+    const double * upper = solver->getColUpper();
+    int firstNonFixed = -1;
+    int lastNonFixed = -1;
+    int firstNonZero = -1;
+    int lastNonZero = -1;
+    double weight = 0.0;
+    double sum = 0.0;
+    double * fix = new double[numberMembers_];
+    int * which = new int[numberMembers_];
+    for (j = 0; j < numberMembers_; j++) {
+        int iColumn = members_[j];
+        // fix all on one side or other (even if fixed)
+        fix[j] = 0.0;
+        which[j] = iColumn;
+        if (upper[iColumn]) {
+            double value = CoinMax(0.0, solution[iColumn]);
+            sum += value;
+            if (firstNonFixed < 0)
+                firstNonFixed = j;
+            lastNonFixed = j;
+            if (value > integerTolerance) {
+                weight += weights_[j] * value;
+                if (firstNonZero < 0)
+                    firstNonZero = j;
+                lastNonZero = j;
+            }
+        }
+    }
+    assert (lastNonZero - firstNonZero >= sosType_) ;
+    // find where to branch
+    assert (sum > 0.0);
+    weight /= sum;
+    // down branch fixes ones above weight to 0
+    int iWhere;
+    int iDownStart = 0;
+    int iUpEnd = 0;
+    for (iWhere = firstNonZero; iWhere < lastNonZero; iWhere++)
+        if (weight < weights_[iWhere+1])
+            break;
+    if (sosType_ == 1) {
+        // SOS 1
+        iUpEnd = iWhere + 1;
+        iDownStart = iUpEnd;
+    } else {
+        // SOS 2
+        if (iWhere == firstNonFixed)
+            iWhere++;;
+        if (iWhere == lastNonFixed - 1)
+            iWhere = lastNonFixed - 2;
+        iUpEnd = iWhere + 1;
+        iDownStart = iUpEnd + 1;
+    }
+    //
+    OsiSolverBranch * branch = new OsiSolverBranch();
+    branch->addBranch(-1, 0, NULL, NULL, numberMembers_ - iDownStart, which + iDownStart, fix);
+    branch->addBranch(1, 0, NULL, NULL, iUpEnd, which, fix);
+    delete [] fix;
+    delete [] which;
+    return branch;
+}
+// Construct an OsiSOS object
+OsiSOS *
+CbcSOS::osiObject(const OsiSolverInterface * solver) const
+{
+    OsiSOS * obj = new OsiSOS(solver, numberMembers_, members_, weights_, sosType_);
+    obj->setPriority(priority());
+    return obj;
+}
+
+// Default Constructor
+CbcSOSBranchingObject::CbcSOSBranchingObject()
+        : CbcBranchingObject(),
+        firstNonzero_(-1),
+        lastNonzero_(-1)
+{
+    set_ = NULL;
+    separator_ = 0.0;
+}
+
+// Useful constructor
+CbcSOSBranchingObject::CbcSOSBranchingObject (CbcModel * model,
+        const CbcSOS * set,
+        int way ,
+        double separator)
+        : CbcBranchingObject(model, set->id(), way, 0.5)
+{
+    set_ = set;
+    separator_ = separator;
+    computeNonzeroRange();
+}
+
+// Copy constructor
+CbcSOSBranchingObject::CbcSOSBranchingObject (const CbcSOSBranchingObject & rhs)
+        : CbcBranchingObject(rhs),
+        firstNonzero_(rhs.firstNonzero_),
+        lastNonzero_(rhs.lastNonzero_)
+{
+    set_ = rhs.set_;
+    separator_ = rhs.separator_;
+}
+
+// Assignment operator
+CbcSOSBranchingObject &
+CbcSOSBranchingObject::operator=( const CbcSOSBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        set_ = rhs.set_;
+        separator_ = rhs.separator_;
+        firstNonzero_ = rhs.firstNonzero_;
+        lastNonzero_ = rhs.lastNonzero_;
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcSOSBranchingObject::clone() const
+{
+    return (new CbcSOSBranchingObject(*this));
+}
+
+
+// Destructor
+CbcSOSBranchingObject::~CbcSOSBranchingObject ()
+{
+}
+
+void
+CbcSOSBranchingObject::computeNonzeroRange()
+{
+    const int numberMembers = set_->numberMembers();
+    const double * weights = set_->weights();
+    int i = 0;
+    if (way_ < 0) {
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] > separator_)
+                break;
+        }
+        assert (i < numberMembers);
+        firstNonzero_ = 0;
+        lastNonzero_ = i;
+    } else {
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] >= separator_)
+                break;
+        }
+        assert (i < numberMembers);
+        firstNonzero_ = i;
+        lastNonzero_ = numberMembers;
+    }
+}
+
+double
+CbcSOSBranchingObject::branch()
+{
+    decrementNumberBranchesLeft();
+    int numberMembers = set_->numberMembers();
+    const int * which = set_->members();
+    const double * weights = set_->weights();
+    OsiSolverInterface * solver = model_->solver();
+    //const double * lower = solver->getColLower();
+    //const double * upper = solver->getColUpper();
+    // *** for way - up means fix all those in down section
+    if (way_ < 0) {
+        int i;
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] > separator_)
+                break;
+        }
+        assert (i < numberMembers);
+        for (; i < numberMembers; i++)
+            solver->setColUpper(which[i], 0.0);
+        way_ = 1;	  // Swap direction
+    } else {
+        int i;
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] >= separator_)
+                break;
+            else
+                solver->setColUpper(which[i], 0.0);
+        }
+        assert (i < numberMembers);
+        way_ = -1;	  // Swap direction
+    }
+    computeNonzeroRange();
+    return 0.0;
+}
+/* Update bounds in solver as in 'branch' and update given bounds.
+   branchState is -1 for 'down' +1 for 'up' */
+void
+CbcSOSBranchingObject::fix(OsiSolverInterface * solver,
+                           double * /*lower*/, double * upper,
+                           int branchState) const
+{
+    int numberMembers = set_->numberMembers();
+    const int * which = set_->members();
+    const double * weights = set_->weights();
+    //const double * lower = solver->getColLower();
+    //const double * upper = solver->getColUpper();
+    // *** for way - up means fix all those in down section
+    if (branchState < 0) {
+        int i;
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] > separator_)
+                break;
+        }
+        assert (i < numberMembers);
+        for (; i < numberMembers; i++) {
+            solver->setColUpper(which[i], 0.0);
+            upper[which[i]] = 0.0;
+        }
+    } else {
+        int i;
+        for ( i = 0; i < numberMembers; i++) {
+            if (weights[i] >= separator_) {
+                break;
+            } else {
+                solver->setColUpper(which[i], 0.0);
+                upper[which[i]] = 0.0;
+            }
+        }
+        assert (i < numberMembers);
+    }
+}
+// Print what would happen
+void
+CbcSOSBranchingObject::print()
+{
+    int numberMembers = set_->numberMembers();
+    const int * which = set_->members();
+    const double * weights = set_->weights();
+    OsiSolverInterface * solver = model_->solver();
+    //const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    int first = numberMembers;
+    int last = -1;
+    int numberFixed = 0;
+    int numberOther = 0;
+    int i;
+    for ( i = 0; i < numberMembers; i++) {
+        double bound = upper[which[i]];
+        if (bound) {
+            first = CoinMin(first, i);
+            last = CoinMax(last, i);
+        }
+    }
+    // *** for way - up means fix all those in down section
+    if (way_ < 0) {
+        printf("SOS Down");
+        for ( i = 0; i < numberMembers; i++) {
+            double bound = upper[which[i]];
+            if (weights[i] > separator_)
+                break;
+            else if (bound)
+                numberOther++;
+        }
+        assert (i < numberMembers);
+        for (; i < numberMembers; i++) {
+            double bound = upper[which[i]];
+            if (bound)
+                numberFixed++;
+        }
+    } else {
+        printf("SOS Up");
+        for ( i = 0; i < numberMembers; i++) {
+            double bound = upper[which[i]];
+            if (weights[i] >= separator_)
+                break;
+            else if (bound)
+                numberFixed++;
+        }
+        assert (i < numberMembers);
+        for (; i < numberMembers; i++) {
+            double bound = upper[which[i]];
+            if (bound)
+                numberOther++;
+        }
+    }
+    printf(" - at %g, free range %d (%g) => %d (%g), %d would be fixed, %d other way\n",
+           separator_, which[first], weights[first], which[last], weights[last], numberFixed, numberOther);
+}
+
+/** Compare the original object of \c this with the original object of \c
+    brObj. Assumes that there is an ordering of the original objects.
+    This method should be invoked only if \c this and brObj are of the same
+    type.
+    Return negative/0/positive depending on whether \c this is
+    smaller/same/larger than the argument.
+*/
+int
+CbcSOSBranchingObject::compareOriginalObject
+(const CbcBranchingObject* brObj) const
+{
+    const CbcSOSBranchingObject* br =
+        dynamic_cast<const CbcSOSBranchingObject*>(brObj);
+    assert(br);
+    const CbcSOS* s0 = set_;
+    const CbcSOS* s1 = br->set_;
+    if (s0->sosType() != s1->sosType()) {
+        return s0->sosType() - s1->sosType();
+    }
+    if (s0->numberMembers() != s1->numberMembers()) {
+        return s0->numberMembers() - s1->numberMembers();
+    }
+    const int memberCmp = memcmp(s0->members(), s1->members(),
+                                 s0->numberMembers() * sizeof(int));
+    if (memberCmp != 0) {
+        return memberCmp;
+    }
+    return memcmp(s0->weights(), s1->weights(),
+                  s0->numberMembers() * sizeof(double));
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcSOSBranchingObject::compareBranchingObject
+(const CbcBranchingObject* brObj, const bool replaceIfOverlap)
+{
+    const CbcSOSBranchingObject* br =
+        dynamic_cast<const CbcSOSBranchingObject*>(brObj);
+    assert(br);
+    if (firstNonzero_ < br->firstNonzero_) {
+        if (lastNonzero_ >= br->lastNonzero_) {
+            return CbcRangeSuperset;
+        } else if (lastNonzero_ <= br->firstNonzero_) {
+            return CbcRangeDisjoint;
+        } else {
+            // overlap
+            if (replaceIfOverlap) {
+                firstNonzero_ = br->firstNonzero_;
+            }
+            return CbcRangeOverlap;
+        }
+    } else if (firstNonzero_ > br->firstNonzero_) {
+        if (lastNonzero_ <= br->lastNonzero_) {
+            return CbcRangeSubset;
+        } else if (firstNonzero_ >= br->lastNonzero_) {
+            return CbcRangeDisjoint;
+        } else {
+            // overlap
+            if (replaceIfOverlap) {
+                lastNonzero_ = br->lastNonzero_;
+            }
+            return CbcRangeOverlap;
+        }
+    } else {
+        if (lastNonzero_ == br->lastNonzero_) {
+            return CbcRangeSame;
+        }
+        return lastNonzero_ < br->lastNonzero_ ? CbcRangeSubset : CbcRangeSuperset;
+    }
+    return CbcRangeSame; // fake return
+}
+
diff --git a/cbits/coin/CbcSOS.hpp b/cbits/coin/CbcSOS.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSOS.hpp
@@ -0,0 +1,277 @@
+// $Id: CbcSOS.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/9/2009-- carved out of CbcBranchActual
+
+#ifndef CbcSOS_H
+#define CbcSOS_H
+
+/** \brief Branching object for Special Ordered Sets of type 1 and 2.
+
+  SOS1 are an ordered set of variables where at most one variable can be
+  non-zero. SOS1 are commonly defined with binary variables (interpreted as
+  selection between alternatives) but this is not necessary.  An SOS1 with
+  all binary variables is a special case of a clique (setting any one
+  variable to 1 forces all others to 0).
+
+  In theory, the implementation makes no assumptions about integrality in
+  Type 1 sets. In practice, there are places where the code seems to have been
+  written with a binary SOS mindset. Current development of SOS branching
+  objects is proceeding in OsiSOS.
+
+  SOS2 are an ordered set of variables in which at most two consecutive
+  variables can be non-zero and must sum to 1 (interpreted as interpolation
+  between two discrete values). By definition the variables are non-integer.
+*/
+
+class CbcSOS : public CbcObject {
+
+public:
+
+    // Default Constructor
+    CbcSOS ();
+
+	/** \brief Constructor with SOS type and member information
+
+    Type specifies SOS 1 or 2. Identifier is an arbitrary value.
+
+    Which should be an array of variable indices with numberMembers entries.
+    Weights can be used to assign arbitrary weights to variables, in the order
+    they are specified in which. If no weights are provided, a default array of
+    0, 1, 2, ... is generated.
+	*/
+
+    CbcSOS (CbcModel * model, int numberMembers,
+            const int * which, const double * weights, int identifier,
+            int type = 1);
+
+    // Copy constructor
+    CbcSOS ( const CbcSOS &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcSOS & operator=( const CbcSOS& rhs);
+
+    // Destructor
+    virtual ~CbcSOS ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /// This looks at solution and sets bounds to contain solution
+    virtual void feasibleRegion();
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+
+
+
+    /** Pass in information on branch just done and create CbcObjectUpdateData instance.
+        If object does not need data then backward pointer will be NULL.
+        Assumes can get information from solver */
+    virtual CbcObjectUpdateData createUpdateInformation(const OsiSolverInterface * solver,
+            const CbcNode * node,
+            const CbcBranchingObject * branchingObject);
+    /// Update object by CbcObjectUpdateData
+    virtual void updateInformation(const CbcObjectUpdateData & data) ;
+    using CbcObject::solverBranch ;
+    /** Create an OsiSolverBranch object
+
+        This returns NULL if branch not represented by bound changes
+    */
+    virtual OsiSolverBranch * solverBranch() const;
+    /// Redoes data when sequence numbers change
+    virtual void redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns);
+
+    /// Construct an OsiSOS object
+    OsiSOS * osiObject(const OsiSolverInterface * solver) const;
+    /// Number of members
+    inline int numberMembers() const {
+        return numberMembers_;
+    }
+
+    /// Members (indices in range 0 ... numberColumns-1)
+    inline const int * members() const {
+        return members_;
+    }
+
+    /// SOS type
+    inline int sosType() const {
+        return sosType_;
+    }
+    /// Down number times
+    inline int numberTimesDown() const {
+        return numberTimesDown_;
+    }
+    /// Up number times
+    inline int numberTimesUp() const {
+        return numberTimesUp_;
+    }
+
+    /** Array of weights */
+    inline const double * weights() const {
+        return weights_;
+    }
+
+    /// Set number of members
+    inline void setNumberMembers(int n) {
+        numberMembers_ = n;
+    }
+
+    /// Members (indices in range 0 ... numberColumns-1)
+    inline int * mutableMembers() const {
+        return members_;
+    }
+
+    /** Array of weights */
+    inline double * mutableWeights() const {
+        return weights_;
+    }
+
+    /** \brief Return true if object can take part in normal heuristics
+    */
+    virtual bool canDoHeuristics() const {
+        return (sosType_ == 1 && integerValued_);
+    }
+    /// Set whether set is integer valued or not
+    inline void setIntegerValued(bool yesNo) {
+        integerValued_ = yesNo;
+    }
+private:
+    /// data
+
+    /// Members (indices in range 0 ... numberColumns-1)
+    int * members_;
+  /** \brief Weights for individual members
+
+    Arbitrary weights for members. Can be used to attach meaning to variable
+    values independent of objective coefficients. For example, if the SOS set
+    comprises binary variables used to choose a facility of a given size, the
+    weight could be the corresponding facilty size. Fractional values of the
+    SOS variables can then be used to estimate ideal facility size.
+
+    Weights cannot be completely arbitrary. From the code, they must be
+    differ by at least 1.0e-7
+  */
+
+    double * weights_;
+    /// Current pseudo-shadow price estimate down
+    mutable double shadowEstimateDown_;
+    /// Current pseudo-shadow price estimate up
+    mutable double shadowEstimateUp_;
+    /// Down pseudo ratio
+    double downDynamicPseudoRatio_;
+    /// Up pseudo ratio
+    double upDynamicPseudoRatio_;
+    /// Number of times we have gone down
+    int numberTimesDown_;
+    /// Number of times we have gone up
+    int numberTimesUp_;
+    /// Number of members
+    int numberMembers_;
+    /// SOS type
+    int sosType_;
+    /// Whether integer valued
+    bool integerValued_;
+};
+
+/** Branching object for Special ordered sets
+
+    Variable_ is the set id number (redundant, as the object also holds a
+    pointer to the set.
+ */
+class CbcSOSBranchingObject : public CbcBranchingObject {
+
+public:
+
+    // Default Constructor
+    CbcSOSBranchingObject ();
+
+    // Useful constructor
+    CbcSOSBranchingObject (CbcModel * model,  const CbcSOS * clique,
+                           int way,
+                           double separator);
+
+    // Copy constructor
+    CbcSOSBranchingObject ( const CbcSOSBranchingObject &);
+
+    // Assignment operator
+    CbcSOSBranchingObject & operator=( const CbcSOSBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    // Destructor
+    virtual ~CbcSOSBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /// Does next branch and updates state
+    virtual double branch();
+    /** Update bounds in solver as in 'branch' and update given bounds.
+        branchState is -1 for 'down' +1 for 'up' */
+    virtual void fix(OsiSolverInterface * solver,
+                     double * lower, double * upper,
+                     int branchState) const ;
+
+    /** Reset every information so that the branching object appears to point to
+        the previous child. This method does not need to modify anything in any
+        solver. */
+    virtual void previousBranch() {
+        CbcBranchingObject::previousBranch();
+        computeNonzeroRange();
+    }
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return SoSBranchObj;
+    }
+
+    /** Compare the original object of \c this with the original object of \c
+        brObj. Assumes that there is an ordering of the original objects.
+        This method should be invoked only if \c this and brObj are of the same
+        type.
+        Return negative/0/positive depending on whether \c this is
+        smaller/same/larger than the argument.
+    */
+    virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+    /** Fill out the \c firstNonzero_ and \c lastNonzero_ data members */
+    void computeNonzeroRange();
+
+private:
+    /// data
+    const CbcSOS * set_;
+    /// separator
+    double separator_;
+    /** The following two members describe the range in the members_ of the
+        original object that whose upper bound is not fixed to 0. This is not
+        necessary for Cbc to function correctly, this is there for heuristics so
+        that separate branching decisions on the same object can be pooled into
+        one branching object. */
+    int firstNonzero_;
+    int lastNonzero_;
+};
+#endif
+
diff --git a/cbits/coin/CbcSimpleInteger.cpp b/cbits/coin/CbcSimpleInteger.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSimpleInteger.cpp
@@ -0,0 +1,728 @@
+// $Id: CbcSimpleInteger.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/9/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcSimpleInteger.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+
+//##############################################################################
+
+/** Default Constructor
+
+  Equivalent to an unspecified binary variable.
+*/
+CbcSimpleInteger::CbcSimpleInteger ()
+        : CbcObject(),
+        originalLower_(0.0),
+        originalUpper_(1.0),
+        breakEven_(0.5),
+        columnNumber_(-1),
+        preferredWay_(0)
+{
+}
+
+/** Useful constructor
+
+  Loads actual upper & lower bounds for the specified variable.
+*/
+CbcSimpleInteger::CbcSimpleInteger ( CbcModel * model, int iColumn, double breakEven)
+        : CbcObject(model)
+{
+    columnNumber_ = iColumn ;
+    originalLower_ = model->solver()->getColLower()[columnNumber_] ;
+    originalUpper_ = model->solver()->getColUpper()[columnNumber_] ;
+    breakEven_ = breakEven;
+    assert (breakEven_ > 0.0 && breakEven_ < 1.0);
+    preferredWay_ = 0;
+}
+
+
+// Copy constructor
+CbcSimpleInteger::CbcSimpleInteger ( const CbcSimpleInteger & rhs)
+        : CbcObject(rhs)
+
+{
+    columnNumber_ = rhs.columnNumber_;
+    originalLower_ = rhs.originalLower_;
+    originalUpper_ = rhs.originalUpper_;
+    breakEven_ = rhs.breakEven_;
+    preferredWay_ = rhs.preferredWay_;
+}
+
+// Clone
+CbcObject *
+CbcSimpleInteger::clone() const
+{
+    return new CbcSimpleInteger(*this);
+}
+
+// Assignment operator
+CbcSimpleInteger &
+CbcSimpleInteger::operator=( const CbcSimpleInteger & rhs)
+{
+    if (this != &rhs) {
+        CbcObject::operator=(rhs);
+        columnNumber_ = rhs.columnNumber_;
+        originalLower_ = rhs.originalLower_;
+        originalUpper_ = rhs.originalUpper_;
+        breakEven_ = rhs.breakEven_;
+        preferredWay_ = rhs.preferredWay_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcSimpleInteger::~CbcSimpleInteger ()
+{
+}
+// Construct an OsiSimpleInteger object
+OsiSimpleInteger *
+CbcSimpleInteger::osiObject() const
+{
+    OsiSimpleInteger * obj = new OsiSimpleInteger(columnNumber_,
+            originalLower_, originalUpper_);
+    obj->setPriority(priority());
+    return obj;
+}
+double
+CbcSimpleInteger::infeasibility(const OsiBranchingInformation * info,
+                                int &preferredWay) const
+{
+    double value = info->solution_[columnNumber_];
+    value = CoinMax(value, info->lower_[columnNumber_]);
+    value = CoinMin(value, info->upper_[columnNumber_]);
+    double nearest = floor(value + (1.0 - breakEven_));
+    assert (breakEven_ > 0.0 && breakEven_ < 1.0);
+    if (nearest > value)
+        preferredWay = 1;
+    else
+        preferredWay = -1;
+    if (preferredWay_)
+        preferredWay = preferredWay_;
+    double weight = fabs(value - nearest);
+    // normalize so weight is 0.5 at break even
+    if (nearest < value)
+        weight = (0.5 / breakEven_) * weight;
+    else
+        weight = (0.5 / (1.0 - breakEven_)) * weight;
+    if (fabs(value - nearest) <= info->integerTolerance_)
+        return 0.0;
+    else
+        return weight;
+}
+double
+CbcSimpleInteger::feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const
+{
+    double value = info->solution_[columnNumber_];
+#ifdef COIN_DEVELOP
+    if (fabs(value - floor(value + 0.5)) > 1.0e-5)
+        printf("value for %d away from integer %g\n", columnNumber_, value);
+#endif
+    double newValue = CoinMax(value, info->lower_[columnNumber_]);
+    newValue = CoinMin(newValue, info->upper_[columnNumber_]);
+    newValue = floor(newValue + 0.5);
+    solver->setColLower(columnNumber_, newValue);
+    solver->setColUpper(columnNumber_, newValue);
+    return fabs(value - newValue);
+}
+
+/* Create an OsiSolverBranch object
+
+This returns NULL if branch not represented by bound changes
+*/
+OsiSolverBranch *
+CbcSimpleInteger::solverBranch(OsiSolverInterface * /*solver*/,
+                               const OsiBranchingInformation * info) const
+{
+    double value = info->solution_[columnNumber_];
+    value = CoinMax(value, info->lower_[columnNumber_]);
+    value = CoinMin(value, info->upper_[columnNumber_]);
+    assert (info->upper_[columnNumber_] > info->lower_[columnNumber_]);
+#ifndef NDEBUG
+    double nearest = floor(value + 0.5);
+    assert (fabs(value - nearest) > info->integerTolerance_);
+#endif
+    OsiSolverBranch * branch = new OsiSolverBranch();
+    branch->addBranch(columnNumber_, value);
+    return branch;
+}
+// Creates a branching object
+CbcBranchingObject *
+CbcSimpleInteger::createCbcBranch(OsiSolverInterface * /*solver*/,
+                                  const OsiBranchingInformation * info, int way)
+{
+    CbcIntegerBranchingObject * branch = new CbcIntegerBranchingObject(model_, 0, -1, 0.5);
+    fillCreateBranch(branch, info, way);
+    return branch;
+}
+// Fills in a created branching object
+void
+CbcSimpleInteger::fillCreateBranch(CbcIntegerBranchingObject * branch, const OsiBranchingInformation * info, int way)
+{
+    branch->setOriginalObject(this);
+    double value = info->solution_[columnNumber_];
+    value = CoinMax(value, info->lower_[columnNumber_]);
+    value = CoinMin(value, info->upper_[columnNumber_]);
+    assert (info->upper_[columnNumber_] > info->lower_[columnNumber_]);
+    if (!info->hotstartSolution_ && priority_ != -999) {
+#if 0 // out because of very strong branching ndef NDEBUG
+        double nearest = floor(value + 0.5);
+        assert (fabs(value - nearest) > info->integerTolerance_);
+#endif
+    } else if (info->hotstartSolution_) {
+        double targetValue = info->hotstartSolution_[columnNumber_];
+        if (way > 0)
+            value = targetValue - 0.1;
+        else
+            value = targetValue + 0.1;
+    } else {
+        if (value <= info->lower_[columnNumber_])
+            value += 0.1;
+        else if (value >= info->upper_[columnNumber_])
+            value -= 0.1;
+    }
+    assert (value >= info->lower_[columnNumber_] &&
+            value <= info->upper_[columnNumber_]);
+    branch->fillPart(columnNumber_, way, value);
+}
+/* Column number if single column object -1 otherwise,
+   so returns >= 0
+   Used by heuristics
+*/
+int
+CbcSimpleInteger::columnNumber() const
+{
+    return columnNumber_;
+}
+/* Reset variable bounds to their original values.
+
+    Bounds may be tightened, so it may be good to be able to set this info in object.
+*/
+void
+CbcSimpleInteger::resetBounds(const OsiSolverInterface * solver)
+{
+    originalLower_ = solver->getColLower()[columnNumber_] ;
+    originalUpper_ = solver->getColUpper()[columnNumber_] ;
+}
+
+/*  Change column numbers after preprocessing
+ */
+void
+CbcSimpleInteger::resetSequenceEtc(int /*numberColumns*/,
+                                   const int * originalColumns)
+{
+    //assert (numberColumns>0);
+    int iColumn;
+#ifdef JJF_ZERO
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        if (columnNumber_ == originalColumns[iColumn])
+            break;
+    }
+    assert (iColumn < numberColumns);
+#else
+    iColumn = originalColumns[columnNumber_];
+    assert (iColumn >= 0);
+#endif
+    columnNumber_ = iColumn;
+}
+// This looks at solution and sets bounds to contain solution
+/** More precisely: it first forces the variable within the existing
+    bounds, and then tightens the bounds to fix the variable at the
+    nearest integer value.
+*/
+void
+CbcSimpleInteger::feasibleRegion()
+{
+    abort();
+}
+
+//##############################################################################
+
+// Default Constructor
+CbcIntegerBranchingObject::CbcIntegerBranchingObject()
+        : CbcBranchingObject()
+{
+    down_[0] = 0.0;
+    down_[1] = 0.0;
+    up_[0] = 0.0;
+    up_[1] = 0.0;
+#ifdef FUNNY_BRANCHING2
+    variables_ = NULL;
+    newBounds_ = NULL;
+    numberExtraChangedBounds_ = 0;
+#endif
+}
+// Useful constructor
+CbcIntegerBranchingObject::CbcIntegerBranchingObject (CbcModel * model,
+        int variable, int way , double value)
+        : CbcBranchingObject(model, variable, way, value)
+{
+    int iColumn = variable;
+    assert (model_->solver()->getNumCols() > 0);
+    down_[0] = model_->solver()->getColLower()[iColumn];
+    down_[1] = floor(value_);
+    up_[0] = ceil(value_);
+    up_[1] = model->getColUpper()[iColumn];
+#ifdef FUNNY_BRANCHING2
+    variables_ = NULL;
+    newBounds_ = NULL;
+    numberExtraChangedBounds_ = 0;
+#endif
+}
+// Does part of constructor
+void
+CbcIntegerBranchingObject::fillPart (int variable,
+                                     int way , double value)
+{
+    //originalObject_=NULL;
+    branchIndex_ = 0;
+    value_ = value;
+    numberBranches_ = 2;
+    //model_= model;
+    //originalCbcObject_=NULL;
+    variable_ = variable;
+    way_ = way;
+    int iColumn = variable;
+    down_[0] = model_->solver()->getColLower()[iColumn];
+    down_[1] = floor(value_);
+    up_[0] = ceil(value_);
+    up_[1] = model_->getColUpper()[iColumn];
+}
+// Useful constructor for fixing
+CbcIntegerBranchingObject::CbcIntegerBranchingObject (CbcModel * model,
+        int variable, int way,
+        double lowerValue,
+        double upperValue)
+        : CbcBranchingObject(model, variable, way, lowerValue)
+{
+    setNumberBranchesLeft(1);
+    down_[0] = lowerValue;
+    down_[1] = upperValue;
+    up_[0] = lowerValue;
+    up_[1] = upperValue;
+#ifdef FUNNY_BRANCHING2
+    variables_ = NULL;
+    newBounds_ = NULL;
+    numberExtraChangedBounds_ = 0;
+#endif
+}
+
+
+// Copy constructor
+CbcIntegerBranchingObject::CbcIntegerBranchingObject ( const CbcIntegerBranchingObject & rhs) : CbcBranchingObject(rhs)
+{
+    down_[0] = rhs.down_[0];
+    down_[1] = rhs.down_[1];
+    up_[0] = rhs.up_[0];
+    up_[1] = rhs.up_[1];
+#ifdef FUNNY_BRANCHING2
+    numberExtraChangedBounds_ = rhs.numberExtraChangedBounds_;
+    int size = numberExtraChangedBounds_ * (sizeof(double) + sizeof(int));
+    char * temp = new char [size];
+    newBounds_ = (double *) temp;
+    variables_ = (int *) (newBounds_ + numberExtraChangedBounds_);
+
+    int i ;
+    for (i = 0; i < numberExtraChangedBounds_; i++) {
+        variables_[i] = rhs.variables_[i];
+        newBounds_[i] = rhs.newBounds_[i];
+    }
+#endif
+}
+
+// Assignment operator
+CbcIntegerBranchingObject &
+CbcIntegerBranchingObject::operator=( const CbcIntegerBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcBranchingObject::operator=(rhs);
+        down_[0] = rhs.down_[0];
+        down_[1] = rhs.down_[1];
+        up_[0] = rhs.up_[0];
+        up_[1] = rhs.up_[1];
+#ifdef FUNNY_BRANCHING2
+        delete [] newBounds_;
+        numberExtraChangedBounds_ = rhs.numberExtraChangedBounds_;
+        int size = numberExtraChangedBounds_ * (sizeof(double) + sizeof(int));
+        char * temp = new char [size];
+        newBounds_ = (double *) temp;
+        variables_ = (int *) (newBounds_ + numberExtraChangedBounds_);
+
+        int i ;
+        for (i = 0; i < numberExtraChangedBounds_; i++) {
+            variables_[i] = rhs.variables_[i];
+            newBounds_[i] = rhs.newBounds_[i];
+        }
+#endif
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcIntegerBranchingObject::clone() const
+{
+    return (new CbcIntegerBranchingObject(*this));
+}
+
+
+// Destructor
+CbcIntegerBranchingObject::~CbcIntegerBranchingObject ()
+{
+    // for debugging threads
+    way_ = -23456789;
+#ifdef FUNNY_BRANCHING2
+    delete [] newBounds_;
+#endif
+}
+
+/*
+  Perform a branch by adjusting the bounds of the specified variable. Note
+  that each arm of the branch advances the object to the next arm by
+  advancing the value of way_.
+
+  Providing new values for the variable's lower and upper bounds for each
+  branching direction gives a little bit of additional flexibility and will
+  be easily extensible to multi-way branching.
+  Returns change in guessed objective on next branch
+*/
+double
+CbcIntegerBranchingObject::branch()
+{
+    // for debugging threads
+    if (way_ < -1 || way_ > 100000) {
+        printf("way %d, left %d, iCol %d, variable %d\n",
+               way_, numberBranchesLeft(),
+               originalCbcObject_->columnNumber(), variable_);
+        assert (way_ != -23456789);
+    }
+    decrementNumberBranchesLeft();
+    if (down_[1] == -COIN_DBL_MAX)
+        return 0.0;
+    int iColumn = originalCbcObject_->columnNumber();
+    assert (variable_ == iColumn);
+    double olb, oub ;
+    olb = model_->solver()->getColLower()[iColumn] ;
+    oub = model_->solver()->getColUpper()[iColumn] ;
+    //#define CBCSIMPLE_TIGHTEN_BOUNDS
+#ifndef CBCSIMPLE_TIGHTEN_BOUNDS
+#ifdef COIN_DEVELOP
+    if (olb != down_[0] || oub != up_[1]) {
+        if (way_ > 0)
+            printf("branching up on var %d: [%g,%g] => [%g,%g] - other [%g,%g]\n",
+                   iColumn, olb, oub, up_[0], up_[1], down_[0], down_[1]) ;
+        else
+            printf("branching down on var %d: [%g,%g] => [%g,%g] - other [%g,%g]\n",
+                   iColumn, olb, oub, down_[0], down_[1], up_[0], up_[1]) ;
+    }
+#endif
+#endif
+    if (way_ < 0) {
+#ifdef CBC_DEBUG
+        { double olb, oub ;
+            olb = model_->solver()->getColLower()[iColumn] ;
+            oub = model_->solver()->getColUpper()[iColumn] ;
+            printf("branching down on var %d: [%g,%g] => [%g,%g]\n",
+                   iColumn, olb, oub, down_[0], down_[1]) ;
+        }
+#endif
+#ifndef CBCSIMPLE_TIGHTEN_BOUNDS
+        model_->solver()->setColLower(iColumn, down_[0]);
+#else
+        model_->solver()->setColLower(iColumn, CoinMax(down_[0], olb));
+#endif
+        model_->solver()->setColUpper(iColumn, down_[1]);
+	//#define CBC_PRINT2
+#ifdef CBC_PRINT2
+        printf("%d branching down has bounds %g %g", iColumn, down_[0], down_[1]);
+#endif
+#ifdef FUNNY_BRANCHING2
+        // branch - do extra bounds
+        for (int i = 0; i < numberExtraChangedBounds_; i++) {
+            int variable = variables_[i];
+            if ((variable&0x40000000) != 0) {
+                // for going down
+                int k = variable & 0x3fffffff;
+                assert (k != iColumn);
+                if ((variable&0x80000000) == 0) {
+                    // lower bound changing
+#ifdef CBC_PRINT2
+                    printf(" extra for %d changes lower from %g to %g",
+                           k, model_->solver()->getColLower()[k], newBounds_[i]);
+#endif
+                    model_->solver()->setColLower(k, newBounds_[i]);
+                } else {
+                    // upper bound changing
+#ifdef CBC_PRINT2
+                    printf(" extra for %d changes upper from %g to %g",
+                           k, model_->solver()->getColUpper()[k], newBounds_[i]);
+#endif
+                    model_->solver()->setColUpper(k, newBounds_[i]);
+                }
+            }
+        }
+#endif
+#ifdef CBC_PRINT2
+        printf("\n");
+#endif
+        way_ = 1;
+    } else {
+#ifdef CBC_DEBUG
+        { double olb, oub ;
+            olb = model_->solver()->getColLower()[iColumn] ;
+            oub = model_->solver()->getColUpper()[iColumn] ;
+            printf("branching up on var %d: [%g,%g] => [%g,%g]\n",
+                   iColumn, olb, oub, up_[0], up_[1]) ;
+        }
+#endif
+        model_->solver()->setColLower(iColumn, up_[0]);
+#ifndef CBCSIMPLE_TIGHTEN_BOUNDS
+        model_->solver()->setColUpper(iColumn, up_[1]);
+#else
+        model_->solver()->setColUpper(iColumn, CoinMin(up_[1], oub));
+#endif
+#ifdef CBC_PRINT2
+        printf("%d branching up has bounds %g %g", iColumn, up_[0], up_[1]);
+#endif
+#ifdef FUNNY_BRANCHING2
+        // branch - do extra bounds
+        for (int i = 0; i < numberExtraChangedBounds_; i++) {
+            int variable = variables_[i];
+            if ((variable&0x40000000) == 0) {
+                // for going up
+                int k = variable & 0x3fffffff;
+                assert (k != iColumn);
+                if ((variable&0x80000000) == 0) {
+                    // lower bound changing
+#ifdef CBC_PRINT2
+                    printf(" extra for %d changes lower from %g to %g",
+                           k, model_->solver()->getColLower()[k], newBounds_[i]);
+#endif
+                    model_->solver()->setColLower(k, newBounds_[i]);
+                } else {
+                    // upper bound changing
+#ifdef CBC_PRINT2
+                    printf(" extra for %d changes upper from %g to %g",
+                           k, model_->solver()->getColUpper()[k], newBounds_[i]);
+#endif
+                    model_->solver()->setColUpper(k, newBounds_[i]);
+                }
+            }
+        }
+#endif
+#ifdef CBC_PRINT2
+        printf("\n");
+#endif
+        way_ = -1;	  // Swap direction
+    }
+    double nlb = model_->solver()->getColLower()[iColumn];
+    double nub = model_->solver()->getColUpper()[iColumn];
+    if (nlb < olb) {
+#ifdef CBC_PRINT2
+        printf("bad lb change for column %d from %g to %g\n", iColumn, olb, nlb);
+#endif
+	//abort();
+        model_->solver()->setColLower(iColumn, CoinMin(olb, nub));
+        nlb = olb;
+    }
+    if (nub > oub) {
+#ifdef CBC_PRINT2
+        printf("bad ub change for column %d from %g to %g\n", iColumn, oub, nub);
+#endif
+	//abort();
+        model_->solver()->setColUpper(iColumn, CoinMax(oub, nlb));
+    }
+#ifdef CBC_PRINT2
+    if (nlb < olb + 1.0e-8 && nub > oub - 1.0e-8 && false)
+        printf("bad null change for column %d - bounds %g,%g\n", iColumn, olb, oub);
+#endif
+    return 0.0;
+}
+/* Update bounds in solver as in 'branch' and update given bounds.
+   branchState is -1 for 'down' +1 for 'up' */
+void
+CbcIntegerBranchingObject::fix(OsiSolverInterface * /*solver*/,
+                               double * lower, double * upper,
+                               int branchState) const
+{
+    int iColumn = originalCbcObject_->columnNumber();
+    assert (variable_ == iColumn);
+    if (branchState < 0) {
+        model_->solver()->setColLower(iColumn, down_[0]);
+        lower[iColumn] = down_[0];
+        model_->solver()->setColUpper(iColumn, down_[1]);
+        upper[iColumn] = down_[1];
+    } else {
+        model_->solver()->setColLower(iColumn, up_[0]);
+        lower[iColumn] = up_[0];
+        model_->solver()->setColUpper(iColumn, up_[1]);
+        upper[iColumn] = up_[1];
+    }
+}
+// Change (tighten) bounds in object to reflect bounds in solver.
+// Return true if now fixed
+bool 
+CbcIntegerBranchingObject::tighten(OsiSolverInterface * solver) 
+{
+    double lower = solver->getColLower()[variable_];
+    double upper = solver->getColUpper()[variable_];
+    assert (upper>lower);
+    down_[0] = CoinMax(down_[0],lower);
+    up_[0] = CoinMax(up_[0],lower);
+    down_[1] = CoinMin(down_[1],upper);
+    up_[1] = CoinMin(up_[1],upper);
+    return (down_[0]==up_[1]);
+}
+#ifdef FUNNY_BRANCHING2
+// Deactivate bounds for branching
+void
+CbcIntegerBranchingObject::deactivate()
+{
+    down_[1] = -COIN_DBL_MAX;
+}
+int
+CbcIntegerBranchingObject::applyExtraBounds(int iColumn, double lower, double upper, int way)
+{
+    // branch - do bounds
+
+    int i;
+    int found = 0;
+    if (variable_ == iColumn) {
+        printf("odd applyExtra %d\n", iColumn);
+        if (way < 0) {
+            down_[0] = CoinMax(lower, down_[0]);
+            down_[1] = CoinMin(upper, down_[1]);
+            assert (down_[0] <= down_[1]);
+        } else {
+            up_[0] = CoinMax(lower, up_[0]);
+            up_[1] = CoinMin(upper, up_[1]);
+            assert (up_[0] <= up_[1]);
+        }
+        return 0;
+    }
+    int check = (way < 0) ? 0x40000000 : 0;
+    double newLower = lower;
+    double newUpper = upper;
+    for (i = 0; i < numberExtraChangedBounds_; i++) {
+        int variable = variables_[i];
+        if ((variable&0x40000000) == check) {
+            int k = variable & 0x3fffffff;
+            if (k == iColumn) {
+                if ((variable&0x80000000) == 0) {
+                    // lower bound changing
+                    found |= 1;
+                    newBounds_[i] = CoinMax(lower, newBounds_[i]);
+                    newLower = newBounds_[i];
+                } else {
+                    // upper bound changing
+                    found |= 2;
+                    newBounds_[i] = CoinMin(upper, newBounds_[i]);
+                    newUpper = newBounds_[i];
+                }
+            }
+        }
+    }
+    int nAdd = 0;
+    if ((found&2) == 0) {
+        // need to add new upper
+        nAdd++;
+    }
+    if ((found&1) == 0) {
+        // need to add new lower
+        nAdd++;
+    }
+    if (nAdd) {
+        int size = (numberExtraChangedBounds_ + nAdd) * (sizeof(double) + sizeof(int));
+        char * temp = new char [size];
+        double * newBounds = (double *) temp;
+        int * variables = (int *) (newBounds + numberExtraChangedBounds_ + nAdd);
+
+        int i ;
+        for (i = 0; i < numberExtraChangedBounds_; i++) {
+            variables[i] = variables_[i];
+            newBounds[i] = newBounds_[i];
+        }
+        delete [] newBounds_;
+        newBounds_ = newBounds;
+        variables_ = variables;
+        if ((found&2) == 0) {
+            // need to add new upper
+            int variable = iColumn | 0x80000000;
+            variables_[numberExtraChangedBounds_] = variable;
+            newBounds_[numberExtraChangedBounds_++] = newUpper;
+        }
+        if ((found&1) == 0) {
+            // need to add new lower
+            int variable = iColumn;
+            variables_[numberExtraChangedBounds_] = variable;
+            newBounds_[numberExtraChangedBounds_++] = newLower;
+        }
+    }
+
+    return (newUpper >= newLower) ? 0 : 1;
+}
+#endif
+// Print what would happen
+void
+CbcIntegerBranchingObject::print()
+{
+    int iColumn = originalCbcObject_->columnNumber();
+    assert (variable_ == iColumn);
+    if (way_ < 0) {
+        {
+            double olb, oub ;
+            olb = model_->solver()->getColLower()[iColumn] ;
+            oub = model_->solver()->getColUpper()[iColumn] ;
+            printf("CbcInteger would branch down on var %d (int var %d): [%g,%g] => [%g,%g]\n",
+                   iColumn, variable_, olb, oub, down_[0], down_[1]) ;
+        }
+    } else {
+        {
+            double olb, oub ;
+            olb = model_->solver()->getColLower()[iColumn] ;
+            oub = model_->solver()->getColUpper()[iColumn] ;
+            printf("CbcInteger would branch up on var %d (int var %d): [%g,%g] => [%g,%g]\n",
+                   iColumn, variable_, olb, oub, up_[0], up_[1]) ;
+        }
+    }
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+   */
+CbcRangeCompare
+CbcIntegerBranchingObject::compareBranchingObject
+(const CbcBranchingObject* brObj, const bool replaceIfOverlap)
+{
+    const CbcIntegerBranchingObject* br =
+        dynamic_cast<const CbcIntegerBranchingObject*>(brObj);
+    assert(br);
+    double* thisBd = way_ < 0 ? down_ : up_;
+    const double* otherBd = br->way_ < 0 ? br->down_ : br->up_;
+    return CbcCompareRanges(thisBd, otherBd, replaceIfOverlap);
+}
+
diff --git a/cbits/coin/CbcSimpleInteger.hpp b/cbits/coin/CbcSimpleInteger.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSimpleInteger.hpp
@@ -0,0 +1,286 @@
+// $Id: CbcSimpleInteger.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/9/2009-- carved out of CbcBranchActual
+
+#ifndef CbcSimpleInteger_H
+#define CbcSimpleInteger_H
+
+#include "CbcBranchingObject.hpp"
+
+/** Simple branching object for an integer variable
+
+  This object can specify a two-way branch on an integer variable. For each
+  arm of the branch, the upper and lower bounds on the variable can be
+  independently specified.
+
+  Variable_ holds the index of the integer variable in the integerVariable_
+  array of the model.
+*/
+
+class CbcIntegerBranchingObject : public CbcBranchingObject {
+
+public:
+
+    /// Default constructor
+    CbcIntegerBranchingObject ();
+
+    /** Create a standard floor/ceiling branch object
+
+      Specifies a simple two-way branch. Let \p value = x*. One arm of the
+      branch will be lb <= x <= floor(x*), the other ceil(x*) <= x <= ub.
+      Specify way = -1 to set the object state to perform the down arm first,
+      way = 1 for the up arm.
+    */
+    CbcIntegerBranchingObject (CbcModel *model, int variable,
+                               int way , double value) ;
+
+    /** Create a degenerate branch object
+
+      Specifies a `one-way branch'. Calling branch() for this object will
+      always result in lowerValue <= x <= upperValue. Used to fix a variable
+      when lowerValue = upperValue.
+    */
+
+    CbcIntegerBranchingObject (CbcModel *model, int variable, int way,
+                               double lowerValue, double upperValue) ;
+
+    /// Copy constructor
+    CbcIntegerBranchingObject ( const CbcIntegerBranchingObject &);
+
+    /// Assignment operator
+    CbcIntegerBranchingObject & operator= (const CbcIntegerBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    /// Destructor
+    virtual ~CbcIntegerBranchingObject ();
+
+    /// Does part of constructor
+    void fillPart ( int variable, int way , double value) ;
+    using CbcBranchingObject::branch ;
+    /** \brief Sets the bounds for the variable according to the current arm
+           of the branch and advances the object state to the next arm.
+           Returns change in guessed objective on next branch
+    */
+    virtual double branch();
+    /** Update bounds in solver as in 'branch' and update given bounds.
+        branchState is -1 for 'down' +1 for 'up' */
+    virtual void fix(OsiSolverInterface * solver,
+                     double * lower, double * upper,
+                     int branchState) const ;
+    /** Change (tighten) bounds in object to reflect bounds in solver.
+	Return true if now fixed */
+    virtual bool tighten(OsiSolverInterface * ) ;
+
+#ifdef JJF_ZERO
+    // No need to override. Default works fine.
+    /** Reset every information so that the branching object appears to point to
+        the previous child. This method does not need to modify anything in any
+        solver. */
+    virtual void previousBranch();
+#endif
+
+    using CbcBranchingObject::print ;
+    /** \brief Print something about branch - only if log level high
+    */
+    virtual void print();
+
+    /// Lower and upper bounds for down branch
+    inline const double * downBounds() const {
+        return down_;
+    }
+    /// Lower and upper bounds for up branch
+    inline const double * upBounds() const {
+        return up_;
+    }
+    /// Set lower and upper bounds for down branch
+    inline void setDownBounds(const double bounds[2]) {
+        memcpy(down_, bounds, 2*sizeof(double));
+    }
+    /// Set lower and upper bounds for up branch
+    inline void setUpBounds(const double bounds[2]) {
+        memcpy(up_, bounds, 2*sizeof(double));
+    }
+#ifdef FUNNY_BRANCHING
+    /** Which variable (top bit if upper bound changing,
+        next bit if on down branch */
+    inline const int * variables() const {
+        return variables_;
+    }
+    // New bound
+    inline const double * newBounds() const {
+        return newBounds_;
+    }
+    /// Number of bound changes
+    inline int numberExtraChangedBounds() const {
+        return numberExtraChangedBounds_;
+    }
+    /// Just apply extra bounds to one variable - COIN_DBL_MAX ignore
+    int applyExtraBounds(int iColumn, double lower, double upper, int way) ;
+    /// Deactivate bounds for branching
+    void deactivate();
+    /// Are active bounds for branching
+    inline bool active() const {
+        return (down_[1] != -COIN_DBL_MAX);
+    }
+#endif
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return SimpleIntegerBranchObj;
+    }
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+protected:
+    /// Lower [0] and upper [1] bounds for the down arm (way_ = -1)
+    double down_[2];
+    /// Lower [0] and upper [1] bounds for the up arm (way_ = 1)
+    double up_[2];
+#ifdef FUNNY_BRANCHING
+    /** Which variable (top bit if upper bound changing)
+        next bit if changing on down branch only */
+    int * variables_;
+    // New bound
+    double * newBounds_;
+    /// Number of Extra bound changes
+    int numberExtraChangedBounds_;
+#endif
+};
+
+/// Define a single integer class
+
+
+class CbcSimpleInteger : public CbcObject {
+
+public:
+
+    // Default Constructor
+    CbcSimpleInteger ();
+
+    // Useful constructor - passed model and index
+    CbcSimpleInteger (CbcModel * model,  int iColumn, double breakEven = 0.5);
+
+    // Useful constructor - passed model and Osi object
+    CbcSimpleInteger (CbcModel * model,  const OsiSimpleInteger * object);
+
+    // Copy constructor
+    CbcSimpleInteger ( const CbcSimpleInteger &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcSimpleInteger & operator=( const CbcSimpleInteger& rhs);
+
+    // Destructor
+    virtual ~CbcSimpleInteger ();
+    /// Construct an OsiSimpleInteger object
+    OsiSimpleInteger * osiObject() const;
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    using CbcObject::feasibleRegion ;
+    /** Set bounds to fix the variable at the current (integer) value.
+
+      Given an integer value, set the lower and upper bounds to fix the
+      variable. Returns amount it had to move variable.
+    */
+    virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+    /** Create a branching object and indicate which way to branch first.
+
+        The branching object has to know how to create branches (fix
+        variables, etc.)
+    */
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+    /// Fills in a created branching object
+    void fillCreateBranch(CbcIntegerBranchingObject * branching, const OsiBranchingInformation * info, int way) ;
+
+    using CbcObject::solverBranch ;
+    /** Create an OsiSolverBranch object
+
+        This returns NULL if branch not represented by bound changes
+    */
+    virtual OsiSolverBranch * solverBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+    /** Set bounds to fix the variable at the current (integer) value.
+
+      Given an integer value, set the lower and upper bounds to fix the
+      variable. The algorithm takes a bit of care in order to compensate for
+      minor numerical inaccuracy.
+    */
+    virtual void feasibleRegion();
+
+    /** Column number if single column object -1 otherwise,
+        so returns >= 0
+        Used by heuristics
+    */
+    virtual int columnNumber() const;
+    /// Set column number
+    inline void setColumnNumber(int value) {
+        columnNumber_ = value;
+    }
+
+    /** Reset variable bounds to their original values.
+
+      Bounds may be tightened, so it may be good to be able to set this info in object.
+     */
+    virtual void resetBounds(const OsiSolverInterface * solver) ;
+
+    /**  Change column numbers after preprocessing
+     */
+    virtual void resetSequenceEtc(int numberColumns, const int * originalColumns) ;
+    /// Original bounds
+    inline double originalLowerBound() const {
+        return originalLower_;
+    }
+    inline void setOriginalLowerBound(double value) {
+        originalLower_ = value;
+    }
+    inline double originalUpperBound() const {
+        return originalUpper_;
+    }
+    inline void setOriginalUpperBound(double value) {
+        originalUpper_ = value;
+    }
+    /// Breakeven e.g 0.7 -> >= 0.7 go up first
+    inline double breakEven() const {
+        return breakEven_;
+    }
+    /// Set breakeven e.g 0.7 -> >= 0.7 go up first
+    inline void setBreakEven(double value) {
+        breakEven_ = value;
+    }
+
+
+protected:
+    /// data
+
+    /// Original lower bound
+    double originalLower_;
+    /// Original upper bound
+    double originalUpper_;
+    /// Breakeven i.e. >= this preferred is up
+    double breakEven_;
+    /// Column number in model
+    int columnNumber_;
+    /// If -1 down always chosen first, +1 up always, 0 normal
+    int preferredWay_;
+};
+#endif
+
diff --git a/cbits/coin/CbcSimpleIntegerDynamicPseudoCost.cpp b/cbits/coin/CbcSimpleIntegerDynamicPseudoCost.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSimpleIntegerDynamicPseudoCost.cpp
@@ -0,0 +1,1400 @@
+// $Id: CbcSimpleIntegerDynamicPseudoCost.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/17/2009 - carved out of CbcBranchDynamic
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+//#define TRACE_ONE 19
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcBranchDynamic.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+#include "CbcSimpleIntegerDynamicPseudoCost.hpp"
+#ifdef COIN_DEVELOP
+typedef struct {
+    double sumUp_;
+    double upEst_; // or change in obj in update
+    double sumDown_;
+    double downEst_; // or movement in value in update
+    int sequence_;
+    int numberUp_;
+    int numberUpInf_;
+    int numberDown_;
+    int numberDownInf_;
+    char where_;
+    char status_;
+} History;
+History * history = NULL;
+int numberHistory = 0;
+int maxHistory = 0;
+bool getHistoryStatistics_ = true;
+static void increaseHistory()
+{
+    if (numberHistory == maxHistory) {
+        maxHistory = 100 + (3 * maxHistory) / 2;
+        History * temp = new History [maxHistory];
+        memcpy(temp, history, numberHistory*sizeof(History));
+        delete [] history;
+        history = temp;
+    }
+}
+static bool addRecord(History newOne)
+{
+    //if (!getHistoryStatistics_)
+    return false;
+    bool fromCompare = false;
+    int i;
+    for ( i = numberHistory - 1; i >= 0; i--) {
+        if (newOne.sequence_ != history[i].sequence_)
+            continue;
+        if (newOne.where_ != history[i].where_)
+            continue;
+        if (newOne.numberUp_ != history[i].numberUp_)
+            continue;
+        if (newOne.sumUp_ != history[i].sumUp_)
+            continue;
+        if (newOne.numberUpInf_ != history[i].numberUpInf_)
+            continue;
+        if (newOne.upEst_ != history[i].upEst_)
+            continue;
+        if (newOne.numberDown_ != history[i].numberDown_)
+            continue;
+        if (newOne.sumDown_ != history[i].sumDown_)
+            continue;
+        if (newOne.numberDownInf_ != history[i].numberDownInf_)
+            continue;
+        if (newOne.downEst_ != history[i].downEst_)
+            continue;
+        // If B knock out previous B
+        if (newOne.where_ == 'C') {
+            fromCompare = true;
+            if (newOne.status_ == 'B') {
+                int j;
+                for (j = i - 1; j >= 0; j--) {
+                    if (history[j].where_ == 'C') {
+                        if (history[j].status_ == 'I') {
+                            break;
+                        } else if (history[j].status_ == 'B') {
+                            history[j].status_ = ' ';
+                            break;
+                        }
+                    }
+                }
+            }
+            break;
+        }
+    }
+    if (i == -1 || fromCompare) {
+        //add
+        increaseHistory();
+        history[numberHistory++] = newOne;
+        return true;
+    } else {
+        return false;
+    }
+}
+#endif
+
+/** Default Constructor
+
+  Equivalent to an unspecified binary variable.
+*/
+CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost ()
+        : CbcSimpleInteger(),
+        downDynamicPseudoCost_(1.0e-5),
+        upDynamicPseudoCost_(1.0e-5),
+        upDownSeparator_(-1.0),
+        sumDownCost_(0.0),
+        sumUpCost_(0.0),
+        sumDownChange_(0.0),
+        sumUpChange_(0.0),
+        downShadowPrice_(0.0),
+        upShadowPrice_(0.0),
+        sumDownDecrease_(0.0),
+        sumUpDecrease_(0.0),
+        lastDownCost_(0.0),
+        lastUpCost_(0.0),
+        lastDownDecrease_(0),
+        lastUpDecrease_(0),
+        numberTimesDown_(0),
+        numberTimesUp_(0),
+        numberTimesDownInfeasible_(0),
+        numberTimesUpInfeasible_(0),
+        numberBeforeTrust_(0),
+        numberTimesDownLocalFixed_(0),
+        numberTimesUpLocalFixed_(0),
+        numberTimesDownTotalFixed_(0.0),
+        numberTimesUpTotalFixed_(0.0),
+        numberTimesProbingTotal_(0),
+        method_(0)
+{
+}
+
+/** Useful constructor
+
+  Loads dynamic upper & lower bounds for the specified variable.
+*/
+CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
+        int iColumn, double breakEven)
+        : CbcSimpleInteger(model, iColumn, breakEven),
+        upDownSeparator_(-1.0),
+        sumDownCost_(0.0),
+        sumUpCost_(0.0),
+        sumDownChange_(0.0),
+        sumUpChange_(0.0),
+        downShadowPrice_(0.0),
+        upShadowPrice_(0.0),
+        sumDownDecrease_(0.0),
+        sumUpDecrease_(0.0),
+        lastDownCost_(0.0),
+        lastUpCost_(0.0),
+        lastDownDecrease_(0),
+        lastUpDecrease_(0),
+        numberTimesDown_(0),
+        numberTimesUp_(0),
+        numberTimesDownInfeasible_(0),
+        numberTimesUpInfeasible_(0),
+        numberBeforeTrust_(0),
+        numberTimesDownLocalFixed_(0),
+        numberTimesUpLocalFixed_(0),
+        numberTimesDownTotalFixed_(0.0),
+        numberTimesUpTotalFixed_(0.0),
+        numberTimesProbingTotal_(0),
+        method_(0)
+{
+    const double * cost = model->getObjCoefficients();
+    double costValue = CoinMax(1.0e-5, fabs(cost[iColumn]));
+    // treat as if will cost what it says up
+    upDynamicPseudoCost_ = costValue;
+    // and balance at breakeven
+    downDynamicPseudoCost_ = ((1.0 - breakEven_) * upDynamicPseudoCost_) / breakEven_;
+    // so initial will have some effect
+    sumUpCost_ = 2.0 * upDynamicPseudoCost_;
+    sumUpChange_ = 2.0;
+    numberTimesUp_ = 2;
+    sumDownCost_ = 2.0 * downDynamicPseudoCost_;
+    sumDownChange_ = 2.0;
+    numberTimesDown_ = 2;
+#if TYPE2==0
+    // No
+    sumUpCost_ = 0.0;
+    sumUpChange_ = 0.0;
+    numberTimesUp_ = 0;
+    sumDownCost_ = 0.0;
+    sumDownChange_ = 0.0;
+    numberTimesDown_ = 0;
+#else
+    sumUpCost_ = 1.0 * upDynamicPseudoCost_;
+    sumUpChange_ = 1.0;
+    numberTimesUp_ = 1;
+    sumDownCost_ = 1.0 * downDynamicPseudoCost_;
+    sumDownChange_ = 1.0;
+    numberTimesDown_ = 1;
+#endif
+}
+
+/** Useful constructor
+
+  Loads dynamic upper & lower bounds for the specified variable.
+*/
+CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
+        int iColumn, double downDynamicPseudoCost,
+        double upDynamicPseudoCost)
+        : CbcSimpleInteger(model, iColumn),
+        upDownSeparator_(-1.0),
+        sumDownCost_(0.0),
+        sumUpCost_(0.0),
+        sumDownChange_(0.0),
+        sumUpChange_(0.0),
+        downShadowPrice_(0.0),
+        upShadowPrice_(0.0),
+        sumDownDecrease_(0.0),
+        sumUpDecrease_(0.0),
+        lastDownCost_(0.0),
+        lastUpCost_(0.0),
+        lastDownDecrease_(0),
+        lastUpDecrease_(0),
+        numberTimesDown_(0),
+        numberTimesUp_(0),
+        numberTimesDownInfeasible_(0),
+        numberTimesUpInfeasible_(0),
+        numberBeforeTrust_(0),
+        numberTimesDownLocalFixed_(0),
+        numberTimesUpLocalFixed_(0),
+        numberTimesDownTotalFixed_(0.0),
+        numberTimesUpTotalFixed_(0.0),
+        numberTimesProbingTotal_(0),
+        method_(0)
+{
+    downDynamicPseudoCost_ = downDynamicPseudoCost;
+    upDynamicPseudoCost_ = upDynamicPseudoCost;
+    breakEven_ = upDynamicPseudoCost_ / (upDynamicPseudoCost_ + downDynamicPseudoCost_);
+    // so initial will have some effect
+    sumUpCost_ = 2.0 * upDynamicPseudoCost_;
+    sumUpChange_ = 2.0;
+    numberTimesUp_ = 2;
+    sumDownCost_ = 2.0 * downDynamicPseudoCost_;
+    sumDownChange_ = 2.0;
+    numberTimesDown_ = 2;
+#if TYPE2==0
+    // No
+    sumUpCost_ = 0.0;
+    sumUpChange_ = 0.0;
+    numberTimesUp_ = 0;
+    sumDownCost_ = 0.0;
+    sumDownChange_ = 0.0;
+    numberTimesDown_ = 0;
+    sumUpCost_ = 1.0e-4 * upDynamicPseudoCost_;
+    sumDownCost_ = 1.0e-4 * downDynamicPseudoCost_;
+#else
+    sumUpCost_ = 1.0 * upDynamicPseudoCost_;
+    sumUpChange_ = 1.0;
+    numberTimesUp_ = 1;
+    sumDownCost_ = 1.0 * downDynamicPseudoCost_;
+    sumDownChange_ = 1.0;
+    numberTimesDown_ = 1;
+#endif
+}
+/** Useful constructor
+
+  Loads dynamic upper & lower bounds for the specified variable.
+*/
+CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,
+        int /*dummy*/,
+        int iColumn, double downDynamicPseudoCost,
+        double upDynamicPseudoCost)
+{
+    CbcSimpleIntegerDynamicPseudoCost(model, iColumn, downDynamicPseudoCost, upDynamicPseudoCost);
+}
+
+// Copy constructor
+CbcSimpleIntegerDynamicPseudoCost::CbcSimpleIntegerDynamicPseudoCost ( const CbcSimpleIntegerDynamicPseudoCost & rhs)
+        : CbcSimpleInteger(rhs),
+        downDynamicPseudoCost_(rhs.downDynamicPseudoCost_),
+        upDynamicPseudoCost_(rhs.upDynamicPseudoCost_),
+        upDownSeparator_(rhs.upDownSeparator_),
+        sumDownCost_(rhs.sumDownCost_),
+        sumUpCost_(rhs.sumUpCost_),
+        sumDownChange_(rhs.sumDownChange_),
+        sumUpChange_(rhs.sumUpChange_),
+        downShadowPrice_(rhs.downShadowPrice_),
+        upShadowPrice_(rhs.upShadowPrice_),
+        sumDownDecrease_(rhs.sumDownDecrease_),
+        sumUpDecrease_(rhs.sumUpDecrease_),
+        lastDownCost_(rhs.lastDownCost_),
+        lastUpCost_(rhs.lastUpCost_),
+        lastDownDecrease_(rhs.lastDownDecrease_),
+        lastUpDecrease_(rhs.lastUpDecrease_),
+        numberTimesDown_(rhs.numberTimesDown_),
+        numberTimesUp_(rhs.numberTimesUp_),
+        numberTimesDownInfeasible_(rhs.numberTimesDownInfeasible_),
+        numberTimesUpInfeasible_(rhs.numberTimesUpInfeasible_),
+        numberBeforeTrust_(rhs.numberBeforeTrust_),
+        numberTimesDownLocalFixed_(rhs.numberTimesDownLocalFixed_),
+        numberTimesUpLocalFixed_(rhs.numberTimesUpLocalFixed_),
+        numberTimesDownTotalFixed_(rhs.numberTimesDownTotalFixed_),
+        numberTimesUpTotalFixed_(rhs.numberTimesUpTotalFixed_),
+        numberTimesProbingTotal_(rhs.numberTimesProbingTotal_),
+        method_(rhs.method_)
+
+{
+}
+
+// Clone
+CbcObject *
+CbcSimpleIntegerDynamicPseudoCost::clone() const
+{
+    return new CbcSimpleIntegerDynamicPseudoCost(*this);
+}
+
+// Assignment operator
+CbcSimpleIntegerDynamicPseudoCost &
+CbcSimpleIntegerDynamicPseudoCost::operator=( const CbcSimpleIntegerDynamicPseudoCost & rhs)
+{
+    if (this != &rhs) {
+        CbcSimpleInteger::operator=(rhs);
+        downDynamicPseudoCost_ = rhs.downDynamicPseudoCost_;
+        upDynamicPseudoCost_ = rhs.upDynamicPseudoCost_;
+        upDownSeparator_ = rhs.upDownSeparator_;
+        sumDownCost_ = rhs.sumDownCost_;
+        sumUpCost_ = rhs.sumUpCost_;
+        sumDownChange_ = rhs.sumDownChange_;
+        sumUpChange_ = rhs.sumUpChange_;
+        downShadowPrice_ = rhs.downShadowPrice_;
+        upShadowPrice_ = rhs.upShadowPrice_;
+        sumDownDecrease_ = rhs.sumDownDecrease_;
+        sumUpDecrease_ = rhs.sumUpDecrease_;
+        lastDownCost_ = rhs.lastDownCost_;
+        lastUpCost_ = rhs.lastUpCost_;
+        lastDownDecrease_ = rhs.lastDownDecrease_;
+        lastUpDecrease_ = rhs.lastUpDecrease_;
+        numberTimesDown_ = rhs.numberTimesDown_;
+        numberTimesUp_ = rhs.numberTimesUp_;
+        numberTimesDownInfeasible_ = rhs.numberTimesDownInfeasible_;
+        numberTimesUpInfeasible_ = rhs.numberTimesUpInfeasible_;
+        numberBeforeTrust_ = rhs.numberBeforeTrust_;
+        numberTimesDownLocalFixed_ = rhs.numberTimesDownLocalFixed_;
+        numberTimesUpLocalFixed_ = rhs.numberTimesUpLocalFixed_;
+        numberTimesDownTotalFixed_ = rhs.numberTimesDownTotalFixed_;
+        numberTimesUpTotalFixed_ = rhs.numberTimesUpTotalFixed_;
+        numberTimesProbingTotal_ = rhs.numberTimesProbingTotal_;
+        method_ = rhs.method_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcSimpleIntegerDynamicPseudoCost::~CbcSimpleIntegerDynamicPseudoCost ()
+{
+}
+// Copy some information i.e. just variable stuff
+void
+CbcSimpleIntegerDynamicPseudoCost::copySome(const CbcSimpleIntegerDynamicPseudoCost * otherObject)
+{
+    downDynamicPseudoCost_ = otherObject->downDynamicPseudoCost_;
+    upDynamicPseudoCost_ = otherObject->upDynamicPseudoCost_;
+    sumDownCost_ = otherObject->sumDownCost_;
+    sumUpCost_ = otherObject->sumUpCost_;
+    sumDownChange_ = otherObject->sumDownChange_;
+    sumUpChange_ = otherObject->sumUpChange_;
+    downShadowPrice_ = otherObject->downShadowPrice_;
+    upShadowPrice_ = otherObject->upShadowPrice_;
+    sumDownDecrease_ = otherObject->sumDownDecrease_;
+    sumUpDecrease_ = otherObject->sumUpDecrease_;
+    lastDownCost_ = otherObject->lastDownCost_;
+    lastUpCost_ = otherObject->lastUpCost_;
+    lastDownDecrease_ = otherObject->lastDownDecrease_;
+    lastUpDecrease_ = otherObject->lastUpDecrease_;
+    numberTimesDown_ = otherObject->numberTimesDown_;
+    numberTimesUp_ = otherObject->numberTimesUp_;
+    numberTimesDownInfeasible_ = otherObject->numberTimesDownInfeasible_;
+    numberTimesUpInfeasible_ = otherObject->numberTimesUpInfeasible_;
+    numberTimesDownLocalFixed_ = otherObject->numberTimesDownLocalFixed_;
+    numberTimesUpLocalFixed_ = otherObject->numberTimesUpLocalFixed_;
+    numberTimesDownTotalFixed_ = otherObject->numberTimesDownTotalFixed_;
+    numberTimesUpTotalFixed_ = otherObject->numberTimesUpTotalFixed_;
+    numberTimesProbingTotal_ = otherObject->numberTimesProbingTotal_;
+}
+// Updates stuff like pseudocosts before threads
+void
+CbcSimpleIntegerDynamicPseudoCost::updateBefore(const OsiObject * rhs)
+{
+#ifndef NDEBUG
+    const CbcSimpleIntegerDynamicPseudoCost * rhsObject =
+        dynamic_cast <const CbcSimpleIntegerDynamicPseudoCost *>(rhs) ;
+    assert (rhsObject);
+#else
+    const CbcSimpleIntegerDynamicPseudoCost * rhsObject =
+        static_cast <const CbcSimpleIntegerDynamicPseudoCost *>(rhs) ;
+#endif
+    copySome(rhsObject);
+}
+// Updates stuff like pseudocosts after threads finished
+void
+CbcSimpleIntegerDynamicPseudoCost::updateAfter(const OsiObject * rhs, const OsiObject * baseObjectX)
+{
+#ifndef NDEBUG
+    const CbcSimpleIntegerDynamicPseudoCost * rhsObject =
+        dynamic_cast <const CbcSimpleIntegerDynamicPseudoCost *>(rhs) ;
+    assert (rhsObject);
+    const CbcSimpleIntegerDynamicPseudoCost * baseObject =
+        dynamic_cast <const CbcSimpleIntegerDynamicPseudoCost *>(baseObjectX) ;
+    assert (baseObject);
+#else
+    const CbcSimpleIntegerDynamicPseudoCost * rhsObject =
+        static_cast <const CbcSimpleIntegerDynamicPseudoCost *>(rhs) ;
+    const CbcSimpleIntegerDynamicPseudoCost * baseObject =
+        static_cast <const CbcSimpleIntegerDynamicPseudoCost *>(baseObjectX) ;
+#endif
+    // compute current
+    double sumDown = downDynamicPseudoCost_ * numberTimesDown_;
+    sumDown -= baseObject->downDynamicPseudoCost_ * baseObject->numberTimesDown_;
+    sumDown = CoinMax(sumDown, 0.0);
+    sumDown += rhsObject->downDynamicPseudoCost_ * rhsObject->numberTimesDown_;
+    assert (rhsObject->numberTimesDown_ >= baseObject->numberTimesDown_);
+    assert (rhsObject->numberTimesDownInfeasible_ >= baseObject->numberTimesDownInfeasible_);
+    assert( rhsObject->sumDownCost_ >= baseObject->sumDownCost_);
+    double sumUp = upDynamicPseudoCost_ * numberTimesUp_;
+    sumUp -= baseObject->upDynamicPseudoCost_ * baseObject->numberTimesUp_;
+    sumUp = CoinMax(sumUp, 0.0);
+    sumUp += rhsObject->upDynamicPseudoCost_ * rhsObject->numberTimesUp_;
+    assert (rhsObject->numberTimesUp_ >= baseObject->numberTimesUp_);
+    assert (rhsObject->numberTimesUpInfeasible_ >= baseObject->numberTimesUpInfeasible_);
+    assert( rhsObject->sumUpCost_ >= baseObject->sumUpCost_);
+    sumDownCost_ += rhsObject->sumDownCost_ - baseObject->sumDownCost_;
+    sumUpCost_ += rhsObject->sumUpCost_ - baseObject->sumUpCost_;
+    sumDownChange_ += rhsObject->sumDownChange_ - baseObject->sumDownChange_;
+    sumUpChange_ += rhsObject->sumUpChange_ - baseObject->sumUpChange_;
+    downShadowPrice_ = 0.0;
+    upShadowPrice_ = 0.0;
+    sumDownDecrease_ += rhsObject->sumDownDecrease_ - baseObject->sumDownDecrease_;
+    sumUpDecrease_ += rhsObject->sumUpDecrease_ - baseObject->sumUpDecrease_;
+    lastDownCost_ += rhsObject->lastDownCost_ - baseObject->lastDownCost_;
+    lastUpCost_ += rhsObject->lastUpCost_ - baseObject->lastUpCost_;
+    lastDownDecrease_ += rhsObject->lastDownDecrease_ - baseObject->lastDownDecrease_;
+    lastUpDecrease_ += rhsObject->lastUpDecrease_ - baseObject->lastUpDecrease_;
+    numberTimesDown_ += rhsObject->numberTimesDown_ - baseObject->numberTimesDown_;
+    numberTimesUp_ += rhsObject->numberTimesUp_ - baseObject->numberTimesUp_;
+    numberTimesDownInfeasible_ += rhsObject->numberTimesDownInfeasible_ - baseObject->numberTimesDownInfeasible_;
+    numberTimesUpInfeasible_ += rhsObject->numberTimesUpInfeasible_ - baseObject->numberTimesUpInfeasible_;
+    numberTimesDownLocalFixed_ += rhsObject->numberTimesDownLocalFixed_ - baseObject->numberTimesDownLocalFixed_;
+    numberTimesUpLocalFixed_ += rhsObject->numberTimesUpLocalFixed_ - baseObject->numberTimesUpLocalFixed_;
+    numberTimesDownTotalFixed_ += rhsObject->numberTimesDownTotalFixed_ - baseObject->numberTimesDownTotalFixed_;
+    numberTimesUpTotalFixed_ += rhsObject->numberTimesUpTotalFixed_ - baseObject->numberTimesUpTotalFixed_;
+    numberTimesProbingTotal_ += rhsObject->numberTimesProbingTotal_ - baseObject->numberTimesProbingTotal_;
+    if (numberTimesDown_ > 0) {
+        setDownDynamicPseudoCost(sumDown / static_cast<double> (numberTimesDown_));
+    }
+    if (numberTimesUp_ > 0) {
+        setUpDynamicPseudoCost(sumUp / static_cast<double> (numberTimesUp_));
+    }
+    //printf("XX %d down %d %d %g up %d %d %g\n",columnNumber_,numberTimesDown_,numberTimesDownInfeasible_,downDynamicPseudoCost_,
+    // numberTimesUp_,numberTimesUpInfeasible_,upDynamicPseudoCost_);
+    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
+}
+// Same - returns true if contents match(ish)
+bool
+CbcSimpleIntegerDynamicPseudoCost::same(const CbcSimpleIntegerDynamicPseudoCost * otherObject) const
+{
+    bool okay = true;
+    if (downDynamicPseudoCost_ != otherObject->downDynamicPseudoCost_)
+        okay = false;
+    if (upDynamicPseudoCost_ != otherObject->upDynamicPseudoCost_)
+        okay = false;
+    if (sumDownCost_ != otherObject->sumDownCost_)
+        okay = false;
+    if (sumUpCost_ != otherObject->sumUpCost_)
+        okay = false;
+    if (sumDownChange_ != otherObject->sumDownChange_)
+        okay = false;
+    if (sumUpChange_ != otherObject->sumUpChange_)
+        okay = false;
+    if (downShadowPrice_ != otherObject->downShadowPrice_)
+        okay = false;
+    if (upShadowPrice_ != otherObject->upShadowPrice_)
+        okay = false;
+    if (sumDownDecrease_ != otherObject->sumDownDecrease_)
+        okay = false;
+    if (sumUpDecrease_ != otherObject->sumUpDecrease_)
+        okay = false;
+    if (lastDownCost_ != otherObject->lastDownCost_)
+        okay = false;
+    if (lastUpCost_ != otherObject->lastUpCost_)
+        okay = false;
+    if (lastDownDecrease_ != otherObject->lastDownDecrease_)
+        okay = false;
+    if (lastUpDecrease_ != otherObject->lastUpDecrease_)
+        okay = false;
+    if (numberTimesDown_ != otherObject->numberTimesDown_)
+        okay = false;
+    if (numberTimesUp_ != otherObject->numberTimesUp_)
+        okay = false;
+    if (numberTimesDownInfeasible_ != otherObject->numberTimesDownInfeasible_)
+        okay = false;
+    if (numberTimesUpInfeasible_ != otherObject->numberTimesUpInfeasible_)
+        okay = false;
+    if (numberTimesDownLocalFixed_ != otherObject->numberTimesDownLocalFixed_)
+        okay = false;
+    if (numberTimesUpLocalFixed_ != otherObject->numberTimesUpLocalFixed_)
+        okay = false;
+    if (numberTimesDownTotalFixed_ != otherObject->numberTimesDownTotalFixed_)
+        okay = false;
+    if (numberTimesUpTotalFixed_ != otherObject->numberTimesUpTotalFixed_)
+        okay = false;
+    if (numberTimesProbingTotal_ != otherObject->numberTimesProbingTotal_)
+        okay = false;
+    return okay;
+}
+/* Create an OsiSolverBranch object
+
+This returns NULL if branch not represented by bound changes
+*/
+OsiSolverBranch *
+CbcSimpleIntegerDynamicPseudoCost::solverBranch() const
+{
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    assert (upper[columnNumber_] > lower[columnNumber_]);
+#ifndef NDEBUG
+    double nearest = floor(value + 0.5);
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    assert (fabs(value - nearest) > integerTolerance);
+#endif
+    OsiSolverBranch * branch = new OsiSolverBranch();
+    branch->addBranch(columnNumber_, value);
+    return branch;
+}
+//#define FUNNY_BRANCHING
+double
+CbcSimpleIntegerDynamicPseudoCost::infeasibility(const OsiBranchingInformation * info,
+        int &preferredWay) const
+{
+    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
+    const double * solution = model_->testSolution();
+    const double * lower = model_->getCbcColLower();
+    const double * upper = model_->getCbcColUpper();
+#ifdef FUNNY_BRANCHING2
+    const double * dj = model_->getCbcReducedCost();
+    double djValue = dj[columnNumber_];
+    lastDownDecrease_++;
+    if (djValue > 1.0e-6) {
+        // wants to go down
+        if (true || lower[columnNumber_] > originalLower_) {
+            // Lower bound active
+            lastUpDecrease_++;
+        }
+    } else if (djValue < -1.0e-6) {
+        // wants to go up
+        if (true || upper[columnNumber_] < originalUpper_) {
+            // Upper bound active
+            lastUpDecrease_++;
+        }
+    }
+#endif
+    if (upper[columnNumber_] == lower[columnNumber_]) {
+        // fixed
+        preferredWay = 1;
+        return 0.0;
+    }
+    assert (breakEven_ > 0.0 && breakEven_ < 1.0);
+	/*
+	  Find nearest integer, and integers above and below current value.
+
+	  Given that we've already forced value within bounds, if
+	  (current value)+(integer tolerance) > (upper bound)
+	  shouldn't we declare this variable integer?
+	*/
+
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    /*printf("%d %g %g %g %g\n",columnNumber_,value,lower[columnNumber_],
+      solution[columnNumber_],upper[columnNumber_]);*/
+    double nearest = floor(value + 0.5);
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double below = floor(value + integerTolerance);
+    double above = below + 1.0;
+    if (above > upper[columnNumber_]) {
+        above = below;
+        below = above - 1;
+    }
+#if INFEAS==1
+/*
+  Why do we inflate the distance to the cutoff by a factor of 10 for
+  values that could be considered reachable? Why do we add 100 for values
+  larger than 1e20?
+*/
+    double distanceToCutoff = 0.0;
+    double objectiveValue = model_->getCurrentMinimizationObjValue();
+    distanceToCutoff =  model_->getCutoff()  - objectiveValue;
+    if (distanceToCutoff < 1.0e20)
+        distanceToCutoff *= 10.0;
+    else
+        distanceToCutoff = 1.0e2 + fabs(objectiveValue);
+    distanceToCutoff = CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(objectiveValue)));
+#endif
+    double sum;
+#ifndef INFEAS_MULTIPLIER 
+#define INFEAS_MULTIPLIER 1.0
+#endif
+    double number;
+    double downCost = CoinMax(value - below, 0.0);
+#if TYPE2==0
+    sum = sumDownCost_;
+    number = numberTimesDown_;
+#if INFEAS==1
+    sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible_ * CoinMax(distanceToCutoff / (downCost + 1.0e-12), sumDownCost_);
+#endif
+#elif TYPE2==1
+    sum = sumDownCost_;
+    number = sumDownChange_;
+#if INFEAS==1
+    sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible_ * CoinMax(distanceToCutoff / (downCost + 1.0e-12), sumDownCost_);
+#endif
+#elif TYPE2==2
+    abort();
+#if INFEAS==1
+    sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible_ * (distanceToCutoff / (downCost + 1.0e-12));
+#endif
+#endif
+#if MOD_SHADOW>0
+    if (!downShadowPrice_) {
+        if (number > 0.0)
+            downCost *= sum / number;
+        else
+            downCost  *=  downDynamicPseudoCost_;
+    } else if (downShadowPrice_ > 0.0) {
+        downCost *= downShadowPrice_;
+    } else {
+        downCost *= (downDynamicPseudoCost_ - downShadowPrice_);
+    }
+#else
+    if (downShadowPrice_ <= 0.0) {
+        if (number > 0.0)
+            downCost *= sum / number;
+        else
+            downCost  *=  downDynamicPseudoCost_;
+    } else {
+        downCost *= downShadowPrice_;
+    }
+#endif
+    double upCost = CoinMax((above - value), 0.0);
+#if TYPE2==0
+    sum = sumUpCost_;
+    number = numberTimesUp_;
+#if INFEAS==1
+    sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible_ * CoinMax(distanceToCutoff / (upCost + 1.0e-12), sumUpCost_);
+#endif
+#elif TYPE2==1
+    sum = sumUpCost_;
+    number = sumUpChange_;
+#if INFEAS==1
+    sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible_ * CoinMax(distanceToCutoff / (upCost + 1.0e-12), sumUpCost_);
+#endif
+#elif TYPE2==1
+    abort();
+#if INFEAS==1
+    sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible_ * (distanceToCutoff / (upCost + 1.0e-12));
+#endif
+#endif
+#if MOD_SHADOW>0
+    if (!upShadowPrice_) {
+        if (number > 0.0)
+            upCost *= sum / number;
+        else
+            upCost  *=  upDynamicPseudoCost_;
+    } else if (upShadowPrice_ > 0.0) {
+        upCost *= upShadowPrice_;
+    } else {
+        upCost *= (upDynamicPseudoCost_ - upShadowPrice_);
+    }
+#else
+    if (upShadowPrice_ <= 0.0) {
+        if (number > 0.0)
+            upCost *= sum / number;
+        else
+            upCost  *=  upDynamicPseudoCost_;
+    } else {
+        upCost *= upShadowPrice_;
+    }
+#endif
+    if (downCost >= upCost)
+        preferredWay = 1;
+    else
+        preferredWay = -1;
+    // See if up down choice set
+    if (upDownSeparator_ > 0.0) {
+        preferredWay = (value - below >= upDownSeparator_) ? 1 : -1;
+    }
+#ifdef FUNNY_BRANCHING2
+    if (fabs(value - nearest) > integerTolerance) {
+        double ratio = (100.0 + lastUpDecrease_) / (100.0 + lastDownDecrease_);
+        downCost *= ratio;
+        upCost *= ratio;
+        if ((lastUpDecrease_ % 100) == -1)
+            printf("col %d total %d djtimes %d\n",
+                   columnNumber_, lastDownDecrease_, lastUpDecrease_);
+    }
+#endif
+    if (preferredWay_)
+        preferredWay = preferredWay_;
+    if (info->hotstartSolution_) {
+        double targetValue = info->hotstartSolution_[columnNumber_];
+        if (value > targetValue)
+            preferredWay = -1;
+        else
+            preferredWay = 1;
+    }
+    if (fabs(value - nearest) <= integerTolerance) {
+        if (priority_ != -999)
+            return 0.0;
+        else
+            return 1.0e-13;
+    } else {
+        int stateOfSearch = model_->stateOfSearch() % 10;
+        double returnValue = 0.0;
+        double minValue = CoinMin(downCost, upCost);
+        double maxValue = CoinMax(downCost, upCost);
+#ifdef COIN_DEVELOP
+        char where;
+#endif
+        // was <= 10
+        //if (stateOfSearch<=1||model_->currentNode()->depth()<=-10 /* was ||maxValue>0.2*distanceToCutoff*/) {
+        if (stateOfSearch <= 2) {
+            // no branching solution
+#ifdef COIN_DEVELOP
+            where = 'i';
+#endif
+            returnValue = WEIGHT_BEFORE * minValue + (1.0 - WEIGHT_BEFORE) * maxValue;
+            if (0) {
+                double sum;
+                int number;
+                double downCost2 = CoinMax(value - below, 0.0);
+                sum = sumDownCost_;
+                number = numberTimesDown_;
+                if (number > 0)
+                    downCost2 *= sum / static_cast<double> (number);
+                else
+                    downCost2  *=  downDynamicPseudoCost_;
+                double upCost2 = CoinMax((above - value), 0.0);
+                sum = sumUpCost_;
+                number = numberTimesUp_;
+                if (number > 0)
+                    upCost2 *= sum / static_cast<double> (number);
+                else
+                    upCost2  *=  upDynamicPseudoCost_;
+                double minValue2 = CoinMin(downCost2, upCost2);
+                double maxValue2 = CoinMax(downCost2, upCost2);
+                printf("%d value %g downC %g upC %g minV %g maxV %g downC2 %g upC2 %g minV2 %g maxV2 %g\n",
+                       columnNumber_, value, downCost, upCost, minValue, maxValue,
+                       downCost2, upCost2, minValue2, maxValue2);
+            }
+        } else {
+            // some solution
+#ifdef COIN_DEVELOP
+            where = 'I';
+#endif
+#ifndef WEIGHT_PRODUCT
+            returnValue = WEIGHT_AFTER * minValue + (1.0 - WEIGHT_AFTER) * maxValue;
+#else
+            double minProductWeight = model_->getDblParam(CbcModel::CbcSmallChange);
+            returnValue = CoinMax(minValue, minProductWeight) * CoinMax(maxValue, minProductWeight);
+            //returnValue += minProductWeight*minValue;
+#endif
+        }
+        if (numberTimesUp_ < numberBeforeTrust_ ||
+                numberTimesDown_ < numberBeforeTrust_) {
+            //if (returnValue<1.0e10)
+            //returnValue += 1.0e12;
+            //else
+            returnValue *= 1.0e3;
+            if (!numberTimesUp_ && !numberTimesDown_)
+                returnValue *= 1.0e10;
+        }
+        //if (fabs(value-0.5)<1.0e-5) {
+        //returnValue = 3.0*returnValue + 0.2;
+        //} else if (value>0.9) {
+        //returnValue = 2.0*returnValue + 0.1;
+        //}
+        if (method_ == 1) {
+            // probing
+            // average
+            double up = 1.0e-15;
+            double down = 1.0e-15;
+            if (numberTimesProbingTotal_) {
+                up += numberTimesUpTotalFixed_ / static_cast<double> (numberTimesProbingTotal_);
+                down += numberTimesDownTotalFixed_ / static_cast<double> (numberTimesProbingTotal_);
+            }
+            returnValue = 1 + 10.0 * CoinMin(numberTimesDownLocalFixed_, numberTimesUpLocalFixed_) +
+                          CoinMin(down, up);
+            returnValue *= 1.0e-3;
+        }
+#ifdef COIN_DEVELOP
+        History hist;
+        hist.where_ = where;
+        hist.status_ = ' ';
+        hist.sequence_ = columnNumber_;
+        hist.numberUp_ = numberTimesUp_;
+        hist.numberUpInf_ = numberTimesUpInfeasible_;
+        hist.sumUp_ = sumUpCost_;
+        hist.upEst_ = upCost;
+        hist.numberDown_ = numberTimesDown_;
+        hist.numberDownInf_ = numberTimesDownInfeasible_;
+        hist.sumDown_ = sumDownCost_;
+        hist.downEst_ = downCost;
+        if (stateOfSearch)
+            addRecord(hist);
+#endif
+        return CoinMax(returnValue, 1.0e-15);
+    }
+}
+// Creates a branching object
+CbcBranchingObject *
+CbcSimpleIntegerDynamicPseudoCost::createCbcBranch(OsiSolverInterface * /*solver*/,
+        const OsiBranchingInformation * info, int way)
+{
+    double value = info->solution_[columnNumber_];
+    value = CoinMax(value, info->lower_[columnNumber_]);
+    value = CoinMin(value, info->upper_[columnNumber_]);
+    assert (info->upper_[columnNumber_] > info->lower_[columnNumber_]);
+    if (!info->hotstartSolution_ && priority_ != -999) {
+#ifndef NDEBUG
+        double nearest = floor(value + 0.5);
+        assert (fabs(value - nearest) > info->integerTolerance_);
+#endif
+    } else if (info->hotstartSolution_) {
+        double targetValue = info->hotstartSolution_[columnNumber_];
+        if (way > 0)
+            value = targetValue - 0.1;
+        else
+            value = targetValue + 0.1;
+    } else {
+        if (value <= info->lower_[columnNumber_])
+            value += 0.1;
+        else if (value >= info->upper_[columnNumber_])
+            value -= 0.1;
+    }
+    assert (value >= info->lower_[columnNumber_] &&
+            value <= info->upper_[columnNumber_]);
+    CbcDynamicPseudoCostBranchingObject * newObject =
+        new CbcDynamicPseudoCostBranchingObject(model_, columnNumber_, way,
+                                                value, this);
+    double up =  upDynamicPseudoCost_ * (ceil(value) - value);
+    double down =  downDynamicPseudoCost_ * (value - floor(value));
+    double changeInGuessed = up - down;
+    if (way > 0)
+        changeInGuessed = - changeInGuessed;
+    changeInGuessed = CoinMax(0.0, changeInGuessed);
+    //if (way>0)
+    //changeInGuessed += 1.0e8; // bias to stay up
+    newObject->setChangeInGuessed(changeInGuessed);
+    newObject->setOriginalObject(this);
+    return newObject;
+}
+
+// Return "up" estimate
+double
+CbcSimpleIntegerDynamicPseudoCost::upEstimate() const
+{
+    const double * solution = model_->testSolution();
+    const double * lower = model_->getCbcColLower();
+    const double * upper = model_->getCbcColUpper();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    if (upper[columnNumber_] == lower[columnNumber_]) {
+        // fixed
+        return 0.0;
+    }
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double below = floor(value + integerTolerance);
+    double above = below + 1.0;
+    if (above > upper[columnNumber_]) {
+        above = below;
+        below = above - 1;
+    }
+    double upCost = CoinMax((above - value) * upDynamicPseudoCost_, 0.0);
+    return upCost;
+}
+// Return "down" estimate
+double
+CbcSimpleIntegerDynamicPseudoCost::downEstimate() const
+{
+    const double * solution = model_->testSolution();
+    const double * lower = model_->getCbcColLower();
+    const double * upper = model_->getCbcColUpper();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    if (upper[columnNumber_] == lower[columnNumber_]) {
+        // fixed
+        return 0.0;
+    }
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double below = floor(value + integerTolerance);
+    double above = below + 1.0;
+    if (above > upper[columnNumber_]) {
+        above = below;
+        below = above - 1;
+    }
+    double downCost = CoinMax((value - below) * downDynamicPseudoCost_, 0.0);
+    return downCost;
+}
+// Set down pseudo cost
+void
+CbcSimpleIntegerDynamicPseudoCost::setDownDynamicPseudoCost(double value)
+{
+#ifdef TRACE_ONE
+    double oldDown = sumDownCost_;
+#endif
+    downDynamicPseudoCost_ = value;
+    sumDownCost_ = CoinMax(sumDownCost_, value * numberTimesDown_);
+#ifdef TRACE_ONE
+    if (columnNumber_ == TRACE_ONE) {
+        double down = downDynamicPseudoCost_ * numberTimesDown_;
+        printf("For %d sumDown %g (%d), inf (%d) - pseudo %g - sumDown was %g -> %g\n",
+               TRACE_ONE, down, numberTimesDown_,
+               numberTimesDownInfeasible_, downDynamicPseudoCost_,
+               oldDown, sumDownCost_);
+    }
+#endif
+}
+// Modify down pseudo cost in a slightly different way
+void
+CbcSimpleIntegerDynamicPseudoCost::updateDownDynamicPseudoCost(double value)
+{
+    sumDownCost_ += value;
+    numberTimesDown_++;
+    downDynamicPseudoCost_ = sumDownCost_ / static_cast<double>(numberTimesDown_);
+}
+// Set up pseudo cost
+void
+CbcSimpleIntegerDynamicPseudoCost::setUpDynamicPseudoCost(double value)
+{
+#ifdef TRACE_ONE
+    double oldUp = sumUpCost_;
+#endif
+    upDynamicPseudoCost_ = value;
+    sumUpCost_ = CoinMax(sumUpCost_, value * numberTimesUp_);
+#ifdef TRACE_ONE
+    if (columnNumber_ == TRACE_ONE) {
+        double up = upDynamicPseudoCost_ * numberTimesUp_;
+        printf("For %d sumUp %g (%d), inf (%d) - pseudo %g - sumUp was %g -> %g\n",
+               TRACE_ONE, up, numberTimesUp_,
+               numberTimesUpInfeasible_, upDynamicPseudoCost_,
+               oldUp, sumUpCost_);
+    }
+#endif
+}
+// Modify up pseudo cost in a slightly different way
+void
+CbcSimpleIntegerDynamicPseudoCost::updateUpDynamicPseudoCost(double value)
+{
+    sumUpCost_ += value;
+    numberTimesUp_++;
+    upDynamicPseudoCost_ = sumUpCost_ / static_cast<double>(numberTimesUp_);
+}
+/* Pass in information on branch just done and create CbcObjectUpdateData instance.
+   If object does not need data then backward pointer will be NULL.
+   Assumes can get information from solver */
+CbcObjectUpdateData
+CbcSimpleIntegerDynamicPseudoCost::createUpdateInformation(const OsiSolverInterface * solver,
+        const CbcNode * node,
+        const CbcBranchingObject * branchingObject)
+{
+    double originalValue = node->objectiveValue();
+    int originalUnsatisfied = node->numberUnsatisfied();
+    double objectiveValue = solver->getObjValue() * solver->getObjSense();
+    int unsatisfied = 0;
+    int i;
+    //might be base model - doesn't matter
+    int numberIntegers = model_->numberIntegers();;
+    const double * solution = solver->getColSolution();
+    //const double * lower = solver->getColLower();
+    //const double * upper = solver->getColUpper();
+    double change = CoinMax(0.0, objectiveValue - originalValue);
+    int iStatus;
+    if (solver->isProvenOptimal())
+        iStatus = 0; // optimal
+    else if (solver->isIterationLimitReached()
+             && !solver->isDualObjectiveLimitReached())
+        iStatus = 2; // unknown
+    else
+        iStatus = 1; // infeasible
+
+    bool feasible = iStatus != 1;
+    if (feasible) {
+        double integerTolerance =
+            model_->getDblParam(CbcModel::CbcIntegerTolerance);
+        const int * integerVariable = model_->integerVariable();
+        for (i = 0; i < numberIntegers; i++) {
+            int j = integerVariable[i];
+            double value = solution[j];
+            double nearest = floor(value + 0.5);
+            if (fabs(value - nearest) > integerTolerance)
+                unsatisfied++;
+        }
+    }
+    int way = branchingObject->way();
+    way = - way; // because after branch so moved on
+    double value = branchingObject->value();
+    CbcObjectUpdateData newData (this, way,
+                                 change, iStatus,
+                                 originalUnsatisfied - unsatisfied, value);
+    newData.originalObjective_ = originalValue;
+    // Solvers know about direction
+    double direction = solver->getObjSense();
+    solver->getDblParam(OsiDualObjectiveLimit, newData.cutoff_);
+    newData.cutoff_ *= direction;
+    return newData;
+}
+// Just update using feasible branches and keep count of infeasible
+#undef INFEAS
+// Update object by CbcObjectUpdateData
+void
+CbcSimpleIntegerDynamicPseudoCost::updateInformation(const CbcObjectUpdateData & data)
+{
+    bool feasible = data.status_ != 1;
+    int way = data.way_;
+    double value = data.branchingValue_;
+    double change = data.change_;
+#ifdef COIN_DEVELOP
+    History hist;
+    hist.where_ = 'U'; // need to tell if hot
+#endif
+    double movement = 0.0;
+    if (way < 0) {
+        // down
+        movement = value - floor(value);
+        if (feasible) {
+#ifdef COIN_DEVELOP
+            hist.status_ = 'D';
+#endif
+            movement = CoinMax(movement, MINIMUM_MOVEMENT);
+            //printf("(down change %g value down %g ",change,movement);
+            incrementNumberTimesDown();
+            addToSumDownChange(1.0e-30 + movement);
+            addToSumDownDecrease(data.intDecrease_);
+#if TYPE2==0
+            addToSumDownCost(change / (1.0e-30 + movement));
+            setDownDynamicPseudoCost(sumDownCost() / static_cast<double>( numberTimesDown()));
+#elif TYPE2==1
+            addToSumDownCost(change);
+            setDownDynamicPseudoCost(sumDownCost() / sumDownChange());
+#elif TYPE2==2
+            addToSumDownCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (1.0e-30 + movement));
+            setDownDynamicPseudoCost(sumDownCost()*(TYPERATIO / sumDownChange() + (1.0 - TYPERATIO) / (double) numberTimesDown()));
+#endif
+        } else {
+#ifdef COIN_DEVELOP
+            hist.status_ = 'd';
+#endif
+            //printf("(down infeasible value down %g ",change,movement);
+            incrementNumberTimesDown();
+            incrementNumberTimesDownInfeasible();
+#if INFEAS==2
+            double distanceToCutoff = 0.0;
+            double objectiveValue = model->getCurrentMinimizationObjValue();
+            distanceToCutoff =  model->getCutoff()  - originalValue;
+            if (distanceToCutoff < 1.0e20)
+                change = distanceToCutoff * 2.0;
+            else
+                change = downDynamicPseudoCost() * movement * 10.0;
+            change = CoinMax(1.0e-12 * (1.0 + fabs(originalValue)), change);
+            addToSumDownChange(1.0e-30 + movement);
+            addToSumDownDecrease(data.intDecrease_);
+#if TYPE2==0
+            addToSumDownCost(change / (1.0e-30 + movement));
+            setDownDynamicPseudoCost(sumDownCost() / (double) numberTimesDown());
+#elif TYPE2==1
+            addToSumDownCost(change);
+            setDownDynamicPseudoCost(sumDownCost() / sumDownChange());
+#elif TYPE2==2
+            addToSumDownCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (1.0e-30 + movement));
+            setDownDynamicPseudoCost(sumDownCost()*(TYPERATIO / sumDownChange() + (1.0 - TYPERATIO) / (double) numberTimesDown()));
+#endif
+#endif
+        }
+#if INFEAS==1
+        double sum = sumDownCost_;
+        int number = numberTimesDown_;
+        double originalValue = data.originalObjective_;
+        assert (originalValue != COIN_DBL_MAX);
+        double distanceToCutoff =  data.cutoff_  - originalValue;
+        if (distanceToCutoff > 1.0e20)
+            distanceToCutoff = 10.0 + fabs(originalValue);
+        sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible_ * CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(originalValue)));
+        setDownDynamicPseudoCost(sum / static_cast<double> (number));
+#endif
+    } else {
+        // up
+        movement = ceil(value) - value;
+        if (feasible) {
+#ifdef COIN_DEVELOP
+            hist.status_ = 'U';
+#endif
+            movement = CoinMax(movement, MINIMUM_MOVEMENT);
+            //printf("(up change %g value down %g ",change,movement);
+            incrementNumberTimesUp();
+            addToSumUpChange(1.0e-30 + movement);
+            addToSumUpDecrease(data.intDecrease_);
+#if TYPE2==0
+            addToSumUpCost(change / (1.0e-30 + movement));
+            setUpDynamicPseudoCost(sumUpCost() / static_cast<double> (numberTimesUp()));
+#elif TYPE2==1
+            addToSumUpCost(change);
+            setUpDynamicPseudoCost(sumUpCost() / sumUpChange());
+#elif TYPE2==2
+            addToSumUpCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (1.0e-30 + movement));
+            setUpDynamicPseudoCost(sumUpCost()*(TYPERATIO / sumUpChange() + (1.0 - TYPERATIO) / (double) numberTimesUp()));
+#endif
+        } else {
+#ifdef COIN_DEVELOP
+            hist.status_ = 'u';
+#endif
+            //printf("(up infeasible value down %g ",change,movement);
+            incrementNumberTimesUp();
+            incrementNumberTimesUpInfeasible();
+#if INFEAS==2
+            double distanceToCutoff = 0.0;
+            double objectiveValue = model->getCurrentMinimizationObjValue();
+            distanceToCutoff =  model->getCutoff()  - originalValue;
+            if (distanceToCutoff < 1.0e20)
+                change = distanceToCutoff * 2.0;
+            else
+                change = upDynamicPseudoCost() * movement * 10.0;
+            change = CoinMax(1.0e-12 * (1.0 + fabs(originalValue)), change);
+            addToSumUpChange(1.0e-30 + movement);
+            addToSumUpDecrease(data.intDecrease_);
+#if TYPE2==0
+            addToSumUpCost(change / (1.0e-30 + movement));
+            setUpDynamicPseudoCost(sumUpCost() / (double) numberTimesUp());
+#elif TYPE2==1
+            addToSumUpCost(change);
+            setUpDynamicPseudoCost(sumUpCost() / sumUpChange());
+#elif TYPE2==2
+            addToSumUpCost(change*TYPERATIO + (1.0 - TYPERATIO)*change / (1.0e-30 + movement));
+            setUpDynamicPseudoCost(sumUpCost()*(TYPERATIO / sumUpChange() + (1.0 - TYPERATIO) / (double) numberTimesUp()));
+#endif
+#endif
+        }
+#if INFEAS==1
+        double sum = sumUpCost_;
+        int number = numberTimesUp_;
+        double originalValue = data.originalObjective_;
+        assert (originalValue != COIN_DBL_MAX);
+        double distanceToCutoff =  data.cutoff_  - originalValue;
+        if (distanceToCutoff > 1.0e20)
+            distanceToCutoff = 10.0 + fabs(originalValue);
+        sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible_ * CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(originalValue)));
+        setUpDynamicPseudoCost(sum / static_cast<double> (number));
+#endif
+    }
+    if (data.way_ < 0)
+        assert (numberTimesDown_ > 0);
+    else
+        assert (numberTimesUp_ > 0);
+    assert (downDynamicPseudoCost_ >= 0.0 && downDynamicPseudoCost_ < 1.0e100);
+    downDynamicPseudoCost_ = CoinMax(1.0e-10, downDynamicPseudoCost_);
+    assert (upDynamicPseudoCost_ >= 0.0 && upDynamicPseudoCost_ < 1.0e100);
+    upDynamicPseudoCost_ = CoinMax(1.0e-10, upDynamicPseudoCost_);
+#ifdef COIN_DEVELOP
+    hist.sequence_ = columnNumber_;
+    hist.numberUp_ = numberTimesUp_;
+    hist.numberUpInf_ = numberTimesUpInfeasible_;
+    hist.sumUp_ = sumUpCost_;
+    hist.upEst_ = change;
+    hist.numberDown_ = numberTimesDown_;
+    hist.numberDownInf_ = numberTimesDownInfeasible_;
+    hist.sumDown_ = sumDownCost_;
+    hist.downEst_ = movement;
+    addRecord(hist);
+#endif
+    //print(1,0.5);
+    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
+#if MOD_SHADOW>1
+    if (upShadowPrice_ > 0.0 && numberTimesDown_ >= numberBeforeTrust_
+            && numberTimesUp_ >= numberBeforeTrust_) {
+        // Set negative
+        upShadowPrice_ = -upShadowPrice_;
+        assert (downShadowPrice_ > 0.0);
+        downShadowPrice_ = - downShadowPrice_;
+    }
+#endif
+}
+// Updates stuff like pseudocosts after mini branch and bound
+void
+CbcSimpleIntegerDynamicPseudoCost::updateAfterMini(int numberDown, int numberDownInfeasible,
+        double sumDown, int numberUp,
+        int numberUpInfeasible, double sumUp)
+{
+    numberTimesDown_ = numberDown;
+    numberTimesDownInfeasible_ = numberDownInfeasible;
+    sumDownCost_ = sumDown;
+    numberTimesUp_ = numberUp;
+    numberTimesUpInfeasible_ = numberUpInfeasible;
+    sumUpCost_ = sumUp;
+    if (numberTimesDown_ > 0) {
+        setDownDynamicPseudoCost(sumDownCost_ / static_cast<double> (numberTimesDown_));
+        assert (downDynamicPseudoCost_ > 0.0 && downDynamicPseudoCost_ < 1.0e50);
+    }
+    if (numberTimesUp_ > 0) {
+        setUpDynamicPseudoCost(sumUpCost_ / static_cast<double> (numberTimesUp_));
+        assert (upDynamicPseudoCost_ > 0.0 && upDynamicPseudoCost_ < 1.0e50);
+    }
+    assert (downDynamicPseudoCost_ > 1.0e-40 && upDynamicPseudoCost_ > 1.0e-40);
+}
+// Pass in probing information
+void
+CbcSimpleIntegerDynamicPseudoCost::setProbingInformation(int fixedDown, int fixedUp)
+{
+    numberTimesProbingTotal_++;
+    numberTimesDownLocalFixed_ = fixedDown;
+    numberTimesDownTotalFixed_ += fixedDown;
+    numberTimesUpLocalFixed_ = fixedUp;
+    numberTimesUpTotalFixed_ += fixedUp;
+}
+// Print
+void
+CbcSimpleIntegerDynamicPseudoCost::print(int type, double value) const
+{
+    if (!type) {
+        double meanDown = 0.0;
+        double devDown = 0.0;
+        if (numberTimesDown_) {
+            meanDown = sumDownCost_ / static_cast<double> (numberTimesDown_);
+            devDown = meanDown * meanDown - 2.0 * meanDown * sumDownCost_;
+            if (devDown >= 0.0)
+                devDown = sqrt(devDown);
+        }
+        double meanUp = 0.0;
+        double devUp = 0.0;
+        if (numberTimesUp_) {
+            meanUp = sumUpCost_ / static_cast<double> (numberTimesUp_);
+            devUp = meanUp * meanUp - 2.0 * meanUp * sumUpCost_;
+            if (devUp >= 0.0)
+                devUp = sqrt(devUp);
+        }
+        printf("%d down %d times (%d inf) mean %g (dev %g) up %d times (%d inf) mean %g (dev %g)\n",
+               columnNumber_,
+               numberTimesDown_, numberTimesDownInfeasible_, meanDown, devDown,
+               numberTimesUp_, numberTimesUpInfeasible_, meanUp, devUp);
+    } else {
+        const double * upper = model_->getCbcColUpper();
+        double integerTolerance =
+            model_->getDblParam(CbcModel::CbcIntegerTolerance);
+        double below = floor(value + integerTolerance);
+        double above = below + 1.0;
+        if (above > upper[columnNumber_]) {
+            above = below;
+            below = above - 1;
+        }
+        double objectiveValue = model_->getCurrentMinimizationObjValue();
+        double distanceToCutoff =  model_->getCutoff() - objectiveValue;
+        if (distanceToCutoff < 1.0e20)
+            distanceToCutoff *= 10.0;
+        else
+            distanceToCutoff = 1.0e2 + fabs(objectiveValue);
+        distanceToCutoff = CoinMax(distanceToCutoff, 1.0e-12 * (1.0 + fabs(objectiveValue)));
+        double sum;
+        int number;
+        double downCost = CoinMax(value - below, 0.0);
+        double downCost0 = downCost * downDynamicPseudoCost_;
+        sum = sumDownCost();
+        number = numberTimesDown();
+        sum += INFEAS_MULTIPLIER*numberTimesDownInfeasible() * (distanceToCutoff / (downCost + 1.0e-12));
+        if (number > 0)
+            downCost *= sum / static_cast<double> (number);
+        else
+            downCost  *=  downDynamicPseudoCost_;
+        double upCost = CoinMax((above - value), 0.0);
+        double upCost0 = upCost * upDynamicPseudoCost_;
+        sum = sumUpCost();
+        number = numberTimesUp();
+        sum += INFEAS_MULTIPLIER*numberTimesUpInfeasible() * (distanceToCutoff / (upCost + 1.0e-12));
+        if (number > 0)
+            upCost *= sum / static_cast<double> (number);
+        else
+            upCost  *=  upDynamicPseudoCost_;
+        printf("%d down %d times %g (est %g)  up %d times %g (est %g)\n",
+               columnNumber_,
+               numberTimesDown_, downCost, downCost0,
+               numberTimesUp_, upCost, upCost0);
+    }
+}
+
+//##############################################################################
+
+// Default Constructor
+CbcIntegerPseudoCostBranchingObject::CbcIntegerPseudoCostBranchingObject()
+        : CbcIntegerBranchingObject()
+{
+    changeInGuessed_ = 1.0e-5;
+}
+
+// Useful constructor
+CbcIntegerPseudoCostBranchingObject::CbcIntegerPseudoCostBranchingObject (CbcModel * model,
+        int variable, int way , double value)
+        : CbcIntegerBranchingObject(model, variable, way, value)
+{
+}
+// Useful constructor for fixing
+CbcIntegerPseudoCostBranchingObject::CbcIntegerPseudoCostBranchingObject (CbcModel * model,
+        int variable, int way,
+        double lowerValue,
+        double /*upperValue*/)
+        : CbcIntegerBranchingObject(model, variable, way, lowerValue)
+{
+    changeInGuessed_ = 1.0e100;
+}
+
+
+// Copy constructor
+CbcIntegerPseudoCostBranchingObject::CbcIntegerPseudoCostBranchingObject (
+    const CbcIntegerPseudoCostBranchingObject & rhs)
+        : CbcIntegerBranchingObject(rhs)
+{
+    changeInGuessed_ = rhs.changeInGuessed_;
+}
+
+// Assignment operator
+CbcIntegerPseudoCostBranchingObject &
+CbcIntegerPseudoCostBranchingObject::operator=( const CbcIntegerPseudoCostBranchingObject & rhs)
+{
+    if (this != &rhs) {
+        CbcIntegerBranchingObject::operator=(rhs);
+        changeInGuessed_ = rhs.changeInGuessed_;
+    }
+    return *this;
+}
+CbcBranchingObject *
+CbcIntegerPseudoCostBranchingObject::clone() const
+{
+    return (new CbcIntegerPseudoCostBranchingObject(*this));
+}
+
+
+// Destructor
+CbcIntegerPseudoCostBranchingObject::~CbcIntegerPseudoCostBranchingObject ()
+{
+}
+
+/*
+  Perform a branch by adjusting the bounds of the specified variable. Note
+  that each arm of the branch advances the object to the next arm by
+  advancing the value of way_.
+
+  Providing new values for the variable's lower and upper bounds for each
+  branching direction gives a little bit of additional flexibility and will
+  be easily extensible to multi-way branching.
+  Returns change in guessed objective on next branch
+*/
+double
+CbcIntegerPseudoCostBranchingObject::branch()
+{
+    CbcIntegerBranchingObject::branch();
+    return changeInGuessed_;
+}
+
+/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+    same type and must have the same original object, but they may have
+    different feasible regions.
+    Return the appropriate CbcRangeCompare value (first argument being the
+    sub/superset if that's the case). In case of overlap (and if \c
+    replaceIfOverlap is true) replace the current branching object with one
+    whose feasible region is the overlap.
+*/
+CbcRangeCompare
+CbcIntegerPseudoCostBranchingObject::compareBranchingObject
+(const CbcBranchingObject* brObj, const bool replaceIfOverlap)
+{
+    const CbcIntegerPseudoCostBranchingObject* br =
+        dynamic_cast<const CbcIntegerPseudoCostBranchingObject*>(brObj);
+    assert(br);
+    double* thisBd = way_ < 0 ? down_ : up_;
+    const double* otherBd = br->way_ < 0 ? br->down_ : br->up_;
+    return CbcCompareRanges(thisBd, otherBd, replaceIfOverlap);
+}
+
diff --git a/cbits/coin/CbcSimpleIntegerDynamicPseudoCost.hpp b/cbits/coin/CbcSimpleIntegerDynamicPseudoCost.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSimpleIntegerDynamicPseudoCost.hpp
@@ -0,0 +1,465 @@
+// $Id: CbcSimpleIntegerDynamicPseudoCost.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/17/2009 - carved out of CbcBranchDynamic
+
+#ifndef CbcSimpleIntegerDynamicPseudoCost_H
+#define CbcSimpleIntegerDynamicPseudoCost_H
+
+#include "CbcSimpleInteger.hpp"
+
+#define TYPERATIO 0.9
+#define MINIMUM_MOVEMENT 0.1
+#define TYPE2 0
+// was 1 - but that looks flakey
+#define INFEAS 1
+#define MOD_SHADOW 1
+// weight at 1.0 is max min
+#define WEIGHT_AFTER 0.8
+#define WEIGHT_BEFORE 0.1
+//Stolen from Constraint Integer Programming book (with epsilon change)
+#define WEIGHT_PRODUCT
+
+
+/** Define a single integer class but with dynamic pseudo costs.
+    Based on work by Achterberg, Koch and Martin.
+
+    It is wild overkill but to keep design all twiddly things are in each.
+    This could be used for fine tuning.
+
+ */
+
+
+class CbcSimpleIntegerDynamicPseudoCost : public CbcSimpleInteger {
+
+public:
+
+    // Default Constructor
+    CbcSimpleIntegerDynamicPseudoCost ();
+
+    // Useful constructor - passed  model index
+    CbcSimpleIntegerDynamicPseudoCost (CbcModel * model,  int iColumn, double breakEven = 0.5);
+
+    // Useful constructor - passed  model index and pseudo costs
+    CbcSimpleIntegerDynamicPseudoCost (CbcModel * model, int iColumn,
+                                       double downDynamicPseudoCost, double upDynamicPseudoCost);
+
+    // Useful constructor - passed  model index and pseudo costs
+    CbcSimpleIntegerDynamicPseudoCost (CbcModel * model, int dummy, int iColumn,
+                                       double downDynamicPseudoCost, double upDynamicPseudoCost);
+
+    // Copy constructor
+    CbcSimpleIntegerDynamicPseudoCost ( const CbcSimpleIntegerDynamicPseudoCost &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcSimpleIntegerDynamicPseudoCost & operator=( const CbcSimpleIntegerDynamicPseudoCost& rhs);
+
+    // Destructor
+    virtual ~CbcSimpleIntegerDynamicPseudoCost ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+
+
+    /// Fills in a created branching object
+    void fillCreateBranch(CbcIntegerBranchingObject * branching, const OsiBranchingInformation * info, int way) ;
+
+
+    /** Pass in information on branch just done and create CbcObjectUpdateData instance.
+        If object does not need data then backward pointer will be NULL.
+        Assumes can get information from solver */
+    virtual CbcObjectUpdateData createUpdateInformation(const OsiSolverInterface * solver,
+            const CbcNode * node,
+            const CbcBranchingObject * branchingObject);
+    /// Update object by CbcObjectUpdateData
+    virtual void updateInformation(const CbcObjectUpdateData & data) ;
+    /// Copy some information i.e. just variable stuff
+    void copySome(const CbcSimpleIntegerDynamicPseudoCost * otherObject);
+    /// Updates stuff like pseudocosts before threads
+    virtual void updateBefore(const OsiObject * rhs) ;
+    /// Updates stuff like pseudocosts after threads finished
+    virtual void updateAfter(const OsiObject * rhs, const OsiObject * baseObject) ;
+    /// Updates stuff like pseudocosts after mini branch and bound
+    void updateAfterMini(int numberDown, int numberDownInfeasible, double sumDown,
+                         int numberUp, int numberUpInfeasible, double sumUp);
+
+    using CbcSimpleInteger::solverBranch ;
+    /** Create an OsiSolverBranch object
+
+        This returns NULL if branch not represented by bound changes
+    */
+    virtual OsiSolverBranch * solverBranch() const;
+
+    /// Down pseudo cost
+    inline double downDynamicPseudoCost() const {
+        return downDynamicPseudoCost_;
+    }
+    /// Set down pseudo cost
+    void setDownDynamicPseudoCost(double value) ;
+    /// Modify down pseudo cost in a slightly different way
+    void updateDownDynamicPseudoCost(double value);
+
+    /// Up pseudo cost
+    inline double upDynamicPseudoCost() const {
+        return upDynamicPseudoCost_;
+    }
+    /// Set up pseudo cost
+    void setUpDynamicPseudoCost(double value);
+    /// Modify up pseudo cost in a slightly different way
+    void updateUpDynamicPseudoCost(double value);
+
+    /// Down pseudo shadow price cost
+    inline double downShadowPrice() const {
+        return downShadowPrice_;
+    }
+    /// Set down pseudo shadow price cost
+    inline void setDownShadowPrice(double value) {
+        downShadowPrice_ = value;
+    }
+    /// Up pseudo shadow price cost
+    inline double upShadowPrice() const {
+        return upShadowPrice_;
+    }
+    /// Set up pseudo shadow price cost
+    inline void setUpShadowPrice(double value) {
+        upShadowPrice_ = value;
+    }
+
+    /// Up down separator
+    inline double upDownSeparator() const {
+        return upDownSeparator_;
+    }
+    /// Set up down separator
+    inline void setUpDownSeparator(double value) {
+        upDownSeparator_ = value;
+    }
+
+    /// Down sum cost
+    inline double sumDownCost() const {
+        return sumDownCost_;
+    }
+    /// Set down sum cost
+    inline void setSumDownCost(double value) {
+        sumDownCost_ = value;
+    }
+    /// Add to down sum cost and set last and square
+    inline void addToSumDownCost(double value) {
+        sumDownCost_ += value;
+        lastDownCost_ = value;
+    }
+
+    /// Up sum cost
+    inline double sumUpCost() const {
+        return sumUpCost_;
+    }
+    /// Set up sum cost
+    inline void setSumUpCost(double value) {
+        sumUpCost_ = value;
+    }
+    /// Add to up sum cost and set last and square
+    inline void addToSumUpCost(double value) {
+        sumUpCost_ += value;
+        lastUpCost_ = value;
+    }
+
+    /// Down sum change
+    inline double sumDownChange() const {
+        return sumDownChange_;
+    }
+    /// Set down sum change
+    inline void setSumDownChange(double value) {
+        sumDownChange_ = value;
+    }
+    /// Add to down sum change
+    inline void addToSumDownChange(double value) {
+        sumDownChange_ += value;
+    }
+
+    /// Up sum change
+    inline double sumUpChange() const {
+        return sumUpChange_;
+    }
+    /// Set up sum change
+    inline void setSumUpChange(double value) {
+        sumUpChange_ = value;
+    }
+    /// Add to up sum change and set last and square
+    inline void addToSumUpChange(double value) {
+        sumUpChange_ += value;
+    }
+
+    /// Sum down decrease number infeasibilities from strong or actual
+    inline double sumDownDecrease() const {
+        return sumDownDecrease_;
+    }
+    /// Set sum down decrease number infeasibilities from strong or actual
+    inline void setSumDownDecrease(double value) {
+        sumDownDecrease_ = value;
+    }
+    /// Add to sum down decrease number infeasibilities from strong or actual
+    inline void addToSumDownDecrease(double value) {
+        sumDownDecrease_ += value;/*lastDownDecrease_ = (int) value;*/
+    }
+
+    /// Sum up decrease number infeasibilities from strong or actual
+    inline double sumUpDecrease() const {
+        return sumUpDecrease_;
+    }
+    /// Set sum up decrease number infeasibilities from strong or actual
+    inline void setSumUpDecrease(double value) {
+        sumUpDecrease_ = value;
+    }
+    /// Add to sum up decrease number infeasibilities from strong or actual
+    inline void addToSumUpDecrease(double value) {
+        sumUpDecrease_ += value;/*lastUpDecrease_ = (int) value;*/
+    }
+
+    /// Down number times
+    inline int numberTimesDown() const {
+        return numberTimesDown_;
+    }
+    /// Set down number times
+    inline void setNumberTimesDown(int value) {
+        numberTimesDown_ = value;
+    }
+    /// Increment down number times
+    inline void incrementNumberTimesDown() {
+        numberTimesDown_++;
+    }
+
+    /// Up number times
+    inline int numberTimesUp() const {
+        return numberTimesUp_;
+    }
+    /// Set up number times
+    inline void setNumberTimesUp(int value) {
+        numberTimesUp_ = value;
+    }
+    /// Increment up number times
+    inline void incrementNumberTimesUp() {
+        numberTimesUp_++;
+    }
+
+    /// Down number times infeasible
+    inline int numberTimesDownInfeasible() const {
+        return numberTimesDownInfeasible_;
+    }
+    /// Set down number times infeasible
+    inline void setNumberTimesDownInfeasible(int value) {
+        numberTimesDownInfeasible_ = value;
+    }
+    /// Increment down number times infeasible
+    inline void incrementNumberTimesDownInfeasible() {
+        numberTimesDownInfeasible_++;
+    }
+
+    /// Up number times infeasible
+    inline int numberTimesUpInfeasible() const {
+        return numberTimesUpInfeasible_;
+    }
+    /// Set up number times infeasible
+    inline void setNumberTimesUpInfeasible(int value) {
+        numberTimesUpInfeasible_ = value;
+    }
+    /// Increment up number times infeasible
+    inline void incrementNumberTimesUpInfeasible() {
+        numberTimesUpInfeasible_++;
+    }
+
+    /// Number of times before trusted
+    inline int numberBeforeTrust() const {
+        return numberBeforeTrust_;
+    }
+    /// Set number of times before trusted
+    inline void setNumberBeforeTrust(int value) {
+        numberBeforeTrust_ = value;
+    }
+    /// Increment number of times before trusted
+    inline void incrementNumberBeforeTrust() {
+        numberBeforeTrust_++;
+    }
+
+    /// Return "up" estimate
+    virtual double upEstimate() const;
+    /// Return "down" estimate (default 1.0e-5)
+    virtual double downEstimate() const;
+
+    /// method - see below for details
+    inline int method() const {
+        return method_;
+    }
+    /// Set method
+    inline void setMethod(int value) {
+        method_ = value;
+    }
+
+    /// Pass in information on a down branch
+    void setDownInformation(double changeObjectiveDown, int changeInfeasibilityDown);
+    /// Pass in information on a up branch
+    void setUpInformation(double changeObjectiveUp, int changeInfeasibilityUp);
+    /// Pass in probing information
+    void setProbingInformation(int fixedDown, int fixedUp);
+
+    /// Print - 0 -summary, 1 just before strong
+    void print(int type = 0, double value = 0.0) const;
+    /// Same - returns true if contents match(ish)
+    bool same(const CbcSimpleIntegerDynamicPseudoCost * obj) const;
+protected:
+    /// data
+
+    /// Down pseudo cost
+    double downDynamicPseudoCost_;
+    /// Up pseudo cost
+    double upDynamicPseudoCost_;
+    /** Up/down separator
+        If >0.0 then do first branch up if value-floor(value)
+        >= this value
+    */
+    double upDownSeparator_;
+    /// Sum down cost from strong or actual
+    double sumDownCost_;
+    /// Sum up cost from strong or actual
+    double sumUpCost_;
+    /// Sum of all changes to x when going down
+    double sumDownChange_;
+    /// Sum of all changes to x when going up
+    double sumUpChange_;
+    /// Current pseudo-shadow price estimate down
+    mutable double downShadowPrice_;
+    /// Current pseudo-shadow price estimate up
+    mutable double upShadowPrice_;
+    /// Sum down decrease number infeasibilities from strong or actual
+    double sumDownDecrease_;
+    /// Sum up decrease number infeasibilities from strong or actual
+    double sumUpDecrease_;
+    /// Last down cost from strong (i.e. as computed by last strong)
+    double lastDownCost_;
+    /// Last up cost from strong (i.e. as computed by last strong)
+    double lastUpCost_;
+    /// Last down decrease number infeasibilities from strong (i.e. as computed by last strong)
+    mutable int lastDownDecrease_;
+    /// Last up decrease number infeasibilities from strong (i.e. as computed by last strong)
+    mutable int lastUpDecrease_;
+    /// Number of times we have gone down
+    int numberTimesDown_;
+    /// Number of times we have gone up
+    int numberTimesUp_;
+    /// Number of times we have been infeasible going down
+    int numberTimesDownInfeasible_;
+    /// Number of times we have been infeasible going up
+    int numberTimesUpInfeasible_;
+    /// Number of branches before we trust
+    int numberBeforeTrust_;
+    /// Number of local probing fixings going down
+    int numberTimesDownLocalFixed_;
+    /// Number of local probing fixings going up
+    int numberTimesUpLocalFixed_;
+    /// Number of total probing fixings going down
+    double numberTimesDownTotalFixed_;
+    /// Number of total probing fixings going up
+    double numberTimesUpTotalFixed_;
+    /// Number of times probing done
+    int numberTimesProbingTotal_;
+    /// Number of times infeasible when tested
+    /** Method -
+        0 - pseudo costs
+        1 - probing
+    */
+    int method_;
+};
+/** Simple branching object for an integer variable with pseudo costs
+
+  This object can specify a two-way branch on an integer variable. For each
+  arm of the branch, the upper and lower bounds on the variable can be
+  independently specified.
+
+  Variable_ holds the index of the integer variable in the integerVariable_
+  array of the model.
+*/
+
+class CbcIntegerPseudoCostBranchingObject : public CbcIntegerBranchingObject {
+
+public:
+
+    /// Default constructor
+    CbcIntegerPseudoCostBranchingObject ();
+
+    /** Create a standard floor/ceiling branch object
+
+      Specifies a simple two-way branch. Let \p value = x*. One arm of the
+      branch will be is lb <= x <= floor(x*), the other ceil(x*) <= x <= ub.
+      Specify way = -1 to set the object state to perform the down arm first,
+      way = 1 for the up arm.
+    */
+    CbcIntegerPseudoCostBranchingObject (CbcModel *model, int variable,
+                                         int way , double value) ;
+
+    /** Create a degenerate branch object
+
+      Specifies a `one-way branch'. Calling branch() for this object will
+      always result in lowerValue <= x <= upperValue. Used to fix a variable
+      when lowerValue = upperValue.
+    */
+
+    CbcIntegerPseudoCostBranchingObject (CbcModel *model, int variable, int way,
+                                         double lowerValue, double upperValue) ;
+
+    /// Copy constructor
+    CbcIntegerPseudoCostBranchingObject ( const CbcIntegerPseudoCostBranchingObject &);
+
+    /// Assignment operator
+    CbcIntegerPseudoCostBranchingObject & operator= (const CbcIntegerPseudoCostBranchingObject& rhs);
+
+    /// Clone
+    virtual CbcBranchingObject * clone() const;
+
+    /// Destructor
+    virtual ~CbcIntegerPseudoCostBranchingObject ();
+
+    using CbcBranchingObject::branch ;
+    /** \brief Sets the bounds for the variable according to the current arm
+           of the branch and advances the object state to the next arm.
+           This version also changes guessed objective value
+    */
+    virtual double branch();
+
+    /// Change in guessed
+    inline double changeInGuessed() const {
+        return changeInGuessed_;
+    }
+    /// Set change in guessed
+    inline void setChangeInGuessed(double value) {
+        changeInGuessed_ = value;
+    }
+
+    /** Return the type (an integer identifier) of \c this */
+    virtual CbcBranchObjType type() const {
+        return SimpleIntegerDynamicPseudoCostBranchObj;
+    }
+
+    /** Compare the \c this with \c brObj. \c this and \c brObj must be os the
+        same type and must have the same original object, but they may have
+        different feasible regions.
+        Return the appropriate CbcRangeCompare value (first argument being the
+        sub/superset if that's the case). In case of overlap (and if \c
+        replaceIfOverlap is true) replace the current branching object with one
+        whose feasible region is the overlap.
+     */
+    virtual CbcRangeCompare compareBranchingObject
+    (const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
+
+protected:
+    /// Change in guessed objective value for next branch
+    double changeInGuessed_;
+};
+#endif
+
diff --git a/cbits/coin/CbcSimpleIntegerPseudoCost.cpp b/cbits/coin/CbcSimpleIntegerPseudoCost.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSimpleIntegerPseudoCost.cpp
@@ -0,0 +1,267 @@
+// $Id: CbcSimpleIntegerPseudoCost.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcSimpleIntegerPseudoCost.hpp"
+#include "CbcSimpleIntegerDynamicPseudoCost.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+//##############################################################################
+
+/** Default Constructor
+
+  Equivalent to an unspecified binary variable.
+*/
+CbcSimpleIntegerPseudoCost::CbcSimpleIntegerPseudoCost ()
+        : CbcSimpleInteger(),
+        downPseudoCost_(1.0e-5),
+        upPseudoCost_(1.0e-5),
+        upDownSeparator_(-1.0),
+        method_(0)
+{
+}
+
+/** Useful constructor
+
+  Loads actual upper & lower bounds for the specified variable.
+*/
+CbcSimpleIntegerPseudoCost::CbcSimpleIntegerPseudoCost (CbcModel * model,
+        int iColumn, double breakEven)
+        : CbcSimpleInteger(model, iColumn, breakEven)
+{
+    const double * cost = model->getObjCoefficients();
+    double costValue = CoinMax(1.0e-5, fabs(cost[iColumn]));
+    // treat as if will cost what it says up
+    upPseudoCost_ = costValue;
+    // and balance at breakeven
+    downPseudoCost_ = ((1.0 - breakEven_) * upPseudoCost_) / breakEven_;
+    upDownSeparator_ = -1.0;
+    method_ = 0;
+}
+
+/** Useful constructor
+
+  Loads actual upper & lower bounds for the specified variable.
+*/
+CbcSimpleIntegerPseudoCost::CbcSimpleIntegerPseudoCost (CbcModel * model,
+        int iColumn, double downPseudoCost,
+        double upPseudoCost)
+        : CbcSimpleInteger(model, iColumn)
+{
+    downPseudoCost_ = CoinMax(1.0e-10, downPseudoCost);
+    upPseudoCost_ = CoinMax(1.0e-10, upPseudoCost);
+    breakEven_ = upPseudoCost_ / (upPseudoCost_ + downPseudoCost_);
+    upDownSeparator_ = -1.0;
+    method_ = 0;
+}
+// Useful constructor - passed and model index and pseudo costs
+CbcSimpleIntegerPseudoCost::CbcSimpleIntegerPseudoCost (CbcModel * model,
+        int /*dummy*/,
+        int iColumn,
+        double downPseudoCost, double upPseudoCost)
+{
+    *this = CbcSimpleIntegerPseudoCost(model, iColumn, downPseudoCost, upPseudoCost);
+    columnNumber_ = iColumn;
+}
+
+// Copy constructor
+CbcSimpleIntegerPseudoCost::CbcSimpleIntegerPseudoCost ( const CbcSimpleIntegerPseudoCost & rhs)
+        : CbcSimpleInteger(rhs),
+        downPseudoCost_(rhs.downPseudoCost_),
+        upPseudoCost_(rhs.upPseudoCost_),
+        upDownSeparator_(rhs.upDownSeparator_),
+        method_(rhs.method_)
+
+{
+}
+
+// Clone
+CbcObject *
+CbcSimpleIntegerPseudoCost::clone() const
+{
+    return new CbcSimpleIntegerPseudoCost(*this);
+}
+
+// Assignment operator
+CbcSimpleIntegerPseudoCost &
+CbcSimpleIntegerPseudoCost::operator=( const CbcSimpleIntegerPseudoCost & rhs)
+{
+    if (this != &rhs) {
+        CbcSimpleInteger::operator=(rhs);
+        downPseudoCost_ = rhs.downPseudoCost_;
+        upPseudoCost_ = rhs.upPseudoCost_;
+        upDownSeparator_ = rhs.upDownSeparator_;
+        method_ = rhs.method_;
+    }
+    return *this;
+}
+
+// Destructor
+CbcSimpleIntegerPseudoCost::~CbcSimpleIntegerPseudoCost ()
+{
+}
+CbcBranchingObject *
+CbcSimpleIntegerPseudoCost::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int way)
+{
+    //OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+#ifndef NDEBUG
+    double nearest = floor(value + 0.5);
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    assert (upper[columnNumber_] > lower[columnNumber_]);
+#endif
+    if (!model_->hotstartSolution()) {
+        assert (fabs(value - nearest) > integerTolerance);
+    } else {
+        const double * hotstartSolution = model_->hotstartSolution();
+        double targetValue = hotstartSolution[columnNumber_];
+        if (way > 0)
+            value = targetValue - 0.1;
+        else
+            value = targetValue + 0.1;
+    }
+    CbcIntegerPseudoCostBranchingObject * newObject =
+        new CbcIntegerPseudoCostBranchingObject(model_, columnNumber_, way,
+                                                value);
+    double up =  upPseudoCost_ * (ceil(value) - value);
+    double down =  downPseudoCost_ * (value - floor(value));
+    double changeInGuessed = up - down;
+    if (way > 0)
+        changeInGuessed = - changeInGuessed;
+    changeInGuessed = CoinMax(0.0, changeInGuessed);
+    //if (way>0)
+    //changeInGuessed += 1.0e8; // bias to stay up
+    newObject->setChangeInGuessed(changeInGuessed);
+    newObject->setOriginalObject(this);
+    return newObject;
+}
+double
+CbcSimpleIntegerPseudoCost::infeasibility(const OsiBranchingInformation * /*info*/,
+        int &preferredWay) const
+{
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    if (upper[columnNumber_] == lower[columnNumber_]) {
+        // fixed
+        preferredWay = 1;
+        return 0.0;
+    }
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    /*printf("%d %g %g %g %g\n",columnNumber_,value,lower[columnNumber_],
+      solution[columnNumber_],upper[columnNumber_]);*/
+    double nearest = floor(value + 0.5);
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double below = floor(value + integerTolerance);
+    double above = below + 1.0;
+    if (above > upper[columnNumber_]) {
+        above = below;
+        below = above - 1;
+    }
+    double downCost = CoinMax((value - below) * downPseudoCost_, 0.0);
+    double upCost = CoinMax((above - value) * upPseudoCost_, 0.0);
+    if (downCost >= upCost)
+        preferredWay = 1;
+    else
+        preferredWay = -1;
+    // See if up down choice set
+    if (upDownSeparator_ > 0.0) {
+        preferredWay = (value - below >= upDownSeparator_) ? 1 : -1;
+    }
+    if (preferredWay_)
+        preferredWay = preferredWay_;
+    if (fabs(value - nearest) <= integerTolerance) {
+        return 0.0;
+    } else {
+        // can't get at model so 1,2 don't make sense
+        assert(method_ < 1 || method_ > 2);
+        if (!method_)
+            return CoinMin(downCost, upCost);
+        else
+            return CoinMax(downCost, upCost);
+    }
+}
+
+// Return "up" estimate
+double
+CbcSimpleIntegerPseudoCost::upEstimate() const
+{
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    if (upper[columnNumber_] == lower[columnNumber_]) {
+        // fixed
+        return 0.0;
+    }
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double below = floor(value + integerTolerance);
+    double above = below + 1.0;
+    if (above > upper[columnNumber_]) {
+        above = below;
+        below = above - 1;
+    }
+    double upCost = CoinMax((above - value) * upPseudoCost_, 0.0);
+    return upCost;
+}
+// Return "down" estimate
+double
+CbcSimpleIntegerPseudoCost::downEstimate() const
+{
+    OsiSolverInterface * solver = model_->solver();
+    const double * solution = model_->testSolution();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    double value = solution[columnNumber_];
+    value = CoinMax(value, lower[columnNumber_]);
+    value = CoinMin(value, upper[columnNumber_]);
+    if (upper[columnNumber_] == lower[columnNumber_]) {
+        // fixed
+        return 0.0;
+    }
+    double integerTolerance =
+        model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double below = floor(value + integerTolerance);
+    double above = below + 1.0;
+    if (above > upper[columnNumber_]) {
+        above = below;
+        below = above - 1;
+    }
+    double downCost = CoinMax((value - below) * downPseudoCost_, 0.0);
+    return downCost;
+}
+
diff --git a/cbits/coin/CbcSimpleIntegerPseudoCost.hpp b/cbits/coin/CbcSimpleIntegerPseudoCost.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSimpleIntegerPseudoCost.hpp
@@ -0,0 +1,114 @@
+// $Id: CbcSimpleIntegerPseudoCost.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#ifndef CbcSimpleIntegerPseudoCost_H
+#define CbcSimpleIntegerPseudoCost_H
+
+#include "CbcSimpleInteger.hpp"
+/// Define a single integer class but with pseudo costs
+
+class CbcSimpleIntegerPseudoCost : public CbcSimpleInteger {
+
+public:
+
+    // Default Constructor
+    CbcSimpleIntegerPseudoCost ();
+
+    // Useful constructor - passed model index
+    CbcSimpleIntegerPseudoCost (CbcModel * model, int iColumn, double breakEven = 0.5);
+
+    // Useful constructor - passed and model index and pseudo costs
+    CbcSimpleIntegerPseudoCost (CbcModel * model, int iColumn,
+                                double downPseudoCost, double upPseudoCost);
+    // Useful constructor - passed and model index and pseudo costs
+    CbcSimpleIntegerPseudoCost (CbcModel * model, int dummy, int iColumn,
+                                double downPseudoCost, double upPseudoCost);
+
+    // Copy constructor
+    CbcSimpleIntegerPseudoCost ( const CbcSimpleIntegerPseudoCost &);
+
+    /// Clone
+    virtual CbcObject * clone() const;
+
+    // Assignment operator
+    CbcSimpleIntegerPseudoCost & operator=( const CbcSimpleIntegerPseudoCost& rhs);
+
+    // Destructor
+    virtual ~CbcSimpleIntegerPseudoCost ();
+
+    /// Infeasibility - large is 0.5
+    virtual double infeasibility(const OsiBranchingInformation * info,
+                                 int &preferredWay) const;
+
+    /// Creates a branching object
+    virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
+
+    /// Down pseudo cost
+    inline double downPseudoCost() const {
+        return downPseudoCost_;
+    }
+    /// Set down pseudo cost
+    inline void setDownPseudoCost(double value) {
+        downPseudoCost_ = value;
+    }
+
+    /// Up pseudo cost
+    inline double upPseudoCost() const {
+        return upPseudoCost_;
+    }
+    /// Set up pseudo cost
+    inline void setUpPseudoCost(double value) {
+        upPseudoCost_ = value;
+    }
+
+    /// Up down separator
+    inline double upDownSeparator() const {
+        return upDownSeparator_;
+    }
+    /// Set up down separator
+    inline void setUpDownSeparator(double value) {
+        upDownSeparator_ = value;
+    }
+
+    /// Return "up" estimate
+    virtual double upEstimate() const;
+    /// Return "down" estimate (default 1.0e-5)
+    virtual double downEstimate() const;
+
+    /// method - see below for details
+    inline int method() const {
+        return method_;
+    }
+    /// Set method
+    inline void setMethod(int value) {
+        method_ = value;
+    }
+
+protected:
+    /// data
+
+    /// Down pseudo cost
+    double downPseudoCost_;
+    /// Up pseudo cost
+    double upPseudoCost_;
+    /** Up/down separator
+        If >0.0 then do first branch up if value-floor(value)
+        >= this value
+    */
+    double upDownSeparator_;
+    /** Method -
+        0 - normal - return min (up,down)
+        1 - if before any solution return CoinMax(up,down)
+        2 - if before branched solution return CoinMax(up,down)
+        3 - always return CoinMax(up,down)
+    */
+    int method_;
+};
+
+
+#endif
+
diff --git a/cbits/coin/CbcSolver.cpp b/cbits/coin/CbcSolver.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSolver.cpp
@@ -0,0 +1,9940 @@
+/* $Id: CbcSolver.cpp 1908 2013-04-17 10:02:33Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*! \file CbcSolver.cpp
+    \brief Second level routines for the cbc stand-alone solver.
+*/
+
+#include "CbcConfig.h"
+#include "CoinPragma.hpp"
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+#include <cstring>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+
+#include "CoinMpsIO.hpp"
+#include "CoinModel.hpp"
+
+#include "ClpFactorization.hpp"
+#include "ClpQuadraticObjective.hpp"
+#include "CoinTime.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpSimplexOther.hpp"
+#include "ClpSolve.hpp"
+#include "ClpMessage.hpp"
+#include "ClpPackedMatrix.hpp"
+#include "ClpPlusMinusOneMatrix.hpp"
+#include "ClpNetworkMatrix.hpp"
+#include "ClpDualRowSteepest.hpp"
+#include "ClpDualRowDantzig.hpp"
+#include "ClpLinearObjective.hpp"
+#include "ClpPrimalColumnSteepest.hpp"
+#include "ClpPrimalColumnDantzig.hpp"
+
+#include "ClpPresolve.hpp"
+#ifndef COIN_HAS_CBC
+#define COIN_HAS_CBC
+#endif
+#include "CbcOrClpParam.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "OsiChooseVariable.hpp"
+#include "OsiAuxInfo.hpp"
+#include "CbcMipStartIO.hpp"
+
+#include "CbcSolverHeuristics.hpp"
+#ifdef COIN_HAS_GLPK
+#include "glpk.h"
+extern glp_tran* cbc_glp_tran;
+extern glp_prob* cbc_glp_prob;
+#else
+#define GLP_UNDEF 1
+#define GLP_FEAS 2
+#define GLP_INFEAS 3
+#define GLP_NOFEAS 4
+#define GLP_OPT 5
+#endif
+
+#ifndef CBC_QUIET
+#define CBC_QUIET 0
+#endif
+
+//#define USER_HAS_FAKE_CLP
+//#define USER_HAS_FAKE_CBC
+
+//#define CLP_MALLOC_STATISTICS
+
+#ifdef CLP_MALLOC_STATISTICS
+#include <malloc.h>
+#include <exception>
+#include <new>
+#include "stolen_from_ekk_malloc.cpp"
+static double malloc_times = 0.0;
+static double malloc_total = 0.0;
+static int malloc_amount[] = {0, 32, 128, 256, 1024, 4096, 16384, 65536, 262144, INT_MAX};
+static int malloc_n = 10;
+double malloc_counts[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+bool malloc_counts_on = true;
+void * operator new (size_t size) throw (std::bad_alloc)
+{
+    malloc_times ++;
+    malloc_total += size;
+    int i;
+    for (i = 0; i < malloc_n; i++) {
+        if ((int) size <= malloc_amount[i]) {
+            malloc_counts[i]++;
+            break;
+        }
+    }
+# ifdef DEBUG_MALLOC
+    void *p;
+    if (malloc_counts_on)
+        p = stolen_from_ekk_mallocBase(size);
+    else
+        p = malloc(size);
+# else
+    void * p = malloc(size);
+# endif
+    //char * xx = (char *) p;
+    //memset(xx,0,size);
+    // Initialize random seed
+    //CoinSeedRandom(987654321);
+    return p;
+}
+void operator delete (void *p) throw()
+{
+# ifdef DEBUG_MALLOC
+    if (malloc_counts_on)
+        stolen_from_ekk_freeBase(p);
+    else
+        free(p);
+# else
+    free(p);
+# endif
+}
+static void malloc_stats2()
+{
+    double average = malloc_total / malloc_times;
+    printf("count %g bytes %g - average %g\n", malloc_times, malloc_total, average);
+    for (int i = 0; i < malloc_n; i++)
+        printf("%g ", malloc_counts[i]);
+    printf("\n");
+    malloc_times = 0.0;
+    malloc_total = 0.0;
+    memset(malloc_counts, 0, sizeof(malloc_counts));
+    // print results
+}
+#else	//CLP_MALLOC_STATISTICS
+//void stolen_from_ekk_memory(void * dummy,int type)
+//{
+//}
+//bool malloc_counts_on=false;
+#endif	//CLP_MALLOC_STATISTICS
+
+//#define DMALLOC
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+#ifdef WSSMP_BARRIER
+#define FOREIGN_BARRIER
+#endif
+
+#ifdef UFL_BARRIER
+#define FOREIGN_BARRIER
+#endif
+
+#ifdef TAUCS_BARRIER
+#define FOREIGN_BARRIER
+#endif
+
+static int initialPumpTune = -1;
+#include "CoinWarmStartBasis.hpp"
+
+#include "OsiSolverInterface.hpp"
+#include "OsiCuts.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiColCut.hpp"
+
+#ifndef COIN_HAS_LINK
+#define COIN_HAS_LINK
+#endif
+#ifdef COIN_HAS_LINK
+#include "CbcLinked.hpp"
+#endif
+
+#include "CglPreProcess.hpp"
+#include "CglCutGenerator.hpp"
+#include "CglGomory.hpp"
+#include "CglProbing.hpp"
+#include "CglKnapsackCover.hpp"
+#include "CglRedSplit.hpp"
+#include "CglRedSplit2.hpp"
+#include "CglGMI.hpp"
+#include "CglClique.hpp"
+#include "CglFlowCover.hpp"
+#include "CglMixedIntegerRounding2.hpp"
+#include "CglTwomir.hpp"
+#include "CglDuplicateRow.hpp"
+#include "CglStored.hpp"
+#include "CglLandP.hpp"
+#include "CglResidualCapacity.hpp"
+#include "CglZeroHalf.hpp"
+//#define CGL_WRITEMPS 
+#ifdef CGL_WRITEMPS
+extern double * debugSolution;
+extern int debugNumberColumns;
+#endif
+#include "CbcModel.hpp"
+#include "CbcHeuristic.hpp"
+#include "CbcHeuristicLocal.hpp"
+#include "CbcHeuristicPivotAndFix.hpp"
+//#include "CbcHeuristicPivotAndComplement.hpp"
+#include "CbcHeuristicRandRound.hpp"
+#include "CbcHeuristicGreedy.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcHeuristicRINS.hpp"
+#include "CbcHeuristicDiveCoefficient.hpp"
+#include "CbcHeuristicDiveFractional.hpp"
+#include "CbcHeuristicDiveGuided.hpp"
+#include "CbcHeuristicDiveVectorLength.hpp"
+#include "CbcHeuristicDivePseudoCost.hpp"
+#include "CbcHeuristicDiveLineSearch.hpp"
+#include "CbcTreeLocal.hpp"
+#include "CbcCompareActual.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcBranchLotsize.hpp"
+#include  "CbcOrClpParam.hpp"
+#include  "CbcCutGenerator.hpp"
+#include  "CbcStrategy.hpp"
+#include "CbcBranchCut.hpp"
+
+#include "OsiClpSolverInterface.hpp"
+
+#include "CbcSolverAnalyze.hpp"
+#include "CbcSolverExpandKnapsack.hpp"
+
+#include "CbcSolver.hpp"
+
+//#define IN_BRANCH_AND_BOUND (0x01000000|262144)
+#define IN_BRANCH_AND_BOUND (0x01000000|262144|128|1024|2048)
+//#define IN_BRANCH_AND_BOUND (0x01000000|262144|128)
+
+/*
+  CbcStopNow class definitions.
+*/
+
+CbcStopNow::CbcStopNow()
+{
+}
+CbcStopNow::~CbcStopNow()
+{
+}
+// Copy constructor
+CbcStopNow::CbcStopNow ( const CbcStopNow & )
+{
+}
+// Assignment operator
+CbcStopNow &
+CbcStopNow::operator=(const CbcStopNow & rhs)
+{
+    if (this != &rhs) {
+    }
+    return *this;
+}
+// Clone
+CbcStopNow *
+CbcStopNow::clone() const
+{
+    return new CbcStopNow(*this);
+}
+
+/*
+  CbcUser class definitions.
+*/
+
+// User stuff (base class)
+CbcUser::CbcUser()
+        : coinModel_(NULL),
+        userName_("null")
+{
+}
+CbcUser::~CbcUser()
+{
+    delete coinModel_;
+}
+// Copy constructor
+CbcUser::CbcUser ( const CbcUser & rhs)
+{
+    if (rhs.coinModel_)
+        coinModel_ = new CoinModel(*rhs.coinModel_);
+    else
+        coinModel_ = NULL;
+    userName_ = rhs.userName_;
+}
+// Assignment operator
+CbcUser &
+CbcUser::operator=(const CbcUser & rhs)
+{
+    if (this != &rhs) {
+        if (rhs.coinModel_)
+            coinModel_ = new CoinModel(*rhs.coinModel_);
+        else
+            coinModel_ = NULL;
+        userName_ = rhs.userName_;
+    }
+    return *this;
+}
+
+static void putBackOtherSolutions(CbcModel * presolvedModel, CbcModel * model,
+			   CglPreProcess * preProcess)
+{
+  int numberSolutions=presolvedModel->numberSavedSolutions();
+  int numberColumns=presolvedModel->getNumCols();
+  if (numberSolutions>1) {
+    model->deleteSolutions();
+    double * bestSolution = CoinCopyOfArray(presolvedModel->bestSolution(),numberColumns);
+    //double cutoff = presolvedModel->getCutoff();
+    double objectiveValue=presolvedModel->getObjValue();
+    //model->createSpaceForSavedSolutions(numberSolutions-1);
+    for (int iSolution=numberSolutions-1;iSolution>=0;iSolution--) {
+      presolvedModel->setCutoff(COIN_DBL_MAX);
+      presolvedModel->solver()->setColSolution(presolvedModel->savedSolution(iSolution));
+      //presolvedModel->savedSolutionObjective(iSolution));
+      preProcess->postProcess(*presolvedModel->solver(),false);
+      model->setBestSolution(preProcess->originalModel()->getColSolution(),model->solver()->getNumCols(),
+			     presolvedModel->savedSolutionObjective(iSolution));
+    }
+    presolvedModel->setBestObjectiveValue(objectiveValue);
+    presolvedModel->solver()->setColSolution(bestSolution);
+    //presolvedModel->setBestSolution(bestSolution,numberColumns,objectiveValue);
+  }
+}
+
+/*
+  CbcSolver class definitions
+*/
+
+CbcSolver::CbcSolver()
+        : babModel_(NULL),
+        userFunction_(NULL),
+        statusUserFunction_(NULL),
+        originalSolver_(NULL),
+        originalCoinModel_(NULL),
+        cutGenerator_(NULL),
+        numberUserFunctions_(0),
+        numberCutGenerators_(0),
+        startTime_(CoinCpuTime()),
+        parameters_(NULL),
+        numberParameters_(0),
+        doMiplib_(false),
+        noPrinting_(false),
+        readMode_(1)
+{
+    callBack_ = new CbcStopNow();
+    fillParameters();
+}
+CbcSolver::CbcSolver(const OsiClpSolverInterface & solver)
+        : babModel_(NULL),
+        userFunction_(NULL),
+        statusUserFunction_(NULL),
+        originalSolver_(NULL),
+        originalCoinModel_(NULL),
+        cutGenerator_(NULL),
+        numberUserFunctions_(0),
+        numberCutGenerators_(0),
+        startTime_(CoinCpuTime()),
+        parameters_(NULL),
+        numberParameters_(0),
+        doMiplib_(false),
+        noPrinting_(false),
+        readMode_(1)
+{
+    callBack_ = new CbcStopNow();
+    model_ = CbcModel(solver);
+    fillParameters();
+}
+CbcSolver::CbcSolver(const CbcModel & solver)
+        : babModel_(NULL),
+        userFunction_(NULL),
+        statusUserFunction_(NULL),
+        originalSolver_(NULL),
+        originalCoinModel_(NULL),
+        cutGenerator_(NULL),
+        numberUserFunctions_(0),
+        numberCutGenerators_(0),
+        startTime_(CoinCpuTime()),
+        parameters_(NULL),
+        numberParameters_(0),
+        doMiplib_(false),
+        noPrinting_(false),
+        readMode_(1)
+{
+    callBack_ = new CbcStopNow();
+    model_ = solver;
+    fillParameters();
+}
+CbcSolver::~CbcSolver()
+{
+    int i;
+    for (i = 0; i < numberUserFunctions_; i++)
+        delete userFunction_[i];
+    delete [] userFunction_;
+    for (i = 0; i < numberCutGenerators_; i++)
+        delete cutGenerator_[i];
+    delete [] cutGenerator_;
+    delete [] statusUserFunction_;
+    delete originalSolver_;
+    delete originalCoinModel_;
+    delete babModel_;
+    delete [] parameters_;
+    delete callBack_;
+}
+// Copy constructor
+CbcSolver::CbcSolver ( const CbcSolver & rhs)
+        : model_(rhs.model_),
+        babModel_(NULL),
+        userFunction_(NULL),
+        statusUserFunction_(NULL),
+        numberUserFunctions_(rhs.numberUserFunctions_),
+        startTime_(CoinCpuTime()),
+        parameters_(NULL),
+        numberParameters_(rhs.numberParameters_),
+        doMiplib_(rhs.doMiplib_),
+        noPrinting_(rhs.noPrinting_),
+        readMode_(rhs.readMode_)
+{
+    fillParameters();
+    if (rhs.babModel_)
+        babModel_ = new CbcModel(*rhs.babModel_);
+    userFunction_ = new CbcUser * [numberUserFunctions_];
+    int i;
+    for (i = 0; i < numberUserFunctions_; i++)
+        userFunction_[i] = rhs.userFunction_[i]->clone();
+    for (i = 0; i < numberParameters_; i++)
+        parameters_[i] = rhs.parameters_[i];
+    for (i = 0; i < numberCutGenerators_; i++)
+        cutGenerator_[i] = rhs.cutGenerator_[i]->clone();
+    callBack_ = rhs.callBack_->clone();
+    originalSolver_ = NULL;
+    if (rhs.originalSolver_) {
+        OsiSolverInterface * temp = rhs.originalSolver_->clone();
+        originalSolver_ = dynamic_cast<OsiClpSolverInterface *> (temp);
+        assert (originalSolver_);
+    }
+    originalCoinModel_ = NULL;
+    if (rhs.originalCoinModel_)
+        originalCoinModel_ = new CoinModel(*rhs.originalCoinModel_);
+}
+// Assignment operator
+CbcSolver &
+CbcSolver::operator=(const CbcSolver & rhs)
+{
+    if (this != &rhs) {
+        int i;
+        for (i = 0; i < numberUserFunctions_; i++)
+            delete userFunction_[i];
+        delete [] userFunction_;
+        for (i = 0; i < numberCutGenerators_; i++)
+            delete cutGenerator_[i];
+        delete [] cutGenerator_;
+        delete [] statusUserFunction_;
+        delete originalSolver_;
+        delete originalCoinModel_;
+        statusUserFunction_ = NULL;
+        delete babModel_;
+        delete [] parameters_;
+        delete callBack_;
+        numberUserFunctions_ = rhs.numberUserFunctions_;
+        startTime_ = rhs.startTime_;
+        numberParameters_ = rhs.numberParameters_;
+        for (i = 0; i < numberParameters_; i++)
+            parameters_[i] = rhs.parameters_[i];
+        for (i = 0; i < numberCutGenerators_; i++)
+            cutGenerator_[i] = rhs.cutGenerator_[i]->clone();
+        noPrinting_ = rhs.noPrinting_;
+        readMode_ = rhs.readMode_;
+        doMiplib_ = rhs.doMiplib_;
+        model_ = rhs.model_;
+        if (rhs.babModel_)
+            babModel_ = new CbcModel(*rhs.babModel_);
+        else
+            babModel_ = NULL;
+        userFunction_ = new CbcUser * [numberUserFunctions_];
+        for (i = 0; i < numberUserFunctions_; i++)
+            userFunction_[i] = rhs.userFunction_[i]->clone();
+        callBack_ = rhs.callBack_->clone();
+        originalSolver_ = NULL;
+        if (rhs.originalSolver_) {
+            OsiSolverInterface * temp = rhs.originalSolver_->clone();
+            originalSolver_ = dynamic_cast<OsiClpSolverInterface *> (temp);
+            assert (originalSolver_);
+        }
+        originalCoinModel_ = NULL;
+        if (rhs.originalCoinModel_)
+            originalCoinModel_ = new CoinModel(*rhs.originalCoinModel_);
+    }
+    return *this;
+}
+// Get int value
+int CbcSolver::intValue(CbcOrClpParameterType type) const
+{
+    return parameters_[whichParam(type, numberParameters_, parameters_)].intValue();
+}
+// Set int value
+void CbcSolver::setIntValue(CbcOrClpParameterType type, int value)
+{
+    parameters_[whichParam(type, numberParameters_, parameters_)].setIntValue(value);
+}
+// Get double value
+double CbcSolver::doubleValue(CbcOrClpParameterType type) const
+{
+    return parameters_[whichParam(type, numberParameters_, parameters_)].doubleValue();
+}
+// Set double value
+void CbcSolver::setDoubleValue(CbcOrClpParameterType type, double value)
+{
+    parameters_[whichParam(type, numberParameters_, parameters_)].setDoubleValue(value);
+}
+// User function (NULL if no match)
+CbcUser * CbcSolver::userFunction(const char * name) const
+{
+    int i;
+    for (i = 0; i < numberUserFunctions_; i++) {
+        if (!strcmp(name, userFunction_[i]->name().c_str()))
+            break;
+    }
+    if (i < numberUserFunctions_)
+        return userFunction_[i];
+    else
+        return NULL;
+}
+void CbcSolver::fillParameters()
+{
+    int maxParam = 200;
+    CbcOrClpParam * parameters = new CbcOrClpParam [maxParam];
+    numberParameters_ = 0 ;
+    establishParams(numberParameters_, parameters) ;
+    assert (numberParameters_ <= maxParam);
+    parameters_ = new CbcOrClpParam [numberParameters_];
+    int i;
+    for (i = 0; i < numberParameters_; i++)
+        parameters_[i] = parameters[i];
+    delete [] parameters;
+    const char dirsep =  CoinFindDirSeparator();
+    std::string directory;
+    std::string dirSample;
+    std::string dirNetlib;
+    std::string dirMiplib;
+    if (dirsep == '/') {
+        directory = "./";
+        dirSample = "../../Data/Sample/";
+        dirNetlib = "../../Data/Netlib/";
+        dirMiplib = "../../Data/miplib3/";
+    } else {
+        directory = ".\\";
+        dirSample = "..\\..\\..\\..\\Data\\Sample\\";
+        dirNetlib = "..\\..\\..\\..\\Data\\Netlib\\";
+        dirMiplib = "..\\..\\..\\..\\Data\\miplib3\\";
+    }
+    std::string defaultDirectory = directory;
+    std::string importFile = "";
+    std::string exportFile = "default.mps";
+    std::string importBasisFile = "";
+    std::string importPriorityFile = "";
+    std::string mipStartFile = "";
+    std::string debugFile = "";
+    std::string printMask = "";
+    std::string exportBasisFile = "default.bas";
+    std::string saveFile = "default.prob";
+    std::string restoreFile = "default.prob";
+    std::string solutionFile = "stdout";
+    std::string solutionSaveFile = "solution.file";
+    int doIdiot = -1;
+    int outputFormat = 2;
+    int substitution = 3;
+    int dualize = 3;
+    int preSolve = 5;
+    int doSprint = -1;
+    int testOsiParameters = -1;
+    int createSolver = 0;
+    ClpSimplex * lpSolver;
+    OsiClpSolverInterface * clpSolver;
+    if (model_.solver()) {
+        clpSolver = dynamic_cast<OsiClpSolverInterface *> (model_.solver());
+        assert (clpSolver);
+        lpSolver = clpSolver->getModelPtr();
+        assert (lpSolver);
+    } else {
+        lpSolver = new ClpSimplex();
+        clpSolver = new OsiClpSolverInterface(lpSolver, true);
+        createSolver = 1 ;
+    }
+    parameters_[whichParam(CLP_PARAM_ACTION_BASISIN, numberParameters_, parameters_)].setStringValue(importBasisFile);
+    parameters_[whichParam(CBC_PARAM_ACTION_PRIORITYIN, numberParameters_, parameters_)].setStringValue(importPriorityFile);
+    parameters_[whichParam(CBC_PARAM_ACTION_MIPSTART, numberParameters_, parameters_)].setStringValue(mipStartFile);
+    parameters_[whichParam(CLP_PARAM_ACTION_BASISOUT, numberParameters_, parameters_)].setStringValue(exportBasisFile);
+    parameters_[whichParam(CLP_PARAM_ACTION_DEBUG, numberParameters_, parameters_)].setStringValue(debugFile);
+    parameters_[whichParam(CLP_PARAM_ACTION_PRINTMASK, numberParameters_, parameters_)].setStringValue(printMask);
+    parameters_[whichParam(CLP_PARAM_ACTION_DIRECTORY, numberParameters_, parameters_)].setStringValue(directory);
+    parameters_[whichParam(CLP_PARAM_ACTION_DIRSAMPLE, numberParameters_, parameters_)].setStringValue(dirSample);
+    parameters_[whichParam(CLP_PARAM_ACTION_DIRNETLIB, numberParameters_, parameters_)].setStringValue(dirNetlib);
+    parameters_[whichParam(CBC_PARAM_ACTION_DIRMIPLIB, numberParameters_, parameters_)].setStringValue(dirMiplib);
+    parameters_[whichParam(CLP_PARAM_DBL_DUALBOUND, numberParameters_, parameters_)].setDoubleValue(lpSolver->dualBound());
+    parameters_[whichParam(CLP_PARAM_DBL_DUALTOLERANCE, numberParameters_, parameters_)].setDoubleValue(lpSolver->dualTolerance());
+    parameters_[whichParam(CLP_PARAM_ACTION_EXPORT, numberParameters_, parameters_)].setStringValue(exportFile);
+    parameters_[whichParam(CLP_PARAM_INT_IDIOT, numberParameters_, parameters_)].setIntValue(doIdiot);
+    parameters_[whichParam(CLP_PARAM_ACTION_IMPORT, numberParameters_, parameters_)].setStringValue(importFile);
+    parameters_[whichParam(CLP_PARAM_DBL_PRESOLVETOLERANCE, numberParameters_, parameters_)].setDoubleValue(1.0e-8);
+    int iParam = whichParam(CLP_PARAM_INT_SOLVERLOGLEVEL, numberParameters_, parameters_);
+    int value = 1;
+    clpSolver->messageHandler()->setLogLevel(1) ;
+    lpSolver->setLogLevel(1);
+    parameters_[iParam].setIntValue(value);
+    iParam = whichParam(CLP_PARAM_INT_LOGLEVEL, numberParameters_, parameters_);
+    model_.messageHandler()->setLogLevel(value);
+    parameters_[iParam].setIntValue(value);
+    parameters_[whichParam(CLP_PARAM_INT_MAXFACTOR, numberParameters_, parameters_)].setIntValue(lpSolver->factorizationFrequency());
+    parameters_[whichParam(CLP_PARAM_INT_MAXITERATION, numberParameters_, parameters_)].setIntValue(lpSolver->maximumIterations());
+    parameters_[whichParam(CLP_PARAM_INT_OUTPUTFORMAT, numberParameters_, parameters_)].setIntValue(outputFormat);
+    parameters_[whichParam(CLP_PARAM_INT_PRESOLVEPASS, numberParameters_, parameters_)].setIntValue(preSolve);
+    parameters_[whichParam(CLP_PARAM_INT_PERTVALUE, numberParameters_, parameters_)].setIntValue(lpSolver->perturbation());
+    parameters_[whichParam(CLP_PARAM_DBL_PRIMALTOLERANCE, numberParameters_, parameters_)].setDoubleValue(lpSolver->primalTolerance());
+    parameters_[whichParam(CLP_PARAM_DBL_PRIMALWEIGHT, numberParameters_, parameters_)].setDoubleValue(lpSolver->infeasibilityCost());
+    parameters_[whichParam(CLP_PARAM_ACTION_RESTORE, numberParameters_, parameters_)].setStringValue(restoreFile);
+    parameters_[whichParam(CLP_PARAM_ACTION_SAVE, numberParameters_, parameters_)].setStringValue(saveFile);
+    //parameters_[whichParam(CLP_PARAM_DBL_TIMELIMIT,numberParameters_,parameters_)].setDoubleValue(1.0e8);
+    parameters_[whichParam(CBC_PARAM_DBL_TIMELIMIT_BAB, numberParameters_, parameters_)].setDoubleValue(1.0e8);
+    parameters_[whichParam(CLP_PARAM_ACTION_SOLUTION, numberParameters_, parameters_)].setStringValue(solutionFile);
+    parameters_[whichParam(CLP_PARAM_ACTION_NEXTBESTSOLUTION, numberParameters_, parameters_)].setStringValue(solutionFile);
+    parameters_[whichParam(CLP_PARAM_ACTION_SAVESOL, numberParameters_, parameters_)].setStringValue(solutionSaveFile);
+    parameters_[whichParam(CLP_PARAM_INT_SPRINT, numberParameters_, parameters_)].setIntValue(doSprint);
+    parameters_[whichParam(CLP_PARAM_INT_SUBSTITUTION, numberParameters_, parameters_)].setIntValue(substitution);
+    parameters_[whichParam(CLP_PARAM_INT_DUALIZE, numberParameters_, parameters_)].setIntValue(dualize);
+    parameters_[whichParam(CBC_PARAM_INT_NUMBERBEFORE, numberParameters_, parameters_)].setIntValue(model_.numberBeforeTrust());
+    parameters_[whichParam(CBC_PARAM_INT_MAXNODES, numberParameters_, parameters_)].setIntValue(model_.getMaximumNodes());
+    parameters_[whichParam(CBC_PARAM_INT_STRONGBRANCHING, numberParameters_, parameters_)].setIntValue(model_.numberStrong());
+    parameters_[whichParam(CBC_PARAM_DBL_INFEASIBILITYWEIGHT, numberParameters_, parameters_)].setDoubleValue(model_.getDblParam(CbcModel::CbcInfeasibilityWeight));
+    parameters_[whichParam(CBC_PARAM_DBL_INTEGERTOLERANCE, numberParameters_, parameters_)].setDoubleValue(model_.getDblParam(CbcModel::CbcIntegerTolerance));
+    parameters_[whichParam(CBC_PARAM_DBL_INCREMENT, numberParameters_, parameters_)].setDoubleValue(model_.getDblParam(CbcModel::CbcCutoffIncrement));
+    parameters_[whichParam(CBC_PARAM_INT_TESTOSI, numberParameters_, parameters_)].setIntValue(testOsiParameters);
+    parameters_[whichParam(CBC_PARAM_INT_FPUMPTUNE, numberParameters_, parameters_)].setIntValue(1003);
+    initialPumpTune = 1003;
+#ifdef CBC_THREAD
+    parameters_[whichParam(CBC_PARAM_INT_THREADS, numberParameters_, parameters_)].setIntValue(0);
+#endif
+    // Set up likely cut generators and defaults
+    parameters_[whichParam(CBC_PARAM_STR_PREPROCESS, numberParameters_, parameters_)].setCurrentOption("sos");
+    parameters_[whichParam(CBC_PARAM_INT_MIPOPTIONS, numberParameters_, parameters_)].setIntValue(1057);
+    parameters_[whichParam(CBC_PARAM_INT_CUTPASSINTREE, numberParameters_, parameters_)].setIntValue(1);
+    parameters_[whichParam(CBC_PARAM_INT_MOREMIPOPTIONS, numberParameters_, parameters_)].setIntValue(-1);
+    parameters_[whichParam(CBC_PARAM_INT_MAXHOTITS, numberParameters_, parameters_)].setIntValue(100);
+    parameters_[whichParam(CBC_PARAM_STR_CUTSSTRATEGY, numberParameters_, parameters_)].setCurrentOption("on");
+    parameters_[whichParam(CBC_PARAM_STR_HEURISTICSTRATEGY, numberParameters_, parameters_)].setCurrentOption("on");
+    parameters_[whichParam(CBC_PARAM_STR_NODESTRATEGY, numberParameters_, parameters_)].setCurrentOption("fewest");
+    parameters_[whichParam(CBC_PARAM_STR_GOMORYCUTS, numberParameters_, parameters_)].setCurrentOption("ifmove");
+    parameters_[whichParam(CBC_PARAM_STR_PROBINGCUTS, numberParameters_, parameters_)].setCurrentOption("ifmove");
+    parameters_[whichParam(CBC_PARAM_STR_KNAPSACKCUTS, numberParameters_, parameters_)].setCurrentOption("ifmove");
+    parameters_[whichParam(CBC_PARAM_STR_ZEROHALFCUTS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_REDSPLITCUTS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_REDSPLIT2CUTS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_GMICUTS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_CLIQUECUTS, numberParameters_, parameters_)].setCurrentOption("ifmove");
+    parameters_[whichParam(CBC_PARAM_STR_MIXEDCUTS, numberParameters_, parameters_)].setCurrentOption("ifmove");
+    parameters_[whichParam(CBC_PARAM_STR_FLOWCUTS, numberParameters_, parameters_)].setCurrentOption("ifmove");
+    parameters_[whichParam(CBC_PARAM_STR_TWOMIRCUTS, numberParameters_, parameters_)].setCurrentOption("ifmove");
+    parameters_[whichParam(CBC_PARAM_STR_LANDPCUTS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_RESIDCUTS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_ROUNDING, numberParameters_, parameters_)].setCurrentOption("on");
+    parameters_[whichParam(CBC_PARAM_STR_FPUMP, numberParameters_, parameters_)].setCurrentOption("on");
+    parameters_[whichParam(CBC_PARAM_STR_GREEDY, numberParameters_, parameters_)].setCurrentOption("on");
+    parameters_[whichParam(CBC_PARAM_STR_COMBINE, numberParameters_, parameters_)].setCurrentOption("on");
+    parameters_[whichParam(CBC_PARAM_STR_CROSSOVER2, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_PIVOTANDCOMPLEMENT, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_PIVOTANDFIX, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_RANDROUND, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_NAIVE, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_RINS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_DINS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_RENS, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_LOCALTREE, numberParameters_, parameters_)].setCurrentOption("off");
+    parameters_[whichParam(CBC_PARAM_STR_COSTSTRATEGY, numberParameters_, parameters_)].setCurrentOption("off");
+    if (createSolver)
+        delete clpSolver;
+}
+
+/*
+  Initialise a subset of the parameters prior to processing any input from
+  the user.
+
+  Why this choice of subset?
+*/
+/*!
+  \todo Guard/replace clp-specific code
+*/
+void CbcSolver::fillValuesInSolver()
+{
+    OsiSolverInterface * solver = model_.solver();
+    OsiClpSolverInterface * clpSolver =
+        dynamic_cast< OsiClpSolverInterface*> (solver);
+    assert (clpSolver);
+    ClpSimplex * lpSolver = clpSolver->getModelPtr();
+
+    /*
+      Why are we reaching into the underlying solver(s) for these settings?
+      Shouldn't CbcSolver have its own defaults, which are then imposed on the
+      underlying solver?
+
+      Coming at if from the other side, if CbcSolver had the capability to use
+      multiple solvers then it definitely makes sense to acquire the defaults from
+      the solver (on the assumption that we haven't processed command line
+      parameters yet, which can then override the defaults). But then it's more of
+      a challenge to avoid solver-specific coding here.
+    */
+    noPrinting_ = (lpSolver->logLevel() == 0);
+    CoinMessageHandler * generalMessageHandler = clpSolver->messageHandler();
+    generalMessageHandler->setPrefix(true);
+
+    lpSolver->setPerturbation(50);
+    lpSolver->messageHandler()->setPrefix(false);
+
+    parameters_[whichParam(CLP_PARAM_DBL_DUALBOUND, numberParameters_, parameters_)].setDoubleValue(lpSolver->dualBound());
+    parameters_[whichParam(CLP_PARAM_DBL_DUALTOLERANCE, numberParameters_, parameters_)].setDoubleValue(lpSolver->dualTolerance());
+    /*
+      Why are we doing this? We read the log level from parameters_, set it into
+      the message handlers for cbc and the underlying solver. Then we read the
+      log level back from the handlers and use it to set the values in
+      parameters_!
+    */
+    int iParam = whichParam(CLP_PARAM_INT_SOLVERLOGLEVEL, numberParameters_, parameters_);
+    int value = parameters_[iParam].intValue();
+    clpSolver->messageHandler()->setLogLevel(value) ;
+    lpSolver->setLogLevel(value);
+    iParam = whichParam(CLP_PARAM_INT_LOGLEVEL, numberParameters_, parameters_);
+    value = parameters_[iParam].intValue();
+    model_.messageHandler()->setLogLevel(value);
+    parameters_[whichParam(CLP_PARAM_INT_LOGLEVEL, numberParameters_, parameters_)].setIntValue(model_.logLevel());
+    parameters_[whichParam(CLP_PARAM_INT_SOLVERLOGLEVEL, numberParameters_, parameters_)].setIntValue(lpSolver->logLevel());
+    parameters_[whichParam(CLP_PARAM_INT_MAXFACTOR, numberParameters_, parameters_)].setIntValue(lpSolver->factorizationFrequency());
+    parameters_[whichParam(CLP_PARAM_INT_MAXITERATION, numberParameters_, parameters_)].setIntValue(lpSolver->maximumIterations());
+    parameters_[whichParam(CLP_PARAM_INT_PERTVALUE, numberParameters_, parameters_)].setIntValue(lpSolver->perturbation());
+    parameters_[whichParam(CLP_PARAM_DBL_PRIMALTOLERANCE, numberParameters_, parameters_)].setDoubleValue(lpSolver->primalTolerance());
+    parameters_[whichParam(CLP_PARAM_DBL_PRIMALWEIGHT, numberParameters_, parameters_)].setDoubleValue(lpSolver->infeasibilityCost());
+    parameters_[whichParam(CBC_PARAM_INT_NUMBERBEFORE, numberParameters_, parameters_)].setIntValue(model_.numberBeforeTrust());
+    parameters_[whichParam(CBC_PARAM_INT_MAXNODES, numberParameters_, parameters_)].setIntValue(model_.getMaximumNodes());
+    parameters_[whichParam(CBC_PARAM_INT_STRONGBRANCHING, numberParameters_, parameters_)].setIntValue(model_.numberStrong());
+    parameters_[whichParam(CBC_PARAM_DBL_INFEASIBILITYWEIGHT, numberParameters_, parameters_)].setDoubleValue(model_.getDblParam(CbcModel::CbcInfeasibilityWeight));
+    parameters_[whichParam(CBC_PARAM_DBL_INTEGERTOLERANCE, numberParameters_, parameters_)].setDoubleValue(model_.getDblParam(CbcModel::CbcIntegerTolerance));
+    parameters_[whichParam(CBC_PARAM_DBL_INCREMENT, numberParameters_, parameters_)].setDoubleValue(model_.getDblParam(CbcModel::CbcCutoffIncrement));
+}
+// Add user function
+void
+CbcSolver::addUserFunction(CbcUser * function)
+{
+    CbcUser ** temp = new CbcUser * [numberUserFunctions_+1];
+    int i;
+    for (i = 0; i < numberUserFunctions_; i++)
+        temp[i] = userFunction_[i];
+    delete [] userFunction_;
+    userFunction_ = temp;
+    userFunction_[numberUserFunctions_++] = function->clone();
+    delete [] statusUserFunction_;
+    statusUserFunction_ = NULL;
+}
+// Set user call back
+void
+CbcSolver::setUserCallBack(CbcStopNow * function)
+{
+    delete callBack_;
+    callBack_ = function->clone();
+}
+// Copy of model on initial load (will contain output solutions)
+void
+CbcSolver::setOriginalSolver(OsiClpSolverInterface * originalSolver)
+{
+    delete originalSolver_;
+    OsiSolverInterface * temp = originalSolver->clone();
+    originalSolver_ = dynamic_cast<OsiClpSolverInterface *> (temp);
+    assert (originalSolver_);
+
+}
+// Copy of model on initial load
+void
+CbcSolver::setOriginalCoinModel(CoinModel * originalCoinModel)
+{
+    delete originalCoinModel_;
+    originalCoinModel_ = new CoinModel(*originalCoinModel);
+}
+// Add cut generator
+void
+CbcSolver::addCutGenerator(CglCutGenerator * generator)
+{
+    CglCutGenerator ** temp = new CglCutGenerator * [numberCutGenerators_+1];
+    int i;
+    for (i = 0; i < numberCutGenerators_; i++)
+        temp[i] = cutGenerator_[i];
+    delete [] cutGenerator_;
+    cutGenerator_ = temp;
+    cutGenerator_[numberCutGenerators_++] = generator->clone();
+}
+
+/*
+  The only other solver that's ever been used is cplex, and the use is
+  limited -- do the root with clp and all the cbc smarts, then give the
+  problem over to cplex to finish. Although the defines can be read in some
+  places to allow other options, nothing's been tested and success is
+  unlikely.
+
+  CBC_OTHER_SOLVER == 1 is cplex.
+*/
+
+#if CBC_OTHER_SOLVER==1
+#  ifndef COIN_HAS_CPX
+#    error "Configuration did not detect cplex installation."
+#  else
+#    include "OsiCpxSolverInterface.hpp"
+#  endif
+#endif
+
+#ifdef COIN_HAS_ASL
+#include "Cbc_ampl.h"
+#endif
+
+static double totalTime = 0.0;
+static void statistics(ClpSimplex * originalModel, ClpSimplex * model);
+static bool maskMatches(const int * starts, char ** masks,
+                        std::string & check);
+static void generateCode(CbcModel * model, const char * fileName, int type, int preProcess);
+
+// dummy fake main programs for UserClp and UserCbc
+void fakeMain (ClpSimplex & model, OsiSolverInterface & osiSolver, CbcModel & babSolver);
+void fakeMain2 (ClpSimplex & model, OsiClpSolverInterface & osiSolver, int options);
+
+// Allow for interrupts
+// But is this threadsafe? (so switched off by option)
+
+#include "CoinSignal.hpp"
+static CbcModel * currentBranchModel = NULL;
+
+extern "C" {
+    static void signal_handler(int whichSignal) {
+      if (currentBranchModel != NULL) {
+	currentBranchModel->sayEventHappened(); // say why stopped
+	if (currentBranchModel->heuristicModel())
+	  currentBranchModel->heuristicModel()->sayEventHappened();
+      }
+        return;
+    }
+}
+
+//#define CBC_SIG_TRAP
+#ifdef CBC_SIG_TRAP
+#include <setjmp.h>
+static sigjmp_buf cbc_seg_buffer;
+extern "C" {
+    static void signal_handler_error(int whichSignal) {
+        siglongjmp(cbc_seg_buffer, 1);
+    }
+}
+#endif
+
+
+/*
+  Debug checks on special ordered sets.
+
+  This is active only for debugging. The entire body of the routine becomes
+  a noop when COIN_DEVELOP is not defined. To avoid compiler warnings, the
+  formal parameters also need to go away.
+*/
+#ifdef COIN_DEVELOP
+void checkSOS(CbcModel * babModel, const OsiSolverInterface * solver)
+#else
+void checkSOS(CbcModel * /*babModel*/, const OsiSolverInterface * /*solver*/)
+#endif
+{
+#ifdef COIN_DEVELOP
+    if (!babModel->ownObjects())
+        return;
+#if COIN_DEVELOP>2
+    //const double *objective = solver->getObjCoefficients() ;
+    const double *columnLower = solver->getColLower() ;
+    const double * columnUpper = solver->getColUpper() ;
+    const double * solution = solver->getColSolution();
+    //int numberRows = solver->getNumRows();
+    //double direction = solver->getObjSense();
+    //int iRow,iColumn;
+#endif
+
+    // Row copy
+    CoinPackedMatrix matrixByRow(*solver->getMatrixByRow());
+    //const double * elementByRow = matrixByRow.getElements();
+    //const int * column = matrixByRow.getIndices();
+    //const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+    const int * rowLength = matrixByRow.getVectorLengths();
+
+    // Column copy
+    CoinPackedMatrix  matrixByCol(*solver->getMatrixByCol());
+    const double * element = matrixByCol.getElements();
+    const int * row = matrixByCol.getIndices();
+    const CoinBigIndex * columnStart = matrixByCol.getVectorStarts();
+    const int * columnLength = matrixByCol.getVectorLengths();
+
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    OsiObject ** objects = babModel->objects();
+    int numberObjects = babModel->numberObjects();
+    int numberColumns = solver->getNumCols() ;
+    for (int iObj = 0; iObj < numberObjects; iObj++) {
+        CbcSOS * objSOS =
+            dynamic_cast <CbcSOS *>(objects[iObj]) ;
+        if (objSOS) {
+            int n = objSOS->numberMembers();
+            const int * which = objSOS->members();
+#if COIN_DEVELOP>2
+            const double * weight = objSOS->weights();
+#endif
+            int type = objSOS->sosType();
+            // convexity row?
+            int iColumn;
+            iColumn = which[0];
+            int j;
+            int convex = -1;
+            for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                int iRow = row[j];
+                double value = element[j];
+                if (rowLower[iRow] == 1.0 && rowUpper[iRow] == 1.0 &&
+                        value == 1.0) {
+                    // possible
+                    if (rowLength[iRow] == n) {
+                        if (convex == -1)
+                            convex = iRow;
+                        else
+                            convex = -2;
+                    }
+                }
+            }
+            printf ("set %d of type %d has %d members - possible convexity row %d\n",
+                    iObj, type, n, convex);
+            for (int i = 0; i < n; i++) {
+                iColumn = which[i];
+                // Column may have been added
+                if (iColumn < numberColumns) {
+                    int convex2 = -1;
+                    for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        int iRow = row[j];
+                        if (iRow == convex) {
+                            double value = element[j];
+                            if (value == 1.0) {
+                                convex2 = iRow;
+                            }
+                        }
+                    }
+                    if (convex2<0 && convex >= 0) {
+                        printf("odd convexity row\n");
+                        convex = -2;
+                    }
+#if COIN_DEVELOP>2
+                    printf("col %d has weight %g and value %g, bounds %g %g\n",
+                           iColumn, weight[i], solution[iColumn], columnLower[iColumn],
+                           columnUpper[iColumn]);
+#endif
+                }
+            }
+        }
+    }
+#endif	// COIN_DEVELOP
+}
+
+static int dummyCallBack(CbcModel * /*model*/, int /*whereFrom*/)
+{
+    return 0;
+}
+
+
+/*
+  Global parameters for command processing.
+
+  These will need to be moved into an object of some sort in order to make
+  this set of calls thread-safe.
+*/
+
+int CbcOrClpRead_mode = 1;
+FILE * CbcOrClpReadCommand = stdin;
+extern int CbcOrClpEnvironmentIndex;
+static bool noPrinting = false;
+
+
+
+/*
+  Wrappers for CbcMain0, CbcMain1. The various forms of callCbc will eventually
+  resolve to a call to CbcMain0 followed by a call to callCbc1.
+*/
+/*
+  Simplest calling form: supply just a string with the command options. The
+  wrapper creates an OsiClpSolverInterface and calls the next wrapper.
+*/
+int callCbc(const std::string input2)
+{
+    char * input3 = CoinStrdup(input2.c_str());
+    OsiClpSolverInterface solver1;
+    int returnCode = callCbc(input3, solver1);
+    free(input3);
+    return returnCode;
+}
+
+int callCbc(const char * input2)
+{
+    {
+        OsiClpSolverInterface solver1;
+        return callCbc(input2, solver1);
+    }
+}
+
+/*
+  Second calling form: supply the command line and an OsiClpSolverInterface.
+  the wrapper will create a CbcModel and call the next wrapper.
+*/
+
+int callCbc(const std::string input2, OsiClpSolverInterface& solver1)
+{
+    char * input3 = CoinStrdup(input2.c_str());
+    int returnCode = callCbc(input3, solver1);
+    free(input3);
+    return returnCode;
+}
+
+int callCbc(const char * input2, OsiClpSolverInterface& solver1)
+{
+    CbcModel model(solver1);
+    return callCbc(input2, model);
+}
+
+/*
+  Third calling form: supply the command line and a CbcModel. This wrapper will
+  actually call CbcMain0 and then call the next set of wrappers (callCbc1) to
+  handle the call to CbcMain1.
+*/
+int callCbc(const char * input2, CbcModel & babSolver)
+{
+    CbcMain0(babSolver);
+    return callCbc1(input2, babSolver);
+}
+
+int callCbc(const std::string input2, CbcModel & babSolver)
+{
+    char * input3 = CoinStrdup(input2.c_str());
+    CbcMain0(babSolver);
+    int returnCode = callCbc1(input3, babSolver);
+    free(input3);
+    return returnCode;
+}
+
+
+/*
+  Various overloads of callCbc1. The first pair accepts just a CbcModel and
+  supplements it with a dummy callback routine. The second pair allows the
+  user to supply a callback. See CbcMain1 for further explanation of the
+  callback. The various overloads of callCbc1 resolve to the final version,
+  which breaks the string into individual parameter strings (i.e., creates
+  something that looks like a standard argv vector).
+*/
+
+int callCbc1(const std::string input2, CbcModel & babSolver)
+{
+    char * input3 = CoinStrdup(input2.c_str());
+    int returnCode = callCbc1(input3, babSolver);
+    free(input3);
+    return returnCode;
+}
+
+int callCbc1(const char * input2, CbcModel & model)
+{
+    return callCbc1(input2, model, dummyCallBack);
+}
+
+int callCbc1(const std::string input2, CbcModel & babSolver,
+             int callBack(CbcModel * currentSolver, int whereFrom))
+{
+    char * input3 = CoinStrdup(input2.c_str());
+    int returnCode = callCbc1(input3, babSolver, callBack);
+    free(input3);
+    return returnCode;
+}
+
+int callCbc1(const char * input2, CbcModel & model,
+             int callBack(CbcModel * currentSolver, int whereFrom))
+{
+    char * input = CoinStrdup(input2);
+    size_t length = strlen(input);
+    bool blank = input[0] == '0';
+    int n = blank ? 0 : 1;
+    for (size_t i = 0; i < length; i++) {
+        if (blank) {
+            // look for next non blank
+            if (input[i] == ' ') {
+                continue;
+            } else {
+                n++;
+                blank = false;
+            }
+        } else {
+            // look for next blank
+            if (input[i] != ' ') {
+                continue;
+            } else {
+                blank = true;
+            }
+        }
+    }
+    char ** argv = new char * [n+2];
+    argv[0] = CoinStrdup("cbc");
+    size_t i = 0;
+    while (input[i] == ' ')
+        i++;
+    for (int j = 0; j < n; j++) {
+        size_t saveI = i;
+        for (; i < length; i++) {
+            // look for next blank
+            if (input[i] != ' ') {
+                continue;
+            } else {
+                break;
+            }
+        }
+        input[i++] = '\0';
+        argv[j+1] = CoinStrdup(input + saveI);
+        while (input[i] == ' ')
+            i++;
+    }
+    argv[n+1] = CoinStrdup("-quit");
+    free(input);
+    totalTime = 0.0;
+    currentBranchModel = NULL;
+    CbcOrClpRead_mode = 1;
+    CbcOrClpReadCommand = stdin;
+    noPrinting = false;
+    int returnCode = CbcMain1(n + 2, const_cast<const char **>(argv),
+                              model, callBack);
+    for (int k = 0; k < n + 2; k++)
+        free(argv[k]);
+    delete [] argv;
+    return returnCode;
+}
+
+static CbcOrClpParam parameters[CBCMAXPARAMETERS];
+static int numberParameters = 0 ;
+CglPreProcess * cbcPreProcessPointer=NULL;
+
+int CbcClpUnitTest (const CbcModel & saveModel,
+                    const std::string& dirMiplib, int testSwitch,
+                    const double * stuff);
+
+int CbcMain1 (int argc, const char *argv[],
+              CbcModel  & model)
+{
+    return CbcMain1(argc, argv, model, dummyCallBack);
+}
+
+
+/*
+  Meaning of whereFrom:
+    1 after initial solve by dualsimplex etc
+    2 after preprocessing
+    3 just before branchAndBound (so user can override)
+    4 just after branchAndBound (before postprocessing)
+    5 after postprocessing
+    6 after a user called heuristic phase
+*/
+
+int CbcMain1 (int argc, const char *argv[],
+              CbcModel  & model,
+              int callBack(CbcModel * currentSolver, int whereFrom))
+{
+    CbcOrClpParam * parameters_ = parameters;
+    int numberParameters_ = numberParameters;
+    CbcModel & model_ = model;
+#ifdef CBC_USE_INITIAL_TIME
+    if (model_.useElapsedTime())
+      model_.setDblParam(CbcModel::CbcStartSeconds, CoinGetTimeOfDay());
+    else
+      model_.setDblParam(CbcModel::CbcStartSeconds, CoinCpuTime());
+#endif
+    CbcModel * babModel_ = NULL;
+    int returnMode = 1;
+    CbcOrClpRead_mode = 1;
+    int statusUserFunction_[1];
+    int numberUserFunctions_ = 1; // to allow for ampl
+    // Statistics
+    double statistics_seconds = 0.0, statistics_obj = 0.0;
+    double statistics_sys_seconds = 0.0, statistics_elapsed_seconds = 0.0;
+    CoinWallclockTime();
+    double statistics_continuous = 0.0, statistics_tighter = 0.0;
+    double statistics_cut_time = 0.0;
+    int statistics_nodes = 0, statistics_iterations = 0;
+    int statistics_nrows = 0, statistics_ncols = 0;
+    int statistics_nprocessedrows = 0, statistics_nprocessedcols = 0;
+    std::string statistics_result;
+    int * statistics_number_cuts = NULL;
+    const char ** statistics_name_generators = NULL;
+    int statistics_number_generators = 0;
+    memset(statusUserFunction_, 0, numberUserFunctions_*sizeof(int));
+    /* Note
+       This is meant as a stand-alone executable to do as much of coin as possible.
+       It should only have one solver known to it.
+    */
+    CoinMessageHandler * generalMessageHandler = model_.messageHandler();
+    generalMessageHandler->setPrefix(false);
+#ifndef CBC_OTHER_SOLVER
+    OsiClpSolverInterface * originalSolver = dynamic_cast<OsiClpSolverInterface *> (model_.solver());
+    assert (originalSolver);
+    // Move handler across if not default
+    if (!originalSolver->defaultHandler() && originalSolver->getModelPtr()->defaultHandler())
+        originalSolver->getModelPtr()->passInMessageHandler(originalSolver->messageHandler());
+    CoinMessages generalMessages = originalSolver->getModelPtr()->messages();
+    char generalPrint[10000];
+    if (originalSolver->getModelPtr()->logLevel() == 0)
+        noPrinting = true;
+#elif CBC_OTHER_SOLVER==1
+    OsiCpxSolverInterface * originalSolver = dynamic_cast<OsiCpxSolverInterface *> (model_.solver());
+    assert (originalSolver);
+    OsiClpSolverInterface dummySolver;
+    OsiCpxSolverInterface * clpSolver = originalSolver;
+    CoinMessages generalMessages = dummySolver.getModelPtr()->messages();
+    char generalPrint[10000];
+    noPrinting = true;
+#endif
+    bool noPrinting_ = noPrinting;
+    // Say not in integer
+    int integerStatus = -1;
+    // Say no resolve after cuts
+    model_.setResolveAfterTakeOffCuts(false);
+    // see if log in list
+    for (int i = 1; i < argc; i++) {
+        if (!strncmp(argv[i], "log", 3)) {
+            const char * equals = strchr(argv[i], '=');
+            if (equals && atoi(equals + 1) != 0)
+                noPrinting_ = false;
+            else
+                noPrinting_ = true;
+            break;
+        } else if (!strncmp(argv[i], "-log", 4) && i < argc - 1) {
+            if (atoi(argv[i+1]) != 0)
+                noPrinting_ = false;
+            else
+                noPrinting_ = true;
+            break;
+        }
+    }
+    double time0;
+    double time0Elapsed = CoinGetTimeOfDay();
+    {
+        double time1 = CoinCpuTime(), time2;
+        time0 = time1;
+	double time1Elapsed = time0Elapsed;
+        bool goodModel = (originalSolver->getNumCols()) ? true : false;
+
+        // register signal handler
+        //CoinSighandler_t saveSignal=signal(SIGINT,signal_handler);
+#if CBC_QUIET < 2
+        signal(SIGINT, signal_handler);
+#endif
+        // Set up all non-standard stuff
+        int cutPass = -1234567;
+        int cutPassInTree = -1234567;
+        int tunePreProcess = 0;
+        int testOsiParameters = -1;
+        // 0 normal, 1 from ampl or MIQP etc (2 allows cuts)
+        int complicatedInteger = 0;
+        OsiSolverInterface * solver = model_.solver();
+        if (noPrinting_)
+            setCbcOrClpPrinting(false);
+#ifndef CBC_OTHER_SOLVER
+        OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+        ClpSimplex * lpSolver = clpSolver->getModelPtr();
+        if (noPrinting_) {
+            lpSolver->setLogLevel(0);
+        }
+#else
+        ClpSimplex * lpSolver = NULL;
+#endif
+        // For priorities etc
+        int * priorities = NULL;
+        int * branchDirection = NULL;
+        double * pseudoDown = NULL;
+        double * pseudoUp = NULL;
+        double * solutionIn = NULL;
+        int * prioritiesIn = NULL;
+        std::vector< std::pair< std::string, double > > mipStart;
+        std::vector< std::pair< std::string, double > > mipStartBefore;
+        int numberSOS = 0;
+        int * sosStart = NULL;
+        int * sosIndices = NULL;
+        char * sosType = NULL;
+        double * sosReference = NULL;
+        int * cut = NULL;
+        int * sosPriority = NULL;
+        CglStored storedAmpl;
+        CoinModel * coinModel = NULL;
+        CoinModel saveCoinModel;
+        CoinModel saveTightenedModel;
+        int * whichColumn = NULL;
+        int * knapsackStart = NULL;
+        int * knapsackRow = NULL;
+        int numberKnapsack = 0;
+#ifdef COIN_HAS_ASL
+        ampl_info info;
+        {
+            memset(&info, 0, sizeof(info));
+            if (argc > 2 && !strcmp(argv[2], "-AMPL")) {
+                statusUserFunction_[0] = 1;
+                // see if log in list
+                noPrinting_ = true;
+                for (int i = 1; i < argc; i++) {
+                    if (!strncmp(argv[i], "log", 3)) {
+                        const char * equals = strchr(argv[i], '=');
+                        if (equals && atoi(equals + 1) > 0) {
+                            noPrinting_ = false;
+                            info.logLevel = atoi(equals + 1);
+                            int log = whichParam(CLP_PARAM_INT_LOGLEVEL, numberParameters_, parameters_);
+                            parameters_[log].setIntValue(info.logLevel);
+                            // mark so won't be overWritten
+                            info.numberRows = -1234567;
+                            break;
+                        }
+                    }
+                }
+
+                union {
+                    void * voidModel;
+                    CoinModel * model;
+                } coinModelStart;
+                coinModelStart.model = NULL;
+                int returnCode = readAmpl(&info, argc, const_cast<char **>(argv), & coinModelStart.voidModel);
+                coinModel = coinModelStart.model;
+                if (returnCode)
+                    return returnCode;
+                CbcOrClpRead_mode = 2; // so will start with parameters
+                // see if log in list (including environment)
+                for (int i = 1; i < info.numberArguments; i++) {
+                    if (!strcmp(info.arguments[i], "log")) {
+                        if (i < info.numberArguments - 1 && atoi(info.arguments[i+1]) > 0)
+                            noPrinting_ = false;
+                        break;
+                    }
+                }
+                if (noPrinting_) {
+                    model_.messageHandler()->setLogLevel(0);
+                    setCbcOrClpPrinting(false);
+                }
+                if (!noPrinting_)
+                    printf("%d rows, %d columns and %d elements\n",
+                           info.numberRows, info.numberColumns, info.numberElements);
+#ifdef COIN_HAS_LINK
+                if (!coinModel) {
+#endif
+                    solver->loadProblem(info.numberColumns, info.numberRows, info.starts,
+                                        info.rows, info.elements,
+                                        info.columnLower, info.columnUpper, info.objective,
+                                        info.rowLower, info.rowUpper);
+                    // take off cuts if ampl wants that
+                    if (info.cut && 0) {
+                        printf("AMPL CUTS OFF until global cuts fixed\n");
+                        info.cut = NULL;
+                    }
+                    if (info.cut) {
+                        int numberRows = info.numberRows;
+                        int * whichRow = new int [numberRows];
+                        // Row copy
+                        const CoinPackedMatrix * matrixByRow = solver->getMatrixByRow();
+                        const double * elementByRow = matrixByRow->getElements();
+                        const int * column = matrixByRow->getIndices();
+                        const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+                        const int * rowLength = matrixByRow->getVectorLengths();
+
+                        const double * rowLower = solver->getRowLower();
+                        const double * rowUpper = solver->getRowUpper();
+                        int nDelete = 0;
+                        for (int iRow = 0; iRow < numberRows; iRow++) {
+                            if (info.cut[iRow]) {
+                                whichRow[nDelete++] = iRow;
+                                int start = rowStart[iRow];
+                                storedAmpl.addCut(rowLower[iRow], rowUpper[iRow],
+                                                  rowLength[iRow], column + start, elementByRow + start);
+                            }
+                        }
+                        solver->deleteRows(nDelete, whichRow);
+                        delete [] whichRow;
+                    }
+#ifdef COIN_HAS_LINK
+                } else {
+#ifndef CBC_OTHER_SOLVER
+                    // save
+                    saveCoinModel = *coinModel;
+                    // load from coin model
+                    OsiSolverLink solver1;
+                    OsiSolverInterface * solver2 = solver1.clone();
+                    model_.assignSolver(solver2, false);
+                    OsiSolverLink * si =
+                        dynamic_cast<OsiSolverLink *>(model_.solver()) ;
+                    assert (si != NULL);
+                    si->setDefaultMeshSize(0.001);
+                    // need some relative granularity
+                    si->setDefaultBound(100.0);
+                    double dextra3 = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA3, numberParameters_, parameters_)].doubleValue();
+                    if (dextra3)
+                        si->setDefaultMeshSize(dextra3);
+                    si->setDefaultBound(100000.0);
+                    si->setIntegerPriority(1000);
+                    si->setBiLinearPriority(10000);
+                    CoinModel * model2 = reinterpret_cast<CoinModel *> (coinModel);
+                    int logLevel = parameters_[whichParam(CLP_PARAM_INT_LOGLEVEL, numberParameters_, parameters_)].intValue();
+                    si->load(*model2, true, logLevel);
+                    // redo
+                    solver = model_.solver();
+                    clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+                    lpSolver = clpSolver->getModelPtr();
+                    clpSolver->messageHandler()->setLogLevel(0) ;
+                    testOsiParameters = 0;
+                    parameters_[whichParam(CBC_PARAM_INT_TESTOSI, numberParameters_, parameters_)].setIntValue(0);
+                    complicatedInteger = 1;
+                    if (info.cut) {
+                        printf("Sorry - can't do cuts with LOS as ruins delicate row order\n");
+                        abort();
+                        int numberRows = info.numberRows;
+                        int * whichRow = new int [numberRows];
+                        // Row copy
+                        const CoinPackedMatrix * matrixByRow = solver->getMatrixByRow();
+                        const double * elementByRow = matrixByRow->getElements();
+                        const int * column = matrixByRow->getIndices();
+                        const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+                        const int * rowLength = matrixByRow->getVectorLengths();
+
+                        const double * rowLower = solver->getRowLower();
+                        const double * rowUpper = solver->getRowUpper();
+                        int nDelete = 0;
+                        for (int iRow = 0; iRow < numberRows; iRow++) {
+                            if (info.cut[iRow]) {
+                                whichRow[nDelete++] = iRow;
+                                int start = rowStart[iRow];
+                                storedAmpl.addCut(rowLower[iRow], rowUpper[iRow],
+                                                  rowLength[iRow], column + start, elementByRow + start);
+                            }
+                        }
+                        solver->deleteRows(nDelete, whichRow);
+                        // and special matrix
+                        si->cleanMatrix()->deleteRows(nDelete, whichRow);
+                        delete [] whichRow;
+                    }
+#endif
+                }
+#endif
+                // If we had a solution use it
+                if (info.primalSolution) {
+                    solver->setColSolution(info.primalSolution);
+                }
+                // status
+                if (info.rowStatus) {
+                    unsigned char * statusArray = lpSolver->statusArray();
+                    int i;
+                    for (i = 0; i < info.numberColumns; i++)
+                        statusArray[i] = static_cast<unsigned char>(info.columnStatus[i]);
+                    statusArray += info.numberColumns;
+                    for (i = 0; i < info.numberRows; i++)
+                        statusArray[i] = static_cast<unsigned char>(info.rowStatus[i]);
+                    CoinWarmStartBasis * basis = lpSolver->getBasis();
+                    solver->setWarmStart(basis);
+                    delete basis;
+                }
+                freeArrays1(&info);
+                // modify objective if necessary
+                solver->setObjSense(info.direction);
+                solver->setDblParam(OsiObjOffset, info.offset);
+                if (info.offset) {
+                    sprintf(generalPrint, "Ampl objective offset is %g",
+                            info.offset);
+                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                    << generalPrint
+                    << CoinMessageEol;
+                }
+                // Set integer variables (unless nonlinear when set)
+                if (!info.nonLinear) {
+                    for (int i = info.numberColumns - info.numberIntegers;
+                            i < info.numberColumns; i++)
+                        solver->setInteger(i);
+                }
+                goodModel = true;
+                // change argc etc
+                argc = info.numberArguments;
+                argv = const_cast<const char **>(info.arguments);
+            }
+        }
+#endif
+        // default action on import
+        int allowImportErrors = 0;
+        int keepImportNames = 1;
+        int doIdiot = -1;
+        int outputFormat = 2;
+        int slpValue = -1;
+        int cppValue = -1;
+        int printOptions = 0;
+        int printMode = 0;
+        int presolveOptions = 0;
+        int substitution = 3;
+        int dualize = 3;
+        int doCrash = 0;
+        int doVector = 0;
+        int doSprint = -1;
+        int doScaling = 4;
+        // set reasonable defaults
+        int preSolve = 5;
+        int preProcess = 4;
+        bool useStrategy = false;
+        bool preSolveFile = false;
+        bool strongChanged = false;
+        bool pumpChanged = false;
+
+        double djFix = 1.0e100;
+        double tightenFactor = 0.0;
+        const char dirsep =  CoinFindDirSeparator();
+        std::string directory;
+        std::string dirSample;
+        std::string dirNetlib;
+        std::string dirMiplib;
+        if (dirsep == '/') {
+            directory = "./";
+            dirSample = "../../Data/Sample/";
+            dirNetlib = "../../Data/Netlib/";
+            dirMiplib = "../../Data/miplib3/";
+        } else {
+            directory = ".\\";
+            dirSample = "..\\..\\..\\..\\Data\\Sample\\";
+            dirNetlib = "..\\..\\..\\..\\Data\\Netlib\\";
+            dirMiplib = "..\\..\\..\\..\\Data\\miplib3\\";
+        }
+        std::string defaultDirectory = directory;
+        std::string importFile = "";
+        std::string exportFile = "default.mps";
+        std::string importBasisFile = "";
+        std::string importPriorityFile = "";
+        std::string debugFile = "";
+        std::string printMask = "";
+        double * debugValues = NULL;
+        int numberDebugValues = -1;
+        int basisHasValues = 0;
+        std::string exportBasisFile = "default.bas";
+        std::string saveFile = "default.prob";
+        std::string restoreFile = "default.prob";
+        std::string solutionFile = "stdout";
+        std::string solutionSaveFile = "solution.file";
+        int slog = whichParam(CLP_PARAM_INT_SOLVERLOGLEVEL, numberParameters_, parameters_);
+        int log = whichParam(CLP_PARAM_INT_LOGLEVEL, numberParameters_, parameters_);
+#ifndef CBC_OTHER_SOLVER
+        double normalIncrement = model_.getCutoffIncrement();;
+#endif
+        if (testOsiParameters >= 0) {
+            // trying nonlinear - switch off some stuff
+            preProcess = 0;
+        }
+        // Set up likely cut generators and defaults
+        int nodeStrategy = 0;
+        bool dominatedCuts = false;
+        int doSOS = 1;
+        int verbose = 0;
+        CglGomory gomoryGen;
+        // try larger limit
+        gomoryGen.setLimitAtRoot(1000);
+        gomoryGen.setLimit(50);
+        // set default action (0=off,1=on,2=root)
+        int gomoryAction = 3;
+
+        CglProbing probingGen;
+        probingGen.setUsingObjective(1);
+        probingGen.setMaxPass(1);
+        probingGen.setMaxPassRoot(1);
+        // Number of unsatisfied variables to look at
+        probingGen.setMaxProbe(10);
+        probingGen.setMaxProbeRoot(50);
+        // How far to follow the consequences
+        probingGen.setMaxLook(10);
+        probingGen.setMaxLookRoot(50);
+        probingGen.setMaxLookRoot(10);
+        // Only look at rows with fewer than this number of elements
+        probingGen.setMaxElements(200);
+        probingGen.setMaxElementsRoot(300);
+        probingGen.setRowCuts(3);
+        // set default action (0=off,1=on,2=root)
+        int probingAction = 1;
+
+        CglKnapsackCover knapsackGen;
+        //knapsackGen.switchOnExpensive();
+        //knapsackGen.setMaxInKnapsack(100);
+        // set default action (0=off,1=on,2=root)
+        int knapsackAction = 3;
+
+        CglRedSplit redsplitGen;
+        //redsplitGen.setLimit(100);
+        // set default action (0=off,1=on,2=root)
+        // Off as seems to give some bad cuts
+        int redsplitAction = 0;
+
+        CglRedSplit2 redsplit2Gen;
+        //redsplit2Gen.setLimit(100);
+        // set default action (0=off,1=on,2=root)
+        // Off
+        int redsplit2Action = 0;
+
+        CglGMI GMIGen;
+        //GMIGen.setLimit(100);
+        // set default action (0=off,1=on,2=root)
+        // Off 
+        int GMIAction = 0;
+
+        CglFakeClique cliqueGen(NULL, false);
+        //CglClique cliqueGen(false,true);
+        cliqueGen.setStarCliqueReport(false);
+        cliqueGen.setRowCliqueReport(false);
+        cliqueGen.setMinViolation(0.1);
+        // set default action (0=off,1=on,2=root)
+        int cliqueAction = 3;
+
+        // maxaggr,multiply,criterion(1-3)
+        CglMixedIntegerRounding2 mixedGen(1, true, 1);
+        // set default action (0=off,1=on,2=root)
+        int mixedAction = 3;
+	mixedGen.setDoPreproc(1); // safer (and better)
+
+        CglFlowCover flowGen;
+        // set default action (0=off,1=on,2=root)
+        int flowAction = 3;
+
+        CglTwomir twomirGen;
+        twomirGen.setMaxElements(250);
+        // set default action (0=off,1=on,2=root)
+        int twomirAction = 3;
+#ifndef DEBUG_MALLOC
+        CglLandP landpGen;
+	landpGen.validator().setMinViolation(1.0e-4);
+#endif
+        // set default action (0=off,1=on,2=root)
+        int landpAction = 0;
+        CglResidualCapacity residualCapacityGen;
+        residualCapacityGen.setDoPreproc(1); // always preprocess
+        // set default action (0=off,1=on,2=root)
+        int residualCapacityAction = 0;
+
+        CglZeroHalf zerohalfGen;
+        //zerohalfGen.switchOnExpensive();
+        // set default action (0=off,1=on,2=root)
+        int zerohalfAction = 0;
+
+        // Stored cuts
+        //bool storedCuts = false;
+
+        int useCosts = 0;
+        // don't use input solution
+        int useSolution = -1;
+
+        // total number of commands read
+        int numberGoodCommands = 0;
+        // Set false if user does anything advanced
+        bool defaultSettings = true;
+
+        // Hidden stuff for barrier
+        int choleskyType = 0;
+        int gamma = 0;
+        int scaleBarrier = 0;
+        int doKKT = 0;
+        int crossover = 2; // do crossover unless quadratic
+	bool biLinearProblem=false;
+        // For names
+        int lengthName = 0;
+        std::vector<std::string> rowNames;
+        std::vector<std::string> columnNames;
+        // Default strategy stuff
+        {
+            // try changing tolerance at root
+#define MORE_CUTS
+#ifdef MORE_CUTS
+            gomoryGen.setAwayAtRoot(0.005);
+            twomirGen.setAwayAtRoot(0.005);
+            twomirGen.setAway(0.01);
+            //twomirGen.setMirScale(1,1);
+            //twomirGen.setTwomirScale(1,1);
+            //twomirGen.setAMax(2);
+#else
+            gomoryGen.setAwayAtRoot(0.01);
+            twomirGen.setAwayAtRoot(0.01);
+            twomirGen.setAway(0.01);
+#endif
+            int iParam;
+            iParam = whichParam(CBC_PARAM_INT_DIVEOPT, numberParameters_, parameters_);
+            parameters_[iParam].setIntValue(3);
+            iParam = whichParam(CBC_PARAM_INT_FPUMPITS, numberParameters_, parameters_);
+            parameters_[iParam].setIntValue(30);
+            iParam = whichParam(CBC_PARAM_INT_FPUMPTUNE, numberParameters_, parameters_);
+            parameters_[iParam].setIntValue(1005043);
+            initialPumpTune = 1005043;
+            iParam = whichParam(CLP_PARAM_INT_PROCESSTUNE, numberParameters_, parameters_);
+            parameters_[iParam].setIntValue(6);
+            tunePreProcess = 6;
+            iParam = whichParam(CBC_PARAM_STR_DIVINGC, numberParameters_, parameters_);
+            parameters_[iParam].setCurrentOption("on");
+            iParam = whichParam(CBC_PARAM_STR_RINS, numberParameters_, parameters_);
+            parameters_[iParam].setCurrentOption("on");
+            iParam = whichParam(CBC_PARAM_STR_PROBINGCUTS, numberParameters_, parameters_);
+            parameters_[iParam].setCurrentOption("on");
+            probingAction = 3;
+            //parameters_[iParam].setCurrentOption("forceOnStrong");
+            //probingAction = 8;
+        }
+        std::string field;
+#if CBC_QUIET == 0
+        if (!noPrinting_) {
+	   sprintf(generalPrint,
+		   "Welcome to the CBC MILP Solver \n");
+	    if (strcmp(CBC_VERSION, "trunk")){
+	       sprintf(generalPrint + strlen(generalPrint),
+		       "Version: %s \n", CBC_VERSION);
+	    }else{
+	       sprintf(generalPrint + strlen(generalPrint),
+		       "Version: Trunk (unstable) \n");
+	    }
+	    sprintf(generalPrint + strlen(generalPrint),
+		    "Build Date: %s \n", __DATE__);
+#ifdef CBC_SVN_REV
+	    sprintf(generalPrint + strlen(generalPrint),
+		    "Revision Number: %d \n", CBC_SVN_REV);
+#endif
+            generalMessageHandler->message(CLP_GENERAL, generalMessages)
+            << generalPrint
+            << CoinMessageEol;
+            // Print command line
+            if (argc > 1) {
+                bool foundStrategy = false;
+                sprintf(generalPrint, "command line - ");
+                for (int i = 0; i < argc; i++) {
+                    if (!argv[i])
+                        break;
+                    if (strstr(argv[i], "strat"))
+                        foundStrategy = true;
+                    sprintf(generalPrint + strlen(generalPrint), "%s ", argv[i]);
+                }
+                if (!foundStrategy)
+                    sprintf(generalPrint + strlen(generalPrint), "(default strategy 1)");
+                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                << generalPrint
+                << CoinMessageEol;
+            }
+        }
+#endif
+        while (1) {
+            // next command
+            field = CoinReadGetCommand(argc, argv);
+            // Reset time
+            time1 = CoinCpuTime();
+	    time1Elapsed = CoinGetTimeOfDay();
+            // adjust field if has odd trailing characters
+            char temp [200];
+            strcpy(temp, field.c_str());
+            int length = static_cast<int>(strlen(temp));
+            for (int k = length - 1; k >= 0; k--) {
+                if (temp[k] < ' ')
+                    length--;
+                else
+                    break;
+            }
+            temp[length] = '\0';
+            field = temp;
+            // exit if null or similar
+            if (!field.length()) {
+                if (numberGoodCommands == 1 && goodModel) {
+                    // we just had file name - do branch and bound
+                    field = "branch";
+                } else if (!numberGoodCommands) {
+                    // let's give the sucker a hint
+                    std::cout
+                        << "CoinSolver takes input from arguments ( - switches to stdin)"
+                        << std::endl
+                        << "Enter ? for list of commands or help" << std::endl;
+                    field = "-";
+                } else {
+                    break;
+                }
+            }
+
+            // see if ? at end
+            size_t numberQuery = 0;
+            if (field != "?" && field != "???") {
+                size_t length = field.length();
+                size_t i;
+                for (i = length - 1; i > 0; i--) {
+                    if (field[i] == '?')
+                        numberQuery++;
+                    else
+                        break;
+                }
+                field = field.substr(0, length - numberQuery);
+            }
+            // find out if valid command
+            int iParam;
+            int numberMatches = 0;
+            int firstMatch = -1;
+            for ( iParam = 0; iParam < numberParameters_; iParam++ ) {
+                int match = parameters_[iParam].matches(field);
+                if (match == 1) {
+                    numberMatches = 1;
+                    firstMatch = iParam;
+                    break;
+                } else {
+                    if (match && firstMatch < 0)
+                        firstMatch = iParam;
+                    numberMatches += match >> 1;
+                }
+            }
+            if (iParam < numberParameters_ && !numberQuery) {
+                // found
+                CbcOrClpParam found = parameters_[iParam];
+                CbcOrClpParameterType type = found.type();
+                int valid;
+                numberGoodCommands++;
+                if (type == CBC_PARAM_ACTION_BAB && goodModel) {
+#ifndef CBC_USE_INITIAL_TIME
+		  if (model_.useElapsedTime())
+		    model_.setDblParam(CbcModel::CbcStartSeconds, CoinGetTimeOfDay());
+		  else
+		    model_.setDblParam(CbcModel::CbcStartSeconds, CoinCpuTime());
+#endif
+		  biLinearProblem=false;
+                    // check if any integers
+#ifndef CBC_OTHER_SOLVER
+#ifdef COIN_HAS_ASL
+                    if (info.numberSos && doSOS && statusUserFunction_[0]) {
+                        // SOS
+                        numberSOS = info.numberSos;
+                    }
+#endif
+                    lpSolver = clpSolver->getModelPtr();
+                    if (!lpSolver->integerInformation() && !numberSOS &&
+                            !clpSolver->numberSOS() && !model_.numberObjects() && !clpSolver->numberObjects())
+                        type = CLP_PARAM_ACTION_DUALSIMPLEX;
+#endif
+                }
+                if (type == CBC_PARAM_GENERALQUERY) {
+                    bool evenHidden = false;
+                    int printLevel =
+                        parameters_[whichParam(CLP_PARAM_STR_ALLCOMMANDS,
+                                               numberParameters_, parameters_)].currentOptionAsInteger();
+                    int convertP[] = {2, 1, 0};
+                    printLevel = convertP[printLevel];
+                    if ((verbose&8) != 0) {
+                        // even hidden
+                        evenHidden = true;
+                        verbose &= ~8;
+                    }
+#ifdef COIN_HAS_ASL
+                    if (verbose < 4 && statusUserFunction_[0])
+                        verbose += 4;
+#endif
+                    if (verbose < 4) {
+                        std::cout << "In argument list keywords have leading - "
+                                  ", -stdin or just - switches to stdin" << std::endl;
+                        std::cout << "One command per line (and no -)" << std::endl;
+                        std::cout << "abcd? gives list of possibilities, if only one + explanation" << std::endl;
+                        std::cout << "abcd?? adds explanation, if only one fuller help" << std::endl;
+                        std::cout << "abcd without value (where expected) gives current value" << std::endl;
+                        std::cout << "abcd value sets value" << std::endl;
+                        std::cout << "Commands are:" << std::endl;
+                    } else {
+                        std::cout << "Cbc options are set within AMPL with commands like:" << std::endl << std::endl;
+                        std::cout << "         option cbc_options \"cuts=root log=2 feas=on slog=1\"" << std::endl << std::endl;
+                        std::cout << "only maximize, dual, primal, help and quit are recognized without =" << std::endl;
+                    }
+                    int maxAcross = 10;
+                    if ((verbose % 4) != 0)
+                        maxAcross = 1;
+                    int limits[] = {1, 51, 101, 151, 201, 251, 301, 351, 401};
+                    std::vector<std::string> types;
+                    types.push_back("Double parameters:");
+                    types.push_back("Branch and Cut double parameters:");
+                    types.push_back("Integer parameters:");
+                    types.push_back("Branch and Cut integer parameters:");
+                    types.push_back("Keyword parameters:");
+                    types.push_back("Branch and Cut keyword parameters:");
+                    types.push_back("Actions or string parameters:");
+                    types.push_back("Branch and Cut actions:");
+                    int iType;
+                    for (iType = 0; iType < 8; iType++) {
+                        int across = 0;
+                        int lengthLine = 0;
+                        if ((verbose % 4) != 0)
+                            std::cout << std::endl;
+                        std::cout << types[iType] << std::endl;
+                        if ((verbose&2) != 0)
+                            std::cout << std::endl;
+                        for ( iParam = 0; iParam < numberParameters_; iParam++ ) {
+                            int type = parameters_[iParam].type();
+                            //printf("%d type %d limits %d %d display %d\n",iParam,
+                            //     type,limits[iType],limits[iType+1],parameters_[iParam].displayThis());
+                            if ((parameters_[iParam].displayThis() >= printLevel || evenHidden) &&
+                                    type >= limits[iType]
+                                    && type < limits[iType+1]) {
+                                // but skip if not useful for ampl (and in ampl mode)
+                                if (verbose >= 4 && (parameters_[iParam].whereUsed()&4) == 0)
+                                    continue;
+                                if (!across) {
+                                    if ((verbose&2) != 0)
+                                        std::cout << "Command ";
+                                }
+                                int length = parameters_[iParam].lengthMatchName() + 1;
+                                if (lengthLine + length > 80) {
+                                    std::cout << std::endl;
+                                    across = 0;
+                                    lengthLine = 0;
+                                }
+                                std::cout << " " << parameters_[iParam].matchName();
+                                lengthLine += length;
+                                across++;
+                                if (across == maxAcross) {
+                                    across = 0;
+                                    if ((verbose % 4) != 0) {
+                                        // put out description as well
+                                        if ((verbose&1) != 0)
+                                            std::cout << " " << parameters_[iParam].shortHelp();
+                                        std::cout << std::endl;
+                                        if ((verbose&2) != 0) {
+                                            std::cout << "---- description" << std::endl;
+                                            parameters_[iParam].printLongHelp();
+                                            std::cout << "----" << std::endl << std::endl;
+                                        }
+                                    } else {
+                                        std::cout << std::endl;
+                                    }
+                                }
+                            }
+                        }
+                        if (across)
+                            std::cout << std::endl;
+                    }
+                } else if (type == CBC_PARAM_FULLGENERALQUERY) {
+                    std::cout << "Full list of commands is:" << std::endl;
+                    int maxAcross = 5;
+                    int limits[] = {1, 51, 101, 151, 201, 251, 301, 351, 401};
+                    std::vector<std::string> types;
+                    types.push_back("Double parameters:");
+                    types.push_back("Branch and Cut double parameters:");
+                    types.push_back("Integer parameters:");
+                    types.push_back("Branch and Cut integer parameters:");
+                    types.push_back("Keyword parameters:");
+                    types.push_back("Branch and Cut keyword parameters:");
+                    types.push_back("Actions or string parameters:");
+                    types.push_back("Branch and Cut actions:");
+                    int iType;
+                    for (iType = 0; iType < 8; iType++) {
+                        int across = 0;
+                        std::cout << types[iType] << "  ";
+                        for ( iParam = 0; iParam < numberParameters_; iParam++ ) {
+                            int type = parameters_[iParam].type();
+                            if (type >= limits[iType]
+                                    && type < limits[iType+1]) {
+                                if (!across)
+                                    std::cout << "  ";
+                                std::cout << parameters_[iParam].matchName() << "  ";
+                                across++;
+                                if (across == maxAcross) {
+                                    std::cout << std::endl;
+                                    across = 0;
+                                }
+                            }
+                        }
+                        if (across)
+                            std::cout << std::endl;
+                    }
+                } else if (type < 101) {
+                    // get next field as double
+                    double value = CoinReadGetDoubleField(argc, argv, &valid);
+                    if (!valid) {
+                        if (type < 51) {
+                            int returnCode;
+                            const char * message =
+                                parameters_[iParam].setDoubleParameterWithMessage(lpSolver, value, returnCode);
+                            if (!noPrinting_ && strlen(message)) {
+                                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                << message
+                                << CoinMessageEol;
+                            }
+                        } else if (type < 81) {
+                            int returnCode;
+                            const char * message =
+                                parameters_[iParam].setDoubleParameterWithMessage(model_, value, returnCode);
+                            if (!noPrinting_ && strlen(message)) {
+                                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                << message
+                                << CoinMessageEol;
+                            }
+                        } else {
+                            int returnCode;
+                            const char * message =
+                                parameters_[iParam].setDoubleParameterWithMessage(lpSolver, value, returnCode);
+                            if (!noPrinting_ && strlen(message)) {
+                                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                << message
+                                << CoinMessageEol;
+                            }
+                            switch (type) {
+                            case CBC_PARAM_DBL_DJFIX:
+                                djFix = value;
+#ifndef CBC_OTHER_SOLVER
+                                if (goodModel && djFix < 1.0e20) {
+                                    // do some fixing
+                                    clpSolver = dynamic_cast< OsiClpSolverInterface*> (model_.solver());
+                                    clpSolver->initialSolve();
+                                    lpSolver = clpSolver->getModelPtr();
+                                    int numberColumns = lpSolver->numberColumns();
+                                    int i;
+                                    const char * type = lpSolver->integerInformation();
+                                    double * lower = lpSolver->columnLower();
+                                    double * upper = lpSolver->columnUpper();
+                                    double * solution = lpSolver->primalColumnSolution();
+                                    double * dj = lpSolver->dualColumnSolution();
+                                    int numberFixed = 0;
+                                    double dextra4 = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA4, numberParameters_, parameters_)].doubleValue();
+                                    if (dextra4)
+                                        printf("Multiple for continuous dj fixing is %g\n", dextra4);
+                                    for (i = 0; i < numberColumns; i++) {
+                                        double djValue = dj[i];
+                                        if (!type[i])
+                                            djValue *= dextra4;
+                                        if (type[i] || dextra4) {
+                                            double value = solution[i];
+                                            if (value < lower[i] + 1.0e-5 && djValue > djFix) {
+                                                solution[i] = lower[i];
+                                                upper[i] = lower[i];
+                                                numberFixed++;
+                                            } else if (value > upper[i] - 1.0e-5 && djValue < -djFix) {
+                                                solution[i] = upper[i];
+                                                lower[i] = upper[i];
+                                                numberFixed++;
+                                            }
+                                        }
+                                    }
+                                    sprintf(generalPrint, "%d columns fixed\n", numberFixed);
+                                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                    << generalPrint
+                                    << CoinMessageEol;
+                                }
+#endif
+                                break;
+                            case CBC_PARAM_DBL_TIGHTENFACTOR:
+                                tightenFactor = value;
+                                if (!complicatedInteger)
+                                    defaultSettings = false; // user knows what she is doing
+                                break;
+                            default:
+                                break;
+                            }
+                        }
+                    } else if (valid == 1) {
+                        std::cout << " is illegal for double parameter " << parameters_[iParam].name() << " value remains " <<
+                                  parameters_[iParam].doubleValue() << std::endl;
+                    } else {
+                        std::cout << parameters_[iParam].name() << " has value " <<
+                                  parameters_[iParam].doubleValue() << std::endl;
+                    }
+                } else if (type < 201) {
+                    // get next field as int
+                    int value = CoinReadGetIntField(argc, argv, &valid);
+                    if (!valid) {
+                        if (type < 151) {
+                            if (parameters_[iParam].type() == CLP_PARAM_INT_PRESOLVEPASS)
+                                preSolve = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_IDIOT)
+                                doIdiot = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_SPRINT)
+                                doSprint = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_OUTPUTFORMAT)
+                                outputFormat = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_SLPVALUE)
+                                slpValue = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_CPP)
+                                cppValue = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_PRESOLVEOPTIONS)
+                                presolveOptions = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_PRINTOPTIONS)
+                                printOptions = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_SUBSTITUTION)
+                                substitution = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_DUALIZE)
+                                dualize = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_PROCESSTUNE)
+                                tunePreProcess = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_USESOLUTION)
+                                useSolution = value;
+                            else if (parameters_[iParam].type() == CLP_PARAM_INT_VERBOSE)
+                                verbose = value;
+                            int returnCode;
+                            const char * message =
+                                parameters_[iParam].setIntParameterWithMessage(lpSolver, value, returnCode);
+                            if (!noPrinting_ && strlen(message)) {
+                                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                << message
+                                << CoinMessageEol;
+                            }
+                        } else {
+                            if (parameters_[iParam].type() == CBC_PARAM_INT_CUTPASS)
+                                cutPass = value;
+                            else if (parameters_[iParam].type() == CBC_PARAM_INT_CUTPASSINTREE)
+                                cutPassInTree = value;
+                            else if (parameters_[iParam].type() == CBC_PARAM_INT_STRONGBRANCHING ||
+                                     parameters_[iParam].type() == CBC_PARAM_INT_NUMBERBEFORE)
+                                strongChanged = true;
+                            else if (parameters_[iParam].type() == CBC_PARAM_INT_FPUMPTUNE ||
+                                     parameters_[iParam].type() == CBC_PARAM_INT_FPUMPTUNE2 ||
+                                     parameters_[iParam].type() == CBC_PARAM_INT_FPUMPITS)
+                                pumpChanged = true;
+                            else if (parameters_[iParam].type() == CBC_PARAM_INT_EXPERIMENT) {
+  			        int addFlags=0;
+				if (value>=10) {
+				  addFlags = 1048576*(value/10);
+				  value = value % 10;
+				  parameters[whichParam(CBC_PARAM_INT_EXPERIMENT, numberParameters, parameters)].setIntValue(value);
+				}
+                                if (value >= 1) {
+				    int values[]={24003,280003,792003,24003,24003};
+				    if (value>=2&&value<=3) {
+				      // swap default diving
+				      int iParam = whichParam(CBC_PARAM_STR_DIVINGC, numberParameters_, parameters_);
+				      parameters_[iParam].setCurrentOption("off");
+				      iParam = whichParam(CBC_PARAM_STR_DIVINGP, numberParameters_, parameters_);
+				      parameters_[iParam].setCurrentOption("on");
+				    }
+				    int extra4 = values[value-1]+addFlags;
+                                    parameters[whichParam(CBC_PARAM_INT_EXTRA4, numberParameters, parameters)].setIntValue(extra4);
+                                    if (!noPrinting_) {
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << "switching on global root cuts for gomory and knapsack"
+                                        << CoinMessageEol;
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << "using OSL factorization"
+                                        << CoinMessageEol;
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << "extra options - -rens on -extra4 "
+					<<extra4<<" -passc 1000!"
+                                        << CoinMessageEol;
+                                    }
+                                    parameters[whichParam(CBC_PARAM_STR_PROBINGCUTS, numberParameters, parameters)].setCurrentOption("forceOnStrong");
+                                    probingAction = 8;
+                                    parameters_[whichParam(CBC_PARAM_STR_GOMORYCUTS, numberParameters_, parameters_)].setCurrentOption("onGlobal");
+                                    gomoryAction = 5;
+                                    parameters_[whichParam(CBC_PARAM_STR_KNAPSACKCUTS, numberParameters_, parameters_)].setCurrentOption("onGlobal");
+                                    knapsackAction = 5;
+                                    parameters_[whichParam(CLP_PARAM_STR_FACTORIZATION, numberParameters_, parameters_)].setCurrentOption("osl");
+                                    lpSolver->factorization()->forceOtherFactorization(3);
+                                    parameters_[whichParam(CBC_PARAM_INT_MAXHOTITS, numberParameters_, parameters_)].setIntValue(100);
+                                    parameters[whichParam(CBC_PARAM_INT_CUTPASS, numberParameters, parameters)].setIntValue(1000);
+                                    cutPass = 1000;
+                                    parameters[whichParam(CBC_PARAM_STR_RENS, numberParameters, parameters)].setCurrentOption("on");
+                                }
+                            } else if (parameters_[iParam].type() == CBC_PARAM_INT_STRATEGY) {
+                                if (value == 0) {
+                                    gomoryGen.setAwayAtRoot(0.05);
+                                    int iParam;
+                                    iParam = whichParam(CBC_PARAM_INT_DIVEOPT, numberParameters_, parameters_);
+                                    parameters_[iParam].setIntValue(-1);
+                                    iParam = whichParam(CBC_PARAM_INT_FPUMPITS, numberParameters_, parameters_);
+                                    parameters_[iParam].setIntValue(20);
+                                    iParam = whichParam(CBC_PARAM_INT_FPUMPTUNE, numberParameters_, parameters_);
+                                    parameters_[iParam].setIntValue(1003);
+                                    initialPumpTune = 1003;
+                                    iParam = whichParam(CLP_PARAM_INT_PROCESSTUNE, numberParameters_, parameters_);
+                                    parameters_[iParam].setIntValue(0);
+                                    tunePreProcess = 0;
+                                    iParam = whichParam(CBC_PARAM_STR_DIVINGC, numberParameters_, parameters_);
+                                    parameters_[iParam].setCurrentOption("off");
+                                    iParam = whichParam(CBC_PARAM_STR_RINS, numberParameters_, parameters_);
+                                    parameters_[iParam].setCurrentOption("off");
+                                    iParam = whichParam(CBC_PARAM_STR_PROBINGCUTS, numberParameters_, parameters_);
+				    // but not if cuts off
+                                    int jParam = whichParam(CBC_PARAM_STR_CUTSSTRATEGY, numberParameters_, parameters_);
+				    
+                                    jParam = parameters_[jParam].currentOptionAsInteger();
+				    if (jParam) {
+				      parameters_[iParam].setCurrentOption("on");
+				      probingAction = 1;
+				    } else {
+				      parameters_[iParam].setCurrentOption("off");
+				      probingAction = 0;
+				    }
+                                }
+                            }
+                            int returnCode;
+                            const char * message =
+                                parameters_[iParam].setIntParameterWithMessage(model_, value, returnCode);
+                            if (!noPrinting_ && strlen(message)) {
+                                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                << message
+                                << CoinMessageEol;
+                            }
+                        }
+                    } else if (valid == 1) {
+                        std::cout << " is illegal for integer parameter " << parameters_[iParam].name() << " value remains " <<
+                                  parameters_[iParam].intValue() << std::endl;
+                    } else {
+                        std::cout << parameters_[iParam].name() << " has value " <<
+                                  parameters_[iParam].intValue() << std::endl;
+                    }
+                } else if (type < 301) {
+                    // one of several strings
+                    std::string value = CoinReadGetString(argc, argv);
+                    int action = parameters_[iParam].parameterOption(value);
+                    if (action < 0) {
+                        if (value != "EOL") {
+                            // no match
+                            parameters_[iParam].printOptions();
+                        } else {
+                            // print current value
+                            std::cout << parameters_[iParam].name() << " has value " <<
+                                      parameters_[iParam].currentOption() << std::endl;
+                        }
+                    } else {
+                        const char * message =
+                            parameters_[iParam].setCurrentOptionWithMessage(action);
+                        if (!noPrinting_ && strlen(message)) {
+                            generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                            << message
+                            << CoinMessageEol;
+                        }
+                        // for now hard wired
+                        switch (type) {
+                        case CLP_PARAM_STR_DIRECTION:
+                            if (action == 0)
+                                lpSolver->setOptimizationDirection(1);
+                            else if (action == 1)
+                                lpSolver->setOptimizationDirection(-1);
+                            else
+                                lpSolver->setOptimizationDirection(0);
+                            break;
+                        case CLP_PARAM_STR_DUALPIVOT:
+                            if (action == 0) {
+                                ClpDualRowSteepest steep(3);
+                                lpSolver->setDualRowPivotAlgorithm(steep);
+                            } else if (action == 1) {
+                                ClpDualRowDantzig dantzig;
+                                //ClpDualRowSteepest dantzig(5);
+                                lpSolver->setDualRowPivotAlgorithm(dantzig);
+                            } else if (action == 2) {
+                                // partial steep
+                                ClpDualRowSteepest steep(2);
+                                lpSolver->setDualRowPivotAlgorithm(steep);
+                            } else {
+                                ClpDualRowSteepest steep;
+                                lpSolver->setDualRowPivotAlgorithm(steep);
+                            }
+                            break;
+                        case CLP_PARAM_STR_PRIMALPIVOT:
+                            if (action == 0) {
+                                ClpPrimalColumnSteepest steep(3);
+                                lpSolver->setPrimalColumnPivotAlgorithm(steep);
+                            } else if (action == 1) {
+                                ClpPrimalColumnSteepest steep(0);
+                                lpSolver->setPrimalColumnPivotAlgorithm(steep);
+                            } else if (action == 2) {
+                                ClpPrimalColumnDantzig dantzig;
+                                lpSolver->setPrimalColumnPivotAlgorithm(dantzig);
+                            } else if (action == 3) {
+                                ClpPrimalColumnSteepest steep(4);
+                                lpSolver->setPrimalColumnPivotAlgorithm(steep);
+                            } else if (action == 4) {
+                                ClpPrimalColumnSteepest steep(1);
+                                lpSolver->setPrimalColumnPivotAlgorithm(steep);
+                            } else if (action == 5) {
+                                ClpPrimalColumnSteepest steep(2);
+                                lpSolver->setPrimalColumnPivotAlgorithm(steep);
+                            } else if (action == 6) {
+                                ClpPrimalColumnSteepest steep(10);
+                                lpSolver->setPrimalColumnPivotAlgorithm(steep);
+                            }
+                            break;
+                        case CLP_PARAM_STR_SCALING:
+                            lpSolver->scaling(action);
+                            solver->setHintParam(OsiDoScale, action != 0, OsiHintTry);
+                            doScaling = action;
+                            break;
+                        case CLP_PARAM_STR_AUTOSCALE:
+                            lpSolver->setAutomaticScaling(action != 0);
+                            break;
+                        case CLP_PARAM_STR_SPARSEFACTOR:
+                            lpSolver->setSparseFactorization((1 - action) != 0);
+                            break;
+                        case CLP_PARAM_STR_BIASLU:
+                            lpSolver->factorization()->setBiasLU(action);
+                            break;
+                        case CLP_PARAM_STR_PERTURBATION:
+                            if (action == 0)
+                                lpSolver->setPerturbation(50);
+                            else
+                                lpSolver->setPerturbation(100);
+                            break;
+                        case CLP_PARAM_STR_ERRORSALLOWED:
+                            allowImportErrors = action;
+                            break;
+                        case CLP_PARAM_STR_INTPRINT:
+                            printMode = action;
+                            break;
+                            //case CLP_PARAM_NOTUSED_ALGORITHM:
+                            //algorithm  = action;
+                            //defaultSettings=false; // user knows what she is doing
+                            //abort();
+                            //break;
+                        case CLP_PARAM_STR_KEEPNAMES:
+                            keepImportNames = 1 - action;
+                            break;
+                        case CLP_PARAM_STR_PRESOLVE:
+                            if (action == 0)
+                                preSolve = 5;
+                            else if (action == 1)
+                                preSolve = 0;
+                            else if (action == 2)
+                                preSolve = 10;
+                            else
+                                preSolveFile = true;
+                            break;
+                        case CLP_PARAM_STR_PFI:
+                            lpSolver->factorization()->setForrestTomlin(action == 0);
+                            break;
+                        case CLP_PARAM_STR_FACTORIZATION:
+                            lpSolver->factorization()->forceOtherFactorization(action);
+                            break;
+                        case CLP_PARAM_STR_CRASH:
+                            doCrash = action;
+                            break;
+                        case CLP_PARAM_STR_VECTOR:
+                            doVector = action;
+                            break;
+                        case CLP_PARAM_STR_MESSAGES:
+                            lpSolver->messageHandler()->setPrefix(action != 0);
+                            break;
+                        case CLP_PARAM_STR_CHOLESKY:
+                            choleskyType = action;
+                            break;
+                        case CLP_PARAM_STR_GAMMA:
+                            gamma = action;
+                            break;
+                        case CLP_PARAM_STR_BARRIERSCALE:
+                            scaleBarrier = action;
+                            break;
+                        case CLP_PARAM_STR_KKT:
+                            doKKT = action;
+                            break;
+                        case CLP_PARAM_STR_CROSSOVER:
+                            crossover = action;
+                            break;
+                        case CLP_PARAM_STR_TIME_MODE:
+			    model_.setUseElapsedTime(action!=0);
+                            break;
+                        case CBC_PARAM_STR_SOS:
+                            doSOS = action;
+                            break;
+                        case CBC_PARAM_STR_GOMORYCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            gomoryAction = action;
+                            break;
+                        case CBC_PARAM_STR_PROBINGCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            probingAction = action;
+                            break;
+                        case CBC_PARAM_STR_KNAPSACKCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            knapsackAction = action;
+                            break;
+                        case CBC_PARAM_STR_REDSPLITCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            redsplitAction = action;
+                            break;
+                        case CBC_PARAM_STR_REDSPLIT2CUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            redsplit2Action = action;
+                            break;
+                        case CBC_PARAM_STR_GMICUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            GMIAction = action;
+                            break;
+                        case CBC_PARAM_STR_CLIQUECUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            cliqueAction = action;
+                            break;
+                        case CBC_PARAM_STR_FLOWCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            flowAction = action;
+                            break;
+                        case CBC_PARAM_STR_MIXEDCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            mixedAction = action;
+                            break;
+                        case CBC_PARAM_STR_TWOMIRCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            twomirAction = action;
+                            break;
+                        case CBC_PARAM_STR_LANDPCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            landpAction = action;
+                            break;
+                        case CBC_PARAM_STR_RESIDCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            residualCapacityAction = action;
+                            break;
+                        case CBC_PARAM_STR_ZEROHALFCUTS:
+                            defaultSettings = false; // user knows what she is doing
+                            zerohalfAction = action;
+                            break;
+                        case CBC_PARAM_STR_ROUNDING:
+                            defaultSettings = false; // user knows what she is doing
+                            break;
+                        case CBC_PARAM_STR_FPUMP:
+                            defaultSettings = false; // user knows what she is doing
+                            break;
+                        case CBC_PARAM_STR_RINS:
+                            break;
+                        case CBC_PARAM_STR_DINS:
+                            break;
+                        case CBC_PARAM_STR_RENS:
+                            break;
+                        case CBC_PARAM_STR_CUTSSTRATEGY:
+                            gomoryAction = action;
+                            probingAction = action;
+                            knapsackAction = action;
+                            zerohalfAction = action;
+                            cliqueAction = action;
+                            flowAction = action;
+                            mixedAction = action;
+                            twomirAction = action;
+                            //landpAction = action;
+                            parameters_[whichParam(CBC_PARAM_STR_GOMORYCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_PROBINGCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_KNAPSACKCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_CLIQUECUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_FLOWCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_MIXEDCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_TWOMIRCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_ZEROHALFCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            if (!action) {
+                                redsplitAction = action;
+                                parameters_[whichParam(CBC_PARAM_STR_REDSPLITCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                                redsplit2Action = action;
+                                parameters_[whichParam(CBC_PARAM_STR_REDSPLIT2CUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                                GMIAction = action;
+                                parameters_[whichParam(CBC_PARAM_STR_GMICUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                                landpAction = action;
+                                parameters_[whichParam(CBC_PARAM_STR_LANDPCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                                residualCapacityAction = action;
+                                parameters_[whichParam(CBC_PARAM_STR_RESIDCUTS, numberParameters_, parameters_)].setCurrentOption(action);
+                            }
+                            break;
+                        case CBC_PARAM_STR_HEURISTICSTRATEGY:
+                            parameters_[whichParam(CBC_PARAM_STR_ROUNDING, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_GREEDY, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_COMBINE, numberParameters_, parameters_)].setCurrentOption(action);
+                            //parameters_[whichParam(CBC_PARAM_STR_LOCALTREE,numberParameters_,parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_FPUMP, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_DIVINGC, numberParameters_, parameters_)].setCurrentOption(action);
+                            parameters_[whichParam(CBC_PARAM_STR_RINS, numberParameters_, parameters_)].setCurrentOption(action);
+                            break;
+                        case CBC_PARAM_STR_GREEDY:
+                        case CBC_PARAM_STR_DIVINGS:
+                        case CBC_PARAM_STR_DIVINGC:
+                        case CBC_PARAM_STR_DIVINGF:
+                        case CBC_PARAM_STR_DIVINGG:
+                        case CBC_PARAM_STR_DIVINGL:
+                        case CBC_PARAM_STR_DIVINGP:
+                        case CBC_PARAM_STR_DIVINGV:
+                        case CBC_PARAM_STR_COMBINE:
+                        case CBC_PARAM_STR_PIVOTANDCOMPLEMENT:
+                        case CBC_PARAM_STR_PIVOTANDFIX:
+                        case CBC_PARAM_STR_RANDROUND:
+                        case CBC_PARAM_STR_LOCALTREE:
+                        case CBC_PARAM_STR_NAIVE:
+                        case CBC_PARAM_STR_CPX:
+                            defaultSettings = false; // user knows what she is doing
+                            break;
+                        case CBC_PARAM_STR_COSTSTRATEGY:
+                            useCosts = action;
+                            break;
+                        case CBC_PARAM_STR_NODESTRATEGY:
+                            nodeStrategy = action;
+                            break;
+                        case CBC_PARAM_STR_PREPROCESS:
+                            preProcess = action;
+                            break;
+                        default:
+                            //abort();
+                            break;
+                        }
+                    }
+                } else {
+                    // action
+                    if (type == CLP_PARAM_ACTION_EXIT) {
+#ifdef COIN_HAS_ASL
+                        if (statusUserFunction_[0]) {
+                            if (info.numberIntegers || info.numberBinary) {
+                                // integer
+                            } else {
+                                // linear
+                            }
+                            writeAmpl(&info);
+                            freeArrays2(&info);
+                            freeArgs(&info);
+                        }
+#endif
+                        break; // stop all
+                    }
+                    switch (type) {
+                    case CLP_PARAM_ACTION_DUALSIMPLEX:
+                    case CLP_PARAM_ACTION_PRIMALSIMPLEX:
+                    case CLP_PARAM_ACTION_SOLVECONTINUOUS:
+                    case CLP_PARAM_ACTION_BARRIER:
+                        if (goodModel) {
+                            // Say not in integer
+                            integerStatus = -1;
+                            double objScale =
+                                parameters_[whichParam(CLP_PARAM_DBL_OBJSCALE2, numberParameters_, parameters_)].doubleValue();
+                            if (objScale != 1.0) {
+                                int iColumn;
+                                int numberColumns = lpSolver->numberColumns();
+                                double * dualColumnSolution =
+                                    lpSolver->dualColumnSolution();
+                                ClpObjective * obj = lpSolver->objectiveAsObject();
+                                assert(dynamic_cast<ClpLinearObjective *> (obj));
+                                double offset;
+                                double * objective = obj->gradient(NULL, NULL, offset, true);
+                                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                    dualColumnSolution[iColumn] *= objScale;
+                                    objective[iColumn] *= objScale;;
+                                }
+                                int iRow;
+                                int numberRows = lpSolver->numberRows();
+                                double * dualRowSolution =
+                                    lpSolver->dualRowSolution();
+                                for (iRow = 0; iRow < numberRows; iRow++)
+                                    dualRowSolution[iRow] *= objScale;
+                                lpSolver->setObjectiveOffset(objScale*lpSolver->objectiveOffset());
+                            }
+                            ClpSolve::SolveType method;
+                            ClpSolve::PresolveType presolveType;
+                            ClpSimplex * model2 = lpSolver;
+                            if (dualize) {
+                                bool tryIt = true;
+                                double fractionColumn = 1.0;
+                                double fractionRow = 1.0;
+                                if (dualize == 3) {
+                                    dualize = 1;
+                                    int numberColumns = lpSolver->numberColumns();
+                                    int numberRows = lpSolver->numberRows();
+                                    if (numberRows < 50000 || 5*numberColumns > numberRows) {
+                                        tryIt = false;
+                                    } else {
+                                        fractionColumn = 0.1;
+                                        fractionRow = 0.1;
+                                    }
+                                }
+                                if (tryIt) {
+                                    model2 = static_cast<ClpSimplexOther *> (model2)->dualOfModel(fractionRow, fractionColumn);
+                                    if (model2) {
+                                        sprintf(generalPrint, "Dual of model has %d rows and %d columns",
+                                                model2->numberRows(), model2->numberColumns());
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << generalPrint
+                                        << CoinMessageEol;
+                                        model2->setOptimizationDirection(1.0);
+                                    } else {
+                                        model2 = lpSolver;
+                                        dualize = 0;
+                                    }
+                                } else {
+                                    dualize = 0;
+                                }
+                            }
+                            if (noPrinting_)
+                                lpSolver->setLogLevel(0);
+                            ClpSolve solveOptions;
+                            solveOptions.setPresolveActions(presolveOptions);
+                            solveOptions.setSubstitution(substitution);
+                            if (preSolve != 5 && preSolve) {
+                                presolveType = ClpSolve::presolveNumber;
+                                if (preSolve < 0) {
+                                    preSolve = - preSolve;
+                                    if (preSolve <= 100) {
+                                        presolveType = ClpSolve::presolveNumber;
+                                        sprintf(generalPrint, "Doing %d presolve passes - picking up non-costed slacks",
+                                                preSolve);
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << generalPrint
+                                        << CoinMessageEol;
+                                        solveOptions.setDoSingletonColumn(true);
+                                    } else {
+                                        preSolve -= 100;
+                                        presolveType = ClpSolve::presolveNumberCost;
+                                        sprintf(generalPrint, "Doing %d presolve passes - picking up costed slacks",
+                                                preSolve);
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << generalPrint
+                                        << CoinMessageEol;
+                                    }
+                                }
+                            } else if (preSolve) {
+                                presolveType = ClpSolve::presolveOn;
+                            } else {
+                                presolveType = ClpSolve::presolveOff;
+                            }
+                            solveOptions.setPresolveType(presolveType, preSolve);
+                            if (type == CLP_PARAM_ACTION_DUALSIMPLEX ||
+                                    type == CLP_PARAM_ACTION_SOLVECONTINUOUS) {
+                                method = ClpSolve::useDual;
+                            } else if (type == CLP_PARAM_ACTION_PRIMALSIMPLEX) {
+                                method = ClpSolve::usePrimalorSprint;
+                            } else {
+                                method = ClpSolve::useBarrier;
+                                if (crossover == 1) {
+                                    method = ClpSolve::useBarrierNoCross;
+                                } else if (crossover == 2) {
+                                    ClpObjective * obj = lpSolver->objectiveAsObject();
+                                    if (obj->type() > 1) {
+                                        method = ClpSolve::useBarrierNoCross;
+                                        presolveType = ClpSolve::presolveOff;
+                                        solveOptions.setPresolveType(presolveType, preSolve);
+                                    }
+                                }
+                            }
+                            solveOptions.setSolveType(method);
+                            if (preSolveFile)
+                                presolveOptions |= 0x40000000;
+                            solveOptions.setSpecialOption(4, presolveOptions);
+                            solveOptions.setSpecialOption(5, printOptions);
+                            if (doVector) {
+                                ClpMatrixBase * matrix = lpSolver->clpMatrix();
+                                if (dynamic_cast< ClpPackedMatrix*>(matrix)) {
+                                    ClpPackedMatrix * clpMatrix = dynamic_cast< ClpPackedMatrix*>(matrix);
+                                    clpMatrix->makeSpecialColumnCopy();
+                                }
+                            }
+                            if (method == ClpSolve::useDual) {
+                                // dual
+                                if (doCrash)
+                                    solveOptions.setSpecialOption(0, 1, doCrash); // crash
+                                else if (doIdiot)
+                                    solveOptions.setSpecialOption(0, 2, doIdiot); // possible idiot
+                            } else if (method == ClpSolve::usePrimalorSprint) {
+                                // primal
+                                // if slp turn everything off
+                                if (slpValue > 0) {
+                                    doCrash = false;
+                                    doSprint = 0;
+                                    doIdiot = -1;
+                                    solveOptions.setSpecialOption(1, 10, slpValue); // slp
+                                    method = ClpSolve::usePrimal;
+                                }
+                                if (doCrash) {
+                                    solveOptions.setSpecialOption(1, 1, doCrash); // crash
+                                } else if (doSprint > 0) {
+                                    // sprint overrides idiot
+                                    solveOptions.setSpecialOption(1, 3, doSprint); // sprint
+                                } else if (doIdiot > 0) {
+                                    solveOptions.setSpecialOption(1, 2, doIdiot); // idiot
+                                } else if (slpValue <= 0) {
+                                    if (doIdiot == 0) {
+                                        if (doSprint == 0)
+                                            solveOptions.setSpecialOption(1, 4); // all slack
+                                        else
+                                            solveOptions.setSpecialOption(1, 9); // all slack or sprint
+                                    } else {
+                                        if (doSprint == 0)
+                                            solveOptions.setSpecialOption(1, 8); // all slack or idiot
+                                        else
+                                            solveOptions.setSpecialOption(1, 7); // initiative
+                                    }
+                                }
+                                if (basisHasValues == -1)
+                                    solveOptions.setSpecialOption(1, 11); // switch off values
+                            } else if (method == ClpSolve::useBarrier || method == ClpSolve::useBarrierNoCross) {
+                                int barrierOptions = choleskyType;
+                                if (scaleBarrier)
+                                    barrierOptions |= 8;
+                                if (doKKT)
+                                    barrierOptions |= 16;
+                                if (gamma)
+                                    barrierOptions |= 32 * gamma;
+                                if (crossover == 3)
+                                    barrierOptions |= 256; // try presolve in crossover
+                                solveOptions.setSpecialOption(4, barrierOptions);
+                            }
+                            model2->setMaximumSeconds(model_.getMaximumSeconds());
+#ifdef COIN_HAS_LINK
+                            OsiSolverInterface * coinSolver = model_.solver();
+                            OsiSolverLink * linkSolver = dynamic_cast< OsiSolverLink*> (coinSolver);
+                            if (!linkSolver) {
+                                model2->initialSolve(solveOptions);
+                            } else {
+                                // special solver
+                                int testOsiOptions = parameters_[whichParam(CBC_PARAM_INT_TESTOSI, numberParameters_, parameters_)].intValue();
+                                double * solution = NULL;
+                                if (testOsiOptions < 10) {
+                                    solution = linkSolver->nonlinearSLP(slpValue > 0 ? slpValue : 20 , 1.0e-5);
+                                } else if (testOsiOptions >= 10) {
+                                    CoinModel coinModel = *linkSolver->coinModel();
+                                    ClpSimplex * tempModel = approximateSolution(coinModel, slpValue > 0 ? slpValue : 50 , 1.0e-5, 0);
+                                    assert (tempModel);
+                                    solution = CoinCopyOfArray(tempModel->primalColumnSolution(), coinModel.numberColumns());
+                                    model2->setObjectiveValue(tempModel->objectiveValue());
+                                    model2->setProblemStatus(tempModel->problemStatus());
+                                    model2->setSecondaryStatus(tempModel->secondaryStatus());
+                                    delete tempModel;
+                                }
+                                if (solution) {
+                                    memcpy(model2->primalColumnSolution(), solution,
+                                           CoinMin(model2->numberColumns(), linkSolver->coinModel()->numberColumns())*sizeof(double));
+                                    delete [] solution;
+                                } else {
+                                    printf("No nonlinear solution\n");
+                                }
+                            }
+#else
+                            model2->initialSolve(solveOptions);
+#endif
+                            {
+                                // map states
+                                /* clp status
+                                   -1 - unknown e.g. before solve or if postSolve says not optimal
+                                   0 - optimal
+                                   1 - primal infeasible
+                                   2 - dual infeasible
+                                   3 - stopped on iterations or time
+                                   4 - stopped due to errors
+                                   5 - stopped by event handler (virtual int ClpEventHandler::event()) */
+                                /* cbc status
+                                   -1 before branchAndBound
+                                   0 finished - check isProvenOptimal or isProvenInfeasible to see if solution found
+                                   (or check value of best solution)
+                                   1 stopped - on maxnodes, maxsols, maxtime
+                                   2 difficulties so run was abandoned
+                                   (5 event user programmed event occurred) */
+                                /* clp secondary status of problem - may get extended
+                                   0 - none
+                                   1 - primal infeasible because dual limit reached OR probably primal
+                                   infeasible but can't prove it (main status 4)
+                                   2 - scaled problem optimal - unscaled problem has primal infeasibilities
+                                   3 - scaled problem optimal - unscaled problem has dual infeasibilities
+                                   4 - scaled problem optimal - unscaled problem has primal and dual infeasibilities
+                                   5 - giving up in primal with flagged variables
+                                   6 - failed due to empty problem check
+                                   7 - postSolve says not optimal
+                                   8 - failed due to bad element check
+                                   9 - status was 3 and stopped on time
+                                   100 up - translation of enum from ClpEventHandler
+                                */
+                                /* cbc secondary status of problem
+                                   -1 unset (status_ will also be -1)
+                                   0 search completed with solution
+                                   1 linear relaxation not feasible (or worse than cutoff)
+                                   2 stopped on gap
+                                   3 stopped on nodes
+                                   4 stopped on time
+                                   5 stopped on user event
+                                   6 stopped on solutions
+                                   7 linear relaxation unbounded
+                                   8 stopped on iterations limit
+                                */
+                                int iStatus = model2->status();
+                                int iStatus2 = model2->secondaryStatus();
+                                if (iStatus == 0) {
+                                    iStatus2 = 0;
+                                    if (found.type() == CBC_PARAM_ACTION_BAB) {
+                                        // set best solution in model as no integers
+                                        model_.setBestSolution(model2->primalColumnSolution(),
+                                                               model2->numberColumns(),
+                                                               model2->getObjValue()*
+                                                               model2->getObjSense());
+                                    }
+                                } else if (iStatus == 1) {
+                                    iStatus = 0;
+                                    iStatus2 = 1; // say infeasible
+                                } else if (iStatus == 2) {
+                                    iStatus = 0;
+                                    iStatus2 = 7; // say unbounded
+                                } else if (iStatus == 3) {
+                                    iStatus = 1;
+                                    if (iStatus2 == 9)  // what does 9 mean ?????????????
+                                        iStatus2 = 4;
+                                    else
+                                        iStatus2 = 3; // Use nodes - as closer than solutions
+                                } else if (iStatus == 4) {
+                                    iStatus = 2; // difficulties
+                                    iStatus2 = 0;
+                                }
+                                model_.setProblemStatus(iStatus);
+                                model_.setSecondaryStatus(iStatus2);
+				if ((iStatus == 2 || iStatus2 > 0) &&
+				    !noPrinting_) {
+				   std::string statusName[] = {"", "Stopped on ", "Run abandoned", "", "", "User ctrl-c"};
+				   std::string minor[] = {"Optimal solution found", "Linear relaxation infeasible", "Optimal solution found (within gap tolerance)", "node limit", "time limit", "user ctrl-c", "solution limit", "Linear relaxation unbounded", "iterations limit", "Problem proven infeasible"};
+				   sprintf(generalPrint, "\nResult - %s%s\n\n", 
+					   statusName[iStatus].c_str(), 
+					   minor[iStatus2].c_str());
+				   sprintf(generalPrint + strlen(generalPrint),
+					   "Enumerated nodes:           0\n");
+				   sprintf(generalPrint + strlen(generalPrint), 
+					   "Total iterations:           0\n");
+#if CBC_QUIET == 0
+				   sprintf(generalPrint + strlen(generalPrint),
+					   "Time (CPU seconds):         %.2f\n", 
+					   CoinCpuTime() - time0);
+				   sprintf(generalPrint + strlen(generalPrint),
+					   "Time (Wallclock Seconds):   %.2f\n", 
+					   CoinGetTimeOfDay()-time0Elapsed);
+#endif
+				   generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				      << generalPrint
+				      << CoinMessageEol;
+				}
+				//assert (lpSolver==clpSolver->getModelPtr());
+                                assert (clpSolver == model_.solver());
+                                clpSolver->setWarmStart(NULL);
+                                // and in babModel if exists
+                                if (babModel_) {
+                                    babModel_->setProblemStatus(iStatus);
+                                    babModel_->setSecondaryStatus(iStatus2);
+                                }
+                                int returnCode = callBack(&model, 1);
+                                if (returnCode) {
+                                    // exit if user wants
+                                    delete babModel_;
+                                    babModel_ = NULL;
+                                    return returnCode;
+                                }
+                            }
+                            basisHasValues = 1;
+                            if (dualize) {
+                                int returnCode = static_cast<ClpSimplexOther *> (lpSolver)->restoreFromDual(model2);
+                                if (model2->status() == 3)
+                                    returnCode = 0;
+                                delete model2;
+                                if (returnCode && dualize != 2)
+                                    lpSolver->primal(1);
+                                model2 = lpSolver;
+                            }
+#ifdef COIN_HAS_ASL
+                            if (statusUserFunction_[0]) {
+                                double value = model2->getObjValue() * model2->getObjSense();
+                                char buf[300];
+                                int pos = 0;
+                                int iStat = model2->status();
+                                if (iStat == 0) {
+                                    pos += sprintf(buf + pos, "optimal," );
+                                } else if (iStat == 1) {
+                                    // infeasible
+                                    pos += sprintf(buf + pos, "infeasible,");
+                                } else if (iStat == 2) {
+                                    // unbounded
+                                    pos += sprintf(buf + pos, "unbounded,");
+                                } else if (iStat == 3) {
+                                    pos += sprintf(buf + pos, "stopped on iterations or time,");
+                                } else if (iStat == 4) {
+                                    iStat = 7;
+                                    pos += sprintf(buf + pos, "stopped on difficulties,");
+                                } else if (iStat == 5) {
+                                    iStat = 3;
+                                    pos += sprintf(buf + pos, "stopped on ctrl-c,");
+                                } else if (iStat == 6) {
+                                    // bab infeasible
+                                    pos += sprintf(buf + pos, "integer infeasible,");
+                                    iStat = 1;
+                                } else {
+                                    pos += sprintf(buf + pos, "status unknown,");
+                                    iStat = 6;
+                                }
+                                info.problemStatus = iStat;
+                                info.objValue = value;
+                                pos += sprintf(buf + pos, " objective %.*g", ampl_obj_prec(),
+                                               value);
+                                sprintf(buf + pos, "\n%d iterations",
+                                        model2->getIterationCount());
+                                free(info.primalSolution);
+                                int numberColumns = model2->numberColumns();
+                                info.primalSolution = reinterpret_cast<double *> (malloc(numberColumns * sizeof(double)));
+                                CoinCopyN(model2->primalColumnSolution(), numberColumns, info.primalSolution);
+                                int numberRows = model2->numberRows();
+                                free(info.dualSolution);
+                                info.dualSolution = reinterpret_cast<double *> (malloc(numberRows * sizeof(double)));
+                                CoinCopyN(model2->dualRowSolution(), numberRows, info.dualSolution);
+                                CoinWarmStartBasis * basis = model2->getBasis();
+                                free(info.rowStatus);
+                                info.rowStatus = reinterpret_cast<int *> (malloc(numberRows * sizeof(int)));
+                                free(info.columnStatus);
+                                info.columnStatus = reinterpret_cast<int *> (malloc(numberColumns * sizeof(int)));
+                                // Put basis in
+                                int i;
+                                // free,basic,ub,lb are 0,1,2,3
+                                for (i = 0; i < numberRows; i++) {
+                                    CoinWarmStartBasis::Status status = basis->getArtifStatus(i);
+                                    info.rowStatus[i] = status;
+                                }
+                                for (i = 0; i < numberColumns; i++) {
+                                    CoinWarmStartBasis::Status status = basis->getStructStatus(i);
+                                    info.columnStatus[i] = status;
+                                }
+                                // put buffer into info
+                                strcpy(info.buffer, buf);
+                                delete basis;
+                            }
+#endif
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_STATISTICS:
+                        if (goodModel) {
+                            // If presolve on look at presolved
+                            bool deleteModel2 = false;
+                            ClpSimplex * model2 = lpSolver;
+                            if (preSolve) {
+                                ClpPresolve pinfo;
+                                int presolveOptions2 = presolveOptions&~0x40000000;
+                                if ((presolveOptions2&0xffff) != 0)
+                                    pinfo.setPresolveActions(presolveOptions2);
+                                pinfo.setSubstitution(substitution);
+                                if ((printOptions&1) != 0)
+                                    pinfo.statistics();
+                                double presolveTolerance =
+                                    parameters_[whichParam(CLP_PARAM_DBL_PRESOLVETOLERANCE, numberParameters_, parameters_)].doubleValue();
+                                model2 =
+                                    pinfo.presolvedModel(*lpSolver, presolveTolerance,
+                                                         true, preSolve);
+                                if (model2) {
+                                    printf("Statistics for presolved model\n");
+                                    deleteModel2 = true;
+                                } else {
+                                    printf("Presolved model looks infeasible - will use unpresolved\n");
+                                    model2 = lpSolver;
+                                }
+                            } else {
+                                printf("Statistics for unpresolved model\n");
+                                model2 =  lpSolver;
+                            }
+                            statistics(lpSolver, model2);
+                            if (deleteModel2)
+                                delete model2;
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_TIGHTEN:
+                        if (goodModel) {
+                            int numberInfeasibilities = lpSolver->tightenPrimalBounds();
+                            if (numberInfeasibilities)
+                                std::cout << "** Analysis indicates model infeasible" << std::endl;
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_PLUSMINUS:
+                        if (goodModel) {
+                            ClpMatrixBase * saveMatrix = lpSolver->clpMatrix();
+                            ClpPackedMatrix* clpMatrix =
+                                dynamic_cast< ClpPackedMatrix*>(saveMatrix);
+                            if (clpMatrix) {
+                                ClpPlusMinusOneMatrix * newMatrix = new ClpPlusMinusOneMatrix(*(clpMatrix->matrix()));
+                                if (newMatrix->getIndices()) {
+                                    lpSolver->replaceMatrix(newMatrix);
+                                    delete saveMatrix;
+                                    std::cout << "Matrix converted to +- one matrix" << std::endl;
+                                } else {
+                                    std::cout << "Matrix can not be converted to +- 1 matrix" << std::endl;
+                                }
+                            } else {
+                                std::cout << "Matrix not a ClpPackedMatrix" << std::endl;
+                            }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_OUTDUPROWS:
+                        dominatedCuts = true;
+#ifdef JJF_ZERO
+                        if (goodModel) {
+                            int numberRows = clpSolver->getNumRows();
+                            //int nOut = outDupRow(clpSolver);
+                            CglDuplicateRow dupcuts(clpSolver);
+                            storedCuts = dupcuts.outDuplicates(clpSolver) != 0;
+                            int nOut = numberRows - clpSolver->getNumRows();
+                            if (nOut && !noPrinting_)
+                                sprintf(generalPrint, "%d rows eliminated", nOut);
+                            generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                            << generalPrint
+                            << CoinMessageEol;
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+#endif
+                        break;
+                    case CLP_PARAM_ACTION_NETWORK:
+                        if (goodModel) {
+                            ClpMatrixBase * saveMatrix = lpSolver->clpMatrix();
+                            ClpPackedMatrix* clpMatrix =
+                                dynamic_cast< ClpPackedMatrix*>(saveMatrix);
+                            if (clpMatrix) {
+                                ClpNetworkMatrix * newMatrix = new ClpNetworkMatrix(*(clpMatrix->matrix()));
+                                if (newMatrix->getIndices()) {
+                                    lpSolver->replaceMatrix(newMatrix);
+                                    delete saveMatrix;
+                                    std::cout << "Matrix converted to network matrix" << std::endl;
+                                } else {
+                                    std::cout << "Matrix can not be converted to network matrix" << std::endl;
+                                }
+                            } else {
+                                std::cout << "Matrix not a ClpPackedMatrix" << std::endl;
+                            }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CBC_PARAM_ACTION_DOHEURISTIC:
+                        if (goodModel) {
+                            int vubAction = parameters_[whichParam(CBC_PARAM_INT_VUBTRY, numberParameters_, parameters_)].intValue();
+                            if (vubAction != -1) {
+                                // look at vubs
+                                // extra1 is number of ints to leave free
+                                // Just ones which affect >= extra3
+                                int extra3 = parameters_[whichParam(CBC_PARAM_INT_EXTRA3, numberParameters_, parameters_)].intValue();
+                                /* 2 is cost above which to fix if feasible
+                                   3 is fraction of integer variables fixed if relaxing (0.97)
+                                   4 is fraction of all variables fixed if relaxing (0.0)
+                                */
+                                double dextra[6];
+                                int extra[5];
+                                extra[1] = parameters_[whichParam(CBC_PARAM_INT_EXTRA1, numberParameters_, parameters_)].intValue();
+                                int exp1 = parameters_[whichParam(CBC_PARAM_INT_EXPERIMENT, numberParameters_,
+                                                                  parameters_)].intValue();
+                                if (exp1 == 4 && extra[1] == -1)
+                                    extra[1] = 999998;
+                                dextra[1] = parameters_[whichParam(CBC_PARAM_DBL_FAKEINCREMENT, numberParameters_, parameters_)].doubleValue();
+                                dextra[2] = parameters_[whichParam(CBC_PARAM_DBL_FAKECUTOFF, numberParameters_, parameters_)].doubleValue();
+                                dextra[3] = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA3, numberParameters_, parameters_)].doubleValue();
+                                dextra[4] = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA4, numberParameters_, parameters_)].doubleValue();
+                                dextra[5] = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA5, numberParameters_, parameters_)].doubleValue();
+                                if (!dextra[3])
+                                    dextra[3] = 0.97;
+                                //OsiClpSolverInterface * newSolver =
+                                fixVubs(model_, extra3, vubAction, generalMessageHandler,
+                                        debugValues, dextra, extra);
+                                //assert (!newSolver);
+                            }
+                            // Actually do heuristics
+                            doHeuristics(&model_, 2, parameters_,
+                                         numberParameters_, noPrinting_, initialPumpTune);
+                            if (model_.bestSolution()) {
+                                model_.setProblemStatus(1);
+                                model_.setSecondaryStatus(6);
+#ifdef COIN_HAS_ASL
+                                if (statusUserFunction_[0]) {
+                                    double value = model_.getObjValue();
+                                    char buf[300];
+                                    int pos = 0;
+                                    pos += sprintf(buf + pos, "feasible,");
+                                    info.problemStatus = 0;
+                                    info.objValue = value;
+                                    pos += sprintf(buf + pos, " objective %.*g", ampl_obj_prec(),
+                                                   value);
+                                    sprintf(buf + pos, "\n0 iterations");
+                                    free(info.primalSolution);
+                                    int numberColumns = lpSolver->numberColumns();
+                                    info.primalSolution = reinterpret_cast<double *> (malloc(numberColumns * sizeof(double)));
+                                    CoinCopyN(model_.bestSolution(), numberColumns, info.primalSolution);
+                                    int numberRows = lpSolver->numberRows();
+                                    free(info.dualSolution);
+                                    info.dualSolution = reinterpret_cast<double *> (malloc(numberRows * sizeof(double)));
+                                    CoinZeroN(info.dualSolution, numberRows);
+                                    CoinWarmStartBasis * basis = lpSolver->getBasis();
+                                    free(info.rowStatus);
+                                    info.rowStatus = reinterpret_cast<int *> (malloc(numberRows * sizeof(int)));
+                                    free(info.columnStatus);
+                                    info.columnStatus = reinterpret_cast<int *> (malloc(numberColumns * sizeof(int)));
+                                    // Put basis in
+                                    int i;
+                                    // free,basic,ub,lb are 0,1,2,3
+                                    for (i = 0; i < numberRows; i++) {
+                                        CoinWarmStartBasis::Status status = basis->getArtifStatus(i);
+                                        info.rowStatus[i] = status;
+                                    }
+                                    for (i = 0; i < numberColumns; i++) {
+                                        CoinWarmStartBasis::Status status = basis->getStructStatus(i);
+                                        info.columnStatus[i] = status;
+                                    }
+                                    // put buffer into info
+                                    strcpy(info.buffer, buf);
+                                    delete basis;
+                                }
+#endif
+                            }
+                            int returnCode = callBack(&model, 6);
+                            if (returnCode) {
+                                // exit if user wants
+                                delete babModel_;
+                                babModel_ = NULL;
+                                return returnCode;
+                            }
+                        }
+                        break;
+                    case CBC_PARAM_ACTION_MIPLIB:
+                        // User can set options - main difference is lack of model and CglPreProcess
+                        goodModel = true;
+                        /*
+                          Run branch-and-cut. First set a few options -- node comparison, scaling.
+                          Print elapsed time at the end.
+                        */
+                    case CBC_PARAM_ACTION_BAB: // branchAndBound
+                        // obsolete case STRENGTHEN:
+                        if (goodModel) {
+                            bool miplib = type == CBC_PARAM_ACTION_MIPLIB;
+                            int logLevel = parameters_[slog].intValue();
+			    int truncateColumns=COIN_INT_MAX;
+			    int * newPriorities=NULL;
+                            // Reduce printout
+                            if (logLevel <= 1) {
+                                model_.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+                            } else {
+                                model_.solver()->setHintParam(OsiDoReducePrint, false, OsiHintTry);
+                            }
+                            {
+                                OsiSolverInterface * solver = model_.solver();
+#ifndef CBC_OTHER_SOLVER
+                                OsiClpSolverInterface * si =
+                                    dynamic_cast<OsiClpSolverInterface *>(solver) ;
+                                assert (si != NULL);
+                                si->getModelPtr()->scaling(doScaling);
+                                ClpSimplex * lpSolver = si->getModelPtr();
+                                if (doVector) {
+                                    ClpMatrixBase * matrix = lpSolver->clpMatrix();
+                                    if (dynamic_cast< ClpPackedMatrix*>(matrix)) {
+                                        ClpPackedMatrix * clpMatrix = dynamic_cast< ClpPackedMatrix*>(matrix);
+                                        clpMatrix->makeSpecialColumnCopy();
+                                    }
+                                }
+#elif CBC_OTHER_SOLVER==1
+                                OsiCpxSolverInterface * si =
+                                    dynamic_cast<OsiCpxSolverInterface *>(solver) ;
+                                assert (si != NULL);
+#endif
+                                statistics_nrows = si->getNumRows();
+                                statistics_ncols = si->getNumCols();
+                                statistics_nprocessedrows = si->getNumRows();
+                                statistics_nprocessedcols = si->getNumCols();
+                                // See if quadratic
+#ifndef CBC_OTHER_SOLVER
+#ifdef COIN_HAS_LINK
+                                if (!complicatedInteger) {
+                                    ClpQuadraticObjective * obj = (dynamic_cast< ClpQuadraticObjective*>(lpSolver->objectiveAsObject()));
+                                    if (obj) {
+                                        preProcess = 0;
+                                        int testOsiOptions = parameters_[whichParam(CBC_PARAM_INT_TESTOSI, numberParameters_, parameters_)].intValue();
+                                        parameters_[whichParam(CBC_PARAM_INT_TESTOSI, numberParameters_, parameters_)].setIntValue(CoinMax(0, testOsiOptions));
+                                        // create coin model
+                                        coinModel = lpSolver->createCoinModel();
+                                        assert (coinModel);
+                                        // load from coin model
+                                        OsiSolverLink solver1;
+                                        OsiSolverInterface * solver2 = solver1.clone();
+                                        model_.assignSolver(solver2, false);
+                                        OsiSolverLink * si =
+                                            dynamic_cast<OsiSolverLink *>(model_.solver()) ;
+                                        assert (si != NULL);
+                                        si->setDefaultMeshSize(0.001);
+                                        // need some relative granularity
+                                        si->setDefaultBound(100.0);
+                                        double dextra3 = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA3, numberParameters_, parameters_)].doubleValue();
+                                        if (dextra3)
+                                            si->setDefaultMeshSize(dextra3);
+                                        si->setDefaultBound(1000.0);
+                                        si->setIntegerPriority(1000);
+                                        si->setBiLinearPriority(10000);
+					biLinearProblem=true;
+                                        si->setSpecialOptions2(2 + 4 + 8);
+                                        CoinModel * model2 = coinModel;
+                                        si->load(*model2, true, parameters_[log].intValue());
+                                        // redo
+                                        solver = model_.solver();
+                                        clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+                                        lpSolver = clpSolver->getModelPtr();
+                                        clpSolver->messageHandler()->setLogLevel(0) ;
+                                        testOsiParameters = 0;
+                                        complicatedInteger = 2;  // allow cuts
+                                        OsiSolverInterface * coinSolver = model_.solver();
+                                        OsiSolverLink * linkSolver = dynamic_cast< OsiSolverLink*> (coinSolver);
+                                        if (linkSolver->quadraticModel()) {
+                                            ClpSimplex * qp = linkSolver->quadraticModel();
+                                            //linkSolver->nonlinearSLP(CoinMax(slpValue,10),1.0e-5);
+                                            qp->nonlinearSLP(CoinMax(slpValue, 40), 1.0e-5);
+                                            qp->primal(1);
+                                            OsiSolverLinearizedQuadratic solver2(qp);
+                                            const double * solution = NULL;
+                                            // Reduce printout
+                                            solver2.setHintParam(OsiDoReducePrint, true, OsiHintTry);
+                                            CbcModel model2(solver2);
+                                            // Now do requested saves and modifications
+                                            CbcModel * cbcModel = & model2;
+                                            OsiSolverInterface * osiModel = model2.solver();
+                                            OsiClpSolverInterface * osiclpModel = dynamic_cast< OsiClpSolverInterface*> (osiModel);
+                                            ClpSimplex * clpModel = osiclpModel->getModelPtr();
+
+                                            // Set changed values
+
+                                            CglProbing probing;
+                                            probing.setMaxProbe(10);
+                                            probing.setMaxLook(10);
+                                            probing.setMaxElements(200);
+                                            probing.setMaxProbeRoot(50);
+                                            probing.setMaxLookRoot(10);
+                                            probing.setRowCuts(3);
+                                            probing.setUsingObjective(true);
+                                            cbcModel->addCutGenerator(&probing, -1, "Probing", true, false, false, -100, -1, -1);
+                                            cbcModel->cutGenerator(0)->setTiming(true);
+
+                                            CglGomory gomory;
+                                            gomory.setLimitAtRoot(512);
+                                            cbcModel->addCutGenerator(&gomory, -98, "Gomory", true, false, false, -100, -1, -1);
+                                            cbcModel->cutGenerator(1)->setTiming(true);
+
+                                            CglKnapsackCover knapsackCover;
+                                            cbcModel->addCutGenerator(&knapsackCover, -98, "KnapsackCover", true, false, false, -100, -1, -1);
+                                            cbcModel->cutGenerator(2)->setTiming(true);
+
+                                            CglRedSplit redSplit;
+                                            cbcModel->addCutGenerator(&redSplit, -99, "RedSplit", true, false, false, -100, -1, -1);
+                                            cbcModel->cutGenerator(3)->setTiming(true);
+
+                                            CglClique clique;
+                                            clique.setStarCliqueReport(false);
+                                            clique.setRowCliqueReport(false);
+                                            clique.setMinViolation(0.1);
+                                            cbcModel->addCutGenerator(&clique, -98, "Clique", true, false, false, -100, -1, -1);
+                                            cbcModel->cutGenerator(4)->setTiming(true);
+
+                                            CglMixedIntegerRounding2 mixedIntegerRounding2;
+                                            cbcModel->addCutGenerator(&mixedIntegerRounding2, -98, "MixedIntegerRounding2", true, false, false, -100, -1, -1);
+                                            cbcModel->cutGenerator(5)->setTiming(true);
+
+                                            CglFlowCover flowCover;
+                                            cbcModel->addCutGenerator(&flowCover, -98, "FlowCover", true, false, false, -100, -1, -1);
+                                            cbcModel->cutGenerator(6)->setTiming(true);
+
+                                            CglTwomir twomir;
+                                            twomir.setMaxElements(250);
+                                            cbcModel->addCutGenerator(&twomir, -99, "Twomir", true, false, false, -100, -1, -1);
+                                            cbcModel->cutGenerator(7)->setTiming(true);
+
+                                            CbcHeuristicFPump heuristicFPump(*cbcModel);
+                                            heuristicFPump.setWhen(13);
+                                            heuristicFPump.setMaximumPasses(20);
+                                            heuristicFPump.setMaximumRetries(7);
+                                            heuristicFPump.setHeuristicName("feasibility pump");
+                                            heuristicFPump.setInitialWeight(1);
+                                            heuristicFPump.setFractionSmall(0.6);
+                                            cbcModel->addHeuristic(&heuristicFPump);
+
+                                            CbcRounding rounding(*cbcModel);
+                                            rounding.setHeuristicName("rounding");
+                                            cbcModel->addHeuristic(&rounding);
+
+                                            CbcHeuristicLocal heuristicLocal(*cbcModel);
+                                            heuristicLocal.setHeuristicName("combine solutions");
+                                            heuristicLocal.setSearchType(1);
+                                            heuristicLocal.setFractionSmall(0.6);
+                                            cbcModel->addHeuristic(&heuristicLocal);
+
+                                            CbcHeuristicGreedyCover heuristicGreedyCover(*cbcModel);
+                                            heuristicGreedyCover.setHeuristicName("greedy cover");
+                                            cbcModel->addHeuristic(&heuristicGreedyCover);
+
+                                            CbcHeuristicGreedyEquality heuristicGreedyEquality(*cbcModel);
+                                            heuristicGreedyEquality.setHeuristicName("greedy equality");
+                                            cbcModel->addHeuristic(&heuristicGreedyEquality);
+
+                                            CbcCompareDefault compare;
+                                            cbcModel->setNodeComparison(compare);
+                                            cbcModel->setNumberBeforeTrust(5);
+                                            cbcModel->setSpecialOptions(2);
+                                            cbcModel->messageHandler()->setLogLevel(1);
+                                            cbcModel->setMaximumCutPassesAtRoot(-100);
+                                            cbcModel->setMaximumCutPasses(1);
+                                            cbcModel->setMinimumDrop(0.05);
+                                            // For branchAndBound this may help
+                                            clpModel->defaultFactorizationFrequency();
+                                            clpModel->setDualBound(1.0001e+08);
+                                            clpModel->setPerturbation(50);
+                                            osiclpModel->setSpecialOptions(193);
+                                            osiclpModel->messageHandler()->setLogLevel(0);
+                                            osiclpModel->setIntParam(OsiMaxNumIterationHotStart, 100);
+                                            osiclpModel->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+                                            // You can save some time by switching off message building
+                                            // clpModel->messagesPointer()->setDetailMessages(100,10000,(int *) NULL);
+
+                                            // Solve
+
+                                            cbcModel->initialSolve();
+                                            if (clpModel->tightenPrimalBounds() != 0) {
+#ifndef DISALLOW_PRINTING
+                                                std::cout << "Problem is infeasible - tightenPrimalBounds!" << std::endl;
+#endif
+                                                break;
+                                            }
+                                            clpModel->dual();  // clean up
+                                            cbcModel->initialSolve();
+#ifdef CBC_THREAD
+                                            int numberThreads = parameters_[whichParam(CBC_PARAM_INT_THREADS, numberParameters_, parameters_)].intValue();
+                                            cbcModel->setNumberThreads(numberThreads % 100);
+                                            cbcModel->setThreadMode(CoinMin(numberThreads / 100, 7));
+#endif
+                                            //setCutAndHeuristicOptions(*cbcModel);
+                                            cbcModel->branchAndBound();
+                                            OsiSolverLinearizedQuadratic * solver3 = dynamic_cast<OsiSolverLinearizedQuadratic *> (model2.solver());
+                                            assert (solver3);
+                                            solution = solver3->bestSolution();
+					    double bestObjectiveValue = solver3->bestObjectiveValue();
+					    linkSolver->setBestObjectiveValue(bestObjectiveValue);
+					    if (solution) {
+					      linkSolver->setBestSolution(solution, solver3->getNumCols());
+					    }
+                                            CbcHeuristicDynamic3 dynamic(model_);
+                                            dynamic.setHeuristicName("dynamic pass thru");
+                                            model_.addHeuristic(&dynamic);
+                                            // if convex
+                                            if ((linkSolver->specialOptions2()&4) != 0 && solution) {
+                                                int numberColumns = coinModel->numberColumns();
+                                                assert (linkSolver->objectiveVariable() == numberColumns);
+                                                // add OA cut
+                                                double offset;
+                                                double * gradient = new double [numberColumns+1];
+                                                memcpy(gradient, qp->objectiveAsObject()->gradient(qp, solution, offset, true, 2),
+                                                       numberColumns*sizeof(double));
+                                                double rhs = 0.0;
+                                                int * column = new int[numberColumns+1];
+                                                int n = 0;
+                                                for (int i = 0; i < numberColumns; i++) {
+                                                    double value = gradient[i];
+                                                    if (fabs(value) > 1.0e-12) {
+                                                        gradient[n] = value;
+                                                        rhs += value * solution[i];
+                                                        column[n++] = i;
+                                                    }
+                                                }
+                                                gradient[n] = -1.0;
+                                                column[n++] = numberColumns;
+                                                storedAmpl.addCut(-COIN_DBL_MAX, offset + 1.0e-7, n, column, gradient);
+                                                delete [] gradient;
+                                                delete [] column;
+                                            }
+                                            // could do three way branching round a) continuous b) best solution
+                                            printf("obj %g\n", bestObjectiveValue);
+                                            linkSolver->initialSolve();
+                                        }
+                                    }
+                                }
+#endif
+#endif
+                                if (logLevel <= 1)
+                                    si->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+#ifndef CBC_OTHER_SOLVER
+                                si->setSpecialOptions(0x40000000);
+#endif
+                            }
+                            if (!miplib) {
+                                if (!preSolve) {
+                                    model_.solver()->setHintParam(OsiDoPresolveInInitial, false, OsiHintTry);
+                                    model_.solver()->setHintParam(OsiDoPresolveInResolve, false, OsiHintTry);
+                                }
+                                double time1a = CoinCpuTime();
+                                OsiSolverInterface * solver = model_.solver();
+#ifndef CBC_OTHER_SOLVER
+                                OsiClpSolverInterface * si =
+                                    dynamic_cast<OsiClpSolverInterface *>(solver) ;
+                                if (si)
+                                    si->setSpecialOptions(si->specialOptions() | 1024);
+#endif
+                                model_.initialSolve();
+#ifndef CBC_OTHER_SOLVER
+                                ClpSimplex * clpSolver = si->getModelPtr();
+                                int iStatus = clpSolver->status();
+                                int iStatus2 = clpSolver->secondaryStatus();
+                                if (iStatus == 0) {
+                                    iStatus2 = 0;
+                                } else if (iStatus == 1) {
+                                    iStatus = 0;
+                                    iStatus2 = 1; // say infeasible
+                                } else if (iStatus == 2) {
+                                    iStatus = 0;
+                                    iStatus2 = 7; // say unbounded
+                                } else if (iStatus == 3) {
+                                    iStatus = 1;
+                                    if (iStatus2 == 9)
+                                        iStatus2 = 4;
+                                    else
+                                        iStatus2 = 3; // Use nodes - as closer than solutions
+                                } else if (iStatus == 4) {
+                                    iStatus = 2; // difficulties
+                                    iStatus2 = 0;
+                                }
+                                model_.setProblemStatus(iStatus);
+                                model_.setSecondaryStatus(iStatus2);
+                                si->setWarmStart(NULL);
+                                int returnCode = callBack(&model_, 1);
+                                if (returnCode) {
+                                    // exit if user wants
+                                    delete babModel_;
+                                    babModel_ = NULL;
+                                    return returnCode;
+                                }
+                                if (clpSolver->status() > 0) {
+                                    // and in babModel if exists
+                                    if (babModel_) {
+                                        babModel_->setProblemStatus(iStatus);
+                                        babModel_->setSecondaryStatus(iStatus2);
+                                    }
+                                    if (!noPrinting_) {
+                                        iStatus = clpSolver->status();
+                                        const char * msg[] = {"infeasible", "unbounded", "stopped",
+                                                              "difficulties", "other"
+                                                             };
+                                        sprintf(generalPrint, "Problem is %s - %.2f seconds",
+                                                msg[iStatus-1], CoinCpuTime() - time1a);
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << generalPrint
+                                        << CoinMessageEol;
+                                    }
+                                    break;
+                                }
+                                clpSolver->setSpecialOptions(clpSolver->specialOptions() | IN_BRANCH_AND_BOUND); // say is Cbc (and in branch and bound)
+#elif CBC_OTHER_SOLVER==1
+#endif
+                                if (!noPrinting_) {
+                                    sprintf(generalPrint, "Continuous objective value is %g - %.2f seconds",
+                                            solver->getObjValue(), CoinCpuTime() - time1a);
+                                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                    << generalPrint
+                                    << CoinMessageEol;
+                                }
+                                if (model_.getMaximumNodes() == -987654321) {
+                                    // See if No objective!
+                                    int numberColumns = clpSolver->getNumCols();
+                                    const double * obj = clpSolver->getObjCoefficients();
+                                    const double * lower = clpSolver->getColLower();
+                                    const double * upper = clpSolver->getColUpper();
+                                    int nObj = 0;
+                                    for (int i = 0; i < numberColumns; i++) {
+                                        if (upper[i] > lower[i] && obj[i])
+                                            nObj++;
+                                    }
+                                    if (!nObj) {
+                                        printf("************No objective!!\n");
+                                        model_.setMaximumSolutions(1);
+                                        // Column copy
+                                        CoinPackedMatrix  matrixByCol(*model_.solver()->getMatrixByCol());
+                                        //const double * element = matrixByCol.getElements();
+                                        //const int * row = matrixByCol.getIndices();
+                                        //const CoinBigIndex * columnStart = matrixByCol.getVectorStarts();
+                                        const int * columnLength = matrixByCol.getVectorLengths();
+                                        for (int i = 0; i < numberColumns; i++) {
+                                            double value = (CoinDrand48() + 0.5) * 10000;
+                                            value = 10;
+                                            value *= columnLength[i];
+                                            int iValue = static_cast<int> (value) / 10;
+                                            //iValue=1;
+                                            clpSolver->setObjCoeff(i, iValue);
+                                        }
+                                    }
+                                }
+#ifndef CBC_OTHER_SOLVER
+                                if (!complicatedInteger && preProcess == 0 && clpSolver->tightenPrimalBounds(0.0, 0, true) != 0) {
+#ifndef DISALLOW_PRINTING
+                                    std::cout << "Problem is infeasible - tightenPrimalBounds!" << std::endl;
+#endif
+                                    model_.setProblemStatus(0);
+                                    model_.setSecondaryStatus(1);
+                                    // and in babModel if exists
+                                    if (babModel_) {
+                                        babModel_->setProblemStatus(0);
+                                        babModel_->setSecondaryStatus(1);
+                                    }
+                                    break;
+                                }
+                                if (clpSolver->dualBound() == 1.0e10) {
+                                    ClpSimplex temp = *clpSolver;
+                                    temp.setLogLevel(0);
+                                    temp.dual(0, 7);
+                                    // user did not set - so modify
+                                    // get largest scaled away from bound
+                                    double largest = 1.0e-12;
+                                    double largestScaled = 1.0e-12;
+                                    int numberRows = temp.numberRows();
+                                    const double * rowPrimal = temp.primalRowSolution();
+                                    const double * rowLower = temp.rowLower();
+                                    const double * rowUpper = temp.rowUpper();
+                                    const double * rowScale = temp.rowScale();
+                                    int iRow;
+                                    for (iRow = 0; iRow < numberRows; iRow++) {
+                                        double value = rowPrimal[iRow];
+                                        double above = value - rowLower[iRow];
+                                        double below = rowUpper[iRow] - value;
+                                        if (above < 1.0e12) {
+                                            largest = CoinMax(largest, above);
+                                        }
+                                        if (below < 1.0e12) {
+                                            largest = CoinMax(largest, below);
+                                        }
+                                        if (rowScale) {
+                                            double multiplier = rowScale[iRow];
+                                            above *= multiplier;
+                                            below *= multiplier;
+                                        }
+                                        if (above < 1.0e12) {
+                                            largestScaled = CoinMax(largestScaled, above);
+                                        }
+                                        if (below < 1.0e12) {
+                                            largestScaled = CoinMax(largestScaled, below);
+                                        }
+                                    }
+
+                                    int numberColumns = temp.numberColumns();
+                                    const double * columnPrimal = temp.primalColumnSolution();
+                                    const double * columnLower = temp.columnLower();
+                                    const double * columnUpper = temp.columnUpper();
+                                    const double * columnScale = temp.columnScale();
+                                    int iColumn;
+                                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                        double value = columnPrimal[iColumn];
+                                        double above = value - columnLower[iColumn];
+                                        double below = columnUpper[iColumn] - value;
+                                        if (above < 1.0e12) {
+                                            largest = CoinMax(largest, above);
+                                        }
+                                        if (below < 1.0e12) {
+                                            largest = CoinMax(largest, below);
+                                        }
+                                        if (columnScale) {
+                                            double multiplier = 1.0 / columnScale[iColumn];
+                                            above *= multiplier;
+                                            below *= multiplier;
+                                        }
+                                        if (above < 1.0e12) {
+                                            largestScaled = CoinMax(largestScaled, above);
+                                        }
+                                        if (below < 1.0e12) {
+                                            largestScaled = CoinMax(largestScaled, below);
+                                        }
+                                    }
+#ifdef COIN_DEVELOP
+                                    if (!noPrinting_)
+                                        std::cout << "Largest (scaled) away from bound " << largestScaled
+                                                  << " unscaled " << largest << std::endl;
+#endif
+                                    clpSolver->setDualBound(CoinMax(1.0001e8, CoinMin(100.0*largest, 1.00001e10)));
+                                }
+                                si->resolve();  // clean up
+#endif
+                            }
+                            // If user made settings then use them
+                            if (!defaultSettings) {
+                                OsiSolverInterface * solver = model_.solver();
+                                if (!doScaling)
+                                    solver->setHintParam(OsiDoScale, false, OsiHintTry);
+#ifndef CBC_OTHER_SOLVER
+                                OsiClpSolverInterface * si =
+                                    dynamic_cast<OsiClpSolverInterface *>(solver) ;
+                                assert (si != NULL);
+                                // get clp itself
+                                ClpSimplex * modelC = si->getModelPtr();
+                                //if (modelC->tightenPrimalBounds()!=0) {
+                                //std::cout<<"Problem is infeasible!"<<std::endl;
+                                //break;
+                                //}
+                                // bounds based on continuous
+                                if (tightenFactor && !complicatedInteger) {
+                                    if (modelC->tightenPrimalBounds(tightenFactor) != 0) {
+#ifndef DISALLOW_PRINTING
+                                        std::cout << "Problem is infeasible!" << std::endl;
+#endif
+                                        model_.setProblemStatus(0);
+                                        model_.setSecondaryStatus(1);
+                                        // and in babModel if exists
+                                        if (babModel_) {
+                                            babModel_->setProblemStatus(0);
+                                            babModel_->setSecondaryStatus(1);
+                                        }
+                                        break;
+                                    }
+                                }
+#endif
+                            }
+                            // See if we want preprocessing
+                            OsiSolverInterface * saveSolver = NULL;
+                            CglPreProcess process;
+                            // Say integers in sync
+                            bool integersOK = true;
+                            delete babModel_;
+                            babModel_ = new CbcModel(model_);
+#ifndef CBC_OTHER_SOLVER
+                            int numberChanged = 0;
+                            OsiSolverInterface * solver3 = clpSolver->clone();
+                            babModel_->assignSolver(solver3);
+                            OsiClpSolverInterface * clpSolver2 = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                            if (clpSolver2->messageHandler()->logLevel())
+                                clpSolver2->messageHandler()->setLogLevel(1);
+                            if (logLevel > -1)
+                                clpSolver2->messageHandler()->setLogLevel(logLevel);
+                            lpSolver = clpSolver2->getModelPtr();
+                            if (lpSolver->factorizationFrequency() == 200 && !miplib) {
+                                // User did not touch preset
+                                int numberRows = lpSolver->numberRows();
+                                const int cutoff1 = 10000;
+                                const int cutoff2 = 100000;
+                                const int base = 75;
+                                const int freq0 = 50;
+                                const int freq1 = 200;
+                                const int freq2 = 400;
+                                const int maximum = 1000;
+                                int frequency;
+                                if (numberRows < cutoff1)
+                                    frequency = base + numberRows / freq0;
+                                else if (numberRows < cutoff2)
+                                    frequency = base + cutoff1 / freq0 + (numberRows - cutoff1) / freq1;
+                                else
+                                    frequency = base + cutoff1 / freq0 + (cutoff2 - cutoff1) / freq1 + (numberRows - cutoff2) / freq2;
+                                lpSolver->setFactorizationFrequency(CoinMin(maximum, frequency));
+                            }
+#elif CBC_OTHER_SOLVER==1
+                            OsiSolverInterface * solver3 = model_.solver()->clone();
+                            babModel_->assignSolver(solver3);
+#endif
+                            time2 = CoinCpuTime();
+                            totalTime += time2 - time1;
+                            //time1 = time2;
+                            double timeLeft = babModel_->getMaximumSeconds();
+                            int numberOriginalColumns = babModel_->solver()->getNumCols();
+                            if (preProcess == 7) {
+                                // use strategy instead
+                                preProcess = 0;
+                                useStrategy = true;
+#ifdef COIN_HAS_LINK
+                                // empty out any cuts
+                                if (storedAmpl.sizeRowCuts()) {
+                                    printf("Emptying ampl stored cuts as internal preprocessing\n");
+                                    CglStored temp;
+                                    storedAmpl = temp;
+                                }
+#endif
+                            }
+                            if (preProcess && type == CBC_PARAM_ACTION_BAB) {
+			      // see whether to switch off preprocessing
+			      // only allow SOS and integer
+			      OsiObject ** objects = babModel_->objects();
+			      int numberObjects = babModel_->numberObjects();
+			      for (int iObj = 0; iObj < numberObjects; iObj++) {
+				CbcSOS * objSOS =
+				  dynamic_cast <CbcSOS *>(objects[iObj]) ;
+				CbcSimpleInteger * objSimpleInteger =
+				  dynamic_cast <CbcSimpleInteger *>(objects[iObj]) ;
+				if (!objSimpleInteger&&!objSOS) {
+				  preProcess=0;
+				  break;
+				}
+			      }
+			    }
+                            if (type == CBC_PARAM_ACTION_BAB) {
+                                double limit;
+                                clpSolver->getDblParam(OsiDualObjectiveLimit, limit);
+                                if (clpSolver->getObjValue()*clpSolver->getObjSense() >=
+                                        limit*clpSolver->getObjSense())
+                                    preProcess = 0;
+                            }
+			    if (mipStartBefore.size())
+			      {
+				CbcModel tempModel=*babModel_;
+				std::vector< std::string > colNames;
+				for ( int i=0 ; (i<babModel_->solver()->getNumCols()) ; ++i )
+				  colNames.push_back( model_.solver()->getColName(i) );
+				std::vector< double > x( babModel_->getNumCols(), 0.0 );
+				double obj;
+				int status = computeCompleteSolution( &tempModel, colNames, mipStartBefore, &x[0], obj );
+				// set cutoff 
+				if (!status)
+				  babModel_->setCutoff(CoinMin(babModel_->getCutoff(),obj+1.0e-4));
+			      }
+                            if (preProcess && type == CBC_PARAM_ACTION_BAB) {
+#ifndef CBC_OTHER_SOLVER
+                                // See if sos from mps file
+                                if (numberSOS == 0 && clpSolver->numberSOS() && doSOS) {
+                                    // SOS
+                                    numberSOS = clpSolver->numberSOS();
+                                    const CoinSet * setInfo = clpSolver->setInfo();
+                                    sosStart = new int [numberSOS+1];
+                                    sosType = new char [numberSOS];
+                                    int i;
+                                    int nTotal = 0;
+                                    sosStart[0] = 0;
+                                    for ( i = 0; i < numberSOS; i++) {
+                                        int type = setInfo[i].setType();
+                                        int n = setInfo[i].numberEntries();
+                                        sosType[i] = static_cast<char>(type);
+                                        nTotal += n;
+                                        sosStart[i+1] = nTotal;
+                                    }
+                                    sosIndices = new int[nTotal];
+                                    sosReference = new double [nTotal];
+                                    for (i = 0; i < numberSOS; i++) {
+                                        int n = setInfo[i].numberEntries();
+                                        const int * which = setInfo[i].which();
+                                        const double * weights = setInfo[i].weights();
+                                        int base = sosStart[i];
+                                        for (int j = 0; j < n; j++) {
+                                            int k = which[j];
+                                            sosIndices[j+base] = k;
+                                            sosReference[j+base] = weights ? weights[j] : static_cast<double> (j);
+                                        }
+                                    }
+                                }
+#endif
+                                saveSolver = babModel_->solver()->clone();
+                                /* Do not try and produce equality cliques and
+                                   do up to 10 passes */
+                                OsiSolverInterface * solver2;
+                                {
+                                    // Tell solver we are in Branch and Cut
+                                    saveSolver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ;
+                                    // Default set of cut generators
+                                    CglProbing generator1;
+                                    generator1.setUsingObjective(1);
+                                    generator1.setMaxPass(1);
+                                    generator1.setMaxPassRoot(1);
+                                    generator1.setMaxProbeRoot(CoinMin(3000, saveSolver->getNumCols()));
+                                    generator1.setMaxElements(100);
+                                    generator1.setMaxElementsRoot(200);
+                                    generator1.setMaxLookRoot(50);
+                                    if (saveSolver->getNumCols() > 3000)
+                                        generator1.setMaxProbeRoot(123);
+                                    generator1.setRowCuts(3);
+                                    if ((tunePreProcess&1) != 0) {
+                                        // heavy probing
+                                        generator1.setMaxPassRoot(2);
+                                        generator1.setMaxElements(300);
+                                        generator1.setMaxProbeRoot(saveSolver->getNumCols());
+                                    }
+                                    if ((babModel_->specialOptions()&65536) != 0)
+                                        process.setOptions(1);
+                                    // Add in generators
+				    if ((model_.moreSpecialOptions()&65536)==0)
+				      process.addCutGenerator(&generator1);
+                                    int translate[] = {9999, 0, 0, -3, 2, 3, -2, 9999, 4, 5};
+                                    process.passInMessageHandler(babModel_->messageHandler());
+                                    //process.messageHandler()->setLogLevel(babModel_->logLevel());
+#ifdef COIN_HAS_ASL
+                                    if (info.numberSos && doSOS && statusUserFunction_[0]) {
+                                        // SOS
+                                        numberSOS = info.numberSos;
+                                        sosStart = info.sosStart;
+                                        sosIndices = info.sosIndices;
+                                    }
+#endif
+                                    if (numberSOS && doSOS) {
+                                        // SOS
+                                        int numberColumns = saveSolver->getNumCols();
+                                        char * prohibited = new char[numberColumns];
+                                        memset(prohibited, 0, numberColumns);
+                                        int n = sosStart[numberSOS];
+                                        for (int i = 0; i < n; i++) {
+                                            int iColumn = sosIndices[i];
+                                            prohibited[iColumn] = 1;
+                                        }
+                                        process.passInProhibited(prohibited, numberColumns);
+                                        delete [] prohibited;
+                                    }
+                                    if (0) {
+				      
+				      // Special integers
+				      int numberColumns = saveSolver->getNumCols();
+				      char * prohibited = new char[numberColumns];
+				      memset(prohibited, 0, numberColumns);
+				      const CoinPackedMatrix * matrix = saveSolver->getMatrixByCol();
+				      const int * columnLength = matrix->getVectorLengths();
+				      int numberProhibited=0;
+				      for (int iColumn = numberColumns-1; iColumn >=0; iColumn--) {
+					if (!saveSolver->isInteger(iColumn)||
+					    columnLength[iColumn]>1)
+					  break;
+					numberProhibited++;
+					prohibited[iColumn] = 1;
+				      }
+				      if (numberProhibited) {
+					process.passInProhibited(prohibited, numberColumns);
+					printf("**** Treating last %d integers as special - give high priority?\n",numberProhibited);
+				      }
+				      delete [] prohibited;
+                                    }
+                                    if (!model_.numberObjects() && true) {
+                                        /* model may not have created objects
+                                           If none then create
+                                        */
+                                        model_.findIntegers(true);
+                                    }
+                                    if (model_.numberObjects()) {
+                                        OsiObject ** oldObjects = babModel_->objects();
+                                        int numberOldObjects = babModel_->numberObjects();
+                                        // SOS
+                                        int numberColumns = saveSolver->getNumCols();
+                                        char * prohibited = new char[numberColumns];
+                                        memset(prohibited, 0, numberColumns);
+                                        int numberProhibited = 0;
+                                        for (int iObj = 0; iObj < numberOldObjects; iObj++) {
+                                            CbcSOS * obj =
+                                                dynamic_cast <CbcSOS *>(oldObjects[iObj]) ;
+                                            if (obj) {
+                                                int n = obj->numberMembers();
+                                                const int * which = obj->members();
+                                                for (int i = 0; i < n; i++) {
+                                                    int iColumn = which[i];
+                                                    prohibited[iColumn] = 1;
+                                                    numberProhibited++;
+                                                }
+                                            }
+                                            CbcLotsize * obj2 =
+                                                dynamic_cast <CbcLotsize *>(oldObjects[iObj]) ;
+                                            if (obj2) {
+                                                int iColumn = obj2->columnNumber();
+                                                prohibited[iColumn] = 1;
+                                                numberProhibited++;
+                                            }
+                                        }
+                                        if (numberProhibited)
+                                            process.passInProhibited(prohibited, numberColumns);
+                                        delete [] prohibited;
+                                    }
+                                    int numberPasses = 10;
+                                    if (tunePreProcess >= 1000000) {
+                                        numberPasses = (tunePreProcess / 1000000) - 1;
+                                        tunePreProcess = tunePreProcess % 1000000;
+                                    } else if (tunePreProcess >= 1000) {
+                                        numberPasses = (tunePreProcess / 1000) - 1;
+                                        tunePreProcess = tunePreProcess % 1000;
+                                    }
+#ifndef CBC_OTHER_SOLVER
+                                    if (doSprint > 0) {
+                                        // Sprint for primal solves
+                                        ClpSolve::SolveType method = ClpSolve::usePrimalorSprint;
+                                        ClpSolve::PresolveType presolveType = ClpSolve::presolveOff;
+                                        int numberPasses = 5;
+                                        int options[] = {0, 3, 0, 0, 0, 0};
+                                        int extraInfo[] = { -1, 20, -1, -1, -1, -1};
+                                        extraInfo[1] = doSprint;
+                                        int independentOptions[] = {0, 0, 3};
+                                        ClpSolve clpSolve(method, presolveType, numberPasses,
+                                                          options, extraInfo, independentOptions);
+                                        // say use in OsiClp
+                                        clpSolve.setSpecialOption(6, 1);
+                                        OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (saveSolver);
+                                        osiclp->setSolveOptions(clpSolve);
+                                        osiclp->setHintParam(OsiDoDualInResolve, false);
+                                        // switch off row copy
+                                        osiclp->getModelPtr()->setSpecialOptions(osiclp->getModelPtr()->specialOptions() | 256);
+                                        osiclp->getModelPtr()->setInfeasibilityCost(1.0e11);
+                                    }
+#endif
+#ifndef CBC_OTHER_SOLVER
+                                    {
+                                        OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (saveSolver);
+                                        osiclp->setSpecialOptions(osiclp->specialOptions() | 1024);
+                                        int savePerturbation = osiclp->getModelPtr()->perturbation();
+                                        //#define CBC_TEMP1
+#ifdef CBC_TEMP1
+                                        if (savePerturbation == 50)
+                                            osiclp->getModelPtr()->setPerturbation(52); // try less
+#endif
+					if ((model_.moreSpecialOptions()&65536)!=0)
+					  process.setOptions(2+4+8); // no cuts
+					cbcPreProcessPointer = & process;
+                                        solver2 = process.preProcessNonDefault(*saveSolver, translate[preProcess], numberPasses,
+                                                                               tunePreProcess);
+                                        /*solver2->writeMps("after");
+                                          saveSolver->writeMps("before");*/
+                                        osiclp->getModelPtr()->setPerturbation(savePerturbation);
+                                    }
+#elif CBC_OTHER_SOLVER==1
+				    cbcPreProcessPointer = & process;
+                                    solver2 = process.preProcessNonDefault(*saveSolver, translate[preProcess], numberPasses,
+                                                                           tunePreProcess);
+#endif
+                                    integersOK = false; // We need to redo if CbcObjects exist
+                                    // Tell solver we are not in Branch and Cut
+                                    saveSolver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+                                    if (solver2)
+                                        solver2->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+                                }
+#ifdef COIN_HAS_ASL
+                                if (!solver2 && statusUserFunction_[0]) {
+                                    // infeasible
+                                    info.problemStatus = 1;
+                                    info.objValue = 1.0e100;
+                                    sprintf(info.buffer, "infeasible/unbounded by pre-processing");
+                                    info.primalSolution = NULL;
+                                    info.dualSolution = NULL;
+                                    break;
+                                }
+#endif
+                                if (!noPrinting_) {
+                                    if (!solver2) {
+                                        sprintf(generalPrint, "Pre-processing says infeasible or unbounded");
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << generalPrint
+                                        << CoinMessageEol;
+                                    } else {
+                                        //printf("processed model has %d rows, %d columns and %d elements\n",
+                                        //     solver2->getNumRows(),solver2->getNumCols(),solver2->getNumElements());
+                                    }
+                                }
+                                if (!solver2) {
+                                    // say infeasible for solution
+                                    integerStatus = 6;
+                                    model_.setProblemStatus(0);
+                                    model_.setSecondaryStatus(1);
+                                    babModel_->setProblemStatus(0);
+                                    babModel_->setSecondaryStatus(1);
+                                } else {
+                                    statistics_nprocessedrows = solver2->getNumRows();
+                                    statistics_nprocessedcols = solver2->getNumCols();
+                                    model_.setProblemStatus(-1);
+                                    babModel_->setProblemStatus(-1);
+                                }
+                                int returnCode = callBack(babModel_, 2);
+                                if (returnCode) {
+                                    // exit if user wants
+                                    delete babModel_;
+                                    babModel_ = NULL;
+                                    return returnCode;
+                                }
+                                if (!solver2)
+                                    break;
+                                if (model_.bestSolution()) {
+                                    // need to redo - in case no better found in BAB
+                                    // just get integer part right
+                                    const int * originalColumns = process.originalColumns();
+                                    int numberColumns = solver2->getNumCols();
+                                    double * bestSolution = babModel_->bestSolution();
+                                    const double * oldBestSolution = model_.bestSolution();
+                                    for (int i = 0; i < numberColumns; i++) {
+                                        int jColumn = originalColumns[i];
+                                        bestSolution[i] = oldBestSolution[jColumn];
+                                    }
+                                }
+                                //solver2->resolve();
+                                if (preProcess == 2) {
+                                    OsiClpSolverInterface * clpSolver2 = dynamic_cast< OsiClpSolverInterface*> (solver2);
+                                    ClpSimplex * lpSolver = clpSolver2->getModelPtr();
+                                    lpSolver->writeMps("presolved.mps", 0, 1, lpSolver->optimizationDirection());
+                                    printf("Preprocessed model (minimization) on presolved.mps\n");
+                                }
+                                {
+                                    // look at new integers
+                                    int numberOriginalColumns =
+                                        process.originalModel()->getNumCols();
+                                    const int * originalColumns = process.originalColumns();
+                                    OsiClpSolverInterface * osiclp2 = dynamic_cast< OsiClpSolverInterface*> (solver2);
+                                    int numberColumns = osiclp2->getNumCols();
+                                    OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (saveSolver);
+                                    for (int i = 0; i < numberColumns; i++) {
+                                        int iColumn = originalColumns[i];
+                                        if (iColumn < numberOriginalColumns) {
+                                            if (osiclp2->isInteger(i) && !osiclp->isInteger(iColumn))
+                                                osiclp2->setOptionalInteger(i); // say optional
+                                        }
+                                    }
+                                }
+                                // we have to keep solver2 so pass clone
+                                solver2 = solver2->clone();
+				// see if extra variables wanted
+				int threshold = 
+				  parameters_[whichParam(CBC_PARAM_INT_EXTRA_VARIABLES, numberParameters_, parameters_)].intValue();
+				if (threshold) {
+				  int numberColumns = solver2->getNumCols();
+				  int highPriority=0;
+				  /*
+				    normal - no priorities
+				    >10000 equal high priority
+				    >20000 higher priority for higher cost
+				  */
+				  if (threshold>10000) {
+				    highPriority=threshold/10000;
+				    threshold -= 10000*highPriority;
+				  }
+				  const double * columnLower = solver2->getColLower();
+				  const double * columnUpper = solver2->getColUpper();
+				  const double * objective = solver2->getObjCoefficients();
+				  int numberIntegers = 0;
+				  int numberBinary = 0;
+				  int numberTotalIntegers=0;
+				  double * obj = new double [numberColumns];
+				  int * which = new int [numberColumns];
+				  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+				    if (solver2->isInteger(iColumn)) {
+				      numberTotalIntegers++;
+				      if (columnUpper[iColumn] > columnLower[iColumn]) {
+					numberIntegers++;
+					if (columnLower[iColumn] == 0.0 && columnUpper[iColumn] == 1)
+					  numberBinary++;
+				      }
+				    }
+				  }
+				  int numberSort=0;
+				  int numberZero=0;
+				  int numberZeroContinuous=0;
+				  int numberDifferentObj=0;
+				  int numberContinuous=0;
+				  for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+				    if (columnUpper[iColumn] > columnLower[iColumn]) {
+				      if (solver2->isInteger(iColumn)) {
+					if (!objective[iColumn]) {
+					  numberZero++;
+					} else {
+					  obj[numberSort]= fabs(objective[iColumn]);
+					  which[numberSort++]=iColumn;
+					}
+				      } else if (objective[iColumn]) {
+					numberContinuous++;
+				      } else {
+					numberZeroContinuous++;
+				      }
+				    }
+				  }
+				  CoinSort_2(obj,obj+numberSort,which);
+				  double last=obj[0];
+				  for (int jColumn = 1; jColumn < numberSort; jColumn++) {
+				    if (fabs(obj[jColumn]-last)>1.0e-12) {
+				      numberDifferentObj++;
+				      last=obj[jColumn];
+				    }
+				  }
+				  numberDifferentObj++;
+				  sprintf(generalPrint,"Problem has %d integers (%d of which binary) and %d continuous",
+					 numberIntegers,numberBinary,numberColumns-numberIntegers);
+				  generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                    << generalPrint
+                                    << CoinMessageEol;
+				  if (numberColumns>numberIntegers) {
+				    sprintf(generalPrint,"%d continuous have nonzero objective, %d have zero objective",
+					    numberContinuous,numberZeroContinuous);
+				    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				      << generalPrint
+				      << CoinMessageEol;
+				  }
+				  sprintf(generalPrint,"%d integer have nonzero objective, %d have zero objective, %d different nonzero (taking abs)",
+					  numberSort,numberZero,numberDifferentObj);
+				  generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                    << generalPrint
+                                    << CoinMessageEol;
+				  if (numberDifferentObj<=threshold + (numberZero) ? 1 : 0 && numberDifferentObj) {
+				    int * backward=NULL;
+				    if (highPriority) {
+				      newPriorities = new int [numberTotalIntegers+numberDifferentObj+numberColumns];
+				      backward=newPriorities+numberTotalIntegers+numberDifferentObj;
+				      numberTotalIntegers=0;
+				      for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+					if (solver2->isInteger(iColumn)) {
+					  backward[iColumn]=numberTotalIntegers;
+					  newPriorities[numberTotalIntegers++]=10000;
+					}
+				      }
+				    }
+				    int iLast=0;
+				    double last=obj[0];
+				    for (int jColumn = 1; jColumn < numberSort; jColumn++) {
+				      if (fabs(obj[jColumn]-last)>1.0e-12) {
+					sprintf(generalPrint,"%d variables have objective of %g",
+					       jColumn-iLast,last);
+					generalMessageHandler->message(CLP_GENERAL, generalMessages)
+					  << generalPrint
+					  << CoinMessageEol;
+					iLast=jColumn;
+					last=obj[jColumn];
+				      }
+				    }
+				    sprintf(generalPrint,"%d variables have objective of %g",
+					   numberSort-iLast,last);
+				    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				      << generalPrint
+				      << CoinMessageEol;
+				    int spaceNeeded=numberSort+numberDifferentObj;
+				    int * columnAdd = new int[spaceNeeded+numberDifferentObj+1];
+				    double * elementAdd = new double[spaceNeeded];
+				    int * rowAdd = new int[numberDifferentObj+1];
+				    double * objectiveNew = new double[3*numberDifferentObj];
+				    double * lowerNew = objectiveNew+numberDifferentObj;
+				    double * upperNew = lowerNew+numberDifferentObj;
+				    memset(columnAdd+spaceNeeded,0,
+					   (numberDifferentObj+1)*sizeof(int));
+				    iLast=0;
+				    last=obj[0];
+				    numberDifferentObj=0;
+				    int priorityLevel=9999;
+				    int numberElements=0;
+				    rowAdd[0]=0;
+				    for (int jColumn = 1; jColumn < numberSort+1; jColumn++) {
+				      if (jColumn==numberSort||fabs(obj[jColumn]-last)>1.0e-12) {
+					// not if just one
+					if (jColumn-iLast>1) {
+					  // do priority
+					  if (highPriority==1) {
+					    newPriorities[numberTotalIntegers+numberDifferentObj]
+					      = 500;
+					  } else if (highPriority==2) {
+					    newPriorities[numberTotalIntegers+numberDifferentObj]
+					      = priorityLevel;
+					    priorityLevel--;
+					  }
+					  int iColumn=which[iLast];
+					  objectiveNew[numberDifferentObj]=objective[iColumn];
+					  double lower=0.0;
+					  double upper=0.0;
+					  for (int kColumn=iLast;kColumn<jColumn;kColumn++) {
+					    iColumn=which[kColumn];
+					    solver2->setObjCoeff(iColumn,0.0);
+					    double lowerValue=columnLower[iColumn];
+					    double upperValue=columnUpper[iColumn];
+					    double elementValue=-1.0;
+					    if (objectiveNew[numberDifferentObj]*objective[iColumn]<0.0) {
+					      lowerValue=-columnUpper[iColumn];
+					      upperValue=-columnLower[iColumn];
+					      elementValue=1.0;
+					    }
+					    columnAdd[numberElements]=iColumn;
+					    elementAdd[numberElements++]=elementValue;
+					    if (lower!=-COIN_DBL_MAX) {
+					      if (lowerValue!=-COIN_DBL_MAX)
+						lower += lowerValue;
+					      else
+						lower=-COIN_DBL_MAX;
+					    }
+					    if (upper!=COIN_DBL_MAX) {
+					      if (upperValue!=COIN_DBL_MAX)
+						upper += upperValue;
+					      else
+						upper=COIN_DBL_MAX;
+					    }
+					  }
+					  columnAdd[numberElements]=numberColumns+numberDifferentObj;
+					  elementAdd[numberElements++]=1.0;
+					  lowerNew[numberDifferentObj]=lower;
+					  upperNew[numberDifferentObj]=upper;
+					  numberDifferentObj++;
+					  rowAdd[numberDifferentObj]=numberElements;
+					} else if (highPriority) {
+					  // just one
+					  // do priority
+					  int iColumn=which[iLast];
+					  int iInt=backward[iColumn];
+					  if (highPriority==1) {
+					    newPriorities[iInt] = 500;
+					  } else {
+					    newPriorities[iInt] = priorityLevel;
+					    priorityLevel--;
+					  }
+					}
+					if (jColumn<numberSort) {
+					  iLast=jColumn;
+					  last=obj[jColumn];
+					}
+				      }
+				    }
+				    if (numberDifferentObj) {
+				      // add columns
+				      solver2->addCols(numberDifferentObj, 
+						       columnAdd+spaceNeeded, NULL, NULL,
+						       lowerNew, upperNew,objectiveNew);
+				      // add constraints and make integer if all integer in group
+				      for (int iObj=0; iObj < numberDifferentObj; iObj++) {
+					lowerNew[iObj]=0.0;
+					upperNew[iObj]=0.0;
+					solver2->setInteger(numberColumns+iObj);
+				      }
+				      solver2->addRows(numberDifferentObj, 
+						       rowAdd,columnAdd,elementAdd,
+						       lowerNew, upperNew);
+				      sprintf(generalPrint,"Replacing model - %d new variables",numberDifferentObj);
+				      generalMessageHandler->message(CLP_GENERAL, generalMessages)
+					<< generalPrint
+					<< CoinMessageEol;
+				      truncateColumns=numberColumns;
+				    }
+				    delete [] columnAdd;
+				    delete [] elementAdd;
+				    delete [] rowAdd;
+				    delete [] objectiveNew;
+				  }
+				  delete [] which;
+				  delete [] obj;
+				}
+                                babModel_->assignSolver(solver2);
+                                babModel_->setOriginalColumns(process.originalColumns(),
+							      truncateColumns);
+                                babModel_->initialSolve();
+                                babModel_->setMaximumSeconds(timeLeft - (CoinCpuTime() - time2));
+                            }
+                            // now tighten bounds
+                            if (!miplib) {
+#ifndef CBC_OTHER_SOLVER
+                                OsiClpSolverInterface * si =
+                                    dynamic_cast<OsiClpSolverInterface *>(babModel_->solver()) ;
+                                assert (si != NULL);
+                                // get clp itself
+                                ClpSimplex * modelC = si->getModelPtr();
+                                //if (noPrinting_)
+                                //modelC->setLogLevel(0);
+                                if (!complicatedInteger && modelC->tightenPrimalBounds() != 0) {
+#ifndef DISALLOW_PRINTING
+                                    std::cout << "Problem is infeasible!" << std::endl;
+#endif
+                                    model_.setProblemStatus(0);
+                                    model_.setSecondaryStatus(1);
+                                    // and in babModel_ if exists
+                                    if (babModel_) {
+                                        babModel_->setProblemStatus(0);
+                                        babModel_->setSecondaryStatus(1);
+                                    }
+                                    break;
+                                }
+                                si->resolve();
+#elif CBC_OTHER_SOLVER==1
+#endif
+                            }
+                            if (debugValues) {
+                                // for debug
+                                std::string problemName ;
+                                babModel_->solver()->getStrParam(OsiProbName, problemName) ;
+                                babModel_->solver()->activateRowCutDebugger(problemName.c_str()) ;
+                                twomirGen.probname_ = CoinStrdup(problemName.c_str());
+                                // checking seems odd
+                                //redsplitGen.set_given_optsol(babModel_->solver()->getRowCutDebuggerAlways()->optimalSolution(),
+                                //                         babModel_->getNumCols());
+                            }
+                            int testOsiOptions = parameters_[whichParam(CBC_PARAM_INT_TESTOSI, numberParameters_, parameters_)].intValue();
+                            //#ifdef COIN_HAS_ASL
+#ifndef JJF_ONE
+                            // If linked then see if expansion wanted
+                            {
+                                OsiSolverLink * solver3 = dynamic_cast<OsiSolverLink *> (babModel_->solver());
+                                int options = parameters_[whichParam(CBC_PARAM_INT_MIPOPTIONS, numberParameters_, parameters_)].intValue() / 10000;
+                                if (solver3 || (options&16) != 0) {
+                                    if (options) {
+                                        /*
+                                          1 - force mini branch and bound
+                                          2 - set priorities high on continuous
+                                          4 - try adding OA cuts
+                                          8 - try doing quadratic linearization
+                                          16 - try expanding knapsacks
+                                        */
+                                        if ((options&16)) {
+                                            int numberColumns = saveCoinModel.numberColumns();
+                                            int numberRows = saveCoinModel.numberRows();
+                                            whichColumn = new int[numberColumns];
+                                            knapsackStart = new int[numberRows+1];
+                                            knapsackRow = new int[numberRows];
+                                            numberKnapsack = 10000;
+                                            int extra1 = parameters_[whichParam(CBC_PARAM_INT_EXTRA1, numberParameters_, parameters_)].intValue();
+                                            int extra2 = parameters_[whichParam(CBC_PARAM_INT_EXTRA2, numberParameters_, parameters_)].intValue();
+                                            int logLevel = parameters_[log].intValue();
+                                            OsiSolverInterface * solver = expandKnapsack(saveCoinModel, whichColumn, knapsackStart,
+                                                                          knapsackRow, numberKnapsack,
+                                                                          storedAmpl, logLevel, extra1, extra2,
+                                                                          saveTightenedModel);
+                                            if (solver) {
+#ifndef CBC_OTHER_SOLVER
+                                                clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+                                                assert (clpSolver);
+                                                lpSolver = clpSolver->getModelPtr();
+#endif
+                                                babModel_->assignSolver(solver);
+                                                testOsiOptions = 0;
+                                                // allow gomory
+                                                complicatedInteger = 0;
+#ifdef COIN_HAS_ASL
+                                                // Priorities already done
+                                                free(info.priorities);
+                                                info.priorities = NULL;
+#endif
+                                            } else {
+                                                numberKnapsack = 0;
+                                                delete [] whichColumn;
+                                                delete [] knapsackStart;
+                                                delete [] knapsackRow;
+                                                whichColumn = NULL;
+                                                knapsackStart = NULL;
+                                                knapsackRow = NULL;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+#endif
+                            if (useCosts && testOsiOptions < 0) {
+                                int numberColumns = babModel_->getNumCols();
+                                int * sort = new int[numberColumns];
+                                double * dsort = new double[numberColumns];
+                                int * priority = new int [numberColumns];
+                                const double * objective = babModel_->getObjCoefficients();
+                                const double * lower = babModel_->getColLower() ;
+                                const double * upper = babModel_->getColUpper() ;
+                                const CoinPackedMatrix * matrix = babModel_->solver()->getMatrixByCol();
+                                const int * columnLength = matrix->getVectorLengths();
+                                int iColumn;
+                                int n = 0;
+                                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                    if (babModel_->isInteger(iColumn)) {
+                                        sort[n] = n;
+                                        if (useCosts == 1)
+                                            dsort[n++] = -fabs(objective[iColumn]);
+                                        else if (useCosts == 2)
+                                            dsort[n++] = iColumn;
+                                        else if (useCosts == 3)
+                                            dsort[n++] = upper[iColumn] - lower[iColumn];
+                                        else if (useCosts == 4)
+                                            dsort[n++] = -(upper[iColumn] - lower[iColumn]);
+                                        else if (useCosts == 5)
+                                            dsort[n++] = -columnLength[iColumn];
+                                        else if (useCosts == 6)
+					    dsort[n++] = (columnLength[iColumn]==1) ? -1.0 : 0.0;
+                                        else if (useCosts == 7)
+					    dsort[n++] = (objective[iColumn]) ? -1.0 : 0.0;
+                                    }
+                                }
+                                CoinSort_2(dsort, dsort + n, sort);
+                                int level = 0;
+                                double last = -1.0e100;
+                                for (int i = 0; i < n; i++) {
+                                    int iPut = sort[i];
+                                    if (dsort[i] != last) {
+                                        level++;
+                                        last = dsort[i];
+                                    }
+                                    priority[iPut] = level;
+                                }
+				if(newPriorities ) {
+				  // get rid of
+				  delete [] newPriorities;
+				  newPriorities = NULL;
+				}
+                                babModel_->passInPriorities( priority, false);
+                                integersOK = true;
+                                delete [] priority;
+                                delete [] sort;
+                                delete [] dsort;
+                            }
+                            // Set up heuristics
+                            doHeuristics(babModel_, ((!miplib) ? 1 : 10), parameters_,
+                                         numberParameters_, noPrinting_, initialPumpTune);
+                            if (!miplib) {
+                                if (parameters_[whichParam(CBC_PARAM_STR_LOCALTREE, numberParameters_, parameters_)].currentOptionAsInteger()) {
+                                    CbcTreeLocal localTree(babModel_, NULL, 10, 0, 0, 10000, 2000);
+                                    babModel_->passInTreeHandler(localTree);
+                                }
+                            }
+                            if (type == CBC_PARAM_ACTION_MIPLIB) {
+                                if (babModel_->numberStrong() == 5 && babModel_->numberBeforeTrust() == 5)
+                                    babModel_->setNumberBeforeTrust(10);
+                            }
+                            int experimentFlag = parameters_[whichParam(CBC_PARAM_INT_EXPERIMENT, numberParameters_,
+                                                             parameters_)].intValue();
+                            int strategyFlag = parameters_[whichParam(CBC_PARAM_INT_STRATEGY, numberParameters_,
+                                                           parameters_)].intValue();
+                            int bothFlags = CoinMax(CoinMin(experimentFlag, 1), strategyFlag);
+                            // add cut generators if wanted
+                            int switches[30];
+                            int accuracyFlag[30];
+			    char doAtEnd[30];
+			    memset(doAtEnd,0,30);
+                            int numberGenerators = 0;
+                            int translate[] = { -100, -1, -99, -98, 1, -1098, -999, 1, 1, 1, -1};
+			    int maximumSlowPasses = 
+			      parameters_[whichParam(CBC_PARAM_INT_MAX_SLOW_CUTS, 
+						     numberParameters_, parameters_)].intValue();
+                            if (probingAction) {
+                                int numberColumns = babModel_->solver()->getNumCols();
+                                if (probingAction > 7) {
+                                    probingGen.setMaxElements(numberColumns);
+                                    probingGen.setMaxElementsRoot(numberColumns);
+                                }
+                                probingGen.setMaxProbeRoot(CoinMin(2000, numberColumns));
+                                probingGen.setMaxProbeRoot(123);
+                                probingGen.setMaxProbe(123);
+                                probingGen.setMaxLookRoot(20);
+                                if (probingAction == 7 || probingAction == 9)
+                                    probingGen.setRowCuts(-3); // strengthening etc just at root
+                                if (probingAction == 8 || probingAction == 9) {
+                                    // Number of unsatisfied variables to look at
+                                    probingGen.setMaxProbeRoot(numberColumns);
+                                    probingGen.setMaxProbe(numberColumns);
+                                    // How far to follow the consequences
+                                    probingGen.setMaxLook(50);
+                                    probingGen.setMaxLookRoot(50);
+                                }
+                                if (probingAction == 10) {
+                                    probingGen.setMaxPassRoot(2);
+                                    probingGen.setMaxProbeRoot(numberColumns);
+                                    probingGen.setMaxLookRoot(100);
+                                }
+                                // If 5 then force on
+                                int iAction = translate[probingAction];
+                                if (probingAction == 5)
+                                    iAction = 1;
+                                babModel_->addCutGenerator(&probingGen, iAction, "Probing");
+                                accuracyFlag[numberGenerators] = 5;
+                                switches[numberGenerators++] = 0;
+                            }
+                            if (gomoryAction && (complicatedInteger != 1 ||
+                                                 (gomoryAction == 1 || gomoryAction >= 4))) {
+                                // try larger limit
+                                int numberColumns = babModel_->getNumCols();
+                                if (gomoryAction == 7) {
+                                    gomoryAction = 4;
+                                    gomoryGen.setLimitAtRoot(numberColumns);
+                                    gomoryGen.setLimit(numberColumns);
+                                } else if (gomoryAction == 8) {
+                                    gomoryAction = 3;
+                                    gomoryGen.setLimitAtRoot(numberColumns);
+                                    gomoryGen.setLimit(200);
+                                } else if (numberColumns > 5000) {
+                                    //#define MORE_CUTS2
+#ifdef MORE_CUTS2
+                                    // try larger limit
+                                    gomoryGen.setLimitAtRoot(numberColumns);
+                                    gomoryGen.setLimit(200);
+#else
+                                    gomoryGen.setLimitAtRoot(2000);
+                                    //gomoryGen.setLimit(200);
+#endif
+                                } else {
+#ifdef MORE_CUTS2
+                                    // try larger limit
+                                    gomoryGen.setLimitAtRoot(numberColumns);
+                                    gomoryGen.setLimit(200);
+#endif
+                                }
+                                int cutLength =
+                                    parameters_[whichParam(CBC_PARAM_INT_CUTLENGTH, numberParameters_, parameters_)].intValue();
+                                if (cutLength != -1) {
+                                    gomoryGen.setLimitAtRoot(cutLength);
+                                    if (cutLength < 10000000) {
+                                        gomoryGen.setLimit(cutLength);
+                                    } else {
+                                        gomoryGen.setLimit(cutLength % 10000000);
+                                    }
+                                }
+                                int laGomory = parameters_[whichParam(CBC_PARAM_STR_LAGOMORYCUTS, numberParameters_, parameters_)].currentOptionAsInteger();
+				int gType = translate[gomoryAction];
+				if (!laGomory) {
+				  // Normal
+				  babModel_->addCutGenerator(&gomoryGen, translate[gomoryAction], "Gomory");
+				  accuracyFlag[numberGenerators] = 3;
+				  switches[numberGenerators++] = 0;
+				} else {
+				  laGomory--;
+				  int type = (laGomory % 3)+1;
+				  int when = laGomory/3;
+				  char atEnd = (when<2) ? 1 : 0;
+				  int gomoryTypeMajor = 10;
+				  if (when<3) {
+				    // normal as well
+				    babModel_->addCutGenerator(&gomoryGen, gType, "Gomory");
+				    accuracyFlag[numberGenerators] = 3;
+				    switches[numberGenerators++] = 0;
+				    if (when==2)
+				      gomoryTypeMajor=20;
+				  } else {
+				    when--; // so on
+				    gomoryTypeMajor=20;
+				  }
+				  if (!when)
+				    gType=-99; // root
+				  gomoryGen.passInOriginalSolver(babModel_->solver());
+				  if ((type&1) !=0) {
+				    // clean
+				    gomoryGen.setGomoryType(gomoryTypeMajor+1);
+				    babModel_->addCutGenerator(&gomoryGen, gType, "GomoryL1");
+				    accuracyFlag[numberGenerators] = 3;
+				    doAtEnd[numberGenerators]=atEnd;
+				    if (atEnd) {
+				      babModel_->cutGenerator(numberGenerators)->setMaximumTries(99999999);
+				      babModel_->cutGenerator(numberGenerators)->setHowOften(1);
+				    }
+				    switches[numberGenerators++] = 0;
+				  }
+				  if ((type&2) !=0) {
+				    // simple
+				    gomoryGen.setGomoryType(gomoryTypeMajor+2);
+				    babModel_->addCutGenerator(&gomoryGen, gType, "GomoryL2");
+				    accuracyFlag[numberGenerators] = 3;
+				    doAtEnd[numberGenerators]=atEnd;
+				    if (atEnd) {
+				      babModel_->cutGenerator(numberGenerators)->setMaximumTries(99999999);
+				      babModel_->cutGenerator(numberGenerators)->setHowOften(1);
+				    }
+				    switches[numberGenerators++] = 0;
+				  }
+				}
+                            }
+#ifdef CLIQUE_ANALYSIS
+                            if (miplib && !storedAmpl.sizeRowCuts()) {
+                                printf("looking at probing\n");
+                                babModel_->addCutGenerator(&storedAmpl, 1, "Stored");
+                            }
+#endif
+                            if (knapsackAction) {
+                                babModel_->addCutGenerator(&knapsackGen, translate[knapsackAction], "Knapsack");
+                                accuracyFlag[numberGenerators] = 1;
+                                switches[numberGenerators++] = -2;
+                            }
+                            if (redsplitAction && !complicatedInteger) {
+                                babModel_->addCutGenerator(&redsplitGen, translate[redsplitAction], "Reduce-and-split");
+                                accuracyFlag[numberGenerators] = 5;
+				// slow ? - just do a few times
+				if (redsplitAction!=1) {
+				  babModel_->cutGenerator(numberGenerators)->setMaximumTries(maximumSlowPasses);
+				  babModel_->cutGenerator(numberGenerators)->setHowOften(10);
+				}
+				switches[numberGenerators++] = 1;
+                            }
+                            if (redsplit2Action && !complicatedInteger) {
+				int maxLength=256;
+				if (redsplit2Action>2) {
+				  redsplit2Action-=2;
+				  maxLength=COIN_INT_MAX;
+				}
+				CglRedSplit2Param & parameters = redsplit2Gen.getParam();
+				parameters.setMaxNonzeroesTab(maxLength);
+                                babModel_->addCutGenerator(&redsplit2Gen, translate[redsplit2Action], "Reduce-and-split(2)");
+                                accuracyFlag[numberGenerators] = 5;
+				// slow ? - just do a few times
+				if (redsplit2Action!=1) {
+				  babModel_->cutGenerator(numberGenerators)->setHowOften(maximumSlowPasses);
+				  babModel_->cutGenerator(numberGenerators)->setMaximumTries(maximumSlowPasses);
+				  babModel_->cutGenerator(numberGenerators)->setHowOften(5);
+				}
+				
+				switches[numberGenerators++] = 1;
+                            }
+                            if (GMIAction && !complicatedInteger) {
+			        if (GMIAction>5) {
+				  // long
+				  GMIAction-=5;
+				  CglGMIParam & parameters = GMIGen.getParam();
+				  parameters.setMaxSupportRel(1.0);
+				}
+                                babModel_->addCutGenerator(&GMIGen, translate[GMIAction], "Gomory(2)");
+			        if (GMIAction==5) {
+				  // just at end and root
+				  GMIAction=2;
+				  doAtEnd[numberGenerators]=1;
+				  babModel_->cutGenerator(numberGenerators)->setMaximumTries(99999999);
+				  babModel_->cutGenerator(numberGenerators)->setHowOften(1);
+				}
+                                accuracyFlag[numberGenerators] = 5;
+				switches[numberGenerators++] = 0;
+                            }
+                            if (cliqueAction) {
+                                babModel_->addCutGenerator(&cliqueGen, translate[cliqueAction], "Clique");
+                                accuracyFlag[numberGenerators] = 0;
+                                switches[numberGenerators++] = 0;
+                            }
+                            if (mixedAction) {
+                                babModel_->addCutGenerator(&mixedGen, translate[mixedAction], "MixedIntegerRounding2");
+                                accuracyFlag[numberGenerators] = 2;
+                                switches[numberGenerators++] = 0;
+                            }
+                            if (flowAction) {
+                                babModel_->addCutGenerator(&flowGen, translate[flowAction], "FlowCover");
+                                accuracyFlag[numberGenerators] = 2;
+                                switches[numberGenerators++] = 1;
+                            }
+                            if (twomirAction && (complicatedInteger != 1 ||
+                                                 (twomirAction == 1 || twomirAction >= 4))) {
+                                // try larger limit
+                                int numberColumns = babModel_->getNumCols();
+                                if (twomirAction == 7) {
+                                    twomirAction = 4;
+                                    twomirGen.setMaxElements(numberColumns);
+                                } else if (numberColumns > 5000 && twomirAction == 4) {
+                                    twomirGen.setMaxElements(2000);
+                                }
+                                int laTwomir = parameters_[whichParam(CBC_PARAM_STR_LATWOMIRCUTS, numberParameters_, parameters_)].currentOptionAsInteger();
+				int twomirType = translate[twomirAction];
+				if (!laTwomir) {
+				  // Normal
+				  babModel_->addCutGenerator(&twomirGen, translate[twomirAction], "TwoMirCuts");
+				  accuracyFlag[numberGenerators] = 4;
+				  switches[numberGenerators++] = 1;
+				} else {
+				  laTwomir--;
+				  int type = (laTwomir % 3)+1;
+				  int when = laTwomir/3;
+				  char atEnd = (when<2) ? 1 : 0;
+				  int twomirTypeMajor = 10;
+				  if (when<3) {
+				    // normal as well
+				    babModel_->addCutGenerator(&twomirGen, translate[twomirAction], "TwoMirCuts");
+				    accuracyFlag[numberGenerators] = 4;
+				    switches[numberGenerators++] = 1;
+				    if (when==2)
+				      twomirTypeMajor=10;
+				  } else {
+				    when--; // so on
+				    twomirTypeMajor=20;
+				  }
+				  if (!when)
+				    twomirType=-99; // root
+				  twomirGen.passInOriginalSolver(babModel_->solver());
+				  if ((type&1) !=0) {
+				    // clean
+				    twomirGen.setTwomirType(twomirTypeMajor+1);
+				    babModel_->addCutGenerator(&twomirGen, twomirType, "TwoMirCutsL1");
+				    accuracyFlag[numberGenerators] = 4;
+				    doAtEnd[numberGenerators]=atEnd;
+				    switches[numberGenerators++] = atEnd ? 0 : 1;
+				  }
+				  if ((type&2) !=0) {
+				    // simple
+				    twomirGen.setTwomirType(twomirTypeMajor+2);
+				    babModel_->addCutGenerator(&twomirGen, twomirType, "TwoMirCutsL2");
+				    accuracyFlag[numberGenerators] = 4;
+				    doAtEnd[numberGenerators]=atEnd;
+				    switches[numberGenerators++] = atEnd ? 0 : 1;
+				  }
+				}
+                            }
+#ifndef DEBUG_MALLOC
+                            if (landpAction) {
+                                babModel_->addCutGenerator(&landpGen, translate[landpAction], "LiftAndProject");
+                                accuracyFlag[numberGenerators] = 5;
+				// slow ? - just do a few times
+				if (landpAction!=1) {
+				  babModel_->cutGenerator(numberGenerators)->setMaximumTries(maximumSlowPasses);
+				  babModel_->cutGenerator(numberGenerators)->setHowOften(10);
+				}
+                                switches[numberGenerators++] = 1;
+                            }
+#endif
+                            if (residualCapacityAction) {
+                                babModel_->addCutGenerator(&residualCapacityGen, translate[residualCapacityAction], "ResidualCapacity");
+                                accuracyFlag[numberGenerators] = 5;
+                                switches[numberGenerators++] = 1;
+                            }
+                            if (zerohalfAction) {
+                                if (zerohalfAction > 4) {
+                                    //zerohalfAction -=4;
+                                    zerohalfGen.setFlags(1);
+                                }
+                                babModel_->addCutGenerator(&zerohalfGen, translate[zerohalfAction], "ZeroHalf");
+                                accuracyFlag[numberGenerators] = 5;
+                                switches[numberGenerators++] = 2;
+                            }
+                            if (dominatedCuts)
+                                babModel_->setSpecialOptions(babModel_->specialOptions() | 64);
+                            // Say we want timings
+                            numberGenerators = babModel_->numberCutGenerators();
+                            int iGenerator;
+                            int cutDepth =
+                                parameters_[whichParam(CBC_PARAM_INT_CUTDEPTH, numberParameters_, parameters_)].intValue();
+                            for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+                                CbcCutGenerator * generator = babModel_->cutGenerator(iGenerator);
+                                int howOften = generator->howOften();
+                                if (howOften == -98 || howOften == -99 || generator->maximumTries()>0)
+                                    generator->setSwitchOffIfLessThan(switches[iGenerator]);
+                                // Use if any at root as more likely later and fairly cheap
+                                //if (switches[iGenerator]==-2)
+                                //generator->setWhetherToUse(true);
+                                generator->setInaccuracy(accuracyFlag[iGenerator]);
+                                if (doAtEnd[iGenerator]) {
+                                    generator->setWhetherCallAtEnd(true);
+                                    //generator->setMustCallAgain(true);
+                                }
+                                generator->setTiming(true);
+                                if (cutDepth >= 0)
+                                    generator->setWhatDepth(cutDepth) ;
+                            }
+                            // Could tune more
+                            if (!miplib) {
+                                double minimumDrop =
+                                    fabs(babModel_->solver()->getObjValue()) * 1.0e-5 + 1.0e-5;
+                                babModel_->setMinimumDrop(CoinMin(5.0e-2, minimumDrop));
+                                if (cutPass == -1234567) {
+                                    if (babModel_->getNumCols() < 500)
+                                        babModel_->setMaximumCutPassesAtRoot(-100); // always do 100 if possible
+                                    else if (babModel_->getNumCols() < 5000)
+                                        babModel_->setMaximumCutPassesAtRoot(100); // use minimum drop
+                                    else
+                                        babModel_->setMaximumCutPassesAtRoot(20);
+                                } else {
+                                    babModel_->setMaximumCutPassesAtRoot(cutPass);
+                                }
+                                if (cutPassInTree == -1234567)
+                                    babModel_->setMaximumCutPasses(4);
+                                else
+                                    babModel_->setMaximumCutPasses(cutPassInTree);
+                            } else if (cutPass != -1234567) {
+                                babModel_->setMaximumCutPassesAtRoot(cutPass);
+                            }
+                            // Do more strong branching if small
+                            //if (babModel_->getNumCols()<5000)
+                            //babModel_->setNumberStrong(20);
+                            // Switch off strong branching if wanted
+                            //if (babModel_->getNumCols()>10*babModel_->getNumRows())
+                            //babModel_->setNumberStrong(0);
+                            if (!noPrinting_) {
+                                int iLevel = parameters_[log].intValue();
+                                if (iLevel < 0) {
+                                    if (iLevel > -10) {
+                                        babModel_->setPrintingMode(1);
+                                    } else {
+                                        babModel_->setPrintingMode(2);
+                                        iLevel += 10;
+                                        parameters_[log].setIntValue(iLevel);
+                                    }
+                                    iLevel = -iLevel;
+                                }
+                                babModel_->messageHandler()->setLogLevel(iLevel);
+                                if (babModel_->getNumCols() > 2000 || babModel_->getNumRows() > 1500 ||
+                                        babModel_->messageHandler()->logLevel() > 1)
+                                    babModel_->setPrintFrequency(100);
+                            }
+
+                            babModel_->solver()->setIntParam(OsiMaxNumIterationHotStart,
+                                                             parameters_[whichParam(CBC_PARAM_INT_MAXHOTITS, numberParameters_, parameters_)].intValue());
+#ifndef CBC_OTHER_SOLVER
+                            OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                            // go faster stripes
+                            if ((osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500)) {
+                                osiclp->setupForRepeatedUse(2, parameters_[slog].intValue());
+                                if (bothFlags >= 1) {
+                                    ClpSimplex * lp = osiclp->getModelPtr();
+                                    int specialOptions = lp->specialOptions();
+                                    lp->setSpecialOptions(specialOptions | (2048 + 4096));
+                                }
+                            } else {
+                                osiclp->setupForRepeatedUse(0, parameters_[slog].intValue());
+                            }
+                            if (bothFlags >= 2) {
+                                ClpSimplex * lp = osiclp->getModelPtr();
+                                int specialOptions = lp->specialOptions();
+                                lp->setSpecialOptions(specialOptions | (2048 + 4096));
+                            }
+                            double increment = babModel_->getCutoffIncrement();;
+                            int * changed = NULL;
+                            if (!miplib && increment == normalIncrement)
+                                changed = analyze( osiclp, numberChanged, increment, false, generalMessageHandler, noPrinting);
+#elif CBC_OTHER_SOLVER==1
+                            double increment = babModel_->getCutoffIncrement();;
+#endif
+                            if (debugValues) {
+                                int numberColumns = babModel_->solver()->getNumCols();
+                                if (numberDebugValues == numberColumns) {
+                                    // for debug
+                                    babModel_->solver()->activateRowCutDebugger(debugValues) ;
+                                } else {
+                                    int numberOriginalColumns =
+                                        process.originalModel()->getNumCols();
+                                    if (numberDebugValues <= numberOriginalColumns) {
+                                        const int * originalColumns = process.originalColumns();
+                                        double * newValues = new double [numberColumns];
+                                        // in case preprocess added columns!
+                                        // need to find values
+                                        OsiSolverInterface * siCopy =
+                                            babModel_->solver()->clone();
+                                        for (int i = 0; i < numberColumns; i++) {
+                                            int jColumn = originalColumns[i];
+                                            if (jColumn < numberDebugValues &&
+                                                    siCopy->isInteger(i)) {
+                                                // integer variable
+                                                double soln = floor(debugValues[jColumn] + 0.5);
+                                                // Set bounds to fix variable to its solution
+                                                siCopy->setColUpper(i, soln);
+                                                siCopy->setColLower(i, soln);
+                                            }
+                                        }
+                                        // All integers have been fixed at optimal value.
+                                        // Now solve to get continuous values
+                                        siCopy->setHintParam(OsiDoScale, false);
+                                        siCopy->initialSolve();
+                                        if (siCopy->isProvenOptimal()) {
+                                            memcpy(newValues, siCopy->getColSolution(),
+                                                   numberColumns*sizeof(double));
+                                        } else {
+                                            printf("BAD debug file\n");
+                                            siCopy->writeMps("Bad");
+                                            exit(22);
+                                        }
+                                        delete siCopy;
+                                        // for debug
+                                        babModel_->solver()->activateRowCutDebugger(newValues) ;
+                                        delete [] newValues;
+                                    } else {
+                                        printf("debug file has incorrect number of columns\n");
+                                    }
+                                }
+                            }
+                            babModel_->setCutoffIncrement(CoinMax(babModel_->getCutoffIncrement(), increment));
+                            // Turn this off if you get problems
+                            // Used to be automatically set
+                            int mipOptions = parameters_[whichParam(CBC_PARAM_INT_MIPOPTIONS, numberParameters_, parameters_)].intValue() % 10000;
+                            if (mipOptions != (1057)) {
+                                sprintf(generalPrint, "mip options %d", mipOptions);
+                                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                << generalPrint
+                                << CoinMessageEol;
+                            }
+#ifndef CBC_OTHER_SOLVER
+                            osiclp->setSpecialOptions(mipOptions);
+#elif CBC_OTHER_SOLVER==1
+#endif
+                            // probably faster to use a basis to get integer solutions
+                            babModel_->setSpecialOptions(babModel_->specialOptions() | 2);
+                            currentBranchModel = babModel_;
+                            //OsiSolverInterface * strengthenedModel=NULL;
+                            if (type == CBC_PARAM_ACTION_BAB ||
+                                    type == CBC_PARAM_ACTION_MIPLIB) {
+                                if (strategyFlag == 1) {
+                                    // try reduced model
+                                    babModel_->setSpecialOptions(babModel_->specialOptions() | 512);
+                                }
+                                if (experimentFlag >= 5 || strategyFlag == 2) {
+                                    // try reduced model at root
+                                    babModel_->setSpecialOptions(babModel_->specialOptions() | 32768);
+                                }
+                                {
+                                    int depthMiniBab = parameters_[whichParam(CBC_PARAM_INT_DEPTHMINIBAB, numberParameters_, parameters_)].intValue();
+                                    if (depthMiniBab != -1)
+                                        babModel_->setFastNodeDepth(depthMiniBab);
+                                }
+                                int extra4 = parameters_[whichParam(CBC_PARAM_INT_EXTRA4, numberParameters_, parameters_)].intValue();
+                                if (extra4 >= 0) {
+                                    int strategy = extra4 % 10;
+                                    extra4 /= 10;
+                                    int method = extra4 % 100;
+                                    extra4 /= 100;
+                                    extra4 = strategy + method * 8 + extra4 * 1024;
+                                    babModel_->setMoreSpecialOptions(extra4);
+                                }
+                                int moreMipOptions = parameters_[whichParam(CBC_PARAM_INT_MOREMIPOPTIONS, numberParameters_, parameters_)].intValue();
+                                if (moreMipOptions >= 0) {
+                                    sprintf(generalPrint, "more mip options %d", moreMipOptions);
+                                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                    << generalPrint
+                                    << CoinMessageEol;
+#if 1
+				    // some options may have been set already
+				    // e.g. use elapsed time
+                                    babModel_->setMoreSpecialOptions(moreMipOptions|babModel_->moreSpecialOptions());
+#else
+                                    OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                                    if (moreMipOptions == 10000) {
+                                        // test memory saving
+                                        moreMipOptions -= 10000;
+                                        ClpSimplex * lpSolver = osiclp->getModelPtr();
+                                        lpSolver->setPersistenceFlag(1);
+                                        // switch off row copy if few rows
+                                        if (lpSolver->numberRows() < 150)
+                                            lpSolver->setSpecialOptions(lpSolver->specialOptions() | 256);
+                                    }
+                                    if (moreMipOptions < 10000 && moreMipOptions) {
+                                        if (((moreMipOptions + 1) % 1000000) != 0)
+                                            babModel_->setSearchStrategy(moreMipOptions % 1000000);
+                                    } else if (moreMipOptions < 100000) {
+                                        // try reduced model
+                                        babModel_->setSpecialOptions(babModel_->specialOptions() | 512);
+                                    }
+                                    // go faster stripes
+                                    if ( moreMipOptions >= 999999) {
+                                        if (osiclp) {
+                                            int save = osiclp->specialOptions();
+                                            osiclp->setupForRepeatedUse(2, 0);
+                                            osiclp->setSpecialOptions(save | osiclp->specialOptions());
+                                        }
+                                    }
+#endif
+                                }
+                            }
+                            {
+                                int extra1 = parameters_[whichParam(CBC_PARAM_INT_EXTRA1, numberParameters_, parameters_)].intValue();
+                                if (extra1 != -1) {
+                                    if (extra1 < 0) {
+                                        if (extra1 == -7777)
+                                            extra1 = -1;
+                                        else if (extra1 == -8888)
+                                            extra1 = 1;
+                                        babModel_->setWhenCuts(-extra1);
+                                    } else if (extra1 < 19000) {
+                                        babModel_->setSearchStrategy(extra1);
+                                        printf("XXXXX searchStrategy %d\n", extra1);
+                                    } else {
+                                        int n = extra1 - 20000;
+                                        if (!n)
+                                            n--;
+                                        babModel_->setNumberAnalyzeIterations(n);
+                                        printf("XXXXX analyze %d\n", extra1);
+                                    }
+                                } else if (bothFlags >= 1) {
+                                    babModel_->setWhenCuts(999998);
+                                }
+                            }
+                            if (type == CBC_PARAM_ACTION_BAB) {
+#ifdef COIN_HAS_ASL
+                                if (statusUserFunction_[0]) {
+                                    priorities = info.priorities;
+                                    branchDirection = info.branchDirection;
+                                    pseudoDown = info.pseudoDown;
+                                    pseudoUp = info.pseudoUp;
+                                    solutionIn = info.primalSolution;
+                                    prioritiesIn = info.priorities;
+                                    if (info.numberSos && doSOS) {
+                                        // SOS
+                                        numberSOS = info.numberSos;
+                                        sosStart = info.sosStart;
+                                        sosIndices = info.sosIndices;
+                                        sosType = info.sosType;
+                                        sosReference = info.sosReference;
+                                        sosPriority = info.sosPriority;
+                                    }
+                                }
+#endif
+                                const int * originalColumns = preProcess ? process.originalColumns() : NULL;
+                                if (mipStart.size())
+                                {
+                                   std::vector< std::string > colNames;
+                                   if (preProcess)
+                                   {
+				     for ( int i=0 ; (i<babModel_->solver()->getNumCols()) ; ++i ) {
+				       int iColumn = babModel_->originalColumns()[i];
+				       if (iColumn>=0) {
+                                         colNames.push_back( model_.solver()->getColName( iColumn ) );
+				       } else {
+					 // created variable
+					 char newName[15];
+					 sprintf(newName,"C%7.7d",i);
+                                         colNames.push_back( newName );
+				       }
+				     }
+				   } else {
+                                      for ( int i=0 ; (i<babModel_->solver()->getNumCols()) ; ++i )
+                                         colNames.push_back( model_.solver()->getColName(i) );
+				   }
+				   //printf("--- %s %d\n", babModel_->solver()->getColName(0).c_str(), babModel_->solver()->getColNames().size() );
+				   //printf("-- SIZES of models %d %d %d\n", model_.getNumCols(),  babModel_->solver()->getNumCols(), babModel_->solver()->getColNames().size() );
+				   std::vector< double > x( babModel_->getNumCols(), 0.0 );
+				   double obj;
+				   int status = computeCompleteSolution( babModel_, colNames, mipStart, &x[0], obj );
+				   if (!status)
+				     babModel_->setBestSolution( &x[0], static_cast<int>(x.size()), obj, false );
+				}
+
+                                if (solutionIn && useSolution >= 0) {
+                                    if (!prioritiesIn) {
+                                        int n;
+                                        if (preProcess) {
+                                            int numberColumns = babModel_->getNumCols();
+                                            // extend arrays in case SOS
+                                            n = originalColumns[numberColumns-1] + 1;
+                                        } else {
+                                            n = babModel_->getNumCols();
+                                        }
+                                        prioritiesIn = reinterpret_cast<int *> (malloc(n * sizeof(int)));
+                                        for (int i = 0; i < n; i++)
+                                            prioritiesIn[i] = 100;
+                                    }
+                                    if (preProcess) {
+                                        int numberColumns = babModel_->getNumCols();
+                                        // extend arrays in case SOS
+                                        int n = originalColumns[numberColumns-1] + 1;
+                                        int nSmaller = CoinMin(n, numberOriginalColumns);
+                                        double * solutionIn2 = new double [n];
+                                        int * prioritiesIn2 = new int[n];
+                                        int i;
+                                        for (i = 0; i < nSmaller; i++) {
+                                            solutionIn2[i] = solutionIn[i];
+                                            prioritiesIn2[i] = prioritiesIn[i];
+                                        }
+                                        for (; i < n; i++) {
+                                            solutionIn2[i] = 0.0;
+                                            prioritiesIn2[i] = 1000000;
+                                        }
+#ifndef NDEBUG
+                                        int iLast = -1;
+#endif
+                                        for (i = 0; i < numberColumns; i++) {
+                                            int iColumn = originalColumns[i];
+#ifndef NDEBUG
+                                            assert (iColumn > iLast);
+                                            iLast = iColumn;
+#endif
+                                            solutionIn2[i] = solutionIn2[iColumn];
+                                            if (prioritiesIn)
+                                                prioritiesIn2[i] = prioritiesIn2[iColumn];
+                                        }
+                                        if (useSolution)
+                                            babModel_->setHotstartSolution(solutionIn2, prioritiesIn2);
+                                        else
+                                            babModel_->setBestSolution(solutionIn2, numberColumns,
+                                                                       COIN_DBL_MAX, true);
+                                        delete [] solutionIn2;
+                                        delete [] prioritiesIn2;
+                                    } else {
+                                        if (useSolution)
+                                            babModel_->setHotstartSolution(solutionIn, prioritiesIn);
+                                        else
+                                            babModel_->setBestSolution(solutionIn, babModel_->getNumCols(),
+                                                                       COIN_DBL_MAX, true);
+                                    }
+                                }
+                                OsiSolverInterface * testOsiSolver = (testOsiOptions >= 0) ? babModel_->solver() : NULL;
+                                if (!testOsiSolver) {
+                                    // *************************************************************
+                                    // CbcObjects
+                                    if (preProcess && (process.numberSOS() || babModel_->numberObjects())) {
+                                        int numberSOS = process.numberSOS();
+                                        int numberIntegers = babModel_->numberIntegers();
+                                        /* model may not have created objects
+                                           If none then create
+                                        */
+                                        if (!numberIntegers || !babModel_->numberObjects()) {
+                                            int type = (pseudoUp) ? 1 : 0;
+                                            babModel_->findIntegers(true, type);
+                                            numberIntegers = babModel_->numberIntegers();
+                                            integersOK = true;
+                                        }
+                                        OsiObject ** oldObjects = babModel_->objects();
+                                        // Do sets and priorities
+                                        OsiObject ** objects = new OsiObject * [numberSOS];
+                                        // set old objects to have low priority
+                                        int numberOldObjects = babModel_->numberObjects();
+                                        int numberColumns = babModel_->getNumCols();
+                                        // backward pointer to new variables
+                                        // extend arrays in case SOS
+                                        assert (originalColumns);
+					int n = CoinMin(truncateColumns,numberColumns);
+                                        n = originalColumns[n-1] + 1;
+                                        n = CoinMax(n, CoinMax(numberColumns, numberOriginalColumns));
+                                        int * newColumn = new int[n];
+                                        int i;
+                                        for (i = 0; i < numberOriginalColumns; i++)
+                                            newColumn[i] = -1;
+                                        for (i = 0; i < CoinMin(truncateColumns,numberColumns); i++)
+                                            newColumn[originalColumns[i]] = i;
+                                        if (!integersOK) {
+                                            // Change column numbers etc
+                                            int n = 0;
+                                            for (int iObj = 0; iObj < numberOldObjects; iObj++) {
+                                                int iColumn = oldObjects[iObj]->columnNumber();
+                                                if (iColumn < 0 || iColumn >= numberOriginalColumns) {
+                                                    oldObjects[n++] = oldObjects[iObj];
+                                                } else {
+                                                    iColumn = newColumn[iColumn];
+                                                    if (iColumn >= 0) {
+                                                        CbcSimpleInteger * obj =
+                                                            dynamic_cast <CbcSimpleInteger *>(oldObjects[iObj]) ;
+                                                        if (obj) {
+                                                            obj->setColumnNumber(iColumn);
+                                                        } else {
+                                                            // only other case allowed is lotsizing
+                                                            CbcLotsize * obj2 =
+                                                                dynamic_cast <CbcLotsize *>(oldObjects[iObj]) ;
+                                                            assert (obj2);
+                                                            obj2->setModelSequence(iColumn);
+                                                        }
+                                                        oldObjects[n++] = oldObjects[iObj];
+                                                    } else {
+                                                        delete oldObjects[iObj];
+                                                    }
+                                                }
+                                            }
+                                            babModel_->setNumberObjects(n);
+                                            numberOldObjects = n;
+                                            babModel_->zapIntegerInformation();
+                                        }
+                                        int nMissing = 0;
+                                        for (int iObj = 0; iObj < numberOldObjects; iObj++) {
+                                            if (process.numberSOS())
+                                                oldObjects[iObj]->setPriority(numberColumns + 1);
+                                            int iColumn = oldObjects[iObj]->columnNumber();
+                                            if (iColumn < 0 || iColumn >= numberOriginalColumns) {
+                                                CbcSOS * obj =
+                                                    dynamic_cast <CbcSOS *>(oldObjects[iObj]) ;
+                                                if (obj) {
+                                                    int n = obj->numberMembers();
+                                                    int * which = obj->mutableMembers();
+                                                    double * weights = obj->mutableWeights();
+                                                    int nn = 0;
+                                                    for (i = 0; i < n; i++) {
+                                                        int iColumn = which[i];
+                                                        int jColumn = newColumn[iColumn];
+                                                        if (jColumn >= 0) {
+                                                            which[nn] = jColumn;
+                                                            weights[nn++] = weights[i];
+                                                        } else {
+                                                            nMissing++;
+                                                        }
+                                                    }
+                                                    obj->setNumberMembers(nn);
+                                                }
+                                                continue;
+                                            }
+                                            if (originalColumns)
+                                                iColumn = originalColumns[iColumn];
+                                            if (branchDirection) {
+                                                CbcSimpleInteger * obj =
+                                                    dynamic_cast <CbcSimpleInteger *>(oldObjects[iObj]) ;
+                                                if (obj) {
+                                                    obj->setPreferredWay(branchDirection[iColumn]);
+                                                } else {
+                                                    CbcObject * obj =
+                                                        dynamic_cast <CbcObject *>(oldObjects[iObj]) ;
+                                                    assert (obj);
+                                                    obj->setPreferredWay(branchDirection[iColumn]);
+                                                }
+                                            }
+                                            if (pseudoUp) {
+                                                CbcSimpleIntegerPseudoCost * obj1a =
+                                                    dynamic_cast <CbcSimpleIntegerPseudoCost *>(oldObjects[iObj]) ;
+                                                assert (obj1a);
+                                                if (pseudoDown[iColumn] > 0.0)
+                                                    obj1a->setDownPseudoCost(pseudoDown[iColumn]);
+                                                if (pseudoUp[iColumn] > 0.0)
+                                                    obj1a->setUpPseudoCost(pseudoUp[iColumn]);
+                                            }
+                                        }
+                                        if (nMissing) {
+                                            sprintf(generalPrint, "%d SOS variables vanished due to pre processing? - check validity?", nMissing);
+                                            generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                            << generalPrint
+                                            << CoinMessageEol;
+                                        }
+                                        delete [] newColumn;
+                                        const int * starts = process.startSOS();
+                                        const int * which = process.whichSOS();
+                                        const int * type = process.typeSOS();
+                                        const double * weight = process.weightSOS();
+                                        int iSOS;
+                                        for (iSOS = 0; iSOS < numberSOS; iSOS++) {
+                                            int iStart = starts[iSOS];
+                                            int n = starts[iSOS+1] - iStart;
+                                            objects[iSOS] = new CbcSOS(babModel_, n, which + iStart, weight + iStart,
+                                                                       iSOS, type[iSOS]);
+                                            // branch on long sets first
+                                            objects[iSOS]->setPriority(numberColumns - n);
+                                        }
+                                        if (numberSOS)
+                                            babModel_->addObjects(numberSOS, objects);
+                                        for (iSOS = 0; iSOS < numberSOS; iSOS++)
+                                            delete objects[iSOS];
+                                        delete [] objects;
+                                    } else if (priorities || branchDirection || pseudoDown || pseudoUp || numberSOS) {
+                                        // do anyway for priorities etc
+                                        int numberIntegers = babModel_->numberIntegers();
+                                        /* model may not have created objects
+                                           If none then create
+                                        */
+                                        if (!numberIntegers || !babModel_->numberObjects()) {
+                                            int type = (pseudoUp) ? 1 : 0;
+                                            babModel_->findIntegers(true, type);
+                                        }
+                                        if (numberSOS) {
+                                            // Do sets and priorities
+                                            OsiObject ** objects = new OsiObject * [numberSOS];
+                                            int iSOS;
+                                            if (originalColumns) {
+                                                // redo sequence numbers
+                                                int numberColumns = babModel_->getNumCols();
+                                                int nOld = originalColumns[numberColumns-1] + 1;
+                                                int * back = new int[nOld];
+                                                int i;
+                                                for (i = 0; i < nOld; i++)
+                                                    back[i] = -1;
+                                                for (i = 0; i < numberColumns; i++)
+                                                    back[originalColumns[i]] = i;
+                                                // Really need better checks
+                                                int nMissing = 0;
+                                                int n = sosStart[numberSOS];
+                                                for (i = 0; i < n; i++) {
+                                                    int iColumn = sosIndices[i];
+                                                    int jColumn = back[iColumn];
+                                                    if (jColumn >= 0)
+                                                        sosIndices[i] = jColumn;
+                                                    else
+                                                        nMissing++;
+                                                }
+                                                delete [] back;
+                                                if (nMissing) {
+                                                    sprintf(generalPrint, "%d SOS variables vanished due to pre processing? - check validity?", nMissing);
+                                                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                                    << generalPrint
+                                                    << CoinMessageEol;
+                                                }
+                                            }
+                                            for (iSOS = 0; iSOS < numberSOS; iSOS++) {
+                                                int iStart = sosStart[iSOS];
+                                                int n = sosStart[iSOS+1] - iStart;
+                                                objects[iSOS] = new CbcSOS(babModel_, n, sosIndices + iStart, sosReference + iStart,
+                                                                           iSOS, sosType[iSOS]);
+                                                if (sosPriority)
+                                                    objects[iSOS]->setPriority(sosPriority[iSOS]);
+                                                else if (!prioritiesIn)
+                                                    objects[iSOS]->setPriority(10);  // rather than 1000
+                                            }
+                                            // delete any existing SOS objects
+                                            int numberObjects = babModel_->numberObjects();
+                                            OsiObject ** oldObjects = babModel_->objects();
+                                            int nNew = 0;
+                                            for (int i = 0; i < numberObjects; i++) {
+                                                OsiObject * objThis = oldObjects[i];
+                                                CbcSOS * obj1 =
+                                                    dynamic_cast <CbcSOS *>(objThis) ;
+                                                OsiSOS * obj2 =
+                                                    dynamic_cast <OsiSOS *>(objThis) ;
+                                                if (!obj1 && !obj2) {
+                                                    oldObjects[nNew++] = objThis;
+                                                } else {
+                                                    delete objThis;
+                                                }
+                                            }
+                                            babModel_->setNumberObjects(nNew);
+                                            babModel_->addObjects(numberSOS, objects);
+                                            for (iSOS = 0; iSOS < numberSOS; iSOS++)
+                                                delete objects[iSOS];
+                                            delete [] objects;
+                                        }
+                                    }
+                                    OsiObject ** objects = babModel_->objects();
+                                    int numberObjects = babModel_->numberObjects();
+                                    for (int iObj = 0; iObj < numberObjects; iObj++) {
+                                        // skip sos
+                                        CbcSOS * objSOS =
+                                            dynamic_cast <CbcSOS *>(objects[iObj]) ;
+                                        if (objSOS)
+                                            continue;
+                                        int iColumn = objects[iObj]->columnNumber();
+                                        assert (iColumn >= 0);
+                                        if (originalColumns)
+                                            iColumn = originalColumns[iColumn];
+                                        if (branchDirection) {
+                                            CbcSimpleInteger * obj =
+                                                dynamic_cast <CbcSimpleInteger *>(objects[iObj]) ;
+                                            if (obj) {
+                                                obj->setPreferredWay(branchDirection[iColumn]);
+                                            } else {
+                                                CbcObject * obj =
+                                                    dynamic_cast <CbcObject *>(objects[iObj]) ;
+                                                assert (obj);
+                                                obj->setPreferredWay(branchDirection[iColumn]);
+                                            }
+                                        }
+                                        if (priorities) {
+                                            int iPriority = priorities[iColumn];
+                                            if (iPriority > 0)
+                                                objects[iObj]->setPriority(iPriority);
+                                        }
+                                        if (pseudoUp && pseudoUp[iColumn]) {
+                                            CbcSimpleIntegerPseudoCost * obj1a =
+                                                dynamic_cast <CbcSimpleIntegerPseudoCost *>(objects[iObj]) ;
+                                            assert (obj1a);
+                                            if (pseudoDown[iColumn] > 0.0)
+                                                obj1a->setDownPseudoCost(pseudoDown[iColumn]);
+                                            if (pseudoUp[iColumn] > 0.0)
+                                                obj1a->setUpPseudoCost(pseudoUp[iColumn]);
+                                        }
+                                    }
+                                    // *************************************************************
+                                } else {
+                                    // *************************************************************
+                                    // OsiObjects
+                                    // Find if none
+                                    int numberIntegers = testOsiSolver->getNumIntegers();
+                                    /* model may not have created objects
+                                       If none then create
+                                    */
+                                    if (!numberIntegers || !testOsiSolver->numberObjects()) {
+                                        //int type = (pseudoUp) ? 1 : 0;
+                                        testOsiSolver->findIntegers(false);
+                                        numberIntegers = testOsiSolver->getNumIntegers();
+                                    }
+                                    if (preProcess && process.numberSOS()) {
+                                        int numberSOS = process.numberSOS();
+                                        OsiObject ** oldObjects = testOsiSolver->objects();
+                                        // Do sets and priorities
+                                        OsiObject ** objects = new OsiObject * [numberSOS];
+                                        // set old objects to have low priority
+                                        int numberOldObjects = testOsiSolver->numberObjects();
+                                        int numberColumns = testOsiSolver->getNumCols();
+                                        for (int iObj = 0; iObj < numberOldObjects; iObj++) {
+                                            oldObjects[iObj]->setPriority(numberColumns + 1);
+                                            int iColumn = oldObjects[iObj]->columnNumber();
+                                            assert (iColumn >= 0);
+                                            if (iColumn >= numberOriginalColumns)
+                                                continue;
+                                            if (originalColumns)
+                                                iColumn = originalColumns[iColumn];
+                                            if (branchDirection) {
+                                                OsiSimpleInteger * obj =
+                                                    dynamic_cast <OsiSimpleInteger *>(oldObjects[iObj]) ;
+                                                if (obj) {
+                                                    obj->setPreferredWay(branchDirection[iColumn]);
+                                                } else {
+                                                    OsiObject2 * obj =
+                                                        dynamic_cast <OsiObject2 *>(oldObjects[iObj]) ;
+                                                    if (obj)
+                                                        obj->setPreferredWay(branchDirection[iColumn]);
+                                                }
+                                            }
+                                            if (pseudoUp) {
+                                                abort();
+                                            }
+                                        }
+                                        const int * starts = process.startSOS();
+                                        const int * which = process.whichSOS();
+                                        const int * type = process.typeSOS();
+                                        const double * weight = process.weightSOS();
+                                        int iSOS;
+                                        for (iSOS = 0; iSOS < numberSOS; iSOS++) {
+                                            int iStart = starts[iSOS];
+                                            int n = starts[iSOS+1] - iStart;
+                                            objects[iSOS] = new OsiSOS(testOsiSolver, n, which + iStart, weight + iStart,
+                                                                       type[iSOS]);
+                                            // branch on long sets first
+                                            objects[iSOS]->setPriority(numberColumns - n);
+                                        }
+                                        testOsiSolver->addObjects(numberSOS, objects);
+                                        for (iSOS = 0; iSOS < numberSOS; iSOS++)
+                                            delete objects[iSOS];
+                                        delete [] objects;
+                                    } else if (priorities || branchDirection || pseudoDown || pseudoUp || numberSOS) {
+                                        if (numberSOS) {
+                                            // Do sets and priorities
+                                            OsiObject ** objects = new OsiObject * [numberSOS];
+                                            int iSOS;
+                                            if (originalColumns) {
+                                                // redo sequence numbers
+                                                int numberColumns = testOsiSolver->getNumCols();
+                                                int nOld = originalColumns[numberColumns-1] + 1;
+                                                int * back = new int[nOld];
+                                                int i;
+                                                for (i = 0; i < nOld; i++)
+                                                    back[i] = -1;
+                                                for (i = 0; i < numberColumns; i++)
+                                                    back[originalColumns[i]] = i;
+                                                // Really need better checks
+                                                int nMissing = 0;
+                                                int n = sosStart[numberSOS];
+                                                for (i = 0; i < n; i++) {
+                                                    int iColumn = sosIndices[i];
+                                                    int jColumn = back[iColumn];
+                                                    if (jColumn >= 0)
+                                                        sosIndices[i] = jColumn;
+                                                    else
+                                                        nMissing++;
+                                                }
+                                                delete [] back;
+                                                if (nMissing) {
+                                                    sprintf(generalPrint, "%d SOS variables vanished due to pre processing? - check validity?", nMissing);
+                                                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                                    << generalPrint
+                                                    << CoinMessageEol;
+                                                }
+                                            }
+                                            for (iSOS = 0; iSOS < numberSOS; iSOS++) {
+                                                int iStart = sosStart[iSOS];
+                                                int n = sosStart[iSOS+1] - iStart;
+                                                objects[iSOS] = new OsiSOS(testOsiSolver, n, sosIndices + iStart, sosReference + iStart,
+                                                                           sosType[iSOS]);
+                                                if (sosPriority)
+                                                    objects[iSOS]->setPriority(sosPriority[iSOS]);
+                                                else if (!prioritiesIn)
+                                                    objects[iSOS]->setPriority(10);  // rather than 1000
+                                            }
+                                            // delete any existing SOS objects
+                                            int numberObjects = testOsiSolver->numberObjects();
+                                            OsiObject ** oldObjects = testOsiSolver->objects();
+                                            int nNew = 0;
+                                            for (int i = 0; i < numberObjects; i++) {
+                                                OsiObject * objThis = oldObjects[i];
+                                                OsiSOS * obj1 =
+                                                    dynamic_cast <OsiSOS *>(objThis) ;
+                                                OsiSOS * obj2 =
+                                                    dynamic_cast <OsiSOS *>(objThis) ;
+                                                if (!obj1 && !obj2) {
+                                                    oldObjects[nNew++] = objThis;
+                                                } else {
+                                                    delete objThis;
+                                                }
+                                            }
+                                            testOsiSolver->setNumberObjects(nNew);
+                                            testOsiSolver->addObjects(numberSOS, objects);
+                                            for (iSOS = 0; iSOS < numberSOS; iSOS++)
+                                                delete objects[iSOS];
+                                            delete [] objects;
+                                        }
+                                    }
+                                    OsiObject ** objects = testOsiSolver->objects();
+                                    int numberObjects = testOsiSolver->numberObjects();
+                                    int logLevel = parameters_[log].intValue();
+                                    for (int iObj = 0; iObj < numberObjects; iObj++) {
+                                        // skip sos
+                                        OsiSOS * objSOS =
+                                            dynamic_cast <OsiSOS *>(objects[iObj]) ;
+                                        if (objSOS) {
+                                            if (logLevel > 2)
+                                                printf("Set %d is SOS - priority %d\n", iObj, objSOS->priority());
+                                            continue;
+                                        }
+                                        int iColumn = objects[iObj]->columnNumber();
+                                        if (iColumn >= 0) {
+                                            if (originalColumns)
+                                                iColumn = originalColumns[iColumn];
+                                            if (branchDirection) {
+                                                OsiSimpleInteger * obj =
+                                                    dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ;
+                                                if (obj) {
+                                                    obj->setPreferredWay(branchDirection[iColumn]);
+                                                } else {
+                                                    OsiObject2 * obj =
+                                                        dynamic_cast <OsiObject2 *>(objects[iObj]) ;
+                                                    if (obj)
+                                                        obj->setPreferredWay(branchDirection[iColumn]);
+                                                }
+                                            }
+                                            if (priorities) {
+                                                int iPriority = priorities[iColumn];
+                                                if (iPriority > 0)
+                                                    objects[iObj]->setPriority(iPriority);
+                                            }
+                                            if (logLevel > 2)
+                                                printf("Obj %d is int? - priority %d\n", iObj, objects[iObj]->priority());
+                                            if (pseudoUp && pseudoUp[iColumn]) {
+                                                abort();
+                                            }
+                                        }
+                                    }
+                                    // *************************************************************
+                                }
+                                int statistics = (printOptions > 0) ? printOptions : 0;
+#ifdef COIN_HAS_ASL
+                                if (!statusUserFunction_[0]) {
+#endif
+                                    free(priorities);
+                                    priorities = NULL;
+                                    free(branchDirection);
+                                    branchDirection = NULL;
+                                    free(pseudoDown);
+                                    pseudoDown = NULL;
+                                    free(pseudoUp);
+                                    pseudoUp = NULL;
+                                    free(solutionIn);
+                                    solutionIn = NULL;
+                                    free(prioritiesIn);
+                                    prioritiesIn = NULL;
+                                    free(sosStart);
+                                    sosStart = NULL;
+                                    free(sosIndices);
+                                    sosIndices = NULL;
+                                    free(sosType);
+                                    sosType = NULL;
+                                    free(sosReference);
+                                    sosReference = NULL;
+                                    free(cut);
+                                    cut = NULL;
+                                    free(sosPriority);
+                                    sosPriority = NULL;
+#ifdef COIN_HAS_ASL
+                                }
+#endif
+                                if (nodeStrategy) {
+                                    // change default
+                                    if (nodeStrategy > 2) {
+                                        // up or down
+                                        int way = (((nodeStrategy - 1) % 1) == 1) ? -1 : +1;
+                                        babModel_->setPreferredWay(way);
+#ifdef JJF_ZERO
+                                        OsiObject ** objects = babModel_->objects();
+                                        int numberObjects = babModel_->numberObjects();
+                                        for (int iObj = 0; iObj < numberObjects; iObj++) {
+                                            CbcObject * obj =
+                                                dynamic_cast <CbcObject *>(objects[iObj]) ;
+                                            assert (obj);
+                                            obj->setPreferredWay(way);
+                                        }
+#endif
+                                    }
+                                    if (nodeStrategy == 2 || nodeStrategy > 4) {
+                                        // depth
+                                        CbcCompareDefault compare;
+                                        compare.setWeight(-3.0);
+                                        babModel_->setNodeComparison(compare);
+                                    } else if (nodeStrategy == 0) {
+                                        // hybrid was default i.e. mixture of low depth and infeasibility
+                                    } else if (nodeStrategy == 1) {
+                                        // real fewest
+                                        CbcCompareDefault compare;
+                                        compare.setWeight(-2.0);
+                                        babModel_->setNodeComparison(compare);
+                                    }
+                                }
+                                if (cppValue >= 0) {
+                                    int prepro = useStrategy ? -1 : preProcess;
+                                    // generate code
+                                    FILE * fp = fopen("user_driver.cpp", "w");
+                                    if (fp) {
+                                        // generate enough to do BAB
+                                        babModel_->generateCpp(fp, 1);
+                                        OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                                        // Make general so do factorization
+                                        int factor = osiclp->getModelPtr()->factorizationFrequency();
+                                        osiclp->getModelPtr()->setFactorizationFrequency(200);
+                                        osiclp->generateCpp(fp);
+                                        osiclp->getModelPtr()->setFactorizationFrequency(factor);
+                                        //solveOptions.generateCpp(fp);
+                                        fclose(fp);
+                                        // now call generate code
+                                        generateCode(babModel_, "user_driver.cpp", cppValue, prepro);
+                                    } else {
+                                        std::cout << "Unable to open file user_driver.cpp" << std::endl;
+                                    }
+                                }
+                                if (!babModel_->numberStrong() && babModel_->numberBeforeTrust() > 0)
+                                    babModel_->setNumberBeforeTrust(0);
+                                if (useStrategy) {
+                                    CbcStrategyDefault strategy(1, babModel_->numberStrong(), babModel_->numberBeforeTrust());
+                                    strategy.setupPreProcessing(1);
+                                    babModel_->setStrategy(strategy);
+                                }
+                                if (testOsiOptions >= 0) {
+                                    sprintf(generalPrint, "Testing OsiObject options %d", testOsiOptions);
+                                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                    << generalPrint
+                                    << CoinMessageEol;
+                                    if (!numberSOS) {
+                                        babModel_->solver()->findIntegersAndSOS(false);
+#ifdef COIN_HAS_LINK
+                                        // If linked then pass in model
+                                        OsiSolverLink * solver3 = dynamic_cast<OsiSolverLink *> (babModel_->solver());
+                                        if (solver3) {
+                                            CbcHeuristicDynamic3 serendipity(*babModel_);
+                                            serendipity.setHeuristicName("linked");
+                                            babModel_->addHeuristic(&serendipity);
+                                            double dextra3 = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA3, numberParameters_, parameters_)].doubleValue();
+                                            if (dextra3)
+                                                solver3->setMeshSizes(dextra3);
+                                            int options = parameters_[whichParam(CBC_PARAM_INT_MIPOPTIONS, numberParameters_, parameters_)].intValue() / 10000;
+                                            CglStored stored;
+                                            if (options) {
+                                                printf("nlp options %d\n", options);
+                                                /*
+                                                  1 - force mini branch and bound
+                                                  2 - set priorities high on continuous
+                                                  4 - try adding OA cuts
+                                                  8 - try doing quadratic linearization
+                                                  16 - try expanding knapsacks
+                                                              32 - OA cuts strictly concave
+                                                  64 - no branching at all on bilinear x-x!
+                                                */
+                                                if ((options&2)) {
+                                                    solver3->setBiLinearPriorities(10, tightenFactor > 0.0 ? tightenFactor : 1.0);
+                                                } else if (tightenFactor > 0.0) {
+                                                    // set grid size for all continuous bi-linear
+                                                    solver3->setMeshSizes(tightenFactor);
+                                                }
+                                                if ((options&4)) {
+                                                    solver3->setSpecialOptions2(solver3->specialOptions2() | (8 + 4));
+                                                    // say convex
+                                                    solver3->sayConvex((options&32) == 0);
+                                                }
+                                                int extra1 = parameters_[whichParam(CBC_PARAM_INT_EXTRA1, numberParameters_, parameters_)].intValue();
+                                                if ((options&1) != 0 && extra1 > 0)
+                                                    solver3->setFixedPriority(extra1);
+                                                double cutoff = COIN_DBL_MAX;
+                                                if ((options&8))
+                                                    cutoff = solver3->linearizedBAB(&stored);
+                                                if (cutoff < babModel_->getCutoff()) {
+                                                    babModel_->setCutoff(cutoff);
+                                                    // and solution
+                                                    //babModel_->setBestObjectiveValue(solver3->bestObjectiveValue());
+                                                    babModel_->setBestSolution(solver3->bestSolution(), solver3->getNumCols(),
+                                                                               solver3->bestObjectiveValue());
+                                                }
+                                                if ((options&64))
+                                                    solver3->setBranchingStrategyOnVariables(16, -1, 4);
+                                            }
+                                            solver3->setCbcModel(babModel_);
+                                            if (stored.sizeRowCuts())
+                                                babModel_->addCutGenerator(&stored, 1, "Stored");
+                                            CglTemporary temp;
+                                            babModel_->addCutGenerator(&temp, 1, "OnceOnly");
+                                            //choose.setNumberBeforeTrusted(2000);
+                                            //choose.setNumberStrong(20);
+                                        }
+                                        // For temporary testing of heuristics
+                                        //int testOsiOptions = parameters_[whichParam(CBC_PARAM_INT_TESTOSI,numberParameters_,parameters_)].intValue();
+                                        if (testOsiOptions >= 10) {
+                                            if (testOsiOptions >= 20)
+                                                testOsiOptions -= 10;
+                                            printf("*** Temp heuristic with mode %d\n", testOsiOptions - 10);
+                                            OsiSolverLink * solver3 = dynamic_cast<OsiSolverLink *> (babModel_->solver());
+                                            assert (solver3) ;
+                                            int extra1 = parameters_[whichParam(CBC_PARAM_INT_EXTRA1, numberParameters_, parameters_)].intValue();
+                                            solver3->setBiLinearPriority(extra1);
+                                            printf("bilinear priority now %d\n", extra1);
+                                            int extra2 = parameters_[whichParam(CBC_PARAM_INT_EXTRA2, numberParameters_, parameters_)].intValue();
+                                            double saveDefault = solver3->defaultBound();
+                                            solver3->setDefaultBound(static_cast<double> (extra2));
+                                            double * solution = solver3->heuristicSolution(slpValue > 0 ? slpValue : 40 , 1.0e-5, testOsiOptions - 10);
+                                            solver3->setDefaultBound(saveDefault);
+                                            if (!solution)
+                                                printf("Heuristic failed\n");
+                                        }
+#endif
+                                    } else {
+                                        // move across
+                                        babModel_->deleteObjects(false);
+                                        //babModel_->addObjects(babModel_->solver()->numberObjects(),babModel_->solver()->objects());
+                                    }
+                                    CbcBranchDefaultDecision decision;
+                                    if (babModel_->numberStrong()) {
+                                        OsiChooseStrong choose(babModel_->solver());
+                                        choose.setNumberBeforeTrusted(babModel_->numberBeforeTrust());
+                                        choose.setNumberStrong(babModel_->numberStrong());
+                                        choose.setShadowPriceMode(testOsiOptions);
+                                        decision.setChooseMethod(choose);
+                                    } else {
+                                        OsiChooseVariable choose(babModel_->solver());
+                                        decision.setChooseMethod(choose);
+                                    }
+                                    babModel_->setBranchingMethod(decision);
+                                    if (useCosts && testOsiOptions >= 0) {
+				      if(newPriorities ) {
+					// get rid of
+					delete [] newPriorities;
+					newPriorities = NULL;
+				      }
+                                        int numberColumns = babModel_->getNumCols();
+                                        int * sort = new int[numberColumns];
+                                        double * dsort = new double[numberColumns];
+                                        int * priority = new int [numberColumns];
+                                        const double * objective = babModel_->getObjCoefficients();
+                                        const double * lower = babModel_->getColLower() ;
+                                        const double * upper = babModel_->getColUpper() ;
+                                        const CoinPackedMatrix * matrix = babModel_->solver()->getMatrixByCol();
+                                        const int * columnLength = matrix->getVectorLengths();
+                                        int iColumn;
+                                        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                            sort[iColumn] = iColumn;
+                                            if (useCosts == 1)
+                                                dsort[iColumn] = -fabs(objective[iColumn]);
+                                            else if (useCosts == 2)
+                                                dsort[iColumn] = iColumn;
+                                            else if (useCosts == 3)
+                                                dsort[iColumn] = upper[iColumn] - lower[iColumn];
+                                            else if (useCosts == 4)
+                                                dsort[iColumn] = -(upper[iColumn] - lower[iColumn]);
+                                            else if (useCosts == 5)
+                                                dsort[iColumn] = -columnLength[iColumn];
+                                        }
+                                        CoinSort_2(dsort, dsort + numberColumns, sort);
+                                        int level = 0;
+                                        double last = -1.0e100;
+                                        for (int i = 0; i < numberColumns; i++) {
+                                            int iPut = sort[i];
+                                            if (dsort[i] != last) {
+                                                level++;
+                                                last = dsort[i];
+                                            }
+                                            priority[iPut] = level;
+                                        }
+                                        OsiObject ** objects = babModel_->objects();
+                                        int numberObjects = babModel_->numberObjects();
+                                        for (int iObj = 0; iObj < numberObjects; iObj++) {
+                                            OsiObject * obj = objects[iObj] ;
+                                            int iColumn = obj->columnNumber();
+                                            if (iColumn >= 0)
+                                                obj->setPriority(priority[iColumn]);
+                                        }
+                                        delete [] priority;
+                                        delete [] sort;
+                                        delete [] dsort;
+                                    }
+                                }
+                                checkSOS(babModel_, babModel_->solver());
+                                if (doSprint > 0) {
+                                    // Sprint for primal solves
+                                    ClpSolve::SolveType method = ClpSolve::usePrimalorSprint;
+                                    ClpSolve::PresolveType presolveType = ClpSolve::presolveOff;
+                                    int numberPasses = 5;
+                                    int options[] = {0, 3, 0, 0, 0, 0};
+                                    int extraInfo[] = { -1, 20, -1, -1, -1, -1};
+                                    extraInfo[1] = doSprint;
+                                    int independentOptions[] = {0, 0, 3};
+                                    ClpSolve clpSolve(method, presolveType, numberPasses,
+                                                      options, extraInfo, independentOptions);
+                                    // say use in OsiClp
+                                    clpSolve.setSpecialOption(6, 1);
+                                    OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                                    osiclp->setSolveOptions(clpSolve);
+                                    osiclp->setHintParam(OsiDoDualInResolve, false);
+                                    // switch off row copy
+                                    osiclp->getModelPtr()->setSpecialOptions(osiclp->getModelPtr()->specialOptions() | 256);
+                                    osiclp->getModelPtr()->setInfeasibilityCost(1.0e11);
+                                }
+#ifdef COIN_HAS_LINK
+                                if (storedAmpl.sizeRowCuts()) {
+                                    if (preProcess) {
+                                        const int * originalColumns = process.originalColumns();
+                                        int numberColumns = babModel_->getNumCols();
+                                        int * newColumn = new int[numberOriginalColumns];
+                                        int i;
+                                        for (i = 0; i < numberOriginalColumns; i++)
+                                            newColumn[i] = -1;
+                                        for (i = 0; i < numberColumns; i++) {
+                                            int iColumn = originalColumns[i];
+                                            newColumn[iColumn] = i;
+                                        }
+                                        int * buildColumn = new int[numberColumns];
+                                        // Build up valid cuts
+                                        int nBad = 0;
+                                        int nCuts = storedAmpl.sizeRowCuts();
+                                        CglStored newCuts;
+                                        for (i = 0; i < nCuts; i++) {
+                                            const OsiRowCut * cut = storedAmpl.rowCutPointer(i);
+                                            double lb = cut->lb();
+                                            double ub = cut->ub();
+                                            int n = cut->row().getNumElements();
+                                            const int * column = cut->row().getIndices();
+                                            const double * element = cut->row().getElements();
+                                            bool bad = false;
+                                            for (int i = 0; i < n; i++) {
+                                                int iColumn = column[i];
+                                                iColumn = newColumn[iColumn];
+                                                if (iColumn >= 0) {
+                                                    buildColumn[i] = iColumn;
+                                                } else {
+                                                    bad = true;
+                                                    break;
+                                                }
+                                            }
+                                            if (!bad) {
+                                                newCuts.addCut(lb, ub, n, buildColumn, element);
+                                            } else {
+                                                nBad++;
+                                            }
+                                        }
+                                        storedAmpl = newCuts;
+                                        if (nBad)
+                                            printf("%d cuts dropped\n", nBad);
+                                        delete [] newColumn;
+                                        delete [] buildColumn;
+                                    }
+                                }
+#endif
+#ifdef CLP_MALLOC_STATISTICS
+                                malloc_stats();
+                                malloc_stats2();
+#endif
+#ifndef CBC_OTHER_SOLVER
+                                if (outputFormat == 5) {
+                                    osiclp = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                                    lpSolver = osiclp->getModelPtr();
+                                    lpSolver->setPersistenceFlag(1);
+                                }
+#endif
+#ifdef COIN_HAS_ASL
+                                // add in lotsizing
+                                if (statusUserFunction_[0] && info.special) {
+                                    int numberColumns = babModel_->getNumCols();
+                                    int i;
+                                    int n = 0;
+                                    if (preProcess) {
+                                        const int * originalColumns = process.originalColumns();
+                                        for (i = 0; i < numberColumns; i++) {
+                                            int iColumn = originalColumns[i];
+                                            assert (iColumn >= i);
+                                            int iType = info.special[iColumn];
+                                            if (iType) {
+                                                assert (iType == 1);
+                                                n++;
+                                            }
+                                            info.special[i] = iType;
+                                        }
+                                    }
+                                    if (n) {
+                                        int numberIntegers = 0;
+                                        int numberOldObjects = 0;
+                                        OsiObject ** oldObjects = NULL;
+                                        const double * lower = babModel_->solver()->getColLower();
+                                        const double * upper = babModel_->solver()->getColUpper();
+                                        if (testOsiOptions < 0) {
+                                            // *************************************************************
+                                            // CbcObjects
+                                            numberIntegers = babModel_->numberIntegers();
+                                            /* model may not have created objects
+                                            If none then create
+                                            */
+                                            if (!numberIntegers || !babModel_->numberObjects()) {
+                                                int type = (pseudoUp) ? 1 : 0;
+                                                babModel_->findIntegers(true, type);
+                                                numberIntegers = babModel_->numberIntegers();
+                                            }
+                                            oldObjects = babModel_->objects();
+                                            numberOldObjects = babModel_->numberObjects();
+                                        } else {
+                                            numberIntegers = testOsiSolver->getNumIntegers();
+                                            if (!numberIntegers || !testOsiSolver->numberObjects()) {
+                                                /* model may not have created objects
+                                                   If none then create
+                                                */
+                                                testOsiSolver->findIntegers(false);
+                                                numberIntegers = testOsiSolver->getNumIntegers();
+                                            }
+                                            oldObjects = testOsiSolver->objects();
+                                            numberOldObjects = testOsiSolver->numberObjects();
+                                        }
+                                        OsiObject ** objects = new OsiObject * [n];
+                                        n = 0;
+                                        // set new objects to have one lower priority
+                                        double ranges[] = { -COIN_DBL_MAX, -1.0, 1.0, COIN_DBL_MAX};
+                                        for (int iObj = 0; iObj < numberOldObjects; iObj++) {
+                                            int iColumn = oldObjects[iObj]->columnNumber();
+                                            if (iColumn >= 0 && info.special[iColumn]) {
+                                                if (lower[iColumn] <= -1.0 && upper[iColumn] >= 0.0) {
+                                                    ranges[0] = lower[iColumn];
+                                                    ranges[3] = upper[iColumn];
+                                                    int priority = oldObjects[iObj]->priority();
+                                                    if (testOsiOptions < 0) {
+                                                        objects[n] = new CbcLotsize(babModel_, iColumn, 2, ranges, true);
+                                                    } else {
+                                                        objects[n] = new OsiLotsize(testOsiSolver, iColumn, 2, ranges, true);
+                                                    }
+                                                    objects[n++]->setPriority (priority - 1);
+                                                }
+                                            }
+                                        }
+                                        if (testOsiOptions < 0) {
+                                            babModel_->addObjects(n, objects);
+                                        } else {
+                                            testOsiSolver->addObjects(n, objects);
+                                        }
+                                        for (i = 0; i < n; i++)
+                                            delete objects[i];
+                                        delete [] objects;
+                                    }
+                                }
+#endif
+                                if (storedAmpl.sizeRowCuts()) {
+                                    //babModel_->addCutGenerator(&storedAmpl,1,"AmplStored");
+                                    int numberRowCuts = storedAmpl.sizeRowCuts();
+                                    for (int i = 0; i < numberRowCuts; i++) {
+                                        const OsiRowCut * rowCutPointer = storedAmpl.rowCutPointer(i);
+                                        babModel_->makeGlobalCut(rowCutPointer);
+                                    }
+                                }
+                                // If defaults then increase trust for small models
+                                if (!strongChanged) {
+                                    int numberColumns = babModel_->getNumCols();
+                                    if (numberColumns <= 50)
+                                        babModel_->setNumberBeforeTrust(1000);
+                                    else if (numberColumns <= 100)
+                                        babModel_->setNumberBeforeTrust(100);
+                                    else if (numberColumns <= 300)
+                                        babModel_->setNumberBeforeTrust(50);
+                                }
+#ifdef CBC_THREAD
+                                int numberThreads = parameters_[whichParam(CBC_PARAM_INT_THREADS, numberParameters_, parameters_)].intValue();
+                                babModel_->setNumberThreads(numberThreads % 100);
+                                babModel_->setThreadMode(numberThreads / 100);
+#endif
+                                int returnCode = callBack(babModel_, 3);
+                                if (returnCode) {
+                                    // exit if user wants
+                                    delete babModel_;
+                                    babModel_ = NULL;
+                                    return returnCode;
+                                }
+#ifndef CBC_OTHER_SOLVER
+                                osiclp = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                                lpSolver = osiclp->getModelPtr();
+#elif CBC_OTHER_SOLVER==1
+#endif
+                                if ((experimentFlag >= 1 || strategyFlag >= 1) && babModel_->fastNodeDepth() == -1) {
+                                    if (babModel_->solver()->getNumCols() +
+                                            babModel_->solver()->getNumRows() < 500)
+                                        babModel_->setFastNodeDepth(-12);
+                                } else if (babModel_->fastNodeDepth() == -999) {
+                                    babModel_->setFastNodeDepth(-1);
+                                }
+                                int heurOptions = parameters_[whichParam(CBC_PARAM_INT_HOPTIONS, numberParameters_, parameters_)].intValue();
+                                if (heurOptions > 100)
+                                    babModel_->setSpecialOptions(babModel_->specialOptions() | 8192);
+
+#ifndef CBC_OTHER_SOLVER
+#ifdef CLP_MULTIPLE_FACTORIZATIONS
+                                int denseCode = parameters_[whichParam(CBC_PARAM_INT_DENSE, numberParameters_, parameters_)].intValue();
+                                int smallCode = parameters_[whichParam(CBC_PARAM_INT_SMALLFACT, numberParameters_, parameters_)].intValue();
+                                if (bothFlags >= 1) {
+                                    if (denseCode < 0)
+                                        denseCode = 40;
+                                    if (smallCode < 0 && !lpSolver->factorization()->isDenseOrSmall())
+                                        smallCode = 40;
+                                }
+                                if (denseCode > 0) {
+                                    lpSolver->factorization()->setGoDenseThreshold(denseCode);
+                                    assert (osiclp == babModel_->solver());
+                                    osiclp->setSpecialOptions(osiclp->specialOptions() | 1024);
+                                }
+                                if (smallCode > 0 && smallCode > denseCode)
+                                    lpSolver->factorization()->setGoSmallThreshold(smallCode);
+                                //if (denseCode>=lpSolver->numberRows()) {
+                                //lpSolver->factorization()->goDense();
+                                //}
+                                if (lpSolver->factorization()->goOslThreshold() > 1000) {
+                                    // use osl in gomory (may not if CglGomory decides not to)
+                                    int numberGenerators = babModel_->numberCutGenerators();
+				    int nGomory=0;
+                                    for (int iGenerator = 0; iGenerator < numberGenerators;
+                                            iGenerator++) {
+                                        CbcCutGenerator * generator = babModel_->cutGenerator(iGenerator);
+                                        CglGomory * gomory = dynamic_cast<CglGomory *>
+                                                             (generator->generator());
+                                        if (gomory) {
+					  if (nGomory<2) {
+                                            gomory->useAlternativeFactorization();
+					  } else if (gomory->originalSolver()) {
+					    OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *>(gomory->originalSolver());
+					    if (clpSolver) {
+					      ClpSimplex * simplex = clpSolver->getModelPtr();
+					      simplex->factorization()->setGoOslThreshold(0);
+					    }
+					  }
+					    nGomory++;
+					}
+                                    }
+                                }
+#endif
+#endif
+#ifdef CLIQUE_ANALYSIS
+                                if (!storedAmpl.sizeRowCuts()) {
+                                    printf("looking at probing\n");
+                                    babModel_->addCutGenerator(&storedAmpl, 1, "Stored");
+                                }
+#endif
+                                if (useSolution > 1) {
+                                    // use hotstart to try and find solution
+                                    CbcHeuristicPartial partial(*babModel_, 10000, useSolution);
+                                    partial.setHeuristicName("Partial solution given");
+                                    babModel_->addHeuristic(&partial);
+                                }
+                                if (logLevel <= 1)
+                                    babModel_->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+#ifdef CBC_TEMP1
+                                if (osiclp->getModelPtr()->perturbation() == 50)
+                                    osiclp->getModelPtr()->setPerturbation(52); // try less
+#endif
+#ifdef JJF_ZERO
+                                if (osiclp->getNumCols() == 29404) {
+                                    void restoreSolution(ClpSimplex * lpSolver,
+                                                         std::string fileName, int mode);
+                                    restoreSolution(osiclp->getModelPtr(), "debug.file", 0);
+                                    int numberColumns = osiclp->getNumCols();
+                                    const double * solution = osiclp->getColSolution();
+                                    const int * originalColumns = process.originalColumns();
+                                    for (int i = 0; i < numberColumns; i++) {
+                                        int iColumn = originalColumns[i];
+                                        if (saveSolver->isInteger(iColumn)) {
+                                            double value = solution[i];
+                                            double value2 = floor(value + 0.5);
+                                            assert (fabs(value - value2) < 1.0e-3);
+                                            saveSolver->setColLower(iColumn, value2);
+                                            saveSolver->setColUpper(iColumn, value2);
+                                        }
+                                    }
+                                    saveSolver->writeMps("fixed");
+                                    babModel_->setBestSolution(osiclp->getColSolution(),
+                                                               osiclp->getNumCols(),
+                                                               1.5325e10);
+                                } else {
+                                    babModel_->branchAndBound(statistics);
+                                }
+#else
+#ifdef ORBITAL
+                                CbcOrbital orbit(babModel_);
+                                orbit.morph();
+                                exit(1);
+#endif
+                                int hOp1 = parameters_[whichParam(CBC_PARAM_INT_HOPTIONS, numberParameters_, parameters_)].intValue() / 100000;
+                                if (hOp1 % 10) {
+                                    CbcCompareDefault compare;
+                                    compare.setBreadthDepth(hOp1 % 10);
+                                    babModel_->setNodeComparison(compare);
+                                }
+#if CBC_OTHER_SOLVER==1
+                                if (dynamic_cast<OsiCpxSolverInterface *> (babModel_->solver()))
+                                    babModel_->solver()->messageHandler()->setLogLevel(0);
+#endif
+                                if (parameters_[whichParam(CBC_PARAM_STR_CPX, numberParameters_, parameters_)].currentOptionAsInteger()) {
+                                    babModel_->setSpecialOptions(babModel_->specialOptions() | 16384);
+                                    //if (babModel_->fastNodeDepth()==-1)
+                                    babModel_->setFastNodeDepth(-2); // Use Cplex at root
+                                }
+                                int hOp2 = parameters_[whichParam(CBC_PARAM_INT_HOPTIONS, numberParameters_, parameters_)].intValue() / 10000;
+                                if (hOp2 % 10) {
+                                    babModel_->setSpecialOptions(babModel_->specialOptions() | 16384);
+                                    if (babModel_->fastNodeDepth() == -1)
+                                        babModel_->setFastNodeDepth(-2); // Use Cplex at root
+                                }
+                                if (experimentFlag >= 5) {
+                                    CbcModel donor(*babModel_);
+                                    int options = babModel_->specialOptions();
+                                    donor.setSpecialOptions(options | 262144);
+                                    ClpSimplex * lpSolver2;
+                                    OsiClpSolverInterface * clpSolver2;
+                                    clpSolver2 =
+                                        dynamic_cast<OsiClpSolverInterface *> (donor.solver());
+                                    assert (clpSolver2);
+                                    lpSolver2 = clpSolver2->getModelPtr();
+                                    assert (lpSolver2);
+                                    if (lpSolver->factorization()->isDenseOrSmall()) {
+                                        lpSolver2->factorization()->forceOtherFactorization(0);
+                                        lpSolver2->factorization()->setGoOslThreshold(0);
+                                        lpSolver2->factorization()->setGoDenseThreshold(0);
+                                        lpSolver2->factorization()->setGoSmallThreshold(0);
+                                        lpSolver2->allSlackBasis();
+                                        lpSolver2->initialSolve();
+                                        int numberGenerators = donor.numberCutGenerators();
+                                        for (int iGenerator = 0; iGenerator < numberGenerators;
+                                                iGenerator++) {
+                                            CbcCutGenerator * generator = donor.cutGenerator(iGenerator);
+                                            CglGomory * gomory = dynamic_cast<CglGomory *>
+                                                                 (generator->generator());
+                                            if (gomory)
+                                                gomory->useAlternativeFactorization(false);
+                                        }
+                                    } else {
+                                        printf("code this\n");
+                                        abort();
+                                    }
+                                    babModel_->setSpecialOptions(options | 524288);
+                                    CglStored * stored = new CglStored(donor.getNumCols());
+                                    donor.setStoredRowCuts(stored);
+                                    donor.branchAndBound(0);
+                                    babModel_->setStoredRowCuts(donor.storedRowCuts());
+                                    donor.setStoredRowCuts(NULL);
+                                }
+				// We may have priorities from extra variables
+				if(newPriorities ) {
+				  if (truncateColumns<babModel_->getNumCols()) {
+				    // set new ones as high prority
+				    babModel_->passInPriorities(newPriorities,false);
+				  }
+				  delete [] newPriorities;
+				}
+#ifdef JJF_ZERO
+                                int extra5 = parameters_[whichParam(EXTRA5, numberParameters_, parameters_)].intValue();
+                                if (extra5 > 0) {
+                                    int numberGenerators = babModel_->numberCutGenerators();
+                                    for (int iGenerator = 0; iGenerator < numberGenerators;
+                                            iGenerator++) {
+                                        CbcCutGenerator * generator = babModel_->cutGenerator(iGenerator);
+                                        CglGomory * gomory = dynamic_cast<CglGomory *>
+                                                             (generator->generator());
+                                        if (gomory) {
+                                            CglGomory gomory2(*gomory);
+                                            gomory2.useAlternativeFactorization(!gomory->alternativeFactorization());
+                                            babModel_->addCutGenerator(&gomory2, -99, "Gomory2");
+                                        }
+                                    }
+                                }
+#endif
+                                int specialOptions = parameters_[whichParam(CBC_PARAM_INT_STRONG_STRATEGY, numberParameters_, parameters_)].intValue();
+				if (specialOptions>=0)
+				  babModel_->setStrongStrategy(specialOptions);
+				int jParam = whichParam(CBC_PARAM_STR_CUTOFF_CONSTRAINT, 
+							numberParameters_, parameters_);
+				if(parameters_[jParam].currentOptionAsInteger())
+				  babModel_->setCutoffAsConstraint(true);
+                                int multipleRoot = parameters_[whichParam(CBC_PARAM_INT_MULTIPLEROOTS, numberParameters_, parameters_)].intValue();
+				if (multipleRoot<10000) {
+				  babModel_->setMultipleRootTries(multipleRoot);
+				} else {
+				  // will be doing repeated solves and saves
+				  int numberGoes=multipleRoot/10000;
+				  multipleRoot-=10000*numberGoes;
+				  int moreOptions=babModel_->moreSpecialOptions();
+				  if (numberGoes<100) {
+				    remove("global.cuts");
+				    remove("global.fix");
+				    moreOptions |= (67108864|134217728);
+				  } else {
+				    moreOptions |= 67108864*(numberGoes/100);
+				    numberGoes=numberGoes%100;
+				  }
+				  babModel_->setMultipleRootTries(multipleRoot);
+				  babModel_->setMoreSpecialOptions(moreOptions);
+				  int numberColumns=babModel_->getNumCols();
+				  double * bestValues=new double [numberGoes];
+				  double ** bestSolutions=new double * [numberGoes];
+				  int * which=new int[numberGoes];
+				  int numberSolutions=0;
+				  sprintf(generalPrint,"Starting %d passes each with %d solvers",
+					  numberGoes, multipleRoot%10);
+				  generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				    << generalPrint
+				    << CoinMessageEol;
+				  for (int iGo=0;iGo<numberGoes;iGo++) {
+				    sprintf(generalPrint,"Starting pass %d",iGo+1);
+				    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				      << generalPrint
+				      << CoinMessageEol;
+				    CbcModel tempModel=*babModel_;
+				    tempModel.setMaximumNodes(0);
+				    // switch off cuts if none generated
+				    int numberGenerators = tempModel.numberCutGenerators();
+				    for (int iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+				      CbcCutGenerator * generator = tempModel.cutGenerator(iGenerator);
+				      generator->setSwitchOffIfLessThan(1);
+				    }
+				    // random
+				    tempModel.setRandomSeed(tempModel.getRandomSeed()+100000000*(iGo+1+5*numberGoes));
+				    for (int i=0;i<tempModel.numberHeuristics();i++)
+				      tempModel.heuristic(i)->setSeed(tempModel.heuristic(i)->getSeed()+100000000*iGo);
+#ifndef CBC_OTHER_SOLVER
+				    OsiClpSolverInterface * solver = dynamic_cast<OsiClpSolverInterface *> (tempModel.solver());
+				    ClpSimplex * simplex = solver->getModelPtr();
+				    int solverSeed=simplex->randomNumberGenerator()->getSeed();
+				    simplex->setRandomSeed(solverSeed+100000000*(iGo+1));
+#endif
+				    tempModel.branchAndBound();
+				    if (tempModel.bestSolution()) {
+				      bestSolutions[numberSolutions]=
+					CoinCopyOfArray(tempModel.bestSolution(),
+							numberColumns);
+				      bestValues[numberSolutions]=-tempModel.getMinimizationObjValue();
+				      which[numberSolutions]=numberSolutions;
+				      numberSolutions++;
+				    }
+				  }
+				  // allow solutions
+				  double sense = babModel_->solver()->getObjSense();;
+				  CoinSort_2(bestValues,bestValues+numberSolutions,which);
+				  babModel_->setMoreSpecialOptions(moreOptions&(~16777216));
+				  for (int i=0;i<numberSolutions;i++) {
+				    int k=which[i];
+				    if (bestValues[i]<babModel_->getCutoff()) {
+				      babModel_->setBestSolution(bestSolutions[k],numberColumns,
+								 -bestValues[i]*sense,true);
+				      babModel_->incrementUsed(bestSolutions[k]);
+				    }
+				    delete [] bestSolutions[k];
+				  }
+				  babModel_->setMoreSpecialOptions(moreOptions);
+				  if (numberSolutions)
+				    sprintf(generalPrint,"Ending major passes - best solution %g",-bestValues[numberSolutions-1]);
+				  else
+				    sprintf(generalPrint,"Ending major passes - no solution found");
+				    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				      << generalPrint
+				      << CoinMessageEol;
+				  delete [] which;
+				  delete [] bestValues;
+				  delete [] bestSolutions;
+				}
+				if (biLinearProblem)
+				  babModel_->setSpecialOptions(babModel_->specialOptions() &(~(512|32768)));
+                                babModel_->branchAndBound(statistics);
+				if (truncateColumns<babModel_->solver()->getNumCols()) {
+				  OsiSolverInterface * solverX = babModel_->solver();
+				  int numberColumns=solverX->getNumCols();
+				  int numberRows=solverX->getNumRows();
+				  int numberDelete = numberColumns-truncateColumns;
+				  int * delStuff=new int [numberDelete];
+				  for (int i=0;i<numberDelete;i++)
+				    delStuff[i]=i+truncateColumns;
+				  solverX->deleteCols(numberDelete,delStuff);
+				  for (int i=0;i<numberDelete;i++)
+				    delStuff[i]=i+numberRows-numberDelete;
+				  solverX->deleteRows(numberDelete,delStuff);
+				  delete [] delStuff;
+				}
+                                //#define CLP_FACTORIZATION_INSTRUMENT
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+                                extern double factorization_instrument(int type);
+                                double facTime = factorization_instrument(0);
+                                printf("Factorization %g seconds\n",
+                                       facTime);
+#endif
+#endif
+#ifdef COIN_DEVELOP
+#ifndef JJF_ONE
+                                {
+                                    int numberColumns = babModel_->getNumCols();
+                                    const double * solution = babModel_->bestSolution();
+                                    if (solution && numberColumns < 1000) {
+                                        for (int i = 0; i < numberColumns; i++) {
+                                            if (solution[i])
+                                                printf("SOL %d %.18g\n", i, solution[i]);
+                                        }
+                                    }
+                                }
+#endif
+                                void printHistory(const char * file/*,CbcModel * model*/);
+                                printHistory("branch.log"/*,babModel_*/);
+#endif
+                                returnCode = callBack(babModel_, 4);
+                                if (returnCode) {
+                                    // exit if user wants
+                                    model_.moveInfo(*babModel_);
+                                    delete babModel_;
+                                    babModel_ = NULL;
+                                    return returnCode;
+				} else {
+				  int numberSolutions = babModel_->numberSavedSolutions();
+				  if (numberSolutions>1) {
+				    for (int iSolution=numberSolutions-1;iSolution>=0;iSolution--) {
+				      model_.setBestSolution(babModel_->savedSolution(iSolution),
+							     model_.solver()->getNumCols(),
+							     babModel_->savedSolutionObjective(iSolution));
+				    }
+				  }
+                                }
+#ifdef CLP_MALLOC_STATISTICS
+                                malloc_stats();
+                                malloc_stats2();
+#endif
+                                checkSOS(babModel_, babModel_->solver());
+                            } else if (type == CBC_PARAM_ACTION_MIPLIB) {
+                                int typeOfCuts = babModel_->numberCutGenerators() ? 1 : -1;
+                                CbcStrategyDefault strategy(typeOfCuts,
+                                                            babModel_->numberStrong(),
+                                                            babModel_->numberBeforeTrust());
+                                // Set up pre-processing
+                                int translate2[] = {9999, 1, 1, 3, 2, 4, 5, 6, 6};
+                                if (preProcess)
+                                    strategy.setupPreProcessing(translate2[ preProcess ]);
+                                babModel_->setStrategy(strategy);
+#ifdef CBC_THREAD
+                                int numberThreads = parameters_[whichParam(CBC_PARAM_INT_THREADS, numberParameters_, parameters_)].intValue();
+                                babModel_->setNumberThreads(numberThreads % 100);
+                                babModel_->setThreadMode(numberThreads / 100);
+#endif
+#ifndef CBC_OTHER_SOLVER
+                                if (outputFormat == 5) {
+                                    osiclp = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                                    lpSolver = osiclp->getModelPtr();
+                                    lpSolver->setPersistenceFlag(1);
+                                }
+#endif
+                                if (testOsiOptions >= 0) {
+                                    printf("Testing OsiObject options %d\n", testOsiOptions);
+                                    CbcBranchDefaultDecision decision;
+                                    OsiChooseStrong choose(babModel_->solver());
+                                    choose.setNumberBeforeTrusted(babModel_->numberBeforeTrust());
+                                    choose.setNumberStrong(babModel_->numberStrong());
+                                    choose.setShadowPriceMode(testOsiOptions);
+                                    //babModel_->deleteObjects(false);
+                                    decision.setChooseMethod(choose);
+                                    babModel_->setBranchingMethod(decision);
+                                }
+                                model_ = *babModel_;
+#ifndef CBC_OTHER_SOLVER
+                                {
+                                    osiclp = dynamic_cast< OsiClpSolverInterface*> (model_.solver());
+                                    lpSolver = osiclp->getModelPtr();
+                                    lpSolver->setSpecialOptions(lpSolver->specialOptions() | IN_BRANCH_AND_BOUND); // say is Cbc (and in branch and bound)
+                                    if (lpSolver->factorization()->goOslThreshold() > 1000) {
+                                        // use osl in gomory (may not if CglGomory decides not to)
+                                        int numberGenerators = model_.numberCutGenerators();
+                                        for (int iGenerator = 0; iGenerator < numberGenerators;
+                                                iGenerator++) {
+                                            CbcCutGenerator * generator = model_.cutGenerator(iGenerator);
+                                            CglGomory * gomory = dynamic_cast<CglGomory *>
+                                                                 (generator->generator());
+                                            if (gomory)
+                                                gomory->useAlternativeFactorization();
+                                        }
+                                    }
+                                }
+#endif
+                                /* LL: this was done in CoinSolve.cpp: main(argc, argv).
+                                   I have moved it here so that the miplib directory location
+                                   could be passed to CbcClpUnitTest. */
+                                /* JJF: No need to have 777 flag at all - user
+                                   says -miplib
+                                */
+                                int extra2 = parameters_[whichParam(CBC_PARAM_INT_EXTRA2, numberParameters_, parameters_)].intValue();
+                                double stuff[11];
+                                stuff[0] = parameters_[whichParam(CBC_PARAM_DBL_FAKEINCREMENT, numberParameters_, parameters_)].doubleValue();
+                                stuff[1] = parameters_[whichParam(CBC_PARAM_DBL_FAKECUTOFF, numberParameters_, parameters_)].doubleValue();
+                                stuff[2] = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA3, numberParameters_, parameters_)].doubleValue();
+                                stuff[3] = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA4, numberParameters_, parameters_)].doubleValue();
+                                stuff[4] = parameters_[whichParam(CBC_PARAM_INT_DENSE, numberParameters_, parameters_)].intValue();
+                                stuff[5] = parameters_[whichParam(CBC_PARAM_INT_EXTRA1, numberParameters_, parameters_)].intValue();
+                                stuff[6] = parameters_[whichParam(CBC_PARAM_INT_EXTRA3, numberParameters_, parameters_)].intValue();
+                                stuff[7] = parameters_[whichParam(CBC_PARAM_INT_DEPTHMINIBAB, numberParameters_, parameters_)].intValue();
+                                stuff[8] = bothFlags;
+                                stuff[9] = doVector;
+                                stuff[10] = parameters_[whichParam(CBC_PARAM_INT_SMALLFACT, numberParameters_, parameters_)].intValue();
+                                if ( dominatedCuts)
+                                    model_.setSpecialOptions(model_.specialOptions() | 64);
+                                if (parameters_[whichParam(CBC_PARAM_STR_CPX, numberParameters_, parameters_)].currentOptionAsInteger()) {
+                                    model_.setSpecialOptions(model_.specialOptions() | 16384);
+                                    //if (model_.fastNodeDepth()==-1)
+                                    model_.setFastNodeDepth(-2); // Use Cplex at root
+                                }
+                                int hOp2 = parameters_[whichParam(CBC_PARAM_INT_HOPTIONS, numberParameters_, parameters_)].intValue() / 10000;
+                                if (hOp2 % 10) {
+                                    model_.setSpecialOptions(model_.specialOptions() | 16384);
+                                    if (model_.fastNodeDepth() == -1)
+                                        model_.setFastNodeDepth(-2); // Use Cplex at root
+                                }
+                                int multipleRoot = parameters_[whichParam(CBC_PARAM_INT_MULTIPLEROOTS, numberParameters_, parameters_)].intValue();
+				model_.setMultipleRootTries(multipleRoot);
+                                int specialOptions = parameters_[whichParam(CBC_PARAM_INT_STRONG_STRATEGY, numberParameters_, parameters_)].intValue();
+				if (specialOptions>=0)
+				  model_.setStrongStrategy(specialOptions);
+                                if (!pumpChanged) {
+                                    // Make more lightweight
+                                    for (int iHeur = 0; iHeur < model_.numberHeuristics(); iHeur++) {
+                                        CbcHeuristic * heuristic = model_.heuristic(iHeur);
+                                        CbcHeuristicFPump* pump =
+                                            dynamic_cast<CbcHeuristicFPump*>(heuristic);
+                                        if (pump) {
+                                            CbcHeuristicFPump heuristic4(model_);
+                                            heuristic4.setFractionSmall(0.5);
+                                            heuristic4.setMaximumPasses(5);
+                                            heuristic4.setFeasibilityPumpOptions(30);
+                                            heuristic4.setWhen(13);
+                                            heuristic4.setHeuristicName("feasibility pump");
+                                            //CbcHeuristicFPump & pump2 = pump;
+                                            *pump = heuristic4;
+                                        }
+                                    }
+                                }
+                                int returnCode = CbcClpUnitTest(model_, dirMiplib, extra2, stuff);
+                                babModel_ = NULL;
+                                return returnCode;
+                            } else {
+                                abort(); // can't get here
+                                //strengthenedModel = babModel_->strengthenedModel();
+                            }
+                            currentBranchModel = NULL;
+#ifndef CBC_OTHER_SOLVER
+                            osiclp = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+                            if (debugFile == "createAfterPre" && babModel_->bestSolution()) {
+                                lpSolver = osiclp->getModelPtr();
+                                //move best solution (should be there -- but ..)
+                                int n = lpSolver->getNumCols();
+                                memcpy(lpSolver->primalColumnSolution(), babModel_->bestSolution(), n*sizeof(double));
+                                saveSolution(osiclp->getModelPtr(), "debug.file");
+                            }
+#endif
+                            statistics_cut_time = 0.0;
+                            if (!noPrinting_) {
+                                // Print more statistics
+                                sprintf(generalPrint, "Cuts at root node changed objective from %g to %g",
+                                        babModel_->getContinuousObjective(), babModel_->rootObjectiveAfterCuts());
+                                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                << generalPrint
+                                << CoinMessageEol;
+
+                                numberGenerators = babModel_->numberCutGenerators();
+                                statistics_number_cuts = new int [numberGenerators];;
+                                statistics_number_generators = numberGenerators;
+                                statistics_name_generators = new const char *[numberGenerators];
+                                char timing[30];
+                                for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+                                    CbcCutGenerator * generator = babModel_->cutGenerator(iGenerator);
+                                    statistics_name_generators[iGenerator] =
+                                        generator->cutGeneratorName();
+                                    statistics_number_cuts[iGenerator] = generator->numberCutsInTotal();
+                                    sprintf(generalPrint, "%s was tried %d times and created %d cuts of which %d were active after adding rounds of cuts",
+                                            generator->cutGeneratorName(),
+                                            generator->numberTimesEntered(),
+                                            generator->numberCutsInTotal() +
+                                            generator->numberColumnCuts(),
+                                            generator->numberCutsActive());
+                                    if (generator->timing()) {
+                                        sprintf(timing, " (%.3f seconds)", generator->timeInCutGenerator());
+                                        strcat(generalPrint, timing);
+                                        statistics_cut_time += generator->timeInCutGenerator();
+                                    }
+                                    CglStored * stored = dynamic_cast<CglStored*>(generator->generator());
+                                    if (stored && !generator->numberCutsInTotal())
+                                        continue;
+#ifndef CLP_INVESTIGATE
+                                    CglImplication * implication = dynamic_cast<CglImplication*>(generator->generator());
+                                    if (implication)
+                                        continue;
+#endif
+                                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                    << generalPrint
+                                    << CoinMessageEol;
+                                }
+#ifdef COIN_DEVELOP
+                                printf("%d solutions found by heuristics\n",
+                                       babModel_->getNumberHeuristicSolutions());
+                                // Not really generator but I am feeling lazy
+                                for (iGenerator = 0; iGenerator < babModel_->numberHeuristics(); iGenerator++) {
+                                    CbcHeuristic * heuristic = babModel_->heuristic(iGenerator);
+                                    if (heuristic->numRuns()) {
+                                        // Need to bring others inline
+                                        sprintf(generalPrint, "%s was tried %d times out of %d and created %d solutions\n",
+                                                heuristic->heuristicName(),
+                                                heuristic->numRuns(),
+                                                heuristic->numCouldRun(),
+                                                heuristic->numberSolutionsFound());
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << generalPrint
+                                        << CoinMessageEol;
+                                    }
+                                }
+#endif
+                            }
+                            // adjust time to allow for children on some systems
+                            time2 = CoinCpuTime() + CoinCpuTimeJustChildren();
+                            totalTime += time2 - time1;
+                            // For best solution
+                            double * bestSolution = NULL;
+                            // Say in integer
+                            if (babModel_->status()) {
+                                // treat as stopped
+                                integerStatus = 3;
+                            } else {
+                                if (babModel_->isProvenOptimal()) {
+                                    integerStatus = 0;
+                                } else {
+                                    // infeasible
+                                    integerStatus = 6;
+                                }
+                            }
+                            if (babModel_->getMinimizationObjValue() < 1.0e50 && type == CBC_PARAM_ACTION_BAB) {
+                                // post process
+                                int n;
+                                if (preProcess) {
+                                    n = saveSolver->getNumCols();
+                                    bestSolution = new double [n];
+#ifndef CBC_OTHER_SOLVER
+                                    OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+#else
+                                    OsiCpxSolverInterface * clpSolver = dynamic_cast< OsiCpxSolverInterface*> (babModel_->solver());
+#endif
+                                    // Save bounds on processed model
+                                    const int * originalColumns = process.originalColumns();
+                                    int numberColumns2 = clpSolver->getNumCols();
+                                    double * solution2 = new double[n];
+                                    double * lower2 = new double [n];
+                                    double * upper2 = new double [n];
+                                    for (int i = 0; i < n; i++) {
+                                        solution2[i] = COIN_DBL_MAX;
+                                        lower2[i] = COIN_DBL_MAX;
+                                        upper2[i] = -COIN_DBL_MAX;
+                                    }
+                                    const double *columnLower = clpSolver->getColLower() ;
+                                    const double * columnUpper = clpSolver->getColUpper() ;
+                                    const double * solution = babModel_->bestSolution();
+                                    for (int i = 0; i < numberColumns2; i++) {
+                                        int jColumn = originalColumns[i];
+                                        if (jColumn < n) {
+                                            solution2[jColumn] = solution[i];
+                                            lower2[jColumn] = columnLower[i];
+                                            upper2[jColumn] = columnUpper[i];
+                                        }
+                                    }
+#ifndef CBC_OTHER_SOLVER
+                                    ClpSimplex * lpSolver = clpSolver->getModelPtr();
+                                    lpSolver->setSpecialOptions(lpSolver->specialOptions() | IN_BRANCH_AND_BOUND); // say is Cbc (and in branch and bound)
+#endif
+                                    // put back any saved solutions
+                                    putBackOtherSolutions(babModel_,&model_,&process);
+                                    process.postProcess(*babModel_->solver());
+#ifdef COIN_DEVELOP
+                                    if (model_.bestSolution() && fabs(model_.getMinimizationObjValue() -
+                                                                      babModel_->getMinimizationObjValue()) < 1.0e-8) {
+                                        const double * b1 = model_.bestSolution();
+                                        const double * b2 = saveSolver->getColSolution();
+                                        const double * columnLower = saveSolver->getColLower() ;
+                                        const double * columnUpper = saveSolver->getColUpper() ;
+                                        for (int i = 0; i < n; i++) {
+                                            if (fabs(b1[i] - b2[i]) > 1.0e-7) {
+                                                printf("%d %g %g %g %g\n", i, b1[i], b2[i],
+                                                       columnLower[i], columnUpper[i]);
+                                            }
+                                        }
+                                    }
+#endif
+                                    bool tightenB = false;
+                                    {
+                                        int n = babModel_->numberObjects();
+                                        for (int i = 0; i < n; i++) {
+                                            const OsiObject * obj = babModel_->object(i);
+                                            if (!dynamic_cast<const CbcSimpleInteger *>(obj)) {
+                                                tightenB = true;
+                                                break;
+                                            }
+                                        }
+                                    }
+                                    // Solution now back in saveSolver
+                                    // Double check bounds
+                                    columnLower = saveSolver->getColLower() ;
+                                    columnUpper = saveSolver->getColUpper() ;
+                                    solution = saveSolver->getColSolution();
+                                    int numberChanged = 0;
+                                    for (int i = 0; i < n; i++) {
+                                        if (!saveSolver->isInteger(i) && !tightenB)
+                                            continue;
+                                        if (lower2[i] != COIN_DBL_MAX) {
+                                            if (lower2[i] != columnLower[i] ||
+                                                    upper2[i] != columnUpper[i]) {
+                                                if (lower2[i] < columnLower[i] ||
+                                                        upper2[i] > columnUpper[i]) {
+#ifdef COIN_DEVELOP
+                                                    printf("odd bounds tighter");
+                                                    printf("%d bab bounds %g %g now %g %g\n",
+                                                           i, lower2[i], upper2[i], columnLower[i],
+                                                           columnUpper[i]);
+#endif
+                                                } else {
+#ifdef COIN_DEVELOP
+                                                    printf("%d bab bounds %g %g now %g %g\n",
+                                                           i, lower2[i], upper2[i], columnLower[i],
+                                                           columnUpper[i]);
+#endif
+                                                    numberChanged++;
+                                                    saveSolver->setColLower(i, lower2[i]);
+                                                    saveSolver->setColUpper(i, upper2[i]);
+                                                }
+                                            }
+                                        }
+                                    }
+#ifdef JJF_ZERO
+                                    // See if sos so we can fix
+                                    OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (saveSolver);
+                                    if (osiclp && osiclp->numberSOS()) {
+                                        // SOS
+                                        numberSOS = osiclp->numberSOS();
+                                        const CoinSet * setInfo = osiclp->setInfo();
+                                        int i;
+                                        for ( i = 0; i < numberSOS; i++) {
+                                            int type = setInfo[i].setType();
+                                            int n = setInfo[i].numberEntries();
+                                            const int * which = setInfo[i].which();
+                                            int first = -1;
+                                            int last = -1;
+                                            for (int j = 0; j < n; j++) {
+                                                int iColumn = which[j];
+                                                if (fabs(solution[iColumn]) > 1.0e-7) {
+                                                    last = j;
+                                                    if (first < 0)
+                                                        first = j;
+                                                }
+                                            }
+                                            assert (last - first < type);
+                                            for (int j = 0; j < n; j++) {
+                                                if (j < first || j > last) {
+                                                    int iColumn = which[j];
+                                                    saveSolver->setColLower(iColumn, 0.0);
+                                                    saveSolver->setColUpper(iColumn, 0.0);
+                                                }
+                                            }
+                                        }
+                                    }
+#endif
+                                    delete [] solution2;
+                                    delete [] lower2;
+                                    delete [] upper2;
+                                    if (numberChanged) {
+                                        sprintf(generalPrint, "%d bounds tightened after postprocessing\n",
+                                                numberChanged);
+                                        generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                        << generalPrint
+                                        << CoinMessageEol;
+                                    }
+                                    saveSolver->resolve();
+                                    if (!saveSolver->isProvenOptimal()) {
+                                        // try all slack
+                                        CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (babModel_->solver()->getEmptyWarmStart());
+                                        saveSolver->setWarmStart(basis);
+                                        delete basis;
+                                        saveSolver->initialSolve();
+#ifdef COIN_DEVELOP
+                                        saveSolver->writeMps("inf2");
+#endif
+					OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (saveSolver);
+					if (osiclp)
+					  osiclp->getModelPtr()->checkUnscaledSolution();
+                                    }
+                                    assert (saveSolver->isProvenOptimal());
+#ifndef CBC_OTHER_SOLVER
+                                    // and original solver
+                                    originalSolver->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX);
+                                    assert (n >= originalSolver->getNumCols());
+                                    n = originalSolver->getNumCols();
+                                    originalSolver->setColLower(saveSolver->getColLower());
+                                    originalSolver->setColUpper(saveSolver->getColUpper());
+                                    // basis
+                                    CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (babModel_->solver()->getWarmStart());
+                                    originalSolver->setBasis(*basis);
+                                    delete basis;
+                                    originalSolver->resolve();
+                                    if (!originalSolver->isProvenOptimal()) {
+                                        // try all slack
+                                        CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (babModel_->solver()->getEmptyWarmStart());
+                                        originalSolver->setBasis(*basis);
+                                        delete basis;
+                                        originalSolver->initialSolve();
+					OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (originalSolver);
+					if (osiclp)
+					  osiclp->getModelPtr()->checkUnscaledSolution();
+                                    }
+                                    assert (originalSolver->isProvenOptimal());
+#endif
+                                    babModel_->assignSolver(saveSolver);
+                                    memcpy(bestSolution, babModel_->solver()->getColSolution(), n*sizeof(double));
+                                } else {
+                                    n = babModel_->solver()->getNumCols();
+                                    bestSolution = new double [n];
+                                    memcpy(bestSolution, babModel_->solver()->getColSolution(), n*sizeof(double));
+                                }
+                                if (returnMode == 1&&model_.numberSavedSolutions()<2) {
+                                    model_.deleteSolutions();
+                                    model_.setBestSolution(bestSolution, n, babModel_->getMinimizationObjValue());
+                                }
+                                babModel_->deleteSolutions();
+                                babModel_->setBestSolution(bestSolution, n, babModel_->getMinimizationObjValue());
+#ifndef CBC_OTHER_SOLVER
+                                // and put back in very original solver
+                                {
+                                    ClpSimplex * original = originalSolver->getModelPtr();
+                                    double * lower = original->columnLower();
+                                    double * upper = original->columnUpper();
+                                    double * solution = original->primalColumnSolution();
+                                    int n = original->numberColumns();
+                                    //assert (!n||n==babModel_->solver()->getNumCols());
+                                    for (int i = 0; i < n; i++) {
+                                        solution[i] = bestSolution[i];
+                                        if (originalSolver->isInteger(i)) {
+                                            lower[i] = solution[i];
+                                            upper[i] = solution[i];
+                                        }
+                                    }
+                                    // basis
+                                    CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (babModel_->solver()->getWarmStart());
+                                    originalSolver->setBasis(*basis);
+                                    delete basis;
+                                    originalSolver->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX);
+                                    originalSolver->resolve();
+                                    if (!originalSolver->isProvenOptimal()) {
+                                        // try all slack
+                                        CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (babModel_->solver()->getEmptyWarmStart());
+                                        originalSolver->setBasis(*basis);
+                                        delete basis;
+                                        originalSolver->initialSolve();
+					OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (originalSolver);
+					if (osiclp)
+					  osiclp->getModelPtr()->checkUnscaledSolution();
+#ifdef CLP_INVESTIGATE
+                                        if (!originalSolver->isProvenOptimal()) {
+                                            if (saveSolver) {
+                                                printf("saveSolver and originalSolver matrices saved\n");
+                                                saveSolver->writeMps("infA");
+                                            } else {
+                                                printf("originalSolver matrix saved\n");
+                                                originalSolver->writeMps("infB");
+                                            }
+                                        }
+#endif
+                                    }
+                                    assert (originalSolver->isProvenOptimal());
+                                }
+#endif
+                                checkSOS(babModel_, babModel_->solver());
+                            } else if (model_.bestSolution() && type == CBC_PARAM_ACTION_BAB && model_.getMinimizationObjValue() < 1.0e50 && preProcess) {
+                                sprintf(generalPrint, "Restoring heuristic best solution of %g", model_.getMinimizationObjValue());
+                                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                << generalPrint
+                                << CoinMessageEol;
+                                int n = saveSolver->getNumCols();
+                                bestSolution = new double [n];
+                                // Put solution now back in saveSolver
+                                saveSolver->setColSolution(model_.bestSolution());
+                                babModel_->assignSolver(saveSolver);
+				saveSolver=NULL;
+                                babModel_->setMinimizationObjValue(model_.getMinimizationObjValue());
+                                memcpy(bestSolution, babModel_->solver()->getColSolution(), n*sizeof(double));
+#ifndef CBC_OTHER_SOLVER
+                                // and put back in very original solver
+                                {
+                                    ClpSimplex * original = originalSolver->getModelPtr();
+                                    double * lower = original->columnLower();
+                                    double * upper = original->columnUpper();
+                                    double * solution = original->primalColumnSolution();
+                                    int n = original->numberColumns();
+                                    //assert (!n||n==babModel_->solver()->getNumCols());
+                                    for (int i = 0; i < n; i++) {
+                                        solution[i] = bestSolution[i];
+                                        if (originalSolver->isInteger(i)) {
+                                            lower[i] = solution[i];
+                                            upper[i] = solution[i];
+                                        }
+                                    }
+                                    // basis
+                                    CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (babModel_->solver()->getWarmStart());
+                                    originalSolver->setBasis(*basis);
+                                    delete basis;
+                                }
+#endif
+                            }
+#ifndef CBC_OTHER_SOLVER
+                            //if (type==CBC_PARAM_ACTION_STRENGTHEN&&strengthenedModel)
+                            //clpSolver = dynamic_cast< OsiClpSolverInterface*> (strengthenedModel);
+#ifdef COIN_HAS_ASL
+                            else if (statusUserFunction_[0])
+                                clpSolver = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+#endif
+                            lpSolver = clpSolver->getModelPtr();
+                            if (numberChanged) {
+                                for (int i = 0; i < numberChanged; i++) {
+                                    int iColumn = changed[i];
+                                    clpSolver->setContinuous(iColumn);
+                                }
+                                delete [] changed;
+                            }
+#endif
+                            if (type == CBC_PARAM_ACTION_BAB) {
+#ifndef CBC_OTHER_SOLVER
+                                //move best solution (should be there -- but ..)
+                                int n = lpSolver->getNumCols();
+                                if (bestSolution) {
+                                    memcpy(lpSolver->primalColumnSolution(), bestSolution, n*sizeof(double));
+                                    // now see what that does to row solution
+                                    int numberRows = lpSolver->numberRows();
+                                    double * rowSolution = lpSolver->primalRowSolution();
+                                    memset (rowSolution, 0, numberRows*sizeof(double));
+                                    lpSolver->clpMatrix()->times(1.0, bestSolution, rowSolution);
+                                    lpSolver->setObjectiveValue(babModel_->getObjValue());
+                                }
+                                if (debugFile == "create" && bestSolution) {
+                                    saveSolution(lpSolver, "debug.file");
+                                }
+#else
+                                if (bestSolution) {
+                                    model_.solver()->setColSolution(bestSolution);
+                                }
+#endif
+				delete saveSolver;
+                                delete [] bestSolution;
+				std::string statusName[] = {"", "Stopped on ", "Run abandoned", "", "", "User ctrl-c"};
+				std::string minor[] = {"Optimal solution found", "Linear relaxation infeasible", "Optimal solution found (within gap tolerance)", "node limit", "time limit", "user ctrl-c", "solution limit", "Linear relaxation unbounded", "Problem proven infeasible"};
+                                int iStat = babModel_->status();
+                                int iStat2 = babModel_->secondaryStatus();
+                                if (!iStat && !iStat2 && !bestSolution)
+                                    iStat2 = 8;
+                                if (!iStat && iStat2==1 && bestSolution)
+				  iStat2 = 0; // solution and search completed
+                                statistics_seconds = time2 - time1;
+                                statistics_sys_seconds = CoinSysTime();
+                                statistics_elapsed_seconds = CoinWallclockTime();
+                                statistics_obj = babModel_->getObjValue();
+                                statistics_continuous = babModel_->getContinuousObjective();
+                                statistics_tighter = babModel_->rootObjectiveAfterCuts();
+                                statistics_nodes = babModel_->getNodeCount();
+                                statistics_iterations = babModel_->getIterationCount();;
+                                statistics_result = statusName[iStat];;
+                                if (!noPrinting_) {
+				    sprintf(generalPrint, "\nResult - %s%s\n", 
+					    statusName[iStat].c_str(), 
+					    minor[iStat2].c_str());
+				    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				       << generalPrint
+				       << CoinMessageEol;
+				    if (babModel_->bestSolution()){
+				      sprintf(generalPrint, 
+					      "Objective value:                %.8f\n", 
+					      babModel_->getObjValue());
+				    }else{
+				      sprintf(generalPrint,
+					      "No feasible solution found\n");
+				    }
+				    if (iStat2 >= 2 && iStat2 <=6){
+				       sprintf(generalPrint + strlen(generalPrint), 
+					       "Lower bound:                    %.3f\n", 
+					       babModel_->getBestPossibleObjValue());
+				       if (babModel_->bestSolution()){
+					  sprintf(generalPrint + strlen(generalPrint), 
+						  "Gap:                            %.2f\n", 
+						  (babModel_->getObjValue()-babModel_->getBestPossibleObjValue())/babModel_->getBestPossibleObjValue());
+				       }
+				    }
+				    sprintf(generalPrint + strlen(generalPrint), 
+					    "Enumerated nodes:               %d\n", 
+					    babModel_->getNodeCount());
+				    sprintf(generalPrint + strlen(generalPrint), 
+					    "Total iterations:               %d\n", 
+					    babModel_->getIterationCount());
+#if CBC_QUIET == 0
+				    sprintf(generalPrint + strlen(generalPrint), 
+					    "Time (CPU seconds):             %.2f\n",
+					    CoinCpuTime() - time1);
+				    sprintf(generalPrint + strlen(generalPrint),
+					    "Time (Wallclock seconds):       %.2f\n", 
+					    CoinGetTimeOfDay() - time1Elapsed);
+#endif
+				    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				       << generalPrint
+				       << CoinMessageEol;
+                                }
+                                int returnCode = callBack(babModel_, 5);
+                                if (returnCode) {
+                                    // exit if user wants
+                                    model_.moveInfo(*babModel_);
+                                    delete babModel_;
+                                    babModel_ = NULL;
+                                    return returnCode;
+                                }
+#ifdef COIN_HAS_ASL
+				if (statusUserFunction_[0]) {
+				   clpSolver = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+				   lpSolver = clpSolver->getModelPtr();
+				   double value = babModel_->getObjValue()*lpSolver->getObjSense();
+				   char buf[300];
+				   int pos=0;
+				   if (iStat==0) {
+				      if (babModel_->getObjValue()<1.0e40) {
+					 pos += sprintf(buf+pos,"optimal," );
+				      } else {
+					 // infeasible
+					 iStat=1;
+					 pos += sprintf(buf+pos,"infeasible,");
+				      }
+				   } else if (iStat==1) {
+				      if (iStat2!=6)
+					 iStat=3;
+				      else
+					 iStat=4;
+				      pos += sprintf(buf+pos,"stopped on %s,",minor[iStat2].c_str());
+				   } else if (iStat==2) {
+				      iStat = 7;
+				      pos += sprintf(buf+pos,"stopped on difficulties,");
+				   } else if (iStat==5) {
+				      iStat = 3;
+				      pos += sprintf(buf+pos,"stopped on ctrl-c,");
+				   } else {
+				      pos += sprintf(buf+pos,"status unknown,");
+				      iStat=6;
+				   }
+				   info.problemStatus=iStat;
+				   info.objValue = value;
+				   if (babModel_->getObjValue()<1.0e40) {
+				      int precision = ampl_obj_prec();
+				      if (precision>0)
+					 pos += sprintf(buf+pos," objective %.*g",precision,
+							value);
+				      else
+					 pos += sprintf(buf+pos," objective %g",value);
+				   }
+				   sprintf(buf+pos,"\n%d nodes, %d iterations, %g seconds",
+					   babModel_->getNodeCount(),
+					   babModel_->getIterationCount(),
+					   totalTime);
+				   if (bestSolution) {
+				      free(info.primalSolution);
+				      if (!numberKnapsack) {
+					 info.primalSolution = (double *) malloc(n*sizeof(double));
+					 CoinCopyN(lpSolver->primalColumnSolution(),n,info.primalSolution);
+					 int numberRows = lpSolver->numberRows();
+					 free(info.dualSolution);
+					 info.dualSolution = (double *) malloc(numberRows*sizeof(double));
+					 CoinCopyN(lpSolver->dualRowSolution(),numberRows,info.dualSolution);
+				      } else {
+					 // expanded knapsack
+					 info.dualSolution=NULL;
+					 int numberColumns = saveCoinModel.numberColumns();
+					 info.primalSolution = (double *) malloc(numberColumns*sizeof(double));
+					 // Fills in original solution (coinModel length)
+					 afterKnapsack(saveTightenedModel,  whichColumn,  knapsackStart,
+					 	       knapsackRow,  numberKnapsack,
+					 	       lpSolver->primalColumnSolution(), info.primalSolution,1);
+				      }
+				   } else {
+				      info.primalSolution=NULL;
+				      info.dualSolution=NULL;
+				   }
+				   // put buffer into info
+				   strcpy(info.buffer,buf);
+				}
+#endif
+                            } else {
+                                std::cout << "Model strengthened - now has " << clpSolver->getNumRows()
+                                          << " rows" << std::endl;
+                            }
+                            time1 = time2;
+#ifdef COIN_HAS_ASL
+                            if (statusUserFunction_[0]) {
+                                // keep if going to be destroyed
+                                OsiSolverInterface * solver = babModel_->solver();
+                                OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+                                ClpSimplex * lpSolver2 = clpSolver->getModelPtr();
+                                if (lpSolver == lpSolver2)
+                                    babModel_->setModelOwnsSolver(false);
+                            }
+#endif
+                            //delete babModel_;
+                            //babModel_=NULL;
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl ;
+#endif
+                        }
+                        break ;
+                    case CLP_PARAM_ACTION_IMPORT: {
+#ifdef COIN_HAS_ASL
+                        if (!statusUserFunction_[0]) {
+#endif
+                            free(priorities);
+                            priorities = NULL;
+                            free(branchDirection);
+                            branchDirection = NULL;
+                            free(pseudoDown);
+                            pseudoDown = NULL;
+                            free(pseudoUp);
+                            pseudoUp = NULL;
+                            free(solutionIn);
+                            solutionIn = NULL;
+                            free(prioritiesIn);
+                            prioritiesIn = NULL;
+                            free(sosStart);
+                            sosStart = NULL;
+                            free(sosIndices);
+                            sosIndices = NULL;
+                            free(sosType);
+                            sosType = NULL;
+                            free(sosReference);
+                            sosReference = NULL;
+                            free(cut);
+                            cut = NULL;
+                            free(sosPriority);
+                            sosPriority = NULL;
+#ifdef COIN_HAS_ASL
+                        }
+#endif
+                        //delete babModel_;
+                        //babModel_=NULL;
+                        // get next field
+                        field = CoinReadGetString(argc, argv);
+                        if (field == "$") {
+                            field = parameters_[iParam].stringValue();
+                        } else if (field == "EOL") {
+                            parameters_[iParam].printString();
+                            break;
+                        } else {
+                            parameters_[iParam].setStringValue(field);
+                        }
+                        std::string fileName;
+                        bool canOpen = false;
+                        // See if gmpl file
+                        int gmpl = 0;
+                        std::string gmplData;
+                        if (field == "-" || field == "stdin") {
+                            // stdin
+                            canOpen = true;
+                            fileName = "-";
+                        } else if (field == "stdin_lp") {
+                            // stdin
+                            canOpen = true;
+                            fileName = "-";
+			    gmpl = -1; //.lp format
+                        } else {
+                            // See if .lp
+                            {
+                                const char * c_name = field.c_str();
+                                size_t length = strlen(c_name);
+                                if (length > 3 && !strncmp(c_name + length - 3, ".lp", 3))
+                                    gmpl = -1; // .lp
+                            }
+                            bool absolutePath;
+                            if (dirsep == '/') {
+                                // non Windows (or cygwin)
+                                absolutePath = (field[0] == '/');
+                            } else {
+                                //Windows (non cycgwin)
+                                absolutePath = (field[0] == '\\');
+                                // but allow for :
+                                if (strchr(field.c_str(), ':'))
+                                    absolutePath = true;
+                            }
+                            if (absolutePath) {
+                                fileName = field;
+				size_t length = field.size();
+				size_t percent = field.find('%');
+				if (percent < length && percent > 0) {
+				  gmpl = 1;
+				  fileName = field.substr(0, percent);
+				  gmplData = field.substr(percent + 1);
+				  if (percent < length - 1)
+				    gmpl = 2; // two files
+				  printf("GMPL model file %s and data file %s\n",
+					 fileName.c_str(), gmplData.c_str());
+				}
+                            } else if (field[0] == '~') {
+                                char * environVar = getenv("HOME");
+                                if (environVar) {
+                                    std::string home(environVar);
+                                    field = field.erase(0, 1);
+                                    fileName = home + field;
+                                } else {
+                                    fileName = field;
+                                }
+                            } else {
+                                fileName = directory + field;
+                                // See if gmpl (model & data) - or even lp file
+                                size_t length = field.size();
+                                size_t percent = field.find('%');
+                                if (percent<length && percent>0) {
+                                    gmpl = 1;
+                                    fileName = directory + field.substr(0, percent);
+                                    gmplData = directory + field.substr(percent + 1);
+                                    if (percent < length - 1)
+                                        gmpl = 2; // two files
+                                    printf("GMPL model file %s and data file %s\n",
+                                           fileName.c_str(), gmplData.c_str());
+                                }
+                            }
+                            std::string name = fileName;
+                            if (fileCoinReadable(name)) {
+                                // can open - lets go for it
+                                canOpen = true;
+                                if (gmpl == 2) {
+                                    FILE *fp;
+                                    fp = fopen(gmplData.c_str(), "r");
+                                    if (fp) {
+                                        fclose(fp);
+                                    } else {
+                                        canOpen = false;
+                                        std::cout << "Unable to open file " << gmplData << std::endl;
+                                    }
+                                }
+                            } else {
+                                std::cout << "Unable to open file " << fileName << std::endl;
+                            }
+                        }
+                        if (canOpen) {
+                            int status;
+#ifndef CBC_OTHER_SOLVER
+                            ClpSimplex * lpSolver = clpSolver->getModelPtr();
+                            if (!gmpl) {
+                                status = clpSolver->readMps(fileName.c_str(),
+                                                            keepImportNames != 0,
+                                                            allowImportErrors != 0);
+                            } else if (gmpl > 0) {
+                                status = lpSolver->readGMPL(fileName.c_str(),
+                                                            (gmpl == 2) ? gmplData.c_str() : NULL,
+                                                            keepImportNames != 0);
+                            } else {
+#ifdef KILL_ZERO_READLP
+                                status = lpSolver->readLp(fileName.c_str(), lpSolver->getSmallElementValue());
+#else
+                                status = lpSolver->readLp(fileName.c_str(), 1.0e-12);
+#endif
+                            }
+#else
+                            status = clpSolver->readMps(fileName.c_str(), "");
+#endif
+                            if (!status || (status > 0 && allowImportErrors)) {
+#ifndef CBC_OTHER_SOLVER
+                                if (keepImportNames) {
+                                    lengthName = lpSolver->lengthNames();
+                                    rowNames = *(lpSolver->rowNames());
+                                    columnNames = *(lpSolver->columnNames());
+                                } else {
+                                    lengthName = 0;
+                                }
+                                goodModel = true;
+                                // sets to all slack (not necessary?)
+                                lpSolver->createStatus();
+                                // make sure integer
+                                int numberColumns = lpSolver->numberColumns();
+                                for (int i = 0; i < numberColumns; i++) {
+                                    if (lpSolver->isInteger(i))
+                                        clpSolver->setInteger(i);
+                                }
+#else
+                                lengthName = 0;
+                                goodModel = true;
+#endif
+                                time2 = CoinCpuTime();
+                                totalTime += time2 - time1;
+                                time1 = time2;
+                                // Go to canned file if just input file
+                                if (CbcOrClpRead_mode == 2 && argc == 2) {
+                                    // only if ends .mps
+                                    char * find = const_cast<char *>(strstr(fileName.c_str(), ".mps"));
+                                    if (find && find[4] == '\0') {
+                                        find[1] = 'p';
+                                        find[2] = 'a';
+                                        find[3] = 'r';
+                                        FILE *fp = fopen(fileName.c_str(), "r");
+                                        if (fp) {
+                                            CbcOrClpReadCommand = fp; // Read from that file
+                                            CbcOrClpRead_mode = -1;
+                                        }
+                                    }
+                                }
+                            } else {
+                                // errors
+                                std::cout << "There were " << status <<
+                                          " errors on input" << std::endl;
+                            }
+                        }
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_MODELIN:
+#ifndef CBC_OTHER_SOLVER
+#ifdef COIN_HAS_LINK
+                        {
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                            }
+                            std::string fileName;
+                            bool canOpen = false;
+                            if (field == "-") {
+                                // stdin
+                                canOpen = true;
+                                fileName = "-";
+                            } else {
+                                bool absolutePath;
+                                if (dirsep == '/') {
+                                    // non Windows (or cygwin)
+                                    absolutePath = (field[0] == '/');
+                                } else {
+                                    //Windows (non cycgwin)
+                                    absolutePath = (field[0] == '\\');
+                                    // but allow for :
+                                    if (strchr(field.c_str(), ':'))
+                                        absolutePath = true;
+                                }
+                                if (absolutePath) {
+                                    fileName = field;
+                                } else if (field[0] == '~') {
+                                    char * environVar = getenv("HOME");
+                                    if (environVar) {
+                                        std::string home(environVar);
+                                        field = field.erase(0, 1);
+                                        fileName = home + field;
+                                    } else {
+                                        fileName = field;
+                                    }
+                                } else {
+                                    fileName = directory + field;
+                                }
+                                FILE *fp = fopen(fileName.c_str(), "r");
+                                if (fp) {
+                                    // can open - lets go for it
+                                    fclose(fp);
+                                    canOpen = true;
+                                } else {
+                                    std::cout << "Unable to open file " << fileName << std::endl;
+                                }
+                            }
+                            if (canOpen) {
+                                CoinModel coinModel(fileName.c_str(), 2);
+                                // load from coin model
+                                OsiSolverLink solver1;
+                                OsiSolverInterface * solver2 = solver1.clone();
+                                model_.assignSolver(solver2, false);
+                                OsiSolverLink * si =
+                                    dynamic_cast<OsiSolverLink *>(model_.solver()) ;
+                                assert (si != NULL);
+                                si->setDefaultMeshSize(0.001);
+                                // need some relative granularity
+                                si->setDefaultBound(100.0);
+                                double dextra3 = parameters_[whichParam(CBC_PARAM_DBL_DEXTRA3, numberParameters_, parameters_)].doubleValue();
+                                if (dextra3)
+                                    si->setDefaultMeshSize(dextra3);
+                                si->setDefaultBound(100.0);
+                                si->setIntegerPriority(1000);
+                                si->setBiLinearPriority(10000);
+                                CoinModel * model2 = &coinModel;
+                                si->load(*model2);
+                                // redo
+                                solver = model_.solver();
+                                clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+                                lpSolver = clpSolver->getModelPtr();
+                                clpSolver->messageHandler()->setLogLevel(0) ;
+                                testOsiParameters = 0;
+                                complicatedInteger = 2;
+                            }
+                        }
+#endif
+#endif
+                        break;
+                    case CLP_PARAM_ACTION_EXPORT:
+                        if (goodModel) {
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                            }
+                            std::string fileName;
+                            bool canOpen = false;
+                            if (field[0] == '/' || field[0] == '\\') {
+                                fileName = field;
+                            } else if (field[0] == '~') {
+                                char * environVar = getenv("HOME");
+                                if (environVar) {
+                                    std::string home(environVar);
+                                    field = field.erase(0, 1);
+                                    fileName = home + field;
+                                } else {
+                                    fileName = field;
+                                }
+                            } else {
+                                fileName = directory + field;
+                            }
+                            FILE *fp = fopen(fileName.c_str(), "w");
+                            if (fp) {
+                                // can open - lets go for it
+                                fclose(fp);
+                                canOpen = true;
+                            } else {
+                                std::cout << "Unable to open file " << fileName << std::endl;
+                            }
+                            if (canOpen) {
+                                // If presolve on then save presolved
+                                bool deleteModel2 = false;
+                                ClpSimplex * model2 = lpSolver;
+                                if (dualize && dualize < 3) {
+                                    model2 = static_cast<ClpSimplexOther *> (model2)->dualOfModel();
+                                    sprintf(generalPrint, "Dual of model has %d rows and %d columns",
+                                            model2->numberRows(), model2->numberColumns());
+                                    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                                    << generalPrint
+                                    << CoinMessageEol;
+                                    model2->setOptimizationDirection(1.0);
+                                }
+#ifndef CBC_OTHER_SOLVER
+#ifdef COIN_HAS_ASL
+                                if (info.numberSos && doSOS && statusUserFunction_[0]) {
+                                    // SOS
+                                    numberSOS = info.numberSos;
+                                    sosStart = info.sosStart;
+                                    sosIndices = info.sosIndices;
+                                    sosReference = info.sosReference;
+                                    preSolve = false;
+                                    clpSolver->setSOSData(numberSOS, info.sosType, sosStart, sosIndices, sosReference);
+                                }
+#endif
+#endif
+                                if (preSolve) {
+                                    ClpPresolve pinfo;
+                                    int presolveOptions2 = presolveOptions&~0x40000000;
+                                    if ((presolveOptions2&0xffff) != 0)
+                                        pinfo.setPresolveActions(presolveOptions2);
+                                    if ((printOptions&1) != 0)
+                                        pinfo.statistics();
+                                    double presolveTolerance =
+                                        parameters_[whichParam(CLP_PARAM_DBL_PRESOLVETOLERANCE, numberParameters_, parameters_)].doubleValue();
+                                    model2 =
+                                        pinfo.presolvedModel(*lpSolver, presolveTolerance,
+                                                             true, preSolve);
+                                    if (model2) {
+                                        printf("Saving presolved model on %s\n",
+                                               fileName.c_str());
+                                        deleteModel2 = true;
+                                    } else {
+                                        printf("Presolved model looks infeasible - saving original on %s\n",
+                                               fileName.c_str());
+                                        deleteModel2 = false;
+                                        model2 = lpSolver;
+
+                                    }
+                                    model2->writeMps(fileName.c_str(), (outputFormat - 1) / 2, 1 + ((outputFormat - 1)&1));
+                                    if (deleteModel2)
+                                        delete model2;
+                                } else {
+                                    printf("Saving model on %s\n",
+                                           fileName.c_str());
+                                    if (numberSOS) {
+                                        // Convert names
+                                        int iRow;
+                                        int numberRows = model2->numberRows();
+                                        int iColumn;
+                                        int numberColumns = model2->numberColumns();
+
+                                        char ** rowNames = NULL;
+                                        char ** columnNames = NULL;
+                                        if (model2->lengthNames()) {
+                                            rowNames = new char * [numberRows];
+                                            for (iRow = 0; iRow < numberRows; iRow++) {
+                                                rowNames[iRow] =
+                                                    CoinStrdup(model2->rowName(iRow).c_str());
+                                            }
+
+                                            columnNames = new char * [numberColumns];
+                                            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                                columnNames[iColumn] =
+                                                    CoinStrdup(model2->columnName(iColumn).c_str());
+                                            }
+                                        }
+                                        clpSolver->writeMpsNative(fileName.c_str(), const_cast<const char **> (rowNames), const_cast<const char **> (columnNames),
+                                                                  (outputFormat - 1) / 2, 1 + ((outputFormat - 1)&1));
+                                        if (rowNames) {
+                                            for (iRow = 0; iRow < numberRows; iRow++) {
+                                                free(rowNames[iRow]);
+                                            }
+                                            delete [] rowNames;
+                                            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                                free(columnNames[iColumn]);
+                                            }
+                                            delete [] columnNames;
+                                        }
+                                    } else {
+#ifdef COIN_HAS_LINK
+                                        OsiSolverLink * linkSolver = dynamic_cast< OsiSolverLink*> (clpSolver);
+                                        if (!linkSolver || !linkSolver->quadraticModel())
+                                            model2->writeMps(fileName.c_str(), (outputFormat - 1) / 2, 1 + ((outputFormat - 1)&1));
+                                        else
+                                            linkSolver->quadraticModel()->writeMps(fileName.c_str(), (outputFormat - 1) / 2, 1 + ((outputFormat - 1)&1));
+#endif
+                                    }
+                                }
+                                time2 = CoinCpuTime();
+                                totalTime += time2 - time1;
+                                time1 = time2;
+                            }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_BASISIN:
+                        if (goodModel) {
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                            }
+                            std::string fileName;
+                            bool canOpen = false;
+                            if (field == "-") {
+                                // stdin
+                                canOpen = true;
+                                fileName = "-";
+                            } else {
+                                if (field[0] == '/' || field[0] == '\\') {
+                                    fileName = field;
+                                } else if (field[0] == '~') {
+                                    char * environVar = getenv("HOME");
+                                    if (environVar) {
+                                        std::string home(environVar);
+                                        field = field.erase(0, 1);
+                                        fileName = home + field;
+                                    } else {
+                                        fileName = field;
+                                    }
+                                } else {
+                                    fileName = directory + field;
+                                }
+                                FILE *fp = fopen(fileName.c_str(), "r");
+                                if (fp) {
+                                    // can open - lets go for it
+                                    fclose(fp);
+                                    canOpen = true;
+                                } else {
+                                    std::cout << "Unable to open file " << fileName << std::endl;
+                                }
+                            }
+                            if (canOpen) {
+#ifndef CBC_OTHER_SOLVER
+                                int values = lpSolver->readBasis(fileName.c_str());
+                                if (values == 0)
+                                    basisHasValues = -1;
+                                else
+                                    basisHasValues = 1;
+                                assert (lpSolver == clpSolver->getModelPtr());
+                                clpSolver->setWarmStart(NULL);
+#endif
+                            }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CBC_PARAM_ACTION_PRIORITYIN:
+                        if (goodModel) {
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                            }
+                            std::string fileName;
+                            if (field[0] == '/' || field[0] == '\\') {
+                                fileName = field;
+                            } else if (field[0] == '~') {
+                                char * environVar = getenv("HOME");
+                                if (environVar) {
+                                    std::string home(environVar);
+                                    field = field.erase(0, 1);
+                                    fileName = home + field;
+                                } else {
+                                    fileName = field;
+                                }
+                            } else {
+                                fileName = directory + field;
+                            }
+                            FILE *fp = fopen(fileName.c_str(), "r");
+                            if (fp) {
+                                // can open - lets go for it
+                                std::string headings[] = {"name", "number", "direction", "priority", "up", "down",
+                                                          "solution", "priin"
+                                                         };
+                                int got[] = { -1, -1, -1, -1, -1, -1, -1, -1};
+                                int order[8];
+                                assert(sizeof(got) == sizeof(order));
+                                int nAcross = 0;
+                                char line[1000];
+                                int numberColumns = lpSolver->numberColumns();
+                                if (!fgets(line, 1000, fp)) {
+                                    std::cout << "Odd file " << fileName << std::endl;
+                                } else {
+                                    char * pos = line;
+                                    char * put = line;
+                                    while (*pos >= ' ' && *pos != '\n') {
+                                        if (*pos != ' ' && *pos != '\t') {
+                                            *put = static_cast<char>(tolower(*pos));
+                                            put++;
+                                        }
+                                        pos++;
+                                    }
+                                    *put = '\0';
+                                    pos = line;
+                                    int i;
+                                    bool good = true;
+                                    while (pos) {
+                                        char * comma = strchr(pos, ',');
+                                        if (comma)
+                                            *comma = '\0';
+                                        for (i = 0; i < static_cast<int> (sizeof(got) / sizeof(int)); i++) {
+                                            if (headings[i] == pos) {
+                                                if (got[i] < 0) {
+                                                    order[nAcross] = i;
+                                                    got[i] = nAcross++;
+                                                } else {
+                                                    // duplicate
+                                                    good = false;
+                                                }
+                                                break;
+                                            }
+                                        }
+                                        if (i == static_cast<int> (sizeof(got) / sizeof(int)))
+                                            good = false;
+                                        if (comma) {
+                                            *comma = ',';
+                                            pos = comma + 1;
+                                        } else {
+                                            break;
+                                        }
+                                    }
+                                    if (got[0] < 0 && got[1] < 0)
+                                        good = false;
+                                    if (got[0] >= 0 && got[1] >= 0)
+                                        good = false;
+                                    if (got[0] >= 0 && !lpSolver->lengthNames())
+                                        good = false;
+                                    int numberFields = 99;
+                                    if (good && (strstr(fileName.c_str(), ".mst") || strstr(fileName.c_str(), ".MST") || strstr(fileName.c_str(), ".csv"))) {
+                                        numberFields = 0;
+                                        for (i = 2; i < static_cast<int> (sizeof(got) / sizeof(int)); i++) {
+                                            if (got[i] >= 0)
+                                                numberFields++;
+                                        }
+                                        if (!numberFields) {
+                                            // Like Cplex format
+                                            order[nAcross] = 6;
+                                            got[6] = nAcross++;
+                                        }
+                                    }
+                                    if (good) {
+                                        char ** columnNames = new char * [numberColumns];
+                                        pseudoDown = reinterpret_cast<double *> (malloc(numberColumns * sizeof(double)));
+                                        pseudoUp = reinterpret_cast<double *> (malloc(numberColumns * sizeof(double)));
+                                        branchDirection = reinterpret_cast<int *> (malloc(numberColumns * sizeof(int)));
+                                        priorities = reinterpret_cast<int *> (malloc(numberColumns * sizeof(int)));
+                                        free(solutionIn);
+                                        solutionIn = NULL;
+                                        free(prioritiesIn);
+                                        prioritiesIn = NULL;
+                                        int iColumn;
+                                        if (got[6] >= 0) {
+                                            solutionIn = reinterpret_cast<double *> (malloc(numberColumns * sizeof(double)));
+                                            for (iColumn = 0; iColumn < numberColumns; iColumn++)
+                                                solutionIn[iColumn] = -COIN_DBL_MAX;
+                                        }
+                                        if (got[7] >= 0 || !numberFields) {
+                                            prioritiesIn = reinterpret_cast<int *> (malloc(numberColumns * sizeof(int)));
+                                            for (iColumn = 0; iColumn < numberColumns; iColumn++)
+                                                prioritiesIn[iColumn] = 10000;
+                                        }
+                                        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                            columnNames[iColumn] =
+                                                CoinStrdup(lpSolver->columnName(iColumn).c_str());
+                                            pseudoDown[iColumn] = 0.0;
+                                            pseudoUp[iColumn] = 0.0;
+                                            branchDirection[iColumn] = 0;
+                                            priorities[iColumn] = 0;
+                                        }
+                                        int nBadPseudo = 0;
+                                        int nBadDir = 0;
+                                        int nBadPri = 0;
+                                        int nBadName = 0;
+                                        int nBadLine = 0;
+                                        int nLine = 0;
+                                        while (fgets(line, 1000, fp)) {
+                                            if (!strncmp(line, "ENDATA", 6))
+                                                break;
+                                            nLine++;
+                                            iColumn = -1;
+                                            double up = 0.0;
+                                            double down = 0.0;
+                                            int pri = 0;
+                                            int dir = 0;
+                                            double solValue = COIN_DBL_MAX;
+                                            int priValue = 1000000;
+                                            char * pos = line;
+                                            char * put = line;
+                                            if (!numberFields) {
+                                                // put in ,
+                                                for (i = 4; i < 100; i++) {
+                                                    if (line[i] == ' ' || line[i] == '\t') {
+                                                        line[i] = ',';
+                                                        break;
+                                                    }
+                                                }
+                                            }
+                                            while (*pos >= ' ' && *pos != '\n') {
+                                                if (*pos != ' ' && *pos != '\t') {
+                                                    *put = *pos;
+                                                    put++;
+                                                }
+                                                pos++;
+                                            }
+                                            *put = '\0';
+                                            pos = line;
+                                            for (int i = 0; i < nAcross; i++) {
+                                                char * comma = strchr(pos, ',');
+                                                if (comma) {
+                                                    *comma = '\0';
+                                                } else if (i < nAcross - 1) {
+                                                    nBadLine++;
+                                                    break;
+                                                }
+                                                switch (order[i]) {
+                                                    // name
+                                                case 0:
+                                                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                                        if (!strcmp(columnNames[iColumn], pos))
+                                                            break;
+                                                    }
+                                                    if (iColumn == numberColumns)
+                                                        iColumn = -1;
+                                                    break;
+                                                    // number
+                                                case 1:
+                                                    iColumn = atoi(pos);
+                                                    if (iColumn < 0 || iColumn >= numberColumns)
+                                                        iColumn = -1;
+                                                    break;
+                                                    // direction
+                                                case 2:
+                                                    if (*pos == 'D')
+                                                        dir = -1;
+                                                    else if (*pos == 'U')
+                                                        dir = 1;
+                                                    else if (*pos == 'N')
+                                                        dir = 0;
+                                                    else if (*pos == '1' && *(pos + 1) == '\0')
+                                                        dir = 1;
+                                                    else if (*pos == '0' && *(pos + 1) == '\0')
+                                                        dir = 0;
+                                                    else if (*pos == '1' && *(pos + 1) == '1' && *(pos + 2) == '\0')
+                                                        dir = -1;
+                                                    else
+                                                        dir = -2; // bad
+                                                    break;
+                                                    // priority
+                                                case 3:
+                                                    pri = atoi(pos);
+                                                    break;
+                                                    // up
+                                                case 4:
+                                                    up = atof(pos);
+                                                    break;
+                                                    // down
+                                                case 5:
+                                                    down = atof(pos);
+                                                    break;
+                                                    // sol value
+                                                case 6:
+                                                    solValue = atof(pos);
+                                                    break;
+                                                    // priority in value
+                                                case 7:
+                                                    priValue = atoi(pos);
+                                                    break;
+                                                }
+                                                if (comma) {
+                                                    *comma = ',';
+                                                    pos = comma + 1;
+                                                }
+                                            }
+                                            if (iColumn >= 0) {
+                                                if (down < 0.0) {
+                                                    nBadPseudo++;
+                                                    down = 0.0;
+                                                }
+                                                if (up < 0.0) {
+                                                    nBadPseudo++;
+                                                    up = 0.0;
+                                                }
+                                                if (!up)
+                                                    up = down;
+                                                if (!down)
+                                                    down = up;
+                                                if (dir < -1 || dir > 1) {
+                                                    nBadDir++;
+                                                    dir = 0;
+                                                }
+                                                if (pri < 0) {
+                                                    nBadPri++;
+                                                    pri = 0;
+                                                }
+                                                pseudoDown[iColumn] = down;
+                                                pseudoUp[iColumn] = up;
+                                                branchDirection[iColumn] = dir;
+                                                priorities[iColumn] = pri;
+                                                if (solValue != COIN_DBL_MAX) {
+                                                    assert (solutionIn);
+                                                    solutionIn[iColumn] = solValue;
+                                                }
+                                                if (priValue != 1000000) {
+                                                    assert (prioritiesIn);
+                                                    prioritiesIn[iColumn] = priValue;
+                                                }
+                                            } else {
+                                                nBadName++;
+                                            }
+                                        }
+                                        if (!noPrinting_) {
+                                            printf("%d fields and %d records", nAcross, nLine);
+                                            if (nBadPseudo)
+                                                printf(" %d bad pseudo costs", nBadPseudo);
+                                            if (nBadDir)
+                                                printf(" %d bad directions", nBadDir);
+                                            if (nBadPri)
+                                                printf(" %d bad priorities", nBadPri);
+                                            if (nBadName)
+                                                printf(" ** %d records did not match on name/sequence", nBadName);
+                                            printf("\n");
+                                        }
+                                        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                            free(columnNames[iColumn]);
+                                        }
+                                        delete [] columnNames;
+                                    } else {
+                                        std::cout << "Duplicate or unknown keyword - or name/number fields wrong" << line << std::endl;
+                                    }
+                                }
+                                fclose(fp);
+                            } else {
+                                std::cout << "Unable to open file " << fileName << std::endl;
+                            }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CBC_PARAM_ACTION_MIPSTART:
+                        if (goodModel) {
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                            }
+                            std::string fileName;
+                            if (field[0] == '/' || field[0] == '\\') {
+                                fileName = field;
+                            } else if (field[0] == '~') {
+                                char * environVar = getenv("HOME");
+                                if (environVar) {
+                                    std::string home(environVar);
+                                    field = field.erase(0, 1);
+                                    fileName = home + field;
+                                } else {
+                                    fileName = field;
+                                }
+                            } else {
+                                fileName = directory + field;
+                            }
+			    sprintf(generalPrint,"will open mipstart file %s.",fileName.c_str() );
+			    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+			      << generalPrint
+			      << CoinMessageEol;
+                            double msObj;
+                            readMIPStart( &model_, fileName.c_str(), mipStart, msObj );
+			    // copy to before preprocess if has .before.
+			    if (strstr(fileName.c_str(),".before.")) {
+			      mipStartBefore = mipStart;
+			      sprintf(generalPrint,"file %s will be used before preprocessing.",fileName.c_str() );
+			      generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				<< generalPrint
+				<< CoinMessageEol;
+			    }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_DEBUG:
+                        if (goodModel) {
+                            delete [] debugValues;
+                            debugValues = NULL;
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                                debugFile = field;
+                                if (debugFile == "create" ||
+                                        debugFile == "createAfterPre") {
+                                    printf("Will create a debug file so this run should be a good one\n");
+                                    break;
+                                }
+                            }
+                            std::string fileName;
+                            if (field[0] == '/' || field[0] == '\\') {
+                                fileName = field;
+                            } else if (field[0] == '~') {
+                                char * environVar = getenv("HOME");
+                                if (environVar) {
+                                    std::string home(environVar);
+                                    field = field.erase(0, 1);
+                                    fileName = home + field;
+                                } else {
+                                    fileName = field;
+                                }
+                            } else {
+                                fileName = directory + field;
+                            }
+                            FILE *fp = fopen(fileName.c_str(), "rb");
+                            if (fp) {
+                                // can open - lets go for it
+                                int numRows;
+                                double obj;
+                                size_t nRead;
+                                nRead = fread(&numRows, sizeof(int), 1, fp);
+                                if (nRead != 1)
+                                    throw("Error in fread");
+                                nRead = fread(&numberDebugValues, sizeof(int), 1, fp);
+                                if (nRead != 1)
+                                    throw("Error in fread");
+                                nRead = fread(&obj, sizeof(double), 1, fp);
+                                if (nRead != 1)
+                                    throw("Error in fread");
+                                debugValues = new double[numberDebugValues+numRows];
+                                nRead = fread(debugValues, sizeof(double), numRows, fp);
+                                if (nRead != static_cast<size_t>(numRows))
+                                    throw("Error in fread");
+                                nRead = fread(debugValues, sizeof(double), numRows, fp);
+                                if (nRead != static_cast<size_t>(numRows))
+                                    throw("Error in fread");
+                                nRead = fread(debugValues, sizeof(double), numberDebugValues, fp);
+                                if (nRead != static_cast<size_t>(numberDebugValues))
+                                    throw("Error in fread");
+                                printf("%d doubles read into debugValues\n", numberDebugValues);
+#ifdef CGL_WRITEMPS
+				debugSolution = debugValues;
+				debugNumberColumns = numberDebugValues;
+#endif
+                                if (numberDebugValues < 200) {
+                                    for (int i = 0; i < numberDebugValues; i++) {
+                                        if (clpSolver->isInteger(i) && debugValues[i])
+                                            printf("%d %g\n", i, debugValues[i]);
+                                    }
+                                }
+                                fclose(fp);
+                            } else {
+                                std::cout << "Unable to open file " << fileName << std::endl;
+                            }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_PRINTMASK:
+                        // get next field
+                    {
+                        std::string name = CoinReadGetString(argc, argv);
+                        if (name != "EOL") {
+                            parameters_[iParam].setStringValue(name);
+                            printMask = name;
+                        } else {
+                            parameters_[iParam].printString();
+                        }
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_BASISOUT:
+                        if (goodModel) {
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                            }
+                            std::string fileName;
+                            bool canOpen = false;
+                            if (field[0] == '/' || field[0] == '\\') {
+                                fileName = field;
+                            } else if (field[0] == '~') {
+                                char * environVar = getenv("HOME");
+                                if (environVar) {
+                                    std::string home(environVar);
+                                    field = field.erase(0, 1);
+                                    fileName = home + field;
+                                } else {
+                                    fileName = field;
+                                }
+                            } else {
+                                fileName = directory + field;
+                            }
+                            FILE *fp = fopen(fileName.c_str(), "w");
+                            if (fp) {
+                                // can open - lets go for it
+                                fclose(fp);
+                                canOpen = true;
+                            } else {
+                                std::cout << "Unable to open file " << fileName << std::endl;
+                            }
+                            if (canOpen) {
+                                ClpSimplex * model2 = lpSolver;
+                                model2->writeBasis(fileName.c_str(), outputFormat > 1, outputFormat - 2);
+                                time2 = CoinCpuTime();
+                                totalTime += time2 - time1;
+                                time1 = time2;
+                            }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_SAVE: {
+                        // get next field
+                        field = CoinReadGetString(argc, argv);
+                        if (field == "$") {
+                            field = parameters_[iParam].stringValue();
+                        } else if (field == "EOL") {
+                            parameters_[iParam].printString();
+                            break;
+                        } else {
+                            parameters_[iParam].setStringValue(field);
+                        }
+                        std::string fileName;
+                        bool canOpen = false;
+                        if (field[0] == '/' || field[0] == '\\') {
+                            fileName = field;
+                        } else if (field[0] == '~') {
+                            char * environVar = getenv("HOME");
+                            if (environVar) {
+                                std::string home(environVar);
+                                field = field.erase(0, 1);
+                                fileName = home + field;
+                            } else {
+                                fileName = field;
+                            }
+                        } else {
+                            fileName = directory + field;
+                        }
+                        FILE *fp = fopen(fileName.c_str(), "wb");
+                        if (fp) {
+                            // can open - lets go for it
+                            fclose(fp);
+                            canOpen = true;
+                        } else {
+                            std::cout << "Unable to open file " << fileName << std::endl;
+                        }
+                        if (canOpen) {
+                            int status;
+                            // If presolve on then save presolved
+                            bool deleteModel2 = false;
+                            ClpSimplex * model2 = lpSolver;
+                            if (preSolve) {
+                                ClpPresolve pinfo;
+                                double presolveTolerance =
+                                    parameters_[whichParam(CLP_PARAM_DBL_PRESOLVETOLERANCE, numberParameters_, parameters_)].doubleValue();
+                                model2 =
+                                    pinfo.presolvedModel(*lpSolver, presolveTolerance,
+                                                         false, preSolve);
+                                if (model2) {
+                                    printf("Saving presolved model on %s\n",
+                                           fileName.c_str());
+                                    deleteModel2 = true;
+                                } else {
+                                    printf("Presolved model looks infeasible - saving original on %s\n",
+                                           fileName.c_str());
+                                    deleteModel2 = false;
+                                    model2 = lpSolver;
+
+                                }
+                            } else {
+                                printf("Saving model on %s\n",
+                                       fileName.c_str());
+                            }
+                            status = model2->saveModel(fileName.c_str());
+                            if (deleteModel2)
+                                delete model2;
+                            if (!status) {
+                                goodModel = true;
+                                time2 = CoinCpuTime();
+                                totalTime += time2 - time1;
+                                time1 = time2;
+                            } else {
+                                // errors
+                                std::cout << "There were errors on output" << std::endl;
+                            }
+                        }
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_RESTORE: {
+                        // get next field
+                        field = CoinReadGetString(argc, argv);
+                        if (field == "$") {
+                            field = parameters_[iParam].stringValue();
+                        } else if (field == "EOL") {
+                            parameters_[iParam].printString();
+                            break;
+                        } else {
+                            parameters_[iParam].setStringValue(field);
+                        }
+                        std::string fileName;
+                        bool canOpen = false;
+                        if (field[0] == '/' || field[0] == '\\') {
+                            fileName = field;
+                        } else if (field[0] == '~') {
+                            char * environVar = getenv("HOME");
+                            if (environVar) {
+                                std::string home(environVar);
+                                field = field.erase(0, 1);
+                                fileName = home + field;
+                            } else {
+                                fileName = field;
+                            }
+                        } else {
+                            fileName = directory + field;
+                        }
+                        FILE *fp = fopen(fileName.c_str(), "rb");
+                        if (fp) {
+                            // can open - lets go for it
+                            fclose(fp);
+                            canOpen = true;
+                        } else {
+                            std::cout << "Unable to open file " << fileName << std::endl;
+                        }
+                        if (canOpen) {
+                            int status = lpSolver->restoreModel(fileName.c_str());
+                            if (!status) {
+                                goodModel = true;
+                                time2 = CoinCpuTime();
+                                totalTime += time2 - time1;
+                                time1 = time2;
+                            } else {
+                                // errors
+                                std::cout << "There were errors on input" << std::endl;
+                            }
+                        }
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_MAXIMIZE:
+                        lpSolver->setOptimizationDirection(-1);
+                        break;
+                    case CLP_PARAM_ACTION_MINIMIZE:
+                        lpSolver->setOptimizationDirection(1);
+                        break;
+                    case CLP_PARAM_ACTION_ALLSLACK:
+                        lpSolver->allSlackBasis(true);
+                        break;
+                    case CLP_PARAM_ACTION_REVERSE:
+                        if (goodModel) {
+                            int iColumn;
+                            int numberColumns = lpSolver->numberColumns();
+                            double * dualColumnSolution =
+                                lpSolver->dualColumnSolution();
+                            ClpObjective * obj = lpSolver->objectiveAsObject();
+                            assert(dynamic_cast<ClpLinearObjective *> (obj));
+                            double offset;
+                            double * objective = obj->gradient(NULL, NULL, offset, true);
+                            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                dualColumnSolution[iColumn] = dualColumnSolution[iColumn];
+                                objective[iColumn] = -objective[iColumn];
+                            }
+                            int iRow;
+                            int numberRows = lpSolver->numberRows();
+                            double * dualRowSolution =
+                                lpSolver->dualRowSolution();
+                            for (iRow = 0; iRow < numberRows; iRow++)
+                                dualRowSolution[iRow] = dualRowSolution[iRow];
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_DIRECTORY: {
+                        std::string name = CoinReadGetString(argc, argv);
+                        if (name != "EOL") {
+                            size_t length = name.length();
+                            if (length > 0 && name[length-1] == dirsep) {
+                                directory = name;
+                            } else {
+                                directory = name + dirsep;
+                            }
+                            parameters_[iParam].setStringValue(directory);
+                        } else {
+                            parameters_[iParam].printString();
+                        }
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_DIRSAMPLE: {
+                        std::string name = CoinReadGetString(argc, argv);
+                        if (name != "EOL") {
+                            size_t length = name.length();
+                            if (length > 0 && name[length-1] == dirsep) {
+                                dirSample = name;
+                            } else {
+                                dirSample = name + dirsep;
+                            }
+                            parameters_[iParam].setStringValue(dirSample);
+                        } else {
+                            parameters_[iParam].printString();
+                        }
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_DIRNETLIB: {
+                        std::string name = CoinReadGetString(argc, argv);
+                        if (name != "EOL") {
+                            size_t length = name.length();
+                            if (length > 0 && name[length-1] == dirsep) {
+                                dirNetlib = name;
+                            } else {
+                                dirNetlib = name + dirsep;
+                            }
+                            parameters_[iParam].setStringValue(dirNetlib);
+                        } else {
+                            parameters_[iParam].printString();
+                        }
+                    }
+                    break;
+                    case CBC_PARAM_ACTION_DIRMIPLIB: {
+                        std::string name = CoinReadGetString(argc, argv);
+                        if (name != "EOL") {
+                            size_t length = name.length();
+                            if (length > 0 && name[length-1] == dirsep) {
+                                dirMiplib = name;
+                            } else {
+                                dirMiplib = name + dirsep;
+                            }
+                            parameters_[iParam].setStringValue(dirMiplib);
+                        } else {
+                            parameters_[iParam].printString();
+                        }
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_STDIN:
+                        CbcOrClpRead_mode = -1;
+                        break;
+                    case CLP_PARAM_ACTION_NETLIB_DUAL:
+                    case CLP_PARAM_ACTION_NETLIB_EITHER:
+                    case CLP_PARAM_ACTION_NETLIB_BARRIER:
+                    case CLP_PARAM_ACTION_NETLIB_PRIMAL:
+                    case CLP_PARAM_ACTION_NETLIB_TUNE: {
+                        printf("unit test is now only from clp - does same thing\n");
+                        //return(22);
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_UNITTEST: {
+                        CbcClpUnitTest(model_, dirSample, -2, NULL);
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_FAKEBOUND:
+                        if (goodModel) {
+                            // get bound
+                            double value = CoinReadGetDoubleField(argc, argv, &valid);
+                            if (!valid) {
+                                std::cout << "Setting " << parameters_[iParam].name() <<
+                                          " to DEBUG " << value << std::endl;
+                                int iRow;
+                                int numberRows = lpSolver->numberRows();
+                                double * rowLower = lpSolver->rowLower();
+                                double * rowUpper = lpSolver->rowUpper();
+                                for (iRow = 0; iRow < numberRows; iRow++) {
+                                    // leave free ones for now
+                                    if (rowLower[iRow] > -1.0e20 || rowUpper[iRow] < 1.0e20) {
+                                        rowLower[iRow] = CoinMax(rowLower[iRow], -value);
+                                        rowUpper[iRow] = CoinMin(rowUpper[iRow], value);
+                                    }
+                                }
+                                int iColumn;
+                                int numberColumns = lpSolver->numberColumns();
+                                double * columnLower = lpSolver->columnLower();
+                                double * columnUpper = lpSolver->columnUpper();
+                                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                    // leave free ones for now
+                                    if (columnLower[iColumn] > -1.0e20 ||
+                                            columnUpper[iColumn] < 1.0e20) {
+                                        columnLower[iColumn] = CoinMax(columnLower[iColumn], -value);
+                                        columnUpper[iColumn] = CoinMin(columnUpper[iColumn], value);
+                                    }
+                                }
+                            } else if (valid == 1) {
+                                abort();
+                            } else {
+                                std::cout << "enter value for " << parameters_[iParam].name() <<
+                                          std::endl;
+                            }
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_REALLY_SCALE:
+                        if (goodModel) {
+                            ClpSimplex newModel(*lpSolver,
+                                                lpSolver->scalingFlag());
+                            printf("model really really scaled\n");
+                            *lpSolver = newModel;
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_USERCLP:
+#ifdef USER_HAS_FAKE_CLP
+                        // Replace the sample code by whatever you want
+                        if (goodModel) {
+                            // Way of using an existing piece of code
+                            OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (model_.solver());
+                            ClpSimplex * lpSolver = clpSolver->getModelPtr();
+                            // set time from integer model
+                            double timeToGo = model_.getMaximumSeconds();
+                            lpSolver->setMaximumSeconds(timeToGo);
+                            int extra1 = parameters_[whichParam(CBC_PARAM_INT_EXTRA1, numberParameters_, parameters_)].intValue();
+                            fakeMain2(*lpSolver, *clpSolver, extra1);
+                            lpSolver = clpSolver->getModelPtr();
+#ifdef COIN_HAS_ASL
+                            // My actual usage has objective only in clpSolver
+                            //double objectiveValue=clpSolver->getObjValue();
+                            //int iStat = lpSolver->status();
+                            //int iStat2 = lpSolver->secondaryStatus();
+#endif
+                        }
+#endif
+                        break;
+                    case CBC_PARAM_ACTION_USERCBC:
+#ifdef USER_HAS_FAKE_CBC
+                        // Replace the sample code by whatever you want
+                        if (goodModel) {
+                            // Way of using an existing piece of code
+                            OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (model_.solver());
+                            ClpSimplex * lpSolver = clpSolver->getModelPtr();
+                            // set time from integer model
+                            double timeToGo = model_.getMaximumSeconds();
+                            lpSolver->setMaximumSeconds(timeToGo);
+                            fakeMain(*lpSolver, *clpSolver, model);
+#ifdef COIN_HAS_ASL
+                            // My actual usage has objective only in clpSolver
+                            double objectiveValue = clpSolver->getObjValue();
+                            int iStat = lpSolver->status();
+                            int iStat2 = lpSolver->secondaryStatus();
+#endif
+                            // make sure solution back in correct place
+                            clpSolver = dynamic_cast< OsiClpSolverInterface*> (model_.solver());
+                            lpSolver = clpSolver->getModelPtr();
+#ifdef COIN_HAS_ASL
+                            if (statusUserFunction_[0]) {
+                                int n = clpSolver->getNumCols();
+                                double value = objectiveValue * lpSolver->getObjSense();
+                                char buf[300];
+                                int pos = 0;
+                                std::string minor[] = {"", "", "gap", "nodes", "time", "", "solutions", "user ctrl-c"};
+                                if (iStat == 0) {
+                                    if (objectiveValue < 1.0e40) {
+                                        pos += sprintf(buf + pos, "optimal," );
+                                    } else {
+                                        // infeasible
+                                        iStat = 1;
+                                        pos += sprintf(buf + pos, "infeasible,");
+                                    }
+                                } else if (iStat == 1) {
+                                    if (iStat2 != 6)
+                                        iStat = 3;
+                                    else
+                                        iStat = 4;
+                                    pos += sprintf(buf + pos, "stopped on %s,", minor[iStat2].c_str());
+                                } else if (iStat == 2) {
+                                    iStat = 7;
+                                    pos += sprintf(buf + pos, "stopped on difficulties,");
+                                } else if (iStat == 5) {
+                                    iStat = 3;
+                                    pos += sprintf(buf + pos, "stopped on ctrl-c,");
+                                } else if (iStat == 6) {
+                                    // bab infeasible
+                                    pos += sprintf(buf + pos, "integer infeasible,");
+                                    iStat = 1;
+                                } else {
+                                    pos += sprintf(buf + pos, "status unknown,");
+                                    iStat = 6;
+                                }
+                                info.problemStatus = iStat;
+                                info.objValue = value;
+                                if (objectiveValue < 1.0e40)
+                                    pos += sprintf(buf + pos, " objective %.*g", ampl_obj_prec(),
+                                                   value);
+                                sprintf(buf + pos, "\n%d nodes, %d iterations",
+                                        model_.getNodeCount(),
+                                        model_.getIterationCount());
+                                if (objectiveValue < 1.0e50) {
+                                    free(info.primalSolution);
+                                    info.primalSolution = (double *) malloc(n * sizeof(double));
+                                    CoinCopyN(lpSolver->primalColumnSolution(), n, info.primalSolution);
+                                    int numberRows = lpSolver->numberRows();
+                                    free(info.dualSolution);
+                                    info.dualSolution = (double *) malloc(numberRows * sizeof(double));
+                                    CoinCopyN(lpSolver->dualRowSolution(), numberRows, info.dualSolution);
+                                } else {
+                                    info.primalSolution = NULL;
+                                    info.dualSolution = NULL;
+                                }
+                                // put buffer into info
+                                strcpy(info.buffer, buf);
+                            }
+#endif
+                        }
+#endif
+                        break;
+                    case CLP_PARAM_ACTION_HELP:
+                        std::cout << "Cbc version " << CBC_VERSION
+                                  << ", build " << __DATE__ << std::endl;
+                        std::cout << "Non default values:-" << std::endl;
+                        std::cout << "Perturbation " << lpSolver->perturbation() << " (default 100)"
+                                  << std::endl;
+                        CoinReadPrintit(
+                            "Presolve being done with 5 passes\n\
+Dual steepest edge steep/partial on matrix shape and factorization density\n\
+Clpnnnn taken out of messages\n\
+If Factorization frequency default then done on size of matrix\n\n\
+(-)unitTest, (-)netlib or (-)netlibp will do standard tests\n\n\
+You can switch to interactive mode at any time so\n\
+clp watson.mps -scaling off -primalsimplex\nis the same as\n\
+clp watson.mps -\nscaling off\nprimalsimplex"
+                        );
+                        break;
+                    case CLP_PARAM_ACTION_CSVSTATISTICS: {
+                        // get next field
+                        field = CoinReadGetString(argc, argv);
+                        if (field == "$") {
+                            field = parameters_[iParam].stringValue();
+                        } else if (field == "EOL") {
+                            parameters_[iParam].printString();
+                            break;
+                        } else {
+                            parameters_[iParam].setStringValue(field);
+                        }
+                        std::string fileName;
+                        if (field[0] == '/' || field[0] == '\\') {
+                            fileName = field;
+                        } else if (field[0] == '~') {
+                            char * environVar = getenv("HOME");
+                            if (environVar) {
+                                std::string home(environVar);
+                                field = field.erase(0, 1);
+                                fileName = home + field;
+                            } else {
+                                fileName = field;
+                            }
+                        } else {
+                            fileName = directory + field;
+                        }
+                        int state = 0;
+                        char buffer[1000];
+                        FILE *fp = fopen(fileName.c_str(), "r");
+                        if (fp) {
+                            // file already there
+                            state = 1;
+                            char * getBuffer = fgets(buffer, 1000, fp);
+                            if (getBuffer) {
+                                // assume header there
+                                state = 2;
+                            }
+                            fclose(fp);
+                        }
+                        fp = fopen(fileName.c_str(), "a");
+                        if (fp) {
+                            // can open - lets go for it
+                            // first header if needed
+                            if (state != 2) {
+                                fprintf(fp, "Name,result,time,sys,elapsed,objective,continuous,tightened,cut_time,nodes,iterations,rows,columns,processed_rows,processed_columns");
+                                for (int i = 0; i < statistics_number_generators; i++)
+                                    fprintf(fp, ",%s", statistics_name_generators[i]);
+                                fprintf(fp, ",runtime_options");
+                                fprintf(fp, "\n");
+                            }
+                            strcpy(buffer, argv[1]);
+                            char * slash = buffer;
+                            for (int i = 0; i < static_cast<int>(strlen(buffer)); i++) {
+                                if (buffer[i] == '/' || buffer[i] == '\\')
+                                    slash = buffer + i + 1;
+                            }
+                            fprintf(fp, "%s,%s,%.2f,%.2f,%.2f,%.16g,%g,%g,%.2f,%d,%d,%d,%d,%d,%d",
+                                    slash, statistics_result.c_str(), statistics_seconds,
+                                    statistics_sys_seconds, statistics_elapsed_seconds,
+                                    statistics_obj,
+                                    statistics_continuous, statistics_tighter, statistics_cut_time, statistics_nodes,
+                                    statistics_iterations, statistics_nrows, statistics_ncols,
+                                    statistics_nprocessedrows, statistics_nprocessedcols);
+                            for (int i = 0; i < statistics_number_generators; i++)
+                                fprintf(fp, ",%d", statistics_number_cuts[i]);
+                            fprintf(fp, ",");
+                            for (int i = 1; i < argc; i++) {
+                                if (strstr(argv[i], ".gz") || strstr(argv[i], ".mps"))
+                                    continue;
+                                if (!argv[i] || !strncmp(argv[i], "-csv", 4))
+                                    break;
+                                fprintf(fp, "%s ", argv[i]);
+                            }
+                            fprintf(fp, "\n");
+                            fclose(fp);
+                        } else {
+                            std::cout << "Unable to open file " << fileName << std::endl;
+                        }
+                    }
+                    break;
+                    case CLP_PARAM_ACTION_SOLUTION:
+                    case CLP_PARAM_ACTION_NEXTBESTSOLUTION:
+                    case CLP_PARAM_ACTION_GMPL_SOLUTION:
+                        if (goodModel) {
+			  ClpSimplex * saveLpSolver = NULL;
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+			    bool append = false;
+			    if (field == "append$") {
+			      field = "$";
+			      append = true;
+			    }
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                            }
+                            std::string fileName;
+                            FILE *fp = NULL;
+                            if (field == "-" || field == "EOL" || field == "stdout") {
+                                // stdout
+                                fp = stdout;
+                            } else if (field == "stderr") {
+                                // stderr
+                                fp = stderr;
+                            } else {
+                                bool absolutePath;
+                                if (dirsep == '/') {
+                                    // non Windows (or cygwin)
+                                    absolutePath = (field[0] == '/');
+                                } else {
+                                    //Windows (non cycgwin)
+                                    absolutePath = (field[0] == '\\');
+                                    // but allow for :
+                                    if (strchr(field.c_str(), ':'))
+                                        absolutePath = true;
+                                }
+                                if (absolutePath) {
+                                    fileName = field;
+                                } else if (field[0] == '~') {
+                                    char * environVar = getenv("HOME");
+                                    if (environVar) {
+                                        std::string home(environVar);
+                                        field = field.erase(0, 1);
+                                        fileName = home + field;
+                                    } else {
+                                        fileName = field;
+                                    }
+                                } else {
+                                    fileName = directory + field;
+                                }
+				if (!append)
+				  fp = fopen(fileName.c_str(), "w");
+				else
+				  fp = fopen(fileName.c_str(), "a");
+                            }
+                            if (fp) {
+#ifndef CBC_OTHER_SOLVER
+			      // See if Glpk 
+			      if (type == CLP_PARAM_ACTION_GMPL_SOLUTION) {
+				int numberRows = lpSolver->getNumRows();
+				int numberColumns = lpSolver->getNumCols();
+				int numberGlpkRows=numberRows+1;
+#ifdef COIN_HAS_GLPK
+				if (cbc_glp_prob) {
+				  // from gmpl
+				  numberGlpkRows=glp_get_num_rows(cbc_glp_prob);
+				  if (numberGlpkRows!=numberRows)
+				    printf("Mismatch - cbc %d rows, glpk %d\n",
+					   numberRows,numberGlpkRows);
+				}
+#endif
+				fprintf(fp,"%d %d\n",numberGlpkRows,
+					numberColumns);
+				int iStat = lpSolver->status();
+				int iStat2 = GLP_UNDEF;
+				bool integerProblem = false;
+				if (integerStatus >= 0){
+				  iStat = integerStatus;
+				  integerProblem = true;
+				}
+				if (iStat == 0) {
+				  // optimal
+				  if (integerProblem)
+				    iStat2 = GLP_OPT;
+				  else
+				    iStat2 = GLP_FEAS;
+				} else if (iStat == 1) {
+				  // infeasible
+				  iStat2 = GLP_NOFEAS;
+				} else if (iStat == 2) {
+				  // unbounded
+				  // leave as 1
+				} else if (iStat >= 3 && iStat <= 5) {
+				  if (babModel_ && !babModel_->bestSolution())
+				    iStat2 = GLP_NOFEAS;
+				  else
+				    iStat2 = GLP_FEAS;
+				} else if (iStat == 6) {
+				  // bab infeasible
+				  iStat2 = GLP_NOFEAS;
+				}
+				lpSolver->computeObjectiveValue(false);
+				double objValue = clpSolver->getObjValue(); 
+				if (integerProblem)
+				  fprintf(fp,"%d %g\n",iStat2,objValue);
+				else
+				  fprintf(fp,"%d 2 %g\n",iStat2,objValue);
+				if (numberGlpkRows > numberRows) {
+				  // objective as row
+				  if (integerProblem) {
+				    fprintf(fp,"%g\n",objValue);
+				  } else {
+				    fprintf(fp,"4 %g 1.0\n",objValue);
+				  }
+				}
+				int lookup[6]=
+				  {4,1,3,2,4,5};
+				const double * primalRowSolution =
+				  lpSolver->primalRowSolution();
+				const double * dualRowSolution =
+				  lpSolver->dualRowSolution();
+				for (int i=0;i<numberRows;i++) {
+				  if (integerProblem) {
+				    fprintf(fp,"%g\n",primalRowSolution[i]);
+				  } else {
+				    fprintf(fp,"%d %g %g\n",lookup[lpSolver->getRowStatus(i)],
+								   primalRowSolution[i],dualRowSolution[i]);
+				  }
+				}
+				const double * primalColumnSolution =
+				  lpSolver->primalColumnSolution();
+				const double * dualColumnSolution =
+				  lpSolver->dualColumnSolution();
+				for (int i=0;i<numberColumns;i++) {
+				  if (integerProblem) {
+				    fprintf(fp,"%g\n",primalColumnSolution[i]);
+				  } else {
+				    fprintf(fp,"%d %g %g\n",lookup[lpSolver->getColumnStatus(i)],
+								   primalColumnSolution[i],dualColumnSolution[i]);
+				  }
+				}
+				fclose(fp);
+#ifdef COIN_HAS_GLPK
+				if (cbc_glp_prob) {
+				  if (integerProblem) {
+				    glp_read_mip(cbc_glp_prob,fileName.c_str());
+				    glp_mpl_postsolve(cbc_glp_tran,
+						      cbc_glp_prob,
+						      GLP_MIP);
+				  } else {
+				    glp_read_sol(cbc_glp_prob,fileName.c_str());
+				    glp_mpl_postsolve(cbc_glp_tran,
+						      cbc_glp_prob,
+						      GLP_SOL);
+				  }
+				  // free up as much as possible
+				  glp_free(cbc_glp_prob);
+				  glp_mpl_free_wksp(cbc_glp_tran);
+				  cbc_glp_prob = NULL;
+				  cbc_glp_tran = NULL;
+				  //gmp_free_mem();
+				  /* check that no memory blocks are still allocated */
+				  glp_free_env();
+				}
+#endif
+				break;
+			      }
+			      if (printMode < 5) {
+			        if (type == CLP_PARAM_ACTION_NEXTBESTSOLUTION) {
+				  // save
+				  const double * nextBestSolution = model_.savedSolution(1);
+				  if (!nextBestSolution) {
+				    sprintf(generalPrint, "All alternative solutions printed");
+				    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				      << generalPrint
+				      << CoinMessageEol;
+				    break;
+				  } else {
+				    sprintf(generalPrint, "Alternative solution - %d remaining",model_.numberSavedSolutions()-2);
+				    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+				      << generalPrint
+				      << CoinMessageEol;
+				  }
+				  saveLpSolver = lpSolver;
+				  assert (clpSolver->getModelPtr()==saveLpSolver);
+				  lpSolver = new ClpSimplex(*saveLpSolver);
+#ifndef NDEBUG
+				  ClpSimplex * oldSimplex = clpSolver->swapModelPtr(lpSolver);
+				  assert (oldSimplex==saveLpSolver);
+#else
+              clpSolver->swapModelPtr(lpSolver);
+#endif
+				  double * solution = lpSolver->primalColumnSolution();
+				  double * lower = lpSolver->columnLower();
+				  double * upper = lpSolver->columnUpper();
+				  int numberColumns=lpSolver->numberColumns();
+				  memcpy(solution,nextBestSolution,numberColumns*sizeof(double));
+				  model_.deleteSavedSolution(1);
+				  for (int i = 0; i < numberColumns; i++) {
+				    if (clpSolver->isInteger(i)) {
+				      double value=floor(solution[i]+0.5);
+				      lower[i]=value;
+				      upper[i]=value;
+				    }
+				  }
+				  lpSolver->allSlackBasis();
+				  lpSolver->initialSolve();
+				}
+                                    // Write solution header (suggested by Luigi Poderico)
+                                    lpSolver->computeObjectiveValue(false);
+                                    double objValue = lpSolver->getObjValue();
+                                    int iStat = lpSolver->status();
+				    int iStat2 = -1;
+                                    if (integerStatus >= 0){
+                                        iStat = integerStatus;
+					iStat2 = babModel_->secondaryStatus();
+				    }
+                                    if (iStat == 0) {
+                                        fprintf(fp, "Optimal" );
+					if (iStat2 == 2){
+					   fprintf(fp, " (within gap tolerance)" );
+					}
+                                    } else if (iStat == 1) {
+                                        // infeasible
+                                        fprintf(fp, "Infeasible" );
+                                    } else if (iStat == 2) {
+                                        // unbounded
+                                        fprintf(fp, "Unbounded" );
+                                    } else if (iStat >= 3 && iStat <= 5) {
+				        if (iStat == 3) {
+					    if (iStat2 == 4){
+					        fprintf(fp, "Stopped on time" );
+					    }else{
+					        fprintf(fp, "Stopped on iterations" );
+					    }
+					} else if (iStat == 4){
+					    fprintf(fp, "Stopped on difficulties" );
+					} else {
+					    fprintf(fp, "Stopped on ctrl-c" );
+					}
+                                        if (babModel_ && !babModel_->bestSolution())
+                                            fprintf(fp, " (no integer solution - continuous used)");
+                                    } else if (iStat == 6) {
+				         // bab infeasible
+				         fprintf(fp, "Integer infeasible" );
+                                    } else {
+				         fprintf(fp, "Status unknown" );
+                                    }
+                                    fprintf(fp, " - objective value %.8f\n", objValue);
+                                }
+#endif
+                                // make fancy later on
+                                int iRow;
+                                int numberRows = clpSolver->getNumRows();
+                                const double * dualRowSolution = clpSolver->getRowPrice();
+                                const double * primalRowSolution =
+                                    clpSolver->getRowActivity();
+                                const double * rowLower = clpSolver->getRowLower();
+                                const double * rowUpper = clpSolver->getRowUpper();
+                                double primalTolerance ;
+                                clpSolver->getDblParam(OsiPrimalTolerance, primalTolerance);
+                                size_t lengthPrint = static_cast<size_t>(CoinMax(lengthName, 8));
+                                bool doMask = (printMask != "" && lengthName);
+                                int * maskStarts = NULL;
+                                int maxMasks = 0;
+                                char ** masks = NULL;
+                                if (doMask) {
+                                    int nAst = 0;
+                                    const char * pMask2 = printMask.c_str();
+                                    char pMask[100];
+                                    size_t iChar;
+                                    size_t lengthMask = strlen(pMask2);
+                                    assert (lengthMask < 100);
+                                    if (*pMask2 == '"') {
+                                        if (pMask2[lengthMask-1] != '"') {
+                                            printf("mismatched \" in mask %s\n", pMask2);
+                                            break;
+                                        } else {
+                                            strcpy(pMask, pMask2 + 1);
+                                            *strchr(pMask, '"') = '\0';
+                                        }
+                                    } else if (*pMask2 == '\'') {
+                                        if (pMask2[lengthMask-1] != '\'') {
+                                            printf("mismatched ' in mask %s\n", pMask2);
+                                            break;
+                                        } else {
+                                            strcpy(pMask, pMask2 + 1);
+                                            *strchr(pMask, '\'') = '\0';
+                                        }
+                                    } else {
+                                        strcpy(pMask, pMask2);
+                                    }
+                                    if (lengthMask > static_cast<size_t>(lengthName)) {
+                                        printf("mask %s too long - skipping\n", pMask);
+                                        break;
+                                    }
+                                    maxMasks = 1;
+                                    for (iChar = 0; iChar < lengthMask; iChar++) {
+                                        if (pMask[iChar] == '*') {
+                                            nAst++;
+                                            maxMasks *= (lengthName + 1);
+                                        }
+                                    }
+                                    int nEntries = 1;
+                                    maskStarts = new int[lengthName+2];
+                                    masks = new char * [maxMasks];
+                                    char ** newMasks = new char * [maxMasks];
+                                    int i;
+                                    for (i = 0; i < maxMasks; i++) {
+                                        masks[i] = new char[lengthName+1];
+                                        newMasks[i] = new char[lengthName+1];
+                                    }
+                                    strcpy(masks[0], pMask);
+                                    for (int iAst = 0; iAst < nAst; iAst++) {
+                                        int nOldEntries = nEntries;
+                                        nEntries = 0;
+                                        for (int iEntry = 0; iEntry < nOldEntries; iEntry++) {
+                                            char * oldMask = masks[iEntry];
+                                            char * ast = strchr(oldMask, '*');
+                                            assert (ast);
+                                            size_t length = strlen(oldMask) - 1;
+                                            size_t nBefore = ast - oldMask;
+                                            size_t nAfter = length - nBefore;
+                                            // and add null
+                                            nAfter++;
+                                            for (int i = 0; i <= lengthName - static_cast<int>(length); i++) {
+                                                char * maskOut = newMasks[nEntries];
+                                                memcpy(maskOut, oldMask, nBefore);
+                                                for (int k = 0; k < i; k++)
+                                                    maskOut[k+nBefore] = '?';
+                                                memcpy(maskOut + nBefore + i, ast + 1, nAfter);
+                                                nEntries++;
+                                                assert (nEntries <= maxMasks);
+                                            }
+                                        }
+                                        char ** temp = masks;
+                                        masks = newMasks;
+                                        newMasks = temp;
+                                    }
+                                    // Now extend and sort
+                                    int * sort = new int[nEntries];
+                                    for (i = 0; i < nEntries; i++) {
+                                        char * maskThis = masks[i];
+                                        size_t length = strlen(maskThis);
+                                        while (length > 0 && maskThis[length-1] == ' ')
+                                            length--;
+                                        maskThis[length] = '\0';
+                                        sort[i] = static_cast<int>(length);
+                                    }
+                                    CoinSort_2(sort, sort + nEntries, masks);
+                                    int lastLength = -1;
+                                    for (i = 0; i < nEntries; i++) {
+                                        int length = sort[i];
+                                        while (length > lastLength)
+                                            maskStarts[++lastLength] = i;
+                                    }
+                                    maskStarts[++lastLength] = nEntries;
+                                    delete [] sort;
+                                    for (i = 0; i < maxMasks; i++)
+                                        delete [] newMasks[i];
+                                    delete [] newMasks;
+                                }
+				if (printMode > 5) {
+				  ClpSimplex * solver = clpSolver->getModelPtr();
+				  int numberColumns = solver->numberColumns();
+				  // column length unless rhs ranging
+				  int number = numberColumns;
+				  switch (printMode) {
+				    // bound ranging
+				  case 6:
+				    fprintf(fp,"Bound ranging");
+				    break;
+				    // rhs ranging
+				  case 7:
+				    fprintf(fp,"Rhs ranging");
+				    number = numberRows;
+				    break;
+				    // objective ranging
+				  case 8:
+				    fprintf(fp,"Objective ranging");
+				    break;
+				  }
+				  if (lengthName)
+				    fprintf(fp,",name");
+				  fprintf(fp,",increase,variable,decrease,variable\n");
+				  int * which = new int [ number];
+				  if (printMode != 7) {
+				    if (!doMask) {
+				      for (int i = 0; i < number;i ++)
+					which[i]=i;
+				    } else {
+				      int n = 0;
+				      for (int i = 0; i < number;i ++) {
+					if (maskMatches(maskStarts,masks,columnNames[i]))
+					  which[n++]=i;
+				      }
+				      if (n) {
+					number=n;
+				      } else {
+					printf("No names match - doing all\n");
+					for (int i = 0; i < number;i ++)
+					  which[i]=i;
+				      }
+				    }
+				  } else {
+				    if (!doMask) {
+				    for (int i = 0; i < number;i ++)
+				      which[i]=i+numberColumns;
+				    } else {
+				      int n = 0;
+				      for (int i = 0; i < number;i ++) {
+					if (maskMatches(maskStarts,masks,rowNames[i]))
+					  which[n++]=i+numberColumns;
+				      }
+				      if (n) {
+					number=n;
+				      } else {
+					printf("No names match - doing all\n");
+					for (int i = 0; i < number;i ++)
+					  which[i]=i+numberColumns;
+				      }
+				    }
+				  }
+				  double * valueIncrease = new double [ number];
+				  int * sequenceIncrease = new int [ number];
+				  double * valueDecrease = new double [ number];
+				  int * sequenceDecrease = new int [ number];
+				  switch (printMode) {
+				    // bound or rhs ranging
+				  case 6:
+				  case 7:
+				    solver->primalRanging(numberRows,
+								 which, valueIncrease, sequenceIncrease,
+								 valueDecrease, sequenceDecrease);
+				    break;
+				    // objective ranging
+				  case 8:
+				    solver->dualRanging(number,
+							       which, valueIncrease, sequenceIncrease,
+							       valueDecrease, sequenceDecrease);
+				    break;
+				  }
+				  for (int i = 0; i < number; i++) {
+				    int iWhich = which[i];
+				    fprintf(fp, "%d,", (iWhich<numberColumns) ? iWhich : iWhich-numberColumns);
+				    if (lengthName) {
+				      const char * name = (printMode==7) ? rowNames[iWhich-numberColumns].c_str() : columnNames[iWhich].c_str();
+				      fprintf(fp,"%s,",name);
+				    }
+				    if (valueIncrease[i]<1.0e30) {
+				      fprintf(fp, "%.10g,", valueIncrease[i]);
+				      int outSequence = sequenceIncrease[i];
+				      if (outSequence<numberColumns) {
+					if (lengthName)
+					  fprintf(fp,"%s,",columnNames[outSequence].c_str());
+					else
+					  fprintf(fp,"C%7.7d,",outSequence);
+				      } else {
+					outSequence -= numberColumns;
+					if (lengthName)
+					  fprintf(fp,"%s,",rowNames[outSequence].c_str());
+					else
+					  fprintf(fp,"R%7.7d,",outSequence);
+				      }
+				    } else {
+				      fprintf(fp,"1.0e100,,");
+				    }
+				    if (valueDecrease[i]<1.0e30) {
+				      fprintf(fp, "%.10g,", valueDecrease[i]);
+				      int outSequence = sequenceDecrease[i];
+				      if (outSequence<numberColumns) {
+					if (lengthName)
+					  fprintf(fp,"%s",columnNames[outSequence].c_str());
+					else
+					  fprintf(fp,"C%7.7d",outSequence);
+				      } else {
+					outSequence -= numberColumns;
+					if (lengthName)
+					  fprintf(fp,"%s",rowNames[outSequence].c_str());
+					else
+					  fprintf(fp,"R%7.7d",outSequence);
+				      }
+				    } else {
+				      fprintf(fp,"1.0e100,");
+				    }
+				    fprintf(fp,"\n");
+				  }
+				  if (fp != stdout)
+				    fclose(fp);
+				  delete [] which;
+				  delete [] valueIncrease;
+				  delete [] sequenceIncrease;
+				  delete [] valueDecrease;
+				  delete [] sequenceDecrease;
+				  if (masks) {
+				    delete [] maskStarts;
+				    for (int i = 0; i < maxMasks; i++)
+				      delete [] masks[i];
+				    delete [] masks;
+				  }
+				  break;
+				}
+                                if (printMode > 2 && printMode < 5) {
+                                    for (iRow = 0; iRow < numberRows; iRow++) {
+                                        int type = printMode - 3;
+                                        if (primalRowSolution[iRow] > rowUpper[iRow] + primalTolerance ||
+                                                primalRowSolution[iRow] < rowLower[iRow] - primalTolerance) {
+                                            fprintf(fp, "** ");
+                                            type = 2;
+                                        } else if (fabs(primalRowSolution[iRow]) > 1.0e-8) {
+                                            type = 1;
+                                        } else if (numberRows < 50) {
+                                            type = 3;
+                                        }
+                                        if (doMask && !maskMatches(maskStarts, masks, rowNames[iRow]))
+                                            type = 0;
+                                        if (type) {
+                                            fprintf(fp, "%7d ", iRow);
+                                            if (lengthName) {
+                                                const char * name = rowNames[iRow].c_str();
+                                                size_t n = strlen(name);
+                                                size_t i;
+                                                for (i = 0; i < n; i++)
+                                                    fprintf(fp, "%c", name[i]);
+                                                for (; i < lengthPrint; i++)
+                                                    fprintf(fp, " ");
+                                            }
+                                            fprintf(fp, " %15.8g        %15.8g\n", primalRowSolution[iRow],
+                                                    dualRowSolution[iRow]);
+                                        }
+                                    }
+                                }
+                                int iColumn;
+                                int numberColumns = clpSolver->getNumCols();
+                                const double * dualColumnSolution =
+                                    clpSolver->getReducedCost();
+                                const double * primalColumnSolution =
+                                    clpSolver->getColSolution();
+                                const double * columnLower = clpSolver->getColLower();
+                                const double * columnUpper = clpSolver->getColUpper();
+                                if (printMode != 2) {
+                                    if (printMode == 5) {
+                                        if (lengthName)
+                                            fprintf(fp, "name");
+                                        else
+                                            fprintf(fp, "number");
+                                        fprintf(fp, ",solution\n");
+                                    }
+                                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                        int type = (printMode > 3) ? 1 : 0;
+                                        if (primalColumnSolution[iColumn] > columnUpper[iColumn] + primalTolerance ||
+                                                primalColumnSolution[iColumn] < columnLower[iColumn] - primalTolerance) {
+                                            fprintf(fp, "** ");
+                                            type = 2;
+                                        } else if (fabs(primalColumnSolution[iColumn]) > 1.0e-8) {
+                                            type = 1;
+                                        } else if (numberColumns < 50) {
+                                            type = 3;
+                                        }
+                                        // see if integer
+                                        if ((!clpSolver->isInteger(iColumn) || fabs(primalColumnSolution[iColumn]) < 1.0e-8)
+                                                && printMode == 1)
+                                            type = 0;
+                                        if (doMask && !maskMatches(maskStarts, masks,
+                                                                   columnNames[iColumn]))
+                                            type = 0;
+                                        if (type) {
+                                            if (printMode != 5) {
+                                                fprintf(fp, "%7d ", iColumn);
+                                                if (lengthName) {
+                                                    const char * name = columnNames[iColumn].c_str();
+                                                    size_t n = strlen(name);
+                                                    size_t i;
+                                                    for (i = 0; i < n; i++)
+                                                        fprintf(fp, "%c", name[i]);
+                                                    for (; i < lengthPrint; i++)
+                                                        fprintf(fp, " ");
+                                                }
+                                                fprintf(fp, " %15.8g        %15.8g\n",
+                                                        primalColumnSolution[iColumn],
+                                                        dualColumnSolution[iColumn]);
+                                            } else {
+                                                char temp[100];
+                                                if (lengthName) {
+                                                    const char * name = columnNames[iColumn].c_str();
+                                                    for (int i = 0; i < lengthName; i++)
+                                                        temp[i] = name[i];
+                                                    temp[lengthName] = '\0';
+                                                } else {
+                                                    sprintf(temp, "%7d", iColumn);
+                                                }
+                                                sprintf(temp + strlen(temp), ", %15.8g",
+                                                        primalColumnSolution[iColumn]);
+                                                size_t n = strlen(temp);
+                                                size_t k = 0;
+                                                for (size_t i = 0; i < n + 1; i++) {
+                                                    if (temp[i] != ' ')
+                                                        temp[k++] = temp[i];
+                                                }
+                                                fprintf(fp, "%s\n", temp);
+                                            }
+                                        }
+                                    }
+				    if (type == CLP_PARAM_ACTION_NEXTBESTSOLUTION) {
+				      if(saveLpSolver) {
+					clpSolver->swapModelPtr(saveLpSolver);
+					delete lpSolver;
+					lpSolver=saveLpSolver;
+					saveLpSolver=NULL;
+				      }
+				    }
+                                } else {
+                                    // special format suitable for OsiRowCutDebugger
+                                    int n = 0;
+                                    bool comma = false;
+                                    bool newLine = false;
+                                    fprintf(fp, "\tint intIndicesV[]={\n");
+                                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                        if (primalColumnSolution[iColumn] > 0.5 && model_.solver()->isInteger(iColumn)) {
+                                            if (comma)
+                                                fprintf(fp, ",");
+                                            if (newLine)
+                                                fprintf(fp, "\n");
+                                            fprintf(fp, "%d ", iColumn);
+                                            comma = true;
+                                            newLine = false;
+                                            n++;
+                                            if (n == 10) {
+                                                n = 0;
+                                                newLine = true;
+                                            }
+                                        }
+                                    }
+                                    fprintf(fp, "};\n");
+                                    n = 0;
+                                    comma = false;
+                                    newLine = false;
+                                    fprintf(fp, "\tdouble intSolnV[]={\n");
+                                    for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                                        if (primalColumnSolution[iColumn] > 0.5 && model_.solver()->isInteger(iColumn)) {
+                                            if (comma)
+                                                fprintf(fp, ",");
+                                            if (newLine)
+                                                fprintf(fp, "\n");
+                                            int value = static_cast<int> (primalColumnSolution[iColumn] + 0.5);
+                                            fprintf(fp, "%d. ", value);
+                                            comma = true;
+                                            newLine = false;
+                                            n++;
+                                            if (n == 10) {
+                                                n = 0;
+                                                newLine = true;
+                                            }
+                                        }
+                                    }
+                                    fprintf(fp, "};\n");
+                                }
+                                if (fp != stdout)
+                                    fclose(fp);
+                                if (masks) {
+                                    delete [] maskStarts;
+                                    for (int i = 0; i < maxMasks; i++)
+                                        delete [] masks[i];
+                                    delete [] masks;
+                                }
+                            } else {
+                                std::cout << "Unable to open file " << fileName << std::endl;
+                            }
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_SAVESOL:
+                        if (goodModel) {
+                            // get next field
+                            field = CoinReadGetString(argc, argv);
+                            if (field == "$") {
+                                field = parameters_[iParam].stringValue();
+                            } else if (field == "EOL") {
+                                parameters_[iParam].printString();
+                                break;
+                            } else {
+                                parameters_[iParam].setStringValue(field);
+                            }
+                            std::string fileName;
+                            if (field[0] == '/' || field[0] == '\\') {
+                                fileName = field;
+                            } else if (field[0] == '~') {
+                                char * environVar = getenv("HOME");
+                                if (environVar) {
+                                    std::string home(environVar);
+                                    field = field.erase(0, 1);
+                                    fileName = home + field;
+                                } else {
+                                    fileName = field;
+                                }
+                            } else {
+                                fileName = directory + field;
+                            }
+                            saveSolution(lpSolver, fileName);
+                        } else {
+#ifndef DISALLOW_PRINTING
+                            std::cout << "** Current model not valid" << std::endl;
+#endif
+                        }
+                        break;
+                    case CLP_PARAM_ACTION_DUMMY:
+                        break;
+                    case CLP_PARAM_ACTION_ENVIRONMENT:
+                        CbcOrClpEnvironmentIndex = 0;
+                        break;
+                    case CLP_PARAM_ACTION_PARAMETRICS:
+                          if (goodModel) {
+                               // get next field
+                               field = CoinReadGetString(argc, argv);
+                               if (field == "$") {
+                                    field = parameters[iParam].stringValue();
+                               } else if (field == "EOL") {
+                                    parameters[iParam].printString();
+                                    break;
+                               } else {
+                                    parameters[iParam].setStringValue(field);
+                               }
+                               std::string fileName;
+                               //bool canOpen = false;
+                               if (field[0] == '/' || field[0] == '\\') {
+                                    fileName = field;
+                               } else if (field[0] == '~') {
+                                    char * environVar = getenv("HOME");
+                                    if (environVar) {
+                                         std::string home(environVar);
+                                         field = field.erase(0, 1);
+                                         fileName = home + field;
+                                    } else {
+                                         fileName = field;
+                                    }
+                               } else {
+                                    fileName = directory + field;
+                               }
+			       static_cast<ClpSimplexOther *> (lpSolver)->parametrics(fileName.c_str());
+			       time2 = CoinCpuTime();
+			       totalTime += time2 - time1;
+			       time1 = time2;
+                          } else {
+                               std::cout << "** Current model not valid" << std::endl;
+                          }
+                          break;
+                    default:
+                        abort();
+                    }
+                }
+            } else if (!numberMatches) {
+                std::cout << "No match for " << field << " - ? for list of commands"
+                          << std::endl;
+            } else if (numberMatches == 1) {
+                if (!numberQuery) {
+                    std::cout << "Short match for " << field << " - completion: ";
+                    std::cout << parameters_[firstMatch].matchName() << std::endl;
+                } else if (numberQuery) {
+                    std::cout << parameters_[firstMatch].matchName() << " : ";
+                    std::cout << parameters_[firstMatch].shortHelp() << std::endl;
+                    if (numberQuery >= 2)
+                        parameters_[firstMatch].printLongHelp();
+                }
+            } else {
+                if (!numberQuery)
+                    std::cout << "Multiple matches for " << field << " - possible completions:"
+                              << std::endl;
+                else
+                    std::cout << "Completions of " << field << ":" << std::endl;
+                for ( iParam = 0; iParam < numberParameters_; iParam++ ) {
+                    int match = parameters_[iParam].matches(field);
+                    if (match && parameters_[iParam].displayThis()) {
+                        std::cout << parameters_[iParam].matchName();
+                        if (numberQuery >= 2)
+                            std::cout << " : " << parameters_[iParam].shortHelp();
+                        std::cout << std::endl;
+                    }
+                }
+            }
+        }
+    }
+#if CBC_QUIET == 0
+    sprintf(generalPrint ,
+	    "Total time (CPU seconds):       %.2f   (Wallclock seconds):       %.2f\n", 
+	    CoinCpuTime() - time0,
+	    CoinGetTimeOfDay() - time0Elapsed);
+    generalMessageHandler->message(CLP_GENERAL, generalMessages)
+      << generalPrint
+      << CoinMessageEol;
+#endif
+#ifdef COIN_HAS_GLPK
+    if (cbc_glp_prob) {
+      // free up as much as possible
+      glp_free(cbc_glp_prob);
+      glp_mpl_free_wksp(cbc_glp_tran);
+      glp_free_env(); 
+      cbc_glp_prob = NULL;
+      cbc_glp_tran = NULL;
+    }
+#endif
+    delete [] statistics_number_cuts;
+    delete [] statistics_name_generators;
+    // By now all memory should be freed
+#ifdef DMALLOC
+    //dmalloc_log_unfreed();
+    //dmalloc_shutdown();
+#endif
+    if (babModel_) {
+        model_.moveInfo(*babModel_);
+#ifndef CBC_OTHER_SOLVER
+        OsiClpSolverInterface * clpSolver0 = dynamic_cast< OsiClpSolverInterface*> (babModel_->solver());
+        ClpSimplex * lpSolver0 = clpSolver0->getModelPtr();
+        OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (model_.solver());
+        ClpSimplex * lpSolver = clpSolver->getModelPtr();
+        if (lpSolver0 != lpSolver && lpSolver != originalSolver->getModelPtr())
+            lpSolver->moveInfo(*lpSolver0);
+        //babModel_->setModelOwnsSolver(false);
+#endif
+    }
+#ifdef CBC_SIG_TRAP
+    // On Sun sometimes seems to be error - try and get round it
+    CoinSighandler_t saveSignal = SIG_DFL;
+    // register signal handler
+    saveSignal = signal(SIGSEGV, signal_handler_error);
+    // to force failure!babModel_->setNumberObjects(20000);
+    if (!sigsetjmp(cbc_seg_buffer, 1)) {
+#endif
+        delete babModel_;
+#ifdef CBC_SIG_TRAP
+    } else {
+        std::cerr << "delete babModel_ failed" << std::endl;
+    }
+#endif
+    babModel_ = NULL;
+    model_.solver()->setWarmStart(NULL);
+    //sprintf(generalPrint, "Total time %.2f", CoinCpuTime() - time0);
+    //generalMessageHandler->message(CLP_GENERAL, generalMessages)
+    //<< generalPrint
+    //<< CoinMessageEol;
+    return 0;
+}
+
+
+
+int CbcMain (int argc, const char *argv[],
+             CbcModel  & model)
+{
+    CbcMain0(model);
+    return CbcMain1(argc, argv, model);
+}
+
+
+void CbcMain0 (CbcModel  & model)
+{
+#ifndef CBC_OTHER_SOLVER
+    OsiClpSolverInterface * originalSolver = dynamic_cast<OsiClpSolverInterface *> (model.solver());
+#elif CBC_OTHER_SOLVER==1
+    OsiCpxSolverInterface * originalSolver = dynamic_cast<OsiCpxSolverInterface *> (model.solver());
+    // Dummy solvers
+    OsiClpSolverInterface dummySolver;
+    ClpSimplex * lpSolver = dummySolver.getModelPtr();
+    OsiCpxSolverInterface * clpSolver = originalSolver;
+#endif
+    assert (originalSolver);
+    CoinMessageHandler * generalMessageHandler = originalSolver->messageHandler();
+    generalMessageHandler->setPrefix(true);
+#ifndef CBC_OTHER_SOLVER
+    OsiSolverInterface * solver = model.solver();
+    OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+    ClpSimplex * lpSolver = clpSolver->getModelPtr();
+    lpSolver->setPerturbation(50);
+    lpSolver->messageHandler()->setPrefix(false);
+#endif
+    establishParams(numberParameters, parameters) ;
+    const char dirsep =  CoinFindDirSeparator();
+    std::string directory;
+    std::string dirSample;
+    std::string dirNetlib;
+    std::string dirMiplib;
+    if (dirsep == '/') {
+        directory = "./";
+        dirSample = "../../Data/Sample/";
+        dirNetlib = "../../Data/Netlib/";
+        dirMiplib = "../../Data/miplib3/";
+    } else {
+        directory = ".\\";
+        dirSample = "..\\..\\..\\..\\Data\\Sample\\";
+        dirNetlib = "..\\..\\..\\..\\Data\\Netlib\\";
+        dirMiplib = "..\\..\\..\\..\\Data\\miplib3\\";
+    }
+    std::string defaultDirectory = directory;
+    std::string importFile = "";
+    std::string exportFile = "default.mps";
+    std::string importBasisFile = "";
+    std::string importPriorityFile = "";
+    std::string debugFile = "";
+    std::string printMask = "";
+    std::string exportBasisFile = "default.bas";
+    std::string saveFile = "default.prob";
+    std::string restoreFile = "default.prob";
+    std::string solutionFile = "stdout";
+    std::string solutionSaveFile = "solution.file";
+    int doIdiot = -1;
+    int outputFormat = 2;
+    int substitution = 3;
+    int dualize = 3;
+    int preSolve = 5;
+    int doSprint = -1;
+    int testOsiParameters = -1;
+    parameters[whichParam(CLP_PARAM_ACTION_BASISIN, numberParameters, parameters)].setStringValue(importBasisFile);
+    parameters[whichParam(CBC_PARAM_ACTION_PRIORITYIN, numberParameters, parameters)].setStringValue(importPriorityFile);
+    parameters[whichParam(CLP_PARAM_ACTION_BASISOUT, numberParameters, parameters)].setStringValue(exportBasisFile);
+    parameters[whichParam(CLP_PARAM_ACTION_DEBUG, numberParameters, parameters)].setStringValue(debugFile);
+    parameters[whichParam(CLP_PARAM_ACTION_PRINTMASK, numberParameters, parameters)].setStringValue(printMask);
+    parameters[whichParam(CLP_PARAM_ACTION_DIRECTORY, numberParameters, parameters)].setStringValue(directory);
+    parameters[whichParam(CLP_PARAM_ACTION_DIRSAMPLE, numberParameters, parameters)].setStringValue(dirSample);
+    parameters[whichParam(CLP_PARAM_ACTION_DIRNETLIB, numberParameters, parameters)].setStringValue(dirNetlib);
+    parameters[whichParam(CBC_PARAM_ACTION_DIRMIPLIB, numberParameters, parameters)].setStringValue(dirMiplib);
+    parameters[whichParam(CLP_PARAM_DBL_DUALBOUND, numberParameters, parameters)].setDoubleValue(lpSolver->dualBound());
+    parameters[whichParam(CLP_PARAM_DBL_DUALTOLERANCE, numberParameters, parameters)].setDoubleValue(lpSolver->dualTolerance());
+    parameters[whichParam(CLP_PARAM_ACTION_EXPORT, numberParameters, parameters)].setStringValue(exportFile);
+    parameters[whichParam(CLP_PARAM_INT_IDIOT, numberParameters, parameters)].setIntValue(doIdiot);
+    parameters[whichParam(CLP_PARAM_ACTION_IMPORT, numberParameters, parameters)].setStringValue(importFile);
+    parameters[whichParam(CLP_PARAM_DBL_PRESOLVETOLERANCE, numberParameters, parameters)].setDoubleValue(1.0e-8);
+    int slog = whichParam(CLP_PARAM_INT_SOLVERLOGLEVEL, numberParameters, parameters);
+    int log = whichParam(CLP_PARAM_INT_LOGLEVEL, numberParameters, parameters);
+    parameters[slog].setIntValue(1);
+    clpSolver->messageHandler()->setLogLevel(1) ;
+    model.messageHandler()->setLogLevel(1);
+    lpSolver->setLogLevel(1);
+    parameters[log].setIntValue(1);
+    parameters[whichParam(CLP_PARAM_INT_MAXFACTOR, numberParameters, parameters)].setIntValue(lpSolver->factorizationFrequency());
+    parameters[whichParam(CLP_PARAM_INT_MAXITERATION, numberParameters, parameters)].setIntValue(lpSolver->maximumIterations());
+    parameters[whichParam(CLP_PARAM_INT_OUTPUTFORMAT, numberParameters, parameters)].setIntValue(outputFormat);
+    parameters[whichParam(CLP_PARAM_INT_PRESOLVEPASS, numberParameters, parameters)].setIntValue(preSolve);
+    parameters[whichParam(CLP_PARAM_INT_PERTVALUE, numberParameters, parameters)].setIntValue(lpSolver->perturbation());
+    parameters[whichParam(CLP_PARAM_DBL_PRIMALTOLERANCE, numberParameters, parameters)].setDoubleValue(lpSolver->primalTolerance());
+    parameters[whichParam(CLP_PARAM_DBL_PRIMALWEIGHT, numberParameters, parameters)].setDoubleValue(lpSolver->infeasibilityCost());
+    parameters[whichParam(CLP_PARAM_ACTION_RESTORE, numberParameters, parameters)].setStringValue(restoreFile);
+    parameters[whichParam(CLP_PARAM_ACTION_SAVE, numberParameters, parameters)].setStringValue(saveFile);
+    //parameters[whichParam(CLP_PARAM_DBL_TIMELIMIT,numberParameters,parameters)].setDoubleValue(1.0e8);
+    parameters[whichParam(CBC_PARAM_DBL_TIMELIMIT_BAB, numberParameters, parameters)].setDoubleValue(1.0e8);
+    parameters[whichParam(CLP_PARAM_ACTION_SOLUTION, numberParameters, parameters)].setStringValue(solutionFile);
+    parameters[whichParam(CLP_PARAM_ACTION_NEXTBESTSOLUTION, numberParameters, parameters)].setStringValue(solutionFile);
+    parameters[whichParam(CLP_PARAM_ACTION_SAVESOL, numberParameters, parameters)].setStringValue(solutionSaveFile);
+    parameters[whichParam(CLP_PARAM_INT_SPRINT, numberParameters, parameters)].setIntValue(doSprint);
+    parameters[whichParam(CLP_PARAM_INT_SUBSTITUTION, numberParameters, parameters)].setIntValue(substitution);
+    parameters[whichParam(CLP_PARAM_INT_DUALIZE, numberParameters, parameters)].setIntValue(dualize);
+    model.setNumberBeforeTrust(10);
+    parameters[whichParam(CBC_PARAM_INT_NUMBERBEFORE, numberParameters, parameters)].setIntValue(5);
+    parameters[whichParam(CBC_PARAM_INT_MAXNODES, numberParameters, parameters)].setIntValue(model.getMaximumNodes());
+    model.setNumberStrong(5);
+    parameters[whichParam(CBC_PARAM_INT_STRONGBRANCHING, numberParameters, parameters)].setIntValue(model.numberStrong());
+    parameters[whichParam(CBC_PARAM_DBL_INFEASIBILITYWEIGHT, numberParameters, parameters)].setDoubleValue(model.getDblParam(CbcModel::CbcInfeasibilityWeight));
+    parameters[whichParam(CBC_PARAM_DBL_INTEGERTOLERANCE, numberParameters, parameters)].setDoubleValue(model.getDblParam(CbcModel::CbcIntegerTolerance));
+    parameters[whichParam(CBC_PARAM_DBL_INCREMENT, numberParameters, parameters)].setDoubleValue(model.getDblParam(CbcModel::CbcCutoffIncrement));
+    parameters[whichParam(CBC_PARAM_INT_TESTOSI, numberParameters, parameters)].setIntValue(testOsiParameters);
+    parameters[whichParam(CBC_PARAM_INT_FPUMPTUNE, numberParameters, parameters)].setIntValue(1003);
+    initialPumpTune = 1003;
+#ifdef CBC_THREAD
+    parameters[whichParam(CBC_PARAM_INT_THREADS, numberParameters, parameters)].setIntValue(0);
+#endif
+    // Set up likely cut generators and defaults
+    parameters[whichParam(CBC_PARAM_STR_PREPROCESS, numberParameters, parameters)].setCurrentOption("sos");
+    parameters[whichParam(CBC_PARAM_INT_MIPOPTIONS, numberParameters, parameters)].setIntValue(1057);
+    parameters[whichParam(CBC_PARAM_INT_CUTPASSINTREE, numberParameters, parameters)].setIntValue(1);
+    parameters[whichParam(CBC_PARAM_INT_MOREMIPOPTIONS, numberParameters, parameters)].setIntValue(-1);
+    parameters[whichParam(CBC_PARAM_INT_MAXHOTITS, numberParameters, parameters)].setIntValue(100);
+    parameters[whichParam(CBC_PARAM_STR_CUTSSTRATEGY, numberParameters, parameters)].setCurrentOption("on");
+    parameters[whichParam(CBC_PARAM_STR_HEURISTICSTRATEGY, numberParameters, parameters)].setCurrentOption("on");
+    parameters[whichParam(CBC_PARAM_STR_NODESTRATEGY, numberParameters, parameters)].setCurrentOption("fewest");
+    parameters[whichParam(CBC_PARAM_STR_GOMORYCUTS, numberParameters, parameters)].setCurrentOption("ifmove");
+    parameters[whichParam(CBC_PARAM_STR_PROBINGCUTS, numberParameters, parameters)].setCurrentOption("ifmove");
+    parameters[whichParam(CBC_PARAM_STR_KNAPSACKCUTS, numberParameters, parameters)].setCurrentOption("ifmove");
+    parameters[whichParam(CBC_PARAM_STR_ZEROHALFCUTS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_REDSPLITCUTS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_REDSPLIT2CUTS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_GMICUTS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_CLIQUECUTS, numberParameters, parameters)].setCurrentOption("ifmove");
+    parameters[whichParam(CBC_PARAM_STR_MIXEDCUTS, numberParameters, parameters)].setCurrentOption("ifmove");
+    parameters[whichParam(CBC_PARAM_STR_FLOWCUTS, numberParameters, parameters)].setCurrentOption("ifmove");
+    parameters[whichParam(CBC_PARAM_STR_TWOMIRCUTS, numberParameters, parameters)].setCurrentOption("root");
+    parameters[whichParam(CBC_PARAM_STR_LANDPCUTS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_RESIDCUTS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_ROUNDING, numberParameters, parameters)].setCurrentOption("on");
+    parameters[whichParam(CBC_PARAM_STR_FPUMP, numberParameters, parameters)].setCurrentOption("on");
+    parameters[whichParam(CBC_PARAM_STR_GREEDY, numberParameters, parameters)].setCurrentOption("on");
+    parameters[whichParam(CBC_PARAM_STR_COMBINE, numberParameters, parameters)].setCurrentOption("on");
+    parameters[whichParam(CBC_PARAM_STR_CROSSOVER2, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_PIVOTANDCOMPLEMENT, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_PIVOTANDFIX, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_RANDROUND, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_NAIVE, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_RINS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_DINS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_RENS, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_LOCALTREE, numberParameters, parameters)].setCurrentOption("off");
+    parameters[whichParam(CBC_PARAM_STR_COSTSTRATEGY, numberParameters, parameters)].setCurrentOption("off");
+}
+
+/*
+  Routines to print statistics.
+*/
+static void breakdown(const char * name, int numberLook, const double * region)
+{
+    double range[] = {
+        -COIN_DBL_MAX,
+        -1.0e15, -1.0e11, -1.0e8, -1.0e5, -1.0e4, -1.0e3, -1.0e2, -1.0e1,
+        -1.0,
+        -1.0e-1, -1.0e-2, -1.0e-3, -1.0e-4, -1.0e-5, -1.0e-8, -1.0e-11, -1.0e-15,
+        0.0,
+        1.0e-15, 1.0e-11, 1.0e-8, 1.0e-5, 1.0e-4, 1.0e-3, 1.0e-2, 1.0e-1,
+        1.0,
+        1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e8, 1.0e11, 1.0e15,
+        COIN_DBL_MAX
+    };
+    int nRanges = static_cast<int> (sizeof(range) / sizeof(double));
+    int * number = new int[nRanges];
+    memset(number, 0, nRanges*sizeof(int));
+    int * numberExact = new int[nRanges];
+    memset(numberExact, 0, nRanges*sizeof(int));
+    int i;
+    for ( i = 0; i < numberLook; i++) {
+        double value = region[i];
+        for (int j = 0; j < nRanges; j++) {
+            if (value == range[j]) {
+                numberExact[j]++;
+                break;
+            } else if (value < range[j]) {
+                number[j]++;
+                break;
+            }
+        }
+    }
+    printf("\n%s has %d entries\n", name, numberLook);
+    for (i = 0; i < nRanges; i++) {
+        if (number[i])
+            printf("%d between %g and %g", number[i], range[i-1], range[i]);
+        if (numberExact[i]) {
+            if (number[i])
+                printf(", ");
+            printf("%d exactly at %g", numberExact[i], range[i]);
+        }
+        if (number[i] + numberExact[i])
+            printf("\n");
+    }
+    delete [] number;
+    delete [] numberExact;
+}
+static void statistics(ClpSimplex * originalModel, ClpSimplex * model)
+{
+    int numberColumns = originalModel->numberColumns();
+    const char * integerInformation  = originalModel->integerInformation();
+    const double * columnLower = originalModel->columnLower();
+    const double * columnUpper = originalModel->columnUpper();
+    int numberIntegers = 0;
+    int numberBinary = 0;
+    int iRow, iColumn;
+    if (integerInformation) {
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (integerInformation[iColumn]) {
+                if (columnUpper[iColumn] > columnLower[iColumn]) {
+                    numberIntegers++;
+                    if (columnUpper[iColumn] == 0.0 && columnLower[iColumn] == 1)
+                        numberBinary++;
+                }
+            }
+        }
+    }
+    numberColumns = model->numberColumns();
+    int numberRows = model->numberRows();
+    columnLower = model->columnLower();
+    columnUpper = model->columnUpper();
+    const double * rowLower = model->rowLower();
+    const double * rowUpper = model->rowUpper();
+    const double * objective = model->objective();
+    CoinPackedMatrix * matrix = model->matrix();
+    CoinBigIndex numberElements = matrix->getNumElements();
+    const int * columnLength = matrix->getVectorLengths();
+    //const CoinBigIndex * columnStart = matrix->getVectorStarts();
+    const double * elementByColumn = matrix->getElements();
+    int * number = new int[numberRows+1];
+    memset(number, 0, (numberRows + 1)*sizeof(int));
+    int numberObjSingletons = 0;
+    /* cType
+       0 0/inf, 1 0/up, 2 lo/inf, 3 lo/up, 4 free, 5 fix, 6 -inf/0, 7 -inf/up,
+       8 0/1
+    */
+    int cType[9];
+    std::string cName[] = {"0.0->inf,", "0.0->up,", "lo->inf,", "lo->up,", "free,", "fixed,", "-inf->0.0,",
+                           "-inf->up,", "0.0->1.0"
+                          };
+    int nObjective = 0;
+    memset(cType, 0, sizeof(cType));
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        int length = columnLength[iColumn];
+        if (length == 1 && objective[iColumn])
+            numberObjSingletons++;
+        number[length]++;
+        if (objective[iColumn])
+            nObjective++;
+        if (columnLower[iColumn] > -1.0e20) {
+            if (columnLower[iColumn] == 0.0) {
+                if (columnUpper[iColumn] > 1.0e20)
+                    cType[0]++;
+                else if (columnUpper[iColumn] == 1.0)
+                    cType[8]++;
+                else if (columnUpper[iColumn] == 0.0)
+                    cType[5]++;
+                else
+                    cType[1]++;
+            } else {
+                if (columnUpper[iColumn] > 1.0e20)
+                    cType[2]++;
+                else if (columnUpper[iColumn] == columnLower[iColumn])
+                    cType[5]++;
+                else
+                    cType[3]++;
+            }
+        } else {
+            if (columnUpper[iColumn] > 1.0e20)
+                cType[4]++;
+            else if (columnUpper[iColumn] == 0.0)
+                cType[6]++;
+            else
+                cType[7]++;
+        }
+    }
+    /* rType
+       0 E 0, 1 E 1, 2 E -1, 3 E other, 4 G 0, 5 G 1, 6 G other,
+       7 L 0,  8 L 1, 9 L other, 10 Range 0/1, 11 Range other, 12 free
+    */
+    int rType[13];
+    std::string rName[] = {"E 0.0,", "E 1.0,", "E -1.0,", "E other,", "G 0.0,", "G 1.0,", "G other,",
+                           "L 0.0,", "L 1.0,", "L other,", "Range 0.0->1.0,", "Range other,", "Free"
+                          };
+    memset(rType, 0, sizeof(rType));
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        if (rowLower[iRow] > -1.0e20) {
+            if (rowLower[iRow] == 0.0) {
+                if (rowUpper[iRow] > 1.0e20)
+                    rType[4]++;
+                else if (rowUpper[iRow] == 1.0)
+                    rType[10]++;
+                else if (rowUpper[iRow] == 0.0)
+                    rType[0]++;
+                else
+                    rType[11]++;
+            } else if (rowLower[iRow] == 1.0) {
+                if (rowUpper[iRow] > 1.0e20)
+                    rType[5]++;
+                else if (rowUpper[iRow] == rowLower[iRow])
+                    rType[1]++;
+                else
+                    rType[11]++;
+            } else if (rowLower[iRow] == -1.0) {
+                if (rowUpper[iRow] > 1.0e20)
+                    rType[6]++;
+                else if (rowUpper[iRow] == rowLower[iRow])
+                    rType[2]++;
+                else
+                    rType[11]++;
+            } else {
+                if (rowUpper[iRow] > 1.0e20)
+                    rType[6]++;
+                else if (rowUpper[iRow] == rowLower[iRow])
+                    rType[3]++;
+                else
+                    rType[11]++;
+            }
+        } else {
+            if (rowUpper[iRow] > 1.0e20)
+                rType[12]++;
+            else if (rowUpper[iRow] == 0.0)
+                rType[7]++;
+            else if (rowUpper[iRow] == 1.0)
+                rType[8]++;
+            else
+                rType[9]++;
+        }
+    }
+    // Basic statistics
+    printf("\n\nProblem has %d rows, %d columns (%d with objective) and %d elements\n",
+           numberRows, numberColumns, nObjective, numberElements);
+    if (number[0] + number[1]) {
+        printf("There are ");
+        if (numberObjSingletons)
+            printf("%d singletons with objective ", numberObjSingletons);
+        int numberNoObj = number[1] - numberObjSingletons;
+        if (numberNoObj)
+            printf("%d singletons with no objective ", numberNoObj);
+        if (number[0])
+            printf("** %d columns have no entries", number[0]);
+        printf("\n");
+    }
+    printf("Column breakdown:\n");
+    int k;
+    for (k = 0; k < static_cast<int> (sizeof(cType) / sizeof(int)); k++) {
+        printf("%d of type %s ", cType[k], cName[k].c_str());
+        if (((k + 1) % 3) == 0)
+            printf("\n");
+    }
+    if ((k % 3) != 0)
+        printf("\n");
+    printf("Row breakdown:\n");
+    for (k = 0; k < static_cast<int> (sizeof(rType) / sizeof(int)); k++) {
+        printf("%d of type %s ", rType[k], rName[k].c_str());
+        if (((k + 1) % 3) == 0)
+            printf("\n");
+    }
+    if ((k % 3) != 0)
+        printf("\n");
+    if (model->logLevel() < 2)
+        return ;
+    int kMax = model->logLevel() > 3 ? 1000000 : 10;
+    k = 0;
+    for (iRow = 1; iRow <= numberRows; iRow++) {
+        if (number[iRow]) {
+            k++;
+            printf("%d columns have %d entries\n", number[iRow], iRow);
+            if (k == kMax)
+                break;
+        }
+    }
+    if (k < numberRows) {
+        int kk = k;
+        k = 0;
+        for (iRow = numberRows; iRow >= 1; iRow--) {
+            if (number[iRow]) {
+                k++;
+                if (k == kMax)
+                    break;
+            }
+        }
+        if (k > kk) {
+            printf("\n    .........\n\n");
+            iRow = k;
+            k = 0;
+            for (; iRow < numberRows; iRow++) {
+                if (number[iRow]) {
+                    k++;
+                    printf("%d columns have %d entries\n", number[iRow], iRow);
+                    if (k == kMax)
+                        break;
+                }
+            }
+        }
+    }
+    delete [] number;
+    printf("\n\n");
+    // get row copy
+    CoinPackedMatrix rowCopy = *matrix;
+    rowCopy.reverseOrdering();
+    //const int * column = rowCopy.getIndices();
+    const int * rowLength = rowCopy.getVectorLengths();
+    //const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+    //const double * element = rowCopy.getElements();
+    number = new int[numberColumns+1];
+    memset(number, 0, (numberColumns + 1)*sizeof(int));
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        int length = rowLength[iRow];
+        number[length]++;
+    }
+    if (number[0])
+        printf("** %d rows have no entries\n", number[0]);
+    k = 0;
+    for (iColumn = 1; iColumn <= numberColumns; iColumn++) {
+        if (number[iColumn]) {
+            k++;
+            printf("%d rows have %d entries\n", number[iColumn], iColumn);
+            if (k == kMax)
+                break;
+        }
+    }
+    if (k < numberColumns) {
+        int kk = k;
+        k = 0;
+        for (iColumn = numberColumns; iColumn >= 1; iColumn--) {
+            if (number[iColumn]) {
+                k++;
+                if (k == kMax)
+                    break;
+            }
+        }
+        if (k > kk) {
+            printf("\n    .........\n\n");
+            iColumn = k;
+            k = 0;
+            for (; iColumn < numberColumns; iColumn++) {
+                if (number[iColumn]) {
+                    k++;
+                    printf("%d rows have %d entries\n", number[iColumn], iColumn);
+                    if (k == kMax)
+                        break;
+                }
+            }
+        }
+    }
+    delete [] number;
+    // Now do breakdown of ranges
+    breakdown("Elements", numberElements, elementByColumn);
+    breakdown("RowLower", numberRows, rowLower);
+    breakdown("RowUpper", numberRows, rowUpper);
+    breakdown("ColumnLower", numberColumns, columnLower);
+    breakdown("ColumnUpper", numberColumns, columnUpper);
+    breakdown("Objective", numberColumns, objective);
+}
+
+
+static bool maskMatches(const int * starts, char ** masks,
+                        std::string & check)
+{
+    // back to char as I am old fashioned
+    const char * checkC = check.c_str();
+    size_t length = strlen(checkC);
+    while (length > 0 && checkC[length-1] == ' ')
+        length--;
+    for (int i = starts[length]; i < starts[length+1]; i++) {
+        char * thisMask = masks[i];
+        size_t k;
+        for ( k = 0; k < length; k++) {
+            if (thisMask[k] != '?' && thisMask[k] != checkC[k])
+                break;
+        }
+        if (k == length)
+            return true;
+    }
+    return false;
+}
+
+static void clean(char * temp)
+{
+    char * put = temp;
+    while (*put >= ' ')
+        put++;
+    *put = '\0';
+}
+
+static void generateCode(CbcModel * /*model*/, const char * fileName, int type, int preProcess)
+{
+    // options on code generation
+    bool sizecode = (type & 4) != 0;
+    type &= 3;
+    FILE * fp = fopen(fileName, "r");
+    assert (fp);
+    int numberLines = 0;
+#define MAXLINES 5000
+#define MAXONELINE 200
+    char line[MAXLINES][MAXONELINE];
+    strcpy(line[numberLines++], "0#if defined(_MSC_VER)");
+    strcpy(line[numberLines++], "0// Turn off compiler warning about long names");
+    strcpy(line[numberLines++], "0#  pragma warning(disable:4786)");
+    strcpy(line[numberLines++], "0#endif\n");
+    strcpy(line[numberLines++], "0#include <cassert>");
+    strcpy(line[numberLines++], "0#include <iomanip>");
+    strcpy(line[numberLines++], "0#include \"OsiClpSolverInterface.hpp\"");
+    strcpy(line[numberLines++], "0#include \"CbcModel.hpp\"");
+    strcpy(line[numberLines++], "0#include \"CbcCutGenerator.hpp\"");
+    strcpy(line[numberLines++], "0#include \"CbcStrategy.hpp\"");
+    strcpy(line[numberLines++], "0#include \"CglPreProcess.hpp\"");
+    strcpy(line[numberLines++], "0#include \"CoinTime.hpp\"");
+    if (preProcess > 0)
+        strcpy(line[numberLines++], "0#include \"CglProbing.hpp\""); // possibly redundant
+    // To allow generated 5's to be just before branchAndBound - do rest here
+    strcpy(line[numberLines++], "5  cbcModel->initialSolve();");
+    strcpy(line[numberLines++], "5  if (clpModel->tightenPrimalBounds()!=0) {");
+    strcpy(line[numberLines++], "5    std::cout<<\"Problem is infeasible - tightenPrimalBounds!\"<<std::endl;");
+    strcpy(line[numberLines++], "5    exit(1);");
+    strcpy(line[numberLines++], "5  }");
+    strcpy(line[numberLines++], "5  clpModel->dual();  // clean up");
+    if (sizecode) {
+        // override some settings
+        strcpy(line[numberLines++], "5  // compute some things using problem size");
+        strcpy(line[numberLines++], "5  cbcModel->setMinimumDrop(CoinMin(5.0e-2,");
+        strcpy(line[numberLines++], "5       fabs(cbcModel->getMinimizationObjValue())*1.0e-3+1.0e-4));");
+        strcpy(line[numberLines++], "5  if (cbcModel->getNumCols()<500)");
+        strcpy(line[numberLines++], "5    cbcModel->setMaximumCutPassesAtRoot(-100); // always do 100 if possible");
+        strcpy(line[numberLines++], "5  else if (cbcModel->getNumCols()<5000)");
+        strcpy(line[numberLines++], "5    cbcModel->setMaximumCutPassesAtRoot(100); // use minimum drop");
+        strcpy(line[numberLines++], "5  else");
+        strcpy(line[numberLines++], "5    cbcModel->setMaximumCutPassesAtRoot(20);");
+        strcpy(line[numberLines++], "5  cbcModel->setMaximumCutPasses(1);");
+    }
+    if (preProcess <= 0) {
+        // no preprocessing or strategy
+        if (preProcess) {
+            strcpy(line[numberLines++], "5  // Preprocessing using CbcStrategy");
+            strcpy(line[numberLines++], "5  CbcStrategyDefault strategy(1,5,5);");
+            strcpy(line[numberLines++], "5  strategy.setupPreProcessing(1);");
+            strcpy(line[numberLines++], "5  cbcModel->setStrategy(strategy);");
+        }
+    } else {
+        int translate[] = {9999, 0, 0, -1, 2, 3, -2};
+        strcpy(line[numberLines++], "5  // Hand coded preprocessing");
+        strcpy(line[numberLines++], "5  CglPreProcess process;");
+        strcpy(line[numberLines++], "5  OsiSolverInterface * saveSolver=cbcModel->solver()->clone();");
+        strcpy(line[numberLines++], "5  // Tell solver we are in Branch and Cut");
+        strcpy(line[numberLines++], "5  saveSolver->setHintParam(OsiDoInBranchAndCut,true,OsiHintDo) ;");
+        strcpy(line[numberLines++], "5  // Default set of cut generators");
+        strcpy(line[numberLines++], "5  CglProbing generator1;");
+        strcpy(line[numberLines++], "5  generator1.setUsingObjective(1);");
+        strcpy(line[numberLines++], "5  generator1.setMaxPass(3);");
+        strcpy(line[numberLines++], "5  generator1.setMaxProbeRoot(saveSolver->getNumCols());");
+        strcpy(line[numberLines++], "5  generator1.setMaxElements(100);");
+        strcpy(line[numberLines++], "5  generator1.setMaxLookRoot(50);");
+        strcpy(line[numberLines++], "5  generator1.setRowCuts(3);");
+        strcpy(line[numberLines++], "5  // Add in generators");
+        strcpy(line[numberLines++], "5  process.addCutGenerator(&generator1);");
+        strcpy(line[numberLines++], "5  process.messageHandler()->setLogLevel(cbcModel->logLevel());");
+        strcpy(line[numberLines++], "5  OsiSolverInterface * solver2 = ");
+        sprintf(line[numberLines++], "5    process.preProcessNonDefault(*saveSolver,%d,10);", translate[preProcess]);
+        strcpy(line[numberLines++], "5  // Tell solver we are not in Branch and Cut");
+        strcpy(line[numberLines++], "5  saveSolver->setHintParam(OsiDoInBranchAndCut,false,OsiHintDo) ;");
+        strcpy(line[numberLines++], "5  if (solver2)");
+        strcpy(line[numberLines++], "5    solver2->setHintParam(OsiDoInBranchAndCut,false,OsiHintDo) ;");
+        strcpy(line[numberLines++], "5  if (!solver2) {");
+        strcpy(line[numberLines++], "5    std::cout<<\"Pre-processing says infeasible!\"<<std::endl;");
+        strcpy(line[numberLines++], "5    exit(1);");
+        strcpy(line[numberLines++], "5  } else {");
+        strcpy(line[numberLines++], "5    std::cout<<\"processed model has \"<<solver2->getNumRows()");
+        strcpy(line[numberLines++], "5	     <<\" rows, \"<<solver2->getNumCols()");
+        strcpy(line[numberLines++], "5	     <<\" columns and \"<<solver2->getNumElements()");
+        strcpy(line[numberLines++], "5	     <<\" elements\"<<solver2->getNumElements()<<std::endl;");
+        strcpy(line[numberLines++], "5  }");
+        strcpy(line[numberLines++], "5  // we have to keep solver2 so pass clone");
+        strcpy(line[numberLines++], "5  solver2 = solver2->clone();");
+        strcpy(line[numberLines++], "5  cbcModel->assignSolver(solver2);");
+        strcpy(line[numberLines++], "5  cbcModel->initialSolve();");
+    }
+    while (fgets(line[numberLines], MAXONELINE, fp)) {
+        assert (numberLines < MAXLINES);
+        clean(line[numberLines]);
+        numberLines++;
+    }
+    fclose(fp);
+    strcpy(line[numberLines++], "0\nint main (int argc, const char *argv[])\n{");
+    strcpy(line[numberLines++], "0  OsiClpSolverInterface solver1;");
+    strcpy(line[numberLines++], "0  int status=1;");
+    strcpy(line[numberLines++], "0  if (argc<2)");
+    strcpy(line[numberLines++], "0    std::cout<<\"Please give file name\"<<std::endl;");
+    strcpy(line[numberLines++], "0  else");
+    strcpy(line[numberLines++], "0    status=solver1.readMps(argv[1],\"\");");
+    strcpy(line[numberLines++], "0  if (status) {");
+    strcpy(line[numberLines++], "0    std::cout<<\"Bad readMps \"<<argv[1]<<std::endl;");
+    strcpy(line[numberLines++], "0    exit(1);");
+    strcpy(line[numberLines++], "0  }\n");
+    strcpy(line[numberLines++], "0  double time1 = CoinCpuTime();");
+    strcpy(line[numberLines++], "0  CbcModel model(solver1);");
+    strcpy(line[numberLines++], "0  // Now do requested saves and modifications");
+    strcpy(line[numberLines++], "0  CbcModel * cbcModel = & model;");
+    strcpy(line[numberLines++], "0  OsiSolverInterface * osiModel = model.solver();");
+    strcpy(line[numberLines++], "0  OsiClpSolverInterface * osiclpModel = dynamic_cast< OsiClpSolverInterface*> (osiModel);");
+    strcpy(line[numberLines++], "0  ClpSimplex * clpModel = osiclpModel->getModelPtr();");
+    // add in comments about messages
+    strcpy(line[numberLines++], "3  // You can save some time by switching off message building");
+    strcpy(line[numberLines++], "3  // clpModel->messagesPointer()->setDetailMessages(100,10000,(int *) NULL);");
+    // add in actual solve
+    strcpy(line[numberLines++], "5  cbcModel->branchAndBound();");
+    strcpy(line[numberLines++], "8  std::cout<<argv[1]<<\" took \"<<CoinCpuTime()-time1<<\" seconds, \"");
+    strcpy(line[numberLines++], "8	   <<cbcModel->getNodeCount()<<\" nodes with objective \"");
+    strcpy(line[numberLines++], "8	   <<cbcModel->getObjValue()");
+    strcpy(line[numberLines++], "8	   <<(!cbcModel->status() ? \" Finished\" : \" Not finished\")");
+    strcpy(line[numberLines++], "8	   <<std::endl;");
+    strcpy(line[numberLines++], "5  // For best solution");
+    strcpy(line[numberLines++], "5  int numberColumns = solver1.getNumCols();");
+    strcpy(line[numberLines++], "5  if (cbcModel->getMinimizationObjValue()<1.0e50) {");
+    if (preProcess > 0) {
+        strcpy(line[numberLines++], "5    // post process");
+        strcpy(line[numberLines++], "5    process.postProcess(*cbcModel->solver());");
+        strcpy(line[numberLines++], "5    // Solution now back in saveSolver");
+        strcpy(line[numberLines++], "5    cbcModel->assignSolver(saveSolver);");
+        strcpy(line[numberLines++], "5    memcpy(cbcModel->bestSolution(),cbcModel->solver()->getColSolution(),");
+        strcpy(line[numberLines++], "5	   numberColumns*sizeof(double));");
+    }
+    strcpy(line[numberLines++], "5    // put back in original solver");
+    strcpy(line[numberLines++], "5    solver1.setColSolution(cbcModel->bestSolution());");
+    strcpy(line[numberLines++], "5    const double * solution = solver1.getColSolution();");
+    strcpy(line[numberLines++], "8  \n  // Now you would use solution etc etc\n");
+    strcpy(line[numberLines++], "5");
+    strcpy(line[numberLines++], "5    // Get names from solver1 (as OsiSolverInterface may lose)");
+    strcpy(line[numberLines++], "5    std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames();");
+    strcpy(line[numberLines++], "5    ");
+    strcpy(line[numberLines++], "5    int iColumn;");
+    strcpy(line[numberLines++], "5    std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14);");
+    strcpy(line[numberLines++], "5    ");
+    strcpy(line[numberLines++], "5    std::cout<<\"--------------------------------------\"<<std::endl;");
+    strcpy(line[numberLines++], "5    for (iColumn=0;iColumn<numberColumns;iColumn++) {");
+    strcpy(line[numberLines++], "5      double value=solution[iColumn];");
+    strcpy(line[numberLines++], "5      if (fabs(value)>1.0e-7&&solver1.isInteger(iColumn)) ");
+    strcpy(line[numberLines++], "5	std::cout<<std::setw(6)<<iColumn<<\" \"");
+    strcpy(line[numberLines++], "5                 <<columnNames[iColumn]<<\" \"");
+    strcpy(line[numberLines++], "5                 <<value<<std::endl;");
+    strcpy(line[numberLines++], "5    }");
+    strcpy(line[numberLines++], "5    std::cout<<\"--------------------------------------\"<<std::endl;");
+    strcpy(line[numberLines++], "5  ");
+    strcpy(line[numberLines++], "5    std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific);");
+    strcpy(line[numberLines++], "5  }");
+    strcpy(line[numberLines++], "8  return 0;\n}");
+    fp = fopen(fileName, "w");
+    assert (fp);
+
+    int wanted[9];
+    memset(wanted, 0, sizeof(wanted));
+    wanted[0] = wanted[3] = wanted[5] = wanted[8] = 1;
+    if (type > 0)
+        wanted[1] = wanted[6] = 1;
+    if (type > 1)
+        wanted[2] = wanted[4] = wanted[7] = 1;
+    std::string header[9] = { "", "Save values", "Redundant save of default values", "Set changed values",
+                              "Redundant set default values", "Solve", "Restore values", "Redundant restore values", "Finish up"
+                            };
+    for (int iType = 0; iType < 9; iType++) {
+        if (!wanted[iType])
+            continue;
+        int n = 0;
+        int iLine;
+        for (iLine = 0; iLine < numberLines; iLine++) {
+            if (line[iLine][0] == '0' + iType) {
+                if (!n && header[iType] != "")
+                    fprintf(fp, "\n  // %s\n\n", header[iType].c_str());
+                n++;
+                // skip save and clp as cloned
+                if (!strstr(line[iLine], "save") || (!strstr(line[iLine], "clpMo") &&
+                                                     !strstr(line[iLine], "_Osi")))
+                    fprintf(fp, "%s\n", line[iLine] + 1);
+            }
+        }
+    }
+    fclose(fp);
+    printf("C++ file written to %s\n", fileName);
+}
+/*
+  Version 1.00.00 November 16 2005.
+  This is to stop me (JJF) messing about too much.
+  Tuning changes should be noted here.
+  The testing next version may be activated by CBC_NEXT_VERSION
+  This applies to OsiClp, Clp etc
+  Version 1.00.01 November 24 2005
+  Added several classes for advanced users.  This can't affect code (if you don't use it)
+  Made some tiny changes (for N way branching) which should not change anything.
+  CbcNWay object class - for N way branching this also allows use of CbcConsequence class.
+  CbcBranchAllDifferent object class - for branching on general integer variables
+  to stop them having same value so branches are x >= y+1 and x <= y-1.
+  Added two new Cgl classes - CglAllDifferent which does column fixing (too slowly)
+  and CglStored which just has a list of cuts which can be activated.
+  Modified preprocess option to SOS
+  Version 1.00.02 December 9 2005
+  Added use of CbcStrategy to do clean preprocessing
+  Added use of referenceSolver for cleaner repetition of Cbc
+  Version 1.01.00 February 2 2006
+  Added first try at Ampl interface
+  Version 1.04 June 2007
+  Goes parallel
+  Version 2.00 September 2007
+  Improvements to feaspump
+  Source code changes so up to 2.0
+*/
+                            
diff --git a/cbits/coin/CbcSolver.hpp b/cbits/coin/CbcSolver.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSolver.hpp
@@ -0,0 +1,399 @@
+/* $Id: CbcSolver.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+/*! \file CbcSolver.hpp
+    \brief Defines CbcSolver, the proposed top-level class for the new-style
+    cbc solver.
+
+    This class is currently an orphan. With the removal of all code flagged
+    with the NEWS_STYLE_SOLVER, this class is never instantiated (and cannot
+    be instantiated). It is available to be coopted as a top-level object
+    wrapping the current CbcMain0 and CbcMain1, should that appear to be a
+    desireable path forward.  -- lh, 091211 --
+*/
+
+#ifndef CbcSolver_H
+#define CbcSolver_H
+
+#include <string>
+#include <vector>
+#include "CoinMessageHandler.hpp"
+#include "OsiClpSolverInterface.hpp"
+
+#if CBC_OTHER_SOLVER==1
+#include "OsiCpxSolverInterface.hpp"
+#endif
+
+#include "CbcModel.hpp"
+#include "CbcOrClpParam.hpp"
+
+class CbcUser;
+class CbcStopNow;
+class CglCutGenerator;
+
+//#############################################################################
+
+/*! \brief This allows the use of the standalone solver in a flexible manner.
+
+    It has an original OsiClpSolverInterface and CbcModel which it can use
+    repeatedly, e.g., to get a heuristic solution and then start again.
+
+    So I [jjf] will need a primitive scripting language which can then call
+    solve and manipulate solution value and solution arrays.
+
+    Also provides for user callback functions. Currently two ideas in
+    gestation, CbcUser and CbcStopNow. The latter seems limited to deciding
+    whether or not to stop. The former seems completely general, with a notion
+    of importing and exporting, and a `solve', which should be interpreted as
+    `do whatever this user function does'.
+
+    Parameter initialisation is at last centralised in fillParameters().
+*/
+
+class CbcSolver {
+
+public:
+    ///@name Solve method
+    //@{
+    /** This takes a list of commands, does "stuff" and returns
+        returnMode -
+        0 model and solver untouched - babModel updated
+        1 model updated - just with solution basis etc
+        2 model updated i.e. as babModel (babModel NULL) (only use without preprocessing)
+    */
+    int solve(int argc, const char * argv[], int returnMode);
+    /** This takes a list of commands, does "stuff" and returns
+        returnMode -
+        0 model and solver untouched - babModel updated
+        1 model updated - just with solution basis etc
+        2 model updated i.e. as babModel (babModel NULL) (only use without preprocessing)
+    */
+    int solve(const char * input, int returnMode);
+    //@}
+    ///@name Constructors and destructors etc
+    //@{
+    /// Default Constructor
+    CbcSolver();
+
+    /// Constructor from solver
+    CbcSolver(const OsiClpSolverInterface &);
+
+    /// Constructor from model
+    CbcSolver(const CbcModel &);
+
+    /** Copy constructor .
+     */
+    CbcSolver(const CbcSolver & rhs);
+
+    /// Assignment operator
+    CbcSolver & operator=(const CbcSolver& rhs);
+
+    /// Destructor
+    ~CbcSolver ();
+    /// Fill with standard parameters
+    void fillParameters();
+    /*! \brief Set default values in solvers from parameters
+
+      Misleading. The current code actually reads default values from
+      the underlying solvers and installs them as default values for a subset of
+      parameters in #parameters_.
+    */
+    void fillValuesInSolver();
+    /// Add user function
+    void addUserFunction(CbcUser * function);
+    /// Set user call back
+    void setUserCallBack(CbcStopNow * function);
+    /// Add cut generator
+    void addCutGenerator(CglCutGenerator * generator);
+    //@}
+    ///@name miscellaneous methods to line up with old
+    //@{
+    // analyze model
+    int * analyze(OsiClpSolverInterface * solverMod, int & numberChanged, double & increment,
+                  bool changeInt,  CoinMessageHandler * generalMessageHandler);
+    /** 1 - add heuristics to model
+        2 - do heuristics (and set cutoff and best solution)
+        3 - for miplib test so skip some
+        (out model later)
+    */
+    //int doHeuristics(CbcModel * model, int type);
+    /** Updates model_ from babModel_ according to returnMode
+        returnMode -
+        0 model and solver untouched - babModel updated
+        1 model updated - just with solution basis etc
+        2 model updated i.e. as babModel (babModel NULL) (only use without preprocessing)
+    */
+    void updateModel(ClpSimplex * model2, int returnMode);
+    //@}
+    ///@name useful stuff
+    //@{
+    /// Get int value
+    int intValue(CbcOrClpParameterType type) const;
+    /// Set int value
+    void setIntValue(CbcOrClpParameterType type, int value);
+    /// Get double value
+    double doubleValue(CbcOrClpParameterType type) const;
+    /// Set double value
+    void setDoubleValue(CbcOrClpParameterType type, double value);
+    /// User function (NULL if no match)
+    CbcUser * userFunction(const char * name) const;
+    /// Return original Cbc model
+    inline CbcModel * model() {
+        return &model_;
+    }
+    /// Return updated Cbc model
+    inline CbcModel * babModel() {
+        return babModel_;
+    }
+    /// Number of userFunctions
+    inline int numberUserFunctions() const {
+        return numberUserFunctions_;
+    }
+    /// User function array
+    inline CbcUser ** userFunctionArray() const {
+        return userFunction_;
+    }
+    /// Copy of model on initial load (will contain output solutions)
+    inline OsiClpSolverInterface * originalSolver() const {
+        return originalSolver_;
+    }
+    /// Copy of model on initial load
+    inline CoinModel * originalCoinModel() const {
+        return originalCoinModel_;
+    }
+    /// Copy of model on initial load (will contain output solutions)
+    void setOriginalSolver(OsiClpSolverInterface * originalSolver);
+    /// Copy of model on initial load
+    void setOriginalCoinModel(CoinModel * originalCoinModel);
+    /// Number of cutgenerators
+    inline int numberCutGenerators() const {
+        return numberCutGenerators_;
+    }
+    /// Cut generator array
+    inline CglCutGenerator ** cutGeneratorArray() const {
+        return cutGenerator_;
+    }
+    /// Start time
+    inline double startTime() const {
+        return startTime_;
+    }
+    /// Whether to print to std::cout
+    inline void setPrinting(bool onOff) {
+        noPrinting_ = !onOff;
+    }
+    /// Where to start reading commands
+    inline void setReadMode(int value) {
+        readMode_ = value;
+    }
+    //@}
+private:
+    ///@name Private member data
+    //@{
+
+    /// Reference model
+    CbcModel model_;
+
+    /// Updated model
+    CbcModel * babModel_;
+
+    /// User functions
+    CbcUser ** userFunction_;
+    /** Status of user functions
+        0 - not used
+        1 - needs cbc_load
+        2 - available - data in coinModel
+        3 - data loaded - can do cbc_save
+    */
+    int * statusUserFunction_;
+    /// Copy of model on initial load (will contain output solutions)
+    OsiClpSolverInterface * originalSolver_;
+    /// Copy of model on initial load
+    CoinModel * originalCoinModel_;
+    /// Cut generators
+    CglCutGenerator ** cutGenerator_;
+    /// Number of user functions
+    int numberUserFunctions_;
+    /// Number of cut generators
+    int numberCutGenerators_;
+    /// Stop now stuff
+    CbcStopNow * callBack_;
+    /// Cpu time at instantiation
+    double startTime_;
+    /// Parameters and values
+    CbcOrClpParam * parameters_;
+    /// Number of parameters
+    int numberParameters_ ;
+    /// Whether to do miplib test
+    bool doMiplib_;
+    /// Whether to print to std::cout
+    bool noPrinting_;
+    /// Where to start reading commands
+    int readMode_;
+    //@}
+};
+//#############################################################################
+
+/// Structure to hold useful arrays
+typedef struct {
+    // Priorities
+    int * priorities_;
+    // SOS priorities
+    int * sosPriority_;
+    // Direction to branch first
+    int * branchDirection_;
+    // Input solution
+    double * primalSolution_;
+    // Down pseudo costs
+    double * pseudoDown_;
+    // Up pseudo costs
+    double * pseudoUp_;
+} CbcSolverUsefulData;
+
+
+/*! \brief A class to allow the use of unknown user functionality
+
+    For example, access to a modelling language (CbcAmpl).
+*/
+class CbcUser {
+
+public:
+    ///@name import/export methods
+    //@{
+    /*! \brief Import - gets full command arguments
+
+      \return
+      - -1 - no action
+      -  0 - data read in without error
+      -  1 - errors
+    */
+    virtual int importData(CbcSolver * /*model*/, int & /*argc*/, char ** /*argv[]*/) {
+        return -1;
+    }
+
+    /*! \brief Export
+
+      Values for mode:
+      - 1 OsiClpSolver
+      - 2 CbcModel
+      - add 10 if infeasible from odd situation
+    */
+    virtual void exportSolution(CbcSolver * /*model*/,
+                                int /*mode*/, const char * /*message*/ = NULL) {}
+
+    /// Export Data (i.e. at very end)
+    virtual void exportData(CbcSolver * /*model*/) {}
+
+    /// Get useful stuff
+    virtual void fillInformation(CbcSolver * /*model*/,
+                                 CbcSolverUsefulData & /*info*/) {}
+    //@}
+
+    ///@name usage methods
+    //@{
+    /// CoinModel if valid
+    inline CoinModel *coinModel() const {
+        return coinModel_;
+    }
+    /// Other info - needs expanding
+    virtual void * stuff() {
+        return NULL;
+    }
+    /// Name
+    inline std::string name() const {
+        return userName_;
+    }
+    /// Solve (whatever that means)
+    virtual void solve(CbcSolver * model, const char * options) = 0;
+    /// Returns true if function knows about option
+    virtual bool canDo(const char * options) = 0;
+    //@}
+
+    ///@name Constructors and destructors etc
+    //@{
+    /// Default Constructor
+    CbcUser();
+
+    /// Copy constructor
+    CbcUser(const CbcUser & rhs);
+
+    /// Assignment operator
+    CbcUser & operator=(const CbcUser& rhs);
+
+    /// Clone
+    virtual CbcUser * clone() const = 0;
+
+    /// Destructor
+    virtual ~CbcUser ();
+    //@}
+
+protected:
+    ///@name Private member data
+    //@{
+
+    /// CoinModel
+    CoinModel * coinModel_;
+
+    /// Name of user function
+    std::string userName_;
+
+//@}
+};
+//#############################################################################
+
+/*! \brief Support the use of a call back class to decide whether to stop
+
+  Definitely under construction.
+*/
+
+class CbcStopNow {
+
+public:
+    ///@name Decision methods
+    //@{
+    /*! \brief Import
+
+      Values for whereFrom:
+       - 1 after initial solve by dualsimplex etc
+       - 2 after preprocessing
+       - 3 just before branchAndBound (so user can override)
+       - 4 just after branchAndBound (before postprocessing)
+       - 5 after postprocessing
+       - 6 after a user called heuristic phase
+
+      \return 0 if good
+       nonzero return code to stop
+    */
+    virtual int callBack(CbcModel * /*currentSolver*/, int /*whereFrom*/) {
+        return 0;
+    }
+    //@}
+
+    ///@name Constructors and destructors etc
+    //@{
+    /// Default Constructor
+    CbcStopNow();
+
+    /** Copy constructor .
+     */
+    CbcStopNow(const CbcStopNow & rhs);
+
+    /// Assignment operator
+    CbcStopNow & operator=(const CbcStopNow& rhs);
+
+    /// Clone
+    virtual CbcStopNow * clone() const;
+
+    /// Destructor
+    virtual ~CbcStopNow ();
+    //@}
+
+private:
+    ///@name Private member data
+    //@{
+//@}
+};
+#endif
+
diff --git a/cbits/coin/CbcSolverAnalyze.cpp b/cbits/coin/CbcSolverAnalyze.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSolverAnalyze.cpp
@@ -0,0 +1,333 @@
+/* $Id: CbcSolverAnalyze.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*! \file CbcSolverAnalyze.cpp
+
+  Look to see if a constraint is all-integer (variables & coeffs), or could be
+  all integer. Consider whether one or two continuous variables can be declared
+  integer. John's comment is that integer preprocessing might do a better job,
+  so we should consider whether this routine should stay.
+
+  No hurry to get rid of it, in my opinion  -- lh, 091210 --
+
+*/
+
+#include "CbcConfig.h"
+#include "CoinPragma.hpp"
+
+#include "OsiClpSolverInterface.hpp"
+
+#include "ClpMessage.hpp"
+
+#include "CbcModel.hpp"
+
+
+#ifndef CBC_OTHER_SOLVER
+
+int * analyze(OsiClpSolverInterface * solverMod, int & numberChanged,
+		     double & increment, bool changeInt,
+		     CoinMessageHandler * generalMessageHandler, bool noPrinting)
+{
+    bool noPrinting_ = noPrinting;
+    OsiSolverInterface * solver = solverMod->clone();
+    char generalPrint[200];
+    if (0) {
+        // just get increment
+        CbcModel model(*solver);
+        model.analyzeObjective();
+        double increment2 = model.getCutoffIncrement();
+        printf("initial cutoff increment %g\n", increment2);
+    }
+    const double *objective = solver->getObjCoefficients() ;
+    const double *lower = solver->getColLower() ;
+    const double *upper = solver->getColUpper() ;
+    int numberColumns = solver->getNumCols() ;
+    int numberRows = solver->getNumRows();
+    double direction = solver->getObjSense();
+    int iRow, iColumn;
+
+    // Row copy
+    CoinPackedMatrix matrixByRow(*solver->getMatrixByRow());
+    const double * elementByRow = matrixByRow.getElements();
+    const int * column = matrixByRow.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+    const int * rowLength = matrixByRow.getVectorLengths();
+
+    // Column copy
+    CoinPackedMatrix  matrixByCol(*solver->getMatrixByCol());
+    const double * element = matrixByCol.getElements();
+    const int * row = matrixByCol.getIndices();
+    const CoinBigIndex * columnStart = matrixByCol.getVectorStarts();
+    const int * columnLength = matrixByCol.getVectorLengths();
+
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+
+    char * ignore = new char [numberRows];
+    int * changed = new int[numberColumns];
+    int * which = new int[numberRows];
+    double * changeRhs = new double[numberRows];
+    memset(changeRhs, 0, numberRows*sizeof(double));
+    memset(ignore, 0, numberRows);
+    numberChanged = 0;
+    int numberInteger = 0;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        if (upper[iColumn] > lower[iColumn] + 1.0e-8 && solver->isInteger(iColumn))
+            numberInteger++;
+    }
+    bool finished = false;
+    while (!finished) {
+        int saveNumberChanged = numberChanged;
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            int numberContinuous = 0;
+            double value1 = 0.0, value2 = 0.0;
+            bool allIntegerCoeff = true;
+            double sumFixed = 0.0;
+            int jColumn1 = -1, jColumn2 = -1;
+            for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+                int jColumn = column[j];
+                double value = elementByRow[j];
+                if (upper[jColumn] > lower[jColumn] + 1.0e-8) {
+                    if (!solver->isInteger(jColumn)) {
+                        if (numberContinuous == 0) {
+                            jColumn1 = jColumn;
+                            value1 = value;
+                        } else {
+                            jColumn2 = jColumn;
+                            value2 = value;
+                        }
+                        numberContinuous++;
+                    } else {
+                        if (fabs(value - floor(value + 0.5)) > 1.0e-12)
+                            allIntegerCoeff = false;
+                    }
+                } else {
+                    sumFixed += lower[jColumn] * value;
+                }
+            }
+            double low = rowLower[iRow];
+            if (low > -1.0e20) {
+                low -= sumFixed;
+                if (fabs(low - floor(low + 0.5)) > 1.0e-12)
+                    allIntegerCoeff = false;
+            }
+            double up = rowUpper[iRow];
+            if (up < 1.0e20) {
+                up -= sumFixed;
+                if (fabs(up - floor(up + 0.5)) > 1.0e-12)
+                    allIntegerCoeff = false;
+            }
+            if (!allIntegerCoeff)
+                continue; // can't do
+            if (numberContinuous == 1) {
+                // see if really integer
+                // This does not allow for complicated cases
+                if (low == up) {
+                    if (fabs(value1) > 1.0e-3) {
+                        value1 = 1.0 / value1;
+                        if (fabs(value1 - floor(value1 + 0.5)) < 1.0e-12) {
+                            // integer
+                            changed[numberChanged++] = jColumn1;
+                            solver->setInteger(jColumn1);
+                            if (upper[jColumn1] > 1.0e20)
+                                solver->setColUpper(jColumn1, 1.0e20);
+                            if (lower[jColumn1] < -1.0e20)
+                                solver->setColLower(jColumn1, -1.0e20);
+                        }
+                    }
+                } else {
+                    if (fabs(value1) > 1.0e-3) {
+                        value1 = 1.0 / value1;
+                        if (fabs(value1 - floor(value1 + 0.5)) < 1.0e-12) {
+                            // This constraint will not stop it being integer
+                            ignore[iRow] = 1;
+                        }
+                    }
+                }
+            } else if (numberContinuous == 2) {
+                if (low == up) {
+                    /* need general theory - for now just look at 2 cases -
+                       1 - +- 1 one in column and just costs i.e. matching objective
+                       2 - +- 1 two in column but feeds into G/L row which will try and minimize
+                    */
+                    if (fabs(value1) == 1.0 && value1*value2 == -1.0 && !lower[jColumn1]
+                            && !lower[jColumn2]) {
+                        int n = 0;
+                        int i;
+                        double objChange = direction * (objective[jColumn1] + objective[jColumn2]);
+                        double bound = CoinMin(upper[jColumn1], upper[jColumn2]);
+                        bound = CoinMin(bound, 1.0e20);
+                        for ( i = columnStart[jColumn1]; i < columnStart[jColumn1] + columnLength[jColumn1]; i++) {
+                            int jRow = row[i];
+                            double value = element[i];
+                            if (jRow != iRow) {
+                                which[n++] = jRow;
+                                changeRhs[jRow] = value;
+                            }
+                        }
+                        for ( i = columnStart[jColumn1]; i < columnStart[jColumn1] + columnLength[jColumn1]; i++) {
+                            int jRow = row[i];
+                            double value = element[i];
+                            if (jRow != iRow) {
+                                if (!changeRhs[jRow]) {
+                                    which[n++] = jRow;
+                                    changeRhs[jRow] = value;
+                                } else {
+                                    changeRhs[jRow] += value;
+                                }
+                            }
+                        }
+                        if (objChange >= 0.0) {
+                            // see if all rows OK
+                            bool good = true;
+                            for (i = 0; i < n; i++) {
+                                int jRow = which[i];
+                                double value = changeRhs[jRow];
+                                if (value) {
+                                    value *= bound;
+                                    if (rowLength[jRow] == 1) {
+                                        if (value > 0.0) {
+                                            double rhs = rowLower[jRow];
+                                            if (rhs > 0.0) {
+                                                double ratio = rhs / value;
+                                                if (fabs(ratio - floor(ratio + 0.5)) > 1.0e-12)
+                                                    good = false;
+                                            }
+                                        } else {
+                                            double rhs = rowUpper[jRow];
+                                            if (rhs < 0.0) {
+                                                double ratio = rhs / value;
+                                                if (fabs(ratio - floor(ratio + 0.5)) > 1.0e-12)
+                                                    good = false;
+                                            }
+                                        }
+                                    } else if (rowLength[jRow] == 2) {
+                                        if (value > 0.0) {
+                                            if (rowLower[jRow] > -1.0e20)
+                                                good = false;
+                                        } else {
+                                            if (rowUpper[jRow] < 1.0e20)
+                                                good = false;
+                                        }
+                                    } else {
+                                        good = false;
+                                    }
+                                }
+                            }
+                            if (good) {
+                                // both can be integer
+                                changed[numberChanged++] = jColumn1;
+                                solver->setInteger(jColumn1);
+                                if (upper[jColumn1] > 1.0e20)
+                                    solver->setColUpper(jColumn1, 1.0e20);
+                                if (lower[jColumn1] < -1.0e20)
+                                    solver->setColLower(jColumn1, -1.0e20);
+                                changed[numberChanged++] = jColumn2;
+                                solver->setInteger(jColumn2);
+                                if (upper[jColumn2] > 1.0e20)
+                                    solver->setColUpper(jColumn2, 1.0e20);
+                                if (lower[jColumn2] < -1.0e20)
+                                    solver->setColLower(jColumn2, -1.0e20);
+                            }
+                        }
+                        // clear
+                        for (i = 0; i < n; i++) {
+                            changeRhs[which[i]] = 0.0;
+                        }
+                    }
+                }
+            }
+        }
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (upper[iColumn] > lower[iColumn] + 1.0e-8 && !solver->isInteger(iColumn)) {
+                double value;
+                value = upper[iColumn];
+                if (value < 1.0e20 && fabs(value - floor(value + 0.5)) > 1.0e-12)
+                    continue;
+                value = lower[iColumn];
+                if (value > -1.0e20 && fabs(value - floor(value + 0.5)) > 1.0e-12)
+                    continue;
+                bool integer = true;
+                for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    if (!ignore[iRow]) {
+                        integer = false;
+                        break;
+                    }
+                }
+                if (integer) {
+                    // integer
+                    changed[numberChanged++] = iColumn;
+                    solver->setInteger(iColumn);
+                    if (upper[iColumn] > 1.0e20)
+                        solver->setColUpper(iColumn, 1.0e20);
+                    if (lower[iColumn] < -1.0e20)
+                        solver->setColLower(iColumn, -1.0e20);
+                }
+            }
+        }
+        finished = numberChanged == saveNumberChanged;
+    }
+    delete [] which;
+    delete [] changeRhs;
+    delete [] ignore;
+    //if (numberInteger&&!noPrinting_)
+    //printf("%d integer variables",numberInteger);
+    if (changeInt) {
+        //if (!noPrinting_) {
+        //if (numberChanged)
+        //  printf(" and %d variables made integer\n",numberChanged);
+        //else
+        //  printf("\n");
+        //}
+        delete [] ignore;
+        //increment=0.0;
+        if (!numberChanged) {
+            delete [] changed;
+            delete solver;
+            return NULL;
+        } else {
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (solver->isInteger(iColumn))
+                    solverMod->setInteger(iColumn);
+            }
+            delete solver;
+            return changed;
+        }
+    } else {
+        //if (!noPrinting_) {
+        //if (numberChanged)
+        //  printf(" and %d variables could be made integer\n",numberChanged);
+        //else
+        //  printf("\n");
+        //}
+        // just get increment
+        int logLevel = generalMessageHandler->logLevel();
+        CbcModel model(*solver);
+	if (!model.defaultHandler())
+	  model.passInMessageHandler(generalMessageHandler);
+        if (noPrinting_)
+            model.setLogLevel(0);
+        model.analyzeObjective();
+        generalMessageHandler->setLogLevel(logLevel);
+        double increment2 = model.getCutoffIncrement();
+        if (increment2 > increment && increment2 > 0.0) {
+            if (!noPrinting_) {
+                sprintf(generalPrint, "Cutoff increment increased from %g to %g", increment, increment2);
+                CoinMessages generalMessages = solverMod->getModelPtr()->messages();
+                generalMessageHandler->message(CLP_GENERAL, generalMessages)
+                << generalPrint
+                << CoinMessageEol;
+            }
+            increment = increment2;
+        }
+        delete solver;
+        numberChanged = 0;
+        delete [] changed;
+        return NULL;
+    }
+}
+#endif	// ifndef CBC_OTHER_SOLVER
+
diff --git a/cbits/coin/CbcSolverAnalyze.hpp b/cbits/coin/CbcSolverAnalyze.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSolverAnalyze.hpp
@@ -0,0 +1,21 @@
+/* $Id: CbcSolverAnalyze.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+/*! \file CbcSolverAnalyze.hpp
+    \brief Look to see if a constraint is all-integer (variables & coeffs), or could be
+  all integer.
+*/
+
+#ifndef CbcSolverAnalyze_H
+#define CbcSolverAnalyze_H
+
+
+int * analyze(OsiClpSolverInterface * solverMod, int & numberChanged,
+		     double & increment, bool changeInt,
+		     CoinMessageHandler * generalMessageHandler, bool noPrinting);
+		     
+#endif
+
diff --git a/cbits/coin/CbcSolverExpandKnapsack.cpp b/cbits/coin/CbcSolverExpandKnapsack.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSolverExpandKnapsack.cpp
@@ -0,0 +1,590 @@
+/* $Id: CbcSolverExpandKnapsack.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*! \file CbcSolverExpandKnapsack.cpp
+
+  Returns OsiSolverInterface (User should delete)
+  On entry numberKnapsack is maximum number of Total entries
+
+  Expanding possibilities of x*y, where x*y are both integers, constructing
+  a knapsack constraint. Results in a tighter model.
+
+*/
+
+#include "CbcConfig.h"
+#include "CoinPragma.hpp"
+
+#include "OsiSolverInterface.hpp"
+
+#include "CglStored.hpp"
+
+#ifndef COIN_HAS_LINK
+#define COIN_HAS_LINK
+#endif
+#ifdef COIN_HAS_LINK
+#include "CbcLinked.hpp"
+#endif
+
+#ifdef COIN_HAS_LINK
+
+OsiSolverInterface *
+expandKnapsack(CoinModel & model, int * whichColumn, int * knapsackStart,
+               int * knapsackRow, int &numberKnapsack,
+               CglStored & stored, int logLevel,
+               int fixedPriority, int SOSPriority, CoinModel & tightenedModel)
+{
+    int maxTotal = numberKnapsack;
+    // load from coin model
+    OsiSolverLink *si = new OsiSolverLink();
+    OsiSolverInterface * finalModel = NULL;
+    si->setDefaultMeshSize(0.001);
+    // need some relative granularity
+    si->setDefaultBound(100.0);
+    si->setDefaultMeshSize(0.01);
+    si->setDefaultBound(100000.0);
+    si->setIntegerPriority(1000);
+    si->setBiLinearPriority(10000);
+    si->load(model, true, logLevel);
+    // get priorities
+    const int * priorities = model.priorities();
+    int numberColumns = model.numberColumns();
+    if (priorities) {
+        OsiObject ** objects = si->objects();
+        int numberObjects = si->numberObjects();
+        for (int iObj = 0; iObj < numberObjects; iObj++) {
+            int iColumn = objects[iObj]->columnNumber();
+            if (iColumn >= 0 && iColumn < numberColumns) {
+#ifndef NDEBUG
+                OsiSimpleInteger * obj =
+                    dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ;
+#endif
+                assert (obj);
+                int iPriority = priorities[iColumn];
+                if (iPriority > 0)
+                    objects[iObj]->setPriority(iPriority);
+            }
+        }
+        if (fixedPriority > 0) {
+            si->setFixedPriority(fixedPriority);
+        }
+        if (SOSPriority < 0)
+            SOSPriority = 100000;
+    }
+    CoinModel coinModel = *si->coinModel();
+    assert(coinModel.numberRows() > 0);
+    tightenedModel = coinModel;
+    int numberRows = coinModel.numberRows();
+    // Mark variables
+    int * whichKnapsack = new int [numberColumns];
+    int iRow, iColumn;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++)
+        whichKnapsack[iColumn] = -1;
+    int kRow;
+    bool badModel = false;
+    // analyze
+    if (logLevel > 1) {
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            /* Just obvious one at first
+            positive non unit coefficients
+            all integer
+            positive rowUpper
+            for now - linear (but further down in code may use nonlinear)
+            column bounds should be tight
+            */
+            //double lower = coinModel.getRowLower(iRow);
+            double upper = coinModel.getRowUpper(iRow);
+            if (upper < 1.0e10) {
+                CoinModelLink triple = coinModel.firstInRow(iRow);
+                bool possible = true;
+                int n = 0;
+                int n1 = 0;
+                while (triple.column() >= 0) {
+                    int iColumn = triple.column();
+                    const char *  el = coinModel.getElementAsString(iRow, iColumn);
+                    if (!strcmp("Numeric", el)) {
+                        if (coinModel.columnLower(iColumn) == coinModel.columnUpper(iColumn)) {
+                            triple = coinModel.next(triple);
+                            continue; // fixed
+                        }
+                        double value = coinModel.getElement(iRow, iColumn);
+                        if (value < 0.0) {
+                            possible = false;
+                        } else {
+                            n++;
+                            if (value == 1.0)
+                                n1++;
+                            if (coinModel.columnLower(iColumn) < 0.0)
+                                possible = false;
+                            if (!coinModel.isInteger(iColumn))
+                                possible = false;
+                            if (whichKnapsack[iColumn] >= 0)
+                                possible = false;
+                        }
+                    } else {
+                        possible = false; // non linear
+                    }
+                    triple = coinModel.next(triple);
+                }
+                if (n - n1 > 1 && possible) {
+                    double lower = coinModel.getRowLower(iRow);
+                    double upper = coinModel.getRowUpper(iRow);
+                    CoinModelLink triple = coinModel.firstInRow(iRow);
+                    while (triple.column() >= 0) {
+                        int iColumn = triple.column();
+                        lower -= coinModel.columnLower(iColumn) * triple.value();
+                        upper -= coinModel.columnLower(iColumn) * triple.value();
+                        triple = coinModel.next(triple);
+                    }
+                    printf("%d is possible %g <=", iRow, lower);
+                    // print
+                    triple = coinModel.firstInRow(iRow);
+                    while (triple.column() >= 0) {
+                        int iColumn = triple.column();
+                        if (coinModel.columnLower(iColumn) != coinModel.columnUpper(iColumn))
+                            printf(" (%d,el %g up %g)", iColumn, triple.value(),
+                                   coinModel.columnUpper(iColumn) - coinModel.columnLower(iColumn));
+                        triple = coinModel.next(triple);
+                    }
+                    printf(" <= %g\n", upper);
+                }
+            }
+        }
+    }
+    numberKnapsack = 0;
+    for (kRow = 0; kRow < numberRows; kRow++) {
+        iRow = kRow;
+        /* Just obvious one at first
+           positive non unit coefficients
+           all integer
+           positive rowUpper
+           for now - linear (but further down in code may use nonlinear)
+           column bounds should be tight
+        */
+        //double lower = coinModel.getRowLower(iRow);
+        double upper = coinModel.getRowUpper(iRow);
+        if (upper < 1.0e10) {
+            CoinModelLink triple = coinModel.firstInRow(iRow);
+            bool possible = true;
+            int n = 0;
+            int n1 = 0;
+            while (triple.column() >= 0) {
+                int iColumn = triple.column();
+                const char *  el = coinModel.getElementAsString(iRow, iColumn);
+                if (!strcmp("Numeric", el)) {
+                    if (coinModel.columnLower(iColumn) == coinModel.columnUpper(iColumn)) {
+                        triple = coinModel.next(triple);
+                        continue; // fixed
+                    }
+                    double value = coinModel.getElement(iRow, iColumn);
+                    if (value < 0.0) {
+                        possible = false;
+                    } else {
+                        n++;
+                        if (value == 1.0)
+                            n1++;
+                        if (coinModel.columnLower(iColumn) < 0.0)
+                            possible = false;
+                        if (!coinModel.isInteger(iColumn))
+                            possible = false;
+                        if (whichKnapsack[iColumn] >= 0)
+                            possible = false;
+                    }
+                } else {
+                    possible = false; // non linear
+                }
+                triple = coinModel.next(triple);
+            }
+            if (n - n1 > 1 && possible) {
+                // try
+                CoinModelLink triple = coinModel.firstInRow(iRow);
+                while (triple.column() >= 0) {
+                    int iColumn = triple.column();
+                    if (coinModel.columnLower(iColumn) != coinModel.columnUpper(iColumn))
+                        whichKnapsack[iColumn] = numberKnapsack;
+                    triple = coinModel.next(triple);
+                }
+                knapsackRow[numberKnapsack++] = iRow;
+            }
+        }
+    }
+    if (logLevel > 0)
+        printf("%d out of %d candidate rows are possible\n", numberKnapsack, numberRows);
+    // Check whether we can get rid of nonlinearities
+    /* mark rows
+       -2 in knapsack and other variables
+       -1 not involved
+       n only in knapsack n
+    */
+    int * markRow = new int [numberRows];
+    for (iRow = 0; iRow < numberRows; iRow++)
+        markRow[iRow] = -1;
+    int canDo = 1; // OK and linear
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        CoinModelLink triple = coinModel.firstInColumn(iColumn);
+        int iKnapsack = whichKnapsack[iColumn];
+        bool linear = true;
+        // See if quadratic objective
+        const char * expr = coinModel.getColumnObjectiveAsString(iColumn);
+        if (strcmp(expr, "Numeric")) {
+            linear = false;
+        }
+        while (triple.row() >= 0) {
+            int iRow = triple.row();
+            if (iKnapsack >= 0) {
+                if (markRow[iRow] == -1) {
+                    markRow[iRow] = iKnapsack;
+                } else if (markRow[iRow] != iKnapsack) {
+                    markRow[iRow] = -2;
+                }
+            }
+            const char * expr = coinModel.getElementAsString(iRow, iColumn);
+            if (strcmp(expr, "Numeric")) {
+                linear = false;
+            }
+            triple = coinModel.next(triple);
+        }
+        if (!linear) {
+            if (whichKnapsack[iColumn] < 0) {
+                canDo = 0;
+                break;
+            } else {
+                canDo = 2;
+            }
+        }
+    }
+    int * markKnapsack = NULL;
+    double * coefficient = NULL;
+    double * linear = NULL;
+    int * whichRow = NULL;
+    int * lookupRow = NULL;
+    badModel = (canDo == 0);
+    if (numberKnapsack && canDo) {
+        /* double check - OK if
+           no nonlinear
+           nonlinear only on columns in knapsack
+           nonlinear only on columns in knapsack * ONE other - same for all in knapsack
+           AND that is only row connected to knapsack
+           (theoretically could split knapsack if two other and small numbers)
+           also ONE could be ONE expression - not just a variable
+        */
+        int iKnapsack;
+        markKnapsack = new int [numberKnapsack];
+        coefficient = new double [numberKnapsack];
+        linear = new double [numberColumns];
+        for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++)
+            markKnapsack[iKnapsack] = -1;
+        if (canDo == 2) {
+            for (iRow = -1; iRow < numberRows; iRow++) {
+                int numberOdd;
+                CoinPackedMatrix * row = coinModel.quadraticRow(iRow, linear, numberOdd);
+                if (row) {
+                    // see if valid
+                    const double * element = row->getElements();
+                    const int * column = row->getIndices();
+                    const CoinBigIndex * columnStart = row->getVectorStarts();
+                    const int * columnLength = row->getVectorLengths();
+                    int numberLook = row->getNumCols();
+                    for (int i = 0; i < numberLook; i++) {
+                        int iKnapsack = whichKnapsack[i];
+                        if (iKnapsack < 0) {
+                            // might be able to swap - but for now can't have knapsack in
+                            for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                                int iColumn = column[j];
+                                if (whichKnapsack[iColumn] >= 0) {
+                                    canDo = 0; // no good
+                                    badModel = true;
+                                    break;
+                                }
+                            }
+                        } else {
+                            // OK if in same knapsack - or maybe just one
+                            int marked = markKnapsack[iKnapsack];
+                            for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                                int iColumn = column[j];
+                                if (whichKnapsack[iColumn] != iKnapsack && whichKnapsack[iColumn] >= 0) {
+                                    canDo = 0; // no good
+                                    badModel = true;
+                                    break;
+                                } else if (marked == -1) {
+                                    markKnapsack[iKnapsack] = iColumn;
+                                    marked = iColumn;
+                                    coefficient[iKnapsack] = element[j];
+                                    coinModel.associateElement(coinModel.columnName(iColumn), 1.0);
+                                } else if (marked != iColumn) {
+                                    badModel = true;
+                                    canDo = 0; // no good
+                                    break;
+                                } else {
+                                    // could manage with different coefficients - but for now ...
+                                    assert(coefficient[iKnapsack] == element[j]);
+                                }
+                            }
+                        }
+                    }
+                    delete row;
+                }
+            }
+        }
+        if (canDo) {
+            // for any rows which are cuts
+            whichRow = new int [numberRows];
+            lookupRow = new int [numberRows];
+            bool someNonlinear = false;
+            double maxCoefficient = 1.0;
+            for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) {
+                if (markKnapsack[iKnapsack] >= 0) {
+                    someNonlinear = true;
+                    int iColumn = markKnapsack[iKnapsack];
+                    maxCoefficient = CoinMax(maxCoefficient, fabs(coefficient[iKnapsack] * coinModel.columnUpper(iColumn)));
+                }
+            }
+            if (someNonlinear) {
+                // associate all columns to stop possible error messages
+                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    coinModel.associateElement(coinModel.columnName(iColumn), 1.0);
+                }
+            }
+            ClpSimplex tempModel;
+            tempModel.loadProblem(coinModel);
+            // Create final model - first without knapsacks
+            int nCol = 0;
+            int nRow = 0;
+            for (iRow = 0; iRow < numberRows; iRow++) {
+                if (markRow[iRow] < 0) {
+                    lookupRow[iRow] = nRow;
+                    whichRow[nRow++] = iRow;
+                } else {
+                    lookupRow[iRow] = -1;
+                }
+            }
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (whichKnapsack[iColumn] < 0)
+                    whichColumn[nCol++] = iColumn;
+            }
+            ClpSimplex finalModelX(&tempModel, nRow, whichRow, nCol, whichColumn, false, false, false);
+            OsiClpSolverInterface finalModelY(&finalModelX, true);
+            finalModel = finalModelY.clone();
+            finalModelY.releaseClp();
+            // Put back priorities
+            const int * priorities = model.priorities();
+            if (priorities) {
+                finalModel->findIntegers(false);
+                OsiObject ** objects = finalModel->objects();
+                int numberObjects = finalModel->numberObjects();
+                for (int iObj = 0; iObj < numberObjects; iObj++) {
+                    int iColumn = objects[iObj]->columnNumber();
+                    if (iColumn >= 0 && iColumn < nCol) {
+#ifndef NDEBUG
+                        OsiSimpleInteger * obj =
+                            dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ;
+#endif
+                        assert (obj);
+                        int iPriority = priorities[whichColumn[iColumn]];
+                        if (iPriority > 0)
+                            objects[iObj]->setPriority(iPriority);
+                    }
+                }
+            }
+            for (iRow = 0; iRow < numberRows; iRow++) {
+                whichRow[iRow] = iRow;
+            }
+            int numberOther = finalModel->getNumCols();
+            int nLargest = 0;
+            int nelLargest = 0;
+            int nTotal = 0;
+            for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) {
+                iRow = knapsackRow[iKnapsack];
+                int nCreate = maxTotal;
+                int nelCreate = coinModel.expandKnapsack(iRow, nCreate, NULL, NULL, NULL, NULL);
+                if (nelCreate < 0)
+                    badModel = true;
+                nTotal += nCreate;
+                nLargest = CoinMax(nLargest, nCreate);
+                nelLargest = CoinMax(nelLargest, nelCreate);
+            }
+            if (nTotal > maxTotal)
+                badModel = true;
+            if (!badModel) {
+                // Now arrays for building
+                nelLargest = CoinMax(nelLargest, nLargest) + 1;
+                double * buildObj = new double [nLargest];
+                double * buildElement = new double [nelLargest];
+                int * buildStart = new int[nLargest+1];
+                int * buildRow = new int[nelLargest];
+                // alow for integers in knapsacks
+                OsiObject ** object = new OsiObject * [numberKnapsack+nTotal];
+                int nSOS = 0;
+                int nObj = numberKnapsack;
+                for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) {
+                    knapsackStart[iKnapsack] = finalModel->getNumCols();
+                    iRow = knapsackRow[iKnapsack];
+                    int nCreate = 10000;
+                    coinModel.expandKnapsack(iRow, nCreate, buildObj, buildStart, buildRow, buildElement);
+                    // Redo row numbers
+                    for (iColumn = 0; iColumn < nCreate; iColumn++) {
+                        for (int j = buildStart[iColumn]; j < buildStart[iColumn+1]; j++) {
+                            int jRow = buildRow[j];
+                            jRow = lookupRow[jRow];
+                            assert (jRow >= 0 && jRow < nRow);
+                            buildRow[j] = jRow;
+                        }
+                    }
+                    finalModel->addCols(nCreate, buildStart, buildRow, buildElement, NULL, NULL, buildObj);
+                    int numberFinal = finalModel->getNumCols();
+                    for (iColumn = numberOther; iColumn < numberFinal; iColumn++) {
+                        if (markKnapsack[iKnapsack] < 0) {
+                            finalModel->setColUpper(iColumn, maxCoefficient);
+                            finalModel->setInteger(iColumn);
+                        } else {
+                            finalModel->setColUpper(iColumn, maxCoefficient + 1.0);
+                            finalModel->setInteger(iColumn);
+                        }
+                        OsiSimpleInteger * sosObject = new OsiSimpleInteger(finalModel, iColumn);
+                        sosObject->setPriority(1000000);
+                        object[nObj++] = sosObject;
+                        buildRow[iColumn-numberOther] = iColumn;
+                        buildElement[iColumn-numberOther] = 1.0;
+                    }
+                    if (markKnapsack[iKnapsack] < 0) {
+                        // convexity row
+                        finalModel->addRow(numberFinal - numberOther, buildRow, buildElement, 1.0, 1.0);
+                    } else {
+                        int iColumn = markKnapsack[iKnapsack];
+                        int n = numberFinal - numberOther;
+                        buildRow[n] = iColumn;
+                        buildElement[n++] = -fabs(coefficient[iKnapsack]);
+                        // convexity row (sort of)
+                        finalModel->addRow(n, buildRow, buildElement, 0.0, 0.0);
+                        OsiSOS * sosObject = new OsiSOS(finalModel, n - 1, buildRow, NULL, 1);
+                        sosObject->setPriority(iKnapsack + SOSPriority);
+                        // Say not integral even if is (switch off heuristics)
+                        sosObject->setIntegerValued(false);
+                        object[nSOS++] = sosObject;
+                    }
+                    numberOther = numberFinal;
+                }
+                finalModel->addObjects(nObj, object);
+                for (iKnapsack = 0; iKnapsack < nObj; iKnapsack++)
+                    delete object[iKnapsack];
+                delete [] object;
+                // Can we move any rows to cuts
+                const int * cutMarker = coinModel.cutMarker();
+                if (cutMarker && 0) {
+                    printf("AMPL CUTS OFF until global cuts fixed\n");
+                    cutMarker = NULL;
+                }
+                if (cutMarker) {
+                    // Row copy
+                    const CoinPackedMatrix * matrixByRow = finalModel->getMatrixByRow();
+                    const double * elementByRow = matrixByRow->getElements();
+                    const int * column = matrixByRow->getIndices();
+                    const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+                    const int * rowLength = matrixByRow->getVectorLengths();
+
+                    const double * rowLower = finalModel->getRowLower();
+                    const double * rowUpper = finalModel->getRowUpper();
+                    int nDelete = 0;
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                        if (cutMarker[iRow] && lookupRow[iRow] >= 0) {
+                            int jRow = lookupRow[iRow];
+                            whichRow[nDelete++] = jRow;
+                            int start = rowStart[jRow];
+                            stored.addCut(rowLower[jRow], rowUpper[jRow],
+                                          rowLength[jRow], column + start, elementByRow + start);
+                        }
+                    }
+                    finalModel->deleteRows(nDelete, whichRow);
+                }
+                knapsackStart[numberKnapsack] = finalModel->getNumCols();
+                delete [] buildObj;
+                delete [] buildElement;
+                delete [] buildStart;
+                delete [] buildRow;
+                finalModel->writeMps("full");
+            }
+        }
+    }
+    delete [] whichKnapsack;
+    delete [] markRow;
+    delete [] markKnapsack;
+    delete [] coefficient;
+    delete [] linear;
+    delete [] whichRow;
+    delete [] lookupRow;
+    delete si;
+    si = NULL;
+    if (!badModel && finalModel) {
+        finalModel->setDblParam(OsiObjOffset, coinModel.objectiveOffset());
+        return finalModel;
+    } else {
+        delete finalModel;
+        printf("can't make knapsacks - did you set fixedPriority (extra1)\n");
+        return NULL;
+    }
+}
+#endif	//COIN_HAS_LINK
+
+
+// Fills in original solution (coinModel length)
+void
+afterKnapsack(const CoinModel & coinModel2, const int * whichColumn, const int * knapsackStart,
+	      const int * knapsackRow, int numberKnapsack,
+	      const double * knapsackSolution, double * solution, int logLevel)
+{
+   CoinModel coinModel = coinModel2;
+   int numberColumns = coinModel.numberColumns();
+   int iColumn;
+   // associate all columns to stop possible error messages
+   for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      coinModel.associateElement(coinModel.columnName(iColumn),1.0);
+   }
+   CoinZeroN(solution,numberColumns);
+   int nCol=knapsackStart[0];
+   for (iColumn=0;iColumn<nCol;iColumn++) {
+      int jColumn = whichColumn[iColumn];
+      solution[jColumn]=knapsackSolution[iColumn];
+   }
+   int * buildRow = new int [numberColumns]; // wild overkill
+   double * buildElement = new double [numberColumns];
+   int iKnapsack;
+   for (iKnapsack=0;iKnapsack<numberKnapsack;iKnapsack++) {
+      int k=-1;
+      for (iColumn=knapsackStart[iKnapsack];iColumn<knapsackStart[iKnapsack+1];iColumn++) {
+	 if (knapsackSolution[iColumn]>1.0e-5) {
+	    if (k>=0) {
+	       printf("Two nonzero values for knapsack %d at (%d,%g) and (%d,%g)\n",iKnapsack,
+		      k,knapsackSolution[k],iColumn,knapsackSolution[iColumn]);
+	       abort();
+	    }
+	    k=iColumn;
+	    assert (fabs(floor(knapsackSolution[iColumn]+0.5)-knapsackSolution[iColumn])<1.0e-5);
+	 }
+      }
+      if (k>=0) {
+	 int iRow = knapsackRow[iKnapsack];
+	 int nCreate = 10000;
+	 int nel=coinModel.expandKnapsack(iRow,nCreate,NULL,NULL,buildRow,buildElement,k-knapsackStart[iKnapsack]);
+	 assert (nel);
+	 if (logLevel>0)
+	    printf("expanded column %d in knapsack %d has %d nonzero entries:\n",
+		   k-knapsackStart[iKnapsack],iKnapsack,nel);
+	 for (int i=0;i<nel;i++) {
+	    int jColumn = buildRow[i];
+	    double value = buildElement[i];
+	    if (logLevel>0)
+	       printf("%d - original %d has value %g\n",i,jColumn,value);
+	    solution[jColumn]=value;
+	 }
+      }
+   }
+   delete [] buildRow;
+   delete [] buildElement;
+#if 0
+   for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (solution[iColumn]>1.0e-5&&coinModel.isInteger(iColumn))
+	 printf("%d %g\n",iColumn,solution[iColumn]);
+   }
+#endif
+}
diff --git a/cbits/coin/CbcSolverExpandKnapsack.hpp b/cbits/coin/CbcSolverExpandKnapsack.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSolverExpandKnapsack.hpp
@@ -0,0 +1,28 @@
+/* $Id: CbcSolverExpandKnapsack.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+/*! \file CbcSolverExpandKnapsack.hpp
+    \brief Expanding possibilities of x*y, where x*y are both integers, constructing
+  a knapsack constraint. Results in a tighter model.
+*/
+
+
+#ifndef CbcSolverExpandKnapsack_H
+#define CbcSolverExpandKnapsack_H
+
+OsiSolverInterface *
+expandKnapsack(CoinModel & model, int * whichColumn, int * knapsackStart,
+               int * knapsackRow, int &numberKnapsack,
+               CglStored & stored, int logLevel,
+               int fixedPriority, int SOSPriority, CoinModel & tightenedModel);
+
+void
+afterKnapsack(const CoinModel & coinModel2, const int * whichColumn, const int * knapsackStart,
+              const int * knapsackRow, int numberKnapsack,
+              const double * knapsackSolution, double * solution, int logLevel);
+
+#endif
+
diff --git a/cbits/coin/CbcSolverHeuristics.cpp b/cbits/coin/CbcSolverHeuristics.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSolverHeuristics.cpp
@@ -0,0 +1,1689 @@
+/* $Id: CbcSolverHeuristics.cpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+/*! \file CbcSolverHeuristics.cpp
+    \brief Second level routines for the cbc stand-alone solver.
+*/
+
+#include "CbcConfig.h"
+#include "CoinPragma.hpp"
+
+
+#include "CoinTime.hpp"
+
+#include "OsiClpSolverInterface.hpp"
+
+#include "ClpPresolve.hpp"
+
+#include "CbcOrClpParam.hpp"
+
+#include "CbcModel.hpp"
+
+#include "CbcHeuristicLocal.hpp"
+#include "CbcHeuristicPivotAndFix.hpp"
+//#include "CbcHeuristicPivotAndComplement.hpp"
+#include "CbcHeuristicRandRound.hpp"
+#include "CbcHeuristicGreedy.hpp"
+#include "CbcHeuristicFPump.hpp"
+#include "CbcHeuristicRINS.hpp"
+
+#include "CbcHeuristicDiveCoefficient.hpp"
+#include "CbcHeuristicDiveFractional.hpp"
+#include "CbcHeuristicDiveGuided.hpp"
+#include "CbcHeuristicDiveVectorLength.hpp"
+#include "CbcHeuristicDivePseudoCost.hpp"
+#include "CbcHeuristicDiveLineSearch.hpp"
+
+#include "CbcStrategy.hpp"
+#include "OsiAuxInfo.hpp"
+
+#include "ClpSimplexOther.hpp"
+
+// Crunch down model
+void
+crunchIt(ClpSimplex * model)
+{
+#ifdef JJF_ZERO
+    model->dual();
+#else
+    int numberColumns = model->numberColumns();
+    int numberRows = model->numberRows();
+    // Use dual region
+    double * rhs = model->dualRowSolution();
+    int * whichRow = new int[3*numberRows];
+    int * whichColumn = new int[2*numberColumns];
+    int nBound;
+    ClpSimplex * small = static_cast<ClpSimplexOther *> (model)->crunch(rhs, whichRow, whichColumn,
+                         nBound, false, false);
+    if (small) {
+        small->dual();
+        if (small->problemStatus() == 0) {
+            model->setProblemStatus(0);
+            static_cast<ClpSimplexOther *> (model)->afterCrunch(*small, whichRow, whichColumn, nBound);
+        } else if (small->problemStatus() != 3) {
+            model->setProblemStatus(1);
+        } else {
+            if (small->problemStatus() == 3) {
+                // may be problems
+                small->computeObjectiveValue();
+                model->setObjectiveValue(small->objectiveValue());
+                model->setProblemStatus(3);
+            } else {
+                model->setProblemStatus(3);
+            }
+        }
+        delete small;
+    } else {
+        model->setProblemStatus(1);
+    }
+    delete [] whichRow;
+    delete [] whichColumn;
+#endif
+}
+/*
+  On input
+  doAction - 0 just fix in original and return NULL
+             1 return fixed non-presolved solver
+             2 as one but use presolve Inside this
+	     3 use presolve and fix ones with large cost
+             ? do heuristics and set best solution
+	     ? do BAB and just set best solution
+	     10+ then use lastSolution and relax a few
+             -2 cleanup afterwards if using 2
+  On output - number fixed
+*/
+OsiClpSolverInterface *
+fixVubs(CbcModel & model, int skipZero2,
+        int & doAction,
+        CoinMessageHandler * /*generalMessageHandler*/,
+        const double * lastSolution, double dextra[6],
+        int extra[5])
+{
+    if (doAction == 11 && !lastSolution)
+        lastSolution = model.bestSolution();
+    assert (((doAction >= 0 && doAction <= 3) && !lastSolution) || (doAction == 11 && lastSolution));
+    double fractionIntFixed = dextra[3];
+    double fractionFixed = dextra[4];
+    double fixAbove = dextra[2];
+    double fixAboveValue = (dextra[5] > 0.0) ? dextra[5] : 1.0;
+#ifdef COIN_DETAIL
+    double time1 = CoinCpuTime();
+#endif
+    int leaveIntFree = extra[1];
+    OsiSolverInterface * originalSolver = model.solver();
+    OsiClpSolverInterface * originalClpSolver = dynamic_cast< OsiClpSolverInterface*> (originalSolver);
+    ClpSimplex * originalLpSolver = originalClpSolver->getModelPtr();
+    int * originalColumns = NULL;
+    OsiClpSolverInterface * clpSolver;
+    ClpSimplex * lpSolver;
+    ClpPresolve pinfo;
+    assert(originalSolver->getObjSense() > 0);
+    if (doAction == 2 || doAction == 3) {
+        double * saveLB = NULL;
+        double * saveUB = NULL;
+        int numberColumns = originalLpSolver->numberColumns();
+        if (fixAbove > 0.0) {
+#ifdef COIN_DETAIL
+            double time1 = CoinCpuTime();
+#endif
+            originalClpSolver->initialSolve();
+            COIN_DETAIL_PRINT(printf("first solve took %g seconds\n", CoinCpuTime() - time1));
+            double * columnLower = originalLpSolver->columnLower() ;
+            double * columnUpper = originalLpSolver->columnUpper() ;
+            const double * solution = originalLpSolver->primalColumnSolution();
+            saveLB = CoinCopyOfArray(columnLower, numberColumns);
+            saveUB = CoinCopyOfArray(columnUpper, numberColumns);
+            const double * objective = originalLpSolver->getObjCoefficients() ;
+            int iColumn;
+            int nFix = 0;
+            int nArt = 0;
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (objective[iColumn] > fixAbove) {
+                    if (solution[iColumn] < columnLower[iColumn] + 1.0e-8) {
+                        columnUpper[iColumn] = columnLower[iColumn];
+                        nFix++;
+                    } else {
+                        nArt++;
+                    }
+                } else if (objective[iColumn] < -fixAbove) {
+                    if (solution[iColumn] > columnUpper[iColumn] - 1.0e-8) {
+                        columnLower[iColumn] = columnUpper[iColumn];
+                        nFix++;
+                    } else {
+                        nArt++;
+                    }
+                }
+            }
+            COIN_DETAIL_PRINT(printf("%d artificials fixed, %d left as in solution\n", nFix, nArt));
+            lpSolver = pinfo.presolvedModel(*originalLpSolver, 1.0e-8, true, 10);
+            if (!lpSolver || doAction == 2) {
+                // take off fixing in original
+                memcpy(columnLower, saveLB, numberColumns*sizeof(double));
+                memcpy(columnUpper, saveUB, numberColumns*sizeof(double));
+            }
+            delete [] saveLB;
+            delete [] saveUB;
+            if (!lpSolver) {
+                // try again
+                pinfo.destroyPresolve();
+                lpSolver = pinfo.presolvedModel(*originalLpSolver, 1.0e-8, true, 10);
+                assert (lpSolver);
+            }
+        } else {
+            lpSolver = pinfo.presolvedModel(*originalLpSolver, 1.0e-8, true, 10);
+            assert (lpSolver);
+        }
+        clpSolver = new OsiClpSolverInterface(lpSolver, true);
+        assert(lpSolver == clpSolver->getModelPtr());
+        numberColumns = lpSolver->numberColumns();
+        originalColumns = CoinCopyOfArray(pinfo.originalColumns(), numberColumns);
+        doAction = 1;
+    } else {
+        OsiSolverInterface * solver = originalSolver->clone();
+        clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+        lpSolver = clpSolver->getModelPtr();
+    }
+    // Tighten bounds
+    lpSolver->tightenPrimalBounds(0.0, 11, true);
+    int numberColumns = clpSolver->getNumCols() ;
+    double * saveColumnLower = CoinCopyOfArray(lpSolver->columnLower(), numberColumns);
+    double * saveColumnUpper = CoinCopyOfArray(lpSolver->columnUpper(), numberColumns);
+    //char generalPrint[200];
+    const double *objective = lpSolver->getObjCoefficients() ;
+    double *columnLower = lpSolver->columnLower() ;
+    double *columnUpper = lpSolver->columnUpper() ;
+    int numberRows = clpSolver->getNumRows();
+    int iRow, iColumn;
+
+    // Row copy
+    CoinPackedMatrix matrixByRow(*clpSolver->getMatrixByRow());
+    const double * elementByRow = matrixByRow.getElements();
+    const int * column = matrixByRow.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+    const int * rowLength = matrixByRow.getVectorLengths();
+
+    // Column copy
+    CoinPackedMatrix  matrixByCol(*clpSolver->getMatrixByCol());
+    //const double * element = matrixByCol.getElements();
+    const int * row = matrixByCol.getIndices();
+    const CoinBigIndex * columnStart = matrixByCol.getVectorStarts();
+    const int * columnLength = matrixByCol.getVectorLengths();
+
+    const double * rowLower = clpSolver->getRowLower();
+    const double * rowUpper = clpSolver->getRowUpper();
+
+    // Get maximum size of VUB tree
+    // otherColumn is one fixed to 0 if this one zero
+    int nEl = matrixByCol.getNumElements();
+    CoinBigIndex * fixColumn = new CoinBigIndex [numberColumns+1];
+    int * otherColumn = new int [nEl];
+    int * fix = new int[numberColumns];
+    char * mark = new char [numberColumns];
+    memset(mark, 0, numberColumns);
+    int numberInteger = 0;
+    int numberOther = 0;
+    fixColumn[0] = 0;
+    double large = lpSolver->largeValue(); // treat bounds > this as infinite
+#ifndef NDEBUG
+    double large2 = 1.0e10 * large;
+#endif
+    double tolerance = lpSolver->primalTolerance();
+    int * check = new int[numberRows];
+    for (iRow = 0; iRow < numberRows; iRow++) {
+        check[iRow] = -2; // don't check
+        if (rowLower[iRow] < -1.0e6 && rowUpper[iRow] > 1.0e6)
+            continue;// unlikely
+        // possible row
+        int numberPositive = 0;
+        int iPositive = -1;
+        int numberNegative = 0;
+        int iNegative = -1;
+        CoinBigIndex rStart = rowStart[iRow];
+        CoinBigIndex rEnd = rowStart[iRow] + rowLength[iRow];
+        CoinBigIndex j;
+        int kColumn;
+        for (j = rStart; j < rEnd; ++j) {
+            double value = elementByRow[j];
+            kColumn = column[j];
+            if (columnUpper[kColumn] > columnLower[kColumn]) {
+                if (value > 0.0) {
+                    numberPositive++;
+                    iPositive = kColumn;
+                } else {
+                    numberNegative++;
+                    iNegative = kColumn;
+                }
+            }
+        }
+        if (numberPositive == 1 && numberNegative == 1)
+            check[iRow] = -1; // try both
+        if (numberPositive == 1 && rowLower[iRow] > -1.0e20)
+            check[iRow] = iPositive;
+        else if (numberNegative == 1 && rowUpper[iRow] < 1.0e20)
+            check[iRow] = iNegative;
+    }
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        fix[iColumn] = -1;
+        if (columnUpper[iColumn] > columnLower[iColumn] + 1.0e-8) {
+            if (clpSolver->isInteger(iColumn))
+                numberInteger++;
+            if (columnLower[iColumn] == 0.0) {
+                bool infeasible = false;
+                fix[iColumn] = 0;
+                // fake upper bound
+                double saveUpper = columnUpper[iColumn];
+                columnUpper[iColumn] = 0.0;
+                for (CoinBigIndex i = columnStart[iColumn];
+                        i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+                    iRow = row[i];
+                    if (check[iRow] != -1 && check[iRow] != iColumn)
+                        continue; // unlikely
+                    // possible row
+                    int infiniteUpper = 0;
+                    int infiniteLower = 0;
+                    double maximumUp = 0.0;
+                    double maximumDown = 0.0;
+                    double newBound;
+                    CoinBigIndex rStart = rowStart[iRow];
+                    CoinBigIndex rEnd = rowStart[iRow] + rowLength[iRow];
+                    CoinBigIndex j;
+                    int kColumn;
+                    // Compute possible lower and upper ranges
+                    for (j = rStart; j < rEnd; ++j) {
+                        double value = elementByRow[j];
+                        kColumn = column[j];
+                        if (value > 0.0) {
+                            if (columnUpper[kColumn] >= large) {
+                                ++infiniteUpper;
+                            } else {
+                                maximumUp += columnUpper[kColumn] * value;
+                            }
+                            if (columnLower[kColumn] <= -large) {
+                                ++infiniteLower;
+                            } else {
+                                maximumDown += columnLower[kColumn] * value;
+                            }
+                        } else if (value < 0.0) {
+                            if (columnUpper[kColumn] >= large) {
+                                ++infiniteLower;
+                            } else {
+                                maximumDown += columnUpper[kColumn] * value;
+                            }
+                            if (columnLower[kColumn] <= -large) {
+                                ++infiniteUpper;
+                            } else {
+                                maximumUp += columnLower[kColumn] * value;
+                            }
+                        }
+                    }
+                    // Build in a margin of error
+                    maximumUp += 1.0e-8 * fabs(maximumUp);
+                    maximumDown -= 1.0e-8 * fabs(maximumDown);
+                    double maxUp = maximumUp + infiniteUpper * 1.0e31;
+                    double maxDown = maximumDown - infiniteLower * 1.0e31;
+                    if (maxUp <= rowUpper[iRow] + tolerance &&
+                            maxDown >= rowLower[iRow] - tolerance) {
+                        //printf("Redundant row in vubs %d\n",iRow);
+                    } else {
+                        if (maxUp < rowLower[iRow] - 100.0*tolerance ||
+                                maxDown > rowUpper[iRow] + 100.0*tolerance) {
+                            infeasible = true;
+                            break;
+                        }
+                        double lower = rowLower[iRow];
+                        double upper = rowUpper[iRow];
+                        for (j = rStart; j < rEnd; ++j) {
+                            double value = elementByRow[j];
+                            kColumn = column[j];
+                            double nowLower = columnLower[kColumn];
+                            double nowUpper = columnUpper[kColumn];
+                            if (value > 0.0) {
+                                // positive value
+                                if (lower > -large) {
+                                    if (!infiniteUpper) {
+                                        assert(nowUpper < large2);
+                                        newBound = nowUpper +
+                                                   (lower - maximumUp) / value;
+                                        // relax if original was large
+                                        if (fabs(maximumUp) > 1.0e8)
+                                            newBound -= 1.0e-12 * fabs(maximumUp);
+                                    } else if (infiniteUpper == 1 && nowUpper > large) {
+                                        newBound = (lower - maximumUp) / value;
+                                        // relax if original was large
+                                        if (fabs(maximumUp) > 1.0e8)
+                                            newBound -= 1.0e-12 * fabs(maximumUp);
+                                    } else {
+                                        newBound = -COIN_DBL_MAX;
+                                    }
+                                    if (newBound > nowLower + 1.0e-12 && newBound > -large) {
+                                        // Tighten the lower bound
+                                        // check infeasible (relaxed)
+                                        if (nowUpper < newBound) {
+                                            if (nowUpper - newBound <
+                                                    -100.0*tolerance) {
+                                                infeasible = true;
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+                                if (upper < large) {
+                                    if (!infiniteLower) {
+                                        assert(nowLower > - large2);
+                                        newBound = nowLower +
+                                                   (upper - maximumDown) / value;
+                                        // relax if original was large
+                                        if (fabs(maximumDown) > 1.0e8)
+                                            newBound += 1.0e-12 * fabs(maximumDown);
+                                    } else if (infiniteLower == 1 && nowLower < -large) {
+                                        newBound =   (upper - maximumDown) / value;
+                                        // relax if original was large
+                                        if (fabs(maximumDown) > 1.0e8)
+                                            newBound += 1.0e-12 * fabs(maximumDown);
+                                    } else {
+                                        newBound = COIN_DBL_MAX;
+                                    }
+                                    if (newBound < nowUpper - 1.0e-12 && newBound < large) {
+                                        // Tighten the upper bound
+                                        // check infeasible (relaxed)
+                                        if (nowLower > newBound) {
+                                            if (newBound - nowLower <
+                                                    -100.0*tolerance) {
+                                                infeasible = true;
+                                                break;
+                                            } else {
+                                                newBound = nowLower;
+                                            }
+                                        }
+                                        if (!newBound || (clpSolver->isInteger(kColumn) && newBound < 0.999)) {
+                                            // fix to zero
+                                            if (!mark[kColumn]) {
+                                                otherColumn[numberOther++] = kColumn;
+                                                mark[kColumn] = 1;
+                                                if (check[iRow] == -1)
+                                                    check[iRow] = iColumn;
+                                                else
+                                                    assert(check[iRow] == iColumn);
+                                            }
+                                        }
+                                    }
+                                }
+                            } else {
+                                // negative value
+                                if (lower > -large) {
+                                    if (!infiniteUpper) {
+                                        assert(nowLower < large2);
+                                        newBound = nowLower +
+                                                   (lower - maximumUp) / value;
+                                        // relax if original was large
+                                        if (fabs(maximumUp) > 1.0e8)
+                                            newBound += 1.0e-12 * fabs(maximumUp);
+                                    } else if (infiniteUpper == 1 && nowLower < -large) {
+                                        newBound = (lower - maximumUp) / value;
+                                        // relax if original was large
+                                        if (fabs(maximumUp) > 1.0e8)
+                                            newBound += 1.0e-12 * fabs(maximumUp);
+                                    } else {
+                                        newBound = COIN_DBL_MAX;
+                                    }
+                                    if (newBound < nowUpper - 1.0e-12 && newBound < large) {
+                                        // Tighten the upper bound
+                                        // check infeasible (relaxed)
+                                        if (nowLower > newBound) {
+                                            if (newBound - nowLower <
+                                                    -100.0*tolerance) {
+                                                infeasible = true;
+                                                break;
+                                            } else {
+                                                newBound = nowLower;
+                                            }
+                                        }
+                                        if (!newBound || (clpSolver->isInteger(kColumn) && newBound < 0.999)) {
+                                            // fix to zero
+                                            if (!mark[kColumn]) {
+                                                otherColumn[numberOther++] = kColumn;
+                                                mark[kColumn] = 1;
+                                                if (check[iRow] == -1)
+                                                    check[iRow] = iColumn;
+                                                else
+                                                    assert(check[iRow] == iColumn);
+                                            }
+                                        }
+                                    }
+                                }
+                                if (upper < large) {
+                                    if (!infiniteLower) {
+                                        assert(nowUpper < large2);
+                                        newBound = nowUpper +
+                                                   (upper - maximumDown) / value;
+                                        // relax if original was large
+                                        if (fabs(maximumDown) > 1.0e8)
+                                            newBound -= 1.0e-12 * fabs(maximumDown);
+                                    } else if (infiniteLower == 1 && nowUpper > large) {
+                                        newBound =   (upper - maximumDown) / value;
+                                        // relax if original was large
+                                        if (fabs(maximumDown) > 1.0e8)
+                                            newBound -= 1.0e-12 * fabs(maximumDown);
+                                    } else {
+                                        newBound = -COIN_DBL_MAX;
+                                    }
+                                    if (newBound > nowLower + 1.0e-12 && newBound > -large) {
+                                        // Tighten the lower bound
+                                        // check infeasible (relaxed)
+                                        if (nowUpper < newBound) {
+                                            if (nowUpper - newBound <
+                                                    -100.0*tolerance) {
+                                                infeasible = true;
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                for (int i = fixColumn[iColumn]; i < numberOther; i++)
+                    mark[otherColumn[i]] = 0;
+                // reset bound unless infeasible
+                if (!infeasible || !clpSolver->isInteger(iColumn))
+                    columnUpper[iColumn] = saveUpper;
+                else if (clpSolver->isInteger(iColumn))
+                    columnLower[iColumn] = 1.0;
+            }
+        }
+        fixColumn[iColumn+1] = numberOther;
+    }
+    delete [] check;
+    delete [] mark;
+    // Now do reverse way
+    int * counts = new int [numberColumns];
+    CoinZeroN(counts, numberColumns);
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+        for (int i = fixColumn[iColumn]; i < fixColumn[iColumn+1]; i++)
+            counts[otherColumn[i]]++;
+    }
+    numberOther = 0;
+    CoinBigIndex * fixColumn2 = new CoinBigIndex [numberColumns+1];
+    int * otherColumn2 = new int [fixColumn[numberColumns]];
+    fixColumn2[0] = 0;
+    for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+        numberOther += counts[iColumn];
+        counts[iColumn] = 0;
+        fixColumn2[iColumn+1] = numberOther;
+    }
+    // Create other way
+    for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+        for (int i = fixColumn[iColumn]; i < fixColumn[iColumn+1]; i++) {
+            int jColumn = otherColumn[i];
+            CoinBigIndex put = fixColumn2[jColumn] + counts[jColumn];
+            counts[jColumn]++;
+            otherColumn2[put] = iColumn;
+        }
+    }
+    // get top layer i.e. those which are not fixed by any other
+    int kLayer = 0;
+    while (true) {
+        int numberLayered = 0;
+        for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (fix[iColumn] == kLayer) {
+                for (int i = fixColumn2[iColumn]; i < fixColumn2[iColumn+1]; i++) {
+                    int jColumn = otherColumn2[i];
+                    if (fix[jColumn] == kLayer) {
+                        fix[iColumn] = kLayer + 100;
+                    }
+                }
+            }
+            if (fix[iColumn] == kLayer) {
+                numberLayered++;
+            }
+        }
+        if (numberLayered) {
+            kLayer += 100;
+        } else {
+            break;
+        }
+    }
+    for (int iPass = 0; iPass < 2; iPass++) {
+        for (int jLayer = 0; jLayer < kLayer; jLayer++) {
+            int check[] = { -1, 0, 1, 2, 3, 4, 5, 10, 50, 100, 500, 1000, 5000, 10000, COIN_INT_MAX};
+            int nCheck = static_cast<int> (sizeof(check) / sizeof(int));
+            int countsI[20];
+            int countsC[20];
+            assert (nCheck <= 20);
+            memset(countsI, 0, nCheck*sizeof(int));
+            memset(countsC, 0, nCheck*sizeof(int));
+            check[nCheck-1] = numberColumns;
+            int numberLayered = 0;
+            int numberInteger = 0;
+            for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (fix[iColumn] == jLayer) {
+                    numberLayered++;
+                    int nFix = fixColumn[iColumn+1] - fixColumn[iColumn];
+                    if (iPass) {
+                        // just integers
+                        nFix = 0;
+                        for (int i = fixColumn[iColumn]; i < fixColumn[iColumn+1]; i++) {
+                            int jColumn = otherColumn[i];
+                            if (clpSolver->isInteger(jColumn))
+                                nFix++;
+                        }
+                    }
+                    int iFix;
+                    for (iFix = 0; iFix < nCheck; iFix++) {
+                        if (nFix <= check[iFix])
+                            break;
+                    }
+                    assert (iFix < nCheck);
+                    if (clpSolver->isInteger(iColumn)) {
+                        numberInteger++;
+                        countsI[iFix]++;
+                    } else {
+                        countsC[iFix]++;
+                    }
+                }
+            }
+#ifdef COIN_DETAIL
+            if (numberLayered) {
+	        printf("%d (%d integer) at priority %d\n", numberLayered, numberInteger, 1 + (jLayer / 100));
+                char buffer[50];
+                for (int i = 1; i < nCheck; i++) {
+                    if (countsI[i] || countsC[i]) {
+                        if (i == 1)
+                            sprintf(buffer, " ==    zero            ");
+                        else if (i < nCheck - 1)
+                            sprintf(buffer, "> %6d and <= %6d ", check[i-1], check[i]);
+                        else
+                            sprintf(buffer, "> %6d                ", check[i-1]);
+                        printf("%s %8d integers and %8d continuous\n", buffer, countsI[i], countsC[i]);
+                    }
+                }
+            }
+#endif
+        }
+    }
+    delete [] counts;
+    // Now do fixing
+    {
+        // switch off presolve and up weight
+        ClpSolve solveOptions;
+        //solveOptions.setPresolveType(ClpSolve::presolveOff,0);
+        solveOptions.setSolveType(ClpSolve::usePrimalorSprint);
+        //solveOptions.setSpecialOption(1,3,30); // sprint
+        int numberColumns = lpSolver->numberColumns();
+        int iColumn;
+        bool allSlack = true;
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            if (lpSolver->getColumnStatus(iColumn) == ClpSimplex::basic) {
+                allSlack = false;
+                break;
+            }
+        }
+        if (allSlack)
+            solveOptions.setSpecialOption(1, 2, 50); // idiot
+        lpSolver->setInfeasibilityCost(1.0e11);
+        lpSolver->defaultFactorizationFrequency();
+        if (doAction != 11)
+            lpSolver->initialSolve(solveOptions);
+        double * columnLower = lpSolver->columnLower();
+        double * columnUpper = lpSolver->columnUpper();
+        double * fullSolution = lpSolver->primalColumnSolution();
+        const double * dj = lpSolver->dualColumnSolution();
+        int iPass = 0;
+#define MAXPROB 2
+        ClpSimplex models[MAXPROB];
+        int kPass = -1;
+        int kLayer = 0;
+        int skipZero = 0;
+        if (skipZero2 == -1)
+            skipZero2 = 40; //-1;
+        /* 0 fixed to 0 by choice
+           1 lb of 1 by choice
+           2 fixed to 0 by another
+           3 as 2 but this go
+           -1 free
+        */
+        char * state = new char [numberColumns];
+        for (iColumn = 0; iColumn < numberColumns; iColumn++)
+            state[iColumn] = -1;
+        while (true) {
+            double largest = -0.1;
+            double smallest = 1.1;
+            int iLargest = -1;
+            int iSmallest = -1;
+            int atZero = 0;
+            int atOne = 0;
+            int toZero = 0;
+            int toOne = 0;
+            int numberFree = 0;
+            int numberGreater = 0;
+            columnLower = lpSolver->columnLower();
+            columnUpper = lpSolver->columnUpper();
+            fullSolution = lpSolver->primalColumnSolution();
+            if (doAction == 11) {
+                {
+                    double * columnLower = lpSolver->columnLower();
+                    double * columnUpper = lpSolver->columnUpper();
+                    //	  lpSolver->dual();
+                    memcpy(columnLower, saveColumnLower, numberColumns*sizeof(double));
+                    memcpy(columnUpper, saveColumnUpper, numberColumns*sizeof(double));
+                    //	  lpSolver->dual();
+                    int iColumn;
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        if (columnUpper[iColumn] > columnLower[iColumn] + 1.0e-8) {
+                            if (clpSolver->isInteger(iColumn)) {
+                                double value = lastSolution[iColumn];
+                                int iValue = static_cast<int> (value + 0.5);
+                                assert (fabs(value - static_cast<double> (iValue)) < 1.0e-3);
+                                assert (iValue >= columnLower[iColumn] &&
+                                        iValue <= columnUpper[iColumn]);
+                                columnLower[iColumn] = iValue;
+                                columnUpper[iColumn] = iValue;
+                            }
+                        }
+                    }
+                    lpSolver->initialSolve(solveOptions);
+                    memcpy(columnLower, saveColumnLower, numberColumns*sizeof(double));
+                    memcpy(columnUpper, saveColumnUpper, numberColumns*sizeof(double));
+                }
+                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (columnUpper[iColumn] > columnLower[iColumn] + 1.0e-8) {
+                        if (clpSolver->isInteger(iColumn)) {
+                            double value = lastSolution[iColumn];
+                            int iValue = static_cast<int> (value + 0.5);
+                            assert (fabs(value - static_cast<double> (iValue)) < 1.0e-3);
+                            assert (iValue >= columnLower[iColumn] &&
+                                    iValue <= columnUpper[iColumn]);
+                            if (!fix[iColumn]) {
+                                if (iValue == 0) {
+                                    state[iColumn] = 0;
+                                    assert (!columnLower[iColumn]);
+                                    columnUpper[iColumn] = 0.0;
+                                } else if (iValue == 1) {
+                                    state[iColumn] = 1;
+                                    columnLower[iColumn] = 1.0;
+                                } else {
+                                    // leave fixed
+                                    columnLower[iColumn] = iValue;
+                                    columnUpper[iColumn] = iValue;
+                                }
+                            } else if (iValue == 0) {
+                                state[iColumn] = 10;
+                                columnUpper[iColumn] = 0.0;
+                            } else {
+                                // leave fixed
+                                columnLower[iColumn] = iValue;
+                                columnUpper[iColumn] = iValue;
+                            }
+                        }
+                    }
+                }
+                int jLayer = 0;
+                int nFixed = -1;
+                int nTotalFixed = 0;
+                while (nFixed) {
+                    nFixed = 0;
+                    for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                        if (columnUpper[iColumn] == 0.0 && fix[iColumn] == jLayer) {
+                            for (int i = fixColumn[iColumn]; i < fixColumn[iColumn+1]; i++) {
+                                int jColumn = otherColumn[i];
+                                if (columnUpper[jColumn]) {
+                                    bool canFix = true;
+                                    for (int k = fixColumn2[jColumn]; k < fixColumn2[jColumn+1]; k++) {
+                                        int kColumn = otherColumn2[k];
+                                        if (state[kColumn] == 1) {
+                                            canFix = false;
+                                            break;
+                                        }
+                                    }
+                                    if (canFix) {
+                                        columnUpper[jColumn] = 0.0;
+                                        nFixed++;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    nTotalFixed += nFixed;
+                    jLayer += 100;
+                }
+                COIN_DETAIL_PRINT(printf("This fixes %d variables in lower priorities\n", nTotalFixed));
+                break;
+            }
+            for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (!clpSolver->isInteger(iColumn) || fix[iColumn] > kLayer)
+                    continue;
+                // skip if fixes nothing
+                if (fixColumn[iColumn+1] - fixColumn[iColumn] <= skipZero2)
+                    continue;
+                double value = fullSolution[iColumn];
+                if (value > 1.00001) {
+                    numberGreater++;
+                    continue;
+                }
+                double lower = columnLower[iColumn];
+                double upper = columnUpper[iColumn];
+                if (lower == upper) {
+                    if (lower)
+                        atOne++;
+                    else
+                        atZero++;
+                    continue;
+                }
+                if (value < 1.0e-7) {
+                    toZero++;
+                    columnUpper[iColumn] = 0.0;
+                    state[iColumn] = 10;
+                    continue;
+                }
+                if (value > 1.0 - 1.0e-7) {
+                    toOne++;
+                    columnLower[iColumn] = 1.0;
+                    state[iColumn] = 1;
+                    continue;
+                }
+                numberFree++;
+                // skip if fixes nothing
+                if (fixColumn[iColumn+1] - fixColumn[iColumn] <= skipZero)
+                    continue;
+                if (value < smallest) {
+                    smallest = value;
+                    iSmallest = iColumn;
+                }
+                if (value > largest) {
+                    largest = value;
+                    iLargest = iColumn;
+                }
+            }
+            if (toZero || toOne)
+	      COIN_DETAIL_PRINT(printf("%d at 0 fixed and %d at one fixed\n", toZero, toOne));
+            COIN_DETAIL_PRINT(printf("%d variables free, %d fixed to 0, %d to 1 - smallest %g, largest %g\n",
+				     numberFree, atZero, atOne, smallest, largest));
+            if (numberGreater && !iPass)
+	      COIN_DETAIL_PRINT(printf("%d variables have value > 1.0\n", numberGreater));
+            //skipZero2=0; // leave 0 fixing
+            int jLayer = 0;
+            int nFixed = -1;
+            int nTotalFixed = 0;
+            while (nFixed) {
+                nFixed = 0;
+                for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (columnUpper[iColumn] == 0.0 && fix[iColumn] == jLayer) {
+                        for (int i = fixColumn[iColumn]; i < fixColumn[iColumn+1]; i++) {
+                            int jColumn = otherColumn[i];
+                            if (columnUpper[jColumn]) {
+                                bool canFix = true;
+                                for (int k = fixColumn2[jColumn]; k < fixColumn2[jColumn+1]; k++) {
+                                    int kColumn = otherColumn2[k];
+                                    if (state[kColumn] == 1) {
+                                        canFix = false;
+                                        break;
+                                    }
+                                }
+                                if (canFix) {
+                                    columnUpper[jColumn] = 0.0;
+                                    nFixed++;
+                                }
+                            }
+                        }
+                    }
+                }
+                nTotalFixed += nFixed;
+                jLayer += 100;
+            }
+            COIN_DETAIL_PRINT(printf("This fixes %d variables in lower priorities\n", nTotalFixed));
+            if (iLargest < 0 || numberFree <= leaveIntFree)
+                break;
+            double movement;
+            int way;
+            if (smallest <= 1.0 - largest && smallest < 0.2 && largest < fixAboveValue) {
+                columnUpper[iSmallest] = 0.0;
+                state[iSmallest] = 0;
+                movement = smallest;
+                way = -1;
+            } else {
+                columnLower[iLargest] = 1.0;
+                state[iLargest] = 1;
+                movement = 1.0 - largest;
+                way = 1;
+            }
+            double saveObj = lpSolver->objectiveValue();
+            iPass++;
+            kPass = iPass % MAXPROB;
+            models[kPass] = *lpSolver;
+            if (way == -1) {
+                // fix others
+                for (int i = fixColumn[iSmallest]; i < fixColumn[iSmallest+1]; i++) {
+                    int jColumn = otherColumn[i];
+                    if (state[jColumn] == -1) {
+                        columnUpper[jColumn] = 0.0;
+                        state[jColumn] = 3;
+                    }
+                }
+            }
+            double maxCostUp = COIN_DBL_MAX;
+            objective = lpSolver->getObjCoefficients() ;
+            if (way == -1)
+                maxCostUp = (1.0 - movement) * objective[iSmallest];
+            lpSolver->setDualObjectiveLimit(saveObj + maxCostUp);
+            crunchIt(lpSolver);
+            double moveObj = lpSolver->objectiveValue() - saveObj;
+            COIN_DETAIL_PRINT(printf("movement %s was %g costing %g\n",
+				     (way == -1) ? "down" : "up", movement, moveObj));
+            if (way == -1 && (moveObj >= maxCostUp || lpSolver->status())) {
+                // go up
+                columnLower = models[kPass].columnLower();
+                columnUpper = models[kPass].columnUpper();
+                columnLower[iSmallest] = 1.0;
+                columnUpper[iSmallest] = saveColumnUpper[iSmallest];
+                *lpSolver = models[kPass];
+                columnLower = lpSolver->columnLower();
+                columnUpper = lpSolver->columnUpper();
+                fullSolution = lpSolver->primalColumnSolution();
+                dj = lpSolver->dualColumnSolution();
+                columnLower[iSmallest] = 1.0;
+                columnUpper[iSmallest] = saveColumnUpper[iSmallest];
+                state[iSmallest] = 1;
+                // unfix others
+                for (int i = fixColumn[iSmallest]; i < fixColumn[iSmallest+1]; i++) {
+                    int jColumn = otherColumn[i];
+                    if (state[jColumn] == 3) {
+                        columnUpper[jColumn] = saveColumnUpper[jColumn];
+                        state[jColumn] = -1;
+                    }
+                }
+                crunchIt(lpSolver);
+            }
+            models[kPass] = *lpSolver;
+        }
+        lpSolver->dual();
+        COIN_DETAIL_PRINT(printf("Fixing took %g seconds\n", CoinCpuTime() - time1));
+        columnLower = lpSolver->columnLower();
+        columnUpper = lpSolver->columnUpper();
+        fullSolution = lpSolver->primalColumnSolution();
+        dj = lpSolver->dualColumnSolution();
+        int * sort = new int[numberColumns];
+        double * dsort = new double[numberColumns];
+        int chunk = 20;
+        int iRelax = 0;
+        //double fractionFixed=6.0/8.0;
+        // relax while lots fixed
+        while (true) {
+            if (skipZero2 > 10 && doAction < 10)
+                break;
+            iRelax++;
+            int n = 0;
+            double sum0 = 0.0;
+            double sum00 = 0.0;
+            double sum1 = 0.0;
+            for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (!clpSolver->isInteger(iColumn) || fix[iColumn] > kLayer)
+                    continue;
+                // skip if fixes nothing
+                if (fixColumn[iColumn+1] - fixColumn[iColumn] == 0 && doAction < 10)
+                    continue;
+                double djValue = dj[iColumn];
+                if (state[iColumn] == 1) {
+                    assert (columnLower[iColumn]);
+                    assert (fullSolution[iColumn] > 0.1);
+                    if (djValue > 0.0) {
+                        //printf("YY dj of %d at %g is %g\n",iColumn,value,djValue);
+                        sum1 += djValue;
+                        sort[n] = iColumn;
+                        dsort[n++] = -djValue;
+                    } else {
+                        //printf("dj of %d at %g is %g\n",iColumn,value,djValue);
+                    }
+                } else if (state[iColumn] == 0 || state[iColumn] == 10) {
+                    assert (fullSolution[iColumn] < 0.1);
+                    assert (!columnUpper[iColumn]);
+                    double otherValue = 0.0;
+                    int nn = 0;
+                    for (int i = fixColumn[iColumn]; i < fixColumn[iColumn+1]; i++) {
+                        int jColumn = otherColumn[i];
+                        if (columnUpper[jColumn] == 0.0) {
+                            if (dj[jColumn] < -1.0e-5) {
+                                nn++;
+                                otherValue += dj[jColumn]; // really need to look at rest
+                            }
+                        }
+                    }
+                    if (djValue < -1.0e-2 || otherValue < -1.0e-2) {
+                        //printf("XX dj of %d at %g is %g - %d out of %d contribute %g\n",iColumn,value,djValue,
+                        // nn,fixColumn[iColumn+1]-fixColumn[iColumn],otherValue);
+                        if (djValue < 1.0e-8) {
+                            sum0 -= djValue;
+                            sum00 -= otherValue;
+                            sort[n] = iColumn;
+                            if (djValue < -1.0e-2)
+                                dsort[n++] = djValue + otherValue;
+                            else
+                                dsort[n++] = djValue + 0.001 * otherValue;
+                        }
+                    } else {
+                        //printf("dj of %d at %g is %g - no contribution from %d\n",iColumn,value,djValue,
+                        //   fixColumn[iColumn+1]-fixColumn[iColumn]);
+                    }
+                }
+            }
+            CoinSort_2(dsort, dsort + n, sort);
+            double * originalColumnLower = saveColumnLower;
+            double * originalColumnUpper = saveColumnUpper;
+            double * lo = CoinCopyOfArray(columnLower, numberColumns);
+            double * up = CoinCopyOfArray(columnUpper, numberColumns);
+            for (int k = 0; k < CoinMin(chunk, n); k++) {
+                iColumn = sort[k];
+                state[iColumn] = -2;
+            }
+            memcpy(columnLower, originalColumnLower, numberColumns*sizeof(double));
+            memcpy(columnUpper, originalColumnUpper, numberColumns*sizeof(double));
+            int nFixed = 0;
+            int nFixed0 = 0;
+            int nFixed1 = 0;
+            for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (state[iColumn] == 0 || state[iColumn] == 10) {
+                    columnUpper[iColumn] = 0.0;
+                    assert (lo[iColumn] == 0.0);
+                    nFixed++;
+                    nFixed0++;
+                    for (int i = fixColumn[iColumn]; i < fixColumn[iColumn+1]; i++) {
+                        int jColumn = otherColumn[i];
+                        if (columnUpper[jColumn]) {
+                            bool canFix = true;
+                            for (int k = fixColumn2[jColumn]; k < fixColumn2[jColumn+1]; k++) {
+                                int kColumn = otherColumn2[k];
+                                if (state[kColumn] == 1 || state[kColumn] == -2) {
+                                    canFix = false;
+                                    break;
+                                }
+                            }
+                            if (canFix) {
+                                columnUpper[jColumn] = 0.0;
+                                assert (lo[jColumn] == 0.0);
+                                nFixed++;
+                            }
+                        }
+                    }
+                } else if (state[iColumn] == 1) {
+                    columnLower[iColumn] = 1.0;
+                    nFixed1++;
+                }
+            }
+            COIN_DETAIL_PRINT(printf("%d fixed %d orig 0 %d 1\n", nFixed, nFixed0, nFixed1));
+            int jLayer = 0;
+            nFixed = -1;
+            int nTotalFixed = 0;
+            while (nFixed) {
+                nFixed = 0;
+                for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (columnUpper[iColumn] == 0.0 && fix[iColumn] == jLayer) {
+                        for (int i = fixColumn[iColumn]; i < fixColumn[iColumn+1]; i++) {
+                            int jColumn = otherColumn[i];
+                            if (columnUpper[jColumn]) {
+                                bool canFix = true;
+                                for (int k = fixColumn2[jColumn]; k < fixColumn2[jColumn+1]; k++) {
+                                    int kColumn = otherColumn2[k];
+                                    if (state[kColumn] == 1 || state[kColumn] == -2) {
+                                        canFix = false;
+                                        break;
+                                    }
+                                }
+                                if (canFix) {
+                                    columnUpper[jColumn] = 0.0;
+                                    assert (lo[jColumn] == 0.0);
+                                    nFixed++;
+                                }
+                            }
+                        }
+                    }
+                }
+                nTotalFixed += nFixed;
+                jLayer += 100;
+            }
+            nFixed = 0;
+            int nFixedI = 0;
+            for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (columnLower[iColumn] == columnUpper[iColumn]) {
+                    if (clpSolver->isInteger(iColumn))
+                        nFixedI++;
+                    nFixed++;
+                }
+            }
+            COIN_DETAIL_PRINT(printf("This fixes %d variables in lower priorities - total %d (%d integer) - all target %d, int target %d\n",
+				     nTotalFixed, nFixed, nFixedI, static_cast<int>(fractionFixed*numberColumns), static_cast<int> (fractionIntFixed*numberInteger)));
+            int nBad = 0;
+            int nRelax = 0;
+            for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                if (lo[iColumn] < columnLower[iColumn] ||
+                        up[iColumn] > columnUpper[iColumn]) {
+                    COIN_DETAIL_PRINT(printf("bad %d old %g %g, new %g %g\n", iColumn, lo[iColumn], up[iColumn],
+					     columnLower[iColumn], columnUpper[iColumn]));
+                    nBad++;
+                }
+                if (lo[iColumn] > columnLower[iColumn] ||
+                        up[iColumn] < columnUpper[iColumn]) {
+                    nRelax++;
+                }
+            }
+            COIN_DETAIL_PRINT(printf("%d relaxed\n", nRelax));
+            if (iRelax > 20 && nRelax == chunk)
+                nRelax = 0;
+            if (iRelax > 50)
+                nRelax = 0;
+            assert (!nBad);
+            delete [] lo;
+            delete [] up;
+            lpSolver->primal(1);
+            if (nFixed < fractionFixed*numberColumns || nFixedI < fractionIntFixed*numberInteger || !nRelax)
+                break;
+        }
+        delete [] state;
+        delete [] sort;
+        delete [] dsort;
+    }
+    delete [] fix;
+    delete [] fixColumn;
+    delete [] otherColumn;
+    delete [] otherColumn2;
+    delete [] fixColumn2;
+    // See if was presolved
+    if (originalColumns) {
+        columnLower = lpSolver->columnLower();
+        columnUpper = lpSolver->columnUpper();
+        for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+            saveColumnLower[iColumn] = columnLower[iColumn];
+            saveColumnUpper[iColumn] = columnUpper[iColumn];
+        }
+        pinfo.postsolve(true);
+        columnLower = originalLpSolver->columnLower();
+        columnUpper = originalLpSolver->columnUpper();
+        double * newColumnLower = lpSolver->columnLower();
+        double * newColumnUpper = lpSolver->columnUpper();
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            int jColumn = originalColumns[iColumn];
+            columnLower[jColumn] = CoinMax(columnLower[jColumn], newColumnLower[iColumn]);
+            columnUpper[jColumn] = CoinMin(columnUpper[jColumn], newColumnUpper[iColumn]);
+        }
+        numberColumns = originalLpSolver->numberColumns();
+        delete [] originalColumns;
+    }
+    delete [] saveColumnLower;
+    delete [] saveColumnUpper;
+    if (!originalColumns) {
+        // Basis
+        memcpy(originalLpSolver->statusArray(), lpSolver->statusArray(), numberRows + numberColumns);
+        memcpy(originalLpSolver->primalColumnSolution(), lpSolver->primalColumnSolution(), numberColumns*sizeof(double));
+        memcpy(originalLpSolver->primalRowSolution(), lpSolver->primalRowSolution(), numberRows*sizeof(double));
+        // Fix in solver
+        columnLower = lpSolver->columnLower();
+        columnUpper = lpSolver->columnUpper();
+    }
+    double * originalColumnLower = originalLpSolver->columnLower();
+    double * originalColumnUpper = originalLpSolver->columnUpper();
+    // number fixed
+    doAction = 0;
+    for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+        originalColumnLower[iColumn] = columnLower[iColumn];
+        originalColumnUpper[iColumn] = columnUpper[iColumn];
+        if (columnLower[iColumn] == columnUpper[iColumn])
+            doAction++;
+    }
+    COIN_DETAIL_PRINT(printf("%d fixed by vub preprocessing\n", doAction));
+    if (originalColumns) {
+        originalLpSolver->initialSolve();
+    }
+    delete clpSolver;
+    return NULL;
+}
+
+int doHeuristics(CbcModel * model, int type, CbcOrClpParam* parameters_,
+		 int numberParameters_,int noPrinting_,int initialPumpTune)
+{
+#ifdef JJF_ZERO //NEW_STYLE_SOLVER==0
+    CbcOrClpParam * parameters_ = parameters;
+    int numberParameters_ = numberParameters;
+    bool noPrinting_ = noPrinting_;
+#endif
+    char generalPrint[10000];
+    CoinMessages generalMessages = model->messages();
+    CoinMessageHandler * generalMessageHandler = model->messageHandler();
+    //generalMessageHandler->setPrefix(false);
+    bool anyToDo = false;
+    int logLevel = parameters_[whichParam(CLP_PARAM_INT_LOGLEVEL, numberParameters_, parameters_)].intValue();
+    int useFpump = parameters_[whichParam(CBC_PARAM_STR_FPUMP, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useRounding = parameters_[whichParam(CBC_PARAM_STR_ROUNDING, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useGreedy = parameters_[whichParam(CBC_PARAM_STR_GREEDY, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useCombine = parameters_[whichParam(CBC_PARAM_STR_COMBINE, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useProximity = parameters_[whichParam(CBC_PARAM_STR_PROXIMITY, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useCrossover = parameters_[whichParam(CBC_PARAM_STR_CROSSOVER2, numberParameters_, parameters_)].currentOptionAsInteger();
+    //int usePivotC = parameters_[whichParam(CBC_PARAM_STR_PIVOTANDCOMPLEMENT, numberParameters_, parameters_)].currentOptionAsInteger();
+    int usePivotF = parameters_[whichParam(CBC_PARAM_STR_PIVOTANDFIX, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useRand = parameters_[whichParam(CBC_PARAM_STR_RANDROUND, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useRINS = parameters_[whichParam(CBC_PARAM_STR_RINS, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useRENS = parameters_[whichParam(CBC_PARAM_STR_RENS, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useDINS = parameters_[whichParam(CBC_PARAM_STR_DINS, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useDIVING2 = parameters_[whichParam(CBC_PARAM_STR_DIVINGS, numberParameters_, parameters_)].currentOptionAsInteger();
+    int useNaive = parameters_[whichParam(CBC_PARAM_STR_NAIVE, numberParameters_, parameters_)].currentOptionAsInteger();
+    int kType = (type < 10) ? type : 1;
+    assert (kType == 1 || kType == 2);
+    // FPump done first as it only works if no solution
+    if (useFpump >= kType && useFpump <= kType + 1) {
+        anyToDo = true;
+        CbcHeuristicFPump heuristic4(*model);
+        double dextra3 = parameters_[whichParam(CBC_PARAM_DBL_SMALLBAB, numberParameters_, parameters_)].doubleValue();
+        heuristic4.setFractionSmall(dextra3);
+        double dextra1 = parameters_[whichParam(CBC_PARAM_DBL_ARTIFICIALCOST, numberParameters_, parameters_)].doubleValue();
+        if (dextra1)
+            heuristic4.setArtificialCost(dextra1);
+        heuristic4.setMaximumPasses(parameters_[whichParam(CBC_PARAM_INT_FPUMPITS, numberParameters_, parameters_)].intValue());
+        if (parameters_[whichParam(CBC_PARAM_INT_FPUMPITS, numberParameters_, parameters_)].intValue() == 21)
+            heuristic4.setIterationRatio(1.0);
+        int pumpTune = parameters_[whichParam(CBC_PARAM_INT_FPUMPTUNE, numberParameters_, parameters_)].intValue();
+        int pumpTune2 = parameters_[whichParam(CBC_PARAM_INT_FPUMPTUNE2, numberParameters_, parameters_)].intValue();
+        if (pumpTune > 0) {
+            bool printStuff = (pumpTune != initialPumpTune || logLevel > 1 || pumpTune2 > 0)
+                              && !noPrinting_;
+            if (printStuff) {
+                generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                << "Options for feasibility pump - "
+                << CoinMessageEol;
+            }
+            /*
+            >=10000000 for using obj
+            >=1000000 use as accumulate switch
+            >=1000 use index+1 as number of large loops
+            >=100 use dextra1 as cutoff
+            %100 == 10,20 etc for experimentation
+            1 == fix ints at bounds, 2 fix all integral ints, 3 and continuous at bounds
+            4 and static continuous, 5 as 3 but no internal integers
+            6 as 3 but all slack basis!
+            */
+            double value = model->solver()->getObjSense() * model->solver()->getObjValue();
+            int w = pumpTune / 10;
+            int i = w % 10;
+            w /= 10;
+            int c = w % 10;
+            w /= 10;
+            int r = w;
+            int accumulate = r / 1000;
+            r -= 1000 * accumulate;
+            if (accumulate >= 10) {
+                int which = accumulate / 10;
+                accumulate -= 10 * which;
+                which--;
+                // weights and factors
+                double weight[] = {0.01, 0.01, 0.1, 0.1, 0.5, 0.5, 1.0, 1.0, 5.0, 5.0};
+                double factor[] = {0.1, 0.5, 0.1, 0.5, 0.1, 0.5, 0.1, 0.5, 0.1, 0.5};
+                heuristic4.setInitialWeight(weight[which]);
+                heuristic4.setWeightFactor(factor[which]);
+                if (printStuff) {
+                    sprintf(generalPrint, "Initial weight for objective %g, decay factor %g",
+                            weight[which], factor[which]);
+                    generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                    << generalPrint
+                    << CoinMessageEol;
+                }
+
+            }
+            // fake cutoff
+            if (c) {
+                double cutoff;
+                model->solver()->getDblParam(OsiDualObjectiveLimit, cutoff);
+                cutoff = CoinMin(cutoff, value + 0.05 * fabs(value) * c);
+                double fakeCutoff = parameters_[whichParam(CBC_PARAM_DBL_FAKECUTOFF, numberParameters_, parameters_)].doubleValue();
+                if (fakeCutoff)
+                    cutoff = fakeCutoff;
+                heuristic4.setFakeCutoff(cutoff);
+                if (printStuff) {
+                    sprintf(generalPrint, "Fake cutoff of %g", cutoff);
+                    generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                    << generalPrint
+                    << CoinMessageEol;
+                }
+            }
+            int offRandomEtc = 0;
+            if (pumpTune2) {
+                if ((pumpTune2 / 1000) != 0) {
+                    offRandomEtc = 1000000 * (pumpTune2 / 1000);
+                    if (printStuff) {
+                        generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                        << "Feasibility pump may run twice"
+                        << CoinMessageEol;
+                    }
+                    pumpTune2 = pumpTune2 % 1000;
+                }
+                if ((pumpTune2 / 100) != 0) {
+                    offRandomEtc += 100 * (pumpTune2 / 100);
+                    if (printStuff) {
+                        generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                        << "Not using randomized objective"
+                        << CoinMessageEol;
+                    }
+                }
+                int maxAllowed = pumpTune2 % 100;
+                if (maxAllowed) {
+                    offRandomEtc += 1000 * maxAllowed;
+                    if (printStuff) {
+                        sprintf(generalPrint, "Fixing if same for %d passes",
+                                maxAllowed);
+                        generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                        << generalPrint
+                        << CoinMessageEol;
+                    }
+                }
+            }
+            if (accumulate) {
+                heuristic4.setAccumulate(accumulate);
+                if (printStuff) {
+                    if (accumulate) {
+                        sprintf(generalPrint, "Accumulate of %d", accumulate);
+                        generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                        << generalPrint
+                        << CoinMessageEol;
+                    }
+                }
+            }
+            if (r) {
+                // also set increment
+                //double increment = (0.01*i+0.005)*(fabs(value)+1.0e-12);
+                double increment = 0.0;
+                double fakeIncrement = parameters_[whichParam(CBC_PARAM_DBL_FAKEINCREMENT, numberParameters_, parameters_)].doubleValue();
+                if (fakeIncrement)
+                    increment = fakeIncrement;
+                heuristic4.setAbsoluteIncrement(increment);
+                heuristic4.setMaximumRetries(r + 1);
+                if (printStuff) {
+                    if (increment) {
+                        sprintf(generalPrint, "Increment of %g", increment);
+                        generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                        << generalPrint
+                        << CoinMessageEol;
+                    }
+                    sprintf(generalPrint, "%d retries", r + 1);
+                    generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                    << generalPrint
+                    << CoinMessageEol;
+                }
+            }
+            if (i + offRandomEtc) {
+                heuristic4.setFeasibilityPumpOptions(i*10 + offRandomEtc);
+                if (printStuff) {
+                    sprintf(generalPrint, "Feasibility pump options of %d",
+                            i*10 + offRandomEtc);
+                    generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                    << generalPrint
+                    << CoinMessageEol;
+                }
+            }
+            pumpTune = pumpTune % 100;
+            if (pumpTune == 6)
+                pumpTune = 13;
+            heuristic4.setWhen((pumpTune % 10) + 10);
+            if (printStuff) {
+                sprintf(generalPrint, "Tuning (fixing) %d", pumpTune % 10);
+                generalMessageHandler->message(CBC_GENERAL, generalMessages)
+                << generalPrint
+                << CoinMessageEol;
+            }
+        }
+        heuristic4.setHeuristicName("feasibility pump");
+        //#define ROLF
+#ifdef ROLF
+        CbcHeuristicFPump pump(*model);
+        pump.setMaximumTime(60);
+        pump.setMaximumPasses(100);
+        pump.setMaximumRetries(1);
+        pump.setFixOnReducedCosts(0);
+        pump.setHeuristicName("Feasibility pump");
+        pump.setFractionSmall(1.0);
+        pump.setWhen(13);
+        model->addHeuristic(&pump);
+#else
+        model->addHeuristic(&heuristic4);
+#endif
+    }
+    if (useRounding >= type && useRounding >= kType && useRounding <= kType + 1) {
+        CbcRounding heuristic1(*model);
+        heuristic1.setHeuristicName("rounding");
+        model->addHeuristic(&heuristic1) ;
+        anyToDo = true;
+    }
+    if (useGreedy >= type && useGreedy >= kType && useGreedy <= kType + 1) {
+        CbcHeuristicGreedyCover heuristic3(*model);
+        heuristic3.setHeuristicName("greedy cover");
+        CbcHeuristicGreedyEquality heuristic3a(*model);
+        heuristic3a.setHeuristicName("greedy equality");
+        model->addHeuristic(&heuristic3);
+        model->addHeuristic(&heuristic3a);
+        anyToDo = true;
+    }
+    if ((useRENS==7 && kType==1) || (useRENS==8 && kType==2)) {
+        useRENS=1+2*(useRENS-7);
+        CbcHeuristicRENS heuristic6a(*model);
+        heuristic6a.setHeuristicName("RENSdj");
+        heuristic6a.setFractionSmall(0.6/*3.4*/);
+        heuristic6a.setFeasibilityPumpOptions(3);
+        heuristic6a.setNumberNodes(10);
+	heuristic6a.setWhereFrom(4*256+4*1);
+	heuristic6a.setWhen(2);
+	heuristic6a.setRensType(1+16);
+        model->addHeuristic(&heuristic6a) ;
+        heuristic6a.setHeuristicName("RENSub");
+        heuristic6a.setFractionSmall(0.4);
+        heuristic6a.setFeasibilityPumpOptions(1008003);
+        heuristic6a.setNumberNodes(50);
+	heuristic6a.setWhereFrom(4*256+4*1);
+	heuristic6a.setWhen(2);
+	heuristic6a.setRensType(2+16);
+        model->addHeuristic(&heuristic6a) ;
+    }
+    if (useRENS >= kType && useRENS <= kType + 1) {
+#ifndef JJF_ONE
+        CbcHeuristicRENS heuristic6(*model);
+        heuristic6.setHeuristicName("RENS");
+        heuristic6.setFractionSmall(0.4);
+        heuristic6.setFeasibilityPumpOptions(1008003);
+        int nodes [] = { -2, 50, 50, 50, 200, 1000, 10000};
+        heuristic6.setNumberNodes(nodes[useRENS]);
+#else
+        CbcHeuristicVND heuristic6(*model);
+        heuristic6.setHeuristicName("VND");
+        heuristic5.setFractionSmall(0.5);
+        heuristic5.setDecayFactor(5.0);
+#endif
+        model->addHeuristic(&heuristic6) ;
+        anyToDo = true;
+    }
+    if (useNaive >= kType && useNaive <= kType + 1) {
+        CbcHeuristicNaive heuristic5b(*model);
+        heuristic5b.setHeuristicName("Naive");
+        heuristic5b.setFractionSmall(0.4);
+        heuristic5b.setNumberNodes(50);
+        model->addHeuristic(&heuristic5b) ;
+        anyToDo = true;
+    }
+    int useDIVING = 0;
+    {
+        int useD;
+        useD = parameters_[whichParam(CBC_PARAM_STR_DIVINGV, numberParameters_, parameters_)].currentOptionAsInteger();
+        useDIVING |= 1 * ((useD >= kType) ? 1 : 0);
+        useD = parameters_[whichParam(CBC_PARAM_STR_DIVINGG, numberParameters_, parameters_)].currentOptionAsInteger();
+        useDIVING |= 2 * ((useD >= kType) ? 1 : 0);
+        useD = parameters_[whichParam(CBC_PARAM_STR_DIVINGF, numberParameters_, parameters_)].currentOptionAsInteger();
+        useDIVING |= 4 * ((useD >= kType) ? 1 : 0);
+        useD = parameters_[whichParam(CBC_PARAM_STR_DIVINGC, numberParameters_, parameters_)].currentOptionAsInteger();
+        useDIVING |= 8 * ((useD >= kType) ? 1 : 0);
+        useD = parameters_[whichParam(CBC_PARAM_STR_DIVINGL, numberParameters_, parameters_)].currentOptionAsInteger();
+        useDIVING |= 16 * ((useD >= kType) ? 1 : 0);
+        useD = parameters_[whichParam(CBC_PARAM_STR_DIVINGP, numberParameters_, parameters_)].currentOptionAsInteger();
+        useDIVING |= 32 * ((useD >= kType) ? 1 : 0);
+    }
+    if (useDIVING2 >= kType && useDIVING2 <= kType + 1) {
+        int diveOptions = parameters_[whichParam(CBC_PARAM_INT_DIVEOPT, numberParameters_, parameters_)].intValue();
+        if (diveOptions < 0 || diveOptions > 10)
+            diveOptions = 2;
+        CbcHeuristicJustOne heuristicJustOne(*model);
+        heuristicJustOne.setHeuristicName("DiveAny");
+        heuristicJustOne.setWhen(diveOptions);
+        // add in others
+        CbcHeuristicDiveCoefficient heuristicDC(*model);
+        heuristicDC.setHeuristicName("DiveCoefficient");
+        heuristicJustOne.addHeuristic(&heuristicDC, 1.0) ;
+        CbcHeuristicDiveFractional heuristicDF(*model);
+        heuristicDF.setHeuristicName("DiveFractional");
+        heuristicJustOne.addHeuristic(&heuristicDF, 1.0) ;
+        CbcHeuristicDiveGuided heuristicDG(*model);
+        heuristicDG.setHeuristicName("DiveGuided");
+        heuristicJustOne.addHeuristic(&heuristicDG, 1.0) ;
+        CbcHeuristicDiveLineSearch heuristicDL(*model);
+        heuristicDL.setHeuristicName("DiveLineSearch");
+        heuristicJustOne.addHeuristic(&heuristicDL, 1.0) ;
+        CbcHeuristicDivePseudoCost heuristicDP(*model);
+        heuristicDP.setHeuristicName("DivePseudoCost");
+        heuristicJustOne.addHeuristic(&heuristicDP, 1.0) ;
+        CbcHeuristicDiveVectorLength heuristicDV(*model);
+        heuristicDV.setHeuristicName("DiveVectorLength");
+        heuristicJustOne.addHeuristic(&heuristicDV, 1.0) ;
+        // Now normalize probabilities
+        heuristicJustOne.normalizeProbabilities();
+        model->addHeuristic(&heuristicJustOne) ;
+    }
+
+    if (useDIVING > 0) {
+        int majorIterations=64;
+        int diveOptions2 = parameters_[whichParam(CBC_PARAM_INT_DIVEOPT, numberParameters_, parameters_)].intValue();
+        int diveOptions;
+        if (diveOptions2 > 99) {
+            // switch on various active set stuff
+	    diveOptions = diveOptions2%100;
+            diveOptions2 /= 100;
+        } else {
+            diveOptions = diveOptions2;
+            diveOptions2 = 0;
+        }
+        if (diveOptions < 0 || diveOptions > 9)
+            diveOptions = 2;
+        if ((useDIVING&1) != 0) {
+            CbcHeuristicDiveVectorLength heuristicDV(*model);
+            heuristicDV.setHeuristicName("DiveVectorLength");
+            heuristicDV.setWhen(diveOptions);
+	    if (diveOptions2) {
+	      heuristicDV.setMaxIterations(majorIterations);
+	      heuristicDV.setPercentageToFix(0.0);
+	      heuristicDV.setMaxSimplexIterations(COIN_INT_MAX);
+	      heuristicDV.setMaxSimplexIterationsAtRoot(COIN_INT_MAX-(diveOptions2-1));
+	    }
+            model->addHeuristic(&heuristicDV) ;
+        }
+        if ((useDIVING&2) != 0) {
+            CbcHeuristicDiveGuided heuristicDG(*model);
+            heuristicDG.setHeuristicName("DiveGuided");
+            heuristicDG.setWhen(diveOptions);
+	    if (diveOptions2) {
+	      heuristicDG.setMaxIterations(majorIterations);
+	      heuristicDG.setPercentageToFix(0.0);
+	      heuristicDG.setMaxSimplexIterations(COIN_INT_MAX);
+	      heuristicDG.setMaxSimplexIterationsAtRoot(COIN_INT_MAX-(diveOptions2-1));
+	    }
+            model->addHeuristic(&heuristicDG) ;
+        }
+        if ((useDIVING&4) != 0) {
+            CbcHeuristicDiveFractional heuristicDF(*model);
+            heuristicDF.setHeuristicName("DiveFractional");
+            heuristicDF.setWhen(diveOptions);
+	    if (diveOptions2) {
+	      heuristicDF.setMaxIterations(majorIterations);
+	      heuristicDF.setPercentageToFix(0.0);
+	      heuristicDF.setMaxSimplexIterations(COIN_INT_MAX);
+	      heuristicDF.setMaxSimplexIterationsAtRoot(COIN_INT_MAX-(diveOptions2-1));
+	    }
+            model->addHeuristic(&heuristicDF) ;
+        }
+        if ((useDIVING&8) != 0) {
+            CbcHeuristicDiveCoefficient heuristicDC(*model);
+            heuristicDC.setHeuristicName("DiveCoefficient");
+            heuristicDC.setWhen(diveOptions);
+	    if (diveOptions2) {
+	      heuristicDC.setMaxIterations(majorIterations);
+	      heuristicDC.setPercentageToFix(0.0);
+	      heuristicDC.setMaxSimplexIterations(COIN_INT_MAX);
+	      heuristicDC.setMaxSimplexIterationsAtRoot(COIN_INT_MAX-(diveOptions2-1));
+	    }
+            model->addHeuristic(&heuristicDC) ;
+        }
+        if ((useDIVING&16) != 0) {
+            CbcHeuristicDiveLineSearch heuristicDL(*model);
+            heuristicDL.setHeuristicName("DiveLineSearch");
+            heuristicDL.setWhen(diveOptions);
+	    if (diveOptions2) {
+	      heuristicDL.setMaxIterations(majorIterations);
+	      heuristicDL.setPercentageToFix(0.0);
+	      heuristicDL.setMaxSimplexIterations(COIN_INT_MAX);
+	      heuristicDL.setMaxSimplexIterationsAtRoot(COIN_INT_MAX-(diveOptions2-1));
+	    }
+            model->addHeuristic(&heuristicDL) ;
+        }
+        if ((useDIVING&32) != 0) {
+            CbcHeuristicDivePseudoCost heuristicDP(*model);
+            heuristicDP.setHeuristicName("DivePseudoCost");
+            heuristicDP.setWhen(diveOptions /*+ diveOptions2*/);
+	    if (diveOptions2) {
+	      heuristicDP.setMaxIterations(majorIterations);
+	      heuristicDP.setPercentageToFix(0.0);
+	      heuristicDP.setMaxSimplexIterations(COIN_INT_MAX);
+	      heuristicDP.setMaxSimplexIterationsAtRoot(COIN_INT_MAX-(diveOptions2-1));
+	    }
+            model->addHeuristic(&heuristicDP) ;
+        }
+        anyToDo = true;
+    }
+#ifdef JJF_ZERO
+    if (usePivotC >= type && usePivotC <= kType + 1) {
+        CbcHeuristicPivotAndComplement heuristic(*model);
+        heuristic.setHeuristicName("pivot and complement");
+        heuristic.setFractionSmall(10.0); // normally 0.5
+        model->addHeuristic(&heuristic);
+        anyToDo = true;
+    }
+#endif
+    if (usePivotF >= type && usePivotF <= kType + 1) {
+        CbcHeuristicPivotAndFix heuristic(*model);
+        heuristic.setHeuristicName("pivot and fix");
+        heuristic.setFractionSmall(10.0); // normally 0.5
+        model->addHeuristic(&heuristic);
+        anyToDo = true;
+    }
+    if (useRand >= type && useRand <= kType + 1) {
+        CbcHeuristicRandRound heuristic(*model);
+        heuristic.setHeuristicName("randomized rounding");
+        heuristic.setFractionSmall(10.0); // normally 0.5
+        model->addHeuristic(&heuristic);
+        anyToDo = true;
+    }
+    if (useDINS >= kType && useDINS <= kType + 1) {
+        CbcHeuristicDINS heuristic5a(*model);
+        heuristic5a.setHeuristicName("DINS");
+        heuristic5a.setFractionSmall(0.6);
+        if (useDINS < 4)
+            heuristic5a.setDecayFactor(5.0);
+        else
+            heuristic5a.setDecayFactor(1.5);
+        heuristic5a.setNumberNodes(1000);
+        model->addHeuristic(&heuristic5a) ;
+        anyToDo = true;
+    }
+    if (useRINS >= kType && useRINS <= kType + 1) {
+        CbcHeuristicRINS heuristic5(*model);
+        heuristic5.setHeuristicName("RINS");
+        if (useRINS < 4) {
+            heuristic5.setFractionSmall(0.5);
+            heuristic5.setDecayFactor(5.0);
+        } else {
+            heuristic5.setFractionSmall(0.6);
+            heuristic5.setDecayFactor(1.5);
+        }
+        model->addHeuristic(&heuristic5) ;
+        anyToDo = true;
+    }
+    if (useCombine >= kType && useCombine <= kType + 1) {
+        CbcHeuristicLocal heuristic2(*model);
+        heuristic2.setHeuristicName("combine solutions");
+        heuristic2.setFractionSmall(0.5);
+        heuristic2.setSearchType(1);
+        model->addHeuristic(&heuristic2);
+        anyToDo = true;
+    }
+    if ((useProximity >= kType && useProximity <= kType + 1)||
+	(kType == 1 && useProximity >= 4)) {
+        CbcHeuristicProximity heuristic2a(*model);
+        heuristic2a.setHeuristicName("Proximity Search");
+        heuristic2a.setFractionSmall(9999999.0);
+        heuristic2a.setNumberNodes(30);
+        heuristic2a.setFeasibilityPumpOptions(-2);
+	if (useProximity>=4) {
+	  const int nodes[]={10,100,300};
+	  heuristic2a.setNumberNodes(nodes[useProximity-4]);
+	  // more print out and stronger feasibility pump
+	  if (useProximity==6)
+	    heuristic2a.setFeasibilityPumpOptions(-3);
+	}
+        model->addHeuristic(&heuristic2a);
+        anyToDo = true;
+    }
+    if (useCrossover >= kType && useCrossover <= kType + 1) {
+        CbcHeuristicCrossover heuristic2a(*model);
+        heuristic2a.setHeuristicName("crossover");
+        heuristic2a.setFractionSmall(0.3);
+        // just fix at lower
+        heuristic2a.setWhen(11);
+        model->addHeuristic(&heuristic2a);
+        model->setMaximumSavedSolutions(5);
+        anyToDo = true;
+    }
+    int heurSwitches = parameters_[whichParam(CBC_PARAM_INT_HOPTIONS, numberParameters_, parameters_)].intValue() % 100;
+    if (heurSwitches) {
+        for (int iHeur = 0; iHeur < model->numberHeuristics(); iHeur++) {
+            CbcHeuristic * heuristic = model->heuristic(iHeur);
+            heuristic->setSwitches(heurSwitches);
+        }
+    }
+    if (type == 2 && anyToDo) {
+        // Do heuristics
+#ifndef JJF_ONE
+        // clean copy
+        CbcModel model2(*model);
+        // But get rid of heuristics in model
+        model->doHeuristicsAtRoot(2);
+        if (logLevel <= 1)
+            model2.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        OsiBabSolver defaultC;
+        //solver_->setAuxiliaryInfo(&defaultC);
+        model2.passInSolverCharacteristics(&defaultC);
+        // Save bounds
+        int numberColumns = model2.solver()->getNumCols();
+        model2.createContinuousSolver();
+        bool cleanModel = !model2.numberIntegers() && !model2.numberObjects();
+        model2.findIntegers(false);
+        int heurOptions = (parameters_[whichParam(CBC_PARAM_INT_HOPTIONS, numberParameters_, parameters_)].intValue() / 100) % 100;
+        if (heurOptions == 0 || heurOptions == 2) {
+            model2.doHeuristicsAtRoot(1);
+        } else if (heurOptions == 1 || heurOptions == 3) {
+            model2.setMaximumNodes(-1);
+            CbcStrategyDefault strategy(0, 5, 5);
+            strategy.setupPreProcessing(1, 0);
+            model2.setStrategy(strategy);
+            model2.branchAndBound();
+        }
+        if (cleanModel)
+            model2.zapIntegerInformation(false);
+        if (model2.bestSolution()) {
+            double value = model2.getMinimizationObjValue();
+            model->setCutoff(value);
+            model->setBestSolution(model2.bestSolution(), numberColumns, value);
+            model->setSolutionCount(1);
+            model->setNumberHeuristicSolutions(1);
+        }
+#else
+        if (logLevel <= 1)
+            model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        OsiBabSolver defaultC;
+        //solver_->setAuxiliaryInfo(&defaultC);
+        model->passInSolverCharacteristics(&defaultC);
+        // Save bounds
+        int numberColumns = model->solver()->getNumCols();
+        model->createContinuousSolver();
+        bool cleanModel = !model->numberIntegers() && !model->numberObjects();
+        model->findIntegers(false);
+        model->doHeuristicsAtRoot(1);
+        if (cleanModel)
+            model->zapIntegerInformation(false);
+#endif
+        return 0;
+    } else {
+        return 0;
+    }
+}
+
diff --git a/cbits/coin/CbcSolverHeuristics.hpp b/cbits/coin/CbcSolverHeuristics.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSolverHeuristics.hpp
@@ -0,0 +1,47 @@
+/* $Id: CbcSolverHeuristics.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+/*! \file CbcSolverHeuristics.hpp
+    \brief Routines for doing heuristics.
+*/
+
+
+#ifndef CbcSolverHeuristics_H
+#define CbcSolverHeuristics_H
+
+
+void crunchIt(ClpSimplex * model);
+
+/*
+  On input
+  doAction - 0 just fix in original and return NULL
+             1 return fixed non-presolved solver
+             2 as one but use presolve Inside this
+	     3 use presolve and fix ones with large cost
+             ? do heuristics and set best solution
+	     ? do BAB and just set best solution
+	     10+ then use lastSolution and relax a few
+             -2 cleanup afterwards if using 2
+  On output - number fixed
+*/
+OsiClpSolverInterface *
+fixVubs(CbcModel & model, int skipZero2,
+        int & doAction,
+        CoinMessageHandler * /*generalMessageHandler*/,
+        const double * lastSolution, double dextra[6],
+        int extra[5]);
+        
+    /** 1 - add heuristics to model
+        2 - do heuristics (and set cutoff and best solution)
+        3 - for miplib test so skip some
+        (out model later)
+    */
+int doHeuristics(CbcModel * model, int type, CbcOrClpParam *parameters_,
+		 int numberParameters_,int noPrinting_,int initialPumpTune) ;
+
+
+#endif  //CbcSolverHeuristics_H
+
diff --git a/cbits/coin/CbcStatistics.cpp b/cbits/coin/CbcStatistics.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcStatistics.cpp
@@ -0,0 +1,139 @@
+/* $Id: CbcStatistics.cpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+#include <cstdio>
+
+#include "CbcStatistics.hpp"
+CbcStatistics &
+CbcStatistics::operator=(const CbcStatistics & rhs)
+{
+    if (this != &rhs) {
+        value_ = rhs.value_;
+        startingObjective_ = rhs.startingObjective_;
+        endingObjective_ = rhs.endingObjective_;
+        id_ = rhs.id_;
+        parentId_ = rhs.parentId_;
+        way_ = rhs.way_;
+        sequence_ = rhs.sequence_;
+        depth_ = rhs.depth_;
+        startingInfeasibility_ = rhs.startingInfeasibility_;
+        endingInfeasibility_ = rhs.endingInfeasibility_;
+        numberIterations_ = rhs.numberIterations_;
+    }
+    return *this;
+}
+
+CbcStatistics::CbcStatistics () :
+        value_ ( 0.0),
+        startingObjective_(0.0),
+        endingObjective_(COIN_DBL_MAX),
+        id_(-1),
+        parentId_(-1),
+        way_ ( 0),
+        sequence_(-1),
+        depth_(0),
+        startingInfeasibility_(-1),
+        endingInfeasibility_(0),
+        numberIterations_(0)
+{
+}
+// First or second branch
+CbcStatistics::CbcStatistics(CbcNode * node, CbcModel * model)
+        :  endingObjective_(COIN_DBL_MAX),
+        endingInfeasibility_(0),
+        numberIterations_(0)
+{
+    CbcNodeInfo * nodeInfo = node->nodeInfo();
+    CbcNodeInfo * parent = nodeInfo->parent();
+    int numberBranches = nodeInfo->numberBranchesLeft();
+    const CbcBranchingObject * branch = dynamic_cast <const CbcBranchingObject *>(node->branchingObject());
+    const OsiTwoWayBranchingObject * branch2 = dynamic_cast <const OsiTwoWayBranchingObject *>(node->branchingObject());
+    startingObjective_ = node->objectiveValue();
+    way_ = node->way();
+    depth_ = node->depth();
+    startingInfeasibility_ = node->numberUnsatisfied();
+    if (branch) {
+        sequence_ = branch->variable();
+        value_ = branch->value();
+    } else {
+        const OsiSimpleInteger * obj = dynamic_cast<const OsiSimpleInteger *>(branch2->originalObject());
+        assert (obj);
+        sequence_ = obj->columnNumber();
+        value_ = branch2->value();
+    }
+    if (parent)
+        parentId_ = parent->nodeNumber();
+    else
+        parentId_ = -1;
+    if (numberBranches == 2) {
+        id_ = nodeInfo->nodeNumber();
+    } else {
+        way_ *= 10;
+        id_ = model->getNodeCount2();
+    }
+}
+
+CbcStatistics::CbcStatistics(const CbcStatistics & rhs) :
+        value_ ( rhs.value_),
+        startingObjective_(rhs.startingObjective_),
+        endingObjective_(rhs.endingObjective_),
+        id_(rhs.id_),
+        parentId_(rhs.parentId_),
+        way_ ( rhs.way_),
+        sequence_(rhs.sequence_),
+        depth_(rhs.depth_),
+        startingInfeasibility_(rhs.startingInfeasibility_),
+        endingInfeasibility_(rhs.endingInfeasibility_),
+        numberIterations_(rhs.numberIterations_)
+{
+}
+
+CbcStatistics::~CbcStatistics ()
+{
+}
+// Update at end of branch
+void
+CbcStatistics::endOfBranch(int numberIterations, double objectiveValue)
+{
+    numberIterations_ = numberIterations;
+    endingObjective_ = objectiveValue;
+}
+// Update number of infeasibilities
+void
+CbcStatistics::updateInfeasibility(int numberInfeasibilities)
+{
+    endingInfeasibility_ = numberInfeasibilities;
+}
+// Branch found to be infeasible by chooseBranch
+void
+CbcStatistics::sayInfeasible()
+{
+    endingObjective_ = COIN_DBL_MAX;
+}
+// Just prints
+void
+CbcStatistics::print(const int * sequenceLookup) const
+{
+    int sequence = -1;
+    if (sequence_ >= 0)
+        sequence = sequenceLookup ? sequenceLookup[sequence_] : sequence_;
+    printf("%6d %6d %5d %6d %7.3f %s %s %13.7g (%5d) -> ",
+           id_, parentId_, depth_, sequence, value_, abs(way_) == 1 ? " left" : "right",
+           way_ < 0 ? "down" : " up ", startingObjective_, startingInfeasibility_);
+    if (endingObjective_ != COIN_DBL_MAX)
+        if (endingInfeasibility_)
+            printf("%13.7g (%5d)\n", endingObjective_, endingInfeasibility_);
+        else
+            printf("%13.7g ** Solution\n", endingObjective_);
+    else
+        printf("cutoff\n");
+}
+
diff --git a/cbits/coin/CbcStatistics.hpp b/cbits/coin/CbcStatistics.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcStatistics.hpp
@@ -0,0 +1,101 @@
+/* $Id: CbcStatistics.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcStatistics_H
+#define CbcStatistics_H
+
+#include "CbcModel.hpp"
+
+/** For gathering statistics */
+
+class CbcStatistics {
+public:
+    // Default Constructor
+    CbcStatistics ();
+    // Branch
+    CbcStatistics(CbcNode * node, CbcModel * model);
+
+    ~CbcStatistics();
+    // Copy
+    CbcStatistics(const CbcStatistics & rhs);
+    // Assignment
+    CbcStatistics& operator=(const CbcStatistics & rhs);
+    // Update at end of branch
+    void endOfBranch(int numberIterations, double objectiveValue);
+    // Update number of infeasibilities
+    void updateInfeasibility(int numberInfeasibilities);
+    // Branch found to be infeasible by chooseBranch
+    void sayInfeasible();
+    // Just prints
+    void print(const int * sequenceLookup = NULL) const;
+    // Node number
+    inline int node() const {
+        return id_;
+    }
+    // Parent node number
+    inline int parentNode() const {
+        return parentId_;
+    }
+    // depth
+    inline int depth() const {
+        return depth_;
+    }
+    // way
+    inline int way() const {
+        return way_;
+    }
+    // value
+    inline double value() const {
+        return value_;
+    }
+    // starting objective
+    inline double startingObjective() const {
+        return startingObjective_;
+    }
+    // Unsatisfied at beginning
+    inline int startingInfeasibility() const {
+        return startingInfeasibility_;
+    }
+    // starting objective
+    inline double endingObjective() const {
+        return endingObjective_;
+    }
+    // Unsatisfied at end
+    inline int endingInfeasibility() const {
+        return endingInfeasibility_;
+    }
+    // Number iterations
+    inline int numberIterations() const {
+        return numberIterations_;
+    }
+
+protected:
+    // Data
+    /// Value
+    double value_;
+    /// Starting objective
+    double startingObjective_;
+    /// Ending objective
+    double endingObjective_;
+    /// id
+    int id_;
+    /// parent id
+    int parentId_;
+    /// way -1 or +1 is first branch -10 or +10 is second branch
+    int way_;
+    /// sequence number branched on
+    int sequence_;
+    /// depth
+    int depth_;
+    /// starting number of integer infeasibilities
+    int startingInfeasibility_;
+    /// ending number of integer infeasibilities
+    int endingInfeasibility_;
+    /// number of iterations
+    int numberIterations_;
+};
+
+#endif
+
diff --git a/cbits/coin/CbcStrategy.cpp b/cbits/coin/CbcStrategy.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcStrategy.cpp
@@ -0,0 +1,1029 @@
+/* $Id: CbcStrategy.cpp 1641 2011-04-17 15:08:40Z forrest $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcConfig.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "OsiSolverInterface.hpp"
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcStrategy.hpp"
+#include "CbcCutGenerator.hpp"
+#include "CbcBranchActual.hpp"
+#include "CbcNode.hpp"
+#include "CoinWarmStart.hpp"
+#include "CglPreProcess.hpp"
+// Cuts
+
+#include "CglGomory.hpp"
+#include "CglProbing.hpp"
+#include "CglKnapsackCover.hpp"
+#include "CglOddHole.hpp"
+#include "CglClique.hpp"
+#include "CglFlowCover.hpp"
+#include "CglMixedIntegerRounding2.hpp"
+
+// Heuristics
+
+#include "CbcHeuristic.hpp"
+#include "CbcHeuristicLocal.hpp"
+#include "CbcHeuristicRINS.hpp"
+
+// Default Constructor
+CbcStrategy::CbcStrategy()
+        : depth_(0),
+        preProcessState_(0),
+        process_(NULL)
+{
+}
+
+// Destructor
+CbcStrategy::~CbcStrategy ()
+{
+    delete process_;
+}
+// Delete pre-processing object to save memory
+void
+CbcStrategy::deletePreProcess()
+{
+    delete process_;
+    process_ = NULL;
+}
+// Return a new Full node information pointer (descendant of CbcFullNodeInfo)
+CbcNodeInfo *
+CbcStrategy::fullNodeInfo(CbcModel * model, int numberRowsAtContinuous) const
+{
+    return new CbcFullNodeInfo(model, numberRowsAtContinuous);
+}
+// Return a new Partial node information pointer (descendant of CbcPartialNodeInfo)
+CbcNodeInfo *
+CbcStrategy::partialNodeInfo(CbcModel * /*model*/,
+                             CbcNodeInfo * parent, CbcNode * owner,
+                             int numberChangedBounds, const int * variables,
+                             const double * boundChanges,
+                             const CoinWarmStartDiff *basisDiff) const
+{
+    return new CbcPartialNodeInfo(parent, owner, numberChangedBounds, variables,
+                                  boundChanges, basisDiff);
+}
+/* After a CbcModel::resolve this can return a status
+   -1 no effect
+   0 treat as optimal
+   1 as 0 but do not do any more resolves (i.e. no more cuts)
+   2 treat as infeasible
+*/
+int
+CbcStrategy::status(CbcModel * /*model*/, CbcNodeInfo * /*parent*/,
+                    int /*whereFrom*/)
+{
+    return -1;
+}
+
+// Default Constructor
+CbcStrategyDefault::CbcStrategyDefault(int cutsOnlyAtRoot,
+                                       int numberStrong,
+                                       int numberBeforeTrust,
+                                       int printLevel)
+        : CbcStrategy(),
+        cutsOnlyAtRoot_(cutsOnlyAtRoot),
+        numberStrong_(numberStrong),
+        numberBeforeTrust_(numberBeforeTrust),
+        printLevel_(printLevel),
+        desiredPreProcess_(0),
+        preProcessPasses_(0)
+{
+}
+
+
+// Destructor
+CbcStrategyDefault::~CbcStrategyDefault ()
+{
+}
+
+// Clone
+CbcStrategy *
+CbcStrategyDefault::clone() const
+{
+    return new CbcStrategyDefault(*this);
+}
+
+// Copy constructor
+CbcStrategyDefault::CbcStrategyDefault(const CbcStrategyDefault & rhs)
+        :
+        CbcStrategy(rhs),
+        cutsOnlyAtRoot_(rhs.cutsOnlyAtRoot_),
+        numberStrong_(rhs.numberStrong_),
+        numberBeforeTrust_(rhs.numberBeforeTrust_),
+        printLevel_(rhs.printLevel_),
+        desiredPreProcess_(rhs.desiredPreProcess_),
+        preProcessPasses_(rhs.preProcessPasses_)
+{
+    setNested(rhs.getNested());
+}
+
+/*
+  Set up cut generators. Will instantiate Probing, Gomory, Knapsack, Clique,
+  FlowCover, and MIR2 generators. Probing should be the first in the vector
+  of generators as it tightens bounds on continuous variables.
+
+  Cut generators already installed will dominate cut generators instantiated
+  here.
+
+  There's a classic magic number overloaded parameter example here. The
+  variable genFlags below is interpreted as single-bit flags to control
+  whether a cut generator will be instantiated: Probing:1, Gomory:2,
+  Knapsack:4, Clique:8, FlowCover:16, MIR2:32. Normally it's hardcoded to 63.
+  If CBC_GENERATE_TEST is defined, and the model's node limit is set between
+  190000 and 190064, genFlags is loaded with the low-order bits.
+*/
+void
+CbcStrategyDefault::setupCutGenerators(CbcModel & model)
+{
+    if (cutsOnlyAtRoot_ < 0)
+        return; // no cuts wanted
+
+    // Magic number overloaded parameter -- see comment at head.
+    int genFlags = 63;
+#   ifdef CBC_GENERATE_TEST
+    int nNodes = model.getMaximumNodes();
+    if (nNodes >= 190000 && nNodes < 190064)
+        genFlags = nNodes - 190000;
+#   endif
+
+    CglProbing generator1;
+    generator1.setUsingObjective(true);
+    generator1.setMaxPass(1);
+    generator1.setMaxPassRoot(1);
+    // Number of unsatisfied variables to look at
+    generator1.setMaxProbe(10);
+    // How far to follow the consequences
+    generator1.setMaxLook(10);
+    // Only look at rows with fewer than this number of elements
+    generator1.setMaxElements(200);
+    generator1.setMaxElementsRoot(300);
+    //generator1.setRowCuts(3);
+
+    CglGomory generator2;
+    // try larger limit
+    generator2.setLimit(300);
+
+    CglKnapsackCover generator3;
+
+    //CglOddHole generator4;
+    //generator4.setMinimumViolation(0.005);
+    //generator4.setMinimumViolationPer(0.00002);
+    // try larger limit
+    //generator4.setMaximumEntries(200);
+
+    CglClique generator5;
+    generator5.setStarCliqueReport(false);
+    generator5.setRowCliqueReport(false);
+
+    CglMixedIntegerRounding2 mixedGen;
+    CglFlowCover flowGen;
+
+    /*
+      Add in generators. Do not override generators already installed.
+    */
+    int setting = cutsOnlyAtRoot_ ? -99 : -1;
+    int numberGenerators = model.numberCutGenerators();
+    int iGenerator;
+    bool found;
+    found = false;
+    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+        CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found && (genFlags&1) != 0)
+        model.addCutGenerator(&generator1, setting, "Probing");
+    found = false;
+
+    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+        CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found && (genFlags&2) != 0)
+        model.addCutGenerator(&generator2, setting, "Gomory");
+
+    found = false;
+    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+        CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found && (genFlags&4) != 0)
+        model.addCutGenerator(&generator3, setting, "Knapsack");
+    //model.addCutGenerator(&generator4,setting,"OddHole");
+
+    found = false;
+    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+        CglClique * cgl = dynamic_cast<CglClique *>(generator);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found && (genFlags&8) != 0)
+        model.addCutGenerator(&generator5, setting, "Clique");
+
+    found = false;
+    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+        CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found && (genFlags&16) != 0)
+        model.addCutGenerator(&flowGen, setting, "FlowCover");
+
+    found = false;
+    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+        CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found && (genFlags&32) != 0)
+        model.addCutGenerator(&mixedGen, setting, "MixedIntegerRounding2");
+
+    // Say we want timings
+    int newNumberGenerators = model.numberCutGenerators();
+    for (iGenerator = numberGenerators; iGenerator < newNumberGenerators; iGenerator++) {
+        CbcCutGenerator * generator = model.cutGenerator(iGenerator);
+        generator->setTiming(true);
+    }
+
+    // Caution! Undocumented magic numbers.
+    int currentPasses = model.getMaximumCutPassesAtRoot();
+    if (currentPasses >= 0) {
+        if (model.getNumCols() < 5000)
+            model.setMaximumCutPassesAtRoot(CoinMax(50, currentPasses)); // use minimum drop
+        else
+            model.setMaximumCutPassesAtRoot(CoinMax(20, currentPasses));
+    } else {
+        currentPasses = -currentPasses;
+        if (model.getNumCols() < 500)
+            model.setMaximumCutPassesAtRoot(-CoinMax(100, currentPasses)); // always do 100 if possible
+        else
+            model.setMaximumCutPassesAtRoot(-CoinMax(20, currentPasses));
+    }
+}
+// Setup heuristics
+void
+CbcStrategyDefault::setupHeuristics(CbcModel & model)
+{
+    // Allow rounding heuristic
+
+    CbcRounding heuristic1(model);
+    heuristic1.setHeuristicName("rounding");
+    int numberHeuristics = model.numberHeuristics();
+    int iHeuristic;
+    bool found;
+    found = false;
+    for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
+        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
+        CbcRounding * cgl = dynamic_cast<CbcRounding *>(heuristic);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found)
+        model.addHeuristic(&heuristic1);
+#ifdef JJF_ZERO
+    // Allow join solutions
+    CbcHeuristicLocal heuristic2(model);
+    heuristic2.setHeuristicName("join solutions");
+    heuristic2.setSearchType(1);
+    found = false;
+    for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
+        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
+        CbcHeuristicLocal * cgl = dynamic_cast<CbcHeuristicLocal *>(heuristic);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found)
+        model.addHeuristic(&heuristic2);
+#endif
+}
+// Do printing stuff
+void
+CbcStrategyDefault::setupPrinting(CbcModel & model, int modelLogLevel)
+{
+    if (!modelLogLevel) {
+        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        model.messageHandler()->setLogLevel(0);
+        model.solver()->messageHandler()->setLogLevel(0);
+    } else if (modelLogLevel == 1) {
+        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        model.messageHandler()->setLogLevel(1);
+        model.solver()->messageHandler()->setLogLevel(0);
+    } else {
+        model.messageHandler()->setLogLevel(CoinMax(2, model.messageHandler()->logLevel()));
+        model.solver()->messageHandler()->setLogLevel(CoinMax(1, model.solver()->messageHandler()->logLevel()));
+        model.setPrintFrequency(CoinMin(50, model.printFrequency()));
+    }
+}
+
+/*
+ Aside from setting CbcModel::numberStrong_ and numberBeforeTrust, the big
+ activity is integer preprocessing. Surely this code to do preprocessing
+ duplicates code to do preprocessing up in the solver main routine. Most of the
+ effort goes into manipulating SOS sets.
+*/
+// Other stuff e.g. strong branching
+void
+CbcStrategyDefault::setupOther(CbcModel & model)
+{
+    // See if preprocessing wanted
+    if (desiredPreProcess_) {
+        delete process_;
+        /*
+          Inaccurate as of 080122 --- assignSolver (below) can now be instructed not to
+          delete the existing solver when the preprocessed solver is assigned to the
+          model. 'Course, we do need to hold on to a pointer somewhere, and that must
+          be captured before this call.
+        */
+        // solver_ should have been cloned outside
+        CglPreProcess * process = new CglPreProcess();
+        // Pass in models message handler
+        process->passInMessageHandler(model.messageHandler());
+        OsiSolverInterface * solver = model.solver();
+#ifdef COIN_HAS_CLP
+        OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+        if (clpSolver && false) {
+            // see if all coefficients multiple of 0.01 (close enough)
+            CoinPackedMatrix * matrix = clpSolver->getModelPtr()->matrix();
+            double * element = matrix->getMutableElements();
+            //const int * row = matrix->getIndices();
+            const CoinBigIndex * columnStart = matrix->getVectorStarts();
+            const int * columnLength = matrix->getVectorLengths();
+            int numberInt = 0;
+            int numberNon = 0;
+            int numberClose = 0;
+            int numberColumns = clpSolver->getNumCols();
+            int iColumn;
+            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                for (int j = columnStart[iColumn];
+                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    //int iRow = row[j];
+                    double value1 = element[j];
+                    double value = fabs(value1);
+                    if (value > 1.0e7) {
+                        if (value != floor(value))
+                            numberNon++;
+                        else
+                            numberInt++;
+                    } else {
+                        int iValue = static_cast<int>( 100 * (value + 0.005));
+                        double value2 = iValue;
+                        if (value2 == 100.0*value) {
+                            numberInt++;
+                        } else if (fabs(value2 - 100.0*value) < 1.0e-5) {
+                            numberClose++;
+                        } else {
+                            numberNon++;
+                        }
+                    }
+                }
+            }
+            if (!numberNon && numberClose) {
+                COIN_DETAIL_PRINT(printf("Tidying %d multiples of 0.01, %d close\n",
+					 numberInt, numberClose));
+                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    for (int j = columnStart[iColumn];
+                            j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                        //int iRow = row[j];
+                        double value1 = element[j];
+                        double value = fabs(value1);
+                        if (value < 1.0e7) {
+                            int iValue = static_cast<int>( 100 * (value + 0.005));
+                            double value2 = iValue;
+                            if (value2 != 100.0*value) {
+                                value2 *= 0.01;
+                                if (fabs(value - floor(value + 0.5)) <= 1.0e-7)
+                                    value2 = floor(value + 0.5);
+                                if (value1 < 0.0)
+                                    value2 = -value2;
+                                element[j] = value2;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+#endif
+        {
+            // mark some columns as ineligible for presolve
+            int numberColumns = solver->getNumCols();
+            char * prohibited = new char[numberColumns];
+            memset(prohibited, 0, numberColumns);
+            int numberProhibited = 0;
+            /*
+              Create CbcSimpleInteger objects would be more accurate in the general
+              case.  The `false' parameter says we won't delete existing objects.
+
+              Only Clp will produce SOS objects in findIntegers (080122), and that's
+              where a possible conversion can occur. If clp is holding OsiSOS objects,
+              they'll be converted to CbcSOS objects.
+            */
+            // convert to Cbc integers
+            model.findIntegers(false);
+            int numberObjects = model.numberObjects();
+            if (numberObjects) {
+                OsiObject ** objects = model.objects();
+                for (int iObject = 0; iObject < numberObjects; iObject++) {
+                    CbcSOS * obj =
+                        dynamic_cast <CbcSOS *>(objects[iObject]) ;
+                    if (obj) {
+                        // SOS
+                        int n = obj->numberMembers();
+                        const int * which = obj->members();
+                        for (int i = 0; i < n; i++) {
+                            int iColumn = which[i];
+                            prohibited[iColumn] = 1;
+                            numberProhibited++;
+                        }
+                    }
+                }
+            }
+            if (numberProhibited)
+                process->passInProhibited(prohibited, numberColumns);
+            delete [] prohibited;
+        }
+        int logLevel = model.messageHandler()->logLevel();
+#ifdef COIN_HAS_CLP
+        //OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+        ClpSimplex * lpSolver = NULL;
+        if (clpSolver) {
+            if (clpSolver->messageHandler()->logLevel())
+                clpSolver->messageHandler()->setLogLevel(1);
+            if (logLevel > -1)
+                clpSolver->messageHandler()->setLogLevel(CoinMin(logLevel, clpSolver->messageHandler()->logLevel()));
+            lpSolver = clpSolver->getModelPtr();
+            /// If user left factorization frequency then compute
+            lpSolver->defaultFactorizationFrequency();
+        }
+#endif
+        // Tell solver we are in Branch and Cut
+        solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ;
+        // Default set of cut generators
+	// Limited set that could reduce problem size (drop rows / fix values)
+        CglProbing generator1;
+        generator1.setUsingObjective(true);
+        generator1.setMaxPass(1);
+        generator1.setMaxPassRoot(1);
+        generator1.setMaxProbeRoot(CoinMin(3000, solver->getNumCols()));
+        generator1.setMaxProbeRoot(123);
+        generator1.setMaxElements(100);
+        generator1.setMaxElementsRoot(200);
+        generator1.setMaxLookRoot(50);
+        generator1.setRowCuts(3);
+        //generator1.messageHandler()->setLogLevel(logLevel);
+        // Not needed with pass in process->messageHandler()->setLogLevel(logLevel);
+        // Add in generators
+        process->addCutGenerator(&generator1);
+        int translate[] = {9999, 0, 2, -2, 3, 4, 4, 4};
+        OsiSolverInterface * solver2 =
+            process->preProcessNonDefault(*solver,
+                                          translate[desiredPreProcess_], preProcessPasses_, 6);
+        // Tell solver we are not in Branch and Cut
+        solver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+        if (solver2)
+            solver2->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
+        bool feasible = true;
+        if (!solver2) {
+            feasible = false;
+            //printf("Pre-processing says infeasible\n");
+            delete process;
+            preProcessState_ = -1;
+            process_ = NULL;
+        } else {
+            // now tighten bounds
+#ifdef COIN_HAS_CLP
+            if (clpSolver) {
+                // model has changed
+                solver = model.solver();
+                OsiClpSolverInterface * clpSolver = dynamic_cast< OsiClpSolverInterface*> (solver);
+                ClpSimplex * lpSolver = clpSolver->getModelPtr();
+                lpSolver->passInMessageHandler(solver->messageHandler());
+                if (lpSolver->tightenPrimalBounds() == 0) {
+                    lpSolver->dual();
+                } else {
+                    feasible = false;
+                }
+            }
+#endif
+            if (feasible) {
+                preProcessState_ = 1;
+                process_ = process;
+                /* Note that original solver will be kept (with false)
+                   and that final solver will also be kept.
+                   This is for post-processing
+
+		   Keep in mind when examining this that linear presolve does not
+		   understand SOS.
+                */
+                OsiSolverInterface * solver3 = solver2->clone();
+                model.assignSolver(solver3, false);
+                if (process_->numberSOS()) {
+                    int numberSOS = process_->numberSOS();
+                    int numberIntegers = model.numberIntegers();
+                    /* model may not have created objects
+                       If none then create
+                       NOTE - put back to original column numbers as
+                       CbcModel will pack down ALL as it doesn't know where from
+                    */
+                    bool someObjects = model.numberObjects() > 0;
+                    if (!numberIntegers || !model.numberObjects()) {
+                        model.findIntegers(true);
+                        numberIntegers = model.numberIntegers();
+                    }
+                    OsiObject ** oldObjects = model.objects();
+                    // Do sets and priorities
+                    OsiObject ** objects = new OsiObject * [numberSOS];
+                    // set old objects to have low priority
+                    int numberOldObjects = model.numberObjects();
+                    int numberColumns = model.getNumCols();
+                    for (int iObj = 0; iObj < numberOldObjects; iObj++) {
+                        int oldPriority = oldObjects[iObj]->priority();
+                        oldObjects[iObj]->setPriority(numberColumns + oldPriority);
+                    }
+                    const int * starts = process_->startSOS();
+                    const int * which = process_->whichSOS();
+                    const int * type = process_->typeSOS();
+                    const double * weight = process_->weightSOS();
+                    int iSOS;
+                    for (iSOS = 0; iSOS < numberSOS; iSOS++) {
+                        int iStart = starts[iSOS];
+                        int n = starts[iSOS+1] - iStart;
+                        objects[iSOS] = new CbcSOS(&model, n, which + iStart, weight + iStart,
+                                                   iSOS, type[iSOS]);
+                        // branch on long sets first
+                        objects[iSOS]->setPriority(numberColumns - n);
+                    }
+                    model.addObjects(numberSOS, objects);
+                    for (iSOS = 0; iSOS < numberSOS; iSOS++)
+                        delete objects[iSOS];
+                    delete [] objects;
+                    if (!someObjects) {
+                        // put back old column numbers
+                        const int * originalColumns = process_->originalColumns();
+                        // use reverse lookup to fake it
+                        int n = originalColumns[numberColumns-1] + 1;
+                        int * fake = new int[n];
+                        int i;
+                        // This was wrong (now is correct) - so could never have been called
+                        abort();
+                        for ( i = 0; i < n; i++)
+                            fake[i] = -1;
+                        for (i = 0; i < numberColumns; i++)
+                            fake[originalColumns[i]] = i;
+                        for (int iObject = 0; iObject < model.numberObjects(); iObject++) {
+                            // redo ids etc
+                            CbcSimpleInteger * obj =
+                                dynamic_cast <CbcSimpleInteger *>(model.modifiableObject(iObject)) ;
+                            if (obj) {
+                                obj->resetSequenceEtc(n, fake);
+                            } else {
+                                // redo ids etc
+                                CbcObject * obj =
+                                    dynamic_cast <CbcObject *>(model.modifiableObject(iObject)) ;
+                                assert (obj);
+                                obj->redoSequenceEtc(&model, n, fake);
+                            }
+                        }
+                        delete [] fake;
+                    }
+                }
+            } else {
+                //printf("Pre-processing says infeasible\n");
+                delete process;
+                preProcessState_ = -1;
+                process_ = NULL;
+            }
+        }
+    }
+    model.setNumberStrong(numberStrong_);
+    model.setNumberBeforeTrust(numberBeforeTrust_);
+}
+
+// Create C++ lines to get to current state
+void
+CbcStrategyDefault::generateCpp( FILE * fp)
+{
+    fprintf(fp, "0#include \"CbcStrategy.hpp\"\n");
+    fprintf(fp, "3  CbcStrategyDefault strategy(%s,%d,%d,%d);\n",
+            cutsOnlyAtRoot_ ? "1" : "0",
+            numberStrong_,
+            numberBeforeTrust_,
+            printLevel_);
+    fprintf(fp, "3  strategy.setupPreProcessing(%d,%d);\n",
+            desiredPreProcess_, preProcessPasses_);
+}
+// Default Constructor
+CbcStrategyDefaultSubTree::CbcStrategyDefaultSubTree(CbcModel * parent ,
+        int cutsOnlyAtRoot,
+        int numberStrong,
+        int numberBeforeTrust,
+        int printLevel)
+        : CbcStrategy(),
+        parentModel_(parent),
+        cutsOnlyAtRoot_(cutsOnlyAtRoot),
+        numberStrong_(numberStrong),
+        numberBeforeTrust_(numberBeforeTrust),
+        printLevel_(printLevel)
+{
+}
+
+
+// Destructor
+CbcStrategyDefaultSubTree::~CbcStrategyDefaultSubTree ()
+{
+}
+
+// Clone
+CbcStrategy *
+CbcStrategyDefaultSubTree::clone() const
+{
+    return new CbcStrategyDefaultSubTree(*this);
+}
+
+// Copy constructor
+CbcStrategyDefaultSubTree::CbcStrategyDefaultSubTree(const CbcStrategyDefaultSubTree & rhs)
+        :
+        CbcStrategy(rhs),
+        parentModel_(rhs.parentModel_),
+        cutsOnlyAtRoot_(rhs.cutsOnlyAtRoot_),
+        numberStrong_(rhs.numberStrong_),
+        numberBeforeTrust_(rhs.numberBeforeTrust_),
+        printLevel_(rhs.printLevel_)
+{
+    setNested(rhs.getNested());
+}
+
+// Setup cut generators
+void
+CbcStrategyDefaultSubTree::setupCutGenerators(CbcModel & model)
+{
+    // Set up some cut generators and defaults
+    if (cutsOnlyAtRoot_ < 0)
+        return; // no cuts wanted
+    // Probing first as gets tight bounds on continuous
+
+    CglProbing generator1;
+    generator1.setUsingObjective(true);
+    generator1.setMaxPass(1);
+    // Number of unsatisfied variables to look at
+    generator1.setMaxProbe(10);
+    // How far to follow the consequences
+    generator1.setMaxLook(10);
+    // Only look at rows with fewer than this number of elements
+    generator1.setMaxElements(200);
+    //generator1.setRowCuts(3);
+
+    CglGomory generator2;
+    // try larger limit
+    generator2.setLimit(300);
+
+    CglKnapsackCover generator3;
+
+    //CglOddHole generator4;
+    //generator4.setMinimumViolation(0.005);
+    //generator4.setMinimumViolationPer(0.00002);
+    // try larger limit
+    //generator4.setMaximumEntries(200);
+
+    CglClique generator5;
+    generator5.setStarCliqueReport(false);
+    generator5.setRowCliqueReport(false);
+
+    CglMixedIntegerRounding2 mixedGen;
+    CglFlowCover flowGen;
+
+    // Add in generators
+    int setting = cutsOnlyAtRoot_ ? -99 : -1;
+    int numberGenerators = model.numberCutGenerators();
+    int numberParentGenerators = parentModel_->numberCutGenerators();
+    int iGenerator;
+    bool found;
+    found = false;
+    int howOften = 0;
+    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
+        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
+        CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
+        if (cgl) {
+            found = true;
+            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
+            break;
+        }
+    }
+
+    if (found && (howOften >= -1 || howOften == -98)) {
+        found = false;
+        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+            CglProbing * cgl = dynamic_cast<CglProbing *>(generator);
+            if (cgl) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            if (howOften == -1)
+                howOften = -98;
+            else if (howOften == -98)
+                howOften = -99;
+            model.addCutGenerator(&generator1, setting, "Probing");
+            CbcCutGenerator * generator =
+                model.cutGenerator(numberGenerators);
+            generator->setHowOften(howOften);
+            numberGenerators++;
+        }
+    }
+    found = false;
+    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
+        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
+        CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
+        if (cgl) {
+            found = true;
+            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
+            break;
+        }
+    }
+    if (found && howOften >= 0) {
+        found = false;
+        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+            CglGomory * cgl = dynamic_cast<CglGomory *>(generator);
+            if (cgl) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            model.addCutGenerator(&generator2, setting, "Gomory");
+    }
+    found = false;
+    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
+        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
+        CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
+        if (cgl) {
+            found = true;
+            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
+            break;
+        }
+    }
+    if (found && howOften >= 0) {
+        found = false;
+        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+            CglKnapsackCover * cgl = dynamic_cast<CglKnapsackCover *>(generator);
+            if (cgl) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            model.addCutGenerator(&generator3, setting, "Knapsack");
+    }
+    found = false;
+    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
+        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
+        CglClique * cgl = dynamic_cast<CglClique *>(generator);
+        if (cgl) {
+            found = true;
+            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
+            break;
+        }
+    }
+    if (found && howOften >= 0) {
+        found = false;
+        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+            CglClique * cgl = dynamic_cast<CglClique *>(generator);
+            if (cgl) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            model.addCutGenerator(&generator5, setting, "Clique");
+    }
+    found = false;
+    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
+        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
+        CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
+        if (cgl) {
+            found = true;
+            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
+            break;
+        }
+    }
+    if (found && howOften >= 0) {
+        found = false;
+        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+            CglFlowCover * cgl = dynamic_cast<CglFlowCover *>(generator);
+            if (cgl) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            model.addCutGenerator(&flowGen, setting, "FlowCover");
+        found = false;
+    }
+    for (iGenerator = 0; iGenerator < numberParentGenerators; iGenerator++) {
+        CglCutGenerator * generator = parentModel_->cutGenerator(iGenerator)->generator();
+        CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
+        if (cgl) {
+            found = true;
+            howOften = parentModel_->cutGenerator(iGenerator)->howOften();
+            break;
+        }
+    }
+    if (found && howOften >= 0) {
+        found = false;
+        for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+            CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+            CglMixedIntegerRounding2 * cgl = dynamic_cast<CglMixedIntegerRounding2 *>(generator);
+            if (cgl) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            model.addCutGenerator(&mixedGen, setting, "MixedIntegerRounding2");
+    }
+#ifdef JJF_ZERO
+    // Say we want timings
+    int newNumberGenerators = model.numberCutGenerators();
+    for (iGenerator = numberGenerators; iGenerator < newNumberGenerators; iGenerator++) {
+        CbcCutGenerator * generator = model.cutGenerator(iGenerator);
+        generator->setTiming(true);
+    }
+#endif
+    if (model.getNumCols() < -500)
+        model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible
+    else if (model.getNumCols() < 5000)
+        model.setMaximumCutPassesAtRoot(100); // use minimum drop
+    else
+        model.setMaximumCutPassesAtRoot(20);
+}
+// Setup heuristics
+void
+CbcStrategyDefaultSubTree::setupHeuristics(CbcModel & model)
+{
+    // Allow rounding heuristic
+
+    CbcRounding heuristic1(model);
+    heuristic1.setHeuristicName("rounding");
+    int numberHeuristics = model.numberHeuristics();
+    int iHeuristic;
+    bool found;
+    found = false;
+    for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
+        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
+        CbcRounding * cgl = dynamic_cast<CbcRounding *>(heuristic);
+        if (cgl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found)
+        model.addHeuristic(&heuristic1);
+    if ((model.moreSpecialOptions()&32768)!=0) {
+      // Allow join solutions
+      CbcHeuristicLocal heuristic2(model);
+      heuristic2.setHeuristicName("join solutions");
+      //sheuristic2.setSearchType(1);
+      found = false;
+      for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
+        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
+        CbcHeuristicLocal * cgl = dynamic_cast<CbcHeuristicLocal *>(heuristic);
+        if (cgl) {
+	  found = true;
+	  break;
+        }
+      }
+      if (!found)
+        model.addHeuristic(&heuristic2);
+      // Allow RINS
+      CbcHeuristicRINS heuristic5(model);
+      heuristic5.setHeuristicName("RINS");
+      heuristic5.setFractionSmall(0.5);
+      heuristic5.setDecayFactor(5.0);
+      //heuristic5.setSearchType(1);
+      found = false;
+      for (iHeuristic = 0; iHeuristic < numberHeuristics; iHeuristic++) {
+        CbcHeuristic * heuristic = model.heuristic(iHeuristic);
+        CbcHeuristicLocal * cgl = dynamic_cast<CbcHeuristicLocal *>(heuristic);
+        if (cgl) {
+	  found = true;
+	  break;
+        }
+      }
+      if (!found)
+        model.addHeuristic(&heuristic5);
+    }
+}
+// Do printing stuff
+void
+CbcStrategyDefaultSubTree::setupPrinting(CbcModel & model, int modelLogLevel)
+{
+    if (!modelLogLevel) {
+        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        model.messageHandler()->setLogLevel(0);
+        model.solver()->messageHandler()->setLogLevel(0);
+    } else if (modelLogLevel == 1) {
+        model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
+        model.messageHandler()->setLogLevel(1);
+        model.solver()->messageHandler()->setLogLevel(0);
+    } else {
+        model.messageHandler()->setLogLevel(2);
+        model.solver()->messageHandler()->setLogLevel(1);
+        model.setPrintFrequency(50);
+    }
+}
+// Other stuff e.g. strong branching
+void
+CbcStrategyDefaultSubTree::setupOther(CbcModel & model)
+{
+    model.setNumberStrong(numberStrong_);
+    model.setNumberBeforeTrust(numberBeforeTrust_);
+}
+// For uniform setting of cut and heuristic options
+void
+setCutAndHeuristicOptions(CbcModel & model)
+{
+    int numberGenerators = model.numberCutGenerators();
+    int iGenerator;
+    for (iGenerator = 0; iGenerator < numberGenerators; iGenerator++) {
+        CglCutGenerator * generator = model.cutGenerator(iGenerator)->generator();
+        CglProbing * cglProbing = dynamic_cast<CglProbing *>(generator);
+        if (cglProbing) {
+            cglProbing->setUsingObjective(1);
+            cglProbing->setMaxPass(1);
+            cglProbing->setMaxPassRoot(1);
+            // Number of unsatisfied variables to look at
+            cglProbing->setMaxProbe(10);
+            cglProbing->setMaxProbeRoot(50);
+            //cglProbing->setMaxProbeRoot(123);
+            // How far to follow the consequences
+            cglProbing->setMaxLook(5);
+            cglProbing->setMaxLookRoot(50);
+            cglProbing->setMaxLookRoot(10);
+            // Only look at rows with fewer than this number of elements
+            cglProbing->setMaxElements(200);
+            cglProbing->setMaxElementsRoot(300);
+            cglProbing->setRowCuts(3);
+        }
+#ifdef JJF_ZERO
+        CglGomory * cglGomory = dynamic_cast<CglGomory *>(generator);
+        if (cglGomory) {
+            // try larger limit
+            cglGomory->setLimitAtRoot(1000);
+            cglGomory->setLimit(50);
+        }
+        CglKnapsackCover * cglKnapsackCover = dynamic_cast<CglKnapsackCover *>(generator);
+        if (cglKnapsackCover) {
+        }
+#endif
+    }
+}
+
+
+
diff --git a/cbits/coin/CbcStrategy.hpp b/cbits/coin/CbcStrategy.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcStrategy.hpp
@@ -0,0 +1,258 @@
+/* $Id: CbcStrategy.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcStrategy_H
+#define CbcStrategy_H
+
+#include "CbcModel.hpp"
+class CglPreProcess;
+class CbcNodeInfo;
+class CbcNode;
+class CoinWarmStartDiff;
+
+//#############################################################################
+/** Strategy base class */
+
+class CbcStrategy {
+public:
+    // Default Constructor
+    CbcStrategy ();
+
+    virtual ~CbcStrategy();
+
+    /// Clone
+    virtual CbcStrategy * clone() const = 0;
+
+    /// Setup cut generators
+    virtual void setupCutGenerators(CbcModel & model) = 0;
+    /// Setup heuristics
+    virtual void setupHeuristics(CbcModel & model) = 0;
+    /// Do printing stuff
+    virtual void setupPrinting(CbcModel & model, int modelLogLevel) = 0;
+    /// Other stuff e.g. strong branching and preprocessing
+    virtual void setupOther(CbcModel & model) = 0;
+    /// Set model depth (i.e. how nested)
+    inline void setNested(int depth) {
+        depth_ = depth;
+    }
+    /// Get model depth (i.e. how nested)
+    inline int getNested() const {
+        return depth_;
+    }
+    /// Say preProcessing done
+    inline void setPreProcessState(int state) {
+        preProcessState_ = state;
+    }
+    /// See what sort of preprocessing was done
+    inline int preProcessState() const {
+        return preProcessState_;
+    }
+    /// Pre-processing object
+    inline CglPreProcess * process() const {
+        return process_;
+    }
+    /// Delete pre-processing object to save memory
+    void deletePreProcess();
+    /// Return a new Full node information pointer (descendant of CbcFullNodeInfo)
+    virtual CbcNodeInfo * fullNodeInfo(CbcModel * model, int numberRowsAtContinuous) const;
+    /// Return a new Partial node information pointer (descendant of CbcPartialNodeInfo)
+    virtual CbcNodeInfo * partialNodeInfo(CbcModel * model, CbcNodeInfo * parent, CbcNode * owner,
+                                          int numberChangedBounds, const int * variables,
+                                          const double * boundChanges,
+                                          const CoinWarmStartDiff *basisDiff) const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+    /** After a CbcModel::resolve this can return a status
+        -1 no effect
+        0 treat as optimal
+        1 as 0 but do not do any more resolves (i.e. no more cuts)
+        2 treat as infeasible
+    */
+    virtual int status(CbcModel * model, CbcNodeInfo * parent, int whereFrom);
+private:
+
+    /// Illegal Assignment operator
+    CbcStrategy & operator=(const CbcStrategy& rhs);
+protected:
+    // Data
+    /// Model depth
+    int depth_;
+    /** PreProcessing state -
+        -1 infeasible
+        0 off
+        1 was done (so need post-processing)
+    */
+    int preProcessState_;
+    /// If preprocessing then this is object
+    CglPreProcess * process_;
+};
+
+/** Null class
+ */
+
+class CbcStrategyNull : public CbcStrategy {
+public:
+
+    // Default Constructor
+    CbcStrategyNull () {}
+
+    // Copy constructor
+    CbcStrategyNull ( const CbcStrategyNull & rhs) : CbcStrategy(rhs) {}
+
+    // Destructor
+    ~CbcStrategyNull () {}
+
+    /// Clone
+    virtual CbcStrategy * clone() const {
+        return new CbcStrategyNull(*this);
+    }
+
+    /// Setup cut generators
+    virtual void setupCutGenerators(CbcModel & ) {}
+    /// Setup heuristics
+    virtual void setupHeuristics(CbcModel & ) {}
+    /// Do printing stuff
+    virtual void setupPrinting(CbcModel & , int ) {}
+    /// Other stuff e.g. strong branching
+    virtual void setupOther(CbcModel & ) {}
+
+protected:
+    // Data
+private:
+    /// Illegal Assignment operator
+    CbcStrategyNull & operator=(const CbcStrategyNull& rhs);
+};
+
+/** Default class
+ */
+
+class CbcStrategyDefault : public CbcStrategy {
+public:
+
+    // Default Constructor
+    CbcStrategyDefault (int cutsOnlyAtRoot = 1,
+                        int numberStrong = 5,
+                        int numberBeforeTrust = 0,
+                        int printLevel = 0);
+
+    // Copy constructor
+    CbcStrategyDefault ( const CbcStrategyDefault &);
+
+    // Destructor
+    ~CbcStrategyDefault ();
+
+    /// Clone
+    virtual CbcStrategy * clone() const;
+
+    /// Setup cut generators
+    virtual void setupCutGenerators(CbcModel & model);
+    /// Setup heuristics
+    virtual void setupHeuristics(CbcModel & model);
+    /// Do printing stuff
+    virtual void setupPrinting(CbcModel & model, int modelLogLevel) ;
+    /// Other stuff e.g. strong branching
+    virtual void setupOther(CbcModel & model);
+    /// Set up preProcessing - see below
+    inline void setupPreProcessing(int desired = 1, int passes = 10) {
+        desiredPreProcess_ = desired;
+        preProcessPasses_ = passes;
+    }
+    /// See what sort of preprocessing wanted
+    inline int desiredPreProcess() const {
+        return desiredPreProcess_;
+    }
+    /// See how many passes wanted
+    inline int preProcessPasses() const {
+        return preProcessPasses_;
+    }
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+protected:
+    // Data
+
+    // Whether to do cuts only at root (-1 -> switch off totally)
+    int cutsOnlyAtRoot_;
+
+    // How much strong branching to do
+    int numberStrong_;
+
+    // Number branches needed to trust with dynamic pseudo costs
+    int numberBeforeTrust_;
+
+    // Print level 0 little, 1 medium
+    int printLevel_;
+
+    /** Desired pre-processing
+        0 - none
+        1 - ordinary
+        2 - find sos
+        3 - find cliques
+        4 - more aggressive sos
+        5 - add integer slacks
+    */
+    int desiredPreProcess_;
+    /// Number of pre-processing passes
+    int preProcessPasses_;
+
+private:
+    /// Illegal Assignment operator
+    CbcStrategyDefault & operator=(const CbcStrategyDefault& rhs);
+};
+
+
+/** Default class for sub trees
+ */
+
+class CbcStrategyDefaultSubTree : public CbcStrategy {
+public:
+
+    // Default Constructor
+    CbcStrategyDefaultSubTree (CbcModel * parent = NULL, int cutsOnlyAtRoot = 1,
+                               int numberStrong = 5,
+                               int numberBeforeTrust = 0,
+                               int printLevel = 0);
+
+    // Copy constructor
+    CbcStrategyDefaultSubTree ( const CbcStrategyDefaultSubTree &);
+
+    // Destructor
+    ~CbcStrategyDefaultSubTree ();
+
+    /// Clone
+    virtual CbcStrategy * clone() const;
+
+    /// Setup cut generators
+    virtual void setupCutGenerators(CbcModel & model);
+    /// Setup heuristics
+    virtual void setupHeuristics(CbcModel & model);
+    /// Do printing stuff
+    virtual void setupPrinting(CbcModel & model, int modelLogLevel) ;
+    /// Other stuff e.g. strong branching
+    virtual void setupOther(CbcModel & model);
+protected:
+    // Data
+    // Parent model
+    CbcModel * parentModel_;
+    // Whether to do cuts only at root (-1 -> switch off totally)
+    int cutsOnlyAtRoot_;
+
+    // How much strong branching to do
+    int numberStrong_;
+
+    // Number branches needed to trust with dynamic pseudo costs
+    int numberBeforeTrust_;
+
+    // Print level 0 little, 1 medium
+    int printLevel_;
+
+private:
+    /// Illegal Assignment operator
+    CbcStrategyDefaultSubTree & operator=(const CbcStrategyDefaultSubTree& rhs);
+};
+
+
+#endif
+
diff --git a/cbits/coin/CbcSubProblem.cpp b/cbits/coin/CbcSubProblem.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSubProblem.cpp
@@ -0,0 +1,329 @@
+// $Id: CbcSubProblem.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define CBC_DEBUG
+
+#include "CoinPragma.hpp"
+#include "CoinTypes.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CbcModel.hpp"
+#include "CbcMessage.hpp"
+#include "CbcSubProblem.hpp"
+#include "CbcBranchActual.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+
+// Default Constructor
+CbcSubProblem::CbcSubProblem()
+  : objectiveValue_(0.0),
+    sumInfeasibilities_(0.0),
+    branchValue_(0.0),
+    djValue_(0.0),
+    variables_(NULL),
+    newBounds_(NULL),
+    status_(NULL),
+    depth_(0),
+    numberChangedBounds_(0),
+    numberInfeasibilities_(0),
+    problemStatus_(0),
+    branchVariable_(0)
+{
+}
+
+// Useful constructor
+CbcSubProblem::CbcSubProblem (const OsiSolverInterface * solver,
+                              const double * lastLower,
+                              const double * lastUpper,
+                              const unsigned char * status,
+                              int depth)
+  : objectiveValue_(0.0),
+    sumInfeasibilities_(0.0),
+    branchValue_(0.0),
+    djValue_(0.0),
+    variables_(NULL),
+    newBounds_(NULL),
+    status_(NULL),
+    depth_(depth),
+    numberChangedBounds_(0),
+    numberInfeasibilities_(0),
+    problemStatus_(0),
+    branchVariable_(0)
+{
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+
+    numberChangedBounds_ = 0;
+    int numberColumns = solver->getNumCols();
+    int i;
+    for (i = 0; i < numberColumns; i++) {
+        if (lower[i] != lastLower[i])
+            numberChangedBounds_++;
+        if (upper[i] != lastUpper[i])
+            numberChangedBounds_++;
+    }
+    if (numberChangedBounds_) {
+        newBounds_ = new double [numberChangedBounds_] ;
+        variables_ = new int [numberChangedBounds_] ;
+        numberChangedBounds_ = 0;
+        for (i = 0; i < numberColumns; i++) {
+            if (lower[i] != lastLower[i]) {
+                variables_[numberChangedBounds_] = i;
+                newBounds_[numberChangedBounds_++] = lower[i];
+            }
+            if (upper[i] != lastUpper[i]) {
+                variables_[numberChangedBounds_] = i | 0x80000000;
+                newBounds_[numberChangedBounds_++] = upper[i];
+            }
+#ifdef CBC_DEBUG
+            if (lower[i] != lastLower[i]) {
+                std::cout
+                    << "lower on " << i << " changed from "
+                    << lastLower[i] << " to " << lower[i] << std::endl ;
+            }
+            if (upper[i] != lastUpper[i]) {
+                std::cout
+                    << "upper on " << i << " changed from "
+                    << lastUpper[i] << " to " << upper[i] << std::endl ;
+            }
+#endif
+        }
+#ifdef CBC_DEBUG
+        std::cout << numberChangedBounds_ << " changed bounds." << std::endl ;
+#endif
+    }
+    const OsiClpSolverInterface * clpSolver
+    = dynamic_cast<const OsiClpSolverInterface *> (solver);
+    assert (clpSolver);
+    // Do difference
+    // Current basis
+    status_ = clpSolver->getBasis(status);
+    assert (status_->fullBasis());
+    //status_->print();
+}
+
+// Copy constructor
+CbcSubProblem::CbcSubProblem ( const CbcSubProblem & rhs)
+        : objectiveValue_(rhs.objectiveValue_),
+	  sumInfeasibilities_(rhs.sumInfeasibilities_),
+	  branchValue_(rhs.branchValue_),
+	  djValue_(rhs.djValue_),
+	  variables_(NULL),
+	  newBounds_(NULL),
+	  status_(NULL),
+	  depth_(rhs.depth_),
+	  numberChangedBounds_(rhs.numberChangedBounds_),
+	  numberInfeasibilities_(rhs.numberInfeasibilities_),
+	  problemStatus_(rhs.problemStatus_),
+	  branchVariable_(rhs.branchVariable_)
+{
+    if (numberChangedBounds_) {
+        variables_ = CoinCopyOfArray(rhs.variables_, numberChangedBounds_);
+        newBounds_ = CoinCopyOfArray(rhs.newBounds_, numberChangedBounds_);
+    }
+    if (rhs.status_) {
+        status_ = new CoinWarmStartBasis(*rhs.status_);
+    }
+}
+
+// Assignment operator
+CbcSubProblem &
+CbcSubProblem::operator=( const CbcSubProblem & rhs)
+{
+    if (this != &rhs) {
+        delete [] variables_;
+        delete [] newBounds_;
+        delete status_;
+        objectiveValue_ = rhs.objectiveValue_;
+        sumInfeasibilities_ = rhs.sumInfeasibilities_;
+	branchValue_ = rhs.branchValue_;
+	djValue_ = rhs.djValue_;
+        depth_ = rhs.depth_;
+        numberChangedBounds_ = rhs.numberChangedBounds_;
+        numberInfeasibilities_ = rhs.numberInfeasibilities_;
+	problemStatus_ = rhs.problemStatus_; 
+	branchVariable_ = rhs.branchVariable_;
+        if (numberChangedBounds_) {
+            variables_ = CoinCopyOfArray(rhs.variables_, numberChangedBounds_);
+            newBounds_ = CoinCopyOfArray(rhs.newBounds_, numberChangedBounds_);
+        } else {
+            variables_ = NULL;
+            newBounds_ = NULL;
+        }
+        if (rhs.status_) {
+            status_ = new CoinWarmStartBasis(*rhs.status_);
+        } else {
+            status_ = NULL;
+        }
+    }
+    return *this;
+}
+// Take over
+void
+CbcSubProblem::takeOver( CbcSubProblem & rhs, bool cleanUp)
+{
+    if (this != &rhs) {
+        delete [] variables_;
+        delete [] newBounds_;
+        delete status_;
+        objectiveValue_ = rhs.objectiveValue_;
+        sumInfeasibilities_ = rhs.sumInfeasibilities_;
+	branchValue_ = rhs.branchValue_;
+	djValue_ = rhs.djValue_;
+        depth_ = rhs.depth_;
+        numberChangedBounds_ = rhs.numberChangedBounds_;
+        numberInfeasibilities_ = rhs.numberInfeasibilities_;
+	problemStatus_ = rhs.problemStatus_; 
+	branchVariable_ = rhs.branchVariable_;
+	variables_ = rhs.variables_;
+	newBounds_ = rhs.newBounds_;
+	rhs.variables_ = NULL;
+	rhs.newBounds_ = NULL;
+	status_ = rhs.status_;
+	rhs.status_ = NULL;
+	if (cleanUp) {
+	  delete [] variables_;
+	  delete [] newBounds_;
+	  variables_ = new int [1];
+	  newBounds_ = new double [1];
+	  // swap way and make only fix
+	  numberChangedBounds_=1;
+	  if ((problemStatus_&1)==0) {
+	    // last way was down
+	    newBounds_[0] = ceil(branchValue_);
+	    variables_[0] = branchVariable_;
+	  } else {
+	    // last way was up
+	    newBounds_[0] = floor(branchValue_);
+	    variables_[0] = branchVariable_ | 0x80000000;
+	  }
+	}
+    }
+}
+
+// Destructor
+CbcSubProblem::~CbcSubProblem ()
+{
+    delete [] variables_;
+    delete [] newBounds_;
+    delete status_;
+}
+// Apply subproblem
+void
+CbcSubProblem::apply(OsiSolverInterface * solver, int what) const
+{
+    int i;
+    if ((what&1) != 0) {
+    printf("CbcSubapply depth %d column %d way %d bvalue %g obj %g\n",
+		 this->depth_,this->branchVariable_,this->problemStatus_,
+		 this->branchValue_,this->objectiveValue_);
+    printf("current bounds %g <= %g <= %g\n",solver->getColLower()[branchVariable_],branchValue_,solver->getColUpper()[branchVariable_]);
+#ifndef NDEBUG
+        int nSame = 0;
+#endif
+        for (i = 0; i < numberChangedBounds_; i++) {
+            int variable = variables_[i];
+            int k = variable & 0x3fffffff;
+            if ((variable&0x80000000) == 0) {
+                // lower bound changing
+                //#define CBC_PRINT2
+#ifdef CBC_PRINT2
+                if (solver->getColLower()[k] != newBounds_[i])
+                    printf("lower change for column %d - from %g to %g\n", k, solver->getColLower()[k], newBounds_[i]);
+#endif
+#ifndef NDEBUG
+                if ((variable&0x40000000) == 0 && true) {
+                    double oldValue = solver->getColLower()[k];
+                    assert (newBounds_[i] > oldValue - 1.0e-8);
+                    if (newBounds_[i] < oldValue + 1.0e-8) {
+#ifdef CBC_PRINT2
+                        printf("bad null lower change for column %d - bound %g\n", k, oldValue);
+#endif
+                        if (newBounds_[i] == oldValue)
+                            nSame++;
+                    }
+                }
+#endif
+                solver->setColLower(k, newBounds_[i]);
+            } else {
+                // upper bound changing
+#ifdef CBC_PRINT2
+                if (solver->getColUpper()[k] != newBounds_[i])
+                    printf("upper change for column %d - from %g to %g\n", k, solver->getColUpper()[k], newBounds_[i]);
+#endif
+#ifndef NDEBUG
+                if ((variable&0x40000000) == 0 && true) {
+                    double oldValue = solver->getColUpper()[k];
+                    assert (newBounds_[i] < oldValue + 1.0e-8);
+                    if (newBounds_[i] > oldValue - 1.0e-8) {
+#ifdef CBC_PRINT2
+                        printf("bad null upper change for column %d - bound %g\n", k, oldValue);
+#endif
+                        if (newBounds_[i] == oldValue)
+                            nSame++;
+                    }
+                }
+#endif
+                solver->setColUpper(k, newBounds_[i]);
+            }
+        }
+#ifndef NDEBUG
+#ifdef CBC_PRINT2
+        if (nSame && (nSame < numberChangedBounds_ || (what&3) != 3))
+            printf("%d changes out of %d redundant %d\n",
+                   nSame, numberChangedBounds_, what);
+        else if (numberChangedBounds_ && what == 7 && !nSame)
+            printf("%d good changes %d\n",
+                   numberChangedBounds_, what);
+#endif
+#endif
+    printf("new bounds %g <= %g <= %g\n",solver->getColLower()[branchVariable_],branchValue_,solver->getColUpper()[branchVariable_]);
+    }
+#ifdef JJF_ZERO
+    if ((what&2) != 0) {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver);
+        assert (clpSolver);
+        //assert (clpSolver->getNumRows()==numberRows_);
+        //clpSolver->setBasis(*status_);
+        // Current basis
+        CoinWarmStartBasis * basis = clpSolver->getPointerToWarmStart();
+        printf("BBBB\n");
+        basis->print();
+        assert (basis->fullBasis());
+        basis->applyDiff(status_);
+        printf("diff applied %x\n", status_);
+        printf("CCCC\n");
+        basis->print();
+        assert (basis->fullBasis());
+#ifndef NDEBUG
+        if (!basis->fullBasis())
+            printf("Debug this basis!!\n");
+#endif
+        clpSolver->setBasis(*basis);
+    }
+#endif
+    if ((what&8) != 0) {
+        OsiClpSolverInterface * clpSolver
+        = dynamic_cast<OsiClpSolverInterface *> (solver);
+        assert (clpSolver);
+        clpSolver->setBasis(*status_);
+	if ((what&16)==0) {
+	  delete status_;
+	  status_ = NULL;
+	}
+    }
+}
+
diff --git a/cbits/coin/CbcSubProblem.hpp b/cbits/coin/CbcSubProblem.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcSubProblem.hpp
@@ -0,0 +1,83 @@
+// $Id: CbcSubProblem.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// Edwin 11/10/2009-- carved out of CbcBranchActual
+
+#ifndef CbcSubProblem_H
+#define CbcSubProblem_H
+
+#ifdef COIN_HAS_CLP
+#include "ClpSimplex.hpp"
+#include "ClpNode.hpp"
+
+/** Defines a general subproblem
+    Basis will be made more compact later
+*/
+class CoinWarmStartDiff;
+class CbcSubProblem {
+
+public:
+
+    /// Default constructor
+    CbcSubProblem ();
+
+    /// Constructor from model
+    CbcSubProblem (const OsiSolverInterface * solver,
+                   const double * lowerBefore,
+                   const double * upperBefore,
+                   const unsigned char * status,
+                   int depth);
+
+    /// Copy constructor
+    CbcSubProblem ( const CbcSubProblem &);
+
+    /// Assignment operator
+    CbcSubProblem & operator= (const CbcSubProblem& rhs);
+
+    /// Destructor
+    virtual ~CbcSubProblem ();
+
+    /// Take over
+  void takeOver ( CbcSubProblem &, bool cleanup);
+    /// Apply subproblem (1=bounds, 2=basis, 3=both)
+    void apply(OsiSolverInterface * model, int what = 3) const;
+
+public:
+    /// Value of objective
+    double objectiveValue_;
+    /// Sum of infeasibilities
+    double sumInfeasibilities_;
+    /// Branch value
+    double branchValue_;
+    /// Dj on branching variable at end
+    double djValue_;
+    /** Which variable (top bit if upper bound changing)
+        next bit if changing on down branch only */
+    int * variables_;
+    /// New bound
+    double * newBounds_;
+    /// Status
+    mutable CoinWarmStartBasis * status_;
+    /// Depth
+    int depth_;
+    /// Number of Extra bound changes
+    int numberChangedBounds_;
+    /// Number of infeasibilities
+    int numberInfeasibilities_;
+    /** Status 1 bit going up on first, 2 bit set first branch infeasible on second, 4 bit redundant branch,
+	bits after 256 give reason for stopping (just last node)
+	0 - solution
+	1 - infeasible
+	2 - maximum depth
+	>2 - error or max time or something
+    */
+    int problemStatus_;
+    /// Variable branched on
+    int branchVariable_;
+};
+
+#endif //COIN_HAS_CLP
+#endif
+
diff --git a/cbits/coin/CbcThread.cpp b/cbits/coin/CbcThread.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcThread.cpp
@@ -0,0 +1,1961 @@
+/* $Id: CbcThread.cpp 1973 2013-10-19 15:59:44Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CbcConfig.h"
+
+//#define THREAD_DEBUG
+#include <string>
+#include <cassert>
+#include <cmath>
+#include <cfloat>
+
+#include "CbcEventHandler.hpp"
+
+#include "OsiSolverInterface.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CbcThread.hpp"
+#include "CbcTree.hpp"
+#include "CbcHeuristic.hpp"
+#include "CbcCutGenerator.hpp"
+#include "CbcModel.hpp"
+#include "CbcFathom.hpp"
+#include "CbcSimpleIntegerDynamicPseudoCost.hpp"
+#include "ClpDualRowDantzig.hpp"
+#include "OsiAuxInfo.hpp"
+
+#include "CoinTime.hpp"
+#ifdef CBC_THREAD
+/// Thread functions
+static void * doNodesThread(void * voidInfo);
+static void * doCutsThread(void * voidInfo);
+static void * doHeurThread(void * voidInfo);
+// Default Constructor
+CbcSpecificThread::CbcSpecificThread ()
+        : basePointer_(NULL),
+        masterMutex_(NULL),
+        locked_(false)
+{
+#ifdef CBC_PTHREAD
+    pthread_mutex_init(&mutex2_, NULL);
+    pthread_cond_init(&condition2_, NULL);
+    threadId_.status = 0;
+#else
+#endif
+}
+// Useful Constructor
+CbcSpecificThread::CbcSpecificThread (CbcSpecificThread * master, pthread_mutex_t * masterMutex)
+        : basePointer_(master),
+        masterMutex_(masterMutex),
+        locked_(false)
+
+{
+#ifdef CBC_PTHREAD
+    pthread_mutex_init(&mutex2_, NULL);
+    pthread_cond_init(&condition2_, NULL);
+    threadId_.status = 0;
+#else
+#endif
+
+}
+// Useful stuff
+void
+CbcSpecificThread::setUsefulStuff (CbcSpecificThread * master, void *& masterMutex)
+
+{
+#ifdef CBC_PTHREAD
+    basePointer_ = master;
+    if (masterMutex) {
+        masterMutex_ = reinterpret_cast<pthread_mutex_t *>(masterMutex);
+    } else {
+        // create master mutex
+        masterMutex_ = new pthread_mutex_t;
+        pthread_mutex_init(masterMutex_, NULL);
+        masterMutex = reinterpret_cast<void *>(masterMutex_);
+    }
+#else
+#endif
+}
+
+CbcSpecificThread::~CbcSpecificThread()
+{
+#ifdef CBC_PTHREAD
+    pthread_mutex_destroy (&mutex2_);
+    if (basePointer_ == this) {
+        pthread_mutex_destroy (masterMutex_);
+        delete masterMutex_;
+    }
+#else
+#endif
+}
+/*
+  Locks a thread if parallel so that stuff like cut pool
+  can be updated and/or used.
+*/
+void
+CbcSpecificThread::lockThread()
+{
+#ifdef CBC_PTHREAD
+    // Use master mutex
+    assert (basePointer_->masterMutex_ == masterMutex_);
+    pthread_mutex_lock (masterMutex_);
+#else
+#endif
+}
+/*
+  Unlocks a thread if parallel to say cut pool stuff not needed
+*/
+void
+CbcSpecificThread::unlockThread()
+{
+#ifdef CBC_PTHREAD
+    // Use master mutex
+    pthread_mutex_unlock (masterMutex_);
+#else
+#endif
+}
+//  Locks a thread for testing whether to start etc
+void
+CbcSpecificThread::lockThread2(bool doAnyway)
+{
+    if (!locked_ || doAnyway) {
+#ifdef CBC_PTHREAD
+        pthread_mutex_lock (&mutex2_);
+#else
+#endif
+        locked_ = true;
+    }
+}
+//  Unlocks a thread for testing whether to start etc
+void
+CbcSpecificThread::unlockThread2(bool doAnyway)
+{
+    if (locked_ || doAnyway) {
+#ifdef CBC_PTHREAD
+        pthread_mutex_unlock (&mutex2_);
+#else
+#endif
+        locked_ = false;
+    }
+}
+#ifdef HAVE_CLOCK_GETTIME
+inline int my_gettime(struct timespec* tp)
+{
+    return clock_gettime(CLOCK_REALTIME, tp);
+}
+#else
+#ifndef _MSC_VER
+inline int my_gettime(struct timespec* tp)
+{
+    struct timeval tv;
+    int ret = gettimeofday(&tv, NULL);
+    tp->tv_sec = tv.tv_sec;
+    tp->tv_nsec = tv.tv_usec * 1000;
+    return ret;
+}
+#else
+inline int my_gettime(struct timespec* tp)
+{
+    double t = CoinGetTimeOfDay();
+    tp->tv_sec = (int)floor(t);
+    tp->tv_nsec = (int)((tp->tv_sec - floor(t)) / 1000000.0);
+    return 0;
+}
+#endif
+#endif
+// Get time
+static double getTime()
+{
+    struct timespec absTime2;
+    my_gettime(&absTime2);
+    double time2 = (double)absTime2.tv_sec + 1.0e-9 * (double)absTime2.tv_nsec;
+    return time2;
+}
+// Timed wait in nanoseconds - if negative then seconds
+void
+CbcSpecificThread::timedWait(int time)
+{
+
+#ifdef CBC_PTHREAD
+    struct timespec absTime;
+    my_gettime(&absTime);
+    if (time > 0) {
+        absTime.tv_nsec += time;
+        if (absTime.tv_nsec >= 1000000000) {
+            absTime.tv_nsec -= 1000000000;
+            absTime.tv_sec++;
+        }
+    } else {
+        absTime.tv_sec -= time;
+    }
+    pthread_cond_timedwait(&condition2_, &mutex2_, &absTime);
+#else
+#endif
+}
+// Signal
+void
+CbcSpecificThread::signal()
+{
+#ifdef CBC_PTHREAD
+    pthread_cond_signal(&condition2_);
+#else
+#endif
+}
+// Actually starts a thread
+void
+CbcSpecificThread::startThread(void * (*routine ) (void *), CbcThread * thread)
+{
+#ifdef CBC_PTHREAD
+    pthread_create(&(threadId_.thr), NULL, routine, thread);
+    threadId_.status = 1;
+#else
+#endif
+}
+// Exits thread (from master)
+int
+CbcSpecificThread::exit()
+{
+#ifdef CBC_PTHREAD
+    pthread_cond_signal(&condition2_); // unlock
+    return pthread_join(threadId_.thr, NULL);
+#else
+#endif
+}
+// Exits thread
+void
+CbcSpecificThread::exitThread()
+{
+#ifdef CBC_PTHREAD
+    pthread_mutex_unlock(&mutex2_);
+    pthread_exit(NULL);
+#else
+#endif
+
+}
+// Get status
+int
+CbcSpecificThread::status() const
+{
+#ifdef CBC_PTHREAD
+    return static_cast<int>(threadId_.status);
+#else
+#endif
+}
+// Set status
+void
+CbcSpecificThread::setStatus(int value)
+{
+#ifdef CBC_PTHREAD
+    threadId_.status = value;
+#else
+#endif
+}
+// Parallel heuristics
+void
+parallelHeuristics (int numberThreads,
+                    int sizeOfData,
+                    void * argBundle)
+{
+    Coin_pthread_t * threadId = new Coin_pthread_t [numberThreads];
+    char * args = reinterpret_cast<char *>(argBundle);
+    for (int i = 0; i < numberThreads; i++) {
+        pthread_create(&(threadId[i].thr), NULL, doHeurThread,
+                       args + i*sizeOfData);
+    }
+    // now wait
+    for (int i = 0; i < numberThreads; i++) {
+        pthread_join(threadId[i].thr, NULL);
+    }
+    delete [] threadId;
+}
+// End of specific thread stuff
+
+/// Default constructor
+CbcThread::CbcThread()
+        :
+        baseModel_(NULL),
+        thisModel_(NULL),
+        node_(NULL), // filled in every time
+        createdNode_(NULL), // filled in every time on return
+        returnCode_(-1), // -1 available, 0 busy, 1 finished , 2??
+        timeLocked_(0.0),
+        timeWaitingToLock_(0.0),
+        timeWaitingToStart_(0.0),
+        timeInThread_(0.0),
+        numberTimesLocked_(0),
+        numberTimesUnlocked_(0),
+        numberTimesWaitingToStart_(0),
+        dantzigState_(0), // 0 unset, -1 waiting to be set, 1 set
+        locked_(false),
+        nDeleteNode_(0),
+        delNode_(NULL),
+        maxDeleteNode_(0),
+        nodesThisTime_(0),
+        iterationsThisTime_(0),
+        deterministic_(0)
+{
+}
+void
+CbcThread::gutsOfDelete()
+{
+    baseModel_ = NULL;
+    thisModel_ = NULL;
+    node_ = NULL;
+    createdNode_ = NULL;
+    delNode_ = NULL;
+}
+// Destructor
+CbcThread::~CbcThread()
+{
+}
+// Fills in useful stuff
+void
+CbcThread::setUsefulStuff (CbcModel * model, int deterministic, CbcModel * baseModel,
+                           CbcThread * master,
+                           void *& masterMutex)
+{
+    baseModel_ = baseModel;
+    thisModel_ = model;
+    deterministic_ = deterministic;
+    threadStuff_.setUsefulStuff(&master->threadStuff_, masterMutex);
+    node_ = NULL;
+    createdNode_ = NULL;
+    master_ = master;
+    returnCode_ = -1;
+    timeLocked_ = 0.0;
+    timeWaitingToLock_ = 0.0;
+    timeWaitingToStart_ = 0.0;
+    timeInThread_ = 0.0;
+    numberTimesLocked_ = 0;
+    numberTimesUnlocked_ = 0;
+    numberTimesWaitingToStart_ = 0;
+    dantzigState_ = 0; // 0 unset, -1 waiting to be set, 1 set
+    locked_ = false;
+    delNode_ = NULL;
+    maxDeleteNode_ = 0;
+    nDeleteNode_ = 0;
+    nodesThisTime_ = 0;
+    iterationsThisTime_ = 0;
+    if (model != baseModel) {
+        // thread
+        thisModel_->setInfoInChild(-3, this);
+        if (deterministic_ >= 0)
+            thisModel_->moveToModel(baseModel, -1);
+        if (deterministic == -1)
+            threadStuff_.startThread( doCutsThread, this);
+        else
+            threadStuff_.startThread( doNodesThread, this);
+    }
+}
+/*
+  Locks a thread if parallel so that stuff like cut pool
+  can be updated and/or used.
+*/
+void
+CbcThread::lockThread()
+{
+    if (!locked_) {
+        double time2 = getTime();
+        threadStuff_.lockThread();
+        locked_ = true;
+        timeWhenLocked_ = getTime();
+        timeWaitingToLock_ += timeWhenLocked_ - time2;;
+        numberTimesLocked_++;
+#ifdef THREAD_DEBUG
+        lockCount_ ++;
+#if THREAD_DEBUG>1
+        if (threadNumber_ == -1)
+            printf("locking master %d\n", lockCount_);
+        else
+            printf("locking thread %d %d\n", threadNumber_, lockCount_);
+#endif
+    } else {
+        if (threadNumber_ == -1)
+            printf("master already locked %d\n", lockCount_);
+        else
+            printf("thread already locked %d %d\n", threadNumber_, lockCount_);
+#endif
+    }
+}
+/*
+  Unlocks a thread if parallel
+*/
+void
+CbcThread::unlockThread()
+{
+    if (locked_) {
+        locked_ = false;
+        threadStuff_.unlockThread();
+        double time2 = getTime();
+        timeLocked_ += time2 - timeWhenLocked_;
+        numberTimesUnlocked_++;
+#ifdef THREAD_DEBUG
+#if THREAD_DEBUG>1
+        if (threadNumber_ == -1)
+            printf("unlocking master %d\n", lockCount_);
+        else
+            printf("unlocking thread %d %d\n", threadNumber_, lockCount_);
+#endif
+    } else {
+        if (threadNumber_ == -1)
+            printf("master already unlocked %d\n", lockCount_);
+        else
+            printf("thread already unlocked %d %d\n", threadNumber_, lockCount_);
+#endif
+    }
+}
+/* Wait for child to have return code NOT == to currentCode
+   type - 0 timed wait
+   1 wait
+   returns true if return code changed */
+bool
+CbcThread::wait(int type, int currentCode)
+{
+    if (!type) {
+        // just timed wait
+        master_->threadStuff_.lockThread2();
+        master_->threadStuff_.timedWait(1000000);
+        master_->threadStuff_.unlockThread2();
+    } else {
+        // wait until return code changes
+        while (returnCode_ == currentCode) {
+            threadStuff_.signal();
+            master_->threadStuff_.lockThread2();
+            master_->threadStuff_.timedWait(1000000);
+            master_->threadStuff_.unlockThread2();
+        }
+    }
+    return (returnCode_ != currentCode);
+}
+#if 0
+pthread_cond_signal(&condition2_);
+-
+if (!locked_)
+{
+    pthread_mutex_lock (&mutex2_);
+    locked_ = true;
+}
+-
+pthread_cond_timedwait(&condition2_, &mutex2_, &absTime);
+-
+if (locked_)
+{
+    pthread_mutex_unlock (&mutex2_);
+    locked_ = false;
+}
+#endif
+// Waits until returnCode_ goes to zero
+void
+CbcThread::waitThread()
+{
+    double time = getTime();
+    threadStuff_.lockThread2();
+    while (returnCode_) {
+        threadStuff_.timedWait(-10); // 10 seconds
+    }
+    timeWaitingToStart_ += getTime() - time;
+    numberTimesWaitingToStart_++;
+}
+// Just wait for so many nanoseconds
+void
+CbcThread::waitNano(int time)
+{
+    threadStuff_.lockThread2();
+    threadStuff_.timedWait(time);
+    threadStuff_.unlockThread2();
+}
+// Signal child to carry on
+void
+CbcThread::signal()
+{
+    threadStuff_.signal();
+}
+// Lock from master with mutex2 and signal before lock
+void
+CbcThread::lockFromMaster()
+{
+    threadStuff_.signal();
+    master_->threadStuff_.lockThread2(true);
+}
+// Unlock from master with mutex2 and signal after unlock
+void
+CbcThread::unlockFromMaster()
+{
+    master_->threadStuff_.unlockThread2(true); // unlock anyway
+    threadStuff_.signal();
+}
+// Lock from thread with mutex2 and signal before lock
+void
+CbcThread::lockFromThread()
+{
+    master_->threadStuff_.signal();
+    threadStuff_.lockThread2();
+}
+// Unlock from thread with mutex2 and signal after unlock
+void
+CbcThread::unlockFromThread()
+{
+    master_->threadStuff_.signal();
+    threadStuff_.unlockThread2();
+}
+// Exits thread (from master)
+int
+CbcThread::exit()
+{
+    return threadStuff_.exit();
+}
+// Exits thread
+void
+CbcThread::exitThread()
+{
+    threadStuff_.exitThread();
+}
+// Default constructor
+CbcBaseModel::CbcBaseModel()
+        :
+        numberThreads_(0),
+        children_(NULL),
+        type_(0),
+        threadCount_(NULL),
+        threadModel_(NULL),
+        numberObjects_(0),
+        saveObjects_(NULL),
+        defaultParallelIterations_(400),
+        defaultParallelNodes_(2)
+{
+}
+// Constructor with model
+CbcBaseModel::CbcBaseModel (CbcModel & model,  int type)
+        :
+        children_(NULL),
+        type_(type),
+        threadCount_(NULL),
+        threadModel_(NULL),
+        numberObjects_(0),
+        saveObjects_(NULL),
+        defaultParallelIterations_(400),
+        defaultParallelNodes_(2)
+{
+    numberThreads_ = model.getNumberThreads();
+    if (numberThreads_) {
+        children_ = new CbcThread [numberThreads_+1];
+        // Do a partial one for base model
+        void * mutex_main = NULL;
+        children_[numberThreads_].setUsefulStuff(&model, type_, &model,
+                children_ + numberThreads_, mutex_main);
+#ifdef THREAD_DEBUG
+        children_[numberThreads_].threadNumber_ = -1;
+        children_[numberThreads_].lockCount_ = 0;
+#endif
+        threadCount_ = new int [numberThreads_];
+        CoinZeroN(threadCount_, numberThreads_);
+        threadModel_ = new CbcModel * [numberThreads_+1];
+        memset(threadStats_, 0, sizeof(threadStats_));
+        if (type_ > 0) {
+            // May need for deterministic
+            numberObjects_ = model.numberObjects();
+            saveObjects_ = new OsiObject * [numberObjects_];
+            for (int i = 0; i < numberObjects_; i++) {
+                saveObjects_[i] = model.object(i)->clone();
+            }
+        }
+        // we don't want a strategy object
+        CbcStrategy * saveStrategy = model.strategy();
+        model.setStrategy(NULL);
+        for (int i = 0; i < numberThreads_; i++) {
+            //threadModel_[i] = new CbcModel(model, true);
+            threadModel_[i] = model. clone (true);
+            threadModel_[i]->synchronizeHandlers(1);
+#ifdef COIN_HAS_CLP
+            // Solver may need to know about model
+            CbcModel * thisModel = threadModel_[i];
+            CbcOsiSolver * solver =
+                dynamic_cast<CbcOsiSolver *>(thisModel->solver()) ;
+            if (solver)
+                solver->setCbcModel(thisModel);
+#endif
+            children_[i].setUsefulStuff(threadModel_[i], type_, &model,
+                                        children_ + numberThreads_, mutex_main);
+#ifdef THREAD_DEBUG
+            children_[i].threadNumber_ = i;
+            children_[i].lockCount_ = 0;
+#endif
+        }
+        model.setStrategy(saveStrategy);
+    }
+}
+// Stop threads
+void
+CbcBaseModel::stopThreads(int type)
+{
+    if (type < 0) {
+	// max nodes ?
+	bool finished = false;
+	while (!finished) {
+	  finished = true;
+	  for (int i = 0; i < numberThreads_; i++) {
+            if (abs(children_[i].returnCode()) != 1) {
+	      children_[i].wait(1, 0); 
+	      finished=false;
+	    }
+	  }
+        }
+        return;
+    }
+    for (int i = 0; i < numberThreads_; i++) {
+        children_[i].wait(1, 0);
+        assert (children_[i].returnCode() == -1);
+        threadModel_[i]->setInfoInChild(-2, NULL);
+        children_[i].setReturnCode( 0);
+        children_[i].exit();
+        children_[i].setStatus( 0);
+    }
+    // delete models and solvers
+    for (int i = 0; i < numberThreads_; i++) {
+        threadModel_[i]->setInfoInChild(type_, NULL);
+        delete threadModel_[i];
+    }
+    delete [] children_;
+    delete [] threadModel_;
+    for (int i = 0; i < numberObjects_; i++)
+        delete saveObjects_[i];
+    delete [] saveObjects_;
+    children_ = NULL;
+    threadModel_ = NULL;
+    saveObjects_ = NULL;
+    numberObjects_ = 0;
+    numberThreads_ = 0;
+}
+// Wait for threads in tree
+int
+CbcBaseModel::waitForThreadsInTree(int type)
+{
+    CbcModel * baseModel = children_[0].baseModel();
+    int anyLeft = 0;
+    // May be able to combine parts later
+
+    if (type == 0) {
+        bool locked = true;
+#ifdef COIN_DEVELOP
+        printf("empty\n");
+#endif
+        // may still be outstanding nodes
+        while (true) {
+            int iThread;
+            for (iThread = 0; iThread < numberThreads_; iThread++) {
+                if (children_[iThread].status()) {
+                    if (children_[iThread].returnCode() == 0)
+                        break;
+                }
+            }
+            if (iThread < numberThreads_) {
+#ifdef COIN_DEVELOP
+                printf("waiting for thread %d code 0\n", iThread);
+#endif
+                unlockThread();
+                locked = false;
+                children_[iThread].wait(1, 0);
+                assert(children_[iThread].returnCode() == 1);
+                threadModel_[iThread]->moveToModel(baseModel, 1);
+#ifdef THREAD_PRINT
+                printf("off thread2 %d node %x\n", iThread, children_[iThread].node());
+#endif
+                children_[iThread].setNode(NULL);
+                anyLeft = 1;
+                assert (children_[iThread].returnCode() == 1);
+                if (children_[iThread].dantzigState() == -1) {
+                    // 0 unset, -1 waiting to be set, 1 set
+                    children_[iThread].setDantzigState(1);
+                    CbcModel * model = children_[iThread].thisModel();
+                    OsiClpSolverInterface * clpSolver2
+                    = dynamic_cast<OsiClpSolverInterface *> (model->solver());
+                    assert (clpSolver2);
+                    ClpSimplex * simplex2 = clpSolver2->getModelPtr();
+                    ClpDualRowDantzig dantzig;
+                    simplex2->setDualRowPivotAlgorithm(dantzig);
+                }
+                // say available
+                children_[iThread].setReturnCode( -1);
+                threadStats_[4]++;
+#ifdef COIN_DEVELOP
+                printf("thread %d code now -1\n", iThread);
+#endif
+                break;
+            } else {
+#ifdef COIN_DEVELOP
+                printf("no threads at code 0 \n");
+#endif
+                // now check if any have just finished
+                for (iThread = 0; iThread < numberThreads_; iThread++) {
+                    if (children_[iThread].status()) {
+                        if (children_[iThread].returnCode() == 1)
+                            break;
+                    }
+                }
+                if (iThread < numberThreads_) {
+                    unlockThread();
+                    locked = false;
+                    threadModel_[iThread]->moveToModel(baseModel, 1);
+#ifdef THREAD_PRINT
+                    printf("off thread3 %d node %x\n", iThread, children_[iThread].node());
+#endif
+                    children_[iThread].setNode(NULL);
+                    anyLeft = 1;
+                    assert (children_[iThread].returnCode() == 1);
+                    // say available
+                    children_[iThread].setReturnCode( -1);
+                    threadStats_[4]++;
+#ifdef COIN_DEVELOP
+                    printf("thread %d code now -1\n", iThread);
+#endif
+                    break;
+                }
+            }
+            if (!baseModel->tree()->empty()) {
+#ifdef COIN_DEVELOP
+                printf("tree not empty!!!!!!\n");
+#endif
+                if (locked)
+                    unlockThread();
+                return 1;
+                break;
+            }
+            for (iThread = 0; iThread < numberThreads_; iThread++) {
+                if (children_[iThread].status()) {
+                    if (children_[iThread].returnCode() != -1) {
+                        printf("bad end of tree\n");
+                        abort();
+                    }
+                }
+            }
+            break;
+        }
+#ifdef COIN_DEVELOP
+        printf("finished ************\n");
+#endif
+        if (locked)
+            unlockThread();
+        return anyLeft;
+    } else if (type == 1) {
+        // normal
+        double cutoff = baseModel->getCutoff();
+        CbcNode * node = baseModel->tree()->bestNode(cutoff) ;
+        // Possible one on tree worse than cutoff
+        if (!node || node->objectiveValue() > cutoff)
+            return 1;
+        threadStats_[0]++;
+        //need to think
+        int iThread;
+        // Start one off if any available
+        for (iThread = 0; iThread < numberThreads_; iThread++) {
+            if (children_[iThread].returnCode() == -1)
+                break;
+        }
+        if (iThread < numberThreads_) {
+            children_[iThread].setNode(node);
+#ifdef THREAD_PRINT
+            printf("empty thread %d node %x\n", iThread, children_[iThread].node());
+#endif
+            assert (children_[iThread].returnCode() == -1);
+            // say in use
+            threadModel_[iThread]->moveToModel(baseModel, 0);
+            // This has to be AFTER moveToModel
+            children_[iThread].setReturnCode( 0);
+            children_[iThread].signal();
+            threadCount_[iThread]++;
+        }
+        lockThread();
+        // see if any finished
+        for (iThread = 0; iThread < numberThreads_; iThread++) {
+            if (children_[iThread].returnCode() > 0)
+                break;
+        }
+        unlockThread();
+        if (iThread < numberThreads_) {
+            threadModel_[iThread]->moveToModel(baseModel, 1);
+#ifdef THREAD_PRINT
+            printf("off thread4 %d node %x\n", iThread, children_[iThread].node());
+#endif
+            children_[iThread].setNode(NULL);
+            anyLeft = 1;
+            assert (children_[iThread].returnCode() == 1);
+            // say available
+            children_[iThread].setReturnCode( -1);
+            // carry on
+            threadStats_[3]++;
+        } else {
+            // Start one off if any available
+            for (iThread = 0; iThread < numberThreads_; iThread++) {
+                if (children_[iThread].returnCode() == -1)
+                    break;
+            }
+            if (iThread < numberThreads_) {
+                // If any on tree get
+                if (!baseModel->tree()->empty()) {
+                    //node = baseModel->tree()->bestNode(cutoff) ;
+                    //assert (node);
+                    threadStats_[1]++;
+                    return 1; // ** get another node
+                }
+            }
+            // wait (for debug could sleep and use test)
+            bool finished = false;
+            while (!finished) {
+                double time = getTime();
+                children_[numberThreads_].wait(0, 0);
+                children_[numberThreads_].incrementTimeInThread(getTime() - time);
+                for (iThread = 0; iThread < numberThreads_; iThread++) {
+                    if (children_[iThread].returnCode() > 0) {
+                        finished = true;
+                        break;
+                    } else if (children_[iThread].returnCode() == 0) {
+                        children_[iThread].signal(); // unlock
+                    }
+                }
+            }
+            assert (iThread < numberThreads_);
+            // move information to model
+            threadModel_[iThread]->moveToModel(baseModel, 1);
+            anyLeft = 1;
+#ifdef THREAD_PRINT
+            printf("off thread %d node %x\n", iThread, children_[iThread].node());
+#endif
+            children_[iThread].setNode(NULL);
+            assert (children_[iThread].returnCode() == 1);
+            // say available
+            children_[iThread].setReturnCode( -1);
+        }
+        // carry on
+        threadStats_[2]++;
+        for (int iThread = 0; iThread < numberThreads_; iThread++) {
+            if (children_[iThread].status()) {
+                if (children_[iThread].returnCode() != -1) {
+                    anyLeft = 1;
+                    break;
+                }
+            }
+        }
+        return anyLeft;
+    } else if (type == 2) {
+        if (!baseModel->tree()->empty()) {
+  	  // max nodes ?
+	  bool finished = false;
+	  while (!finished) {
+	    finished = true;
+	    for (int iThread = 0; iThread < numberThreads_; iThread++) {
+	      if (children_[iThread].returnCode() == 0) { 
+		double time = getTime();
+		children_[numberThreads_].wait(0, 0);
+		children_[numberThreads_].incrementTimeInThread(getTime() - time);
+		finished = false;
+		children_[iThread].signal(); // unlock
+	      }
+	    }
+	  }
+        }
+        int i;
+        // do statistics
+        // Seems to be bug in CoinCpu on Linux - does threads as well despite documentation
+        double time = 0.0;
+        for (i = 0; i < numberThreads_; i++)
+            time += children_[i].timeInThread();
+        bool goodTimer = time < (baseModel->getCurrentSeconds());
+        for (i = 0; i < numberThreads_; i++) {
+            while (children_[i].returnCode() == 0) {
+                children_[i].signal();
+                double time = getTime();
+                children_[numberThreads_].wait(0, 0);
+                children_[numberThreads_].incrementTimeInThread(getTime() - time);
+            }
+            children_[i].lockFromMaster();
+            threadModel_[i]->setNumberThreads(0); // say exit
+            if (children_[i].deterministic() > 0)
+                delete [] children_[i].delNode();
+            children_[i].setReturnCode( 0);
+            children_[i].unlockFromMaster();
+#ifndef NDEBUG
+            int returnCode = children_[i].exit();
+            assert (!returnCode);
+#else
+            children_[i].exit();
+#endif
+            children_[i].setStatus( 0);
+            //else
+            threadModel_[i]->moveToModel(baseModel, 2);
+            assert (children_[i].numberTimesLocked() == children_[i].numberTimesUnlocked());
+            baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
+            << "Thread";
+            baseModel->messageHandler()->printing(true)
+            << i << threadCount_[i] << children_[i].timeWaitingToStart();
+            baseModel->messageHandler()->printing(goodTimer) << children_[i].timeInThread();
+            baseModel->messageHandler()->printing(false) << 0.0;
+            baseModel->messageHandler()->printing(true) << children_[i].numberTimesLocked()
+            << children_[i].timeLocked() << children_[i].timeWaitingToLock()
+            << CoinMessageEol;
+        }
+        assert (children_[numberThreads_].numberTimesLocked() == children_[numberThreads_].numberTimesUnlocked());
+        baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
+        << "Main thread";
+        baseModel->messageHandler()->printing(false) << 0 << 0 << 0.0;
+        baseModel->messageHandler()->printing(false) << 0.0;
+        baseModel->messageHandler()->printing(true) << children_[numberThreads_].timeInThread();
+        baseModel->messageHandler()->printing(true) << children_[numberThreads_].numberTimesLocked()
+        << children_[numberThreads_].timeLocked() << children_[numberThreads_].timeWaitingToLock()
+        << CoinMessageEol;
+        // delete models (here in case some point to others)
+        for (i = 0; i < numberThreads_; i++) {
+            // make sure handler will be deleted
+            threadModel_[i]->setDefaultHandler(true);
+            //delete threadModel_[i];
+        }
+    } else {
+        abort();
+    }
+    return 0;
+}
+void
+CbcBaseModel::waitForThreadsInCuts(int type, OsiCuts * eachCuts,
+                                   int whichGenerator)
+{
+    if (type == 0) {
+        // cuts while doing
+        bool finished = false;
+        int iThread = -1;
+        // see if any available
+        for (iThread = 0; iThread < numberThreads_; iThread++) {
+            if (children_[iThread].returnCode()) {
+                finished = true;
+                break;
+            } else if (children_[iThread].returnCode() == 0) {
+                children_[iThread].signal();
+            }
+        }
+        while (!finished) {
+            children_[numberThreads_].waitNano(1000000);
+            for (iThread = 0; iThread < numberThreads_; iThread++) {
+                if (children_[iThread].returnCode() > 0) {
+                    finished = true;
+                    break;
+                } else if (children_[iThread].returnCode() == 0) {
+                    children_[iThread].signal();
+                }
+            }
+        }
+        assert (iThread < numberThreads_);
+        assert (children_[iThread].returnCode());
+        // Use dantzigState to signal which generator
+        children_[iThread].setDantzigState(whichGenerator);
+        // and delNode for eachCuts
+        children_[iThread].fakeDelNode(reinterpret_cast<CbcNode **> (eachCuts));
+        // allow to start
+        children_[iThread].setReturnCode( 0);
+        children_[iThread].signal();
+    } else if (type == 1) {
+        // cuts - finish up
+        for (int iThread = 0; iThread < numberThreads_; iThread++) {
+            if (children_[iThread].returnCode() == 0) {
+                bool finished = false;
+                while (!finished) {
+                    children_[numberThreads_].wait(0, 0);
+                    if (children_[iThread].returnCode() > 0) {
+                        finished = true;
+                        break;
+                        //#ifndef NEW_STYLE_PTHREAD
+                        //} else if (children_[iThread].returnCode_ == 0) {
+                        //pthread_cond_signal(&children_[iThread].threadStuff_.condition2_); // unlock
+                        //#endif
+                    }
+                }
+            }
+            assert (children_[iThread].returnCode());
+            // say available
+            children_[iThread].setReturnCode( -1);
+            //delete threadModel_[iThread]->solver();
+            //threadModel_[iThread]->setSolver(NULL);
+        }
+    } else {
+        abort();
+    }
+}
+// Returns pointer to master thread
+CbcThread *
+CbcBaseModel::masterThread() const
+{
+    return children_ + numberThreads_;
+}
+
+// Split model and do work in deterministic parallel
+void
+CbcBaseModel::deterministicParallel()
+{
+    CbcModel * baseModel = children_[0].baseModel();
+    for (int i = 0; i < numberThreads_; i++)
+        threadCount_[i]++;
+    int saveTreeSize = baseModel->tree()->size();
+    // For now create threadModel - later modify splitModel
+    CbcModel ** threadModel = new CbcModel * [numberThreads_];
+    int iThread;
+    for (iThread = 0; iThread < numberThreads_; iThread++)
+        threadModel[iThread] = children_[iThread].thisModel();
+
+    int nAffected = baseModel->splitModel(numberThreads_, threadModel, defaultParallelNodes_);
+    // do all until finished
+    for (iThread = 0; iThread < numberThreads_; iThread++) {
+        // obviously tune
+        children_[iThread].setNDeleteNode(defaultParallelIterations_);
+    }
+    // Save current state
+    int iObject;
+    OsiObject ** object = baseModel->objects();
+    for (iObject = 0; iObject < numberObjects_; iObject++) {
+        saveObjects_[iObject]->updateBefore(object[iObject]);
+    }
+    //#define FAKE_PARALLEL
+#ifndef FAKE_PARALLEL
+    for (iThread = 0; iThread < numberThreads_; iThread++) {
+        children_[iThread].setReturnCode( 0);
+        children_[iThread].signal();
+    }
+    // wait
+    bool finished = false;
+    double time = getTime();
+    while (!finished) {
+        children_[numberThreads_].waitNano( 1000000); // millisecond
+        finished = true;
+        for (iThread = 0; iThread < numberThreads_; iThread++) {
+            if (children_[iThread].returnCode() <= 0) {
+                finished = false;
+            }
+        }
+    }
+    for (iThread = 0; iThread < numberThreads_; iThread++)
+        children_[iThread].setReturnCode(-1);
+#else
+    // wait
+    bool finished = false;
+    double time = getTime();
+    for (iThread = 0; iThread < numberThreads_; iThread++) {
+        children_[iThread].setReturnCode( 0);
+        children_[iThread].signal();
+	while (!finished) {
+	  children_[numberThreads_].waitNano( 1000000); // millisecond
+	  finished = (children_[iThread].returnCode() >0);
+	}
+        children_[iThread].setReturnCode(-1);
+	finished=false;
+    }
+#endif
+    children_[numberThreads_].incrementTimeInThread(getTime() - time);
+    // Unmark marked
+    for (int i = 0; i < nAffected; i++) {
+        baseModel->walkback()[i]->unmark();
+    }
+    int iModel;
+    double scaleFactor = 1.0;
+    for (iModel = 0; iModel < numberThreads_; iModel++) {
+        //printf("model %d tree size %d\n",iModel,threadModel[iModel]->baseModel->tree()->size());
+        if (saveTreeSize > 4*numberThreads_*defaultParallelNodes_) {
+            if (!threadModel[iModel]->tree()->size()) {
+                scaleFactor *= 1.05;
+            }
+        }
+        threadModel[iModel]->moveToModel(baseModel, 11);
+        // Update base model
+        OsiObject ** threadObject = threadModel[iModel]->objects();
+        for (iObject = 0; iObject < numberObjects_; iObject++) {
+            object[iObject]->updateAfter(threadObject[iObject], saveObjects_[iObject]);
+        }
+    }
+    if (scaleFactor != 1.0) {
+        int newNumber = static_cast<int> (defaultParallelNodes_ * scaleFactor + 0.5001);
+        if (newNumber*2 < defaultParallelIterations_) {
+            if (defaultParallelNodes_ == 1)
+                newNumber = 2;
+            if (newNumber != defaultParallelNodes_) {
+                char general[200];
+                sprintf(general, "Changing tree size from %d to %d",
+                        defaultParallelNodes_, newNumber);
+                baseModel->messageHandler()->message(CBC_GENERAL,
+                                                     baseModel->messages())
+                << general << CoinMessageEol ;
+                defaultParallelNodes_ = newNumber;
+            }
+        }
+    }
+    delete [] threadModel;
+}
+// Destructor
+CbcBaseModel::~CbcBaseModel()
+{
+    delete [] threadCount_;
+#if 1
+    for (int i = 0; i < numberThreads_; i++)
+        delete threadModel_[i];
+    delete [] threadModel_;
+    delete [] children_;
+#endif
+    for (int i = 0; i < numberObjects_; i++)
+        delete saveObjects_[i];
+    delete [] saveObjects_;
+}
+// Sets Dantzig state in children
+void
+CbcBaseModel::setDantzigState()
+{
+    for (int i = 0; i < numberThreads_; i++) {
+        children_[i].setDantzigState(-1);
+    }
+}
+static void * doNodesThread(void * voidInfo)
+{
+    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
+    CbcModel * thisModel = stuff->thisModel();
+    CbcModel * baseModel = stuff->baseModel();
+    while (true) {
+        stuff->waitThread();
+        //printf("start node %x\n",stuff->node);
+        int mode = thisModel->getNumberThreads();
+        if (mode) {
+            // normal
+            double time2 = CoinCpuTime();
+            assert (stuff->returnCode() == 0);
+            if (thisModel->parallelMode() >= 0) {
+                CbcNode * node = stuff->node();
+                //assert (node->nodeInfo());
+                CbcNode * createdNode = stuff->createdNode();
+		// try and see if this has slipped through
+		if (node) {
+		  thisModel->doOneNode(baseModel, node, createdNode);
+		} else {
+		  //printf("null node\n");
+		  createdNode=NULL;
+		}
+                stuff->setNode(node);
+                stuff->setCreatedNode(createdNode);
+                stuff->setReturnCode( 1);
+            } else {
+                assert (!stuff->node());
+                assert (!stuff->createdNode());
+                int numberIterations = stuff->nDeleteNode();
+                int nDeleteNode = 0;
+                int maxDeleteNode = stuff->maxDeleteNode();
+                CbcNode ** delNode = stuff->delNode();
+                int returnCode = 1;
+                // this should be updated by heuristics strong branching etc etc
+                assert (numberIterations > 0);
+                thisModel->setNumberThreads(0);
+                int nodesThisTime = thisModel->getNodeCount();
+                int iterationsThisTime = thisModel->getIterationCount();
+                int strongThisTime = thisModel->numberStrongIterations();
+                thisModel->setStopNumberIterations(thisModel->getIterationCount() + numberIterations);
+                int numberColumns = thisModel->getNumCols();
+                int * used = CoinCopyOfArray(thisModel->usedInSolution(), numberColumns);
+                int numberSolutions = thisModel->getSolutionCount();
+                while (true) {
+                    if (thisModel->tree()->empty()) {
+                        returnCode = 1 + 1;
+#ifdef CLP_INVESTIGATE_2
+                        printf("%x tree empty - time %18.6f\n", thisModel, CoinGetTimeOfDay() - 1.2348e9);
+#endif
+                        break;
+                    }
+#define NODE_ITERATIONS 2
+                    int nodesNow = thisModel->getNodeCount();
+                    int iterationsNow = thisModel->getIterationCount();
+                    int strongNow = thisModel->numberStrongIterations();
+                    bool exit1 = (NODE_ITERATIONS * ((nodesNow - nodesThisTime) +
+                                                     ((strongNow - strongThisTime) >> 1)) +
+                                  (iterationsNow - iterationsThisTime) > numberIterations);
+                    //bool exit2 =(thisModel->getIterationCount()>thisModel->getStopNumberIterations()) ;
+                    //assert (exit1==exit2);
+                    if (exit1 && nodesNow - nodesThisTime >= 10) {
+                        // out of loop
+                        //printf("out of loop\n");
+#ifdef CLP_INVESTIGATE3
+                        printf("%x tree %d nodes left, done %d and %d its - time %18.6f\n", thisModel,
+                               thisModel->tree()->size(), nodesNow - nodesThisTime,
+                               iterationsNow - iterationsThisTime, CoinGetTimeOfDay() - 1.2348e9);
+#endif
+                        break;
+                    }
+                    double cutoff = thisModel->getCutoff() ;
+                    CbcNode *node = thisModel->tree()->bestNode(cutoff) ;
+                    // Possible one on tree worse than cutoff
+                    if (!node)
+                        continue;
+                    CbcNode * createdNode = NULL;
+                    // Do real work of node
+                    thisModel->doOneNode(NULL, node, createdNode);
+                    assert (createdNode);
+                    if (!createdNode->active()) {
+                        delete createdNode;
+                    } else {
+                        // Say one more pointing to this **** postpone if marked
+                        node->nodeInfo()->increment() ;
+                        thisModel->tree()->push(createdNode) ;
+                    }
+                    if (node->active()) {
+                        assert (node->nodeInfo());
+                        if (node->nodeInfo()->numberBranchesLeft()) {
+                            thisModel->tree()->push(node) ;
+                        } else {
+                            node->setActive(false);
+                        }
+                    } else {
+                        if (node->nodeInfo()) {
+                            if (!node->nodeInfo()->numberBranchesLeft())
+                                node->nodeInfo()->allBranchesGone(); // can clean up
+                            // So will delete underlying stuff
+                            node->setActive(true);
+                        }
+                        if (nDeleteNode == maxDeleteNode) {
+                            maxDeleteNode = (3 * maxDeleteNode) / 2 + 10;
+                            stuff->setMaxDeleteNode(maxDeleteNode);
+                            stuff->setDelNode(new CbcNode * [maxDeleteNode]);
+                            for (int i = 0; i < nDeleteNode; i++)
+                                stuff->delNode()[i] = delNode[i];
+                            delete [] delNode;
+                            delNode = stuff->delNode();
+                        }
+                        delNode[nDeleteNode++] = node;
+                    }
+                }
+                // end of this sub-tree
+                int * usedA = thisModel->usedInSolution();
+                for (int i = 0; i < numberColumns; i++) {
+                    usedA[i] -= used[i];
+                }
+                delete [] used;
+                thisModel->setSolutionCount(thisModel->getSolutionCount() - numberSolutions);
+                stuff->setNodesThisTime(thisModel->getNodeCount() - nodesThisTime);
+                stuff->setIterationsThisTime(thisModel->getIterationCount() - iterationsThisTime);
+                stuff->setNDeleteNode(nDeleteNode);
+                stuff->setReturnCode( returnCode);
+                thisModel->setNumberThreads(mode);
+            }
+            //printf("end node %x\n",stuff->node);
+            stuff->unlockFromThread();
+            stuff->incrementTimeInThread(CoinCpuTime() - time2);
+        } else {
+            // exit
+            break;
+        }
+    }
+    //printf("THREAD exiting\n");
+    stuff->exitThread();
+    return NULL;
+}
+static void * doHeurThread(void * voidInfo)
+{
+    typedef struct {
+        double solutionValue;
+        CbcModel * model;
+        double * solution;
+        int foundSol;
+    } argBundle;
+    argBundle * stuff = reinterpret_cast<argBundle *> (voidInfo);
+    stuff->foundSol =
+        stuff->model->heuristic(0)->solution(stuff->solutionValue,
+                                             stuff->solution);
+    return NULL;
+}
+static void * doCutsThread(void * voidInfo)
+{
+    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
+    CbcModel * thisModel =  stuff->thisModel();
+    while (true) {
+        stuff->waitThread();
+        //printf("start node %x\n",stuff->node);
+        int mode = thisModel->getNumberThreads();
+        if (mode) {
+            // normal
+            assert (stuff->returnCode() == 0);
+            int fullScan = thisModel->getNodeCount() == 0 ? 1 : 0; //? was >0
+            CbcCutGenerator * generator = thisModel->cutGenerator(stuff->dantzigState());
+            generator->refreshModel(thisModel);
+            OsiCuts * cuts = reinterpret_cast<OsiCuts *> (stuff->delNode());
+            OsiSolverInterface * thisSolver = thisModel->solver();
+            generator->generateCuts(*cuts, fullScan, thisSolver, NULL);
+            stuff->setReturnCode( 1);
+            stuff->unlockFromThread();
+        } else {
+            // exit
+            break;
+        }
+    }
+    stuff->exitThread();
+    return NULL;
+}
+// Split up nodes - returns number of CbcNodeInfo's affected
+int
+CbcModel::splitModel(int numberModels, CbcModel ** model,
+                     int numberNodes)
+{
+    int iModel;
+    int i;
+    for (iModel = 0; iModel < numberModels; iModel++) {
+        CbcModel * otherModel = model[iModel];
+        otherModel->moveToModel(this, 10);
+        assert (!otherModel->tree()->size());
+        otherModel->tree()->resetNodeNumbers();
+        otherModel->bestPossibleObjective_ = bestPossibleObjective_;
+        otherModel->sumChangeObjective1_ = sumChangeObjective1_;
+        otherModel->sumChangeObjective2_ = sumChangeObjective2_;
+        int numberColumns = solver_->getNumCols();
+        if (otherModel->bestSolution_) {
+            assert (bestSolution_);
+            memcpy(otherModel->bestSolution_, bestSolution_, numberColumns*sizeof(double));
+        } else if (bestSolution_) {
+            otherModel->bestSolution_ = CoinCopyOfArray(bestSolution_, numberColumns);
+        }
+        otherModel->globalCuts_ = globalCuts_;
+        otherModel->numberSolutions_ = numberSolutions_;
+        otherModel->numberHeuristicSolutions_ = numberHeuristicSolutions_;
+        otherModel->numberNodes_ = 1; //numberNodes_;
+        otherModel->numberIterations_ = numberIterations_;
+#ifdef JJF_ZERO
+        if (maximumNumberCuts_ > otherModel->maximumNumberCuts_) {
+            otherModel->maximumNumberCuts_ = maximumNumberCuts_;
+            delete [] otherModel->addedCuts_;
+            otherModel->addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
+        }
+        if (maximumDepth_ > otherModel->maximumDepth_) {
+            otherModel->maximumDepth_ = maximumDepth_;
+            delete [] otherModel->walkback_;
+            otherModel->walkback_ = new CbcNodeInfo * [maximumDepth_];
+        }
+#endif
+        otherModel->currentNumberCuts_ = currentNumberCuts_;
+        if (otherModel->usedInSolution_) {
+            assert (usedInSolution_);
+            memcpy(otherModel->usedInSolution_, usedInSolution_, numberColumns*sizeof(int));
+        } else if (usedInSolution_) {
+            otherModel->usedInSolution_ = CoinCopyOfArray(usedInSolution_, numberColumns);
+        }
+        /// ??? tree_;
+        // Need flag (stopNumberIterations_>0?) which says don't update cut etc counts
+        for (i = 0; i < numberObjects_; i++) {
+            otherModel->object_[i]->updateBefore(object_[i]);
+        }
+        otherModel->maximumDepthActual_ = maximumDepthActual_;
+        // Real cuts are in node info
+        otherModel->numberOldActiveCuts_ = numberOldActiveCuts_;
+        otherModel->numberNewCuts_ = numberNewCuts_;
+        otherModel->numberStrongIterations_ = numberStrongIterations_;
+    }
+    double cutoff = getCutoff();
+    int nAffected = 0;
+    while (!tree_->empty()) {
+        for (iModel = 0; iModel < numberModels; iModel++) {
+            if (tree_->empty())
+                break;
+            CbcModel * otherModel = model[iModel];
+            CbcNode * node = tree_->bestNode(cutoff) ;
+            CbcNodeInfo * nodeInfo = node->nodeInfo();
+            assert (nodeInfo);
+            if (!nodeInfo->marked()) {
+                //while (nodeInfo&&!nodeInfo->marked()) {
+                if (nAffected == maximumDepth_) {
+                    redoWalkBack();
+                }
+                nodeInfo->mark();
+                //nodeInfo->incrementCuts(1000000);
+                walkback_[nAffected++] = nodeInfo;
+                //nodeInfo = nodeInfo->parent() ;
+                //}
+            }
+            // Make node join otherModel
+            OsiBranchingObject * bobj = node->modifiableBranchingObject();
+            CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
+            //assert (cbcobj);
+            if (cbcobj) {
+                CbcObject * object = cbcobj->object();
+                assert (object);
+                int position = object->position();
+                assert (position >= 0);
+                assert (object_[position] == object);
+                CbcObject * objectNew =
+                    dynamic_cast<CbcObject *> (otherModel->object_[position]);
+                cbcobj->setOriginalObject(objectNew);
+            }
+            otherModel->tree_->push(node);
+        }
+        numberNodes--;
+        if (!numberNodes)
+            break;
+    }
+    return nAffected;
+}
+// Start threads
+void
+CbcModel::startSplitModel(int /*numberIterations*/)
+{
+    abort();
+}
+// Merge models
+void
+CbcModel::mergeModels(int /*numberModel*/, CbcModel ** /*model*/,
+                      int /*numberNodes*/)
+{
+    abort();
+}
+/* Move/copy information from one model to another
+   -1 - initial setup
+   0 - from base model
+   1 - to base model (and reset)
+   2 - add in final statistics etc (and reset so can do clean destruction)
+   10 - from base model (deterministic)
+   11 - to base model (deterministic)
+*/
+void
+CbcModel::moveToModel(CbcModel * baseModel, int mode)
+{
+    if (mode == 0) {
+        setCutoff(baseModel->getCutoff());
+        bestObjective_ = baseModel->bestObjective_;
+        //assert (!baseModel->globalCuts_.sizeRowCuts());
+        if (numberSolutions_ < baseModel->numberSolutions_) {
+	  assert (baseModel->bestSolution_);
+	  int numberColumns = solver_->getNumCols();
+	  if (!bestSolution_)
+	    bestSolution_ = new double [numberColumns];
+	  memcpy(bestSolution_,baseModel->bestSolution_,
+		 numberColumns*sizeof(double));
+	  numberSolutions_ = baseModel->numberSolutions_;
+	}
+        stateOfSearch_ = baseModel->stateOfSearch_;
+        numberNodes_ = baseModel->numberNodes_;
+        numberIterations_ = baseModel->numberIterations_;
+        numberFixedAtRoot_ = numberIterations_; // for statistics
+        numberSolves_ = 0;
+        phase_ = baseModel->phase_;
+        assert (!nextRowCut_);
+        nodeCompare_ = baseModel->nodeCompare_;
+        tree_ = baseModel->tree_;
+        assert (!subTreeModel_);
+        //branchingMethod_ = NULL; // need something but what
+        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
+        cutModifier_ = NULL;
+        assert (!analyzeResults_);
+        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
+        assert (stuff);
+        //if (stuff)
+        stuff->setCreatedNode(NULL);
+        // ?? searchStrategy_;
+        searchStrategy_ = baseModel->searchStrategy_;
+        stuff->saveStuff()[0] = searchStrategy_;
+        stateOfSearch_ = baseModel->stateOfSearch_;
+        stuff->saveStuff()[1] = stateOfSearch_;
+        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
+            CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
+                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[iObject]) ;
+            if (dynamicObject) {
+                CbcSimpleIntegerDynamicPseudoCost * baseObject =
+                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(baseModel->object_[iObject]) ;
+                assert (baseObject);
+                dynamicObject->copySome(baseObject);
+            }
+        }
+    } else if (mode == 1) {
+        lockThread();
+        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
+        assert (stuff);
+        //stateOfSearch_
+        if (stuff->saveStuff()[0] != searchStrategy_) {
+#ifdef COIN_DEVELOP
+            printf("changing searchStrategy from %d to %d\n",
+                   baseModel->searchStrategy_, searchStrategy_);
+#endif
+            baseModel->searchStrategy_ = searchStrategy_;
+        }
+        if (stuff->saveStuff()[1] != stateOfSearch_) {
+#ifdef COIN_DEVELOP
+            printf("changing stateOfSearch from %d to %d\n",
+                   baseModel->stateOfSearch_, stateOfSearch_);
+#endif
+            baseModel->stateOfSearch_ = stateOfSearch_;
+        }
+        if (numberUpdateItems_) {
+            for (int i = 0; i < numberUpdateItems_; i++) {
+                CbcObjectUpdateData * update = updateItems_ + i;
+                int objectNumber = update->objectNumber_;
+                CbcObject * object = dynamic_cast<CbcObject *> (baseModel->object_[objectNumber]);
+                if (object)
+                    object->updateInformation(*update);
+            }
+            numberUpdateItems_ = 0;
+        }
+        if (eventHappened_)
+            baseModel->eventHappened_ = true;
+        baseModel->numberNodes_++;
+        baseModel->numberIterations_ +=
+            numberIterations_ - numberFixedAtRoot_;
+        baseModel->numberSolves_ += numberSolves_;
+        if (stuff->node())
+            baseModel->tree_->push(stuff->node());
+        if (stuff->createdNode())
+            baseModel->tree_->push(stuff->createdNode());
+        unlockThread();
+    } else if (mode == 2) {
+        baseModel->sumChangeObjective1_ += sumChangeObjective1_;
+        baseModel->sumChangeObjective2_ += sumChangeObjective2_;
+        //baseModel->numberIterations_ += numberIterations_;
+        for (int iGenerator = 0; iGenerator < numberCutGenerators_; iGenerator++) {
+            CbcCutGenerator * generator = baseModel->generator_[iGenerator];
+            CbcCutGenerator * generator2 = generator_[iGenerator];
+            generator->incrementNumberTimesEntered(generator2->numberTimesEntered());
+            generator->incrementNumberCutsInTotal(generator2->numberCutsInTotal());
+            generator->incrementNumberCutsActive(generator2->numberCutsActive());
+            generator->incrementTimeInCutGenerator(generator2->timeInCutGenerator());
+        }
+        if (parallelMode() >= 0)
+            nodeCompare_ = NULL;
+        baseModel->maximumDepthActual_ = CoinMax(baseModel->maximumDepthActual_, maximumDepthActual_);
+        baseModel->numberDJFixed_ += numberDJFixed_;
+        baseModel->numberStrongIterations_ += numberStrongIterations_;
+        int i;
+        for (i = 0; i < 3; i++)
+            baseModel->strongInfo_[i] += strongInfo_[i];
+        if (parallelMode() >= 0) {
+            walkback_ = NULL;
+            lastNodeInfo_ = NULL;
+            lastNumberCuts_ = NULL;
+            lastCut_ = NULL;
+            //addedCuts_ = NULL;
+            tree_ = NULL;
+        }
+        eventHandler_ = NULL;
+        delete solverCharacteristics_;
+        solverCharacteristics_ = NULL;
+        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
+        if (newMethod) {
+            // new method - we were using base models
+            numberObjects_ = 0;
+            object_ = NULL;
+        }
+    } else if (mode == -1) {
+        delete eventHandler_;
+        eventHandler_ = baseModel->eventHandler_;
+        assert (!statistics_);
+        assert(baseModel->solverCharacteristics_);
+        solverCharacteristics_ = new OsiBabSolver (*baseModel->solverCharacteristics_);
+        solverCharacteristics_->setSolver(solver_);
+        setMaximumNodes(COIN_INT_MAX);
+        if (parallelMode() >= 0) {
+            delete [] walkback_;
+            //delete [] addedCuts_;
+            walkback_ = NULL;
+            //addedCuts_ = NULL;
+            delete [] lastNodeInfo_ ;
+            lastNodeInfo_ = NULL;
+            delete [] lastNumberCuts_ ;
+            lastNumberCuts_ = NULL;
+            delete [] lastCut_ ;
+            lastCut_ = NULL;
+            delete tree_;
+            tree_ = NULL;
+            delete nodeCompare_;
+            nodeCompare_ = NULL;
+        } else {
+            delete tree_;
+            tree_ = new CbcTree();
+            tree_->setComparison(*nodeCompare_) ;
+        }
+        continuousSolver_ = baseModel->continuousSolver_->clone();
+        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
+        if (newMethod) {
+            // new method uses solver - but point to base model
+            // We may update an object in wrong order - shouldn't matter?
+            numberObjects_ = baseModel->numberObjects_;
+            if (parallelMode() >= 0) {
+                object_ = baseModel->object_;
+            } else {
+                printf("*****WARNING - fix testosi option\n");
+                object_ = baseModel->object_;
+            }
+        }
+        int i;
+        for (i = 0; i < numberHeuristics_; i++) {
+            delete heuristic_[i];
+            heuristic_[i] = baseModel->heuristic_[i]->clone();
+            heuristic_[i]->setModelOnly(this);
+        }
+        for (i = 0; i < numberCutGenerators_; i++) {
+            delete generator_[i];
+            generator_[i] = new CbcCutGenerator(*baseModel->generator_[i]);
+            // refreshModel was overkill as thought too many rows
+            generator_[i]->setModel(this);
+        }
+    } else if (mode == 10) {
+        setCutoff(baseModel->getCutoff());
+        bestObjective_ = baseModel->bestObjective_;
+        //assert (!baseModel->globalCuts_.sizeRowCuts());
+        numberSolutions_ = baseModel->numberSolutions_;
+        assert (usedInSolution_);
+        assert (baseModel->usedInSolution_);
+        memcpy(usedInSolution_, baseModel->usedInSolution_, solver_->getNumCols()*sizeof(int));
+        stateOfSearch_ = baseModel->stateOfSearch_;
+        //numberNodes_ = baseModel->numberNodes_;
+        //numberIterations_ = baseModel->numberIterations_;
+        //numberFixedAtRoot_ = numberIterations_; // for statistics
+        phase_ = baseModel->phase_;
+        assert (!nextRowCut_);
+        delete nodeCompare_;
+        nodeCompare_ = baseModel->nodeCompare_->clone();
+        tree_->setComparison(*nodeCompare_) ;
+        assert (!subTreeModel_);
+        //branchingMethod_ = NULL; // need something but what
+        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
+        cutModifier_ = NULL;
+        assert (!analyzeResults_);
+        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
+        assert (stuff);
+        //if (stuff)
+        stuff->setCreatedNode(NULL);
+        // ?? searchStrategy_;
+        searchStrategy_ = baseModel->searchStrategy_;
+        stuff->saveStuff()[0] = searchStrategy_;
+        stateOfSearch_ = baseModel->stateOfSearch_;
+        stuff->saveStuff()[1] = stateOfSearch_;
+        OsiObject ** baseObject = baseModel->object_;
+        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
+            object_[iObject]->updateBefore(baseObject[iObject]);
+        }
+        //delete [] stuff->nodeCount;
+        //stuff->nodeCount = new int [baseModel->maximumDepth_+1];
+    } else if (mode == 11) {
+        if (parallelMode() < 0) {
+            // from deterministic
+            CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
+            assert (stuff);
+            // Move solution etc
+            // might as well mark all including continuous
+            int numberColumns = solver_->getNumCols();
+            for (int i = 0; i < numberColumns; i++) {
+                baseModel->usedInSolution_[i] += usedInSolution_[i];
+                //usedInSolution_[i]=0;
+            }
+            baseModel->numberSolutions_ += numberSolutions_;
+            if (bestObjective_ < baseModel->bestObjective_ && bestObjective_ < baseModel->getCutoff()) {
+                baseModel->bestObjective_ = bestObjective_ ;
+                int numberColumns = solver_->getNumCols();
+                if (!baseModel->bestSolution_)
+                    baseModel->bestSolution_ = new double[numberColumns];
+                CoinCopyN(bestSolution_, numberColumns, baseModel->bestSolution_);
+                baseModel->setCutoff(getCutoff());
+            }
+            //stateOfSearch_
+            if (stuff->saveStuff()[0] != searchStrategy_) {
+#ifdef COIN_DEVELOP
+                printf("changing searchStrategy from %d to %d\n",
+                       baseModel->searchStrategy_, searchStrategy_);
+#endif
+                baseModel->searchStrategy_ = searchStrategy_;
+            }
+            if (stuff->saveStuff()[1] != stateOfSearch_) {
+#ifdef COIN_DEVELOP
+                printf("changing stateOfSearch from %d to %d\n",
+                       baseModel->stateOfSearch_, stateOfSearch_);
+#endif
+                baseModel->stateOfSearch_ = stateOfSearch_;
+            }
+            int i;
+            if (eventHappened_)
+                baseModel->eventHappened_ = true;
+            baseModel->numberNodes_ += stuff->nodesThisTime();
+            baseModel->numberIterations_ += stuff->iterationsThisTime();
+            double cutoff = baseModel->getCutoff();
+            while (!tree_->empty()) {
+                CbcNode * node = tree_->bestNode(COIN_DBL_MAX) ;
+                if (node->objectiveValue() < cutoff) {
+                    assert(node->nodeInfo());
+                    // Make node join correctly
+                    OsiBranchingObject * bobj = node->modifiableBranchingObject();
+                    CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
+                    if (cbcobj) {
+                        CbcObject * object = cbcobj->object();
+                        assert (object);
+                        int position = object->position();
+                        assert (position >= 0);
+                        assert (object_[position] == object);
+                        CbcObject * objectNew =
+                            dynamic_cast<CbcObject *> (baseModel->object_[position]);
+                        cbcobj->setOriginalObject(objectNew);
+                    }
+                    baseModel->tree_->push(node);
+                } else {
+                    delete node;
+                }
+            }
+            for (i = 0; i < stuff->nDeleteNode(); i++) {
+                //printf("CbcNode %x stuff delete\n",stuff->delNode[i]);
+                delete stuff->delNode()[i];
+            }
+        }
+    } else {
+        abort();
+    }
+}
+// Generate one round of cuts - parallel mode
+int
+CbcModel::parallelCuts(CbcBaseModel * master, OsiCuts & theseCuts,
+                       CbcNode * /*node*/, OsiCuts & slackCuts, int lastNumberCuts)
+{
+    /*
+      Is it time to scan the cuts in order to remove redundant cuts? If so, set
+      up to do it.
+    */
+    int fullScan = 0 ;
+    if ((numberNodes_ % SCANCUTS) == 0 || (specialOptions_&256) != 0) {
+        fullScan = 1 ;
+        if (!numberNodes_ || (specialOptions_&256) != 0)
+            fullScan = 2;
+        specialOptions_ &= ~256; // mark as full scan done
+    }
+    // do cuts independently
+    OsiCuts * eachCuts = new OsiCuts [numberCutGenerators_];;
+    int i;
+    assert (master);
+    for (i = 0; i < numberThreads_; i++) {
+        // set solver here after cloning
+        master->model(i)->solver_ = solver_->clone();
+        master->model(i)->numberNodes_ = (fullScan) ? 1 : 0;
+    }
+    // generate cuts
+    int status = 0;
+    const OsiRowCutDebugger * debugger = NULL;
+    bool onOptimalPath = false;
+    for (i = 0; i < numberCutGenerators_; i++) {
+        bool generate = generator_[i]->normal();
+        // skip if not optimal and should be (maybe a cut generator has fixed variables)
+        if (generator_[i]->needsOptimalBasis() && !solver_->basisIsAvailable())
+            generate = false;
+        if (generator_[i]->switchedOff())
+            generate = false;;
+        if (generate) {
+            master->waitForThreadsInCuts(0, eachCuts + i, i);
+        }
+    }
+    // wait
+    master->waitForThreadsInCuts(1, eachCuts, 0);
+    // Now put together
+    for (i = 0; i < numberCutGenerators_; i++) {
+        // add column cuts
+        int numberColumnCutsBefore = theseCuts.sizeColCuts() ;
+        int numberColumnCuts = eachCuts[i].sizeColCuts();
+        int numberColumnCutsAfter = numberColumnCutsBefore
+                                    + numberColumnCuts;
+        int j;
+        for (j = 0; j < numberColumnCuts; j++) {
+            theseCuts.insert(eachCuts[i].colCut(j));
+        }
+        int numberRowCutsBefore = theseCuts.sizeRowCuts() ;
+        int numberRowCuts = eachCuts[i].sizeRowCuts();
+        // insert good cuts
+        if (numberRowCuts) {
+            int n = numberRowCuts;
+            numberRowCuts = 0;
+            for (j = 0; j < n; j++) {
+                const OsiRowCut * thisCut = eachCuts[i].rowCutPtr(j) ;
+                if (thisCut->lb() <= 1.0e10 && thisCut->ub() >= -1.0e10) {
+                    theseCuts.insert(eachCuts[i].rowCut(j));
+                    numberRowCuts++;
+                }
+            }
+            if (generator_[i]->mustCallAgain() && status >= 0)
+                status = 1; // say must go round
+        }
+        int numberRowCutsAfter = numberRowCutsBefore
+                                 + numberRowCuts;
+        if (numberRowCuts) {
+            // Check last cut to see if infeasible
+            const OsiRowCut * thisCut = theseCuts.rowCutPtr(numberRowCutsAfter - 1) ;
+            if (thisCut->lb() > thisCut->ub()) {
+                status = -1; // sub-problem is infeasible
+                break;
+            }
+        }
+#ifdef CBC_DEBUG
+        {
+            int k ;
+            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                OsiRowCut thisCut = theseCuts.rowCut(k) ;
+                /* check size of elements.
+                   We can allow smaller but this helps debug generators as it
+                   is unsafe to have small elements */
+                int n = thisCut.row().getNumElements();
+                const int * column = thisCut.row().getIndices();
+                const double * element = thisCut.row().getElements();
+                //assert (n);
+                for (int i = 0; i < n; i++) {
+                    double value = element[i];
+                    assert(fabs(value) > 1.0e-12 && fabs(value) < 1.0e20);
+                }
+            }
+        }
+#endif
+        if ((specialOptions_&1) != 0) {
+            if (onOptimalPath) {
+                int k ;
+                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
+                    OsiRowCut thisCut = theseCuts.rowCut(k) ;
+                    if (debugger->invalidCut(thisCut)) {
+                        solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
+                        solver_->writeMpsNative("badCut.mps", NULL, NULL, 2);
+#ifdef NDEBUG
+                        printf("Cut generator %d (%s) produced invalid cut (%dth in this go)\n",
+                               i, generator_[i]->cutGeneratorName(), k - numberRowCutsBefore);
+                        const double *lower = getColLower() ;
+                        const double *upper = getColUpper() ;
+                        int numberColumns = solver_->getNumCols();
+                        for (int i = 0; i < numberColumns; i++)
+                            printf("%d bounds %g,%g\n", i, lower[i], upper[i]);
+                        abort();
+#endif
+                    }
+                    assert(!debugger->invalidCut(thisCut)) ;
+                }
+            }
+        }
+        /*
+          The cut generator has done its thing, and maybe it generated some
+          cuts.  Do a bit of bookkeeping: load
+          whichGenerator[i] with the index of the generator responsible for a cut,
+          and place cuts flagged as global in the global cut pool for the model.
+
+          lastNumberCuts is the sum of cuts added in previous iterations; it's the
+          offset to the proper starting position in whichGenerator.
+        */
+        int numberBefore =
+            numberRowCutsBefore + numberColumnCutsBefore + lastNumberCuts ;
+        int numberAfter =
+            numberRowCutsAfter + numberColumnCutsAfter + lastNumberCuts ;
+        // possibly extend whichGenerator
+        resizeWhichGenerator(numberBefore, numberAfter);
+
+        for (j = numberRowCutsBefore; j < numberRowCutsAfter; j++) {
+            whichGenerator_[numberBefore++] = i ;
+            const OsiRowCut * thisCut = theseCuts.rowCutPtr(j) ;
+            if (thisCut->lb() > thisCut->ub())
+                status = -1; // sub-problem is infeasible
+            if (thisCut->globallyValid()) {
+                // add to global list
+                OsiRowCut newCut(*thisCut);
+                newCut.setGloballyValid(true);
+                newCut.mutableRow().setTestForDuplicateIndex(false);
+                globalCuts_.addCutIfNotDuplicate(newCut) ;
+            }
+        }
+        for (j = numberColumnCutsBefore; j < numberColumnCutsAfter; j++) {
+            //whichGenerator_[numberBefore++] = i ;
+            const OsiColCut * thisCut = theseCuts.colCutPtr(j) ;
+            if (thisCut->globallyValid()) {
+                // add to global list
+                makeGlobalCut(thisCut);
+            }
+        }
+    }
+    // Add in any violated saved cuts
+    if (!theseCuts.sizeRowCuts() && !theseCuts.sizeColCuts()) {
+        int numberOld = theseCuts.sizeRowCuts() + lastNumberCuts;
+        int numberCuts = slackCuts.sizeRowCuts() ;
+        int i;
+        // possibly extend whichGenerator
+        resizeWhichGenerator(numberOld, numberOld + numberCuts);
+        double primalTolerance;
+        solver_->getDblParam(OsiPrimalTolerance, primalTolerance) ;
+        for ( i = 0; i < numberCuts; i++) {
+            const OsiRowCut * thisCut = slackCuts.rowCutPtr(i) ;
+            if (thisCut->violated(cbcColSolution_) > 100.0*primalTolerance) {
+                if (messageHandler()->logLevel() > 2)
+                    printf("Old cut added - violation %g\n",
+                           thisCut->violated(cbcColSolution_)) ;
+                whichGenerator_[numberOld++] = -1;
+                theseCuts.insert(*thisCut) ;
+            }
+        }
+    }
+    delete [] eachCuts;
+    return status;
+}
+/*
+  Locks a thread if parallel so that stuff like cut pool
+  can be updated and/or used.
+*/
+void
+CbcModel::lockThread()
+{
+    if (masterThread_ && (threadMode_&1) == 0)
+        masterThread_->lockThread();
+}
+/*
+  Unlocks a thread if parallel
+*/
+void
+CbcModel::unlockThread()
+{
+    if (masterThread_ && (threadMode_&1) == 0)
+        masterThread_->unlockThread();
+}
+// Returns true if locked
+bool
+CbcModel::isLocked() const
+{
+    if (masterThread_) {
+        return (masterThread_->locked());
+    } else {
+        return true;
+    }
+}
+// Stop a child
+void
+CbcModel::setInfoInChild(int type, CbcThread * info)
+{
+    if (type == -3) {
+        // set up
+        masterThread_ = info;
+    } else if (type == -2) {
+        numberThreads_ = 0; // signal to stop
+    } else {
+        // make sure message handler will be deleted
+        defaultHandler_ = true;
+        ownObjects_ = false;
+        delete solverCharacteristics_;
+        solverCharacteristics_ = NULL;
+        if (type >= 0) {
+            delete [] object_; // may be able to when all over to CbcThread
+            for (int i = 0; i < numberCutGenerators_; i++) {
+                delete generator_[i];
+                generator_[i] = NULL;
+                //delete virginGenerator_[i];
+                //virginGenerator_[i]=NULL;
+            }
+            //generator_[0] = NULL;
+            //delete [] generator_;
+            //generator_ = NULL;
+            numberCutGenerators_ = 0;
+        } else {
+            for (int i = 0; i < numberCutGenerators_; i++) {
+                generator_[i] = NULL;
+            }
+        }
+        object_ = NULL;
+    }
+}
+
+/// Indicates whether Cbc library has been compiled with multithreading support
+bool CbcModel::haveMultiThreadSupport() { return true; }
+
+#else
+// Default constructor
+CbcBaseModel::CbcBaseModel() {}
+
+bool CbcModel::haveMultiThreadSupport() { return false; }
+#endif
+
diff --git a/cbits/coin/CbcThread.hpp b/cbits/coin/CbcThread.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcThread.hpp
@@ -0,0 +1,440 @@
+/* $Id: CbcThread.hpp 1902 2013-04-10 16:58:16Z stefan $ */
+// Copyright (C) 2009, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcThread_H
+#define CbcThread_H
+
+#include "CbcModel.hpp"
+#include "CbcNode.hpp"
+class OsiObject;
+class OsiCuts;
+#ifdef CBC_THREAD
+class CbcThread;
+// Use pthreads
+#define CBC_PTHREAD
+#ifdef CBC_PTHREAD
+#include <pthread.h>
+typedef struct {
+    pthread_t	thr;
+    long		status;
+} Coin_pthread_t;
+#endif
+//#define THREAD_DEBUG 1
+/** A class to encapsulate specific thread stuff
+    To use another api with same style - you just need to implement
+    these methods.
+
+    At present just pthreads
+ */
+
+
+class CbcSpecificThread {
+public:
+    // Default Constructor
+    CbcSpecificThread ();
+
+    // Useful Constructor
+    CbcSpecificThread (CbcSpecificThread * master, pthread_mutex_t * masterMutex);
+
+    virtual ~CbcSpecificThread();
+
+    // Useful stuff
+    void setUsefulStuff (CbcSpecificThread * master,
+                         void *& masterMutex);
+    /**
+       Locks a thread if parallel so that stuff like cut pool
+       can be updated and/or used.
+    */
+    void lockThread();
+    /**
+       Unlocks a thread if parallel to say cut pool stuff not needed
+    */
+    void unlockThread();
+    ///  Locks a thread for testing whether to start etc
+    void lockThread2(bool doAnyway = false);
+    ///  Unlocks a thread for testing whether to start etc
+    void unlockThread2(bool doAnyway = false);
+    /// Signal
+    void signal();
+    /// Timed wait in nanoseconds - if negative then seconds
+    void timedWait(int time);
+    /// Actually starts a thread
+    void startThread(void * (*routine ) (void *), CbcThread * thread);
+    /// Exits thread (called from master) - return code should be zero
+    int exit();
+    /// Exits thread
+    void exitThread();
+    /// Get status
+    int status() const;
+    /// Set status
+    void setStatus(int value);
+    //}
+
+
+public: // private:
+    CbcSpecificThread * basePointer_; // for getting main mutex and threadid of base
+#ifdef CBC_PTHREAD
+    pthread_mutex_t *masterMutex_; // for synchronizing
+    pthread_mutex_t mutex2_; // for waking up threads
+    pthread_cond_t condition2_; // for waking up thread
+    Coin_pthread_t threadId_;
+#endif
+    bool locked_; // For mutex2
+};
+/** A class to encapsulate thread stuff */
+
+
+class CbcThread {
+private:
+    void gutsOfDelete();
+    void gutsOfCopy(const CbcThread & rhs);
+
+public:
+    // Default Constructor
+    CbcThread ();
+
+    virtual ~CbcThread();
+
+    /// Fills in useful stuff
+    void setUsefulStuff (CbcModel * model, int deterministic,
+                         CbcModel * baseModel,
+                         CbcThread * master,
+                         void *& masterMutex);
+    /**
+       Locks a thread if parallel so that stuff like cut pool
+       can be updated and/or used.
+    */
+    void lockThread();
+    /**
+       Unlocks a thread if parallel to say cut pool stuff not needed
+    */
+    void unlockThread();
+
+    /// Returns true if locked
+    inline bool isLocked() const {
+        return locked_;
+    }
+    /** Wait for child to have return code NOT == to currentCode
+        type - 0 timed wait
+               1 wait
+           returns true if return code changed */
+    bool wait(int type, int currentCode);
+    /// Just wait for so many nanoseconds
+    void waitNano(int time);
+    /// Signal child to carry on
+    void signal();
+    /// Lock from master with mutex2 and signal before lock
+    void lockFromMaster();
+    /// Unlock from master with mutex2 and signal after unlock
+    void unlockFromMaster();
+    /// Lock from thread with mutex2 and signal before lock
+    void lockFromThread();
+    /// Unlock from thread with mutex2 and signal after unlock
+    void unlockFromThread();
+    /// Exits thread (called from master) - return code should be zero
+    int exit();
+    /// Exits thread
+    void exitThread();
+    /// Waits until returnCode_ goes to zero
+    void waitThread();
+    /// Get status
+    inline int status() const {
+        return threadStuff_.status();
+    }
+    /// Set status
+    inline void setStatus(int value) {
+        threadStuff_.setStatus( value);
+    }
+    /// Get return code
+    inline int returnCode() const {
+        return returnCode_;
+    }
+    /// Set return code
+    inline void setReturnCode(int value) {
+        returnCode_ = value;
+    }
+    /// Get base model
+    inline CbcModel * baseModel() const {
+        return baseModel_;
+    }
+    /// Get this model
+    inline CbcModel * thisModel() const {
+        return thisModel_;
+    }
+    /// Get node
+    inline CbcNode * node() const {
+        return node_;
+    }
+    /// Set node
+    inline void setNode(CbcNode * node) {
+        node_ = node;
+    }
+    /// Get created node
+    inline CbcNode * createdNode() const {
+        return createdNode_;
+    }
+    /// Set created node
+    inline void setCreatedNode(CbcNode * node) {
+        createdNode_ = node;
+    }
+    /// Get dantzig state
+    inline int dantzigState() const {
+        return dantzigState_;
+    }
+    /// Set dantzig state
+    inline void setDantzigState(int value) {
+        dantzigState_ = value;
+    }
+    /// Get time in thread
+    inline double timeInThread() const {
+        return timeInThread_;
+    }
+    /// Increment time in thread
+    inline void incrementTimeInThread(double value) {
+        timeInThread_ += value;
+    }
+    /// Get time waiting to start
+    inline double timeWaitingToStart() const {
+        return timeWaitingToStart_;
+    }
+    /// Increment time waiting to start
+    inline void incrementTimeWaitingToStart(double value) {
+        timeWaitingToStart_ += value;
+    }
+    /// Get time locked
+    inline double timeLocked() const {
+        return timeLocked_;
+    }
+    /// Increment time locked
+    inline void incrementTimeLocked(double value) {
+        timeLocked_ += value;
+    }
+    /// Get time waiting to lock
+    inline double timeWaitingToLock() const {
+        return timeWaitingToLock_;
+    }
+    /// Increment time waiting to lock
+    inline void incrementTimeWaitingToLock(double value) {
+        timeWaitingToLock_ += value;
+    }
+    /// Get if deterministic
+    inline int deterministic() const {
+        return deterministic_;
+    }
+    /// Get maxDeleteNode
+    inline int maxDeleteNode() const {
+        return maxDeleteNode_;
+    }
+    /// Set maxDeleteNode
+    inline void setMaxDeleteNode(int value) {
+        maxDeleteNode_ = value;
+    }
+    /// Get nDeleteNode (may be fake i.e. defaultParallelIterations_)
+    inline int nDeleteNode() const {
+        return nDeleteNode_;
+    }
+    /// Set nDeleteNode (may be fake i.e. defaultParallelIterations_)
+    inline void setNDeleteNode(int value) {
+        nDeleteNode_ = value;
+    }
+    /// Clear delNode
+    inline void clearDelNode() {
+        delete delNode_;
+        delNode_ = NULL;
+    }
+    /// Set fake delNode to pass across OsiCuts
+    inline void fakeDelNode(CbcNode ** delNode) {
+        delNode_ = delNode;
+    }
+    /// Get delNode
+    inline CbcNode ** delNode() const {
+        return delNode_;
+    }
+    /// Set delNode
+    inline void setDelNode(CbcNode ** delNode) {
+        delNode_ = delNode;
+    }
+    /// Get number times locked
+    inline int numberTimesLocked() const {
+        return numberTimesLocked_;
+    }
+    /// Get number times unlocked
+    inline int numberTimesUnlocked() const {
+        return numberTimesUnlocked_;
+    }
+    /// Get number of nodes this time
+    inline int nodesThisTime() const {
+        return nodesThisTime_;
+    }
+    /// Set number of nodes this time
+    inline void setNodesThisTime(int value) {
+        nodesThisTime_ = value;
+    }
+    /// Get number of iterations this time
+    inline int iterationsThisTime() const {
+        return iterationsThisTime_;
+    }
+    /// Set number of iterations this time
+    inline void setIterationsThisTime(int value) {
+        iterationsThisTime_ = value;
+    }
+    /// Get save stuff array
+    inline int * saveStuff() {
+        return saveStuff_;
+    }
+    /// Say if locked
+    inline bool locked() const {
+        return locked_;
+    }
+
+public: // private:
+    CbcSpecificThread threadStuff_;
+    CbcModel * baseModel_;
+    CbcModel * thisModel_;
+    CbcNode * node_; // filled in every time
+    CbcNode * createdNode_; // filled in every time on return
+    CbcThread * master_; // points back to master thread
+    int returnCode_; // -1 available, 0 busy, 1 finished , 2??
+    double timeLocked_;
+    double timeWaitingToLock_;
+    double timeWaitingToStart_;
+    double timeInThread_;
+    double timeWhenLocked_; // time when thread got lock (in seconds)
+    int numberTimesLocked_;
+    int numberTimesUnlocked_;
+    int numberTimesWaitingToStart_;
+    int saveStuff_[2];
+    int dantzigState_; // 0 unset, -1 waiting to be set, 1 set
+    bool locked_;
+    int nDeleteNode_;
+    CbcNode ** delNode_;
+    int maxDeleteNode_;
+    int nodesThisTime_;
+    int iterationsThisTime_;
+    int deterministic_;
+#ifdef THREAD_DEBUG
+public:
+    int threadNumber_;
+    int lockCount_;
+#endif
+};
+/** Base model */
+
+
+class CbcBaseModel {
+public:
+    // Default Constructor
+    CbcBaseModel ();
+
+    /** Constructor with model
+        type -1 cuts
+              0 opportunistic
+              1 deterministic */
+    /** Constructor with model
+        type -1 cuts
+              0 opportunistic
+              1 deterministic */
+    CbcBaseModel (CbcModel & model, int type);
+
+    virtual ~CbcBaseModel();
+
+    /** Stop all threads
+        -1 just check all in good state
+        0 actually stop
+    */
+    void stopThreads(int type);
+
+    /** Wait for threads in tree
+        type 0 - tree looks empty - see if any nodes outstanding
+             1 - tree not empty
+         2 - finish and do statistics
+        returns non-zero if keep going
+    */
+    int waitForThreadsInTree(int type);
+
+    /** Wait for threads n parallel cuts
+        type 0 - parallel cuts
+         1 - finishing parallel cuts
+    */
+    void waitForThreadsInCuts(int type, OsiCuts * eachCuts, int whichGenerator);
+
+    /// Split model and do work in deterministic parallel
+    void  deterministicParallel();
+    /**
+       Locks a thread if parallel so that stuff like cut pool
+       can be updated and/or used.
+    */
+    inline void lockThread() {
+        children_[numberThreads_].lockThread();
+    }
+    /**
+       Unlocks a thread if parallel to say cut pool stuff not needed
+    */
+    inline void unlockThread() {
+        children_[numberThreads_].unlockThread();
+    }
+
+    /// Returns true if locked
+    inline bool isLocked() const {
+        return children_[numberThreads_].locked();
+    }
+
+    /// Returns pointer to master thread
+    CbcThread * masterThread() const;
+
+    /// Returns pointer to a thread model
+    inline CbcModel * model(int i) const {
+        return threadModel_[i];
+    }
+
+    /// Sets Dantzig state in children
+    void setDantzigState();
+
+private:
+
+    /// Number of children
+    int numberThreads_;
+    /// Child models (with base model at end)
+    CbcThread * children_;
+    /** type -1 cuts
+              0 opportunistic
+              1 deterministic */
+    int type_;
+    int * threadCount_;
+    CbcModel ** threadModel_;
+    int numberObjects_;
+    OsiObject ** saveObjects_;
+    int threadStats_[6];
+    int defaultParallelIterations_;
+    int defaultParallelNodes_;
+};
+#else
+// Dummy threads
+/** A class to encapsulate thread stuff */
+
+
+class CbcThread {
+public:
+    // Default Constructor
+    CbcThread () {}
+
+    virtual ~CbcThread() {}
+
+};
+/** Base model */
+
+
+class CbcBaseModel {
+public:
+    // Default Constructor (not declared here so that CbcThread.cpp not empty)
+    CbcBaseModel ();
+
+    virtual ~CbcBaseModel() {}
+
+};
+#endif
+
+#endif
+
diff --git a/cbits/coin/CbcTree.cpp b/cbits/coin/CbcTree.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcTree.cpp
@@ -0,0 +1,1406 @@
+/* $Id: CbcTree.cpp 1813 2012-11-22 19:00:22Z forrest $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CbcModel.hpp"
+#include "CbcNode.hpp"
+#include "CbcTree.hpp"
+#include "CbcCountRowCut.hpp"
+#include "CbcCompareActual.hpp"
+#include "CbcBranchActual.hpp"
+
+
+#if CBC_DEBUG_HEAP > 0
+
+namespace {
+
+
+/*
+  The next few methods test that the heap property (parent equal or better
+  than either child) is maintained in the heap. Originally created to sort out
+  why `cbc -unitTest' triggered an `Invalid heap' error in a MSVS debug build.
+*/
+/*
+  Predicate test. The parent should be better or equal to the child. Since the
+  predicate comparison_(x,y) returns true if y (child) is strictly better,
+  we want failure on the initial test. Clearly, success for comparison(x,y)
+  and comparison(y,x) is also a failure.
+
+  Returns true if the predicate passes, false if it fails.
+*/
+bool check_pred (CbcCompareBase &pred, CbcNode *parent, CbcNode *child)
+{
+  if (parent == 0 || child == 0) return (false) ;
+	if (!pred(parent,child))
+		return (true) ;
+  else if (pred(child,parent))
+	  std::cout
+			<< " Heap predicate failure! (x<y) && (y<x)!" << std::endl ;
+	return (false) ;
+}
+
+} // end file-local namespace
+
+/*
+  Check for the heap property: the parent is better than or equal to
+  either child.
+
+  The heap is a binary tree, stored in the vector layer by layer. By advancing
+  parent at half the rate of child (aka curNode), we check both children
+  of a given parent.  (Draw yourself a picture; it'll help.) An empty heap
+  is trivially valid. A heap with no predicate is trivially invalid.
+
+  TODO: The heap -> vector mapping assumed here is valid for the MSVS heap
+	implementation.  No guarantee it's valid elsewhere.
+*/
+
+void CbcTree::validateHeap ()
+{
+  if (comparison_.test_ == 0) {
+    std::cout
+      << " Invalid heap (no predicate)!" << std::endl ;
+    return ;
+  }
+  std::vector<CbcNode *>::const_iterator curNode,lastNode ;
+  curNode = nodes_.begin() ;
+  lastNode = nodes_.end() ;
+  int curNdx = 0 ;
+  int parNdx = 0 ;
+  if (curNode == lastNode) return ;
+  if (*curNode == 0) {
+    std::cout
+      << " Invalid heap[" << curNdx << "] (null entry)!" << std::endl ;
+  }
+  std::vector<CbcNode *>::const_iterator parent ;
+  std::vector<CbcNode*>::const_iterator &child = curNode ;
+  for (parent = curNode ; ++curNode != lastNode ; ++parent, ++parNdx) {
+    curNdx++ ;
+    if (*parent == 0) {
+      std::cout
+        << " Invalid heap[" << parNdx << "] (parent null entry)!" << std::endl ;
+      curNode++ ;
+      curNdx++ ;
+      continue ;
+    }
+    if (*curNode == 0) {
+      std::cout
+        << " Invalid heap[" << curNdx << "] (left child null entry)!"
+	<< std::endl ;
+    } else {
+      if (!check_pred(*comparison_.test_,*parent,*child)) {
+        std::cout
+          << " Invalid heap (left child better)!" << std::endl ;
+        CbcNode *node = *parent ; 
+        std::cout
+          << "   Parent [" << parNdx << "] (" << std::hex << node << std::dec
+          << ") unsat " << node->numberUnsatisfied() << ", depth "
+	  << node->depth() << ", obj " << node->objectiveValue() << "."
+	  << std::endl ;
+        node = *child ;
+        std::cout
+          << "   Child [" << curNdx << "] (" << std::hex << node << std::dec
+          << ") unsat " << node->numberUnsatisfied() << ", depth "
+	  << node->depth() << ", obj " << node->objectiveValue() << "."
+	  << std::endl ;
+      }
+    }
+    curNode++ ;
+    curNdx++ ;
+    if (curNode == lastNode) break ;
+    if (*curNode == 0) {
+      std::cout
+        << " Invalid heap[" << curNdx << "] (right child null entry)!"
+	<< std::endl ;
+    } else {
+      if (!check_pred(*comparison_.test_,*parent,*child)) {
+        std::cout
+          << " Invalid heap (right child better)!" << std::endl ;
+        CbcNode *node = *parent ;
+        std::cout
+          << "   Parent [" << parNdx << "] (" << std::hex << node << std::dec
+          << ") unsat " << node->numberUnsatisfied() << ", depth "
+	  << node->depth() << ", obj " << node->objectiveValue() << "."
+	  << std::endl ;
+        node = *child ;
+        std::cout
+          << "   Child [" << curNdx << "] (" << std::hex << node << std::dec
+          << ") unsat " << node->numberUnsatisfied() << ", depth "
+	  << node->depth() << ", obj " << node->objectiveValue() << "."
+	  << std::endl ;
+      }
+    }
+  }
+  return ;
+}
+    
+
+#endif // CBC_DEBUG_HEAP
+
+
+CbcTree::CbcTree()
+{
+    maximumNodeNumber_ = 0;
+    numberBranching_ = 0;
+    maximumBranching_ = 0;
+    branched_ = NULL;
+    newBound_ = NULL;
+}
+CbcTree::~CbcTree()
+{
+    delete [] branched_;
+    delete [] newBound_;
+}
+// Copy constructor
+CbcTree::CbcTree ( const CbcTree & rhs)
+{
+    nodes_ = rhs.nodes_;
+    maximumNodeNumber_ = rhs.maximumNodeNumber_;
+    numberBranching_ = rhs.numberBranching_;
+    maximumBranching_ = rhs.maximumBranching_;
+    if (maximumBranching_ > 0) {
+        branched_ = CoinCopyOfArray(rhs.branched_, maximumBranching_);
+        newBound_ = CoinCopyOfArray(rhs.newBound_, maximumBranching_);
+    } else {
+        branched_ = NULL;
+        newBound_ = NULL;
+    }
+}
+// Assignment operator
+CbcTree &
+CbcTree::operator=(const CbcTree & rhs)
+{
+    if (this != &rhs) {
+        nodes_ = rhs.nodes_;
+        maximumNodeNumber_ = rhs.maximumNodeNumber_;
+        delete [] branched_;
+        delete [] newBound_;
+        numberBranching_ = rhs.numberBranching_;
+        maximumBranching_ = rhs.maximumBranching_;
+        if (maximumBranching_ > 0) {
+            branched_ = CoinCopyOfArray(rhs.branched_, maximumBranching_);
+            newBound_ = CoinCopyOfArray(rhs.newBound_, maximumBranching_);
+        } else {
+            branched_ = NULL;
+            newBound_ = NULL;
+        }
+    }
+    return *this;
+}
+
+/*
+  Rebuild the heap.
+*/
+void CbcTree::rebuild ()
+{
+  std::make_heap(nodes_.begin(), nodes_.end(), comparison_);
+# if CBC_DEBUG_HEAP > 1
+  std::cout << "  HEAP: rebuild complete." << std::endl ;
+# endif
+# if CBC_DEBUG_HEAP > 0
+  validateHeap() ;
+# endif
+}
+
+
+// Adds branching information to complete state
+void
+CbcTree::addBranchingInformation(const CbcModel * model, const CbcNodeInfo * nodeInfo,
+                                 const double * currentLower,
+                                 const double * currentUpper)
+{
+    const OsiBranchingObject * objA  = nodeInfo->owner()->branchingObject();
+    const CbcIntegerBranchingObject * objBranch  = dynamic_cast<const CbcIntegerBranchingObject *> (objA);
+    if (objBranch) {
+        const CbcObject * objB = objBranch->object();
+        const CbcSimpleInteger * obj = dynamic_cast<const CbcSimpleInteger *> (objB);
+        assert (obj);
+        int iColumn = obj->columnNumber();
+        const double * down = objBranch->downBounds();
+        const double * up = objBranch->upBounds();
+        assert (currentLower[iColumn] == down[0]);
+        assert (currentUpper[iColumn] == up[1]);
+        if (dynamic_cast<const CbcPartialNodeInfo *> (nodeInfo)) {
+            const CbcPartialNodeInfo * info = dynamic_cast<const CbcPartialNodeInfo *> (nodeInfo);
+            const double * newBounds = info->newBounds();
+            const int * variables = info->variables();
+            int numberChanged = info->numberChangedBounds();
+            for (int i = 0; i < numberChanged; i++) {
+                int jColumn = variables[i];
+                int kColumn = jColumn & (~0x80000000);
+                if (iColumn == kColumn) {
+                    jColumn |= 0x40000000;
+#ifndef NDEBUG
+                    double value = newBounds[i];
+                    if ((jColumn&0x80000000) == 0) {
+                        assert (value == up[0]);
+                    } else {
+                        assert (value == down[1]);
+                    }
+#endif
+                }
+                if (numberBranching_ == maximumBranching_)
+                    increaseSpace();
+                newBound_[numberBranching_] = static_cast<int> (newBounds[i]);
+                branched_[numberBranching_++] = jColumn;
+            }
+        } else {
+            const CbcFullNodeInfo * info = dynamic_cast<const CbcFullNodeInfo *> (nodeInfo);
+            int numberIntegers = model->numberIntegers();
+            const int * which = model->integerVariable();
+            const double * newLower = info->lower();
+            const double * newUpper = info->upper();
+            if (numberBranching_ == maximumBranching_)
+                increaseSpace();
+            assert (newLower[iColumn] == up[0] ||
+                    newUpper[iColumn] == down[1]);
+            int jColumn = iColumn | 0x40000000;
+            if (newLower[iColumn] == up[0]) {
+                newBound_[numberBranching_] = static_cast<int> (up[0]);
+            } else {
+                newBound_[numberBranching_] = static_cast<int> (down[1]);
+                jColumn |= 0x80000000;
+            }
+            branched_[numberBranching_++] = jColumn;
+            for (int i = 0; i < numberIntegers; i++) {
+                int jColumn = which[i];
+                assert (currentLower[jColumn] == newLower[jColumn] ||
+                        currentUpper[jColumn] == newUpper[jColumn]);
+                if (jColumn != iColumn) {
+                    bool changed = false;
+                    double value;
+                    if (newLower[jColumn] > currentLower[jColumn]) {
+                        value = newLower[jColumn];
+                        changed = true;
+                    } else if (newUpper[jColumn] < currentUpper[jColumn]) {
+                        value = newUpper[jColumn];
+                        jColumn |= 0x80000000;
+                        changed = true;
+                    }
+                    if (changed) {
+                        if (numberBranching_ == maximumBranching_)
+                            increaseSpace();
+                        newBound_[numberBranching_] = static_cast<int> (value);
+                        branched_[numberBranching_++] = jColumn;
+                    }
+                }
+            }
+        }
+    } else {
+        // switch off
+        delete [] branched_;
+        delete [] newBound_;
+        maximumBranching_ = -1;
+        branched_ = NULL;
+        newBound_ = NULL;
+    }
+}
+// Increase space for data
+void
+CbcTree::increaseSpace()
+{
+    assert (numberBranching_ == maximumBranching_);
+    maximumBranching_ = (3 * maximumBranching_ + 10) >> 1;
+    unsigned int * temp1 = CoinCopyOfArrayPartial(branched_, maximumBranching_, numberBranching_);
+    delete [] branched_;
+    branched_ = temp1;
+    int * temp2 = CoinCopyOfArrayPartial(newBound_, maximumBranching_, numberBranching_);
+    delete [] newBound_;
+    newBound_ = temp2;
+}
+// Clone
+CbcTree *
+CbcTree::clone() const
+{
+    return new CbcTree(*this);
+}
+
+#ifndef CBC_DUBIOUS_HEAP
+/*
+  Set comparison predicate and re-sort the heap.
+
+  Note that common usage is to tweak the incumbent predicate and then
+  call this method to rebuild the heap. Hence we cannot check for heap
+  validity at entry. rebuild() will check on the way out, if
+  CBC_DEBUG_HEAP is set.
+
+  TODO: remove the call to cleanDive and put it somewhere appropriate.
+*/
+void
+CbcTree::setComparison(CbcCompareBase  &compare)
+{
+#   if CBC_DEBUG_HEAP > 1
+    std::cout << "  HEAP: resetting comparison predicate." << std::endl ;
+#   endif
+    comparison_.test_ = &compare;
+    
+/*
+  From a software engineering point of view, setComparison has no business
+  knowing anything about the comparison function. Need to look for a better
+  solution. Perhaps a callback comparable to newSolution, executing when
+  the comparison method is set (i.e., in setComparison).
+  -- lh, 100921 --
+*/
+    CbcCompareDefault *compareD =
+          dynamic_cast<CbcCompareDefault *>(&compare);
+    if (compareD) {
+        // clean up diving
+        compareD->cleanDive();
+    }
+    rebuild() ;
+}
+
+// Return the top node of the heap
+CbcNode *
+CbcTree::top() const
+{
+    return nodes_.front();
+}
+
+// Add a node to the heap
+void
+CbcTree::push(CbcNode * x)
+{
+    x->setNodeNumber(maximumNodeNumber_);
+    maximumNodeNumber_++;
+#   if CBC_DEBUG_HEAP > 2
+    CbcNodeInfo *info = x->nodeInfo() ;
+    assert(info) ;
+    std::cout
+      << "  HEAP: Pushing node " << x->nodeNumber()
+      << "(" << std::hex << x << std::dec << ") obj " << x->objectiveValue()
+      << ", ref " << info->decrement(0)
+      << ", todo " << info->numberBranchesLeft()
+      << ", refd by " << info->numberPointingToThis() << "." << std::endl ;
+    assert(x->objectiveValue() != COIN_DBL_MAX);
+#   endif
+#   if CBC_DEBUG_HEAP > 0
+    validateHeap() ;
+#   endif
+    x->setOnTree(true);
+    nodes_.push_back(x);
+    std::push_heap(nodes_.begin(), nodes_.end(), comparison_);
+#   if CBC_DEBUG_HEAP > 0
+    validateHeap() ;
+#   endif
+}
+
+// Remove the top node from the heap
+void
+CbcTree::pop()
+{
+    
+#   if CBC_DEBUG_HEAP > 2
+    CbcNode *node = nodes_.front() ;
+    CbcNodeInfo *info = node->nodeInfo() ;
+    assert(info) ;
+    std::cout
+      << "  HEAP: Popping node " << node->nodeNumber()
+      << "(" << std::hex << node << std::dec
+      << ") obj " << node->objectiveValue()
+      << ", ref " << info->decrement(0)
+      << ", todo " << info->numberBranchesLeft()
+      << ", refd by " << info->numberPointingToThis() << "." << std::endl ;
+#   endif
+#   if CBC_DEBUG_HEAP > 0
+    validateHeap() ;
+#   endif
+    nodes_.front()->setOnTree(false);
+    std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+    nodes_.pop_back();
+
+#   if CBC_DEBUG_HEAP > 0
+    validateHeap() ;
+#   endif
+
+}
+
+// Test if empty *** note may be overridden
+bool
+CbcTree::empty()
+{
+    return nodes_.empty();
+}
+/*
+  Return the best node from the heap.
+
+  Note that best is offered a chance (checkIsCutoff) to reevaluate
+  itself and make arbitrary changes. A caller should be prepared
+  to check that the returned node is acceptable.
+
+  There's quite a bit of suspect code here, much of it disabled in
+  some way. The net effect at present is to return the top node on
+  the heap after offering the node an opportunity to reevaluate itself.
+  Documentation for checkIsCutoff() puts no restrictions on allowable
+  changes. -- lh, 100921 --
+*/
+CbcNode *
+CbcTree::bestNode(double cutoff)
+{
+# if CBC_DEBUG_HEAP > 0
+  validateHeap() ;
+# endif
+/*
+  This code is problematic. As of 100921, there's really no loop.
+  If front() == null, an assert will trigger. checkIsCutoff seems to be
+  work in progress; comments assert that it can make pretty much arbitrary
+  changes to best. If best can change its objective, there's a good
+  possibility the heap is invalid.
+*/
+    CbcNode * best = NULL;
+    while (!best && nodes_.size()) {
+        best = nodes_.front();
+        if (best)
+            assert(best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo());
+        if (best && best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo())
+            assert (best->nodeInfo()->numberBranchesLeft());
+        if (best && best->objectiveValue() >= cutoff) {
+            // double check in case node can change its mind!
+            best->checkIsCutoff(cutoff);
+        }
+        if (!best || best->objectiveValue() >= cutoff) {
+#ifdef JJF_ZERO
+            // take off
+            std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+            nodes_.pop_back();
+            delete best;
+            best = NULL;
+#else
+            // let code get rid of it
+            assert (best);
+#endif
+        }
+    }
+/*
+  See if the comparison object wants us to do a full scan with the
+  alternative criteria. The net effect is to confirm best by the
+  alternative criteria, or identify a competitor and erase it.
+
+  This code is problematic. Nulling an arbitrary node will in general
+  break the heap property. Disabled some time ago, as noted in several
+  places.
+*/
+    if (false && best && comparison_.test_->fullScan()) {
+        CbcNode * saveBest = best;
+        size_t n = nodes_.size();
+        size_t iBest = -1;
+        for (size_t i = 0; i < n; i++) {
+            // temp
+            assert (nodes_[i]);
+            assert (nodes_[i]->nodeInfo());
+            if (nodes_[i] && nodes_[i]->objectiveValue() != COIN_DBL_MAX && nodes_[i]->nodeInfo())
+                assert (nodes_[i]->nodeInfo()->numberBranchesLeft());
+            if (nodes_[i] && nodes_[i]->objectiveValue() < cutoff
+                    && comparison_.alternateTest(best, nodes_[i])) {
+                best = nodes_[i];
+                iBest = i;
+            }
+        }
+        if (best == saveBest) {
+            // can pop
+            // take off
+            std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+            nodes_.pop_back();
+        } else {
+            // make impossible
+            nodes_[iBest] = NULL;
+        }
+    } else if (best) {
+#       if CBC_DEBUG_HEAP > 2
+        CbcNode *node = nodes_.front() ;
+        CbcNodeInfo *info = node->nodeInfo() ;
+        assert(info) ;
+        std::cout
+          << "  bestNode: Popping node " << node->nodeNumber()
+          << "(" << std::hex << node << std::dec
+          << ") obj " << node->objectiveValue()
+          << ", ref " << info->decrement(0)
+          << ", todo " << info->numberBranchesLeft()
+          << ", refd by " << info->numberPointingToThis() << "." << std::endl ;
+#       endif
+        // take off
+        std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+        nodes_.pop_back();
+    }
+#if CBC_DEBUG_HEAP > 0
+    validateHeap() ;
+#endif
+    if (best)
+        best->setOnTree(false);
+    return best;
+}
+/*! \brief Prune the tree using an objective function cutoff
+
+  This routine removes all nodes with objective worse than the
+  specified cutoff value.
+*/
+
+void
+CbcTree::cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective)
+{
+#   if CBC_DEBUG_HEAP > 1
+    std::cout << " cleanTree: beginning clean." << std::endl ;
+#   endif
+#   if CBC_DEBUG_HEAP > 0
+    validateHeap() ;
+#   endif
+    int j;
+    int nNodes = size();
+    CbcNode ** nodeArray = new CbcNode * [nNodes];
+    int * depth = new int [nNodes];
+    int k = 0;
+    int kDelete = nNodes;
+    bestPossibleObjective = 1.0e100 ;
+    /*
+        Destructively scan the heap. Nodes to be retained go into the front of
+        nodeArray, nodes to be deleted into the back. Store the depth in a
+        correlated array for nodes to be deleted.
+    */
+    for (j = 0; j < nNodes; j++) {
+        CbcNode * node = top();
+        pop();
+        double value = node ? node->objectiveValue() : COIN_DBL_MAX;
+        if (node && value >= cutoff) {
+            // double check in case node can change its mind!
+            value = node->checkIsCutoff(cutoff);
+        }
+        if (value >= cutoff || !node->active()) {
+            if (node) {
+                nodeArray[--kDelete] = node;
+                depth[kDelete] = node->depth();
+            }
+        } else {
+            bestPossibleObjective = CoinMin(bestPossibleObjective, value);
+            nodeArray[k++] = node;
+        }
+    }
+    /*
+      Rebuild the heap using the retained nodes.
+    */
+    for (j = 0; j < k; j++) {
+        push(nodeArray[j]);
+    }
+#   if CBC_DEBUG_HEAP > 1
+    std::cout << " cleanTree: finished rebuild." << std::endl ;
+#   endif
+#   if CBC_DEBUG_HEAP > 0
+    validateHeap() ;
+#   endif
+    /*
+      Sort the list of nodes to be deleted, nondecreasing.
+    */
+    CoinSort_2(depth + kDelete, depth + nNodes, nodeArray + kDelete);
+    /*
+      Work back from deepest to shallowest. In spite of the name, addCuts1 is
+      just a preparatory step. When it returns, the following will be true:
+        * all cuts are removed from the solver's copy of the constraint system;
+        * lastws will be a basis appropriate for the specified node;
+        * variable bounds will be adjusted to be appropriate for the specified
+          node;
+        * addedCuts_ (returned via addedCuts()) will contain a list of cuts that
+          should be added to the constraint system at this node (but they have
+          not actually been added).
+      Then we scan the cut list for the node. Decrement the reference count
+      for the cut, and if it's gone to 0, really delete it.
+
+      I don't yet see why the checks for status != basic and addedCuts_[i] != 0
+      are necessary. When reconstructing a node, these checks are used to skip
+      over loose cuts, excluding them from the reconstituted basis. But here
+      we're just interested in correcting the reference count. Tight/loose
+      should make no difference.
+
+      Arguably a separate routine should be used in place of addCuts1. It's
+      doing more work than needed, modifying the model to match a subproblem
+      at a node that will be discarded.  Then again, we seem to need the basis.
+    */
+    for (j = nNodes - 1; j >= kDelete; j--) {
+        CbcNode * node = nodeArray[j];
+        CoinWarmStartBasis *lastws = model->getEmptyBasis() ;
+
+        model->addCuts1(node, lastws);
+        // Decrement cut counts
+        assert (node);
+        //assert (node->nodeInfo());
+        int numberLeft = (node->nodeInfo()) ? node->nodeInfo()->numberBranchesLeft() : 0;
+        int i;
+        for (i = 0; i < model->currentNumberCuts(); i++) {
+            // take off node
+            CoinWarmStartBasis::Status status =
+                lastws->getArtifStatus(i + model->numberRowsAtContinuous());
+            if (status != CoinWarmStartBasis::basic &&
+                    model->addedCuts()[i]) {
+                if (!model->addedCuts()[i]->decrement(numberLeft))
+                    delete model->addedCuts()[i];
+            }
+        }
+        // node should not have anything pointing to it
+        if (node->nodeInfo())
+            node->nodeInfo()->throwAway();
+        delete node ;
+        delete lastws ;
+    }
+    delete [] nodeArray;
+    delete [] depth;
+}
+
+// Return the best node of the heap using alternate criterion
+CbcNode *
+CbcTree::bestAlternate()
+{
+    size_t n = nodes_.size();
+    CbcNode * best = NULL;
+    if (n) {
+        best = nodes_[0];
+        for (size_t i = 1; i < n; i++) {
+            if (comparison_.alternateTest(best, nodes_[i])) {
+                best = nodes_[i];
+            }
+        }
+    }
+    return best;
+}
+
+#ifdef JJF_ZERO // not used, reference removed in CbcModel.cpp
+CbcTreeArray::CbcTreeArray()
+        : CbcTree(),
+        lastNode_(NULL),
+        lastNodePopped_(NULL),
+        switches_(0)
+{
+}
+CbcTreeArray::~CbcTreeArray()
+{
+}
+// Copy constructor
+CbcTreeArray::CbcTreeArray ( const CbcTreeArray & rhs)
+        : CbcTree(rhs),
+        lastNode_(rhs.lastNode_),
+        lastNodePopped_(rhs.lastNodePopped_),
+        switches_(rhs.switches_)
+{
+}
+// Assignment operator
+CbcTreeArray &
+CbcTreeArray::operator=(const CbcTreeArray & rhs)
+{
+    if (this != &rhs) {
+        CbcTree::operator=(rhs);
+        lastNode_ = rhs.lastNode_;
+        lastNodePopped_ = rhs.lastNodePopped_;
+        switches_ = rhs.switches_;
+    }
+    return *this;
+}
+// Clone
+CbcTree *
+CbcTreeArray::clone() const
+{
+    return new CbcTreeArray(*this);
+}
+// Set comparison function and resort heap
+void
+CbcTreeArray::setComparison(CbcCompareBase  &compare)
+{
+    comparison_.test_ = &compare;
+    rebuild() ;
+}
+
+// Add a node to the heap
+void
+CbcTreeArray::push(CbcNode * x)
+{
+    /*printf("push obj %g, refcount %d, left %d, pointing to %d\n",
+       x->objectiveValue(),x->nodeInfo()->decrement(0),
+       x->nodeInfo()->numberBranchesLeft(),x->nodeInfo()->numberPointingToThis());*/
+    assert(x->objectiveValue() != COIN_DBL_MAX && x->nodeInfo());
+    x->setOnTree(true);
+    if (lastNode_) {
+        if (lastNode_->nodeInfo()->parent() == x->nodeInfo()) {
+            // x is parent of lastNode_ so put x on heap
+            //#define CBCTREE_PRINT
+#ifdef CBCTREE_PRINT
+            printf("pushX x %x (%x at depth %d n %d) is parent of lastNode_ %x (%x at depth %d n %d)\n",
+                   x, x->nodeInfo(), x->depth(), x->nodeNumber(),
+                   lastNode_, lastNode_->nodeInfo(), lastNode_->depth(), lastNode_->nodeNumber());
+#endif
+            nodes_.push_back(x);
+        } else {
+            x->setNodeNumber(maximumNodeNumber_);
+            maximumNodeNumber_++;
+#ifdef CBCTREE_PRINT
+            printf("pushLast x %x (%x at depth %d n %d) is parent of lastNode_ %x (%x at depth %d n %d)\n",
+                   x, x->nodeInfo(), x->depth(), x->nodeNumber(),
+                   lastNode_, lastNode_->nodeInfo(), lastNode_->depth(), lastNode_->nodeNumber());
+#endif
+            nodes_.push_back(lastNode_);
+            lastNode_ = x;
+        }
+        std::push_heap(nodes_.begin(), nodes_.end(), comparison_);
+    } else {
+        x->setNodeNumber(maximumNodeNumber_);
+        maximumNodeNumber_++;
+        if (x != lastNodePopped_) {
+            lastNode_ = x;
+#ifdef CBCTREE_PRINT
+            printf("pushNULL x %x (%x at depth %d n %d)\n",
+                   x, x->nodeInfo(), x->depth(), x->nodeNumber());
+#endif
+        } else {
+            // means other way was infeasible
+#ifdef CBCTREE_PRINT
+            printf("push_other_infeasible x %x (%x at depth %d n %d)\n",
+                   x, x->nodeInfo(), x->depth(), x->nodeNumber());
+#endif
+            nodes_.push_back(x);
+            std::push_heap(nodes_.begin(), nodes_.end(), comparison_);
+        }
+    }
+}
+
+// Test if empty *** note may be overridden
+bool
+CbcTreeArray::empty()
+{
+    return nodes_.empty() && (lastNode_ == NULL);
+}
+// Gets best node and takes off heap
+CbcNode *
+CbcTreeArray::bestNode(double cutoff)
+{
+    CbcNode * best = NULL;
+    // See if we want last node or best on heap
+    if (lastNode_) {
+#ifdef CBCTREE_PRINT
+        printf("Best lastNode_ %x (%x at depth %d) - nodeNumber %d obj %g\n",
+               lastNode_, lastNode_->nodeInfo(), lastNode_->depth(),
+               lastNode_->nodeNumber(), lastNode_->objectiveValue());
+#endif
+        assert (lastNode_->onTree());
+        int nodeNumber = lastNode_->nodeNumber();
+        bool useLastNode = false;
+        if (nodeNumber + 1 == maximumNodeNumber_) {
+            // diving - look further
+            CbcCompareDefault * compareDefault
+            = dynamic_cast<CbcCompareDefault *> (comparison_.test_);
+            assert (compareDefault);
+            double bestPossible = compareDefault->getBestPossible();
+            double cutoff = compareDefault->getCutoff();
+            double objValue = lastNode_->objectiveValue();
+            if (cutoff < 1.0e20) {
+                if (objValue - bestPossible < 0.999*(cutoff - bestPossible))
+                    useLastNode = true;
+            } else {
+                useLastNode = true;
+            }
+        }
+        if (useLastNode) {
+            lastNode_->setOnTree(false);
+            best = lastNode_;
+            lastNode_ = NULL;
+            assert(best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo());
+            if (best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo())
+                assert (best->nodeInfo()->numberBranchesLeft());
+            if (best->objectiveValue() >= cutoff) {
+                // double check in case node can change its mind!
+                best->checkIsCutoff(cutoff);
+            }
+            lastNodePopped_ = best;
+            return best;
+        } else {
+            // put on tree
+            nodes_.push_back(lastNode_);
+            lastNode_->setNodeNumber(maximumNodeNumber_);
+            maximumNodeNumber_++;
+            lastNode_ = NULL;
+            std::push_heap(nodes_.begin(), nodes_.end(), comparison_);
+        }
+    }
+    while (!best && nodes_.size()) {
+        best = nodes_.front();
+        if (best)
+            assert(best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo());
+        if (best && best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo())
+            assert (best->nodeInfo()->numberBranchesLeft());
+        if (best && best->objectiveValue() >= cutoff) {
+            // double check in case node can change its mind!
+            best->checkIsCutoff(cutoff);
+        }
+        if (!best || best->objectiveValue() >= cutoff) {
+            // let code get rid of it
+            assert (best);
+        }
+    }
+    lastNodePopped_ = best;
+#ifdef CBCTREE_PRINT
+    if (best)
+        printf("Heap returning node %x (%x at depth %d) - nodeNumber %d - obj %g\n",
+               best, best->nodeInfo(), best->depth(),
+               best->nodeNumber(), best->objectiveValue());
+    else
+        printf("Heap returning Null\n");
+#endif
+    if (best) {
+        // take off
+        std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+        nodes_.pop_back();
+    }
+#ifdef DEBUG_CBC_HEAP
+    if (best) {
+        int n = nodes_.size();
+        bool good = true;
+        for (int i = 0; i < n; i++) {
+            // temp
+            assert (nodes_[i]);
+            if (!comparison_.compareNodes(nodes_[i], best)) {
+                good = false;
+                CbcNode * x = nodes_[i];
+                printf("i=%d x is better nun %d depth %d obj %g, best nun %d depth %d obj %g\n", i,
+                       x->numberUnsatisfied(), x->depth(), x->objectiveValue(),
+                       best->numberUnsatisfied(), best->depth(), best->objectiveValue());
+            }
+        }
+        if (!good) {
+            // compare best to all
+            int i;
+            for (i = 0; i < n; i++) {
+                CbcNode * x = nodes_[i];
+                printf("i=%d x is nun %d depth %d obj %g", i,
+                       x->numberUnsatisfied(), x->depth(), x->objectiveValue());
+                if (!comparison_.compareNodes(x, best)) {
+                    printf(" - best is worse!\n");
+                } else {
+                    printf("\n");
+                }
+            }
+            // Now compare amongst rest
+            for (i = 0; i < n; i++) {
+                CbcNode * x = nodes_[i];
+                printf("For i=%d ", i);
+                for (int j = i + 1; j < n; j++) {
+                    CbcNode * y = nodes_[j];
+                    if (!comparison_.compareNodes(x, y)) {
+                        printf(" b %d", j);
+                    } else {
+                        printf(" w %d", j);
+                    }
+                }
+                printf("\n");
+            }
+            assert(good);
+        }
+    }
+#endif
+    if (best)
+        best->setOnTree(false);
+    return best;
+}
+
+double
+CbcTreeArray::getBestPossibleObjective()
+{
+    double bestPossibleObjective = 1e100;
+    for (int i = 0 ; i < static_cast<int> (nodes_.size()) ; i++) {
+        if (nodes_[i] && nodes_[i]->objectiveValue() < bestPossibleObjective) {
+            bestPossibleObjective = nodes_[i]->objectiveValue();
+        }
+    }
+    if (lastNode_) {
+        bestPossibleObjective = CoinMin(bestPossibleObjective, lastNode_->objectiveValue());
+    }
+    CbcCompareDefault * compareDefault
+    = dynamic_cast<CbcCompareDefault *> (comparison_.test_);
+    assert (compareDefault);
+    compareDefault->setBestPossible(bestPossibleObjective);
+    return bestPossibleObjective;
+}
+/*! \brief Prune the tree using an objective function cutoff
+
+  This routine removes all nodes with objective worst than the
+  specified cutoff value.
+*/
+
+void
+CbcTreeArray::cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective)
+{
+    int j;
+    int nNodes = size();
+    int lastNode = nNodes + 1;
+    CbcNode ** nodeArray = new CbcNode * [lastNode];
+    int * depth = new int [lastNode];
+    int k = 0;
+    int kDelete = lastNode;
+    bestPossibleObjective = 1.0e100 ;
+    /*
+        Destructively scan the heap. Nodes to be retained go into the front of
+        nodeArray, nodes to be deleted into the back. Store the depth in a
+        correlated array for nodes to be deleted.
+    */
+    for (j = 0; j < nNodes; j++) {
+        CbcNode * node = nodes_.front();
+        nodes_.front()->setOnTree(false);
+        std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+        nodes_.pop_back();
+        double value = node ? node->objectiveValue() : COIN_DBL_MAX;
+        if (node && value >= cutoff) {
+            // double check in case node can change its mind!
+            value = node->checkIsCutoff(cutoff);
+        }
+        if (value >= cutoff || !node->active()) {
+            if (node) {
+                nodeArray[--kDelete] = node;
+                depth[kDelete] = node->depth();
+            }
+        } else {
+            bestPossibleObjective = CoinMin(bestPossibleObjective, value);
+            nodeArray[k++] = node;
+        }
+    }
+    if (lastNode_) {
+        double value = lastNode_->objectiveValue();
+        bestPossibleObjective = CoinMin(bestPossibleObjective, value);
+        if (value >= cutoff || !lastNode_->active()) {
+            nodeArray[--kDelete] = lastNode_;
+            depth[kDelete] = lastNode_->depth();
+            lastNode_ = NULL;
+        }
+    }
+    CbcCompareDefault * compareDefault
+    = dynamic_cast<CbcCompareDefault *> (comparison_.test_);
+    assert (compareDefault);
+    compareDefault->setBestPossible(bestPossibleObjective);
+    compareDefault->setCutoff(cutoff);
+    /*
+      Rebuild the heap using the retained nodes.
+    */
+    for (j = 0; j < k; j++) {
+        CbcNode * node = nodeArray[j];
+        node->setOnTree(true);
+        nodes_.push_back(node);
+        std::push_heap(nodes_.begin(), nodes_.end(), comparison_);
+    }
+    /*
+      Sort the list of nodes to be deleted, nondecreasing.
+    */
+    CoinSort_2(depth + kDelete, depth + lastNode, nodeArray + kDelete);
+    /*
+      Work back from deepest to shallowest. In spite of the name, addCuts1 is
+      just a preparatory step. When it returns, the following will be true:
+        * all cuts are removed from the solver's copy of the constraint system;
+        * lastws will be a basis appropriate for the specified node;
+        * variable bounds will be adjusted to be appropriate for the specified
+          node;
+        * addedCuts_ (returned via addedCuts()) will contain a list of cuts that
+          should be added to the constraint system at this node (but they have
+          not actually been added).
+      Then we scan the cut list for the node. Decrement the reference count
+      for the cut, and if it's gone to 0, really delete it.
+
+      I don't yet see why the checks for status != basic and addedCuts_[i] != 0
+      are necessary. When reconstructing a node, these checks are used to skip
+      over loose cuts, excluding them from the reconstituted basis. But here
+      we're just interested in correcting the reference count. Tight/loose
+      should make no difference.
+
+      Arguably a separate routine should be used in place of addCuts1. It's
+      doing more work than needed, modifying the model to match a subproblem
+      at a node that will be discarded.  Then again, we seem to need the basis.
+    */
+    for (j = lastNode - 1; j >= kDelete; j--) {
+        CbcNode * node = nodeArray[j];
+        CoinWarmStartBasis *lastws = model->getEmptyBasis() ;
+
+        model->addCuts1(node, lastws);
+        // Decrement cut counts
+        assert (node);
+        //assert (node->nodeInfo());
+        int numberLeft = (node->nodeInfo()) ? node->nodeInfo()->numberBranchesLeft() : 0;
+        int i;
+        for (i = 0; i < model->currentNumberCuts(); i++) {
+            // take off node
+            CoinWarmStartBasis::Status status =
+                lastws->getArtifStatus(i + model->numberRowsAtContinuous());
+            if (status != CoinWarmStartBasis::basic &&
+                    model->addedCuts()[i]) {
+                if (!model->addedCuts()[i]->decrement(numberLeft))
+                    delete model->addedCuts()[i];
+            }
+        }
+        // node should not have anything pointing to it
+        if (node->nodeInfo())
+            node->nodeInfo()->throwAway();
+        delete node ;
+        delete lastws ;
+    }
+    delete [] nodeArray;
+    delete [] depth;
+}
+#endif
+
+#else  // defined(CBC_DUBIOUS_HEAP)
+
+/*
+  Unclear whether this code is useful any longer. Likely stale. See
+  note in CbcCompareDefault.hpp re. CBC_DUBIOUS_HEAP.
+  -- lh, 100921 --
+*/
+
+// Set comparison function and resort heap
+void
+CbcTree::setComparison(CbcCompareBase  &compare)
+{
+    comparison_.test_ = &compare;
+    std::vector <CbcNode *> newNodes = nodes_;
+    nodes_.resize(0);
+    while (newNodes.size() > 0) {
+        push( newNodes.back());
+        newNodes.pop_back();
+    }
+}
+
+// Return the top node of the heap
+CbcNode *
+CbcTree::top() const
+{
+    return nodes_.front();
+}
+
+// Add a node to the heap
+void
+CbcTree::push(CbcNode * x)
+{
+    x->setNodeNumber(maximumNodeNumber_);
+    maximumNodeNumber_++;
+    /*printf("push obj %g, refcount %d, left %d, pointing to %d\n",
+       x->objectiveValue(),x->nodeInfo()->decrement(0),
+       x->nodeInfo()->numberBranchesLeft(),x->nodeInfo()->numberPointingToThis());*/
+    assert(x->objectiveValue() != COIN_DBL_MAX && x->nodeInfo());
+#ifdef JJF_ZERO
+    nodes_.push_back(x);
+    push_heap(nodes_.begin(), nodes_.end(), comparison_);
+#else
+realpush(x);
+#endif
+}
+
+// Remove the top node from the heap
+void
+CbcTree::pop()
+{
+#ifdef JJF_ZERO
+    std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+    nodes_.pop_back();
+#else
+if (nodes_.size()) {
+    //CbcNode* s = nodes_.front();
+    realpop();
+    //delete s;
+}
+assert (nodes_.size() >= 0);
+#endif
+}
+
+// Test if empty *** note may be overridden
+bool
+CbcTree::empty()
+{
+    return nodes_.empty();
+}
+// Gets best node and takes off heap
+CbcNode *
+CbcTree::bestNode(double cutoff)
+{
+    CbcNode * best = NULL;
+    while (!best && nodes_.size()) {
+        best = nodes_.front();
+        if (best)
+            assert(best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo());
+        if (best && best->objectiveValue() != COIN_DBL_MAX && best->nodeInfo())
+            assert (best->nodeInfo()->numberBranchesLeft());
+        if (best && best->objectiveValue() >= cutoff) {
+            // double check in case node can change its mind!
+            best->checkIsCutoff(cutoff);
+        }
+        if (!best || best->objectiveValue() >= cutoff) {
+#ifdef JJF_ZERO
+            // take off
+            std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+            nodes_.pop_back();
+            delete best;
+            best = NULL;
+#else
+// let code get rid of it
+assert (best);
+#endif
+        }
+    }
+    // switched off for now
+    if (best && comparison_.test_->fullScan() && false) {
+        CbcNode * saveBest = best;
+        int n = nodes_.size();
+        int iBest = -1;
+        for (int i = 0; i < n; i++) {
+            // temp
+            assert (nodes_[i]);
+            assert (nodes_[i]->nodeInfo());
+            if (nodes_[i] && nodes_[i]->objectiveValue() != COIN_DBL_MAX && nodes_[i]->nodeInfo())
+                assert (nodes_[i]->nodeInfo()->numberBranchesLeft());
+            if (nodes_[i] && nodes_[i]->objectiveValue() < cutoff
+                    && comparison_.alternateTest(best, nodes_[i])) {
+                best = nodes_[i];
+                iBest = i;
+            }
+        }
+        if (best == saveBest) {
+            // can pop
+            // take off
+            std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+            nodes_.pop_back();
+        } else {
+            // make impossible
+            nodes_[iBest] = NULL;
+        }
+    } else if (best) {
+        // take off
+#ifdef JJF_ZERO
+        std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+        nodes_.pop_back();
+#else
+realpop();
+#endif
+    }
+#ifdef DEBUG_CBC_HEAP
+    if (best) {
+        int n = nodes_.size();
+        bool good = true;
+        for (int i = 0; i < n; i++) {
+            // temp
+            assert (nodes_[i]);
+            if (!comparison_.compareNodes(nodes_[i], best)) {
+                good = false;
+                CbcNode * x = nodes_[i];
+                printf("i=%d x is better nun %d depth %d obj %g, best nun %d depth %d obj %g\n", i,
+                       x->numberUnsatisfied(), x->depth(), x->objectiveValue(),
+                       best->numberUnsatisfied(), best->depth(), best->objectiveValue());
+            }
+        }
+        if (!good) {
+            // compare best to all
+            int i;
+            for (i = 0; i < n; i++) {
+                CbcNode * x = nodes_[i];
+                printf("i=%d x is nun %d depth %d obj %g", i,
+                       x->numberUnsatisfied(), x->depth(), x->objectiveValue());
+                if (!comparison_.compareNodes(x, best)) {
+                    printf(" - best is worse!\n");
+                } else {
+                    printf("\n");
+                }
+            }
+            // Now compare amongst rest
+            for (i = 0; i < n; i++) {
+                CbcNode * x = nodes_[i];
+                printf("For i=%d ", i);
+                for (int j = i + 1; j < n; j++) {
+                    CbcNode * y = nodes_[j];
+                    if (!comparison_.compareNodes(x, y)) {
+                        printf(" b %d", j);
+                    } else {
+                        printf(" w %d", j);
+                    }
+                }
+                printf("\n");
+            }
+            assert(good);
+        }
+    }
+#endif
+    if (best)
+        best->setOnTree(false);
+    return best;
+}
+
+/*! \brief Prune the tree using an objective function cutoff
+
+  This routine removes all nodes with objective worst than the
+  specified cutoff value.
+*/
+
+void
+CbcTree::cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective)
+{
+    int j;
+    int nNodes = nodes_.size();
+    CbcNode ** nodeArray = new CbcNode * [nNodes];
+    int * depth = new int [nNodes];
+    int k = 0;
+    int kDelete = nNodes;
+    bestPossibleObjective = 1.0e100 ;
+    /*
+        Destructively scan the heap. Nodes to be retained go into the front of
+        nodeArray, nodes to be deleted into the back. Store the depth in a
+        correlated array for nodes to be deleted.
+    */
+    for (j = 0; j < nNodes; j++) {
+        CbcNode * node = top();
+        pop();
+        double value = node ? node->objectiveValue() : COIN_DBL_MAX;
+        if (node && value >= cutoff) {
+            // double check in case node can change its mind!
+            value = node->checkIsCutoff(cutoff);
+        }
+        bestPossibleObjective = CoinMin(bestPossibleObjective, value);
+        if (value >= cutoff) {
+            if (node) {
+                nodeArray[--kDelete] = node;
+                depth[kDelete] = node->depth();
+            }
+        } else {
+            nodeArray[k++] = node;
+        }
+    }
+    /*
+      Rebuild the heap using the retained nodes.
+    */
+    for (j = 0; j < k; j++) {
+        push(nodeArray[j]);
+    }
+    /*
+      Sort the list of nodes to be deleted, nondecreasing.
+    */
+    CoinSort_2(depth + kDelete, depth + nNodes, nodeArray + kDelete);
+    /*
+      Work back from deepest to shallowest. In spite of the name, addCuts1 is
+      just a preparatory step. When it returns, the following will be true:
+        * all cuts are removed from the solver's copy of the constraint system;
+        * lastws will be a basis appropriate for the specified node;
+        * variable bounds will be adjusted to be appropriate for the specified
+          node;
+        * addedCuts_ (returned via addedCuts()) will contain a list of cuts that
+          should be added to the constraint system at this node (but they have
+          not actually been added).
+      Then we scan the cut list for the node. Decrement the reference count
+      for the cut, and if it's gone to 0, really delete it.
+
+      I don't yet see why the checks for status != basic and addedCuts_[i] != 0
+      are necessary. When reconstructing a node, these checks are used to skip
+      over loose cuts, excluding them from the reconstituted basis. But here
+      we're just interested in correcting the reference count. Tight/loose
+      should make no difference.
+
+      Arguably a separate routine should be used in place of addCuts1. It's
+      doing more work than needed, modifying the model to match a subproblem
+      at a node that will be discarded.  Then again, we seem to need the basis.
+    */
+    for (j = nNodes - 1; j >= kDelete; j--) {
+        CbcNode * node = nodeArray[j];
+        CoinWarmStartBasis *lastws = model->getEmptyBasis() ;
+
+        model->addCuts1(node, lastws);
+        // Decrement cut counts
+        assert (node);
+        //assert (node->nodeInfo());
+        int numberLeft = (node->nodeInfo()) ? node->nodeInfo()->numberBranchesLeft() : 0;
+        int i;
+        for (i = 0; i < model->currentNumberCuts(); i++) {
+            // take off node
+            CoinWarmStartBasis::Status status =
+                lastws->getArtifStatus(i + model->numberRowsAtContinuous());
+            if (status != CoinWarmStartBasis::basic &&
+                    model->addedCuts()[i]) {
+                if (!model->addedCuts()[i]->decrement(numberLeft))
+                    delete model->addedCuts()[i];
+            }
+        }
+        // node should not have anything pointing to it
+        if (node->nodeInfo())
+            node->nodeInfo()->throwAway();
+        delete node ;
+        delete lastws ;
+    }
+    delete [] nodeArray;
+    delete [] depth;
+}
+
+// Return the best node of the heap using alternate criterion
+CbcNode *
+CbcTree::bestAlternate()
+{
+    int n = nodes_.size();
+    CbcNode * best = NULL;
+    if (n) {
+        best = nodes_[0];
+        for (int i = 1; i < n; i++) {
+            if (comparison_.alternateTest(best, nodes_[i])) {
+                best = nodes_[i];
+            }
+        }
+    }
+    return best;
+}
+void
+CbcTree::realpop()
+{
+    if (nodes_.size() > 0) {
+        nodes_[0] = nodes_.back();
+        nodes_.pop_back();
+        fixTop();
+    }
+    assert (nodes_.size() >= 0);
+}
+/* After changing data in the top node, fix the heap */
+void
+CbcTree::fixTop()
+{
+    const int size = nodes_.size();
+    if (size > 1) {
+        CbcNode** candidates = &nodes_[0];
+        CbcNode* s = candidates[0];
+        --candidates;
+        int pos = 1;
+        int ch;
+        for (ch = 2; ch < size; pos = ch, ch *= 2) {
+            if (!comparison_.compareNodes(candidates[ch+1], candidates[ch]))
+                ++ch;
+            if (!comparison_.compareNodes(s, candidates[ch]))
+                break;
+            candidates[pos] = candidates[ch];
+        }
+        if (ch == size) {
+            if (!comparison_.compareNodes(candidates[ch], s)) {
+                candidates[pos] = candidates[ch];
+                pos = ch;
+            }
+        }
+        candidates[pos] = s;
+    }
+}
+void
+CbcTree::realpush(CbcNode * node)
+{
+    node->setOnTree(true);
+    nodes_.push_back(node);
+    CbcNode** candidates = &nodes_[0];
+    --candidates;
+    int pos = nodes_.size();
+    int ch;
+    for (ch = pos / 2; ch != 0; pos = ch, ch /= 2) {
+        if (!comparison_.compareNodes(candidates[ch], node))
+            break;
+        candidates[pos] = candidates[ch];
+    }
+    candidates[pos] = node;
+}
+#endif
+
+double
+CbcTree::getBestPossibleObjective()
+{
+    double r_val = 1e100;
+    for (int i = 0 ; i < static_cast<int> (nodes_.size()) ; i++) {
+        if (nodes_[i] && nodes_[i]->objectiveValue() < r_val) {
+            r_val = nodes_[i]->objectiveValue();
+        }
+    }
+    return r_val;
+}
+
diff --git a/cbits/coin/CbcTree.hpp b/cbits/coin/CbcTree.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcTree.hpp
@@ -0,0 +1,472 @@
+/* $Id: CbcTree.hpp 1813 2012-11-22 19:00:22Z forrest $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcTree_H
+#define CbcTree_H
+
+#include <vector>
+#include <algorithm>
+#include <cmath>
+
+#include "CoinHelperFunctions.hpp"
+#include "CbcCompare.hpp"
+
+/*! \brief Using MS heap implementation
+
+  It's unclear if this is needed any longer, or even if it should be allowed.
+  Cbc occasionally tries to do things to the tree (typically tweaking the
+  comparison predicate) that can cause a violation of the heap property (parent better
+  than either child). In a debug build, Microsoft's heap implementation does checks that
+  detect this and fail. This symbol switched to an alternate implementation of CbcTree,
+  and there are clearly differences, but no explanation as to why or what for.
+
+  As of 100921, the code is cleaned up to make it through `cbc -unitTest' without
+  triggering `Invalid heap' in an MSVS debug build. The method validateHeap() can
+  be used for debugging if this turns up again.
+*/
+//#define CBC_DUBIOUS_HEAP
+#if defined(_MSC_VER) || defined(__MNO_CYGWIN)
+//#define CBC_DUBIOUS_HEAP
+#endif
+#if 1 //ndef CBC_DUBIOUS_HEAP
+
+/*! \brief Controls search tree debugging
+
+  In order to have validateHeap() available, set CBC_DEBUG_HEAP
+  to 1 or higher.
+
+  - 1 calls validateHeap() after each change to the heap
+  - 2 will print a line for major operations (clean, set comparison, etc.)
+  - 3 will print information about each push and pop
+
+#define CBC_DEBUG_HEAP 1
+*/
+
+
+/*! \class CbcTree
+    \brief Implementation of the live set as a heap.
+
+    This class is used to hold the set of live nodes in the search tree.
+*/
+class CbcTree {
+
+public:
+    /*! \name Constructors and related */
+//@{
+    /// Default Constructor
+    CbcTree ();
+
+    /// Copy constructor
+    CbcTree (const CbcTree &rhs);
+
+    /// = operator
+    CbcTree & operator=(const CbcTree &rhs);
+
+    /// Destructor
+    virtual ~CbcTree();
+
+    /// Clone
+    virtual CbcTree * clone() const;
+
+    /// Create C++ lines to get to current state
+    virtual void generateCpp(FILE *) {}
+//@}
+
+    /*! \name Heap access and maintenance methods */
+//@{
+    /// Set comparison function and resort heap
+    void setComparison(CbcCompareBase &compare);
+
+    /// Return the top node of the heap
+    virtual CbcNode * top() const;
+
+    /// Add a node to the heap
+    virtual void push(CbcNode *x);
+
+    /// Remove the top node from the heap
+    virtual void pop() ;
+
+    /*! \brief Gets best node and takes off heap
+
+      Before returning the node from the top of the heap, the node
+      is offered an opportunity to reevaluate itself. Callers should
+      be prepared to check that the node returned is suitable for use.
+    */
+    virtual CbcNode * bestNode(double cutoff);
+
+    /*! \brief Rebuild the heap */
+    virtual void rebuild() ;
+//@}
+
+    /*! \name Direct node access methods */
+//@{
+    /// Test for an empty tree
+    virtual bool empty() ;
+
+    /// Return size
+    virtual int size() const { return static_cast<int>(nodes_.size()); }
+
+    /// Return a node pointer
+    inline CbcNode * operator [] (int i) const { return nodes_[i]; }
+
+    /// Return a node pointer
+    inline CbcNode * nodePointer (int i) const { return nodes_[i]; }
+    void realpop();
+    /** After changing data in the top node, fix the heap */
+    void fixTop();
+    void realpush(CbcNode * node);
+//@}
+
+    /*! \name Search tree maintenance */
+//@{
+    /*! \brief Prune the tree using an objective function cutoff
+
+      This routine removes all nodes with objective worse than the
+      specified cutoff value. It also sets bestPossibleObjective to
+      the best objective over remaining nodes.
+    */
+    virtual void cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective);
+
+    /// Get best on list using alternate method
+    CbcNode * bestAlternate();
+
+    /// We may have got an intelligent tree so give it one more chance
+    virtual void endSearch() {}
+
+    /// Get best possible objective function in the tree
+    virtual double getBestPossibleObjective();
+
+    /// Reset maximum node number
+    inline void resetNodeNumbers() { maximumNodeNumber_ = 0; }
+
+    /// Get maximum node number
+    inline int maximumNodeNumber() const { return maximumNodeNumber_; }
+
+    /// Set number of branches
+    inline void setNumberBranching(int value) { numberBranching_ = value; }
+
+    /// Get number of branches
+    inline int getNumberBranching() const { return numberBranching_; }
+
+    /// Set maximum branches
+    inline void setMaximumBranching(int value) { maximumBranching_ = value; }
+
+    /// Get maximum branches
+    inline int getMaximumBranching() const { return maximumBranching_; }
+
+    /// Get branched variables
+    inline unsigned int * branched() const { return branched_; }
+
+    /// Get bounds
+    inline int * newBounds() const { return newBound_; }
+
+    /// Adds branching information to complete state
+    void addBranchingInformation(const CbcModel * model, const CbcNodeInfo * nodeInfo,
+                                 const double * currentLower,
+                                 const double * currentUpper);
+    /// Increase space for data
+    void increaseSpace();
+//@}
+
+# if CBC_DEBUG_HEAP > 0
+  /*! \name Debugging methods */
+  //@{
+    /*! \brief Check that the heap property is satisfied. */
+    void validateHeap() ;
+  //@}
+# endif
+
+protected:
+    /// Storage vector for the heap
+    std::vector <CbcNode *> nodes_;
+	  /// Sort predicate for heap ordering.
+    CbcCompare comparison_;
+    /// Maximum "node" number so far to split ties
+    int maximumNodeNumber_;
+    /// Size of variable list
+    int numberBranching_;
+    /// Maximum size of variable list
+    int maximumBranching_;
+    /** Integer variables branched or bounded
+        top bit set if new upper bound
+        next bit set if a branch
+    */
+    unsigned int * branched_;
+    /// New bound
+    int * newBound_;
+};
+
+#ifdef JJF_ZERO // not used
+/*! \brief Implementation of live set as a managed array.
+
+    This class is used to hold the set of live nodes in the search tree.
+*/
+class CbcTreeArray : public CbcTree {
+
+public:
+
+    // Default Constructor
+    CbcTreeArray ();
+
+    // Copy constructor
+    CbcTreeArray ( const CbcTreeArray & rhs);
+    // = operator
+    CbcTreeArray & operator=(const CbcTreeArray & rhs);
+
+    virtual ~CbcTreeArray();
+
+    /// Clone
+    virtual CbcTree * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+
+    /*! \name Heap access and maintenance methods */
+//@{
+
+    /// Set comparison function and resort heap
+    void setComparison(CbcCompareBase  &compare);
+
+    /// Add a node to the heap
+    virtual void push(CbcNode * x);
+
+    /// Gets best node and takes off heap
+    virtual CbcNode * bestNode(double cutoff);
+
+//@}
+    /*! \name vector methods */
+//@{
+
+    /// Test if empty *** note may be overridden
+    virtual bool empty() ;
+
+//@}
+
+    /*! \name Search tree maintenance */
+//@{
+
+    /*! \brief Prune the tree using an objective function cutoff
+
+      This routine removes all nodes with objective worst than the
+      specified cutoff value.
+      It also sets bestPossibleObjective to best
+      of all on tree before deleting.
+    */
+
+    void cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective);
+    /// Get best possible objective function in the tree
+    virtual double getBestPossibleObjective();
+//@}
+protected:
+    /// Returns
+    /// Last node
+    CbcNode * lastNode_;
+    /// Last node popped
+    CbcNode * lastNodePopped_;
+    /// Not used yet
+    int switches_;
+
+};
+
+/// New style
+#include "CoinSearchTree.hpp"
+/*! \class tree
+    \brief Implementation of live set as a heap.
+
+    This class is used to hold the set of live nodes in the search tree.
+*/
+
+class CbcNewTree : public CbcTree, public CoinSearchTreeManager {
+
+public:
+
+    // Default Constructor
+    CbcNewTree ();
+
+    // Copy constructor
+    CbcNewTree ( const CbcNewTree & rhs);
+    // = operator
+    CbcNewTree & operator=(const CbcNewTree & rhs);
+
+    virtual ~CbcNewTree();
+
+    /// Clone
+    virtual CbcNewTree * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * ) {}
+
+    /*! \name Heap access and maintenance methods */
+//@{
+
+    /// Set comparison function and resort heap
+    void setComparison(CbcCompareBase  &compare);
+
+    /// Return the top node of the heap
+    virtual CbcNode * top() const;
+
+    /// Add a node to the heap
+    virtual void push(CbcNode * x);
+
+    /// Remove the top node from the heap
+    virtual void pop() ;
+    /// Gets best node and takes off heap
+    virtual CbcNode * bestNode(double cutoff);
+
+//@}
+    /*! \name vector methods */
+//@{
+
+    /// Test if empty *** note may be overridden
+    virtual bool empty() ;
+
+    /// Return size
+    inline int size() const {
+        return nodes_.size();
+    }
+
+    /// [] operator
+    inline CbcNode * operator [] (int i) const {
+        return nodes_[i];
+    }
+
+    /// Return a node pointer
+    inline CbcNode * nodePointer (int i) const {
+        return nodes_[i];
+    }
+
+//@}
+
+    /*! \name Search tree maintenance */
+//@{
+
+    /*! \brief Prune the tree using an objective function cutoff
+
+      This routine removes all nodes with objective worst than the
+      specified cutoff value.
+      It also sets bestPossibleObjective to best
+      of all on tree before deleting.
+    */
+
+    void cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective);
+
+    /// Get best on list using alternate method
+    CbcNode * bestAlternate();
+
+    /// We may have got an intelligent tree so give it one more chance
+    virtual void endSearch() {}
+//@}
+protected:
+
+
+};
+#endif
+#else
+/* CBC_DUBIOUS_HEAP is defined
+
+  See note at top of file. This code is highly suspect.
+  -- lh, 100921 --
+*/
+class CbcTree {
+
+public:
+
+    // Default Constructor
+    CbcTree ();
+
+    // Copy constructor
+    CbcTree ( const CbcTree & rhs);
+    // = operator
+    CbcTree & operator=(const CbcTree & rhs);
+
+    virtual ~CbcTree();
+
+    /// Clone
+    virtual CbcTree * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) {}
+
+    /*! \name Heap access and maintenance methods */
+//@{
+
+    /// Set comparison function and resort heap
+    void setComparison(CbcCompareBase  &compare);
+
+    /// Return the top node of the heap
+    virtual CbcNode * top() const;
+
+    /// Add a node to the heap
+    virtual void push(CbcNode * x);
+
+    /// Remove the top node from the heap
+    virtual void pop() ;
+    /// Gets best node and takes off heap
+    virtual CbcNode * bestNode(double cutoff);
+
+//@}
+    /*! \name vector methods */
+//@{
+
+    /// Test if empty *** note may be overridden
+    //virtual bool empty() ;
+
+    /// Return size
+    inline int size() const {
+        return nodes_.size();
+    }
+
+    /// [] operator
+    inline CbcNode * operator [] (int i) const {
+        return nodes_[i];
+    }
+
+    /// Return a node pointer
+    inline CbcNode * nodePointer (int i) const {
+        return nodes_[i];
+    }
+
+    virtual bool empty();
+    //inline int size() const { return size_; }
+    void realpop();
+    /** After changing data in the top node, fix the heap */
+    void fixTop();
+    void realpush(CbcNode * node);
+//@}
+
+    /*! \name Search tree maintenance */
+//@{
+
+    /*! \brief Prune the tree using an objective function cutoff
+
+      This routine removes all nodes with objective worst than the
+      specified cutoff value.
+      It also sets bestPossibleObjective to best
+      of all on tree before deleting.
+    */
+
+    void cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective);
+
+    /// Get best on list using alternate method
+    CbcNode * bestAlternate();
+
+    /// We may have got an intelligent tree so give it one more chance
+    virtual void endSearch() {}
+    /// Reset maximum node number
+    inline void resetNodeNumbers() {
+        maximumNodeNumber_ = 0;
+    }
+
+    /// Get maximum node number
+    inline int maximumNodeNumber() const { return maximumNodeNumber_; }
+//@}
+protected:
+    std::vector <CbcNode *> nodes_;
+    CbcCompare comparison_;	///> Sort function for heap ordering.
+    /// Maximum "node" number so far to split ties
+    int maximumNodeNumber_;
+
+
+};
+#endif
+#endif
+
diff --git a/cbits/coin/CbcTreeLocal.cpp b/cbits/coin/CbcTreeLocal.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcTreeLocal.cpp
@@ -0,0 +1,1760 @@
+/* $Id: CbcTreeLocal.cpp 1839 2013-01-16 18:41:25Z forrest $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CbcModel.hpp"
+#include "CbcNode.hpp"
+#include "CbcTreeLocal.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinTime.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include <cassert>
+#ifdef JJF_ZERO
+// gdb doesn't always put breakpoints in this virtual function
+// just stick xxxxxx() where you want to start
+static void xxxxxx()
+{
+    printf("break\n");
+}
+#endif
+CbcTreeLocal::CbcTreeLocal()
+        : localNode_(NULL),
+        bestSolution_(NULL),
+        savedSolution_(NULL),
+        saveNumberSolutions_(0),
+        model_(NULL),
+        originalLower_(NULL),
+        originalUpper_(NULL),
+        range_(0),
+        typeCuts_(-1),
+        maxDiversification_(0),
+        diversification_(0),
+        nextStrong_(false),
+        rhs_(0.0),
+        savedGap_(0.0),
+        bestCutoff_(0.0),
+        timeLimit_(0),
+        startTime_(0),
+        nodeLimit_(0),
+        startNode_(-1),
+        searchType_(-1),
+        refine_(false)
+{
+
+}
+/* Constructor with solution.
+   range is upper bound on difference from given solution.
+   maxDiversification is maximum number of diversifications to try
+   timeLimit is seconds in subTree
+   nodeLimit is nodes in subTree
+*/
+CbcTreeLocal::CbcTreeLocal(CbcModel * model, const double * solution ,
+                           int range, int typeCuts, int maxDiversification,
+                           int timeLimit, int nodeLimit, bool refine)
+        : localNode_(NULL),
+        bestSolution_(NULL),
+        savedSolution_(NULL),
+        saveNumberSolutions_(0),
+        model_(model),
+        originalLower_(NULL),
+        originalUpper_(NULL),
+        range_(range),
+        typeCuts_(typeCuts),
+        maxDiversification_(maxDiversification),
+        diversification_(0),
+        nextStrong_(false),
+        rhs_(0.0),
+        savedGap_(0.0),
+        bestCutoff_(0.0),
+        timeLimit_(timeLimit),
+        startTime_(0),
+        nodeLimit_(nodeLimit),
+        startNode_(-1),
+        searchType_(-1),
+        refine_(refine)
+{
+
+    OsiSolverInterface * solver = model_->solver();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    //const double * solution = solver->getColSolution();
+    //const double * objective = solver->getObjCoefficients();
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    // Get increment
+    model_->analyzeObjective();
+
+    {
+        // needed to sync cutoffs
+        double value ;
+        solver->getDblParam(OsiDualObjectiveLimit, value) ;
+        model_->setCutoff(value * solver->getObjSense());
+    }
+    bestCutoff_ = model_->getCutoff();
+    // save current gap
+    savedGap_ = model_->getDblParam(CbcModel::CbcAllowableGap);
+
+    // make sure integers found
+    model_->findIntegers(false);
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    int i;
+    double direction = solver->getObjSense();
+    double newSolutionValue = 1.0e50;
+    if (solution) {
+        // copy solution
+        solver->setColSolution(solution);
+        newSolutionValue = direction * solver->getObjValue();
+    }
+    originalLower_ = new double [numberIntegers];
+    originalUpper_ = new double [numberIntegers];
+    bool all01 = true;
+    int number01 = 0;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        originalLower_[i] = lower[iColumn];
+        originalUpper_[i] = upper[iColumn];
+        if (upper[iColumn] - lower[iColumn] > 1.5)
+            all01 = false;
+        else if (upper[iColumn] - lower[iColumn] == 1.0)
+            number01++;
+    }
+    if (all01 && !typeCuts_)
+        typeCuts_ = 1; // may as well so we don't have to deal with refine
+    if (!number01 && !typeCuts_) {
+        if (model_->messageHandler()->logLevel() > 1)
+            printf("** No 0-1 variables and local search only on 0-1 - switching off\n");
+        typeCuts_ = -1;
+    } else {
+        if (model_->messageHandler()->logLevel() > 1) {
+            std::string type;
+            if (all01) {
+                printf("%d 0-1 variables normal local  cuts\n",
+                       number01);
+            } else if (typeCuts_) {
+                printf("%d 0-1 variables, %d other - general integer local cuts\n",
+                       number01, numberIntegers - number01);
+            } else {
+                printf("%d 0-1 variables, %d other - local cuts but just on 0-1 variables\n",
+                       number01, numberIntegers - number01);
+            }
+            printf("maximum diversifications %d, initial cutspace %d, max time %d seconds, max nodes %d\n",
+                   maxDiversification_, range_, timeLimit_, nodeLimit_);
+        }
+    }
+    int numberColumns = model_->getNumCols();
+    savedSolution_ = new double [numberColumns];
+    memset(savedSolution_, 0, numberColumns*sizeof(double));
+    if (solution) {
+        rhs_ = range_;
+        // Check feasible
+        int goodSolution = createCut(solution, cut_);
+        if (goodSolution >= 0) {
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                double value = floor(solution[iColumn] + 0.5);
+                // fix so setBestSolution will work
+                solver->setColLower(iColumn, value);
+                solver->setColUpper(iColumn, value);
+            }
+            model_->reserveCurrentSolution();
+            // Create cut and get total gap
+            if (newSolutionValue < bestCutoff_) {
+                model_->setBestSolution(CBC_ROUNDING, newSolutionValue, solution);
+                bestCutoff_ = model_->getCutoff();
+                // save as best solution
+                memcpy(savedSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+            }
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                // restore bounds
+                solver->setColLower(iColumn, originalLower_[i]);
+                solver->setColUpper(iColumn, originalUpper_[i]);
+            }
+            // make sure can't stop on gap
+            model_->setDblParam(CbcModel::CbcAllowableGap, -1.0e50);
+        } else {
+            model_ = NULL;
+        }
+    } else {
+        // no solution
+        rhs_ = 1.0e50;
+        // make sure can't stop on gap
+        model_->setDblParam(CbcModel::CbcAllowableGap, -1.0e50);
+    }
+}
+CbcTreeLocal::~CbcTreeLocal()
+{
+    delete [] originalLower_;
+    delete [] originalUpper_;
+    delete [] bestSolution_;
+    delete [] savedSolution_;
+    delete localNode_;
+}
+// Copy constructor
+CbcTreeLocal::CbcTreeLocal ( const CbcTreeLocal & rhs)
+        : CbcTree(rhs),
+        saveNumberSolutions_(rhs.saveNumberSolutions_),
+        model_(rhs.model_),
+        range_(rhs.range_),
+        typeCuts_(rhs.typeCuts_),
+        maxDiversification_(rhs.maxDiversification_),
+        diversification_(rhs.diversification_),
+        nextStrong_(rhs.nextStrong_),
+        rhs_(rhs.rhs_),
+        savedGap_(rhs.savedGap_),
+        bestCutoff_(rhs.bestCutoff_),
+        timeLimit_(rhs.timeLimit_),
+        startTime_(rhs.startTime_),
+        nodeLimit_(rhs.nodeLimit_),
+        startNode_(rhs.startNode_),
+        searchType_(rhs.searchType_),
+        refine_(rhs.refine_)
+{
+    cut_ = rhs.cut_;
+    fixedCut_ = rhs.fixedCut_;
+    if (rhs.localNode_)
+        localNode_ = new CbcNode(*rhs.localNode_);
+    else
+        localNode_ = NULL;
+    if (rhs.originalLower_) {
+        int numberIntegers = model_->numberIntegers();
+        originalLower_ = new double [numberIntegers];
+        memcpy(originalLower_, rhs.originalLower_, numberIntegers*sizeof(double));
+        originalUpper_ = new double [numberIntegers];
+        memcpy(originalUpper_, rhs.originalUpper_, numberIntegers*sizeof(double));
+    } else {
+        originalLower_ = NULL;
+        originalUpper_ = NULL;
+    }
+    if (rhs.bestSolution_) {
+        int numberColumns = model_->getNumCols();
+        bestSolution_ = new double [numberColumns];
+        memcpy(bestSolution_, rhs.bestSolution_, numberColumns*sizeof(double));
+    } else {
+        bestSolution_ = NULL;
+    }
+    if (rhs.savedSolution_) {
+        int numberColumns = model_->getNumCols();
+        savedSolution_ = new double [numberColumns];
+        memcpy(savedSolution_, rhs.savedSolution_, numberColumns*sizeof(double));
+    } else {
+        savedSolution_ = NULL;
+    }
+}
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+CbcTreeLocal &
+CbcTreeLocal::operator=(const CbcTreeLocal & rhs)
+{
+    if (this != &rhs) {
+        CbcTree::operator=(rhs);
+        saveNumberSolutions_ = rhs.saveNumberSolutions_;
+        cut_ = rhs.cut_;
+        fixedCut_ = rhs.fixedCut_;
+        delete localNode_;
+        if (rhs.localNode_)
+            localNode_ = new CbcNode(*rhs.localNode_);
+        else
+            localNode_ = NULL;
+        model_ = rhs.model_;
+        range_ = rhs.range_;
+        typeCuts_ = rhs.typeCuts_;
+        maxDiversification_ = rhs.maxDiversification_;
+        diversification_ = rhs.diversification_;
+        nextStrong_ = rhs.nextStrong_;
+        rhs_ = rhs.rhs_;
+        savedGap_ = rhs.savedGap_;
+        bestCutoff_ = rhs.bestCutoff_;
+        timeLimit_ = rhs.timeLimit_;
+        startTime_ = rhs.startTime_;
+        nodeLimit_ = rhs.nodeLimit_;
+        startNode_ = rhs.startNode_;
+        searchType_ = rhs.searchType_;
+        refine_ = rhs.refine_;
+        delete [] originalLower_;
+        delete [] originalUpper_;
+        if (rhs.originalLower_) {
+            int numberIntegers = model_->numberIntegers();
+            originalLower_ = new double [numberIntegers];
+            memcpy(originalLower_, rhs.originalLower_, numberIntegers*sizeof(double));
+            originalUpper_ = new double [numberIntegers];
+            memcpy(originalUpper_, rhs.originalUpper_, numberIntegers*sizeof(double));
+        } else {
+            originalLower_ = NULL;
+            originalUpper_ = NULL;
+        }
+        delete [] bestSolution_;
+        if (rhs.bestSolution_) {
+            int numberColumns = model_->getNumCols();
+            bestSolution_ = new double [numberColumns];
+            memcpy(bestSolution_, rhs.bestSolution_, numberColumns*sizeof(double));
+        } else {
+            bestSolution_ = NULL;
+        }
+        delete [] savedSolution_;
+        if (rhs.savedSolution_) {
+            int numberColumns = model_->getNumCols();
+            savedSolution_ = new double [numberColumns];
+            memcpy(savedSolution_, rhs.savedSolution_, numberColumns*sizeof(double));
+        } else {
+            savedSolution_ = NULL;
+        }
+    }
+    return *this;
+}
+// Clone
+CbcTree *
+CbcTreeLocal::clone() const
+{
+    return new CbcTreeLocal(*this);
+}
+// Pass in solution (so can be used after heuristic)
+void
+CbcTreeLocal::passInSolution(const double * solution, double solutionValue)
+{
+    int numberColumns = model_->getNumCols();
+    delete [] savedSolution_;
+    savedSolution_ = new double [numberColumns];
+    memcpy(savedSolution_, solution, numberColumns*sizeof(double));
+    rhs_ = range_;
+    // Check feasible
+    int goodSolution = createCut(solution, cut_);
+    if (goodSolution >= 0) {
+        bestCutoff_ = CoinMin(solutionValue, model_->getCutoff());
+    } else {
+        model_ = NULL;
+    }
+}
+// Return the top node of the heap
+CbcNode *
+CbcTreeLocal::top() const
+{
+#ifdef CBC_DEBUG
+    int smallest = 9999999;
+    int largest = -1;
+    double smallestD = 1.0e30;
+    double largestD = -1.0e30;
+    int n = nodes_.size();
+    for (int i = 0; i < n; i++) {
+        int nn = nodes_[i]->nodeInfo()->nodeNumber();
+        double dd = nodes_[i]->objectiveValue();
+        largest = CoinMax(largest, nn);
+        smallest = CoinMin(smallest, nn);
+        largestD = CoinMax(largestD, dd);
+        smallestD = CoinMin(smallestD, dd);
+    }
+    if (model_->messageHandler()->logLevel() > 1) {
+        printf("smallest %d, largest %d, top %d\n", smallest, largest,
+               nodes_.front()->nodeInfo()->nodeNumber());
+        printf("smallestD %g, largestD %g, top %g\n", smallestD, largestD, nodes_.front()->objectiveValue());
+    }
+#endif
+    return nodes_.front();
+}
+
+// Add a node to the heap
+void
+CbcTreeLocal::push(CbcNode * x)
+{
+    if (typeCuts_ >= 0 && !nodes_.size() && searchType_ < 0) {
+        startNode_ = model_->getNodeCount();
+        // save copy of node
+        localNode_ = new CbcNode(*x);
+
+        if (cut_.row().getNumElements()) {
+            // Add to global cuts
+            // we came in with solution
+            model_->makeGlobalCut(cut_);
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("initial cut - rhs %g %g\n",
+                       cut_.lb(), cut_.ub());
+            searchType_ = 1;
+        } else {
+            // stop on first solution
+            searchType_ = 0;
+        }
+        startTime_ = static_cast<int> (CoinCpuTime());
+        saveNumberSolutions_ = model_->getSolutionCount();
+    }
+    nodes_.push_back(x);
+#ifdef CBC_DEBUG
+    if (model_->messageHandler()->logLevel() > 0)
+        printf("pushing node onto heap %d %x %x\n",
+               x->nodeInfo()->nodeNumber(), x, x->nodeInfo());
+#endif
+    std::push_heap(nodes_.begin(), nodes_.end(), comparison_);
+}
+
+// Remove the top node from the heap
+void
+CbcTreeLocal::pop()
+{
+    std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+    nodes_.pop_back();
+}
+// Test if empty - does work if so
+bool
+CbcTreeLocal::empty()
+{
+    if (typeCuts_ < 0)
+        return !nodes_.size();
+    /* state -
+       0 iterating
+       1 subtree finished optimal solution for subtree found
+       2 subtree finished and no solution found
+       3 subtree exiting and solution found
+       4 subtree exiting and no solution found
+    */
+    int state = 0;
+    assert (searchType_ != 2);
+    if (searchType_) {
+        if (CoinCpuTime() - startTime_ > timeLimit_ || model_->getNodeCount() - startNode_ >= nodeLimit_) {
+            state = 4;
+        }
+    } else {
+        if (model_->getSolutionCount() > saveNumberSolutions_) {
+            state = 4;
+        }
+    }
+    if (!nodes_.size())
+        state = 2;
+    if (!state) {
+        return false;
+    }
+    // Finished this phase
+    int numberColumns = model_->getNumCols();
+    if (model_->getSolutionCount() > saveNumberSolutions_) {
+        if (model_->getCutoff() < bestCutoff_) {
+            // Save solution
+            if (!bestSolution_)
+                bestSolution_ = new double [numberColumns];
+            memcpy(bestSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+            bestCutoff_ = model_->getCutoff();
+        }
+        state--;
+    }
+    // get rid of all nodes (safe even if already done)
+    double bestPossibleObjective;
+    cleanTree(model_, -COIN_DBL_MAX, bestPossibleObjective);
+
+    double increment = model_->getDblParam(CbcModel::CbcCutoffIncrement) ;
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("local state %d after %d nodes and %d seconds, new solution %g, best solution %g, k was %g\n",
+               state,
+               model_->getNodeCount() - startNode_,
+               static_cast<int> (CoinCpuTime()) - startTime_,
+               model_->getCutoff() + increment, bestCutoff_ + increment, rhs_);
+    saveNumberSolutions_ = model_->getSolutionCount();
+    bool finished = false;
+    bool lastTry = false;
+    switch (state) {
+    case 1:
+        // solution found and subtree exhausted
+        if (rhs_ > 1.0e30) {
+            finished = true;
+        } else {
+            // find global cut and reverse
+            reverseCut(1);
+            searchType_ = 1; // first false
+            rhs_ = range_; // reset range
+            nextStrong_ = false;
+
+            // save best solution in this subtree
+            memcpy(savedSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+        }
+        break;
+    case 2:
+        // solution not found and subtree exhausted
+        if (rhs_ > 1.0e30) {
+            finished = true;
+        } else {
+            // find global cut and reverse
+            reverseCut(2);
+            searchType_ = 1; // first false
+            if (diversification_ < maxDiversification_) {
+                if (nextStrong_) {
+                    diversification_++;
+                    // cut is valid so don't model_->setCutoff(1.0e50);
+                    searchType_ = 0;
+                }
+                nextStrong_ = true;
+                rhs_ += range_ / 2;
+            } else {
+                // This will be last try (may hit max time)
+                lastTry = true;
+                if (!maxDiversification_)
+                    typeCuts_ = -1; // make sure can't start again
+                model_->setCutoff(bestCutoff_);
+                if (model_->messageHandler()->logLevel() > 1)
+                    printf("Exiting local search with current set of cuts\n");
+                rhs_ = 1.0e100;
+                // Can now stop on gap
+                model_->setDblParam(CbcModel::CbcAllowableGap, savedGap_);
+            }
+        }
+        break;
+    case 3:
+        // solution found and subtree not exhausted
+        if (rhs_ < 1.0e30) {
+            if (searchType_) {
+                if (!typeCuts_ && refine_ && searchType_ == 1) {
+                    // We need to check we have best solution given these 0-1 values
+                    OsiSolverInterface * subSolver = model_->continuousSolver()->clone();
+                    CbcModel * subModel = model_->subTreeModel(subSolver);
+                    CbcTree normalTree;
+                    subModel->passInTreeHandler(normalTree);
+                    int numberIntegers = model_->numberIntegers();
+                    const int * integerVariable = model_->integerVariable();
+                    const double * solution = model_->bestSolution();
+                    int i;
+                    int numberColumns = model_->getNumCols();
+                    for (i = 0; i < numberIntegers; i++) {
+                        int iColumn = integerVariable[i];
+                        double value = floor(solution[iColumn] + 0.5);
+                        if (!typeCuts_ && originalUpper_[i] - originalLower_[i] > 1.0)
+                            continue; // skip as not 0-1
+                        if (originalLower_[i] == originalUpper_[i])
+                            continue;
+                        subSolver->setColLower(iColumn, value);
+                        subSolver->setColUpper(iColumn, value);
+                    }
+                    subSolver->initialSolve();
+                    // We can copy cutoff
+                    // But adjust
+                    subModel->setCutoff(model_->getCutoff() + model_->getDblParam(CbcModel::CbcCutoffIncrement) + 1.0e-6);
+                    subModel->setSolutionCount(0);
+                    assert (subModel->isProvenOptimal());
+                    if (!subModel->typePresolve()) {
+                        subModel->branchAndBound();
+                        if (subModel->status()) {
+                            model_->incrementSubTreeStopped();
+                        }
+                        //printf("%g %g %g %g\n",subModel->getCutoff(),model_->getCutoff(),
+                        //   subModel->getMinimizationObjValue(),model_->getMinimizationObjValue());
+                        double newCutoff = subModel->getMinimizationObjValue() -
+                                           subModel->getDblParam(CbcModel::CbcCutoffIncrement) ;
+                        if (subModel->getSolutionCount()) {
+                            if (!subModel->status())
+                                assert (subModel->isProvenOptimal());
+                            memcpy(model_->bestSolution(), subModel->bestSolution(),
+                                   numberColumns*sizeof(double));
+                            model_->setCutoff(newCutoff);
+                        }
+                    } else if (subModel->typePresolve() == 1) {
+                        CbcModel * model2 = subModel->integerPresolve(true);
+                        if (model2) {
+                            // Do complete search
+                            model2->branchAndBound();
+                            // get back solution
+                            subModel->originalModel(model2, false);
+                            if (model2->status()) {
+                                model_->incrementSubTreeStopped();
+                            }
+                            double newCutoff = model2->getMinimizationObjValue() -
+                                               model2->getDblParam(CbcModel::CbcCutoffIncrement) ;
+                            if (model2->getSolutionCount()) {
+                                if (!model2->status())
+                                    assert (model2->isProvenOptimal());
+                                memcpy(model_->bestSolution(), subModel->bestSolution(),
+                                       numberColumns*sizeof(double));
+                                model_->setCutoff(newCutoff);
+                            }
+                            delete model2;
+                        } else {
+                            // infeasible - could just be - due to cutoff
+                        }
+                    } else {
+                        // too dangerous at present
+                        assert (subModel->typePresolve() != 2);
+                    }
+                    if (model_->getCutoff() < bestCutoff_) {
+                        // Save solution
+                        if (!bestSolution_)
+                            bestSolution_ = new double [numberColumns];
+                        memcpy(bestSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+                        bestCutoff_ = model_->getCutoff();
+                    }
+                    delete subModel;
+                }
+                // we have done search to make sure best general solution
+                searchType_ = 1;
+                // Reverse cut weakly
+                reverseCut(3, rhs_);
+            } else {
+                searchType_ = 1;
+                // delete last cut
+                deleteCut(cut_);
+            }
+        } else {
+            searchType_ = 1;
+        }
+        // save best solution in this subtree
+        memcpy(savedSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+        nextStrong_ = false;
+        rhs_ = range_;
+        break;
+    case 4:
+        // solution not found and subtree not exhausted
+        if (maxDiversification_) {
+            if (nextStrong_) {
+                // Reverse cut weakly
+                reverseCut(4, rhs_);
+                model_->setCutoff(1.0e50);
+                diversification_++;
+                searchType_ = 0;
+            } else {
+                // delete last cut
+                deleteCut(cut_);
+                searchType_ = 1;
+            }
+            nextStrong_ = true;
+            rhs_ += range_ / 2;
+        } else {
+            // special case when using as heuristic
+            // Reverse cut weakly if lb -infinity
+            reverseCut(4, rhs_);
+            // This will be last try (may hit max time0
+            lastTry = true;
+            model_->setCutoff(bestCutoff_);
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("Exiting local search with current set of cuts\n");
+            rhs_ = 1.0e100;
+            // Can now stop on gap
+            model_->setDblParam(CbcModel::CbcAllowableGap, savedGap_);
+            typeCuts_ = -1;
+        }
+        break;
+    }
+    if (rhs_ < 1.0e30 || lastTry) {
+        int goodSolution = createCut(savedSolution_, cut_);
+        if (goodSolution >= 0) {
+            // Add to global cuts
+	    model_->makeGlobalCut(cut_);
+            CbcRowCuts * global = model_->globalCuts();
+            int n = global->sizeRowCuts();
+            OsiRowCut * rowCut = global->rowCutPtr(n - 1);
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("inserting cut - now %d cuts, rhs %g %g, cutspace %g, diversification %d\n",
+                       n, rowCut->lb(), rowCut->ub(), rhs_, diversification_);
+            const OsiRowCutDebugger *debugger = model_->solver()->getRowCutDebuggerAlways() ;
+            if (debugger) {
+                if (debugger->invalidCut(*rowCut))
+                    printf("ZZZZTree Global cut - cuts off optimal solution!\n");
+            }
+            for (int i = 0; i < n; i++) {
+                rowCut = global->rowCutPtr(i);
+                if (model_->messageHandler()->logLevel() > 0)
+                    printf("%d - rhs %g %g\n",
+                           i, rowCut->lb(), rowCut->ub());
+            }
+        }
+        // put back node
+        startTime_ = static_cast<int> (CoinCpuTime());
+        startNode_ = model_->getNodeCount();
+        if (localNode_) {
+            // save copy of node
+            CbcNode * localNode2 = new CbcNode(*localNode_);
+            // But localNode2 now owns cuts so swap
+            //printf("pushing local node2 onto heap %d %x %x\n",localNode_->nodeNumber(),
+            //   localNode_,localNode_->nodeInfo());
+            nodes_.push_back(localNode_);
+            localNode_ = localNode2;
+            std::make_heap(nodes_.begin(), nodes_.end(), comparison_);
+        }
+    }
+    return finished;
+}
+// We may have got an intelligent tree so give it one more chance
+void
+CbcTreeLocal::endSearch()
+{
+    if (typeCuts_ >= 0) {
+        // copy best solution to model
+        int numberColumns = model_->getNumCols();
+        if (bestSolution_ && bestCutoff_ < model_->getCutoff()) {
+            memcpy(model_->bestSolution(), bestSolution_, numberColumns*sizeof(double));
+            model_->setCutoff(bestCutoff_);
+            // recompute objective value
+            const double * objCoef = model_->getObjCoefficients();
+            double objOffset = 0.0;
+            model_->continuousSolver()->getDblParam(OsiObjOffset, objOffset);
+
+            // Compute dot product of objCoef and colSol and then adjust by offset
+            double objValue = -objOffset;
+            for ( int i = 0 ; i < numberColumns ; i++ )
+                objValue += objCoef[i] * bestSolution_[i];
+            model_->setMinimizationObjValue(objValue);
+        }
+        // Can now stop on gap
+        model_->setDblParam(CbcModel::CbcAllowableGap, savedGap_);
+    }
+}
+// Create cut
+int
+CbcTreeLocal::createCut(const double * solution, OsiRowCut & rowCut)
+{
+    if (rhs_ > 1.0e20)
+        return -1;
+    OsiSolverInterface * solver = model_->solver();
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    //const double * solution = solver->getColSolution();
+    //const double * objective = solver->getObjCoefficients();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+    // relax
+    primalTolerance *= 1000.0;
+
+    int numberRows = model_->getNumRows();
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    int i;
+
+    // Check feasible
+
+    double * rowActivity = new double[numberRows];
+    memset(rowActivity, 0, numberRows*sizeof(double));
+    solver->getMatrixByCol()->times(solution, rowActivity) ;
+    int goodSolution = 0;
+    // check was feasible
+    for (i = 0; i < numberRows; i++) {
+        if (rowActivity[i] < rowLower[i] - primalTolerance) {
+            goodSolution = -1;
+        } else if (rowActivity[i] > rowUpper[i] + primalTolerance) {
+            goodSolution = -1;
+        }
+    }
+    delete [] rowActivity;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = solution[iColumn];
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            goodSolution = -1;
+        }
+    }
+    // zap cut
+    if (goodSolution == 0) {
+        // Create cut and get total gap
+        CoinPackedVector cut;
+        double rhs = rhs_;
+        double maxValue = 0.0;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            double value = floor(solution[iColumn] + 0.5);
+            /*
+              typeCuts_ == 0 restricts to binary, 1 allows general integer. But we're
+              still restricted to being up against a bound. Consider: the notion is that
+              the cut restricts us to a k-neighbourhood. For binary variables, this
+              amounts to k variables which change value. For general integer, we could
+              end up with a single variable sucking up all of k (hence mu --- the
+              variable must swing to its other bound to look like a movement of 1).  For
+              variables in the middle of a range, we're talking about fabs(sol<j> - x<j>).
+            */
+            if (!typeCuts_ && originalUpper_[i] - originalLower_[i] > 1.0)
+                continue; // skip as not 0-1
+            if (originalLower_[i] == originalUpper_[i])
+                continue;
+            double mu = 1.0 / (originalUpper_[i] - originalLower_[i]);
+            if (value == originalLower_[i]) {
+                rhs += mu * originalLower_[i];
+                cut.insert(iColumn, 1.0);
+                maxValue += originalUpper_[i];
+            } else if (value == originalUpper_[i]) {
+                rhs -= mu * originalUpper_[i];
+                cut.insert(iColumn, -1.0);
+                maxValue += originalLower_[i];
+            }
+        }
+        if (maxValue < rhs - primalTolerance) {
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("slack cut\n");
+            goodSolution = 1;
+        }
+        rowCut.setRow(cut);
+        rowCut.setLb(-COIN_DBL_MAX);
+        rowCut.setUb(rhs);
+        rowCut.setGloballyValid();
+        if (model_->messageHandler()->logLevel() > 1)
+            printf("Cut size: %i Cut rhs: %g\n", cut.getNumElements(), rhs);
+#ifdef CBC_DEBUG
+        if (model_->messageHandler()->logLevel() > 0) {
+            int k;
+            for (k = 0; k < cut.getNumElements(); k++) {
+                printf("%i    %g ", cut.getIndices()[k], cut.getElements()[k]);
+                if ((k + 1) % 5 == 0)
+                    printf("\n");
+            }
+            if (k % 5 != 0)
+                printf("\n");
+        }
+#endif
+        return goodSolution;
+    } else {
+        if (model_->messageHandler()->logLevel() > 1)
+            printf("Not a good solution\n");
+        return -1;
+    }
+}
+// Other side of last cut branch
+void
+CbcTreeLocal::reverseCut(int state, double bias)
+{
+    // find global cut
+    CbcRowCuts * global = model_->globalCuts();
+    int n = global->sizeRowCuts();
+    int i;
+    OsiRowCut * rowCut = NULL;
+    for ( i = 0; i < n; i++) {
+        rowCut = global->rowCutPtr(i);
+        if (cut_ == *rowCut) {
+            break;
+        }
+    }
+    if (!rowCut) {
+        // must have got here in odd way e.g. strong branching
+        return;
+    }
+    if (rowCut->lb() > -1.0e10)
+        return;
+    // get smallest element
+    double smallest = COIN_DBL_MAX;
+    CoinPackedVector row = cut_.row();
+    for (int k = 0; k < row.getNumElements(); k++)
+        smallest = CoinMin(smallest, fabs(row.getElements()[k]));
+    if (!typeCuts_ && !refine_) {
+        // Reverse cut very very weakly
+        if (state > 2)
+            smallest = 0.0;
+    }
+    // replace by other way
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("reverseCut - changing cut %d out of %d, old rhs %g %g ",
+               i, n, rowCut->lb(), rowCut->ub());
+    rowCut->setLb(rowCut->ub() + smallest - bias);
+    rowCut->setUb(COIN_DBL_MAX);
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("new rhs %g %g, bias %g smallest %g ",
+               rowCut->lb(), rowCut->ub(), bias, smallest);
+    const OsiRowCutDebugger *debugger = model_->solver()->getRowCutDebuggerAlways() ;
+    if (debugger) {
+        if (debugger->invalidCut(*rowCut))
+            printf("ZZZZTree Global cut - cuts off optimal solution!\n");
+    }
+}
+// Delete last cut branch
+void
+CbcTreeLocal::deleteCut(OsiRowCut & cut)
+{
+    // find global cut
+    CbcRowCuts * global = model_->globalCuts();
+    int n = global->sizeRowCuts();
+    int i;
+    OsiRowCut * rowCut = NULL;
+    for ( i = 0; i < n; i++) {
+        rowCut = global->rowCutPtr(i);
+        if (cut == *rowCut) {
+            break;
+        }
+    }
+    assert (i < n);
+    // delete last cut
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("deleteCut - deleting cut %d out of %d, rhs %g %g\n",
+               i, n, rowCut->lb(), rowCut->ub());
+    global->eraseRowCut(i);
+}
+// Create C++ lines to get to current state
+void
+CbcTreeLocal::generateCpp( FILE * fp)
+{
+    CbcTreeLocal other;
+    fprintf(fp, "0#include \"CbcTreeLocal.hpp\"\n");
+    fprintf(fp, "5  CbcTreeLocal localTree(cbcModel,NULL);\n");
+    if (range_ != other.range_)
+        fprintf(fp, "5  localTree.setRange(%d);\n", range_);
+    if (typeCuts_ != other.typeCuts_)
+        fprintf(fp, "5  localTree.setTypeCuts(%d);\n", typeCuts_);
+    if (maxDiversification_ != other.maxDiversification_)
+        fprintf(fp, "5  localTree.setMaxDiversification(%d);\n", maxDiversification_);
+    if (timeLimit_ != other.timeLimit_)
+        fprintf(fp, "5  localTree.setTimeLimit(%d);\n", timeLimit_);
+    if (nodeLimit_ != other.nodeLimit_)
+        fprintf(fp, "5  localTree.setNodeLimit(%d);\n", nodeLimit_);
+    if (refine_ != other.refine_)
+        fprintf(fp, "5  localTree.setRefine(%s);\n", refine_ ? "true" : "false");
+    fprintf(fp, "5  cbcModel->passInTreeHandler(localTree);\n");
+}
+
+
+CbcTreeVariable::CbcTreeVariable()
+        : localNode_(NULL),
+        bestSolution_(NULL),
+        savedSolution_(NULL),
+        saveNumberSolutions_(0),
+        model_(NULL),
+        originalLower_(NULL),
+        originalUpper_(NULL),
+        range_(0),
+        typeCuts_(-1),
+        maxDiversification_(0),
+        diversification_(0),
+        nextStrong_(false),
+        rhs_(0.0),
+        savedGap_(0.0),
+        bestCutoff_(0.0),
+        timeLimit_(0),
+        startTime_(0),
+        nodeLimit_(0),
+        startNode_(-1),
+        searchType_(-1),
+        refine_(false)
+{
+
+}
+/* Constructor with solution.
+   range is upper bound on difference from given solution.
+   maxDiversification is maximum number of diversifications to try
+   timeLimit is seconds in subTree
+   nodeLimit is nodes in subTree
+*/
+CbcTreeVariable::CbcTreeVariable(CbcModel * model, const double * solution ,
+                                 int range, int typeCuts, int maxDiversification,
+                                 int timeLimit, int nodeLimit, bool refine)
+        : localNode_(NULL),
+        bestSolution_(NULL),
+        savedSolution_(NULL),
+        saveNumberSolutions_(0),
+        model_(model),
+        originalLower_(NULL),
+        originalUpper_(NULL),
+        range_(range),
+        typeCuts_(typeCuts),
+        maxDiversification_(maxDiversification),
+        diversification_(0),
+        nextStrong_(false),
+        rhs_(0.0),
+        savedGap_(0.0),
+        bestCutoff_(0.0),
+        timeLimit_(timeLimit),
+        startTime_(0),
+        nodeLimit_(nodeLimit),
+        startNode_(-1),
+        searchType_(-1),
+        refine_(refine)
+{
+
+    OsiSolverInterface * solver = model_->solver();
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    //const double * solution = solver->getColSolution();
+    //const double * objective = solver->getObjCoefficients();
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+
+    // Get increment
+    model_->analyzeObjective();
+
+    {
+        // needed to sync cutoffs
+        double value ;
+        solver->getDblParam(OsiDualObjectiveLimit, value) ;
+        model_->setCutoff(value * solver->getObjSense());
+    }
+    bestCutoff_ = model_->getCutoff();
+    // save current gap
+    savedGap_ = model_->getDblParam(CbcModel::CbcAllowableGap);
+
+    // make sure integers found
+    model_->findIntegers(false);
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    int i;
+    double direction = solver->getObjSense();
+    double newSolutionValue = 1.0e50;
+    if (solution) {
+        // copy solution
+        solver->setColSolution(solution);
+        newSolutionValue = direction * solver->getObjValue();
+    }
+    originalLower_ = new double [numberIntegers];
+    originalUpper_ = new double [numberIntegers];
+    bool all01 = true;
+    int number01 = 0;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        originalLower_[i] = lower[iColumn];
+        originalUpper_[i] = upper[iColumn];
+        if (upper[iColumn] - lower[iColumn] > 1.5)
+            all01 = false;
+        else if (upper[iColumn] - lower[iColumn] == 1.0)
+            number01++;
+    }
+    if (all01 && !typeCuts_)
+        typeCuts_ = 1; // may as well so we don't have to deal with refine
+    if (!number01 && !typeCuts_) {
+        if (model_->messageHandler()->logLevel() > 1)
+            printf("** No 0-1 variables and local search only on 0-1 - switching off\n");
+        typeCuts_ = -1;
+    } else {
+        if (model_->messageHandler()->logLevel() > 1) {
+            std::string type;
+            if (all01) {
+                printf("%d 0-1 variables normal local  cuts\n",
+                       number01);
+            } else if (typeCuts_) {
+                printf("%d 0-1 variables, %d other - general integer local cuts\n",
+                       number01, numberIntegers - number01);
+            } else {
+                printf("%d 0-1 variables, %d other - local cuts but just on 0-1 variables\n",
+                       number01, numberIntegers - number01);
+            }
+            printf("maximum diversifications %d, initial cutspace %d, max time %d seconds, max nodes %d\n",
+                   maxDiversification_, range_, timeLimit_, nodeLimit_);
+        }
+    }
+    int numberColumns = model_->getNumCols();
+    savedSolution_ = new double [numberColumns];
+    memset(savedSolution_, 0, numberColumns*sizeof(double));
+    if (solution) {
+        rhs_ = range_;
+        // Check feasible
+        int goodSolution = createCut(solution, cut_);
+        if (goodSolution >= 0) {
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                double value = floor(solution[iColumn] + 0.5);
+                // fix so setBestSolution will work
+                solver->setColLower(iColumn, value);
+                solver->setColUpper(iColumn, value);
+            }
+            model_->reserveCurrentSolution();
+            // Create cut and get total gap
+            if (newSolutionValue < bestCutoff_) {
+                model_->setBestSolution(CBC_ROUNDING, newSolutionValue, solution);
+                bestCutoff_ = model_->getCutoff();
+                // save as best solution
+                memcpy(savedSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+            }
+            for (i = 0; i < numberIntegers; i++) {
+                int iColumn = integerVariable[i];
+                // restore bounds
+                solver->setColLower(iColumn, originalLower_[i]);
+                solver->setColUpper(iColumn, originalUpper_[i]);
+            }
+            // make sure can't stop on gap
+            model_->setDblParam(CbcModel::CbcAllowableGap, -1.0e50);
+        } else {
+            model_ = NULL;
+        }
+    } else {
+        // no solution
+        rhs_ = 1.0e50;
+        // make sure can't stop on gap
+        model_->setDblParam(CbcModel::CbcAllowableGap, -1.0e50);
+    }
+}
+CbcTreeVariable::~CbcTreeVariable()
+{
+    delete [] originalLower_;
+    delete [] originalUpper_;
+    delete [] bestSolution_;
+    delete [] savedSolution_;
+    delete localNode_;
+}
+// Copy constructor
+CbcTreeVariable::CbcTreeVariable ( const CbcTreeVariable & rhs)
+        : CbcTree(rhs),
+        saveNumberSolutions_(rhs.saveNumberSolutions_),
+        model_(rhs.model_),
+        range_(rhs.range_),
+        typeCuts_(rhs.typeCuts_),
+        maxDiversification_(rhs.maxDiversification_),
+        diversification_(rhs.diversification_),
+        nextStrong_(rhs.nextStrong_),
+        rhs_(rhs.rhs_),
+        savedGap_(rhs.savedGap_),
+        bestCutoff_(rhs.bestCutoff_),
+        timeLimit_(rhs.timeLimit_),
+        startTime_(rhs.startTime_),
+        nodeLimit_(rhs.nodeLimit_),
+        startNode_(rhs.startNode_),
+        searchType_(rhs.searchType_),
+        refine_(rhs.refine_)
+{
+    cut_ = rhs.cut_;
+    fixedCut_ = rhs.fixedCut_;
+    if (rhs.localNode_)
+        localNode_ = new CbcNode(*rhs.localNode_);
+    else
+        localNode_ = NULL;
+    if (rhs.originalLower_) {
+        int numberIntegers = model_->numberIntegers();
+        originalLower_ = new double [numberIntegers];
+        memcpy(originalLower_, rhs.originalLower_, numberIntegers*sizeof(double));
+        originalUpper_ = new double [numberIntegers];
+        memcpy(originalUpper_, rhs.originalUpper_, numberIntegers*sizeof(double));
+    } else {
+        originalLower_ = NULL;
+        originalUpper_ = NULL;
+    }
+    if (rhs.bestSolution_) {
+        int numberColumns = model_->getNumCols();
+        bestSolution_ = new double [numberColumns];
+        memcpy(bestSolution_, rhs.bestSolution_, numberColumns*sizeof(double));
+    } else {
+        bestSolution_ = NULL;
+    }
+    if (rhs.savedSolution_) {
+        int numberColumns = model_->getNumCols();
+        savedSolution_ = new double [numberColumns];
+        memcpy(savedSolution_, rhs.savedSolution_, numberColumns*sizeof(double));
+    } else {
+        savedSolution_ = NULL;
+    }
+}
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+CbcTreeVariable &
+CbcTreeVariable::operator=(const CbcTreeVariable & rhs)
+{
+    if (this != &rhs) {
+        CbcTree::operator=(rhs);
+        saveNumberSolutions_ = rhs.saveNumberSolutions_;
+        cut_ = rhs.cut_;
+        fixedCut_ = rhs.fixedCut_;
+        delete localNode_;
+        if (rhs.localNode_)
+            localNode_ = new CbcNode(*rhs.localNode_);
+        else
+            localNode_ = NULL;
+        model_ = rhs.model_;
+        range_ = rhs.range_;
+        typeCuts_ = rhs.typeCuts_;
+        maxDiversification_ = rhs.maxDiversification_;
+        diversification_ = rhs.diversification_;
+        nextStrong_ = rhs.nextStrong_;
+        rhs_ = rhs.rhs_;
+        savedGap_ = rhs.savedGap_;
+        bestCutoff_ = rhs.bestCutoff_;
+        timeLimit_ = rhs.timeLimit_;
+        startTime_ = rhs.startTime_;
+        nodeLimit_ = rhs.nodeLimit_;
+        startNode_ = rhs.startNode_;
+        searchType_ = rhs.searchType_;
+        refine_ = rhs.refine_;
+        delete [] originalLower_;
+        delete [] originalUpper_;
+        if (rhs.originalLower_) {
+            int numberIntegers = model_->numberIntegers();
+            originalLower_ = new double [numberIntegers];
+            memcpy(originalLower_, rhs.originalLower_, numberIntegers*sizeof(double));
+            originalUpper_ = new double [numberIntegers];
+            memcpy(originalUpper_, rhs.originalUpper_, numberIntegers*sizeof(double));
+        } else {
+            originalLower_ = NULL;
+            originalUpper_ = NULL;
+        }
+        delete [] bestSolution_;
+        if (rhs.bestSolution_) {
+            int numberColumns = model_->getNumCols();
+            bestSolution_ = new double [numberColumns];
+            memcpy(bestSolution_, rhs.bestSolution_, numberColumns*sizeof(double));
+        } else {
+            bestSolution_ = NULL;
+        }
+        delete [] savedSolution_;
+        if (rhs.savedSolution_) {
+            int numberColumns = model_->getNumCols();
+            savedSolution_ = new double [numberColumns];
+            memcpy(savedSolution_, rhs.savedSolution_, numberColumns*sizeof(double));
+        } else {
+            savedSolution_ = NULL;
+        }
+    }
+    return *this;
+}
+// Clone
+CbcTree *
+CbcTreeVariable::clone() const
+{
+    return new CbcTreeVariable(*this);
+}
+// Pass in solution (so can be used after heuristic)
+void
+CbcTreeVariable::passInSolution(const double * solution, double solutionValue)
+{
+    int numberColumns = model_->getNumCols();
+    delete [] savedSolution_;
+    savedSolution_ = new double [numberColumns];
+    memcpy(savedSolution_, solution, numberColumns*sizeof(double));
+    rhs_ = range_;
+    // Check feasible
+    int goodSolution = createCut(solution, cut_);
+    if (goodSolution >= 0) {
+        bestCutoff_ = CoinMin(solutionValue, model_->getCutoff());
+    } else {
+        model_ = NULL;
+    }
+}
+// Return the top node of the heap
+CbcNode *
+CbcTreeVariable::top() const
+{
+#ifdef CBC_DEBUG
+    int smallest = 9999999;
+    int largest = -1;
+    double smallestD = 1.0e30;
+    double largestD = -1.0e30;
+    int n = nodes_.size();
+    for (int i = 0; i < n; i++) {
+        int nn = nodes_[i]->nodeInfo()->nodeNumber();
+        double dd = nodes_[i]->objectiveValue();
+        largest = CoinMax(largest, nn);
+        smallest = CoinMin(smallest, nn);
+        largestD = CoinMax(largestD, dd);
+        smallestD = CoinMin(smallestD, dd);
+    }
+    if (model_->messageHandler()->logLevel() > 1) {
+        printf("smallest %d, largest %d, top %d\n", smallest, largest,
+               nodes_.front()->nodeInfo()->nodeNumber());
+        printf("smallestD %g, largestD %g, top %g\n", smallestD, largestD, nodes_.front()->objectiveValue());
+    }
+#endif
+    return nodes_.front();
+}
+
+// Add a node to the heap
+void
+CbcTreeVariable::push(CbcNode * x)
+{
+    if (typeCuts_ >= 0 && !nodes_.size() && searchType_ < 0) {
+        startNode_ = model_->getNodeCount();
+        // save copy of node
+        localNode_ = new CbcNode(*x);
+
+        if (cut_.row().getNumElements()) {
+            // Add to global cuts
+            // we came in with solution
+            model_->makeGlobalCut(cut_);
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("initial cut - rhs %g %g\n",
+                       cut_.lb(), cut_.ub());
+            searchType_ = 1;
+        } else {
+            // stop on first solution
+            searchType_ = 0;
+        }
+        startTime_ = static_cast<int> (CoinCpuTime());
+        saveNumberSolutions_ = model_->getSolutionCount();
+    }
+    nodes_.push_back(x);
+#ifdef CBC_DEBUG
+    if (model_->messageHandler()->logLevel() > 0)
+        printf("pushing node onto heap %d %x %x\n",
+               x->nodeInfo()->nodeNumber(), x, x->nodeInfo());
+#endif
+    std::push_heap(nodes_.begin(), nodes_.end(), comparison_);
+}
+
+// Remove the top node from the heap
+void
+CbcTreeVariable::pop()
+{
+    std::pop_heap(nodes_.begin(), nodes_.end(), comparison_);
+    nodes_.pop_back();
+}
+// Test if empty - does work if so
+bool
+CbcTreeVariable::empty()
+{
+    if (typeCuts_ < 0)
+        return !nodes_.size();
+    /* state -
+       0 iterating
+       1 subtree finished optimal solution for subtree found
+       2 subtree finished and no solution found
+       3 subtree exiting and solution found
+       4 subtree exiting and no solution found
+    */
+    int state = 0;
+    assert (searchType_ != 2);
+    if (searchType_) {
+        if (CoinCpuTime() - startTime_ > timeLimit_ || model_->getNodeCount() - startNode_ >= nodeLimit_) {
+            state = 4;
+        }
+    } else {
+        if (model_->getSolutionCount() > saveNumberSolutions_) {
+            state = 4;
+        }
+    }
+    if (!nodes_.size())
+        state = 2;
+    if (!state) {
+        return false;
+    }
+    // Finished this phase
+    int numberColumns = model_->getNumCols();
+    if (model_->getSolutionCount() > saveNumberSolutions_) {
+        if (model_->getCutoff() < bestCutoff_) {
+            // Save solution
+            if (!bestSolution_)
+                bestSolution_ = new double [numberColumns];
+            memcpy(bestSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+            bestCutoff_ = model_->getCutoff();
+        }
+        state--;
+    }
+    // get rid of all nodes (safe even if already done)
+    double bestPossibleObjective;
+    cleanTree(model_, -COIN_DBL_MAX, bestPossibleObjective);
+
+    double increment = model_->getDblParam(CbcModel::CbcCutoffIncrement) ;
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("local state %d after %d nodes and %d seconds, new solution %g, best solution %g, k was %g\n",
+               state,
+               model_->getNodeCount() - startNode_,
+               static_cast<int> (CoinCpuTime()) - startTime_,
+               model_->getCutoff() + increment, bestCutoff_ + increment, rhs_);
+    saveNumberSolutions_ = model_->getSolutionCount();
+    bool finished = false;
+    bool lastTry = false;
+    switch (state) {
+    case 1:
+        // solution found and subtree exhausted
+        if (rhs_ > 1.0e30) {
+            finished = true;
+        } else {
+            // find global cut and reverse
+            reverseCut(1);
+            searchType_ = 1; // first false
+            rhs_ = range_; // reset range
+            nextStrong_ = false;
+
+            // save best solution in this subtree
+            memcpy(savedSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+        }
+        break;
+    case 2:
+        // solution not found and subtree exhausted
+        if (rhs_ > 1.0e30) {
+            finished = true;
+        } else {
+            // find global cut and reverse
+            reverseCut(2);
+            searchType_ = 1; // first false
+            if (diversification_ < maxDiversification_) {
+                if (nextStrong_) {
+                    diversification_++;
+                    // cut is valid so don't model_->setCutoff(1.0e50);
+                    searchType_ = 0;
+                }
+                nextStrong_ = true;
+                rhs_ += range_ / 2;
+            } else {
+                // This will be last try (may hit max time)
+                lastTry = true;
+                if (!maxDiversification_)
+                    typeCuts_ = -1; // make sure can't start again
+                model_->setCutoff(bestCutoff_);
+                if (model_->messageHandler()->logLevel() > 1)
+                    printf("Exiting local search with current set of cuts\n");
+                rhs_ = 1.0e100;
+                // Can now stop on gap
+                model_->setDblParam(CbcModel::CbcAllowableGap, savedGap_);
+            }
+        }
+        break;
+    case 3:
+        // solution found and subtree not exhausted
+        if (rhs_ < 1.0e30) {
+            if (searchType_) {
+                if (!typeCuts_ && refine_ && searchType_ == 1) {
+                    // We need to check we have best solution given these 0-1 values
+                    OsiSolverInterface * subSolver = model_->continuousSolver()->clone();
+                    CbcModel * subModel = model_->subTreeModel(subSolver);
+                    CbcTree normalTree;
+                    subModel->passInTreeHandler(normalTree);
+                    int numberIntegers = model_->numberIntegers();
+                    const int * integerVariable = model_->integerVariable();
+                    const double * solution = model_->bestSolution();
+                    int i;
+                    int numberColumns = model_->getNumCols();
+                    for (i = 0; i < numberIntegers; i++) {
+                        int iColumn = integerVariable[i];
+                        double value = floor(solution[iColumn] + 0.5);
+                        if (!typeCuts_ && originalUpper_[i] - originalLower_[i] > 1.0)
+                            continue; // skip as not 0-1
+                        if (originalLower_[i] == originalUpper_[i])
+                            continue;
+                        subSolver->setColLower(iColumn, value);
+                        subSolver->setColUpper(iColumn, value);
+                    }
+                    subSolver->initialSolve();
+                    // We can copy cutoff
+                    // But adjust
+                    subModel->setCutoff(model_->getCutoff() + model_->getDblParam(CbcModel::CbcCutoffIncrement) + 1.0e-6);
+                    subModel->setSolutionCount(0);
+                    assert (subModel->isProvenOptimal());
+                    if (!subModel->typePresolve()) {
+                        subModel->branchAndBound();
+                        if (subModel->status()) {
+                            model_->incrementSubTreeStopped();
+                        }
+                        //printf("%g %g %g %g\n",subModel->getCutoff(),model_->getCutoff(),
+                        //   subModel->getMinimizationObjValue(),model_->getMinimizationObjValue());
+                        double newCutoff = subModel->getMinimizationObjValue() -
+                                           subModel->getDblParam(CbcModel::CbcCutoffIncrement) ;
+                        if (subModel->getSolutionCount()) {
+                            if (!subModel->status())
+                                assert (subModel->isProvenOptimal());
+                            memcpy(model_->bestSolution(), subModel->bestSolution(),
+                                   numberColumns*sizeof(double));
+                            model_->setCutoff(newCutoff);
+                        }
+                    } else if (subModel->typePresolve() == 1) {
+                        CbcModel * model2 = subModel->integerPresolve(true);
+                        if (model2) {
+                            // Do complete search
+                            model2->branchAndBound();
+                            // get back solution
+                            subModel->originalModel(model2, false);
+                            if (model2->status()) {
+                                model_->incrementSubTreeStopped();
+                            }
+                            double newCutoff = model2->getMinimizationObjValue() -
+                                               model2->getDblParam(CbcModel::CbcCutoffIncrement) ;
+                            if (model2->getSolutionCount()) {
+                                if (!model2->status())
+                                    assert (model2->isProvenOptimal());
+                                memcpy(model_->bestSolution(), subModel->bestSolution(),
+                                       numberColumns*sizeof(double));
+                                model_->setCutoff(newCutoff);
+                            }
+                            delete model2;
+                        } else {
+                            // infeasible - could just be - due to cutoff
+                        }
+                    } else {
+                        // too dangerous at present
+                        assert (subModel->typePresolve() != 2);
+                    }
+                    if (model_->getCutoff() < bestCutoff_) {
+                        // Save solution
+                        if (!bestSolution_)
+                            bestSolution_ = new double [numberColumns];
+                        memcpy(bestSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+                        bestCutoff_ = model_->getCutoff();
+                    }
+                    delete subModel;
+                }
+                // we have done search to make sure best general solution
+                searchType_ = 1;
+                // Reverse cut weakly
+                reverseCut(3, rhs_);
+            } else {
+                searchType_ = 1;
+                // delete last cut
+                deleteCut(cut_);
+            }
+        } else {
+            searchType_ = 1;
+        }
+        // save best solution in this subtree
+        memcpy(savedSolution_, model_->bestSolution(), numberColumns*sizeof(double));
+        nextStrong_ = false;
+        rhs_ = range_;
+        break;
+    case 4:
+        // solution not found and subtree not exhausted
+        if (maxDiversification_) {
+            if (nextStrong_) {
+                // Reverse cut weakly
+                reverseCut(4, rhs_);
+                model_->setCutoff(1.0e50);
+                diversification_++;
+                searchType_ = 0;
+            } else {
+                // delete last cut
+                deleteCut(cut_);
+                searchType_ = 1;
+            }
+            nextStrong_ = true;
+            rhs_ += range_ / 2;
+        } else {
+            // special case when using as heuristic
+            // Reverse cut weakly if lb -infinity
+            reverseCut(4, rhs_);
+            // This will be last try (may hit max time0
+            lastTry = true;
+            model_->setCutoff(bestCutoff_);
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("Exiting local search with current set of cuts\n");
+            rhs_ = 1.0e100;
+            // Can now stop on gap
+            model_->setDblParam(CbcModel::CbcAllowableGap, savedGap_);
+            typeCuts_ = -1;
+        }
+        break;
+    }
+    if (rhs_ < 1.0e30 || lastTry) {
+        int goodSolution = createCut(savedSolution_, cut_);
+        if (goodSolution >= 0) {
+            // Add to global cuts
+            model_->makeGlobalCut(cut_);
+            CbcRowCuts * global = model_->globalCuts();
+            int n = global->sizeRowCuts();
+            OsiRowCut * rowCut = global->rowCutPtr(n - 1);
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("inserting cut - now %d cuts, rhs %g %g, cutspace %g, diversification %d\n",
+                       n, rowCut->lb(), rowCut->ub(), rhs_, diversification_);
+            const OsiRowCutDebugger *debugger = model_->solver()->getRowCutDebuggerAlways() ;
+            if (debugger) {
+                if (debugger->invalidCut(*rowCut))
+                    printf("ZZZZTree Global cut - cuts off optimal solution!\n");
+            }
+            for (int i = 0; i < n; i++) {
+                rowCut = global->rowCutPtr(i);
+                if (model_->messageHandler()->logLevel() > 1)
+                    printf("%d - rhs %g %g\n",
+                           i, rowCut->lb(), rowCut->ub());
+            }
+        }
+        // put back node
+        startTime_ = static_cast<int> (CoinCpuTime());
+        startNode_ = model_->getNodeCount();
+        if (localNode_) {
+            // save copy of node
+            CbcNode * localNode2 = new CbcNode(*localNode_);
+            // But localNode2 now owns cuts so swap
+            //printf("pushing local node2 onto heap %d %x %x\n",localNode_->nodeNumber(),
+            //   localNode_,localNode_->nodeInfo());
+            nodes_.push_back(localNode_);
+            localNode_ = localNode2;
+            std::make_heap(nodes_.begin(), nodes_.end(), comparison_);
+        }
+    }
+    return finished;
+}
+// We may have got an intelligent tree so give it one more chance
+void
+CbcTreeVariable::endSearch()
+{
+    if (typeCuts_ >= 0) {
+        // copy best solution to model
+        int numberColumns = model_->getNumCols();
+        if (bestSolution_ && bestCutoff_ < model_->getCutoff()) {
+            memcpy(model_->bestSolution(), bestSolution_, numberColumns*sizeof(double));
+            model_->setCutoff(bestCutoff_);
+            // recompute objective value
+            const double * objCoef = model_->getObjCoefficients();
+            double objOffset = 0.0;
+            model_->continuousSolver()->getDblParam(OsiObjOffset, objOffset);
+
+            // Compute dot product of objCoef and colSol and then adjust by offset
+            double objValue = -objOffset;
+            for ( int i = 0 ; i < numberColumns ; i++ )
+                objValue += objCoef[i] * bestSolution_[i];
+            model_->setMinimizationObjValue(objValue);
+        }
+        // Can now stop on gap
+        model_->setDblParam(CbcModel::CbcAllowableGap, savedGap_);
+    }
+}
+// Create cut
+int
+CbcTreeVariable::createCut(const double * solution, OsiRowCut & rowCut)
+{
+    if (rhs_ > 1.0e20)
+        return -1;
+    OsiSolverInterface * solver = model_->solver();
+    const double * rowLower = solver->getRowLower();
+    const double * rowUpper = solver->getRowUpper();
+    //const double * solution = solver->getColSolution();
+    //const double * objective = solver->getObjCoefficients();
+    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
+    double primalTolerance;
+    solver->getDblParam(OsiPrimalTolerance, primalTolerance);
+    // relax
+    primalTolerance *= 1000.0;
+
+    int numberRows = model_->getNumRows();
+
+    int numberIntegers = model_->numberIntegers();
+    const int * integerVariable = model_->integerVariable();
+    int i;
+
+    // Check feasible
+
+    double * rowActivity = new double[numberRows];
+    memset(rowActivity, 0, numberRows*sizeof(double));
+    solver->getMatrixByCol()->times(solution, rowActivity) ;
+    int goodSolution = 0;
+    // check was feasible
+    for (i = 0; i < numberRows; i++) {
+        if (rowActivity[i] < rowLower[i] - primalTolerance) {
+            goodSolution = -1;
+        } else if (rowActivity[i] > rowUpper[i] + primalTolerance) {
+            goodSolution = -1;
+        }
+    }
+    delete [] rowActivity;
+    for (i = 0; i < numberIntegers; i++) {
+        int iColumn = integerVariable[i];
+        double value = solution[iColumn];
+        if (fabs(floor(value + 0.5) - value) > integerTolerance) {
+            goodSolution = -1;
+        }
+    }
+    // zap cut
+    if (goodSolution == 0) {
+        // Create cut and get total gap
+        CoinPackedVector cut;
+        double rhs = rhs_;
+        double maxValue = 0.0;
+        for (i = 0; i < numberIntegers; i++) {
+            int iColumn = integerVariable[i];
+            double value = floor(solution[iColumn] + 0.5);
+            if (!typeCuts_ && originalUpper_[i] - originalLower_[i] > 1.0)
+                continue; // skip as not 0-1
+            if (originalLower_[i] == originalUpper_[i])
+                continue;
+            double mu = 1.0 / (originalUpper_[i] - originalLower_[i]);
+            if (value == originalLower_[i]) {
+                rhs += mu * originalLower_[i];
+                cut.insert(iColumn, 1.0);
+                maxValue += originalUpper_[i];
+            } else if (value == originalUpper_[i]) {
+                rhs -= mu * originalUpper_[i];
+                cut.insert(iColumn, -1.0);
+                maxValue += originalLower_[i];
+            }
+        }
+        if (maxValue < rhs - primalTolerance) {
+            if (model_->messageHandler()->logLevel() > 1)
+                printf("slack cut\n");
+            goodSolution = 1;
+        }
+        rowCut.setRow(cut);
+        rowCut.setLb(-COIN_DBL_MAX);
+        rowCut.setUb(rhs);
+        rowCut.setGloballyValid();
+        if (model_->messageHandler()->logLevel() > 1)
+            printf("Cut size: %i Cut rhs: %g\n", cut.getNumElements(), rhs);
+#ifdef CBC_DEBUG
+        if (model_->messageHandler()->logLevel() > 0) {
+            int k;
+            for (k = 0; k < cut.getNumElements(); k++) {
+                printf("%i    %g ", cut.getIndices()[k], cut.getElements()[k]);
+                if ((k + 1) % 5 == 0)
+                    printf("\n");
+            }
+            if (k % 5 != 0)
+                printf("\n");
+        }
+#endif
+        return goodSolution;
+    } else {
+        if (model_->messageHandler()->logLevel() > 1)
+            printf("Not a good solution\n");
+        return -1;
+    }
+}
+// Other side of last cut branch
+void
+CbcTreeVariable::reverseCut(int state, double bias)
+{
+    // find global cut
+    CbcRowCuts * global = model_->globalCuts();
+    int n = global->sizeRowCuts();
+    int i;
+    OsiRowCut * rowCut = NULL;
+    for ( i = 0; i < n; i++) {
+        rowCut = global->rowCutPtr(i);
+        if (cut_ == *rowCut) {
+            break;
+        }
+    }
+    if (!rowCut) {
+        // must have got here in odd way e.g. strong branching
+        return;
+    }
+    if (rowCut->lb() > -1.0e10)
+        return;
+    // get smallest element
+    double smallest = COIN_DBL_MAX;
+    CoinPackedVector row = cut_.row();
+    for (int k = 0; k < row.getNumElements(); k++)
+        smallest = CoinMin(smallest, fabs(row.getElements()[k]));
+    if (!typeCuts_ && !refine_) {
+        // Reverse cut very very weakly
+        if (state > 2)
+            smallest = 0.0;
+    }
+    // replace by other way
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("reverseCut - changing cut %d out of %d, old rhs %g %g ",
+               i, n, rowCut->lb(), rowCut->ub());
+    rowCut->setLb(rowCut->ub() + smallest - bias);
+    rowCut->setUb(COIN_DBL_MAX);
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("new rhs %g %g, bias %g smallest %g ",
+               rowCut->lb(), rowCut->ub(), bias, smallest);
+    const OsiRowCutDebugger *debugger = model_->solver()->getRowCutDebuggerAlways() ;
+    if (debugger) {
+        if (debugger->invalidCut(*rowCut))
+            printf("ZZZZTree Global cut - cuts off optimal solution!\n");
+    }
+}
+// Delete last cut branch
+void
+CbcTreeVariable::deleteCut(OsiRowCut & cut)
+{
+    // find global cut
+    CbcRowCuts * global = model_->globalCuts();
+    int n = global->sizeRowCuts();
+    int i;
+    OsiRowCut * rowCut = NULL;
+    for ( i = 0; i < n; i++) {
+        rowCut = global->rowCutPtr(i);
+        if (cut == *rowCut) {
+            break;
+        }
+    }
+    assert (i < n);
+    // delete last cut
+    if (model_->messageHandler()->logLevel() > 1)
+        printf("deleteCut - deleting cut %d out of %d, rhs %g %g\n",
+               i, n, rowCut->lb(), rowCut->ub());
+    global->eraseRowCut(i);
+}
+// Create C++ lines to get to current state
+void
+CbcTreeVariable::generateCpp( FILE * fp)
+{
+    CbcTreeVariable other;
+    fprintf(fp, "0#include \"CbcTreeVariable.hpp\"\n");
+    fprintf(fp, "5  CbcTreeVariable variableTree(cbcModel,NULL);\n");
+    if (range_ != other.range_)
+        fprintf(fp, "5  variableTree.setRange(%d);\n", range_);
+    if (typeCuts_ != other.typeCuts_)
+        fprintf(fp, "5  variableTree.setTypeCuts(%d);\n", typeCuts_);
+    if (maxDiversification_ != other.maxDiversification_)
+        fprintf(fp, "5  variableTree.setMaxDiversification(%d);\n", maxDiversification_);
+    if (timeLimit_ != other.timeLimit_)
+        fprintf(fp, "5  variableTree.setTimeLimit(%d);\n", timeLimit_);
+    if (nodeLimit_ != other.nodeLimit_)
+        fprintf(fp, "5  variableTree.setNodeLimit(%d);\n", nodeLimit_);
+    if (refine_ != other.refine_)
+        fprintf(fp, "5  variableTree.setRefine(%s);\n", refine_ ? "true" : "false");
+    fprintf(fp, "5  cbcModel->passInTreeHandler(variableTree);\n");
+}
+
+
+
diff --git a/cbits/coin/CbcTreeLocal.hpp b/cbits/coin/CbcTreeLocal.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CbcTreeLocal.hpp
@@ -0,0 +1,372 @@
+/* $Id: CbcTreeLocal.hpp 1573 2011-01-05 01:12:36Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CbcTreeLocal_H
+#define CbcTreeLocal_H
+
+//#############################################################################
+/*  This implements (approximately) local branching as in the 2002 paper by
+    Matteo Fischetti and Andrea Lodi.
+
+    The very simple version of the algorithm for problems with
+    0-1 variables and continuous is as follows:
+
+    Obtain a feasible solution (one can be passed in).
+
+    Add a cut which limits search to a k neighborhood of this solution.
+    (At most k 0-1 variables may change value)
+    Do branch and bound on this problem.
+
+    If finished search and proven optimal then we can reverse cut so
+    any solutions must be at least k+1 away from solution and we can
+    add a new cut limiting search to a k neighborhood of new solution
+    repeat.
+
+    If finished search and no new solution then the simplest version
+    would reverse last cut and complete search.  The version implemented
+    here can use time and node limits and can widen search (increase effective k)
+    .... and more
+
+*/
+
+#include "CbcTree.hpp"
+#include "CbcNode.hpp"
+#include "OsiRowCut.hpp"
+class CbcModel;
+
+
+class CbcTreeLocal : public CbcTree {
+
+public:
+
+    // Default Constructor
+    CbcTreeLocal ();
+
+    /* Constructor with solution.
+       If solution NULL no solution, otherwise must be integer
+       range is initial upper bound (k) on difference from given solution.
+       typeCuts -
+                0 means just 0-1 cuts and will need to refine 0-1 solution
+            1 uses weaker cuts on all integer variables
+       maxDiversification is maximum number of range widenings to try
+       timeLimit is seconds in subTree
+       nodeLimit is nodes in subTree
+       refine is whether to see if we can prove current solution is optimal
+       when we fix all 0-1 (in case typeCuts==0 and there are general integer variables)
+       if false then no refinement but reverse cuts weaker
+    */
+    CbcTreeLocal (CbcModel * model, const double * solution , int range = 10,
+                  int typeCuts = 0, int maxDiversification = 0,
+                  int timeLimit = 1000000, int nodeLimit = 1000000, bool refine = true);
+    // Copy constructor
+    CbcTreeLocal ( const CbcTreeLocal & rhs);
+
+    // = operator
+    CbcTreeLocal & operator=(const CbcTreeLocal & rhs);
+
+    virtual ~CbcTreeLocal();
+
+    /// Clone
+    virtual CbcTree * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /*! \name Heap access and maintenance methods */
+//@{
+
+    /// Return the top node of the heap
+    virtual CbcNode * top() const;
+
+    /// Add a node to the heap
+    virtual void push(CbcNode * x);
+
+    /// Remove the top node from the heap
+    virtual void pop() ;
+
+//@}
+    /*! \name Other stuff */
+//@{
+
+    /// Create cut - return -1 if bad, 0 if okay and 1 if cut is everything
+    int createCut(const double * solution, OsiRowCut & cut);
+
+    /// Test if empty *** note may be overridden
+    virtual bool empty() ;
+
+    /// We may have got an intelligent tree so give it one more chance
+    virtual void endSearch() ;
+    /// Other side of last cut branch (if bias==rhs_ will be weakest possible)
+    void reverseCut(int state, double bias = 0.0);
+    /// Delete last cut branch
+    void deleteCut(OsiRowCut & cut);
+    /// Pass in solution (so can be used after heuristic)
+    void passInSolution(const double * solution, double solutionValue);
+    // range i.e. k
+    inline int range() const {
+        return range_;
+    }
+    // setrange i.e. k
+    inline void setRange(int value) {
+        range_ = value;
+    }
+    // Type of cuts - 0=just 0-1, 1=all
+    inline int typeCuts() const {
+        return typeCuts_;
+    }
+    // Type of cuts - 0=just 0-1, 1=all
+    inline void setTypeCuts(int value) {
+        typeCuts_ = value;
+    }
+    // maximum number of diversifications
+    inline int maxDiversification() const {
+        return maxDiversification_;
+    }
+    // maximum number of diversifications
+    inline void setMaxDiversification(int value) {
+        maxDiversification_ = value;
+    }
+    // time limit per subtree
+    inline int timeLimit() const {
+        return timeLimit_;
+    }
+    // time limit per subtree
+    inline void setTimeLimit(int value) {
+        timeLimit_ = value;
+    }
+    // node limit for subtree
+    inline int nodeLimit() const {
+        return nodeLimit_;
+    }
+    // node limit for subtree
+    inline void setNodeLimit(int value) {
+        nodeLimit_ = value;
+    }
+    // Whether to do refinement step
+    inline bool refine() const {
+        return refine_;
+    }
+    // Whether to do refinement step
+    inline void setRefine(bool yesNo) {
+        refine_ = yesNo;
+    }
+
+//@}
+private:
+    // Node for local cuts
+    CbcNode * localNode_;
+    // best solution
+    double * bestSolution_;
+    // saved solution
+    double * savedSolution_;
+    // solution number at start of pass
+    int saveNumberSolutions_;
+    /* Cut.  If zero size then no solution yet.  Otherwise is left hand branch */
+    OsiRowCut cut_;
+    // This cut fixes all 0-1 variables
+    OsiRowCut fixedCut_;
+    // Model
+    CbcModel * model_;
+    // Original lower bounds
+    double * originalLower_;
+    // Original upper bounds
+    double * originalUpper_;
+    // range i.e. k
+    int range_;
+    // Type of cuts - 0=just 0-1, 1=all
+    int typeCuts_;
+    // maximum number of diversifications
+    int maxDiversification_;
+    // current diversification
+    int diversification_;
+    // Whether next will be strong diversification
+    bool nextStrong_;
+    // Current rhs
+    double rhs_;
+    // Save allowable gap
+    double savedGap_;
+    // Best solution
+    double bestCutoff_;
+    // time limit per subtree
+    int timeLimit_;
+    // time when subtree started
+    int startTime_;
+    // node limit for subtree
+    int nodeLimit_;
+    // node count when subtree started
+    int startNode_;
+    // -1 not started, 0 == stop on first solution, 1 don't stop on first, 2 refinement step
+    int searchType_;
+    // Whether to do refinement step
+    bool refine_;
+
+};
+
+class CbcTreeVariable : public CbcTree {
+
+public:
+
+    // Default Constructor
+    CbcTreeVariable ();
+
+    /* Constructor with solution.
+       If solution NULL no solution, otherwise must be integer
+       range is initial upper bound (k) on difference from given solution.
+       typeCuts -
+                0 means just 0-1 cuts and will need to refine 0-1 solution
+            1 uses weaker cuts on all integer variables
+       maxDiversification is maximum number of range widenings to try
+       timeLimit is seconds in subTree
+       nodeLimit is nodes in subTree
+       refine is whether to see if we can prove current solution is optimal
+       when we fix all 0-1 (in case typeCuts==0 and there are general integer variables)
+       if false then no refinement but reverse cuts weaker
+    */
+    CbcTreeVariable (CbcModel * model, const double * solution , int range = 10,
+                     int typeCuts = 0, int maxDiversification = 0,
+                     int timeLimit = 1000000, int nodeLimit = 1000000, bool refine = true);
+    // Copy constructor
+    CbcTreeVariable ( const CbcTreeVariable & rhs);
+
+    // = operator
+    CbcTreeVariable & operator=(const CbcTreeVariable & rhs);
+
+    virtual ~CbcTreeVariable();
+
+    /// Clone
+    virtual CbcTree * clone() const;
+    /// Create C++ lines to get to current state
+    virtual void generateCpp( FILE * fp) ;
+
+    /*! \name Heap access and maintenance methods */
+//@{
+
+    /// Return the top node of the heap
+    virtual CbcNode * top() const;
+
+    /// Add a node to the heap
+    virtual void push(CbcNode * x);
+
+    /// Remove the top node from the heap
+    virtual void pop() ;
+
+//@}
+    /*! \name Other stuff */
+//@{
+
+    /// Create cut - return -1 if bad, 0 if okay and 1 if cut is everything
+    int createCut(const double * solution, OsiRowCut & cut);
+
+    /// Test if empty *** note may be overridden
+    virtual bool empty() ;
+
+    /// We may have got an intelligent tree so give it one more chance
+    virtual void endSearch() ;
+    /// Other side of last cut branch (if bias==rhs_ will be weakest possible)
+    void reverseCut(int state, double bias = 0.0);
+    /// Delete last cut branch
+    void deleteCut(OsiRowCut & cut);
+    /// Pass in solution (so can be used after heuristic)
+    void passInSolution(const double * solution, double solutionValue);
+    // range i.e. k
+    inline int range() const {
+        return range_;
+    }
+    // setrange i.e. k
+    inline void setRange(int value) {
+        range_ = value;
+    }
+    // Type of cuts - 0=just 0-1, 1=all
+    inline int typeCuts() const {
+        return typeCuts_;
+    }
+    // Type of cuts - 0=just 0-1, 1=all
+    inline void setTypeCuts(int value) {
+        typeCuts_ = value;
+    }
+    // maximum number of diversifications
+    inline int maxDiversification() const {
+        return maxDiversification_;
+    }
+    // maximum number of diversifications
+    inline void setMaxDiversification(int value) {
+        maxDiversification_ = value;
+    }
+    // time limit per subtree
+    inline int timeLimit() const {
+        return timeLimit_;
+    }
+    // time limit per subtree
+    inline void setTimeLimit(int value) {
+        timeLimit_ = value;
+    }
+    // node limit for subtree
+    inline int nodeLimit() const {
+        return nodeLimit_;
+    }
+    // node limit for subtree
+    inline void setNodeLimit(int value) {
+        nodeLimit_ = value;
+    }
+    // Whether to do refinement step
+    inline bool refine() const {
+        return refine_;
+    }
+    // Whether to do refinement step
+    inline void setRefine(bool yesNo) {
+        refine_ = yesNo;
+    }
+
+//@}
+private:
+    // Node for local cuts
+    CbcNode * localNode_;
+    // best solution
+    double * bestSolution_;
+    // saved solution
+    double * savedSolution_;
+    // solution number at start of pass
+    int saveNumberSolutions_;
+    /* Cut.  If zero size then no solution yet.  Otherwise is left hand branch */
+    OsiRowCut cut_;
+    // This cut fixes all 0-1 variables
+    OsiRowCut fixedCut_;
+    // Model
+    CbcModel * model_;
+    // Original lower bounds
+    double * originalLower_;
+    // Original upper bounds
+    double * originalUpper_;
+    // range i.e. k
+    int range_;
+    // Type of cuts - 0=just 0-1, 1=all
+    int typeCuts_;
+    // maximum number of diversifications
+    int maxDiversification_;
+    // current diversification
+    int diversification_;
+    // Whether next will be strong diversification
+    bool nextStrong_;
+    // Current rhs
+    double rhs_;
+    // Save allowable gap
+    double savedGap_;
+    // Best solution
+    double bestCutoff_;
+    // time limit per subtree
+    int timeLimit_;
+    // time when subtree started
+    int startTime_;
+    // node limit for subtree
+    int nodeLimit_;
+    // node count when subtree started
+    int startNode_;
+    // -1 not started, 0 == stop on first solution, 1 don't stop on first, 2 refinement step
+    int searchType_;
+    // Whether to do refinement step
+    bool refine_;
+
+};
+#endif
+
diff --git a/cbits/coin/Cbc_C_Interface.cpp b/cbits/coin/Cbc_C_Interface.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Cbc_C_Interface.cpp
@@ -0,0 +1,2553 @@
+// $Id: Cbc_C_Interface.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <math.h>
+#include <cfloat>
+
+#include "CoinPragma.hpp"
+//#include "CoinHelperFunctions.hpp"
+//#include "CoinPackedMatrix.hpp"
+#include "CoinTime.hpp"
+
+#include "CbcModel.hpp"
+#include "CbcBranchActual.hpp"
+
+#include "CoinMessageHandler.hpp"
+#include "OsiClpSolverInterface.hpp"
+
+//  bobe including extras.h to get strdup()
+#if defined(__MWERKS__)
+// #include <extras.h>  // bobe 06-02-14
+#endif
+
+// Get C stuff but with extern C
+#define CBC_EXTERN_C
+#include "Coin_C_defines.h"
+
+const int  VERBOSE = 0;
+
+// To allow call backs
+class Cbc_MessageHandler
+            : public CoinMessageHandler {
+
+public:
+    /**@name Overrides */
+    //@{
+    virtual int print();
+    //@}
+    /**@name set and get */
+    //@{
+    /// Model
+    const Cbc_Model * model() const;
+    void setModel(Cbc_Model * model);
+    /// Call back
+    void setCallBack(cbc_callback callback);
+    //@}
+
+    /**@name Constructors, destructor */
+    //@{
+    /** Default constructor. */
+    Cbc_MessageHandler();
+    /// Constructor with pointer to model
+    Cbc_MessageHandler(Cbc_Model * model,
+                       FILE * userPointer = NULL);
+    /** Destructor */
+    virtual ~Cbc_MessageHandler();
+    //@}
+
+    /**@name Copy method */
+    //@{
+    /** The copy constructor. */
+    Cbc_MessageHandler(const Cbc_MessageHandler&);
+    /** The copy constructor from an CoinSimplexMessageHandler. */
+    Cbc_MessageHandler(const CoinMessageHandler&);
+
+    Cbc_MessageHandler& operator=(const Cbc_MessageHandler&);
+    /// Clone
+    virtual CoinMessageHandler * clone() const ;
+    //@}
+
+
+protected:
+    /**@name Data members
+       The data members are protected to allow access for derived classes. */
+    //@{
+    /// Pointer back to model
+    Cbc_Model * model_;
+    /// call back
+    cbc_callback callback_;
+    //@}
+};
+
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+Cbc_MessageHandler::Cbc_MessageHandler ()
+        : CoinMessageHandler(),
+        model_(NULL),
+        callback_(NULL)
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+Cbc_MessageHandler::Cbc_MessageHandler (const Cbc_MessageHandler & rhs)
+        : CoinMessageHandler(rhs),
+        model_(rhs.model_),
+        callback_(rhs.callback_)
+{
+}
+
+Cbc_MessageHandler::Cbc_MessageHandler (const CoinMessageHandler & rhs)
+        : CoinMessageHandler(rhs),
+        model_(NULL),
+        callback_(NULL)
+{
+}
+
+// Constructor with pointer to model
+Cbc_MessageHandler::Cbc_MessageHandler(Cbc_Model * model,
+                                       FILE * /*userPointer*/)
+        : CoinMessageHandler(),
+        model_(model),
+        callback_(NULL)
+{
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+Cbc_MessageHandler::~Cbc_MessageHandler ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+Cbc_MessageHandler &
+Cbc_MessageHandler::operator=(const Cbc_MessageHandler & rhs)
+{
+    if (this != &rhs) {
+        CoinMessageHandler::operator=(rhs);
+        model_ = rhs.model_;
+        callback_ = rhs.callback_;
+    }
+    return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CoinMessageHandler * Cbc_MessageHandler::clone() const
+{
+    return new Cbc_MessageHandler(*this);
+}
+int
+Cbc_MessageHandler::print()
+{
+    if (callback_) {
+        int messageNumber = currentMessage().externalNumber();
+        if (currentSource() != "Cbc")
+            messageNumber += 1000000;
+        int i;
+        int nDouble = numberDoubleFields();
+        assert (nDouble <= 200);
+        double vDouble[200];
+        for (i = 0; i < nDouble; i++)
+            vDouble[i] = doubleValue(i);
+        int nInt = numberIntFields();
+        assert (nInt <= 200);
+        int vInt[200];
+        for (i = 0; i < nInt; i++)
+            vInt[i] = intValue(i);
+        int nString = numberStringFields();
+        assert (nString <= 200);
+        char * vString[200];
+        for (i = 0; i < nString; i++) {
+            std::string value = stringValue(i);
+            vString[i] = CoinStrdup(value.c_str());
+        }
+        callback_(model_, messageNumber,
+                  nDouble, vDouble,
+                  nInt, vInt,
+                  nString, vString);
+        for (i = 0; i < nString; i++)
+            free(vString[i]);
+
+    }
+    return CoinMessageHandler::print();
+    return 0;
+}
+const Cbc_Model *
+Cbc_MessageHandler::model() const
+{
+    return model_;
+}
+void
+Cbc_MessageHandler::setModel(Cbc_Model * model)
+{
+    model_ = model;
+}
+// Call back
+void
+Cbc_MessageHandler::setCallBack(cbc_callback callback)
+{
+    callback_ = callback;
+}
+/**
+  *
+  *  C Interface Routines
+  *
+  */
+#include "Cbc_C_Interface.h"
+#include <string>
+#include <stdio.h>
+#include <iostream>
+
+#if defined(__MWERKS__)
+#pragma export on
+#endif
+
+/* Version */
+COINLIBAPI double COINLINKAGE Cbc_getVersion()
+{
+    double v = 1.0;
+    return v;
+}
+
+/* Default Cbc_Model constructor */
+COINLIBAPI Cbc_Model *  COINLINKAGE
+Cbc_newModel()
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_newModel(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    Cbc_Model * model = new Cbc_Model;
+    OsiClpSolverInterface solver1;
+    model->solver_    = &solver1;
+    model->solver_->OsiClpSolverInterface::setHintParam(OsiDoReducePrint, true, OsiHintTry);
+    model->model_     = new CbcModel(solver1);
+    model->handler_   = NULL;
+    model->information_ = NULL;
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return model;
+}
+/* Cbc_Model Destructor */
+COINLIBAPI void COINLINKAGE
+Cbc_deleteModel(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_deleteModel(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+    fflush(stdout);
+
+    if (VERBOSE > 1) printf("%s delete model->model_\n", prefix);
+    fflush(stdout);
+    delete model->model_;
+
+    if (VERBOSE > 1) printf("%s delete model->handler_\n", prefix);
+    fflush(stdout);
+    delete model->handler_;
+
+    if (VERBOSE > 1) printf("%s free model->information_\n", prefix);
+    fflush(stdout);
+    if (model->information_) free(model->information_);
+
+    if (VERBOSE > 1) printf("%s delete model\n", prefix);
+    fflush(stdout);
+    delete model;
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    fflush(stdout);
+}
+
+/* Loads a problem (the constraints on the
+    rows are given by lower and upper bounds). If a pointer is NULL then the
+    following values are the default:
+    <ul>
+    <li> <code>colub</code>: all columns have upper bound infinity
+    <li> <code>collb</code>: all columns have lower bound 0
+    <li> <code>rowub</code>: all rows have upper bound infinity
+    <li> <code>rowlb</code>: all rows have lower bound -infinity
+    <li> <code>obj</code>: all variables have 0 objective coefficient
+    </ul>
+
+   Just like the other loadProblem() method except that the matrix is
+   given in a standard column major ordered format (without gaps).
+*/
+COINLIBAPI void COINLINKAGE
+Cbc_loadProblem (Cbc_Model * model,  const int numcols, const int numrows,
+                 const CoinBigIndex * start, const int* index,
+                 const double* value,
+                 const double* collb, const double* colub,
+                 const double* obj,
+                 const double* rowlb, const double* rowub)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_loadProblem(): ";
+//  const int  VERBOSE = 2;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    OsiSolverInterface * solver = model->model_->solver();
+
+    if (VERBOSE > 1) {
+        printf("%s numcols = %i, numrows = %i\n",
+               prefix, numcols, numrows);
+        printf("%s model = %p, start = %p, index = %p, value = %p\n",
+               prefix, static_cast<void*>(model), static_cast<const void*>(start),
+               static_cast<const void*>(index), static_cast<const void*>(value));
+        printf("%s collb = %p, colub = %p, obj = %p, rowlb = %p, rowub = %p\n",
+               prefix, static_cast<const void*>(collb),
+               static_cast<const void*>(colub), static_cast<const void*>(obj),
+               static_cast<const void*>(rowlb), static_cast<const void*>(rowub));
+    }
+
+    if (VERBOSE > 1) printf("%s Calling solver->loadProblem()\n", prefix);
+    fflush(stdout);
+
+    if (1) {
+        solver->loadProblem(numcols, numrows, start, index, value,
+                            collb, colub, obj, rowlb, rowub);
+    } else {
+        solver->loadProblem(0, 0, NULL, NULL, NULL,
+                            NULL, NULL, NULL, NULL, NULL);
+    }
+    if (VERBOSE > 1) printf("%s Finished solver->loadProblem()\n", prefix);
+    fflush(stdout);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+} //  Cbc_loadProblem()
+
+/* Read an mps file from the given filename */
+COINLIBAPI int COINLINKAGE
+Cbc_readMps(Cbc_Model * model, const char *filename)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_readMps(): ";
+//  const int  VERBOSE = 2;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+    if (VERBOSE > 1) printf("%s filename = '%s'\n", prefix, filename);
+
+    int result = 1;
+    result = model->model_->solver()->readMps(filename);
+    assert(result == 0);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Write an mps file from the given filename */
+COINLIBAPI void COINLINKAGE
+Cbc_writeMps(Cbc_Model * model, const char *filename)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_writeMps(): ";
+//  const int  VERBOSE = 2;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+    if (VERBOSE > 1) printf("%s filename = '%s'\n", prefix, filename);
+
+    model->model_->solver()->writeMps(filename, "mps", Cbc_optimizationDirection(model));
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return;
+}
+/* Integer information */
+COINLIBAPI char * COINLINKAGE
+Cbc_integerInformation(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_integerInformation(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int col;
+    int numcols = Cbc_getNumCols(model);
+
+    // allocate model->information_ if null
+    // this is freed in Cbc_deleteModel() if not null
+    if (!model->information_)
+        model->information_ = (char *) malloc(numcols * sizeof(char));
+
+    for (col = 0; col < numcols; col++)
+        if (model->model_->solver()->isContinuous(col))
+            model->information_[col] = 0;
+        else
+            model->information_[col] = 1;
+
+    char * result = model->information_;
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, result);
+    return result;
+}
+/* Copy in integer information */
+COINLIBAPI void COINLINKAGE
+Cbc_copyInIntegerInformation(Cbc_Model * model, const char * information)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_copyInIntegerInformation(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int col;
+    int numcols = Cbc_getNumCols(model);
+    for (col = 0; col < numcols; col++)
+        if (information[col])
+            model->model_->solver()->setInteger(col);
+        else
+            model->model_->solver()->setContinuous(col);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Drop integer informations */
+COINLIBAPI void COINLINKAGE
+Cbc_deleteIntegerInformation(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_deleteIntegerInformation(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+//  available through
+//    OsiClpSolverInterface::setContinuous
+//tbd  model->model_->deleteIntegerInformation();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Resizes rim part of model  */
+COINLIBAPI void COINLINKAGE
+Cbc_resize (Cbc_Model * /*model*/, int /*newNumberRows*/,
+            int /*newNumberColumns*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_resize(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find this in Cbc, Osi, or OsiClp
+//tbd  model->model_->solver()->resize(newNumberRows,newNumberColumns);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Deletes rows */
+COINLIBAPI void COINLINKAGE
+Cbc_deleteRows(Cbc_Model * model, int number, const int * which)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_deleteRows(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    OsiSolverInterface * solver = model->model_->solver();
+    solver->deleteRows(number, which);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Add rows */
+COINLIBAPI void COINLINKAGE
+Cbc_addRows(Cbc_Model * /*model*/, const int /*number*/,
+            const double * /*rowLower*/,
+            const double * /*rowUpper*/,
+            const int * /*rowStarts*/, const int * /*columns*/,
+            const double * /*elements*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_addRows(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// available through OsiClp
+//tbd  model->model_->addRows(number,rowLower,rowUpper,rowStarts,columns,elements);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+
+/* Deletes columns */
+COINLIBAPI void COINLINKAGE
+Cbc_deleteColumns(Cbc_Model * model, int number, const int * which)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_deleteColumns(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    OsiSolverInterface * solver = model->model_->solver();
+    solver->deleteCols(number, which);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Add columns */
+COINLIBAPI void COINLINKAGE
+Cbc_addColumns(Cbc_Model * /*model*/, int /*number*/,
+               const double * /*columnLower*/,
+               const double * /*columnUpper*/,
+               const double * /*objective*/,
+               const int * /*columnStarts*/, const int * /*rows*/,
+               const double * /*elements*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_addColumns(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// available through OsiClp
+//tbd  model->model_->addColumns(number,columnLower,columnUpper,objective,
+//tbd			    columnStarts,rows,elements);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Drops names - makes lengthnames 0 and names empty */
+COINLIBAPI void COINLINKAGE
+Cbc_dropNames(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_dropNames(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  model->model_->dropNames();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Copies in names */
+COINLIBAPI void COINLINKAGE
+Cbc_copyNames(Cbc_Model * /*model*/, const char * const * /*rowNamesIn*/,
+              const char * const * /*columnNamesIn*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_copyNames(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find names in Cbc, Osi, or OsiClp
+    /*clean
+      int iRow;
+      std::vector<std::string> rowNames;
+      int numberRows = model->model_->getNumRows();
+      rowNames.reserve(numberRows);
+      for (iRow=0;iRow<numberRows;iRow++) {
+        rowNames.push_back(rowNamesIn[iRow]);
+      }
+
+      int iColumn;
+      std::vector<std::string> columnNames;
+      int numberColumns = model->model_->getNumCols();
+      columnNames.reserve(numberColumns);
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+        columnNames.push_back(columnNamesIn[iColumn]);
+      }
+      model->model_->copyNames(rowNames,columnNames);
+    */
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+
+/* Number of rows */
+COINLIBAPI int COINLINKAGE
+Cbc_numberRows(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_numberRows(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getNumRows();
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Number of columns */
+COINLIBAPI int COINLINKAGE
+Cbc_numberColumns(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_numberColumns(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getNumCols();
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Primal tolerance to use */
+COINLIBAPI double COINLINKAGE
+Cbc_primalTolerance(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_primalTolerance(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0.0;
+    model->model_->solver()->getDblParam(OsiPrimalTolerance, result) ;
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setPrimalTolerance(Cbc_Model * model,  double value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setPrimalTolerance(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->solver()->setDblParam(OsiPrimalTolerance, value) ;
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Dual tolerance to use */
+COINLIBAPI double COINLINKAGE
+Cbc_dualTolerance(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_dualTolerance(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0.0;
+    model->model_->solver()->getDblParam(OsiDualTolerance, result) ;
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setDualTolerance(Cbc_Model * model,  double value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setDualTolerance(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->solver()->setDblParam(OsiDualTolerance, value) ;
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Integer tolerance to use */
+COINLIBAPI double COINLINKAGE
+Cbc_integerTolerance(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_primalTolerance(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0.0;
+    result = model->model_->getDblParam(CbcModel::CbcIntegerTolerance) ;
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setIntegerTolerance(Cbc_Model * model,  double value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setPrimalTolerance(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->setDblParam(CbcModel::CbcIntegerTolerance, value) ;
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Dual objective limit */
+COINLIBAPI double COINLINKAGE
+Cbc_dualObjectiveLimit(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_dualObjectiveLimit(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0.0;
+    model->model_->solver()->getDblParam(OsiDualObjectiveLimit, result) ;
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setDualObjectiveLimit(Cbc_Model * model, double value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setDualObjectiveLimit(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->solver()->setDblParam(OsiDualObjectiveLimit, value) ;
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Objective offset */
+COINLIBAPI double COINLINKAGE
+Cbc_objectiveOffset(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_objectiveOffset(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0.0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  return model->model_->objectiveOffset();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setObjectiveOffset(Cbc_Model * /*model*/, double /*value*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setObjectiveOffset(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  model->model_->solver()->setObjectiveOffset(value);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Fills in array with problem name  */
+COINLIBAPI void COINLINKAGE
+Cbc_problemName(Cbc_Model * model, int maxNumberCharacters, char * array)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_problemName(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    std::string name;
+    model->model_->solver()->getStrParam(OsiProbName, name);
+    maxNumberCharacters = CoinMin(maxNumberCharacters, (int)strlen(name.c_str()));
+    strncpy(array, name.c_str(), maxNumberCharacters - 1);
+    array[maxNumberCharacters-1] = '\0';
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Sets problem name.  Must have \0 at end.  */
+COINLIBAPI int COINLINKAGE
+Cbc_setProblemName(Cbc_Model * model, int /*maxNumberCharacters*/, char * array)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setProblemName(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    bool result = false;
+    result = model->model_->solver()->setStrParam(OsiProbName, array);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return (result) ? 1 : 0;
+}
+/* Number of iterations */
+COINLIBAPI int COINLINKAGE
+Cbc_numberIterations(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_numberIterations(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getIterationCount();
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setNumberIterations(Cbc_Model * /*model*/, int /*numberIterations*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setNumberIterations(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find this in Cbc, Osi, or OsiClp
+//tbd  model->model_->setNumberIterations(numberIterations);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return;
+}
+/* Maximum number of iterations */
+COINLIBAPI int COINLINKAGE
+Cbc_maximumIterations(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_maximumIterations(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// cannot find this in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->solver()->maximumIterations();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setMaximumIterations(Cbc_Model * /*model*/, int /*value*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setMaximumIterations(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find this in Cbc, Osi, or OsiClp
+//tbd  model->model_->setMaximumIterations(value);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Maximum number of nodes */
+COINLIBAPI int COINLINKAGE
+Cbc_maxNumNode(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_maxNumNode(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getIntParam(CbcModel::CbcMaxNumNode);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setMaxNumNode(Cbc_Model * model, int value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setMaxNumNode(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->setIntParam(CbcModel::CbcMaxNumNode, value);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Maximum number of solutions */
+COINLIBAPI int COINLINKAGE
+Cbc_maxNumSol(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::maxNumSol(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getIntParam(CbcModel::CbcMaxNumSol);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setMaxNumSol(Cbc_Model * model, int value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setMaxNumSol(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->setIntParam(CbcModel::CbcMaxNumSol, value);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Maximum time in seconds (from when set called) */
+COINLIBAPI double COINLINKAGE
+Cbc_maximumSeconds(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_maximumSeconds(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0.0;
+    result = model->model_->getDblParam(CbcModel::CbcMaximumSeconds);
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setMaximumSeconds(Cbc_Model * model, double value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setMaximumSeconds(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->setDblParam(CbcModel::CbcMaximumSeconds, value);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Returns true if hit maximum iteratio`ns (or time) */
+COINLIBAPI int COINLINKAGE
+Cbc_hitMaximumIterations(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_hitMaximumIterations(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->solver()->hitMaximumIterations() ? 1 : 0;
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Status of problem:
+   0 - optimal
+   1 - primal infeasible
+   2 - dual infeasible
+   3 - stopped on iterations etc
+   4 - stopped due to errors
+*/
+COINLIBAPI int COINLINKAGE
+Cbc_status(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_status(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->status();
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Set problem status */
+COINLIBAPI void COINLINKAGE
+Cbc_setProblemStatus(Cbc_Model * /*model*/, int /*problemStatus*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setProblemStatus(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find this in Cbc, Osi, or OsiClp
+//tbd  model->model_->setProblemStatus(problemStatus);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Secondary status of problem - may get extended
+   0 - none
+   1 - primal infeasible because dual limit reached
+   2 - scaled problem optimal - unscaled has primal infeasibilities
+   3 - scaled problem optimal - unscaled has dual infeasibilities
+   4 - scaled problem optimal - unscaled has both dual and primal infeasibilities
+*/
+COINLIBAPI int COINLINKAGE
+Cbc_secondaryStatus(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_secondaryStatus(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// cannot find this in Cbc, Osi, or OsiClp
+    result = model->model_->secondaryStatus();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setSecondaryStatus(Cbc_Model * /*model*/, int /*status*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setSecondaryStatus(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find this in Cbc, Osi, or OsiClp
+//tbd  model->model_->setSecondaryStatus(status);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+COINLIBAPI double COINLINKAGE
+Cbc_optimizationDirection(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_optimizationDirection(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0.0;
+    result = model->model_->getObjSense();
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setOptimizationDirection(Cbc_Model * model, double value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setOptimizationDirection(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin, value = %g\n", prefix, value);
+
+    model->model_->setObjSense(value);
+//  model->model_->solver()->setObjSense(value);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Primal row solution */
+COINLIBAPI double * COINLINKAGE
+Cbc_primalRowSolution(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_primalRowSolution(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//tbd  return model->model_->primalRowSolution();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return result;
+}
+/* Primal column solution */
+COINLIBAPI double * COINLINKAGE
+Cbc_primalColumnSolution(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_primalColumnSolution(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//  result = model->model_->getColSolution();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return result;
+}
+/* Dual row solution */
+COINLIBAPI double * COINLINKAGE
+Cbc_dualRowSolution(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_dualRowSolution(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//tbd  return model->model_->dualRowSolution();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return NULL;
+}
+/* Reduced costs */
+COINLIBAPI double * COINLINKAGE
+Cbc_dualColumnSolution(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_dualColumnSolution(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//tbd  return model->model_->dualColumnSolution();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return NULL;
+}
+/* Row lower */
+COINLIBAPI double * COINLINKAGE
+Cbc_rowLower(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_rowLower(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//tbd  return model->model_->rowLower();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return NULL;
+}
+/* Row upper  */
+COINLIBAPI double * COINLINKAGE
+Cbc_rowUpper(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_rowUpper(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//tbd  return model->model_->rowUpper();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return NULL;
+}
+/* Objective Coefficients */
+COINLIBAPI double * COINLINKAGE
+Cbc_objective(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_objective(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//  result = model->model_->objective();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return NULL;
+}
+/* Column Lower */
+COINLIBAPI double * COINLINKAGE
+Cbc_columnLower(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_columnLower(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//tbd  return model->model_->columnLower();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return NULL;
+}
+/* Column Upper */
+COINLIBAPI double * COINLINKAGE
+Cbc_columnUpper(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_columnUpper(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+// cannot find this in Cbc, Osi, or OsiClp
+// may have to make it somehow
+//tbd  return model->model_->columnUpper();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return NULL;
+}
+/* Number of elements in matrix */
+COINLIBAPI int COINLINKAGE
+Cbc_getNumElements(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getNumElements(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getNumElements();
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+
+// Column starts in matrix
+COINLIBAPI const CoinBigIndex * COINLINKAGE
+Cbc_getVectorStarts(Cbc_Model * model)
+{
+    const CoinPackedMatrix * matrix = NULL;
+    matrix = model->model_->solver()->getMatrixByCol();
+    return (matrix == NULL) ? NULL : matrix->getVectorStarts();
+}
+// Row indices in matrix
+COINLIBAPI const int * COINLINKAGE
+Cbc_getIndices(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getIndices(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const int * result = NULL;
+    const CoinPackedMatrix * matrix = NULL;
+    matrix = model->model_->solver()->getMatrixByCol();
+    result = (matrix == NULL) ? NULL : matrix->getIndices();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+
+// Column vector lengths in matrix
+COINLIBAPI const int * COINLINKAGE
+Cbc_getVectorLengths(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getVectorLengths(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const int * result = NULL;
+    const CoinPackedMatrix * matrix = NULL;
+    matrix = model->model_->solver()->getMatrixByCol();
+    result = (matrix == NULL) ? NULL : matrix->getVectorLengths();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+
+// Element values in matrix
+COINLIBAPI const double * COINLINKAGE
+Cbc_getElements(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getElements(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    const CoinPackedMatrix * matrix = NULL;
+    matrix = model->model_->solver()->getMatrixByCol();
+    result = (matrix == NULL) ? NULL : matrix->getElements();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+// ======================================================================
+
+/* Objective value */
+COINLIBAPI double COINLINKAGE
+Cbc_objectiveValue(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_objectiveValue(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0.0;
+    result = model->model_->getObjValue();
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+/* Infeasibility/unbounded ray (NULL returned if none/wrong)
+   Up to user to use delete [] on these arrays.  */
+COINLIBAPI double * COINLINKAGE
+Cbc_infeasibilityRay(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_infeasibilityRay(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+    // lots of rays (probably too many) are available in
+    // OsiClpSolverInterface::getDualRays()
+    //
+//tbd  result = model->model_->infeasibilityRay();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return result;
+}
+COINLIBAPI double * COINLINKAGE
+Cbc_unboundedRay(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_unboundedRay(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double * result = NULL;
+    // lots of rays (probably too many) are available in
+    // OsiClpSolverInterface::getPrimalRays()
+    //
+//tbd  result = model->model_->unboundedRay();
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, static_cast<void*>(result));
+    return result;
+}
+/* See if status array exists (partly for OsiClp) */
+COINLIBAPI int COINLINKAGE
+Cbc_statusExists(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_statusExists(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+//tbd  result = model->model_->statusExists() ? 1 : 0;
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Return address of status array (char[numberRows+numberColumns]) */
+COINLIBAPI void  COINLINKAGE
+Cbc_getBasisStatus(Cbc_Model * /*model*/, int * /*cstat*/, int * /*rstat*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getBasisStatus(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// have to figure this out
+//tbd  model->model_->solver()->getBasisStatus(cstat, rstat);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return;
+}
+/* Copy in status vector */
+COINLIBAPI void COINLINKAGE
+Cbc_setBasisStatus(Cbc_Model * /*model*/,  int * /*cstat*/, int * /*rstat*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setBasisStatus(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+//  model->model_->solver()->setBasisStatus(cstat, rstat);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+
+/* User pointer for whatever reason */
+COINLIBAPI void COINLINKAGE
+Cbc_setUserPointer (Cbc_Model * /*model*/, void * /*pointer*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setUserPointer(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    // not sure what this is for
+    //
+//tbd  model->model_->setUserPointer(pointer);
+    if (VERBOSE > 0) printf("%s WARNING: NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+COINLIBAPI void * COINLINKAGE
+Cbc_getUserPointer (Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getUserPointer(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    void * result = NULL;
+    // not sure what this is for
+    //
+//tbd result = model->model_->getUserPointer();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %p\n", prefix, result);
+    return result;
+}
+/* Pass in Callback function */
+COINLIBAPI void COINLINKAGE
+Cbc_registerCallBack(Cbc_Model * model,
+                     cbc_callback userCallBack)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_registerCallBack(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    // reuse existing log level
+    int oldLogLevel = model->model_->messageHandler()->logLevel();
+    // Will be copy of users one
+    delete model->handler_;
+    model->handler_ = new Cbc_MessageHandler(*(model->model_->messageHandler()));
+    model->handler_->setCallBack(userCallBack);
+    model->handler_->setModel(model);
+    model->model_->passInMessageHandler(model->handler_);
+    model->model_->messageHandler()->setLogLevel(oldLogLevel);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Unset Callback function */
+COINLIBAPI void COINLINKAGE
+Cbc_clearCallBack(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_clearCallBack(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    delete model->handler_;
+    model->handler_ = NULL;
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Amount of print out:
+   0 - none
+   1 - just final
+   2 - just factorizations
+   3 - as 2 plus a bit more
+   4 - verbose
+   above that 8,16,32 etc just for selective debug
+*/
+COINLIBAPI void COINLINKAGE
+Cbc_setLogLevel(Cbc_Model * model, int value)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setLogLevel(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+    if (VERBOSE > 1) printf("%s value = %i\n", prefix, value);
+
+    model->model_->messageHandler()->setLogLevel(value);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+COINLIBAPI int COINLINKAGE
+Cbc_logLevel(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_logLevel(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->messageHandler()->logLevel();
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* length of names (0 means no names0 */
+COINLIBAPI int COINLINKAGE
+Cbc_lengthNames(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_lengthNames(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->lengthNames();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Fill in array (at least lengthNames+1 long) with a row name */
+COINLIBAPI void COINLINKAGE
+Cbc_rowName(Cbc_Model * /*model*/, int iRow, char * name)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_rowName(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    sprintf(name, "ROW%5i", iRow);
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  std::string rowName=model->model_->rowName(iRow);
+//tbd  strcpy(name,rowName.c_str());
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Fill in array (at least lengthNames+1 long) with a column name */
+// cannot find names in Cbc, Osi, or OsiClp
+COINLIBAPI void COINLINKAGE
+Cbc_columnName(Cbc_Model * /*model*/, int iColumn, char * name)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_columnName(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    sprintf(name, "COL%5i", iColumn);
+//tbd  std::string columnName= model->model_->columnName(iColumn);
+//tbd  strcpy(name,columnName.c_str());
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+
+/* General branch and bound solve algorithm which can do presolve.
+   See  CbcSolve.hpp for options
+*/
+COINLIBAPI int COINLINKAGE
+Cbc_initialSolve(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_initialSolve(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    model->model_->initialSolve();
+    result = model->model_->status();
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* General solve algorithm which can do presolve.
+   See  CbcModel.hpp for options
+*/
+COINLIBAPI int COINLINKAGE
+Cbc_branchAndBound(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_branchAndBound(): ";
+//  const int  VERBOSE = 3;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    if (VERBOSE > 2) Cbc_printModel(model, prefix);
+    try {
+        model->model_->branchAndBound();
+        model->model_->solver()->resolve();
+    } catch (CoinError e) {
+        printf("%s ERROR: %s::%s, %s\n", prefix,
+               e.className().c_str(), e.methodName().c_str(), e.message().c_str());
+    }
+    result = model->model_->status();
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Sets or unsets scaling, 0 -off, 1 equilibrium, 2 geometric, 3, auto, 4 dynamic(later) */
+COINLIBAPI void COINLINKAGE
+Cbc_scaling(Cbc_Model * model, int mode)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_scaling(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    OsiSolverInterface * solver = model->model_->solver();
+    bool modeBool = (mode == 0);
+    solver->setHintParam(OsiDoScale, modeBool);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Gets scalingFlag */
+COINLIBAPI int COINLINKAGE
+Cbc_scalingFlag(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_scalingFlag(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// try to use OsiSolverInterface::getHintParam(OsiDoScale, ???)
+//tbd  result = model->model_->scalingFlag();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Crash - at present just aimed at dual, returns
+   -2 if dual preferred and crash basis created
+   -1 if dual preferred and all slack basis preferred
+   0 if basis going in was not all slack
+   1 if primal preferred and all slack basis preferred
+   2 if primal preferred and crash basis created.
+
+   if gap between bounds <="gap" variables can be flipped
+
+   If "pivot" is
+   0 No pivoting (so will just be choice of algorithm)
+   1 Simple pivoting e.g. gub
+   2 Mini iterations
+*/
+COINLIBAPI int COINLINKAGE
+Cbc_crash(Cbc_Model * /*model*/, double /*gap*/, int /*pivot*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_crash(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->crash(gap,pivot);
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* If problem is primal feasible */
+COINLIBAPI int COINLINKAGE
+Cbc_primalFeasible(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_primalFeasible(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    OsiSolverInterface * solver = model->model_->solver();
+    result = solver->isProvenPrimalInfeasible() ? 0 : 1;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* If problem is dual feasible */
+COINLIBAPI int COINLINKAGE
+Cbc_dualFeasible(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_dualFeasible(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    OsiSolverInterface * solver = model->model_->solver();
+    result = solver->isProvenDualInfeasible() ? 0 : 1;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Dual bound */
+COINLIBAPI double COINLINKAGE
+Cbc_dualBound(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_dualBound(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0;
+// cannot find in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->dualBound();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setDualBound(Cbc_Model * /*model*/, double /*value*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setDualBound(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  model->model_->setDualBound(value);
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Infeasibility cost */
+COINLIBAPI double COINLINKAGE
+Cbc_infeasibilityCost(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_infeasibilityCost(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->solver()->infeasibilityCost();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setInfeasibilityCost(Cbc_Model * /*model*/, double /*value*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setInfeasibilityCost(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  model->model_->setInfeasibilityCost(value);
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Perturbation:
+   50  - switch on perturbation
+   100 - auto perturb if takes too long (1.0e-6 largest nonzero)
+   101 - we are perturbed
+   102 - don't try perturbing again
+   default is 100
+   others are for playing
+*/
+COINLIBAPI int COINLINKAGE
+Cbc_perturbation(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_perturbation(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->perturbation();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setPerturbation(Cbc_Model * /*model*/, int /*value*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setPerturbation(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  model->model_->setPerturbation(value);
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Current (or last) algorithm */
+COINLIBAPI int COINLINKAGE
+Cbc_algorithm(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setPerturbation(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->algorithm();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Set algorithm */
+COINLIBAPI void COINLINKAGE
+Cbc_setAlgorithm(Cbc_Model * /*model*/, int /*value*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setAlgorithm(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  model->model_->setAlgorithm(value);
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}
+/* Sum of dual infeasibilities */
+COINLIBAPI double COINLINKAGE
+Cbc_sumDualInfeasibilities(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_sumDualInfeasibilities(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->sumDualInfeasibilities();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+/* Number of dual infeasibilities */
+COINLIBAPI int COINLINKAGE
+Cbc_numberDualInfeasibilities(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_numberDualInfeasibilities(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd  result = model->model_->numberDualInfeasibilities();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Sum of primal infeasibilities */
+COINLIBAPI double COINLINKAGE
+Cbc_sumPrimalInfeasibilities(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_sumPrimalInfeasibilities(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0;
+// cannot find names in Cbc, Osi, or OsiClp
+//tbd result = model->model_->sumPrimalInfeasibilities();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+/* Number of primal infeasibilities */
+COINLIBAPI int COINLINKAGE
+Cbc_numberPrimalInfeasibilities(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_numberPrimalInfeasibilities(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+//tbd  result = model->model_->getContinuousInfeasibilities();
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Save model to file, returns 0 if success.  This is designed for
+   use outside algorithms so does not save iterating arrays etc.
+   It does not save any messaging information.
+   Does not save scaling values.
+   It does not know about all types of virtual functions.
+*/
+COINLIBAPI int COINLINKAGE
+Cbc_saveModel(Cbc_Model * /*model*/, const char * /*fileName*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_saveModel(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// there is a writeMPS method in Osi
+//tbd  result = model->model_->saveModel(fileName);
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Restore model from file, returns 0 if success,
+   deletes current model */
+COINLIBAPI int COINLINKAGE
+Cbc_restoreModel(Cbc_Model * /*model*/, const char * /*fileName*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_restoreModel(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+// there is a readMPS method in Osi
+//tbd  result = model->model_->restoreModel(fileName);
+    if (VERBOSE > 0) printf("%s WARNING:  NOT IMPLEMENTED\n", prefix);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+
+/** Call this to really test if a valid solution can be feasible
+    Solution is number columns in size.
+    If fixVariables true then bounds of continuous solver updated.
+    Returns objective value (worse than cutoff if not feasible)
+*/
+COINLIBAPI void COINLINKAGE
+Cbc_checkSolution(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_checkSolution(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    // see CbcModel::checkSolution(double cutoff, const double * solution,
+    //	       bool fixVariables);
+//  model->model_->checkSolution();
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return;
+}
+/* Number of rows */
+COINLIBAPI int COINLINKAGE
+Cbc_getNumRows(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getNumRows(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getNumRows();
+
+    if (VERBOSE > 0) printf("%s return %d\n", prefix, result);
+    return result;
+}
+/* Number of columns */
+COINLIBAPI int COINLINKAGE
+Cbc_getNumCols(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getNumCols(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getNumCols();
+
+    if (VERBOSE > 0) printf("%s return %d\n", prefix, result);
+    return result;
+}
+/* Number of iterations */
+COINLIBAPI int COINLINKAGE
+Cbc_getIterationCount(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getIterationCount(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getIterationCount();
+
+    if (VERBOSE > 0) printf("%s return %d\n", prefix, result);
+    return result;
+}
+/* Are there a numerical difficulties? */
+COINLIBAPI int COINLINKAGE
+Cbc_isAbandoned(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_isAbandoned(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->isAbandoned() ? 1 : 0;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Is optimality proven? */
+COINLIBAPI int COINLINKAGE
+Cbc_isProvenOptimal(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_isProvenOptimal(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->isProvenOptimal() ? 1 : 0;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Is primal infeasiblity proven? */
+COINLIBAPI int COINLINKAGE
+Cbc_isProvenPrimalInfeasible(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_isProvenPrimalInfeasible(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    OsiSolverInterface * solver = model->model_->solver();
+    result = solver->isProvenPrimalInfeasible() ? 1 : 0;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Is dual infeasiblity proven? */
+COINLIBAPI int COINLINKAGE
+Cbc_isProvenDualInfeasible(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_isProvenDualInfeasible(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    OsiSolverInterface * solver = model->model_->solver();
+    result = solver->isProvenDualInfeasible() ? 1 : 0;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Is the given primal objective limit reached? */
+COINLIBAPI int COINLINKAGE
+Cbc_isPrimalObjectiveLimitReached(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_isPrimalObjectiveLimitReached(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    OsiSolverInterface * solver = model->model_->solver();
+    result = solver->isPrimalObjectiveLimitReached() ? 1 : 0;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Is the given dual objective limit reached? */
+COINLIBAPI int COINLINKAGE
+Cbc_isDualObjectiveLimitReached(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_isDualObjectiveLimitReached(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    OsiSolverInterface * solver = model->model_->solver();
+    result = solver->isDualObjectiveLimitReached() ? 1 : 0;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Iteration limit reached? */
+COINLIBAPI int COINLINKAGE
+Cbc_isIterationLimitReached(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_isIterationLimitReached(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    OsiSolverInterface * solver = model->model_->solver();
+    result = solver->isIterationLimitReached() ? 1 : 0;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/* Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+COINLIBAPI double COINLINKAGE
+Cbc_getObjSense(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getObjSense(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0;
+    result = model->model_->getObjSense();
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+/* Primal row solution */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getRowActivity(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getRowActivity(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getRowActivity();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+/* Primal column solution */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getColSolution(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getColSolution(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getColSolution();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+COINLIBAPI void COINLINKAGE
+Cbc_setColSolution(Cbc_Model * model, const double * input)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setColSolution(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    OsiSolverInterface * solver = model->model_->solver();
+    solver->setColSolution(input);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return;
+}
+/* Dual row solution */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getRowPrice(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getRowPrice(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getRowPrice();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+/* Reduced costs */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getReducedCost(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getReducedCost(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getReducedCost();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+/* Row lower */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getRowLower(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getRowLower(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getRowLower();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+/* Row upper  */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getRowUpper(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getRowUpper(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getRowUpper();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+/* Objective Coefficients */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getObjCoefficients(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getObjCoefficients(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getObjCoefficients();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+/* Column Lower */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getColLower(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getColLower(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getColLower();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+/* Column Upper */
+COINLIBAPI const double * COINLINKAGE
+Cbc_getColUpper(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getColUpper(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    const double * result = NULL;
+    result = model->model_->getColUpper();
+
+    if (VERBOSE > 0)
+        printf("%s return %p\n", prefix, static_cast<const void*>(result));
+    return result;
+}
+/* Objective value */
+COINLIBAPI double COINLINKAGE
+Cbc_getObjValue(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getObjValue(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0;
+    result = model->model_->getObjValue();
+
+    if (VERBOSE > 0)
+        printf("%s return %g\n", prefix, result);
+    return result;
+}
+/* Print model */
+COINLIBAPI void COINLINKAGE
+Cbc_printModel(Cbc_Model * model, const char * argPrefix)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_printModel(): ";
+    const int  VERBOSE = 4;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    CbcModel *cbc_model = model->model_;
+    int numrows    = cbc_model->getNumRows();
+    int numcols    = cbc_model->getNumCols();
+    int numelem    = cbc_model->getNumElements();
+    const CoinPackedMatrix * matrix = cbc_model->solver()->getMatrixByCol();
+    const CoinBigIndex     * start  = matrix->getVectorStarts();
+    const int              * index  = matrix->getIndices();
+    const double           * value  = matrix->getElements();
+    const double           * collb  = cbc_model->getColLower();
+    const double           * colub  = cbc_model->getColUpper();
+    const double           * obj    = cbc_model->getObjCoefficients();
+    const double           * rowlb  = cbc_model->getRowLower();
+    const double           * rowub  = cbc_model->getRowUpper();
+
+    printf("%s numcols = %i, numrows = %i, numelem = %i\n",
+           argPrefix, numcols, numrows, numelem);
+    printf("%s model = %p, start = %p, index = %p, value = %p\n",
+           argPrefix, static_cast<void*>(model), static_cast<const void*>(start),
+           static_cast<const void*>(index), static_cast<const void*>(value));
+    matrix->dumpMatrix(NULL);
+    {
+        int i;
+        for (i = 0; i <= numcols; i++)
+            printf("%s start[%i] = %i\n", argPrefix, i, start[i]);
+        for (i = 0; i < numelem; i++)
+            printf("%s index[%i] = %i, value[%i] = %g\n",
+                   argPrefix, i, index[i], i, value[i]);
+    }
+
+    printf("%s collb = %p, colub = %p, obj = %p, rowlb = %p, rowub = %p\n",
+           argPrefix, static_cast<const void*>(collb),
+           static_cast<const void*>(colub), static_cast<const void*>(obj),
+           static_cast<const void*>(rowlb), static_cast<const void*>(rowub));
+    printf("%s optimization direction = %g\n", argPrefix, Cbc_optimizationDirection(model));
+    printf("  (1 - minimize, -1 - maximize, 0 - ignore)\n");
+    {
+        int i;
+        for (i = 0; i < numcols; i++)
+            printf("%s collb[%i] = %g, colub[%i] = %g, obj[%i] = %g\n",
+                   argPrefix, i, collb[i], i, colub[i], i, obj[i]);
+        for (i = 0; i < numrows; i++)
+            printf("%s rowlb[%i] = %g, rowub[%i] = %g\n",
+                   argPrefix, i, rowlb[i], i, rowub[i]);
+    }
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+}  // Cbc_printModel()
+
+COINLIBAPI int COINLINKAGE
+Cbc_isInteger(Cbc_Model * model, int i)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_isInteger(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    bool result = false;
+    result = model->model_->isInteger(i);
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return (result) ? 1 : 0;
+}
+
+COINLIBAPI double COINLINKAGE
+Cbc_cpuTime(Cbc_Model * /*model*/)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_cpuTime(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    double result = 0;
+    result = CoinCpuTime() ;
+
+    if (VERBOSE > 0) printf("%s return %g\n", prefix, result);
+    return result;
+}
+/** Number of nodes explored in B&B tree */
+COINLIBAPI int COINLINKAGE
+Cbc_getNodeCount(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_getNodeCount(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    int result = 0;
+    result = model->model_->getNodeCount() ;
+
+    if (VERBOSE > 0) printf("%s return %i\n", prefix, result);
+    return result;
+}
+/** Return a copy of this model */
+COINLIBAPI Cbc_Model * COINLINKAGE
+Cbc_clone(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_clone(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    Cbc_Model * result = new Cbc_Model;
+    result->model_     = new CbcModel(*(model->model_));
+    result->solver_    = dynamic_cast< OsiClpSolverInterface*> (result->model_->solver());
+    result->handler_   = NULL;
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return model;
+}
+/** Set this the variable to be continuous */
+COINLIBAPI Cbc_Model * COINLINKAGE
+Cbc_setContinuous(Cbc_Model * model, int iColumn)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_setContinuous(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->solver()->setContinuous(iColumn);
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return model;
+}
+/* Add an SOS constraint to the model */
+COINLIBAPI void  COINLINKAGE
+Cbc_addSOS_Dense(Cbc_Model * model, int numObjects, const int * len,
+                 const int * const* which, const double * weights, const int type)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_addSOS_Dense(): ";
+//  const int  VERBOSE = 2;
+    if (VERBOSE > 0) printf("%sbegin\n", prefix);
+
+    assert(1 > 0);// this is probably broken
+    int i, j;
+    // I think this is a different model due to overriding = operator
+    CbcModel m = *(model->model_);
+
+    CbcObject ** objects = new CbcObject * [numObjects];
+
+    if (VERBOSE > 1) printf("%s numObjects = %i\n", prefix, numObjects);
+    for (i = 0; i < numObjects; i++) {
+        if (VERBOSE > 1) {
+            printf("%s len[%i] = %i, identifier = %i, type = %i\n",
+                   prefix, i, len[i], i, type);
+            fflush(stdout);
+            for (j = 0; j < len[i]; j++) {
+                if (VERBOSE > 2 || j == 0 || j == (len[i] - 1)) {
+                    printf("%s which[%i][%i] = %d, weights[%i] = %g\n",
+                           prefix, i, j, which[i][j], j, weights[j]);
+                    fflush(stdout);
+                }
+            }
+        }
+
+        // Make a CbcSOS and assign it to objects
+        if (VERBOSE > 1) printf("%s len[%i] = %i\n", prefix, i, len[i]);
+        if (VERBOSE > 1) printf("%s new CbcSOS()\n", prefix);
+        // ***
+        objects[i] = new CbcSOS(model->model_, (int)(len[i]),
+                                (const int*)which[i], (const double*)weights, (int)i, (int)type);
+        // ***
+        if (objects[i] == NULL) {
+            printf("%s ERROR: objects[%i] == NULL\n", prefix, i);
+            fflush(stdout);
+            assert(objects[i] != NULL);
+        }
+    }
+    if (VERBOSE > 1) printf("%s calling addObjects()\n", prefix);
+    fflush(stdout);
+    model->model_->addObjects(numObjects, objects);
+    if (VERBOSE > 1) printf("%s finished addObjects()\n", prefix);
+
+    for (i = 0; i < numObjects; i++) delete objects[i];
+    delete [] objects;
+
+    if (VERBOSE > 0) printf("%sreturn\n", prefix);
+    return;
+}
+/** Add SOS constraints to the model using row-order matrix */
+COINLIBAPI void  COINLINKAGE
+Cbc_addSOS_Sparse(Cbc_Model * model, const int * rowStarts,
+                  const int * rowIndices, const double * weights, const int type)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_addSOS_Sparse(): ";
+//  const int  VERBOSE = 1;
+    if (VERBOSE > 0) printf("%sbegin\n", prefix);
+
+    int numRows = Cbc_numberRows(model);
+    if (VERBOSE > 0) printf("%s numRows = %i\n", prefix, numRows);
+
+    // The passed sparse matrix must have the same number of rows as the model
+    assert(numRows == Cbc_numberRows(model));
+
+    int row, i;
+    const int *colIndex;
+    const double *colWeight;
+
+    // loop on rows and count number of objects according to numWeights>0
+    int numObjects = 0;
+    for (row = 0; row < numRows; row++) {
+        if (VERBOSE > 2) {
+            printf("%s row = %i\n", prefix, row);
+            printf("%s rowStarts[%i] = %i\n", prefix, row, rowStarts[row]);
+            printf("%s rowStarts[%i+1] = %i\n", prefix, row, rowStarts[row+1]);
+            fflush(stdout);
+        }
+        const int numWeights = rowStarts[row+1] - rowStarts[row];
+        if (VERBOSE > 2) printf("%s  numWeights = %i\n", prefix, numWeights);
+        if (numWeights > 0) numObjects++;
+    }
+
+    // make objects
+    CbcObject ** objects = new CbcObject * [numObjects];
+//  if (VERBOSE>1) printf("%s numObjects = %i, objects = %X\n",prefix,numObjects,objects);
+
+    // loop on rows and make an object when numWeights>0
+    int objNum = 0;
+    for (row = 0; row < numRows; row++) {
+        if (VERBOSE > 2) {
+            printf("%s row = %i\n", prefix, row);
+            printf("%s rowStarts[%i] = %i\n", prefix, row, rowStarts[row]);
+            printf("%s rowStarts[%i+1] = %i\n", prefix, row, rowStarts[row+1]);
+        }
+        const int numWeights = rowStarts[row+1] - rowStarts[row];
+        if (VERBOSE > 2) printf("%s  numWeights = %i\n", prefix, numWeights);
+        colIndex    = rowIndices + rowStarts[row];
+        colWeight   = weights + rowStarts[row];
+        if (numWeights > 0) {
+            // Make a CbcSOS and assign it to objects
+            if (VERBOSE > 3) {
+                for (i = 0; i < numWeights; i++) {
+                    printf("%s  colIndex [%i] = %i\n", prefix, i, colIndex[i]);
+                    printf("%s  colWeight[%i] = %f\n", prefix, i, colWeight[i]);
+                }
+                fflush(stdout);
+            }
+            objects[objNum] = new CbcSOS(model->model_, (int)(numWeights),
+                                         (const int*)colIndex, (const double*)colWeight, (int)objNum, (int)type);
+//      if (VERBOSE>2) printf("%s objects[%i] = %X\n",prefix,objNum,objects[objNum]);
+            if (objects[objNum] == NULL) {
+                printf("%s ERROR: objects[%i] == NULL\n", prefix, objNum);
+                fflush(stdout);
+                assert(objects[objNum] != NULL);
+            }
+            objNum++;
+        }
+    }
+    if (VERBOSE > 2) {
+        printf("%s calling addObjects()\n", prefix);
+        /*
+            printf("%s numObjects = %i, objects = %X\n",prefix,numObjects,objects);
+            for (row=0; row<numObjects; row++)
+              printf("%s  objects[%i] = %X\n",prefix,row,objects[row]);
+        */
+    }
+    fflush(stdout);
+    model->model_->addObjects(numObjects, objects);
+    if (VERBOSE > 1) printf("%s finished addObjects()\n", prefix);
+
+    for (objNum = 0; objNum < numObjects; objNum++) delete objects[objNum];
+    delete [] objects;
+
+    if (VERBOSE > 0) printf("%sreturn\n", prefix);
+    return;
+}
+
+/** Delete all object information */
+COINLIBAPI void  COINLINKAGE
+Cbc_deleteObjects(Cbc_Model * model)
+{
+    const char prefix[] = "Cbc_C_Interface::Cbc_deleteObjects(): ";
+//  const int  VERBOSE = 2;
+    if (VERBOSE > 0) printf("%s begin\n", prefix);
+
+    model->model_->deleteObjects();
+
+    if (VERBOSE > 0) printf("%s return\n", prefix);
+    return;
+}
+
+/** Print the solution */
+COINLIBAPI void  COINLINKAGE
+Cbc_printSolution(Cbc_Model * model)
+{
+    {
+        //
+        //  Now to print out row solution.  The methods used return const
+        //  pointers - which is of course much more virtuous.
+        //
+        //  This version just does non-zero columns
+        //
+
+        // * Rows
+
+        int numberRows = Cbc_getNumRows(model);
+        int iRow;
+
+
+        const double * rowPrimal = Cbc_getRowActivity(model);
+        // * Alternatively getReducedCost(model)
+        const double * rowDual = Cbc_getRowPrice(model);
+        // * Alternatively getColLower(model)
+        const double * rowLower = Cbc_getRowLower(model);
+        // * Alternatively getColUpper(model)
+        const double * rowUpper = Cbc_getRowUpper(model);
+        printf("--------------------------------------\n");
+
+        // * If we have not kept names (parameter to readMps) this will be 0
+        //    assert(Cbc_lengthNames(model));
+
+        printf("                       Primal          Dual         Lower         Upper\n");
+        for (iRow = 0; iRow < numberRows; iRow++) {
+            double value;
+            value = rowPrimal[iRow];
+            if (value > 1.0e-8 || value < -1.0e-8) {
+                char name[20];
+                //      	Cbc_columnName(model,iColumn,name);
+                sprintf(name, "ROW%5i", iRow);
+                printf("%6d %8s", iRow, name);
+                printf(" %13g", rowPrimal[iRow]);
+                printf(" %13g", rowDual[iRow]);
+                printf(" %13g", rowLower[iRow]);
+                printf(" %13g", rowUpper[iRow]);
+                printf("\n");
+            }
+        }
+        printf("--------------------------------------\n");
+    }
+    {
+        //
+        //  Now to print out column solution.  The methods used return const
+        //  pointers - which is of course much more virtuous.
+        //
+        //  This version just does non-zero columns
+        //
+        //
+
+        // * Columns
+
+        int numberColumns = Cbc_numberColumns(model);
+        int iColumn;
+
+
+        // * Alternatively getColSolution(model)
+        const double * columnPrimal = Cbc_getColSolution(model);
+        // * Alternatively getReducedCost(model)
+        const double * columnDual = Cbc_getReducedCost(model);
+        // * Alternatively getColLower(model)
+        const double * columnLower = Cbc_getColLower(model);
+        // * Alternatively getColUpper(model)
+        const double * columnUpper = Cbc_getColUpper(model);
+        // * Alternatively getObjCoefficients(model)
+        const double * columnObjective = Cbc_getObjCoefficients(model);
+
+        const char * isInteger = Cbc_integerInformation(model);
+
+        printf("--------------------------------------\n");
+
+        // * If we have not kept names (parameter to readMps) this will be 0
+//    assert(Cbc_lengthNames(model));
+
+        printf("                       Primal          Dual         Lower         Upper          Cost     isInteger\n");
+        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+            double value;
+            value = columnPrimal[iColumn];
+            if (value > 1.0e-8 || value < -1.0e-8) {
+                char name[20];
+//      	Cbc_columnName(model,iColumn,name);
+                sprintf(name, "COL%5i", iColumn);
+                printf("%6d %8s", iColumn, name);
+                printf(" %13g", columnPrimal[iColumn]);
+                printf(" %13g", columnDual[iColumn]);
+                printf(" %13g", columnLower[iColumn]);
+                printf(" %13g", columnUpper[iColumn]);
+                printf(" %13g", columnObjective[iColumn]);
+                printf(" %13i", isInteger[iColumn]);
+                printf("\n");
+            }
+        }
+        printf("--------------------------------------\n");
+    }
+    if (0) Cbc_printModel(model, "cbc::main(): ");
+    return;
+}
+/** Dual initial solve */
+COINLIBAPI int COINLINKAGE
+Cbc_initialDualSolve(Cbc_Model * /*model*/)
+{
+    return 0;
+}
+/** Primal initial solve */
+COINLIBAPI int COINLINKAGE
+Cbc_initialPrimalSolve(Cbc_Model * /*model*/)
+{
+    return 0;
+}
+/** Dual algorithm - see ClpSimplexDual.hpp for method */
+COINLIBAPI int COINLINKAGE
+Cbc_dual(Cbc_Model * /*model*/, int /*ifValuesPass*/)
+{
+    return 0;
+}
+/** Primal algorithm - see ClpSimplexPrimal.hpp for method */
+COINLIBAPI int COINLINKAGE
+Cbc_primal(Cbc_Model * /*model*/, int /*ifValuesPass*/)
+{
+    return 0;
+}
+#if defined(__MWERKS__)
+#pragma export off
+#endif
+
diff --git a/cbits/coin/Cbc_C_Interface.h b/cbits/coin/Cbc_C_Interface.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Cbc_C_Interface.h
@@ -0,0 +1,666 @@
+/* $Id: Cbc_C_Interface.h 1902 2013-04-10 16:58:16Z stefan $ */
+/*
+  Copyright (C) 2004 International Business Machines Corporation and others.
+  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+#ifndef CbcModelC_H
+#define CbcModelC_H
+
+/* include all defines and ugly stuff */
+#include "Coin_C_defines.h"
+
+/** This is a first "C" interface to Cbc.
+    It is mostly similar to the "C" interface to Clp and
+    was contributed by Bob Entriken.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    /**@name Constructors and destructor
+       These do not have an exact analogue in C++.
+       The user does not need to know structure of Cbc_Model.
+
+       For all functions outside this group there is an exact C++
+       analogue created by taking the first parameter out, removing the Cbc_
+       from name and applying the method to an object of type ClpSimplex.
+    */
+    /*@{*/
+
+    /** Version */
+    COINLIBAPI double COINLINKAGE Cbc_getVersion()
+    ;
+    /** Default Cbc_Model constructor */
+    COINLIBAPI Cbc_Model * COINLINKAGE
+    Cbc_newModel()
+    ;
+    /** Cbc_Model Destructor */
+    COINLIBAPI void COINLINKAGE
+    Cbc_deleteModel(Cbc_Model * model)
+    ;
+    /*@}*/
+
+    /**@name Load model - loads some stuff and initializes others */
+    /*@{*/
+    /* Loads a problem (the constraints on the
+        rows are given by lower and upper bounds). If a pointer is NULL then the
+        following values are the default:
+        <ul>
+        <li> <code>colub</code>: all columns have upper bound infinity
+        <li> <code>collb</code>: all columns have lower bound 0
+        <li> <code>rowub</code>: all rows have upper bound infinity
+        <li> <code>rowlb</code>: all rows have lower bound -infinity
+        <li> <code>obj</code>: all variables have 0 objective coefficient
+        </ul>
+
+     Just like the other loadProblem() method except that the matrix is
+     given in a standard column major ordered format (without gaps).
+    */
+    COINLIBAPI void COINLINKAGE
+    Cbc_loadProblem (Cbc_Model * model,  const int numcols, const int numrows,
+                     const CoinBigIndex * start, const int* index,
+                     const double* value,
+                     const double* collb, const double* colub,
+                     const double* obj,
+                     const double* rowlb, const double* rowub)
+    ;
+    /** Read an mps file from the given filename */
+    COINLIBAPI int COINLINKAGE
+    Cbc_readMps(Cbc_Model * model, const char *filename)
+    ;
+    /** Write an mps file from the given filename */
+    COINLIBAPI void COINLINKAGE
+    Cbc_writeMps(Cbc_Model * model, const char *filename)
+    ;
+    /** Integer information */
+    COINLIBAPI char * COINLINKAGE
+    Cbc_integerInformation(Cbc_Model * model)
+    ;
+    /** Copy in integer information */
+    COINLIBAPI void COINLINKAGE
+    Cbc_copyInIntegerInformation(Cbc_Model * model, const char * information)
+    ;
+    /** Drop integer informations */
+    COINLIBAPI void COINLINKAGE
+    Cbc_deleteIntegerInformation(Cbc_Model * model)
+    ;
+    /** Resizes rim part of model  */
+    COINLIBAPI void COINLINKAGE
+    Cbc_resize (Cbc_Model * model, int newNumberRows, int newNumberColumns)
+    ;
+    /** Deletes rows */
+    COINLIBAPI void COINLINKAGE
+    Cbc_deleteRows(Cbc_Model * model, int number, const int * which)
+    ;
+    /** Add rows */
+    COINLIBAPI void COINLINKAGE
+    Cbc_addRows(Cbc_Model * model, const int number, const double * rowLower,
+                const double * rowUpper,
+                const int * rowStarts, const int * columns,
+                const double * elements)
+    ;
+
+    /** Deletes columns */
+    COINLIBAPI void COINLINKAGE
+    Cbc_deleteColumns(Cbc_Model * model, int number, const int * which)
+    ;
+    /** Add columns */
+    COINLIBAPI void COINLINKAGE
+    Cbc_addColumns(Cbc_Model * model, int number, const double * columnLower,
+                   const double * columnUpper,
+                   const double * objective,
+                   const int * columnStarts, const int * rows,
+                   const double * elements);
+    /** Drops names - makes lengthnames 0 and names empty */
+    COINLIBAPI void COINLINKAGE
+    Cbc_dropNames(Cbc_Model * model)
+    ;
+    /** Copies in names */
+    COINLIBAPI void COINLINKAGE
+    Cbc_copyNames(Cbc_Model * model, const char * const * rowNamesIn,
+                  const char * const * columnNamesIn)
+    ;
+
+    /*@}*/
+    /**@name gets and sets - you will find some synonyms at the end of this file */
+    /*@{*/
+    /** Number of rows */
+    COINLIBAPI int COINLINKAGE
+    Cbc_numberRows(Cbc_Model * model)
+    ;
+    /** Number of columns */
+    COINLIBAPI int COINLINKAGE
+    Cbc_numberColumns(Cbc_Model * model)
+    ;
+    /** Primal tolerance to use */
+    COINLIBAPI double COINLINKAGE
+    Cbc_primalTolerance(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setPrimalTolerance(Cbc_Model * model,  double value)
+    ;
+    /** Dual tolerance to use */
+    COINLIBAPI double COINLINKAGE
+    Cbc_dualTolerance(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setDualTolerance(Cbc_Model * model,  double value)
+    ;
+    /* Integer tolerance to use */
+    COINLIBAPI double COINLINKAGE
+    Cbc_integerTolerance(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setIntegerTolerance(Cbc_Model * model,  double value)
+    ;
+    /** Dual objective limit */
+    COINLIBAPI double COINLINKAGE
+    Cbc_dualObjectiveLimit(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setDualObjectiveLimit(Cbc_Model * model, double value)
+    ;
+    /** Objective offset */
+    COINLIBAPI double COINLINKAGE
+    Cbc_objectiveOffset(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setObjectiveOffset(Cbc_Model * model, double value)
+    ;
+    /** Fills in array with problem name  */
+    COINLIBAPI void COINLINKAGE
+    Cbc_problemName(Cbc_Model * model, int maxNumberCharacters, char * array)
+    ;
+    /** Sets problem name.
+    
+      \p array must be a null-terminated string.
+    */
+    COINLIBAPI int COINLINKAGE
+    Cbc_setProblemName(Cbc_Model * model, int maxNumberCharacters, char * array)
+    ;
+    /** Number of iterations */
+    COINLIBAPI int COINLINKAGE
+    Cbc_numberIterations(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setNumberIterations(Cbc_Model * model, int numberIterations)
+    ;
+    /** Maximum number of iterations */
+    COINLIBAPI int COINLINKAGE
+    Cbc_maximumIterations(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setMaximumIterations(Cbc_Model * model, int value)
+    ;
+    /** Maximum number of nodes */
+    COINLIBAPI int COINLINKAGE
+    Cbc_maxNumNode(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setMaxNumNode(Cbc_Model * model, int value)
+    ;
+    /* Maximum number of solutions */
+    COINLIBAPI int COINLINKAGE
+    Cbc_maxNumSol(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setMaxNumSol(Cbc_Model * model, int value)
+    ;
+    /** Maximum time in seconds (from when set called) */
+    COINLIBAPI double COINLINKAGE
+    Cbc_maximumSeconds(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setMaximumSeconds(Cbc_Model * model, double value)
+    ;
+    /** Returns true if hit maximum iterations (or time) */
+    COINLIBAPI int COINLINKAGE
+    Cbc_hitMaximumIterations(Cbc_Model * model)
+    ;
+    /** Status of problem:
+        0 - optimal
+        1 - primal infeasible
+        2 - dual infeasible
+        3 - stopped on iterations etc
+        4 - stopped due to errors
+    */
+    COINLIBAPI int COINLINKAGE
+    Cbc_status(Cbc_Model * model)
+    ;
+    /** Set problem status */
+    COINLIBAPI void COINLINKAGE
+    Cbc_setProblemStatus(Cbc_Model * model, int problemStatus)
+    ;
+    /** Secondary status of problem - may get extended
+        0 - none
+        1 - primal infeasible because dual limit reached
+        2 - scaled problem optimal - unscaled has primal infeasibilities
+        3 - scaled problem optimal - unscaled has dual infeasibilities
+        4 - scaled problem optimal - unscaled has both dual and primal infeasibilities
+    */
+    COINLIBAPI int COINLINKAGE
+    Cbc_secondaryStatus(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setSecondaryStatus(Cbc_Model * model, int status)
+    ;
+    /** Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+    COINLIBAPI double COINLINKAGE
+    Cbc_optimizationDirection(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setOptimizationDirection(Cbc_Model * model, double value)
+    ;
+    /** Primal row solution */
+    COINLIBAPI double * COINLINKAGE
+    Cbc_primalRowSolution(Cbc_Model * model)
+    ;
+    /** Primal column solution */
+    COINLIBAPI double * COINLINKAGE
+    Cbc_primalColumnSolution(Cbc_Model * model)
+    ;
+    /** Dual row solution */
+    COINLIBAPI double * COINLINKAGE
+    Cbc_dualRowSolution(Cbc_Model * model)
+    ;
+    /** Reduced costs */
+    COINLIBAPI double * COINLINKAGE
+    Cbc_dualColumnSolution(Cbc_Model * model)
+    ;
+    /** Row lower */
+    COINLIBAPI double* COINLINKAGE
+    Cbc_rowLower(Cbc_Model * model)
+    ;
+    /** Row upper  */
+    COINLIBAPI double* COINLINKAGE
+    Cbc_rowUpper(Cbc_Model * model)
+    ;
+    /** Objective */
+    COINLIBAPI double * COINLINKAGE
+    Cbc_objective(Cbc_Model * model)
+    ;
+    /** Column Lower */
+    COINLIBAPI double * COINLINKAGE
+    Cbc_columnLower(Cbc_Model * model)
+    ;
+    /** Column Upper */
+    COINLIBAPI double * COINLINKAGE
+    Cbc_columnUpper(Cbc_Model * model)
+    ;
+    /** Number of elements in matrix */
+    COINLIBAPI int COINLINKAGE
+    Cbc_getNumElements(Cbc_Model * model)
+    ;
+    /** Column starts in matrix */
+    COINLIBAPI const CoinBigIndex * COINLINKAGE
+    Cbc_getVectorStarts(Cbc_Model * model)
+    ;
+    /** Row indices in matrix */
+    COINLIBAPI const int * COINLINKAGE
+    Cbc_getIndices(Cbc_Model * model)
+    ;
+    /** Column vector lengths in matrix */
+    COINLIBAPI const int * COINLINKAGE
+    Cbc_getVectorLengths(Cbc_Model * model)
+    ;
+    /** Element values in matrix */
+    COINLIBAPI const double * COINLINKAGE
+    Cbc_getElements(Cbc_Model * model)
+    ;
+    /** Objective value */
+    COINLIBAPI double COINLINKAGE
+    Cbc_objectiveValue(Cbc_Model * model)
+    ;
+    /** Infeasibility/unbounded ray (NULL returned if none/wrong)
+        Up to user to use delete [] on these arrays.  */
+    COINLIBAPI double * COINLINKAGE
+    Cbc_infeasibilityRay(Cbc_Model * model)
+    ;
+    COINLIBAPI double * COINLINKAGE
+    Cbc_unboundedRay(Cbc_Model * model)
+    ;
+    /** See if status array exists (partly for OsiClp) */
+    COINLIBAPI int COINLINKAGE
+    Cbc_statusExists(Cbc_Model * model)
+    ;
+    /** Return address of status array (char[numberRows+numberColumns]) */
+    COINLIBAPI void  COINLINKAGE
+    Cbc_getBasisStatus(Cbc_Model * model, int * cstat, int * rstat)
+    ;
+    /** Copy in status vector */
+    COINLIBAPI void COINLINKAGE
+    Cbc_setBasisStatus(Cbc_Model * model, int * cstat, int * rstat)
+    ;
+
+    /** User pointer for whatever reason */
+    COINLIBAPI void COINLINKAGE
+    Cbc_setUserPointer (Cbc_Model * model, void * pointer)
+    ;
+    COINLIBAPI void * COINLINKAGE
+    Cbc_getUserPointer (Cbc_Model * model)
+    ;
+    /*@}*/
+    /**@name Message handling.  Call backs are handled by ONE function */
+    /*@{*/
+    /** Pass in Callback function.
+     Message numbers up to 1000000 are Clp, Coin ones have 1000000 added */
+    COINLIBAPI void COINLINKAGE
+    Cbc_registerCallBack(Cbc_Model * model,
+                         cbc_callback userCallBack)
+    ;
+    /** Unset Callback function */
+    COINLIBAPI void COINLINKAGE
+    Cbc_clearCallBack(Cbc_Model * model)
+    ;
+    /** Amount of print out:
+        0 - none
+        1 - just final
+        2 - just factorizations
+        3 - as 2 plus a bit more
+        4 - verbose
+        above that 8,16,32 etc just for selective debug
+    */
+    COINLIBAPI void COINLINKAGE
+    Cbc_setLogLevel(Cbc_Model * model, int value)
+    ;
+    COINLIBAPI int COINLINKAGE
+    Cbc_logLevel(Cbc_Model * model)
+    ;
+    /** length of names (0 means no names0 */
+    COINLIBAPI int COINLINKAGE
+    Cbc_lengthNames(Cbc_Model * model)
+    ;
+    /** Fill in array (at least lengthNames+1 long) with a row name */
+    COINLIBAPI void COINLINKAGE
+    Cbc_rowName(Cbc_Model * model, int iRow, char * name)
+    ;
+    /** Fill in array (at least lengthNames+1 long) with a column name */
+    COINLIBAPI void COINLINKAGE
+    Cbc_columnName(Cbc_Model * model, int iColumn, char * name)
+    ;
+
+    /*@}*/
+
+
+    /**@name Functions most useful to user */
+    /*@{*/
+    /** General solve algorithm which can do presolve.
+        See  ClpSolve.hpp for options
+     */
+    COINLIBAPI int COINLINKAGE
+    Cbc_initialSolve(Cbc_Model * model)
+    ;
+    /* General solve algorithm which can do presolve.
+       See  CbcModel.hpp for options
+    */
+    COINLIBAPI int COINLINKAGE
+    Cbc_branchAndBound(Cbc_Model * model)
+    ;
+    /** Sets or unsets scaling, 0 -off, 1 equilibrium, 2 geometric, 3, auto, 4 dynamic(later) */
+    COINLIBAPI void COINLINKAGE
+    Cbc_scaling(Cbc_Model * model, int mode)
+    ;
+    /** Gets scalingFlag */
+    COINLIBAPI int COINLINKAGE
+    Cbc_scalingFlag(Cbc_Model * model)
+    ;
+    /** Crash - at present just aimed at dual, returns
+        -2 if dual preferred and crash basis created
+        -1 if dual preferred and all slack basis preferred
+         0 if basis going in was not all slack
+         1 if primal preferred and all slack basis preferred
+         2 if primal preferred and crash basis created.
+
+         if gap between bounds <="gap" variables can be flipped
+
+         If "pivot" is
+         0 No pivoting (so will just be choice of algorithm)
+         1 Simple pivoting e.g. gub
+         2 Mini iterations
+    */
+    COINLIBAPI int COINLINKAGE
+    Cbc_crash(Cbc_Model * model, double gap, int pivot)
+    ;
+    /*@}*/
+
+
+    /**@name most useful gets and sets */
+    /*@{*/
+    /** If problem is primal feasible */
+    COINLIBAPI int COINLINKAGE
+    Cbc_primalFeasible(Cbc_Model * model)
+    ;
+    /** If problem is dual feasible */
+    COINLIBAPI int COINLINKAGE
+    Cbc_dualFeasible(Cbc_Model * model)
+    ;
+    /** Dual bound */
+    COINLIBAPI double COINLINKAGE
+    Cbc_dualBound(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setDualBound(Cbc_Model * model, double value)
+    ;
+    /** Infeasibility cost */
+    COINLIBAPI double COINLINKAGE
+    Cbc_infeasibilityCost(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setInfeasibilityCost(Cbc_Model * model, double value)
+    ;
+    /** Perturbation:
+        50  - switch on perturbation
+        100 - auto perturb if takes too long (1.0e-6 largest nonzero)
+        101 - we are perturbed
+        102 - don't try perturbing again
+        default is 100
+        others are for playing
+    */
+    COINLIBAPI int COINLINKAGE
+    Cbc_perturbation(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setPerturbation(Cbc_Model * model, int value)
+    ;
+    /** Current (or last) algorithm */
+    COINLIBAPI int COINLINKAGE
+    Cbc_algorithm(Cbc_Model * model)
+    ;
+    /** Set algorithm */
+    COINLIBAPI void COINLINKAGE
+    Cbc_setAlgorithm(Cbc_Model * model, int value)
+    ;
+    /** Sum of dual infeasibilities */
+    COINLIBAPI double COINLINKAGE
+    Cbc_sumDualInfeasibilities(Cbc_Model * model)
+    ;
+    /** Number of dual infeasibilities */
+    COINLIBAPI int COINLINKAGE
+    Cbc_numberDualInfeasibilities(Cbc_Model * model)
+    ;
+    /** Sum of primal infeasibilities */
+    COINLIBAPI double COINLINKAGE
+    Cbc_sumPrimalInfeasibilities(Cbc_Model * model)
+    ;
+    /** Number of primal infeasibilities */
+    COINLIBAPI int COINLINKAGE
+    Cbc_numberPrimalInfeasibilities(Cbc_Model * model)
+    ;
+    /** Save model to file, returns 0 if success.  This is designed for
+        use outside algorithms so does not save iterating arrays etc.
+    It does not save any messaging information.
+    Does not save scaling values.
+    It does not know about all types of virtual functions.
+    */
+    COINLIBAPI int COINLINKAGE
+    Cbc_saveModel(Cbc_Model * model, const char * fileName)
+    ;
+    /** Restore model from file, returns 0 if success,
+        deletes current model */
+    COINLIBAPI int COINLINKAGE
+    Cbc_restoreModel(Cbc_Model * model, const char * fileName)
+    ;
+
+    /** Just check solution (for external use) - sets sum of
+        infeasibilities etc */
+    COINLIBAPI void COINLINKAGE
+    Cbc_checkSolution(Cbc_Model * model)
+    ;
+    /*@}*/
+
+    /******************** End of most useful part **************/
+    /**@name gets and sets - some synonyms */
+    /*@{*/
+    /** Number of rows */
+    COINLIBAPI int COINLINKAGE
+    Cbc_getNumRows(Cbc_Model * model)
+    ;
+    /** Number of columns */
+    COINLIBAPI int COINLINKAGE
+    Cbc_getNumCols(Cbc_Model * model)
+    ;
+    /** Number of iterations */
+    COINLIBAPI int COINLINKAGE
+    Cbc_getIterationCount(Cbc_Model * model)
+    ;
+    /** Are there a numerical difficulties? */
+    COINLIBAPI int COINLINKAGE
+    Cbc_isAbandoned(Cbc_Model * model)
+    ;
+    /** Is optimality proven? */
+    COINLIBAPI int COINLINKAGE
+    Cbc_isProvenOptimal(Cbc_Model * model)
+    ;
+    /** Is primal infeasiblity proven? */
+    COINLIBAPI int COINLINKAGE
+    Cbc_isProvenPrimalInfeasible(Cbc_Model * model)
+    ;
+    /** Is dual infeasiblity proven? */
+    COINLIBAPI int COINLINKAGE
+    Cbc_isProvenDualInfeasible(Cbc_Model * model)
+    ;
+    /** Is the given primal objective limit reached? */
+    COINLIBAPI int COINLINKAGE
+    Cbc_isPrimalObjectiveLimitReached(Cbc_Model * model)
+    ;
+    /** Is the given dual objective limit reached? */
+    COINLIBAPI int COINLINKAGE
+    Cbc_isDualObjectiveLimitReached(Cbc_Model * model)
+    ;
+    /** Iteration limit reached? */
+    COINLIBAPI int COINLINKAGE
+    Cbc_isIterationLimitReached(Cbc_Model * model)
+    ;
+    /** Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+    COINLIBAPI double COINLINKAGE
+    Cbc_getObjSense(Cbc_Model * model)
+    ;
+    /** Primal row solution */
+    COINLIBAPI const double * COINLINKAGE
+    Cbc_getRowActivity(Cbc_Model * model)
+    ;
+    /** Primal column solution */
+    COINLIBAPI const double * COINLINKAGE
+    Cbc_getColSolution(Cbc_Model * model)
+    ;
+    COINLIBAPI void COINLINKAGE
+    Cbc_setColSolution(Cbc_Model * model, const double * input)
+    ;
+    /** Dual row solution */
+    COINLIBAPI const double * COINLINKAGE
+    Cbc_getRowPrice(Cbc_Model * model)
+    ;
+    /** Reduced costs */
+    COINLIBAPI const double * COINLINKAGE
+    Cbc_getReducedCost(Cbc_Model * model)
+    ;
+    /** Row lower */
+    COINLIBAPI const double* COINLINKAGE
+    Cbc_getRowLower(Cbc_Model * model)
+    ;
+    /** Row upper  */
+    COINLIBAPI const double* COINLINKAGE
+    Cbc_getRowUpper(Cbc_Model * model)
+    ;
+    /** Objective */
+    COINLIBAPI const double * COINLINKAGE
+    Cbc_getObjCoefficients(Cbc_Model * model)
+    ;
+    /** Column Lower */
+    COINLIBAPI const double * COINLINKAGE
+    Cbc_getColLower(Cbc_Model * model)
+    ;
+    /** Column Upper */
+    COINLIBAPI const double * COINLINKAGE
+    Cbc_getColUpper(Cbc_Model * model)
+    ;
+    /** Objective value */
+    COINLIBAPI double COINLINKAGE
+    Cbc_getObjValue(Cbc_Model * model)
+    ;
+    /** Print the model */
+    COINLIBAPI void COINLINKAGE
+    Cbc_printModel(Cbc_Model * model, const char * argPrefix)
+    ;
+    /** Determine whether the variable at location i is integer restricted */
+    COINLIBAPI int COINLINKAGE
+    Cbc_isInteger(Cbc_Model * model, int i)
+    ;
+    /** Return CPU time */
+    COINLIBAPI double COINLINKAGE
+    Cbc_cpuTime(Cbc_Model * model)
+    ;
+    /** Number of nodes explored in B&B tree */
+    COINLIBAPI int COINLINKAGE
+    Cbc_getNodeCount(Cbc_Model * model)
+    ;
+    /** Return a copy of this model */
+    COINLIBAPI Cbc_Model * COINLINKAGE
+    Cbc_clone(Cbc_Model * model)
+    ;
+    /** Set this the variable to be continuous */
+    COINLIBAPI Cbc_Model * COINLINKAGE
+    Cbc_setContinuous(Cbc_Model * model, int iColumn)
+    ;
+    /** Add SOS constraints to the model using dense matrix */
+    COINLIBAPI void  COINLINKAGE
+    Cbc_addSOS_Dense(Cbc_Model * model, int numObjects, const int * len,
+                     const int * const * which, const double * weights, const int type)
+    ;
+    /** Add SOS constraints to the model using row-order matrix */
+    COINLIBAPI void  COINLINKAGE
+    Cbc_addSOS_Sparse(Cbc_Model * model, const int * rowStarts,
+                      const int * rowIndices, const double * weights, const int type)
+    ;
+    /** Delete all object information */
+    COINLIBAPI void  COINLINKAGE
+    Cbc_deleteObjects(Cbc_Model * model)
+    ;
+    /** Print the solution */
+    COINLIBAPI void  COINLINKAGE
+    Cbc_printSolution(Cbc_Model * model)
+    ;
+    /** Dual initial solve */
+    COINLIBAPI int COINLINKAGE
+    Cbc_initialDualSolve(Cbc_Model * model)
+    ;
+    /** Primal initial solve */
+    COINLIBAPI int COINLINKAGE
+    Cbc_initialPrimalSolve(Cbc_Model * model)
+    ;
+    /** Dual algorithm - see ClpSimplexDual.hpp for method */
+    COINLIBAPI int COINLINKAGE
+    Cbc_dual(Cbc_Model * model, int ifValuesPass)
+    ;
+    /** Primal algorithm - see ClpSimplexPrimal.hpp for method */
+    COINLIBAPI int COINLINKAGE
+    Cbc_primal(Cbc_Model * model, int ifValuesPass)
+    ;
+    /*@}*/
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/cbits/coin/Cbc_ampl.cpp b/cbits/coin/Cbc_ampl.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Cbc_ampl.cpp
@@ -0,0 +1,1512 @@
+/* $Id: Cbc_ampl.cpp 1926 2013-05-24 10:19:49Z stefan $ */
+/****************************************************************
+Copyright (C) 1997-2000 Lucent Technologies
+Modifications for Coin -  Copyright (C) 2006, International Business Machines Corporation and others.
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+****************************************************************/
+
+/*! \file Cbc_ampl.cpp
+
+  Interface routines for AMPL.
+*/
+
+#include "CbcConfig.h"
+
+#ifdef COIN_HAS_ASL
+
+#ifdef HAVE_UNISTD_H
+# include "unistd.h"
+#endif
+#include "CoinUtilsConfig.h"
+#include "CoinHelperFunctions.hpp"
+#include "CoinModel.hpp"
+#include "CoinSort.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinMpsIO.hpp"
+#include "CoinFloatEqual.hpp"
+#ifdef COIN_HAS_CLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+#include "Cbc_ampl.h"
+extern "C" {
+# include "getstub.h"
+# include "asl_pfgh.h"
+}
+
+#include <string>
+#include <cassert>
+/* so decodePhrase and clpCheck can access */
+static ampl_info * saveInfo = NULL;
+// Set to 1 if algorithm found
+static char algFound[20] = "";
+static char*
+checkPhrase(Option_Info *oi, keyword *kw, char *v)
+{
+    if (strlen(v))
+        printf("string %s\n", v);
+    // Say algorithm found
+    strcpy(algFound, kw->desc);
+    return v;
+}
+static char*
+checkPhrase2(Option_Info *oi, keyword *kw, char *v)
+{
+    if (strlen(v))
+        printf("string %s\n", v);
+    // put out keyword
+    saveInfo->arguments = (char **) realloc(saveInfo->arguments, (saveInfo->numberArguments + 1) * sizeof(char *));
+    saveInfo->arguments[saveInfo->numberArguments++] = strdup(kw->desc);
+    return v;
+}
+static fint
+decodePhrase(char * phrase, ftnlen length)
+{
+    char * blank = strchr(phrase, ' ');
+    if (blank) {
+        /* split arguments */
+        *blank = '\0';
+        saveInfo->arguments = (char **) realloc(saveInfo->arguments, (saveInfo->numberArguments + 2) * sizeof(char *));
+        saveInfo->arguments[saveInfo->numberArguments++] = strdup(phrase);
+        *blank = ' ';
+        phrase = blank + 1; /* move on */
+        if (strlen(phrase))
+            saveInfo->arguments[saveInfo->numberArguments++] = strdup(phrase);
+    } else if (strlen(phrase)) {
+        saveInfo->arguments = (char **) realloc(saveInfo->arguments, (saveInfo->numberArguments + 1) * sizeof(char *));
+        saveInfo->arguments[saveInfo->numberArguments++] = strdup(phrase);
+    }
+    return 0;
+}
+static void
+sos_kludge(int nsos, int *sosbeg, double *sosref, int * sosind)
+{
+    // Adjust sosref if necessary to make monotonic increasing
+    int i, j, k;
+    // first sort
+    for (i = 0; i < nsos; i++) {
+        k = sosbeg[i];
+        int end = sosbeg[i+1];
+        CoinSort_2(sosref + k, sosref + end, sosind + k);
+    }
+    double t, t1;
+    for (i = j = 0; i++ < nsos; ) {
+        k = sosbeg[i];
+        t = sosref[j];
+        while (++j < k) {
+            t1 = sosref[j];
+            t += 1e-10;
+            if (t1 <= t)
+                sosref[j] = t1 = t + 1e-10;
+            t = t1;
+        }
+    }
+}
+static char xxxxxx[20];
+#define VP (char*)
+static keyword keywds[] = { /* must be sorted */
+    { const_cast<char*>("barrier"),  checkPhrase,  (char *) xxxxxx ,
+        const_cast<char*>("-barrier")},
+    { const_cast<char*>("dual"),     checkPhrase,  (char *) xxxxxx ,
+      const_cast<char*>("-dualsimplex")},
+    { const_cast<char*>("help"),     checkPhrase2, (char *) xxxxxx ,
+      const_cast<char*>("-?")},
+    { const_cast<char*>("initial"),  checkPhrase,  (char *) xxxxxx ,
+      const_cast<char*>("-initialsolve")},
+    { const_cast<char*>("max"),      checkPhrase2, (char *) xxxxxx ,
+      const_cast<char*>("-maximize")},
+    { const_cast<char*>("maximize"), checkPhrase2, (char *) xxxxxx ,
+      const_cast<char*>("-maximize")},
+    { const_cast<char*>("primal"),   checkPhrase,  (char *) xxxxxx ,
+      const_cast<char*>("-primalsimplex")},
+    { const_cast<char*>("quit"),     checkPhrase2, (char *) xxxxxx ,
+      const_cast<char*>("-quit")},
+    { const_cast<char*>("wantsol"),  WS_val,       NULL,
+      const_cast<char*>("write .sol file (without -AMPL)")}
+};
+static Option_Info Oinfo = {
+    const_cast<char*>("cbc"),
+    const_cast<char*>("CBC " CBC_VERSION),
+    const_cast<char*>("cbc_options"),
+    keywds,
+    nkeywds,
+    0,
+    0,
+    0,
+    decodePhrase,
+    0,
+    0,
+    0,
+    20130502
+};
+// strdup used to avoid g++ compiler warning
+static SufDecl suftab[] = {
+#ifdef JJF_ZERO
+    { const_cast<char*>("current"), 0, ASL_Sufkind_con | ASL_Sufkind_outonly },
+    { const_cast<char*>("current"), 0, ASL_Sufkind_var | ASL_Sufkind_outonly },
+    { const_cast<char*>("direction"), 0, ASL_Sufkind_var },
+    { const_cast<char*>("down"), 0, ASL_Sufkind_con | ASL_Sufkind_outonly },
+    { const_cast<char*>("down"), 0, ASL_Sufkind_var | ASL_Sufkind_outonly },
+    { const_cast<char*>("priority"), 0, ASL_Sufkind_var },
+#endif
+    { const_cast<char*>("cut"), 0, ASL_Sufkind_con },
+    { const_cast<char*>("direction"), 0, ASL_Sufkind_var },
+    { const_cast<char*>("downPseudocost"), 0, ASL_Sufkind_var | ASL_Sufkind_real },
+    { const_cast<char*>("priority"), 0, ASL_Sufkind_var },
+    { const_cast<char*>("ref"), 0, ASL_Sufkind_var | ASL_Sufkind_real },
+    { const_cast<char*>("sos"), 0, ASL_Sufkind_var },
+    { const_cast<char*>("sos"), 0, ASL_Sufkind_con },
+    { const_cast<char*>("sosno"), 0, ASL_Sufkind_var | ASL_Sufkind_real },
+    { const_cast<char*>("sosref"), 0, ASL_Sufkind_var | ASL_Sufkind_real },
+    { const_cast<char*>("special"), 0, ASL_Sufkind_var },
+    { const_cast<char*>("special"), 0, ASL_Sufkind_con },
+    /*{ const_cast<char*>("special"), 0, ASL_Sufkind_con },*/
+    { const_cast<char*>("sstatus"), 0, ASL_Sufkind_var, 0 },
+    { const_cast<char*>("sstatus"), 0, ASL_Sufkind_con, 0 },
+    { const_cast<char*>("upPseudocost"), 0, ASL_Sufkind_var | ASL_Sufkind_real }
+#ifdef JJF_ZERO
+    { const_cast<char*>("unbdd"), 0, ASL_Sufkind_var | ASL_Sufkind_outonly},
+    { const_cast<char*>("up"), 0, ASL_Sufkind_con | ASL_Sufkind_outonly },
+    { const_cast<char*>("up"), 0, ASL_Sufkind_var | ASL_Sufkind_outonly }
+#endif
+};
+#include "float.h"
+#include "limits.h"
+static ASL *asl = NULL;
+static FILE *nl = NULL;
+
+static void
+mip_stuff(void)
+{
+    int i;
+    double *pseudoUp, *pseudoDown;
+    int *priority, *direction;
+    // To label cuts (there will be other uses for special)
+    int *cut;
+    // To label special variables - at present 1= must be >= 1 or <= -1
+    int * special;
+    SufDesc *dpup, *dpdown, *dpri, *ddir, *dcut, *dspecial;
+
+    ddir = suf_get("direction", ASL_Sufkind_var);
+    direction = ddir->u.i;
+    dpri = suf_get("priority", ASL_Sufkind_var);
+    priority = dpri->u.i;
+    dspecial = suf_get("special", ASL_Sufkind_con);
+    dcut = suf_get("cut", ASL_Sufkind_con);
+    cut = dcut->u.i;
+    if (!cut) {
+        // try special
+        dcut = suf_get("special", ASL_Sufkind_con);
+        cut = dcut->u.i;
+    }
+    dspecial = suf_get("special", ASL_Sufkind_var);
+    special = dspecial->u.i;
+    dpdown = suf_get("downPseudocost", ASL_Sufkind_var);
+    pseudoDown = dpdown->u.r;
+    dpup = suf_get("upPseudocost", ASL_Sufkind_var);
+    pseudoUp = dpup->u.r;
+    assert(saveInfo);
+    int numberColumns = saveInfo->numberColumns;
+    if (direction) {
+        int baddir = 0;
+        saveInfo->branchDirection = (int *) malloc(numberColumns * sizeof(int));
+        for (i = 0; i < numberColumns; i++) {
+            int value = direction[i];
+            if (value < -1 || value > 1) {
+                baddir++;
+                value = 0;
+            }
+            saveInfo->branchDirection[i] = value;
+        }
+        if (baddir)
+            fprintf(Stderr,
+                    "Treating %d .direction values outside [-1, 1] as 0.\n",
+                    baddir);
+    }
+    if (priority) {
+        int badpri = 0;
+        saveInfo->priorities = (int *) malloc(numberColumns * sizeof(int));
+        for (i = 0; i < numberColumns; i++) {
+            int value = priority[i];
+            if (value < 0) {
+                badpri++;
+                value = 0;
+            }
+            saveInfo->priorities[i] = value;
+        }
+        if (badpri)
+            fprintf(Stderr,
+                    "Treating %d negative .priority values as 0\n",
+                    badpri);
+    }
+    if (special) {
+        int badspecial = 0;
+        saveInfo->special = (int *) malloc(numberColumns * sizeof(int));
+        for (i = 0; i < numberColumns; i++) {
+            int value = special[i];
+            if (value < 0) {
+                badspecial++;
+                value = 0;
+            }
+            saveInfo->special[i] = value;
+        }
+        if (badspecial)
+            fprintf(Stderr,
+                    "Treating %d negative special values as 0\n",
+                    badspecial);
+    }
+    int numberRows = saveInfo->numberRows;
+    if (cut) {
+        int badcut = 0;
+        saveInfo->cut = (int *) malloc(numberRows * sizeof(int));
+        for (i = 0; i < numberRows; i++) {
+            int value = cut[i];
+            if (value < 0) {
+                badcut++;
+                value = 0;
+            }
+            saveInfo->cut[i] = value;
+        }
+        if (badcut)
+            fprintf(Stderr,
+                    "Treating %d negative cut values as 0\n",
+                    badcut);
+    }
+    if (pseudoDown || pseudoUp) {
+        int badpseudo = 0;
+        if (!pseudoDown || !pseudoUp)
+            fprintf(Stderr,
+                    "Only one set of pseudocosts - assumed same\n");
+        saveInfo->pseudoDown = (double *) malloc(numberColumns * sizeof(double));
+        saveInfo->pseudoUp = (double *) malloc(numberColumns * sizeof(double));
+        for (i = 0; i < numberColumns; i++) {
+            double valueD = 0.0, valueU = 0.0;
+            if (pseudoDown) {
+                valueD = pseudoDown[i];
+                if (valueD < 0) {
+                    badpseudo++;
+                    valueD = 0.0;
+                }
+            }
+            if (pseudoUp) {
+                valueU = pseudoUp[i];
+                if (valueU < 0) {
+                    badpseudo++;
+                    valueU = 0.0;
+                }
+            }
+            if (!valueD)
+                valueD = valueU;
+            if (!valueU)
+                valueU = valueD;
+            saveInfo->pseudoDown[i] = valueD;
+            saveInfo->pseudoUp[i] = valueU;
+        }
+        if (badpseudo)
+            fprintf(Stderr,
+                    "Treating %d negative pseudoCosts as 0.0\n", badpseudo);
+    }
+}
+static void
+stat_map(int *stat, int n, int *map, int mx, const char *what)
+{
+    int bad, i, i1 = 0, j, j1 = 0;
+    static char badfmt[] = "Coin driver: %s[%d] = %d\n";
+
+    for (i = bad = 0; i < n; i++) {
+        if ((j = stat[i]) >= 0 && j <= mx)
+            stat[i] = map[j];
+        else {
+            stat[i] = 0;
+            i1 = i;
+            j1 = j;
+            if (!bad++)
+                fprintf(Stderr, badfmt, what, i, j);
+        }
+    }
+    if (bad > 1) {
+        if (bad == 2)
+            fprintf(Stderr, badfmt, what, i1, j1);
+        else
+            fprintf(Stderr,
+                    "Coin driver: %d messages about bad %s values suppressed.\n",
+                    bad - 1, what);
+    }
+}
+
+int
+readAmpl(ampl_info * info, int argc, char **argv, void ** coinModel)
+{
+    char *stub;
+    ograd *og;
+    int i;
+    SufDesc *csd;
+    SufDesc *rsd;
+    /*bool *basis, *lower;*/
+    /*double *LU, *c, lb, objadj, *rshift, *shift, t, ub, *x, *x0, *x1;*/
+    char * environment = getenv("cbc_options");
+    char tempBuffer[20];
+    double * obj;
+    double * columnLower;
+    double * columnUpper;
+    double * rowLower;
+    double * rowUpper;
+    char ** saveArgv = argv;
+    char fileName[1000];
+    if (argc > 1)
+        strcpy(fileName, argv[1]);
+    else
+        fileName[0] = '\0';
+    int nonLinearType = -1;
+    // testosi parameter - if >= 10 then go in through coinModel
+    for (i = 1; i < argc; i++) {
+        if (!strncmp(argv[i], "testosi", 7)) {
+            char * equals = strchr(argv[i], '=');
+            if (equals && atoi(equals + 1) >= 10 && atoi(equals + 1) <= 20) {
+                nonLinearType = atoi(equals + 1);
+                break;
+            }
+        }
+    }
+    int saveArgc = argc;
+    if (info->numberRows != -1234567)
+        memset(info, 0, sizeof(ampl_info)); // overwrite unless magic number set
+    /* save so can be accessed by decodePhrase */
+    saveInfo = info;
+    info->numberArguments = 0;
+    info->arguments = (char **) malloc(2 * sizeof(char *));
+    info->arguments[info->numberArguments++] = strdup("ampl");
+    info->arguments[info->numberArguments++] = strdup("cbc");
+    asl = ASL_alloc(ASL_read_f);
+    stub = getstub(&argv, &Oinfo);
+    if (!stub)
+        usage_ASL(&Oinfo, 1);
+    nl = jac0dim(stub, 0);
+    suf_declare(suftab, sizeof(suftab) / sizeof(SufDecl));
+
+    /* set A_vals to get the constraints column-wise (malloc so can be freed) */
+    A_vals = (double *) malloc(nzc * sizeof(double));
+    if (!A_vals) {
+        printf("no memory\n");
+        return 1;
+    }
+    /* say we want primal solution */
+    want_xpi0 = 1;
+    /* for basis info */
+    info->columnStatus = (int *) malloc(n_var * sizeof(int));
+    info->rowStatus = (int *) malloc(n_con * sizeof(int));
+    csd = suf_iput("sstatus", ASL_Sufkind_var, info->columnStatus);
+    rsd = suf_iput("sstatus", ASL_Sufkind_con, info->rowStatus);
+    if (!(nlvc + nlvo) && nonLinearType < 10) {
+        /* read linear model*/
+        f_read(nl, 0);
+        // see if any sos
+        if (true) {
+            char *sostype;
+            int nsosnz, *sosbeg, *sosind, * sospri;
+            double *sosref;
+            int nsos;
+            int i = ASL_suf_sos_explict_free;
+            int copri[2], **p_sospri;
+            copri[0] = 0;
+            copri[1] = 0;
+            p_sospri = &sospri;
+            nsos = suf_sos(i, &nsosnz, &sostype, p_sospri, copri,
+                           &sosbeg, &sosind, &sosref);
+            if (nsos) {
+                info->numberSos = nsos;
+                info->sosType = (char *) malloc(nsos);
+                info->sosPriority = (int *) malloc(nsos * sizeof(int));
+                info->sosStart = (int *) malloc((nsos + 1) * sizeof(int));
+                info->sosIndices = (int *) malloc(nsosnz * sizeof(int));
+                info->sosReference = (double *) malloc(nsosnz * sizeof(double));
+                sos_kludge(nsos, sosbeg, sosref, sosind);
+                for (int i = 0; i < nsos; i++) {
+                    char ichar = sostype[i];
+                    assert (ichar == '1' || ichar == '2');
+                    info->sosType[i] = static_cast<char>(ichar - '0');
+                }
+                memcpy(info->sosPriority, sospri, nsos*sizeof(int));
+                memcpy(info->sosStart, sosbeg, (nsos + 1)*sizeof(int));
+                memcpy(info->sosIndices, sosind, nsosnz*sizeof(int));
+                memcpy(info->sosReference, sosref, nsosnz*sizeof(double));
+            }
+        }
+
+        /*sos_finish(&specialOrderedInfo, 0, &j, 0, 0, 0, 0, 0);*/
+        Oinfo.uinfo = tempBuffer;
+        if (getopts(argv, &Oinfo))
+            return 1;
+        /* objective*/
+        obj = (double *) malloc(n_var * sizeof(double));
+        for (i = 0; i < n_var; i++)
+            obj[i] = 0.0;
+        if (n_obj) {
+            for (og = Ograd[0]; og; og = og->next)
+                obj[og->varno] = og->coef;
+        }
+        if (objtype[0])
+            info->direction = -1.0;
+        else
+            info->direction = 1.0;
+        info->offset = objconst(0);
+        /* Column bounds*/
+        columnLower = (double *) malloc(n_var * sizeof(double));
+        columnUpper = (double *) malloc(n_var * sizeof(double));
+        for (i = 0; i < n_var; i++) {
+            columnLower[i] = LUv[2*i];
+            if (columnLower[i] <= negInfinity)
+                columnLower[i] = -COIN_DBL_MAX;
+            columnUpper[i] = LUv[2*i+1];
+            if (columnUpper[i] >= Infinity)
+                columnUpper[i] = COIN_DBL_MAX;
+        }
+        /* Row bounds*/
+        rowLower = (double *) malloc(n_con * sizeof(double));
+        rowUpper = (double *) malloc(n_con * sizeof(double));
+        for (i = 0; i < n_con; i++) {
+            rowLower[i] = LUrhs[2*i];
+            if (rowLower[i] <= negInfinity)
+                rowLower[i] = -COIN_DBL_MAX;
+            rowUpper[i] = LUrhs[2*i+1];
+            if (rowUpper[i] >= Infinity)
+                rowUpper[i] = COIN_DBL_MAX;
+        }
+        info->numberRows = n_con;
+        info->numberColumns = n_var;
+        info->numberElements = nzc;
+        info->numberBinary = nbv;
+        info->numberIntegers = niv + nbv;
+        info->objective = obj;
+        info->rowLower = rowLower;
+        info->rowUpper = rowUpper;
+        info->columnLower = columnLower;
+        info->columnUpper = columnUpper;
+        info->starts = A_colstarts;
+        /*A_colstarts=NULL;*/
+        info->rows = A_rownos;
+        /*A_rownos=NULL;*/
+        info->elements = A_vals;
+        /*A_vals=NULL;*/
+        info->primalSolution = NULL;
+        /* put in primalSolution if exists */
+        if (X0) {
+            info->primalSolution = (double *) malloc(n_var * sizeof(double));
+            memcpy(info->primalSolution, X0, n_var*sizeof(double));
+        }
+        info->dualSolution = NULL;
+        if (niv + nbv > 0)
+            mip_stuff(); // get any extra info
+        if ((!(niv + nbv) && (csd->kind & ASL_Sufkind_input))
+                || (rsd->kind & ASL_Sufkind_input)) {
+            /* convert status - need info on map */
+            static int map[] = {1, 3, 1, 1, 2, 1, 1};
+            stat_map(info->columnStatus, n_var, map, 6, "incoming columnStatus");
+            stat_map(info->rowStatus, n_con, map, 6, "incoming rowStatus");
+        } else {
+            /* all slack basis */
+            // leave status for output */
+#ifdef JJF_ZERO
+            free(info->rowStatus);
+            info->rowStatus = NULL;
+            free(info->columnStatus);
+            info->columnStatus = NULL;
+#endif
+        }
+    } else {
+        // QP
+        // Add .nl if not there
+        if (!strstr(fileName, ".nl"))
+            strcat(fileName, ".nl");
+        CoinModel * model = new CoinModel((nonLinearType > 10) ? 2 : 1, fileName, info);
+        if (model->numberRows() > 0 || model->numberColumns() > 0)
+            *coinModel = (void *) model;
+        Oinfo.uinfo = tempBuffer;
+        if (getopts(argv, &Oinfo))
+            return 1;
+        Oinfo.wantsol = 1;
+        if (objtype[0])
+            info->direction = -1.0;
+        else
+            info->direction = 1.0;
+        model->setOptimizationDirection(info->direction);
+        info->offset = objconst(0);
+        info->numberRows = n_con;
+        info->numberColumns = n_var;
+        info->numberElements = nzc;
+        info->numberBinary = nbv;
+        int numberIntegers = niv + nlvci + nlvoi + nbv;
+        if (nlvci + nlvoi + nlvc + nlvo) {
+            // Non linear
+            // No idea if there are overlaps so compute
+            int numberIntegers = 0;
+            for ( i = 0; i < n_var; i++) {
+                if (model->columnIsInteger(i))
+                    numberIntegers++;
+            }
+        }
+        info->numberIntegers = numberIntegers;
+        // Say nonlinear if it is
+        info->nonLinear = nlvc + nlvo;
+        if (numberIntegers > 0) {
+            mip_stuff(); // get any extra info
+            if (info->cut)
+                model->setCutMarker(info->numberRows, info->cut);
+            if (info->priorities)
+                model->setPriorities(info->numberColumns, info->priorities);
+        }
+    }
+    /* add -solve - unless something there already
+     - also check for sleep=yes */
+    {
+        int found = 0;
+        int foundLog = 0;
+        int foundSleep = 0;
+        const char * something[] = {"solve", "branch", "duals", "primals", "user"};
+        for (i = 0; i < info->numberArguments; i++) {
+            unsigned int j;
+            const char * argument = info->arguments[i];
+            for (j = 0; j < sizeof(something) / sizeof(char *); j++) {
+                const char * check = something[j];
+                if (!strncmp(argument, check, sizeof(check))) {
+                    found = (int)(j + 1);
+                } else if (!strncmp(argument, "log", 3)) {
+                    foundLog = 1;
+                } else if (!strncmp(argument, "sleep", 5)) {
+                    foundSleep = 1;
+                }
+            }
+        }
+        if (foundLog) {
+            /* print options etc */
+            for (i = 0; i < saveArgc; i++)
+                printf("%s ", saveArgv[i]);
+            printf("\n");
+            if (environment)
+                printf("env %s\n", environment);
+            /*printf("%d rows %d columns %d elements\n",n_con,n_var,nzc);*/
+        }
+        if (!found) {
+            if (!strlen(algFound)) {
+                info->arguments = (char **) realloc(info->arguments, (info->numberArguments + 1) * sizeof(char *));
+                info->arguments[info->numberArguments++] = strdup("-solve");
+            } else {
+                // use algorithm from keyword
+                info->arguments = (char **) realloc(info->arguments, (info->numberArguments + 1) * sizeof(char *));
+                info->arguments[info->numberArguments++] = strdup(algFound);
+            }
+        }
+        if (foundSleep) {
+            /* let user copy .nl file */
+            fprintf(stderr, "You can copy .nl file %s for debug purposes or attach debugger\n", saveArgv[1]);
+            fprintf(stderr, "Type q to quit, anything else to continue\n");
+            int getChar = getc(stdin);
+            if (getChar == 'q' || getChar == 'Q')
+                exit(1);
+        }
+    }
+    /* add -quit */
+    info->arguments = (char **) realloc(info->arguments, (info->numberArguments + 1) * sizeof(char *));
+    info->arguments[info->numberArguments++] = strdup("-quit");
+    return 0;
+}
+void freeArrays1(ampl_info * info)
+{
+    free(info->objective);
+    info->objective = NULL;
+    free(info->rowLower);
+    info->rowLower = NULL;
+    free(info->rowUpper);
+    info->rowUpper = NULL;
+    free(info->columnLower);
+    info->columnLower = NULL;
+    free(info->columnUpper);
+    info->columnUpper = NULL;
+    /* this one not freed by ASL_free */
+    free(info->elements);
+    info->elements = NULL;
+    free(info->primalSolution);
+    info->primalSolution = NULL;
+    free(info->dualSolution);
+    info->dualSolution = NULL;
+    /*free(info->rowStatus);
+    info->rowStatus=NULL;
+    free(info->columnStatus);
+    info->columnStatus=NULL;*/
+}
+void freeArrays2(ampl_info * info)
+{
+    free(info->primalSolution);
+    info->primalSolution = NULL;
+    free(info->dualSolution);
+    info->dualSolution = NULL;
+    free(info->rowStatus);
+    info->rowStatus = NULL;
+    free(info->columnStatus);
+    info->columnStatus = NULL;
+    free(info->priorities);
+    info->priorities = NULL;
+    free(info->branchDirection);
+    info->branchDirection = NULL;
+    free(info->pseudoDown);
+    info->pseudoDown = NULL;
+    free(info->pseudoUp);
+    info->pseudoUp = NULL;
+    free(info->sosType);
+    info->sosType = NULL;
+    free(info->sosPriority);
+    info->sosPriority = NULL;
+    free(info->sosStart);
+    info->sosStart = NULL;
+    free(info->sosIndices);
+    info->sosIndices = NULL;
+    free(info->sosReference);
+    info->sosReference = NULL;
+    free(info->cut);
+    info->cut = NULL;
+    ASL_free(&asl);
+}
+void freeArgs(ampl_info * info)
+{
+    int i;
+    for ( i = 0; i < info->numberArguments; i++)
+        free(info->arguments[i]);
+    free(info->arguments);
+}
+int ampl_obj_prec()
+{
+    return obj_prec();
+}
+void writeAmpl(ampl_info * info)
+{
+    char buf[1000];
+    typedef struct {
+        const char *msg;
+        int code;
+        int wantObj;
+    } Sol_info;
+    static Sol_info solinfo[] = {
+        { "optimal solution",			000, 1 },
+        { "infeasible",     			200, 1 },
+        { "unbounded",	        		300, 0 },
+        { "iteration limit etc",			400, 1 },
+        { "solution limit",				401, 1 },
+        { "ran out of space",			500, 0 },
+        { "status unknown",				501, 1 },
+        { "bug!",					502, 0 },
+        { "best MIP solution so far restored",	101, 1 },
+        { "failed to restore best MIP solution",	503, 1 },
+        { "optimal (?) solution",			100, 1 }
+    };
+    /* convert status - need info on map */
+    static int map[] = {0, 3, 4, 1};
+    sprintf(buf, "%s %s", Oinfo.bsname, info->buffer);
+    solve_result_num = solinfo[info->problemStatus].code;
+    if (info->columnStatus) {
+        stat_map(info->columnStatus, n_var, map, 4, "outgoing columnStatus");
+        stat_map(info->rowStatus, n_con, map, 4, "outgoing rowStatus");
+        suf_iput("sstatus", ASL_Sufkind_var, info->columnStatus);
+        suf_iput("sstatus", ASL_Sufkind_con, info->rowStatus);
+    }
+    write_sol(buf, info->primalSolution, info->dualSolution, &Oinfo);
+}
+/* Read a problem from AMPL nl file
+ */
+CoinModel::CoinModel( int nonLinear, const char * fileName, const void * info)
+        :  CoinBaseModel(),
+        maximumRows_(0),
+        maximumColumns_(0),
+        numberElements_(0),
+        maximumElements_(0),
+        numberQuadraticElements_(0),
+        maximumQuadraticElements_(0),
+        rowLower_(NULL),
+        rowUpper_(NULL),
+        rowType_(NULL),
+        objective_(NULL),
+        columnLower_(NULL),
+        columnUpper_(NULL),
+        integerType_(NULL),
+        columnType_(NULL),
+        start_(NULL),
+        elements_(NULL),
+        packedMatrix_(NULL),
+        quadraticElements_(NULL),
+        sortIndices_(NULL),
+        sortElements_(NULL),
+        sortSize_(0),
+        sizeAssociated_(0),
+        associated_(NULL),
+        numberSOS_(0),
+        startSOS_(NULL),
+        memberSOS_(NULL),
+        typeSOS_(NULL),
+        prioritySOS_(NULL),
+        referenceSOS_(NULL),
+        priority_(NULL),
+        cut_(NULL),
+        moreInfo_(NULL),
+        type_(-1),
+	noNames_(false),
+        links_(0)
+{
+    problemName_ = "";
+    int status = 0;
+    if (!strcmp(fileName, "-") || !strcmp(fileName, "stdin")) {
+        // stdin
+    } else {
+        std::string name = fileName;
+        bool readable = fileCoinReadable(name);
+        if (!readable) {
+            std::cerr << "Unable to open file "
+                      << fileName << std::endl;
+            status = -1;
+        }
+    }
+    if (!status) {
+        gdb(nonLinear, fileName, info);
+    }
+}
+#ifdef JJF_ZERO
+static real
+qterm(ASL *asl, fint *colq, fint *rowq, real *delsq)
+{
+    double t, t1, *x, *x0, *xe;
+    fint *rq0, *rqe;
+
+    t = 0.;
+    x0 = x = X0;
+    xe = x + n_var;
+    rq0 = rowq;
+    while (x < xe) {
+        t1 = *x++;
+        rqe = rq0 + *++colq;
+        while (rowq < rqe)
+            t += t1 * x0[*rowq++]**delsq++;
+    }
+    return 0.5 * t;
+}
+#endif
+// stolen from IPopt with changes
+typedef struct {
+    double obj_sign_;
+    ASL_pfgh * asl_;
+    double * non_const_x_;
+    int * column_; // for jacobian
+    int * rowStart_;
+    double * gradient_;
+    double * constraintValues_;
+    int nz_h_full_; // number of nonzeros in hessian
+    int nerror_;
+    bool objval_called_with_current_x_;
+    bool conval_called_with_current_x_;
+    bool jacval_called_with_current_x_;
+} CbcAmplInfo;
+
+void
+CoinModel::gdb( int nonLinear, const char * fileName, const void * info)
+{
+    const ampl_info * amplInfo = (const ampl_info *) info;
+    ograd *og = NULL;
+    int i;
+    SufDesc *csd = NULL;
+    SufDesc *rsd = NULL;
+    /*bool *basis, *lower;*/
+    /*double *LU, *c, lb, objadj, *rshift, *shift, t, ub, *x, *x0, *x1;*/
+    //char tempBuffer[20];
+    double * objective = NULL;
+    double * columnLower = NULL;
+    double * columnUpper = NULL;
+    double * rowLower = NULL;
+    double * rowUpper = NULL;
+    int * columnStatus = NULL;
+    int * rowStatus = NULL;
+    int numberRows = -1;
+    int numberColumns = -1;
+    int numberElements = -1;
+    int numberBinary = -1;
+    int numberIntegers = -1;
+    int numberAllNonLinearBoth = 0;
+    int numberIntegerNonLinearBoth = 0;
+    int numberAllNonLinearConstraints = 0;
+    int numberIntegerNonLinearConstraints = 0;
+    int numberAllNonLinearObjective = 0;
+    int numberIntegerNonLinearObjective = 0;
+    double * primalSolution = NULL;
+    double direction = 1.0;
+    char * stub = strdup(fileName);
+    CoinPackedMatrix matrixByRow;
+    fint ** colqp = NULL;
+    int *z = NULL;
+    if (nonLinear == 0) {
+        // linear
+        asl = ASL_alloc(ASL_read_f);
+        nl = jac0dim(stub, 0);
+        free(stub);
+        suf_declare(suftab, sizeof(suftab) / sizeof(SufDecl));
+
+        /* set A_vals to get the constraints column-wise (malloc so can be freed) */
+        A_vals = (double *) malloc(nzc * sizeof(double));
+        if (!A_vals) {
+            printf("no memory\n");
+            return ;
+        }
+        /* say we want primal solution */
+        want_xpi0 = 1;
+        /* for basis info */
+        columnStatus = (int *) malloc(n_var * sizeof(int));
+        rowStatus = (int *) malloc(n_con * sizeof(int));
+        csd = suf_iput("sstatus", ASL_Sufkind_var, columnStatus);
+        rsd = suf_iput("sstatus", ASL_Sufkind_con, rowStatus);
+        /* read linear model*/
+        f_read(nl, 0);
+        // see if any sos
+        if (true) {
+            char *sostype;
+            int nsosnz, *sosbeg, *sosind, * sospri;
+            double *sosref;
+            int nsos;
+            int i = ASL_suf_sos_explict_free;
+            int copri[2], **p_sospri;
+            copri[0] = 0;
+            copri[1] = 0;
+            p_sospri = &sospri;
+            nsos = suf_sos(i, &nsosnz, &sostype, p_sospri, copri,
+                           &sosbeg, &sosind, &sosref);
+            if (nsos) {
+                abort();
+#ifdef JJF_ZERO
+                info->numberSos = nsos;
+                info->sosType = (char *) malloc(nsos);
+                info->sosPriority = (int *) malloc(nsos * sizeof(int));
+                info->sosStart = (int *) malloc((nsos + 1) * sizeof(int));
+                info->sosIndices = (int *) malloc(nsosnz * sizeof(int));
+                info->sosReference = (double *) malloc(nsosnz * sizeof(double));
+                sos_kludge(nsos, sosbeg, sosref, sosind);
+                for (int i = 0; i < nsos; i++) {
+                    int ichar = sostype[i];
+                    assert (ichar == '1' || ichar == '2');
+                    info->sosType[i] = ichar - '0';
+                }
+                memcpy(info->sosPriority, sospri, nsos*sizeof(int));
+                memcpy(info->sosStart, sosbeg, (nsos + 1)*sizeof(int));
+                memcpy(info->sosIndices, sosind, nsosnz*sizeof(int));
+                memcpy(info->sosReference, sosref, nsosnz*sizeof(double));
+#endif
+            }
+        }
+
+        /*sos_finish(&specialOrderedInfo, 0, &j, 0, 0, 0, 0, 0);*/
+        //Oinfo.uinfo = tempBuffer;
+        //if (getopts(argv, &Oinfo))
+        //return 1;
+        /* objective*/
+        objective = (double *) malloc(n_var * sizeof(double));
+        for (i = 0; i < n_var; i++)
+            objective[i] = 0.0;
+        if (n_obj) {
+            for (og = Ograd[0]; og; og = og->next)
+                objective[og->varno] = og->coef;
+        }
+        if (objtype[0])
+            direction = -1.0;
+        else
+            direction = 1.0;
+        objectiveOffset_ = objconst(0);
+        /* Column bounds*/
+        columnLower = (double *) malloc(n_var * sizeof(double));
+        columnUpper = (double *) malloc(n_var * sizeof(double));
+        for (i = 0; i < n_var; i++) {
+            columnLower[i] = LUv[2*i];
+            if (columnLower[i] <= negInfinity)
+                columnLower[i] = -COIN_DBL_MAX;
+            columnUpper[i] = LUv[2*i+1];
+            if (columnUpper[i] >= Infinity)
+                columnUpper[i] = COIN_DBL_MAX;
+        }
+        /* Row bounds*/
+        rowLower = (double *) malloc(n_con * sizeof(double));
+        rowUpper = (double *) malloc(n_con * sizeof(double));
+        for (i = 0; i < n_con; i++) {
+            rowLower[i] = LUrhs[2*i];
+            if (rowLower[i] <= negInfinity)
+                rowLower[i] = -COIN_DBL_MAX;
+            rowUpper[i] = LUrhs[2*i+1];
+            if (rowUpper[i] >= Infinity)
+                rowUpper[i] = COIN_DBL_MAX;
+        }
+        numberRows = n_con;
+        numberColumns = n_var;
+        numberElements = nzc;
+        numberBinary = nbv;
+        numberIntegers = niv;
+        /* put in primalSolution if exists */
+        if (X0) {
+            primalSolution = (double *) malloc(n_var * sizeof(double));
+            memcpy( primalSolution, X0, n_var*sizeof(double));
+        }
+        //double * dualSolution=NULL;
+        if (niv + nbv > 0)
+            mip_stuff(); // get any extra info
+        if ((!(niv + nbv) && (csd->kind & ASL_Sufkind_input))
+                || (rsd->kind & ASL_Sufkind_input)) {
+            /* convert status - need info on map */
+            static int map[] = {1, 3, 1, 1, 2, 1, 1};
+            stat_map(columnStatus, n_var, map, 6, "incoming columnStatus");
+            stat_map(rowStatus, n_con, map, 6, "incoming rowStatus");
+        } else {
+            /* all slack basis */
+            // leave status for output */
+#ifdef JJF_ZERO
+            free(rowStatus);
+            rowStatus = NULL;
+            free(columnStatus);
+            columnStatus = NULL;
+#endif
+        }
+        CoinPackedMatrix columnCopy(true, numberRows, numberColumns, numberElements,
+                                    A_vals, A_rownos, A_colstarts, NULL);
+        matrixByRow.reverseOrderedCopyOf(columnCopy);
+    } else if (nonLinear == 1) {
+        // quadratic
+        asl = ASL_alloc(ASL_read_fg);
+        nl = jac0dim(stub, (ftnlen) strlen(stub));
+        free(stub);
+        suf_declare(suftab, sizeof(suftab) / sizeof(SufDecl));
+        /* read  model*/
+        X0 = (double*) malloc(n_var * sizeof(double));
+        CoinZeroN(X0, n_var);
+        qp_read(nl, 0);
+        assert (n_obj == 1);
+        int nz = 1 + n_con;
+        colqp = (fint**) malloc(nz * (2 * sizeof(int*)
+                                      + sizeof(double*)));
+        fint ** rowqp = colqp + nz;
+        double ** delsqp = (double **)(rowqp + nz);
+        z = (int*) malloc(nz * sizeof(int));
+        for (i = 0; i <= n_con; i++) {
+            z[i] = nqpcheck(-i, rowqp + i, colqp + i, delsqp + i);
+        }
+        qp_opify();
+        /* objective*/
+        objective = (double *) malloc(n_var * sizeof(double));
+        for (i = 0; i < n_var; i++)
+            objective[i] = 0.0;
+        if (n_obj) {
+            for (og = Ograd[0]; og; og = og->next)
+                objective[og->varno] = og->coef;
+        }
+        if (objtype[0])
+            direction = -1.0;
+        else
+            direction = 1.0;
+        objectiveOffset_ = objconst(0);
+        /* Column bounds*/
+        columnLower = (double *) malloc(n_var * sizeof(double));
+        columnUpper = (double *) malloc(n_var * sizeof(double));
+        for (i = 0; i < n_var; i++) {
+            columnLower[i] = LUv[2*i];
+            if (columnLower[i] <= negInfinity)
+                columnLower[i] = -COIN_DBL_MAX;
+            columnUpper[i] = LUv[2*i+1];
+            if (columnUpper[i] >= Infinity)
+                columnUpper[i] = COIN_DBL_MAX;
+        }
+        // Build by row from scratch
+        //matrixByRow.reserve(n_var,nzc,true);
+        // say row orderded
+        matrixByRow.transpose();
+        /* Row bounds*/
+        rowLower = (double *) malloc(n_con * sizeof(double));
+        rowUpper = (double *) malloc(n_con * sizeof(double));
+        CoinBigIndex * rowStart = new CoinBigIndex [n_con+1];
+        int * column = new int [nzc];
+        double * element = new double [nzc];
+        rowStart[0] = 0;
+        numberElements = 0;
+        for (i = 0; i < n_con; i++) {
+            rowLower[i] = LUrhs[2*i];
+            if (rowLower[i] <= negInfinity)
+                rowLower[i] = -COIN_DBL_MAX;
+            rowUpper[i] = LUrhs[2*i+1];
+            if (rowUpper[i] >= Infinity)
+                rowUpper[i] = COIN_DBL_MAX;
+            for (cgrad * cg = Cgrad[i]; cg; cg = cg->next) {
+                column[numberElements] = cg->varno;
+                element[numberElements++] = cg->coef;
+            }
+            rowStart[i+1] = numberElements;
+        }
+        assert (numberElements == nzc);
+        matrixByRow.appendRows(n_con, rowStart, column, element);
+        delete [] rowStart;
+        delete [] column;
+        delete [] element;
+        numberRows = n_con;
+        numberColumns = n_var;
+        //numberElements=nzc;
+        numberBinary = nbv;
+        numberIntegers = niv;
+        numberAllNonLinearBoth = nlvb;
+        numberIntegerNonLinearBoth = nlvbi;
+        numberAllNonLinearConstraints = nlvc;
+        numberIntegerNonLinearConstraints = nlvci;
+        numberAllNonLinearObjective = nlvo;
+        numberIntegerNonLinearObjective = nlvoi;
+        /* say we want primal solution */
+        want_xpi0 = 1;
+        //double * dualSolution=NULL;
+        // save asl
+        // Fix memory leak one day
+        CbcAmplInfo * info = new CbcAmplInfo;
+        //amplGamsData_ = info;
+        info->asl_ = NULL; // as wrong form asl;
+        info->nz_h_full_ = -1; // number of nonzeros in hessian
+        info->objval_called_with_current_x_ = false;
+        info->nerror_ = 0;
+        info->obj_sign_ = direction;
+        info->conval_called_with_current_x_ = false;
+        info->non_const_x_ = NULL;
+        info->jacval_called_with_current_x_ = false;
+        info->rowStart_ = NULL;
+        info->column_ = NULL;
+        info->gradient_ = NULL;
+        info->constraintValues_ = NULL;
+    } else if (nonLinear == 2) {
+        // General nonlinear!
+        //ASL_pfgh* asl = (ASL_pfgh*)ASL_alloc(ASL_read_pfgh);
+        asl = ASL_alloc(ASL_read_pfgh);
+        nl = jac0dim(stub, (ftnlen) strlen(stub));
+        free(stub);
+        suf_declare(suftab, sizeof(suftab) / sizeof(SufDecl));
+        /* read  model*/
+        X0 = (double*) malloc(n_var * sizeof(double));
+        CoinZeroN(X0, n_var);
+        // code stolen from Ipopt
+        int retcode = pfgh_read(nl, ASL_return_read_err | ASL_findgroups);
+
+        switch (retcode) {
+        case ASL_readerr_none : {}
+        break;
+        case ASL_readerr_nofile : {
+            printf( "Cannot open .nl file\n");
+            exit(-1);
+        }
+        break;
+        case ASL_readerr_nonlin : {
+            assert(false); // this better not be an error!
+            printf( "model involves nonlinearities (ed0read)\n");
+            exit(-1);
+        }
+        break;
+        case  ASL_readerr_argerr : {
+            printf( "user-defined function with bad args\n");
+            exit(-1);
+        }
+        break;
+        case ASL_readerr_unavail : {
+            printf( "user-defined function not available\n");
+            exit(-1);
+        }
+        break;
+        case ASL_readerr_corrupt : {
+            printf( "corrupt .nl file\n");
+            exit(-1);
+        }
+        break;
+        case ASL_readerr_bug : {
+            printf( "bug in .nl reader\n");
+            exit(-1);
+        }
+        break;
+        case ASL_readerr_CLP : {
+            printf( "ASL error message: \"solver cannot handle CLP extensions\"\n");
+            exit(-1);
+        }
+        break;
+        default: {
+            printf( "Unknown error in stub file read. retcode = %d\n", retcode);
+            exit(-1);
+        }
+        break;
+        }
+
+        // see "changes" in solvers directory of ampl code...
+        hesset(1, 0, 1, 0, nlc);
+
+        assert (n_obj == 1);
+        // find the nonzero structure for the hessian
+        // parameters to sphsetup:
+        int coeff_obj = 1; // coefficient of the objective fn ???
+        int mult_supplied = 1; // multipliers will be supplied
+        int uptri = 1; // only need the upper triangular part
+        // save asl
+        // Fix memory leak one day
+        CbcAmplInfo * info = new CbcAmplInfo;
+        moreInfo_ = (void *) info;
+        //amplGamsData_ = info;
+        info->asl_ = (ASL_pfgh *) asl;
+        // This is not easy to get from ampl so save
+        info->nz_h_full_ = sphsetup(-1, coeff_obj, mult_supplied, uptri);
+        info->objval_called_with_current_x_ = false;
+        info->nerror_ = 0;
+        info->obj_sign_ = direction;
+        info->conval_called_with_current_x_ = false;
+        info->non_const_x_ = NULL;
+        info->jacval_called_with_current_x_ = false;
+        // Look at nonlinear
+        if (nzc) {
+            n_conjac[1] = nlc; // just nonlinear
+            int * rowStart = new int [nlc+1];
+            info->rowStart_ = rowStart;
+            // See how many
+            int  current_nz = 0;
+            for (int i = 0; i < nlc; i++) {
+                for (cgrad* cg = Cgrad[i]; cg; cg = cg->next) {
+                    current_nz++;
+                }
+            }
+            // setup the structure
+            int * column = new int [current_nz];
+            info->column_ = column;
+            current_nz = 0;
+            rowStart[0] = 0;
+            for (int i = 0; i < nlc; i++) {
+                for (cgrad* cg = Cgrad[i]; cg; cg = cg->next) {
+                    cg->goff = current_nz;
+                    //iRow[cg->goff] = i ;
+                    //jCol[cg->goff] = cg->varno + 1;
+                    column[cg->goff] = cg->varno ;
+                    current_nz++;
+                }
+                rowStart[i+1] = current_nz;
+            }
+            info->gradient_ = new double [nzc];
+            info->constraintValues_ = new double [nlc];
+        }
+        /* objective*/
+        objective = (double *) malloc(n_var * sizeof(double));
+        for (i = 0; i < n_var; i++)
+            objective[i] = 0.0;
+        if (n_obj) {
+            for (og = Ograd[0]; og; og = og->next)
+                objective[og->varno] = og->coef;
+        }
+        if (objtype[0])
+            direction = -1.0;
+        else
+            direction = 1.0;
+        objectiveOffset_ = objconst(0);
+        /* Column bounds*/
+        columnLower = (double *) malloc(n_var * sizeof(double));
+        columnUpper = (double *) malloc(n_var * sizeof(double));
+        for (i = 0; i < n_var; i++) {
+            columnLower[i] = LUv[2*i];
+            if (columnLower[i] <= negInfinity)
+                columnLower[i] = -COIN_DBL_MAX;
+            columnUpper[i] = LUv[2*i+1];
+            if (columnUpper[i] >= Infinity)
+                columnUpper[i] = COIN_DBL_MAX;
+        }
+        // Build by row from scratch
+        //matrixByRow.reserve(n_var,nzc,true);
+        // say row orderded
+        matrixByRow.transpose();
+        CoinBigIndex * rowStart = new CoinBigIndex [n_con+1];
+        int * column = new int [nzc];
+        double * element = new double [nzc];
+        rowStart[0] = 0;
+        numberElements = 0;
+        /* Row bounds*/
+        rowLower = (double *) malloc(n_con * sizeof(double));
+        rowUpper = (double *) malloc(n_con * sizeof(double));
+        for (i = 0; i < n_con; i++) {
+            rowLower[i] = LUrhs[2*i];
+            if (rowLower[i] <= negInfinity)
+                rowLower[i] = -COIN_DBL_MAX;
+            rowUpper[i] = LUrhs[2*i+1];
+            if (rowUpper[i] >= Infinity)
+                rowUpper[i] = COIN_DBL_MAX;
+            for (cgrad * cg = Cgrad[i]; cg; cg = cg->next) {
+                column[numberElements] = cg->varno;
+                double value = cg->coef;
+                if (!value)
+                    value = -1.2345e-29;
+                element[numberElements++] = value;
+            }
+            rowStart[i+1] = numberElements;
+        }
+        assert (numberElements == nzc);
+        matrixByRow.appendRows(n_con, rowStart, column, element);
+        delete [] rowStart;
+        delete [] column;
+        delete [] element;
+        numberRows = n_con;
+        numberColumns = n_var;
+        numberElements = nzc;
+        numberBinary = nbv;
+        numberIntegers = niv;
+        numberAllNonLinearBoth = nlvb;
+        numberIntegerNonLinearBoth = nlvbi;
+        numberAllNonLinearConstraints = nlvc;
+        numberIntegerNonLinearConstraints = nlvci;
+        numberAllNonLinearObjective = nlvo;
+        numberIntegerNonLinearObjective = nlvoi;
+        /* say we want primal solution */
+        want_xpi0 = 1;
+        //double * dualSolution=NULL;
+    } else {
+        abort();
+    }
+    // set problem name
+    problemName_ = "???";
+
+    // Build by row from scratch
+    const double * element = matrixByRow.getElements();
+    const int * column = matrixByRow.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+    const int * rowLength = matrixByRow.getVectorLengths();
+    for (i = 0; i < numberRows; i++) {
+        addRow(rowLength[i], column + rowStart[i],
+               element + rowStart[i], rowLower[i], rowUpper[i]);
+    }
+    // Now do column part
+    for (i = 0; i < numberColumns; i++) {
+        setColumnBounds(i, columnLower[i], columnUpper[i]);
+        setColumnObjective(i, objective[i]);
+    }
+    for ( i = numberColumns - numberBinary - numberIntegers;
+            i < numberColumns; i++) {
+        setColumnIsInteger(i, true);
+    }
+    // and non linear
+    for (i = numberAllNonLinearBoth - numberIntegerNonLinearBoth;
+            i < numberAllNonLinearBoth; i++) {
+        setColumnIsInteger(i, true);
+    }
+    for (i = numberAllNonLinearConstraints - numberIntegerNonLinearConstraints;
+            i < numberAllNonLinearConstraints; i++) {
+        setColumnIsInteger(i, true);
+    }
+    for (i = numberAllNonLinearObjective - numberIntegerNonLinearObjective;
+            i < numberAllNonLinearObjective; i++) {
+        setColumnIsInteger(i, true);
+    }
+    free(columnLower);
+    free(columnUpper);
+    free(rowLower);
+    free(rowUpper);
+    free(objective);
+    // do names
+    int iRow;
+    for (iRow = 0; iRow < numberRows_; iRow++) {
+        char name[9];
+        sprintf(name, "r%7.7d", iRow);
+        setRowName(iRow, name);
+    }
+    int iColumn;
+    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+        char name[9];
+        sprintf(name, "c%7.7d", iColumn);
+        setColumnName(iColumn, name);
+    }
+    if (colqp) {
+        // add in quadratic
+        int nz = 1 + n_con;
+        int nOdd = 0;
+        fint ** rowqp = colqp + nz;
+        double ** delsqp = (double **)(rowqp + nz);
+        for (i = 0; i <= n_con; i++) {
+            int nels = z[i];
+            if (nels) {
+                double * element = delsqp[i];
+                int * start = (int *) colqp[i];
+                int * row = (int *) rowqp[i];
+                if (!element) {
+                    // odd row - probably not quadratic
+                    nOdd++;
+                    continue;
+                }
+#ifdef JJF_ZERO
+                printf("%d quadratic els\n", nels);
+                for (int j = 0; j < n_var; j++) {
+                    for (int k = start[j]; k < start[j+1]; k++)
+                        printf("%d %d %g\n", j, row[k], element[k]);
+                }
+#endif
+                if (i) {
+                    int iRow = i - 1;
+                    for (int j = 0; j < n_var; j++) {
+                        for (int k = start[j]; k < start[j+1]; k++) {
+                            int kColumn = row[k];
+                            double value = element[k];
+                            // ampl gives twice with assumed 0.5
+                            if (kColumn < j)
+                                continue;
+                            else if (kColumn == j)
+                                value *= 0.5;
+                            const char * expr = getElementAsString(iRow, j);
+                            double constant = 0.0;
+                            bool linear;
+                            if (expr && strcmp(expr, "Numeric")) {
+                                linear = false;
+                            } else {
+                                constant = getElement(iRow, j);
+                                linear = true;
+                            }
+                            char temp[1000];
+                            char temp2[30];
+                            if (value == 1.0)
+                                sprintf(temp2, "c%7.7d", kColumn);
+                            else
+                                sprintf(temp2, "%g*c%7.7d", value, kColumn);
+                            if (linear) {
+                                if (!constant)
+                                    strcpy(temp, temp2);
+                                else if (value > 0.0)
+                                    sprintf(temp, "%g+%s", constant, temp2);
+                                else
+                                    sprintf(temp, "%g%s", constant, temp2);
+                            } else {
+                                if (value > 0.0)
+                                    sprintf(temp, "%s+%s", expr, temp2);
+                                else
+                                    sprintf(temp, "%s%s", expr, temp2);
+                            }
+                            assert (strlen(temp) < 1000);
+                            setElement(iRow, j, temp);
+                            if (amplInfo->logLevel > 1)
+                                printf("el for row %d column c%7.7d is %s\n", iRow, j, temp);
+                        }
+                    }
+                } else {
+                    // objective
+                    for (int j = 0; j < n_var; j++) {
+                        for (int k = start[j]; k < start[j+1]; k++) {
+                            int kColumn = row[k];
+                            double value = element[k];
+                            // ampl gives twice with assumed 0.5
+                            if (kColumn < j)
+                                continue;
+                            else if (kColumn == j)
+                                value *= 0.5;
+                            const char * expr = getColumnObjectiveAsString(j);
+                            double constant = 0.0;
+                            bool linear;
+                            if (expr && strcmp(expr, "Numeric")) {
+                                linear = false;
+                            } else {
+                                constant = getColumnObjective(j);
+                                linear = true;
+                            }
+                            char temp[1000];
+                            char temp2[30];
+                            if (value == 1.0)
+                                sprintf(temp2, "c%7.7d", kColumn);
+                            else
+                                sprintf(temp2, "%g*c%7.7d", value, kColumn);
+                            if (linear) {
+                                if (!constant)
+                                    strcpy(temp, temp2);
+                                else if (value > 0.0)
+                                    sprintf(temp, "%g+%s", constant, temp2);
+                                else
+                                    sprintf(temp, "%g%s", constant, temp2);
+                            } else {
+                                if (value > 0.0)
+                                    sprintf(temp, "%s+%s", expr, temp2);
+                                else
+                                    sprintf(temp, "%s%s", expr, temp2);
+                            }
+                            assert (strlen(temp) < 1000);
+                            setObjective(j, temp);
+                            if (amplInfo->logLevel > 1)
+                                printf("el for objective column c%7.7d is %s\n", j, temp);
+                        }
+                    }
+                }
+            }
+        }
+        if (nOdd) {
+            printf("%d non-linear constraints could not be converted to quadratic\n", nOdd);
+            exit(77);
+        }
+    }
+    free(colqp);
+    free(z);
+    // see if any sos
+    {
+        char *sostype;
+        int nsosnz, *sosbeg, *sosind, * sospri;
+        double *sosref;
+        int nsos;
+        int i = ASL_suf_sos_explict_free;
+        int copri[2], **p_sospri;
+        copri[0] = 0;
+        copri[1] = 0;
+        p_sospri = &sospri;
+        nsos = suf_sos(i, &nsosnz, &sostype, p_sospri, copri,
+                       &sosbeg, &sosind, &sosref);
+        if (nsos) {
+            numberSOS_ = nsos;
+            typeSOS_ = new int [numberSOS_];
+            prioritySOS_ = new int [numberSOS_];
+            startSOS_ = new int [numberSOS_+1];
+            memberSOS_ = new int[nsosnz];
+            referenceSOS_ = new double [nsosnz];
+            sos_kludge(nsos, sosbeg, sosref, sosind);
+            for (int i = 0; i < nsos; i++) {
+                int ichar = sostype[i];
+                assert (ichar == '1' || ichar == '2');
+                typeSOS_[i] = ichar - '0';
+            }
+            memcpy(prioritySOS_, sospri, nsos*sizeof(int));
+            memcpy(startSOS_, sosbeg, (nsos + 1)*sizeof(int));
+            memcpy(memberSOS_, sosind, nsosnz*sizeof(int));
+            memcpy(referenceSOS_, sosref, nsosnz*sizeof(double));
+        }
+    }
+}
+#else
+#include "Cbc_ampl.h"
+int
+readAmpl(ampl_info * , int , char **, void ** )
+{
+    return 0;
+}
+void freeArrays1(ampl_info *)
+{
+}
+void freeArrays2(ampl_info *)
+{
+}
+void freeArgs(ampl_info * )
+{
+}
+int ampl_obj_prec()
+{
+    return 0;
+}
+void writeAmpl(ampl_info * )
+{
+}
+#endif
+
diff --git a/cbits/coin/Cbc_ampl.h b/cbits/coin/Cbc_ampl.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Cbc_ampl.h
@@ -0,0 +1,70 @@
+/* $Id: Cbc_ampl.h 1573 2011-01-05 01:12:36Z lou $ */
+/*
+  Copyright (C) 2006, International Business Machines Corporation and others.
+  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+
+#ifndef AmplInterface_H
+#define AmplInterface_H
+typedef struct {
+    int numberRows;
+    int numberColumns;
+    int numberBinary;
+    int numberIntegers; /* non binary */
+    int numberSos;
+    int numberElements;
+    int numberArguments;
+    int problemStatus;
+    double direction;
+    double offset;
+    double objValue;
+    double * objective;
+    double * rowLower;
+    double * rowUpper;
+    double * columnLower;
+    double * columnUpper;
+    int * starts;
+    int * rows;
+    double * elements;
+    double * primalSolution;
+    double * dualSolution;
+    int * columnStatus;
+    int * rowStatus;
+    int * priorities;
+    int * branchDirection;
+    double * pseudoDown;
+    double * pseudoUp;
+    char * sosType;
+    int * sosPriority;
+    int * sosStart;
+    int * sosIndices;
+    double * sosReference;
+    int * cut;
+    int * special;
+    char ** arguments;
+    char buffer[300];
+    int logLevel;
+    int nonLinear;
+} ampl_info;
+#ifdef __cplusplus
+extern "C" {
+#endif
+    /* return nonzero if bad */
+    int readAmpl(ampl_info * info, int argc, char ** argv,
+    void ** coinModel);
+    /* frees some input arrays */
+    void freeArrays1(ampl_info * info);
+    /* frees rest */
+    void freeArrays2(ampl_info * info);
+    /* frees fake arguments */
+    void freeArgs(ampl_info * info);
+    /* writes ampl stuff */
+    void writeAmpl(ampl_info * info);
+    /* objective precision */
+    int ampl_obj_prec();
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/cbits/coin/Cgl012cut.cpp b/cbits/coin/Cgl012cut.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Cgl012cut.cpp
@@ -0,0 +1,3797 @@
+// $Id: Cgl012cut.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2010, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/** @file 012cut.c Definition file for C coded 0-1/2 separator */
+#include "CoinFinite.hpp"
+#include "CoinTime.hpp"
+#include "Cgl012cut.hpp"
+#include "CglZeroHalf.hpp"
+int MAX_CUTS = 1000;
+//#define PRINT_TABU
+//#define PRINT_CUTS
+//#define PRINT_TIME
+//#define TIME
+
+/* #define TIME  */
+#undef TIME
+
+#define TRUE 1
+#define FALSE 0
+
+#define ODD 1
+#define EVEN 0
+
+#define NONE -1
+#define BOTH 2
+
+#define IN 1
+#define OUT 0
+#define ADD 1
+#define DEL 0
+
+#define LOWER_BOUND 0
+#define UPPER_BOUND 1
+
+#define EPS 0.0001 /* small tolerance */
+//#define EPS 0.000001 /* small tolerance */
+#define ZERO 0.000001 /* estimated accuracy for doubles */
+//#define ZERO 0.0001 /* estimated accuracy for doubles */
+#define INF 1000000000.0
+#define IINF 1000000000
+
+#define MAX_SLACK 1.0
+#define MAX_LOSS 1.0
+#define MAX_CYCLE_WEIGHT 1.0
+#define MIN_VIOLATION 0.001
+#define MIN_SCORE_RANGE 10.0
+#define MAX_SCORE_RANGE ZERO /* 1.0 */
+
+#define ISCALE 10000
+
+//#define MAX_CUTS  10
+
+#define MAX_CUT_POOL 10000
+#define MAX_CUT_COD 10000
+#define MAX_ITER_POOL 100
+#define CLEAN_THRESH 0.9
+#define MANY_IT_ZERO 10
+
+#define mod2(I) ( I % 2 == 0 ? 0 : 1 )
+
+
+#ifdef TIME
+
+static float tot_basic_sep_time = 0.0; /* total time spent for basic 
+					  separation */
+static float avg_basic_sep_time; /* average time per iteration spent for basic
+				    separation */
+static float total_time = 0.0; /* total time spent in the separation */
+static float prep_time = 0.0; /* time spent for the definition of the
+				 parity ILP data structure */
+static float weak_time = 0.0; /* time spent for the construction of the
+				 separation graph by weakening */
+static float aux_time = 0.0; /* time spent for the definition of the 
+				auxiliary graph */
+static float path_time = 0.0; /* time spent in the computation of the
+				 shortest paths */ 
+static float cycle_time = 0.0; /* time spent in the determination of the
+				  shortest cycles */ 
+static float cut_time = 0.0; /* time spent in the determination of the
+				violated cuts */
+static float bw_time = 0.0; /* time spent in best_weakening */
+static float coef_time = 0.0; /* time spent in the initial computation
+				 of coef in get_cut */
+static float pool_time = 0.0; /* time spent for the addition and
+				 extraction of cuts from the pool */
+static int cut_ncalls = 0; /* number of calls to get_cut */
+static float tabu_time = 0.0; /* time spent within tabu search */
+float ti, tf, td, tti, ttf, tsi, tsf, tii, tff, tpi, tpf, ttabi, ttabf;
+void 
+second_(float *t) {*t=CoinCpuTime();}
+#endif
+
+/* #endif */
+
+/* global data structures */
+
+#define CGGGGG
+#ifndef CGGGGG
+static ilp *inp_ilp; /* input ILP data structure */
+static parity_ilp *p_ilp; /* parity ILP data structure */
+#endif
+
+#ifdef PRINT_CUTS
+/* utility subroutines */
+
+void print_int_vect(char *s,int *v,int n)
+{
+  int i;
+
+  printf("integer vector %s:",s);
+  for ( i = 0; i < n; i++ ) printf(" %d",v[i]);
+  printf("\n");
+}
+
+void print_short_int_vect(char *s,short int *v,int n)
+{
+  int i;
+
+  printf("short integer vector %s:",s);
+  for ( i = 0; i < n; i++ ) printf(" %d",v[i]);
+  printf("\n");
+}
+
+void print_double_vect(char *s,double *v,int n)
+{
+  int i;
+
+  printf("double vector %s:",s);
+  for ( i = 0; i < n; i++ ) printf(" %f",v[i]);
+  printf("\n");
+}
+#endif
+void alloc_error(char *s)
+{
+  printf("\n Warning: Not enough memory to allocate %s\n",s);
+  printf("\n Cannot proceed with 0-1/2 cut separation\n");
+  exit(FALSE);
+}
+
+/* double2int: compute the integer equivalent of a double */
+
+int double2int(double x)
+{
+  if ( x > IINF ) return (IINF);
+  if ( x < - IINF ) return (- IINF);
+  if ( x < ZERO && x > - ZERO ) return(0);
+  if ( x > 0.0 ) return(static_cast<int> (x + ZERO));
+  return(static_cast<int> (x - ZERO));
+}
+
+/* gcd: compute the greatest common divisor of two integers */
+
+int gcd(int a,int b)
+{
+  int c;
+
+  if ( a < 0 ) a = - a;
+  if ( b < 0 ) b = - b;
+  if ( a < b ) { c = a; a = b; b = c; }
+  while ( b != 0 ) {
+    c = a % b; a = b; b = c;
+  }
+  return(a);
+}
+
+/* ILP data structures subroutines */
+
+/* ilp_load: load the input ILP into an internal data structure */
+
+void Cgl012Cut::ilp_load(
+	      int mr, /* number of rows in the ILP matrix */
+	      int mc, /* number of columns in the ILP matrix */
+	      int mnz, /* number of nonzero's in the ILP matrix */
+	      int *mtbeg, /* starting position of each row in arrays mtind and mtval */
+	      int *mtcnt, /* number of entries of each row in arrays mtind and mtval */
+	      int *mtind, /* column indices of the nonzero entries of the ILP matrix */
+	      int *mtval, /* values of the nonzero entries of the ILP matrix */
+	      int *vlb, /* lower bounds on the variables */
+	      int *vub, /* upper bounds on the variables */
+	      int *mrhs, /* right hand sides of the constraints */
+	      char *msense /* senses of the constraints: 'L', 'G' or 'E' */
+	      )
+{
+  inp_ilp = reinterpret_cast<ilp *> (calloc(1,sizeof(ilp)));
+  if ( inp_ilp == NULL ) alloc_error(const_cast<char*>("inp_ilp"));
+
+  inp_ilp->mr = mr; inp_ilp->mc = mc; inp_ilp->mnz = mnz; 
+  inp_ilp->mtbeg = mtbeg; inp_ilp->mtcnt = mtcnt; 
+  inp_ilp->mtind = mtind; inp_ilp->mtval = mtval; 
+  inp_ilp->vlb = vlb; inp_ilp->vub = vub; 
+  inp_ilp->mrhs = mrhs; inp_ilp->msense = msense;
+}
+void Cgl012Cut::free_ilp()
+{
+  free(inp_ilp);
+  inp_ilp=NULL;
+}
+
+#ifdef PRINT_CUTS
+void Cgl012Cut::print_constr(int i /* constraint to be printed */)
+{
+
+  printf("\n content of constraint %d: nzcnt = %d, rhs = %d, sense = %c, slack = %f\n",
+    i, inp_ilp->mtcnt[i], inp_ilp->mrhs[i], inp_ilp->msense[i], p_ilp->slack[i]);
+  print_int_vect(const_cast<char*>("ind"),inp_ilp->mtind + inp_ilp->mtbeg[i],inp_ilp->mtcnt[i]);
+  print_int_vect(const_cast<char*>("val"),inp_ilp->mtval + inp_ilp->mtbeg[i],inp_ilp->mtcnt[i]);
+}
+#endif
+
+/* alloc_parity_ilp: allocate the memory for the parity ILP data structure */
+
+void Cgl012Cut::alloc_parity_ilp(
+		      int mr, /* number of rows in the ILP matrix */
+		      int mc, /* number of columns in the ILP matrix */
+		      int mnz /* number of nonzero's in the ILP matrix */
+		      )
+{
+  p_ilp = reinterpret_cast<parity_ilp *> (calloc(1,sizeof(parity_ilp)));
+  if ( p_ilp == NULL ) alloc_error(const_cast<char*>("p_ilp"));
+
+  p_ilp->mtbeg = reinterpret_cast<int *> (calloc(mr,sizeof(int))); 
+  if ( p_ilp->mtbeg == NULL ) alloc_error(const_cast<char*>("p_ilp->mtbeg"));
+  p_ilp->mtcnt = reinterpret_cast<int *> (calloc(mr,sizeof(int)));
+  if ( p_ilp->mtcnt == NULL ) alloc_error(const_cast<char*>("p_ilp->mtcnt"));
+  p_ilp->mtind = reinterpret_cast<int *> (calloc(mnz,sizeof(int)));
+  if ( p_ilp->mtind == NULL ) alloc_error(const_cast<char*>("p_ilp->mtind"));
+  p_ilp->mrhs = reinterpret_cast<short int *> (calloc(mr,sizeof(short int)));
+  if ( p_ilp->mrhs== NULL ) alloc_error(const_cast<char*>("p_ilp->mrhs"));
+  p_ilp->xstar = reinterpret_cast<double *> (calloc(mc,sizeof(double)));
+  if ( p_ilp->xstar== NULL ) alloc_error(const_cast<char*>("p_ilp->xstar"));
+  p_ilp->slack = reinterpret_cast<double *> (calloc(mr,sizeof(double)));
+  if ( p_ilp->slack == NULL ) alloc_error(const_cast<char*>("p_ilp->slack"));
+  p_ilp->row_to_delete = reinterpret_cast<short int *> (calloc(mr,sizeof(short int)));
+  if ( p_ilp->row_to_delete == NULL ) alloc_error(const_cast<char*>("p_ilp->row_to_delete"));
+  p_ilp->col_to_delete = reinterpret_cast<short int *> (calloc(mc,sizeof(short int)));
+  if ( p_ilp->col_to_delete == NULL ) alloc_error(const_cast<char*>("p_ilp->col_to_delete"));
+  p_ilp->gcd = reinterpret_cast<int *> (calloc(mr,sizeof(int)));
+  if ( p_ilp->gcd == NULL ) alloc_error(const_cast<char*>("p_ilp->gcd"));
+  p_ilp->possible_weak = reinterpret_cast<short int *> (calloc(mc,sizeof(short int)));
+  if ( p_ilp->possible_weak == NULL ) alloc_error(const_cast<char*>("p_ilp->possible_weak"));
+  p_ilp->type_even_weak = reinterpret_cast<short int *> (calloc(mc,sizeof(short int)));
+  if ( p_ilp->type_even_weak == NULL ) alloc_error(const_cast<char*>("p_ilp->type_even_weak"));
+  p_ilp->type_odd_weak = reinterpret_cast<short int *> (calloc(mc,sizeof(short int)));
+  if ( p_ilp->type_odd_weak == NULL ) alloc_error(const_cast<char*>("p_ilp->type_odd_weak"));
+  p_ilp->loss_even_weak = reinterpret_cast<double *> (calloc(mc,sizeof(double)));
+  if ( p_ilp->loss_even_weak == NULL ) alloc_error(const_cast<char*>("p_ilp->loss_even_weak"));
+  p_ilp->loss_odd_weak = reinterpret_cast<double *> (calloc(mc,sizeof(double)));
+  if ( p_ilp->loss_odd_weak == NULL ) alloc_error(const_cast<char*>("p_ilp->loss_odd_weak"));
+  p_ilp->min_loss_by_weak = reinterpret_cast<double *> (calloc(mc,sizeof(double)));
+  if ( p_ilp->min_loss_by_weak == NULL ) alloc_error(const_cast<char*>("p_ilp->min_loss_by_weak"));
+  p_ilp->mr=mr;
+  p_ilp->mc=mc;
+  p_ilp->mnz=mnz;
+}
+
+#ifdef PRINT_CUTS
+void Cgl012Cut::print_parity_ilp()
+{
+  printf("\n content of parity_ilp data structure: mc = %d, mr = %d, mnz = %d\n",
+    p_ilp->mc,p_ilp->mr,p_ilp->mnz);
+  print_int_vect(const_cast<char*>("mtbeg"),p_ilp->mtbeg,p_ilp->mr); 
+  print_int_vect(const_cast<char*>("mtcnt"),p_ilp->mtcnt,p_ilp->mr); 
+  print_int_vect(const_cast<char*>("mtind"),p_ilp->mtind,p_ilp->mnz); 
+print_short_int_vect(const_cast<char*>("mrhs"),p_ilp->mrhs,p_ilp->mr); 
+print_double_vect(const_cast<char*>("xstar"),p_ilp->xstar,p_ilp->mc); 
+print_double_vect(const_cast<char*>("slack"),p_ilp->slack,p_ilp->mr); 
+print_short_int_vect(const_cast<char*>("row_to_delete"),p_ilp->row_to_delete,p_ilp->mr); 
+print_short_int_vect(const_cast<char*>("col_to_delete"),p_ilp->col_to_delete,p_ilp->mc); 
+print_int_vect(const_cast<char*>("gcd"),p_ilp->gcd,p_ilp->mr); 
+print_short_int_vect(const_cast<char*>("possible_weak"),p_ilp->possible_weak,p_ilp->mc);
+print_short_int_vect(const_cast<char*>("type_even_weak"),p_ilp->type_even_weak,p_ilp->mc);
+print_short_int_vect(const_cast<char*>("type_odd_weak"),p_ilp->type_odd_weak,p_ilp->mc);
+print_double_vect(const_cast<char*>("loss_even_weak"),p_ilp->loss_even_weak,p_ilp->mc); 
+print_double_vect(const_cast<char*>("loss_odd_weak"),p_ilp->loss_odd_weak,p_ilp->mc); 
+print_double_vect(const_cast<char*>("min_loss_by_weak"),p_ilp->min_loss_by_weak,p_ilp->mc); 
+}
+#endif
+
+void Cgl012Cut::free_parity_ilp()
+{
+  if (p_ilp) {
+    free(p_ilp->mtbeg); 
+    free(p_ilp->mtcnt); 
+    free(p_ilp->mtind); 
+    free(p_ilp->mrhs); 
+    free(p_ilp->xstar); 
+    free(p_ilp->slack); 
+    free(p_ilp->row_to_delete); 
+    free(p_ilp->col_to_delete); 
+    free(p_ilp->gcd); 
+    free(p_ilp->possible_weak); 
+    free(p_ilp->type_even_weak); 
+    free(p_ilp->type_odd_weak); 
+    free(p_ilp->loss_even_weak); 
+    free(p_ilp->loss_odd_weak); 
+    free(p_ilp->min_loss_by_weak); 
+    free(p_ilp);
+    p_ilp=NULL;
+  }
+}
+
+/* alloc_info_weak: allocate memory for the weakening info data structure */
+
+info_weak *alloc_info_weak(int nweak /* number of variables to be weakened */)
+{
+  info_weak *i_weak;
+
+  i_weak = reinterpret_cast<info_weak *> (calloc(1,sizeof(info_weak)));
+  if ( i_weak == NULL ) alloc_error(const_cast<char*>("i_weak"));
+  if ( nweak > 0 ) {
+    i_weak->var = reinterpret_cast<int *> (calloc(nweak,sizeof(int)));
+    if ( i_weak->var == NULL ) alloc_error(const_cast<char*>("i_weak->var"));
+    i_weak->type = reinterpret_cast<short int *> (calloc(nweak,sizeof(short int)));
+    if ( i_weak->type == NULL ) alloc_error(const_cast<char*>("i_weak->type"));
+  }
+
+  return(i_weak);
+}
+
+#ifdef PRINT_CUTS
+void print_info_weak(info_weak *i_weak)
+{
+  printf("\n content of info_weak: nweak = %d\n",i_weak->nweak); 
+  if ( i_weak->nweak > 0 ) {
+    print_int_vect(const_cast<char*>("var"),i_weak->var,i_weak->nweak);
+    print_short_int_vect(const_cast<char*>("type"),i_weak->type,i_weak->nweak);
+  }
+}
+#endif
+
+void free_info_weak(info_weak *i_weak)
+{
+  if ( i_weak->nweak > 0 ) {
+    free(i_weak->var);
+    free(i_weak->type);
+  }
+  free(i_weak);
+} 
+
+/* get_parity_ilp: construct an internal data structure containing all the 
+   information which can be useful for  0-1/2 cut separation */
+
+void Cgl012Cut::get_parity_ilp()
+{
+  int i, j, h, ij, aij, cnti, cnttot, begi, begh, ofsj, gcdi, ubj, lbj;
+  double slacki, xstarj, loss_upper, loss_lower;
+  short int parity_col_removed, equalih;
+
+  /* allocate the memory for the parity ILP data structure */
+
+  //alloc_parity_ilp(inp_ilp->mr,inp_ilp->mc,inp_ilp->mnz);
+
+  p_ilp->mr = inp_ilp->mr;
+  p_ilp->mc = inp_ilp->mc;
+  
+  /* mark the variables equal to their lower/upper bound */
+
+  parity_col_removed = 0;
+  for ( j = 0; j < inp_ilp->mc; j++ ) {
+    xstarj = p_ilp->xstar[j] = inp_ilp->xstar[j];
+    ubj = inp_ilp->vub[j]; lbj = inp_ilp->vlb[j];
+    if ( xstarj > static_cast<double> (ubj - ZERO) ) {
+      /* variable at its upper bound */
+      p_ilp->col_to_delete[j] = TRUE;
+      if ( mod2(ubj) == ODD ) {
+	p_ilp->possible_weak[j] = ODD;
+	p_ilp->type_odd_weak[j] = UPPER_BOUND;
+	p_ilp->loss_odd_weak[j] = 0.0;
+	if ( parity_col_removed == EVEN ) parity_col_removed = ODD;
+	else parity_col_removed = EVEN;
+      }
+      else {
+	p_ilp->possible_weak[j] = EVEN;
+	p_ilp->type_even_weak[j] = UPPER_BOUND;
+	p_ilp->loss_even_weak[j] = 0.0;
+      }
+      p_ilp->min_loss_by_weak[j] = 0.0;
+    }
+    else if ( xstarj < static_cast<double> (lbj) + ZERO ) {
+      /* variable at its lower bound */
+      p_ilp->col_to_delete[j] = TRUE;
+      if ( mod2(lbj) == ODD ) {
+	p_ilp->possible_weak[j] = ODD;
+	p_ilp->type_odd_weak[j] = LOWER_BOUND;
+	p_ilp->loss_odd_weak[j] = 0.0;
+	p_ilp->min_loss_by_weak[j] = 0.0;
+	if ( parity_col_removed == EVEN ) parity_col_removed = ODD;
+	else parity_col_removed = EVEN;
+      }
+      else {
+	p_ilp->possible_weak[j] = EVEN;
+	p_ilp->type_even_weak[j] = LOWER_BOUND;
+	p_ilp->loss_even_weak[j] = 0.0;
+	p_ilp->min_loss_by_weak[j] = 0.0;
+      }
+      p_ilp->min_loss_by_weak[j] = 0.0;
+    }
+    else { 
+      /* variable neither at its lower nor at its upper bound */
+      p_ilp->col_to_delete[j] = FALSE;
+      loss_upper = static_cast<double> (ubj) - xstarj; 
+      loss_lower = xstarj - static_cast<double> (lbj); 
+      if ( ( loss_upper > MAX_LOSS ) && ( loss_lower > MAX_LOSS ) ) 
+	/* no weakening for the variable */
+	p_ilp->possible_weak[j] = NONE;
+      else if ( loss_upper > MAX_LOSS ) {
+	/* lower weakening only */
+	if ( mod2(lbj) == EVEN ) {
+	  p_ilp->possible_weak[j] = EVEN;
+	  p_ilp->type_even_weak[j] = LOWER_BOUND;
+	  p_ilp->loss_even_weak[j] = loss_lower;
+	}
+	else {
+	  p_ilp->possible_weak[j] = ODD;
+	  p_ilp->type_odd_weak[j] = LOWER_BOUND;
+	  p_ilp->loss_odd_weak[j] = loss_lower;
+	}
+      }
+      else if ( loss_lower > MAX_LOSS ) {
+	/* upper weakening only */
+	if ( mod2(ubj) == EVEN ) {
+	  p_ilp->possible_weak[j] = EVEN;
+	  p_ilp->type_even_weak[j] = UPPER_BOUND;
+	  p_ilp->loss_even_weak[j] = loss_upper;
+	}
+	else {
+	  p_ilp->possible_weak[j] = ODD;
+	  p_ilp->type_odd_weak[j] = UPPER_BOUND;
+	  p_ilp->loss_odd_weak[j] = loss_upper;
+	}
+      }
+      else if ( mod2(ubj) == mod2(lbj) ) {
+	/* lower and upper bound have the same parity: 
+	   choose the best weakening */
+	if ( mod2(ubj) == EVEN ) {
+	  p_ilp->possible_weak[j] = EVEN;
+	  if ( loss_lower <= loss_upper ) {
+	    p_ilp->type_even_weak[j] = LOWER_BOUND;
+	    p_ilp->loss_even_weak[j] = loss_lower;
+	  }
+	  else {  
+	    p_ilp->type_even_weak[j] = UPPER_BOUND;
+	    p_ilp->loss_even_weak[j] = loss_upper;
+	  }
+	}
+	else {
+	  p_ilp->possible_weak[j] = ODD;
+	  if ( loss_lower <= loss_upper ) {
+	    p_ilp->type_odd_weak[j] = LOWER_BOUND;
+	    p_ilp->loss_odd_weak[j] = loss_lower;
+	  }
+	  else {  
+	    p_ilp->type_odd_weak[j] = UPPER_BOUND;
+	    p_ilp->loss_odd_weak[j] = loss_upper;
+	  }
+	}
+      }
+      else {
+	/* lower and upper bound have different parities: 
+	   consider both weakenings */
+	p_ilp->possible_weak[j] = BOTH;
+	if ( mod2(ubj) == EVEN ) {
+	  p_ilp->type_even_weak[j] = UPPER_BOUND;
+	  p_ilp->loss_even_weak[j] = loss_upper;
+	  p_ilp->type_odd_weak[j] = LOWER_BOUND;
+	  p_ilp->loss_odd_weak[j] = loss_lower;
+	}
+	else {  
+	  p_ilp->type_even_weak[j] = LOWER_BOUND;
+	  p_ilp->loss_even_weak[j] = loss_lower;
+	  p_ilp->type_odd_weak[j] = UPPER_BOUND;
+	  p_ilp->loss_odd_weak[j] = loss_upper;
+	}
+      }
+      if ( loss_upper > loss_lower ) p_ilp->min_loss_by_weak[j] = loss_lower;
+      else p_ilp->min_loss_by_weak[j] = loss_upper;
+    }
+  }    
+  
+  /* scan the constraints and delete those which are trivially useless 
+     in the 0-1/2 cut separation */
+
+  cnttot = 0;
+  for ( i = 0; i < inp_ilp->mr; i++ ) {
+    begi = inp_ilp->mtbeg[i];
+    
+    /* compute the row slack and the GCD of the entries of the row */
+    
+    slacki = static_cast<double> (inp_ilp->mrhs[i]); 
+    gcdi = inp_ilp->mrhs[i];
+    for ( ofsj = 0; ofsj < inp_ilp->mtcnt[i]; ofsj++ ) {
+      ij = begi + ofsj;
+      j = inp_ilp->mtind[ij];
+      aij = inp_ilp->mtval[ij];
+      slacki -= static_cast<double> (aij ) * ( inp_ilp->xstar[j] );        
+      gcdi = gcd(gcdi,aij);
+    }
+    if ( inp_ilp->msense[i] == 'G' ) slacki = -slacki;
+    if ( slacki < -ZERO || ( inp_ilp->msense[i] == 'E' && slacki > ZERO ) ) {
+#ifdef COIN_DEVELOP
+      printf("\n Warning: constraint %d in the model is violated:\n",i);
+      printf("\n 0-1/2 cut separation is not possible\n");
+printf("\nnumber of nonzero's %d\n",inp_ilp->mtcnt[i]);
+printf("nonzero's (col,coef,xstar) ");
+for (ofsj=0;ofsj<inp_ilp->mtcnt[i];ofsj++) printf("(%d,%d,%f) ",
+  inp_ilp->mtind[begi+ofsj], inp_ilp->mtval[begi+ofsj],
+  inp_ilp->xstar[inp_ilp->mtind[begi+ofsj]]);
+printf("\n");
+printf("sense %c and rhs %d and slack %.5e\n",inp_ilp->msense[i],inp_ilp->mrhs[i], slacki);
+#endif
+      //exit(0);
+	  slacki = INF;
+    }
+    p_ilp->slack[i] = slacki;
+  
+    /* mark the rows with slack greater than the maximum allowed */
+    
+    if ( slacki > MAX_SLACK - EPS ) p_ilp->row_to_delete[i] = TRUE;
+    else p_ilp->row_to_delete[i] = FALSE;
+
+    /* store the odd entries in the (possibly scaled) row i */
+   
+    //if ( gcdi != 1 ) 
+    //printf("Warning: constraint %d with nonprime coefficients\n",i); 
+    p_ilp->gcd[i] = gcdi;
+    p_ilp->mrhs[i] = mod2(( inp_ilp->mrhs[i] / gcdi ));
+    p_ilp->mtbeg[i] = cnttot;
+    cnti = 0;
+    for ( ofsj = 0; ofsj < inp_ilp->mtcnt[i]; ofsj++ ) {
+      ij = begi + ofsj;
+      j = inp_ilp->mtind[ij];
+      aij = mod2(( inp_ilp->mtval[ij] / gcdi ));
+      if ( aij == ODD ) { 
+	if ( ! p_ilp->col_to_delete[j] ) {
+	  p_ilp->mtind[cnttot] = j;
+	  cnti++; cnttot++;       
+	}
+	else if ( p_ilp->possible_weak[j] == ODD ) {
+	  if ( p_ilp->mrhs[i] == EVEN ) p_ilp->mrhs[i] = ODD; 
+	  else p_ilp->mrhs[i] = EVEN;
+	}
+      }
+    }
+    p_ilp->mtcnt[i] = cnti;
+    if ( cnti == 0 ) /* (scaled) row with even entries only */
+      p_ilp->row_to_delete[i] = TRUE;
+    else {
+      if ( cnti == 1 && slacki < EPS ) { /* the row could be deleted */
+#ifdef PRINT
+	printf("get_parity_ilp: row %d could be deleted since it\n",i);
+	printf("has only one odd entry and is tight, but it is not ...\n");
+#endif
+      }
+    }
+  }    
+  p_ilp->mnz = cnttot;
+
+#ifdef REDUCTION
+  
+  /* remove identical rows in the parity matrix */
+  /* very trivial implementation */
+
+  for ( i = 0; i < p_ilp->mr; i++ ) 
+    for ( h = i+1; h < p_ilp->mr; h++ ) 
+      if ( ( p_ilp->mrhs[i] == p_ilp->mrhs[h] ) &&
+	   ( p_ilp->mtcnt[i] == p_ilp->mtcnt[h] ) && 
+	   ( ! p_ilp->row_to_delete[i] ) && 
+	   ( ! p_ilp->row_to_delete[h] ) ) {
+	begi = p_ilp->mtbeg[i]; begh = p_ilp->mtbeg[h];
+	equalih = TRUE;
+	for ( ofsj = 0; ofsj < p_ilp->mtcnt[i]; ofsj++ )
+	  /* the check assumes the indexes of the columns associated
+	     with each row are ordered in p_ilp->mtind[] ... */
+	  if ( p_ilp->mtind[begi+ofsj] != p_ilp->mtind[begh+ofsj] ) {
+	    equalih = FALSE;
+	    break;
+	  }
+	if ( equalih ) {
+	  if ( p_ilp->slack[h] > p_ilp->slack[i] )
+	    p_ilp->row_to_delete[h] = TRUE;
+	  else 
+	    p_ilp->row_to_delete[i] = TRUE;
+	}
+      }
+
+  /* check for the existence of separate connected components in the 
+     parity matrix row intersection graph */
+  /* not implemented so far - if ever, the availability of the parity
+     matrix in column form also would be really convenient */
+
+#endif
+
+}
+
+/* separation graph subroutines */
+
+#define SG_EDGE_INDEX(s_graph,J,K) ( ((J) < (K)) ? ( (s_graph->nnodes * (J)) - (((J)+1)*(J)/2) + (K) - (J) -1 ) : ( (s_graph->nnodes * (K)) - (((K)+1)*(K)/2) + (J) - (K) -1 ) ) 
+  
+/* initialize_sep_graph: allocate and initialize the data structure
+   to contain the information associated with a separation graph */
+
+separation_graph *Cgl012Cut::initialize_sep_graph()
+{
+  int maxnodes, maxedges, nnodes, j, jk; 
+  int *nodes, *ind;
+  separation_graph *s_graph;
+
+  s_graph = reinterpret_cast<separation_graph *> (calloc(1,sizeof(separation_graph)));
+  if ( s_graph == NULL ) alloc_error(const_cast<char*>("s_graph"));
+  
+  maxnodes = p_ilp->mc + 1;
+  nnodes = 0;
+  nodes = reinterpret_cast<int *> (calloc(maxnodes,sizeof(int)));
+  if ( nodes == NULL ) alloc_error(const_cast<char*>("nodes"));
+  ind = reinterpret_cast<int *> (calloc(maxnodes,sizeof(int)));
+  if ( ind == NULL ) alloc_error(const_cast<char*>("ind"));
+  for ( j = 0; j < p_ilp->mc; j++ )
+    if ( ! p_ilp->col_to_delete[j] ) {
+      /* variable not removed from the separation problem */
+      nodes[nnodes] = j;
+      ind[j] = nnodes;
+      nnodes++;
+    }
+
+  /* take into account the special node */
+  nodes[nnodes] = maxnodes - 1;
+  ind[maxnodes-1] = nnodes;
+  nnodes++; 
+  
+  s_graph->nnodes = nnodes;
+  s_graph->nedges = 0;
+  s_graph->nodes = reinterpret_cast<int *> (malloc(nnodes*sizeof(int)));
+  if ( s_graph->nodes == NULL ) alloc_error(const_cast<char*>("s_graph->nodes"));
+  for ( j = 0; j < nnodes; j++ ) s_graph->nodes[j] = nodes[j];
+  free(nodes);
+  s_graph->ind = reinterpret_cast<int *> (malloc(maxnodes*sizeof(int)));
+  if ( s_graph->ind == NULL ) alloc_error(const_cast<char*>("s_graph->ind"));
+  for ( j = 0; j < maxnodes; j++ ) s_graph->ind[j] = ind[j];
+  free(ind);
+  maxedges = (nnodes * (nnodes - 1)) / 2;
+  s_graph->even_adj_list = reinterpret_cast<edge **> (malloc(maxedges*sizeof(edge *)));
+  if ( s_graph->even_adj_list == NULL ) alloc_error(const_cast<char*>("s_graph->even_adj_list"));
+  s_graph->odd_adj_list = reinterpret_cast<edge **> (malloc(maxedges*sizeof(edge *)));
+  if ( s_graph->odd_adj_list == NULL ) alloc_error(const_cast<char*>("s_graph->odd_adj_list"));
+  for ( jk = 0; jk < maxedges; jk++ ) 
+    s_graph->even_adj_list[jk] = s_graph->odd_adj_list[jk] = NULL;
+
+  return(s_graph);
+}
+
+/* update_weight_sep_graph: consider a new edge obtained from the 
+   (weakened) parity ILP and (possibly) add it to the separation graph */
+
+separation_graph *update_weight_sep_graph(
+					  int j, int k, /* endpoints of the new edge */
+					  double weight, /* weight of the new edge */
+					  short int parity, /* parity of the new edge */
+					  int i, /* constraint associated with the new edge */
+					  info_weak *i_weak, /* information associated with the weakening */
+					  separation_graph *s_graph /* separation graph to be updated */
+					  )
+{
+  int indj, indk, indjk;
+  edge *old_edge, *new_edge;
+  
+  indj = s_graph->ind[j]; indk = s_graph->ind[k]; 
+  indjk = SG_EDGE_INDEX(s_graph,indj,indk);
+  if ( parity == EVEN ) old_edge = s_graph->even_adj_list[indjk];
+  else old_edge = s_graph->odd_adj_list[indjk];
+  if ( old_edge == NULL ) {
+    /* edge is not in the graph */
+    new_edge = reinterpret_cast<edge *> (calloc(1,sizeof(edge)));
+    if ( new_edge == NULL ) alloc_error(const_cast<char*>("new_edge"));
+    new_edge->endpoint1 = indj; new_edge->endpoint2 = indk;
+    new_edge->weight = weight; new_edge->parity = parity;
+    new_edge->constr = i; new_edge->weak = i_weak;
+    (s_graph->nedges)++;
+    if ( parity == EVEN ) s_graph->even_adj_list[indjk] = new_edge;
+    else s_graph->odd_adj_list[indjk] = new_edge;
+  }
+  else {
+    /* edge is already in the graph */
+    if ( old_edge->weight > weight ) {
+      /* replace the old edge */
+      old_edge->weight = weight; old_edge->constr = i; 
+      free_info_weak(old_edge->weak); 
+      old_edge->weak = i_weak;
+    }   
+    else {
+      /* keep the old edge */
+      free_info_weak(i_weak);
+    }
+  }
+
+  return(s_graph);
+}
+
+#ifdef PRINT_CUTS
+void print_edge(edge *e)
+{
+  printf("\n content of edge: endpoint1 = %d, endpoint2 = %d, weight = %f, parity = %d, constr = %d\n",
+    e->endpoint1,e->endpoint2,e->weight,e->parity,e->constr);
+  print_info_weak(e->weak);
+}
+#endif
+
+void free_edge(edge *e)
+{
+  if ( e->weak != NULL )  
+    free_info_weak(e->weak);
+  free(e);
+}
+
+#ifdef PRINT_CUTS
+void print_sep_graph(separation_graph *s_graph)
+{
+  int nnodes, maxedges, jk;
+  
+  nnodes = s_graph->nnodes;
+  maxedges = (nnodes * (nnodes - 1)) / 2;
+  printf("\n content of separation_graph: nnodes = %d, nedges = %d\n",
+    nnodes, s_graph->nedges);
+  print_int_vect(const_cast<char*>("nodes"),s_graph->nodes,nnodes);
+  print_int_vect(const_cast<char*>("ind"),s_graph->ind,nnodes);
+  for ( jk = 0; jk < maxedges; jk++ ) {
+    if ( s_graph->even_adj_list[jk] != NULL )
+      print_edge(s_graph->even_adj_list[jk]);
+    if ( s_graph->odd_adj_list[jk] != NULL )
+      print_edge(s_graph->odd_adj_list[jk]);
+  }
+}
+#endif
+
+void free_sep_graph(separation_graph *s_graph)
+{
+  int nnodes, maxedges, jk;
+  
+  nnodes = s_graph->nnodes;
+  maxedges = (nnodes * (nnodes - 1)) / 2;
+  for ( jk = 0; jk < maxedges; jk++ ) {
+    if ( s_graph->even_adj_list[jk] != NULL )
+      free_edge(s_graph->even_adj_list[jk]);
+    if ( s_graph->odd_adj_list[jk] != NULL )
+      free_edge(s_graph->odd_adj_list[jk]);
+  }
+  free(s_graph->nodes);
+  free(s_graph->ind);
+  free(s_graph->even_adj_list);
+  free(s_graph->odd_adj_list);
+  free(s_graph);
+}
+
+/* auxiliary graph subroutines - depend on the shortest path code used */
+
+#ifndef CGL_NEW_SHORT
+// will error if we get here
+#include "Cgldikbd.c"
+#endif
+
+#define AG_TWIN1(J) 2 * J
+#define AG_TWIN2(J) 2 * J + 1
+#define AG_MATE(J) 2 * static_cast<int> ( J / 2 ) + ( J % 2 == EVEN ? 1 : 0 )
+#define AG_TYPE(J,K) ( (J % 2) == (K % 2) ? EVEN : ODD )
+#define SG_ORIG(J) static_cast<int> (J / 2)
+
+/* define_aux_graph: construct the auxiliary graph for the shortest 
+   path computation - the data structure is based on that used by
+   Cherkassky, Goldberg and Radzik's shortest path codes */
+     
+auxiliary_graph *define_aux_graph(separation_graph *s_graph /* input separation graph */)
+{
+  int j, k, indjk, auxj1, auxj2, auxk1, auxk2, noutj, totoutj, narcs;
+  edge *s_edge;
+  auxiliary_graph *a_graph;
+
+  a_graph = reinterpret_cast<auxiliary_graph *> (calloc(1,sizeof(auxiliary_graph)));
+  if ( a_graph == NULL ) alloc_error(const_cast<char*>("a_graph"));
+
+  a_graph->nnodes = 2 * s_graph->nnodes;
+  a_graph->narcs = 4 * s_graph->nedges;
+
+#ifndef CGL_NEW_SHORT
+  a_graph->nodes = reinterpret_cast<node *> (calloc((a_graph->nnodes + 1),sizeof(node)));
+#else
+  a_graph->nodes = reinterpret_cast<cgl_node *> (calloc((a_graph->nnodes + 1),sizeof(cgl_node)));
+#endif
+  if ( a_graph->nodes == NULL ) alloc_error(const_cast<char*>("a_graph->nodes"));
+#ifndef CGL_NEW_SHORT
+  a_graph->arcs = reinterpret_cast<arc *> (calloc(((a_graph->narcs) + 1),sizeof(arc)));
+#else
+  a_graph->arcs = reinterpret_cast<cgl_arc *> (calloc(((a_graph->narcs) + 1),sizeof(cgl_arc)));
+#endif
+  if ( a_graph->arcs == NULL ) alloc_error(const_cast<char*>("a_graph->arcs"));
+
+  narcs = 0; 
+  for ( j = 0; j < s_graph->nnodes; j++ ) {
+    /* count the number of edges incident with j in the separation graph */
+    totoutj = 0;
+    for ( k = 0; k < s_graph->nnodes; k++ ) 
+      if ( k != j ) {
+	indjk = SG_EDGE_INDEX(s_graph,j,k);
+	if ( s_graph->even_adj_list[indjk] != NULL ) totoutj++;
+	if ( s_graph->odd_adj_list[indjk] != NULL ) totoutj++;
+      }
+    auxj1 = AG_TWIN1(j); auxj2 = AG_TWIN2(j);
+    a_graph->nodes[auxj1].index = auxj1;
+    a_graph->nodes[auxj2].index = auxj2;
+#ifndef CGL_NEW_SHORT
+    a_graph->nodes[auxj1].first = &(a_graph->arcs[narcs]);
+    a_graph->nodes[auxj2].first = &(a_graph->arcs[narcs+totoutj]);
+#else
+    a_graph->nodes[auxj1].firstArc = &(a_graph->arcs[narcs]);
+    a_graph->nodes[auxj2].firstArc = &(a_graph->arcs[narcs+totoutj]);
+#endif
+    /* add the edges as arcs outgoing from j to the auxiliary graph */
+    noutj = 0;
+    for ( k = 0; k < s_graph->nnodes; k++ ) {
+      if ( k != j ) {
+	auxk1 = AG_TWIN1(k); auxk2 = AG_TWIN2(k);
+	indjk = SG_EDGE_INDEX(s_graph,j,k);
+	s_edge = s_graph->even_adj_list[indjk];
+	if ( s_edge != NULL ) {
+	  /* there is an even edge between j and k */        
+#ifndef CGL_NEW_SHORT
+	  a_graph->arcs[narcs].len = a_graph->arcs[narcs+totoutj].len = 
+	    (int) (s_edge->weight * ISCALE); 
+	  a_graph->arcs[narcs].head = &(a_graph->nodes[auxk1]);
+	  a_graph->arcs[narcs+totoutj].head = &(a_graph->nodes[auxk2]);
+#else
+	  a_graph->arcs[narcs].length = a_graph->arcs[narcs+totoutj].length = 
+	    static_cast<int> (s_edge->weight * ISCALE); 
+	  a_graph->arcs[narcs].to = auxk1;
+	  a_graph->arcs[narcs+totoutj].to = auxk2;
+#endif
+	  narcs++; noutj++; 
+	}
+	s_edge = s_graph->odd_adj_list[indjk];
+	if ( s_edge != NULL ) {
+	  /* there is an odd edge between j and k */        
+#ifndef CGL_NEW_SHORT
+	  a_graph->arcs[narcs].len = a_graph->arcs[narcs+totoutj].len = 
+	    (int) (s_edge->weight * ISCALE); 
+	  a_graph->arcs[narcs].head = &(a_graph->nodes[auxk2]);
+	  a_graph->arcs[narcs+totoutj].head = &(a_graph->nodes[auxk1]);
+#else
+	  a_graph->arcs[narcs].length = a_graph->arcs[narcs+totoutj].length = 
+	    static_cast<int> (s_edge->weight * ISCALE); 
+	  a_graph->arcs[narcs].to = auxk2;
+	  a_graph->arcs[narcs+totoutj].to = auxk1;
+#endif
+	  /* this looks really useless - to be removed ...
+	  if ( noutj == 0 ) {
+	    a_graph->nodes[auxj1].first = &(a_graph->arcs[narcs]);
+	    a_graph->nodes[auxj2].first = &(a_graph->arcs[narcs+totoutj]);
+	  } 
+	  ... */
+	  narcs++; noutj++; 
+	}
+      }
+    }
+    narcs += totoutj;
+  }
+#ifndef CGL_NEW_SHORT
+  a_graph->nodes[a_graph->nnodes].first = &(a_graph->arcs[narcs]);
+#else
+  a_graph->nodes[a_graph->nnodes].firstArc = &(a_graph->arcs[narcs]);
+#endif
+  
+  return(a_graph);
+}
+
+/* cancel_node_aux_graph: remove the node j in the separation graph
+  from the auxiliary graph - all the outgoing arc lengths are set to
+  a large value */
+
+auxiliary_graph *cancel_node_aux_graph(
+				       int j, /* index of the node in the separation graph */
+				       auxiliary_graph *a_graph /* auxiliary graph to be updated */
+				       )
+{
+  int auxj1, auxj2;
+#ifndef CGL_NEW_SHORT
+  arc *arc_ptr;
+#else
+  cgl_arc *arc_ptr;
+#endif
+
+  auxj1 = AG_TWIN1(j); auxj2 = AG_TWIN2(j); 
+#ifndef CGL_NEW_SHORT
+  for ( arc_ptr = a_graph->nodes[auxj1].first; 
+	arc_ptr < a_graph->nodes[auxj1+1].first; 
+	arc_ptr++ )  
+    (*arc_ptr).len = ISCALE;
+  for ( arc_ptr = a_graph->nodes[auxj2].first; 
+	arc_ptr < a_graph->nodes[auxj2+1].first; 
+	arc_ptr++ )  
+    (*arc_ptr).len = ISCALE;
+#else
+  for ( arc_ptr = a_graph->nodes[auxj1].firstArc; 
+	arc_ptr < a_graph->nodes[auxj1+1].firstArc; 
+	arc_ptr++ )  
+    (*arc_ptr).length = ISCALE;
+  for ( arc_ptr = a_graph->nodes[auxj2].firstArc; 
+	arc_ptr < a_graph->nodes[auxj2+1].firstArc; 
+	arc_ptr++ )  
+    (*arc_ptr).length = ISCALE;
+#endif
+
+  return(a_graph);
+}
+  
+#ifdef PRINT_CUTS
+#ifndef CGL_NEW_SHORT
+void print_node(node *n)
+{
+  printf("\n content of node (addr = %d): first = %d, dist = %d, parent = %d, next = %d, prev = %d, status = %d\n",
+    (int)n,(int)(*n).first,(*n).dist,(int)(*n).parent,(int)(*n).next,(int)(*n).prev,
+    (*n).status);
+}
+
+void print_arc(arc *a)
+{
+  printf("\n content of arc (addr = %d): len = %d, head = %d\n",
+    (int)a,(*a).len,(int)(*a).head);
+}
+
+void print_node_vect(char *s,node *v,int n)
+{
+  int i;
+
+  printf("node vector %s:",s);
+  for ( i = 0; i < n; i++ ) print_node(&v[i]);
+  printf("\n");
+}
+
+void print_arc_vect(char *s,arc *v,int n)
+{
+  int i;
+
+  printf("arc vector %s:",s);
+  for ( i = 0; i < n; i++ ) print_arc(&v[i]);
+  printf("\n");
+}
+#else
+void print_node(cgl_node *n)
+{
+  printf("\n content of node (addr = %p): first = %p, dist = %d, parent = %p\n",
+	 reinterpret_cast<void *>(n),
+	 reinterpret_cast<void *>((*n).firstArc),
+	 (*n).distanceBack,
+	 static_cast<int>((*n).parentNode));
+}
+
+void print_arc(cgl_arc *a)
+{
+  printf("\n content of arc (addr = %p): len = %d, head = %d\n",
+	 reinterpret_cast<void *>(a),(*a).length,static_cast<int>((*a).to));
+}
+
+void print_node_vect(char *s,cgl_node *v,int n)
+{
+  int i;
+
+  printf("node vector %s:",s);
+  for ( i = 0; i < n; i++ ) print_node(&v[i]);
+  printf("\n");
+}
+
+void print_arc_vect(char *s,cgl_arc *v,int n)
+{
+  int i;
+
+  printf("arc vector %s:",s);
+  for ( i = 0; i < n; i++ ) print_arc(&v[i]);
+  printf("\n");
+}
+#endif
+
+void print_aux_graph(auxiliary_graph *a_graph)
+{
+  printf("\n content of auxiliary graph: nnodes = %d, narcs = %d\n",
+    a_graph->nnodes,a_graph->narcs);
+  print_node_vect(const_cast<char*>("nodes"),a_graph->nodes,a_graph->nnodes);
+  print_arc_vect(const_cast<char*>("nodes"),a_graph->arcs,a_graph->narcs);
+}
+#endif
+
+void free_aux_graph(auxiliary_graph *a_graph)
+{
+  free(a_graph->nodes);
+  free(a_graph->arcs);
+  free(a_graph);
+}
+
+/* odd cycles management subroutines */
+
+/* simple_cycle: check whether a given cycle is simple
+   (and therefore may correspond to a non-dominated ineq.) */
+
+short int simple_cycle(cycle *s_cyc /* cycle to be checked */)
+{
+  int i, e, maxnodes;
+  int *cnt;
+ 
+  maxnodes = 0; 
+  for ( e = 0; e < s_cyc->length; e++ ) {
+    if (!s_cyc->edge_list[e]) {
+      // bad
+      maxnodes=-1;
+      abort();//break;
+    }
+    i = s_cyc->edge_list[e]->endpoint1;
+    if ( i > maxnodes ) maxnodes = i;
+    i = s_cyc->edge_list[e]->endpoint2;
+    if ( i > maxnodes ) maxnodes = i;
+  }
+  if (maxnodes<0)
+    return FALSE;
+  cnt = reinterpret_cast<int *> (calloc(maxnodes+1,sizeof(int)));
+  if ( cnt == NULL ) alloc_error(const_cast<char*>("cnt"));
+  //for ( i = 0; i <= maxnodes; i++ ) cnt[i] = 0;
+
+  for ( e = 0; e < s_cyc->length; e++ ) {
+    i = s_cyc->edge_list[e]->endpoint1;
+    cnt[i]++;
+    if ( cnt[i] > 2 ) {
+      free(cnt);
+      return(FALSE);
+    }
+    i = s_cyc->edge_list[e]->endpoint2;
+    cnt[i]++;
+    if ( cnt[i] > 2 ) {
+      free(cnt);
+      return(FALSE);
+    }
+  }
+
+  free(cnt);
+  return(TRUE);
+}
+  
+/* same_cycle: check whether two cycles are identical 
+   (assumes the first nodes of the cycles coincide) */
+
+short int same_cycle(cycle *s_cyc1, cycle *s_cyc2 /* cycles to be compared */)
+{
+  int e, eb;
+  short int same;
+
+  if ( s_cyc1->length != s_cyc2->length ) return(FALSE);
+  /* check the cycles in the same direction ... */
+  same = TRUE;
+  for ( e = 0; e < s_cyc1->length; e++ ) {
+    if ( s_cyc1->edge_list[e] != s_cyc2->edge_list[e] ) {
+      same = FALSE;
+      break;
+    }
+  }
+  if ( same ) return(TRUE);
+  /* ... and in reverse direction */
+  same = TRUE;
+  for ( e = 0, eb = s_cyc2->length - 1; e < s_cyc1->length; e++, eb-- ) {
+    if ( s_cyc1->edge_list[e] != s_cyc2->edge_list[eb] ) {
+      same = FALSE;
+      break;
+    }
+  }
+  if ( same ) return(TRUE);
+  return(FALSE);
+}
+
+#ifdef PRINT_CUTS
+void print_cycle(cycle *s_cycle)
+{
+  int e;
+
+  printf("\n content of cycle: weight = %f, length = %d\n",
+    s_cycle->weight,s_cycle->length);
+  for ( e = 0; e < s_cycle->length; e++ )
+    print_edge(s_cycle->edge_list[e]);
+}
+#endif
+
+void free_cycle(cycle *s_cycle)
+{
+  free(s_cycle->edge_list);
+  free(s_cycle);
+}
+
+/* initialize_cycle_list: allocate and initialize the cycle list data structure */
+
+cycle_list *initialize_cycle_list(int max_cyc /* maximum number of cycles in the list */)
+{
+  cycle_list *s_cycle_list;
+
+  s_cycle_list = reinterpret_cast<cycle_list *> (calloc(1,sizeof(cycle_list)));
+  if ( s_cycle_list == NULL ) alloc_error(const_cast<char*>("s_cycle_list"));
+  s_cycle_list->cnum = 0;
+  s_cycle_list->list = reinterpret_cast<cycle **> (calloc(max_cyc,sizeof(cycle *)));
+  if ( s_cycle_list->list == NULL ) alloc_error(const_cast<char*>("s_cycle_list->list"));
+  return(s_cycle_list);
+}
+
+/* add_cycle_to_list: add a new cycle to the cycle list data structure
+   (if not already in the list) */
+
+cycle_list *add_cycle_to_list(
+			      cycle *s_cycle, /* pointer to the cycle to be added to the list */
+			      cycle_list *s_cycle_list /* input cycle list to be updated */
+			      )
+{
+  int c;
+
+  if ( ! simple_cycle(s_cycle) ) {
+    free_cycle(s_cycle);
+    return(s_cycle_list);
+  }
+
+  for ( c = 0; c < s_cycle_list->cnum; c++ )
+    if ( same_cycle(s_cycle,s_cycle_list->list[c]) ) {
+      free_cycle(s_cycle);
+      return(s_cycle_list);
+  }
+
+  s_cycle_list->list[s_cycle_list->cnum] = s_cycle;
+  (s_cycle_list->cnum)++;        
+
+  return(s_cycle_list);
+}
+
+void free_cycle_list(cycle_list *s_cycle_list)
+{
+  int c;
+
+  for ( c = 0; c < s_cycle_list->cnum; c++ ) 
+    free_cycle(s_cycle_list->list[c]);
+  free(s_cycle_list->list);
+  free(s_cycle_list);
+}
+
+#ifdef PRINT_CUTS
+void print_cycle_list(cycle_list *s_cycle_list)
+{
+  int c;
+
+  printf("\n content of cycle_list: cnum = %d\n",s_cycle_list->cnum);
+  for ( c = 0; c < s_cycle_list->cnum; c++ )
+    print_cycle(s_cycle_list->list[c]);
+}
+#endif
+
+/* get_shortest_odd_cycle_list: computation of the shortest odd cycles
+   visiting a certain node in the separation graph, and each other 
+   possible intermediate node, using the auxiliary graph data structure 
+   for the shortest path computation - all the cycles in the list are
+   different from each other */
+
+cycle_list *get_shortest_odd_cycle_list(
+					int j, /* first node to be visited by the odd cycle */
+					separation_graph *s_graph, /* current separation graph */
+					auxiliary_graph *a_graph /* auxiliary graph for the shortest path computation */
+					)
+{
+  int source, sink, curr, pred, totedges, k, t, kt;
+  double weight;
+#ifndef CGL_NEW_SHORT
+  //node *source_ptr, *sink_ptr, *first_ptr; 
+#else
+  //cgl_node *source_ptr, *sink_ptr, *first_ptr; 
+#endif
+  edge *curr_edge;
+  short_path_node *forw_arb, *backw_arb;
+  cycle *s_cycle;
+  cycle_list *s_cycle_list;
+
+#ifdef TIME
+  second_(&tsi);
+#endif
+ 
+  s_cycle_list = initialize_cycle_list((a_graph->nnodes)-2);
+
+  source = AG_TWIN1(j); sink = AG_TWIN2(j);
+  //source_ptr = &(a_graph->nodes[source]);
+  //sink_ptr = &(a_graph->nodes[sink]);
+  //first_ptr = &(a_graph->nodes[0]);
+
+  /* compute the shortest path arborescence rooted at source and
+     the shortest path arborescence rooted at sink (that comes for
+     free due to symmetry) and store them (the path information is 
+     hidden into aux_graph) */
+
+#ifdef TIME
+  second_(&ti);
+#endif
+#ifndef CGL_NEW_SHORT
+  {
+    int nNodes = a_graph->nnodes;
+    int nArcs = a_graph->narcs;
+    cgl_arc * arcs = new cgl_arc [nArcs];
+    for (int i=0;i<nArcs;i++) {
+      arcs[i].length=a_graph->arcs[i].len;
+      arcs[i].to=a_graph->arcs[i].head->index;
+    }
+    cgl_node * nodes = new cgl_node[nNodes+1];
+    for (int i=0;i<nNodes;i++) {
+      int iArc = a_graph->nodes[i].first-a_graph->arcs;
+      nodes[i].firstArc=arcs+iArc;
+      nodes[i].index=i;
+    }
+    int iArc = a_graph->nodes[nNodes].first-a_graph->arcs;
+    nodes[nNodes].firstArc=arcs+iArc;
+    cgl_graph graph;
+    graph.nnodes=nNodes;
+    graph.narcs=nArcs;
+    graph.nodes=nodes;
+    graph.arcs=arcs;
+    cglShortestPath(&graph,source,ISCALE);
+    dikbd(a_graph->nnodes,first_ptr,source_ptr,ISCALE);
+    for ( k = 0; k < a_graph->nnodes; k++ ) { 
+      if ( a_graph->nodes[k].parent != NULL ) {
+	int distance1 = a_graph->nodes[k].dist;
+	int distance2 = graph.nodes[k].distanceBack;
+	assert (distance1==distance2);
+      } else {
+	//
+	printf("null parent %d\n",k);
+      }
+    }
+  }
+#else
+  cglShortestPath(a_graph,source,ISCALE);
+#endif
+#ifdef TIME
+  second_(&tf);
+  path_time += tf - ti;
+#endif
+  forw_arb = 
+    reinterpret_cast<short_path_node *> (calloc(a_graph->nnodes,sizeof(short_path_node)));
+  if ( forw_arb == NULL ) alloc_error(const_cast<char*>("forw_arb"));
+  for ( k = 0; k < a_graph->nnodes; k++ ) { 
+#ifndef CGL_NEW_SHORT
+    if ( a_graph->nodes[k].parent != NULL ) {
+      forw_arb[k].dist = a_graph->nodes[k].dist;
+      forw_arb[k].pred = a_graph->nodes[k].parent->index;
+    }
+#else
+    if ( a_graph->nodes[k].parentNode >=0 ) {
+      forw_arb[k].dist = a_graph->nodes[k].distanceBack;
+      forw_arb[k].pred = a_graph->nodes[k].parentNode;
+    }
+#endif
+    else {
+      forw_arb[k].dist = COIN_INT_MAX;
+      forw_arb[k].pred = NONE;
+    }
+  }
+  backw_arb = 
+    reinterpret_cast<short_path_node *> (calloc(a_graph->nnodes,sizeof(short_path_node)));
+  if ( backw_arb == NULL ) alloc_error(const_cast<char*>("backw_arb"));
+  for ( k = 0; k < a_graph->nnodes; k++ ) { 
+#ifndef CGL_NEW_SHORT
+    if ( a_graph->nodes[k].parent != NULL ) {
+      backw_arb[AG_MATE(k)].dist = a_graph->nodes[k].dist;
+      backw_arb[AG_MATE(k)].pred = AG_MATE(a_graph->nodes[k].parent->index);
+    }
+#else
+    if ( a_graph->nodes[k].parentNode >=0) {
+      backw_arb[AG_MATE(k)].dist = a_graph->nodes[k].distanceBack;
+      backw_arb[AG_MATE(k)].pred = AG_MATE(a_graph->nodes[k].parentNode);
+    }
+#endif
+    else {
+      backw_arb[AG_MATE(k)].dist = COIN_INT_MAX;
+      backw_arb[AG_MATE(k)].pred = NONE;
+    }
+  }
+
+#ifdef USELESS
+  /* compute second the shortest path anti-arborescence rooted at sink 
+     (which coincides with the arborescence since aux_graph is 
+     symmetrical) and store it */
+
+#ifdef TIME
+  second_(&ti);
+#endif
+  cc = dikbd(a_graph->nnodes,first_ptr,sink_ptr,ISCALE);
+#ifdef TIME
+  second_(&tf);
+  path_time += tf - ti;
+#endif
+  backw_arb = 
+    (short_path_node *) calloc(a_graph->nnodes,sizeof(short_path_node));
+  if ( backw_arb == NULL ) alloc_error("backw_arb");
+  for ( k = 0; k < a_graph->nnodes; k++ ) { 
+    backw_arb[k].dist = a_graph->nodes[k].dist;
+    backw_arb[k].pred = a_graph->nodes[k].parent->index;
+  }
+#endif
+
+  /* consider each possible intermediate node in aux_graph */
+
+  for ( k = 0; k < s_graph->nnodes; k++ ) {
+    if ( k != j ) {
+      for ( t = 1; t <= 2; t++ ) {
+	if ( t == 1 ) kt = AG_TWIN1(k); 
+	else kt = AG_TWIN2(k);
+	weight = 
+	  (static_cast<double> (forw_arb[kt].dist + backw_arb[kt].dist)) / 
+	  (static_cast<double> (ISCALE));
+	if ( weight < MAX_CYCLE_WEIGHT + EPS ) {
+	  totedges = 0;
+	  /* count how many edges are in the forward path from source ... */
+	  curr = kt;
+	  do {
+	    if (curr<0) {
+	      totedges=-1;
+	      break;
+	    }
+	    curr = forw_arb[curr].pred; totedges++;
+	  } while ( curr != source );
+	  if (totedges>=0) {
+	    /* ... and in the backward path to sink */
+	    curr = kt;
+	    do {
+	      if (curr<0) {
+		totedges=-1;
+		break;
+	      }
+	      curr = backw_arb[curr].pred; totedges++;
+	    } while ( curr != sink );
+	  }
+	  if (totedges>0) {
+	    s_cycle = reinterpret_cast<cycle *> (calloc(1,sizeof(cycle)));
+	    if ( s_cycle == NULL ) alloc_error(const_cast<char*>("s_cycle"));
+	    s_cycle->weight = weight;
+	    s_cycle->length = totedges;
+	    s_cycle->edge_list = reinterpret_cast<edge **> (calloc(totedges,sizeof(edge *)));
+	    if ( s_cycle->edge_list == NULL ) alloc_error(const_cast<char*>("s_cycle->edge_list"));
+	    /* define the set of edges corresponding to the paths in sep_graph */
+	    totedges = 0;
+	    /* forward path from source ... */
+	    curr = kt;
+	    do {
+	      pred = forw_arb[curr].pred;
+	      if ( AG_TYPE(pred,curr) == EVEN ) 
+		curr_edge = s_graph->even_adj_list
+		  [SG_EDGE_INDEX(s_graph,SG_ORIG(curr),SG_ORIG(pred))]; 
+	      else
+		curr_edge = s_graph->odd_adj_list
+		  [SG_EDGE_INDEX(s_graph,SG_ORIG(curr),SG_ORIG(pred))]; 
+	      s_cycle->edge_list[totedges] = curr_edge;
+	      curr = pred; 
+	      totedges++;
+	    } while ( curr != source );
+	    /* ... and backward path to sink */
+	    curr = kt;
+	    do {
+	      pred = backw_arb[curr].pred;
+	      if ( AG_TYPE(pred,curr) == EVEN ) 
+		curr_edge = s_graph->even_adj_list
+		  [SG_EDGE_INDEX(s_graph,SG_ORIG(curr),SG_ORIG(pred))]; 
+	      else
+		curr_edge = s_graph->odd_adj_list
+		  [SG_EDGE_INDEX(s_graph,SG_ORIG(curr),SG_ORIG(pred))]; 
+	      s_cycle->edge_list[totedges] = curr_edge;
+	      curr = pred; 
+	      totedges++;
+	    } while ( curr != sink );
+	    /* insert the new cycle in the list */
+	    s_cycle_list = add_cycle_to_list(s_cycle,s_cycle_list);
+	  }
+	}
+      }
+    }
+  }
+  free(forw_arb);
+  free(backw_arb);
+
+#ifdef TIME
+  second_(&tsf);
+  cycle_time += tsf - tsi;
+#endif
+
+  return(s_cycle_list);
+}
+
+/* cut management subroutines */
+
+/* initialize_cut_list: allocate and initialize the cut list data structure */
+
+cut_list *initialize_cut_list(int max_cut /* maximum number of cuts in the list */)
+{
+  cut_list *cuts;
+
+  cuts = reinterpret_cast<cut_list *> (calloc(1,sizeof(cut_list)));
+  if ( cuts == NULL ) alloc_error(const_cast<char*>("cuts"));
+  cuts->cnum = 0;
+  cuts->list = reinterpret_cast<cut **> (calloc(max_cut,sizeof(cut *)));
+
+  return(cuts);
+}
+
+#ifdef PRINT_CUTS
+void Cgl012Cut::print_cut(cut *v_cut)
+{
+  printf("\n content of cut: n_of_constr = %d, cnzcnt = %d, crhs = %d, csense = %c, violation = %f\n",
+    v_cut->n_of_constr,v_cut->cnzcnt,v_cut->crhs,v_cut->csense,v_cut->violation);
+  print_int_vect(const_cast<char*>("cind"),v_cut->cind,v_cut->cnzcnt);
+  print_int_vect(const_cast<char*>("cval"),v_cut->cval,v_cut->cnzcnt);
+  if ( v_cut->constr_list != NULL ) 
+    print_int_vect(const_cast<char*>("constr_list"),v_cut->constr_list,v_cut->n_of_constr);
+  if ( v_cut->in_constr_list != NULL )
+    print_short_int_vect(const_cast<char*>("in_constr_list"),v_cut->in_constr_list,inp_ilp->mr);
+	;
+}
+
+void Cgl012Cut::print_cut_list(cut_list *cuts)
+{
+  int c;
+
+  printf("\n content of cut_list: cnum = %d\n",cuts->cnum);
+  for ( c = 0; c < cuts->cnum; c++ )
+    print_cut(cuts->list[c]);
+}
+#endif
+
+void free_cut(cut *v_cut)
+{
+  if ( v_cut->constr_list != NULL ) free(v_cut->constr_list);
+  if ( v_cut->in_constr_list != NULL ) free(v_cut->in_constr_list);
+  if ( v_cut->cind != NULL ) free(v_cut->cind);
+  if ( v_cut->cval != NULL ) free(v_cut->cval);
+  free(v_cut);
+}
+
+void free_cut_list(cut_list *cuts)
+{
+  int c;
+
+  for ( c = 0; c < cuts->cnum; c++ ) 
+    if ( cuts->list[c] != NULL ) free_cut(cuts->list[c]);
+  free(cuts->list);
+  free(cuts);
+}
+
+/* get_ori_cut_coef: get the coefficients of a cut, before dividing by 2 and
+   rounding, starting from the list of the constraints combined to get 
+   the cut */
+
+short int Cgl012Cut::get_ori_cut_coef(
+			   int n_of_constr, /* number of constraints combined */
+			   int *constr_list, /* list of the constraints combined */
+			   int *ccoef, /* cut left hand side coefficients */
+			   int *crhs, /* cut right hand side */
+			   short int only_viol /* flag which tells whether only an inequality of
+			slack smaller than MAX_SLACK is of interest (TRUE)
+			otherwise (FALSE) */
+			   )
+{
+  int h, i, begi, gcdi, ofsj;
+  double tot_slack;
+
+  /* fast check of the possible violation of the cut */
+  if ( only_viol ) {
+    tot_slack = 0.0;
+    for ( h = 0; h < n_of_constr; h++ ) {
+      tot_slack += p_ilp->slack[constr_list[h]];
+      if ( tot_slack > MAX_SLACK - EPS ) return(FALSE);
+    }
+  }
+      
+  //for ( j = 0; j < inp_ilp->mc; j++ )
+  //ccoef[j] = 0;
+  memset(ccoef,0,inp_ilp->mc*sizeof(int));
+  (*crhs) = 0;
+
+  for ( h = 0; h < n_of_constr; h++ ) {
+    i = constr_list[h];
+    begi = inp_ilp->mtbeg[i]; gcdi = p_ilp->gcd[i];
+    if ( inp_ilp->msense[i] != 'G' ) {
+      if ( gcdi == 1 ) {
+	for ( ofsj = 0; ofsj < inp_ilp->mtcnt[i]; ofsj++ ) 
+	  ccoef[inp_ilp->mtind[begi+ofsj]] += inp_ilp->mtval[begi+ofsj];
+	(*crhs) += inp_ilp->mrhs[i];
+      }
+      else {
+	for ( ofsj = 0; ofsj < inp_ilp->mtcnt[i]; ofsj++ ) 
+	  ccoef[inp_ilp->mtind[begi+ofsj]] += inp_ilp->mtval[begi+ofsj] / gcdi;
+	(*crhs) += inp_ilp->mrhs[i] / gcdi;
+      }
+    }
+    else {
+      if ( gcdi == 1 ) {
+	for ( ofsj = 0; ofsj < inp_ilp->mtcnt[i]; ofsj++ ) 
+	  ccoef[inp_ilp->mtind[begi+ofsj]] -= inp_ilp->mtval[begi+ofsj];
+	(*crhs) -= inp_ilp->mrhs[i];
+      }
+      else {
+	for ( ofsj = 0; ofsj < inp_ilp->mtcnt[i]; ofsj++ ) 
+	  ccoef[inp_ilp->mtind[begi+ofsj]] -= inp_ilp->mtval[begi+ofsj] / gcdi;
+	(*crhs) -= inp_ilp->mrhs[i] / gcdi;
+      }
+    }
+  }
+  
+  return(TRUE);
+}
+
+/* best_cut: find the coefficients, the rhs and the violation of the
+   best possible cut that can be obtained by weakening a given set of
+   coefficients to even and a rhs to odd, dividing by 2 and rounding */
+
+short int Cgl012Cut::best_cut(
+		   int *ccoef, /* vector of the coefficients */
+		   int *crhs, /* pointer to rhs value */
+		   double *violation, /* violation of the cut */
+		   short int update, /* TRUE/FALSE: if TRUE, the new ccoef and crhs are 
+					given on output */ 
+		   short int only_viol /* flag which tells whether only an inequality of
+			slack smaller than MAX_SLACK is of interest (TRUE)
+			otherwise (FALSE) */
+		   )
+{
+  int j, n_to_weak;
+  short int original_parity; 
+  double original_slack, best_even_slack, best_odd_slack; 
+  int *vars_to_weak;  
+  info_weak *info_even_weak, *info_odd_weak; 
+
+  /* choose the best weakening for the variables whose coefficient
+     is not odd - this hopefully produces a stronger cut than that
+     associated with the weakened inequalities to define the edges */
+
+  vars_to_weak = reinterpret_cast<int *> (calloc(inp_ilp->mc,sizeof(int)));
+  if ( vars_to_weak == NULL ) alloc_error(const_cast<char*>("vars_to_weak"));
+  
+  n_to_weak = 0;
+  original_slack = 0.0;
+  for ( j = 0; j < inp_ilp->mc; j++ ) {
+    if ( ccoef[j] != 0 ) {
+      if ( mod2(ccoef[j]) == ODD ) {
+	vars_to_weak[n_to_weak] = j;
+	n_to_weak++;
+      }
+      original_slack -= inp_ilp->xstar[j] * static_cast<double> (ccoef[j]);
+    }
+  }
+  original_slack += static_cast<double> (*crhs);
+  if ( original_slack > MAX_SLACK - EPS ) {
+    free(vars_to_weak);
+    return(FALSE);
+  }
+  original_parity = mod2(*crhs);
+
+  if ( best_weakening(n_to_weak,vars_to_weak,
+		      original_parity,original_slack,
+		      &best_even_slack,&best_odd_slack,
+		      &info_even_weak,&info_odd_weak,
+		      TRUE,only_viol) == ODD ) {
+    *violation = ( 1.0 - best_odd_slack ) / 2.0;
+    if ( ! update ) { 
+      /* new ccoef and rhs are not required on output */
+      free(vars_to_weak);
+      free_info_weak(info_odd_weak);
+      return(TRUE);
+    }
+    /* update ccoef and crhs according to the best odd weakening */
+    for ( j = 0; j < n_to_weak; j++ )
+      if ( info_odd_weak->type[j] == LOWER_BOUND ) {
+	ccoef[vars_to_weak[j]]--;
+	*crhs -= inp_ilp->vlb[vars_to_weak[j]];
+      }
+      else {
+	ccoef[vars_to_weak[j]]++;
+	*crhs += inp_ilp->vub[vars_to_weak[j]];
+      }
+    /* compute and check the correctness of the cut coefficients */
+    for ( j = 0; j < inp_ilp->mc; j++ ) {
+      if ( mod2(ccoef[j]) == ODD ) {
+	printf("!!! Error 2 in weakening a cut !!!\n");
+	exit(0);
+      }
+      if ( ccoef[j] != 0 ) ccoef[j] /= 2;
+    }
+    if ( mod2(*crhs) == EVEN ) {
+      printf("!!! Error 1 in weakening a cut !!!\n");
+      exit(0);
+    }
+    *crhs = (*crhs - 1) / 2;
+    free(vars_to_weak);
+    free_info_weak(info_odd_weak);
+    return(TRUE);
+  }
+  else {
+    free(vars_to_weak);
+    return(FALSE);
+  }
+}
+
+/* define_cut: construct a cut data structure from a vector of
+   coefficients and a right-hand-side */
+
+cut *Cgl012Cut::define_cut(
+		int *ccoef, /* coefficients of the cut */
+		int crhs /* right hand side of the cut */
+		)
+{
+  int cnzcnt, j;
+  cut *v_cut;
+
+  v_cut = reinterpret_cast<cut *> (calloc(1,sizeof(cut)));
+  if ( v_cut == NULL ) alloc_error(const_cast<char*>("v_cut"));
+  v_cut->crhs = crhs;
+  cnzcnt = 0;
+  for ( j = 0; j < inp_ilp->mc; j++ )
+    if ( ccoef[j] != 0 ) cnzcnt++;
+  v_cut->cnzcnt = cnzcnt;
+  v_cut->csense = 'L';
+  v_cut->cind = reinterpret_cast<int *> (calloc(cnzcnt,sizeof(int)));
+  if ( v_cut->cind == NULL ) alloc_error(const_cast<char*>("v_cut->cind"));
+  v_cut->cval = reinterpret_cast<int *> (calloc(cnzcnt,sizeof(int)));
+  if ( v_cut->cval == NULL ) alloc_error(const_cast<char*>("v_cut->cval"));
+  cnzcnt = 0; v_cut->violation = 0.0;
+  for ( j = 0; j < inp_ilp->mc; j++ )
+    if ( ccoef[j] != 0 ) {
+      v_cut->cind[cnzcnt] = j;
+      v_cut->cval[cnzcnt] = ccoef[j];
+      v_cut->violation += inp_ilp->xstar[j] * static_cast<double> (ccoef[j]);
+      cnzcnt++;
+    }
+  v_cut->violation -= static_cast<double> (crhs); 
+  return(v_cut);
+}
+
+/* get_cut: extract a hopefully violated cut from an odd cycle of the
+   separation graph */
+
+cut *Cgl012Cut::get_cut(
+	     cycle *s_cyc /* shortest odd cycles identified in the separation graph */
+	     )
+{ 
+  int i, e, crhs;
+  short int ok;
+  /* short int original_parity; */
+  double violation;
+  /* double original_slack, best_even_slack, best_odd_slack; */
+  int *ccoef /*, *vars_to_weak */ ;  
+  /* info_weak *info_even_weak, *info_odd_weak; */
+  cut *v_cut;
+  int ncomb;
+  int *comb;
+  short int *flag_comb;
+#ifndef CGGGGG
+  static int iter = 0;
+  static double gap, maxgap = 0.0;
+#endif
+
+#ifdef TIME
+  second_(&tsi);
+  cut_ncalls++;
+#endif
+
+  /* compute the cut obtained by adding-up all the constraints 
+     corresponding to edges in the cycle, in their non-weak form */
+
+#ifdef TIME
+  second_(&tii);
+#endif
+  
+  ccoef = reinterpret_cast<int *> (calloc(inp_ilp->mc,sizeof(int)));
+  if ( ccoef == NULL ) alloc_error(const_cast<char*>("ccoef"));
+  ncomb = 0;
+  comb = reinterpret_cast<int *> (calloc(inp_ilp->mr,sizeof(int)));
+  if ( comb == NULL ) alloc_error(const_cast<char*>("comb"));
+  flag_comb = reinterpret_cast<short int *> (calloc(inp_ilp->mr,sizeof(short int)));
+  if ( flag_comb == NULL ) alloc_error(const_cast<char*>("flag_comb"));
+#if 0
+  // no need to as calloc used
+  for ( i = 0; i < inp_ilp->mr; i++ ) flag_comb[i] = OUT;
+
+  for ( j = 0; j < inp_ilp->mc; j++ )
+    ccoef[j] = 0;
+#endif
+  crhs = 0;
+  for ( e = 0; e < s_cyc->length; e++ ) {
+    i = (s_cyc->edge_list[e])->constr; 
+    if ( i >= 0 ) {
+      /* the edge is not associated with a bound constraint */
+      comb[ncomb] = i; ncomb++; flag_comb[i] = IN;
+    }
+  }
+  ok = get_ori_cut_coef(ncomb,comb,ccoef,&crhs,TRUE);
+
+#ifdef TIME
+  second_(&tff);
+  coef_time += tff - tii;
+#endif
+  
+  ok = ok && best_cut(ccoef,&crhs,&violation,TRUE,TRUE); 
+  if ( ! ok ) {
+    free(ccoef);
+    free(comb);
+    free(flag_comb);
+#ifdef TIME
+    second_(&tsf);
+    cut_time += tsf - tsi;
+#endif
+    return(NULL);
+  }
+
+  v_cut = define_cut(ccoef,crhs);
+iter++;
+  if ( v_cut->violation > violation + EPS || 
+       v_cut->violation < violation - EPS ) {
+    //printf("Error in violation check\n");
+    //printf("v_cut->violation %f  violation %f  gap %f  maxgap (previous) %f\n",
+    //	   v_cut->violation,violation,v_cut->violation-violation,maxgap);
+    //printf("iter %d\n",iter);
+    //exit(0);
+    free_cut(v_cut);
+    free(ccoef);
+    free(comb);
+    free(flag_comb);
+    errorNo=1;
+    return(NULL);
+  }
+gap = v_cut->violation - violation;
+if ( gap < 0.0 ) gap = -gap;
+if ( gap > maxgap ) maxgap = gap;
+  v_cut->n_of_constr = ncomb;
+  v_cut->constr_list = comb;
+  v_cut->in_constr_list = flag_comb;
+
+  free(ccoef);
+
+#ifdef TIME
+  second_(&tsf);
+  cut_time += tsf - tsi;
+#endif
+
+  return(v_cut);
+}
+
+/* cut_score: define the score of a (violated) cut */
+
+double Cgl012Cut::cut_score(
+		 int *ccoef, /* cut left hand side coefficients */
+		 int crhs, /* cut right hand side */
+		 double viol, /* cut violation */
+		 short int only_viol /* flag which tells whether only an inequality of
+			slack smaller than MAX_SLACK is of interest (TRUE)
+			otherwise (FALSE) */
+		 )
+{
+  int j, norm;
+
+  /* very simple score: violation divided/multiplied by the lhs norm */
+  if ( only_viol && viol < MIN_VIOLATION ) return(-INF);
+  norm = 0;
+  for ( j = 0; j < p_ilp->mc; j++ ) {
+    if ( ccoef[j] != 0 ) norm += ccoef[j] * ccoef[j];
+  }
+  if ( viol > 0.0 ) return (viol / sqrt(static_cast<double> (norm)));
+  else return (viol * sqrt(static_cast<double> (norm)));
+}
+
+/* same_cut: check whether two cuts are identical - not too clever
+   (assumes the sparse coefficients are sorted by column index) */
+
+short int same_cut(cut *cut1, cut *cut2 /* cuts to be compared */)
+{
+  int j;
+
+  if ( cut1->cnzcnt != cut2->cnzcnt ) return(FALSE);
+  if ( cut1->crhs != cut2->crhs ) return(FALSE);
+  if ( cut1->csense != cut2->csense ) return(FALSE);
+  for ( j = 0; j < cut1->cnzcnt; j++ ) {
+    if ( cut1->cind[j] != cut2->cind[j] ) return(FALSE);
+    if ( cut1->cval[j] != cut2->cval[j] ) return(FALSE);
+  }
+  return(TRUE);
+}
+
+/* add_cut_to_list: adds a cut to a list after checking that a copy of
+   the same cut is not already in the list - no checking is made about 
+   cuts dominating each other or implied by other cuts in the list plus
+   the constraints of the original problem */
+
+cut_list *add_cut_to_list(
+			  cut *v_cut, /* pointer to the violated cut to be added to the list */
+			  cut_list *cuts /* input cut list to be updated */
+			  )
+{
+  int c;
+
+  for ( c = 0; c < cuts->cnum; c++ ) {
+    if ( same_cut(v_cut,cuts->list[c]) ) {
+      free_cut(v_cut);
+      return(cuts);
+    }
+  }
+  cuts->list[cuts->cnum] = v_cut;
+  cuts->cnum++;
+  return(cuts);
+}
+
+/* getcuts: pick the 0-1/2 cuts in the list and give them on output */
+
+void getcuts(
+	     cut_list *cuts, /* input cut list */
+	     int *cnum, /* number of violated 0-1/2 cuts identified by the procedure */
+	     int *cnzcnt, /* overall number of nonzero's in the cuts */
+	     int **cbeg, /* starting position of each cut in arrays cind and cval */
+	     int **ccnt, /* number of entries of each cut in arrays cind and cval */
+	     int **cind, /* column indices of the nonzero entries of the cuts */
+	     int **cval, /* values of the nonzero entries of the cuts */
+	     int **crhs, /* right hand sides of the cuts */
+	     char **csense /* senses of the cuts: 'L', 'G' or 'E' */
+	     )
+{
+  int i, ofsj, count;
+  cut *cut_ptr;
+
+  /* allocate the memory for the output vectors */
+
+  (*cnum) = cuts->cnum;
+  (*cnzcnt) = 0;
+  for ( i = 0; i < cuts->cnum; i++ )
+    (*cnzcnt) += (cuts->list[i])->cnzcnt;
+  /* if ( (*cbeg) != NULL ) free(*cbeg); */
+  (*cbeg) = reinterpret_cast<int *> (calloc((*cnum),sizeof(int)));
+  if ( (*cbeg) == NULL ) alloc_error(const_cast<char*>("*cbeg"));
+  /* if ( (*ccnt) != NULL ) free(*ccnt); */
+  (*ccnt) = reinterpret_cast<int *> (calloc((*cnum),sizeof(int)));
+  if ( (*ccnt) == NULL ) alloc_error(const_cast<char*>("*ccnt"));
+  /* if ( (*crhs) != NULL ) free(*crhs); */
+  (*crhs) = reinterpret_cast<int *> (calloc((*cnum),sizeof(int)));
+  if ( (*crhs) == NULL ) alloc_error(const_cast<char*>("*crhs"));
+  /* if ( (*csense) != NULL ) free(*csense); */
+  (*csense) = reinterpret_cast<char *> (calloc((*cnum),sizeof(char)));
+  if ( (*csense) == NULL ) alloc_error(const_cast<char*>("*csense"));
+  /* if ( (*cind) != NULL ) free(*cind); */
+  (*cind) = reinterpret_cast<int *> (calloc((*cnzcnt),sizeof(int)));
+  if ( (*cind) == NULL ) alloc_error(const_cast<char*>("*cind")); 
+  /* if ( (*cval) != NULL ) free(*cval); */
+  (*cval) = reinterpret_cast<int *> (calloc((*cnzcnt),sizeof(int)));
+  if ( (*cval) == NULL ) alloc_error(const_cast<char*>("*cval"));
+
+  /* transfer the cuts information into the output data structures */
+
+  count = 0;
+  for ( i = 0; i < cuts->cnum; i++ ) {
+    cut_ptr = cuts->list[i];
+    (*cbeg)[i] = count; 
+    (*ccnt)[i] = cut_ptr->cnzcnt;
+    (*crhs)[i] = cut_ptr->crhs;
+    (*csense)[i] = cut_ptr->csense;
+    for ( ofsj = 0; ofsj < cut_ptr->cnzcnt; ofsj++ ) {
+      (*cind)[count] = cut_ptr->cind[ofsj];
+      (*cval)[count] = cut_ptr->cval[ofsj];
+      count++;
+    }
+  }
+}
+
+/* actual separation subroutines */
+
+/* best_weakening: find the best upper/lower bound weakening of a set
+   of variables */
+
+int Cgl012Cut::best_weakening(
+		   int n_to_weak, /* number of variables to weaken */
+int *vars_to_weak, /* indices of the variables to weaken */
+short int original_parity, /* original parity of the constraint to weaken */
+double original_slack, /* original slack of the constraint to weaken */
+double *best_even_slack, /* best possible slack of a weakened constraint 
+			   with even right-hand-side */
+double *best_odd_slack, /* best possible slack of a weakened constraint 
+			  with odd right-hand-side */
+info_weak **info_even_weak, /* weakening information about the best possible
+			       even weakened constraint */ 
+info_weak **info_odd_weak, /* weakening information about the best possible
+			      odd weakened constraint */ 
+short int only_odd, /* flag which tells whether only an odd weakening is of
+		       interest (TRUE) or both weakenings are (FALSE) */
+short int only_viol /* flag which tells whether only an inequality of
+			slack smaller than MAX_SLACK is of interest (TRUE)
+			otherwise (FALSE) */
+		   )
+{
+  int nweak, cntweak, ofsl, l;
+  short int flag_even, flag_odd, ok_even, ok_odd;
+  double best_even_e, best_even_o, best_odd_e, best_odd_o;
+  short int *type_even_weak, *type_odd_weak,   
+	    *switch_even_weak, *switch_odd_weak;
+
+#ifdef TIME
+  second_(&tii);
+#endif
+
+  type_even_weak = reinterpret_cast<short int *> (calloc(p_ilp->mc,sizeof(short int)));
+  if (type_even_weak == NULL ) alloc_error(const_cast<char*>("type_even_weak"));
+  switch_even_weak = reinterpret_cast<short int *> (calloc(p_ilp->mc,sizeof(short int)));
+  if (switch_even_weak == NULL ) alloc_error(const_cast<char*>("switch_even_weak"));
+  type_odd_weak = reinterpret_cast<short int *> (calloc(p_ilp->mc,sizeof(short int)));
+  if (type_odd_weak == NULL ) alloc_error(const_cast<char*>("type_odd_weak"));
+  switch_odd_weak = reinterpret_cast<short int *> (calloc(p_ilp->mc,sizeof(short int)));
+  if (switch_odd_weak == NULL ) alloc_error(const_cast<char*>("switch_odd_weak"));
+
+  if ( original_parity == EVEN ) {
+    (*best_even_slack) = original_slack;
+    (*best_odd_slack) = INF;
+  }
+  else {
+    (*best_odd_slack) = original_slack;
+    (*best_even_slack) = INF;
+  }
+  nweak = 0;
+  for ( ofsl = 0; ofsl < n_to_weak; ofsl++ ) {
+    l = vars_to_weak[nweak];
+    if ( p_ilp->possible_weak[l] == NONE ) {
+      free(type_even_weak); free(type_odd_weak);
+      free(switch_even_weak); free(switch_odd_weak);
+#ifdef TIME
+      second_(&tff);
+      bw_time += tff - tii;
+#endif
+      return(NONE);
+    }
+    else if ( p_ilp->possible_weak[l] == EVEN ) { 
+      /* only even weakening of l is possible */
+      (*best_even_slack) += p_ilp->loss_even_weak[l];
+      type_even_weak[nweak] = p_ilp->type_even_weak[l];
+      switch_even_weak[nweak] = FALSE;
+      (*best_odd_slack) += p_ilp->loss_even_weak[l];
+      type_odd_weak[nweak] = p_ilp->type_even_weak[l];
+      switch_odd_weak[nweak] = FALSE;
+    }
+    else if ( p_ilp->possible_weak[l] == ODD ) { 
+      /* only odd weakening of l is possible */
+      best_even_e = (*best_even_slack);
+      best_odd_o = (*best_odd_slack);
+      (*best_even_slack) = best_odd_o + p_ilp->loss_odd_weak[l];
+      type_even_weak[nweak] = p_ilp->type_odd_weak[l];
+      switch_even_weak[nweak] = TRUE;
+      (*best_odd_slack) = best_even_e + p_ilp->loss_odd_weak[l];
+      type_odd_weak[nweak] = p_ilp->type_odd_weak[l];
+      switch_odd_weak[nweak] = TRUE;
+    }
+    else {
+      /* both weakenings of l are possible */
+      best_even_e = (*best_even_slack) + p_ilp->loss_even_weak[l];
+      best_even_o = (*best_odd_slack) + p_ilp->loss_odd_weak[l];
+      best_odd_e = (*best_odd_slack) + p_ilp->loss_even_weak[l];
+      best_odd_o = (*best_even_slack) + p_ilp->loss_odd_weak[l];
+      if ( best_even_e <= best_even_o ) {
+	(*best_even_slack) = best_even_e;
+	type_even_weak[nweak] = p_ilp->type_even_weak[l];
+	switch_even_weak[nweak] = FALSE;
+      }
+      else {
+	(*best_even_slack) = best_even_o;
+	type_even_weak[nweak] = p_ilp->type_odd_weak[l];
+	switch_even_weak[nweak] = TRUE;
+      }
+      if ( best_odd_e <= best_odd_o ) {
+	(*best_odd_slack) = best_odd_e;
+	type_odd_weak[nweak] = p_ilp->type_even_weak[l];
+	switch_odd_weak[nweak] = FALSE;
+      }
+      else {
+	(*best_odd_slack) = best_odd_o;
+	type_odd_weak[nweak] = p_ilp->type_odd_weak[l];
+	switch_odd_weak[nweak] = TRUE;
+      }
+    }
+    if ( ( only_viol ) &&
+	 ( (*best_even_slack) > MAX_SLACK - EPS ) &&
+	 ( (*best_odd_slack) > MAX_SLACK - EPS ) ) {
+      free(type_even_weak); free(type_odd_weak);
+      free(switch_even_weak); free(switch_odd_weak);
+#ifdef TIME
+      second_(&tff);
+      bw_time += tff - tii;
+#endif
+      return(NONE);
+    }
+    nweak++;
+  }
+
+  /* construct the weakening vectors associated with the best
+     even and odd pairs (if the associated slack is not too big) */
+
+  if ( (! only_odd) && 
+       ( ( (*best_even_slack) <= MAX_SLACK - EPS ) ||
+       ( (! only_viol) && (*best_even_slack) <= INF - EPS ) ) ) {
+    ok_even = TRUE;
+    (*info_even_weak) = alloc_info_weak(nweak);
+    (*info_even_weak)->nweak = nweak;
+    flag_even = EVEN;
+    cntweak = nweak; 
+    for ( ofsl = n_to_weak - 1; ofsl >= 0; ofsl-- ) {
+      cntweak--;
+      (*info_even_weak)->var[cntweak] = vars_to_weak[ofsl];
+      if ( flag_even == EVEN ) {
+	(*info_even_weak)->type[cntweak] = type_even_weak[cntweak];
+	if ( switch_even_weak[cntweak] ) flag_even = ODD;
+      }
+      else {
+	(*info_even_weak)->type[cntweak] = type_odd_weak[cntweak];
+	if ( switch_odd_weak[cntweak] ) flag_even = EVEN;
+      }
+    }
+  }
+  else ok_even = FALSE;
+
+  if ( ( (*best_odd_slack) <= MAX_SLACK - EPS ) || 
+       ( (! only_viol) && (*best_odd_slack) <= INF - EPS ) ) {
+    ok_odd = TRUE;
+    (*info_odd_weak) = alloc_info_weak(nweak);
+    (*info_odd_weak)->nweak = nweak;
+    flag_odd = ODD;
+    cntweak = nweak; 
+    for ( ofsl = n_to_weak - 1; ofsl >= 0; ofsl-- ) {
+      cntweak--;
+      (*info_odd_weak)->var[cntweak] = vars_to_weak[ofsl];
+      if ( flag_odd == EVEN ) {
+	(*info_odd_weak)->type[cntweak] = type_even_weak[cntweak];
+	if ( switch_even_weak[cntweak] ) flag_odd = ODD;
+      }
+      else {
+	(*info_odd_weak)->type[cntweak] = type_odd_weak[cntweak];
+	if ( switch_odd_weak[cntweak] ) flag_odd = EVEN;
+      }
+    }
+  }
+  else ok_odd = FALSE;
+
+  free(type_even_weak); free(type_odd_weak);
+  free(switch_even_weak); free(switch_odd_weak);
+#ifdef TIME
+  second_(&tff);        
+  bw_time += tff - tii;
+#endif
+
+  if ( ok_odd && ok_even ) return(BOTH);
+  if ( ok_even ) return(EVEN);
+  if ( ok_odd ) return(ODD);
+  return(NONE);
+}
+
+/* basic_separation: try to identify violated 0-1/2 cuts by using the 
+   original procedure described in Caprara and Fischetti's MP paper */
+
+cut_list *Cgl012Cut::basic_separation()
+{
+  int i, j, k, l, begi, special, ofsj, ofsk, ofsl, n_to_weak, c;
+  short int parity, original_parity, ok_weak;
+  double weight, original_slack, best_even_slack, best_odd_slack;
+  int *vars_to_weak;
+  info_weak *info_even_weak, *info_odd_weak, *i_weak;
+  separation_graph *sep_graph;
+  auxiliary_graph *aux_graph;
+  cycle_list *short_cycle_list;
+  cut *violated_cut;
+  cut_list *out_cuts;
+
+  /* construct the separation graph by the standard weakening procedure */
+  
+#ifdef PRINT
+  print_parity_ilp();
+#endif
+
+#ifdef TIME
+  second_(&td);
+#endif
+#ifdef PRINT_TIME
+  printf("... time elapsed at the beginning of basic_separation: %f\n",td - tti);
+#endif
+#ifdef TIME
+  second_(&td);
+#endif
+#ifdef PRINT_TIME
+  printf("... time elapsed before initialize_sep_graph: %f\n",td - tti);
+#endif
+  sep_graph = initialize_sep_graph();
+  special = p_ilp->mc;
+#ifdef TIME
+  second_(&td);
+#endif
+#ifdef PRINT_TIME
+  printf("... time elapsed before weakening: %f\n",td - tti);
+#endif
+
+  /* edges associated with actual constraints in the ILP */
+
+  for ( i = 0; i < p_ilp->mr; i++ ) {
+    if ( ! p_ilp->row_to_delete[i] ) {
+      begi = p_ilp->mtbeg[i];
+      if ( p_ilp->mtcnt[i] == 1 ) {
+	/* row with one odd entry only: edge j -- special */
+	weight = p_ilp->slack[i];
+	if ( weight < MAX_SLACK - EPS ) {
+	  j = p_ilp->mtind[begi];
+	  parity = p_ilp->mrhs[i];
+	  i_weak = alloc_info_weak(0);
+	  sep_graph = update_weight_sep_graph
+	    (j,special,weight,parity,i,i_weak,sep_graph);
+	}
+      }
+      else if ( p_ilp->mtcnt[i] == 2 ) {
+	/* row with two odd entries only: edge j -- k */
+	weight = p_ilp->slack[i];
+	if ( weight < MAX_SLACK - EPS ) {
+	  j = p_ilp->mtind[begi];
+	  k = p_ilp->mtind[begi+1];
+	  parity = p_ilp->mrhs[i];
+	  i_weak = alloc_info_weak(0);
+	  sep_graph = update_weight_sep_graph
+	    (j,k,weight,parity,i,i_weak,sep_graph);
+	}
+      }
+      else {
+	/* row with three or more odd entries: weakening for all 1's pairs */
+	for ( ofsj = 0; ofsj < p_ilp->mtcnt[i]; ofsj++ ) {
+	  for ( ofsk = ofsj + 1; ofsk < p_ilp->mtcnt[i]; ofsk++ ) {
+	    /* edge(s) j -- k */
+	    j = p_ilp->mtind[begi+ofsj];
+	    k = p_ilp->mtind[begi+ofsk];
+	    original_slack = p_ilp->slack[i];
+	    original_parity = p_ilp->mrhs[i];
+	    n_to_weak = 0;
+	    vars_to_weak = reinterpret_cast<int *> (calloc(inp_ilp->mc,sizeof(int)));
+	    if ( vars_to_weak == NULL ) alloc_error(const_cast<char*>("vars_to_weak")); 
+	    for ( ofsl = 0; ofsl < p_ilp->mtcnt[i]; ofsl++ ) 
+	      if ( ofsl != ofsj && ofsl != ofsk ) {
+		l = p_ilp->mtind[begi+ofsl];
+		vars_to_weak[n_to_weak] = l;
+		n_to_weak++;
+	      }
+	    ok_weak = best_weakening(n_to_weak,vars_to_weak,
+				     original_parity,original_slack,
+				     &best_even_slack,&best_odd_slack,
+				     &info_even_weak,&info_odd_weak,
+				     FALSE,TRUE); 
+	    free(vars_to_weak); 
+	    if ( ok_weak == NONE ) goto EXITJK;
+	    if ( ok_weak == BOTH || ok_weak == EVEN ) {
+	      if ( best_even_slack < MAX_SLACK - EPS ) {
+		weight = best_even_slack; parity = EVEN;
+		sep_graph = update_weight_sep_graph
+		  (j,k,weight,parity,i,info_even_weak,sep_graph);
+	      }
+	    }
+	    if ( ok_weak == BOTH || ok_weak == ODD ) {
+	      if ( best_odd_slack < MAX_SLACK - EPS ) {
+		weight = best_odd_slack; parity = ODD;
+		sep_graph = update_weight_sep_graph
+		  (j,k,weight,parity,i,info_odd_weak,sep_graph);
+	      }
+	    }
+EXITJK:;  }
+	}
+      }
+    }
+  }
+
+  /* edges associated with the bound constraints (probably useless
+     but necessary in some cases */
+
+  for ( j = 0; j < p_ilp->mc; j++ ) {
+    if ( ! p_ilp->col_to_delete[j] ) {
+      weight = p_ilp->xstar[j] - inp_ilp->vlb[j];
+      if ( weight < MAX_SLACK - EPS ) {
+	parity = mod2(inp_ilp->vlb[j]);
+	i_weak = alloc_info_weak(0);
+	sep_graph = update_weight_sep_graph
+	  (j,special,weight,parity,NONE,i_weak,sep_graph);
+      }
+      weight = inp_ilp->vub[j] - p_ilp->xstar[j];
+      if ( weight < MAX_SLACK - EPS ) {
+	parity = mod2(inp_ilp->vub[j]);
+	i_weak = alloc_info_weak(0);
+	sep_graph = update_weight_sep_graph
+	  (j,special,weight,parity,NONE,i_weak,sep_graph);
+      }
+    }
+  }   
+#ifdef TIME
+  second_(&tf);
+  weak_time += tf - ti;
+#endif
+
+  /* construct the auxiliary graph for the shortest path computation 
+     and compute the smallest cost odd cycle visiting each node -
+     this part is strongly dependent on the data structure used by
+     the shortest path subroutine used */ 
+     
+#ifdef PRINT
+  print_sep_graph(sep_graph);
+#endif
+
+#ifdef TIME
+  second_(&ti);
+#endif
+#ifdef TIME
+  second_(&td);
+#endif
+#ifdef PRINT_TIME
+  printf("... time elapsed before define_aux_graph: %f\n",td - tti);
+#endif
+  aux_graph = define_aux_graph(sep_graph);
+#ifdef TIME
+  second_(&tf);
+  aux_time += tf - ti;
+#endif
+#ifdef PRINT
+  print_aux_graph(aux_graph);
+#endif
+  
+/* exit(1); */
+  
+#ifdef TIME
+  second_(&td);
+#endif
+#ifdef PRINT_TIME
+  printf("... time elapsed before cycles and cuts: %f\n",td - tti);
+  printf("%d nodes on list\n",sep_graph->nnodes);
+#endif
+  out_cuts = initialize_cut_list(MAX_CUTS);
+  for ( j = 0; j < sep_graph->nnodes; j++ ) {
+    short_cycle_list = get_shortest_odd_cycle_list(j,sep_graph,aux_graph);
+    if ( short_cycle_list == NULL ) goto EXIT_NODE;
+#ifdef PRINT
+    print_cycle_list(short_cycle_list);
+#endif
+    for ( c = 0; c < short_cycle_list->cnum; c++ ) {
+      violated_cut = get_cut(short_cycle_list->list[c]);
+      if ( violated_cut == NULL ) {
+	if (!errorNo)
+	  continue;
+	else
+	  break;
+      }
+#ifdef PRINT
+      print_cut(violated_cut);
+#endif
+      if ( violated_cut->violation > MIN_VIOLATION + EPS ) {
+	/* violated 0-1/2 cut found */  
+	out_cuts = add_cut_to_list(violated_cut,out_cuts);  
+	if ( out_cuts->cnum >= MAX_CUTS ) {
+	  free_cycle_list(short_cycle_list);
+	  goto EXIT_CUTS; 
+	}
+      }
+      else free_cut(violated_cut);
+    }
+    /* remove the current node from the auxiliary graph */
+EXIT_NODE:
+    aux_graph = cancel_node_aux_graph(j,aux_graph); 
+    free_cycle_list(short_cycle_list);
+  }
+
+EXIT_CUTS:
+  free_sep_graph(sep_graph);
+  free_aux_graph(aux_graph);
+
+#ifdef PRINT_CUTS
+  print_cut_list(out_cuts);
+#endif
+#ifdef TIME
+  second_(&td);
+#endif
+#ifdef PRINT_TIME
+  printf("... time elapsed at the end of basic_separation: %f\n",td - tti);
+#endif
+
+  return(out_cuts);
+}
+
+/*
+  012cut: main procedure for 0-1/2 cut separation
+  first release: Aug 12 1996
+  last revision: Jun 10 1997
+*/  
+
+/* static data structures for log information about separation */
+
+#ifndef CGGGGG
+static int sep_iter = 0; /* number of the current separation iteration */
+//#define POOL 
+#ifdef POOL 
+static pool_cut_list *pool = NULL; /* information about the cuts separated
+				      so far, used to decide when they should 
+				      be added to the current LP */
+#endif
+static log_var **vlog = NULL; /* information about the value attained
+				  by the variables in the last iterations,
+				  used to possibly set to 0 some coefficient
+				  > 0 in a cut to be added */ 
+static bool aggr; /* flag saying whether as many cuts as possible are required
+		   from the separation procedure (TRUE) or not (FALSE) */
+#endif
+/* include the reactive local search heuristic */
+
+//was #include "Cgltabu_012.c"
+//start include "Cgltabu_012.c"
+
+#define MAX_TABU_ITER 100
+#define NUM_HASH_ENTRIES MAX_CUT_POOL
+/* initial length of the tabu list */
+#define IN_PROHIB_PERIOD 3
+#define MAX_TIME_FACTOR 3
+
+/* data structure for the current local search solution */
+
+typedef struct {
+int n_of_constr; /* number of constraints in the current cut */
+short int *in_constr_list; /* flag saying whether a given constraint is
+			      in the list of constraints of the cut (IN)
+			      or not (OUT) */
+int *non_weak_coef; /* coefficients of the cut before weakening */
+int non_weak_rhs; /* coefficient of the rhs before weakening */
+double slack_sum; /* sum of the slacks of the constraints in the cut */
+double min_weak_loss; /* minimum loss by weakening the non even 
+			 coefficients */
+int one_norm; /* 1-norm of the lhs, i.e. sum of the absolute values of
+		 the coefficients */
+short int ok; /* logical flag telling whether the cut could be weakened
+		 to a 0-1/2 cut or not - if false the two fields below
+		 have no meaning */
+int *coef; /* actual coefficients of the cut */
+int rhs; /* actual rhs of the cut */
+double violation; /* violation of the cut */
+} tabu_cut;
+
+/* data structure for the hash table used in memory reaction */
+
+typedef struct h_e {
+int n_of_el; /* number of components to be considered */
+short int *flag_vect; /* vector of flags for the components */
+int last_vis; /* last iteration when this element was visited */
+struct h_e *next; /* pointer to the next element in the hash chain */
+} hash_element;
+
+typedef hash_element **hash_table;
+
+/* global variables for local search */
+
+int n; /* number of variables in the ILP */
+int m; /* number of constraints in the ILP */
+int it; /* number of tabu search iterations so far */
+tabu_cut *cur_cut; /* information about the current cut in local search */
+int *last_moved; /* last iteration when a given constraint was added/
+		    deleted from the list of constraints of the cut */
+int last_it_add; /* last iteration when a cut was added to the list */
+int last_it_restart; /* last iteration when a restart was performed */
+int prohib_period; /* current prohibition period */
+int last_prohib_period_mod; /* last iteration where prohibition period was modified */
+hash_table hash_tab; /* hash table */
+int A; /* parameter A in Battiti and Protasi */
+int B; /* parameter B in Battiti and Protasi */
+float elapsed_time; /* time elapsed since the beginning of the current
+		       tabu search call */
+
+/* clear_cur_cut: clear the current solution (no constraint in the cut) */
+
+void clear_cur_cut()
+{
+  int i, j;
+
+  cur_cut->n_of_constr = 0;
+  cur_cut->rhs = 0;
+  cur_cut->non_weak_rhs = 0;
+  cur_cut->violation = 0.0;
+  cur_cut->slack_sum = 0.0;
+  cur_cut->min_weak_loss = 0.0;
+  cur_cut->one_norm = 0;
+  for ( j = 0; j < n; j++ ) {
+    cur_cut->coef[j] = 0;
+    cur_cut->non_weak_coef[j] = 0;
+  }
+  for ( i = 0; i < m; i++ ) {
+    cur_cut->in_constr_list[i] = OUT;
+  }
+  cur_cut->ok = FALSE;
+}
+
+/* initialize_cur_cut: allocate the memory for cur_cut */
+
+void initialize_cur_cut() 
+{
+  cur_cut = reinterpret_cast<tabu_cut *> (calloc(1,sizeof(tabu_cut)));
+  if ( cur_cut == NULL ) alloc_error(const_cast<char*>("cur_cut"));
+  cur_cut->coef = reinterpret_cast<int *> (calloc(n,sizeof(int)));
+  if ( cur_cut->coef == NULL ) alloc_error(const_cast<char*>("cur_cut->coef"));
+  cur_cut->non_weak_coef = reinterpret_cast<int *> (calloc(n,sizeof(int)));
+  if ( cur_cut->non_weak_coef == NULL ) alloc_error(const_cast<char*>("cur_cut->non_weak_coef"));
+  cur_cut->in_constr_list = reinterpret_cast<short int *> (calloc(m,sizeof(short int)));
+  if ( cur_cut->in_constr_list == NULL ) alloc_error(const_cast<char*>("cur_cut->in_constr_list"));
+  clear_cur_cut();
+}
+
+/* free_cur_cut: free the memory for cur_cut */
+
+void free_cur_cut()
+{
+  free(cur_cut->coef);
+  free(cur_cut->non_weak_coef);
+  free(cur_cut->in_constr_list);
+  free(cur_cut);
+}
+
+#ifdef PRINT_TABU
+/* print_cur_cut: display cur_cut on output */
+
+void Cgl012Cut::print_cur_cut()
+{
+  int i, j; 
+
+  printf("iteration %d  prohib_period %d\n",it,prohib_period);
+  printf("\n content of cur_cut data structure: n_of_constr = %d, ok = %d\n", cur_cut->n_of_constr, cur_cut->ok);
+  for ( i = 0; i < m; i++ ) 
+    if ( cur_cut->in_constr_list[i] == IN ) 
+      printf("constr. %d\n",i);
+  /*
+  printf(" list of constraints:\n");
+  for ( i = 0; i < m; i++ ) 
+    if ( cur_cut->in_constr_list[i] == IN ) 
+      print_constr(i);
+  print_int_vect("non_weak_coef",cur_cut->non_weak_coef,n);
+  printf(" non_weak_rhs = %d\n",cur_cut->non_weak_rhs);
+  print_int_vect("coef",cur_cut->coef,n);
+  printf(" rhs = %d\n",cur_cut->rhs);
+  */
+  for ( j = 0 /* , viol = - (double) cur_cut->rhs */ ; j < n; j++ ) 
+    if ( ( p_ilp->xstar[j] > ZERO || p_ilp->xstar[j] < -ZERO ) && cur_cut->non_weak_coef[j] != 0 ) {
+      printf("var. %d  xstar %f  non_weak_coef %d  coef %d\n", j, p_ilp->xstar[j], cur_cut->non_weak_coef[j], cur_cut->coef[j]);
+      /* viol += p_ilp->xstar[j] * cur_cut->coef[j]; */
+    }
+  printf("rhs %d  viol %f  slack_sum %f  min_weak_loss %f  one_norm %d\n", 
+	 cur_cut->rhs, cur_cut->violation, cur_cut->slack_sum,
+	 cur_cut->min_weak_loss, cur_cut->one_norm);
+}  
+#endif  
+/* same_short_vect: check whether two short int vectors have the same content */
+
+short int same_short_vect(
+			  int n_of_el, /* number of components in the vectors */
+			  short int *vec_1, 
+			  short int *vec_2 /* vectors to be checked */
+			  )
+{
+  int i;
+  for ( i = 0; i < n_of_el; i++ ) 
+    if ( vec_1[i] != vec_2[i] ) return(FALSE);
+  return(TRUE);
+}
+
+/* initialize_hash_table: allocate the memory for the hash table */
+
+void initialize_hash_table()
+{
+  int i;
+  hash_tab = reinterpret_cast<hash_element **> (calloc(NUM_HASH_ENTRIES,sizeof(hash_element *)));
+  if ( hash_tab == NULL ) alloc_error(const_cast<char*>("hash_tab"));
+  for ( i = 0; i < NUM_HASH_ENTRIES; i++ ) hash_tab[i] = NULL;
+}
+
+/* clear_hash_table: clear the current hash table */
+
+void clear_hash_table()
+{
+  int i; 
+  hash_element *hash_ptr, *hash_el;
+
+  for ( i = 0; i < NUM_HASH_ENTRIES; i++ ) {
+    if ( hash_tab[i] != NULL ) {
+      hash_ptr = hash_tab[i];
+      do {
+	hash_el = hash_ptr->next;
+	free(hash_ptr->flag_vect);
+	free(hash_ptr);
+	hash_ptr = hash_el;
+      } while ( hash_ptr != NULL );
+      hash_tab[i] = NULL;
+    } 
+  }
+}
+
+/* free_hash_table: deallocate the memory for the hash table */
+
+void free_hash_table()
+{
+  clear_hash_table();
+  free(hash_tab);
+}
+
+/* hash_addr: compute the hash address associated with the current cut */
+
+int hash_addr(
+	      int n_of_el, /* number of elements to be considered */
+	      short int *flag_vect /* vector of flags for the elements */
+	      )
+{
+  int i, addr;
+
+  /* very simple algorithm: just add-up the squared indices of the IN elements */
+  addr = 0;
+  for ( i = 0; i < n_of_el; i++ ) 
+    if ( flag_vect[i] == IN ) addr += i * i;
+  return(addr % NUM_HASH_ENTRIES);
+}
+
+/* hash_search: search for the current cut in the hash list of all cuts -
+   if found return TRUE and update the last iteration the cut was found */
+
+short int hash_search(int *cyc_len /* length of the cycle if the current cut is found */)
+{ 
+  int addr;
+  hash_element *hash_el;
+
+  addr = hash_addr(m,cur_cut->in_constr_list);
+  hash_el = hash_tab[addr];
+  while ( hash_el != NULL ) {
+    if ( same_short_vect(m,cur_cut->in_constr_list,hash_el->flag_vect) ) {
+      *cyc_len = it - hash_el->last_vis;
+      hash_el->last_vis = it;
+      return(TRUE);
+    }
+    hash_el = hash_el->next;
+  }
+  return(FALSE);
+}
+
+/* hash_insert: insert a new cut in the hash list of all cuts */
+
+void hash_insert()
+{
+  int addr, i;
+  hash_element *hash_el, *hash_ptr;
+
+  addr = hash_addr(m,cur_cut->in_constr_list);
+  hash_el = reinterpret_cast<hash_element *> (calloc(1,sizeof(hash_element)));
+  if ( hash_el == NULL ) alloc_error(const_cast<char*>("hash_el"));
+  hash_el->n_of_el = m;
+  hash_el->last_vis = it;
+  hash_el->next = NULL;
+  hash_el->flag_vect = reinterpret_cast<short int *> (calloc(m,sizeof(short int)));
+  if ( hash_el->flag_vect == NULL ) alloc_error(const_cast<char*>("hash_el->flag_vect"));
+  for ( i = 0; i < m; i++ )
+    hash_el->flag_vect[i] = cur_cut->in_constr_list[i];
+  if ( hash_tab[addr] == NULL ) 
+    hash_tab[addr] = hash_el;
+  else {
+    hash_ptr = hash_tab[addr];
+    while ( hash_ptr->next != NULL ) {
+#if 0
+      /* this check can be omitted to save time */
+      if ( same_short_vect(m,cur_cut->in_constr_list,hash_ptr->flag_vect) ) {
+	printf("attempt to insert in the hash an already present cut\n");
+	exit(0);
+      }
+#endif
+      hash_ptr = hash_ptr->next;
+    }
+    hash_ptr->next = hash_el;
+  }
+}        
+
+/* increase_prohib_period: implemented as in Battiti and Protasi */
+
+void increase_prohib_period()
+{
+  if ( prohib_period * 1.1 > prohib_period + 1 ) 
+    if ( prohib_period * 1.1 < m - 2 ) prohib_period = 
+					 static_cast<int> (prohib_period*1.1);
+    else prohib_period = m - 2;
+  else
+    if ( prohib_period + 1 < m - 2 ) prohib_period += 1;
+    else prohib_period = m - 2;
+  last_prohib_period_mod = it;
+}
+
+/* decrease_prohib_period: implemented as in Battiti and Protasi */
+
+void decrease_prohib_period()
+{
+  if ( prohib_period * 0.9 < prohib_period - 1 ) 
+    if ( prohib_period * 0.9 > IN_PROHIB_PERIOD ) prohib_period = static_cast<int> (prohib_period* 0.9);
+    else prohib_period = IN_PROHIB_PERIOD;
+  else
+    if ( prohib_period - 1 > IN_PROHIB_PERIOD ) prohib_period -= 1;
+    else prohib_period = IN_PROHIB_PERIOD;
+  last_prohib_period_mod = it;
+}
+
+/* allowed: check if moving (adding/deleting) a given constraint 
+   is not a tabu move */
+
+short int allowed(int i /* constraint to be checked */)
+{
+  if ( last_moved[i]  < it - prohib_period ) {
+    if ( cur_cut->in_constr_list[i] == IN ) {
+      if ( cur_cut->n_of_constr > 1 ) return(TRUE);
+      else return(FALSE);
+    }
+    else {
+      if ( cur_cut->n_of_constr < m - 1 ) return(TRUE);
+      else return(FALSE);
+    }
+  }
+  else return(FALSE);
+}
+
+/* in_cur_cut: check whether a given constraint is in the list of
+   constraints defining the current cut */
+
+short int in_cur_cut(int i /* constraint to be checked */)
+{
+  if ( cur_cut->in_constr_list[i] == OUT ) return(FALSE);
+  else return(TRUE);
+}
+
+/* tabu_score: define the score of a potential new cut */
+
+double tabu_score(
+		  int *ccoef, /* cut left hand side coefficients */
+		  int crhs, /* cut right hand side */
+		  double viol, /* cut violation */
+double norm /* cut norm - 1-norm is used below */
+		  )
+{
+  /* very simple score: violation divided/multiplied by the lhs 1-norm */
+   
+  if ( norm == 0 ) norm = 1;
+  if ( viol > 0.0 ) return (viol / norm);
+  else return (viol * norm);
+}
+
+/* score_by_moving: compute the score of the best cut obtainable from 
+   the current local search solution by inserting/deleting a constraint */
+
+double Cgl012Cut::score_by_moving(
+		       int i, /* constraint to be moved */
+		       short int itype, /* type of move - ADD or DEL */
+		       double thresh /* minimum value of an interesting score */
+		       )
+{
+#define PENALTY_NON_WEAKABLE -1.0
+#define FAST_SCORE_EVAL 1
+  int j, begi, gcdi, ofsj, ij, crhs, one_norm, support_inter; 
+  short int flag_gt, ok;
+  double slack_sum, weak_loss, score, viol;
+  int *new_coef, *ccoef;
+  begi = inp_ilp->mtbeg[i];
+  gcdi = p_ilp->gcd[i];
+  
+  /* fast check - optimistic evaluation of the score */
+
+  slack_sum = cur_cut->slack_sum;
+
+  if ( itype == ADD ) slack_sum += p_ilp->slack[i] / static_cast<double> (gcdi);
+  else slack_sum -= p_ilp->slack[i] / static_cast<double> (gcdi);
+
+  viol = ( 1.0 - slack_sum ) / 2.0;
+
+  score = tabu_score(NULL,0,viol,1.0);
+/*
+printf("Score estimate 1 %f   Threshold %f\n",score,thresh);
+*/
+  if ( score < thresh + ZERO ) {
+    return (score);
+  }
+
+  /* discard the cuts that have empty support intersection with the 
+     current one */
+
+  support_inter = 0;
+
+  for ( ofsj = 0, ij = begi; ofsj < inp_ilp->mtcnt[i]; ofsj++, ij++ ) 
+    if ( cur_cut->non_weak_coef[inp_ilp->mtind[ij]] !=0 ) support_inter++;
+
+  if ( support_inter == 0 ) return(-INF);
+
+  /* compute the new cut coefficients and rhs (before weakening) */
+
+  new_coef = reinterpret_cast<int *> (calloc(inp_ilp->mtcnt[i],sizeof(int)));
+  if ( new_coef == NULL ) alloc_error(const_cast<char*>("new_coef"));
+
+  if ( ( itype == ADD && inp_ilp->msense[i] != 'G' ) ||
+    ( itype == DEL && inp_ilp->msense[i] == 'G' ) ) flag_gt = 1;
+  else flag_gt = -1;
+  if ( flag_gt == 1 ) {
+    if ( gcdi == 1 ) {
+      for ( ofsj = 0, ij = begi; ofsj < inp_ilp->mtcnt[i]; ofsj++, ij++ ) {
+	j = inp_ilp->mtind[ij];
+	new_coef[ofsj] = cur_cut->non_weak_coef[j] + inp_ilp->mtval[ij];
+      }
+      crhs = cur_cut->non_weak_rhs + inp_ilp->mrhs[i];
+    }
+    else {
+      for ( ofsj = 0, ij = begi; ofsj < inp_ilp->mtcnt[i]; ofsj++, ij++ ) {
+	j = inp_ilp->mtind[ij];
+	new_coef[ofsj] = cur_cut->non_weak_coef[j] + inp_ilp->mtval[ij] / gcdi;
+      }
+      crhs = cur_cut->non_weak_rhs + inp_ilp->mrhs[i] / gcdi;
+    }
+  }
+  else {
+    if ( gcdi == 1 ) {
+      for ( ofsj = 0, ij= begi; ofsj < inp_ilp->mtcnt[i]; ofsj++, ij++ ) {
+	j = inp_ilp->mtind[ij];
+	new_coef[ofsj] = cur_cut->non_weak_coef[j] - inp_ilp->mtval[ij];
+      }
+      crhs = cur_cut->non_weak_rhs - inp_ilp->mrhs[i];
+    }
+    else {
+      for ( ofsj = 0, ij = begi; ofsj < inp_ilp->mtcnt[i]; ofsj++, ij++ ) {
+	j = inp_ilp->mtind[ij];
+	new_coef[ofsj] = cur_cut->non_weak_coef[j] - inp_ilp->mtval[ij] / gcdi;
+      }
+      crhs = cur_cut->non_weak_rhs - inp_ilp->mrhs[i] / gcdi;
+    }
+  }
+
+  /* other - relatively fast - check by optimistic evaluation of the 
+     cut score */
+
+  weak_loss = cur_cut->min_weak_loss;
+  one_norm = cur_cut->one_norm;
+  for ( ofsj = 0, ij = begi; ofsj < inp_ilp->mtcnt[i]; ofsj++, ij++ ) {
+    j = inp_ilp->mtind[ij];
+    if ( cur_cut->coef[j] > 0 ) one_norm -= cur_cut->coef[j];
+    else one_norm += cur_cut->coef[j];
+    if ( new_coef[ofsj] >= 2 ) one_norm += new_coef[ofsj] / 2;
+    else one_norm -= new_coef[ofsj] / 2;
+    if ( mod2(cur_cut->non_weak_coef[j]) == ODD ) {
+      if ( mod2(new_coef[ofsj]) == EVEN ) 
+	weak_loss -= p_ilp->min_loss_by_weak[j];
+    }
+    else {
+      if ( mod2(new_coef[ofsj]) == ODD ) 
+	weak_loss += p_ilp->min_loss_by_weak[j];
+    }
+  }
+    
+  viol = ( 1.0 - slack_sum - weak_loss ) / 2.0;
+
+  score = tabu_score(NULL,0,viol,static_cast<double> (one_norm));
+/*
+printf("Score estimate 2 %f   Threshold %f\n",score,thresh);
+*/
+  if ( score < thresh + ZERO || FAST_SCORE_EVAL ) {
+
+    free(new_coef);
+    return (score);
+  }
+  /* get the actual cut coefficients and the violation of the 
+     best cut obtainable trough weakening */
+
+  ccoef = reinterpret_cast<int *> (calloc(n,sizeof(int)));
+  if ( ccoef == NULL ) alloc_error(const_cast<char*>("ccoef"));
+  for ( j = 0; j < n; j++ ) ccoef[j] = cur_cut->non_weak_coef[j];
+  for ( ofsj = 0; ofsj < inp_ilp->mtcnt[i]; ofsj++ ) {
+    ij = begi + ofsj;
+    j = inp_ilp->mtind[ij];
+    ccoef[j] = new_coef[ofsj];
+  }
+
+  ok = best_cut(ccoef,&crhs,&viol,FALSE,FALSE);
+  if ( ok ) score = tabu_score(ccoef,crhs,viol,static_cast<double> (one_norm));
+  else {
+    viol = ( - slack_sum - weak_loss ) / 2.0;
+    score = PENALTY_NON_WEAKABLE + tabu_score(ccoef,crhs,viol,static_cast<double> (one_norm));
+  }
+
+/*
+printf("Score actual %f   Threshold %f\n",score,thresh);
+*/
+
+  free(new_coef);
+  free(ccoef);
+  return(score);
+}
+
+/* modify_current: update the current local search solution by inserting/
+   deleting a constraint */
+
+void Cgl012Cut::modify_current(
+		    int i, /* constraint to be moved */
+		    short int itype /* type of move - ADD or DEL */
+		    )
+{
+  int j, begi, gcdi, ofsj, ij; 
+  short int flag_gt;
+
+  if ( itype == ADD ) {
+    cur_cut->n_of_constr++;
+    cur_cut->in_constr_list[i] = IN;
+  }
+  else {
+    cur_cut->n_of_constr--;
+    cur_cut->in_constr_list[i] = OUT;
+  }
+  last_moved[i] = it;
+
+  /* compute the new cut coefficients and rhs (before weakening) */
+
+  if ( ( itype == ADD && inp_ilp->msense[i] != 'G' ) ||
+    ( itype == DEL && inp_ilp->msense[i] == 'G' ) ) flag_gt = 1;
+  else flag_gt = -1;
+  begi = inp_ilp->mtbeg[i];
+  gcdi = p_ilp->gcd[i];
+  for ( ofsj = 0; ofsj < inp_ilp->mtcnt[i]; ofsj++ ) {
+    ij = begi + ofsj;
+    j = inp_ilp->mtind[ij];
+    /* the '*' and '/' operations can be saved by writing some more code ... */
+    cur_cut->non_weak_coef[j] += flag_gt * (inp_ilp->mtval[ij] / gcdi);
+  }
+  cur_cut->non_weak_rhs += flag_gt * (inp_ilp->mrhs[i] / gcdi);
+
+  if ( itype == ADD ) 
+    cur_cut->slack_sum += p_ilp->slack[i] / static_cast<double> (gcdi);
+  else 
+    cur_cut->slack_sum -= p_ilp->slack[i] / static_cast<double> (gcdi);
+
+  /* get the best possible cut */
+
+  cur_cut->min_weak_loss = 0.0;
+  for ( j = 0; j < n; j++ ) {
+    cur_cut->coef[j] = cur_cut->non_weak_coef[j];
+    if ( mod2(cur_cut->coef[j]) == ODD ) 
+      cur_cut->min_weak_loss += p_ilp->min_loss_by_weak[j];
+  }
+  cur_cut->rhs = cur_cut->non_weak_rhs;
+  cur_cut->ok = 
+    best_cut(cur_cut->coef,&cur_cut->rhs,&cur_cut->violation,TRUE,FALSE);
+  cur_cut->one_norm = 0;
+  for ( j = 0; j < n; j++ ) {
+    if ( cur_cut->coef[j] > 0 ) cur_cut->one_norm += cur_cut->coef[j];
+    else cur_cut->one_norm -= cur_cut->coef[j];
+  }
+}
+
+/* get_current_cut: return a cut data type with the information about
+   the current cut of the search procedure */
+
+cut *Cgl012Cut::get_current_cut()
+{
+  int i, j, nz;
+  /*double viol;*/
+  cut *cut_ptr;
+
+  cut_ptr = reinterpret_cast<cut *> (calloc(1,sizeof(cut)));
+  if ( cut_ptr == NULL ) alloc_error(const_cast<char*>("cut_ptr"));  
+  cut_ptr->crhs = cur_cut->rhs;
+  cut_ptr->csense = 'L';
+  /* count the number of nonzeroes in the cut */
+  for ( j = 0, nz = 0; j < n; j++ ) if ( cur_cut->coef[j] != 0 ) nz++;
+  cut_ptr->cnzcnt = nz; 
+  cut_ptr->cind = reinterpret_cast<int *> (calloc(nz,sizeof(int)));
+  if ( cut_ptr->cind == NULL ) alloc_error(const_cast<char*>("cut_ptr->cind"));
+  cut_ptr->cval = reinterpret_cast<int *> (calloc(nz,sizeof(int)));
+  if ( cut_ptr->cval == NULL ) alloc_error(const_cast<char*>("cut_ptr->cval"));
+  nz = 0; /*viol = 0.0;*/
+  for ( j = 0; j < n; j++ ) {
+    if ( cur_cut->coef[j] != 0 ) {
+      cut_ptr->cind[nz] = j;
+      cut_ptr->cval[nz] = cur_cut->coef[j];
+      nz++;
+      /* viol += p_ilp->xstar[j] * (double) cur_cut->coef[j]; */
+    }
+  }
+  /* viol -= (double) cur_cut->rhs; */
+  /* cut_ptr->violation = viol; */
+  cut_ptr->violation = cur_cut->violation;
+  cut_ptr->n_of_constr = 0;
+  cut_ptr->constr_list = reinterpret_cast<int *> (calloc(inp_ilp->mr,sizeof(int)));
+  if ( cut_ptr->constr_list == NULL ) alloc_error(const_cast<char*>("cut_ptr->constr_list"));
+  cut_ptr->in_constr_list = reinterpret_cast<short int *> (calloc(inp_ilp->mr,sizeof(short int)));
+  if ( cut_ptr->in_constr_list == NULL ) alloc_error(const_cast<char*>("cut_ptr->in_constr_list"));
+  for ( i = 0; i < m; i++ ) {
+    if ( cur_cut->in_constr_list[i] == IN ) {
+      cut_ptr->in_constr_list[i] = IN;
+      cut_ptr->constr_list[cut_ptr->n_of_constr] = i;
+      (cut_ptr->n_of_constr)++;
+    }
+    else cut_ptr->in_constr_list[i] = OUT;
+  }
+  return(cut_ptr);
+}
+
+/* best neighbour: find the cut to be added/deleted from the current
+   solution among those allowed by the tabu rules */
+
+short int Cgl012Cut::best_neighbour(cut_list *out_cuts /* list of the violated cuts found */)
+{
+  int i, ibest;
+  short int itype, itypebest=-1;
+  double score, max_score;
+  cut *new_cut;
+
+  /* cycle through all the constraints in your problem ... */
+
+  max_score = -INF;  
+  ibest = NONE;
+  for ( i = 0; i < m; i++ ) {
+    if ( ! p_ilp->row_to_delete[i] && allowed(i) ) {
+      if ( in_cur_cut(i) ) {
+	/* constraint i is in the current set of constraints  
+	   (those defining the current cut) */
+	itype = DEL;
+      }
+      else {
+	/* constraint i is not in the current set of constraints  
+	   (those defining the current cut) */
+	itype = ADD;
+      } 
+      score = score_by_moving(i,itype,max_score); 
+      if ( score > max_score ) {
+	/* best cut found in this iteration: store it */
+	ibest = i;
+	itypebest = itype;
+	max_score = score;
+      }
+    }
+  } /* for ( i = 0; i < m; i++ ) */
+  
+  if ( ibest == NONE ) {
+#ifdef PRINT_TABU
+    printf("No move could be performed by best_neighbour\n");
+#endif
+    return(TRUE);
+  }
+  modify_current(ibest,itypebest);  
+  if ( cur_cut->violation > MIN_VIOLATION + EPS ) {
+#ifdef PRINT_TABU
+    printf("... adding the current cut to the output list - it = %d viol = %f\n",it, cur_cut->violation);
+#endif
+    new_cut = get_current_cut();
+    out_cuts = add_cut_to_list(new_cut,out_cuts);
+    last_it_add = it;
+  }
+  return(FALSE);
+}
+
+/* memory_reaction: perform the long term reaction by cheching whether the
+   current solution has already been visited or the best solution has not 
+   been updated for too many iterations */
+
+void memory_reaction()
+{
+  int cycle_length;
+
+  if ( hash_search(&cycle_length) ) {
+    if ( cycle_length < 2 * ( m - 1 ) ) {
+      increase_prohib_period();
+      return;
+    }
+  }
+  else hash_insert();
+  if ( it - last_prohib_period_mod > B ) 
+    decrease_prohib_period();
+}
+
+/* add_tight_constraint: initialize the current cut by adding a tight 
+   constraint to it */
+       
+void Cgl012Cut::add_tight_constraint()
+{
+  int i, ntight;
+  double smin=COIN_DBL_MAX;
+  abort();
+  int *tight;
+    
+  ntight = 0;
+  tight = reinterpret_cast<int *> (calloc(m,sizeof(int)));
+  if ( tight == NULL ) alloc_error(const_cast<char*>("tight"));
+  for ( i = 0; i < m; i++ ) {
+    /* search for the tightest constraint never added to cut */
+    if ( last_moved[i] < 0 && p_ilp->slack[i] < smin ) {
+      if ( p_ilp->slack[i] < ZERO ) {
+	/* tight constraint */
+	smin = ZERO;
+	tight[ntight] = i;   
+	ntight++;
+      }
+      else {
+	/* best constraint so far */
+	smin = p_ilp->slack[i];
+	tight[0] = i;
+	ntight = 1;
+      }
+    }
+  }
+  if ( ntight > 0 ) i = tight[rand() % ntight];
+  /* if all constraints have already been in cur_cut choose first at random */
+  else i = rand() % m;
+  free(tight);
+  modify_current(i,ADD);
+}    
+
+/* initialize: initialize the data structures for local search */
+
+void Cgl012Cut::initialize()
+{
+  int i;
+
+  m = inp_ilp->mr;
+  n = inp_ilp->mc;
+  it = 0;
+  last_it_add = 0;
+  last_it_restart = 0;
+  last_prohib_period_mod = 0;
+  prohib_period = IN_PROHIB_PERIOD; 
+  initialize_cur_cut();
+  last_moved = reinterpret_cast<int *> (calloc(m,sizeof(int)));
+  if ( last_moved == NULL ) alloc_error(const_cast<char*>("last_moved"));
+  for ( i = 0; i < m; i++ ) {
+    last_moved[i] = -COIN_INT_MAX;
+  }
+  initialize_hash_table();
+  add_tight_constraint();
+  A = m;
+  B = 10 * m;
+}
+
+/* restart: perform a restart of the search - IMPORTANT: in the current
+   implementation vector last_moved is not cleared at restart */
+       
+void Cgl012Cut::restart(short int failure /* flag forcing the restart if some trouble occurred */)
+{
+  if ( failure || ( it - last_it_add > A && it - last_it_restart > A ) ) {
+    /* perform restart */
+    last_it_restart = it;
+    prohib_period = IN_PROHIB_PERIOD;
+    last_prohib_period_mod = it;
+    clear_hash_table();
+    clear_cur_cut();
+    add_tight_constraint();
+  }
+}
+
+/* free_memory: free the memory used by local search */
+
+void free_memory()
+{
+  free_cur_cut();
+  free(last_moved);
+  free_hash_table();
+}
+
+/* tabu_012: try to identify violated 0-1/2 cuts by a simple tabu search
+   procedure adapted from that used by Battiti and Protasi for finding
+   large cliques */
+
+cut_list *Cgl012Cut::tabu_012()
+{
+  short int failure;
+  cut_list *out_cuts;
+
+  out_cuts = initialize_cut_list(MAX_CUTS);
+  initialize();
+ 
+  it = 0; 
+  do {
+    memory_reaction();
+    failure = best_neighbour(out_cuts);
+#ifdef PRINT_TABU
+    print_cur_cut();
+#endif
+    it++;
+    restart(failure);
+
+  }
+  while ( out_cuts->cnum < MAX_CUTS && it < MAX_TABU_ITER );
+  free_memory();
+#ifdef PRINT_TABU
+    printf("Number of violated cuts found by Tabu Search %d\n",out_cuts->cnum);
+    printf("Tabu Search timings: best_neighbour %f  score_by_moving %f coefficient %f  best_cut %f\n",
+	   time_best_neigh, time_scor_by_mov, time_coef, time_best_cut);
+#endif
+  return(out_cuts);
+}
+//end include "Cgltabu_012.c"
+#ifdef POOL 
+
+/* same_pool_cut: check whether two pool cuts are in fact the same cut */
+
+short int same_pool_cut(pool_cut *p_cut1, pool_cut *p_cut2)
+{
+  int c;
+
+  if ( p_cut1->n_of_constr != p_cut2->n_of_constr ) return(FALSE);
+  if ( p_cut1->code != p_cut2->code ) return(FALSE);
+  /* assumes constr_list is sorted for increasing/decreasing constraint index */
+  for ( c = 1; c < p_cut1->n_of_constr; c++ )
+    if ( p_cut1->constr_list[c] != p_cut2->constr_list[c] ) return(FALSE);
+  return(TRUE);
+}
+
+/* free_pool_cut: free the memory for a non-empty pool cut */
+
+void free_pool_cut(pool_cut *p_cut)
+{
+  if ( p_cut == NULL ) return;
+  if ( p_cut->constr_list != NULL ) free(p_cut->constr_list);
+  free(p_cut);
+}
+
+/* initialize_pool: initialize the pool data structure */
+
+void initialize_pool()
+{
+  pool = (pool_cut_list *) calloc(1,sizeof(pool_cut_list));
+  if ( pool == NULL ) alloc_error(const_cast<char*>("pool"));
+  pool->cnum = 0;
+  pool->list = (pool_cut **) calloc(MAX_CUT_POOL,sizeof(pool_cut *));
+  if ( pool->list == NULL ) alloc_error(const_cast<char*>("pool->list"));
+  pool->ncod = (int *) calloc(MAX_CUT_COD,sizeof(int));
+  if ( pool->ncod == NULL ) alloc_error(const_cast<char*>("pool->ncod"));
+}
+
+/* free_pool: free the memory used by the pool */
+
+void free_pool()
+{
+  int c;
+
+  if ( pool == NULL ) return;
+  for ( c = 0; c < pool->cnum; c++ ) 
+    free_pool_cut(pool->list[c]);
+  free(pool);
+}
+
+/* clean_pool: remove form the pool the cuts which are inactive since a
+   large number of iterations */
+
+void clean_pool()
+{
+  int c, d;
+
+  /* the pool compression could be implemented more efficiently */
+
+  for ( c = 0; c < pool->cnum; c++ ) {
+    if ( pool->list[c]->it_found > MAX_ITER_POOL ) {
+      free_pool_cut(pool->list[c]);
+      pool->list[c] = NULL;
+      for ( d = c ; d < pool->cnum; d++ ) 
+	pool->list[d] = pool->list[d + 1];
+      (pool->cnum)--;
+    }
+  }
+}
+
+/* insert_cut_in_pool: add a cut to the pool if there is space */
+
+void insert_cut_in_pool(pool_cut *p_cut)
+{
+
+  if ( pool->cnum == MAX_CUT_POOL ) {
+#ifdef COIN_DEVELOP
+    printf("Warning: pool is full and separated cuts cannot be added\n");
+#endif
+    return;
+  }
+  pool->list[pool->cnum] = p_cut;
+  (pool->cnum)++;
+  (pool->ncod[p_cut->code])++;
+}
+
+/* cut_is_in_pool: check whether a given cut is already in the pool */
+
+short int cut_is_in_pool(cut *v_cut)
+{
+  int c, i, cod;
+  short int equal;
+  short int *flag_v;
+  pool_cut *p_cut;
+
+/*
+print_cut(v_cut);
+printf("checking for a cut in the pool ...\n");
+*/
+  cod = hash_addr(inp_ilp->mr,v_cut->in_constr_list);
+  if ( pool->ncod[cod] == 0 ) return(FALSE);
+  /* trivial sequential search */
+/*
+printf("... sequential search needed ...\n");
+*/
+  flag_v = (short int *) calloc(inp_ilp->mr,sizeof(short int));
+  if ( flag_v == NULL ) alloc_error(const_cast<char*>("flag_v"));
+  for ( c = 0; c < pool->cnum; c++ ) {
+    if ( pool->list[c]->code != cod ) continue;
+    p_cut = pool->list[c];
+    equal = TRUE;
+    for ( i = 0; i < inp_ilp->mr; i++ ) flag_v[i] = OUT;
+    for ( i = 0; i < p_cut->n_of_constr; i++ ) 
+      flag_v[p_cut->constr_list[i]] = IN;
+    for ( i = 0; i < inp_ilp->mr; i++ ) {
+      if ( v_cut->in_constr_list[i] != flag_v[i] ) {
+	equal = FALSE;
+	break;
+      }
+    }
+    if ( equal ) {
+      free(flag_v);
+/*
+printf("... cut was in the pool!\n");
+*/
+      return(TRUE);
+    }
+  }
+  return(FALSE);
+}
+
+/* good_pool_cut: check whether the current cut is worth adding to the pool */
+
+short int good_pool_cut(cut *v_cut)
+{
+  /* no check performed */
+  return(TRUE);
+}
+
+/* add_cuts_to_pool: add the cuts separated to the pool structure */
+
+void add_cuts_to_pool(cut_list *out_cuts)
+{
+  int i, c;
+  cut *v_cut;
+  pool_cut *p_cut;
+  /* float ti, tf, tti, ttf; */
+  /* static float tcutis = 0.0, taddcut = 0.0; */
+
+  /* second_(&tti); */
+
+  if ( pool == NULL ) initialize_pool();
+  if ( pool->cnum >= MAX_CUT_POOL * CLEAN_THRESH ) clean_pool();
+
+  for ( i = 0; i < out_cuts->cnum; i++ ) {
+    v_cut = out_cuts->list[i];
+    /* second_(&ti); */
+    if ( cut_is_in_pool(v_cut) ) {
+      /* second_(&tf); */
+      /* tcutis += tf - ti; */
+      continue;
+    }
+    else {
+      /* second_(&tf); */
+      /* tcutis += tf - ti; */
+    }
+    if ( good_pool_cut(v_cut) ) {
+      /* add the cut to the pool list */
+      p_cut = (pool_cut *) calloc(1,sizeof(pool_cut));
+      if ( p_cut == NULL ) alloc_error(const_cast<char*>("p_cut"));
+      p_cut->n_of_constr = v_cut->n_of_constr;
+      p_cut->constr_list = (int *) calloc(v_cut->n_of_constr,sizeof(int));
+      if ( p_cut->constr_list == NULL ) alloc_error(const_cast<char*>("p_cut->constr_list"));
+      for ( c = 0; c < v_cut->n_of_constr; c++ ) 
+	p_cut->constr_list[c] = v_cut->constr_list[c];
+      p_cut->code = hash_addr(inp_ilp->mr,v_cut->in_constr_list);
+      p_cut->n_it_violated = 0;
+      p_cut->it_found = sep_iter;
+      insert_cut_in_pool(p_cut);
+    }
+  }
+
+  /* second_(&ttf); */
+  /* taddcut += ttf - tti; */
+  /* printf("add_cuts_to_pool: tcutis %f  taddcut %f\n",tcutis,taddcut); */
+
+}
+
+/* interesting_var: decides whether a variable is relevant in the
+   separation or not */
+
+short int interesting_var(int j /* variable to be evaluated */)
+{
+  /* return ( vlog[j]->n_it_zero < MANY_IT_ZERO ); */
+  /* if ( aggr ) return (TRUE); */
+  return( ! p_ilp->col_to_delete[j] );
+}
+
+/* get_cuts_from_pool: select from the pool a convenient set of violated
+   constraints to be added to the current LP */
+
+static double max_score_ever = ZERO; /* maximum score of a violated cut during
+					the whole cutting plane procedure */
+#define MIN_CUT_SCORE ( max_score_ever / MIN_SCORE_RANGE )
+#define MAX_CUT_SCORE ( max_score_ever / MAX_SCORE_RANGE )
+#define MIN_IT_VIOL 2
+
+cut_list *get_cuts_from_pool(
+short int after_sep /* flag telling whether the pool is searched after
+			a new separation in which case only new cuts are
+			checked */
+			     )
+{
+  int c, crhs, j, k, l, maxc, n_interest_var;
+  double viol, score, maxscore, min_cut_score, max_cut_score;
+  short int ok;
+  int *interest_var, *ccoef;
+  short int *added;
+  pool_cut *p_cut;
+  select_cut **best_var_cut;
+  cut *a_cut;
+  cut_list *add_cuts;
+  /* float ti, tf, tti, ttf; */
+  /* static float tgetcut = 0.0, talloc = 0.0, tgetcoef = 0.0, tbestcut = 0.0, tscore = 0.0, tupdbest = 0.0, tadd = 0.0; */
+
+  /* second_(&tti); */
+
+  if ( pool == NULL ) {
+    add_cuts = initialize_cut_list(1);  
+    return(add_cuts);
+  }
+
+  /* in the current implementation, the cut with best score with nonzero
+     coefficient for each "interesting" variable is added to the current LP, 
+     provided the cut satisfies some requirements (violation, depth, etc.) */
+
+  /* define the set of the interesting variables */
+  interest_var = (int *) calloc(p_ilp->mc,sizeof(int));
+  if ( interest_var == NULL ) alloc_error(const_cast<char*>("interest_var"));
+  n_interest_var = 0;
+  for ( j = 0; j < p_ilp->mc; j++ ) {
+    if ( interesting_var(j) ) {
+      interest_var[n_interest_var] = j;
+      n_interest_var++;
+    }
+  }
+  best_var_cut = (select_cut **) calloc(n_interest_var,sizeof(select_cut *));
+  if ( best_var_cut == NULL ) alloc_error(const_cast<char*>("best_var_cut"));
+  for ( k = 0; k < n_interest_var; k++ ) {
+    best_var_cut[k] = (select_cut *) calloc(1,sizeof(select_cut));
+    if ( best_var_cut[k] == NULL ) alloc_error(const_cast<char*>("best_var_cut[k]"));
+    best_var_cut[k]->ccoef = (int *) calloc(p_ilp->mc,sizeof(int));
+    if ( best_var_cut[k]->ccoef == NULL )
+      alloc_error(const_cast<char*>("best_var_cut[k]->ccoef"));
+    best_var_cut[k]->score = -INF;
+  }
+
+  /* find the cuts with the best scores and the list of the cuts
+     violated by the current fractional point */
+  maxscore = -INF;
+  ccoef = (int *) calloc(p_ilp->mc,sizeof(int));
+  if ( ccoef == NULL ) alloc_error(const_cast<char*>("ccoef"));
+
+  /* second_(&tf); */
+  /* talloc += tf - tti; */
+
+  min_cut_score = MIN_CUT_SCORE;
+  max_cut_score = MAX_CUT_SCORE;
+
+  for ( c = 0; c < pool->cnum; c++ ) {
+    p_cut = pool->list[c];
+    /* if a new separation was made before the call check only new cuts */
+    if ( after_sep && p_cut->it_found != sep_iter ) continue; 
+    /* determine the actual coefficients of the cut */
+    /* second_(&ti); */
+    ok = get_ori_cut_coef(p_cut->n_of_constr,p_cut->constr_list,
+			  ccoef,&crhs,TRUE);
+    /* second_(&tf); */
+    /* tgetcoef += tf - ti; */
+    /* second_(&ti); */
+    ok = ok && best_cut(ccoef,&crhs,&viol,TRUE,TRUE);
+    /* second_(&tf); */
+    /* tbestcut += tf - ti; */
+    if ( ok && viol > MIN_VIOLATION ) {
+      (p_cut->n_it_violated)++; 
+      /* second_(&ti); */
+      score = cut_score(ccoef,crhs,viol,TRUE);
+      if ( score > maxscore ) {
+	maxscore = score;
+	maxc = c;
+      }
+      /* second_(&tf); */
+      /* tscore += tf - ti; */
+      if ( ! aggr ) {
+	if ( score < min_cut_score ) continue;
+	if ( score < max_cut_score && p_cut->n_it_violated < MIN_IT_VIOL ) 
+	  continue;
+      }
+      /* second_(&ti); */
+      for ( k = 0; k < n_interest_var; k++ ) {
+	j = interest_var[k];
+	if ( ccoef[j] != 0 && best_var_cut[k]->score < score ) {
+	  best_var_cut[k]->score = score;
+	  for ( l = 0; l < p_ilp->mc; l++ ) 
+	    best_var_cut[k]->ccoef[l] = ccoef[l];
+	  best_var_cut[k]->crhs = crhs;
+	  best_var_cut[k]->pool_index = c;
+	}
+      }
+      /* second_(&tf); */
+      /* tupdbest += tf - ti; */
+    }
+    else p_cut->n_it_violated = 0;
+  }
+  free(ccoef);
+
+/* printf("maxscore of a cut : %f  ever: %f\n",maxscore,max_score_ever); */
+  if ( maxscore > max_score_ever ) max_score_ever = maxscore;
+
+  /* second_(&ti); */
+
+  add_cuts = initialize_cut_list(n_interest_var);
+  added = (short int *) calloc(pool->cnum,sizeof(short int));
+  if ( added == NULL ) alloc_error(const_cast<char*>("added"));
+  for ( c = 0; c < pool->cnum; c++ ) added[c] = FALSE;
+
+  for ( k = 0; k < n_interest_var; k++ ) {
+    j = interest_var[k];  
+    if ( ! added[best_var_cut[k]->pool_index] &&
+	 best_var_cut[k]->score >= MIN_CUT_SCORE ) {
+      /* add the cut to the cut list on output */
+      a_cut = define_cut(best_var_cut[k]->ccoef,best_var_cut[k]->crhs);
+      add_cuts = add_cut_to_list(a_cut,add_cuts);
+      added[best_var_cut[k]->pool_index] = TRUE;
+    }
+    free(best_var_cut[k]->ccoef);
+    free(best_var_cut[k]);
+  }
+  free(best_var_cut);
+  free(interest_var);
+  free(added);
+
+  /* second_(&tf); */
+  /* tadd += tf - ti; */
+
+  /* second_(&ttf); */
+  /* tgetcut += ttf - tti; */
+  /* printf("get_cuts_from_pool: talloc %f  tgetcoef %f  tbestcut %f  tscore %f  tupdbest %f  tadd %f  tgetcut %f\n",talloc,tgetcoef,tbestcut,tscore,tupdbest,tadd,tgetcut); */
+
+  return(add_cuts);
+}
+#endif
+/* initialize_log_var: initialize the log information for the problem variables */  
+
+void Cgl012Cut::initialize_log_var()
+{
+  int j;
+  if (!vlog) {
+    if (p_ilp->mc) {
+      vlog = reinterpret_cast<log_var **> (calloc(p_ilp->mc,sizeof(log_var *)));
+      if ( vlog == NULL ) alloc_error(const_cast<char*>("vlog"));
+      for ( j = 0; j < p_ilp->mc; j++ ) {
+	vlog[j] = reinterpret_cast<log_var *> (calloc(1,sizeof(log_var)));
+	if ( vlog[j] == NULL ) alloc_error(const_cast<char*>("vlog[j]"));
+	vlog[j]->n_it_zero = 0;
+      }
+    }
+  } else {
+    // just initialize counts
+    for ( j = 0; j < p_ilp->mc; j++ ) {
+      vlog[j]->n_it_zero = 0;
+    }
+  }
+}
+
+/* free_log_var */
+
+void Cgl012Cut::free_log_var()
+{
+  if (vlog) {
+    int j;
+    for ( j = 0; j < p_ilp->mc; j++ ) free(vlog[j]);
+    free(vlog);
+    vlog=NULL;
+  }
+}
+
+/* update_log_var: update the log information for the problem variables */
+
+void Cgl012Cut::update_log_var()
+{
+  int j;
+
+  /* so far one counts only the number of consecutive iterations with
+     0 value for each variable */
+
+  if ( vlog == NULL ) initialize_log_var();
+    
+  for ( j = 0; j < p_ilp->mc; j++ ) {
+    if ( p_ilp->xstar[j] < ZERO && p_ilp->xstar[j] > - ZERO ) 
+      vlog[j]->n_it_zero++;
+    else  vlog[j]->n_it_zero = 0;
+  }
+}
+
+/* the final implementation should use the following additional functions:
+   init_sep_012_cut: defines the inp_ilp and p_ilp data structures and 
+		     initializes pool and vlog
+   sep_012_cut: updates inp_ilp and p_ilp, performs separation and pool
+		management
+   kill_sep_012_cut: frees all the permanent memory (inp_ilp, p_ilp,
+		     pool, vlog, etc.)
+*/
+
+int Cgl012Cut::sep_012_cut(
+/*
+  INPUT parameters:
+*/
+int mr, /* number of rows in the ILP matrix */
+int mc, /* number of columns in the ILP matrix */
+int mnz, /* number of nonzero's in the ILP matrix */
+int *mtbeg, /* starting position of each row in arrays mtind and mtval */
+int *mtcnt, /* number of entries of each row in arrays mtind and mtval */
+int *mtind, /* column indices of the nonzero entries of the ILP matrix */
+int *mtval, /* values of the nonzero entries of the ILP matrix */
+int *vlb, /* lower bounds on the variables */
+int *vub, /* upper bounds on the variables */
+int *mrhs, /* right hand sides of the constraints */
+char *msense, /* senses of the constraints: 'L', 'G' or 'E' */
+const double *xstar, /* current optimal solution of the LP relaxation */
+bool aggressive, /* flag asking whether as many cuts as possible are
+			 required on output (TRUE) or not (FALSE) */
+/*
+  OUTPUT parameters (the memory for the vectors is allocated INTERNALLY
+  by the procedure: if some memory is already allocated, it is FREED):
+*/
+int *cnum, /* number of violated 0-1/2 cuts identified by the procedure */
+int *cnzcnt, /* overall number of nonzero's in the cuts */
+int **cbeg, /* starting position of each cut in arrays cind and cval */
+int **ccnt, /* number of entries of each cut in arrays cind and cval */
+int **cind, /* column indices of the nonzero entries of the cuts */
+int **cval, /* values of the nonzero entries of the cuts */
+int **crhs, /* right hand sides of the cuts */
+char **csense /* senses of the cuts: 'L', 'G' or 'E' */
+/* 
+  NOTE that all the numerical input/output vectors are INTEGER (with
+  the exception of xstar), since the procedure is intended to work
+  with pure ILP's, and that the ILP matrix has to be given on input
+  in ROW format.
+*/
+		)
+{
+#ifdef TIME
+  float tbasi, tbasf;
+#endif
+  errorNo=0;
+  cut_list *out_cuts, *add_cuts;
+#ifdef TIME
+  second_(&tti);
+#endif
+
+  aggr = aggressive; 
+
+  /* load the input ILP into an internal data structure */
+  
+  //ilp_load(mr,mc,mnz,mtbeg,mtcnt,mtind,mtval,
+  //   vlb,vub,mrhs,msense);
+  inp_ilp->xstar = xstar;
+  
+
+  /* construct an internal data structure containing all the information
+     which can be useful for 0-1/2 cut separation  - this may in fact be
+     done only at the first call of the separation procedure */
+
+#ifdef TIME
+  second_(&ti);
+#endif
+
+  get_parity_ilp();
+
+/*
+print_double_vect("xstar",p_ilp->xstar,p_ilp->mc); 
+print_parity_ilp();
+*/
+
+#ifdef TIME
+  second_(&tf);
+  prep_time += tf - ti;
+#endif
+
+  if ( p_ilp->mnz == 0 ) {
+#ifdef COIN_DEVELOP
+    printf("Warning: no significant constraint for 0-1/2 cut separation\n");
+    printf("... end separation\n");
+#endif
+    //free_ilp();
+    //free_parity_ilp();
+#ifdef TIME
+  second_(&ttf);
+  total_time += ttf - tti;
+#endif 
+    return(FALSE);
+  }
+
+/* print_double_vect("xstar",p_ilp->xstar,p_ilp->mc); */
+
+  sep_iter++;
+  update_log_var();
+
+#ifdef POOL
+
+  /* search for possible violated cuts in the pool */
+
+#ifdef TIME
+  second_(&tpi);
+#endif
+  add_cuts = get_cuts_from_pool(FALSE);
+#ifdef TIME
+  second_(&tpf);
+  pool_time += tpf - tpi;
+#ifdef PRINT_TIME
+  printf("... time elapsed at the end of get_cuts_from_pool: %f\n",tpf - tti);
+#endif
+#endif
+
+  if ( add_cuts->cnum == 0 ) {
+    free_cut_list(add_cuts);
+  }
+  else {
+/* printf("Violated cuts found in the pool - no separation procedure used\n"); */
+    goto free_memory;
+  }
+
+#endif
+
+  /* try to identify violated 0-1/2 cuts by using the original procedure 
+     described in Caprara and Fischetti's MP paper */
+
+#ifdef TIME
+  second_(&tbasi);
+#endif
+  
+  out_cuts = basic_separation(); 
+
+#ifdef TIME
+  second_(&tbasf);
+  tot_basic_sep_time += tbasf - tbasi;
+  avg_basic_sep_time = tot_basic_sep_time / (float) sep_iter;
+#endif
+
+//#define TABU_SEARCH 
+#ifdef TABU_SEARCH
+
+  /* try to identify violated cuts by tabu search if none was found */
+
+  if ( out_cuts->cnum == 0 ) {
+    free_cut_list(out_cuts); 
+
+#ifdef TIME
+  second_(&ttabi);
+#endif
+
+    out_cuts = tabu_012(); 
+
+#ifdef TIME
+  second_(&ttabf);
+  tabu_time += ttabf - ttabi;
+#endif
+
+  }
+
+#endif
+
+#ifdef POOL
+
+  /* add the cuts separated to the pool */
+
+#ifdef TIME
+  second_(&tpi);
+#endif
+  add_cuts_to_pool(out_cuts);
+  free_cut_list(out_cuts); 
+
+  /* select from the pool a convenient set of violated constraints
+     to be added to the current LP */
+
+  add_cuts = get_cuts_from_pool(TRUE);
+#ifdef TIME
+  second_(&tpf);
+  pool_time += tpf - tpi;
+#ifdef PRINT_TIME
+  printf("... time elapsed at the end of get_cuts_from_pool: %f\n",tpf - tti);
+#endif
+#endif
+
+#else
+
+  /* give on output the cuts separated */
+
+  add_cuts = out_cuts;
+
+#endif
+
+  //free_ilp();
+  //free_parity_ilp();
+  
+#ifdef TIME
+  second_(&ttf);
+  total_time += ttf - tti;
+#endif 
+
+  if ( add_cuts->cnum > 0 ) {
+    getcuts(add_cuts,cnum,cnzcnt,cbeg,ccnt,cind,cval,crhs,csense);
+/* print_cut_list(add_cuts); */
+    free_cut_list(add_cuts); 
+    return(TRUE); 
+  }
+  else {
+    free_cut_list(add_cuts); 
+    return(FALSE); 
+  }
+}
+
+#ifdef TIME
+/* print_times: print the timings of the separation procedure */
+
+void print_times()
+{
+  printf("... separation timings \n");
+  printf("times  total: %f  prep: %f  weak: %f  aux: %f  path: %f cycle: %f  cut: %f (%d calls)  bw: %f  coef: %f  pool: %f  tabu: %f\n",
+    total_time, prep_time, weak_time, aux_time, path_time, cycle_time, cut_time, cut_ncalls, bw_time, coef_time, pool_time, tabu_time);
+}
+#endif
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+Cgl012Cut::Cgl012Cut () :
+  inp_ilp(NULL),
+  p_ilp(NULL),
+  iter(0),
+  gap(0.0),
+  maxgap(0.0),
+  errorNo(0),
+  sep_iter(0),
+  vlog(NULL),
+  aggr(true)
+{
+  // nothing to do here
+}
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+Cgl012Cut::Cgl012Cut (const Cgl012Cut & rhs) :
+  inp_ilp(NULL),
+  p_ilp(NULL),
+  iter(rhs.iter),
+  gap(rhs.gap),
+  maxgap(rhs.maxgap),
+  errorNo(rhs.errorNo),
+  sep_iter(rhs.sep_iter),
+  vlog(NULL),
+  aggr(rhs.aggr)
+{
+  if (rhs.p_ilp||rhs.vlog||inp_ilp)
+    abort();  
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+Cgl012Cut::~Cgl012Cut ()
+{
+  free_log_var();
+  free_parity_ilp();
+  free_ilp();
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+Cgl012Cut &
+Cgl012Cut::operator=(
+                   const Cgl012Cut& rhs)
+{
+  if (this != &rhs) {
+    if (rhs.p_ilp||rhs.vlog||inp_ilp)
+      abort();  
+    free_log_var();
+    free_parity_ilp();
+    free_ilp();
+#if 0
+    inp_ilp = reinterpret_cast<ilp *> (calloc(1,sizeof(ilp)));
+    if ( inp_ilp == NULL ) alloc_error(const_cast<char*>("inp_ilp"));
+
+    inp_ilp->mr = rhs.inp_ilp->mr; inp_ilp->mc = rhs.inp_ilp->mc;
+    inp_ilp->mnz = rhs.inp_ilp->mnz; 
+    inp_ilp->mtbeg = rhs.inp_ilp->mtbeg; inp_ilp->mtcnt = rhs.inp_ilp->mtcnt; 
+    inp_ilp->mtind = rhs.inp_ilp->mtind; inp_ilp->mtval = rhs.inp_ilp->mtval; 
+    inp_ilp->vlb = rhs.inp_ilp->vlb; inp_ilp->vub = rhs.inp_ilp->vub; 
+    inp_ilp->mrhs = rhs.inp_ilp->mrhs; inp_ilp->msense = rhs.inp_ilp->msense;
+#endif
+    iter = rhs.iter;
+    gap = rhs.gap;
+    maxgap = rhs.maxgap;
+    errorNo = rhs.errorNo;
+    sep_iter = rhs.sep_iter;
+    aggr = rhs.aggr;
+  }
+  return *this;
+}
diff --git a/cbits/coin/Cgl012cut.hpp b/cbits/coin/Cgl012cut.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Cgl012cut.hpp
@@ -0,0 +1,464 @@
+// $Id: Cgl012cut.hpp 1150 2013-10-21 18:24:45Z tkr $
+// Copyright (C) 2010, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/** @file 012cut.h Include file for C coded 0-1/2 separator */
+#ifndef CGL012CUT
+#define CGL012CUT
+#include <cstdio>
+#include <cstdlib>
+#include <cmath>
+
+#define CGL_NEW_SHORT
+#ifndef CGL_NEW_SHORT
+typedef  /* arc */
+   struct arc_st
+{
+   int              len;            /* length of the arc */
+   struct node_st   *head;           /* head node */
+}
+  arc;
+
+typedef  /* node */
+   struct node_st
+{
+   arc              *first;           /* first outgoing arc */
+   int              dist;	      /* tentative shortest path length */
+   struct node_st   *parent;          /* parent pointer */
+   struct node_st   *next;            /* next node in queue */
+   struct node_st   *prev;            /* previous node in queue */
+   int               status;          /* status of node */
+   int               temp;            /* for temporary labels */
+   int               index;           /* index of the node in the graph */
+} node;
+#endif
+typedef struct 
+{
+  int length; // Length of arc
+  int to; // To node
+} cgl_arc;
+
+typedef struct
+{
+  cgl_arc * firstArc; // First outgoing arc 
+  int parentNode; // Parent node in shortest path 
+  int index; // Which node I am
+  int distanceBack; // Distance back to source
+} cgl_node;
+
+typedef struct 
+{
+  int nnodes; // Number of nodes in graph
+  int narcs; // Number of arcs in graph
+  cgl_node * nodes;
+  cgl_arc * arcs;
+} cgl_graph;
+/* #define PRINT */
+/* #define PRINT_CUTS */
+#define REDUCTION
+
+typedef struct {
+int mr; /* number of rows in the ILP matrix */
+int mc; /* number of columns in the ILP matrix */
+int mnz; /* number of nonzero's in the ILP matrix */
+int *mtbeg; /* starting position of each row in arrays mtind and mtval */
+int *mtcnt; /* number of entries of each row in arrays mtind and mtval */
+int *mtind; /* column indices of the nonzero entries of the ILP matrix */
+int *mtval; /* values of the nonzero entries of the ILP matrix */
+int *vlb; /* lower bounds on the variables */
+int *vub; /* upper bounds on the variables */
+int *mrhs; /* right hand sides of the constraints */
+char *msense; /* senses of the constraints: 'L', 'G' or 'E' */
+const double *xstar; /* current optimal solution of the LP relaxation */
+} ilp; 
+
+typedef struct {
+int mr; /* number of rows in the parity ILP matrix */
+int mc; /* number of columns in the parity ILP matrix */
+int mnz; /* number of 1's in the parity ILP matrix */
+int *mtbeg; /* starting position of each row in arrays mtind and mtval */
+int *mtcnt; /* number of entries of each row in arrays mtind and mtval */
+int *mtind; /* column indices of the 1's of the parity ILP matrix */
+short int *mrhs; /* right hand side parity of the constraints */
+double *xstar; /* current optimal solution of the LP relaxation */
+double *slack; /* slack of the constraints w.r.t. xstar */
+short int *row_to_delete; /* flag for marking rows not to be considered */
+short int *col_to_delete; /* flag for marking columns not to be considered */
+int *gcd; /* greatest common divisor of each row in the input ILP matrix */
+short int *possible_weak; /* possible weakening types of each column */
+short int *type_even_weak; /* type of even weakening of each column 
+                              (lower or upper bound weakening) */
+short int *type_odd_weak; /* type of odd weakening of each column 
+                              (lower or upper bound weakening) */
+double *loss_even_weak; /* loss for the even weakening of each column */
+double *loss_odd_weak; /* loss for the odd weakening of each column */
+double *min_loss_by_weak; /* minimum loss for the weakening of each column */
+} parity_ilp; 
+
+typedef struct {
+int nweak; /* number of variables weakened */
+int *var; /* list of variables weakened */
+short int *type; /* type of weakening (lower or upper bound weakening) */
+} info_weak;
+
+typedef struct {
+int endpoint1, endpoint2; /* endpoints of the edge */
+double weight; /* edge weight */
+short int parity; /* edge parity (even or odd) */
+int constr; /* constraint associated with the edge */
+info_weak *weak; /* weakening information */
+} edge;
+
+typedef struct {
+int nnodes; /* number of nodes */
+int nedges; /* number of edges */
+int *nodes; /* indexes of the ILP columns corresponding to the nodes */
+int *ind; /* indexes of the nodes corresponding to the ILP columns */
+edge **even_adj_list; /* pointers to the even edges */ 
+edge **odd_adj_list; /* pointers to the odd edges */ 
+} separation_graph;
+
+#ifndef CGL_NEW_SHORT
+typedef struct {
+int nnodes; /* number of nodes */
+int narcs; /* number of arcs */
+node *nodes; /* array of the nodes - see "types_db.h" */ 
+arc *arcs; /* array of the arcs - see "types_db.h" */ 
+} auxiliary_graph;
+#else
+typedef struct {
+int nnodes; /* number of nodes */
+int narcs; /* number of arcs */
+cgl_node *nodes; /* array of the nodes - see "types_db.h" */ 
+cgl_arc *arcs; /* array of the arcs - see "types_db.h" */ 
+} auxiliary_graph;
+#endif
+
+typedef struct {
+long dist; /* distance from/to root */
+int pred; /* index of the predecessor */
+} short_path_node;
+
+typedef struct {
+double weight; /* overall weight of the cycle */
+int length; /* number of edges in the cycle */
+edge **edge_list; /* list of edges in the cycle */
+} cycle;
+
+typedef struct {
+int cnum; /* overall number of cycles */
+cycle **list; /* pointers to the cycles in the list */
+} cycle_list;
+
+typedef struct {
+int n_of_constr; /* number of constraints combined to get the cut */
+int *constr_list; /* list of the constraints combined */
+short int *in_constr_list; /* flag saying whether a given constraint is
+                              in the list of constraints of the cut (IN)
+                              or not (OUT) */
+int cnzcnt; /* overall number of nonzero's in the cut */
+int *cind; /* column indices of the nonzero entries of the cut */
+int *cval; /* values of the nonzero entries of the cut */
+int crhs; /* right hand side of the cut */
+char csense; /* sense of the cut: 'L', 'G' or 'E' */
+double violation; /* violation of the cut w.r.t. the current LP solution */
+} cut;
+
+typedef struct {
+int cnum; /* overall number of cuts */
+cut **list; /* pointers to the cuts in the list */
+} cut_list;
+
+typedef struct {
+int n_of_constr; /* number of constraints combined to get the cut */
+int *constr_list; /* list of the constraints combined */
+int code; /* identifier of the cut */
+int n_it_violated; /* number of consecutive iterations (starting from the
+                      last and going backward) in which the cut was
+                      violated by the LP solution */
+int it_found; /* iteration in which the cut was separated */
+double score; /* score of the cut, used to choose wich cut should be 
+                 added to the current LP (if any) */
+} pool_cut;
+ 
+typedef struct {
+int cnum; /* overall number of cuts */
+pool_cut **list; /* pointers to the cuts in the list */
+int *ncod; /* number of cuts with a given code in the pool */
+} pool_cut_list;
+
+typedef struct {
+int *ccoef; /* coefficients of the cut */
+int crhs; /* right hand side of the cut */
+int pool_index; /* index of the cut in the pool */
+double score; /* cut score (to be maximized) */
+} select_cut;
+
+typedef struct {
+int n_it_zero; /* number of consecutive iterations (starting from the
+                   last and going backward) in which each variable took
+                   the value 0 in the LP solution */
+} log_var;
+/** 012Cut Generator Class
+
+ This class is to make Cgl01cut thread safe etc
+*/
+
+class Cgl012Cut {
+ 
+public:
+
+  /**@name Generate Cuts */
+  //@{
+int sep_012_cut(
+/*
+  INPUT parameters:
+*/
+int mr, /* number of rows in the ILP matrix */
+int mc, /* number of columns in the ILP matrix */
+int mnz, /* number of nonzero's in the ILP matrix */
+int *mtbeg, /* starting position of each row in arrays mtind and mtval */
+int *mtcnt, /* number of entries of each row in arrays mtind and mtval */
+int *mtind, /* column indices of the nonzero entries of the ILP matrix */
+int *mtval, /* values of the nonzero entries of the ILP matrix */
+int *vlb, /* lower bounds on the variables */
+int *vub, /* upper bounds on the variables */
+int *mrhs, /* right hand sides of the constraints */
+char *msense, /* senses of the constraints: 'L', 'G' or 'E' */
+const double *xstar, /* current optimal solution of the LP relaxation */
+bool aggressive, /* flag asking whether as many cuts as possible are
+			 required on output (TRUE) or not (FALSE) */
+/*
+  OUTPUT parameters (the memory for the vectors is allocated INTERNALLY
+  by the procedure: if some memory is already allocated, it is FREED):
+*/
+int *cnum, /* number of violated 0-1/2 cuts identified by the procedure */
+int *cnzcnt, /* overall number of nonzero's in the cuts */
+int **cbeg, /* starting position of each cut in arrays cind and cval */
+int **ccnt, /* number of entries of each cut in arrays cind and cval */
+int **cind, /* column indices of the nonzero entries of the cuts */
+int **cval, /* values of the nonzero entries of the cuts */
+int **crhs, /* right hand sides of the cuts */
+char **csense /* senses of the cuts: 'L', 'G' or 'E' */
+/* 
+  NOTE that all the numerical input/output vectors are INTEGER (with
+  the exception of xstar), since the procedure is intended to work
+  with pure ILP's, and that the ILP matrix has to be given on input
+  in ROW format.
+*/
+		);
+void ilp_load(
+	      int mr, /* number of rows in the ILP matrix */
+	      int mc, /* number of columns in the ILP matrix */
+	      int mnz, /* number of nonzero's in the ILP matrix */
+	      int *mtbeg, /* starting position of each row in arrays mtind and mtval */
+	      int *mtcnt, /* number of entries of each row in arrays mtind and mtval */
+	      int *mtind, /* column indices of the nonzero entries of the ILP matrix */
+	      int *mtval, /* values of the nonzero entries of the ILP matrix */
+	      int *vlb, /* lower bounds on the variables */
+	      int *vub, /* upper bounds on the variables */
+	      int *mrhs, /* right hand sides of the constraints */
+	      char *msense /* senses of the constraints: 'L', 'G' or 'E' */
+	      );
+void free_ilp();
+/* alloc_parity_ilp: allocate the memory for the parity ILP data structure */
+
+void alloc_parity_ilp(
+		      int mr, /* number of rows in the ILP matrix */
+		      int mc, /* number of columns in the ILP matrix */
+		      int mnz /* number of nonzero's in the ILP matrix */
+		      );
+void free_parity_ilp();
+  void initialize_log_var();
+/* free_log_var */
+  void free_log_var();
+private:
+/* best_weakening: find the best upper/lower bound weakening of a set
+   of variables */
+
+int best_weakening(
+		   int n_to_weak, /* number of variables to weaken */
+int *vars_to_weak, /* indices of the variables to weaken */
+short int original_parity, /* original parity of the constraint to weaken */
+double original_slack, /* original slack of the constraint to weaken */
+double *best_even_slack, /* best possible slack of a weakened constraint 
+			   with even right-hand-side */
+double *best_odd_slack, /* best possible slack of a weakened constraint 
+			  with odd right-hand-side */
+info_weak **info_even_weak, /* weakening information about the best possible
+			       even weakened constraint */ 
+info_weak **info_odd_weak, /* weakening information about the best possible
+			      odd weakened constraint */ 
+short int only_odd, /* flag which tells whether only an odd weakening is of
+		       interest (TRUE) or both weakenings are (FALSE) */
+short int only_viol /* flag which tells whether only an inequality of
+			slack smaller than MAX_SLACK is of interest (TRUE)
+			otherwise (FALSE) */
+		   );
+
+/* best_cut: find the coefficients, the rhs and the violation of the
+   best possible cut that can be obtained by weakening a given set of
+   coefficients to even and a rhs to odd, dividing by 2 and rounding */
+
+short int best_cut(
+		   int *ccoef, /* vector of the coefficients */
+		   int *crhs, /* pointer to rhs value */
+		   double *violation, /* violation of the cut */
+		   short int update, /* TRUE/FALSE: if TRUE, the new ccoef and crhs are 
+					given on output */ 
+		   short int only_viol /* flag which tells whether only an inequality of
+			slack smaller than MAX_SLACK is of interest (TRUE)
+			otherwise (FALSE) */
+			      );
+/* get_cut: extract a hopefully violated cut from an odd cycle of the
+   separation graph */
+
+cut *get_cut(
+	     cycle *s_cyc /* shortest odd cycles identified in the separation graph */
+	     );
+
+/* update_log_var: update the log information for the problem variables */
+  void update_log_var();
+
+/* basic_separation: try to identify violated 0-1/2 cuts by using the 
+   original procedure described in Caprara and Fischetti's MP paper */
+
+  cut_list *basic_separation();
+
+/* score_by_moving: compute the score of the best cut obtainable from 
+   the current local search solution by inserting/deleting a constraint */
+
+double score_by_moving(
+		       int i, /* constraint to be moved */
+		       short int itype, /* type of move - ADD or DEL */
+		       double thresh /* minimum value of an interesting score */
+		       );
+/* modify_current: update the current local search solution by inserting/
+   deleting a constraint */
+
+void modify_current(
+		    int i, /* constraint to be moved */
+		    short int itype /* type of move - ADD or DEL */
+		    );
+
+/* best neighbour: find the cut to be added/deleted from the current
+   solution among those allowed by the tabu rules */
+
+  short int best_neighbour(cut_list *out_cuts /* list of the violated cuts found */);
+
+/* add_tight_constraint: initialize the current cut by adding a tight 
+   constraint to it */
+       
+  void add_tight_constraint();
+
+/* tabu_012: try to identify violated 0-1/2 cuts by a simple tabu search
+   procedure adapted from that used by Battiti and Protasi for finding
+   large cliques */
+
+  cut_list *tabu_012();
+/* initialize: initialize the data structures for local search */
+
+  void initialize();
+/* restart: perform a restart of the search - IMPORTANT: in the current
+   implementation vector last_moved is not cleared at restart */
+       
+  void restart(short int failure /* flag forcing the restart if some trouble occurred */);
+  void print_constr(int i /* constraint to be printed */);
+  void print_parity_ilp();
+
+/* get_parity_ilp: construct an internal data structure containing all the 
+   information which can be useful for  0-1/2 cut separation */
+
+  void get_parity_ilp();
+/* initialize_sep_graph: allocate and initialize the data structure
+   to contain the information associated with a separation graph */
+
+  separation_graph *initialize_sep_graph();
+  void print_cut(cut *v_cut);
+/* get_ori_cut_coef: get the coefficients of a cut, before dividing by 2 and
+   rounding, starting from the list of the constraints combined to get 
+   the cut */
+
+short int get_ori_cut_coef(
+			   int n_of_constr, /* number of constraints combined */
+			   int *constr_list, /* list of the constraints combined */
+			   int *ccoef, /* cut left hand side coefficients */
+			   int *crhs, /* cut right hand side */
+			   short int only_viol /* flag which tells whether only an inequality of
+			slack smaller than MAX_SLACK is of interest (TRUE)
+			otherwise (FALSE) */
+			   );
+/* define_cut: construct a cut data structure from a vector of
+   coefficients and a right-hand-side */
+
+cut *define_cut(
+		int *ccoef, /* coefficients of the cut */
+		int crhs /* right hand side of the cut */
+		);
+
+/* cut_score: define the score of a (violated) cut */
+
+double cut_score(
+		 int *ccoef, /* cut left hand side coefficients */
+		 int crhs, /* cut right hand side */
+		 double viol, /* cut violation */
+		 short int only_viol /* flag which tells whether only an inequality of
+			slack smaller than MAX_SLACK is of interest (TRUE)
+			otherwise (FALSE) */
+		 );
+/* get_current_cut: return a cut data type with the information about
+   the current cut of the search procedure */
+
+  cut *get_current_cut();
+/* print_cur_cut: display cur_cut on output */
+
+  void print_cur_cut();
+  void print_cut_list(cut_list *cuts);
+  //@}
+public:
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  Cgl012Cut ();
+ 
+  /// Copy constructor 
+  Cgl012Cut (
+    const Cgl012Cut &);
+
+  /// Assignment operator 
+  Cgl012Cut &
+    operator=(
+    const Cgl012Cut& rhs);
+  
+  /// Destructor 
+  virtual ~Cgl012Cut ();
+  //@}
+
+private:
+  
+  // Private member methods
+   
+  /**@name Private methods */
+  //@{
+  //@}
+  
+  
+  /**@name Private member data */
+  //@{
+
+ilp *inp_ilp; /* input ILP data structure */
+parity_ilp *p_ilp; /* parity ILP data structure */
+int iter;
+double gap;
+double maxgap;
+int errorNo;
+int sep_iter; /* number of the current separation iteration */
+log_var **vlog; /* information about the value attained
+				  by the variables in the last iterations,
+				  used to possibly set to 0 some coefficient
+				  > 0 in a cut to be added */ 
+bool aggr; /* flag saying whether as many cuts as possible are required
+		   from the separation procedure (TRUE) or not (FALSE) */
+  //@}
+};
+#endif
diff --git a/cbits/coin/CglAllDifferent.cpp b/cbits/coin/CglAllDifferent.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglAllDifferent.cpp
@@ -0,0 +1,578 @@
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+//#define PRINT_DEBUG
+//#define CGL_DEBUG 1
+//#undef NDEBUG
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinFinite.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CglAllDifferent.hpp"
+
+#ifdef CGL_DEBUG
+// A declaration is required somewhere, eh? I'm assuming static so the value
+// carries over between calls to generateCuts.
+namespace { int nPath = 0 ; }
+#endif
+//-------------------------------------------------------------------
+// Generate cuts
+//------------------------------------------------------------------- 
+void CglAllDifferent::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			      const CglTreeInfo )
+{
+#ifndef NDEBUG
+  int nCols=si.getNumCols();
+#endif
+  int i;
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+#ifdef CGL_DEBUG
+  const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+  if (debugger&&debugger->onOptimalPath(si)) {
+    printf("On optimal path %d\n",nPath);
+    nPath++;
+    int nCols=si.getNumCols();
+    const double * solution = si.getColSolution();
+    const double * optimal = debugger->optimalSolution();
+    const double * objective = si.getObjCoefficients();
+    double objval1=0.0,objval2=0.0;
+    for (i=0;i<nCols;i++) {
+#if CGL_DEBUG>1
+      printf("%d %g %g %g %g\n",i,lower[i],solution[i],upper[i],optimal[i]);
+#endif
+      objval1 += solution[i]*objective[i];
+      objval2 += optimal[i]*objective[i];
+      assert(optimal[i]>=lower[i]&&optimal[i]<=upper[i]);
+    }
+    printf("current obj %g, integer %g\n",objval1,objval2);
+  }
+#endif
+  int * lo = new int[numberDifferent_];
+  int * up = new int[numberDifferent_];
+  for (i=0;i<numberDifferent_;i++) {
+    int iColumn = originalWhich_[i];
+    assert (iColumn<nCols);
+    lo[i]  = static_cast<int> (lower[iColumn]);
+    assert (floor(lower[iColumn]+0.5)==lower[iColumn]);
+    up[i]  = static_cast<int> (upper[iColumn]);
+    assert (floor(upper[iColumn]+0.5)==upper[iColumn]);
+    assert (up[i]>=lo[i]);
+  }
+  // We are going to assume we can just have one big 2d array!
+  // Could save by going to bits
+  // also could skip sets where all are fixed
+  // could do some of above by separate first pass
+  // once a variable fixed - can take out of list
+  // so need to redo complete stuff (including temp which_) every big pass
+  int offset = COIN_INT_MAX;
+  int maxValue = -COIN_INT_MAX;
+  int numberLook=0;
+  // copies
+  //int * which = new int [numberTotal];
+  //int * start = new int [numberSets_+1];
+  for (i=0;i<numberSets_;i++) {
+    for (int j=start_[i];j<start_[i+1];j++) {
+      int k=which_[j];
+      offset = CoinMin(offset,lo[k]);
+      maxValue = CoinMax(maxValue,up[k]);
+    }
+    numberLook++;
+    int gap = maxValue-offset+1;
+    double size = static_cast<double> (gap) * numberDifferent_;
+    if (size>1.0e7) {
+      if (logLevel_)
+        printf("Only looking at %d sets\n",numberLook);
+      break;
+    }
+  }
+  // Which sets a variable is in
+  int * back = new int [start_[numberSets_]];
+  int * backStart = new int[numberDifferent_+1];
+  memset(backStart,0,(numberDifferent_+1)*sizeof(int));
+  int numberTotal = start_[numberLook];
+  for (i=0;i<numberTotal;i++) {
+    int k=which_[i];
+    // note +1 
+    backStart[k+1]++;
+  }
+  int n=0;
+  for (i=0;i<numberDifferent_;i++) {
+    int nThis = backStart[i+1];
+    backStart[i+1]=n;
+    n+= nThis;
+  }
+  // at end all backStart correct!
+  for (i=0;i<numberLook;i++) {
+    for (int j=start_[i];j<start_[i+1];j++) {
+      int k=which_[j];
+      // note +1 
+      int iPut = backStart[k+1];
+      back[iPut]=i;
+      backStart[k+1]=iPut+1;
+    }
+  }
+  // value is possible for variable k if possible[k*gap+value] is nonzero
+  int gap = maxValue-offset+1;
+  char * possible = new char[gap*numberDifferent_];
+  memset(possible,0,gap*numberDifferent_);
+  // initialize
+  int numberFixed=0;
+  int * alreadyFixed = new int[numberDifferent_];
+  for (i=0;i<numberDifferent_;i++) {
+    alreadyFixed[i]=-1;
+    int startV = i*gap + lo[i] - offset;
+    int n = up[i]-lo[i]+1;
+    memset(possible+startV,1,n);
+  }
+  for (i=0;i<numberDifferent_;i++) {
+    int n = up[i]-lo[i]+1;
+    if (n==1) {
+      int fixedAt = lo[i]-offset;
+      numberFixed++;
+      alreadyFixed[i]=fixedAt;
+      // take out of all others
+      for (int j=backStart[i];j<backStart[i+1];j++) {
+        int iSet = back[j];
+        for (int jj=start_[iSet];jj<start_[iSet+1];jj++) {
+          int k=which_[jj];
+          if (k!=i) {
+            // impossible
+            possible[k*gap+fixedAt]=0;
+          }
+        }
+      }
+    }
+  }
+  bool finished=false;
+  //int numberTightened=0;
+  bool infeasible=false;
+  // space to see which values possible
+  int * check = new int[gap];
+  unsigned int * bitmap = new unsigned int[numberDifferent_];
+  int * stack = new int[numberDifferent_+1];
+  int * first = new int[numberDifferent_+1];
+  // just for valgrind etc
+  memset(stack,0,(numberDifferent_+1)*sizeof(int));
+  memset(first,0,(numberDifferent_+1)*sizeof(int));
+  // do one set at a time
+  while (!finished) {
+    finished=true;
+    int fixed=numberFixed;
+    for (i=0;i<numberLook;i++) {
+      memset(check,0,gap*sizeof(int));
+      for (int j=start_[i];j<start_[i+1];j++) {
+        int k=which_[j];
+        if (alreadyFixed[k]>=0) {
+          if (check[alreadyFixed[k]]==0) {
+            check[alreadyFixed[k]]=1;
+            continue;
+          } else {
+            // infeasible
+            infeasible=true;
+            i=numberLook;
+            break;
+          }
+        }
+        char * allowed = possible + k*gap;
+        int n=0;
+        for (int jj=0;jj<gap;jj++) {
+          if (allowed[jj]) {
+            n++;
+            check[jj]++;
+          }
+        }
+        if (n<2) {
+          if (n==1) {
+            // fix
+            int fixedAt = -1;
+            for (int jj=0;jj<gap;jj++) {
+              if (allowed[jj]) {
+                fixedAt=jj;
+                break;
+              }
+            }
+            numberFixed++;
+            alreadyFixed[k]=fixedAt;
+            check[fixedAt]=1;
+            // take out of all others
+            for (int j=backStart[k];j<backStart[k+1];j++) {
+              int iSet = back[j];
+              for (int jj=start_[iSet];jj<start_[iSet+1];jj++) {
+                int kk=which_[jj];
+                if (kk!=k) {
+                  // impossible
+                  possible[kk*gap+fixedAt]=0;
+                }
+              }
+            }
+          } else {
+            // infeasible
+            infeasible=true;
+            j=numberTotal;
+            i=numberLook;
+            break;
+          }
+        }
+      }
+      // now check set
+      // If number covered < number in set infeasible
+      if (gap<30&&!infeasible) {
+        int n=start_[i+1]-start_[i];
+        memset(bitmap,0,n*sizeof(unsigned int));
+        int j;
+        int * which = which_+start_[i];
+        unsigned int covered=0;
+        bool good=true;
+        for (j=0;j<n;j++) {
+          int k=which[j];
+          char * allowed = possible + k*gap;
+          int jj;
+          for (jj=0;jj<gap;jj++) 
+            if (allowed[jj]) 
+              break;
+          assert (jj<gap);
+          first[j]=jj;
+          unsigned int iBit = 1<<jj;
+          if ((covered&iBit)==0) {
+            stack[j]=jj;
+            covered |= iBit;
+          } else {
+            // can't
+            jj++;
+            for (;jj<gap;jj++) {
+              iBit  = iBit << 1;
+              if (allowed[jj]&&(covered&iBit)==0) 
+                break;
+            }
+            if (jj<gap) {
+              stack[j]=jj;
+              covered |= iBit;
+            } else {
+              good = false;
+              break;
+            }
+          }
+        }
+        int nStack=j;
+        // just do first for rest
+        for (;j<n;j++) {
+          int k=which[j];
+          char * allowed = possible + k*gap;
+          int jj;
+          for (jj=0;jj<gap;jj++) 
+            if (allowed[jj]) 
+              break;
+          assert (jj<gap);
+          first[j]=jj;
+        }
+        int kLook=0;
+        while (nStack) {
+          nStack--;
+          if (good) {
+#if 0
+            printf("con %d = ",i);
+            for (j=0;j<n;j++) 
+              printf("%d ",stack[j]+1);
+            printf("\n");
+#endif
+            // bug - kLook >= 0
+            kLook=0;
+            for (j=kLook;j<n;j++) {
+              int iBit = 1 << stack[j];
+              bitmap[j] |= iBit;
+            }
+          }
+          kLook=nStack;
+          int jj=stack[nStack];
+          unsigned int iBit = 1<<jj;
+          covered &= ~iBit;
+          {
+            unsigned int kBit=0;
+            for (int k=0;k<nStack;k++) {
+              int kk=stack[k];
+              kBit |= 1<<kk;
+            }
+            assert (covered==kBit);
+          }
+          jj++;
+          stack[nStack]=jj;
+          while (nStack<n) {
+            int k=which[nStack];
+            char * allowed = possible + k*gap;
+            for (;jj<gap;jj++) {
+              iBit  = 1 << jj;
+              if (allowed[jj]&&(covered&iBit)==0) 
+                break;
+            }
+            if (jj<gap) {
+              stack[nStack]=jj;
+              covered |= iBit;
+              nStack++;
+              stack[nStack]=first[nStack];
+              jj = first[nStack];
+              good=true;
+            } else {
+              good = false;
+              break;
+            }
+          }
+        }
+        int nnFix=0;
+        // Now see if we can fix any
+        for (j=0;j<n;j++) {
+          int k=which[j];
+          unsigned int mapped = bitmap[j];
+          char * allowed = possible + k*gap;
+          unsigned int iBit=1;
+          for (int jj=0;jj<gap;jj++) {
+            if ((mapped&iBit)==0) {
+              if (allowed[jj]) {
+                if (!nnFix)
+                  printf("for con %d x ",i);
+                nnFix++;
+                printf("%d not %d ",j,jj+1);
+                allowed[jj]=0;
+                finished=false;
+              }
+            }
+            iBit  = iBit << 1;
+          }
+        }
+        if (nnFix)
+          printf("\n");
+      }
+    }
+    if (numberFixed>fixed)
+      finished=false; // try again
+  }
+  // Could try two sets
+  if (infeasible) {
+    // create infeasible cut
+    OsiRowCut rc;
+    rc.setLb(COIN_DBL_MAX);
+    rc.setUb(0.0);   
+    cs.insert(rc);
+  } else {
+    // check to see if can tighten bounds
+    CoinPackedVector lbs;
+    CoinPackedVector ubs;
+    int nTightened=0;
+    for (i=0;i<numberDifferent_;i++) {
+      int iColumn = originalWhich_[i];
+      char * allowed = possible+i*gap;
+      int firstLo=-1;
+      int lastUp=-1;
+      for (int jj=0;jj<gap;jj++) {
+        if (allowed[jj]) {
+          if (firstLo<0)
+            firstLo=jj;
+          lastUp = jj;
+        }
+      }
+      if (firstLo+offset>lo[i]) {
+        lbs.insert(iColumn,static_cast<double> (firstLo+offset));
+        nTightened++;
+      }
+      if (lastUp+offset<up[i]) {
+        ubs.insert(iColumn,static_cast<double> (lastUp+offset));
+        nTightened++;
+      }
+    }
+    if (nTightened) {
+      OsiColCut cc;
+      cc.setUbs(ubs);
+      cc.setLbs(lbs);
+      cc.setEffectiveness(100.0);
+      cs.insert(cc);
+    }
+  }
+  //delete [] which;
+  //delete [] start;
+  delete [] first;
+  delete [] stack;
+  delete [] bitmap;
+  delete [] check;
+  delete [] alreadyFixed;
+  delete [] back;
+  delete [] backStart;
+  delete [] possible;
+  delete [] lo;
+  delete [] up;
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglAllDifferent::CglAllDifferent ()
+:
+CglCutGenerator(),
+numberSets_(0),
+numberDifferent_(0),
+maxLook_(2),
+logLevel_(0),
+start_(NULL),
+which_(NULL),
+originalWhich_(NULL)
+{
+}
+
+//-------------------------------------------------------------------
+// Useful Constructor 
+//-------------------------------------------------------------------
+CglAllDifferent::CglAllDifferent (int numberSets,
+                                  const int * starts, const int * which)
+:
+CglCutGenerator(),
+numberSets_(numberSets),
+maxLook_(2),
+logLevel_(0),
+start_(NULL),
+which_(NULL),
+originalWhich_(NULL)
+{
+  if (numberSets_>0) {
+    int n = starts[numberSets_];
+    start_ = CoinCopyOfArray(starts,numberSets_+1);
+    originalWhich_ = CoinCopyOfArray(which,n);
+    which_ = new int[n];
+    int i;
+    int maxValue=-1;
+    for (i=0;i<n;i++) {
+      int iColumn = which[i];
+      assert (iColumn>=0);
+      maxValue = CoinMax(iColumn,maxValue);
+    }
+    maxValue++;
+    int * translate = new int[maxValue];
+    for (i=0;i<maxValue;i++)
+      translate[i]=-1;
+    for (i=0;i<n;i++) {
+      int iColumn = which[i];
+      translate[iColumn]=0;
+    }
+    numberDifferent_=0;
+    for (i=0;i<maxValue;i++) {
+      if (!translate[i]) 
+        translate[i]=numberDifferent_++;
+    }
+    // Now translate
+    for (i=0;i<n;i++) {
+      int iColumn = which[i];
+      iColumn = translate[iColumn];
+      assert (iColumn>=0);
+      which_[i]=iColumn;
+    }
+    delete [] translate;
+  }
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglAllDifferent::CglAllDifferent (  const CglAllDifferent & rhs)
+                                                              :
+  CglCutGenerator(rhs),
+  numberSets_(rhs.numberSets_),
+  numberDifferent_(rhs.numberDifferent_),
+  maxLook_(rhs.maxLook_),
+  logLevel_(rhs.logLevel_)
+{  
+  if (numberSets_) {
+    int n = rhs.start_[numberSets_];
+    start_ = CoinCopyOfArray(rhs.start_,numberSets_+1);
+    which_ = CoinCopyOfArray(rhs.which_,n);
+    originalWhich_ = CoinCopyOfArray(rhs.originalWhich_,n);
+  } else {
+    start_=NULL;
+    which_=NULL;
+    originalWhich_=NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglAllDifferent::clone() const
+{
+  return new CglAllDifferent(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglAllDifferent::~CglAllDifferent ()
+{
+  // free memory
+  delete [] start_;
+  delete [] which_;
+  delete [] originalWhich_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglAllDifferent &
+CglAllDifferent::operator=(
+                                         const CglAllDifferent& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    // free memory
+    delete [] start_;
+    delete [] which_;
+    delete [] originalWhich_;
+    numberSets_ = rhs.numberSets_;
+    numberDifferent_ = rhs.numberDifferent_;
+    maxLook_ = rhs.maxLook_;
+    logLevel_ = rhs.logLevel_;
+    if (numberSets_) {
+      int n = rhs.start_[numberSets_];
+      start_ = CoinCopyOfArray(rhs.start_,numberSets_+1);
+      which_ = CoinCopyOfArray(rhs.which_,n);
+      originalWhich_ = CoinCopyOfArray(rhs.originalWhich_,n);
+    } else {
+      start_=NULL;
+      which_=NULL;
+      originalWhich_=NULL;
+    }
+  }
+  return *this;
+}
+
+/// This can be used to refresh any inforamtion
+void 
+CglAllDifferent::refreshSolver(OsiSolverInterface * )
+{
+}
+// Create C++ lines to get to current state
+std::string
+CglAllDifferent::generateCpp( FILE * fp) 
+{
+  CglAllDifferent other;
+  fprintf(fp,"0#include \"CglAllDifferent.hpp\"\n");
+  fprintf(fp,"3  CglAllDifferent allDifferent;\n");
+  if (logLevel_!=other.logLevel_)
+    fprintf(fp,"3  allDifferent.setLogLevel(%d);\n",logLevel_);
+  else
+    fprintf(fp,"4  allDifferent.setLogLevel(%d);\n",logLevel_);
+  if (maxLook_!=other.maxLook_)
+    fprintf(fp,"3  allDifferent.setMaxLook(%d);\n",maxLook_);
+  else
+    fprintf(fp,"4  allDifferent.setMaxLook(%d);\n",maxLook_);
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  allDifferent.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  allDifferent.setAggressiveness(%d);\n",getAggressiveness());
+  return "allDifferent";
+}
diff --git a/cbits/coin/CglAllDifferent.hpp b/cbits/coin/CglAllDifferent.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglAllDifferent.hpp
@@ -0,0 +1,115 @@
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglAllDifferent_H
+#define CglAllDifferent_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+
+/** AllDifferent Cut Generator Class 
+    This has a number of sets.  All the members in each set are general integer
+    variables which have to be different from all others in the set.
+
+    At present this only generates column cuts
+
+    At present it is very primitive compared to proper CSP implementations
+ */
+class CglAllDifferent : public CglCutGenerator {
+ 
+public:
+    
+  
+  /**@name Generate Cuts */
+  //@{
+  /** This fixes (or reduces bounds) on sets of all different variables
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglAllDifferent ();
+
+  /// Useful constructot
+  CglAllDifferent(int numberSets, const int * starts, const int * which);
+ 
+  /// Copy constructor 
+  CglAllDifferent (
+    const CglAllDifferent &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglAllDifferent &
+    operator=(
+    const CglAllDifferent& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglAllDifferent ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+
+  /// This can be used to refresh any inforamtion
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  /**
+     Returns true if may generate Row cuts in tree (rather than root node).
+     Used so know if matrix will change in tree.  Really
+     meant so column cut generators can still be active
+     without worrying code.
+     Default is true
+  */
+  virtual bool mayGenerateRowCutsInTree() const
+  { return false;}
+  //@}
+  /**@name Sets and Gets */
+  //@{
+  /// Set log level
+  inline void setLogLevel(int value)
+  { logLevel_=value;}
+  /// Get log level
+  inline int getLogLevel() const
+  { return logLevel_;}
+  /// Set Maximum number of sets to look at at once
+  inline void setMaxLook(int value)
+  { maxLook_=value;}
+  /// Get Maximum number of sets to look at at once
+  inline int getMaxLook() const
+  { return maxLook_;}
+  //@}
+      
+private:
+  
+ // Private member methods
+  /**@name  */
+  //@{
+  //@}
+
+  // Private member data
+
+  /**@name Private member data */
+  //@{
+  /// Number of sets
+  int numberSets_;
+  /// Total number of variables in all different sets
+  int numberDifferent_;
+  /// Maximum number of sets to look at at once
+  int maxLook_;
+  /// Log level - 0 none, 1 - a bit, 2 - more details
+  int logLevel_;
+  /// Start of each set
+  int * start_;
+  /// Members (0,1,....) not as in original model
+  int * which_;
+  /// Original members
+  int * originalWhich_;
+  //@}
+};
+#endif
diff --git a/cbits/coin/CglClique.cpp b/cbits/coin/CglClique.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglClique.cpp
@@ -0,0 +1,868 @@
+// $Id: CglClique.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdio>
+#include <cassert>
+
+#include "CoinHelperFunctions.hpp"
+#include "OsiCuts.hpp"
+#include "OsiRowCut.hpp"
+#include "CglClique.hpp"
+
+/*****************************************************************************/
+
+CglClique::CglClique(bool setPacking, bool justOriginalRows) :
+  CglCutGenerator(),
+   setPacking_(setPacking),
+  justOriginalRows_(justOriginalRows),
+   sp_numrows(0),
+   sp_orig_row_ind(0),
+   sp_numcols(0),
+   sp_orig_col_ind(0),
+   sp_colsol(0),
+   sp_col_start(0),
+   sp_col_ind(0),
+   sp_row_start(0),
+   sp_row_ind(0),
+   node_node(0),
+   petol(-1.0),
+   do_row_clique(true),
+   do_star_clique(true),
+   scl_next_node_rule(SCL_MAX_XJ_MAX_DEG),
+   scl_candidate_length_threshold(12),
+   scl_report_result(true),
+   rcl_candidate_length_threshold(12),
+   rcl_report_result(true),
+   cl_perm_indices(0),
+   cl_perm_length(0),
+   cl_indices(0),
+   cl_length(0),
+   cl_del_indices(0),
+   cl_del_length(0)
+{}
+// Copy constructor
+CglClique::CglClique(const CglClique& rhs)
+  : CglCutGenerator(rhs),
+    setPacking_(rhs.setPacking_),
+    justOriginalRows_(rhs.justOriginalRows_),
+    sp_numrows(rhs.sp_numrows),
+    sp_orig_row_ind(rhs.sp_orig_row_ind),
+    sp_numcols(rhs.sp_numcols),
+    sp_orig_col_ind(rhs.sp_orig_col_ind),
+    sp_colsol(rhs.sp_colsol),
+    sp_col_start(rhs.sp_col_start),
+    sp_col_ind(rhs.sp_col_ind),
+    sp_row_start(rhs.sp_row_start),
+    sp_row_ind(rhs.sp_row_ind),
+    node_node(rhs.node_node),
+    petol(rhs.petol),
+    do_row_clique(rhs.do_row_clique),
+    do_star_clique(rhs.do_star_clique),
+    scl_next_node_rule(rhs.scl_next_node_rule),
+    scl_candidate_length_threshold(rhs.scl_candidate_length_threshold),
+    scl_report_result(rhs.scl_report_result),
+    rcl_candidate_length_threshold(rhs.rcl_candidate_length_threshold),
+    rcl_report_result(rhs.rcl_report_result),
+    cl_perm_indices(rhs.cl_perm_indices),
+    cl_perm_length(rhs.cl_perm_length),
+    cl_indices(rhs.cl_indices),
+    cl_length(rhs.cl_length),
+    cl_del_indices(rhs.cl_del_indices),
+    cl_del_length(rhs.cl_del_length)
+{
+}
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+
+void
+CglClique::generateCuts(const OsiSolverInterface& si, OsiCuts & cs,
+			const CglTreeInfo info)
+{
+   int i;
+   bool has_petol_set = petol != -1.0;
+
+   if (! has_petol_set)
+      si.getDblParam(OsiPrimalTolerance, petol);
+   int numberOriginalRows = si.getNumRows();
+   if (info.inTree&&justOriginalRows_)
+     numberOriginalRows = info.formulation_rows;
+   int numberRowCutsBefore = cs.sizeRowCuts();
+   // First select which rows/columns we are interested in.
+   if (!setPacking_) {
+      selectFractionalBinaries(si);
+      if (!sp_orig_row_ind) {
+	 selectRowCliques(si,numberOriginalRows);
+      }
+   } else {
+      selectFractionals(si);
+      delete[] sp_orig_row_ind;
+      sp_numrows = numberOriginalRows;
+      //sp_numcols = si.getNumCols();
+      sp_orig_row_ind = new int[sp_numrows];
+      for (i = 0; i < sp_numrows; ++i)
+	 sp_orig_row_ind[i] = i;
+   }
+   // Just original rows
+   if (justOriginalRows_&&info.inTree) 
+     sp_numrows = CoinMin(info.formulation_rows,sp_numrows);
+     
+
+   createSetPackingSubMatrix(si);
+   fgraph.edgenum = createNodeNode();
+   createFractionalGraph();
+
+   cl_indices = new int[sp_numcols];
+   cl_del_indices = new int[sp_numcols];
+
+   if (do_row_clique)
+      find_rcl(cs);
+   if (do_star_clique)
+      find_scl(cs);
+   if (!info.inTree&&((info.options&4)==4||((info.options&8)&&!info.pass))) {
+     int numberRowCutsAfter = cs.sizeRowCuts();
+     for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++)
+       cs.rowCutPtr(i)->setGloballyValid();
+   }
+
+   delete[] cl_indices;     cl_indices = 0;
+   delete[] cl_del_indices; cl_del_indices = 0;
+
+   deleteFractionalGraph();
+   delete[] node_node;      node_node = 0;
+   deleteSetPackingSubMatrix();
+
+   if (! has_petol_set)
+      petol = -1;
+}
+
+/*****************************************************************************/
+/*===========================================================================*
+ * Find violated row cliques.
+ *
+ * Algorithm: For each row of the matrix collect all variables not in the
+ * row's support that are non-orthogonal to all variables in the row. These
+ * variables form a candidate set in which we look for maximal cliques
+ * (enumerate all or try to find one greedily, depending on the size of the
+ * candidate set). When a violated maximal clique is found, it is recorded in
+ * the cut set.
+ *===========================================================================*/
+
+void
+CglClique::find_rcl(OsiCuts& cs)
+{
+   const int nodenum = fgraph.nodenum;
+   const fnode *nodes = fgraph.nodes;
+
+   /* A flag for each column that might be used to extend the current row
+      clique */
+   bool *cand = new bool[nodenum];
+   /* In cl_indices we'll list the indices of the 'true' entries in cand */
+   /* The degree of each candidate (those listed in cl_indices) */
+   int *degrees = new int[nodenum];
+
+   /** An array used in the recursive complete enumeration of maximal cliques.
+       The first cl_length entries are used. */
+   bool* label = new bool[nodenum];
+
+   int i, j, k;
+
+   /* initialize global variables */
+   cl_del_length = 0;
+   cl_length = 0;
+
+   int clique_count = 0;
+   int largest_length = 0;
+
+   /* for each row of the matrix */
+   for (j = 0; j < sp_numrows; j++) {
+
+      /* if the row is of zero length, take the next row */
+      const int len = sp_row_start[j+1] - sp_row_start[j];
+      if (!len)
+	 continue;
+
+      /* the beginning of the row to be considered */
+      const int *row = sp_row_ind + sp_row_start[j];
+
+      /* copy the row of node_node corresponding to the first column in 'row'
+	 into cand, and take the AND of this vector with every row of
+	 node_node corresponding to the rest of the columns in 'row' to
+	 determine those columns that are non-orthog to every column in row */
+      std::copy(node_node + row[0]*nodenum, node_node + (row[0]+1)*nodenum,
+		cand);
+      for (i = 1; i < len; i++) {
+	 const bool* node_node_col = node_node + row[i] * nodenum;
+	 for (k = 0; k < nodenum; k++)
+	    cand[k] &= node_node_col[k];
+      }
+      cl_length = 0;
+      for (k = 0; k < nodenum; k++)
+	 if (cand[k])
+	    cl_indices[cl_length++] = k;
+      largest_length = CoinMax(cl_length, largest_length);
+
+      /* if there is anything in indices, enumerate (or greedily find)
+	 maximal cliques */
+      if (cl_length > 0) {
+	 cl_perm_length = len;
+	 cl_perm_indices = row;
+	 if (cl_length <= rcl_candidate_length_threshold) {
+	    for (i = 0; i < cl_length; i++)
+	       label[i] = false;
+	    int pos = 0;
+	    clique_count += enumerate_maximal_cliques(pos, label, cs);
+	 } else {
+	    /* order cl_indices into decreasing order of their degrees */
+	    for (i = 0; i < cl_length; i++)
+	       degrees[i] = nodes[cl_indices[i]].degree;
+	    CoinSort_2(degrees, degrees + cl_length, cl_indices,
+		       CoinFirstGreater_2<int,int>());
+	    clique_count += greedy_maximal_clique(cs);
+	 }
+      }
+   }
+
+   if (rcl_report_result) {
+      printf("\nrcl Found %i new violated cliques with the row-clique method",
+	     clique_count);
+      printf("\nrcl The largest admissible number was %i (threshold %i)\n",
+	     largest_length, rcl_candidate_length_threshold);
+      if (largest_length < rcl_candidate_length_threshold)
+	 printf("rcl    all row cliques have been enumerated\n");
+      else
+	 printf("rcl    not all row cliques have been eliminated\n");
+   }
+
+   delete[] degrees;
+   delete[] cand;
+   delete[] label;
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ * Find violated star cliques, a la Hoffman-Padberg.
+ *
+ * Algorithm: Take min degree node. Check for violated cuts in the subgraph
+ * consisting of this node and its neighbors (the "star" of this node). Then
+ * delete the node and continue with the now min degree node.
+ * 
+ * Implementation: Two arrays are defined, one contains the indices the other
+ * the degrees of all the nodes still in the graph. If the min degree is 0
+ * or 1 then the min degree node can be deleted at once.
+ * All cliques are enumerated in v U star(v) if the min degree is smaller
+ * than the threshold  scl_candidate_length_threshold, otherwise attemp to
+ * find maximal clique greedily.
+ * 
+ * Note: Indices in current_indices are always kept in increasing order.
+ *===========================================================================*/
+
+void
+CglClique::find_scl(OsiCuts& cs)
+{
+   const int nodenum = fgraph.nodenum;
+   const fnode *nodes = fgraph.nodes;
+
+   // Return at once if no nodes - otherwise we get invalid reads
+   if (!nodenum)
+     return;
+   int *current_indices = new int[nodenum];
+   int *current_degrees = new int[nodenum];
+   double *current_values = new double[nodenum];
+
+   int *star = cl_indices;
+   int *star_deg = new int[nodenum];
+
+   /** An array used in the recursive complete enumeration of maximal cliques.
+       The first cl_length entries are used. */
+   bool* label = new bool[nodenum];
+
+   int i, cnt1 = 0, cnt2 = 0, cnt3 = 0;
+   int clique_cnt_e = 0, clique_cnt_g = 0;
+   int largest_star_size = 0;
+
+   /* initialize global variables */
+   cl_del_length = 0;
+
+   /* initialize current_nodes, current_degrees and current_values */
+   int current_nodenum = nodenum;
+   for (i = 0; i < nodenum; i++) {
+      current_indices[i] = i;
+      current_degrees[i] = nodes[i].degree;
+      current_values[i] = nodes[i].val;
+   }
+   
+   /* find first node to be checked */
+   int best_ind = scl_choose_next_node(current_nodenum, current_indices,
+				       current_degrees, current_values);
+
+   int v = current_indices[best_ind];
+   int v_deg = current_degrees[best_ind];
+   double v_val = current_values[best_ind];
+      
+   /* while there are nodes left in the graph ... (more precisely, while
+      there are at least 3 nodes in the graph) */
+   while (current_nodenum > 2) {
+
+      /* if the best node is of degree < 2 then it can be deleted */
+      if (v_deg < 2) {
+	 cl_del_indices[cl_del_length++] = v;
+	 scl_delete_node(best_ind, current_nodenum,
+			 current_indices, current_degrees, current_values);
+	 best_ind = scl_choose_next_node(current_nodenum, current_indices,
+					 current_degrees, current_values);
+	 v = current_indices[best_ind];
+	 v_deg = current_degrees[best_ind];
+	 v_val = current_values[best_ind];
+	 largest_star_size = CoinMax(largest_star_size, v_deg);
+	 continue;
+      }
+
+      /* star will contain the indices of v's neighbors (but not v's index) */
+      const bool* node_node_start = node_node + nodenum * v;
+      int& star_length = cl_length;
+      star_length = 0;
+      double star_val = v_val;
+      for (i = 0; i < current_nodenum; i++) {
+	 const int other_node = current_indices[i];
+	 if (node_node_start[other_node]) {
+	    star[star_length] = other_node;
+	    star_deg[star_length++] = current_degrees[i];
+	    star_val += current_values[i];
+	 }
+      }
+
+      /* quick check: if sum of values for the star does not exceed 1 then
+	 there won't be a violated clique in the star */
+      if (star_val >= 1 + petol) {
+	 /* node whose star we're evaluating is always in */
+	 cl_perm_length = 1;
+	 cl_perm_indices = &v;
+
+	 /* find maximal violated cliques in star. cliques found here might not
+	    be maximal wrt to entire fractional graph, only for the current
+	    subset of it (some nodes might be already deleted...)
+	    Note that star is the same as cl_indices and start_length is
+	    cl_length... 
+	 */
+	 if (v_deg < scl_candidate_length_threshold) { // par
+	    /* enumerate if v_deg is small enough */
+	    for (i = 0; i < star_length; i++)
+	       label[i] = false;
+	    int pos = 0;
+	    clique_cnt_e += enumerate_maximal_cliques(pos, label, cs);
+	    cnt1++;
+	 } else {
+	    /* greedily find if v_deg is too big */
+	    /* order nodes in *decreasing* order of their degrees in star */
+	    CoinSort_2(star_deg, star_deg + star_length, star,
+		       CoinFirstGreater_2<int,int>());
+	    /* find maxl clique greedily, including v */
+	    clique_cnt_g += greedy_maximal_clique(cs);
+	    cnt2++;
+	 }
+      } else {
+	 cnt3++;
+      }
+      /* delete v from current_indices */
+      cl_del_indices[cl_del_length++] = v;
+      scl_delete_node(best_ind, current_nodenum,
+		      current_indices, current_degrees, current_values);
+      best_ind = scl_choose_next_node(current_nodenum, current_indices,
+				      current_degrees, current_values);
+      v = current_indices[best_ind];
+      v_deg = current_degrees[best_ind];
+      v_val = current_values[best_ind];
+      largest_star_size = CoinMax(largest_star_size, v_deg);
+   }
+
+   const int clique_cnt = clique_cnt_e + clique_cnt_g;
+
+   if (scl_report_result) {
+      printf("\nscl Found %i new violated cliques with the star-clique method",
+	     clique_cnt);
+      printf("\nscl The largest star size was %i (threshold %i)\n",
+	     largest_star_size, scl_candidate_length_threshold); // par
+      printf("scl Enumeration %i times, found %i maxl cliques\n",
+	     cnt1, clique_cnt_e);
+      printf("scl Greedy %i times, found %i maxl cliques\n",
+	     cnt2, clique_cnt_g);
+      printf("scl Skipped a star b/c of small solution value %i times\n",
+	     cnt3);
+
+      if (cnt2 == 0)
+	 printf("scl    all cliques have been enumerated\n");
+      else
+	 printf("scl    not all cliques have been eliminated\n");
+   }
+
+   delete[] current_indices;
+   delete[] current_degrees;
+   delete[] current_values;
+   delete[] star_deg;
+   delete[] label;
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ * returns the index of the "best" node wrt current_indices, etc.
+ *===========================================================================*/
+
+int
+CglClique::scl_choose_next_node(const int current_nodenum,
+				const int * /* current_indices */,
+				const int *current_degrees,
+				const double *current_values)
+{
+   int best = 0;
+   int best_deg = current_degrees[0];
+   double best_val = current_values[0];
+   int i;
+
+   switch (scl_next_node_rule) { // p->par.scl_which_node
+   case SCL_MIN_DEGREE: // NOTE: could use stl::min_element
+      for (i = 1; i < current_nodenum; i++)
+	 if (current_degrees[i] < best_deg) {
+	    best = i;
+	    best_deg = current_degrees[i];
+	 }
+      break;
+   case SCL_MAX_DEGREE: // NOTE: could use stl::max_element
+      for (i = 1; i < current_nodenum; i++)
+	 if (current_degrees[i] > best_deg) {
+	    best = i;
+	    best_deg = current_degrees[i];
+	 }
+      break;
+   case SCL_MAX_XJ_MAX_DEG:
+      for (i = 1; i < current_nodenum; i++) {
+	 if (current_values[i] > best_val) {
+	    best = i;
+	    best_val = current_values[i];
+	    best_deg = current_degrees[i];
+	 } else if (current_values[i] == best_val &&
+		    current_degrees[i] > best_deg) {
+	    best = i;
+	    best_deg = current_degrees[i];
+	 }
+      }
+      break;
+   default:
+      printf("ERROR: bad starcl_which_node (in scl_choose_next_node\n");
+      break;
+   }
+   return(best);
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ * Delete the node of index del_ind (this index is wrt current_indices) from
+ * the list current_indices (current_degrees and current_values) and based on
+ * the graph stored in fgraph decrease the degrees of its neighbors.
+ *
+ * There are at least 3 nodes in the graph when this function is invoked.
+ *
+ * Note that the node indices in current_indices are in increasing order,
+ * and that this ordering is maintained here.
+ *
+ * fgraph: IN, pointer to the fractional graph
+ * node_node: IN, node_node incidence matrix
+ * del_ind: IN, the index of the node to be deleted (wrt to current_indices)
+ * pcurrent_nodenum: INOUT, pointer to the current number of nodes
+ * current_indices: INOUT, array of current node indices
+ * current_degrees: INOUT, array of current node degrees, in the dame order
+ *                  as in current_indices
+ * current_values: INOUT, array of solution values
+ *===========================================================================*/
+
+void
+CglClique::scl_delete_node(const int del_ind, int& current_nodenum,
+			   int *current_indices, int *current_degrees,
+			   double *current_values)
+{
+   const int v = current_indices[del_ind];
+
+   /* delete the entry corresponding to del_ind from current_indices, 
+      current_degrees and current_values */
+   memmove(reinterpret_cast<char *>(current_indices + del_ind),
+	   reinterpret_cast<char *>(current_indices + (del_ind+1)),
+	   (current_nodenum-del_ind-1) * sizeof(int));
+   memmove(reinterpret_cast<char *>(current_degrees + del_ind),
+	   reinterpret_cast<char *>(current_degrees + (del_ind+1)),
+	   (current_nodenum-del_ind-1) * sizeof(int));
+   memmove(reinterpret_cast<char *>(current_values + del_ind),
+	   reinterpret_cast<char *>(current_values + (del_ind+1)),
+	   (current_nodenum-del_ind-1) * sizeof(double));
+   current_nodenum--;
+   
+   /* decrease the degrees of v's neighbors by 1 */
+   const bool* node_node_start = node_node + (fgraph.nodenum * v);
+   for (int i = 0; i < current_nodenum; ++i)
+      if (node_node_start[current_indices[i]])
+	 current_degrees[i]--;
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ * Enumerate all maximal cliques on the nodes in scl_indices. Maximal cliques
+ * that are violated are added to the cut list. Returns the number of maximal
+ * violated cliques found. The algorithm is recursive.
+ *
+ * Data members used from CglClique
+ *   fgraph: IN, the description of the intersection graph
+ *   cl_perm_length: IN, the length of cl_perm_indices
+ *   cl_perm_indices: IN, indices of nodes that MUST be in the clique, these
+ *                    nodes are supposed to be connected to all nodes in
+ *                    cl_indices
+ *   cl_length: IN, length of cl_indices and label
+ *   cl_indices: IN, indices of nodes on which maximal cliques are sought
+ *   cl_del_length: IN, length of cl_del_indices
+ *   cl_del_indices: IN, indices of nodes that are already deleted. these
+ *                   nodes are tested whether they can be added to a max
+ *                   clique discovered in scl_indices. if any of them can be
+ *                   added then the clique is not maximal after all...
+ *
+ * Arguments:
+ *   label: INOUT, indicates which nodes are in the clique at the moment
+ *   pos: INOUT, position within cl_indices (and label), nodes up to
+ *        position pos in cl_indices are permanently labeled (backtrack cannot
+ *        change labels)
+ *===========================================================================*/
+
+int
+CglClique::enumerate_maximal_cliques(int& pos, bool* label, OsiCuts& cs)
+{
+   const fnode *nodes = fgraph.nodes;
+   const int nodenum = fgraph.nodenum;
+
+   int i, j, k, cnt;
+
+   /* starting from position pos, find the first node in cl_indices that
+      can be added to the clique, and label it with true */
+   while (pos < cl_length) {
+      label[pos] = true;
+      const bool* node_node_start = node_node + cl_indices[pos] * nodenum;
+      for (j = 0; j < pos; j++)
+	 if (label[j] && ! node_node_start[cl_indices[j]]) {
+	    label[pos] = false;
+	    break;
+	 }
+      if (label[pos++] == true)
+	 break;
+   }
+
+   /* found counts the number of maximal violated cliques that have been sent
+      to the lp under the current level of recursion */
+   int found = 0;
+
+   /* if not all nodes are labeled: recurse by setting the last node
+      labeled true once to true and once to false;
+      otherwise check whether the clique found is maximal and violated */
+   if (pos < cl_length) {
+      found += enumerate_maximal_cliques(pos, label, cs);
+      label[pos-1] = false;
+      found += enumerate_maximal_cliques(pos, label, cs);
+   } else {
+      /* check if the clique can be extended on cl_indices */
+
+      /* copy indices of the clique into coef (not user inds, coef is a tmp) */
+      int* coef = new int[cl_length + cl_perm_length];
+      for (j = cl_length - 1, cnt = 0; j >= 0; j--)
+	 if (label[j])
+	    coef[cnt++] = cl_indices[j];
+      if (!cnt) {
+	 delete[] coef;
+	 return(found);
+      }
+      
+      /* check if the clique can be extended on cl_indices */
+      for (k = cl_length - 1; k >= 0; k--) {
+	 if (!label[k]) {
+	    const bool* node_node_start = node_node + cl_indices[k] * nodenum;
+	    for (i = cnt - 1; i >= 0; i--)
+	       if (!node_node_start[coef[i]])
+		  break;
+	    /* if k can be added to the clique, return (the clique is not
+	       maximal, so it will be or was recorded) */
+	    if (i < 0) {
+	       delete[] coef;
+	       return(found);
+	    }
+	 }
+      }
+
+      /* now the clique is maximal on cl_indices.
+	 fill relative indices into coef */
+      for (j = 0; j < cl_perm_length; j++)
+	 coef[cnt++] = cl_perm_indices[j];
+      
+      /* check if clique is violated */
+      double lhs = 0;
+      for (j = 0; j < cnt; j++)
+	 lhs += nodes[coef[j]].val;
+      if (lhs < 1 + petol) {
+	 delete[] coef;
+	 return(found);
+      }
+      
+      /* if clique can be extended on cl_del_indices then it can be
+	 discarded (was already counted) */
+      for (i = 0; i < cl_del_length; i++) {
+	 const bool* node_node_start = node_node + cl_del_indices[i]*nodenum;
+	 for (j = cnt - 1; j >= 0; j--)
+	    if (!node_node_start[coef[j]])
+	       break;
+	 /* if cl_del_indices[i] can be added to the clique, return */
+	 if (j < 0) {
+	    delete[] coef;
+	    return(found);
+	 }
+      }
+
+      recordClique(cnt, coef, cs);
+      delete[] coef;
+      
+      ++found;
+   }
+
+   return(found);
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ * Find a violated clique greedily in the given array of indices, starting
+ * from pos. Return the number of violated cliques found (1 or 0).
+ * This routine overwrites the array indices: those variables in the
+ * clique will be shuffled to the beginning of the array (after pos).
+ *===========================================================================*/
+
+int
+CglClique::greedy_maximal_clique(OsiCuts& cs)
+{
+   assert(cl_length > 0);
+   const fnode *nodes = fgraph.nodes;
+   const int nodenum = fgraph.nodenum;
+   int i, j;
+
+   int * coef = new int[cl_length + cl_perm_length];
+   coef[0] = cl_indices[0];
+   int cnt = 1;
+   for (j = 1; j < cl_length; j++) {
+      const int var = cl_indices[j];
+      const bool* node_node_start = node_node + var * nodenum;
+      for (i = cnt-1; i >= 0; i--)
+	 if (!node_node_start[coef[i]])
+	    break;
+      if (i < 0)
+	 coef[cnt++] = var;
+   }
+
+   for (j = 0; j < cl_perm_length; j++)
+      coef[cnt++] = cl_perm_indices[j];
+
+   /* now coef contains the clique */
+   /* only cliques of size at least 3 are interesting */
+   if (cnt < 3) {
+      delete[] coef;
+      return(0);
+   }
+
+   /* compute lhs */
+   double lhs = 0;
+   for (j = 0; j < cnt; j++)
+      lhs += nodes[coef[j]].val;
+
+   if (lhs > 1 + petol) {
+      recordClique(cnt, coef, cs);
+      delete[] coef;
+      return(1);
+   }
+
+   delete[] coef;
+   return(0);
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ *===========================================================================*/
+
+void
+CglClique::recordClique(const int len, int* indices, OsiCuts& cs)
+{
+   /* transform relative indices into user indices and order them */
+   for (int j = len - 1; j >= 0; j--)
+      indices[j] = sp_orig_col_ind[indices[j]];
+   std::sort(indices, indices + len);
+   OsiRowCut rowcut;
+   double* coef = new double[len];
+   std::fill(coef, coef + len, 1.0);
+   rowcut.setRow(len, indices, coef);
+   rowcut.setUb(1.0);
+   CoinAbsFltEq equal(1.0e-12);
+   cs.insertIfNotDuplicate(rowcut,equal);
+   delete[] coef;
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglClique::clone() const
+{
+  return new CglClique(*this);
+}
+
+/*****************************************************************************/
+// Create C++ lines to get to current state
+std::string
+CglClique::generateCpp( FILE * fp) 
+{
+  CglClique other;
+  fprintf(fp,"0#include \"CglClique.hpp\"\n");
+  fprintf(fp,"3  CglClique clique;\n");
+  std::string types[] = {"SCL_MIN_DEGREE","SCL_MAX_DEGREE",
+			 "SCL_MAX_XJ_MAX_DEG"};
+  if (scl_next_node_rule!=other.scl_next_node_rule)
+    fprintf(fp,"3  clique.setStarCliqueNextNodeMethod(CglClique::%s);\n",
+	    types[scl_next_node_rule].c_str());
+  else
+    fprintf(fp,"4  clique.setStarCliqueNextNodeMethod(CglClique::%s);\n",
+	    types[scl_next_node_rule].c_str());
+  if (scl_candidate_length_threshold!=other.scl_candidate_length_threshold)
+    fprintf(fp,"3  clique.setStarCliqueCandidateLengthThreshold(%d);\n",
+	    scl_candidate_length_threshold);
+  else
+    fprintf(fp,"4  clique.setStarCliqueCandidateLengthThreshold(%d);\n",
+	    scl_candidate_length_threshold);
+  if (rcl_candidate_length_threshold!=other.rcl_candidate_length_threshold)
+    fprintf(fp,"3  clique.setRowCliqueCandidateLengthThreshold(%d);\n",
+	    rcl_candidate_length_threshold);
+  else
+    fprintf(fp,"4  clique.setRowCliqueCandidateLengthThreshold(%d);\n",
+	    rcl_candidate_length_threshold);
+  if (scl_report_result!=other.scl_report_result)
+    fprintf(fp,"3  clique.setStarCliqueReport(%s);\n",
+	    scl_report_result ? "true" : "false");
+  else
+    fprintf(fp,"4  clique.setStarCliqueReport(%s);\n",
+	    scl_report_result ? "true" : "false");
+  if (rcl_report_result!=other.rcl_report_result)
+    fprintf(fp,"3  clique.setRowCliqueReport(%s);\n",
+	    rcl_report_result ? "true" : "false");
+  else
+    fprintf(fp,"4  clique.setRowCliqueReport(%s);\n",
+	    rcl_report_result ? "true" : "false");
+  if (do_star_clique!=other.do_star_clique)
+    fprintf(fp,"3  clique.setDoStarClique(%s);\n",
+	    do_star_clique ? "true" : "false");
+  else
+    fprintf(fp,"4  clique.setDoStarClique(%s);\n",
+	    do_star_clique ? "true" : "false");
+  if (do_row_clique!=other.do_row_clique)
+    fprintf(fp,"3  clique.setDoRowClique(%s);\n",
+	    do_row_clique ? "true" : "false");
+  else
+    fprintf(fp,"4  clique.setDoRowClique(%s);\n",
+	    do_row_clique ? "true" : "false");
+  if (petol!=other.petol)
+    fprintf(fp,"3  clique.setMinViolation(%g);\n",petol);
+  else
+    fprintf(fp,"4  clique.setMinViolation(%g);\n",petol);
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  clique.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  clique.setAggressiveness(%d);\n",getAggressiveness());
+  return "clique";
+}
+/*****************************************************************************/
+
+#include "CglProbing.hpp"
+CglFakeClique::CglFakeClique(OsiSolverInterface * solver, bool setPacking) :
+  CglClique(setPacking,true)
+{
+  if (solver)
+    fakeSolver_ = solver->clone();
+  else
+    fakeSolver_ = NULL;
+  if (fakeSolver_) {
+    probing_ = new CglProbing();
+    probing_->refreshSolver(fakeSolver_);
+  } else {
+    probing_ = NULL;
+  }
+			      
+}
+// Copy constructor
+CglFakeClique::CglFakeClique(const CglFakeClique& rhs)
+  : CglClique(rhs)
+{
+  if (rhs.fakeSolver_) {
+    fakeSolver_ = rhs.fakeSolver_->clone();
+    probing_ = new CglProbing(*rhs.probing_);
+    probing_->refreshSolver(fakeSolver_);
+  } else {
+    fakeSolver_ = NULL;
+    probing_ = NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglFakeClique::clone() const
+{
+  return new CglFakeClique(*this);
+}
+
+// Destructor
+CglFakeClique::~CglFakeClique()
+{
+  delete fakeSolver_;
+  delete probing_;
+}
+// Assign solver (generator takes over ownership)
+void 
+CglFakeClique::assignSolver(OsiSolverInterface * fakeSolver)
+{
+  delete fakeSolver_;
+  fakeSolver_ = fakeSolver;
+  if (fakeSolver_) {
+    delete [] sp_orig_row_ind;
+    sp_orig_row_ind=NULL;
+  }
+  if (probing_)
+    probing_->refreshSolver(fakeSolver_);
+}
+// Generate cuts
+void
+CglFakeClique::generateCuts(const OsiSolverInterface& si, OsiCuts & cs,
+			const CglTreeInfo info)
+{
+  if (fakeSolver_) {
+    assert (si.getNumCols()==fakeSolver_->getNumCols());
+    fakeSolver_->setColLower(si.getColLower());
+    fakeSolver_->setColSolution(si.getColSolution());
+    fakeSolver_->setColUpper(si.getColUpper());
+    CglClique::generateCuts(*fakeSolver_,cs,info);
+    if (probing_) {
+      // get and set branch and bound cutoff
+      double cutoff;
+      si.getDblParam(OsiDualObjectiveLimit,cutoff);
+      fakeSolver_->setDblParam(OsiDualObjectiveLimit,cutoff);
+      probing_->generateCuts(*fakeSolver_,cs,info);
+    }
+  } else {
+    // just use real solver
+    CglClique::generateCuts(si,cs,info);
+  }
+}
diff --git a/cbits/coin/CglClique.hpp b/cbits/coin/CglClique.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglClique.hpp
@@ -0,0 +1,308 @@
+// $Id: CglClique.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef _CglClique_h_
+#define _CglClique_h_
+
+#include "CglCutGenerator.hpp"
+
+//class OsiCuts;
+//class OsiSolverInterface;
+
+class CglClique : public CglCutGenerator {
+
+    friend void CglCliqueUnitTest(const OsiSolverInterface * siP,
+				  const std::string mpdDir );
+public:
+    /// Copy constructor
+    CglClique(const CglClique& rhs);
+    /// Clone
+    virtual CglCutGenerator * clone() const;
+
+    /// Assignment operator
+    CglClique& operator=(const CglClique& rhs);
+   
+public:
+    
+    virtual void
+    generateCuts(const OsiSolverInterface& si, OsiCuts & cs,
+		 const CglTreeInfo info = CglTreeInfo());
+   
+    /**@name Constructors and destructors */
+    //@{
+    /** Default constructor.
+	If the setPacking argument is set to true then CglClique will assume that the
+	problem in the solverinterface passed to the generateCuts() method
+	describes a set packing problem, i.e.,
+	- all variables are binary
+	- the matrix is a 0-1 matrix
+	- all constraints are '= 1' or '<= 1'
+       
+	Otherwise the user can use the considerRows() method to set the list of
+	clique rows, that is,
+	- all coeffs corresponding to binary variables at fractional level is 1
+	- all other coeffs are non-negative
+	- the constraint is '= 1' or '<= 1'.
+
+	If the user does not set the list of clique rows then CglClique will
+	start the generateCuts() methods by scanning the matrix for them.
+	Also justOriginalRows can be set to true to limit clique creation
+    */
+    CglClique(bool setPacking = false, bool justOriginalRows = false);
+    /// Destructor
+    virtual ~CglClique() {}
+    /// Create C++ lines to get to current state
+    virtual std::string generateCpp( FILE * fp);
+
+    void considerRows(const int numRows, const int* rowInd);
+
+public:
+    /** possible choices for selecting the next node in the star clique search
+     */
+    enum scl_next_node_method {
+	SCL_MIN_DEGREE,
+	SCL_MAX_DEGREE,
+	SCL_MAX_XJ_MAX_DEG
+    };
+
+    void setStarCliqueNextNodeMethod(scl_next_node_method method) {
+	scl_next_node_rule = method;
+    }
+
+    void setStarCliqueCandidateLengthThreshold(int maxlen) {
+	scl_candidate_length_threshold = maxlen;
+    }
+    void setRowCliqueCandidateLengthThreshold(int maxlen) {
+	rcl_candidate_length_threshold = maxlen;
+    }
+
+    void setStarCliqueReport(bool yesno = true) { scl_report_result = yesno; }
+    void setRowCliqueReport(bool yesno = true) { rcl_report_result = yesno; }
+
+    void setDoStarClique(bool yesno = true) { do_star_clique = yesno; }
+    void setDoRowClique(bool yesno = true) { do_row_clique = yesno; }
+
+    void setMinViolation(double minviol) { petol = minviol; }
+    double getMinViolation() const { return petol; }
+
+private:
+
+    struct frac_graph ;
+    friend struct frac_graph ;
+
+    /** A node of the fractional graph. There is a node for every variable at
+	fractional level. */
+    struct fnode {
+	/** pointer into all_nbr */
+	int          *nbrs;
+	/** 1-x_i-x_j, needed for odd holes, in the same order as the adj list,
+	    pointer into all_edgecost */
+	double       *edgecosts;
+	/** degree of the node */
+	int           degree;
+	/** the fractional value of the variable corresponding to this node */
+	double        val;
+    };
+
+    /** A graph corresponding to a fractional solution of an LP. Two nodes are
+	adjacent iff their columns are non-orthogonal. */
+    struct frac_graph {
+	/** # of nodes = # of fractional values in the LP solution */
+	int    nodenum;
+	/** # of edges in the graph */
+	int    edgenum;
+	/** density= edgenum/(nodenum choose 2) */
+	double density;
+	int    min_deg_node;
+	int    min_degree;
+	int    max_deg_node;
+	int    max_degree;
+	/** The array of the nodes in the graph */
+	fnode  *nodes;
+	/** The array of all the neighbors. First the indices of the nodes
+	    adjacent to node 0 are listed, then those adjacent to node 1, etc. */
+	int    *all_nbr;
+	/** The array of the costs of the edges going to the neighbors */
+	double *all_edgecost;
+
+	frac_graph() :
+	    nodenum(0), edgenum(0), density(0),
+	    min_deg_node(0), min_degree(0), max_deg_node(0), max_degree(0),
+	    nodes(0), all_nbr(0), all_edgecost(0) {}
+    };
+
+protected:
+    /** An indicator showing whether the whole matrix in the solverinterface is
+	a set packing problem or not */
+    bool setPacking_;
+    /// True if just look at original rows
+    bool justOriginalRows_;
+    /** pieces of the set packing part of the solverinterface */
+    int sp_numrows;
+    int* sp_orig_row_ind;
+    int sp_numcols;
+    int* sp_orig_col_ind;
+    double* sp_colsol;
+    int* sp_col_start;
+    int* sp_col_ind;
+    int* sp_row_start;
+    int* sp_row_ind;
+
+    /** the intersection graph corresponding to the set packing problem */
+    frac_graph fgraph;
+    /** the node-node incidence matrix of the intersection graph. */
+    bool* node_node;
+
+    /** The primal tolerance in the solverinterface. */
+    double petol;
+
+    /** data for the star clique algorithm */
+
+    /** Parameters */
+    /**@{*/
+    /** whether to do the row clique algorithm or not. */
+    bool do_row_clique;
+    /** whether to do the star clique algorithm or not. */
+    bool do_star_clique;
+
+    /** How the next node to be added to the star clique should be selected */
+    scl_next_node_method scl_next_node_rule;
+    /** In the star clique method the maximal length of the candidate list
+	(those nodes that are in a star, i.e., connected to the center of the
+	star) to allow complete enumeration of maximal cliques. Otherwise a
+	greedy algorithm is used. */
+    int scl_candidate_length_threshold;
+    /** whether to give a detailed statistics on the star clique method */
+    bool scl_report_result;
+
+    /** In the row clique method the maximal length of the candidate list
+	(those nodes that can extend the row clique, i.e., connected to all
+	nodes in the row clique) to allow complete enumeration of maximal
+	cliques. Otherwise a greedy algorithm is used. */
+    int rcl_candidate_length_threshold;
+    /** whether to give a detailed statistics on the row clique method */
+    bool rcl_report_result;
+    /**@}*/
+
+    /** variables/arrays that are used across many methods */
+    /**@{*/
+    /** List of indices that must be in the to be created clique. This is just
+	a pointer, it is never new'd and therefore does not need to be
+	delete[]'d either. */
+    const int* cl_perm_indices;
+    /** The length of cl_perm_indices */
+    int cl_perm_length;
+
+    /** List of indices that should be considered for extending the ones listed
+	in cl_perm_indices. */
+    int* cl_indices;
+    /** The length of cl_indices */
+    int cl_length;
+
+    /** An array of nodes discarded from the candidate list. These are
+	rechecked when a maximal clique is found just to make sure that the
+	clique is really maximal. */
+    int* cl_del_indices;
+    /** The length of cl_del_indices */
+    int cl_del_length;
+
+    /**@}*/
+
+private:
+    /** Scan through the variables and select those that are binary and are at
+	a fractional level. */
+    void selectFractionalBinaries(const OsiSolverInterface& si);
+    /** Scan through the variables and select those that are at a fractional
+	level. We already know that everything is binary. */
+    void selectFractionals(const OsiSolverInterface& si);
+    /**  */
+    void selectRowCliques(const OsiSolverInterface& si,int numOriginalRows);
+    /**  */
+    void createSetPackingSubMatrix(const OsiSolverInterface& si);
+    /**  */
+    void createFractionalGraph();
+    /**  */
+    int createNodeNode();
+    /**  */
+    void deleteSetPackingSubMatrix();
+    /**  */
+    void deleteFractionalGraph();
+    /**  */
+    void find_scl(OsiCuts& cs);
+    /**  */
+    void find_rcl(OsiCuts& cs);
+    /**  */
+    int scl_choose_next_node(const int current_nodenum,
+			     const int *current_indices,
+			     const int *current_degrees,
+			     const double *current_values);
+    /**  */
+    void scl_delete_node(const int del_ind, int& current_nodenum,
+			 int *current_indices, int *current_degrees,
+			 double *current_values);
+    /**  */
+    int enumerate_maximal_cliques(int& pos, bool* scl_label, OsiCuts& cs);
+    /**  */
+    int greedy_maximal_clique(OsiCuts& cs);
+    /**  */
+    void recordClique(const int len, int* indices, OsiCuts& cs);
+};
+//#############################################################################
+/** A function that tests the methods in the CglClique class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglCliqueUnitTest(const OsiSolverInterface * siP,
+		       const std::string mpdDir);
+/// This works on a fake solver i.e. invented rows
+class CglProbing;
+class CglFakeClique : public CglClique {
+  
+public:
+  /// Copy constructor
+  CglFakeClique(const CglFakeClique& rhs);
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+  
+  /// Assignment operator
+  CglFakeClique& operator=(const CglFakeClique& rhs);
+  
+  virtual void
+  generateCuts(const OsiSolverInterface& si, OsiCuts & cs,
+	       const CglTreeInfo info = CglTreeInfo());
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor.
+      If the setPacking argument is set to true then CglFakeClique will assume that the
+      problem in the solverinterface passed to the generateCuts() method
+      describes a set packing problem, i.e.,
+      - all variables are binary
+      - the matrix is a 0-1 matrix
+      - all constraints are '= 1' or '<= 1'
+      
+      Otherwise the user can use the considerRows() method to set the list of
+      clique rows, that is,
+      - all coeffs corresponding to binary variables at fractional level is 1
+      - all other coeffs are non-negative
+      - the constraint is '= 1' or '<= 1'.
+      
+      If the user does not set the list of clique rows then CglFakeClique will
+      start the generateCuts() methods by scanning the matrix for them.
+  */
+  CglFakeClique(OsiSolverInterface * solver=NULL,bool setPacking = false);
+  /// Destructor
+  virtual ~CglFakeClique();
+  /// Assign solver (generator takes over ownership)
+  void assignSolver(OsiSolverInterface * fakeSolver);
+protected:
+  /// fake solver to use
+  OsiSolverInterface * fakeSolver_;
+  /// Probing object
+  CglProbing * probing_;
+};
+
+#endif
diff --git a/cbits/coin/CglCliqueHelper.cpp b/cbits/coin/CglCliqueHelper.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglCliqueHelper.cpp
@@ -0,0 +1,373 @@
+// $Id: CglCliqueHelper.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <numeric>
+#include <cassert>
+
+#include "CoinPackedMatrix.hpp"
+#include "OsiSolverInterface.hpp"
+#include "CglClique.hpp"
+
+/*****************************************************************************/
+
+/*===========================================================================*
+  Scan through the variables and select those that are binary and are at a
+  fractional level.
+ *===========================================================================*/
+void
+CglClique::selectFractionalBinaries(const OsiSolverInterface& si)
+{
+   // extract the primal tolerance from the solver
+   double lclPetol = 0.0;
+   si.getDblParam(OsiPrimalTolerance, lclPetol);
+
+   const int numcols = si.getNumCols();
+   if (petol<0.0) {
+     // do all if not too many
+     int n=0;
+     for (int i = 0; i < numcols; ++i) {
+       if (si.isBinary(i))
+	 n++;
+     }
+     if (n<5000)
+       lclPetol=-1.0e-5;
+   }
+   const double* x = si.getColSolution();
+   std::vector<int> fracind;
+   int i;
+   for (i = 0; i < numcols; ++i) {
+      if (si.isBinary(i) && x[i] > lclPetol && x[i] < 1-petol)
+	 fracind.push_back(i);
+   }
+   sp_numcols = static_cast<int>(fracind.size());
+   sp_orig_col_ind = new int[sp_numcols];
+   sp_colsol = new double[sp_numcols];
+   for (i = 0; i < sp_numcols; ++i) {
+      sp_orig_col_ind[i] = fracind[i];
+      sp_colsol[i] = x[fracind[i]];
+   }
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+  Scan through the variables and select those that are at a fractional
+  level. We already know that everything is binary.
+ *===========================================================================*/
+
+void
+CglClique::selectFractionals(const OsiSolverInterface& si)
+{
+   // extract the primal tolerance from the solver
+   double lclPetol = 0.0;
+   si.getDblParam(OsiPrimalTolerance, lclPetol);
+
+   const int numcols = si.getNumCols();
+   const double* x = si.getColSolution();
+   std::vector<int> fracind;
+   int i;
+   for (i = 0; i < numcols; ++i) {
+      if (x[i] > lclPetol && x[i] < 1-lclPetol)
+	 fracind.push_back(i);
+   }
+   sp_numcols = static_cast<int>(fracind.size());
+   sp_orig_col_ind = new int[sp_numcols];
+   sp_colsol = new double[sp_numcols];
+   for (i = 0; i < sp_numcols; ++i) {
+      sp_orig_col_ind[i] = fracind[i];
+      sp_colsol[i] = x[fracind[i]];
+   }
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ *===========================================================================*/
+
+void
+CglClique::selectRowCliques(const OsiSolverInterface& si,int numOriginalRows)
+{
+   const int numrows = si.getNumRows();
+   std::vector<int> clique(numrows, 1);
+
+   int i, j, k;
+   
+   // First scan through the binary fractional variables and see where do they
+   // have a 1 coefficient
+   const CoinPackedMatrix& mcol = *si.getMatrixByCol();
+   for (j = 0; j < sp_numcols; ++j) {
+      const CoinShallowPackedVector& vec = mcol.getVector(sp_orig_col_ind[j]);
+      const int* ind = vec.getIndices();
+      const double* elem = vec.getElements();
+      for (i = vec.getNumElements() - 1; i >= 0; --i) {
+	 if (elem[i] != 1.0) {
+	    clique[ind[i]] = 0;
+	 }
+      }
+   }
+
+   // Now check the sense and rhs (by checking rowupper) and the rest of the
+   // coefficients 
+   const CoinPackedMatrix& mrow = *si.getMatrixByRow();
+   const double* rub = si.getRowUpper();
+   for (i = 0; i < numrows; ++i) {
+      if (rub[i] != 1.0||i>=numOriginalRows) {
+	 clique[i] = 0;
+	 continue;
+      }
+      if (clique[i] == 1) {
+	 const CoinShallowPackedVector& vec = mrow.getVector(i);
+	 const double* elem = vec.getElements();
+	 for (j = vec.getNumElements() - 1; j >= 0; --j) {
+	    if (elem[j] < 0) {
+	       clique[i] = 0;
+	       break;
+	    }
+	 }
+      }
+   }
+
+   // Finally collect the still standing rows into sp_orig_row_ind
+   sp_numrows = std::accumulate(clique.begin(), clique.end(), 0);
+   sp_orig_row_ind = new int[sp_numrows];
+   for (i = 0, k = 0; i < numrows; ++i) {
+      if (clique[i] == 1) {
+	 sp_orig_row_ind[k++] = i;
+      }
+   }
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+  Create the set packing submatrix
+ *===========================================================================*/
+void
+CglClique::createSetPackingSubMatrix(const OsiSolverInterface& si)
+{
+   sp_col_start = new int[sp_numcols+1];
+   sp_row_start = new int[sp_numrows+1];
+   std::fill(sp_col_start, sp_col_start + (sp_numcols+1), 0);
+   std::fill(sp_row_start, sp_row_start + (sp_numrows+1), 0);
+
+   int i, j;
+
+   const CoinPackedMatrix& mcol = *si.getMatrixByCol();
+   const int numrows = si.getNumRows();
+   int* clique = new int[numrows];
+   std::fill(clique, clique+numrows, -1);
+   for (i = 0; i < sp_numrows; ++i)
+      clique[sp_orig_row_ind[i]] = i;
+
+   for (j = 0; j < sp_numcols; ++j) {
+      const CoinShallowPackedVector& vec = mcol.getVector(sp_orig_col_ind[j]);
+      const int* ind = vec.getIndices();
+      for (i = vec.getNumElements() - 1; i >= 0; --i) {
+	 if (clique[ind[i]] >= 0) {
+	    ++sp_col_start[j];
+	    ++sp_row_start[clique[ind[i]]];
+	 }
+      }
+   }
+
+   std::partial_sum(sp_col_start, sp_col_start+sp_numcols, sp_col_start);
+   std::rotate(sp_col_start, sp_col_start+sp_numcols,
+	       sp_col_start + (sp_numcols+1));
+   std::partial_sum(sp_row_start, sp_row_start+sp_numrows, sp_row_start);
+   std::rotate(sp_row_start, sp_row_start+sp_numrows,
+	       sp_row_start + (sp_numrows+1));
+   const int nzcnt = sp_col_start[sp_numcols];
+   assert(nzcnt == sp_row_start[sp_numrows]);
+/*
+  Now create the vectors with row indices for each column (sp_col_ind) and
+  column indices for each row (sp_row_ind). It turns out that
+  CoinIsOrthogonal assumes that the row indices for a given column are listed
+  in ascending order. This is *not* a solver-independent assumption! At best,
+  one can hope that the underlying solver will produce an index vector that's
+  either ascending or descending. Under that assumption, compare the first
+  and last entries and proceed accordingly. Eventually some solver will come
+  along that hands back an index vector in random order, and CoinIsOrthogonal
+  will break.  Until then, try and avoid the cost of a sort.
+*/
+   sp_col_ind = new int[nzcnt];
+   sp_row_ind = new int[nzcnt];
+   int last=0;
+   for (j = 0; j < sp_numcols; ++j) {
+      const CoinShallowPackedVector& vec = mcol.getVector(sp_orig_col_ind[j]);
+      const int len = vec.getNumElements();
+      const int* ind = vec.getIndices();
+      if (ind[0] < ind[len-1]) {
+	for (i = 0; i < len; ++i) {
+	   const int sp_row = clique[ind[i]];
+	   if (sp_row >= 0) {
+	      sp_col_ind[sp_col_start[j]++] = sp_row;
+	      sp_row_ind[sp_row_start[sp_row]++] = j;
+	   }
+	}
+      }
+      else {
+	for (i = len-1; i >= 0; --i) {
+	   const int sp_row = clique[ind[i]];
+	   if (sp_row >= 0) {
+	      sp_col_ind[sp_col_start[j]++] = sp_row;
+	      sp_row_ind[sp_row_start[sp_row]++] = j;
+	   }
+	}
+      }
+      // sort
+      std::sort(sp_col_ind+last,sp_col_ind+sp_col_start[j]);
+      last=sp_col_start[j];
+   }
+   std::rotate(sp_col_start, sp_col_start+sp_numcols,
+	       sp_col_start + (sp_numcols+1));
+   sp_col_start[0] = 0;
+   std::rotate(sp_row_start, sp_row_start+sp_numrows,
+	       sp_row_start + (sp_numrows+1));
+   sp_row_start[0] = 0;
+
+   delete[] clique;
+}
+
+/*****************************************************************************/
+
+static inline bool
+CoinIsOrthogonal(const int* first0, const int* last0,
+		 const int* first1, const int* last1)
+{
+   while (first0 != last0 && first1 != last1) {
+      if (*first0 == *first1)
+	 return false;
+      if (*first0 < *first1)
+	 ++first0;
+      else
+	 ++first1;
+   }
+   return true;
+}
+
+/*===========================================================================*
+  Build up the fractional graph
+ *===========================================================================*/
+
+void
+CglClique::createFractionalGraph()
+{
+   // fgraph.edgenum is filled when createNodeNode is invoked
+   fgraph.nodenum = sp_numcols;
+   fgraph.all_nbr = new int[2*fgraph.edgenum];
+   fgraph.nodes = new fnode[sp_numcols+1];
+
+   int *all_nbr = fgraph.all_nbr;
+   fnode *nodes = fgraph.nodes;
+   int min_degree, max_degree, min_deg_node, max_deg_node;
+
+#  ifdef ZEROFAULT
+   // May be read below even if sp_numcols == 0
+   nodes[0].degree = 0 ;
+#  endif
+
+   int i, j, total_deg, old_total;
+
+   /*========================================================================*
+      Construct the adjacency lists (neighbors) of the nodes in fgraph.
+      Two nodes are adjacent iff the columns corresponding to them are
+      non-orthogonal.
+    *========================================================================*/
+
+   for ( i = 0, total_deg = 0; i < sp_numcols; i++ ) {
+      old_total = total_deg;
+      const bool* node_node_i = node_node + i * sp_numcols;
+      for ( j = 0; j < sp_numcols; j++ ) {
+	 if ( node_node_i[j] ) {
+	    all_nbr[total_deg++] = j;
+	 }
+      }
+      nodes[i].val = sp_colsol[i];
+      nodes[i].degree = total_deg - old_total;
+      nodes[i].nbrs = all_nbr + old_total;
+   }
+
+   fgraph.density = static_cast<double> (total_deg) / (sp_numcols * (sp_numcols-1));
+
+   /*========================================================================*
+     Compute the min and max degree.
+    *========================================================================*/
+   min_deg_node = 0; max_deg_node = 0;
+   min_degree = max_degree = nodes[0].degree;
+   for ( i = 0; i < sp_numcols; i++ ) {
+      if ( nodes[i].degree < min_degree ) {
+	 min_deg_node = i;
+	 min_degree = nodes[i].degree;
+      }
+      if ( nodes[i].degree > max_degree ) {
+	 max_deg_node = i;
+	 max_degree = nodes[i].degree;
+      }
+   }
+   fgraph.min_degree = min_degree;
+   fgraph.max_degree = max_degree;
+   fgraph.min_deg_node = min_deg_node;
+   fgraph.max_deg_node = max_deg_node;
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ * Construct the node-node incidence matrix from the fractional graph.
+ *===========================================================================*/
+int
+CglClique::createNodeNode()
+{
+   node_node = new bool[sp_numcols * sp_numcols];
+   std::fill(node_node, node_node + sp_numcols * sp_numcols, false);
+
+   int i, j;
+   int edgenum = 0;
+   for (i = 0; i < sp_numcols; ++i) {
+      for (j = i+1; j < sp_numcols; ++j) {
+	 if (! CoinIsOrthogonal(sp_col_ind + sp_col_start[i],
+				sp_col_ind + sp_col_start[i+1],
+				sp_col_ind + sp_col_start[j],
+				sp_col_ind + sp_col_start[j+1]) ) {
+	    node_node[i * sp_numcols + j] = true;
+	    node_node[j * sp_numcols + i] = true;
+	    ++edgenum;
+	 }
+      }
+   }
+   return edgenum;
+}
+
+/*****************************************************************************/
+
+/*===========================================================================*
+ * Cleanup routines
+ *===========================================================================*/
+void
+CglClique::deleteSetPackingSubMatrix()
+{
+   delete[] sp_orig_row_ind; sp_orig_row_ind = 0; 
+   delete[] sp_orig_col_ind; sp_orig_col_ind = 0; 
+   delete[] sp_colsol;	     sp_colsol = 0;       
+   delete[] sp_col_start;    sp_col_start = 0;    
+   delete[] sp_col_ind;	     sp_col_ind = 0;      
+   delete[] sp_row_start;    sp_row_start = 0;    
+   delete[] sp_row_ind;      sp_row_ind = 0;
+}
+
+void
+CglClique::deleteFractionalGraph()
+{
+   fgraph.nodenum = 0;
+   fgraph.edgenum = 0;
+   fgraph.density = 0;
+   fgraph.min_deg_node = 0;
+   fgraph.min_degree = 0;
+   fgraph.max_deg_node = 0;
+   fgraph.max_degree = 0;
+   delete[] fgraph.all_nbr;      fgraph.all_nbr = 0;
+   delete[] fgraph.nodes;        fgraph.nodes = 0;
+   delete[] fgraph.all_edgecost; fgraph.all_edgecost = 0;
+}
diff --git a/cbits/coin/CglConfig.h b/cbits/coin/CglConfig.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglConfig.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2011
+ * All Rights Reserved.
+ * This code is published under the Eclipse Public License.
+ *
+ * $Id: CglConfig.h 1024 2011-06-09 11:56:44Z stefan $
+ *
+ * Include file for the configuration of Cgl.
+ *
+ * On systems where the code is configured with the configure script
+ * (i.e., compilation is always done with HAVE_CONFIG_H defined), this
+ * header file includes the automatically generated header file, and
+ * undefines macros that might configure with other Config.h files.
+ *
+ * On systems that are compiled in other ways (e.g., with the
+ * Developer Studio), a header files is included to define those
+ * macros that depend on the operating system and the compiler.  The
+ * macros that define the configuration of the particular user setting
+ * (e.g., presence of other COIN-OR packages or third party code) are set
+ * by the files config_*default.h. The project maintainer needs to remember
+ * to update these file and choose reasonable defines.
+ * A user can modify the default setting by editing the config_*default.h files.
+ *
+ */
+
+#ifndef __CGLCONFIG_H__
+#define __CGLCONFIG_H__
+
+#ifdef HAVE_CONFIG_H
+#ifdef CGL_BUILD
+#include "config.h"
+#else
+#include "config_cgl.h"
+#endif
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef CGL_BUILD
+#include "config_default.h"
+#else
+#include "config_cgl_default.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+#endif /*__CGLCONFIG_H__*/
diff --git a/cbits/coin/CglCutGenerator.cpp b/cbits/coin/CglCutGenerator.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglCutGenerator.cpp
@@ -0,0 +1,83 @@
+// $Id: CglCutGenerator.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cassert>
+//#include <cfloat>
+//#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CglCutGenerator.hpp"
+#include "CoinHelperFunctions.hpp"
+ 
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglCutGenerator::CglCutGenerator ()
+  : aggressive_(0),
+canDoGlobalCuts_(false)
+{
+  // nothing to do here
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglCutGenerator::CglCutGenerator (
+                  const CglCutGenerator & source)         
+  : aggressive_(source.aggressive_),
+    canDoGlobalCuts_(source.canDoGlobalCuts_)
+{  
+  // nothing to do here
+}
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglCutGenerator::~CglCutGenerator ()
+{
+  // nothing to do here
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglCutGenerator &
+CglCutGenerator::operator=(
+                   const CglCutGenerator& rhs)
+{
+  if (this != &rhs) {
+    aggressive_ = rhs.aggressive_;
+    canDoGlobalCuts_ = rhs.canDoGlobalCuts_;
+  }
+  return *this;
+}
+bool 
+CglCutGenerator::mayGenerateRowCutsInTree() const
+{
+  return true;
+}
+// Return true if needs optimal basis to do cuts
+bool 
+CglCutGenerator::needsOptimalBasis() const
+{
+  return false;
+}
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#if 0
+//--------------------------------------------------------------------------
+// test EKKsolution methods.
+//--------------------------------------------------------------------------
+void
+CglCutGenerator::unitTest()
+{
+}
+#endif
diff --git a/cbits/coin/CglCutGenerator.hpp b/cbits/coin/CglCutGenerator.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglCutGenerator.hpp
@@ -0,0 +1,121 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglCutGenerator_H
+#define CglCutGenerator_H
+
+#include "OsiCuts.hpp"
+#include "OsiSolverInterface.hpp"
+#include "CglTreeInfo.hpp"
+
+//-------------------------------------------------------------------
+//
+// Abstract base class for generating cuts.
+//
+//-------------------------------------------------------------------
+///
+/** Cut Generator Base Class
+
+This is an abstract base class for generating cuts.  A specific cut 
+generator will inherit from this class.
+*/
+class CglCutGenerator  {
+  
+public:
+    
+  /**@name Generate Cuts */
+  //@{
+  /** Generate cuts for the model data contained in si.
+  The generated cuts are inserted into and returned in the
+  collection of cuts cs.
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo())=0;
+  //@}
+
+    
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglCutGenerator (); 
+ 
+  /// Copy constructor 
+  CglCutGenerator ( const CglCutGenerator &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const = 0;
+
+  /// Assignment operator 
+  CglCutGenerator & operator=(const CglCutGenerator& rhs);
+
+  /// Destructor 
+  virtual ~CglCutGenerator ();
+
+  /** Create C++ lines to set the generator in the current state.
+      The output must be parsed by the calling code, as each line
+      starts with a key indicating the following:<BR>
+      0: must be kept (for #includes etc)<BR>
+      3: Set to changed (not default) values<BR>
+      4: Set to default values (redundant)<BR>
+
+      Keys 1, 2, 5, 6, 7, 8 are defined, but not applicable to 
+      cut generators.
+  */
+  virtual std::string generateCpp( FILE * ) {return "";}
+
+  /// This can be used to refresh any information
+  virtual void refreshSolver(OsiSolverInterface * ) {}
+  //@}
+  
+  /**@name Gets and Sets */
+  //@{
+  /**
+     Get Aggressiveness - 0 = neutral, 100 is normal root node.
+     Really just a hint to cut generator
+  */
+  inline int getAggressiveness() const
+  { return aggressive_;}
+
+  /**
+     Set Aggressiveness - 0 = neutral, 100 is normal root node.
+     Really just a hint to cut generator
+  */
+  inline void setAggressiveness(int value)
+  { aggressive_=value;}
+  /// Set whether can do global cuts
+  inline void setGlobalCuts(bool trueOrFalse)
+  { canDoGlobalCuts_ = trueOrFalse;}
+  /// Say whether can do global cuts
+  inline bool canDoGlobalCuts() const
+  {return canDoGlobalCuts_;}
+  /**
+     Returns true if may generate Row cuts in tree (rather than root node).
+     Used so know if matrix will change in tree.  Really
+     meant so column cut generators can still be active
+     without worrying code.
+     Default is true
+  */
+  virtual bool mayGenerateRowCutsInTree() const;
+  /// Return true if needs optimal basis to do cuts
+  virtual bool needsOptimalBasis() const;
+  /// Return maximum length of cut in tree
+  virtual int maximumLengthOfCutInTree() const
+  { return COIN_INT_MAX;}
+  //@}
+  
+  // test this class
+  //static void unitTest();
+  
+// private:
+  
+  /**
+     Aggressiveness - 0 = neutral, 100 is normal root node.
+     Really just a hint to cut generator
+  */
+  int aggressive_;
+  /// True if can do global cuts i.e. no general integers
+  bool canDoGlobalCuts_;
+};
+
+#endif
diff --git a/cbits/coin/CglDuplicateRow.cpp b/cbits/coin/CglDuplicateRow.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglDuplicateRow.cpp
@@ -0,0 +1,3388 @@
+// $Id: CglDuplicateRow.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+//#define PRINT_DEBUG
+//#define CGL_DEBUG
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinFinite.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CglDuplicateRow.hpp"
+#include "CglStored.hpp"
+//-------------------------------------------------------------------
+// Generate duplicate row column cuts
+//------------------------------------------------------------------- 
+void CglDuplicateRow::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			      const CglTreeInfo info)
+{
+#ifdef CGL_DEBUG
+  const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+  if (debugger&&debugger->onOptimalPath(si)) {
+    printf("On optimal path\n");
+  }
+#endif
+  // Don't do in tree ?
+  if (info.inTree) {
+    // but do any stored cuts
+    if (storedCuts_)
+      storedCuts_->generateCuts(si,cs,info);
+    return;
+  }
+  if ((mode_&3)!=0) {
+    generateCuts12(si,cs,info);
+  } else if ((mode_&4)!=0) {
+    generateCuts4(si,cs,info);
+  } else {
+    assert ((mode_&8)!=0);
+    generateCuts8(si,cs,info);
+  }
+}
+void CglDuplicateRow::generateCuts12(const OsiSolverInterface & si, OsiCuts & cs,
+			      const CglTreeInfo info)
+{
+  int numberColumns = matrix_.getNumCols();
+  CoinPackedVector ubs;
+  
+  // Column copy
+  const double * element = matrix_.getElements();
+  const int * row = matrix_.getIndices();
+  const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+  const int * columnLength = matrix_.getVectorLengths();
+  // Row copy
+  const double * elementByRow = matrixByRow_.getElements();
+  const int * column = matrixByRow_.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+  const int * rowLength = matrixByRow_.getVectorLengths();
+  const double * columnLower = si.getColLower();
+  const double * columnUpper = si.getColUpper();
+  int nFree=0;
+  int nOut=0;
+  int nFixed=0;
+  int i;
+  int numberRows=matrix_.getNumRows();
+  const double * rowLower = si.getRowLower();
+  const double * rowUpper = si.getRowUpper();
+  int * effectiveRhs = CoinCopyOfArray(rhs_,numberRows);
+  int * effectiveLower = CoinCopyOfArray(lower_,numberRows);
+  double * effectiveRhs2 = new double [numberRows];
+  /* For L or G rows - compute effective lower we have to raech */
+  // mark bad rows - also used for domination
+  for (i=0;i<numberRows;i++) {
+    int duplicate=-1;
+    int LorG=0;
+    double rhs=0.0;
+    if (rowLower[i]<-1.0e20) {
+      LorG=1;
+      rhs=rowUpper[i];
+    } else if (rowUpper[i]>1.0e20) {
+      LorG=2;
+      rhs=rowLower[i];
+    }
+    int j;
+    for (j=rowStart[i];j<rowStart[i]+rowLength[i];j++) {
+      int iColumn = column[j];
+      double value=elementByRow[j];
+      if (LorG==1) {
+	// need lowest contribution
+	if (value>0.0) {
+	  double bound=columnLower[iColumn];
+	  if (bound>-1.0e20) 
+	    rhs -= bound*value;
+	  else
+	    LorG=-1;
+	} else {
+	  double bound=columnUpper[iColumn];
+	  if (bound<1.0e20) 
+	    rhs -= bound*value;
+	  else
+	    LorG=-1;
+	}
+      } else if (LorG==2) {
+	// need highest contribution
+	if (value<0.0) {
+	  double bound=columnLower[iColumn];
+	  if (bound>-1.0e20) 
+	    rhs -= bound*value;
+	  else
+	    LorG=-2;
+	} else {
+	  double bound=columnUpper[iColumn];
+	  if (bound<1.0e20) 
+	    rhs -= bound*value;
+	  else
+	    LorG=-2;
+	}
+      }
+      if (duplicate!=-3) {
+	if (value!=1.0) {
+	  duplicate=-3;
+	  rhs_[i]=-1000000;
+	  //break;
+	} else if (!si.isInteger(iColumn)) {
+	  duplicate=-5;
+	}
+      }
+    }
+    duplicate_[i]=duplicate;
+    if (!LorG) {
+      effectiveRhs2[i]=0.0;
+    } else if (LorG<0) {
+      // weak
+      effectiveRhs2[i]=-COIN_DBL_MAX;
+    } else if (LorG==1) {
+      effectiveRhs2[i]=rhs;
+    } else {
+      effectiveRhs2[i]=rhs;
+    }
+  }
+  double * colUpper2 = CoinCopyOfArray(columnUpper,numberColumns);
+  if (!info.pass&&(mode_&2)!=0) {
+    // First look at duplicate or dominated columns
+    double * random = new double[numberRows];
+    double * sort = new double[numberColumns+1];
+    if (info.randomNumberGenerator) {
+      const CoinThreadRandom * randomGenerator = info.randomNumberGenerator;
+      for (i=0;i<numberRows;i++) {
+	if (rowLower[i]<-1.0e20||rowUpper[i]>1.0e20)
+	  random[i]=0.0;
+	else
+	  random[i] = randomGenerator->randomDouble();
+      }
+    } else {
+      for (i=0;i<numberRows;i++) {
+	if (rowLower[i]<-1.0e20||rowUpper[i]>1.0e20)
+	  random[i]=0.0;
+	else
+	  random[i] = CoinDrand48();
+      }
+    }
+    int * which = new int[numberColumns];
+    int nPossible=0;
+    for ( i=0;i<numberColumns;i++) {
+      if (si.isBinary(i)) {
+	double value = 0.0;
+	for (int jj=columnStart[i];jj<columnStart[i]+columnLength[i];jj++) {
+	  int iRow = row[jj];
+	  value += element[jj]*random[iRow];
+	}
+	sort[nPossible]=value;
+	which[nPossible++]=i;
+      }
+    }
+    sort[nPossible]=COIN_DBL_MAX;
+    CoinSort_2(sort,sort+nPossible,which);
+    int last=maximumDominated_-1;
+    double lastValue=-1.0;
+    const double *objective = si.getObjCoefficients() ;
+    double direction = si.getObjSense();
+    // arrays for checking
+    double * elementEqualJ = new double [2*numberRows];
+    CoinZeroN(elementEqualJ,numberRows); // for memory checkers
+    double * elementGeJ = elementEqualJ + numberRows;
+    CoinZeroN(elementGeJ,numberRows);
+    int * rowEqualJ = new int[2*numberRows];
+    CoinZeroN(rowEqualJ,numberRows); // for memory checkers
+    int * rowGeJ = rowEqualJ + numberRows;
+    char * mark = new char[numberRows];
+    CoinZeroN(mark,numberRows);
+#if 1
+    for (i=0;i<nPossible+1;i++) {
+      if (sort[i]>lastValue) {
+	if (i-last<=maximumDominated_&&i>last+1) {
+	  // look to see if dominated
+	  for (int j=last;j<i;j++) {
+	    int jColumn = which[j];
+	    // skip if already fixed
+	    if (!colUpper2[jColumn])
+	      continue;
+	    int nGeJ=0;
+	    int nEqualJ=0;
+	    int jj;
+	    int nJ=columnLength[jColumn];
+	    for (jj=columnStart[jColumn];jj<columnStart[jColumn]+columnLength[jColumn];jj++) {
+	      int iRow = row[jj];
+	      if (random[iRow]) {
+		elementEqualJ[nEqualJ]=element[jj];
+		rowEqualJ[nEqualJ++]=iRow;
+	      } else {
+		// swap sign so all rows look like G
+		elementGeJ[iRow]=(rowUpper[iRow]>1.0e20) ? element[jj] : -element[jj];
+		rowGeJ[nGeJ++]=iRow;
+	      }
+	    }
+	    double objValueJ = objective[jColumn]*direction;
+	    for (int k=j+1;k<i;k++) {
+	      int kColumn = which[k];
+	      // skip if already fixed
+	      if (!colUpper2[kColumn])
+		continue;
+	      int nK=columnLength[kColumn];
+	      double objValueK = objective[kColumn]*direction;
+	      if ((nJ-nK)*(objValueK-objValueJ)>0.0)
+		continue;
+	      int nEqualK=0;
+	      // -2 no good, -1 J dominates K, 0 unknown or equal, 1 K dominates J
+	      int dominate=0;
+	      // mark
+	      int kk;
+	      for (kk=0;kk<nGeJ;kk++)
+		mark[rowGeJ[kk]]=1;
+	      for (kk=columnStart[kColumn];kk<columnStart[kColumn]+columnLength[kColumn];kk++) {
+		int iRow = row[kk];
+		if (random[iRow]) {
+		  if (iRow!=rowEqualJ[nEqualK]||
+		      element[kk]!=elementEqualJ[nEqualK]) {
+		    dominate=-2;
+		    break;
+		  } else {
+		    nEqualK++;
+		  }
+		} else {
+		  // swap sign so all rows look like G
+		  double valueK = (rowUpper[iRow]>1.0e20) ? element[kk] : -element[kk];
+		  double valueJ = elementGeJ[iRow];
+		  mark[iRow]=0;
+		  if (valueJ==valueK) {
+		    // equal
+		  } else if (valueJ>valueK) {
+		    // J would dominate K
+		    if (dominate==1) {
+		      // no good
+		      dominate=-2;
+		      break;
+		    } else {
+		      dominate=-1;
+		    }
+		  } else {
+		    // K would dominate J
+		    if (dominate==-1) {
+		      // no good
+		      dominate=-2;
+		      break;
+		    } else {
+		      dominate=1;
+		    }
+		  }
+		}
+	      }
+	      kk=0;
+	      if (dominate!=-2) {
+		// unmark and check
+		for (;kk<nGeJ;kk++) {
+		  int iRow = rowGeJ[kk];
+		  if (mark[iRow]) {
+		    double valueK = 0.0;
+		    double valueJ = elementGeJ[iRow];
+		    if (valueJ>valueK) {
+		      // J would dominate K
+		      if (dominate==1) {
+			// no good
+			dominate=-2;
+			break;
+		      } else {
+			dominate=-1;
+		      }
+		    } else {
+		      // K would dominate J
+		      if (dominate==-1) {
+			// no good
+			dominate=-2;
+			break;
+		      } else {
+			dominate=1;
+		      }
+		    }
+		  }
+		  mark[iRow]=0;
+		}
+	      } 
+	      // just unmark rest
+	      for (;kk<nGeJ;kk++)
+		mark[rowGeJ[kk]]=0;
+	      if (nEqualK==nEqualJ&&dominate!=-2) {
+		if (objValueJ==objValueK) {
+		  if (dominate<=0) {
+		    // say J dominates
+		    assert (colUpper2[kColumn]);
+		    dominate=-1;
+		  } else {
+		    // say K dominates
+		    assert (colUpper2[jColumn]);
+		    dominate=1;
+		  }
+		} else if (objValueJ<objValueK&&dominate<=0) {
+		  // say J dominates
+		  assert (colUpper2[kColumn]);
+		  dominate=-1;
+		} else if (objValueJ>objValueK&&dominate==1) {
+		  // say K dominates
+		  assert (colUpper2[jColumn]);
+		  dominate=1;
+		} else {
+		  dominate=0;
+		}
+		if (dominate) {
+		  // see if both can be 1
+		  bool canFix=false;
+		  for (int jj=0;jj<nEqualJ;jj++) {
+		    double value = 2.0*elementEqualJ[jj];
+		    int iRow = rowEqualJ[jj];
+		    if (duplicate_[iRow]==-1&&rowUpper[iRow]<1.999999) {
+		      canFix=true;
+		    } else {
+		      double minSum=0.0;
+		      double maxSum=0.0;
+		      for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+			int iColumn = column[j];
+			if (iColumn!=jColumn&&iColumn!=kColumn) {
+			  double elValue = elementByRow[j];
+			  double lo = columnLower[iColumn];
+			  double up = colUpper2[iColumn];
+			  if (elValue>0.0) {
+			    minSum += lo*elValue;
+			    maxSum += up*elValue;
+			  } else {
+			    maxSum += lo*elValue;
+			    minSum += up*elValue;
+			  }
+			}
+		      }
+		      if (minSum+value>rowUpper[iRow]+1.0e-5)
+			canFix=true;
+		      else if (maxSum+value<rowLower[iRow]-1.0e-5)
+			canFix=true;
+		    }
+		    if (canFix)
+		      break;
+		  }
+		  if (!canFix) {
+		    for (kk=columnStart[kColumn];kk<columnStart[kColumn]+columnLength[kColumn];kk++) {
+		      int iRow = row[kk];
+		      if (!random[iRow]) {
+			if (rowUpper[iRow]<1.0e20) {
+			  // just <= row
+			  double valueK = element[kk] - elementGeJ[iRow];
+			  if (valueK>effectiveRhs2[iRow]+1.0e-4) {
+			    canFix=true;
+			    break;
+			  }
+			} else {
+			  // >= row
+			  double valueK = element[kk] + elementGeJ[iRow];
+			  if (valueK<effectiveRhs2[iRow]-1.0e-4) {
+			    canFix=true;
+			    break;
+			  }
+			}
+		      }
+		    }
+		  }
+		  if (canFix) {
+		    int iColumn = (dominate>0) ? jColumn : kColumn;
+		    nFixed++;
+		    assert (!columnLower[iColumn]);
+		    colUpper2[iColumn]=0.0;
+		    ubs.insert(iColumn,0.0);
+		    if (iColumn==jColumn)
+		      break; // no need to carry on on jColumn
+		  } else {
+		    int iDominated = (dominate>0) ? jColumn : kColumn;
+		    int iDominating = (dominate<0) ? jColumn : kColumn;
+		    double els[]={1.0,-1.0};
+		    int inds[2];
+		    inds[0]=iDominating;
+		    inds[1]=iDominated;
+		    if (!storedCuts_)
+		      storedCuts_ = new CglStored();
+		    storedCuts_->addCut(0.0,COIN_DBL_MAX,2,inds,els);
+		  }
+		}
+	      }
+	    }
+	    for (jj=0;jj<nGeJ;jj++) {
+	      int iRow = rowGeJ[jj];
+	      elementGeJ[iRow]=0.0;
+	    }
+	  }
+	}
+	last=i;
+	lastValue = sort[i];
+      }
+    }
+#endif
+    delete [] mark;
+    delete [] elementEqualJ;
+    delete [] rowEqualJ;
+    delete [] random;
+    delete [] sort;
+    delete [] which;
+#ifdef COIN_DEVELOP
+    int numberCuts = storedCuts_ ? storedCuts_->sizeRowCuts() : 0;
+    if (nFixed||numberCuts) 
+      printf("** %d fixed and %d cuts from domination\n",nFixed,numberCuts);
+#endif
+  }
+  delete [] effectiveRhs2;
+  bool infeasible=false;
+  // if we were just doing columns - mark all as bad
+  if ((mode_&1)==0) {
+    for (i=0;i<numberRows;i++) {
+      duplicate_[i]=-3;
+      rhs_[i]=-1000000;
+      effectiveLower[i]=-1000000;
+    }
+  }
+  for ( i=0;i<numberColumns;i++) {
+    if (columnLower[i]) {
+      double value = columnLower[i];
+      for (int jj=columnStart[i];jj<columnStart[i]+columnLength[i];jj++) {
+        int iRow = row[jj];
+        nOut += static_cast<int> (element[jj]*value);
+        effectiveRhs[iRow] -= static_cast<int> (element[jj]*value);
+        effectiveLower[iRow] -= static_cast<int> (element[jj]*value);
+      }
+    }
+  }
+  for ( i=0;i<numberColumns;i++) {
+    if (columnLower[i]!=colUpper2[i]) {
+      bool fixed=false;
+      for (int jj=columnStart[i];jj<columnStart[i]+columnLength[i];jj++) {
+        int iRow = row[jj];
+        if (rhs_[iRow]>=0&&element[jj]>effectiveRhs[iRow]) 
+          fixed=true;
+      }
+      if (fixed) {
+        nFixed++;
+        colUpper2[i]=columnLower[i];
+        ubs.insert(i,columnLower[i]);
+      } else {
+        nFree++;
+      }
+    }
+  }
+  // See if anything odd
+  char * check = new char[numberColumns];
+  memset(check,0,numberColumns);
+  int * which2 = new int[numberColumns];
+  for (i=0;i<numberRows;i++) {
+    if (duplicate_[i]==-5) {
+      if ((rowLower[i]<=0.0||rowLower[i]==rowUpper[i])&&
+	  rowUpper[i]==floor(rowUpper[i])) {
+	effectiveRhs[i]= static_cast<int> (rowUpper[i]);
+	effectiveLower[i] = static_cast<int> (CoinMax(0.0,rowLower[i]));
+	bool goodRow=true;
+	for (int j=rowStart[i];j<rowStart[i]+rowLength[i];j++) {
+	  int iColumn = column[j];
+	  double value=columnLower[iColumn];
+	  if (value) {
+	    if (value==floor(value)) {
+	      effectiveRhs[i] -= static_cast<int> (value);
+	      effectiveLower[i] -= static_cast<int> (value);
+	    } else {
+	      goodRow=false;
+	    }
+	  }
+	}
+	if (goodRow)
+	  duplicate_[i] = -1; // can have continuous variables now
+	else
+	  duplicate_[i] = -3;
+      } else {
+	duplicate_[i] = -3;
+      }
+    }
+    if (duplicate_[i]==-1) {
+      if (effectiveRhs[i]>0) {
+	// leave
+      } else if (effectiveRhs[i]==0) {
+        duplicate_[i]=-2;
+      } else {
+        duplicate_[i]=-3;
+	// leave unless >=1 row
+	if (effectiveLower[i]==1&&rhs_[i]<0.0)
+	  duplicate_[i]=-4;
+      }
+    } else {
+      effectiveRhs[i]=-1000;
+    }
+  }
+  // Look at <= rows
+  for (i=0;i<numberRows;i++) {
+    // initially just one
+    if (effectiveRhs[i]==1&&duplicate_[i]==-1) {
+      int nn=0;
+      int j,k;
+      for (j=rowStart[i];j<rowStart[i]+rowLength[i];j++) {
+	int iColumn = column[j];
+	if (columnLower[iColumn]!=colUpper2[iColumn]) {
+#ifndef NDEBUG
+          assert (elementByRow[j]==1.0);
+#endif
+          check[iColumn]=1;
+          which2[nn++]=iColumn;
+        }
+      }
+      for ( k=i+1;k<numberRows;k++) {
+        if (effectiveRhs[k]==1&&duplicate_[k]==-1) {
+          int nn2=0;
+          int nnsame=0;
+          for ( j=rowStart[k];j<rowStart[k]+rowLength[k];j++) {
+            int iColumn = column[j];
+            if (columnLower[iColumn]!=colUpper2[iColumn]) {
+#ifndef NDEBUG
+              assert (elementByRow[j]==1.0);
+#endif
+              nn2++;
+              if (check[iColumn]) 
+                nnsame++;
+            }
+          }
+	  //if (nnsame)
+	  //printf("rows %d and %d, %d same - %d %d\n",
+	  //   i,k,nnsame,nn,nn2);
+	  bool checked=false;
+          if (nnsame==nn2) {
+            if (nn2<nn&&effectiveLower[k]==rhs_[k]&&rhs_[i]==rhs_[k]) {
+              if (logLevel_)
+                printf("row %d strict subset of row %d, fix some in row %d\n",
+                       k,i,i);
+              // treat i as duplicate
+              duplicate_[i]=k;
+              // zero out check so we can see what is extra
+              for ( j=rowStart[k];j<rowStart[k]+rowLength[k];j++) {
+                int iColumn = column[j];
+                check[iColumn]=0; 
+              }
+              // now redo and fix
+              nn=0;
+              for (j=rowStart[i];j<rowStart[i]+rowLength[i];j++) {
+                int iColumn = column[j];
+                if (columnLower[iColumn]!=colUpper2[iColumn]) {
+                  if (check[iColumn]) {
+                    // fix
+                    colUpper2[iColumn]=columnLower[iColumn];
+                    nFixed++;
+                    ubs.insert(iColumn,columnLower[iColumn]);
+                    check[iColumn]=0;
+                  } else {
+                    check[iColumn]=1;
+                    which2[nn++]=iColumn;
+                  }
+                }
+              }
+	      checked=true;
+            } else if (nn2==nn&&effectiveLower[i]==rhs_[i]&&effectiveLower[k]==rhs_[k]) {
+              if (logLevel_)
+                printf("row %d identical to row %d\n",
+                       k,i);
+              duplicate_[k]=i;
+	      checked=true;
+            } else if (nn2>=nn&&effectiveLower[i]==rhs_[i]&&effectiveLower[k]==rhs_[k]) {
+              abort();
+            }
+          } else if (nnsame==nn&&nn2>nn&&effectiveLower[i]==rhs_[i]&&rhs_[i]<=rhs_[k]) {
+            if (logLevel_)
+              printf("row %d strict superset of row %d, fix some in row %d\n",
+                     k,i,k);
+            // treat k as duplicate
+            duplicate_[k]=i;
+            // set check for k
+            for ( j=rowStart[k];j<rowStart[k]+rowLength[k];j++) {
+              int iColumn = column[j];
+              if (columnLower[iColumn]!=colUpper2[iColumn]) 
+                check[iColumn]=1; 
+            }
+            // zero out check so we can see what is extra
+            for ( j=rowStart[i];j<rowStart[i]+rowLength[i];j++) {
+              int iColumn = column[j];
+              check[iColumn]=0; 
+            }
+            //  fix
+            for (j=rowStart[k];j<rowStart[k]+rowLength[k];j++) {
+              int iColumn = column[j];
+              if (check[iColumn]) {
+                // fix
+                colUpper2[iColumn]=columnLower[iColumn];
+                nFixed++;
+                ubs.insert(iColumn,columnLower[iColumn]);
+                check[iColumn]=0;
+              }
+            }
+            // redo
+            nn=0;
+            for (j=rowStart[i];j<rowStart[i]+rowLength[i];j++) {
+              int iColumn = column[j];
+              if (columnLower[iColumn]!=colUpper2[iColumn]) {
+                check[iColumn]=1;
+                which2[nn++]=iColumn;
+              }
+            }
+	    checked=true;
+          }
+	  if (!checked) {
+            // may be redundant
+            if (nnsame==nn2) {
+              // k redundant ?
+              if (nn2<nn&&effectiveLower[k]<=0&&rhs_[i]<=rhs_[k]) {
+                if (logLevel_)
+                  printf("row %d slack subset of row %d, drop row %d\n",
+                         k,i,k);
+                // treat k as duplicate
+                duplicate_[k]=i;
+              }
+            } else if (nnsame==nn) {
+              // i redundant ?
+              if (nn2>nn&&effectiveLower[i]<=0&&rhs_[k]<=rhs_[i]) {
+                if (logLevel_)
+                  printf("row %d slack subset of row %d, drop row %d\n",
+                         i,k,i);
+                // treat i as duplicate
+                duplicate_[i]=k;
+              }
+            }
+          }
+        }
+      }
+      for (k=0;k<nn;k++) 
+        check[which2[k]]=0;
+      
+    }
+  }
+  // Look at >=1 rows
+  for (i=0;i<numberRows;i++) {
+    if (duplicate_[i]==-4) {
+      int nn=0;
+      int j,k;
+      for (j=rowStart[i];j<rowStart[i]+rowLength[i];j++) {
+	int iColumn = column[j];
+	if (columnLower[iColumn]!=colUpper2[iColumn]) {
+#ifndef NDEBUG
+          assert (elementByRow[j]==1.0);
+#endif
+          check[iColumn]=1;
+          which2[nn++]=iColumn;
+        }
+      }
+      for ( k=i+1;k<numberRows;k++) {
+        if (duplicate_[k]==-4) {
+          int nn2=0;
+          int nnsame=0;
+          for ( j=rowStart[k];j<rowStart[k]+rowLength[k];j++) {
+            int iColumn = column[j];
+            if (columnLower[iColumn]!=colUpper2[iColumn]) {
+#ifndef NDEBUG
+              assert (elementByRow[j]==1.0);
+#endif
+              nn2++;
+              if (check[iColumn]) 
+                nnsame++;
+            }
+          }
+	  // may be redundant
+	  if (nnsame==nn||nnsame==nn2) {
+	    if (nn2>nn) {
+	      // k redundant
+	      if (logLevel_) 
+		printf("row %d slack superset of row %d, drop row %d\n",
+		       k,i,k);
+	      // treat k as duplicate
+	      duplicate_[k]=i;
+	    } else if (nn2<nn) {
+	      // i redundant ?
+	      if (logLevel_)
+		printf("row %d slack superset of row %d, drop row %d\n",
+		     i,k,i);
+	      // treat i as duplicate
+	      duplicate_[i]=k;
+	    } else {
+	      if (logLevel_) 
+		printf("row %d same as row %d, drop row %d\n",
+		       k,i,k);
+	      // treat k as duplicate
+	      duplicate_[k]=i;
+	    }
+          }
+        }
+      }
+      for (k=0;k<nn;k++) 
+        check[which2[k]]=0;
+      
+    }
+  }
+  if ((mode_&1)!=0&&true) {
+    // look at doubletons
+    const double * rowLower = si.getRowLower();
+    const double * rowUpper = si.getRowUpper();
+    int i;
+    int nPossible=0;
+    for (i=0;i<numberRows;i++) {
+      if (rowLength[i]==2&&(duplicate_[i]<0&&duplicate_[i]!=-2)) {
+	bool possible=true;
+	int j;
+	for (j=rowStart[i];j<rowStart[i]+2;j++) {
+	  int iColumn = column[j];
+	  if (fabs(elementByRow[j])!=1.0||!si.isInteger(iColumn)) {
+	    possible=false;
+	    break;
+	  }
+	}
+	if (possible) {
+	  int j = rowStart[i];
+	  int column0 = column[j];
+	  double element0 = elementByRow[j];
+	  int column1 = column[j+1];
+	  double element1 = elementByRow[j+1];
+	  if (element0==1.0&&element1==1.0&&rowLower[i]==1.0&&
+	      rowUpper[i]>1.0e30) {
+	    if (logLevel_) {
+	      printf("Cover row %d %g <= ",i,rowLower[i]);
+	      printf("(%d,%g) (%d,%g) ",column0,element0,column1,element1);
+	      printf(" <= %g\n",rowUpper[i]);
+	    }
+	    effectiveRhs[nPossible++]=i;
+	  } else {
+	    // not at present
+	    //printf("NON Cover row %d %g <= ",i,rowLower[i]);
+	    //printf("(%d,%g) (%d,%g) ",column0,element0,column1,element1);
+	    //printf(" <= %g\n",rowUpper[i]);
+	  }
+	}
+      }
+    }
+    if (nPossible) {
+      int * check2 = new int [numberColumns];
+      CoinFillN(check2,numberColumns,-1);
+      for (int iPossible=0;iPossible<nPossible;iPossible++) {
+#ifndef NDEBUG
+	for (i=0;i<numberColumns;i++)
+	  assert (check2[i]==-1);
+#endif
+	i=effectiveRhs[iPossible];
+	int j = rowStart[i];
+	int column0 = column[j];
+	int column1 = column[j+1];
+	int k;
+	int nMarked=0;
+	for (int kPossible=iPossible+1;kPossible<nPossible;kPossible++) {
+	  k=effectiveRhs[kPossible];
+	  int j = rowStart[k];
+	  int columnB0 = column[j];
+	  int columnB1 = column[j+1];
+	  if (column0==columnB1||column1==columnB1) {
+	    columnB1=columnB0;
+	    columnB0=column[j+1];
+	  }
+	  bool good = false;
+	  if (column0==columnB0) {
+	    if (column1==columnB1) {
+	      // probably should have been picked up
+	      // safest to ignore
+	    } else {
+	      good=true;
+	    }
+	  } else if (column1==columnB0) {
+	    if (column0==columnB1) {
+	      // probably should have been picked up
+	      // safest to ignore
+	    } else {
+	      good=true;
+	    }
+	  }
+	  if (good) {
+	    if (check2[columnB1]<0) {
+	      check2[columnB1]=k;
+	      which2[nMarked++]=columnB1;
+	    } else {
+	      // found
+#ifndef COIN_DEVELOP
+	      if (logLevel_>1)
+#endif 
+		printf("***Make %d %d %d >=2 and take out rows %d %d %d\n",
+		       columnB1,column0,column1,
+		       i,k,check2[columnB1]);
+	      OsiRowCut rc;
+	      rc.setLb(2.0);
+	      rc.setUb(COIN_DBL_MAX);   
+	      int index[3];
+	      double element[3]={1.0,1.0,1.0};
+	      index[0]=column0;
+	      index[1]=column1;
+	      index[2]=columnB1;
+	      rc.setRow(3,index,element,false);
+	      cs.insert(rc);
+	      // drop rows
+	      duplicate_[i]=-2;
+	      duplicate_[k]=-2;
+	      duplicate_[check2[columnB1]]=-2;
+	    }
+	  }
+	}
+	for (k=0;k<nMarked;k++) {
+	  int iColumn = which2[k];
+	  check2[iColumn]=-1;
+	}
+      }
+      delete [] check2;
+    }
+  }
+  delete [] check;
+  delete [] which2;
+  delete [] colUpper2;
+  int nRow=0;
+  sizeDynamic_=1;
+  for (i=0;i<numberRows;i++) {
+    if (duplicate_[i]!=-3) {
+      if (duplicate_[i]==-1) {
+        nRow++;
+        int k=effectiveRhs[i];
+        while (k) {
+          if (sizeDynamic_<1000000000)
+            sizeDynamic_ = sizeDynamic_<<1;
+          k = k >>1;
+        }
+      }
+    } else {
+      duplicate_[i]=-1;
+    }
+  }
+  delete [] effectiveRhs;
+  delete [] effectiveLower;
+
+  if (logLevel_)
+    printf("%d free (but %d fixed this time), %d out of rhs, DP size %d, %d rows\n",
+           nFree,nFixed,nOut,sizeDynamic_,nRow);
+  if (nFixed) {
+    OsiColCut cc;
+    cc.setUbs(ubs);
+    cc.setEffectiveness(100.0);
+    cs.insert(cc);
+  }
+  if (infeasible) {
+    // generate infeasible cut and return
+    OsiRowCut rc;
+    rc.setLb(COIN_DBL_MAX);
+    rc.setUb(0.0);   
+    cs.insert(rc);
+  }
+}
+void CglDuplicateRow::generateCuts4(const OsiSolverInterface & si, OsiCuts & cs,
+			      const CglTreeInfo )
+{
+  int numberColumns = matrix_.getNumCols();
+  
+  // Column copy
+  const double * element = matrix_.getElements();
+  const int * row = matrix_.getIndices();
+  const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+  const int * columnLength = matrix_.getVectorLengths();
+  const double * columnLower = si.getColLower();
+  const double * columnUpper = si.getColUpper();
+  int nFixed=0;
+  int numberRows=matrix_.getNumRows();
+  const double * rowLower = si.getRowLower();
+  const double * rowUpper = si.getRowUpper();
+  bool infeasible=false;
+  // try more complicated domination
+  int * originalColumns = new int [numberColumns];
+  int * originalRows = new int [2*numberRows];
+  int * rowCount = originalRows+numberRows;
+  memset(rowCount,0,numberRows*sizeof(int));
+  memset(originalRows,0,numberRows*sizeof(int));
+  unsigned char * rowFlag = new unsigned char[numberRows];
+  unsigned char * columnFlag = new unsigned char[2*numberColumns];
+  double * newBound = new double[numberColumns];
+  double * trueLower = new double[numberColumns];
+  double * effectiveRhs = new double [2*numberRows];
+  double *rhs2 = effectiveRhs+numberRows;
+  // first take out fixed stuff
+  memset(rhs2,0,numberRows*sizeof(double));
+  memset(rowFlag,0,numberRows);
+  memset(columnFlag,0,numberColumns);
+  int nCol2=0;
+  for (int i=0;i<numberColumns;i++) {
+    if (columnLower[i]<-1.0e20&&columnUpper[i]>-1.0e20) {
+      for (int jj=columnStart[i];jj<columnStart[i]+columnLength[i];jj++) {
+	int iRow = row[jj];
+	rowFlag[iRow] |= 8; // say no good
+      }
+    } else {
+      double lo=columnLower[i];
+      double up=columnUpper[i];
+      double value=lo;
+      if (lo<-1.0e20) {
+	columnFlag[nCol2]=1; // say flipped
+	lo=-up;
+	up=-value;
+	value=-lo;
+	abort(); // double check
+      }
+      if (up>lo) {
+	int add=0;
+	if (si.isInteger(i)) {
+	  columnFlag[nCol2]|=2;
+	  if (up>lo+1.5) {
+	    add=1; // only allow one general
+	    columnFlag[nCol2]|=4;
+	  }
+	} else {
+	  add=1;
+	}
+	newBound[nCol2]=up-lo;
+	trueLower[nCol2]=lo;
+	originalColumns[nCol2++]=i;
+	for (int jj=columnStart[i];jj<columnStart[i]+columnLength[i];jj++) {
+	  int iRow = row[jj];
+	  rowCount[iRow]++;
+	  originalRows[iRow] += add;
+	}
+      }
+      for (int jj=columnStart[i];jj<columnStart[i]+columnLength[i];jj++) {
+	int iRow = row[jj];
+	rhs2[iRow] += element[jj]*value;
+      }
+    }
+  }
+  int nRow2=0;
+  for (int i=0;i<numberRows;i++) {
+    int nCont=originalRows[i];
+    int nInt=rowCount[i]-nCont;
+    unsigned char flag=rowFlag[i];
+    if (nCont>1||!nInt)
+      flag=8; // don't look at for now
+    if (rowLower[i]==rowUpper[i]) 
+      flag |= 1;
+    else if (rowLower[i]>-1.0e20&&rowUpper[i]<1.0e20)
+      flag |=8;
+    else if (rowUpper[i]>1.0e20)
+      flag |= 2;
+    if ((flag&8)==0) {
+      rowCount[nRow2]=rowCount[i];
+      originalRows[nRow2++]=i;
+    }
+  }
+  CoinSort_2(rowCount,rowCount+nRow2,originalRows);
+  for (int i=0;i<nRow2;i++) {
+    int k=originalRows[i];
+    unsigned char flag=0;
+    if (rowLower[k]==rowUpper[k]) 
+      flag |= 1;
+    else if (rowUpper[k]>1.0e20)
+      flag |= 2;
+    rowFlag[i]=flag;
+  }
+  if (nRow2&&nCol2) {
+    CoinPackedMatrix small(matrix_,nRow2,originalRows,
+			   nCol2,originalColumns);
+    // Column copy
+    small.removeGaps();
+    double * element = small.getMutableElements();
+    const int * row = small.getIndices();
+    const CoinBigIndex * columnStart = small.getVectorStarts();
+    //const int * columnLength = small.getVectorLengths();
+    for (int i=0;i<nCol2;i++) {
+      for (int jj=columnStart[i];jj<columnStart[i+1];jj++) {
+	int iRow=row[jj];
+	if ((rowFlag[iRow]&2)!=0)
+	  element[jj] = -element[jj];
+      }
+      if ((columnFlag[i]&1)!=0) {
+	for (int jj=columnStart[i];jj<columnStart[i+1];jj++) {
+	  element[jj] = -element[jj];
+	}
+      }
+    }
+    // same thing for row matrix
+    CoinPackedMatrix smallRow;
+    smallRow.setExtraGap(0.0);
+    smallRow.setExtraMajor(0.0);
+    smallRow.reverseOrderedCopyOf(small);
+    // Row copy
+    double * elementByRow = smallRow.getMutableElements();
+    int * column = smallRow.getMutableIndices();
+    const CoinBigIndex * rowStart = smallRow.getVectorStarts();
+    //const int * rowLength = smallRow.getVectorLengths();
+    for (int i=0;i<nRow2;i++) {
+      int start=rowStart[i];
+      int end=rowStart[i+1];
+      CoinSort_2(column+start,column+end,elementByRow+start);
+      int k=originalRows[i];
+      double rhs;
+      if ((rowFlag[i]&2)==0) 
+	rhs = rowUpper[k]-rhs2[k];
+      else
+	rhs = - (rowLower[k]-rhs2[k]);
+      effectiveRhs[i]=rhs;
+    }
+    int nRowLook=0;
+    int nRowStart=-1;
+#define MAX_IN_BASE 3
+#define MAX_IN_COMP 3
+    for (nRowLook=0;nRowLook<nRow2;nRowLook++) {
+      int start1 = rowStart[nRowLook];
+      int n=rowStart[nRowLook+1]-start1;
+      if (n>=2&&nRowStart<0)
+	nRowStart=nRowLook;
+      if (n>MAX_IN_BASE) 
+	break;
+    }
+    // cut back nRow2
+    int nnRow2=nRowLook;
+    for (nnRow2=0;nnRow2<nRow2;nnRow2++) {
+      int start1 = rowStart[nnRow2];
+      int n=rowStart[nnRow2+1]-start1;
+      if (n>MAX_IN_COMP) 
+	break;
+    }
+    nRow2=nnRow2;
+    nRowStart=CoinMax(0,nRowStart);
+    unsigned char * mark = columnFlag+nCol2;
+    memset(mark,0,nCol2);
+    /* at most 3 0-1 integers -
+       if all 0-1 then see if same allowed
+       if one other then get bounds
+    */
+    double loC0[4];
+    double upC0[4];
+    int allowed0[8];
+    double loC1[4];
+    double upC1[4];
+    int allowed1[8];
+    for (int i=nRowStart;i<nRowLook;i++) {
+      int start0 = rowStart[i];
+      int n=rowStart[i+1]-start0;
+      const int * column0 = column+start0;
+      const double * element0 = elementByRow+start0;
+      int nInt=0;
+      for (int j=0;j<n;j++) {
+	int iColumn = column0[j];
+	if ((columnFlag[iColumn]&(2+4))==2)
+	  nInt++;
+	mark[iColumn] =1;
+      }
+      for (int k=i+1;k<nRow2;k++) {
+	if (duplicate_[k]==-2)
+	  continue;
+	if (duplicate_[i]==-2)
+	  break;
+	int start1 = rowStart[k];
+	int n1=rowStart[k+1]-start1;
+	const int * column1 = column+start1;
+	const double * element1 = elementByRow+start1;
+	int nMatch=0;
+	for (int j=0;j<n1;j++) {
+	  if (mark[column1[j]])
+	    nMatch++;
+	}
+	if (nMatch==n) {
+#define CGL_INVESTIGATE
+	  if (n==n1) {
+	    // same - look at all 0-1 integers
+	    if (nInt==n) {
+	      // crude - should go stack based
+	      if (nInt==2) {
+		double upRhs = effectiveRhs[i];
+		double loRhs = ((rowFlag[i]&1)!=0) ? effectiveRhs[i] : -1.0e30;
+		double tolerance = CoinMax(1.0e-5,fabs(upRhs)*1.0e-10);
+		for (int j0=0;j0<2;j0++) {
+		  for (int j1=0;j1<2;j1++) {
+		    double value = element0[0]*j0+element0[1]*j1;
+		    int put = j0+2*j1;
+		    if (value<upRhs+tolerance&&value>loRhs-tolerance)
+		      allowed0[put]=1;
+		    else
+		      allowed0[put]=0;
+		  }
+		}
+		upRhs = effectiveRhs[k];
+		loRhs = ((rowFlag[k]&1)!=0) ? effectiveRhs[k] : -1.0e30;
+		tolerance = CoinMax(1.0e-5,fabs(upRhs)*1.0e-10);
+		for (int j0=0;j0<2;j0++) {
+		  for (int j1=0;j1<2;j1++) {
+		    double value = element1[0]*j0+element1[1]*j1;
+		    int put = j0+2*j1;
+		    if (value<upRhs+tolerance&&value>loRhs-tolerance)
+		      allowed1[put]=1;
+		    else
+		      allowed1[put]=0;
+		  }
+		}
+		/* interesting cases are when -
+		   one forces fixing (but probably found in probing)
+		   and of two is zero
+		   and of two forces fixing
+		   two same - this is probably only one
+		*/
+		int intersect[4];
+		bool same=true;
+		bool tighter0=true;
+		bool tighter1=true;
+		bool feasible=false;
+		bool redundant=true;
+		for (int j=0;j<4;j++) {
+		  intersect[j]=allowed0[j]&allowed1[j];
+		  if (intersect[j]<allowed0[j])
+		    tighter0=false;
+		  if (intersect[j]<allowed1[j])
+		    tighter1=false;
+		  if (allowed0[j]!=allowed1[j])
+		    same=false;
+		  if (!intersect[j])
+		    redundant=false;
+		  if (intersect[j])
+		    feasible=true;
+		}
+		int fixed[2]={0,0};
+		if (feasible) {
+		  int count=2;
+		  for (int jj=0;jj<count;jj++) {
+		    int multiplier=1<<jj;
+		    int increment=1<<(count-1-jj);
+		    bool zeroOk=false;
+		    bool oneOk=false;
+		    for (int j=0;j<(1<<(count-1));j++) {
+		      if (intersect[0*multiplier+increment*j])
+			zeroOk=true;
+		      if (intersect[1*multiplier+increment*j])
+			oneOk=true;
+		    }
+		    if (!zeroOk) {
+		      fixed[jj]=1;
+		      assert (oneOk);
+		    } else if (!oneOk) {
+		      fixed[jj]=-1;
+		    }
+		  }
+		}
+		if (same||redundant||!feasible||fixed[0]||fixed[1]||
+		    tighter0||tighter1) {
+#ifdef CGL_INVESTIGATE
+		  /* start debug print */
+		  {
+		    printf("Base %d (orig %d) ",i,originalRows[i]);
+		    for (int j=0;j<n;j++) {
+		      double value = element0[j];
+		      if (j) {
+			if(value>0.0)
+			  printf(" +");
+			else
+			  printf(" ");
+		      }
+		      int iColumn=column0[j];
+		      if ((columnFlag[iColumn]&2)==0)
+			printf("%g*X%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		      else if ((columnFlag[iColumn]&(2+4))==2)
+			printf("%g*B%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		      else
+			printf("%g*I%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		    } 
+		    if ((rowFlag[i]&1)!=0)
+		      printf(" == ");
+		    else
+		      printf(" <= ");
+		    printf("%g\n",effectiveRhs[i]);
+		    printf("Comp %d (orig %d) ",k,originalRows[k]);
+		    for (int j=0;j<n1;j++) {
+		      double value = element1[j];
+		      if (j) {
+			if(value>0.0)
+			  printf(" +");
+			else
+			  printf(" ");
+		      }
+		      int iColumn=column1[j];
+		      if ((columnFlag[iColumn]&2)==0)
+			printf("%g*X%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		      else if ((columnFlag[iColumn]&(2+4))==2)
+			printf("%g*B%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		      else
+			printf("%g*I%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		    } 
+		    if ((rowFlag[k]&1)!=0)
+		      printf(" == ");
+		    else
+		      printf(" <= ");
+		    printf("%g\n",effectiveRhs[k]);
+		  }
+		  /* end debug print */
+#endif
+#ifdef CGL_INVESTIGATE
+		  printf("**same %c redundant %c feasible %c tight %c,%c fixed %d,%d\n",
+			 same ? 'Y' : 'N',
+			 redundant ? 'Y' : 'N',
+			 feasible ? 'Y' : 'N',
+			 tighter0 ? 'Y' : 'N',
+			 tighter1 ? 'Y' : 'N',
+			 fixed[0],fixed[1]);
+#endif
+		  if (!feasible) {
+#ifdef CGL_INVESTIGATE
+		    printf("QQ infeasible\n");
+#endif
+		    infeasible=true;
+		  } else if (fixed[0]||fixed[1]) {
+#ifdef CGL_INVESTIGATE
+		    printf("QQ fixed\n");
+#endif
+		    for (int k=0;k<2;k++) {
+		      if (fixed[k]) {
+			int iColumn=column0[k];
+			int kColumn=originalColumns[iColumn];
+#ifdef CGL_INVESTIGATE
+			printf("true bounds %g %g\n",columnLower[kColumn],
+			       columnUpper[kColumn]);
+#endif
+			double lo;
+			if (fixed[k]>0) {
+			  lo=1.0;
+			} else {
+			  lo=0.0;
+			}
+			if ((columnFlag[iColumn]&1)==0) {
+			  columnFlag[iColumn] |= 16;
+			  trueLower[iColumn] += lo;
+			  newBound[iColumn] = 0.0;
+			  for (int jj=columnStart[iColumn];jj<columnStart[iColumn+1];
+			       jj++) {
+			    int iRow=row[jj];
+			    effectiveRhs[iRow] -= lo*element[jj];
+			  }
+			} else {
+			  abort();
+			}
+		      }
+		    }
+		  } else if (!same&&(tighter0||tighter1)) {
+		    assert (!tighter0||!tighter1);
+		    if (tighter0) {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ discard oneT k\n");
+#endif
+		      duplicate_[k]=-2;
+		    } else {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ discard oneT i\n");
+#endif
+		      duplicate_[i]=-2;
+		    }
+		  } else if (redundant) {
+#ifdef CGL_INVESTIGATE
+		    printf("QQ discard both\n");
+#endif
+		    duplicate_[i]=-2;
+		    duplicate_[k]=-2;
+		  } else {
+		    assert (same);
+		    if (fabs(effectiveRhs[i]-effectiveRhs[k])<1.0e-7&&
+			element0[1]==element1[1]&&
+			element0[0]==element1[0]) {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ discard identical k I2\n");
+#endif
+		      duplicate_[k]=-2;
+		    } else {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ Don't know what to do nintI==2 I\n");
+#endif
+		    }
+		  }
+		}
+	      } else {
+		assert (nInt==3);
+		double upRhs = effectiveRhs[i];
+		double loRhs = ((rowFlag[i]&1)!=0) ? effectiveRhs[i] : -1.0e30;
+		double tolerance = CoinMax(1.0e-5,fabs(upRhs)*1.0e-10);
+		for (int j0=0;j0<2;j0++) {
+		  for (int j1=0;j1<2;j1++) {
+		    for (int j2=0;j2<2;j2++) {
+		      double value = element0[0]*j0+element0[1]*j1
+			+element0[2]*j2;
+		      int put = j0+2*j1+4*j2;
+		      if (value<upRhs+tolerance&&value>loRhs-tolerance)
+			allowed0[put]=1;
+		      else
+			allowed0[put]=0;
+		    }
+		  }
+		}
+		upRhs = effectiveRhs[k];
+		loRhs = ((rowFlag[k]&1)!=0) ? effectiveRhs[k] : -1.0e30;
+		tolerance = CoinMax(1.0e-5,fabs(upRhs)*1.0e-10);
+		for (int j0=0;j0<2;j0++) {
+		  for (int j1=0;j1<2;j1++) {
+		    for (int j2=0;j2<2;j2++) {
+		      double value = element1[0]*j0+element1[1]*j1
+			+element1[2]*j2;
+		      int put = j0+2*j1+4*j2;
+		      if (value<upRhs+tolerance&&value>loRhs-tolerance)
+			allowed1[put]=1;
+		      else
+			allowed1[put]=0;
+		    }
+		  }
+		}
+		/* interesting cases are when -
+		   one forces fixing (but probably found in probing)
+		   and of two is zero
+		   and of two forces fixing
+		   two same - this is probably only one
+		*/
+		int intersect[8];
+		bool same=true;
+		bool tighter0=true;
+		bool tighter1=true;
+		bool feasible=false;
+		bool redundant=true;
+		for (int j=0;j<8;j++) {
+		  intersect[j]=allowed0[j]&allowed1[j];
+		  if (intersect[j]<allowed0[j])
+		    tighter0=false;
+		  if (intersect[j]<allowed1[j])
+		    tighter1=false;
+		  if (allowed0[j]!=allowed1[j])
+		    same=false;
+		  if (!intersect[j])
+		    redundant=false;
+		  if (intersect[j])
+		    feasible=true;
+		}
+		int fixed[3]={0,0,0};
+		if (feasible) {
+		  bool zeroOk[3]={false,false,false};
+		  bool oneOk[3]={false,false,false};
+		  for (int j0=0;j0<2;j0++) {
+		    for (int j1=0;j1<2;j1++) {
+		      for (int j2=0;j2<2;j2++) {
+			int get = j0+2*j1+4*j2;
+			if (intersect[get]) {
+			  if (j0)
+			    oneOk[0]=true;
+			  else
+			    zeroOk[0]=true;
+			  if (j1)
+			    oneOk[1]=true;
+			  else
+			    zeroOk[1]=true;
+			  if (j2)
+			    oneOk[2]=true;
+			  else
+			    zeroOk[2]=true;
+			}
+		      }
+		    }
+		  }
+		  for (int jj=0;jj<3;jj++) {
+		    if (!zeroOk[jj]) {
+		      fixed[jj]=1;
+		      assert (oneOk[jj]);
+		    } else if (!oneOk[jj]) {
+		      fixed[jj]=-1;
+		    }
+		  }
+		}
+		if (same||redundant||!feasible||fixed[0]||fixed[1]||fixed[2]||
+		    tighter0||tighter1) {
+#ifdef CGL_INVESTIGATE
+		  /* start debug print */
+		  {
+		    printf("Base %d (orig %d) ",i,originalRows[i]);
+		    for (int j=0;j<n;j++) {
+		      double value = element0[j];
+		      if (j) {
+			if(value>0.0)
+			  printf(" +");
+			else
+			  printf(" ");
+		      }
+		      int iColumn=column0[j];
+		      if ((columnFlag[iColumn]&2)==0)
+			printf("%g*X%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		      else if ((columnFlag[iColumn]&(2+4))==2)
+			printf("%g*B%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		      else
+			printf("%g*I%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		    } 
+		    if ((rowFlag[i]&1)!=0)
+		      printf(" == ");
+		    else
+		      printf(" <= ");
+		    printf("%g\n",effectiveRhs[i]);
+		    printf("Comp %d (orig %d) ",k,originalRows[k]);
+		    for (int j=0;j<n1;j++) {
+		      double value = element1[j];
+		      if (j) {
+			if(value>0.0)
+			  printf(" +");
+			else
+			  printf(" ");
+		      }
+		      int iColumn=column1[j];
+		      if ((columnFlag[iColumn]&2)==0)
+			printf("%g*X%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		      else if ((columnFlag[iColumn]&(2+4))==2)
+			printf("%g*B%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		      else
+			printf("%g*I%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		    } 
+		    if ((rowFlag[k]&1)!=0)
+		      printf(" == ");
+		    else
+		      printf(" <= ");
+		    printf("%g\n",effectiveRhs[k]);
+		  }
+		  /* end debug print */
+#endif
+#ifdef CGL_INVESTIGATE
+		  printf("**same3 %c redundant %c feasible %c tight %c,%c fixed %d,%d,%d\n",
+			 same ? 'Y' : 'N',
+			 redundant ? 'Y' : 'N',
+			 feasible ? 'Y' : 'N',
+			 tighter0 ? 'Y' : 'N',
+			 tighter1 ? 'Y' : 'N',
+			 fixed[0],fixed[1],fixed[2]);
+#endif
+		  if (!feasible) {
+#ifdef CGL_INVESTIGATE
+		    printf("QQ infeasible\n");
+#endif
+		    infeasible=true;
+		  } else if (fixed[0]||fixed[1]||fixed[2]) {
+#ifdef CGL_INVESTIGATE
+		    printf("QQ fixed\n");
+#endif
+		    for (int k=0;k<3;k++) {
+		      if (fixed[k]) {
+			int iColumn=column0[k];
+			int kColumn=originalColumns[iColumn];
+#ifdef CGL_INVESTIGATE
+			printf("true bounds %g %g\n",columnLower[kColumn],
+			       columnUpper[kColumn]);
+#endif
+			double lo;
+			if (fixed[k]>0) {
+			  lo=1.0;
+			} else {
+			  lo=0.0;
+			}
+			if ((columnFlag[iColumn]&1)==0) {
+			  columnFlag[iColumn] |= 16;
+			  trueLower[iColumn] += lo;
+			  newBound[iColumn] = 0.0;
+			  for (int jj=columnStart[iColumn];jj<columnStart[iColumn+1];
+			       jj++) {
+			    int iRow=row[jj];
+			    effectiveRhs[iRow] -= lo*element[jj];
+			  }
+			} else {
+			  abort();
+			}
+		      }
+		    }
+		  } else if (!same&&(tighter0||tighter1)) {
+		    assert (!tighter0||!tighter1);
+		    if (tighter0) {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ discard oneT k\n");
+#endif
+		      duplicate_[k]=-2;
+		    } else {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ discard oneT i\n");
+#endif
+		      duplicate_[i]=-2;
+		    }
+		  } else if (redundant) {
+#ifdef CGL_INVESTIGATE
+		    printf("QQ discard both\n");
+#endif
+		    duplicate_[i]=-2;
+		    duplicate_[k]=-2;
+		  } else {
+		    assert (same);
+		    if (fabs(effectiveRhs[i]-effectiveRhs[k])<1.0e-7&&
+			element0[2]==element1[2]&&
+			element0[1]==element1[1]&&
+			element0[0]==element1[0]) {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ discard identical k I\n");
+#endif
+		      duplicate_[k]=-2;
+		    } else {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ Don't know what to do nintI==3 I\n");
+#endif
+		    }
+		  }
+		}
+	      }
+	    } else {
+	      // one other - put last
+	      double el0[3];
+	      double el1[3];
+	      int col[3];
+	      double bound=0.0;
+	      int kk=0;
+	      el0[1]=0.0;
+	      el1[1]=0.0;
+	      for (int j=0;j<n;j++) {
+		int iColumn=column0[j];
+		if ((columnFlag[iColumn]&(2+4))==2) {
+		  el0[kk]=element0[j];
+		  col[kk++]=iColumn;
+		} else {
+		  el0[2]=element0[j];
+		  col[2]=iColumn;
+		  bound=CoinMin(newBound[iColumn],1.0e30);
+		}
+	      }
+	      kk=0;
+	      for (int j=0;j<n;j++) {
+		int iColumn=column1[j];
+		if ((columnFlag[iColumn]&(2+4))==2) {
+		  el1[kk++]=element1[j];
+		} else {
+		  el1[2]=element1[j];
+		}
+	      }
+	      double gap0=bound*el0[2];
+	      double gap1=bound*el1[2];
+	      for (kk=0;kk<4;kk++) {
+		loC0[kk]=0.0;
+		loC1[kk]=0.0;
+		upC0[kk]=bound;
+		upC1[kk]=bound;
+	      }
+	      // crude - should go stack based
+	      double upRhs = effectiveRhs[i];
+	      double loRhs = ((rowFlag[i]&1)!=0) ? effectiveRhs[i] : -1.0e30;
+	      double tolerance = CoinMax(1.0e-5,fabs(upRhs)*1.0e-10);
+	      for (int j0=0;j0<2;j0++) {
+		for (int j1=0;j1<2;j1++) {
+		  double value = el0[0]*j0+el0[1]*j1;
+		  int put = j0+2*j1;
+		  double valueLo,valueHi;
+		  if (gap0>0.0) {
+		    valueLo=value;
+		    valueHi=value+gap0;
+		  } else {
+		    valueLo=value+gap0;
+		    valueHi=value;
+		  }
+		  if (valueLo<upRhs+tolerance&&valueHi>loRhs-tolerance)
+		    allowed0[put]=1;
+		  else
+		    allowed0[put]=0;
+		  if (valueLo<loRhs-tolerance) {
+		    if (gap0>0.0) {
+		      loC0[put]=(loRhs-valueLo)/el0[2];
+		    } else {
+		      upC0[put]=bound-((valueLo-loRhs)/el0[2]);
+		    }
+		  }
+		  if (valueHi>upRhs+tolerance) {
+		    if (gap0>0.0) {
+		      upC0[put]=bound-((valueHi-upRhs)/el0[2]);
+		    } else {
+		      loC0[put]=(upRhs-valueHi)/el0[2];
+		    }
+		  }
+		}
+	      }
+	      upRhs = effectiveRhs[k];
+	      loRhs = ((rowFlag[k]&1)!=0) ? effectiveRhs[k] : -1.0e30;
+	      tolerance = CoinMax(1.0e-5,fabs(upRhs)*1.0e-10);
+	      for (int j0=0;j0<2;j0++) {
+		for (int j1=0;j1<2;j1++) {
+		  double value = el1[0]*j0+el1[1]*j1;
+		  int put = j0+2*j1;
+		  double valueLo,valueHi;
+		  if (gap1>0.0) {
+		    valueLo=value;
+		    valueHi=value+gap1;
+		  } else {
+		    valueLo=value+gap1;
+		    valueHi=value;
+		  }
+		  if (valueLo<upRhs+tolerance&&valueHi>loRhs-tolerance)
+		    allowed1[put]=1;
+		  else
+		    allowed1[put]=0;
+		  if (valueLo<loRhs-tolerance) {
+		    if (gap1>0.0) {
+		      loC1[put]=(loRhs-valueLo)/el1[2];
+		    } else {
+		      upC1[put]=bound-((valueLo-loRhs)/el1[2]);
+		    }
+		  }
+		  if (valueHi>upRhs+tolerance) {
+		    if (gap1>0.0) {
+		      upC1[put]=bound-((valueHi-upRhs)/el1[2]);
+		    } else {
+		      loC1[put]=(upRhs-valueHi)/el1[2];
+		    }
+		  }
+		}
+	      }
+	      /* interesting cases are when -
+		 one forces fixing (but probably found in probing)
+		 and of two is zero
+		 and of two forces fixing
+		 two same - this is probably only one
+	      */
+	      int intersect[4];
+	      bool same=true;
+	      bool tighter0=true;
+	      bool tighter1=true;
+	      bool feasible=false;
+	      bool redundant=true;
+	      int count=nInt;
+	      for (int j=0;j<(1<<count);j++) {
+		intersect[j]=allowed0[j]&allowed1[j];
+		if (intersect[j]<allowed0[j])
+		  tighter0=false;
+		if (intersect[j]<allowed1[j])
+		  tighter1=false;
+		if (allowed0[j]!=allowed1[j])
+		  same=false;
+		if (!intersect[j])
+		  redundant=false;
+		if (intersect[j])
+		  feasible=true;
+	      }
+	      int fixed[2]={0,0};
+	      if (feasible) {
+		for (int jj=0;jj<count;jj++) {
+		  int multiplier=1<<jj;
+		  int increment=1<<(count-1-jj);
+		  bool zeroOk=false;
+		  bool oneOk=false;
+		  for (int j=0;j<(1<<(count-1));j++) {
+		    if (intersect[0*multiplier+increment*j])
+		      zeroOk=true;
+		    if (intersect[1*multiplier+increment*j])
+		      oneOk=true;
+		  }
+		  if (!zeroOk) {
+		    fixed[jj]=1;
+		    assert (oneOk);
+		  } else if (!oneOk) {
+		    fixed[jj]=-1;
+		  }
+		}
+	      }
+	      double newLo=bound;
+	      double newUp=0.0;
+	      if (nInt==1) {
+		for (int jj=0;jj<2;jj++) {
+#ifdef CGL_INVESTIGATE
+		  printf("int at %d -> lo0 %g lo1 %g up0 %g up1 %g",
+			 jj,loC0[jj],loC1[jj],upC0[jj],upC1[jj]);
+#endif
+		  if (intersect[jj]) {
+#ifdef CGL_INVESTIGATE
+		    printf("\n");
+#endif
+		    newLo=CoinMin(newLo,CoinMax(loC0[jj],loC1[jj]));
+		    newUp=CoinMax(newUp,CoinMin(upC0[jj],upC1[jj]));
+		  } else {
+#ifdef CGL_INVESTIGATE
+		    printf(" INF\n");
+#endif
+		    loC0[jj]=0.0;
+		    loC1[jj]=0.0;
+		    upC0[jj]=bound;
+		    upC1[jj]=bound;
+		  }
+		}
+	      } else {
+		for (int jj=0;jj<2;jj++) { 
+		  for (int jj1=0;jj1<2;jj1++) {
+		    int k=jj+2*jj1;
+#ifdef CGL_INVESTIGATE
+		    printf("first int at %d, second at %d -> lo0 %g lo1 %g up0 %g up1 %g",
+			   jj,jj1,loC0[k],loC1[k],upC0[k],upC1[k]);
+#endif
+		    if (intersect[k]) {
+#ifdef CGL_INVESTIGATE
+		      printf("\n");
+#endif
+		      newLo=CoinMin(newLo,CoinMax(loC0[k],loC1[k]));
+		      newUp=CoinMax(newUp,CoinMin(upC0[k],upC1[k]));
+		    } else {
+#ifdef CGL_INVESTIGATE
+		      printf(" INF\n");
+#endif
+		      loC0[k]=0.0;
+		      loC1[k]=0.0;
+		      upC0[k]=bound;
+		      upC1[k]=bound;
+		    }
+		  }
+		}
+	      }
+	      if (newLo>0.0||newUp<bound) {
+#ifdef CGL_INVESTIGATE
+		printf("Can tighten bounds to %g,%g\n",newLo,newUp);
+#endif
+		int iColumn=col[2];
+		int kColumn=originalColumns[iColumn];
+#ifdef CGL_INVESTIGATE
+		printf("true bounds %g %g\n",columnLower[kColumn],
+		       columnUpper[kColumn]);
+#endif
+		if ((columnFlag[iColumn]&1)==0) {
+		  columnFlag[iColumn] |= 16;
+		  trueLower[iColumn] += newLo;
+		  newBound[iColumn] = newUp-newLo;
+		  for (int jj=columnStart[iColumn];jj<columnStart[iColumn+1];
+		       jj++) {
+		    int iRow=row[jj];
+		    effectiveRhs[iRow] -= newLo*element[jj];
+		  }
+		} else {
+		  abort();
+		}
+	      }
+	      for (int jj=0;jj<(1<<nInt);jj++) {
+		loC0[jj]=CoinMax(loC0[jj],newLo);
+		loC1[jj]=CoinMax(loC1[jj],newLo);
+		upC0[jj]=CoinMin(upC0[jj],newUp);
+		upC1[jj]=CoinMin(upC1[jj],newUp);
+	      }
+	      for (int jj=0;jj<(1<<nInt);jj++) {
+		if (fabs(loC0[jj]-loC1[jj])>1.0e-8)
+		  same=false;
+		if (fabs(upC0[jj]-upC1[jj])>1.0e-8)
+		  same=false;
+		if (loC0[jj]<loC1[jj]-1.0e-12||
+		    upC0[jj]>upC1[jj]+1.0e-12) {
+		  tighter0=false;
+		  redundant=false;
+		}
+		if (loC1[jj]<loC0[jj]-1.0e-12||
+		    upC1[jj]>upC0[jj]+1.0e-12) {
+		  tighter1=false;
+		  redundant=false;
+		}
+		if (fabs(newLo-loC0[jj])>1.0e-12)
+		  redundant=false;
+		if (fabs(newLo-loC1[jj])>1.0e-12)
+		  redundant=false;
+		if (fabs(newUp-upC0[jj])>1.0e-12)
+		  redundant=false;
+		if (fabs(newUp-upC1[jj])>1.0e-12)
+		  redundant=false;
+	      }
+	      if (same||redundant||!feasible||fixed[0]||fixed[1]||
+		  tighter0||tighter1) {
+#ifdef CGL_INVESTIGATE
+		/* start debug print */
+		{
+		  printf("Base %d (orig %d) ",i,originalRows[i]);
+		  for (int j=0;j<n;j++) {
+		    double value = element0[j];
+		    if (j) {
+		      if(value>0.0)
+			printf(" +");
+		      else
+			printf(" ");
+		    }
+		    int iColumn=column0[j];
+		    if ((columnFlag[iColumn]&2)==0)
+		      printf("%g*X%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		    else if ((columnFlag[iColumn]&(2+4))==2)
+		      printf("%g*B%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		    else
+		      printf("%g*I%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		  } 
+		  if ((rowFlag[i]&1)!=0)
+		    printf(" == ");
+		  else
+		    printf(" <= ");
+		  printf("%g\n",effectiveRhs[i]);
+		  printf("Comp %d (orig %d) ",k,originalRows[k]);
+		  for (int j=0;j<n1;j++) {
+		    double value = element1[j];
+		    if (j) {
+		      if(value>0.0)
+			printf(" +");
+		      else
+			printf(" ");
+		    }
+		    int iColumn=column1[j];
+		    if ((columnFlag[iColumn]&2)==0)
+		      printf("%g*X%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		    else if ((columnFlag[iColumn]&(2+4))==2)
+		      printf("%g*B%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		    else
+		      printf("%g*I%d(%d) (<=%g)",value,iColumn,originalColumns[iColumn],newBound[iColumn]);
+		  } 
+		  if ((rowFlag[k]&1)!=0)
+		    printf(" == ");
+		  else
+		    printf(" <= ");
+		  printf("%g\n",effectiveRhs[k]);
+		}
+		/* end debug print */
+#endif
+#ifdef CGL_INVESTIGATE
+		printf("**same %c redundant %c feasible %c tight %c,%c fixed %d,%d\n",
+		       same ? 'Y' : 'N',
+		       redundant ? 'Y' : 'N',
+		       feasible ? 'Y' : 'N',
+		       tighter0 ? 'Y' : 'N',
+		       tighter1 ? 'Y' : 'N',
+		       fixed[0],fixed[1]);
+#endif
+		//if (nInt>1)
+		//continue;
+		if (!feasible) {
+#ifdef CGL_INVESTIGATE
+		  printf("QQ infeasible\n");
+#endif
+		  infeasible=true;
+		} else if (fixed[0]||fixed[1]) {
+#ifdef CGL_INVESTIGATE
+		  printf("QQ fixed\n");
+#endif
+		  for (int k=0;k<2;k++) {
+		    if (fixed[k]) {
+		      int iColumn=col[k];
+		      int kColumn=originalColumns[iColumn];
+#ifdef CGL_INVESTIGATE
+		      printf("true bounds %g %g\n",columnLower[kColumn],
+			     columnUpper[kColumn]);
+#endif
+		      double lo;
+		      if (fixed[k]>0) {
+			lo=1.0;
+		      } else {
+			lo=0.0;
+		      }
+		      if ((columnFlag[iColumn]&1)==0) {
+			columnFlag[iColumn] |= 16;
+			trueLower[iColumn] += lo;
+			newBound[iColumn] = 0.0;
+			for (int jj=columnStart[iColumn];jj<columnStart[iColumn+1];
+			     jj++) {
+			  int iRow=row[jj];
+			  effectiveRhs[iRow] -= lo*element[jj];
+			}
+		      } else {
+			abort();
+		      }
+		    }
+		  }
+		} else if (!same&&(tighter0||tighter1)) {
+		  assert (!tighter0||!tighter1);
+		  if (tighter0) {
+#ifdef CGL_INVESTIGATE
+		    printf("QQ discard oneT k\n");
+#endif
+		    duplicate_[k]=-2;
+		  } else {
+#ifdef CGL_INVESTIGATE
+		    printf("QQ discard oneT i\n");
+#endif
+		    duplicate_[i]=-2;
+		  }
+		} else if (redundant) {
+#ifdef CGL_INVESTIGATE
+		  printf("QQ discard both\n");
+#endif
+		  duplicate_[i]=-2;
+		  duplicate_[k]=-2;
+		} else {
+		  assert (same);
+		  if (fabs(effectiveRhs[i]-effectiveRhs[k])<1.0e-7&&
+		      el0[2]==el1[2]&&
+		      el0[0]==el1[0]) {
+		    if (nInt==1||el0[1]==el1[1]) {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ discard identical k\n");
+#endif
+		      duplicate_[k]=-2;
+		    }
+		  }
+		  if (duplicate_[k]!=-2) {
+		    if (nInt==1) {
+		      // one may be stronger
+		      if (el0[2]>0.0&&el1[2]>0.0&&
+			  el0[0]>0.0&&el1[0]>0.0&&
+			  (rowFlag[k]&1)==0&&
+			  (rowFlag[i]&1)==0) {
+			// bounds same at 0 and 1
+			double up0 = (effectiveRhs[i]-el0[0])/el0[2];
+			double up1 = (effectiveRhs[k]-el1[0])/el1[2];
+			if (up0<up1) {
+#ifdef CGL_INVESTIGATE
+			  printf("QQ discard oneS k\n");
+#endif
+			  duplicate_[k]=-2;
+			} else {
+#ifdef CGL_INVESTIGATE
+			  printf("QQ discard oneS i\n");
+#endif
+			  duplicate_[i]=-2;
+			}
+		      } else {
+			if ((rowFlag[k]&1)==0&&(rowFlag[i]&1)==0) {
+			  int which=0;
+			  for (int i0=0;i<=10;i++) {
+			    double value0=0.05*i0;
+			    double rhs0 =effectiveRhs[i]-el0[0]*value0;
+			    double lo0=0.0;
+			    double up0=1.0e30;
+			    double bound0=rhs0/el0[2];
+			    if (el0[2]>0.0) 
+			      up0=bound0;
+			    else
+			      lo0=CoinMax(0.0,bound0);
+			    double rhs1 =effectiveRhs[k]-el1[0]*value0;
+			    double lo1=0.0;
+			    double up1=1.0e30;
+			    double bound1=rhs1/el1[2];
+			    if (el1[2]>0.0) 
+			      up1=bound1;
+			    else
+			      lo1=CoinMax(0.0,bound1);
+			    if (fabs(lo0-lo1)>1.0e-8||
+				fabs(up0-up1)>1.0e-8*(1.0+fabs(up1))) {
+			      if (lo0>lo1+1.0e-8) {
+				if (up0<up1-1.0e-8) {
+				  // 0 tighter
+				  if (which==1) {
+				    which=-2;
+				    break;
+				  } else {
+				    which=-1;
+				  }
+				} else if (up0>up1+1.0e-8) {
+				  which=-2;
+				  break;
+				}
+			      } else if (lo0<lo1-1.0e-8) {
+				if (up1<up0-1.0e-8) {
+				  // 1 tighter
+				  if (which==-1) {
+				    which=-2;
+				    break;
+				  } else {
+				    which=1;
+				  }
+				} else if (up1>up0+1.0e-8) {
+				  which=-2;
+				  break;
+				}
+			      } else {
+				if (up1<up0-1.0e-8) {
+				  // 1 tighter
+				  if (which==-1) {
+				    which=-2;
+				    break;
+				  } else {
+				    which=1;
+				  }
+				} else if (up1>up0+1.0e-8) {
+				  // 0 tighter
+				  if (which==1) {
+				    which=-2;
+				    break;
+				  } else {
+				    which=-1;
+				  }
+				}
+			      }
+			    }
+			  }
+			  if (which==0) {
+			    duplicate_[k]=-2;
+#ifdef CGL_INVESTIGATE
+			  printf("QQ discard one same same k\n");
+#endif
+			  } else if (which==-1) {
+			    duplicate_[k]=-2;
+#ifdef CGL_INVESTIGATE
+			  printf("QQ discard one (i tighter) k\n");
+#endif
+			  } else if (which==1) {
+			    duplicate_[i]=-2;
+#ifdef CGL_INVESTIGATE
+			  printf("QQ discard one (k tighter) i\n");
+#endif
+			  } else {
+			    printf("QQ Can't decide what to do nint==1\n");
+			  }
+			} else {
+			  printf("QQ Don't know what to do nint==1\n");
+			}
+		      }
+		    } else {
+		      if ((rowFlag[k]&1)==0&&(rowFlag[i]&1)==0) {
+			int which=0;
+			for (int i0=0;i0<=10;i0++) {
+			  double value0=0.05*i0;
+			  for (int i1=0;i1<=10;i1++) {
+			    double value1=0.05*i1;
+			    double rhs0 =effectiveRhs[i]-el0[0]*value0
+			      -el0[1]*value1;
+			    double lo0=0.0;
+			    double up0=1.0e30;
+			    double bound0=rhs0/el0[2];
+			    if (el0[2]>0.0) 
+			      up0=bound0;
+			    else
+			      lo0=CoinMax(0.0,bound0);
+			    double rhs1 =effectiveRhs[k]-el1[0]*value0
+			      -el1[1]*value1;
+			    double lo1=0.0;
+			    double up1=1.0e30;
+			    double bound1=rhs1/el1[2];
+			    if (el1[2]>0.0) 
+			      up1=bound1;
+			    else
+			      lo1=CoinMax(0.0,bound1);
+			    if (fabs(lo0-lo1)>1.0e-8||
+				fabs(up0-up1)>1.0e-8*(1.0+fabs(up1))) {
+			      if (lo0>lo1+1.0e-8) {
+				if (up0<up1-1.0e-8) {
+				  // 0 tighter
+				  if (which==1) {
+				    which=-2;
+				    break;
+				  } else {
+				    which=-1;
+				  }
+				} else if (up0>up1+1.0e-8) {
+				  which=-2;
+				  break;
+				}
+			      } else if (lo0<lo1-1.0e-8) {
+				if (up1<up0-1.0e-8) {
+				  // 1 tighter
+				  if (which==-1) {
+				    which=-2;
+				    break;
+				  } else {
+				    which=1;
+				  }
+				} else if (up1>up0+1.0e-8) {
+				  which=-2;
+				  break;
+				}
+			      } else {
+				if (up1<up0-1.0e-8) {
+				  // 1 tighter
+				  if (which==-1) {
+				    which=-2;
+				    break;
+				  } else {
+				    which=1;
+				  }
+				} else if (up1>up0+1.0e-8) {
+				  // 0 tighter
+				  if (which==1) {
+				    which=-2;
+				    break;
+				  } else {
+				    which=-1;
+				  }
+				}
+			      }
+			    }
+			  }
+			  if (which==-2)
+			    break;
+			}
+			if (which==0) {
+			  duplicate_[k]=-2;
+#ifdef CGL_INVESTIGATE
+			  printf("QQ discard one same same k\n");
+#endif
+			} else if (which==-1) {
+			  duplicate_[k]=-2;
+#ifdef CGL_INVESTIGATE
+			  printf("QQ discard one (i tighter) k\n");
+#endif
+			} else if (which==1) {
+			  duplicate_[i]=-2;
+#ifdef CGL_INVESTIGATE
+			  printf("QQ discard one (k tighter) i\n");
+#endif
+			} else {
+			  printf("QQ Can't decide what to do nint==2\n");
+			}
+		      } else {
+#ifdef CGL_INVESTIGATE
+		      printf("QQ Don't know what to do nint==2\n");
+#endif
+		      }
+		    }
+		  }
+		}
+	      }
+	    }	      
+	  }
+	}
+      }
+      for (int j=0;j<n;j++) 
+	mark[column0[j]] =0;
+    }
+  }
+  if (0) {
+    // Column copy
+    const double * element = matrix_.getElements();
+    const int * row = matrix_.getIndices();
+    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
+    //const int * columnLength = matrix_.getVectorLengths();
+    // Row copy
+    const double * elementByRow = matrixByRow_.getElements();
+    const int * column = matrixByRow_.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+    //const int * rowLength = matrixByRow_.getVectorLengths();
+    for (int i=1231;i<1235;i++) {
+      for (int jj=columnStart[i];jj<columnStart[i+1];
+	   jj++) {
+	int iRow=row[jj];
+	printf("row %d el %g\n",iRow,element[jj]);
+      }
+    }
+    for (int i=283;i<284;i++) {
+      for (int jj=rowStart[i];jj<rowStart[i+1];
+	   jj++) {
+	printf("col %d el %g\n",column[jj],elementByRow[jj]);
+      }
+    }
+    printf("OK?\n");
+  }
+  // See if any fixed
+  CoinPackedVector lbs;
+  CoinPackedVector ubs;
+  //OsiSolverInterface * xx = si.clone();
+  for (int i=0;i<nCol2;i++) {
+    if ((columnFlag[i]&16)!=0) {
+      assert ((columnFlag[i]&1)==0);
+      int kColumn=originalColumns[i];
+      double lower=trueLower[i];
+      double upper=lower+newBound[i];
+      if (fabs(lower-floor(lower+0.5))<1.0e-8) 
+	lower=floor(lower+0.5);
+      if (fabs(upper-floor(upper+0.5))<1.0e-8) 
+	upper=floor(upper+0.5);
+      if ((columnFlag[i]&2)==0) {
+	// continuous
+	if (lower>columnLower[kColumn]+1.0e-7) {
+	  nFixed++;
+	  lbs.insert(kColumn,lower);
+	  //xx->setColLower(kColumn,lower);
+	}
+	if (upper<columnUpper[kColumn]-1.0e-7) {
+	  nFixed++;
+	  ubs.insert(kColumn,upper);
+	  //xx->setColUpper(kColumn,upper);
+	}
+      } else {
+	// integer
+	if (lower>columnLower[kColumn]+1.0e-7) {
+	  nFixed++;
+	  lower = ceil(lower);
+	  //xx->setColLower(kColumn,lower);
+	  lbs.insert(kColumn,lower);
+	}
+	if (upper<columnUpper[kColumn]-1.0e-7) {
+	  upper=floor(upper);
+	  nFixed++;
+	  //xx->setColUpper(kColumn,upper);
+	  ubs.insert(kColumn,upper);
+	}
+      }
+      if (lower>upper+1.0e-7)
+	infeasible=true;
+      //printf("Bounds for %d are %g and %g, were %g %g\n",
+      //     kColumn,
+      //     xx->getColLower()[kColumn],
+      //     xx->getColUpper()[kColumn],
+      //     si.getColLower()[kColumn],
+      //     si.getColUpper()[kColumn]);
+    }
+  }
+  //if (!infeasible) {
+  //si.writeMps("si");
+  //xx->writeMps("xx");
+  //xx->resolve();
+  //assert (xx->isProvenOptimal());
+  //printf("obj value %g %g\n",si.getObjValue(),xx->getObjValue());
+  //}
+  //delete xx;
+  // Move duplicate flags
+  int * temp = reinterpret_cast<int *>(effectiveRhs);
+  for (int i=0;i<numberRows;i++)
+    temp[i]=-1;
+  for (int i=0;i<nRow2;i++)
+    temp[originalRows[i]]=duplicate_[i];
+  memcpy(duplicate_,temp,numberRows*sizeof(int));
+  delete [] effectiveRhs;
+  delete [] newBound;
+  delete [] trueLower;
+  delete [] rowFlag;
+  delete [] columnFlag;
+  delete [] originalColumns;
+  delete [] originalRows;
+  if (nFixed) {
+#ifdef CGL_INVESTIGATE
+    printf("QQ - %d bounds changed\n",nFixed);
+#endif
+    OsiColCut cc;
+    cc.setLbs(lbs);
+    cc.setUbs(ubs);
+    cc.setEffectiveness(100.0);
+    cs.insert(cc);
+  }
+  if (infeasible) {
+    // generate infeasible cut and return
+    printf("QQ**** infeasible cut\n");
+    OsiRowCut rc;
+    rc.setLb(COIN_DBL_MAX);
+    rc.setUb(0.0);   
+    cs.insert(rc);
+  }
+}
+#if 0
+class CglOneRow {
+
+public:
+  /// data
+  /// Row number
+  int row_;
+  /// Start
+  const int * start_;
+  /// End
+  const int * end_;
+
+public:
+
+    // Default Constructor
+  inline CglOneRow () : row_(-1),start_(0), end_(0) {} 
+
+  // Useful constructor
+  inline CglOneRow (int iRow,const int * start, const int * end) : row_(iRow),start_(start), end_(end) {}
+  // Destructor
+  inline ~CglOneRow () {}
+
+};
+class CglCompare {
+public:
+  /// Compare function
+  inline bool operator()(const CglOneRow & row1,
+			 const CglOneRow & row2) const
+  { 
+    const int * where1 = row1.start_;
+    const int * where2 = row2.start_;
+    while (where1 != row1.end_ && where2 != row2.end_) {
+      int iColumn1 = *where1;
+      int iColumn2 = *where2;
+      if (iColumn1<iColumn2) {
+	return true;
+      } else if (iColumn1>iColumn2) {
+	return false;
+      } else {
+	where1++;
+	where2++;
+      }
+    }
+    if (where1==row1.end_)
+      return false;
+    else
+      return true;
+  }
+};
+static int * lexSort(int numberCliques,
+		    int * cliqueStart, int * entry)
+{
+  CglOneRow * rows = new CglOneRow [numberCliques];
+  for (int i=0;i<numberCliques;i++) {
+    rows[i]=CglOneRow(i,entry+cliqueStart[i],entry+cliqueStart[i+1]);
+  }
+  std::sort(rows,rows+numberCliques,CglCompare());
+  int * sorted = new int [numberCliques];
+  for (int i=0;i<numberCliques;i++) {
+    sorted[i]=rows[i].row_;
+  }
+  delete [] rows;
+  return sorted;
+}
+static int outDupsEtc2(int numberIntegers, int numberCliques, int * statusClique,
+		      int * cliqueStart, char * cliqueType, int * entry, 
+		      int printit)
+{
+  int * sorted = lexSort(numberCliques,cliqueStart,entry);
+  delete [] sorted;
+  return 0;
+}
+#endif
+static int outDupsEtc(int numberIntegers, int numberCliques, int * statusClique,
+		      int * cliqueStart, char * cliqueType, int * entry,
+		      int * fixed,
+		      int printit)
+#if 0
+{
+  //outDupsEtc2(numberIntegers,numberCliques,statusClique,
+  //      cliqueStart,cliqueType,entry,printit);
+  int * whichP = new int [numberIntegers];
+  int iClique;
+  assert (sizeof(int)==4);
+  assert (sizeof(int)==4);
+  // sort
+  for (iClique=0;iClique<numberCliques;iClique++) {
+    int j = cliqueStart[iClique];
+    int n = cliqueStart[iClique+1]-j;
+    for (int i=0;i<n;i++) 
+      whichP[i]=entry[i+j];
+    CoinSort_2(whichP,whichP+n,entry+j);
+  }
+  // lexicographic sort
+  int * which = new int [numberCliques];
+  int * position = new int [numberCliques];
+  int * sort = new int [numberCliques];
+  for (iClique=0;iClique<numberCliques;iClique++) {
+    which[iClique]=iClique;
+    sort[iClique]=entry[cliqueStart[iClique]];
+    statusClique[iClique]=sort[iClique];
+    position[iClique]=0;
+  }
+  CoinSort_2(sort,sort+numberCliques,which);
+  int lastDone=-1;
+  int nDup=0;
+  int nSave=0;
+  while (lastDone<numberCliques-1) {
+    int jClique=lastDone+1;
+    int jFirst = jClique;
+    int iFirst = which[jFirst];
+    int iValue = statusClique[iFirst];
+    int iPos = position[iFirst];
+    jClique++;
+    for (;jClique<numberCliques;jClique++) {
+      int kClique = which[jClique];
+      int jValue = statusClique[kClique];
+      if (jValue>iValue||position[kClique]<iPos)
+	break;
+    }
+    if (jClique==jFirst+1) {
+      // done that bit
+      lastDone++;
+    } else {
+      // use next bit to sort and then repeat
+      int jLast=jClique;
+      for (jClique=jFirst;jClique<jLast;jClique++) {
+	int kClique = which[jClique];
+	int iValue = statusClique[kClique];
+	// put at end if finished
+	if (iValue<numberIntegers) {
+	  int kPos=position[kClique]+1;
+	  position[kClique]=kPos;
+	  kPos += cliqueStart[kClique];
+	  if (kPos==cliqueStart[kClique+1]) {
+	    iValue = numberIntegers;
+	  } else {
+	    iValue = entry[kPos];
+	  }
+	  statusClique[kClique]=iValue;
+	}
+	sort[jClique]=iValue;
+      }
+      CoinSort_2(sort+jFirst,sort+jLast,which+jFirst);
+      // if duplicate mark and move on
+      int iLowest=numberCliques;
+      char type='S';
+      for (jClique=jFirst;jClique<jLast;jClique++) {
+	int kClique = which [jClique];
+	int iValue = statusClique[kClique];
+	if (iValue<numberIntegers) 
+	  break;
+	if (cliqueType[kClique]=='E') {
+	  iLowest = CoinMin(iLowest,kClique);
+	  type='E';
+	} else if (type=='S') {
+	  iLowest = CoinMin(iLowest,kClique);
+	}
+      }
+      if (jClique>jFirst) {
+	// mark all apart from lowest number as duplicate and move on
+	// use cliqueType
+	lastDone =jClique-1;
+	for (jClique=jFirst;jClique<=lastDone;jClique++) {
+	  int kClique = which [jClique];
+	  if (kClique!=iLowest) {
+	    statusClique[kClique]=-2;
+	    nDup++;
+	    nSave += cliqueStart[kClique+1]-cliqueStart[kClique];
+	  }
+	}
+      }
+    }
+  }
+#if 1
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    int iClique=which[jClique];
+    printf("clique %d %d ",jClique,iClique);
+    for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
+      int iColumn = entry[j];
+      printf("%d ",iColumn);
+    }
+    printf("\n");
+  }
+#endif
+  if (printit)
+    printf("%d duplicates\n",nDup);
+  // For column version
+  int numberElements=cliqueStart[numberCliques];
+  int * start = new int [numberIntegers];
+  int * end = new int [numberIntegers];
+  int * clique = new int [numberElements];
+  int * marked = new int [numberCliques];
+  int * count = new int [numberCliques];
+  int * fixed = new int [numberIntegers];
+  memset(count,0,numberCliques*sizeof(int));
+  memset(end,0,numberIntegers*sizeof(int));
+  memset(fixed,0,numberIntegers*sizeof(int));
+  nSave=0;
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    if (statusClique[jClique]!=-2) {
+      for (int j=cliqueStart[jClique];j<cliqueStart[jClique+1];j++) {
+	int iColumn = entry[j];
+	end[iColumn]++;
+      }
+    } else {
+      nSave += cliqueStart[jClique+1]-cliqueStart[jClique];
+    }
+  }
+  numberElements=0;
+  for (int i=0;i<numberIntegers;i++) {
+    start[i]=numberElements;
+    int n=end[i];
+    end[i]=numberElements;
+    numberElements += n;
+  }
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    int iClique=which[jClique];
+    if (statusClique[iClique]!=-2) {
+      for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
+	int iColumn = entry[j];
+	int put=end[iColumn];
+	end[iColumn]=put+1;
+	clique[put]=iClique;
+      }
+    }
+  }
+
+  // Now see if any subset
+  int nOut=0;
+  int nFixed=0;
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    int kClique = which[jClique];
+    if (statusClique[kClique]==-2) 
+      continue;
+    // do first
+    int nMarked=0;
+    int iEnd=cliqueStart[kClique+1];
+    int iEl = cliqueStart[kClique];
+    int iColumn=entry[iEl++];
+    while (fixed[iColumn]) {
+      iColumn=-1;
+      if(iEl<iEnd) {
+	iColumn=entry[iEl++];
+      } else {
+	break;
+      }
+    }
+    if (iColumn<0) {
+      // now empty
+      printf("now empty clique %d !\n",kClique);
+      statusClique[kClique]=-2;
+      continue;
+    }
+    int i;
+    for ( i=start[iColumn];i<end[iColumn];i++) {
+      int iClique=clique[i];
+      // faster to shuffle up -2's?
+      if (statusClique[iClique]!=-2) {
+	if (iClique!=kClique) {
+	  count[iClique]=1;
+	  marked[nMarked++]=iClique;
+	} else {
+	  break;
+	}
+      }
+    }
+    assert (i<end[iColumn]);
+    if (nMarked) {
+      int n=nMarked;
+      int sizeClique=1;
+      for (;iEl<iEnd;iEl++) {
+	int iColumn=entry[iEl];
+	for ( i=start[iColumn];i<end[iColumn];i++) {
+	  int iClique=clique[i];
+	  // faster to shuffle up -2's?
+	  if (statusClique[iClique]!=-2) {
+	    if (iClique!=kClique) {
+	      if (count[iClique]) {
+		if (count[iClique]==sizeClique) {
+		  count[iClique]++;
+		} else {
+		  count[iClique]=0;
+		  n--;
+		}
+	      }
+	    } else {
+	      break;
+	    }
+	  }
+	}
+	sizeClique++;
+	assert (i<end[iColumn]);
+	if (!n)
+	  break;
+      }
+      if (n) {
+	// still some left
+	// But need to look at type
+	// when might be able to fix variables
+	bool subset=false;
+	if (cliqueType[kClique]=='E') {
+	  for (i=0;i<nMarked;i++) {
+	    int iClique=marked[i];
+	    if (count[iClique]==sizeClique) {
+	      subset=true;
+	      // can fix all in iClique not in kClique
+	      int iEl=cliqueStart[kClique];
+	      int jEl=cliqueStart[iClique];
+	      int jEnd=cliqueStart[iClique+1];
+	      int iColumn=entry[iEl];
+	      for (int j=jEl;j<jEnd;j++) {
+		int jColumn=entry[j];
+		if (jColumn==iColumn) {
+		  iEl++;
+		  if (iEl<iEnd)
+		    iColumn=entry[iEl];
+		  else
+		    iColumn=numberIntegers;
+		} else if (!fixed[jColumn]) {
+		  // fix
+		  nFixed++;
+		  fixed[jColumn]=1;
+		}
+	      }
+	    }
+	  }
+	} else {
+	  // print first for now
+	  for (i=0;i<nMarked;i++) {
+	    int iClique=marked[i];
+	    if (count[iClique]==sizeClique) {
+	      subset=true;
+#if 0
+	      if (printit>10
+		  printf("clique %d is subset of %d\n",kClique,iClique);
+	      printf("Kclique %d ",kClique);
+	      for (int j=cliqueStart[kClique];j<cliqueStart[kClique+1];j++) {
+		int kColumn = entry[j];
+		printf("%d ",kColumn);
+	      }
+	      printf("\n");
+	      printf("Iclique %d ",iClique);
+	      for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
+		int iColumn = entry[j];
+		printf("%d ",iColumn);
+	      }
+	      printf("\n");
+#endif
+	      break;
+	    }
+	  }
+	}
+	if (subset) {
+	  nOut++;
+	  statusClique[kClique]=-2;
+	}
+      }
+      for (i=0;i<nMarked;i++)
+	count[marked[i]]=0;
+    }
+  }
+  if (nOut) {
+    if(printit) 
+      printf("Can get rid of %d cliques\n",nOut);
+  }
+  if (nFixed) {
+    printf("Can fix to zero ");
+    // numbers are subset of column variables
+    for (int i=0;i<numberIntegers;i++) {
+      if (fixed[i])
+	printf("%d ",i);
+    }
+    printf("\n");
+    abort();
+  }
+  delete [] sort;
+  delete [] which;
+  delete [] position;
+  delete [] whichP;
+  delete [] start;
+  delete [] end;
+  delete [] clique;
+  delete [] marked;
+  delete [] count;
+  delete [] fixed;
+  return nOut;
+}
+#else
+{
+  //outDupsEtc2(numberIntegers,numberCliques,statusClique,
+  //      cliqueStart,cliqueType,entry,printit);
+  int * whichP = new int [numberIntegers];
+  int iClique;
+  assert (sizeof(int)==4);
+  assert (sizeof(int)==4);
+  // sort
+  for (iClique=0;iClique<numberCliques;iClique++) {
+    int j = cliqueStart[iClique];
+    int n = cliqueStart[iClique+1]-j;
+    for (int i=0;i<n;i++) 
+      whichP[i]=entry[i+j];
+    CoinSort_2(whichP,whichP+n,entry+j);
+  }
+  // lexicographic sort
+  int * which = new int [numberCliques];
+  int * position = new int [numberCliques];
+  int * sort = new int [numberCliques];
+  for (iClique=0;iClique<numberCliques;iClique++) {
+    which[iClique]=iClique;
+    sort[iClique]=entry[cliqueStart[iClique]];
+    statusClique[iClique]=sort[iClique];
+    position[iClique]=0;
+  }
+  CoinSort_2(sort,sort+numberCliques,which);
+  int lastDone=-1;
+  int nDup=0;
+  int nSave=0;
+  while (lastDone<numberCliques-1) {
+    int jClique=lastDone+1;
+    int jFirst = jClique;
+    int iFirst = which[jFirst];
+    int iValue = statusClique[iFirst];
+    int iPos = position[iFirst];
+    jClique++;
+    for (;jClique<numberCliques;jClique++) {
+      int kClique = which[jClique];
+      int jValue = statusClique[kClique];
+      if (jValue>iValue||position[kClique]<iPos)
+	break;
+    }
+    if (jClique==jFirst+1) {
+      // done that bit
+      lastDone++;
+    } else {
+      // use next bit to sort and then repeat
+      int jLast=jClique;
+      for (jClique=jFirst;jClique<jLast;jClique++) {
+	int kClique = which[jClique];
+	int iValue = statusClique[kClique];
+	// put at end if finished
+	if (iValue<numberIntegers) {
+	  int kPos=position[kClique]+1;
+	  position[kClique]=kPos;
+	  kPos += cliqueStart[kClique];
+	  if (kPos==cliqueStart[kClique+1]) {
+	    iValue = numberIntegers;
+	  } else {
+	    iValue = entry[kPos];
+	  }
+	  statusClique[kClique]=iValue;
+	}
+	sort[jClique]=iValue;
+      }
+      CoinSort_2(sort+jFirst,sort+jLast,which+jFirst);
+      // if duplicate mark and move on
+      int iLowest=numberCliques;
+      char type='S';
+      for (jClique=jFirst;jClique<jLast;jClique++) {
+	int kClique = which [jClique];
+	int iValue = statusClique[kClique];
+	if (iValue<numberIntegers) 
+	  break;
+	if (cliqueType[kClique]=='E') {
+	  iLowest = CoinMin(iLowest,kClique);
+	  type='E';
+	} else if (type=='S') {
+	  iLowest = CoinMin(iLowest,kClique);
+	}
+      }
+      if (jClique>jFirst) {
+	// mark all apart from lowest number as duplicate and move on
+	// use cliqueType
+	lastDone =jClique-1;
+	for (jClique=jFirst;jClique<=lastDone;jClique++) {
+	  int kClique = which [jClique];
+	  if (kClique!=iLowest) {
+	    statusClique[kClique]=-2;
+	    nDup++;
+	    nSave += cliqueStart[kClique+1]-cliqueStart[kClique];
+	  }
+	}
+      }
+    }
+  }
+#if 0
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    int iClique=which[jClique];
+    printf("clique %d %d ",jClique,iClique);
+    for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
+      int iColumn = entry[j];
+      printf("%d ",iColumn);
+    }
+    printf("\n");
+  }
+#endif
+  if (printit)
+    printf("%d duplicates\n",nDup);
+  int nOutMax=2000000;
+  // mark cliques used to remove other cliques
+  int * used = statusClique+numberCliques;
+  // Now see if any subset
+  int nOut=0;
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    used[jClique]=numberCliques;
+    if (statusClique[jClique]!=-2) {
+      position[jClique]=cliqueStart[jClique];
+      statusClique[jClique]=entry[cliqueStart[jClique]];
+    }
+  }
+  nSave=0;
+  int startLooking=0;
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    int kClique = which[jClique];
+    if (statusClique[kClique]==-2) {
+      nOut++;
+      nSave += cliqueStart[kClique+1]-cliqueStart[kClique];
+      if (jClique==startLooking)
+	startLooking++;
+      continue;
+    }
+    int kValue =statusClique[kClique];
+    bool ppp=false;
+    for (int iiClique=startLooking;iiClique<jClique;iiClique++) {
+      int iClique = which[iiClique];
+      int iValue = statusClique[iClique];
+      if (iValue==-2||iValue==numberIntegers) {
+	if (iiClique==startLooking)
+	  startLooking++;
+	continue;
+      } else {
+	if (kValue>entry[cliqueStart[iClique+1]-1]) {
+	  statusClique[iClique]=numberIntegers;
+	  continue;
+	}
+      }
+      if (iValue<kValue) {
+	while (iValue<kValue) {
+	  int iPos=position[iClique]+1;
+	  position[iClique]=iPos;
+	  if (iPos==cliqueStart[iClique+1]) {
+	    iValue = numberIntegers;
+	  } else {
+	    iValue = entry[iPos];
+	  }
+	  statusClique[iClique]=iValue;
+	}
+      } 
+      if (iValue>kValue) 
+	continue; // not a candidate
+      // See if subset (remember duplicates have gone)
+      if (cliqueStart[iClique+1]-position[iClique]>
+	  cliqueStart[kClique+1]-cliqueStart[kClique]) {
+	// could be subset ?
+	int offset = cliqueStart[iClique]-position[kClique];
+	int j;
+	bool subset=true;
+	// what about different fixes bool odd=false;
+	for (j=cliqueStart[kClique];j<cliqueStart[kClique+1];j++) {
+	  int kColumn = entry[j];
+	  int iColumn = entry[j+offset];
+	  while (iColumn<kColumn) {
+	    offset++;
+	    if (j+offset<cliqueStart[iClique+1]) {
+	      iColumn = entry[j+offset];
+	    } else {
+	      iColumn=numberIntegers;
+	    }
+	  }
+	  if (iColumn!=kColumn) {
+	    subset=false;
+	    break;
+	  }
+	}
+	if (subset&&nOut<=nOutMax) {
+	  int kSave=statusClique[kClique];
+	  statusClique[kClique]=-2;
+	  if (printit>1)
+	    printf("clique %d is subset of %d\n",kClique,iClique);
+	  if (!ppp&&false) {
+	    ppp=true;
+	    printf("Kclique %d ",kClique);
+	    for (int j=cliqueStart[kClique];j<cliqueStart[kClique+1];j++) {
+	      int kColumn = entry[j];
+	      printf("%d ",kColumn);
+	    }
+	    printf("\n");
+	  }
+	  if (false) {
+	    printf("Iclique %d ",iClique);
+	    for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
+	      int iColumn = entry[j];
+	      printf("%d ",iColumn);
+	    }
+	    printf("\n");
+	  }
+	  nOut++;
+	  used[iClique]=CoinMin(used[iClique],kClique);;
+	  used[kClique]=CoinMin(used[kClique],iClique);;
+	  // But need to look at type
+	  // when might be able to fix variables
+	  if (cliqueType[kClique]=='E') {
+	    statusClique[kClique]=kSave;
+	    //statusClique[iClique]=-2;
+	    nOut--;
+	    // can fix all in iClique not in kClique
+	    printf("ZZ clique %d E, %d S\n",kClique,iClique);
+	    int offset = cliqueStart[iClique]-position[kClique];
+	    int j;
+	    for (j=cliqueStart[kClique];j<cliqueStart[kClique+1];j++) {
+	      int kColumn = entry[j];
+	      int iColumn = entry[j+offset];
+	      while (iColumn<kColumn) {
+		if (!fixed[iColumn]) {
+		  printf("ZZ fixing %d to zero\n",iColumn);
+		  fixed[iColumn]=-1;
+		} else {
+		  assert (fixed[iColumn]==-1);
+		}
+		offset++;
+		if (j+offset<cliqueStart[iClique+1]) {
+		  iColumn = entry[j+offset];
+		} else {
+		  iColumn=numberIntegers;
+		}
+	      }
+	    }
+#if 0
+	  } else if (cliqueType[iClique]=='E') {
+	    printf("ZZ clique %d S, %d E\n",kClique,iClique);
+	    statusClique[kClique]=-1;
+	    nOut--;
+#endif
+	  }
+	  break;
+	}
+      }
+    }
+  }
+  if (nOut) {
+    if(printit) 
+      printf("Can get rid of %d cliques\n",nOut);
+  }
+  for (int i=0;i<numberCliques;i++) {
+    if (statusClique[i]!=-2) {
+      statusClique[i]=-1;
+    }
+  }
+  delete [] sort;
+  delete [] which;
+  delete [] position;
+  delete [] whichP;
+  return nOut;
+}
+#endif
+void CglDuplicateRow::generateCuts8(const OsiSolverInterface & si, OsiCuts & cs,
+				    const CglTreeInfo )
+{
+  bool printit=false;
+  bool feasible=true;
+  int numberCliques=0;
+  int numberEntries=0;
+  int * cliqueStart = NULL;
+  int * entry = NULL;
+  char * cliqueType=NULL;
+  int numberRows=si.getNumRows(); 
+  const CoinPackedMatrix * rowCopy = si.getMatrixByRow();
+  assert(numberRows&&si.getNumCols());
+  int iRow;
+  const int * column = rowCopy->getIndices();
+  const double * elementByRow = rowCopy->getElements();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const int * rowLength = rowCopy->getVectorLengths(); 
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+  const double * rowLower = si.getRowLower();
+  const double * rowUpper = si.getRowUpper();
+  // Find 0-1 variables
+  int numberIntegers=0;
+  int numberColumns=si.getNumCols();
+  int * backward = new int [numberColumns];
+  for (int i=0;i<numberColumns;i++) {
+    if (lower[i]==0.0&&upper[i]==1.0) 
+      backward[i]=numberIntegers++;
+    else
+      backward[i]=-1;
+  }
+  int * whichP = new int [numberIntegers];
+  for (int iPass=0;iPass<2;iPass++) {
+    if (iPass) {
+      cliqueStart = new int [numberCliques+1];
+      cliqueStart[0]=0;
+      entry = new int [numberEntries];
+      cliqueType = new char [numberCliques];
+      numberCliques=0;
+      numberEntries=0;
+    }
+    for (iRow=0;iRow<numberRows;iRow++) {
+      duplicate_[iRow]=-1;
+      int numberP1=0;
+      int numberTotal=0;
+      CoinBigIndex j;
+      double upperValue=rowUpper[iRow];
+      double lowerValue=rowLower[iRow];
+      bool good=true;
+      for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	int iColumn = column[j];
+	double value = elementByRow[j];
+	if (upper[iColumn]-lower[iColumn]<1.0e-8) {
+	  // fixed
+	  upperValue -= lower[iColumn]*value;
+	  lowerValue -= lower[iColumn]*value;
+	  continue;
+	} else if (backward[iColumn]<0) {
+	  good = false;
+	  break;
+	} else {
+	  iColumn = backward[iColumn];
+	  numberTotal++;
+	}
+	if (value!=1.0) {
+	  good=false;
+	} else {
+	  assert (numberP1<numberIntegers);
+	  whichP[numberP1++]=iColumn;;
+	}
+      }
+      int iUpper = static_cast<int> (floor(upperValue+1.0e-5));
+      int iLower = static_cast<int> (ceil(lowerValue-1.0e-5));
+      int state=0;
+      if (upperValue<1.0e6) {
+	if (iUpper==1)
+	  state=1;
+	else if (iUpper==0)
+	  state=2;
+	else if (iUpper<0)
+	  state=3;
+	if (fabs(static_cast<double> (iUpper)-upperValue)>1.0e-9)
+	  state =-1;
+      }
+      if (!state&&lowerValue>-1.0e6) {
+	if (-iLower==1-numberP1)
+	  state=-1;
+	else if (-iLower==-numberP1)
+	  state=-2;
+	else if (-iLower<-numberP1)
+	  state=-3;
+	if (fabs(static_cast<double> (iLower)-lowerValue)>1.0e-9)
+	  state =-1;
+      }
+      if (numberP1<2)
+	state=-1;
+      if (good&&state>0) {
+	if (abs(state)==3) {
+	  // infeasible
+	  printf("FFF Infeasible\n");;
+	  feasible=false;
+	  break;
+	} else if (abs(state)==2) {
+	  // we can fix all
+	  //numberFixed += numberP1+numberM1;
+	  printf("FFF can fix %d\n",numberP1);
+	} else {
+	  for (j=0;j<numberP1;j++) {
+	    int iColumn = whichP[j];
+	    if (iPass) {
+	      entry[numberEntries]=iColumn;
+	    }
+	    numberEntries++;
+	  }
+	  if (iPass) {
+	    if (iLower!=iUpper) {
+	      // slack
+	      cliqueType[numberCliques]='S';
+	    } else {
+	      cliqueType[numberCliques]='E';
+	    }
+	    cliqueStart[numberCliques+1]=numberEntries;
+	    duplicate_[iRow]=numberCliques;
+	  }
+	  numberCliques++;
+	}
+      }
+    }
+  }
+  int * dups = new int [2*numberCliques];
+  int * fixed = new int[CoinMax(numberIntegers,numberCliques)];
+  memset(fixed,0,numberIntegers*sizeof(int));
+  outDupsEtc(numberIntegers, numberCliques, dups,
+	     cliqueStart, cliqueType, entry, fixed, printit ? 2 : 1);
+  int nFixed=0;
+  CoinPackedVector ubs;
+  for (int i=0;i<numberColumns;i++) {
+    int i01=backward[i];
+    if (i01>=0&&fixed[i01]==-1) {
+      ubs.insert(i,0.0);
+      nFixed++;
+    }
+  }
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int iClique = duplicate_[iRow];
+    if (iClique>=0) 
+      fixed[iClique]=iRow;
+  }
+  int * dup2 = new int [2*numberRows];
+  int * used2 = dup2+numberRows;
+  int * used = dups+numberCliques;
+  for (iRow=0;iRow<numberRows;iRow++) {
+    dup2[iRow]=-3; // say not clique
+    used2[iRow]=-1; // say not used
+  }
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int iClique = duplicate_[iRow];
+    if (iClique>=0) {
+      dup2[iRow] = dups[iClique];
+      int which = used[iClique];
+      if (which>=0&&which<numberCliques)
+	which = fixed[which];
+      used2[iRow]=which;
+    }
+  }
+  delete [] duplicate_;
+  duplicate_=dup2;
+  delete [] fixed;
+  delete [] dups;
+  delete [] backward;
+  if (nFixed) {
+    OsiColCut cc;
+    cc.setUbs(ubs);
+    cc.setEffectiveness(100.0);
+    cs.insert(cc);
+  }
+  if (!feasible) {
+    // generate infeasible cut and return
+    printf("QQ**** infeasible cut\n");
+    OsiRowCut rc;
+    rc.setLb(COIN_DBL_MAX);
+    rc.setUb(0.0);   
+    cs.insert(rc);
+  }
+}
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglDuplicateRow::CglDuplicateRow ()
+:
+  CglCutGenerator(),
+  rhs_(NULL),
+  duplicate_(NULL),
+  lower_(NULL),
+  storedCuts_(NULL),
+  maximumDominated_(1000),
+  maximumRhs_(1),
+  sizeDynamic_(COIN_INT_MAX),
+  mode_(3),
+  logLevel_(0)
+{
+}
+// Useful constructor
+CglDuplicateRow::CglDuplicateRow(OsiSolverInterface * solver)
+  : CglCutGenerator(),
+    rhs_(NULL),
+    duplicate_(NULL),
+    lower_(NULL),
+    storedCuts_(NULL),
+    maximumDominated_(1000),
+    maximumRhs_(1),
+    sizeDynamic_(COIN_INT_MAX),
+    mode_(3),
+    logLevel_(0)
+{
+  refreshSolver(solver);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglDuplicateRow::CglDuplicateRow (  const CglDuplicateRow & rhs)
+                                                              :
+  CglCutGenerator(rhs),
+  matrix_(rhs.matrix_),
+  matrixByRow_(rhs.matrixByRow_),
+  storedCuts_(NULL),
+  maximumDominated_(rhs.maximumDominated_),
+  maximumRhs_(rhs.maximumRhs_),
+  sizeDynamic_(rhs.sizeDynamic_),
+  mode_(rhs.mode_),
+  logLevel_(rhs.logLevel_)
+{  
+  int numberRows=matrix_.getNumRows();
+  rhs_ = CoinCopyOfArray(rhs.rhs_,numberRows);
+  duplicate_ = CoinCopyOfArray(rhs.duplicate_,numberRows);
+  lower_ = CoinCopyOfArray(rhs.lower_,numberRows);
+  if (rhs.storedCuts_)
+    storedCuts_ = new CglStored(*rhs.storedCuts_);
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglDuplicateRow::clone() const
+{
+  return new CglDuplicateRow(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglDuplicateRow::~CglDuplicateRow ()
+{
+  // free memory
+  delete [] rhs_;
+  delete [] duplicate_;
+  delete [] lower_;
+  delete storedCuts_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglDuplicateRow &
+CglDuplicateRow::operator=(
+                                         const CglDuplicateRow& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    delete [] rhs_;
+    delete [] duplicate_;
+    delete [] lower_;
+    delete storedCuts_;
+    storedCuts_ = NULL;
+    matrix_=rhs.matrix_;
+    matrixByRow_=rhs.matrixByRow_;
+    maximumDominated_ = rhs.maximumDominated_;
+    maximumRhs_=rhs.maximumRhs_;
+    sizeDynamic_ = rhs.sizeDynamic_;
+    mode_ = rhs.mode_;
+    logLevel_ = rhs.logLevel_;
+    int numberRows=matrix_.getNumRows();
+    rhs_ = CoinCopyOfArray(rhs.rhs_,numberRows);
+    duplicate_ = CoinCopyOfArray(rhs.duplicate_,numberRows);
+    lower_ = CoinCopyOfArray(rhs.lower_,numberRows);
+  if (rhs.storedCuts_)
+    storedCuts_ = new CglStored(*rhs.storedCuts_);
+  }
+  return *this;
+}
+
+// This can be used to refresh any information
+void 
+CglDuplicateRow::refreshSolver(OsiSolverInterface * solver)
+{
+  delete [] rhs_;
+  delete [] duplicate_;
+  delete [] lower_;
+  matrix_ = *solver->getMatrixByCol();
+  matrix_.removeGaps();
+  matrix_.orderMatrix();
+  matrixByRow_ = *solver->getMatrixByRow();
+  int numberRows=matrix_.getNumRows();
+  rhs_ = new int[numberRows];
+  duplicate_ = new int[numberRows];
+  lower_ = new int[numberRows];
+  const double * columnLower = solver->getColLower();
+  const double * rowLower = solver->getRowLower();
+  const double * rowUpper = solver->getRowUpper();
+  // Row copy
+  const double * elementByRow = matrixByRow_.getElements();
+  const int * column = matrixByRow_.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts();
+  const int * rowLength = matrixByRow_.getVectorLengths();
+  int iRow;
+  int numberGood=0;
+  int markBad = -(solver->getNumCols()+1);
+  for (iRow=0;iRow<numberRows;iRow++) {
+    rhs_[iRow]=markBad;
+    lower_[iRow]=markBad;
+    duplicate_[iRow]=-1;
+    if (rowUpper[iRow]<100) {
+      int iRhs= static_cast<int> (floor(rowUpper[iRow]));
+      // check elements
+      bool good=true;
+      for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+        int iColumn = column[j];
+        if (!solver->isInteger(iColumn))
+	  good=false;
+        double value = elementByRow[j];
+        if (floor(value)!=value||value<1.0) {
+          good=false;
+        }
+      }
+      if (good) {
+        lower_[iRow] = static_cast<int> (CoinMax(0.0,ceil(rowLower[iRow])));
+        if (iRhs>=lower_[iRow]) {
+          rhs_[iRow]=iRhs;
+          numberGood++;
+        } else {
+          // infeasible ?
+          lower_[iRow]=markBad;
+          rhs_[iRow]=markBad;
+        }
+      } else {
+        lower_[iRow]=markBad;
+        rhs_[iRow]=markBad;
+      }
+    } else if (rowUpper[iRow]>1.0e30&&rowLower[iRow]==1.0) {
+      // may be OK to look for dominated in >=1 rows
+      // check elements
+      bool good=true;
+      for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+        int iColumn = column[j];
+        if (!solver->isInteger(iColumn))
+	  good=false;
+        double value = elementByRow[j];
+        if (floor(value)!=value||value<1.0) {
+          good=false;
+        }
+	if (columnLower[iColumn]!=0.0)
+	  good=false;
+      }
+      if (good) {
+        lower_[iRow] = 1;
+      }
+    }
+  }
+}
+  /** Fix variables and find duplicate/dominated rows for the model of the 
+      solver interface, si.
+
+      This is a very simple minded idea but I (JJF) am using it in a project so thought
+      I might as well add it.  It should really be called before first solve and I may
+      modify CBC to allow for that.
+
+      This is designed for problems with few rows and many integer variables where the rhs
+      are <= or == and all coefficients and rhs are small integers.
+
+      If effective rhs is K then we can fix all variables with coefficients > K to their lower bounds
+      (effective rhs just means original with variables with nonzero lower bounds subtracted out).
+
+      If one row is a subset of another and the effective rhs are same we can fix some variables
+      and then the two rows are identical.
+
+      This version does deletions and fixings and may return stored cuts for
+      dominated columns 
+  */
+CglStored * 
+CglDuplicateRow::outDuplicates( OsiSolverInterface * solver)
+{
+  
+  CglTreeInfo info;
+  info.level = 0;
+  info.pass = 0;
+  int numberRows = solver->getNumRows();
+  info.formulation_rows = numberRows;
+  info.inTree = false;
+  info.strengthenRow= NULL;
+  info.pass = 0;
+  OsiCuts cs;
+  generateCuts(*solver,cs,info);
+  // Get rid of duplicate rows
+  int * which = new int[numberRows]; 
+  int numberDrop=0;
+  for (int iRow=0;iRow<numberRows;iRow++) {
+    if (duplicate_[iRow]==-2||duplicate_[iRow]>=0) 
+      which[numberDrop++]=iRow;
+  }
+  if (numberDrop) {
+    solver->deleteRows(numberDrop,which);
+  }
+  delete [] which;
+  // see if we have any column cuts
+  int numberColumnCuts = cs.sizeColCuts() ;
+  const double * columnLower = solver->getColLower();
+  const double * columnUpper = solver->getColUpper();
+  for (int k = 0;k<numberColumnCuts;k++) {
+    OsiColCut * thisCut = cs.colCutPtr(k) ;
+    const CoinPackedVector & lbs = thisCut->lbs() ;
+    const CoinPackedVector & ubs = thisCut->ubs() ;
+    int j ;
+    int n ;
+    const int * which ;
+    const double * values ;
+    n = lbs.getNumElements() ;
+    which = lbs.getIndices() ;
+    values = lbs.getElements() ;
+    for (j = 0;j<n;j++) {
+      int iColumn = which[j] ;
+      if (values[j]>columnLower[iColumn]) 
+        solver->setColLower(iColumn,values[j]) ;
+    }
+    n = ubs.getNumElements() ;
+    which = ubs.getIndices() ;
+    values = ubs.getElements() ;
+    for (j = 0;j<n;j++) {
+      int iColumn = which[j] ;
+      if (values[j]<columnUpper[iColumn]) 
+        solver->setColUpper(iColumn,values[j]) ;
+    }
+  }
+  return storedCuts_;
+}
+// Create C++ lines to get to current state
+std::string
+CglDuplicateRow::generateCpp( FILE * fp) 
+{
+  CglDuplicateRow other;
+  fprintf(fp,"0#include \"CglDuplicateRow.hpp\"\n");
+  fprintf(fp,"3  CglDuplicateRow duplicateRow;\n");
+  if (logLevel_!=other.logLevel_)
+    fprintf(fp,"3  duplicateRow.setLogLevel(%d);\n",logLevel_);
+  else
+    fprintf(fp,"4  duplicateRow.setLogLevel(%d);\n",logLevel_);
+  if (maximumRhs_!=other.maximumRhs_)
+    fprintf(fp,"3  duplicateRow.setMaximumRhs(%d);\n",maximumRhs_);
+  else
+    fprintf(fp,"4  duplicateRow.setMaximumRhs(%d);\n",maximumRhs_);
+  if (maximumDominated_!=other.maximumDominated_)
+    fprintf(fp,"3  duplicateRow.setMaximumDominated(%d);\n",maximumDominated_);
+  else
+    fprintf(fp,"4  duplicateRow.setMaximumDominated(%d);\n",maximumDominated_);
+  if (mode_!=other.mode_)
+    fprintf(fp,"3  duplicateRow.setMode(%d);\n",mode_);
+  else
+    fprintf(fp,"4  duplicateRow.setMode(%d);\n",mode_);
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  duplicateRow.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  duplicateRow.setAggressiveness(%d);\n",getAggressiveness());
+  return "duplicateRow";
+}
diff --git a/cbits/coin/CglDuplicateRow.hpp b/cbits/coin/CglDuplicateRow.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglDuplicateRow.hpp
@@ -0,0 +1,189 @@
+// $Id: CglDuplicateRow.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglDuplicateRow_H
+#define CglDuplicateRow_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+class CglStored;
+
+/** DuplicateRow Cut Generator Class */
+class CglDuplicateRow : public CglCutGenerator {
+ 
+public:
+    
+  
+  /**@name Generate Cuts */
+  //@{
+  /** Fix variables and find duplicate/dominated rows for the model of the 
+      solver interface, si.
+
+      This is a very simple minded idea but I (JJF) am using it in a project so thought
+      I might as well add it.  It should really be called before first solve and I may
+      modify CBC to allow for that.
+
+      This is designed for problems with few rows and many integer variables where the rhs
+      are <= or == and all coefficients and rhs are small integers.
+
+      If effective rhs is K then we can fix all variables with coefficients > K to their lower bounds
+      (effective rhs just means original with variables with nonzero lower bounds subtracted out).
+
+      If one row is a subset of another and the effective rhs are same we can fix some variables
+      and then the two rows are identical.
+
+      The generator marks identical rows so can be taken out in solve
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+private:
+  /// Does work for modes 1,2
+  void generateCuts12( const OsiSolverInterface & si, OsiCuts & cs,
+		       const CglTreeInfo info = CglTreeInfo());
+  /// Does work for mode 4
+  void generateCuts4( const OsiSolverInterface & si, OsiCuts & cs,
+		       const CglTreeInfo info = CglTreeInfo());
+  /// Does work for mode 8
+  void generateCuts8( const OsiSolverInterface & si, OsiCuts & cs,
+		       const CglTreeInfo info = CglTreeInfo());
+public:
+  /** Fix variables and find duplicate/dominated rows for the model of the 
+      solver interface, si.
+
+      This is a very simple minded idea but I (JJF) am using it in a project so thought
+      I might as well add it.  It should really be called before first solve and I may
+      modify CBC to allow for that.
+
+      This is designed for problems with few rows and many integer variables where the rhs
+      are <= or == and all coefficients and rhs are small integers.
+
+      If effective rhs is K then we can fix all variables with coefficients > K to their lower bounds
+      (effective rhs just means original with variables with nonzero lower bounds subtracted out).
+
+      If one row is a subset of another and the effective rhs are same we can fix some variables
+      and then the two rows are identical.
+
+      This version does deletions and fixings and may return stored cuts for
+      dominated columns 
+  */
+  CglStored * outDuplicates( OsiSolverInterface * solver);
+
+  //@}
+
+  /**@name Get information on size of problem */
+  //@{
+  /// Get duplicate row list, -1 means still in, -2 means out (all fixed), k>= means same as row k 
+  inline const int * duplicate() const
+  { return duplicate_;}
+  /// Size of dynamic program
+  inline int sizeDynamic() const
+  { return sizeDynamic_;}
+  /// Number of rows in original problem
+  inline int numberOriginalRows() const
+  { return matrix_.getNumRows();}
+  //@}
+
+  /**@name Get information on size of problem */
+  //@{
+  /// logLevel
+  inline int logLevel() const
+  { return logLevel_;}
+  inline void setLogLevel(int value)
+  { logLevel_ = value;}
+  //@}
+
+
+  /**@name We only check for duplicates amongst rows with effective rhs <= this */
+  //@{
+  /// Get
+  inline int maximumRhs() const
+  { return maximumRhs_;}
+  /// Set
+  inline void setMaximumRhs(int value)
+  { maximumRhs_=value;}
+  //@}
+
+  /**@name We only check for dominated amongst groups of columns whose size <= this */
+  //@{
+  /// Get
+  inline int maximumDominated() const
+  { return maximumDominated_;}
+  /// Set
+  inline void setMaximumDominated(int value)
+  { maximumDominated_=value;}
+  //@}
+  /**@name gets and sets */
+  //@{
+  /// Get mode
+  inline int mode() const
+  { return mode_;}
+  /// Set mode
+  inline void setMode(int value)
+  { mode_=value;}
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglDuplicateRow ();
+ 
+  /// Useful constructor 
+  CglDuplicateRow (OsiSolverInterface * solver);
+ 
+  /// Copy constructor 
+  CglDuplicateRow (
+    const CglDuplicateRow & rhs);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglDuplicateRow &
+    operator=(
+    const CglDuplicateRow& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglDuplicateRow ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+
+  /// This can be used to refresh any information
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  //@}
+      
+protected:
+  
+
+  // Protected member data
+
+  /**@name Protected member data */
+  //@{
+  /// Matrix
+  CoinPackedMatrix matrix_;
+  /// Matrix by row
+  CoinPackedMatrix matrixByRow_; 
+  /// Possible rhs (if 0 then not possible)
+  int * rhs_;
+  /// Marks duplicate rows
+  int * duplicate_;
+  /// To allow for <= rows
+  int * lower_;
+  /// Stored cuts if we found dominance cuts
+  CglStored * storedCuts_;
+  /// Check dominated columns if less than this number of candidates
+  int maximumDominated_;
+  /// Check duplicates if effective rhs <= this
+  int maximumRhs_;
+  /// Size of dynamic program
+  int sizeDynamic_;
+  /// 1 do rows, 2 do columns, 3 do both
+  int mode_;
+  /// Controls print out
+  int logLevel_;
+  //@}
+};
+#endif
diff --git a/cbits/coin/CglFlowCover.cpp b/cbits/coin/CglFlowCover.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglFlowCover.cpp
@@ -0,0 +1,1514 @@
+// $Id: CglFlowCover.cpp 1123 2013-04-06 20:47:24Z stefan $
+//-----------------------------------------------------------------------------
+// name:     Cgl Lifted Simple Generalized Flow Cover Cut Generator
+// author:   Yan Xu                email: yan.xu@sas.com
+//           Jeff Linderoth        email: jtl3@lehigh.edu
+//           Martin Savelsberg     email: martin.savelsbergh@isye.gatech.edu
+// date:     05/01/2003
+// comments: please scan this file for '???' and read the comments
+//-----------------------------------------------------------------------------
+// Copyright (C) 2003, Yan Xu, Jeff Linderoth, Martin Savelsberg and others. 
+// All Rights Reserved.
+// This code is published under the Eclipse Public License.
+
+#include <cstdlib>
+#include <cmath>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinSort.hpp"
+
+#include "CglFlowCover.hpp"
+
+// added #define to get rid of warnings (so uncomment if =true)
+//#define CGLFLOW_DEBUG2
+static bool CGLFLOW_DEBUG=false;
+static bool doLift=true;
+#include <iomanip>
+//-------------------------------------------------------------------
+// Overloaded operator<< for printing VUB and VLB.
+//-------------------------------------------------------------------  
+std::ostream& operator<<( std::ostream& os, const CglFlowVUB &v ) 
+{ 
+  os << " VAR = " << v.getVar() << "\t VAL = " << v.getVal() << std::endl; 
+  return os; 
+}
+
+// Initialize static memeber
+int CglFlowCover::numFlowCuts_ = 0;
+
+//-------------------------------------------------------------------
+// Determine row types. Find the VUBS and VLBS. 
+//-------------------------------------------------------------------  
+void 
+CglFlowCover::flowPreprocess(const OsiSolverInterface& si)
+{
+  CoinPackedMatrix matrixByRow(*si.getMatrixByRow());
+
+  int numRows = si.getNumRows();
+  int numCols = si.getNumCols();
+  
+  const char* sense        = si.getRowSense();
+  const double* RHS        = si.getRightHandSide();
+
+  const double* coefByRow  = matrixByRow.getElements();
+  const int* colInds       = matrixByRow.getIndices();
+  const int* rowStarts     = matrixByRow.getVectorStarts();
+  const int* rowLengths    = matrixByRow.getVectorLengths();
+  int iRow      = -1; 
+  int iCol      = -1;
+
+  numCols_ = numCols;     // Record col and row numbers for copy constructor
+  numRows_ = numRows;
+
+  if (rowTypes_ != 0) {
+    delete [] rowTypes_; rowTypes_ = 0;
+  }
+  rowTypes_ = new CglFlowRowType [numRows];// Destructor will free memory
+  // Get integer types
+  const char * columnType = si.getColType (true);
+    
+  // Summarize the row type infomation.
+  int numUNDEFINED   = 0;
+  int numVARUB       = 0;
+  int numVARLB       = 0;
+  int numVAREQ       = 0;
+  int numMIXUB       = 0;
+  int numMIXEQ       = 0;
+  int numNOBINUB     = 0;
+  int numNOBINEQ     = 0;
+  int numSUMVARUB    = 0;
+  int numSUMVAREQ    = 0;
+  int numUNINTERSTED = 0;
+
+  int* ind     = new int [numCols];
+  double* coef = new double [numCols];
+  for (iRow = 0; iRow < numRows; ++iRow) {
+    int rowLen   = rowLengths[iRow];
+    char sen     = sense[iRow];
+    double rhs   = RHS[iRow];
+
+    CoinDisjointCopyN(colInds + rowStarts[iRow], rowLen, ind);
+    CoinDisjointCopyN(coefByRow + rowStarts[iRow], rowLen, coef);
+ 
+    CglFlowRowType rowType = determineOneRowType(si, rowLen, ind, coef, 
+						 sen, rhs);
+
+    rowTypes_[iRow] = rowType;
+
+    switch(rowType) {
+    case  CGLFLOW_ROW_UNDEFINED:
+      ++numUNDEFINED; 
+      break;
+    case  CGLFLOW_ROW_VARUB:
+      ++numVARUB; 
+      break;
+    case  CGLFLOW_ROW_VARLB:
+      ++numVARLB; 
+      break;
+    case  CGLFLOW_ROW_VAREQ:
+      ++numVAREQ; 
+      break;
+    case  CGLFLOW_ROW_MIXUB:
+      ++numMIXUB; 
+      break;
+    case  CGLFLOW_ROW_MIXEQ:
+      ++numMIXEQ; 
+      break;
+    case  CGLFLOW_ROW_NOBINUB:
+      ++numNOBINUB; 
+      break;
+    case  CGLFLOW_ROW_NOBINEQ:
+      ++numNOBINEQ; 
+      break;
+    case  CGLFLOW_ROW_SUMVARUB:
+      ++numSUMVARUB; 
+      break;
+    case  CGLFLOW_ROW_SUMVAREQ:
+      ++numSUMVAREQ; 
+      break;
+    case  CGLFLOW_ROW_UNINTERSTED:
+      ++numUNINTERSTED;
+      break;
+    default:
+      throw CoinError("Unknown row type", "flowPreprocess",
+		      "CglFlowCover");
+    }
+    
+  }
+  delete [] ind;  ind  = NULL;
+  delete [] coef; coef = NULL;
+
+  if(CGLFLOW_DEBUG) {
+    std::cout << "The num of rows = "  << numRows        << std::endl;
+    std::cout << "Summary of Row Type" << std::endl;
+    std::cout << "numUNDEFINED     = " << numUNDEFINED   << std::endl;
+    std::cout << "numVARUB         = " << numVARUB       << std::endl;
+    std::cout << "numVARLB         = " << numVARLB       << std::endl;
+    std::cout << "numVAREQ         = " << numVAREQ       << std::endl;
+    std::cout << "numMIXUB         = " << numMIXUB       << std::endl;
+    std::cout << "numMIXEQ         = " << numMIXEQ       << std::endl;
+    std::cout << "numNOBINUB       = " << numNOBINUB     << std::endl;
+    std::cout << "numNOBINEQ       = " << numNOBINEQ     << std::endl;
+    std::cout << "numSUMVARUB      = " << numSUMVARUB    << std::endl;
+    std::cout << "numSUMVAREQ      = " << numSUMVAREQ    << std::endl;
+    std::cout << "numUNINTERSTED   = " << numUNINTERSTED << std::endl;
+  }
+
+  //---------------------------------------------------------------------------
+  // Setup  vubs_ and vlbs_
+  if (vubs_ != 0) { delete [] vubs_; vubs_ = 0; }
+  vubs_ = new CglFlowVUB [numCols];      // Destructor will free memory
+  if (vlbs_ != 0) { delete [] vlbs_; vlbs_ = 0; }
+  vlbs_ = new CglFlowVLB [numCols];      // Destructor will free memory
+
+  for (iCol = 0; iCol < numCols; ++iCol) {   // Initilized in constructor
+    vubs_[iCol].setVar(UNDEFINED_);     // but, need redo since may call
+    vlbs_[iCol].setVar(UNDEFINED_);     // preprocess(...) more than once
+  }
+  
+  for (iRow = 0; iRow < numRows; ++iRow) {
+	
+    CglFlowRowType rowType2 = rowTypes_[iRow];
+    
+    if ( (rowType2 == CGLFLOW_ROW_VARUB) || 
+	 (rowType2 == CGLFLOW_ROW_VARLB) || 
+	 (rowType2 == CGLFLOW_ROW_VAREQ) )  { 
+      
+      int startPos = rowStarts[iRow];
+      int index0   = colInds[startPos];
+      int index1   = colInds[startPos + 1];
+      double coef0 = coefByRow[startPos];
+      double coef1 = coefByRow[startPos + 1];
+	    
+      int    xInd,  yInd;   // x is binary
+      double xCoef, yCoef;
+
+      if ( columnType[index0]==1 ) {
+	xInd  = index0;   yInd  = index1;
+	xCoef = coef0;    yCoef = coef1;
+      }
+      else {
+	xInd  = index1;   yInd  = index0;
+	xCoef = coef1;    yCoef = coef0;
+      }
+
+      switch (rowType2) {
+      case CGLFLOW_ROW_VARUB:       // Inequality: y <= ? * x
+	vubs_[yInd].setVar(xInd);
+	vubs_[yInd].setVal(-xCoef / yCoef);
+	break;
+      case CGLFLOW_ROW_VARLB:       // Inequality: y >= ? * x
+	vlbs_[yInd].setVar(xInd);
+	vlbs_[yInd].setVal(-xCoef / yCoef);
+	break;
+      case CGLFLOW_ROW_VAREQ:       // Inequality: y >= AND <= ? * x
+	vubs_[yInd].setVar(xInd);
+	vubs_[yInd].setVal(-xCoef / yCoef);
+	vlbs_[yInd].setVar(xInd);
+	vlbs_[yInd].setVal(-xCoef / yCoef);
+	break;
+      default:
+	throw CoinError("Unknown row type: impossible", 
+			"flowPreprocess", "CglFlowCover");
+      }
+    }
+  }
+
+  if(CGLFLOW_DEBUG) {
+    printVubs(std::cout);
+  }
+}
+
+
+//-----------------------------------------------------------------------------
+// Generate LSGFC cuts
+//------------------------------------------------------------------- 
+void CglFlowCover::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+				const CglTreeInfo info)
+{
+  static int count=0;
+  if (getMaxNumCuts() <= 0) return;
+    
+  if (getNumFlowCuts() >= getMaxNumCuts()) return;
+  ++count;
+
+#if 0
+  bool preInit = false;
+  bool preReso = false;
+  si.getHintParam(OsiDoPresolveInInitial, preInit);
+  si.getHintParam(OsiDoPresolveInResolve, preReso);
+
+  if (preInit == false &&  preReso == false) { // Do once
+    if (doneInitPre_ == false) {   
+      flowPreprocess(si);
+      doneInitPre_ = true;
+    }
+  }
+  else
+#endif
+    int numberRowCutsBefore = cs.sizeRowCuts();
+    
+  flowPreprocess(si);
+
+  CoinPackedMatrix matrixByRow(*si.getMatrixByRow());
+  const char* sense = si.getRowSense();
+  const double* rhs = si.getRightHandSide();
+
+  const double* elementByRow = matrixByRow.getElements();
+  const int* colInd = matrixByRow.getIndices();
+  const CoinBigIndex* rowStart = matrixByRow.getVectorStarts();
+  const int* rowLength = matrixByRow.getVectorLengths();
+    
+  int* ind        = 0;
+  double* coef    = 0;
+  int iRow, iCol;
+
+  CglFlowRowType rType;
+
+  for (iRow = 0; iRow < numRows_; ++iRow) {
+    rType = getRowType(iRow);
+    if( ( rType != CGLFLOW_ROW_MIXUB ) &&
+	( rType != CGLFLOW_ROW_MIXEQ ) &&
+	( rType != CGLFLOW_ROW_NOBINUB ) &&
+	( rType != CGLFLOW_ROW_NOBINEQ ) &&
+	( rType != CGLFLOW_ROW_SUMVARUB ) &&
+	( rType != CGLFLOW_ROW_SUMVAREQ ) )
+      continue;  
+
+    const int sta = rowStart[iRow];     // Start position of iRow
+    const int rowLen = rowLength[iRow]; // iRow length / non-zero elements
+
+    if (ind != 0) { delete [] ind; ind = 0; }
+    ind = new int [rowLen];
+    if (coef != 0) { delete [] coef; coef = 0; }
+    coef = new double [rowLen];
+
+    int lastPos = sta + rowLen;
+    for (iCol = sta; iCol < lastPos; ++iCol) {
+      ind[iCol - sta]  = colInd[iCol];
+      coef[iCol - sta] = elementByRow[iCol];
+    }
+
+    OsiRowCut flowCut1, flowCut2, flowCut3;
+    double violation = 0.0;
+    bool hasCut = false;
+
+    if (sense[iRow] == 'E') {
+      hasCut = generateOneFlowCut(si, rowLen, ind, coef, 'L', 
+				  rhs[iRow], flowCut1, violation);
+      if (hasCut)  {                         // If find a cut
+	cs.insert(flowCut1);
+	incNumFlowCuts();
+	if (getNumFlowCuts() >= getMaxNumCuts())
+	  break;
+      }
+      hasCut = false;
+      hasCut = generateOneFlowCut(si, rowLen, ind, coef, 'G', 
+				  rhs[iRow], flowCut2, violation);
+      if (hasCut)  {
+	cs.insert(flowCut2);
+	incNumFlowCuts();
+	if (getNumFlowCuts() >= getMaxNumCuts())
+	  break;
+      }
+    }
+    if (sense[iRow] == 'L' || sense[iRow] == 'G') {
+      hasCut = generateOneFlowCut(si, rowLen, ind, coef, sense[iRow], 
+				  rhs[iRow], flowCut3, violation);
+      if (hasCut)  {
+	cs.insert(flowCut3);
+	incNumFlowCuts();
+	if (getNumFlowCuts() >= getMaxNumCuts())
+	  break;
+      }
+    }
+  }
+
+
+#ifdef CGLFLOW_DEBUG2
+  if(CGLFLOW_DEBUG) {
+    std::cout << "\nnumFlowCuts = "<< getNumFlowCuts()  << std::endl;
+    std::cout << "CGLFLOW_COL_BINNEG = "<< CGLFLOW_COL_BINNEG  << std::endl;
+  }
+#endif
+  if (!info.inTree&&((info.options&4)==4||((info.options&8)&&!info.pass))) {
+    int numberRowCutsAfter = cs.sizeRowCuts();
+    for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++)
+      cs.rowCutPtr(i)->setGloballyValid();
+  }
+
+  if (ind != 0)  { delete [] ind; ind = 0; }
+  if (coef != 0) { delete [] coef; coef = 0; }
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglFlowCover::CglFlowCover()
+  :
+  CglCutGenerator(),
+  maxNumCuts_(2000),
+  EPSILON_(1.0e-6),
+  UNDEFINED_(-1),
+  INFTY_(1.0e30),
+  TOLERANCE_(0.05),
+  firstProcess_(true),
+  numRows_(0),
+  numCols_(0),
+  doneInitPre_(false),
+  vubs_(0),
+  vlbs_(0),
+  rowTypes_(0)
+{ 
+  // DO NOTHING
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglFlowCover::CglFlowCover (const CglFlowCover & source)
+  :
+  CglCutGenerator(source), 
+  maxNumCuts_(source.maxNumCuts_),
+  EPSILON_(source.EPSILON_),
+  UNDEFINED_(source.UNDEFINED_),
+  INFTY_(source.INFTY_),
+  TOLERANCE_(source.TOLERANCE_),
+  firstProcess_(true),
+  numRows_(source.numRows_),
+  numCols_(source.numCols_),
+  doneInitPre_(source.doneInitPre_)
+{ 
+  setNumFlowCuts(source.numFlowCuts_);
+  if (numCols_ > 0) {
+    vubs_ = new CglFlowVUB [numCols_];
+    vlbs_ = new CglFlowVLB [numCols_];
+    CoinDisjointCopyN(source.vubs_, numCols_, vubs_);
+    CoinDisjointCopyN(source.vlbs_, numCols_, vlbs_);
+  }
+  else {
+    vubs_ = 0;
+    vlbs_ = 0;
+  }
+  if (numRows_ > 0) {
+    rowTypes_ = new CglFlowRowType [numRows_];
+    CoinDisjointCopyN(source.rowTypes_, numRows_, rowTypes_);
+  }
+  else {
+    rowTypes_ = 0;
+  }
+}
+
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglFlowCover::clone() const
+{
+  return new CglFlowCover(*this);
+}
+
+//------------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglFlowCover &
+CglFlowCover::operator=(const CglFlowCover& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    maxNumCuts_ = rhs.maxNumCuts_;
+    EPSILON_ = rhs.EPSILON_;
+    UNDEFINED_ = rhs.UNDEFINED_;
+    INFTY_ = rhs.INFTY_;
+    TOLERANCE_ = rhs.TOLERANCE_;
+    numRows_ = rhs.numRows_;
+    numCols_ = rhs.numCols_;
+    //    numFlowCuts_ = rhs.numFlowCuts_;
+    setNumFlowCuts(rhs.numFlowCuts_);
+    doneInitPre_ = rhs.doneInitPre_;
+    if (numCols_ > 0) {
+      vubs_ = new CglFlowVUB [numCols_];
+      vlbs_ = new CglFlowVLB [numCols_];
+      CoinDisjointCopyN(rhs.vubs_, numCols_, vubs_);
+      CoinDisjointCopyN(rhs.vlbs_, numCols_, vlbs_);
+    }
+    if (numRows_ > 0) {
+      rowTypes_ = new CglFlowRowType [numRows_];
+      CoinDisjointCopyN(rhs.rowTypes_, numRows_, rowTypes_);
+    }
+  }
+  return *this;
+}
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------  
+CglFlowCover::~CglFlowCover ()
+{
+  if (vubs_ != 0) { delete [] vubs_; vubs_ = 0; }
+  if (vlbs_ != 0) { delete [] vlbs_; vlbs_ = 0; }
+  if (rowTypes_ != 0) { delete [] rowTypes_; rowTypes_ = 0; } 
+}
+
+
+//-------------------------------------------------------------------
+//  Given the model data, a row of the model, and a LP solution, 
+//  this function tries to generate a violated lifted simple generalized 
+//  flow cover.
+//-------------------------------------------------------------------  
+bool 
+CglFlowCover::generateOneFlowCut( const OsiSolverInterface & si, 
+				  const int rowLen,
+				  int* ind,
+				  double* coef,
+				  char sense,
+				  double rhs,
+				  OsiRowCut& flowCut,
+				  double& violation )
+{
+  bool generated       = false;
+  const double* xlp    = si.getColSolution();
+  const int numCols    = si.getNumCols();
+    
+  double* up           = new double [rowLen];
+  double* x            = new double [rowLen];
+  double* y            = new double [rowLen];
+  CglFlowColType* sign = new CglFlowColType [rowLen];
+    
+  int i, j;  
+  double value, LB, UB;
+    
+  CglFlowVLB VLB;
+  CglFlowVUB VUB;
+  static int count=0;
+  ++count;
+  CGLFLOW_DEBUG=false;
+  doLift=true;
+  // Get integer types
+  const char * columnType = si.getColType ();
+  for (i = 0; i < rowLen; ++i) {
+    if ( xlp[ind[i]] - floor(xlp[ind[i]]) > EPSILON_ && ceil(xlp[ind[i]]) - xlp[ind[i]] > EPSILON_ )
+      break;
+  }
+
+  if (i == rowLen)  {
+    delete [] sign;
+    delete [] up; 
+    delete [] x;   
+    delete [] y; 
+    return generated;
+  }
+
+  //-------------------------------------------------------------------------
+
+  if (sense == 'G') flipRow(rowLen, coef, rhs); // flips everything,
+  // but the sense
+					  
+
+  if(CGLFLOW_DEBUG) {
+    std::cout << "***************************" << std::endl;
+    std::cout << "Generate Flow cover -- initial constraint, converted to L sense..." << std::endl;
+    std::cout << "Rhs = " << rhs << std::endl;
+    std::cout << "coef [var_index]" << " -- " <<  "xlp[var_index]" << '\t' << "vub_coef[vub_index] vub_lp_value OR var_index_col_ub" << std::endl;
+   
+    for(int iD = 0; iD < rowLen; ++iD) {
+      VUB = getVubs(ind[iD]);
+
+      std::cout << std::setw(5) << coef[iD] << "["  << std::setw(5)  << ind[iD] << "] -- " 
+		<< std::setw(20) << xlp[ind[iD]] << '\t';
+      if (VUB.getVar() != UNDEFINED_) {  
+	std::cout << std::setw(20) << VUB.getVal() << "[" << std::setw(5) << VUB.getVar() << "]" 
+		  << std::setw(20) << xlp[VUB.getVar()] << std::endl; 
+      }
+      else
+	std::cout << std::setw(20) << si.getColUpper()[ind[iD]] << "       " << std::setw(20) << 1.0 << std::endl;
+	
+    }
+  }
+
+  //-------------------------------------------------------------------------
+  // Generate conservation inequality and capacity equalities from 
+  // the given row.
+  
+  for (i = 0; i < rowLen; ++i) {
+	
+    VLB = getVlbs(ind[i]);
+    LB = ( VLB.getVar() != UNDEFINED_ ) ? 
+      VLB.getVal() : si.getColLower()[ind[i]];
+
+    VUB = getVubs(ind[i]);
+    UB = ( VUB.getVar() != UNDEFINED_ ) ? 
+      VUB.getVal() : si.getColUpper()[ind[i]];
+
+    if (LB < -EPSILON_) {   // Only consider rows whose variables are all
+      delete [] sign;       // non-negative (LB>= 0). 
+      delete [] up; 
+      delete [] x;   
+      delete [] y;  
+      return generated;     
+    }
+
+    if ( columnType[ind[i]]==1 ) {   // Binary variable
+      value = coef[i];
+      if (value > EPSILON_)
+	sign[i] = CGLFLOW_COL_BINPOS;
+      else {
+	sign[i] = CGLFLOW_COL_BINNEG;
+	value = -value;
+      }    
+      up[i] = value;
+      x[i] =  xlp[ind[i]];
+      y[i] = value * x[i];
+    }
+    else {   
+      value = coef[i];
+      if (value > EPSILON_)
+	sign[i] = CGLFLOW_COL_CONTPOS;
+      else {
+	sign[i] = CGLFLOW_COL_CONTNEG;
+	value = -value;
+      }
+      up[i] = value* UB;
+      x[i] = (VUB.getVar() != UNDEFINED_) ? xlp[VUB.getVar()] : 1.0;
+      y[i] = value * xlp[ind[i]];
+    }
+  }
+
+  //-------------------------------------------------------------------------
+  // Find a initial cover (C+, C-) in (N+, N-)
+  double  knapRHS   = rhs;
+  double  tempSum   = 0.0;
+  double  tempMin   = INFTY_;
+  CglFlowColCut *    candidate = new CglFlowColCut [rowLen];
+  CglFlowColCut *    label     = new CglFlowColCut [rowLen];
+  double* ratio     = new double [rowLen];
+  int t = -1;
+  for (i = 0; i < rowLen; ++i) {
+    candidate[i] = label[i] = CGLFLOW_COL_OUTCUT;
+    ratio[i] = INFTY_;
+	
+    switch(sign[i]) {
+    case CGLFLOW_COL_CONTPOS:
+    case CGLFLOW_COL_BINPOS:
+      if( y[i] > EPSILON_ ) {
+	ratio[i] = (1.0 - x[i]) / up[i];
+	if( y[i] > up[i] * x[i] - EPSILON_ ) {       // Violated
+	  candidate[i] = CGLFLOW_COL_PRIME;
+	  tempSum += up[i];
+	}
+	else {
+	  candidate[i] = CGLFLOW_COL_SECONDARY;
+	}
+      }
+      break;
+    case CGLFLOW_COL_CONTNEG:
+    case CGLFLOW_COL_BINNEG:
+      if( up[i] > ( (1.0 - EPSILON_) * INFTY_ ) ) {  // UB is infty
+	label[i] = CGLFLOW_COL_INCUT;
+      }
+      else {
+	knapRHS += up[i];
+	if( y[i] < up[i] ) {
+	  candidate[i] = CGLFLOW_COL_PRIME;
+	  ratio[i] = x[i] / up[i];
+	  tempSum += up[i];
+	}
+      }
+      break;
+    }    
+  }
+    
+  double diff, tempD, lambda;
+  int xID = -1;
+  if (knapRHS >1.0e10) {
+    if(CGLFLOW_DEBUG) {
+      std::cout << "knapsack RHS too large. RETURN." << std::endl; 
+    }
+    delete [] sign;                              
+    delete [] up; 
+    delete [] x;   
+    delete [] y;  
+    delete [] candidate;
+    delete [] label;
+    delete [] ratio;
+    return generated;
+  }
+
+  while (tempSum < knapRHS + EPSILON_) { // Not a cover yet
+    diff = INFTY_;
+    for (i = 0; i < rowLen; ++i) {
+      if (candidate[i] == CGLFLOW_COL_SECONDARY) {
+	tempD = up[i] * x[i] - y[i];
+	if (tempD < diff - EPSILON_) {
+	  diff = tempD;
+	  xID = i;
+	}
+      }
+    }
+    
+    if( diff > (1.0 - EPSILON_) * INFTY_  ) {   // NO cover exits.
+      delete [] sign;                              
+      delete [] up; 
+      delete [] x;   
+      delete [] y;  
+      delete [] candidate;
+      delete [] label;
+      delete [] ratio;
+      return generated;
+    }
+    else {
+      tempSum += up[xID];
+      candidate[xID] = CGLFLOW_COL_PRIME;
+    }
+  }
+
+  // Solve the knapsack problem to get an initial cover
+  tempSum = 0.0;
+  for (i = 0; i < rowLen; ++i) {
+    if (candidate[i] == CGLFLOW_COL_PRIME && ratio[i] < EPSILON_) {
+      //Zero ratio
+      label[i] = CGLFLOW_COL_INCUT;
+      tempSum += up[i];
+    }
+  }
+  
+  while (tempSum < knapRHS + EPSILON_) {
+    tempMin = INFTY_;
+    xID=-1;
+    for (i = 0; i < rowLen; i++) {   // Search the col with  minimum ratio
+      if (candidate[i] == CGLFLOW_COL_PRIME && label[i] == 0 && 
+	  ratio[i] < tempMin) {
+	tempMin = ratio[i];  
+	xID = i; 
+      }
+    }
+    if (xID>=0) {
+      label[xID] = CGLFLOW_COL_INCUT;
+      tempSum += up[xID];
+    } else {
+      if(CGLFLOW_DEBUG) {
+	std::cout << "knapsack RHS too large B. RETURN." << std::endl; 
+      }
+      delete [] sign;                              
+      delete [] up; 
+      delete [] x;   
+      delete [] y;  
+      delete [] candidate;
+      delete [] label;
+      delete [] ratio;
+      return generated;
+    }
+  }
+  
+  // Reduce to a minimal cover
+  for (i = 0; i < rowLen; ++i) {
+    if (label[i] == CGLFLOW_COL_INCUT && ratio[i] > EPSILON_) {
+      if (tempSum - up[i] > knapRHS + EPSILON_) {
+	label[i] = CGLFLOW_COL_OUTCUT;
+	tempSum -= up[i];
+      }
+    }
+  }
+  for (i = 0; i < rowLen; ++i) {
+    if (label[i] == CGLFLOW_COL_INCUT && ratio[i] < EPSILON_) {
+      if (tempSum - up[i] > knapRHS + EPSILON_) {
+	label[i] = CGLFLOW_COL_OUTCUT;
+	tempSum -= up[i];
+      }
+    }
+  }
+    
+  // Due to the way to handle N-
+  for(i = 0; i < rowLen; ++i) {
+    if( sign[i] < 0 ) 
+      label[i] = label[i]==CGLFLOW_COL_OUTCUT?CGLFLOW_COL_INCUT:CGLFLOW_COL_OUTCUT;
+  }
+
+  // No cover, no cut. 
+  bool emptyCover = true; 
+  for (i = 0; i < rowLen; ++i) {
+    if (label[i] == CGLFLOW_COL_INCUT) {
+      emptyCover = false; 
+      break;
+    }
+  }
+  if (emptyCover) {	
+    if(CGLFLOW_DEBUG) {
+      std::cout << "No cover. RETURN." << std::endl; 
+    }
+    delete [] sign;                              
+    delete [] up; 
+    delete [] x;   
+    delete [] y;  
+    delete [] candidate;
+    delete [] label;
+    delete [] ratio;
+    return generated;  
+  }
+
+  lambda = tempSum - knapRHS;
+
+  if(CGLFLOW_DEBUG) {
+    double sum_mj_Cplus = 0.0;
+    double sum_mj_Cminus= 0.0;
+    // double checkLambda; // variable not used anywhere (LL)
+    // print out the knapsack variables
+    std::cout << "Knapsack Cover: C+" << std::endl;
+    for (i = 0; i < rowLen; ++i) { 
+      if ( label[i] == CGLFLOW_COL_INCUT && sign[i] > 0 ) {
+	std::cout << ind[i] << '\t' << up[i] << std::endl;
+	sum_mj_Cplus += up[i];
+      }
+    } 
+    std::cout << "Knapsack Cover: C-" << std::endl;
+    for (i = 0; i < rowLen; ++i) { 
+      if ( label[i] == CGLFLOW_COL_INCUT && sign[i] < 0 ) {
+	std::cout << ind[i] << '\t' << up[i] << std::endl;
+	sum_mj_Cminus += up[i];
+      }
+    }
+
+    // rlh: verified "lambda" is lambda in the paper.
+    // lambda = (sum coefficients in C+) - (sum of VUB
+    // coefficients in C-) - rhs-orig-constraint
+    std::cout << "lambda = " << lambda << std::endl;
+  }
+
+  //-------------------------------------------------------------------------
+  // Generate a violated SGFC
+
+  int numCMinus = 0;
+  int numPlusPlus = 0;
+  double* rho     = new double [rowLen];
+  double* xCoef   = new double [rowLen]; 
+  double* yCoef   = new double [rowLen];
+  double cutRHS   = rhs;
+  double temp     = 0.0;
+  double sum      = 0.0;
+  double minPlsM  = INFTY_;
+  double minNegM  = INFTY_;
+
+  for(i = 0; i < rowLen; ++i) {
+    rho[i]   = 0.0;
+    xCoef[i] = 0.0;
+    yCoef[i] = 0.0;
+  }
+    
+  // Project out variables in C-
+  // d^' = d + sum_{i in C^-} m_i. Now cutRHS = d^'
+  for (i = 0; i < rowLen; ++i) { 
+    if ( label[i] == CGLFLOW_COL_INCUT && sign[i] < 0 ) {
+      cutRHS += up[i];
+      ++numCMinus;
+    }
+  }
+
+  // (1) Compute the coefficients of the simple generalized flow cover
+  // (2) Compute minPlsM, minNegM and sum
+  //
+  // sum = sum_{i in C+\C++} m_i + sum_{i in L--} m_i = m. Page 15.
+  // minPlsM = min_{i in C++} m_i
+  // minNegM = min_{i in L-} m_i
+
+  temp = cutRHS;
+    
+  for (i = 0; i < rowLen; ++i) {
+    if (label[i] == CGLFLOW_COL_INCUT  && sign[i] > 0) { // C+
+      yCoef[i] = 1.0;
+      if ( up[i] > lambda + EPSILON_ ) { // C++
+	++numPlusPlus;
+	xCoef[i] = lambda - up[i];
+	cutRHS += xCoef[i];
+	if( up[i] < minPlsM ) {
+	  minPlsM = up[i];
+	}
+      }
+      else {  // C+\C++
+	xCoef[i] = 0.0;  // rlh: is this necesarry? (xCoef initialized to zero)
+	sum += up[i];
+      } 
+    }
+	
+    if (label[i] != CGLFLOW_COL_INCUT && sign[i] < 0) { // N-\C-
+      temp += up[i];
+      if ( up[i] > lambda) {      // L-
+	if(CGLFLOW_DEBUG) {
+	  std::cout << "Variable " << ind[i] << " is in L-" << std::endl;
+	}
+	yCoef[i] = 0.0;
+	xCoef[i] = -lambda;
+	label[i] = CGLFLOW_COL_INLMIN;
+	if ( up[i] < minNegM ) { 
+	  minNegM = up[i];
+	}
+      }
+      else  {        // L--
+	if(CGLFLOW_DEBUG) {
+	  std::cout << "Variable " << ind[i] << " is in L-- " << std::endl;
+	}
+	yCoef[i] = -1.0;
+	xCoef[i] = 0.0; // rlh: is this necesarry? (xCoef initialized to zero)
+	label[i] = CGLFLOW_COL_INLMINMIN;
+	sum += up[i];
+      }
+    }
+  }
+   
+  // Sort the upper bounds (m_i) of variables in C++ and L-.
+
+  int     ix;
+  int     index  = 0;
+  double* mt     = new double [rowLen];
+  double* M      = new double [rowLen + 1];
+  // order to look at variables
+  int * order = new int [rowLen];
+  int nLook=0;
+  for (int i = 0; i < rowLen; ++i) {
+    if ( (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) || 
+	 label[i] == CGLFLOW_COL_INLMIN ) {     //  C+ || L- 
+      // possible
+      M[nLook]=-up[i];
+      order[nLook++]=i;
+    }
+  }
+  CoinSort_2(M,M+nLook,order);
+  int kLook=0;
+  
+  while (kLook<nLook) {
+    ix = UNDEFINED_;
+    i = order[kLook];
+    kLook++;
+    if ( (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) || 
+	 label[i] == CGLFLOW_COL_INLMIN ) {     //  C+ || L- 
+      if ( up[i] > lambda ) {       // C++ || L-(up[i] > lambda)
+	ix = i;
+      }
+    }
+      
+    if( ix == UNDEFINED_ )  break;
+      
+    mt[index++] = up[ix];  // Record m_i in C++ and L-(not all) in descending order.
+	
+    if( label[ix] == CGLFLOW_COL_INLMIN )  
+      label[ix] = CGLFLOW_COL_INLMINDONE;
+    else
+      label[ix] = CGLFLOW_COL_INCUTDONE;
+  }
+  //printf("mins %g %g\n",minNegM,minPlsM);
+  if( index == 0 || numPlusPlus == 0) {
+    // No column in C++ and L-(not all). RETURN.
+    if(CGLFLOW_DEBUG) {
+      std::cout << "index = 0. RETURN." << std::endl; 
+    }
+    delete [] sign;
+    delete [] up; 
+    delete [] x;   
+    delete [] y;  
+    delete [] candidate;
+    delete [] label;
+    delete [] ratio;
+    delete [] rho;
+    delete [] xCoef;
+    delete [] yCoef;
+    delete [] mt; 
+    delete [] M; 
+    delete [] order;
+    return generated;
+  }
+
+  for ( i = 0; i < rowLen; i++ ) {
+    switch( label[i] ) {
+    case  CGLFLOW_COL_INCUTDONE:
+      label[i] = CGLFLOW_COL_INCUT;
+      break;
+    case  CGLFLOW_COL_INLMIN:
+    case  CGLFLOW_COL_INLMINDONE:
+    case  CGLFLOW_COL_INLMINMIN:
+      label[i] = CGLFLOW_COL_OUTCUT;
+      break;
+    case CGLFLOW_COL_INCUT:
+    case CGLFLOW_COL_OUTCUT:
+    case CGLFLOW_COL_PRIME:
+    case CGLFLOW_COL_SECONDARY:
+      break;
+    }
+  }
+    
+  /* Get t */
+  t = 0;
+  for ( i = 0; i < index; ++i ) {
+    if ( mt[i] < minPlsM ) {
+      t = i;
+      break;
+    } 
+  }
+
+  if (i == index) {
+    t = index;
+  }
+    
+  /* Compute M_i */
+  M[0] = 0.0;
+  for ( i = 1; i <= index; ++i ) {
+    M[i] = M[(i-1)] + mt[(i-1)];
+    if(CGLFLOW_DEBUG) {
+      std::cout << "t = " << t << std::endl; 
+      std::cout << "mt[" << std::setw(5) << (i-1) << "]=" << std::setw(2) << ", M[" << std::setw(5) << i << "]=" << std::setw(20) << M[i] << std::endl;
+    }
+  }
+  // Exit if very big M
+  if (M[index]>1.0e30) { // rlh: should test for huge col UB earler 
+    // no sense doing all this work in that case.
+    if(CGLFLOW_DEBUG) {
+      std::cout << "M[index]>1.0e30. RETURN." << std::endl; 
+      delete [] sign;
+      delete [] up; 
+      delete [] x;   
+      delete [] y;  
+      delete [] candidate;
+      delete [] label;
+      delete [] ratio;
+      delete [] rho;
+      delete [] xCoef;
+      delete [] yCoef;
+      delete [] mt; 
+      delete [] M; 
+      delete [] order;
+      return generated;
+    }
+  }
+
+  /* Get ml */
+  double ml = CoinMin(sum, lambda);
+  if(CGLFLOW_DEBUG) {
+    // sum = sum_{i in C+\C++} m_i + sum_{i in L--} m_i = m. Page 15.
+    std::cout << "ml = CoinMin(m, lambda) = CoinMin(" << sum << ", " << lambda << ") =" << ml << std::endl; 
+  }
+  /* rho_i = max[0, m_i - (minPlsM - lamda) - ml */
+  if (t < index ) { /* rho exits only for t <= index-1 */
+    value = (minPlsM - lambda) + ml;
+    for (i = t; i < index; ++i) {
+      rho[i] =  CoinMax(0.0, mt[i] - value);
+      if(CGLFLOW_DEBUG) {
+	std::cout << "rho[" << std::setw(5) << i << "]=" << std::setw(20) << rho[i] << std::endl;
+      }
+    }
+  }
+  // Calculate the violation
+  violation = -cutRHS;
+  for ( i = 0; i < rowLen; ++i ) {
+#ifdef CGLFLOW_DEBUG2
+    if(CGLFLOW_DEBUG) {
+      std::cout << "i = " << i << " ind = " << ind[i] << " sign = " 
+		<< sign[i] 
+		<< " coef = " << coef[i] << " x = " << x[i] << " xCoef = " 
+		<< xCoef[i] << " y = " << y[i] << " yCoef = " << yCoef[i] 
+		<< " up = " << up[i] << " label = " << label[i] << std::endl;
+    }
+#endif
+    violation += y[i] * yCoef[i] + x[i] * xCoef[i];
+  }
+
+  if(CGLFLOW_DEBUG) {
+    std::cout << "violation = " << violation << std::endl;
+  }
+  //  double violationBeforeLift=violation; // variable not used anywhere (LL)
+  if(doLift && fabs(violation) > TOLERANCE_ ) {  // LIFTING
+    double estY, estX;
+    double movement = 0.0;
+    double dPrimePrime = temp + cutRHS; 
+    bool lifted = false;
+    for( i = 0; i < rowLen; ++i ) {
+      if ( (label[i] != CGLFLOW_COL_INCUT) && (sign[i] > 0) ) {/* N+\C+*/
+	lifted = liftPlus(estY, estX,
+			  index, up[i],
+			  lambda,
+			  y[i], x[i], 
+			  dPrimePrime, M);
+	    
+	xCoef[i] = -estX;
+	yCoef[i] = estY;
+	if(CGLFLOW_DEBUG) {
+	  if (lifted) {
+	    printf("Success: Lifted col %i (up_i=%f,yCoef[i]=%f,xCoef[i]=%f) in N+\\C+\n", 
+		   ind[i], up[i], yCoef[i], xCoef[i]);
+	  }
+	  else {
+	    printf("Failed to Lift col %i (m_i=%f) in N+\\C+\n", 
+		   ind[i], up[i]);
+	  }       
+	}
+      }
+      if (label[i] == CGLFLOW_COL_INCUT && sign[i] < 0) { 
+	/* C- */
+	liftMinus(movement, t,
+		  index, up[i], 
+		  dPrimePrime, 
+		  lambda, ml,
+		  M, rho);
+                
+	if(movement > EPSILON_) {
+	  if(CGLFLOW_DEBUG) {
+	    printf("Success: Lifted col %i in C-, movement=%f\n", 
+		   ind[i], movement);
+	  }
+	  lifted = true;
+	  xCoef[i] = -movement;
+	  cutRHS -= movement;
+	}
+	else {
+	  if(CGLFLOW_DEBUG) {
+	    printf("Failed to Lift col %i in C-, g=%f\n",
+		   ind[i], movement);
+	  }
+	}
+      }
+    }
+  }
+  //-------------------------------------------------------------------
+
+    
+  // Calculate the violation
+  violation = -cutRHS;
+  for ( i = 0; i < rowLen; ++i ) {
+#ifdef CGLFLOW_DEBUG2
+    if(CGLFLOW_DEBUG) {
+      std::cout << "i = " << i << " ind = " << ind[i] << " sign = " 
+		<< sign[i] 
+		<< " coef = " << coef[i] << " x = " << x[i] << " xCoef = " 
+		<< xCoef[i] << " y = " << y[i] << " yCoef = " << yCoef[i] 
+		<< " up = " << up[i] << " label = " << label[i] << std::endl;
+    }
+#endif
+    violation += y[i] * yCoef[i] + x[i] * xCoef[i];
+  }
+
+  if(CGLFLOW_DEBUG) {
+    std::cout << "violation = " << violation << std::endl;
+  }
+    
+  int     cutLen     = 0;
+  int*    cutInd     = 0;
+  double* cutCoef    = 0;
+
+  // If violated, transform the inequality back to original system
+  if ( violation > TOLERANCE_ ) {
+    cutLen = 0;
+    cutInd  = new int [3*numCols];
+    cutCoef = new double [3*numCols];
+      
+	  assert (cutLen<numCols);
+    for ( i = 0; i < rowLen; ++i )  {
+      VUB = getVubs(ind[i]);
+      
+      if ( ( sign[i] == CGLFLOW_COL_CONTPOS ) || 
+	   ( sign[i] == CGLFLOW_COL_CONTNEG ) ) {
+
+	if ( fabs( yCoef[i] ) > EPSILON_ ) {
+		    
+	  if ( sign[i] == CGLFLOW_COL_CONTPOS ) 
+	    cutCoef[cutLen] = coef[i] * yCoef[i];
+	  else 
+	    cutCoef[cutLen] = -coef[i] * yCoef[i];
+	  cutInd[cutLen++] = ind[i];
+	}
+
+	if ( fabs( xCoef[i] ) > EPSILON_ ) {
+	  if ( VUB.getVar() != UNDEFINED_ ) {
+	    cutCoef[cutLen] = xCoef[i];
+	    cutInd[cutLen++] = VUB.getVar();
+	  }
+	  else
+	    cutRHS -= xCoef[i];
+	}
+      }
+            
+      if ( ( sign[i] == CGLFLOW_COL_BINPOS ) || 
+	   ( sign[i] == CGLFLOW_COL_BINNEG ) ) {
+	if (fabs(yCoef[i]) > EPSILON_ || fabs(xCoef[i]) > EPSILON_) {
+	  if (sign[i] == CGLFLOW_COL_BINPOS) 
+	    cutCoef[cutLen] = coef[i] * yCoef[i] + xCoef[i];
+	  else 
+	    cutCoef[cutLen] = -coef[i] * yCoef[i] + xCoef[i];
+	  cutInd[cutLen++] = ind[i];
+	}
+      }
+    }
+#if 1
+    assert (cutLen);
+    CoinShortSort_2(cutInd,cutInd+cutLen,cutCoef);
+    j=0;
+    int lastInd=cutInd[0];
+    double lastCoef=cutCoef[0];
+    for ( i = 1; i < cutLen+1; ++i ) {
+      if (i==cutLen||cutInd[i]>lastInd) {
+	if ( fabs(lastCoef) >= EPSILON_ ) {
+	  cutCoef[j]=lastCoef;
+	  cutInd[j++]=lastInd;
+	  lastCoef = cutCoef[i];
+	  if (i<cutLen)
+	    lastInd=cutInd[i];
+	}
+      } else {
+	lastCoef += cutCoef[i];
+      }
+    }
+#else
+    for ( i = 0; i < cutLen; ++i ) {
+      for ( j = 0; j < i; j++ ) {
+	if ( cutInd[j] == cutInd[i] ) { /* Duplicate*/
+	  cutCoef[j] += cutCoef[i];
+	  cutInd[i] = -1;
+	}
+      }
+    }
+
+    for ( j = 0, i = 0; i < cutLen; ++i ) {
+      if ( ( cutInd[i] == -1 ) || ( fabs( cutCoef[i]) < EPSILON_ ) ){
+	/* Small coeff*/
+      }
+      else {
+	cutCoef[j] = cutCoef[i];
+	cutInd[j] = cutInd[i];
+	j++;
+      }
+    }
+#endif
+    cutLen = j;
+    // Skip if no elements ? - bug somewhere
+    assert (cutLen);
+        
+    // Recheck the violation.
+    violation = 0.0;
+    for (i = 0; i < cutLen; ++i) 
+      violation += cutCoef[i] * xlp[cutInd[i]];
+    
+    violation -= cutRHS;
+
+    if ( violation > TOLERANCE_ ) {
+      flowCut.setRow(cutLen, cutInd, cutCoef);
+      flowCut.setLb(-1.0 * si.getInfinity());
+      flowCut.setUb(cutRHS);
+      flowCut.setEffectiveness(violation);
+      generated = true;
+
+      if(CGLFLOW_DEBUG) {
+	std::cout << "generateOneFlowCover(): Found a cut" << std::endl;
+      }
+    }
+    else {
+      if(CGLFLOW_DEBUG) {
+	std::cout << "generateOneFlowCover(): Lost a cut" << std::endl;
+      }
+    }
+  }
+
+  //-------------------------------------------------------------------------
+  delete [] sign;
+  delete [] up; 
+  delete [] x;   
+  delete [] y;  
+  delete [] candidate;
+  delete [] label;
+  delete [] ratio;
+  delete [] rho;
+  delete [] xCoef;
+  delete [] yCoef;
+  delete [] mt; 
+  delete [] M; 
+  delete [] order;
+  delete [] cutInd;
+  delete [] cutCoef;
+    
+  return generated;
+}
+
+
+//-------------------------------------------------------------------
+// Flip a row from ">=" to "<=", and vice versa. 
+//-------------------------------------------------------------------
+void 
+CglFlowCover::flipRow(int rowLen, double* coef, double& rhs) const
+{
+  for(int i = 0; i < rowLen; ++i) coef[i] = -coef[i]; 
+  rhs = -rhs;  
+}
+
+//-------------------------------------------------------------------
+// Flip a row from ">=" to "<=", and vice versa. Have 'sense'.
+//-------------------------------------------------------------------
+void 
+CglFlowCover::flipRow(int rowLen, double* coef, char& sen,
+		      double& rhs) const
+{
+  for(int i = 0; i < rowLen; ++i) coef[i] = -coef[i]; 
+  sen = (sen == 'G') ?  'L' : 'G';
+  rhs = -rhs;  
+}
+
+//-------------------------------------------------------------------
+// Determine the type of a given row 
+//-------------------------------------------------------------------
+CglFlowRowType
+CglFlowCover::determineOneRowType(const OsiSolverInterface& si,
+				  int rowLen, int* ind, 
+				  double* coef, char sense, 
+				  double rhs) const
+{
+  if (rowLen == 0) 
+    return CGLFLOW_ROW_UNDEFINED;
+    
+  CglFlowRowType rowType = CGLFLOW_ROW_UNDEFINED;
+  // Get integer types
+  const char * columnType = si.getColType ();
+    
+  int  numPosBin = 0;      // num of positive binary variables
+  int  numNegBin = 0;      // num of negative binary variables
+  int  numBin    = 0;      // num of binary variables
+  int  numPosCol = 0;      // num of positive variables
+  int  numNegCol = 0;      // num of negative variables
+  int  i;
+  bool flipped = false;
+
+  // Range row will only consider as 'L'
+  if (sense == 'G') {        // Transform to " <= "
+    flipRow(rowLen, coef, sense, rhs);                
+    flipped = true;
+  }
+    
+  // Summarize the variable types of the given row.
+  for ( i = 0; i < rowLen; ++i ) {
+    if ( coef[i] < -EPSILON_ ) {
+      ++numNegCol;
+      if( columnType[ind[i]]==1 )
+	++numNegBin;
+    }
+    else {
+      ++numPosCol;
+      if( columnType[ind[i]]==1 )
+	++numPosBin;    
+    }
+  }
+  numBin = numNegBin + numPosBin;
+
+  if(CGLFLOW_DEBUG) {
+    std::cout << "numNegBin = " << numNegBin << std::endl;
+    std::cout << "numPosBin = " << numPosBin << std::endl;
+    std::cout << "numBin = " << numBin << std::endl;
+    std::cout << "rowLen = " << rowLen << std::endl;
+  }
+    
+    
+  //------------------------------------------------------------------------
+  // Classify row type based on the types of variables.
+    
+  // All variables are binary. NOT interested in this type of row right now
+  if (numBin == rowLen) 
+    rowType = CGLFLOW_ROW_UNINTERSTED;
+
+  // All variables are NOT binary
+  if (rowType == CGLFLOW_ROW_UNDEFINED && numBin == 0) {
+    if (sense == 'L')
+      rowType = CGLFLOW_ROW_NOBINUB;
+    else 
+      rowType = CGLFLOW_ROW_NOBINEQ;
+  }
+
+  // There are binary and other types of variables   
+  if (rowType == CGLFLOW_ROW_UNDEFINED) {  
+    if ((rhs < -EPSILON_) || (rhs > EPSILON_) || (numBin != 1)) {
+      if (sense == 'L')
+	rowType = CGLFLOW_ROW_MIXUB;
+      else 
+	rowType = CGLFLOW_ROW_MIXEQ;
+    }
+    else {                               // EXACTLY one binary
+      if (rowLen == 2) {               // One binary and one other type
+	if (sense == 'L') {
+	  if (numNegCol == 1 && numNegBin == 1)
+	    rowType = CGLFLOW_ROW_VARUB;
+	  if (numPosCol == 1 && numPosBin == 1)
+	    rowType = CGLFLOW_ROW_VARLB;
+	}
+	else
+	  rowType = CGLFLOW_ROW_VAREQ;
+      }
+      else {               // One binary and 2 or more other types
+	if (numNegCol==1 && numNegBin==1) {// Binary has neg coef and 
+	  if (sense == 'L')  // other are positive
+	    rowType = CGLFLOW_ROW_SUMVARUB;
+	  else
+	    rowType = CGLFLOW_ROW_SUMVAREQ;
+	}
+      }
+    }
+  }
+  
+  // Still undefined
+  if (rowType == CGLFLOW_ROW_UNDEFINED) {
+    if (sense == 'L') 
+      rowType = CGLFLOW_ROW_MIXUB;
+    else
+      rowType = CGLFLOW_ROW_MIXEQ;
+  }
+  if (flipped == true) {
+    flipRow(rowLen, coef, sense, rhs);                
+  }
+
+  return rowType;
+}
+
+/*===========================================================================*/
+
+void
+CglFlowCover::liftMinus(double &movement, /* Output */ 
+			int t,
+			int r,
+			double z,
+			double dPrimePrime, 
+			double lambda,
+			double ml,
+			double *M,
+			double *rho) const
+{
+  int i;
+  movement = 0.0;
+    
+  if (z > dPrimePrime) {
+    movement = z - M[r] + r * lambda;
+  }
+  else {
+    for (i = 0; i < t; ++i) {
+      if ( (z >= M[i]) && (z <= M[(i+1)] - lambda) ) {
+	movement = i * lambda;
+	return;
+      }
+    }
+        
+    for (i = 1; i < t; ++i) {
+      if ( (z >= M[i] - lambda) && (z <= M[i]) ) {
+	movement = z - M[i] + i * lambda;
+	return;
+      }
+    }
+        
+    for (i = t; i < r; ++i) {
+      if ( (z >= M[i] - lambda) && (z <= M[i] - lambda + ml + rho[i]) ) {
+	movement = z - M[i] + i * lambda;
+	return;
+      }
+    }
+        
+    for (i = t; i < r; ++i) {
+      if ( (z >= M[i]-lambda+ml+rho[i]) && (z <= M[(i+1)]-lambda) ) {
+	movement = i * lambda;
+	return;
+      }
+    }
+    
+    if ((z >= M[r] - lambda) && z <= dPrimePrime) {
+      movement = z - M[r] + r * lambda;
+    }
+  }
+    
+}
+
+/*===========================================================================*/
+
+bool
+CglFlowCover::liftPlus(double &alpha, 
+		       double &beta,
+		       int r,
+		       double m_j, 
+		       double lambda,
+		       double y_j,
+		       double x_j,
+		       double dPrimePrime,
+		       double *M) const
+{
+  int i;
+  bool status = false;  /* Default: fail to lift */
+  double value;
+  alpha = 0.0;
+  beta = 0.0;
+    
+  if (m_j > M[r] - lambda + EPSILON_) {
+    if (m_j < dPrimePrime - EPSILON_) {
+      if ((m_j > (M[r] - lambda)) && (m_j <= M[r])){ /* FIXME: Test */
+	value = y_j - x_j * (M[r] - r * lambda);
+                
+	/* FIXME: Is this "if" useful */
+	if (value > 0.0) {
+	  status = true;
+	  alpha = 1.0;
+	  beta = M[r] - r * lambda;
+	  if(CGLFLOW_DEBUG) {
+	    printf("liftPlus:1: value=%f, alpah=%f, beta=%f\n",
+		   value, alpha,beta);
+	  }
+	}
+	else {
+	  if(CGLFLOW_DEBUG) {
+	    printf("liftPlus:1: value=%f, become worst\n",value);
+	  }
+	}
+      }
+    }
+    else {    
+      if(CGLFLOW_DEBUG) {
+	printf("liftPlus:1: too big number\n");
+      }
+    }
+  }
+  else {
+    for (i = 1; i <= r; ++i) {
+      if ((m_j > (M[i] - lambda)) && (m_j <= M[i])){ /* FIXME: Test */
+                
+	value = y_j - x_j * (M[i] - i * lambda);
+
+	/* FIXME: Is this "if" useful */
+	if (value > 0.0) {
+	  status = true;
+	  alpha = 1.0;
+	  beta = M[i] - i * lambda;
+	  if(CGLFLOW_DEBUG) {
+	    printf("liftPlus:2: value=%f, alpah=%f, beta=%f\n",
+		   value, alpha, beta);
+	  }
+	}
+	else {
+	  if(CGLFLOW_DEBUG) {
+	    printf("liftPlus:2: value=%f, become worst\n",value);
+	  }
+	}
+	return status;
+      }
+    }
+  }
+    
+  return status;
+}
+// Create C++ lines to get to current state
+std::string
+CglFlowCover::generateCpp( FILE * fp) 
+{
+  CglFlowCover other;
+  fprintf(fp,"0#include \"CglFlowCover.hpp\"\n");
+  fprintf(fp,"3  CglFlowCover flowCover;\n");
+  if (maxNumCuts_!=other.maxNumCuts_)
+    fprintf(fp,"3  flowCover.setMaxNumCuts(%d);\n",maxNumCuts_);
+  else
+    fprintf(fp,"4  flowCover.setMaxNumCuts(%d);\n",maxNumCuts_);
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  flowCover.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  flowCover.setAggressiveness(%d);\n",getAggressiveness());
+  return "flowCover";
+}
+
diff --git a/cbits/coin/CglFlowCover.hpp b/cbits/coin/CglFlowCover.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglFlowCover.hpp
@@ -0,0 +1,371 @@
+// $Id: CglFlowCover.hpp 1123 2013-04-06 20:47:24Z stefan $
+//-----------------------------------------------------------------------------
+// name:     Cgl Lifted Simple Generalized Flow Cover Cut Generator
+// author:   Yan Xu                email: yan.xu@sas.com
+//           Jeff Linderoth        email: jtl3@lehigh.edu
+//           Martin Savelsberg     email: martin.savelsbergh@isye.gatech.edu
+// date:     05/01/2003
+// comments: please scan this file for '???' and read the comments
+//-----------------------------------------------------------------------------
+// Copyright (C) 2003, Yan Xu, Jeff Linderoth, Martin Savelsberg and others. 
+// All Rights Reserved.
+// This code is published under the Eclipse Public License.
+
+#ifndef CglFlowCover_H
+#define CglFlowCover_H
+
+#include <iostream>
+
+#include "CoinError.hpp"
+
+#include "CglCutGenerator.hpp"
+
+//=============================================================================
+
+//=============================================================================
+
+/** This enumerative constant describes the various col types.*/
+enum CglFlowColType {
+    /** The column(variable) is a negative binary variable.*/
+    CGLFLOW_COL_BINNEG  = -2,
+    /** The column is a negative continous variable.*/
+    CGLFLOW_COL_CONTNEG,
+    /** The column is a positive continous variable.*/
+    CGLFLOW_COL_CONTPOS =  1,
+    /** The column is a positive binary variable.*/
+    CGLFLOW_COL_BINPOS
+};
+
+enum CglFlowColStatus{
+};
+
+/** This enumerative constant describes the various stati of vars in 
+    a cut or not.*/
+enum CglFlowColCut{
+    /** The column is NOT in cover.*/
+    CGLFLOW_COL_OUTCUT = 0,
+    /** The column is in cover now. */
+    CGLFLOW_COL_INCUT,
+    /** The column is decided to be in cover. */
+    CGLFLOW_COL_INCUTDONE,
+    /** The column is in L-. */
+    CGLFLOW_COL_INLMIN,
+    /** The column is decided to be in L-. */
+    CGLFLOW_COL_INLMINDONE,
+    /** The column is in L--.*/
+    CGLFLOW_COL_INLMINMIN,
+    /** This enumerative constant describes the various stati of vars in 
+                   determining the cover.*/
+    /** The column is a prime candidate. */
+    CGLFLOW_COL_PRIME,
+    /** The column is a secondary candidate. */
+    CGLFLOW_COL_SECONDARY
+};
+
+/** This enumerative constant describes the various row types.*/
+enum CglFlowRowType {
+    /** The row type of this row is NOT defined yet.*/
+    CGLFLOW_ROW_UNDEFINED,
+    /** After the row is flipped to 'L', the row has exactly two variables: 
+	one is negative binary and the other is continous, and the RHS 
+	is zero.*/
+    CGLFLOW_ROW_VARUB,
+    /** After the row is flipped to 'L', the row has exactlytwo variables: 
+	one is positive binary and the other is continous, and the RHS 
+	is zero.*/
+    CGLFLOW_ROW_VARLB,
+    /** The row sense is 'E', the row has exactly two variables: 
+	one is binary and the other is a continous, and the RHS is zero.*/ 
+    CGLFLOW_ROW_VAREQ,
+    /** Rows can not be classfied into other types and the row sense 
+	is NOT 'E'.*/
+    CGLFLOW_ROW_MIXUB,
+    /** Rows can not be classfied into other types and the row sense is 'E'.*/
+    CGLFLOW_ROW_MIXEQ,
+    /** All variables are NOT binary and the row sense is NOT 'E'. */
+    CGLFLOW_ROW_NOBINUB,
+    /** All variables are NOT binary and the row sense is 'E'. */
+    CGLFLOW_ROW_NOBINEQ,
+    /** The row has one binary and 2 or more other types of variables and 
+	the row sense is NOT 'E'. */
+    CGLFLOW_ROW_SUMVARUB,
+    /** The row has one binary and 2 or more other types of variables and 
+	the row sense is 'E'. */
+    CGLFLOW_ROW_SUMVAREQ,
+    /** All variables are binary. */
+    CGLFLOW_ROW_UNINTERSTED
+};
+
+//=============================================================================
+
+/** Variable upper bound class. */
+class CglFlowVUB
+{
+protected:
+    int    varInd_;            /** The index of the associated 0-1 variable.*/
+    double upper_;             /** The Value of the associated upper bound.*/ 
+
+public:
+    CglFlowVUB() : varInd_(-1), upper_(-1) {}
+    
+    CglFlowVUB(const CglFlowVUB& source) { 
+	varInd_= source.varInd_; 
+	upper_ = source.upper_; 
+    } 
+    
+    CglFlowVUB& operator=(const CglFlowVUB& rhs) { 
+	if (this == &rhs) 
+	    return *this;
+	varInd_= rhs.varInd_; 
+	upper_ = rhs.upper_; 
+	return *this; 
+  }
+    
+    /**@name Query and set functions for associated 0-1 variable index 
+       and value.
+    */ 
+    //@{  
+    inline int    getVar() const          { return varInd_; }
+    inline double getVal() const          { return upper_; }
+    inline void   setVar(const int v)     { varInd_ = v; }
+    inline void   setVal(const double v)  { upper_ = v; }
+    //@}
+};
+
+//=============================================================================
+
+/** Variable lower bound class, which is the same as vub. */
+typedef CglFlowVUB CglFlowVLB;
+
+/** Overloaded operator<< for printing VUB and VLB.*/
+std::ostream& operator<<( std::ostream& os, const CglFlowVUB &v );
+
+//=============================================================================
+
+/** 
+ *  Lifed Simple Generalized Flow Cover Cut Generator Class. 
+ */
+class CglFlowCover : public CglCutGenerator {
+    friend void CglFlowCoverUnitTest(const OsiSolverInterface * siP,
+				     const std::string mpdDir );
+    
+public:
+    
+    /** 
+     *  Do the following tasks:
+     *  <ul>
+     *  <li> classify row types 
+     *  <li> indentify vubs and vlbs
+     *  </ul>
+     *  This function is called by 
+     *  <CODE>generateCuts(const OsiSolverInterface & si, OsiCuts & cs)</CODE>.
+   */
+    void flowPreprocess(const OsiSolverInterface& si);
+
+    /**@name Generate Cuts */
+    //@{
+    /** Generate Lifed Simple Generalized flow cover cuts for the model data 
+	contained in si. The generated cuts are inserted into and returned 
+	in the collection of cuts cs. 
+    */
+    virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			      const CglTreeInfo info = CglTreeInfo());
+    //@}
+
+    /**@name Functions to query and set maximum number of cuts can be 
+       generated. */
+    //@{
+    inline int getMaxNumCuts() const { return maxNumCuts_; }
+    inline void setMaxNumCuts(int mc) { maxNumCuts_ = mc; }
+    //@}
+  
+    /**@name Functions to query and set the number of cuts have been
+       generated. */
+    //@{
+    static int getNumFlowCuts() { return numFlowCuts_; }
+    static void setNumFlowCuts(int fc) { numFlowCuts_ = fc; }
+    static void incNumFlowCuts(int fc = 1) { numFlowCuts_ += fc; } 
+    //@}
+
+    //-------------------------------------------------------------------------
+    /**@name Constructors and destructors */
+    //@{
+    /// Default constructor 
+    CglFlowCover ();
+
+    /// Copy constructor 
+    CglFlowCover (
+	const CglFlowCover &);
+
+    /// Clone
+    virtual CglCutGenerator * clone() const;
+
+    /// Assignment operator 
+    CglFlowCover &
+    operator=(
+	const CglFlowCover& rhs);
+    
+    /// Destructor 
+    virtual
+    ~CglFlowCover ();
+    /// Create C++ lines to get to current state
+    virtual std::string generateCpp( FILE * fp);
+    //@}
+
+private:
+    //-------------------------------------------------------------------------
+    // Private member functions
+
+    /** Based a given row, a LP solution and other model data, this function
+	tries to generate a violated lifted simple generalized flow cover. 
+    */
+    bool generateOneFlowCut( const OsiSolverInterface & si, 
+			     const int rowLen,
+			     int* ind,
+			     double* coef,
+			     char sense,
+			     double rhs,
+			     OsiRowCut& flowCut,
+			     double& violation );
+
+
+    /** Transform a row from ">=" to "<=", and vice versa. */
+    void flipRow(int rowLen, double* coef, double& rhs) const;
+
+    /** Transform a row from ">=" to "<=", and vice versa. Have 'sense'. */
+    void flipRow(int rowLen, double* coef, char& sen, double& rhs) const;
+
+    /** Determine the type of a given row. */
+    CglFlowRowType determineOneRowType(const OsiSolverInterface& si,
+				       int rowLen, int* ind, 
+				       double* coef, char sen, 
+				       double rhs) const;
+    /** Lift functions */
+    void liftMinus(double &movement, /* Output */ 
+		   int t,
+		   int r,
+		   double z,
+		   double dPrimePrime, 
+		   double lambda,
+		    double ml,
+		   double *M,
+		   double *rho) const;
+
+    bool liftPlus(double &alpha, 
+		 double &beta,
+		 int r,
+		 double m_j, 
+		 double lambda,
+		 double y_j,
+		 double x_j,
+		 double dPrimePrime,
+		 double *M) const;
+    
+
+    //-------------------------------------------------------------------------
+    //**@name Query and set the row type of a givne row. */
+    //@{
+    inline const CglFlowRowType* getRowTypes() const 
+	{ return rowTypes_; }
+    inline CglFlowRowType getRowType(const int i) const 
+	{ return rowTypes_[i]; }
+    /** Set rowtypes, take over the ownership. */
+    inline void setRowTypes(CglFlowRowType* rt) 
+	{ rowTypes_ = rt; rt = 0; }  
+    inline void setRowTypes(const CglFlowRowType rt, const int i) {
+	if (rowTypes_ != 0) 
+	    rowTypes_[i] = rt;
+	else {
+	    std::cout << "ERROR: Should allocate memory for rowType_ before "
+		      << "using it " << std::endl;
+	    throw CoinError("Forgot to allocate memory for rowType_", 
+			    "setRowType", "CglFlowCover");
+	}
+    }
+    //@}
+    
+    //-------------------------------------------------------------------------
+    //**@name Query and set vubs. */
+    //@{
+    inline const CglFlowVUB* getVubs() const          { return vubs_; }
+    inline const CglFlowVUB& getVubs(int i) const     { return vubs_[i]; }
+    /** Set CglFlowVUBs,take over the ownership. */
+    inline void setVubs(CglFlowVUB* vubs) { vubs_ = vubs; vubs = 0; }
+    inline void setVubs(const CglFlowVUB& vub, int i) { 
+	if (vubs_ != 0) 
+	    vubs_[i] = vub;
+	else {
+	    std::cout << "ERROR: Should allocate memory for vubs_ before "
+		      << "using it " << std::endl;
+	    throw CoinError("Forgot to allocate memory for vubs_", "setVubs",
+			    "CglFlowCover");
+	}
+    }
+    inline void printVubs(std::ostream& os) const {
+	for (int i = 0; i < numCols_; ++i) {
+	    os << "ix: " << i << ", " << vubs_[i];
+	}
+    }
+    //@}
+
+    //-------------------------------------------------------------------------
+    //**@name Query and set vlbs. */
+    //@{
+    inline const CglFlowVLB* getVlbs() const          { return vlbs_; }
+    inline const CglFlowVLB& getVlbs(int i) const     { return vlbs_[i]; }
+    /** Set CglFlowVLBs,take over the ownership. */
+    inline void setVlbs(CglFlowVLB* vlbs)          { vlbs_ = vlbs; vlbs = 0; }
+    inline void setVlbs(const CglFlowVLB& vlb, int i) { 
+	if (vlbs_ != 0) 
+	    vlbs_[i] = vlb;
+	else {
+	    std::cout << "ERROR: Should allocate memory for vlbs_ before "
+		      << "using it " << std::endl;
+	    throw CoinError("Forgot to allocate memory for vlbs_", "setVlbs",
+			    "CglFlowCover");
+	}
+    }
+    //@}
+
+private:
+    //------------------------------------------------------------------------
+    // Private member data
+    
+    /** The maximum number of flow cuts to be generated. Default is 1000. */
+    int maxNumCuts_;
+    /** Tolerance used for numerical purpose. */
+    double EPSILON_;
+    /** The variable upper bound of a flow is not indentified yet.*/
+    int UNDEFINED_;
+    /** Very large number. */
+    double INFTY_;
+    /** If violation of a cut is greater that this number, the cut is useful.*/
+    double TOLERANCE_;
+    /** First time preprocessing */
+    bool firstProcess_;
+    /** The number rows of the problem.*/
+    int numRows_;
+    /** The number columns of the problem.*/
+    int numCols_;
+    /** The number flow cuts found.*/
+    static int numFlowCuts_;
+    /** Indicate whether initial flow preprecessing has been done. */
+    bool doneInitPre_;
+    /** The array of CglFlowVUBs. */
+    CglFlowVUB* vubs_;
+    /** The array of CglFlowVLBs. */
+    CglFlowVLB* vlbs_;
+    /** CglFlowRowType of the rows in model. */
+    CglFlowRowType* rowTypes_;
+};
+
+//#############################################################################
+/** A function that tests the methods in the CglFlowCover class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglFlowCoverUnitTest(const OsiSolverInterface * siP,
+			  const std::string mpdDir );
+
+#endif
diff --git a/cbits/coin/CglGMI.cpp b/cbits/coin/CglGMI.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglGMI.cpp
@@ -0,0 +1,1669 @@
+// Last edit: 02/05/2013
+//
+// Name:     CglGMI.cpp
+// Author:   Giacomo Nannicini
+//           Singapore University of Technology and Design, Singapore
+//           email: nannicini@sutd.edu.sg
+// Date:     11/17/09
+//-----------------------------------------------------------------------------
+// Copyright (C) 2009, Giacomo Nannicini.  All Rights Reserved.
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+#include <climits>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CoinFactorization.hpp"
+#include "CglGMI.hpp"
+#include "CoinFinite.hpp"
+
+//-------------------------------------------------------------------
+// Generate GMI cuts
+//------------------------------------------------------------------- 
+
+/***************************************************************************/
+CglGMI::CglGMI() : 
+  CglCutGenerator(),
+  param(),
+  nrow(0),
+  ncol(0),
+  colLower(NULL),
+  colUpper(NULL),
+  rowLower(NULL),
+  rowUpper(NULL),
+  rowRhs(NULL),
+  isInteger(NULL),
+  cstat(NULL),
+  rstat(NULL),
+  solver(NULL),
+  xlp(NULL),
+  rowActivity(NULL),
+  byRow(NULL),
+  byCol(NULL),
+  f0(0.0),
+  f0compl(0.0),
+  ratiof0compl(0.0)
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+  ,
+  trackRejection(false),
+  fracFail(0),
+  dynFail(0),
+  violFail(0),
+  suppFail(0),
+  scaleFail(0),
+  numGeneratedCuts(0)
+#endif
+{
+
+}
+
+/***************************************************************************/
+CglGMI::CglGMI(const CglGMIParam &parameters) : 
+  CglCutGenerator(),
+  param(parameters),
+  nrow(0),
+  ncol(0),
+  colLower(NULL),
+  colUpper(NULL),
+  rowLower(NULL),
+  rowUpper(NULL),
+  rowRhs(NULL),
+  isInteger(NULL),
+  cstat(NULL),
+  rstat(NULL),
+  solver(NULL),
+  xlp(NULL),
+  rowActivity(NULL),
+  byRow(NULL),
+  byCol(NULL),
+  f0(0.0),
+  f0compl(0.0),
+  ratiof0compl(0.0)
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+  ,
+  trackRejection(false),
+  fracFail(0),
+  dynFail(0),
+  violFail(0),
+  suppFail(0),
+  scaleFail(0),
+  numGeneratedCuts(0)
+#endif
+{
+
+}
+
+/***************************************************************************/
+CglGMI::CglGMI(const CglGMI& rhs) : 
+  CglCutGenerator(rhs),
+  param(rhs.param),
+  nrow(rhs.nrow),
+  ncol(rhs.ncol),
+  colLower(rhs.colLower),
+  colUpper(rhs.colUpper),
+  rowLower(rhs.rowLower),
+  rowUpper(rhs.rowUpper),
+  rowRhs(rhs.rowRhs),
+  isInteger(rhs.isInteger),
+  cstat(rhs.cstat),
+  rstat(rhs.rstat),
+  solver(rhs.solver),
+  xlp(rhs.xlp),
+  rowActivity(rhs.rowActivity),
+  byRow(rhs.byRow),
+  byCol(rhs.byCol),
+  f0(rhs.f0),
+  f0compl(rhs.f0compl),
+  ratiof0compl(rhs.ratiof0compl)
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+  ,
+  trackRejection(rhs.trackRejection),
+  fracFail(rhs.fracFail),
+  dynFail(rhs.dynFail),
+  violFail(rhs.violFail),
+  suppFail(rhs.suppFail),
+  scaleFail(rhs.scaleFail),
+  numGeneratedCuts(rhs.numGeneratedCuts)
+#endif
+{
+
+}
+
+/***************************************************************************/
+CglGMI & CglGMI::operator=(const CglGMI& rhs) {
+  if(this != &rhs){
+    CglCutGenerator::operator=(rhs);
+    param = rhs.param;
+    nrow = rhs.nrow;
+    ncol = rhs.ncol;
+    colLower = rhs.colLower;
+    colUpper = rhs.colUpper;
+    rowLower = rhs.rowLower;
+    rowUpper = rhs.rowUpper;
+    rowRhs = rhs.rowRhs;
+    isInteger = rhs.isInteger;
+    cstat = rhs.cstat;
+    rstat = rhs.rstat;
+    solver = rhs.solver;
+    xlp = rhs.xlp;
+    rowActivity = rhs.rowActivity;
+    byRow = rhs.byRow;
+    byCol = rhs.byCol;
+    f0 = rhs.f0;
+    f0compl = rhs.f0compl;
+    ratiof0compl = rhs.ratiof0compl;
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+    trackRejection = rhs.trackRejection;
+    fracFail = rhs.fracFail;
+    dynFail = rhs.dynFail;
+    violFail = rhs.violFail;
+    suppFail = rhs.suppFail;
+    scaleFail = rhs.scaleFail;
+    numGeneratedCuts = rhs.numGeneratedCuts;
+#endif						
+  }
+  return *this;
+}
+
+/***************************************************************************/
+CglGMI::~CglGMI() {
+
+}
+
+/*********************************************************************/
+CglCutGenerator *
+CglGMI::clone() const
+{
+  return new CglGMI(*this);
+}
+
+/***************************************************************************/
+
+// Returns (value - floor)
+inline double CglGMI::aboveInteger(double value) const {
+  return (value - floor(value));
+} /* aboveInteger */
+
+/**********************************************************/
+void CglGMI::printvecINT(const char *vecstr, const int *x, int n) const {
+  int num, fromto, upto;
+
+  num = (n/10) + 1;
+  printf("%s :\n", vecstr);
+  for (int j = 0; j < num; ++j) {
+    fromto = 10*j;
+    upto = 10 * (j+1);
+    if(n <= upto) upto = n;
+    for (int i = fromto; i < upto; ++i)
+      printf(" %4d", x[i]);
+    printf("\n");
+  }
+  printf("\n");
+} /* printvecINT */
+
+/**********************************************************/
+void CglGMI::printvecDBL(const char *vecstr, const double *x, int n) const
+{
+  int num, fromto, upto;
+
+  num = (n/10) + 1;
+  printf("%s :\n", vecstr);
+  for (int j = 0; j < num; ++j) {
+    fromto = 10*j;
+    upto = 10 * (j+1);
+    if(n <= upto) upto = n;
+    for (int i = fromto; i < upto; ++i)
+      printf(" %7.3f", x[i]);
+    printf("\n");
+  }
+  printf("\n");
+} /* printvecDBL */
+
+/**********************************************************/
+void CglGMI::printvecDBL(const char *vecstr, const double *elem, 
+			 const int * index, int nz) const
+{
+  printf("%s\n", vecstr);
+  int written = 0;
+  for (int j = 0; j < nz; ++j) {
+    written += printf("%d:%.3f ", index[j], elem[j]);
+    if (written > 70) {
+      printf("\n");
+      written = 0;
+    }
+  }
+  if (written > 0) {
+    printf("\n");
+  }
+
+} /* printvecDBL */
+
+/************************************************************************/
+inline bool CglGMI::computeCutFractionality(double varRhs, 
+					    double& cutRhs) {
+  f0 = aboveInteger(varRhs);
+  f0compl = 1 - f0;
+  if (f0 < param.getAway() || f0compl < param.getAway())
+    return false;
+  ratiof0compl = f0/f0compl;
+  cutRhs = -f0;
+  return true;
+} /* computeCutFractionality */
+
+/************************************************************************/
+inline double CglGMI::computeCutCoefficient(double rowElem, int index) {
+  
+  // See Wolsey "Integer Programming" (1998), p. 130, fourth line from top
+  // after correcting typo (Proposition 8.8), flipping all signs to get <=.
+
+  if (index < ncol && isInteger[index]) {
+    double f = aboveInteger(rowElem);
+    if(f > f0) {
+      return (-((1-f) * ratiof0compl));
+    }
+    else {
+      return (-f);
+    }
+  }
+  else{
+    if(rowElem < 0) {
+      return (rowElem*ratiof0compl);
+    }
+    else {
+      return (-rowElem);
+    }
+  }
+  
+} /* computeCutCoefficient */
+
+/************************************************************************/
+inline void CglGMI::eliminateSlack(double cutElem, int index, double* cut,
+				   double& cutRhs, const double *elements, 
+				   const int *rowStart, const int *indices, 
+				   const int *rowLength, const double *rhs) {
+
+  // now i is where coefficients on slack variables begin;
+  // eliminate the slacks
+  int rowpos = index - ncol;
+  if(fabs(cutElem) > param.getEPS_ELIM()) {
+    if (areEqual(rowLower[rowpos], rowUpper[rowpos], 
+		 param.getEPS(), param.getEPS())) {
+      // "almost" fixed slack, we'll just skip it
+      return;
+    }
+
+    int upto = rowStart[rowpos] + rowLength[rowpos];
+    for (int j = rowStart[rowpos]; j < upto; ++j) {
+      cut[indices[j]] -= cutElem * elements[j];      
+    }
+    cutRhs -= cutElem * rhs[rowpos];
+  }
+
+} /* eliminateSlack */
+
+/************************************************************************/
+inline void CglGMI::flip(double& rowElem, int index) {  
+  if ((index < ncol && cstat[index] == 2) ||
+      (index >= ncol && rstat[index-ncol] == 2)) {
+      rowElem = -rowElem;
+  }
+} /* flip */
+
+/************************************************************************/
+inline void CglGMI::unflipOrig(double& rowElem, int index, double& rowRhs) {
+  if (cstat[index] == 2) {
+    // structural variable at upper bound
+    rowElem = -rowElem;
+    rowRhs += rowElem*colUpper[index];
+  }
+  else if (cstat[index] == 3) {
+    // structural variable at lower bound
+    rowRhs += rowElem*colLower[index];
+  }
+} /* unflipOrig */
+
+/************************************************************************/
+inline void CglGMI::unflipSlack(double& rowElem, int index, double& rowRhs, 
+				const double* slackVal) {
+  if (rstat[index-ncol] == 2) {
+    // artificial variable at upper bound
+    rowElem = -rowElem;
+    rowRhs += rowElem*slackVal[index-ncol];
+  }
+  else if (rstat[index-ncol] == 3) {
+    // artificial variable at lower bound
+    rowRhs += rowElem*slackVal[index-ncol];
+  }
+
+} /* unflipSlack */
+
+/************************************************************************/
+inline void CglGMI::packRow(double* row, double* rowElem, int* rowIndex,
+			     int& rowNz) {
+  rowNz = 0;
+  for (int i = 0; i < ncol; ++i) {
+    if (!isZero(fabs(row[i]))) {
+      rowElem[rowNz] = row[i];
+      rowIndex[rowNz] = i;
+      rowNz++;
+    }
+  }
+}
+
+/************************************************************************/
+bool CglGMI::cleanCut(double* cutElem, int* cutIndex, int& cutNz,
+		       double& cutRhs, const double* xbar) {
+  CglGMIParam::CleaningProcedure cleanProc = param.getCLEAN_PROC();
+  if (cleanProc == CglGMIParam::CP_CGLLANDP1) {
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+    relaxRhs(cutRhs);
+    removeSmallCoefficients(cutElem, cutIndex, cutNz, cutRhs);
+    if (!checkSupport(cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: too large support\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	suppFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkDynamism(cutElem, cutIndex, cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad dynamism\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	dynFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation (final check)\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+  } /* end of cleaning procedure CP_CGLLANDP1 */
+  else if (cleanProc == CglGMIParam::CP_CGLLANDP2) {
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+    relaxRhs(cutRhs);
+    if (!checkDynamism(cutElem, cutIndex, cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad dynamism\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	dynFail++;
+      }
+#endif
+      return false;
+    }
+    if (!scaleCut(cutElem, cutIndex, cutNz, cutRhs, 1) &&
+	param.getENFORCE_SCALING()) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad scaling\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	scaleFail++;
+      }
+#endif
+      return false;
+    }
+    removeSmallCoefficients(cutElem, cutIndex, cutNz, cutRhs);
+    if (!checkSupport(cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: too large support\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	suppFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation (final check)\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+  } /* end of cleaning procedure CP_CGLLANDP2 */
+  else if (cleanProc == CglGMIParam::CP_CGLREDSPLIT) {
+    if (!scaleCut(cutElem, cutIndex, cutNz, cutRhs, 3) &&
+	param.getENFORCE_SCALING()) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad scaling\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	scaleFail++;
+      }
+#endif
+      return false;
+    }
+    removeSmallCoefficients(cutElem, cutIndex, cutNz, cutRhs);
+    if (!checkDynamism(cutElem, cutIndex, cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad dynamism\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	dynFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkSupport(cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: too large support\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	suppFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation (final check)\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+    relaxRhs(cutRhs);
+  } /* end of cleaning procedure CP_CGLREDSPLIT */
+  else if (cleanProc == CglGMIParam::CP_INTEGRAL_CUTS) {
+    removeSmallCoefficients(cutElem, cutIndex, cutNz, cutRhs);
+    if (!checkSupport(cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: too large support\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	suppFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkDynamism(cutElem, cutIndex, cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad dynamism\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	dynFail++;
+      }
+#endif
+      return false;
+    }
+    if (!scaleCut(cutElem, cutIndex, cutNz, cutRhs, 0) &&
+	param.getENFORCE_SCALING()) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad scaling\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	scaleFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation (final check)\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+  } /* end of cleaning procedure CP_INTEGRAL_CUTS */
+  else if (cleanProc == CglGMIParam::CP_CGLLANDP1_INT) {
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+    removeSmallCoefficients(cutElem, cutIndex, cutNz, cutRhs);
+    if (!checkSupport(cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: too large support\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	suppFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkDynamism(cutElem, cutIndex, cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad dynamism\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	dynFail++;
+      }
+#endif
+      return false;
+    }
+    // scale cut so that it becomes integral, if possible
+    if (!scaleCut(cutElem, cutIndex, cutNz, cutRhs, 0)) {
+      if (param.getENFORCE_SCALING()){
+#if defined GMI_TRACE_CLEAN
+	printf("CglGMI::cleanCut(): cut discarded: bad scaling\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+	if (trackRejection) {
+	  scaleFail++;
+	}
+#endif
+	return false;
+      }
+      else {
+	// If cannot scale to integral and not enforcing, relax rhs
+	// (as per CglLandP cleaning procedure)
+	relaxRhs(cutRhs);
+      }
+    }
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation (final check)\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+  } /* end of cleaning procedure CP_CGLLANDP1_INT */
+  else if (cleanProc == CglGMIParam::CP_CGLLANDP1_SCALEMAX ||
+	   cleanProc == CglGMIParam::CP_CGLLANDP1_SCALERHS) {
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+    if (// Try to scale cut, but do not discard if cannot scale
+	((cleanProc == CglGMIParam::CP_CGLLANDP1_SCALEMAX &&
+	  !scaleCut(cutElem, cutIndex, cutNz, cutRhs, 1)) ||
+	 (cleanProc == CglGMIParam::CP_CGLLANDP1_SCALERHS &&
+	  !scaleCut(cutElem, cutIndex, cutNz, cutRhs, 2))) &&
+	param.getENFORCE_SCALING()) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad scaling\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	scaleFail++;
+      }
+#endif
+      return false;
+    }
+    relaxRhs(cutRhs);
+    removeSmallCoefficients(cutElem, cutIndex, cutNz, cutRhs);
+    if (!checkSupport(cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: too large support\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	suppFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkDynamism(cutElem, cutIndex, cutNz)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad dynamism\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	dynFail++;
+      }
+#endif
+      return false;
+    }
+    if (!checkViolation(cutElem, cutIndex, cutNz, cutRhs, xbar)) {
+#if defined GMI_TRACE_CLEAN
+      printf("CglGMI::cleanCut(): cut discarded: bad violation (final check)\n");
+#endif
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {
+	violFail++;
+      }
+#endif
+      return false;
+    }
+  } /* end of cleaning procedures CP_CGLLANDP1_SCALEMAX and CG_CGLLANDP1_SCALERHS */
+  return true;
+}
+
+/************************************************************************/
+bool CglGMI::checkViolation(const double* cutElem, const int* cutIndex,
+			     int cutNz, double cutrhs, const double* xbar) {
+  double lhs = 0.0;
+  for (int i = 0; i < cutNz; ++i) {
+    lhs += cutElem[i]*xbar[cutIndex[i]];
+  }
+  double violation = lhs - cutrhs;
+  if (fabs(cutrhs) > 1) {
+    violation /= fabs(cutrhs);
+  }
+  if (violation >= param.getMINVIOL()) {
+    return true;
+  }
+  else{
+#if defined GMI_TRACE_CLEAN
+    printf("Cut lhs %g, rhs %g, violation %g; cut discarded\n", lhs, cutrhs, violation);
+#endif
+    return false;
+  }
+} /* checkViolation */
+
+/************************************************************************/
+bool CglGMI::checkDynamism(const double* cutElem, const int* cutIndex,
+			   int cutNz) {
+  double min = param.getINFINIT();
+  double max = 0.0;
+  double val = 0.0;
+  for (int i = 0; i < cutNz; ++i) {
+    if (!isZero(cutElem[i])) {
+      val = fabs(cutElem[i]);
+      min = CoinMin(min, val);
+      max = CoinMax(max, val);
+    }
+  }
+  if (max > min*param.getMAXDYN()) {
+#if defined GMI_TRACE_CLEAN
+    printf("Max elem %g, min elem %g, dyn %g; cut discarded\n", max, min, max/min);
+#endif
+    return false;
+  }
+  else{
+    return true;
+  }
+  
+} /* checkDynamism */
+
+/************************************************************************/
+bool CglGMI::checkSupport(int cutNz) {
+  if (cutNz > param.getMAX_SUPPORT_ABS() + param.getMAX_SUPPORT_REL()*ncol) {
+#if defined GMI_TRACE_CLEAN
+    printf("Support %d; cut discarded\n", cutNz);
+#endif
+    return false;
+  }
+  else{
+    return true;
+  }
+}
+
+/************************************************************************/
+bool CglGMI::removeSmallCoefficients(double* cutElem, int* cutIndex, 
+				     int& cutNz, double& cutRhs) {
+  double value, absval;
+  int currPos = 0;
+  int col;
+  for (int i = 0; i < cutNz; ++i) {
+    col = cutIndex[i];
+    value = cutElem[i];
+    absval = fabs(value);
+    if (!isZero(absval) && absval <= param.getEPS_COEFF()) {
+      // small coefficient: remove and adjust rhs if possible
+      if ((value > 0.0) && (colLower[col] > -param.getINFINIT())) {
+        cutRhs -= value * colLower[col];
+      } 
+      else if ((value < 0.0) && (colUpper[col] < param.getINFINIT())) {
+        cutRhs -= value * colUpper[col];      
+      } 
+    }
+    else if (absval > param.getEPS_COEFF()) {
+      if (currPos < i) {
+	cutElem[currPos] = cutElem[i];
+	cutIndex[currPos] = cutIndex[i];
+      }
+      currPos++;
+    }
+  }
+  cutNz = currPos;
+  return true;
+}
+
+/************************************************************************/
+void CglGMI::relaxRhs(double& rhs) {
+  if(param.getEPS_RELAX_REL() > 0.0) {
+    rhs += fabs(rhs) * param.getEPS_RELAX_REL() + param.getEPS_RELAX_ABS();
+  }
+  else{
+    rhs += param.getEPS_RELAX_ABS();
+  }
+}
+
+/************************************************************************/
+bool CglGMI::scaleCut(double* cutElem, int* cutIndex, int cutNz,
+		       double& cutRhs, int scalingType) {
+  /// scalingType possible values:
+  /// 0 : scale to obtain integral cut
+  /// 1 : scale to obtain largest coefficient equal to 1
+  /// 2 : scale to obtain rhs equal to 1
+  /// 3 : scale based on norm, to obtain cut norm equal to ncol
+  /// Returns true if scaling is successful.
+  if (scalingType == 0) {
+    return scaleCutIntegral(cutElem, cutIndex, cutNz, cutRhs);
+  }
+  else if (scalingType == 1) {
+    double max = fabs(cutRhs);
+    for (int i = 0; i < cutNz; ++i) {
+      if (!isZero(cutElem[i])) {
+	max = CoinMax(max, fabs(cutElem[i]));
+      }
+    }
+    if (max < param.getEPS() || max > param.getMAXDYN()) {
+#if defined GMI_TRACE_CLEAN
+      printf("Scale %g; %g %g cut discarded\n", max, param.getEPS(), 1/param.getMAXDYN());
+#endif
+      return false;
+    }
+    else{
+      for (int i = 0; i < cutNz; ++i) {
+	cutElem[i] /= max;
+      }
+      cutRhs /= max;
+      return true;
+    }
+  }
+  else if (scalingType == 2) {
+    double max = fabs(cutRhs);
+    if (max < param.getEPS() || max > param.getMAXDYN()) {
+#if defined GMI_TRACE_CLEAN
+      printf("Scale %g; %g %g cut discarded\n", max, param.getEPS(), 1/param.getMAXDYN());
+#endif
+      return false;
+    }
+    else{
+      for (int i = 0; i < cutNz; ++i) {
+	cutElem[i] /= max;
+      }
+      cutRhs /= max;
+      return true;
+    }
+  }
+  else if (scalingType == 3) {
+    int support = 0;
+    double norm = 0.0;
+    for (int i = 0; i < cutNz; ++i) {
+      if (!isZero(fabs(cutElem[i]))) {
+	support++;
+	norm += cutElem[i]*cutElem[i];
+      }
+    }
+    double scale = sqrt(norm / support);
+    if ((scale < 0.02) || (scale > 100)) {
+#if defined GMI_TRACE_CLEAN
+      printf("Scale %g; cut discarded\n", scale);
+#endif
+      return false;
+    }
+    else{
+      for (int i = 0; i < cutNz; ++i) {
+	cutElem[i] /= scale;
+      }
+      cutRhs /= scale;
+      return true;
+    }
+  }
+  return false;
+} /* scaleCut */
+
+/************************************************************************/
+bool CglGMI::scaleCutIntegral(double* cutElem, int* cutIndex, int cutNz,
+			      double& cutRhs) {
+  long gcd, lcm;
+  double maxdelta = param.getEPS(); 
+  double maxscale = 1000; 
+  long maxdnom = 1000; 
+  long numerator = 0, denominator = 0;
+  // Initialize gcd and lcm
+  if (nearestRational(cutRhs, maxdelta, maxdnom, numerator, denominator)) {
+    gcd = labs(numerator);
+    lcm = denominator;
+  }
+  else{
+#if defined GMI_TRACE_CLEAN
+      printf("Cannot compute rational number, scaling procedure aborted\n");
+#endif
+    return false;
+  }
+  for (int i = 0; i < cutNz; ++i) {
+    if (solver->isContinuous(cutIndex[i]) && !param.getINTEGRAL_SCALE_CONT()) {
+      continue;
+    }
+    if(nearestRational(cutElem[i], maxdelta, maxdnom, numerator, denominator)) {
+      gcd = computeGcd(gcd,labs(numerator));
+      lcm *= denominator/(computeGcd(lcm,denominator));
+    }
+    else{
+#if defined GMI_TRACE_CLEAN
+      printf("Cannot compute rational number, scaling procedure aborted\n");
+#endif
+      return false;
+    } 
+  }
+  double scale = ((double)lcm)/((double)gcd);
+  if (fabs(scale) > maxscale) {
+#if defined GMI_TRACE_CLEAN
+      printf("Scaling factor too large, scaling procedure aborted\n");
+#endif
+      return false;
+  }
+  // Looks like we have a good scaling factor; scale and return;
+  for (int i = 0; i < cutNz; ++i) {
+    cutElem[i] *= scale;
+  }
+  cutRhs *= scale;
+  return true;
+} /* scaleCutIntegral */
+
+/************************************************************************/
+/* arguments:
+ * val = double precision value that must be converted
+ * maxdelta = max allowed difference between val and the rational computed
+ * maxdnom = max allowed denominator
+ * numerator = the numerator will be stored here if successful
+ * denominator = the denominator will be stored here if successful
+ * returns true if successful, false if not.
+ *
+ * This function is based on SCIPrealToRational() from SCIP, scip@zib.de.
+ * The copyright of SCIP and of this function belongs to ZIB.
+ * We explicitly obtained the rights to license this function under GPL 
+ * from ZIB. More information can be obtained from the authors.
+ *
+ * Copyright (C) 2012 Konrad-Zuse-Zentrum                           
+ *                    fuer Informationstechnik Berlin
+ */
+bool CglGMI::nearestRational(double val, double maxdelta, long maxdnom,
+			      long& numerator, long& denominator)
+{
+
+  /// Denominators that should be tried for the integral scaling phase.
+  /// These values are taken from SCIP.
+  static const double simplednoms[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 
+				       8.0, 9.0, 11.0, 12.0, 13.0, 14.0, 
+				       15.0, 16.0, 17.0, 18.0, 19.0, 25.0, 
+				       -1.0};
+
+  double a, b;
+  double g0, g1, gx;
+  double h0, h1, hx;
+  double delta0, delta1;
+  double epsilon;
+  int i;
+
+  /* try the simple denominators first: each value of the simplednoms table 
+   * multiplied by powers of 10 is tried as denominator
+   */
+  for (i = 0; simplednoms[i] > 0.0; ++i) {
+    double num, dnom;
+    double ratval0, ratval1;
+    double diff;
+    
+    /* try powers of 10 (including 10^0) */
+    dnom = simplednoms[i];
+    while (dnom <= maxdnom) {
+      num = floor(val * dnom);
+      ratval0 = num/dnom;
+      ratval1 = (num+1.0)/dnom;
+      diff = fabs(val - ratval0);
+      if (diff < maxdelta) {
+	numerator = (long)num;
+	denominator = (long)dnom;
+	return true;
+      }
+      diff = fabs(val - ratval1);
+      if (diff < maxdelta) {
+	numerator = (long)(num+1.0);
+	denominator = (long)dnom;
+	return true;
+      }
+      dnom *= 10.0;
+    }
+  }
+
+  /* the simple denominators didn't work: calculate rational
+   * representation with arbitrary denominator */
+  epsilon = maxdelta/2.0;
+
+  b = val;
+  a = floor(b + epsilon);
+  g0 = a;
+  h0 = 1.0;
+  g1 = 1.0;
+  h1 = 0.0;
+  delta0 = val - g0/h0;
+  delta1 = (delta0 < 0.0 ? val - (g0-1.0)/h0 : val - (g0+1.0)/h0);
+  
+  while ((fabs(delta0) > maxdelta) && (fabs(delta1) > maxdelta)) {
+    if ((b-a) < epsilon || h0 < 0 || h1 < 0)
+      return false;
+
+    b = 1.0 / (b - a);
+    a = floor(b + epsilon);
+    
+    if (a < 0.0)
+      return false;
+    gx = g0;
+    hx = h0;
+    
+    g0 = a * g0 + g1;
+    h0 = a * h0 + h1;
+    
+    g1 = gx;
+    h1 = hx;
+    
+    if (h0 > maxdnom)
+      return false;
+    
+    delta0 = val - g0/h0;
+    delta1 = (delta0 < 0.0 ? val - (g0-1.0)/h0 : val - (g0+1.0)/h0);
+  }
+
+  if (fabs(g0) > (LONG_MAX >> 4) || h0 > (LONG_MAX >> 4))
+    return false;
+
+  if (h0 > 0.5)
+    return false;
+
+  if (delta0 < -maxdelta) {
+    if (fabs(delta1) > maxdelta)
+      return false;
+    numerator = (long)(g0 - 1.0);
+    denominator = (long)h0;
+  }
+  else if (delta0 > maxdelta) {
+    if (fabs(delta1) > maxdelta)
+      return false;
+    numerator = (long)(g0 + 1.0);
+    denominator = (long)h0;
+  }
+  else{
+    numerator = (long)g0;
+    denominator = (long)h0;
+  }
+  if ((denominator < 1) || 
+      (fabs(val - (double)(numerator)/(double)(denominator)) > maxdelta))
+    return false;
+  return true;
+} /* nearestRational */
+
+/************************************************************************/
+long CglGMI::computeGcd(long a, long b) {
+  // This is the standard Euclidean algorithm for gcd
+  long remainder = 1;
+  // Make sure a<=b (will always remain so)
+  if (a > b) {
+    // Swap a and b
+    long temp = a;
+    a = b;
+    b = temp;
+  }
+  // If zero then gcd is nonzero
+  if (!a) {
+    if (b) {
+      return b;
+    } 
+    else {
+      printf("### WARNING: CglGMI::computeGcd() given two zeroes!\n");
+      exit(1);
+    }
+  }
+  while (remainder) {
+    remainder = b % a;
+    b = a;
+    a = remainder;
+  }
+  return b;
+} /* computeGcd */
+
+
+/************************************************************************/
+void CglGMI::generateCuts(const OsiSolverInterface &si, OsiCuts & cs,
+			  const CglTreeInfo )
+{
+  solver = const_cast<OsiSolverInterface *>(&si);
+  if (solver == NULL) {
+    printf("### WARNING: CglGMI::generateCuts(): no solver available.\n");
+    return;    
+  }  
+
+  if (!solver->optimalBasisIsAvailable()) {
+    printf("### WARNING: CglGMI::generateCuts(): no optimal basis available.\n");
+    return;
+  }
+
+#if defined OSI_TABLEAU
+  if (!solver->canDoSimplexInterface()) {
+    printf("### WARNING: CglGMI::generateCuts(): solver does not provide simplex tableau.\n");
+    printf("### WARNING: CglGMI::generateCuts(): recompile without OSI_TABLEAU.\n");
+    return;
+  }
+#endif
+  
+
+  // Get basic problem information from solver
+  ncol = solver->getNumCols(); 
+  nrow = solver->getNumRows(); 
+  colLower = solver->getColLower();
+  colUpper = solver->getColUpper();
+  rowLower = solver->getRowLower();
+  rowUpper = solver->getRowUpper();
+  rowRhs = solver->getRightHandSide();
+
+  xlp = solver->getColSolution();
+  rowActivity = solver->getRowActivity();
+  byRow = solver->getMatrixByRow();
+  byCol = solver->getMatrixByCol();
+  
+  generateCuts(cs);
+
+} /* generateCuts */
+
+/************************************************************************/
+void CglGMI::generateCuts(OsiCuts &cs)
+{
+  isInteger = new bool[ncol]; 
+  
+  computeIsInteger();
+
+  cstat = new int[ncol];
+  rstat = new int[nrow];
+
+
+  solver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
+                                          // 2: upper 3: lower
+
+
+#if defined GMI_TRACETAB
+  printvecINT("cstat", cstat, ncol);
+  printvecINT("rstat", rstat, nrow);
+#endif
+
+  // list of basic integer fractional variables
+  int *listFracBasic = new int[nrow];
+  int numFracBasic = 0;
+  for (int i = 0; i < ncol; ++i) {
+    // j is the variable which is basic in row i
+    if ((cstat[i] == 1) && (isInteger[i])) {
+      if (CoinMin(aboveInteger(xlp[i]),
+		  1-aboveInteger(xlp[i])) > param.getAway()) {
+	listFracBasic[numFracBasic] = i;
+	numFracBasic++;
+      }
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      else if (trackRejection) {	
+	// Say that we tried to generate a cut, but it was discarded
+	// because of small fractionality
+	if (!isIntegerValue(xlp[i])) {
+	  fracFail++;
+	  numGeneratedCuts++;
+	}
+      }
+#endif
+    }
+  }
+
+#if defined GMI_TRACE
+  printf("CglGMI::generateCuts() : %d fractional rows\n", numFracBasic);
+#endif
+  
+  if (numFracBasic == 0) {
+    delete[] listFracBasic;
+    delete[] cstat;
+    delete[] rstat;
+    delete[] isInteger;
+    return;
+  }
+
+  // there are rows with basic integer fractional variables, so we can
+  // generate cuts
+
+  // Basis index for columns and rows; each element is -1 if corresponding
+  // variable is nonbasic, and contains the basis index if basic.
+  // The basis index is the row in which the variable is basic.
+  int* colBasisIndex = new int[ncol];
+  int* rowBasisIndex = new int[nrow];
+
+#if defined OSI_TABLEAU
+  memset(colBasisIndex, -1, ncol*sizeof(int));
+  memset(rowBasisIndex, -1, nrow*sizeof(int));
+  solver->enableFactorization();
+  int* basicVars = new int[nrow];
+  solver->getBasics(basicVars);
+  for (int i = 0; i < nrow; ++i) {
+    if (basicVars[i] < ncol) {
+      colBasisIndex[basicVars[i]] = i;
+    }
+    else {
+      rowBasisIndex[basicVars[i] - ncol] = i;
+    }
+  }
+#else
+  CoinFactorization factorization;
+  if (factorize(factorization, colBasisIndex, rowBasisIndex)) {
+    printf("### WARNING: CglGMI::generateCuts(): error during factorization!\n");
+    return;
+  }
+#endif
+
+
+  // cut in sparse form
+  double* cutElem = new double[ncol];
+  int* cutIndex = new int[ncol];
+  int cutNz = 0;
+  double cutRhs;
+
+  // cut in dense form
+  double* cut = new double[ncol];
+
+  double *slackVal = new double[nrow];
+
+  for (int i = 0; i < nrow; ++i) {
+    slackVal[i] = rowRhs[i] - rowActivity[i];
+  }
+
+#if defined OSI_TABLEAU
+  // Column part and row part of a row of the simplex tableau
+  double* tableauColPart = new double[ncol];
+  double* tableauRowPart = new double[nrow];
+#else
+  // Need some more data for simplex tableau computation
+  const int * row = byCol->getIndices();
+  const CoinBigIndex * columnStart = byCol->getVectorStarts();
+  const int * columnLength = byCol->getVectorLengths(); 
+  const double * columnElements = byCol->getElements();
+
+  // Create work arrays for factorization
+  // two vectors for updating: the first one is needed to do the computations
+  // but we do not use it, the second one contains a row of the basis inverse
+  CoinIndexedVector work;
+  CoinIndexedVector array;
+  // Make sure they large enough
+  work.reserve(nrow);
+  array.reserve(nrow);
+  int * arrayRows = array.getIndices();
+  double * arrayElements = array.denseVector();
+  // End of code to create work arrays
+  double one = 1.0;
+#endif
+
+  // Matrix elements by row for slack substitution
+  const double *elements = byRow->getElements();
+  const int *rowStart = byRow->getVectorStarts();
+  const int *indices = byRow->getIndices();
+  const int *rowLength = byRow->getVectorLengths(); 
+
+  // Indices of basic and slack variables, and cut elements
+  int iBasic, slackIndex;
+  double cutCoeff;
+  double rowElem;
+  // Now generate the cuts: obtain a row of the simplex tableau
+  // where an integer variable is basic and fractional, and compute the cut
+  for (int i = 0; i < numFracBasic; ++i) {
+    if (!computeCutFractionality(xlp[listFracBasic[i]], cutRhs)) {
+      // cut is discarded because of the small fractionalities involved
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+      if (trackRejection) {	
+	// Say that we tried to generate a cut, but it was discarded
+	// because of small fractionality
+	fracFail++;
+	numGeneratedCuts++;
+      }
+#endif
+      continue;
+    }
+
+    // the variable listFracBasic[i] is basic in row iBasic
+    iBasic = colBasisIndex[listFracBasic[i]];
+
+#if defined GMI_TRACE
+    printf("Row %d with var %d basic, f0 = %f\n", i, listFracBasic[i], f0);
+#endif
+
+#if defined OSI_TABLEAU
+    solver->getBInvARow(iBasic, tableauColPart, tableauRowPart);
+#else
+    array.clear();
+    array.setVector(1, &iBasic, &one);
+
+    factorization.updateColumnTranspose (&work, &array);
+
+    int numberInArray=array.getNumElements();
+#endif
+
+    // reset the cut
+    memset(cut, 0, ncol*sizeof(double));
+
+    // columns
+    for (int j = 0; j < ncol; ++j) {
+      if ((colBasisIndex[j] >= 0) || 
+	  (areEqual(colLower[j], colUpper[j], 
+		    param.getEPS(), param.getEPS()))) {
+	// Basic or fixed variable -- skip
+	continue;
+      }
+#ifdef OSI_TABLEAU
+      rowElem = tableauColPart[j];
+#else
+      rowElem = 0.0;
+      // add in row of tableau
+      for (int h = columnStart[j]; h < columnStart[j]+columnLength[j]; ++h) {
+	rowElem += columnElements[h]*arrayElements[row[h]];
+      }
+#endif
+      if (!isZero(fabs(rowElem))) {
+	// compute cut coefficient
+	flip(rowElem, j);
+	cutCoeff = computeCutCoefficient(rowElem, j);
+	if (isZero(cutCoeff)) {
+	  continue;
+	}
+	unflipOrig(cutCoeff, j, cutRhs);
+	cut[j] = cutCoeff;
+#if defined GMI_TRACE
+	printf("var %d, row %f, cut %f\n", j, rowElem, cutCoeff);
+#endif
+      }
+    }
+
+    // now do slacks part
+#if defined OSI_TABLEAU
+    for (int j = 0 ; j < nrow; ++j) {
+      // index of the row corresponding to the slack variable
+      slackIndex = j;
+      if (rowBasisIndex[j] >= 0) {
+	// Basic variable -- skip it
+	continue;
+      }
+      rowElem = tableauRowPart[j];
+#else
+    for (int j = 0 ; j < numberInArray ; ++j) {
+      // index of the row corresponding to the slack variable
+      slackIndex = arrayRows[j];
+      rowElem = arrayElements[slackIndex];
+#endif
+      if (!isZero(fabs(rowElem))) {
+	slackIndex += ncol;
+	// compute cut coefficient
+	flip(rowElem, slackIndex);
+	cutCoeff = computeCutCoefficient(rowElem, slackIndex);
+	if (isZero(fabs(cutCoeff))) {
+	  continue;
+	}
+	unflipSlack(cutCoeff, slackIndex, cutRhs, slackVal);
+	eliminateSlack(cutCoeff, slackIndex, cut, cutRhs,
+		       elements, rowStart, indices, rowLength, rowRhs);
+#if defined GMI_TRACE
+	printf("var %d, row %f, cut %f\n", slackIndex, rowElem, cutCoeff);
+#endif
+      }
+    }
+
+    packRow(cut, cutElem, cutIndex, cutNz);
+    if (cutNz == 0)
+      continue;
+
+#if defined GMI_TRACE
+    printvecDBL("final cut:", cutElem, cutIndex, cutNz);
+    printf("cutRhs: %f\n", cutRhs);
+#endif
+    
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+    if (trackRejection) {
+      numGeneratedCuts++;
+    }
+#endif
+    if (cleanCut(cutElem, cutIndex, cutNz, cutRhs, xlp) && cutNz > 0) {
+      OsiRowCut rc;
+      rc.setRow(cutNz, cutIndex, cutElem);
+      rc.setLb(-param.getINFINIT());
+      rc.setUb(cutRhs);
+      if (!param.getCHECK_DUPLICATES()) {
+	cs.insert(rc);
+      }
+      else{
+	cs.insertIfNotDuplicate(rc, CoinAbsFltEq(param.getEPS_COEFF()));
+      }
+    }
+
+  }
+
+#if defined GMI_TRACE
+  printf("CglGMI::generateCuts() : number of cuts : %d\n", cs.sizeRowCuts());
+#endif
+
+#if defined OSI_TABLEAU
+  solver->disableFactorization();
+  delete[] basicVars;
+  delete[] tableauColPart;
+  delete[] tableauRowPart;
+#endif
+
+  delete[] colBasisIndex;
+  delete[] rowBasisIndex;
+  delete[] cut;
+  delete[] slackVal;
+  delete[] cutElem;
+  delete[] cutIndex;
+  delete[] listFracBasic;
+  delete[] cstat;
+  delete[] rstat;
+  delete[] isInteger;
+
+} /* generateCuts */
+
+/***********************************************************************/
+void CglGMI::setParam(const CglGMIParam &source) {
+  param = source;
+} /* setParam */
+
+/***********************************************************************/
+void CglGMI::computeIsInteger() {
+  for (int i = 0; i < ncol; ++i) {
+    if(solver->isInteger(i)) {
+      isInteger[i] = true;
+    }
+    else {
+      if((areEqual(colLower[i], colUpper[i], 
+		   param.getEPS(), param.getEPS()))
+	 && (isIntegerValue(colUpper[i]))) {	
+	// continuous variable fixed to an integer value
+	isInteger[i] = true;
+      }
+      else {
+	isInteger[i] = false;
+      }
+    }
+  }    
+} /* computeIsInteger */
+
+/***********************************************************************/
+void CglGMI::printOptTab(OsiSolverInterface *lclSolver) const
+{
+  int *cstat = new int[ncol];
+  int *rstat = new int[nrow];
+
+  lclSolver->enableFactorization();
+  lclSolver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
+  // 2: upper 3: lower
+
+  int *basisIndex = new int[nrow]; // basisIndex[i] = 
+                                    //        index of pivot var in row i
+                                    //        (slack if number >= ncol) 
+  lclSolver->getBasics(basisIndex);
+
+  double *z = new double[ncol];  // workspace to get row of the tableau
+  double *slack = new double[nrow];  // workspace to get row of the tableau
+  double *slackVal = new double[nrow];
+
+  for (int i = 0; i < nrow; i++) {
+    slackVal[i] = rowRhs[i] - rowActivity[i];
+  }
+
+  const double *rc = lclSolver->getReducedCost();
+  const double *dual = lclSolver->getRowPrice();
+  const double *solution = lclSolver->getColSolution();
+
+  printvecINT("cstat", cstat, ncol);
+  printvecINT("rstat", rstat, nrow);
+  printvecINT("basisIndex", basisIndex, nrow);
+
+  printvecDBL("solution", solution, ncol);
+  printvecDBL("slackVal", slackVal, nrow);
+  printvecDBL("reduced_costs", rc, ncol);
+  printvecDBL("dual solution", dual, nrow);
+
+  printf("Optimal Tableau:\n");
+
+  for (int i = 0; i < nrow; i++) {
+    lclSolver->getBInvARow(i, z, slack);
+    for (int ii = 0; ii < ncol; ++ii) {
+      printf("%5.2f ", z[ii]);
+    }
+    printf(" | ");
+    for (int ii = 0; ii < nrow; ++ii) {
+      printf("%5.2f ", slack[ii]);
+    }
+    printf(" | ");
+    if(basisIndex[i] < ncol) {
+      printf("%5.2f ", solution[basisIndex[i]]);
+    }
+    else {
+      printf("%5.2f ", slackVal[basisIndex[i]-ncol]);
+    }
+    printf("\n");
+  }
+  for (int ii = 0; ii < 7*(ncol+nrow+1); ++ii) {
+    printf("-");
+  }
+  printf("\n");
+
+  for (int ii = 0; ii < ncol; ++ii) {
+    printf("%5.2f ", rc[ii]);    
+  }
+  printf(" | ");
+  for (int ii = 0; ii < nrow; ++ii) {
+    printf("%5.2f ", -dual[ii]);
+  }
+  printf(" | ");
+  printf("%5.2f\n", -lclSolver->getObjValue());
+  lclSolver->disableFactorization();
+
+  delete[] cstat;
+  delete[] rstat;
+  delete[] basisIndex;
+  delete[] slack;
+  delete[] z;
+  delete[] slackVal;
+} /* printOptTab */
+
+
+/*********************************************************************/
+// Create C++ lines to get to current state
+std::string
+CglGMI::generateCpp(FILE * fp) 
+{
+  CglGMI other;
+  fprintf(fp,"0#include \"CglGMI.hpp\"\n");
+  fprintf(fp,"3  CglGMI GMI;\n");
+  if (param.getMAX_SUPPORT()!=other.param.getMAX_SUPPORT())
+    fprintf(fp,"3  GMI.setLimit(%d);\n",param.getMAX_SUPPORT());
+  else
+    fprintf(fp,"4  GMI.setLimit(%d);\n",param.getMAX_SUPPORT());
+  if (param.getAway()!=other.param.getAway())
+    fprintf(fp,"3  GMI.setAway(%g);\n",param.getAway());
+  else
+    fprintf(fp,"4  GMI.setAway(%g);\n",param.getAway());
+  if (param.getEPS()!=other.param.getEPS())
+    fprintf(fp,"3  GMI.setEPS(%g);\n",param.getEPS());
+  else
+    fprintf(fp,"4  GMI.setEPS(%g);\n",param.getEPS());
+  if (param.getEPS_COEFF()!=other.param.getEPS_COEFF())
+    fprintf(fp,"3  GMI.setEPS_COEFF(%g);\n",param.getEPS_COEFF());
+  else
+    fprintf(fp,"4  GMI.set.EPS_COEFF(%g);\n",param.getEPS_COEFF());
+  if (param.getEPS_RELAX_ABS()!=other.param.getEPS_RELAX_ABS())
+    fprintf(fp,"3  GMI.set.EPS_RELAX(%g);\n",param.getEPS_RELAX_ABS());
+  else
+    fprintf(fp,"4  GMI.set.EPS_RELAX(%g);\n",param.getEPS_RELAX_ABS());
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  GMI.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  GMI.setAggressiveness(%d);\n",getAggressiveness());
+  return "GMI";
+}
+
+/*********************************************************************/
+int
+CglGMI::factorize(CoinFactorization & factorization,
+		  int* colBasisIndex, int* rowBasisIndex) {
+  // Start of code to create a factorization from warm start ====
+  // Taken (with small modifications) from CglGomory
+  int status=-100;
+  for (int i = 0; i < nrow; ++i) {
+    if (rstat[i] == 1) {
+      rowBasisIndex[i]=1;
+    } else {
+      rowBasisIndex[i]=-1;
+    }
+  }
+  for (int i = 0; i < ncol; ++i) {
+    if (cstat[i] == 1) {
+      colBasisIndex[i]=1;
+    } else {
+      colBasisIndex[i]=-1;
+    }
+  }
+  // returns 0 if okay, -1 singular, -2 too many in basis, -99 memory */
+  while (status<-98) {
+    status=factorization.factorize(*byCol, rowBasisIndex, colBasisIndex);
+    if (status==-99) factorization.areaFactor(factorization.areaFactor()*2.0);
+  } 
+  if (status) {
+    return -1;
+  }
+#if defined GMI_TRACE
+  double condition = 0.0;
+  const CoinFactorizationDouble * pivotRegion = factorization.pivotRegion();
+  for (int i = 0; i < nrow; ++i) {
+    condition += log(fabs(pivotRegion[i]));
+  }  
+  printf("CglGMI::factorize(): condition number recomputed as sum of log: %g\n", (condition));
+#endif
+  return 0;
+}
+
+/*********************************************************************/
+void CglGMI::setTrackRejection(bool value) {
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+  trackRejection = value;
+  if (trackRejection) {
+    // reset data members
+    resetRejectionCounters();
+  }
+#endif
+}
+
+/*********************************************************************/
+bool CglGMI::getTrackRejection() {
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+  return trackRejection;
+#else
+  return false;
+#endif
+}
+
+/*********************************************************************/
+void CglGMI::resetRejectionCounters() {
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+  fracFail = 0;
+  dynFail = 0;
+  violFail = 0;
+  suppFail = 0;
+  scaleFail = 0;
+  numGeneratedCuts = 0;
+#endif
+}
+
+/*********************************************************************/
+int CglGMI::getNumberRejectedCuts(RejectionType reason) {
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+  switch (reason) {
+  case failureFractionality:
+    return fracFail;
+  case failureDynamism:
+    return dynFail;
+  case failureViolation:
+    return violFail;
+  case failureSupport:
+    return suppFail;
+  case failureScale:
+    return scaleFail;
+  }
+  return 0;
+#else
+  return 0;
+#endif
+}
+
+/*********************************************************************/
+int CglGMI::getNumberGeneratedCuts() {
+#if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE
+  return numGeneratedCuts;
+#else
+  return 0;
+#endif
+}
diff --git a/cbits/coin/CglGMI.hpp b/cbits/coin/CglGMI.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglGMI.hpp
@@ -0,0 +1,364 @@
+// Last edit: 02/05/2013
+//
+// Name:     CglGMI.hpp
+// Author:   Giacomo Nannicini
+//           Singapore University of Technology and Design, Singapore
+//           email: nannicini@sutd.edu.sg
+// Date:     11/17/09
+//-----------------------------------------------------------------------------
+// Copyright (C) 2009, Giacomo Nannicini.  All Rights Reserved.
+
+#ifndef CglGMI_H
+#define CglGMI_H
+
+#include "CglCutGenerator.hpp"
+#include "CglGMIParam.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinFactorization.hpp"
+
+/* Enable tracking of rejection of cutting planes. If this is disabled,
+   the cut generator is slightly faster. If defined, it enables proper use
+   of setTrackRejection and related functions. */
+//#define TRACK_REJECT
+
+/* Debug output */
+//#define GMI_TRACE
+
+/* Debug output: print optimal tableau */
+//#define GMI_TRACETAB
+
+/* Print reason for cut rejection, whenever a cut is discarded */
+//#define GMI_TRACE_CLEAN
+
+/** Gomory cut generator with several cleaning procedures, used to test
+ *  the numerical safety of the resulting cuts 
+ */
+
+class CglGMI : public CglCutGenerator {
+
+  friend void CglGMIUnitTest(const OsiSolverInterface * siP,
+			     const std::string mpdDir);
+public:
+
+  /** Public enum: all possible reasons for cut rejection */
+  enum RejectionType{
+    failureFractionality,
+    failureDynamism,
+    failureViolation,
+    failureSupport,
+    failureScale
+  };
+
+  /**@name generateCuts */
+  //@{
+  /** Generate Gomory Mixed-Integer cuts for the model of the solver
+      interface si.
+
+      Insert the generated cuts into OsiCuts cs.
+
+      Warning: This generator currently works only with the Lp solvers Clp or 
+      Cplex9.0 or higher. It requires access to the optimal tableau and 
+      optimal basis inverse and makes assumptions on the way slack variables 
+      are added by the solver. The Osi implementations for Clp and Cplex 
+      verify these assumptions.
+
+      When calling the generator, the solver interface si must contain
+      an optimized problem and information related to the optimal
+      basis must be available through the OsiSolverInterface methods
+      (si->optimalBasisIsAvailable() must return 'true'). It is also
+      essential that the integrality of structural variable i can be
+      obtained using si->isInteger(i).
+
+  */
+  virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			    const CglTreeInfo info = CglTreeInfo());
+
+  /// Return true if needs optimal basis to do cuts (will return true)
+  virtual bool needsOptimalBasis() const { return true; }
+  //@}
+
+  /**@name Common Methods */
+  //@{
+  // Function for checking equality with user tolerance
+  inline bool areEqual(double x, double y, 
+		       double epsAbs = 1e-12, 
+		       double epsRel = 1e-12) {
+    return (fabs((x) - (y)) <= 
+	    std::max(epsAbs, epsRel * std::max(fabs(x), fabs(y))));
+  }
+
+  // Function for checking is a number is zero
+  inline bool isZero(double x, double epsZero = 1e-20) {
+    return (fabs(x) <= epsZero);
+  }
+
+
+  // Function for checking if a number is integer
+  inline bool isIntegerValue(double x, 
+			     double intEpsAbs = 1e-9,
+			     double intEpsRel = 1e-15) {
+    return (fabs((x) - floor((x)+0.5)) <= 
+	    std::max(intEpsAbs, intEpsRel * fabs(x)));
+  }
+
+  
+  //@}
+  
+  
+  /**@name Public Methods */
+  //@{
+
+  // Set the parameters to the values of the given CglGMIParam object.
+  void setParam(const CglGMIParam &source); 
+  // Return the CglGMIParam object of the generator. 
+  inline CglGMIParam getParam() const {return param;}
+  inline CglGMIParam & getParam() {return param;}
+
+  // Compute entries of is_integer.
+  void computeIsInteger();
+
+  /// Print the current simplex tableau  
+  void printOptTab(OsiSolverInterface *solver) const;
+
+  /// Set/get tracking of the rejection of cutting planes.
+  /// Note that all rejection related functions will not do anything 
+  /// unless the generator is compiled with the define GMI_TRACK_REJECTION
+  void setTrackRejection(bool value);
+  bool getTrackRejection();
+
+  /// Get number of cuts rejected for given reason; see above
+  int getNumberRejectedCuts(RejectionType reason);
+
+  /// Reset counters for cut rejection tracking; see above
+  void resetRejectionCounters();
+
+  /// Get total number of generated cuts since last resetRejectionCounters()
+  int getNumberGeneratedCuts();
+  
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglGMI();
+
+  /// Constructor with specified parameters 
+  CglGMI(const CglGMIParam &param);
+ 
+  /// Copy constructor 
+  CglGMI(const CglGMI &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglGMI & operator=(const CglGMI& rhs);
+  
+  /// Destructor 
+  virtual ~CglGMI();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+
+  //@}
+    
+private:
+  
+  // Private member methods
+
+/**@name Private member methods */
+
+  //@{
+
+  // Method generating the cuts after all CglGMI members are properly set.
+  void generateCuts(OsiCuts & cs);
+
+  /// Compute the fractional part of value, allowing for small error.
+  inline double aboveInteger(double value) const; 
+
+  /// Compute the fractionalities involved in the cut, and the cut rhs.
+  /// Returns true if cut is accepted, false if discarded
+  inline bool computeCutFractionality(double varRhs, double& cutRhs);
+
+  /// Compute the cut coefficient on a given variable
+  inline double computeCutCoefficient(double rowElem, int index);
+
+  /// Use multiples of the initial inequalities to cancel out the coefficient
+  /// on a slack variables. 
+  inline void eliminateSlack(double cutElem, int cutIndex, double* cut,
+			      double& cutRhs, const double *elements, 
+			      const int *rowStart, const int *indices, 
+			      const int *rowLength, const double *rhs);
+
+  /// Change the sign of the coefficients of the non basic
+  /// variables at their upper bound.
+  inline void flip(double& rowElem, int rowIndex);
+
+  /// Change the sign of the coefficients of the non basic
+  /// variables at their upper bound and do the translations restoring
+  /// the original bounds. Modify the right hand side
+  /// accordingly. Two functions: one for original variables, one for slacks.
+  inline void unflipOrig(double& rowElem, int rowIndex, double& rowRhs);
+  inline void unflipSlack(double& rowElem, int rowIndex, double& rowRhs,
+			   const double* slack_val);
+
+  /// Pack a row of ncol elements
+  inline void packRow(double* row, double* rowElem, int* rowIndex,
+		       int& rowNz);
+
+  /// Clean the cutting plane; the cleaning procedure does several things
+  /// like removing small coefficients, scaling, and checks several
+  /// acceptance criteria. If this returns false, the cut should be discarded.
+  /// There are several cleaning procedures available, that can be selected
+  /// via the parameter param.setCLEANING_PROCEDURE(int value)
+  bool cleanCut(double* cutElem, int* cutIndex, int& cutNz,
+		 double& cutRhs, const double* xbar);
+
+  /// Cut cleaning procedures: return true if successfull, false if
+  /// cut should be discarded by the caller of if problems encountered
+
+  /// Check the violation
+  bool checkViolation(const double* cutElem, const int* cutIndex,
+		       int cutNz, double cutrhs, const double* xbar);
+
+  /// Check the dynamism
+  bool checkDynamism(const double* cutElem, const int* cutIndex,
+		      int cutNz);
+
+  /// Check the support
+  bool checkSupport(int cutNz);
+
+  /// Remove small coefficients and adjust the rhs accordingly
+  bool removeSmallCoefficients(double* cutElem, int* cutIndex, 
+				 int& cutNz, double& cutRhs);
+
+  /// Adjust the rhs by relaxing by a small amount (relative or absolute)
+  void relaxRhs(double& rhs);
+
+  /// Scale the cutting plane in different ways;
+  /// scaling_type possible values:
+  /// 0 : scale to obtain integral cut
+  /// 1 : scale based on norm, to obtain cut norm equal to ncol
+  /// 2 : scale to obtain largest coefficient equal to 1
+  bool scaleCut(double* cutElem, int* cutIndex, int cutNz,
+		 double& cutRhs, int scalingType);
+
+  /// Scale the cutting plane in order to generate integral coefficients
+  bool scaleCutIntegral(double* cutElem, int* cutIndex, int cutNz,
+			  double& cutRhs);
+
+  /// Compute the nearest rational number; used by scale_row_integral
+  bool nearestRational(double val, double maxdelta, long maxdnom,
+			long& numerator, long& denominator);
+
+  /// Compute the greatest common divisor
+  long computeGcd(long a, long b);
+
+  /// print a vector of integers
+  void printvecINT(const char *vecstr, const int *x, int n) const;
+  /// print a vector of doubles: dense form
+  void printvecDBL(const char *vecstr, const double *x, int n) const;
+  /// print a vector of doubles: sparse form
+  void printvecDBL(const char *vecstr, const double *elem, const int * index, 
+		   int nz) const;
+
+  /// Recompute the simplex tableau for want of a better accuracy.
+  /// Requires an empty CoinFactorization object to do the computations,
+  /// and two empty (already allocated) arrays which will contain 
+  /// the basis indices on exit. Returns 0 if successfull.
+  int factorize(CoinFactorization & factorization,
+		int* colBasisIndex, int* rowBasisIndex);
+
+
+  //@}
+
+  
+  // Private member data
+
+/**@name Private member data */
+
+  //@{
+
+  /// Object with CglGMIParam members. 
+  CglGMIParam param;
+
+  /// Number of rows ( = number of slack variables) in the current LP.
+  int nrow; 
+
+  /// Number of structural variables in the current LP.
+  int ncol;
+
+  /// Lower bounds for structural variables
+  const double *colLower;
+
+  /// Upper bounds for structural variables
+  const double *colUpper;
+  
+  /// Lower bounds for constraints
+  const double *rowLower;
+
+  /// Upper bounds for constraints
+  const double *rowUpper;
+
+  /// Righ hand side for constraints (upper bound for ranged constraints).
+  const double *rowRhs;
+
+  /// Characteristic vectors of structural integer variables or continuous
+  /// variables currently fixed to integer values. 
+  bool *isInteger;
+
+  /// Current basis status: columns
+  int *cstat;
+
+  /// Current basis status: rows
+  int *rstat;
+
+  /// Pointer on solver. Reset by each call to generateCuts().
+  OsiSolverInterface *solver;
+
+  /// Pointer on point to separate. Reset by each call to generateCuts().
+  const double *xlp;
+
+  /// Pointer on row activity. Reset by each call to generateCuts().
+  const double *rowActivity;
+
+  /// Pointer on matrix of coefficient ordered by rows. 
+  /// Reset by each call to generateCuts().
+  const CoinPackedMatrix *byRow;
+
+  /// Pointer on matrix of coefficient ordered by columns. 
+  /// Reset by each call to generateCuts().
+  const CoinPackedMatrix *byCol;
+
+  /// Fractionality of the cut and related quantities.
+  double f0;
+  double f0compl;
+  double ratiof0compl;
+
+#if defined(TRACK_REJECT) || defined (TRACK_REJECT_SIMPLE)
+  /// Should we track the reason of each cut rejection?
+  bool trackRejection;
+  /// Number of failures by type
+  int fracFail;
+  int dynFail;
+  int violFail;
+  int suppFail;
+  int smallCoeffFail;
+  int scaleFail;
+  /// Total number of generated cuts
+  int numGeneratedCuts;
+#endif
+
+  //@}
+};
+
+//#############################################################################
+/** A function that tests the methods in the CglGMI class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglGMIUnitTest(const OsiSolverInterface * siP,
+			 const std::string mpdDir );
+
+
+#endif
diff --git a/cbits/coin/CglGMIParam.cpp b/cbits/coin/CglGMIParam.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglGMIParam.cpp
@@ -0,0 +1,225 @@
+// Name:     CglGMIParam.hpp
+// Author:   Giacomo Nannicini
+//           Singapore University of Technology and Design
+//           email: nannicini@sutd.edu.sg
+//           based on CglRedSplitParam.cpp by Francois Margot
+// Date:     11/17/09
+//-----------------------------------------------------------------------------
+// Copyright (C) 2009, Giacomo Nannicini and others.  All Rights Reserved.
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CglGMIParam.hpp"
+
+/***********************************************************************/
+void CglGMIParam::setAway(double value) {
+  if (value > 0.0 && value <= 0.5) {
+    AWAY = value;
+  }
+  else {
+    printf("### WARNING: CglGMIParam::setAWAY(): value: %f ignored\n", value);
+  }
+}
+
+/***********************************************************************/
+void CglGMIParam::setEPS_ELIM(double value) {
+  if (value >= 0) {
+    EPS_ELIM = value;
+  }
+  else {
+    printf("### WARNING: CglGMIParam::setEPS_ELIM(): value: %f ignored\n", value);
+  }
+} /* setEPS_ELIM */
+
+/***********************************************************************/
+void CglGMIParam::setEPS_RELAX_ABS(double value) {
+  if (value >= 0) {
+    EPS_RELAX_ABS = value;
+  }
+  else {
+    printf("### WARNING: CglGMIParam::setEPS_RELAX_ABS(): value: %f ignored\n", value);
+  }
+} /* setEPS_RELAX_ABS */
+
+/***********************************************************************/
+void CglGMIParam::setEPS_RELAX_REL(double value) {
+  if (value >= 0) {
+    EPS_RELAX_REL = value;
+  }
+  else {
+    printf("### WARNING: CglGMIParam::setEPS_RELAX_REL(): value: %f ignored\n", value);
+  }
+} /* setEPS_RELAX_REL */
+
+/***********************************************************************/
+void CglGMIParam::setMAXDYN(double value) {
+  if (value >= 1.0) {
+    MAXDYN = value;
+  }
+  else {
+    printf("### WARNING: CglGMI::setMAXDYN(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMAXDYN */
+
+/***********************************************************************/
+void CglGMIParam::setMINVIOL(double value) {
+  if (value >= 0.0) {
+    MINVIOL = value;
+  }
+  else {
+    printf("### WARNING: CglGMIParam::setMINVIOL(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMINVIOL */
+
+/***********************************************************************/
+void CglGMIParam::setMAX_SUPPORT_REL(double value) {
+  if (value >= 0.0 && value <= 1.0) {
+    MAX_SUPPORT_REL = value;
+  }
+  else {
+    printf("### WARNING: CglGMIParam::setMAX_SUPPORT_REL(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMAX_SUPPORT_REL */
+
+/***********************************************************************/
+void CglGMIParam::setUSE_INTSLACKS(bool value) {
+  USE_INTSLACKS = value;
+} /* setUSE_INTSLACKS */
+
+/***********************************************************************/
+void CglGMIParam::setCHECK_DUPLICATES(bool value) {
+  CHECK_DUPLICATES = value;
+} /* setCHECK_DUPLICATES */
+
+/***********************************************************************/
+void CglGMIParam::setINTEGRAL_SCALE_CONT(bool value) {
+  INTEGRAL_SCALE_CONT = value;
+} /* setINTEGRAL_SCALE_CONT */
+
+/***********************************************************************/
+void CglGMIParam::setENFORCE_SCALING(bool value) {
+  ENFORCE_SCALING = value;
+} /* setENFORCE_SCALING */
+
+/***********************************************************************/
+void CglGMIParam::setCLEAN_PROC(CleaningProcedure value) {
+  CLEAN_PROC = value;
+} /* setCLEAN_PROC */
+
+/***********************************************************************/
+CglGMIParam::CglGMIParam(double eps,
+			 double away,
+			 double eps_coeff,
+			 double eps_el,
+			 double eps_relax_abs,
+			 double eps_relax_rel,
+			 double max_dyn,
+			 double min_viol,
+			 int max_supp_abs,
+			 double max_supp_rel,
+			 CleaningProcedure clean_proc,
+			 bool use_int_slacks,
+			 bool check_duplicates,
+			 bool integral_scale_cont,
+			 bool enforce_scaling) :
+  CglParam(COIN_DBL_MAX, eps, eps_coeff, max_supp_abs),
+  AWAY(away),
+  EPS_ELIM(eps_el),
+  EPS_RELAX_ABS(eps_relax_abs),
+  EPS_RELAX_REL(eps_relax_rel),
+  MAXDYN(max_dyn),
+  MINVIOL(min_viol),
+  MAX_SUPPORT_REL(max_supp_rel),
+  CLEAN_PROC(clean_proc),
+  USE_INTSLACKS(use_int_slacks),
+  CHECK_DUPLICATES(check_duplicates),
+  INTEGRAL_SCALE_CONT(integral_scale_cont),
+  ENFORCE_SCALING(enforce_scaling)
+{}
+
+/***********************************************************************/
+CglGMIParam::CglGMIParam(CglParam &source,
+			 double away,
+			 double eps_el, 
+			 double eps_ra, 
+			 double eps_rr, 
+			 double max_dyn,
+			 double min_viol,
+			 double max_supp_rel,
+			 CleaningProcedure clean_proc,
+			 bool use_int_slacks,
+			 bool check_duplicates,
+			 bool integral_scale_cont,
+			 bool enforce_scaling) :
+  CglParam(source), 
+  AWAY(away),
+  EPS_ELIM(eps_el),
+  EPS_RELAX_ABS(eps_ra),
+  EPS_RELAX_REL(eps_rr),
+  MAXDYN(max_dyn),
+  MINVIOL(min_viol),
+  MAX_SUPPORT_REL(max_supp_rel),
+  CLEAN_PROC(clean_proc),
+  USE_INTSLACKS(use_int_slacks),
+  CHECK_DUPLICATES(check_duplicates),
+  INTEGRAL_SCALE_CONT(integral_scale_cont),
+  ENFORCE_SCALING(enforce_scaling)
+{}
+
+/***********************************************************************/
+CglGMIParam::CglGMIParam(const CglGMIParam &source) :
+  CglParam(source),
+  AWAY(source.AWAY),
+  EPS_ELIM(source.EPS_ELIM),
+  EPS_RELAX_ABS(source.EPS_RELAX_ABS),
+  EPS_RELAX_REL(source.EPS_RELAX_REL),
+  MAXDYN(source.MAXDYN),
+  MINVIOL(source.MINVIOL),
+  MAX_SUPPORT_REL(source.MAX_SUPPORT_REL),
+  CLEAN_PROC(source.CLEAN_PROC),
+  USE_INTSLACKS(source.USE_INTSLACKS),
+  CHECK_DUPLICATES(source.CHECK_DUPLICATES),
+  INTEGRAL_SCALE_CONT(source.INTEGRAL_SCALE_CONT),
+  ENFORCE_SCALING(source.ENFORCE_SCALING)
+{}
+
+/***********************************************************************/
+CglGMIParam* CglGMIParam::clone() const
+{
+  return new CglGMIParam(*this);
+}
+
+/***********************************************************************/
+CglGMIParam& CglGMIParam::operator=(const CglGMIParam &rhs)
+{
+  if(this != &rhs) {
+    CglParam::operator=(rhs);
+
+    AWAY = rhs.AWAY;
+    EPS_ELIM = rhs.EPS_ELIM;
+    EPS_RELAX_ABS = rhs.EPS_RELAX_ABS;
+    EPS_RELAX_REL = rhs.EPS_RELAX_REL;
+    MAXDYN = rhs.MAXDYN;
+    MINVIOL = rhs.MINVIOL;
+    MAX_SUPPORT_REL = rhs.MAX_SUPPORT_REL;
+    CLEAN_PROC = rhs.CLEAN_PROC;
+    USE_INTSLACKS = rhs.USE_INTSLACKS;
+    CHECK_DUPLICATES = rhs.CHECK_DUPLICATES;
+    INTEGRAL_SCALE_CONT = rhs.INTEGRAL_SCALE_CONT;
+    ENFORCE_SCALING = rhs.ENFORCE_SCALING;
+  }
+  return *this;
+}
+
+/***********************************************************************/
+CglGMIParam::~CglGMIParam()
+{}
diff --git a/cbits/coin/CglGMIParam.hpp b/cbits/coin/CglGMIParam.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglGMIParam.hpp
@@ -0,0 +1,313 @@
+// Name:     CglGMIParam.hpp
+// Author:   Giacomo Nannicini
+//           Singapore University of Technology and Design
+//           email: nannicini@sutd.edu.sg
+//           based on CglRedSplitParam.hpp by Francois Margot
+// Date:     11/17/09
+//-----------------------------------------------------------------------------
+// Copyright (C) 2009, Giacomo Nannicini and others.  All Rights Reserved.
+
+#ifndef CglGMIParam_H
+#define CglGMIParam_H
+
+#include "CglParam.hpp"
+
+
+  /**@name CglGMI Parameters */
+  //@{
+
+  /** Class collecting parameters for the GMI cut generator.
+
+      Parameters of the generator are listed below. Modifying the default 
+      values for parameters other than the last four might result in 
+      invalid cuts.
+
+      - MAXDYN: Maximum ratio between largest and smallest non zero 
+                coefficients in a cut. See method setMAXDYN().
+      - EPS_ELIM: Precision for deciding if a coefficient is zero when 
+                  eliminating slack variables. See method setEPS_ELIM().
+      - MINVIOL: Minimum violation for the current basic solution in 
+                 a generated cut. See method setMINVIOL().
+      - USE_INTSLACKS: Use integer slacks to generate cuts. 
+                       (not implemented yet, will be in the future).
+                       See method setUSE_INTSLACKS().
+      - AWAY: Look only at basic integer variables whose current value is at
+              least this value away from being integer. See method setAway().
+      - CHECK_DUPLICATES: Should we check for duplicates when adding a cut
+                          to the collection? Can be slow. 
+                          Default 0 - do not check, add cuts anyway.
+      - CLEAN_PROC: Cleaning procedure that should be used. Look below at the
+                    enumeration CleaningProcedure for possible values.
+      - INTEGRAL_SCALE_CONT: If we try to scale cut coefficients so that
+                             they become integral, do we also scale on 
+			     continuous variables?
+			     Default 0 - do not scale continuous vars.
+			     Used only if CLEAN_PROC does integral scaling.
+      - ENFORCE_SCALING: Discard badly scaled cuts, or keep them (unscaled).
+                         Default 1 - yes.
+
+  */
+  //@}
+
+class CglGMIParam : public CglParam {
+
+public:
+
+  /**@name Enumerations */
+  enum CleaningProcedure{
+    /* CglLandP procedure I */
+    CP_CGLLANDP1,
+    /* CglLandP procedure II */
+    CP_CGLLANDP2,
+    /* CglRedSplit procedure I */
+    CP_CGLREDSPLIT,
+    /* Only integral cuts, i.e. cuts with integral coefficients */
+    CP_INTEGRAL_CUTS,
+    /* CglLandP procedure I with integral scaling */
+    CP_CGLLANDP1_INT,
+    /* CglLandP procedure I with scaling of the max element to 1 if possible */
+    CP_CGLLANDP1_SCALEMAX,
+    /* CglLandP procedure I with scaling of the rhs to 1 if possible */
+    CP_CGLLANDP1_SCALERHS
+  };
+
+  /**@name Set/get methods */
+
+  //@{
+  /** Aliases for parameter get/set method in the base class CglParam */
+  
+  /** Value for Infinity. Default: DBL_MAX */
+  inline void setInfinity(double value) {setINFINIT(value);}
+  inline double getInfinity() const {return INFINIT;}
+
+  /** Epsilon for comparing numbers. Default: 1.0e-6  */
+  inline void setEps(double value) {setEPS(value);}
+  inline double getEps() const {return EPS;}
+
+  /** Epsilon for zeroing out coefficients. Default: 1.0e-5 */
+  inline void setEpsCoeff(double value) {setEPS_COEFF(value);}
+  inline double getEpsCoeff() const {return EPS_COEFF;}
+
+  /** Maximum support of the cutting planes. Default: INT_MAX */
+  inline void setMaxSupport(int value) {setMAX_SUPPORT(value);}
+  inline int getMaxSupport() const {return MAX_SUPPORT;}
+  /** Alias for consistency with our naming scheme */
+  inline void setMaxSupportAbs(int value) {setMAX_SUPPORT(value);}
+  inline int getMaxSupportAbs() const {return MAX_SUPPORT;}
+  inline int getMAX_SUPPORT_ABS() const {return MAX_SUPPORT;}
+
+  /** Set AWAY, the minimum distance from being integer used for selecting 
+      rows for cut generation;  all rows whose pivot variable should be 
+      integer but is more than away from integrality will be selected; 
+      Default: 0.005 */
+  virtual void setAway(double value);
+  /** Get value of away */
+  inline double getAway() const {return AWAY;}
+  /// Aliases
+  inline void setAWAY(double value) {setAway(value);}
+  inline double getAWAY() const {return AWAY;}
+
+  /** Set the value of EPS_ELIM, epsilon for values of coefficients when 
+      eliminating slack variables;
+      Default: 0 */
+  virtual void setEPS_ELIM(double value);
+  /** Get the value of EPS_ELIM */
+  inline double getEPS_ELIM() const {return EPS_ELIM;}
+  /// Aliases
+  inline void setEpsElim(double value) {setEPS_ELIM(value);}
+  inline double getEpsElim() const {return EPS_ELIM;}
+  
+  /** Set EPS_RELAX_ABS */
+  virtual void setEPS_RELAX_ABS(double value);
+  /** Get value of EPS_RELAX_ABS */
+  inline double getEPS_RELAX_ABS() const {return EPS_RELAX_ABS;}
+  /// Aliases
+  inline void setEpsRelaxAbs(double value) {setEPS_RELAX_ABS(value);}
+  inline double getEpsRelaxAbs() const {return EPS_RELAX_ABS;}
+
+  /** Set EPS_RELAX_REL */
+  virtual void setEPS_RELAX_REL(double value);
+  /** Get value of EPS_RELAX_REL */
+  inline double getEPS_RELAX_REL() const {return EPS_RELAX_REL;}
+  /// Aliases
+  inline void setEpsRelaxRel(double value) {setEPS_RELAX_REL(value);}
+  inline double getEpsRelaxRel() const {return EPS_RELAX_REL;}
+
+  // Set the maximum ratio between largest and smallest non zero 
+  // coefficients in a cut. Default: 1e6.
+  virtual void setMAXDYN(double value);
+  /** Get the value of MAXDYN */
+  inline double getMAXDYN() const {return MAXDYN;}
+  /// Aliases
+  inline void setMaxDyn(double value) {setMAXDYN(value);}
+  inline double getMaxDyn() const {return MAXDYN;}
+
+  /** Set the value of MINVIOL, the minimum violation for the current 
+      basic solution in a generated cut. Default: 1e-7 */
+  virtual void setMINVIOL(double value);
+  /** Get the value of MINVIOL */
+  inline double getMINVIOL() const {return MINVIOL;}
+  /// Aliases
+  inline void setMinViol(double value) {setMINVIOL(value);}
+  inline double getMinViol() const {return MINVIOL;}
+
+  /** Set the value of MAX_SUPPORT_REL, the factor contributing to the
+      maximum support relative to the number of columns. Maximum
+      allowed support is: MAX_SUPPORT_ABS +
+      MAX_SUPPORT_REL*ncols. Default: 0.1 */
+  virtual void setMAX_SUPPORT_REL(double value);
+  /** Get the value of MINVIOL */
+  inline double getMAX_SUPPORT_REL() const {return MAX_SUPPORT_REL;}
+  /// Aliases
+  inline void setMaxSupportRel(double value) {setMAX_SUPPORT_REL(value);}
+  inline double getMaxSupportRel() const {return MAX_SUPPORT_REL;}
+
+  /** Set the value of USE_INTSLACKS. Default: 0 */
+  virtual void setUSE_INTSLACKS(bool value);
+  /** Get the value of USE_INTSLACKS */
+  inline bool getUSE_INTSLACKS() const {return USE_INTSLACKS;}
+  /// Aliases
+  inline void setUseIntSlacks(bool value) {setUSE_INTSLACKS(value);}
+  inline int getUseIntSlacks() const {return USE_INTSLACKS;}
+
+  /** Set the value of CHECK_DUPLICATES. Default: 0 */
+  virtual void setCHECK_DUPLICATES(bool value);
+  /** Get the value of CHECK_DUPLICATES */
+  inline bool getCHECK_DUPLICATES() const {return CHECK_DUPLICATES;}
+  /// Aliases
+  inline void setCheckDuplicates(bool value) {setCHECK_DUPLICATES(value);}
+  inline bool getCheckDuplicates() const {return CHECK_DUPLICATES;}
+
+  /** Set the value of CLEAN_PROC. Default: CP_CGLLANDP1 */
+  virtual void setCLEAN_PROC(CleaningProcedure value);
+  /** Get the value of CLEAN_PROC. */
+  inline CleaningProcedure getCLEAN_PROC() const {return CLEAN_PROC;}
+  /// Aliases
+  inline void setCleanProc(CleaningProcedure value) {setCLEAN_PROC(value);}
+  inline CleaningProcedure getCleaningProcedure() const {return CLEAN_PROC;}
+
+  /** Set the value of INTEGRAL_SCALE_CONT. Default: 0 */
+  virtual void setINTEGRAL_SCALE_CONT(bool value);
+  /** Get the value of INTEGRAL_SCALE_CONT. */
+  inline bool getINTEGRAL_SCALE_CONT() const {return INTEGRAL_SCALE_CONT;}
+  /// Aliases
+  inline void setIntegralScaleCont(bool value) {setINTEGRAL_SCALE_CONT(value);}
+  inline bool getIntegralScaleCont() const {return INTEGRAL_SCALE_CONT;}
+
+  /** Set the value of ENFORCE_SCALING. Default: 1 */
+  virtual void setENFORCE_SCALING(bool value);
+  /** Get the value of ENFORCE_SCALING. */
+  inline bool getENFORCE_SCALING() const {return ENFORCE_SCALING;}
+  /// Aliases
+  inline void setEnforceScaling(bool value) {setENFORCE_SCALING(value);}
+  inline bool getEnforcescaling() const {return ENFORCE_SCALING;}
+
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglGMIParam(double eps = 1e-12,
+	      double away = 0.005,
+	      double eps_coeff = 1e-11,
+	      double eps_elim = 0,
+	      double eps_relax_abs = 1e-11,
+	      double eps_relax_rel = 1e-13,
+	      double max_dyn = 1e6,
+	      double min_viol = 1e-4,
+	      int max_supp_abs = 1000,
+	      double max_supp_rel = 0.1,
+	      CleaningProcedure clean_proc = CP_CGLLANDP1,
+	      bool use_int_slacks = false,
+	      bool check_duplicates = false,
+	      bool integral_scale_cont = false,
+	      bool enforce_scaling = true);
+
+   /// Constructor from CglParam
+  CglGMIParam(CglParam &source,
+	      double away = 0.005,
+	      double eps_elim = 1e-12,
+	      double eps_relax_abs = 1e-11,
+	      double eps_relax_rel = 1e-13,
+	      double max_dyn = 1e6,
+	      double min_viol = 1e-4,
+	      double max_supp_rel = 0.1,
+	      CleaningProcedure clean_proc = CP_CGLLANDP1,
+	      bool use_int_slacks = false,
+	      bool check_duplicates = false,
+	      bool integral_scale_cont = false,
+	      bool enforce_scaling = true);
+  
+  /// Copy constructor 
+  CglGMIParam(const CglGMIParam &source);
+
+  /// Clone
+  virtual CglGMIParam* clone() const;
+
+  /// Assignment operator 
+  virtual CglGMIParam& operator=(const CglGMIParam &rhs);
+
+  /// Destructor 
+  virtual ~CglGMIParam();
+  //@}
+
+protected:
+
+  /**@name Parameters */
+  //@{
+
+  /** Use row only if pivot variable should be integer but is more 
+      than AWAY from being integer. */
+  double AWAY;
+
+  /** Epsilon for value of coefficients when eliminating slack variables. 
+      Default: 0. */
+  double EPS_ELIM;
+
+  /** Value added to the right hand side of each generated cut to relax it.
+      Default: 1e-11 */
+  double EPS_RELAX_ABS;
+
+  /** For a generated cut with right hand side rhs_val, 
+      EPS_RELAX_EPS * fabs(rhs_val) is used to relax the constraint.
+      Default: 1.e-13 */
+  double EPS_RELAX_REL;
+
+  /** Maximum ratio between largest and smallest non zero 
+      coefficients in a cut. Default: 1e6. */
+  double MAXDYN;
+
+  /** Minimum violation for the current basic solution in a generated cut.
+      Default: 1e-4. */
+  double MINVIOL;
+
+  /** Maximum support relative to number of columns. Must be between 0
+      and 1. Default: 0. */
+  double MAX_SUPPORT_REL;
+
+  /** Which cleaning procedure should be used? */
+  CleaningProcedure CLEAN_PROC;
+
+  /** Use integer slacks to generate cuts if USE_INTSLACKS = 1. Default: 0. */
+  bool USE_INTSLACKS;
+
+  /** Check for duplicates when adding the cut to the collection? */
+  bool CHECK_DUPLICATES;
+
+  /** Should we try to rescale cut coefficients on continuous variables
+      so that they become integral, or do we only rescale coefficients
+      on integral variables? Used only by cleaning procedure that try
+      the integral scaling. */
+  bool INTEGRAL_SCALE_CONT;
+
+  /** Should we discard badly scaled cuts (according to the scaling
+      procedure in use)? If false, CglGMI::scaleCut always returns
+      true, even though it still scales cuts whenever possible, but
+      not cut is rejected for scaling. Default true. Used only by
+      cleaning procedure that try to scale. */
+  bool ENFORCE_SCALING;
+
+  //@}
+};
+
+#endif
diff --git a/cbits/coin/CglGomory.cpp b/cbits/coin/CglGomory.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglGomory.cpp
@@ -0,0 +1,1689 @@
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+//#define CGL_DEBUG 1
+//#ifdef NDEBUG
+//#undef NDEBUG
+//#endif
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "OsiRowCutDebugger.hpp"
+#define COIN_HAS_CLP_GOMORY
+#ifdef COIN_HAS_CLP_GOMORY
+#include "OsiClpSolverInterface.hpp"
+#endif
+#include "CoinFactorization.hpp"
+#undef CLP_OSL
+#if 1
+#define CLP_OSL 1
+#if CLP_OSL!=1&&CLP_OSL!=3
+#undef CLP_OSL
+#else
+#include "CoinOslFactorization.hpp"
+#endif
+#endif
+#include "CoinWarmStartBasis.hpp"
+#include "CglGomory.hpp"
+#include "CoinFinite.hpp"
+#ifdef CGL_DEBUG_GOMORY
+int gomory_try=CGL_DEBUG_GOMORY;
+#endif
+//-------------------------------------------------------------------
+// Generate Gomory cuts
+//------------------------------------------------------------------- 
+void CglGomory::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info)
+{
+#ifdef CGL_DEBUG_GOMORY
+  gomory_try++;
+#endif
+  // Get basic problem information
+  int numberColumns=si.getNumCols(); 
+  
+  // get integer variables and basis
+  char * intVar = new char[numberColumns];
+  int i;
+  CoinWarmStart * warmstart = si.getWarmStart();
+  CoinWarmStartBasis* warm =
+    dynamic_cast<CoinWarmStartBasis*>(warmstart);
+  const double * colUpper = si.getColUpper();
+  const double * colLower = si.getColLower();
+  //#define CLP_INVESTIGATE2
+#ifndef CLP_INVESTIGATE2
+  if ((info.options&16)!=0)
+#endif
+    printf("%d %d %d\n",info.inTree,info.options,info.pass);
+  for (i=0;i<numberColumns;i++) {
+    if (si.isInteger(i)) {
+      if (colUpper[i]>colLower[i]+0.5) {
+	if (fabs(colUpper[i]-1.0)<1.0e-12&&fabs(colLower[i])<1.0e-12) {
+	  intVar[i]=1; //0-1
+	} else  if (colLower[i]>=0.0) {
+	  intVar[i] = 2; // other
+	} else {
+	  // negative bounds - I am not sure works
+	  intVar[i] = 0;
+	}
+      } else {
+	intVar[i] = 0;
+      }
+    } else {
+      intVar[i]=0;
+    }
+  }
+  const OsiSolverInterface * useSolver=&si;
+#ifdef COIN_HAS_CLP_GOMORY
+  double * objective = NULL;
+  OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *>(originalSolver_);
+  int numberOriginalRows = -1;
+  if (clpSolver) {
+    useSolver = originalSolver_;
+    assert (gomoryType_);
+    // check simplex is plausible
+    if (!clpSolver->getNumRows()||numberColumns!=clpSolver->getNumCols()) {
+      delete originalSolver_;
+      originalSolver_=si.clone();
+      clpSolver = dynamic_cast<OsiClpSolverInterface *>(originalSolver_);
+      assert (clpSolver);
+      useSolver = originalSolver_;
+    }
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+    numberOriginalRows = simplex->numberRows();
+    int numberRows = si.getNumRows();
+    assert (numberOriginalRows<=numberRows);
+    // only do if different (unless type 2x)
+    int gomoryType = gomoryType_%10;
+    int whenToDo = gomoryType_/10;
+    if (whenToDo==2 ||(numberRows>numberOriginalRows && whenToDo==1
+		       && (info.options&512)==0) ||
+	((info.options&1024)!=0 && (info.options&512)==0
+	 && numberTimesStalled_<3)) {
+      // bounds
+      memcpy(simplex->columnLower(),colLower,numberColumns*sizeof(double));
+      memcpy(simplex->columnUpper(),colUpper,numberColumns*sizeof(double));
+      double * obj = simplex->objective();
+      objective = CoinCopyOfArray(obj,numberColumns);
+      const double * pi = si.getRowPrice();
+      const CoinPackedMatrix * rowCopy = si.getMatrixByRow();
+      const int * column = rowCopy->getIndices();
+      const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+      const int * rowLength = rowCopy->getVectorLengths(); 
+      const double * rowElements = rowCopy->getElements();
+      const double * rowLower = si.getRowLower();
+      const double * rowUpper = si.getRowUpper();
+      int numberCopy;
+      int numberAdd;
+      double * rowLower2 = NULL;
+      double * rowUpper2 = NULL;
+      int * column2 = NULL;
+      CoinBigIndex * rowStart2 = NULL;
+      double * rowElements2 = NULL;
+      char * copy = new char [numberRows-numberOriginalRows];
+      memset(copy,0,numberRows-numberOriginalRows);
+      if (gomoryType==2) {
+	numberCopy=0;
+	numberAdd=0;
+	for (int iRow=numberOriginalRows;iRow<numberRows;iRow++) {
+	  bool simple = true;
+	  for (int k=rowStart[iRow];
+	       k<rowStart[iRow]+rowLength[iRow];k++) {
+	    double value = rowElements[k];
+	    if (value!=floor(value+0.5)) {
+	      simple=false;
+	      break;
+	    }
+	  }
+	  if (simple) {
+	    numberCopy++;
+	    numberAdd+=rowLength[iRow];
+	    copy[iRow-numberOriginalRows]=1;
+	  }
+	}
+	if (numberCopy) {
+	  //printf("Using %d rows out of %d\n",numberCopy,numberRows-numberOriginalRows);
+	  rowLower2 = new double [numberCopy];
+	  rowUpper2 = new double [numberCopy];
+	  rowStart2 = new CoinBigIndex [numberCopy+1];
+	  rowStart2[0]=0;
+	  column2 = new int [numberAdd];
+	  rowElements2 = new double [numberAdd];
+	}
+      }
+      numberCopy=0;
+      numberAdd=0;
+      const double * rowSolution = si.getRowActivity();
+      double offset=0.0;
+      for (int iRow=numberOriginalRows;iRow<numberRows;iRow++) {
+	if (!copy[iRow-numberOriginalRows]) {
+	  double value = pi[iRow];
+	  offset += rowSolution[iRow]*value;
+	  for (int k=rowStart[iRow];
+	       k<rowStart[iRow]+rowLength[iRow];k++) {
+	    int iColumn=column[k];
+	    obj[iColumn] -= value*rowElements[k];
+	  }
+	} else {
+	  rowLower2[numberCopy]=rowLower[iRow];
+	  rowUpper2[numberCopy]=rowUpper[iRow];
+	  for (int k=rowStart[iRow];
+	       k<rowStart[iRow]+rowLength[iRow];k++) {
+	    column2[numberAdd]=column[k];
+	    rowElements2[numberAdd++]=rowElements[k];
+	  }
+	  numberCopy++;
+	  rowStart2[numberCopy]=numberAdd;
+	}
+      }
+#if 0
+      CoinThreadRandom randomNumberGenerator;
+      const double * solution = si.getColSolution();
+      for (int i=0;i<numberColumns;i++) {
+	if (intVar[i]==1) {
+	  double randomNumber = randomNumberGenerator.randomDouble();
+	  //randomNumber = 0.001*floor(randomNumber*1000.0);
+	  if (solution[i]>0.5)
+	    obj[i] -= randomNumber*0.001*fabs(obj[i]);
+	  else
+	    obj[i] += randomNumber*0.001*fabs(obj[i]);
+	}
+      }
+#endif
+      if (numberCopy) {
+	clpSolver->addRows(numberCopy,
+			   rowStart2,column2,rowElements2,
+			   rowLower2,rowUpper2);
+	delete [] rowLower2 ;
+	delete [] rowUpper2 ;
+	delete [] column2 ;
+	delete [] rowStart2 ;
+	delete [] rowElements2 ;
+      }
+      delete [] copy;
+      memcpy(simplex->primalColumnSolution(),si.getColSolution(),
+	     numberColumns*sizeof(double));
+      warm->resize(numberOriginalRows,numberColumns);
+      clpSolver->setBasis(*warm);
+      delete warm;
+      simplex->setDualObjectiveLimit(COIN_DBL_MAX);
+      simplex->setLogLevel(0);
+      simplex->primal(1);
+      // check basis
+      int numberTotal=simplex->numberRows()+simplex->numberColumns();
+      int superbasic=0;
+      for (int i=0;i<numberTotal;i++) {
+	if (simplex->getStatus(i)==ClpSimplex::superBasic)
+	  superbasic++;
+      }
+      if (superbasic) {
+	//printf("%d superbasic!\n",superbasic);
+	simplex->dual();
+	superbasic=0;
+	for (int i=0;i<numberTotal;i++) {
+	  if (simplex->getStatus(i)==ClpSimplex::superBasic)
+	    superbasic++;
+	}
+	assert (!superbasic);
+      }
+      //printf("Trying - %d its status %d objs %g %g - with offset %g\n",
+      //     simplex->numberIterations(),simplex->status(),
+      //     simplex->objectiveValue(),si.getObjValue(),simplex->objectiveValue()+offset);
+      //simplex->setLogLevel(0);
+      warm=simplex->getBasis();
+      warmstart=warm;
+      if (simplex->status()) {
+	//printf("BAD status %d\n",simplex->status());
+	//clpSolver->writeMps("clp");
+	//si.writeMps("si");
+	delete [] objective;
+	objective=NULL;
+	useSolver=&si;
+      }
+    } else {
+      // don't do
+      delete warmstart;
+      warmstart=NULL;
+      if ((info.options&1024)==0)
+	numberTimesStalled_=0;
+    }
+  }
+#endif
+#ifdef CGL_DEBUG
+  const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+  if (debugger&&!debugger->onOptimalPath(si))
+    debugger = NULL;
+#else
+  const OsiRowCutDebugger * debugger = NULL;
+#endif
+  int numberRowCutsBefore = cs.sizeRowCuts();
+
+  if (warmstart)
+    generateCuts(debugger, cs, *useSolver->getMatrixByCol(), 
+		 *useSolver->getMatrixByRow(),
+		 useSolver->getColSolution(),
+		 useSolver->getColLower(), useSolver->getColUpper(), 
+		 useSolver->getRowLower(), useSolver->getRowUpper(),
+		 intVar,warm,info);
+#ifdef COIN_HAS_CLP_GOMORY
+  if (objective) {
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+    memcpy(simplex->objective(),objective,numberColumns*sizeof(double));
+    delete [] objective;
+    // take out locally useless cuts
+    const double * solution = si.getColSolution();
+    double primalTolerance = 1.0e-7;
+    int numberRowCutsAfter = cs.sizeRowCuts();
+    for (int k = numberRowCutsAfter - 1; k >= numberRowCutsBefore; k--) {
+      const OsiRowCut * thisCut = cs.rowCutPtr(k) ;
+      double sum = 0.0;
+      int n = thisCut->row().getNumElements();
+      const int * column = thisCut->row().getIndices();
+      const double * element = thisCut->row().getElements();
+      assert (n);
+      for (int i = 0; i < n; i++) {
+	double value = element[i];
+	sum += value * solution[column[i]];
+      }
+      if (sum > thisCut->ub() + primalTolerance) {
+	sum = sum - thisCut->ub();
+      } else if (sum < thisCut->lb() - primalTolerance) {
+	sum = thisCut->lb() - sum;
+      } else {
+	sum = 0.0;
+      }
+      if (!sum) {
+	// take out
+	cs.eraseRowCut(k);
+      }
+    }
+#ifdef CLP_INVESTIGATE2
+    printf("OR %p pass %d inTree %c - %d cuts (but %d deleted)\n",
+       originalSolver_,info.pass,info.inTree?'Y':'N',
+       numberRowCutsAfter-numberRowCutsBefore,
+       numberRowCutsAfter-cs.sizeRowCuts());
+#endif
+  }
+#endif
+
+  delete warmstart;
+  delete [] intVar;
+  if ((!info.inTree&&((info.options&4)==4||((info.options&8)&&!info.pass)))
+      ||(info.options&16)!=0) {
+    int limit = maximumLengthOfCutInTree();
+    int numberRowCutsAfter = cs.sizeRowCuts();
+    for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++) {
+      int length = cs.rowCutPtr(i)->row().getNumElements();
+      if (length<=limit)
+	cs.rowCutPtr(i)->setGloballyValid();
+    }
+  }
+  if ((gomoryType_%10)==2) {
+    // back to original
+    assert(clpSolver);
+    int numberRows = clpSolver->getNumRows();
+    if (numberRows>numberOriginalRows) {
+      int numberDelete = numberRows-numberOriginalRows;
+      int * delRow = new int [numberDelete];
+      for (int i=0;i<numberDelete;i++)
+	delRow[i]=i+numberOriginalRows;
+      clpSolver->deleteRows(numberDelete,delRow);
+      delete [] delRow;
+    }
+  }
+}
+
+// Returns value - floor but allowing for small errors
+inline double above_integer(double value) {
+  double value2=floor(value);
+  double value3=floor(value+0.5);
+  if (fabs(value3-value)<1.0e-7*(fabs(value3)+1.0))
+    return 0.0;
+  return value-value2;
+}
+//-------------------------------------------------------------------
+// Returns the greatest common denominator of two 
+// positive integers, a and b, found using Euclid's algorithm 
+//-------------------------------------------------------------------
+static int gcd(int a, int b) 
+{
+  int remainder = -1;
+#if CGL_DEBUG>1
+  printf("gcd of %d and %d\n",a,b);
+  int nLoop=0;
+#endif
+  // make sure a<=b (will always remain so)
+  if(a > b) {
+    // Swap a and b
+    int temp = a;
+    a = b;
+    b = temp;
+  }
+  // if zero then gcd is nonzero (zero may occur in rhs of packed)
+  if (!a) {
+    if (b) {
+      return b;
+    } else {
+      printf("**** gcd given two zeros!!\n");
+      abort();
+    }
+  }
+  while (remainder) {
+
+#if CGL_DEBUG>1
+    nLoop++;
+    if (nLoop>50) {
+      abort();
+      return -1;
+    }
+#endif
+    remainder = b % a;
+    b = a;
+    a = remainder;
+  }
+#if CGL_DEBUG>1
+  printf("=> %d\n",b);
+#endif
+  return b;
+}
+
+//-------------------------------------------------------------------
+// Returns the nearest rational with denominator < maxDenominator
+//-------------------------------------------------------------------
+typedef struct {
+  int numerator;
+  int denominator;
+} Rational;
+inline Rational nearestRational(double value, int maxDenominator) 
+{
+  Rational tryThis;
+  Rational tryA;
+  Rational tryB;
+  double integerPart;
+
+#if CGL_DEBUG>1
+  printf("Rational of %g is ",value);
+#endif
+  int nLoop=0;
+
+  tryA.numerator=0;
+  tryA.denominator=1;
+  tryB.numerator=1;
+  tryB.denominator=0;
+
+  if (fabs(value)<1.0e-10)
+    return tryA;
+  integerPart = floor(value);
+  value -= integerPart;
+  tryThis.numerator = tryB.numerator* static_cast<int> (integerPart) + tryA.numerator;
+  tryThis.denominator = tryB.denominator* static_cast<int> (integerPart) + tryA.denominator;
+  tryA = tryB;
+  tryB = tryThis;
+
+  while (value>1.0e-10 && tryB.denominator <=maxDenominator) {
+    nLoop++;
+    if (nLoop>50) {
+      Rational bad;
+      bad.numerator=-1;
+      bad.denominator=-1;
+#if CGL_DEBUG>1
+      printf(" *** bad rational\n");
+#endif
+      return bad;
+    }
+    value = 1.0/value;
+    integerPart = floor(value+1.0e-10);
+    value -= integerPart;
+    tryThis.numerator = tryB.numerator* static_cast<int> (integerPart) + tryA.numerator;
+    tryThis.denominator = tryB.denominator* static_cast<int>(integerPart) + tryA.denominator;
+    tryA = tryB;
+    tryB = tryThis;
+  }
+  if (tryB.denominator <= maxDenominator) {
+#if CGL_DEBUG>1
+    printf("%d/%d\n",tryB.numerator,tryB.denominator);
+#endif
+    return tryB;
+  } else {
+#if CGL_DEBUG>1
+    printf("%d/%d\n",tryA.numerator,tryA.denominator);
+#endif
+    return tryA;
+  }
+}
+// Does actual work - returns number of cuts
+int
+CglGomory::generateCuts( 
+#ifdef CGL_DEBUG
+			const OsiRowCutDebugger * debugger, 
+#else
+			const OsiRowCutDebugger * , 
+#endif
+                         OsiCuts & cs,
+                         const CoinPackedMatrix & columnCopy,
+                         const CoinPackedMatrix & rowCopy,
+                         const double * colsol,
+                         const double * colLower, const double * colUpper,
+                         const double * rowLower, const double * rowUpper,
+			 const char * intVar,
+                         const CoinWarmStartBasis* warm,
+                         const CglTreeInfo info)
+{
+  int infoOptions=info.options;
+  bool globalCuts = (infoOptions&16)!=0;
+  double testFixed = (!globalCuts) ? 1.0e-8 : -1.0;
+  // get what to look at
+  double away = info.inTree ? away_ : CoinMin(away_,awayAtRoot_);
+  int numberRows=columnCopy.getNumRows();
+  int numberColumns=columnCopy.getNumCols(); 
+  int numberElements=columnCopy.getNumElements();
+  // Allow bigger length on initial matrix (if special setting)
+  //if (limit==512&&!info.inTree&&!info.pass)
+  //limit=1024;
+  // Start of code to create a factorization from warm start (A) ====
+  // check factorization is okay
+  CoinFactorization factorization;
+#ifdef CLP_OSL
+  CoinOslFactorization * factorization2=NULL;
+  if (alternateFactorization_) {
+    factorization2 = new CoinOslFactorization();
+  }
+#endif
+  // We can either set increasing rows so ...IsBasic gives pivot row
+  // or we can just increment iBasic one by one
+  // for now let ...iBasic give pivot row
+  int status=-100;
+  // probably could use pivotVariables from OsiSimplexModel
+  int * rowIsBasic = new int[numberRows];
+  int * columnIsBasic = new int[numberColumns];
+  int i;
+  int numberBasic=0;
+  for (i=0;i<numberRows;i++) {
+    if (warm->getArtifStatus(i) == CoinWarmStartBasis::basic) {
+      rowIsBasic[i]=1;
+      numberBasic++;
+    } else {
+      rowIsBasic[i]=-1;
+    }
+  }
+  for (i=0;i<numberColumns;i++) {
+    if (warm->getStructStatus(i) == CoinWarmStartBasis::basic) {
+      columnIsBasic[i]=1;
+      numberBasic++;
+    } else {
+      columnIsBasic[i]=-1;
+    }
+  }
+  //returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
+  while (status<-98) {
+#ifdef CLP_OSL
+    if (!alternateFactorization_) {
+#endif
+      status=factorization.factorize(columnCopy,
+				     rowIsBasic, columnIsBasic);
+      if (status==-99) factorization.areaFactor(factorization.areaFactor() * 2.0);
+#ifdef CLP_OSL
+    } else {
+      double areaFactor=1.0;
+      status=factorization2->factorize(columnCopy,
+				      rowIsBasic, columnIsBasic,areaFactor);
+      if (status==-99) areaFactor *= 2.0;
+    }
+#endif
+  } 
+  if (status) {
+#ifdef COIN_DEVELOP
+    std::cout<<"Bad factorization of basis - status "<<status<<std::endl;
+#endif
+    delete [] rowIsBasic;
+    delete [] columnIsBasic;
+    return -1;
+  }
+  // End of creation of factorization (A) ====
+  
+#ifdef CLP_OSL
+  double relaxation = !alternateFactorization_ ? factorization.conditionNumber() :
+    factorization2->conditionNumber();
+#else
+  double relaxation = factorization.conditionNumber();
+#endif
+#ifdef COIN_DEVELOP_z
+  if (relaxation>1.0e49)
+    printf("condition %g\n",relaxation);
+#endif
+  relaxation *= conditionNumberMultiplier_;
+  double bounds[2]={-COIN_DBL_MAX,0.0};
+  int iColumn,iRow;
+
+  const int * column = rowCopy.getIndices();
+  const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+  const int * rowLength = rowCopy.getVectorLengths(); 
+  const double * rowElements = rowCopy.getElements();
+  const int * row = columnCopy.getIndices();
+  const CoinBigIndex * columnStart = columnCopy.getVectorStarts();
+  const int * columnLength = columnCopy.getVectorLengths(); 
+  const double * columnElements = columnCopy.getElements();
+
+  // we need to do book-keeping for variables at ub
+  double tolerance = 1.0e-7;
+  bool * swap= new bool [numberColumns];
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (columnIsBasic[iColumn]<0&&
+	colUpper[iColumn]-colsol[iColumn]<=tolerance) {
+      swap[iColumn]=true;
+    } else {
+      swap[iColumn]=false;
+    }
+  }
+
+  // get row activities (could use solver but lets do here )
+  double * rowActivity = new double [numberRows];
+  CoinFillN(rowActivity,numberRows,0.0);
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    double value = colsol[iColumn];
+    int k;
+    for (k=columnStart[iColumn];k<columnStart[iColumn]+columnLength[iColumn];k++) {
+      iRow = row[k];
+      rowActivity[iRow] += columnElements[k]*value;
+    }
+  }
+  /* we need to mark rows:
+     0) equality
+     1) slack at lb (activity at ub)
+     2) slack at ub (activity at lb)
+     and 4 bit is set if slack must be integer
+
+  */
+  int * rowType = new int[numberRows];
+  for (iRow=0;iRow<numberRows;iRow++) {
+    if (rowIsBasic[iRow]<0&&rowUpper[iRow]>rowLower[iRow]+1.0e-7) {
+      int type=0;
+      double rhs=0.0;
+      if (rowActivity[iRow]>=rowUpper[iRow]-1.0e-7) {
+	type=1;
+	rhs=rowUpper[iRow];
+      } else if (rowActivity[iRow]<=rowLower[iRow]+1.0e-7) {
+	type=2;
+	rhs=rowLower[iRow];
+      } else {
+	// probably large rhs
+	if (rowActivity[iRow]-rowLower[iRow]<
+	    rowUpper[iRow]-rowActivity[iRow])
+	  rowType[iRow]=2;
+	else
+	  rowType[iRow]=1;
+#ifdef CGL_DEBUG
+	assert (CoinMin(rowUpper[iRow]-rowActivity[iRow],
+		    rowActivity[iRow]-rowUpper[iRow])<1.0e-5);
+	//abort();
+        continue;
+#else
+	continue;
+#endif
+      }
+      if (above_integer(rhs)<1.0e-10) {
+	// could be integer slack
+	bool allInteger=true;
+	int k;
+	for (k=rowStart[iRow];
+	     k<rowStart[iRow]+rowLength[iRow];k++) {
+	  int iColumn=column[k];
+	  if (!intVar[iColumn]||above_integer(rowElements[k])>1.0e-10) {
+	    // not integer slacks
+	    allInteger=false;
+	    break;
+	  }
+	}
+	if (allInteger) {
+	  type |= 4;
+	}
+      }
+      rowType[iRow]=type;
+    } else {
+      // row is equality or basic
+      rowType[iRow]=0;
+    }
+  }
+
+  // Start of code to create work arrays for factorization (B) ====
+  // two vectors for updating (one is work)
+  CoinIndexedVector work;
+  CoinIndexedVector array;
+  // make sure large enough
+  work.reserve(numberRows);
+  array.reserve(numberRows);
+  int * arrayRows = array.getIndices();
+  double * arrayElements = array.denseVector();
+  // End of code to create work arrays (B) ====
+
+  int numberAdded=0;
+  // we also need somewhere to accumulate cut
+  CoinIndexedVector cutVector;
+  cutVector.reserve(numberColumns+1);
+  int * cutIndex = cutVector.getIndices();
+  double * cutElement = cutVector.denseVector(); 
+  // and for packed form (as not necessarily in order)
+  // also space for sort
+  bool doSorted = (infoOptions&256)!=0;
+  int lengthArray = static_cast<int>(numberColumns+1+((numberColumns+1)*sizeof(int))/sizeof(double));
+  if (doSorted)
+    lengthArray+=numberColumns;
+  double * packed = new double[lengthArray]; 
+  double * sort = packed+numberColumns+1;
+  int * which = reinterpret_cast<int *>(doSorted ? (sort+numberColumns): (sort));
+  double tolerance1=1.0e-6;
+  double tolerance2=0.9;
+  double tolerance3=1.0e-4;
+  double tolerance6=1.0e-6;
+  double tolerance9=1.0e-4;
+#define MORE_GOMORY_CUTS 1
+#ifdef CLP_INVESTIGATE2
+  int saveLimit = info.inTree ? 50 : 1000;
+#else
+#if MORE_GOMORY_CUTS==2||MORE_GOMORY_CUTS==3
+  int saveLimit;
+#endif  
+#endif  
+  // get limit on length of cut
+  int limit = 0;
+  if (!limit_)
+    dynamicLimitInTree_ = CoinMax(50,numberColumns/40);
+  if (!info.inTree) {
+    limit = limitAtRoot_;
+    if (!info.pass) {
+      tolerance1=1.0;
+      tolerance2=1.0e-2;
+      tolerance3=1.0e-6;
+      tolerance6=1.0e-7;
+      tolerance9=1.0e-5;
+      if (!limit)
+	limit=numberColumns;
+    } else {
+      if((infoOptions&32)==0/*&&numberTimesStalled_<3*/) {
+	if (!limit) {
+	  if(numberElements>8*numberColumns)
+	    limit=numberColumns;
+	  else
+	    limit = CoinMax(1000,numberRows/4);
+	}
+      } else {
+	limit=numberColumns;
+	numberTimesStalled_++;
+      } 
+    }
+  } else {
+    limit = limit_;
+    if (!limit) {
+      if (!info.pass) 
+	limit = dynamicLimitInTree_;
+      else
+	limit=50;
+    }
+  }
+  // If big - allow for rows
+  if (limit>=numberColumns)
+    limit += numberRows;
+#ifdef CLP_INVESTIGATE2
+  if (limit>saveLimit&&!info.inTree&&(infoOptions&512)==0) 
+    printf("Gomory limit changed from %d to %d, inTree %c, pass %d, r %d,c %d,e %d\n",
+	   saveLimit,limit,info.inTree ? 'Y' : 'N',info.pass,
+	   numberRows,numberColumns,numberElements);
+#endif
+  int nCandidates=0;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    // This returns pivot row for columns or -1 if not basic (C) ====
+    int iBasic=columnIsBasic[iColumn];
+    if (iBasic>=0&&intVar[iColumn]) {
+      double reducedValue=above_integer(colsol[iColumn]);
+      //printf("col %d bas %d val %.18g\n",iColumn,iBasic,colsol[iColumn]);
+      if(intVar[iColumn]&&reducedValue<1.0-away&&reducedValue>away) {
+	if (doSorted)
+	  sort[nCandidates]=fabs(0.5-reducedValue);
+	which[nCandidates++]=iColumn;
+      }
+    }
+  }
+  int nTotalEls=COIN_INT_MAX;
+  if (doSorted) {
+    CoinSort_2(sort,sort+nCandidates,which);
+    int nElsNow = columnCopy.getNumElements();
+    int nAdd;
+    int nAdd2;
+    int nReasonable;
+    int depth=info.level;
+    if (depth<2) {
+      nAdd=10000;
+      if (info.pass>0)
+	nAdd = CoinMin(nAdd,nElsNow+2*numberRows);
+      nAdd2 = 5*numberColumns;
+      nReasonable = CoinMax(nAdd2,nElsNow/8+nAdd);
+      if (!depth&&!info.pass) {
+	// allow more
+	nAdd += nElsNow/2;
+	nAdd2 += nElsNow/2;
+	nReasonable += nElsNow/2;
+	limit=numberRows+numberColumns;
+      }
+    } else {
+      nAdd = 200;
+      nAdd2 = 2*numberColumns;
+      nReasonable = CoinMax(nAdd2,nElsNow/8+nAdd);
+    }
+    nTotalEls=nReasonable;
+  }
+#ifdef MORE_GOMORY_CUTS
+  int saveTotalEls=nTotalEls;
+#endif
+#if MORE_GOMORY_CUTS==2||MORE_GOMORY_CUTS==3
+  saveLimit=limit;
+  if (doSorted)
+    limit=numberRows+numberColumns;
+  OsiCuts longCuts;
+#endif
+#if MORE_GOMORY_CUTS==1||MORE_GOMORY_CUTS==3
+  OsiCuts secondaryCuts;
+#endif
+  for (int kColumn=0;kColumn<nCandidates;kColumn++) {
+    if (nTotalEls<=0)
+      break;  // Got enough
+    iColumn=which[kColumn];
+    double reducedValue=above_integer(colsol[iColumn]);;
+    // This returns pivot row for columns or -1 if not basic (C) ====
+    int iBasic=columnIsBasic[iColumn];
+    double ratio=reducedValue/(1.0-reducedValue);
+    if (iBasic>=0) {
+  // Debug code below computes tableau column of basic ====
+      int j;
+#ifdef CGL_DEBUG
+      {
+	// put column into array
+	array.setVector(columnLength[iColumn],row+columnStart[iColumn],
+			columnElements+columnStart[iColumn]);
+	// get column in tableau
+#ifdef CLP_OSL
+	if (!alternateFactorization_)
+#endif
+	  factorization.updateColumn ( &work, &array );
+#ifdef CLP_OSL
+	else
+	  factorization2->updateColumn ( &work, &array );
+#endif
+	int nn=0;
+	int numberInArray=array.getNumElements();
+	for (j=0;j<numberInArray;j++) {
+	  int indexValue=arrayRows[j];
+	  double value=arrayElements[indexValue];
+	  if (fabs(value)>1.0e-5) {
+	    assert (fabs(value-1.0)<1.0e-7);
+	    assert (indexValue==iBasic);
+	    nn++;
+	  }
+	}
+	assert (nn==1);
+	array.clear();
+	work.checkClear();
+      }
+#endif
+      array.clear();
+      assert(intVar[iColumn]&&reducedValue<1.0-away&&reducedValue>away);
+      {
+#ifdef CGL_DEBUG
+	cutVector.checkClear();
+#endif
+	// get row of tableau
+	double one =1.0;
+	array.setVector(1,&iBasic,&one);
+	int numberNonInteger=0;
+	//Code below computes tableau row ====
+	// get pi
+#ifdef CLP_OSL
+	if (!alternateFactorization_)
+#endif
+	  factorization.updateColumnTranspose ( &work, &array );
+#ifdef CLP_OSL
+	else
+	  factorization2->updateColumnTranspose ( &work, &array );
+#endif
+	int numberInArray=array.getNumElements();
+#ifdef CGL_DEBUG
+	// check pivot on iColumn
+	{
+	  double value=0.0;
+	  int k;
+	  // add in row of tableau
+	  for (k=columnStart[iColumn];
+	       k<columnStart[iColumn]+columnLength[iColumn];k++) {
+	    iRow = row[k];
+	    value += columnElements[k]*arrayElements[iRow];
+	  }
+	  // should be 1
+	  assert (fabs(value-1.0) < 1.0e-7);
+	}
+#endif
+	double largestFactor=0.0;
+	for (j=0;j<numberInArray;j++) {
+	  int indexValue=arrayRows[j];
+	  double value=arrayElements[indexValue];
+	  largestFactor = CoinMax(largestFactor,fabs(value));
+	}
+	//reducedValue=colsol[iColumn];
+	// coding from pg 130 of Wolsey 
+	// adjustment to rhs
+	double rhs=0.0;
+	int number=0;
+#ifdef CGL_DEBUG_GOMORY
+	    if (!gomory_try)
+	      printf("start for basic column %d\n",iColumn);
+#endif
+	// columns
+	for (j=0;j<numberColumns;j++) {
+	  if (columnIsBasic[j]<0&&colUpper[j]>colLower[j]+testFixed) {
+	    double value=0.0;
+	    int k;
+	    // add in row of tableau
+	    for (k=columnStart[j];k<columnStart[j]+columnLength[j];k++) {
+	      iRow = row[k];
+	      double value2 = columnElements[k]*arrayElements[iRow];
+	      largestFactor = CoinMax(largestFactor,fabs(value2));
+	      value += value2;
+	    }
+#ifdef CGL_DEBUG_GOMORY
+	    if (!gomory_try&&value)
+	      printf("col %d alpha %g colsol %g swap %c bounds %g %g\n",
+		     j,value,colsol[j],swap[j] ? 'Y' : 'N',
+		     colLower[j],colUpper[j]);
+#endif
+	    // value is entry in tableau row end (C) ====
+	    if (fabs(value)<1.0e-16) {
+	      // small value
+	      continue;
+	    } else {
+	      // left in to stop over compilation?
+	      //if (iColumn==-52) printf("for basic %d, column %d has alpha %g, colsol %g\n",
+	      //		      iColumn,j,value,colsol[j]);
+#if CGL_DEBUG>1
+	      if (iColumn==52) printf("for basic %d, column %d has alpha %g, colsol %g\n",
+				      iColumn,j,value,colsol[j]);
+#endif
+	      // deal with bounds
+	      if (swap[j]) {
+		//reducedValue -= value*colUpper[j];
+		// negate
+		value = - value;
+	      } else {
+		//reducedValue -= value*colLower[j];
+	      }
+#if CGL_DEBUG>1
+	      if (iColumn==52) printf("%d value %g reduced %g int %d rhs %g swap %d\n",
+				      j,value,reducedValue,intVar[j],rhs,swap[j]);
+#endif
+	      double coefficient;
+	      if (intVar[j]) {
+		// integer
+		coefficient = above_integer(value);
+		if (coefficient > reducedValue) {
+		  coefficient = ratio * (1.0-coefficient);
+		} 
+	      } else {
+		// continuous
+		numberNonInteger++;
+		if (value > 0.0) {
+		  coefficient = value;
+		} else {
+		  //??? sign wrong in book
+		  coefficient = -ratio*value;
+		}
+	      }
+	      if (swap[j]) {
+		// negate
+		coefficient = - coefficient;
+		rhs += colUpper[j]*coefficient;
+	      } else {
+		rhs += colLower[j]*coefficient;
+	      }
+	      if (fabs(coefficient)>= COIN_INDEXED_TINY_ELEMENT) {
+		cutElement[j] = coefficient;
+		cutIndex[number++]=j;
+		// If too many - break from loop
+		if (number>limit) 
+		  break;
+	      }
+	    }
+	  } else {
+	    // basic
+	    continue;
+	  }
+	}
+	cutVector.setNumElements(number);
+	// If too many - just clear vector and skip
+	if (number>limit) {
+	  cutVector.clear();
+	  continue;
+	}
+	//check will be cut
+	//reducedValue=above_integer(reducedValue);
+	rhs += reducedValue;
+	double violation = reducedValue;
+#ifdef CGL_DEBUG
+	std::cout<<"cut has violation of "<<violation
+		 <<" value "<<colsol[iColumn]<<std::endl;
+#endif
+	// now do slacks part
+	for (j=0;j<numberInArray;j++) {
+	  iRow=arrayRows[j];
+	  double value = arrayElements[iRow];
+	  int type=rowType[iRow];
+	  if (type&&fabs(value)>=1.0e-16) {
+	    if ((type&1)==0) {
+	      // negate to get correct coefficient
+	      value = - value;
+	    }
+	    double coefficient;
+	    if ((type&4)!=0) {
+	      // integer
+	      coefficient = above_integer(value);
+	      if (coefficient > reducedValue) {
+		coefficient = ratio * (1.0-coefficient);
+	      } 
+	    } else {
+	      numberNonInteger++;
+	      // continuous
+	      if (value > 0.0) {
+		coefficient = value;
+	      } else {
+		coefficient = -ratio*value;
+	      }
+	    }
+	    if ((type&1)!=0) {
+	      // slack at ub - treat as +1.0
+	      rhs -= coefficient*rowUpper[iRow];
+	    } else {
+	      // negate yet again ?
+	      coefficient = - coefficient;
+	      rhs -= coefficient*rowLower[iRow];
+	    }
+	    int k;
+	    for (k=rowStart[iRow];
+		 k<rowStart[iRow]+rowLength[iRow];k++) {
+	      int jColumn=column[k];
+	      double value=rowElements[k];
+	      cutVector.quickAdd(jColumn,-coefficient*value);
+	    }
+	  }
+	}
+	//check again and pack down
+	// also change signs
+	// also zero cutElement
+	double sum=0.0;
+	rhs = - rhs;
+	int n = cutVector.getNumElements();
+#if MORE_GOMORY_CUTS==1||MORE_GOMORY_CUTS==3
+	double violation2=violation;
+#endif
+	number=0;
+	for (j=0;j<n;j++) {
+	  int jColumn =cutIndex[j];
+	  double value=-cutElement[jColumn];
+	  cutElement[jColumn]=0.0;
+	  if (fabs(value)>1.0e-8) {
+	    sum+=value*colsol[jColumn];
+	    packed[number]=value;
+	    cutIndex[number++]=jColumn;
+          } else {
+#define LARGE_BOUND 1.0e20
+            // small - adjust rhs if rhs reasonable
+            if (value>0.0&&colLower[jColumn]>-LARGE_BOUND) {
+              rhs -= value*colLower[jColumn];
+#if MORE_GOMORY_CUTS==1||MORE_GOMORY_CUTS==3
+	      // weaken violation
+	      violation2 -= fabs(value*(colsol[jColumn]-colLower[jColumn]));
+#endif
+            } else if (value<0.0&&colUpper[jColumn]<LARGE_BOUND) {
+              rhs -= value*colUpper[jColumn];
+#if MORE_GOMORY_CUTS==1||MORE_GOMORY_CUTS==3
+	      // weaken violation
+	      violation2 -= fabs(value*(colsol[jColumn]-colUpper[jColumn]));
+#endif
+            } else if (fabs(value)>1.0e-13) {
+              // take anyway
+              sum+=value*colsol[jColumn];
+              packed[number]=value;
+              cutIndex[number++]=jColumn;
+            } 
+          }
+	}
+	// Final test on number
+	//if (number>limit)
+	//continue;
+	// say zeroed out
+	cutVector.setNumElements(0);
+	bool accurate2=false;
+	double difference=fabs((sum-rhs)-violation);
+	double useTolerance;
+	if (tolerance1>0.99) {
+	  // use absolute
+	  useTolerance = tolerance;
+	} else {
+	  double rhs2=CoinMax(fabs(rhs),10.0);
+	  useTolerance=rhs2*0.1*tolerance1;
+	}
+	bool accurate = (difference<useTolerance);
+#if MORE_GOMORY_CUTS==1||MORE_GOMORY_CUTS==3
+	double difference2=fabs((sum-rhs)-violation2);
+#if MORE_GOMORY_CUTS==1
+	if (difference2<useTolerance&&doSorted) 
+#else
+	if (difference2<useTolerance&&doSorted&&number<saveLimit) 
+#endif
+	  accurate2=true;
+#endif
+	if (sum >rhs+tolerance2*away&&
+	    (accurate||accurate2)) {
+	  //#ifdef CGL_DEBUG
+#ifdef CGL_DEBUG
+#if CGL_DEBUG<=1
+	  if (number<=-10) {
+#endif
+	    for (j=0;j<number;j++) {
+	      std::cout<<" ["<<cutIndex[j]<<","<<packed[j]<<"]";
+	    }
+	    std::cout<<" <= "<<rhs<<std::endl;
+#if CGL_DEBUG<=1
+	  }
+#endif
+#endif
+	  if (!numberNonInteger&&number) {
+#ifdef CGL_DEBUG
+	    assert (sizeof(Rational)==sizeof(double));
+#endif
+	    Rational * cleaned = reinterpret_cast<Rational *> (cutElement);
+	    int * xInt = reinterpret_cast<int *> (cutElement);
+	    // cut should have an integer slack so try and simplify
+	    // add in rhs and put in cutElements (remember to zero later)
+	    cutIndex[number]=numberColumns+1;
+	    packed[number]=rhs;
+	    int numberNonSmall=0;
+	    int lcm = 1;
+	    
+	    for (j=0;j<number+1;j++) {
+	      double value=above_integer(fabs(packed[j]));
+	      if (fabs(value)<tolerance3) {
+		// too small
+		continue;
+	      } else {
+		numberNonSmall++;
+	      }
+	      
+	      cleaned[j]=nearestRational(value,100000);
+	      if (cleaned[j].denominator<0) {
+		// bad rational
+		lcm=-1;
+		break;
+	      }
+	      int thisGcd = gcd(lcm,cleaned[j].denominator);
+	      // may need to check for overflow
+	      lcm /= thisGcd;
+	      lcm *= cleaned[j].denominator;
+	    }
+	    if (lcm>0&&numberNonSmall) {
+	      double multiplier = lcm;
+	      int nOverflow = 0; 
+	      for (j=0; j<number+1;j++) {
+		double value = fabs(packed[j]);
+		double dxInt = value*multiplier;
+		xInt[j]= static_cast<int> (dxInt+0.5); 
+#if CGL_DEBUG>1
+		printf("%g => %g   \n",value,dxInt);
+#endif
+		if (dxInt>1.0e9||fabs(dxInt-xInt[j])> 1.0e-8) {
+		  nOverflow++;
+		  break;
+		}
+	      }
+	      
+	      if (nOverflow){
+#ifdef CGL_DEBUG
+		printf("Gomory Scaling: Warning: Overflow detected \n");
+#endif
+		numberNonInteger=-1;
+	      } else {
+		
+		// find greatest common divisor of the elements
+		j=0;
+		while (!xInt[j])
+		  j++; // skip zeros
+		int thisGcd = gcd(xInt[j],xInt[j+1]);
+		j++;
+		for (;j<number+1;j++) {
+		  if (xInt[j])
+		    thisGcd = gcd(thisGcd,xInt[j]);
+		}
+#if 0
+		// Check nothing too illegal - FIX this
+		for (j=0;j<number+1;j++) {
+		  double old = lcm*packed[j];
+		  int newOne;
+		  if (old>0.0)
+		    newOne=xInt[j]/thisGcd;
+		  else
+		    newOne=-xInt[j]/thisGcd;
+		  if (fabs(((double) newOne)-old)>
+		      1.0e-10*(fabs(newOne)+1.0)) {
+		    // say no good - first see if happens
+		    printf("Fix this test 456 - just skip\n");
+		    abort();
+		  }
+		} 
+#endif		  
+#if CGL_DEBUG>1
+		printf("The gcd of xInt is %i\n",thisGcd);    
+#endif
+		
+		// construct new cut by dividing through by gcd and 
+		double minMultiplier=1.0e100;
+		double maxMultiplier=0.0;
+		for (j=0; j<number+1;j++) {
+		  double old=packed[j];
+		  if (old>0.0) {
+		    packed[j]=xInt[j]/thisGcd;
+		  } else {
+		    packed[j]=-xInt[j]/thisGcd;
+		  }
+#if CGL_DEBUG>1
+		  printf("%g => %g   \n",old,packed[j]);
+#endif
+		  if (packed[j]) {
+		    if (fabs(packed[j])>maxMultiplier*fabs(old))
+		      maxMultiplier = packed[j]/old;
+		    if (fabs(packed[j])<minMultiplier*fabs(old))
+		      minMultiplier = packed[j]/old;
+		  }
+		}
+		rhs = packed[number];
+#ifdef CGL_DEBUG
+		printf("min, max multipliers - %g, %g\n",
+		       minMultiplier,maxMultiplier);
+#endif
+		assert(maxMultiplier/minMultiplier>0.9999&&maxMultiplier/minMultiplier<1.0001);
+	      }
+	    }
+	    // erase cutElement
+	    CoinFillN(cutElement,number+1,0.0);
+	  } else {
+	    // relax rhs a tiny bit
+	    rhs += 1.0e-8;
+	    // relax if lots of elements for mixed gomory
+	    if (number>=20) {
+	      rhs  += 1.0e-7*(static_cast<double> (number/20));
+	    }
+	  }
+	  // Take off tiny elements
+	  // for first pass reject
+#define TINY_ELEMENT 1.0e-12
+	  {
+	    int i,number2=number;
+	    number=0;
+	    double largest=0.0;
+	    double smallest=1.0e30;
+	    for (i=0;i<number2;i++) {
+	      double value=fabs(packed[i]);
+	      if (value<TINY_ELEMENT) {
+		int iColumn = cutIndex[i];
+		if (colUpper[iColumn]-colLower[iColumn]<LARGE_BOUND) {
+		  // weaken cut
+		  if (packed[i]>0.0) 
+		    rhs -= value*colLower[iColumn];
+		  else
+		    rhs += value*colUpper[iColumn];
+		} else {
+		  // throw away
+		  number=limit+1;
+		  numberNonInteger=1;
+		  break;
+		}
+	      } else {
+		int iColumn = cutIndex[i];
+		if (colUpper[iColumn]!=colLower[iColumn]||globalCuts) {
+		  largest=CoinMax(largest,value);
+		  smallest=CoinMin(smallest,value);
+		  cutIndex[number]=cutIndex[i];
+		  packed[number++]=packed[i];
+		} else {
+		  // fixed so subtract out
+		  rhs -= packed[i]*colLower[iColumn];
+		}
+	      }
+	    }
+	    if (largest>1.0e10*smallest) {
+	      number=limit+1; //reject
+	      numberNonInteger=1;
+	    } else if (largest>1.0e9*smallest) {
+#ifdef CLP_INVESTIGATE2
+	      printf("WOuld reject %g %g ratio %g\n",smallest,largest,
+		     smallest/largest);
+#endif
+#if MORE_GOMORY_CUTS==1||MORE_GOMORY_CUTS==3
+	      accurate=false;
+#endif
+	    }
+	  }
+	  if (number<limit||!numberNonInteger) {
+	    bounds[1]=rhs;
+	    if (number>50&&numberNonInteger)
+	      bounds[1] = rhs+tolerance6+1.0e-8*fabs(rhs); // weaken
+	    double test = CoinMin(largestFactor*largestFactorMultiplier_,
+				  relaxation);
+	    if (number>5&&numberNonInteger&&test>1.0e-20) {
+#ifdef CLP_INVESTIGATE2
+	      printf("relaxing rhs by %g - largestFactor was %g, rel %g\n",
+	         CoinMin(test*fabs(rhs),tolerance9),largestFactor,relaxation);
+#endif
+	      //bounds[1] = CoinMax(bounds[1],
+	      //		  rhs+CoinMin(test*fabs(rhs),tolerance9)); // weaken
+	      bounds[1] = bounds[1]+CoinMin(test*fabs(rhs),tolerance9); // weaken
+	    }
+#ifdef MORE_GOMORY_CUTS
+	    if (accurate) {
+#else
+	    {
+#endif
+	      OsiRowCut rc;
+	      rc.setRow(number,cutIndex,packed,false);
+	      rc.setLb(bounds[0]);
+	      rc.setUb(bounds[1]);   
+#if MORE_GOMORY_CUTS<2
+	      nTotalEls -= number;
+	      cs.insert(rc);
+#else
+	      if(number<saveLimit) {
+		nTotalEls -= number;
+		cs.insert(rc);
+	      } else {
+		longCuts.insert(rc);
+	      }
+#endif
+	      //printf("nTot %d kCol %d iCol %d ibasic %d\n",
+	      //     nTotalEls,kColumn,iColumn,iBasic);
+	      numberAdded++;
+#if MORE_GOMORY_CUTS==1||MORE_GOMORY_CUTS==3
+	    } else if (accurate2) {
+	      OsiRowCut rc;
+	      rc.setRow(number,cutIndex,packed,false);
+	      rc.setLb(bounds[0]);
+	      rc.setUb(bounds[1]);   
+	      secondaryCuts.insert(rc);
+#endif
+	    }
+	  } else {
+#ifdef CGL_DEBUG
+	    std::cout<<"cut has "<<number<<" entries - skipped"
+		     <<std::endl;
+	    if (!number)
+	      std::cout<<"******* Empty cut - infeasible"<<std::endl;
+#endif
+	  }
+	} else {
+	  // why dropped?
+#ifdef CGL_DEBUG
+	  std::cout<<"first violation "<<violation<<" now "
+		   <<sum-rhs<<" why?, rhs= "<<rhs<<std::endl;
+	  
+	  for (j=0;j<number;j++) {
+	    int jColumn =cutIndex[j];
+	    double value=packed[j];
+	    std::cout<<"("<<jColumn<<","<<value<<","<<colsol[jColumn]
+		     <<") ";
+	  }
+	  std::cout<<std::endl;
+	  //abort();
+#endif
+	}
+      }
+    } else {
+      // not basic
+#if CGL_DEBUG>1
+      {
+	// put column into array
+	array.setVector(columnLength[iColumn],row+columnStart[iColumn],
+			columnElements+columnStart[iColumn]);
+	// get column in tableau
+#ifdef CLP_OSL
+	if (!alternateFactorization_)
+#endif
+	  factorization.updateColumn ( &work, &array );
+#ifdef CLP_OSL
+	else
+	  factorization2->updateColumn ( &work, &array );
+#endif
+	int numberInArray=array.getNumElements();
+	printf("non-basic %d\n",iColumn);
+	for (int j=0;j<numberInArray;j++) {
+	  int indexValue=arrayRows[j];
+	  double value=arrayElements[indexValue];
+	  if (fabs(value)>1.0e-6) {
+	    printf("%d %g\n",indexValue,value);
+	  }
+	}
+      }
+#endif
+    }
+  }
+#ifdef CLP_OSL
+  delete factorization2;
+#endif
+
+  delete [] rowActivity;
+  delete [] swap;
+  delete [] rowType;
+  delete [] packed;
+  delete [] rowIsBasic;
+  delete [] columnIsBasic;
+#ifdef MORE_GOMORY_CUTS
+#if MORE_GOMORY_CUTS==1
+  int numberInaccurate = secondaryCuts.sizeRowCuts();
+#ifdef CLP_INVESTIGATE2
+  int numberOrdinary = numberAdded-numberInaccurate;
+  if (!info.inTree&&(infoOptions&512)==0) 
+    printf("Gomory has %d ordinary and %d less accurate cuts(%d els)\n",
+	   numberOrdinary,numberInaccurate,saveTotalEls-nTotalEls);
+#endif
+#elif MORE_GOMORY_CUTS==2
+  int numberLong = longCuts.sizeRowCuts();
+#ifdef CLP_INVESTIGATE2
+  int numberOrdinary = numberAdded-numberLong;
+  if (!info.inTree&&(infoOptions&512)==0) 
+    printf("Gomory has %d ordinary and %d long cuts(%d els)\n",
+	   numberOrdinary,numberLong,saveTotalEls-nTotalEls);
+#endif
+#elif MORE_GOMORY_CUTS==3
+  int numberLong = longCuts.sizeRowCuts();
+  int numberInaccurate = secondaryCuts.sizeRowCuts();
+#ifdef CLP_INVESTIGATE2
+  int numberOrdinary = numberAdded-numberLong-numberInaccurate;
+  if (!info.inTree&&(infoOptions&512)==0) 
+    printf("Gomory has %d ordinary, %d long and %d less accurate cuts(%d els)\n",
+	   numberOrdinary,numberLong,numberInaccurate,saveTotalEls-nTotalEls);
+#endif
+#endif
+  if (doSorted&&limit<numberColumns) {
+    // Just half
+    nTotalEls -= saveTotalEls/2;
+#if MORE_GOMORY_CUTS==2||MORE_GOMORY_CUTS==3
+    while (nTotalEls>0) {
+      for (int i=0;i<numberLong;i++) {
+	nTotalEls -= longCuts.rowCutPtr(i)->row().getNumElements();
+	cs.insert(longCuts.rowCut(i));
+	numberAdded ++;
+	if (nTotalEls<=0)
+	  break;
+      }
+      break;
+    }
+#endif
+#if MORE_GOMORY_CUTS==1||MORE_GOMORY_CUTS==3
+    while (nTotalEls>0) {
+      for (int i=0;i<numberInaccurate;i++) {
+	nTotalEls -= secondaryCuts.rowCutPtr(i)->row().getNumElements();
+	cs.insert(secondaryCuts.rowCut(i));
+	numberAdded ++;
+	if (nTotalEls<=0)
+	  break;
+      }
+      break;
+    }
+#endif
+  }
+#else
+#ifdef CLP_INVESTIGATE2
+  if (!info.inTree&&(infoOptions&512)==0) 
+    printf("Gomory added %d cuts(%d els)\n",numberAdded,saveTotalEls-nTotalEls);
+#endif
+#endif
+  return numberAdded;
+}
+// Limit stuff
+void CglGomory::setLimit(int limit)
+{
+  if (limit>=0)
+    limit_=limit; 
+}
+int CglGomory::getLimit() const
+{
+  return limit_;
+}
+// Limit stuff at root
+void CglGomory::setLimitAtRoot(int limit)
+{
+  if (limit>=0)
+    limitAtRoot_=limit;
+}
+int CglGomory::getLimitAtRoot() const
+{
+  return limitAtRoot_;
+}
+// Return maximum length of cut in tree
+int 
+CglGomory::maximumLengthOfCutInTree() const
+{
+  if (limit_)
+    return limit_;
+  else
+    return dynamicLimitInTree_;
+}
+
+// Away stuff
+void CglGomory::setAway(double value)
+{
+  if (value>0.0&&value<=0.5)
+    away_=value;
+}
+double CglGomory::getAway() const
+{
+  return away_;
+}
+
+// Away stuff at root
+void CglGomory::setAwayAtRoot(double value)
+{
+  if (value>0.0&&value<=0.5)
+    awayAtRoot_=value;
+}
+double CglGomory::getAwayAtRoot() const
+{
+  return awayAtRoot_;
+}
+
+// ConditionNumberMultiplier stuff
+void CglGomory::setConditionNumberMultiplier(double value)
+{
+  if (value>=0.0)
+    conditionNumberMultiplier_=value;
+}
+double CglGomory::getConditionNumberMultiplier() const
+{
+  return conditionNumberMultiplier_;
+}
+
+// LargestFactorMultiplier stuff
+void CglGomory::setLargestFactorMultiplier(double value)
+{
+  if (value>=0.0)
+    largestFactorMultiplier_=value;
+}
+double CglGomory::getLargestFactorMultiplier() const
+{
+  return largestFactorMultiplier_;
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglGomory::CglGomory ()
+:
+CglCutGenerator(),
+away_(0.05),
+awayAtRoot_(0.05),
+conditionNumberMultiplier_(1.0e-18),
+largestFactorMultiplier_(1.0e-13),
+originalSolver_(NULL),
+limit_(50),
+limitAtRoot_(0),
+dynamicLimitInTree_(-1),
+alternateFactorization_(0),
+gomoryType_(0)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglGomory::CglGomory (const CglGomory & source) :
+  CglCutGenerator(source),
+  away_(source.away_),
+  awayAtRoot_(source.awayAtRoot_),
+  conditionNumberMultiplier_(source.conditionNumberMultiplier_),
+  largestFactorMultiplier_(source.largestFactorMultiplier_),
+  originalSolver_(NULL),
+  limit_(source.limit_),
+  limitAtRoot_(source.limitAtRoot_),
+  dynamicLimitInTree_(source.dynamicLimitInTree_),
+  alternateFactorization_(source.alternateFactorization_),
+  gomoryType_(source.gomoryType_)
+{ 
+  if (source.originalSolver_)
+    originalSolver_ = source.originalSolver_->clone();
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglGomory::clone() const
+{
+  return new CglGomory(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglGomory::~CglGomory ()
+{
+  delete originalSolver_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglGomory &
+CglGomory::operator=(const CglGomory& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    away_=rhs.away_;
+    awayAtRoot_=rhs.awayAtRoot_;
+    conditionNumberMultiplier_ = rhs.conditionNumberMultiplier_;
+    largestFactorMultiplier_ = rhs.largestFactorMultiplier_;
+    limit_=rhs.limit_;
+    limitAtRoot_=rhs.limitAtRoot_;
+    dynamicLimitInTree_ = rhs.dynamicLimitInTree_;
+    alternateFactorization_=rhs.alternateFactorization_; 
+    gomoryType_ = rhs.gomoryType_;
+    delete originalSolver_;
+    if (rhs.originalSolver_)
+      originalSolver_ = rhs.originalSolver_->clone();
+    else
+      originalSolver_=NULL;
+  }
+  return *this;
+}
+// This can be used to refresh any information
+void 
+CglGomory::refreshSolver(OsiSolverInterface * solver)
+{
+  int numberColumns=solver->getNumCols(); 
+  const double * colUpper = solver->getColUpper();
+  const double * colLower = solver->getColLower();
+  canDoGlobalCuts_ = true;
+  if (originalSolver_) {
+    delete originalSolver_;
+    originalSolver_ = solver->clone();
+  }
+  for (int i=0;i<numberColumns;i++) {
+    if (solver->isInteger(i)) {
+      if (colUpper[i]>colLower[i]+1.0) {
+	canDoGlobalCuts_ = false;
+	break;
+      }
+    }
+  }
+}
+// Pass in a copy of original solver (clone it)
+void 
+CglGomory::passInOriginalSolver(OsiSolverInterface * solver)
+{
+  delete originalSolver_;
+  if (solver) {
+    if (!gomoryType_)
+      gomoryType_=1;
+    originalSolver_ = solver->clone();
+  } else {
+    gomoryType_=0;
+    originalSolver_=NULL;
+  }
+}
+// Does actual work - returns number of cuts
+int
+CglGomory::generateCuts( const OsiRowCutDebugger * debugger, 
+                         OsiCuts & cs,
+                         const CoinPackedMatrix & columnCopy,
+                         const double * colsol,
+                         const double * colLower, const double * colUpper,
+                         const double * rowLower, const double * rowUpper,
+			 const char * intVar,
+                         const CoinWarmStartBasis* warm,
+                         const CglTreeInfo info)
+{
+  CoinPackedMatrix rowCopy;
+  rowCopy.reverseOrderedCopyOf(columnCopy);
+  return generateCuts( debugger, cs, columnCopy, rowCopy,
+		       colsol, colLower, colUpper,
+		       rowLower, rowUpper, intVar, warm, info);
+}
+// Create C++ lines to get to current state
+std::string
+CglGomory::generateCpp( FILE * fp) 
+{
+  CglGomory other;
+  fprintf(fp,"0#include \"CglGomory.hpp\"\n");
+  fprintf(fp,"3  CglGomory gomory;\n");
+  if (limit_!=other.limit_)
+    fprintf(fp,"3  gomory.setLimit(%d);\n",limit_);
+  else
+    fprintf(fp,"4  gomory.setLimit(%d);\n",limit_);
+  if (limitAtRoot_!=other.limitAtRoot_)
+    fprintf(fp,"3  gomory.setLimitAtRoot(%d);\n",limitAtRoot_);
+  else
+    fprintf(fp,"4  gomory.setLimitAtRoot(%d);\n",limitAtRoot_);
+  if (away_!=other.away_)
+    fprintf(fp,"3  gomory.setAway(%g);\n",away_);
+  else
+    fprintf(fp,"4  gomory.setAway(%g);\n",away_);
+  if (awayAtRoot_!=other.awayAtRoot_)
+    fprintf(fp,"3  gomory.setAwayAtRoot(%g);\n",awayAtRoot_);
+  else
+    fprintf(fp,"4  gomory.setAwayAtRoot(%g);\n",awayAtRoot_);
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  gomory.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  gomory.setAggressiveness(%d);\n",getAggressiveness());
+  return "gomory";
+}
diff --git a/cbits/coin/CglGomory.hpp b/cbits/coin/CglGomory.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglGomory.hpp
@@ -0,0 +1,204 @@
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglGomory_H
+#define CglGomory_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+
+class CoinWarmStartBasis;
+/** Gomory Cut Generator Class */
+class CglGomory : public CglCutGenerator {
+   friend void CglGomoryUnitTest(const OsiSolverInterface * siP,
+				  const std::string mpdDir );
+ 
+public:
+    
+  
+  /**@name Generate Cuts */
+  //@{
+  /** Generate Mixed Integer Gomory cuts for the model of the 
+      solver interface, si.
+
+      Insert the generated cuts into OsiCut, cs.
+
+      There is a limit option, which will only generate cuts with
+      less than this number of entries.
+
+      We can also only look at 0-1 variables a certain distance
+      from integer.
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+  /** Generates cuts given matrix and solution etc,
+      returns number of cuts generated */
+  int generateCuts( const OsiRowCutDebugger * debugger, 
+		    OsiCuts & cs,
+		    const CoinPackedMatrix & columnCopy,
+		    const CoinPackedMatrix & rowCopy,
+		    const double * colsol,
+		    const double * colLower, const double * colUpper,
+		    const double * rowLower, const double * rowUpper,
+		    const char * intVar ,
+		    const CoinWarmStartBasis* warm,
+                    const CglTreeInfo info = CglTreeInfo());
+  /** Generates cuts given matrix and solution etc,
+      returns number of cuts generated (no row copy passed in) */
+  int generateCuts( const OsiRowCutDebugger * debugger, 
+		    OsiCuts & cs,
+		    const CoinPackedMatrix & columnCopy,
+		    const double * colsol,
+		    const double * colLower, const double * colUpper,
+		    const double * rowLower, const double * rowUpper,
+		    const char * intVar ,
+		    const CoinWarmStartBasis* warm,
+                    const CglTreeInfo info = CglTreeInfo());
+
+  /// Return true if needs optimal basis to do cuts (will return true)
+  virtual bool needsOptimalBasis() const { return true; }
+  //@}
+
+  /**@name Change way Gomory works */
+  //@{
+  /// Pass in a copy of original solver (clone it)
+  void passInOriginalSolver(OsiSolverInterface * solver);
+  /// Returns original solver
+  inline OsiSolverInterface * originalSolver() const
+  { return originalSolver_;}
+  /// Set type - 0 normal, 1 add original matrix one, 2 replace
+  inline void setGomoryType(int type)
+  { gomoryType_=type;}
+  /// Return type
+  inline int gomoryType() const
+  { return gomoryType_;}
+  //@}
+
+  /**@name Change limit on how many variables in cut (default 50) */
+  //@{
+  /// Set
+  void setLimit(int limit);
+  /// Get
+  int getLimit() const;
+  /// Set at root (if <normal then use normal)
+  void setLimitAtRoot(int limit);
+  /// Get at root
+  int getLimitAtRoot() const;
+  /// Return maximum length of cut in tree
+  virtual int maximumLengthOfCutInTree() const;
+  //@}
+
+  /**@name Change criterion on which variables to look at.  All ones
+   more than "away" away from integrality will be investigated 
+  (default 0.05) */
+  //@{
+  /// Set away
+  void setAway(double value);
+  /// Get away
+  double getAway() const;
+  /// Set away at root
+  void setAwayAtRoot(double value);
+  /// Get away at root
+  double getAwayAtRoot() const;
+  //@}
+
+  /**@name Change criterion on which the cut id relaxed if the code
+           thinks the factorization has inaccuracies.  The relaxation to
+	   RHS is smallest of -
+	   1) 1.0e-4
+	   2) conditionNumberMultiplier * condition number of factorization
+	   3) largestFactorMultiplier * largest (dual*element) forming tableau
+	      row
+  */
+  //@{
+  /// Set ConditionNumberMultiplier
+  void setConditionNumberMultiplier(double value);
+  /// Get ConditionNumberMultiplier
+  double getConditionNumberMultiplier() const;
+  /// Set LargestFactorMultiplier
+  void setLargestFactorMultiplier(double value);
+  /// Get LargestFactorMultiplier
+  double getLargestFactorMultiplier() const;
+  //@}
+
+  /**@name change factorization */
+  //@{
+   /// Set/unset alternative factorization
+   inline void useAlternativeFactorization(bool yes=true)
+   { alternateFactorization_= (yes) ? 1 : 0;} 
+   /// Get whether alternative factorization being used
+   inline bool alternativeFactorization() const
+   { return (alternateFactorization_!=0);} 
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglGomory ();
+ 
+  /// Copy constructor 
+  CglGomory (
+    const CglGomory &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglGomory &
+    operator=(
+    const CglGomory& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglGomory ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  /// This can be used to refresh any inforamtion
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  //@}
+      
+private:
+  
+ // Private member methods
+
+  // Private member data
+
+  /**@name Private member data */
+  //@{
+  /// Only investigate if more than this away from integrality
+  double away_;
+  /// Only investigate if more than this away from integrality (at root)
+  double awayAtRoot_;
+  /// Multiplier for conditionNumber cut relaxation
+  double conditionNumberMultiplier_;
+  /// Multiplier for largest factor cut relaxation
+  double largestFactorMultiplier_;
+  /// Original solver
+  OsiSolverInterface * originalSolver_;
+  /// Limit - only generate if fewer than this in cut
+  int limit_;
+  /// Limit - only generate if fewer than this in cut (at root)
+  int limitAtRoot_;
+  /// Dynamic limit in tree
+  int dynamicLimitInTree_;
+  /// Number of times stalled
+  int numberTimesStalled_;
+  /// nonzero to use alternative factorization
+  int alternateFactorization_;
+  /// Type - 0 normal, 1 add original matrix one, 2 replace
+  int gomoryType_;
+  //@}
+};
+
+//#############################################################################
+/** A function that tests the methods in the CglGomory class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglGomoryUnitTest(const OsiSolverInterface * siP,
+			const std::string mpdDir );
+  
+#endif
diff --git a/cbits/coin/CglKnapsackCover.cpp b/cbits/coin/CglKnapsackCover.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglKnapsackCover.cpp
@@ -0,0 +1,4154 @@
+// $Id: CglKnapsackCover.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cassert>
+#include <cfloat>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CglKnapsackCover.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinSort.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "OsiRowCutDebugger.hpp"
+#define GUBCOVER 1
+//#define PRINT_DEBUG
+//#define CGL_DEBUG 1
+//-----------------------------------------------------------------------------
+// Generate knapsack cover cuts
+//------------------------------------------------------------------- 
+void CglKnapsackCover::generateCuts(const OsiSolverInterface& si, OsiCuts& cs,
+				    const CglTreeInfo info)
+{
+  // Get basic problem information
+  int nRows=si.getNumRows(); 
+  int nCols=si.getNumCols(); 
+
+  // Create working space for "canonical" knapsack inequality
+  // - krow will contain the coefficients and indices of the 
+  // (potentially complemented) variables in the knapsack inequality.
+  // - b is the rhs of knapsack inequality.
+  // - complement[i] is 1 if the index i in krow refers to the complement
+  // of the variable, and 0 otherwise. 
+  CoinPackedVector krow; 
+  double b=0.0;
+  int numberRowCutsBefore = cs.sizeRowCuts();
+  int * complement= new int[nCols];
+  complement_ = complement;
+#if GUBCOVER==1
+  elements_=new double [2*nCols];
+  CoinZeroN(elements_,2*nCols);
+#elif GUBCOVER==2
+  int size1=4*nCols+2*numberCliques_;
+  int size2=2*nCols+5*numberCliques_+5;
+  elements_=reinterpret_cast<double *>(new int [size2+size1*sizeof(double)/sizeof(int)]);
+  CoinZeroN(elements_,2*nCols+2*numberCliques_);
+  int * restInd = reinterpret_cast<int *> (elements_+size1);
+  CoinFillN(restInd,nCols,-2);
+#endif
+    
+  // Create a local copy of the column solution (colsol), call it xstar, and
+  // inititalize it. 
+  // Assumes the lp-relaxation has been solved, and the solver interface
+  // has a meaningful colsol.
+  double * xstar= new double[nCols];
+  solver_ = &si;
+
+  // To allow for vub knapsacks
+  int * thisColumnIndex = new int [nCols];
+  double * thisElement = new double[nCols];
+  int * back = new int[nCols];
+  
+  const double *colsol = si.getColSolution(); 
+  int k; 
+  // For each row point to vub variable
+  // -1 if no vub
+  // -2 if can skip row for knapsacks
+
+  int * vub = new int [nRows];
+
+  // Now vubValue are for positive coefficients and vlbValue for negative
+  // when L row
+  // For each column point to vub row
+  int * vubRow = new int [nCols];
+  double * vubValue = new double [nRows];
+
+  // For each column point to vlb row
+  int * vlbRow = new int [nCols];
+  double * vlbValue = new double [nRows];
+
+  // Take out all fixed
+  double * effectiveUpper = new double [nRows];
+  double * effectiveLower = new double [nRows];
+  const double * colUpper = si.getColUpper();
+  const double * colLower = si.getColLower();
+  for (k=0; k<nCols; k++){
+    back[k]=-1;
+    xstar[k]=colsol[k];
+    if (xstar[k]>colUpper[k])
+      xstar[k]=colUpper[k];
+    else if (xstar[k]<colLower[k])
+      xstar[k]=colLower[k];
+    complement[k]=0;
+    vubRow[k]=-1;
+    vlbRow[k]=-1;
+    if (si.isBinary(k)) {
+      if (si.isFreeBinary(k)) {
+	vubRow[k]=-2;
+	vlbRow[k]=-2;
+      } else {
+	vubRow[k]=-10;
+	vlbRow[k]=-10;
+      }
+    } else if (colUpper[k]==colLower[k]) {
+      vubRow[k]=-10; // fixed
+      vlbRow[k]=-10; // fixed
+    }
+  }
+
+  int rowIndex;
+  int numberVub=0;
+
+  const CoinPackedMatrix * matrixByRow = si.getMatrixByRow();
+  const double * elementByRow = matrixByRow->getElements();
+  const int * column = matrixByRow->getIndices();
+  const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+  const int * rowLength = matrixByRow->getVectorLengths();
+  const double * rowUpper = si.getRowUpper();
+  const double * rowLower = si.getRowLower();
+
+  // Scan all rows looking for possibles
+
+  for (rowIndex=0;rowIndex<nRows;rowIndex++) {
+    vub[rowIndex]=-1;
+    int start = rowStart[rowIndex];
+    int end = start + rowLength[rowIndex];
+    double upRhs = rowUpper[rowIndex]; 
+    double loRhs = rowLower[rowIndex]; 
+    double multiplier=0.0;
+    if (upRhs>1.0e20)
+      multiplier=-1.0;
+    else if (loRhs<-1.0e20)
+      multiplier=1.0;
+    int numberContinuous=0;
+    int numberBinary=0;
+    int iCont=-1;
+    double sum = 0.0;
+    double valueContinuous=0.0;
+#ifdef PRINT_DEBUG
+    double valueBinary=0.0;
+    int iBinary=-1;
+#endif
+    int j;
+    for (j=start;j<end;j++) {
+      int iColumn=column[j];
+      double value = elementByRow[j];
+      if (colUpper[iColumn]>colLower[iColumn]) {
+	sum += xstar[iColumn]*value;
+	if (vubRow[iColumn]==-2&&value*multiplier>0.0) {
+	  // binary
+	  numberBinary++;
+#ifdef PRINT_DEBUG
+	  valueBinary=value;
+	  iBinary=iColumn;
+#endif
+	} else if (vlbRow[iColumn]==-2&&value*multiplier<0.0) {
+	  // binary
+	  numberBinary++;
+#ifdef PRINT_DEBUG
+	  valueBinary=value;
+     iBinary=iColumn;
+#endif
+	} else if (vubRow[iColumn]==-1) {
+	  // only use if not at bound
+          //	  if (colsol[iColumn]<colUpper[iColumn]-1.0e-6&&
+          //  colsol[iColumn]>colLower[iColumn]+1.0e-6) {
+	    // possible
+	    iCont=iColumn;
+	    numberContinuous++;
+	    valueContinuous=value;
+            //} else {
+	    //// ** needs more thought
+	    //numberContinuous ++;
+	    //iCont=-1;
+            //}
+	} else {
+	  // ** needs more thought
+	  numberContinuous ++;
+	  iCont=-1;
+	  //if (colsol[iColumn]<colUpper[iColumn]-1.0e-6&&
+          //  colsol[iColumn]>colLower[iColumn]+1.0e-6) {
+          //// already assigned
+          //numberContinuous ++;
+          //iCont=-1;
+	  //}
+	}
+      } else {
+	// fixed
+	upRhs -= colLower[iColumn]*value;
+	loRhs -= colLower[iColumn]*value;
+      }
+    }
+    // see if binding
+    effectiveUpper[rowIndex] = upRhs;
+    effectiveLower[rowIndex] = loRhs;
+    bool possible = false;
+    if (fabs(sum-upRhs)<1.0e-5) {
+      possible=true;
+    } else {
+      effectiveUpper[rowIndex]=COIN_DBL_MAX;
+    }
+    if (fabs(sum-loRhs)<1.0e-5) {
+      possible=true;
+    } else {
+      effectiveLower[rowIndex]=-COIN_DBL_MAX;
+    }
+    if (possible&&numberBinary&&numberBinary+numberContinuous<=maxInKnapsack_) {
+      // binding with binary
+      if(numberContinuous==1&&iCont>=0&&numberBinary==1) {
+	// vub
+#ifdef PRINT_DEBUG
+	printf("vub/vlb (by row %d) %g <= 0-1 %g * %d + %g * %d <= %g\n",
+	       rowIndex,effectiveLower[rowIndex],valueBinary,iBinary,
+	       valueContinuous,iCont,effectiveUpper[rowIndex]);
+#endif
+        if (multiplier*valueContinuous>0.0) {
+          vubValue[rowIndex] = valueContinuous;
+          vubRow[iCont]=rowIndex;
+        } else {
+          vlbValue[rowIndex] = valueContinuous;
+          vlbRow[iCont]=rowIndex;
+        }
+	vub[rowIndex]=iCont;
+	numberVub++;
+      } else if (numberBinary>1) {
+	// could be knapsack
+	vub[rowIndex]=-1;
+      } else {
+	// no point looking at this row
+	vub[rowIndex]=-2;
+      }
+    } else {
+      if (!possible||numberBinary+numberContinuous>maxInKnapsack_)
+	vub[rowIndex]=-2;      // no point looking at this row
+    }
+  }
+  // Main loop
+  int numCheck = 0;
+  int* toCheck = 0;
+  if (!rowsToCheck_) {
+     toCheck = new int[nRows];
+     CoinIotaN(toCheck, nRows, 0);
+     numCheck = nRows;
+  } else {
+     numCheck = numRowsToCheck_;
+     toCheck = rowsToCheck_;
+  }
+  // Long row
+  int longRow =20; //15;
+  int longRow2 =20; //15;
+  if (!info.inTree) {
+    longRow=25;
+    //longRow2=20;
+    if (!info.pass)
+      longRow=30;
+  }
+
+  // Set up number of tries for each row
+  int ntry;
+  if (numberVub) 
+    ntry=4;
+  else
+    ntry=2;
+  //ntry=2; // switch off
+  for (int ii=0; ii < numCheck; ++ii){
+     rowIndex = toCheck[ii];
+     if (rowIndex < 0 || rowIndex >= nRows)
+	continue;
+     if (vub[rowIndex]==-2)
+       continue;
+     whichRow_=ii;
+
+#ifdef PRINT_DEBUG
+    std::cout << "CGL: Processing row " << rowIndex << std::endl;
+#endif
+    
+    // Get a tight row 
+    // (want to be able to 
+    //  experiment by turning this on and off)
+    //
+    // const double * pi=si.rowprice(); 
+    // if (fabs(pi[row]) < epsilon_){
+    //  continue;
+    // }
+    
+    
+    //////////////////////////////////////////////////////
+    // Derive a "canonical"  knapsack                  //
+    // inequality (in binary variables)                 //
+    // from the model row in mixed integer variables    //
+    //////////////////////////////////////////////////////
+#ifdef CGL_DEBUG
+    assert(!krow.getNumElements());
+#endif
+    double effectiveRhs[4];
+    double rhs[4];
+    double sign[]={0.0,0.0,-1.0,1.0};
+    bool rowType[] = {false,true,false,true};
+    effectiveRhs[0] = effectiveLower[rowIndex]; 
+    rhs[0]=rowLower[rowIndex];
+    effectiveRhs[2] = effectiveRhs[0];
+    rhs[2]= effectiveRhs[0];
+    effectiveRhs[1] = effectiveUpper[rowIndex]; 
+    rhs[1]=rowUpper[rowIndex];
+    effectiveRhs[3] = effectiveRhs[1];
+    rhs[3]= effectiveRhs[1];
+    int itry;
+#ifdef CGL_DEBUG
+    int kcuts[4];
+    memset(kcuts,0,4*sizeof(int));
+#endif
+    for (itry=0;itry<ntry;itry++) {
+#ifdef CGL_DEBUG
+      int nlast=cs.sizeRowCuts();
+#endif
+      // see if to skip
+      if (fabs(effectiveRhs[itry])>1.0e20)
+	continue;
+      int length = rowLength[rowIndex];
+      memcpy(thisColumnIndex,column+rowStart[rowIndex],length*sizeof(int));
+      memcpy(thisElement,elementByRow+rowStart[rowIndex],
+	     length*sizeof(double));
+      b=rhs[itry];
+      if (itry>1) {
+	// see if we would be better off relaxing
+	int i;
+	// mark columns
+	int length2=length; // for new length
+	int numberReplaced=0;
+	for (i=0;i<length;i++) {
+	  int iColumn = thisColumnIndex[i];
+	  back[thisColumnIndex[i]]=i;
+	  if (vubRow[iColumn]==-10) {
+	    // fixed - take out
+	    thisElement[i]=0.0;
+	  }
+	}
+        double dSign = sign[itry];
+	for (i=0;i<length;i++) {
+	  int iColumn = thisColumnIndex[i];
+          int iRow=-1;
+          double vubCoefficient=0.0;
+          double thisCoefficient=thisElement[i];
+          int replace = 0;
+          if (vubRow[iColumn]>=0) {
+            iRow = vubRow[iColumn];
+            if (vub[iRow]==iColumn&&iRow!=rowIndex) {
+              vubCoefficient = vubValue[iRow];
+              // break it out - may be able to do better
+              if (dSign*thisCoefficient>0.0) {
+                // we want valid lower bound on continuous
+                if (effectiveLower[iRow]>-1.0e20&&vubCoefficient>0.0) 
+                  replace=-1;
+                else if (effectiveUpper[iRow]<1.0e20&&vubCoefficient<0.0) 
+                  replace=1;
+                // q assert (replace!=-1);
+                // q assert (replace!=1);
+              } else {
+                // we want valid upper bound on continuous
+                if (effectiveLower[iRow]>-1.0e20&&vubCoefficient<0.0) 
+                  replace=-1;
+                else if (effectiveUpper[iRow]<1.0e20&&vubCoefficient>0.0) 
+                  replace=1;
+                //assert (replace!=-1);
+              }
+            }
+          }
+          if (vlbRow[iColumn]>=0) {
+            iRow = vlbRow[iColumn];
+            if (vub[iRow]==iColumn&&iRow!=rowIndex) {
+              vubCoefficient = vlbValue[iRow];
+              // break it out - may be able to do better
+              if (dSign*thisCoefficient>0.0) {
+                // we want valid lower bound on continuous
+                if (effectiveLower[iRow]>-1.0e20&&vubCoefficient>0.0) 
+                  replace=-1;
+                else if (effectiveUpper[iRow]<1.0e20&&vubCoefficient<0.0) 
+                  replace=1;
+                //assert (replace!=1);
+              } else {
+                // we want valid upper bound on continuous
+                if (effectiveLower[iRow]>-1.0e20&&vubCoefficient<0.0) 
+                  replace=-1;
+                else if (effectiveUpper[iRow]<1.0e20&&vubCoefficient>0.0) 
+                  replace=1;
+                //q assert (replace!=-1);
+                //assert (replace!=1);
+              }
+            }
+          }
+          if (replace) {
+            double useRhs=0.0;
+            numberReplaced++;
+            if (replace<0)
+              useRhs = effectiveLower[iRow];
+            else
+              useRhs = effectiveUpper[iRow];
+            // now replace (just using vubRow==-2)
+            // delete continuous
+            thisElement[i]=0.0;
+            double scale = thisCoefficient/vubCoefficient;
+            // modify rhs
+            b -= scale*useRhs;
+            int start = rowStart[iRow];
+            int end = start+rowLength[iRow];
+            int j;
+            for (j=start;j<end;j++) {
+              int iColumn = column[j];
+              if (vubRow[iColumn]==-2) {
+                double change = scale*elementByRow[j];
+                int iBack = back[iColumn];
+                if (iBack<0) {
+                  // element does not exist
+                  back[iColumn]=length2;
+                  thisElement[length2]=-change;
+                  thisColumnIndex[length2++]=iColumn;
+                } else {
+                  // element does exist
+                  thisElement[iBack] -= change;
+                }
+              }
+            }
+	  }
+	}
+	if (numberReplaced) {
+	  length=0;
+	  for (i=0;i<length2;i++) {
+	    int iColumn = thisColumnIndex[i];
+	    back[iColumn]=-1; // un mark
+	    if (thisElement[i]) {
+	      thisElement[length]=thisElement[i];
+	      thisColumnIndex[length++]=iColumn;
+	    }
+	  }
+	  if (length>maxInKnapsack_)
+	    continue; // too long
+	} else {
+	  for (i=0;i<length;i++) {
+	    int iColumn = thisColumnIndex[i];
+	    back[iColumn]=-1; // un mark
+	  }
+	  continue; // no good
+	}
+      }
+      if (!deriveAKnapsack(si, cs, krow, rowType[itry], b, complement, 
+			   xstar, rowIndex, 
+			   length,thisColumnIndex,thisElement)) {
+	
+	// Reset local data and continue to the next iteration 
+	// of the rowIndex-loop
+	for(k=0; k<krow.getNumElements(); k++) {
+	  if (complement[krow.getIndices()[k]]){
+	    xstar[krow.getIndices()[k]]= 1.0-xstar[krow.getIndices()[k]];
+	    complement[krow.getIndices()[k]]=0;        
+	  }
+	}
+	krow.setVector(0,NULL,NULL);
+	continue;
+      }
+#ifdef PRINT_DEBUG
+      {
+	// Get the sense of the row
+	int i;
+	printf("rhs sense %c rhs %g\n",si.getRowSense()[rowIndex],
+	       si.getRightHandSide()[rowIndex]);
+	const int * indices = si.getMatrixByRow()->getVector(rowIndex).getIndices();
+	const double * elements = si.getMatrixByRow()->getVector(rowIndex).getElements();
+	// for every variable in the constraint
+	for (i=0; i<si.getMatrixByRow()->getVector(rowIndex).getNumElements(); i++){
+	  printf("%d (s=%g) %g, ",indices[i],colsol[indices[i]],elements[i]);
+	}
+	printf("\n");
+      }
+#endif
+      
+      //////////////////////////////////////////////////////
+      // Look for a series of                             //
+      // different types of minimal covers.               //
+      // If a minimal cover is found,                     //
+      // lift the associated minimal cover inequality,    //
+      // uncomplement the vars                            //
+      // and add it to the cut set.                       //
+      // After the last type of cover is tried,           //
+      // restore xstar values                             //
+      //////////////////////////////////////////////////////
+      
+      //////////////////////////////////////////////////////
+      // Try to generate a violated                       //
+      // minimal cover greedily from fractional vars      //
+      //////////////////////////////////////////////////////
+      
+      CoinPackedVector cover, remainder;  
+      
+      
+      if (findGreedyCover(rowIndex, krow, b, xstar, cover, remainder) == 1){
+	
+	// Lift cover inequality and add to cut set 
+	if (!liftAndUncomplementAndAdd(rowUpper[rowIndex], krow, b,
+				       complement, rowIndex, cover, 
+				       remainder, cs)) {
+	  // Reset local data and continue to the next iteration 
+	  // of the rowIndex-loop
+	  // I am not sure this is needed but I am just being careful
+	  for(k=0; k<krow.getNumElements(); k++) {
+	    if (complement[krow.getIndices()[k]]){
+	      xstar[krow.getIndices()[k]]= 1.0-xstar[krow.getIndices()[k]];
+	      complement[krow.getIndices()[k]]=0;        
+	    }
+	  }
+	  krow.setVector(0,NULL,NULL);
+	  continue;
+	}  
+      }
+      
+      
+      //////////////////////////////////////////////////////
+      // Try to generate a violated                       //
+      // minimal cover using pseudo John and Ellis logic  //
+      //////////////////////////////////////////////////////
+      
+      // Reset the cover and remainder
+      cover.setVector(0,NULL,NULL);
+      remainder.setVector(0,NULL,NULL);
+      
+      if (findPseudoJohnAndEllisCover(rowIndex, krow, b,
+				      xstar, cover, remainder) == 1){
+	int n = krow.getNumElements();
+	bool possible = (n<=longRow);
+	if (possible) {
+	  // Calculate the sum of the knapsack coefficients of the cover variables 
+	  double sum = cover.sum();
+
+	  // Define lambda to be the "cover excess". 
+	  // By definition, lambda > 0. If this is not the case, something's screwy. Exit gracefully.
+	  double lambda = sum-b;
+	  if (lambda < epsilon_) {
+#ifdef CGL_DEBUG
+	    if (lambda < -epsilon_) {
+	      printf("lambda < epsilon....aborting. \n");
+	      std::cout << "lambda " << lambda << " epsilon " << epsilon_ << std::endl;
+	      abort();
+	    } else {
+#endif
+	      possible=false;
+#ifdef CGL_DEBUG
+	    }
+#endif
+	  }
+	}
+	if (possible) {
+	  CoinPackedVector atOnes;
+	  CoinPackedVector fracCover; // different than cover
+	  int nInCover = cover.getNumElements();
+	  const int * ind = cover.getIndices();
+	  const double * elsIn = cover.getElements();
+	  for (int i=0;i<nInCover;i++) {
+	    int iColumn = ind[i];
+	    double value = elsIn[i];
+	    if (xstar[iColumn]<1.0)
+	      fracCover.insert(iColumn,value);
+	    else
+	      atOnes.insert(iColumn,value);
+	  }
+          liftUpDownAndUncomplementAndAdd(nCols, xstar, complement, rowIndex,
+                                          n, b, fracCover,
+                                          atOnes, remainder, cs);
+#if 0
+	} else {
+	  // (Sequence Independent) Lift cover inequality and add to cut set 
+	  if (!liftAndUncomplementAndAdd(rowUpper[rowIndex], krow, b,
+				       complement, rowIndex, cover, 
+				       remainder, cs)) {
+	    // Reset local data and continue to the next iteration 
+	    // of the rowIndex-loop
+	    // I am not sure this is needed but I am just being careful
+	    for(k=0; k<krow.getNumElements(); k++) {
+	      if (complement[krow.getIndices()[k]]){
+		xstar[krow.getIndices()[k]]= 1.0-xstar[krow.getIndices()[k]];
+		complement[krow.getIndices()[k]]=0;        
+	      }
+	    }
+	    krow.setVector(0,NULL,NULL);
+	    continue;
+	  }
+#endif  
+	}
+	
+	// Skip experiment for now...
+#if 0
+	// experimenting here...
+	// (Sequence Dependent) Lift cover inequality and add to cut set
+	seqLiftAndUncomplementAndAdd(nCols, xstar, complement, rowIndex,
+				     krow.getNumElements(), b, cover, remainder,
+				     cs);
+#endif 
+      }  
+      
+      
+      
+      //////////////////////////////////////////////////////
+      // Try to generate cuts using covers of unsat       //
+      // vars on reduced krows with John and Ellis logic  //
+      //////////////////////////////////////////////////////
+      CoinPackedVector atOnes;
+      CoinPackedVector fracCover; // different than cover
+      
+      // reset the remainder
+      remainder.setVector(0,NULL,NULL);
+      
+      if (expensiveCuts_||krow.getNumElements()<=longRow) {
+        if (findJohnAndEllisCover(rowIndex, krow, b,
+                                  xstar, fracCover, atOnes, remainder) == 1){
+          
+          // experimenting here...
+          // Sequence Dependent Lifting up on remainders and lifting down on the
+          // atOnes 
+          liftUpDownAndUncomplementAndAdd(nCols, xstar, complement, rowIndex,
+                                          krow.getNumElements(), b, fracCover,
+                                          atOnes, remainder, cs);
+        }
+      }
+      
+      //////////////////////////////////////////////////////
+      // Try to generate a violated                       //
+      // minimal cover by considering the                 //
+      // most violated cover problem                      //
+      //////////////////////////////////////////////////////
+      
+      
+      // reset cover and remainder
+      cover.setVector(0,NULL,NULL);
+      remainder.setVector(0,NULL,NULL);
+      
+      // if the size of the krow is "small", 
+      //    use an exact algorithm to find the most violated (minimal) cover, 
+      // else, 
+      //    use an lp-relaxation to find the most violated (minimal) cover.
+      if(krow.getNumElements()<=longRow2){
+	if (findExactMostViolatedMinCover(nCols, rowIndex, krow, b,
+					  xstar, cover, remainder) == 1){
+	  
+	  // Lift cover inequality and add to cut set 
+	  if (!liftAndUncomplementAndAdd(rowUpper[rowIndex], krow, b,
+					 complement, rowIndex, cover, remainder,
+                                         cs)) {
+	    // Reset local data and continue to the next iteration 
+	    // of the rowIndex-loop
+	    // I am not sure this is needed but I am just being careful
+	    for(k=0; k<krow.getNumElements(); k++) {
+	      if (complement[krow.getIndices()[k]]){
+		xstar[krow.getIndices()[k]]= 1.0-xstar[krow.getIndices()[k]];
+		complement[krow.getIndices()[k]]=0;        
+	      }
+	    }
+	    krow.setVector(0,NULL,NULL);
+	    continue;
+	  }  
+	}
+      } 
+      else {
+	if (findLPMostViolatedMinCover(nCols, rowIndex, krow, b,
+				       xstar, cover, remainder) == 1){
+	  
+	  // Lift cover inequality and add to cut set 
+	  if (!liftAndUncomplementAndAdd(rowUpper[rowIndex], krow, b,
+					 complement, rowIndex, cover, remainder,
+                                         cs)) {
+	    // Reset local data and continue to the next iteration 
+	    // of the rowIndex-loop
+	    // I am not sure this is needed but I am just being careful
+	    for(k=0; k<krow.getNumElements(); k++) {
+	      if (complement[krow.getIndices()[k]]){
+		xstar[krow.getIndices()[k]]= 1.0-xstar[krow.getIndices()[k]];
+		complement[krow.getIndices()[k]]=0;        
+	      }
+	    }
+	    krow.setVector(0,NULL,NULL);
+	    continue;
+	  }  
+	}
+      } 
+      
+      
+      
+      // Reset xstar and complement to their initialized values for the next
+      // go-around 
+      int k;
+      if (fabs(b-rowUpper[rowIndex]) > epsilon_) {
+	for(k=0; k<krow.getNumElements(); k++) {
+	  if (complement[krow.getIndices()[k]]){
+	    xstar[krow.getIndices()[k]]= 1.0-xstar[krow.getIndices()[k]];
+	    complement[krow.getIndices()[k]]=0;
+	  }
+	}
+      }
+      krow.setVector(0,NULL,NULL);
+#ifdef CGL_DEBUG
+      int nnow = cs.sizeRowCuts();
+      if (nnow>nlast) {
+	const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+	if (debugger&&debugger->onOptimalPath(si)) {
+	  // check cuts okay
+	  int k;
+	  for (k=nlast;k<nnow;k++) {
+	    OsiRowCut rc=cs.rowCut(k);
+	    if(debugger->invalidCut(rc)) {
+	      printf("itry %d, rhs %g, length %d\n",itry,rhs[itry],length);
+	      int i;
+	      for (i=0;i<length;i++) {
+		int iColumn = thisColumnIndex[i];
+		printf("column %d, coefficient %g, value %g, bounds %g %g\n",iColumn,
+		       thisElement[i],colsol[iColumn],colLower[iColumn],
+		       colUpper[iColumn]);
+	      }
+	      if (itry>1) {
+		int length = rowLength[rowIndex];
+		memcpy(thisColumnIndex,column+rowStart[rowIndex],
+		       length*sizeof(int));
+		memcpy(thisElement,elementByRow+rowStart[rowIndex],
+		       length*sizeof(double));
+		printf("Original row had rhs %g and length %d\n",
+		       (itry==2 ? rowLower[rowIndex] :rowUpper[rowIndex]),
+		       length);
+		for (i=0;i<length;i++) {
+		  int iColumn = thisColumnIndex[i];
+		  printf("column %d, coefficient %g, value %g, bounds %g %g\n",iColumn,
+			 thisElement[i],colsol[iColumn],colLower[iColumn],
+			 colUpper[iColumn]);
+		}
+	      }
+	      assert(!debugger->invalidCut(rc));
+	    }
+	  }
+	}
+	if (itry>1&&nnow-nlast>kcuts[itry-2]) {
+	  printf("itry %d gave %d cuts as against %d for itry %d\n",
+		 itry,nnow-nlast,kcuts[itry-2],itry-2);
+	}
+	kcuts[itry]=nnow-nlast;
+	nlast=nnow;
+      }
+#endif
+    }
+  }
+  if (!info.inTree&&((info.options&4)==4||((info.options&8)&&!info.pass))) {
+    int numberRowCutsAfter = cs.sizeRowCuts();
+    for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++)
+      cs.rowCutPtr(i)->setGloballyValid();
+  }
+  // Clean up: free allocated memory
+  if (toCheck != rowsToCheck_)
+     delete[] toCheck;
+  delete[] xstar;
+  delete[] complement;
+#ifdef GUBCOVER
+  delete [] elements_;
+#endif
+  delete [] thisColumnIndex;
+  delete [] thisElement;
+  delete [] back;
+  delete [] vub;
+  delete [] vubRow;
+  delete [] vubValue;
+  delete [] vlbRow;
+  delete [] vlbValue;
+  delete [] effectiveLower;
+  delete [] effectiveUpper;
+}
+
+void
+CglKnapsackCover::setTestedRowIndices(int num, const int* ind)
+{
+   if (rowsToCheck_)
+      delete[] rowsToCheck_;
+   numRowsToCheck_ = num;
+   if (num > 0) {
+      rowsToCheck_ = new int[num];
+      CoinCopyN(ind, num, rowsToCheck_);
+   }
+}
+
+//------------------------------------------------------------- 
+// Lift and uncomplement cut. Add cut to the cutset
+//-------------------------------------------------------------------
+int 
+CglKnapsackCover::liftAndUncomplementAndAdd(
+					    double /*rowub*/,
+         CoinPackedVector & krow,
+         double & b,
+         int * complement,
+         int /*row*/,
+         CoinPackedVector & cover,
+         CoinPackedVector & remainder,
+         OsiCuts & cs )
+{
+  CoinPackedVector cut;
+  double cutRhs = cover.getNumElements() - 1.0;
+  int goodCut=1;
+  
+  if (remainder.getNumElements() > 0){
+    // Construct lifted cover cut 
+    if (!liftCoverCut( 
+		      b, krow.getNumElements(), 
+		      cover, remainder,
+		      cut )) 
+      goodCut= 0; // no cut
+  }
+  // The cover consists of every variable in the knapsack.
+  // There is nothing to lift, so just add cut            
+  else {
+    cut.reserve(cover.getNumElements());
+    cut.setConstant(cover.getNumElements(),cover.getIndices(),1.0);
+  }
+  
+  if (goodCut) {
+    // Uncomplement the complemented variables in the cut
+    int k;
+    //if (fabs(b-rowub)> epsilon_) {
+    double * elements = cut.getElements();
+    int * indices = cut.getIndices();
+    for (k=0; k<cut.getNumElements(); k++){
+      if (complement[indices[k]]) {
+        // Negate the k'th element in packedVector cut
+        // and correspondingly adjust the rhs
+        elements[k] *= -1;
+        cutRhs += elements[k];
+      }
+    }
+    //}
+    // Create row cut. Effectiveness defaults to 0.
+    OsiRowCut rc;
+    rc.setRow(cut);
+#ifdef CGL_DEBUG
+    {
+      double * elements = cut.getElements();
+      int * indices = cut.getIndices();
+      int n=cut.getNumElements();
+      for (k=0; k<n; k++){
+	assert(indices[k]>=0);
+	assert(elements[k]);
+        assert (fabs(elements[k])>1.0e-12);
+      }
+    }
+#endif
+    rc.setLb(-COIN_DBL_MAX);
+    rc.setUb(cutRhs);
+    //  rc.setEffectiveness(0);
+    // Todo: put in a more useful measure such as  the violation. 
+    
+    // Add row cut to the cut set  
+#ifdef PRINT_DEBUG
+    {
+      int k;
+      printf("cutrhs %g %d elements\n",cutRhs,cut.getNumElements());
+      double * elements = cut.getElements();
+      int * indices = cut.getIndices();
+      for (k=0; k<cut.getNumElements(); k++){
+	printf("%d %g\n",indices[k],elements[k]);
+      }
+    }
+#endif
+    cs.insert(rc);
+    
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+//-------------------------------------------------------------------
+// deriveAKnapsack - returns 1 if the method is able to 
+//                  derive a canonical knapsack inequality
+//                  in binary variables of the form ax<=b 
+//                  from the rowIndex-th row of the constraint matrix.
+//                  returns 0, otherwise.
+//  Precondition: complement must be 0'd out!!!
+//-------------------------------------------------------------------
+int 
+CglKnapsackCover::deriveAKnapsack(
+       const OsiSolverInterface & si, 
+       OsiCuts & cs,
+       CoinPackedVector & krow, 
+       bool treatAsLRow,
+       double & b,
+       int *  complement,
+       double *  xstar,
+       int /*rowIndex*/,
+       int numberElements,
+       const int * index,
+       const double * element)
+{
+
+  // Fix to https://projects.coin-or.org/Cbc/ticket/30
+  {
+    // On investiagtion looks as if it can happen without being a bug
+    if (numberElements==0) return 0;
+  }
+
+  int i;
+
+  krow.clear();
+
+  // if the matrixRow represent a ge inequality, then
+  //     leMatrixRow == -matrixRow  // otherwise
+  //     leMatrixRow == matrixRow.
+
+  CoinPackedVector leMatrixRow(numberElements,index,element); 
+
+  double maxKrowElement = -COIN_DBL_MAX;
+  double minKrowElement = COIN_DBL_MAX;
+  
+
+  if (treatAsLRow) {
+    // treat as if L row
+  } else {
+    // treat as if G row
+    b=-b;
+    std::transform(leMatrixRow.getElements(),
+		   leMatrixRow.getElements() + leMatrixRow.getNumElements(),
+		   leMatrixRow.getElements(),
+		   std::negate<double>());
+  }
+  
+  // nBinUnsat is a counter for the number of unsatisfied
+  // (i.e. fractional) binary vars  
+  int nBinUnsat =0;
+  const double * colupper = si.getColUpper();
+  const double * collower = si.getColLower();
+  
+  // At this point, leMatrixRow and b represent a le inequality in general
+  // variables. 
+  // To derive a canonical knapsack inequality in free binary variable,
+  // process out the continuous & non-binary integer & fixed binary variables.
+  // If the non-free-binary variables can be appropriately bounded, 
+  // net them out of the constraint, otherwise abandon this row and return 0.
+
+  const int * indices = leMatrixRow.getIndices();
+  const double * elements = leMatrixRow.getElements();
+  // for every variable in the constraint
+  for (i=0; i<leMatrixRow.getNumElements(); i++){
+    // if the variable is not a free binary var
+    if ( !si.isFreeBinary(indices[i]) ) {
+      // and the coefficient is strictly negative
+      if(elements[i]<-epsilon_){
+	// and the variable has a finite upper bound
+        if (colupper[indices[i]] < si.getInfinity()){
+	  // then replace the variable with its upper bound.
+          b=b-elements[i]*colupper[indices[i]];
+        } 
+        else {
+          return 0;
+        }
+      }
+      // if the coefficient is strictly positive
+      else if(elements[i]>epsilon_){
+	// and the variable has a finite lower bound
+        if (collower[indices[i]] > -si.getInfinity()){
+	  // then replace the variable with its lower bound.
+          b=b-elements[i]*collower[indices[i]];
+        }
+        else {
+          return 0;
+        }
+      }
+      // note: if the coefficient is zero, the variable is not included in the 
+      //       knapsack inequality.
+    }
+    // else the variable is a free binary var and is included in the knapsack
+    // inequality. 
+    // note: the variable is included regardless of its solution value to the
+    // lp relaxation. 
+    else{
+      krow.insert(indices[i], elements[i]);
+
+      // if the binary variable is unsatified (i.e. has fractional value),
+      // increment the counter. 
+      if(xstar[indices[i]] > epsilon_ && xstar[indices[i]] < onetol_)
+        nBinUnsat++;
+
+      // keep track of the largest and smallest elements in the knapsack
+      // (the idea is if there is not a lot of variation in the knapsack
+      // coefficients, it is unlikely we will find a violated minimal
+      // cover from this knapsack so don't even bother trying) 
+      if (fabs(elements[i]) > maxKrowElement) 
+        maxKrowElement = fabs(elements[i]);
+      if (fabs(elements[i]) < minKrowElement) 
+        minKrowElement = fabs(elements[i]);
+    }
+  }
+  
+  // If there's little variation in the knapsack coefficients, return 0.
+  // If there are no unsatisfied binary variables, return.
+  // If there's only one binary, return.  
+  // ToDo: but why return if 2 binary? ...there was some assumption in the
+  // findVioMinCover..(?)   
+  // Anyway probing will probably find something
+  if (krow.getNumElements() < 3 ||
+      nBinUnsat == 0 ||
+      maxKrowElement-minKrowElement < 1.0e-3*maxKrowElement ) {
+    return 0;
+  }
+
+  // However if we do decide to do when count is two - look carefully
+  if (krow.getNumElements()==2) {
+    const int * indices = krow.getIndices();
+    double * elements = krow.getElements();
+    double sum=0.0;
+    for(i=0; i<2; i++){
+      int iColumn = indices[i];
+      sum += elements[i]*xstar[iColumn];
+    }
+    if (sum<b-1.0e-4) {
+      return 0;
+    } else {
+
+#ifdef PRINT_DEBUG
+      printf("*** Doubleton Row is ");
+      for(i=0; i<2; i++){
+	int iColumn = indices[i];
+	sum += elements[i]*xstar[iColumn];
+	printf("%d (coeff = %g, value = %g} ",indices[i],
+	       elements[i],xstar[iColumn]);
+      }
+      printf("<= %g - go for it\n",b);
+#endif
+
+    }
+  }
+
+
+  // At this point krow and b represent a le inequality in binary variables.  
+  // To obtain an le inequality with all positive coefficients, complement
+  // any variable with a negative coefficient by changing the sign of 
+  // the coefficient, adjusting the rhs, and adjusting xstar, the column
+  // solution vector.
+  {
+     const int s = krow.getNumElements();
+     const int * indices = krow.getIndices();
+     double * elements = krow.getElements();
+     for(i=0; i<s; i++){
+	 if (elements[i] < -epsilon_) {
+	   complement[indices[i]]= 1;
+	   elements[i] *= -1;
+	   b+=elements[i]; 
+	   xstar[indices[i]]=1.0-xstar[indices[i]];
+	}
+     }
+  }
+
+  // Quick feasibility check.
+  // If the problem is infeasible, add an infeasible col cut to cut set
+  // e.g. one that has lb > ub.
+  // TODO: test this scenario in BCP
+  if (b < 0 ){ 
+    OsiColCut cc;
+    int index = krow.getIndices()[0]; 
+    const double fakeLb = colupper[index] + 1.0;;  // yes, colupper.
+#ifdef CGL_DEBUG
+    const double fakeUb = collower[index];
+    assert( fakeUb < fakeLb );
+#endif
+    cc.setLbs( 1, &index, &fakeLb);
+    cc.setUbs( 1, &index, &fakeLb);
+    cc.setEffectiveness(COIN_DBL_MAX);
+    cs.insert(cc);
+#ifdef PRINT_DEBUG
+    printf("Cgl: Problem is infeasible\n");
+#endif
+  }
+  
+  // At this point, krow and b represent a le inequality with postive
+  // coefficients. 
+  // If any coefficient a_j > b, then x_j = 0, return 0
+  // If any complemented var has coef a_j > b, then x_j = 1, return 0 
+  int fixed = 0;
+  CoinPackedVector fixedBnd;  
+  for(i=0; i<krow.getNumElements(); i++){
+    if (krow.getElements()[i]> b){
+      fixedBnd.insert(krow.getIndices()[i],complement[krow.getIndices()[i]]);
+#ifdef PRINT_DEBUG   
+      printf("Variable %i being fixed to %i due to row %i.\n",
+	     krow.getIndices()[i],complement[krow.getIndices()[i]],rowIndex); 
+#endif
+      fixed = 1;      
+    }
+  }
+
+  // After all possible variables are fixed by adding a column cut with 
+  // equivalent lower and upper bounds, return
+  if (fixed) {
+    OsiColCut cc;
+    cc.setLbs(fixedBnd);
+    cc.setUbs(fixedBnd);
+    cc.setEffectiveness(COIN_DBL_MAX);
+    return 0; 
+  }  
+
+  return 1;
+}
+
+
+//-------------------------------------------------------------------
+// deriveAKnapsack - returns 1 if the method is able to 
+//                  derive a cannonical knapsack inequality
+//                  in binary variables of the form ax<=b 
+//                  from the rowIndex-th row of the constraint matrix.
+//                  returns 0, otherwise.
+//  Precondition: complement must be 0'd out!!!
+//-------------------------------------------------------------------
+int 
+CglKnapsackCover::deriveAKnapsack(
+       const OsiSolverInterface & si, 
+       OsiCuts & cs,
+       CoinPackedVector & krow, 
+       double & b,
+       int *  complement,
+       double *  xstar,
+       int rowIndex,
+       const CoinPackedVectorBase & matrixRow )
+{
+  // Get the sense of the row
+  const char  rowsense = si.getRowSense()[rowIndex];
+  
+  // Skip equality and unbounded rows 
+  if  (rowsense=='E' || rowsense=='N') {
+    return 0; 
+  }
+  
+  bool treatAsLRow =  (rowsense=='L');
+  const int * indices = matrixRow.getIndices();
+  const double * elements = matrixRow.getElements();
+  int numberElements = matrixRow.getNumElements();
+  return deriveAKnapsack( si, cs, krow, treatAsLRow, b, complement,
+			  xstar, rowIndex, numberElements, indices,
+			  elements);
+}
+
+//--------------------------------------------------
+// Find a violated minimal cover from 
+// a canonical form knapsack inequality by
+// solving the lp relaxation of the 
+// -most- violated cover problem.
+// Postprocess to ensure minimality.
+// -----------------------------------------
+int 
+CglKnapsackCover::findLPMostViolatedMinCover(
+      int nCols,
+      int /*row*/,
+      CoinPackedVector & krow,
+      double & b,
+      double * xstar, 
+      CoinPackedVector & cover,
+      CoinPackedVector & remainder)
+{
+  
+  // Assumes krow and b describe a knapsack inequality in canonical form
+
+  // Given a knapsack inequality sum a_jx_j <= b, and optimal lp solution
+  // xstart, a violated minimal cover inequality exists if the following 0-1
+  // programming problem has an optimal objective function value (oofv) < 1
+  //     oofv = min sum (1-xstar_j)z_j
+  //            s.t. sum a_jz_j > b
+  //            z binary
+  
+  // The vector z is an incidence vector, defining the cover R with the 
+  // associated cover inequality:
+  //    (sum j in R) x_j <= |R|-1
+  
+  // This problem is itself a (min version of the) knapsack problem
+  // but with a unsightly strict inequalty.
+  
+  // To transform transform it into a max version, 
+  // complement the z's, z_j=1-y_j.
+  // To compensate for the strict inequality, subtract epsilon from the rhs.
+  
+  //     oofv = (sum (1-xstar_j))-  max sum (1-xstar)y_j
+  //                        s.t. sum a_jy_j <= (sum over j)a_j - b (- EPSILON)
+  //                             y binary
+  
+  // If oofv < 1, then a violated min cover inequality has
+  // incidence vector z with elements z_j=1-y_j and rhs= num of nonzero's in 
+  // z, i.e. the number of 0's in y.
+
+  // If the size of the knapsack is "small", we solve the problem exactly. 
+  // If the size of the knapsack is large, we solve the (simpler) lp relaxation
+  // of the  knapsack problem and postprocess to ensure the construction of a 
+  // minimimal cover.
+  
+  // We also assume that testing/probing/fixing based on the knapsack structure
+  // is done elsewhere. Only convenient-to-do sanity checks are done here.
+  // (We do not assume that data is integer.)
+
+  double elementSum = krow.sum();
+
+  // Redundant/useless adjusted rows should have been trapped in the 
+  // transformation to the canonical form of knapsack inequality
+  if (elementSum < b + epsilon_) {
+    return -1; 
+  }
+  
+  // Order krow in nonincreasing order of coefObj_j/a_j.  
+  // (1-xstar_1)/a_1 >= (1-xstar_2)/a_2 >= ... >= (1-xstar_n)/a_n   
+  // by defining this full-storage array "ratio" to be the external sort key.
+  double * ratio= new double[nCols];
+  memset(ratio, 0, (nCols*sizeof(double)));
+
+  int i;
+  for (i=0; i<krow.getNumElements(); i++){
+    if (fabs(krow.getElements()[i])> epsilon_ ){
+      ratio[krow.getIndices()[i]]=
+	 (1.0-xstar[krow.getIndices()[i]]) / (krow.getElements()[i]);
+    }
+    else {
+      ratio[krow.getIndices()[i]] = 0.0;
+    }
+  }
+
+  // ToDo: would be nice to have sortkey NOT be full-storage vector
+  CoinDecrSolutionOrdered dso(ratio);
+  krow.sort(dso);   
+
+  // Find the "critical" element index "r" in the knapsack lp solution
+  int r = 0;
+  double sum = krow.getElements()[0];
+  while ( sum <= (elementSum - b - epsilon_ ) ){
+    r++;
+    sum += krow.getElements()[r];
+  }    
+  
+  // Note: It is possible the r=0, and you get a violated minimal cover 
+  // if (r=0), then you've got a var with a really large coeff. compared
+  //   to the rest of the row.
+  // r=0 says trivially that the 
+  //   sum of ALL the binary vars in the row <= (cardinality of all the set -1)
+  // Note: The cover may not be minimal if there are alternate optimals to the 
+  // maximization problem, so the cover must be post-processed to ensure 
+  // minimality.
+  
+  // "r" is the critical element 
+  // The lp relaxation column solution is:
+  // y_j = 1 for  j=0,...,(r-1)
+  // y_r = (elementSum - b - sum + krow.element()[r])/krow.element()[r] 
+  // y_j = 0 for j=r+1,...,krow.getNumElements() 
+  
+  // The number of nonzeros in the lp column solution is r+1 
+  
+  // if oofv to the lp knap >= 1, then no violated min cover is possible 
+  int nCover;
+
+  double lpoofv=0.0;
+  for (i=r+1; i<krow.getNumElements(); i++){
+    lpoofv += (1-xstar[krow.getIndices()[i]]);
+  }
+  double ipofv = lpoofv + (1-xstar[krow.getIndices()[r]]);
+
+  // Couldn't find an lp violated min cover inequality 
+  if (ipofv > 1.0 - epsilon_){    
+    delete [] ratio;
+    return -1;
+  }
+  else {
+    // Partition knapsack into cover and noncover (i.e. remainder)
+    // pieces
+    nCover = krow.getNumElements() - r;
+    double coverSum =0.0;
+    cover.reserve(nCover);
+    remainder.reserve(r);
+    
+    for (i=r; i<krow.getNumElements(); i++){
+      cover.insert(krow.getIndices()[i],krow.getElements()[i]);
+      coverSum += krow.getElements()[i];
+    }
+    for (i=0; i<r; i++){
+      remainder.insert(krow.getIndices()[i],krow.getElements()[i]);
+    }
+    
+    if (coverSum <= b+1.0e-8*(1.0+fabs(b))){
+#ifdef PRINT_DEBUG
+      if (coverSum <= b) {
+	printf("The identified cover is NOT a cover\n");
+	abort();
+      }
+#endif
+      delete [] ratio;
+      return -1;
+    }
+    
+    // Sort cover in terms of knapsack row coefficients   
+    cover.sortDecrElement();
+    
+    
+    // We have a violated cover inequality.
+    // Construct a -minimal- violated cover
+    // by testing and potentially tossing smallest
+    // elements 
+    double oneLessCoverSum = coverSum - cover.getElements()[nCover-1];
+    while (oneLessCoverSum > b+1.0e-12){
+      // move the excess cover member into the set of remainders
+      remainder.insert(cover.getIndices()[nCover-1],
+		       cover.getElements()[nCover-1]);
+      cover.truncate(nCover-1);
+      nCover--;
+      oneLessCoverSum -= cover.getElements()[nCover-1];
+    }
+
+    if (nCover<2){
+#ifdef PRINT_DEBUG
+      printf("nCover < 2...aborting\n");
+      abort();
+#endif
+      delete [] ratio;
+      return -1;
+    }
+    
+#ifdef PRINT_DEBUG   /* debug */
+    printf("\
+Lp relax of most violated minimal cover: row %i has cover of size %i.\n",
+	   row,nCover);
+    //double sumCover = 0.0;
+    for (i=0; i<cover.getNumElements(); i++){
+      printf("index %i, element %g, xstar value % g \n",
+	     cover.getIndices()[i],cover.getElements()[i],
+	     xstar[cover.getIndices()[i]]);
+      //sumCover += cover.getElements()[i];
+    }
+    printf("The b = %.18g, and the cover element sum is %.18g (%.18g)\n\n",
+	   b,cover.sum(),coverSum);
+    printf("The b = %g, and the cover sum is %g\n\n", b, cover.sum());
+#endif
+
+#ifdef P0201
+      double ppsum=0.0;
+      for (i=0; i<nCover; i++){
+        ppsum += p0201[krow.getIndices()[i]];
+      }
+        
+      if (ppsum > nCover-1){
+          printf("\
+\nBad cover from lp relax of most violated cover..aborting\n");
+          abort();
+      }
+#endif
+    
+    /* clean up */
+    delete [] ratio;
+    return  1;
+  }
+}
+
+
+//--------------------------------------------------
+// Find a violated minimal cover from 
+// a canonical form knapsack inequality by
+// solving the -most- violated cover problem
+// and postprocess to ensure minimality
+// -----------------------------------------
+int 
+CglKnapsackCover::findExactMostViolatedMinCover(
+        int nCols,
+        int /*row*/,
+        CoinPackedVector & krow,
+        double b, 
+        double *  xstar, 
+        CoinPackedVector & cover,
+        CoinPackedVector & remainder)
+{
+  
+  // assumes the row is in canonical knapsack form 
+  
+  // A violated min.cover inequality exists if the
+  // opt obj func value (oofv) < 1: 
+  //     oofv = min sum (1-xstar_j)z_j
+  //            s.t. sum a_jz_j > b
+  //            x binary
+
+  //     The vector z is the incidence vector 
+  //     defines the set R and the cover inequality.
+  //      (sum j in R) x_j <= |R|-1
+
+  //    This is the min version of the knapsack problem.
+  //    (note that strict inequalty...bleck)
+
+  //    To obtain the max version, complement the z's, z_j=1-y_j and 
+  //    adjust the constraint.
+
+  //    oofv = (sum (1-xstar_j))-  max sum (1-xstar)y_j
+  //                       s.t. sum a_jy_j <= (sum over j)a_j - b (- EPSILON)]
+  //                   y binary
+
+  // If oofv < 1, violated min cover inequality has
+  //    incidence vector z=1-y and rhs= num of nonzero's in z, i.e.
+  //    the number 0 in y.
+
+  //    We solve the  0-1 knapsack problem by explicit ennumeration
+
+  double elementSum = krow.sum();
+
+  // Redundant/useless adjusted rows should have been trapped in 
+  // transformation to canonical form of knapsack inequality
+  if (elementSum < b + epsilon_) {
+#ifdef PRINT_DEBUG
+    printf("Redundant/useless adjusted row\n");
+#endif
+    return -1; 
+  }
+
+  // Order krow in nonincreasing order of coefObj_j/a_j.  
+  // (1-xstar_1)/a_1 >= (1-xstar_2)/a_2 >= ... >= (1-xstar_n)/a_n   
+  // by defining this full-storage array "ratio" to be the external sort key.  
+  double * ratio= new double[nCols];
+  memset(ratio, 0, (nCols*sizeof(double)));
+
+  int i;
+  {
+     const int * indices = krow.getIndices();
+     const double * elements = krow.getElements();
+     for (i=0; i<krow.getNumElements(); i++){
+	if (fabs(elements[i])> epsilon_ ){
+	   ratio[indices[i]]= (1.0-xstar[indices[i]]) / elements[i];
+	}
+	else {
+	   ratio[indices[i]] = 0.0;
+	}
+     }
+  }
+
+  // ToDo: would be nice to have sortkey NOT be full-storage vector
+  CoinDecrSolutionOrdered dso(ratio);
+  krow.sort(dso);   
+
+#ifdef CGL_DEBUG
+  // sanity check
+  for ( i=1; i<krow.getNumElements(); i++ ) {
+    double ratioim1 =  ratio[krow.getIndices()[i-1]];
+    double ratioi= ratio[krow.getIndices()[i]];
+    assert( ratioim1 >= ratioi );
+  }  
+#endif  
+  
+  // Recall:
+  // oofv = (sum (1-xstar_j))-  max sum (1-xstar)y_j
+  //           s.t. sum a_jy_j <= (sum over j)a_j - b (- epsilon_)]
+  //           y binary
+
+  double objConst = 0.0;
+  double exactOptVal = -1.0;
+  int * exactOptSol = new int[krow.getNumElements()];
+  double * p = new double[krow.getNumElements()];
+  double * w = new double[krow.getNumElements()];
+  int kk;
+  for (kk=0; kk<krow.getNumElements(); kk++){
+    p[kk]=1.0-xstar[krow.getIndices()[kk]];
+    w[kk]=krow.getElements()[kk];
+    objConst+=p[kk];
+  }
+  
+  // vectors are indexed in ratioSortIndex order 
+  exactSolveKnapsack(krow.getNumElements(), (elementSum-b-epsilon_), p, w,
+		     exactOptVal, exactOptSol);
+  
+  if(objConst-exactOptVal < 1){
+    cover.reserve(krow.getNumElements());
+    remainder.reserve(krow.getNumElements());
+
+    // Partition the krow into the cover and the remainder.
+    // The cover is complement of solution.
+    double coverElementSum = 0;
+    for(kk=0;kk<krow.getNumElements();kk++){
+      if(exactOptSol[kk]==0){
+        cover.insert(krow.getIndices()[kk],krow.getElements()[kk]);
+        coverElementSum += krow.getElements()[kk];
+      }
+      else {
+        remainder.insert(krow.getIndices()[kk],krow.getElements()[kk]);
+      }
+    }
+
+    cover.sortDecrElement();
+
+    // We have a violated cover inequality.
+    // Construct a -minimal- violated cover
+    // by testing and potentially tossing smallest
+    // elements 
+    double oneLessCoverElementSum =
+       coverElementSum - cover.getElements()[cover.getNumElements()-1];
+    while (oneLessCoverElementSum > b){
+      // move the excess cover member into the set of remainders
+      remainder.insert(cover.getIndices()[cover.getNumElements()-1],
+		       cover.getElements()[cover.getNumElements()-1]);
+      cover.truncate(cover.getNumElements()-1);
+      oneLessCoverElementSum -= cover.getElements()[cover.getNumElements()-1];
+    }
+
+#ifdef PRINT_DEBUG
+    printf("Exact Most Violated Cover: row %i has cover of size %i.\n",
+	   row,cover.getNumElements());
+    //double sumCover = 0.0;
+    for (i=0; i<cover.getNumElements(); i++){
+      printf("index %i, element %g, xstar value % g \n",
+	     cover.getIndices()[i], cover.getElements()[i],
+	     xstar[cover.getIndices()[i]]);
+      //sumCover += cover.getElements()[i];
+    }
+    printf("The b = %g, and the cover sum is %g\n\n", b, cover.sum() );
+#endif
+   
+    // local clean up 
+    delete [] exactOptSol;
+    delete [] p;
+    delete [] w;
+    delete [] ratio;
+    
+    return  1; // found an exact one
+  }
+
+  // local clean up 
+  delete [] exactOptSol;
+  delete [] p;
+  delete [] w;
+  delete [] ratio;
+  
+  return 0; // didn't find an exact one
+
+}  
+
+//-------------------------------------------------------------------
+// Find Pseudo John-and-Ellis Cover
+// 
+// only generates -violated- minimal covers
+//-------------------------------------------------------------------
+int
+CglKnapsackCover::findPseudoJohnAndEllisCover(
+					      int /*row*/,
+     CoinPackedVector & krow,
+     double & b,
+     double * xstar, 
+     CoinPackedVector & cover,  
+     CoinPackedVector & remainder)
+
+{
+  // semi-mimic of John&Ellis's approach without taking advantage of SOS info
+  // RLH: They find a minimal cover on unsatisfied variables, but it is 
+  // not guaranteed to be violated by currently solution 
+
+  // going for functional now, will make efficient when working 
+  
+  // look at unstatisfied binary vars with nonzero row coefficients only
+  // get row in canonical form (here row is in canonical form)
+  // if complement var, complement soln val too. (already done)
+  // (*) sort in increasing value of soln val
+  // track who is the biggest coef and it's index.
+  // if biggest > adjRhs, skip row. Bad knapsack.
+  // margin = adjRhs
+  // idea: if (possibly compl) soln >= .5 round up, else round down
+  // they do more, but that's the essence
+  // go through the elements {
+  // if round down, skip
+  // if round up, add to element to cover. adjust margin 
+  // if current element = biggest, then get next biggest
+  // if biggest > marg, you've got a cover. stop looking               
+  // else try next element in the loop
+  // }       
+  // (*)RLH: I'm going to sort in decreasing order of soln val
+  // b/c var's whose soln < .5 in can. form get rounded down 
+  // and skipped. If you can get a min cover of the vars
+  // whose soln is >= .5, I believe this gives the same as J&E.
+  // But if not, maybe I can get something more.
+       
+  // (**)By checking largest value left, they ensure a minimal cover
+  // on the unsatisfied variables
+     
+  // if you have a cover
+  // sort the elements to be lifted in order of their reduced costs.
+  // lift in this order.
+  // ...I don't understand their lifting, so for now use sequence-indep lifting
+
+  // J&E employ lifting up and down. 
+  // Here I'm including the vars at one in the cover.
+  // Adding these vars back in may cause the minimality of the cover to lost.
+  // So, post-processing to establish minimality is required.
+  
+  cover.reserve(krow.getNumElements());
+  remainder.reserve(krow.getNumElements());
+
+  double unsatRhs = b;
+
+  // working info on unsatisfied vars
+  CoinPackedVector unsat;
+  unsat.reserve(krow.getNumElements());
+
+  // working info on vars with value one
+  CoinPackedVector atOne;
+  atOne.reserve(krow.getNumElements());
+
+  // partition the (binary) variables in the canonical knapsack
+  // into those at zero, those at fractions, and those at one. 
+  // Note: no consideration given to whether variables are free
+  // or fixed at binary values.
+  // Note: continuous and integer vars have already been netted out
+  // to derive the canonical knapsack form
+  int i;
+  for (i=0; i<krow.getNumElements(); i++){
+
+    if (xstar[krow.getIndices()[i]] > onetol_){
+      atOne.insert(krow.getIndices()[i],krow.getElements()[i]); 
+      unsatRhs -= krow.getElements()[i];
+    }   
+    else if (xstar[krow.getIndices()[i]] >= epsilon_){
+      unsat.insert(krow.getIndices()[i],krow.getElements()[i]) ;
+    }
+    else { 
+      remainder.insert(krow.getIndices()[i],krow.getElements()[i]);
+    }
+  }
+
+  // sort the indices of the unsat var in order of decreasing solution value
+  CoinDecrSolutionOrdered decrSol(xstar);
+  unsat.sort(decrSol);
+  
+#ifdef CGL_DEBUG
+  // sanity check
+  for (i=1; i<unsat.getNumElements(); i++){
+    double xstarim1= xstar[unsat.getIndices()[i-1]];
+    double xstari= xstar[unsat.getIndices()[i]];
+    assert( xstarim1 >= xstari );
+  }
+#endif
+
+  // get the largest coefficient among the unsatisfied variables   
+  double bigCoef= 0.0;
+  // double temp;
+  int bigIndex = 0;
+  for (i=0; i<unsat.getNumElements(); i++){
+    if (unsat.getElements()[i]>bigCoef){
+      bigCoef = unsat.getElements()[i];
+      bigIndex = i;
+    }
+  }
+  
+  // initialize 
+  i=0;
+  double margin = unsatRhs;
+  int gotCover=0;
+  int j;
+  
+  // look in order through the unsatisfied vars which along with the 
+  // the max element defines a cover
+  while (i<unsat.getNumElements() && !gotCover){
+    margin -= unsat.getElements()[i];
+    
+    // get the biggest row coef downstream in the given order   
+    if (i == bigIndex){
+      bigCoef = 0.0;
+      bigIndex = 0;
+      for (j=i+1; j<unsat.getNumElements(); j++){
+        double temp = unsat.getElements()[j];
+        if (temp > bigCoef ){
+          bigCoef = temp;
+          bigIndex = j;
+        }
+      }
+    }
+    
+    if (bigCoef > margin+epsilon2_) gotCover = 1;
+    i++;          
+  }
+
+  // J&E approach; get first single one element that fills the margin   
+  if(gotCover){
+    j=i;
+    if (j<unsat.getNumElements()){ // need this "if" incase nUnsat=1   
+      while (unsat.getElements()[j]< margin) {
+        j++;
+      }
+      // switch members so that first nUnsat define the cover
+      unsat.swap(i,j);
+      i++;
+    }
+    
+    // check that detected cover is violated 
+    // (would we want to save incase it's violated later?)
+    int nCover = i;
+    double coverElementSum = 0.0;
+    double coverXstarSum = 0.0;
+    int k;
+    for (k=0; k<nCover; k++){
+      coverElementSum += unsat.getElements()[k];
+      coverXstarSum +=  xstar[unsat.getIndices()[k]];
+    }
+    
+    // Split the unsatisfied elements into those in the cover and those
+    // not in the cover. The elements not in the cover are considered
+    // remainders. Variables atOne belong to the cover
+
+    // Test if the detected cover is violated
+    if (coverXstarSum > (nCover-1) && coverElementSum > unsatRhs+epsilon2_){
+      for (i=nCover; i<unsat.getNumElements(); i++) {
+        remainder.insert(unsat.getIndices()[i],unsat.getElements()[i]);
+      }
+      unsat.truncate(nCover);
+      cover = unsat;
+      cover.append(atOne);
+
+      for (k=nCover; k<cover.getNumElements(); k++){
+        coverElementSum+=cover.getElements()[k];
+        coverXstarSum+=xstar[cover.getIndices()[k]];
+      }
+ 
+#ifdef CGL_DEBUG     
+      // Sanity check
+      int size = cover.getNumElements() + remainder.getNumElements(); 
+      int krowsize = krow.getNumElements();
+      assert( size == krowsize );
+#endif
+      
+      // Sort cover in terms of knapsack row coefficients   
+      cover.sortDecrElement();
+
+    // New!
+    // We have a violated cover inequality.
+    // Construct a -minimal- violated cover
+    // by testing and potentially tossing smallest
+    // elements 
+    double oneLessCoverElementSum =
+       coverElementSum - cover.getElements()[cover.getNumElements()-1];
+    while (oneLessCoverElementSum > b){
+      // move the excess cover member into the set of remainders
+      remainder.insert(cover.getIndices()[cover.getNumElements()-1],
+		       cover.getElements()[cover.getNumElements()-1]);
+      cover.truncate(cover.getNumElements()-1);
+      oneLessCoverElementSum -= cover.getElements()[cover.getNumElements()-1];
+    }
+  
+#ifdef PRINT_DEBUG
+    if (coverXstarSum > (nCover-1) && coverElementSum > b){
+      printf("John and Ellis: row %i has cover of size %i.\n",
+	     row,cover.getNumElements());
+      //double sumCover = 0.0;
+      for (i=0; i<cover.getNumElements(); i++){
+        printf("index %i, element %g, xstar value % g \n",
+	       cover.getIndices()[i], cover.getElements()[i],
+	       xstar[cover.getIndices()[i]]);
+      }
+      printf("The b = %.18g, and the cover element sum is %.18g (%.18g)\n\n",
+	     b,cover.sum(),coverElementSum);
+    }
+#endif
+
+    }
+    // if minimal cover is not violated, turn gotCover off
+    else {
+//    printf("heuristically found minimal cover is NOT violated by current lp solution");
+      gotCover = 0;
+    }          
+  }
+
+  // If no minimal cover was found, pack it in   
+  if (!gotCover || cover.getNumElements() < 2) {
+    return -1;
+  }
+  
+  //printf("PseudoJohnAndEllisCover - row %d elements %d\n",
+  // row,cover.getNumElements());
+  return  1;
+}
+
+
+
+
+
+//-------------------------------------------------------------------
+// Find a "approx" John-and-Ellis Cover
+// (i.e. that this approximates John & Ellis code)
+//  Test to see if we generate the same covers, and lifted cuts
+// 
+// generates minimal covers, not necessarily violated ones.
+//-------------------------------------------------------------------
+int
+CglKnapsackCover::findJohnAndEllisCover(
+					int /*row*/,
+     CoinPackedVector & krow,
+     double & b,
+     double * xstar, 
+     CoinPackedVector & fracCover,  
+     CoinPackedVector & atOne,
+     CoinPackedVector & remainder)
+
+{
+  // John Forrest and Ellis Johnson's approach as I see it.
+  // RLH: They find a minimal cover on unsatisfied variables, 
+  // which may not be violated by the solution to the lp relaxation
+
+  // "functional before efficient" is my creed.
+  
+  // look at unstatisfied binary vars with nonzero row coefficients only
+  // get row in canonical form (here krow is in canonical form)
+  // if complement var, complement soln val too. (already done)
+  // (*) sort in increasing value of soln val
+  // track who is the biggest coef and it's index.
+  // if biggest > adjRhs, skip row. Bad knapsack.
+  // margin = adjRhs
+  // idea: if (possibly compl) soln >= .5 round up, else round down
+  // they do more, but that's the essence
+  // go through the elements {
+  // if round down, skip
+  // if round up, add to element to cover. adjust margin 
+  // if current element = biggest, then get next biggest
+  // if biggest > marg, you've got a cover. stop looking               
+  // else try next element in the loop
+  // }       
+  // (*)RLH: I'm going to sort in decreasing order of soln val
+  // b/c var's whose soln < .5 in can. form get rounded down 
+  // and skipped. If you can get a min cover of the vars
+  // whose soln is >= .5, I believe this gives the same as J&E.
+  // But if not, maybe I can get something more.
+       
+  // (**)By checking largest value left, they ensure a minimal cover
+  // on the unsatisfied variables
+     
+  // if you have a cover
+  // sort the elements to be lifted in order of their reduced costs.
+  // lift in this order.
+  // They lift down on variables at one, in a sequence-dependent manner.
+  // Partion the variables into three sets: those in the cover, those 
+  // not in the cover at value one, and those remaining.
+  
+  fracCover.reserve(krow.getNumElements());
+  remainder.reserve(krow.getNumElements());
+  atOne.reserve(krow.getNumElements());
+
+  double unsatRhs = b;
+
+  // working info on unsatisfied vars
+  CoinPackedVector unsat;
+  unsat.reserve(krow.getNumElements());
+
+  // partition the (binary) variables in the canonical knapsack
+  // into those at zero, those at fractions, and those at one. 
+  // 
+  // essentially, temporarily fix to one the free vars with lp soln value of
+  // one by calculating the "unsatRhs". Call the result the "reduced krow".
+  //
+  // Note: continuous and integer vars, and variables fixed at 
+  // binary values have already been netted out
+  // in deriving the canonical knapsack form
+  int i;
+  for (i=0; i<krow.getNumElements(); i++){
+
+    if (xstar[krow.getIndices()[i]] > onetol_){
+      atOne.insert(krow.getIndices()[i],krow.getElements()[i]); 
+      unsatRhs -= krow.getElements()[i];
+    }   
+    else if (xstar[krow.getIndices()[i]] >= epsilon_){
+      unsat.insert(krow.getIndices()[i],krow.getElements()[i]) ;
+    }
+    else { 
+      remainder.insert(krow.getIndices()[i],krow.getElements()[i]);
+    }
+  }
+
+  // sort the indices of the unsat var in order of decreasing solution value
+  CoinDecrSolutionOrdered decrSol(xstar);
+  unsat.sort(decrSol);
+  
+#ifdef CGL_DEBUG
+  // sanity check
+  for (i=1; i<unsat.getNumElements(); i++){
+    double xstarim1 = xstar[unsat.getIndices()[i-1]];
+    double xstari=  xstar[unsat.getIndices()[i]];
+    assert( xstarim1 >= xstari );
+  }
+#endif
+
+  // get the largest coefficient among the unsatisfied variables   
+  double bigCoef= 0.0;
+  // double temp;
+  int bigIndex = 0;
+  for (i=0; i<unsat.getNumElements(); i++){
+    if (unsat.getElements()[i]>bigCoef){
+      bigCoef = unsat.getElements()[i];
+      bigIndex = i;
+    }
+  }
+  
+  // initialize 
+  i=0;
+  double margin = unsatRhs;
+  int gotCover=0;
+  int j;
+  
+  // look in order through the unsatisfied vars which along with the 
+  // the max element defines a cover
+  while (i<unsat.getNumElements() && !gotCover){
+    margin -= unsat.getElements()[i];
+    
+    // get the biggest row coef downstream in the given order   
+    if (i == bigIndex){
+      bigCoef = 0.0;
+      bigIndex = 0;
+      for (j=i+1; j<unsat.getNumElements(); j++){
+        double temp = unsat.getElements()[j];
+        if (temp > bigCoef ){
+          bigCoef = temp;
+          bigIndex = j;
+        }
+      }
+    }
+    
+    if (bigCoef > margin+epsilon2_) gotCover = 1;
+    i++;          
+  }
+
+  // J&E approach; get first single one element that fills the margin   
+  if(gotCover){ 
+    j=i;
+    if (j<unsat.getNumElements()){ // need this "if" incase nUnsat=1   
+      while (unsat.getElements()[j]< margin) {
+        j++;
+      }
+      // switch members so that first nUnsat define the cover
+      unsat.swap(i,j);
+      i++;
+    }
+    
+    // DEBUG: verify we have a cover over the reduced krow
+    // (may not be violated)
+    int nCover = i;
+    double coverElementSum = 0.0;
+    int k;
+    for (k=0; k<nCover; k++){
+      coverElementSum += unsat.getElements()[k];
+    }
+    
+    // Split the unsatisfied elements into those in the "reduced krow" cover
+    // and those not in the cover. The elements not in the cover are
+    // considered remainders. Variables atOne are reported as atOne.
+
+
+    // Test if the detected cover is violated
+    if (coverElementSum > unsatRhs+epsilon2_){
+      for (i=nCover; i<unsat.getNumElements(); i++) {
+        remainder.insert(unsat.getIndices()[i],unsat.getElements()[i]);
+      }
+      unsat.truncate(nCover);
+      fracCover = unsat;
+      // cover.append(atOne);
+
+#ifdef CGL_DEBUG
+      // Sanity check
+      int size = (fracCover.getNumElements() + remainder.getNumElements() +
+		  atOne.getNumElements());
+      int krowsize =  krow.getNumElements();
+      assert( size == krowsize );
+#endif
+      
+      // Sort cover in terms of knapsack row coefficients   
+      fracCover.sortDecrElement();
+
+    // We have a not-necessarily-violated "reduced krow" cover inequality.
+    // Minimal on the "reduced krow" 
+
+#if 0
+      
+      double oneLessCoverElementSum =
+	 coverElementSum-fracCover.getElements()[fracCover.getNumElements()-1];
+      while (oneLessCoverElementSum > b){
+        // move the excess cover member into the set of remainders
+        remainder.insert(fracCover.getIndices()[fracCover.getNumElements()-1],
+			 fracCover.getElements()[fracCover.getNumElements()-1]);
+        fracCover.truncate(fracCover.getNumElements()-1);
+        oneLessCoverElementSum -=
+	   fracCover.getElements()[fracCover.getNumElements()-1];
+      }
+#endif
+  
+#ifdef PRINT_DEBUG
+      printf("More Exactly John and Ellis:");
+      printf(" row %i has -reduced--fractional- cover of size %i.\n",
+	     row,fracCover.getNumElements());
+      double sumFracCover = 0.0;
+      for (i=0; i<fracCover.getNumElements(); i++){
+        printf("index %i, element %g, xstar value % g \n",
+	       fracCover.getIndices()[i],fracCover.getElements()[i],
+	       xstar[fracCover.getIndices()[i]]);
+        sumFracCover += fracCover.getElements()[i];
+      }
+      double sumAtOne = 0.0;
+      printf("There are %i variables at one:\n",atOne.getNumElements());
+      for (i=0; i<atOne.getNumElements(); i++){
+        printf("index %i, element %g, xstar value % g \n",
+	       atOne.getIndices()[i],atOne.getElements()[i],
+	       xstar[atOne.getIndices()[i]]);
+        sumAtOne += atOne.getElements()[i];
+      }
+      printf("The b = %g, sumAtOne = %g, unsatRhs = b-sumAtOne = %g, ",
+	     b, sumAtOne, unsatRhs);
+      printf("and the (fractional) cover element sum is %g\n\n", sumFracCover);
+#endif
+
+    }
+    // if minimal cover is not violated, turn gotCover off
+    else {
+//    printf("heuristically found minimal cover is NOT violated by current lp solution");
+      gotCover = 0;
+    }          
+  }
+
+  // If no minimal cover was found, pack it in   
+  if (!gotCover || fracCover.getNumElements() < 2) {
+    return -1;
+  }
+  //printf("JohnAndEllisCover - row %d elements %d\n",
+  // row,fracCover.getNumElements());
+  return  1;
+}
+
+//-------------------------------------------------------------------
+// findGreedyCover: attempts to find a violated minimal
+//                  cover using a greedy approach
+//
+// If a cover is found, it the cover and the remainder are 
+// sorted in nonincreasing order of the coefficients.
+//-------------------------------------------------------------------
+int
+CglKnapsackCover::findGreedyCover(
+				  int /*row*/,
+     CoinPackedVector & krow,
+     double & b,
+     double * xstar,
+     CoinPackedVector & cover,
+     CoinPackedVector & remainder
+     )
+  // the row argument is a hold over from debugging
+  // ToDo: move the print cover statement out to the mainprogram 
+  // and remove the row argument
+
+{ 
+  int i;
+  int gotCover =0;
+  
+  cover.reserve(krow.getNumElements());
+  remainder.reserve(krow.getNumElements());
+  
+  // sort knapsack in non-increasing size of row Coefficients 
+  krow.sortDecrElement();  
+  
+  // greedily pack them in 
+  // looking only at unsatisfied vars, i.e. 0<xstar[.]<1 
+  double greedyElementSum = 0.0;
+  double greedyXstarSum = 0.0;
+  
+  for (i=0;i<krow.getNumElements();i++){
+    // if xstar fractional && no cover yet, consider it for the cover 
+    if (xstar[krow.getIndices()[i]] >= epsilon_ &&
+	xstar[krow.getIndices()[i]] <= onetol_ &&
+	!gotCover){
+      greedyElementSum += krow.getElements()[i];
+      greedyXstarSum += xstar[krow.getIndices()[i]];
+      cover.insert(krow.getIndices()[i],krow.getElements()[i]);
+      if (greedyElementSum > b+epsilon2_){
+        gotCover = 1;
+      }
+    }
+    else{
+      remainder.insert(krow.getIndices()[i],krow.getElements()[i]);
+    }
+  }
+
+#ifdef CGL_DEBUG
+  // sanity check
+  int size =  remainder.getNumElements()+cover.getNumElements();
+  int krowsize = krow.getNumElements();
+  assert( size==krowsize );
+#endif  
+
+  // if no violated minimal cover was found, pack it in 
+  if ( (greedyXstarSum<=(cover.getNumElements()-1)+epsilon2_) ||
+       (!gotCover) ||
+       (cover.getNumElements() < 2)){
+    return -1;
+  }
+  
+#ifdef PRINT_DEBUG 
+  printf("Greedy cover: row %i has cover of size %i\n",
+	 row,cover.getNumElements());
+  for (i=0; i<cover.getNumElements(); i++){
+    printf("index %i, element %g, xstar value % g \n", 
+	   cover.getIndices()[i], cover.getElements()[i],
+	   xstar[cover.getIndices()[i]]);
+  }
+  printf("The b = %g, and the cover sum is %g\n\n", b, greedyElementSum);
+#endif
+
+  return  1;
+}
+
+//------------------------------------------------------------- 
+// Lift Up, Down, and Uncomplement. Add the resutling cut to the cutset
+//
+// In the solution to the lp relaxtion, 
+// the binary variable's solution value is either 0, 1 or fractional.
+//
+// Input:
+// The variables in fracCover form a cover, when the vars atOne take value one.
+// A cover for the krow would consist of the union of the fracCover and atOne vars
+// (which may not be violated, and may need to be processed to acheieve minimal-ness).
+//
+// Rather than take the "union" cover and lift up the remainder variables, 
+// we do something a little bit more interesting with the vars at one.
+//
+// The ip theory says that the lifted minimal cover cut can be strengthen by
+// "lifting down" the vars atOne.
+// -- this is what I believe John&Ellis were doing in OSL's knapsack cover cuts
+//    with a lifting heuristic.
+//
+//-------------------------------------------------------------------
+#if 0 //def CLP_INVESTIGATE
+static int nTry=0;
+static int howMany[5]={0,0,0,0,0};
+#endif
+void 
+CglKnapsackCover::liftUpDownAndUncomplementAndAdd(
+         int nCols,
+         double * xstar, 
+         int * complement,
+         int /*row*/,
+         int nRowElem,
+         double & b,
+
+         // the following 3 packed vectors partition the krow:
+
+	 // vars have frac soln values in lp relaxation
+	 // and form cover with the vars atOne
+         CoinPackedVector & fracCover, 
+	 // vars have soln value of 1 in lp relaxation
+         CoinPackedVector & atOne,
+	 // and together with fracCover form minimal (?) cover. 
+         CoinPackedVector & remainder,
+         OsiCuts & cs )
+{
+  CoinPackedVector cut;
+
+  // reserve storage for the cut
+  cut.reserve(nRowElem);
+  
+  // the cut coefficent for the members of the cover is 1.0
+  cut.setConstant(fracCover.getNumElements(),fracCover.getIndices(),1.0);
+  
+  // Preserve the cutRhs which is |C|-1, where |C| is the size of the
+  // fracCover.
+  double cutRhs=fracCover.getNumElements()-1;
+
+  // local variables
+  // unsatRhs is the rhs for the reduced krow
+  double unsatRhs = 0, sumAtOne = 0;
+  int i;
+  for (i=0; i<atOne.getNumElements(); i++){
+    sumAtOne += atOne.getElements()[i];
+  }
+  unsatRhs=b-sumAtOne;
+
+#ifdef PRINT_DEBUG
+  int firstFrac = fracCover.getIndices()[0];
+  if (unsatRhs<=0.0&&fabs(xstar[firstFrac])>epsilon2_) {
+    printf("At one %d\n",atOne.getNumElements());
+    for (i=0; i<atOne.getNumElements(); i++){
+      int iColumn = atOne.getIndices()[i];
+      printf("%d %g %g\n",atOne.getIndices()[i],atOne.getElements()[i],
+	     xstar[iColumn]);
+    }
+    printf("frac %d\n",fracCover.getNumElements());
+    for (i=0; i<fracCover.getNumElements(); i++){
+      int iColumn = fracCover.getIndices()[i];
+      printf("%d %g %g\n",fracCover.getIndices()[i],fracCover.getElements()[i],
+	     xstar[iColumn]);
+    }
+  }
+#endif
+
+  //assert ( unsatRhs > 0 );
+
+  // If there is something to lift, then calculate the lifted coefficients
+  if (unsatRhs>0.0&&(remainder.getNumElements()+atOne.getNumElements())> 0){
+    
+    // What order to lift?
+    // Take the remainder vars in decreasing order of their
+    // xstar solution value. Sort remainder in order of decreasing 
+    // xstar value.
+    // Lift them "up"
+    // (The lift "down" the variables atOne.
+    CoinDecrSolutionOrdered dso1(xstar);
+    remainder.sort(dso1);   
+
+#if GUBCOVER==2
+    int nClique=0;
+    double * weightClique2 = NULL;
+    int * indices = NULL;
+    int * starts = NULL;
+    if (numberCliques_) {
+      int nInCover = fracCover.getNumElements();
+      int nRest = remainder.getNumElements();
+      const CoinPackedMatrix * matrixByRow = solver_->getMatrixByRow();
+#ifdef PRINT_DEBUG
+      const double * elementByRow = matrixByRow->getElements();
+#endif
+      const int * column = matrixByRow->getIndices();
+      const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+      const int * rowLength = matrixByRow->getVectorLengths();
+#ifdef PRINT_DEBUG
+      const double * rowUpper = solver_->getRowUpper();
+      const double * rowLower = solver_->getRowLower();
+#endif
+      int numberColumns = solver_->getNumCols();
+      double * els = elements_;
+      double * els2 = els+numberColumns;
+      double * weightClique = els2+numberColumns;
+      weightClique2 = weightClique+numberCliques_;
+      double * temp = weightClique2+2*numberColumns;
+      int * count = reinterpret_cast<int *>(temp);
+      indices = reinterpret_cast<int *> (temp+numberCliques_);
+      int * whichClique = indices+numberColumns;
+      for (i=rowStart[whichRow_];i<rowStart[whichRow_]+rowLength[whichRow_];i++) {
+	int iColumn = column[i];
+	indices[iColumn]=-1;
+#ifdef PRINT_DEBUG
+	els2[iColumn]=elementByRow[i];
+#endif
+      }
+      const int * ind;
+      ind = fracCover.getIndices();
+#ifdef PRINT_DEBUG
+      const double * elsIn;
+      elsIn = fracCover.getElements();
+#endif
+      // Deal with complemented and cliques later
+      for (i=0;i<nInCover;i++) {
+	int iColumn = ind[i];
+#ifdef PRINT_DEBUG
+	els[iColumn]=elsIn[i];
+#endif
+	if (oneFixStart_[iColumn]>=0&&!complement_[iColumn]) {
+	  //printf("Cover column %d, xstar %g ",iColumn,xstar[iColumn]); 
+	  for (int j=oneFixStart_[iColumn];j<zeroFixStart_[iColumn];j++) {
+	    int iClique = whichClique_[j];
+	    //printf("(clique %d %g => ",iClique,weightClique[iClique]);
+	    double value=weightClique[iClique];
+	    if (!value) {
+	      whichClique[nClique++] =iClique;
+	      count[iClique]=0;
+	    }
+	    count[iClique]++;
+	    value += 3.0;
+	    weightClique[iClique]=value;
+	    //printf("%g) ",weightClique[iClique]);
+	  }
+	  //printf("\n");
+	}
+      }
+      ind = remainder.getIndices();
+#ifdef PRINT_DEBUG
+      elsIn = remainder.getElements();
+#endif
+      for (i=0;i<nRest;i++) {
+	int iColumn = ind[i];
+#ifdef PRINT_DEBUG
+	els[iColumn]=elsIn[i];
+#endif
+	double value = xstar[iColumn];
+	if (fabs(value-floor(value+0.5))>1.0e-5)
+	  value=3.0;
+	else 
+	  value=0.99;
+	if (oneFixStart_[iColumn]>=0&&!complement_[iColumn]) {
+	  //printf("Column %d, xstar %g ",iColumn,xstar[iColumn]); 
+	  for (int j=oneFixStart_[iColumn];j<zeroFixStart_[iColumn];j++) {
+	    int iClique = whichClique_[j];
+	    double oldValue=weightClique[iClique];
+	    if (!oldValue) {
+	      whichClique[nClique++] =iClique;
+	      count[iClique]=0;
+	    }
+	    count[iClique]++;
+	    value += oldValue;
+	    weightClique[iClique]=value;
+	    //printf("(clique %d %g => ",iClique,weightClique[iClique]);
+	    //printf("%g) ",weightClique[iClique]);
+	  }
+	  //printf("\n");
+	}
+      }
+      // But only look at cliques with more than one entry
+      int nnClique=0;
+      for (i=0;i<nClique;i++) {
+	int iClique=whichClique[i];
+	if (count[iClique]>1) 
+	  whichClique[nnClique++]=iClique;
+	else
+	  weightClique[iClique]=0.0;
+      }
+      nClique=nnClique;
+      ind = fracCover.getIndices();
+      for (i=0;i<nInCover;i++) {
+	int iColumn = ind[i];
+	if (oneFixStart_[iColumn]>=0&&!complement_[iColumn]) {
+	  double value=3.1;
+	  int jClique=-1;
+	  for (int j=oneFixStart_[iColumn];j<zeroFixStart_[iColumn];j++) {
+	    int iClique = whichClique_[j];
+	    if(weightClique[iClique]>value) {
+	      jClique=iClique;
+	      value=weightClique[iClique];
+	    }
+	  }
+	  if (jClique>=0) {
+	    indices[iColumn]=jClique;
+	    count[jClique]=-1;
+	  } else {
+	    indices[iColumn]=-2;
+	  }
+	}
+      }
+      ind = remainder.getIndices();
+      for (i=0;i<nRest;i++) {
+	int iColumn = ind[i];
+	if (oneFixStart_[iColumn]>=0&&!complement_[iColumn]) {
+	  double value=1.1;
+	  int jClique=-1;
+	  for (int j=oneFixStart_[iColumn];j<zeroFixStart_[iColumn];j++) {
+	    int iClique = whichClique_[j];
+	    if(weightClique[iClique]>value) {
+	      jClique=iClique;
+	      value=weightClique[iClique];
+	    }
+	  }
+	  if (jClique>=0) {
+	    indices[iColumn]=jClique;
+	    count[jClique]=-1;
+	  } else {
+	    indices[iColumn]=-2;
+	  }
+	}
+      }
+#ifdef PRINT_DEBUG
+      bool interesting = false;
+#endif
+      nnClique=0;
+      for (i=0;i<nClique;i++) {
+	int iClique=whichClique[i];
+	if (count[iClique]<0) {
+#ifdef PRINT_DEBUG
+	  if (!interesting) {
+	    interesting=true;
+	    printf("%d cover, %d remainder - b = %g (rhs %g,%g)",
+		   nInCover,nRest,b,rowLower[whichRow_],
+		   rowUpper[whichRow_]);
+	    for (int k=rowStart[whichRow_];k<rowStart[whichRow_]+rowLength[whichRow_];k++) {
+	      int iColumn = column[k];
+	      printf(" (%d,%g) ",iColumn,elementByRow[k]);
+	    }
+	    printf("\n");
+	  }
+	  printf("Clique %d weight %g - ",iClique,weightClique[iClique]);
+	  for (int j=0;j<numberColumns;j++) {
+	    if (indices[j]==iClique) {
+	      printf("%d,%g (real el %g),%g) ",j,els[j],els2[j],xstar[j]);
+	    }
+	  }
+	  printf("\n");
+#endif
+	  whichClique[nnClique++]=iClique;
+	}
+	weightClique[iClique]=0.0;
+      }
+      nClique=nnClique;
+      if (nClique) {
+	// Space for columns in each clique
+	starts = whichClique + numberCliques_;
+	int * current = starts + nClique+1;
+	int * nNow = current+nClique+1;
+	int * stack = nNow+nClique+1;
+	int * which = stack+nClique+3;
+	CoinZeroN(current,3*nClique+5);
+	nnClique=0;
+	for (i=0;i<numberColumns;i++) {
+	  int iClique=indices[i];
+	  if (iClique>=0) {
+	    int back = count[iClique];
+	    if (back<0) {
+	      // first
+	      back=nnClique;
+	      count[iClique]=nnClique;
+	      whichClique[nnClique++]=iClique;
+	      current[iClique]=0;
+	    }
+	    current[iClique]++;
+	    weightClique[back] -= xstar[i];
+	  }
+	}
+	assert (nnClique==nClique);
+	CoinSort_2(weightClique,weightClique+nClique,whichClique);
+	int n=0;
+	for (i=0;i<nClique;i++) {
+	  starts[i]=n;
+	  int iClique = whichClique[i];
+	  count[iClique]=i;
+	  n += current[iClique];
+	}
+	starts[nClique]=n;
+	for (i=0;i<nClique;i++) {
+	  current[i]=starts[i]; // make start
+	  nNow[i]=0;
+	}
+	starts[nClique]=n;
+	which[n]=-1;
+	// Now fracCover in
+	ind = fracCover.getIndices();
+	for (i=0;i<nInCover;i++) {
+	  int iColumn = ind[i];
+	  int iClique=indices[iColumn];
+	  if (iClique>=0) {
+	    int back = count[iClique];
+	    int put = current[back];
+	    current[back]++;
+	    which[put]=iColumn;
+	    indices[iColumn]=back;
+	    nNow[back]++; // already in
+	  }
+	}
+	// Next remainder (maybe should split into nonzero and zero)
+	// and add atOnes in middle
+	// *** NEED to sort so best gub first
+	ind = remainder.getIndices();
+	for (i=0;i<nRest;i++) {
+	  int iColumn = ind[i];
+	  int iClique=indices[iColumn];
+	  if (iClique>=0) {
+	    int back = count[iClique];
+	    int put = current[back];
+	    current[back]++;
+	    which[put]=iColumn;
+	    indices[iColumn]=back;
+	  }
+	}
+#ifdef CLP_INVESTIGATE
+	nTry++;
+	int k=CoinMin(nClique,4);
+	howMany[k]++;
+	if ((nTry%100)==0) {
+	  printf("TRY %d ",nTry);
+	  for (i=1;i<5;i++)
+	    if (howMany[i])
+	      printf("(%d cliques -> %d) ",i,howMany[i]);
+	  printf("\n");
+	}
+#endif
+      }
+    }
+#endif
+    
+    // a is the part of krow corresponding to vars which have been lifted
+    // alpha are the lifted coefficients with explicit storage of lifted zero
+    // coefficients the a.getIndices() and alpha.getIndices() are identical
+    CoinPackedVector a(fracCover);
+    CoinPackedVector alpha;
+    int i;
+    for (i=0; i<fracCover.getNumElements(); i++){
+      alpha.insert(fracCover.getIndices()[i],1.0);
+    }
+    // needed as an argument for exactSolveKnapsack
+    int * x = new int[nRowElem];
+    double psi_j=0.0;
+    
+    // Order alpha and a in nonincreasing order of alpha_j/a_j.  
+    // alpha_1/a_1 >= alpha_2/a_2 >= ... >= alpha_n/a_n   
+    // by defining this full-storage array "ratio" to be the external sort key.
+    // right now external sort key must be full-storage.
+
+    double * ratio= new double[nCols];
+    memset(ratio, 0, (nCols*sizeof(double)));
+
+#ifdef CGL_DEBUG
+    double alphasize = alpha.getNumElements();
+    double asize = a.getNumElements();
+    assert( alphasize == asize );
+#endif
+    
+    for (i=0; i<a.getNumElements(); i++){
+      if (fabs(a.getElements()[i])> epsilon_ ){
+        ratio[a.getIndices()[i]]=alpha.getElements()[i]/a.getElements()[i];
+      }
+      else {
+        ratio[a.getIndices()[i]] = 0.0;
+      }
+    }
+
+    CoinDecrSolutionOrdered dso2(ratio);
+    a.sort(dso2);   
+    alpha.sort(dso2);
+    
+#ifdef CGL_DEBUG
+    // sanity check
+    for ( i=1; i<a.getNumElements(); i++ ) {
+      int alphai=  alpha.getIndices()[i];
+      int ai = a.getIndices()[i];
+      assert( alphai == ai);
+    }  
+#endif  
+    
+#if GUBCOVER==2
+    int * current = starts + nClique+1;
+    int * nNow = current+nClique+1;
+    int * stack = nNow+nClique+1;
+    int * which = stack+nClique+3;
+#endif
+    // Loop through the remainder variables to be lifted "up", and lift.
+    int j;
+    int firstZero=remainder.getNumElements();
+    for (j=0; j<firstZero; j++){
+      int iColumn = remainder.getIndices()[j];
+      double element = remainder.getElements()[j];
+      //printf("xstar for %d is %g\n",iColumn,xstar[iColumn]);
+      //if (xstar[iColumn]<1.0e-8) {
+      //firstZero=j;
+      //break;
+      //}
+      // calculate the lifted coefficient of x_j = cutRhs-psi_j
+      // where 
+      // psi_j =  max of the current lefthand side of the cut
+      //          s.t. the reduced knapsack corresponding to vars that have
+      //          been lifted <= unsatRhs-a_j
+      
+      // Note: For exact solve, must be sorted in
+      // alpha_1/a_1>=alpha_2/a_2>=...>=alpha_n/a_n order
+      // check if lifted var can take value 1 
+      ratio[iColumn] = 0.0;
+#if GUBCOVER==2
+      int inClique = (nClique) ? indices[iColumn] : -3;
+#endif
+      if (unsatRhs - element >= epsilon_) {
+#if GUBCOVER==2
+	if (!nClique) {
+#endif
+	  exactSolveKnapsack(alpha.getNumElements(),
+			     unsatRhs-element,
+			     alpha.getElements(),a.getElements(),psi_j,x);
+#if GUBCOVER==2
+	} else {
+	  // A) should sort "remainder" so strongest clique first
+	  // B) make more efficient
+	  // C) take out news in exactKnapsack
+	  // weightClique2 is 2*ncolumns
+	  // indices
+	  for (i=0;i<nClique;i++) {
+	    stack[i]=nNow[i]-1;
+	    int k =starts[i];
+	    current[i]=which[k+stack[i]];
+	  }
+	  stack[nClique]=-1;
+	  current[nClique]=-1;
+	  double oldPsi_j;
+	  exactSolveKnapsack(alpha.getNumElements(),
+			     unsatRhs-element,
+			     alpha.getElements(),a.getElements(),oldPsi_j,x);
+	  //#define FULL_GUB_PRINT
+#ifdef FULL_GUB_PRINT
+	  printf("Ordinary psi %g\n",oldPsi_j);
+#endif
+	  double biggestPsi_j=0.0;
+	  double nowPsi_j;
+	  int n1=alpha.getNumElements();
+	  int * indIn = alpha.getIndices();
+	  double * pIn = alpha.getElements();
+	  double * wIn = a.getElements();
+	  double * p = weightClique2;
+	  double * w = p+n1;
+	  int kStack=nClique-1;
+#ifdef FULL_GUB_PRINT
+	  {
+	    printf ("Looking at column %d\n",iColumn);
+	    for (int j=0;j<nClique;j++) {
+	      printf("Clique %d ",j);
+	      for (int jj=starts[j];jj<starts[j+1];jj++)
+		printf("%d ",which[jj]);
+	      printf("\n");
+	    }
+	  }
+	  if (iColumn==17) {
+	    printf("col %d\n",iColumn);
+	  }
+#endif
+	  while (kStack>=0) {
+	    // Do current
+	    for (i=0;i<nClique;i++) {
+	      int k =starts[i];
+	      int kk=stack[i];
+	      if (kk>=0) {
+		current[i]=which[k+kk];
+	      } else {
+		current[i]=-3;
+	      }
+	    }
+	    double offsetObj=0.0;
+	    double testRhs=unsatRhs-element;
+	    int n=0;
+	    for (i=0;i<n1;i++) {
+	      int jColumn = indIn[i];
+	      int jClique = indices[jColumn];
+	      if (jClique<0) {
+		// not in gub - take
+		p[n]=pIn[i];
+		w[n++]=wIn[i];
+	      } else if (jColumn==current[jClique]&&jClique!=inClique) {
+		// forced in unless will go negative
+		offsetObj += pIn[i];
+		testRhs -= wIn[i];
+	      }
+	    }
+	    if (testRhs >= epsilon_) {
+	      exactSolveKnapsack(n,testRhs,p,w,nowPsi_j,x);
+	      nowPsi_j += offsetObj;
+#ifdef FULL_GUB_PRINT
+	      printf("gub psi %g\n",nowPsi_j);
+#endif
+	      assert (nowPsi_j>=0.0);
+	      if (nowPsi_j>biggestPsi_j)
+		biggestPsi_j=nowPsi_j;
+	    } else if (testRhs >= -epsilon_) {
+	      // as is
+	      nowPsi_j = offsetObj;
+#ifdef FULL_GUB_PRINT
+	      printf("gub psi %g (no knapsack computation)\n",nowPsi_j);
+#endif
+	      assert (nowPsi_j>=0.0);
+	      if (nowPsi_j>biggestPsi_j)
+		biggestPsi_j=nowPsi_j;
+	    } else {
+#ifdef FULL_GUB_PRINT
+	      printf("take as zero\n");
+#endif
+	    }
+	    stack[kStack]--;
+	    while (stack[kStack]<0) {
+	      stack[kStack]=nNow[kStack]-1;
+	      kStack--;
+	      if (kStack>=0) {
+		stack[kStack]--;
+		if (stack[kStack]>=0) {
+		  kStack=nClique-1;
+		  break;
+		}
+	      }
+	    }
+	  }
+#ifdef FULL_GUB_PRINT
+	  if (fabs(biggestPsi_j-oldPsi_j)>1.0e-7) {
+	    printf("gub ** Ordinary psi %g, gub %g\n",oldPsi_j,
+		   biggestPsi_j);
+	  }
+#endif
+	  assert (biggestPsi_j<oldPsi_j+1.0e-6);
+	  psi_j = biggestPsi_j;
+	}
+#endif
+      } else {
+	// Take as zero!
+	psi_j=cutRhs; //0.0;
+      }
+      // if the lifted coefficient is non-zero 
+      // (i.e. psi_j != cutRhs), add it to the cut
+      if (cutRhs-psi_j>epsilon_) {
+	cut.insert(iColumn,cutRhs-psi_j);
+	
+	// assert the new coefficient is nonegative?
+	alpha.insert(iColumn,cutRhs-psi_j);
+	a.insert(iColumn,element);
+	
+	
+	ratio[iColumn] = (cutRhs-psi_j)/element;
+	CoinDecrSolutionOrdered dso(ratio);
+	a.sort(dso);   
+	alpha.sort(dso);    
+      }
+#if GUBCOVER==2
+      if (inClique>=0) {
+	int kStart =starts[inClique];
+	int kEnd =starts[inClique+1];
+	int j=nNow[inClique];
+	j += kStart;
+	assert (kStart<kEnd);
+	assert (iColumn==which[j]);
+	if (cutRhs-psi_j>epsilon_) {
+	  nNow[inClique]++;
+	} else {
+	  // shuffle up (some may have already gone)
+	  for (int k=j+1;k<kEnd;k++) {
+	    which[k-1]=which[k];
+	    if (which[k-1]==-1)
+	      break;
+	  }
+	  // set to -1 at end
+	  which[kEnd-1]=-1;
+	}
+      }
+#endif
+    }
+
+    // Loop throught the variables atOne and lift "down"
+    for (j=0; j<atOne.getNumElements(); j++){
+      // calculate the lifted coefficient of x_j = psi_j-cutRhs (now cutRhs
+      // gets updated) where 
+      // psi_j =  max of the current lefthand side of the cut
+      //          s.t. the reduced knapsack corresponding to vars that have
+      //          been lifted <= unsatRhs+a_j 
+      
+      // Note: For exact solve, must be sorted in
+      // alpha_1/a_1>=alpha_2/a_2>=...>=alpha_n/a_n order 
+      exactSolveKnapsack(alpha.getNumElements(),
+			 unsatRhs+atOne.getElements()[j],
+			 alpha.getElements(),a.getElements(),psi_j,x);
+      alpha.insert(atOne.getIndices()[j],psi_j-cutRhs);
+      a.insert(atOne.getIndices()[j],atOne.getElements()[j]);
+      // if the lifted coefficient is non-zero (i.e. psi_j != cutRhs), add it
+      // to the cut 
+      if (fabs(psi_j-cutRhs)>epsilon_)
+	 cut.insert(atOne.getIndices()[j],psi_j-cutRhs);
+
+#ifdef CGL_DEBUG
+      assert ( fabs(atOne.getElements()[j])> epsilon_ );
+#else
+      if ( fabs(atOne.getElements()[j])<= epsilon_ ) {
+	// exit gracefully
+	cutRhs = COIN_DBL_MAX;
+	break;
+      }
+#endif
+      ratio[atOne.getIndices()[j]]=(psi_j-cutRhs)/atOne.getElements()[j];
+
+      // update cutRhs and unsatRhs
+      cutRhs = psi_j ;      
+      unsatRhs += atOne.getElements()[j];
+
+      CoinDecrSolutionOrdered dso(ratio);
+      a.sort(dso);   
+      alpha.sort(dso);    
+    }
+
+#if 0
+    for (j=firstZero; j<remainder.getNumElements(); j++){
+      int iColumn = remainder.getIndices()[j];
+      printf("xstar for %d is %g\n",iColumn,xstar[iColumn]);
+      // calculate the lifted coefficient of x_j = cutRhs-psi_j
+      // where 
+      // psi_j =  max of the current lefthand side of the cut
+      //          s.t. the reduced knapsack corresponding to vars that have
+      //          been lifted <= unsatRhs-a_j
+      
+      // Note: For exact solve, must be sorted in
+      // alpha_1/a_1>=alpha_2/a_2>=...>=alpha_n/a_n order
+      // check if lifted var can take value 1 
+      if (unsatRhs - remainder.getElements()[j] < epsilon_){
+	psi_j = cutRhs;
+      }
+      else {	  
+	exactSolveKnapsack(alpha.getNumElements(),
+	      	 unsatRhs-remainder.getElements()[j],
+		 alpha.getElements(),a.getElements(),psi_j,x);
+      }
+      
+      // assert the new coefficient is nonegative?
+      alpha.insert(remainder.getIndices()[j],cutRhs-psi_j);
+      a.insert(remainder.getIndices()[j],remainder.getElements()[j]);
+      
+      // if the lifted coefficient is non-zero 
+      // (i.e. psi_j != cutRhs), add it to the cut
+      if (fabs(cutRhs-psi_j)>epsilon_)
+	 cut.insert(remainder.getIndices()[j],cutRhs-psi_j);
+      
+      ratio[remainder.getIndices()[j]]=
+	 (cutRhs-psi_j)/remainder.getElements()[j];
+      CoinDecrSolutionOrdered dso(ratio);
+      a.sort(dso);   
+      alpha.sort(dso);    
+    }
+#endif
+    delete [] x;
+    delete [] ratio;
+#if GUBCOVER==2
+    if (numberCliques_) {
+      const CoinPackedMatrix * matrixByRow = solver_->getMatrixByRow();
+      //const double * elementByRow = matrixByRow->getElements();
+      const int * column = matrixByRow->getIndices();
+      const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+      const int * rowLength = matrixByRow->getVectorLengths();
+      //const double * rowUpper = solver_->getRowUpper();
+      //const double * rowLower = solver_->getRowLower();
+      int numberColumns = solver_->getNumCols();
+      double * els = elements_;
+      double * els2 = els+numberColumns;
+      double * weightClique = els2+numberColumns;
+      double * weightClique2 = weightClique+numberCliques_;
+      double * temp=weightClique2+2*numberColumns;
+      //int * count = reinterpret_cast<int *>(temp);
+      int * indices = reinterpret_cast<int *> (temp+numberCliques_);
+      //int * whichClique = indices+numberColumns;
+      for (i=rowStart[whichRow_];i<rowStart[whichRow_]+rowLength[whichRow_];i++) {
+	int iColumn = column[i];
+	indices[iColumn]=-2;
+#ifdef PRINT_DEBUG
+	els2[iColumn]=0.0;
+#endif
+      }
+      for (i=0;i<nClique;i++) 
+	weightClique[i]=0.0;
+      for (i=0;i<numberCliques_;i++)
+	assert (!weightClique[i]);
+      //int numberColumns = solver_->getNumCols();
+#ifdef PRINT_DEBUG
+      CoinZeroN(els,numberColumns); //temp
+      for (i=0;i<numberColumns;i++) {
+	assert (indices[i]==-2);
+	assert (!els[i]);
+	assert (!els2[i]);
+      }
+#endif
+    }
+#endif
+
+  }
+
+  // If the cut is violated, add it to the pool
+  // if (sum over cut.getIndices())
+  //    cut.element()*xstar > cover.getNumElements()-1, un-complement
+  // and add it to the pool.
+  double sum=0;
+  for (i=0; i<cut.getNumElements(); i++){
+    sum+= cut.getElements()[i]*xstar[cut.getIndices()[i]];
+  }
+  if (sum > cutRhs+epsilon2_){
+#ifdef PRINT_DEBUG
+    printf("Sequentially lifted UpDown cover cut of ");
+    printf("size %i derived from fracCover of size %i.\n",
+	   cut.getNumElements(), fracCover.getNumElements());
+    for (i=0; i<cut.getNumElements(); i++){
+      printf("index %i, element %g, xstar value % g \n",
+	     cut.getIndices()[i],cut.getElements()[i],
+	     xstar[cut.getIndices()[i]]);
+    }
+    printf("The cutRhs = %g, and the alpha_j*xstar_j sum is %g\n\n",
+	   cutRhs, sum);
+#endif
+    
+#ifdef GUBCOVER
+  if (numberCliques_) {
+    int n = cut.getNumElements();
+    const int * ind3;
+    const double * els3;
+    ind3 = cut.getIndices();
+    els3 = cut.getElements();
+    const CoinPackedMatrix * matrixByRow = solver_->getMatrixByRow();
+    const double * elementByRow = matrixByRow->getElements();
+    const int * column = matrixByRow->getIndices();
+    const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+    const int * rowLength = matrixByRow->getVectorLengths();
+    int numberColumns = solver_->getNumCols();
+    double * els = elements_;
+    double * els2 = els+numberColumns;
+    for (i=0;i<n;i++) 
+      els[ind3[i]]=els3[i];
+    for (i=rowStart[whichRow_];i<rowStart[whichRow_]+rowLength[whichRow_];i++) {
+      int iColumn = column[i];
+      els2[iColumn]=elementByRow[i];
+    }
+#if CGL_DEBUG
+    bool found=false;
+#endif
+    for (i=0;i<n;i++) {
+      int iColumn = ind3[i];
+      // complement doesn't seem to work?
+      if (!complement_[iColumn]) {
+	if (oneFixStart_[iColumn]>=0) {
+	  for (int j=oneFixStart_[iColumn];j<zeroFixStart_[iColumn];j++) {
+	    int iClique = whichClique_[j];
+	    for (int k=cliqueStart_[iClique];k<cliqueStart_[iClique+1];k++) {
+	      int jColumn = sequenceInCliqueEntry(cliqueEntry_[k]);
+	      if (!els[jColumn]&&els2[jColumn]) {
+		assert (jColumn!=iColumn);
+		if (!complement_[jColumn]&&oneFixesInCliqueEntry(cliqueEntry_[k])) {
+		  //if (els2[iColumn]<0.0||els2[jColumn]<0.0)
+		    //printf("true els %g (c%d) and %g (c%d)\n",
+		    //   els2[iColumn],complement_[iColumn],
+		    //   els2[jColumn],complement_[jColumn]);
+		  if (fabs(els2[jColumn])>=fabs(els2[iColumn])) {
+#if CGL_DEBUG
+		    if (!found) {
+		      found=true;
+		      printf("Good cut can be improved");
+		      for (i=0;i<n;i++) 
+			printf("(%d,%g) ",ind3[i],els3[i]);
+		      printf("<= %g\n",b);
+		    }
+		    printf("can add! %d %d\n",iColumn,jColumn);
+#endif
+		    els[jColumn]=els[iColumn];
+		    cut.insert(jColumn,els[jColumn]);
+		    // recompute as may have changed
+		    ind3 = cut.getIndices();
+		  }
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    // zero out
+    n = cut.getNumElements();
+    ind3 = cut.getIndices();
+    for (i=0;i<n;i++) 
+      els[ind3[i]]=0.0;
+    for (i=rowStart[whichRow_];i<rowStart[whichRow_]+rowLength[whichRow_];i++) {
+      int iColumn = column[i];
+      els2[iColumn]=0.0;
+    }
+    for (i=0;i<numberColumns;i++) {
+      assert (!els[i]);
+      assert (!els2[i]);
+    }
+  }
+#endif
+    // de-complement
+    int k;
+    const int s = cut.getNumElements();
+    const int * indices = cut.getIndices();
+    double * elements = cut.getElements();
+    for (k=0; k<s; k++){
+      if (complement[indices[k]]) {
+        // Negate the k'th element in packedVector cut
+        // and correspondingly adjust the rhs
+        elements[k] *= -1;
+        cutRhs += elements[k];
+      }
+    }
+    
+   
+    // Create row cut
+    OsiRowCut rc;
+    rc.setRow(cut);
+#ifdef CGL_DEBUG
+    {
+      double * elements = cut.getElements();
+      int * indices = cut.getIndices();
+      int n=cut.getNumElements();
+      for (k=0; k<n; k++){
+	assert(indices[k]>=0);
+	assert(elements[k]);
+        assert (fabs(elements[k])>1.0e-12);
+      }
+    }
+#endif
+    rc.setLb(-COIN_DBL_MAX);
+    rc.setUb(cutRhs);
+    // ToDo: what's the default effectiveness?
+    //  rc.setEffectiveness(1.0);
+    // Add row cut to the cut set  
+#ifdef PRINT_DEBUG
+    {
+      int k;
+      printf("cutrhs %g %d elements\n",cutRhs,cut.getNumElements());
+      double * elements = cut.getElements();
+      int * indices = cut.getIndices();
+      for (k=0; k<cut.getNumElements(); k++){
+	printf("%d %g\n",indices[k],elements[k]);
+      }
+    }
+#endif
+    cs.insert(rc);
+  }
+}
+
+//-------------------------------------------------------------------
+// seqLiftCoverCut:  Given a canonical knapsack inequality and a
+//                cover, performs sequence-dependent lifting.
+//                Reference: Nemhauser & Wolsey
+//
+// NW suggest a lifting heuristic order that requires an argmax operation.
+// What's the strength vs performance tradeoff of using argmax over
+// a heuristic that depends soley on an a-prioi ordering based on
+// the optimal solution to the lp relaxation? ToDo:  Do both, and report.
+//
+//-------------------------------------------------------------------
+void
+CglKnapsackCover::seqLiftAndUncomplementAndAdd(
+      int nCols,
+      double * xstar, 
+      int * complement,
+      int /*row*/,                       // row index number: used for debugging 
+                                     //     and to index into row bounds
+      int nRowElem,                  // number of elements in the row, aka row
+                                     //     size, row length. 
+      double & b,                    // rhs of the canonical knapsack
+                                     //     inequality derived from row 
+      CoinPackedVector & cover,       // need not be violated
+      CoinPackedVector & remainder,
+      OsiCuts & cs)
+{
+  CoinPackedVector cut;
+  
+  // reserve storage for the cut
+  cut.reserve(nRowElem);
+  
+  // the cut coefficent for the members of the cover is 1.0
+  cut.setConstant(cover.getNumElements(),cover.getIndices(),1.0);
+  
+  // so preserve the cutRhs which is |C|-1, where |C| is the size of the cover.
+  double cutRhs=cover.getNumElements()-1;
+  
+  // If there is something to lift, then calcualte the lifted coefficients
+  if (remainder.getNumElements()> 0){
+    
+    // What order to lift?
+    // Take the to-be-lifted vars in decreasing order of their
+    // xstar solution value. Sort remainder in order of decreasing 
+    // xstar value.
+    CoinDecrSolutionOrdered dso1(xstar);
+    remainder.sort(dso1);   
+    
+    // a is the part of krow corresponding to vars which have been lifted
+    // alpha are the lifted coefficients with explicit storage of lifted zero
+    // coefficients the a.getIndices() and alpha.getIndices() are identical
+    CoinPackedVector a(cover);
+    CoinPackedVector alpha;
+    int i;
+    for (i=0; i<cover.getNumElements(); i++){
+      alpha.insert(cover.getIndices()[i],1.0);
+    }
+    // needed as an argument for exactSolveKnapsack
+    int * x = new int[nRowElem]; 
+    double psi_j=0.0;
+    
+    // Order alpha and a in nonincreasing order of alpha_j/a_j.  
+    // alpha_1/a_1 >= alpha_2/a_2 >= ... >= alpha_n/a_n   
+    // by defining this full-storage array "ratio" to be the external sort key.
+    
+    double * ratio= new double[nCols];
+    memset(ratio, 0, (nCols*sizeof(double)));
+
+#ifdef CGL_DEBUG
+    int alphasize =  alpha.getNumElements();
+    int asize = a.getNumElements();
+    assert( alphasize == asize );
+#endif
+    
+    for (i=0; i<a.getNumElements(); i++){
+      if (fabs(a.getElements()[i])> epsilon_ ){
+        ratio[a.getIndices()[i]]=alpha.getElements()[i]/a.getElements()[i];
+      }
+      else {
+        ratio[a.getIndices()[i]] = 0.0;
+      }
+    }
+    
+    // ToDo: would be nice to have sortkey NOT be full-storage vector
+    CoinDecrSolutionOrdered dso2(ratio);
+    // RLH:  JP, Is there a more efficient way?
+    // The sort is identical for a and alpha, but I'm having to sort twice
+    // here, and at every iteration in the loop below.
+    a.sort(dso2);   
+    alpha.sort(dso2);
+    
+#ifdef CGL_DEBUG
+    // sanity check
+    for ( i=1; i<a.getNumElements(); i++ ) {
+      int alphai= alpha.getIndices()[i];
+      int ai = a.getIndices()[i];
+      assert( alphai == ai);
+    }  
+#endif  
+    
+    // Loop through the variables to be lifted, and lift.
+    int j;
+    for (j=0; j<remainder.getNumElements(); j++){
+      // calculate the lifted coefficient of x_j = cutRhs-psi_j
+      // where psi_j =  max of the current lefthand side of the cut
+      // s.t. the knapsack corresponding to vars that have been lifted <= b-a_j
+      
+      // Note: For exact solve, must be sorted in
+      // alpha_1/a_1>=alpha_2/a_2>=...>=alpha_n/a_n order
+      exactSolveKnapsack(alpha.getNumElements(),
+			 b-remainder.getElements()[j],
+			 alpha.getElements(),a.getElements(),psi_j,x);
+      alpha.insert(remainder.getIndices()[j],cutRhs-psi_j);
+      a.insert(remainder.getIndices()[j],remainder.getElements()[j]);
+      // if the lifted coefficient is non-zero (i.e. psi_j != cutRhs), add it
+      // to the cut 
+      if (fabs(cutRhs-psi_j)>epsilon_)
+	 cut.insert(remainder.getIndices()[j],cutRhs-psi_j);
+      
+      ratio[remainder.getIndices()[j]]=
+	 (cutRhs-psi_j)/remainder.getElements()[j];
+      CoinDecrSolutionOrdered dso(ratio);
+      a.sort(dso);   
+      alpha.sort(dso);    
+    }
+    delete [] x;
+    delete [] ratio;
+  }
+
+  // If the cut is violated, add it to the pool
+  // if (sum over cut.getIndices())
+  //    cut.element()*xstar > cover.getNumElements()-1, un-complement
+  // and add it to the pool.
+  double sum=0;
+  int i;
+  for (i=0; i<cut.getNumElements(); i++){
+    sum+= cut.getElements()[i]*xstar[cut.getIndices()[i]];
+  }
+  if (sum > cutRhs+epsilon2_){
+#ifdef PRINT_DEBUG
+    printf("Sequentially lifted cover cut of size %i derived from cover of size %i.\n",cut.getNumElements(), cover.getNumElements());
+    for (i=0; i<cut.getNumElements(); i++){
+      printf("index %i, element %g, xstar value % g \n", cut.getIndices()[i],cut.getElements()[i], xstar[cut.getIndices()[i]]);
+    }
+    printf("The cutRhs = %g, and the alpha_j*xstar_j sum is %g\n\n", cutRhs, sum);
+#endif
+    
+#ifdef GUBCOVER
+  if (numberCliques_) {
+    int n = cut.getNumElements();
+    const int * ind3;
+    const double * els3;
+    ind3 = cut.getIndices();
+    els3 = cut.getElements();
+    const CoinPackedMatrix * matrixByRow = solver_->getMatrixByRow();
+    const double * elementByRow = matrixByRow->getElements();
+    const int * column = matrixByRow->getIndices();
+    const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+    const int * rowLength = matrixByRow->getVectorLengths();
+    int numberColumns = solver_->getNumCols();
+    double * els = elements_;
+    double * els2 = els+numberColumns;
+    for (i=0;i<n;i++) 
+      els[ind3[i]]=els3[i];
+    for (i=rowStart[whichRow_];i<rowStart[whichRow_]+rowLength[whichRow_];i++) {
+      int iColumn = column[i];
+      els2[iColumn]=elementByRow[i];
+    }
+#if CGL_DEBUG
+    bool found=false;
+#endif
+    for (i=0;i<n;i++) {
+      int iColumn = ind3[i];
+      // complement doesn't seem to work?
+      if (!complement_[iColumn]) {
+	if (oneFixStart_[iColumn]>=0) {
+	  for (int j=oneFixStart_[iColumn];j<zeroFixStart_[iColumn];j++) {
+	    int iClique = whichClique_[j];
+	    for (int k=cliqueStart_[iClique];k<cliqueStart_[iClique+1];k++) {
+	      int jColumn = sequenceInCliqueEntry(cliqueEntry_[k]);
+	      if (!els[jColumn]&&els2[jColumn]) {
+		assert (jColumn!=iColumn);
+		if (!complement_[jColumn]&&oneFixesInCliqueEntry(cliqueEntry_[k])) {
+		  //if (els2[iColumn]<0.0||els2[jColumn]<0.0)
+		    //printf("true els %g (c%d) and %g (c%d)\n",
+		    //   els2[iColumn],complement_[iColumn],
+		    //   els2[jColumn],complement_[jColumn]);
+		  if (fabs(els2[jColumn])>=fabs(els2[iColumn])) {
+#if CGL_DEBUG
+		    if (!found) {
+		      found=true;
+		      printf("Good cut can be improved");
+		      for (i=0;i<n;i++) 
+			printf("(%d,%g) ",ind3[i],els3[i]);
+		      printf("<= %g\n",b);
+		    }
+		    printf("can add! %d %d\n",iColumn,jColumn);
+#endif
+		    els[jColumn]=els[iColumn];
+		    cut.insert(jColumn,els[jColumn]);
+		    // recompute as may have changed
+		    ind3 = cut.getIndices();
+		  }
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    // zero out
+    n = cut.getNumElements();
+    ind3 = cut.getIndices();
+    for (i=0;i<n;i++) 
+      els[ind3[i]]=0.0;
+    for (i=rowStart[whichRow_];i<rowStart[whichRow_]+rowLength[whichRow_];i++) {
+      int iColumn = column[i];
+      els2[iColumn]=0.0;
+    }
+  }
+#endif
+    int k;
+    const int s = cut.getNumElements();
+    const int * indices = cut.getIndices();
+    double * elements = cut.getElements();
+    for (k=0; k<s; k++){
+      if (complement[indices[k]]) {
+        // Negate the k'th element in packedVector cut
+        // and correspondingly adjust the rhs
+        elements[k] *= -1;
+        cutRhs += elements[k];
+      }
+    }
+    
+    // Create a row cut and add it to the cut set
+    OsiRowCut rc;
+    rc.setRow(cut);
+#ifdef CGL_DEBUG
+    {
+      double * elements = cut.getElements();
+      int * indices = cut.getIndices();
+      int n=cut.getNumElements();
+      for (k=0; k<n; k++){
+	assert(indices[k]>=0);
+	assert(elements[k]);
+        assert (fabs(elements[k])>1.0e-12);
+      }
+    }
+#endif
+    rc.setLb(-COIN_DBL_MAX);
+    rc.setUb(cutRhs);
+    // ToDo: what's a meaningful effectivity?
+    //  rc.setEffectiveness(1.0);
+#ifdef PRINT_DEBUG
+    {
+      int k;
+      printf("cutrhs %g\n",cutRhs);
+      double * elements = cut.getElements();
+      int * indices = cut.getIndices();
+      for (k=0; k<cut.getNumElements(); k++){
+	printf("%d %g\n",indices[k],elements[k]);
+      }
+    }
+#endif
+    cs.insert(rc);
+  }
+}
+
+//-------------------------------------------------------------------
+// liftCoverCut:  Given a canonical knapsack inequality and a
+//                cover, constructs a lift cover cut via
+//                sequence-independent lifting.
+//
+//                Reference: "Sequence Independent Lifting of Cover 
+//                Inequalities," by Gu, Nemhauser, and Savelsbergh
+//                in Integer Prog. and Combinatorial Opt, 4th Int'l
+//                IPCO Conference Proceedings, Copenhagen, Denmark,
+//                May 1995, pgs 452-461.
+//                
+//-------------------------------------------------------------------
+int
+CglKnapsackCover::liftCoverCut(
+      double & b,
+      int nRowElem,
+      CoinPackedVector & cover,
+      CoinPackedVector & remainder,
+      CoinPackedVector & cut)
+{
+  int i;
+  int  goodCut=1;
+  // Given knapsack ax <=b, and a cover (e.g. cover corresponds to {0,...,nCover-1})
+  // coverIndices are assumed in nondecr order of coverElements   
+  // a_0>=a_1>=...>=a_(nCover-1)   
+
+  // TODO: right now if the lifted coefficient is zero, 
+  // then it's still in the cut. 
+  // Should not carry explicit zero coefficients 
+
+  // Calculate the sum of the knapsack coefficients of the cover variables 
+  double sum = cover.sum();
+
+  // Define lambda to be the "cover excess". 
+  // By definition, lambda > 0. If this is not the case, something's screwy. Exit gracefully.
+  double lambda = sum-b;
+  if (lambda < epsilon_) {
+#ifdef PRINT_DEBUG
+    printf("lambda < epsilon....aborting. \n");
+    std::cout << "lambda " << lambda << " epsilon " << epsilon_ << std::endl;
+    //abort();
+#else
+    //std::cout << "lambda " << lambda << " exiting" << std::endl;
+#endif
+    return 0;
+  }
+
+  // mu is vector of partial sums: 
+  //   mu[i] = sum(j=0 to i) a_j where the cover is C={0,1,..,r}
+  //   mu[0] = 0, mu[1]=a_0, mu[2]=a_0+a_1, etc.
+  //   and C is assumed to be sorted in nondecreasing knapsack coefficient order.
+  double * mu= new double[cover.getNumElements()+1];
+  double * muMinusLambda= new double[cover.getNumElements()+1];
+  memset(mu, 0, (cover.getNumElements()+1)*sizeof(double));
+  memset(muMinusLambda, 0, (cover.getNumElements()+1)*sizeof(double));
+  
+  // mu[0] = 0, mu[1]= knapsack coef of cover element 0, etc.
+  muMinusLambda[0]= -lambda;
+  for(i=1; i<(cover.getNumElements()+1); i++){
+    mu[i]=mu[i-1]+ cover.getElements()[i-1];
+    muMinusLambda[i]=mu[i]-lambda;
+  }
+
+  cut.reserve(nRowElem);
+  // the cut coefficent for the members of the cover is 1.0
+  cut.setConstant(cover.getNumElements(),cover.getIndices(),1.0);
+  
+  // if f(z) is superadditive 
+  int h;
+  if (muMinusLambda[1] >= cover.getElements()[1]-epsilon_){
+    for (h=0; h<remainder.getNumElements(); h++){
+      if (remainder.getElements()[h] <= muMinusLambda[1]+epsilon_){
+        // cutCoef[nCut] is 0, so don't bother storing 
+      }    
+      else{  
+	// Todo: searching is inefficient. sort not in cover... 
+        // change so that I sort remainder before the call to lift.
+        int found=0;
+        i=2;
+        while (!found && i<(cover.getNumElements()+1)){
+          if (remainder.getElements()[h] <= muMinusLambda[i]){
+#ifdef CGL_DEBUG
+	    bool e = cut.isExistingIndex(remainder.getIndices()[h]);
+            assert( !e );
+#endif
+            cut.insert( remainder.getIndices()[h], i-1.0 );
+            found=1;
+          }
+          i++;
+        }
+        if (!found) {
+#ifdef CGL_DEBUG
+          printf("Error: Unable to fix lifted coefficient\n");
+	  abort();
+#else
+	  goodCut=0;
+#endif
+        }
+      } // end else 
+    }// end for each j not in C 
+  } // end if f superadditive 
+
+  // else use superadditive function g 
+  else {
+    int coverSizePlusOne = cover.getNumElements()+1;
+    double * rho= new double[coverSizePlusOne];
+    rho[0]=lambda;
+    rho[cover.getNumElements()]=0.0;
+    for (i=1; i<cover.getNumElements(); i++){
+      rho[i]=CoinMax(0.0, cover.getElements()[i]- muMinusLambda[1]);
+    }
+    
+    int h;
+    for (h=0; h<remainder.getNumElements(); h++){
+      
+      int found=0; // Todo: searcing is inefficient: sort...
+      i=0;
+      while(!found && i<cover.getNumElements()){
+        if (remainder.getElements()[h] <= muMinusLambda[i+1]){
+#ifdef CGL_DEBUG
+	  bool notE = !cut.isExistingIndex(remainder.getIndices()[h]);
+          assert( notE );
+#endif
+	  if (i)
+	    cut.insert( remainder.getIndices()[h], static_cast<double>(i) );
+          found=1;
+        }
+        else if (remainder.getElements()[h] < muMinusLambda[i+1]+rho[i+1]){
+#ifdef CGL_DEBUG
+	  bool notE = !cut.isExistingIndex(remainder.getIndices()[h]); 
+          assert( notE );
+#endif
+          double cutCoef = i+1 
+              - (muMinusLambda[i+1]+rho[i+1]-remainder.getElements()[h])/rho[1];    
+	  if (fabs(cutCoef)>epsilon_)
+	    cut.insert( remainder.getIndices()[h], cutCoef );
+          found=1;
+        }
+        i++;
+      } // endwhile 
+    } // end for j not in C
+    delete [] rho;
+  } // end else use g 
+
+  delete [] muMinusLambda;
+  delete [] mu;
+
+#ifdef GUBCOVER
+  if (goodCut&&numberCliques_) {
+    int n = cut.getNumElements();
+    const int * ind3;
+    const double * els3;
+    ind3 = cut.getIndices();
+    els3 = cut.getElements();
+    const CoinPackedMatrix * matrixByRow = solver_->getMatrixByRow();
+    const double * elementByRow = matrixByRow->getElements();
+    const int * column = matrixByRow->getIndices();
+    const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+    const int * rowLength = matrixByRow->getVectorLengths();
+    int numberColumns = solver_->getNumCols();
+    double * els = elements_;
+    double * els2 = els+numberColumns;
+    for (i=0;i<n;i++) 
+      els[ind3[i]]=els3[i];
+    for (i=rowStart[whichRow_];i<rowStart[whichRow_]+rowLength[whichRow_];i++) {
+      int iColumn = column[i];
+      els2[iColumn]=elementByRow[i];
+    }
+#if CGL_DEBUG
+    bool found=false;
+#endif
+    for (i=0;i<n;i++) {
+      int iColumn = ind3[i];
+      // complement doesn't seem to work?
+      if (!complement_[iColumn]) {
+	if (oneFixStart_[iColumn]>=0) {
+	  for (int j=oneFixStart_[iColumn];j<zeroFixStart_[iColumn];j++) {
+	    int iClique = whichClique_[j];
+	    for (int k=cliqueStart_[iClique];k<cliqueStart_[iClique+1];k++) {
+	      int jColumn = sequenceInCliqueEntry(cliqueEntry_[k]);
+	      if (!els[jColumn]&&els2[jColumn]) {
+		assert (jColumn!=iColumn);
+		if (!complement_[jColumn]&&oneFixesInCliqueEntry(cliqueEntry_[k])) {
+		  //if (els2[iColumn]<0.0||els2[jColumn]<0.0)
+		    //printf("true els %g (c%d) and %g (c%d)\n",
+		    //   els2[iColumn],complement_[iColumn],
+		    //   els2[jColumn],complement_[jColumn]);
+		  if (fabs(els2[jColumn])>=fabs(els2[iColumn])) {
+#if CGL_DEBUG
+		    if (!found) {
+		      found=true;
+		      printf("Good cut can be improved");
+		      for (i=0;i<n;i++) 
+			printf("(%d,%g) ",ind3[i],els3[i]);
+		      printf("<= %g\n",b);
+		    }
+		    printf("can add! %d %d\n",iColumn,jColumn);
+#endif
+		    els[jColumn]=els[iColumn];
+		    cut.insert(jColumn,els[jColumn]);
+		    // recompute as may have changed
+		    ind3 = cut.getIndices();
+		  }
+		} else if (false&&complement_[jColumn]&&!oneFixesInCliqueEntry(cliqueEntry_[k])) {
+		  printf("COMP true els %g (c%d) and %g (c%d)\n",
+			 els2[iColumn],complement_[iColumn],
+			 els2[jColumn],complement_[jColumn]);
+		  printf("Good cut can be ??");
+		  for (i=0;i<n;i++) 
+		    printf("(%d,%g) ",ind3[i],els3[i]);
+		  printf("<= %g\n",b);
+		  printf("can add?? %d %d\n",iColumn,jColumn);
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    // zero out
+    n = cut.getNumElements();
+    ind3 = cut.getIndices();
+    for (i=0;i<n;i++) 
+      els[ind3[i]]=0.0;
+    for (i=rowStart[whichRow_];i<rowStart[whichRow_]+rowLength[whichRow_];i++) {
+      int iColumn = column[i];
+      els2[iColumn]=0.0;
+    }
+  }
+#endif
+  return goodCut;
+}
+
+//-------------------------------------------------------------------
+// A goto-less implementation of the Horowitz-Sahni exact solution 
+// procedure for solving knapsack problem.
+//
+// Reference: Martello and Toth, Knapsack Problems, Wiley, 1990, p30-31.
+//
+// ToDo: Implement a dynamic programming appraoch for case
+//       of knapsacks with integral coefficients
+//-------------------------------------------------------------------
+int
+CglKnapsackCover::exactSolveKnapsack(
+       int n, 
+       double c, 
+       double const *pp, 
+       double const *ww, 
+       double & z, 
+       int * x)
+{
+  // The knapsack problem is to find:
+
+  // max {sum(j=1,n) p_j*x_j st. sum (j=1,n)w_j*x_j <= c, x binary}
+
+  // Notation:
+  //     xhat : current solution vector
+  //     zhat : current solution value = sum (j=1,n) p_j*xhat_j
+  //     chat : current residual capacity = c - sum (j=1,n) w_j*xhat_j
+  //     x    : best solution so far, n-vector.
+  //     z    : value of the best solution so far =  sum (j=1,n) p_j*x_j
+     
+
+  // Input: n, the number of variables; 
+  //        c, the rhs;
+  //        p, n-vector of objective func. coefficients;
+  //        w, n-vector of the row coeff.
+
+  // Output: z, the optimal objective function value;
+  //         x, the optimal (binary) solution n-vector;
+
+  // Assumes items are sorted  p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n
+  
+  memset(x, 0, (n)*sizeof(int));
+  int * xhat = new int[n+1];
+  memset(xhat, 0, (n+1)*sizeof(int));
+  int j;
+
+  // set up: adding the extra element and
+  // accounting for the FORTRAN vs C difference in indexing arrays.
+  double * p = new double[n+2];
+  double * w = new double[n+2];
+  int ii;
+  for (ii=1; ii<n+1; ii++){
+    p[ii]=pp[ii-1];
+    w[ii]=ww[ii-1];
+  }
+
+  // 1. initialize 
+  double zhat = 0.0;
+  z = 0.0;
+  double chat = c+epsilon2_;
+  p[n+1] = 0.0;
+  w[n+1]= COIN_DBL_MAX;
+  j=1;
+
+  while (1){
+    // 2. compute upper bound u
+    // "find r = min {i: sum k=j,i w_k>chat};"
+    ii=j;
+    double wSemiSum = w[j];
+    double pSemiSum = p[j];
+    while (wSemiSum <= chat && ii<n+2){
+      ii++;
+      wSemiSum+=w[ii];
+      pSemiSum+=p[ii];
+    }
+    if (ii==n+2){
+      printf("Exceeded iterator limit. Aborting...\n");
+      abort();
+    }
+    // r = ii at this point 
+    wSemiSum -= w[ii];
+    pSemiSum -= p[ii];
+    double u = pSemiSum + floor((chat - wSemiSum)*p[ii]/w[ii]);
+    
+    // "if (z >= zhat + u) goto 5: backtrack;"
+    if (!(z >= zhat + u)) {
+      do {
+        // 3. perform a forward step 
+        while (w[j] <= chat){
+          chat = chat - w[j];
+          zhat = zhat + p[j];
+          xhat[j] = 1;
+          j+=1;
+        }
+        if (j<=n) {
+          xhat[j]= 0;
+          j+=1;
+        }
+      } while(j==n); 
+
+      // "if (j<n) goto 2: compute_ub;"
+      if (j<n)
+        continue;
+      
+      // 4. up date the best solution so far 
+      if (zhat > z) {
+        z=zhat;
+        int k;
+        for (k=0; k<n; k++){
+          x[k]=xhat[k+1];
+        }
+      }
+      j=n;
+      if (xhat[n] == 1){
+        chat = chat+ w[n];
+        zhat = zhat-p[n];
+        xhat[n]=0;
+      }
+    }
+    // 5. backtrack 
+    // "find i=max{k<j:xhat[k]=1};"
+    int i=j-1; 
+    while (!(xhat[i]==1) && i>0){
+      i--;
+    }
+    
+    // "if (no such i exists) return;"
+    if (i==0){
+      delete [] p;
+      delete [] w;
+      delete [] xhat;
+      return 1;
+    }
+    
+    chat = chat + w[i];
+    zhat=zhat -p[i];
+    xhat[i]=0;
+    j=i+1;
+    // "goto 2: compute_ub;"
+  }
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglKnapsackCover::CglKnapsackCover ()
+:
+CglCutGenerator(),
+epsilon_(1.0e-07),
+epsilon2_(1.0e-5),
+onetol_(1-epsilon_),
+maxInKnapsack_(50),
+numRowsToCheck_(-1),
+rowsToCheck_(0),
+expensiveCuts_(false)
+{
+  numberCliques_=0;
+  numberColumns_=0;
+  cliqueType_=NULL;
+  cliqueStart_=NULL;
+  cliqueEntry_=NULL;
+  oneFixStart_=NULL;
+  zeroFixStart_=NULL;
+  endFixStart_=NULL;
+  whichClique_=NULL;
+  canDoGlobalCuts_=true;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglKnapsackCover::CglKnapsackCover (const CglKnapsackCover & source) :
+   CglCutGenerator(source),
+   epsilon_(source.epsilon_),
+   epsilon2_(source.epsilon2_),
+   onetol_(source.onetol_),
+   maxInKnapsack_(source.maxInKnapsack_),
+   numRowsToCheck_(source.numRowsToCheck_),
+   rowsToCheck_(0),
+   expensiveCuts_(source.expensiveCuts_)
+{
+   if (numRowsToCheck_ > 0) {
+      rowsToCheck_ = new int[numRowsToCheck_];
+      CoinCopyN(source.rowsToCheck_, numRowsToCheck_, rowsToCheck_);
+   }
+  numberCliques_=source.numberCliques_;
+  numberColumns_=source.numberColumns_;
+  if (numberCliques_) {
+    cliqueType_ = new cliqueType [numberCliques_];
+    CoinMemcpyN(source.cliqueType_,numberCliques_,cliqueType_);
+    cliqueStart_ = new int [numberCliques_+1];
+    CoinMemcpyN(source.cliqueStart_,(numberCliques_+1),cliqueStart_);
+    int n = cliqueStart_[numberCliques_];
+    cliqueEntry_ = new cliqueEntry [n];
+    CoinMemcpyN(source.cliqueEntry_,n,cliqueEntry_);
+    oneFixStart_ = new int [numberColumns_];
+    CoinMemcpyN(source.oneFixStart_,numberColumns_,oneFixStart_);
+    zeroFixStart_ = new int [numberColumns_];
+    CoinMemcpyN(source.zeroFixStart_,numberColumns_,zeroFixStart_);
+    endFixStart_ = new int [numberColumns_];
+    CoinMemcpyN(source.endFixStart_,numberColumns_,endFixStart_);
+#ifndef NDEBUG
+    int n2=-1;
+    for (int i=numberColumns_-1;i>=0;i--) {
+      if (oneFixStart_[i]>=0) {
+	n2=endFixStart_[i];
+	break;
+      }
+    }
+    assert (n==n2);
+#endif
+    whichClique_ = new int [n];
+    CoinMemcpyN(source.whichClique_,n,whichClique_);
+  } else {
+    cliqueType_=NULL;
+    cliqueStart_=NULL;
+    cliqueEntry_=NULL;
+    oneFixStart_=NULL;
+    zeroFixStart_=NULL;
+    endFixStart_=NULL;
+    whichClique_=NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglKnapsackCover::clone() const
+{
+  return new CglKnapsackCover(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglKnapsackCover::~CglKnapsackCover ()
+{
+   delete[] rowsToCheck_;
+   deleteCliques();
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglKnapsackCover &
+CglKnapsackCover::operator=(const CglKnapsackCover& rhs)
+{
+   if (this != &rhs) {
+      CglCutGenerator::operator=(rhs);
+      epsilon_=rhs.epsilon_;
+      epsilon2_=rhs.epsilon2_;
+      onetol_=rhs.onetol_;
+      maxInKnapsack_=rhs.maxInKnapsack_;
+      delete[] rowsToCheck_;
+      numRowsToCheck_ = rhs.numRowsToCheck_;
+      if (numRowsToCheck_ > 0) {
+	 rowsToCheck_ = new int[numRowsToCheck_];
+	 CoinCopyN(rhs.rowsToCheck_, numRowsToCheck_, rowsToCheck_);
+      } else {
+	 rowsToCheck_ = 0;
+      }
+      expensiveCuts_ = rhs.expensiveCuts_;
+      deleteCliques();
+      numberCliques_=rhs.numberCliques_;
+      numberColumns_=rhs.numberColumns_;
+      if (numberCliques_) {
+	cliqueType_ = new cliqueType [numberCliques_];
+	CoinMemcpyN(rhs.cliqueType_,numberCliques_,cliqueType_);
+	cliqueStart_ = new int [numberCliques_+1];
+	CoinMemcpyN(rhs.cliqueStart_,(numberCliques_+1),cliqueStart_);
+	int n = cliqueStart_[numberCliques_];
+	cliqueEntry_ = new cliqueEntry [n];
+	CoinMemcpyN(rhs.cliqueEntry_,n,cliqueEntry_);
+	oneFixStart_ = new int [numberColumns_];
+	CoinMemcpyN(rhs.oneFixStart_,numberColumns_,oneFixStart_);
+	zeroFixStart_ = new int [numberColumns_];
+	CoinMemcpyN(rhs.zeroFixStart_,numberColumns_,zeroFixStart_);
+	endFixStart_ = new int [numberColumns_];
+	CoinMemcpyN(rhs.endFixStart_,numberColumns_,endFixStart_);
+#ifndef NDEBUG
+	int n2=-1;
+	for (int i=numberColumns_-1;i>=0;i--) {
+	  if (oneFixStart_[i]>=0) {
+	    n2=endFixStart_[i];
+	    break;
+	  }
+	}
+	assert (n==n2);
+#endif
+	whichClique_ = new int [n];
+	CoinMemcpyN(rhs.whichClique_,n,whichClique_);
+      }
+   }
+   return *this;
+}
+// Create C++ lines to get to current state
+std::string
+CglKnapsackCover::generateCpp( FILE * fp) 
+{
+  CglKnapsackCover other;
+  fprintf(fp,"0#include \"CglKnapsackCover.hpp\"\n");
+  fprintf(fp,"3  CglKnapsackCover knapsackCover;\n");
+  if (maxInKnapsack_!=other.maxInKnapsack_)
+    fprintf(fp,"3  knapsackCover.setMaxInKnapsack(%d);\n",maxInKnapsack_);
+  else
+    fprintf(fp,"4  knapsackCover.setMaxInKnapsack(%d);\n",maxInKnapsack_);
+  if (expensiveCuts_ != other.expensiveCuts_) {
+    if (expensiveCuts_)	
+      fprintf(fp,"3  knapsackCover.switchOnExpensive();\n");
+    else
+      fprintf(fp,"3  knapsackCover.switchOffExpensive();\n");
+  } else {
+    if (expensiveCuts_)	
+      fprintf(fp,"4  knapsackCover.switchOnExpensive();\n");
+    else
+      fprintf(fp,"4  knapsackCover.switchOffExpensive();\n");
+  }
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  knapsackCover.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  knapsackCover.setAggressiveness(%d);\n",getAggressiveness());
+  return "knapsackCover";
+}
+// This can be used to refresh any information
+void 
+CglKnapsackCover::refreshSolver(OsiSolverInterface * solver)
+{
+#ifdef GUBCOVER
+  deleteCliques();
+  if (solver->getMatrixByCol())
+    createCliques( *solver,2,200,false);
+#endif
+}
+/* Creates cliques for use by probing.
+   Can also try and extend cliques as a result of probing (root node).
+   Returns number of cliques found.
+*/
+int 
+CglKnapsackCover::createCliques( OsiSolverInterface & si, 
+			  int minimumSize, int maximumSize, 
+				 bool /*extendCliques*/)
+{
+  // Should be 0 unless you're debugging!
+  const int logLevel = 0 ;
+  // get rid of what is there
+  deleteCliques();
+  CoinPackedMatrix matrixByRow(*si.getMatrixByRow());
+  int numberRows = si.getNumRows();
+  numberColumns_ = si.getNumCols();
+
+  numberCliques_=0;
+  int numberEntries=0;
+  int numberIntegers=0;
+  int * lookup = new int[numberColumns_];
+  int i;
+  for (i=0;i<numberColumns_;i++) {
+    if (si.isBinary(i))
+      lookup[i]=numberIntegers++;
+    else
+      lookup[i]=-1;
+  }
+
+  int * which = new int[numberColumns_];
+  int * whichRow = new int[numberRows];
+  // Statistics
+  int totalP1=0,totalM1=0;
+  int numberBig=0,totalBig=0;
+  int numberFixed=0;
+
+  // Row copy
+  const double * elementByRow = matrixByRow.getElements();
+  const int * column = matrixByRow.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  const int * rowLength = matrixByRow.getVectorLengths();
+
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+  const double * rowLower = si.getRowLower();
+  const double * rowUpper = si.getRowUpper();
+  int iRow;
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int numberP1=0, numberM1=0;
+    int j;
+    double upperValue=rowUpper[iRow];
+    double lowerValue=rowLower[iRow];
+    bool good=true;
+    for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+      int iColumn = column[j];
+      int iInteger=lookup[iColumn];
+      if (upper[iColumn]-lower[iColumn]<1.0e-8) {
+	// fixed
+	upperValue -= lower[iColumn]*elementByRow[j];
+	lowerValue -= lower[iColumn]*elementByRow[j];
+	continue;
+      } else if (upper[iColumn]!=1.0||lower[iColumn]!=0.0) {
+	good = false;
+	break;
+      } else if (iInteger<0) {
+	good = false;
+	break;
+      }
+      if (fabs(elementByRow[j])!=1.0) {
+	good=false;
+	break;
+      } else if (elementByRow[j]>0.0) {
+	which[numberP1++]=iColumn;
+      } else {
+	numberM1++;
+	which[numberIntegers-numberM1]=iColumn;
+      }
+    }
+    int iUpper = static_cast<int> (floor(upperValue+1.0e-5));
+    int iLower = static_cast<int> (ceil(lowerValue-1.0e-5));
+    int state=0;
+    if (upperValue<1.0e6) {
+      if (iUpper==1-numberM1)
+	state=1;
+      else if (iUpper==-numberM1)
+	state=2;
+      else if (iUpper<-numberM1)
+	state=3;
+    }
+    if (!state&&lowerValue>-1.0e6) {
+      if (-iLower==1-numberP1)
+	state=-1;
+      else if (-iLower==-numberP1)
+	state=-2;
+      else if (-iLower<-numberP1)
+	state=-3;
+    }
+    if (good&&state) {
+      if (abs(state)==3) {
+	// infeasible
+	numberCliques_ = -99999;
+	break;
+      } else if (abs(state)==2) {
+	// we can fix all
+	numberFixed += numberP1+numberM1;
+	if (state>0) {
+	  // fix all +1 at 0, -1 at 1
+	  for (i=0;i<numberP1;i++)
+	    si.setColUpper(which[i],0.0);
+	  for (i=0;i<numberM1;i++)
+	    si.setColLower(which[numberIntegers-i-1],
+				 1.0);
+	} else {
+	  // fix all +1 at 1, -1 at 0
+	  for (i=0;i<numberP1;i++)
+	    si.setColLower(which[i],1.0);
+	  for (i=0;i<numberM1;i++)
+	    si.setColUpper(which[numberIntegers-i-1],
+				 0.0);
+	}
+      } else {
+	int length = numberP1+numberM1;
+	// temp
+	if (numberM1) {
+	  if (logLevel>1)
+	    printf("bad clique %d +1, %d -1\n",
+		   numberP1,numberM1);
+	  length=0;
+	}
+        totalP1 += numberP1;
+        totalM1 += numberM1;
+	if (length >= minimumSize&&length<maximumSize) {
+	  whichRow[numberCliques_++]=iRow;
+	  numberEntries += length;
+	} else if (length >= maximumSize) {
+	  // too big
+	  numberBig++;
+	  totalBig += length;
+	}
+      }
+    }
+  }
+  if (logLevel > 0) {
+    if (numberCliques_<0) {
+	printf("*** Problem infeasible\n");
+    } else {
+      if (numberCliques_) {
+	if (logLevel>1)
+	  printf("%d cliques of average size %g found, %d P1, %d M1\n",
+		 numberCliques_,
+		 (static_cast<double>(totalP1+totalM1))/
+		 (static_cast<double> (numberCliques_)),
+		 totalP1,totalM1);
+      } else {
+	if (logLevel>1)
+	  printf("No cliques found\n");
+      }
+      if (numberBig) {
+	if (logLevel>1)
+	  printf("%d large cliques ( >= %d) found, total %d\n",
+	       numberBig,maximumSize,totalBig);
+      }
+      if (numberFixed) {
+	  printf("%d variables fixed\n",numberFixed);
+      }
+    }
+  }
+  if (numberCliques_>0) {
+    cliqueType_ = new cliqueType [numberCliques_];
+    cliqueStart_ = new int [numberCliques_+1];
+    cliqueEntry_ = new cliqueEntry [numberEntries];
+    oneFixStart_ = new int [numberColumns_];
+    zeroFixStart_ = new int [numberColumns_];
+    endFixStart_ = new int [numberColumns_];
+    whichClique_ = new int [numberEntries];
+    numberEntries=0;
+    cliqueStart_[0]=0;
+    for (i=0;i<numberColumns_;i++) {
+      oneFixStart_[i]=-1;
+      zeroFixStart_[i]=-1;
+      endFixStart_[i]=-1;
+    }
+    int iClique;
+    // Possible some have been fixed
+    int numberCliques=numberCliques_;
+    numberCliques_=0;
+    for (iClique=0;iClique<numberCliques;iClique++) {
+      int iRow=whichRow[iClique];
+      whichRow[numberCliques_]=iRow;
+      int numberP1=0, numberM1=0;
+      int j;
+      double upperValue=rowUpper[iRow];
+      double lowerValue=rowLower[iRow];
+      for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	int iColumn = column[j];
+	if (upper[iColumn]-lower[iColumn]<1.0e-8) {
+	  // fixed
+	  upperValue -= lower[iColumn]*elementByRow[j];
+	  lowerValue -= lower[iColumn]*elementByRow[j];
+	  continue;
+	}
+	if (elementByRow[j]>0.0) {
+	  which[numberP1++]=iColumn;
+	} else {
+	  numberM1++;
+	  which[numberIntegers-numberM1]=iColumn;
+	}
+      }
+      int iUpper = static_cast<int> (floor(upperValue+1.0e-5));
+      int iLower = static_cast<int> (ceil(lowerValue-1.0e-5));
+      int state=0;
+      if (upperValue<1.0e6) {
+	if (iUpper==1-numberM1)
+	  state=1;
+      }
+      if (!state&&lowerValue>-1.0e6) {
+	state=-1;
+      }
+      if (abs(state)!=1)
+	continue; // must have been fixed
+      if (iLower==iUpper) {
+	cliqueType_[numberCliques_].equality=1;
+      } else {
+	cliqueType_[numberCliques_].equality=0;
+      }
+      if (state>0) {
+	for (i=0;i<numberP1;i++) {
+	  // 1 is strong branch
+	  int iColumn = which[i];
+	  setSequenceInCliqueEntry(cliqueEntry_[numberEntries],iColumn);
+	  setOneFixesInCliqueEntry(cliqueEntry_[numberEntries],true);
+	  numberEntries++;
+	  // zero counts
+	  oneFixStart_[iColumn]=0;
+	  zeroFixStart_[iColumn]=0;
+	}
+	for (i=0;i<numberM1;i++) {
+	  // 0 is strong branch
+	  int iColumn = which[numberIntegers-i-1];
+	  setSequenceInCliqueEntry(cliqueEntry_[numberEntries],iColumn);
+	  setOneFixesInCliqueEntry(cliqueEntry_[numberEntries],false);
+	  numberEntries++;
+	  // zero counts
+	  oneFixStart_[iColumn]=0;
+	  zeroFixStart_[iColumn]=0;
+	}
+      } else {
+	for (i=0;i<numberP1;i++) {
+	  // 0 is strong branch
+	  int iColumn = which[i];
+	  setSequenceInCliqueEntry(cliqueEntry_[numberEntries],iColumn);
+	  setOneFixesInCliqueEntry(cliqueEntry_[numberEntries],false);
+	  numberEntries++;
+	  // zero counts
+	  oneFixStart_[iColumn]=0;
+	  zeroFixStart_[iColumn]=0;
+	}
+	for (i=0;i<numberM1;i++) {
+	  // 1 is strong branch
+	  int iColumn = which[numberIntegers-i-1];
+	  setSequenceInCliqueEntry(cliqueEntry_[numberEntries],iColumn);
+	  setOneFixesInCliqueEntry(cliqueEntry_[numberEntries],true);
+	  numberEntries++;
+	  // zero counts
+	  oneFixStart_[iColumn]=0;
+	  zeroFixStart_[iColumn]=0;
+	}
+      }
+      numberCliques_++;
+      cliqueStart_[numberCliques_]=numberEntries;
+    }
+    // Now do column lists
+    // First do counts
+    for (iClique=0;iClique<numberCliques_;iClique++) {
+      for (int j=cliqueStart_[iClique];j<cliqueStart_[iClique+1];j++) {
+	int iColumn = sequenceInCliqueEntry(cliqueEntry_[j]);
+	if (oneFixesInCliqueEntry(cliqueEntry_[j]))
+	  oneFixStart_[iColumn]++;
+	else
+	  zeroFixStart_[iColumn]++;
+      }
+    }
+    // now get starts and use which and end as counters
+    numberEntries=0;
+    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+      if (oneFixStart_[iColumn]>=0) {
+	int n1=oneFixStart_[iColumn];
+	int n2=zeroFixStart_[iColumn];
+	oneFixStart_[iColumn]=numberEntries;
+	which[iColumn]=numberEntries;
+	numberEntries += n1;
+	zeroFixStart_[iColumn]=numberEntries;
+	endFixStart_[iColumn]=numberEntries;
+	numberEntries += n2;
+      }
+    }
+    // now put in
+    for (iClique=0;iClique<numberCliques_;iClique++) {
+      for (int j=cliqueStart_[iClique];j<cliqueStart_[iClique+1];j++) {
+	int iColumn = sequenceInCliqueEntry(cliqueEntry_[j]);
+	if (oneFixesInCliqueEntry(cliqueEntry_[j])) {
+	  int put = which[iColumn];
+	  which[iColumn]++;
+	  whichClique_[put]=iClique;
+	} else {
+	  int put = endFixStart_[iColumn];
+	  endFixStart_[iColumn]++;
+	  whichClique_[put]=iClique;
+	}
+      }
+    }
+  }
+  delete [] which;
+  delete [] whichRow;
+  delete [] lookup;
+  return numberCliques_;
+}
+// Delete all clique information
+void 
+CglKnapsackCover::deleteCliques()
+{
+  delete [] cliqueType_;
+  delete [] cliqueStart_;
+  delete [] cliqueEntry_;
+  delete [] oneFixStart_;
+  delete [] zeroFixStart_;
+  delete [] endFixStart_;
+  delete [] whichClique_;
+  cliqueType_=NULL;
+  cliqueStart_=NULL;
+  cliqueEntry_=NULL;
+  oneFixStart_=NULL;
+  zeroFixStart_=NULL;
+  endFixStart_=NULL;
+  whichClique_=NULL;
+  numberCliques_=0;
+}
diff --git a/cbits/coin/CglKnapsackCover.hpp b/cbits/coin/CglKnapsackCover.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglKnapsackCover.hpp
@@ -0,0 +1,307 @@
+// $Id: CglKnapsackCover.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglKnapsackCover_H
+#define CglKnapsackCover_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+#include "CglTreeInfo.hpp"
+
+/** Knapsack Cover Cut Generator Class */
+class CglKnapsackCover : public CglCutGenerator {
+   friend void CglKnapsackCoverUnitTest(const OsiSolverInterface * siP,
+					const std::string mpdDir );
+
+public:
+   /** A method to set which rows should be tested for knapsack covers */
+   void setTestedRowIndices(int num, const int* ind);
+
+   /**@name Generate Cuts */
+  //@{
+  /** Generate knapsack cover cuts for the model of the solver interface, si. 
+      Insert the generated cuts into OsiCut, cs.
+  */
+  virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			    const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglKnapsackCover ();
+ 
+  /// Copy constructor 
+  CglKnapsackCover (
+    const CglKnapsackCover &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglKnapsackCover &
+    operator=(
+    const CglKnapsackCover& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglKnapsackCover ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  /// This can be used to refresh any information
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  //@}
+
+
+  /**@name Sets and gets */
+  //@{
+  /// Set limit on number in knapsack
+  inline void setMaxInKnapsack(int value)
+           { if (value>0) maxInKnapsack_ = value;}
+  /// get limit on number in knapsack
+  inline int getMaxInKnapsack() const
+           {return maxInKnapsack_;}
+  /// Switch off expensive cuts
+  inline void switchOffExpensive()
+  { expensiveCuts_=false;}
+  /// Switch on expensive cuts
+  inline void switchOnExpensive()
+  { expensiveCuts_=true;}
+private:
+  
+ // Private member methods
+
+
+  /**@name Private methods */
+  //@{
+
+  /** deriveAKnapsack 
+                 returns 1 if it is able to derive
+                 a (canonical) knapsack inequality
+                in binary variables of the form ax<=b 
+                 from the rowIndex-th  row in the model, 
+                returns 0 otherwise.
+  */
+  int deriveAKnapsack(
+    const OsiSolverInterface & si, 
+    OsiCuts & cs,
+    CoinPackedVector & krow,
+    bool treatAsLRow,
+    double & b,
+    int *  complement,
+    double *  xstar,
+    int rowIndex,
+    int numberElements,
+    const int * index,
+    const double * element);
+
+  int deriveAKnapsack(
+    const OsiSolverInterface & si, 
+    OsiCuts & cs,
+    CoinPackedVector & krow,
+    double & b,
+    int *  complement,
+    double *  xstar,
+    int rowIndex,
+    const CoinPackedVectorBase & matrixRow);
+
+  /** Find a violated minimal cover from 
+ a canonical form knapsack inequality by
+ solving the -most- violated cover problem
+ and postprocess to ensure minimality
+  */
+  int findExactMostViolatedMinCover(
+      int nCols, 
+      int row,
+      CoinPackedVector & krow,
+      double b, 
+      double *  xstar, 
+      CoinPackedVector & cover,
+      CoinPackedVector & remainder);
+
+  /** Find the most violate minimum cover by solving the lp-relaxation of the
+      most-violate-min-cover problem 
+  */
+  int findLPMostViolatedMinCover(
+      int nCols,
+      int row,
+      CoinPackedVector & krow,
+      double & b,
+      double * xstar, 
+      CoinPackedVector & cover,
+      CoinPackedVector & remainder);
+  
+/// find a minimum cover by a simple greedy approach
+  int findGreedyCover(
+      int row,
+      CoinPackedVector & krow,
+      double & b,
+      double * xstar,
+      CoinPackedVector & cover,
+      CoinPackedVector & remainder
+      );
+
+  /// lift the cover inequality
+  int liftCoverCut(
+     double & b,
+     int nRowElem,
+     CoinPackedVector & cover,
+     CoinPackedVector & remainder,
+     CoinPackedVector & cut );
+ 
+  /// sequence-independent lift and uncomplement and add the resulting cut to the cut set
+  int liftAndUncomplementAndAdd(
+     double rowub,
+     CoinPackedVector & krow,
+     double & b,
+     int * complement,
+     int row,
+     CoinPackedVector & cover,
+     CoinPackedVector & remainder,
+     OsiCuts & cs );
+
+  /// sequence-dependent lift, uncomplement and add the resulting cut to the cut set
+void seqLiftAndUncomplementAndAdd(
+      int nCols,
+      double * xstar, 
+      int * complement,
+      int row,
+      int nRowElem,
+      double & b,
+      CoinPackedVector & cover,      // need not be violated
+      CoinPackedVector & remainder,
+      OsiCuts & cs );
+
+  /// sequence-dependent lift binary variables either up or down, uncomplement and add to the cut set
+void liftUpDownAndUncomplementAndAdd(
+         int nCols,
+         double * xstar, 
+         int * complement,
+         int row,
+         int nRowElem,
+         double & b,
+
+         // the following 3 packed vectors partition the krow:
+         CoinPackedVector & fracCover, // vars have frac soln values in lp relaxation
+                                       // and form cover with the vars atOne
+         CoinPackedVector & atOne,     // vars have soln value of 1 in lp relaxation
+                                       // and together with fracCover form minimal (?) cover. 
+         CoinPackedVector & remainder,
+         OsiCuts & cs );
+
+  /// find a cover using a variation of the logic found in OSL (w/o SOS)
+  int findPseudoJohnAndEllisCover (
+     int row,
+     CoinPackedVector & krow,
+     double & b,
+     double * xstar,                     
+     CoinPackedVector & cover,  
+     CoinPackedVector & remainder);
+
+  /// find a cover using the basic logic found in OSL (w/o SOS)
+  int findJohnAndEllisCover (
+     int row,
+     CoinPackedVector & krow,
+     double & b,
+     double * xstar,                     
+     CoinPackedVector & fracCover,  
+     CoinPackedVector & atOnes,  
+     CoinPackedVector & remainder);
+
+
+  /** A C-style implementation of the Horowitz-Sahni exact solution 
+   procedure for solving knapsack problem. 
+   
+   (ToDo: implement the more efficient dynamic programming approach)
+
+   (Reference: Martello and Toth, Knapsack Problems, Wiley, 1990, p30.)
+  */
+  int exactSolveKnapsack(
+      int n, 
+      double c, 
+      double const *pp, 
+      double const *ww,
+      double & z, 
+      int * x);
+
+  /** Creates cliques for use by probing.
+      Only cliques >= minimumSize and < maximumSize created
+      Can also try and extend cliques as a result of probing (root node).
+      Returns number of cliques found.
+  */
+  int createCliques( OsiSolverInterface & si, 
+		    int minimumSize=2, int maximumSize=100, bool extendCliques=false);
+  /// Delete all clique information
+  void deleteCliques();
+  //@}
+
+  // Private member data
+
+  /**@name Private member data */
+  //@{
+  /// epsilon
+  double epsilon_;  
+  /// Tolerance to use for violation - bigger than epsilon_
+  double epsilon2_;
+  /// 1-epsilon
+  double onetol_;  
+  /// Maximum in knapsack
+  int maxInKnapsack_;
+  /** which rows to look at. If specified, only these rows will be considered
+      for generating knapsack covers. Otherwise all rows will be tried */
+  int numRowsToCheck_;
+  int* rowsToCheck_;
+  /// exactKnapsack can be expensive - this switches off some
+  bool expensiveCuts_;
+  /// Cliques
+  /// **** TEMP so can reference from listing
+  const OsiSolverInterface * solver_;
+  int whichRow_;
+  int * complement_;
+  double * elements_;
+  /// Number of cliques
+  int numberCliques_;
+  /// Clique type
+  typedef struct {
+    unsigned int equality:1; //  nonzero if clique is ==
+  } cliqueType;
+  cliqueType * cliqueType_;
+  /// Start of each clique
+  int * cliqueStart_;
+  /// Entries for clique
+  cliqueEntry * cliqueEntry_;
+  /** Start of oneFixes cliques for a column in matrix or -1 if not
+      in any clique */
+  int * oneFixStart_;
+  /** Start of zeroFixes cliques for a column in matrix or -1 if not
+      in any clique */
+  int * zeroFixStart_;
+  /// End of fixes for a column
+  int * endFixStart_;
+  /// Clique numbers for one or zero fixes
+  int * whichClique_;
+  /// Number of columns
+  int numberColumns_;
+  /** For each column with nonzero in row copy this gives a clique "number".
+      So first clique mentioned in row is always 0.  If no entries for row
+      then no cliques.  If sequence > numberColumns then not in clique.
+  */
+  //cliqueEntry * cliqueRow_;
+  /// cliqueRow_ starts for each row
+  //int * cliqueRowStart_;
+  //@}
+};
+
+//#############################################################################
+/** A function that tests the methods in the CglKnapsackCover class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglKnapsackCoverUnitTest(const OsiSolverInterface * siP,
+			      const std::string mpdDir );
+  
+#endif
diff --git a/cbits/coin/CglLandP.cpp b/cbits/coin/CglLandP.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandP.cpp
@@ -0,0 +1,771 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     07/21/05
+//
+// $Id: CglLandP.cpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+#include "CglLandP.hpp"
+#include "CglLandPSimplex.hpp"
+
+#define INT_INFEAS(value) fabs(value - floor(value+0.5))
+
+#include "CglConfig.h"
+
+#ifdef COIN_HAS_OSICLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+
+#define CLONE_SI //Solver is cloned between two cuts
+
+#include "CoinTime.hpp"
+#include "CglGomory.hpp"
+#include "CoinFactorization.hpp"
+#include <fstream>
+namespace LAP
+{
+//Setup output messages
+LapMessages::LapMessages( )
+        :CoinMessages(LAP_MESSAGES_DUMMY_END)
+{
+    strcpy(source_,"Lap");
+    addMessage(BEGIN_ROUND,CoinOneMessage( 1, 2,"Starting %s round %d variable considered for separation."));
+    addMessage(END_ROUND,CoinOneMessage(2, 2,"End ouf %s round %d cut generated in %g seconds."));
+    addMessage(DURING_SEP,CoinOneMessage(3,1,"After %g seconds, separated %d cuts."));
+    addMessage(CUT_REJECTED, CoinOneMessage(4,1,"Cut rejected for %s."));
+    addMessage(CUT_FAILED,CoinOneMessage(5,1,"Generation failed."));
+    addMessage(CUT_GAP, CoinOneMessage(7,1,"CUTGAP after %i pass objective is %g"));
+    addMessage(LAP_CUT_FAILED_DO_MIG, CoinOneMessage(3006,1,"Failed to generate a cut generate a Gomory cut instead"));
+}
+}
+using namespace LAP;
+CglLandP::Parameters::Parameters():
+        CglParam(),
+        pivotLimit(20),
+        pivotLimitInTree(10),
+        maxCutPerRound(5000),
+        failedPivotLimit(1),
+        degeneratePivotLimit(0),
+        extraCutsLimit(5),
+        pivotTol(1e-4),
+        away(5e-4),
+        timeLimit(COIN_DBL_MAX),
+        singleCutTimeLimit(COIN_DBL_MAX),
+        rhsWeight(1.),
+        useTableauRow(true),
+        modularize(false),
+        strengthen(true),
+        countMistakenRc(false),
+        sepSpace(Fractional),
+        perturb(true),
+        normalization(Unweighted),
+        rhsWeightType(Fixed),
+        lhs_norm(L1),
+        generateExtraCuts(none),
+        pivotSelection(mostNegativeRc)
+{
+    EPS = 1e-08;
+}
+
+CglLandP::Parameters::Parameters(const Parameters &other):
+        CglParam(other),
+        pivotLimit(other.pivotLimit),
+        pivotLimitInTree(other.pivotLimitInTree),
+        maxCutPerRound(other.maxCutPerRound),
+        failedPivotLimit(other.failedPivotLimit),
+        degeneratePivotLimit(other.degeneratePivotLimit),
+        extraCutsLimit(other.extraCutsLimit),
+        pivotTol(other.pivotTol),
+        away(other.away),
+        timeLimit(other.timeLimit),
+        singleCutTimeLimit(other.singleCutTimeLimit),
+        rhsWeight(other.rhsWeight),
+        useTableauRow(other.useTableauRow),
+        modularize(other.modularize),
+        strengthen(other.strengthen),
+        countMistakenRc(other.countMistakenRc),
+        sepSpace(other.sepSpace),
+        perturb(other.perturb),
+        normalization(other.normalization),
+        rhsWeightType(other.rhsWeightType),
+        lhs_norm(other.lhs_norm),
+        generateExtraCuts(other.generateExtraCuts),
+        pivotSelection(other.pivotSelection)
+{}
+
+CglLandP::Parameters & CglLandP::Parameters::operator=(const Parameters &other)
+{
+    if (this != &other)
+    {
+        CglParam::operator=(other);
+        pivotLimit = other.pivotLimit;
+        pivotLimitInTree = other.pivotLimitInTree;
+        maxCutPerRound = other.maxCutPerRound;
+        failedPivotLimit = other.failedPivotLimit;
+        degeneratePivotLimit = other.failedPivotLimit;
+        extraCutsLimit = other.extraCutsLimit;
+        pivotTol = other.pivotTol;
+        away = other.away;
+        timeLimit = other.timeLimit;
+        singleCutTimeLimit = other.singleCutTimeLimit;
+        rhsWeight = other.rhsWeight;
+        useTableauRow = other.useTableauRow;
+        modularize = other.modularize;
+        strengthen = other.strengthen;
+        countMistakenRc = other.countMistakenRc;
+        sepSpace = other.sepSpace;
+        perturb = other.perturb;
+        normalization = other.normalization;
+        rhsWeightType = other.rhsWeightType;
+        lhs_norm = other.lhs_norm;
+        generateExtraCuts = other.generateExtraCuts;
+        pivotSelection = other.pivotSelection;
+    }
+    return *this;
+}
+
+CglLandP::CachedData::CachedData(int nBasics, int nNonBasics):
+        basics_(NULL), nonBasics_(NULL), nBasics_(nBasics),
+        nNonBasics_(nNonBasics), basis_(NULL), colsol_(NULL),
+        slacks_(NULL), integers_(NULL), solver_(NULL)
+{
+    if (nBasics_>0)
+    {
+        basics_ = new int[nBasics_];
+        integers_ = new bool [nNonBasics_ + nBasics_];
+    }
+    if (nNonBasics_>0)
+        nonBasics_ = new int[nNonBasics_];
+    if (nBasics_ + nNonBasics_ > 0)
+    {
+        colsol_ = new double[nBasics_ + nNonBasics_];
+        slacks_ = &colsol_[nNonBasics_];
+    }
+}
+
+CglLandP::CachedData::CachedData(const CachedData &source):
+        basics_(NULL), nonBasics_(NULL), nBasics_(source.nBasics_),
+        nNonBasics_(source.nNonBasics_), basis_(NULL),
+        colsol_(NULL), slacks_(NULL), integers_(NULL), solver_(NULL)
+{
+    if (nBasics_>0)
+    {
+        basics_ = new int[nBasics_];
+        CoinCopyN(source.basics_, nBasics_, basics_);
+        integers_ = new bool [nNonBasics_ + nBasics_];
+        CoinCopyN(source.integers_, nBasics_ + nNonBasics_, integers_);
+    }
+    if (nNonBasics_>0)
+    {
+        nonBasics_ = new int[nNonBasics_];
+        CoinCopyN(source.nonBasics_, nBasics_, nonBasics_);
+    }
+    if (nBasics_ + nNonBasics_ > 0)
+    {
+        colsol_ = new double[nBasics_ + nNonBasics_];
+        slacks_ = &colsol_[nNonBasics_];
+        CoinCopyN(source.colsol_, nBasics_ + nNonBasics_, colsol_);
+    }
+    if (source.basis_!=NULL)
+        basis_ = new CoinWarmStartBasis(*source.basis_);
+    if (source.solver_!=NULL)
+      solver_ = source.solver_->clone();
+}
+
+CglLandP::CachedData& CglLandP::CachedData::operator=(const CachedData &source)
+{
+    if (this != &source)
+    {
+        nBasics_ = source.nBasics_;
+        nNonBasics_ = source.nNonBasics_;
+        if (basics_ == NULL) delete [] basics_;
+        basics_ = NULL;
+        if (nonBasics_ == NULL) delete [] nonBasics_;
+        nonBasics_ = NULL;
+        if (basis_ == NULL) delete [] basis_;
+        basis_ = NULL;
+        if (colsol_ == NULL) delete [] colsol_;
+        colsol_ = NULL;
+        if (slacks_ == NULL) delete [] slacks_;
+        slacks_ = NULL;
+        if (integers_ == NULL) delete [] integers_;
+        integers_ = NULL;
+        if (nBasics_>0)
+        {
+            basics_ = new int[nBasics_];
+            CoinCopyN(source.basics_, nBasics_, basics_);
+            integers_ = new bool [nBasics_ + nNonBasics_];
+            CoinCopyN(source.integers_, nBasics_ + nNonBasics_, integers_);
+        }
+        if (nNonBasics_>0)
+        {
+            nonBasics_ = new int[nNonBasics_];
+            CoinCopyN(source.nonBasics_, nBasics_, nonBasics_);
+        }
+        if (nBasics_ + nNonBasics_ > 0)
+        {
+            colsol_ = new double[nBasics_ + nNonBasics_];
+            slacks_ = &colsol_[nNonBasics_];
+            CoinCopyN(source.colsol_, nBasics_ + nNonBasics_, colsol_);
+        }
+        if (source.basis_!=NULL)
+            basis_ = new CoinWarmStartBasis(*source.basis_);
+        delete solver_;
+	if (source.solver_)
+	  solver_ = source.solver_->clone();
+    }
+    return *this;
+}
+
+void
+CglLandP::CachedData::getData(const OsiSolverInterface &si)
+{
+    int nBasics = si.getNumRows();
+    int nNonBasics = si.getNumCols();
+    if (basis_ != NULL)
+        delete basis_;
+    basis_ = dynamic_cast<CoinWarmStartBasis *> (si.getWarmStart());
+    if (!basis_)
+        throw NoBasisError();
+
+    if (nBasics_ > 0 || nBasics != nBasics_)
+    {
+        delete [] basics_;
+        basics_ = NULL;
+    }
+    if (basics_ == NULL)
+    {
+        basics_ = new int[nBasics];
+        nBasics_ = nBasics;
+    }
+
+    if (nNonBasics_ > 0 || nNonBasics != nNonBasics_)
+    {
+        delete [] nonBasics_;
+        nonBasics_ = NULL;
+    }
+    if (nonBasics_ == NULL)
+    {
+        nonBasics_ = new int[nNonBasics];
+        nNonBasics_ = nNonBasics;
+    }
+    int n = nBasics + nNonBasics;
+    if ( nBasics_ + nNonBasics_ > 0 || nBasics_ + nNonBasics_ != n)
+    {
+        delete [] colsol_;
+        delete [] integers_;
+        integers_ = NULL;
+        colsol_ = NULL;
+        slacks_ = NULL;
+    }
+    if (colsol_ == NULL)
+    {
+        colsol_ = new double[n];
+        slacks_ = &colsol_[nNonBasics];
+    }
+
+    if (integers_ == NULL)
+    {
+        integers_ = new bool[n];
+    }
+
+    const double * rowLower = si.getRowLower();
+    const double * rowUpper = si.getRowUpper();
+    //determine which slacks are integer
+    const CoinPackedMatrix * m = si.getMatrixByCol();
+    const double * elems = m->getElements();
+    const int * inds = m->getIndices();
+    const CoinBigIndex * starts = m->getVectorStarts();
+    const int * lengths = m->getVectorLengths();
+    //    int numElems = m->getNumElements();
+    int numCols = m->getNumCols();
+    assert(numCols == nNonBasics_);
+    //   int numRows = m->getNumRows();
+    CoinFillN(integers_ ,n, true);
+    for (int i = 0 ;  i < numCols ; i++)
+    {
+        if (si.isContinuous(i))
+            integers_[i] = false;
+    }
+    bool * integerSlacks = integers_ + numCols;
+    for (int i = 0 ; i < nBasics ; i++)
+    {
+        if (rowLower[i] > -1e50 && INT_INFEAS(rowLower[i]) > 1e-15)
+            integerSlacks[i] = false;
+        if (rowUpper[i] < 1e50 && INT_INFEAS(rowUpper[i]) > 1e-15)
+            integerSlacks[i] = false;
+    }
+    for (int i = 0 ;  i < numCols ; i++)
+    {
+        CoinBigIndex end = starts[i] + lengths[i];
+        if (integers_[i])
+        {
+            for (CoinBigIndex k=starts[i] ; k < end; k++)
+            {
+                if (integerSlacks[inds[k]] && INT_INFEAS(elems[k])>1e-15 )
+                    integerSlacks[inds[k]] = false;
+            }
+        }
+        else
+        {
+            for (CoinBigIndex k=starts[i] ; k < end; k++)
+            {
+                if (integerSlacks[inds[k]])
+                    integerSlacks[inds[k]] = false;
+            }
+        }
+    }
+
+    CoinCopyN(si.getColSolution(), si.getNumCols(), colsol_);
+    CoinCopyN(si.getRowActivity(), si.getNumRows(), slacks_);
+    for (int i = 0 ; i < si.getNumRows() ; i++)
+    {
+        slacks_[i]*=-1;
+        if (rowLower[i]>-1e50)
+        {
+            slacks_[i] += rowLower[i];
+        }
+        else
+        {
+            slacks_[i] += rowUpper[i];
+        }
+    }
+    //Now get the fill the arrays;
+    nNonBasics = 0;
+    nBasics = 0;
+
+
+
+    //For having the index variables correctly ordered we need to access to OsiSimplexInterface
+    {
+        OsiSolverInterface * ncSi = (const_cast<OsiSolverInterface *>(&si));
+        ncSi->enableSimplexInterface(0);
+        ncSi->getBasics(basics_);
+	// Save enabled solver
+	solver_ = si.clone();
+#ifdef COIN_HAS_OSICLP
+	OsiClpSolverInterface * clpSi = dynamic_cast<OsiClpSolverInterface *>(solver_);
+	const OsiClpSolverInterface * clpSiRhs = dynamic_cast<const OsiClpSolverInterface *>(&si);
+	if (clpSi)
+	  clpSi->getModelPtr()->copyEnabledStuff(clpSiRhs->getModelPtr());;
+#endif
+        ncSi->disableSimplexInterface();
+    }
+
+    int numStructural = basis_->getNumStructural();
+    for (int i = 0 ; i < numStructural ; i++)
+    {
+        if (basis_->getStructStatus(i)== CoinWarmStartBasis::basic)
+        {
+            nBasics++;
+            //Basically do nothing
+        }
+        else
+        {
+            nonBasics_[nNonBasics++] = i;
+        }
+    }
+
+    int numArtificial = basis_->getNumArtificial();
+    for (int i = 0 ; i < numArtificial ; i++)
+    {
+        if (basis_->getArtifStatus(i)== CoinWarmStartBasis::basic)
+        {
+            //Just check number of basics
+            nBasics++;
+        }
+        else
+        {
+            nonBasics_[nNonBasics++] = i + basis_->getNumStructural();
+        }
+    }
+}
+void
+CglLandP::CachedData::clean(){
+    if (basics_!=NULL)
+        delete [] basics_;
+    basics_ = NULL;
+    if (nonBasics_!=NULL)
+        delete [] nonBasics_;
+    nonBasics_ = NULL;
+    if (colsol_ != NULL)
+        delete [] colsol_;
+    colsol_ = NULL;
+    delete basis_;
+    basis_ = NULL;
+    if (integers_)
+        delete [] integers_;
+    integers_ = NULL;
+
+   nBasics_ = 0;
+   nNonBasics_ = 0;
+   delete solver_;
+   solver_ = NULL;
+}
+CglLandP::CachedData::~CachedData()
+{
+    if (basics_!=NULL)
+        delete [] basics_;
+    if (nonBasics_!=NULL)
+        delete [] nonBasics_;
+    if (colsol_ != NULL)
+        delete [] colsol_;
+    delete basis_;
+    if (integers_)
+        delete [] integers_;
+    delete solver_;
+}
+
+CglLandP::CglLandP(const CglLandP::Parameters &params,
+                   const LAP::Validator &validator):
+        params_(params), cached_(), validator_(validator), numcols_(-1),
+        originalColLower_(NULL), originalColUpper_(NULL),
+        canLift_(false),
+        extraCuts_()
+{
+    handler_ = new CoinMessageHandler();
+    handler_->setLogLevel(0);
+    messages_ = LapMessages();
+}
+
+
+CglLandP::~CglLandP()
+{
+    delete handler_;
+    if (originalColLower_ != NULL)
+        delete [] originalColLower_;
+    if (originalColUpper_ != NULL)
+        delete [] originalColUpper_;
+}
+
+CglLandP::CglLandP(const CglLandP & source):
+        CglCutGenerator(source),
+        params_(source.params_), cached_(source.cached_),
+        validator_(source.validator_), numcols_(source.numcols_),
+        originalColLower_(NULL), originalColUpper_(NULL),
+        canLift_(source.canLift_),
+        extraCuts_(source.extraCuts_)
+{
+    handler_ = new CoinMessageHandler();
+    handler_->setLogLevel(source.handler_->logLevel());
+    messages_ = LapMessages();
+    if (numcols_ != -1)
+    {
+        assert(numcols_ > 0);
+        assert(originalColLower_!=NULL);
+        assert(originalColUpper_!=NULL);
+        originalColLower_ = new double[numcols_];
+        originalColUpper_ = new double[numcols_];
+        CoinCopyN(source.originalColLower_,numcols_,originalColLower_);
+        CoinCopyN(source.originalColUpper_,numcols_,originalColUpper_);
+    }
+}
+
+/** Assignment operator */
+CglLandP& CglLandP::operator=(const CglLandP &rhs)
+{
+    if (this != &rhs)
+    {
+        params_ = rhs.params_;
+        cached_ = rhs.cached_;
+        validator_ = rhs.validator_;
+        extraCuts_ = rhs.extraCuts_;
+    }
+    return *this;
+}
+
+
+CglCutGenerator *
+CglLandP::clone() const
+{
+    return new CglLandP(*this);
+}
+
+extern double restaurationTime;
+
+struct cutsCos
+{
+    int i;
+    int j;
+    double angle;
+    cutsCos(int  i_, int j_ , double angle_):i(i_), j(j_), angle(angle_)
+    {
+    }
+    bool operator<(const cutsCos&other)const
+    {
+        return angle > other.angle;
+    }
+};
+
+
+void
+CglLandP::scanExtraCuts(OsiCuts& cs, const double * colsol) const
+{
+    int numAdded = 0;
+    for (int i = extraCuts_.sizeRowCuts() - 1; i > -1 ; i--)
+    {
+        double violation = extraCuts_.rowCut(i).violated(colsol);
+        if (violation > 0.)
+        {
+            cs.insert(extraCuts_.rowCut(i));
+            numAdded++;
+            //      std::cout<<"A cut computed in a previous iteration is violated by "<<violation<<"."<<std::endl;
+            //extraCuts_.eraseRowCut(i);
+        }
+    }
+    //  std::cout<<"Added "<<numAdded<<" previously generated cuts."<<std::endl;
+}
+
+void
+CglLandP::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+                       const CglTreeInfo info )
+{
+    if ((info.pass == 0) && !info.inTree)
+    {
+        numrows_ = si.getNumRows();
+    }
+// scanExtraCuts(cs, si.getColSolution());
+    Parameters params = params_;
+    params.rhsWeight = numrows_ + 2;
+
+    handler_->message(CUT_GAP, messages_)<<info.pass<<si.getObjValue() <<CoinMessageEol;
+
+    if (info.inTree)   //put lower pivot limit
+    {
+        params.pivotLimit = std::min(params.pivotLimit, params.pivotLimitInTree);
+        params.countMistakenRc = true;
+    }
+    if (params.timeLimit < 0)
+    {
+        params.pivotLimit = 0;
+    }
+
+    assert(si.basisIsAvailable());
+
+
+#ifdef APPEND_ROW
+    OsiSolverInterface * t_si = si.clone();
+    if (params.modularize)
+    {
+        int new_idx = si.getNumCols();
+        int v_idx[1] = {new_idx};
+        double v_val[1] = {-1};
+        CoinPackedVector v(1, v_idx, v_val, false);
+        t_si->addCol(CoinPackedVector(), 0, 1, 0);
+        t_si->setInteger(new_idx);
+        t_si->addRow(v,0, 0);
+        t_si->resolve();
+    }
+#else
+    const OsiSolverInterface * t_si = &si;
+#endif
+
+    cached_.getData(*t_si);
+    CglLandPSimplex landpSi(*t_si, cached_, params, validator_);
+    if (params.generateExtraCuts == CglLandP::AllViolatedMigs)
+    {
+        landpSi.genThisBasisMigs(cached_, params);
+    }
+    landpSi.setLogLevel(handler_->logLevel());
+    int nCut = 0;
+
+    std::vector<int> indices;
+    getSortedFractionalIndices(indices,cached_, params);
+
+#ifndef NDEBUG
+    int numrows = si.getNumRows();
+#endif
+
+#ifdef DO_STAT
+    //Get informations on current optimum
+    {
+        OsiSolverInterface * gapTester = si.clone();
+        gapTester->resolve();
+
+        roundsStats_.analyseOptimalBasis(gapTester,info.pass, numrows_);
+        delete gapTester;
+    }
+#endif
+
+    params_.timeLimit += CoinCpuTime();
+    CoinRelFltEq eq(1e-04);
+
+    for (unsigned int i = 0; i < indices.size() && nCut < params.maxCutPerRound &&
+            nCut < cached_.nBasics_ ; i++)
+    {
+
+        //Check for time limit
+        int iRow = indices[i];
+        assert(iRow < numrows);
+        OsiRowCut cut;
+        int code=1;
+        OsiSolverInterface * ncSi = NULL;
+
+        if (params.pivotLimit != 0)
+        {
+            ncSi = t_si->clone();
+            landpSi.setSi(ncSi);
+            ncSi->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX);
+            ncSi->messageHandler()->setLogLevel(0);
+        }
+
+        int generated = 0;
+        if (params.pivotLimit == 0)
+        {
+            generated = landpSi.generateMig(iRow, cut, params);
+        }
+        else
+        {
+            generated = landpSi.optimize(iRow, cut, cached_, params);
+            if (params.generateExtraCuts == CglLandP::AllViolatedMigs)
+            {
+                landpSi.genThisBasisMigs(cached_, params);
+            }
+            landpSi.resetSolver(cached_.basis_);
+        }
+        code = 0;
+        if (generated)
+            code = validator_(cut, cached_.colsol_, si, params, originalColLower_, originalColUpper_);
+        if (!generated || code)
+        {
+            if (params.pivotLimit !=0)
+            {
+                handler_->message(LAP_CUT_FAILED_DO_MIG, messages_)<<validator_.failureString(code)<<CoinMessageEol;
+                landpSi.freeSi();
+                OsiSolverInterface * ncSi = t_si->clone();
+                landpSi.setSi(ncSi);
+                params.pivotLimit = 0;
+                if (landpSi.optimize(iRow, cut, cached_, params))
+                {
+                    code = validator_(cut, cached_.colsol_, si, params, originalColLower_, originalColUpper_);
+                }
+                params.pivotLimit = params_.pivotLimit;
+            }
+        }
+
+        if (params.pivotLimit != 0)
+        {
+            landpSi.freeSi();
+        }
+        if (code)
+        {
+            handler_->message(CUT_REJECTED, messages_)<<
+            validator_.failureString(code)<<CoinMessageEol;
+        }
+        else
+        {
+            if (canLift_)
+            {
+                cut.setGloballyValid(true);
+            }
+            cs.insertIfNotDuplicate(cut, eq);
+            //cs.insert(cut);
+            {
+                //std::cout<<"Violation "<<cut.violated(cached_.colsol_)<<std::endl;
+                nCut++;
+            }
+        }
+    }
+
+    Cuts& extra = landpSi.extraCuts();
+    for (int i = 0 ; i < cached_.nNonBasics_; i++)
+    {
+        OsiRowCut * cut = extra.rowCut(i);
+        if (cut == NULL) continue;
+        int code = validator_(*cut, cached_.colsol_, si, params,
+                              originalColLower_, originalColUpper_);
+        if (code)
+        {
+            handler_->message(LAP_CUT_FAILED_DO_MIG, messages_)
+            <<validator_.failureString(code)<<CoinMessageEol;
+        }
+        else
+        {
+            cs.insertIfNotDuplicate(*cut, eq);
+            {
+                nCut++;
+            }
+        }
+        delete cut;
+    }
+
+    landpSi.outPivInfo(nCut);
+    params_.timeLimit -= CoinCpuTime();
+
+    cached_.clean();
+#ifdef APPEND_ROW
+    assert(t_si != &si);
+    delete t_si;
+#endif
+}
+
+
+template < class S, class T, class U >
+class StableCompare
+{
+public:
+    inline bool operator()(const CoinTriple<S,T,U>& t1,
+                           const CoinTriple<S,T,U>& t2) const
+    {
+        return (t1.third < t2.third) ||
+               ((t1.third == t2.third) && (t1.second < t2.second));
+    }
+
+};
+
+template <class T1,class T2>
+struct StableExternalComp
+{
+    const std::vector<T1> &vec_1_;
+    const std::vector<T2> &vec_2_;
+    StableExternalComp(const std::vector<T1> &vec_1,
+                       const std::vector<T2> &vec_2):
+            vec_1_(vec_1),
+            vec_2_(vec_2)
+    {
+    }
+    CoinRelFltEq eq;
+    bool operator()(int i, int j)
+    {
+        bool result = (vec_1_[i] < vec_1_[j]) ||
+                      ( ((vec_1_[i]== vec_1_[j]))
+                        && (vec_2_[i] < vec_2_[j]));
+        return result;
+    }
+
+};
+void
+CglLandP::getSortedFractionalIndices(std::vector<int> &frac_indices,
+                                     const CachedData &data,
+                                     const CglLandP::Parameters & params) const
+{
+    std::vector<int> colIndices;
+    std::vector<double> values;
+    std::vector<int> indices;
+    for (int i = 0 ; i < data.nBasics_ ; i++)
+    {
+        const int& iCol = data.basics_[i];
+        if (iCol >= data.nNonBasics_ ||
+                !data.integers_[iCol] ||
+                INT_INFEAS(data.colsol_[iCol]) <= params.away)
+            continue;
+        const double value = INT_INFEAS(data.colsol_[iCol]);
+
+        frac_indices.push_back(i);
+        indices.push_back(static_cast<int>(values.size()));
+        values.push_back(- value);
+        colIndices.push_back(iCol);
+    }
+    std::sort(indices.begin(), indices.end(),StableExternalComp<double, int>(values,colIndices));
+    colIndices = frac_indices;
+    for (unsigned int i = 0; i < indices.size() ; i++)
+    {
+        frac_indices[i] = colIndices[indices[i]];
+    }
+
+}
+
+
diff --git a/cbits/coin/CglLandP.hpp b/cbits/coin/CglLandP.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandP.hpp
@@ -0,0 +1,306 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     07/21/05
+//
+// $Id: CglLandP.hpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+#ifndef CglLandP_H
+#define CglLandP_H
+
+#include "CglLandPValidator.hpp"
+#include "CglCutGenerator.hpp"
+#include "CglParam.hpp"
+
+#include <iostream>
+class CoinWarmStartBasis;
+/** Performs one round of Lift & Project using CglLandPSimplex
+    to build cuts
+*/
+
+namespace LAP
+{
+enum LapMessagesTypes
+{
+    BEGIN_ROUND,
+    END_ROUND,
+    DURING_SEP,
+    CUT_REJECTED,
+    CUT_FAILED,
+    CUT_GAP,
+    LAP_CUT_FAILED_DO_MIG,
+    LAP_MESSAGES_DUMMY_END
+};
+/** Output messages for Cgl */
+class LapMessages : public CoinMessages
+{
+public:
+    /** Constructor */
+    LapMessages( );
+    /** destructor.*/
+    virtual ~LapMessages() {}
+};
+class CglLandPSimplex;
+}
+
+class CglLandP : public CglCutGenerator
+{
+    friend void CglLandPUnitTest(OsiSolverInterface *si, const std::string & mpsDir);
+
+    friend class LAP::CglLandPSimplex;
+    friend class CftCglp;
+
+public:
+
+    enum SelectionRules
+    {
+        mostNegativeRc /** select most negative reduced cost */,
+        bestPivot /** select best possible pivot.*/,
+        initialReducedCosts/** Select only those rows which had initialy a 0 reduced cost.*/
+    };
+
+    enum ExtraCutsMode
+    {
+        none/** Generate no extra cuts.*/,
+        AtOptimalBasis /** Generate cuts from the optimal basis.*/,
+        WhenEnteringBasis /** Generate cuts as soon as a structural enters the basis.*/,
+        AllViolatedMigs/** Generate all violated Mixed integer Gomory cuts in the course of the optimization.*/
+    };
+
+    /** Space where cuts are optimized.*/
+    enum SeparationSpaces
+    {
+        Fractional=0 /** True fractional space.*/,
+        Fractional_rc/** Use fractional space only for computing reduced costs.*/,
+        Full /** Work in full space.*/
+    };
+
+    /** Normalization */
+    enum Normalization
+    {
+        Unweighted = 0,
+        WeightRHS,
+        WeightLHS,
+        WeightBoth
+    };
+
+    enum LHSnorm
+    {
+        L1 = 0,
+        L2,
+        SupportSize,
+        Infinity,
+        Average,
+        Uniform
+    };
+    /** RHS weight in normalization.*/
+    enum RhsWeightType
+    {
+        Fixed = 0 /** 2*initial number of constraints. */,
+        Dynamic /** 2 * current number of constraints. */
+    };
+    /** Class storing parameters.
+        \remark I take all parameters from Ionut's code */
+    class Parameters : public CglParam
+    {
+    public:
+        /** Default constructor (with default values)*/
+        Parameters();
+        /** Copy constructor */
+        Parameters(const Parameters &other);
+        /** Assignment opertator */
+        Parameters & operator=(const Parameters &other);
+        /// @name integer parameters
+        ///@{
+
+        /** Max number of pivots before we generate the cut
+          \default 20 */
+        int pivotLimit;
+        /** Max number of pivots at regular nodes. Put a value if you want it lower than the global pivot limit.
+         \default 100.*/
+        int pivotLimitInTree;
+        /** Maximum number of cuts generated at a given round*/
+        int maxCutPerRound;
+        /** Maximum number of failed pivots before aborting */
+        int failedPivotLimit;
+        /** maximum number of consecutive degenerate pivots
+          \default 0 */
+        int degeneratePivotLimit;
+        /** Maximum number of extra rows to generate per round.*/
+        int extraCutsLimit;
+        ///@}
+        /// @name double parameters
+        ///@{
+        /** Tolerance for small pivots values (should be the same as the solver */
+        double pivotTol;
+        /** A variable have to be at least away from integrity to be generated */
+        double away;
+        /** Total time limit for cut generation.*/
+        double timeLimit;
+        /** Time limit for generating a single cut.*/
+        double singleCutTimeLimit;
+        /** Weight to put in RHS of normalization if static.*/
+        double rhsWeight;
+        ///@}
+
+        /// @name Flags
+        ///@{
+        /** Do we use tableau row or the disjunction (I don't really get that there should be a way to always use the tableau)*/
+        bool useTableauRow;
+        /** Do we apply Egon Balas's Heuristic for modularized cuts */
+        bool modularize;
+        /** Do we strengthen the final cut (always do if modularize is 1) */
+        bool strengthen;
+        /** Wether to limit or not the number of mistaken RC (when perturbation is applied).*/
+        bool countMistakenRc;
+        /** Work in the reduced space (only non-structurals enter the basis) */
+        SeparationSpaces sepSpace;
+        /** Apply perturbation procedure. */
+        bool perturb;
+        /** How to weight normalization.*/
+        Normalization normalization;
+        /** How to weight RHS of normalization.*/
+        RhsWeightType rhsWeightType;
+        /** How to weight LHS of normalization.*/
+        LHSnorm lhs_norm;
+        /** Generate extra constraints from optimal lift-and-project basis.*/
+        ExtraCutsMode generateExtraCuts;
+        /** Which rule to apply for choosing entering and leaving variables.*/
+        SelectionRules pivotSelection;
+        ///@}
+    };
+
+
+    /** Constructor for the class*/
+    CglLandP(const CglLandP::Parameters &params = CglLandP::Parameters(),
+             const LAP::Validator &validator = LAP::Validator());
+    /** Destructor */
+    ~CglLandP();
+    /** Copy constructor */
+    CglLandP(const CglLandP &source);
+    /** Assignment operator */
+    CglLandP& operator=(const CglLandP &rhs);
+    /** Clone function */
+    CglCutGenerator * clone() const;
+
+    /**@name Generate Cuts */
+    //@{
+
+    virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+                              const CglTreeInfo info = CglTreeInfo());
+
+    //@}
+
+    virtual bool needsOptimalBasis() const
+    {
+        return true;
+    }
+
+    LAP::Validator & validator()
+    {
+        return validator_;
+    }
+    /** set level of log for cut generation procedure :
+    <ol start=0 >
+    	<li> for none </li>
+    	<li> for log at begin and end of procedure + at some time interval </li>
+    	<li> for log at every cut generated </li>
+    	</ol>
+    	*/
+    void setLogLevel(int level)
+    {
+        handler_->setLogLevel(level);
+    }
+
+    class NoBasisError : public CoinError
+    {
+    public:
+        NoBasisError(): CoinError("No basis available","LandP","") {}
+    };
+
+    class SimplexInterfaceError : public CoinError
+    {
+    public:
+        SimplexInterfaceError(): CoinError("Invalid conversion to simplex interface", "CglLandP","CglLandP") {}
+    };
+    Parameters & parameter()
+    {
+        return params_;
+    }
+private:
+
+
+    void scanExtraCuts(OsiCuts& cs, const double * colsol) const;
+
+    Parameters params_;
+
+    /** Some informations that will be changed by the pivots and that we want to keep*/
+    struct CachedData
+    {
+        CachedData(int nBasics = 0 , int nNonBasics = 0);
+        CachedData(const CachedData & source);
+
+        CachedData& operator=(const CachedData &source);
+        /** Get the data from a problem */
+        void getData(const OsiSolverInterface &si);
+
+        void clean();
+
+        ~CachedData();
+        /** Indices of basic variables in starting basis (ordered if variable basics_[i] s basic in row i)*/
+        int * basics_;
+        /** Indices of non-basic variables */
+        int *nonBasics_;
+        /** number of basics variables */
+        int nBasics_;
+        /** number of non-basics */
+        int nNonBasics_;
+        /** Optimal basis */
+        CoinWarmStartBasis * basis_;
+        /** Stores the value of the solution to cut */
+        double * colsol_;
+        /** Stores the values of the slacks */
+        double * slacks_;
+        /** Stores wheter slacks are integer constrained */
+        bool * integers_;
+        /** Solver before pivots */
+        OsiSolverInterface * solver_;
+    };
+    /** Retrieve sorted integer variables which are fractional in the solution.
+        Return the number of variables.*/
+    int getSortedFractionals(CoinPackedVector &xFrac,
+                             const CachedData & data,
+                             const CglLandP::Parameters& params) const;
+    /** Retrieve sorted integer variables which are fractional in the solution.
+        Return the number of variables.*/
+    void getSortedFractionalIndices(std::vector<int>& indices,
+                                    const CachedData &data,
+                                    const CglLandP::Parameters & params) const;
+    /** Cached informations about problem.*/
+    CachedData cached_;
+    /** message handler */
+    CoinMessageHandler * handler_;
+    /** messages */
+    CoinMessages messages_;
+    /** cut validator */
+    LAP::Validator validator_;
+    /** number of rows in the original problems. */
+    int numrows_;
+    /** number of columns in the original problems. */
+    int numcols_;
+    /** Original lower bounds for the problem (for lifting cuts).*/
+    double * originalColLower_;
+    /** Original upper bounds for the problem (for lifting cuts).*/
+    double * originalColUpper_;
+    /** Flag to say if cuts can be lifted.*/
+    bool canLift_;
+    /** Store some extra cut which could be cheaply generated but do not cut current incumbent.*/
+    OsiCuts extraCuts_;
+};
+void CglLandPUnitTest(OsiSolverInterface *si, const std::string & mpsDir);
+
+#endif
+
diff --git a/cbits/coin/CglLandPMessages.cpp b/cbits/coin/CglLandPMessages.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPMessages.cpp
@@ -0,0 +1,90 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     21/07/05
+//
+// $Id: CglLandPMessages.cpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+#include "CglLandPMessages.hpp"
+#include <cstring>
+#define REMOVE_LOG 0
+namespace LAP
+{
+
+#ifdef LAP_ADD_MSG
+#error "Macro ADD_MSG already defined"    
+#endif
+#define LAP_ADD_MSG(Id,Type,Level,MSG) addMessage(Id, CoinOneMessage( Type(Id), Level, MSG))
+inline int std_m(int n)
+{
+    return 1 + n;
+}
+inline int warn_m(int n)
+{
+    return  3000 + n;
+}
+inline int err_m(int n)
+{
+    return n + 6000;
+}
+
+
+LandPMessages::LandPMessages()
+        :
+        CoinMessages(DUMMY_END)
+{
+    strcpy(source_,"Lap");
+    LAP_ADD_MSG(Separating,std_m,3+REMOVE_LOG,"Starting separation on variable %d, initial depth of cut %f");
+    LAP_ADD_MSG(FoundImprovingRow, std_m,4,
+                "Found improving row (leaving variable). Row %d (basic var %d), "
+                "leaving status %d, sign of gamma %d, reduced cost %f");
+    LAP_ADD_MSG(FoundBestImprovingCol, std_m, 4,
+                " Found best improvement (entering variable). Var %d, "
+                "value of gamma %f, expected depth of next cut %f");
+    LAP_ADD_MSG(WarnFailedBestImprovingCol, err_m, 3,
+                "Failed to find an improving entering variable while reduced cost was %f, "
+                "depth of current cut %f, best cut depth with pivot %f");
+    //Log line is cut number time pivot number,  cut depth, leaving, incoming gamma degenerate
+    LAP_ADD_MSG(LogHead, std_m, 3+REMOVE_LOG,
+                "Pivot no \t cut depth \t leaving var \t incoming var \t direction \t gamma \t degenerate");
+    LAP_ADD_MSG(PivotLog, std_m, 3+REMOVE_LOG,
+                "%8d\t %9f\t %11d \t %11d \t %11d \t %8f \t %12d \t %.5g \t %11d");
+    LAP_ADD_MSG(FinishedOptimal, std_m, 2,
+                "Found optimal lift-and-project cut, depth %f number of pivots performed %d");
+    LAP_ADD_MSG(HitLimit, std_m, 2, "Stopping lift-and-project optimization hit %s limit. Number of pivots %d");
+    LAP_ADD_MSG(WarnBadSigmaComputation, err_m, 1,
+                "Cut depth after pivot is not what was expected by computations before, difference %.15f");
+    LAP_ADD_MSG(WarnBadRowComputation, err_m, 1,
+                "Row obtained after pivot is not what was expected (distance between the two %f in norm inf).");
+    LAP_ADD_MSG(WarnGiveUpRow, err_m,1,"Limit of %d negative reduced costs with no strict improvement");
+    LAP_ADD_MSG(PivotFailedSigmaUnchanged, err_m, 1,
+                "A pivot failed to be performed (probably refactorization was performed) but sigma is unchanged continue...");
+    LAP_ADD_MSG(PivotFailedSigmaIncreased, err_m,
+                1,"A pivot failed to be performed, and sigma has changed exit without generating cut");
+    LAP_ADD_MSG(FailedSigmaIncreased, err_m,1,"Cut violation has increased in last pivot");
+    LAP_ADD_MSG
+    (WarnBadRhsComputation,
+     err_m,1,
+     "rhs obtained  after pivot is not what was expected (distance between the two %f).");
+    LAP_ADD_MSG(WarnFailedPivotTol,
+                err_m, 2,"All pivots are below tolerance");
+    LAP_ADD_MSG(WarnFailedPivotIIf,
+                err_m, 2,"There is no possible pivot within tolerance (every pivot make rhs for current row %f too close to integer feasibility");
+    LAP_ADD_MSG(NumberNegRc, std_m, 4,
+                "Number of rows with negative reduced cost %i");
+    LAP_ADD_MSG(NumberZeroRc, std_m, 4,
+                "Number of rows with zero reduced cost %i");
+    LAP_ADD_MSG(NumberPosRc, std_m, 4,
+                "Number of rows with positive reduced cost %i");
+    LAP_ADD_MSG(WeightsStats, std_m, 2,
+                "Maximal weight %g minimal weight %g");
+    LAP_ADD_MSG(RoundStats, std_m, 1,
+                "Separated %i cuts with %i pivots, source entered %i times, %i sigma increases.");
+    LAP_ADD_MSG(CutStat, std_m, 1,
+                "Separated cut %i with %i pivots, source entered %i times, %i sigma increases, %i potential cycles.%g");
+}
+}
+
diff --git a/cbits/coin/CglLandPMessages.hpp b/cbits/coin/CglLandPMessages.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPMessages.hpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           LIF
+//           CNRS, Aix-Marseille Universites
+// Date:     02/23/08
+//
+// $Id: CglLandPMessages.hpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+#ifndef CglLandPMessages_H
+#define CglLandPMessages_H
+
+#include "CoinMessage.hpp"
+#include "CoinMessageHandler.hpp"
+
+namespace LAP
+{
+/** Forward declaration of class to store extra debug data.*/
+class DebugData;
+/** Types of messages for lift-and-project simplex.*/
+enum LAP_messages
+{
+    Separating,
+    FoundImprovingRow,
+    FoundBestImprovingCol,
+    WarnFailedBestImprovingCol,
+    LogHead,
+    PivotLog,
+    FinishedOptimal,
+    HitLimit,
+    NumberNegRc,
+    NumberZeroRc,
+    NumberPosRc,
+    WeightsStats,
+    WarnBadSigmaComputation,
+    WarnBadRowComputation,
+    WarnGiveUpRow,
+    PivotFailedSigmaUnchanged,
+    PivotFailedSigmaIncreased,
+    FailedSigmaIncreased,
+    WarnBadRhsComputation,
+    WarnFailedPivotTol,
+    WarnFailedPivotIIf,
+    RoundStats,
+    CutStat,
+    DUMMY_END
+};
+/** Message handler for lift-and-project simplex. */
+class LandPMessages : public CoinMessages
+{
+public:
+
+    /** Constructor */
+    LandPMessages();
+};
+}
+#endif
diff --git a/cbits/coin/CglLandPSimplex.cpp b/cbits/coin/CglLandPSimplex.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPSimplex.cpp
@@ -0,0 +1,3373 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     21/07/05
+//
+// $Id: CglLandPSimplex.cpp 1152 2013-10-29 14:52:29Z forrest $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+#include "CglLandPSimplex.hpp"
+#include "CoinTime.hpp"
+#ifdef COIN_HAS_OSICLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+#include "CoinIndexedVector.hpp"
+#include <cassert>
+#include <iterator>
+
+#include <list>
+#include <algorithm>
+
+#define REMOVE_LOG 0
+
+#define RED_COST_CHECK 1e-6
+
+
+//#define OUT_CGLP_PIVOTS
+#ifdef OUT_CGLP_PIVOTS
+#include "CglLandPOutput.hpp"
+#endif
+#ifdef DEBUG_LAP
+
+/* The function is not used anywhere (LL)
+static void MyAssertFunc(bool c, const std::string &s, const std::string&  file, unsigned int line){
+    if (c != true){
+        fprintf(stderr, "Failed MyAssertion: %s in %s line %i.\n", s.c_str(), file.c_str(), line);
+        throw -1;
+    }
+}
+*/
+
+static void DblGtAssertFunc(const double& a, const std::string &a_s, const double&b, const std::string& b_s,
+                     const std::string&  file, unsigned int line)
+{
+    if (a<b)
+    {
+        fprintf(stderr, "Failed comparison: %s = %f < %s =%f in  %s line %i.\n", a_s.c_str(),
+                a, b_s.c_str(), b, file.c_str(), line);
+        throw -1;
+    }
+}
+
+static void DblEqAssertFunc(const double& a, const std::string &a_s, const double&b, const std::string& b_s,
+                     const std::string&  file, unsigned int line)
+{
+    CoinRelFltEq eq(1e-7);
+    if (!eq(a,b))
+    {
+        fprintf(stderr, "Failed comparison: %s = %f != %s =%f in  %s line %i.\n", a_s.c_str(),
+                a, b_s.c_str(), b, file.c_str(), line);
+        throw -1;
+    }
+}
+
+static void VecModEqAssertFunc(const CoinIndexedVector& a, const std::string a_s,
+                        const CoinIndexedVector& b, const std::string b_s,
+                        const std::string file, unsigned int line)
+{
+    CoinRelFltEq eq(1e-7);
+    assert(a.capacity()==b.capacity());
+    int n = a.capacity();
+    const double * a_v = a.denseVector();
+    const double * b_v = b.denseVector();
+    bool failed=false;
+    for (int i = 0 ; i < n ; i++)
+    {
+        double a = a_v[i] - floor(a_v[i]);
+        double b = b_v[i] - floor(b_v[i]);
+        if (!eq(a,b) && !eq(a_v[i],b_v[i]))
+        {
+            fprintf(stderr, "Failed comparison: %s[%i] = %.15f != %s[%i] =%.15f in  %s line %i.\n", a_s.c_str(),i,
+                    a_v[i], b_s.c_str(), i, b_v[i], file.c_str(), line);
+            failed = true;
+        }
+    }
+    if (failed) throw -1;
+}
+
+static void VecEqAssertFunc(const CoinIndexedVector& a, const std::string a_s,
+                     const CoinIndexedVector& b, const std::string b_s,
+                     const std::string file, unsigned int line)
+{
+    CoinRelFltEq eq(1e-7);
+    assert(a.capacity()==b.capacity());
+    int n = a.capacity();
+    const double * a_v = a.denseVector();
+    const double * b_v = b.denseVector();
+    bool failed=false;
+    for (int i = 0 ; i < n ; i++)
+    {
+        if (!eq(a_v[i],b_v[i]))
+        {
+            fprintf(stderr, "Failed comparison: %s[%i] = %f != %s[%i] =%f in  %s line %i.\n", a_s.c_str(),i,
+                    a_v[i], b_s.c_str(), i, b_v[i], file.c_str(), line);
+            failed = true;
+        }
+    }
+    if (failed) throw -1;
+}
+
+
+#define MAKE_STRING(exp) std::string(#exp)
+#define MyAssert(exp)  MyAssertFunc(exp, MAKE_STRING(exp), __FILE__, __LINE__);
+#define DblEqAssert(a,b)  DblEqAssertFunc(a,MAKE_STRING(a),b,MAKE_STRING(b), __FILE__, __LINE__);
+#define DblGtAssert(a,b)  DblGtAssertFunc(a,MAKE_STRING(a),b,MAKE_STRING(b), __FILE__, __LINE__);
+
+#define VecEqAssert(a,b) VecEqAssertFunc(a, MAKE_STRING(a), b, MAKE_STRING(b), __FILE__, __LINE__);
+#define VecModEqAssert(a,b) VecModEqAssertFunc(a, MAKE_STRING(a), b, MAKE_STRING(b), __FILE__, __LINE__);
+
+void checkVecFunc(const CoinIndexedVector &v)
+{
+    CoinIndexedVector v2 = v;
+    double * x = v2.denseVector();
+    const int * idx = v2.getIndices();
+    int n = v2.getNumElements();
+    for (int i = 0 ; i < n ; i++)
+    {
+        x[idx[i]] = 0.;
+    }
+    n = v2.capacity();
+    for (int i = 0 ; i < n ; i++)
+    {
+        DblEqAssert(x[i],0.);
+    }
+}
+
+#define checkVec(a) checkVecFunc(a)
+#else
+#define MyAssert(exp)
+#define DblEqAssert(a,b)
+#define DblGtAssert(a,b)
+#define VecEqAssert(a,b)
+#define VecModEqAssert(a,b)
+
+#define checkVec(a)
+#endif
+
+#include <algorithm>
+//#define TEST_M3
+namespace LAP
+{
+
+void CglLandPSimplex::printTableau(std::ostream & os)
+{
+    int width = 9;
+    os<<"Tableau at current basis"<<std::endl;
+    os<<"    ";
+    //Head with non basics indices
+    for (int i = 0 ; i < ncols_orig_ ; i++)
+    {
+        os.width(width);
+        os.setf(std::ios_base::right, std::ios_base::adjustfield);
+        std::cout<<nonBasics_[i]<<" ";
+    }
+
+    os.width(width);
+    os.setf(std::ios_base::right, std::ios_base::adjustfield);
+    std::cout<<'b';
+
+    os<<std::endl;
+
+    //print row by row
+    for (int i = 0 ; i < nrows_ ; i++)
+    {
+        //int ind = basics_[i];
+        row_i_.num = i;
+        pullTableauRow(row_i_);
+        row_i_.print(os, width, nonBasics_, ncols_orig_);
+
+    }
+
+}
+
+bool
+CglLandPSimplex::checkBasis()
+{
+    //Check that basics_ is correct
+    int * basic2 = new int [nrows_];
+    si_->getBasics(basic2);
+    for (int i = 0; i < nrows_ ; i++)
+        assert(basics_[i]==basic2[i]);
+    delete [] basic2;
+    return true;
+}
+
+
+CglLandPSimplex::CglLandPSimplex(const OsiSolverInterface &si,
+                                 const CglLandP::CachedData &cached,
+                                 const CglLandP::Parameters &params,
+                                 Validator& validator):
+#ifdef COIN_HAS_OSICLP
+        clp_(NULL),
+#endif
+        row_k_(this),
+        original_row_k_(this),
+        row_i_(this),
+        new_row_(this),
+        gammas_(false),
+        rowFlags_(NULL),
+        col_in_subspace(),
+        colCandidateToLeave_(NULL),
+        basics_(NULL), nonBasics_(NULL),
+        M1_(), M2_(), M3_(),
+        sigma_(0), basis_(NULL), colsolToCut_(NULL),
+        colsol_(NULL),
+        ncols_orig_(0),nrows_orig_(0),
+        inDegenerateSequence_(false),
+        chosenReducedCostVal_(1e100),
+        original_index_(),
+        si_(NULL),
+        validator_(validator),
+        numPivots_(0),
+        numSourceRowEntered_(0),
+        numIncreased_(0)
+{
+    ncols_orig_ = si.getNumCols();
+    nrows_orig_ = si.getNumRows();
+    handler_ = new CoinMessageHandler();
+    handler_->setLogLevel(2);
+    messages_ = LandPMessages();
+
+    si_ = const_cast<OsiSolverInterface *>(&si);
+
+#ifdef COIN_HAS_OSICLP
+    OsiClpSolverInterface * clpSi = dynamic_cast<OsiClpSolverInterface *>(si_);
+    if (clpSi)
+    {
+        clp_ = clpSi;
+    }
+#endif
+
+    int rowsize = ncols_orig_ + nrows_orig_ + 1;
+    row_k_.reserve(rowsize);
+#ifndef NDEBUG
+    new_row_.reserve(rowsize);
+#endif
+
+    lo_bounds_.resize(ncols_orig_ + nrows_orig_);
+    up_bounds_.resize(ncols_orig_ + nrows_orig_);
+
+    CoinCopyN(si.getColLower(),ncols_orig_, &lo_bounds_[0]);
+    CoinCopyN(si.getColUpper(),ncols_orig_,&up_bounds_[0]);
+    const double * rowUpper = si.getRowUpper();
+    const double * rowLower = si.getRowLower();
+    double infty = si.getInfinity();
+    int i=ncols_orig_;
+    for (int iRow = 0; iRow < nrows_orig_ ; iRow++, i++)
+    {
+        if (rowUpper[iRow] < infty)
+            lo_bounds_[i]=0.;
+        else lo_bounds_[i]= - infty;
+        if (rowLower[iRow] <= - infty)
+            up_bounds_[i] = infty;
+        else if (rowUpper[iRow] < infty)
+        {
+            lo_bounds_[i] = rowLower[iRow] - rowUpper[iRow];
+            up_bounds_[i] = 0;
+        }
+        else
+            up_bounds_[i] = 0.;
+    }
+    cuts_.resize(ncols_orig_);
+    if (params.pivotLimit != 0)
+    {
+        own_ = true;
+        rWk1_.resize(nrows_orig_);
+        rWk2_.resize(nrows_orig_);
+        rWk3_.resize(nrows_orig_);
+        rWk4_.resize(nrows_orig_);
+        rIntWork_.resize(nrows_orig_);
+
+        row_i_.reserve(rowsize);
+        rowFlags_ = new bool[nrows_orig_];
+        col_in_subspace.resize(ncols_orig_ + nrows_orig_);
+        colCandidateToLeave_ = new bool[ncols_orig_];
+        basics_ = new int[nrows_orig_];
+        nonBasics_ = new int[ncols_orig_];
+
+        colsolToCut_ = new double[ncols_orig_ + nrows_orig_];
+        colsol_ = new double[ncols_orig_ + nrows_orig_];
+        original_index_.resize(ncols_orig_ + nrows_orig_);
+        CoinIotaN(&original_index_[0],ncols_orig_ + nrows_orig_, 0);
+
+
+
+    }
+    else
+    {
+        nrows_ = nrows_orig_;
+        ncols_ = ncols_orig_;
+        original_index_.resize(ncols_orig_ + nrows_orig_);
+        CoinIotaN(&original_index_[0],ncols_orig_ + nrows_orig_, 0);
+        own_ = false;
+        si_->enableSimplexInterface(0);
+        basis_ = new CoinWarmStartBasis(*cached.basis_);
+    }
+    cacheUpdate(cached,params.sepSpace != CglLandP::Full);
+    if (params.normalization)
+    {
+        computeWeights(params.lhs_norm, params.normalization, params.rhsWeightType);
+    }
+    else rhs_weight_ = 1;
+}
+
+CglLandPSimplex::~CglLandPSimplex()
+{
+    delete handler_;
+    handler_ = NULL;
+    delete basis_;
+    basis_ = NULL;
+    if (own_)
+    {
+        delete [] rowFlags_;
+        rowFlags_ = NULL;
+        delete [] colCandidateToLeave_;
+        colCandidateToLeave_ = NULL;
+        delete [] basics_;
+        basics_ = NULL;
+        delete [] nonBasics_;
+        nonBasics_ = NULL;
+        delete [] colsolToCut_;
+        colsolToCut_ = NULL;
+        delete [] colsol_;
+        colsol_ = NULL;
+    }
+    else
+    {
+        si_->disableSimplexInterface();
+    }
+}
+
+/** Compute normalization weights.*/
+void
+CglLandPSimplex::computeWeights(CglLandP::LHSnorm norm, CglLandP::Normalization type,
+                                CglLandP::RhsWeightType rhs)
+{
+    norm_weights_.clear();
+    norm_weights_.resize(ncols_orig_ ,1.);
+    norm_weights_.resize(ncols_orig_ + nrows_orig_, 0.);
+
+    double * rows_weights = &norm_weights_[ncols_orig_];
+    std::vector<int> nnz(nrows_orig_,0);
+    const CoinPackedMatrix * m = si_->getMatrixByCol();
+    const double * val = m->getElements();
+    const int * ind = m->getIndices();
+    const int * length = m->getVectorLengths();
+    const CoinBigIndex * start = m->getVectorStarts();
+
+    rhs_weight_ = 1;
+
+    if (type== CglLandP::WeightRHS)
+    {
+        if (rhs == CglLandP::Fixed)
+            rhs_weight_ = (ncols_orig_ + 1);//params.rhsWeight;
+        else if (rhs == CglLandP::Dynamic)
+        {
+            throw -1;
+        }
+    }
+
+    if (norm == CglLandP::Infinity)
+    {
+        for (int i = 0 ; i < ncols_orig_ ; i++)
+        {
+            CoinBigIndex begin = start[i];
+            CoinBigIndex end = begin + length[i];
+            for (CoinBigIndex k = begin ; k < end ; k++)
+            {
+                rows_weights[ind[k]] = CoinMax(fabs(val[k]), rows_weights[ind[k]]);
+                rhs_weight_ += fabs(val[k]);
+                nnz[ind[k]] ++;
+            }
+        }
+    }
+    else if (norm == CglLandP::L1 ||
+             norm == CglLandP::Average)
+    {
+        for (int i = 0 ; i < ncols_orig_ ; i++)
+        {
+            CoinBigIndex begin = start[i];
+            CoinBigIndex end = begin + length[i];
+            for (CoinBigIndex k = begin ; k < end ; k++)
+            {
+                rows_weights[ind[k]] += fabs(val[k]);
+                nnz[ind[k]] ++;
+            }
+        }
+        if (norm == CglLandP::Average)
+        {
+            for (int i = 0 ; i < nrows_orig_ ; i++)
+            {
+                rows_weights[i] = static_cast<double>(nnz[i]);
+            }
+        }
+        if (type== CglLandP::WeightBoth)
+        {
+           rhs_weight_ += (ncols_orig_ + 1);
+           std::cout<<"rhs_weight : "<<rhs_weight_<<std::endl;
+        }
+    }
+    else if (norm == CglLandP::L2)
+    {
+        for (int i = 0 ; i < ncols_orig_ ; i++)
+        {
+            CoinBigIndex begin = start[i];
+            CoinBigIndex end = begin + length[i];
+            for (CoinBigIndex k = begin ; k < end ; k++)
+            {
+                rows_weights[ind[k]] += (val[k])*(val[k]);
+                nnz[ind[k]] ++;
+                rhs_weight_ += fabs(val[k]);
+            }
+        }
+        for (int i = 0 ; i < nrows_orig_ ; i++)
+        {
+            rows_weights[i] = sqrt(rows_weights[i]);;
+        }
+        if (type== CglLandP::WeightBoth)
+        {
+          rhs_weight_ = (ncols_orig_ + 1);
+        }
+    }
+    else if (norm == CglLandP::SupportSize)
+    {
+        for (int i = 0 ; i < ncols_orig_ ; i++)
+        {
+            CoinBigIndex begin = start[i];
+            CoinBigIndex end = begin + length[i];
+            for (CoinBigIndex k = begin ; k < end ; k++)
+            {
+                nnz[ind[k]] ++;
+            }
+        }
+
+        for (int i = 0 ; i < nrows_orig_ ; i++)
+        {
+            rows_weights[i] = 1./ static_cast<double> (nnz[i]);
+        }
+
+       if (type== CglLandP::WeightBoth)
+        {
+          rhs_weight_ = (ncols_orig_ + 1);
+        }
+
+    }
+    else if (norm ==CglLandP::Uniform)
+    {
+        for (int i = 0 ; i < nrows_orig_ ; i++)
+        {
+            rows_weights[i] = static_cast<double> (1);
+        }
+       if (type== CglLandP::WeightBoth)
+        {
+          rhs_weight_ = (ncols_orig_ + 1);
+        }
+
+    }
+
+}
+void
+CglLandPSimplex::cacheUpdate(const CglLandP::CachedData &cached, bool reducedSpace)
+{
+    integers_ = cached.integers_;
+    if (own_)
+    {
+        CoinCopyN(cached.basics_, nrows_orig_, basics_);
+        CoinCopyN(cached.nonBasics_, ncols_orig_, nonBasics_);
+        CoinCopyN(cached.colsol_, nrows_orig_ + ncols_orig_, colsol_);
+        for (int i = 0 ; i < ncols_orig_ ; i++)
+        {
+            colsol_[nonBasics_[i]] = 0;
+        }
+        CoinCopyN(cached.colsol_, nrows_orig_ + ncols_orig_, colsolToCut_);
+        //Zero all non basics in colsol setup the reduced space
+        col_in_subspace.resize(0);
+        col_in_subspace.resize(ncols_orig_+nrows_orig_,true);
+        for (int i = 0 ; i < ncols_orig_ ; i++)
+        {
+            setColsolToCut(nonBasics_[i],0.);
+            colsol_[nonBasics_[i]] = 0;
+        }
+        /** Mark the variables at zero in solution to cut so that we know that their contribution to reduced cost has to be computed*/
+        int n_removed =0;
+        if (reducedSpace)
+        {
+            for (int ii = 0; ii < ncols_orig_ ; ii++)
+            {
+                if (getColsolToCut(ii) - up_bounds_[ii] > 1e-08 || getColsolToCut(ii) - lo_bounds_[ii] < 1e-08)
+                {
+                    col_in_subspace[ii]=false;
+                    n_removed++;
+                }
+            }
+        }
+    }
+    else
+    {
+        basics_ = cached.basics_;
+        nonBasics_ = cached.nonBasics_;
+    }
+}
+
+bool CglLandPSimplex::resetSolver(const CoinWarmStartBasis * /*basis*/)
+{
+    si_->disableSimplexInterface();
+    return 0;
+}
+
+int
+CglLandPSimplex::generateExtraCuts(const CglLandP::CachedData & cached,
+                                   const CglLandP::Parameters& params)
+{
+    int ret_val = 0;
+    for (int i = 0 ; i < nrows_ && cuts_.numberCuts() < params.extraCutsLimit; i++)
+    {
+        if (basics_[i] < ncols_)
+            ret_val += generateExtraCut(i, cached, params);
+    }
+    return ret_val;
+}
+
+int
+CglLandPSimplex::generateExtraCut(int i, const CglLandP::CachedData & cached,
+                                  const CglLandP::Parameters& params)
+{
+    const int & iCol = basics_[i];
+    if (!isInteger(iCol) || int_val(colsol_[iCol], params.away) ||
+            !int_val(getColsolToCut(iCol), params.away) ||
+            colsol_[iCol] < getLoBound(iCol) || colsol_[iCol] > getUpBound(iCol) ||
+            (cuts_.rowCut(iCol) != NULL) )
+    {
+        return false;
+    }
+
+#ifdef DBG_OUT
+    printf("var: %i, basic in row %i. integer=%i, colsol_=%f, colsolToCut_=%f.\n",iCol, i,
+           isInteger(iCol), colsol_[iCol],
+           getColsolToCut(iCol));
+
+    printf("generating extra cut....\n");
+#endif
+
+    OsiRowCut * cut = new OsiRowCut;
+    generateMig(i, *cut, params);
+    assert(fabs(row_k_.rhs - colsol_[iCol]) < 1e-10);
+
+    int code = validator_(*cut, cached.colsol_, *si_, params, &lo_bounds_[0], &up_bounds_[0]);
+    if (code)
+    {
+        delete cut;
+        return false;
+    }
+    else
+    {
+        cuts_.insert(iCol, cut);
+        return true;
+    }
+}
+
+
+void
+CglLandPSimplex::genThisBasisMigs(const CglLandP::CachedData &cached,
+                                  const CglLandP::Parameters & params)
+{
+    for (int i = 0 ; i < cached.nBasics_ ; i++)
+    {
+        const int iCol = basics_[i];
+        if (iCol >= ncols_ ||
+                !cached.integers_[iCol] ||
+                int_val(colsol_[iCol], params.away))
+            continue;
+        OsiRowCut * cut = new OsiRowCut;
+        generateMig(i, *cut, params);
+        int code = validator_(*cut, cached.colsol_, *si_, params, &lo_bounds_[0], &up_bounds_[0]);
+        if (code)
+        {
+            delete cut;
+            continue;
+        }
+        cut->setEffectiveness(cut->violated(cached.colsol_));
+        if (cuts_.rowCut(iCol) == NULL || cut->effectiveness() > cuts_.rowCut(iCol)->effectiveness())
+        {
+            cuts_.insert(iCol,cut);
+        }
+        else
+            delete cut;
+    }
+}
+
+
+bool
+CglLandPSimplex::generateMig(int row, OsiRowCut & cut,
+                             const CglLandP::Parameters & params)
+{
+    row_k_.num = row;
+    pullTableauRow(row_k_);
+    row_k_.rhs = row_k_.rhs - floor(row_k_.rhs);
+    if (params.strengthen || params.modularize)
+        createMIG(row_k_, cut);
+    else
+        createIntersectionCut(row_k_, cut);
+
+    return 1;//At this point nothing failed, always generate a cut
+}
+
+bool
+CglLandPSimplex::optimize
+(int row, OsiRowCut & cut,const CglLandP::CachedData &cached,const CglLandP::Parameters & params)
+{
+    bool optimal = false;
+    int nRowFailed = 0;
+
+    double timeLimit = CoinMin(params.timeLimit, params.singleCutTimeLimit);
+    timeLimit += CoinCpuTime();
+    // double timeBegin = CoinCpuTime();
+    /** Copy the cached information */
+    nrows_ = nrows_orig_;
+    ncols_ = ncols_orig_;
+    CoinCopyN(cached.basics_, nrows_, basics_);
+    CoinCopyN(cached.nonBasics_, ncols_, nonBasics_);
+    CoinCopyN(cached.colsol_, nrows_+ ncols_, colsol_);
+    CoinCopyN(cached.colsol_, nrows_+ ncols_, colsolToCut_);
+
+    delete basis_;
+    basis_ = new CoinWarmStartBasis(*cached.basis_);
+#define CACHED_SOLVER
+#ifndef CACHED_SOLVER
+    si_->enableSimplexInterface(0);
+#else
+    delete si_;
+    si_ = cached.solver_->clone();
+#ifdef COIN_HAS_OSICLP
+    OsiClpSolverInterface * clpSi = dynamic_cast<OsiClpSolverInterface *>(si_);
+    OsiClpSolverInterface * clpSiRhs = dynamic_cast<OsiClpSolverInterface *>(cached.solver_);
+    if (clpSi)
+    {
+        clp_ = clpSi;
+	clpSi->getModelPtr()->copyEnabledStuff(clpSiRhs->getModelPtr());;
+    }
+#endif
+#endif
+#ifdef APPEND_ROW
+    if (params.modularize)
+    {
+        append_row(row, params.modularize);
+        row_k_.modularize(integers_);
+    }
+#endif
+    for (int i = 0 ; i < ncols_; i++)
+    {
+        setColsolToCut(nonBasics_[i], 0.);
+        colsol_[nonBasics_[i]] = 0;
+    }
+
+#ifdef APPEND_ROW
+    if (params.modularize)
+        row_k_.num = nrows_ - 1;
+    else
+#endif
+        row_k_.num = row;
+
+    pullTableauRow(row_k_);
+    row_k_.rhs = row_k_.rhs - floor(row_k_.rhs);
+
+    if (params.modularize)
+        row_k_.modularize(integers_);
+
+    updateM1_M2_M3(row_k_, 0., params.perturb);
+    sigma_ = computeCglpObjective(row_k_);
+
+    handler_->message(Separating,messages_)<<basics_[row]<<sigma_<<CoinMessageEol<<CoinMessageEol;
+    handler_->message(LogHead, messages_)<<CoinMessageEol<<CoinMessageEol;
+
+    //Save the variable basic in this row
+    //  int var_k = cached.basics_[k_];
+
+    //Put a flag on each row to say if we want to continue trying to use it
+    CoinFillN(rowFlags_,nrows_,true);
+
+    int numberConsecutiveDegenerate = 0;
+    bool allowDegeneratePivot = numberConsecutiveDegenerate < params.degeneratePivotLimit;
+    bool beObstinate = 0;
+    int numPivots = 0;
+    int saveNumSourceEntered = numSourceRowEntered_;
+    int saveNumIncreased = numIncreased_;
+    int numCycle = 0;
+    int numFailedPivots = 0;
+    bool hasFlagedRow = false;
+    int maxTryRow = 5;
+    while (  !optimal && numPivots < params.pivotLimit)
+    {
+        if (timeLimit - CoinCpuTime() < 0.) break;
+
+        updateM1_M2_M3(row_k_, 0., params.perturb);
+        sigma_ = computeCglpObjective(row_k_);
+        int direction = 0;
+        int gammaSign = 0;
+        int leaving = -1;
+        int incoming = -1;
+        double bestSigma;
+        if (params.pivotSelection != CglLandP::initialReducedCosts || numPivots == 0)
+        {
+            leaving = fastFindCutImprovingPivotRow(direction, gammaSign, params.pivotTol,
+                                                   params.pivotSelection == CglLandP::initialReducedCosts);
+#if 0
+            plotCGLPobj(direction, params.pivotTol, params.pivotTol, true, true, false);
+            exit(1);
+#endif
+            if (leaving >= 0)
+            {
+                if (params.pivotSelection == CglLandP::mostNegativeRc ||
+                        (params.pivotSelection == CglLandP::initialReducedCosts && numPivots == 0))
+                {
+
+                    if (params.pivotSelection == CglLandP::initialReducedCosts)
+                        rowFlags_[leaving] = false;
+                    incoming = fastFindBestPivotColumn(direction, gammaSign,
+                                                       params.pivotTol, params.away,
+                                                       (params.sepSpace==CglLandP::Fractional),
+                                                       allowDegeneratePivot,
+                                                       bestSigma, false//params.modularize
+                                                      );
+                    while (incoming < 0 && !optimal &&
+                            nRowFailed < maxTryRow)   // if no improving was found rescan the tables of reduced cost to find a good one
+                    {
+                        if (incoming == -1 || params.countMistakenRc) nRowFailed ++;
+                        rowFlags_[leaving] = false;
+                        hasFlagedRow = true;
+                        leaving = rescanReducedCosts(direction, gammaSign, params.pivotTol);
+                        if (leaving >= 0)
+                        {
+                            incoming = fastFindBestPivotColumn(direction, gammaSign,
+                                                               params.pivotTol,
+                                                               params.away,
+                                                               (params.sepSpace==CglLandP::Fractional),
+                                                               allowDegeneratePivot,
+                                                               bestSigma, false//params.modularize
+                                                              );
+                        }
+                        else optimal = true;
+                    }
+                }
+                else if (params.pivotSelection == CglLandP::bestPivot)
+                {
+                    incoming = findBestPivot(leaving, direction, params);
+                }
+            }
+        }
+        else if (params.pivotSelection == CglLandP::initialReducedCosts)
+        {
+            assert(numPivots > 0);
+            while (incoming < 0 && !optimal)   // if no improving was found rescan the tables of reduced cost to find a good one
+            {
+                if (!hasFlagedRow)
+                    hasFlagedRow = true;
+                leaving = rescanReducedCosts(direction, gammaSign, params.pivotTol);
+                rowFlags_[leaving] = false;
+                if (leaving >= 0)
+                {
+                    incoming = fastFindBestPivotColumn(direction, gammaSign,
+                                                       params.pivotTol,
+                                                       params.away,
+                                                       (params.sepSpace==CglLandP::Fractional),
+                                                       allowDegeneratePivot,
+                                                       bestSigma, false//params.modularize
+                                                      );
+                }
+                else optimal = true;
+            }
+        }
+        if (leaving >= 0)
+        {
+            if ( incoming >= 0 && !optimal)
+            {
+                if (inDegenerateSequence_)   //flag leaving row
+                {
+                    numberConsecutiveDegenerate++;
+                    allowDegeneratePivot = numberConsecutiveDegenerate < params.degeneratePivotLimit;
+                    rowFlags_[leaving] = false;
+                }
+                else
+                {
+                    beObstinate = 0;
+                    numberConsecutiveDegenerate = 0;
+                    allowDegeneratePivot = numberConsecutiveDegenerate < params.degeneratePivotLimit;
+                }
+                double gamma = - row_k_[nonBasics_[incoming]] / row_i_[nonBasics_[incoming]];
+#ifdef COIN_HAS_OSICLP
+                if (numPivots && ( numPivots % 40 == 0 ) && clp_)
+                {
+                    clp_->getModelPtr()->factorize();
+                }
+#endif
+
+#ifndef OLD_COMPUTATION
+                bool recompute_source_row = (numPivots && (numPivots % 10 == 0 ||
+                                            fabs(gamma) < 1e-05));
+#endif
+
+                std::pair<int, int> cur_pivot(nonBasics_[incoming],basics_[leaving]);
+
+                bool pivoted = changeBasis(incoming,leaving,direction,
+#ifndef OLD_COMPUTATION
+                                           recompute_source_row, 
+#endif
+                                           false);//params.modularize);
+
+                if (leaving == row)
+                {
+                    numSourceRowEntered_++;
+                }
+
+                if (params.generateExtraCuts == CglLandP::WhenEnteringBasis &&
+                        basics_[leaving] < ncols_ && cuts_.numberCuts() < params.extraCutsLimit)
+                    generateExtraCut(leaving, cached, params);
+                if (pivoted)
+                {
+                    numPivots++;
+
+                    double lastSigma = sigma_;
+                    if (params.modularize)
+                    {
+		      row_k_.modularize(integers_);
+                    }
+                    sigma_ = computeCglpObjective(row_k_);
+
+                    if (sigma_ - lastSigma > -1e-4*(lastSigma))
+                    {
+                      if(sigma_ > 0) return 0;
+#if 0
+		      if (sigma_ > 0 || sigma_ - lastSigma > 1e1*(-lastSigma))
+			return 0;
+#endif
+                    }
+
+
+                    handler_->message(PivotLog,messages_)<<numPivots<<sigma_<<
+                    nonBasics_[incoming]<<basics_[leaving]<<direction<<gamma<<inDegenerateSequence_<<CoinMessageEol<<CoinMessageEol;
+                }
+                else   //pivot failed
+                {
+                    numFailedPivots++;
+                    //check wether sigma has changed if it has exit cut generation if it has not continue
+                    double lastSigma = sigma_;
+                    sigma_ = computeCglpObjective(row_k_);
+                    if ( sigma_-lastSigma>1e-8)
+                    {
+                        handler_->message(PivotFailedSigmaIncreased,messages_)<<CoinMessageEol<<CoinMessageEol;
+                        //break;
+                        return 0;
+                    }
+                    handler_->message(PivotFailedSigmaUnchanged,messages_)<<CoinMessageEol<<CoinMessageEol;
+                    numFailedPivots = params.failedPivotLimit + 1;
+                    return 0;
+                    if (numFailedPivots > params.failedPivotLimit)
+                        break;
+
+                }
+            }
+            else   //attained max number of leaving vars tries with no improvement
+            {
+                handler_->message(WarnGiveUpRow,messages_)<<nRowFailed<<CoinMessageEol<<CoinMessageEol;
+                break;
+            }
+        }
+        else
+        {
+            if (hasFlagedRow && beObstinate)
+            {
+                //Reset row flags
+                CoinFillN(rowFlags_,nrows_,true);
+                hasFlagedRow = false;
+                if (inDegenerateSequence_)
+                {
+                    allowDegeneratePivot = false;
+                    beObstinate = false;
+                }
+            }
+            else
+            {
+                //could perturb but Ionut skipped that will see later
+                optimal = true;
+                handler_->message(FinishedOptimal, messages_)<<sigma_<<numPivots<<CoinMessageEol<<CoinMessageEol;
+            }
+        }
+    }
+
+    if (!optimal && numPivots >= params.pivotLimit)
+    {
+        std::string limit="pivots";
+        handler_->message(HitLimit, messages_)<<limit<<numPivots<<CoinMessageEol<<CoinMessageEol;
+    }
+    if (!optimal && numFailedPivots >= params.failedPivotLimit)
+    {
+        std::string limit="failed pivots";
+        handler_->message(HitLimit, messages_)<<limit<<numPivots<<CoinMessageEol<<CoinMessageEol;
+    }
+    //Create the cut
+
+    //pullTableauRow(row_k_);
+    //row_k_.rhs = row_k_.rhs - floor(row_k_.rhs);
+
+    //  double normalization = 100*normCoef(row_k_);
+    {
+        if (params.strengthen || params.modularize)
+            createMIG(row_k_, cut);
+        else
+            createIntersectionCut(row_k_, cut);
+    }
+
+    if (params.generateExtraCuts == CglLandP::AtOptimalBasis)
+    {
+        generateExtraCuts(cached, params);
+    }
+    handler_->message(CutStat, messages_)<<row<<numPivots
+    <<numSourceRowEntered_ - saveNumSourceEntered
+    <<numIncreased_- saveNumIncreased
+    <<numCycle<<CoinMessageEol;
+    return 1;//At this point nothing failed, always generate a cut
+}
+
+
+bool
+CglLandPSimplex::changeBasis(int incoming, int leaving, int leavingStatus,
+#ifndef OLD_COMPUTATION
+                             bool recompute_source_row,
+#endif
+                             bool modularize)
+{
+    double infty = si_->getInfinity();
+    int clpLeavingStatus = leavingStatus;
+
+#ifdef COIN_HAS_OSICLP
+    if (clp_)
+    {
+        if (basics_[leaving] >= ncols_)
+            clpLeavingStatus = - leavingStatus;
+    }
+#endif
+
+    int code = 0;
+
+    code = si_->pivot(nonBasics_[incoming],basics_[leaving], clpLeavingStatus);
+    if (code)
+    {
+#ifdef OLD_COMPUTATION
+        if (!modularize)
+        {
+            pullTableauRow(row_k_);
+            row_k_.rhs = row_k_.rhs - floor(row_k_.rhs);
+        }
+	else{
+	  int & indexLeaving = basics_[leaving];
+	  if (leavingStatus==1)
+	  {
+	    setColsolToCut(indexLeaving, getUpBound(indexLeaving) - getColsolToCut(indexLeaving));
+	  }
+	else
+	  {
+	    setColsolToCut(indexLeaving, getColsolToCut(indexLeaving) + getLoBound(indexLeaving));
+	  }
+        }
+#endif
+        return 0;
+    }
+    numPivots_ ++;
+    //swap bounds
+    int & indexLeaving = basics_[leaving];
+#ifdef OLD_COMPUTATION
+    if (!modularize)
+      {
+	if (leavingStatus==1)
+	  {
+	    setColsolToCut(indexLeaving, getUpBound(indexLeaving) - getColsolToCut(indexLeaving));
+	  }
+	else
+	  {
+	    setColsolToCut(indexLeaving, getColsolToCut(indexLeaving) - getLoBound(indexLeaving));
+	  }
+      }
+#endif
+    
+    if (indexLeaving < ncols_)
+      {
+	basis_->setStructStatus(indexLeaving, leavingStatus==1 ? CoinWarmStartBasis::atUpperBound : CoinWarmStartBasis::atLowerBound);
+      }
+    else
+      {
+	int iRow = basics_[leaving] - ncols_;
+	basis_->setArtifStatus(iRow,  leavingStatus==1 ? CoinWarmStartBasis::atUpperBound : CoinWarmStartBasis::atLowerBound);
+	//    assert(leavingStatus==-1 || (rowLower_[iRow]>-1e50 && rowUpper_[iRow] < 1e50));
+      }
+    
+    if (nonBasics_[incoming] < ncols_)
+      {
+	int & indexIncoming = nonBasics_[incoming];
+	CoinWarmStartBasis::Status status = basis_->getStructStatus(indexIncoming);
+	if (status==CoinWarmStartBasis::atUpperBound)
+	  setColsolToCut(indexIncoming, getUpBound(indexIncoming) - getColsolToCut(indexIncoming));
+	else
+	  setColsolToCut(indexIncoming, getColsolToCut(indexIncoming) + getLoBound(indexIncoming));
+	basis_->setStructStatus(indexIncoming, CoinWarmStartBasis::basic);
+      }
+    else
+      {
+	int iRow = nonBasics_[incoming] - ncols_;
+	int & indexIncoming = nonBasics_[incoming];
+	
+	if (basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atUpperBound)
+	  setColsolToCut(indexIncoming, getUpBound(indexIncoming) - getColsolToCut(indexIncoming));
+	else
+	  setColsolToCut(indexIncoming, getColsolToCut(indexIncoming) + getLoBound(indexIncoming));
+	
+	basis_->setArtifStatus(iRow,  CoinWarmStartBasis::basic);
+      }
+    
+    int swap = basics_[leaving];
+    basics_[leaving] = nonBasics_[incoming];
+    nonBasics_[incoming] = swap;
+    //update solution of leaving variable
+    colsol_[nonBasics_[incoming]] = 0;
+    
+    //update solution for basics
+    const double * lpSol = si_->getColSolution();
+    const double * rowAct = si_->getRowActivity();
+    const double * rowLower = si_->getRowLower();
+    const double * rowUpper = si_->getRowUpper();
+
+    for (int i = 0 ; i < nrows_ ; i++)
+    {
+        int& iCol = basics_[i];
+        if (iCol<ncols_)
+            colsol_[iCol] = lpSol[iCol];
+        else   // Osi does not give direct acces to the value of slacks
+        {
+            int iRow = iCol - ncols_;
+            colsol_[iCol] = - rowAct[iRow];
+            if (rowLower[iRow]> -infty)
+            {
+                colsol_[iCol] += rowLower[iRow];
+            }
+            else
+            {
+                colsol_[iCol] += rowUpper[iRow];
+            }
+        }
+    }
+
+    // basics_ may unfortunately change reload
+    int k = basics_[row_k_.num];
+    si_->getBasics(basics_);
+    if (basics_[row_k_.num] != k)
+    {
+        for (int ii = 0 ; ii < nrows_ ; ii++)
+        {
+            if (basics_[ii]==k)
+            {
+                row_k_.num= ii;
+                break;
+            }
+        }
+    }
+
+#ifndef OLD_COMPUTATION
+    if (!modularize && recompute_source_row)
+    {
+#else
+    if (!modularize)
+    {
+#endif
+        pullTableauRow(row_k_);
+        row_k_.rhs =  row_k_.rhs - floor(row_k_.rhs);
+    }
+#if 0
+}
+#endif
+else //Update row k by hand
+{
+    double gamma = - row_k_[basics_[leaving]] / row_i_[basics_[leaving]];
+    row_k_[basics_[leaving]] = 0;
+    row_k_.quickAdd(nonBasics_[incoming], gamma);
+    if(1 || fabs(gamma) > 1e-9){
+      int nnz = row_i_.getNumElements();
+      const int * indices = row_i_.getIndices();
+      for (int i = 0 ; i < nnz; i++)
+	{
+	  if(row_k_.getNumElements() > row_k_.capacity() - 2) row_k_.scan();
+	  if (indices[i] != nonBasics_[incoming] && indices[i] != basics_[leaving])
+	    row_k_.quickAdd(indices[i], gamma * row_i_[indices[i]]);
+	}
+      row_k_.rhs += gamma * row_i_.rhs;
+    }
+    row_k_.scan();
+    row_k_.clean(1e-10);
+    checkVec(row_k_);
+#if 0
+    TabRow test_row(this);
+    int rowsize = ncols_orig_ + nrows_orig_ + 1;
+    test_row.reserve(rowsize);
+    test_row.num = row_k_.num;
+    pullTableauRow(test_row);
+    test_row.rhs =  test_row.rhs - floor(test_row.rhs);
+    VecModEqAssert(row_k_, test_row);
+#endif
+}
+    
+    return true;
+}
+
+/** Find a row which can be used to perform an improving pivot return index of the cut or -1 if none exists
+ * (i.e., find the leaving variable).*/
+int
+CglLandPSimplex::findCutImprovingPivotRow( int &direction, int &gammaSign, double tolerance)
+{
+    bool bestRed = 0;
+    tolerance = -10*tolerance;
+    int bestRow = -1;
+    int bestDirection = 0;
+    int bestGamma = 0;
+    double infty = si_->getInfinity();
+    for (row_i_.num = 0 ; row_i_.num < nrows_; row_i_.num++)
+    {
+        //if ( (row_k_.modularized_ || row_i_.num != row_k_.num)//obviously not necessary to combine row k with itself (unless modularized)
+        if ( (row_i_.num != row_k_.num)//obviously not necessary to combine row k with itself (unless modularized)
+                && rowFlags_[row_i_.num] //row has not been flaged
+                //   && fabs(getUpBound(basics_[row_i_.num]) - getLoBound(basics_[row_i_.num]))>1e-09 //variable is not fixed
+           )
+        {
+            pullTableauRow(row_i_);
+            double tau = computeRedCostConstantsInRow();
+
+            if (getLoBound(basics_[row_i_.num]) > -infty)
+                // variable can leave at its lower bound
+                //Compute reduced cost with basics_[i] value decreasing
+            {
+                direction = -1;
+
+                gammaSign = -1;
+                double redCost = computeCglpRedCost(direction, gammaSign, tau);
+                if (redCost<tolerance)
+                {
+                    if (bestRed)
+                    {
+                        tolerance = redCost;
+                        bestRow = row_i_.num;
+                        bestDirection = direction;
+                        bestGamma = gammaSign;
+                    }
+                    else return row_i_.num;
+                }
+                gammaSign = 1;
+                redCost = computeCglpRedCost(direction, gammaSign, tau);
+                if (redCost<tolerance)
+                {
+                    if (bestRed)
+                    {
+                        tolerance = redCost;
+                        bestRow = row_i_.num;
+                        bestDirection = direction;
+                        bestGamma = gammaSign;
+                    }
+                    else return row_i_.num;
+                }
+            }
+            if ( getUpBound(basics_[row_i_.num])<infty) // variable can leave at its upper bound
+                //Compute reduced cost with basics_[i] value decreasing
+            {
+                direction = 1;
+                //         adjustTableauRow(i_, row_i_, rhs_i_, direction);
+                gammaSign = -1;
+                double redCost = computeCglpRedCost(direction, gammaSign, tau);
+                if (redCost<tolerance)
+                {
+                    if (bestRed)
+                    {
+                        tolerance = redCost;
+                        bestRow = row_i_.num;
+                        bestDirection = direction;
+                        bestGamma = gammaSign;
+                    }
+                    else return row_i_.num;
+                }
+                gammaSign = 1;
+                redCost = computeCglpRedCost(direction, gammaSign, tau);
+                if (redCost<tolerance)
+                {
+                    if (bestRed)
+                    {
+                        tolerance = redCost;
+                        bestRow = row_i_.num;
+                        bestDirection = direction;
+                        bestGamma = gammaSign;
+                    }
+                    else return row_i_.num;
+                }
+            }
+            rowFlags_[row_i_.num]=false;
+        }
+    }
+    direction = bestDirection;
+    gammaSign = bestGamma;
+    row_i_.num=bestRow;
+    if (row_i_.num >=0 && row_i_.num != bestRow)
+    {
+        row_i_.num=bestRow;
+        pullTableauRow(row_i_);
+    }
+    assert (bestRow<0||direction!=0); 
+    return bestRow;
+}
+
+
+/** Find a row which can be used to perform an improving pivot the fast way
+ * (i.e., find the leaving variable).
+ \return index of the cut or -1 if none exists. */
+int
+CglLandPSimplex::fastFindCutImprovingPivotRow( int &direction, int &gammaSign,
+        double tolerance, bool flagPositiveRows)
+{
+    bool modularize = false;
+    double sigma = sigma_ /rhs_weight_;
+    //Fill vector to compute contribution to reduced cost of variables in M1 and M2 (nz non-basic vars in row_k_.row).
+    // 1. Put the values
+    // 2. Post multiply by basis inverse
+    double * rWk1bis_ =NULL;
+    CoinFillN(&rWk1_[0],nrows_,static_cast<double> (0));
+    if (modularize)
+        CoinFillN(rWk1bis_, nrows_, static_cast<double> (0));
+    int capacity = 0;
+    const CoinPackedMatrix* mat = si_->getMatrixByCol();
+
+    const CoinBigIndex* starts = mat->getVectorStarts();
+    const CoinBigIndex * lengths = mat->getVectorLengths();
+    const int * indices = mat->getIndices();
+    const double * elements = mat->getElements();
+
+    for (unsigned int i = 0 ;  i < M1_.size() ; i++)
+    {
+        const int& ii = M1_[i];
+        if (ii < ncols_)
+        {
+            const CoinBigIndex& begin = starts[ii];
+            const CoinBigIndex end = begin + lengths[ii];
+            bool swap = false;
+            if (basis_->getStructStatus(ii)==CoinWarmStartBasis::atUpperBound) swap = true;
+            for (CoinBigIndex k = begin ; k < end ;  k++)
+            {
+                if (swap)
+                {
+                    rWk1_[indices[k]] += normedCoef(elements[k] * sigma, ii);
+                    if (modularize)
+                    {
+                        rWk1bis_[indices[k]] += elements[k] * (getColsolToCut(ii) - normedCoef(sigma, ii));
+                    }
+
+                }
+                else
+                {
+                    rWk1_[indices[k]] -= normedCoef(elements[k] * sigma, ii);
+                    if (modularize)
+                    {
+                        rWk1bis_[indices[k]] -= elements[k] * (getColsolToCut(ii) - normedCoef(sigma, ii));
+                    }
+                }
+            }
+        }
+        else
+        {
+            bool swap = false;
+            if (basis_->getArtifStatus(ii - ncols_orig_)==CoinWarmStartBasis::atUpperBound) swap = true;
+            if (swap)
+            {
+                rWk1_[ii - ncols_] += normedCoef(sigma, ii);
+                if (modularize)
+                {
+                    rWk1bis_[ii - ncols_] += (getColsolToCut(ii) - normedCoef(sigma, ii));
+                }
+            }
+            else
+            {
+                rWk1_[ii - ncols_] -= normedCoef(sigma, ii);
+                if (modularize)
+                {
+                    rWk1bis_[ii - ncols_] -= (getColsolToCut(ii) - normedCoef(sigma, ii));
+                }
+            }
+        }
+    }
+    for (unsigned int i = 0 ;  i < M2_.size(); i++)
+    {
+        const int& ii = M2_[i];
+        if (ii<ncols_)
+        {
+            const CoinBigIndex& begin = starts[ii];
+            const CoinBigIndex end = begin + lengths[ii];
+            bool swap = false;
+            if (basis_->getStructStatus(ii)==CoinWarmStartBasis::atUpperBound) swap = true;
+            for (CoinBigIndex k = begin ; k < end ;  k++)
+            {
+                if (swap)
+                {
+                    rWk1_[indices[k]] += elements[k] * (getColsolToCut(ii) - normedCoef(sigma, ii));
+                    if (modularize)
+                        rWk1bis_[indices[k]] += elements[k] * normedCoef(sigma, ii);
+                }
+                else
+                {
+                    rWk1_[indices[k]] -= elements[k] * (getColsolToCut(ii) - normedCoef(sigma, ii));
+                    if (modularize)
+                        rWk1bis_[indices[k]] -= elements[k] * normedCoef(sigma, ii);
+                }
+            }
+        }
+        else
+        {
+            bool swap = false;
+            if (basis_->getArtifStatus(M2_[i] - ncols_orig_)==CoinWarmStartBasis::atUpperBound) swap = true;
+            if (swap)
+            {
+                rWk1_[ii - ncols_] += (getColsolToCut(ii) - normedCoef(sigma, ii));
+                if (modularize)
+                    rWk1bis_[ii - ncols_] += normedCoef(sigma, ii);
+            }
+            else
+            {
+                rWk1_[ii - ncols_] -= (getColsolToCut(ii) - normedCoef(sigma, ii));
+                if (modularize)
+                    rWk1bis_[ii - ncols_] -= normedCoef(sigma, ii);
+            }
+        }
+    }
+
+    for (int i = 0 ; i < nrows_ ; i++)
+    {
+        if (rWk1_[i])
+            rIntWork_[capacity++] = i;
+    }
+    CoinIndexedVector indexed;
+    indexed.borrowVector(nrows_, capacity, &rIntWork_[0], &rWk1_[0]);
+
+#ifdef COIN_HAS_OSICLP
+    if (clp_)
+        clp_->getBInvACol(&indexed);
+    else
+#endif
+        throw CoinError("Function not implemented in this OsiSolverInterface",
+                        "getBInvACol","CglLandpSimplex");
+    indexed.returnVector();
+    if (modularize)
+    {
+        capacity = 0;
+        for (int i = 0 ; i < nrows_ ; i++)
+        {
+            if (rWk1bis_[i])
+                rIntWork_[capacity++] = i;
+        }
+
+        indexed.borrowVector(nrows_, capacity, &rIntWork_[0], rWk1bis_);
+#ifdef COIN_HAS_OSICLP
+        if (clp_)
+            clp_->getBInvACol(&indexed);
+        else
+#endif
+            indexed.returnVector();
+    }
+    //Now compute the contribution of the variables in M3_
+    //Need to get the column of the tableau in rW3_ for each of these and
+    //add up with correctly in storage for multiplier for negative gamma (named rW3_) and
+    //for positive gamma (which is named rW4_)
+    if (!M3_.empty())
+    {
+        CoinFillN(&rWk3_[0],nrows_,0.);
+        CoinFillN(&rWk4_[0],nrows_,0.);
+        if (modularize)
+        {
+            double * rWk3bis_ = NULL;
+            double * rWk4bis_ = NULL;
+            CoinFillN(rWk3bis_,nrows_,0.);
+            CoinFillN(rWk4bis_,nrows_,0.);
+        }
+    }
+    for (unsigned int i = 0 ; i < M3_.size() ; i++)
+    {
+        const int & ii = M3_[i];
+        si_->getBInvACol(ii, &rWk2_[0]);
+        bool swap = false;
+        if (ii < ncols_orig_ && basis_->getStructStatus(ii)==CoinWarmStartBasis::atUpperBound) swap = true;
+        if (ii >= ncols_orig_ && basis_->getArtifStatus(ii - ncols_orig_)==CoinWarmStartBasis::atUpperBound) swap = true;
+
+        for (int j = 0 ; j < nrows_ ; j++)
+        {
+            if (swap)
+                rWk2_[j] = - rWk2_[j];
+            if (rWk2_[j] > 0.)
+            {
+                //is in M1 for multiplier with negative gamma
+                rWk3_[j] -= normedCoef(sigma*rWk2_[j], ii);
+                //is in M2 for multiplier with positive gamma
+                rWk4_[j] -= (getColsolToCut(ii) - normedCoef(sigma, ii))*rWk2_[j];
+            }
+            else if (rWk2_[j] < 0.)
+            {
+                //is in M2 for multiplier with negative gamma
+                rWk3_[j] -=(getColsolToCut(ii) - normedCoef(sigma, ii))*rWk2_[j];
+
+                //is in M1 for multiplier with positive gamma
+                rWk4_[j] -= normedCoef(sigma, ii)*rWk2_[j];
+            }
+        }
+
+    }
+    //Now, we just need to add up everything correctly for each of the reduced
+    //cost. Compute the Tau in rWk2_ which is not used anymore then compute the reduced cost in rWk1_ for u^l_j
+    // rwk2_ in u^u_j rWk3_ for v^u_j rWk4_ for v^u_j
+    // Let's rename not to get too much confused
+    double * ul_i = &rWk1_[0];
+    double * uu_i = &rWk2_[0];
+    double * vl_i = &rWk3_[0];
+    double * vu_i = &rWk4_[0];
+    int bestRow = -1;
+    int bestDirection = 0;
+    int bestGammaSign = 0;
+    // double infty = si_->getInfinity();
+
+
+    nNegativeRcRows_ = 0;//counter
+    int nZeroRc = 0;
+    int nPositiveRc = 0;
+
+    double fzero = getColsolToCut(basics_[row_k_.num]) - floor(getColsolToCut(basics_[row_k_.num]));
+    //    fzero = row_k_.rhs;
+    //for (int i = 0 ; i < ncols_orig_ ; i++) {
+    //  fzero -= getColsolToCut(nonBasics_[i]) * row_k_[nonBasics_[i]];
+    //}
+
+    double bestReducedCost = -tolerance;
+    for (int i = 0 ; i < nrows_ ; i++)
+    {
+      //if ((!row_k_.modularized_ && i == row_k_.num)//obviously not necessary to combine row k with itself
+        if ((i == row_k_.num)//obviously not necessary to combine row k with itself
+                //   && fabs(getUpBound(basics_[row_i_.num]) - getLoBound(basics_[row_i_.num]))>1e-09 //variable is not fixed
+                || col_in_subspace[basics_[i]] == false
+           )
+        {
+            ul_i[i]=uu_i[i]=vl_i[i]=vu_i[i]=10.;
+            rowFlags_[i] = false;
+            continue;
+        }
+
+        double tau1 = rWk1_[i];
+        double tau2 = rWk1_[i];
+        double tau3 = rWk1_[i];
+        double tau4 = rWk1_[i];
+        if (!M3_.empty())
+        {
+            tau1 += rWk3_[i];
+            tau2 += rWk4_[i];
+            tau3 += rWk4_[i];
+            tau4 += rWk3_[i];
+        }
+        if (modularize)
+        {
+            tau1 = rWk1_[i] + rWk3_[i];
+            tau2 = rWk1bis_[i] + rWk3_[i];
+            tau3 = - rWk1_[i] - rWk4_[i];
+            tau4 = - rWk1bis_[i] - rWk3_[i];
+        }
+
+
+        double redCost;
+        bool hasNegativeRc = false;
+
+        double loBound = getLoBound(basics_[i]);
+
+        if (loBound > -1e50)
+        {
+            redCost = - normedCoef(sigma,basics_[i]) + (tau1)
+                      + (1 - fzero) * ( colsol_[basics_[i]]
+                                        - loBound);
+
+
+            if (redCost < -tolerance)
+            {
+                ul_i[i] = redCost;
+                hasNegativeRc = true;
+            }
+            else
+            {
+                if (fabs(redCost) < tolerance) nZeroRc++;
+                else nPositiveRc ++;
+                ul_i[i] = 10.;
+            }
+            if (redCost < bestReducedCost
+                    && rowFlags_[i] )   //row has not been flaged
+            {
+                bestDirection = -1;
+                bestGammaSign = -1;
+                bestReducedCost = redCost;
+                bestRow = i;
+            }
+
+
+            redCost = -normedCoef(sigma,basics_[i]) - (tau2)
+                      - (1 - fzero) * ( colsol_[basics_[i]]
+                                        - loBound)
+                      - loBound + getColsolToCut(basics_[i]);
+
+            if (redCost < -tolerance)
+            {
+                vl_i[i] = redCost;
+                hasNegativeRc = true;
+            }
+            else
+            {
+                if (fabs(redCost) < tolerance) nZeroRc++;
+                else nPositiveRc ++;
+                vl_i[i]=10.;
+            }
+
+            if (redCost < bestReducedCost
+                    && rowFlags_[i])   //row has not been flaged
+            {
+                bestDirection = -1;
+                bestGammaSign = 1;
+                bestReducedCost = redCost;
+                bestRow = i;
+            }
+
+
+
+        }
+        else
+        {
+            ul_i[i] = 10.;
+            vl_i[i] = 10.;
+        }
+        double upBound = getUpBound(basics_[i]);
+        if (getUpBound(basics_[i]) < 1e50)
+        {
+            redCost = - normedCoef(sigma,basics_[i]) - (tau3)
+                      + (1 - fzero) * ( - colsol_[basics_[i]]
+                                        + upBound);
+
+            if (redCost < -tolerance)
+            {
+                uu_i[i] = redCost;
+                hasNegativeRc = true;
+            }
+            else
+            {
+                if (fabs(redCost) < tolerance) nZeroRc++;
+                else nPositiveRc ++;
+                uu_i[i] = 10.;
+            }
+
+            if (redCost < bestReducedCost
+                    && rowFlags_[i])   //row has not been flaged
+            {
+                bestDirection = 1;
+                bestGammaSign = -1;
+                bestReducedCost = redCost;
+                bestRow = i;
+            }
+
+            redCost = -normedCoef(sigma,basics_[i]) + (tau4)
+                      - (1 - fzero) * ( - colsol_[basics_[i]]
+                                        + upBound)
+                      + upBound - getColsolToCut(basics_[i]);
+
+            if (redCost < -tolerance)
+            {
+                vu_i[i] = redCost;
+                hasNegativeRc = true;
+            }
+
+
+            else
+            {
+                if (fabs(redCost) < tolerance) nZeroRc++;
+                else nPositiveRc ++;
+                vu_i[i] = 10.;
+            }
+
+            if (redCost < bestReducedCost
+                    && rowFlags_[i])   //row has not been flaged
+            {
+                bestDirection = 1;
+                bestGammaSign = 1;
+                bestReducedCost = redCost;
+                bestRow = i;
+            }
+        }
+        else
+        {
+            uu_i[i] = 10.;
+            vu_i[i] = 10.;
+        }
+        if (hasNegativeRc) nNegativeRcRows_ ++;
+        else if (flagPositiveRows) rowFlags_[i] = false;
+    }
+    handler_->message(NumberNegRc, messages_)<<nNegativeRcRows_<<CoinMessageEol;
+    handler_->message(NumberZeroRc, messages_)<<nZeroRc<<CoinMessageEol;
+    handler_->message(NumberPosRc, messages_)<<nPositiveRc<<CoinMessageEol;
+    //  throw -1;
+    direction = bestDirection;
+    gammaSign = bestGammaSign;
+    //  row_i_.num=bestRow;
+    if (bestRow != -1)
+    {
+        chosenReducedCostVal_ = bestReducedCost;
+        row_i_.num=bestRow;
+        pullTableauRow(row_i_);
+        handler_->message(FoundImprovingRow, messages_)<<
+        bestRow<<basics_[bestRow]<<direction<<gammaSign<<bestReducedCost
+        <<CoinMessageEol;
+    }
+    assert (bestRow<0||direction!=0); 
+    return bestRow;
+}
+
+
+/** Find a row which can be used to perform an improving pivot tables are already filled.
+ \return index of the cut or -1 if none exists. */
+int
+CglLandPSimplex::rescanReducedCosts( int &direction, int &gammaSign, double tolerance)
+{
+    // The reduced cost are already here in rWk1_ is u^l_j
+    // rwk2_ is u^u_j rWk3_ is v^u_j rWk4_ is v^u_j
+    // Let's rename not to get too much confused
+    double * ul_i = &rWk1_[0];
+    double * uu_i = &rWk2_[0];
+    double * vl_i = &rWk3_[0];
+    double * vu_i = &rWk4_[0];
+    int bestRow = -1;
+    int bestDirection = 0;
+    int bestGammaSign = 0;
+    // double infty = si_->getInfinity();
+    double bestReducedCost = -tolerance;
+    for (int i = 0 ; i < nrows_ ; i++)
+    {
+        if (i == row_k_.num//obviously not necessary to combine row k with itself
+                || !rowFlags_[i] //row has not been flaged
+                //   && fabs(getUpBound(basics_[row_i_.num]) - getLoBound(basics_[row_i_.num]))>1e-09 //variable is not fixed
+           )
+            continue;
+
+        if (ul_i[i] < bestReducedCost
+                && rowFlags_[i])   //row has not been flaged
+        {
+            bestDirection = -1;
+            bestGammaSign = -1;
+            bestReducedCost = ul_i[i];
+            bestRow = i;
+        }
+
+        if (vl_i[i] < bestReducedCost
+                && rowFlags_[i])   //row has not been flaged
+        {
+            bestDirection = -1;
+            bestGammaSign = 1;
+            bestReducedCost = vl_i[i];
+            bestRow = i;
+        }
+
+
+        if (uu_i[i] < bestReducedCost
+                && rowFlags_[i])   //row has not been flaged
+        {
+            bestDirection = 1;
+            bestGammaSign = -1;
+            bestReducedCost = uu_i[i];
+            bestRow = i;
+        }
+        if (vu_i[i] < bestReducedCost
+                && rowFlags_[i])   //row has not been flaged
+        {
+            bestDirection = 1;
+            bestGammaSign = 1;
+            bestReducedCost = vu_i[i];
+            bestRow = i;
+        }
+
+    }
+    direction = bestDirection;
+    gammaSign = bestGammaSign;
+    //  row_i_.num=bestRow;
+    if (bestRow != -1)
+    {
+        chosenReducedCostVal_ = bestReducedCost;
+        row_i_.num=bestRow;
+        pullTableauRow(row_i_);
+        handler_->message(FoundImprovingRow, messages_)<<
+        bestRow<<basics_[bestRow]<<direction<<gammaSign<<bestReducedCost
+        <<CoinMessageEol;
+    }
+    assert (bestRow<0||direction!=0); 
+    return bestRow;
+}
+
+
+void
+CglLandPSimplex::compute_p_q_r_s(double gamma, int gammaSign, double &p, double & q, double & r , double &s)
+{
+    for (int i = 0 ; i < ncols_ ; i++)
+    {
+        const int &ii = nonBasics_[i];//True index
+        if (colCandidateToLeave_[i]==false) continue;
+        const double& val = getColsolToCut(ii); //value in solution to cut
+        const double& row_k = row_k_[ii]; // coefficient in row k
+        const double& row_i = row_i_[ii]; // coefficient in row i
+        double coeff = row_k + gammaSign * gamma*row_i;
+        if (coeff>0.)
+        {
+            if (gammaSign > 0)
+            {
+                p += row_k * val;
+            }
+            else
+            {
+                //        if(fabs(getColsolToCut(nonBasics_[i])) > 0)
+                {
+                    p += row_k * val;
+                    q += row_i * val;
+                }
+            }
+            r += normedCoef(row_k, ii) ;
+            s += normedCoef(row_i, ii);
+        }
+        else if (coeff< 0.)
+        {
+            if (gammaSign > 0)
+            {
+                q -= row_i * val;
+            }
+            r -= normedCoef(row_k,ii);
+            s -= normedCoef(row_i,ii);
+        }
+        else
+        {
+            if (gammaSign > 0 && row_i < 0)
+            {
+                q -= row_i * val;
+            }
+            else if (gammaSign < 0 && row_i < 0)
+            {
+                q += row_i * val;
+            }
+            s += normedCoef(gammaSign*fabs(row_i),ii);
+        }
+    }
+}
+
+//  double f_plus(double gamma, int gammaSign){
+//  double num = row_k_.
+//  for(int i = 0 ; i < ncols_ ; i++){
+//  }
+//}
+
+/** Find the column which leads to the best cut (i.e., find incoming variable).*/
+int
+CglLandPSimplex::fastFindBestPivotColumn(int direction, int gammaSign,
+        double pivotTol, double rhsTol,
+        bool reducedSpace, bool allowDegenerate,
+        double & bestSigma, bool modularize)
+{
+    gammas_.clear();
+    pivotTol = 1e-05;
+    adjustTableauRow(basics_[row_i_.num], row_i_, direction);
+
+    double fzero = getColsolToCut(basics_[row_k_.num]) - floor(getColsolToCut(basics_[row_k_.num]));
+
+ 
+
+    double p = 0;
+    double q = 0;
+    if(!modularize){//Take a shortcut
+      p = -row_k_.rhs * (1 - fzero);
+      q = row_i_.rhs * fzero;
+      
+      if (gammaSign < 0){
+	q -= row_i_.rhs;
+      }
+    }
+    double r = 1.;
+    double s = normedCoef( static_cast<double> (gammaSign), basics_[row_i_.num]);
+
+    bool haveSmallGammaPivot = false;
+    double gammaTolerance = 0;
+    if (allowDegenerate)
+        gammaTolerance = 0;
+    //fill the array with the gammas of correct sign
+    for (int i = 0 ; i < ncols_ ; i++)
+    {
+        const int &ii = nonBasics_[i];//True index
+        const double& val = getColsolToCut(ii); //value in solution to cut
+        const double& row_k = row_k_[ii]; // coefficient in row k
+        const double& row_i = row_i_[ii]; // coefficient in row i
+        if(modularize){
+	  p-=row_k_.rhs*row_k*val;
+	  q-=row_i_.rhs*row_k*val;
+	}
+
+        if (reducedSpace && colCandidateToLeave_[i]==false)
+        {
+            assert(col_in_subspace[ii]==false);
+            continue;
+        }
+        double gamma = 1;
+        if (fabs(row_i) > gammaTolerance && fabs(row_k) > gammaTolerance)
+        {
+            gamma = - row_k/row_i;
+            if (gamma * gammaSign > gammaTolerance)
+            {
+                gammas_.insert(i,gamma*gammaSign);
+            }
+        }
+        gamma = fabs(gamma); //  we already know the sign of gamma, its absolute value is more usefull
+        if (row_k>gammaTolerance)
+        {
+            if (gammaSign > 0)
+            {
+                p += row_k * val;
+            }
+            else
+            {
+                {
+                    p += row_k * val;
+                    q += row_i * val;
+                }
+            }
+            r += normedCoef(row_k, ii) ;
+            s += normedCoef(row_i, ii);
+        }
+        else if (row_k< gammaTolerance)
+        {
+            if (gammaSign > 0)
+            {
+                q -= row_i * val;
+            }
+            r -= normedCoef(row_k,ii);
+            s -= normedCoef(row_i,ii);
+        }
+        else
+        {
+            haveSmallGammaPivot |= true;
+            if (gammaSign > 0 && row_i < 0)
+            {
+                q -= row_i * val;
+            }
+            else if (gammaSign < 0 && row_i < 0)
+            {
+                q += row_i * val;
+            }
+            s += normedCoef(gammaSign*fabs(row_i),ii);
+        }
+    }
+
+
+    if(modularize){
+      p -= row_k_.rhs * (1 - row_k_.rhs);
+      q += row_i_.rhs * row_k_.rhs;
+      if (gammaSign < 0){
+	q -= row_i_.rhs;
+      }
+    }
+
+    int n = gammas_.getNumElements();
+    if (n==0)
+    {
+        resetOriginalTableauRow(basics_[row_i_.num], row_i_, direction);
+        return -2;
+    }
+    gammas_.sortIncrElement();
+    const int* inds = gammas_.getIndices();
+    const double * elements = gammas_.getElements();
+    int bestColumn = -1;
+    double newSigma = 1e100;
+    DblEqAssert(sigma_, rhs_weight_*p/r);
+    bestSigma = sigma_ = rhs_weight_*p/r;
+    int lastValid = -1;
+#ifndef NDEBUG
+    bool rc_positive=false;
+    if (M3_.size())
+        DblEqAssert( gammaSign*(q * r - p * s)/r, chosenReducedCostVal_);
+#endif
+    if ( gammaSign*(q * r - p * s) >= 0)
+    {
+        // after recomputing reduced cost (using exact row) it is found to be >=0
+        resetOriginalTableauRow(basics_[row_i_.num], row_i_, direction);
+        return -2;
+#ifndef NDEBUG
+        rc_positive = true;
+#endif
+    }
+    for (int i = 0 ; i < n ; i++)
+    {
+        double newRhs = row_k_.rhs + gammaSign * elements[i] * row_i_.rhs;
+        if (newRhs < rhsTol || newRhs > 1 - rhsTol)
+        {
+            //	if(i == 0)
+            break;
+        }
+        newSigma = (p + gammaSign * elements[i] * q)*rhs_weight_/(r + gammaSign*elements[i] * s);
+#ifdef DEBUG_LAP
+        double alt = computeCglpObjective(gammaSign*elements[i], false);
+        DblEqAssert(newSigma, alt);
+#endif
+        if (newSigma > bestSigma - 1e-08*bestSigma)
+        {
+#ifndef NDEBUG
+
+            if (!rc_positive)
+            {
+            }
+
+
+            if (0 && elements[i] <= 1e-05)
+            {
+            }
+#endif
+            break;
+        }
+        else if (newSigma <= bestSigma)  // && colCandidateToLeave_[inds[i]])
+        {
+            bestColumn = inds[i];
+            bestSigma = newSigma;
+            lastValid = i;
+        }
+
+
+#ifndef NDEBUG
+        if (rc_positive)
+        {
+            break;
+        }
+#endif
+        int col = nonBasics_[inds[i]];
+        if (row_i_[col] *gammaSign > 0)
+        {
+            p += row_k_[col] * getColsolToCut(col);
+            q += row_i_[col] * getColsolToCut(col);
+            r += normedCoef(row_k_[col]*2,col);
+            s += normedCoef(row_i_[col]*2,col);
+        }
+        else
+        {
+            p -= row_k_[col] * getColsolToCut(col);
+            q -= row_i_[col] * getColsolToCut(col);
+            r -= normedCoef(row_k_[col]*2,col);
+            s -= normedCoef(row_i_[col]*2,col);
+        }
+        if (gammaSign*(q * r - p * s) >= 0)   /* function is starting to increase stop here*/
+        {
+#ifndef NDEBUG
+            if (0 && elements[i] <= 1e-5)
+            {
+            }
+            rc_positive = true;
+#endif
+            break;
+        }
+
+    }
+//Get the results did we find a valid pivot? is it degenerate?
+    if (bestColumn == -1)   // Apparently no pivot is within the tolerances
+    {
+        resetOriginalTableauRow(basics_[row_i_.num], row_i_, direction);
+        handler_->message(WarnFailedPivotTol, messages_)<<CoinMessageEol<<CoinMessageEol;
+        return -1;
+    }
+
+    if (fabs(row_i_[nonBasics_[bestColumn]]) < 1e-05)   // Apparently no pivot is within the tolerances
+    {
+        resetOriginalTableauRow(basics_[row_i_.num], row_i_, direction);
+        handler_->message(WarnFailedPivotTol, messages_)<<CoinMessageEol<<CoinMessageEol;
+        return -2;
+    }
+
+    //std::cout<<"Minimum of f attained at breakpoint "<<lastValid<<std::endl;
+    assert(bestSigma <= sigma_);
+#ifdef DEBUG_LAP
+    bestSigma_ = bestSigma;
+    double otherSigma= computeCglpObjective(gammaSign*elements[lastValid], false);
+    DblEqAssert(bestSigma, otherSigma);
+    DblEqAssert(bestSigma, computeCglpObjective(gammaSign*elements[lastValid], false, new_row_));
+    DblEqAssert(bestSigma, computeCglpObjective(new_row_));
+    assert(row_k_.modularized_ || row_i_.num != row_k_.num);
+#endif
+
+#ifdef OLD_COMPUTATION
+    if (!modularize)
+        resetOriginalTableauRow(basics_[row_i_.num], row_i_, direction);
+#endif
+    if (bestSigma < sigma_ - 1e-07)   //everything has gone ok
+    {
+        handler_->message(FoundBestImprovingCol, messages_)<<nonBasics_[bestColumn]<<gammaSign * elements[lastValid]<<bestSigma<<CoinMessageEol<<CoinMessageEol;
+        inDegenerateSequence_ = false;
+        assert (bestColumn<0||direction!=0); 
+        return bestColumn;
+    }
+    else if (allowDegenerate)   //Pivot is degenerate and we allow
+    {
+        inDegenerateSequence_ = true;
+        assert (bestColumn<0||direction!=0); 
+        return bestColumn;
+    }
+    else   //we don't accept a degenerate pivot
+    {
+        handler_->message(WarnFailedBestImprovingCol, messages_)<<chosenReducedCostVal_<<sigma_<<bestSigma<<CoinMessageEol<<CoinMessageEol;
+        return -1;
+    }
+}
+
+
+int
+CglLandPSimplex::findBestPivotColumn(int direction,
+                                     double pivotTol, bool reducedSpace, bool allowDegenerate, bool modularize)
+{
+    TabRow newRow(this);
+    newRow.reserve(ncols_ + nrows_);
+    int varOut=-1;
+
+    adjustTableauRow(basics_[row_i_.num], row_i_, direction);
+
+    double m = si_->getInfinity();
+
+    int j = 0;
+    double gamma = 0.;
+
+    for (; j< ncols_orig_ ; j++)
+    {
+        if (reducedSpace &&
+                !colCandidateToLeave_[j]
+           )
+            continue;
+        if (fabs(row_i_[nonBasics_[j]])< pivotTol)
+        {
+            continue;
+        }
+        gamma = - row_k_[nonBasics_[j]]/row_i_[nonBasics_[j]];
+
+
+        newRow[basics_[row_k_.num]] = 1.;
+        newRow.rhs = row_k_.rhs + gamma * row_i_.rhs;
+        if (newRow.rhs > 1e-5  && newRow.rhs < 1 - 1e-5 )
+        {
+            double m_j = computeCglpObjective(gamma, modularize, newRow);
+            if (m_j < m)
+            {
+                varOut = j;
+                m = m_j;
+            }
+        }
+    }
+    resetOriginalTableauRow(basics_[row_i_.num], row_i_, direction);
+
+    if (m < sigma_ )
+    {
+        handler_->message(FoundBestImprovingCol, messages_)<<nonBasics_[varOut]<<gamma<<m<<CoinMessageEol<<CoinMessageEol;
+        inDegenerateSequence_ = false;
+         assert (varOut<0||direction!=0);
+        return varOut;
+    }
+    else if (allowDegenerate && m<=sigma_)
+    {
+        inDegenerateSequence_ = true;
+    }
+    else
+    {
+        return -1;
+    }
+    return -1;
+}
+
+struct reducedCost
+{
+    /** To avoid computing two times the same row direction will have strange
+     values, direction is -1 or 1 if for only one of the two direction
+     rc is <0 and is -2 or 2 if the two direction have one <0 rc with the sign
+     indicating which one of the two directions is the best.<br>
+     Note that by theory only one reduced cost (for u_i, or v_i)
+     maybe negative for each direction.
+     */
+    int direction;
+    /** gammSign is the sign of gamma (corresponding to taking rc for u_i or v_i)
+     for the best of the two rc for this row.*/
+    int gammaSign;
+    /** gammaSign2 is the sign of gamma for the worst of the two rc for this row.*/
+    int gammaSign2;
+    /** if both reduced costs are <0 value is the smallest of the two.*/
+    double value;
+    /** greatest of the two reduced costs */
+    double value2;
+    /** index of the row.*/
+    int row;
+    bool operator<(const reducedCost & other) const
+    {
+        return (value>other.value);
+    }
+};
+
+/** Find incoming and leaving variables which lead to the most violated
+ adjacent normalized lift-and-project cut.
+ \remark At this point reduced costs should be already computed.
+ \return incoming variable variable,
+ \param leaving variable
+ \param direction leaving direction
+ \param numTryRows number rows tried
+ \param pivotTol pivot tolerance
+ \param reducedSpace separaration space (reduced or full)
+ \param allowNonStrictlyImproving wether or not to allow non stricly improving pivots.
+ */
+int CglLandPSimplex::findBestPivot(int &leaving, int & direction,
+                                   const CglLandP::Parameters & params)
+{
+    // 1. Sort <0 reduced costs in increasing order
+    // 2. for numTryRows reduced costs call findBestPivotColumn
+    // if better record
+
+    // The reduced cost are already here in rWk1_ is u^l_j
+    // rwk2_ is u^u_j rWk3_ is v^u_j rWk4_ is v^u_j
+    // Let's rename not to get too much confused
+    double * ul_i = &rWk1_[0];
+    double * uu_i = &rWk2_[0];
+    double * vl_i = &rWk3_[0];
+    double * vu_i = &rWk4_[0];
+
+    reducedCost * rc = new reducedCost[nNegativeRcRows_];
+    int k = 0;
+    rc[k].direction = 0;//initialize first rc
+    int k2 = 0;
+    for (int i = 0 ; i < nrows_ ; i++)
+    {
+        if (ul_i[i] < -params.pivotTol)
+            //       && rowFlags_[i]) //row has not been flaged
+        {
+            rc[k].direction = -1;
+            rc[k].gammaSign = -1;
+            rc[k].value = ul_i[i];
+            rc[k].row = i;
+            k2++;
+        }
+
+        if (vl_i[i] < -params.pivotTol)
+            //&& rowFlags_[i]) //row has not been flaged
+        {
+            rc[k].direction = -1;
+            rc[k].gammaSign = 1;
+            rc[k].value = vl_i[i];
+            rc[k].row = i;
+            k2++;
+        }
+
+
+        if (uu_i[i] < -params.pivotTol)
+            //       && rowFlags_[i]) //row has not been flaged
+        {
+            if (rc[k].direction == 0)
+            {
+                rc[k].direction = 1;
+                rc[k].gammaSign = -1;
+                rc[k].value = uu_i[i];
+                rc[k].row = i;
+            }
+            else
+            {
+                if (uu_i[i] <rc[k].value)   //this one is better
+                {
+                    rc[k].direction = 2;
+                    rc[k].gammaSign2 = rc[k].gammaSign;
+                    rc[k].gammaSign = -1;
+                    rc[k].value2 = rc[k].value;
+                    rc[k].value = uu_i[i];
+                }
+                else
+                {
+                    rc[k].direction = -2;
+                    rc[k].gammaSign2 = -1;
+                    rc[k].value2 = uu_i[i];
+                }
+            }
+            k2++;
+        }
+        if (vu_i[i] < -params.pivotTol)
+            //&& rowFlags_[i]) //row has not been flaged
+        {
+            if (rc[k].direction==0)
+            {
+                rc[k].direction = 1;
+                rc[k].gammaSign = 1;
+                rc[k].value = vu_i[i];
+                rc[k].row = i;
+            }
+            else
+            {
+                if (vu_i[i] < rc[k].value)   //this one is better
+                {
+                    rc[k].direction = 2;
+                    rc[k].gammaSign2 = rc[k].gammaSign;
+                    rc[k].gammaSign = 1;
+                    rc[k].value2 = rc[k].value;
+                    rc[k].value = vu_i[i];
+                }
+                else   //the other one is better
+                {
+                    rc[k].direction = -2;
+                    rc[k].gammaSign2 = 1;
+                    rc[k].value2 = vu_i[i];
+                }
+            }
+            k2++;
+        }
+        if (rc[k].direction!=0) //We have added a row with < 0 rc during
+            //last iteration
+        {
+            k++;
+            if (k<nNegativeRcRows_)
+                rc[k].direction = 0;
+            else
+                break;
+        }
+
+    }
+
+    assert(k==nNegativeRcRows_);
+
+    //now make a heap
+    std::make_heap(rc, rc + k);
+    //  assert(rc[0].value==chosenReducedCostVal_);
+    int bestLeaving = -1;
+    int bestIncoming = -1;
+    int bestDirection = 0;
+
+    double bestSigma = COIN_DBL_MAX;
+    double bestRc = COIN_DBL_MAX;
+    //now scan the heap
+#ifndef NDEBUG
+    int best_l = 0;
+#endif
+    int notImproved = 0;
+    for (int l = 0; l < k && l < 10  ; l++, notImproved++)
+    {
+        if (!rowFlags_[rc[l].row]) continue;//this row has been marked to be skipped
+        //     if(bestLeaving != -1 && rc[l].value > -1e-02) break;
+        if (rc[l].value > -1e-02) break;
+        row_i_.num=rc[l].row;
+        pullTableauRow(row_i_);//Get the tableau row
+
+        //compute f+ or f- for the best negative rc corresponding to this row
+        chosenReducedCostVal_ = rc[l].value;
+        double sigma;
+        int incoming =
+            fastFindBestPivotColumn
+            (rc[l].direction, rc[l].gammaSign,
+             params.pivotTol, params.away,
+             (params.sepSpace==CglLandP::Fractional),
+             0,
+             sigma, params.modularize);
+        if (incoming!=-1 && bestSigma > sigma)
+        {
+            //          std::cout<<"I found a better pivot "<<sigma - sigma_<< " for indice number "<<l<<std::endl;
+#ifndef NDEBUG
+            best_l = l;
+#endif
+            bestSigma = sigma;
+            bestIncoming = incoming;
+            bestLeaving = rc[l].row;
+            bestDirection = rc[l].direction > 0 ? 1 : -1;
+            bestRc = rc[l].value;
+            notImproved = 0;
+        }
+
+        //Now evenutally compute f+ or f- for the other negative rc (if if exists)
+        if (rc[l].direction == 2 || rc[l].direction == -2)
+        {
+            rc[l].direction/= -2;//Reverse the direction
+            chosenReducedCostVal_ = rc[l].value2;//need to set this for debug double
+            //checks
+            incoming = fastFindBestPivotColumn
+                       (rc[l].direction, rc[l].gammaSign2,
+                        params.pivotTol, params.away,
+                        (params.sepSpace==CglLandP::Fractional),
+                        0,
+                        sigma, params.modularize);
+            if (incoming!=-1 && bestSigma > sigma)
+            {
+                // std::cout<<"I found a better pivot "<<sigma - sigma_<<std::endl;
+#ifndef NDEBUG
+                best_l = l;
+#endif
+                bestSigma = sigma;
+                bestIncoming = incoming;
+                bestLeaving = rc[l].row;
+                bestDirection = rc[l].direction;
+                bestRc = rc[l].value2;
+                notImproved = 0;
+            }
+        }
+    }
+
+    row_i_.num = leaving = bestLeaving;
+    chosenReducedCostVal_ = bestRc;
+    assert(best_l <= nNegativeRcRows_);
+    if (bestLeaving!=-1)
+    {
+        //      std::cout<<"Best pivot pivot "<<best_l<<std::endl;
+        pullTableauRow(row_i_);
+    }
+    direction = bestDirection;
+    delete [] rc;
+    assert (bestIncoming<0||direction!=0);
+    return bestIncoming;
+
+}
+
+double
+CglLandPSimplex::computeCglpObjective(const TabRow &row, bool modularize) const
+{
+    double numerator = -row.rhs * (1 - row.rhs);
+    double denominator = 1;
+
+    const int & n = row.getNumElements();
+    const int * ind = row.getIndices();
+    const double * val = row.denseVector();
+    for (int j = 0 ; j < n ; j++)
+    {
+        const int& jj = ind[j];
+        if (col_in_subspace[jj]==false) continue;
+        double coeff = val[jj];
+        if (modularize && isInteger(jj))
+            coeff = modularizedCoef(coeff, row.rhs);
+        denominator += normedCoef(fabs(coeff), jj);
+        numerator += (coeff > 0 ?
+                      coeff *(1- row.rhs):
+                      - coeff * row.rhs)*getColsolToCut(jj);
+    }
+    return numerator*rhs_weight_/denominator;
+}
+
+double
+CglLandPSimplex::computeCglpObjective(double gamma, bool strengthen)
+{
+    double rhs = row_k_.rhs + gamma * row_i_.rhs;
+    double numerator = - rhs * (1 - rhs);
+    double denominator = 1;
+
+    double coeff = gamma;//newRowCoefficient(basics_[row_i_.num], gamma);
+    if (strengthen && isInteger(basics_[row_i_.num]))
+        coeff = modularizedCoef(coeff, rhs);
+    denominator += normedCoef(fabs(coeff), basics_[row_i_.num]);
+    numerator += (coeff > 0 ?
+                  coeff *(1- rhs):
+                  - coeff * rhs)*
+                 getColsolToCut(basics_[row_i_.num]);
+    for (int j = 0 ; j < ncols_ ; j++)
+    {
+        if (col_in_subspace[nonBasics_[j]]==false) {
+          continue;
+        }
+        coeff = newRowCoefficient(nonBasics_[j], gamma);
+        if (strengthen && nonBasics_[j] < ncols_orig_ &&  isInteger(j))
+            coeff = modularizedCoef(coeff, rhs);
+        denominator += normedCoef(fabs(coeff), nonBasics_[j]);
+        numerator += (coeff > 0 ?
+                      coeff *(1- rhs):
+                      - coeff * rhs)*
+                     getColsolToCut(nonBasics_[j]);
+    }
+    return numerator*rhs_weight_/denominator;
+}
+
+
+double
+CglLandPSimplex::computeCglpObjective(double gamma, bool strengthen, TabRow & newRow)
+{
+    newRow.clear();
+    newRow.rhs = row_k_.rhs + gamma * row_i_.rhs;
+    double numerator = -newRow.rhs * (1 - newRow.rhs);
+    double denominator = 1;
+
+    int * indices = newRow.getIndices();
+    int k = 0;
+    {
+        if (col_in_subspace[basics_[row_i_.num]]==false)
+          {
+            DblEqAssert(0.,1.);
+          }
+        double & val = newRow[ basics_[row_i_.num]] = gamma;//newRowCoefficient(basics_[row_i_.num], gamma);
+        indices[k++] = basics_[row_i_.num];
+        if (strengthen && row_i_.num < ncols_orig_ && isInteger(row_i_.num))
+            newRow[ basics_[row_i_.num]] = modularizedCoef(newRow[ basics_[row_i_.num]], newRow.rhs);
+        denominator += normedCoef(fabs(val), basics_[row_i_.num]);
+        numerator += (val > 0 ?
+                      val *(1- newRow.rhs):
+                      - val * newRow.rhs)*
+                     getColsolToCut(basics_[row_i_.num]);
+    }
+    for (int j = 0 ; j < ncols_ ; j++)
+    {
+        double & val = newRow[nonBasics_[j]] = newRowCoefficient(nonBasics_[j], gamma);
+        indices[k++] = nonBasics_[j];
+        if (strengthen && nonBasics_[j] < ncols_orig_ &&  isInteger(j))
+            newRow[ nonBasics_[j]] = modularizedCoef(val, newRow.rhs);
+        if (col_in_subspace[nonBasics_[j]]==false) continue;
+        denominator += normedCoef(fabs(val), nonBasics_[j]);
+        numerator += (val > 0 ?
+                      val *(1- newRow.rhs):
+                      - val * newRow.rhs)*
+                     getColsolToCut(nonBasics_[j]);
+    }
+    newRow.setNumElements(k);
+    //assert (fabs(numerator/denominator - computeCglpObjective(newRow))<1e-04);
+    return numerator*rhs_weight_/denominator;
+}
+
+
+
+/** Compute the reduced cost of Cglp */
+double
+CglLandPSimplex::computeCglpRedCost(int direction, int gammaSign, double tau)
+{
+    double toBound;
+    toBound = direction == -1 ? getLoBound(basics_[row_i_.num])  : getUpBound(basics_[row_i_.num]);
+
+    double value =0;
+    int sign = gammaSign * direction;
+    double tau1 = 0;
+    double tau2 = 0;
+    for (unsigned int i = 0 ; i < M3_.size() ; i++)
+    {
+        tau1 += fabs(row_i_ [M3_[i]]);
+        if (sign == 1 && row_i_[M3_[i]] < 0)
+        {
+            tau2 += row_i_[M3_[i]] * getColsolToCut(M3_[i]);
+        }
+        else if (sign == -1 && row_i_[M3_[i]] > 0)
+        {
+            tau2 += row_i_[M3_[i]] * getColsolToCut(M3_[i]);
+        }
+    }
+    double Tau = - sign * (tau + tau2) - tau1 * sigma_;
+    value = - sigma_ + Tau
+            + (1 - getColsolToCut(basics_[row_k_.num])) * sign * (row_i_.rhs
+                    -  toBound)
+            + (gammaSign == 1)*direction*(toBound - getColsolToCut(basics_[row_i_.num]));
+
+    return value;
+}
+
+
+/** Compute the value of sigma and thau (which are constants for a row i as defined in Mike Perregaard thesis */
+double
+CglLandPSimplex::computeRedCostConstantsInRow()
+{
+    double tau1 = 0; //the part which will be multiplied by sigma
+    double tau2 = 0;//the rest
+
+    for (unsigned int i = 0 ; i < M1_.size() ; i++)
+    {
+        tau1 += row_i_[M1_[i]];
+    }
+    for (unsigned int i = 0 ; i < M2_.size() ; i++)
+    {
+        tau1 -= row_i_[M2_[i]];
+        tau2 += row_i_[M2_[i]] * getColsolToCut(M2_[i]);
+    }
+    return sigma_ * tau1 + tau2;
+
+}
+
+void
+CglLandPSimplex::updateM1_M2_M3(TabRow & row, double tolerance, bool perturb)
+{
+    M1_.clear();
+    M2_.clear();
+    M3_.clear();
+    tolerance = 0;
+    for (int i = 0; i<ncols_ ; i++)
+    {
+        const int &ii = nonBasics_[i];
+        const double &f = row[ii];
+        if (f< -tolerance)
+        {
+            if (col_in_subspace[ii])
+            {
+                M1_.push_back(ii);
+                colCandidateToLeave_[i]=true;
+            }
+            else
+            {
+                colCandidateToLeave_[i]=false;
+            }
+        }
+        else if (f>tolerance)
+        {
+            if (col_in_subspace[ii])
+            {
+                M2_.push_back(ii);
+                colCandidateToLeave_[i]=true;
+            }
+            else
+            {
+                colCandidateToLeave_[i]=false;
+            }
+        }
+        else
+        {
+            if (col_in_subspace[ii])
+            {
+                if (perturb)   //assign to M1 or M2 at random
+                {
+                    int sign = CoinDrand48() > 0.5 ? 1 : -1;
+                    if (sign == -1)   //put into M1
+                    {
+                        M1_.push_back(ii);
+                        colCandidateToLeave_[i]=true;
+                    }
+                    else   //put into M2
+                    {
+                        M2_.push_back(ii);
+                        colCandidateToLeave_[i]=true;
+                    }
+                }
+                else
+                {
+                    M3_.push_back(ii);
+                    colCandidateToLeave_[i] = true;
+                }
+            }
+            else
+            {
+                colCandidateToLeave_[i] = false;
+            }
+        }
+    }
+    //std::cout<<"M3 has "<<M3_.size()<<" variables."<<std::endl;
+}
+
+/** Create the intersection cut of row k*/
+void
+CglLandPSimplex::createIntersectionCut(TabRow & row, OsiRowCut &cut) const
+{
+    const double * colLower = si_->getColLower();
+    const double * rowLower = si_->getRowLower();
+    const double * colUpper = si_->getColUpper();
+    const double * rowUpper = si_->getRowUpper();
+    // double f_0 = row.rhs;
+    //put the row back into original form
+    for (int j = 0; j < ncols_ ; j++)
+    {
+        if ((nonBasics_[j] < ncols_))
+        {
+            CoinWarmStartBasis::Status status = getStatus(nonBasics_[j]);
+
+            if (status==CoinWarmStartBasis::atLowerBound)
+            {
+                //        row.rhs += getLoBound(nonBasics_[j]) * row[nonBasics_[j]];
+            }
+            else if (status==CoinWarmStartBasis::atUpperBound)
+            {
+                row[nonBasics_[j]] = - row[nonBasics_[j]];
+                //        row.rhs += getUpBound(nonBasics_[j]) * row[nonBasics_[j]];
+            }
+            else
+            {
+                throw;
+            }
+        }
+    }
+
+
+
+    //  return ;
+
+    cut.setUb(COIN_DBL_MAX);
+    double * vec = new double[ncols_orig_+ nrows_orig_ ];
+    CoinFillN(vec, ncols_orig_ + nrows_orig_, 0.);
+    double infty = si_->getInfinity();
+    double cutRhs = row.rhs;
+    cutRhs = cutRhs * (1 - cutRhs);
+    for (int j = 0; j < ncols_ ; j++)
+    {
+        if (fabs(row[nonBasics_[j]])>1e-10)
+        {
+            double value = intersectionCutCoef(row[nonBasics_[j]], row.rhs);
+
+            if (nonBasics_[j]<ncols_)
+            {
+                CoinWarmStartBasis::Status status = //CoinWarmStartBasis::basic;
+                    basis_->getStructStatus(nonBasics_[j]);
+                if (status==CoinWarmStartBasis::atUpperBound)
+                {
+                    value = - intersectionCutCoef(- row[nonBasics_[j]], row.rhs) ;
+                    cutRhs += value * colUpper[nonBasics_[j]];
+                }
+                else
+                    cutRhs += value * colLower[nonBasics_[j]];
+                vec[original_index_[nonBasics_[j]]] += value;
+            }
+            else if (nonBasics_[j]>=ncols_)
+            {
+                int iRow = nonBasics_[j] - ncols_;
+
+                if (rowLower[iRow] > -infty)
+                {
+                    value = -value;
+                    cutRhs -= value*rowLower[iRow];
+                    assert(basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atUpperBound ||
+                           (fabs(rowLower[iRow] - rowUpper[iRow]) < 1e-08));
+                }
+                else
+                {
+                    cutRhs -= value*rowUpper[iRow];
+                    assert(basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atLowerBound);
+                }
+                vec[nonBasics_[j]] = value;
+                assert(fabs(cutRhs)<1e100);
+            }
+        }
+    }
+
+    const CoinPackedMatrix * mat = si_->getMatrixByCol();
+    const CoinBigIndex * starts = mat->getVectorStarts();
+    const int * lengths = mat->getVectorLengths();
+    const double * values = mat->getElements();
+    const CoinBigIndex * indices = mat->getIndices();
+    for (int j = 0 ; j < ncols_ ; j++)
+    {
+        const int& start = starts[j];
+        int end = start + lengths[j];
+        for (int k = start ; k < end ; k++)
+        {
+            vec[original_index_[j]] -= vec[original_index_[ncols_ + indices[k]]] * values[k];
+        }
+
+    }
+
+    //Pack vec into the cut
+    int * inds = new int [ncols_orig_];
+    int nelem = 0;
+    for (int i = 0 ; i < ncols_orig_ ; i++)
+    {
+        if (fabs(vec[i]) > COIN_INDEXED_TINY_ELEMENT)
+        {
+            vec[nelem] = vec[i];
+            inds[nelem++] = i;
+        }
+    }
+
+    cut.setLb(cutRhs);
+    cut.setRow(nelem, inds, vec, false);
+    delete [] vec;
+
+}
+
+/** Compute the normalization factor of the cut.*/
+double
+CglLandPSimplex::normalizationFactor(const TabRow & row) const
+{
+    double numerator = rhs_weight_;
+    double denominator = 1.;
+    for (int j = 0 ; j < ncols_ ; j++)
+    {
+        denominator += fabs(normedCoef(row[nonBasics_[j]], nonBasics_[j]));
+    }
+    return numerator/denominator;
+}
+
+
+/** Create MIG cut from row k*/
+void
+CglLandPSimplex::createMIG( TabRow &row, OsiRowCut &cut) const
+{
+    const double * colLower = si_->getColLower();
+    const double * rowLower = si_->getRowLower();
+    const double * colUpper = si_->getColUpper();
+    const double * rowUpper = si_->getRowUpper();
+
+    if (1)
+    {
+        double f_0 = row.rhs - floor(row.rhs);
+        //put the row back into original form
+        for (int j = 0; j < ncols_ ; j++)
+        {
+            if (nonBasics_[j] < ncols_)
+            {
+                const CoinWarmStartBasis::Status status = basis_->getStructStatus(nonBasics_[j]);
+
+                if (status==CoinWarmStartBasis::atLowerBound)
+                {
+                    //        row.rhs += getLoBound(nonBasics_[j]) * row[nonBasics_[j]];
+                }
+                else if (status==CoinWarmStartBasis::atUpperBound)
+                {
+                    row[nonBasics_[j]] = - row[nonBasics_[j]];
+                    //        row.rhs += getUpBound(nonBasics_[j]) * row[nonBasics_[j]];
+                }
+                else
+                {
+                    throw;
+                }
+            }
+        }
+        //double scaleFactor = normalizationFactor(row);
+        row.rhs = f_0;
+
+        cut.setUb(COIN_DBL_MAX);
+        double * vec = new double[ncols_orig_ + nrows_orig_];
+        CoinFillN(vec, ncols_orig_ + nrows_orig_, 0.);
+        //f_0 = row.rhs - floor(row.rhs);
+        double infty = si_->getInfinity();
+        double cutRhs = row.rhs - floor(row.rhs);
+        cutRhs = cutRhs * (1 - cutRhs);
+        assert(fabs(cutRhs)<1e100);
+        for (int j = 0; j < ncols_ ; j++)
+        {
+            if (fabs(row[nonBasics_[j]])>0.)
+            {
+                {
+                    if (nonBasics_[j]<ncols_orig_)
+                    {
+                        const CoinWarmStartBasis::Status status = basis_->getStructStatus(nonBasics_[j]);
+                        double value;
+                        if (status==CoinWarmStartBasis::atUpperBound)
+                        {
+                            value = - strengthenedIntersectionCutCoef(nonBasics_[j], - row[nonBasics_[j]], row.rhs) ;
+                            cutRhs += value * colUpper[nonBasics_[j]];
+                        }
+                        else if (status==CoinWarmStartBasis::atLowerBound)
+                        {
+                            value = strengthenedIntersectionCutCoef(nonBasics_[j], row[nonBasics_[j]], row.rhs);
+                            cutRhs += value * colLower[nonBasics_[j]];
+                        }
+                        else
+                        {
+                            std::cerr<<"Invalid basis"<<std::endl;
+                            throw -1;
+                        }
+
+                        assert(fabs(cutRhs)<1e100);
+                        vec[original_index_[nonBasics_[j]]] = value;
+                    }
+                    else
+                    {
+                        int iRow = nonBasics_[j] - ncols_;
+                        double value = strengthenedIntersectionCutCoef(nonBasics_[j], row[nonBasics_[j]], row.rhs);
+                        if (rowUpper[iRow] < infty)
+                        {
+                            cutRhs -= value*rowUpper[iRow];
+                        }
+                        else
+                        {
+                            value = -value;
+                            cutRhs -= value*rowLower[iRow];
+                            assert(basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atUpperBound ||
+                                   (rowUpper[iRow] < infty));
+                        }
+                        vec[original_index_[nonBasics_[j]]] = value;
+                        assert(fabs(cutRhs)<1e100);
+                    }
+                }
+            }
+        }
+
+        //Eliminate slacks
+        eliminate_slacks(vec);
+
+        //Pack vec into the cut
+        int * inds = new int [ncols_orig_];
+        int nelem = 0;
+        for (int i = 0 ; i < ncols_orig_ ; i++)
+        {
+            if (fabs(vec[i]) > COIN_INDEXED_TINY_ELEMENT)
+            {
+                vec[nelem] = vec[i];
+                inds[nelem++] = i;
+            }
+        }
+
+        cut.setLb(cutRhs);
+        cut.setRow(nelem, inds, vec, false);
+        //std::cout<<"Scale factor: "<<scaleFactor<<" rhs weight "<<rhs_weight_<<std::endl;
+        //scaleCut(cut, scaleFactor);
+        delete [] vec;
+        delete [] inds;
+
+    }
+}
+
+void
+CglLandPSimplex::eliminate_slacks(double * vec) const
+{
+    const CoinPackedMatrix * mat = si_->getMatrixByCol();
+    const CoinBigIndex * starts = mat->getVectorStarts();
+    const int * lengths = mat->getVectorLengths();
+    const double * values = mat->getElements();
+    const CoinBigIndex * indices = mat->getIndices();
+    const double * vecSlacks = vec + ncols_orig_;
+    for (int j = 0 ; j < ncols_ ; j++)
+    {
+        const CoinBigIndex& start = starts[j];
+        CoinBigIndex end = start + lengths[j];
+        double & val = vec[original_index_[j]];
+        for (CoinBigIndex k = start ; k < end ; k++)
+        {
+            val -= vecSlacks[indices[k]] * values[k];
+        }
+    }
+}
+void
+CglLandPSimplex::scaleCut(OsiRowCut & cut, double factor) const
+{
+    DblGtAssert(factor, 0.);
+    cut *= factor;
+    cut.setLb(cut.lb()*factor);
+}
+
+#ifdef APPEND_ROW
+void
+CglLandPSimplex::append_row(int row_num, bool modularize)
+{
+    int old_idx = basics_[row_num];
+    int r_idx = nrows_ - 1;
+
+    if (basis_->getArtifStatus(nrows_ - 1) == CoinWarmStartBasis::basic)
+    {
+        int i = 0;
+        for (; i < ncols_ ; i++)
+        {
+            if (nonBasics_[i] == ncols_ + nrows_ -1)
+                break;
+        }
+        if (i < ncols_)
+        {
+            nonBasics_[i] = ncols_ + nrows_ - 1;
+            assert(basics_[nrows_ - 1] == ncols_ + nrows_ - 1);
+            basics_[nrows_ - 1] = ncols_ - 1;
+        }
+    }
+#if 0
+    if (basis_->getStructStatus(ncols_ - 1) != CoinWarmStartBasis::basic)
+    {
+        basis_->setStructStatus(ncols_ - 1, CoinWarmStartBasis::basic);
+        assert(basis_->getArtifStatus(nrows_ - 1) == CoinWarmStartBasis::basic);
+        basis_->setArtifStatus(nrows_ - 1, CoinWarmStartBasis::atLowerBound);
+        si_->pivot(ncols_ - 1, ncols_ + nrows_ - 1, -1);
+    }
+#endif
+    TabRow row(this);
+    int rowsize = ncols_orig_ + nrows_orig_ + 1;
+    row.reserve(rowsize);
+    row.num = row_num;
+    pullTableauRow(row);
+    row.rhs -= floor(row.rhs);
+    if (basis_->getStructStatus(ncols_ - 1) != CoinWarmStartBasis::basic)
+    {
+        basis_->setStructStatus(ncols_ - 1, CoinWarmStartBasis::basic);
+        assert(basis_->getArtifStatus(nrows_ - 1) == CoinWarmStartBasis::basic);
+        basis_->setArtifStatus(nrows_ - 1, CoinWarmStartBasis::atLowerBound);
+        si_->pivot(ncols_ - 1, ncols_ + nrows_ - 1, -1);
+    }
+
+    int n = row.getNumElements();
+    const int* ind = row.getIndices();
+#ifdef COIN_HAS_OSICLP
+    CoinPackedMatrix * m = clp_->getMutableMatrixByCol();
+#endif
+
+#if 1
+    const double * rowLower = si_->getRowLower();
+    const double * rowUpper = si_->getRowUpper();
+    double infty = si_->getInfinity();
+    double rhs = floor (colsol_[old_idx]);//floor(row.rhs);
+    std::vector<double> vec(rowsize,0.);
+    for (int i = 0 ; i < n ; i++)
+    {
+        const int &ni = ind[i];
+        if (ni == old_idx) continue;
+        if (integers_[ni])
+        {
+            double f = modularizedCoef(row[ni],row.rhs);
+            f = floor(row[ni] - f + 0.5);
+            row[ni] -= f;
+            if (ni < ncols_)
+            {
+                if (basis_->getStructStatus(ni) == CoinWarmStartBasis::atUpperBound)
+                {
+                    f *= -1;
+                    rhs += f * getUpBound(ni);
+                }
+                if (basis_->getStructStatus(ni) == CoinWarmStartBasis::atLowerBound)
+                {
+                    //f *= -1;
+                    rhs -= f * getLoBound(ni);
+                }
+                vec[ni]=f;
+            }
+            else
+            {
+                int iRow = ind[i] - ncols_;
+                if (basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atLowerBound)
+                {
+                    rhs -= f*rowUpper[iRow];
+                }
+                else if (basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atUpperBound)
+                {
+                    f *= -1;
+                    rhs -= f*rowLower[iRow];
+                    assert(rowLower[iRow] < infty);
+                }
+                vec[ni] = f;
+            }
+        }
+    }
+    vec[old_idx] = 1;
+
+    eliminate_slacks(&vec[0]);
+
+    for (int i = 0 ; i < rowsize ; i++)
+    {
+        if (vec[i])
+            m->modifyCoefficient(r_idx, i, vec[i], true);
+    }
+    si_->setRowBounds(r_idx, rhs, rhs);
+#endif
+
+#if 1
+    si_->messageHandler()->setLogLevel(0);
+    si_->resolve();
+    assert(si_->getIterationCount() == 0);
+#endif
+    /* Update the cached info.*/
+#ifndef NDEBUG
+    int * basics = new int[nrows_];
+#else
+    int * basics = basics_;
+#endif
+    si_->getBasics(basics);
+#ifndef NDEBUG
+    for (int i = 0 ; i < r_idx ; i++)
+    {
+        assert(basics[i] == basics_[i]);
+    }
+    assert(basics[r_idx] == ncols_ - 1);
+    delete [] basics_;
+    basics_ = basics;
+#endif
+    assert(basis_->getStructStatus(old_idx) == CoinWarmStartBasis::basic);
+    assert(basis_->getStructStatus(ncols_ - 1) == CoinWarmStartBasis::basic);
+
+    n = 0;
+    for (int i = 0 ; i < ncols_ ; i++)
+    {
+        if (basis_->getStructStatus(i) != CoinWarmStartBasis::basic)
+        {
+            nonBasics_[n++] = i;
+        }
+    }
+    for (int i = 0 ; i < nrows_ ; i++)
+    {
+        if (basis_->getArtifStatus(i) != CoinWarmStartBasis::basic)
+        {
+            nonBasics_[n++] = i + ncols_;
+        }
+    }
+    assert (n == ncols_);
+    colsol_[ncols_ - 1] = si_->getColSolution()[ncols_-1];
+    colsolToCut_[ncols_ - 1] = si_->getColSolution()[ncols_-1];
+}
+
+void
+CglLandPSimplex::check_mod_row(TabRow & row)
+{
+    int rowsize = ncols_orig_ + nrows_orig_;
+    for (int i = 0 ; i < rowsize ; i++)
+    {
+        assert(! integers_[i] || ((row[i] <= row.rhs+1e-08) && (row[i] >= row.rhs - 1- 1e-08)));
+    }
+}
+
+void
+CglLandPSimplex::update_row(TabRow &row)
+{
+    int r_idx = nrows_ - 1;
+    int c_idx = ncols_ - 1;
+    assert(basics_[row.num] == ncols_ - 1);
+    assert(r_idx == row.num);
+    int rowsize = nrows_ + ncols_;
+    int n = row.getNumElements();
+    const int* ind = row.getIndices();
+#ifdef COIN_HAS_OSICLP
+    CoinPackedMatrix * m = clp_->getMutableMatrixByCol();
+#endif
+    //double * m_el = m->getMutableElements();
+    //const int * m_id = m->getIndices();
+    //const int * m_le = m->getVectorLengths();
+    //const CoinBigIndex * m_st = m->getVectorStarts();
+    const double * rowLower = si_->getRowLower();
+    const double * rowUpper = si_->getRowUpper();
+    double infty = si_->getInfinity();
+    double rhs = floor(row.rhs);
+    std::vector<double> vec(rowsize,0.);
+    for (int i = 0 ; i < n ; i++)
+    {
+        const int &ni = ind[i];
+        if (ni == c_idx) continue;
+        if (integers_[ni])
+        {
+            double f = modularizedCoef(row[ni],row.rhs);
+            f = floor(row[ni] - f + 0.5);
+            //row[ni] -= f;
+            if (ni < ncols_)
+            {
+                assert(basis_->getStructStatus(ni) != CoinWarmStartBasis::basic);
+                if (basis_->getStructStatus(ni) == CoinWarmStartBasis::atUpperBound)
+                {
+                    f *= -1;
+                    rhs += f * getUpBound(ni);
+                }
+                if (basis_->getStructStatus(ni) == CoinWarmStartBasis::atLowerBound)
+                {
+                    rhs -= f * getLoBound(ni);
+                }
+                vec[ni]=f;
+            }
+            else
+            {
+                //continue;
+                int iRow = ind[i] - ncols_;
+                if (iRow == r_idx) continue;
+                assert(basis_->getArtifStatus(iRow) != CoinWarmStartBasis::basic);
+                if (basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atLowerBound)
+                {
+                    rhs -= f*rowUpper[iRow];
+                }
+                else if (basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atUpperBound)
+                {
+                    f *= -1;
+                    rhs -= f*rowLower[iRow];
+                    assert(rowUpper[iRow] < infty);
+                }
+                vec[ni] = f;
+            }
+        }
+    }
+    std::copy(vec.begin(),vec.end(), std::ostream_iterator<double>(std::cout, "\t"));
+    std::cout<<std::endl;
+
+    //vec[c_idx] = 1;
+    eliminate_slacks(&vec[0]);
+    std::copy(vec.begin(),vec.end(), std::ostream_iterator<double>(std::cout, "\t"));
+    std::cout<<std::endl;
+//    assert(vec[c_idx] == 0);
+    for (int i = 0 ; i < ncols_ ; i++)
+    {
+        if (vec[i])
+        {
+            double f = m->getCoefficient(r_idx,i);
+            m->modifyCoefficient(r_idx, i, f + vec[i], true);
+        }
+    }
+    si_->setRowBounds(r_idx, rowLower[r_idx] + rhs, rowUpper[r_idx] + rhs);
+
+#ifdef COIN_HAS_OSICLP
+    clp_->getModelPtr()->factorize();
+#endif
+
+    pullTableauRow(row);
+    assert(row.rhs >= 0. && row.rhs <= 1.);
+    bool stop = false;
+    for (int i = 0 ; i < rowsize ; i++)
+    {
+        if (integers_[i] && (row[i] > row.rhs || row[i] < row.rhs - 1))
+        {
+            stop = true;
+        }
+        //assert(! integers_[i] || (row[i] <= row.rhs && row[i] > row.rhs - 1));
+    }
+    if (stop) exit(10);
+
+}
+#endif
+
+/** Get the row i of the tableau */
+void
+CglLandPSimplex::pullTableauRow(TabRow &row) const
+{
+    const double * rowLower = si_->getRowLower();
+    const double * rowUpper = si_->getRowUpper();
+
+    row.clear();
+    row.modularized_ = false;
+    double infty = si_->getInfinity();
+    /* Get the row */
+#ifdef COIN_HAS_OSICLP
+    if (clp_)
+    {
+        CoinIndexedVector array2;
+        array2.borrowVector(nrows_, 0, row.getIndices() + ncols_, row.denseVector() + ncols_);
+        clp_->getBInvARow(row.num, &row, &array2);
+        {
+            int n = array2.getNumElements();
+            int * indices1 = row.getIndices() + row.getNumElements();
+            int * indices2 = array2.getIndices();
+            for ( int i = 0 ; i < n ; i++)
+            {
+                *indices1 = indices2[i] + ncols_;
+                indices1++;
+            }
+            row.setNumElements(n + row.getNumElements());
+            array2.returnVector();
+        }
+    }
+    else
+#endif
+    {
+        si_->getBInvARow(row.num,row.denseVector(),row.denseVector() + ncols_);
+    }
+    //Clear basic element (it is a trouble for most of the computations)
+    row[basics_[row.num]]=0.;
+    //  row.row[basics_[row.num]]=1;
+    /* get the rhs */
+    {
+        int iCol = basics_[row.num];
+        if (iCol<ncols_)
+            row.rhs = si_->getColSolution()[iCol];
+        else   // Osi does not give direct acces to the value of slacks
+        {
+            iCol -= ncols_;
+            row.rhs = - si_->getRowActivity()[iCol];
+            if (rowLower[iCol]> -infty)
+            {
+                row.rhs += rowLower[iCol];
+            }
+            else
+            {
+                row.rhs+= rowUpper[iCol];
+            }
+        }
+    }
+    //Now adjust the row of the tableau to reflect non-basic variables activity
+    for (int j = 0; j < ncols_ ; j++)
+    {
+        if (nonBasics_[j]<ncols_)
+        {
+            if (basis_->getStructStatus(nonBasics_[j])==CoinWarmStartBasis::atLowerBound)
+            {
+            }
+            else if (basis_->getStructStatus(nonBasics_[j])==CoinWarmStartBasis::atUpperBound)
+            {
+                row[nonBasics_[j]] = -row[nonBasics_[j]];
+            }
+            else
+            {
+                std::cout<<(basis_->getStructStatus(nonBasics_[j])==CoinWarmStartBasis::isFree)<<std::endl;
+                throw CoinError("Invalid basis","CglLandPSimplex","pullTableauRow");
+            }
+        }
+        else
+        {
+            int iRow = nonBasics_[j] - ncols_;
+
+            if (basis_->getArtifStatus(iRow)==CoinWarmStartBasis::atUpperBound)
+            {
+                row[nonBasics_[j]] = -row[nonBasics_[j]];
+            }
+        }
+    }
+    //  row.clean(1e-30);
+}
+
+/** Adjust the row of the tableau to reflect leaving variable direction */
+void
+CglLandPSimplex::adjustTableauRow(int var, TabRow & row, int direction)
+{
+    double bound = 0;
+    assert(direction != 0);
+    if (direction > 0)
+    {
+        for (int j = 0 ; j < ncols_orig_ ; j++)
+            row[nonBasics_[j]] = - row[nonBasics_[j]];
+
+        row.rhs = -row.rhs;
+        bound = getUpBound(var);
+        setColsolToCut(var, bound - getColsolToCut(var));
+        row.rhs += bound;
+    }
+    else if (direction < 0)
+    {
+        bound = getLoBound(var);
+        setColsolToCut(var, getColsolToCut(var) - bound);
+        row.rhs -= bound;
+    }
+    //  assert(fabs(row.rhs)<1e100);
+}
+
+
+/** reset the tableau row after a call to adjustTableauRow */
+void
+CglLandPSimplex::resetOriginalTableauRow(int var, TabRow & row, int direction)
+{
+    if (direction > 0)
+    {
+        adjustTableauRow(var, row, direction);
+    }
+    else
+    {
+        double bound = getLoBound(var);
+        row.rhs += bound;
+        setColsolToCut(var, getColsolToCut(var) + bound);
+    }
+}
+
+template <class X>
+struct SortingOfArray
+{
+    X * array;
+    SortingOfArray(X* a): array(a) {}
+
+    bool operator()(const int i, const int j)
+    {
+        return array[i] < array[j];
+    }
+};
+
+void
+CglLandPSimplex::removeRows(int nDelete, const int * rowsIdx)
+{
+    std::vector<int> sortedIdx;
+    for (int i = 0 ; i < nDelete ; i++)
+        sortedIdx.push_back(rowsIdx[i]);
+    std::sort(sortedIdx.end(), sortedIdx.end());
+    si_->deleteRows(nDelete, rowsIdx);
+    int k = 1;
+    int l = sortedIdx[0];
+    for (int i = sortedIdx[0] + 1 ; k < nDelete ; i++)
+    {
+        if (sortedIdx[k] == i)
+        {
+            k++;
+        }
+        else
+        {
+            original_index_[l] = original_index_[i];
+            l++;
+        }
+    }
+    delete basis_;
+    basis_ = dynamic_cast<CoinWarmStartBasis *> (si_->getWarmStart());
+    assert(basis_);
+
+    /* Update rowFlags_ */
+    std::vector<int> order(nrows_);
+    for (unsigned int i = 0 ; i < order.size() ; i++)
+    {
+        order[i] = i;
+    }
+    std::sort(order.begin(), order.end(), SortingOfArray<int>(basics_));
+    k = 0;
+    l = 0;
+    for (int i = 0 ; k < nDelete ; i++)
+    {
+        if (basics_[order[i]] == sortedIdx[k])
+        {
+            basics_[order[i]] = -1;
+            k++;
+        }
+        else
+        {
+            order[l] = order[i];
+            l++;
+        }
+    }
+    k = 0;
+    for (int i = 0 ; i < nrows_ ; i++)
+    {
+        if (basics_[i] == -1)
+        {
+            k++;
+        }
+        else
+        {
+            basics_[l] = basics_[i];
+            rowFlags_[l] = rowFlags_[i];
+            rWk1_[l] = rWk1_[i];
+            rWk2_[l] = rWk2_[i];
+            rWk4_[l] = rWk3_[i];
+            rWk4_[l] = rWk4_[i];
+            if (row_k_.num == i) row_k_.num = l;
+
+            l++;
+        }
+    }
+
+    nrows_ = nrows_ - nDelete;
+    original_index_.resize(nrows_);
+
+    int numStructural = basis_->getNumStructural();
+    assert(ncols_ = numStructural);
+    int nNonBasics = 0;
+    for (int i = 0 ; i < numStructural ; i++)
+    {
+        if (basis_->getStructStatus(i) != CoinWarmStartBasis::basic)
+        {
+            nonBasics_[nNonBasics++] = i;
+        }
+    }
+
+    int numArtificial = basis_->getNumArtificial();
+    assert(nrows_ = numArtificial);
+    for (int i = 0 ; i < numArtificial ; i++)
+    {
+        if (basis_->getArtifStatus(i)!= CoinWarmStartBasis::basic)
+        {
+            nonBasics_[nNonBasics++] = i + numStructural;
+        }
+    }
+    assert (nNonBasics == ncols_);
+}
+
+  void
+  CglLandPSimplex::printEverything(){
+    row_k_.print(std::cout, 2, nonBasics_, ncols_);
+    printf("nonBasics_: ");
+    for(int i = 0 ; i < ncols_ ; i++){
+      printf("%5i ",nonBasics_[i]);
+    }
+    printf("\n");
+
+ printf("basics_: ");
+    for(int i = 0 ; i < nrows_ ; i++){
+      printf("%5i ",basics_[i]);
+    }
+    printf("\n");
+
+    printf("source row:");
+    for(int i = 0 ; i < ncols_ + nrows_ ; i++){
+      printf("%10.9g ", row_k_[i]);
+    }
+    printf("%10.9g", row_k_.rhs);
+    printf("\n");
+
+    printf(" source indices: ");
+    for(int i = 0 ; i < row_k_.getNumElements() ; i++){
+      printf("%5i %20.20g ", row_k_.getIndices()[i], row_k_[row_k_.getIndices()[i]]);
+    }
+    printf("\n");
+
+    printf("colsolToCut: ");
+    for(int i = 0 ; i < ncols_ + nrows_ ; i++){
+      printf("%10.6g ", colsolToCut_[i]);
+    }
+    printf("\n");
+
+    printf("colsol: ");
+    for(int i = 0 ; i < ncols_ + nrows_ ; i++){
+      printf("%10.6g ", colsol_[i]);
+    }
+    printf("\n");
+  }
+}/* Ends LAP namespace.*/
+
diff --git a/cbits/coin/CglLandPSimplex.hpp b/cbits/coin/CglLandPSimplex.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPSimplex.hpp
@@ -0,0 +1,450 @@
+// Copyright (C) 2005-2009 Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     21/07/05
+//
+// $Id: CglLandPSimplex.hpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+#ifndef CglLandPSimplex_H
+#define CglLandPSimplex_H
+
+#include <iostream>
+#include <vector>
+
+#include "CglConfig.h"
+#include "CglLandP.hpp"
+
+#include "OsiSolverInterface.hpp"
+#include "CoinMessage.hpp"
+#include "CoinMessageHandler.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinPackedMatrix.hpp"
+
+#ifdef COIN_HAS_OSICLP
+#include "OsiClpSolverInterface.hpp"
+#endif
+
+#include "CglLandPTabRow.hpp"
+#include "CglLandPUtils.hpp"
+#include "CglLandPMessages.hpp"
+
+//#define APPEND_ROW
+#define OLD_COMPUTATION
+
+namespace LAP
+{
+/** Forward declaration of class to store extra debug data.*/
+class DebugData;
+
+class CglLandPSimplex
+{
+public:
+    /** Usefull onstructor */
+    CglLandPSimplex(const OsiSolverInterface &si,
+                    const CglLandP::CachedData &cached,
+                    const CglLandP::Parameters &params,
+                    Validator &validator);
+    /** Destructor */
+    ~CglLandPSimplex();
+    /**Update cached information in case of basis change in a round*/
+    void cacheUpdate(const CglLandP::CachedData &cached, bool reducedSpace = 0);
+    /** reset the solver to optimal basis */
+    bool resetSolver(const CoinWarmStartBasis * basis);
+    /** Perfom pivots to find the best cuts */
+    bool optimize(int var, OsiRowCut & cut, const CglLandP::CachedData &cached, const CglLandP::Parameters & params);
+    /** Find Gomory cut (i.e. don't do extra setup required for pivots).*/
+    bool generateMig(int row, OsiRowCut &cut, const CglLandP::Parameters & params);
+
+    /** Find extra constraints in current tableau.*/
+    int generateExtraCuts(const CglLandP::CachedData &cached, const CglLandP::Parameters & params);
+    /** Generate a constrainte for a row of the tableau different from the source row.*/
+    int generateExtraCut(int i, const CglLandP::CachedData & cached,
+                         const CglLandP::Parameters& params);
+
+    void genThisBasisMigs(const CglLandP::CachedData &cached,
+                          const CglLandP::Parameters & params) ;
+
+    /** insert all extra cuts in cs.*/
+    int insertAllExtr(OsiCuts & cs, CoinRelFltEq eq);
+
+    void setLogLevel(int level)
+    {
+        handler_->setLogLevel(level);
+    }
+
+
+    void setSi(OsiSolverInterface *si)
+    {
+        si_ = si;
+#ifdef COIN_HAS_OSICLP
+        OsiClpSolverInterface * clpSi = dynamic_cast<OsiClpSolverInterface *>(si_);
+        if (clpSi)
+        {
+            clp_ = clpSi;
+        }
+#endif
+    }
+    void freeSi()
+    {
+        assert(si_ != NULL);
+        delete si_;
+        si_ = NULL;
+#ifdef COIN_HAS_OSICLP
+        clp_ = NULL;
+#endif
+    }
+
+    Cuts& extraCuts()
+    {
+        return cuts_;
+    }
+    void loadBasis(const OsiSolverInterface &si,
+                   std::vector<int> &M1, std::vector<int> &M2,
+                   int k);
+
+
+    int getNumCols() const
+    {
+        return ncols_;
+    }
+
+    int getNumRows() const
+    {
+        return nrows_;
+    }
+
+    const CoinWarmStartBasis  * getBasis() const
+    {
+        return basis_;
+    }
+    const int * getNonBasics() const
+    {
+        return nonBasics_;
+    }
+
+    const int * getBasics() const
+    {
+        return basics_;
+    }
+
+    void outPivInfo(int ncuts)
+    {
+        handler_->message(RoundStats, messages_)<<ncuts<<numPivots_
+        <<numSourceRowEntered_
+        <<numIncreased_<<CoinMessageEol;
+    }
+#ifdef APPEND_ROW
+    /** Append source row to tableau.*/
+    void append_row(int row_num, bool modularize) ;
+    /** Update appended row after a pivot.*/
+    void update_row(TabRow &row);
+
+    void check_mod_row(TabRow &row);
+#endif
+protected:
+    /** Perform a change in the basis (direction is 1 if leaving variable is going to ub, 0 otherwise)*/
+    bool changeBasis(int incoming, int leaving, int direction, 
+#ifndef OLD_COMPUTATION
+                     bool recompute_source_row,
+#endif
+                     bool modularize);
+    /** Find a row which can be used to perform an improving pivot the fast way
+      * (i.e., find the leaving variable).
+      \return index of the row on which to pivot or -1 if none exists. */
+    int fastFindCutImprovingPivotRow( int &direction, int &gammaSign, double tolerance, bool flagPositiveRows);
+    /** Rescan reduced costs tables */
+    int rescanReducedCosts( int &direction, int &gammaSign, double tolerance);
+    /** Find the column which leads to the best cut (i.e., find incoming variable).*/
+    int fastFindBestPivotColumn(int direction, int gammaSign,
+                                double pivotTol, double rhsTol,
+                                bool reducedSpace,
+                                bool allowNonImproving,
+                                double &bestSigma, bool modularize);
+
+    /** Find incoming and leaving variables which lead to the most violated
+      adjacent normalized lift-and-project cut.
+      \remark At this point reduced costs should be already computed.
+      \return incoming variable variable,
+      \param leaving variable
+      \param direction leaving direction
+      */
+    int findBestPivot(int &leaving, int & direction,
+                      const CglLandP::Parameters & params);
+
+
+    /** Compute the objective value of the Cglp for given row and rhs (if strengthening shall be applied
+      row should have been modularized).*/
+    double computeCglpObjective(const TabRow & row, bool modularize = false) const;
+    /** return the coefficients of the strengthened intersection cut
+      * takes one extra argument seens needs to consider variable type.
+      */
+    inline double strengthenedIntersectionCutCoef(int i, double alpha_i, double beta) const;
+    /** return the coefficient of the new row (combining row_k + gamma row_i).
+      */
+    inline double newRowCoefficient(int j, double gamma) const;
+    /** Create the intersection cut of row k*/
+    void createIntersectionCut(TabRow & row, OsiRowCut &cut) const;
+    /** Compute the normalization factor of the cut.*/
+    double normalizationFactor(const TabRow & row) const;
+    /** Scale the cut by factor.*/
+    void scaleCut(OsiRowCut & cut, double factor) const;
+    /** Create strenghtened row */
+    //  void createIntersectionCut(double * row);
+    /** Create MIG cut from row k*/
+    void createMIG( TabRow & row, OsiRowCut &cut) const;
+    /** Get the row i of the tableau */
+    void pullTableauRow(TabRow & row) const;
+    /** Adjust the row of the tableau to reflect leaving variable direction */
+    void adjustTableauRow(int var, TabRow & row, int direction);
+    /** reset the tableau row after a call to adjustTableauRow */
+    void resetOriginalTableauRow(int var, TabRow & row, int direction);
+    /**Get lower bound for variable or constraint */
+    inline double getLoBound(int index) const
+    {
+        return lo_bounds_[original_index_[index]];
+    }
+    /**Get upper bound for variable or constraint */
+    inline double getUpBound(int index) const
+    {
+        return up_bounds_[original_index_[index]];
+    }
+    /** Access to value in solution to cut (indexed in reduced problem) */
+    inline double getColsolToCut(int index) const
+    {
+        return colsolToCut_[original_index_[index]];
+    }
+    bool isGtConst(int index) const
+    {
+        return (index >= ncols_ && lo_bounds_[original_index_[index]] < -1e-10 && up_bounds_[original_index_[index]] <= 1e-09);
+    }
+    /** Access to value in solution to cut (indexed in reduced problem) */
+    inline void setColsolToCut(int index, double value)
+    {
+        colsolToCut_[original_index_[index]] = value;
+    }
+    /** Get the basic status of a variable (structural or slack).*/
+    inline CoinWarmStartBasis::Status getStatus(int index) const
+    {
+        if (index < ncols_) return basis_->getStructStatus(index);
+        return basis_->getArtifStatus(index - ncols_);
+    }
+    /** Say if variable index by i in current tableau is integer.*/
+    inline bool isInteger(int index) const
+    {
+        return integers_[original_index_[index]];
+    }
+    /** Compute normalization weights.*/
+    void computeWeights(CglLandP::LHSnorm norm, CglLandP::Normalization type,
+                        CglLandP::RhsWeightType rhs);
+    /** Evenutaly multiply a by w if normed_weights_ is not empty.*/
+    double normedCoef(double a, int ii) const
+    {
+        if (norm_weights_.empty())
+        {
+            return a;
+        }
+        else
+        {
+            return a*norm_weights_[ii];
+        }
+    }
+    /** print the tableau of current basis. */
+    void printTableau(std::ostream & os);
+
+  /** Print everything .*/
+  void printEverything();
+    /** print the tableau of current basis. */
+    void printTableauLateX(std::ostream & os);
+    void printRowLateX(std::ostream & os, int i);
+    void printCutLateX(std::ostream & os, int i);
+
+    /** Print CGLP basis corresponding to current tableau and source row.*/
+    void printCglpBasis(std::ostream& os = std::cout);
+    /** Put variables in M1 M2 and M3 according to their sign.*/
+    void get_M1_M2_M3(const TabRow & row,
+                      std::vector<int> &M1,
+                      std::vector<int> &M2,
+                      std::vector<int> &M3);
+    /** Put a vector in structural sapce.*/
+    void eliminate_slacks(double * vec) const;
+private:
+    /// No default constructor
+    CglLandPSimplex();
+    /// No copy constructor
+    CglLandPSimplex(const CglLandPSimplex&);
+    /// No assignment operator
+    CglLandPSimplex& operator=(const CglLandPSimplex&);
+#ifdef COIN_HAS_OSICLP
+    /** Pointer to OsiClpSolverInterface if used.*/
+    OsiClpSolverInterface * clp_;
+#endif
+
+    /** Update values in M1 M2 and M3 before an iteration.*/
+    void updateM1_M2_M3(TabRow & row, double tolerance, bool alwaysComputeCheap);
+    /** Remove rows from current tableau.*/
+    void removeRows(int nDelete, const int * rowsIdx);
+
+
+    void compute_p_q_r_s(double gamma, int gammaSign, double &p, double & q, double & r , double &s);
+
+
+    /// @name Work infos
+    /// @{
+    /** Source row for cut */
+    TabRow row_k_;
+    /** Original version of source row (without modularization).*/
+    TabRow original_row_k_;
+    /** Row of leaving candidate*/
+    TabRow row_i_;
+#ifndef NDBEUG
+    TabRow new_row_;
+#endif
+    /**vector to sort the gammas*/
+    CoinPackedVector gammas_;
+    /**first work vector in row space.*/
+    std::vector<double> rWk1_;
+    /**scond work vector in row space.*/
+    std::vector<double> rWk2_;
+    /**third work vector in row space.*/
+    std::vector<double> rWk3_;
+    /**fourth work vector in row space.*/
+    std::vector<double> rWk4_;
+    /** integer valued work vector on the rows */
+    std::vector<int> rIntWork_;
+    /** Flag rows which we don't want to try anymore */
+    bool * rowFlags_;
+    /** Flag columns which are in the subspace (usualy remove nonbasic structurals in subspace) */
+    std::vector<bool> col_in_subspace;
+    /** Flag columns which have to be considered for leaving the basis */
+    bool *colCandidateToLeave_;
+    /** Store the basics variable */
+    int * basics_;
+    /** Stores the nonBasicVariables */
+    int * nonBasics_;
+    /** Stores the variables which are always in M1 for a given k*/
+    std::vector<int> M1_;
+    /** Stores the variables which are always in M2 for a given k*/
+    std::vector<int> M2_;
+    /** Stores the variables which could be either in M1 or M2 */
+    std::vector<int> M3_;
+    /** stores the cglp value of the normalized cut obtained from row k_ */
+    double sigma_;
+    /** Keep track of basis status */
+    CoinWarmStartBasis * basis_;
+    /** Pointer to the solution to cut (need to be modified after each pivot because we are only considering slacks).*/
+    double * colsolToCut_;
+    /** Pointer to the current basic solution.*/
+    double * colsol_;
+    /// cached numcols in original problem
+    int ncols_orig_;
+    ///cached numrows in original problem
+    int nrows_orig_;
+    /// cached number of columns in reduced size problem
+    int ncols_;
+    /// Cached number of rows in reduced size problem
+    int nrows_;
+    // for fast access to lower bounds (both cols and rows)
+    std::vector<double> lo_bounds_;
+    // for fast access to upper bounds (both cols and rows)
+    std::vector<double> up_bounds_;
+    /// Say if we are in a sequence of degenerate pivots
+    bool inDegenerateSequence_;
+    /// Value for the reduced cost chosen for pivoting
+    double chosenReducedCostVal_;
+    /// pointer to array of integer info for both structural and slacks
+    const bool * integers_;
+    /// Original index of variable before deletions.
+    std::vector<int> original_index_;
+    /// Stores extra cuts which are generated along the procedure
+    Cuts cuts_;
+    /// @}
+    /// @name Interfaces to the solver
+    /// @{
+    /** Pointer to the solver interface */
+    OsiSolverInterface * si_;
+    ///@}
+    /// Own the data or not?
+    bool own_;
+    /// A pointer to a cut validator
+    Validator & validator_;
+    /// Weights for the normalization constraint
+    std::vector<double> norm_weights_;
+    /// Weight for rhs of normalization constraint.*/
+    double rhs_weight_;
+
+    /// number of rows with a <0 rc in current iteration
+    int nNegativeRcRows_;
+    /** Check that the basis is correct.*/
+    bool checkBasis();
+
+    /** Record the number of pivots.*/
+    int numPivots_;
+    /** Record the number of times the source row entered the basis.*/
+    int numSourceRowEntered_;
+    /** Record the number of times that sigma increased.*/
+    int numIncreased_;
+
+    /** Message handler. */
+    CoinMessageHandler * handler_;
+    /** Messages. */
+    CoinMessages messages_;
+#ifndef NDEBUG
+    double bestSigma_;
+#endif
+
+protected:
+    /** \name Slow versions of the function (old versions do not work).*/
+    /** @{ */
+    /** Compute the reduced cost of Cglp */
+    double computeCglpRedCost(int direction, int gammaSign, double tau);
+    /** Compute the value of sigma and thau (which are constants for a row i as defined in Mike Perregaard thesis */
+    double computeRedCostConstantsInRow();
+    /** Compute the objective value of the Cglp with linear combintation of the two rows by gamma */
+    double computeCglpObjective(double gamma, bool strengthen, TabRow &row);
+    /** Compute the objective value of the Cglp with linear combintation of the row_k_ and gamma row_i_ */
+    double computeCglpObjective(double gamma, bool strengthen);
+    /** Find a row which can be used to perform an improving pivot return index of the cut or -1 if none exists
+      * (i.e., find the leaving variable).*/
+    int findCutImprovingPivotRow( int &direction, int &gammaSign, double tolerance);
+    /** Find the column which leads to the best cut (i.e., find incoming variable).*/
+    int findBestPivotColumn(int direction,
+                            double pivotTol, bool reducedSpace, bool allowDegeneratePivot,
+                            bool modularize);
+#if 1
+    int plotCGLPobj(int direction, double gammaTolerance,
+                    double pivotTol, bool reducedSpace, bool allowDegenerate, bool modularize);
+#endif
+
+    /** @} */
+};
+
+
+/** return the coefficients of the strengthened intersection cut */
+double CglLandPSimplex::strengthenedIntersectionCutCoef(int i, double alpha_i, double beta) const
+{
+    //  double ratio = beta/(1-beta);
+    if ( (!integers_[i]))
+        return intersectionCutCoef(alpha_i, beta);
+    else
+    {
+        double f_i = alpha_i - floor(alpha_i);
+        if (f_i < beta)
+            return f_i*(1- beta);
+        else
+            return (1 - f_i)*beta;//(1-beta);
+    }
+}
+
+/** return the coefficient of the new row (combining row_k + gamma row_i).
+  */
+double
+CglLandPSimplex::newRowCoefficient(int j, double gamma) const
+{
+    return row_k_[j] + gamma * row_i_[j];
+}
+
+}
+#endif
diff --git a/cbits/coin/CglLandPTabRow.cpp b/cbits/coin/CglLandPTabRow.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPTabRow.cpp
@@ -0,0 +1,80 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           LIF
+//           CNRS, Aix-Marseille Universites
+// Date:     02/23/08
+//
+// $Id: CglLandPTabRow.cpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+
+#include "CglLandPTabRow.hpp"
+#include "CglLandPSimplex.hpp"
+namespace LAP
+{
+void
+TabRow::print(std::ostream & os, int width, const int * nonBasics,
+              int m)
+{
+    os.width(3);
+    os.precision(4);
+    os.setf(std::ios_base::right, std::ios_base::adjustfield);
+    os<<"idx: ";
+    const double * dense = denseVector();
+    for (int j = 0 ; j < m ; j++)
+    {
+        os.width(width);
+        os.setf(std::ios_base::right, std::ios_base::adjustfield);
+        os<<nonBasics[j]<<" ";
+    }
+
+    os<<std::endl;
+    os.width(3);
+    os.precision(4);
+    os.setf(std::ios_base::right, std::ios_base::adjustfield);
+    os<< num <<": ";
+    for (int j = 0 ; j < m ; j++)
+    {
+        os.width(width);
+        os.precision(3);
+        //      os.setf(std::ios_base::fixed, std::ios_base::floatfield);
+        os.setf(std::ios_base::right, std::ios_base::adjustfield);
+        os<<dense[nonBasics[j]]<<" ";
+    }
+
+    os.width(width);
+    os.precision(4);
+    //    os.setf(std::ios_base::fixed, std::ios_base::floatfield);
+    os.setf(std::ios_base::right, std::ios_base::adjustfield);
+    os<<rhs;
+
+    os<<std::endl;
+
+}
+
+bool
+TabRow::operator==(const TabRow &r) const
+{
+    return CoinIndexedVector::operator==(r);
+}
+
+
+/** Modularize row.*/
+void
+TabRow::modularize(const bool * integerVar)
+{
+    const int& n = getNumElements();
+    const int* ind = getIndices();
+    double * el = denseVector();
+    for (int i = 0 ; i < n ; i++)
+    {
+        const int &ni = ind[i];
+        if (integerVar[ni])
+        {
+            el[ni] = modularizedCoef(el[ni], rhs);
+        }
+    }
+    modularized_ = true;
+}
+}/* Ends namespace LAP.*/
diff --git a/cbits/coin/CglLandPTabRow.hpp b/cbits/coin/CglLandPTabRow.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPTabRow.hpp
@@ -0,0 +1,80 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           LIF
+//           CNRS, Aix-Marseille Universites
+// Date:     02/23/08
+//
+// $Id: CglLandPTabRow.hpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+
+#ifndef CglLandPTabRow_H
+#define CglLandPTabRow_H
+
+#include "CoinIndexedVector.hpp"
+#include <iostream>
+
+namespace LAP
+{
+class CglLandPSimplex;
+struct TabRow: public CoinIndexedVector
+{
+    /** Row number.*/
+    int num;
+    /** Row right-hand-side.*/
+    double rhs;
+    /** Row of what?*/
+    const CglLandPSimplex * si_;
+
+    /** Flag to say if row is modularized.*/
+    bool modularized_;
+
+    TabRow():
+            CoinIndexedVector(), si_(NULL), modularized_(false) {}
+
+    TabRow(const CglLandPSimplex *si):
+            CoinIndexedVector(), num(-1), rhs(0), si_(si), modularized_(false) {}
+
+    TabRow(const TabRow & source):CoinIndexedVector(source),
+            num(source.num), rhs(source.rhs), si_(source.si_)
+    {
+    }
+
+    TabRow& operator=(const TabRow & r)
+    {
+        if (this != &r)
+        {
+            CoinIndexedVector::operator=(r);
+            num = r.num;
+            rhs = r.rhs;
+            si_ = r.si_;
+        }
+        return *this;
+    }
+
+    bool operator==(const TabRow &r) const;
+    ~TabRow()
+    {
+    }
+
+    void modularize(const bool * integerVar);
+
+    void print(std::ostream & os, int width = 9, const int * nonBasics = NULL,
+               int m = 0);
+    inline
+    const double& operator[](const int &index) const
+    {
+        return denseVector()[index];
+    }
+
+    inline
+    double& operator[](const int &index)
+    {
+        return denseVector()[index];
+    }
+};
+}/* Ends LAP Namespace.*/
+
+#endif
+
diff --git a/cbits/coin/CglLandPTest.cpp b/cbits/coin/CglLandPTest.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPTest.cpp
@@ -0,0 +1,352 @@
+// $Id: CglLandPTest.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000-2009, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// UnitTest for CglGomory adapted for lift-and-project
+
+#include <cstdio>
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <cassert>
+
+#include "CoinPragma.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "OsiCuts.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CglLandP.hpp"
+
+void
+CglLandPUnitTest(
+    OsiSolverInterface * si,
+    const std::string &mpsDir)
+{
+    CoinRelFltEq eq(1e-05);
+    // Test default constructor
+    {
+        CglLandP aGenerator;
+        assert(aGenerator.parameter().pivotLimit==20);
+        assert(aGenerator.parameter().maxCutPerRound==5000);
+        assert(aGenerator.parameter().failedPivotLimit==1);
+        assert(aGenerator.parameter().degeneratePivotLimit==0);
+        assert(eq(aGenerator.parameter().pivotTol, 1e-04));
+        assert(eq(aGenerator.parameter().away, 5e-04));
+        assert(eq(aGenerator.parameter().timeLimit, COIN_DBL_MAX));
+        assert(eq(aGenerator.parameter().singleCutTimeLimit, COIN_DBL_MAX));
+        assert(aGenerator.parameter().useTableauRow==true);
+        assert(aGenerator.parameter().modularize==false);
+        assert(aGenerator.parameter().strengthen==true);
+        assert(aGenerator.parameter().perturb==true);
+        assert(aGenerator.parameter().pivotSelection==CglLandP::mostNegativeRc);
+    }
+
+
+    // Test copy constructor
+    {
+        CglLandP a;
+        {
+            CglLandP b;
+            b.parameter().pivotLimit = 100;
+            b.parameter().maxCutPerRound = 100;
+            b.parameter().failedPivotLimit = 10;
+            b.parameter().degeneratePivotLimit = 10;
+            b.parameter().pivotTol = 1e-07;
+            b.parameter().away = 1e-10;
+            b.parameter().timeLimit = 120;
+            b.parameter().singleCutTimeLimit = 15;
+            b.parameter().useTableauRow = true;
+            b.parameter().modularize = true;
+            b.parameter().strengthen = false;
+            b.parameter().perturb = false;
+            b.parameter().pivotSelection=CglLandP::bestPivot;
+            //Test Copy
+            CglLandP c(b);
+            assert(c.parameter().pivotLimit == 100);
+            assert(c.parameter().maxCutPerRound == 100);
+            assert(c.parameter().failedPivotLimit == 10);
+            assert(c.parameter().degeneratePivotLimit == 10);
+            assert(c.parameter().pivotTol == 1e-07);
+            assert(c.parameter().away == 1e-10);
+            assert(c.parameter().timeLimit == 120);
+            assert(c.parameter().singleCutTimeLimit == 15);
+            assert(c.parameter().useTableauRow == true);
+            assert(c.parameter().modularize == true);
+            assert(c.parameter().strengthen == false);
+            assert(c.parameter().perturb == false);
+            assert(c.parameter().pivotSelection == CglLandP::bestPivot);
+            a=b;
+            assert(a.parameter().pivotLimit == 100);
+            assert(a.parameter().maxCutPerRound == 100);
+            assert(a.parameter().failedPivotLimit == 10);
+            assert(a.parameter().degeneratePivotLimit == 10);
+            assert(a.parameter().pivotTol == 1e-07);
+            assert(a.parameter().away == 1e-10);
+            assert(a.parameter().timeLimit == 120);
+            assert(a.parameter().singleCutTimeLimit == 15);
+            assert(a.parameter().useTableauRow == true);
+            assert(a.parameter().modularize == true);
+            assert(a.parameter().strengthen == false);
+            assert(a.parameter().perturb == false);
+            assert(a.parameter().pivotSelection == CglLandP::bestPivot);
+        }
+    }
+
+    {
+        //  Maximize  2 x2
+        // s.t.
+        //    2x1 +  2x2 <= 3
+        //   -2x1 +  2x2 <= 1
+        //    7x1 +  4x2 <= 8
+        //   -7x1 +  4x2 <= 1
+        //     x1, x2 >= 0 and x1, x2 integer
+        // Slacks are s1, s2, s3, s4
+
+
+
+        //Test that problem is correct
+        // Optimal Basis is x1, x2, s3, s4 with tableau
+        //    x1            0.25 s1  -0.25 s2             =  0.5
+        //           x2     0.25 s1   0.25 s2             =  1
+        //                 -2.75 s1   0.75 s2    s3       =  0.5
+        //                  0.75 s1  -2.75 s2        s4   =  0.5
+        // z=              -0.25 s1  -0.25 s2             =  -1
+        // Gomory cut from variable x1 is x2 <= 0.5
+        // Can be improved by first pivoting s2 in and s4 out, then s1 in and s3 out
+        // to x2 <= 0.25
+        {
+            int start[2] = {0,4};
+            int length[2] = {4,4};
+            int rows[8] = {0,1,2,3,0,1,2,3};
+            double elements[8] = {2.0,-2.0,7.0,-7.0,2.0,2.0,4.0,4.0};
+            CoinPackedMatrix  columnCopy(true,4,2,8,elements,rows,start,length);
+
+            double rowLower[4]={-COIN_DBL_MAX,-COIN_DBL_MAX,
+                                -COIN_DBL_MAX,-COIN_DBL_MAX};
+            double rowUpper[4]={3.,1.,8.,1.};
+            double colLower[2]={0.0,0.0};
+            double colUpper[2]={1.0,1.0};
+            double obj[2]={-1,-1};
+            int intVar[2]={0,1};
+
+            OsiSolverInterface  * siP = si->clone();
+            siP->loadProblem(columnCopy, colLower, colUpper, obj, rowLower, rowUpper);
+            siP->setInteger(intVar,2);
+            CglLandP test;
+            test.setLogLevel(2);
+            test.parameter().sepSpace = CglLandP::Full;
+            siP->resolve();
+            // Test generateCuts method
+            {
+                OsiCuts cuts;
+                test.generateCuts(*siP,cuts);
+                cuts.printCuts();
+                assert(cuts.sizeRowCuts()==1);
+                OsiRowCut aCut = cuts.rowCut(0);
+                assert(eq(aCut.lb(), -.0714286));
+                CoinPackedVector row = aCut.row();
+                if (row.getNumElements() == 1)
+                {
+                    assert(row.getIndices()[0]==1);
+                    assert(eq(row.getElements()[0], -4*.0714286));
+                }
+                else if (row.getNumElements() == 2)
+                {
+                    assert(row.getIndices()[0]==0);
+                    assert(eq(row.getElements()[0], 0.));
+                    assert(row.getIndices()[1]==1);
+                    assert(eq(row.getElements()[1], -1));
+                }
+                OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts);
+
+                siP->resolve();
+            }
+            if (0)
+            {
+                OsiCuts cuts;
+                test.generateCuts(*siP,cuts);
+                cuts.printCuts();
+                assert(cuts.sizeRowCuts()==1);
+                OsiRowCut aCut = cuts.rowCut(0);
+                CoinPackedVector row = aCut.row();
+                if (row.getNumElements() == 1)
+                {
+                    assert(row.getIndices()[0]==1);
+                    assert(eq(row.getElements()[0], -1));
+                }
+                else if (row.getNumElements() == 2)
+                {
+                    assert(row.getIndices()[0]==0);
+                    assert(eq(row.getElements()[0], 0.));
+                    assert(row.getIndices()[1]==1);
+                    assert(eq(row.getElements()[1], -1));
+                }
+                assert(eq(aCut.lb(), 0.));
+                OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts);
+
+                siP->resolve();
+            }
+            delete siP;
+        }
+    }
+
+    if (1)  //Test on p0033
+    {
+        // Setup
+        OsiSolverInterface  * siP = si->clone();
+        std::string fn(mpsDir+"p0033");
+        siP->readMps(fn.c_str(),"mps");
+        siP->activateRowCutDebugger("p0033");
+        CglLandP test;
+
+        // Solve the LP relaxation of the model and
+        // print out ofv for sake of comparison
+        siP->initialSolve();
+        double lpRelaxBefore=siP->getObjValue();
+        assert( eq(lpRelaxBefore, 2520.5717391304347) );
+#ifdef CGL_DEBUG
+        printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
+#endif
+
+        OsiCuts cuts;
+
+        // Test generateCuts method
+        test.generateCuts(*siP,cuts);
+        OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts);
+
+        siP->resolve();
+        double lpRelaxAfter=siP->getObjValue();
+        //assert( eq(lpRelaxAfter, 2592.1908295194507) );
+
+        std::cout<<"Relaxation after "<<lpRelaxAfter<<std::endl;
+        assert( lpRelaxAfter> 2840. );
+#ifdef CGL_DEBUG
+        printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
+        printf("\n\nFinal LP min=%f\n",lpRelaxAfter);
+#endif
+        assert( lpRelaxBefore < lpRelaxAfter );
+
+        delete siP;
+    }
+    if (1)  //test again with modularization
+    {
+        // Setup
+        OsiSolverInterface  * siP = si->clone();
+        std::string fn(mpsDir+"p0033");
+        siP->readMps(fn.c_str(),"mps");
+        siP->activateRowCutDebugger("p0033");
+        CglLandP test;
+        test.parameter().modularize = true;
+        // Solve the LP relaxation of the model and
+        // print out ofv for sake of comparison
+        siP->initialSolve();
+        double lpRelaxBefore=siP->getObjValue();
+        assert( eq(lpRelaxBefore, 2520.5717391304347) );
+#ifdef CGL_DEBUG
+        printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
+#endif
+
+        OsiCuts cuts;
+
+        // Test generateCuts method
+        test.generateCuts(*siP,cuts);
+        OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts);
+
+        siP->resolve();
+        double lpRelaxAfter=siP->getObjValue();
+        //assert( eq(lpRelaxAfter, 2592.1908295194507) );
+
+        std::cout<<"Relaxation after "<<lpRelaxAfter<<std::endl;
+        assert( lpRelaxAfter> 2840. );
+#ifdef CGL_DEBUG
+        printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
+        printf("\n\nFinal LP min=%f\n",lpRelaxAfter);
+#endif
+        assert( lpRelaxBefore < lpRelaxAfter );
+
+        delete siP;
+    }
+    if (1)  //test again with alternate pivoting rule
+    {
+        // Setup
+        OsiSolverInterface  * siP = si->clone();
+        std::string fn(mpsDir+"p0033");
+        siP->readMps(fn.c_str(),"mps");
+        siP->activateRowCutDebugger("p0033");
+        CglLandP test;
+        test.parameter().pivotSelection = CglLandP::bestPivot;
+        // Solve the LP relaxation of the model and
+        // print out ofv for sake of comparison
+        siP->initialSolve();
+        double lpRelaxBefore=siP->getObjValue();
+        assert( eq(lpRelaxBefore, 2520.5717391304347) );
+#ifdef CGL_DEBUG
+        printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
+#endif
+
+        OsiCuts cuts;
+
+        // Test generateCuts method
+        test.generateCuts(*siP,cuts);
+        OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts);
+
+        siP->resolve();
+        double lpRelaxAfter=siP->getObjValue();
+        //assert( eq(lpRelaxAfter, 2592.1908295194507) );
+
+        std::cout<<"Relaxation after "<<lpRelaxAfter<<std::endl;
+        assert( lpRelaxAfter> 2840. );
+#ifdef CGL_DEBUG
+        printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
+        printf("\n\nFinal LP min=%f\n",lpRelaxAfter);
+#endif
+        assert( lpRelaxBefore < lpRelaxAfter );
+
+        delete siP;
+    }
+
+    if (1)  //Finally test code in documentation
+    {
+        // Setup
+        OsiSolverInterface  * siP = si->clone();
+        std::string fn(mpsDir+"p0033");
+        siP->readMps(fn.c_str(),"mps");
+        siP->activateRowCutDebugger("p0033");
+        CglLandP landpGen;
+
+        landpGen.parameter().timeLimit = 10.;
+        landpGen.parameter().pivotLimit = 2;
+
+
+        // Solve the LP relaxation of the model and
+        // print out ofv for sake of comparison
+        siP->initialSolve();
+        double lpRelaxBefore=siP->getObjValue();
+        assert( eq(lpRelaxBefore, 2520.5717391304347) );
+#ifdef CGL_DEBUG
+        printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
+#endif
+
+        OsiCuts cuts;
+
+        // Test generateCuts method
+        landpGen.generateCuts(*siP, cuts);
+        OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts);
+
+        siP->resolve();
+        double lpRelaxAfter=siP->getObjValue();
+        //assert( eq(lpRelaxAfter, 2592.1908295194507) );
+
+        std::cout<<"Relaxation after "<<lpRelaxAfter<<std::endl;
+        assert( lpRelaxAfter> 2840. );
+#ifdef CGL_DEBUG
+        printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
+        printf("\n\nFinal LP min=%f\n",lpRelaxAfter);
+#endif
+        assert( lpRelaxBefore < lpRelaxAfter );
+
+        delete siP;
+    }
+}
diff --git a/cbits/coin/CglLandPUtils.cpp b/cbits/coin/CglLandPUtils.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPUtils.cpp
@@ -0,0 +1,102 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           LIF
+//           CNRS, Aix-Marseille Universites
+// Date:     02/23/08
+//
+// $Id: CglLandPUtils.cpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+
+#include "CglLandPUtils.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiCuts.hpp"
+namespace LAP
+{
+double
+normCoef(TabRow &row, int ncols, const int * nonBasics)
+{
+    double res = 1;
+    for (int i = 0 ; i < ncols ; i++)
+        res += fabs(row[nonBasics[i]]);
+    return res/(1-row.rhs);
+}
+
+
+/** scale the cut passed as argument using provided normalization factor*/
+void scale(OsiRowCut &cut, double norma)
+{
+    assert(norma >0.);
+    CoinPackedVector row;
+    row.reserve(cut.row().getNumElements());
+    for (int i = 0 ; i < cut.row().getNumElements() ; i++)
+    {
+        row.insert(cut.row().getIndices()[i], cut.row().getElements()[i]/norma);
+    }
+    cut.setLb(cut.lb()/norma);
+    cut.setRow(row);
+}
+
+/** scale the cut passed as argument*/
+void scale(OsiRowCut &cut)
+{
+    double rhs = fabs(cut.lb());
+    CoinPackedVector row;
+    row.reserve(cut.row().getNumElements());
+    for (int i = 0 ; i < cut.row().getNumElements() ; i++)
+    {
+        row.insert(cut.row().getIndices()[i], cut.row().getElements()[i]/rhs);
+    }
+    cut.setLb(cut.lb()/rhs);
+    cut.setRow(row);
+}
+
+
+/** Modularize row.*/
+void modularizeRow(TabRow & row, const bool * integerVar)
+{
+    const int& n = row.getNumElements();
+    const int* ind = row.getIndices();
+    for (int i = 0 ; i < n ; i++)
+    {
+        const int &ni = ind[i];
+        if (integerVar[ni])
+            row[ni] = modularizedCoef(row[ni],row.rhs);
+    }
+}
+
+
+int
+Cuts::insertAll(OsiCuts & cs, CoinRelFltEq& eq)
+{
+    int r_val = 0;
+    for (unsigned int i = 0 ; i < cuts_.size() ; i++)
+    {
+        if (cuts_[i] != NULL)
+        {
+            cs.insertIfNotDuplicate(*cuts_[i], eq);
+            delete cuts_[i];
+            cuts_[i] = NULL;
+            r_val++;
+        }
+    }
+    return r_val;
+}
+
+/** insert a cut for variable i and count number of cuts.*/
+void
+Cuts::insert(int i, OsiRowCut * cut)
+{
+    if (cuts_[i] == NULL) numberCuts_++;
+    else
+    {
+        printf("Replacing cut with violation %g with one from optimal basis with violation %g.\n",
+               cuts_[i]->effectiveness(), cut->effectiveness());
+        delete cuts_[i];
+    }
+    cuts_[i] = cut;
+}
+
+}
+
diff --git a/cbits/coin/CglLandPUtils.hpp b/cbits/coin/CglLandPUtils.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPUtils.hpp
@@ -0,0 +1,99 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           LIF
+//           CNRS, Aix-Marseille Universites
+// Date:     02/23/08
+//
+// $Id: CglLandPUtils.hpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+
+#ifndef CglLandPUtils_H
+#define CglLandPUtils_H
+#include "CglLandPTabRow.hpp"
+
+class CoinRelFltEq;
+class OsiRowCut;
+class OsiCuts;
+#include <vector>
+#include <cmath>
+
+namespace LAP
+{
+/** Compute \$ \frac{\sum\limits_{j=1}^n | \overline a_{ij} |}{1 - \overline a_{i0}} \$ for row passed as argument.*/
+double normCoef(TabRow &row, int ncols, const int * nonBasics);
+/** scale the cut passed as argument*/
+void scale(OsiRowCut &cut);
+/** scale the cut passed as argument using provided normalization factor*/
+void scale(OsiRowCut &cut, double norma);
+/** Modularize row.*/
+void modularizeRow(TabRow & row, const bool * integerVar);
+
+
+/** return the coefficients of the intersection cut */
+inline double intersectionCutCoef(double alpha_i, double beta)
+{
+    if (alpha_i>0) return alpha_i* (1 - beta);
+    else return -alpha_i * beta;// (1 - beta);
+}
+
+/** compute the modularized row coefficient for an integer variable*/
+inline double modularizedCoef(double alpha, double beta)
+{
+    double f_i = alpha - floor(alpha);
+    if (f_i <= beta)
+        return f_i;
+    else
+        return f_i - 1;
+}
+
+/** Says is value is integer*/
+inline bool int_val(double value, double tol)
+{
+    return fabs( floor( value + 0.5 ) - value ) < tol;
+}
+
+
+/** To store extra cuts generated by columns from which they origin.*/
+struct Cuts
+{
+    Cuts():  numberCuts_(0), cuts_(0)
+    {
+    }
+    /** Puts all the cuts into an OsiCuts */
+    int insertAll(OsiCuts & cs, CoinRelFltEq& eq);
+    /** Destructor.*/
+    ~Cuts() {}
+    /** Access to row cut indexed by i*/
+    OsiRowCut * rowCut(unsigned int i)
+    {
+        return cuts_[i];
+    }
+    /** const access to row cut indexed by i*/
+    const OsiRowCut * rowCut(unsigned int i) const
+    {
+        return cuts_[i];
+    }
+    /** insert a cut for variable i and count number of cuts.*/
+    void insert(int i, OsiRowCut * cut);
+    /** Access to number of cuts.*/
+    int numberCuts()
+    {
+        return numberCuts_;
+    }
+    /** resize vector.*/
+    void resize(unsigned int i)
+    {
+        cuts_.resize(i, reinterpret_cast<OsiRowCut *> (NULL));
+    }
+private:
+    /** Stores the number of cuts.*/
+    int numberCuts_;
+    /** Store the cuts by index of the generating simple disjunction.*/
+    std::vector<OsiRowCut *> cuts_;
+};
+
+}
+#endif
+
diff --git a/cbits/coin/CglLandPValidator.cpp b/cbits/coin/CglLandPValidator.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPValidator.cpp
@@ -0,0 +1,327 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     11/22/05
+//
+// $Id: CglLandPValidator.cpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+#include "CglLandPValidator.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "OsiRowCut.hpp"
+
+#ifdef HAVE_CMATH
+# include <cmath>
+#else
+# ifdef HAVE_MATH_H
+#  include <math.h>
+# endif
+#endif
+
+
+namespace LAP
+{
+std::vector<std::string> Validator::rejections_;
+
+
+/** Clean an OsiCut
+\return 1 if min violation is too small
+\return 2 if small coefficient can not be removed
+\return 3 if dynamic is too big
+\return 4 if too many non zero element*/
+int
+Validator::cleanCut(OsiRowCut & aCut, const double * solCut, const OsiSolverInterface &si, const CglParam& par,
+                    const double * origColLower, const double * origColUpper)
+{
+    /** Compute fill-in in si */
+    int numcols = si.getNumCols();
+
+    const double * colLower = (origColLower) ? origColLower : si.getColLower();
+    const double * colUpper = (origColUpper) ? origColUpper : si.getColUpper();
+
+    int maxNnz = static_cast<int> (maxFillIn_ * static_cast<double> (numcols));
+
+    double rhs = aCut.lb();
+    assert (aCut.ub()> 1e50);
+
+    CoinPackedVector *vec = const_cast<CoinPackedVector *>(&aCut.row());
+    int * indices = vec->getIndices();
+    double * elems = vec->getElements();
+    int n = vec->getNumElements();
+
+    /** First compute violation if it is too small exit */
+    double violation = aCut.violated(solCut);
+    if (violation < minViolation_)
+        return 1;
+
+    /** Now relax get dynamic and remove tiny elements */
+    int offset = 0;
+    rhs -= 1e-8;
+    double smallest = 1e100;
+    double biggest = 0;
+    for (int i = 0 ; i < n ; i++)
+    {
+        double val = fabs(elems[i]);
+        if (val <= par.getEPS())   //try to remove coef
+        {
+            if (val>0 && val<1e-20)
+            {
+                offset++;
+                continue;
+                throw;
+            }
+            if (val==0)
+            {
+                offset++;
+                continue;
+            }
+
+            int & iCol = indices[i];
+            if (elems[i]>0. && colUpper[iCol] < 10000.)
+            {
+                offset++;
+                rhs -= elems[i] * colUpper[iCol];
+                elems[i]=0;
+            }
+            else if (elems[i]<0. && colLower[iCol] > -10000.)
+            {
+                offset++;
+                rhs -= elems[i] * colLower[iCol];
+                elems[i]=0.;
+            }
+            else
+            {
+#ifdef DEBUG
+                std::cout<<"Small coefficient : "<<elems[i]<<" bounds : ["<<colLower[iCol]<<", "<<colUpper[iCol]<<std::endl;
+#endif
+                numRejected_[SmallCoefficient]++;
+                return SmallCoefficient;
+            }
+        }
+
+        else   //Not a small coefficient keep it
+        {
+            smallest = std::min(val,smallest);
+            biggest = std::max (val,biggest);
+            if (biggest > maxRatio_ * smallest)
+            {
+#ifdef DEBUG
+                std::cout<<"Whaooo "<<biggest/smallest<<std::endl;
+#endif
+                numRejected_[BigDynamic]++;
+                return BigDynamic;
+            }
+            if (offset)   //if offset is zero current values are ok otherwise translate
+            {
+                int i2 = i - offset;
+                indices[i2] = indices[i];
+                elems[i2] = elems[i];
+            }
+        }
+    }
+    if ((n - offset) > maxNnz)
+    {
+        numRejected_[DenseCut] ++;
+        return DenseCut;
+    }
+    if (offset == n)
+    {
+        numRejected_[EmptyCut]++;
+        return EmptyCut;
+    }
+
+    if (offset)
+        vec->truncate(n - offset);
+
+    indices = vec->getIndices();
+    elems = vec->getElements();
+    n = vec->getNumElements();
+
+    aCut.setLb(rhs);
+    violation = aCut.violated(solCut);
+    if (violation < minViolation_)
+    {
+        numRejected_[SmallViolation]++;
+        return SmallViolation;
+    }
+
+    return NoneAccepted;
+}
+
+/**Clean cut 2, different algorithm. First check the dynamic of the cut if < maxRatio scale to a biggest coef of 1
+   otherwise scale it so that biggest coeff is 1 and try removing tinys ( < 1/maxRatio) either succeed or fail */
+int
+Validator::cleanCut2(OsiRowCut & aCut, const double * solCut, const OsiSolverInterface &si, const CglParam &/* par */,
+                     const double * origColLower, const double * origColUpper)
+{
+    /** Compute fill-in in si */
+    int numcols = si.getNumCols();
+    // int numrows = si.getNumRows();
+    const double * colLower = (origColLower) ? origColLower : si.getColLower();
+    const double * colUpper = (origColUpper) ? origColUpper : si.getColUpper();
+
+    int maxNnz = static_cast<int> ( maxFillIn_ * static_cast<double> (numcols));
+
+    double rhs = aCut.lb();
+    assert (aCut.ub()> 1e50);
+
+    CoinPackedVector *vec = const_cast<CoinPackedVector *>(&aCut.row());
+    //  vec->sortIncrIndex();
+
+    int * indices = vec->getIndices();
+    double * elems = vec->getElements();
+    int n = vec->getNumElements();
+    if (n==0)
+    {
+        numRejected_[EmptyCut]++;
+        return EmptyCut;
+    }
+    /** First compute violation if it is too small exit */
+    double violation = aCut.violated(solCut);
+    if (violation < minViolation_)
+        return 1;
+
+    /** Now relax get dynamic and remove tiny elements */
+    int offset = 0;
+    rhs -= 1e-10;
+    double smallest = fabs(rhs);
+    double biggest = smallest;
+    double veryTiny = 1e-20;
+    for (int i = 0 ; i < n ; i++)
+    {
+        double val = fabs(elems[i]);
+        if (val > veryTiny)   //tiny should be very very small
+        {
+            smallest = std::min(val,smallest);
+            biggest = std::max (val,biggest);
+        }
+    }
+
+    if (biggest > 1e9)
+    {
+#ifdef DEBUG
+        std::cout<<"Whaooo "<<biggest/smallest<<std::endl;
+#endif
+        numRejected_[BigDynamic]++;
+        return BigDynamic;
+    }
+
+    //rescale the cut so that biggest is 1e1.
+    double toBeBiggest = rhsScale_;
+    rhs *= (toBeBiggest / biggest);
+    toBeBiggest /= biggest;
+    for (int i = 0 ; i < n ; i++)
+    {
+        elems[i] *= toBeBiggest;
+    }
+
+
+    if (biggest > maxRatio_ * smallest)   //we have to remove some small coefficients
+    {
+        double myTiny = biggest * toBeBiggest / maxRatio_;
+        veryTiny *= toBeBiggest ;
+        for (int i = 0 ; i < n ; i++)
+        {
+            double val = fabs(elems[i]);
+            if (val < myTiny)
+            {
+                if (val< veryTiny)
+                {
+                    offset++;
+                    continue;
+                }
+                int & iCol = indices[i];
+                if (elems[i]>0. && colUpper[iCol] < 1000.)
+                {
+                    offset++;
+                    rhs -= elems[i] * colUpper[iCol];
+                    elems[i]=0;
+                }
+                else if (elems[i]<0. && colLower[iCol] > -1000.)
+                {
+                    offset++;
+                    rhs -= elems[i] * colLower[iCol];
+                    elems[i]=0.;
+                }
+                else
+                {
+                    numRejected_[SmallCoefficient]++;
+                    return SmallCoefficient;
+                }
+            }
+            else   //Not a small coefficient keep it
+            {
+                if (offset)   //if offset is zero current values are ok
+                {
+                    int i2 = i - offset;
+                    indices[i2] = indices[i];
+                    elems[i2] = elems[i];
+                }
+            }
+        }
+    }
+    if ((n - offset) > maxNnz)
+    {
+        numRejected_[DenseCut] ++;
+        return DenseCut;
+    }
+
+
+    if (offset)
+        vec->truncate(n - offset);
+
+    if (vec->getNumElements() == 0 )
+    {
+        numRejected_[EmptyCut]++;
+        return EmptyCut;
+    }
+
+    /** recheck violation */
+    aCut.setLb(rhs);
+    violation = aCut.violated(solCut);
+    if (violation < minViolation_)
+    {
+        numRejected_[SmallViolation]++;
+        return SmallViolation;
+    }
+    assert(fabs(rhs)<1e09);
+
+    return NoneAccepted;
+}
+
+
+/** Constructor with default values */
+Validator::Validator(double maxFillIn,
+                     double maxRatio,
+                     double minViolation,
+                     bool scale,
+                     double rhsScale):
+        maxFillIn_(maxFillIn),
+        maxRatio_(maxRatio),
+        minViolation_(minViolation),
+        scale_(scale),
+        rhsScale_(rhsScale),
+        numRejected_(DummyEnd,0)
+{
+    fillRejectionReasons();
+}
+
+
+void
+Validator::fillRejectionReasons()
+{
+    if (rejections_.size() == 0)
+    {
+        rejections_.resize(DummyEnd) ;
+        rejections_[NoneAccepted] = "Cut was accepted";
+        rejections_[SmallViolation] = "Violation of the cut is too small ";
+        rejections_[SmallCoefficient] = "There is a small coefficient we can not get rid off.";
+        rejections_[BigDynamic] = "Dynamic of coefficinet is too important. ";
+        rejections_[DenseCut] = "Cut is too dense.";
+        rejections_[EmptyCut] = "Cleaned cut is empty";
+    }
+}
+
+} /* Ends namespace LAP.*/
diff --git a/cbits/coin/CglLandPValidator.hpp b/cbits/coin/CglLandPValidator.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLandPValidator.hpp
@@ -0,0 +1,131 @@
+// Copyright (C) 2005-2009, Pierre Bonami and others.  All Rights Reserved.
+// Author:   Pierre Bonami
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     11/22/05
+//
+// $Id: CglLandPValidator.hpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//---------------------------------------------------------------------------
+
+#ifndef CglLandPValidator_H
+#define CglLandPValidator_H
+#include "OsiSolverInterface.hpp"
+#include "CglParam.hpp"
+#include <vector>
+
+/** constants describing rejection codes*/
+//[5] = {"Accepted", "violation too small", "small coefficient too small", "big dynamic","too dense"}
+
+
+namespace LAP
+{
+
+/** Class to validate or reject a cut */
+class Validator
+{
+public:
+    /** Reasons for rejecting a cut */
+    enum RejectionsReasons
+    {
+        NoneAccepted=0 /**Cut was accepted*/,
+        SmallViolation /** Violation of the cut is too small */,
+        SmallCoefficient /** There is a small coefficient we can not get rid off.*/,
+        BigDynamic /** Dynamic of coefficinet is too important. */,
+        DenseCut/**cut is too dense */,
+        EmptyCut/**After cleaning cut has become empty*/,
+        DummyEnd/** dummy*/
+    };
+
+    /** Constructor with default values */
+    Validator(double maxFillIn = 1.,
+              double maxRatio = 1e8,
+              double minViolation = 0,
+              bool scale = false,
+              double rhsScale = 1);
+
+    /** Clean an OsiCut */
+    int cleanCut(OsiRowCut & aCut, const double * solCut,const OsiSolverInterface &si, const CglParam & par,
+                 const double * colLower, const double * colUpper);
+    /** Clean an OsiCut by another method */
+    int cleanCut2(OsiRowCut & aCut, const double * solCut, const OsiSolverInterface &si, const CglParam & par,
+                  const double * colLower, const double * colUpper);
+    /** Call the cut cleaner */
+    int operator()(OsiRowCut & aCut, const double * solCut,const OsiSolverInterface &si, const CglParam & par,
+                   const double * colLower, const double * colUpper)
+    {
+        return cleanCut(aCut, solCut, si, par, colLower, colUpper);
+    }
+    /** @name set functions */
+    /** @{ */
+    void setMaxFillIn(double value)
+    {
+        maxFillIn_ = value;
+    }
+    void setMaxRatio(double value)
+    {
+        maxRatio_ = value;
+    }
+    void setMinViolation(double value)
+    {
+        minViolation_ = value;
+    }
+
+    void setRhsScale(double v)
+    {
+        rhsScale_ = v;
+    }
+    /** @} */
+    /** @name get functions */
+    /** @{ */
+    double getMaxFillIn()
+    {
+        return maxFillIn_;
+    }
+    double getMaxRatio()
+    {
+        return maxRatio_;
+    }
+    double getMinViolation()
+    {
+        return minViolation_;
+    }
+    /** @} */
+
+    const std::string& failureString(RejectionsReasons code) const
+    {
+        return rejections_[static_cast<int> (code)];
+    }
+    const std::string& failureString(int code) const
+    {
+        return rejections_[ code];
+    }
+    int numRejected(RejectionsReasons code)const
+    {
+        return numRejected_[static_cast<int> (code)];
+    }
+    int numRejected(int code)const
+    {
+        return numRejected_[ code];
+    }
+private:
+    static void fillRejectionReasons();
+    /** max percentage of given formulation fillIn should be accepted for cut fillin.*/
+    double maxFillIn_;
+    /** max ratio between smallest and biggest coefficient */
+    double maxRatio_;
+    /** minimum violation for accepting a cut */
+    double minViolation_;
+    /** Do we do scaling? */
+    bool scale_;
+    /** Scale of right-hand-side.*/
+    double rhsScale_;
+    /** Strings explaining reason for rejections */
+    static std::vector<std::string> rejections_;
+    /** Number of cut rejected for each of the reasons.*/
+    std::vector<int> numRejected_;
+};
+
+}/* Ends namespace LAP.*/
+#endif
diff --git a/cbits/coin/CglLiftAndProject.cpp b/cbits/coin/CglLiftAndProject.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLiftAndProject.cpp
@@ -0,0 +1,396 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cassert>
+#include <cfloat>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CglLiftAndProject.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinSort.hpp"
+#include "CoinPackedMatrix.hpp"
+
+//-----------------------------------------------------------------------------
+// Generate Lift-and-Project cuts
+//------------------------------------------------------------------- 
+void CglLiftAndProject::generateCuts(const OsiSolverInterface& si, OsiCuts& cs,
+				     const CglTreeInfo /*info*/)
+{
+  // Assumes the mixed 0-1 problem 
+  //
+  //   min {cx: <Atilde,x> >= btilde} 
+  //
+  // is in canonical form with all bounds,
+  // including x_t>=0, -x_t>=-1 for x_t binary,
+  // explicitly stated in the constraint matrix. 
+  // See ~/COIN/Examples/Cgl2/cgl2.cpp 
+  // for a general purpose "convert" function. 
+
+  // Reference [BCC]: Balas, Ceria, and Corneujols,
+  // "A lift-and-project cutting plane algorithm
+  // for mixed 0-1 program", Math Prog 58, (1993) 
+  // 295-324.
+
+  // This implementation uses Normalization 1.
+
+  // Given canonical problem and
+  // the lp-relaxation solution, x,
+  // the LAP cut generator attempts to construct
+  // a cut for every x_j such that 0<x_j<1
+  // [BCC:307]
+ 
+
+  // x_j is the strictly fractional binary variable
+  // the cut is generated from
+  int j = 0; 
+
+  // Get basic problem information
+  // let Atilde be an m by n matrix
+  const int m = si.getNumRows(); 
+  const int n = si.getNumCols(); 
+  const double * x = si.getColSolution();
+
+  // Remember - Atildes may have gaps..
+  const CoinPackedMatrix * Atilde = si.getMatrixByRow();
+  const double * AtildeElements =  Atilde->getElements();
+  const int * AtildeIndices =  Atilde->getIndices();
+  const CoinBigIndex * AtildeStarts = Atilde->getVectorStarts();
+  const int * AtildeLengths = Atilde->getVectorLengths();  
+  const int AtildeFullSize = AtildeStarts[m];
+  const double * btilde = si.getRowLower();
+
+  // Set up memory for system (10) [BCC:307]
+  // (the problem over the norm intersected 
+  //  with the polar cone)
+  // 
+  // min <<x^T,Atilde^T>,u> + x_ju_0
+  // s.t.
+  //     <B,w> = (0,...,0,beta_,beta)^T
+  //        w  is nonneg for all but the
+  //           last two entries, which are free.
+  // where 
+  // w = (u,v,v_0,u_0)in BCC notation 
+  //      u and v are m-vectors; u,v >=0
+  //      v_0 and u_0 are free-scalars, and
+  //  
+  // B = Atilde^T  -Atilde^T  -e_j e_j
+  //     btilde^T   e_0^T      0   0
+  //     e_0^T      btilde^T   1   0
+
+  // ^T indicates Transpose
+  // e_0 is a (AtildeNCols x 1) vector of all zeros 
+  // e_j is e_0 with a 1 in the jth position
+
+  // Storing B in column order. B is a (n+2 x 2m+2) matrix 
+  // But need to allow for possible gaps in Atilde.
+  // At each iteration, only need to change 2 cols and objfunc
+  // Sane design of OsiSolverInterface does not permit mucking
+  // with matrix.
+  // Because we must delete and add cols to alter matrix,
+  // and we can only add columns on the end of the matrix
+  // put the v_0 and u_0 columns on the end.
+  // rather than as described in [BCC]
+ 
+  // Initially allocating B with space for v_0 and u_O cols
+  // but not populating, for efficiency.
+
+  // B without u_0 and v_0 is a (n+2 x 2m) size matrix.
+
+  int twoM = 2*m;
+  int BNumRows = n+2;
+  int BNumCols = twoM+2;
+  int BFullSize = 2*AtildeFullSize+twoM+3;
+  double * BElements = new double[BFullSize];
+  int * BIndices = new int[BFullSize];
+  CoinBigIndex * BStarts = new CoinBigIndex [BNumCols+1];
+  int * BLengths = new int[BNumCols];
+
+
+  int i, ij, k=0;
+  int nPlus1=n+1;
+  int offset = AtildeStarts[m]+m;
+  for (i=0; i<m; i++){
+    for (ij=AtildeStarts[i];ij<AtildeStarts[i]+AtildeLengths[i];ij++){
+      BElements[k]=AtildeElements[ij];
+      BElements[k+offset]=-AtildeElements[ij];
+      BIndices[k]= AtildeIndices[ij];
+      BIndices[k+offset]= AtildeIndices[ij];
+
+      k++;
+    }
+    BElements[k]=btilde[i];
+    BElements[k+offset]=btilde[i];
+    BIndices[k]=n;
+    BIndices[k+offset]=nPlus1;
+    BStarts[i]= AtildeStarts[i]+i;
+    BStarts[i+m]=offset+BStarts[i];// = AtildeStarts[m]+m+AtildeStarts[i]+i
+    BLengths[i]= AtildeLengths[i]+1;
+    BLengths[i+m]= AtildeLengths[i]+1;
+    k++;
+  }
+
+  BStarts[twoM]=BStarts[twoM-1]+BLengths[twoM-1];
+
+  // Cols that will be deleted each iteration
+  int BNumColsLessOne=BNumCols-1;
+  int BNumColsLessTwo=BNumCols-2;
+  const int delCols[2] = {BNumColsLessOne, BNumColsLessTwo};
+
+  // Set lower bound on u and v
+  // u_0, v_0 will be reset as free
+  const double solverINFINITY = si.getInfinity();
+  double * BColLowers = new double[BNumCols];
+  double * BColUppers = new double[BNumCols];
+  CoinFillN(BColLowers,BNumCols,0.0);  
+  CoinFillN(BColUppers,BNumCols,solverINFINITY); 
+
+  // Set row lowers and uppers.
+  // The rhs is zero, for but the last two rows.
+  // For these the rhs is beta_
+  double * BRowLowers = new double[BNumRows];
+  double * BRowUppers = new double[BNumRows];
+  CoinFillN(BRowLowers,BNumRows,0.0);  
+  CoinFillN(BRowUppers,BNumRows,0.0);
+  BRowLowers[BNumRows-2]=beta_;
+  BRowUppers[BNumRows-2]=beta_;
+  BRowLowers[BNumRows-1]=beta_;
+  BRowUppers[BNumRows-1]=beta_;
+
+
+  // Calculate base objective <<x^T,Atilde^T>,u>
+  // Note: at each iteration coefficient u_0
+  //       changes to <x^T,e_j>
+  //       w=(u,v,beta,v_0,u_0) size 2m+3
+  //       So, BOjective[2m+2]=x[j]
+  double * BObjective= new double[BNumCols];
+  double * Atildex = new double[m];
+  CoinFillN(BObjective,BNumCols,0.0);
+  Atilde->times(x,Atildex); // Atildex is size m, x is size n
+  CoinDisjointCopyN(Atildex,m,BObjective); 
+
+  // Number of cols and size of Elements vector
+  // in B without the v_0 and u_0 cols
+  int BFullSizeLessThree = BFullSize-3;
+
+  // Load B matrix into a column orders CoinPackedMatrix
+  CoinPackedMatrix * BMatrix = new CoinPackedMatrix(true, BNumRows,
+						  BNumColsLessTwo, 
+						  BFullSizeLessThree,
+						  BElements,BIndices, 
+						  BStarts,BLengths);
+  // Assign problem into a solver interface 
+  // Note: coneSi will cleanup the memory itself
+  OsiSolverInterface * coneSi = si.clone(false);
+  coneSi->assignProblem (BMatrix, BColLowers, BColUppers, 
+		      BObjective,
+		      BRowLowers, BRowUppers);
+
+  // Problem sense should default to "min" by default, 
+  // but just to be virtuous...
+  coneSi->setObjSense(1.0);
+
+  // The plot outline from here on down:
+  // coneSi has been assigned B without the u_0 and v_0 columns
+  // Calculate base objective <<x^T,Atilde^T>,u>
+  // bool haveWarmStart = false;
+  // For (j=0; j<n, j++)
+  //   if (!isBinary(x_j) || x_j<=0 || x_j>=1) continue;
+  //   // IMPROVEME: if(haveWarmStart) check if j attractive
+  //   add {-e_j,0,-1} matrix column for v_0
+  //   add {e_j,0,0} matrix column for u_0
+  //   objective coefficient for u_0 is  x_j 
+  //   if (haveWarmStart) 
+  //      set warmstart info
+  //   solve min{objw:Bw=0; w>=0,except v_0, u_0 free}
+  //   if (bounded)
+  //      get warmstart info
+  //      haveWarmStart=true;
+  //      ustar = optimal u solution
+  //      ustar_0 = optimal u_0 solution
+  //      alpha^T= <ustar^T,Atilde> -ustar_0e_j^T
+  //      (double check <alpha^T,x> >= beta_ should be violated)
+  //      add <alpha^T,x> >= beta_ to cutset 
+  //   endif
+  //   delete column for u_0 // this deletes all column info.
+  //   delete column for v_0
+  // endFor
+  // clean up memory
+  // return 0;
+
+  int * nVectorIndices = new int[n];
+  CoinIotaN(nVectorIndices, n, 0);
+
+  bool haveWarmStart = false;
+  bool equalObj1, equalObj2;
+  CoinRelFltEq eq;
+
+  double v_0Elements[2] = {-1,1};
+  double u_0Elements[1] = {1};
+
+  CoinWarmStart * warmStart = 0;
+
+  double * ustar = new double[m];
+  CoinFillN(ustar, m, 0.0);
+
+  double* alpha = new double[n];
+  CoinFillN(alpha, n, 0.0);
+
+  for (j=0;j<n;j++){
+    if (!si.isBinary(j)) continue; // Better to ask coneSi? No! 
+                                   // coneSi has no binInfo.
+    equalObj1=eq(x[j],0);
+    equalObj2=eq(x[j],1);
+    if (equalObj1 || equalObj2) continue;
+    // IMPROVEME: if (haveWarmStart) check if j attractive;
+
+    // AskLL:wanted to declare u_0 and v_0 packedVec outside loop
+    // and setIndices, but didn't see a method to do that(?)
+    // (Could "insert". Seems inefficient)
+    int v_0Indices[2]={j,nPlus1};
+    int u_0Indices[1]={j};
+    // 
+    CoinPackedVector  v_0(2,v_0Indices,v_0Elements,false);
+    CoinPackedVector  u_0(1,u_0Indices,u_0Elements,false);
+
+#if CGL_DEBUG
+    const CoinPackedMatrix *see1 = coneSi->getMatrixByRow();
+#endif
+
+    coneSi->addCol(v_0,-solverINFINITY,solverINFINITY,0);
+    coneSi->addCol(u_0,-solverINFINITY,solverINFINITY,x[j]);
+    if(haveWarmStart) {
+      coneSi->setWarmStart(warmStart);
+      coneSi->resolve();
+    }
+    else {
+
+#if CGL_DEBUG
+      const CoinPackedMatrix *see2 = coneSi->getMatrixByRow();
+#endif
+
+      coneSi->initialSolve();
+    }
+    if(coneSi->isProvenOptimal()){
+      warmStart = coneSi->getWarmStart();
+      haveWarmStart=true;
+      const double * wstar = coneSi->getColSolution();
+      CoinDisjointCopyN(wstar, m, ustar);
+      Atilde->transposeTimes(ustar,alpha);
+      alpha[j]+=wstar[BNumCols-1]; 
+      
+#if debug
+      int p;
+      double sum;
+      for(p=0;p<n;p++)sum+=alpha[p]*x[p];
+      if (sum<=beta_){
+	throw CoinError("Cut not violated",
+			"cutGeneration",
+			"CglLiftAndProject");
+      }
+#endif
+
+      // add <alpha^T,x> >= beta_ to cutset
+      OsiRowCut rc;
+      rc.setRow(n,nVectorIndices,alpha);
+      rc.setLb(beta_);
+      rc.setUb(solverINFINITY);
+      cs.insert(rc);
+    }
+    // delete col for u_o and v_0
+    coneSi->deleteCols(2,delCols);
+
+    // clean up memory
+  }
+  // clean up
+  delete [] alpha;
+  delete [] ustar;
+  delete [] nVectorIndices;
+  // BMatrix, BColLowers,BColUppers, BObjective, BRowLowers, BRowUppers
+  // are all freed by OsiSolverInterface destructor (?)
+  delete [] BLengths;
+  delete [] BStarts;
+  delete [] BIndices;
+  delete [] BElements;
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglLiftAndProject::CglLiftAndProject ()
+:
+CglCutGenerator(),
+beta_(1),
+epsilon_(1.0e-08),
+onetol_(1-epsilon_)
+{
+  // nothing to do here
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglLiftAndProject::CglLiftAndProject (const CglLiftAndProject & source) :
+   CglCutGenerator(source),
+   beta_(source.beta_),
+   epsilon_(source.epsilon_),
+   onetol_(source.onetol_)
+{
+  // Nothing to do here
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglLiftAndProject::clone() const
+{
+  return new CglLiftAndProject(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglLiftAndProject::~CglLiftAndProject ()
+{
+  // Nothing to do here
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglLiftAndProject &
+CglLiftAndProject::operator=(
+                                         const CglLiftAndProject& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    beta_=rhs.beta_;
+    epsilon_=rhs.epsilon_;
+    onetol_=rhs.onetol_;
+  }
+  return *this;
+}
+// Create C++ lines to get to current state
+std::string
+CglLiftAndProject::generateCpp( FILE * fp) 
+{
+  CglLiftAndProject other;
+  fprintf(fp,"0#include \"CglLiftAndProject.hpp\"\n");
+  fprintf(fp,"3  CglLiftAndProject liftAndProject;\n");
+  if (beta_!=other.beta_)
+    fprintf(fp,"3  liftAndProject.setBeta(%d);\n",static_cast<int> (beta_));
+  else
+    fprintf(fp,"4  liftAndProject.setBeta(%d);\n",static_cast<int> (beta_));
+  fprintf(fp,"3  liftAndProject.setAggressiveness(%d);\n",getAggressiveness());
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  liftAndProject.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  liftAndProject.setAggressiveness(%d);\n",getAggressiveness());
+  return "liftAndProject";
+}
diff --git a/cbits/coin/CglLiftAndProject.hpp b/cbits/coin/CglLiftAndProject.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglLiftAndProject.hpp
@@ -0,0 +1,104 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglLiftAndProject_H
+#define CglLiftAndProject_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+
+/** Lift And Project Cut Generator Class */
+class CglLiftAndProject : public CglCutGenerator {
+   friend void CglLiftAndProjectUnitTest(const OsiSolverInterface * siP,
+					const std::string mpdDir );
+
+public:
+  /**@name Generate Cuts */
+  //@{
+  /** Generate lift-and-project cuts for the 
+      model of the solver interface, si. 
+      Insert the generated cuts into OsiCut, cs.
+  */
+  virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			    const CglTreeInfo info = CglTreeInfo());
+
+  /** Get the normalization : Either beta=+1 or beta=-1.
+  */
+
+  double getBeta() const {
+    return beta_;
+  }
+
+  /** Set the normalization : Either beta=+1 or beta=-1.
+      Default value is 1.
+  */
+  void setBeta(int oneOrMinusOne){
+    if (oneOrMinusOne==1 || oneOrMinusOne==-1){
+      beta_= static_cast<double>(oneOrMinusOne);
+    }
+    else {
+      throw CoinError("Unallowable value. Beta must be 1 or -1",
+		      "cutGeneration","CglLiftAndProject");
+    }
+  }
+
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglLiftAndProject ();
+ 
+  /// Copy constructor 
+  CglLiftAndProject (
+    const CglLiftAndProject &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglLiftAndProject &
+    operator=(
+    const CglLiftAndProject& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglLiftAndProject ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  //@}
+
+private:
+  
+ // Private member methods
+
+  /**@name Private methods */
+  //@{
+
+  //@}
+
+  // Private member data
+
+  /**@name Private member data */
+  //@{
+  /// The normalization is beta_=1 or beta_=-1
+  double beta_;  
+  /// epsilon
+  double epsilon_;  
+  /// 1-epsilon
+  double onetol_;  
+  //@}
+};
+
+//#############################################################################
+/** A function that tests the methods in the CglLiftAndProject class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglLiftAndProjectUnitTest(const OsiSolverInterface * siP,
+			      const std::string mpdDir );
+  
+#endif
diff --git a/cbits/coin/CglMessage.cpp b/cbits/coin/CglMessage.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglMessage.cpp
@@ -0,0 +1,54 @@
+// $Id: CglMessage.cpp 1113 2013-04-06 13:28:20Z stefan $
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "CglMessage.hpp"
+#include <cstring>
+/// Structure for use by CglMessage.cpp
+typedef struct {
+  CGL_Message internalNumber;
+  int externalNumber; // or continuation
+  char detail;
+  const char * message;
+} Cgl_message;
+static Cgl_message us_english[]=
+{
+  {CGL_INFEASIBLE,0,1,"Cut generators found to be infeasible! (or unbounded)"},
+  {CGL_CLIQUES,1,2,"%d cliques of average size %g"},
+  {CGL_FIXED,2,1,"%d variables fixed"},
+  {CGL_PROCESS_STATS,3,1,"%d fixed, %d tightened bounds, %d strengthened rows, %d substitutions"},
+  {CGL_SLACKS,8,1,"%d inequality constraints converted to equality constraints"},
+  {CGL_PROCESS_STATS2,4,1,"processed model has %d rows, %d columns (%d integer) and %d elements"},
+  {CGL_PROCESS_SOS1,5,1,"%d SOS with %d members"},
+  {CGL_PROCESS_SOS2,6,2,"%d SOS (%d members out of %d) with %d overlaps - too much overlap or too many others"},
+  {CGL_UNBOUNDED,7,1,"Continuous relaxation is unbounded!"},
+  {CGL_ELEMENTS_CHANGED1,9,2,"%d elements changed"},
+  {CGL_ELEMENTS_CHANGED2,10,3,"element in row %d for column %d changed from %g to %g"},
+  {CGL_MADE_INTEGER,11,1,"%d variables made integer"},
+  {CGL_ADDED_INTEGERS,12,1,"Added %d variables (from %d rows) with %d elements"},
+  {CGL_POST_INFEASIBLE,13,1,"Postprocessed model is infeasible - possible tolerance issue - try without preprocessing"},
+  {CGL_POST_CHANGED,14,1,"Postprocessing changed objective from %g to %g - possible tolerance issue - try without preprocessing"},
+  {CGL_GENERAL, 1000, 1, "%s"},
+  {CGL_DUMMY_END,999999,0,""}
+};
+/* Constructor */
+CglMessage::CglMessage(Language language) :
+  CoinMessages(sizeof(us_english)/sizeof(Cgl_message))
+{
+  language_=language;
+  strcpy(source_,"Cgl");
+  class_ = 3; // Cuts
+  Cgl_message * message = us_english;
+
+  while (message->internalNumber!=CGL_DUMMY_END) {
+     CoinOneMessage oneMessage(message->externalNumber,message->detail,
+			       message->message);
+     addMessage(message->internalNumber,oneMessage);
+     message ++;
+  }
+  // Put into compact form
+  toCompact();
+
+}
diff --git a/cbits/coin/CglMessage.hpp b/cbits/coin/CglMessage.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglMessage.hpp
@@ -0,0 +1,50 @@
+// $Id: CglMessage.hpp 1113 2013-04-06 13:28:20Z stefan $
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglMessage_H
+#define CglMessage_H
+
+
+#include "CoinPragma.hpp"
+
+// This deals with Cgl messages (as against Osi messages etc)
+
+#include "CoinMessageHandler.hpp"
+enum CGL_Message
+{
+  CGL_INFEASIBLE,
+  CGL_CLIQUES,
+  CGL_FIXED,
+  CGL_PROCESS_STATS,
+  CGL_SLACKS,
+  CGL_PROCESS_STATS2,
+  CGL_PROCESS_SOS1,
+  CGL_PROCESS_SOS2,
+  CGL_UNBOUNDED,
+  CGL_ELEMENTS_CHANGED1,
+  CGL_ELEMENTS_CHANGED2,
+  CGL_MADE_INTEGER,
+  CGL_ADDED_INTEGERS,
+  CGL_POST_INFEASIBLE,
+  CGL_POST_CHANGED,
+  CGL_GENERAL,
+  CGL_DUMMY_END
+};
+
+/** This deals with Cgl messages (as against Osi messages etc)
+ */
+class CglMessage : public CoinMessages {
+
+public:
+
+  /**@name Constructors etc */
+  //@{
+  /** Constructor */
+  CglMessage(Language language=us_en);
+  //@}
+
+};
+
+#endif
diff --git a/cbits/coin/CglMixedIntegerRounding.cpp b/cbits/coin/CglMixedIntegerRounding.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglMixedIntegerRounding.cpp
@@ -0,0 +1,1717 @@
+// LAST EDIT: 
+//-----------------------------------------------------------------------------
+// name: Mixed Integer Rounding Cut Generator
+// authors: Joao Goncalves (jog7@lehigh.edu) 
+//          Laszlo Ladanyi (ladanyi@us.ibm.com) 
+// date: August 11, 2004 
+//-----------------------------------------------------------------------------
+// Copyright (C) 2004, International Business Machines Corporation and others. 
+// All Rights Reserved.
+// This code is published under the Eclipse Public License.
+
+//#include <cmath>
+//#include <cstdlib>
+#include <cassert>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinPackedVector.hpp"
+
+#include "CglMixedIntegerRounding.hpp"
+//#define CGL_DEBUG 1
+//-----------------------------------------------------------------------------
+// Generate Mixed Integer Rounding inequality
+//------------------------------------------------------------------- 
+void
+CglMixedIntegerRounding::generateCuts(const OsiSolverInterface& si,
+				      OsiCuts& cs,
+				      const CglTreeInfo )
+{
+
+  // If the LP or integer presolve is used, then need to redo preprocessing
+  // everytime this function is called. Otherwise, just do once.
+  bool preInit = false;
+  bool preReso = false;
+  si.getHintParam(OsiDoPresolveInInitial, preInit);
+  si.getHintParam(OsiDoPresolveInResolve, preReso);
+  if (preInit == false &&  preReso == false && doPreproc_ == -1 ) { // Do once
+    if (doneInitPre_ == false) {   
+      mixIntRoundPreprocess(si);
+      doneInitPre_ = true;
+    }
+  }
+  else {
+    if(doPreproc_ == 1){ // Do everytime       
+      mixIntRoundPreprocess(si);
+      doneInitPre_ = true;
+    } 
+    else {
+      if (doneInitPre_ == false) {   
+	mixIntRoundPreprocess(si);
+	doneInitPre_ = true;
+      }  
+    }
+  }
+
+  const double* xlp        = si.getColSolution();  // LP solution
+  const double* colUpperBound = si.getColUpper();  // vector of upper bounds
+  const double* colLowerBound = si.getColLower();  // vector of lower bounds
+
+  // get matrix by row
+  const CoinPackedMatrix & tempMatrixByRow = *si.getMatrixByRow();
+  CoinPackedMatrix matrixByRow;
+  matrixByRow.submatrixOf(tempMatrixByRow, numRows_, indRows_);
+  CoinPackedMatrix matrixByCol = matrixByRow;
+  matrixByCol.reverseOrdering();
+  //const CoinPackedMatrix & matrixByRow = *si.getMatrixByRow();
+  const double* LHS        = si.getRowActivity();
+  const double* coefByRow  = matrixByRow.getElements();
+  const int* colInds       = matrixByRow.getIndices();
+  const int* rowStarts     = matrixByRow.getVectorStarts();
+  const int* rowLengths    = matrixByRow.getVectorLengths();
+
+  // get matrix by column
+  //const CoinPackedMatrix & matrixByCol = *si.getMatrixByCol();
+  const double* coefByCol  = matrixByCol.getElements();
+  const int* rowInds       = matrixByCol.getIndices();
+  const int* colStarts     = matrixByCol.getVectorStarts();
+  const int* colLengths    = matrixByCol.getVectorLengths();
+
+
+  generateMirCuts(si, xlp, colUpperBound, colLowerBound,
+		  matrixByRow, LHS, coefByRow,
+		  colInds, rowStarts, rowLengths, //matrixByCol,
+		  coefByCol, rowInds, colStarts, colLengths,
+		  cs);
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding::CglMixedIntegerRounding ()
+  :
+  CglCutGenerator()
+{ 
+  gutsOfConstruct(1, true, 1, -1);
+}
+
+
+//-------------------------------------------------------------------
+// Alternate Constructor 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding::CglMixedIntegerRounding (const int maxaggr,
+						  const bool multiply,
+						  const int criterion,
+						  const int preproc)
+  :
+  CglCutGenerator()
+{ 
+  gutsOfConstruct(maxaggr, multiply, criterion, preproc);
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding::CglMixedIntegerRounding ( 
+				 const CglMixedIntegerRounding & rhs)
+  :
+  CglCutGenerator(rhs)
+{ 
+  gutsOfCopy(rhs);
+}
+
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglMixedIntegerRounding::clone() const
+{
+  return new CglMixedIntegerRounding(*this);
+}
+
+//------------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding &
+CglMixedIntegerRounding::operator=(const CglMixedIntegerRounding& rhs)
+{
+  if (this != &rhs) {
+    gutsOfDelete();
+    CglCutGenerator::operator=(rhs);
+    gutsOfCopy(rhs);
+  }
+  return *this;
+}
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------  
+CglMixedIntegerRounding::~CglMixedIntegerRounding ()
+{
+  gutsOfDelete();
+}
+
+//-------------------------------------------------------------------
+// Construct
+//-------------------------------------------------------------------  
+void
+CglMixedIntegerRounding::gutsOfConstruct (const int maxaggr,
+					  const bool multiply,
+					  const int criterion,
+					  const int preproc)
+{
+  if (maxaggr > 0) {
+    MAXAGGR_ = maxaggr;
+  }
+  else {
+    throw CoinError("Unallowable value. maxaggr must be > 0",
+                      "gutsOfConstruct","CglMixedIntegerRounding");
+  }
+  MULTIPLY_ = multiply;
+  if ((criterion >= 1) && (criterion <= 3)) {
+    CRITERION_ = criterion;
+  }
+  else {
+    throw CoinError("Unallowable value. criterion must be 1, 2 or 3",
+                      "gutsOfConstruct","CglMixedIntegerRounding");
+  }
+  if ((preproc >= -1) && (preproc <= 2)) {
+    doPreproc_ = preproc;
+  }
+  else {
+    throw CoinError("Unallowable value. preproc must be -1, 0 or 1",
+                      "gutsOfConstruct","CglMixedIntegerRounding");
+  }
+  EPSILON_ = 1.0e-6;
+  UNDEFINED_ = -1;
+  TOLERANCE_ = 1.0e-4;
+  numRows_ = 0;
+  numCols_ = 0;
+  doneInitPre_ = false;
+  vubs_ = 0;
+  vlbs_ = 0;
+  rowTypes_ = 0;
+  indRows_ = 0;
+  numRowMix_ = 0;
+  indRowMix_ = 0;
+  numRowCont_ = 0;
+  indRowCont_ = 0;
+  numRowInt_ = 0;
+  indRowInt_ = 0;
+  numRowContVB_ = 0;
+  indRowContVB_ = 0;
+  sense_=NULL;
+  RHS_=NULL;
+}
+
+//-------------------------------------------------------------------
+// Delete
+//-------------------------------------------------------------------  
+void
+CglMixedIntegerRounding::gutsOfDelete ()
+{
+  if (vubs_ != 0) { delete [] vubs_; vubs_ = 0; }
+  if (vlbs_ != 0) { delete [] vlbs_; vlbs_ = 0; }
+  if (rowTypes_ != 0) { delete [] rowTypes_; rowTypes_ = 0; } 
+  if (indRows_ != 0) { delete [] indRows_; indRows_ = 0; }
+  if (indRowMix_ != 0) { delete [] indRowMix_; indRowMix_ = 0; }
+  if (indRowCont_ != 0) { delete [] indRowCont_; indRowCont_ = 0; }
+  if (indRowInt_ != 0) { delete [] indRowInt_; indRowInt_ = 0; }
+  if (indRowContVB_ != 0) { delete [] indRowContVB_; indRowContVB_ = 0; }
+  if (sense_ !=NULL) { delete [] sense_; sense_=NULL;}
+  if (RHS_ !=NULL) { delete [] RHS_; RHS_=NULL;}
+}
+
+//-------------------------------------------------------------------
+// Copy
+//-------------------------------------------------------------------  
+void
+CglMixedIntegerRounding::gutsOfCopy (const CglMixedIntegerRounding& rhs)
+{
+  MAXAGGR_ = rhs.MAXAGGR_;
+  MULTIPLY_ = rhs.MULTIPLY_;
+  CRITERION_ = rhs.CRITERION_;
+  EPSILON_ = rhs.EPSILON_;
+  UNDEFINED_ = rhs.UNDEFINED_;
+  TOLERANCE_ = rhs.TOLERANCE_;
+  doPreproc_ = rhs.doPreproc_;
+  numRows_ = rhs.numRows_;
+  numCols_ = rhs.numCols_;
+  doneInitPre_ = rhs.doneInitPre_;
+  numRowMix_ = rhs.numRowMix_;
+  numRowCont_ = rhs.numRowCont_;
+  numRowInt_ = rhs.numRowInt_;
+  numRowContVB_ = rhs.numRowContVB_;
+
+  if (numCols_ > 0) {
+    vubs_ = new CglMixIntRoundVUB [numCols_];
+    vlbs_ = new CglMixIntRoundVLB [numCols_];
+    CoinDisjointCopyN(rhs.vubs_, numCols_, vubs_);
+    CoinDisjointCopyN(rhs.vlbs_, numCols_, vlbs_);
+  }
+  else {
+    vubs_ = 0;
+    vlbs_ = 0;
+  }
+
+  if (numRows_ > 0) {
+    rowTypes_ = new RowType [numRows_];
+    CoinDisjointCopyN(rhs.rowTypes_, numRows_, rowTypes_);
+    indRows_ = new int [numRows_];
+    CoinDisjointCopyN(rhs.indRows_, numRows_, indRows_);
+    sense_ = CoinCopyOfArray(rhs.sense_,numRows_);
+    RHS_ = CoinCopyOfArray(rhs.RHS_,numRows_);
+  }
+  else {
+    rowTypes_ = 0;
+    indRows_ = 0;
+    sense_=NULL;
+    RHS_=NULL;
+  }
+
+  if (numRowMix_ > 0) {
+    indRowMix_ = new int [numRowMix_];
+    CoinDisjointCopyN(rhs.indRowMix_, numRowMix_, indRowMix_);
+  }
+  else {
+    indRowMix_ = 0;
+  }
+
+  if (numRowCont_ > 0) {
+    indRowCont_ = new int [numRowCont_];
+    CoinDisjointCopyN(rhs.indRowCont_, numRowCont_, indRowCont_);
+    indRowContVB_ = new int [numRowCont_];
+    CoinDisjointCopyN(rhs.indRowContVB_, numRowCont_, indRowContVB_);
+  }
+  else {
+    indRowCont_ = 0;
+    indRowContVB_ = 0;
+  }
+
+  if (numRowInt_ > 0) {
+    indRowInt_ = new int [numRowInt_];
+    CoinDisjointCopyN(rhs.indRowInt_, numRowInt_, indRowInt_);
+  }
+  else {
+    indRowInt_ = 0;
+  }
+
+}
+
+//-------------------------------------------------------------------
+// Do preprocessing
+// It determines the type of each row. It also identifies the variable
+// upper bounds and variable lower bounds.
+//-------------------------------------------------------------------  
+void 
+CglMixedIntegerRounding::
+mixIntRoundPreprocess(const OsiSolverInterface& si)
+{
+  // get matrix stored by row
+  const CoinPackedMatrix & matrixByRow = *si.getMatrixByRow();
+  numRows_ = si.getNumRows();
+  numCols_ = si.getNumCols();
+  const double* coefByRow  = matrixByRow.getElements();
+  const int* colInds       = matrixByRow.getIndices();
+  const int* rowStarts     = matrixByRow.getVectorStarts();
+  const int* rowLengths    = matrixByRow.getVectorLengths();
+  // Get copies of sense and RHS so we can modify if ranges
+  if (sense_) {
+    delete [] sense_;
+    delete [] RHS_;
+  }
+  sense_ = CoinCopyOfArray(si.getRowSense(),numRows_);
+  RHS_  = CoinCopyOfArray(si.getRightHandSide(),numRows_);
+
+  if (rowTypes_ != 0) {
+    delete [] rowTypes_; rowTypes_ = 0;
+  }
+  rowTypes_ = new RowType [numRows_];     // Destructor will free memory
+
+  // Summarize the row type infomation.
+  int numUNDEFINED   = 0;
+  int numVARUB       = 0;
+  int numVARLB       = 0;
+  int numVAREQ       = 0;
+  int numMIX         = 0;
+  int numCONT        = 0;
+  int numINT         = 0;
+  int numOTHER       = 0;
+
+  int iRow;
+  const double* rowActivity        = si.getRowActivity();
+  const double* rowLower        = si.getRowLower();
+  const double* rowUpper        = si.getRowUpper();
+  for (iRow = 0; iRow < numRows_; ++iRow) {
+    // If range then choose which to use
+    if (sense_[iRow]=='R') {
+      if (rowActivity[iRow]-rowLower[iRow]<
+          rowUpper[iRow]-rowActivity[iRow]) {
+        // treat as G row
+        RHS_[iRow]=rowLower[iRow];
+        sense_[iRow]='G';
+      } else {
+        // treat as L row
+        RHS_[iRow]=rowUpper[iRow];
+        sense_[iRow]='L';
+      }
+    }
+    // get the type of a row
+    const RowType rowType = 
+      determineRowType(si, rowLengths[iRow], colInds+rowStarts[iRow],
+		       coefByRow+rowStarts[iRow], sense_[iRow], RHS_[iRow]);
+    // store the type of the current row
+    rowTypes_[iRow] = rowType;
+
+    // Summarize information about row types
+    switch(rowType) {
+    case  ROW_UNDEFINED:
+      ++numUNDEFINED; 
+      break;
+    case  ROW_VARUB:
+      ++numVARUB; 
+      break;
+    case  ROW_VARLB:
+      ++numVARLB; 
+      break;
+    case  ROW_VAREQ:
+      ++numVAREQ; 
+      break;
+    case  ROW_MIX:
+      ++numMIX; 
+      break;
+    case  ROW_CONT:
+      ++numCONT; 
+      break;
+    case  ROW_INT:
+      ++numINT; 
+      break;
+    case  ROW_OTHER:
+      ++numOTHER; 
+      break;
+    default:
+      throw CoinError("Unknown row type", "MixIntRoundPreprocess",
+		      "CglMixedIntegerRounding");
+    }
+  }
+
+  // allocate memory for vector of indices of all rows
+  if (indRows_ != 0) { delete [] indRows_; indRows_ = 0; }
+  if (numRows_ > 0)
+    indRows_ = new int [numRows_];     // Destructor will free memory
+  // allocate memory for vector of indices of rows of type ROW_MIX
+  numRowMix_ = numMIX;
+  if (indRowMix_ != 0) { delete [] indRowMix_; indRowMix_ = 0; }
+  if (numRowMix_ > 0)
+    indRowMix_ = new int [numRowMix_];     // Destructor will free memory
+  // allocate memory for vector of indices of rows of type ROW_CONT
+  numRowCont_ = numCONT;
+  if (indRowCont_ != 0) { delete [] indRowCont_; indRowCont_ = 0; }
+  if (numRowCont_ > 0)
+    indRowCont_ = new int [numRowCont_];     // Destructor will free memory
+  // allocate memory for vector of indices of rows of type ROW_INT
+  numRowInt_ = numINT;
+  if (indRowInt_ != 0) { delete [] indRowInt_; indRowInt_ = 0; }
+  if (numRowInt_ > 0)
+    indRowInt_ = new int [numRowInt_];     // Destructor will free memory
+
+#if CGL_DEBUG
+  std::cout << "The num of rows = "  << numRows_        << std::endl;
+  std::cout << "Summary of Row Type" << std::endl;
+  std::cout << "numUNDEFINED     = " << numUNDEFINED   << std::endl;
+  std::cout << "numVARUB         = " << numVARUB       << std::endl;
+  std::cout << "numVARLB         = " << numVARLB       << std::endl;
+  std::cout << "numVAREQ         = " << numVAREQ       << std::endl;
+  std::cout << "numMIX           = " << numMIX         << std::endl;
+  std::cout << "numCONT          = " << numCONT        << std::endl;
+  std::cout << "numINT           = " << numINT         << std::endl;
+  std::cout << "numOTHER         = " << numOTHER       << std::endl;
+#endif
+
+  //---------------------------------------------------------------------------
+  // Setup  vubs_ and vlbs_
+  if (vubs_ != 0) { delete [] vubs_; vubs_ = 0; }
+  vubs_ = new CglMixIntRoundVUB [numCols_]; // Destructor will free
+  if (vlbs_ != 0) { delete [] vlbs_; vlbs_ = 0; }
+  vlbs_ = new CglMixIntRoundVLB [numCols_]; // Destructor will free
+
+  // Initialization. Altough this has been done in constructor, it is needed
+  // for the case where the mixIntRoundPreprocess is called more than once
+  for (int iCol = 0; iCol < numCols_; ++iCol) {
+    vubs_[iCol].setVar(UNDEFINED_);
+    vlbs_[iCol].setVar(UNDEFINED_);
+  }
+  
+  int countM = 0;
+  int countC = 0;
+  int countI = 0;
+  for ( iRow = 0; iRow < numRows_; ++iRow) {
+
+    RowType rowType = rowTypes_[iRow];
+
+    // fill the vector indRows_ with the indices of all rows
+    indRows_[iRow] = iRow;
+
+    // fill the vector indRowMix_ with the indices of the rows of type ROW_MIX
+    if (rowType == ROW_MIX) {
+      indRowMix_[countM] = iRow;
+      countM++;
+    }
+    // fill the vector indRowCont_ with the indices of rows of type ROW_CONT
+    else if (rowType == ROW_CONT) {
+      indRowCont_[countC] = iRow;
+      countC++;
+    }
+    // fill the vector indRowInt_ with the indices of the rows of type ROW_INT
+    else if (rowType == ROW_INT) {
+      indRowInt_[countI] = iRow;
+      countI++;
+    }
+    // create vectors with variable lower and upper bounds
+    else if ( (rowType == ROW_VARUB) || 
+	      (rowType == ROW_VARLB) || 
+	      (rowType == ROW_VAREQ) )  { 
+      
+      int startPos = rowStarts[iRow];
+      int stopPos  = startPos + rowLengths[iRow];
+      int    xInd = 0,  yInd = 0;   // x is continuous, y is integer
+      double xCoef = 0.0, yCoef = 0.0;
+
+      for (int i = startPos; i < stopPos; ++i) {
+	if ( fabs(coefByRow[i]) > EPSILON_ ) {
+	  if( si.isInteger(colInds[i]) ) {
+	    yInd  = colInds[i];
+	    yCoef = coefByRow[i];
+	  }
+	  else {
+	    xInd  = colInds[i];
+	    xCoef = coefByRow[i];
+	  }
+	}
+      }
+
+      switch (rowType) {
+      case ROW_VARUB:       // Inequality: x <= ? * y
+	vubs_[xInd].setVar(yInd);
+	vubs_[xInd].setVal(-yCoef / xCoef);
+	break;
+      case ROW_VARLB:       // Inequality: x >= ? * y
+	vlbs_[xInd].setVar(yInd);
+	vlbs_[xInd].setVal(-yCoef / xCoef);
+	break;
+      case ROW_VAREQ:       // Inequality: x >= AND <= ? * y
+	vubs_[xInd].setVar(yInd);
+	vubs_[xInd].setVal(-yCoef / xCoef);
+	vlbs_[xInd].setVar(yInd);
+	vlbs_[xInd].setVal(-yCoef / xCoef);
+	break;
+      default:
+        // I am getting compiler bug which gets here - I am disabling - JJF
+	//throw CoinError("Unknown row type: impossible", 
+        //	"MixIntRoundPreprocess",
+        //	"CglMixedIntegerRounding");
+        break;
+      }
+    }
+  }
+
+  // allocate memory for vector of indices of rows of type ROW_CONT
+  // that have at least one variable with variable upper or lower bound
+  if (indRowContVB_ != 0) { delete [] indRowContVB_; indRowContVB_ = 0; }
+  if (numRowCont_ > 0)
+    indRowContVB_ = new int [numRowCont_];     // Destructor will free memory
+  // create vector with rows of type ROW_CONT that have at least
+  // one variable with variable upper or lower bound
+  countC = 0;
+  for (int i = 0; i < numRowCont_; ++i) {
+    int indRow = indRowCont_[i];
+    int jStart = rowStarts[indRow];
+    int jStop = jStart + rowLengths[indRow];
+    for (int j = jStart; j < jStop; ++j) {
+      int indCol = colInds[j];
+      CglMixIntRoundVLB VLB = vlbs_[indCol];
+      CglMixIntRoundVUB VUB = vubs_[indCol];
+      if (( VLB.getVar() != UNDEFINED_ ) || ( VUB.getVar() != UNDEFINED_ ) ){
+	indRowContVB_[countC] = indRow;
+	countC++;
+	break;
+      }
+    }
+  }
+  numRowContVB_ = countC;
+
+}
+
+//-------------------------------------------------------------------
+// Determine the type of a given row 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding::RowType
+CglMixedIntegerRounding::determineRowType(const OsiSolverInterface& si,
+				  const int rowLen, const int* ind, 
+				  const double* coef, const char sense, 
+				  const double rhs) const
+{
+  if (rowLen == 0) 
+    return ROW_UNDEFINED;
+
+  if (sense == 'N' || rhs == si.getInfinity() || rhs == -si.getInfinity())
+    return ROW_OTHER;
+
+  RowType rowType = ROW_UNDEFINED;
+
+  int  numPosInt = 0;      // num of positive integer variables
+  int  numNegInt = 0;      // num of negative integer variables
+  int  numInt    = 0;      // num of integer variables
+  int  numPosCon = 0;      // num of positive continuous variables
+  int  numNegCon = 0;      // num of negative continuous variables
+  int  numCon    = 0;      // num of continuous variables
+
+
+  // Summarize the variable types of the given row.
+  for ( int i = 0; i < rowLen; ++i ) {
+    if ( coef[i] < -EPSILON_ ) {
+      if( si.isInteger(ind[i]) )
+	++numNegInt;
+      else
+	++numNegCon;
+    }
+    else if ( coef[i] > EPSILON_ ) {
+      if( si.isInteger(ind[i]) )
+	++numPosInt;
+      else
+	++numPosCon;
+    }
+  }
+  numInt = numNegInt + numPosInt;
+  numCon = numNegCon + numPosCon;
+
+#if CGL_DEBUG
+  std::cout << "numNegInt = " << numNegInt << std::endl;
+  std::cout << "numPosInt = " << numPosInt << std::endl;
+  std::cout << "numInt = " << numInt << std::endl;
+  std::cout << "numNegCon = " << numNegCon << std::endl;
+  std::cout << "numPosCon = " << numPosCon << std::endl;
+  std::cout << "numCon = " << numCon << std::endl;
+  std::cout << "rowLen = " << rowLen << std::endl;
+#endif
+
+
+  //-------------------------------------------------------------------------
+  // Classify row type based on the types of variables.
+    
+  if ((numInt > 0) && (numCon > 0)) {
+    if ((numInt == 1) && (numCon == 1) && (fabs(rhs) <= EPSILON_)) {
+      // It's a variable bound constraint
+      switch (sense) {
+      case 'L':
+	rowType = numPosCon == 1 ? ROW_VARUB : ROW_VARLB;
+	break;
+      case 'G':
+	rowType = numPosCon == 1 ? ROW_VARLB : ROW_VARUB;
+	break;
+      case 'E':
+        rowType = ROW_VAREQ;
+	break;
+      default:
+	break;
+      }
+    }
+    else {
+      // It's a constraint with continuous and integer variables;
+      // The total number of variables is at least 2
+      rowType = ROW_MIX;
+    }
+  }
+  else if (numInt == 0) {
+    // It's a constraint with only continuous variables
+    rowType = ROW_CONT;
+  }
+  else if ((numCon == 0) && ((sense == 'L') || (sense == 'G'))) {
+    // It's a <= or >= constraint with only integer variables 
+    rowType = ROW_INT;
+  }
+  else
+    // It's a constraint that does not fit the above categories
+    rowType = ROW_OTHER;
+
+
+  return rowType;
+}
+
+//-------------------------------------------------------------------
+// Generate MIR cuts
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding::generateMirCuts( 
+			    const OsiSolverInterface& si,
+			    const double* xlp,
+			    const double* colUpperBound,
+			    const double* colLowerBound,
+			    const CoinPackedMatrix& matrixByRow,
+			    const double* LHS,
+			    const double* /*coefByRow*/,
+			    const int* /*colInds*/,
+			    const int* /*rowStarts*/,
+			    const int* /*rowLengths*/,
+			    //const CoinPackedMatrix& matrixByCol,
+			    const double* coefByCol,
+			    const int* rowInds,
+			    const int* colStarts,
+			    const int* colLengths,
+			    OsiCuts& cs ) const
+{
+
+#if CGL_DEBUG
+  // Open debug data file; incorporate solver name so we get separate files
+  // when running unit test.
+  std::string dbgFname ;
+  si.getStrParam(OsiSolverName,dbgFname) ;
+  dbgFname = "mir_"+dbgFname+"_stats.dat" ;
+  std::ofstream fout(dbgFname.c_str()) ;
+#endif
+
+  // Define upper limit for the loop where the cMIRs are constructed
+  int upperLimit;
+  if (MULTIPLY_)
+    upperLimit = 2;
+  else
+    upperLimit = 1;
+  
+  // create a vector with the columns that were used in the aggregation
+  int* listColsSelected = new int[MAXAGGR_];
+  // create a vector with the rows that were aggregated
+  int* listRowsAggregated = new int[MAXAGGR_];
+  // create a vector with the LP solutions of the slack variables
+  double* xlpExtra = new double[MAXAGGR_];
+
+  // loop until maximum number of aggregated rows is reached or a 
+  // violated cut is found
+  int numRowMixAndRowContVB = numRowMix_ + numRowContVB_;
+  int numRowMixAndRowContVBAndRowInt = numRowMixAndRowContVB + numRowInt_;
+  for (int iRow = 0; iRow < numRowMixAndRowContVBAndRowInt; ++iRow) {
+
+    int rowSelected;  // row selected to be aggregated next
+    int colSelected;  // column selected for pivot in aggregation
+    CoinPackedVector rowAggregated;
+    double rhsAggregated;
+    // create a set with the indices of rows selected
+    std::set<int> setRowsAggregated;
+
+    // loop until the maximum number of aggregated rows is reached
+    for (int iAggregate = 0; iAggregate < MAXAGGR_; ++iAggregate) {
+
+      if (iAggregate == 0) {
+
+	// select row
+	if (iRow < numRowMix_) {
+	  rowSelected = indRowMix_[iRow];
+	}
+	else if (iRow < numRowMixAndRowContVB) {
+	  rowSelected = indRowContVB_[iRow - numRowMix_];
+	}
+	else {
+	  rowSelected = indRowInt_[iRow - numRowMixAndRowContVB];
+	}
+
+	copyRowSelected(iAggregate, rowSelected, setRowsAggregated,
+			listRowsAggregated, xlpExtra, sense_[rowSelected], 
+			RHS_[rowSelected], LHS[rowSelected], 
+			matrixByRow, rowAggregated, rhsAggregated);
+
+      } 
+      else {
+
+	// search for a row to aggregate
+	bool foundRowToAggregate = selectRowToAggregate(
+				        si, rowAggregated,
+					colUpperBound, colLowerBound, 
+					setRowsAggregated, xlp, 
+					coefByCol, rowInds, colStarts,
+					colLengths, 
+					rowSelected, colSelected);
+
+	// if finds row to aggregate, compute aggregated row
+	if (foundRowToAggregate) {
+
+	  CoinPackedVector rowToAggregate;
+	  double rhsToAggregate;
+
+	  listColsSelected[iAggregate] = colSelected;
+
+	  copyRowSelected(iAggregate, rowSelected, setRowsAggregated,
+			  listRowsAggregated, xlpExtra, sense_[rowSelected], 
+			  RHS_[rowSelected], LHS[rowSelected], 
+			  matrixByRow, rowToAggregate, rhsToAggregate);
+
+	  // call aggregate row heuristic
+	  aggregateRow(colSelected, rowToAggregate, rhsToAggregate, 
+		       rowAggregated, rhsAggregated);
+
+	}
+	else
+	  break;
+      }
+
+
+      // construct cMIR with current rowAggregated
+      // and, if upperLimit=2 construct also a cMIR with 
+      // the current rowAggregated multiplied by -1
+      for (int i = 0; i < upperLimit; ++i) {
+      
+	// create vector for mixed knapsack constraint
+	CoinPackedVector rowToUse = rowAggregated;
+	double rhsMixedKnapsack = rhsAggregated;
+	if (i == 1) {
+	  rowToUse *= (-1.0);
+	  rhsMixedKnapsack *= (-1.0);
+	}	  
+	CoinPackedVector mixedKnapsack;
+	double sStar = 0.0;
+
+	// create vector for the continuous variables in s
+	CoinPackedVector contVariablesInS;
+
+	// call bound substitution heuristic
+	bool foundMixedKnapsack = boundSubstitution(
+					si, rowToUse, 
+					xlp, xlpExtra, 
+					colUpperBound, colLowerBound,
+					mixedKnapsack, rhsMixedKnapsack, 
+					sStar, contVariablesInS);
+        // may want some limit?
+        if (mixedKnapsack.getNumElements()>25000) {
+#if CGL_DEBUG	  
+	  std::cout << "mixed knapsack has " 
+                    <<mixedKnapsack.getNumElements()<<" elements - rhs is "
+                    <<rhsMixedKnapsack
+                    << std::endl;
+#endif
+	  continue;
+	}
+          
+	// if it did not find a mixed knapsack it is because there is at
+	// least one integer variable with lower bound different than zero
+	// or there are no integer or continuous variables.
+	// In this case, we continue without trying to generate a c-MIR
+	if (!foundMixedKnapsack) {
+#if CGL_DEBUG	  
+	  std::cout << "couldn't create mixed knapsack" << std::endl;
+#endif
+	  continue;
+	}
+
+	OsiRowCut cMirCut;
+
+	// Find a c-MIR cut with the current mixed knapsack constraint
+	bool hasCut = cMirSeparation(si, matrixByRow, rowToUse,
+				     listRowsAggregated, sense_, RHS_,
+				     //coefByRow, colInds, rowStarts, rowLengths,
+				     xlp, sStar, colUpperBound, colLowerBound, 
+				     mixedKnapsack,
+				     rhsMixedKnapsack, contVariablesInS,
+				     cMirCut);
+
+#if CGL_DEBUG
+	// PRINT STATISTICS
+	printStats(fout, hasCut, si, rowAggregated, rhsAggregated, xlp,
+		   xlpExtra, listRowsAggregated, listColsSelected, 
+		   iAggregate+1, colUpperBound, colLowerBound );
+#endif
+
+	// if a cut was found, insert it into cs
+	if (hasCut)  {
+#if CGL_DEBUG
+	  std::cout << "MIR cut generated " << std::endl;
+#endif
+	  cs.insert(cMirCut);
+	}
+
+      }
+	
+    }
+
+  }
+
+  // free memory
+  delete [] listColsSelected; listColsSelected = 0;
+  delete [] listRowsAggregated; listRowsAggregated = 0;
+  delete [] xlpExtra; xlpExtra = 0;
+  
+#if CGL_DEBUG
+  // CLOSE FILE
+  fout.close();
+#endif
+
+  return;
+
+}
+
+//-------------------------------------------------------------------
+// Copy row selected to CoinPackedVector
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding::copyRowSelected(
+			    const int iAggregate,
+			    const int rowSelected,
+			    std::set<int>& setRowsAggregated,
+			    int* listRowsAggregated,
+			    double* xlpExtra,
+			    const char sen,
+			    const double rhs,
+			    const double lhs,
+			    const CoinPackedMatrix& matrixByRow,
+			    CoinPackedVector& rowToAggregate,
+			    double& rhsToAggregate) const
+{
+
+  // copy the row selected to a vector of type CoinPackedVector
+  const CoinShallowPackedVector reqdBySunCC = matrixByRow.getVector(rowSelected);
+  rowToAggregate = reqdBySunCC ;
+  rhsToAggregate = rhs;
+
+  // update list of indices of rows selected
+  setRowsAggregated.insert(rowSelected);
+  listRowsAggregated[iAggregate] = rowSelected;
+
+  // Add a slack variable if needed and compute its current value
+  if (sen == 'L') {
+    rowToAggregate.insert(numCols_ + iAggregate, 1);
+    xlpExtra[iAggregate] = rhs - lhs;
+  }
+  else if (sen == 'G') {
+    rowToAggregate.insert(numCols_ + iAggregate, -1);
+    xlpExtra[iAggregate] = lhs - rhs;
+  }
+
+}
+
+//-------------------------------------------------------------------
+// Construct the set P* and select a row to aggregate
+//-------------------------------------------------------------------
+bool
+CglMixedIntegerRounding::selectRowToAggregate( 
+			    const OsiSolverInterface& si,
+			    const CoinPackedVector& rowAggregated,
+			    const double* colUpperBound,
+			    const double* colLowerBound,
+			    const std::set<int>& setRowsAggregated,
+			    const double* xlp, const double* coefByCol,
+			    const int* rowInds, const int* colStarts,
+			    const int* colLengths,
+			    int& rowSelected,
+			    int& colSelected ) const
+{
+
+  bool foundRowToAggregate = false;
+
+  double deltaMax = 0.0;  // maximum delta
+  const int numColsAggregated = rowAggregated.getNumElements();
+  const int *rowAggregatedIndices = rowAggregated.getIndices();
+  const double *rowAggregatedElements = rowAggregated.getElements();  
+
+  for (int j = 0; j < numColsAggregated; ++j) {
+
+    // store the index and coefficient of column j
+    int indCol = rowAggregatedIndices[j];
+    if (indCol >= numCols_) continue;
+    double coefCol = rowAggregatedElements[j];
+
+    // Consider only continuous variables
+    if ( (!si.isContinuous(indCol)) || (fabs(coefCol) < EPSILON_)) continue;
+
+    // Compute current lower bound
+    CglMixIntRoundVLB VLB = vlbs_[indCol];
+    double LB = ( VLB.getVar() != UNDEFINED_ ) ? 
+                      VLB.getVal() * xlp[VLB.getVar()] : colLowerBound[indCol];
+    
+    // Compute current upper bound
+    CglMixIntRoundVUB VUB = vubs_[indCol];
+    double UB = ( VUB.getVar() != UNDEFINED_ ) ? 
+                      VUB.getVal() * xlp[VUB.getVar()] : colUpperBound[indCol];
+
+    // Compute distances from current solution to upper and lower bounds
+    double delta = CoinMin(xlp[indCol] - LB, UB - xlp[indCol]);
+
+    // In case this variable is acceptable look for possible rows
+    if (delta > deltaMax) {
+
+      int iStart = colStarts[indCol];
+      int iStop  = iStart + colLengths[indCol];
+      //      int count = 0;
+
+      //      std::vector<int> rowPossible;
+
+      // find a row to use in aggregation
+      for (int i = iStart; i < iStop; ++i) {
+	int rowInd = rowInds[i];
+	if (setRowsAggregated.find(rowInd) == setRowsAggregated.end()) {
+	  // if the row was not already selected, select it
+	  RowType rType = rowTypes_[rowInd];
+	  if ( ((rType == ROW_MIX) || (rType == ROW_CONT)) 
+	       && (fabs(coefByCol[i]) > EPSILON_) ) {
+	    //	    rowPossible.push_back(rowInd);
+	    rowSelected = rowInd;
+	    deltaMax = delta;
+	    colSelected = indCol;
+	    foundRowToAggregate = true;
+	    //count++;
+	    break;
+	  }
+	}
+      }
+
+      //      if (count > 0)
+      //	rowSelected = rowPossible[rand() % count];
+      //      std::cout << count << std::endl;
+    }
+	
+  }
+
+  return foundRowToAggregate;
+
+}
+      
+//-------------------------------------------------------------------
+// Aggregate the selected row with the current aggregated row
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding::aggregateRow( 
+			    const int colSelected,
+			    CoinPackedVector& rowToAggregate, double rhs,
+			    CoinPackedVector& rowAggregated, 
+			    double& rhsAggregated ) const
+{
+
+  // quantity to multiply by the coefficients of the row to aggregate
+  double multiCoef = rowAggregated[colSelected] / rowToAggregate[colSelected];
+
+  rowToAggregate *= multiCoef; 
+  rhs *= multiCoef;
+
+  rowAggregated = rowAggregated - rowToAggregate;
+  rhsAggregated -= rhs;
+
+}
+
+//-------------------------------------------------------------------
+// Choose the bound substitution based on the criteria defined by the user
+//-------------------------------------------------------------------
+inline bool
+CglMixedIntegerRounding::isLowerSubst(const double inf, 
+				      const double aj,
+				      const double xlp, 
+				      const double LB, 
+				      const double UB) const
+{
+  if (CRITERION_ == 1) {
+    // criterion 1 (the same as criterion (a) in the paper)
+    return xlp - LB < UB - xlp;
+  }
+  else {
+    if (UB == inf || xlp == LB) 
+      return true;
+    if (LB == -inf || xlp == UB)
+      return false;
+    if (CRITERION_ == 2) 
+      // criterion 2 (the same as criterion (b) in the paper)
+      return aj < 0;
+    else
+      // criterion 3 (the same as criterion (c) in the paper)
+      return aj > 0;
+  }
+}
+
+
+
+//-------------------------------------------------------------------
+// Bound substitution heuristic
+//-------------------------------------------------------------------
+bool
+CglMixedIntegerRounding::boundSubstitution( 
+			    const OsiSolverInterface& si,
+			    const CoinPackedVector& rowAggregated,
+			    const double* xlp,
+			    const double* xlpExtra,
+			    const double* colUpperBound,
+			    const double* colLowerBound,
+			    CoinPackedVector& mixedKnapsack,
+			    double& rhsMixedKnapsack, double& sStar,
+			    CoinPackedVector& contVariablesInS ) const
+{
+
+  bool generated = false;
+  const int numColsAggregated = rowAggregated.getNumElements();
+  const int *rowAggregatedIndices = rowAggregated.getIndices();
+  const double *rowAggregatedElements = rowAggregated.getElements();  
+
+  // go through all the variables and if it is continuous and delta is 
+  // negative, store variable in the vector contVariablesInS.
+  // If it is integer, store variable in the vector mixedKnapsack
+  int numCont = 0;
+  int j;
+  for ( j = 0; j < numColsAggregated; ++j) {
+
+    // get index and coefficient of column j in the aggregated row
+    const int indCol = rowAggregatedIndices[j];
+    const double coefCol = rowAggregatedElements[j];
+
+    // if the lower bound is equal to the upper bound, remove variable
+    if ( (indCol < numCols_) &&
+	 (colLowerBound[indCol] == colUpperBound[indCol]) ) {
+      rhsMixedKnapsack -= coefCol * colLowerBound[indCol];
+      continue;
+    }
+
+    if (fabs(coefCol) < EPSILON_) continue;
+    // set the coefficients of the integer variables
+    if ( (indCol < numCols_)  && (!si.isContinuous(indCol)) ) {
+      // Copy the integer variable to the vector mixedKnapsack
+      if (mixedKnapsack.isExistingIndex(indCol)) {
+	const int index = mixedKnapsack.findIndex(indCol);
+	mixedKnapsack.setElement(index, mixedKnapsack[indCol] + coefCol);
+      }
+      else
+	mixedKnapsack.insert(indCol, coefCol);
+      continue;
+    }
+
+    // Select the continuous variables and copy the ones in s to 
+    // the vector contVariablesInS
+    if (indCol < numCols_) {  // variable is model variable
+
+      // Compute lower bound for variable indCol
+      const CglMixIntRoundVLB VLB = vlbs_[indCol];
+      const double LB = ( VLB.getVar() != UNDEFINED_ ) ? 
+	        VLB.getVal() * xlp[VLB.getVar()] : colLowerBound[indCol];
+    
+      // Compute upper bound for variable indCol
+      const CglMixIntRoundVUB VUB = vubs_[indCol];
+      const double UB = ( VUB.getVar() != UNDEFINED_ ) ? 
+	        VUB.getVal() * xlp[VUB.getVar()] : colUpperBound[indCol];
+
+      // if both bounds are infinite, then we cannot form a mixed knapsack
+      if ( (LB == -1.0 * si.getInfinity()) &&
+	   (UB == si.getInfinity()) ) {
+#if CGL_DEBUG
+	std::cout << "continuous var with infinite bounds. " <<
+                     "Cannot form mixed Knapsack = " << std::endl;
+#endif
+	return generated;
+      }
+
+      // Select the bound substitution
+      if (isLowerSubst(si.getInfinity(), rowAggregatedElements[j],
+			 xlp[indCol], LB, UB)) {
+	if (VLB.getVar() != UNDEFINED_ ) {
+	  const int indVLB = VLB.getVar();
+	  if (mixedKnapsack.isExistingIndex(indVLB)) {
+	    const int index = mixedKnapsack.findIndex(indVLB);
+	    mixedKnapsack.setElement(index, mixedKnapsack[indVLB] + 
+				     coefCol * VLB.getVal());
+	  }
+	  else
+	    mixedKnapsack.insert(indVLB, coefCol * VLB.getVal());
+	}
+	else {
+	  rhsMixedKnapsack -= coefCol * LB;
+	}
+	// Update sStar
+	if (coefCol < -EPSILON_) {
+	  contVariablesInS.insert(indCol, coefCol);
+	  sStar -= coefCol * (xlp[indCol] - LB);
+	  numCont++;
+	}
+      }
+      else {
+	if (VUB.getVar() != UNDEFINED_ ) {
+	  const int indVUB = VUB.getVar();
+	  if (mixedKnapsack.isExistingIndex(indVUB)) {
+	    const int index = mixedKnapsack.findIndex(indVUB);
+	    mixedKnapsack.setElement(index, mixedKnapsack[indVUB] + 
+				     coefCol * VUB.getVal());
+	  }
+	  else
+	    mixedKnapsack.insert(indVUB, coefCol * VUB.getVal());
+	}
+	else {
+	  rhsMixedKnapsack -= coefCol * UB;
+	}
+	// Update sStar
+	if (coefCol > EPSILON_) {
+	  contVariablesInS.insert(indCol, - coefCol);
+	  sStar += coefCol * (UB - xlp[indCol]);
+	  numCont++;
+	}
+      }
+    }
+    else {  // variable is slack variable
+      // in this case the LB = 0 and the UB = infinity
+      // Update sStar
+      const double tLB = xlpExtra[indCol - numCols_];
+      if (coefCol < -EPSILON_) {
+	contVariablesInS.insert(indCol, coefCol);
+	sStar -= coefCol * tLB;
+	numCont++;
+      }
+    }
+
+  }
+
+  // if there are no continuous variables to form s, then we stop
+#if CGL_DEBUG
+  std::cout << "# of continuous var in mixedKnapsack = " << numCont <<
+    std::endl;
+#endif
+  if (numCont == 0) return generated;
+
+  // check that the integer variables have lower bound equal to zero
+  const int numInt = mixedKnapsack.getNumElements();
+  // if there are not integer variables in mixedKnapsack, then we stop
+  // CAUTION: all the coefficients could be zero
+#if CGL_DEBUG
+  std::cout << "# of integer var in mixedKnapsack = " << numInt <<
+    std::endl;
+#endif
+  if (numInt == 0) return generated;
+  const int *knapsackIndices = mixedKnapsack.getIndices();
+  const double *knapsackElements = mixedKnapsack.getElements();  
+
+  for ( j = 0; j < numInt; ++j) {
+    // if the coefficient is zero, disregard
+    if (fabs(knapsackElements[j]) < EPSILON_) continue;
+    // if the lower bound is not zero, then we stop
+    if (fabs(colLowerBound[knapsackIndices[j]]) > EPSILON_) return generated;
+  }
+  // if the lower bounds of all integer variables are zero, proceed
+  generated = true;
+  return generated;
+
+}
+
+//-------------------------------------------------------------------
+// c-MIR separation heuristic
+//-------------------------------------------------------------------
+bool
+CglMixedIntegerRounding::cMirSeparation( 
+			    const OsiSolverInterface& si,
+			    const CoinPackedMatrix& matrixByRow,
+			    const CoinPackedVector& rowAggregated,
+			    const int* listRowsAggregated,
+			    const char* sense, const double* RHS,
+			    //const double* coefByRow,
+			    //const int* colInds, const int* rowStarts,
+			    //const int* rowLengths,
+			    const double* xlp, const double sStar,
+			    const double* colUpperBound,
+			    const double* colLowerBound,
+			    const CoinPackedVector& mixedKnapsack,
+			    const double& rhsMixedKnapsack,
+			    const CoinPackedVector& contVariablesInS,
+			    OsiRowCut& cMirCut) const
+{
+
+  bool generated = false;
+  double numeratorBeta = rhsMixedKnapsack;
+  CoinPackedVector cMIR = mixedKnapsack;
+  double rhscMIR;
+  double maxViolation = 0.0;
+  double bestDelta = 0.0;
+  CoinPackedVector bestCut;
+  double rhsBestCut = 0.0;
+  double sCoefBestCut = 0.0;
+  const int numInt = mixedKnapsack.getNumElements();  
+  const int *knapsackIndices = mixedKnapsack.getIndices();
+  const double *knapsackElements = mixedKnapsack.getElements();  
+  const int *contVarInSIndices = contVariablesInS.getIndices();
+  const double *contVarInSElements = contVariablesInS.getElements();
+
+  // Construct set C, T will be the rest.
+  // Also, for T we construct a CoinPackedVector named complT which
+  // contains the vars in T that are strictly between their bounds
+  std::set<int> setC;
+  CoinPackedVector complT;
+  int j;
+  for ( j = 0; j < numInt; ++j) {
+    const int indCol = knapsackIndices[j];
+    // if the upper bound is infinity, then indCol is in T and cannot
+    // be in complT
+    if (colUpperBound[indCol] != si.getInfinity()) {
+      if (xlp[indCol] >= colUpperBound[indCol] / 2.0) {
+	setC.insert(j);
+	numeratorBeta -= knapsackElements[j] * colUpperBound[indCol];
+      } else {
+	if ( (xlp[indCol] <= EPSILON_) || 
+	     (xlp[indCol] >= colUpperBound[indCol] - EPSILON_))
+	  continue;
+	complT.insert(j, fabs(xlp[indCol] - colUpperBound[indCol]/2));
+      }
+    }
+  }
+
+  // Sort the indices in complT by nondecreasing values 
+  // (which are  $|y^*_j-u_j/2|$)
+  if (complT.getNumElements() > 0) {
+    complT.sortIncrElement();
+  }
+
+  // Construct c-MIR inequalities and take the one with the largest violation
+  for ( j = 0; j < numInt; ++j) {
+    int indCol = knapsackIndices[j];
+    if ( (xlp[indCol] <= EPSILON_) || 
+	 (xlp[indCol] >= colUpperBound[indCol] - EPSILON_))
+      continue;
+    double delta = knapsackElements[j];
+    // delta has to be positive
+    if (delta <= EPSILON_) continue;
+
+    double violation = 0.0;
+    double sCoef = 0.0;
+
+    // form a cMIR inequality
+    cMirInequality(numInt, delta, numeratorBeta, knapsackIndices, 
+		   knapsackElements, xlp, sStar, colUpperBound, setC, cMIR,
+		   rhscMIR, sCoef, violation);
+
+    // store cut if it is the best found so far
+    if (violation > maxViolation + EPSILON_) {
+      bestCut = cMIR;
+      rhsBestCut = rhscMIR;
+      sCoefBestCut = sCoef;
+      maxViolation = violation;
+      bestDelta = delta;
+    }
+  }
+
+  // if no violated inequality has been found, exit now
+  if (maxViolation == 0.0) return generated;
+
+  // improve the best violated inequality.
+  // try to divide delta by 2, 4 or 8 and see if increases the violation
+  double deltaBase = bestDelta;
+  for (int multFactor = 2; multFactor <= 8; multFactor *= 2) {
+    double delta = deltaBase / multFactor;
+    double violation = 0.0;
+    double sCoef = 0.0;
+
+    // form a cMIR inequality
+    cMirInequality(numInt, delta, numeratorBeta, knapsackIndices, 
+		   knapsackElements, xlp, sStar, colUpperBound, setC, cMIR,
+		   rhscMIR, sCoef, violation);
+
+    // store cut if it is the best found so far
+    if (violation > maxViolation + EPSILON_) {
+      bestCut = cMIR;
+      rhsBestCut = rhscMIR;
+      sCoefBestCut = sCoef;
+      maxViolation = violation;
+      bestDelta = delta;
+    }
+  }
+
+  // improve cMIR for the best delta
+  // complT contains indices into mixedKnapsack for the variables
+  // which may be complemented and they are already appropriately
+  // sorted.
+  const int complTSize = complT.getNumElements();
+  if (complTSize > 0) {
+    const int *complTIndices = complT.getIndices();
+    for (int j = 0; j < complTSize; ++j) {
+      // move variable in set complT from set T to set C
+      int jIndex = complTIndices[j];
+      int indCol = knapsackIndices[jIndex];
+      // do nothing if upper bound is infinity
+      if (colUpperBound[indCol] >= si.getInfinity()) continue;
+      setC.insert(jIndex);
+      double violation = 0.0;
+      double sCoef = 0.0;
+      double localNumeratorBeta = numeratorBeta -
+	mixedKnapsack[indCol] * colUpperBound[indCol];
+
+      // form a cMIR inequality
+      cMirInequality(numInt, bestDelta, localNumeratorBeta, knapsackIndices, 
+		     knapsackElements, xlp, sStar, colUpperBound, setC, cMIR,
+		     rhscMIR, sCoef, violation);
+
+      // store cut if it is the best found so far; otherwise, move the variable
+      // that was added to set C back to set T
+      if (violation > maxViolation + EPSILON_) {
+	bestCut = cMIR;
+	rhsBestCut = rhscMIR;
+	sCoefBestCut = sCoef;
+	maxViolation = violation;
+	numeratorBeta = localNumeratorBeta;
+      }
+      else
+	setC.erase(jIndex);
+    }
+  }
+
+  // write the best cut found with the model variables
+  int numCont = contVariablesInS.getNumElements();
+  for ( j = 0; j < numCont; ++j) {
+    int indCol = contVarInSIndices[j];
+    double coefCol = contVarInSElements[j];
+      
+    if (indCol < numCols_) {  // variable is model variable
+
+      // Compute lower bound for variable indCol
+      CglMixIntRoundVLB VLB = vlbs_[indCol];
+      double LB = ( VLB.getVar() != UNDEFINED_ ) ? 
+	VLB.getVal() * xlp[VLB.getVar()] : colLowerBound[indCol];
+    
+      // Compute upper bound for variable indCol
+      CglMixIntRoundVUB VUB = vubs_[indCol];
+      double UB = ( VUB.getVar() != UNDEFINED_ ) ? 
+	VUB.getVal() * xlp[VUB.getVar()] : colUpperBound[indCol];
+
+      // Select the bound substitution
+      if (isLowerSubst(si.getInfinity(), rowAggregated[indCol],
+			 xlp[indCol], LB, UB)) { 
+	if (VLB.getVar() != UNDEFINED_ ) {
+	  int indVLB = VLB.getVar();
+	  if (bestCut.isExistingIndex(indVLB)){
+	    int index = bestCut.findIndex(indVLB);
+	    bestCut.setElement(index, bestCut[indVLB] - 
+			       sCoefBestCut * coefCol * VLB.getVal());
+	  }
+	  else
+	    bestCut.insert(indVLB, - sCoefBestCut * coefCol * VLB.getVal());
+	  bestCut.insert(indCol, sCoefBestCut * coefCol);
+	}
+	else {
+	  rhsBestCut += sCoefBestCut * coefCol * colLowerBound[indCol];
+	  bestCut.insert(indCol, sCoefBestCut * coefCol);
+	}
+      }
+      else {
+	if (VUB.getVar() != UNDEFINED_ ) {
+	  int indVUB = VUB.getVar();
+	  if (bestCut.isExistingIndex(indVUB)){
+	    int index = bestCut.findIndex(indVUB);
+	    bestCut.setElement(index, bestCut[indVUB] + 
+			       sCoefBestCut * coefCol * VUB.getVal());
+	  }
+	  else
+	    bestCut.insert(indVUB, sCoefBestCut * coefCol * VUB.getVal());
+	  bestCut.insert(indCol, - sCoefBestCut * coefCol);
+	}
+	else {
+	  rhsBestCut -= sCoefBestCut * coefCol * colUpperBound[indCol];
+	  bestCut.insert(indCol, - sCoefBestCut * coefCol);
+	}
+      }
+    }
+    else {  // variable is slack variable
+      // in this case the LB = 0 and the UB = infinity
+      // copy the row selected to a vector of type CoinPackedVector
+      const int iRow = listRowsAggregated[indCol - numCols_];
+      const CoinShallowPackedVector reqdBySunCC = matrixByRow.getVector(iRow);
+      CoinPackedVector row = reqdBySunCC ;
+      double rhs     = RHS[iRow];
+
+      if (sense[iRow] == 'L') {
+	// if it is a <= inequality, the coefficient of the slack is 1
+	row *= (- sCoefBestCut * coefCol);
+	rhs *= (- sCoefBestCut * coefCol);
+      }
+      else {
+        assert (sense[iRow]=='G');
+	// if it is a <= inequality, the coefficient of the slack is -1
+	row *= (sCoefBestCut * coefCol);
+	rhs *= (sCoefBestCut * coefCol);
+      }
+
+      rhsBestCut += rhs;
+      bestCut = bestCut + row;
+    }
+  }
+
+  // Check the violation of the cut after it is written with the original
+  // variables.
+  int cutLen = bestCut.getNumElements();
+  int* cutInd = bestCut.getIndices();
+  double* cutCoef = bestCut.getElements();
+  double cutRHS = rhsBestCut;
+  double violation = 0.0;
+  double normCut = 0.0;
+  // Also weaken by small coefficients
+  int n=0;
+  for ( j = 0; j < cutLen; ++j) {
+    double value = cutCoef[j];
+    int column = cutInd[j];
+    if (fabs(value)>1.0e-12) {
+      violation += cutCoef[j] * xlp[column];
+      normCut += cutCoef[j] * cutCoef[j];
+      cutCoef[n]=value;
+      cutInd[n++]=column;
+    } else if (value) {
+      // Weaken
+      if (value>0.0) {
+        // Allow for at lower bound
+        cutRHS -= value*colLowerBound[column];
+      } else {
+        // Allow for at upper bound
+        cutRHS -= value*colUpperBound[column];
+      }
+    }
+  }
+  cutLen=n;
+  violation -= cutRHS;
+  violation /= sqrt(normCut);
+
+  if ( violation > TOLERANCE_ ) {
+    cMirCut.setRow(cutLen, cutInd, cutCoef);
+    cMirCut.setLb(-1.0 * si.getInfinity());
+    cMirCut.setUb(cutRHS);
+    cMirCut.setEffectiveness(violation);
+#ifdef CGL_DEBUG
+    {
+      for (int k=0; k<cutLen; k++){
+	assert(cutInd[k]>=0);
+	assert(cutCoef[k]);
+        assert (fabs(cutCoef[k])>1.0e-12);
+      }
+    }
+#endif
+    generated = true;
+  }
+
+  return generated;
+
+}
+
+//-------------------------------------------------------------------
+// construct a c-MIR inequality
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding::cMirInequality(
+				  const int numInt, 
+				  const double delta,
+				  const double numeratorBeta,
+				  const int *knapsackIndices,
+				  const double* knapsackElements,
+				  const double* xlp, 
+				  const double sStar,	       
+				  const double* colUpperBound,
+				  const std::set<int>& setC,
+				  CoinPackedVector& cMIR,
+				  double& rhscMIR,
+				  double& sCoef,
+				  double& violation) const
+{
+
+      // form a cMIR inequality
+      double beta = numeratorBeta / delta;
+      double f = beta - floor(beta);
+      rhscMIR = floor(beta);
+      double normCut = 0.0;
+      // coefficients of variables in set T
+      for (int i = 0; i < numInt; ++i) {
+	const int iIndex = knapsackIndices[i];
+	double G = 0.0;
+	if (setC.find(i) == setC.end()) {
+	  // i is not in setC, i.e., it is in T
+	  G = functionG(knapsackElements[i] / delta, f);
+	  violation += (G * xlp[iIndex]);
+	  normCut += G * G;
+	  cMIR.setElement(i, G);
+	} else {
+	  G = functionG( - knapsackElements[i] / delta, f);
+	  violation -= (G * xlp[iIndex]);
+	  normCut += G * G;
+	  rhscMIR -= G * colUpperBound[iIndex];
+	  cMIR.setElement(i, -G);	  
+	}
+      }
+      sCoef = 1.0 / (delta * (1.0 - f));
+      violation -= (rhscMIR + sCoef * sStar);
+      normCut += sCoef * sCoef;
+      violation /= sqrt(normCut);
+
+}
+
+
+//-------------------------------------------------------------------
+// function G for computing coefficients in cMIR inequality
+//-------------------------------------------------------------------
+inline double
+CglMixedIntegerRounding::functionG( const double d, const double f ) const
+{
+  double delta = d - floor(d) - f;
+  if (delta > EPSILON_)
+    return floor(d) + delta / (1 - f);
+  else
+    return floor(d);
+}
+
+//-------------------------------------------------------------------
+// Printing statistics
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding::printStats(
+			    std::ofstream & fout,
+			    const bool hasCut,
+			    const OsiSolverInterface& si,
+			    const CoinPackedVector& rowAggregated,
+			    const double& rhsAggregated, const double* xlp,
+			    const double* xlpExtra,
+			    const int* listRowsAggregated,
+			    const int* listColsSelected,
+			    const int level,
+			    const double* colUpperBound,
+			    const double* colLowerBound ) const
+{
+
+
+  const int numColsAggregated = rowAggregated.getNumElements();
+  const int *rowAggregatedIndices = rowAggregated.getIndices();
+  const double *rowAggregatedElements = rowAggregated.getElements();  
+
+  fout << "Rows ";
+  for (int i = 0; i < level; ++i) {
+    fout << listRowsAggregated[i] << " ";
+  }
+  fout << std::endl;
+
+  int numColsBack = 0;
+
+  // go through all the variables 
+  for (int j = 0; j < numColsAggregated; ++j) {
+
+    // get index and coefficient of column j in the aggregated row
+    int indCol = rowAggregatedIndices[j];
+    double coefCol = rowAggregatedElements[j];
+
+    // check if a column used in aggregation is back into the aggregated row
+    for (int i = 0; i < level-1; ++i) {
+      if ( (listColsSelected[i] == indCol) && (coefCol != 0) ) {
+	numColsBack++;
+	break;
+      }
+    }
+
+
+
+    if (fabs(coefCol) < EPSILON_) {
+      // print variable number and coefficient
+      fout << indCol << " " << 0.0 << std::endl;
+      continue;
+    }
+    else {
+      // print variable number and coefficient
+      fout << indCol << " " << coefCol << " ";
+    }
+
+    // integer variables
+    if ( (indCol < numCols_)  && (!si.isContinuous(indCol)) ) {
+
+      // print 
+      fout << "I " << xlp[indCol] << " " << colLowerBound[indCol] <<
+	" " << colUpperBound[indCol] << std::endl;
+
+      continue;
+    }
+
+    // continuous variables 
+    if (indCol < numCols_) {  // variable is model variable
+
+      // print
+      fout << "C " << xlp[indCol] << " " << colLowerBound[indCol] <<
+	" " << colUpperBound[indCol] << " ";
+
+      // variable lower bound?
+      CglMixIntRoundVLB VLB = vlbs_[indCol];
+      if (VLB.getVar() != UNDEFINED_) {
+	fout << VLB.getVal() << " " << xlp[VLB.getVar()] << " " <<
+	  colLowerBound[VLB.getVar()] << " " <<
+	  colUpperBound[VLB.getVar()] << " ";
+      }
+      else {
+	fout << "-1 -1 -1 -1 ";
+      }
+
+      // variable upper bound?
+      CglMixIntRoundVUB VUB = vubs_[indCol];
+      if (VUB.getVar() != UNDEFINED_) {
+	fout << VUB.getVal() << " " << xlp[VUB.getVar()] << " " <<
+	  colLowerBound[VUB.getVar()] << " " <<
+	  colUpperBound[VUB.getVar()] << " ";
+      }
+      else {
+	fout << "-1 -1 -1 -1 ";
+      }
+
+    }	  
+    else {  // variable is slack variable
+      // in this case the LB = 0 and the UB = infinity
+      // print
+      fout << "C " << xlpExtra[indCol-numCols_] << " " << 0.0 <<
+	" " << si.getInfinity() << " ";
+    }
+
+    fout << std::endl;
+
+  }
+
+  fout << "rhs " << rhsAggregated << std::endl;
+
+  fout << "numColsBack " << numColsBack << std::endl;
+
+  if (hasCut) {
+    fout << "CUT: YES" << std::endl;
+  }
+  else {
+    fout << "CUT: NO" << std::endl;
+  }
+
+}
+// This can be used to refresh any inforamtion
+void 
+CglMixedIntegerRounding::refreshSolver(OsiSolverInterface * )
+{
+  doneInitPre_ = false;
+}
+// Create C++ lines to get to current state
+std::string
+CglMixedIntegerRounding::generateCpp( FILE * fp) 
+{
+  CglMixedIntegerRounding other;
+  fprintf(fp,"0#include \"CglMixedIntegerRounding.hpp\"\n");
+  fprintf(fp,"3  CglMixedIntegerRounding mixedIntegerRounding;\n");
+  if (MAXAGGR_!=other.MAXAGGR_)
+    fprintf(fp,"3  mixedIntegerRounding.setMAXAGGR_(%d);\n",MAXAGGR_);
+  else
+    fprintf(fp,"4  mixedIntegerRounding.setMAXAGGR_(%d);\n",MAXAGGR_);
+  if (MULTIPLY_!=other.MULTIPLY_)
+    fprintf(fp,"3  mixedIntegerRounding.setMULTIPLY_(%d);\n",MULTIPLY_);
+  else
+    fprintf(fp,"4  mixedIntegerRounding.setMULTIPLY_(%d);\n",MULTIPLY_);
+  if (CRITERION_!=other.CRITERION_)
+  fprintf(fp,"3  mixedIntegerRounding.setCRITERION_(%d);\n",CRITERION_);
+  if (doPreproc_!=other.doPreproc_)
+    fprintf(fp,"3  mixedIntegerRounding.setDoPreproc_(%d);\n", doPreproc_);
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  mixedIntegerRounding.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  mixedIntegerRounding.setAggressiveness(%d);\n",getAggressiveness());
+  return "mixedIntegerRounding";
+}
+void CglMixedIntegerRounding::setDoPreproc(int value)
+{
+  if (value != -1 && value != 0 && value != 1) {
+    throw CoinError("setDoPrepoc", "invalid value",
+		    "CglMixedIntegerRounding2");
+  }
+  else {
+    doPreproc_ = value;
+  }  
+}
+
+bool CglMixedIntegerRounding::getDoPreproc() const
+{
+  return (doPreproc_!=0);
+}
diff --git a/cbits/coin/CglMixedIntegerRounding.hpp b/cbits/coin/CglMixedIntegerRounding.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglMixedIntegerRounding.hpp
@@ -0,0 +1,429 @@
+// LAST EDIT: 
+//-----------------------------------------------------------------------------
+// name: Mixed Integer Rounding Cut Generator
+// authors: Joao Goncalves (jog7@lehigh.edu) 
+//          Laszlo Ladanyi (ladanyi@us.ibm.com) 
+// date: August 11, 2004 
+//-----------------------------------------------------------------------------
+// Copyright (C) 2004, International Business Machines Corporation and others. 
+// All Rights Reserved.
+// This code is published under the Eclipse Public License.
+
+#ifndef CglMixedIntegerRounding_H
+#define CglMixedIntegerRounding_H
+
+#include <iostream>
+#include <fstream>
+//#include <vector>
+
+#include "CoinError.hpp"
+
+#include "CglCutGenerator.hpp"
+
+//=============================================================================
+
+#ifndef CGL_DEBUG
+#define CGL_DEBUG 0
+#endif
+
+//=============================================================================
+
+// Class to store variable upper bounds (VUB)
+class CglMixIntRoundVUB
+{
+  // Variable upper bounds have the form x_j <= a y_j, where x_j is
+  // a continuous variable and y_j is an integer variable
+
+protected:
+  int    var_;            // The index of y_j
+  double val_;            // The value of a 
+
+public:
+  // Default constructor
+  CglMixIntRoundVUB() : var_(-1), val_(-1) {}
+
+  // Copy constructor
+  CglMixIntRoundVUB(const CglMixIntRoundVUB& source) { 
+    var_ = source.var_; 
+    val_ = source.val_; 
+  } 
+
+  // Assignment operator
+  CglMixIntRoundVUB& operator=(const CglMixIntRoundVUB& rhs) { 
+    if (this != &rhs) { 
+      var_ = rhs.var_; 
+      val_ = rhs.val_; 
+    }
+    return *this; 
+  }
+
+  // Destructor
+  ~CglMixIntRoundVUB() {}
+
+  // Query and set functions
+  int    getVar() const          { return var_; }
+  double getVal() const          { return val_; }
+  void   setVar(const int v)     { var_ = v; }
+  void   setVal(const double v)  { val_ = v; }
+};
+
+//=============================================================================
+
+// Class to store variable lower bounds (VLB).
+// It is the same as the class to store variable upper bounds
+typedef CglMixIntRoundVUB CglMixIntRoundVLB;
+
+//=============================================================================
+
+/** Mixed Integer Rounding Cut Generator Class */
+
+// Reference: 
+//    Hugues Marchand and Laurence A. Wolsey
+//    Aggregation and Mixed Integer Rounding to Solve MIPs
+//    Operations Research, 49(3), May-June 2001.
+//    Also published as CORE Dicusion Paper 9839, June 1998.
+
+class CglMixedIntegerRounding : public CglCutGenerator {
+
+  friend void CglMixedIntegerRoundingUnitTest(const OsiSolverInterface * siP,
+					      const std::string mpdDir);
+
+
+private:
+  //---------------------------------------------------------------------------
+  // Enumeration constants that describe the various types of rows
+  enum RowType {
+    // The row type of this row is NOT defined yet.
+    ROW_UNDEFINED,
+    /** After the row is flipped to 'L', the row has exactly two variables: 
+	one is negative binary and the other is a continous, 
+	and the RHS is zero.*/
+    ROW_VARUB,
+    /** After the row is flipped to 'L', the row has exactly two variables: 
+	one is positive binary and the other is a continous, 
+	and the RHS is zero.*/
+    ROW_VARLB,
+    /** The row sense is 'E', the row has exactly two variables: 
+	one is binary and the other is a continous, and the RHS is zero.*/ 
+    ROW_VAREQ,
+    // The row contains continuous and integer variables;
+    // the total number of variables is at least 2
+    ROW_MIX,
+    // The row contains only continuous variables
+    ROW_CONT,
+    // The row contains only integer variables
+    ROW_INT,
+    // The row contains other types of rows
+    ROW_OTHER
+  };
+
+
+public:
+
+  /**@name Generate Cuts */
+  //@{
+  /** Generate Mixed Integer Rounding cuts for the model data 
+      contained in si. The generated cuts are inserted 
+      in the collection of cuts cs. 
+  */
+  virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			    const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglMixedIntegerRounding ();
+
+  /// Alternate Constructor 
+  CglMixedIntegerRounding (const int maxaggr,
+			   const bool multiply,
+			   const int criterion,
+			   const int preproc = -1);
+
+  /// Copy constructor 
+  CglMixedIntegerRounding (
+    const CglMixedIntegerRounding &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglMixedIntegerRounding &
+    operator=(
+    const CglMixedIntegerRounding& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglMixedIntegerRounding ();
+  /// This can be used to refresh any inforamtion
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Set and get methods */
+  //@{
+  /// Set MAXAGGR_
+  inline void setMAXAGGR_ (int maxaggr) {
+    if (maxaggr > 0) {
+      MAXAGGR_ = maxaggr;
+    }
+    else {
+      throw CoinError("Unallowable value. maxaggr must be > 0",
+                      "gutsOfConstruct","CglMixedIntegerRounding");
+    }
+  }
+
+  /// Get MAXAGGR_
+  inline int getMAXAGGR_ () const { return MAXAGGR_; }
+
+  /// Set MULTIPLY_
+  inline void setMULTIPLY_ (bool multiply) { MULTIPLY_ = multiply; }
+
+  /// Get MULTIPLY_
+  inline bool getMULTIPLY_ () const { return MULTIPLY_; }
+
+  /// Set CRITERION_
+  inline void setCRITERION_ (int criterion) {
+    if ((criterion >= 1) && (criterion <= 3)) {
+      CRITERION_ = criterion;
+    }
+    else {
+      throw CoinError("Unallowable value. criterion must be 1, 2 or 3",
+                      "gutsOfConstruct","CglMixedIntegerRounding");
+    }
+  }
+
+  /// Get CRITERION_
+  inline int getCRITERION_ () const { return CRITERION_; }
+
+
+  /// Set doPreproc
+  void setDoPreproc(int value);
+  /// Get doPreproc
+  bool getDoPreproc() const;
+
+  //@}
+
+private:
+  //--------------------------------------------------------------------------
+  // Private member methods
+
+  // Construct
+  void gutsOfConstruct (const int maxaggr,
+			const bool multiply,
+			const int criterion,
+			const int preproc);
+
+  // Delete
+  void gutsOfDelete();
+
+  // Copy
+  void gutsOfCopy (const CglMixedIntegerRounding& rhs);
+
+  // Do preprocessing.
+  // It determines the type of each row. It also identifies the variable
+  // upper bounds and variable lower bounds.
+  // It may change sense and RHS for ranged rows
+  void mixIntRoundPreprocess(const OsiSolverInterface& si);
+
+  // Determine the type of a given row.
+  RowType determineRowType(const OsiSolverInterface& si,
+			   const int rowLen, const int* ind, 
+			   const double* coef, const char sense, 
+			   const double rhs) const;
+
+  // Generate MIR cuts
+  void generateMirCuts( const OsiSolverInterface& si,
+			const double* xlp,
+			const double* colUpperBound,
+			const double* colLowerBound,
+			const CoinPackedMatrix& matrixByRow,
+			const double* LHS,
+			const double* coefByRow,
+			const int* colInds,
+			const int* rowStarts,
+			const int* rowLengths,
+			//const CoinPackedMatrix& matrixByCol,
+			const double* coefByCol,
+			const int* rowInds,
+			const int* colStarts,
+			const int* colLengths,
+			OsiCuts& cs ) const;
+
+  // Copy row selected to CoinPackedVector
+  void copyRowSelected( const int iAggregate,
+			const int rowSelected,
+			std::set<int>& setRowsAggregated,
+			int* listRowsAggregated,
+			double* xlpExtra,
+			const char sen,
+			const double rhs,
+			const double lhs,
+			const CoinPackedMatrix& matrixByRow,
+			CoinPackedVector& rowToAggregate,
+			double& rhsToAggregate) const;
+
+  // Select a row to aggregate
+  bool selectRowToAggregate( const OsiSolverInterface& si,
+			     const CoinPackedVector& rowAggregated,
+			     const double* colUpperBound,
+			     const double* colLowerBound,
+			     const std::set<int>& setRowsAggregated,
+			     const double* xlp, const double* coefByCol,
+			     const int* rowInds, const int* colStarts,
+			     const int* colLengths,
+			     int& rowSelected,
+			     int& colSelected ) const;
+
+  // Aggregation heuristic. 
+  // Combines one or more rows of the original matrix 
+  void aggregateRow( const int colSelected,
+		     CoinPackedVector& rowToAggregate, double rhs,
+		     CoinPackedVector& rowAggregated, 
+		     double& rhsAggregated ) const;
+
+  // Choose the bound substitution based on the criteria defined by the user
+  inline bool isLowerSubst(const double inf, 
+			   const double aj,
+			   const double xlp, 
+			   const double LB, 
+			   const double UB) const;
+    
+  // Bound substitution heuristic
+  bool boundSubstitution( const OsiSolverInterface& si,
+			  const CoinPackedVector& rowAggregated,
+			  const double* xlp,
+			  const double* xlpExtra,
+			  const double* colUpperBound,
+			  const double* colLowerBound,
+			  CoinPackedVector& mixedKnapsack,
+			  double& rhsMixedKnapsack, double& sStar,
+			  CoinPackedVector& contVariablesInS ) const;
+
+  // c-MIR separation heuristic
+  bool cMirSeparation ( const OsiSolverInterface& si,
+			const CoinPackedMatrix& matrixByRow,
+			const CoinPackedVector& rowAggregated,
+			const int* listRowsAggregated,
+			const char* sense, const double* RHS,
+			//const double* coefByRow,
+			//const int* colInds, const int* rowStarts,
+			//const int* rowLengths,
+			const double* xlp, const double sStar,
+			const double* colUpperBound,
+			const double* colLowerBound,
+			const CoinPackedVector& mixedKnapsack,
+			const double& rhsMixedKnapsack,
+			const CoinPackedVector& contVariablesInS,
+			OsiRowCut& flowCut ) const;
+
+  // function to create one c-MIR inequality
+  void cMirInequality( const int numInt, 
+		       const double delta,
+		       const double numeratorBeta,
+		       const int *knapsackIndices,
+		       const double* knapsackElements,
+		       const double* xlp, 
+		       const double sStar,	       
+		       const double* colUpperBound,
+		       const std::set<int>& setC,
+		       CoinPackedVector& cMIR,
+		       double& rhscMIR,
+		       double& sCoef,
+		       double& violation) const;
+
+  // function to compute G
+  inline double functionG( const double d, const double f ) const;
+
+  // function to print statistics (used only in debug mode)
+  void printStats(
+			    std::ofstream & fout,
+			    const bool hasCut,
+			    const OsiSolverInterface& si,
+			    const CoinPackedVector& rowAggregated,
+			    const double& rhsAggregated, const double* xlp,
+			    const double* xlpExtra,
+			    const int* listRowsAggregated,
+			    const int* listColsSelected,
+			    const int level,
+			    const double* colUpperBound,
+			    const double* colLowerBound ) const;
+
+
+private:
+  //---------------------------------------------------------------------------
+  // Private member data
+  
+  // Maximum number of rows to aggregate
+  int MAXAGGR_;
+  // Flag that indicates if an aggregated row is also multiplied by -1
+  bool MULTIPLY_;
+  // The criterion to use in the bound substitution
+  int CRITERION_;
+  // Tolerance used for numerical purposes
+  double EPSILON_;
+  /// There is no variable upper bound or variable lower bound defined
+  int UNDEFINED_;
+  // If violation of a cut is greater that this number, the cut is accepted
+  double TOLERANCE_;
+  /** Controls the preprocessing of the matrix to identify rows suitable for
+      cut generation.<UL>
+      <LI> -1: preprocess according to solver settings;
+      <LI> 0: Do preprocessing only if it has not yet been done;
+      <LI> 1: Do preprocessing.
+      </UL>
+      Default value: -1 **/
+  int doPreproc_;
+  // The number of rows of the problem.
+  int numRows_;
+  // The number columns of the problem.
+  int numCols_;
+  // Indicates whether preprocessing has been done.
+  bool doneInitPre_;
+  // The array of CglMixIntRoundVUBs.
+  CglMixIntRoundVUB* vubs_;
+  // The array of CglMixIntRoundVLBs.
+  CglMixIntRoundVLB* vlbs_;
+  // Array with the row types of the rows in the model.
+  RowType* rowTypes_;
+  // The indices of the rows of the initial matrix
+  int* indRows_;
+  // The number of rows of type ROW_MIX
+  int numRowMix_;
+  // The indices of the rows of type ROW_MIX
+  int* indRowMix_;
+  // The number of rows of type ROW_CONT
+  int numRowCont_;
+  // The indices of the rows of type ROW_CONT
+  int* indRowCont_;
+  // The number of rows of type ROW_INT
+  int numRowInt_;
+  // The indices of the rows of type ROW_INT
+  int* indRowInt_;
+  // The number of rows of type ROW_CONT that have at least one variable
+  // with variable upper or lower bound
+  int numRowContVB_;
+  // The indices of the rows of type ROW_CONT that have at least one variable
+  // with variable upper or lower bound
+  int* indRowContVB_;
+  // Sense of rows (modified if ranges)
+  char * sense_;
+  // RHS of rows (modified if ranges)
+  double * RHS_;
+  
+};
+
+//#############################################################################
+// A function that tests the methods in the CglMixedIntegerRounding class. The
+// only reason for it not to be a member method is that this way it doesn't
+// have to be compiled into the library. And that's a gain, because the
+// library should be compiled with optimization on, but this method should be
+// compiled with debugging.
+void CglMixedIntegerRoundingUnitTest(const OsiSolverInterface * siP,
+				     const std::string mpdDir);
+  
+#endif
diff --git a/cbits/coin/CglMixedIntegerRounding2.cpp b/cbits/coin/CglMixedIntegerRounding2.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglMixedIntegerRounding2.cpp
@@ -0,0 +1,1746 @@
+// LAST EDIT: 
+//-----------------------------------------------------------------------------
+// name: Mixed Integer Rounding Cut Generator
+// authors: Joao Goncalves (jog7@lehigh.edu) 
+//          Laszlo Ladanyi (ladanyi@us.ibm.com) 
+// date: August 11, 2004 
+//-----------------------------------------------------------------------------
+// Copyright (C) 2004, International Business Machines Corporation and others. 
+// All Rights Reserved.
+// This code is published under the Eclipse Public License.
+
+//#include <cmath>
+//#include <cstdlib>
+#include <cassert>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinPackedVector.hpp"
+
+#include "CglMixedIntegerRounding2.hpp"
+
+//-----------------------------------------------------------------------------
+// Generate Mixed Integer Rounding inequality
+//------------------------------------------------------------------- 
+void
+CglMixedIntegerRounding2::generateCuts(const OsiSolverInterface& si,
+				      OsiCuts& cs,
+				      const CglTreeInfo info)
+{
+
+  // If the LP or integer presolve is used, then need to redo preprocessing
+  // everytime this function is called. Otherwise, just do once.
+  bool preInit = false;
+  bool preReso = false;
+  si.getHintParam(OsiDoPresolveInInitial, preInit);
+  si.getHintParam(OsiDoPresolveInResolve, preReso);
+
+  if (preInit == false &&  preReso == false && doPreproc_ == -1 ) { // Do once
+    if (doneInitPre_ == false) {   
+      mixIntRoundPreprocess(si);
+      doneInitPre_ = true;
+    }
+  }
+  else {
+    if(doPreproc_ == 1){ // Do everytime       
+      mixIntRoundPreprocess(si);
+      doneInitPre_ = true;
+    } 
+    else {
+      if (doneInitPre_ == false) {   
+	mixIntRoundPreprocess(si);
+	doneInitPre_ = true;
+      }  
+    }
+  }
+
+  int numberRowCutsBefore = cs.sizeRowCuts();
+  const double* xlp        = si.getColSolution();  // LP solution
+  const double* colUpperBound = si.getColUpper();  // vector of upper bounds
+  const double* colLowerBound = si.getColLower();  // vector of lower bounds
+
+  // get matrix by row
+  const CoinPackedMatrix & tempMatrixByRow = *si.getMatrixByRow();
+  CoinPackedMatrix matrixByRow(false,0.0,0.0);
+  // There are no duplicates but this is faster
+  matrixByRow.submatrixOfWithDuplicates(tempMatrixByRow, numRows_, indRows_);
+  CoinPackedMatrix matrixByCol(matrixByRow,0,0,true);
+  //matrixByCol.reverseOrdering();
+  //const CoinPackedMatrix & matrixByRow = *si.getMatrixByRow();
+  const double* LHS        = si.getRowActivity();
+  //const double* coefByRow  = matrixByRow.getElements();
+  //const int* colInds       = matrixByRow.getIndices();
+  //const int* rowStarts     = matrixByRow.getVectorStarts();
+
+  // get matrix by column
+  //const CoinPackedMatrix & matrixByCol = *si.getMatrixByCol();
+  const double* coefByCol  = matrixByCol.getElements();
+  const int* rowInds       = matrixByCol.getIndices();
+  const int* colStarts     = matrixByCol.getVectorStarts();
+
+
+  generateMirCuts(si, xlp, colUpperBound, colLowerBound,
+		  matrixByRow,  LHS, //coefByRow,
+		  //colInds, rowStarts, //matrixByCol,
+		  coefByCol, rowInds, colStarts,
+		  cs);
+  if (!info.inTree&&((info.options&4)==4||((info.options&8)&&!info.pass))) {
+    int numberRowCutsAfter = cs.sizeRowCuts();
+    for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++)
+      cs.rowCutPtr(i)->setGloballyValid();
+  }
+
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding2::CglMixedIntegerRounding2 ()
+  :
+  CglCutGenerator()
+{ 
+  gutsOfConstruct(1, true, 1, -1);
+}
+
+
+//-------------------------------------------------------------------
+// Alternate Constructor 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding2::CglMixedIntegerRounding2 (const int maxaggr,
+						    const bool multiply,
+						    const int criterion,
+						    const int preproc)
+  :
+  CglCutGenerator()
+{ 
+  gutsOfConstruct(maxaggr, multiply, criterion, preproc);
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding2::CglMixedIntegerRounding2 ( 
+				 const CglMixedIntegerRounding2 & rhs)
+  :
+  CglCutGenerator(rhs)
+{ 
+  gutsOfCopy(rhs);
+}
+
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglMixedIntegerRounding2::clone() const
+{
+  return new CglMixedIntegerRounding2(*this);
+}
+
+//------------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding2 &
+CglMixedIntegerRounding2::operator=(const CglMixedIntegerRounding2& rhs)
+{
+  if (this != &rhs) {
+    gutsOfDelete();
+    CglCutGenerator::operator=(rhs);
+    gutsOfCopy(rhs);
+  }
+  return *this;
+}
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------  
+CglMixedIntegerRounding2::~CglMixedIntegerRounding2 ()
+{
+  gutsOfDelete();
+}
+
+//-------------------------------------------------------------------
+// Construct
+//-------------------------------------------------------------------  
+void
+CglMixedIntegerRounding2::gutsOfConstruct (const int maxaggr,
+					   const bool multiply,
+					   const int criterion,
+					   const int preproc)
+{
+  if (maxaggr > 0) {
+    MAXAGGR_ = maxaggr;
+  }
+  else {
+    throw CoinError("Unallowable value. maxaggr must be > 0",
+                      "gutsOfConstruct","CglMixedIntegerRounding2");
+  }
+  MULTIPLY_ = multiply;
+  if ((criterion >= 1) && (criterion <= 3)) {
+    CRITERION_ = criterion;
+  }
+  else {
+    throw CoinError("Unallowable value. criterion must be 1, 2 or 3",
+                      "gutsOfConstruct","CglMixedIntegerRounding2");
+  }
+  if ((preproc >= -1) && (preproc <= 2)) {
+    doPreproc_ = preproc;
+  }
+  else {
+    throw CoinError("Unallowable value. preproc must be -1, 0 or 1",
+                      "gutsOfConstruct","CglMixedIntegerRounding");
+  }
+  EPSILON_ = 1.0e-6;
+  UNDEFINED_ = -1;
+  TOLERANCE_ = 1.0e-4;
+  numRows_ = 0;
+  numCols_ = 0;
+  doneInitPre_ = false;
+  vubs_ = 0;
+  vlbs_ = 0;
+  rowTypes_ = 0;
+  indRows_ = 0;
+  numRowMix_ = 0;
+  indRowMix_ = 0;
+  numRowCont_ = 0;
+  indRowCont_ = 0;
+  numRowInt_ = 0;
+  indRowInt_ = 0;
+  numRowContVB_ = 0;
+  indRowContVB_ = 0;
+  integerType_ = NULL;
+  sense_=NULL;
+  RHS_=NULL;
+}
+
+//-------------------------------------------------------------------
+// Delete
+//-------------------------------------------------------------------  
+void
+CglMixedIntegerRounding2::gutsOfDelete ()
+{
+  if (vubs_ != 0) { delete [] vubs_; vubs_ = 0; }
+  if (vlbs_ != 0) { delete [] vlbs_; vlbs_ = 0; }
+  if (rowTypes_ != 0) { delete [] rowTypes_; rowTypes_ = 0; } 
+  if (indRows_ != 0) { delete [] indRows_; indRows_ = 0; }
+  if (indRowMix_ != 0) { delete [] indRowMix_; indRowMix_ = 0; }
+  if (indRowCont_ != 0) { delete [] indRowCont_; indRowCont_ = 0; }
+  if (indRowInt_ != 0) { delete [] indRowInt_; indRowInt_ = 0; }
+  if (indRowContVB_ != 0) { delete [] indRowContVB_; indRowContVB_ = 0; }
+  if (integerType_ !=NULL) { delete [] integerType_; integerType_=NULL;}
+  if (sense_ !=NULL) { delete [] sense_; sense_=NULL;}
+  if (RHS_ !=NULL) { delete [] RHS_; RHS_=NULL;}
+}
+
+//-------------------------------------------------------------------
+// Copy
+//-------------------------------------------------------------------  
+void
+CglMixedIntegerRounding2::gutsOfCopy (const CglMixedIntegerRounding2& rhs)
+{
+  MAXAGGR_ = rhs.MAXAGGR_;
+  MULTIPLY_ = rhs.MULTIPLY_;
+  CRITERION_ = rhs.CRITERION_;
+  EPSILON_ = rhs.EPSILON_;
+  UNDEFINED_ = rhs.UNDEFINED_;
+  TOLERANCE_ = rhs.TOLERANCE_;
+  doPreproc_ = rhs.doPreproc_;
+  numRows_ = rhs.numRows_;
+  numCols_ = rhs.numCols_;
+  doneInitPre_ = rhs.doneInitPre_;
+  numRowMix_ = rhs.numRowMix_;
+  numRowCont_ = rhs.numRowCont_;
+  numRowInt_ = rhs.numRowInt_;
+  numRowContVB_ = rhs.numRowContVB_;
+
+  if (numCols_ > 0) {
+    vubs_ = new CglMixIntRoundVUB2 [numCols_];
+    vlbs_ = new CglMixIntRoundVLB2 [numCols_];
+    CoinDisjointCopyN(rhs.vubs_, numCols_, vubs_);
+    CoinDisjointCopyN(rhs.vlbs_, numCols_, vlbs_);
+    integerType_ = CoinCopyOfArray(rhs.integerType_,numCols_);
+  }
+  else {
+    vubs_ = 0;
+    vlbs_ = 0;
+    integerType_ = NULL;
+  }
+
+  if (numRows_ > 0) {
+    rowTypes_ = new RowType [numRows_];
+    CoinDisjointCopyN(rhs.rowTypes_, numRows_, rowTypes_);
+    indRows_ = new int [numRows_];
+    CoinDisjointCopyN(rhs.indRows_, numRows_, indRows_);
+    sense_ = CoinCopyOfArray(rhs.sense_,numRows_);
+    RHS_ = CoinCopyOfArray(rhs.RHS_,numRows_);
+  }
+  else {
+    rowTypes_ = 0;
+    indRows_ = 0;
+    sense_=NULL;
+    RHS_=NULL;
+  }
+
+  if (numRowMix_ > 0) {
+    indRowMix_ = new int [numRowMix_];
+    CoinDisjointCopyN(rhs.indRowMix_, numRowMix_, indRowMix_);
+  }
+  else {
+    indRowMix_ = 0;
+  }
+
+  if (numRowCont_ > 0) {
+    indRowCont_ = new int [numRowCont_];
+    CoinDisjointCopyN(rhs.indRowCont_, numRowCont_, indRowCont_);
+    indRowContVB_ = new int [numRowCont_];
+    CoinDisjointCopyN(rhs.indRowContVB_, numRowCont_, indRowContVB_);
+  }
+  else {
+    indRowCont_ = 0;
+    indRowContVB_ = 0;
+  }
+
+  if (numRowInt_ > 0) {
+    indRowInt_ = new int [numRowInt_];
+    CoinDisjointCopyN(rhs.indRowInt_, numRowInt_, indRowInt_);
+  }
+  else {
+    indRowInt_ = 0;
+  }
+
+}
+
+//-------------------------------------------------------------------
+// Do preprocessing
+// It determines the type of each row. It also identifies the variable
+// upper bounds and variable lower bounds.
+//-------------------------------------------------------------------  
+void 
+CglMixedIntegerRounding2::
+mixIntRoundPreprocess(const OsiSolverInterface& si)
+{
+  // get matrix stored by row
+  const CoinPackedMatrix & matrixByRow = *si.getMatrixByRow();
+  numRows_ = si.getNumRows();
+  numCols_ = si.getNumCols();
+  const double* coefByRow  = matrixByRow.getElements();
+  const int* colInds       = matrixByRow.getIndices();
+  const int* rowStarts     = matrixByRow.getVectorStarts();
+  const int* rowLengths    = matrixByRow.getVectorLengths();
+  // Get copies of sense and RHS so we can modify if ranges
+  if (sense_) {
+    delete [] sense_;
+    delete [] RHS_;
+  }
+  sense_ = CoinCopyOfArray(si.getRowSense(),numRows_);
+  RHS_  = CoinCopyOfArray(si.getRightHandSide(),numRows_);
+  // Save integer type for speed
+  if (integerType_) 
+    delete [] integerType_;
+  integerType_ = new char [numCols_];
+  int iColumn;
+  for (iColumn=0;iColumn<numCols_;iColumn++) {
+    if (si.isInteger(iColumn))
+      integerType_[iColumn]=1;
+    else
+      integerType_[iColumn]=0;
+  }
+
+  if (rowTypes_ != 0) {
+    delete [] rowTypes_; rowTypes_ = 0;
+  }
+  rowTypes_ = new RowType [numRows_];     // Destructor will free memory
+
+  // Summarize the row type infomation.
+  int numUNDEFINED   = 0;
+  int numVARUB       = 0;
+  int numVARLB       = 0;
+  int numVAREQ       = 0;
+  int numMIX         = 0;
+  int numCONT        = 0;
+  int numINT         = 0;
+  int numOTHER       = 0;
+
+  int iRow;
+  const double* rowActivity        = si.getRowActivity();
+  const double* rowLower        = si.getRowLower();
+  const double* rowUpper        = si.getRowUpper();
+  for (iRow = 0; iRow < numRows_; ++iRow) {
+    // If range then choose which to use
+    if (sense_[iRow]=='R') {
+      if (rowActivity[iRow]-rowLower[iRow]<
+          rowUpper[iRow]-rowActivity[iRow]) {
+        // treat as G row
+        RHS_[iRow]=rowLower[iRow];
+        sense_[iRow]='G';
+      } else {
+        // treat as L row
+        RHS_[iRow]=rowUpper[iRow];
+        sense_[iRow]='L';
+      }
+    }
+    // get the type of a row
+    const RowType rowType = 
+      determineRowType(/*si,*/ rowLengths[iRow], colInds+rowStarts[iRow],
+		       coefByRow+rowStarts[iRow], sense_[iRow], RHS_[iRow]);
+    // store the type of the current row
+    rowTypes_[iRow] = rowType;
+
+    // Summarize information about row types
+    switch(rowType) {
+    case  ROW_UNDEFINED:
+      ++numUNDEFINED; 
+      break;
+    case  ROW_VARUB:
+      ++numVARUB; 
+      break;
+    case  ROW_VARLB:
+      ++numVARLB; 
+      break;
+    case  ROW_VAREQ:
+      ++numVAREQ; 
+      break;
+    case  ROW_MIX:
+      ++numMIX; 
+      break;
+    case  ROW_CONT:
+      ++numCONT; 
+      break;
+    case  ROW_INT:
+      ++numINT; 
+      break;
+    case  ROW_OTHER:
+      ++numOTHER; 
+      break;
+    default:
+      throw CoinError("Unknown row type", "MixIntRoundPreprocess",
+		      "CglMixedIntegerRounding2");
+    }
+  }
+
+  // allocate memory for vector of indices of all rows
+  if (indRows_ != 0) { delete [] indRows_; indRows_ = 0; }
+  if (numRows_ > 0)
+    indRows_ = new int [numRows_];     // Destructor will free memory
+  // allocate memory for vector of indices of rows of type ROW_MIX
+  numRowMix_ = numMIX;
+  if (indRowMix_ != 0) { delete [] indRowMix_; indRowMix_ = 0; }
+  if (numRowMix_ > 0)
+    indRowMix_ = new int [numRowMix_];     // Destructor will free memory
+  // allocate memory for vector of indices of rows of type ROW_CONT
+  numRowCont_ = numCONT;
+  if (indRowCont_ != 0) { delete [] indRowCont_; indRowCont_ = 0; }
+  if (numRowCont_ > 0)
+    indRowCont_ = new int [numRowCont_];     // Destructor will free memory
+  // allocate memory for vector of indices of rows of type ROW_INT
+  numRowInt_ = numINT;
+  if (indRowInt_ != 0) { delete [] indRowInt_; indRowInt_ = 0; }
+  if (numRowInt_ > 0)
+    indRowInt_ = new int [numRowInt_];     // Destructor will free memory
+
+#if CGL_DEBUG
+  std::cout << "The num of rows = "  << numRows_        << std::endl;
+  std::cout << "Summary of Row Type" << std::endl;
+  std::cout << "numUNDEFINED     = " << numUNDEFINED   << std::endl;
+  std::cout << "numVARUB         = " << numVARUB       << std::endl;
+  std::cout << "numVARLB         = " << numVARLB       << std::endl;
+  std::cout << "numVAREQ         = " << numVAREQ       << std::endl;
+  std::cout << "numMIX           = " << numMIX         << std::endl;
+  std::cout << "numCONT          = " << numCONT        << std::endl;
+  std::cout << "numINT           = " << numINT         << std::endl;
+  std::cout << "numOTHER         = " << numOTHER       << std::endl;
+#endif
+
+  //---------------------------------------------------------------------------
+  // Setup  vubs_ and vlbs_
+  if (vubs_ != 0) { delete [] vubs_; vubs_ = 0; }
+  vubs_ = new CglMixIntRoundVUB2 [numCols_]; // Destructor will free
+  if (vlbs_ != 0) { delete [] vlbs_; vlbs_ = 0; }
+  vlbs_ = new CglMixIntRoundVLB2 [numCols_]; // Destructor will free
+
+  // Initialization. Altough this has been done in constructor, it is needed
+  // for the case where the mixIntRoundPreprocess is called more than once
+  for (int iCol = 0; iCol < numCols_; ++iCol) {
+    vubs_[iCol].setVar(UNDEFINED_);
+    vlbs_[iCol].setVar(UNDEFINED_);
+  }
+  
+  int countM = 0;
+  int countC = 0;
+  int countI = 0;
+  for ( iRow = 0; iRow < numRows_; ++iRow) {
+
+    RowType rowType = rowTypes_[iRow];
+
+    // fill the vector indRows_ with the indices of all rows
+    indRows_[iRow] = iRow;
+
+    // fill the vector indRowMix_ with the indices of the rows of type ROW_MIX
+    if (rowType == ROW_MIX) {
+      indRowMix_[countM] = iRow;
+      countM++;
+    }
+    // fill the vector indRowCont_ with the indices of rows of type ROW_CONT
+    else if (rowType == ROW_CONT) {
+      indRowCont_[countC] = iRow;
+      countC++;
+    }
+    // fill the vector indRowInt_ with the indices of the rows of type ROW_INT
+    else if (rowType == ROW_INT) {
+      indRowInt_[countI] = iRow;
+      countI++;
+    }
+    // create vectors with variable lower and upper bounds
+    else if ( (rowType == ROW_VARUB) || 
+	      (rowType == ROW_VARLB) || 
+	      (rowType == ROW_VAREQ) )  { 
+      
+      int startPos = rowStarts[iRow];
+      int stopPos  = startPos + rowLengths[iRow];
+      int    xInd = 0,  yInd = 0;   // x is continuous, y is integer
+      double xCoef = 0.0, yCoef = 0.0;
+
+      for (int i = startPos; i < stopPos; ++i) {
+	if ( fabs(coefByRow[i]) > EPSILON_ ) {
+	  if( integerType_[colInds[i]] ) {
+	    yInd  = colInds[i];
+	    yCoef = coefByRow[i];
+	  }
+	  else {
+	    xInd  = colInds[i];
+	    xCoef = coefByRow[i];
+	  }
+	}
+      }
+
+      switch (rowType) {
+      case ROW_VARUB:       // Inequality: x <= ? * y
+	vubs_[xInd].setVar(yInd);
+	vubs_[xInd].setVal(-yCoef / xCoef);
+	break;
+      case ROW_VARLB:       // Inequality: x >= ? * y
+	vlbs_[xInd].setVar(yInd);
+	vlbs_[xInd].setVal(-yCoef / xCoef);
+	break;
+      case ROW_VAREQ:       // Inequality: x >= AND <= ? * y
+	vubs_[xInd].setVar(yInd);
+	vubs_[xInd].setVal(-yCoef / xCoef);
+	vlbs_[xInd].setVar(yInd);
+	vlbs_[xInd].setVal(-yCoef / xCoef);
+	break;
+      default:
+        // I am getting compiler bug which gets here - I am disabling - JJF
+	//throw CoinError("Unknown row type: impossible", 
+        //	"MixIntRoundPreprocess",
+        //	"CglMixedIntegerRounding2");
+        break;
+      }
+    }
+  }
+
+  // allocate memory for vector of indices of rows of type ROW_CONT
+  // that have at least one variable with variable upper or lower bound
+  if (indRowContVB_ != 0) { delete [] indRowContVB_; indRowContVB_ = 0; }
+  if (numRowCont_ > 0)
+    indRowContVB_ = new int [numRowCont_];     // Destructor will free memory
+  // create vector with rows of type ROW_CONT that have at least
+  // one variable with variable upper or lower bound
+  countC = 0;
+  for (int i = 0; i < numRowCont_; ++i) {
+    int indRow = indRowCont_[i];
+    int jStart = rowStarts[indRow];
+    int jStop = jStart + rowLengths[indRow];
+    for (int j = jStart; j < jStop; ++j) {
+      int indCol = colInds[j];
+      CglMixIntRoundVLB2 VLB = vlbs_[indCol];
+      CglMixIntRoundVUB2 VUB = vubs_[indCol];
+      if (( VLB.getVar() != UNDEFINED_ ) || ( VUB.getVar() != UNDEFINED_ ) ){
+	indRowContVB_[countC] = indRow;
+	countC++;
+	break;
+      }
+    }
+  }
+  numRowContVB_ = countC;
+
+}
+
+//-------------------------------------------------------------------
+// Determine the type of a given row 
+//-------------------------------------------------------------------
+CglMixedIntegerRounding2::RowType
+CglMixedIntegerRounding2::determineRowType(//const OsiSolverInterface& si,
+				  const int rowLen, const int* ind, 
+				  const double* coef, const char sense, 
+				  const double rhs) const
+{
+  if (rowLen == 0 || fabs(rhs) > 1.0e20) 
+    return ROW_UNDEFINED;
+
+  RowType rowType = ROW_UNDEFINED;
+
+  int  numPosInt = 0;      // num of positive integer variables
+  int  numNegInt = 0;      // num of negative integer variables
+  int  numInt    = 0;      // num of integer variables
+  int  numPosCon = 0;      // num of positive continuous variables
+  int  numNegCon = 0;      // num of negative continuous variables
+  int  numCon    = 0;      // num of continuous variables
+
+
+  // Summarize the variable types of the given row.
+  for ( int i = 0; i < rowLen; ++i ) {
+    if ( coef[i] < -EPSILON_ ) {
+      if( integerType_[ind[i]] )
+	++numNegInt;
+      else
+	++numNegCon;
+    }
+    else if ( coef[i] > EPSILON_ ) {
+      if( integerType_[ind[i]] )
+	++numPosInt;
+      else
+	++numPosCon;
+    }
+  }
+  numInt = numNegInt + numPosInt;
+  numCon = numNegCon + numPosCon;
+
+#if CGL_DEBUG
+  std::cout << "numNegInt = " << numNegInt << std::endl;
+  std::cout << "numPosInt = " << numPosInt << std::endl;
+  std::cout << "numInt = " << numInt << std::endl;
+  std::cout << "numNegCon = " << numNegCon << std::endl;
+  std::cout << "numPosCon = " << numPosCon << std::endl;
+  std::cout << "numCon = " << numCon << std::endl;
+  std::cout << "rowLen = " << rowLen << std::endl;
+#endif
+
+
+  //-------------------------------------------------------------------------
+  // Classify row type based on the types of variables.
+    
+  if ((numInt > 0) && (numCon > 0)) {
+    if ((numInt == 1) && (numCon == 1) && (fabs(rhs) <= EPSILON_)) {
+      // It's a variable bound constraint
+      switch (sense) {
+      case 'L':
+	rowType = numPosCon == 1 ? ROW_VARUB : ROW_VARLB;
+	break;
+      case 'G':
+	rowType = numPosCon == 1 ? ROW_VARLB : ROW_VARUB;
+	break;
+      case 'E':
+        rowType = ROW_VAREQ;
+	break;
+      default:
+	break;
+      }
+    }
+    else {
+      // It's a constraint with continuous and integer variables;
+      // The total number of variables is at least 2
+      rowType = ROW_MIX;
+    }
+  }
+  else if (numInt == 0) {
+    // It's a constraint with only continuous variables
+    rowType = ROW_CONT;
+  }
+  else if ((numCon == 0) && ((sense == 'L') || (sense == 'G'))) {
+    // It's a <= or >= constraint with only integer variables 
+    rowType = ROW_INT;
+  }
+  else
+    // It's a constraint that does not fit the above categories
+    rowType = ROW_OTHER;
+
+
+  return rowType;
+}
+
+//-------------------------------------------------------------------
+// Generate MIR cuts
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding2::generateMirCuts( 
+			    const OsiSolverInterface& si,
+			    const double* xlp,
+			    const double* colUpperBound,
+			    const double* colLowerBound,
+			    const CoinPackedMatrix& matrixByRow,
+			    const double* LHS,
+			    //const double* coefByRow,
+			    //const int* colInds,
+			    //const int* rowStarts,
+			    //const CoinPackedMatrix& matrixByCol,
+			    const double* coefByCol,
+			    const int* rowInds,
+			    const int* colStarts,
+			    OsiCuts& cs ) const
+{
+
+#if CGL_DEBUG
+  // OPEN FILE
+  std::ofstream fout("stats.dat");
+#endif
+
+  // Define upper limit for the loop where the cMIRs are constructed
+  int upperLimit;
+  if (MULTIPLY_)
+    upperLimit = 2;
+  else
+    upperLimit = 1;
+  
+  // create a vector with the columns that were used in the aggregation
+  int* listColsSelected = new int[MAXAGGR_];
+  // create a vector with the rows that were aggregated
+  int* listRowsAggregated = new int[MAXAGGR_];
+  // create a vector with the LP solutions of the slack variables
+  double* xlpExtra = new double[MAXAGGR_];
+
+  // loop until maximum number of aggregated rows is reached or a 
+  // violated cut is found
+  int numRowMixAndRowContVB = numRowMix_ + numRowContVB_;
+  int numRowMixAndRowContVBAndRowInt = numRowMixAndRowContVB + numRowInt_;
+  // Get large enough vector
+  CoinIndexedVector rowAggregated(si.getNumCols());
+  CoinIndexedVector rowToAggregate(si.getNumCols());
+  CoinIndexedVector mixedKnapsack(si.getNumCols());
+  CoinIndexedVector contVariablesInS(si.getNumCols());
+  CoinIndexedVector rowToUse(si.getNumCols());
+  // And work vectors
+  CoinIndexedVector workVectors[4];
+  for (int i=0; i<4; i++)
+    workVectors[i].reserve(si.getNumCols());
+  CoinIndexedVector setRowsAggregated(si.getNumRows());
+  for (int iRow = 0; iRow < numRowMixAndRowContVBAndRowInt; ++iRow) {
+
+    int rowSelected;  // row selected to be aggregated next
+    int colSelected;  // column selected for pivot in aggregation
+    rowAggregated.clear();
+    double rhsAggregated;
+    // create a set with the indices of rows selected
+    setRowsAggregated.clear();
+
+    // loop until the maximum number of aggregated rows is reached
+    for (int iAggregate = 0; iAggregate < MAXAGGR_; ++iAggregate) {
+
+      if (iAggregate == 0) {
+
+	// select row
+	if (iRow < numRowMix_) {
+	  rowSelected = indRowMix_[iRow];
+	}
+	else if (iRow < numRowMixAndRowContVB) {
+	  rowSelected = indRowContVB_[iRow - numRowMix_];
+	}
+	else {
+	  rowSelected = indRowInt_[iRow - numRowMixAndRowContVB];
+	}
+
+	copyRowSelected(iAggregate, rowSelected, setRowsAggregated,
+			listRowsAggregated, xlpExtra, sense_[rowSelected], 
+			RHS_[rowSelected], LHS[rowSelected], 
+			matrixByRow, rowAggregated, rhsAggregated);
+
+      } 
+      else {
+
+	// search for a row to aggregate
+	bool foundRowToAggregate = selectRowToAggregate(
+							/*si,*/ rowAggregated,
+					colUpperBound, colLowerBound, 
+					setRowsAggregated, xlp, 
+					coefByCol, rowInds, colStarts,
+					rowSelected, colSelected);
+
+	// if finds row to aggregate, compute aggregated row
+	if (foundRowToAggregate) {
+
+	  rowToAggregate.clear();
+	  double rhsToAggregate;
+
+	  listColsSelected[iAggregate] = colSelected;
+
+	  copyRowSelected(iAggregate, rowSelected, setRowsAggregated,
+			  listRowsAggregated, xlpExtra, sense_[rowSelected], 
+			  RHS_[rowSelected], LHS[rowSelected], 
+			  matrixByRow, rowToAggregate, rhsToAggregate);
+
+	  // call aggregate row heuristic
+	  aggregateRow(colSelected, rowToAggregate, rhsToAggregate, 
+		       rowAggregated, rhsAggregated);
+
+	}
+	else
+	  break;
+      }
+
+      // construct cMIR with current rowAggregated
+      // and, if upperLimit=2 construct also a cMIR with 
+      // the current rowAggregated multiplied by -1
+      for (int i = 0; i < upperLimit; ++i) {
+      
+	// create vector for mixed knapsack constraint
+	double rhsMixedKnapsack;
+        rowToUse.copy(rowAggregated);
+        if (i==0) {
+          rhsMixedKnapsack = rhsAggregated;
+	} else {
+          rowToUse *= -1.0;
+	  rhsMixedKnapsack  = - rhsAggregated;
+	}	  
+	mixedKnapsack.clear();
+	double sStar = 0.0;
+
+	// create vector for the continuous variables in s
+	contVariablesInS.clear();
+
+	// call bound substitution heuristic
+	bool foundMixedKnapsack = boundSubstitution(
+					si, rowToUse, 
+					xlp, xlpExtra, 
+					colUpperBound, colLowerBound,
+					mixedKnapsack, rhsMixedKnapsack, 
+					sStar, contVariablesInS);
+    
+	// if it did not find a mixed knapsack it is because there is at
+	// least one integer variable with lower bound different than zero
+	// or there are no integer or continuous variables.
+	// In this case, we continue without trying to generate a c-MIR
+	if (!foundMixedKnapsack) {
+#if CGL_DEBUG	  
+	  std::cout << "couldn't create mixed knapsack" << std::endl;
+#endif
+	  continue;
+	}
+
+	OsiRowCut cMirCut;
+
+	// Find a c-MIR cut with the current mixed knapsack constraint
+	bool hasCut = cMirSeparation(si, matrixByRow, rowToUse,
+				     listRowsAggregated, sense_, RHS_,
+				     //coefByRow, colInds, rowStarts, 
+				     xlp, sStar, colUpperBound, colLowerBound, 
+				     mixedKnapsack,
+				     rhsMixedKnapsack, contVariablesInS,
+				     workVectors,cMirCut);
+
+#if CGL_DEBUG
+	// PRINT STATISTICS
+	printStats(fout, hasCut, si, rowAggregated, rhsAggregated, xlp,
+		   xlpExtra, listRowsAggregated, listColsSelected, 
+		   iAggregate+1, colUpperBound, colLowerBound );
+#endif
+
+	// if a cut was found, insert it into cs
+	if (hasCut)  {
+#if CGL_DEBUG
+	  std::cout << "MIR cut generated " << std::endl;
+#endif
+	  cs.insert(cMirCut);
+	}
+
+      }
+	
+    }
+
+  }
+
+  // free memory
+  delete [] listColsSelected; listColsSelected = 0;
+  delete [] listRowsAggregated; listRowsAggregated = 0;
+  delete [] xlpExtra; xlpExtra = 0;
+  
+#if CGL_DEBUG
+  // CLOSE FILE
+  fout.close();
+#endif
+
+  return;
+
+}
+
+//-------------------------------------------------------------------
+// Copy row selected to CoinIndexedVector
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding2::copyRowSelected(
+			    const int iAggregate,
+			    const int rowSelected,
+			    CoinIndexedVector& setRowsAggregated,
+			    int* listRowsAggregated,
+			    double* xlpExtra,
+			    const char sen,
+			    const double rhs,
+			    const double lhs,
+			    const CoinPackedMatrix& matrixByRow,
+			    CoinIndexedVector& rowToAggregate,
+			    double& rhsToAggregate) const
+{
+
+  // copy the row selected to a vector of type CoinIndexedVector
+  const CoinShallowPackedVector reqdBySunCC = matrixByRow.getVector(rowSelected) ;
+  rowToAggregate = reqdBySunCC ;
+  rhsToAggregate = rhs;
+
+  // update list of indices of rows selected
+  setRowsAggregated.insert(rowSelected,1.0);
+  listRowsAggregated[iAggregate] = rowSelected;
+
+  // Add a slack variable if needed and compute its current value
+  if (sen == 'L') {
+    rowToAggregate.insert(numCols_ + iAggregate, 1);
+    xlpExtra[iAggregate] = rhs - lhs;
+  }
+  else if (sen == 'G') {
+    rowToAggregate.insert(numCols_ + iAggregate, -1);
+    xlpExtra[iAggregate] = lhs - rhs;
+  }
+
+}
+
+//-------------------------------------------------------------------
+// Construct the set P* and select a row to aggregate
+//-------------------------------------------------------------------
+bool
+CglMixedIntegerRounding2::selectRowToAggregate( 
+					       //const OsiSolverInterface& si,
+			    const CoinIndexedVector& rowAggregated,
+			    const double* colUpperBound,
+			    const double* colLowerBound,
+			    const CoinIndexedVector& setRowsAggregated,
+			    const double* xlp, const double* coefByCol,
+			    const int* rowInds, const int* colStarts,
+			    int& rowSelected,
+			    int& colSelected ) const
+{
+
+  bool foundRowToAggregate = false;
+
+  double deltaMax = 0.0;  // maximum delta
+  const int numColsAggregated = rowAggregated.getNumElements();
+  const int *rowAggregatedIndices = rowAggregated.getIndices();
+  const double *rowAggregatedElements = rowAggregated.denseVector();  
+
+  for (int j = 0; j < numColsAggregated; ++j) {
+
+    // store the index and coefficient of column j
+    int indCol = rowAggregatedIndices[j];
+    if (indCol >= numCols_) continue;
+    double coefCol = rowAggregatedElements[indCol];
+
+    // Consider only continuous variables
+    if ( (integerType_[indCol]) || (fabs(coefCol) < EPSILON_)) continue;
+
+    // Compute current lower bound
+    CglMixIntRoundVLB2 VLB = vlbs_[indCol];
+    double LB = ( VLB.getVar() != UNDEFINED_ ) ? 
+                      VLB.getVal() * xlp[VLB.getVar()] : colLowerBound[indCol];
+    
+    // Compute current upper bound
+    CglMixIntRoundVUB2 VUB = vubs_[indCol];
+    double UB = ( VUB.getVar() != UNDEFINED_ ) ? 
+                      VUB.getVal() * xlp[VUB.getVar()] : colUpperBound[indCol];
+
+    // Compute distances from current solution to upper and lower bounds
+    double delta = CoinMin(xlp[indCol] - LB, UB - xlp[indCol]);
+
+    // In case this variable is acceptable look for possible rows
+    if (delta > deltaMax) {
+
+      int iStart = colStarts[indCol];
+      int iStop  = colStarts[indCol+1];
+      //      int count = 0;
+
+      //      std::vector<int> rowPossible;
+
+      // find a row to use in aggregation
+      for (int i = iStart; i < iStop; ++i) {
+	int rowInd = rowInds[i];
+	if (!setRowsAggregated.denseVector()[rowInd]) {
+	  // if the row was not already selected, select it
+	  RowType rType = rowTypes_[rowInd];
+	  if ( ((rType == ROW_MIX) || (rType == ROW_CONT)) 
+	       && (fabs(coefByCol[i]) > EPSILON_) ) {
+	    //	    rowPossible.push_back(rowInd);
+	    rowSelected = rowInd;
+	    deltaMax = delta;
+	    colSelected = indCol;
+	    foundRowToAggregate = true;
+	    //count++;
+	    break;
+	  }
+	}
+      }
+
+      //      if (count > 0)
+      //	rowSelected = rowPossible[rand() % count];
+      //      std::cout << count << std::endl;
+    }
+	
+  }
+
+  return foundRowToAggregate;
+
+}
+      
+//-------------------------------------------------------------------
+// Aggregate the selected row with the current aggregated row
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding2::aggregateRow( 
+			    const int colSelected,
+			    CoinIndexedVector& rowToAggregate, double rhs,
+			    CoinIndexedVector& rowAggregated, 
+			    double& rhsAggregated ) const
+{
+
+  // quantity to multiply by the coefficients of the row to aggregate
+  double multiCoef = rowAggregated[colSelected] / rowToAggregate[colSelected];
+
+  rowToAggregate *= multiCoef; 
+  rhs *= multiCoef;
+
+  rowAggregated = rowAggregated - rowToAggregate;
+  rhsAggregated -= rhs;
+
+}
+
+//-------------------------------------------------------------------
+// Choose the bound substitution based on the criteria defined by the user
+//-------------------------------------------------------------------
+inline bool
+CglMixedIntegerRounding2::isLowerSubst(const double inf, 
+				      const double aj,
+				      const double xlp, 
+				      const double LB, 
+				      const double UB) const
+{
+  if (CRITERION_ == 1) {
+    // criterion 1 (the same as criterion (a) in the paper)
+    return xlp - LB < UB - xlp;
+  }
+  else {
+    if (UB == inf || xlp == LB) 
+      return true;
+    if (LB == -inf || xlp == UB)
+      return false;
+    if (CRITERION_ == 2) 
+      // criterion 2 (the same as criterion (b) in the paper)
+      return aj < 0;
+    else
+      // criterion 3 (the same as criterion (c) in the paper)
+      return aj > 0;
+  }
+}
+
+
+
+//-------------------------------------------------------------------
+// Bound substitution heuristic
+//-------------------------------------------------------------------
+bool
+CglMixedIntegerRounding2::boundSubstitution( 
+			    const OsiSolverInterface& si,
+			    const CoinIndexedVector& rowAggregated,
+			    const double* xlp,
+			    const double* xlpExtra,
+			    const double* colUpperBound,
+			    const double* colLowerBound,
+			    CoinIndexedVector& mixedKnapsack,
+			    double& rhsMixedKnapsack, double& sStar,
+			    CoinIndexedVector& contVariablesInS ) const
+{
+
+  bool generated = false;
+  const int numColsAggregated = rowAggregated.getNumElements();
+  const int *rowAggregatedIndices = rowAggregated.getIndices();
+  const double *rowAggregatedElements = rowAggregated.denseVector();  
+
+  // go through all the variables and if it is continuous and delta is 
+  // negative, store variable in the vector contVariablesInS.
+  // If it is integer, store variable in the vector mixedKnapsack
+  int numCont = 0;
+  double infinity = si.getInfinity();
+  int j;
+  for ( j = 0; j < numColsAggregated; ++j) {
+
+    // get index and coefficient of column j in the aggregated row
+    const int indCol = rowAggregatedIndices[j];
+    const double coefCol = rowAggregatedElements[indCol];
+
+    // if the lower bound is equal to the upper bound, remove variable
+    if ( (indCol < numCols_) &&
+	 (colLowerBound[indCol] == colUpperBound[indCol]) ) {
+      rhsMixedKnapsack -= coefCol * colLowerBound[indCol];
+      continue;
+    }
+
+    if (fabs(coefCol) < EPSILON_) continue;
+    // set the coefficients of the integer variables
+    if ( (indCol < numCols_)  && (integerType_[indCol]) ) {
+      // Copy the integer variable to the vector mixedKnapsack
+      mixedKnapsack.add(indCol,coefCol);
+      continue;
+    }
+
+    // Select the continuous variables and copy the ones in s to 
+    // the vector contVariablesInS
+    if (indCol < numCols_) {  // variable is model variable
+
+      // Compute lower bound for variable indCol
+      const CglMixIntRoundVLB2 VLB = vlbs_[indCol];
+      const double LB = ( VLB.getVar() != UNDEFINED_ ) ? 
+	        VLB.getVal() * xlp[VLB.getVar()] : colLowerBound[indCol];
+    
+      // Compute upper bound for variable indCol
+      const CglMixIntRoundVUB2 VUB = vubs_[indCol];
+      const double UB = ( VUB.getVar() != UNDEFINED_ ) ? 
+	        VUB.getVal() * xlp[VUB.getVar()] : colUpperBound[indCol];
+
+      // if both bounds are infinite, then we cannot form a mixed knapsack
+      if ( (LB == -1.0 * infinity) &&
+	   (UB == infinity) ) {
+#if CGL_DEBUG
+	std::cout << "continuous var with infinite bounds. " <<
+                     "Cannot form mixed Knapsack = " << std::endl;
+#endif
+	return generated;
+      }
+
+      // Select the bound substitution
+      if (isLowerSubst(infinity, rowAggregatedElements[indCol],
+			 xlp[indCol], LB, UB)) {
+	if (VLB.getVar() != UNDEFINED_ ) {
+	  const int indVLB = VLB.getVar();
+          mixedKnapsack.add(indVLB, coefCol * VLB.getVal());
+	}
+	else {
+	  rhsMixedKnapsack -= coefCol * LB;
+	}
+	// Update sStar
+	if (coefCol < -EPSILON_) {
+	  contVariablesInS.insert(indCol, coefCol);
+	  sStar -= coefCol * (xlp[indCol] - LB);
+	  numCont++;
+	}
+      }
+      else {
+	if (VUB.getVar() != UNDEFINED_ ) {
+	  const int indVUB = VUB.getVar();
+          mixedKnapsack.add(indVUB, coefCol * VUB.getVal());
+	}
+	else {
+	  rhsMixedKnapsack -= coefCol * UB;
+	}
+	// Update sStar
+	if (coefCol > EPSILON_) {
+	  contVariablesInS.insert(indCol, - coefCol);
+	  sStar += coefCol * (UB - xlp[indCol]);
+	  numCont++;
+	}
+      }
+    }
+    else {  // variable is slack variable
+      // in this case the LB = 0 and the UB = infinity
+      // Update sStar
+      const double tLB = xlpExtra[indCol - numCols_];
+      if (coefCol < -EPSILON_) {
+	contVariablesInS.insert(indCol, coefCol);
+	sStar -= coefCol * tLB;
+	numCont++;
+      }
+    }
+
+  }
+
+  // if there are no continuous variables to form s, then we stop
+#if CGL_DEBUG
+  std::cout << "# of continuous var in mixedKnapsack = " << numCont <<
+    std::endl;
+#endif
+  if (numCont == 0) return generated;
+
+  // check that the integer variables have lower bound equal to zero
+  const int numInt = mixedKnapsack.getNumElements();
+  // if there are not integer variables in mixedKnapsack, then we stop
+  // CAUTION: all the coefficients could be zero
+#if CGL_DEBUG
+  std::cout << "# of integer var in mixedKnapsack = " << numInt <<
+    std::endl;
+#endif
+  if (numInt == 0) return generated;
+  const int *knapsackIndices = mixedKnapsack.getIndices();
+  const double *knapsackElements = mixedKnapsack.denseVector();  
+
+  for ( j = 0; j < numInt; ++j) {
+    int indCol = knapsackIndices[j];
+    // if the coefficient is zero, disregard
+    if (fabs(knapsackElements[indCol]) < EPSILON_) continue;
+    // if the lower bound is not zero, then we stop
+    if (fabs(colLowerBound[indCol]) > EPSILON_) return generated;
+  }
+  // if the lower bounds of all integer variables are zero, proceed
+  generated = true;
+  return generated;
+
+}
+
+//-------------------------------------------------------------------
+// c-MIR separation heuristic
+//-------------------------------------------------------------------
+bool
+CglMixedIntegerRounding2::cMirSeparation( 
+			    const OsiSolverInterface& si,
+			    const CoinPackedMatrix& matrixByRow,
+			    const CoinIndexedVector& rowAggregated,
+			    const int* listRowsAggregated,
+			    const char* sense, const double* RHS,
+			    //const double* coefByRow,
+			    //const int* colInds, const int* rowStarts,
+			    const double* xlp, const double sStar,
+			    const double* colUpperBound,
+			    const double* colLowerBound,
+			    const CoinIndexedVector& mixedKnapsack,
+			    const double& rhsMixedKnapsack,
+			    const CoinIndexedVector& contVariablesInS,
+                            CoinIndexedVector * workVectors,
+			    OsiRowCut& cMirCut) const
+{
+
+  bool generated = false;
+  double numeratorBeta = rhsMixedKnapsack;
+  CoinIndexedVector * cMIR = &workVectors[0];
+  cMIR->copy(mixedKnapsack);
+  double rhscMIR;
+  double maxViolation = 0.0;
+  double bestDelta = 0.0;
+  CoinIndexedVector * bestCut = &workVectors[1];
+  double rhsBestCut = 0.0;
+  double sCoefBestCut = 0.0;
+  const int numInt = mixedKnapsack.getNumElements();  
+  const int *knapsackIndices = mixedKnapsack.getIndices();
+  const double *knapsackElements = mixedKnapsack.denseVector();  
+  const int *contVarInSIndices = contVariablesInS.getIndices();
+  const double *contVarInSElements = contVariablesInS.denseVector();
+
+  // Construct set C, T will be the rest.
+  // Also, for T we construct a CoinIndexedVector named complT which
+  // contains the vars in T that are strictly between their bounds
+  CoinIndexedVector & setC = workVectors[3];
+  setC.clear();
+  CoinIndexedVector * complT = &workVectors[2];
+  complT->clear();
+  double infinity = si.getInfinity();
+  int j;
+  for ( j = 0; j < numInt; ++j) {
+    const int indCol = knapsackIndices[j];
+    // if the upper bound is infinity, then indCol is in T and cannot
+    // be in complT
+    if (colUpperBound[indCol] != infinity) {
+      if (xlp[indCol] >= colUpperBound[indCol] / 2.0) {
+	setC.insert(j,1.0);
+	numeratorBeta -= knapsackElements[indCol] * colUpperBound[indCol];
+      } else {
+	if ( (xlp[indCol] <= EPSILON_) || 
+	     (xlp[indCol] >= colUpperBound[indCol] - EPSILON_))
+	  continue;
+	complT->insert(j, fabs(xlp[indCol] - colUpperBound[indCol]/2));
+      }
+    }
+  }
+
+  // Sort the indices in complT by nondecreasing values 
+  // (which are  $|y^*_j-u_j/2|$)
+  if (complT->getNumElements() > 0) {
+    complT->sortIncrElement();
+  }
+
+  // Construct c-MIR inequalities and take the one with the largest violation
+  for ( j = 0; j < numInt; ++j) {
+    int indCol = knapsackIndices[j];
+    if ( (xlp[indCol] <= EPSILON_) || 
+	 (xlp[indCol] >= colUpperBound[indCol] - EPSILON_))
+      continue;
+    double delta = knapsackElements[indCol];
+    // delta has to be positive
+    if (delta <= EPSILON_) continue;
+
+    double violation = 0.0;
+    double sCoef = 0.0;
+
+    // form a cMIR inequality
+    cMirInequality(numInt, delta, numeratorBeta, knapsackIndices, 
+		   knapsackElements, xlp, sStar, colUpperBound, setC, *cMIR,
+		   rhscMIR, sCoef, violation);
+
+    // store cut if it is the best found so far
+    if (violation > maxViolation + EPSILON_) {
+      bestCut->copy(*cMIR);
+      rhsBestCut = rhscMIR;
+      sCoefBestCut = sCoef;
+      maxViolation = violation;
+      bestDelta = delta;
+    }
+  }
+
+  // if no violated inequality has been found, exit now
+  if (maxViolation == 0.0) {
+    bestCut->clear();
+    return generated;
+  }
+
+  // improve the best violated inequality.
+  // try to divide delta by 2, 4 or 8 and see if increases the violation
+  double deltaBase = bestDelta;
+  for (int multFactor = 2; multFactor <= 8; multFactor *= 2) {
+    double delta = deltaBase / multFactor;
+    double violation = 0.0;
+    double sCoef = 0.0;
+
+    // form a cMIR inequality
+    cMirInequality(numInt, delta, numeratorBeta, knapsackIndices, 
+		   knapsackElements, xlp, sStar, colUpperBound, setC, *cMIR,
+		   rhscMIR, sCoef, violation);
+
+    // store cut if it is the best found so far
+    if (violation > maxViolation + EPSILON_) {
+      bestCut->copy(cMIR);
+      rhsBestCut = rhscMIR;
+      sCoefBestCut = sCoef;
+      maxViolation = violation;
+      bestDelta = delta;
+    }
+  }
+
+  // improve cMIR for the best delta
+  // complT contains indices into mixedKnapsack for the variables
+  // which may be complemented and they are already appropriately
+  // sorted.
+  const int complTSize = complT->getNumElements();
+  if (complTSize > 0) {
+    const int *complTIndices = complT->getIndices();
+    for (int j = 0; j < complTSize; ++j) {
+      // move variable in set complT from set T to set C
+      int jIndex = complTIndices[j];
+      int indCol = knapsackIndices[jIndex];
+      // do nothing if upper bound is infinity
+      if (colUpperBound[indCol] >= infinity) continue;
+      setC.insert(jIndex,1.0);
+      double violation = 0.0;
+      double sCoef = 0.0;
+      double localNumeratorBeta = numeratorBeta -
+	mixedKnapsack[indCol] * colUpperBound[indCol];
+
+      // form a cMIR inequality
+      cMirInequality(numInt, bestDelta, localNumeratorBeta, knapsackIndices, 
+		     knapsackElements, xlp, sStar, colUpperBound, setC, *cMIR,
+		     rhscMIR, sCoef, violation);
+
+      // store cut if it is the best found so far; otherwise, move the variable
+      // that was added to set C back to set T
+      if (violation > maxViolation + EPSILON_) {
+	bestCut->copy(cMIR);
+	rhsBestCut = rhscMIR;
+	sCoefBestCut = sCoef;
+	maxViolation = violation;
+	numeratorBeta = localNumeratorBeta;
+      }
+      else
+	setC.quickAdd(jIndex,-1.0);
+    }
+  }
+
+  // write the best cut found with the model variables
+  int numCont = contVariablesInS.getNumElements();
+  for ( j = 0; j < numCont; ++j) {
+    int indCol = contVarInSIndices[j];
+    double coefCol = contVarInSElements[indCol];
+      
+    if (indCol < numCols_) {  // variable is model variable
+
+      // Compute lower bound for variable indCol
+      CglMixIntRoundVLB2 VLB = vlbs_[indCol];
+      double LB = ( VLB.getVar() != UNDEFINED_ ) ? 
+	VLB.getVal() * xlp[VLB.getVar()] : colLowerBound[indCol];
+    
+      // Compute upper bound for variable indCol
+      CglMixIntRoundVUB2 VUB = vubs_[indCol];
+      double UB = ( VUB.getVar() != UNDEFINED_ ) ? 
+	VUB.getVal() * xlp[VUB.getVar()] : colUpperBound[indCol];
+
+      // Select the bound substitution
+      if (isLowerSubst(infinity, rowAggregated[indCol],
+			 xlp[indCol], LB, UB)) { 
+	if (VLB.getVar() != UNDEFINED_ ) {
+	  int indVLB = VLB.getVar();
+          bestCut->add(indVLB, - sCoefBestCut * coefCol * VLB.getVal());
+	  bestCut->insert(indCol, sCoefBestCut * coefCol);
+	}
+	else {
+	  rhsBestCut += sCoefBestCut * coefCol * colLowerBound[indCol];
+	  bestCut->insert(indCol, sCoefBestCut * coefCol);
+	}
+      }
+      else {
+	if (VUB.getVar() != UNDEFINED_ ) {
+	  int indVUB = VUB.getVar();
+          bestCut->add(indVUB, sCoefBestCut * coefCol * VUB.getVal());
+	  bestCut->insert(indCol, - sCoefBestCut * coefCol);
+	}
+	else {
+	  rhsBestCut -= sCoefBestCut * coefCol * colUpperBound[indCol];
+	  bestCut->insert(indCol, - sCoefBestCut * coefCol);
+	}
+      }
+    }
+    else {  // variable is slack variable
+      // in this case the LB = 0 and the UB = infinity
+      // copy the row selected to a vector of type CoinIndexedVector
+      const int iRow = listRowsAggregated[indCol - numCols_];
+
+      double multiplier;
+      if (sense[iRow] == 'L') {
+	// if it is a <= inequality, the coefficient of the slack is 1
+	 multiplier = (- sCoefBestCut * coefCol);
+      }
+      else {
+	// if it is a <= inequality, the coefficient of the slack is -1
+	multiplier = (sCoefBestCut * coefCol);
+      }
+      rhsBestCut += RHS[iRow]*multiplier;
+      CoinShallowPackedVector row = matrixByRow.getVector(iRow);
+      int nElements = row.getNumElements();
+      const int * column = row.getIndices();
+      const double * element = row.getElements();
+      for (int i=0;i<nElements;i++) 
+        bestCut->add(column[i],element[i]*multiplier);
+    }
+  }
+
+  // Check the violation of the cut after it is written with the original
+  // variables.
+  int cutLen = bestCut->getNumElements();
+  int* cutInd = bestCut->getIndices();
+  double* cutCoef = bestCut->denseVector();
+  double cutRHS = rhsBestCut;
+  double violation = 0.0;
+  double normCut = 0.0;
+  //double smallest=COIN_DBL_MAX;
+  double largest=0.0;
+  // Also weaken by small coefficients
+  for ( j = 0; j < cutLen; ++j) {
+    int column = cutInd[j];
+    double value = cutCoef[column];
+    //smallest=CoinMin(smallest,fabs(value));
+    largest=CoinMax(largest,fabs(value));
+    //normCut += value * value;
+  }
+  //normCut=sqrt(normCut);
+  //printf("smallest %g largest %g norm %g\n",
+  //	 smallest,largest,normCut);
+  double testValue=CoinMax(1.0e-6*largest,1.0e-12);
+  //normCut=0.0;
+  int n=0;
+  for ( j = 0; j < cutLen; ++j) {
+    int column = cutInd[j];
+    double value = cutCoef[column];
+    if (fabs(value)>testValue) {
+      violation += value * xlp[column];
+      normCut += value * value;
+      cutInd[n++]=column;
+    } else if (value) {
+      cutCoef[column]=0.0;
+      // Weaken
+      if (value>0.0) {
+        // Allow for at lower bound
+        cutRHS -= value*colLowerBound[column];
+      } else {
+        // Allow for at upper bound
+        cutRHS -= value*colUpperBound[column];
+      }
+    }
+  }
+  cutLen=n;
+  violation -= cutRHS;
+  violation /= sqrt(normCut);
+
+  if ( violation > TOLERANCE_ ) {
+    // cutCoef is still unpacked
+    std::sort(cutInd,cutInd+cutLen);
+    int i;
+    for ( i=0;i<cutLen;i++) {
+      int column=cutInd[i];
+      assert (cutCoef[column]);
+      double value = cutCoef[column];
+      cutCoef[column] =0.0;
+      cutCoef[i]=value;
+    }
+    cMirCut.setRow(cutLen, cutInd, cutCoef);
+    cMirCut.setLb(-1.0 * infinity);
+    cMirCut.setUb(cutRHS);
+    cMirCut.setEffectiveness(violation);
+#ifdef CGL_DEBUG
+    {
+      for (int k=0; k<cutLen; k++){
+	assert(cutInd[k]>=0);
+	assert(cutCoef[k]);
+        assert (fabs(cutCoef[k])>1.0e-12);
+      }
+    }
+#endif
+    // Zero bestCut by hand
+    bestCut->setNumElements(0);
+    for ( i=0;i<cutLen;i++) {
+      cutCoef[i]=0.0;
+    }
+    generated = true;
+  } else {
+    // just clear
+    bestCut->clear();
+  }
+
+  return generated;
+
+}
+
+//-------------------------------------------------------------------
+// construct a c-MIR inequality
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding2::cMirInequality(
+				  const int numInt, 
+				  const double delta,
+				  const double numeratorBeta,
+				  const int *knapsackIndices,
+				  const double* knapsackElements,
+				  const double* xlp, 
+				  const double sStar,	       
+				  const double* colUpperBound,
+				  const CoinIndexedVector& setC,
+				  CoinIndexedVector& cMIR,
+				  double& rhscMIR,
+				  double& sCoef,
+				  double& violation) const
+{
+
+      // form a cMIR inequality
+      double beta = numeratorBeta / delta;
+      double f = beta - floor(beta);
+      rhscMIR = floor(beta);
+      double normCut = 0.0;
+      // coefficients of variables in set T
+      for (int i = 0; i < numInt; ++i) {
+	const int iIndex = knapsackIndices[i];
+	double G = 0.0;
+	if (setC.denseVector()[i] != 1.0) {
+	  // i is not in setC, i.e., it is in T
+	  G = functionG(knapsackElements[iIndex] / delta, f);
+	  violation += (G * xlp[iIndex]);
+	  normCut += G * G;
+	  cMIR.setElement(i, G);
+	} else {
+	  G = functionG( - knapsackElements[iIndex] / delta, f);
+	  violation -= (G * xlp[iIndex]);
+	  normCut += G * G;
+	  rhscMIR -= G * colUpperBound[iIndex];
+	  cMIR.setElement(i, -G);	  
+	}
+      }
+      sCoef = 1.0 / (delta * (1.0 - f));
+      violation -= (rhscMIR + sCoef * sStar);
+      normCut += sCoef * sCoef;
+      violation /= sqrt(normCut);
+
+}
+
+
+//-------------------------------------------------------------------
+// function G for computing coefficients in cMIR inequality
+//-------------------------------------------------------------------
+inline double
+CglMixedIntegerRounding2::functionG( const double d, const double f ) const
+{
+  double delta = d - floor(d) - f;
+  if (delta > EPSILON_)
+    return floor(d) + delta / (1 - f);
+  else
+    return floor(d);
+}
+
+//-------------------------------------------------------------------
+// Printing statistics
+//-------------------------------------------------------------------
+void
+CglMixedIntegerRounding2::printStats(
+			    std::ofstream & fout,
+			    const bool hasCut,
+			    const OsiSolverInterface& si,
+			    const CoinIndexedVector& rowAggregated,
+			    const double& rhsAggregated, const double* xlp,
+			    const double* xlpExtra,
+			    const int* listRowsAggregated,
+			    const int* listColsSelected,
+			    const int level,
+			    const double* colUpperBound,
+			    const double* colLowerBound ) const
+{
+
+
+  const int numColsAggregated = rowAggregated.getNumElements();
+  const int *rowAggregatedIndices = rowAggregated.getIndices();
+  const double *rowAggregatedElements = rowAggregated.denseVector();  
+
+  fout << "Rows ";
+  for (int i = 0; i < level; ++i) {
+    fout << listRowsAggregated[i] << " ";
+  }
+  fout << std::endl;
+
+  int numColsBack = 0;
+
+  // go through all the variables 
+  for (int j = 0; j < numColsAggregated; ++j) {
+
+    // get index and coefficient of column j in the aggregated row
+    int indCol = rowAggregatedIndices[j];
+    double coefCol = rowAggregatedElements[indCol];
+
+    // check if a column used in aggregation is back into the aggregated row
+    for (int i = 0; i < level-1; ++i) {
+      if ( (listColsSelected[i] == indCol) && (coefCol != 0) ) {
+	numColsBack++;
+	break;
+      }
+    }
+
+
+
+    if (fabs(coefCol) < EPSILON_) {
+      // print variable number and coefficient
+      fout << indCol << " " << 0.0 << std::endl;
+      continue;
+    }
+    else {
+      // print variable number and coefficient
+      fout << indCol << " " << coefCol << " ";
+    }
+
+    // integer variables
+    if ( (indCol < numCols_)  && (integerType_[indCol]) ) {
+
+      // print 
+      fout << "I " << xlp[indCol] << " " << colLowerBound[indCol] <<
+	" " << colUpperBound[indCol] << std::endl;
+
+      continue;
+    }
+
+    // continuous variables 
+    if (indCol < numCols_) {  // variable is model variable
+
+      // print
+      fout << "C " << xlp[indCol] << " " << colLowerBound[indCol] <<
+	" " << colUpperBound[indCol] << " ";
+
+      // variable lower bound?
+      CglMixIntRoundVLB2 VLB = vlbs_[indCol];
+      if (VLB.getVar() != UNDEFINED_) {
+	fout << VLB.getVal() << " " << xlp[VLB.getVar()] << " " <<
+	  colLowerBound[VLB.getVar()] << " " <<
+	  colUpperBound[VLB.getVar()] << " ";
+      }
+      else {
+	fout << "-1 -1 -1 -1 ";
+      }
+
+      // variable upper bound?
+      CglMixIntRoundVUB2 VUB = vubs_[indCol];
+      if (VUB.getVar() != UNDEFINED_) {
+	fout << VUB.getVal() << " " << xlp[VUB.getVar()] << " " <<
+	  colLowerBound[VUB.getVar()] << " " <<
+	  colUpperBound[VUB.getVar()] << " ";
+      }
+      else {
+	fout << "-1 -1 -1 -1 ";
+      }
+
+    }	  
+    else {  // variable is slack variable
+      // in this case the LB = 0 and the UB = infinity
+      // print
+      fout << "C " << xlpExtra[indCol-numCols_] << " " << 0.0 <<
+	" " << si.getInfinity() << " ";
+    }
+
+    fout << std::endl;
+
+  }
+
+  fout << "rhs " << rhsAggregated << std::endl;
+
+  fout << "numColsBack " << numColsBack << std::endl;
+
+  if (hasCut) {
+    fout << "CUT: YES" << std::endl;
+  }
+  else {
+    fout << "CUT: NO" << std::endl;
+  }
+
+}
+// This can be used to refresh any inforamtion
+void 
+CglMixedIntegerRounding2::refreshSolver(OsiSolverInterface * solver)
+{
+  if (solver->getNumRows()) {
+    mixIntRoundPreprocess(*solver);
+    doneInitPre_ = true;
+  } else {
+    doneInitPre_ = false;
+  }
+}
+// Create C++ lines to get to current state
+std::string
+CglMixedIntegerRounding2::generateCpp( FILE * fp) 
+{
+  CglMixedIntegerRounding2 other;
+  fprintf(fp,"0#include \"CglMixedIntegerRounding2.hpp\"\n");
+  fprintf(fp,"3  CglMixedIntegerRounding2 mixedIntegerRounding2;\n");
+  if (MAXAGGR_!=other.MAXAGGR_)
+    fprintf(fp,"3  mixedIntegerRounding2.setMAXAGGR_(%d);\n",MAXAGGR_);
+  else
+    fprintf(fp,"4  mixedIntegerRounding2.setMAXAGGR_(%d);\n",MAXAGGR_);
+  if (MULTIPLY_!=other.MULTIPLY_)
+    fprintf(fp,"3  mixedIntegerRounding2.setMULTIPLY_(%d);\n",MULTIPLY_);
+  else
+    fprintf(fp,"4  mixedIntegerRounding2.setMULTIPLY_(%d);\n",MULTIPLY_);
+  if (CRITERION_!=other.CRITERION_)
+  fprintf(fp,"3  mixedIntegerRounding2.setCRITERION_(%d);\n",CRITERION_);
+  if (doPreproc_!=other.doPreproc_)
+    fprintf(fp,"3  mixedIntegerRounding2.setDoPreproc_(%d);\n", doPreproc_);
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  mixedIntegerRounding2.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  mixedIntegerRounding2.setAggressiveness(%d);\n",getAggressiveness());
+  return "mixedIntegerRounding2";
+}
+void CglMixedIntegerRounding2::setDoPreproc(int value)
+{
+  if (value != -1 && value != 0 && value != 1) {
+    throw CoinError("setDoPrepoc", "invalid value",
+		    "CglMixedIntegerRounding2");
+  }
+  else {
+    doPreproc_ = value;
+  }  
+}
+
+bool CglMixedIntegerRounding2::getDoPreproc() const
+{
+  return (doPreproc_!=0);
+}
diff --git a/cbits/coin/CglMixedIntegerRounding2.hpp b/cbits/coin/CglMixedIntegerRounding2.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglMixedIntegerRounding2.hpp
@@ -0,0 +1,427 @@
+// LAST EDIT: 
+//-----------------------------------------------------------------------------
+// name: Mixed Integer Rounding Cut Generator
+// authors: Joao Goncalves (jog7@lehigh.edu) 
+//          Laszlo Ladanyi (ladanyi@us.ibm.com) 
+// date: August 11, 2004 
+//-----------------------------------------------------------------------------
+// Copyright (C) 2004, International Business Machines Corporation and others. 
+// All Rights Reserved.
+// This code is published under the Eclipse Public License.
+
+#ifndef CglMixedIntegerRounding2_H
+#define CglMixedIntegerRounding2_H
+
+#include <iostream>
+#include <fstream>
+//#include <vector>
+
+#include "CoinError.hpp"
+
+#include "CglCutGenerator.hpp"
+#include "CoinIndexedVector.hpp"
+
+//=============================================================================
+
+#ifndef CGL_DEBUG
+#define CGL_DEBUG 0
+#endif
+
+//=============================================================================
+
+// Class to store variable upper bounds (VUB)
+class CglMixIntRoundVUB2
+{
+  // Variable upper bounds have the form x_j <= a y_j, where x_j is
+  // a continuous variable and y_j is an integer variable
+
+protected:
+  int    var_;            // The index of y_j
+  double val_;            // The value of a 
+
+public:
+  // Default constructor
+  CglMixIntRoundVUB2() : var_(-1), val_(-1) {}
+
+  // Copy constructor
+  CglMixIntRoundVUB2(const CglMixIntRoundVUB2& source) { 
+    var_ = source.var_; 
+    val_ = source.val_; 
+  } 
+
+  // Assignment operator
+  CglMixIntRoundVUB2& operator=(const CglMixIntRoundVUB2& rhs) { 
+    if (this != &rhs) { 
+      var_ = rhs.var_; 
+      val_ = rhs.val_; 
+    }
+    return *this; 
+  }
+
+  // Destructor
+  ~CglMixIntRoundVUB2() {}
+
+  // Query and set functions
+  int    getVar() const          { return var_; }
+  double getVal() const          { return val_; }
+  void   setVar(const int v)     { var_ = v; }
+  void   setVal(const double v)  { val_ = v; }
+};
+
+//=============================================================================
+
+// Class to store variable lower bounds (VLB).
+// It is the same as the class to store variable upper bounds
+typedef CglMixIntRoundVUB2 CglMixIntRoundVLB2;
+
+//=============================================================================
+
+/** Mixed Integer Rounding Cut Generator Class */
+
+// Reference: 
+//    Hugues Marchand and Laurence A. Wolsey
+//    Aggregation and Mixed Integer Rounding to Solve MIPs
+//    Operations Research, 49(3), May-June 2001.
+//    Also published as CORE Dicusion Paper 9839, June 1998.
+
+class CglMixedIntegerRounding2 : public CglCutGenerator {
+
+  friend void CglMixedIntegerRounding2UnitTest(const OsiSolverInterface * siP,
+					       const std::string mpdDir);
+
+
+private:
+  //---------------------------------------------------------------------------
+  // Enumeration constants that describe the various types of rows
+  enum RowType {
+    // The row type of this row is NOT defined yet.
+    ROW_UNDEFINED,
+    /** After the row is flipped to 'L', the row has exactly two variables: 
+	one is negative binary and the other is a continous, 
+	and the RHS is zero.*/
+    ROW_VARUB,
+    /** After the row is flipped to 'L', the row has exactly two variables: 
+	one is positive binary and the other is a continous, 
+	and the RHS is zero.*/
+    ROW_VARLB,
+    /** The row sense is 'E', the row has exactly two variables: 
+	one is binary and the other is a continous, and the RHS is zero.*/ 
+    ROW_VAREQ,
+    // The row contains continuous and integer variables;
+    // the total number of variables is at least 2
+    ROW_MIX,
+    // The row contains only continuous variables
+    ROW_CONT,
+    // The row contains only integer variables
+    ROW_INT,
+    // The row contains other types of rows
+    ROW_OTHER
+  };
+
+
+public:
+
+  /**@name Generate Cuts */
+  //@{
+  /** Generate Mixed Integer Rounding cuts for the model data 
+      contained in si. The generated cuts are inserted 
+      in the collection of cuts cs. 
+  */
+  virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			    const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglMixedIntegerRounding2 ();
+
+  /// Alternate Constructor 
+  CglMixedIntegerRounding2 (const int maxaggr,
+			    const bool multiply,
+			    const int criterion,
+			    const int preproc = -1);
+
+  /// Copy constructor 
+  CglMixedIntegerRounding2 (
+    const CglMixedIntegerRounding2 &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglMixedIntegerRounding2 &
+    operator=(
+    const CglMixedIntegerRounding2& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglMixedIntegerRounding2 ();
+  /// This can be used to refresh any inforamtion
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Set and get methods */
+  //@{
+  /// Set MAXAGGR_
+  inline void setMAXAGGR_ (int maxaggr) {
+    if (maxaggr > 0) {
+      MAXAGGR_ = maxaggr;
+    }
+    else {
+      throw CoinError("Unallowable value. maxaggr must be > 0",
+                      "gutsOfConstruct","CglMixedIntegerRounding2");
+    }
+  }
+
+  /// Get MAXAGGR_
+  inline int getMAXAGGR_ () const { return MAXAGGR_; }
+
+  /// Set MULTIPLY_
+  inline void setMULTIPLY_ (bool multiply) { MULTIPLY_ = multiply; }
+
+  /// Get MULTIPLY_
+  inline bool getMULTIPLY_ () const { return MULTIPLY_; }
+
+  /// Set CRITERION_
+  inline void setCRITERION_ (int criterion) {
+    if ((criterion >= 1) && (criterion <= 3)) {
+      CRITERION_ = criterion;
+    }
+    else {
+      throw CoinError("Unallowable value. criterion must be 1, 2 or 3",
+                      "gutsOfConstruct","CglMixedIntegerRounding2");
+    }
+  }
+
+  /// Get CRITERION_
+  inline int getCRITERION_ () const { return CRITERION_; }
+
+  /// Set doPreproc
+  void setDoPreproc(int value);
+  /// Get doPreproc
+  bool getDoPreproc() const;
+  //@}
+
+private:
+  //--------------------------------------------------------------------------
+  // Private member methods
+
+  // Construct
+  void gutsOfConstruct ( const int maxaggr,
+			 const bool multiply,
+			 const int criterion,
+			 const int preproc);
+
+  // Delete
+  void gutsOfDelete();
+
+  // Copy
+  void gutsOfCopy (const CglMixedIntegerRounding2& rhs);
+
+  // Do preprocessing.
+  // It determines the type of each row. It also identifies the variable
+  // upper bounds and variable lower bounds.
+  // It may change sense and RHS for ranged rows
+  void mixIntRoundPreprocess(const OsiSolverInterface& si);
+
+  // Determine the type of a given row.
+  RowType determineRowType(//const OsiSolverInterface& si,
+			   const int rowLen, const int* ind, 
+			   const double* coef, const char sense, 
+			   const double rhs) const;
+
+  // Generate MIR cuts
+  void generateMirCuts( const OsiSolverInterface& si,
+			const double* xlp,
+			const double* colUpperBound,
+			const double* colLowerBound,
+			const CoinPackedMatrix& matrixByRow,
+			const double* LHS,
+			//const double* coefByRow,
+			//const int* colInds,
+			//const int* rowStarts,
+			//const CoinPackedMatrix& matrixByCol,
+			const double* coefByCol,
+			const int* rowInds,
+			const int* colStarts,
+			OsiCuts& cs ) const;
+
+  // Copy row selected to CoinIndexedVector
+  void copyRowSelected( const int iAggregate,
+			const int rowSelected,
+			CoinIndexedVector& setRowsAggregated,
+			int* listRowsAggregated,
+			double* xlpExtra,
+			const char sen,
+			const double rhs,
+			const double lhs,
+			const CoinPackedMatrix& matrixByRow,
+			CoinIndexedVector& rowToAggregate,
+			double& rhsToAggregate) const;
+
+  // Select a row to aggregate
+  bool selectRowToAggregate( //const OsiSolverInterface& si,
+			     const CoinIndexedVector& rowAggregated,
+			     const double* colUpperBound,
+			     const double* colLowerBound,
+			     const CoinIndexedVector& setRowsAggregated,
+			     const double* xlp, const double* coefByCol,
+			     const int* rowInds, const int* colStarts,
+			     int& rowSelected,
+			     int& colSelected ) const;
+
+  // Aggregation heuristic. 
+  // Combines one or more rows of the original matrix 
+  void aggregateRow( const int colSelected,
+		     CoinIndexedVector& rowToAggregate, double rhs,
+		     CoinIndexedVector& rowAggregated, 
+		     double& rhsAggregated ) const;
+
+  // Choose the bound substitution based on the criteria defined by the user
+  inline bool isLowerSubst(const double inf, 
+			   const double aj,
+			   const double xlp, 
+			   const double LB, 
+			   const double UB) const;
+    
+  // Bound substitution heuristic
+  bool boundSubstitution( const OsiSolverInterface& si,
+			  const CoinIndexedVector& rowAggregated,
+			  const double* xlp,
+			  const double* xlpExtra,
+			  const double* colUpperBound,
+			  const double* colLowerBound,
+			  CoinIndexedVector& mixedKnapsack,
+			  double& rhsMixedKnapsack, double& sStar,
+			  CoinIndexedVector& contVariablesInS ) const;
+
+  // c-MIR separation heuristic
+  bool cMirSeparation ( const OsiSolverInterface& si,
+			const CoinPackedMatrix& matrixByRow,
+			const CoinIndexedVector& rowAggregated,
+			const int* listRowsAggregated,
+			const char* sense, const double* RHS,
+			//const double* coefByRow,
+			//const int* colInds, const int* rowStarts,
+			const double* xlp, const double sStar,
+			const double* colUpperBound,
+			const double* colLowerBound,
+			const CoinIndexedVector& mixedKnapsack,
+			const double& rhsMixedKnapsack,
+			const CoinIndexedVector& contVariablesInS,
+                        CoinIndexedVector * workVector,
+			OsiRowCut& flowCut ) const;
+
+  // function to create one c-MIR inequality
+  void cMirInequality( const int numInt, 
+		       const double delta,
+		       const double numeratorBeta,
+		       const int *knapsackIndices,
+		       const double* knapsackElements,
+		       const double* xlp, 
+		       const double sStar,	       
+		       const double* colUpperBound,
+		       const CoinIndexedVector& setC,
+		       CoinIndexedVector& cMIR,
+		       double& rhscMIR,
+		       double& sCoef,
+		       double& violation) const;
+
+  // function to compute G
+  inline double functionG( const double d, const double f ) const;
+
+  // function to print statistics (used only in debug mode)
+  void printStats(
+			    std::ofstream & fout,
+			    const bool hasCut,
+			    const OsiSolverInterface& si,
+			    const CoinIndexedVector& rowAggregated,
+			    const double& rhsAggregated, const double* xlp,
+			    const double* xlpExtra,
+			    const int* listRowsAggregated,
+			    const int* listColsSelected,
+			    const int level,
+			    const double* colUpperBound,
+			    const double* colLowerBound ) const;
+
+
+private:
+  //---------------------------------------------------------------------------
+  // Private member data
+  
+  // Maximum number of rows to aggregate
+  int MAXAGGR_;
+  // Flag that indicates if an aggregated row is also multiplied by -1
+  bool MULTIPLY_;
+  // The criterion to use in the bound substitution
+  int CRITERION_;
+  // Tolerance used for numerical purposes
+  double EPSILON_;
+  /// There is no variable upper bound or variable lower bound defined
+  int UNDEFINED_;
+  // If violation of a cut is greater that this number, the cut is accepted
+  double TOLERANCE_;
+  /** Controls the preprocessing of the matrix to identify rows suitable for
+      cut generation.<UL>
+      <LI> -1: preprocess according to solver settings;
+      <LI> 0: Do preprocessing only if it has not yet been done;
+      <LI> 1: Do preprocessing.
+      </UL>
+      Default value: -1 **/
+  int doPreproc_;
+  // The number of rows of the problem.
+  int numRows_;
+  // The number columns of the problem.
+  int numCols_;
+  // Indicates whether preprocessing has been done.
+  bool doneInitPre_;
+  // The array of CglMixIntRoundVUB2s.
+  CglMixIntRoundVUB2* vubs_;
+  // The array of CglMixIntRoundVLB2s.
+  CglMixIntRoundVLB2* vlbs_;
+  // Array with the row types of the rows in the model.
+  RowType* rowTypes_;
+  // The indices of the rows of the initial matrix
+  int* indRows_;
+  // The number of rows of type ROW_MIX
+  int numRowMix_;
+  // The indices of the rows of type ROW_MIX
+  int* indRowMix_;
+  // The number of rows of type ROW_CONT
+  int numRowCont_;
+  // The indices of the rows of type ROW_CONT
+  int* indRowCont_;
+  // The number of rows of type ROW_INT
+  int numRowInt_;
+  // The indices of the rows of type ROW_INT
+  int* indRowInt_;
+  // The number of rows of type ROW_CONT that have at least one variable
+  // with variable upper or lower bound
+  int numRowContVB_;
+  // The indices of the rows of type ROW_CONT that have at least one variable
+  // with variable upper or lower bound
+  int* indRowContVB_;
+  // If integer - for speed
+  char * integerType_;
+  // Sense of rows (modified if ranges)
+  char * sense_;
+  // RHS of rows (modified if ranges)
+  double * RHS_;
+  
+};
+
+//#############################################################################
+// A function that tests the methods in the CglMixedIntegerRounding2 class. The
+// only reason for it not to be a member method is that this way it doesn't
+// have to be compiled into the library. And that's a gain, because the
+// library should be compiled with optimization on, but this method should be
+// compiled with debugging.
+void CglMixedIntegerRounding2UnitTest(const OsiSolverInterface * siP,
+				      const std::string mpdDir);
+  
+#endif
diff --git a/cbits/coin/CglOddHole.cpp b/cbits/coin/CglOddHole.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglOddHole.cpp
@@ -0,0 +1,842 @@
+// $Id: CglOddHole.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CglOddHole.hpp"
+//#define CGL_DEBUG
+// We may want to sort cut
+typedef struct {double dj;double element; int sequence;} 
+double_double_int_triple;
+class double_double_int_triple_compare {
+public:
+  bool operator() (double_double_int_triple x , double_double_int_triple y) const
+  {
+    return ( x.dj < y.dj);
+  }
+}; 
+//-------------------------------------------------------------------------------
+// Generate three cycle cuts
+//------------------------------------------------------------------- 
+void CglOddHole::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			      const CglTreeInfo info)
+{
+  // Get basic problem information
+  int nRows=si.getNumRows(); 
+  int nCols=si.getNumCols(); 
+  
+  const CoinPackedMatrix * rowCopy = si.getMatrixByRow();
+
+  // Could do cliques and extra OSL cliques
+  // For moment just easy ones
+  
+  // If no information exists then get a list of suitable rows
+  // If it does then suitable rows are subset of information
+  
+  CglOddHole temp;
+  int * checkRow = new int[nRows];
+  int i;
+  if (!suitableRows_) {
+    for (i=0;i<nRows;i++) {
+      checkRow[i]=1;
+    }
+  } else {
+    // initialize and extend rows to current size
+    memset(checkRow,0,nRows*sizeof(int));
+    memcpy(checkRow,suitableRows_,CoinMin(nRows,numberRows_)*sizeof(int));
+  }
+  temp.createRowList(si,checkRow);
+  // now cut down further by only allowing rows with fractional solution
+  double * solution = new double[nCols];
+  memcpy(solution,si.getColSolution(),nCols*sizeof(double));
+  const int * column = rowCopy->getIndices();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const int * rowLength = rowCopy->getVectorLengths(); 
+  const double * collower = si.getColLower();
+  const double * colupper = si.getColUpper();
+  int * suitable = temp.suitableRows_;
+
+  // At present I am using new and delete as easier to see arrays in debugger
+  int * fixed = new int[nCols]; // mark fixed columns 
+
+  for (i=0;i<nCols;i++) {
+    if (si.isBinary(i) ) {
+      fixed[i]=0;
+      if (colupper[i]-collower[i]<epsilon_) {
+	solution[i]=0.0;
+	fixed[i]=2;
+      } else if (solution[i]<epsilon_) {
+	solution[i]=0.0;
+	fixed[i]=-1;
+      } else if (solution[i]>onetol_) {
+	solution[i]=1.0;
+	fixed[i]=+1;
+      }
+    } else {
+      //mark as fixed even if not (can not intersect any interesting rows)
+      solution[i]=0.0;
+      fixed[i]=3;
+    }
+  }
+  // first do packed
+  const double * rowlower = si.getRowLower();
+  const double * rowupper = si.getRowUpper();
+  for (i=0;i<nRows;i++) {
+    if (suitable[i]) {
+      int k;
+      double sum=0.0;
+      if (rowupper[i]>1.001) suitable[i]=-1;
+      for (k=rowStart[i]; k<rowStart[i]+rowLength[i];k++) {
+	int icol=column[k];
+	if (!fixed[icol]) sum += solution[icol];
+      }
+      if (sum<0.9) suitable[i]=-1; //say no good
+    }
+  }
+#ifdef CGL_DEBUG
+  const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+  if (debugger&&!debugger->onOptimalPath(si))
+    debugger = NULL;
+#else
+  const OsiRowCutDebugger * debugger = NULL;
+#endif
+  temp.generateCuts(debugger, *rowCopy,solution,
+		    si.getReducedCost(),cs,suitable,fixed,info,true);
+  // now cover
+  //if no >= then skip
+  bool doCover=false;
+  int nsuitable=0;
+  for (i=0;i<nRows;i++) {
+    suitable[i]=abs(suitable[i]);
+    if (suitable[i]) {
+      int k;
+      double sum=0.0;
+      if (rowlower[i]<0.999) sum=2.0;
+      if (rowupper[i]>1.001) doCover=true;
+      for (k=rowStart[i]; k<rowStart[i]+rowLength[i];k++) {
+	int icol=column[k];
+	if (!fixed[icol]) sum += solution[icol];
+	if (fixed[icol]==1) sum=2.0; //don't use if any at 1
+      }
+      if (sum>1.1) {
+	suitable[i]=-1; //say no good
+      } else {
+	nsuitable++;
+      }
+    }
+  }
+  if (doCover&&nsuitable) 
+    temp.generateCuts(debugger, *rowCopy,solution,si.getReducedCost(),
+		      cs,suitable,fixed,info,false);
+  delete [] checkRow;
+  delete [] solution;
+  delete [] fixed;
+    
+}
+void CglOddHole::generateCuts(const OsiRowCutDebugger * /*debugger*/,
+			      const CoinPackedMatrix & rowCopy, 
+				 const double * solution, 
+			      const double * dj, OsiCuts & cs,
+				 const int * suitableRow,
+			      const int * fixedColumn,
+			      const CglTreeInfo info,
+			      bool packed)
+{
+  CoinPackedMatrix columnCopy = rowCopy;
+  columnCopy.reverseOrdering();
+
+  // Get basic problem information
+  int nRows=columnCopy.getNumRows(); 
+  int nCols=columnCopy.getNumCols(); 
+  
+  const int * column = rowCopy.getIndices();
+  const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+  const int * rowLength = rowCopy.getVectorLengths(); 
+  
+  const int * row = columnCopy.getIndices();
+  const CoinBigIndex * columnStart = columnCopy.getVectorStarts();
+  const int * columnLength = columnCopy.getVectorLengths(); 
+
+  // we need only look at suitable rows and variables with unsatisfied 0-1
+  // lookup from true row to compressed matrix
+  int * mrow = new int[nRows];
+  // lookup from true column to compressed
+  int * lookup = new int[nCols];
+  // number of columns in compressed matrix
+  int nSmall=0;
+  int i;
+  //do lookup from true sequence to compressed
+  int n=0;
+  for (i=0;i<nRows;i++) {
+    if (suitableRow[i]>0) {
+      mrow[i]=n++;
+    } else {
+      mrow[i]=-1;
+    }
+  }
+  for (i=0;i<nCols;i++) {
+    if (!fixedColumn[i]) {
+      lookup[i]=nSmall++;
+    } else {
+      lookup[i]=-1;
+    }
+  }
+  int nSmall2=2*nSmall;
+  // we don't know how big matrix will be
+#define MAXELS 50000
+  int maxels=MAXELS;
+  //How do I do reallocs in C++?
+  // 1.0 - value x(i) - value x(j) for each node pair (or reverse if cover) 
+  double * cost = reinterpret_cast<double *> (malloc(maxels*sizeof(double)));
+  // arc i.e. j which can be reached from i
+  int * to= reinterpret_cast<int *> (malloc(maxels*sizeof(int)));
+  //original row for each arc
+  int * rowfound=reinterpret_cast<int *> (malloc(maxels*sizeof(int)));
+  // start of each column
+  int * starts=new int[2*nSmall+1];
+  starts[0]=0;
+  // useful array for marking if already connected
+  int * mark =new int[nSmall2];
+  memset(mark,0,nSmall2*sizeof(int));
+  n=0; //number of elements in matrix
+  for (i=0;i<nCols;i++) {
+    int icol=lookup[i];
+    if (icol>=0) {
+      // column in compressed matrix
+      int k;
+      double dd=1.0000001-solution[i];
+      mark[icol]=1;
+      // reallocate if matrix reached size limit
+      if (n+nCols>maxels) {
+	maxels*=2;
+	cost=reinterpret_cast<double *> (realloc(cost,maxels*sizeof(double)));
+	to=reinterpret_cast<int *> (realloc(to,maxels*sizeof(int)));
+	rowfound=reinterpret_cast<int *> (realloc(rowfound,maxels*sizeof(int)));
+      }
+      // get all other connected variables
+      for (k=columnStart[i];k<columnStart[i]+columnLength[i];k++) {
+	int irow=row[k];
+	int jrow=mrow[irow];
+	// but only if row in compressed matrix
+	if (jrow>=0) {
+	  int j;
+	  for (j=rowStart[irow];j<rowStart[irow]+rowLength[irow];j++) {
+	    int jcol=column[j];
+	    int kcol=lookup[jcol];
+	    if (kcol>=0&&!mark[kcol]) {
+	      cost[n]=dd-solution[jcol];
+	      to[n]=kcol;
+	      rowfound[n++]=irow;//original row
+	      mark[kcol]=1;
+	    }
+	  }
+	}
+      }
+      starts[icol+1]=n;
+      // zero out markers for next column
+      mark[icol]=0;
+      for (k=starts[icol];k<starts[icol+1];k++) {
+	int ito=to[k];
+	if (ito<0||ito>=nSmall) abort();
+	mark[to[k]]=0;
+      }
+    }
+  }
+  //if cover then change sign - otherwise make sure positive
+  if (packed) {
+    for (i=0;i<n;i++) {
+      if (cost[i]<1.0e-10) {
+	cost[i]=1.0e-10;
+      }
+    }
+  } else {
+    for (i=0;i<n;i++) {
+      cost[i]=-cost[i];
+      if (cost[i]<1.0e-10) {
+	cost[i]=1.0e-10;
+      }
+    }
+  }
+  // we are going to double size 
+
+  if (2*n>maxels) {
+    maxels=2*n;
+    cost=reinterpret_cast<double *> (realloc(cost,maxels*sizeof(double)));
+    to=reinterpret_cast<int *> (realloc(to,maxels*sizeof(int)));
+    rowfound=reinterpret_cast<int *> (realloc(rowfound,maxels*sizeof(int)));
+  }
+  /* copy and make bipartite*/
+
+  for (i=0;i<nSmall;i++) {
+    int k,j=i+nSmall;
+    for (k=starts[i];k<starts[i+1];k++) {
+      int ito=to[k];
+      to[n]=ito;
+      to[k]=ito+nSmall;
+      cost[n]=cost[k];
+      rowfound[n++]=rowfound[k];;
+    }
+    starts[j+1]=n;
+  }
+  //random numbers to winnow out duplicate cuts
+  double * check = new double[nCols];
+  if (info.randomNumberGenerator) {
+    const CoinThreadRandom * randomGenerator = info.randomNumberGenerator;
+    for (i=0;i<nCols;i++) {
+      check[i]=randomGenerator->randomDouble();
+    }
+  } else {
+    CoinSeedRandom(13579);
+    for (i=0;i<nCols;i++) {
+      check[i]=CoinDrand48(); // NOT on a thread by thread basis
+    }
+  }
+
+  // Shortest path algorithm from Dijkstra - is there a better one?
+
+  typedef struct {
+    double cost; //cost to starting node
+    int back; //previous node
+  } Path;
+  typedef struct {
+    double cost; //cost to starting node
+    int node; //node
+  } Item;
+  Item * stack = new Item [nSmall2];
+  Path * path = new Path [nSmall2];
+  // arrays below are used only if looks promising
+  // allocate here
+  // we don't know how many cuts will be generated
+  int ncuts=0;
+  int maxcuts=1000;
+  double * hash = reinterpret_cast<double *> (malloc(maxcuts*sizeof(double)));
+  // to clean (should not be needed)
+  int * clean = new int[nSmall2];
+  int * candidate = new int[CoinMax(nSmall2,nCols)];
+  double * element = new double[nCols];
+  // in case we want to sort
+  double_double_int_triple * sortit = 
+    new double_double_int_triple [nCols];
+  memset(mark,0,nSmall2*sizeof(int));
+  int * countcol = new int[nCols];
+  memset(countcol,0,nCols*sizeof(int));
+  int bias = packed ? 0 : 1; //amount to add before halving
+  // If nSmall large then should do a randomized subset
+  // Improvement 1
+  int icol;
+  for (icol=0;icol<nSmall;icol++) {
+    int j;
+    int jcol=icol+nSmall;
+    int istack=1;
+    for (j=0;j<nSmall2;j++) {
+      path[j].cost=1.0e70;
+      path[j].back=nSmall2+1;
+    }
+    path[icol].cost=0.0;
+    path[icol].back=-1;
+    stack[0].cost=0.0;
+    stack[0].node=icol;
+    mark[icol]=1;
+    while(istack) {
+      Item thisItem=stack[--istack];
+      double thisCost=thisItem.cost;
+      int inode=thisItem.node;
+      int k;
+      mark[inode]=0; //say available for further work
+      // See if sorting every so many would help (and which way)?
+      // Improvement 2
+      for (k=starts[inode];k<starts[inode+1];k++) {
+	int jnode=to[k];
+	if (!mark[jnode]&&thisCost+cost[k]<path[jnode].cost-1.0e-12) {
+	  path[jnode].cost=thisCost+cost[k];
+	  path[jnode].back=inode;
+	  // add to stack
+	  stack[istack].cost=path[jnode].cost;
+	  stack[istack++].node=jnode;
+	  mark[jnode]=1;
+#ifdef CGL_DEBUG
+	  assert (istack<=nSmall2);
+#endif
+	}
+      }
+    }
+    bool good=(path[jcol].cost<0.9999);
+
+    if (good)  { /* try */
+      int ii;
+      int nrow2=0;
+      int nclean=0;
+      double sum=0;
+#ifdef CGL_DEBUG
+      printf("** %d ",jcol-nSmall);
+#endif
+      ii=1;
+      candidate[0]=jcol;
+      while(jcol!=icol) {
+	int jjcol;
+	jcol=path[jcol].back;
+	if (jcol>=nSmall) {
+	  jjcol=jcol-nSmall;
+	} else {
+	  jjcol=jcol;
+	}
+#ifdef CGL_DEBUG
+	printf(" %d",jjcol);
+#endif
+	if (mark[jjcol]) {
+	  // good=false;
+	  // probably means this is from another cycle (will have been found)
+	  // one of cycles must be zero cost
+	  // printf("variable already on chain!\n");
+	} else {
+	  mark[jjcol]=1;
+	  clean[nclean++]=jjcol;
+	  candidate[ii++]=jcol;
+#ifdef CGL_DEBUG
+	  assert (ii<=nSmall2);
+#endif
+	}
+      }
+#ifdef CGL_DEBUG
+      printf("\n");
+#endif
+      for (j=0;j<nclean;j++) {
+	int k=clean[j];
+	mark[k]=0;
+      }
+      if (good) {
+	int k;
+	for (k=ii-1;k>0;k--) {
+	  int jk,kk=candidate[k];
+	  int ix=0;
+	  for (jk=starts[kk];jk<starts[kk+1];jk++) {
+	    int ito=to[jk];
+	    if (ito==candidate[k-1]) {
+	      ix=1;
+	      // back to original row
+	      mrow[nrow2++]=rowfound[jk];
+	      break;
+	    }
+	  }
+	  if (!ix) {
+	    good=false;
+	  }
+	}
+	if ((nrow2&1)!=1) {
+	  good=false;
+	}
+	if (good) {
+	  int nincut=0;
+	  for (k=0;k<nrow2;k++) {
+	    int j,irow=mrow[k];
+	    for (j=rowStart[irow];j<rowStart[irow]+rowLength[irow];j++) {
+	      int icol=column[j];
+	      if (!countcol[icol]) candidate[nincut++]=icol;
+	      countcol[icol]++;
+	    }
+	  }
+#ifdef CGL_DEBUG
+	  printf("true constraint %d",nrow2);
+#endif
+	  nrow2=nrow2>>1;
+	  double rhs=nrow2; 
+	  if (!packed) rhs++; // +1 for cover
+	  ii=0;
+	  for (k=0;k<nincut;k++) {
+	    int jcol=candidate[k];
+	    if (countcol[jcol]) {
+#ifdef CGL_DEBUG
+	      printf(" %d %d",jcol,countcol[jcol]);
+#endif
+	      int ihalf=(countcol[jcol]+bias)>>1;
+	      if (ihalf) {
+		element[ii]=ihalf;
+		sum+=solution[jcol]*element[ii];
+		/*printf("%d %g %g\n",jcol,element[ii],sumall[jcol]);*/
+		candidate[ii++]=jcol;
+	      }
+	      countcol[jcol]=0;
+	    }
+	  }
+#ifdef CGL_DEBUG
+          printf("\n");
+#endif
+	  OsiRowCut rc;
+	  double violation=0.0;
+	  if (packed) {
+	    violation = sum-rhs;
+	    rc.setLb(-COIN_DBL_MAX);
+	    rc.setUb(rhs);   
+	  } else {
+	    // other way for cover
+	    violation = rhs-sum;
+	    rc.setUb(COIN_DBL_MAX);
+	    rc.setLb(rhs);   
+	  }
+	  if (violation<minimumViolation_) {
+#ifdef CGL_DEBUG
+	    printf("why no cut\n");
+#endif
+	    good=false;
+	  } else {
+	    if (static_cast<double> (ii) * minimumViolationPer_>violation||
+		ii>maximumEntries_) {
+#ifdef CGL_DEBUG
+	      printf("why no cut\n");
+#endif
+	      if (packed) {
+		// sort and see if we can get down to length
+		// relax by taking out ones with solution 0.0
+		nincut=ii;
+		for (k=0;k<nincut;k++) {
+		  int jcol=candidate[k];
+		  double value = fabs(dj[jcol]);
+		  if (solution[jcol])
+		  value = -solution[jcol];
+		  sortit[k].dj=value;
+		  sortit[k].element=element[k];
+		  sortit[k].sequence=jcol;
+		}
+		// sort 
+		std::sort(sortit,sortit+nincut,double_double_int_triple_compare());
+		nincut = CoinMin(nincut,maximumEntries_);
+		sum=0.0;
+		for (k=0;k<nincut;k++) {
+		  int jcol=sortit[k].sequence;
+		  candidate[k]=jcol;
+		  element[k]=sortit[k].element;
+		  sum+=solution[jcol]*element[k];
+		}
+		violation = sum-rhs;
+		ii=nincut;
+		if (violation<minimumViolation_) {
+		  good=false;
+		}
+	      } else { 
+		good=false;
+	      }
+	    }
+	  }
+	  if (good) {
+	    //this assumes not many cuts
+	    int j;
+#if 0
+	    double value=0.0;
+	    for (j=0;j<ii;j++) {
+	      int icol=candidate[j];
+	      value += check[icol]*element[j];
+	    }
+#else
+            CoinPackedVector candidatePv(ii,candidate,element);
+            candidatePv.sortIncrIndex();
+            double value = candidatePv.dotProduct(check);
+#endif
+
+	    for (j=0;j<ncuts;j++) {
+	      if (value==hash[j]) {
+		//could check equality - quicker just to assume
+		break;
+	      }
+	    }
+	    if (j==ncuts) {
+	      //new
+	      if (ncuts==maxcuts) {
+		maxcuts *= 2;
+		hash = reinterpret_cast<double *> (realloc(hash,maxcuts*sizeof(double)));
+	      }
+	      hash[ncuts++]=value;
+	      rc.setRow(ii,candidate,element);
+#ifdef CGL_DEBUG
+	      printf("sum %g rhs %g %d\n",sum,rhs,ii);
+	      if (debugger) 
+		assert(!debugger->invalidCut(rc)); 
+#endif
+	      cs.insert(rc);
+	    }
+	  }
+	}
+	/* end of adding cut */
+      }
+    }
+  }
+  delete [] countcol;
+  delete [] element;
+  delete [] candidate;
+  delete [] sortit;
+  delete [] clean;
+  delete [] path;
+  delete [] stack;
+  free(hash);
+  delete [] check;
+  delete [] mark;
+  delete [] starts;
+  delete [] lookup;
+  delete [] mrow;
+  free(rowfound);
+  free(to);
+  free(cost);
+}
+
+// Create a list of rows which might yield cuts
+// The possible parameter is a list to cut down search
+void CglOddHole::createRowList( const OsiSolverInterface & si,
+		      const int * possible)
+{
+  // Get basic problem information
+  int nRows=si.getNumRows(); 
+  
+  const CoinPackedMatrix * rowCopy = si.getMatrixByRow();
+
+  const int * column = rowCopy->getIndices();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const int * rowLength = rowCopy->getVectorLengths(); 
+  
+  int rowIndex;
+  delete [] suitableRows_;
+  numberRows_=nRows;
+
+  const double * rowElements = rowCopy->getElements();
+  const double * rowupper = si.getRowUpper();
+  const double * rowlower = si.getRowLower();
+  const double * collower = si.getColLower();
+  const double * colupper = si.getColUpper();
+
+  suitableRows_=new int[nRows];
+  if (possible) {
+    memcpy(suitableRows_,possible,nRows*sizeof(int));
+  } else {
+    int i;
+    for (i=0;i<nRows;i++) {
+      suitableRows_[i]=1;
+    }
+  }
+  for (rowIndex=0; rowIndex<nRows; rowIndex++){
+    double rhs1=rowupper[rowIndex];
+    double rhs2=rowlower[rowIndex];
+    if (suitableRows_[rowIndex]) {
+      int i;
+      bool goodRow=true;
+      for (i=rowStart[rowIndex];
+	   i<rowStart[rowIndex]+rowLength[rowIndex];i++) {
+	int thisCol=column[i];
+	if (colupper[thisCol]-collower[thisCol]>epsilon_) {
+	  // could allow general integer variables but unlikely
+	  if (!si.isBinary(thisCol) ) {
+	    goodRow=false;
+	    break;
+	  }
+	  if (fabs(rowElements[i]-1.0)>epsilon_) {
+	    goodRow=false;
+	    break;
+	  }
+	} else {
+	  rhs1 -= collower[thisCol]*rowElements[i];
+	  rhs2 -= collower[thisCol]*rowElements[i];
+	}
+      }
+      if (fabs(rhs1-1.0)>epsilon_&&fabs(rhs2-1.0)>epsilon_) {
+	goodRow=false;
+      }
+      if (goodRow) {
+	suitableRows_[rowIndex]=1;
+      } else {
+	suitableRows_[rowIndex]=0;
+      }
+    }
+  }
+}
+  /// This version passes in a list - 1 marks possible
+void CglOddHole::createRowList(int numberRows, const int * whichRow)
+{
+  suitableRows_=new int [numberRows];
+  numberRows_=numberRows;
+  memcpy(suitableRows_,whichRow,numberRows*sizeof(int));
+}
+
+// Create a list of extra row cliques which may not be in matrix
+// At present these are classical cliques
+void CglOddHole::createCliqueList(int numberCliques, const int * cliqueStart,
+		     const int * cliqueMember)
+{
+  numberCliques_=numberCliques;
+  startClique_=new int[numberCliques_+1];
+  memcpy(startClique_,cliqueStart,(numberCliques_+1)*sizeof(int));
+  int length=startClique_[numberCliques_];
+  member_=new int[length];
+  memcpy(member_,cliqueMember,length*sizeof(int));
+}
+// Returns how many rows might give three cycle cuts
+int CglOddHole::numberPossible()
+{
+  int i,n=0;
+  for (i=0;i<numberRows_;i++) {
+    if (suitableRows_[i]) n++;
+  }
+  return n;
+}
+
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglOddHole::CglOddHole ()
+:
+CglCutGenerator(),
+epsilon_(1.0e-08),
+onetol_(1-epsilon_)
+{
+  // null copy of suitable rows
+  numberRows_=0;
+  suitableRows_=NULL;
+  startClique_=NULL;
+  numberCliques_=0;
+  member_=NULL;
+  minimumViolation_=0.001;
+  minimumViolationPer_=0.0003;
+  maximumEntries_=100;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglOddHole::CglOddHole (
+                                                              const CglOddHole & source)
+                                                              :
+CglCutGenerator(source),
+epsilon_(source.epsilon_),
+onetol_(source.onetol_)
+{  
+  // copy list of suitable rows
+  numberRows_=source.numberRows_;
+  if (numberRows_) {
+    suitableRows_=new int[numberRows_];
+    memcpy(suitableRows_,source.suitableRows_,numberRows_*sizeof(int));
+  } else {
+    suitableRows_=NULL;
+  }
+  // copy list of cliques
+  numberCliques_=source.numberCliques_;
+  if (numberCliques_) {
+    startClique_=new int[numberCliques_+1];
+    memcpy(startClique_,source.startClique_,(numberCliques_+1)*sizeof(int));
+    int length=startClique_[numberCliques_];
+    member_=new int[length];
+    memcpy(member_,source.member_,length*sizeof(int));
+  } else {
+    startClique_=NULL;
+    member_=NULL;
+  }
+  minimumViolation_=source.minimumViolation_;
+  minimumViolationPer_=source.minimumViolationPer_;
+  maximumEntries_=source.maximumEntries_;
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglOddHole::clone() const
+{
+  return new CglOddHole(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglOddHole::~CglOddHole ()
+{
+  // free memory
+  delete [] suitableRows_;
+  delete [] startClique_;
+  delete [] member_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglOddHole &
+CglOddHole::operator=(
+                                         const CglOddHole& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    epsilon_=rhs.epsilon_;
+    onetol_=rhs.onetol_;
+    delete [] suitableRows_;
+    // copy list of suitable rows
+    numberRows_=rhs.numberRows_;
+    suitableRows_=new int[numberRows_];
+    memcpy(suitableRows_,rhs.suitableRows_,numberRows_*sizeof(int));
+    delete [] startClique_;
+    delete [] member_;
+    // copy list of cliques
+    numberCliques_=rhs.numberCliques_;
+    if (numberCliques_) {
+      startClique_=new int[numberCliques_+1];
+      memcpy(startClique_,rhs.startClique_,(numberCliques_+1)*sizeof(int));
+      int length=startClique_[numberCliques_];
+      member_=new int[length];
+      memcpy(member_,rhs.member_,length*sizeof(int));
+    } else {
+      startClique_=NULL;
+      member_=NULL;
+    }
+    minimumViolation_=rhs.minimumViolation_;
+    minimumViolationPer_=rhs.minimumViolationPer_;
+    maximumEntries_=rhs.maximumEntries_;
+  }
+  return *this;
+}
+// Minimum violation
+double 
+CglOddHole::getMinimumViolation() const
+{
+  return minimumViolation_;
+}
+void 
+CglOddHole::setMinimumViolation(double value)
+{
+  if (value>1.0e-8&&value<=0.5)
+    minimumViolation_=value;
+}
+// Minimum violation per entry
+double 
+CglOddHole::getMinimumViolationPer() const
+{
+  return minimumViolationPer_;
+}
+void 
+CglOddHole::setMinimumViolationPer(double value)
+{
+  if (value>1.0e-8&&value<=0.25)
+    minimumViolationPer_=value;
+}
+// Maximum number of entries in a cut
+int 
+CglOddHole::getMaximumEntries() const
+{
+  return maximumEntries_;
+}
+void 
+CglOddHole::setMaximumEntries(int value)
+{
+  if (value>2)
+    maximumEntries_=value;
+}
+
+// This can be used to refresh any inforamtion
+void 
+CglOddHole::refreshSolver(OsiSolverInterface * )
+{
+}
diff --git a/cbits/coin/CglOddHole.hpp b/cbits/coin/CglOddHole.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglOddHole.hpp
@@ -0,0 +1,160 @@
+// $Id: CglOddHole.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglOddHole_H
+#define CglOddHole_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+
+/** Odd Hole Cut Generator Class */
+class CglOddHole : public CglCutGenerator {
+   friend void CglOddHoleUnitTest(const OsiSolverInterface * siP,
+				  const std::string mpdDir );
+ 
+public:
+    
+  
+  /**@name Generate Cuts */
+  //@{
+  /** Generate odd hole cuts for the model of the solver interface, si.
+      This looks at all rows of type sum x(i) <= 1 (or == 1) (x 0-1)
+      and sees if there is an odd cycle cut.  See Grotschel, Lovasz
+      and Schrijver (1988) for method.
+      This is then lifted by using the corresponding Chvatal cut i.e.
+      Take all rows in cycle and add them together. RHS will be odd so  
+      weaken all odd coefficients so 1.0 goes to 0.0 etc - then
+      constraint is  sum even(j)*x(j) <= odd which can be replaced by
+      sum (even(j)/2)*x(j) <= (odd-1.0)/2.
+      A similar cut can be generated for sum x(i) >= 1.
+
+      Insert the generated cuts into OsiCut, cs.
+
+      This is only done for rows with unsatisfied 0-1 variables.  If there
+      are many of these it will be slow.  Improvements would do a 
+      randomized subset and also speed up shortest path algorithm used.
+
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+  /**@name Create Row List */
+  //@{
+  /// Create a list of rows which might yield cuts
+  /// this is to speed up process
+  /// The possible parameter is a list to cut down search
+  void createRowList( const OsiSolverInterface & si,
+		      const int * possible=NULL);
+  /// This version passes in a list - 1 marks possible
+  void createRowList(int numberRows, const int * whichRow);
+  //@}
+
+  /**@name Create Clique List */
+  //@{
+  /// Create a list of extra row cliques which may not be in matrix
+  /// At present these are classical cliques
+  void createCliqueList(int numberCliques, const int * cliqueStart,
+		     const int * cliqueMember);
+  //@}
+
+  /**@name Number Possibilities */
+  //@{
+  /// Returns how many rows might give odd hole cuts
+  int numberPossible();
+  //@}
+  /**@name Gets and Sets */
+  //@{
+  /// Minimum violation
+  double getMinimumViolation() const;
+  void setMinimumViolation(double value);
+  /// Minimum violation per entry
+  double getMinimumViolationPer() const;
+  void setMinimumViolationPer(double value);
+  /// Maximum number of entries in a cut
+  int getMaximumEntries() const;
+  void setMaximumEntries(int value);
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglOddHole ();
+ 
+  /// Copy constructor 
+  CglOddHole (
+    const CglOddHole &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglOddHole &
+    operator=(
+    const CglOddHole& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglOddHole ();
+
+  /// This can be used to refresh any inforamtion
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  //@}
+      
+private:
+  
+ // Private member methods
+
+
+  /**@name Private methods */
+  //@{
+  /// Generate cuts from matrix copy and solution
+  /// If packed true then <=1 rows, otherwise >=1 rows.
+  void generateCuts(const OsiRowCutDebugger * debugger, 
+		    const CoinPackedMatrix & rowCopy,
+		    const double * solution, const double * dj,
+		    OsiCuts & cs, const int * suitableRow,
+		    const int * fixedColumn,const CglTreeInfo info,
+		    bool packed);
+  //@}
+
+  // Private member data
+
+  /**@name Private member data */
+  //@{
+  /// list of suitableRows
+  int * suitableRows_;
+  /// start of each clique
+  int * startClique_;
+  /// clique members
+  int * member_;
+  /// epsilon
+  double epsilon_;  
+  /// 1-epsilon
+  double onetol_;
+  /// Minimum violation
+  double minimumViolation_;
+  /// Minimum violation per entry
+  double minimumViolationPer_;
+  /// Maximum number of entries in a cut
+  int maximumEntries_;
+  /// number of rows when suitability tested
+  int numberRows_;
+  /// number of cliques
+  int numberCliques_;
+  //@}
+};
+
+//#############################################################################
+/** A function that tests the methods in the CglOddHole class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglOddHoleUnitTest(const OsiSolverInterface * siP,
+			const std::string mpdDir );
+  
+#endif
diff --git a/cbits/coin/CglParam.cpp b/cbits/coin/CglParam.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglParam.cpp
@@ -0,0 +1,86 @@
+// Name:     CglParam.cpp
+// Author:   Francois Margot                                                  
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     11/24/06
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+// Copyright (C) 2006, Francois Margot and others.  All Rights Reserved.
+//---------------------------------------------------------------------------
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CglParam.hpp"
+
+/***********************************************************************/
+void CglParam::setINFINIT(const double inf)
+{
+  if(inf > 0)
+    INFINIT = inf;
+} /* setINFINIT */
+
+/***********************************************************************/
+void CglParam::setEPS(const double eps)
+{
+  if(eps >= 0)
+    EPS = eps;
+} /* setEPS */
+
+/***********************************************************************/
+void CglParam::setEPS_COEFF(const double eps_c)
+{
+  if(eps_c >= 0)
+    EPS_COEFF = eps_c;
+} /* setEPS_COEFF */
+
+/***********************************************************************/
+void CglParam::setMAX_SUPPORT(const int max_s)
+{
+  if(max_s > 0)
+    MAX_SUPPORT = max_s;
+} /* setMAX_SUPPORT */
+
+/***********************************************************************/
+CglParam::CglParam(const double inf, const double eps, const double eps_c, 
+		   const int max_s) :
+  INFINIT(inf),
+  EPS(eps),
+  EPS_COEFF(eps_c),
+  MAX_SUPPORT(max_s)
+{}
+
+/***********************************************************************/
+CglParam::CglParam(const CglParam &source) :
+  INFINIT(source.INFINIT),
+  EPS(source.EPS),
+  EPS_COEFF(source.EPS_COEFF),
+  MAX_SUPPORT(source.MAX_SUPPORT)
+{}
+
+/***********************************************************************/
+CglParam* CglParam::clone() const
+{
+  return new CglParam(*this);
+}
+
+/***********************************************************************/
+CglParam& CglParam::operator=(const CglParam &rhs)
+{
+  if(this != &rhs) {
+    INFINIT = rhs.INFINIT;
+    EPS = rhs.EPS;
+    EPS_COEFF = rhs.EPS_COEFF;
+    MAX_SUPPORT = rhs.MAX_SUPPORT;
+  }
+  return *this;
+}
+
+/***********************************************************************/
+CglParam::~CglParam()
+{}
diff --git a/cbits/coin/CglParam.hpp b/cbits/coin/CglParam.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglParam.hpp
@@ -0,0 +1,93 @@
+// Name:     CglParam.hpp
+// Author:   Francois Margot
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+//           email: fmargot@andrew.cmu.edu
+// Date:     11/24/06
+//
+// $Id: CglParam.hpp 1123 2013-04-06 20:47:24Z stefan $
+//
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+//-----------------------------------------------------------------------------
+// Copyright (C) 2006, Francois Margot and others.  All Rights Reserved.
+
+#ifndef CglParam_H
+#define CglParam_H
+#include "CglConfig.h"
+#include "CoinFinite.hpp"
+/** Class collecting parameters for all cut generators. Each generator
+    may have a derived class to add parameters. Each generator might
+    also set different default values for the parameters in CglParam.  */
+
+class CglParam {
+
+public:
+
+  /**@name Public Set/get methods */
+  //@{
+
+  /** Set INFINIT */
+  virtual void setINFINIT(const double inf);
+  /** Get value of INFINIT */
+  inline double getINFINIT() const {return INFINIT;}
+
+  /** Set EPS */
+  virtual void setEPS(const double eps);
+  /** Get value of EPS */
+  inline double getEPS() const {return EPS;}
+
+  /** Set EPS_COEFF */
+  virtual void setEPS_COEFF(const double eps_c);
+  /** Get value of EPS_COEFF */
+  inline double getEPS_COEFF() const {return EPS_COEFF;}
+
+  /** Set MAX_SUPPORT */
+  virtual void setMAX_SUPPORT(const int max_s);
+  /** Get value of MAX_SUPPORT */
+  inline int getMAX_SUPPORT() const {return MAX_SUPPORT;}
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglParam(const double inf = COIN_DBL_MAX, const double eps = 1e-6,
+	   const double eps_c = 1e-5, const int max_s = COIN_INT_MAX);
+ 
+  /// Copy constructor 
+  CglParam(const CglParam&);
+
+  /// Clone
+  virtual CglParam* clone() const;
+
+  /// Assignment operator 
+  CglParam& operator=(const CglParam &rhs);
+
+  /// Destructor 
+  virtual ~CglParam();
+  //@}
+
+protected:
+
+  // Protected member data
+
+  /**@name Protected member data */
+
+  //@{
+  // Value for infinity. Default: COIN_DBL_MAX.
+  double INFINIT;
+
+  // EPSILON for double comparisons. Default: 1e-6.
+  double EPS;
+
+  // Returned cuts do not have coefficients with absolute value smaller 
+  // than EPS_COEFF. Default: 1e-5.
+  double EPS_COEFF;
+
+  /** Maximum number of non zero coefficients in a generated cut;
+      Default: COIN_INT_MAX */ 
+  int MAX_SUPPORT; 
+  //@}
+
+};
+
+#endif
diff --git a/cbits/coin/CglPreProcess.cpp b/cbits/coin/CglPreProcess.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglPreProcess.cpp
@@ -0,0 +1,6524 @@
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <string>
+#include <cassert>
+#include <cmath>
+#include <vector>
+#include <algorithm>
+#include <cfloat>
+
+#include "CoinPragma.hpp"
+#include "CglPreProcess.hpp"
+#include "CglMessage.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiColCut.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CglStored.hpp"
+#include "CglCutGenerator.hpp"
+#include "CoinTime.hpp"
+#include "CoinSort.hpp"
+#include "CoinBuild.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinWarmStartBasis.hpp"
+
+#include "CglProbing.hpp"
+#include "CglDuplicateRow.hpp"
+#include "CglClique.hpp"
+
+OsiSolverInterface *
+CglPreProcess::preProcess(OsiSolverInterface & model, 
+                       bool makeEquality, int numberPasses)
+{
+  // Tell solver we are in Branch and Cut
+  model.setHintParam(OsiDoInBranchAndCut,true,OsiHintDo) ;
+  // Default set of cut generators
+  CglProbing generator1;
+  generator1.setUsingObjective(true);
+  generator1.setMaxPass(3);
+  generator1.setMaxProbeRoot(model.getNumCols());
+  generator1.setMaxElements(100);
+  generator1.setMaxLookRoot(50);
+  generator1.setRowCuts(3);
+  // Add in generators
+  addCutGenerator(&generator1);
+  OsiSolverInterface * newSolver = preProcessNonDefault(model,makeEquality ? 1 : 0,numberPasses);
+  // Tell solver we are not in Branch and Cut
+  model.setHintParam(OsiDoInBranchAndCut,false,OsiHintDo) ;
+  if (newSolver)
+    newSolver->setHintParam(OsiDoInBranchAndCut,false,OsiHintDo) ;
+  return newSolver;
+}
+static void outSingletons(int & nCol, int & nRow,
+			  int * startCol, int * row, double * element,
+			  int * startRow, int *column)
+{
+  int iRow,iCol;
+  bool singletons=false;
+  int * countRow = new int [nRow];
+  int * countCol = new int [nCol];
+  int * temp = new int[nRow];
+  // make row copy
+  memset(countRow,0,nRow*sizeof(int));
+  memset(countCol,0,nCol*sizeof(int));
+  for (iCol=0;iCol<nCol;iCol++) {
+    for (int j=startCol[iCol];j<startCol[iCol+1];j++) {
+      int iRow = row[j];
+      countRow[iRow]++;
+      countCol[iCol]++;
+    }
+  }
+  startRow[0]=0;
+  for (iRow=0;iRow<nRow;iRow++) {
+    int k = countRow[iRow]+startRow[iRow];
+    temp[iRow]=startRow[iRow];
+    startRow[iRow+1]=k;
+  }
+  for (iCol=0;iCol<nCol;iCol++) {
+    for (int j=startCol[iCol];j<startCol[iCol+1];j++) {
+      int iRow = row[j];
+      int k=temp[iRow];
+      temp[iRow]++;
+      column[k]=iCol;
+    }
+  }
+  for (iRow=0;iRow<nRow;iRow++) {
+    if (countRow[iRow]<=1)
+      singletons=true;
+  }
+  for (iCol=0;iCol<nCol;iCol++) {
+    if (countCol[iCol]<=1)
+      singletons=true;
+  }
+  if (singletons) {
+    while (singletons) {
+      singletons=false;
+      for (iCol=0;iCol<nCol;iCol++) {
+	if (countCol[iCol]==1) {
+	  singletons=true;
+	  countCol[iCol]=0;
+	  int iRow = row[startCol[iCol]];
+	  int start = startRow[iRow];
+	  int end = start+countRow[iRow];
+	  countRow[iRow]--;
+	  int j;
+	  for ( j=start;j<end;j++) {
+	    if (column[j]==iCol) {
+	      column[j]=column[end-1];
+	      break;
+	    }
+	  }
+	  assert (j<end);
+	}
+      }
+      for (iRow=0;iRow<nRow;iRow++) {
+	if (countRow[iRow]==1) {
+	  singletons=true;
+	  countRow[iRow]=0;
+	  int iCol = column[startRow[iRow]];
+	  int start = startCol[iCol];
+	  int end = start+countCol[iCol];
+	  countCol[iCol]--;
+	  int j;
+	  for ( j=start;j<end;j++) {
+	    if (row[j]==iRow) {
+	      row[j]=row[end-1];
+	      if (element)
+		element[j]=element[end-1];
+	      break;
+	    }
+	  }
+	  assert (j<end);
+	}
+      }
+    }  
+    // Pack down
+    int newNrow=0;
+    for (iRow=0;iRow<nRow;iRow++) {
+      if (countRow[iRow]==0) {
+	temp[iRow]=-1;
+      } else {
+	assert (countRow[iRow]>1);
+	temp[iRow]=newNrow;
+	newNrow++;
+      }
+    }
+    int newNcol=0;
+    int nEl=0;
+    int iNext=0;
+    for (iCol=0;iCol<nCol;iCol++) {
+      int start = iNext;
+      iNext=startCol[iCol+1];
+      if (countCol[iCol]==0) {
+	countCol[iCol]=-1;
+      } else {
+	assert (countCol[iCol]>1);
+	int end = start+countCol[iCol];
+	countCol[iCol]=newNcol;
+	int j;
+	for ( j=start;j<end;j++) {
+	  int iRow=row[j];
+	  iRow = temp[iRow];
+	  assert (iRow>=0);
+	  row[nEl]=iRow;
+	  if (element)
+	    element[nEl]=element[j];
+	  nEl++;
+	}
+	newNcol++;
+	startCol[newNcol]=nEl;
+      }
+    }
+    newNrow=0;
+    nEl=0;
+    iNext=0;
+    for (iRow=0;iRow<nRow;iRow++) {
+      int start = iNext;
+      iNext = startRow[iRow+1];
+      if (countRow[iRow]>1) {
+	int end = start+countRow[iRow];
+	int j;
+	for ( j=start;j<end;j++) {
+	  int iCol = column[j];
+	  iCol = countCol[iCol];
+	  assert (iCol>=0);
+	  column[nEl++]=iCol;
+	}
+	newNrow++;
+	startRow[newNrow]=nEl;
+      }
+    }
+    nRow=newNrow;
+    nCol=newNcol;
+  }
+  delete [] countCol;
+  delete [] countRow;
+  delete [] temp;
+}
+static int makeIntegers2(OsiSolverInterface * model,int mode)
+{
+  // See whether we should make variables integer
+  const double *objective = model->getObjCoefficients() ;
+  const double *lower = model->getColLower() ;
+  const double *upper = model->getColUpper() ;
+  const double *rowLower = model->getRowLower() ;
+  const double *rowUpper = model->getRowUpper() ;
+  int numberRows = model->getNumRows() ;
+  double * rhs = new double [numberRows];
+  int * count = new int [numberRows];
+  int iColumn;
+  bool makeAll = (mode>1);
+  int numberColumns = model->getNumCols() ;
+  // Column copy of matrix
+  const double * element = model->getMatrixByCol()->getElements();
+  const int * row = model->getMatrixByCol()->getIndices();
+  const CoinBigIndex * columnStart = model->getMatrixByCol()->getVectorStarts();
+  const int * columnLength = model->getMatrixByCol()->getVectorLengths();
+  // Row copy
+  CoinPackedMatrix matrixByRow(*model->getMatrixByRow());
+  //const double * elementByRow = matrixByRow.getElements();
+  const int * column = matrixByRow.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  const int * rowLength = matrixByRow.getVectorLengths();
+  int numberIntegers=1;
+  int totalNumberIntegers=0;
+  while (numberIntegers) {
+    memset(rhs,0,numberRows*sizeof(double));
+    memset(count,0,numberRows*sizeof(int));
+    int currentNumber=0;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      CoinBigIndex start = columnStart[iColumn];
+      CoinBigIndex end = start + columnLength[iColumn];
+      if (upper[iColumn]==lower[iColumn]) {
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  rhs[iRow] += lower[iColumn]*element[j];
+	}
+      } else if (model->isInteger(iColumn)) {
+	currentNumber++;
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  if (fabs(element[j]-floor(element[j]+0.5))>1.0e-10) 
+	    rhs[iRow]  = COIN_DBL_MAX;
+	}
+      } else {
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  count[iRow]++;
+	  if (fabs(element[j])!=1.0)
+	    rhs[iRow]  = COIN_DBL_MAX;
+	}
+      }
+    }
+#ifdef COIN_DEVELOP
+    printf("Current number of integers is %d\n",currentNumber);
+#endif
+    // now look at continuous
+    bool allGood=true;
+    double direction = model->getObjSense() ;
+    int numberObj=0;
+    int numberEq=0;
+    int numberEqI=0;
+    int numberZero=0;
+    int numberNonZero=0;
+    if (false) {
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	if (upper[iColumn]>lower[iColumn]) {
+	  if (!model->isInteger(iColumn)) {
+	    CoinBigIndex start = columnStart[iColumn];
+	    CoinBigIndex end = start + columnLength[iColumn];
+	    int nC=0;
+	    for (CoinBigIndex j=start;j<end;j++) {
+	      int iRow = row[j];
+	      if (count[iRow]>1) {
+		nC++;
+	      }
+	    }
+	    if (nC>2) {
+	      for (CoinBigIndex j=start;j<end;j++) {
+		int iRow = row[j];
+		if (count[iRow]>1) 
+		  count[iRow]=999999;
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    int * newInts = new int[numberColumns];
+    // Columns to zap
+    int nColumnZap=0;
+    int * columnZap = new int[numberColumns];
+    char * noGoodColumn = new char [numberColumns];
+    memset(noGoodColumn,0,numberColumns);
+    int nNew=0;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (upper[iColumn]>lower[iColumn]) {
+	double objValue = objective[iColumn]*direction;
+	bool thisGood=true;
+	if ((objValue||makeAll)&&!model->isInteger(iColumn)) {
+	  if (objValue) {
+	    numberObj++;
+	  } else if (columnLength[iColumn]==1) {
+	    continue; // don't bother with singletons
+	  }
+	  CoinBigIndex start = columnStart[iColumn];
+	  CoinBigIndex end = start + columnLength[iColumn];
+	  if (objValue>=0.0) {
+	    // wants to be as low as possible
+	    if (lower[iColumn]<-1.0e10||fabs(lower[iColumn]-floor(lower[iColumn]+0.5))>1.0e-10) {
+	      thisGood=false;
+	    } else if (upper[iColumn]<1.0e10&&fabs(upper[iColumn]-floor(upper[iColumn]+0.5))>1.0e-10) {
+	      thisGood=false;
+	    }
+	    bool singletonRow=true;
+	    bool equality=false;
+	    int nC=0;
+	    int xxxx=0;
+	    bool badCount=false;
+	    for (CoinBigIndex j=start;j<end;j++) {
+	      int iRow = row[j];
+	      if (count[iRow]>1) {
+		singletonRow=false;
+		//printf("col %d row%d element %g - row count %d\n",iColumn,iRow,element[j],count[iRow]);
+		if (count[iRow]==999999)
+		  badCount=true;
+		if (element[j]==1.0) {
+		  if ((xxxx&1)==0)
+		    xxxx |= 1;
+		  else
+		    xxxx = 15;
+		} else {
+		  if ((xxxx&2)==0)
+		    xxxx |= 2;
+		  else
+		    xxxx = 15;
+		}
+		nC++;
+	      } else if (rowLower[iRow]==rowUpper[iRow]) {
+		equality=true;
+	      }
+	      double rhsValue = rhs[iRow];
+	      double lowerValue = rowLower[iRow];
+	      double upperValue = rowUpper[iRow];
+	      if (rhsValue<1.0e20) {
+		if(lowerValue>-1.0e20)
+		  lowerValue -= rhsValue;
+		if(upperValue<1.0e20)
+		  upperValue -= rhsValue;
+	      }
+	      if (fabs(rhsValue)>1.0e20||fabs(rhsValue-floor(rhsValue+0.5))>1.0e-10
+		  ||fabs(element[j])!=1.0) {
+		// no good
+		thisGood=false;
+		break;
+	      }
+	      if (element[j]>0.0) {
+		if (lowerValue>-1.0e20&&fabs(lowerValue-floor(lowerValue+0.5))>1.0e-10) {
+		  // no good
+		  thisGood=false;
+		  break;
+		}
+	      } else {
+		if (upperValue<1.0e20&&fabs(upperValue-floor(upperValue+0.5))>1.0e-10) {
+		  // no good
+		  thisGood=false;
+		  break;
+		}
+	      }
+	    }
+	    if (!model->isInteger(iColumn)&&false)
+	      printf("%d has %d rows with >1 - state network %s interaction %s\n",iColumn,nC,xxxx>3 ? "bad" : "good",
+		     badCount ? "too much" : "ok");
+	    // If not good here then mark rows
+	    if (!thisGood) {
+	      for (CoinBigIndex j=start;j<end;j++) {
+		int iRow = row[j];
+		count[iRow]=999999;
+	      }
+	    }
+	    if (!singletonRow&&end>start+1&&!equality)
+	      thisGood=false;
+	    // Can we make equality
+	    if (end==start+1&&!equality&&false) {
+	      numberEq++;
+	      int iRow = row[start];
+	      if (element[start]>0.0)
+		model->setRowUpper(iRow,rowLower[iRow]);
+	      else
+		model->setRowLower(iRow,rowUpper[iRow]);
+	    }
+	  } else {
+	    // wants to be as high as possible
+	    if (upper[iColumn]>1.0e10||fabs(upper[iColumn]-floor(upper[iColumn]+0.5))>1.0e-10) {
+	      thisGood=false;
+	    } else if (lower[iColumn]>-1.0e10&&fabs(lower[iColumn]-floor(lower[iColumn]+0.5))>1.0e-10) {
+	      thisGood=false;
+	    }
+	    bool singletonRow=true;
+	    bool equality=false;
+	    for (CoinBigIndex j=start;j<end;j++) {
+	      int iRow = row[j];
+	      if (count[iRow]>1) {
+		singletonRow=false;
+		thisGood=false;
+	      } else if (rowLower[iRow]==rowUpper[iRow]) {
+		equality=true;
+	      }
+	      double rhsValue = rhs[iRow];
+	      double lowerValue = rowLower[iRow];
+	      double upperValue = rowUpper[iRow];
+	      if (rhsValue<1.0e20) {
+		if(lowerValue>-1.0e20)
+		  lowerValue -= rhsValue;
+		if(upperValue<1.0e20)
+		  upperValue -= rhsValue;
+	      }
+	      if (fabs(rhsValue)>1.0e20||fabs(rhsValue-floor(rhsValue+0.5))>1.0e-10
+		  ||fabs(element[j])!=1.0) {
+		// no good
+		thisGood=false;
+		break;
+	      }
+	      if (element[j]<0.0) {
+		if (lowerValue>-1.0e20&&fabs(lowerValue-floor(lowerValue+0.5))>1.0e-10) {
+		  // no good
+		  thisGood=false;
+		  break;
+		}
+	      } else {
+		if (upperValue<1.0e20&&fabs(upperValue-floor(upperValue+0.5))>1.0e-10) {
+		  // no good
+		  thisGood=false;
+		  break;
+		}
+	      }
+	    }
+	    if (!singletonRow&&end>start+1&&!equality)
+	      thisGood=false;
+	    // If not good here then mark rows
+	    if (!thisGood) {
+	      for (CoinBigIndex j=start;j<end;j++) {
+		int iRow = row[j];
+		count[iRow]=999999;
+	      }
+	    }
+	    // Can we make equality
+	    if (end==start+1&&!equality&&false) {
+	      numberEq++;
+	      int iRow = row[start];
+	      if (element[start]<0.0)
+		model->setRowUpper(iRow,rowLower[iRow]);
+	      else
+		model->setRowLower(iRow,rowUpper[iRow]);
+	    }
+	  }
+	} else if (objValue) {
+	  CoinBigIndex start = columnStart[iColumn];
+	  CoinBigIndex end = start + columnLength[iColumn];
+	  if (end==start+1) {
+	    int iRow = row[start];
+	    if (rowUpper[iRow]>rowLower[iRow]&&!count[iRow]) {
+	      if (fabs(rhs[iRow])>1.0e20||fabs(rhs[iRow]-floor(rhs[iRow]+0.5))>1.0e-10
+		  ||fabs(element[start])!=1.0) {
+		// no good
+	      } else if (false) {
+		numberEqI++;
+		if (element[start]*objValue>0.0)
+		  model->setRowUpper(iRow,rowLower[iRow]);
+		else
+		  model->setRowLower(iRow,rowUpper[iRow]);
+	      }
+	    }
+	  }
+	}
+	if (!thisGood) {
+	  if (objValue)
+	    allGood=false;
+	  // look at again
+	  columnZap[nColumnZap++]=iColumn;
+	} else if (makeAll&&!model->isInteger(iColumn)&&
+		   upper[iColumn]-lower[iColumn]<10) {
+	  newInts[nNew++] = iColumn;
+	}
+      }
+    }
+    // Rows to look at
+    int * rowLook = new int[numberRows];
+    while (nColumnZap) {
+      int nRowLook=0;
+      for (int i=0;i<nColumnZap;i++) {
+	int iColumn=columnZap[i];
+	noGoodColumn[iColumn]=1;
+	CoinBigIndex start = columnStart[iColumn];
+	CoinBigIndex end = start + columnLength[iColumn];
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  if (count[iRow]!=999999) {
+	    count[iRow]=999999;
+	    rowLook[nRowLook++]=iRow;
+	  }
+	}
+      }
+      nColumnZap=0;
+      if (nRowLook) {
+	for (int i=0;i<nRowLook;i++) {
+	  int iRow=rowLook[i];
+	  CoinBigIndex start = rowStart[iRow];
+	  CoinBigIndex end = start + rowLength[iRow];
+	  for (CoinBigIndex j=start;j<end;j++) {
+	    int iColumn = column[j];
+	    if (upper[iColumn]>lower[iColumn]&&
+		!model->isInteger(iColumn)) {
+	      if (!noGoodColumn[iColumn]) {
+		noGoodColumn[iColumn]=1;
+		columnZap[nColumnZap++]=iColumn;
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    delete [] rowLook;
+    delete [] noGoodColumn;
+    delete [] columnZap;
+    // Final look
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (upper[iColumn]>lower[iColumn]&&
+	  !model->isInteger(iColumn)&&objective[iColumn]) {
+	CoinBigIndex start = columnStart[iColumn];
+	CoinBigIndex end = start + columnLength[iColumn];
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  if (count[iRow]==999999) 
+	    allGood=false;
+	}
+      }
+    }
+    // do if some but not too many
+    if (nNew&&nNew<currentNumber) {
+      for (int i=0;i<nNew;i++) {
+	int iColumn = newInts[i];
+	double objValue = objective[iColumn];
+	bool thisGood=true;
+	CoinBigIndex start = columnStart[iColumn];
+	CoinBigIndex end = start + columnLength[iColumn];
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  if (count[iRow]==999999) {
+	    thisGood=false;
+	    break;
+	  }
+	} 
+	if (thisGood&&upper[iColumn]<lower[iColumn]+10.0) {
+	  model->setInteger(iColumn);
+	  if (objValue)
+	    numberNonZero++;
+	  else
+	    numberZero++; 
+	} else if (objValue) {
+	  // unable to fix all with obj
+	  allGood=false;
+	}
+      }
+    }
+    delete [] newInts;
+    // Can we look at remainder and make any integer
+    if (makeAll&&false) {
+      int nLook=0;
+      int nEl=0;
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	if (upper[iColumn]>lower[iColumn]&&!model->isInteger(iColumn)) {
+	  CoinBigIndex start = columnStart[iColumn];
+	  CoinBigIndex end = start + columnLength[iColumn];
+	  bool possible=true;
+	  int n=0;
+	  for (CoinBigIndex j=start;j<end;j++) {
+	    int iRow = row[j];
+	    if (count[iRow]>1) {
+	      if (count[iRow]==999999) {
+		possible=false;
+		break;
+	      } else {
+		n++;
+	      }
+	    }
+	  }
+	  if (possible) {
+	    nLook++;
+	    nEl+=n;
+	  }
+	}
+      }
+      if (nLook) {
+	int * startC = new int [nLook+1];
+	int * back = new int [nLook];
+	int * row2 = new int[nEl];
+	double * element2 = new double [nEl];
+	int * backRow = new int [numberRows];
+	int jRow;
+	for (jRow=0;jRow<numberRows;jRow++) {
+	  backRow[jRow]=-1;
+	}
+	int nCol=nLook;
+	nLook=0;
+	nEl=0;
+	startC[0]=0;
+	int nRow=0;
+	for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	  if (upper[iColumn]>lower[iColumn]&&!model->isInteger(iColumn)) {
+	    CoinBigIndex start = columnStart[iColumn];
+	    CoinBigIndex end = start + columnLength[iColumn];
+	    bool possible=true;
+	    int n=0;
+	    for (CoinBigIndex j=start;j<end;j++) {
+	      int iRow = row[j];
+	      if (count[iRow]>1) {
+		if (count[iRow]==999999) {
+		  possible=false;
+		  break;
+		} else {
+		  n++;
+		}
+	      }
+	    }
+	    if (!n)
+	      possible=false; // may be done later
+	    if (possible) {
+	      back[nLook]=iColumn;
+	      for (CoinBigIndex j=start;j<end;j++) {
+		int iRow = row[j];
+		if (count[iRow]>1) {
+		  int jRow=backRow[iRow];
+		  if (jRow<0) {
+		    // new row
+		    backRow[iRow]=nRow;
+		    jRow=nRow;
+		    nRow++;
+		  }
+		  element2[nEl]=element[j];
+		  row2[nEl++]=jRow;
+		}
+	      }
+	      nLook++;
+	      startC[nLook]=nEl;
+	    }
+	  }
+	}
+	// Redo nCol
+	nCol=nLook;
+	delete [] backRow;
+	int * startRow = new int [nRow+1];
+	int * column2 = new int [nEl];
+	// take out singletons and do row copy
+	outSingletons(nCol, nRow,
+		      startC, row2, element2,
+		      startRow, column2);
+	// Decompose
+	int * rowBlock = new int[nRow];
+	int * stack = new int [nRow];
+	for (int iRow=0;iRow<nRow;iRow++)
+	  rowBlock[iRow]=-2;
+	int numberBlocks = 0;
+	// to say if column looked at
+	int * columnBlock = new int[nCol];
+	int iColumn;
+	for (iColumn=0;iColumn<nCol;iColumn++)
+	  columnBlock[iColumn]=-2;
+	for (iColumn=0;iColumn<nCol;iColumn++) {
+	  int kstart = startC[iColumn];
+	  int kend = startC[iColumn+1];
+	  if (columnBlock[iColumn]==-2) {
+	    // column not allocated
+	    int j;
+	    int nstack=0;
+	    for (j=kstart;j<kend;j++) {
+	      int iRow= row2[j];
+	      if (rowBlock[iRow]!=-1) {
+		assert(rowBlock[iRow]==-2);
+		rowBlock[iRow]=numberBlocks; // mark
+		stack[nstack++] = iRow;
+	      }
+	    }
+	    if (nstack) {
+	      // new block - put all connected in
+	      numberBlocks++;
+	      columnBlock[iColumn]=numberBlocks-1;
+	      while (nstack) {
+		int iRow = stack[--nstack];
+		int k;
+		for (k=startRow[iRow];k<startRow[iRow+1];k++) {
+		  int iColumn = column2[k];
+		  int kkstart = startC[iColumn];
+		  int kkend = startC[iColumn+1];
+		  if (columnBlock[iColumn]==-2) {
+		    columnBlock[iColumn]=numberBlocks-1; // mark
+		    // column not allocated
+		    int jj;
+		    for (jj=kkstart;jj<kkend;jj++) {
+		      int jRow= row2[jj];
+		      if (rowBlock[jRow]==-2) {
+			rowBlock[jRow]=numberBlocks-1;
+			stack[nstack++]=jRow;
+		      }
+		    }
+		  } else {
+		    assert (columnBlock[iColumn]==numberBlocks-1);
+		  }
+		}
+	      }
+	    } else {
+	      // Only in master
+	      columnBlock[iColumn]=-1;
+	      // empty - should already be integer
+	      abort();
+	    }
+	  }
+	}
+	// See if each block OK 
+	for (int iBlock=0;iBlock<numberBlocks;iBlock++) {
+	  // Get block
+	  int * startCB = new int [nCol+1];
+	  int * row2B = new int[nEl];
+	  int * startCC = new int [nCol+1];
+	  int * row2C = new int[nEl];
+	  int * startRowC = new int [nRow+1];
+	  int * column2C = new int [nEl];
+	  int * whichRow = new int [nRow];
+	  int * whichCol = new int [nCol];
+	  int i;
+	  int nRowB=0;
+	  int nColB=0;
+	  int nElB=0;
+	  for (i=0;i<nRow;i++) {
+	    if (rowBlock[i]==iBlock) {
+	      whichRow[i]=nRowB;
+	      nRowB++;
+	    } else {
+	      whichRow[i]=-1;
+	    }
+	  }
+	  bool network=true;
+	  // even if not network - take out network columns NO
+	  startCB[0]=0;
+	  for (i=0;i<nCol;i++) {
+	    if (columnBlock[i]==iBlock) {
+	      int type=0;
+	      whichCol[i]=nColB;
+	      for (int j=startC[i];j<startC[i+1];j++) {
+		int iRow = row2[j];
+		iRow = whichRow[iRow];
+		if (iRow>=0) { 
+		  if (element2[j]==1.0) {
+		    if ((type&1)==0)
+		      type |=1;
+		    else 
+		      type=7;
+		  } else {
+		    assert (element2[j]==-1.0);
+		    if ((type&2)==0)
+		      type |=2;
+		    else 
+		      type=7;
+		  }
+		  row2B[nElB++]=iRow;
+		}
+	      }
+	      if (type!=3) 
+		network=false;
+	      nColB++;
+	      startCB[nColB]=nElB;
+	      assert (startCB[nColB]>startCB[nColB-1]+1);
+	    } else {
+	      whichCol[i]=-1;
+	    }
+	  }
+	  // See if network
+	  bool goodInteger=false;
+	  if (!network) {
+	    // take out singletons
+	    outSingletons(nColB, nRowB,
+			  startCB, row2B, NULL,
+			  startRowC, column2C);
+	    // See if totally balanced;
+	    int * split = new int [nRowB];
+	    int * best = new int[nRowB];
+	    int * current = new int [nRowB];
+	    int * size = new int [nRowB];
+	    {
+	      memset(size,0,nRowB*sizeof(int));
+	      for (i=0;i<nColB;i++) {
+		int j;
+		for (j=startCB[i];j<startCB[i+1];j++) {
+		  int iRow = row2B[j];
+		  size[iRow]++;
+		}
+	      }
+	      for (i=0;i<nRowB;i++)
+		if (size[i]<2)
+		  printf("%d entries in row %d\n",size[i],i);
+	    }
+	    for (i=0;i<nColB;i++)
+	      whichCol[i]=i;
+	    for (i=0;i<nRowB;i++)
+	      whichRow[i]=0;
+	    int nLeft=nColB;
+	    int nSet=1;
+	    size[0]=nRowB;
+	    while (nLeft) {
+	      // find best column
+	      int iBest=-1;
+	      memset(best,0,nSet*sizeof(int));
+	      memset(current,0,nSet*sizeof(int));
+	      for (i=0;i<nColB;i++) {
+		if (whichCol[i]<nLeft) {
+		  int j;
+		  for (j=startCB[i];j<startCB[i+1];j++) {
+		    int iRow = row2B[j];
+		    int iSet=whichRow[iRow];
+		    current[iSet]++;
+		  }
+		  // See if better - could this be done faster
+		  bool better=false;
+		  for (j=nSet-1;j>=0;j--) {
+		    if (current[j]>best[j]) {
+		      better=true;
+		      break;
+		    } else if (current[j]<best[j]) {
+		      break;
+		    }
+		  }
+		  if (better) {
+		    iBest=i;
+		    memcpy(best,current,nSet*sizeof(int));
+		  }
+		  for (j=startCB[i];j<startCB[i+1];j++) {
+		    int iRow = row2B[j];
+		    int iSet=whichRow[iRow];
+		    current[iSet]=0;
+		  }
+		}
+	      }
+	      assert (iBest>=0);
+	      // swap
+	      for (i=0;i<nColB;i++) {
+		if (whichCol[i]==nLeft-1) {
+		  whichCol[i]=whichCol[iBest];
+		  whichCol[iBest]=nLeft-1;
+		  break;
+		}
+	      }
+	      // See which ones will have to split
+	      int nMore=0;
+	      for (i=0;i<nSet;i++) {
+		current[i]=i+nMore;
+		if (best[i]>0&&best[i]<size[i]) {
+		  split[i]=i+nMore;
+		  nMore++;
+		} else {
+		  split[i]=-1;
+		}
+	      }
+	      if (nMore) {
+		int j;
+		for (j=startCB[iBest];j<startCB[iBest+1];j++) {
+		  int iRow = row2B[j];
+		  int iSet=whichRow[iRow];
+		  int newSet = split[iSet];
+		  if (newSet>=0) {
+		    whichRow[iRow]=newSet+1+nRowB;
+		  }
+		}
+		nSet += nMore;
+		memset(size,0,nSet*sizeof(int));
+		for (i=0;i<nRowB;i++) {
+		  int iSet = whichRow[i];
+		  if (iSet>=nRowB) {
+		    // has 1 - correct it
+		    iSet -= nRowB;
+		  } else {
+		    // 0 part of split set or not split
+		    iSet=current[iSet];
+		  }
+		  whichRow[i]=iSet;
+		  size[iSet]++;
+		}
+	      }
+	      nLeft--;
+	    }
+	    if (nSet<nRowB) {
+	      // ties - need to spread out whichRow
+	      memset(split,0,nRowB*sizeof(int));
+	      for (i=0;i<nRowB;i++) {
+		int iSet = whichRow[i];
+		split[iSet]++;
+	      }
+	      current[0]=0;
+	      for (i=0;i<nSet;i++) {
+		current[i+1]=current[i]+split[i];
+		split[i]=current[i];
+	      }
+	      for (i=0;i<nRowB;i++) {
+		int iSet = whichRow[i];
+		int k = split[iSet];
+		split[iSet]=k;
+		whichRow[i]=k;
+	      }
+	    }
+	    // Get inverse of whichCol
+	    for (i=0;i<nColB;i++) {
+	      int iColumn = whichCol[i];
+	      startCC[iColumn]=i;
+	    }
+	    memcpy(whichCol,startCC,nColB*sizeof(int));
+	    // Permute matrix
+	    startCC[0]=0;
+	    int nelB=0;
+	    memset(split,0,nRowB*sizeof(int));
+	    for (i=0;i<nColB;i++) {
+	      int iColumn = whichCol[i];
+	      int j;
+	      for (j=startCB[iColumn];j<startCB[iColumn+1];j++) {
+		int iRow = row2B[j];
+		int iSet=whichRow[iRow];
+		row2C[nelB++]=iSet;
+		split[iSet]++;
+	      }
+	      startCC[i+1]=nelB;
+	    }
+	    startRowC[0]=0;
+	    for (i=0;i<nRowB;i++) {
+	      startRowC[i+1]=startRowC[i]+split[i];
+	      split[i]=0;
+	    }
+	    for (i=0;i<nColB;i++) {
+	      int j;
+	      for (j=startCC[i];j<startCC[i+1];j++) {
+		int iRow = row2C[j];
+		int k=split[iRow]+startRowC[iRow];
+		split[iRow]++;
+		column2C[k]=i;
+	      }
+	    }
+	    for (i=0;i<nRowB;i++)
+	      split[i]=0;
+	    goodInteger=true;
+	    for (i=nColB-1;i>0;i--) {
+	      int j;
+	      for (j=startCC[i];j<startCC[i+1];j++) {
+		int iRow = row2C[j];
+		split[iRow]=1;
+	      }
+	      for (j=startCC[i];j<startCC[i+1];j++) {
+		int iRow = row2C[j];
+		for (int k=startRowC[iRow];k<startRowC[iRow+1];k++) {
+		  int iColumn = column2C[k];
+		  if (iColumn<i) {
+		    for (int jj=startCC[iColumn];jj<startCC[iColumn+1];jj++) {
+		      int jRow = row2C[jj];
+		      if (jRow>iRow&&!split[jRow]) {
+			// bad
+			goodInteger=false;
+			break;
+		      }
+		    }
+		  }
+		}
+	      }
+	      if (!goodInteger)
+		break;
+	      for (j=startCC[i];j<startCC[i+1];j++) {
+		int iRow = row2C[j];
+		split[iRow]=0;
+	      }
+	    }
+	    delete [] split;
+	    delete [] best;
+	    delete [] current;
+	    delete [] size;
+	  } else {
+	    // was network
+	    goodInteger=true;
+	  }
+	  if (goodInteger) {
+	    printf("Block %d can be integer\n",iBlock);
+	    for (i=0;i<nCol;i++) {
+	      if (columnBlock[i]==iBlock) {
+		int iBack = back[i];
+		model->setInteger(iBack);
+	      }
+	    }
+	  }
+	  delete [] startRowC;
+	  delete [] column2C;
+	  delete [] startCB;
+	  delete [] row2B;
+	  delete [] startCC;
+	  delete [] row2C;
+	  delete [] whichRow;
+	  delete [] whichCol;
+	}
+	delete [] startRow;
+	delete [] column2;
+	delete [] element2;
+	delete [] startC;
+	delete [] row2;
+	delete [] back;
+      }
+    }
+    numberIntegers=numberNonZero;
+    if (allGood&&numberObj) {
+#ifdef COIN_DEVELOP
+      int numberPossible = 0;
+#endif
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	if (upper[iColumn]>lower[iColumn]&&objective[iColumn]&&!model->isInteger(iColumn)) {
+#ifdef COIN_DEVELOP
+	  numberPossible++;
+#endif
+	  if (upper[iColumn]<=lower[iColumn]+10) {
+	    model->setInteger(iColumn);
+	    numberIntegers++;
+	  }
+	}
+      }
+#ifdef COIN_DEVELOP
+      printf("ZZZZYY CglPreProcess analysis says all (%d) continuous with costs could be made integer - %d were\n",numberPossible,numberIntegers-numberNonZero);
+#endif
+    }
+#ifdef COIN_DEVELOP
+    if (numberZero)
+      printf("ZZZZYY %d continuous with zero cost were made integer\n",numberZero);
+#endif
+    numberIntegers += numberZero;
+#ifdef COIN_DEVELOP
+    if (numberEq||numberEqI)
+      printf("ZZZZYY %d rows made equality from continuous, %d from integer\n",numberEq,numberEqI);
+#endif
+    totalNumberIntegers += numberIntegers;
+    if (!makeAll)
+      numberIntegers=0;
+  }
+  delete [] rhs;
+  delete [] count;
+  return (totalNumberIntegers);
+}
+//#define CGL_WRITEMPS 
+#ifdef CGL_WRITEMPS
+extern double * debugSolution;
+extern int debugNumberColumns;
+static int mpsNumber=0;
+static void writeDebugMps(const OsiSolverInterface * solver,
+			  const char * where,
+			  OsiPresolve * pinfo)
+{ 
+  mpsNumber++;
+  char name[20];
+  sprintf(name,"presolve%2.2d.mps",mpsNumber);
+  printf("saving %s from %s\n",name,where);
+  solver->writeMpsNative(name,NULL,NULL,0,1,0);
+  if (pinfo&&debugSolution) {
+    int n = solver->getNumCols();
+    if (n<debugNumberColumns) {
+      const int * original = pinfo->originalColumns();
+      if (!original) {
+	printf("No original columns\n");
+	abort();
+      }
+      for (int i=0;i<n;i++) 
+	debugSolution[i]=debugSolution[original[i]];
+      debugNumberColumns=n;
+    }
+  }
+  if (debugSolution) {
+    OsiSolverInterface * newSolver = solver->clone();
+    const double * lower = newSolver->getColLower();
+    const double * upper = newSolver->getColUpper();
+    for (int i = 0; i<debugNumberColumns;i++) {
+      if (newSolver->isInteger(i)) {
+	double value = floor(debugSolution[i]+0.5);
+	if (value<lower[i]||value>upper[i]) {
+	  printf("Bad value %d - %g %g %g\n",i,lower[i],debugSolution[i],
+		 upper[i]);
+	} else {
+	  newSolver->setColLower(i,value);
+	  newSolver->setColUpper(i,value);
+	}
+      }
+    }
+    printf("Starting solve %d\n",mpsNumber);
+    newSolver->resolve();
+    printf("Ending solve %d - status %s obj %g\n",mpsNumber,
+	   newSolver->isProvenOptimal() ? "ok" : "bad",
+	   newSolver->getObjValue());
+    delete newSolver;
+  }
+}
+#else
+#define writeDebugMps(x,y,z)
+#endif
+OsiSolverInterface *
+CglPreProcess::preProcessNonDefault(OsiSolverInterface & model, 
+				    int makeEquality, int numberPasses,
+				    int tuning)
+{
+#if 0
+   bool rcdActive = true ;
+   std::string modelName ;
+   model.getStrParam(OsiProbName,modelName) ;
+   std::cout
+     << "  Attempting to activate row cut debugger for "
+     << modelName << " ... " ;
+   writeDebugMps(&model,"IPP:preProcessNonDefault",0) ;
+   model.activateRowCutDebugger(modelName.c_str()) ;
+   if (model.getRowCutDebugger())
+     std::cout << "on optimal path." << std::endl ;
+   else if (model.getRowCutDebuggerAlways())
+     std::cout << "not on optimal path." << std::endl ;
+   else {
+     std::cout << "failure." << std::endl ;
+     rcdActive = false ;
+   }
+   if (rcdActive) {
+     const OsiRowCutDebugger *debugger = model.getRowCutDebuggerAlways() ;
+     std::cout << "  Optimal solution is:" << std::endl ;
+     debugger->printOptimalSolution(model) ;
+   }
+# endif
+  originalModel_ = & model;
+  numberSolvers_ = numberPasses;
+  model_ = new OsiSolverInterface * [numberSolvers_];
+  modifiedModel_ = new OsiSolverInterface * [numberSolvers_];
+  presolve_ = new OsiPresolve * [numberSolvers_];
+  for (int i=0;i<numberSolvers_;i++) {
+    model_[i]=NULL;
+    modifiedModel_[i]=NULL;
+    presolve_[i]=NULL;
+  }
+  // Put presolve option on
+  tuning |= 8;
+  // clear original
+  delete [] originalColumn_;
+  delete [] originalRow_;
+  originalColumn_=NULL;
+  originalRow_=NULL;
+  //startModel_=&model;
+  // make clone
+  delete startModel_;
+  startModel_ = originalModel_->clone();
+  CoinPackedMatrix matrixByRow(*originalModel_->getMatrixByRow());
+  int numberRows = originalModel_->getNumRows();
+  if (rowType_)
+    assert (numberRowType_==numberRows);
+  int numberColumns = originalModel_->getNumCols();
+  //int originalNumberColumns=numberColumns;
+  int minimumLength = 5;
+  int numberModifiedPasses=10;
+  if (numberPasses<=1)
+    numberModifiedPasses=1; // lightweight preprocessing
+  else if (numberPasses<=2)
+    numberModifiedPasses=2; // fairly lightweight preprocessing
+  if (tuning>=10000) {
+    numberModifiedPasses=(tuning-10000)/10000;
+    tuning %= 10000;
+    //minimumLength = tuning;
+  }
+  //bool heavyProbing = (tuning&1)!=0;
+  int makeIntegers = (tuning&6)>>1;
+  // See if we want to do initial presolve
+  int doInitialPresolve = (tuning&8)>>3;
+  if (numberSolvers_<2)
+    doInitialPresolve=0;
+  // We want to add columns
+  int numberSlacks=0;
+  int * rows = new int[numberRows];
+  double * element =new double[numberRows];
+  
+  int iRow;
+  
+  int numberCliques=0;
+  int * which = new int[numberColumns];
+
+  // Statistics
+  int totalP1=0,totalM1=0;
+  int numberFixed=0;
+  // May just find it is infeasible
+  bool feasible=true;
+  
+  // Row copy
+  const double * elementByRow = matrixByRow.getElements();
+  const int * column = matrixByRow.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  const int * rowLength = matrixByRow.getVectorLengths();
+  
+  const double * lower = originalModel_->getColLower();
+  const double * upper = originalModel_->getColUpper();
+  const double * rowLower = originalModel_->getRowLower();
+  const double * rowUpper = originalModel_->getRowUpper();
+  // Clean bounds
+  int iColumn;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (originalModel_->isInteger(iColumn)) {
+      double lo = CoinMax(lower[iColumn],ceil(lower[iColumn]-1.0e-6));
+      if (lo>lower[iColumn])
+	originalModel_->setColLower(iColumn,lo);
+      double up = CoinMin(upper[iColumn],floor(upper[iColumn]+1.0e-6));
+      if (up<upper[iColumn])
+	originalModel_->setColUpper(iColumn,up);
+      if (lo>up)
+	feasible=false;
+    }
+  }
+  bool allToGub = makeEquality==5;
+  if (allToGub)
+    makeEquality=3;
+  // Initialize random seed
+  CoinThreadRandom randomGenerator(987654321);
+  bool justOnesWithObj=false;
+  if (makeEquality==2||makeEquality==3||makeEquality==4) {
+    int iRow, iColumn;
+    int numberIntegers = 0;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (originalModel_->isInteger(iColumn))
+        numberIntegers++;
+    }
+    // Look for possible SOS
+    int numberSOS=0;
+    int * mark = new int[numberColumns];
+    CoinFillN(mark,numberColumns,-1);
+    int numberOverlap=0;
+    int numberInSOS=0;
+    // See if worthwhile creating accumulation variables
+    int firstOther=numberRows;
+    int * whichRow = new int[numberRows];
+    for (iRow=0;iRow<numberRows;iRow++) {
+      if (rowUpper[iRow]==1.0) {
+        if (rowLength[iRow]<5)
+          continue;
+        bool goodRow=true;
+	bool overlap=false;
+        for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+          int iColumn = column[j];
+          if (elementByRow[j]!=1.0||!originalModel_->isInteger(iColumn)||lower[iColumn]) {
+            goodRow=false;
+            break;
+          }
+          if (mark[iColumn]>=0) {
+            overlap=true;
+            numberOverlap++;
+          }
+        }
+        if (goodRow) {
+	  if (!overlap) {
+	    // mark all
+	    for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	      int iColumn = column[j];
+	      mark[iColumn]=numberSOS;
+	    }
+	    numberSOS++;
+	    numberInSOS += rowLength[iRow];
+	  }
+	  // May still be interesting even if overlap
+	  if (rowLength[iRow]>=5) {
+	    firstOther--;
+	    whichRow[firstOther]=iRow;
+	  }
+        }
+      }
+    }
+    if (makeEquality==2&&false) {
+      if(numberOverlap||numberIntegers>numberInSOS+1) {
+	// try just ones with costs
+	CoinFillN(mark,numberColumns,-1);
+	numberOverlap=0;
+	numberInSOS=0;
+	bool allCostsInSOS=true;
+	const double *objective = originalModel_->getObjCoefficients() ;
+	for (iRow=0;iRow<numberRows;iRow++) {
+	  if (rowUpper[iRow]==1.0&&rowLength[iRow]>=5) {
+	    bool goodRow=true;
+	    bool overlap=false;
+	    int nObj=0;
+	    for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	      int iColumn = column[j];
+	      if (elementByRow[j]!=1.0||!originalModel_->isInteger(iColumn)||lower[iColumn]) {
+		goodRow=false;
+	      }
+	      if (objective[iColumn])
+		nObj++;
+	      if (mark[iColumn]>=0) {
+		overlap=true;
+		numberOverlap++;
+	      }
+	    }
+	    if (nObj&&nObj>=rowLength[iRow]-1) {
+	      if (goodRow) {
+		if (!overlap) {
+		  // mark all
+		  for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+		    int iColumn = column[j];
+		    mark[iColumn]=numberSOS;
+		  }
+		  numberSOS++;
+		  numberInSOS += rowLength[iRow];
+		}
+	      } else {
+		// no good
+		allCostsInSOS=false;
+	      }
+	    }
+	  }
+	}
+	if (numberInSOS&&allCostsInSOS) {
+	  int nGoodObj=0;
+	  int nBadObj=0;
+	  for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+	    if (objective[iColumn]) {
+	      if (mark[iColumn]>=0)
+		nGoodObj++;
+	      else
+		nBadObj++;
+	    }
+	  }
+	  if (nBadObj*10<nGoodObj) {
+	    justOnesWithObj=true;
+	    makeEquality=3;
+#ifdef CLP_INVESTIGATE
+	    printf("trying SOS as all costs there\n");
+#endif
+	  }
+	}
+      }
+    }
+    if (firstOther<numberRows&&makeEquality==4) {
+      CoinPackedMatrix * matrixByColumn = const_cast<CoinPackedMatrix *>(startModel_->getMatrixByCol());
+      // Column copy
+      const int * row = matrixByColumn->getIndices();
+      const CoinBigIndex * columnStart = matrixByColumn->getVectorStarts();
+      const int * columnLength = matrixByColumn->getVectorLengths(); 
+      double * columnElements = matrixByColumn->getMutableElements();
+      int * rowCount = new int[numberRows];
+      memset(rowCount,0,numberRows*sizeof(int));
+      double * rowValue = new double [numberRows];
+      int numberY=0;
+      int numberElements=0;
+      int numberSOS=0;
+      for (int kRow=firstOther;kRow<numberRows;kRow++) {
+	int iRow=whichRow[kRow];
+	int n=0;
+	int j;
+	for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	  int iColumn = column[j];
+	  for (int k=columnStart[iColumn];k<columnStart[iColumn]+columnLength[iColumn];
+	       k++) {
+	    int jRow = row[k];
+	    double value = columnElements[k];
+	    if (jRow!=iRow) {
+	      if (rowCount[jRow]>0) {
+		if (value!=rowValue[jRow])
+		  rowCount[jRow]=-1; // no good
+		else
+		  rowCount[jRow]++;
+	      } else if (!rowCount[jRow]) {
+		whichRow[n++]=jRow;
+		rowCount[jRow]=1;
+		rowValue[jRow]=value;
+	      }
+	    }
+	  }
+	}
+	int bestRow=-1;
+	int bestCount=4;
+	for (j=0;j<n;j++) {
+	  int jRow = whichRow[j];
+	  int count=rowCount[jRow];
+	  rowCount[jRow]=0;
+	  if (count>=5) {
+	    numberY++;
+	    numberElements+=count;
+	  }
+	  if (count>bestCount) {
+	    // possible
+	    bestRow=jRow;
+	    bestCount=count;
+	  }
+	}
+	if (bestRow>=0) {
+	  numberSOS++;
+	  numberY++;
+	  numberElements+=bestCount;
+	}
+      }
+      if (numberY) {
+	// Some may be duplicates
+	// make sure ordered
+	matrixByRow.orderMatrix();
+	elementByRow = matrixByRow.getElements();
+	column = matrixByRow.getIndices();
+	rowStart = matrixByRow.getVectorStarts();
+	rowLength = matrixByRow.getVectorLengths();
+	CoinBigIndex * newStart = new CoinBigIndex[numberY+1];
+	int * newColumn = new int [numberElements];
+	double * newValue = new double [numberElements];
+	double * hash = new double [numberY];
+	double * hashColumn = new double [numberColumns];
+	int i;
+	for (i=0;i<numberColumns;i++)
+	  hashColumn[i]=randomGenerator.randomDouble();
+	double * valueY = new double [3*numberY];
+	int * rowY = new int [3*numberY];
+	int * columnY = new int[3*numberY];
+	// For new solution
+	double * newSolution = new double [numberColumns+numberY];
+	memcpy(newSolution,startModel_->getColSolution(),numberColumns*sizeof(double));
+	memset(rowCount,0,numberRows*sizeof(int));
+	// List of SOS entries to zero out
+	CoinBigIndex * where = new CoinBigIndex[numberColumns];
+	numberY=0;
+	numberElements=0;
+	int numberElementsY=0;
+	newStart[0]=0;
+	for (int kRow=firstOther;kRow<numberRows;kRow++) {
+	  int iRow=whichRow[kRow];
+	  int n=0;
+	  int j;
+	  int saveNumberY=numberY;
+	  for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	    int iColumn = column[j];
+	    for (int k=columnStart[iColumn];k<columnStart[iColumn]+columnLength[iColumn];
+		 k++) {
+	      int jRow = row[k];
+	      double value = columnElements[k];
+	      if (jRow!=iRow) {
+		if (rowCount[jRow]>0) {
+		  if (value!=rowValue[jRow])
+		    rowCount[jRow]=-1; // no good
+		  else
+		    rowCount[jRow]++;
+		} else if (!rowCount[jRow]) {
+		  whichRow[n++]=jRow;
+		  rowCount[jRow]=1;
+		  rowValue[jRow]=value;
+		  assert (value);
+		}
+	      }
+	    }
+	  }
+	  for (i=0;i<n;i++) {
+	    // Sort so fewest first
+	    std::sort(whichRow,whichRow+n);
+	    int jRow = whichRow[i];
+	    int count=rowCount[jRow];
+	    rowCount[jRow]=0;
+	    if (count>=5) {
+	      //assert (count<rowLength[jRow]); // not error - just need to think
+	      // mark so not looked at again
+	      rowCount[jRow]=-count;
+	      // form new row
+	      double value=0.0;
+	      double hashValue=0.0;
+	      int nInSOS=0;
+	      double valueOfY=0.0;
+	      for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+		int iColumn = column[j];
+		for (int k=columnStart[iColumn];k<columnStart[iColumn]+columnLength[iColumn];
+		     k++) {
+		  if (row[k]==jRow) {
+		    value = columnElements[k];
+		    newColumn[numberElements]=iColumn;
+		    newValue[numberElements++]=1.0;
+		    hashValue += hashColumn[iColumn];
+		    columnElements[k]=0.0;
+		    valueOfY += newSolution[iColumn];
+		  } else if (row[k]==iRow) {
+		    if (columnElements[k])
+		      where[nInSOS++]=k;
+		  }
+		}
+	      }
+	      // See if already exists
+	      int n=numberElements-newStart[numberY];
+	      for (j=0;j<numberY;j++) {
+		if (hashValue==hash[j]) {
+		  // Double check
+		  int offset=newStart[numberY]-newStart[j];
+		  if (n==newStart[j+1]-newStart[j]) {
+		    int k;
+		    for (k=newStart[j];k<newStart[j]+n;k++) {
+		      if (newColumn[k]!=newColumn[k+offset])
+			break;
+		    }
+		    if (k==newStart[j+1])
+		      break;
+		  }
+		}
+	      }
+	      if (j==numberY) {
+		// not duplicate
+		newSolution[numberY+numberColumns]=valueOfY;
+		numberY++;
+		newStart[numberY]=numberElements;
+		hash[j]=hashValue;
+		// Now do -1
+		rowY[numberElementsY]=j+numberRows;
+		columnY[numberElementsY]=j;
+		valueY[numberElementsY++]=-1;
+		if (n==nInSOS) {
+		  // SOS entry
+		  rowY[numberElementsY]=iRow;
+		  columnY[numberElementsY]=j;
+		  valueY[numberElementsY++]=1;
+		  for (int i=0;i<n;i++) {
+		    int iEl = where[i];
+		    columnElements[iEl]=0.0;
+		  }
+		}
+	      } else {
+		// duplicate
+		numberElements=newStart[numberY];
+	      }
+	      // Now do 
+	      rowY[numberElementsY]=jRow;
+	      columnY[numberElementsY]=j;
+	      valueY[numberElementsY++]=value;
+	    }
+	  }
+	  if (numberY>saveNumberY)
+	    rowCount[iRow]=-1000;
+	}
+	delete [] hash;
+	delete [] hashColumn;
+	matrixByColumn->cleanMatrix();
+	// Now add rows
+	double * rhs = new double[numberY];
+	memset(rhs,0,numberY*sizeof(double));
+	startModel_->addRows(numberY,newStart,newColumn,newValue,rhs,rhs);
+	delete [] rhs;
+	delete [] newStart;
+	delete [] newColumn;
+	delete [] newValue;
+	delete [] where;
+	// Redo matrix
+	CoinPackedMatrix add(true,rowY,columnY,valueY,numberElementsY);
+	delete [] valueY;
+	delete [] rowY;
+	delete [] columnY;
+	const int * row = add.getIndices();
+	const CoinBigIndex * columnStart = add.getVectorStarts();
+	//const int * columnLength = add.getVectorLengths(); 
+	double * columnElements = add.getMutableElements();
+	double * lo = new double [numberY];
+	double * up = new double [numberY];
+	for (i=0;i<numberY;i++) {
+	  lo[i]=0.0;
+	  up[i]=1.0;
+	}
+	startModel_->addCols(numberY,columnStart,row,columnElements,lo,up,NULL);
+	delete [] lo;
+	delete [] up;
+	for (i=0;i<numberY;i++) 
+	  startModel_->setInteger(i+numberColumns);
+	CoinWarmStartBasis* basis =
+	  dynamic_cast <CoinWarmStartBasis*>(startModel_->getWarmStart()) ;
+	if (basis) {
+	  for (i=0;i<numberY;i++) {
+	    basis->setArtifStatus(i+numberRows,CoinWarmStartBasis::atLowerBound);
+	    basis->setStructStatus(i+numberColumns,CoinWarmStartBasis::basic);
+	  }
+	  startModel_->setWarmStart(basis);
+	  delete basis;
+	}
+	startModel_->setColSolution(newSolution);
+	delete [] newSolution;
+	writeDebugMps(startModel_,"start",NULL);
+	if (numberElements<10*CoinMin(numberColumns,100*numberY)) {
+	  handler_->message(CGL_ADDED_INTEGERS,messages_)
+	    <<numberY<<numberSOS<<numberElements
+	    <<CoinMessageEol;
+	  numberColumns += numberY;
+	  bool saveTakeHint;
+	  OsiHintStrength saveStrength;
+	  startModel_->getHintParam(OsiDoDualInResolve,
+			      saveTakeHint,saveStrength);
+	  startModel_->setHintParam(OsiDoDualInResolve,false,OsiHintTry);
+	  startModel_->resolve();
+	  numberIterationsPre_ += startModel_->getIterationCount();
+	  startModel_->setHintParam(OsiDoDualInResolve,saveTakeHint,saveStrength);
+	} else {
+	  // not such a good idea?
+	  delete startModel_;
+	  startModel_=NULL;
+	}
+      }
+      delete [] rowValue;
+      delete [] rowCount;
+    }
+    if (makeEquality==4) {
+      makeEquality=0;
+#if 1
+      // Try and make continuous variables integer
+      // make clone
+      if (!startModel_)
+	startModel_ = originalModel_->clone();
+      makeInteger();
+#endif
+    }
+    delete [] whichRow;
+    delete [] mark;
+    if (numberSOS) {
+      if (makeEquality==2) {
+	if(numberOverlap||numberIntegers>numberInSOS+1) {
+	  handler_->message(CGL_PROCESS_SOS2,messages_)
+	    <<numberSOS<<numberInSOS<<numberIntegers<<numberOverlap
+	    <<CoinMessageEol;
+	  makeEquality=0;
+	}
+      }
+    } else {
+      // no sos
+      makeEquality=0;
+    }
+  }
+  if (startModel_) {
+    lower = originalModel_->getColLower();
+    upper = originalModel_->getColUpper();
+    rowLower = originalModel_->getRowLower();
+    rowUpper = originalModel_->getRowUpper();
+  }
+  // See if all + 1
+  bool allPlusOnes=true;
+  int nPossible=0;
+  int numberMadeEquality=0;
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int numberP1=0, numberM1=0;
+    int numberTotal=0;
+    int j;
+    double upperValue=rowUpper[iRow];
+    double lowerValue=rowLower[iRow];
+    bool good=true;
+    bool possibleSlack=true;
+    bool allPlus=true;
+    for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+      int iColumn = column[j];
+      double value = elementByRow[j];
+      if (upper[iColumn]-lower[iColumn]<1.0e-8) {
+        // fixed
+        upperValue -= lower[iColumn]*value;
+        lowerValue -= lower[iColumn]*value;
+        continue;
+      } else if (!originalModel_->isBinary(iColumn)) {
+        good = false;
+	possibleSlack=false;
+        //break;
+      } else {
+	numberTotal++;
+      }
+      
+      if (fabs(value-floor(value+0.5))>1.0e-12)
+	possibleSlack=false;;
+      if (fabs(value)!=1.0) {
+        good=false;
+        allPlus=false;
+      } else if (value>0.0) {
+        which[numberP1++]=iColumn;
+      } else {
+        numberM1++;
+        which[numberColumns-numberM1]=iColumn;
+        allPlus=false;
+      }
+    }
+    if (possibleSlack) {
+      if(upperValue>1.0e20&&lowerValue>-1.0e12) {
+	possibleSlack =  (fabs(lowerValue-floor(lowerValue+0.5))<1.0e-12);
+      } else if(lowerValue<-1.0e20&&upperValue<1.0e12) {
+	possibleSlack =  (fabs(upperValue-floor(upperValue+0.5))<1.0e-12);
+      } else {
+	possibleSlack=false;
+      }
+    }
+    if (allPlus)
+      nPossible++;
+    int iUpper = static_cast<int> (floor(upperValue+1.0e-5));
+    int iLower = static_cast<int> (ceil(lowerValue-1.0e-5));
+    int state=0;
+    if (upperValue<1.0e6) {
+      if (iUpper==1-numberM1)
+        state=1;
+      else if (iUpper==-numberM1)
+        state=2;
+      else if (iUpper<-numberM1)
+        state=3;
+      if (fabs((static_cast<double> (iUpper))-upperValue)>1.0e-9)
+        state =-1;
+    }
+    if (!state&&lowerValue>-1.0e6) {
+      if (-iLower==1-numberP1)
+        state=-1;
+      else if (-iLower==-numberP1)
+        state=-2;
+      else if (-iLower<-numberP1)
+        state=-3;
+      if (fabs((static_cast<double> (iLower))-lowerValue)>1.0e-9)
+        state =-1;
+    }
+    if (good&&state>0) {
+      if (abs(state)==3) {
+        // infeasible
+        feasible=false;
+        break;
+      } else if (abs(state)==2) {
+        // we can fix all
+        numberFixed += numberP1+numberM1;
+        int i;
+        if (state>0) {
+          // fix all +1 at 0, -1 at 1
+          for (i=0;i<numberP1;i++)
+            originalModel_->setColUpper(which[i],0.0);
+          for (i=0;i<numberM1;i++)
+            originalModel_->setColLower(which[numberColumns-i-1],1.0);
+        } else {
+          // fix all +1 at 1, -1 at 0
+          for (i=0;i<numberP1;i++)
+            originalModel_->setColLower(which[i],1.0);
+          for (i=0;i<numberM1;i++)
+            originalModel_->setColUpper(which[numberColumns-i-1],0.0);
+        }
+      } else {
+        if (!makeEquality||(makeEquality==-1&&numberM1+numberP1<minimumLength))
+          continue;
+        if (makeEquality==2||makeEquality==3) {
+          if (numberM1||numberP1<minimumLength) 
+            continue;
+        }
+        numberCliques++;
+        if (iLower!=iUpper) {
+          element[numberSlacks]=state;
+          rows[numberSlacks++]=iRow;
+        }
+        if (state>0) {
+          totalP1 += numberP1;
+          totalM1 += numberM1;
+        } else {
+          totalP1 += numberM1;
+          totalM1 += numberP1;
+        }
+      }
+    }
+    if (possibleSlack&&makeEquality==-2&&(!good||state<=0)) {
+      if (numberTotal<minimumLength)
+	continue;
+      numberMadeEquality++;
+      element[numberSlacks] = (upperValue<1.0e10) ? 1.0 : -1.0; 
+      rows[numberSlacks++]=iRow+numberRows;
+    }
+  }
+  // allow if some +1's
+  allPlusOnes = 10*nPossible>numberRows;
+  delete [] which;
+  if (!feasible) {
+    handler_->message(CGL_INFEASIBLE,messages_)
+      <<CoinMessageEol;
+    delete [] rows;
+    delete [] element;
+    return NULL;
+  } else {
+    if (numberCliques) {
+      handler_->message(CGL_CLIQUES,messages_)
+        <<numberCliques
+        << (static_cast<double>(totalP1+totalM1))/
+	(static_cast<double> (numberCliques))
+        <<CoinMessageEol;
+      //printf("%d of these could be converted to equality constraints\n",
+      //     numberSlacks);
+    }
+    if (numberFixed)
+      handler_->message(CGL_FIXED,messages_)
+        <<numberFixed
+        <<CoinMessageEol;
+  }
+  if (numberSlacks&&makeEquality&&!justOnesWithObj) {
+    handler_->message(CGL_SLACKS,messages_)
+      <<numberSlacks
+      <<CoinMessageEol;
+    // add variables to make equality rows
+    // Get new model
+    if (!startModel_) {
+      assert (!startModel_);
+      startModel_ = originalModel_->clone();
+    }
+    for (int i=0;i<numberSlacks;i++) {
+      int iRow = rows[i];
+      double value = element[i];
+      double lowerValue = 0.0;
+      double upperValue = 1.0;
+      double objValue  = 0.0;
+      if (iRow>=numberRows) {
+	// just a slack not a clique
+	upperValue=COIN_DBL_MAX;
+	iRow -= numberRows;
+      }
+      CoinPackedVector column(1,&iRow,&value);
+      startModel_->addCol(column,lowerValue,upperValue,objValue);
+      // set integer
+      startModel_->setInteger(numberColumns+i);
+      if (value >0)
+	startModel_->setRowLower(iRow,rowUpper[iRow]);
+      else
+	startModel_->setRowUpper(iRow,rowLower[iRow]);
+    }
+  } else if (!startModel_) {
+    // make clone anyway so can tighten bounds
+    startModel_ = originalModel_->clone();
+  }
+  // move objective to integers or to aggregated
+  lower = startModel_->getColLower();
+  upper = startModel_->getColUpper();
+  rowLower = startModel_->getRowLower();
+  rowUpper = startModel_->getRowUpper();
+  matrixByRow = CoinPackedMatrix(*startModel_->getMatrixByRow());
+  elementByRow = matrixByRow.getElements();
+  column = matrixByRow.getIndices();
+  rowStart = matrixByRow.getVectorStarts();
+  rowLength = matrixByRow.getVectorLengths();
+  char * marked = new char [numberColumns];
+  memset(marked,0,numberColumns);
+  numberRows=startModel_->getNumRows();
+  numberColumns=startModel_->getNumCols();
+  //CoinPackedMatrix * matrixByColumn = const_cast<CoinPackedMatrix *>(startModel_->getMatrixByCol());
+  // Column copy
+  //const int * row = matrixByColumn->getIndices();
+  //const CoinBigIndex * columnStart = matrixByColumn->getVectorStarts();
+  //const int * columnLength = startModel_->getMatrixByCol()->getVectorLengths(); 
+  //const double * columnElements = matrixByColumn->getElements();
+  double * obj = CoinCopyOfArray(startModel_->getObjCoefficients(),numberColumns);
+  double offset;
+  int numberMoved=0;
+  startModel_->getDblParam(OsiObjOffset,offset);
+  for (iRow=0;iRow<numberRows;iRow++) {
+    //int slack = -1;
+    int nPlus=0;
+    int nMinus=0;
+    int iPlus=-1;
+    int iMinus=-1;
+    double valuePlus=0;
+    double valueMinus=0;
+    //bool allInteger=true;
+    double rhs = rowLower[iRow];
+    if (rhs!=rowUpper[iRow])
+      continue;
+    //int multiple=0;
+    //int iSlack=-1;
+    int numberContinuous=0;
+    for (CoinBigIndex j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+      int iColumn = column[j];
+      double value = elementByRow[j];
+      if (upper[iColumn]>lower[iColumn]) {
+	if (startModel_->isInteger(iColumn)) {
+#if 0
+	  if (columnLength[iColumn]==1) {
+	    if (value==1.0) {
+	    }
+	  }
+	  if (value!=floor(value+0.5))
+	    allInteger=false;
+	  if (allInteger&&fabs(value)<1.0e8) {
+	    if (!multiple)
+	      multiple = static_cast<int> (fabs(value));
+	    else if (multiple>0)
+	      multiple = gcd(multiple,static_cast<int> (fabs(value)));
+	  } else {
+	    allInteger=false;
+	  }
+#endif
+	} else {
+	  numberContinuous++;
+	}
+	if (value>0.0) {
+	  if (nPlus>0&&value!=valuePlus) {
+	    nPlus = - numberColumns;
+	  } else if (!nPlus) {
+	    nPlus=1;
+	    iPlus=iColumn;
+	    valuePlus=value;
+	  } else {
+	    nPlus++;
+	  }
+	} else {
+	  if (nMinus>0&&value!=valueMinus) {
+	    nMinus = - numberColumns;
+	  } else if (!nMinus) {
+	    nMinus=1;
+	    iMinus=iColumn;
+	    valueMinus=value;
+	  } else {
+	    nMinus++;
+	  }
+	}
+      } else {
+	rhs -= lower[iColumn]*value;
+      }
+    }
+    if (((nPlus==1&&startModel_->isInteger(iPlus)&&nMinus>0)||
+	 (nMinus==1&&startModel_->isInteger(iMinus)&&nPlus>0))&&numberContinuous&&true) {
+      int jColumn;
+      double multiplier;
+      if (nPlus==1) {
+	jColumn = iPlus;
+	multiplier = fabs(valuePlus/valueMinus);
+	rhs /= -valueMinus;
+      } else {
+	jColumn = iMinus;
+	multiplier = fabs(valueMinus/valuePlus);
+	rhs /= valuePlus;
+      }
+      double smallestPos=COIN_DBL_MAX;
+      double smallestNeg=-COIN_DBL_MAX;
+      for (CoinBigIndex j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	int iColumn = column[j];
+	if (iColumn!=jColumn) {
+	  double objValue = obj[iColumn];
+	  if (upper[iColumn]>lower[iColumn]) {
+	    if (objValue>=0.0)
+	      smallestPos=CoinMin(smallestPos,objValue);
+	    else
+	      smallestNeg=CoinMax(smallestNeg,objValue);
+	  }
+	}
+      }
+      if (smallestPos>0.0) {
+	double move=0.0;
+	if(smallestNeg==-COIN_DBL_MAX)
+	  move=smallestPos;
+	else if (smallestPos==COIN_DBL_MAX)
+	  move=smallestNeg;
+	if (move) {
+	  // can move objective
+	  numberMoved++;
+#ifdef COIN_DEVELOP
+	  if (rhs)
+	    printf("ZZZ on col %d move %g offset %g\n",
+		   jColumn,move,move*rhs);
+#endif
+	  offset += move*rhs;
+	  for (CoinBigIndex j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	    int iColumn = column[j];
+	    if (iColumn!=jColumn) {
+	      if (upper[iColumn]>lower[iColumn]) {
+		obj[iColumn] -= move;
+	      }
+	    } else {
+	      obj[jColumn] += move*multiplier;
+	    }
+	  }
+	}
+      }
+    }
+  }
+#ifdef COIN_DEVELOP
+  if (numberMoved)
+    printf("ZZZ %d costs moved\n",numberMoved);
+#endif
+  startModel_->setDblParam(OsiObjOffset,offset);
+  startModel_->setObjective(obj);
+  delete [] obj;
+  delete [] marked;
+  delete [] rows;
+  delete [] element;
+  if (makeIntegers) {
+    makeIntegers2(startModel_,makeIntegers);
+  }
+  int infeas=0;
+  OsiSolverInterface * startModel2 = startModel_;
+  // Do we want initial presolve
+  if (doInitialPresolve) {
+    assert (doInitialPresolve==1);
+    OsiSolverInterface * presolvedModel;
+    OsiSolverInterface * oldModel = startModel2;
+    OsiPresolve * pinfo = new OsiPresolve();
+    int presolveActions=0;
+    // Allow dual stuff on integers
+    // Allow stuff which may not unroll cleanly
+    presolveActions=1+16;
+    if ((tuning&32)!=0)
+      presolveActions |= 32;
+    // Do not allow all +1 to be tampered with
+    //if (allPlusOnes)
+    //presolveActions |= 2;
+    // allow transfer of costs
+    // presolveActions |= 4;
+    // If trying for SOS don't allow some transfers
+    if (makeEquality==2||makeEquality==3)
+      presolveActions |= 8;
+    pinfo->setPresolveActions(presolveActions);
+    if (prohibited_)
+      assert (numberProhibited_==oldModel->getNumCols());
+    int saveLogLevel = oldModel->messageHandler()->logLevel();
+    if (saveLogLevel==1)
+      oldModel->messageHandler()->setLogLevel(0);
+    std::string solverName;
+    oldModel->getStrParam(OsiSolverName,solverName);
+    // Extend if you want other solvers to keep solution
+    bool keepSolution=solverName=="clp";
+    // Should not be hardwired tolerance - temporary fix
+#ifndef CGL_PREPROCESS_TOLERANCE
+#define CGL_PREPROCESS_TOLERANCE 1.0e-7
+#endif
+    // So standalone version can switch off
+    double feasibilityTolerance = ((tuning&1024)==0) ? CGL_PREPROCESS_TOLERANCE : 1.0e-4;
+    presolvedModel = pinfo->presolvedModel(*oldModel,feasibilityTolerance,true,5,prohibited_,keepSolution,rowType_);
+    oldModel->messageHandler()->setLogLevel(saveLogLevel);
+    if (presolvedModel) {
+      presolvedModel->messageHandler()->setLogLevel(saveLogLevel);
+      //presolvedModel->writeMps("new");
+      writeDebugMps(presolvedModel,"ordinary",pinfo);
+      // update prohibited and rowType
+      update(pinfo,presolvedModel);
+      if (!presolvedModel->getNumRows()) {
+	doInitialPresolve=0;
+	delete presolvedModel;
+	delete pinfo;
+      } else {
+	model_[0]=presolvedModel;
+	presolve_[0]=pinfo;
+	modifiedModel_[0]=presolvedModel->clone();
+	startModel2 = modifiedModel_[0];
+      }
+    } else {
+      infeas=1;
+      doInitialPresolve=0;
+      delete presolvedModel;
+      delete pinfo;
+    }
+  }
+  // tighten bounds
+/*
+
+  Virtuous solvers may require a refresh via initialSolve if this
+  call is ever changed to give a nonzero value to the (default) second
+  parameter. Previous actions may have made significant changes to the
+  constraint system. Safe as long as tightenPrimalBounds doesn't ask for
+  the current solution.
+*/
+  if (!infeas&&true) {
+    // may be better to just do at end
+    writeDebugMps(startModel2,"before",NULL);
+    infeas = tightenPrimalBounds(*startModel2);
+    writeDebugMps(startModel2,"after",NULL);
+  }
+  if (infeas) {
+    handler_->message(CGL_INFEASIBLE,messages_)
+      <<CoinMessageEol;
+    return NULL;
+  }
+  OsiSolverInterface * returnModel=NULL;
+  int numberChanges;
+  if ((tuning&128)!=0) {
+    // take out cliques
+    OsiSolverInterface * newSolver=cliqueIt(*startModel2,0.0001);
+    if (newSolver) {
+      if (startModel2 == modifiedModel_[0])
+	modifiedModel_[0]=newSolver;
+      delete startModel2;
+      startModel2=newSolver;
+      newSolver->initialSolve();
+      assert (newSolver->isProvenOptimal());
+      //printf("new size %d rows, %d columns\n",
+      //     newSolver->getNumRows(),newSolver->getNumCols());
+    }
+  }
+  {
+    // Give a hint to do dual
+    bool saveTakeHint;
+    OsiHintStrength saveStrength;
+    startModel2->getHintParam(OsiDoDualInInitial,
+			      saveTakeHint,saveStrength);
+    startModel2->setHintParam(OsiDoDualInInitial,true,OsiHintTry);
+    startModel2->initialSolve();
+    numberIterationsPre_ += startModel2->getIterationCount();
+    // double check
+    if (!startModel2->isProvenOptimal()) {
+      if (!startModel2->isProvenDualInfeasible()) {
+	// Do presolves
+	bool saveHint;
+	OsiHintStrength saveStrength;
+	startModel2->getHintParam(OsiDoPresolveInInitial,saveHint,saveStrength);
+	startModel2->setHintParam(OsiDoPresolveInInitial,true,OsiHintTry);
+	startModel2->setHintParam(OsiDoDualInInitial,false,OsiHintTry);
+	startModel2->initialSolve();
+	numberIterationsPre_ += startModel2->getIterationCount();
+	if (!startModel2->isProvenDualInfeasible()) {
+	  CoinWarmStart * empty = startModel2->getEmptyWarmStart();
+	  startModel2->setWarmStart(empty);
+	  delete empty;
+	  startModel2->setHintParam(OsiDoDualInInitial,true,OsiHintTry);
+	  startModel2->initialSolve();
+	  numberIterationsPre_ += startModel2->getIterationCount();
+	}
+	startModel2->setHintParam(OsiDoPresolveInInitial,saveHint,saveStrength);
+      }
+    }
+    startModel2->setHintParam(OsiDoDualInInitial,saveTakeHint,saveStrength);
+  }
+  if (!startModel2->isProvenOptimal()) {
+    if (!startModel2->isProvenDualInfeasible()) {
+      handler_->message(CGL_INFEASIBLE,messages_)<< CoinMessageEol ;
+#ifdef COIN_DEVELOP
+      startModel2->writeMps("infeas");
+#endif
+    } else {
+      handler_->message(CGL_UNBOUNDED,messages_)<< CoinMessageEol ;
+    }
+    return NULL;
+  }
+  reducedCostFix(*startModel2);
+  if (!numberSolvers_) {
+    // just fix
+    OsiSolverInterface * newModel = modified(startModel2,false,numberChanges,0,numberModifiedPasses);
+    if (startModel_!=originalModel_)
+      delete startModel_;
+    if (startModel2!=startModel_)
+      delete startModel2;
+    startModel_=newModel;
+    returnModel=startModel_;
+  } else {
+    OsiSolverInterface * presolvedModel;
+    OsiSolverInterface * oldModel = startModel2;
+    if (doInitialPresolve)
+      oldModel = modifiedModel_[0];
+    //CglDuplicateRow dupCuts(oldModel);
+    //dupCuts.setLogLevel(1);
+    // If +1 try duplicate rows
+#define USECGLCLIQUE 512
+    if ((options_&8)!=0)
+      tuning &= ~USECGLCLIQUE;
+    if ((options_&4)!=0)
+      allPlusOnes=false;
+    if (allPlusOnes||(tuning&USECGLCLIQUE)!=0) {
+#if 1
+      // put at beginning
+      int nAdd= ((tuning&(64+USECGLCLIQUE))==64+USECGLCLIQUE&&allPlusOnes) ? 2 : 1;
+      CglCutGenerator ** temp = generator_;
+      generator_ = new CglCutGenerator * [numberCutGenerators_+nAdd];
+      memcpy(generator_+nAdd,temp,numberCutGenerators_*sizeof(CglCutGenerator *));
+      delete[] temp ;
+      numberCutGenerators_+=nAdd;
+      if (nAdd==2||(tuning&USECGLCLIQUE)!=0) {
+	CglClique * cliqueGen=new CglClique(false,true);
+	cliqueGen->setStarCliqueReport(false);
+	cliqueGen->setRowCliqueReport(false);
+	if ((tuning&USECGLCLIQUE)==0)
+	  cliqueGen->setMinViolation(-2.0);
+	else
+	  cliqueGen->setMinViolation(-3.0);
+	generator_[0]=cliqueGen;
+      }
+      if (allPlusOnes) {
+	CglDuplicateRow * dupCuts =new CglDuplicateRow(oldModel);
+	if ((tuning&256)!=0)
+	  dupCuts->setMaximumDominated(numberColumns);
+	generator_[nAdd-1]=dupCuts;
+      }
+#else
+      CglDuplicateRow dupCuts(oldModel);
+      addCutGenerator(&dupCuts);
+#endif
+    }
+    for (int iPass=doInitialPresolve;iPass<numberSolvers_;iPass++) {
+      // Look at Vubs
+      {
+        const double * columnLower = oldModel->getColLower();
+        const double * columnUpper = oldModel->getColUpper();
+        const CoinPackedMatrix * rowCopy = oldModel->getMatrixByRow();
+        const int * column = rowCopy->getIndices();
+        const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+        const int * rowLength = rowCopy->getVectorLengths(); 
+        const double * rowElements = rowCopy->getElements();
+        const CoinPackedMatrix * columnCopy = oldModel->getMatrixByCol();
+        //const int * row = columnCopy->getIndices();
+        //const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+        const int * columnLength = columnCopy->getVectorLengths(); 
+        //const double * columnElements = columnCopy->getElements();
+        const double * rowLower = oldModel->getRowLower();
+        const double * rowUpper = oldModel->getRowUpper();
+        const double * objective = oldModel->getObjCoefficients();
+        double direction = oldModel->getObjSense();
+        int numberRows = oldModel->getNumRows();
+        for (int iRow=0;iRow<numberRows;iRow++) {
+          if (rowLength[iRow]==2&&(rowLower[iRow]<-1.0e20||rowUpper[iRow]>1.0e20)) {
+            CoinBigIndex start = rowStart[iRow];
+            int iColumn1 = column[start];
+            int iColumn2 = column[start+1];
+            double value1 = rowElements[start];
+            double value2 = rowElements[start+1];
+            double upper;
+            if (rowLower[iRow]<-1.0e20) {
+              if (rowUpper[iRow]<1.0e20)
+                upper = rowUpper[iRow];
+              else
+                continue; // free row
+            } else {
+              upper = - rowLower[iRow];
+              value1=-value1;
+              value2=-value2;
+            }
+            //for now just singletons
+            bool integer1 = oldModel->isInteger(iColumn1);
+            bool integer2 = oldModel->isInteger(iColumn2);
+            int debug=0;
+            if (columnLength[iColumn1]==1) {
+              if (integer1) {
+                debug=0;// no good
+              } else if (integer2) {
+                // possible
+                debug=1;
+              }
+            } else if (columnLength[iColumn2]==1) {
+              if (integer2) {
+                debug=-1; // print and skip
+              } else if (integer1) {
+                // possible
+                debug=1;
+                double valueD = value1;
+                value1 = value2;
+                value2 = valueD;
+                int valueI = iColumn1;
+                iColumn1 = iColumn2;
+                iColumn2 = valueI;
+                bool valueB = integer1;
+                integer1 = integer2;
+                integer2 = valueB;
+              }
+            }
+            if (debug&&0) {
+              printf("%d %d elements%selement %g and %d %d elements%selement %g <= %g\n",
+                     iColumn1,columnLength[iColumn1],integer1 ? " (integer) " : " ",value1,
+                     iColumn2,columnLength[iColumn2],integer2 ? " (integer) " : " ",value2,
+                     upper);
+            }
+            if (debug>0) {
+              if (value1>0.0&&objective[iColumn1]*direction<0.0) {
+                // will push as high as possible so make ==
+                // highest effective rhs
+                if (value2>0) 
+                  upper -= value2 * columnLower[iColumn2];
+                else
+                  upper -= value2 * columnUpper[iColumn2];
+                if (columnUpper[iColumn1]>1.0e20||
+                    columnUpper[iColumn1]*value1>=upper) {
+                  //printf("looks possible\n");
+                  // make equality
+                  if (rowLower[iRow]<-1.0e20) 
+                    oldModel->setRowLower(iRow,rowUpper[iRow]);
+                  else
+                    oldModel->setRowUpper(iRow,rowLower[iRow]);
+                } else {
+                  // may be able to make integer
+                  // may just be better to use to see objective integral
+                  if (upper==floor(upper)&&value2==floor(value2)&&
+                      value1==floor(value1)&&objective[iColumn1]==floor(objective[iColumn1]))
+                    oldModel->setInteger(iColumn1);
+                  //printf("odd3\n");
+                }
+              } else if (value1<0.0&&objective[iColumn1]*direction>0.0) {
+                //printf("odd4\n");
+              } else {
+                //printf("odd2\n");
+              }
+            } else if (debug<0) {
+              //printf("odd1\n");
+            }
+          }
+        }
+      }
+      OsiPresolve * pinfo = new OsiPresolve();
+      int presolveActions=0;
+      // Allow dual stuff on integers
+      // Allow stuff which may not unroll cleanly
+      presolveActions=1+16;
+      // Do not allow all +1 to be tampered with
+      //if (allPlusOnes)
+      //presolveActions |= 2;
+      // allow transfer of costs
+      // presolveActions |= 4;
+      // If trying for SOS don't allow some transfers
+      if (makeEquality==2||makeEquality==3)
+        presolveActions |= 8;
+      pinfo->setPresolveActions(presolveActions);
+      if (prohibited_)
+        assert (numberProhibited_==oldModel->getNumCols());
+/*
+  VIRTUOUS but possible bad for performance 
+  
+  At this point, the solution is most likely stale: we may have added cuts as
+  we left the previous call to modified(), or we may have changed row bounds
+  in VUB analysis just above. Continuous presolve doesn't need a solution
+  unless we want it to transform the current solution to match the presolved
+  model.
+*/
+      int saveLogLevel = oldModel->messageHandler()->logLevel();
+      if (saveLogLevel==1)
+	oldModel->messageHandler()->setLogLevel(0);
+      std::string solverName;
+      oldModel->getStrParam(OsiSolverName,solverName);
+      // Extend if you want other solvers to keep solution
+      bool keepSolution=solverName=="clp";
+      presolvedModel = pinfo->presolvedModel(*oldModel,CGL_PREPROCESS_TOLERANCE,true,5,
+					     prohibited_,keepSolution,rowType_);
+      oldModel->messageHandler()->setLogLevel(saveLogLevel);
+      if (!presolvedModel) {
+        returnModel=NULL;
+	delete pinfo;
+        break;
+      }
+      presolvedModel->messageHandler()->setLogLevel(saveLogLevel);
+      // update prohibited and rowType
+      update(pinfo,presolvedModel);
+      writeDebugMps(presolvedModel,"ordinary2",pinfo);
+      model_[iPass]=presolvedModel;
+      presolve_[iPass]=pinfo;
+      if (!presolvedModel->getNumRows()) {
+        // was returnModel=oldModel;
+        returnModel=presolvedModel;
+        numberSolvers_=iPass+1;
+        break; // model totally solved
+      }
+      bool constraints = iPass<numberPasses-1;
+      // Give a hint to do primal
+      bool saveTakeHint;
+      OsiHintStrength saveStrength;
+      presolvedModel->getHintParam(OsiDoDualInInitial,
+                                   saveTakeHint,saveStrength);
+      //if (iPass)
+      presolvedModel->setHintParam(OsiDoDualInInitial,false,OsiHintTry);
+      presolvedModel->initialSolve();
+      numberIterationsPre_ += presolvedModel->getIterationCount();
+      presolvedModel->setHintParam(OsiDoDualInInitial,saveTakeHint,saveStrength);
+      if (!presolvedModel->isProvenOptimal()) {
+	writeDebugMps(presolvedModel,"bad2",NULL);
+	CoinWarmStartBasis *slack =
+	  dynamic_cast<CoinWarmStartBasis *>(presolvedModel->getEmptyWarmStart()) ;
+	presolvedModel->setWarmStart(slack);
+	delete slack ;
+	presolvedModel->resolve();
+	if (!presolvedModel->isProvenOptimal()) {
+	  returnModel=NULL;
+	  //printf("infeasible\n");
+	  break;
+	} else {
+	  //printf("feasible on second try\n");
+	}
+      }
+      // maybe we can fix some
+      int numberFixed = 
+      reducedCostFix(*presolvedModel);
+#ifdef COIN_DEVELOP
+      if (numberFixed)
+	printf("%d variables fixed on reduced cost\n",numberFixed);
+#endif
+      OsiSolverInterface * newModel = modified(presolvedModel,constraints,numberChanges,iPass-doInitialPresolve,numberModifiedPasses);
+      returnModel=newModel;
+      if (!newModel) {
+        break;
+      }
+      modifiedModel_[iPass]=newModel;
+      oldModel=newModel;
+      writeDebugMps(newModel,"ordinary3",NULL);
+      if (!numberChanges&&!numberFixed) {
+#ifdef COIN_DEVELOP
+	printf("exiting after pass %d of %d\n",iPass,numberSolvers_);
+#endif
+        numberSolvers_=iPass+1;
+        break;
+      }
+    }
+  }
+  if (returnModel) {
+    if (returnModel->getNumRows()) {
+      // tighten bounds
+      int infeas = tightenPrimalBounds(*returnModel);
+      if (infeas) {
+        delete returnModel;
+	for (int iPass=0;iPass<numberSolvers_;iPass++) {
+	  if (returnModel==modifiedModel_[iPass])
+	    modifiedModel_[iPass]=NULL;
+	}
+	//printf("startModel_ %p startModel2 %p originalModel_ %p returnModel %p\n",
+	//     startModel_,startModel2,originalModel_,returnModel);
+        if (returnModel==startModel_&&startModel_!=originalModel_)
+          startModel_=NULL;
+        returnModel=NULL;
+      }
+    }
+  } else {
+    handler_->message(CGL_INFEASIBLE,messages_)
+      <<CoinMessageEol;
+  }
+  int numberIntegers=0;
+  if (returnModel) {
+    int iColumn;
+    int numberColumns = returnModel->getNumCols();
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (returnModel->isInteger(iColumn))
+        numberIntegers++;
+    }
+  }
+  if ((makeEquality==2||makeEquality==3)&&numberCliques&&returnModel) {
+    int iRow, iColumn;
+    int numberColumns = returnModel->getNumCols();
+    int numberRows = returnModel->getNumRows();
+    const double * objective = returnModel->getObjCoefficients();
+    // get row copy
+    const CoinPackedMatrix * matrix = returnModel->getMatrixByRow();
+    const double * element = matrix->getElements();
+    const int * column = matrix->getIndices();
+    const CoinBigIndex * rowStart = matrix->getVectorStarts();
+    const int * rowLength = matrix->getVectorLengths();
+    const double * rowLower = returnModel->getRowLower();
+    const double * rowUpper = returnModel->getRowUpper();
+    const double * columnLower = returnModel->getColLower();
+    
+    // Look for possible SOS
+    int numberSOS=0;
+    int * mark = new int[numberColumns];
+    int * sosRow = new int [numberRows];
+    CoinZeroN(sosRow,numberRows);
+    CoinFillN(mark,numberColumns,-1);
+    int numberOverlap=0;
+    int numberInSOS=0;
+    for (iRow=0;iRow<numberRows;iRow++) {
+      if (rowLower[iRow]==1.0&&rowUpper[iRow]==1.0) {
+        if ((rowLength[iRow]<5&&!justOnesWithObj)||(rowLength[iRow]<20&&allToGub))
+          continue;
+        bool goodRow=true;
+	int nObj=0;
+        for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+          iColumn = column[j];
+          if (element[j]!=1.0||!returnModel->isInteger(iColumn)||columnLower[iColumn]) {
+            goodRow=false;
+            break;
+          }
+          if (mark[iColumn]>=0&&!allToGub) {
+            goodRow=false;
+            numberOverlap++;
+          }
+	  if (objective[iColumn])
+	    nObj++;
+        }
+	if (goodRow&&justOnesWithObj) {
+	  if (!nObj||nObj<rowLength[iRow]-1) 
+	    goodRow=false;
+	}
+        if (goodRow) {
+          // mark all
+          for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+            int iColumn = column[j];
+            mark[iColumn]=numberSOS;
+          }
+          sosRow[numberSOS++]=iRow;
+          numberInSOS += rowLength[iRow];
+        }
+      }
+    }
+    if (numberSOS) {
+      if (makeEquality==2&&(numberOverlap||numberIntegers>numberInSOS+1)) {
+        handler_->message(CGL_PROCESS_SOS2,messages_)
+          <<numberSOS<<numberInSOS<<numberIntegers<<numberOverlap
+          <<CoinMessageEol;
+      } else {
+        handler_->message(CGL_PROCESS_SOS1,messages_)
+          <<numberSOS<<numberInSOS
+          <<CoinMessageEol;
+        numberSOS_=numberSOS;
+        typeSOS_ = new int[numberSOS_];
+        startSOS_ = new int[numberSOS_+1];
+        whichSOS_ = new int[numberInSOS];
+        weightSOS_ = new double[numberInSOS];
+        numberInSOS=0;
+        startSOS_[0]=0;
+        const CoinPackedMatrix * columnCopy = returnModel->getMatrixByCol();
+        const int * row = columnCopy->getIndices();
+        const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+        const int * columnLength = columnCopy->getVectorLengths(); 
+        const double * columnElements = columnCopy->getElements();
+        const double * objective = returnModel->getObjCoefficients();
+        int * numberInRow = new int [numberRows];
+        double * sort = new double[numberColumns];
+        int * which = new int[numberColumns];
+        for (int iSOS =0;iSOS<numberSOS_;iSOS++) {
+          int n=0;
+          int numberObj=0;
+          CoinZeroN(numberInRow,numberRows);
+	  int kRow = sosRow[iSOS];
+          for (int j=rowStart[kRow];j<rowStart[kRow]+rowLength[kRow];j++) {
+            int iColumn = column[j];
+	    whichSOS_[numberInSOS]=iColumn;
+	    weightSOS_[numberInSOS]=n;
+	    numberInSOS++;
+	    n++;
+	    if (objective[iColumn])
+	      numberObj++;
+	    for (CoinBigIndex j=columnStart[iColumn];
+		 j<columnStart[iColumn]+columnLength[iColumn];j++) {
+	      int iRow = row[j];
+	      if (!sosRow[iRow])
+		numberInRow[iRow]++;
+	    }
+	  }
+          // See if any rows look good
+          int bestRow=-1;
+          int numberDifferent=1;
+          int start = startSOS_[iSOS];
+          for (int iRow=0;iRow<numberRows;iRow++) {
+            if (numberInRow[iRow]>=n-1) {
+              // See how many different
+              int i;
+              for ( i=0;i<n;i++) {
+                int iColumn = whichSOS_[i+start];
+                sort[i]=0.0;
+                which[i]=iColumn;
+                for (CoinBigIndex j=columnStart[iColumn];
+                     j<columnStart[iColumn]+columnLength[iColumn];j++) {
+                  int jRow = row[j];
+                  if (jRow==iRow) {
+                    sort[i]=columnElements[j];
+                    break;
+                  }
+                }
+              }
+              // sort
+              CoinSort_2(sort,sort+n,which);
+              double last = sort[0];
+              int nDiff=1;
+              for ( i=1;i<n;i++) {
+                if (sort[i]>last+CoinMax(fabs(last)*1.0e-8,1.0e-5)) {
+                  nDiff++;
+                }
+                last = sort[i];
+              }
+              if (nDiff>numberDifferent) {
+                numberDifferent = nDiff;
+                bestRow=iRow;
+              }
+            }
+          }
+          if (numberObj>=n-1||bestRow<0) {
+            int i;
+            for ( i=0;i<n;i++) {
+              int iColumn = whichSOS_[i+start];
+              sort[i]=objective[iColumn];
+              which[i]=iColumn;
+            }
+            // sort
+            CoinSort_2(sort,sort+n,which);
+            double last = sort[0];
+            int nDiff=1;
+            for ( i=1;i<n;i++) {
+              if (sort[i]>last+CoinMax(fabs(last)*1.0e-8,1.0e-5)) {
+                nDiff++;
+              }
+              last = sort[i];
+            }
+            if (nDiff>numberDifferent) {
+              numberDifferent = nDiff;
+              bestRow=numberRows;
+            }
+          }
+          if (bestRow>=0) {
+            // if not objective - recreate
+            if (bestRow<numberRows) {
+              int i;
+              for ( i=0;i<n;i++) {
+                int iColumn = whichSOS_[i+start];
+                sort[i]=0.0;
+                which[i]=iColumn;
+                for (CoinBigIndex j=columnStart[iColumn];
+                     j<columnStart[iColumn]+columnLength[iColumn];j++) {
+                  int jRow = row[j];
+                  if (jRow==bestRow) {
+                    sort[i]=columnElements[j];
+                    break;
+                  }
+                }
+              }
+              // sort
+              CoinSort_2(sort,sort+n,which);
+            }
+            // make sure gaps OK
+            double last = sort[0];
+            for (int i=1;i<n;i++) {
+              double next = last+CoinMax(fabs(last)*1.0e-8,1.0e-5);
+              sort[i]=CoinMax(sort[i],next);
+              last = sort[i];
+            }
+            //CoinCopyN(sort,n,weightSOS_+start);
+            //CoinCopyN(which,n,whichSOS_+start);
+          }
+          typeSOS_[iSOS]=1;
+          startSOS_[iSOS+1]=numberInSOS;
+        }
+        delete [] numberInRow;
+        delete [] sort;
+        delete [] which;
+      }
+    }
+    delete [] mark;
+    delete [] sosRow;
+  }
+  if (returnModel) {
+    if (makeIntegers) 
+      makeIntegers2(returnModel,makeIntegers);
+    handler_->message(CGL_PROCESS_STATS2,messages_)
+      <<returnModel->getNumRows()<<returnModel->getNumCols()
+      <<numberIntegers<<returnModel->getNumElements()
+      <<CoinMessageEol;
+    // If can make some cuts then do so
+    if (rowType_) {
+      int numberRows = returnModel->getNumRows();
+      int numberCuts=0;
+      for (int i=0;i<numberRows;i++) {
+	if (rowType_[i]>0)
+	  numberCuts++;
+      }
+      if (numberCuts) {
+	CglStored stored;
+	
+	int * whichRow = new int[numberRows];
+	// get row copy
+	const CoinPackedMatrix * rowCopy = returnModel->getMatrixByRow();
+	const int * column = rowCopy->getIndices();
+	const int * rowLength = rowCopy->getVectorLengths();
+	const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+	const double * rowLower = returnModel->getRowLower();
+	const double * rowUpper = returnModel->getRowUpper();
+	const double * element = rowCopy->getElements();
+	int iRow,nDelete=0;
+	for (iRow=0;iRow<numberRows;iRow++) {
+	  if (rowType_[iRow]==1) {
+	    // take out
+	    whichRow[nDelete++]=iRow;
+	  }
+	}
+	for (int jRow=0;jRow<nDelete;jRow++) {
+	  iRow=whichRow[jRow];
+	  int start = rowStart[iRow];
+	  stored.addCut(rowLower[iRow],rowUpper[iRow],rowLength[iRow],
+			column+start,element+start);
+	}
+	returnModel->deleteRows(nDelete,whichRow);
+	delete [] whichRow;
+	cuts_ = stored;
+      }
+    }
+  }
+#if 0
+  if (returnModel) {
+    int numberColumns = returnModel->getNumCols();
+    int numberRows = returnModel->getNumRows();
+    int * del = new int [CoinMax(numberColumns,numberRows)];
+    int * original = new int [numberColumns];
+    int nDel=0;
+    for (int i=0;i<numberColumns;i++) {
+      original[i]=i;
+      if (returnModel->isInteger(i))
+	del[nDel++]=i;
+    }
+    int nExtra=0;
+    if (nDel&&nDel!=numberColumns&&(options_&1)!=0&&false) {
+      OsiSolverInterface * yyyy = returnModel->clone();
+      int nPass=0;
+      while (nDel&&nPass<10) {
+	nPass++;
+	OsiSolverInterface * xxxx = yyyy->clone();
+	int nLeft=0;
+	for (int i=0;i<nDel;i++) 
+	  original[del[i]]=-1;
+	for (int i=0;i<numberColumns;i++) {
+	  int kOrig=original[i];
+	  if (kOrig>=0)
+	    original[nLeft++]=kOrig;
+	}
+	assert (nLeft==numberColumns-nDel);
+	xxxx->deleteCols(nDel,del);
+	numberColumns = xxxx->getNumCols();
+	const CoinPackedMatrix * rowCopy = xxxx->getMatrixByRow();
+	numberRows = rowCopy->getNumRows();
+	const int * column = rowCopy->getIndices();
+	const int * rowLength = rowCopy->getVectorLengths();
+	const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+	const double * rowLower = xxxx->getRowLower();
+	const double * rowUpper = xxxx->getRowUpper();
+	const double * element = rowCopy->getElements();
+        const CoinPackedMatrix * columnCopy = xxxx->getMatrixByCol();
+        const int * columnLength = columnCopy->getVectorLengths(); 
+	nDel=0;
+	// Could do gcd stuff on ones with costs
+	for (int i=0;i<numberRows;i++) {
+	  if (!rowLength[i]) {
+	    del[nDel++]=i;
+	  } else if (rowLength[i]==1) {
+	    int k=rowStart[i];
+	    int iColumn = column[k];
+	    if (!xxxx->isInteger(iColumn)) {
+	      double mult =1.0/fabs(element[k]);
+	      if (rowLower[i]<-1.0e20) {
+		double value = rowUpper[i]*mult;
+		if (fabs(value-floor(value+0.5))<1.0e-8) {
+		  del[nDel++]=i;
+		  if (columnLength[iColumn]==1) {
+		    xxxx->setInteger(iColumn);
+		    int kOrig=original[iColumn];
+		    returnModel->setInteger(kOrig);
+		  }
+		}
+	      } else if (rowUpper[i]>1.0e20) {
+		double value = rowLower[i]*mult;
+		if (fabs(value-floor(value+0.5))<1.0e-8) {
+		  del[nDel++]=i;
+		  if (columnLength[iColumn]==1) {
+		    xxxx->setInteger(iColumn);
+		    int kOrig=original[iColumn];
+		    returnModel->setInteger(kOrig);
+		  }
+		}
+	      } else {
+		double value = rowUpper[i]*mult;
+		if (rowLower[i]==rowUpper[i]&&
+		    fabs(value-floor(value+0.5))<1.0e-8) {
+		  del[nDel++]=i;
+		  xxxx->setInteger(iColumn);
+		  int kOrig=original[iColumn];
+		  returnModel->setInteger(kOrig);
+		}
+	      }
+	    }
+	  } else {
+	    // only if all singletons
+	    bool possible=false;
+	    if (rowLower[i]<-1.0e20) {
+	      double value = rowUpper[i];
+	      if (fabs(value-floor(value+0.5))<1.0e-8) 
+		possible=true;
+	    } else if (rowUpper[i]>1.0e20) {
+	      double value = rowLower[i];
+	      if (fabs(value-floor(value+0.5))<1.0e-8) 
+		possible=true;
+	    } else {
+	      double value = rowUpper[i];
+	      if (rowLower[i]==rowUpper[i]&&
+		  fabs(value-floor(value+0.5))<1.0e-8)
+		possible=true;
+	    }
+	    if (possible) {
+	      for (CoinBigIndex j=rowStart[i];
+		   j<rowStart[i]+rowLength[i];j++) {
+		int iColumn = column[j];
+		if (columnLength[iColumn]!=1||fabs(element[j])!=1.0) {
+		  possible=false;
+		  break;
+		}
+	      }
+	      if (possible) {
+		for (CoinBigIndex j=rowStart[i];
+		     j<rowStart[i]+rowLength[i];j++) {
+		  int iColumn = column[j];
+		  if (!xxxx->isInteger(iColumn)) {
+		    xxxx->setInteger(iColumn);
+		    int kOrig=original[iColumn];
+		    returnModel->setInteger(kOrig);
+		  }
+		}
+		del[nDel++]=i;
+	      }
+	    }
+	  }
+	}
+	if (nDel) {
+	  xxxx->deleteRows(nDel,del);
+	}
+	if (nDel!=numberRows) {
+	  nDel=0;
+	  for (int i=0;i<numberColumns;i++) {
+	    if (xxxx->isInteger(i)) {
+	      del[nDel++]=i;
+	      nExtra++;
+	    }
+	  }
+	} 
+	delete yyyy;
+	yyyy=xxxx->clone();
+      }
+      numberColumns = yyyy->getNumCols();
+      numberRows = yyyy->getNumRows();
+      if (!numberColumns||!numberRows) {
+	printf("All gone\n");
+	int numberColumns = returnModel->getNumCols();
+	for (int i=0;i<numberColumns;i++)
+	  assert(returnModel->isInteger(i));
+      }
+      // Would need to check if original bounds integer
+      //yyyy->writeMps("noints");
+      delete yyyy;
+      printf("Creating simplified model with %d rows and %d columns - %d extra integers\n",
+	     numberRows,numberColumns,nExtra);
+    }
+    delete [] del;
+    delete [] original;
+    //exit(2);
+  }
+#endif
+  return returnModel;
+}
+
+/* Tightens primal bounds to make dual and branch and cutfaster.  Unless
+   fixed, bounds are slightly looser than they could be.
+   Returns non-zero if problem infeasible
+   Fudge for branch and bound - put bounds on columns of factor *
+   largest value (at continuous) - should improve stability
+   in branch and bound on infeasible branches (0.0 is off)
+*/
+int 
+CglPreProcess::tightenPrimalBounds(OsiSolverInterface & model,double factor)
+{
+  
+  // Get a row copy in standard format
+  CoinPackedMatrix copy = *model.getMatrixByRow();
+  // get matrix data pointers
+  const int * column = copy.getIndices();
+  const CoinBigIndex * rowStart = copy.getVectorStarts();
+  const int * rowLength = copy.getVectorLengths(); 
+  double * element = copy.getMutableElements();
+  int numberChanged=1,iPass=0;
+  double large = model.getInfinity()*0.1; // treat bounds > this as infinite
+  int numberInfeasible=0;
+  int totalTightened = 0;
+
+  double tolerance;
+  model.getDblParam(OsiPrimalTolerance,tolerance);
+
+
+  int numberColumns=model.getNumCols();
+  const double * colLower = model.getColLower();
+  const double * colUpper = model.getColUpper();
+  // New and saved column bounds
+  double * newLower = new double [numberColumns];
+  memcpy(newLower,colLower,numberColumns*sizeof(double));
+  double * newUpper = new double [numberColumns];
+  memcpy(newUpper,colUpper,numberColumns*sizeof(double));
+  double * columnLower = new double [numberColumns];
+  memcpy(columnLower,colLower,numberColumns*sizeof(double));
+  double * columnUpper = new double [numberColumns];
+  memcpy(columnUpper,colUpper,numberColumns*sizeof(double));
+
+  int iRow, iColumn;
+
+  // If wanted - tighten column bounds using solution
+  if (factor) {
+    /*
+      Callers need to ensure that the solution is fresh 
+    */
+    const double * solution =  model.getColSolution();
+    double largest=0.0;
+    if (factor>0.0) {
+      assert (factor>1.0);
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+        if (columnUpper[iColumn]-columnLower[iColumn]>tolerance) {
+          largest = CoinMax(largest,fabs(solution[iColumn]));
+        }
+      }
+      largest *= factor;
+    } else {
+      // absolute
+       largest = - factor;
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (columnUpper[iColumn]-columnLower[iColumn]>tolerance) {
+        newUpper[iColumn] = CoinMin(columnUpper[iColumn],largest);
+        newLower[iColumn] = CoinMax(columnLower[iColumn],-largest);
+      }
+    }
+  }
+  int numberRows = model.getNumRows();
+  const double * rowLower = model.getRowLower();
+  const double * rowUpper = model.getRowUpper();
+#ifndef NDEBUG
+  double large2= 1.0e10*large;
+#endif
+#define MAXPASS 10
+
+  // Loop round seeing if we can tighten bounds
+  // Would be faster to have a stack of possible rows
+  // and we put altered rows back on stack
+  int numberCheck=-1;
+  while(numberChanged>numberCheck) {
+
+    numberChanged = 0; // Bounds tightened this pass
+    
+    if (iPass==MAXPASS) break;
+    iPass++;
+    
+    for (iRow = 0; iRow < numberRows; iRow++) {
+
+      if (rowLower[iRow]>-large||rowUpper[iRow]<large) {
+
+	// possible row
+	int infiniteUpper = 0;
+	int infiniteLower = 0;
+	double maximumUp = 0.0;
+	double maximumDown = 0.0;
+	double newBound;
+	CoinBigIndex rStart = rowStart[iRow];
+	CoinBigIndex rEnd = rowStart[iRow]+rowLength[iRow];
+	CoinBigIndex j;
+	// Compute possible lower and upper ranges
+      
+	for (j = rStart; j < rEnd; ++j) {
+	  double value=element[j];
+	  iColumn = column[j];
+	  if (value > 0.0) {
+	    if (newUpper[iColumn] >= large) {
+	      ++infiniteUpper;
+	    } else {
+	      maximumUp += newUpper[iColumn] * value;
+	    }
+	    if (newLower[iColumn] <= -large) {
+	      ++infiniteLower;
+	    } else {
+	      maximumDown += newLower[iColumn] * value;
+	    }
+	  } else if (value<0.0) {
+	    if (newUpper[iColumn] >= large) {
+	      ++infiniteLower;
+	    } else {
+	      maximumDown += newUpper[iColumn] * value;
+	    }
+	    if (newLower[iColumn] <= -large) {
+	      ++infiniteUpper;
+	    } else {
+	      maximumUp += newLower[iColumn] * value;
+	    }
+	  }
+	}
+	// Build in a margin of error
+	maximumUp += 1.0e-8*fabs(maximumUp);
+	maximumDown -= 1.0e-8*fabs(maximumDown);
+	double maxUp = maximumUp+infiniteUpper*1.0e31;
+	double maxDown = maximumDown-infiniteLower*1.0e31;
+	if (maxUp <= rowUpper[iRow] + tolerance && 
+	    maxDown >= rowLower[iRow] - tolerance) {
+	  
+	  // Row is redundant - make totally free
+	} else {
+	  if (maxUp < rowLower[iRow] -100.0*tolerance ||
+	      maxDown > rowUpper[iRow]+100.0*tolerance) {
+	    // problem is infeasible - exit at once
+	    numberInfeasible++;
+	    break;
+	  }
+	  double lower = rowLower[iRow];
+	  double upper = rowUpper[iRow];
+	  for (j = rStart; j < rEnd; ++j) {
+	    double value=element[j];
+	    iColumn = column[j];
+	    double nowLower = newLower[iColumn];
+	    double nowUpper = newUpper[iColumn];
+	    if (value > 0.0) {
+	      // positive value
+	      if (lower>-large) {
+		if (!infiniteUpper) {
+		  assert(nowUpper < large2);
+		  newBound = nowUpper + 
+		    (lower - maximumUp) / value;
+		  // relax if original was large
+		  if (fabs(maximumUp)>1.0e8)
+		    newBound -= 1.0e-12*fabs(maximumUp);
+		} else if (infiniteUpper==1&&nowUpper>large) {
+		  newBound = (lower -maximumUp) / value;
+		  // relax if original was large
+		  if (fabs(maximumUp)>1.0e8)
+		    newBound -= 1.0e-12*fabs(maximumUp);
+		} else {
+		  newBound = -COIN_DBL_MAX;
+		}
+		if (newBound > nowLower + 1.0e-12&&newBound>-large) {
+		  // Tighten the lower bound 
+		  newLower[iColumn] = newBound;
+		  numberChanged++;
+		  // check infeasible (relaxed)
+		  if (nowUpper - newBound < 
+		      -100.0*tolerance) {
+		    numberInfeasible++;
+		  }
+		  // adjust
+		  double now;
+		  if (nowLower<-large) {
+		    now=0.0;
+		    infiniteLower--;
+		  } else {
+		    now = nowLower;
+		  }
+		  maximumDown += (newBound-now) * value;
+		  nowLower = newBound;
+		}
+	      } 
+	      if (upper <large) {
+		if (!infiniteLower) {
+		  assert(nowLower >- large2);
+		  newBound = nowLower + 
+		    (upper - maximumDown) / value;
+		  // relax if original was large
+		  if (fabs(maximumDown)>1.0e8)
+		    newBound += 1.0e-12*fabs(maximumDown);
+		} else if (infiniteLower==1&&nowLower<-large) {
+		  newBound =   (upper - maximumDown) / value;
+		  // relax if original was large
+		  if (fabs(maximumDown)>1.0e8)
+		    newBound += 1.0e-12*fabs(maximumDown);
+		} else {
+		  newBound = COIN_DBL_MAX;
+		}
+		if (newBound < nowUpper - 1.0e-12&&newBound<large) {
+		  // Tighten the upper bound 
+		  newUpper[iColumn] = newBound;
+		  numberChanged++;
+		  // check infeasible (relaxed)
+		  if (newBound - nowLower < 
+		      -100.0*tolerance) {
+		    numberInfeasible++;
+		  }
+		  // adjust 
+		  double now;
+		  if (nowUpper>large) {
+		    now=0.0;
+		    infiniteUpper--;
+		  } else {
+		    now = nowUpper;
+		  }
+		  maximumUp += (newBound-now) * value;
+		  nowUpper = newBound;
+		}
+	      }
+	    } else {
+	      // negative value
+	      if (lower>-large) {
+		if (!infiniteUpper) {
+		  assert(nowLower < large2);
+		  newBound = nowLower + 
+		    (lower - maximumUp) / value;
+		  // relax if original was large
+		  if (fabs(maximumUp)>1.0e8)
+		    newBound += 1.0e-12*fabs(maximumUp);
+		} else if (infiniteUpper==1&&nowLower<-large) {
+		  newBound = (lower -maximumUp) / value;
+		  // relax if original was large
+		  if (fabs(maximumUp)>1.0e8)
+		    newBound += 1.0e-12*fabs(maximumUp);
+		} else {
+		  newBound = COIN_DBL_MAX;
+		}
+		if (newBound < nowUpper - 1.0e-12&&newBound<large) {
+		  // Tighten the upper bound 
+		  newUpper[iColumn] = newBound;
+		  numberChanged++;
+		  // check infeasible (relaxed)
+		  if (newBound - nowLower < 
+		      -100.0*tolerance) {
+		    numberInfeasible++;
+		  }
+		  // adjust
+		  double now;
+		  if (nowUpper>large) {
+		    now=0.0;
+		    infiniteLower--;
+		  } else {
+		    now = nowUpper;
+		  }
+		  maximumDown += (newBound-now) * value;
+		  nowUpper = newBound;
+		}
+	      }
+	      if (upper <large) {
+		if (!infiniteLower) {
+		  assert(nowUpper < large2);
+		  newBound = nowUpper + 
+		    (upper - maximumDown) / value;
+		  // relax if original was large
+		  if (fabs(maximumDown)>1.0e8)
+		    newBound -= 1.0e-12*fabs(maximumDown);
+		} else if (infiniteLower==1&&nowUpper>large) {
+		  newBound =   (upper - maximumDown) / value;
+		  // relax if original was large
+		  if (fabs(maximumDown)>1.0e8)
+		    newBound -= 1.0e-12*fabs(maximumDown);
+		} else {
+		  newBound = -COIN_DBL_MAX;
+		}
+		if (newBound > nowLower + 1.0e-12&&newBound>-large) {
+		  // Tighten the lower bound 
+		  newLower[iColumn] = newBound;
+		  numberChanged++;
+		  // check infeasible (relaxed)
+		  if (nowUpper - newBound < 
+		      -100.0*tolerance) {
+		    numberInfeasible++;
+		  }
+		  // adjust
+		  double now;
+		  if (nowLower<-large) {
+		    now=0.0;
+		    infiniteUpper--;
+		  } else {
+		    now = nowLower;
+		  }
+		  maximumUp += (newBound-now) * value;
+		  nowLower = newBound;
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    totalTightened += numberChanged;
+    if (iPass==1)
+      numberCheck=numberChanged>>4;
+    if (numberInfeasible) break;
+  }
+  if (!numberInfeasible) {
+    // Set bounds slightly loose unless integral - now tighter
+    double useTolerance = 1.0e-5;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (columnUpper[iColumn]>columnLower[iColumn]) {
+        double lower = newLower[iColumn];
+        double upper = newUpper[iColumn];
+        if (model.isInteger(iColumn)) {
+          if (fabs(lower-floor(lower+0.5))<1.0e-5)
+            lower=floor(lower+0.5);
+          else
+            lower = ceil(lower);
+          if (fabs(upper-floor(upper+0.5))<1.0e-5)
+            upper=floor(upper+0.5);
+          else
+            upper = floor(upper);
+          if (lower>upper)
+            numberInfeasible++;
+        } else {
+          if (fabs(upper)<1.0e-8&&fabs(lower)<1.0e-8) {
+            lower=0.0;
+            upper=0.0;
+          } else {
+            // Relax unless integral
+            if (fabs(lower-floor(lower+0.5))>1.0e-9)
+              lower -= useTolerance;
+            else
+              lower = floor(lower+0.5);
+            lower=CoinMax(columnLower[iColumn],lower);
+            if (fabs(upper-floor(upper+0.5))>1.0e-9)
+              upper += useTolerance;
+            else
+              upper = floor(upper+0.5);
+            upper=CoinMin(columnUpper[iColumn],upper);
+          }
+	}
+        model.setColLower(iColumn,lower);
+        model.setColUpper(iColumn,upper);
+        newLower[iColumn]=lower;
+        newUpper[iColumn]=upper;
+      }
+    }
+    if (!numberInfeasible) {
+      // check common bad formulations
+      int numberChanges=0;
+      for (iRow = 0; iRow < numberRows; iRow++) {
+        if (rowLower[iRow]>-large||rowUpper[iRow]<large) {
+          // possible row
+          double sumFixed=0.0;
+          int infiniteUpper = 0;
+          int infiniteLower = 0;
+          double maximumUp = 0.0;
+          double maximumDown = 0.0;
+          double largest = 0.0;
+          CoinBigIndex rStart = rowStart[iRow];
+          CoinBigIndex rEnd = rowStart[iRow]+rowLength[iRow];
+          CoinBigIndex j;
+          int numberInteger=0;
+          //int whichInteger=-1;
+          // Compute possible lower and upper ranges
+          for (j = rStart;j < rEnd; ++j) {
+            double value=element[j];
+            iColumn = column[j];
+            if (newUpper[iColumn]>newLower[iColumn]) {
+              if (model.isInteger(iColumn)) {
+                numberInteger++;
+                //whichInteger=iColumn;
+              }
+              largest = CoinMax(largest,fabs(value));
+              if (value > 0.0) {
+                if (newUpper[iColumn] >= large) {
+                  ++infiniteUpper;
+                } else {
+                  maximumUp += newUpper[iColumn] * value;
+                }
+                if (newLower[iColumn] <= -large) {
+                  ++infiniteLower;
+                } else {
+                  maximumDown += newLower[iColumn] * value;
+                }
+              } else if (value<0.0) {
+                if (newUpper[iColumn] >= large) {
+                  ++infiniteLower;
+                } else {
+                  maximumDown += newUpper[iColumn] * value;
+                }
+                if (newLower[iColumn] <= -large) {
+                  ++infiniteUpper;
+                } else {
+                  maximumUp += newLower[iColumn] * value;
+                }
+              }
+            } else {
+              // fixed
+              sumFixed += newLower[iColumn]*value;
+            }
+          }
+          // Adjust
+          maximumUp += sumFixed;
+          maximumDown += sumFixed;
+          // For moment just when all one sign and ints
+          //maximumUp += 1.0e-8*fabs(maximumUp);
+          //maximumDown -= 1.0e-8*fabs(maximumDown);
+          double gap = 0.0;
+          if ((rowLower[iRow]>maximumDown&&largest>rowLower[iRow]-maximumDown)&&
+              ((maximumUp<=rowUpper[iRow]&&!infiniteUpper)||rowUpper[iRow]>=1.0e30)) {
+            gap = rowLower[iRow]-maximumDown;
+            if (infiniteLower)
+              gap=0.0; // switch off
+          } else if ((maximumUp>rowUpper[iRow]&&largest>maximumUp-rowUpper[iRow])&&
+                     ((maximumDown>=rowLower[iRow]&&!infiniteLower)||rowLower[iRow]<=-1.0e30)) {
+            gap = -(maximumUp-rowUpper[iRow]);
+            if (infiniteUpper)
+              gap=0.0; // switch off
+          }
+          if (fabs(gap)>1.0e-8) {
+            for (j = rStart;j < rEnd; ++j) {
+              double value=element[j];
+              iColumn = column[j];
+              double difference = newUpper[iColumn]-newLower[iColumn];
+              if (difference>0.0&&difference<=1.0) {
+                double newValue=value;
+                if (value*gap>0.0&&model.isInteger(iColumn)) {
+                  if (fabs(value*difference) > fabs(gap)) {
+                    // No need for it to be larger than
+                    newValue = gap/difference;
+                  }
+                  if (fabs(value-newValue)>1.0e-12) {
+                    numberChanges++;
+		    // BUT variable may have bound
+		    double rhsAdjust=0.0;
+		    if (gap>0.0) {
+		      // rowLower
+		      if (value>0.0) {
+			// new value is based on going up from lower bound
+			if (colLower[iColumn]) 
+			  rhsAdjust = colLower[iColumn]*(value-newValue);
+		      } else {
+			// new value is based on going down from upper bound
+			if (colUpper[iColumn]) 
+			  rhsAdjust = colUpper[iColumn]*(value-newValue);
+		      }
+		    } else {
+		      // rowUpper
+		      if (value<0.0) {
+			// new value is based on going up from lower bound
+			if (colLower[iColumn]) 
+			  rhsAdjust = colLower[iColumn]*(value-newValue);
+		      } else {
+			// new value is based on going down from upper bound
+			if (colUpper[iColumn]) 
+			  rhsAdjust = colUpper[iColumn]*(value-newValue);
+		      }
+		    }
+		    if (rhsAdjust) {
+#ifdef CLP_INVESTIGATE
+		      printf("FFor column %d bounds %g, %g on row %d bounds %g, %g coefficient was changed from %g to %g with rhs adjustment of %g\n",
+			     iColumn,colLower[iColumn],colUpper[iColumn],
+			     iRow,rowLower[iRow],rowUpper[iRow],
+			     value,newValue,rhsAdjust);
+#endif
+		      if (rowLower[iRow]>-1.0e20)
+			model.setRowLower(iRow,rowLower[iRow]-rhsAdjust);
+		      if (rowUpper[iRow]<1.0e20)
+			model.setRowUpper(iRow,rowUpper[iRow]-rhsAdjust);
+#ifdef CLP_INVESTIGATE
+		      printf("FFor column %d bounds %g, %g on row %d bounds %g, %g coefficient was changed from %g to %g with rhs adjustment of %g\n",
+			     iColumn,colLower[iColumn],colUpper[iColumn],
+			     iRow,rowLower[iRow],rowUpper[iRow],
+			     value,newValue,rhsAdjust);
+#endif
+		    }
+                    element[j]=newValue;
+		    handler_->message(CGL_ELEMENTS_CHANGED2,messages_)
+		      <<iRow<<iColumn<<value<<newValue
+		      <<CoinMessageEol;
+#ifdef CGL_DEBUG
+                    const OsiRowCutDebugger * debugger = model.getRowCutDebugger();
+                    if (debugger&&debugger->numberColumns()==numberColumns) {
+                      const double * optimal = debugger->optimalSolution();
+                      double sum=0.0;
+                      for (int jj = rStart;jj < rEnd; ++jj) {
+                        double value=element[j];
+                        int jColumn = column[jj];
+                        sum += value*optimal[jColumn];
+                      }
+                      assert (sum>=rowLower[iRow]-1.0e7&&sum<=rowUpper[iRow]+1.0e-7);
+                    }
+#endif
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      if (numberChanges) {
+	handler_->message(CGL_ELEMENTS_CHANGED1,messages_)
+			<<numberChanges<<CoinMessageEol;
+        model.replaceMatrixOptional(copy);
+      }
+    }
+  }
+  if (numberInfeasible) {
+    handler_->message(CGL_INFEASIBLE,messages_)
+      <<CoinMessageEol;
+    // restore column bounds
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      model.setColLower(iColumn,columnLower[iColumn]);
+      model.setColUpper(iColumn,columnUpper[iColumn]);
+    }
+  }
+  delete [] newLower;
+  delete [] newUpper;
+  delete [] columnLower;
+  delete [] columnUpper;
+  return (numberInfeasible);
+}
+
+void
+CglPreProcess::postProcess(OsiSolverInterface & modelIn
+			   ,bool deleteStuff)
+{
+  // Do presolves
+  bool saveHint;
+  OsiHintStrength saveStrength;
+  originalModel_->getHintParam(OsiDoPresolveInInitial,saveHint,saveStrength);
+  bool saveHint2;
+  OsiHintStrength saveStrength2;
+  originalModel_->getHintParam(OsiDoDualInInitial,
+                        saveHint2,saveStrength2);
+  OsiSolverInterface * clonedCopy=NULL;
+  double saveObjectiveValue = modelIn.getObjValue();
+  if (!modelIn.isProvenOptimal()) {
+    CoinWarmStartBasis *slack =
+      dynamic_cast<CoinWarmStartBasis *>(modelIn.getEmptyWarmStart()) ;
+    modelIn.setWarmStart(slack);
+    delete slack ;
+    modelIn.resolve();
+  }
+  if (modelIn.isProvenOptimal()) {
+    OsiSolverInterface * modelM = &modelIn;
+    // If some cuts add back rows
+    if (cuts_.sizeRowCuts()) {
+      clonedCopy = modelM->clone();
+      modelM=clonedCopy;
+      int numberRowCuts = cuts_.sizeRowCuts() ;
+      // add in
+      CoinBuild build;
+      for (int k = 0;k<numberRowCuts;k++) {
+	const OsiRowCut * thisCut = cuts_.rowCutPointer(k) ;
+	int n=thisCut->row().getNumElements();
+	const int * columnCut = thisCut->row().getIndices();
+	const double * elementCut = thisCut->row().getElements();
+	double lower = thisCut->lb();
+	double upper = thisCut->ub();
+	build.addRow(n,columnCut,elementCut,lower,upper);
+      }
+      modelM->addRows(build);
+      // basis is wrong
+      CoinWarmStartBasis empty;
+      modelM->setWarmStart(&empty);
+    }
+    for (int iPass=numberSolvers_-1;iPass>=0;iPass--) {
+      OsiSolverInterface * model = model_[iPass];
+      if (model->getNumCols()) {
+	CoinWarmStartBasis* basis =
+	  dynamic_cast <CoinWarmStartBasis*>(modelM->getWarmStart()) ;
+	if (basis) {
+	  model->setWarmStart(basis);
+	  delete basis;
+	}
+	int numberColumns = modelM->getNumCols();
+	const double * solutionM = modelM->getColSolution();
+	const double * columnLower2 = model->getColLower(); 
+	const double * columnUpper2 = model->getColUpper();
+	const double * columnLower = modelM->getColLower(); 
+	const double * columnUpper = modelM->getColUpper();
+	int iColumn;
+	for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	  if (modelM->isInteger(iColumn)) {
+	    double value = solutionM[iColumn];
+	    double value2 = floor(value+0.5);
+	    // if test fails then empty integer
+	    if (fabs(value-value2)<1.0e-3) {
+	      model->setColLower(iColumn,value2);
+	      model->setColUpper(iColumn,value2);
+	    } else {
+#ifdef COIN_DEVELOP
+	      printf("NPASS=%d, ipass %d var %d values %g %g %g\n",
+		     numberSolvers_,iPass,iColumn,model->getColLower()[iColumn],
+		     value,model->getColUpper()[iColumn]);
+#endif
+	    }
+	  } else if (columnUpper[iColumn]==columnLower[iColumn]) {
+	    if (columnUpper2[iColumn]>columnLower2[iColumn]&&!model->isInteger(iColumn)) {
+	      model->setColUpper(iColumn,columnLower[iColumn]);
+	    }
+	  }
+	}
+      }
+      int numberColumns = modelM->getNumCols();
+      const double * solutionM = modelM->getColSolution();
+      int iColumn;
+      // Give a hint to do primal
+      //model->setHintParam(OsiDoPresolveInInitial,true,OsiHintTry);
+      model->setHintParam(OsiDoDualInInitial,false,OsiHintTry);
+      // clean
+/*
+  VIRTUOUS - I am not happy here (JJF) - This was put in for Special Ordered Sets of type 2
+
+  Previous loop has likely made nontrivial bound changes, hence invalidated
+  solution. Why do we need this? We're about to do an initialSolve, which
+  will overwrite solution. Perhaps belongs in same guarded block with
+  following feasibility check? If this is necessary for clp, solution should
+  be acquired before bounds changes.
+*/
+      if (0)
+      {
+	int numberColumns = model->getNumCols();
+	const double * lower = model->getColLower();
+	const double * upper = model->getColUpper();
+	double * solution = CoinCopyOfArray(model->getColSolution(),numberColumns);
+	int i;
+	for ( i=0;i<numberColumns;i++) {
+	  double value = solution[i];
+	  value = CoinMin(value,upper[i]);
+	  value = CoinMax(value,lower[i]);
+	  solution[i]=value;
+	}
+	model->setColSolution(solution);
+	delete [] solution;
+      }
+      if (0) {
+	int numberColumns = model->getNumCols();
+	int numberRows = model->getNumRows();
+	const double * lower = model->getColLower();
+	const double * upper = model->getColUpper();
+	const double * rowLower = model->getRowLower();
+	const double * rowUpper = model->getRowUpper();
+#ifndef NDEBUG
+	double primalTolerance=1.0e-8;
+#endif
+	// Column copy
+	const CoinPackedMatrix * matrix = model->getMatrixByCol();
+	const double * element = matrix->getElements();
+	const int * row = matrix->getIndices();
+	const CoinBigIndex * columnStart = matrix->getVectorStarts();
+	const int * columnLength = matrix->getVectorLengths();
+	double * rowActivity = new double[numberRows];
+	memset(rowActivity,0,numberRows*sizeof(double));
+	int i;
+	for ( i=0;i<numberColumns;i++) {
+	  int j;
+	  double value = lower[i];
+	  if (value<lower[i]) {
+	    value=lower[i];
+	  } else if (value>upper[i]) {
+	    value=upper[i];
+	  }
+	  assert (upper[i]>=lower[i]);
+	  assert ((fabs(value)<1.0e20));
+	  if (value) {
+	    for (j=columnStart[i];
+		 j<columnStart[i]+columnLength[i];j++) {
+	      int iRow=row[j];
+	      rowActivity[iRow] += value*element[j];
+	    }
+	  }
+	}
+	// check was feasible - if not adjust (cleaning may move)
+	for (i=0;i<numberRows;i++) {
+	  if(rowActivity[i]<rowLower[i]) {
+	    assert (rowActivity[i]>rowLower[i]-1000.0*primalTolerance);
+	    rowActivity[i]=rowLower[i];
+	  } else if(rowActivity[i]>rowUpper[i]) {
+	    assert (rowActivity[i]<rowUpper[i]+1000.0*primalTolerance);
+	    rowActivity[i]=rowUpper[i];
+	  }
+	}
+      }
+      {
+	int numberFixed=0;
+	int numberColumns = model->getNumCols();
+	const double * columnLower = model->getColLower(); 
+	const double * columnUpper = model->getColUpper();
+	int iColumn;
+	for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	  if (columnLower[iColumn]==columnUpper[iColumn])
+	    numberFixed++;
+	}
+	if (numberColumns>2000&&numberFixed<numberColumns&&
+	    numberFixed*5>numberColumns) {
+	  model->setHintParam(OsiDoPresolveInInitial,true,OsiHintTry);
+	}
+      }
+      model->initialSolve();
+      numberIterationsPost_ += model->getIterationCount();
+      if (!model->isProvenOptimal()) {
+#ifdef COIN_DEVELOP
+	  model->writeMps("bad2");
+	  printf("bad unwind in postprocess\n");
+#endif
+      } else {
+	//model->writeMps("good2");
+      }
+      const int * originalColumns = presolve_[iPass]->originalColumns();
+      const double * columnLower = modelM->getColLower(); 
+      const double * columnUpper = modelM->getColUpper();
+      OsiSolverInterface * modelM2;
+      if (iPass)
+	modelM2 = modifiedModel_[iPass-1];
+      else
+	modelM2 = startModel_;
+      const double * solutionM2 = modelM2->getColSolution();
+      const double * columnLower2 = modelM2->getColLower(); 
+      const double * columnUpper2 = modelM2->getColUpper();
+      double primalTolerance;
+      modelM->getDblParam(OsiPrimalTolerance,primalTolerance);
+      /* clean up status for any bound alterations made by preprocess which 
+	 postsolve won't understand.
+	 Could move inside OsiPresolve but some people might object */
+      CoinWarmStartBasis *presolvedBasis  = 
+	dynamic_cast<CoinWarmStartBasis*>(model->getWarmStart()) ;
+      assert (presolvedBasis);
+      int numberChanged=0;
+      // Have to use free as superBasic does not exist
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	int jColumn = originalColumns[iColumn];
+	switch (presolvedBasis->getStructStatus(iColumn)) {
+	case CoinWarmStartBasis::basic:
+	case CoinWarmStartBasis::isFree:
+	  break;
+	case CoinWarmStartBasis::atLowerBound:
+	  if (solutionM[iColumn]>columnLower2[jColumn]+primalTolerance) {
+	    presolvedBasis->setStructStatus(iColumn,CoinWarmStartBasis::isFree);
+	    numberChanged++;
+	  }
+	  break;
+	case CoinWarmStartBasis::atUpperBound:
+	  if (solutionM[iColumn]<columnUpper2[jColumn]-primalTolerance) {
+	    presolvedBasis->setStructStatus(iColumn,CoinWarmStartBasis::isFree);
+	    numberChanged++;
+	  }
+	  break;
+	}
+      }
+      if (numberChanged)
+	model->setWarmStart(presolvedBasis);
+      delete presolvedBasis;
+      presolve_[iPass]->postsolve(true);
+      // and fix values
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	int jColumn = originalColumns[iColumn];
+	if (!modelM2->isInteger(jColumn)) {
+	  if (columnUpper[iColumn]==columnLower[iColumn]) {
+	    if (columnUpper2[jColumn]>columnLower2[jColumn]&&!modelM2->isInteger(jColumn)) {
+	      double value = solutionM[iColumn];
+	      value = CoinMax(value,columnLower[iColumn]);
+	      value = CoinMin(value,columnUpper[iColumn]);
+#ifdef COIN_DEVELOP
+	      printf ("assuming %d fixed to solution of %g (was %g) - bounds %g %g, old bounds and sol %g %g\n",
+		      jColumn,value,solutionM2[jColumn],columnLower2[jColumn],columnUpper2[jColumn],
+		      columnLower[iColumn],columnUpper[iColumn]);
+#endif
+	      modelM2->setColUpper(jColumn,value);
+	    }
+	  } else {
+#if 0
+	    if (columnUpper2[jColumn]>columnLower2[jColumn]&&!modelM2->isInteger(jColumn)) {
+	      double value = solutionM[iColumn];
+	      value = CoinMax(value,columnLower[iColumn]);
+	      value = CoinMin(value,columnUpper[iColumn]);
+	      printf ("assuming %d not fixed to solution of %g (was %g) - bounds %g %g, old bounds and sol %g %g\n",
+		      jColumn,value,solutionM2[jColumn],columnLower2[jColumn],columnUpper2[jColumn],
+		      columnLower[iColumn],columnUpper[iColumn]);
+	    }
+#endif
+	  }
+	} else {
+	  // integer - dupcol bounds may be odd so use solution
+	  double value = floor(solutionM2[jColumn]+0.5);
+	  if (value<columnLower2[jColumn]) {
+	    //printf("changing lower bound for %d from %g to %g to allow feasibility\n",
+	    //	   jColumn,columnLower2[jColumn],value);
+	    modelM2->setColLower(jColumn,value);
+	  } else if (value>columnUpper2[jColumn]) {
+	    //printf("changing upper bound for %d from %g to %g to allow feasibility\n",
+	    //	   jColumn,columnUpper2[jColumn],value);
+	    modelM2->setColUpper(jColumn,value);
+	  } 
+	}
+      }
+      if (deleteStuff) {
+	delete modifiedModel_[iPass];;
+	delete model_[iPass];;
+	delete presolve_[iPass];
+	modifiedModel_[iPass]=NULL;
+	model_[iPass]=NULL;
+	presolve_[iPass]=NULL;
+      }
+      modelM = modelM2;
+    }
+    // should be back to startModel_;
+    OsiSolverInterface * model = originalModel_;
+    // Use number of columns in original
+    int numberColumns = model->getNumCols();
+    const double * solutionM = modelM->getColSolution();
+    int iColumn;
+    const double * columnLower2 = model->getColLower(); 
+    const double * columnUpper2 = model->getColUpper();
+    const double * columnLower = modelM->getColLower(); 
+    const double * columnUpper = modelM->getColUpper();
+    int numberBadValues = 0;
+    CoinWarmStartBasis* basis =
+      dynamic_cast <CoinWarmStartBasis*>(modelM->getWarmStart()) ;
+    if (basis) {
+      model->setWarmStart(basis);
+      delete basis;
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (modelM->isInteger(iColumn)) {
+	double value = solutionM[iColumn];
+	double value2 = floor(value+0.5);
+	// if test fails then empty integer
+	if (fabs(value-value2)<1.0e-3) {
+	  value2 = CoinMax(CoinMin(value2,columnUpper[iColumn]),columnLower[iColumn]);
+	  model->setColLower(iColumn,value2);
+	  model->setColUpper(iColumn,value2);
+	} else {
+#ifdef COIN_DEVELOP
+	  printf("NPASS=%d, ipass end var %d values %g %g %g\n",
+		 numberSolvers_,iColumn,model->getColLower()[iColumn],
+		 value,model->getColUpper()[iColumn]);
+#endif
+	  numberBadValues++;
+	}
+      } else if (columnUpper[iColumn]==columnLower[iColumn]) {
+	if (columnUpper2[iColumn]>columnLower2[iColumn]&&!model->isInteger(iColumn)) {
+	  model->setColUpper(iColumn,columnLower[iColumn]);
+	}
+      }
+    }
+    if(numberBadValues) {
+      const CoinPackedMatrix * columnCopy = model->getMatrixByCol();
+      const int * row = columnCopy->getIndices();
+      const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+      const int * columnLength = columnCopy->getVectorLengths(); 
+      const double * element = columnCopy->getElements();
+      int numberRows = model->getNumRows();
+      double * rowActivity = new double[numberRows];
+      memset(rowActivity,0,numberRows*sizeof(double));
+      double * solution = CoinCopyOfArray(solutionM,numberColumns);
+      for ( iColumn=0;iColumn<numberColumns;iColumn++) {
+	double value = solutionM[iColumn];
+	if (modelM->isInteger(iColumn)) {
+	  double value2 = floor(value+0.5);
+	  // if test fails then empty integer
+	  if (fabs(value-value2)<1.0e-3) 
+	    value = value2;
+	}
+	solution[iColumn] = value;
+	for (CoinBigIndex j=columnStart[iColumn];
+	     j<columnStart[iColumn]+columnLength[iColumn];j++) {
+	  int iRow=row[j];
+	  rowActivity[iRow] += value*element[j];
+	}
+      }
+      const double * rowLower = model->getRowLower();
+      const double * rowUpper = model->getRowUpper();
+      //const double * columnLower = model->getColLower(); 
+      //const double * columnUpper = model->getColUpper();
+      const double * objective = model->getObjCoefficients();
+      double direction = model->getObjSense();
+      int numberCheck=0;
+      double tolerance;
+      model->getDblParam(OsiPrimalTolerance,tolerance);
+      tolerance *= 10.0;
+      for ( iColumn=0;iColumn<numberColumns;iColumn++) {
+	double value = solution[iColumn];
+	if (model->isInteger(iColumn)) {
+	  double value2 = floor(value);
+	  // See if empty integer
+	  if (value!=value2) {
+	    numberCheck++;
+	    int allowed=0;
+	    // can we go up
+	    double movement = value2+1.0-value;
+	    CoinBigIndex j;
+	    bool good=true;
+	    for (j=columnStart[iColumn];
+		 j<columnStart[iColumn]+columnLength[iColumn];j++) {
+	      int iRow=row[j];
+#ifdef COIN_DEVELOP
+	      if (rowLower[iRow]>-1.0e20&&rowUpper[iRow]<1.0e20)
+		printf("odd row with both bounds %d %g %g - element %g\n",
+		       iRow,rowLower[iRow],rowUpper[iRow],element[j]);
+#endif
+	      double newActivity = rowActivity[iRow] + movement*element[j];
+	      if (newActivity>rowUpper[iRow]+tolerance||
+		  newActivity<rowLower[iRow]-tolerance)
+		good=false;
+	    }
+	    if (good)
+	      allowed=1;
+	    // can we go down
+	    movement = value2-value;
+	    good=true;
+	    for (j=columnStart[iColumn];
+		 j<columnStart[iColumn]+columnLength[iColumn];j++) {
+	      int iRow=row[j];
+	      double newActivity = rowActivity[iRow] + movement*element[j];
+	      if (newActivity>rowUpper[iRow]+tolerance||
+		  newActivity<rowLower[iRow]-tolerance)
+		good=false;
+	    }
+	    if (good)
+	      allowed |= 2;
+	    if (allowed) {
+	      if (allowed==3) {
+		if (direction*objective[iColumn]>0.0)
+		  allowed=2;
+		else
+		  allowed=1;
+	      }
+	      if(allowed==1) value2++;
+	      movement =  value2-value;
+	      solution[iColumn]=value2;
+	      model->setColLower(iColumn,value2);
+	      model->setColUpper(iColumn,value2);
+	      for (j=columnStart[iColumn];
+		   j<columnStart[iColumn]+columnLength[iColumn];j++) {
+		int iRow=row[j];
+		rowActivity[iRow] += movement*element[j];
+	      }
+	    } else {
+#ifdef COIN_DEVELOP
+	      printf("Unable to move %d\n",iColumn);
+#endif
+	    }
+	  }
+	}
+      }
+      assert (numberCheck==numberBadValues);
+      model->setColSolution(solution);
+      delete [] rowActivity;
+      delete [] solution;
+    }
+  } else {
+    // infeasible 
+    for (int iPass=numberSolvers_-1;iPass>=0;iPass--) {
+      delete modifiedModel_[iPass];;
+      delete model_[iPass];;
+      delete presolve_[iPass];
+      modifiedModel_[iPass]=NULL;
+      model_[iPass]=NULL;
+      presolve_[iPass]=NULL;
+    }
+    // Back to startModel_;
+    OsiSolverInterface * model = originalModel_;
+    // Use number of columns in original
+    int numberColumns = model->getNumCols();
+    const double * columnLower = model->getColLower();
+    int iColumn;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (model->isInteger(iColumn)) 
+	model->setColUpper(iColumn,columnLower[iColumn]);
+    }
+  }
+  delete clonedCopy;
+  originalModel_->setHintParam(OsiDoPresolveInInitial,true,OsiHintTry);
+  originalModel_->setHintParam(OsiDoDualInInitial,false,OsiHintTry);
+  //printf("dumping ss.mps.gz in postprocess\n");
+  //originalModel_->writeMps("ss");
+  {
+    int numberFixed=0;
+    int numberColumns = originalModel_->getNumCols();
+    const double * columnLower = originalModel_->getColLower(); 
+    const double * columnUpper = originalModel_->getColUpper();
+    int iColumn;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (columnLower[iColumn]==columnUpper[iColumn])
+	numberFixed++;
+    }
+    //printf("XX %d columns, %d fixed\n",numberColumns,numberFixed);
+    //double time1 = CoinCpuTime();
+    //originalModel_->initialSolve();
+    //printf("Time with basis %g seconds, %d iterations\n",CoinCpuTime()-time1,originalModel_->getIterationCount());
+    if (numberColumns<10000||numberFixed==numberColumns) {
+      CoinWarmStart * empty = originalModel_->getEmptyWarmStart();
+      originalModel_->setWarmStart(empty);
+      delete empty;
+    }
+  }
+  //double time1 = CoinCpuTime();
+  originalModel_->initialSolve();
+  numberIterationsPost_ += originalModel_->getIterationCount();
+  //printf("Time without basis %g seconds, %d iterations\n",CoinCpuTime()-time1,originalModel_->getIterationCount());
+  double objectiveValue = originalModel_->getObjValue();
+  double testObj = 1.0e-8*CoinMax(fabs(saveObjectiveValue),
+				  fabs(objectiveValue))+1.0e-4;
+  if (!originalModel_->isProvenOptimal()) {
+#ifdef COIN_DEVELOP
+    originalModel_->writeMps("bad3");
+    printf("bad end unwind in postprocess\n");
+#endif
+    handler_->message(CGL_POST_INFEASIBLE,messages_)
+      <<CoinMessageEol;
+  } else if (fabs(saveObjectiveValue-objectiveValue)>testObj
+	     &&deleteStuff
+	     ) {
+    handler_->message(CGL_POST_CHANGED,messages_)
+      <<saveObjectiveValue<<objectiveValue
+      <<CoinMessageEol;
+  }
+  originalModel_->setHintParam(OsiDoDualInInitial,saveHint2,saveStrength2);
+  originalModel_->setHintParam(OsiDoPresolveInInitial,saveHint,saveStrength);
+}
+//-------------------------------------------------------------------
+// Returns the greatest common denominator of two 
+// positive integers, a and b, found using Euclid's algorithm 
+//-------------------------------------------------------------------
+static int gcd(int a, int b) 
+{
+  int remainder = -1;
+  // make sure a<=b (will always remain so)
+  if(a > b) {
+    // Swap a and b
+    int temp = a;
+    a = b;
+    b = temp;
+  }
+  // if zero then gcd is nonzero (zero may occur in rhs of packed)
+  if (!a) {
+    if (b) {
+      return b;
+    } else {
+      printf("**** gcd given two zeros!!\n");
+      abort();
+    }
+  }
+  while (remainder) {
+    remainder = b % a;
+    b = a;
+    a = remainder;
+  }
+  return b;
+}
+/* Return model with useful modifications.  
+   If constraints true then adds any x+y=1 or x-y=0 constraints
+   If NULL infeasible
+*/
+OsiSolverInterface * 
+CglPreProcess::modified(OsiSolverInterface * model,
+			bool constraints,
+			int & numberChanges,
+                        int iBigPass,
+			int numberPasses)
+{
+  OsiSolverInterface * newModel = model->clone();
+  int numberRows = newModel->getNumRows();
+  CglUniqueRowCuts twoCuts(numberRows);
+  int numberColumns = newModel->getNumCols();
+  int number01Integers=0;
+  int iColumn;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (newModel->isBinary(iColumn))
+      number01Integers++;
+  }
+  OsiRowCut ** whichCut = new OsiRowCut * [numberRows+1];
+  memset(whichCut, 0, (numberRows+1)*sizeof(OsiRowCut *));
+  numberChanges=0;
+  CoinThreadRandom randomGenerator;
+  CglTreeProbingInfo info(model);
+  info.level = 0;
+  info.pass = 0;
+  info.formulation_rows = numberRows;
+  info.inTree = false;
+  info.options = !numberProhibited_ ? 0 : 2;
+  info.randomNumberGenerator=&randomGenerator;
+  info.strengthenRow= whichCut;
+#ifdef HEAVY_PROBING
+  // See if user asked for heavy probing
+  bool heavyProbing=false;
+  for (int iGenerator=0;iGenerator<numberCutGenerators_;iGenerator++) {
+    CglProbing * probingCut = dynamic_cast<CglProbing *> (generator_[iGenerator]);
+    if (probingCut&&probingCut->getMaxPassRoot()>1) {
+      heavyProbing=true;
+      break;
+    }
+  }
+#endif
+  bool feasible=true;
+  int firstGenerator=0;
+  int lastGenerator=numberCutGenerators_;
+  for (int iPass=0;iPass<numberPasses;iPass++) {
+    // Statistics
+    int numberFixed=0;
+    int numberTwo=twoCuts.sizeRowCuts();
+    int numberStrengthened=0;
+    info.pass = iPass;
+    info.options=0;
+    int numberChangedThisPass=0;
+    /*
+      needResolve    solution is stale
+      rebuilt   constraint system deleted and recreated (implies initialSolve)
+    */
+    for (int iGenerator=firstGenerator;iGenerator<lastGenerator;iGenerator++) {
+      bool needResolve = false ;
+      bool rebuilt = false ;
+      OsiCuts cs;
+      CoinZeroN(whichCut,numberRows);
+      CglProbing * probingCut=NULL;
+      int numberFromCglDuplicate=0;
+      const int * duplicate=NULL;
+      CglDuplicateRow * dupRow = NULL;
+      CglClique * cliqueGen = NULL;
+      if (iGenerator>=0) {
+        //char name[20];
+        //sprintf(name,"prex%2.2d.mps",iGenerator);
+        //newModel->writeMpsNative(name, NULL, NULL,0,1,0);
+        // refresh as model may have changed
+        generator_[iGenerator]->refreshSolver(newModel);
+        // skip duplicate rows except once
+        dupRow = dynamic_cast<CglDuplicateRow *> (generator_[iGenerator]);
+	cliqueGen = dynamic_cast<CglClique *> (generator_[iGenerator]);
+        if ((dupRow||cliqueGen)&&(iPass/*||iBigPass*/))
+            continue;
+        probingCut = dynamic_cast<CglProbing *> (generator_[iGenerator]);
+	if (!probingCut) {
+	  generator_[iGenerator]->generateCuts(*newModel,cs,info);
+	} else {
+	  info.options=64;
+          probingCut->setMode(4);
+	  probingCut->generateCutsAndModify(*newModel,cs,&info);
+	}
+#if 1 //def CLIQUE_ANALYSIS
+	if (probingCut) {
+	  //printf("ordinary probing\n");
+	  info.analyze(*newModel);
+	} 
+#endif
+        // If CglDuplicate may give us useless rows
+        if (dupRow) {
+          numberFromCglDuplicate = dupRow->numberOriginalRows();
+          duplicate = dupRow->duplicate();
+        }
+	if (cliqueGen&&cs.sizeRowCuts()) {
+	  int n = cs.sizeRowCuts();
+	  printf("%d clique cuts\n",n);
+	  OsiSolverInterface * copySolver = newModel->clone();
+	  numberRows=copySolver->getNumRows();
+	  copySolver->applyCuts(cs);
+	  //static int kk=0;
+	  //char name[20];
+	  //kk++;
+	  //sprintf(name,"matrix%d",kk);
+	  //printf("writing matrix %s\n",name);
+	  //copySolver->writeMps(name);
+	  CglDuplicateRow dupCuts(copySolver);
+	  dupCuts.setMode(8);
+	  OsiCuts cs2;
+	  dupCuts.generateCuts(*copySolver,cs2,info);
+	  // -1 not used, -2 delete, -3 not clique
+	  const int * duplicate = dupCuts.duplicate();
+	  // -1 not used, >=0 earliest row affected
+	  const int * used = duplicate+numberRows+n;
+	  int numberDrop=0;
+	  int * drop = new int[numberRows];
+	  for (int iRow=0;iRow<numberRows;iRow++) {
+	    if (duplicate[iRow]==-2) 
+	      drop[numberDrop++]=iRow;
+	  }
+	  int nOther=0;
+	  for (int iRow=numberRows+n-1;iRow>=numberRows;iRow--) {
+#if 1
+	    int earliest = used[iRow];
+	    while (earliest>=numberRows) {
+	      if (duplicate[earliest]==-2) 
+		earliest = used[earliest];
+	      else
+		break;
+	    }
+#else
+	    int earliest=0;
+#endif
+	    if (duplicate[iRow]==-2||earliest==-1||earliest>=numberRows) { 
+	      cs.eraseRowCut(iRow-numberRows);
+	      nOther++;
+	    }
+	  }
+	  n -= nOther;
+	  int newNumberRows = numberRows-numberDrop+n;
+	  bool special = (cliqueGen->getMinViolation()==-3.0);
+	  printf("could drop %d rows - current nrows %d other %d - new nrows %d\n",
+		 numberDrop,numberRows,nOther,newNumberRows);
+	  if (n<=numberDrop||special) {
+	    printf("Dropping rows current nrows %d - new nrows %d\n",
+		   numberRows,newNumberRows);
+	    if (newNumberRows>numberRows) {
+	      // need new array
+	      delete [] whichCut;
+	      whichCut = new OsiRowCut * [newNumberRows+1];
+	      CoinZeroN(whichCut,newNumberRows);
+	      info.strengthenRow= whichCut;
+	    }
+	    newModel->deleteRows(numberDrop,drop);
+	    // may be able to delete some added cliques
+	    newModel->applyCuts(cs);
+	    numberRows=newModel->getNumRows();
+	    newModel->resolve();
+#if 0
+	    int numberRows2=copySolver->getNumRows();
+	    const double * rowLower = copySolver->getRowLower();
+	    const double * rowUpper = copySolver->getRowUpper();
+	    const CoinPackedMatrix * matrixByRow = copySolver->getMatrixByRow();
+	    // Row copy
+	    const double * elementByRow = matrixByRow->getElements();
+	    const int * column = matrixByRow->getIndices();
+	    const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
+	    const int * rowLength = matrixByRow->getVectorLengths();
+	    const double * solution = newModel->getColSolution();
+	    for (int iRow=0;iRow<numberRows2;iRow++) {
+	      double sum=0.0;
+	      for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+		int iColumn = column[j];
+		double value = elementByRow[j];
+		sum += value*solution[iColumn];
+	      }
+	      assert (sum>rowLower[iRow]-1.0e-4&&sum<rowUpper[iRow]+1.0e-4);
+	    }
+#endif
+	  }
+	  delete copySolver;
+	  delete [] drop;
+	  continue;
+	  //for (int i=0;i<n;i++) {
+	  //OsiRowCut & thisCut = cs.rowCut(i);
+	  //thisCut.print();
+	  //}
+	}
+      } else {
+#ifdef HEAVY_PROBING
+        // special probing
+        CglProbing generator1;
+        probingCut=&generator1;
+        generator1.setUsingObjective(false);
+        generator1.setMaxPass(1);
+        generator1.setMaxPassRoot(1);
+        generator1.setMaxProbeRoot(100);
+        generator1.setMaxLook(100);
+        generator1.setRowCuts(3);
+	if (heavyProbing) {
+	  generator1.setMaxElements(300);
+	  generator1.setMaxProbeRoot(model->getNumCols());
+	}
+	// out for now - think about cliques
+        if(!generator1.snapshot(*newModel,NULL,false)) {
+          generator1.createCliques(*newModel,2,1000,true);
+          // To get special stuff
+          info.pass=4;
+          CoinZeroN(whichCut,numberRows);
+          generator1.setMode(4);
+          generator1.generateCutsAndModify(*newModel,cs,&info);
+#ifdef CLIQUE_ANALYSIS
+	  printf("special probing\n");
+	  info.analyze(*newModel);
+#endif
+        } else {
+          feasible=false;
+        }
+#endif
+      }
+      // check changes
+      // first are any rows strengthened by cuts
+      int iRow;
+      for (iRow=0;iRow<numberRows;iRow++) {
+        if(whichCut[iRow])
+          numberStrengthened++;
+      }
+      // Also can we get rid of duplicate rows
+      int numberDrop=0;
+      for (iRow=0;iRow<numberFromCglDuplicate;iRow++) {
+        if (duplicate[iRow]==-2||duplicate[iRow]>=0) {
+          numberDrop++;
+          newModel->setRowBounds(iRow,-COIN_DBL_MAX,COIN_DBL_MAX);
+        }
+      }
+      const double * columnLower = newModel->getColLower();
+      const double * columnUpper = newModel->getColUpper();
+      if ((numberStrengthened||numberDrop)&&feasible) {
+	/*
+	  
+	Deleting all rows and rebuilding invalidates everything, initialSolve will
+	be required.
+	*/
+	needResolve = true ;
+	rebuilt = true ;
+        // Easier to recreate entire matrix
+        const CoinPackedMatrix * rowCopy = newModel->getMatrixByRow();
+        const int * column = rowCopy->getIndices();
+        const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+        const int * rowLength = rowCopy->getVectorLengths(); 
+        const double * rowElements = rowCopy->getElements();
+        const double * rowLower = newModel->getRowLower();
+        const double * rowUpper = newModel->getRowUpper();
+        CoinBuild build;
+	// For basis
+	char * keepRow = new char [numberRows];
+        for (iRow=0;iRow<numberRows;iRow++) {
+	  keepRow[iRow]=0;
+          OsiRowCut * thisCut = whichCut[iRow];
+          whichCut[iRow]=NULL;
+          if (rowLower[iRow]>-1.0e20||rowUpper[iRow]<1.0e20) {
+#if 0
+	    if (thisCut) {
+	      printf("Cut on row %d\n",iRow);
+	      thisCut->print();
+	    }
+#endif
+            if (!thisCut) {
+              // put in old row
+              int start=rowStart[iRow];
+	      int kInt=-1;
+	      double newValue=0.0;
+	      if (!iPass&&!iBigPass) {
+		// worthwhile seeing if odd gcd
+		int end = start + rowLength[iRow];
+		double rhsAdjustment=0.0;
+		int nPosInt=0;
+		int nNegInt=0;
+		// Find largest integer coefficient
+		int k;
+		for ( k = start; k < end; ++k) {
+		  CoinBigIndex j = column[k];
+		  if (columnUpper[j]>columnLower[j]) {
+		    if (newModel->isInteger(j)) {
+		      if (rowElements[k]>0.0)
+			nPosInt++;
+		      else
+			nNegInt++;
+		    } else {
+		      break; // no good
+		    }
+		  } else {
+		    rhsAdjustment += columnLower[j]*rowElements[k];
+		  }
+		}
+		if (k==end) {
+		  // see if singleton coefficient can be strengthened
+		  if ((nPosInt==1&&nNegInt>1)||(nNegInt==1&&nPosInt>1)) {
+		    double lo;
+		    double up;
+		    if (rowLower[iRow]>-1.0e20)
+		      lo = rowLower[iRow]-rhsAdjustment;
+		    else
+		      lo=-COIN_DBL_MAX;
+		    if(rowUpper[iRow]<1.0e20)
+		      up = rowUpper[iRow]-rhsAdjustment;
+		    else
+		      up=COIN_DBL_MAX;
+		    double multiplier=1.0;
+		    if (nNegInt==1) {
+		      // swap signs
+		      multiplier=lo;
+		      lo=-up;
+		      up=-multiplier;
+		      multiplier=-1.0;
+		    }
+		    bool possible=true;
+		    double singletonValue=0;
+		    double scale = 4.0*5.0*6.0;
+		    int kGcd=-1;
+		    double smallestSum = 0.0;
+		    double largestSum = 0.0;
+		    for ( k = start; k < end; ++k) {
+		      CoinBigIndex j = column[k];
+		      double value=multiplier*rowElements[k];
+		      if (columnUpper[j]>columnLower[j]) {
+			if (value>0.0) {
+			  // singleton
+			  kInt=j;
+			  if (columnUpper[j]-columnLower[j]!=1.0) {
+			    possible = false;
+			    break;
+			  } else {
+			    singletonValue=value;
+			  }
+			} else {
+			  if (columnLower[j]>-1.0e10)
+			    smallestSum += value*columnLower[j];
+			  else
+			    smallestSum = -COIN_DBL_MAX;
+			  if (columnUpper[j]<-1.0e10)
+			    largestSum += value*columnUpper[j];
+			  else
+			    largestSum = COIN_DBL_MAX;
+			  value *=-scale;
+			  if (fabs(value-floor(value+0.5))>1.0e-12) {
+			    possible=false;
+			    break;
+			  } else {
+			    int kVal = static_cast<int> (floor(value+0.5));
+			    if (kGcd>0) 
+			      kGcd = gcd(kGcd,kVal);
+			    else
+			      kGcd=kVal;
+			  }
+			}
+		      }
+		    }
+		    if (possible) {
+		      double multiple = (static_cast<double> (kGcd))/scale;
+		      int interesting=0;
+		      double saveLo=lo;
+		      double saveUp=up;
+#ifdef CLP_INVESTIGATE
+		      double nearestLo0=lo;
+            double nearestLo1=lo;
+#endif
+		      double nearestUp0=up;
+		      double nearestUp1=up;
+		      // adjust rhs for singleton 
+		      if (lo!=-COIN_DBL_MAX) {
+			// singleton at lb
+			lo -= columnLower[kInt]*singletonValue;
+			double exact = lo/multiple;
+			if (fabs(exact-floor(exact+0.5))>1.0e-4) {
+			  interesting +=1;
+#ifdef CLP_INVESTIGATE
+			  nearestLo0 = ceil(exact)*multiple;
+#endif
+			} 
+			// singleton at ub
+			lo -= singletonValue;
+			exact = lo/multiple;
+			if (fabs(exact-floor(exact+0.5))>1.0e-4) {
+			  interesting +=2;
+#ifdef CLP_INVESTIGATE
+			  nearestLo1 = ceil(exact)*multiple;
+#endif
+			}
+		      }
+		      if (up!=COIN_DBL_MAX) {
+			// singleton at lb
+			up -= columnLower[kInt]*singletonValue;
+			double exact = up/multiple;
+			if (fabs(exact-floor(exact+0.5))>1.0e-4) {
+			  interesting +=4;
+			  nearestUp0 = floor(exact)*multiple;
+			} 
+			// singleton at ub
+			up -= singletonValue;
+			exact = up/multiple;
+			if (fabs(exact-floor(exact+0.5))>1.0e-4) {
+			  interesting +=8;
+			  nearestUp1 = floor(exact)*multiple;
+			} 
+		      }
+		      if (interesting) {
+#ifdef CLP_INVESTIGATE
+			printf("Row %d interesting %d lo,up %g,%g singleton %d value %g bounds %g,%g - gcd %g\n",iRow,interesting,saveLo,saveUp,kInt,singletonValue,
+			       columnLower[kInt],columnUpper[kInt],multiple);
+			printf("Orig lo,up %g,%g %d\n",rowLower[iRow],rowUpper[iRow],end-start);
+			for ( k = start; k < end; ++k) {
+			  CoinBigIndex j = column[k];
+			  double value=multiplier*rowElements[k];
+			  printf(" (%d, %g - bds %g, %g)",j,value,
+				 columnLower[j],columnUpper[j]);
+			}
+			printf("\n");
+#endif
+			if(columnLower[kInt]) {
+#ifdef CLP_INVESTIGATE
+			  printf("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\n"); //think
+#endif
+			  interesting=0;
+			}
+			newValue = singletonValue;
+#ifdef CLP_INVESTIGATE
+			double newLoRhs = rowLower[iRow];
+			double newUpRhs = rowUpper[iRow];
+			if ((interesting&3)!=0) {
+			  newLoRhs = nearestLo0;
+			  newValue = nearestLo0-nearestLo1;
+			}
+#endif
+			if (saveLo==saveUp&&((interesting&5)==5||(interesting&10)==10)) {
+#ifdef CLP_INVESTIGATE
+			  printf("INFEAS? ");
+#endif
+			  interesting=0; //ninfeas++;
+			}
+			if ((interesting&12)) {
+#ifdef CLP_INVESTIGATE
+			  double value2 = newValue;
+			  newUpRhs = nearestUp0;
+#endif
+			  newValue = nearestUp0-nearestUp1;
+#ifdef CLP_INVESTIGATE
+			  if (newValue!=value2) {
+			    printf("??? old newvalue %g ",newValue);
+			  }
+#endif
+			}
+#ifdef CLP_INVESTIGATE
+			printf("guess is new lo %g, new up %g, new value %g\n",
+			       newLoRhs,newUpRhs,newValue);
+#endif
+		      }
+		      // Just do mzzv11 case
+		      double exact = singletonValue/multiple;
+		      if (fabs(exact-floor(exact+0.5))<1.0e-5)
+			interesting &= ~2;
+		      if (!smallestSum&&interesting==2&&!saveLo&&saveUp>1.0e20) {
+			newValue = multiple*floor(exact);
+			newValue *= multiplier;
+#ifdef CLP_INVESTIGATE
+			printf("New coefficient for %d will be %g\n",kInt,newValue);
+#endif
+		      } else {
+			// don't do
+			kInt=-1;
+		      }
+		    } else {
+		      kInt=-1;
+		    }
+		  }
+		}
+		// endgcd
+	      }
+	      int length = rowLength[iRow];
+	      if (kInt<0) {
+		build.addRow(length,column+start,rowElements+start,
+			     rowLower[iRow],rowUpper[iRow]);
+	      } else {
+		double * els = CoinCopyOfArray(rowElements+start,length);
+		if (fabs(newValue)>1.0e-13) {
+		  for ( int k = 0; k < length; ++k) {
+		    int j = column[k+start];
+		    if (j==kInt) {
+		      els[k] = newValue;
+		      break;
+		    }
+		  }
+		  build.addRow(length,column+start,els,
+			       rowLower[iRow],rowUpper[iRow]);
+		} else {
+		  // strengthened to zero!
+#ifdef CLP_INVESTIGATE
+		  printf("CglPreProcess - element strenthened to zero!\n");
+#endif
+		  int * cols = CoinCopyOfArray(column+start,length);
+		  int n=0;
+		  for ( int k = 0; k < length; ++k) {
+		    int j = cols[k];
+		    if (j!=kInt) {
+		      els[n] = els[k];
+		      cols[n++]=j;
+		    }
+		  }
+		  build.addRow(n,cols,els,
+			       rowLower[iRow],rowUpper[iRow]);
+		  delete [] cols;
+		}
+		delete [] els;
+	      }
+	      keepRow[iRow]=1;
+            } else {
+              // strengthens this row (should we check?)
+              // may be worth going round again
+              numberChangedThisPass++;
+              int n=thisCut->row().getNumElements();
+              const int * columnCut = thisCut->row().getIndices();
+              const double * elementCut = thisCut->row().getElements();
+              double lower = thisCut->lb();
+              double upper = thisCut->ub();
+              if (probingCut) {
+                int i;
+                int nFree=0;
+                for ( i=0;i<n;i++) {
+                  int iColumn = columnCut[i];
+                  if (columnUpper[iColumn]>columnLower[iColumn]+1.0e-12)
+                    nFree++;
+                }
+                bool good = (n==nFree);
+		nFree=0;
+                int n1=rowLength[iRow];
+                int start=rowStart[iRow];
+                for ( i=0;i<n1;i++) {
+                  int iColumn = column[start+i];
+                  if (columnUpper[iColumn]>columnLower[iColumn]+1.0e-12)
+                    nFree++;
+                }
+                if (n1!=nFree) 
+		  good=false;
+                if (good) {
+#if 0
+                  printf("Original row %.8d %g <= ",iRow,rowLower[iRow]);
+                  for ( i=0;i<n1;i++) 
+		    printf("%g * x%d ",rowElements[start+i],column[start+i]);
+                  printf("<= %g\n",rowUpper[iRow]);
+                  printf("New                   %g <= ",lower);
+                  for ( i=0;i<n;i++) 
+		    printf("%g * x%d ",elementCut[i],columnCut[i]);
+                  printf("<= %g\n",upper);
+#endif
+                } else {
+                  // can't use
+                  n=-1;
+		  numberStrengthened--;
+                  // put in old row
+                  int start=rowStart[iRow];
+                  build.addRow(rowLength[iRow],column+start,rowElements+start,
+                               rowLower[iRow],rowUpper[iRow]);
+		  keepRow[iRow]=1;
+                }
+              }
+              if (n>0) {
+                build.addRow(n,columnCut,elementCut,lower,upper);
+		keepRow[iRow]=1;
+              } else if (!n) {
+                // Either infeasible or redundant
+                if (lower<=0.0&&upper>=0.0) {
+                  // redundant - row will go
+                } else {
+                  // infeasible!
+                  feasible=false;
+                  break;
+                }
+              }
+            }
+          }
+        }
+	if (rowType_) {
+	  assert (numberRowType_==numberRows);
+	  int numberRowType_=0;
+	  for (iRow=0;iRow<numberRows;iRow++) {
+	    if (keepRow[iRow]) {
+	      rowType_[numberRowType_++]=rowType_[iRow];
+	    }
+	  }
+	}
+	// recreate
+        int * del = new int[numberRows];
+	// save and modify basis
+	CoinWarmStartBasis* basis =
+	  dynamic_cast <CoinWarmStartBasis*>(newModel->getWarmStart()) ;
+	if (basis) {
+	  int n=0;
+	  for (iRow=0;iRow<numberRows;iRow++) {
+	    if (!keepRow[iRow]) {
+	      del[n++]=iRow;
+	    }
+	  }
+	  basis->deleteRows(n,del);
+	}
+        for (iRow=0;iRow<numberRows;iRow++) 
+          del[iRow]=iRow;
+        newModel->deleteRows(numberRows,del);
+        newModel->addRows(build);
+        numberRows = newModel->getNumRows();
+	if (basis) {
+	  assert (numberRows==basis->getNumArtificial());
+	  newModel->setWarmStart(basis);
+	  delete basis;
+	}
+        if (dupRow&&cs.sizeRowCuts())
+	  newModel->applyCuts(cs);
+	delete [] keepRow;
+        delete [] del;
+/*
+  VIRTUOUS
+
+  A solver is not required to hold these pointers constant across complete
+  row deletion and rebuild.
+*/
+	columnLower = newModel->getColLower();
+	columnUpper = newModel->getColUpper();
+      }
+      if (!feasible)
+        break;
+      // now see if we have any x=y x+y=1
+      if (constraints) {
+        int numberRowCuts = cs.sizeRowCuts() ;
+        for (int k = 0;k<numberRowCuts;k++) {
+          OsiRowCut * thisCut = cs.rowCutPtr(k) ;
+          int n=thisCut->row().getNumElements();
+          double lower = thisCut->lb();
+          double upper = thisCut->ub();
+          if (n==2&&lower==upper) {
+            twoCuts.insert(*thisCut);
+          }
+        }
+      }
+      if (probingCut) {
+	// we could look harder for infeasibilities 
+	assert (info.numberVariables()==numberColumns);
+	int number01 = info.numberIntegers();
+	const cliqueEntry * entry = info.fixEntries();
+	const int * toZero = info.toZero();
+	const int * toOne = info.toOne();
+	const int * which = info.integerVariable();
+	int numberBounds=0;
+	char * markLB = new char [number01];
+	memset(markLB,0,number01);
+	char * markUB = new char [number01];
+	memset(markUB,0,number01);
+	for (int k=0;k<number01;k++) {
+	  int start = toZero[k];
+	  int end = toOne[k];
+	  // to zero
+	  int j;
+	  for (j=start;j<end;j++) {
+	    int goingToOne = oneFixesInCliqueEntry(entry[j]);
+	    int v = sequenceInCliqueEntry(entry[j]);
+	    if (v>=number01)
+	      continue;
+	    if (goingToOne) {
+	      // If v -> 1 means k -> 0 we have k+v==1 
+	      int startV = toOne[v];
+	      int endV = toZero[v+1];
+	      for (int jv=startV;jv<endV;jv++) {
+		if(k==static_cast<int> (sequenceInCliqueEntry(entry[jv]))) {
+		  int goingToOneV = oneFixesInCliqueEntry(entry[jv]);
+		  double lo,up;
+		  if (!goingToOneV) {
+		    lo=1.0;
+		    up=1.0;
+		    OsiRowCut thisCut;
+		    thisCut.setLb(lo);
+		    thisCut.setUb(up);
+		    double values[]={1.0,1.0};
+		    int columns[2];
+		    columns[0]=which[k];
+		    columns[1]=which[v];
+		    thisCut.setRow(2,columns,values,false);
+		    twoCuts.insertIfNotDuplicate(thisCut);
+		  } else {
+		    // means infeasible for k to go to 0
+		    markLB[k]=1;
+		    numberBounds++;
+		  }
+		  break;
+		}
+	      }
+	    } else {
+	      // If v -> 0 means k -> 0 we have k==v 
+	      int startV = toZero[v];
+	      int endV = toOne[v];
+	      for (int jv=startV;jv<endV;jv++) {
+		if(k==static_cast<int> (sequenceInCliqueEntry(entry[jv]))) {
+		  int goingToOneV = oneFixesInCliqueEntry(entry[jv]);
+		  double lo,up;
+		  if (!goingToOneV) {
+		    lo=0.0;
+		    up=0.0;
+		    OsiRowCut thisCut;
+		    thisCut.setLb(lo);
+		    thisCut.setUb(up);
+		    double values[]={1.0,-1.0};
+		    int columns[2];
+		    columns[0]=which[k];
+		    columns[1]=which[v];
+		    thisCut.setRow(2,columns,values,false);
+		    twoCuts.insertIfNotDuplicate(thisCut);
+		  } else {
+		    // means infeasible for k to go to 0
+		    markLB[k]=1;
+		    numberBounds++;
+		  }
+		  break;
+		}
+	      }
+	    }
+	  }
+	  start = toOne[k];
+	  end = toZero[k+1];
+	  // to one
+	  for (j=start;j<end;j++) {
+	    int goingToOne = oneFixesInCliqueEntry(entry[j]);
+	    int v = sequenceInCliqueEntry(entry[j]);
+	    if (v>=number01)
+	      continue;
+	    if (goingToOne) {
+	      // If v -> 1 means k -> 1 we have k==v 
+	      int startV = toOne[v];
+	      int endV = toZero[v+1];
+	      for (int jv=startV;jv<endV;jv++) {
+		if(k==static_cast<int> (sequenceInCliqueEntry(entry[jv]))) {
+		  int goingToOneV = oneFixesInCliqueEntry(entry[jv]);
+		  double lo,up;
+		  if (goingToOneV) {
+		    lo=0.0;
+		    up=0.0;
+		    OsiRowCut thisCut;
+		    thisCut.setLb(lo);
+		    thisCut.setUb(up);
+		    double values[]={1.0,-1.0};
+		    int columns[2];
+		    columns[0]=which[k];
+		    columns[1]=which[v];
+		    thisCut.setRow(2,columns,values,false);
+		    twoCuts.insertIfNotDuplicate(thisCut);
+		  } else {
+		    // means infeasible for k to go to 1
+		    markUB[k]=1;
+		    numberBounds++;
+		  }
+		  break;
+		}
+	      }
+	    } else {
+	      // If v -> 0 means k -> 1 we have k+v==1 
+	      int startV = toZero[v];
+	      int endV = toOne[v];
+	      for (int jv=startV;jv<endV;jv++) {
+		if(k==static_cast<int> (sequenceInCliqueEntry(entry[jv]))) {
+		  int goingToOneV = oneFixesInCliqueEntry(entry[jv]);
+		  double lo,up;
+		  if (goingToOneV) {
+		    lo=1.0;
+		    up=1.0;
+		    OsiRowCut thisCut;
+		    thisCut.setLb(lo);
+		    thisCut.setUb(up);
+		    double values[]={1.0,1.0};
+		    int columns[2];
+		    columns[0]=which[k];
+		    columns[1]=which[v];
+		    thisCut.setRow(2,columns,values,false);
+		    twoCuts.insertIfNotDuplicate(thisCut);
+		  } else {
+		    // means infeasible for k to go to 1
+		    markUB[k]=1;
+		    numberBounds++;
+		  }
+		  break;
+		}
+	      }
+	    }
+	  }
+	}
+	if (numberBounds) {
+	  CoinPackedVector lbs;
+	  CoinPackedVector ubs;
+	  for (int k=0;k<number01;k++) {
+	    if (markLB[k]&&markUB[k]) {
+	      // infeasible
+	      feasible=false;
+	      break;
+	    } else if (markLB[k]) {
+	      lbs.insert(which[k],1.0);
+	    } else if (markUB[k]) {
+	      ubs.insert(which[k],0.0);
+	    }
+	  }
+	  OsiColCut cc;
+	  cc.setUbs(ubs);
+	  cc.setLbs(lbs);
+	  cc.setEffectiveness(1.0e-5);
+	  cs.insert(cc);
+	}
+	delete [] markLB;
+	delete [] markUB;
+      }
+      // see if we have any column cuts
+      int numberColumnCuts = cs.sizeColCuts() ;
+      int numberBounds=0;
+      for (int k = 0;k<numberColumnCuts;k++) {
+        OsiColCut * thisCut = cs.colCutPtr(k) ;
+	/*
+	  Nontrivial bound changes will invalidate current solution.
+	*/
+	if (thisCut->effectiveness() > 1.0) {
+	  needResolve = true ;
+	}
+	const CoinPackedVector & lbs = thisCut->lbs() ;
+	const CoinPackedVector & ubs = thisCut->ubs() ;
+	int j ;
+	int n ;
+	const int * which ;
+	const double * values ;
+	n = lbs.getNumElements() ;
+	which = lbs.getIndices() ;
+	values = lbs.getElements() ;
+	for (j = 0;j<n;j++) {
+	  int iColumn = which[j] ;
+          if (values[j]>columnLower[iColumn]&&values[j]>-1.0e20) {
+            //printf("%d lower from %g to %g\n",iColumn,columnLower[iColumn],values[j]);
+            newModel->setColLower(iColumn,values[j]) ;
+            if (false) {
+              OsiSolverInterface * xx = newModel->clone();
+              xx->initialSolve();
+              assert (xx->isProvenOptimal());
+              delete xx;
+            }
+            numberChangedThisPass++;
+            if (columnLower[iColumn]==columnUpper[iColumn]) {
+              numberFixed++;
+            } else {
+              numberBounds++;
+	      if (columnLower[iColumn]>columnUpper[iColumn]) 
+		feasible=false;
+	    }
+          }
+	}
+	n = ubs.getNumElements() ;
+	which = ubs.getIndices() ;
+	values = ubs.getElements() ;
+	for (j = 0;j<n;j++) {
+	  int iColumn = which[j] ;
+          if (values[j]<columnUpper[iColumn]&&values[j]<1.0e20) {
+            //printf("%d upper from %g to %g\n",iColumn,columnUpper[iColumn],values[j]);
+            newModel->setColUpper(iColumn,values[j]) ;
+            if (false) {
+              OsiSolverInterface * xx = newModel->clone();
+              xx->initialSolve();
+              assert (xx->isProvenOptimal());
+              delete xx;
+            }
+            numberChangedThisPass++;
+            if (columnLower[iColumn]==columnUpper[iColumn]) {
+              numberFixed++;
+            } else {
+              numberBounds++;
+	      if (columnLower[iColumn]>columnUpper[iColumn]) 
+		feasible=false;
+	    }
+          }
+        }
+      }
+      numberTwo = twoCuts.sizeRowCuts()-numberTwo;
+      numberChanges += numberTwo + numberStrengthened/10;
+      if (numberFixed||numberTwo||numberStrengthened||numberBounds)
+        handler_->message(CGL_PROCESS_STATS,messages_)
+          <<numberFixed<<numberBounds<<numberStrengthened<<numberTwo
+          <<CoinMessageEol;
+      if (!feasible)
+        break;
+      /*
+	If solution needs to be refreshed, do resolve or initialSolve as appropriate.
+      */
+      if (needResolve) {
+	if (rebuilt) {
+	  // basis shot to bits?
+	  //CoinWarmStartBasis *slack =
+	  //dynamic_cast<CoinWarmStartBasis *>(newModel->getEmptyWarmStart()) ;
+	  //newModel->setWarmStart(slack);
+	  //delete slack ;
+	  newModel->initialSolve() ;
+	} else {
+	  newModel->resolve() ;
+	}
+	numberIterationsPre_ += newModel->getIterationCount();
+	feasible = newModel->isProvenOptimal();
+	if (!feasible&&getCutoff()>1.0e20) {
+	  // Better double check
+	  CoinWarmStartBasis *slack =
+	    dynamic_cast<CoinWarmStartBasis *>(newModel->getEmptyWarmStart()) ;
+	  newModel->setWarmStart(slack);
+	  delete slack ;
+	  newModel->resolve() ;
+	  numberIterationsPre_ += newModel->getIterationCount();
+	  feasible = newModel->isProvenOptimal();
+	  //if (!feasible)
+	  //newModel->writeMpsNative("infeas.mps",NULL,NULL,2,1);
+	}
+      }
+      if (!feasible)
+        break;
+    }
+    if (!feasible)
+      break;
+    numberChanges +=  numberChangedThisPass;
+    if (iPass<numberPasses-1) {
+      if ((!numberFixed&&numberChangedThisPass<1000*(numberRows+numberColumns))||iPass==numberPasses-2) {
+        // do special probing at end - but not if very last pass
+	if (iBigPass<numberSolvers_-1) {
+	  firstGenerator=-1;
+	  lastGenerator=0;
+	}
+        iPass=numberPasses-2;
+      }
+    }
+  }
+  delete [] whichCut;
+  int numberRowCuts = twoCuts.sizeRowCuts() ;
+  if (numberRowCuts) {
+    // add in x=y etc
+    CoinBuild build;
+    for (int k = 0;k<numberRowCuts;k++) {
+      OsiRowCut * thisCut = twoCuts.rowCutPtr(k) ;
+      int n=thisCut->row().getNumElements();
+      const int * columnCut = thisCut->row().getIndices();
+      const double * elementCut = thisCut->row().getElements();
+      double lower = thisCut->lb();
+      double upper = thisCut->ub();
+      build.addRow(n,columnCut,elementCut,lower,upper);
+    }
+    newModel->addRows(build);
+    if (rowType_) {
+      // adjust
+      int numberRows=newModel->getNumRows();
+      char * temp = CoinCopyOfArrayPartial(rowType_,numberRows,numberRowType_);
+      delete [] rowType_;
+      rowType_ = temp;
+      for (int iRow=numberRowType_;iRow<numberRows;iRow++)
+	rowType_[iRow]=-1;
+      numberRowType_=numberRows;
+    }
+  }
+  if (!feasible) {
+    delete newModel;
+    newModel=NULL;
+  }
+  return newModel;
+}
+
+/* Default Constructor
+
+*/
+CglPreProcess::CglPreProcess() 
+
+:
+  originalModel_(NULL),
+  startModel_(NULL),
+  numberSolvers_(0),
+  model_(NULL),
+  modifiedModel_(NULL),
+  presolve_(NULL),
+  handler_(NULL),
+  defaultHandler_(true),
+  appData_(NULL),
+  originalColumn_(NULL),
+  originalRow_(NULL),
+  numberCutGenerators_(0),
+  generator_(NULL),
+  numberSOS_(0),
+  typeSOS_(NULL),
+  startSOS_(NULL),
+  whichSOS_(NULL),
+  weightSOS_(NULL),
+  numberProhibited_(0),
+  numberIterationsPre_(0),
+  numberIterationsPost_(0),
+  prohibited_(NULL),
+  numberRowType_(0),
+  options_(0),
+  rowType_(NULL)
+{
+  handler_ = new CoinMessageHandler();
+  handler_->setLogLevel(2);
+  messages_ = CglMessage();
+}
+
+// Copy constructor.
+
+CglPreProcess::CglPreProcess(const CglPreProcess & rhs)
+:
+  numberSolvers_(rhs.numberSolvers_),
+  defaultHandler_(rhs.defaultHandler_),
+  appData_(rhs.appData_),
+  originalColumn_(NULL),
+  originalRow_(NULL),
+  numberCutGenerators_(rhs.numberCutGenerators_),
+  numberProhibited_(rhs.numberProhibited_),
+  numberIterationsPre_(rhs.numberIterationsPre_),
+  numberIterationsPost_(rhs.numberIterationsPost_),
+  numberRowType_(rhs.numberRowType_),
+  options_(rhs.options_)
+{
+  if (defaultHandler_) {
+    handler_ = new CoinMessageHandler();
+    handler_->setLogLevel(rhs.handler_->logLevel());
+  } else {
+    handler_ = rhs.handler_;
+  }
+  messages_ = rhs.messages_;
+  if (numberCutGenerators_) {
+    generator_ = new CglCutGenerator * [numberCutGenerators_];
+    for (int i=0;i<numberCutGenerators_;i++) {
+      generator_[i]=rhs.generator_[i]->clone();
+    }
+  } else {
+    generator_=NULL;
+  }
+  if (rhs.originalModel_) {
+    originalModel_ = rhs.originalModel_;
+    // If no make equality then solvers are same
+    if (rhs.originalModel_!=rhs.startModel_) {
+      startModel_=rhs.startModel_->clone();
+    } else {
+      startModel_=originalModel_;
+    }
+  } else {
+    originalModel_=NULL;
+    startModel_=NULL;
+  }
+  if (numberSolvers_) {
+    model_ = new OsiSolverInterface * [numberSolvers_];
+    modifiedModel_ = new OsiSolverInterface * [numberSolvers_];
+    presolve_ = new OsiPresolve * [numberSolvers_];
+    for (int i=0;i<numberSolvers_;i++) {
+      model_[i]=rhs.model_[i]->clone();
+      modifiedModel_[i]=rhs.modifiedModel_[i]->clone();
+      presolve_[i]=new OsiPresolve(*rhs.presolve_[i]);
+    }
+  } else {
+    model_=NULL;
+    presolve_=NULL;
+  }
+  numberSOS_=rhs.numberSOS_;
+  if (numberSOS_) {
+    int numberTotal = rhs.startSOS_[numberSOS_];
+    typeSOS_= CoinCopyOfArray(rhs.typeSOS_,numberSOS_);
+    startSOS_= CoinCopyOfArray(rhs.startSOS_,numberSOS_+1);
+    whichSOS_= CoinCopyOfArray(rhs.whichSOS_,numberTotal);
+    weightSOS_= CoinCopyOfArray(rhs.weightSOS_,numberTotal);
+  } else {
+    typeSOS_ = NULL;
+    startSOS_ = NULL;
+    whichSOS_ = NULL;
+    weightSOS_ = NULL;
+  }
+  prohibited_ = CoinCopyOfArray(rhs.prohibited_,numberProhibited_);
+  rowType_ = CoinCopyOfArray(rhs.rowType_,numberRowType_);
+  cuts_ = rhs.cuts_;
+}
+  
+// Assignment operator 
+CglPreProcess & 
+CglPreProcess::operator=(const CglPreProcess& rhs)
+{
+  if (this!=&rhs) {
+    gutsOfDestructor();
+    numberSolvers_=rhs.numberSolvers_;
+    defaultHandler_=rhs.defaultHandler_;
+    appData_=rhs.appData_;
+    numberCutGenerators_=rhs.numberCutGenerators_;
+    numberProhibited_ = rhs.numberProhibited_;
+    numberIterationsPre_ = rhs.numberIterationsPre_;
+    numberIterationsPost_ = rhs.numberIterationsPost_;
+    numberRowType_ = rhs.numberRowType_;
+    options_ = rhs.options_;
+    if (defaultHandler_) {
+      handler_ = new CoinMessageHandler();
+      handler_->setLogLevel(rhs.handler_->logLevel());
+    } else {
+      handler_ = rhs.handler_;
+    }
+    messages_ = rhs.messages_;
+    if (numberCutGenerators_) {
+      generator_ = new CglCutGenerator * [numberCutGenerators_];
+      for (int i=0;i<numberCutGenerators_;i++) {
+        generator_[i]=rhs.generator_[i]->clone();
+      }
+    }
+    if (rhs.originalModel_) {
+      originalModel_ = rhs.originalModel_;
+      // If no make equality then solvers are same
+      if (rhs.originalModel_!=rhs.startModel_) {
+        startModel_=rhs.startModel_->clone();
+      } else {
+        startModel_=originalModel_;
+      }
+    } else {
+      originalModel_=NULL;
+      startModel_=NULL;
+    }
+    if (numberSolvers_) {
+      model_ = new OsiSolverInterface * [numberSolvers_];
+      modifiedModel_ = new OsiSolverInterface * [numberSolvers_];
+      presolve_ = new OsiPresolve * [numberSolvers_];
+      for (int i=0;i<numberSolvers_;i++) {
+        model_[i]=rhs.model_[i]->clone();
+        modifiedModel_[i]=rhs.modifiedModel_[i]->clone();
+        presolve_[i]=new OsiPresolve(*rhs.presolve_[i]);
+      }
+    } else {
+      model_=NULL;
+      presolve_=NULL;
+    }
+    numberSOS_=rhs.numberSOS_;
+    if (numberSOS_) {
+      int numberTotal = rhs.startSOS_[numberSOS_];
+      typeSOS_= CoinCopyOfArray(rhs.typeSOS_,numberSOS_);
+      startSOS_= CoinCopyOfArray(rhs.startSOS_,numberSOS_+1);
+      whichSOS_= CoinCopyOfArray(rhs.whichSOS_,numberTotal);
+      weightSOS_= CoinCopyOfArray(rhs.weightSOS_,numberTotal);
+    } else {
+      typeSOS_ = NULL;
+      startSOS_ = NULL;
+      whichSOS_ = NULL;
+      weightSOS_ = NULL;
+    }
+    prohibited_ = CoinCopyOfArray(rhs.prohibited_,numberProhibited_);
+    rowType_ = CoinCopyOfArray(rhs.rowType_,numberRowType_);
+    cuts_ = rhs.cuts_;
+  }
+  return *this;
+}
+  
+// Destructor 
+CglPreProcess::~CglPreProcess ()
+{
+  gutsOfDestructor();
+}
+// Clears out as much as possible (except solver)
+void 
+CglPreProcess::gutsOfDestructor()
+{
+  if (defaultHandler_) {
+    delete handler_;
+    handler_ = NULL;
+  }
+  if (startModel_!=originalModel_) 
+    delete startModel_;
+  startModel_=NULL;
+  //delete originalModel_;
+  originalModel_=NULL;
+  int i;
+  for (i=0;i<numberCutGenerators_;i++) {
+    delete generator_[i];
+  }
+  delete [] generator_;
+  generator_=NULL;
+  for (i=0;i<numberSolvers_;i++) {
+    delete model_[i];
+    delete modifiedModel_[i];
+    delete presolve_[i];
+  }
+  delete [] model_;
+  delete [] modifiedModel_;
+  delete [] presolve_;
+  model_=NULL;
+  presolve_=NULL;
+  delete [] originalColumn_;
+  delete [] originalRow_;
+  originalColumn_=NULL;
+  originalRow_=NULL;
+  delete [] typeSOS_;
+  delete [] startSOS_;
+  delete [] whichSOS_;
+  delete [] weightSOS_;
+  typeSOS_ = NULL;
+  startSOS_ = NULL;
+  whichSOS_ = NULL;
+  weightSOS_ = NULL;
+  delete [] prohibited_;
+  prohibited_=NULL;
+  numberProhibited_=0;
+  numberIterationsPre_=0;
+  numberIterationsPost_=0;
+  delete [] rowType_;
+  rowType_=NULL;
+  numberRowType_=0;
+}
+// Add one generator
+void 
+CglPreProcess::addCutGenerator(CglCutGenerator * generator)
+{
+  CglCutGenerator ** temp = generator_;
+  generator_ = new CglCutGenerator * [numberCutGenerators_+1];
+  memcpy(generator_,temp,numberCutGenerators_*sizeof(CglCutGenerator *));
+  delete[] temp ;
+  generator_[numberCutGenerators_++]=generator->clone(); 
+}
+//#############################################################################
+// Set/Get Application Data
+// This is a pointer that the application can store into and retrieve
+// This field is the application to optionally define and use.
+//#############################################################################
+
+void CglPreProcess::setApplicationData(void * appData)
+{
+  appData_ = appData;
+}
+//-----------------------------------------------------------------------------
+void * CglPreProcess::getApplicationData() const
+{
+  return appData_;
+}
+/* Set cutoff bound on the objective function.
+   
+When using strict comparison, the bound is adjusted by a tolerance to
+avoid accidentally cutting off the optimal solution.
+*/
+void 
+CglPreProcess::setCutoff(double value) 
+{
+  // Solvers know about direction
+  double direction = originalModel_->getObjSense();
+  originalModel_->setDblParam(OsiDualObjectiveLimit,value*direction); 
+}
+
+// Get the cutoff bound on the objective function - always as minimize
+double 
+CglPreProcess::getCutoff() const
+{ 
+  double value ;
+  originalModel_->getDblParam(OsiDualObjectiveLimit,value) ;
+  return value * originalModel_->getObjSense() ;
+}
+// Pass in Message handler (not deleted at end)
+void 
+CglPreProcess::passInMessageHandler(CoinMessageHandler * handler)
+{
+  if (defaultHandler_)
+    delete handler_;
+  defaultHandler_=false;
+  handler_=handler;
+}
+// Set language
+void 
+CglPreProcess::newLanguage(CoinMessages::Language language)
+{
+  messages_ = CglMessage(language);
+}
+// Return a pointer to the original columns (without clique slacks)
+const int * 
+CglPreProcess::originalColumns()
+{
+  if (!originalColumn_) 
+    createOriginalIndices();
+  return originalColumn_;
+}
+// Return a pointer to the original rows
+const int * 
+CglPreProcess::originalRows()
+{
+  if (!originalRow_)
+    createOriginalIndices();
+  return originalRow_;
+}
+// create original columns and rows
+void 
+CglPreProcess::createOriginalIndices()
+{
+  // Find last model and presolve
+  int iPass;
+  for (iPass=numberSolvers_-1;iPass>=0;iPass--) {
+    if (presolve_[iPass])
+      break;
+  }
+  int nRows,nColumns;
+  if (iPass>=0) {
+    nRows=model_[iPass]->getNumRows();
+    nColumns=model_[iPass]->getNumCols();
+  } else {
+    nRows=originalModel_->getNumRows();
+    nColumns=originalModel_->getNumCols();
+  }
+  delete [] originalColumn_;
+  originalColumn_=new int [nColumns];
+  delete [] originalRow_;
+  originalRow_ = new int[nRows];
+  if (iPass>=0) {
+    memcpy(originalColumn_,presolve_[iPass]->originalColumns(),
+           nColumns*sizeof(int));
+    memcpy(originalRow_,presolve_[iPass]->originalRows(),
+           nRows*sizeof(int));
+    iPass--;
+    for (;iPass>=0;iPass--) {
+      const int * originalColumns = presolve_[iPass]->originalColumns();
+      int i;
+      for (i=0;i<nColumns;i++)
+        originalColumn_[i]=originalColumns[originalColumn_[i]];
+      const int * originalRows = presolve_[iPass]->originalRows();
+      int nRowsNow=model_[iPass]->getNumRows();
+      for (i=0;i<nRows;i++) {
+	int iRow=originalRow_[i];
+	if (iRow>=0&&iRow<nRowsNow)
+	  originalRow_[i]=originalRows[iRow];
+	else
+	  originalRow_[i]=-1;
+      }
+    }
+    std::sort(originalColumn_,originalColumn_+nColumns);
+  } else {
+    int i;
+    for (i=0;i<nColumns;i++)
+      originalColumn_[i]=i;
+    for (i=0;i<nRows;i++)
+      originalRow_[i]=i;
+  }
+}
+// Update prohibited and rowType
+void 
+CglPreProcess::update(const OsiPresolve * pinfo,
+		      const OsiSolverInterface * solver)
+{
+  if (prohibited_) {
+    const int * original = pinfo->originalColumns();
+    int numberColumns = solver->getNumCols();
+    // number prohibited must stay constant
+    int n=0;
+    int i;
+    for (i=0;i<numberProhibited_;i++) {
+      if(prohibited_[i])
+	n++;
+    }
+    int n2=0;
+    for (i=0;i<numberColumns;i++) {
+      int iColumn = original[i];
+      assert (i == 0 || iColumn>original[i-1]);
+      char p = prohibited_[iColumn];
+      if (p)
+	n2++;
+      prohibited_[i]=p;
+    }
+    assert (n==n2);
+    numberProhibited_=numberColumns;
+  }
+  if (rowType_) {
+    const int * original = pinfo->originalRows();
+    int numberRows = solver->getNumRows();
+#ifdef COIN_DEVELOP
+    int nMarked1=0;
+    for (int i=0;i<pinfo->getNumRows();i++) {
+      if (rowType_[i])
+	nMarked1++;
+    }
+    int nMarked2=0;
+    int k=-1;
+    for (int i=0;i<numberRows;i++) {
+      int iRow = original[i];
+      if (iRow<i)
+	abort();
+      if (iRow<=k)
+	abort();
+      k=iRow;
+      if (rowType_[iRow])
+	nMarked2++;
+    }
+    if (nMarked1>nMarked2)
+      printf("Marked rows reduced from %d to %d\n",
+	     nMarked1,nMarked2);
+#endif
+    for (int i=0;i<numberRows;i++) {
+      int iRow = original[i];
+      rowType_[i]=rowType_[iRow];
+    }
+    numberRowType_=numberRows;
+  }
+}
+/* Fix some of problem - returning new problem.
+   Uses reduced costs.
+   Optional signed character array
+   1 always keep, -1 always discard, 0 use djs
+   
+*/
+OsiSolverInterface * 
+CglPreProcess::someFixed(OsiSolverInterface & model, 
+                                 double fractionToKeep,
+                                 bool fixContinuousAsWell,
+                                 char * keep) const
+{
+  model.resolve();
+  int numberColumns = model.getNumCols();
+  OsiSolverInterface * newModel = model.clone();
+  int i;
+  const double * lower = model.getColLower();
+  const double * upper = model.getColUpper();
+  const double * solution = model.getColSolution();
+  double * dj = CoinCopyOfArray(model.getReducedCost(),numberColumns);
+  int * sort = new int[numberColumns];
+  int number=0;
+  int numberThrow=0;
+  int numberContinuous=0;
+  for (i=0;i<numberColumns;i++) {
+    if (!model.isInteger(i)&&upper[i]>lower[i])
+      numberContinuous++;
+    if (model.isInteger(i)||fixContinuousAsWell) {
+      if (keep) {
+        if (keep[i]==1) {
+          continue; // always keep
+        } else if (keep[i]==-1) {
+          // always fix
+          dj[number]=-1.0e30;
+          numberThrow++;
+          sort[number++]=i;
+          continue;
+        }
+      }
+      double value = solution[i];
+      if (value<lower[i]+1.0e-8) {
+        dj[number]=-dj[i];
+        sort[number++]=i;
+      } else if (value>upper[number]-1.0e-8) {
+        dj[number]=-dj[i];
+        sort[number++]=i;
+      }
+    }
+  }
+  CoinSort_2(dj,dj+number,sort);
+  int numberToFix = static_cast<int> (numberColumns *(1.0-fractionToKeep));
+  if (!fixContinuousAsWell)
+    numberToFix = static_cast<int> ((numberColumns-numberContinuous) *(1.0-fractionToKeep));
+  numberToFix = CoinMax(numberToFix,numberThrow);
+  numberToFix = CoinMin(number,numberToFix);
+  printf("%d columns fixed\n",numberToFix);
+  for (i=0;i<numberToFix;i++) {
+    int iColumn = sort[i];
+    double value = solution[iColumn];
+    if (value<lower[iColumn]+1.0e-8) {
+      newModel->setColUpper(iColumn,lower[iColumn]);
+    } else if (value>upper[number]-1.0e-8) {
+      newModel->setColLower(iColumn,lower[iColumn]);
+    } else {
+      // must be a throw away on - go to lower
+      newModel->setColUpper(iColumn,lower[iColumn]);
+    }
+  }
+  return newModel;
+}
+// If we have a cutoff - fix variables
+int 
+CglPreProcess::reducedCostFix(OsiSolverInterface & model)
+{
+  double cutoff ;
+  model.getDblParam(OsiDualObjectiveLimit,cutoff) ;
+  double direction = model.getObjSense() ;
+  cutoff *= direction;
+  double gap = cutoff - model.getObjValue()*direction ;
+  double tolerance;
+  model.getDblParam(OsiDualTolerance,tolerance) ;
+  if (gap<=0.0||fabs(cutoff)>1.0e20)
+    return 0;
+  gap += 100.0*tolerance;
+  // not really but thats all we can get
+  double integerTolerance;
+  model.getDblParam(OsiPrimalTolerance,integerTolerance) ;
+  int numberColumns = model.getNumCols();
+
+  const double *lower = model.getColLower() ;
+  const double *upper = model.getColUpper() ;
+  const double *solution = model.getColSolution() ;
+  const double *reducedCost = model.getReducedCost() ;
+
+  int numberFixed = 0 ;
+  int iColumn;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (model.isInteger(iColumn)&&upper[iColumn]>lower[iColumn]) {
+      double djValue = direction*reducedCost[iColumn] ;
+      if (solution[iColumn] < lower[iColumn]+integerTolerance && djValue > gap) {
+	model.setColUpper(iColumn,lower[iColumn]) ;
+	numberFixed++ ; 
+      } else if (solution[iColumn] > upper[iColumn]-integerTolerance && -djValue > gap) {
+	model.setColLower(iColumn,upper[iColumn]) ;
+	numberFixed++ ;
+      }
+    }
+  }
+  return numberFixed;
+}
+// Pass in prohibited columns 
+void 
+CglPreProcess::passInProhibited(const char * prohibited,int numberColumns)
+{
+  delete [] prohibited_;
+  prohibited_ = CoinCopyOfArray(prohibited,numberColumns);
+  numberProhibited_ = numberColumns;
+}
+/* Pass in row types
+   0 normal
+   1 cut rows - will be dropped if remain in
+   At end of preprocess cut rows will be dropped
+   and put into cuts
+*/
+void 
+CglPreProcess::passInRowTypes(const char * rowTypes,int numberRows)
+{
+  delete [] rowType_;
+  rowType_ = CoinCopyOfArray(rowTypes,numberRows);
+  numberRowType_ = numberRows;
+  cuts_ = CglStored();
+}
+// Make continuous variables integer
+void 
+CglPreProcess::makeInteger()
+{
+  // First check if we need to
+  int numberInteger=0;
+  {
+    const double *lower = startModel_->getColLower() ;
+    const double *upper = startModel_->getColUpper() ;
+    int numberColumns = startModel_->getNumCols() ;
+    int iColumn;
+    int numberContinuous=0;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (upper[iColumn] > lower[iColumn]+1.0e-8) {
+	if(startModel_->isInteger(iColumn)) 
+	  numberInteger++;
+	else
+	  numberContinuous++;
+      }
+    }
+    if (!numberContinuous)
+      return;
+  }
+  OsiSolverInterface * solver = startModel_->clone();
+  const double *objective = solver->getObjCoefficients() ;
+  const double *lower = solver->getColLower() ;
+  const double *upper = solver->getColUpper() ;
+  int numberColumns = solver->getNumCols() ;
+  int numberRows = solver->getNumRows();
+  double direction = solver->getObjSense();
+  int iRow,iColumn;
+
+  // Row copy
+  CoinPackedMatrix matrixByRow(*solver->getMatrixByRow());
+  const double * elementByRow = matrixByRow.getElements();
+  const int * column = matrixByRow.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  const int * rowLength = matrixByRow.getVectorLengths();
+
+  // Column copy
+  CoinPackedMatrix  matrixByCol(*solver->getMatrixByCol());
+  const double * element = matrixByCol.getElements();
+  const int * row = matrixByCol.getIndices();
+  const CoinBigIndex * columnStart = matrixByCol.getVectorStarts();
+  const int * columnLength = matrixByCol.getVectorLengths();
+
+  const double * rowLower = solver->getRowLower();
+  const double * rowUpper = solver->getRowUpper();
+
+  char * ignore = new char [numberRows];
+  int * changed = new int[numberColumns];
+  int * which = new int[numberRows];
+  double * changeRhs = new double[numberRows];
+  memset(changeRhs,0,numberRows*sizeof(double));
+  memset(ignore,0,numberRows);
+  int numberChanged=0;
+  bool finished=false;
+  while (!finished) {
+    int saveNumberChanged = numberChanged;
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int numberContinuous=0;
+      double value1=0.0,value2=0.0;
+      bool allIntegerCoeff=true;
+      double sumFixed=0.0;
+      int jColumn1=-1,jColumn2=-1;
+      for (CoinBigIndex j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+        int jColumn = column[j];
+        double value = elementByRow[j];
+        if (upper[jColumn] > lower[jColumn]+1.0e-8) {
+          if (!solver->isInteger(jColumn)) {
+            if (numberContinuous==0) {
+              jColumn1=jColumn;
+              value1=value;
+            } else {
+              jColumn2=jColumn;
+              value2=value;
+            }
+            numberContinuous++;
+          } else {
+            if (fabs(value-floor(value+0.5))>1.0e-12)
+              allIntegerCoeff=false;
+          }
+        } else {
+          sumFixed += lower[jColumn]*value;
+        }
+      }
+      double low = rowLower[iRow];
+      if (low>-1.0e20) {
+        low -= sumFixed;
+        if (fabs(low-floor(low+0.5))>1.0e-12)
+          allIntegerCoeff=false;
+      }
+      double up = rowUpper[iRow];
+      if (up<1.0e20) {
+        up -= sumFixed;
+        if (fabs(up-floor(up+0.5))>1.0e-12)
+          allIntegerCoeff=false;
+      }
+      if (!allIntegerCoeff)
+        continue; // can't do
+      if (numberContinuous==1) {
+        // see if really integer
+        // This does not allow for complicated cases
+        if (low==up) {
+          if (fabs(value1)>1.0e-3) {
+            value1 = 1.0/value1;
+            if (fabs(value1-floor(value1+0.5))<1.0e-12) {
+              // integer
+              changed[numberChanged++]=jColumn1;
+              solver->setInteger(jColumn1);
+              if (upper[jColumn1]>1.0e20)
+                solver->setColUpper(jColumn1,1.0e20);
+              if (lower[jColumn1]<-1.0e20)
+                solver->setColLower(jColumn1,-1.0e20);
+            }
+          }
+        } else {
+          if (fabs(value1)>1.0e-3) {
+            value1 = 1.0/value1;
+            if (fabs(value1-floor(value1+0.5))<1.0e-12) {
+              // This constraint will not stop it being integer
+              ignore[iRow]=1;
+            }
+          }
+        }
+      } else if (numberContinuous==2) {
+        if (low==up) {
+          /* need general theory - for now just look at 2 cases -
+             1 - +- 1 one in column and just costs i.e. matching objective
+             2 - +- 1 two in column but feeds into G/L row which will try and minimize
+          */
+          if (fabs(value1)==1.0&&value1*value2==-1.0&&!lower[jColumn1]
+              &&!lower[jColumn2]) {
+            int n=0;
+            int i;
+            double objChange=direction*(objective[jColumn1]+objective[jColumn2]);
+            double bound = CoinMin(upper[jColumn1],upper[jColumn2]);
+            bound = CoinMin(bound,1.0e20);
+            for ( i=columnStart[jColumn1];i<columnStart[jColumn1]+columnLength[jColumn1];i++) {
+              int jRow = row[i];
+              double value = element[i];
+              if (jRow!=iRow) {
+                which[n++]=jRow;
+                changeRhs[jRow]=value;
+              }
+            }
+            for ( i=columnStart[jColumn1];i<columnStart[jColumn1]+columnLength[jColumn1];i++) {
+              int jRow = row[i];
+              double value = element[i];
+              if (jRow!=iRow) {
+                if (!changeRhs[jRow]) {
+                  which[n++]=jRow;
+                  changeRhs[jRow]=value;
+                } else {
+                  changeRhs[jRow]+=value;
+                }
+              }
+            }
+            if (objChange>=0.0) {
+              // see if all rows OK
+              bool good=true;
+              for (i=0;i<n;i++) {
+                int jRow = which[i];
+                double value = changeRhs[jRow];
+                if (value) {
+                  value *= bound;
+                  if (rowLength[jRow]==1) {
+                    if (value>0.0) {
+                      double rhs = rowLower[jRow];
+                      if (rhs>0.0) {
+                        double ratio =rhs/value;
+                        if (fabs(ratio-floor(ratio+0.5))>1.0e-12)
+                          good=false;
+                      }
+                    } else {
+                      double rhs = rowUpper[jRow];
+                      if (rhs<0.0) {
+                        double ratio =rhs/value;
+                        if (fabs(ratio-floor(ratio+0.5))>1.0e-12)
+                          good=false;
+                      }
+                    }
+                  } else if (rowLength[jRow]==2) {
+                    if (value>0.0) {
+                      if (rowLower[jRow]>-1.0e20)
+                        good=false;
+                    } else {
+                      if (rowUpper[jRow]<1.0e20)
+                        good=false;
+                    }
+                  } else {
+                    good=false;
+                  }
+                }
+              }
+              if (good) {
+                // both can be integer
+                changed[numberChanged++]=jColumn1;
+                solver->setInteger(jColumn1);
+                if (upper[jColumn1]>1.0e20)
+                  solver->setColUpper(jColumn1,1.0e20);
+                if (lower[jColumn1]<-1.0e20)
+                  solver->setColLower(jColumn1,-1.0e20);
+                changed[numberChanged++]=jColumn2;
+                solver->setInteger(jColumn2);
+                if (upper[jColumn2]>1.0e20)
+                  solver->setColUpper(jColumn2,1.0e20);
+                if (lower[jColumn2]<-1.0e20)
+                  solver->setColLower(jColumn2,-1.0e20);
+              }
+            }
+            // clear
+            for (i=0;i<n;i++) {
+              changeRhs[which[i]]=0.0;
+            }
+          }
+        }
+      }
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (upper[iColumn] > lower[iColumn]+1.0e-8&&!solver->isInteger(iColumn)) {
+        double value;
+        value = upper[iColumn];
+        if (value<1.0e20&&fabs(value-floor(value+0.5))>1.0e-12) 
+          continue;
+        value = lower[iColumn];
+        if (value>-1.0e20&&fabs(value-floor(value+0.5))>1.0e-12) 
+          continue;
+        bool integer=true;
+        for (CoinBigIndex j=columnStart[iColumn];j<columnStart[iColumn]+columnLength[iColumn];j++) {
+          int iRow = row[j];
+          if (!ignore[iRow]) {
+            integer=false;
+            break;
+          }
+        }
+        if (integer) {
+          // integer
+          changed[numberChanged++]=iColumn;
+          solver->setInteger(iColumn);
+          if (upper[iColumn]>1.0e20)
+            solver->setColUpper(iColumn,1.0e20);
+          if (lower[iColumn]<-1.0e20)
+            solver->setColLower(iColumn,-1.0e20);
+        }
+      }
+    }
+    finished = numberChanged==saveNumberChanged;
+  }
+  delete [] which;
+  delete [] changeRhs;
+  delete [] ignore;
+  //increment=0.0;
+  if (numberChanged) {
+    handler_->message(CGL_MADE_INTEGER,messages_)
+      <<numberChanged
+      <<CoinMessageEol;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (solver->isInteger(iColumn)&&objective[iColumn])
+	startModel_->setInteger(iColumn);
+    }
+  }
+  delete solver;
+  delete [] changed;
+}
+//#define BRON_TIMES
+#ifdef BRON_TIMES
+static int numberTimesX=0;
+#endif
+/* Replace cliques by more maximal cliques
+   Returns NULL if rows not reduced by greater than cliquesNeeded*rows
+   
+*/
+OsiSolverInterface * 
+CglPreProcess::cliqueIt(OsiSolverInterface & model,
+			double cliquesNeeded) const
+{
+  /*
+    Initial arrays
+    * Candidate nodes (columns)
+    First nIn already in
+    Next nCandidate are candidates
+    numberColumns-1 back to nNot are Nots
+    * Starts
+    * Other node
+    * Original row (paired with other node)
+    * CliqueIn expanded array with 1 in, 2 not, 3 out, 0 possible, -1 never
+    * Type (for original row)
+    */
+  const double *lower = model.getColLower() ;
+  const double *upper = model.getColUpper() ;
+  const double *rowLower = model.getRowLower() ;
+  const double *rowUpper = model.getRowUpper() ;
+  int numberRows = model.getNumRows() ;
+  //int numberColumns = model.getNumCols() ;
+  // Column copy of matrix
+  //const double * element = model.getMatrixByCol()->getElements();
+  //const int * row = model.getMatrixByCol()->getIndices();
+  //const CoinBigIndex * columnStart = model.getMatrixByCol()->getVectorStarts();
+  //const int * columnLength = model.getMatrixByCol()->getVectorLengths();
+  // Row copy
+  CoinPackedMatrix matrixByRow(*model.getMatrixByRow());
+  const double * elementByRow = matrixByRow.getElements();
+  const int * column = matrixByRow.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  const int * rowLength = matrixByRow.getVectorLengths();
+  char * type = new char [numberRows];
+  int numberElements=0;
+  int numberCliques=0;
+  for (int i=0;i<numberRows;i++) {
+    type[i]=-1;
+    if (rowUpper[i]!=1.0||
+	(rowLower[i]>0.0&&rowLower[i]!=1.0))
+      continue;
+    bool possible = true;
+    CoinBigIndex start = rowStart[i];
+    CoinBigIndex end = start + rowLength[i];
+    int n=0;
+    for (CoinBigIndex j=start;j<end;j++) {
+      int iColumn = column[j];
+      if (upper[iColumn]==1.0&&lower[iColumn]==0.0&&
+	  model.isInteger(iColumn)&&elementByRow[j]==1.0) {
+	n++;
+      } else {
+	possible=false;
+	break;
+      }
+    }
+    // temp fix to get working faster for client
+    if (rowLower[i]>0.0||n!=2)
+      possible=false;
+    if (possible) {
+      numberElements+=n;
+      numberCliques++;
+      if (rowLower[i]>0.0)
+	type[i]=1;
+      else
+	type[i]=0;
+    }
+  }
+  OsiSolverInterface * newSolver = NULL;
+  if (numberCliques>CoinMax(1,static_cast<int>(cliquesNeeded*numberRows))) {
+#ifdef BRON_TIMES
+    double time1 = CoinCpuTime();
+#endif
+    CglBK bk(model,type,numberElements);
+    bk.bronKerbosch();
+    newSolver = bk.newSolver(model);
+#ifdef BRON_TIMES
+    printf("Time %g - bron called %d times\n",CoinCpuTime()-time1,numberTimesX);
+#endif
+  }
+  delete [] type;
+  return newSolver;
+}
+// Default constructor
+CglBK::CglBK()
+{
+  candidates_=NULL;
+  mark_=NULL;
+  start_=NULL;
+  otherColumn_=NULL;
+  originalRow_=NULL;
+  dominated_=NULL;
+  cliqueMatrix_=NULL;
+  rowType_=NULL;
+  numberColumns_=0;
+  numberRows_=0;
+  numberPossible_=0;
+  numberCandidates_=0;
+  firstNot_=0;
+  numberIn_=0;
+  left_=0;
+  lastColumn_=0;
+} 
+  
+// Useful constructor
+CglBK::CglBK(const OsiSolverInterface & model, const char * rowType,
+	     int numberElements)
+{
+  const double *lower = model.getColLower() ;
+  const double *upper = model.getColUpper() ;
+  const double *rowLower = model.getRowLower() ;
+  const double *rowUpper = model.getRowUpper() ;
+  numberRows_ = model.getNumRows() ;
+  numberColumns_ = model.getNumCols() ;
+  // Column copy of matrix
+#ifndef NDEBUG
+  const double * element = model.getMatrixByCol()->getElements();
+#endif
+  const int * row = model.getMatrixByCol()->getIndices();
+  const CoinBigIndex * columnStart = model.getMatrixByCol()->getVectorStarts();
+  const int * columnLength = model.getMatrixByCol()->getVectorLengths();
+  start_ = new CoinBigIndex[numberColumns_+1];
+  otherColumn_ = new int [numberElements];
+  candidates_ = new int [2*numberColumns_];
+  CoinZeroN(candidates_,2*numberColumns_); // for valgrind
+  originalRow_ = new int [numberElements];
+  dominated_ = new int [numberRows_];
+  CoinZeroN(dominated_,numberRows_);
+  numberElements=0;
+  numberPossible_=0;
+  rowType_=rowType;
+  // Row copy
+  CoinPackedMatrix matrixByRow(*model.getMatrixByRow());
+  const double * elementByRow = matrixByRow.getElements();
+  const int * column = matrixByRow.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  const int * rowLength = matrixByRow.getVectorLengths();
+#if 1
+  // take out duplicate doubleton rows
+  double * sort = new double[numberRows_];
+  int * which = new int [numberRows_];
+  double * randomValues = new double [numberColumns_];
+  // Initialize random seed
+  CoinThreadRandom randomGenerator(987654321);
+  for (int i=0;i<numberColumns_;i++)
+    randomValues[i]=randomGenerator.randomDouble();
+  int nSort=0;
+  for (int i=0;i<numberRows_;i++) {
+    if (rowLength[i]==2&&rowUpper[i]==1.0) {
+      int first = rowStart[i];
+      int last = first+1;
+      if (column[first]>column[last]) {
+	first=last;
+	last=rowStart[i];
+      }
+      int iColumn1 = column[first];
+      int iColumn2 = column[last];
+      double value = elementByRow[first]*randomValues[iColumn1]+
+	elementByRow[last]*randomValues[iColumn2];
+      sort[nSort]=value;
+      which[nSort++]=i;
+    }
+  }
+  CoinSort_2(sort,sort+nSort,which);
+  double value=sort[0];
+  int nDominated=0;
+  for (int i=1;i<nSort;i++) {
+    if (sort[i]==value) {
+      int i1=which[i-1];
+      int i2=which[i];
+      if (rowLower[i1]==rowLower[i2]) {
+	int first1 = rowStart[i1];
+	int last1 = first1+1;
+	if (column[first1]>column[last1]) {
+	  first1=last1;
+	  last1=rowStart[i1];
+	}
+	int iColumn11 = column[first1];
+	int iColumn12 = column[last1];
+	int first2 = rowStart[i2];
+	int last2 = first2+1;
+	if (column[first2]>column[last2]) {
+	  first2=last2;
+	  last2=rowStart[i2];
+	}
+	int iColumn21 = column[first2];
+	int iColumn22 = column[last2];
+	if (iColumn11==iColumn21&&
+	    iColumn12==iColumn22&&
+	    elementByRow[first1]==elementByRow[first2]&&
+	    elementByRow[last1]==elementByRow[last2]) {
+	  dominated_[i2]=1;
+	  nDominated++;
+	}
+      }
+    }
+    value=sort[i];
+  }
+  //if (nDominated)
+  //printf("%d duplicate doubleton rows!\n",nDominated);
+  delete [] randomValues;
+  delete [] sort;
+  delete [] which;
+#endif
+  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+    start_[iColumn]=numberElements;
+    CoinBigIndex start = columnStart[iColumn];
+    CoinBigIndex end = start + columnLength[iColumn];
+    if (upper[iColumn]==1.0&&lower[iColumn]==0.0&&
+	model.isInteger(iColumn)) {
+      for (CoinBigIndex j=start;j<end;j++) {
+	int iRow = row[j];
+	if (rowType[iRow]>=0&&!dominated_[iRow]) {
+	  assert(element[j]==1.0);
+	  CoinBigIndex r=rowStart[iRow];
+	  assert (rowLength[iRow]==2);
+	  int kColumn = column[r];
+	  if (kColumn==iColumn)
+	    kColumn=column[r+1];
+	  originalRow_[numberElements]=iRow;
+	  otherColumn_[numberElements++]=kColumn;
+	}
+      }
+      if (numberElements>start_[iColumn]) {
+	candidates_[numberPossible_++]=iColumn;
+      }
+    }
+  }
+  start_[numberColumns_]=numberElements;
+  numberCandidates_=numberPossible_;
+  numberIn_=0;
+  firstNot_ = numberPossible_;
+  left_=numberPossible_;
+  lastColumn_=-1;
+  mark_ = new char [numberColumns_];
+  memset(mark_,0,numberColumns_);
+  cliqueMatrix_=new CoinPackedMatrix(false,0.5,0.0);
+  int n=0;
+  for (int i=0;i<numberRows_;i++) {
+    if (rowType[i]>=0)
+      n++;
+  }
+  cliqueMatrix_->reserve(CoinMin(100,n),5*numberPossible_);
+} 
+  
+// Copy constructor .
+CglBK::CglBK(const CglBK & rhs)
+{
+  // This only copies data in candidates_
+  // rest just points
+  candidates_ = CoinCopyOfArray(rhs.candidates_,2*rhs.numberPossible_);
+  mark_=rhs.mark_;
+  start_=rhs.start_;
+  otherColumn_=rhs.otherColumn_;
+  originalRow_=rhs.originalRow_;
+  dominated_=rhs.dominated_;
+  cliqueMatrix_=rhs.cliqueMatrix_;
+  rowType_=rhs.rowType_;
+  numberColumns_=rhs.numberColumns_;
+  numberRows_=rhs.numberRows_;
+  numberPossible_=rhs.numberPossible_;
+  numberCandidates_=rhs.numberCandidates_;
+  firstNot_=rhs.firstNot_;
+  numberIn_=rhs.numberIn_;
+  left_=rhs.left_;
+  lastColumn_=rhs.lastColumn_;
+} 
+
+// Assignment operator 
+CglBK & CglBK::operator=(const CglBK& rhs)
+{
+  if (this!=&rhs) {
+    delete [] candidates_;
+    // This only copies data in candidates_
+    // rest just points
+    candidates_ = CoinCopyOfArray(rhs.candidates_,2*numberPossible_);
+    mark_=rhs.mark_;
+    start_=rhs.start_;
+    otherColumn_=rhs.otherColumn_;
+    originalRow_=rhs.originalRow_;
+    dominated_=rhs.dominated_;
+    cliqueMatrix_=rhs.cliqueMatrix_;
+    rowType_=rhs.rowType_;
+    numberColumns_=rhs.numberColumns_;
+    numberRows_=rhs.numberRows_;
+    numberPossible_=rhs.numberPossible_;
+    numberCandidates_=rhs.numberCandidates_;
+    firstNot_=rhs.firstNot_;
+    numberIn_=rhs.numberIn_;
+    left_=rhs.left_;
+    lastColumn_=rhs.lastColumn_;
+  }
+  return *this;
+} 
+
+// Destructor 
+CglBK::~CglBK ()
+{
+  delete [] candidates_;
+  // only deletes if left_==-1
+  if (left_==-1) {
+    delete [] mark_;
+    delete [] start_;
+    delete [] otherColumn_;
+    delete [] originalRow_;
+    delete [] dominated_;
+    delete cliqueMatrix_;
+  }
+}
+// For Bron-Kerbosch
+void 
+CglBK::bronKerbosch()
+{
+#ifdef BRON_TIMES
+  numberTimesX++;
+  if ((numberTimesX%1000)==0)
+    printf("times %d - %d candidates left\n",numberTimesX,numberCandidates_);
+#endif
+  if (!numberCandidates_&&firstNot_==numberPossible_) {
+    // mark original rows which are dominated
+    // save if clique size >2
+    if (numberIn_>2) {
+      double * elements = new double [numberIn_];
+      int * column = candidates_+numberPossible_;
+      // mark those in clique
+      for (int i=0;i<numberIn_;i++) {
+	int iColumn=column[i];
+	mark_[iColumn]=1;
+      }
+      for (int i=0;i<numberIn_;i++) {
+	elements[i]=1.0;
+	int iColumn=column[i];
+	for (int j=start_[iColumn];j<start_[iColumn+1];j++) {
+	  int jColumn = otherColumn_[j];
+	  if (mark_[jColumn]) {
+	    int iRow=originalRow_[j];
+	    dominated_[iRow]++;
+	  }
+	}
+      }
+      for (int i=0;i<numberIn_;i++) {
+	int iColumn=column[i];
+	mark_[iColumn]=0;
+      }
+      cliqueMatrix_->appendRow(numberIn_,column,elements);
+      delete [] elements;
+    }
+  } else {
+#if 0
+    int nCplusN=numberCandidates_+(numberPossible_-firstNot_);
+    int iChoose = CoinDrand48()*nCplusN;
+    iChoose=CoinMin(0,nCplusN-1);
+    if (iChoose>=numberCandidates_) {
+      iChoose -= numberCandidates_;
+      iChoose += firstNot_;
+    }
+#else
+    for (int i=0;i<numberCandidates_;i++) {
+      int jColumn = candidates_[i];
+      mark_[jColumn]=1;
+    }
+    int nMax=0;
+    int iChoose=0;
+    for (int i=numberPossible_-1;i>=firstNot_;i--) {
+      int iColumn = candidates_[i];
+      int n=0;
+      for (int j=start_[iColumn];j<start_[iColumn+1];j++) {
+	int jColumn = otherColumn_[j];
+	n += mark_[jColumn];
+      }
+      if (n>nMax) {
+	nMax=n;
+	iChoose=i;
+      } 
+    }
+    if (nMax<numberCandidates_-1||!nMax) {
+      for (int i=0;i<numberCandidates_;i++) {
+	int iColumn = candidates_[i];
+	int n=0;
+	for (int j=start_[iColumn];j<start_[iColumn+1];j++) {
+	  int jColumn = otherColumn_[j];
+	  n += mark_[jColumn];
+	}
+	if (n>nMax) {
+	  nMax=n;
+	  iChoose=i;
+	}
+      }
+    }
+    for (int i=0;i<numberCandidates_;i++) {
+      int jColumn = candidates_[i];
+      mark_[jColumn]=0;
+    }
+#endif
+    iChoose = candidates_[iChoose];
+    int * temp = candidates_+numberPossible_+numberIn_;
+    int nTemp=0;
+    if (nMax<numberCandidates_) {
+      // Neighborhood of iColumn
+      for (int j=start_[iChoose];j<start_[iChoose+1];j++) {
+	int jColumn = otherColumn_[j];
+	mark_[jColumn]=1;
+      }
+      for (int i=0;i<numberCandidates_;i++) {
+	int jColumn = candidates_[i];
+	if (!mark_[jColumn])
+	  temp[nTemp++]=jColumn;
+      }
+      for (int j=start_[iChoose];j<start_[iChoose+1];j++) {
+	int jColumn = otherColumn_[j];
+	mark_[jColumn]=0;
+      }
+    }
+    //if (nMax==numberCandidates_)
+    //assert (!nTemp);
+    for (int kk=0;kk<nTemp;kk++) {
+      int iColumn=temp[kk];
+      // move up
+      int put=0;
+      for (int i=0;i<numberCandidates_;i++) {
+	if (candidates_[i]!=iColumn)  
+	  candidates_[put++]=candidates_[i];
+      }
+      numberCandidates_--;
+      CglBK bk2(*this);
+      int * newCandidates=bk2.candidates_;
+#if 0
+      printf("%p (next %p) iColumn %d, %d candidates %d not %d in\n",
+	     this,&bk2,iColumn,numberCandidates_,
+	     numberPossible_-firstNot_,numberIn_);
+      for (int i=0;i<numberCandidates_;i++) {
+	printf(" %d",candidates_[i]);
+      }
+      printf("\n");
+#endif
+      newCandidates[numberPossible_+numberIn_]=iColumn;
+      bk2.numberIn_=numberIn_+1;
+      // Neighborhood of iColumn
+      for (int j=start_[iColumn];j<start_[iColumn+1];j++) {
+	int jColumn = otherColumn_[j];
+	mark_[jColumn]=1;
+      }
+      // Intersection of candidates with neighborhood
+      int numberCandidates=0;
+      for (int i=0;i<bk2.numberCandidates_;i++) {
+	int jColumn = newCandidates[i];
+	if (mark_[jColumn])
+	  newCandidates[numberCandidates++]=jColumn;
+      }
+      bk2.numberCandidates_=numberCandidates;
+      // Intersection of not with neighborhood
+      int firstNot=numberPossible_;
+      for (int i=numberPossible_-1;i>=bk2.firstNot_;i--) {
+	int jColumn = newCandidates[i];
+	if (mark_[jColumn])
+	  newCandidates[--firstNot]=jColumn;
+      }
+      bk2.firstNot_=firstNot;
+      for (int j=start_[iColumn];j<start_[iColumn+1];j++) {
+	int jColumn = otherColumn_[j];
+	mark_[jColumn]=0;
+      }
+      //for (int i=0;i<numberColumns_;i++)
+      //assert (!mark_[i]);
+      bk2.bronKerbosch();
+      candidates_[--firstNot_]=iColumn;
+    }
+  }
+}
+// Creates strengthened smaller model
+OsiSolverInterface * 
+CglBK::newSolver(const OsiSolverInterface & model)
+{
+  // See how many rows can be deleted
+  int nDelete=0;
+  int * deleted = new int [numberRows_];
+  for (int i=0;i<numberRows_;i++) {
+    if (dominated_[i]) {
+      deleted[nDelete++]=i;
+    }
+  }
+  int nAdd=cliqueMatrix_->getNumRows();
+  printf ("%d rows can be deleted with %d new cliques\n",
+	  nDelete,nAdd);
+
+  OsiSolverInterface * newSolver = NULL;
+  if (nDelete>nAdd) {
+    newSolver = model.clone();
+    newSolver->deleteRows(nDelete,deleted);
+    double * lower = new double [nAdd];
+    double * upper = new double [nAdd];
+    for (int i=0;i<nAdd;i++) {
+      lower[i]=-COIN_DBL_MAX;
+      upper[i]=1.0;
+    }
+    const double * elementByRow = cliqueMatrix_->getElements();
+    const int * column = cliqueMatrix_->getIndices();
+    const CoinBigIndex * rowStart = cliqueMatrix_->getVectorStarts();
+    //const int * rowLength = cliqueMatrix_->getVectorLengths();
+    assert (cliqueMatrix_->getNumElements()==rowStart[nAdd]);
+    newSolver->addRows(nAdd,rowStart,column,elementByRow,lower,upper);
+    delete [] lower;
+    delete [] upper;
+  }
+  delete [] deleted;
+  // mark so everything will be deleted
+  left_=-1;
+  return newSolver;
+}
+static double multiplier[] = {1.23456789e2,-9.87654321};
+static int hashCut (const OsiRowCut & x, int size) 
+{
+  int xN =x.row().getNumElements();
+  double xLb = x.lb();
+  double xUb = x.ub();
+  const int * xIndices = x.row().getIndices();
+  const double * xElements = x.row().getElements();
+  unsigned int hashValue;
+  double value=1.0;
+  if (xLb>-1.0e10)
+    value += xLb*multiplier[0];
+  if (xUb<1.0e10)
+    value += xUb*multiplier[1];
+  for( int j=0;j<xN;j++) {
+    int xColumn = xIndices[j];
+    double xValue = xElements[j];
+    int k=(j&1);
+    value += (j+1)*multiplier[k]*(xColumn+1)*xValue;
+  }
+  // should be compile time but too lazy for now
+  if (sizeof(value)>sizeof(hashValue)) {
+    assert (sizeof(value)==2*sizeof(hashValue));
+    union { double d; int i[2]; } xx;
+    xx.d = value;
+    hashValue = (xx.i[0] + xx.i[1]);
+  } else {
+    assert (sizeof(value)==sizeof(hashValue));
+    union { double d; unsigned int i[2]; } xx;
+    xx.d = value;
+    hashValue = xx.i[0];
+  }
+  return hashValue%(size);
+}
+static bool same (const OsiRowCut & x, const OsiRowCut & y) 
+{
+  int xN =x.row().getNumElements();
+  int yN =y.row().getNumElements();
+  bool identical=false;
+  if (xN==yN) {
+    double xLb = x.lb();
+    double xUb = x.ub();
+    double yLb = y.lb();
+    double yUb = y.ub();
+    if (fabs(xLb-yLb)<1.0e-8&&fabs(xUb-yUb)<1.0e-8) {
+      const int * xIndices = x.row().getIndices();
+      const double * xElements = x.row().getElements();
+      const int * yIndices = y.row().getIndices();
+      const double * yElements = y.row().getElements();
+      int j;
+      for( j=0;j<xN;j++) {
+	if (xIndices[j]!=yIndices[j])
+	  break;
+	if (fabs(xElements[j]-yElements[j])>1.0e-12)
+	  break;
+      }
+      identical =  (j==xN);
+    }
+  }
+  return identical;
+}
+CglUniqueRowCuts::CglUniqueRowCuts(int initialMaxSize, int hashMultiplier)
+{
+  numberCuts_=0;
+  size_ = initialMaxSize;
+  hashMultiplier_ = hashMultiplier;
+  int hashSize=hashMultiplier_*size_;
+  if (size_) {
+    rowCut_ = new  OsiRowCut * [size_];
+    hash_ = new CglHashLink[hashSize];
+  } else {
+    rowCut_ = NULL;
+    hash_ = NULL;
+  }
+  for (int i=0;i<hashSize;i++) {
+    hash_[i].index=-1;
+    hash_[i].next=-1;
+  }
+  lastHash_=-1;
+}
+CglUniqueRowCuts::~CglUniqueRowCuts()
+{
+  for (int i=0;i<numberCuts_;i++)
+    delete rowCut_[i];
+  delete [] rowCut_;
+  delete [] hash_;
+}
+CglUniqueRowCuts::CglUniqueRowCuts(const CglUniqueRowCuts& rhs)
+{
+  numberCuts_=rhs.numberCuts_;
+  hashMultiplier_ = rhs.hashMultiplier_;
+  size_ = rhs.size_;
+  int hashSize= size_*hashMultiplier_;
+  lastHash_=rhs.lastHash_;
+  if (size_) {
+    rowCut_ = new  OsiRowCut * [size_];
+    hash_ = new CglHashLink[hashSize];
+    for (int i=0;i<hashSize;i++) {
+      hash_[i] = rhs.hash_[i];
+    }
+    for (int i=0;i<size_;i++) {
+      if (rhs.rowCut_[i])
+	rowCut_[i]=new OsiRowCut(*rhs.rowCut_[i]);
+      else
+	rowCut_[i]=NULL;
+    }
+  } else {
+    rowCut_ = NULL;
+    hash_ = NULL;
+  }
+}
+CglUniqueRowCuts& 
+CglUniqueRowCuts::operator=(const CglUniqueRowCuts& rhs)
+{
+  if (this != &rhs) {
+    for (int i=0;i<numberCuts_;i++)
+      delete rowCut_[i];
+    delete [] rowCut_;
+    delete [] hash_;
+    numberCuts_=rhs.numberCuts_;
+    hashMultiplier_ = rhs.hashMultiplier_;
+    size_ = rhs.size_;
+    lastHash_=rhs.lastHash_;
+    if (size_) {
+      rowCut_ = new  OsiRowCut * [size_];
+      int hashSize= size_*hashMultiplier_;
+      hash_ = new CglHashLink[hashSize];
+      for (int i=0;i<hashSize;i++) {
+	hash_[i] = rhs.hash_[i];
+      }
+      for (int i=0;i<size_;i++) {
+	if (rhs.rowCut_[i])
+	  rowCut_[i]=new OsiRowCut(*rhs.rowCut_[i]);
+	else
+	  rowCut_[i]=NULL;
+      }
+    } else {
+      rowCut_ = NULL;
+      hash_ = NULL;
+    }
+  }
+  return *this;
+}
+void 
+CglUniqueRowCuts::eraseRowCut(int sequence)
+{
+  // find
+  assert (sequence>=0&&sequence<numberCuts_);
+  OsiRowCut * cut = rowCut_[sequence];
+  int hashSize= size_*hashMultiplier_;
+  int ipos = hashCut(*cut,hashSize);
+  int found = -1;
+  while ( true ) {
+    int j1 = hash_[ipos].index;
+    if ( j1 >= 0 ) {
+      if (j1!=sequence) {
+	int k = hash_[ipos].next;
+	if ( k != -1 )
+	  ipos = k;
+	else
+	  break;
+      } else {
+	found = j1;
+	break;
+      }
+    } else {
+      break;
+    }
+  }
+  assert (found>=0);
+  assert (hash_[ipos].index==sequence);
+  // shuffle up
+  while (hash_[ipos].next>=0) {
+    int k = hash_[ipos].next;
+    hash_[ipos]=hash_[k];
+    ipos=k;
+  }
+  delete cut;
+  // move last to found
+  numberCuts_--;
+  if (numberCuts_) {
+    ipos = hashCut(*rowCut_[numberCuts_],hashSize);
+    while ( true ) {
+      int j1 = hash_[ipos].index;
+      if (j1!=numberCuts_) {
+	int k = hash_[ipos].next;
+	ipos = k;
+      } else {
+	// change
+	hash_[ipos].index=found;
+	rowCut_[found]=rowCut_[numberCuts_];
+	rowCut_[numberCuts_]=NULL;
+	break;
+      }
+    }
+  }
+  assert (!rowCut_[numberCuts_]);
+}
+// Return 0 if added, 1 if not
+int 
+CglUniqueRowCuts::insertIfNotDuplicate(const OsiRowCut & cut)
+{
+  int hashSize= size_*hashMultiplier_;
+  if (numberCuts_==size_) {
+    size_ = 2*size_+100;
+    hashSize=hashMultiplier_*size_;
+    OsiRowCut ** temp = new  OsiRowCut * [size_];
+    delete [] hash_;
+    hash_ = new CglHashLink[hashSize];
+    for (int i=0;i<hashSize;i++) {
+      hash_[i].index=-1;
+      hash_[i].next=-1;
+    }
+    for (int i=0;i<numberCuts_;i++) {
+      temp[i]=rowCut_[i];
+      int ipos = hashCut(*temp[i],hashSize);
+      int found = -1;
+      int jpos=ipos;
+      while ( true ) {
+	int j1 = hash_[ipos].index;
+	
+	if ( j1 >= 0 ) {
+	  if ( !same(*temp[i],*temp[j1]) ) {
+	    int k = hash_[ipos].next;
+	    if ( k != -1 )
+	      ipos = k;
+	    else
+	      break;
+	  } else {
+	    found = j1;
+	    break;
+	  }
+	} else {
+	  break;
+	}
+      }
+      if (found<0) {
+	assert (hash_[ipos].next==-1);
+	if (ipos==jpos) {
+	  // first
+	  hash_[ipos].index=i;
+	} else {
+	  // find next space 
+	  while ( true ) {
+	    ++lastHash_;
+	    assert (lastHash_<hashSize);
+	    if ( hash_[lastHash_].index == -1 ) 
+	      break;
+	  }
+	  hash_[ipos].next = lastHash_;
+	  hash_[lastHash_].index = i;
+	}
+      }
+    }
+    delete [] rowCut_;
+    rowCut_ = temp;
+  }
+  if (numberCuts_<size_) {
+    double newLb = cut.lb();
+    double newUb = cut.ub();
+    CoinPackedVector vector = cut.row();
+    int numberElements =vector.getNumElements();
+    int * newIndices = vector.getIndices();
+    double * newElements = vector.getElements();
+    CoinSort_2(newIndices,newIndices+numberElements,newElements);
+    int i;
+    bool bad=false;
+    for (i=0;i<numberElements;i++) {
+      double value = fabs(newElements[i]);
+      if (value<1.0e-12||value>1.0e12) 
+	bad=true;
+    }
+    if (bad)
+      return 1;
+    OsiRowCut newCut;
+    newCut.setLb(newLb);
+    newCut.setUb(newUb);
+    newCut.setRow(vector);
+    int ipos = hashCut(newCut,hashSize);
+    int found = -1;
+    int jpos=ipos;
+    while ( true ) {
+      int j1 = hash_[ipos].index;
+      
+      if ( j1 >= 0 ) {
+	if ( !same(newCut,*rowCut_[j1]) ) {
+	  int k = hash_[ipos].next;
+	  if ( k != -1 )
+	    ipos = k;
+	  else
+	    break;
+	} else {
+	  found = j1;
+	  break;
+	}
+      } else {
+	break;
+      }
+    }
+    if (found<0) {
+      assert (hash_[ipos].next==-1);
+      if (ipos==jpos) {
+	// first
+	hash_[ipos].index=numberCuts_;
+      } else {
+	// find next space 
+	while ( true ) {
+	  ++lastHash_;
+	  assert (lastHash_<hashSize);
+	  if ( hash_[lastHash_].index == -1 ) 
+	    break;
+	}
+	hash_[ipos].next = lastHash_;
+	hash_[lastHash_].index = numberCuts_;
+      }
+      OsiRowCut * newCutPtr = new OsiRowCut();
+      newCutPtr->setLb(newLb);
+      newCutPtr->setUb(newUb);
+      newCutPtr->setRow(vector);
+      rowCut_[numberCuts_++]=newCutPtr;
+      return 0;
+    } else {
+      return 1;
+    }
+  } else {
+    return -1;
+  }
+}
+// Add in cuts as normal cuts and delete
+void 
+CglUniqueRowCuts::addCuts(OsiCuts & cs)
+{
+  for (int i=0;i<numberCuts_;i++) {
+    cs.insert(*rowCut_[i]);
+    delete rowCut_[i] ;
+    rowCut_[i] = NULL ;
+  }
+  numberCuts_=0;
+}
diff --git a/cbits/coin/CglPreProcess.hpp b/cbits/coin/CglPreProcess.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglPreProcess.hpp
@@ -0,0 +1,490 @@
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglPreProcess_H
+#define CglPreProcess_H
+
+#include <string>
+#include <vector>
+
+#include "CoinMessageHandler.hpp"
+#include "OsiSolverInterface.hpp"
+#include "CglStored.hpp"
+#include "OsiPresolve.hpp"
+#include "CglCutGenerator.hpp"
+
+//#############################################################################
+
+/** Class for preProcessing and postProcessing.
+
+    While cuts can be added at any time in the tree, some cuts are actually just
+    stronger versions of existing constraints.  In this case they can replace those
+    constraints rather than being added as new constraints.  This is awkward in the
+    tree but reasonable at the root node.
+
+    This is a general process class which uses other cut generators to strengthen
+    constraints, establish that constraints are redundant, fix variables and
+    find relationships such as x + y == 1.
+
+    Presolve will also be done.
+
+    If row names existed they may be replaced by R0000000 etc
+
+*/
+
+class CglPreProcess  {
+  
+public:
+
+  ///@name Main methods 
+  //@{
+  /** preProcess problem - returning new problem.
+      If makeEquality true then <= cliques converted to ==.
+      Presolve will be done numberPasses times.
+
+      Returns NULL if infeasible
+
+      This version uses default strategy.  For more control copy and edit
+      code from this function i.e. call preProcessNonDefault
+  */
+  OsiSolverInterface * preProcess(OsiSolverInterface & model, 
+                                  bool makeEquality=false, int numberPasses=5);
+  /** preProcess problem - returning new problem.
+      If makeEquality true then <= cliques converted to ==.
+      Presolve will be done numberPasses times.
+
+      Returns NULL if infeasible
+
+      This version assumes user has added cut generators to CglPreProcess object
+      before calling it.  As an example use coding in preProcess
+      If makeEquality is 1 add slacks to get cliques,
+      if 2 add slacks to get sos (but only if looks plausible) and keep sos info
+  */
+  OsiSolverInterface * preProcessNonDefault(OsiSolverInterface & model, 
+                                  int makeEquality=0, int numberPasses=5,
+					    int tuning=0);
+  /// Creates solution in original model
+  void postProcess(OsiSolverInterface &model
+		   ,bool deleteStuff=true);
+  /** Tightens primal bounds to make dual and branch and cutfaster.  Unless
+      fixed or integral, bounds are slightly looser than they could be.
+      Returns non-zero if problem infeasible
+      Fudge for branch and bound - put bounds on columns of factor *
+      largest value (at continuous) - should improve stability
+      in branch and bound on infeasible branches (0.0 is off)
+  */
+  int tightenPrimalBounds(OsiSolverInterface & model,double factor=0.0);
+  /** Fix some of problem - returning new problem.
+      Uses reduced costs.
+      Optional signed character array
+      1 always keep, -1 always discard, 0 use djs
+
+  */
+  OsiSolverInterface * someFixed(OsiSolverInterface & model, 
+                                 double fractionToKeep=0.25,
+                                 bool fixContinuousAsWell=false,
+                                 char * keep=NULL) const;
+  /** Replace cliques by more maximal cliques
+      Returns NULL if rows not reduced by greater than cliquesNeeded*rows
+
+  */
+  OsiSolverInterface * cliqueIt(OsiSolverInterface & model,
+				double cliquesNeeded=0.0) const;
+  /// If we have a cutoff - fix variables
+  int reducedCostFix(OsiSolverInterface & model);
+  //@}
+
+  //---------------------------------------------------------------------------
+
+  /**@name Parameter set/get methods
+
+     The set methods return true if the parameter was set to the given value,
+     false if the value of the parameter is out of range.
+
+     The get methods return the value of the parameter.
+
+  */
+  //@{
+  /** Set cutoff bound on the objective function.
+
+    When using strict comparison, the bound is adjusted by a tolerance to
+    avoid accidentally cutting off the optimal solution.
+  */
+  void setCutoff(double value) ;
+
+  /// Get the cutoff bound on the objective function - always as minimize
+  double getCutoff() const;
+  /// The original solver associated with this model.
+  inline OsiSolverInterface * originalModel() const
+  { return originalModel_;}
+  /// Solver after making clique equalities (may == original)
+  inline OsiSolverInterface * startModel() const
+  { return startModel_;}
+  /// Copies of solver at various stages after presolve
+  inline OsiSolverInterface * modelAtPass(int iPass) const
+  { if (iPass>=0&&iPass<numberSolvers_) return model_[iPass]; else return NULL;}
+  /// Copies of solver at various stages after presolve after modifications
+  inline OsiSolverInterface * modifiedModel(int iPass) const
+  { if (iPass>=0&&iPass<numberSolvers_) return modifiedModel_[iPass]; else return NULL;}
+  /// Matching presolve information
+  inline OsiPresolve * presolve(int iPass) const
+  { if (iPass>=0&&iPass<numberSolvers_) return presolve_[iPass]; else return NULL;}
+  /** Return a pointer to the original columns (with possible  clique slacks)
+      MUST be called before postProcess otherwise you just get 0,1,2.. */
+  const int * originalColumns();
+  /** Return a pointer to the original rows
+      MUST be called before postProcess otherwise you just get 0,1,2.. */
+  const int * originalRows();
+  /// Number of SOS if found
+  inline int numberSOS() const
+  { return numberSOS_;}
+  /// Type of each SOS
+  inline const int * typeSOS() const
+  { return typeSOS_;}
+  /// Start of each SOS
+  inline const int * startSOS() const
+  { return startSOS_;}
+  /// Columns in SOS
+  inline const int * whichSOS() const
+  { return whichSOS_;}
+  /// Weights for each SOS column
+  inline const double * weightSOS() const
+  { return weightSOS_;}
+  /// Pass in prohibited columns 
+  void passInProhibited(const char * prohibited,int numberColumns);
+  /// Updated prohibited columns
+  inline const char * prohibited()
+  { return prohibited_;}
+  /// Number of iterations PreProcessing
+  inline int numberIterationsPre() const
+  { return numberIterationsPre_;}
+  /// Number of iterations PostProcessing
+  inline int numberIterationsPost() const
+  { return numberIterationsPost_;}
+  /** Pass in row types
+      0 normal
+      1 cut rows - will be dropped if remain in
+      At end of preprocess cut rows will be dropped
+      and put into cuts
+  */
+  void passInRowTypes(const char * rowTypes,int numberRows);
+  /** Updated row types - may be NULL
+      Carried around and corresponds to existing rows
+      -1 added by preprocess e.g. x+y=1
+      0 normal
+      1 cut rows - can be dropped if wanted
+  */
+  inline const char * rowTypes()
+  { return rowType_;}
+  /// Return cuts from dropped rows
+  inline const CglStored & cuts() const
+  { return cuts_;}
+  /// Return pointer to cuts from dropped rows
+  inline const CglStored * cutsPointer() const
+  { return &cuts_;}
+  /// Update prohibited and rowType
+  void update(const OsiPresolve * pinfo,const OsiSolverInterface * solver);
+  /// Set options
+  inline void setOptions(int value)
+  { options_=value;}
+  //@}
+
+  ///@name Cut generator methods 
+  //@{
+  /// Get the number of cut generators
+  inline int numberCutGenerators() const
+  { return numberCutGenerators_;}
+  /// Get the list of cut generators
+  inline CglCutGenerator ** cutGenerators() const
+  { return generator_;}
+  ///Get the specified cut generator
+  inline CglCutGenerator * cutGenerator(int i) const
+  { return generator_[i];}
+  /** Add one generator - up to user to delete generators.
+  */
+  void addCutGenerator(CglCutGenerator * generator);
+//@}
+    
+  /**@name Setting/Accessing application data */
+  //@{
+    /** Set application data.
+
+	This is a pointer that the application can store into and
+	retrieve.
+	This field is available for the application to optionally
+	define and use.
+    */
+    void setApplicationData (void * appData);
+
+    /// Get application data
+    void * getApplicationData() const;
+  //@}
+  
+  //---------------------------------------------------------------------------
+
+  /**@name Message handling */
+  //@{
+  /// Pass in Message handler (not deleted at end)
+  void passInMessageHandler(CoinMessageHandler * handler);
+  /// Set language
+  void newLanguage(CoinMessages::Language language);
+  inline void setLanguage(CoinMessages::Language language)
+  {newLanguage(language);}
+  /// Return handler
+  inline CoinMessageHandler * messageHandler() const
+  {return handler_;}
+  /// Return messages
+  inline CoinMessages messages() 
+  {return messages_;}
+  /// Return pointer to messages
+  inline CoinMessages * messagesPointer() 
+  {return &messages_;}
+  //@}
+  //---------------------------------------------------------------------------
+
+
+  ///@name Constructors and destructors etc
+  //@{
+  /// Constructor
+  CglPreProcess(); 
+  
+  /// Copy constructor .
+  CglPreProcess(const CglPreProcess & rhs);
+  
+  /// Assignment operator 
+  CglPreProcess & operator=(const CglPreProcess& rhs);
+
+  /// Destructor 
+  ~CglPreProcess ();
+  
+  /// Clears out as much as possible
+  void gutsOfDestructor();
+  //@}
+private:
+
+  ///@name private methods
+  //@{
+  /** Return model with useful modifications.  
+      If constraints true then adds any x+y=1 or x-y=0 constraints
+      If NULL infeasible
+  */
+  OsiSolverInterface * modified(OsiSolverInterface * model,
+                                bool constraints,
+                                int & numberChanges,
+                                int iBigPass,
+				int numberPasses);
+  /// create original columns and rows
+  void createOriginalIndices();
+  /// Make continuous variables integer
+  void makeInteger();
+  //@}
+
+//---------------------------------------------------------------------------
+
+private:
+  ///@name Private member data 
+  //@{
+
+  /// The original solver associated with this model.
+  OsiSolverInterface * originalModel_;
+  /// Solver after making clique equalities (may == original)
+  OsiSolverInterface * startModel_;
+  /// Number of solvers at various stages
+  int numberSolvers_;
+  /// Copies of solver at various stages after presolve
+  OsiSolverInterface ** model_;
+  /// Copies of solver at various stages after presolve after modifications
+  OsiSolverInterface ** modifiedModel_;
+  /// Matching presolve information
+  OsiPresolve ** presolve_;
+
+   /// Message handler
+  CoinMessageHandler * handler_;
+
+  /** Flag to say if handler_ is the default handler.
+  
+    The default handler is deleted when the model is deleted. Other
+    handlers (supplied by the client) will not be deleted.
+  */
+  bool defaultHandler_;
+
+  /// Cgl messages
+  CoinMessages messages_;
+
+  /// Pointer to user-defined data structure
+  void * appData_;
+  /// Original column numbers
+  int * originalColumn_;
+  /// Original row numbers
+  int * originalRow_;
+  /// Number of cut generators
+  int numberCutGenerators_;
+  /// Cut generators
+  CglCutGenerator ** generator_;
+  /// Number of SOS if found
+  int numberSOS_;
+  /// Type of each SOS
+  int * typeSOS_;
+  /// Start of each SOS
+  int * startSOS_;
+  /// Columns in SOS
+  int * whichSOS_;
+  /// Weights for each SOS column
+  double * weightSOS_;
+  /// Number of columns in original prohibition set
+  int numberProhibited_;
+  /// Number of iterations done in PreProcessing
+  int numberIterationsPre_;
+  /// Number of iterations done in PostProcessing
+  int numberIterationsPost_;
+  /// Columns which should not be presolved e.g. SOS
+  char * prohibited_;
+  /// Number of rows in original row types
+  int numberRowType_;
+  /** Options
+      1 - original model had integer bounds before tightening
+      2 - don't do probing
+      4 - don't do duplicate rows
+      8 - don't do cliques
+  */
+  int options_;
+  /** Row types (may be NULL) 
+      Carried around and corresponds to existing rows
+      -1 added by preprocess e.g. x+y=1
+      0 normal
+      1 cut rows - can be dropped if wanted
+  */
+  char * rowType_;
+  /// Cuts from dropped rows
+  CglStored cuts_;
+ //@}
+};
+/// For Bron-Kerbosch
+class CglBK  {
+  
+public:
+
+  ///@name Main methods 
+  //@{
+  /// For recursive Bron-Kerbosch
+  void bronKerbosch();
+  /// Creates strengthened smaller model
+  OsiSolverInterface * newSolver(const OsiSolverInterface & model);
+  //@}
+
+  //---------------------------------------------------------------------------
+
+  /**@name Parameter set/get methods
+
+     The set methods return true if the parameter was set to the given value,
+     false if the value of the parameter is out of range.
+
+     The get methods return the value of the parameter.
+
+  */
+  //@{
+  //@}
+
+  //---------------------------------------------------------------------------
+
+
+  ///@name Constructors and destructors etc
+  //@{
+  /// Default constructor
+  CglBK(); 
+  
+  /// Useful constructor
+  CglBK(const OsiSolverInterface & model, const char * rowType,
+	int numberElements);
+  
+  /// Copy constructor .
+  CglBK(const CglBK & rhs);
+  
+  /// Assignment operator 
+  CglBK & operator=(const CglBK& rhs);
+
+  /// Destructor 
+  ~CglBK ();
+  
+  //@}
+
+//---------------------------------------------------------------------------
+
+private:
+  ///@name Private member data 
+  //@{
+  /// Current candidates (created at each level)
+  int * candidates_;
+  /// Array to mark stuff 
+  char * mark_;
+  /// Starts for graph (numberPossible+1)
+  int * start_;
+  /// Other column/node
+  int * otherColumn_;
+  /// Original row (in parallel with otherColumn_)
+  int * originalRow_;
+  /// How many times each original row dominated
+  int * dominated_;
+  /// Clique entries
+  CoinPackedMatrix * cliqueMatrix_;
+  /// points to row types
+  const char * rowType_;
+  /// Number of original columns
+  int numberColumns_;
+  /// Number of original rows
+  int numberRows_;
+  /// Number possible
+  int numberPossible_;
+  /// Current number of candidates
+  int numberCandidates_;
+  /// First not (stored backwards from numberPossible_)
+  int firstNot_;
+  /// Current number in clique
+  int numberIn_;
+  /// For acceleration
+  int left_;
+  int lastColumn_;
+ //@}
+};
+/**
+   Only store unique row cuts
+*/
+// for hashing
+typedef struct {
+  int index, next;
+} CglHashLink;
+class OsiRowCut;
+class CglUniqueRowCuts {
+public:
+
+  CglUniqueRowCuts(int initialMaxSize=0, int hashMultiplier=4 );
+  ~CglUniqueRowCuts();
+  CglUniqueRowCuts(const CglUniqueRowCuts& rhs);
+  CglUniqueRowCuts& operator=(const CglUniqueRowCuts& rhs);
+  inline OsiRowCut * cut(int sequence) const
+  { return rowCut_[sequence];}
+  inline int numberCuts() const
+  { return numberCuts_;}
+  inline int sizeRowCuts() const
+  { return numberCuts_;}
+  inline OsiRowCut * rowCutPtr(int sequence)
+  { return rowCut_[sequence];}
+  void eraseRowCut(int sequence);
+  // insert cut
+  inline void insert(const OsiRowCut & cut)
+  { insertIfNotDuplicate(cut);}
+  // Return 0 if added, 1 if not
+  int insertIfNotDuplicate(const OsiRowCut & cut);
+  // Add in cuts as normal cuts (and delete)
+  void addCuts(OsiCuts & cs);
+private:
+  OsiRowCut ** rowCut_;
+  /// Hash table
+  CglHashLink *hash_;
+  int size_;
+  int hashMultiplier_;
+  int numberCuts_;
+  int lastHash_;
+};
+#endif
diff --git a/cbits/coin/CglProbing.cpp b/cbits/coin/CglProbing.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglProbing.cpp
@@ -0,0 +1,9874 @@
+// $Id: CglProbing.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+#define PROBING100 0
+//#define PRINT_DEBUG
+//#define CGL_DEBUG 1
+//#undef NDEBUG
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinFinite.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CglProbing.hpp"
+//#define PROBING_EXTRA_STUFF true
+#define PROBING_EXTRA_STUFF false
+#define FIXED_ALLOWANCE 10
+#define SIZE_ROW_MULT 4
+#define SIZE_ROW_ADD 2000
+typedef struct {double infeasibility;int sequence;} double_int_pair;
+class double_int_pair_compare {
+public:
+  bool operator() (double_int_pair x , double_int_pair y) const
+  {
+    return ( x.infeasibility < y.infeasibility);
+  }
+};
+// for hashing
+typedef struct {
+  int index, next;
+} CoinHashLink;
+static double multiplier[] = {1.23456789e2,-9.87654321};
+static int hashCut (const OsiRowCut2 & x, int size) 
+{
+  int xN =x.row().getNumElements();
+  double xLb = x.lb();
+  double xUb = x.ub();
+  const int * xIndices = x.row().getIndices();
+  const double * xElements = x.row().getElements();
+  unsigned int hashValue;
+  double value=1.0;
+  if (xLb>-1.0e10)
+    value += xLb*multiplier[0];
+  if (xUb<1.0e10)
+    value += xUb*multiplier[1];
+  for( int j=0;j<xN;j++) {
+    int xColumn = xIndices[j];
+    double xValue = xElements[j];
+    int k=(j&1);
+    value += (j+1)*multiplier[k]*(xColumn+1)*xValue;
+  }
+  // should be compile time but too lazy for now
+  if (sizeof(value)>sizeof(hashValue)) {
+    assert (sizeof(value)==2*sizeof(hashValue));
+    union { double d; int i[2]; } xx;
+    xx.d = value;
+    hashValue = (xx.i[0] + xx.i[1]);
+  } else {
+    assert (sizeof(value)==sizeof(hashValue));
+    union { double d; unsigned int i[2]; } xx;
+    xx.d = value;
+    hashValue = xx.i[0];
+  }
+  return hashValue%(size);
+}
+static bool same (const OsiRowCut2 & x, const OsiRowCut2 & y) 
+{
+  int xN =x.row().getNumElements();
+  int yN =y.row().getNumElements();
+  bool identical=false;
+  if (xN==yN) {
+    double xLb = x.lb();
+    double xUb = x.ub();
+    double yLb = y.lb();
+    double yUb = y.ub();
+    if (fabs(xLb-yLb)<1.0e-8&&fabs(xUb-yUb)<1.0e-8) {
+      const int * xIndices = x.row().getIndices();
+      const double * xElements = x.row().getElements();
+      const int * yIndices = y.row().getIndices();
+      const double * yElements = y.row().getElements();
+      int j;
+      for( j=0;j<xN;j++) {
+	if (xIndices[j]!=yIndices[j])
+	  break;
+	if (fabs(xElements[j]-yElements[j])>1.0e-12)
+	  break;
+      }
+      identical =  (j==xN);
+    }
+  }
+  return identical;
+}
+class row_cut {
+public:
+
+  row_cut(int nRows, bool initialPass )
+  {
+    numberCuts_=0;
+    if (nRows<500) {
+      maxSize_ = SIZE_ROW_MULT*nRows + SIZE_ROW_ADD;
+    } else if (nRows<5000) {
+      maxSize_ = (SIZE_ROW_MULT*nRows + SIZE_ROW_ADD)>>1;
+    } else if (nRows<10000) {
+      maxSize_ = (SIZE_ROW_MULT*(nRows>>1) + SIZE_ROW_ADD)>>1;
+    } else {
+      maxSize_ = (SIZE_ROW_MULT*CoinMin(nRows,100000) + SIZE_ROW_ADD)>>2;
+    }
+    size_ = (maxSize_>>3)+10;
+    if (initialPass)
+      size_ = size_>>1;
+    if (size_<1000)
+      hashSize_=4*size_;
+    else
+      hashSize_=2*size_;
+    nRows_ = nRows;
+    rowCut_ = new  OsiRowCut2 * [size_];
+    hash_ = new CoinHashLink[hashSize_];
+    for (int i=0;i<hashSize_;i++) {
+      hash_[i].index=-1;
+      hash_[i].next=-1;
+    }
+    numberCuts_=0;
+    lastHash_=-1;
+  }
+  ~row_cut()
+  {
+    for (int i=0;i<numberCuts_;i++)
+      delete rowCut_[i];
+    delete [] rowCut_;
+    delete [] hash_;
+  }
+  OsiRowCut2 * cut(int i) const
+  { return rowCut_[i];}
+  int numberCuts() const
+  { return numberCuts_;}
+  inline bool outOfSpace() const
+  { return maxSize_==numberCuts_;}
+  OsiRowCut2 ** rowCut_;
+  /// Hash table
+  CoinHashLink *hash_;
+  int size_;
+  int maxSize_;
+  int hashSize_;
+  int nRows_;
+  int numberCuts_;
+  int lastHash_;
+  // Return 0 if added, 1 if not, -1 if not added because of space
+  int addCutIfNotDuplicate(OsiRowCut & cut,int whichRow=-1)
+  {
+    if (numberCuts_==size_&&numberCuts_<maxSize_) {
+      size_ = CoinMin(2*size_+100,maxSize_);
+      if (size_<1000)
+	hashSize_=4*size_;
+      else
+	hashSize_=2*size_;
+#ifdef COIN_DEVELOP
+      printf("increaing size from %d to %d (hash size %d, maxsize %d)\n",
+	     numberCuts_,size_,hashSize_,maxSize_);
+#endif
+      OsiRowCut2 ** temp = new  OsiRowCut2 * [size_];
+      delete [] hash_;
+      hash_ = new CoinHashLink[hashSize_];
+      for (int i=0;i<hashSize_;i++) {
+	hash_[i].index=-1;
+	hash_[i].next=-1;
+      }
+      for (int i=0;i<numberCuts_;i++) {
+	temp[i]=rowCut_[i];
+	int ipos = hashCut(*temp[i],hashSize_);
+	int found = -1;
+	int jpos=ipos;
+	while ( true ) {
+	  int j1 = hash_[ipos].index;
+	  
+	  if ( j1 >= 0 ) {
+	    if ( !same(*temp[i],*temp[j1]) ) {
+	      int k = hash_[ipos].next;
+	      if ( k != -1 )
+		ipos = k;
+	      else
+		break;
+	    } else {
+	      found = j1;
+	      break;
+	    }
+	  } else {
+	    break;
+	  }
+	}
+	if (found<0) {
+	  assert (hash_[ipos].next==-1);
+	  if (ipos==jpos) {
+	    // first
+	    hash_[ipos].index=i;
+	  } else {
+	    // find next space 
+	    while ( true ) {
+	      ++lastHash_;
+	      assert (lastHash_<hashSize_);
+	      if ( hash_[lastHash_].index == -1 ) 
+		break;
+	    }
+	    hash_[ipos].next = lastHash_;
+	    hash_[lastHash_].index = i;
+	  }
+	}
+      }
+      delete [] rowCut_;
+      rowCut_ = temp;
+    }
+    if (numberCuts_<size_) {
+      double newLb = cut.lb();
+      double newUb = cut.ub();
+      CoinPackedVector vector = cut.row();
+      int numberElements =vector.getNumElements();
+      int * newIndices = vector.getIndices();
+      double * newElements = vector.getElements();
+      CoinSort_2(newIndices,newIndices+numberElements,newElements);
+      int i;
+      bool bad=false;
+      for (i=0;i<numberElements;i++) {
+	double value = fabs(newElements[i]);
+	if (value<1.0e-12||value>1.0e12) 
+	  bad=true;
+      }
+      if (bad)
+	return 1;
+      OsiRowCut2 newCut(whichRow);
+      newCut.setLb(newLb);
+      newCut.setUb(newUb);
+      newCut.setRow(vector);
+      int ipos = hashCut(newCut,hashSize_);
+      int found = -1;
+      int jpos=ipos;
+      while ( true ) {
+	int j1 = hash_[ipos].index;
+
+	if ( j1 >= 0 ) {
+	  if ( !same(newCut,*rowCut_[j1]) ) {
+	    int k = hash_[ipos].next;
+	    if ( k != -1 )
+	      ipos = k;
+	    else
+	      break;
+	  } else {
+	    found = j1;
+	    break;
+	  }
+	} else {
+	  break;
+	}
+      }
+      if (found<0) {
+	assert (hash_[ipos].next==-1);
+	if (ipos==jpos) {
+	  // first
+	  hash_[ipos].index=numberCuts_;
+	} else {
+	  // find next space 
+	  while ( true ) {
+	    ++lastHash_;
+	    assert (lastHash_<hashSize_);
+	    if ( hash_[lastHash_].index == -1 ) 
+	      break;
+	  }
+	  hash_[ipos].next = lastHash_;
+	  hash_[lastHash_].index = numberCuts_;
+	}
+        OsiRowCut2 * newCutPtr = new OsiRowCut2(whichRow);
+        newCutPtr->setLb(newLb);
+        newCutPtr->setUb(newUb);
+        newCutPtr->setRow(vector);
+        rowCut_[numberCuts_++]=newCutPtr;
+        return 0;
+      } else {
+        return 1;
+      }
+    } else {
+      return -1;
+    }
+  }
+  void addCuts(OsiCuts & cs, OsiRowCut ** whichRow,int iPass)
+  {
+    int numberCuts=cs.sizeRowCuts();
+    int i ;
+    if (numberCuts_<nRows_) {
+      if ((iPass&1)==1) {
+	for (i=0;i<numberCuts_;i++) {
+	  cs.insert(*rowCut_[i]);
+	  if (whichRow) {
+	    int iRow= rowCut_[i]->whichRow();
+	    if (iRow>=0&&!whichRow[iRow])
+	      whichRow[iRow]=cs.rowCutPtr(numberCuts);;
+	  }
+	  numberCuts++;
+	}
+      } else {
+	for (i=numberCuts_-1;i>=0;i--) {
+	  cs.insert(*rowCut_[i]);
+	  if (whichRow) {
+	    int iRow= rowCut_[i]->whichRow();
+	    if (iRow>=0&&!whichRow[iRow])
+	      whichRow[iRow]=cs.rowCutPtr(numberCuts);;
+	  }
+	  numberCuts++;
+	}
+      }
+    } else {
+      // just best
+      double * effectiveness = new double[numberCuts_];
+      int iCut=0;
+      for (i=0;i<numberCuts_;i++) {
+        double value = -rowCut_[i]->effectiveness();
+	if (whichRow) {
+	  int iRow= rowCut_[i]->whichRow();
+	  if (iRow>=0)
+	    value -= 1.0e10;
+	}
+        effectiveness[iCut++]=value;
+      }
+      std::sort(effectiveness,effectiveness+numberCuts_);
+      double threshold = -1.0e20;
+      if (iCut>nRows_)
+        threshold = effectiveness[nRows_];
+      for ( i=0;i<numberCuts_;i++) {
+        if (rowCut_[i]->effectiveness()>threshold) {
+          cs.insert(*rowCut_[i]);
+          if (whichRow) {
+            int iRow= rowCut_[i]->whichRow();
+            if (iRow>=0&&!whichRow[iRow])
+              whichRow[iRow]=cs.rowCutPtr(numberCuts);;
+          }
+          numberCuts++;
+        }
+      }
+      delete[] effectiveness ;
+    }
+    for (i = 0 ; i < numberCuts_ ; i++)
+    { delete rowCut_[i] ;
+      rowCut_[i] = 0 ; }
+    numberCuts_=0;
+  }
+};
+// Adds in cut to list 
+#ifdef CGL_DEBUG
+// Checks bounds okay against debugger
+static void checkBounds(const OsiRowCutDebugger * debugger,OsiColCut & cut)
+{
+  if (debugger) {
+    // on optimal path
+    const double * optimal = debugger->optimalSolution();
+    int i;
+    int nIndex;
+    const double * values;
+    const int * index;
+    const CoinPackedVector & lbs = cut.lbs();
+    values = lbs.getElements();
+    nIndex = lbs.getNumElements();
+    index = lbs.getIndices();
+    for (i=0;i<nIndex;i++) {
+      double value=values[i];
+      int iColumn = index[i];
+      printf("%d optimal %g lower %g\n",iColumn,optimal[iColumn],value);
+      assert(value<=optimal[iColumn]+1.0e-5);
+    }
+    const CoinPackedVector & ubs = cut.ubs();
+    values = ubs.getElements();
+    nIndex = ubs.getNumElements();
+    index = ubs.getIndices();
+    for (i=0;i<nIndex;i++) {
+      double value=values[i];
+      int iColumn = index[i];
+      printf("%d optimal %g upper %g\n",iColumn,optimal[iColumn],value);
+      assert(value>=optimal[iColumn]-1.0e-5);
+    }
+  }
+}
+#endif
+#define CGL_REASONABLE_INTEGER_BOUND 1.23456789e10
+// This tightens column bounds (and can declare infeasibility)
+// It may also declare rows to be redundant
+int 
+CglProbing::tighten(double *colLower, double * colUpper,
+                    const int *column, const double *rowElements, 
+                    const CoinBigIndex *rowStart, 
+		    const CoinBigIndex * rowStartPos,const int * rowLength,
+                    double *rowLower, double *rowUpper, 
+                    int nRows,int nCols,char * intVar,int maxpass,
+                    double tolerance)
+{
+  int i, j, k, kre;
+  int krs;
+  int dolrows;
+  int iflagu, iflagl;
+  int ntotal=0,nchange=1,jpass=0;
+  double dmaxup, dmaxdown, dbound;
+  int ninfeas=0;
+  // For clique stuff
+  double * cliqueMin=NULL;
+  double * cliqueMax=NULL;
+  // And second best ones
+  double * cliqueMin2 = NULL;
+  double * cliqueMax2 = NULL;
+  if (cliqueRowStart_&&numberRows_&&cliqueRowStart_[numberRows_]) {
+    cliqueMin = new double[nCols];
+    cliqueMax = new double[nCols];
+    cliqueMin2 = new double[nCols];
+    cliqueMax2 = new double[nCols];
+  } else {
+    // do without cliques and using sorted version
+    assert (rowStartPos);
+    while(nchange) {
+      nchange = 0; 
+      if (jpass==maxpass) break;
+      jpass++;
+      dolrows = (jpass & 1) == 1;
+      
+      for (i = 0; i < nRows; ++i) {
+	if (rowLower[i]>-1.0e20||rowUpper[i]<1.0e20) {
+	  int iflagu = 0;
+	  int iflagl = 0;
+	  double dmaxup = 0.0;
+	  double dmaxdown = 0.0;
+	  int krs = rowStart[i];
+	  int krs2 = rowStartPos[i];
+	  int kre = rowStart[i]+rowLength[i];
+	  
+	  /* ------------------------------------------------------------*/
+	  /* Compute L(i) and U(i) */
+	  /* ------------------------------------------------------------*/
+	  for (k = krs; k < krs2; ++k) {
+	    double value=rowElements[k];
+	    int j = column[k];
+	    if (colUpper[j] < 1.0e12) 
+	      dmaxdown += colUpper[j] * value;
+	    else
+	      ++iflagl;
+	    if (colLower[j] > -1.0e12) 
+	      dmaxup += colLower[j] * value;
+	    else
+	      ++iflagu;
+	  }
+	  for (k = krs2; k < kre; ++k) {
+	    double value=rowElements[k];
+	    int j = column[k];
+	    if (colUpper[j] < 1.0e12) 
+	      dmaxup += colUpper[j] * value;
+	    else
+	      ++iflagu;
+	    if (colLower[j] > -1.0e12) 
+	      dmaxdown += colLower[j] * value;
+	    else
+	      ++iflagl;
+	  }
+	  if (iflagu)
+	    dmaxup=1.0e31;
+	  if (iflagl)
+	    dmaxdown=-1.0e31;
+	  if (dmaxup <= rowUpper[i] + tolerance && dmaxdown >= rowLower[i] - tolerance) {
+	    /*
+	     * The sum of the column maxs is at most the row ub, and
+	     * the sum of the column mins is at least the row lb;
+	     * this row says nothing at all.
+	     * I suspect that this corresponds to
+	     * an implied column singleton in the paper (viii, on p. 325),
+	     * where the singleton in question is the row slack.
+	     */
+	    ++nchange;
+	    rowLower[i]=-COIN_DBL_MAX;
+	    rowUpper[i]=COIN_DBL_MAX;
+	  } else {
+	    if (dmaxup < rowLower[i] -tolerance || dmaxdown > rowUpper[i]+tolerance) {
+	      ninfeas++;
+	      break;
+	    }
+	    /*        Finite U(i) */
+	    /* -------------------------------------------------------------*/
+	    /* below is deliberate mistake (previously was by chance) */
+	    /*        never do both */
+	    if (iflagu == 0 && rowLower[i] > 0.0 && iflagl == 0 && rowUpper[i] < 1e15) {
+	      if (dolrows) {
+		iflagu = 1;
+	      } else {
+		iflagl = 1;
+	      }
+	    }
+	    if (iflagu == 0 && rowLower[i] > -1e15) {
+	      for (k = krs; k < kre; ++k) {
+		double value=rowElements[k];
+		j = column[k];
+		if (value > 0.0) {
+		  if (colUpper[j] < 1.0e12) {
+		    dbound = colUpper[j] + (rowLower[i] - dmaxup) / value;
+		    if (dbound > colLower[j] + 1.0e-8) {
+		      /* we can tighten the lower bound */
+		      /* the paper mentions this as a possibility on p. 227 */
+		      colLower[j] = dbound;
+		      ++nchange;
+		      
+		      /* this may have fixed the variable */
+		      /* I believe that this roughly corresponds to a
+		       * forcing constraint in the paper (p. 226).
+		       * If there is a forcing constraint (with respect
+		       * to the original, untightened bounds), then in this 
+		       * loop we will go through all the columns and fix
+		       * each of them to their implied bound, rather than
+		       * determining that the row as a whole is forced
+		       * and just fixing them without doing computation for
+		       * each column (as in the paper).
+		       * By doing it this way, we can tighten bounds and
+		       * get forcing constraints for free.
+		       */
+		      if (colUpper[j] - colLower[j] <= tolerance) {
+			/* --------------------------------------------------*/
+			/*                check if infeasible !!!!! */
+			/* --------------------------------------------------*/
+			if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+			  ninfeas++;
+			}
+		      }
+		    }
+		  }
+		} else {
+		  if (colLower[j] > -1.0e12) {
+		    dbound = colLower[j] + (rowLower[i] - dmaxup) / value;
+		    if (dbound < colUpper[j] - 1.0e-8) {
+		      colUpper[j] = dbound;
+		      ++nchange;
+		      if (colUpper[j] - colLower[j] <= tolerance) {
+			/* --------------------------------------------------*/
+			/*                check if infeasible !!!!! */
+			/* --------------------------------------------------*/
+			if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+			  ninfeas++;
+			}
+		      }
+		    }
+		  }
+		}
+	      }
+	    }
+	    
+	    /* ----------------------------------------------------------------*/
+	    /*        Finite L(i) */
+	    /* ----------------------------------------------------------------*/
+	    if (iflagl == 0 && rowUpper[i] < 1e15) {
+	      for (k = krs; k < kre; ++k) {
+		double value=rowElements[k];
+		j = column[k];
+		if (value < 0.0) {
+		  if (colUpper[j] < 1.0e12) {
+		    dbound = colUpper[j] + (rowUpper[i] - dmaxdown) / value;
+		    if (dbound > colLower[j] + 1.0e-8) {
+		      colLower[j] = dbound;
+		      ++nchange;
+		      if (! (colUpper[j] - colLower[j] > tolerance)) {
+			/* --------------------------------------------------*/
+			/*                check if infeasible !!!!! */
+			/* --------------------------------------------------*/
+			if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+			  ninfeas++;
+			}
+		      }
+		    }
+		  } 
+		} else {
+		  if (colLower[j] > -1.0e12) {
+		    dbound = colLower[j] + (rowUpper[i] - dmaxdown) / value;
+		    if (dbound < colUpper[j] - 1.0e-8) {
+		      colUpper[j] = dbound;
+		      ++nchange;
+		      if (! (colUpper[j] - colLower[j] > tolerance)) {
+			/* --------------------------------------------------*/
+			/*                check if infeasible !!!!! */
+			/* --------------------------------------------------*/
+			if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+			  ninfeas++;
+			}
+		      }
+		    }
+		  }
+		}
+	      }
+	    }
+	  }
+	}
+      }
+      for (j = 0; j < nCols; ++j) {
+	if (intVar[j]) {
+	  if (colUpper[j]-colLower[j]>1.0e-8) {
+	    if (floor(colUpper[j]+1.0e-4)<colUpper[j]) 
+	      nchange++;
+	    // clean up anyway
+	    colUpper[j]=floor(colUpper[j]+1.0e-4);
+	    if (ceil(colLower[j]-1.0e-4)>colLower[j]) 
+	      nchange++;
+	    // clean up anyway
+	    colLower[j]=ceil(colLower[j]-1.0e-4);
+	    if (colUpper[j]<colLower[j]) {
+	      /*printf("infeasible\n");*/
+	      ninfeas++;
+	    }
+	  }
+	}
+      }
+      if (ninfeas) break;
+    }
+    return (ninfeas);
+  }
+  
+  while(nchange) {
+    int ilbred = 0; /* bounds reduced */
+    int iubred = 0; /* bounds reduced */
+    int nrwdrp = 0; /* redundant rows */
+    if (jpass==maxpass) break;
+    jpass++;
+    dolrows = (jpass & 1) == 1;
+    
+    for (i = 0; i < nRows; ++i) {
+      bool cliqueChanges=false;
+      if (rowLower[i]>-1.0e20||rowUpper[i]<1.0e20) {
+	iflagu = 0;
+	iflagl = 0;
+	dmaxup = 0.0;
+	dmaxdown = 0.0;
+	krs = rowStart[i];
+	kre = rowStart[i]+rowLength[i];
+
+	/* ------------------------------------------------------------*/
+	/* Compute L(i) and U(i) */
+	/* ------------------------------------------------------------*/
+        if (!cliqueMin||i>=numberRows_||cliqueRowStart_[i]==cliqueRowStart_[i+1]) {
+          // without cliques
+          for (k = krs; k < kre; ++k) {
+            double value=rowElements[k];
+            j = column[k];
+            if (value > 0.0) {
+              if (colUpper[j] < 1.0e12) 
+                dmaxup += colUpper[j] * value;
+	      else
+                ++iflagu;
+              if (colLower[j] > -1.0e12) 
+                dmaxdown += colLower[j] * value;
+	      else
+                ++iflagl;
+            } else if (value<0.0) {
+              if (colUpper[j] < 1.0e12) 
+                dmaxdown += colUpper[j] * value;
+	      else
+                ++iflagl;
+              if (colLower[j] > -1.0e12) 
+                dmaxup += colLower[j] * value;
+	      else
+                ++iflagu;
+            }
+          }
+	  if (iflagu)
+	    dmaxup=1.0e31;
+	  if (iflagl)
+	    dmaxdown=-1.0e31;
+        } else {
+          // with cliques
+          int nClique=0;
+          int bias = cliqueRowStart_[i]-krs;
+          double dmaxup2=0.0;
+          double dmaxdown2=0.0;
+          double sumZeroFixes=0.0;
+          for (k = krs; k < kre; ++k) {
+            double value=rowElements[k];
+            j = column[k];
+            int iClique = sequenceInCliqueEntry(cliqueRow_[k+bias]);
+            bool oneFixes = oneFixesInCliqueEntry(cliqueRow_[k+bias]);
+            if (iClique>=numberColumns_||colUpper[j]==colLower[j]) {
+              if (value > 0.0) {
+                if (colUpper[j] >= 1.0e12) {
+                  dmaxup = 1e31;
+                  ++iflagu;
+                } else {
+                  dmaxup += colUpper[j] * value;
+                }
+                if (colLower[j] <= -1.0e12) {
+                  dmaxdown = -1e31;
+                  ++iflagl;
+                } else {
+                  dmaxdown += colLower[j] * value;
+                }
+              } else if (value<0.0) {
+                if (colUpper[j] >= 1.0e12) {
+                  dmaxdown = -1e31;
+                  ++iflagl;
+                } else {
+                  dmaxdown += colUpper[j] * value;
+                }
+                if (colLower[j] <= -1.0e12) {
+                  dmaxup = 1e31;
+                  ++iflagu;
+                } else {
+                  dmaxup += colLower[j] * value;
+                }
+              }
+            } else {
+              // clique may help
+              if (iClique>=nClique) {
+                //zero out
+                for (int j=nClique;j<=iClique;j++) {
+                  cliqueMin[j]=0.0;
+                  cliqueMax[j]=0.0;
+                  cliqueMin2[j]=0.0;
+                  cliqueMax2[j]=0.0;
+                }
+                nClique=iClique+1;
+              }
+              //  Update best and second best
+              if (oneFixes) {
+                if (value > 0.0) {
+                  dmaxup2 += value;
+                  cliqueMax2[iClique] = cliqueMax[iClique];
+                  cliqueMax[iClique] = CoinMax(cliqueMax[iClique],value);
+                } else if (value<0.0) {
+                  dmaxdown2 +=  value;
+                  cliqueMin2[iClique] = cliqueMin[iClique];
+                  cliqueMin[iClique] = CoinMin(cliqueMin[iClique],value);
+                }
+              } else {
+                sumZeroFixes += value;
+                if (value > 0.0) {
+                  dmaxup2 += value;
+                  cliqueMin2[iClique] = cliqueMin[iClique];
+                  cliqueMin[iClique] = CoinMin(cliqueMin[iClique],-value);
+                } else if (value<0.0) {
+                  dmaxdown2 +=  value;
+                  cliqueMax2[iClique] = cliqueMax[iClique];
+                  cliqueMax[iClique] = CoinMax(cliqueMax[iClique],-value);
+                }
+              }
+            }
+          }
+          double dmaxup3 = dmaxup + sumZeroFixes;
+          double dmaxdown3 = dmaxdown + sumZeroFixes;
+          for (int iClique=0;iClique<nClique;iClique++) {
+            dmaxup3 += cliqueMax[iClique];
+            dmaxdown3 += cliqueMin[iClique];
+          }
+          dmaxup += dmaxup2;
+          dmaxdown += dmaxdown2;
+          assert (dmaxup3<=dmaxup+1.0e-8);
+          assert (dmaxdown3>=dmaxdown-1.0e-8);
+          if (dmaxup3<dmaxup-1.0e-8||dmaxdown3>dmaxdown+1.0e-8) {
+            cliqueChanges=true;
+            //printf("normal min/max %g , %g clique %g , %g\n",
+            //     dmaxdown,dmaxup,dmaxdown3,dmaxup3);
+            dmaxdown=dmaxdown3;
+            dmaxup=dmaxup3;
+          }
+        }
+	if (dmaxup <= rowUpper[i] + tolerance && dmaxdown >= rowLower[i] - tolerance) {
+	  /*
+	   * The sum of the column maxs is at most the row ub, and
+	   * the sum of the column mins is at least the row lb;
+	   * this row says nothing at all.
+	   * I suspect that this corresponds to
+	   * an implied column singleton in the paper (viii, on p. 325),
+	   * where the singleton in question is the row slack.
+	   */
+	  ++nrwdrp;
+	  rowLower[i]=-COIN_DBL_MAX;
+	  rowUpper[i]=COIN_DBL_MAX;
+	} else {
+	  if (dmaxup < rowLower[i] -tolerance || dmaxdown > rowUpper[i]+tolerance) {
+	    ninfeas++;
+            assert (!cliqueChanges);
+	    break;
+	  }
+	  /*        Finite U(i) */
+	  /* -------------------------------------------------------------*/
+	  /* below is deliberate mistake (previously was by chance) */
+	  /*        never do both */
+	  if (iflagu == 0 && rowLower[i] > 0.0 && iflagl == 0 && rowUpper[i] < 1e15) {
+            if (dolrows) {
+              iflagu = 1;
+            } else {
+              iflagl = 1;
+            }
+          }
+          if (!cliqueChanges) {
+            // without cliques
+            if (iflagu == 0 && rowLower[i] > -1e15) {
+              for (k = krs; k < kre; ++k) {
+                double value=rowElements[k];
+                j = column[k];
+                if (value > 0.0) {
+                  if (colUpper[j] < 1.0e12) {
+                    dbound = colUpper[j] + (rowLower[i] - dmaxup) / value;
+                    if (dbound > colLower[j] + 1.0e-8) {
+                      /* we can tighten the lower bound */
+                      /* the paper mentions this as a possibility on p. 227 */
+                      colLower[j] = dbound;
+                      ++ilbred;
+                      
+                      /* this may have fixed the variable */
+                      /* I believe that this roughly corresponds to a
+                       * forcing constraint in the paper (p. 226).
+                       * If there is a forcing constraint (with respect
+                       * to the original, untightened bounds), then in this 
+                       * loop we will go through all the columns and fix
+                       * each of them to their implied bound, rather than
+                       * determining that the row as a whole is forced
+                       * and just fixing them without doing computation for
+                       * each column (as in the paper).
+                       * By doing it this way, we can tighten bounds and
+                       * get forcing constraints for free.
+                       */
+                      if (colUpper[j] - colLower[j] <= tolerance) {
+                        /* --------------------------------------------------*/
+                        /*                check if infeasible !!!!! */
+                        /* --------------------------------------------------*/
+                        if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+                          ninfeas++;
+                        }
+                      }
+                    }
+                  }
+                } else {
+                  if (colLower[j] > -1.0e12) {
+                    dbound = colLower[j] + (rowLower[i] - dmaxup) / value;
+                    if (dbound < colUpper[j] - 1.0e-8) {
+                      colUpper[j] = dbound;
+                      ++iubred;
+                      if (colUpper[j] - colLower[j] <= tolerance) {
+                        /* --------------------------------------------------*/
+                        /*                check if infeasible !!!!! */
+                        /* --------------------------------------------------*/
+                        if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+                          ninfeas++;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+            
+            /* ----------------------------------------------------------------*/
+            /*        Finite L(i) */
+            /* ----------------------------------------------------------------*/
+            if (iflagl == 0 && rowUpper[i] < 1e15) {
+              for (k = krs; k < kre; ++k) {
+                double value=rowElements[k];
+                j = column[k];
+                if (value < 0.0) {
+                  if (colUpper[j] < 1.0e12) {
+                    dbound = colUpper[j] + (rowUpper[i] - dmaxdown) / value;
+                    if (dbound > colLower[j] + 1.0e-8) {
+                      colLower[j] = dbound;
+                      ++ilbred;
+                      if (! (colUpper[j] - colLower[j] > tolerance)) {
+                        /* --------------------------------------------------*/
+                        /*                check if infeasible !!!!! */
+                        /* --------------------------------------------------*/
+                        if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+                          ninfeas++;
+                        }
+                      }
+                    }
+                  } 
+                } else {
+                  if (colLower[j] > -1.0e12) {
+                    dbound = colLower[j] + (rowUpper[i] - dmaxdown) / value;
+                    if (dbound < colUpper[j] - 1.0e-8) {
+                      colUpper[j] = dbound;
+                      ++iubred;
+                      if (! (colUpper[j] - colLower[j] > tolerance)) {
+                        /* --------------------------------------------------*/
+                        /*                check if infeasible !!!!! */
+                        /* --------------------------------------------------*/
+                        if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+                          ninfeas++;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          } else {
+            // with cliques
+            int bias = cliqueRowStart_[i]-krs;
+            if (iflagu == 0 && rowLower[i] > -1e15) {
+              for (k = krs; k < kre; ++k) {
+                double value=rowElements[k];
+                j = column[k];
+                int iClique = sequenceInCliqueEntry(cliqueRow_[k+bias]);
+                //bool oneFixes = (cliqueRow_[k+bias].oneFixes!=0);
+                if (iClique>=numberColumns_) {
+                  if (value > 0.0) {
+                    if (colUpper[j] < 1.0e12) {
+                      dbound = colUpper[j] + (rowLower[i] - dmaxup) / value;
+                      if (dbound > colLower[j] + 1.0e-8) {
+                        /* we can tighten the lower bound */
+                        /* the paper mentions this as a possibility on p. 227 */
+                        colLower[j] = dbound;
+                        ++ilbred;
+                        
+                        /* this may have fixed the variable */
+                        /* I believe that this roughly corresponds to a
+                         * forcing constraint in the paper (p. 226).
+                         * If there is a forcing constraint (with respect
+                         * to the original, untightened bounds), then in this 
+                         * loop we will go through all the columns and fix
+                         * each of them to their implied bound, rather than
+                         * determining that the row as a whole is forced
+                         * and just fixing them without doing computation for
+                         * each column (as in the paper).
+                         * By doing it this way, we can tighten bounds and
+                         * get forcing constraints for free.
+                         */
+                        if (colUpper[j] - colLower[j] <= tolerance) {
+                          /* --------------------------------------------------*/
+                          /*                check if infeasible !!!!! */
+                          /* --------------------------------------------------*/
+                          if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+                            ninfeas++;
+                          }
+                        }
+#if 0
+                      } else if (intVar[j]==1 && rowUpper[i]>1.0e20) {
+                        // can we modify coefficient
+                        if (dmaxdown+value>rowLower[i]+1.0e-8) {
+                          assert (dmaxdown<rowLower[i]+1.0e-8);
+                          double change = dmaxdown+value - rowLower[i];
+                          double newValue = value - change;
+                          if (newValue<1.0e-12)
+                            newValue=0.0;
+                          printf("Could change value from %g to %g\n",
+                                 value,newValue);
+                          // dmaxup -= change; 
+                        }
+#endif
+                      }
+                    }
+                  } else {
+                    if (colLower[j] > -1.0e12) {
+                      dbound = colLower[j] + (rowLower[i] - dmaxup) / value;
+                      if (dbound < colUpper[j] - 1.0e-8) {
+                        colUpper[j] = dbound;
+                        ++iubred;
+                        if (colUpper[j] - colLower[j] <= tolerance) {
+                          /* --------------------------------------------------*/
+                          /*                check if infeasible !!!!! */
+                          /* --------------------------------------------------*/
+                          if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+                            ninfeas++;
+                          }
+                        }
+#if 0
+                      } else if (intVar[j]==1 && rowUpper[i]>1.0e20) {
+                        // can we modify coefficient
+                        if (dmaxdown-value>rowLower[i]+1.0e-8) {
+                          assert (dmaxdown<rowLower[i]+1.0e-8);
+                          double change = dmaxdown-value-rowLower[i];
+                          double newValue = value+change;
+                          double newLower = rowLower[i]+change;
+                          if (newValue<1.0e-12)
+                            newValue=0.0;
+                          printf("Could change value from %g to %g and lorow from %g to %g\n",
+                                 value,newValue,rowLower[i],newLower);
+                         // dmaxdown += change                          
+                        }
+#endif
+                      }
+                    }
+                  }
+                } else if (colUpper[j]>colLower[j]) {
+                  // in clique
+                  // adjustment
+                  double dmaxup2=dmaxup;
+                  assert (cliqueMax[iClique]>=0);
+                  assert (cliqueMax2[iClique]>=0);
+                  /* get max up if at other bound
+                     May not go down at all but will not go up */
+                  if (fabs(value)==fabs(cliqueMax[iClique]))
+                    dmaxup2 -= cliqueMax[iClique]-cliqueMax2[iClique];
+                  if (dmaxup2<rowLower[i]-1.0e-8) {
+                    /* --------------------------------------------------*/
+                    /*                check if infeasible !!!!! */
+                    /* --------------------------------------------------*/
+                    if ( dmaxup<rowLower[i]-1.0e-8) {
+                      ninfeas++;
+                    } else {
+                      if (value > 0.0) {
+                        colLower[j] = 1.0;
+                        ++ilbred;
+                      } else {
+                        colUpper[j] = 0.0;
+                        ++iubred;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+            
+            /* ----------------------------------------------------------------*/
+            /*        Finite L(i) */
+            /* ----------------------------------------------------------------*/
+            if (iflagl == 0 && rowUpper[i] < 1e15) {
+              for (k = krs; k < kre; ++k) {
+                double value=rowElements[k];
+                j = column[k];
+                int iClique = sequenceInCliqueEntry(cliqueRow_[k+bias]);
+                //bool oneFixes = (cliqueRow_[k+bias].oneFixes!=0);
+                if (iClique>=numberColumns_) {
+                  if (value < 0.0) {
+                    if (colUpper[j] < 1.0e12) {
+                      dbound = colUpper[j] + (rowUpper[i] - dmaxdown) / value;
+                      if (dbound > colLower[j] + 1.0e-8) {
+                        colLower[j] = dbound;
+                        ++ilbred;
+                        if (! (colUpper[j] - colLower[j] > tolerance)) {
+                          /* --------------------------------------------------*/
+                          /*                check if infeasible !!!!! */
+                          /* --------------------------------------------------*/
+                          if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+                            ninfeas++;
+                          }
+                        }
+#if 0
+                      } else if (intVar[j]==1 && rowLower[i]<-1.0e20) {
+                        // can we modify coefficient
+                        if (dmaxup+value<rowUpper[i]-1.0e-8) {
+                          assert (dmaxup>rowUpper[i]-1.0e-8);
+                          double change = dmaxup+value - rowUpper[i];
+                          double newValue = value - change;
+                          if (newValue<1.0e-12)
+                            newValue=0.0;
+                          printf("Could change value from %g to %g b\n",
+                                 value,newValue);
+                          // dmaxdown -= change; 
+                        }
+#endif
+                      }
+                    } 
+                  } else {
+                    if (colLower[j] > -1.0e12) {
+                      dbound = colLower[j] + (rowUpper[i] - dmaxdown) / value;
+                      if (dbound < colUpper[j] - 1.0e-8) {
+                        colUpper[j] = dbound;
+                        ++iubred;
+                        if (! (colUpper[j] - colLower[j] > tolerance)) {
+                          /* --------------------------------------------------*/
+                          /*                check if infeasible !!!!! */
+                          /* --------------------------------------------------*/
+                          if (colUpper[j] - colLower[j] < -100.0*tolerance) {
+                            ninfeas++;
+                          }
+                        }
+#if 0
+                      } else if (intVar[j]==1 && rowLower[i]<-1.0e20) {
+                        // can we modify coefficient
+                        if (dmaxup-value<rowUpper[i]-1.0e-8) {
+                          assert (dmaxup>rowUpper[i]-1.0e-8);
+                          double change = dmaxup-value-rowUpper[i];
+                          double newValue = value+change;
+                          double newUpper = rowUpper[i]+change;
+                          if (newValue<1.0e-12)
+                            newValue=0.0;
+                          printf("Could change value from %g to %g and uprow from %g to %g b\n",
+                                 value,newValue,rowLower[i],newUpper);
+                         // dmaxup += change                          
+                        }
+#endif
+                      }
+                    }
+                  }
+                } else if (colUpper[j]>colLower[j]) {
+                  // in clique
+                  // adjustment
+                  double dmaxdown2=dmaxdown;
+                  assert (cliqueMin[iClique]<=0);
+                  assert (cliqueMin2[iClique]<=0);
+                  /* get max down if this is at other bound
+                     May not go up at all but will not go down */
+                  if (fabs(value)==fabs(cliqueMin[iClique]))
+                    dmaxdown2 -= cliqueMin[iClique]-cliqueMin2[iClique];
+                  if (dmaxdown2>rowUpper[i]+1.0e-8) {
+                    /* --------------------------------------------------*/
+                    /*                check if infeasible !!!!! */
+                    /* --------------------------------------------------*/
+                    if ( dmaxdown>rowUpper[i]+1.0e-8) {
+                      ninfeas++;
+                    } else {
+                      if (value < 0.0) {
+                        colLower[j] = 1.0;
+                        ++ilbred;
+                      } else {
+                        colUpper[j] = 0.0;
+                        ++iubred;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    for (j = 0; j < nCols; ++j) {
+      if (intVar[j]) {
+	if (colUpper[j]-colLower[j]>1.0e-8) {
+	  if (floor(colUpper[j]+1.0e-4)<colUpper[j]) 
+	    nchange++;
+	  // clean up anyway
+	  colUpper[j]=floor(colUpper[j]+1.0e-4);
+	  if (ceil(colLower[j]-1.0e-4)>colLower[j]) 
+	    nchange++;
+	  // clean up anyway
+	  colLower[j]=ceil(colLower[j]-1.0e-4);
+	  if (colUpper[j]<colLower[j]) {
+	    /*printf("infeasible\n");*/
+	    ninfeas++;
+	  }
+	}
+      }
+    }
+    nchange=ilbred+iubred+nrwdrp;
+    ntotal += nchange;
+    if (ninfeas) break;
+  }
+  delete [] cliqueMin;
+  delete [] cliqueMax;
+  delete [] cliqueMin2;
+  delete [] cliqueMax2;
+  return (ninfeas);
+}
+// This just sets minima and maxima on rows
+void 
+CglProbing::tighten2(double *colLower, double * colUpper,
+		     const int *column, const double *rowElements, 
+		     const CoinBigIndex *rowStart, 
+		     const int * rowLength,
+		     double *rowLower, double *rowUpper, 
+		     double * minR, double * maxR, int * markR,
+		     int nRows)
+{
+  int i, j, k, kre;
+  int krs;
+  int iflagu, iflagl;
+  double dmaxup, dmaxdown;
+
+  for (i = 0; i < nRows; ++i) {
+    if (rowLower[i]>-1.0e20||rowUpper[i]<1.0e20) {
+      iflagu = 0;
+      iflagl = 0;
+      dmaxup = 0.0;
+      dmaxdown = 0.0;
+      krs = rowStart[i];
+      kre = rowStart[i]+rowLength[i];
+      
+      /* ------------------------------------------------------------*/
+      /* Compute L(i) and U(i) */
+      /* ------------------------------------------------------------*/
+      for (k = krs; k < kre; ++k) {
+	double value=rowElements[k];
+	j = column[k];
+	if (value > 0.0) {
+	  if (colUpper[j] < 1.0e12) 
+	    dmaxup += colUpper[j] * value;
+	  else
+	    ++iflagu;
+	  if (colLower[j] > -1.0e12) 
+	    dmaxdown += colLower[j] * value;
+	  else
+	    ++iflagl;
+	} else if (value<0.0) {
+	  if (colUpper[j] < 1.0e12) 
+	    dmaxdown += colUpper[j] * value;
+	  else
+	    ++iflagl;
+	  if (colLower[j] > -1.0e12) 
+	    dmaxup += colLower[j] * value;
+	  else
+	    ++iflagu;
+	}
+      }
+      if (iflagu)
+	maxR[i]=1.0e60;
+      else
+	maxR[i]=dmaxup;
+      if (iflagl) 
+	minR[i]=-1.0e60;
+      else
+	minR[i]=dmaxdown;
+#if 0
+      if (minR[i]<-1.0e10&&maxR[i]>1.0e10) {
+	markR[i]=-2;
+      } else {
+#endif
+	markR[i]=-1;
+#if 0
+      }
+#endif
+    } else {
+      minR[i]=-1.0e60;
+      maxR[i]=1.0e60;
+#if 0
+      markR[i]=-2;
+      abort();
+#else
+      markR[i]=-1;
+#endif
+    }
+  }
+}
+#ifdef CGL_DEBUG
+static int nPath=0;
+#endif
+//-------------------------------------------------------------------
+// Generate disaggregation cuts
+//------------------------------------------------------------------- 
+void CglProbing::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			      const CglTreeInfo info2)
+{
+
+#ifdef CGL_DEBUG
+  const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+  if (debugger&&debugger->onOptimalPath(si)) {
+    printf("On optimal path %d\n",nPath);
+    nPath++;
+    int nCols=si.getNumCols();
+    int i;
+    const double * solution = si.getColSolution();
+    const double * lower = si.getColLower();
+    const double * upper = si.getColUpper();
+    const double * optimal = debugger->optimalSolution();
+    const double * objective = si.getObjCoefficients();
+    double objval1=0.0,objval2=0.0;
+    for (i=0;i<nCols;i++) {
+#if CGL_DEBUG>1
+      printf("%d %g %g %g %g\n",i,lower[i],solution[i],upper[i],optimal[i]);
+#endif
+      objval1 += solution[i]*objective[i];
+      objval2 += optimal[i]*objective[i];
+      assert(optimal[i]>=lower[i]&&optimal[i]<=upper[i]);
+    }
+    printf("current obj %g, integer %g\n",objval1,objval2);
+  }
+#endif
+  int saveRowCuts=rowCuts_;
+  if (rowCuts_<0) {
+    if (info2.inTree)
+      rowCuts_=4;
+    else
+      rowCuts_=-rowCuts_;
+  }
+  int nRows=si.getNumRows(); 
+  double * rowLower = new double[nRows+1];
+  double * rowUpper = new double[nRows+1];
+
+  int nCols=si.getNumCols();
+  // Set size if not set
+  if (!rowCopy_) {
+    numberRows_=nRows;
+    numberColumns_=nCols;
+  }
+  double * colLower = new double[nCols];
+  double * colUpper = new double[nCols];
+
+  CglTreeInfo info = info2;
+  int ninfeas=gutsOfGenerateCuts(si,cs,rowLower,rowUpper,colLower,colUpper,&info);
+  if (ninfeas) {
+    // generate infeasible cut and return
+    OsiRowCut rc;
+    rc.setLb(COIN_DBL_MAX);
+    rc.setUb(0.0);   
+    cs.insert(rc);
+#ifdef CGL_DEBUG
+    const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+    if (debugger&&debugger->onOptimalPath(si))
+      assert(!debugger->invalidCut(rc)); 
+#endif
+  }
+  delete [] rowLower;
+  delete [] rowUpper;
+  delete [] colLower;
+  delete [] colUpper;
+  delete [] colLower_;
+  delete [] colUpper_;
+  colLower_	= NULL;
+  colUpper_	= NULL;
+  rowCuts_=saveRowCuts;
+}
+int CglProbing::generateCutsAndModify(const OsiSolverInterface & si, 
+				      OsiCuts & cs,
+				      CglTreeInfo * info) 
+{
+#ifdef CGL_DEBUG
+  const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+  if (debugger&&debugger->onOptimalPath(si)) {
+    printf("On optimal path %d\n",nPath);
+    nPath++;
+    int nCols=si.getNumCols();
+    int i;
+    const double * solution = si.getColSolution();
+    const double * lower = si.getColLower();
+    const double * upper = si.getColUpper();
+    const double * optimal = debugger->optimalSolution();
+    const double * objective = si.getObjCoefficients();
+    double objval1=0.0,objval2=0.0;
+    for (i=0;i<nCols;i++) {
+#if CGL_DEBUG>1
+      printf("%d %g %g %g %g\n",i,lower[i],solution[i],upper[i],optimal[i]);
+#endif
+      objval1 += solution[i]*objective[i];
+      objval2 += optimal[i]*objective[i];
+      assert(optimal[i]>=lower[i]-1.0e-5&&optimal[i]<=upper[i]+1.0e-5);
+    }
+    printf("current obj %g, integer %g\n",objval1,objval2);
+  }
+#endif
+  int saveRowCuts=rowCuts_;
+  if (rowCuts_<0) {
+    if (info->inTree)
+      rowCuts_=4;
+    else
+      rowCuts_=-rowCuts_;
+  }
+  int saveMode = mode_;
+  bool rowCliques=false;
+  if (!mode_) {
+    if (info->pass!=4||info->inTree) {
+      mode_=1;
+    } else {
+      saveMode=1; // make sure do just once
+      rowCliques=true;
+    }
+  }
+  int nRows=si.getNumRows(); 
+  double * rowLower = new double[nRows+1];
+  double * rowUpper = new double[nRows+1];
+
+  int nCols=si.getNumCols(); 
+  double * colLower = new double[nCols];
+  double * colUpper = new double[nCols];
+
+  int ninfeas=gutsOfGenerateCuts(si,cs,rowLower,rowUpper,colLower,colUpper,info);
+  if (ninfeas) {
+    // generate infeasible cut and return
+    OsiRowCut rc;
+    rc.setLb(COIN_DBL_MAX);
+    rc.setUb(0.0);   
+    cs.insert(rc);
+#ifdef CGL_DEBUG
+    const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+    if (debugger&&debugger->onOptimalPath(si))
+      assert(!debugger->invalidCut(rc)); 
+#endif
+  }
+  rowCuts_=saveRowCuts;
+  mode_=saveMode;
+  // move bounds so can be used by user
+  if (mode_==3) {
+    delete [] rowLower_;
+    delete [] rowUpper_;
+    rowLower_ = rowLower;
+    rowUpper_ = rowUpper;
+  } else {
+    delete [] rowLower;
+    delete [] rowUpper;
+  }
+  delete [] colLower_;
+  delete [] colUpper_;
+  colLower_	= colLower;
+  colUpper_	= colUpper;
+  // Setup information 
+  if (rowCliques&&numberRows_&&numberColumns_)
+    setupRowCliqueInformation(si);
+  return ninfeas;
+}
+bool analyze(const OsiSolverInterface * solverX, char * intVar,
+             double * lower, double * upper)
+{
+  OsiSolverInterface * solver = solverX->clone();
+  const double *objective = solver->getObjCoefficients() ;
+  int numberColumns = solver->getNumCols() ;
+  int numberRows = solver->getNumRows();
+  double direction = solver->getObjSense();
+  int iRow,iColumn;
+
+  // Row copy
+  CoinPackedMatrix matrixByRow(*solver->getMatrixByRow());
+  const double * elementByRow = matrixByRow.getElements();
+  const int * column = matrixByRow.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  const int * rowLength = matrixByRow.getVectorLengths();
+
+  // Column copy
+  CoinPackedMatrix  matrixByCol(*solver->getMatrixByCol());
+  const double * element = matrixByCol.getElements();
+  const int * row = matrixByCol.getIndices();
+  const CoinBigIndex * columnStart = matrixByCol.getVectorStarts();
+  const int * columnLength = matrixByCol.getVectorLengths();
+
+  const double * rowLower = solver->getRowLower();
+  const double * rowUpper = solver->getRowUpper();
+
+  char * ignore = new char [numberRows];
+  int * which = new int[numberRows];
+  double * changeRhs = new double[numberRows];
+  memset(changeRhs,0,numberRows*sizeof(double));
+  memset(ignore,0,numberRows);
+  int numberChanged=0;
+  bool finished=false;
+  while (!finished) {
+    int saveNumberChanged = numberChanged;
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int numberContinuous=0;
+      double value1=0.0,value2=0.0;
+      bool allIntegerCoeff=true;
+      double sumFixed=0.0;
+      int jColumn1=-1,jColumn2=-1;
+      for (CoinBigIndex j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+        int jColumn = column[j];
+        double value = elementByRow[j];
+        if (upper[jColumn] > lower[jColumn]+1.0e-8) {
+          if (!intVar[jColumn]) {
+            if (numberContinuous==0) {
+              jColumn1=jColumn;
+              value1=value;
+            } else {
+              jColumn2=jColumn;
+              value2=value;
+            }
+            numberContinuous++;
+          } else {
+            if (fabs(value-floor(value+0.5))>1.0e-12)
+              allIntegerCoeff=false;
+          }
+        } else {
+          sumFixed += lower[jColumn]*value;
+        }
+      }
+      double low = rowLower[iRow];
+      if (low>-1.0e20) {
+        low -= sumFixed;
+        if (fabs(low-floor(low+0.5))>1.0e-12)
+          allIntegerCoeff=false;
+      }
+      double up = rowUpper[iRow];
+      if (up<1.0e20) {
+        up -= sumFixed;
+        if (fabs(up-floor(up+0.5))>1.0e-12)
+          allIntegerCoeff=false;
+      }
+      if (!allIntegerCoeff)
+        continue; // can't do
+      if (numberContinuous==1) {
+        // see if really integer
+        // This does not allow for complicated cases
+        if (low==up) {
+          if (fabs(value1)>1.0e-3) {
+            value1 = 1.0/value1;
+            if (fabs(value1-floor(value1+0.5))<1.0e-12) {
+              // integer
+              numberChanged++;
+              intVar[jColumn1]=77;
+            }
+          }
+        } else {
+          if (fabs(value1)>1.0e-3) {
+            value1 = 1.0/value1;
+            if (fabs(value1-floor(value1+0.5))<1.0e-12) {
+              // This constraint will not stop it being integer
+              ignore[iRow]=1;
+            }
+          }
+        }
+      } else if (numberContinuous==2) {
+        if (low==up) {
+          /* need general theory - for now just look at 2 cases -
+             1 - +- 1 one in column and just costs i.e. matching objective
+             2 - +- 1 two in column but feeds into G/L row which will try and minimize
+             (take out 2 for now - until fixed)
+          */
+          if (fabs(value1)==1.0&&value1*value2==-1.0&&!lower[jColumn1]
+              &&!lower[jColumn2]&&columnLength[jColumn1]==1&&columnLength[jColumn2]==1) {
+            int n=0;
+            int i;
+            double objChange=direction*(objective[jColumn1]+objective[jColumn2]);
+            double bound = CoinMin(upper[jColumn1],upper[jColumn2]);
+            bound = CoinMin(bound,1.0e20);
+            for ( i=columnStart[jColumn1];i<columnStart[jColumn1]+columnLength[jColumn1];i++) {
+              int jRow = row[i];
+              double value = element[i];
+              if (jRow!=iRow) {
+                which[n++]=jRow;
+                changeRhs[jRow]=value;
+              }
+            }
+            for ( i=columnStart[jColumn2];i<columnStart[jColumn2]+columnLength[jColumn2];i++) {
+              int jRow = row[i];
+              double value = element[i];
+              if (jRow!=iRow) {
+                if (!changeRhs[jRow]) {
+                  which[n++]=jRow;
+                  changeRhs[jRow]=value;
+                } else {
+                  changeRhs[jRow]+=value;
+                }
+              }
+            }
+            if (objChange>=0.0) {
+              // see if all rows OK
+              bool good=true;
+              for (i=0;i<n;i++) {
+                int jRow = which[i];
+                double value = changeRhs[jRow];
+                if (value) {
+                  value *= bound;
+                  if (rowLength[jRow]==1) {
+                    if (value>0.0) {
+                      double rhs = rowLower[jRow];
+                      if (rhs>0.0) {
+                        double ratio =rhs/value;
+                        if (fabs(ratio-floor(ratio+0.5))>1.0e-12)
+                          good=false;
+                      }
+                    } else {
+                      double rhs = rowUpper[jRow];
+                      if (rhs<0.0) {
+                        double ratio =rhs/value;
+                        if (fabs(ratio-floor(ratio+0.5))>1.0e-12)
+                          good=false;
+                      }
+                    }
+                  } else if (rowLength[jRow]==2) {
+                    if (value>0.0) {
+                      if (rowLower[jRow]>-1.0e20)
+                        good=false;
+                    } else {
+                      if (rowUpper[jRow]<1.0e20)
+                        good=false;
+                    }
+                  } else {
+                    good=false;
+                  }
+                }
+              }
+              if (good) {
+                // both can be integer
+                numberChanged++;
+                intVar[jColumn1]=77;
+                numberChanged++;
+                intVar[jColumn2]=77;
+              }
+            }
+            // clear
+            for (i=0;i<n;i++) {
+              changeRhs[which[i]]=0.0;
+            }
+          }
+        }
+      }
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (upper[iColumn] > lower[iColumn]+1.0e-8&&!intVar[iColumn]) {
+        double value;
+        value = upper[iColumn];
+        if (value<1.0e20&&fabs(value-floor(value+0.5))>1.0e-12) 
+          continue;
+        value = lower[iColumn];
+        if (value>-1.0e20&&fabs(value-floor(value+0.5))>1.0e-12) 
+          continue;
+        bool integer=true;
+        for (CoinBigIndex j=columnStart[iColumn];j<columnStart[iColumn]+columnLength[iColumn];j++) {
+          int iRow = row[j];
+          if (!ignore[iRow]) {
+            integer=false;
+            break;
+          }
+        }
+        if (integer) {
+          // integer
+          numberChanged++;
+          intVar[iColumn]=77;
+        }
+      }
+    }
+    finished = numberChanged==saveNumberChanged;
+  }
+  bool feasible=true;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (intVar[iColumn]==77) {
+      if (upper[iColumn]>1.0e20) {
+        upper[iColumn] = 1.0e20;
+      } else {
+        upper[iColumn] = floor(upper[iColumn]+1.0e-5);
+      }
+      if (lower[iColumn]<-1.0e20) {
+        lower[iColumn] = -1.0e20;
+      } else {
+        lower[iColumn] = ceil(lower[iColumn]-1.0e-5);
+        if (lower[iColumn]>upper[iColumn])
+          feasible=false;
+      }
+      if (lower[iColumn]==0.0&&upper[iColumn]==1.0)
+        intVar[iColumn]=1;
+      else if (lower[iColumn]==upper[iColumn])
+        intVar[iColumn]=0;
+      else
+        intVar[iColumn]=2;
+    }
+  }
+  delete [] which;
+  delete [] changeRhs;
+  delete [] ignore;
+  //if (numberChanged)
+  //printf("%d variables could be made integer\n",numberChanged);
+  delete solver;
+  return feasible;
+}
+int CglProbing::gutsOfGenerateCuts(const OsiSolverInterface & si, 
+                                   OsiCuts & cs ,
+                                   double * rowLower, double * rowUpper,
+                                   double * colLower, double * colUpper,
+                                   CglTreeInfo * info)
+{
+  //printf("PASS\n");
+  // Get basic problem information
+  int nRows;
+  
+  CoinPackedMatrix * rowCopy=NULL;
+  int numberRowCutsBefore = cs.sizeRowCuts();
+
+  // get branch and bound cutoff
+  double cutoff;
+  bool cutoff_available = si.getDblParam(OsiDualObjectiveLimit,cutoff);
+  if (!cutoff_available||usingObjective_<0) { // cut off isn't set or isn't valid
+    cutoff = si.getInfinity();
+  }
+  cutoff *= si.getObjSense();
+  if (fabs(cutoff)>1.0e30)
+    assert (cutoff>1.0e30);
+  int mode=mode_;
+  
+  int nCols=si.getNumCols(); 
+
+  // get integer variables
+  const char * intVarOriginal = si.getColType(true);
+  char * intVar = CoinCopyOfArray(intVarOriginal,nCols);
+  int i;
+  int numberIntegers=0;
+  CoinMemcpyN(si.getColLower(),nCols,colLower);
+  CoinMemcpyN(si.getColUpper(),nCols,colUpper);
+  const double * colsol =si.getColSolution();
+  // and put reasonable bounds on integer variables
+  for (i=0;i<nCols;i++) {
+    if (intVar[i]) {
+      numberIntegers++;
+      if (intVar[i]==2) {
+	// make sure reasonable bounds
+	if (colsol[i]<1.0e10&&colUpper[i]>1.0e12) 
+	  colUpper[i] = CGL_REASONABLE_INTEGER_BOUND;
+	if (colsol[i]>-1.0e10&&colLower[i]<-1.0e12) 
+	  colLower[i] = -CGL_REASONABLE_INTEGER_BOUND;
+      }
+    }
+  }
+  bool feasible=true;
+  if (!info->inTree&&!info->pass) {
+    // make more integer
+    feasible = analyze(&si,intVar,colLower,colUpper);
+  }
+  if (feasible&&PROBING_EXTRA_STUFF) {
+    // tighten bounds on djs
+    // should be in CbcCutGenerator and check if basic 
+    const double * djs =si.getReducedCost();
+    const double * colsol =si.getColSolution();
+    double direction = si.getObjSense();
+    double cutoff;
+    bool cutoff_available = si.getDblParam(OsiDualObjectiveLimit,cutoff);
+    if (!cutoff_available||usingObjective_<0) { // cut off isn't set or isn't valid
+      cutoff = si.getInfinity();
+    }
+    cutoff *= direction;
+    if (fabs(cutoff)>1.0e30)
+      assert (cutoff>1.0e30);
+    double current = si.getObjValue();
+    current *= direction;
+    double gap=CoinMax(cutoff-current,1.0e-1);
+    for (int i = 0; i < nCols; ++i) {
+      double djValue = djs[i]*direction;
+      if (colUpper[i]-colLower[i]>1.0e-8) {
+        if (colsol[i]<colLower[i]+primalTolerance_) {
+          if (djValue>gap) {
+            if (si.isInteger(i)) {
+              printf("why int %d not fixed at lb\n",i);
+              colUpper[i]= colLower[i];
+            } else {
+              double newUpper = colLower[i] + gap/djValue;
+              if (newUpper<colUpper[i]) {
+                //printf("%d ub from %g to %g\n",i,colUpper[i],newUpper);
+                colUpper[i]= CoinMax(newUpper,colLower[i]+1.0e-5);
+              }
+            }
+          }
+        } else if (colsol[i]>colUpper[i]-primalTolerance_) {
+          if (-djValue>gap) {
+            if (si.isInteger(i)) {
+              printf("why int %d not fixed at ub\n",i);
+              colLower[i]= colUpper[i];
+            } else {
+              double newLower = colUpper[i] + gap/djValue;
+              if (newLower>colLower[i]) {
+                //printf("%d lb from %g to %g\n",i,colLower[i],newLower);
+                colLower[i]= CoinMin(newLower,colUpper[i]-1.0e-5);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  int ninfeas=0;
+  // Set up maxes
+  int maxProbe = info->inTree ? maxProbe_ : maxProbeRoot_;
+  int maxElements = info->inTree ? maxElements_ : maxElementsRoot_;
+  //if (!info->inTree&&!info->pass)
+  //maxElements=nCols;
+  // Get objective offset
+  double offset;
+  si.getDblParam(OsiObjOffset,offset);
+#ifdef COIN_DEVELOP
+  if (offset&&!info->inTree&&!info->pass) 
+    printf("CglProbing obj offset %g\n",offset);
+#endif
+  // see if using cached copy or not
+  if (!rowCopy_) {
+    // create from current
+    nRows=si.getNumRows(); 
+    
+    // mode==0 is invalid if going from current matrix
+    if (mode==0)
+      mode=1;
+    // add in objective if there is a cutoff
+    if (cutoff<1.0e30&&usingObjective_>0) {
+      rowCopy = new CoinPackedMatrix(*si.getMatrixByRow(),1,nCols,false);
+    } else {
+      rowCopy = new CoinPackedMatrix(*si.getMatrixByRow());
+    }
+    // add in objective if there is a cutoff
+    if (cutoff<1.0e30&&usingObjective_>0) {
+      int * columns = new int[nCols];
+      double * elements = new double[nCols];
+      int n=0;
+      const double * objective = si.getObjCoefficients();
+      bool maximize = (si.getObjSense()==-1);
+      for (i=0;i<nCols;i++) {
+	if (objective[i]) {
+	  elements[n]= (maximize) ? -objective[i] : objective[i];
+	  columns[n++]=i;
+	}
+      }
+      rowCopy->appendRow(n,columns,elements);
+      delete [] columns;
+      delete [] elements;
+      CoinMemcpyN(si.getRowLower(),nRows,rowLower);
+      CoinMemcpyN(si.getRowUpper(),nRows,rowUpper);
+      rowLower[nRows]=-COIN_DBL_MAX;
+      rowUpper[nRows]=cutoff+offset;
+      nRows++;
+    } else {
+      CoinMemcpyN(si.getRowLower(),nRows,rowLower);
+      CoinMemcpyN(si.getRowUpper(),nRows,rowUpper);
+    }
+  } else {
+    // use snapshot
+    nRows=numberRows_;
+    assert(nCols==numberColumns_);
+    
+    rowCopy = new CoinPackedMatrix(*rowCopy_);
+    assert (rowCopy_->getNumRows()==numberRows_);
+    rowLower = new double[nRows];
+    rowUpper = new double[nRows];
+    CoinMemcpyN(rowLower_,nRows,rowLower);
+    CoinMemcpyN(rowUpper_,nRows,rowUpper);
+    if (usingObjective_>0) {
+      rowLower[nRows-1]=-COIN_DBL_MAX;
+      rowUpper[nRows-1]=cutoff+offset;
+    }
+  }
+  CoinBigIndex * rowStartPos = NULL;
+  int * realRows = NULL;
+  {
+    // Now take out rows with too many elements
+    int * rowLength = rowCopy->getMutableVectorLengths(); 
+    //#define OUTRUBBISH
+    double * elements = rowCopy->getMutableElements();
+    int * column = rowCopy->getMutableIndices();
+    CoinBigIndex * rowStart = rowCopy->getMutableVectorStarts();
+#ifdef OUTRUBBISH
+    double large=1.0e3;
+#endif
+    int nDelete = 0;
+    int nKeep=0;
+    int * which = new int[nRows];
+    int nElements=rowCopy->getNumElements();
+    int nTotalOut=0;
+    int nRealRows = si.getNumRows();
+    for (i=0;i<nRows;i++) {
+      if (rowLength[i]>maxElements||(rowLower[i]<-1.0e20&&rowUpper[i]>1.0e20)) {
+	// keep objective
+	if (i<nRealRows) 
+	  nTotalOut+=rowLength[i];
+      }
+    }
+    // keep all if only a few dense
+    if (nTotalOut*10<nElements)
+      maxElements=nCols;
+#ifdef OUTRUBBISH
+    int nExtraDel=0;
+#endif
+    for (i=0;i<nRows;i++) {
+      if ((rowLength[i]>maxElements&&i<nRealRows)||
+	  (rowLower[i]<-1.0e20&&rowUpper[i]>1.0e20)) {
+	which[nDelete++]=i;
+      } else {
+#ifdef OUTRUBBISH
+	// out all rows with infinite plus and minus
+	int nPlus=rowUpper[i]>-large ? 0 : 1;
+	int nMinus=rowLower[i]<large ? 0 : 1;
+	CoinBigIndex start = rowStart[i];
+	CoinBigIndex end = start + rowLength[i];
+	for (CoinBigIndex j=start; j<end ; j++) { 
+	  int iColumn = column[j];
+	  if (colUpper[iColumn]>large) {
+	    if (elements[j]>0.0)
+	      nPlus++;
+	    else
+	      nMinus++;
+	  }
+	  if (colLower[iColumn]<-large) {
+	    if (elements[j]<0.0)
+	      nPlus++;
+	    else
+	      nMinus++;
+	  }
+	}
+	if (!nPlus||!nMinus) {
+	  rowLower[nKeep]=rowLower[i];
+	  rowUpper[nKeep]=rowUpper[i];
+	  nKeep++;
+	} else {
+	  nExtraDel++;
+	  which[nDelete++]=i;
+	}
+#else
+	if (info->strengthenRow&&!info->pass&&(rowLower[i]<-1.0e20||rowUpper[i]>1.0e20)) {
+	  int nPlus=0;
+	  int nMinus=0;
+	  for (CoinBigIndex j=rowStart[i];j<rowStart[i+1];j++) {
+	    int jColumn=column[j];
+	    if (intVar[jColumn]&&colLower[jColumn]==0.0&&colUpper[jColumn]==1.0) {
+	      double value=elements[j];
+	      if (value>0.0) {
+		nPlus++;
+	      } else {
+		nMinus++;
+	      }
+	    } else {
+	      nPlus=2;
+	      nMinus=2;
+	      break;
+	    }
+	  }
+	  double effectiveness=0.0;
+	  if (nPlus==1&&rowUpper[i]>0.0&&rowUpper[i]<1.0e10) {
+	    // can make element smaller
+	    for (CoinBigIndex j=rowStart[i];j<rowStart[i+1];j++) {
+	      double value=elements[j];
+	      if (value>0.0) {
+		elements[j] -= rowUpper[i];
+		//printf("pass %d row %d plus el from %g to %g\n",info->pass,
+		//     i,elements[j]+rowUpper[i],elements[j]);
+	      }
+	      effectiveness += fabs(elements[j]);
+	    }
+	    rowUpper[i]=0.0;
+	  } else if (nMinus==1&&rowLower[i]<0.0&&rowLower[i]>-1.0e10) {
+	    // can make element smaller in magnitude
+	    for (CoinBigIndex j=rowStart[i];j<rowStart[i+1];j++) {
+	      double value=elements[j];
+	      if (value<0.0) {
+		elements[j] -= rowLower[i];
+		//printf("pass %d row %d minus el from %g to %g\n",info->pass,
+		//     i,elements[j]+rowLower[i],elements[j]);
+	      }
+	      effectiveness += fabs(elements[j]);
+	    }
+	    rowLower[i]=0.0;
+	  }
+	  if (effectiveness) {
+	    OsiRowCut rc;
+	    rc.setLb(rowLower[i]);
+	    rc.setUb(rowUpper[i]);
+	    int start = rowStart[i];
+	    int n = rowLength[i];
+	    rc.setRow(rowLength[i],column+start,elements+start,false);
+	    // but get rid of tinies
+	    CoinPackedVector & row = rc.mutableRow();
+	    double * elements = row.getElements();
+	    int n2=0;
+	    for (n2=0;n2<n;n2++) {
+	      if (fabs(elements[n2])<1.0e-12)
+		break;
+	    }
+	    if (n2<n) {
+	      int * columns = row.getIndices();
+	      for (int i=n2+1;i<n;i++) {
+		if (fabs(elements[i])>1.0e-12) {
+		  elements[n2]=elements[i];
+		  columns[n2++]=columns[i];
+		}
+	      }
+	      row.truncate(n2);
+	    }
+	    rc.setEffectiveness(effectiveness);
+	    assert (!info->strengthenRow[i]);
+	    info->strengthenRow[i]=rc.clone();
+	  }
+	}
+	rowLower[nKeep]=rowLower[i];
+	rowUpper[nKeep]=rowUpper[i];
+	nKeep++;
+#endif
+      }
+    }
+    if (nDelete) {
+#ifdef OUTRUBBISH
+      if (nExtraDel) {
+	printf("%d rows deleted (extra %d)\n",nDelete,nExtraDel);
+      }
+#else
+#endif
+      if (info->strengthenRow) {
+	// Set up pointers to real rows
+	realRows = new int [nRows];
+	CoinZeroN(realRows,nRows);
+	for (i=0;i<nDelete;i++)
+	  realRows[which[i]]=-1;
+	int k=0;
+	for (i=0;i<nRows;i++) {
+	  if (!realRows[i]) {
+	    if (i<nRealRows)
+	      realRows[k++]=i; // keep
+	    else
+	      realRows[k++]=-1; // objective - discard
+	  }
+	}
+      }
+      rowCopy->deleteRows(nDelete,which);
+      nRows=nKeep;
+    }
+    delete [] which;
+    if (!nRows) {
+#ifdef COIN_DEVELOP
+      printf("All rows too long for probing\n");
+#endif
+      // nothing left!!
+      // delete stuff
+      delete rowCopy;
+      if (rowCopy_) {
+	delete [] rowLower;
+	delete [] rowUpper;
+      }
+      delete [] intVar;
+      // and put back unreasonable bounds on integer variables
+      const double * trueLower = si.getColLower();
+      const double * trueUpper = si.getColUpper();
+      for (i=0;i<nCols;i++) {
+	if (intVarOriginal[i]==2) {
+	  if (colUpper[i] == CGL_REASONABLE_INTEGER_BOUND) 
+	    colUpper[i] = trueUpper[i];
+	  if (colLower[i] == -CGL_REASONABLE_INTEGER_BOUND) 
+	    colLower[i] = trueLower[i];
+	}
+      }
+      delete [] realRows;
+      return 0;
+    }
+    // Out elements for fixed columns and sort
+    elements = rowCopy->getMutableElements();
+    column = rowCopy->getMutableIndices();
+    rowStart = rowCopy->getMutableVectorStarts();
+    rowLength = rowCopy->getMutableVectorLengths(); 
+#if 0
+    int nFixed=0;
+    for (i=0;i<nCols;i++) {
+      if (colUpper[i]==colLower[i])
+	nFixed++;
+    }
+    printf("%d columns fixed\n",nFixed);
+#endif
+    CoinBigIndex newSize=0;
+    int * column2 = new int[nCols];
+    double * elements2 = new double[nCols];
+    rowStartPos = new CoinBigIndex [nRows];
+    for (i=0;i<nRows;i++) {
+      double offset = 0.0;
+      CoinBigIndex start = rowStart[i];
+      rowStart[i]=newSize;
+      CoinBigIndex save=newSize;
+      CoinBigIndex end = start + rowLength[i];
+      int nOther=0;
+      for (CoinBigIndex j=start; j<end ; j++) { 
+	int iColumn = column[j];
+	if (colUpper[iColumn]>colLower[iColumn]) {
+	  double value = elements[j];
+	  if (value<0.0) {
+	    elements[newSize]=value;
+	    column[newSize++]=iColumn;
+	  } else if (value>0.0) {
+	    elements2[nOther]=value;
+	    column2[nOther++]=iColumn;
+	  }
+	} else {
+	  offset += colUpper[iColumn]*elements[j];
+	}
+      }
+      rowStartPos[i] = newSize;
+      for (int k=0;k<nOther;k++) {
+	elements[newSize]=elements2[k];
+	column[newSize++]=column2[k];
+      }
+      rowLength[i]=newSize-save;
+      if (offset) {
+	if (rowLower[i]>-1.0e20)
+	  rowLower[i] -= offset;
+	if (rowUpper[i]<1.0e20)
+	  rowUpper[i] -= offset;
+      }
+    }
+    delete [] column2;
+    delete [] elements2;
+    rowStart[nRows]=newSize;
+    rowCopy->setNumElements(newSize);
+  }
+  CoinPackedMatrix * columnCopy=new CoinPackedMatrix(*rowCopy,0,0,true);
+  int nRowsSafe=CoinMin(nRows,si.getNumRows());
+#ifdef CGL_DEBUG
+  const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
+  if (debugger&&!debugger->onOptimalPath(si))
+    debugger = NULL;
+#else
+  const OsiRowCutDebugger * debugger = NULL;
+#endif
+   
+  const int * column = rowCopy->getIndices();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const int * rowLength = rowCopy->getVectorLengths(); 
+  const double * rowElements = rowCopy->getElements();
+  // Arrays so user can find out what happened
+  if (!lookedAt_) {
+    lookedAt_ = new int[nCols];
+  }
+  numberThisTime_=0;
+  // Let us never add more than twice the number of rows worth of row cuts
+  // Keep cuts out of cs until end so we can find duplicates quickly
+  int nRowsFake = info->inTree ? nRowsSafe/3 : nRowsSafe;
+  if (!info->inTree&&!info->pass) 
+    nRowsFake *= 5;
+  row_cut rowCut(nRowsFake,!info->inTree);
+  int * markR = new int [nRows];
+  double * minR = new double [nRows];
+  double * maxR = new double [nRows];
+  if (mode) {
+    ninfeas= tighten(colLower, colUpper, column, rowElements,
+		     rowStart, rowStartPos ,rowLength, rowLower, rowUpper,
+		     nRows, nCols, intVar, 2, primalTolerance_);
+    if (!feasible)
+      ninfeas=1;
+    if (!ninfeas) {
+      // create column cuts where integer bounds have changed
+      {
+	const double * lower = si.getColLower();
+	const double * upper = si.getColUpper();
+	const double * colsol = si.getColSolution();
+	int numberChanged=0,ifCut=0;
+	CoinPackedVector lbs;
+	CoinPackedVector ubs;
+	for (i = 0; i < nCols; ++i) {
+	  if (intVar[i]) {
+	    colUpper[i] = CoinMin(upper[i],floor(colUpper[i]+1.0e-4));
+	    if (colUpper[i]<upper[i]-1.0e-8) {
+	      if (colUpper[i]<colsol[i]-1.0e-8)
+		ifCut=1;
+	      ubs.insert(i,colUpper[i]);
+	      numberChanged++;
+	    }
+	    colLower[i] = CoinMax(lower[i],ceil(colLower[i]-1.0e-4));
+	    if (colLower[i]>lower[i]+1.0e-8) {
+	      if (colLower[i]>colsol[i]+1.0e-8)
+		ifCut=1;
+	      lbs.insert(i,colLower[i]);
+	      numberChanged++;
+	    }
+	  }
+	}
+	if (numberChanged) {
+	  OsiColCut cc;
+	  cc.setUbs(ubs);
+	  cc.setLbs(lbs);
+	  if (ifCut) {
+	    cc.setEffectiveness(100.0);
+	  } else {
+	    cc.setEffectiveness(1.0e-5);
+	  }
+#ifdef CGL_DEBUG
+	  checkBounds(debugger,cc);
+#endif
+	  cs.insert(cc);
+	}
+      }
+      if (maxProbe>0) {
+        numberThisTime_=0;
+        // get min max etc for rows
+        tighten2(colLower, colUpper, column, rowElements,
+                 rowStart, rowLength, rowLower, rowUpper,
+                 minR , maxR , markR, nRows);
+        // decide what to look at
+        if (mode==1) {
+          const double * colsol = si.getColSolution();
+          double_int_pair * array = new double_int_pair [nCols];
+#	  ifdef ZEROFAULT
+	  std::memset(array,0,sizeof(double_int_pair)*nCols) ;
+#	  endif
+	  double multiplier = -1.0;
+	  if (info->inTree||(info->pass&1)!=0)
+	    multiplier=1.0;
+	  //const int * columnLength = si.getMatrixByCol()->getVectorLengths();
+          for (i=0;i<nCols;i++) {
+            if (intVar[i]&&colUpper[i]-colLower[i]>1.0e-8) {
+              double away = fabs(0.5-(colsol[i]-floor(colsol[i])));
+              if (away<0.49999||!info->inTree) {
+                //array[numberThisTime_].infeasibility=away;
+                array[numberThisTime_].infeasibility=away*multiplier;
+                //array[numberThisTime_].infeasibility=-columnLength[i];
+                array[numberThisTime_++].sequence=i;
+              }
+            }
+          }
+	  //printf("maxP %d num %d\n",maxProbe,numberThisTime_);
+          std::sort(array,array+numberThisTime_,double_int_pair_compare());
+          //numberThisTime_=CoinMin(numberThisTime_,maxProbe);
+          for (i=0;i<numberThisTime_;i++) {
+            lookedAt_[i]=array[i].sequence;
+          }
+          delete [] array;
+        } else {
+          for (i=0;i<nCols;i++) {
+            if (intVar[i]&&colUpper[i]-colLower[i]>1.0e-8) {
+              lookedAt_[numberThisTime_++]=i;
+            }
+          }
+        }
+#if 0
+        // Only look at short rows
+        for (i=0;i<nRows;i++) {
+          if (rowLength[i]>maxElements)
+            abort(); //markR[i]=-2;
+        }
+#endif
+	// sort to be clean
+	//std::sort(lookedAt_,lookedAt_+numberThisTime_);
+        if (!numberCliques_) {
+          ninfeas= probe(si, debugger, cs, colLower, colUpper, rowCopy,columnCopy,
+                         rowStartPos, realRows, rowLower, rowUpper,
+                         intVar, minR, maxR, markR,
+                         info);
+        } else {
+          ninfeas= probeCliques(si, debugger, cs, colLower, colUpper, rowCopy,columnCopy,
+                                realRows,rowLower, rowUpper,
+                                intVar, minR, maxR, markR,
+                                info);
+        }
+      }
+    }
+  } else if (maxProbe>0) {
+    // global cuts from previous calculations
+    // could check more thoroughly that integers are correct
+    assert(numberIntegers==numberIntegers_);
+    // make up list of new variables to look at 
+    numberThisTime_=0;
+    const double * colsol = si.getColSolution();
+    double_int_pair * array = new double_int_pair [nCols];
+#   ifdef ZEROFAULT
+    std::memset(array,0,sizeof(double_int_pair)*nCols) ;
+#   endif
+    for (i=0;i<number01Integers_;i++) {
+      int j=cutVector_[i].sequence;
+      if (!cutVector_[i].index&&colUpper[j]-colLower[j]>1.0e-8) {
+	double away = fabs(0.5-(colsol[j]-floor(colsol[j])));
+        array[numberThisTime_].infeasibility=away;
+        array[numberThisTime_++].sequence=i;
+      }
+    }
+    std::sort(array,array+numberThisTime_,double_int_pair_compare());
+    numberThisTime_=CoinMin(numberThisTime_,maxProbe);
+    for (i=0;i<numberThisTime_;i++) {
+      lookedAt_[i]=array[i].sequence;
+    }
+    // sort to be clean
+    //std::sort(lookedAt_,lookedAt_+numberThisTime_);
+    delete [] array;
+    // get min max etc for rows
+    tighten2(colLower, colUpper, column, rowElements,
+	     rowStart, rowLength, rowLower, rowUpper,
+	     minR , maxR , markR, nRows);
+    OsiCuts csNew;
+    // don't do cuts at all if 0 (i.e. we are just checking bounds)
+    if (rowCuts_) {
+#if 0
+      // Only look at short rows
+      for (i=0;i<nRows;i++) {
+        if (rowLength[i]>maxElements)
+          abort(); //markR[i]=-2;
+      }
+#endif
+      ninfeas= probeCliques(si, debugger, csNew, colLower, colUpper, rowCopy,columnCopy,
+			    realRows, rowLower, rowUpper,
+		     intVar, minR, maxR, markR,
+		     info);
+    }
+    if (!ninfeas) {
+      // go through row cuts
+      int nCuts = csNew.sizeRowCuts();
+      int iCut;
+      // need space for backward lookup
+      // just for ones being looked at
+      int * backward = new int [2*nCols];
+      int * onList = backward + nCols;
+      for (i=0;i<nCols;i++) {
+        backward[i]=-1;
+        onList[i]=0;
+      }
+      for (i=0;i<number01Integers_;i++) {
+	int j=cutVector_[i].sequence;
+	backward[j]=i;
+	onList[j]=1;
+      }
+      // first do counts
+      // we know initialized to zero
+      for (iCut=0;iCut<nCuts;iCut++) {
+	OsiRowCut rcut;
+	CoinPackedVector rpv;
+	rcut = csNew.rowCut(iCut);
+	rpv = rcut.row();
+	assert(rpv.getNumElements()==2);
+	const int * indices = rpv.getIndices();
+	double* elements = rpv.getElements();
+	double lb=rcut.lb();
+	// find out which integer
+        int which=0;
+        i=backward[indices[0]];
+        if (i<0||!onList[indices[0]]) {
+          which=1;
+          i=backward[indices[1]];
+          // Just possible variable was general integer but now 0-1
+          if (!onList[indices[which]])
+            continue;
+        }
+        int other = indices[1-which];
+	if (lb==-COIN_DBL_MAX) {
+          if (!rcut.ub()) {
+            // UB
+            if (elements[which]<0.0) {
+              //assert (elements[1-which]>0.0);
+              // delta to 0 => x to 0.0
+              cutVector_[i].length++;
+            } else {
+              if (elements[1-which]<0.0&&fabs(elements[which]/elements[1-which]-
+                                              colUpper[other])<1.0e-5) {
+                // delta to 1 => x to upper bound
+                cutVector_[i].length++;
+              } else {
+                if (onList[other]) {
+                  double value0 = elements[0];
+                  double value1 = elements[1];
+                  if (value0*value1==-1.0) {
+                    // can do something ?
+                    int j=backward[other];
+                    cutVector_[i].length++;
+                    cutVector_[j].length++;
+                  } else {
+                    continue;
+                  }
+                }
+              }
+            }
+          } else {
+            if (onList[other]) {
+              if (elements[0]==1.0&&elements[1]==1.0&&rcut.ub()==1.0) {
+                // can do something ?
+                int j=backward[other];
+                cutVector_[i].length++;
+                cutVector_[j].length++;
+              } else {
+                continue;
+              }
+            }
+          }
+	} else {
+          assert(rcut.ub()==DBL_MAX);
+          if (!lb) {
+            // LB
+            if (elements[which]>0.0) {
+              //assert (elements[1-which]<0.0);
+              // delta to 0 => x to 0.0
+              // flip so same as UB
+              cutVector_[i].length++; 
+            } else {
+              if (elements[1-which]<0.0&&fabs(elements[which]/elements[1-which]-
+                                              colUpper[other])<1.0e-5) {
+                // delta to 1 => x to upper bound
+                cutVector_[i].length++;
+              } else {
+                if (onList[other]) {
+                  double value0 = elements[0];
+                  double value1 = elements[1];
+                  if (value0*value1==-1.0) {
+                    // can do something ?
+                    int j=backward[other];
+                    cutVector_[i].length++;
+                    cutVector_[j].length++;
+                  } else {
+                    continue;
+                  }
+                }
+              }
+            }
+          }
+	} 
+      }
+      // allocate space
+      for (i=0;i<number01Integers_;i++) {
+	int j=cutVector_[i].sequence;
+	if (onList[j]&&!cutVector_[i].index) {
+	  disaggregation thisOne=cutVector_[i];
+	  cutVector_[i].index=new disaggregationAction [thisOne.length];
+          cutVector_[i].length=0;
+	}
+      }
+      // now put in
+      for (iCut=0;iCut<nCuts;iCut++) {
+	OsiRowCut rcut;
+	CoinPackedVector rpv;
+	int iput;
+	rcut = csNew.rowCut(iCut);
+	rpv = rcut.row();
+	assert(rpv.getNumElements()==2);
+	const int * indices = rpv.getIndices();
+	double* elements = rpv.getElements();
+	double lb=rcut.lb();
+	// find out which integer
+	// find out which integer
+        int which=0;
+        i=backward[indices[0]];
+        if (i<0||!onList[indices[0]]) {
+          which=1;
+          i=backward[indices[1]];
+          // Just possible variable was general integer but now 0-1
+          if (!onList[indices[which]])
+            continue;
+        }
+        int other = indices[1-which];
+        int j = other ? backward[other] : -1;
+	if (lb==-COIN_DBL_MAX) {
+          if (!rcut.ub()) {
+            // UB
+            if (elements[which]<0.0) {
+              iput=cutVector_[i].length;
+              if (j>=0)
+                setAffectedInDisaggregation(cutVector_[i].index[iput],j);
+              else
+                setAffectedInDisaggregation(cutVector_[i].index[iput],other);
+              setWhenAtUBInDisaggregation(cutVector_[i].index[iput],false);
+              setAffectedToUBInDisaggregation(cutVector_[i].index[iput],false);
+	      setZeroOneInDisaggregation(cutVector_[i].index[iput],onList[other]!=0);
+              cutVector_[i].length++;
+            } else { 
+              if (elements[1-which]<0.0&&fabs(elements[which]/elements[1-which]-
+                                              colUpper[other])<1.0e-5) {
+                // delta to 1 => x to upper bound
+                iput=cutVector_[i].length;
+                if (j>=0)
+                  setAffectedInDisaggregation(cutVector_[i].index[iput],j);
+                else
+                  setAffectedInDisaggregation(cutVector_[i].index[iput],other);
+                setWhenAtUBInDisaggregation(cutVector_[i].index[iput],true);
+                setAffectedToUBInDisaggregation(cutVector_[i].index[iput],true);
+                setZeroOneInDisaggregation(cutVector_[i].index[iput],onList[other]!=0);
+                cutVector_[i].length++;
+              } else {
+                if (onList[other]) {
+                  double value0 = elements[0];
+                  double value1 = elements[1];
+                  if (value0*value1==-1.0) {
+                    // can do something ?
+                    int j=backward[other];
+                    assert (j>=0);
+                    // flip so value0 1.0
+                    if (value1==1.0) {
+                      j=i;
+                      i=backward[other];
+                      value1=value0;
+                      value0=1.0;
+                    }
+                    assert (value0==1.0);
+                    assert (value1==-1.0);
+                    iput=cutVector_[i].length;
+                    setAffectedInDisaggregation(cutVector_[i].index[iput],j);
+                    setWhenAtUBInDisaggregation(cutVector_[i].index[iput],true);
+                    setAffectedToUBInDisaggregation(cutVector_[i].index[iput],true);
+                    setZeroOneInDisaggregation(cutVector_[i].index[iput],true);
+                    cutVector_[i].length++;
+                    iput=cutVector_[j].length;
+                    setAffectedInDisaggregation(cutVector_[j].index[iput],i);
+                    setWhenAtUBInDisaggregation(cutVector_[j].index[iput],false);
+                    setAffectedToUBInDisaggregation(cutVector_[j].index[iput],false);
+                    setZeroOneInDisaggregation(cutVector_[j].index[iput],true);
+                    cutVector_[j].length++;
+                  }
+                }
+              }
+            }
+          } else {
+            if (onList[other]) {
+              if (elements[0]==1.0&&elements[1]==1.0&&rcut.ub()==1.0) {
+                // can do something ?
+                int j=backward[other];
+                assert (j>=0);
+                iput=cutVector_[i].length;
+                setAffectedInDisaggregation(cutVector_[i].index[iput],j);
+                setWhenAtUBInDisaggregation(cutVector_[i].index[iput],true);
+                setAffectedToUBInDisaggregation(cutVector_[i].index[iput],false);
+                setZeroOneInDisaggregation(cutVector_[i].index[iput],true);
+                cutVector_[i].length++;
+                iput=cutVector_[j].length;
+                setAffectedInDisaggregation(cutVector_[j].index[iput],i);
+                setWhenAtUBInDisaggregation(cutVector_[j].index[iput],true);
+                setAffectedToUBInDisaggregation(cutVector_[j].index[iput],false);
+                setZeroOneInDisaggregation(cutVector_[j].index[iput],true);
+                cutVector_[j].length++;
+              } else {
+#ifdef COIN_DEVELOP
+                abort();
+#endif
+		continue;
+              }
+            }
+          }
+	} else {
+          assert(rcut.ub()==DBL_MAX);
+          if (!lb) {
+            // LB
+            if (elements[which]>0.0) {
+              iput=cutVector_[i].length;
+              if (j>=0)
+                setAffectedInDisaggregation(cutVector_[i].index[iput],j);
+              else
+                setAffectedInDisaggregation(cutVector_[i].index[iput],other);
+              setWhenAtUBInDisaggregation(cutVector_[i].index[iput],false);
+              setAffectedToUBInDisaggregation(cutVector_[i].index[iput],false);
+              setZeroOneInDisaggregation(cutVector_[i].index[iput],onList[other]!=0);
+              cutVector_[i].length++;
+            } else { 
+              if (elements[1-which]<0.0&&fabs(elements[which]/elements[1-which]-
+                                              colUpper[other])<1.0e-5) {
+                iput=cutVector_[i].length;
+                if (j>=0)
+                  setAffectedInDisaggregation(cutVector_[i].index[iput],j);
+                else
+                  setAffectedInDisaggregation(cutVector_[i].index[iput],other);
+                setWhenAtUBInDisaggregation(cutVector_[i].index[iput],true);
+                setAffectedToUBInDisaggregation(cutVector_[i].index[iput],true);
+                setZeroOneInDisaggregation(cutVector_[i].index[iput],onList[other]!=0);
+                cutVector_[i].length++;
+              } else {
+                if (onList[other]) {
+                  double value0 = elements[0];
+                  double value1 = elements[1];
+                  if (value0*value1==-1.0) {
+                    // can do something ?
+                    int j=backward[other];
+                    assert (j>=0);
+                    // flip so value0 -1.0
+                    if (value1==-1.0) {
+                      j=i;
+                      i=backward[other];
+                      value1=value0;
+                      value0=-1.0;
+                    }
+                    assert (value0==-1.0);
+                    assert (value1==1.0);
+                    iput=cutVector_[i].length;
+                    setAffectedInDisaggregation(cutVector_[i].index[iput],j);
+                    setWhenAtUBInDisaggregation(cutVector_[i].index[iput],true);
+                    setAffectedToUBInDisaggregation(cutVector_[i].index[iput],true);
+                    setZeroOneInDisaggregation(cutVector_[i].index[iput],true);
+                    cutVector_[i].length++;
+                    iput=cutVector_[j].length;
+                    setAffectedInDisaggregation(cutVector_[j].index[iput],i);
+                    setWhenAtUBInDisaggregation(cutVector_[j].index[iput],false);
+                    setAffectedToUBInDisaggregation(cutVector_[j].index[iput],false);
+                    setZeroOneInDisaggregation(cutVector_[j].index[iput],true);
+                    cutVector_[j].length++;
+                  }
+                }
+              }
+            }
+          }
+	} 
+      }
+      delete [] backward;
+      // Now sort and get rid of duplicates
+      // could also see if any are cliques
+      int longest=0;
+      for (i=0;i<number01Integers_;i++) 
+        longest = CoinMax(longest, cutVector_[i].length);
+      unsigned int * sortit = new unsigned int[longest];
+      for (i=0;i<number01Integers_;i++) {
+        disaggregation & thisOne=cutVector_[i];
+        int k;
+        int number = thisOne.length;
+        for (k=0;k<number;k++) {
+          int affected = affectedInDisaggregation(thisOne.index[k]);
+          int zeroOne = zeroOneInDisaggregation(thisOne.index[k]) ? 1 : 0;
+          int whenAtUB = whenAtUBInDisaggregation(thisOne.index[k]) ? 1 : 0;
+          int affectedToUB = affectedToUBInDisaggregation(thisOne.index[k]) ? 1: 0;
+          sortit[k]=(affected<<3)|(zeroOne<<2)|(whenAtUB<<1)|affectedToUB;
+        }
+        std::sort(sortit,sortit+number);
+        int affectedLast = 0xffffffff;
+        int zeroOneLast = 0;
+        int whenAtUBLast = 0;
+        int affectedToUBLast = 0; 
+        int put=0;
+        for (k=0;k<number;k++) {
+          int affected = sortit[k]>>3;
+          int zeroOne = (sortit[k]&4)>>2;
+          int whenAtUB = (sortit[k]&2)>>1;
+          int affectedToUB = sortit[k]&1;
+          disaggregationAction action;
+	  action.affected=0;
+          setAffectedInDisaggregation(action,affected);
+          setZeroOneInDisaggregation(action,zeroOne!=0);
+          setWhenAtUBInDisaggregation(action,whenAtUB!=0);
+          setAffectedToUBInDisaggregation(action,affectedToUB!=0);
+          if (affected!=affectedLast||zeroOne!=zeroOneLast) {
+            // new variable
+            thisOne.index[put++]=action;
+          } else if (whenAtUB!=whenAtUBLast||affectedToUB!=affectedToUBLast) {
+            // new action - what can we discover
+            thisOne.index[put++]=action;
+            int j=cutVector_[i].sequence;
+            int k=affected;
+            if (zeroOne) {
+              k=cutVector_[k].sequence;
+              if (logLevel_>1)
+                printf("For %d %d 0-1 pair",j,k) ;
+            } else {
+              if (logLevel_>1)
+                printf("For %d %d pair",j,k) ;
+            }
+            if (logLevel_>1)
+              printf(" old whenAtUB, affectedToUB %d %d, new whenAtUB, affectedToUB %d %d\n",
+                     whenAtUBLast, affectedToUBLast,whenAtUB, affectedToUB);
+          }
+          affectedLast=affected;
+          zeroOneLast=zeroOne;
+          whenAtUBLast=whenAtUB;
+          affectedToUBLast=affectedToUB;
+        }
+        if (put<number) {
+          //printf("%d reduced from %d to %d\n",i,number,put);
+          thisOne.length=put;
+        }
+      }
+      // And look at all where two 0-1 variables involved
+      for (i=0;i<number01Integers_;i++) {
+        disaggregation & thisOne=cutVector_[i];
+        int k;
+        int number = thisOne.length;
+        for (k=0;k<number;k++) {
+          int affected = affectedInDisaggregation(thisOne.index[k]);
+          bool zeroOne = zeroOneInDisaggregation(thisOne.index[k]);
+          if (zeroOne&&static_cast<int>(affected)>i) {
+            bool whenAtUB = whenAtUBInDisaggregation(thisOne.index[k]);
+            bool affectedToUB = affectedToUBInDisaggregation(thisOne.index[k]);
+            disaggregation otherOne=cutVector_[affected];
+            int numberOther = otherOne.length;
+            // Could do binary search if a lot
+            int lastAction=-1;
+            for (int j=0;j<numberOther;j++) {
+              if (affectedInDisaggregation(otherOne.index[j])==i) {
+                bool whenAtUBOther = whenAtUBInDisaggregation(otherOne.index[j]);
+                bool affectedToUBOther = affectedToUBInDisaggregation(otherOne.index[j]);
+                /* action -
+                   0 -> x + y <=1 (1,1 impossible)
+                   1 -> x - y <=0 (1,0 impossible)
+                   2 -> -x + y <=0 (0,1 impossible)
+                   3 -> -x -y <= -1 (0,0 impossible)
+                  10 -> x == y
+                  11 -> x + y == 1
+                  20 -> x == 0
+                  21 -> x == 1
+                  22 -> y == 0
+                  23 -> y == 1
+                */
+                int action=-1;
+                if (whenAtUB) {
+                  if (affectedToUB) {
+                    // x -> 1 => y -> 1
+                    if (whenAtUBOther) {
+                      if (affectedToUBOther) {
+                        // y -> 1 => x -> 1
+                        action=10; // x,y must be same
+                      } else {
+                        // y -> 1 => x -> 0 
+                        action=20; // If x is 1 then contradiction
+                      }
+                    } else {
+                      if (affectedToUBOther) {
+                        // y -> 0 => x -> 1 
+                        action=23; // if y is 0 then contradiction
+                      } else {
+                        // y -> 0 => x -> 0
+                        action=1; // x,y 1,0 impossible 
+                      }
+                    }
+                  } else {
+                    // x -> 1 => y -> 0
+                    if (whenAtUBOther) {
+                      if (affectedToUBOther) {
+                        // y -> 1 => x -> 1
+                        action=22; // If y is 1 then contradiction
+                      } else {
+                        // y -> 1 => x -> 0 
+                        action=0; 
+                      }
+                    } else {
+                      if (affectedToUBOther) {
+                        // y -> 0 => x -> 1 
+                        action=11; // x,y with same values impossible
+                      } else {
+                        // y -> 0 => x -> 0
+                        action=20; // If x is 1 then contradiction
+                      }
+                    }
+                  }
+                } else {
+                  if (affectedToUB) {
+                    // x -> 0 => y -> 1
+                    if (whenAtUBOther) {
+                      if (affectedToUBOther) {
+                        // y -> 1 => x -> 1
+                        action=21; // If x is 0 then contradiction
+                      } else {
+                        // y -> 1 => x -> 0 
+                        action=11; // x,y must be different
+                      }
+                    } else {
+                      if (affectedToUBOther) {
+                        // y -> 0 => x -> 1 
+                        action=3; // one of x,y must be 1
+                      } else {
+                        // y -> 0 => x -> 0
+                        action=23; // if y is 0 then contradiction
+                      }
+                    }
+                  } else {
+                    // x -> 0 => y -> 0
+                    if (whenAtUBOther) {
+                      if (affectedToUBOther) {
+                        // y -> 1 => x -> 1
+                        action=2; // x,y 0,1 impossible
+                      } else {
+                        // y -> 1 => x -> 0 
+                        action=22; // If y is 1 then contradiction
+                      }
+                    } else {
+                      if (affectedToUBOther) {
+                        // y -> 0 => x -> 1 
+                        action=21; // if x is 0 then contradiction
+                      } else {
+                        // y -> 0 => x -> 0
+                        action=10; // x,y must be same
+                      }
+                    }
+                  }
+                }
+                assert (action>=0);
+                if (action<4) {
+                  // clique - see if there
+                  if (oneFixStart_) {
+                    switch (action) {
+                    case 0:
+                      break;
+                    case 1:
+                      break;
+                    case 2:
+                      break;
+                    case 3:
+                      break;
+                    }
+                    // If not can we add or strengthen
+                  }
+                  // check last action
+                  if (lastAction>=0) {
+                    if (logLevel_>1)
+                      printf("XX lastAction %d, this %d\n",lastAction,action);
+                  }
+                } else if (action<12) {
+                  if (logLevel_>1)
+                    printf("XX Could eliminate one of %d %d 0-1 variables %c\n",i,affected,
+                           (lastAction>=0) ? '*' : ' ');
+                  if (info->strengthenRow) {
+                    OsiRowCut rc;
+                    int index[2];
+                    double element[2];
+                    index[0]=cutVector_[i].sequence;
+                    element[0]=1.0;
+                    index[1]=cutVector_[affected].sequence;
+                    if (action==10) {
+                      // 10 -> x == y
+                      rc.setLb(0.0);
+                      rc.setUb(0.0);   
+                      element[1]= -1.0;
+                    } else {
+                      // 11 -> x + y == 1
+                      rc.setLb(1.0);
+                      rc.setUb(1.0);   
+                      element[1]= 1.0;
+                    }
+                    rc.setRow(2,index,element,false);
+                    cs.insert(rc);
+                  }
+                } else {
+                  if (action<22) {
+                    if (logLevel_>1)
+                      printf("XX Could fix a 0-1 variable %d\n",i);
+                  } else {
+                    if (logLevel_>1)
+                      printf("XX Could fix a 0-1 variable %d\n",affected);
+		  }
+                }
+                //printf("%d when %d forces %d to %d , %d when %d forces %d to %d\n",
+                //     i,whenAtUB,affected,affectedToUB, 
+                //     affected, whenAtUBOther,i, affectedToUBOther);
+              }
+            }
+          }
+        }
+      }
+      delete [] sortit;
+    }
+    if (cutVector_) {
+      // now see if any disaggregation cuts are violated
+      for (i=0;i<number01Integers_;i++) {
+	int j=cutVector_[i].sequence;
+	double solInt=colsol[j];
+	double  upper, solValue;
+	int icol;
+	int index[2];
+	double element[2];
+	if (colUpper[j]-colLower[j]>1.0e-8) {
+	  double away = fabs(0.5-(solInt-floor(solInt)));
+	  if (away<0.4999999) {
+	    disaggregation thisOne=cutVector_[i];
+	    int k;
+	    OsiRowCut rc;
+	    for (k=0;k<thisOne.length;k++) {
+	      icol = affectedInDisaggregation(thisOne.index[k]);
+              if (zeroOneInDisaggregation(thisOne.index[k]))
+                icol = cutVector_[icol].sequence;
+	      solValue=colsol[icol];
+	      upper=colUpper_[icol];
+              double infeasibility=0.0;
+              if (!whenAtUBInDisaggregation(thisOne.index[k])) {
+                if (!affectedToUBInDisaggregation(thisOne.index[k])) {
+                  // delta -> 0 => x to lb (at present just 0)
+                  infeasibility = solValue - upper * solInt;
+                  if (infeasibility > 1.0e-3) {
+                    rc.setLb(-COIN_DBL_MAX);
+                    rc.setUb(0.0);
+                    index[0]=icol;
+                    element[0]=1.0;
+                    index[1]=j;
+                    element[1]= -upper;
+                  } else {
+                    infeasibility=0.0;
+                  }
+                } else {
+                  // delta -> 0 => x to ub
+                  abort();
+                }
+              } else {
+                if (affectedToUBInDisaggregation(thisOne.index[k])) {
+                  // delta -> 1 => x to ub (?)
+                  icol = affectedInDisaggregation(thisOne.index[k]);
+                  if (zeroOneInDisaggregation(thisOne.index[k]))
+                    icol = cutVector_[icol].sequence;
+                  solValue=colsol[icol];
+                  upper=colUpper_[icol];
+                  if (!colLower[icol]) {
+                    infeasibility = upper * solInt - solValue;
+                    if (infeasibility > 1.0e-3) {
+                      rc.setLb(-COIN_DBL_MAX);
+                      rc.setUb(0.0);
+                      index[0]=icol;
+                      element[0]=-1.0;
+                      index[1]=j;
+                      element[1]= upper;
+                    } else {
+                      infeasibility=0.0;
+                    }
+                  } else {
+                    assert (upper==colLower[icol]);
+                    infeasibility=0.0;
+                  }
+                } else {
+                  // delta + delta2 <= 1
+                  assert (zeroOneInDisaggregation(thisOne.index[k]));
+                  // delta -> 1 => delta2 -> 0
+                  icol = affectedInDisaggregation(thisOne.index[k]);
+                  icol = cutVector_[icol].sequence;
+                  // only do if icol > j
+                  if (icol >j && colUpper[icol] ) {
+                    solValue=colsol[icol];
+                    if (!colLower[icol]) {
+                      infeasibility = solInt + solValue - 1.0;
+                      if (infeasibility > 1.0e-3) {
+                        rc.setLb(-COIN_DBL_MAX);
+                        rc.setUb(1.0);
+                        index[0]=icol;
+                        element[0]=1.0;
+                        index[1]=j;
+                        element[1]= 1.0;
+                      } else {
+                        infeasibility=0.0;
+                      }
+                    } else {
+                      assert (upper==colLower[icol]);
+                      infeasibility=0.0;
+                    }
+                  }
+                }
+              }
+              if (infeasibility) {
+                rc.setEffectiveness(infeasibility);
+                rc.setRow(2,index,element,false);
+                if (logLevel_>1)
+                  printf("%g <= %g * x%d + %g * x%d <= %g\n",
+                         rc.lb(),element[0],index[0],element[1],index[1],rc.ub());
+#ifdef CGL_DEBUG
+                if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                rowCut.addCutIfNotDuplicate(rc);
+              }
+	    }
+	  }
+	}
+      }
+    }
+  }
+  delete [] markR;
+  delete [] minR;
+  delete [] maxR;
+  // Add in row cuts
+  if (!ninfeas) {
+    rowCut.addCuts(cs,info->strengthenRow,0);
+  }
+  // delete stuff
+  delete rowCopy;
+  delete columnCopy;
+  if (rowCopy_) {
+    delete [] rowLower;
+    delete [] rowUpper;
+  }
+  delete [] intVar;
+  delete [] rowStartPos;
+  delete [] realRows;
+  // and put back unreasonable bounds on integer variables
+  const double * trueLower = si.getColLower();
+  const double * trueUpper = si.getColUpper();
+  if (!ninfeas) {
+    for (i=0;i<nCols;i++) {
+      if (intVarOriginal[i]==2) {
+	if (colUpper[i] == CGL_REASONABLE_INTEGER_BOUND) 
+	  colUpper[i] = trueUpper[i];
+	if (colLower[i] == -CGL_REASONABLE_INTEGER_BOUND) 
+	  colLower[i] = trueLower[i];
+      }
+    }
+  } else {
+    memcpy(colLower,trueLower,nCols*sizeof(double));
+    memcpy(colUpper,trueUpper,nCols*sizeof(double));
+  }
+  if (!info->inTree&&((info->options&4)==4||((info->options&8)&&!info->pass))) {
+    int numberRowCutsAfter = cs.sizeRowCuts();
+    for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++)
+      cs.rowCutPtr(i)->setGloballyValid();
+  }
+  return ninfeas;
+}
+// Does probing and adding cuts
+int CglProbing::probe( const OsiSolverInterface & si, 
+		       const OsiRowCutDebugger *
+#ifdef CGL_DEBUG
+		       debugger
+#endif 
+		       ,OsiCuts & cs, 
+		       double * colLower, double * colUpper, 
+		       CoinPackedMatrix *rowCopy,
+		       CoinPackedMatrix *columnCopy,
+		       const CoinBigIndex * rowStartPos,const int * realRows, 
+		       const double * rowLower, const double * rowUpper,
+		       const char * intVar, double * minR, double * maxR, 
+		       int * markR, 
+		       CglTreeInfo * info)
+{
+  int nRows=rowCopy->getNumRows();
+  int nRowsSafe=CoinMin(nRows,si.getNumRows());
+  int nCols=rowCopy->getNumCols();
+  const double * currentColLower = si.getColLower();
+  const double * currentColUpper = si.getColUpper();
+  // Set up maxes
+  int maxStack = info->inTree ? maxStack_ : maxStackRoot_;
+  int maxPass = info->inTree ? maxPass_ : maxPassRoot_;
+  if ((totalTimesCalled_%10)==-1) {
+    int newMax=CoinMin(2*maxStack,50);
+    maxStack=CoinMax(newMax,maxStack);
+  }
+#define ONE_ARRAY
+#ifdef ONE_ARRAY
+  unsigned int DIratio = sizeof(double)/sizeof(int);
+  assert (DIratio==1||DIratio==2);
+  int nSpace = 8*nCols+4*nRows+2*maxStack;
+  nSpace += (4*nCols+nRows+maxStack+DIratio-1)>>(DIratio-1);
+  double * colsol = new double[nSpace];
+  double * djs = colsol + nCols;
+  double * columnGap = djs + nCols;
+  double * saveL = columnGap + nCols;
+  double * saveU = saveL + 2*nCols;
+  double * saveMin = saveU + 2*nCols;
+  double * saveMax = saveMin + nRows;
+  double * largestPositiveInRow = saveMax + nRows;
+  double * largestNegativeInRow = largestPositiveInRow + nRows;
+  double * element = largestNegativeInRow + nRows;
+  double * lo0 = element + nCols;
+  double * up0 = lo0 + maxStack;
+  int * markC = reinterpret_cast<int *> (up0+maxStack);
+  int * stackC = markC + nCols;
+  int * stackR = stackC + 2*nCols;
+  int * index = stackR + nRows;
+  int * stackC0 = index + nCols;
+#else 
+  double * colsol = new double[nCols];
+  double * djs = new double[nCols];
+  double * columnGap = new double [nCols];
+  double * saveL = new double [2*nCols];
+  double * saveU = new double [2*nCols];
+  double * saveMin = new double [nRows];
+  double * saveMax = new double [nRows];
+  double * largestPositiveInRow = new double [nRows];
+  double * largestNegativeInRow = new double [nRows];
+  double * element = new double[nCols];
+  double * lo0 = new double[maxStack];
+  double * up0 = new double[maxStack];
+  int * markC = new int [nCols];
+  int * stackC = new int [2*nCols];
+  int * stackR = new int [nRows];
+  int * index = new int[nCols];
+  int * stackC0 = new int[maxStack];
+#endif
+  // Let us never add more than twice the number of rows worth of row cuts
+  // Keep cuts out of cs until end so we can find duplicates quickly
+#define PROBING4
+#ifdef PROBING4
+  int nRowsFake = info->inTree ? nRowsSafe/3 : nRowsSafe*10;
+#else
+  int nRowsFake = info->inTree ? nRowsSafe/3 : nRowsSafe;
+#endif
+  if (!info->inTree&&!info->pass) 
+    nRowsFake *= 10;
+  bool justReplace = ((info->options&64)!=0)&&(realRows!=NULL);
+  if (justReplace) {
+    nRowsFake=nRows;
+  }
+  row_cut rowCut(nRowsFake, !info->inTree);
+  totalTimesCalled_++;
+  const int * column = rowCopy->getIndices();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const double * rowElements = rowCopy->getElements();
+  const int * row = columnCopy->getIndices();
+  const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+  const int * columnLength = columnCopy->getVectorLengths(); 
+  const double * columnElements = columnCopy->getElements();
+#define MOVE_SINGLETONS
+#ifdef MOVE_SINGLETONS
+  const double * objective = si.getObjCoefficients();
+  const int * columnLength2 = si.getMatrixByCol()->getVectorLengths(); 
+#endif
+  bool anyColumnCuts=false;
+  int ninfeas=0;
+  int rowCuts;
+  double disaggEffectiveness;
+  /* clean up djs and solution */
+  CoinMemcpyN(si.getReducedCost(),nCols,djs);
+  CoinMemcpyN( si.getColSolution(),nCols,colsol);
+  disaggEffectiveness=1.0e-3;
+  rowCuts=rowCuts_;
+  //CoinBigIndex * rowStartPos = new CoinBigIndex [nRows];
+#ifndef NDEBUG
+  const int * rowLength = rowCopy->getVectorLengths(); 
+#endif
+  for (int i=0;i<nRows;i++) {
+    assert (rowStart[i]+rowLength[i]==rowStart[i+1]);
+    int kk;
+#ifndef NDEBUG
+    for ( kk =rowStart[i];kk<rowStart[i+1];kk++) {
+      double value = rowElements[kk];
+      if (value>0.0) 
+	break;
+    }
+    assert (rowStartPos[i]==kk);
+#endif
+    double value;
+    value=0.0;
+    for ( kk =rowStart[i];kk<rowStartPos[i];kk++) {
+      int iColumn = column[kk];
+      double gap = CoinMin(1.0e100,colUpper[iColumn]-colLower[iColumn]);
+      value = CoinMin(value,gap*rowElements[kk]);
+    }
+    largestNegativeInRow[i]=value;
+    value=0.0;
+    for ( ;kk<rowStart[i+1];kk++) {
+      int iColumn = column[kk];
+      double gap = CoinMin(1.0e100,colUpper[iColumn]-colLower[iColumn]);
+      value = CoinMax(value,gap*rowElements[kk]);
+    }
+    largestPositiveInRow[i]=value;
+  }
+  double direction = si.getObjSense();
+  for (int i = 0; i < nCols; ++i) {
+    double djValue = djs[i]*direction;
+    double gap=colUpper[i]-colLower[i];
+    if (gap>1.0e-8) {
+      if (colsol[i]<colLower[i]+primalTolerance_) {
+        colsol[i]=colLower[i];
+        djs[i] = CoinMax(0.0,djValue);
+      } else if (colsol[i]>colUpper[i]-primalTolerance_) {
+        colsol[i]=colUpper[i];
+        djs[i] = CoinMin(0.0,djValue);
+      } else {
+        djs[i]=0.0;
+      }
+    }
+    columnGap[i]=gap-primalTolerance_;
+  }
+
+  int ipass=0,nfixed=-1;
+
+  double cutoff;
+  bool cutoff_available = si.getDblParam(OsiDualObjectiveLimit,cutoff);
+  if (!cutoff_available||usingObjective_<0) { // cut off isn't set or isn't valid
+    cutoff = si.getInfinity();
+  }
+  cutoff *= direction;
+  if (fabs(cutoff)>1.0e30)
+    assert (cutoff>1.0e30);
+  double current = si.getObjValue();
+  current *= direction;
+  /* for both way coding */
+  int nstackC0=-1;
+  int nstackR,nstackC;
+  //int nFix=0;
+  for (int i=0;i<nCols;i++) {
+    if (colUpper[i]-colLower[i]<1.0e-8) {
+      markC[i]=3;
+      //nFix++;
+    } else {
+      markC[i]=0;
+      if (colUpper[i]>1.0e10)
+	markC[i] |= 8;
+      if (colLower[i]<-1.0e10)
+	markC[i] |= 4;
+    }
+  }
+  //printf("PROBE %d fixed out of %d\n",nFix,nCols);
+  double tolerance = 1.0e1*primalTolerance_;
+  // If we are going to replace coefficient then we don't need to be effective
+  //double needEffectiveness = info->strengthenRow ? -1.0e10 : 1.0e-3;
+  double needEffectiveness = info->strengthenRow ? 1.0e-8 : 1.0e-3;
+  if (justReplace&&(info->pass&1)!=0)
+    needEffectiveness=-1.0e10;
+  if (PROBING_EXTRA_STUFF) {
+    int nCut=0;
+    for (int iRow=0;iRow<nRows;iRow++) {
+      int numberInt=0;
+      int whichInt=-1;
+      int numberNeg=0;
+      double sumFixed=0.0;
+      double intValue=0.0;
+      for (CoinBigIndex j=rowStart[iRow];j<rowStart[iRow+1];j++) {
+        int jColumn = column[j];
+        double value = rowElements[j];
+        if (colUpper[jColumn] > colLower[jColumn]+1.0e-8) {
+          if (intVar[jColumn]) {
+            numberInt++;
+            whichInt=jColumn;
+            intValue=value;
+          } else if (value<0) {
+            numberNeg++;
+          }
+        } else {
+          sumFixed += colLower[jColumn]*value;
+        }
+      }
+      if (numberInt==1&&numberNeg==0&&intValue<0.0&&!rowUpper[iRow]&&rowLower[iRow]<-1.0e30&&!sumFixed) {
+        double intSol = colsol[whichInt];
+        for (CoinBigIndex j=rowStart[iRow];j<rowStart[iRow+1];j++) {
+          int jColumn = column[j];
+          //double value = rowElements[j];
+          if (colUpper[jColumn] > colLower[jColumn]+1.0e-8) {
+            if (!intVar[jColumn]) {
+              if (colLower[jColumn]||colUpper[jColumn]>1.0)
+                continue;;
+              double upper = colUpper[jColumn];
+              if (colsol[jColumn]>intSol*upper+1.0e-4) {
+                nCut++;
+                OsiRowCut rc;
+                rc.setLb(-COIN_DBL_MAX);
+                rc.setUb(0.0);
+                rc.setEffectiveness(1.0e-5);
+                int index[2];
+                double element[2];
+                index[0]=jColumn;
+                index[1]=whichInt;
+                element[0]=1.0;
+                element[1]=-upper;
+                rc.setRow(2,index,element,false);
+                cs.insert(rc);
+              }
+            }
+          }
+        }
+      }
+    }
+    if (nCut)
+      printf("%d possible cuts\n",nCut);
+  }
+  bool saveFixingInfo =  false;
+#if PROBING100
+  CglTreeProbingInfo * probingInfo = dynamic_cast<CglTreeProbingInfo *> (info);
+  const int * backward = NULL;
+  const int * integerVariable = NULL;
+  const int * toZero = NULL;
+  const int * toOne = NULL;
+  const fixEntry * fixEntries=NULL;
+#endif
+  if (info->inTree) {
+#if PROBING100
+    backward = probingInfo->backward();
+    integerVariable = probingInfo->integerVariable();
+    toZero = probingInfo->toZero();
+    toOne = probingInfo->toOne();
+    fixEntries=probingInfo->fixEntries();
+#endif
+  } else {
+    saveFixingInfo = (info->initializeFixing(&si)>0);
+  }
+  while (ipass<maxPass&&nfixed) {
+    int iLook;
+    ipass++;
+    //printf("pass %d\n",ipass);
+    nfixed=0;
+    int justFix= (!info->inTree&&!info->pass) ? -1 : 0;
+    int maxProbe = info->inTree ? maxProbe_ : maxProbeRoot_;
+    if (justFix<0)
+      maxProbe=numberThisTime_;
+    if (maxProbe==123) {
+      // Try and be a bit intelligent
+      maxProbe=0;
+      if (!info->inTree) {
+	if (!info->pass||numberThisTime_<-100) {
+	  maxProbe=numberThisTime_;
+	} else {
+	  int cutDown = 4;
+	  int offset = info->pass % cutDown;
+	  int i;
+	  int k=0;
+	  int kk=offset;
+	  for (i=0;i<numberThisTime_;i++) {
+	    if (!kk) {
+#define XXXXXX
+#ifdef XXXXXX
+	      lookedAt_[maxProbe]=lookedAt_[i];
+#endif
+	      maxProbe++;
+	      kk=cutDown-1;
+	    } else {
+	      stackC[k++]=lookedAt_[i];
+	      kk--;
+	    }
+	  }
+#ifdef XXXXXX
+	  memcpy(lookedAt_+maxProbe,stackC,k*sizeof(int));
+#endif
+	}
+      } else {
+	// in tree
+	if (numberThisTime_<200) {
+	  maxProbe=numberThisTime_;
+	} else {
+	  int cutDown = CoinMax(numberThisTime_/100,4);
+	  int offset = info->pass % cutDown;
+	  int i;
+	  int k=0;
+	  int kk=offset;
+	  for (i=0;i<numberThisTime_;i++) {
+	    if (!kk) {
+#ifdef XXXXXX
+	      lookedAt_[maxProbe]=lookedAt_[i];
+#endif
+	      maxProbe++;
+	      kk=cutDown-1;
+	    } else {
+	      stackC[k++]=lookedAt_[i];
+	      kk--;
+	    }
+	  }
+#ifdef XXXXXX
+	  memcpy(lookedAt_+maxProbe,stackC,k*sizeof(int));
+#endif
+	}
+      }
+    }
+    int leftTotalStack=maxStack*CoinMax(200,maxProbe);
+#ifdef PROBING5
+    if (!info->inTree&&!info->pass)
+      leftTotalStack = 1234567890;
+#endif
+    //printf("maxStack %d maxPass %d numberThisTime %d info pass %d\n",
+    //   maxStack,maxPass,numberThisTime_,info->pass);
+    for (iLook=0;iLook<numberThisTime_;iLook++) {
+      double solval;
+      double down;
+      double up;
+      if (rowCut.outOfSpace()||leftTotalStack<=0) {
+	if (!justFix&&(!nfixed||info->inTree)) {
+#ifdef COIN_DEVELOP
+	  if (!info->inTree)
+	    printf("Exiting a on pass %d, maxProbe %d\n",
+		   ipass,maxProbe);
+#endif	  
+	  break;
+	} else if (justFix<=0) {
+	  if (!info->inTree) {
+	    rowCuts=0;
+	    justFix=1;
+	    disaggEffectiveness=COIN_DBL_MAX;
+	    needEffectiveness=COIN_DBL_MAX;
+	    //maxStack=10;
+	    maxPass=1;
+	  } else if (!nfixed) {
+#ifdef COIN_DEVELOP
+	    printf("Exiting b on pass %d, maxProbe %d\n",
+		   ipass,maxProbe);
+#endif	  
+	    break;
+	  }
+	}
+      }
+      int j=lookedAt_[iLook];
+      //if (j==231||j==226)
+      //printf("size %d %d j is %d\n",rowCut.numberCuts(),cs.sizeRowCuts(),j);//printf("looking at %d (%d out of %d)\n",j,iLook,numberThisTime_); 
+      solval=colsol[j];
+      down = floor(solval+tolerance);
+      up = ceil(solval-tolerance);
+      if(columnGap[j]<0.0) markC[j]=3;
+      if ((markC[j]&3)!=0||!intVar[j]) continue;
+      double saveSolval = solval;
+      if (solval>=colUpper[j]-tolerance||solval<=colLower[j]+tolerance||up==down) {
+	if (solval<=colLower[j]+2.0*tolerance) {
+	  solval = colLower[j]+1.0e-1;
+	  down=colLower[j];
+	  up=down+1.0;
+	} else if (solval>=colUpper[j]-2.0*tolerance) {
+	  solval = colUpper[j]-1.0e-1;
+	  up=colUpper[j];
+	  down=up-1;
+	} else {
+          // odd
+          up=down+1.0;
+          solval = down+1.0e-1;
+        }
+      }
+      assert (up<=colUpper[j]);
+      assert (down>=colLower[j]);
+      assert (up>down);
+      int istackC,iway, istackR;
+      int way[]={1,2,1};
+      int feas[]={1,2,4};
+      int feasible=0;
+      int notFeasible;
+      for (iway=0;iway<3;iway ++) {
+        int fixThis=0;
+        double objVal=current;
+        int goingToTrueBound=0;
+        stackC[0]=j;
+        markC[j]=way[iway];
+        double solMovement;
+        double movement;
+        if (way[iway]==1) {
+          movement=down-colUpper[j];
+          solMovement = down-colsol[j];
+          assert(movement<-0.99999);
+          if (fabs(down-colLower[j])<1.0e-7) {
+            goingToTrueBound=2;
+            down=colLower[j];
+          }
+        } else {
+          movement=up-colLower[j];
+          solMovement = up-colsol[j];
+          assert(movement>0.99999);
+          if (fabs(up-colUpper[j])<1.0e-7) {
+            goingToTrueBound=2;
+            up=colUpper[j];
+          }
+        }
+        if (goingToTrueBound&&(colUpper[j]-colLower[j]>1.5||colLower[j]))
+          goingToTrueBound=1;
+        // switch off disaggregation if not wanted
+        if ((rowCuts&1)==0)
+          goingToTrueBound=0;
+	bool canReplace = info->strengthenRow&&(goingToTrueBound==2);
+#ifdef PRINT_DEBUG
+        if (fabs(movement)>1.01) {
+          printf("big %d %g %g %g\n",j,colLower[j],solval,colUpper[j]);
+        }
+#endif
+        if (solMovement*djs[j]>0.0)
+          objVal += solMovement*djs[j];
+        nstackC=1;
+        nstackR=0;
+        saveL[0]=colLower[j];
+        saveU[0]=colUpper[j];
+        assert (saveU[0]>saveL[0]);
+        notFeasible=0;
+        if (movement<0.0) {
+          colUpper[j] += movement;
+          colUpper[j] = floor(colUpper[j]+0.5);
+	  columnGap[j] = colUpper[j]-colLower[j]-primalTolerance_;
+#ifdef PRINT_DEBUG
+          printf("** Trying %d down to 0\n",j);
+#endif
+        } else {
+          colLower[j] += movement;
+          colLower[j] = floor(colLower[j]+0.5);
+	  columnGap[j] = colUpper[j]-colLower[j]-primalTolerance_;
+#ifdef PRINT_DEBUG
+          printf("** Trying %d up to 1\n",j);
+#endif
+        }
+        if (fabs(colUpper[j]-colLower[j])<1.0e-6)
+          markC[j]=3; // say fixed
+	markC[j] &= ~12;
+	if (colUpper[j]>1.0e10)
+	  markC[j] |= 8;
+	if (colLower[j]<-1.0e10)
+	  markC[j] |= 4;
+        istackC=0;
+        /* update immediately */
+	int k;
+        for ( k=columnStart[j];k<columnStart[j]+columnLength[j];k++) {
+          int irow = row[k];
+          double value = columnElements[k];
+          assert (markR[irow]!=-2);
+          if (markR[irow]==-1) {
+            stackR[nstackR]=irow;
+            markR[irow]=nstackR;
+            saveMin[nstackR]=minR[irow];
+            saveMax[nstackR]=maxR[irow];
+            nstackR++;
+#if 0
+          } else if (markR[irow]==-2) {
+            continue;
+#endif
+          }
+          /* could check immediately if violation */
+          if (movement>0.0) {
+            /* up */
+            if (value>0.0) {
+              /* up does not change - down does */
+              if (minR[irow]>-1.0e10)
+                minR[irow] += value;
+              if (minR[irow]>rowUpper[irow]+1.0e-5) {
+                notFeasible=1;
+                istackC=1;
+                break;
+              }
+            } else {
+              /* down does not change - up does */
+              if (maxR[irow]<1.0e10)
+                maxR[irow] += value;
+              if (maxR[irow]<rowLower[irow]-1.0e-5) {
+                notFeasible=1;
+                istackC=1;
+                break;
+              }
+            }
+          } else {
+            /* down */
+            if (value<0.0) {
+              /* up does not change - down does */
+              if (minR[irow]>-1.0e10)
+                minR[irow] -= value;
+              if (minR[irow]>rowUpper[irow]+1.0e-5) {
+                notFeasible=1;
+                istackC=1;
+                break;
+              }
+            } else {
+              /* down does not change - up does */
+              if (maxR[irow]<1.0e10)
+                maxR[irow] -= value;
+              if (maxR[irow]<rowLower[irow]-1.0e-5) {
+                notFeasible=1;
+                istackC=1;
+                break;
+              }
+            }
+          }
+        }
+        while (istackC<nstackC&&nstackC<maxStack) { // could be istackC<maxStack?
+	  leftTotalStack--;
+          int jway;
+          int jcol =stackC[istackC];
+          jway=markC[jcol];
+          // If not first and fixed then skip
+          if ((jway&3)==3&&istackC) {
+            //istackC++;
+            //continue;
+            //printf("fixed %d on stack\n",jcol);
+          }
+#if PROBING100
+	  if (backward) {
+	    int jColumn = backward[jcol];
+	    if (jColumn>=0) {
+	      int nFix=0;
+	      // 0-1 see what else could be fixed
+	      if (jway==1) {
+		// fixed to 0
+		int j;
+		for ( j=toZero_[jColumn];j<toOne_[jColumn];j++) {
+		  int kColumn=fixEntry_[j].sequence;
+		  kColumn = integerVariable_[kColumn];
+		  bool fixToOne = fixEntry_[j].oneFixed;
+		  if (fixToOne) {
+		    if (colLower[kColumn]==0.0) {
+		      if (colUpper[kColumn]==1.0) {
+			// See if on list
+			if (!(markC[kColumn]&3)) {
+			  if(nStackC<nCols) {
+			    stackC[nstackC]=kColumn;
+			    saveL[nstackC]=colLower[kColumn];
+			    saveU[nstackC]=colUpper[kColumn];
+			    assert (saveU[nstackC]>saveL[nstackC]);
+			    assert (nstackC<nCols);
+			    nstackC++;
+			    markC[kColumn]|=2;
+			    nFix++;
+			  }
+			} else if ((markC[kColumn]&3)==1) {
+			  notFeasible=true;
+			}
+		      } else {
+			// infeasible!
+			notFeasible=true;
+		      }
+		    }
+		  } else {
+		    if (colUpper[kColumn]==1.0) {
+		      if (colLower[kColumn]==0.0) {
+			// See if on list
+			if (!(markC[kColumn]&3)) {
+			  if(nStackC<nCols) {
+			    stackC[nstackC]=kColumn;
+			    saveL[nstackC]=colLower[kColumn];
+			    saveU[nstackC]=colUpper[kColumn];
+			    assert (saveU[nstackC]>saveL[nstackC]);
+			    assert (nstackC<nCols);
+			    nstackC++;
+			    markC[kColumn]|=1;
+			    nFix++;
+			  }
+			} else if ((markC[kColumn]&3)==2) {
+			  notFeasible=true;
+			}
+		      } else {
+			// infeasible!
+			notFeasible=true;
+		      }
+		    }
+		  }
+		}
+	      } else if (jway==2) {
+		int j;
+		for ( j=toOne_[jColumn];j<toZero_[jColumn+1];j++) {
+		  int kColumn=fixEntry_[j].sequence;
+		  kColumn = integerVariable_[kColumn];
+		  bool fixToOne = fixEntry_[j].oneFixed;
+		  if (fixToOne) {
+		    if (colLower[kColumn]==0.0) {
+		      if (colUpper[kColumn]==1.0) {
+			// See if on list
+			if (!(markC[kColumn]&3)) {
+			  if(nStackC<nCols) {
+			    stackC[nstackC]=kColumn;
+			    saveL[nstackC]=colLower[kColumn];
+			    saveU[nstackC]=colUpper[kColumn];
+			    assert (saveU[nstackC]>saveL[nstackC]);
+			    assert (nstackC<nCols);
+			    nstackC++;
+			    markC[kColumn]|=2;
+			    nFix++;
+			  }
+			} else if ((markC[kColumn]&3)==1) {
+			  notFeasible=true;
+			}
+		      } else {
+			// infeasible!
+			notFeasible=true;
+		      }
+		    }
+		  } else {
+		    if (colUpper[kColumn]==1.0) {
+		      if (colLower[kColumn]==0.0) {
+			// See if on list
+			if (!(markC[kColumn]&3)) {
+			  if(nStackC<nCols) {
+			    stackC[nstackC]=kColumn;
+			    saveL[nstackC]=colLower[kColumn];
+			    saveU[nstackC]=colUpper[kColumn];
+			    assert (saveU[nstackC]>saveL[nstackC]);
+			    assert (nstackC<nCols);
+			    nstackC++;
+			    markC[kColumn]|=1;
+			    nFix++;
+			  }
+			} else if ((markC[kColumn]&3)==2) {
+			  notFeasible=true;
+			}
+		      } else {
+			// infeasible!
+			notFeasible=true;
+		      }
+		    }
+		  }
+		}
+	      }
+	    }
+	  }
+#endif
+          for (k=columnStart[jcol];k<columnStart[jcol]+columnLength[jcol];k++) {
+            // break if found not feasible
+            if (notFeasible)
+              break;
+            int irow = row[k];
+	    /* see if anything forced */
+	    int rStart = rowStart[irow];
+	    int rEnd = rowStartPos[irow];
+	    double rowUp = rowUpper[irow];
+	    double rowUp2=0.0;
+	    bool doRowUpN;
+	    bool doRowUpP;
+	    if (rowUp<1.0e10) {
+	      doRowUpN=true;
+	      doRowUpP=true;
+	      rowUp2 = rowUp-minR[irow];
+	      if (rowUp2<-primalTolerance_) {
+		notFeasible=true;
+		break;
+	      } else {
+		if (rowUp2+largestNegativeInRow[irow]>0)
+		  doRowUpN=false;
+		if (rowUp2-largestPositiveInRow[irow]>0)
+		  doRowUpP=false;
+	      }
+	    } else {
+	      doRowUpN=false;
+	      doRowUpP=false;
+	      rowUp2=COIN_DBL_MAX;
+	    }
+	    double rowLo = rowLower[irow];
+	    double rowLo2=0.0;
+	    bool doRowLoN;
+	    bool doRowLoP;
+	    if (rowLo>-1.0e10) {
+	      doRowLoN=true;
+	      doRowLoP=true;
+	      rowLo2 = rowLo-maxR[irow];
+	      if (rowLo2>primalTolerance_) {
+		notFeasible=true;
+		break;
+	      } else {
+		if (rowLo2-largestNegativeInRow[irow]<0)
+		  doRowLoN=false;
+		if (rowLo2+largestPositiveInRow[irow]<0)
+		  doRowLoP=false;
+	      }
+	    } else {
+	      doRowLoN=false;
+	      doRowLoP=false;
+	      rowLo2=-COIN_DBL_MAX;
+	    }
+	    if (doRowUpN&&doRowLoN) {
+	      //doRowUpN=doRowLoN=false;
+	      // Start neg values loop
+	      for (int kk =rStart;kk<rEnd;kk++) {
+		int kcol=column[kk];
+		int markIt=markC[kcol];
+		if ((markIt&3)!=3) {
+		  double value2=rowElements[kk];
+		  if (colUpper[kcol]<=1e10)
+		    assert ((markIt&8)==0);
+		  else
+		    assert ((markIt&8)!=0);
+		  if (colLower[kcol]>=-1e10)
+		    assert ((markIt&4)==0);
+		  else
+		    assert ((markIt&4)!=0);
+		  assert (value2<0.0);
+		  double gap = columnGap[kcol]*value2;
+		  bool doUp = (rowUp2 + gap < 0.0);
+		  bool doDown = (rowLo2 -gap > 0.0);
+		  if (doUp||doDown) {
+		    double moveUp=0.0;
+		    double moveDown=0.0;
+		    double newUpper=-1.0;
+		    double newLower=1.0;
+		    if ( doUp&&(markIt&(2+8))==0) {
+		      double dbound = colUpper[kcol]+rowUp2/value2;
+		      if (intVar[kcol]) {
+			markIt |= 2;
+			newLower = ceil(dbound-primalTolerance_);
+		      } else {
+			newLower=dbound;
+			if (newLower+primalTolerance_>colUpper[kcol]&&
+			    newLower-primalTolerance_<=colUpper[kcol]) {
+			  newLower=colUpper[kcol];
+			  markIt |= 2;
+			  //markIt=3;
+			} else {
+			  // avoid problems - fix later ?
+			  markIt=3;
+			}
+		      }
+		      moveUp = newLower-colLower[kcol];
+		    }
+		    if ( doDown&&(markIt&(1+4))==0) {
+		      double dbound = colLower[kcol] + rowLo2/value2;
+		      if (intVar[kcol]) {
+			markIt |= 1;
+			newUpper = floor(dbound+primalTolerance_);
+		      } else {
+			newUpper=dbound;
+			if (newUpper-primalTolerance_<colLower[kcol]&&
+			    newUpper+primalTolerance_>=colLower[kcol]) {
+			  newUpper=colLower[kcol];
+			  markIt |= 1;
+			  //markIt=3;
+			} else {
+			  // avoid problems - fix later ?
+			  markIt=3;
+			}
+		      }
+		      moveDown = newUpper-colUpper[kcol];
+		    }
+		    if (!moveUp&&!moveDown)
+		      continue;
+		    bool onList = ((markC[kcol]&3)!=0);
+		    if (nstackC<2*maxStack) {
+		      markC[kcol] = markIt;
+		    }
+		    if (moveUp&&nstackC<2*maxStack) {
+		      fixThis++;
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+			assert (saveU[nstackC]>saveL[nstackC]);
+			assert (nstackC<nCols);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newLower>colsol[kcol]) {
+			if (djs[kcol]<0.0) {
+			  /* should be infeasible */
+			  assert (newLower>colUpper[kcol]+primalTolerance_);
+			} else {
+			  objVal += moveUp*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol]) 
+			newLower = CoinMax(colLower[kcol],ceil(newLower-1.0e-4));
+		      colLower[kcol]=newLower;
+		      columnGap[kcol] = colUpper[kcol]-newLower-primalTolerance_;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      markC[kcol] &= ~12;
+		      if (colUpper[kcol]>1.0e10)
+			markC[kcol] |= 8;
+		      if (colLower[kcol]<-1.0e10)
+			markC[kcol] |= 4;
+		      /* update immediately */
+		      for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			int krow = row[jj];
+			double value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+			}
+			/* could check immediately if violation */
+			/* up */
+			if (value>0.0) {
+			  /* up does not change - down does */
+			  if (minR[krow]>-1.0e10)
+			    minR[krow] += value*moveUp;
+			  if (krow==irow)
+			    rowUp2 = rowUp-minR[irow];
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+			  if (maxR[krow]<1.0e10)
+			    maxR[krow] += value*moveUp;
+			  if (krow==irow)
+			    rowLo2 = rowLo-maxR[irow];
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (moveDown&&nstackC<2*maxStack) {
+		      fixThis++;
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+			assert (saveU[nstackC]>saveL[nstackC]);
+			assert (nstackC<nCols);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newUpper<colsol[kcol]) {
+			if (djs[kcol]>0.0) {
+			  /* should be infeasible */
+			  assert (colLower[kcol]>newUpper+primalTolerance_);
+			} else {
+			  objVal += moveDown*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol])
+			newUpper = CoinMin(colUpper[kcol],floor(newUpper+1.0e-4));
+		      colUpper[kcol]=newUpper;
+		      columnGap[kcol] = newUpper-colLower[kcol]-primalTolerance_;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      markC[kcol] &= ~12;
+		      if (colUpper[kcol]>1.0e10)
+			markC[kcol] |= 8;
+		      if (colLower[kcol]<-1.0e10)
+			markC[kcol] |= 4;
+		      /* update immediately */
+		      for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			int krow = row[jj];
+			double value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+			}
+			/* could check immediately if violation */
+			/* down */
+			if (value<0.0) {
+			  /* up does not change - down does */
+			  if (minR[krow]>-1.0e10)
+			    minR[krow] += value*moveDown;
+			  if (krow==irow)
+			    rowUp2 = rowUp-minR[irow];
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+			  if (maxR[krow]<1.0e10)
+			    maxR[krow] += value*moveDown;
+			  if (krow==irow)
+			    rowLo2 = rowLo-maxR[irow];
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (colLower[kcol]>colUpper[kcol]+primalTolerance_) {
+		      notFeasible=1;;
+		      k=columnStart[jcol]+columnLength[jcol];
+		      istackC=nstackC+1;
+		      break;
+		    }
+		  }
+		}
+	      } // end big loop rStart->rPos
+	    } else if (doRowUpN) {
+	      // Start neg values loop
+	      for (int kk =rStart;kk<rEnd;kk++) {
+		int kcol =column[kk];
+		int markIt=markC[kcol];
+		if ((markIt&3)!=3) {
+		  double value2=rowElements[kk];
+		  double gap = columnGap[kcol]*value2;
+		  if (!(rowUp2 + gap < 0.0))
+		    continue;
+		  double moveUp=0.0;
+		  double newLower=1.0;
+		  if ((markIt&(2+8))==0) {
+		    double dbound = colUpper[kcol]+rowUp2/value2;
+		    if (intVar[kcol]) {
+		      markIt |= 2;
+		      newLower = ceil(dbound-primalTolerance_);
+		    } else {
+		      newLower=dbound;
+		      if (newLower+primalTolerance_>colUpper[kcol]&&
+			  newLower-primalTolerance_<=colUpper[kcol]) {
+			newLower=colUpper[kcol];
+			markIt |= 2;
+			//markIt=3;
+		      } else {
+			// avoid problems - fix later ?
+			markIt=3;
+		      }
+		    }
+		    moveUp = newLower-colLower[kcol];
+		    if (!moveUp)
+		      continue;
+		    bool onList = ((markC[kcol]&3)!=0);
+		    if (nstackC<2*maxStack) {
+		      markC[kcol] = markIt;
+		    }
+		    if (moveUp&&nstackC<2*maxStack) {
+		      fixThis++;
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+			assert (saveU[nstackC]>saveL[nstackC]);
+			assert (nstackC<nCols);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newLower>colsol[kcol]) {
+			if (djs[kcol]<0.0) {
+			  /* should be infeasible */
+			  assert (newLower>colUpper[kcol]+primalTolerance_);
+			} else {
+			  objVal += moveUp*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol]) 
+			newLower = CoinMax(colLower[kcol],ceil(newLower-1.0e-4));
+		      colLower[kcol]=newLower;
+		      columnGap[kcol] = colUpper[kcol]-newLower-primalTolerance_;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      markC[kcol] &= ~12;
+		      if (colUpper[kcol]>1.0e10)
+			markC[kcol] |= 8;
+		      if (colLower[kcol]<-1.0e10)
+			markC[kcol] |= 4;
+		      /* update immediately */
+		      for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			int krow = row[jj];
+			double value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+			}
+			/* could check immediately if violation */
+			/* up */
+			if (value>0.0) {
+			  /* up does not change - down does */
+			  if (minR[krow]>-1.0e10)
+			    minR[krow] += value*moveUp;
+			  if (krow==irow)
+			    rowUp2 = rowUp-minR[irow];
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+			  if (maxR[krow]<1.0e10)
+			    maxR[krow] += value*moveUp;
+			  if (krow==irow)
+			    rowLo2 = rowLo-maxR[irow];
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (colLower[kcol]>colUpper[kcol]+primalTolerance_) {
+		      notFeasible=1;;
+		      k=columnStart[jcol]+columnLength[jcol];
+		      istackC=nstackC+1;
+		      break;
+		    }
+		  }
+		}
+	      } // end big loop rStart->rPos
+	    } else if (doRowLoN) {
+	      // Start neg values loop
+	      for (int kk =rStart;kk<rEnd;kk++) {
+		int kcol =column[kk];
+		if ((markC[kcol]&3)!=3) {
+		  double moveDown=0.0;
+		  double newUpper=-1.0;
+		  double value2=rowElements[kk];
+		  int markIt=markC[kcol];
+		  assert (value2<0.0);
+		  double gap = columnGap[kcol]*value2;
+		  bool doDown = (rowLo2 -gap > 0.0);
+		  if (doDown&& (markIt&(1+4))==0 ) {
+		    double dbound = colLower[kcol] + rowLo2/value2;
+		    if (intVar[kcol]) {
+		      markIt |= 1;
+		      newUpper = floor(dbound+primalTolerance_);
+		    } else {
+		      newUpper=dbound;
+		      if (newUpper-primalTolerance_<colLower[kcol]&&
+			  newUpper+primalTolerance_>=colLower[kcol]) {
+			newUpper=colLower[kcol];
+			markIt |= 1;
+			//markIt=3;
+		      } else {
+			// avoid problems - fix later ?
+			markIt=3;
+		      }
+		    }
+		    moveDown = newUpper-colUpper[kcol];
+		    if (!moveDown)
+		    continue;
+		    bool onList = ((markC[kcol]&3)!=0);
+		    if (nstackC<2*maxStack) {
+		      markC[kcol] = markIt;
+		    }
+		    if (moveDown&&nstackC<2*maxStack) {
+		      fixThis++;
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+			assert (saveU[nstackC]>saveL[nstackC]);
+			assert (nstackC<nCols);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newUpper<colsol[kcol]) {
+			if (djs[kcol]>0.0) {
+			  /* should be infeasible */
+			  assert (colLower[kcol]>newUpper+primalTolerance_);
+			} else {
+			  objVal += moveDown*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol])
+			newUpper = CoinMin(colUpper[kcol],floor(newUpper+1.0e-4));
+		      colUpper[kcol]=newUpper;
+		      columnGap[kcol] = newUpper-colLower[kcol]-primalTolerance_;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      markC[kcol] &= ~12;
+		      if (colUpper[kcol]>1.0e10)
+			markC[kcol] |= 8;
+		      if (colLower[kcol]<-1.0e10)
+			markC[kcol] |= 4;
+		      /* update immediately */
+		      for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			int krow = row[jj];
+			double value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+			}
+			/* could check immediately if violation */
+			/* down */
+			if (value<0.0) {
+			  /* up does not change - down does */
+			  if (minR[krow]>-1.0e10)
+			    minR[krow] += value*moveDown;
+			  if (krow==irow)
+			    rowUp2 = rowUp-minR[irow];
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+			  if (maxR[krow]<1.0e10)
+			    maxR[krow] += value*moveDown;
+			  if (krow==irow)
+			    rowLo2 = rowLo-maxR[irow];
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (colLower[kcol]>colUpper[kcol]+primalTolerance_) {
+		      notFeasible=1;;
+		      k=columnStart[jcol]+columnLength[jcol];
+		      istackC=nstackC+1;
+		      break;
+		    }
+		  }
+		}
+	      } // end big loop rStart->rPos
+	    }
+	    rStart = rEnd;
+	    rEnd = rowStart[irow+1];
+	    if (doRowUpP&&doRowLoP) {
+	      //doRowUpP=doRowLoP=false;
+	      // Start pos values loop
+	      for (int kk =rStart;kk<rEnd;kk++) {
+		int kcol=column[kk];
+		int markIt=markC[kcol];
+		if ((markIt&3)!=3) {
+		  double value2=rowElements[kk];
+		  assert (value2 > 0.0);
+		  /* positive element */
+		  double gap = columnGap[kcol]*value2;
+		  bool doDown = (rowLo2 + gap > 0.0);
+		  bool doUp = (rowUp2 - gap < 0.0);
+		  if (doDown||doUp) {
+		    double moveUp=0.0;
+		    double moveDown=0.0;
+		    double newUpper=-1.0;
+		    double newLower=1.0;
+		    if (doDown&&(markIt&(2+8))==0) {
+		      double dbound = colUpper[kcol] + rowLo2/value2;
+		      if (intVar[kcol]) {
+			markIt |= 2;
+			newLower = ceil(dbound-primalTolerance_);
+		      } else {
+			newLower=dbound;
+			if (newLower+primalTolerance_>colUpper[kcol]&&
+			    newLower-primalTolerance_<=colUpper[kcol]) {
+			  newLower=colUpper[kcol];
+			  markIt |= 2;
+			  //markIt=3;
+			} else {
+			  // avoid problems - fix later ?
+			  markIt=3;
+			}
+		      }
+		      moveUp = newLower-colLower[kcol];
+		    }
+		    if (doUp&&(markIt&(1+4))==0) {
+		      double dbound = colLower[kcol] + rowUp2/value2;
+		      if (intVar[kcol]) {
+			markIt |= 1;
+			newUpper = floor(dbound+primalTolerance_);
+		      } else {
+			newUpper=dbound;
+			if (newUpper-primalTolerance_<colLower[kcol]&&
+			    newUpper+primalTolerance_>=colLower[kcol]) {
+			  newUpper=colLower[kcol];
+			  markIt |= 1;
+			  //markIt=3;
+			} else {
+			  // avoid problems - fix later ?
+			  markIt=3;
+			}
+		      }
+		      moveDown = newUpper-colUpper[kcol];
+		    }
+		    if (!moveUp&&!moveDown)
+		      continue;
+		    bool onList = ((markC[kcol]&3)!=0);
+		    if (nstackC<2*maxStack) {
+		      markC[kcol] = markIt;
+		    }
+		    if (moveUp&&nstackC<2*maxStack) {
+		      fixThis++;
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+			assert (saveU[nstackC]>saveL[nstackC]);
+			assert (nstackC<nCols);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newLower>colsol[kcol]) {
+			if (djs[kcol]<0.0) {
+			  /* should be infeasible */
+			  assert (newLower>colUpper[kcol]+primalTolerance_);
+			} else {
+			  objVal += moveUp*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol]) 
+			newLower = CoinMax(colLower[kcol],ceil(newLower-1.0e-4));
+		      colLower[kcol]=newLower;
+		      columnGap[kcol] = colUpper[kcol]-newLower-primalTolerance_;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      markC[kcol] &= ~12;
+		      if (colUpper[kcol]>1.0e10)
+			markC[kcol] |= 8;
+		      if (colLower[kcol]<-1.0e10)
+			markC[kcol] |= 4;
+		      /* update immediately */
+		      for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			int krow = row[jj];
+			double value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+			}
+			/* could check immediately if violation */
+			/* up */
+			if (value>0.0) {
+			  /* up does not change - down does */
+			  if (minR[krow]>-1.0e10)
+			    minR[krow] += value*moveUp;
+			  if (krow==irow)
+			    rowUp2 = rowUp-minR[irow];
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+			  if (maxR[krow]<1.0e10)
+			    maxR[krow] += value*moveUp;
+			  if (krow==irow)
+			    rowLo2 = rowLo-maxR[irow];
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (moveDown&&nstackC<2*maxStack) {
+		      fixThis++;
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+			assert (saveU[nstackC]>saveL[nstackC]);
+			assert (nstackC<nCols);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newUpper<colsol[kcol]) {
+			if (djs[kcol]>0.0) {
+			  /* should be infeasible */
+			  assert (colLower[kcol]>newUpper+primalTolerance_);
+			} else {
+			  objVal += moveDown*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol])
+			newUpper = CoinMin(colUpper[kcol],floor(newUpper+1.0e-4));
+		      colUpper[kcol]=newUpper;
+		      columnGap[kcol] = newUpper-colLower[kcol]-primalTolerance_;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      markC[kcol] &= ~12;
+		      if (colUpper[kcol]>1.0e10)
+			markC[kcol] |= 8;
+		      if (colLower[kcol]<-1.0e10)
+			markC[kcol] |= 4;
+		      /* update immediately */
+		      for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			int krow = row[jj];
+			double value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+			}
+			/* could check immediately if violation */
+			/* down */
+			if (value<0.0) {
+			  /* up does not change - down does */
+			  if (minR[krow]>-1.0e10)
+			    minR[krow] += value*moveDown;
+			  if (krow==irow)
+			    rowUp2 = rowUp-minR[irow];
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+			  if (maxR[krow]<1.0e10)
+			    maxR[krow] += value*moveDown;
+			  if (krow==irow)
+			    rowLo2 = rowLo-maxR[irow];
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (colLower[kcol]>colUpper[kcol]+primalTolerance_) {
+		      notFeasible=1;;
+		      k=columnStart[jcol]+columnLength[jcol];
+		      istackC=nstackC+1;
+		      break;
+		    }
+		  }
+		}
+	      } // end big loop rPos->rEnd
+	    } else if (doRowUpP) {
+	      // Start pos values loop
+	      for (int kk =rStart;kk<rEnd;kk++) {
+		int kcol =column[kk];
+		int markIt=markC[kcol];
+		if ((markIt&3)!=3) {
+		  double value2=rowElements[kk];
+		  assert (value2 > 0.0);
+		  /* positive element */
+		  double gap = columnGap[kcol]*value2;
+		  bool doUp = (rowUp2 - gap < 0.0);
+		  if (doUp&&(markIt&(1+4))==0) {
+		    double newUpper=-1.0;
+		    double dbound = colLower[kcol] + rowUp2/value2;
+		    if (intVar[kcol]) {
+		      markIt |= 1;
+		      newUpper = floor(dbound+primalTolerance_);
+		    } else {
+		      newUpper=dbound;
+		      if (newUpper-primalTolerance_<colLower[kcol]&&
+			  newUpper+primalTolerance_>=colLower[kcol]) {
+			newUpper=colLower[kcol];
+			markIt |= 1;
+			//markIt=3;
+		      } else {
+			// avoid problems - fix later ?
+			markIt=3;
+		      }
+		    }
+		    double moveDown = newUpper-colUpper[kcol];
+		    if (!moveDown)
+		      continue;
+		    bool onList = ((markC[kcol]&3)!=0);
+		    if (nstackC<2*maxStack) {
+		      markC[kcol] = markIt;
+		    }
+		    if (nstackC<2*maxStack) {
+		      fixThis++;
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+			assert (saveU[nstackC]>saveL[nstackC]);
+			assert (nstackC<nCols);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newUpper<colsol[kcol]) {
+			if (djs[kcol]>0.0) {
+			  /* should be infeasible */
+			  assert (colLower[kcol]>newUpper+primalTolerance_);
+			} else {
+			  objVal += moveDown*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol])
+			newUpper = CoinMin(colUpper[kcol],floor(newUpper+1.0e-4));
+		      colUpper[kcol]=newUpper;
+		      columnGap[kcol] = newUpper-colLower[kcol]-primalTolerance_;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      markC[kcol] &= ~12;
+		      if (colUpper[kcol]>1.0e10)
+			markC[kcol] |= 8;
+		      if (colLower[kcol]<-1.0e10)
+			markC[kcol] |= 4;
+		      /* update immediately */
+		      for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			int krow = row[jj];
+			double value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+			}
+			/* could check immediately if violation */
+			/* down */
+			if (value<0.0) {
+			  /* up does not change - down does */
+			  if (minR[krow]>-1.0e10)
+			    minR[krow] += value*moveDown;
+			  if (krow==irow)
+			    rowUp2 = rowUp-minR[irow];
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+			  if (maxR[krow]<1.0e10)
+			    maxR[krow] += value*moveDown;
+			  if (krow==irow)
+			    rowLo2 = rowLo-maxR[irow];
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (colLower[kcol]>colUpper[kcol]+primalTolerance_) {
+		      notFeasible=1;;
+		      k=columnStart[jcol]+columnLength[jcol];
+		      istackC=nstackC+1;
+		      break;
+		    }
+		  }
+		}
+	      } // end big loop rPos->rEnd
+	    } else if (doRowLoP) {
+	      // Start pos values loop
+	      for (int kk =rStart;kk<rEnd;kk++) {
+		int kcol =column[kk];
+		if ((markC[kcol]&3)!=3) {
+		  double value2=rowElements[kk];
+		  int markIt=markC[kcol];
+		  assert (value2 > 0.0);
+		  /* positive element */
+		  double gap = columnGap[kcol]*value2;
+		  bool doDown = (rowLo2 +gap > 0.0);
+		  if (doDown&&(markIt&(2+8))==0) {
+		    double newLower=1.0;
+		    double dbound = colUpper[kcol] + rowLo2/value2;
+		    if (intVar[kcol]) {
+		      markIt |= 2;
+		      newLower = ceil(dbound-primalTolerance_);
+		    } else {
+		      newLower=dbound;
+		      if (newLower+primalTolerance_>colUpper[kcol]&&
+			  newLower-primalTolerance_<=colUpper[kcol]) {
+			newLower=colUpper[kcol];
+			markIt |= 2;
+			//markIt=3;
+		      } else {
+			// avoid problems - fix later ?
+			markIt=3;
+			}
+		    }
+		    double moveUp = newLower-colLower[kcol];
+		    if (!moveUp)
+		      continue;
+		    bool onList = ((markC[kcol]&3)!=0);
+		    if (nstackC<2*maxStack) {
+		      markC[kcol] = markIt;
+		    }
+		    if (nstackC<2*maxStack) {
+		      fixThis++;
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+			assert (saveU[nstackC]>saveL[nstackC]);
+			assert (nstackC<nCols);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newLower>colsol[kcol]) {
+			if (djs[kcol]<0.0) {
+			  /* should be infeasible */
+			  assert (newLower>colUpper[kcol]+primalTolerance_);
+			} else {
+			  objVal += moveUp*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol]) 
+			newLower = CoinMax(colLower[kcol],ceil(newLower-1.0e-4));
+		      colLower[kcol]=newLower;
+		      columnGap[kcol] = colUpper[kcol]-newLower-primalTolerance_;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      markC[kcol] &= ~12;
+		      if (colUpper[kcol]>1.0e10)
+			markC[kcol] |= 8;
+		      if (colLower[kcol]<-1.0e10)
+			markC[kcol] |= 4;
+		      /* update immediately */
+		      for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			int krow = row[jj];
+			double value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+			}
+			/* could check immediately if violation */
+			/* up */
+			if (value>0.0) {
+			  /* up does not change - down does */
+			  if (minR[krow]>-1.0e10)
+			    minR[krow] += value*moveUp;
+			  if (krow==irow)
+			    rowUp2 = rowUp-minR[irow];
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+			  if (maxR[krow]<1.0e10)
+			    maxR[krow] += value*moveUp;
+			  if (krow==irow)
+			    rowLo2 = rowLo-maxR[irow];
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    columnGap[kcol] = -1.0e50;
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (colLower[kcol]>colUpper[kcol]+primalTolerance_) {
+		      notFeasible=1;;
+		      k=columnStart[jcol]+columnLength[jcol];
+		      istackC=nstackC+1;
+		      break;
+		    }
+		  }
+		}
+	      } // end big loop rPos->rEnd
+	    }
+          }
+          istackC++;
+        }
+        if (!notFeasible) {
+          if (objVal<=cutoff) {
+            feasible |= feas[iway];
+          } else {
+#ifdef PRINT_DEBUG
+            printf("not feasible on dj\n");
+#endif
+            notFeasible=1;
+            if (iway==1&&feasible==0) {
+              /* not feasible at all */
+              ninfeas=1;
+              j=nCols-1;
+              break;
+            }
+          }
+	  if (!notFeasible&&saveFixingInfo) {
+	    // save fixing info
+	    assert (j==stackC[0]);
+	    int toValue = (way[iway]==1) ? -1 : +1;
+	    for (istackC=1;istackC<nstackC;istackC++) {
+	      int icol=stackC[istackC];
+	      // for now back to just 0-1
+	      if (colUpper[icol]-colLower[icol]<1.0e-12&&!saveL[istackC]&&saveU[istackC]==1.0) {
+		assert(saveL[istackC]==colLower[icol]||
+		       saveU[istackC]==colUpper[icol]);
+		saveFixingInfo = info->fixes(j,toValue,
+					     icol,colLower[icol]==saveL[istackC]);
+	      }
+	    }
+	  }
+        } else if (iway==1&&feasible==0) {
+          /* not feasible at all */
+          ninfeas=1;
+          j=nCols-1;
+          iLook=numberThisTime_;
+          ipass=maxPass;
+          break;
+        }
+        if (notFeasible)
+          goingToTrueBound=0;
+        if (iway==2||(iway==1&&feasible==2)) {
+          /* keep */
+          iway=3;
+          nfixed++;
+          OsiColCut cc;
+          int nTot=0,nFix=0,nInt=0;
+          bool ifCut=false;
+          for (istackC=0;istackC<nstackC;istackC++) {
+            int icol=stackC[istackC];
+            if (intVar[icol]) {
+              if (colUpper[icol]<currentColUpper[icol]-1.0e-4) {
+                element[nFix]=colUpper[icol];
+                index[nFix++]=icol;
+                nInt++;
+                if (colsol[icol]>colUpper[icol]+primalTolerance_) {
+                  ifCut=true;
+                  anyColumnCuts=true;
+                }
+              }
+            }
+          }
+          if (nFix) {
+            nTot=nFix;
+            cc.setUbs(nFix,index,element);
+            nFix=0;
+          }
+          for (istackC=0;istackC<nstackC;istackC++) {
+            int icol=stackC[istackC];
+            if (intVar[icol]) {
+              if (colLower[icol]>currentColLower[icol]+1.0e-4) {
+                element[nFix]=colLower[icol];
+                index[nFix++]=icol;
+                nInt++;
+                if (colsol[icol]<colLower[icol]-primalTolerance_) {
+                  ifCut=true;
+                  anyColumnCuts=true;
+                }
+              }
+            }
+          }
+          if (nFix) {
+            nTot+=nFix;
+            cc.setLbs(nFix,index,element);
+          }
+          // could tighten continuous as well
+          if (nInt) {
+            if (ifCut) {
+              cc.setEffectiveness(100.0);
+            } else {
+              cc.setEffectiveness(1.0e-5);
+            }
+#ifdef CGL_DEBUG
+            checkBounds(debugger,cc);
+#endif
+            cs.insert(cc);
+          }
+          for (istackC=0;istackC<nstackC;istackC++) {
+            int icol=stackC[istackC];
+            if (colUpper[icol]-colLower[icol]>primalTolerance_) {
+              markC[icol]&= ~3;
+            } else {
+              markC[icol]=3;
+            }
+          }
+          for (istackR=0;istackR<nstackR;istackR++) {
+            int irow=stackR[istackR];
+            markR[irow]=-1;
+          }
+        } else {
+          /* is it worth seeing if can increase coefficients
+             or maybe better see if it is a cut */
+          if (iway==0) {
+            nstackC0=CoinMin(nstackC,maxStack);
+            double solMove = saveSolval-down;
+            double boundChange;
+            if (notFeasible) {
+              nstackC0=0;
+            } else {
+              for (istackC=0;istackC<nstackC0;istackC++) {
+                int icol=stackC[istackC];
+                stackC0[istackC]=icol;
+                lo0[istackC]=colLower[icol];
+                up0[istackC]=colUpper[icol];
+              }
+            }
+            /* restore all */
+            assert (iway==0);
+            for (istackC=nstackC-1;istackC>=0;istackC--) {
+              int icol=stackC[istackC];
+              double oldU=saveU[istackC];
+              double oldL=saveL[istackC];
+              if(goingToTrueBound==2&&istackC&&!justReplace) {
+                // upper disaggregation cut would be
+                // xval < upper + (old_upper-upper) (jval-down)
+                boundChange = oldU-colUpper[icol];
+                if (boundChange>0.0&&oldU<1.0e10&&
+                    (colsol[icol]>colUpper[icol]
+                     + boundChange*solMove+primalTolerance_)) {
+                  // create cut
+                  OsiRowCut rc;
+                  rc.setLb(-COIN_DBL_MAX);
+                  rc.setUb(colUpper[icol]-down*boundChange);
+                  index[0]=icol;
+                  element[0]=1.0;
+                  index[1]=j;
+                  element[1]= - boundChange;
+                  // effectiveness is how far j moves
+                  double newSol = (colsol[icol]-colUpper[icol])/
+                    boundChange;
+                  assert(newSol>solMove);
+                  rc.setEffectiveness(newSol-solMove);
+                  if (rc.effectiveness()>disaggEffectiveness) {
+                    rc.setRow(2,index,element,false);
+#ifdef CGL_DEBUG
+                    if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                    rowCut.addCutIfNotDuplicate(rc);
+                  }
+                }
+                // lower disaggregation cut would be
+                // xval > lower + (old_lower-lower) (jval-down)
+                boundChange = oldL-colLower[icol];
+                if (boundChange<0.0&&oldL>-1.0e10&&
+                    (colsol[icol]<colLower[icol]
+                     + boundChange*solMove-primalTolerance_)) {
+                  // create cut
+                  OsiRowCut rc;
+                  rc.setLb(colLower[icol]-down*boundChange);
+                  rc.setUb(COIN_DBL_MAX);
+                  index[0]=icol;
+                  element[0]=1.0;
+                  index[1]=j;
+                  element[1]=- boundChange;
+                  // effectiveness is how far j moves
+                  double newSol = (colsol[icol]-colLower[icol])/
+                    boundChange;
+                  assert(newSol>solMove);
+                  rc.setEffectiveness(newSol-solMove);
+                  if (rc.effectiveness()>disaggEffectiveness) {
+                    rc.setRow(2,index,element,false);
+#ifdef CGL_DEBUG
+                    if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                    rowCut.addCutIfNotDuplicate(rc);
+#if 0
+                    printf("%d original bounds %g, %g new Lo %g sol= %g int %d sol= %g\n",icol,oldL,oldU,colLower[icol],colsol[icol], j, colsol[j]);
+                    printf("-1.0 * x(%d) + %g * y(%d) <= %g\n",
+                           icol,boundChange,j,rc.ub());
+#endif
+                  }
+                }
+              }
+              colUpper[icol]=oldU;
+              colLower[icol]=oldL;
+	      columnGap[icol] = oldU-oldL-primalTolerance_;
+              markC[icol]= 0;
+	      if (oldU>1.0e10)
+		markC[icol] |= 8;
+	      if (oldL<-1.0e10)
+		markC[icol] |= 4;
+            }
+            for (istackR=0;istackR<nstackR;istackR++) {
+              int irow=stackR[istackR];
+              // switch off strengthening if not wanted
+              if ((rowCuts&2)!=0&&goingToTrueBound) {
+                bool ifCut=anyColumnCuts;
+                double gap = rowUpper[irow]-maxR[irow];
+                double sum=0.0;
+                if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+                  // see if the strengthened row is a cut
+                  // also see if singletons can go to good objective
+		  // Taken out as should be found elsewhere
+		  // and has to be original column length
+#ifdef MOVE_SINGLETONS
+                  bool moveSingletons=true;
+#endif
+                  for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                       kk++) {
+                    int iColumn = column[kk];
+                    double value = rowElements[kk];
+                    sum += value*colsol[iColumn];
+#ifdef MOVE_SINGLETONS
+                    if (moveSingletons&&j!=iColumn) {
+                      if (colUpper[iColumn]>colLower[iColumn]) {
+                        if (columnLength2[iColumn]!=1) {
+                          moveSingletons=false;
+                        }
+                      }
+                    }
+#endif
+                  }
+#ifdef MOVE_SINGLETONS
+                  if (moveSingletons) {
+                    // can fix any with good costs
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+                      int iColumn = column[kk];
+                      if (j!=iColumn) {
+                        if (colUpper[iColumn]>colLower[iColumn]) {
+                          if (columnLength2[iColumn]==1) {
+                            double value = rowElements[kk];
+                            if (direction*objective[iColumn]*value<0.0&&!(markC[iColumn]&3)) {
+                              // Fix
+                              if (nstackC0+1<maxStack) {
+                                stackC0[nstackC0]=iColumn;
+                                if (value>0.0) {
+                                  lo0[nstackC0]=colUpper[iColumn];
+                                  up0[nstackC0]=colUpper[iColumn];
+                                } else {
+                                  lo0[nstackC0]=colLower[iColumn];
+                                  up0[nstackC0]=colLower[iColumn];
+                                }
+                                nstackC0++;
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+#endif
+                  if (sum-gap*colsol[j]>maxR[irow]+primalTolerance_||(info->strengthenRow&&rowLower[irow]<-1.0e20)) {
+                    // can be a cut
+                    // subtract gap from upper and integer coefficient
+                    // saveU and saveL spare
+                    int * index = reinterpret_cast<int *>(saveL);
+                    double * element = saveU;
+                    int n=0;
+                    bool coefficientExists=false;
+		    double sum2=0.0;
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+		      int kColumn = column[kk];
+		      double el = rowElements[kk];
+                      if (kColumn!=j) {
+                        index[n]=kColumn;
+                        element[n++]=el;
+                      } else {
+                        el=el-gap;
+                        if (fabs(el)>1.0e-12) {
+                          index[n]=kColumn;
+                          element[n++]=el;
+                        }
+                        coefficientExists=true;
+                      }
+		      sum2 += colsol[kColumn]*el;
+                    }
+                    if (!coefficientExists) {
+                      index[n]=j;
+                      element[n++]=-gap;
+		      sum2 -= colsol[j]*gap;
+                    }
+                    OsiRowCut rc;
+                    rc.setLb(-COIN_DBL_MAX);
+		    double ub =rowUpper[irow]-gap*(colLower[j]+1.0);
+                    rc.setUb(ub);
+                    double effectiveness=sum2-ub;
+                    effectiveness = CoinMax(effectiveness,
+					    (sum-gap*colsol[j]
+					     -maxR[irow])/gap);
+		    if (!coefficientExists)
+		      effectiveness=CoinMax(1.0e-7,
+					    effectiveness);
+                    rc.setEffectiveness(effectiveness);
+                    //rc.setEffectiveness((sum-gap*colsol[j]-maxR[irow])/gap);
+                    if (rc.effectiveness()>needEffectiveness) {
+                      rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+                      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                      // If strengthenRow point to row
+                      //if(info->strengthenRow)
+                      //printf("a point to row %d\n",irow);
+		      //#define STRENGTHEN_PRINT
+#ifdef STRENGTHEN_PRINT
+		      if (canReplace&&rowLower[irow]<-1.0e20) {
+			printf("1Cut %g <= ",rc.lb());
+			int k;
+			//printf("original row %d - %g <= <= %g - j = %d\n",iow,rowLower[irow],rowUpper[irow],j);
+			//for (int kk=rowStart[irow];kk<rowStart[irow+1];kk++) 
+			//printf("(%d,%g) ",column[kk],rowElements[kk]);
+			//printf("\n");
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow+1];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+		      int realRow = (canReplace&&rowLower[irow]<-1.0e20) ? irow : -1;
+		      if (realRows&&realRow>=0)
+			realRow=realRows[realRow];
+		      if (!justReplace) {
+			rowCut.addCutIfNotDuplicate(rc,realRow);
+		      } else if (realRow>=0) {
+			double effectiveness=0.0;
+			for (int i=0;i<n;i++)
+			  effectiveness+=fabs(element[i]);
+			if (!info->strengthenRow[realRow]||info->strengthenRow[realRow]->effectiveness()>effectiveness) {
+			  delete info->strengthenRow[realRow];
+			  rc.setEffectiveness(effectiveness);
+			  info->strengthenRow[realRow]=rc.clone();
+			}
+		      }
+                    }
+                  }
+                }
+                gap = minR[irow]-rowLower[irow];
+                if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+                  // see if the strengthened row is a cut
+                  sum =0.0;
+                  // also see if singletons can go to good objective
+#ifdef MOVE_SINGLETONS
+                  bool moveSingletons=true;
+#endif
+                  for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                       kk++) {
+                    int iColumn = column[kk];
+                    double value = rowElements[kk];
+                    sum += value*colsol[iColumn];
+#ifdef MOVE_SINGLETONS
+                    if (moveSingletons&&j!=iColumn) {
+                      if (colUpper[iColumn]>colLower[iColumn]) {
+                        if (columnLength2[iColumn]!=1) {
+                          moveSingletons=false;
+                        }
+                      }
+                    }
+#endif
+                  }
+#ifdef MOVE_SINGLETONS
+                  if (moveSingletons) {
+                    // can fix any with good costs
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+                      int iColumn = column[kk];
+                      if (j!=iColumn) {
+                        if (colUpper[iColumn]>colLower[iColumn]) {
+                          if (columnLength2[iColumn]==1) {
+                            double value = rowElements[kk];
+                            if (direction*objective[iColumn]*value>0.0&&!(markC[iColumn]&3)) {
+                              // Fix
+                              if (nstackC0+1<maxStack) {
+                                stackC0[nstackC0]=iColumn;
+                                if (value<0.0) {
+                                  lo0[nstackC0]=colUpper[iColumn];
+                                  up0[nstackC0]=colUpper[iColumn];
+                                } else {
+                                  lo0[nstackC0]=colLower[iColumn];
+                                  up0[nstackC0]=colLower[iColumn];
+                                }
+                                nstackC0++;
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+#endif
+                  if (sum+gap*colsol[j]<minR[irow]-primalTolerance_||(info->strengthenRow&&rowUpper[irow]>1.0e20)) {
+                    // can be a cut
+                    // add gap to lower and integer coefficient
+                    // saveU and saveL spare
+                    int * index = reinterpret_cast<int *>(saveL);
+                    double * element = saveU;
+                    int n=0;
+                    bool coefficientExists=false;
+		    double sum2=0.0;
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+		      int kColumn = column[kk];
+		      double el = rowElements[kk];
+                      if (kColumn!=j) {
+                        index[n]=kColumn;
+                        element[n++]=el;
+                      } else {
+                        el=el+gap;
+                        if (fabs(el)>1.0e-12) {
+                          index[n]=kColumn;
+                          element[n++]=el;
+                        }
+                        coefficientExists=true;
+                      }
+		      sum2 += colsol[kColumn]*el;
+                    }
+                    if (!coefficientExists) {
+                      index[n]=j;
+                      element[n++]=gap;
+		      sum2 += colsol[j]*gap;
+                    }
+                    OsiRowCut rc;
+		    double lb = rowLower[irow]+gap*(colLower[j]+1.0);
+                    rc.setLb(lb);
+                    rc.setUb(COIN_DBL_MAX);
+                    // effectiveness
+                    double effectiveness=lb-sum2;
+                    effectiveness = CoinMax(effectiveness,
+					    (minR[irow]-
+					     sum-gap*colsol[j])/gap);
+		    if (!coefficientExists)
+		      effectiveness=CoinMax(1.0e-7,
+					    effectiveness);
+                    rc.setEffectiveness(effectiveness);
+                    if (rc.effectiveness()>needEffectiveness) {
+                      rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+                      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                      //if(info->strengthenRow)
+                      //printf("b point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      if (canReplace&&rowUpper[irow]>1.0e20) {
+			printf("2Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow+1];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+		      int realRow = (canReplace&&rowUpper[irow]>1.0e20) ? irow : -1;
+		      if (realRows&&realRow>=0)
+			realRow=realRows[realRow];
+		      if (!justReplace) {
+			rowCut.addCutIfNotDuplicate(rc,realRow);
+		      } else if (realRow>=0) {
+			double effectiveness=0.0;
+			for (int i=0;i<n;i++)
+			  effectiveness+=fabs(element[i]);
+			if (!info->strengthenRow[realRow]||info->strengthenRow[realRow]->effectiveness()>effectiveness) {
+			  delete info->strengthenRow[realRow];
+			  rc.setEffectiveness(effectiveness);
+			  info->strengthenRow[realRow]=rc.clone();
+			}
+		      }
+                    }
+                  }
+                }
+              }
+              minR[irow]=saveMin[istackR];
+              maxR[irow]=saveMax[istackR];
+              markR[irow]=-1;
+            }
+          } else {
+            if (iway==1&&feasible==3) {
+              iway=3;
+#ifdef MOVE_SINGLETONS
+              // look for singletons that can move (just at root)
+              if ((rowCuts&2)!=0&&goingToTrueBound&&info->strengthenRow) {
+                for (istackR=0;istackR<nstackR;istackR++) {
+                  int irow=stackR[istackR];
+                  double gap = rowUpper[irow]-maxR[irow];
+                  if (gap>primalTolerance_) {
+                    // also see if singletons can go to good objective
+                    bool moveSingletons=true;
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+                      int iColumn = column[kk];
+                      if (moveSingletons&&j!=iColumn) {
+                        if (colUpper[iColumn]>colLower[iColumn]) {
+                          if (columnLength2[iColumn]!=1) {
+                            moveSingletons=false;
+                          }
+                        }
+                      }
+                    }
+                    if (moveSingletons) {
+                      // can fix any with good costs
+                      for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                           kk++) {
+                        int iColumn = column[kk];
+                        if (j!=iColumn) {
+                          if (colUpper[iColumn]>colLower[iColumn]) {
+                            if (columnLength2[iColumn]==1) {
+                              double value = rowElements[kk];
+                              if (direction*objective[iColumn]*value<0.0&&!(markC[iColumn]&3)) {
+                                // Fix
+                                stackC[nstackC]=iColumn;
+                                saveL[nstackC]=colLower[iColumn];
+                                saveU[nstackC]=colUpper[iColumn];
+                                assert (saveU[nstackC]>saveL[nstackC]);
+                                if (value>0.0) {
+                                  colLower[iColumn]=colUpper[iColumn];
+                                } else {
+                                  colUpper[iColumn]=colLower[iColumn];
+                                }
+				columnGap[iColumn] = -primalTolerance_;
+                                assert (nstackC<nCols);
+                                nstackC++;
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                  gap = minR[irow]-rowLower[irow];
+                  if (gap>primalTolerance_) {
+                    // also see if singletons can go to good objective
+                    bool moveSingletons=true;
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+                      int iColumn = column[kk];
+                      if (moveSingletons&&j!=iColumn) {
+                        if (colUpper[iColumn]>colLower[iColumn]) {
+                          if (columnLength2[iColumn]!=1) {
+                            moveSingletons=false;
+                          }
+                        }
+                      }
+                    }
+                    if (moveSingletons) {
+                      // can fix any with good costs
+                      for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+                        int iColumn = column[kk];
+                        if (j!=iColumn) {
+                          if (colUpper[iColumn]>colLower[iColumn]) {
+                            if (columnLength2[iColumn]==1) {
+                              double value = rowElements[kk];
+                              if (direction*objective[iColumn]*value>0.0&&!(markC[iColumn]&3)) {
+                                // Fix
+                                stackC[nstackC]=iColumn;
+                                saveL[nstackC]=colLower[iColumn];
+                                saveU[nstackC]=colUpper[iColumn];
+                                assert (saveU[nstackC]>saveL[nstackC]);
+                                if (value<0.0) {
+                                  colLower[iColumn]=colUpper[iColumn];
+                                } else {
+                                  colUpper[iColumn]=colLower[iColumn];
+                                }
+				columnGap[iColumn] = -primalTolerance_;
+                                assert (nstackC<nCols);
+                                nstackC++;
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+#endif
+              /* point back to stack */
+              for (istackC=nstackC-1;istackC>=0;istackC--) {
+                int icol=stackC[istackC];
+                markC[icol]=istackC+1000;
+              }
+              OsiColCut cc;
+              int nTot=0,nFix=0,nInt=0;
+              bool ifCut=false;
+              for (istackC=1;istackC<nstackC0;istackC++) {
+                int icol=stackC0[istackC];
+                int istackC1=markC[icol]-1000;
+                if (istackC1>=0) {
+                  if (CoinMin(lo0[istackC],colLower[icol])>saveL[istackC1]+1.0e-4) {
+                    saveL[istackC1]=CoinMin(lo0[istackC],colLower[icol]);
+                    if (intVar[icol]/*||!info->inTree*/) {
+                      element[nFix]=saveL[istackC1];
+                      index[nFix++]=icol;
+                      nInt++;
+                      if (colsol[icol]<saveL[istackC1]-primalTolerance_)
+                        ifCut=true;
+                    }
+                    nfixed++;
+                  } 
+                }
+              }
+              if (nFix) {
+                nTot=nFix;
+                cc.setLbs(nFix,index,element);
+                nFix=0;
+              }
+              for (istackC=1;istackC<nstackC0;istackC++) {
+                int icol=stackC0[istackC];
+                int istackC1=markC[icol]-1000;
+                if (istackC1>=0) {
+                  if (CoinMax(up0[istackC],colUpper[icol])<saveU[istackC1]-1.0e-4) {
+                    saveU[istackC1]=CoinMax(up0[istackC],colUpper[icol]);
+                    if (intVar[icol]/*||!info->inTree*/) {
+                      element[nFix]=saveU[istackC1];
+                      index[nFix++]=icol;
+                      nInt++;
+                      if (colsol[icol]>saveU[istackC1]+primalTolerance_)
+                        ifCut=true;
+                    }
+                    nfixed++;
+                  } else if (!info->inTree&&saveL[0]==0.0&&saveU[0]==1.0) {
+                    // See if can do two cut
+                    double upperWhenDown = up0[istackC];
+                    double lowerWhenDown = lo0[istackC];
+                    double upperWhenUp = colUpper[icol];
+                    double lowerWhenUp = colLower[icol];
+                    double upperOriginal = saveU[istackC1];
+                    double lowerOriginal = saveL[istackC1];
+                    if (upperWhenDown<lowerOriginal+1.0e-12&&lowerWhenUp>upperOriginal-1.0e-12) {
+                      OsiRowCut rc;
+                      rc.setLb(lowerOriginal);
+                      rc.setUb(lowerOriginal);
+                      rc.setEffectiveness(1.0e-5);
+                      int index[2];
+                      double element[2];
+                      index[0]=j;
+                      index[1]=icol;
+                      element[0]=-(upperOriginal-lowerOriginal);
+		      // If zero then - must have been fixed without noticing!
+		      if (fabs(element[0])>1.0e-8) {
+			element[1]=1.0;
+			rc.setRow(2,index,element,false);
+			cs.insert(rc);
+		      }
+                    } else if (upperWhenUp<lowerOriginal+1.0e-12&&lowerWhenDown>upperOriginal-1.0e-12) {
+                      OsiRowCut rc;
+                      rc.setLb(upperOriginal);
+                      rc.setUb(upperOriginal);
+                      rc.setEffectiveness(1.0e-5);
+                      int index[2];
+                      double element[2];
+                      index[0]=j;
+                      index[1]=icol;
+                      element[0]=upperOriginal-lowerOriginal;
+                      element[1]=1.0;
+                      rc.setRow(2,index,element,false);
+                      cs.insert(rc);
+                    } 
+                  }
+                }
+              }
+              if (nFix) {
+                nTot+=nFix;
+                cc.setUbs(nFix,index,element);
+              }
+              // could tighten continuous as well
+              if (nInt) {
+                if (ifCut) {
+                  cc.setEffectiveness(100.0);
+                } else {
+                  cc.setEffectiveness(1.0e-5);
+                }
+#ifdef CGL_DEBUG
+                checkBounds(debugger,cc);
+#endif
+                cs.insert(cc);
+              }
+            } else {
+              goingToTrueBound=0;
+            }
+            double solMove = up-saveSolval;
+            double boundChange;
+            /* restore all */
+            for (istackC=nstackC-1;istackC>=0;istackC--) {
+              int icol=stackC[istackC];
+              double oldU=saveU[istackC];
+              double oldL=saveL[istackC];
+              if(goingToTrueBound==2&&istackC&&!justReplace) {
+                // upper disaggregation cut would be
+                // xval < upper + (old_upper-upper) (up-jval)
+                boundChange = oldU-colUpper[icol];
+                if (boundChange>0.0&&oldU<1.0e10&&
+                    (colsol[icol]>colUpper[icol]
+                     + boundChange*solMove+primalTolerance_)) {
+                  // create cut
+                  OsiRowCut rc;
+                  rc.setLb(-COIN_DBL_MAX);
+                  rc.setUb(colUpper[icol]+up*boundChange);
+                  index[0]=icol;
+                  element[0]=1.0;
+                  index[1]=j;
+                  element[1]= + boundChange;
+                  // effectiveness is how far j moves
+                  double newSol = (colsol[icol]-colUpper[icol])/
+                    boundChange;
+                  assert(newSol>solMove);
+                  rc.setEffectiveness(newSol-solMove);
+                  if (rc.effectiveness()>disaggEffectiveness) {
+                    rc.setRow(2,index,element,false);
+#ifdef CGL_DEBUG
+                    if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                    rowCut.addCutIfNotDuplicate(rc);
+                  }
+                }
+                // lower disaggregation cut would be
+                // xval > lower + (old_lower-lower) (up-jval)
+                boundChange = oldL-colLower[icol];
+                if (boundChange<0.0&&oldL>-1.0e10&&
+                    (colsol[icol]<colLower[icol]
+                     + boundChange*solMove-primalTolerance_)) {
+                  // create cut
+                  OsiRowCut rc;
+                  rc.setLb(colLower[icol]+up*boundChange);
+                  rc.setUb(COIN_DBL_MAX);
+                  index[0]=icol;
+                  element[0]=1.0;
+                  index[1]=j;
+                  element[1]= + boundChange;
+                  // effectiveness is how far j moves
+                  double newSol = (colsol[icol]-colLower[icol])/
+                    boundChange;
+                  assert(newSol>solMove);
+                  rc.setEffectiveness(newSol-solMove);
+                  if (rc.effectiveness()>disaggEffectiveness) {
+                    rc.setRow(2,index,element,false);
+#ifdef CGL_DEBUG
+                    if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                    rowCut.addCutIfNotDuplicate(rc);
+                  }
+                }
+              }
+              colUpper[icol]=oldU;
+              colLower[icol]=oldL;
+	      columnGap[icol] = oldU-oldL-primalTolerance_;
+              if (oldU>oldL+1.0e-4) {
+                markC[icol]=0;
+		if (oldU>1.0e10)
+		  markC[icol] |= 8;
+		if (oldL<-1.0e10)
+		  markC[icol] |= 4;
+              } else {
+                markC[icol]=3;
+	      }
+            }
+            for (istackR=0;istackR<nstackR;istackR++) {
+              int irow=stackR[istackR];
+              // switch off strengthening if not wanted
+              if ((rowCuts&2)!=0&&goingToTrueBound) {
+		bool canReplace = info->strengthenRow&&(goingToTrueBound==2);
+                bool ifCut=anyColumnCuts;
+                double gap = rowUpper[irow]-maxR[irow];
+                double sum=0.0;
+                if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+                  // see if the strengthened row is a cut
+                  for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                       kk++) {
+                    sum += rowElements[kk]*colsol[column[kk]];
+                  }
+                  if (sum+gap*colsol[j]>rowUpper[irow]+primalTolerance_||(canReplace&&rowLower[irow]<-1.e20)) {
+                    // can be a cut
+                    // add gap to integer coefficient
+                    // saveU and saveL spare
+                    int * index = reinterpret_cast<int *>(saveL);
+                    double * element = saveU;
+                    int n=0;
+                    bool coefficientExists=false;
+		    double sum2=0.0;
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+		      int kColumn = column[kk];
+		      double el = rowElements[kk];
+                      if (kColumn!=j) {
+                        index[n]=kColumn;
+                        element[n++]=el;
+                      } else {
+                        el=el+gap;
+                        if (fabs(el)>1.0e-12) {
+                          index[n]=kColumn;
+                          element[n++]=el;
+                        }
+                        coefficientExists=true;
+                      }
+		      sum2 += colsol[kColumn]*el;
+                    }
+                    if (!coefficientExists) {
+                      index[n]=j;
+                      element[n++]=gap;
+		      sum2 += colsol[j]*gap;
+                    }
+                    OsiRowCut rc;
+                    rc.setLb(-COIN_DBL_MAX);
+		    double ub = rowUpper[irow]+gap*(colUpper[j]-1.0);
+                    rc.setUb(ub);
+                    // effectiveness
+                    double effectiveness=sum2-ub;
+                    effectiveness = CoinMax(effectiveness,
+					    (sum+gap*colsol[j]-
+					     rowUpper[irow])/gap);
+		    if (!coefficientExists)
+		      effectiveness=CoinMax(1.0e-7,
+					    effectiveness);
+                    rc.setEffectiveness(effectiveness);
+                    if (rc.effectiveness()>needEffectiveness) {
+                      rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+                      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                      //if(canReplace)
+                      //printf("c point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      if (canReplace&&rowLower[irow]<-1.0e20) {
+			printf("3Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow+1];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+		      int realRow = (canReplace&&rowLower[irow]<-1.0e20) ? irow : -1;
+		      if (realRows&&realRow>=0)
+			realRow=realRows[realRow];
+		      if (!justReplace) {
+			rowCut.addCutIfNotDuplicate(rc,realRow);
+		      } else if (realRow>=0) {
+			double effectiveness=0.0;
+			for (int i=0;i<n;i++)
+			  effectiveness+=fabs(element[i]);
+			if (!info->strengthenRow[realRow]||info->strengthenRow[realRow]->effectiveness()>effectiveness) {
+			  delete info->strengthenRow[realRow];
+			  rc.setEffectiveness(effectiveness);
+			  info->strengthenRow[realRow]=rc.clone();
+			}
+		      }
+                    }
+                  }
+                }
+                gap = minR[irow]-rowLower[irow];
+                if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+                  // see if the strengthened row is a cut
+                  if (!sum) {
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+                      sum += rowElements[kk]*colsol[column[kk]];
+                    }
+                  }
+                  if (sum-gap*colsol[j]<rowLower[irow]-primalTolerance_||(canReplace&&rowUpper[irow]>1.0e20)) {
+                    // can be a cut
+                    // subtract gap from integer coefficient
+                    // saveU and saveL spare
+                    int * index = reinterpret_cast<int *>(saveL);
+                    double * element = saveU;
+                    int n=0;
+                    bool coefficientExists=false;
+		    double sum2=0.0;
+                    for (int kk =rowStart[irow];kk<rowStart[irow+1];
+                         kk++) {
+		      int kColumn = column[kk];
+		      double el = rowElements[kk];
+                      if (kColumn!=j) {
+                        index[n]=kColumn;
+                        element[n++]=el;
+                      } else {
+                        el=el-gap;
+                        if (fabs(el)>1.0e-12) {
+                          index[n]=kColumn;
+                          element[n++]=el;
+                        }
+                        coefficientExists=true;
+                      }
+		      sum2 += colsol[kColumn]*el;
+                    }
+                    if (!coefficientExists) {
+                      index[n]=j;
+                      element[n++]=-gap;
+		      sum2 -= colsol[j]*gap;
+                    }
+                    OsiRowCut rc;
+                    double lb = rowLower[irow]-gap*(colUpper[j]-1);
+                    rc.setLb(lb);
+                    rc.setUb(COIN_DBL_MAX);
+		    double effectiveness=lb-sum2;
+                    effectiveness = CoinMax(effectiveness,
+					    (rowLower[irow]-
+					     sum+gap*colsol[j])/gap);
+		    if (!coefficientExists)
+		      effectiveness=CoinMax(1.0e-7,
+					    effectiveness);
+                    rc.setEffectiveness(effectiveness);
+                    if (rc.effectiveness()>needEffectiveness) {
+                      rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+                      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                      //if(canReplace)
+                      //printf("d point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      if (canReplace&&rowUpper[irow]>1.0e20) {
+			printf("4Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow+1];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+		      int realRow = (canReplace&&rowUpper[irow]>1.0e20) ? irow : -1;
+		      if (realRows&&realRow>=0)
+			realRow=realRows[realRow];
+		      if (!justReplace) {
+			rowCut.addCutIfNotDuplicate(rc,realRow);
+		      } else if (realRow>=0) {
+			double effectiveness=0.0;
+			for (int i=0;i<n;i++)
+			  effectiveness+=fabs(element[i]);
+			if (!info->strengthenRow[realRow]||info->strengthenRow[realRow]->effectiveness()>effectiveness) {
+			  delete info->strengthenRow[realRow];
+			  rc.setEffectiveness(effectiveness);
+			  info->strengthenRow[realRow]=rc.clone();
+			}
+		      }
+                    }
+                  }
+                }
+              }
+              minR[irow]=saveMin[istackR];
+              maxR[irow]=saveMax[istackR];
+              markR[irow]=-1;
+            }
+          }
+        }
+      }
+    }
+  }
+  if ((!ninfeas&&!rowCut.outOfSpace())&&(info->strengthenRow||
+                 !rowCut.numberCuts())&&rowCuts) {
+    // Try and find ALL big M's
+    for (int i = 0; i < nRowsSafe; ++i) {
+      if ((rowLower[i]>-1.0e20||rowUpper[i]<1.0e20)&&
+          (!info->strengthenRow||!info->strengthenRow[i])) {
+	int iflagu = 0;
+	int iflagl = 0;
+	double dmaxup = 0.0;
+	double dmaxdown = 0.0;
+	int krs = rowStart[i];
+	int kre = rowStart[i+1];
+        int kInt = -1;
+	double rhsAdjustment=0.0;
+	int nPosInt=0;
+	int nNegInt=0;
+        double valueInteger=0.0;
+        // Find largest integer coefficient
+	int k;
+        for ( k = krs; k < kre; ++k) {
+          int j = column[k];
+          if (intVar[j]) {
+            double value=rowElements[k];
+            if (colUpper[j]>colLower[j]&&!colLower[j]&&
+                fabs(value)>fabs(valueInteger)) {
+              kInt=j;
+              valueInteger=value;
+            }
+          }
+        }
+        if (kInt>=0) {
+          double upperBound = CoinMin(colUpper[kInt],static_cast<double>(COIN_INT_MAX));
+	  double upAdjust=0.0;
+	  double downAdjust=0.0;
+          for (k = krs; k < kre; ++k) {
+            double value=rowElements[k];
+            int j = column[k];
+            if (colUpper[j]==colLower[j]) {
+	      rhsAdjustment += colUpper[j]*value;
+              continue;
+            }
+	    if (intVar[j]) {
+	      if (value>0.0)
+		nPosInt++;
+	      else
+		nNegInt++;
+	    } else {
+	      nPosInt = -nCols;
+	    }
+            if (j!=kInt) {
+              // treat as continuous
+              if (value > 0.0) {
+                if (colUpper[j] >= 1e15) {
+                  dmaxup = 1e31;
+                  ++iflagu;
+                } else {
+                  dmaxup += colUpper[j] * value;
+                }
+                if (colLower[j] <= -1e15) {
+                  dmaxdown = -1e31;
+                  ++iflagl;
+                } else {
+                  dmaxdown += colLower[j] * value;
+                }
+              } else if (value<0.0) {
+                if (colUpper[j] >= 1e15) {
+                  dmaxdown = -1e31;
+                  ++iflagl;
+                } else {
+                  dmaxdown += colUpper[j] * value;
+                }
+                if (colLower[j] <= -1e15) {
+                  dmaxup = 1e31;
+                  ++iflagu;
+                } else {
+                  dmaxup += colLower[j] * value;
+                }
+              }
+	    } else {
+              // Chosen variable
+              if (value > 0.0) {
+                if (colUpper[j] >= 1e15) {
+                  upAdjust = 1e31;
+                } else {
+                  upAdjust = colUpper[j] * value;
+                }
+                if (colLower[j] <= -1e15) {
+                  downAdjust = -1e31;
+                } else {
+                  downAdjust = colLower[j] * value;
+                }
+              } else if (value<0.0) {
+                if (colUpper[j] >= 1e15) {
+                  downAdjust = -1e31;
+                } else {
+                  downAdjust = colUpper[j] * value;
+                }
+                if (colLower[j] <= -1e15) {
+                  upAdjust = 1e31;
+                } else {
+                  upAdjust = colLower[j] * value;
+                }
+              }
+            }
+          }
+	  dmaxup += rhsAdjustment;
+	  dmaxdown += rhsAdjustment;
+          // end of row
+          if (iflagu)
+            dmaxup=1.0e31;
+          if (iflagl)
+            dmaxdown=-1.0e31;
+	  // See if redundant
+	  if (dmaxdown+downAdjust>rowLower[i]-tolerance&&
+	      dmaxup+upAdjust<rowUpper[i]+tolerance) 
+	    continue;
+          if (dmaxdown+valueInteger*upperBound>rowLower[i]&&
+              dmaxup+valueInteger*upperBound<rowUpper[i]) {
+            // check to see if always feasible at 1 but not always at 0
+            if (dmaxdown+valueInteger>rowLower[i]&&dmaxup+valueInteger<rowUpper[i]&&
+                (dmaxdown<rowLower[i]-primalTolerance_||dmaxup>rowUpper[i]+primalTolerance_)) {
+              // can tighten (maybe)
+              double saveValue = valueInteger;
+              if (valueInteger>0.0) {
+                assert (dmaxdown<rowLower[i]);
+                valueInteger = rowLower[i]-dmaxdown;
+              } else {
+                assert (dmaxup>rowUpper[i]);
+                valueInteger = rowUpper[i]-dmaxup;
+              }
+              if (fabs(saveValue-valueInteger)>1.0e-12) {
+                // take
+                OsiRowCut rc;
+                rc.setLb(rowLower[i]);
+                rc.setUb(rowUpper[i]);
+                int n=0;
+                double sum=0.0;
+                for (int kk=rowStart[i];kk<rowStart[i+1];kk++) {
+                  int j=column[kk];
+                  if (j!=kInt) {
+                    sum += colsol[j]*rowElements[kk];
+                    index[n]=j;
+                    element[n++]=rowElements[kk];
+                  } else {
+                    sum += colsol[j]*valueInteger;
+                    assert (rowElements[kk]*valueInteger>=0.0);
+#if 0
+                    if (fabs(rowElements[kk])>1.01*fabs(valueInteger)) {
+                      printf("row %d changing coefficient of %d from %g to %g\n",
+                             i,kInt,rowElements[kk],valueInteger);
+                    }
+#endif
+                    if (fabs(valueInteger)>1.0e-12) {
+                      index[n]=column[kk];
+                      element[n++]=valueInteger;
+                    }
+                  }
+                }
+                double gap = 0.0;
+                if (sum<rowLower[i])
+                  gap=rowLower[i]-sum;
+                else if (sum>rowUpper[i])
+                  gap=sum-rowUpper[i];
+                if (gap>1.0e-4||info->strengthenRow!=NULL) {
+		  gap += 1.0e5;
+                  rc.setEffectiveness(gap);
+                  rc.setRow(n,index,element,false);
+#ifdef STRENGTHEN_PRINT
+		  {
+		    printf("1aCut %g <= ",rc.lb());
+		    int irow =i;
+		    int k;
+		    for ( k=0;k<n;k++) {
+		      int iColumn = index[k];
+		      printf("%g*",element[k]);
+		      if (si.isInteger(iColumn))
+			printf("i%d ",iColumn);
+		      else
+			printf("x%d ",iColumn);
+		    }
+		    printf("<= %g\n",rc.ub());
+		    printf("Row %g <= ",rowLower[irow]);
+		    for (k=rowStart[irow];k<rowStart[irow+1];k++) {
+		      int iColumn = column[k];
+		      printf("%g*",rowElements[k]);
+		      if (si.isInteger(iColumn))
+			printf("i%d ",iColumn);
+		      else
+			printf("x%d ",iColumn);
+		    }
+		    printf("<= %g\n",rowUpper[irow]);
+		  }
+#endif
+                  int returnCode=rowCut.addCutIfNotDuplicate(rc,i);
+                  if (returnCode<0)
+                    break; // out of space
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+#ifndef ONE_ARRAY
+  delete [] stackC0;
+  delete [] lo0;
+  delete [] up0;
+  delete [] columnGap;
+  delete [] markC;
+  delete [] stackC;
+  delete [] stackR;
+  delete [] saveL;
+  delete [] saveU;
+  delete [] saveMin;
+  delete [] saveMax;
+  delete [] index;
+  delete [] element;
+  delete [] djs;
+  delete [] largestPositiveInRow;
+  delete [] largestNegativeInRow;
+#endif
+  delete [] colsol;
+  // Add in row cuts
+  if (!ninfeas) {
+    if (!justReplace) {
+      rowCut.addCuts(cs,info->strengthenRow,info->pass);
+    } else {
+      for (int i=0;i<nRows;i++) {
+	int realRow=realRows[i];
+	if (realRow>=0) {
+	  OsiRowCut * cut = info->strengthenRow[realRow];
+	  if (cut) {
+#ifdef CLP_INVESTIGATE
+	    printf("Row %d, real row %d effectiveness %g\n",i,realRow,cut->effectiveness());
+#endif
+	    cs.insert(cut);
+	  }
+	}
+      }
+    }
+  }
+#if 0
+  {
+    int numberRowCutsAfter = cs.sizeRowCuts() ;
+    int k ;
+    for (k = 0;k<numberRowCutsAfter;k++) {
+      OsiRowCut thisCut = cs.rowCut(k) ;
+      printf("Cut %d is %g <=",k,thisCut.lb());
+      int n=thisCut.row().getNumElements();
+      const int * column = thisCut.row().getIndices();
+      const double * element = thisCut.row().getElements();
+      assert (n);
+      for (int i=0;i<n;i++) {
+	printf(" %g*x%d",element[i],column[i]);
+      }
+      printf(" <= %g\n",thisCut.ub());
+    }
+  }
+#endif
+  return (ninfeas);
+}
+// Does probing and adding cuts
+int CglProbing::probeCliques( const OsiSolverInterface & si, 
+                              const OsiRowCutDebugger *
+#ifdef CGL_DEBUG
+			 debugger
+#endif
+                              ,OsiCuts & cs, 
+                              double * colLower, double * colUpper, 
+		       CoinPackedMatrix *rowCopy,
+			      CoinPackedMatrix *columnCopy, const int * realRows,
+		       double * rowLower, double * rowUpper,
+		       char * intVar, double * minR, double * maxR, 
+		       int * markR, 
+                       CglTreeInfo * info)
+{
+  // Set up maxes
+  int maxStack = info->inTree ? maxStack_ : maxStackRoot_;
+  int nRows=rowCopy->getNumRows();
+  int nCols=rowCopy->getNumCols();
+  double * colsol = new double[nCols];
+  double * djs = new double[nCols];
+  const double * currentColLower = si.getColLower();
+  const double * currentColUpper = si.getColUpper();
+  double * tempL = new double [nCols];
+  double * tempU = new double [nCols];
+  int * markC = new int [nCols];
+  int * stackC = new int [2*nCols];
+  int * stackR = new int [nRows];
+  double * saveL = new double [2*nCols];
+  double * saveU = new double [2*nCols];
+  double * saveMin = new double [nRows];
+  double * saveMax = new double [nRows];
+  double * element = new double[nCols];
+  int * index = new int[nCols];
+  // For trying to extend cliques
+  int * cliqueStack=NULL;
+  int * cliqueCount=NULL;
+  int * to_01=NULL;
+  if (!mode_) {
+    to_01 = new int[nCols];
+    cliqueStack = new int[numberCliques_];
+    cliqueCount = new int[numberCliques_];
+    int i;
+    for (i=0;i<numberCliques_;i++) {
+      cliqueCount[i]=cliqueStart_[i+1]-cliqueStart_[i];
+    }
+    for (i=0;i<nCols;i++) 
+      to_01[i]=-1;
+    for (i=0;i<number01Integers_;i++) {
+      int j=cutVector_[i].sequence;
+      to_01[j]=i;
+    }
+  }
+  // Let us never add more than twice the number of rows worth of row cuts
+  // Keep cuts out of cs until end so we can find duplicates quickly
+  int nRowsFake = info->inTree ? nRows/3 : nRows;
+  row_cut rowCut(nRowsFake, !info->inTree);
+  const int * column = rowCopy->getIndices();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const int * rowLength = rowCopy->getVectorLengths(); 
+  const double * rowElements = rowCopy->getElements();
+  const int * row = columnCopy->getIndices();
+  const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+  const int * columnLength = columnCopy->getVectorLengths(); 
+  const double * columnElements = columnCopy->getElements();
+  double movement;
+  int i, j, k,kk,jj;
+  int kcol,krow;
+  bool anyColumnCuts=false;
+  double dbound, value, value2;
+  int ninfeas=0;
+  int rowCuts;
+  double disaggEffectiveness;
+  if (mode_) {
+    /* clean up djs and solution */
+    CoinMemcpyN(si.getReducedCost(),nCols,djs);
+    CoinMemcpyN( si.getColSolution(),nCols,colsol);
+    disaggEffectiveness=1.0e-3;
+    rowCuts=rowCuts_;
+  } else {
+    // need to go from a neutral place
+    memset(djs,0,nCols*sizeof(double));
+    CoinMemcpyN( si.getColSolution(),nCols,colsol);
+    disaggEffectiveness=-1.0e10;
+    if (rowCuts_!=4)
+      rowCuts=1;
+    else
+      rowCuts=4;
+  }
+  for (i = 0; i < nCols; ++i) {
+    /* was if (intVar[i]) */
+    if (1) {
+      if (colUpper[i]-colLower[i]>1.0e-8) {
+	if (colsol[i]<colLower[i]+primalTolerance_) {
+	  colsol[i]=colLower[i];
+	  djs[i] = CoinMax(0.0,djs[i]);
+	} else if (colsol[i]>colUpper[i]-primalTolerance_) {
+	  colsol[i]=colUpper[i];
+	  djs[i] = CoinMin(0.0,djs[i]);
+	} else {
+	  djs[i]=0.0;
+	}
+	/*if (fabs(djs[i])<1.0e-5) 
+	  djs[i]=0.0;*/
+      }
+    }
+  }
+
+  int ipass=0,nfixed=-1;
+
+  double cutoff;
+  bool cutoff_available = si.getDblParam(OsiDualObjectiveLimit,cutoff);
+  if (!cutoff_available||usingObjective_<0) { // cut off isn't set or isn't valid
+    cutoff = si.getInfinity();
+  }
+  cutoff *= si.getObjSense();
+  if (fabs(cutoff)>1.0e30)
+    assert (cutoff>1.0e30);
+  double current = si.getObjValue();
+  // make irrelevant if mode is 0
+  if (!mode_)
+    cutoff=COIN_DBL_MAX;
+  /* for both way coding */
+  int nstackC0=-1;
+  int * stackC0 = new int[maxStack];
+  double * lo0 = new double[maxStack];
+  double * up0 = new double[maxStack];
+  int nstackR,nstackC;
+  for (i=0;i<nCols;i++) {
+    if (colUpper[i]-colLower[i]<1.0e-8) {
+      markC[i]=3;
+    } else {
+      markC[i]=0;
+    }
+  }
+  double tolerance = 1.0e1*primalTolerance_;
+  int maxPass = info->inTree ? maxPass_ : maxPassRoot_;
+  // If we are going to replace coefficient then we don't need to be effective
+  double needEffectiveness = info->strengthenRow ? -1.0e10 : 1.0e-3;
+  while (ipass<maxPass&&nfixed) {
+    int iLook;
+    ipass++;
+    nfixed=0;
+    for (iLook=0;iLook<numberThisTime_;iLook++) {
+      double solval;
+      double down;
+      double up;
+      j=lookedAt_[iLook];
+      solval=colsol[j];
+      down = floor(solval+tolerance);
+      up = ceil(solval-tolerance);
+      if(colUpper[j]-colLower[j]<1.0e-8) markC[j]=3;
+      if (markC[j]||!intVar[j]) continue;
+      double saveSolval = solval;
+      if (solval>=colUpper[j]-tolerance||solval<=colLower[j]+tolerance||up==down) {
+	if (solval<=colLower[j]+2.0*tolerance) {
+	  solval = colLower[j]+1.0e-1;
+	  down=colLower[j];
+	  up=down+1.0;
+	} else if (solval>=colUpper[j]-2.0*tolerance) {
+	  solval = colUpper[j]-1.0e-1;
+	  up=colUpper[j];
+	  down=up-1;
+	} else {
+          // odd
+          up=down+1.0;
+          solval = down+1.0e-1;
+        }
+      }
+      assert (up<=colUpper[j]);
+      assert (down>=colLower[j]);
+      assert (up>down);
+      if ((solval-down>1.0e-6&&up-solval>1.0e-6)||mode_!=1) {
+	int istackC,iway, istackR;
+	int way[]={1,2,1};
+	int feas[]={1,2,4};
+	int feasible=0;
+	int notFeasible;
+	for (iway=0;iway<3;iway ++) {
+	  int fixThis=0;
+	  double objVal=current;
+	  int goingToTrueBound=0;
+	  stackC[0]=j;
+	  markC[j]=way[iway];
+          double solMovement;
+	  if (way[iway]==1) {
+	    movement=down-colUpper[j];
+            solMovement = down-colsol[j];
+	    assert(movement<-0.99999);
+	    if (fabs(down-colLower[j])<1.0e-7) {
+	      goingToTrueBound=2;
+	      down=colLower[j];
+	    }
+	  } else {
+	    movement=up-colLower[j];
+            solMovement = up-colsol[j];
+	    assert(movement>0.99999);
+	    if (fabs(up-colUpper[j])<1.0e-7) {
+	      goingToTrueBound=2;
+	      up=colUpper[j];
+	    }
+	  }
+	  if (goingToTrueBound&&(colUpper[j]-colLower[j]>1.5||colLower[j]))
+	    goingToTrueBound=1;
+	  // switch off disaggregation if not wanted
+	  if ((rowCuts&1)==0)
+	    goingToTrueBound=0;
+#ifdef PRINT_DEBUG
+	  if (fabs(movement)>1.01) {
+	    printf("big %d %g %g %g\n",j,colLower[j],solval,colUpper[j]);
+	  }
+#endif
+	  if (solMovement*djs[j]>0.0)
+	    objVal += solMovement*djs[j];
+	  nstackC=1;
+	  nstackR=0;
+	  saveL[0]=colLower[j];
+	  saveU[0]=colUpper[j];
+          assert (saveU[0]>saveL[0]);
+	  notFeasible=0;
+	  if (movement<0.0) {
+	    colUpper[j] += movement;
+	    colUpper[j] = floor(colUpper[j]+0.5);
+#ifdef PRINT_DEBUG
+	    printf("** Trying %d down to 0\n",j);
+#endif
+	  } else {
+	    colLower[j] += movement;
+	    colLower[j] = floor(colLower[j]+0.5);
+#ifdef PRINT_DEBUG
+	    printf("** Trying %d up to 1\n",j);
+#endif
+	  }
+	  if (fabs(colUpper[j]-colLower[j])<1.0e-6) 
+	    markC[j]=3; // say fixed
+	  istackC=0;
+	  /* update immediately */
+	  for (k=columnStart[j];k<columnStart[j]+columnLength[j];k++) {
+	    int irow = row[k];
+	    value = columnElements[k];
+	    assert (markR[irow]!=-2);
+	    if (markR[irow]==-1) {
+	      stackR[nstackR]=irow;
+	      markR[irow]=nstackR;
+	      saveMin[nstackR]=minR[irow];
+	      saveMax[nstackR]=maxR[irow];
+	      nstackR++;
+#if 0
+	    } else if (markR[irow]==-2) {
+	      continue;
+#endif
+	    }
+	    /* could check immediately if violation */
+	    if (movement>0.0) {
+	      /* up */
+	      if (value>0.0) {
+		/* up does not change - down does */
+                if (minR[irow]>-1.0e10)
+                  minR[irow] += value;
+		if (minR[irow]>rowUpper[irow]+1.0e-5) {
+		  notFeasible=1;
+		  istackC=1;
+		  break;
+		}
+	      } else {
+		/* down does not change - up does */
+                if (maxR[irow]<1.0e10)
+                  maxR[irow] += value;
+		if (maxR[irow]<rowLower[irow]-1.0e-5) {
+		  notFeasible=1;
+		  istackC=1;
+		  break;
+		}
+	      }
+	    } else {
+	      /* down */
+	      if (value<0.0) {
+		/* up does not change - down does */
+                if (minR[irow]>-1.0e10)
+                  minR[irow] -= value;
+		if (minR[irow]>rowUpper[irow]+1.0e-5) {
+		  notFeasible=1;
+		  istackC=1;
+		  break;
+		}
+	      } else {
+		/* down does not change - up does */
+                if (maxR[irow]<1.0e10)
+                  maxR[irow] -= value;
+		if (maxR[irow]<rowLower[irow]-1.0e-5) {
+		  notFeasible=1;
+		  istackC=1;
+		  break;
+		}
+	      }
+	    }
+	  }
+	  while (istackC<nstackC&&nstackC<maxStack) {
+	    int jway;
+	    int jcol =stackC[istackC];
+	    jway=markC[jcol];
+	    // If not first and fixed then skip
+	    if (jway==3&&istackC) {
+	      //istackC++;
+	      //continue;
+              //printf("fixed %d on stack\n",jcol);
+	    }
+	    // Do cliques
+	    if (oneFixStart_&&oneFixStart_[jcol]>=0) {
+	      int start;
+	      int end;
+	      if (colLower[jcol]>saveL[istackC]) {
+		// going up
+		start = oneFixStart_[jcol];
+		end = zeroFixStart_[jcol];
+	      } else {
+		assert (colUpper[jcol]<saveU[istackC]);
+		// going down
+		start = zeroFixStart_[jcol];
+		end = endFixStart_[jcol];
+	      }
+	      for (int i=start;i<end;i++) {
+		int iClique = whichClique_[i];
+		for (int k=cliqueStart_[iClique];k<cliqueStart_[iClique+1];k++) {
+		  int kcol = sequenceInCliqueEntry(cliqueEntry_[k]);
+                  if (jcol==kcol)
+                    continue;
+		  int kway = oneFixesInCliqueEntry(cliqueEntry_[k]);
+                  if (kcol!=jcol) {
+                    if (!markC[kcol]) {
+                      // not on list yet
+                      if (nstackC<2*maxStack) {
+                        markC[kcol] = 3; // say fixed
+                        fixThis++;
+                        stackC[nstackC]=kcol;
+                        saveL[nstackC]=colLower[kcol];
+                        saveU[nstackC]=colUpper[kcol];
+                        assert (saveU[nstackC]>saveL[nstackC]);
+                        nstackC++;
+                        if (!kway) {
+                          // going up
+                          double solMovement=1.0-colsol[kcol];
+                          if (solMovement>0.0001) {
+                            assert (djs[kcol]>=0.0);
+                            objVal += djs[kcol]*solMovement;
+                          }
+                          colLower[kcol]=1.0;
+                          /* update immediately */
+                          for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+                            krow = row[jj];
+                            value = columnElements[jj];
+			    assert (markR[krow]!=-2);
+                            if (markR[krow]==-1) {
+                              stackR[nstackR]=krow;
+                              markR[krow]=nstackR;
+                              saveMin[nstackR]=minR[krow];
+                              saveMax[nstackR]=maxR[krow];
+                              nstackR++;
+#if 0
+                            } else if (markR[krow]==-2) {
+                              continue;
+#endif
+                            }
+                            /* could check immediately if violation */
+                            /* up */
+                            if (value>0.0) {
+                              /* up does not change - down does */
+                              if (minR[krow]>-1.0e10)
+                                minR[krow] += value;
+                              if (minR[krow]>rowUpper[krow]+1.0e-5) {
+                                colUpper[kcol]=-1.0e50; /* force infeasible */
+                                break;
+                              }
+                            } else {
+                              /* down does not change - up does */
+                              if (maxR[krow]<1.0e10)
+                                maxR[krow] += value;
+                              if (maxR[krow]<rowLower[krow]-1.0e-5) {
+                                notFeasible=1;
+                                break;
+                              }
+                            }
+                          }
+                        } else {
+                          // going down
+                          double solMovement=0.0-colsol[kcol];
+                          if (solMovement<-0.0001) {
+                            assert (djs[kcol]<=0.0);
+                            objVal += djs[kcol]*solMovement;
+                          }
+                          colUpper[kcol]=0.0;
+                          /* update immediately */
+                          for (int jj =columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+                            krow = row[jj];
+                            value = columnElements[jj];
+			    assert (markR[krow]!=-2);
+                            if (markR[krow]==-1) {
+                              stackR[nstackR]=krow;
+                              markR[krow]=nstackR;
+                              saveMin[nstackR]=minR[krow];
+                              saveMax[nstackR]=maxR[krow];
+                              nstackR++;
+#if 0
+                            } else if (markR[krow]==-2) {
+                              continue;
+#endif
+                            }
+                            /* could check immediately if violation */
+                            /* down */
+                            if (value<0.0) {
+                              /* up does not change - down does */
+                              if (minR[krow]>-1.0e10)
+                                minR[krow] -= value;
+                              if (minR[krow]>rowUpper[krow]+1.0e-5) {
+                                notFeasible=1;
+                                break;
+                              }
+                            } else {
+                              /* down does not change - up does */
+                              if (maxR[krow]<1.0e10)
+                                maxR[krow] -= value;
+                              if (maxR[krow]<rowLower[krow]-1.0e-5) {
+                                notFeasible=1;
+                                break;
+                              }
+                            }
+                          }
+                        }
+                      }
+                    } else if (markC[kcol]==1) {
+                      // marked as going to 0
+                      assert (!colUpper[kcol]);
+                      if (!kway) {
+                        // contradiction
+                        notFeasible=1;
+                        break;
+                      }
+                    } else if (markC[kcol]==2) {
+                      // marked as going to 1
+                      assert (colLower[kcol]);
+                      if (kway) {
+                        // contradiction
+                        notFeasible=1;
+                        break;
+                      }
+                    } else {
+                      // marked as fixed
+                      assert (markC[kcol]==3);
+                      int jkway;
+                      if (colLower[kcol])
+                        jkway=1;
+                      else
+                        jkway=0;
+                      if (kway==jkway) {
+                        // contradiction
+                        notFeasible=1;
+                        break;
+                      }
+                    }
+                  }
+		}
+		if (notFeasible)
+		  break;
+	      }
+	      if (notFeasible)
+		istackC=nstackC+1;
+	    }
+	    for (k=columnStart[jcol];k<columnStart[jcol]+columnLength[jcol];k++) {
+	      // break if found not feasible
+	      if (notFeasible)
+		break;
+	      int irow = row[k];
+	      /*value = columnElements[k];*/
+	      assert (markR[irow]!=-2);
+#if 0
+	      if (markR[irow]!=-2) {
+#endif
+		/* see if anything forced */
+		for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];kk++) {
+		  double moveUp=0.0;
+		  double moveDown=0.0;
+		  double newUpper=-1.0,newLower=1.0;
+		  kcol=column[kk];
+		  bool onList = (markC[kcol]!=0);
+		  if (markC[kcol]!=3) {
+		    value2=rowElements[kk];
+                    int markIt=markC[kcol];
+		    if (value2 < 0.0) {
+		      if (colUpper[kcol] < 1e10 && (markIt&2)==0 &&
+			  rowUpper[irow]<1.0e10) {
+			dbound = colUpper[kcol]+
+			  (rowUpper[irow]-minR[irow])/value2;
+			if (dbound > colLower[kcol] + primalTolerance_) {
+			  if (intVar[kcol]) {
+                            markIt |= 2;
+			    newLower = ceil(dbound-primalTolerance_);
+			  } else {
+			    newLower=dbound;
+			    if (newLower+primalTolerance_>colUpper[kcol]&&
+				newLower-primalTolerance_<=colUpper[kcol]) {
+			      newLower=colUpper[kcol];
+                              markIt |= 2;
+                              //markIt=3;
+			    } else {
+                              // avoid problems - fix later ?
+                              markIt=3;
+                            }
+			  }
+			  moveUp = newLower-colLower[kcol];
+			}
+		      }
+		      if (colLower[kcol] > -1e10 && (markIt&1)==0 &&
+			  rowLower[irow]>-1.0e10) {
+			dbound = colLower[kcol] + 
+			  (rowLower[irow]-maxR[irow])/value2;
+			if (dbound < colUpper[kcol] - primalTolerance_) {
+			  if (intVar[kcol]) {
+			    markIt |= 1;
+			    newUpper = floor(dbound+primalTolerance_);
+			  } else {
+			    newUpper=dbound;
+			    if (newUpper-primalTolerance_<colLower[kcol]&&
+				newUpper+primalTolerance_>=colLower[kcol]) {
+			      newUpper=colLower[kcol];
+                              markIt |= 1;
+                              //markIt=3;
+			    } else {
+                              // avoid problems - fix later ?
+                              markIt=3;
+                            }
+			  }
+			  moveDown = newUpper-colUpper[kcol];
+			}
+		      }
+		    } else {
+		      /* positive element */
+		      if (colUpper[kcol] < 1e10 && (markIt&2)==0 &&
+			  rowLower[irow]>-1.0e10) {
+			dbound = colUpper[kcol] + 
+			  (rowLower[irow]-maxR[irow])/value2;
+			if (dbound > colLower[kcol] + primalTolerance_) {
+			  if (intVar[kcol]) {
+			    markIt |= 2;
+			    newLower = ceil(dbound-primalTolerance_);
+			  } else {
+			    newLower=dbound;
+			    if (newLower+primalTolerance_>colUpper[kcol]&&
+				newLower-primalTolerance_<=colUpper[kcol]) {
+			      newLower=colUpper[kcol];
+                              markIt |= 2;
+                              //markIt=3;
+			    } else {
+                              // avoid problems - fix later ?
+                              markIt=3;
+			    }
+			  }
+			  moveUp = newLower-colLower[kcol];
+			}
+		      }
+		      if (colLower[kcol] > -1e10 && (markIt&1)==0 &&
+			  rowUpper[irow]<1.0e10) {
+			dbound = colLower[kcol] + 
+			  (rowUpper[irow]-minR[irow])/value2;
+			if (dbound < colUpper[kcol] - primalTolerance_) {
+			  if (intVar[kcol]) {
+			    markIt |= 1;
+			    newUpper = floor(dbound+primalTolerance_);
+			  } else {
+			    newUpper=dbound;
+			    if (newUpper-primalTolerance_<colLower[kcol]&&
+				newUpper+primalTolerance_>=colLower[kcol]) {
+			      newUpper=colLower[kcol];
+                              markIt |= 1;
+                              //markIt=3;
+			    } else {
+                              // avoid problems - fix later ?
+                              markIt=3;
+			    }
+			  }
+			  moveDown = newUpper-colUpper[kcol];
+			}
+		      }
+		    }
+		    if (nstackC<2*maxStack) {
+                      markC[kcol] = markIt;
+		    }
+		    if (moveUp&&nstackC<2*maxStack) {
+		      fixThis++;
+#ifdef PRINT_DEBUG
+		      printf("lower bound on %d increased from %g to %g by row %d %g %g\n",kcol,colLower[kcol],newLower,irow,rowLower[irow],rowUpper[irow]);
+		      value=0.0;
+		      for (jj=rowStart[irow];jj<rowStart[irow]+rowLength[irow];jj++) {
+			int ii=column[jj];
+			if (colUpper[ii]-colLower[ii]>primalTolerance_) {
+			  printf("(%d, %g) ",ii,rowElements[jj]);
+			} else {
+			  value += rowElements[jj]*colLower[ii];
+			}
+		      }
+		      printf(" - fixed %g\n",value);
+		      for (jj=rowStart[irow];jj<rowStart[irow]+rowLength[irow];jj++) {
+			int ii=column[jj];
+			if (colUpper[ii]-colLower[ii]<primalTolerance_) {
+			  printf("(%d, %g, %g) ",ii,rowElements[jj],colLower[ii]);
+			}
+		      }
+		      printf("\n");
+#endif
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+                        assert (saveU[nstackC]>saveL[nstackC]);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newLower>colsol[kcol]) {
+			if (djs[kcol]<0.0) {
+			  /* should be infeasible */
+			  assert (newLower>colUpper[kcol]+primalTolerance_);
+			} else {
+			  objVal += moveUp*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol])
+			newLower = CoinMax(colLower[kcol],ceil(newLower-1.0e-4));
+		      colLower[kcol]=newLower;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      /* update immediately */
+		      for (jj=columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			krow = row[jj];
+			value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+#if 0
+			} else if (markR[krow]==-2) {
+			  continue;
+#endif
+			}
+			/* could check immediately if violation */
+			/* up */
+			if (value>0.0) {
+			  /* up does not change - down does */
+                          if (minR[krow]>-1.0e10)
+                            minR[krow] += value*moveUp;
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+                          if (maxR[krow]<1.0e10)
+                            maxR[krow] += value*moveUp;
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (moveDown&&nstackC<2*maxStack) {
+		      fixThis++;
+#ifdef PRINT_DEBUG
+		      printf("upper bound on %d decreased from %g to %g by row %d %g %g\n",kcol,colUpper[kcol],newUpper,irow,rowLower[irow],rowUpper[irow]);
+		      value=0.0;
+		      for (jj=rowStart[irow];jj<rowStart[irow]+rowLength[irow];jj++) {
+			int ii=column[jj];
+			if (colUpper[ii]-colLower[ii]>primalTolerance_) {
+			  printf("(%d, %g) ",ii,rowElements[jj]);
+			} else {
+			  value += rowElements[jj]*colLower[ii];
+			}
+		      }
+		      printf(" - fixed %g\n",value);
+		      for (jj=rowStart[irow];jj<rowStart[irow]+rowLength[irow];jj++) {
+			int ii=column[jj];
+			if (colUpper[ii]-colLower[ii]<primalTolerance_) {
+			  printf("(%d, %g, %g) ",ii,rowElements[jj],colLower[ii]);
+			}
+		      }
+		      printf("\n");
+#endif
+		      if (!onList) {
+			stackC[nstackC]=kcol;
+			saveL[nstackC]=colLower[kcol];
+			saveU[nstackC]=colUpper[kcol];
+                        assert (saveU[nstackC]>saveL[nstackC]);
+			nstackC++;
+			onList=true;
+		      }
+		      if (newUpper<colsol[kcol]) {
+			if (djs[kcol]>0.0) {
+			  /* should be infeasible */
+			  assert (colLower[kcol]>newUpper+primalTolerance_);
+			} else {
+			  objVal += moveDown*djs[kcol];
+			}
+		      }
+		      if (intVar[kcol])
+			newUpper = CoinMin(colUpper[kcol],floor(newUpper+1.0e-4));
+		      colUpper[kcol]=newUpper;
+		      if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+			markC[kcol]=3; // say fixed
+		      }
+		      /* update immediately */
+		      for (jj=columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+			krow = row[jj];
+			value = columnElements[jj];
+			assert (markR[krow]!=-2);
+			if (markR[krow]==-1) {
+			  stackR[nstackR]=krow;
+			  markR[krow]=nstackR;
+			  saveMin[nstackR]=minR[krow];
+			  saveMax[nstackR]=maxR[krow];
+			  nstackR++;
+#if 0
+			} else if (markR[krow]==-2) {
+#endif
+			  continue;
+			}
+			/* could check immediately if violation */
+			/* down */
+			if (value<0.0) {
+			  /* up does not change - down does */
+                          if (minR[krow]>-1.0e10)
+                            minR[krow] += value*moveDown;
+			  if (minR[krow]>rowUpper[krow]+1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    break;
+			  }
+			} else {
+			  /* down does not change - up does */
+                          if (maxR[krow]<1.0e10)
+                            maxR[krow] += value*moveDown;
+			  if (maxR[krow]<rowLower[krow]-1.0e-5) {
+			    colUpper[kcol]=-1.0e50; /* force infeasible */
+			    break;
+			  }
+			}
+		      }
+		    }
+		    if (colLower[kcol]>colUpper[kcol]+primalTolerance_) {
+		      notFeasible=1;;
+		      k=columnStart[jcol]+columnLength[jcol];
+		      istackC=nstackC+1;
+#ifdef PRINT_DEBUG
+		      printf("** not feasible this way\n");
+#endif
+		      break;
+		    }
+		  }
+		}
+#if 0
+	      }
+#endif
+	    }
+	    istackC++;
+	  }
+	  if (!notFeasible) {
+	    if (objVal<=cutoff) {
+	      feasible |= feas[iway];
+	    } else {
+#ifdef PRINT_DEBUG
+	      printf("not feasible on dj\n");
+#endif
+	      notFeasible=1;
+	      if (iway==1&&feasible==0) {
+		/* not feasible at all */
+		ninfeas=1;
+		j=nCols-1;
+		break;
+	      }
+	    }
+	  } else if (iway==1&&feasible==0) {
+	    /* not feasible at all */
+	    ninfeas=1;
+	    j=nCols-1;
+            iLook=numberThisTime_;
+	    ipass=maxPass;
+	    break;
+	  }
+	  if (notFeasible)
+	    goingToTrueBound=0;
+	  if (iway==2||(iway==1&&feasible==2)) {
+	    /* keep */
+	    iway=3;
+	    nfixed++;
+            if (mode_) {
+	      OsiColCut cc;
+	      int nTot=0,nFix=0,nInt=0;
+	      bool ifCut=false;
+	      for (istackC=0;istackC<nstackC;istackC++) {
+		int icol=stackC[istackC];
+		if (intVar[icol]) {
+		  if (colUpper[icol]<currentColUpper[icol]-1.0e-4) {
+		    element[nFix]=colUpper[icol];
+		    index[nFix++]=icol;
+		    nInt++;
+		    if (colsol[icol]>colUpper[icol]+primalTolerance_) {
+		      ifCut=true;
+		      anyColumnCuts=true;
+		    }
+		  }
+		}
+	      }
+	      if (nFix) {
+		nTot=nFix;
+		cc.setUbs(nFix,index,element);
+		nFix=0;
+	      }
+	      for (istackC=0;istackC<nstackC;istackC++) {
+		int icol=stackC[istackC];
+		if (intVar[icol]) {
+		  if (colLower[icol]>currentColLower[icol]+1.0e-4) {
+		    element[nFix]=colLower[icol];
+		    index[nFix++]=icol;
+		    nInt++;
+		    if (colsol[icol]<colLower[icol]-primalTolerance_) {
+		      ifCut=true;
+		      anyColumnCuts=true;
+		    }
+		  }
+		}
+	      }
+	      if (nFix) {
+		nTot+=nFix;
+		cc.setLbs(nFix,index,element);
+	      }
+	      // could tighten continuous as well
+	      if (nInt) {
+		if (ifCut) {
+		  cc.setEffectiveness(100.0);
+		} else {
+		  cc.setEffectiveness(1.0e-5);
+		}
+#ifdef CGL_DEBUG
+		checkBounds(debugger,cc);
+#endif
+		cs.insert(cc);
+	      }
+	    }
+	    for (istackC=0;istackC<nstackC;istackC++) {
+	      int icol=stackC[istackC];
+	      if (colUpper[icol]-colLower[icol]>primalTolerance_) {
+		markC[icol]=0;
+	      } else {
+		markC[icol]=3;
+	      }
+	    }
+	    for (istackR=0;istackR<nstackR;istackR++) {
+	      int irow=stackR[istackR];
+	      markR[irow]=-1;
+	    }
+	  } else {
+	    /* is it worth seeing if can increase coefficients
+	       or maybe better see if it is a cut */
+	    if (iway==0) {
+	      nstackC0=CoinMin(nstackC,maxStack);
+	      double solMove = saveSolval-down;
+	      double boundChange;
+	      if (notFeasible) {
+		nstackC0=0;
+	      } else {
+		for (istackC=0;istackC<nstackC0;istackC++) {
+		  int icol=stackC[istackC];
+		  stackC0[istackC]=icol;
+		  lo0[istackC]=colLower[icol];
+		  up0[istackC]=colUpper[icol];
+		}
+	      }
+	      /* restore all */
+              int nCliquesAffected=0;
+              assert (iway==0);
+	      for (istackC=nstackC-1;istackC>=0;istackC--) {
+		int icol=stackC[istackC];
+		double oldU=saveU[istackC];
+		double oldL=saveL[istackC];
+		if(goingToTrueBound==2&&istackC) {
+                  // Work for extending cliques
+                  if (!mode_&&numberCliques_) {
+                    int i_01 = to_01[icol];
+                    if (i_01>=0) {
+                      int start;
+                      int end;
+                      if (colLower[icol]) {
+                        // going up - but we want weak way
+                        start = zeroFixStart_[icol];
+                        end = endFixStart_[icol];
+                      } else {
+                        // going down - but we want weak way
+                        start = oneFixStart_[icol];
+                        end = zeroFixStart_[icol];
+                      }
+                      //if (end>start)
+                      //printf("j %d, other %d is in %d cliques\n",
+                      //     j,i_01,end-start);
+                      for (int i=start;i<end;i++) {
+                        int iClique = whichClique_[i];
+                        int size = cliqueStart_[iClique+1]-cliqueStart_[iClique];
+                        if (cliqueCount[iClique]==size) {
+                          // first time
+                          cliqueStack[nCliquesAffected++]=iClique;
+                        }
+                        // decrement counts
+                        cliqueCount[iClique]--;
+                      }
+                    }
+                  }
+		  // upper disaggregation cut would be
+		  // xval < upper + (old_upper-upper) (jval-down)
+		  boundChange = oldU-colUpper[icol];
+		  if (boundChange>0.0&&oldU<1.0e10&&
+		      (!mode_||colsol[icol]>colUpper[icol]
+		      + boundChange*solMove+primalTolerance_)) {
+		    // create cut
+		    OsiRowCut rc;
+		    rc.setLb(-COIN_DBL_MAX);
+		    rc.setUb(colUpper[icol]-down*boundChange);
+		    index[0]=icol;
+		    element[0]=1.0;
+		    index[1]=j;
+		    element[1]= - boundChange;
+		    // effectiveness is how far j moves
+		    double newSol = (colsol[icol]-colUpper[icol])/
+		      boundChange;
+		    if (mode_) 
+		      assert(newSol>solMove);
+		    rc.setEffectiveness(newSol-solMove);
+		    if (rc.effectiveness()>disaggEffectiveness) {
+		      rc.setRow(2,index,element,false);
+#ifdef CGL_DEBUG
+		      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+		      rowCut.addCutIfNotDuplicate(rc);
+		    }
+		  }
+		  // lower disaggregation cut would be
+		  // xval > lower + (old_lower-lower) (jval-down)
+		  boundChange = oldL-colLower[icol];
+		  if (boundChange<0.0&&oldL>-1.0e10&&
+		      (!mode_||colsol[icol]<colLower[icol]
+		      + boundChange*solMove-primalTolerance_)) {
+		    // create cut
+		    OsiRowCut rc;
+		    rc.setLb(colLower[icol]-down*boundChange);
+		    rc.setUb(COIN_DBL_MAX);
+		    index[0]=icol;
+		    element[0]=1.0;
+		    index[1]=j;
+		    element[1]=- boundChange;
+		    // effectiveness is how far j moves
+		    double newSol = (colsol[icol]-colLower[icol])/
+		      boundChange;
+		    if (mode_)
+		      assert(newSol>solMove);
+		    rc.setEffectiveness(newSol-solMove);
+		    if (rc.effectiveness()>disaggEffectiveness) {
+		      rc.setRow(2,index,element,false);
+#ifdef CGL_DEBUG
+		      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+		      rowCut.addCutIfNotDuplicate(rc);
+#if 0
+		      printf("%d original bounds %g, %g new Lo %g sol= %g int %d sol= %g\n",icol,oldL,oldU,colLower[icol],colsol[icol], j, colsol[j]);
+		      printf("-1.0 * x(%d) + %g * y(%d) <= %g\n",
+			     icol,boundChange,j,rc.ub());
+#endif
+		    }
+		  }
+		}
+		colUpper[icol]=oldU;
+		colLower[icol]=oldL;
+		markC[icol]=0;
+	      }
+              if (nCliquesAffected) {
+                for (int i=0;i<nCliquesAffected;i++) {
+                  int iClique = cliqueStack[i];
+                  int size = cliqueCount[iClique];
+                  // restore
+                  cliqueCount[iClique]= cliqueStart_[iClique+1]-cliqueStart_[iClique];
+                  if (!size) {
+                    if (logLevel_>1)
+                      printf("** could extend clique by adding j!\n");
+                  }
+                }
+              }
+	      for (istackR=0;istackR<nstackR;istackR++) {
+		int irow=stackR[istackR];
+		// switch off strengthening if not wanted
+		if ((rowCuts&2)!=0&&goingToTrueBound) {
+		  bool ifCut=anyColumnCuts;
+		  double gap = rowUpper[irow]-maxR[irow];
+		  double sum=0.0;
+		  if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+		    // see if the strengthened row is a cut
+		    for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			 kk++) {
+		      sum += rowElements[kk]*colsol[column[kk]];
+		    }
+		    if (sum-gap*colsol[j]>maxR[irow]+primalTolerance_||(info->strengthenRow&&rowLower[irow]<-1.0e20)) {
+		      // can be a cut
+		      // subtract gap from upper and integer coefficient
+		      // saveU and saveL spare
+		      int * index = reinterpret_cast<int *>(saveL);
+		      double * element = saveU;
+		      int n=0;
+                      bool coefficientExists=false;
+		      for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			   kk++) {
+			if (column[kk]!=j) {
+			  index[n]=column[kk];
+			  element[n++]=rowElements[kk];
+			} else {
+			  double value=rowElements[kk]-gap;
+			  if (fabs(value)>1.0e-12) {
+			    index[n]=column[kk];
+			    element[n++]=value;
+			  }
+			  coefficientExists=true;
+			}
+		      }
+		      if (!coefficientExists) {
+			index[n]=j;
+			element[n++]=-gap;
+		      }
+		      OsiRowCut rc;
+		      rc.setLb(-COIN_DBL_MAX);
+		      rc.setUb(rowUpper[irow]-gap*(colLower[j]+1.0));
+		      // effectiveness is how far j moves
+		      rc.setEffectiveness((sum-gap*colsol[j]-maxR[irow])/gap);
+		      if (rc.effectiveness()>needEffectiveness) {
+			rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+			if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                        // If strengthenRow point to row
+                        //if(info->strengthenRow)
+                        //printf("a point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      if (rowLower[irow]<-1.0e20) {
+			printf("5Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow]+rowLength[irow];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+		      int realRow = (rowLower[irow]<-1.0e20) ? irow : -1;
+		      if (realRows&&realRow>0)
+			realRow=realRows[realRow];
+		      rowCut.addCutIfNotDuplicate(rc,realRow);
+		      }
+		    }
+		  }
+		  gap = minR[irow]-rowLower[irow];
+		  if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+		    // see if the strengthened row is a cut
+		    if (!sum) {
+		      for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			   kk++) {
+			sum += rowElements[kk]*colsol[column[kk]];
+		      }
+		    }
+		    if (sum+gap*colsol[j]<minR[irow]+primalTolerance_||(info->strengthenRow&&rowUpper[irow]>1.0e20)) {
+		      // can be a cut
+		      // add gap to lower and integer coefficient
+		      // saveU and saveL spare
+		      int * index = reinterpret_cast<int *>(saveL);
+		      double * element = saveU;
+		      int n=0;
+                      bool coefficientExists=false;
+		      for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			   kk++) {
+			if (column[kk]!=j) {
+			  index[n]=column[kk];
+			  element[n++]=rowElements[kk];
+			} else {
+			  double value=rowElements[kk]+gap;
+			  if (fabs(value)>1.0e-12) {
+			    index[n]=column[kk];
+			    element[n++]=value;
+			  }
+			  coefficientExists=true;
+			}
+		      }
+		      if (!coefficientExists) {
+			index[n]=j;
+			element[n++]=gap;
+		      }
+		      OsiRowCut rc;
+		      rc.setLb(rowLower[irow]+gap*(colLower[j]+1.0));
+		      rc.setUb(COIN_DBL_MAX);
+		      // effectiveness is how far j moves
+		      rc.setEffectiveness((minR[irow]-sum-gap*colsol[j])/gap);
+		      if (rc.effectiveness()>needEffectiveness) {
+			rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+			if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                        //if(info->strengthenRow)
+                        //printf("b point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      if (rowUpper[irow]>1.0e20) {
+			printf("6Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow]+rowLength[irow];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+		      int realRow = (rowUpper[irow]>1.0e20) ? irow : -1;
+		      if (realRows&&realRow>0)
+			realRow=realRows[realRow];
+		      rowCut.addCutIfNotDuplicate(rc,realRow);
+		      }
+		    }
+		  }
+		}
+		minR[irow]=saveMin[istackR];
+		maxR[irow]=saveMax[istackR];
+		markR[irow]=-1;
+	      }
+	    } else {
+	      if (iway==1&&feasible==3) {
+		iway=3;
+		/* point back to stack */
+		for (istackC=nstackC-1;istackC>=0;istackC--) {
+		  int icol=stackC[istackC];
+		  markC[icol]=istackC+1000;
+		}
+		if (mode_) {
+		  OsiColCut cc;
+		  int nTot=0,nFix=0,nInt=0;
+		  bool ifCut=false;
+		  for (istackC=0;istackC<nstackC0;istackC++) {
+		    int icol=stackC0[istackC];
+		    int istackC1=markC[icol]-1000;
+		    if (istackC1>=0) {
+		      if (CoinMin(lo0[istackC],colLower[icol])>saveL[istackC1]+1.0e-4) {
+			saveL[istackC1]=CoinMin(lo0[istackC],colLower[icol]);
+			if (intVar[icol]) {
+			  element[nFix]=saveL[istackC1];
+			  index[nFix++]=icol;
+			  nInt++;
+			  if (colsol[icol]<saveL[istackC1]-primalTolerance_)
+			    ifCut=true;
+			}
+			nfixed++;
+		      }
+		    }
+		  }
+		  if (nFix) {
+		    nTot=nFix;
+		    cc.setLbs(nFix,index,element);
+		    nFix=0;
+		  }
+		  for (istackC=0;istackC<nstackC0;istackC++) {
+		    int icol=stackC0[istackC];
+		    int istackC1=markC[icol]-1000;
+		    if (istackC1>=0) {
+		      if (CoinMax(up0[istackC],colUpper[icol])<saveU[istackC1]-1.0e-4) {
+			saveU[istackC1]=CoinMax(up0[istackC],colUpper[icol]);
+			if (intVar[icol]) {
+			  element[nFix]=saveU[istackC1];
+			  index[nFix++]=icol;
+			  nInt++;
+			  if (colsol[icol]>saveU[istackC1]+primalTolerance_)
+			    ifCut=true;
+			}
+			nfixed++;
+		      }
+		    }
+		  }
+		  if (nFix) {
+		    nTot+=nFix;
+		    cc.setUbs(nFix,index,element);
+		  }
+		  // could tighten continuous as well
+		  if (nInt) {
+		    if (ifCut) {
+		      cc.setEffectiveness(100.0);
+		    } else {
+		      cc.setEffectiveness(1.0e-5);
+		    }
+#ifdef CGL_DEBUG
+		    checkBounds(debugger,cc);
+#endif
+		    cs.insert(cc);
+		  }
+		}
+	      } else {
+		goingToTrueBound=0;
+	      }
+	      double solMove = up-saveSolval;
+	      double boundChange;
+	      /* restore all */
+              int nCliquesAffected=0;
+	      for (istackC=nstackC-1;istackC>=0;istackC--) {
+		int icol=stackC[istackC];
+		double oldU=saveU[istackC];
+		double oldL=saveL[istackC];
+		if(goingToTrueBound==2&&istackC) {
+                  // Work for extending cliques
+                  if (!mode_&&numberCliques_&&iway==3) {
+                    int i_01 = to_01[icol];
+                    if (i_01>=0) {
+                      int start;
+                      int end;
+                      if (colLower[icol]) {
+                        // going up - but we want weak way
+                        start = zeroFixStart_[icol];
+                        end = endFixStart_[icol];
+                      } else {
+                        // going down - but we want weak way
+                        start = oneFixStart_[icol];
+                        end = zeroFixStart_[icol];
+                      }
+                      //if (end>start)
+                      //printf("up j %d, other %d is in %d cliques\n",
+                      //     j,i_01,end-start);
+                      for (int i=start;i<end;i++) {
+                        int iClique = whichClique_[i];
+                        int size = cliqueStart_[iClique+1]-cliqueStart_[iClique];
+                        if (cliqueCount[iClique]==size) {
+                          // first time
+                          cliqueStack[nCliquesAffected++]=iClique;
+                        }
+                        // decrement counts
+                        cliqueCount[iClique]--;
+                      }
+                    }
+                  }
+		  // upper disaggregation cut would be
+		  // xval < upper + (old_upper-upper) (up-jval)
+		  boundChange = oldU-colUpper[icol];
+		  if (boundChange>0.0&&oldU<1.0e10&&
+		      (!mode_||colsol[icol]>colUpper[icol]
+		      + boundChange*solMove+primalTolerance_)) {
+		    // create cut
+		    OsiRowCut rc;
+		    rc.setLb(-COIN_DBL_MAX);
+		    rc.setUb(colUpper[icol]+up*boundChange);
+		    index[0]=icol;
+		    element[0]=1.0;
+		    index[1]=j;
+		    element[1]= + boundChange;
+		    // effectiveness is how far j moves
+		    double newSol = (colsol[icol]-colUpper[icol])/
+		      boundChange;
+		    if (mode_)
+		      assert(newSol>solMove);
+		    rc.setEffectiveness(newSol-solMove);
+		    if (rc.effectiveness()>disaggEffectiveness) {
+		      rc.setRow(2,index,element,false);
+#ifdef CGL_DEBUG
+		      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+		      rowCut.addCutIfNotDuplicate(rc);
+		    }
+		  }
+		  // lower disaggregation cut would be
+		  // xval > lower + (old_lower-lower) (up-jval)
+		  boundChange = oldL-colLower[icol];
+		  if (boundChange<0.0&&oldL>-1.0e10&&
+		      (!mode_||colsol[icol]<colLower[icol]
+		      + boundChange*solMove-primalTolerance_)) {
+		    // create cut
+		    OsiRowCut rc;
+		    rc.setLb(colLower[icol]+up*boundChange);
+		    rc.setUb(COIN_DBL_MAX);
+		    index[0]=icol;
+		    element[0]=1.0;
+		    index[1]=j;
+		    element[1]= + boundChange;
+		    // effectiveness is how far j moves
+		    double newSol = (colsol[icol]-colLower[icol])/
+		      boundChange;
+		    if (mode_)
+		      assert(newSol>solMove);
+		    rc.setEffectiveness(newSol-solMove);
+		    if (rc.effectiveness()>disaggEffectiveness) {
+		      rc.setRow(2,index,element,false);
+#ifdef CGL_DEBUG
+		      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+		      rowCut.addCutIfNotDuplicate(rc);
+		    }
+		  }
+		}
+		colUpper[icol]=oldU;
+		colLower[icol]=oldL;
+                if (oldU>oldL+1.0e-4)
+                  markC[icol]=0;
+                else
+                  markC[icol]=3;
+	      }
+              if (nCliquesAffected) {
+                for (int i=0;i<nCliquesAffected;i++) {
+                  int iClique = cliqueStack[i];
+                  int size = cliqueCount[iClique];
+                  // restore
+                  cliqueCount[iClique]= cliqueStart_[iClique+1]-cliqueStart_[iClique];
+                  if (!size) {
+                    if (logLevel_>1)
+                      printf("** could extend clique by adding j!\n");
+                  }
+                }
+              }
+	      for (istackR=0;istackR<nstackR;istackR++) {
+		int irow=stackR[istackR];
+		// switch off strengthening if not wanted
+		if ((rowCuts&2)!=0&&goingToTrueBound) {
+		  bool ifCut=anyColumnCuts;
+		  double gap = rowUpper[irow]-maxR[irow];
+		  double sum=0.0;
+		  if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+		    // see if the strengthened row is a cut
+		    for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			 kk++) {
+		      sum += rowElements[kk]*colsol[column[kk]];
+		    }
+		    if (sum+gap*colsol[j]>rowUpper[irow]+primalTolerance_||(info->strengthenRow&&rowLower[irow]<-1.0e20)) {
+		      // can be a cut
+		      // add gap to integer coefficient
+		      // saveU and saveL spare
+		      int * index = reinterpret_cast<int *>(saveL);
+		      double * element = saveU;
+		      int n=0;
+                      bool coefficientExists=false;
+		      for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			   kk++) {
+			if (column[kk]!=j) {
+			  index[n]=column[kk];
+			  element[n++]=rowElements[kk];
+			} else {
+			  double value=rowElements[kk]+gap;
+			  if (fabs(value)>1.0e-12) {
+			    index[n]=column[kk];
+			    element[n++]=value;
+			  }
+			  coefficientExists=true;
+			}
+		      }
+		      if (!coefficientExists) {
+			index[n]=j;
+			element[n++]=gap;
+		      }
+		      OsiRowCut rc;
+		      rc.setLb(-COIN_DBL_MAX);
+		      rc.setUb(rowUpper[irow]+gap*(colUpper[j]-1.0));
+		      // effectiveness is how far j moves
+		      rc.setEffectiveness((sum+gap*colsol[j]-rowUpper[irow])/gap);
+		      if (rc.effectiveness()>needEffectiveness) {
+			rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+			if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                        //if(info->strengthenRow)
+                        //printf("c point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      if (rowLower[irow]<-1.0e20) {
+			printf("7Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow]+rowLength[irow];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+		      int realRow = (rowLower[irow]<-1.0e20) ? irow : -1;
+		      if (realRows&&realRow>0)
+			realRow=realRows[realRow];
+			rowCut.addCutIfNotDuplicate(rc,realRow);
+		      }
+		    }
+		  }
+		  gap = minR[irow]-rowLower[irow];
+		  if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+		    // see if the strengthened row is a cut
+		    if (!sum) {
+		      for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			   kk++) {
+			sum += rowElements[kk]*colsol[column[kk]];
+		      }
+		    }
+		    if (sum-gap*colsol[j]<rowLower[irow]+primalTolerance_||(info->strengthenRow&&rowUpper[irow]>1.0e20)) {
+		      // can be a cut
+		      // subtract gap from integer coefficient
+		      // saveU and saveL spare
+		      int * index = reinterpret_cast<int *>(saveL);
+		      double * element = saveU;
+		      int n=0;
+                      bool coefficientExists=false;
+		      for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			   kk++) {
+			if (column[kk]!=j) {
+			  index[n]=column[kk];
+			  element[n++]=rowElements[kk];
+			} else {
+			  double value=rowElements[kk]-gap;
+			  if (fabs(value)>1.0e-12) {
+			    index[n]=column[kk];
+			    element[n++]=value;
+			  }
+			  coefficientExists=true;
+			}
+		      }
+		      if (!coefficientExists) {
+			index[n]=j;
+			element[n++]=-gap;
+		      }
+		      OsiRowCut rc;
+		      rc.setLb(rowLower[irow]-gap*(colUpper[j]-1));
+		      rc.setUb(COIN_DBL_MAX);
+		      // effectiveness is how far j moves
+		      rc.setEffectiveness((rowLower[irow]-sum+gap*colsol[j])/gap);
+		      if (rc.effectiveness()>needEffectiveness) {
+			rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+			if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                        //if(info->strengthenRow)
+                        //printf("d point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      if (rowUpper[irow]>1.0e20) {
+			printf("8Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow]+rowLength[irow];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+		      int realRow = (rowUpper[irow]>1.0e20) ? irow : -1;
+		      if (realRows&&realRow>0)
+			realRow=realRows[realRow];
+			rowCut.addCutIfNotDuplicate(rc,realRow);
+		      }
+		    }
+		  }
+		}
+		minR[irow]=saveMin[istackR];
+		maxR[irow]=saveMax[istackR];
+		markR[irow]=-1;
+	      }
+	    }
+	  }
+	}
+      }
+    }
+  }
+  delete [] cliqueStack;
+  delete [] cliqueCount;
+  delete [] to_01;
+  delete [] stackC0;
+  delete [] lo0;
+  delete [] up0;
+  delete [] tempL;
+  delete [] tempU;
+  delete [] markC;
+  delete [] stackC;
+  delete [] stackR;
+  delete [] saveL;
+  delete [] saveU;
+  delete [] saveMin;
+  delete [] saveMax;
+  delete [] index;
+  delete [] element;
+  delete [] djs;
+  delete [] colsol;
+  // Add in row cuts
+  if (!ninfeas) {
+    rowCut.addCuts(cs,info->strengthenRow,0);
+  }
+  return (ninfeas);
+}
+// Does probing and adding cuts for clique slacks
+int 
+CglProbing::probeSlacks( const OsiSolverInterface & si, 
+                          const OsiRowCutDebugger * 
+#ifdef CGL_DEBUG
+			 debugger
+#endif
+			 ,OsiCuts & cs, 
+                          double * colLower, double * colUpper, CoinPackedMatrix *rowCopy,
+			 CoinPackedMatrix *columnCopy,
+                          double * rowLower, double * rowUpper,
+                          char * intVar, double * minR, double * maxR,int * markR,
+                          CglTreeInfo * info)
+{
+  if (!numberCliques_)
+    return 0;
+  // Set up maxes
+  int maxProbe = info->inTree ? maxProbe_ : maxProbeRoot_;
+  int maxStack = info->inTree ? maxStack_ : maxStackRoot_;
+  int nRows=rowCopy->getNumRows();
+  int nCols=rowCopy->getNumCols();
+  double * colsol = new double[nCols];
+  CoinMemcpyN( si.getColSolution(),nCols,colsol);
+  int rowCuts=rowCuts_;
+  double_int_pair * array = new double_int_pair [numberCliques_];
+  // look at <= cliques
+  int iClique;
+  int nLook=0;
+  for (iClique=0;iClique<numberCliques_;iClique++) {
+    if (!cliqueType_[iClique].equality) {
+      double sum=0.0;
+      for (int j=cliqueStart_[iClique];j<cliqueStart_[iClique+1];j++) {
+        int iColumn = sequenceInCliqueEntry(cliqueEntry_[j]);
+        double value = colsol[iColumn];
+        if (oneFixesInCliqueEntry(cliqueEntry_[j]))
+          sum += value;
+        else
+          sum -= value;
+      }
+      double away = fabs(0.5-(sum-floor(sum)));
+      if (away<0.49999) {
+        array[nLook].infeasibility=away;
+        array[nLook++].sequence=iClique;
+      }
+    }
+  }
+  std::sort(array,array+nLook,double_int_pair_compare());
+  nLook=CoinMin(nLook,maxProbe);
+  const double * currentColLower = si.getColLower();
+  const double * currentColUpper = si.getColUpper();
+  double * tempL = new double [nCols];
+  double * tempU = new double [nCols];
+  int * markC = new int [nCols];
+  int * stackC = new int [2*nCols];
+  int * stackR = new int [nRows];
+  double * saveL = new double [2*nCols];
+  double * saveU = new double [2*nCols];
+  double * saveMin = new double [nRows];
+  double * saveMax = new double [nRows];
+  double * element = new double[nCols];
+  int * index = new int[nCols];
+  // Let us never add more than twice the number of rows worth of row cuts
+  // Keep cuts out of cs until end so we can find duplicates quickly
+  int nRowsFake = info->inTree ? nRows/3 : nRows;
+  row_cut rowCut(nRowsFake, !info->inTree);
+  const int * column = rowCopy->getIndices();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const int * rowLength = rowCopy->getVectorLengths(); 
+  const double * rowElements = rowCopy->getElements();
+  const int * row = columnCopy->getIndices();
+  const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+  const int * columnLength = columnCopy->getVectorLengths(); 
+  const double * columnElements = columnCopy->getElements();
+  double movement;
+  int i, j, k,kk,jj;
+  int kcol,irow,krow;
+  bool anyColumnCuts=false;
+  double dbound, value, value2;
+  int ninfeas=0;
+  for (i = 0; i < nCols; ++i) {
+    if (colUpper[i]-colLower[i]>1.0e-8) {
+      if (colsol[i]<colLower[i]+primalTolerance_) {
+        colsol[i]=colLower[i];
+      } else if (colsol[i]>colUpper[i]-primalTolerance_) {
+        colsol[i]=colUpper[i];
+      }
+    }
+  }
+
+  int ipass=0,nfixed=-1;
+
+  /* for both way coding */
+  int nstackC0=-1;
+  int * stackC0 = new int[maxStack];
+  double * lo0 = new double[maxStack];
+  double * up0 = new double[maxStack];
+  int nstackR,nstackC;
+  for (i=0;i<nCols;i++) {
+    if (colUpper[i]-colLower[i]<1.0e-8) {
+      markC[i]=3;
+    } else {
+      markC[i]=0;
+    }
+  }
+  double tolerance = 1.0e1*primalTolerance_;
+  // If we are going to replace coefficient then we don't need to be effective
+  int maxPass = info->inTree ? maxPass_ : maxPassRoot_;
+  double needEffectiveness = info->strengthenRow ? -1.0e10 : 1.0e-3;
+  while (ipass<maxPass&&nfixed) {
+    int iLook;
+    ipass++;
+    nfixed=0;
+    for (iLook=0;iLook<nLook;iLook++) {
+      double solval;
+      double down;
+      double up;
+      int iClique=array[iLook].sequence;
+      solval=0.0;
+      j=0;
+      for (j=cliqueStart_[iClique];j<cliqueStart_[iClique+1];j++) {
+        int iColumn = sequenceInCliqueEntry(cliqueEntry_[j]);
+        double value = colsol[iColumn];
+        if (oneFixesInCliqueEntry(cliqueEntry_[j]))
+          solval += value;
+        else
+          solval -= value;
+      }
+      down = floor(solval+tolerance);
+      up = ceil(solval-tolerance);
+      int istackC,iway, istackR;
+      int way[]={1,2,1};
+      int feas[]={1,2,4};
+      int feasible=0;
+      int notFeasible;
+      for (iway=0;iway<3;iway ++) {
+        int fixThis=0;
+        stackC[0]=j;
+        markC[j]=way[iway];
+        if (way[iway]==1) {
+          movement=down-colUpper[j];
+          assert(movement<-0.99999);
+          down=colLower[j];
+        } else {
+          movement=up-colLower[j];
+          assert(movement>0.99999);
+          up=colUpper[j];
+        }
+        nstackC=1;
+        nstackR=0;
+        saveL[0]=colLower[j];
+        saveU[0]=colUpper[j];
+        assert (saveU[0]>saveL[0]);
+        notFeasible=0;
+        if (movement<0.0) {
+          colUpper[j] += movement;
+          colUpper[j] = floor(colUpper[j]+0.5);
+#ifdef PRINT_DEBUG
+          printf("** Trying %d down to 0\n",j);
+#endif
+        } else {
+          colLower[j] += movement;
+          colLower[j] = floor(colLower[j]+0.5);
+#ifdef PRINT_DEBUG
+          printf("** Trying %d up to 1\n",j);
+#endif
+        }
+        if (fabs(colUpper[j]-colLower[j])<1.0e-6) 
+          markC[j]=3; // say fixed
+        istackC=0;
+        /* update immediately */
+        for (k=columnStart[j];k<columnStart[j]+columnLength[j];k++) {
+          int irow = row[k];
+          value = columnElements[k];
+          if (markR[irow]==-1) {
+            stackR[nstackR]=irow;
+            markR[irow]=nstackR;
+            saveMin[nstackR]=minR[irow];
+            saveMax[nstackR]=maxR[irow];
+            nstackR++;
+          } else if (markR[irow]==-2) {
+            continue;
+          }
+          /* could check immediately if violation */
+          if (movement>0.0) {
+            /* up */
+            if (value>0.0) {
+              /* up does not change - down does */
+              if (minR[irow]>-1.0e10)
+                minR[irow] += value;
+              if (minR[irow]>rowUpper[irow]+1.0e-5) {
+                notFeasible=1;
+                istackC=1;
+                break;
+              }
+            } else {
+              /* down does not change - up does */
+              if (maxR[irow]<1.0e10)
+                maxR[irow] += value;
+              if (maxR[irow]<rowLower[irow]-1.0e-5) {
+                notFeasible=1;
+                istackC=1;
+                break;
+              }
+            }
+          } else {
+            /* down */
+            if (value<0.0) {
+              /* up does not change - down does */
+              if (minR[irow]>-1.0e10)
+                minR[irow] -= value;
+              if (minR[irow]>rowUpper[irow]+1.0e-5) {
+                notFeasible=1;
+                istackC=1;
+                break;
+              }
+            } else {
+              /* down does not change - up does */
+              if (maxR[irow]<1.0e10)
+                maxR[irow] -= value;
+              if (maxR[irow]<rowLower[irow]-1.0e-5) {
+                notFeasible=1;
+                istackC=1;
+                break;
+              }
+            }
+          }
+        }
+        while (istackC<nstackC&&nstackC<maxStack) {
+          int jway;
+          int jcol =stackC[istackC];
+          jway=markC[jcol];
+          // If not first and fixed then skip
+          if (jway==3&&istackC) {
+            //istackC++;
+            //continue;
+            //printf("fixed %d on stack\n",jcol);
+          }
+          // Do cliques
+          if (oneFixStart_&&oneFixStart_[jcol]>=0) {
+            int start;
+            int end;
+            if (colLower[jcol]>saveL[istackC]) {
+              // going up
+              start = oneFixStart_[jcol];
+              end = zeroFixStart_[jcol];
+            } else {
+              assert (colUpper[jcol]<saveU[istackC]);
+              // going down
+              start = zeroFixStart_[jcol];
+              end = endFixStart_[jcol];
+            }
+            for (int i=start;i<end;i++) {
+              int iClique = whichClique_[i];
+              for (int k=cliqueStart_[iClique];k<cliqueStart_[iClique+1];k++) {
+                int kcol = sequenceInCliqueEntry(cliqueEntry_[k]);
+                if (jcol==kcol)
+                  continue;
+                int kway = oneFixesInCliqueEntry(cliqueEntry_[k]);
+                if (kcol!=jcol) {
+                  if (!markC[kcol]) {
+                    // not on list yet
+                    if (nstackC<2*maxStack) {
+                      markC[kcol] = 3; // say fixed
+                      fixThis++;
+                      stackC[nstackC]=kcol;
+                      saveL[nstackC]=colLower[kcol];
+                      saveU[nstackC]=colUpper[kcol];
+                      assert (saveU[nstackC]>saveL[nstackC]);
+                      nstackC++;
+                      if (!kway) {
+                        // going up
+                        colLower[kcol]=1.0;
+                        /* update immediately */
+                        for (jj=columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+                          krow = row[jj];
+                          value = columnElements[jj];
+                          if (markR[krow]==-1) {
+                            stackR[nstackR]=krow;
+                            markR[krow]=nstackR;
+                            saveMin[nstackR]=minR[krow];
+                            saveMax[nstackR]=maxR[krow];
+                            nstackR++;
+                          } else if (markR[krow]==-2) {
+                            continue;
+                          }
+                          /* could check immediately if violation */
+                          /* up */
+                          if (value>0.0) {
+                            /* up does not change - down does */
+                            if (minR[krow]>-1.0e10)
+                              minR[krow] += value;
+                            if (minR[krow]>rowUpper[krow]+1.0e-5) {
+                              colUpper[kcol]=-1.0e50; /* force infeasible */
+                              break;
+                            }
+                          } else {
+                            /* down does not change - up does */
+                            if (maxR[krow]<1.0e10)
+                              maxR[krow] += value;
+                            if (maxR[krow]<rowLower[krow]-1.0e-5) {
+                              notFeasible=1;
+                              break;
+                            }
+                          }
+                        }
+                      } else {
+                        // going down
+                        colUpper[kcol]=0.0;
+                        /* update immediately */
+                        for (jj=columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+                          krow = row[jj];
+                          value = columnElements[jj];
+                          if (markR[krow]==-1) {
+                            stackR[nstackR]=krow;
+                            markR[krow]=nstackR;
+                            saveMin[nstackR]=minR[krow];
+                            saveMax[nstackR]=maxR[krow];
+                            nstackR++;
+                          } else if (markR[krow]==-2) {
+                            continue;
+                          }
+                          /* could check immediately if violation */
+                          /* down */
+                          if (value<0.0) {
+                            /* up does not change - down does */
+                            if (minR[krow]>-1.0e10)
+                              minR[krow] -= value;
+                            if (minR[krow]>rowUpper[krow]+1.0e-5) {
+                              notFeasible=1;
+                              break;
+                            }
+                          } else {
+                            /* down does not change - up does */
+                            if (maxR[krow]<1.0e10)
+                              maxR[krow] -= value;
+                            if (maxR[krow]<rowLower[krow]-1.0e-5) {
+                              notFeasible=1;
+                              break;
+                            }
+                          }
+                        }
+                      }
+                    }
+                  } else if (markC[kcol]==1) {
+                    // marked as going to 0
+                    assert (!colUpper[kcol]);
+                    if (!kway) {
+                      // contradiction
+                      notFeasible=1;
+                      break;
+                    }
+                  } else if (markC[kcol]==2) {
+                    // marked as going to 1
+                    assert (colLower[kcol]);
+                    if (kway) {
+                      // contradiction
+                      notFeasible=1;
+                      break;
+                    }
+                  } else {
+                    // marked as fixed
+                    assert (markC[kcol]==3);
+                    int jkway;
+                    if (colLower[kcol])
+                      jkway=1;
+                    else
+                      jkway=0;
+                    if (kway==jkway) {
+                      // contradiction
+                      notFeasible=1;
+                      break;
+                    }
+                  }
+                }
+              }
+              if (notFeasible)
+                break;
+            }
+            if (notFeasible)
+              istackC=nstackC+1;
+          }
+          for (k=columnStart[jcol];k<columnStart[jcol]+columnLength[jcol];k++) {
+            // break if found not feasible
+            if (notFeasible)
+              break;
+            irow = row[k];
+            /*value = columnElements[k];*/
+            if (markR[irow]!=-2) {
+              /* see if anything forced */
+              for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];kk++) {
+                double moveUp=0.0;
+                double moveDown=0.0;
+                double newUpper=-1.0,newLower=1.0;
+                kcol=column[kk];
+                bool onList = (markC[kcol]!=0);
+                if (markC[kcol]!=3) {
+                  value2=rowElements[kk];
+                  int markIt=markC[kcol];
+                  if (value2 < 0.0) {
+                    if (colUpper[kcol] < 1e10 && (markIt&2)==0 &&
+                        rowUpper[irow]<1.0e10) {
+                      dbound = colUpper[kcol]+
+                        (rowUpper[irow]-minR[irow])/value2;
+                      if (dbound > colLower[kcol] + primalTolerance_) {
+                        if (intVar[kcol]) {
+                          markIt |= 2;
+                          newLower = ceil(dbound-primalTolerance_);
+                        } else {
+                          newLower=dbound;
+                          if (newLower+primalTolerance_>colUpper[kcol]&&
+                              newLower-primalTolerance_<=colUpper[kcol]) {
+                            newLower=colUpper[kcol];
+                            markIt |= 2;
+                            markIt=3;
+                          } else {
+                            // avoid problems - fix later ?
+                            markIt=3;
+                          }
+                        }
+                        moveUp = newLower-colLower[kcol];
+                      }
+                    }
+                    if (colLower[kcol] > -1e10 && (markIt&1)==0 &&
+                        rowLower[irow]>-1.0e10) {
+                      dbound = colLower[kcol] + 
+                        (rowLower[irow]-maxR[irow])/value2;
+                      if (dbound < colUpper[kcol] - primalTolerance_) {
+                        if (intVar[kcol]) {
+                          markIt |= 1;
+                          newUpper = floor(dbound+primalTolerance_);
+                        } else {
+                          newUpper=dbound;
+                          if (newUpper-primalTolerance_<colLower[kcol]&&
+                              newUpper+primalTolerance_>=colLower[kcol]) {
+                            newUpper=colLower[kcol];
+                            markIt |= 1;
+                            markIt=3;
+                          } else {
+                            // avoid problems - fix later ?
+                            markIt=3;
+                          }
+                        }
+                        moveDown = newUpper-colUpper[kcol];
+                      }
+                    }
+                  } else {
+                    /* positive element */
+                    if (colUpper[kcol] < 1e10 && (markIt&2)==0 &&
+                        rowLower[irow]>-1.0e10) {
+                      dbound = colUpper[kcol] + 
+                        (rowLower[irow]-maxR[irow])/value2;
+                      if (dbound > colLower[kcol] + primalTolerance_) {
+                        if (intVar[kcol]) {
+                          markIt |= 2;
+                          newLower = ceil(dbound-primalTolerance_);
+                        } else {
+                          newLower=dbound;
+                          if (newLower+primalTolerance_>colUpper[kcol]&&
+                              newLower-primalTolerance_<=colUpper[kcol]) {
+                            newLower=colUpper[kcol];
+                            markIt |= 2;
+                            markIt=3;
+                          } else {
+                            // avoid problems - fix later ?
+                            markIt=3;
+                          }
+                        }
+                        moveUp = newLower-colLower[kcol];
+                      }
+                    }
+                    if (colLower[kcol] > -1e10 && (markIt&1)==0 &&
+                        rowUpper[irow]<1.0e10) {
+                      dbound = colLower[kcol] + 
+                        (rowUpper[irow]-minR[irow])/value2;
+                      if (dbound < colUpper[kcol] - primalTolerance_) {
+                        if (intVar[kcol]) {
+                          markIt |= 1;
+                          newUpper = floor(dbound+primalTolerance_);
+                        } else {
+                          newUpper=dbound;
+                          if (newUpper-primalTolerance_<colLower[kcol]&&
+                              newUpper+primalTolerance_>=colLower[kcol]) {
+                            newUpper=colLower[kcol];
+                            markIt |= 1;
+                            markIt=3;
+                          } else {
+                            // avoid problems - fix later ?
+                            markIt=3;
+                          }
+                        }
+                        moveDown = newUpper-colUpper[kcol];
+                      }
+                    }
+                  }
+                  if (nstackC<2*maxStack) {
+                    markC[kcol] = markIt;
+		  }
+                  if (moveUp&&nstackC<2*maxStack) {
+                    fixThis++;
+#ifdef PRINT_DEBUG
+                    printf("lower bound on %d increased from %g to %g by row %d %g %g\n",kcol,colLower[kcol],newLower,irow,rowLower[irow],rowUpper[irow]);
+                    value=0.0;
+                    for (jj=rowStart[irow];jj<rowStart[irow]+rowLength[irow];jj++) {
+                      int ii=column[jj];
+                      if (colUpper[ii]-colLower[ii]>primalTolerance_) {
+                        printf("(%d, %g) ",ii,rowElements[jj]);
+                      } else {
+                        value += rowElements[jj]*colLower[ii];
+                      }
+                    }
+                    printf(" - fixed %g\n",value);
+                    for (jj=rowStart[irow];jj<rowStart[irow]+rowLength[irow];jj++) {
+                      int ii=column[jj];
+                      if (colUpper[ii]-colLower[ii]<primalTolerance_) {
+                        printf("(%d, %g, %g) ",ii,rowElements[jj],colLower[ii]);
+                      }
+                    }
+                    printf("\n");
+#endif
+                    if (!onList) {
+                      stackC[nstackC]=kcol;
+                      saveL[nstackC]=colLower[kcol];
+                      saveU[nstackC]=colUpper[kcol];
+                      assert (saveU[nstackC]>saveL[nstackC]);
+                      nstackC++;
+                      onList=true;
+                    }
+                    if (intVar[kcol])
+                      newLower = CoinMax(colLower[kcol],ceil(newLower-1.0e-4));
+                    colLower[kcol]=newLower;
+                    if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+                      markC[kcol]=3; // say fixed
+		    }
+                    /* update immediately */
+                    for (jj=columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+                      krow = row[jj];
+                      value = columnElements[jj];
+                      if (markR[krow]==-1) {
+                        stackR[nstackR]=krow;
+                        markR[krow]=nstackR;
+                        saveMin[nstackR]=minR[krow];
+                        saveMax[nstackR]=maxR[krow];
+                        nstackR++;
+                      } else if (markR[krow]==-2) {
+                        continue;
+                      }
+                      /* could check immediately if violation */
+                      /* up */
+                      if (value>0.0) {
+                        /* up does not change - down does */
+                        if (minR[krow]>-1.0e10)
+                          minR[krow] += value*moveUp;
+                        if (minR[krow]>rowUpper[krow]+1.0e-5) {
+                          colUpper[kcol]=-1.0e50; /* force infeasible */
+                          break;
+                        }
+                      } else {
+                        /* down does not change - up does */
+                        if (maxR[krow]<1.0e10)
+                          maxR[krow] += value*moveUp;
+                        if (maxR[krow]<rowLower[krow]-1.0e-5) {
+                          colUpper[kcol]=-1.0e50; /* force infeasible */
+                          break;
+                        }
+                      }
+                    }
+                  }
+                  if (moveDown&&nstackC<2*maxStack) {
+                    fixThis++;
+#ifdef PRINT_DEBUG
+                    printf("upper bound on %d decreased from %g to %g by row %d %g %g\n",kcol,colUpper[kcol],newUpper,irow,rowLower[irow],rowUpper[irow]);
+                    value=0.0;
+                    for (jj=rowStart[irow];jj<rowStart[irow]+rowLength[irow];jj++) {
+                      int ii=column[jj];
+                      if (colUpper[ii]-colLower[ii]>primalTolerance_) {
+                        printf("(%d, %g) ",ii,rowElements[jj]);
+                      } else {
+                        value += rowElements[jj]*colLower[ii];
+                      }
+                    }
+                    printf(" - fixed %g\n",value);
+                    for (jj=rowStart[irow];jj<rowStart[irow]+rowLength[irow];jj++) {
+                      int ii=column[jj];
+                      if (colUpper[ii]-colLower[ii]<primalTolerance_) {
+                        printf("(%d, %g, %g) ",ii,rowElements[jj],colLower[ii]);
+                      }
+                    }
+                    printf("\n");
+#endif
+                    if (!onList) {
+                      stackC[nstackC]=kcol;
+                      saveL[nstackC]=colLower[kcol];
+                      saveU[nstackC]=colUpper[kcol];
+                      assert (saveU[nstackC]>saveL[nstackC]);
+                      nstackC++;
+                      onList=true;
+                    }
+                    if (intVar[kcol])
+                      newUpper = CoinMin(colUpper[kcol],floor(newUpper+1.0e-4));
+                    colUpper[kcol]=newUpper;
+                    if (fabs(colUpper[kcol]-colLower[kcol])<1.0e-6) {
+                      markC[kcol]=3; // say fixed
+		    }
+                    /* update immediately */
+                    for (jj=columnStart[kcol];jj<columnStart[kcol]+columnLength[kcol];jj++) {
+                      krow = row[jj];
+                      value = columnElements[jj];
+                      if (markR[krow]==-1) {
+                        stackR[nstackR]=krow;
+                        markR[krow]=nstackR;
+                        saveMin[nstackR]=minR[krow];
+                        saveMax[nstackR]=maxR[krow];
+                        nstackR++;
+                      } else if (markR[krow]==-2) {
+                        continue;
+                      }
+                      /* could check immediately if violation */
+                      /* down */
+                      if (value<0.0) {
+                        /* up does not change - down does */
+                        if (minR[krow]>-1.0e10)
+                          minR[krow] += value*moveDown;
+                        if (minR[krow]>rowUpper[krow]+1.0e-5) {
+                          colUpper[kcol]=-1.0e50; /* force infeasible */
+                          break;
+                        }
+                      } else {
+                        /* down does not change - up does */
+                        if (maxR[krow]<1.0e10)
+                          maxR[krow] += value*moveDown;
+                        if (maxR[krow]<rowLower[krow]-1.0e-5) {
+                          colUpper[kcol]=-1.0e50; /* force infeasible */
+                          break;
+                        }
+                      }
+                    }
+                  }
+                  if (colLower[kcol]>colUpper[kcol]+primalTolerance_) {
+                    notFeasible=1;;
+                    k=columnStart[jcol]+columnLength[jcol];
+                    istackC=nstackC+1;
+#ifdef PRINT_DEBUG
+                    printf("** not feasible this way\n");
+#endif
+                    break;
+                  }
+                }
+              }
+            }
+          }
+          istackC++;
+        }
+        if (!notFeasible) {
+          feasible |= feas[iway];
+        } else if (iway==1&&feasible==0) {
+          /* not feasible at all */
+          ninfeas=1;
+          j=nCols-1;
+          iLook=nLook;
+          ipass=maxPass;
+          break;
+        }
+        if (iway==2||(iway==1&&feasible==2)) {
+          /* keep */
+          iway=3;
+          nfixed++;
+          if (mode_) {
+            OsiColCut cc;
+            int nTot=0,nFix=0,nInt=0;
+            bool ifCut=false;
+            for (istackC=0;istackC<nstackC;istackC++) {
+              int icol=stackC[istackC];
+              if (intVar[icol]) {
+                if (colUpper[icol]<currentColUpper[icol]-1.0e-4) {
+                  element[nFix]=colUpper[icol];
+                  index[nFix++]=icol;
+                  nInt++;
+                  if (colsol[icol]>colUpper[icol]+primalTolerance_) {
+                    ifCut=true;
+                    anyColumnCuts=true;
+                  }
+                }
+              }
+            }
+            if (nFix) {
+              nTot=nFix;
+              cc.setUbs(nFix,index,element);
+              nFix=0;
+            }
+            for (istackC=0;istackC<nstackC;istackC++) {
+              int icol=stackC[istackC];
+              if (intVar[icol]) {
+                if (colLower[icol]>currentColLower[icol]+1.0e-4) {
+                  element[nFix]=colLower[icol];
+                  index[nFix++]=icol;
+                  nInt++;
+                  if (colsol[icol]<colLower[icol]-primalTolerance_) {
+                    ifCut=true;
+                    anyColumnCuts=true;
+                  }
+                }
+              }
+            }
+            if (nFix) {
+              nTot+=nFix;
+              cc.setLbs(nFix,index,element);
+            }
+            // could tighten continuous as well
+            if (nInt) {
+              if (ifCut) {
+                cc.setEffectiveness(100.0);
+              } else {
+                cc.setEffectiveness(1.0e-5);
+              }
+#ifdef CGL_DEBUG
+              checkBounds(debugger,cc);
+#endif
+              cs.insert(cc);
+            }
+          }
+          for (istackC=0;istackC<nstackC;istackC++) {
+            int icol=stackC[istackC];
+            if (colUpper[icol]-colLower[icol]>primalTolerance_) {
+              markC[icol]=0;
+            } else {
+              markC[icol]=3;
+            }
+          }
+          for (istackR=0;istackR<nstackR;istackR++) {
+            int irow=stackR[istackR];
+            markR[irow]=-1;
+          }
+        } else {
+          /* is it worth seeing if can increase coefficients
+             or maybe better see if it is a cut */
+          if (iway==0) {
+            nstackC0=CoinMin(nstackC,maxStack);
+            if (notFeasible) {
+              nstackC0=0;
+            } else {
+              for (istackC=0;istackC<nstackC0;istackC++) {
+                int icol=stackC[istackC];
+                stackC0[istackC]=icol;
+                lo0[istackC]=colLower[icol];
+                up0[istackC]=colUpper[icol];
+              }
+            }
+            /* restore all */
+            assert (iway==0);
+            for (istackC=nstackC-1;istackC>=0;istackC--) {
+              int icol=stackC[istackC];
+              double oldU=saveU[istackC];
+              double oldL=saveL[istackC];
+              colUpper[icol]=oldU;
+              colLower[icol]=oldL;
+              markC[icol]=0;
+            }
+            for (istackR=0;istackR<nstackR;istackR++) {
+              int irow=stackR[istackR];
+              // switch off strengthening if not wanted
+              if ((rowCuts&2)!=0) {
+                bool ifCut=anyColumnCuts;
+                double gap = rowUpper[irow]-maxR[irow];
+                double sum=0.0;
+                if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+                  // see if the strengthened row is a cut
+                  for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+                       kk++) {
+                    sum += rowElements[kk]*colsol[column[kk]];
+                  }
+                  if (sum-gap*colsol[j]>maxR[irow]+primalTolerance_||info->strengthenRow) {
+                    // can be a cut
+                    // subtract gap from upper and integer coefficient
+                    // saveU and saveL spare
+                    int * index = reinterpret_cast<int *>(saveL);
+                    double * element = saveU;
+                    int n=0;
+                    bool coefficientExists=false;
+                    for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+                         kk++) {
+                      if (column[kk]!=j) {
+                        index[n]=column[kk];
+                        element[n++]=rowElements[kk];
+                      } else {
+                        double value=rowElements[kk]-gap;
+                        if (fabs(value)>1.0e-12) {
+                          index[n]=column[kk];
+                          element[n++]=value;
+                        }
+                        coefficientExists=true;
+                      }
+                    }
+                    if (!coefficientExists) {
+                      index[n]=j;
+                      element[n++]=-gap;
+                    }
+                    OsiRowCut rc;
+                    rc.setLb(-COIN_DBL_MAX);
+                    rc.setUb(rowUpper[irow]-gap*(colLower[j]+1.0));
+                    // effectiveness is how far j moves
+                    rc.setEffectiveness((sum-gap*colsol[j]-maxR[irow])/gap);
+                    if (rc.effectiveness()>needEffectiveness) {
+                      rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+                      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                      // If strengthenRow point to row
+                      //if(info->strengthenRow)
+                      //printf("a point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      {
+			printf("9Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow]+rowLength[irow];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+                      rowCut.addCutIfNotDuplicate(rc,irow);
+                    }
+                  }
+                }
+                gap = minR[irow]-rowLower[irow];
+                if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+                  // see if the strengthened row is a cut
+                  if (!sum) {
+                    for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+                         kk++) {
+                      sum += rowElements[kk]*colsol[column[kk]];
+                    }
+                  }
+                  if (sum+gap*colsol[j]<minR[irow]+primalTolerance_||info->strengthenRow) {
+                    // can be a cut
+                    // add gap to lower and integer coefficient
+                    // saveU and saveL spare
+                    int * index = reinterpret_cast<int *>(saveL);
+                    double * element = saveU;
+                    int n=0;
+                    bool coefficientExists=false;
+                    for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+                         kk++) {
+                      if (column[kk]!=j) {
+                        index[n]=column[kk];
+                        element[n++]=rowElements[kk];
+                      } else {
+                        double value=rowElements[kk]+gap;
+                        if (fabs(value)>1.0e-12) {
+                          index[n]=column[kk];
+                          element[n++]=value;
+                        }
+                        coefficientExists=true;
+                      }
+                    }
+                    if (!coefficientExists) {
+                      index[n]=j;
+                      element[n++]=gap;
+                    }
+                    OsiRowCut rc;
+                    rc.setLb(rowLower[irow]+gap*(colLower[j]+1.0));
+                    rc.setUb(COIN_DBL_MAX);
+                    // effectiveness is how far j moves
+                    rc.setEffectiveness((minR[irow]-sum-gap*colsol[j])/gap);
+                    if (rc.effectiveness()>needEffectiveness) {
+                      rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+                      if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                      //if(info->strengthenRow)
+                      //printf("b point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      {
+			printf("10Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow]+rowLength[irow];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+                      rowCut.addCutIfNotDuplicate(rc,irow);
+                    }
+                  }
+                }
+              }
+              minR[irow]=saveMin[istackR];
+              maxR[irow]=saveMax[istackR];
+              markR[irow]=-1;
+            }
+          } else {
+            if (iway==1&&feasible==3) {
+              iway=3;
+              /* point back to stack */
+              for (istackC=nstackC-1;istackC>=0;istackC--) {
+                int icol=stackC[istackC];
+                markC[icol]=istackC+1000;
+              }
+              if (mode_) {
+                OsiColCut cc;
+                int nTot=0,nFix=0,nInt=0;
+                bool ifCut=false;
+                for (istackC=0;istackC<nstackC0;istackC++) {
+                  int icol=stackC0[istackC];
+                  int istackC1=markC[icol]-1000;
+                  if (istackC1>=0) {
+                    if (CoinMin(lo0[istackC],colLower[icol])>saveL[istackC1]+1.0e-4) {
+                      saveL[istackC1]=CoinMin(lo0[istackC],colLower[icol]);
+                      if (intVar[icol]) {
+                        element[nFix]=saveL[istackC1];
+                        index[nFix++]=icol;
+                        nInt++;
+                        if (colsol[icol]<saveL[istackC1]-primalTolerance_)
+                          ifCut=true;
+                      }
+                      nfixed++;
+                    }
+                  }
+                }
+                if (nFix) {
+                  nTot=nFix;
+                  cc.setLbs(nFix,index,element);
+                  nFix=0;
+                }
+                for (istackC=0;istackC<nstackC0;istackC++) {
+                  int icol=stackC0[istackC];
+                  int istackC1=markC[icol]-1000;
+                  if (istackC1>=0) {
+                    if (CoinMax(up0[istackC],colUpper[icol])<saveU[istackC1]-1.0e-4) {
+                      saveU[istackC1]=CoinMax(up0[istackC],colUpper[icol]);
+                      if (intVar[icol]) {
+                        element[nFix]=saveU[istackC1];
+                        index[nFix++]=icol;
+                        nInt++;
+                        if (colsol[icol]>saveU[istackC1]+primalTolerance_)
+                          ifCut=true;
+                      }
+                      nfixed++;
+                    }
+                  }
+                }
+                if (nFix) {
+                  nTot+=nFix;
+                  cc.setUbs(nFix,index,element);
+                }
+                // could tighten continuous as well
+                if (nInt) {
+                  if (ifCut) {
+                    cc.setEffectiveness(100.0);
+                  } else {
+                    cc.setEffectiveness(1.0e-5);
+                  }
+#ifdef CGL_DEBUG
+                  checkBounds(debugger,cc);
+#endif
+                  cs.insert(cc);
+                }
+              }
+            }
+            /* restore all */
+            for (istackC=nstackC-1;istackC>=0;istackC--) {
+              int icol=stackC[istackC];
+              double oldU=saveU[istackC];
+              double oldL=saveL[istackC];
+              colUpper[icol]=oldU;
+              colLower[icol]=oldL;
+              if (oldU>oldL+1.0e-4)
+                markC[icol]=0;
+              else
+                markC[icol]=3;
+            }
+            for (istackR=0;istackR<nstackR;istackR++) {
+              int irow=stackR[istackR];
+              // switch off strengthening if not wanted
+              if ((rowCuts&2)!=0) {
+                bool ifCut=anyColumnCuts;
+                double gap = rowUpper[irow]-maxR[irow];
+                double sum=0.0;
+                if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+                  // see if the strengthened row is a cut
+                  for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+                       kk++) {
+                    sum += rowElements[kk]*colsol[column[kk]];
+                  }
+                  if (sum+gap*colsol[j]>rowUpper[irow]+primalTolerance_||info->strengthenRow) {
+                    // can be a cut
+                    // add gap to integer coefficient
+                    // saveU and saveL spare
+                    int * index = reinterpret_cast<int *>(saveL);
+                    double * element = saveU;
+                    int n=0;
+                    bool coefficientExists=false;
+                    for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+                         kk++) {
+                      if (column[kk]!=j) {
+                        index[n]=column[kk];
+                        element[n++]=rowElements[kk];
+			} else {
+			  double value=rowElements[kk]+gap;
+			  if (fabs(value)>1.0e-12) {
+			    index[n]=column[kk];
+			    element[n++]=value;
+			  }
+			  coefficientExists=true;
+			}
+		      }
+		      if (!coefficientExists) {
+			index[n]=j;
+			element[n++]=gap;
+		      }
+		      OsiRowCut rc;
+		      rc.setLb(-COIN_DBL_MAX);
+		      rc.setUb(rowUpper[irow]+gap*(colUpper[j]-1.0));
+		      // effectiveness is how far j moves
+		      rc.setEffectiveness((sum+gap*colsol[j]-rowUpper[irow])/gap);
+		      if (rc.effectiveness()>needEffectiveness) {
+			rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+			if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                        //if(info->strengthenRow)
+                        //printf("c point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      {
+			printf("11Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow]+rowLength[irow];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+			rowCut.addCutIfNotDuplicate(rc,irow);
+		      }
+		    }
+		  }
+		  gap = minR[irow]-rowLower[irow];
+		  if (!ifCut&&(gap>primalTolerance_&&gap<1.0e8)) {
+		    // see if the strengthened row is a cut
+		    if (!sum) {
+		      for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			   kk++) {
+			sum += rowElements[kk]*colsol[column[kk]];
+		      }
+		    }
+		    if (sum-gap*colsol[j]<rowLower[irow]+primalTolerance_||info->strengthenRow) {
+		      // can be a cut
+		      // subtract gap from integer coefficient
+		      // saveU and saveL spare
+		      int * index = reinterpret_cast<int *>(saveL);
+		      double * element = saveU;
+		      int n=0;
+                      bool coefficientExists=false;
+		      for (kk=rowStart[irow];kk<rowStart[irow]+rowLength[irow];
+			   kk++) {
+			if (column[kk]!=j) {
+			  index[n]=column[kk];
+			  element[n++]=rowElements[kk];
+			} else {
+			  double value=rowElements[kk]-gap;
+			  if (fabs(value)>1.0e-12) {
+			    index[n]=column[kk];
+			    element[n++]=value;
+			  }
+			  coefficientExists=true;
+			}
+		      }
+		      if (!coefficientExists) {
+			index[n]=j;
+			element[n++]=-gap;
+		      }
+		      OsiRowCut rc;
+		      rc.setLb(rowLower[irow]-gap*(colUpper[j]-1));
+		      rc.setUb(COIN_DBL_MAX);
+		      // effectiveness is how far j moves
+		      rc.setEffectiveness((rowLower[irow]-sum+gap*colsol[j])/gap);
+		      if (rc.effectiveness()>needEffectiveness) {
+			rc.setRow(n,index,element,false);
+#ifdef CGL_DEBUG
+			if (debugger) assert(!debugger->invalidCut(rc)); 
+#endif
+                        //if(info->strengthenRow)
+                        //printf("d point to row %d\n",irow);
+#ifdef STRENGTHEN_PRINT
+		      {
+			printf("12Cut %g <= ",rc.lb());
+			int k;
+			for ( k=0;k<n;k++) {
+			  int iColumn = index[k];
+			  printf("%g*",element[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rc.ub());
+			printf("Row %g <= ",rowLower[irow]);
+			for (k=rowStart[irow];k<rowStart[irow]+rowLength[irow];k++) {
+			  int iColumn = column[k];
+			  printf("%g*",rowElements[k]);
+			  if (si.isInteger(iColumn))
+			    printf("i%d ",iColumn);
+			  else
+			    printf("x%d ",iColumn);
+			}
+			printf("<= %g\n",rowUpper[irow]);
+		      }
+#endif
+			rowCut.addCutIfNotDuplicate(rc,irow);
+		      }
+		    }
+		  }
+		}
+		minR[irow]=saveMin[istackR];
+		maxR[irow]=saveMax[istackR];
+		markR[irow]=-1;
+	      }
+	    }
+	  }
+        }
+    }
+  }
+  delete [] stackC0;
+  delete [] lo0;
+  delete [] up0;
+  delete [] tempL;
+  delete [] tempU;
+  delete [] markC;
+  delete [] stackC;
+  delete [] stackR;
+  delete [] saveL;
+  delete [] saveU;
+  delete [] saveMin;
+  delete [] saveMax;
+  delete [] index;
+  delete [] element;
+  delete [] colsol;
+  // Add in row cuts
+  if (!ninfeas) {
+    rowCut.addCuts(cs,info->strengthenRow,0);
+  }
+  delete [] array;
+  abort();
+  return (ninfeas);
+}
+// Create a copy of matrix which is to be used
+// this is to speed up process and to give global cuts
+// Can give an array with 1 set to select, 0 to ignore
+// column bounds are tightened
+// If array given then values of 1 will be set to 0 if redundant
+int CglProbing::snapshot ( const OsiSolverInterface & si,
+		  char * possible,bool withObjective)
+{
+  deleteSnapshot();
+  // Get basic problem information
+  
+  numberColumns_=si.getNumCols(); 
+  numberRows_=si.getNumRows();
+  colLower_ = new double[numberColumns_];
+  colUpper_ = new double[numberColumns_];
+  CoinMemcpyN(si.getColLower(),numberColumns_,colLower_);
+  CoinMemcpyN(si.getColUpper(),numberColumns_,colUpper_);
+  rowLower_= new double [numberRows_+1];
+  rowUpper_= new double [numberRows_+1];
+  CoinMemcpyN(si.getRowLower(),numberRows_,rowLower_);
+  CoinMemcpyN(si.getRowUpper(),numberRows_,rowUpper_);
+
+  int i;
+  if (possible) {
+    for (i=0;i<numberRows_;i++) {
+      if (!possible[i]) {
+	rowLower_[i]=-COIN_DBL_MAX;
+	rowUpper_[i]=COIN_DBL_MAX;
+      }
+    }
+  }
+  
+
+  // get integer variables
+  const char * intVarOriginal = si.getColType(true);
+  char * intVar = CoinCopyOfArray(intVarOriginal,numberColumns_);
+  numberIntegers_=0;
+  number01Integers_=0;
+  for (i=0;i<numberColumns_;i++) {
+    if (intVar[i]) {
+      numberIntegers_++;
+      if (intVar[i]==1) {
+        number01Integers_++;
+      }
+    }
+  }
+    
+  rowCopy_ = new CoinPackedMatrix(*si.getMatrixByRow());
+
+  int * column = rowCopy_->getMutableIndices();
+  const CoinBigIndex * rowStart = rowCopy_->getVectorStarts();
+  const int * rowLength = rowCopy_->getVectorLengths(); 
+  double * rowElements = rowCopy_->getMutableElements();
+  // Put negative first
+  int * column2 = new int[numberColumns_];
+  double * elements2 = new double[numberColumns_];
+  CoinBigIndex * rowStartPos = new CoinBigIndex [numberRows_];
+  for (int i=0;i<numberRows_;i++) {
+    CoinBigIndex start = rowStart[i];
+    CoinBigIndex end = start + rowLength[i];
+    int nOther=0;
+    for (CoinBigIndex j=start; j<end ; j++) { 
+      int iColumn = column[j];
+      double value = rowElements[j];
+      if (value<0.0) {
+	rowElements[start]=value;
+	column[start++]=iColumn;
+      } else {
+	elements2[nOther]=value;
+	column2[nOther++]=iColumn;
+      }
+    }
+    rowStartPos[i] = start;
+    for (int k=0;k<nOther;k++) {
+      rowElements[start]=elements2[k];
+      column[start++]=column2[k];
+    }
+  }
+  delete [] column2;
+  delete [] elements2;
+  
+  int returnCode=0;
+  int ninfeas= 
+    tighten(colLower_, colUpper_, column, rowElements,
+	    rowStart, NULL,rowLength, rowLower_, rowUpper_,
+	    numberRows_, numberColumns_, intVar, 5, primalTolerance_);
+  delete [] rowStartPos;
+  if (ninfeas) {
+    // let someone else find out
+    returnCode = 1;
+  }
+/*
+  QUESTION: If ninfeas > 1 (one or more variables infeasible), shouldn't we
+	    bail out here?
+*/
+
+  // do integer stuff for mode 0
+  cutVector_ = new disaggregation [number01Integers_];
+  memset(cutVector_,0,number01Integers_*sizeof(disaggregation));
+  number01Integers_=0;
+  for (i=0;i<numberColumns_;i++) {
+    if (intVar[i]==1)
+      cutVector_[number01Integers_++].sequence=i;
+  }
+  delete [] intVar;
+
+  // now delete rows
+  if (possible) {
+    for (i=0;i<numberRows_;i++) {
+      if (rowLower_[i]<-1.0e30&&rowUpper_[i]>1.0e30) 
+	possible[i]=0;
+    }
+  }
+  int * index = new int[numberRows_];
+  int nDrop=0,nKeep=0;
+  for (i=0;i<numberRows_;i++) {
+    if (rowLower_[i]<-1.0e30&&rowUpper_[i]>1.0e30) {
+      index[nDrop++]=i;
+    } else {
+      rowLower_[nKeep]=rowLower_[i];
+      rowUpper_[nKeep++]=rowUpper_[i];
+    }
+  }
+  numberRows_=nKeep;
+  if (nDrop)
+    rowCopy_->deleteRows(nDrop,index);
+  delete [] index;
+  if (withObjective) {
+    // add in objective 
+    int * columns = new int[numberColumns_];
+    double * elements = new double[numberColumns_];
+    int n=0;
+    const double * objective = si.getObjCoefficients();
+    bool maximize = (si.getObjSense()==-1);
+    for (i=0;i<numberColumns_;i++) {
+      if (objective[i]) {
+        elements[n]= (maximize) ? -objective[i] : objective[i];
+        columns[n++]=i;
+      }
+    }
+    rowCopy_->appendRow(n,columns,elements);
+    delete [] columns;
+    delete [] elements;
+    numberRows_++;
+  }
+  // create column copy
+  if (rowCopy_->getNumElements()) {
+    columnCopy_=new CoinPackedMatrix(*rowCopy_,0,0,true);
+  } else {
+    columnCopy_=new CoinPackedMatrix();
+  }
+  // make sure big enough - in case too many rows dropped
+  columnCopy_->setDimensions(numberRows_,numberColumns_);
+  rowCopy_->setDimensions(numberRows_,numberColumns_);
+  return returnCode;
+}
+// Delete snapshot
+void CglProbing::deleteSnapshot()
+{
+  delete [] rowLower_;
+  delete [] rowUpper_;
+  delete [] colLower_;
+  delete [] colUpper_;
+  delete rowCopy_;
+  delete columnCopy_;
+  rowCopy_=NULL;
+  columnCopy_=NULL;
+  rowLower_=NULL;
+  rowUpper_=NULL;
+  colLower_=NULL;
+  colUpper_=NULL;
+  int i;
+  for (i=0;i<number01Integers_;i++) {
+    delete [] cutVector_[i].index;
+  }
+  delete [] cutVector_;
+  numberIntegers_=0;
+  number01Integers_=0;
+  cutVector_=NULL;
+}
+// Mode stuff
+void CglProbing::setMode(int mode)
+{
+  if (mode>=0&&mode<3) {
+    // take off bottom bit
+    mode_ &= ~15;
+    mode_ |= mode;
+  }
+}
+int CglProbing::getMode() const
+{
+  return mode_&15;
+}
+// Set maximum number of passes per node
+void CglProbing::setMaxPass(int value)
+{
+  if (value>0)
+    maxPass_=value;
+}
+// Get maximum number of passes per node
+int CglProbing::getMaxPass() const
+{
+  return maxPass_;
+}
+// Set log level
+void CglProbing::setLogLevel(int value)
+{
+  if (value>=0)
+    logLevel_=value;
+}
+// Get log level
+int CglProbing::getLogLevel() const
+{
+  return logLevel_;
+}
+// Set maximum number of unsatisfied variables to look at
+void CglProbing::setMaxProbe(int value)
+{
+  if (value>=0)
+    maxProbe_=value;
+}
+// Get maximum number of unsatisfied variables to look at
+int CglProbing::getMaxProbe() const
+{
+  return maxProbe_;
+}
+// Set maximum number of variables to look at in one probe
+void CglProbing::setMaxLook(int value)
+{
+  if (value>=0)
+    maxStack_=value;
+}
+// Get maximum number of variables to look at in one probe
+int CglProbing::getMaxLook() const
+{
+  return maxStack_;
+}
+// Set maximum number of elements in row for scan
+void CglProbing::setMaxElements(int value)
+{
+  if (value>0)
+    maxElements_=value;
+}
+// Get maximum number of elements in row for scan
+int CglProbing::getMaxElements() const
+{
+  return maxElements_;
+}
+// Set maximum number of passes per node (root node)
+void CglProbing::setMaxPassRoot(int value)
+{
+  if (value>0)
+    maxPassRoot_=value;
+}
+// Get maximum number of passes per node (root node)
+int CglProbing::getMaxPassRoot() const
+{
+  return maxPassRoot_;
+}
+// Set maximum number of unsatisfied variables to look at (root node)
+void CglProbing::setMaxProbeRoot(int value)
+{
+  if (value>0)
+    maxProbeRoot_=value;
+}
+// Get maximum number of unsatisfied variables to look at (root node)
+int CglProbing::getMaxProbeRoot() const
+{
+  return maxProbeRoot_;
+}
+// Set maximum number of variables to look at in one probe (root node)
+void CglProbing::setMaxLookRoot(int value)
+{
+  if (value>0)
+    maxStackRoot_=value;
+}
+// Get maximum number of variables to look at in one probe (root node)
+int CglProbing::getMaxLookRoot() const
+{
+  return maxStackRoot_;
+}
+// Set maximum number of elements in row for scan (root node)
+void CglProbing::setMaxElementsRoot(int value)
+{
+  if (value>0)
+    maxElementsRoot_=value;
+}
+// Get maximum number of elements in row for scan (root node)
+int CglProbing::getMaxElementsRoot() const
+{
+  return maxElementsRoot_;
+}
+// Set whether to use objective
+void CglProbing::setUsingObjective(int yesNo)
+{
+  usingObjective_=yesNo;
+}
+// Get whether objective is being used
+int CglProbing::getUsingObjective() const
+{
+  return usingObjective_;
+}
+// Decide whether to do row cuts
+void CglProbing::setRowCuts(int type)
+{
+  if (type>-5&&type<5)
+    rowCuts_=type;
+}
+// Returns row cuts generation type
+int CglProbing::rowCuts() const
+{
+  return rowCuts_;
+}
+// Returns tight lower
+const double * CglProbing::tightLower() const
+{
+  return colLower_;
+}
+// Returns tight upper
+const double * CglProbing::tightUpper() const
+{
+  return colUpper_;
+}
+// Returns relaxed Row lower
+const double * CglProbing::relaxedRowLower() const
+{
+  return rowLower_;
+}
+// Returns relaxed Row upper
+const double * CglProbing::relaxedRowUpper() const
+{
+  return rowUpper_;
+}
+
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglProbing::CglProbing ()
+:
+CglCutGenerator(),
+primalTolerance_(1.0e-07),
+mode_(1),
+rowCuts_(1),
+maxPass_(3),
+logLevel_(0),
+maxProbe_(100),
+maxStack_(50),
+maxElements_(1000),
+maxPassRoot_(3),
+maxProbeRoot_(100),
+maxStackRoot_(50),
+maxElementsRoot_(10000),
+usingObjective_(0)
+{
+
+  numberRows_=0;
+  numberColumns_=0;
+  rowCopy_=NULL;
+  columnCopy_=NULL;
+  rowLower_=NULL;
+  rowUpper_=NULL;
+  colLower_=NULL;
+  colUpper_=NULL;
+  numberIntegers_=0;
+  number01Integers_=0;
+  numberThisTime_=0;
+  totalTimesCalled_=0;
+  lookedAt_=NULL;
+  cutVector_=NULL;
+  numberCliques_=0;
+  cliqueType_=NULL;
+  cliqueStart_=NULL;
+  cliqueEntry_=NULL;
+  oneFixStart_=NULL;
+  zeroFixStart_=NULL;
+  endFixStart_=NULL;
+  whichClique_=NULL;
+  cliqueRow_=NULL;
+  cliqueRowStart_=NULL;
+  tightenBounds_=NULL;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglProbing::CglProbing (  const CglProbing & rhs)
+                                                              :
+  CglCutGenerator(rhs),
+  primalTolerance_(rhs.primalTolerance_),
+  mode_(rhs.mode_),
+  rowCuts_(rhs.rowCuts_),
+  maxPass_(rhs.maxPass_),
+  logLevel_(rhs.logLevel_),
+  maxProbe_(rhs.maxProbe_),
+  maxStack_(rhs.maxStack_),
+  maxElements_(rhs.maxElements_),
+  maxPassRoot_(rhs.maxPassRoot_),
+  maxProbeRoot_(rhs.maxProbeRoot_),
+  maxStackRoot_(rhs.maxStackRoot_),
+  maxElementsRoot_(rhs.maxElementsRoot_),
+  usingObjective_(rhs.usingObjective_)
+{  
+  numberRows_=rhs.numberRows_;
+  numberColumns_=rhs.numberColumns_;
+  numberCliques_=rhs.numberCliques_;
+  if (rhs.rowCopy_) {
+    rowCopy_= new CoinPackedMatrix(*(rhs.rowCopy_));
+    columnCopy_= new CoinPackedMatrix(*(rhs.columnCopy_));
+    rowLower_=new double[numberRows_];
+    CoinMemcpyN(rhs.rowLower_,numberRows_,rowLower_);
+    rowUpper_=new double[numberRows_];
+    CoinMemcpyN(rhs.rowUpper_,numberRows_,rowUpper_);
+    colLower_=new double[numberColumns_];
+    CoinMemcpyN(rhs.colLower_,numberColumns_,colLower_);
+    colUpper_=new double[numberColumns_];
+    CoinMemcpyN(rhs.colUpper_,numberColumns_,colUpper_);
+    int i;
+    numberIntegers_=rhs.numberIntegers_;
+    number01Integers_=rhs.number01Integers_;
+    cutVector_=new disaggregation [number01Integers_];
+    CoinMemcpyN(rhs.cutVector_,number01Integers_,cutVector_);
+    for (i=0;i<number01Integers_;i++) {
+      if (cutVector_[i].index) {
+	cutVector_[i].index = CoinCopyOfArray(rhs.cutVector_[i].index,cutVector_[i].length);
+      }
+    }
+  } else {
+    rowCopy_=NULL;
+    columnCopy_=NULL;
+    rowLower_=NULL;
+    rowUpper_=NULL;
+    colLower_=NULL;
+    colUpper_=NULL;
+    numberIntegers_=0;
+    number01Integers_=0;
+    cutVector_=NULL;
+  }
+  numberThisTime_=rhs.numberThisTime_;
+  totalTimesCalled_=rhs.totalTimesCalled_;
+  if (numberColumns_)
+    lookedAt_=CoinCopyOfArray(rhs.lookedAt_,numberColumns_);
+  else
+    lookedAt_ = NULL;
+  if (numberCliques_) {
+    cliqueType_ = new cliqueType [numberCliques_];
+    CoinMemcpyN(rhs.cliqueType_,numberCliques_,cliqueType_);
+    cliqueStart_ = new int [numberCliques_+1];
+    CoinMemcpyN(rhs.cliqueStart_,(numberCliques_+1),cliqueStart_);
+    int n = cliqueStart_[numberCliques_];
+    cliqueEntry_ = new cliqueEntry [n];
+    CoinMemcpyN(rhs.cliqueEntry_,n,cliqueEntry_);
+    oneFixStart_ = new int [numberColumns_];
+    CoinMemcpyN(rhs.oneFixStart_,numberColumns_,oneFixStart_);
+    zeroFixStart_ = new int [numberColumns_];
+    CoinMemcpyN(rhs.zeroFixStart_,numberColumns_,zeroFixStart_);
+    endFixStart_ = new int [numberColumns_];
+    CoinMemcpyN(rhs.endFixStart_,numberColumns_,endFixStart_);
+#ifndef NDEBUG
+    int n2=-1;
+    for (int i=numberColumns_-1;i>=0;i--) {
+      if (oneFixStart_[i]>=0) {
+	n2=endFixStart_[i];
+	break;
+      }
+    }
+    assert (n==n2);
+#endif
+    whichClique_ = new int [n];
+    CoinMemcpyN(rhs.whichClique_,n,whichClique_);
+    if (rhs.cliqueRowStart_) {
+      cliqueRowStart_ = CoinCopyOfArray(rhs.cliqueRowStart_,numberRows_+1);
+      n=cliqueRowStart_[numberRows_];
+      cliqueRow_ = CoinCopyOfArray(rhs.cliqueRow_,n);
+    } else {
+      cliqueRow_=NULL;
+      cliqueRowStart_=NULL;
+    }
+  } else {
+    cliqueType_=NULL;
+    cliqueStart_=NULL;
+    cliqueEntry_=NULL;
+    oneFixStart_=NULL;
+    zeroFixStart_=NULL;
+    endFixStart_=NULL;
+    cliqueRow_=NULL;
+    cliqueRowStart_=NULL;
+    whichClique_=NULL;
+  }
+  if (rhs.tightenBounds_) {
+    assert (numberColumns_);
+    tightenBounds_=CoinCopyOfArray(rhs.tightenBounds_,numberColumns_);
+  } else {
+    tightenBounds_=NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglProbing::clone() const
+{
+  return new CglProbing(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglProbing::~CglProbing ()
+{
+  // free memory
+  delete [] rowLower_;
+  delete [] rowUpper_;
+  delete [] colLower_;
+  delete [] colUpper_;
+  delete rowCopy_;
+  delete columnCopy_;
+  delete [] lookedAt_;
+  delete [] cliqueType_;
+  delete [] cliqueStart_;
+  delete [] cliqueEntry_;
+  delete [] oneFixStart_;
+  delete [] zeroFixStart_;
+  delete [] endFixStart_;
+  delete [] whichClique_;
+  delete [] cliqueRow_;
+  delete [] cliqueRowStart_;
+  if (cutVector_) {
+    for (int i=0;i<number01Integers_;i++) {
+      delete [] cutVector_[i].index;
+    }
+    delete [] cutVector_;
+  }
+  delete [] tightenBounds_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglProbing &
+CglProbing::operator=(
+                                         const CglProbing& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    primalTolerance_=rhs.primalTolerance_;
+    numberRows_=rhs.numberRows_;
+    numberColumns_=rhs.numberColumns_;
+    delete [] rowLower_;
+    delete [] rowUpper_;
+    delete [] colLower_;
+    delete [] colUpper_;
+    delete rowCopy_;
+    delete columnCopy_;
+    delete [] lookedAt_;
+    delete [] cliqueType_;
+    delete [] cliqueStart_;
+    delete [] cliqueEntry_;
+    delete [] oneFixStart_;
+    delete [] zeroFixStart_;
+    delete [] endFixStart_;
+    delete [] whichClique_;
+    delete [] cliqueRow_;
+    delete [] cliqueRowStart_;
+    delete [] tightenBounds_;
+    mode_=rhs.mode_;
+    rowCuts_=rhs.rowCuts_;
+    maxPass_=rhs.maxPass_;
+    logLevel_=rhs.logLevel_;
+    maxProbe_=rhs.maxProbe_;
+    maxStack_=rhs.maxStack_;
+    maxElements_ = rhs.maxElements_;
+    maxPassRoot_ = rhs.maxPassRoot_;
+    maxProbeRoot_ = rhs.maxProbeRoot_;
+    maxStackRoot_ = rhs.maxStackRoot_;
+    maxElementsRoot_ = rhs.maxElementsRoot_;
+    usingObjective_=rhs.usingObjective_;
+    numberCliques_=rhs.numberCliques_;
+    if (rhs.rowCopy_) {
+      rowCopy_= new CoinPackedMatrix(*(rhs.rowCopy_));
+      columnCopy_= new CoinPackedMatrix(*(rhs.columnCopy_));
+      rowLower_=new double[numberRows_];
+      CoinMemcpyN(rhs.rowLower_,numberRows_,rowLower_);
+      rowUpper_=new double[numberRows_];
+      CoinMemcpyN(rhs.rowUpper_,numberRows_,rowUpper_);
+      colLower_=new double[numberColumns_];
+      CoinMemcpyN(rhs.colLower_,numberColumns_,colLower_);
+      colUpper_=new double[numberColumns_];
+      CoinMemcpyN(rhs.colUpper_,numberColumns_,colUpper_);
+      int i;
+      numberIntegers_=rhs.numberIntegers_;
+      number01Integers_=rhs.number01Integers_;
+      for (i=0;i<number01Integers_;i++) {
+        delete [] cutVector_[i].index;
+      }
+      delete [] cutVector_;
+      cutVector_=new disaggregation [number01Integers_];
+      CoinMemcpyN(rhs.cutVector_,number01Integers_,cutVector_);
+      for (i=0;i<number01Integers_;i++) {
+        if (cutVector_[i].index) {
+          cutVector_[i].index = CoinCopyOfArray(rhs.cutVector_[i].index,cutVector_[i].length);
+        }
+      }
+    } else {
+      rowCopy_=NULL;
+      columnCopy_=NULL;
+      rowLower_=NULL;
+      rowUpper_=NULL;
+      colLower_=NULL;
+      colUpper_=NULL;
+      numberIntegers_=0;
+      number01Integers_=0;
+      cutVector_=NULL;
+    }
+    numberThisTime_=rhs.numberThisTime_;
+    totalTimesCalled_=rhs.totalTimesCalled_;
+    if (numberColumns_)
+      lookedAt_=CoinCopyOfArray(rhs.lookedAt_,numberColumns_);
+    else
+      lookedAt_ = NULL;
+    if (numberCliques_) {
+      cliqueType_ = new cliqueType [numberCliques_];
+      CoinMemcpyN(rhs.cliqueType_,numberCliques_,cliqueType_);
+      cliqueStart_ = new int [numberCliques_+1];
+      CoinMemcpyN(rhs.cliqueStart_,(numberCliques_+1),cliqueStart_);
+      int n = cliqueStart_[numberCliques_];
+      cliqueEntry_ = new cliqueEntry [n];
+      CoinMemcpyN(rhs.cliqueEntry_,n,cliqueEntry_);
+      oneFixStart_ = new int [numberColumns_];
+      CoinMemcpyN(rhs.oneFixStart_,numberColumns_,oneFixStart_);
+      zeroFixStart_ = new int [numberColumns_];
+      CoinMemcpyN(rhs.zeroFixStart_,numberColumns_,zeroFixStart_);
+      endFixStart_ = new int [numberColumns_];
+      CoinMemcpyN(rhs.endFixStart_,numberColumns_,endFixStart_);
+#ifndef NDEBUG
+      int n2=-1;
+      for (int i=numberColumns_-1;i>=0;i--) {
+	if (oneFixStart_[i]>=0) {
+	  n2=endFixStart_[i];
+	  break;
+	}
+      }
+      assert (n==n2);
+#endif
+      whichClique_ = new int [n];
+      CoinMemcpyN(rhs.whichClique_,n,whichClique_);
+      if (rhs.cliqueRowStart_) {
+        cliqueRowStart_ = CoinCopyOfArray(rhs.cliqueRowStart_,numberRows_+1);
+        n=cliqueRowStart_[numberRows_];
+        cliqueRow_ = CoinCopyOfArray(rhs.cliqueRow_,n);
+      } else {
+        cliqueRow_=NULL;
+        cliqueRowStart_=NULL;
+      }
+    } else {
+      cliqueType_=NULL;
+      cliqueStart_=NULL;
+      cliqueEntry_=NULL;
+      oneFixStart_=NULL;
+      zeroFixStart_=NULL;
+      endFixStart_=NULL;
+      whichClique_=NULL;
+      cliqueRow_=NULL;
+      cliqueRowStart_=NULL;
+    }
+    if (rhs.tightenBounds_) {
+      assert (numberColumns_);
+      tightenBounds_=CoinCopyOfArray(rhs.tightenBounds_,numberColumns_);
+    } else {
+      tightenBounds_=NULL;
+    }
+  }
+  return *this;
+}
+
+/// This can be used to refresh any inforamtion
+void 
+CglProbing::refreshSolver(OsiSolverInterface * solver)
+{
+  if (rowCopy_) {
+    // snapshot existed - redo
+    snapshot(*solver,NULL);
+  }
+}
+/* Creates cliques for use by probing.
+   Can also try and extend cliques as a result of probing (root node).
+   Returns number of cliques found.
+*/
+int 
+CglProbing::createCliques( OsiSolverInterface & si, 
+			  int minimumSize, int maximumSize)
+{
+  // get rid of what is there
+  deleteCliques();
+  CoinPackedMatrix matrixByRow(*si.getMatrixByRow());
+  int numberRows = si.getNumRows();
+  if (!rowCopy_)
+    numberRows_=numberRows;
+  numberColumns_ = si.getNumCols();
+
+  numberCliques_=0;
+  int numberEntries=0;
+  int numberIntegers=0;
+  int * lookup = new int[numberColumns_];
+  int i;
+  for (i=0;i<numberColumns_;i++) {
+    if (si.isBinary(i))
+      lookup[i]=numberIntegers++;
+    else
+      lookup[i]=-1;
+  }
+
+  int * which = new int[numberColumns_];
+  int * whichRow = new int[numberRows];
+  // Statistics
+  int totalP1=0,totalM1=0;
+  int numberBig=0,totalBig=0;
+  int numberFixed=0;
+
+  // Row copy
+  const double * elementByRow = matrixByRow.getElements();
+  const int * column = matrixByRow.getIndices();
+  const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  const int * rowLength = matrixByRow.getVectorLengths();
+
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+  const double * rowLower = si.getRowLower();
+  const double * rowUpper = si.getRowUpper();
+  int iRow;
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int numberP1=0, numberM1=0;
+    int j;
+    double upperValue=rowUpper[iRow];
+    double lowerValue=rowLower[iRow];
+    bool good=true;
+    for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+      int iColumn = column[j];
+      int iInteger=lookup[iColumn];
+      if (upper[iColumn]-lower[iColumn]<1.0e-8) {
+	// fixed
+	upperValue -= lower[iColumn]*elementByRow[j];
+	lowerValue -= lower[iColumn]*elementByRow[j];
+	continue;
+      } else if (upper[iColumn]!=1.0||lower[iColumn]!=0.0) {
+	good = false;
+	break;
+      } else if (iInteger<0) {
+	good = false;
+	break;
+      }
+      if (fabs(elementByRow[j])!=1.0) {
+	good=false;
+	break;
+      } else if (elementByRow[j]>0.0) {
+	which[numberP1++]=iColumn;
+      } else {
+	numberM1++;
+	which[numberIntegers-numberM1]=iColumn;
+      }
+    }
+    int iUpper = static_cast<int> (floor(upperValue+1.0e-5));
+    int iLower = static_cast<int> (ceil(lowerValue-1.0e-5));
+    int state=0;
+    if (upperValue<1.0e6) {
+      if (iUpper==1-numberM1)
+	state=1;
+      else if (iUpper==-numberM1)
+	state=2;
+      else if (iUpper<-numberM1)
+	state=3;
+    }
+    if (!state&&lowerValue>-1.0e6) {
+      if (-iLower==1-numberP1)
+	state=-1;
+      else if (-iLower==-numberP1)
+	state=-2;
+      else if (-iLower<-numberP1)
+	state=-3;
+    }
+    if (good&&state) {
+      if (abs(state)==3) {
+	// infeasible
+	numberCliques_ = -99999;
+	break;
+      } else if (abs(state)==2) {
+	// we can fix all
+	numberFixed += numberP1+numberM1;
+	if (state>0) {
+	  // fix all +1 at 0, -1 at 1
+	  for (i=0;i<numberP1;i++)
+	    si.setColUpper(which[i],0.0);
+	  for (i=0;i<numberM1;i++)
+	    si.setColLower(which[numberIntegers-i-1],
+				 1.0);
+	} else {
+	  // fix all +1 at 1, -1 at 0
+	  for (i=0;i<numberP1;i++)
+	    si.setColLower(which[i],1.0);
+	  for (i=0;i<numberM1;i++)
+	    si.setColUpper(which[numberIntegers-i-1],
+				 0.0);
+	}
+      } else {
+	int length = numberP1+numberM1;
+        totalP1 += numberP1;
+        totalM1 += numberM1;
+	if (length >= minimumSize&&length<maximumSize) {
+	  whichRow[numberCliques_++]=iRow;
+	  numberEntries += length;
+	} else if (numberP1+numberM1 >= maximumSize) {
+	  // too big
+	  numberBig++;
+	  totalBig += numberP1+numberM1;
+	}
+      }
+    }
+  }
+  if (numberCliques_<0) {
+    if (logLevel_)
+      printf("*** Problem infeasible\n");
+  } else {
+    if (numberCliques_) {
+      if (logLevel_)
+        printf("%d cliques of average size %g found, %d P1, %d M1\n",
+               numberCliques_,
+               (static_cast<double>(totalP1+totalM1))/
+	       (static_cast<double> (numberCliques_)),
+               totalP1,totalM1);
+    } else {
+      if (logLevel_>1)
+        printf("No cliques found\n");
+    }
+    if (numberBig) {
+      if (logLevel_)
+        printf("%d large cliques ( >= %d) found, total %d\n",
+	     numberBig,maximumSize,totalBig);
+    }
+    if (numberFixed) {
+      if (logLevel_)
+        printf("%d variables fixed\n",numberFixed);
+    }
+  }
+  if (numberCliques_>0) {
+    cliqueType_ = new cliqueType [numberCliques_];
+    cliqueStart_ = new int [numberCliques_+1];
+    cliqueEntry_ = new cliqueEntry [numberEntries];
+    oneFixStart_ = new int [numberColumns_];
+    zeroFixStart_ = new int [numberColumns_];
+    endFixStart_ = new int [numberColumns_];
+    whichClique_ = new int [numberEntries];
+    numberEntries=0;
+    cliqueStart_[0]=0;
+    for (i=0;i<numberColumns_;i++) {
+      oneFixStart_[i]=-1;
+      zeroFixStart_[i]=-1;
+      endFixStart_[i]=-1;
+    }
+    int iClique;
+    // Possible some have been fixed
+    int numberCliques=numberCliques_;
+    numberCliques_=0;
+    for (iClique=0;iClique<numberCliques;iClique++) {
+      int iRow=whichRow[iClique];
+      whichRow[numberCliques_]=iRow;
+      int numberP1=0, numberM1=0;
+      int j;
+      double upperValue=rowUpper[iRow];
+      double lowerValue=rowLower[iRow];
+      for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	int iColumn = column[j];
+	if (upper[iColumn]-lower[iColumn]<1.0e-8) {
+	  // fixed
+	  upperValue -= lower[iColumn]*elementByRow[j];
+	  lowerValue -= lower[iColumn]*elementByRow[j];
+	  continue;
+	}
+	if (elementByRow[j]>0.0) {
+	  which[numberP1++]=iColumn;
+	} else {
+	  numberM1++;
+	  which[numberIntegers-numberM1]=iColumn;
+	}
+      }
+      int iUpper = static_cast<int> (floor(upperValue+1.0e-5));
+      int iLower = static_cast<int> (ceil(lowerValue-1.0e-5));
+      int state=0;
+      if (upperValue<1.0e6) {
+	if (iUpper==1-numberM1)
+	  state=1;
+      }
+      if (!state&&lowerValue>-1.0e6) {
+	state=-1;
+      }
+      if (abs(state)!=1)
+	continue; // must have been fixed
+      if (iLower==iUpper) {
+	cliqueType_[numberCliques_].equality=1;
+      } else {
+	cliqueType_[numberCliques_].equality=0;
+      }
+      if (state>0) {
+	for (i=0;i<numberP1;i++) {
+	  // 1 is strong branch
+	  int iColumn = which[i];
+	  setSequenceInCliqueEntry(cliqueEntry_[numberEntries],iColumn);
+	  setOneFixesInCliqueEntry(cliqueEntry_[numberEntries],true);
+	  numberEntries++;
+	  // zero counts
+	  oneFixStart_[iColumn]=0;
+	  zeroFixStart_[iColumn]=0;
+	}
+	for (i=0;i<numberM1;i++) {
+	  // 0 is strong branch
+	  int iColumn = which[numberIntegers-i-1];
+	  setSequenceInCliqueEntry(cliqueEntry_[numberEntries],iColumn);
+	  setOneFixesInCliqueEntry(cliqueEntry_[numberEntries],false);
+	  numberEntries++;
+	  // zero counts
+	  oneFixStart_[iColumn]=0;
+	  zeroFixStart_[iColumn]=0;
+	}
+      } else {
+	for (i=0;i<numberP1;i++) {
+	  // 0 is strong branch
+	  int iColumn = which[i];
+	  setSequenceInCliqueEntry(cliqueEntry_[numberEntries],iColumn);
+	  setOneFixesInCliqueEntry(cliqueEntry_[numberEntries],false);
+	  numberEntries++;
+	  // zero counts
+	  oneFixStart_[iColumn]=0;
+	  zeroFixStart_[iColumn]=0;
+	}
+	for (i=0;i<numberM1;i++) {
+	  // 1 is strong branch
+	  int iColumn = which[numberIntegers-i-1];
+	  setSequenceInCliqueEntry(cliqueEntry_[numberEntries],iColumn);
+	  setOneFixesInCliqueEntry(cliqueEntry_[numberEntries],true);
+	  numberEntries++;
+	  // zero counts
+	  oneFixStart_[iColumn]=0;
+	  zeroFixStart_[iColumn]=0;
+	}
+      }
+      numberCliques_++;
+      cliqueStart_[numberCliques_]=numberEntries;
+    }
+    // Now do column lists
+    // First do counts
+    for (iClique=0;iClique<numberCliques_;iClique++) {
+      for (int j=cliqueStart_[iClique];j<cliqueStart_[iClique+1];j++) {
+	int iColumn = sequenceInCliqueEntry(cliqueEntry_[j]);
+	if (oneFixesInCliqueEntry(cliqueEntry_[j]))
+	  oneFixStart_[iColumn]++;
+	else
+	  zeroFixStart_[iColumn]++;
+      }
+    }
+    // now get starts and use which and end as counters
+    numberEntries=0;
+    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+      if (oneFixStart_[iColumn]>=0) {
+	int n1=oneFixStart_[iColumn];
+	int n2=zeroFixStart_[iColumn];
+	oneFixStart_[iColumn]=numberEntries;
+	which[iColumn]=numberEntries;
+	numberEntries += n1;
+	zeroFixStart_[iColumn]=numberEntries;
+	endFixStart_[iColumn]=numberEntries;
+	numberEntries += n2;
+      }
+    }
+    // now put in
+    for (iClique=0;iClique<numberCliques_;iClique++) {
+      for (int j=cliqueStart_[iClique];j<cliqueStart_[iClique+1];j++) {
+	int iColumn = sequenceInCliqueEntry(cliqueEntry_[j]);
+	if (oneFixesInCliqueEntry(cliqueEntry_[j])) {
+	  int put = which[iColumn];
+	  which[iColumn]++;
+	  whichClique_[put]=iClique;
+	} else {
+	  int put = endFixStart_[iColumn];
+	  endFixStart_[iColumn]++;
+	  whichClique_[put]=iClique;
+	}
+      }
+    }
+  }
+  delete [] which;
+  delete [] whichRow;
+  delete [] lookup;
+  return numberCliques_;
+}
+// Delete all clique information
+void 
+CglProbing::deleteCliques()
+{
+  delete [] cliqueType_;
+  delete [] cliqueStart_;
+  delete [] cliqueEntry_;
+  delete [] oneFixStart_;
+  delete [] zeroFixStart_;
+  delete [] endFixStart_;
+  delete [] whichClique_;
+  delete [] cliqueRow_;
+  delete [] cliqueRowStart_;
+  cliqueType_=NULL;
+  cliqueStart_=NULL;
+  cliqueEntry_=NULL;
+  oneFixStart_=NULL;
+  zeroFixStart_=NULL;
+  endFixStart_=NULL;
+  whichClique_=NULL;
+  cliqueRow_=NULL;
+  cliqueRowStart_=NULL;
+  numberCliques_=0;
+}
+/*
+  Returns true if may generate Row cuts in tree (rather than root node).
+  Used so know if matrix will change in tree.  Really
+  meant so column cut generators can still be active
+  without worrying code.
+  Default is true
+*/
+bool 
+CglProbing::mayGenerateRowCutsInTree() const
+{
+  return rowCuts_>0;
+}
+// Sets up clique information for each row
+void 
+CglProbing::setupRowCliqueInformation(const OsiSolverInterface & si) 
+{
+  if (!numberCliques_)
+    return;
+  CoinPackedMatrix * rowCopy;
+  if (!rowCopy_) {
+    // create from current
+    numberRows_=si.getNumRows(); 
+    numberColumns_=si.getNumCols(); 
+    rowCopy = new CoinPackedMatrix(*si.getMatrixByRow());
+  } else {
+    rowCopy = rowCopy_;
+    assert(numberRows_<=si.getNumRows()); 
+    assert(numberColumns_==si.getNumCols()); 
+  }
+  assert(numberRows_&&numberColumns_);
+  cliqueRowStart_ = new int [numberRows_+1];
+  cliqueRowStart_[0]=0;
+  // Temporary array while building list
+  cliqueEntry ** array = new cliqueEntry * [numberRows_];
+  // Which cliques in use
+  int * which = new int[numberCliques_];
+  int * count = new int[numberCliques_];
+  int * back =new int[numberColumns_];
+  CoinZeroN(count,numberCliques_);
+  CoinFillN(back,numberColumns_,-1);
+  const int * column = rowCopy->getIndices();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const int * rowLength = rowCopy->getVectorLengths(); 
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+  int iRow;
+  for (iRow=0;iRow<numberRows_;iRow++) {
+    int j;
+    int numberFree=0;
+    int numberUsed=0;
+    for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+      int iColumn=column[j];
+      if (upper[iColumn]>lower[iColumn]) {
+        back[iColumn]=j-rowStart[iRow];
+        numberFree++;
+        for (int k=oneFixStart_[iColumn];k<endFixStart_[iColumn];k++) {
+          int iClique = whichClique_[k];
+          if (!count[iClique]) {
+            which[numberUsed++]=iClique;
+          }
+          count[iClique]++;
+        }
+      }
+    }
+    // find largest cliques
+    bool finished=false;
+    int numberInThis=0;
+    cliqueEntry * entries = NULL;
+    array[iRow]=entries;
+    while (!finished) {
+      int largest=1;
+      int whichClique=-1;
+      for (int i=0;i<numberUsed;i++) {
+        int iClique = which[i];
+        if (count[iClique]>largest) {
+          largest=count[iClique];
+          whichClique=iClique;
+        }
+      }
+      // Add in if >1 (but not if all as that means clique==row)
+      if (whichClique>=0&&largest<numberFree) {
+        if (!numberInThis) {
+          int length=rowLength[iRow];
+          entries = new cliqueEntry [length];
+          array[iRow]=entries;
+          for (int i=0;i<length;i++) {
+            setOneFixesInCliqueEntry(entries[i],false);
+            setSequenceInCliqueEntry(entries[i],numberColumns_+1);
+          }
+        }
+        // put in (and take out all counts)
+        for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+          int iColumn=column[j];
+          if (upper[iColumn]>lower[iColumn]) {
+            bool found=false;
+            int k;
+            for ( k=oneFixStart_[iColumn];k<endFixStart_[iColumn];k++) {
+              int iClique = whichClique_[k];
+              if (iClique==whichClique) {
+                found=true;
+                break;
+              }
+            }
+            if (found) {
+              for ( k=oneFixStart_[iColumn];k<endFixStart_[iColumn];k++) {
+                int iClique = whichClique_[k];
+                count[iClique]--;
+              }
+              for (k=cliqueStart_[whichClique];k<cliqueStart_[whichClique+1];k++) {
+                if (sequenceInCliqueEntry(cliqueEntry_[k])==iColumn) {
+                  int iback=back[iColumn];
+                  setSequenceInCliqueEntry(entries[iback],numberInThis);
+                  setOneFixesInCliqueEntry(entries[iback],
+					   oneFixesInCliqueEntry(cliqueEntry_[k]));
+                  break;
+                }
+              }
+            }
+          }
+        }
+        numberInThis++;
+      } else {
+        finished=true;
+      }
+    }
+    if (numberInThis) 
+      cliqueRowStart_[iRow+1]=cliqueRowStart_[iRow]+rowLength[iRow];
+    else
+      cliqueRowStart_[iRow+1]=cliqueRowStart_[iRow];
+    for (int i=0;i<numberUsed;i++) {
+      int iClique = which[i];
+      count[iClique]=0;
+    }
+    for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+      int iColumn=column[j];
+      back[iColumn]=-1;
+    }
+  }
+  delete [] which;
+  delete [] count;
+  delete [] back;
+  // Now put info in one array
+  cliqueRow_ = new cliqueEntry [cliqueRowStart_[numberRows_]];
+  for (iRow=0;iRow<numberRows_;iRow++) {
+    if (array[iRow]) {
+      int start = cliqueRowStart_[iRow];
+      CoinMemcpyN(array[iRow],rowLength[iRow],cliqueRow_+start);
+      delete [] array[iRow];
+    }
+  }
+  delete [] array;
+  if (rowCopy!=rowCopy_)
+    delete rowCopy;
+}
+// Mark variables to be tightened
+void 
+CglProbing::tightenThese(const OsiSolverInterface & solver,int number, const int * which)
+{
+  delete [] tightenBounds_;
+  int numberColumns = solver.getNumCols();
+  if (numberColumns_)
+    assert (numberColumns_==numberColumns);
+  tightenBounds_ = new char [numberColumns];
+  memset(tightenBounds_,0,numberColumns);
+  for (int i=0;i<number;i++) {
+    int k=which[i];
+    if (k>=0&&k<numberColumns)
+      tightenBounds_[k]=1;
+  }
+}
+// Create C++ lines to get to current state
+std::string
+CglProbing::generateCpp( FILE * fp) 
+{
+  CglProbing other;
+  fprintf(fp,"0#include \"CglProbing.hpp\"\n");
+  fprintf(fp,"3  CglProbing probing;\n");
+  if (getMode()!=other.getMode())
+    fprintf(fp,"3  probing.setMode(%d);\n",getMode());
+  else
+    fprintf(fp,"4  probing.setMode(%d);\n",getMode());
+  if (getMaxPass()!=other.getMaxPass())
+    fprintf(fp,"3  probing.setMaxPass(%d);\n",getMaxPass());
+  else
+    fprintf(fp,"4  probing.setMaxPass(%d);\n",getMaxPass());
+  if (getLogLevel()!=other.getLogLevel())
+    fprintf(fp,"3  probing.setLogLevel(%d);\n",getLogLevel());
+  else
+    fprintf(fp,"4  probing.setLogLevel(%d);\n",getLogLevel());
+  if (getMaxProbe()!=other.getMaxProbe())
+    fprintf(fp,"3  probing.setMaxProbe(%d);\n",getMaxProbe());
+  else
+    fprintf(fp,"4  probing.setMaxProbe(%d);\n",getMaxProbe());
+  if (getMaxLook()!=other.getMaxLook())
+    fprintf(fp,"3  probing.setMaxLook(%d);\n",getMaxLook());
+  else
+    fprintf(fp,"4  probing.setMaxLook(%d);\n",getMaxLook());
+  if (getMaxElements()!=other.getMaxElements())
+    fprintf(fp,"3  probing.setMaxElements(%d);\n",getMaxElements());
+  else
+    fprintf(fp,"4  probing.setMaxElements(%d);\n",getMaxElements());
+  if (getMaxPassRoot()!=other.getMaxPassRoot())
+    fprintf(fp,"3  probing.setMaxPassRoot(%d);\n",getMaxPassRoot());
+  else
+    fprintf(fp,"4  probing.setMaxPassRoot(%d);\n",getMaxPassRoot());
+  if (getMaxProbeRoot()!=other.getMaxProbeRoot())
+    fprintf(fp,"3  probing.setMaxProbeRoot(%d);\n",getMaxProbeRoot());
+  else
+    fprintf(fp,"4  probing.setMaxProbeRoot(%d);\n",getMaxProbeRoot());
+  if (getMaxLookRoot()!=other.getMaxLookRoot())
+    fprintf(fp,"3  probing.setMaxLookRoot(%d);\n",getMaxLookRoot());
+  else
+    fprintf(fp,"4  probing.setMaxLookRoot(%d);\n",getMaxLookRoot());
+  if (getMaxElementsRoot()!=other.getMaxElementsRoot())
+    fprintf(fp,"3  probing.setMaxElementsRoot(%d);\n",getMaxElementsRoot());
+  else
+    fprintf(fp,"4  probing.setMaxElementsRoot(%d);\n",getMaxElementsRoot());
+  if (rowCuts()!=other.rowCuts())
+    fprintf(fp,"3  probing.setRowCuts(%d);\n",rowCuts());
+  else
+    fprintf(fp,"4  probing.setRowCuts(%d);\n",rowCuts());
+  if (getUsingObjective()!=other.getUsingObjective())
+    fprintf(fp,"3  probing.setUsingObjective(%d);\n",getUsingObjective());
+  else
+    fprintf(fp,"4  probing.setUsingObjective(%d);\n",getUsingObjective());
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  probing.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  probing.setAggressiveness(%d);\n",getAggressiveness());
+  return "probing";
+}
+//-------------------------------------------------------------
+void
+CglImplication::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+				const CglTreeInfo info)
+{
+  if (probingInfo_) {
+    //int n1=cs.sizeRowCuts();
+    probingInfo_->generateCuts(si,cs,info);
+    //int n2=cs.sizeRowCuts();
+    //if (n2>n1)
+    //printf("added %d cuts\n",n2-n1);
+  }
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglImplication::CglImplication ()
+:
+CglCutGenerator(),
+probingInfo_(NULL)
+{
+  // nothing to do here
+}
+//-------------------------------------------------------------------
+// Constructor with info
+//-------------------------------------------------------------------
+CglImplication::CglImplication (CglTreeProbingInfo * info)
+:
+CglCutGenerator(),
+probingInfo_(info)
+{
+  // nothing to do here
+}
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglImplication::CglImplication (
+                  const CglImplication & source)
+:
+CglCutGenerator(source),
+probingInfo_(source.probingInfo_)
+{  
+  // Nothing to do here
+}
+
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglImplication::clone() const
+{
+  return new CglImplication(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglImplication::~CglImplication ()
+{
+  // Nothing to do here
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglImplication &
+CglImplication::operator=(
+                   const CglImplication& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    probingInfo_=rhs.probingInfo_;
+  }
+  return *this;
+}
+// Create C++ lines to get to current state
+std::string
+CglImplication::generateCpp( FILE * fp) 
+{
+  CglImplication other;
+  fprintf(fp,"0#include \"CglImplication.hpp\"\n");
+  fprintf(fp,"3  CglImplication implication;\n");
+  return "implication";
+}
diff --git a/cbits/coin/CglProbing.hpp b/cbits/coin/CglProbing.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglProbing.hpp
@@ -0,0 +1,521 @@
+// $Id: CglProbing.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglProbing_H
+#define CglProbing_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+  /** Only useful type of disaggregation is most normal
+      For now just done for 0-1 variables
+      Can be used for building cliques
+   */
+  typedef struct {
+    //unsigned int zeroOne:1; // nonzero if affected variable is 0-1
+    //unsigned int whenAtUB:1; // nonzero if fixing happens when this variable at 1
+    //unsigned int affectedToUB:1; // nonzero if affected variable fixed to UB
+    //unsigned int affected:29; // If 0-1 then 0-1 sequence, otherwise true
+    unsigned int affected;
+  } disaggregationAction;
+
+/** Probing Cut Generator Class */
+class CglProbing : public CglCutGenerator {
+   friend void CglProbingUnitTest(const OsiSolverInterface * siP,
+				  const std::string mpdDir );
+ 
+public:
+    
+  
+  /**@name Generate Cuts */
+  //@{
+  /** Generate probing/disaggregation cuts for the model of the 
+      solver interface, si.
+
+      This is a simplification of probing ideas put into OSL about
+      ten years ago.  The only known documentation is a copy of a 
+      talk handout - we think Robin Lougee-Heimer has a copy!
+
+      For selected integer variables (e.g. unsatisfied ones) the effect of
+      setting them up or down is investigated.  Setting a variable up
+      may in turn set other variables (continuous as well as integer).
+      There are various possible results:
+
+      1) It is shown that problem is infeasible (this may also be
+         because objective function or reduced costs show worse than
+	 best solution).  If the other way is feasible we can generate
+	 a column cut (and continue probing), if not feasible we can
+	 say problem infeasible.
+
+      2) If both ways are feasible, it can happen that x to 0 implies y to 1
+         ** and x to 1 implies y to 1 (again a column cut).  More common
+	 is that x to 0 implies y to 1 and x to 1 implies y to 0 so we could
+	 substitute for y which might lead later to more powerful cuts.
+	 ** This is not done in this code as there is no mechanism for
+	 returning information.
+
+      3) When x to 1 a constraint went slack by c.  We can tighten the
+         constraint ax + .... <= b (where a may be zero) to
+	 (a+c)x + .... <= b.  If this cut is violated then it is
+	 generated.
+
+      4) Similarly we can generate implied disaggregation cuts
+
+      Note - differences to cuts in OSL.
+
+      a) OSL had structures intended to make this faster.
+      b) The "chaining" in 2) was done
+      c) Row cuts modified original constraint rather than adding cut
+      b) This code can cope with general integer variables.
+
+      Insert the generated cuts into OsiCut, cs.
+
+      If a "snapshot" of a matrix exists then this will be used.
+      Presumably this will give global cuts and will be faster.
+      No check is done to see if cuts will be global.
+
+      Otherwise use current matrix.
+
+      Both row cuts and column cuts may be returned
+
+      The mode options are:
+      0) Only unsatisfied integer variables will be looked at.
+         If no information exists for that variable then
+	 probing will be done so as a by-product you "may" get a fixing
+	 or infeasibility.  This will be fast and is only available
+         if a snapshot exists (otherwise as 1).  
+	 The bounds in the snapshot are the ones used.
+      1) Look at unsatisfied integer variables, using current bounds.
+         Probing will be done on all looked at.
+      2) Look at all integer variables, using current bounds.
+         Probing will be done on all
+
+	 ** If generateCutsAndModify is used then new relaxed
+	 row bounds and tightened column bounds are generated
+	 Returns number of infeasibilities 
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+  int generateCutsAndModify( const OsiSolverInterface & si, OsiCuts & cs, 
+			     CglTreeInfo * info);
+  //@}
+
+  /**@name snapshot etc */
+  //@{
+  /** Create a copy of matrix which is to be used
+      this is to speed up process and to give global cuts
+      Can give an array with 1 set to select, 0 to ignore
+      column bounds are tightened
+      If array given then values of 1 will be set to 0 if redundant.
+      Objective may be added as constraint
+      Returns 1 if infeasible otherwise 0
+  */
+  int snapshot ( const OsiSolverInterface & si,
+		  char * possible=NULL,
+                  bool withObjective=true);
+  /// Deletes snapshot
+  void deleteSnapshot ( );
+  /** Creates cliques for use by probing.
+      Only cliques >= minimumSize and < maximumSize created
+      Can also try and extend cliques as a result of probing (root node).
+      Returns number of cliques found.
+  */
+  int createCliques( OsiSolverInterface & si, 
+		    int minimumSize=2, int maximumSize=100);
+  /// Delete all clique information
+  void deleteCliques();
+  //@}
+
+  /**@name Get tighter column bounds */
+  //@{
+  /// Lower
+  const double * tightLower() const;
+  /// Upper
+  const double * tightUpper() const;
+  /// Array which says tighten continuous
+  const char * tightenBounds() const
+  { return tightenBounds_;}
+  //@}
+
+  /**@name Get possible freed up row bounds - only valid after mode==3 */
+  //@{
+  /// Lower
+  const double * relaxedRowLower() const;
+  /// Upper
+  const double * relaxedRowUpper() const;
+  //@}
+
+  /**@name Change mode */
+  //@{
+  /// Set
+  void setMode(int mode);
+  /// Get
+  int getMode() const;
+  //@}
+
+  /**@name Change maxima */
+  //@{
+  /// Set maximum number of passes per node
+  void setMaxPass(int value);
+  /// Get maximum number of passes per node
+  int getMaxPass() const;
+  /// Set log level - 0 none, 1 - a bit, 2 - more details
+  void setLogLevel(int value);
+  /// Get log level
+  int getLogLevel() const;
+  /// Set maximum number of unsatisfied variables to look at
+  void setMaxProbe(int value);
+  /// Get maximum number of unsatisfied variables to look at
+  int getMaxProbe() const;
+  /// Set maximum number of variables to look at in one probe
+  void setMaxLook(int value);
+  /// Get maximum number of variables to look at in one probe
+  int getMaxLook() const;
+  /// Set maximum number of elements in row for it to be considered
+  void setMaxElements(int value);
+  /// Get maximum number of elements in row for it to be considered
+  int getMaxElements() const;
+  /// Set maximum number of passes per node  (root node)
+  void setMaxPassRoot(int value);
+  /// Get maximum number of passes per node (root node)
+  int getMaxPassRoot() const;
+  /// Set maximum number of unsatisfied variables to look at (root node)
+  void setMaxProbeRoot(int value);
+  /// Get maximum number of unsatisfied variables to look at (root node)
+  int getMaxProbeRoot() const;
+  /// Set maximum number of variables to look at in one probe (root node)
+  void setMaxLookRoot(int value);
+  /// Get maximum number of variables to look at in one probe (root node)
+  int getMaxLookRoot() const;
+  /// Set maximum number of elements in row for it to be considered (root node)
+  void setMaxElementsRoot(int value);
+  /// Get maximum number of elements in row for it to be considered (root node)
+  int getMaxElementsRoot() const;
+  /**
+     Returns true if may generate Row cuts in tree (rather than root node).
+     Used so know if matrix will change in tree.  Really
+     meant so column cut generators can still be active
+     without worrying code.
+     Default is true
+  */
+  virtual bool mayGenerateRowCutsInTree() const;
+  //@}
+
+  /**@name Get information back from probing */
+  //@{
+  /// Number looked at this time
+  inline int numberThisTime() const
+  { return numberThisTime_;}
+  /// Which ones looked at this time
+  inline const int * lookedAt() const
+  { return lookedAt_;}
+  //@}
+
+  /**@name Stop or restart row cuts (otherwise just fixing from probing) */
+  //@{
+  /// Set
+  /// 0 no cuts, 1 just disaggregation type, 2 coefficient ( 3 both)
+  void setRowCuts(int type);
+  /// Get
+  int rowCuts() const;
+  //@}
+
+  /**@name Whether use objective as constraint */
+  //@{
+  /** Set
+      0 don't
+      1 do
+      -1 don't even think about it
+  */
+  void setUsingObjective(int yesNo);
+  /// Get
+  int getUsingObjective() const;
+  //@}
+
+  /**@name Mark which continuous variables are to be tightened */
+  //@{
+  /// Mark variables to be tightened
+  void tightenThese(const OsiSolverInterface & solver, int number, const int * which);
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglProbing ();
+ 
+  /// Copy constructor 
+  CglProbing (
+    const CglProbing &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglProbing &
+    operator=(
+    const CglProbing& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglProbing ();
+
+  /// This can be used to refresh any inforamtion
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  //@}
+      
+private:
+  
+ // Private member methods
+  /**@name probe */
+  //@{
+  /// Does probing and adding cuts (without cliques and mode_!=0)
+  int probe( const OsiSolverInterface & si, 
+	     const OsiRowCutDebugger * debugger, 
+	     OsiCuts & cs, 
+	     double * colLower, double * colUpper, CoinPackedMatrix *rowCopy,
+	     CoinPackedMatrix *columnCopy,const CoinBigIndex * rowStartPos,
+	     const int * realRow, const double * rowLower, const double * rowUpper,
+	     const char * intVar, double * minR, double * maxR, int * markR, 
+	     CglTreeInfo * info);
+  /// Does probing and adding cuts (with cliques)
+  int probeCliques( const OsiSolverInterface & si, 
+	     const OsiRowCutDebugger * debugger, 
+	     OsiCuts & cs, 
+	     double * colLower, double * colUpper, CoinPackedMatrix *rowCopy,
+		    CoinPackedMatrix *columnCopy, const int * realRow,
+	     double * rowLower, double * rowUpper,
+	     char * intVar, double * minR, double * maxR, int * markR, 
+             CglTreeInfo * info);
+  /// Does probing and adding cuts for clique slacks
+  int probeSlacks( const OsiSolverInterface & si, 
+                    const OsiRowCutDebugger * debugger, 
+                    OsiCuts & cs, 
+                    double * colLower, double * colUpper, CoinPackedMatrix *rowCopy,
+		   CoinPackedMatrix *columnCopy,
+                    double * rowLower, double * rowUpper,
+                    char * intVar, double * minR, double * maxR,int * markR,
+                     CglTreeInfo * info);
+  /** Does most of work of generateCuts 
+      Returns number of infeasibilities */
+  int gutsOfGenerateCuts( const OsiSolverInterface & si, 
+			  OsiCuts & cs,
+			  double * rowLower, double * rowUpper,
+			  double * colLower, double * colUpper,
+                           CglTreeInfo * info);
+  /// Sets up clique information for each row
+  void setupRowCliqueInformation(const OsiSolverInterface & si);
+  /** This tightens column bounds (and can declare infeasibility)
+      It may also declare rows to be redundant */
+  int tighten(double *colLower, double * colUpper,
+              const int *column, const double *rowElements, 
+              const CoinBigIndex *rowStart,const CoinBigIndex * rowStartPos,
+	      const int * rowLength,
+              double *rowLower, double *rowUpper, 
+              int nRows,int nCols,char * intVar,int maxpass,
+              double tolerance);
+  /// This just sets minima and maxima on rows
+  void tighten2(double *colLower, double * colUpper,
+                const int *column, const double *rowElements, 
+                const CoinBigIndex *rowStart,
+		const int * rowLength,
+                double *rowLower, double *rowUpper, 
+                double * minR, double * maxR, int * markR,
+                int nRows);
+  //@}
+
+  // Private member data
+
+  struct disaggregation_struct_tag ;
+  friend struct CglProbing::disaggregation_struct_tag ;
+
+  /**@name Private member data */
+  //@{
+  /// Row copy (only if snapshot)
+  CoinPackedMatrix * rowCopy_;
+  /// Column copy (only if snapshot)
+  CoinPackedMatrix * columnCopy_;
+  /// Lower bounds on rows
+  double * rowLower_;
+  /// Upper bounds on rows
+  double * rowUpper_;
+  /// Lower bounds on columns
+  double * colLower_;
+  /// Upper bounds on columns
+  double * colUpper_;
+  /// Number of rows in snapshot (or when cliqueRow stuff computed)
+  int numberRows_;
+  /// Number of columns in problem ( must == current)
+  int numberColumns_;
+  /// Tolerance to see if infeasible
+  double primalTolerance_;
+  /** Mode - 0 lazy using snapshot, 1 just unsatisfied, 2 all.
+      16 bit set if want to extend cliques at root node
+  */
+  int mode_;
+  /** Row cuts flag
+      0 no cuts, 1 just disaggregation type, 2 coefficient ( 3 both), 4 just column cuts
+      -n as +n but just fixes variables unless at root
+  */
+  int rowCuts_;
+  /// Maximum number of passes to do in probing
+  int maxPass_;
+  /// Log level - 0 none, 1 - a bit, 2 - more details
+  int logLevel_;
+  /// Maximum number of unsatisfied variables to probe
+  int maxProbe_;
+  /// Maximum number of variables to look at in one probe
+  int maxStack_;
+  /// Maximum number of elements in row for scan
+  int maxElements_;
+  /// Maximum number of passes to do in probing at root
+  int maxPassRoot_;
+  /// Maximum number of unsatisfied variables to probe at root
+  int maxProbeRoot_;
+  /// Maximum number of variables to look at in one probe at root
+  int maxStackRoot_;
+  /// Maximum number of elements in row for scan at root
+  int maxElementsRoot_;
+  /// Whether to include objective as constraint
+  int usingObjective_;
+  /// Number of integer variables
+  int numberIntegers_;
+  /// Number of 0-1 integer variables
+  int number01Integers_;
+  /// Number looked at this time
+  int numberThisTime_;
+  /// Total number of times called
+  int totalTimesCalled_;
+  /// Which ones looked at this time
+  int * lookedAt_;
+  /// Disaggregation cuts and for building cliques
+  typedef struct disaggregation_struct_tag {
+    int sequence; // integer variable
+    // index will be NULL if no probing done yet
+    int length; // length of newValue
+    disaggregationAction * index; // columns whose bounds will be changed
+  } disaggregation;
+  disaggregation * cutVector_;
+  /// Cliques
+  /// Number of cliques
+  int numberCliques_;
+  /// Clique type
+  typedef struct {
+    unsigned int equality:1; //  nonzero if clique is ==
+  } cliqueType;
+  cliqueType * cliqueType_;
+  /// Start of each clique
+  int * cliqueStart_;
+  /// Entries for clique
+  cliqueEntry * cliqueEntry_;
+  /** Start of oneFixes cliques for a column in matrix or -1 if not
+      in any clique */
+  int * oneFixStart_;
+  /** Start of zeroFixes cliques for a column in matrix or -1 if not
+      in any clique */
+  int * zeroFixStart_;
+  /// End of fixes for a column
+  int * endFixStart_;
+  /// Clique numbers for one or zero fixes
+  int * whichClique_;
+  /** For each column with nonzero in row copy this gives a clique "number".
+      So first clique mentioned in row is always 0.  If no entries for row
+      then no cliques.  If sequence > numberColumns then not in clique.
+  */
+  cliqueEntry * cliqueRow_;
+  /// cliqueRow_ starts for each row
+  int * cliqueRowStart_;
+  /// If not null and [i] !=0 then also tighten even if continuous
+  char * tightenBounds_;
+  //@}
+};
+inline int affectedInDisaggregation(const disaggregationAction & dis)
+{ return dis.affected&0x1fffffff;}
+inline void setAffectedInDisaggregation(disaggregationAction & dis,
+					   int affected)
+{ dis.affected = affected|(dis.affected&0xe0000000);}
+#ifdef NDEBUG
+inline bool zeroOneInDisaggregation(const disaggregationAction & )
+{ return true;}
+#else
+inline bool zeroOneInDisaggregation(const disaggregationAction & dis)
+//{ return (dis.affected&0x80000000)!=0;}
+{ assert ((dis.affected&0x80000000)!=0); return true;}
+#endif
+inline void setZeroOneInDisaggregation(disaggregationAction & dis,bool zeroOne)
+{ dis.affected = (zeroOne ? 0x80000000 : 0)|(dis.affected&0x7fffffff);}
+inline bool whenAtUBInDisaggregation(const disaggregationAction & dis)
+{ return (dis.affected&0x40000000)!=0;}
+inline void setWhenAtUBInDisaggregation(disaggregationAction & dis,bool whenAtUB)
+{ dis.affected = (whenAtUB ? 0x40000000 : 0)|(dis.affected&0xbfffffff);}
+inline bool affectedToUBInDisaggregation(const disaggregationAction & dis)
+{ return (dis.affected&0x20000000)!=0;}
+inline void setAffectedToUBInDisaggregation(disaggregationAction & dis,bool affectedToUB)
+{ dis.affected = (affectedToUB ? 0x20000000 : 0)|(dis.affected&0xdfffffff);}
+
+//#############################################################################
+/** A function that tests the methods in the CglProbing class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglProbingUnitTest(const OsiSolverInterface * siP,
+			const std::string mpdDir );
+/// This just uses implication info   
+class CglImplication : public CglCutGenerator {
+ 
+public:
+
+  /**@name Generate Cuts */
+  //@{
+  /** Generate cuts from implication table
+  Insert generated cuts into the cut set cs.
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglImplication ();
+ 
+  /// Constructor with info
+  CglImplication (CglTreeProbingInfo * info);
+ 
+  /// Copy constructor 
+  CglImplication (
+    const CglImplication &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglImplication &
+    operator=(
+    const CglImplication& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglImplication ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  //@}
+  /**@name Set implication */
+  //@{
+  /// Set implication
+  inline void setProbingInfo(CglTreeProbingInfo * info)
+  { probingInfo_=info;}
+  //@}
+
+private:
+  /**@name Private member data */
+  //@{
+  /// Pointer to tree probing info
+  CglTreeProbingInfo * probingInfo_;
+  //@}
+};
+#endif
diff --git a/cbits/coin/CglRedSplit.cpp b/cbits/coin/CglRedSplit.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglRedSplit.cpp
@@ -0,0 +1,1936 @@
+// Last edit: 4/20/07
+//
+// Name:     CglRedSplit.cpp
+// Author:   Francois Margot                                                  
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     2/6/05
+//
+// $Id: CglRedSplit.cpp 1123 2013-04-06 20:47:24Z stefan $
+//---------------------------------------------------------------------------
+// Copyright (C) 2005, Francois Margot and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+
+//#define RS_TRACE
+//#define RS_TRACEALL
+//#define RS_TRACETAB
+
+#include "OsiSolverInterface.hpp"
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CoinFactorization.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CglRedSplit.hpp"
+#include "CoinFinite.hpp"
+
+//-------------------------------------------------------------------
+// Generate Gomory Reduce-and-Split cuts
+//------------------------------------------------------------------- 
+
+/***************************************************************************/
+// Returns (value - floor) but allowing for small errors
+inline double CglRedSplit::rs_above_integer(double value) 
+{
+  double value2=floor(value);
+  double value3=floor(value+0.5);
+  if (fabs(value3-value)< param.getEPS() * (fabs(value3)+1.0))
+    return 0.0;
+  return value-value2;
+} /* rs_above_integer */
+
+/**********************************************************/
+void rs_allocmatINT(int ***v, const int m, const int n)
+{
+  int i;
+
+  *v = reinterpret_cast<int **> (calloc (m, sizeof(int *)));
+  if (*v == NULL) {
+    printf("###ERROR: INTEGER matrix allocation failed\n");
+    exit(1);
+  }
+
+  for(i=0; i<m; i++) {
+    (*v)[i] = reinterpret_cast<int *> (calloc (n, sizeof(int)));
+    if ((*v)[i] == NULL) {
+      printf("###ERROR: INTEGER matrix allocation failed\n");
+      exit(1);
+    }
+  }
+} /* rs_allocmatINT */
+
+/**********************************************************/
+void rs_deallocmatINT(int ***v, const int m, const int /*n*/)
+{
+  int i;
+
+  for(i=0; i<m; i++) {
+    free(reinterpret_cast<void *> ((*v)[i]));
+  }
+  free(reinterpret_cast<void *> (*v));
+} /* rs_deallocmatINT */
+
+/**********************************************************/
+void rs_allocmatDBL(double ***v, const int m, const int n)
+{
+  int i;
+
+  *v = reinterpret_cast<double **> (calloc (m, sizeof(double *)));
+  if (*v == NULL) {
+    printf("###ERROR: DOUBLE matrix allocation failed\n");
+    exit(1);
+  }
+
+  for(i=0; i<m; i++) {
+    (*v)[i] = reinterpret_cast<double *> (calloc (n, sizeof(double)));
+    if ((*v)[i] == NULL) {
+      printf("###ERROR: DOUBLE matrix allocation failed\n");
+      exit(1);
+    }
+  }
+} /* rs_allocmatDBL */
+
+/**********************************************************/
+void rs_deallocmatDBL(double ***v, const int m, const int /*n*/)
+{
+  int i;
+
+  for(i=0; i<m; i++) {
+    free(reinterpret_cast<void *> ((*v)[i]));
+  }
+  free(reinterpret_cast<void *> (*v));
+} /* rs_deallocmatDBL */
+
+/**********************************************************/
+void rs_printvecINT(const char *vecstr, const int *x, const int n)
+{
+  int num, fromto, upto, j, i;
+
+  num = (n/10) + 1;
+  printf("%s :\n", vecstr);
+  for(j=0; j<num; j++){
+    fromto = 10*j;
+    upto = 10 * (j+1);
+    if(n <= upto) upto = n;
+    for(i=fromto; i<upto; i++)
+      printf(" %4d", x[i]);
+    printf("\n");
+  }
+  printf("\n");
+} /* rs_printvecINT */
+
+/**********************************************************/
+void rs_printvecDBL(char const *vecstr, 
+		    const double *x, const int n)
+{
+  int num, fromto, upto, j, i;
+
+  num = (n/10) + 1;
+  printf("%s :\n", vecstr);
+  for(j=0; j<num; j++){
+    fromto = 10*j;
+    upto = 10 * (j+1);
+    if(n <= upto) upto = n;
+    for(i=fromto; i<upto; i++)
+      printf(" %7.3f", x[i]);
+    printf("\n");
+  }
+  printf("\n");
+} /* rs_printvecDBL */
+
+/**********************************************************/
+void rs_printmatINT(char const *vecstr, const int **x, 
+		    const int m, const int n)
+{
+  int i, j;
+
+  printf("%s :\n", vecstr);
+
+  for(i=0; i<m; i++){
+    for(j=0; j<n; j++){
+      printf(" %4d", x[i][j]);
+    }
+      printf("\n");
+  }
+  printf("\n");
+} /* rs_printmatINT */
+
+/**********************************************************/
+void rs_printmatINT(char const *vecstr, int **x, const int m, const int n)
+{
+  int i, j;
+
+  printf("%s :\n", vecstr);
+
+  for(i=0; i<m; i++){
+    for(j=0; j<n; j++){
+      printf(" %4d", x[i][j]);
+    }
+      printf("\n");
+  }
+  printf("\n");
+} /* rs_printmatINT */
+
+/**********************************************************/
+void rs_printmatDBL(char const *vecstr, double **x, const int m, const int n)
+{
+  int i, j;
+
+  printf("%s :\n", vecstr);
+
+  for(i=0; i<m; i++){
+    for(j=0; j<n; j++){
+      printf(" %7.3f", x[i][j]);
+    }
+      printf("\n");
+  }
+  printf("\n");
+} /* rs_printmatDBL */
+
+/***************************************************************************/
+double rs_dotProd(const double *u, const double *v, const int dim) {
+
+  int i;
+  double result = 0;
+  for(i=0; i<dim; i++) {
+    result += u[i] * v[i];
+  }
+  return(result);
+} /* rs_dotProd */
+
+/***************************************************************************/
+double rs_dotProd(const int *u, const double *v, const int dim) {
+
+  int i;
+  double result = 0;
+  for(i=0; i<dim; i++) {
+    result += u[i] * v[i];
+  }
+  return(result);
+} /* rs_dotProd */
+
+/***************************************************************************/
+double rs_genalea (int *x0)
+{
+  int m = 2147483647;
+  int a = 16807 ;
+  int b = 127773 ;
+  int c = 2836 ;
+  int x1, k;
+
+  k = static_cast<int> ((*x0)/b) ;
+  x1 = a*(*x0 - k*b) - k*c ;
+  if(x1 < 0) x1 = x1 + m;
+  *x0 = x1;
+
+  return(static_cast<double>(x1)/static_cast<double>(m));
+} /* rs_genalea */
+
+/***********************************************************************/
+void CglRedSplit::update_pi_mat(int r1, int r2, int step) {
+
+  int j;
+  for(j=0; j<mTab; j++) {
+    pi_mat[r1][j] = pi_mat[r1][j] - step * pi_mat[r2][j];
+  }
+} /* update_pi_mat */
+
+/***********************************************************************/
+void CglRedSplit::update_redTab(int r1, int r2, int step) {
+
+  int j;
+  for(j=0; j<nTab; j++) {
+    contNonBasicTab[r1][j] = 
+                  contNonBasicTab[r1][j] - step * contNonBasicTab[r2][j];
+  }
+} /* update_redTab */
+
+/***********************************************************************/
+void CglRedSplit::find_step(int r1, int r2, int *step, 
+			    double *reduc, double *norm) {
+
+   double btb_val = rs_dotProd(contNonBasicTab[r1], contNonBasicTab[r2], nTab);
+   double opt_step = btb_val/norm[r2];
+
+   int f_step= static_cast<int> (floor(opt_step));
+   int c_step = f_step + 1;
+
+   double val_f = norm[r1] + f_step * f_step * norm[r2] - 2 * btb_val * f_step;
+   double val_c = norm[r1] + c_step * c_step * norm[r2] - 2 * btb_val * c_step;
+
+   if(val_f <= val_c ) {
+     (*step) = f_step;
+     (*reduc) = norm[r1] - val_f;
+   }
+   else {
+     (*step) = c_step;
+     (*reduc) = norm[r1] - val_c;
+   }
+} /* find_step */
+
+/***************************************************************************/
+int CglRedSplit::test_pair(int r1, int r2, double *norm) {
+
+   int step;
+   double reduc;
+   
+   find_step(r1, r2, &step, &reduc, norm); 
+
+   if(reduc/norm[r1] >= param.getMinReduc()) {
+     update_pi_mat(r1, r2, step);
+     update_redTab(r1, r2, step);
+     norm[r1] = rs_dotProd(contNonBasicTab[r1], contNonBasicTab[r1], nTab);
+
+#ifdef RS_TRACEALL
+     printf("Use %d and %d for reduction (step: %d)\n", r1, r2, step);
+#endif
+
+     return(1);
+   }
+
+   return(0);
+} /* test_pair */
+
+/***************************************************************************/
+void CglRedSplit::reduce_contNonBasicTab() {
+
+  int i, j;
+
+  double *norm = new double[mTab];
+  for(i=0; i<mTab; i++) {
+    norm[i] = rs_dotProd(contNonBasicTab[i], contNonBasicTab[i], nTab);
+  }
+
+  double sum_norms = 0;
+  for(i=0; i<mTab; i++) {
+    sum_norms += norm[i];
+  }
+
+#ifdef RS_TRACE
+  printf("CglRedSplit::reduce_contNonBasicTab():Initial sum of  norms: %f\n", 
+	 sum_norms);
+#endif
+
+  int iter = 0, done = 0;
+  int *changed = new int[mTab]; // changed[i]: last iter where row i updated
+  int **checked; // checked[i][j]: last iter where pair (i, j) checked
+  
+  rs_allocmatINT(&checked, mTab, mTab);
+  for(i=0; i<mTab; i++) {
+    changed[i] = 0;
+    for(j=0; j<mTab; j++) {
+      checked[i][j] = -1;
+    }
+    checked[i][i] = 0;
+  }
+
+  while(!done) {
+    done = 1;
+
+#ifdef RS_TRACEALL
+    rs_printmatDBL("contNonBasicTab", contNonBasicTab, mTab, nTab);
+    rs_printmatINT("checked", checked, mTab, mTab);
+    rs_printvecINT("changed", changed, mTab);
+    rs_printvecDBL("norm", norm, mTab);
+    rs_printmatINT("pi_mat", pi_mat, mTab, mTab);
+#endif
+
+    for(i=0; i<mTab; i++) {
+      if(norm[i] > param.getNormIsZero()) {
+	for(j=i+1; j<mTab; j++) {
+	  if(norm[j] > param.getNormIsZero()) {
+	    if((checked[i][j] < changed[i]) || (checked[i][j] < changed[j])) {
+	      if(test_pair(i, j, norm)) {
+		changed[i] = iter+1;
+		done = 0;
+	      }
+	      checked[i][j] = iter;
+
+	      if((checked[j][i] < changed[i]) || 
+		 (checked[j][i] < changed[j])) {
+		if(test_pair(j, i, norm)) {
+		  changed[j] = iter+1;
+		  done = 0;
+		}
+		checked[j][i] = iter;
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    iter++;
+  }
+
+#ifdef RS_TRACEALL
+  rs_printmatDBL("contNonBasicTab", contNonBasicTab, mTab, nTab);
+  rs_printmatINT("checked", checked, mTab, mTab);
+  rs_printvecINT("changed", changed, mTab);
+  rs_printvecDBL("norm", norm, mTab);
+  rs_printmatINT("pi_mat", pi_mat, mTab, mTab);
+#endif
+
+  sum_norms = 0;
+  for(i=0; i<mTab; i++) {
+    sum_norms += norm[i];
+  }
+
+#ifdef RS_TRACE
+  printf("CglRedSplit::reduce_contNonBasicTab():Final sum of norms: %f\n", sum_norms);
+#endif
+
+  delete[] norm;
+  delete[] changed;
+  rs_deallocmatINT(&checked, mTab, mTab);
+
+} /* reduce_contNonBasicTab */
+
+/************************************************************************/
+void CglRedSplit::generate_row(int index_row, double *row) {
+
+  int i;
+  for(i=0; i<ncol+nrow; i++) {
+    row[i] = 0;
+  }
+  if(!param.getUSE_CG2()) { 
+       // coeff will become zero in generate_cgcut_2() anyway
+    for(i=0; i<card_intBasicVar_frac; i++) {
+      row[intBasicVar_frac[i]] += pi_mat[index_row][i];
+    }
+  }
+  for(i=0; i<card_intNonBasicVar; i++) {
+    int locind = intNonBasicVar[i];
+    row[locind] = 0;
+    int j;
+    for(j=0; j<mTab; j++) {
+      row[locind] += pi_mat[index_row][j] * intNonBasicTab[j][i];
+    }
+  }
+  for(i=0; i<card_contNonBasicVar; i++) {
+    row[contNonBasicVar[i]] = contNonBasicTab[index_row][i];
+  }
+} /* generate_row */
+
+/************************************************************************/
+int CglRedSplit::generate_cgcut(double *row, double *rhs) {
+  
+  double f0 = rs_above_integer(*rhs);
+  double f0compl = 1 - f0;
+
+#ifdef RS_TRACEALL
+  rs_printvecDBL("CglRedSplit::generate_cgcut(): starting row", 
+		 row, ncol+nrow);
+  printf("rhs: %f\n", *rhs);
+#endif
+
+  // See Wolsey "Integer Programming" (1998), p. 130, second line of proof of 
+  // Proposition 8.8
+
+  if((f0 < param.getAway()) || (f0compl < param.getAway())) {
+    return(0);
+  }
+
+  int i;
+  for(i=0; i<card_intNonBasicVar; i++) {
+    int locind = intNonBasicVar[i];
+    double f = rs_above_integer(row[locind]);
+    row[locind] -= f;
+    if(f > f0) {
+      row[locind] += (f-f0)/f0compl;
+    }
+  }
+
+  for(i=0; i<card_contNonBasicVar; i++) {
+    if(row[contNonBasicVar[i]] < 0) {
+      row[contNonBasicVar[i]] /= f0compl;
+    }
+    else {
+      row[contNonBasicVar[i]] = 0;
+    }
+  }
+  (*rhs) -= f0;
+  
+#ifdef RS_TRACEALL
+  rs_printvecDBL("CglRedSplit::generate_cgcut: row", row, ncol+nrow);
+  printf("rhs: %f\n", *rhs);
+#endif
+
+  return(1);
+} /* generate_cgcut */
+
+/************************************************************************/
+int CglRedSplit::generate_cgcut_2(int/* basic_ind*/, double *row, double *rhs) {
+  
+#ifdef RS_TRACEALL
+  rs_printvecDBL("CglRedSplit::generate_cgcut_2(): starting row", 
+		 row, ncol+nrow);
+  printf("rhs: %f\n", *rhs);
+#endif
+
+  // Note that basic integer variables with fractional value
+  // other than basic_ind might have a non zero integer coefficient in the 
+  // "real" row. However, these coefficients become zero anyway in the
+  // cut. It is thus assumed that all basic integer variables have a
+  // coefficient of zero in the given row (enforced in generate_row()).
+  //
+  // Other integer variables and basic continuous variables
+  // have a coefficient of zero, as the corresponding row is not selected
+  // for combination.
+
+  double f0 = rs_above_integer(*rhs);
+  double f0compl = 1 - f0;
+
+  // See Wolsey "Integer Programming" (1998), p. 130, fourth line from top
+  // after correcting typo (Proposition 8.8), flipping all signs to get <=.
+
+  if((f0 < param.getAway()) || (f0compl < param.getAway())) {
+    return(0);
+  }
+
+  double ratf0f0compl = f0/f0compl;
+  int i;
+
+  /** Not needed since coeff are already zero 
+  for(i=0; i<card_intBasicVar_frac; i++) { 
+         // extra integer coefficients compared to formula.
+         // They all become zero.
+    int locind = intBasicVar_frac[i];
+    row[locind] = 0;
+  }
+  **/
+
+  for(i=0; i<card_intNonBasicVar; i++) {
+    int locind = intNonBasicVar[i];
+    double f = rs_above_integer(row[locind]);
+    double fcompl = 1-f;
+
+    if(f > f0) {
+      row[locind] = -ratf0f0compl * fcompl;
+    }
+    else {
+      row[locind] = -f;
+    }
+  }
+
+  for(i=0; i<card_contNonBasicVar; i++) {
+    int locind = contNonBasicVar[i];
+    if(row[locind] < 0) {
+      row[locind] *= ratf0f0compl;
+    }
+    else {
+      row[locind] = -row[locind];
+    }
+  }
+  (*rhs) = -f0;
+  
+#ifdef RS_TRACEALL
+  rs_printvecDBL("CglRedSplit::generate_cgcut_2(): row", row, ncol+nrow);
+  printf("rhs: %f\n", *rhs);
+#endif
+
+  return(1);
+} /* generate_cgcut_2 */
+
+/************************************************************************/
+void CglRedSplit::eliminate_slacks(double *row, 
+				   const double *elements, 
+				   const int *rowStart,
+				   const int *indices,
+				   const int *rowLength,
+				   const double *rhs, double *tabrowrhs) {
+
+  int i, j;
+  for(i=0; i<nrow; i++) {
+    if(fabs(row[ncol+i]) > param.getEPS_ELIM()) {
+
+      if(rowLower[i] > rowUpper[i] - param.getEPS()) {
+	row[ncol+i] = 0;
+	continue;
+      }
+
+      int upto = rowStart[i] + rowLength[i];
+      for(j=rowStart[i]; j<upto; j++) {
+	row[indices[j]] -= row[ncol+i] * elements[j];
+      }
+      *tabrowrhs -= row[ncol+i] * rhs[i];
+    }
+  }
+
+#ifdef RS_TRACEALL
+  rs_printvecDBL("CglRedSplit::eliminate_slacks: row", row, ncol+nrow);
+  printf("rhs: %f\n", *tabrowrhs);
+#endif
+
+} /* eliminate_slacks */
+
+/************************************************************************/
+void CglRedSplit::flip(double *row) {
+  
+  int i;
+  for(i=0; i<card_nonBasicAtUpper; i++) {
+    row[nonBasicAtUpper[i]] = -row[nonBasicAtUpper[i]];
+  }
+} /* flip */
+
+/************************************************************************/
+void CglRedSplit::unflip(double *row, double *tabrowrhs, double *slack_val) {
+  
+  int i;
+  for(i=0; i<card_nonBasicAtLower; i++) {
+    int locind = nonBasicAtLower[i];
+    if(locind < ncol) {
+      *tabrowrhs += row[locind] * colLower[locind];
+    }
+    else {
+      *tabrowrhs += row[locind] * slack_val[locind-ncol];
+    }
+  }
+  for(i=0; i<card_nonBasicAtUpper; i++) {
+    int locind = nonBasicAtUpper[i];
+    row[locind] = -row[locind];
+    if(locind < ncol) {
+      *tabrowrhs += row[locind] * colUpper[locind];
+    }
+    else {
+      *tabrowrhs += row[locind] * slack_val[locind-ncol];
+    }
+  }
+
+#ifdef RS_TRACEALL
+  rs_printvecDBL("After unflip: row", row, ncol+nrow);
+  printf("rhs: %f\n", *tabrowrhs);
+#endif
+
+} /* unflip */
+
+/************************************************************************/
+double CglRedSplit::row_scale_factor(double *row) {
+
+  int i, has_lub = 0, nelem = 0;
+  double val,  norm = 0, max_val = 0, min_val = param.getINFINIT();
+
+  for(i=0; i<ncol; i++) {
+    val = fabs(row[i]);
+    max_val = CoinMax(max_val, val);
+    norm += val * val;
+
+    if(low_is_lub[i] + up_is_lub[i]) {
+      if(val > param.getEPS_COEFF_LUB()) {
+	min_val = CoinMin(min_val, val);
+	has_lub = 1;
+	nelem++;
+      }
+    }
+    else {
+      if(val > param.getEPS_COEFF()) {
+	min_val = CoinMin(min_val, val);
+	nelem++;
+     }
+    }
+  }
+
+  double retval = 1;
+
+  if(norm > 100 * nelem) {
+    retval = 10 * sqrt(norm / nelem);
+  }
+  if(norm < 0.5 * nelem) {
+    retval = 0.5 * sqrt(norm / nelem);
+  }
+
+  if((retval < 0.02) || (retval > 50)) {
+    return(-1);
+  }
+
+  if(has_lub) {
+    if((max_val > param.getEPS_COEFF_LUB()) && 
+       (max_val < param.getMAXDYN_LUB() * min_val) && 
+       (max_val >= min_val)) {
+      return(retval);
+    }
+  }
+  else {
+    if((max_val > param.getEPS_COEFF()) && 
+       (max_val < param.getMAXDYN() * min_val) && 
+       (max_val >= min_val)) {
+      return(retval);
+    }
+  }
+
+#ifdef RS_TRACE
+  printf("CglRedSplit::scale_row(): max_val: %6.6f   min_val: %6.6f\n",
+	 max_val, min_val);
+#endif
+
+  return(-1);
+} /* row_scale_factor */
+
+/************************************************************************/
+int CglRedSplit::generate_packed_row(const double *lclXlp,
+				     double *row,
+				     int *rowind, double *rowelem, 
+				     int *card_row, double & rhs) {
+  int i;
+  double scale_f = row_scale_factor(row);
+  double value;
+
+  if(scale_f < 0) {
+
+#ifdef RS_TRACE
+    printf("CglRedSplit::generate_packed_row(): Cut discarded (bad numerical behavior)\n");
+#endif	
+
+    return(0);
+  }
+
+  *card_row = 0;
+  rhs /= scale_f;
+
+  for(i=0; i<ncol; i++) {
+    value = row[i]/scale_f;
+    if(fabs(value) > param.getEPS_COEFF()) {
+      rowind[*card_row] = i;
+      rowelem[*card_row] = value;
+      (*card_row)++;
+      if(*card_row > param.getMAX_SUPPORT()) {
+
+#ifdef RS_TRACE
+	printf("CglRedSplit::generate_packed_row(): Cut discarded (too many non zero)\n");
+#endif	
+	return(0);
+      }
+    } else {
+      if((value > 0.0) && (!low_is_lub[i])) {
+        rhs -= value * colLower[i];
+      } 
+      else if((value < 0.0) && (!up_is_lub[i])) {
+        rhs -= value * colUpper[i];
+      } 
+      else if(fabs(value) > param.getEPS_COEFF_LUB()) {
+        // take anyway
+        rowind[*card_row] = i;
+        rowelem[*card_row] = value;
+        (*card_row)++;
+        if(*card_row > param.getMAX_SUPPORT()) {
+#ifdef RS_TRACE
+          printf("CglRedSplit::generate_packed_row(): Cut discarded since too many non zero coefficients\n");
+#endif	
+          return(0);
+        }
+      }
+    }
+  }
+  value = 0;
+  for(i=0; i<(*card_row); i++) {
+    value += lclXlp[rowind[i]] * rowelem[i];
+  }
+
+  if(value > rhs) {
+    value -= rhs;
+    if(value < param.getMINVIOL()) {
+
+#ifdef RS_TRACE
+      printf("CglRedSplit::generate_packed_row(): Cut discarded: violation: %12.10f\n", value);
+#endif	
+      
+      return(0);
+    }
+  }
+  
+  return(1);
+} /* generate_packed_row */
+
+// TO BE REMOVED
+/***********************************************************************/
+void CglRedSplit::setLimit(int limit)
+{
+  if (limit>0)
+    param.setMAX_SUPPORT(limit);
+} /* setLimit */
+
+/***********************************************************************/
+int CglRedSplit::getLimit() const
+{
+  return param.getMAX_SUPPORT();
+} /* getLimit */
+
+/***********************************************************************/
+void CglRedSplit::setAway(double value)
+{
+  if (value>0.0 && value<=0.5)
+    param.setAway(value);
+}
+
+/***********************************************************************/
+double CglRedSplit::getAway() const
+{
+  return param.getAway();
+}
+
+/***********************************************************************/
+void CglRedSplit::setMaxTab(double value)
+{
+  if (value > 10) {
+    param.setMaxTab(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setMaxTab(): value: %f ignored\n", 
+	   value);
+  }
+}
+
+/***********************************************************************/
+double CglRedSplit::getMaxTab() const
+{
+  return param.getMaxTab();
+}
+
+/***********************************************************************/
+void CglRedSplit::setLUB(double value)
+{
+  if (value > 0.0) {
+    param.setLUB(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setLUB(): value: %f ignored\n", value);
+  }
+} /* setLUB */
+
+/***********************************************************************/
+double CglRedSplit::getLUB() const
+{
+  return param.getLUB();
+} /* getLUB */
+
+/***********************************************************************/
+void CglRedSplit::setEPS(double value)
+{
+  if (value>0.0 && value<=0.1) {
+    param.setEPS(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setEPS(): value: %f ignored\n", value);
+  }
+} /* setEPS */
+
+/***********************************************************************/
+double CglRedSplit::getEPS() const
+{
+  return param.getEPS();
+} /* getEPS */
+
+/***********************************************************************/
+void CglRedSplit::setEPS_COEFF(double value)
+{
+  if (value > 0.0 && value <= 0.1) {
+    param.setEPS_COEFF(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setEPS_COEFF(): value: %f ignored\n", 
+	   value);
+  }
+} /* setEPS_COEFF */
+
+/***********************************************************************/
+double CglRedSplit::getEPS_COEFF() const
+{
+  return param.getEPS_COEFF();
+} /* getEPS_COEFF */
+
+/***********************************************************************/
+void CglRedSplit::setEPS_COEFF_LUB(double value)
+{
+  if (value > 0.0 && value <= 0.1) {
+    param.setEPS_COEFF_LUB(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setEPS_COEFF_LUB(): value: %f ignored\n", 
+	   value);
+  }
+} /* setEPS_COEFF_LUB */
+
+/***********************************************************************/
+double CglRedSplit::getEPS_COEFF_LUB() const
+{
+  return param.getEPS_COEFF_LUB();
+} /* getEPS_COEFF_LUB */
+
+/***********************************************************************/
+void CglRedSplit::setEPS_RELAX(double value)
+{
+  if (value > 0.0 && value <= 0.1) {
+    param.setEPS_RELAX_ABS(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setEPS_RELAX(): value: %f ignored\n", 
+	   value);
+  }
+} /* setEPS_RELAX */
+
+/***********************************************************************/
+double CglRedSplit::getEPS_RELAX() const
+{
+  return param.getEPS_RELAX_ABS();
+} /* getEPS_RELAX */
+
+/***********************************************************************/
+void CglRedSplit::setNormIsZero(double value)
+{
+  if (value>0.0 && value<=1) {
+    param.setNormIsZero(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setNormIsZero(): value: %f ignored\n",
+	   value);
+  }
+} /* setNormIsZero */
+
+/***********************************************************************/
+double CglRedSplit::getNormIsZero() const
+{
+  return param.getNormIsZero();
+} /* getNormIsZero */
+
+/***********************************************************************/
+void CglRedSplit::setMinReduc(double value)
+{
+  if (value>0.0 && value<=1) {
+    param.setMinReduc(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit::MinReduc(): value: %f ignored\n",
+	   value);
+  }
+} /* setMinReduc */
+
+/***********************************************************************/
+double CglRedSplit::getMinReduc() const
+{
+  return param.getMinReduc();
+} /* getMinReduc */
+
+/************************************************************************/
+void CglRedSplit::set_given_optsol(const double *given_sol, int card_sol) {
+  given_optsol = given_sol;
+  card_given_optsol = card_sol;
+} /* set_given_optsol */
+
+/************************************************************************/
+void CglRedSplit::check_optsol(const int calling_place,
+			       const double *lclXlp, const double *slack_val,
+			       const int do_flip) {
+
+  if(card_given_optsol != ncol) {
+    printf("### ERROR: CglRedSplit(): card_given_optsol: %d  ncol: %d\n", 
+	   card_given_optsol, ncol);
+    exit(1);
+  }
+
+  int i;
+  double *ck_slack = new double[nrow];
+
+#ifdef RS_TRACEALL
+  print();
+#endif
+
+  byRow->timesMinor(given_optsol, ck_slack);
+  int irow;
+  for(irow=0; irow<nrow; irow++) {
+    ck_slack[irow] = rowRhs[irow] - ck_slack[irow];  
+                                        // slack values for optimal solution
+  }
+  
+  double *ck_row = new double[ncol+nrow];
+  
+  for(irow=0; irow<mTab; irow++) {
+    for(i=0; i<ncol+nrow; i++) {
+      ck_row[i] = 0;
+    }
+    for(i=0; i<card_intBasicVar_frac; i++) {
+      ck_row[intBasicVar_frac[i]] = pi_mat[irow][i];
+    }
+    for(i=0; i<card_intNonBasicVar; i++) {
+      ck_row[intNonBasicVar[i]] = 0;
+      int j;
+      for(j=0; j<mTab; j++) {
+	ck_row[intNonBasicVar[i]] += pi_mat[irow][j] * intNonBasicTab[j][i];
+      }
+    }
+    for(i=0; i<card_contNonBasicVar; i++) {
+      ck_row[contNonBasicVar[i]] = contNonBasicTab[irow][i];
+    }
+
+    double adjust_rhs = 0;
+    if(do_flip) {
+      for(i=0; i<card_nonBasicAtLower; i++) {
+	int locind = nonBasicAtLower[i];
+	if(locind < ncol) {
+	  adjust_rhs += ck_row[locind] * colLower[locind];
+	}
+	else {
+	  adjust_rhs += ck_row[locind] * slack_val[locind-ncol];
+	}
+      }
+      for(i=0; i<card_nonBasicAtUpper; i++) {
+	int locind = nonBasicAtUpper[i];
+	ck_row[locind] = -ck_row[locind];
+	if(locind < ncol) {
+	  adjust_rhs += ck_row[locind] * colUpper[locind];
+	}
+	else {
+	  adjust_rhs += ck_row[locind] * slack_val[locind-ncol];
+	}
+      }
+    }
+
+    double ck_lhs = rs_dotProd(ck_row, given_optsol, ncol);
+    ck_lhs += rs_dotProd(&(ck_row[ncol]), ck_slack, nrow);
+    
+    double ck_rhs = adjust_rhs + rs_dotProd(ck_row, lclXlp, ncol);
+    ck_rhs += rs_dotProd(&(ck_row[ncol]), slack_val, nrow);
+    
+#ifdef RS_TRACEALL
+    rs_printvecDBL("ck_row", ck_row, ncol);
+    rs_printvecDBL("given_optsol", given_optsol, ncol);
+    rs_printvecDBL("ck_row(slacks)", &(ck_row[ncol]), nrow);
+    rs_printvecDBL("ck_slack", ck_slack, nrow);
+    printf("ck_rhs: %12.8f\n", ck_rhs); 
+#endif
+
+    if((ck_lhs < ck_rhs - param.getEPS()) || (ck_lhs > ck_rhs + param.getEPS())) {
+      printf("### ERROR: CglRedSplit::check_optsol(): Cut %d cuts given_optsol\n", 
+	     irow);
+      rs_printvecDBL("ck_row", ck_row, ncol+nrow);
+      printf("lhs: %f  rhs: %f    calling_place: %d\n", 
+	     ck_lhs, ck_rhs, calling_place);
+      exit(1);
+    }
+  }
+  delete[] ck_slack;
+  delete[] ck_row;
+} /* check_optsol */
+
+/************************************************************************/
+void CglRedSplit::check_optsol(const int calling_place,
+			       const double * /*lclXlp*/, const double *slack_val,
+			       const double *ck_row, const double ck_rhs,
+			       const int cut_number, const int do_flip) {
+
+  if(card_given_optsol != ncol) {
+    printf("### ERROR: CglRedSplit(): card_given_optsol: %d  ncol: %d\n", 
+	   card_given_optsol, ncol);
+    exit(1);
+  }
+
+  double *cpy_row = new double[ncol+nrow];
+  double *ck_slack = new double[nrow];
+
+#ifdef RS_TRACEALL
+  print();
+#endif
+
+  int i, irow;
+  for(i=0; i<ncol+nrow; i++) {
+    cpy_row[i] = ck_row[i];
+  }
+
+  byRow->timesMinor(given_optsol, ck_slack);
+  for(irow=0; irow<nrow; irow++) {
+    ck_slack[irow] = rowRhs[irow] - ck_slack[irow];  
+                                       // slack values for optimal solution
+  }
+  
+  double adjust_rhs = 0;
+  if(do_flip) {
+    for(i=0; i<card_nonBasicAtLower; i++) {
+      int locind = nonBasicAtLower[i];
+      if(locind < ncol) {
+	adjust_rhs += cpy_row[locind] * colLower[locind];
+      }
+      else {
+	adjust_rhs += cpy_row[locind] * slack_val[locind-ncol];
+      }
+    }
+    for(i=0; i<card_nonBasicAtUpper; i++) {
+      int locind = nonBasicAtUpper[i];
+      cpy_row[locind] = -cpy_row[locind];
+      if(locind < ncol) {
+	adjust_rhs += cpy_row[locind] * colUpper[locind];
+      }
+      else {
+	adjust_rhs += cpy_row[locind] * slack_val[locind-ncol];
+      }
+    }
+  }
+
+
+  double ck_lhs = rs_dotProd(cpy_row, given_optsol, ncol);
+  ck_lhs += rs_dotProd(&(cpy_row[ncol]), ck_slack, nrow);
+    
+  if(ck_lhs > ck_rhs + adjust_rhs + param.getEPS()) {
+    printf("### ERROR: CglRedSplit::check_optsol(): Cut %d cuts given_optsol\n", 
+	   cut_number);
+    rs_printvecDBL("cpy_row", cpy_row, ncol+nrow);
+    printf("lhs: %f  rhs: %f    calling_place: %d\n", 
+	   ck_lhs, ck_rhs + adjust_rhs, calling_place);
+    exit(1);
+  }
+  delete[] cpy_row;
+  delete[] ck_slack;
+} /* check_optsol */
+
+/************************************************************************/
+bool CglRedSplit::rs_are_different_vectors(const int *vect1, 
+					   const int *vect2,
+					   const int dim) {
+  int i;
+  for(i=0; i<dim; i++) {
+    if(vect1[i] != vect2[i]) {
+      printf("### ERROR: rs_are_different_vectors(): vect1[%d]: %d vect2[%d]: %d\n", i, vect1[i], i, vect2[i]);
+      return(0);
+    }    
+  }
+  return(1);
+} /* rs_are_different_vectors */
+
+/************************************************************************/
+bool CglRedSplit::rs_are_different_vectors(const double *vect1, 
+					   const double *vect2,
+					   const int dim) {
+  int i;
+  for(i=0; i<dim; i++) {
+    if(fabs(vect1[i] - vect2[i]) > 1e-6) {
+      printf("### ERROR: rs_are_different_vectors(): vect1[%d]: %12.8f vect2[%d]: %12.8f\n", i, vect1[i], i, vect2[i]);
+      return(0);
+    }    
+  }
+  return(1);
+} /* rs_are_different_vectors */
+
+/************************************************************************/
+bool CglRedSplit::rs_are_different_matrices(const CoinPackedMatrix *mat1, 
+					    const CoinPackedMatrix *mat2,
+					    const int nmaj,
+					    const int /*nmin*/) {
+  
+  const int *matStart1 = mat1->getVectorStarts();
+  const double *matElements1 = mat1->getElements();
+  const int *matIndices1 = mat1->getIndices();
+  const int *matRowLength1 = mat1->getVectorLengths(); 
+
+  const int *matStart2 = mat2->getVectorStarts();
+  const double *matElements2 = mat2->getElements();
+  const int *matIndices2 = mat2->getIndices();
+  const int *matRowLength2 = mat2->getVectorLengths(); 
+
+  int i, j;
+
+  for(i=0; i<nmaj; i++) {
+    if(matStart1[i] != matStart2[i]) {
+      printf("### ERROR: rs_are_different_matrices(): matStart1[%d]: %d matStart2[%d]: %d\n", i, matStart1[i], i, matStart2[i]);
+      return(1);
+    }
+    if(matRowLength1[i] != matRowLength2[i]) {
+      printf("### ERROR: rs_are_different_matrices(): matRowLength1[%d]: %d matRowLength2[%d]: %d\n", i, matRowLength1[i], i, matRowLength2[i]);
+      return(1);
+    }
+
+    for(j=matStart1[i]; j<matStart1[i]+matRowLength1[i]; j++) {
+      if(matIndices1[j] != matIndices2[j]) {
+	printf("### ERROR: rs_are_different_matrices(): matIndices1[%d]: %d matIndices2[%d]: %d\n", j, matIndices1[j], j, matIndices2[j]);
+	return(1);
+      }
+      if(fabs(matElements1[j] - matElements2[j]) > 1e-6) {
+	printf("### ERROR: rs_are_different_matrices(): matElements1[%d]: %12.8f matElements2[%d]: %12.8f\n", j, matElements1[j], j, matElements2[j]);
+	return(1);
+      }
+    }
+  }
+  return(0);
+} /* rs_are_different_matrices */
+
+/************************************************************************/
+void CglRedSplit::generateCuts(const OsiSolverInterface &si, OsiCuts & cs,
+			       const CglTreeInfo )
+{
+  solver = const_cast<OsiSolverInterface *>(&si);
+  if(solver == NULL) {
+    printf("### WARNING: CglRedSplit::generateCuts(): no solver available.\n");
+    return;    
+  }  
+
+  if(!solver->optimalBasisIsAvailable()) {
+    printf("### WARNING: CglRedSplit::generateCuts(): no optimal basis available.\n");
+    return;
+  }
+
+  // Reset some members of CglRedSplit
+  card_intBasicVar_frac = 0;
+  card_intNonBasicVar = 0;
+  card_contNonBasicVar = 0;
+  card_nonBasicAtUpper = 0;
+  card_nonBasicAtLower = 0;
+
+  // Get basic problem information from solver
+  ncol = solver->getNumCols(); 
+  nrow = solver->getNumRows(); 
+  colLower = solver->getColLower();
+  colUpper = solver->getColUpper();
+  rowLower = solver->getRowLower();
+  rowUpper = solver->getRowUpper();
+  rowRhs = solver->getRightHandSide();
+
+  xlp = solver->getColSolution();
+  rowActivity = solver->getRowActivity();
+  colType = NULL;
+  byRow = solver->getMatrixByRow();
+
+  solver->enableFactorization();
+  generateCuts(cs);
+  solver->disableFactorization();
+} /* generateCuts */
+
+/************************************************************************/
+void CglRedSplit::generateCuts(OsiCuts &cs)
+{
+  int i;
+  low_is_lub = new int[ncol]; 
+  up_is_lub = new int[ncol]; 
+  is_integer = new int[ncol]; 
+  
+  compute_is_lub();
+  compute_is_integer();
+
+  int *cstat = new int[ncol];
+  int *rstat = new int[nrow];
+  solver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
+                                          // 2: upper 3: lower
+
+  int *basis_index = new int[nrow]; // basis_index[i] = 
+                                    //        index of pivot var in row i
+                                    //        (slack if number >= ncol) 
+
+#ifdef RS_TRACETAB
+  rs_printvecINT("cstat", cstat, ncol);
+  rs_printvecINT("rstat", rstat, nrow);
+#endif
+
+  solver->getBasics(basis_index);
+
+  cv_intBasicVar_frac = new int[ncol];  
+  intBasicVar_frac = new int[ncol];                                 
+  intNonBasicVar = new int[ncol];       
+  contNonBasicVar = new int[ncol+nrow]; 
+  nonBasicAtUpper = new int[ncol+nrow]; 
+  nonBasicAtLower = new int[ncol+nrow]; 
+  double dist_int;
+
+  for(i=0; i<ncol; i++) {
+    cv_intBasicVar_frac[i] = 0;
+
+    switch(cstat[i]) {
+    case 1: // basic variable
+      
+      dist_int = rs_above_integer(xlp[i]);
+      if(is_integer[i] && 
+	 (dist_int > param.getAway()) && (dist_int < 1 - param.getAway())) {
+	cv_intBasicVar_frac[i] = 1;
+	card_intBasicVar_frac++;
+
+	// intBasicVar_frac computed below, 
+	// as order must be according to selected rows
+
+      }
+      break;
+
+    case 2: // Non basic at upper bound: must be flipped and shifted
+            // so that it becomes non negative with lower bound 0 
+            // It is assumed that bounds for integer variables have been
+            // tightend so that non basic integer structural variables 
+            // have integer values
+
+      nonBasicAtUpper[card_nonBasicAtUpper] = i;
+      card_nonBasicAtUpper++;
+
+      if(is_integer[i]) {
+	intNonBasicVar[card_intNonBasicVar] = i;
+	card_intNonBasicVar++;
+      }
+      else {
+	contNonBasicVar[card_contNonBasicVar] = i;
+	card_contNonBasicVar++;
+      }
+      break;
+
+    case 3 : // non basic at lower bound: must be shifted so that it becomes
+             // non negative with lower bound 0
+            // It is assumed that bounds for integer variables have been
+            // tightend so that they are integer
+
+      nonBasicAtLower[card_nonBasicAtLower] = i;
+      card_nonBasicAtLower++;
+
+      if(is_integer[i]) {
+	intNonBasicVar[card_intNonBasicVar] = i;
+	card_intNonBasicVar++;
+      }
+      else {
+	contNonBasicVar[card_contNonBasicVar] = i;
+	card_contNonBasicVar++;
+      }
+      break;
+
+    default: // free variable ? Don't know how to handle 
+      printf("### ERROR: CglRedSplit::generateCuts(): cstat[%d]: %d\n",
+	     i, cstat[i]);
+      exit(1);
+      break;
+    } 
+  }
+
+  for(i=0; i<nrow; i++) {
+    switch(rstat[i]) {
+    case 1: // basic slack
+      break;
+
+    case 2: // non basic slack at upper; flipped and shifted
+      nonBasicAtUpper[card_nonBasicAtUpper] = ncol+i;
+      card_nonBasicAtUpper++;
+
+      contNonBasicVar[card_contNonBasicVar] = ncol+i;
+      card_contNonBasicVar++;
+      break;
+
+    case 3: // non basic slack at lower; shifted
+      nonBasicAtLower[card_nonBasicAtLower] = ncol+i;
+      card_nonBasicAtLower++;
+
+      contNonBasicVar[card_contNonBasicVar] = ncol+i;
+      card_contNonBasicVar++;
+      break;
+
+    default: 
+      printf("### ERROR: CglRedSlpit::generateCuts(): rstat[%d]: %d\n",
+	     i, rstat[i]);
+      exit(1);
+      break;
+    }
+  }
+
+  if((card_contNonBasicVar == 0) || (card_intBasicVar_frac == 0)) {
+    delete[] cstat;
+    delete[] rstat;
+    delete[] basis_index;
+
+    delete[] cv_intBasicVar_frac;  
+    delete[] intBasicVar_frac;
+    delete[] intNonBasicVar;
+    delete[] contNonBasicVar;
+    delete[] nonBasicAtUpper;
+    delete[] nonBasicAtLower;
+    delete[] low_is_lub;
+    delete[] up_is_lub;
+    delete[] is_integer;
+
+    return; // no cuts can be generated
+  }
+
+  /* Loop is mTab * mTab * CoinMax(mTab, nTab) so may be very expensive. 
+     Reduce mTab if the above value is larger than maxTab_ */
+
+  int new_mTab = card_intBasicVar_frac;
+  double nc = static_cast<double> (card_contNonBasicVar);
+  double nc3 = nc * nc * nc;
+
+  if(nc3 > param.getMaxTab()) {
+    new_mTab = static_cast<int> (sqrt(param.getMaxTab()/card_contNonBasicVar));
+  }
+  else {
+#if defined(_MSC_VER)
+    new_mTab = static_cast<int> (pow(param.getMaxTab(), 1./3.));
+#else
+    new_mTab = static_cast<int> (cbrt(param.getMaxTab()));
+#endif
+  }
+
+  if(new_mTab == 0) {
+    delete[] cstat;
+    delete[] rstat;
+    delete[] basis_index;
+    
+    delete[] cv_intBasicVar_frac;  
+    delete[] intBasicVar_frac;
+    delete[] intNonBasicVar;
+    delete[] contNonBasicVar;
+    delete[] nonBasicAtUpper;
+    delete[] nonBasicAtLower;
+    delete[] low_is_lub;
+    delete[] up_is_lub;
+    delete[] is_integer;
+    return; // no cuts can be generated
+  }
+
+  int start = 0;  // first row for selecting intBasicVar_frac, if too many.
+                  // Removing rows used for generation whose pivot is some 
+                  // var in intBasicVar_frac is valid since the corresponding 
+                  // column in the optimal tableau is a column of the 
+                  // identity matrix 
+
+  if(new_mTab < card_intBasicVar_frac) {
+    // Remove some of the rows used for generation.
+    // Poor randomness; could do better if needed
+
+    int seed = card_intBasicVar_frac;
+    start = static_cast<int> (nrow * rs_genalea(&seed));
+    
+#ifdef RS_TRACE
+    printf("CglRedSlpit::generateCuts(): mTab: %d  new_mTab: %d\n", 
+	   card_intBasicVar_frac, new_mTab);
+#endif
+
+    card_intBasicVar_frac = new_mTab;
+  }
+  
+double *slack_val = new double[nrow];
+
+  for(i=0; i<nrow; i++) {
+    slack_val[i] = rowRhs[i] - rowActivity[i];
+  }
+
+#ifdef RS_DEBUG
+  double *solver_rhs = solver->getRightHandSide();
+  if(rs_are_different_vectors(rowRhs, solver_rhs, nrow)) {
+    printf("### ERROR: CglRedSplit::generateCuts(): rowRhs[%d]: %12.f  solver_rhs[%d]: %12.f\n", i, rowRhs[i], i, solver_rhs[i]);
+    exit(1);
+  }
+#endif
+
+  double *z = new double[ncol];  // workspace to get row of the tableau
+  double *slack = new double[nrow];  // workspace to get row of the tableau
+
+#ifdef RS_TRACETAB
+  printOptTab(solver);
+#endif
+
+  mTab = card_intBasicVar_frac;
+  nTab = card_contNonBasicVar;
+
+  rhsTab = new double[mTab];
+  int card_rowTab = 0;
+
+  rs_allocmatDBL(&contNonBasicTab, mTab, nTab);
+  rs_allocmatDBL(&intNonBasicTab, mTab, card_intNonBasicVar);
+
+  card_intBasicVar_frac = 0; // recompute in pivot order
+
+  for(i=0; i<nrow; i++) {
+
+    if(mTab <= card_intBasicVar_frac) { 
+      break;
+    }
+
+    int ind_row = start + i;
+    if(ind_row > nrow) {
+      ind_row -= nrow;
+    }
+
+    if(basis_index[ind_row] >= ncol) {
+      continue;
+    } 
+
+    if(cv_intBasicVar_frac[basis_index[ind_row]] == 1) { 
+                                                  // row used in generation
+      intBasicVar_frac[card_intBasicVar_frac] = basis_index[ind_row];
+      card_intBasicVar_frac++;
+      rhsTab[card_rowTab] = xlp[basis_index[ind_row]];
+      solver->getBInvARow(ind_row, z, slack);
+      int ii;
+      for(ii=0; ii<card_contNonBasicVar; ii++) {
+	int locind = contNonBasicVar[ii];
+	if(locind < ncol) {
+	  contNonBasicTab[card_rowTab][ii] = z[locind];
+	}
+	else {
+	  contNonBasicTab[card_rowTab][ii] = slack[locind - ncol];
+	}
+      }
+
+      for(ii=0; ii<card_intNonBasicVar; ii++) {
+	int locind = intNonBasicVar[ii];
+	if(locind < ncol) {
+	  intNonBasicTab[card_rowTab][ii] = z[locind];
+	}
+	else {
+	  printf("### ERROR: CglRedSplit::generateCuts(): integer slack unexpected\n");
+	  exit(1);
+	}
+      }
+
+      card_rowTab++;
+    }
+  }
+
+  rs_allocmatINT(&pi_mat, mTab, mTab);
+  for(i=0; i<mTab; i++) {
+    int ii;
+    for(ii=0; ii<mTab; ii++) {
+      pi_mat[i][ii] = 0;
+    }
+    pi_mat[i][i] = 1;
+  }
+
+#ifdef RS_TRACE
+  printf("intBasicVar_frac:\n");
+  for(i=0; i<card_intBasicVar_frac; i++) {
+    printf("%d ", intBasicVar_frac[i]);
+  }
+  printf("\n");
+  printf("intNonBasicVar:\n");
+  for(i=0; i<card_intNonBasicVar; i++) {
+    printf("%d ", intNonBasicVar[i]);
+  }
+  printf("\n");
+  printf("contNonBasicVar:\n");
+  for(i=0; i<card_contNonBasicVar; i++) {
+    printf("%d ", contNonBasicVar[i]);
+  }
+  printf("\n");
+#endif
+
+  if(given_optsol) {
+    check_optsol(1, xlp, slack_val, 0);
+  }
+
+  reduce_contNonBasicTab();
+
+  if(given_optsol) {
+    check_optsol(2, xlp, slack_val, 0);
+  }
+
+  int card_row;
+  double *row = new double[ncol+nrow];
+  int *rowind = new int[ncol];
+  double *rowelem = new double[ncol];
+
+  const double *elements = byRow->getElements();
+  const int *rowStart = byRow->getVectorStarts();
+  const int *indices = byRow->getIndices();
+  const int *rowLength = byRow->getVectorLengths(); 
+
+  for(i=0; i<mTab; i++) {
+    generate_row(i, row);
+    flip(row);
+
+    // RHS of equalities after flipping/translating non basic variables
+    // is given by the current LP solution (re-ordered according to 
+    // basis_index), i.e. what is now in rhsTab. 
+    // RHS of row i of (pi_mat * contNonBasicTab) is then simply 
+    // pi_mat[i] * rhsTab
+
+    double tabrowrhs = rs_dotProd(pi_mat[i], rhsTab, mTab); 
+    int got_one = 0;
+    
+    if(param.getUSE_CG2()) {
+      got_one = generate_cgcut_2(intBasicVar_frac[i], row, &tabrowrhs);
+    }
+    else {
+      got_one = generate_cgcut(row, &tabrowrhs);
+    }
+    
+    if(got_one) {
+      unflip(row, &tabrowrhs, slack_val);
+
+      if(given_optsol) {
+	check_optsol(3, xlp, slack_val, row, tabrowrhs, i, 0);
+      }
+
+      eliminate_slacks(row, elements, rowStart, indices, 
+		       rowLength, rowRhs, &tabrowrhs);
+
+      if(given_optsol) {
+	check_optsol(4, xlp, slack_val, row, tabrowrhs, i, 0);
+      }
+
+      if(generate_packed_row(xlp, row, rowind, rowelem, &card_row, 
+			     tabrowrhs)) {
+      	OsiRowCut rc;
+	rc.setRow(card_row, rowind, rowelem);
+	rc.setLb(-param.getINFINIT());
+	double adjust = param.getEPS_RELAX_ABS();
+	if(param.getEPS_RELAX_REL() > 0.0) {
+	  adjust += fabs(tabrowrhs) * param.getEPS_RELAX_REL();
+	}
+	rc.setUb(tabrowrhs + adjust);   
+                                  // relax the constraint slightly
+	cs.insertIfNotDuplicate(rc, CoinAbsFltEq(param.getEPS_COEFF()));
+      }
+    }
+  }
+
+  delete[] cstat;
+  delete[] rstat;
+  delete[] basis_index;
+  delete[] slack;
+  delete[] z;
+  delete[] slack_val;
+  delete[] row;
+  delete[] rowind;
+  delete[] rowelem;
+
+  delete[] cv_intBasicVar_frac;  
+  delete[] intBasicVar_frac;
+  delete[] intNonBasicVar;
+  delete[] contNonBasicVar;
+  delete[] nonBasicAtUpper;
+  delete[] nonBasicAtLower;
+  delete[] low_is_lub;
+  delete[] up_is_lub;
+  delete[] is_integer;
+  rs_deallocmatDBL(&contNonBasicTab, mTab, nTab);
+  rs_deallocmatDBL(&intNonBasicTab, mTab, card_intNonBasicVar);
+  rs_deallocmatINT(&pi_mat, mTab, mTab);
+  delete[] rhsTab;
+
+  //return(cs.sizeRowCuts());
+} /* generateCuts */
+
+/***********************************************************************/
+void CglRedSplit::setParam(const CglRedSplitParam &source) {
+  param = source;
+} /* setParam */
+
+/***********************************************************************/
+void CglRedSplit::compute_is_lub() {
+
+  int i;
+  for(i=0; i<ncol; i++) {
+    low_is_lub[i] = 0;
+    up_is_lub[i] = 0;
+    if(fabs(colUpper[i]) > param.getLUB()) {
+      up_is_lub[i] = 1;
+    }
+    if(fabs(colLower[i]) > param.getLUB()) {
+      low_is_lub[i] = 1;
+    }
+  }
+} /* compute_is_lub */
+
+/***********************************************************************/
+void CglRedSplit::compute_is_integer() {
+
+  int i;
+
+  if(colType != NULL) {
+    for(i=0; i<ncol; i++) {
+      if(colType[i] != 'C') {
+	is_integer[i] = 1;
+      }
+      else {
+	if((colUpper[i] - colLower[i] < param.getEPS()) && 
+	   (rs_above_integer(colUpper[i]) < param.getEPS())) {
+	  
+	  // continuous variable fixed to an integer value
+	  is_integer[i] = 1;
+	}
+	else {
+	  is_integer[i] = 0;
+	}
+      }
+    }
+  }
+  else {
+    for(i=0; i<ncol; i++) {
+      if(solver->isInteger(i)) {
+	is_integer[i] = 1;
+      }
+      else {
+	if((colUpper[i] - colLower[i] < param.getEPS()) && 
+	   (rs_above_integer(colUpper[i]) < param.getEPS())) {
+	  
+	  // continuous variable fixed to an integer value
+	  is_integer[i] = 1;
+	}
+	else {
+	  is_integer[i] = 0;
+	}
+      }
+    }    
+  }
+} /* compute_is_integer */
+
+/***********************************************************************/
+void CglRedSplit::print() const
+{
+  rs_printvecINT("intBasicVar_frac", intBasicVar_frac, card_intBasicVar_frac);
+  rs_printmatINT("pi_mat", pi_mat, card_intBasicVar_frac, 
+		 card_intBasicVar_frac);
+  rs_printvecINT("intNonBasicVar", intNonBasicVar, card_intNonBasicVar);
+  rs_printmatDBL("intNonBasicTab", intNonBasicTab, card_intBasicVar_frac, 
+		 card_intNonBasicVar);
+  rs_printvecINT("contNonBasicVar", contNonBasicVar, card_contNonBasicVar);
+  rs_printmatDBL("contNonBasicTab", contNonBasicTab, card_intBasicVar_frac, 
+		 card_contNonBasicVar);
+  rs_printvecINT("nonBasicAtLower", nonBasicAtLower, card_nonBasicAtLower);
+  rs_printvecINT("nonBasicAtUpper", nonBasicAtUpper, card_nonBasicAtUpper);
+
+} /* print */
+
+/***********************************************************************/
+void CglRedSplit::printOptTab(OsiSolverInterface *lclSolver) const
+{
+  int i;
+  int *cstat = new int[ncol];
+  int *rstat = new int[nrow];
+
+  lclSolver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
+                                          // 2: upper 3: lower
+
+  int *basis_index = new int[nrow]; // basis_index[i] = 
+                                    //        index of pivot var in row i
+                                    //        (slack if number >= ncol) 
+  lclSolver->getBasics(basis_index);
+
+  double *z = new double[ncol];  // workspace to get row of the tableau
+  double *slack = new double[nrow];  // workspace to get row of the tableau
+  double *slack_val = new double[nrow];
+
+  for(i=0; i<nrow; i++) {
+    slack_val[i] = rowRhs[i] - rowActivity[i];
+  }
+
+  const double *rc = lclSolver->getReducedCost();
+  const double *dual = lclSolver->getRowPrice();
+  const double *solution = lclSolver->getColSolution();
+
+  rs_printvecINT("cstat", cstat, ncol);
+  rs_printvecINT("rstat", rstat, nrow);
+  rs_printvecINT("basis_index", basis_index, nrow);
+
+  rs_printvecDBL("solution", solution, ncol);
+  rs_printvecDBL("slack_val", slack_val, nrow);
+  rs_printvecDBL("reduced_costs", rc, ncol);
+  rs_printvecDBL("dual solution", dual, nrow);
+
+  printf("Optimal Tableau:\n");
+
+  for(i=0; i<nrow; i++) {
+    lclSolver->getBInvARow(i, z, slack);
+    int ii;
+    for(ii=0; ii<ncol; ii++) {
+      printf("%5.2f ", z[ii]);
+    }
+    printf(" | ");
+    for(ii=0; ii<nrow; ii++) {
+      printf("%5.2f ", slack[ii]);
+    }
+    printf(" | ");
+    if(basis_index[i] < ncol) {
+      printf("%5.2f ", solution[basis_index[i]]);
+    }
+    else {
+      printf("%5.2f ", slack_val[basis_index[i]-ncol]);
+    }
+    printf("\n");
+  }
+  int ii;
+  for(ii=0; ii<7*(ncol+nrow+1); ii++) {
+    printf("-");
+  }
+  printf("\n");
+
+  for(ii=0; ii<ncol; ii++) {
+    printf("%5.2f ", rc[ii]);    
+  }
+  printf(" | ");
+  for(ii=0; ii<nrow; ii++) {
+    printf("%5.2f ", -dual[ii]);
+  }
+  printf(" | ");
+  printf("%5.2f\n", -lclSolver->getObjValue());
+
+  delete[] cstat;
+  delete[] rstat;
+  delete[] basis_index;
+  delete[] slack;
+  delete[] z;
+  delete[] slack_val;
+} /* printOptTab */
+
+/*********************************************************************/
+CglRedSplit::CglRedSplit() :
+CglCutGenerator(),
+nrow(0),
+ncol(0),
+card_intBasicVar_frac(0),
+card_intNonBasicVar(0),
+card_contNonBasicVar(0),
+card_nonBasicAtUpper(0),
+card_nonBasicAtLower(0),
+cv_intBasicVar_frac(0),
+intBasicVar_frac(0),
+intNonBasicVar(0), 
+contNonBasicVar(0),
+nonBasicAtUpper(0),
+nonBasicAtLower(0),
+mTab(0),
+nTab(0),
+pi_mat(0),
+contNonBasicTab(0),
+intNonBasicTab(0),
+rhsTab(0),
+given_optsol(0),
+card_given_optsol(0)
+{}
+
+/*********************************************************************/
+CglRedSplit::CglRedSplit(const CglRedSplitParam &RS_param) :
+CglCutGenerator(),
+nrow(0),
+ncol(0),
+card_intBasicVar_frac(0),
+card_intNonBasicVar(0),
+card_contNonBasicVar(0),
+card_nonBasicAtUpper(0),
+card_nonBasicAtLower(0),
+cv_intBasicVar_frac(0),
+intBasicVar_frac(0),
+intNonBasicVar(0), 
+contNonBasicVar(0),
+nonBasicAtUpper(0),
+nonBasicAtLower(0),
+mTab(0),
+nTab(0),
+pi_mat(0),
+contNonBasicTab(0),
+intNonBasicTab(0),
+rhsTab(0),
+given_optsol(0),
+card_given_optsol(0)
+{
+  param = RS_param;
+}
+ 
+/*********************************************************************/
+CglRedSplit::CglRedSplit (const CglRedSplit & source) :
+  CglCutGenerator(source),
+  param(source.param),
+  nrow(0),
+  ncol(0),
+  card_intBasicVar_frac(0),
+  card_intNonBasicVar(0),
+  card_contNonBasicVar(0),
+  card_nonBasicAtUpper(0),
+  card_nonBasicAtLower(0),
+  cv_intBasicVar_frac(NULL),
+  intBasicVar_frac(NULL),
+  intNonBasicVar(NULL), 
+  contNonBasicVar(NULL),
+  nonBasicAtUpper(NULL),
+  nonBasicAtLower(NULL),
+  mTab(0),
+  nTab(0),
+  pi_mat(NULL),
+  contNonBasicTab(NULL),
+  intNonBasicTab(NULL),
+  rhsTab(NULL),
+  given_optsol(source.given_optsol),
+  card_given_optsol(source.card_given_optsol)
+{}
+
+/*********************************************************************/
+CglCutGenerator *
+CglRedSplit::clone() const
+{
+  return new CglRedSplit(*this);
+}
+
+/*********************************************************************/
+CglRedSplit::~CglRedSplit ()
+{}
+
+/*********************************************************************/
+CglRedSplit &
+CglRedSplit::operator=(const CglRedSplit &source)
+{  
+
+  if (this != &source) {
+    CglCutGenerator::operator=(source);
+    param = source.param;
+    given_optsol = source.given_optsol;
+    card_given_optsol = source.card_given_optsol;
+  }
+  return *this;
+}
+/*********************************************************************/
+// Returns true if needs optimal basis to do cuts
+bool 
+CglRedSplit::needsOptimalBasis() const
+{
+  return true;
+}
+
+/*********************************************************************/
+// Create C++ lines to get to current state
+std::string
+CglRedSplit::generateCpp(FILE * fp) 
+{
+  CglRedSplit other;
+  fprintf(fp,"0#include \"CglRedSplit.hpp\"\n");
+  fprintf(fp,"3  CglRedSplit redSplit;\n");
+  if (param.getMAX_SUPPORT()!=other.param.getMAX_SUPPORT())
+    fprintf(fp,"3  redSplit.setLimit(%d);\n",param.getMAX_SUPPORT());
+  else
+    fprintf(fp,"4  redSplit.setLimit(%d);\n",param.getMAX_SUPPORT());
+  if (param.getAway()!=other.param.getAway())
+    fprintf(fp,"3  redSplit.setAway(%g);\n",param.getAway());
+  else
+    fprintf(fp,"4  redSplit.setAway(%g);\n",param.getAway());
+  if (param.getLUB()!=other.param.getLUB())
+    fprintf(fp,"3  redSplit.setLUB(%g);\n",param.getLUB());
+  else
+    fprintf(fp,"4  redSplit.setLUB(%g);\n",param.getLUB());
+  if (param.getEPS()!=other.param.getEPS())
+    fprintf(fp,"3  redSplit.set.EPS(%g);\n",param.getEPS());
+  else
+    fprintf(fp,"4  redSplit.setEPS(%g);\n",param.getEPS());
+  if (param.getEPS_COEFF()!=other.param.getEPS_COEFF())
+    fprintf(fp,"3  redSplit.setEPS_COEFF(%g);\n",param.getEPS_COEFF());
+  else
+    fprintf(fp,"4  redSplit.set.EPS_COEFF(%g);\n",param.getEPS_COEFF());
+  if (param.getEPS_COEFF_LUB()!=other.param.getEPS_COEFF_LUB())
+    fprintf(fp,"3  redSplit.set.EPS_COEFF_LUB(%g);\n",param.getEPS_COEFF_LUB());
+  else
+    fprintf(fp,"4  redSplit.set.EPS_COEFF_LUB(%g);\n",param.getEPS_COEFF_LUB());
+  if (param.getEPS_RELAX_ABS()!=other.param.getEPS_RELAX_ABS())
+    fprintf(fp,"3  redSplit.set.EPS_RELAX(%g);\n",param.getEPS_RELAX_ABS());
+  else
+    fprintf(fp,"4  redSplit.set.EPS_RELAX(%g);\n",param.getEPS_RELAX_ABS());
+  if (param.getNormIsZero()!=other.param.getNormIsZero())
+    fprintf(fp,"3  redSplit.setNormIsZero(%g);\n",param.getNormIsZero());
+  else
+    fprintf(fp,"4  redSplit.setNormIsZero(%g);\n",param.getNormIsZero());
+  if (param.getMinReduc()!=other.param.getMinReduc())
+    fprintf(fp,"3  redSplit.setMinReduc(%g);\n",param.getMinReduc());
+  else
+    fprintf(fp,"4  redSplit.setMinReduc(%g);\n",param.getMinReduc());
+  if (param.getMaxTab()!=other.param.getMaxTab())
+    fprintf(fp,"3  redSplit.setMaxTab(%g);\n",param.getMaxTab());
+  else
+    fprintf(fp,"4  redSplit.setMaxTab(%g);\n",param.getMaxTab());
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  redSplit.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  redSplit.setAggressiveness(%d);\n",getAggressiveness());
+  return "redSplit";
+}
diff --git a/cbits/coin/CglRedSplit.hpp b/cbits/coin/CglRedSplit.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglRedSplit.hpp
@@ -0,0 +1,448 @@
+// Last edit: 4/20/07
+//
+// Name:     CglRedSplit.hpp
+// Author:   Francois Margot
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+//           email: fmargot@andrew.cmu.edu
+// Date:     2/6/05
+//
+// $Id: CglRedSplit.hpp 1123 2013-04-06 20:47:24Z stefan $
+//-----------------------------------------------------------------------------
+// Copyright (C) 2005, Francois Margot and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglRedSplit_H
+#define CglRedSplit_H
+
+#include "CglCutGenerator.hpp"
+#include "CglRedSplitParam.hpp"
+
+/** Gomory Reduce-and-Split Cut Generator Class; See method generateCuts().
+    Based on the paper by K. Anderson, G. Cornuejols, Yanjun Li, 
+    "Reduce-and-Split Cuts: Improving the Performance of Mixed Integer 
+    Gomory Cuts", Management Science 51 (2005). */
+
+class CglRedSplit : public CglCutGenerator {
+
+  friend void CglRedSplitUnitTest(const OsiSolverInterface * siP,
+				  const std::string mpdDir);
+public:
+  /**@name generateCuts */
+  //@{
+  /** Generate Reduce-and-Split Mixed Integer Gomory cuts 
+      for the model of the solver interface si.
+
+      Insert the generated cuts into OsiCuts cs.
+
+      Warning: This generator currently works only with the Lp solvers Clp or 
+      Cplex9.0 or higher. It requires access to the optimal tableau and 
+      optimal basis inverse and makes assumptions on the way slack variables 
+      are added by the solver. The Osi implementations for Clp and Cplex 
+      verify these assumptions.
+
+      When calling the generator, the solver interface si 
+      must contain an optimized
+      problem and information related to the optimal basis must be available 
+      through the OsiSolverInterface methods (si->optimalBasisIsAvailable()
+      must return 'true'). It is also essential that the integrality of
+      structural variable i can be obtained using si->isInteger(i).
+
+      Reduce-and-Split cuts are variants of Gomory cuts: Starting from
+      the current optimal tableau, linear combinations of the rows of 
+      the current optimal simplex tableau are used for generating Gomory
+      cuts. The choice of the linear combinations is driven by the objective 
+      of reducing the coefficients of the non basic continuous variables
+      in the resulting row.
+      Note that this generator might not be able to generate cuts for some 
+      solutions violating integrality constraints. 
+
+  */
+  virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			    const CglTreeInfo info = CglTreeInfo());
+
+  /// Return true if needs optimal basis to do cuts (will return true)
+  virtual bool needsOptimalBasis() const;
+  //@}
+  
+  
+  /**@name Public Methods */
+  //@{
+
+  // Set the parameters to the values of the given CglRedSplitParam object.
+  void setParam(const CglRedSplitParam &source); 
+  // Return the CglRedSplitParam object of the generator. 
+  inline CglRedSplitParam getParam() const {return param;}
+
+  // Compute entries of low_is_lub and up_is_lub.
+  void compute_is_lub();
+
+  // Compute entries of is_integer.
+  void compute_is_integer();
+
+  /// Set given_optsol to the given optimal solution given_sol.
+  /// If given_optsol is set using this method, 
+  /// the code will stop as soon as
+  /// a generated cut is violated by the given solution; exclusively 
+  /// for debugging purposes.
+  void set_given_optsol(const double *given_sol, const int card_sol);
+
+  /// Print some of the data members  
+  void print() const;
+
+  /// Print the current simplex tableau  
+  void printOptTab(OsiSolverInterface *solver) const;
+  
+  //@}
+
+ /**@name Public Methods (soon to be obsolete)*/
+  //@{
+  //************************************************************
+  // TO BE REMOVED
+  /** Set limit, the maximum number of non zero coefficients in generated cut;
+      Default: 50 */
+  void setLimit(int limit);
+  /** Get value of limit */
+  int getLimit() const;
+
+  /** Set away, the minimum distance from being integer used for selecting 
+      rows for cut generation;  all rows whose pivot variable should be 
+      integer but is more than away from integrality will be selected; 
+      Default: 0.05 */
+  void setAway(double value);
+  /// Get value of away
+  double getAway() const;
+ /** Set the value of LUB, value considered large for the absolute value of
+      a lower or upper bound on a variable;
+      Default: 1000 */
+  void setLUB(double value);
+  /** Get the value of LUB */
+  double getLUB() const;
+
+  /** Set the value of EPS, epsilon for double computations;
+      Default: 1e-7 */
+  void setEPS(double value);
+  /** Get the value of EPS */
+  double getEPS() const;
+
+  /** Set the value of EPS_COEFF, epsilon for values of coefficients;
+      Default: 1e-8 */
+  void setEPS_COEFF(double value);
+  /** Get the value of EPS_COEFF */
+  double getEPS_COEFF() const;
+
+  /** Set the value of EPS_COEFF_LUB, epsilon for values of coefficients for 
+      variables with absolute value of lower or upper bound larger than LUB;
+      Default: 1e-13 */
+  void setEPS_COEFF_LUB(double value);
+  /** Get the value of EPS_COEFF_LUB */
+  double getEPS_COEFF_LUB() const;
+
+  /** Set the value of EPS_RELAX, value used for relaxing the right hand side
+      of each generated cut;
+      Default: 1e-8 */
+  void setEPS_RELAX(double value);
+  /** Get the value of EPS_RELAX */
+  double getEPS_RELAX() const;
+
+  /** Set the value of normIsZero, the threshold for considering a norm to be 
+      0; Default: 1e-5 */
+  void setNormIsZero(double value);
+  /** Get the value of normIsZero */
+  double getNormIsZero() const;
+
+  /** Set the value of minReduc, threshold for relative norm improvement for
+   performing  a reduction; Default: 0.05 */
+  void setMinReduc(double value);
+  /// Get the value of minReduc
+  double getMinReduc() const;
+
+  /** Set the maximum allowed value for (mTab * mTab * CoinMax(mTab, nTab)) where 
+      mTab is the number of rows used in the combinations and nTab is the 
+      number of continuous non basic variables. The work of the generator is 
+      proportional to (mTab * mTab * CoinMax(mTab, nTab)). Reducing the value of 
+      maxTab makes the generator faster, but weaker. Default: 1e7. */
+  void setMaxTab(double value);
+  /// Get the value of maxTab
+  double getMaxTab() const;
+  // END TO BE REMOVED
+  //************************************************************
+
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglRedSplit();
+
+  /// Constructor with specified parameters 
+  CglRedSplit(const CglRedSplitParam &RS_param);
+ 
+  /// Copy constructor 
+  CglRedSplit (const CglRedSplit &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglRedSplit &
+    operator=(
+    const CglRedSplit& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglRedSplit ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  //@}
+    
+private:
+  
+  // Private member methods
+
+/**@name Private member methods */
+
+  //@{
+
+  // Method generating the cuts after all CglRedSplit members are properly set.
+  void generateCuts(OsiCuts & cs);
+
+  /// Compute the fractional part of value, allowing for small error.
+  inline double rs_above_integer(double value); 
+
+  /// Perform row r1 of pi := row r1 of pi - step * row r2 of pi.
+  void update_pi_mat(int r1, int r2, int step);
+
+  /// Perform row r1 of tab := row r1 of tab - step * row r2 of tab.
+  void update_redTab(int r1, int r2, int step);
+
+  /// Find optimal integer step for changing row r1 by adding to it a 
+  /// multiple of another row r2.
+  void find_step(int r1, int r2, int *step, 
+		 double *reduc, double *norm);
+
+  /// Test if an ordered pair of rows yields a reduction. Perform the
+  /// reduction if it is acceptable.
+  int test_pair(int r1, int r2, double *norm);
+
+  /// Reduce rows of contNonBasicTab.
+  void reduce_contNonBasicTab();
+
+  /// Generate a row of the current LP tableau.
+  void generate_row(int index_row, double *row);
+
+  /// Generate a mixed integer Chvatal-Gomory cut, when all non basic 
+  /// variables are non negative and at their lower bound.
+  int generate_cgcut(double *row, double *rhs);
+
+  /// Generate a mixed integer Chvatal-Gomory cut, when all non basic 
+  /// variables are non negative and at their lower bound (different formula)
+  int generate_cgcut_2(int basic_ind, double *row, double *rhs);
+
+  /// Use multiples of the initial inequalities to cancel out the coefficients
+  /// of the slack variables.
+  void eliminate_slacks(double *row, 
+			const double *elements, 
+			const int *start,
+			const int *indices,
+			const int *rowLength,
+			const double *rhs, double *rowrhs);
+
+  /// Change the sign of the coefficients of the continuous non basic
+  /// variables at their upper bound.
+  void flip(double *row);
+
+  /// Change the sign of the coefficients of the continuous non basic
+  /// variables at their upper bound and do the translations restoring
+  /// the original bounds. Modify the right hand side
+  /// accordingly.
+  void unflip(double *row, double *rowrhs, double *slack_val);
+
+  /// Return the scale factor for the row. 
+  /// Compute max_coeff: maximum absolute value of the coefficients.
+  /// Compute min_coeff: minimum absolute value of the coefficients
+  /// larger than EPS_COEFF.
+  /// Return -1 if max_coeff < EPS_COEFF or if max_coeff/min_coeff > MAXDYN
+  /// or MAXDYN_LUB (depending if the row has a non zero coeff. for a variable
+  /// with large lower/upper bound) */.
+  double row_scale_factor(double *row);
+
+  /// Generate the packed cut from the row representation.
+  int generate_packed_row(const double *xlp, double *row,
+			  int *rowind, double *rowelem, 
+			  int *card_row, double & rhs);
+
+  /// Check that the generated cuts do not cut a given optimal solution.
+  void check_optsol(const int calling_place,
+		    const double *xlp, const double *slack_val,
+		    const int do_flip);
+
+  /// Check that the generated cuts do not cut a given optimal solution.
+  void check_optsol(const int calling_place,
+		    const double *xlp, const double *slack_val,
+		    const double *ck_row, const double ck_rhs, 
+		    const int cut_number, const int do_flip);
+
+  // Check that two vectors are different.
+  bool rs_are_different_vectors(const int *vect1, 
+				const int *vect2,
+				const int dim);
+
+  // Check that two vectors are different.
+  bool rs_are_different_vectors(const double *vect1, 
+				const double *vect2,
+				const int dim);
+
+  // Check that two matrices are different.
+  bool rs_are_different_matrices(const CoinPackedMatrix *mat1, 
+				 const CoinPackedMatrix *mat2,
+				 const int nmaj,
+				 const int nmin);
+  //@}
+
+  
+  // Private member data
+
+/**@name Private member data */
+
+  //@{
+
+  /// Object with CglRedSplitParam members. 
+  CglRedSplitParam param;
+
+  /// Number of rows ( = number of slack variables) in the current LP.
+  int nrow; 
+
+  /// Number of structural variables in the current LP.
+  int ncol;
+
+  /// Lower bounds for structural variables
+  const double *colLower;
+
+  /// Upper bounds for structural variables
+  const double *colUpper;
+  
+  /// Lower bounds for constraints
+  const double *rowLower;
+
+  /// Upper bounds for constraints
+  const double *rowUpper;
+
+  /// Righ hand side for constraints (upper bound for ranged constraints).
+  const double *rowRhs;
+
+  /// Number of integer basic structural variables that are fractional in the
+  /// current lp solution (at least param.away_ from being integer).  
+  int card_intBasicVar_frac;
+
+  /// Number of integer non basic structural variables in the
+  /// current lp solution.  
+  int card_intNonBasicVar; 
+
+  /// Number of continuous non basic variables (structural or slack) in the
+  /// current lp solution.  
+  int card_contNonBasicVar;
+
+  /// Number of non basic variables (structural or slack) at their
+  /// upper bound in the current lp solution.
+  int card_nonBasicAtUpper; 
+
+  /// Number of non basic variables (structural or slack) at their
+  /// lower bound in the current lp solution.
+  int card_nonBasicAtLower;
+
+  /// Characteristic vector for integer basic structural variables
+  /// with non integer value in the current lp solution.
+  int *cv_intBasicVar_frac;  
+
+  /// List of integer structural basic variables 
+  /// (in order of pivot in selected rows for cut generation).
+  int *intBasicVar_frac;
+
+  /// List of integer structural non basic variables.
+  int *intNonBasicVar; 
+
+  /// List of continuous non basic variables (structural or slack). 
+  // slacks are considered continuous (no harm if this is not the case).
+  int *contNonBasicVar;
+
+  /// List of non basic variables (structural or slack) at their 
+  /// upper bound. 
+  int *nonBasicAtUpper;
+
+  /// List of non basic variables (structural or slack) at their lower
+  /// bound.
+  int *nonBasicAtLower;
+
+  /// Number of rows in the reduced tableau (= card_intBasicVar_frac).
+  int mTab;
+
+  /// Number of columns in the reduced tableau (= card_contNonBasicVar)
+  int nTab;
+
+  /// Tableau of multipliers used to alter the rows used in generation.
+  /// Dimensions: mTab by mTab. Initially, pi_mat is the identity matrix.
+  int **pi_mat;
+
+  /// Current tableau for continuous non basic variables (structural or slack).
+  /// Only rows used for generation.
+  /// Dimensions: mTab by nTab.
+  double **contNonBasicTab;
+
+  /// Current tableau for integer non basic structural variables.
+  /// Only rows used for generation.
+  // Dimensions: mTab by card_intNonBasicVar.
+  double **intNonBasicTab;
+
+  /// Right hand side of the tableau.
+  /// Only rows used for generation.
+  double *rhsTab ;
+
+  /// Given optimal solution that should not be cut; only for debug. 
+  const double *given_optsol;
+
+  /// Number of entries in given_optsol.
+  int card_given_optsol;
+
+  /// Characteristic vectors of structural integer variables or continuous
+  /// variables currently fixed to integer values. 
+  int *is_integer;
+
+  /// Characteristic vector of the structural variables whose lower bound 
+  /// in absolute value is larger than LUB. 
+  int *low_is_lub;
+
+  /// Characteristic vector of the structural variables whose upper bound 
+  /// in absolute value is larger than LUB. 
+  int *up_is_lub;
+
+  /// Pointer on solver. Reset by each call to generateCuts().
+  OsiSolverInterface *solver;
+
+  /// Pointer on point to separate. Reset by each call to generateCuts().
+  const double *xlp;
+
+  /// Pointer on row activity. Reset by each call to generateCuts().
+  const double *rowActivity;
+
+  /// Pointer on column type. Reset by each call to generateCuts().
+  const char *colType;
+
+  /// Pointer on matrix of coefficient ordered by rows. 
+  /// Reset by each call to generateCuts().
+  const CoinPackedMatrix *byRow;
+
+  //@}
+};
+
+//#############################################################################
+/** A function that tests the methods in the CglRedSplit class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglRedSplitUnitTest(const OsiSolverInterface * siP,
+			 const std::string mpdDir );
+
+
+#endif
diff --git a/cbits/coin/CglRedSplit2.cpp b/cbits/coin/CglRedSplit2.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglRedSplit2.cpp
@@ -0,0 +1,3086 @@
+// Last edit: 04/03/10
+//
+// Name:     CglRedSplit2.cpp
+// Author:   Giacomo Nannicini
+//           Singapore University of Technology and Design
+//           Singapore
+//           email: nannicini@sutd.edu.sg
+//           based on CglRedSplit by Francois Margot
+// Date:     03/09/09
+//-----------------------------------------------------------------------------
+// Copyright (C) 2010, Giacomo Nannicini and others.  All Rights Reserved.
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <climits>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+
+/* Debug output */
+//#define RS2_TRACE
+
+/* Print optimal tableau and basis */
+//#define RS2_TRACETAB
+
+/* Use LAPACK instead of own code for solving linear systems */
+//#define RS2_USE_LAPACK
+// Sparse for intNonBasic 0,1,2
+#define RS_FAST_INT 2
+// Sparse for contNonBasic 0,1,2
+#define RS_FAST_CONT 2
+// Sparse for workNonBasic 0,1,2
+#define RS_FAST_WORK 2
+
+#include "CoinPragma.hpp"
+#include "OsiSolverInterface.hpp"
+
+#include "CglRedSplit2.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CoinFactorization.hpp"
+#include "CoinFinite.hpp"
+
+#define TINY 1e-20
+
+#define rs2round(x) (floor((x)+0.5))
+
+//-------------------------------------------------------------------
+// Generate Reduce-and-Split cuts
+//------------------------------------------------------------------- 
+
+#ifdef RS2_USE_LAPACK
+extern "C" void dgesv_( const int * , const int * , double * , const int * , int * , double * , const int * , int * );
+#endif
+
+/***************************************************************************/
+
+
+// Utility functions and definitions for sorting
+struct sortElement{
+  int index;
+  double cost;
+};
+
+// Return -1 if firstE has lower cost or same cost but lower index
+int rs2_compareElements(const void* firstE, const void* secondE){
+  const struct sortElement* a = static_cast<const struct sortElement*>(firstE);
+  const struct sortElement* b = static_cast<const struct sortElement*>(secondE);
+  if (a->cost < b->cost)
+    return -1;
+  else if (a->cost > b->cost)
+    return 1;
+  else if (a->index < b->index)
+    return -1;
+  else if (a->index > b->index)
+    return 1;
+
+  return 0;
+}
+
+/***************************************************************************/
+// Returns (value - floor) but allowing for small errors;
+// taken from the CglGomory cut generator
+inline double CglRedSplit2::rs_above_integer(const double value) const
+{
+  double value2=floor(value);
+  double value3=rs2round(value);
+  if (fabs(value3-value)< param.getEPS() * (fabs(value3)+1.0))
+    return 0.0;
+  return value-value2;
+} /* rs_above_integer */
+
+/**********************************************************/
+void CglRedSplit2::rs_allocmatINT(int ***v, int m, int n)
+{
+  *v = reinterpret_cast<int **> (calloc (m, sizeof(int *)));
+  if (*v == NULL) {
+    printf("###ERROR: INTEGER matrix allocation failed\n");
+    exit(1);
+  }
+
+  for (int i = 0; i < m; ++i) {
+    (*v)[i] = reinterpret_cast<int *> (calloc (n, sizeof(int)));
+    if ((*v)[i] == NULL) {
+      printf("###ERROR: INTEGER matrix allocation failed\n");
+      exit(1);
+    }
+  }
+} /* rs_allocmatINT */
+
+/**********************************************************/
+void CglRedSplit2::rs_deallocmatINT(int ***v, int m)
+{
+  for (int i = 0; i < m; ++i) {
+    free(reinterpret_cast<void *> ((*v)[i]));
+  }
+  free(reinterpret_cast<void *> (*v));
+} /* rs_deallocmatINT */
+
+/**********************************************************/
+void CglRedSplit2::rs_allocmatDBL(double ***v, int m, int n)
+{
+  *v = reinterpret_cast<double **> (calloc (m, sizeof(double *)));
+  if (*v == NULL) {
+    printf("###ERROR: DOUBLE matrix allocation failed\n");
+    exit(1);
+  }
+
+  for (int i = 0; i < m; ++i){
+    (*v)[i] = reinterpret_cast<double *> (calloc (n, sizeof(double)));
+    if ((*v)[i] == NULL) {
+      printf("###ERROR: DOUBLE matrix allocation failed\n");
+      exit(1);
+    }
+  }
+} /* rs_allocmatDBL */
+
+/**********************************************************/
+void CglRedSplit2::rs_deallocmatDBL(double ***v, int m)
+{
+  for (int i = 0; i < m; ++i){
+    free(reinterpret_cast<void *> ((*v)[i]));
+  }
+  free(reinterpret_cast<void *> (*v));
+} /* rs_deallocmatDBL */
+
+/**********************************************************/
+void CglRedSplit2::rs_printvecINT(const char *vecstr, const int *x, int n) const
+{
+  int num, fromto, upto, j, i;
+
+  num = (n/10) + 1;
+  printf("%s :\n", vecstr);
+  for(j=0; j<num; j++){
+    fromto = 10*j;
+    upto = 10 * (j+1);
+    if(n <= upto) upto = n;
+    for(i=fromto; i<upto; i++)
+      printf(" %4d", x[i]);
+    printf("\n");
+  }
+  printf("\n");
+} /* rs_printvecINT */
+
+/**********************************************************/
+void CglRedSplit2::rs_printvecDBL(const char *vecstr, 
+				  const double *x, int n) const
+{
+  int num, fromto, upto, j, i;
+
+  num = (n/10) + 1;
+  printf("%s :\n", vecstr);
+  for(j=0; j<num; j++){
+    fromto = 10*j;
+    upto = 10 * (j+1);
+    if(n <= upto) upto = n;
+    for(i=fromto; i<upto; i++)
+      printf(" %7.5f", x[i]);
+    printf("\n");
+  }
+  printf("\n");
+} /* rs_printvecDBL */
+
+/**********************************************************/
+void CglRedSplit2::rs_printmatINT(const char *vecstr, const int * const *x, 
+				  int m, int n) const
+{
+  printf("%s :\n", vecstr);
+  for (int i = 0; i < m; ++i){
+    for (int j = 0; j < n; ++j){
+      printf(" %4d", x[i][j]);
+    }
+    printf("\n");
+  }
+  printf("\n");
+} /* rs_printmatINT */
+
+
+/**********************************************************/
+void CglRedSplit2::rs_printmatDBL(const char *vecstr, const double * const *x, int m, int n) const
+{
+  printf("%s :\n", vecstr);
+  for (int i = 0; i < m; ++i){
+    for (int j = 0; j < n; ++j){
+      printf(" %7.3f", x[i][j]);
+    }
+    printf("\n");
+  }
+  printf("\n");
+} /* rs_printmatDBL */
+
+/***************************************************************************/
+double CglRedSplit2::rs_dotProd(const double *u, const double *v, int dim) const
+{
+  double result = 0;
+  for (int i = 0; i < dim; ++i){
+    result += u[i] * v[i];
+  }
+  return(result);
+} /* rs_dotProd */
+
+/***************************************************************************/
+static double rs_sparseDotProd(const double *u, const double *v, 
+			       const int * uInd, const int * vInd)
+{
+  double result = 0;
+  if (uInd[0]<vInd[0]) {
+    int n=uInd[0];
+    uInd++;
+    for (int i = 0; i < n; ++i) {
+      int j=uInd[i];
+      result += u[j] * v[j];
+    }
+  } else {
+    int n=vInd[0];
+    vInd++;
+    for (int i = 0; i < n; ++i) {
+      int j=vInd[i];
+      result += u[j] * v[j];
+    }
+  }
+  return(result);
+} /* rs_sparseDotProd */
+
+/***************************************************************************/
+double CglRedSplit2::rs_dotProd(const int *u, const double *v, int dim) const {
+  double result = 0;
+  for (int i=0; i < dim; ++i){
+    result += u[i] * v[i];
+  }
+  return(result);
+} /* rs_dotProd */
+
+/***************************************************************************/
+// From Numerical Recipes in C: LU decomposition
+int CglRedSplit2::ludcmp(double **a, int n, int *indx, 
+			 double *d, double* vv) const {
+  int ret = true;
+  int i, imax = 0, j, k;
+  double big, dum, sum, temp;
+
+  *d=1.0;
+  for (i = 1; i <= n; ++i){
+    big = 0.0;
+    for(j = 1; j <= n; j++) {
+      temp = fabs(a[i-1][j-1]);
+      if (temp > big) {
+	big = temp;
+      }
+    }
+    if (big == 0.0) {
+      return false;
+    }
+    vv[i-1]=1.0/big;
+  }
+  for (j = 1; j <= n; ++j){
+    for (i=1;i<j;i++) {
+      sum = a[i-1][j-1];
+      for(k = 1; k < i; k++) {
+	sum -= a[i-1][k-1] * a[k-1][j-1];
+      }
+      a[i-1][j-1]=sum;
+    }
+    big=0.0;
+    for (i = j; i <= n; i++) {
+      sum = a[i-1][j-1];
+      for (k = 1; k < j; k++) {
+	sum -= a[i-1][k-1]*a[k-1][j-1];
+      }
+      a[i-1][j-1] = sum;
+      dum = vv[i-1]*fabs(sum);
+      if (dum >= big) {
+	big = dum;
+	imax = i;
+      }
+    }
+    if (j != imax) {
+      for (k=1;k<=n;k++) {
+	dum=a[imax-1][k-1];
+	a[imax-1][k-1]=a[j-1][k-1];
+	a[j-1][k-1]=dum;
+      }
+      *d = -(*d);
+      vv[imax-1]=vv[j-1];
+    }
+    indx[j-1]=imax;
+    if (a[j-1][j-1] == 0.0) a[j-1][j-1]=TINY;
+    if (j != n) {
+      dum=1.0/(a[j-1][j-1]);
+      for (i=j+1;i<=n;i++) a[i-1][j-1] *= dum;
+    }
+  }  
+  return ret;
+}
+
+/***************************************************************************/
+// from Numerical Recipes in C: backward substitution
+void CglRedSplit2::lubksb(double **a, int n, int *indx, double *b) const {
+  int i,ii=0,ip,j;
+  double sum;
+
+  for (i = 1; i <= n; ++i){
+    ip=indx[i-1];
+    sum=b[ip-1];
+    b[ip-1]=b[i-1];
+    if (ii)
+      for (j=ii;j<=i-1;j++) sum -= a[i-1][j-1]*b[j-1];
+    else if (sum) ii=i;
+    b[i-1]=sum;
+  }
+  for (i=n;i>=1;i--) {
+    sum=b[i-1];
+    for (j=i+1;j<=n;j++) sum -= a[i-1][j-1]*b[j-1];
+    b[i-1]=sum/a[i-1][i-1];
+  }
+}
+
+/***************************************************************************/
+double CglRedSplit2::compute_norm_change(double oldnorm, const int* list, 
+					 int numElemList,
+					 const double* multipliers) const {
+  double newnorm = 0;
+  double accumulator;
+  for (int j = 0; j < nTab; ++j){
+    accumulator = 0;
+    for (int i = 0; i < numElemList; ++i){
+      accumulator += multipliers[i]*workNonBasicTab[list[i]][j];
+    }
+    newnorm += accumulator*accumulator;
+  }
+  return (newnorm-oldnorm);
+  
+}
+/***************************************************************************/
+int CglRedSplit2::sort_rows_by_nonzeroes(struct sortElement* array, 
+					 int rowIndex, int maxRows,
+					 int whichTab) const {
+  // Note: this function only takes into account rows which share at least
+  // a nonzero column with the row that we want to reduce (rowIndex).
+  int counter = 0;
+  int numZeroCost = 0;
+  for (int i = 0; i < mTab; ++i){
+    if (!checkTime()){
+      break;
+    }
+    if (numZeroCost == maxRows){
+      // We found enough rows with cost equal to zero, i.e. "perfect" rows
+      // No need to continue!
+      counter = numZeroCost;
+      break;
+    }
+    if ((i != rowIndex) && (norm[i] > param.getNormIsZero())){
+      // sort rows by number of nonzeros on nonbasic columns. 
+      // check if they have at least one nonzero in the same place,
+      // otherwise skip
+      bool match = false;
+      for (int j = 0; j < nTab; ++j){
+	if ((fabs(workNonBasicTab[rowIndex][j]) > param.getEPS_COEFF()) &&
+	    (fabs(workNonBasicTab[i][j]) > param.getEPS_COEFF())){
+	  match = true;
+	  break;
+	}
+      }
+      if (!match)
+	continue;
+      array[counter].index = i;
+      array[counter].cost = 0;
+      // whichTab = 0 means only intNonBasicTab, 1 means only
+      // workNonBasicTab, 2 means both
+      if (whichTab == 0 || whichTab == 2){
+	for (int j = 0; j < card_intNonBasicVar; ++j){
+	  if ((fabs(intNonBasicTab[rowIndex][j]) <= param.getEPS_COEFF()) &&
+	      (fabs(intNonBasicTab[i][j]) > param.getEPS_COEFF())){
+	    array[counter].cost += 1;
+	  }
+	}
+      }
+      if (whichTab == 1 || whichTab == 2){
+	for (int j = 0; j < nTab; ++j){
+	  if ((fabs(workNonBasicTab[rowIndex][j]) <= param.getEPS_COEFF()) &&
+	      (fabs(workNonBasicTab[i][j]) > param.getEPS_COEFF())){
+	    array[counter].cost += 1;
+	  }
+	}
+      }
+      if (array[counter].cost == 0){
+	array[counter] = array[numZeroCost];
+	array[numZeroCost].index = i;
+	array[numZeroCost].cost = 0;
+	numZeroCost++;
+      }
+      counter++;
+    }
+  }
+  if (counter > maxRows){
+    qsort(array, counter, sizeof(struct sortElement), rs2_compareElements);
+  }
+  return counter;
+}
+/***************************************************************************/
+int CglRedSplit2::sort_rows_by_nonzeroes_greedy(struct sortElement* array,
+						int rowIndex, int maxRows,
+						int whichTab) const{
+  int counter = 0;
+  counter = sort_rows_by_nonzeroes(array, rowIndex, maxRows, whichTab);
+  if (counter > maxRows){
+    int i, j;
+    // vector of positions of zero elements
+    int* z_int = NULL;
+    int* z_cont = NULL;
+    // whichTab = 0 means only intNonBasicTab, 1 means only
+    // workNonBasicTab, 2 means both
+    if (whichTab == 0 || whichTab == 2)
+      z_int = new int[card_intNonBasicVar];
+    if (whichTab == 1 || whichTab == 2)
+      z_cont = new int[nTab];
+    // number of elements in the vectors above
+    int numz_int = 0;
+    int numz_cont = 0;
+    // compute initial vector of nonzeroes
+    if (whichTab == 0 || whichTab == 2){
+      for (j = 0; j < card_intNonBasicVar; ++j){
+	if (fabs(intNonBasicTab[rowIndex][j]) <= param.getEPS_COEFF()){
+	  z_int[numz_int++] = j;
+	}
+      }
+    }
+    if (whichTab == 1 || whichTab == 2){
+      for (j = 0; j < nTab; ++j){
+	if (fabs(workNonBasicTab[rowIndex][j]) <= param.getEPS_COEFF()){
+	  z_cont[numz_cont++] = j;
+	}
+      }
+    }
+    int numSorted = counter;
+    counter = 1;
+    // store the minimum number of nz introduced by one row
+    int minNz;
+    // and the position of that row
+    int rowMinNz;
+    // maximum number of nonzero that can be introduced
+    double maxNz;
+    int currentNz;
+    while (counter < maxRows && counter < numSorted){
+      if (!checkTime()){
+	break;
+      }
+      // initialize minNz to a large value
+      minNz = numz_int + numz_cont;;
+      maxNz = array[counter].cost + array[counter-1].cost;
+      rowMinNz = counter;
+      for (i = counter; i < numSorted && array[i].cost < maxNz; ++i){
+	int ii = array[i].index;
+	// pick the row which introduces the smallest
+	// number of nonzeros on the nonbasic integer columns
+	currentNz = 0;
+	for (j = 0; j < numz_int; ++j){
+	  if ((fabs(intNonBasicTab[ii][z_int[j]]) > param.getEPS_COEFF())){
+	    currentNz++;
+	  }
+	}
+	for (j = 0; j < numz_cont; ++j){
+	  if ((fabs(workNonBasicTab[ii][z_cont[j]]) > param.getEPS_COEFF())){
+	    currentNz++;
+	  }
+	}
+	array[i].cost = currentNz;
+	if (currentNz < minNz){
+	  rowMinNz = i;
+	  minNz = currentNz;
+	}
+	if (currentNz == 0){
+	  // perfect matching, no need to look further
+	  break;
+	}
+      }
+      // update introduced nonzeroes by the selected row;
+      // first, put the row in the correct position in the array
+      int swap1 = array[rowMinNz].index;
+      double swap2 = array[rowMinNz].cost;
+      array[rowMinNz] = array[counter];
+      array[counter].index = swap1;
+      array[counter].cost = swap2;
+      // now count how many nonzeroes were introduces, and update
+      // the vectors z_int and z_cont accordingly
+      for (j = 0; j < numz_int; ++j){
+	if (fabs(intNonBasicTab[swap1][z_int[j]]) > param.getEPS_COEFF()){
+	  z_int[j] = z_int[numz_int-1];
+	  numz_int--;
+	}
+      }
+      for (j = 0; j < numz_cont; ++j){
+	if (fabs(workNonBasicTab[swap1][z_cont[j]]) > param.getEPS_COEFF()){
+	  z_cont[j] = z_cont[numz_cont-1];
+	  numz_cont--;
+	}
+      }
+      counter++;
+    }
+    if (z_int)
+      delete[] z_int;
+    if (z_cont)
+      delete[] z_cont;
+  }
+  return counter;
+}
+
+/***************************************************************************/
+int CglRedSplit2::sort_rows_by_cosine(struct sortElement* array, 
+				      int rowIndex, int maxRows,
+				      int whichTab) const {
+  // whichTab == 0 means only integer nonbasic variables, whichTab ==
+  // 1 means only workTab, whichTab == 2 means both
+  int counter = 0;
+  double initnorm = 0.0;
+  if (whichTab == 0 || whichTab == 2){
+#if RS_FAST_INT == 0
+    initnorm += rs_dotProd(intNonBasicTab[rowIndex], 
+			   intNonBasicTab[rowIndex],
+			   card_intNonBasicVar);
+#elif RS_FAST_INT == 1
+    initnorm += rs_dotProd(intNonBasicTab[rowIndex], 
+			   intNonBasicTab[rowIndex],
+			   card_intNonBasicVar);
+    double value = rs_sparseDotProd(intNonBasicTab[rowIndex],
+				       intNonBasicTab[rowIndex], 
+				       pi_mat[rowIndex]+mTab,
+				       pi_mat[rowIndex]+mTab);
+    assert (value==initnorm);
+#else
+    initnorm = rs_sparseDotProd(intNonBasicTab[rowIndex],
+				       intNonBasicTab[rowIndex], 
+				       pi_mat[rowIndex]+mTab,
+				       pi_mat[rowIndex]+mTab);
+#endif
+  }
+  if (whichTab == 1 || whichTab == 2){
+    initnorm += norm[rowIndex];
+  }
+#if RS_FAST_WORK 
+  int workOffset = mTab+card_intNonBasicVar+card_contNonBasicVar+2;
+#endif
+  for (int i = 0; i < mTab; ++i){
+    if ((i != rowIndex) && (norm[i] > param.getNormIsZero())){
+      if (!checkTime()){
+	break;
+      }
+      array[counter].index = i;
+      array[counter].cost = 0;
+
+      if (whichTab == 0 || whichTab == 2){
+#if RS_FAST_INT == 0
+	array[counter].cost -= fabs(rs_dotProd(intNonBasicTab[rowIndex],
+					       intNonBasicTab[i], 
+					       card_intNonBasicVar));
+#elif RS_FAST == 1
+	array[counter].cost -= fabs(rs_dotProd(intNonBasicTab[rowIndex],
+					       intNonBasicTab[i], 
+					       card_intNonBasicVar));
+	double value = -fabs(rs_sparseDotProd(intNonBasicTab[rowIndex],
+				       intNonBasicTab[i], 
+				       pi_mat[rowIndex]+mTab,
+				       pi_mat[i]+mTab));
+	assert (value==array[counter].cost);
+#else
+	array[counter].cost = -fabs(rs_sparseDotProd(intNonBasicTab[rowIndex],
+						     intNonBasicTab[i], 
+						     pi_mat[rowIndex]+mTab,
+						     pi_mat[i]+mTab));
+#endif
+      }
+      if (whichTab == 1 || whichTab == 2){
+#if RS_FAST_WORK == 0
+	  array[counter].cost -= fabs(rs_dotProd(workNonBasicTab[rowIndex],
+						 workNonBasicTab[i], nTab));
+#elif RS_FAST_WORK == 1
+	  double value = array[counter].cost;
+	  array[counter].cost -= fabs(rs_dotProd(workNonBasicTab[rowIndex],
+						 workNonBasicTab[i], nTab));
+	  value -= fabs(rs_sparseDotProd(workNonBasicTab[rowIndex],
+				       workNonBasicTab[i], 
+				       pi_mat[rowIndex]+workOffset,
+				       pi_mat[i]+workOffset));
+	  assert (value==array[counter].cost);
+#else
+	  array[counter].cost -= fabs(rs_sparseDotProd(workNonBasicTab[rowIndex],
+				       workNonBasicTab[i], 
+				       pi_mat[rowIndex]+workOffset,
+				       pi_mat[i]+workOffset));
+#endif
+      }	
+
+      // Now divide by the two norms
+      double denom = 0.0;
+      if (whichTab == 0 || whichTab == 2){
+#if RS_FAST_INT == 0
+	denom += initnorm*rs_dotProd(intNonBasicTab[i], intNonBasicTab[i],
+				     card_intNonBasicVar);
+#elif RS_FAST == 1
+	denom += initnorm*rs_dotProd(intNonBasicTab[i], intNonBasicTab[i],
+				     card_intNonBasicVar);
+	double value = initnorm*rs_sparseDotProd(intNonBasicTab[i],
+				       intNonBasicTab[i], 
+				       pi_mat[i]+mTab,
+				       pi_mat[i]+mTab);
+	assert (value==denom);
+#else
+	denom = initnorm*rs_sparseDotProd(intNonBasicTab[i],
+					  intNonBasicTab[i], 
+					  pi_mat[i]+mTab,
+					  pi_mat[i]+mTab);
+#endif
+      }
+      if (whichTab == 1 || whichTab == 2){
+	denom += initnorm*norm[i];
+      }
+      array[counter].cost /= sqrt(denom);
+      if (array[counter].cost != 0.0){
+	counter++;
+      }
+    }
+  }
+  if (counter >= maxRows){
+    qsort(array, counter, sizeof(struct sortElement), rs2_compareElements);
+  }
+  return counter;
+}
+
+/***************************************************************************/
+int CglRedSplit2::get_list_rows_reduction(int rowIndex, int maxRowsReduction, 
+					  int* list, const double* norm,
+					  CglRedSplit2Param::RowSelectionStrategy selectionStrategy) const{
+#ifdef RS2_TRACE
+  printf("Obtaining list of rows with column strategy %d\n", selectionStrategy);
+#endif
+  struct sortElement* array = new struct sortElement[mTab];
+  int counter = 0;
+  int i, j;
+  // Look in CglRedSplit2Param for a description of each strategy
+  if (selectionStrategy == CglRedSplit2Param::RS1){
+    counter = sort_rows_by_nonzeroes(array, rowIndex, maxRowsReduction-1, 0);
+  } 
+  else if (selectionStrategy == CglRedSplit2Param::RS2){
+    counter = sort_rows_by_nonzeroes(array, rowIndex, maxRowsReduction-1, 1);
+  } 
+  else if (selectionStrategy == CglRedSplit2Param::RS3){
+    counter = sort_rows_by_nonzeroes(array, rowIndex, maxRowsReduction-1, 2);
+  } 
+  else if (selectionStrategy == CglRedSplit2Param::RS4){
+    // compute the *true* number of nonzeroes that we introduce
+    // on the integer nonbasics
+    counter = sort_rows_by_nonzeroes_greedy(array, rowIndex, maxRowsReduction-1, 0);
+  }
+  else if (selectionStrategy == CglRedSplit2Param::RS5){
+    // compute the *true* number of nonzeroes that we introduce
+    // on the working set (continuous nonbasics)
+    counter = sort_rows_by_nonzeroes_greedy(array, rowIndex, maxRowsReduction-1, 1);
+  }
+  else if (selectionStrategy == CglRedSplit2Param::RS6){
+    // compute the *true* number of nonzeroes that we introduce
+    // on all the nonbasics: intNonBasicVar and workNonBasicVar
+    counter = sort_rows_by_nonzeroes_greedy(array, rowIndex, maxRowsReduction-1, 2);
+  }
+  else if (selectionStrategy == CglRedSplit2Param::RS7){
+    // sort rows by cosine of the angle in the space of the nonbasic integer
+    // and nonbasic continuous (working set) columns, wrt row rowIndex
+    counter = sort_rows_by_cosine(array, rowIndex, maxRowsReduction-1, 2);
+  }
+  else if (selectionStrategy == CglRedSplit2Param::RS8){
+    // sort rows by cosine of the angle in the space of the
+    // nonbasic continuous (working set) columns, wrt row rowIndex
+    counter = sort_rows_by_cosine(array, rowIndex, maxRowsReduction-1, 1);
+  }
+  list[0] = rowIndex;
+  j = 1;
+  for (i = 0; i < counter && j < maxRowsReduction; ++i){
+    list[j] = array[i].index;
+    j++;
+  }
+  delete[] array;
+  return j;
+}
+/***************************************************************************/
+void CglRedSplit2::fill_workNonBasicTab(CglRedSplit2Param::ColumnSelectionStrategy strategy, const int* ignore_list){
+  // Sort continuous non basic variables by reduced cost and choose the
+  // columns we will work with.
+  // We can choose among several strategies; these are described in 
+  // CglRedSplit2Param.hpp.
+  int i, j;
+  if (strategy == CglRedSplit2Param::CS_ALLCONT){
+    // select all continuous nonbasic columns
+    for (i = 0; i < mTab; ++i){
+      memcpy(workNonBasicTab[i], contNonBasicTab[i], 
+	     card_contNonBasicVar*sizeof(double));
+    }
+    nTab = card_contNonBasicVar;
+  }
+  else{
+    // Begin by sorting all continuous nonbasic columns by increasing
+    // reduced cost (except those in the ingore_list)
+    struct sortElement* array = new struct sortElement[card_contNonBasicVar];
+    int pos = 0, iter = 0;
+    for (i = 0; i < card_contNonBasicVar; ++i){
+      if (ignore_list != NULL){
+	iter = 0;
+	while (ignore_list[iter] >= 0 && 
+	       ignore_list[iter] != contNonBasicVar[i]){
+	  iter++;
+	}
+	if (ignore_list[iter] == contNonBasicVar[i]){
+	  continue;
+	}
+      }
+      array[pos].index = i;
+      // We take absolute value of reduced costs because sign could be
+      // positive or negative depending on minimization/maximization,
+      // and which bound the variable is at (upper/lower).
+      if (contNonBasicVar[i] < ncol)
+	array[pos].cost = fabs(reducedCost[contNonBasicVar[i]]);
+      else
+	array[pos].cost = fabs(rowPrice[contNonBasicVar[i]-ncol]);
+      pos++;
+    }
+    qsort(array,pos,sizeof(struct sortElement),rs2_compareElements);
+    nTab = 0;
+    int card_contNonBasicVar = pos;
+    // Now choose the variables. These strategies are described in
+    // CglRedSplit2Param.hpp.  
+    // CS1, CS2 and CS3 are the 3 partitions of C-3P: each one
+    // contains one third of the variables, sorted by reduced costs
+    if (strategy == CglRedSplit2Param::CS1){
+      for (i = 0; i < card_contNonBasicVar/3; ++i){
+	for (j = 0; j < mTab; ++j){
+	  workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	}
+	nTab++;
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS2){
+      for (i = card_contNonBasicVar/3; i < 2*card_contNonBasicVar/3; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	for (j = 0; j < mTab; ++j){
+	  workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	}
+	nTab++;
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS3){
+      for (i = 2*card_contNonBasicVar/3; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	for (j = 0; j < mTab; ++j){
+	  workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	}
+	nTab++;
+      }
+    }
+    // CS4, CS5, CS6, CS7 and CS8 are the 5 partitions of C-5P; each
+    // one contains 1/5 of the variables, sorted by increasing reduced
+    // cost: first set has smallest reduced costs, and so on.
+    else if (strategy == CglRedSplit2Param::CS4){
+      for (i = 0; i < card_contNonBasicVar/5; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	for (j = 0; j < mTab; ++j){
+	  workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	}
+	nTab++;	
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS5){
+      for (i = card_contNonBasicVar/5; i < 2*card_contNonBasicVar/5; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	for (j = 0; j < mTab; ++j){
+	  workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	}
+	nTab++;	
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS6){
+      for (i = 2*card_contNonBasicVar/5; i < 3*card_contNonBasicVar/5; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	for (j = 0; j < mTab; ++j){
+	  workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	}
+	nTab++;	
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS7){
+      for (i = 3*card_contNonBasicVar/5; i < 4*card_contNonBasicVar/5; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	for (j = 0; j < mTab; ++j){
+	  workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	}
+	nTab++;	
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS8){
+      for (i = 4*card_contNonBasicVar/5; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	for (j = 0; j < mTab; ++j){
+	  workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	}
+	nTab++;	
+      }
+    }
+    // CS9 and CS10 are the 2 partitions of I-2P-2/3; this is a
+    // partition with interleaving pattern XX--X- on the 2/3 of the
+    // variables with smallest reduced cost
+    else if (strategy == CglRedSplit2Param::CS9){
+      int pat;
+      for (i = 0; i < 2*card_contNonBasicVar/3; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	pat = i%6;
+	if (pat == 0 || pat == 1 || pat == 4){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS10){
+      int pat;
+      for (i = 0; i < 2*card_contNonBasicVar/3; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	pat = i%6;
+	if (pat == 2 || pat == 3 || pat == 5){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;	
+	}
+      }
+    }
+    // CS11 and CS12 are the 2 partitions of I-2P-4/5; partition with
+    // interleaving pattern X---XXX- on 4/5 of the vars with smallest
+    // reduced cost
+    else if (strategy == CglRedSplit2Param::CS11){
+      int pat;
+      for (i = 0; i < 4*card_contNonBasicVar/5; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	pat = i%8;
+	if (pat == 0 || pat == 4 || pat == 5 || pat == 6){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS12){
+      int pat;
+      for (i = 0; i < 4*card_contNonBasicVar/5; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	pat = i%8;
+	if (pat == 1 || pat == 2 || pat == 3 || pat == 7){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    // CS13, and CS14 are the 2 partitions of I-2P-1/2; interleaving
+    // partition with pattern X--X on 1/2 of the variables
+    else if (strategy == CglRedSplit2Param::CS13){
+      for (i = 0; i < card_contNonBasicVar/2; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	if (i%4 == 0 || i%4 == 3){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;	
+	}
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS14){
+      for (i = 0; i < card_contNonBasicVar/2; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	if (i%4 == 1 || i%4 == 2){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    // CS15, CS16 and CS17 are the 3 partitions of I-3P; interleaving
+    // partition with pattern X-/ on all the variables
+    else if (strategy == CglRedSplit2Param::CS15){
+      for (i = 0; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	if (i%3 == 0){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS16){
+      for (i = 0; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	if (i%3 == 1){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS17){
+      for (i = 0; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	if (i%3 == 2){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    // CS18, CS19, CS20, CS21 are the 4 partitions of I-4P;
+    // interleaving partition with pattern X-X/\\-/ on all the
+    // variables
+    else if (strategy == CglRedSplit2Param::CS18){
+      int pat;
+      for (i = 0; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	pat = i%8;
+	if (pat == 0 || pat == 2){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS19){
+      int pat;
+      for (i = 0; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	pat = i%8;
+	if (pat == 1 || pat == 6){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS20){
+      int pat;
+      for (i = 0; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	pat = i%8;
+	if (pat == 3 || pat == 7){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}
+      }
+    }
+    else if (strategy == CglRedSplit2Param::CS21){
+      int pat;
+      for (i = 0; i < card_contNonBasicVar; ++i){
+	if (!checkTime()){
+	  break;
+	}
+	pat = i%8;
+	if (pat == 4 || pat == 5){
+	  for (j = 0; j < mTab; ++j){
+	    workNonBasicTab[j][nTab] = contNonBasicTab[j][array[i].index];
+	  }
+	  nTab++;
+	}	
+      }
+    }
+    delete[] array;
+  }
+  //  create sparse work stuff
+  for(i=0; i<mTab; i++) {
+#if RS_FAST_WORK == 0
+    norm[i] = rs_dotProd(workNonBasicTab[i], workNonBasicTab[i], nTab);
+#elif RS_FAST_WORK == 1
+    int * info = pi_mat[i];
+    int * workSparse=info+mTab+2+card_intNonBasicVar+card_contNonBasicVar;
+    int n = 0;
+    const double * values = workNonBasicTab[i];
+    double checkNorm=0.0;
+    for (int j=0;j<nTab;j++) {
+      if (values[j]) {
+	workSparse[++n]=j;
+	checkNorm += values[j]*values[j];
+      }
+    }
+    workSparse[0]=n; 
+    norm[i] = rs_dotProd(workNonBasicTab[i], workNonBasicTab[i], nTab);
+    assert (checkNorm==norm[i]);
+#else
+    int * info = pi_mat[i];
+    int * workSparse=info+mTab+2+card_intNonBasicVar+card_contNonBasicVar;
+    int n = 0;
+    const double * values = workNonBasicTab[i];
+    double checkNorm=0.0;
+    for (int j=0;j<nTab;j++) {
+      if (values[j]) {
+	workSparse[++n]=j;
+	checkNorm += values[j]*values[j];
+      }
+    }
+    workSparse[0]=n; 
+    norm[i] = checkNorm;
+#endif
+  }
+}
+/***************************************************************************/
+void CglRedSplit2::reduce_workNonBasicTab(int numRowsReduction, 
+					  CglRedSplit2Param::RowSelectionStrategy rowSelectionStrategy,
+					  int maxIterations) {
+  // Use at most this number of rows
+  int maxRowsReduction = CoinMin(numRowsReduction, mTab);
+  if (maxRowsReduction == 1){
+    return;
+  }
+  int i, j, k, h;
+
+  // Allocate space to store the matrix for the linear system
+#ifdef RS2_USE_LAPACK
+  double* A = new double[maxRowsReduction*maxRowsReduction];
+#else
+  double** A;
+  rs_allocmatDBL(&A, maxRowsReduction, maxRowsReduction);
+#endif
+  // Right hand side
+  double* b = new double[maxRowsReduction];
+  // Data for LU decomposition
+  int* indexlu = new int[maxRowsReduction];
+  double tmpnumlu = 0.0;
+  double* tmpveclu = new double[maxRowsReduction];
+  // List of rows involved in the linear combination
+  int* list = new int[maxRowsReduction];
+  
+  // Number of rows actually used
+  int numUsedRows;
+  
+  bool resolveWithNormalization = false;
+
+  for (k = 0; k < mTab && k < maxIterations; ++k) {
+    if (!checkTime()){
+      break;
+    }
+    if (norm[k] > param.getNormIsZero()) {
+      // Obtain the list of rows that should be used to reduce row k
+      numUsedRows = get_list_rows_reduction(k, maxRowsReduction, list, norm,
+					    rowSelectionStrategy);
+#ifdef RS2_TRACE
+      rs_printvecINT("rows used for reduction", list, numUsedRows);
+#endif
+      if (numUsedRows <= 1){
+	// This means that the list only contains the current row;
+	// Thus, no rows were selected for reduction. Skip.
+	continue;
+      }      
+      // Note: the list must have size maxRowsReduction.
+      // Now prepare the linear system according to the paper
+      for (i = 0; i < numUsedRows; ++i){
+	for (j = 0; j < numUsedRows; ++j){
+#ifdef RS2_USE_LAPACK
+	  A[i*numUsedRows+j] = 0;
+#else
+	  A[i][j] = 0;
+#endif
+	  if (list[i] != k && list[j] != k){
+	    for (h = 0; h < nTab; ++h){
+#ifdef RS2_USE_LAPACK
+	      A[i*numUsedRows+j]+=workNonBasicTab[list[i]][h]*workNonBasicTab[list[j]][h];
+#else
+	      A[i][j]+=workNonBasicTab[list[i]][h]*workNonBasicTab[list[j]][h];
+#endif
+	    }
+	    if (resolveWithNormalization && i == j){
+	      // Penalize the norm of lambda, i.e. the solution
+#ifdef RS2_USE_LAPACK
+	      A[i*numUsedRows+j] += norm[k]*param.getNormalization();
+#else
+	      A[i][j] += norm[k]*param.getNormalization();
+#endif
+	    }
+	  }
+	}
+	if (list[i] == k){
+	  b[i] = 1;
+#ifdef RS2_USE_LAPACK
+	  A[i*numUsedRows+i] = 1;
+#else
+	  A[i][i] = 1;
+#endif
+	}
+	else{
+	  b[i] = 0;
+	  for (h = 0; h < nTab; ++h){
+	    b[i] -= workNonBasicTab[list[i]][h]*workNonBasicTab[k][h];
+	  }
+	}
+      }
+      // Linear system has been written, now solve it
+#ifdef RS2_USE_LAPACK
+      int info = 0;
+      int h = 1;
+      dgesv_(&numUsedRows, &h, A, &numUsedRows, indexlu, 
+	     b, &numUsedRows, &info);
+	
+      if (info)
+	continue;
+#else
+      // LU decomposition
+      if (!ludcmp(A, numUsedRows, indexlu, &tmpnumlu, tmpveclu)){
+	// numerical error: exit
+	continue;
+      }
+      // Backward substitution
+      lubksb(A, numUsedRows, indexlu, b);
+#endif
+      // Check the 1-norm of the solution
+      double sumnorm = 0.0;
+      for (i = 0; i < numUsedRows; ++i){
+	b[i] = rs2round(b[i]);
+	sumnorm += fabs(b[i]);
+	if (sumnorm > param.getMaxSumMultipliers()){
+	  break;
+	}
+      }
+#ifdef RS2_TRACE
+      rs_printvecDBL("multipliers", b, numUsedRows);
+      printf("sumnorm: %f\n", sumnorm);
+#endif
+      if (sumnorm == 1){
+	// The optimal solution has lambda_k = 1 and all the rest is zero;
+	// so we cannot reduce any coefficient, let's skip this
+	continue;
+      }
+      else if (!resolveWithNormalization && 
+	       sumnorm > param.getMaxSumMultipliers()){
+	// The norm of lambda is too large, resolve with normalization
+	// (note that we do not want to do this more than once)
+	resolveWithNormalization = true;
+	k--;
+	continue;
+      }
+      resolveWithNormalization = false;
+      if (sumnorm > param.getMaxSumMultipliers()){
+	// If we got this far, even resolving did not help, so we skip
+	continue;
+      }
+      double deltaNorm = compute_norm_change(norm[k], list, 
+					     numUsedRows, b);
+      if (deltaNorm <= -norm[k]*param.getMinNormReduction()){
+	for (i = 0; i < numUsedRows; ++i){
+	  pi_mat[k][list[i]] = (int)(b[i]);
+	}
+	numRedRows++;
+      }
+    } /* if (norm[k] > param.getNormIsZero()) */
+  } /*for (k = 0; k < mTab; ++k) */
+  delete[] b;
+  delete[] list;
+  delete[] indexlu;
+  delete[] tmpveclu;
+#ifdef RS2_USE_LAPACK
+  delete[] A;
+#else
+  rs_deallocmatDBL(&A, maxRowsReduction);
+#endif
+
+#ifdef RS2_TRACE
+  sum_norms = 0;
+  for(i=0; i<mTab; i++) {
+    sum_norms += norm[i];
+  }
+  printf("CglRedSplit2::reduce_contNonBasicTab():Final sum of norms: %f\n", sum_norms);
+  printf("CglRedSplit2::reduce_contNonBasicTab(): %d rows reduced\n",numRedRows);
+#endif
+
+} /* reduce_workNonBasicTab */
+
+/************************************************************************/
+void CglRedSplit2::generate_row(int index_row, double *row) {
+
+  memset(row, 0, (ncol+nrow)*sizeof(double));
+  // we only deal with nonbasic variables - the cut coefficient will be zero
+  // on the basic ones anyway
+#if RS_FAST_INT == 0 && RS_FAST_CONT == 0 && RS_FAST_WORK == 0
+  int i;
+  int locind, j;
+  for(i=0; i<card_intNonBasicVar; i++) {
+    locind = intNonBasicVar[i];
+    row[locind] = 0;
+    for(j=0; j<mTab; j++) {
+      row[locind] += pi_mat[index_row][j] * intNonBasicTab[j][i];
+    }
+  }
+  for(i=0; i<card_contNonBasicVar; i++) {
+    locind = contNonBasicVar[i];
+    row[locind] = 0;
+    for(j=0; j<mTab; j++) {
+      row[locind] += pi_mat[index_row][j] * contNonBasicTab[j][i];
+    }
+  }
+#elif RS_FAST_INT < 2 || RS_FAST_CONT < 2
+  double * rowTemp = new double[ncol+nrow];
+  memset(rowTemp, 0, (ncol+nrow)*sizeof(double));
+  for(int i=0; i<card_intNonBasicVar; i++) {
+    int locind = intNonBasicVar[i];
+    rowTemp[locind] = 0;
+    for(int j=0; j<mTab; j++) {
+      rowTemp[locind] += pi_mat[index_row][j] * intNonBasicTab[j][i];
+    }
+  }
+  for(int i=0; i<card_contNonBasicVar; i++) {
+    int locind = contNonBasicVar[i];
+    rowTemp[locind] = 0;
+    for(int j=0; j<mTab; j++) {
+      rowTemp[locind] += pi_mat[index_row][j] * contNonBasicTab[j][i];
+    }
+  }
+  const int * pi = pi_mat[index_row];
+#if RS_FAST_CONT 
+  int contOffset = mTab+card_intNonBasicVar+1;
+#endif
+  for(int j=0; j<mTab; j++) {
+    double value = pi[j];
+    if (value) {
+      const double * tableau = intNonBasicTab[j];
+#if RS_FAST_INT < 1
+      for(int i=0; i<card_intNonBasicVar; i++) {
+	int locind = intNonBasicVar[i];
+	row[locind] += value * tableau[i];
+      }
+#else
+      const int * which = pi_mat[j]+mTab;
+      int n = which[0];
+      which++;
+      for (int k=0;k<n;k++) {
+	int i=which[k];
+	int locind = intNonBasicVar[i];
+	row[locind] += value * tableau[i];
+      }
+#endif
+      tableau = contNonBasicTab[j];
+#if RS_FAST_CONT < 1
+      for(int i=0; i<card_contNonBasicVar; i++) {
+	int locind = contNonBasicVar[i];
+	row[locind] += value * tableau[i];
+      }
+#else
+      const int * which2 = pi_mat[j]+contOffset;
+      int n2 = which2[0];
+      which2++;
+      for (int k=0;k<n2;k++) {
+	int i=which2[k];
+	int locind = contNonBasicVar[i];
+	row[locind] += value * tableau[i];
+      }
+#endif
+    }
+  }
+  for (int i=0;i<nrow+ncol;i++) {
+    assert (fabs(row[i]-rowTemp[i])<1.0e-11+1.0e-8*CoinMax(fabs(row[i]),fabs(rowTemp[i])));
+  }
+  delete [] rowTemp;
+#else
+  const int * pi = pi_mat[index_row];
+  int contOffset = mTab+card_intNonBasicVar+1;
+  for(int j=0; j<mTab; j++) {
+    double value = pi[j];
+    if (value) {
+      const double * tableau = intNonBasicTab[j];
+      const int * which = pi_mat[j]+mTab;
+      int n = which[0];
+      which++;
+      for (int k=0;k<n;k++) {
+	int i=which[k];
+	int locind = intNonBasicVar[i];
+	row[locind] += value * tableau[i];
+      }
+      tableau = contNonBasicTab[j];
+      which = pi_mat[j]+contOffset;
+      n = which[0];
+      which++;
+      for (int k=0;k<n;k++) {
+	int i=which[k];
+	int locind = contNonBasicVar[i];
+	row[locind] += value * tableau[i];
+      }
+    }
+  }
+#endif
+} /* generate_row */
+
+/************************************************************************/
+int CglRedSplit2::generate_cgcut(double *row, double *rhs) {
+  
+#ifdef RS2_TRACE
+  rs_printvecDBL("CglRedSplit2::generate_cgcut(): starting row", 
+		 row, ncol+nrow);
+  printf("rhs: %f\n", *rhs);
+#endif
+
+  // Note that basic integer variables with fractional value
+  // other than basic_ind might have a non zero integer coefficient in the 
+  // "real" row. However, these coefficients become zero anyway in the
+  // cut. It is thus assumed that all basic integer variables have a
+  // coefficient of zero in the given row (enforced in generate_row()).
+  //
+  // Other integer variables and basic continuous variables
+  // have a coefficient of zero, as the corresponding row is not selected
+  // for combination.
+
+  double f0 = rs_above_integer(*rhs);
+  double f0compl = 1 - f0;
+
+  // See Wolsey "Integer Programming" (1998), p. 130, fourth line from top
+  // after correcting typo (Proposition 8.8), flipping all signs to get <=.
+
+  if((f0 < param.getAway()) || (f0compl < param.getAway())) {
+    return(0);
+  }
+
+  int i, locind;
+  double f;
+
+  for(i=0; i<card_intNonBasicVar; i++) {
+    locind = intNonBasicVar[i];
+    f = rs_above_integer(row[locind]);
+
+    if(f > f0) {
+      row[locind] = - ((1-f) * f0);
+    }
+    else {
+      row[locind] = -(f*f0compl);
+    }
+  }
+
+  for(i=0; i<card_contNonBasicVar; i++) {
+    locind = contNonBasicVar[i];
+    if(row[locind] < 0) {
+      row[locind] *= f0;
+    }
+    else {
+      row[locind] = -(row[locind]*f0compl);
+    }
+  }
+  (*rhs) = -f0*f0compl;
+  
+#ifdef RS2_TRACE
+  rs_printvecDBL("CglRedSplit2::generate_cgcut(): row", row, ncol+nrow);
+  printf("rhs: %f\n", *rhs);
+#endif
+
+  return(1);
+} /* generate_cgcut */
+
+/************************************************************************/
+void CglRedSplit2::eliminate_slacks(double *row, 
+				   const double *elements, 
+				   const int *rowStart,
+				   const int *indices,
+				   const int *rowLength,
+				   const double *rhs, double *tabrowrhs) {
+
+  int i, j;
+  for(i=0; i<nrow; i++) {
+    if(fabs(row[ncol+i]) > param.getEPS_ELIM()) {
+
+      int upto = rowStart[i] + rowLength[i];
+      for(j=rowStart[i]; j<upto; j++) {
+	row[indices[j]] -= row[ncol+i] * elements[j];      
+      }
+      *tabrowrhs -= row[ncol+i] * rhs[i];
+    }
+  }
+
+} /* eliminate_slacks */
+
+/************************************************************************/
+void CglRedSplit2::flip(double *row) {
+  
+  int i;
+  for(i=0; i<card_nonBasicAtUpper; i++) {
+    row[nonBasicAtUpper[i]] = -row[nonBasicAtUpper[i]];
+  }
+} /* flip */
+
+/************************************************************************/
+void CglRedSplit2::unflip(double *row, double *tabrowrhs) {
+  
+  int i;
+  for(i=0; i<card_nonBasicAtLower; i++) {
+    int locind = nonBasicAtLower[i];
+    if(locind < ncol) {
+      *tabrowrhs += row[locind] * colLower[locind];
+    }
+  }
+  for(i=0; i<card_nonBasicAtUpper; i++) {
+    int locind = nonBasicAtUpper[i];
+    row[locind] = -row[locind];
+    if(locind < ncol) {
+      *tabrowrhs += row[locind] * colUpper[locind];
+    }
+  }
+
+} /* unflip */
+
+/************************************************************************/
+int CglRedSplit2::check_dynamism(double *row) {
+
+  int i, nelem = 0;
+  double val, max_val = 0, min_val = param.getINFINIT();
+
+  for(i=0; i<ncol; i++) {
+    val = fabs(row[i]);
+    max_val = CoinMax(max_val, val);
+    if(val > param.getEPS_COEFF()) {
+      min_val = CoinMin(min_val, val);
+      nelem++;
+    }
+  }
+
+  if((max_val < param.getMAXDYN() * min_val) && 
+     (max_val >= min_val)) {
+    return 1;
+  }
+
+#ifdef RS2_TRACE
+  printf("CglRedSplit2::check_dynamism(): max_val: %6.6f   min_val: %6.6f   dynamism: %g\n",
+	 max_val, min_val, max_val/min_val);
+#endif
+
+  return 0;
+} /* row_scale_factor */
+
+/************************************************************************/
+int CglRedSplit2::generate_packed_row(const double *lclXlp,
+				      double *row,
+				      int *rowind, double *rowelem, 
+				      int *card_row, double & rhs) {
+  int i;
+  double value;
+  int max_support = param.getMAX_SUPP_ABS() + 
+    (static_cast<int>(ncol*param.getMAX_SUPP_REL()));
+
+  if(!check_dynamism(row)) {
+#ifdef RS2_TRACE
+    printf("CglRedSplit2::generate_packed_row(): Cut discarded (bad dynamism)\n");
+#endif	
+    return(0);
+  }
+
+  *card_row = 0;
+  
+  for(i=0; i<ncol; i++) {
+    value = row[i];
+    if(fabs(value) > param.getEPS_COEFF()) {
+      rowind[*card_row] = i;
+      rowelem[*card_row] = value;
+      (*card_row)++;
+      if(*card_row > max_support) {
+#ifdef RS2_TRACE
+	printf("CglRedSplit2::generate_packed_row(): Cut discarded (too many non zero)\n");
+#endif	
+	return(0);
+      }
+    } else {
+      if (value > 0.0) {
+        rhs -= value * colLower[i];
+      } 
+      else {
+        rhs -= value * colUpper[i];      
+      } 
+    }
+  }
+  value = 0;
+  for(i=0; i<(*card_row); i++) {
+    value += lclXlp[rowind[i]] * rowelem[i];
+  }
+
+  if(value > rhs) {
+    value = value-rhs;
+    if(value < param.getMINVIOL()) {
+
+#ifdef RS2_TRACE
+      printf("CglRedSplit2::generate_packed_row(): Cut discarded: violation: %12.10f\n", value);
+#endif	
+      
+      return(0);
+    }
+  }
+  
+  return(1);
+} /* generate_packed_row */
+
+/************************************************************************/
+bool CglRedSplit2::rs_are_different_vectors(const int *vect1, 
+					    const int *vect2,
+					    const int dim) {
+  int i;
+  for(i=0; i<dim; i++) {
+    if(vect1[i] != vect2[i]) {
+      return(1);
+    }    
+  }
+  return(0);
+} /* rs_are_different_vectors */
+
+/************************************************************************/
+void CglRedSplit2::generateCuts(const OsiSolverInterface &si, OsiCuts & cs,
+				const CglTreeInfo info)
+{
+  solver = const_cast<OsiSolverInterface *>(&si);
+  if(solver == NULL) {
+    printf("### WARNING: CglRedSplit2::generateCuts(): no solver available.\n");
+    return;    
+  }  
+
+  if(!solver->optimalBasisIsAvailable()) {
+    printf("### WARNING: CglRedSplit2::generateCuts(): no optimal basis available.\n");
+    return;
+  }
+
+  // Reset some members of CglRedSplit2
+  card_intBasicVar = 0;
+  card_intBasicVar_frac = 0;
+  card_intNonBasicVar = 0;
+  card_contNonBasicVar = 0;
+  card_nonBasicAtUpper = 0;
+  card_nonBasicAtLower = 0;
+  numRedRows = 0;
+  startTime = CoinCpuTime();
+
+  // Get basic problem information from solver
+  ncol = solver->getNumCols(); 
+  nrow = solver->getNumRows(); 
+  colLower = solver->getColLower();
+  colUpper = solver->getColUpper();
+  rowLower = solver->getRowLower();
+  rowUpper = solver->getRowUpper();
+  rowRhs = solver->getRightHandSide();
+  reducedCost = solver->getReducedCost();
+  rowPrice = solver->getRowPrice();
+  objective = solver->getObjCoefficients();
+
+  xlp = solver->getColSolution();
+  rowActivity = solver->getRowActivity();
+  byRow = solver->getMatrixByRow();
+
+  solver->enableFactorization();
+  generateCuts(&cs, param.getMaxNumCuts());
+  solver->disableFactorization();
+} /* generateCuts */
+
+/************************************************************************/
+int CglRedSplit2::generateCuts(OsiCuts* cs, int maxNumCuts, int* lambda)
+{
+  int i;
+  is_integer = new int[ncol]; 
+  
+  compute_is_integer();
+
+  int *cstat = new int[ncol];
+  int *rstat = new int[nrow];
+
+
+  solver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
+                                          // 2: upper 3: lower
+
+  int *basis_index = new int[nrow]; // basis_index[i] = 
+                                    //        index of pivot var in row i
+                                    //        (slack if number >= ncol) 
+
+#ifdef RS2_TRACETAB
+  rs_printvecINT("cstat", cstat, ncol);
+  rs_printvecINT("rstat", rstat, nrow);
+#endif
+  solver->getBasics(basis_index);
+
+  cv_intBasicVar = new int[ncol];  
+  cv_intBasicVar_frac = new int[ncol];  
+  intBasicVar = new int[ncol];                                 
+  intNonBasicVar = new int[ncol];       
+  contNonBasicVar = new int[ncol+nrow]; 
+  nonBasicAtUpper = new int[ncol+nrow]; 
+  nonBasicAtLower = new int[ncol+nrow]; 
+  double dist_int;
+
+  for(i=0; i<ncol; i++) {
+    cv_intBasicVar[i] = 0;
+    cv_intBasicVar_frac[i] = 0;
+
+    switch(cstat[i]) {
+    case 1: // basic variable
+      
+      dist_int = rs_above_integer(xlp[i]);
+      if(is_integer[i]){
+	if ((dist_int > param.getAway()) && (dist_int < 1 - param.getAway())) {
+	  cv_intBasicVar_frac[i] = 1;
+	  card_intBasicVar_frac++;
+
+	  // intBasicVar_frac computed below, 
+	  // as order must be according to selected rows
+	}
+	card_intBasicVar++;
+	cv_intBasicVar[i] = 1;
+
+      }
+      break;
+
+    case 2: // Non basic at upper bound: must be flipped and shifted
+            // so that it becomes non negative with lower bound 0 
+            // It is assumed that bounds for integer variables have been
+            // tightend so that non basic integer structural variables 
+            // have integer values
+
+      nonBasicAtUpper[card_nonBasicAtUpper] = i;
+      card_nonBasicAtUpper++;
+
+      if(is_integer[i]) {
+	intNonBasicVar[card_intNonBasicVar] = i;
+	card_intNonBasicVar++;
+      }
+      else {
+	contNonBasicVar[card_contNonBasicVar] = i;
+	card_contNonBasicVar++;
+      }
+      break;
+
+    case 3 : // non basic at lower bound: must be shifted so that it becomes
+             // non negative with lower bound 0
+      // It is assumed that bounds for integer variables have been
+      // tightend so that they are integer
+
+      nonBasicAtLower[card_nonBasicAtLower] = i;
+      card_nonBasicAtLower++;
+
+      if(is_integer[i]) {
+	intNonBasicVar[card_intNonBasicVar] = i;
+	card_intNonBasicVar++;
+      }
+      else {
+	contNonBasicVar[card_contNonBasicVar] = i;
+	card_contNonBasicVar++;
+      }
+      break;
+
+    default: // free variable ? Don't know how to handle 
+      printf("### ERROR: CglRedSplit2::generateCuts(): cstat[%d]: %d\n",
+	     i, cstat[i]);
+      exit(1);
+      break;
+    } 
+  }
+
+  // Use this instead of rowRhs to allow for ranges
+  double *effective_rhs = new double[nrow];
+
+  for(i=0; i<nrow; i++) {
+    // effective rhs
+    effective_rhs[i] = rowRhs[i];
+    switch(rstat[i]) {
+    case 1: // basic slack
+      break;
+
+    case 2: // non basic slack at upper; flipped and shifted
+      effective_rhs[i] = rowLower[i];
+      nonBasicAtUpper[card_nonBasicAtUpper] = ncol+i;
+      card_nonBasicAtUpper++;
+
+      contNonBasicVar[card_contNonBasicVar] = ncol+i;
+      card_contNonBasicVar++;
+      break;
+
+    case 3: // non basic slack at lower; shifted
+      effective_rhs[i] = rowUpper[i];
+      nonBasicAtLower[card_nonBasicAtLower] = ncol+i;
+      card_nonBasicAtLower++;
+
+      contNonBasicVar[card_contNonBasicVar] = ncol+i;
+      card_contNonBasicVar++;
+      break;
+
+    default: 
+      printf("### ERROR: CglRedSlpit::generateCuts(): rstat[%d]: %d\n",
+	     i, rstat[i]);
+      exit(1);
+      break;
+    }
+    assert (fabs(effective_rhs[i])<1.0e100);
+  }
+
+#ifdef RS2_TRACE
+  printf("CglRedSplit2()::card_intBasicVar_frac %d %d\n", 
+	 card_intBasicVar_frac, card_contNonBasicVar);
+#endif
+  if((card_contNonBasicVar == 0) || (card_intBasicVar_frac == 0)) {
+    delete[] cstat;
+    delete[] rstat;
+    delete[] basis_index;
+
+    delete[] cv_intBasicVar;  
+    delete[] cv_intBasicVar_frac;  
+    delete[] intBasicVar;
+    delete[] intNonBasicVar;
+    delete[] contNonBasicVar;
+    delete[] nonBasicAtUpper;
+    delete[] nonBasicAtLower;
+    delete[] is_integer;
+    delete[] effective_rhs;
+
+    return 0; // no cuts can be generated
+  }
+
+  double *z = new double[ncol];  // workspace to get row of the tableau
+  double *slack = new double[nrow];  // workspace to get row of the tableau
+
+#ifdef RS2_TRACETAB
+  printOptTab(solver);
+#endif
+
+  mTab = card_intBasicVar;
+  nTab = card_contNonBasicVar;
+
+  rhsTab = new double[mTab];
+  cv_fracRowsTab = new int[mTab];
+  memset(cv_fracRowsTab, 0, mTab*sizeof(int));
+  int card_rowTab = 0;
+
+  rs_allocmatDBL(&contNonBasicTab, mTab, card_contNonBasicVar);
+  rs_allocmatDBL(&workNonBasicTab, mTab, card_contNonBasicVar);
+  rs_allocmatDBL(&intNonBasicTab, mTab, card_intNonBasicVar);
+  norm = new double[mTab];
+
+  intBasicVar_frac = new int[ncol];                                 
+
+  // position of each integer basic variable in the simplex tableau
+  int* origRow = new int[nrow];
+
+  card_intBasicVar = 0; // recompute in pivot order
+  card_intBasicVar_frac = 0;
+
+  for(i=0; i<nrow; i++) {
+
+    int ind_row = i;
+
+    if(basis_index[ind_row] >= ncol || 
+       cv_intBasicVar[basis_index[ind_row]] != 1) {
+      // If basic variable is not an integer variable, skip
+      continue;
+    } 
+
+    origRow[card_intBasicVar] = ind_row;
+
+    // row used in generation
+    intBasicVar[card_intBasicVar] = basis_index[ind_row];
+    if (cv_intBasicVar_frac[basis_index[ind_row]] == 1){
+      // row is fractional
+      intBasicVar_frac[card_intBasicVar_frac] = basis_index[ind_row];
+      cv_fracRowsTab[card_intBasicVar] = 1;
+    }
+    // obtain row of simplex tableau
+    solver->getBInvARow(ind_row, z, slack);
+
+    rhsTab[card_rowTab] = xlp[basis_index[ind_row]];
+
+    int nonzeroes = 0;
+    int ii;
+
+    for(ii=0; ii<card_contNonBasicVar; ii++) {
+      int locind = contNonBasicVar[ii];
+      if(locind < ncol) {
+	contNonBasicTab[card_rowTab][ii] = z[locind];
+      }
+      else {
+	contNonBasicTab[card_rowTab][ii] = slack[locind - ncol];
+      }
+      if(fabs(contNonBasicTab[card_rowTab][ii]) > TINY)
+	nonzeroes++;
+    }
+
+    for(ii=0; ii<card_intNonBasicVar; ii++) {
+      int locind = intNonBasicVar[ii];
+      if(locind < ncol) {
+	intNonBasicTab[card_rowTab][ii] = z[locind];
+      }
+      else {
+	printf("### ERROR: CglRedSplit2::generateCuts(): integer slack unexpected\n");
+	exit(1);
+      }
+      if(fabs(intNonBasicTab[card_rowTab][ii]) > TINY)
+	nonzeroes++;
+    }
+
+#if RS_FAST_INT > 0 || RS_FAST_CONT > 0 || RS_FAST_WORK > 0
+    if(nonzeroes < param.getMaxNonzeroesTab()) {
+#endif
+      // The number of nonzeroes is small enough, we keep the row
+      card_rowTab++;
+      card_intBasicVar++;
+      if (cv_intBasicVar_frac[basis_index[ind_row]] == 1)
+	card_intBasicVar_frac++;
+#if RS_FAST_INT > 0 || RS_FAST_CONT > 0 || RS_FAST_WORK > 0
+    }
+#endif
+  }
+#if RS_FAST_INT == 0 && RS_FAST_CONT == 0 && RS_FAST_WORK == 0
+  rs_allocmatINT(&pi_mat, mTab, mTab);
+#else
+  // Allow for sparse info (and for work)
+  rs_allocmatINT(&pi_mat, mTab, mTab+
+		 card_intNonBasicVar+2*card_contNonBasicVar+3);
+  for (int i=0;i<mTab;i++) {
+    int * info = pi_mat[i];
+    int * intSparse=info+mTab;
+    int * contSparse=intSparse+1+card_intNonBasicVar;
+    int n;
+    const double * values;
+    n=0;
+    values=intNonBasicTab[i];
+    for (int j=0;j<card_intNonBasicVar;j++) {
+      if (fabs(values[j]) > TINY)
+	intSparse[++n]=j;
+    }
+    intSparse[0]=n; 
+    n=0;
+    values=contNonBasicTab[i];
+    for (int j=0;j<card_contNonBasicVar;j++) {
+      if (fabs(values[j]))
+	contSparse[++n]=j;
+    }
+    contSparse[0]=n; 
+  }
+#endif
+
+#ifdef RS2_TRACE
+  printf("intBasicVar:\n");
+  for(i=0; i<card_intBasicVar; i++) {
+    printf("%d ", intBasicVar[i]);
+  }
+  printf("\n");
+  printf("intBasicVar_frac:\n");
+  for(i=0; i<card_intBasicVar_frac; i++) {
+    printf("%d ", intBasicVar_frac[i]);
+  }
+  printf("\n");
+  printf("intNonBasicVar:\n");
+  for(i=0; i<card_intNonBasicVar; i++) {
+    printf("%d ", intNonBasicVar[i]);
+  }
+  printf("\n");
+  printf("contNonBasicVar:\n");
+  for(i=0; i<card_contNonBasicVar; i++) {
+    printf("%d ", contNonBasicVar[i]);
+  }
+  printf("\n");
+#endif
+
+  int card_row;
+  double *row = new double[ncol+nrow];
+  int *rowind = new int[ncol];
+  double *rowelem = new double[ncol];
+
+  const double *elements = byRow->getElements();
+  const int *rowStart = byRow->getVectorStarts();
+  const int *indices = byRow->getIndices();
+  const int *rowLength = byRow->getVectorLengths(); 
+
+  CglRedSplit2Param::ColumnSelectionStrategy columnSelection;
+  CglRedSplit2Param::RowSelectionStrategy rowSelection;
+  int numRows;
+
+  int maxNumComputedCuts = param.getMaxNumComputedCuts();
+
+  int* bufflambda = lambda;
+  OsiCuts* buffcs = cs;
+  // quality of cuts
+  struct sortElement* quality = NULL; 
+  if (maxNumCuts < maxNumComputedCuts){
+    // user wants the generator to generate several cuts and select only best
+    if (lambda != NULL){
+      bufflambda = new int[maxNumComputedCuts*nrow];
+    }
+    if (cs != NULL){
+      buffcs = new OsiCuts();
+    }
+    quality = new struct sortElement[maxNumComputedCuts];
+  }
+
+  int initNumCuts = 0;
+  if (buffcs != NULL){
+    initNumCuts = buffcs->sizeRowCuts();
+  }
+
+  // reset vector of lambdas
+  if (bufflambda != NULL){
+    if (maxNumCuts < maxNumComputedCuts){
+      memset(bufflambda, 0, maxNumComputedCuts*nrow*sizeof(int));
+    }
+    else{
+      memset(bufflambda, 0, maxNumCuts*nrow*sizeof(int));
+    }
+  }
+
+
+  int numCuts = 0;
+
+  std::vector<CglRedSplit2Param::ColumnSelectionStrategy> listColSel = 
+    param.getColumnSelectionStrategy();
+  std::vector<CglRedSplit2Param::RowSelectionStrategy> listRowSel = 
+    param.getRowSelectionStrategy();
+  std::vector<int> listNumRows = param.getNumRowsReduction();
+#if 0
+  double work= listColSel.size()*listNumRows.size()*listRowSel.size()*nDiag;
+  work *= mTab*(card_intNonBasicVar+card_contNonBasicVar);
+  printf("listColSel %d listNumRows %d listRowSel %d mTab %d intNon %d contnon %d  - %d generate_rows and dense ops %g\n",
+	 listColSel.size(),listNumRows.size(),listRowSel.size(),mTab,
+	 card_intNonBasicVar,card_contNonBasicVar,
+	 listColSel.size()*listNumRows.size()*listRowSel.size()*nDiag,work);
+#endif
+  for (unsigned int coliter = 0; coliter < listColSel.size(); ++coliter){
+    if (!checkTime() || numCuts >= maxNumComputedCuts){
+      break;
+    }
+    columnSelection = listColSel[coliter];
+#ifdef RS2_TRACE
+    printf("Filling workNonBasicTab with column strategy %d\n", columnSelection);
+#endif
+    // select the columns
+    fill_workNonBasicTab(columnSelection);
+    for (unsigned int nriter = 0; nriter < listNumRows.size(); ++nriter){
+      if (!checkTime() || numCuts >= maxNumComputedCuts){
+	break;
+      }
+      numRows = listNumRows[nriter];
+#ifdef RS2_TRACE
+      printf("Applying reduction algorithm with %d rows\n", numRows);
+#endif
+      for (unsigned int rowiter = 0; rowiter < listRowSel.size(); ++rowiter){
+	if (!checkTime() || numCuts >= maxNumComputedCuts){
+	  break;
+	}
+	rowSelection = listRowSel[rowiter];
+#ifdef RS2_TRACE
+	printf("Reducing norms with row strategy %d\n", rowSelection);
+#endif
+	// new iteration: reinitialize pi_mat
+	for(i=0; i<mTab; i++) {
+	  memset(pi_mat[i], 0, mTab*sizeof(int));
+	  if (param.getSkipGomory() == false){
+	    pi_mat[i][i] = 1;
+	  }
+	}
+	reduce_workNonBasicTab(numRows, rowSelection, mTab);
+	// now generate cuts
+	for(i=0; i<mTab && numCuts < maxNumComputedCuts; i++) {
+	  if (pi_mat[i][i] != 0){
+	    card_row = 0;
+	    generate_row(i, row);
+	    flip(row);
+
+	    // RHS of equalities after flipping/translating non basic variables
+	    // is given by the current LP solution (re-ordered according to 
+	    // basis_index), i.e. what is now in rhsTab. 
+	    // RHS of row i of (pi_mat * contNonBasicTab) is then simply 
+	    // pi_mat[i] * rhsTab
+
+	    double tabrowrhs = rs_dotProd(pi_mat[i], rhsTab, mTab); 
+	    int got_one = 0;
+    
+	    got_one = generate_cgcut(row, &tabrowrhs);
+
+	    if (!got_one && param.getSkipGomory() == false){
+	      // Cut improvement failed and we want to generate Gomory
+	      // cuts from single rows; so, revert back to one row and try
+	      // the corresponding Gomory cut. If we still fail, we give up
+	      memset(pi_mat[i], 0, mTab*sizeof(int));
+	      pi_mat[i][i] = 1;
+	      card_row = 0;
+	      generate_row(i, row);
+	      flip(row);
+	      tabrowrhs = rhsTab[i];
+	      got_one = generate_cgcut(row, &tabrowrhs);
+	    }
+
+
+	    if (got_one){
+	      bool skip = false;
+	      if (bufflambda != NULL){
+		for (int k = 0; k < mTab; ++k){
+		  bufflambda[numCuts*nrow + origRow[k]] = pi_mat[i][k];
+		}
+		for (int k = 0; k < numCuts; ++k){
+		  if (!rs_are_different_vectors(bufflambda + k*nrow, 
+						bufflambda + numCuts*nrow, 
+						nrow)){
+		    // Cut was previously generated; skip
+		    skip = true;
+		  }
+		}
+	      }
+	      if (!skip){
+		// new multipliers found, check if the generated cut is good
+		unflip(row, &tabrowrhs);
+
+		eliminate_slacks(row, elements, rowStart, indices, 
+				 rowLength, effective_rhs, &tabrowrhs);
+
+		if(generate_packed_row(xlp, row, rowind, rowelem, &card_row, 
+				       tabrowrhs)) {
+		  // the cut is good, multipliers should be saved.
+		  // record quality of cut if needed
+		  if (quality){
+		    quality[numCuts].index = numCuts;
+		    quality[numCuts].cost = tabrowrhs;
+		    double rnorm = 0.0;
+		    for (int ii = 0; ii < card_row; ++ii){
+		      rnorm += rowelem[ii]*rowelem[ii];
+		      quality[numCuts].cost -= rowelem[ii]*xlp[rowind[ii]];
+		    }
+		    quality[numCuts].cost /= rnorm;
+		  }
+		  // now, add cut to the collection if needed
+		  if (cs != NULL){
+		    OsiRowCut rc;
+		    rc.setRow(card_row, rowind, rowelem);
+		    rc.setLb(-param.getINFINIT());
+		    double adjust = param.getEPS_RELAX_ABS();
+		    if(param.getEPS_RELAX_REL() > 0.0) {
+		      adjust += fabs(tabrowrhs) * param.getEPS_RELAX_REL();
+		    }
+		    rc.setUb(tabrowrhs + adjust);   
+		    // relax the constraint slightly
+		    buffcs->insertIfNotDuplicate(rc, CoinAbsFltEq(param.getEPS()));
+		    numCuts = buffcs->sizeRowCuts() - initNumCuts;
+		  }
+		  else{
+		    numCuts++;
+		  }
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  if (maxNumCuts < maxNumComputedCuts){
+    // select best cuts and copy them back
+    if (numCuts > maxNumCuts){
+      qsort(quality, numCuts, sizeof(struct sortElement), rs2_compareElements);
+    }
+    // also delete temp data
+    if (buffcs){
+      for (int i = 0; i < numCuts && i < maxNumCuts; ++i){
+	cs->insertIfNotDuplicate(buffcs->rowCut(quality[i].index),
+				 CoinAbsFltEq(param.getEPS_COEFF()));
+      }
+      delete buffcs;
+    }
+    if (bufflambda){
+      for (int i = 0; i < numCuts && i < maxNumCuts; ++i){
+	memcpy(lambda + (i*nrow), bufflambda + (quality[i].index*nrow), 
+	       sizeof(int)*nrow);
+      }
+      delete[] bufflambda;
+    }
+    if (numCuts > maxNumCuts){
+      numCuts = maxNumCuts;
+    }
+  }
+
+  delete[] cstat;
+  delete[] rstat;
+  delete[] basis_index;
+  delete[] slack;
+  delete[] z;
+  delete[] effective_rhs;
+  delete[] row;
+  delete[] rowind;
+  delete[] rowelem;
+
+  delete[] origRow;
+  delete[] cv_intBasicVar;  
+  delete[] cv_intBasicVar_frac;  
+  delete[] cv_fracRowsTab;  
+  delete[] intBasicVar;
+  delete[] intBasicVar_frac;
+  delete[] intNonBasicVar;
+  delete[] contNonBasicVar;
+  delete[] nonBasicAtUpper;
+  delete[] nonBasicAtLower;
+  delete[] is_integer;
+  rs_deallocmatDBL(&contNonBasicTab, mTab);
+  rs_deallocmatDBL(&workNonBasicTab, mTab);
+  rs_deallocmatDBL(&intNonBasicTab, mTab);
+  rs_deallocmatINT(&pi_mat, mTab);
+  delete[] rhsTab;
+  delete[] norm;
+
+  return numCuts;
+} /* generateCuts */
+
+/***********************************************************************/
+void CglRedSplit2::setParam(const CglRedSplit2Param &source) {
+  param = source;
+} /* setParam */
+
+/***********************************************************************/
+void CglRedSplit2::compute_is_integer() {
+
+  int i;
+
+  for(i=0; i<ncol; i++) {
+    if(solver->isInteger(i)) {
+      is_integer[i] = 1;
+    }
+    else {
+      if((colUpper[i] - colLower[i] < param.getEPS()) && 
+      	 (rs_above_integer(colUpper[i]) < param.getEPS())) {	
+      	// continuous variable fixed to an integer value
+      	is_integer[i] = 1;
+      }
+      else {
+	is_integer[i] = 0;
+      }
+    }
+  }    
+} /* compute_is_integer */
+
+/***********************************************************************/
+void CglRedSplit2::print() const
+{
+  rs_printvecINT("intBasicVar_frac", intBasicVar_frac, card_intBasicVar_frac);
+  rs_printmatINT("pi_mat", pi_mat, card_intBasicVar_frac, 
+		 card_intBasicVar_frac);
+  rs_printvecINT("intNonBasicVar", intNonBasicVar, card_intNonBasicVar);
+  rs_printmatDBL("intNonBasicTab", intNonBasicTab, card_intBasicVar_frac, 
+		 card_intNonBasicVar);
+  rs_printvecINT("contNonBasicVar", contNonBasicVar, card_contNonBasicVar);
+  rs_printmatDBL("contNonBasicTab", contNonBasicTab, card_intBasicVar_frac, 
+		 card_contNonBasicVar);
+  rs_printvecINT("nonBasicAtLower", nonBasicAtLower, card_nonBasicAtLower);
+  rs_printvecINT("nonBasicAtUpper", nonBasicAtUpper, card_nonBasicAtUpper);
+
+} /* print */
+
+/***********************************************************************/
+void CglRedSplit2::printOptTab(OsiSolverInterface *lclSolver) const
+{
+  int i;
+  int *cstat = new int[ncol];
+  int *rstat = new int[nrow];
+
+  lclSolver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
+  // 2: upper 3: lower
+
+  int *basis_index = new int[nrow]; // basis_index[i] = 
+                                    //        index of pivot var in row i
+                                    //        (slack if number >= ncol) 
+  lclSolver->getBasics(basis_index);
+
+  double *z = new double[ncol];  // workspace to get row of the tableau
+  double *slack = new double[nrow];  // workspace to get row of the tableau
+  double *slack_val = new double[nrow];
+
+  for(i=0; i<nrow; i++) {
+    slack_val[i] = rowRhs[i] - rowActivity[i];
+  }
+
+  const double *rc = lclSolver->getReducedCost();
+  const double *dual = lclSolver->getRowPrice();
+  const double *solution = lclSolver->getColSolution();
+
+  rs_printvecINT("cstat", cstat, ncol);
+  rs_printvecINT("rstat", rstat, nrow);
+  rs_printvecINT("basis_index", basis_index, nrow);
+
+  rs_printvecDBL("solution", solution, ncol);
+  rs_printvecDBL("slack_val", slack_val, nrow);
+  rs_printvecDBL("reduced_costs", rc, ncol);
+  rs_printvecDBL("dual solution", dual, nrow);
+
+  printf("Optimal Tableau:\n");
+
+  for(i=0; i<nrow; i++) {
+    lclSolver->getBInvARow(i, z, slack);
+    int ii;
+    for(ii=0; ii<ncol; ii++) {
+      printf("%5.2f ", z[ii]);
+    }
+    printf(" | ");
+    for(ii=0; ii<nrow; ii++) {
+      printf("%5.2f ", slack[ii]);
+    }
+    printf(" | ");
+    if(basis_index[i] < ncol) {
+      printf("%5.2f ", solution[basis_index[i]]);
+    }
+    else {
+      printf("%5.2f ", slack_val[basis_index[i]-ncol]);
+    }
+    printf("\n");
+  }
+  int ii;
+  for(ii=0; ii<7*(ncol+nrow+1); ii++) {
+    printf("-");
+  }
+  printf("\n");
+
+  for(ii=0; ii<ncol; ii++) {
+    printf("%5.2f ", rc[ii]);    
+  }
+  printf(" | ");
+  for(ii=0; ii<nrow; ii++) {
+    printf("%5.2f ", -dual[ii]);
+  }
+  printf(" | ");
+  printf("%5.2f\n", -lclSolver->getObjValue());
+
+  delete[] cstat;
+  delete[] rstat;
+  delete[] basis_index;
+  delete[] slack;
+  delete[] z;
+  delete[] slack_val;
+} /* printOptTab */
+
+/*********************************************************************/
+CglRedSplit2::CglRedSplit2() :
+  CglCutGenerator(),
+  nrow(0),
+  ncol(0),
+  card_intBasicVar(0),
+  card_intBasicVar_frac(0),
+  card_intNonBasicVar(0),
+  card_contNonBasicVar(0),
+  card_nonBasicAtUpper(0),
+  card_nonBasicAtLower(0),
+  cv_intBasicVar(0),
+  cv_intBasicVar_frac(0),
+  cv_fracRowsTab(0),
+  intBasicVar(0),
+  intBasicVar_frac(0),
+  intNonBasicVar(0), 
+  contNonBasicVar(0),
+  nonBasicAtUpper(0),
+  nonBasicAtLower(0),
+  mTab(0),
+  nTab(0),
+  pi_mat(0),
+  contNonBasicTab(0),
+  intNonBasicTab(0),
+  rhsTab(0)
+{
+}
+
+/*********************************************************************/
+CglRedSplit2::CglRedSplit2(const CglRedSplit2Param &RS_param) :
+  CglCutGenerator(),
+  nrow(0),
+  ncol(0),
+  card_intBasicVar(0),
+  card_intBasicVar_frac(0),
+  card_intNonBasicVar(0),
+  card_contNonBasicVar(0),
+  card_nonBasicAtUpper(0),
+  card_nonBasicAtLower(0),
+  cv_intBasicVar(0),
+  cv_intBasicVar_frac(0),
+  cv_fracRowsTab(0),
+  intBasicVar(0),
+  intBasicVar_frac(0),
+  intNonBasicVar(0), 
+  contNonBasicVar(0),
+  nonBasicAtUpper(0),
+  nonBasicAtLower(0),
+  mTab(0),
+  nTab(0),
+  pi_mat(0),
+  contNonBasicTab(0),
+  intNonBasicTab(0),
+  rhsTab(0)
+{
+  param = RS_param;
+}
+ 
+/*********************************************************************/
+CglRedSplit2::CglRedSplit2 (const CglRedSplit2 & source) :
+  CglCutGenerator(source),
+  param(source.param),
+  nrow(0),
+  ncol(0),
+  card_intBasicVar(0),
+  card_intBasicVar_frac(0),
+  card_intNonBasicVar(0),
+  card_contNonBasicVar(0),
+  card_nonBasicAtUpper(0),
+  card_nonBasicAtLower(0),
+  cv_intBasicVar(NULL),
+  cv_intBasicVar_frac(NULL),
+  cv_fracRowsTab(NULL),
+  intBasicVar(NULL),
+  intBasicVar_frac(NULL),
+  intNonBasicVar(NULL), 
+  contNonBasicVar(NULL),
+  nonBasicAtUpper(NULL),
+  nonBasicAtLower(NULL),
+  mTab(0),
+  nTab(0),
+  pi_mat(NULL),
+  contNonBasicTab(NULL),
+  intNonBasicTab(NULL),
+  rhsTab(NULL)
+{
+}
+
+/*********************************************************************/
+CglCutGenerator *
+CglRedSplit2::clone() const
+{
+  return new CglRedSplit2(*this);
+}
+
+/*********************************************************************/
+CglRedSplit2::~CglRedSplit2 ()
+{}
+
+/*********************************************************************/
+CglRedSplit2 &
+CglRedSplit2::operator=(const CglRedSplit2 &source)
+{  
+
+  if (this != &source) {
+    CglCutGenerator::operator=(source);
+    param = source.param;
+  }
+  return *this;
+}
+/*********************************************************************/
+// Returns true if needs optimal basis to do cuts
+bool 
+CglRedSplit2::needsOptimalBasis() const
+{
+  return true;
+}
+
+/************************************************************************/
+
+int CglRedSplit2::generateMultipliers(const OsiSolverInterface &si, 
+				      int* lambda,
+				      int maxNumMultipliers,
+				      int* basicVariables,
+				      OsiCuts* cs)
+{
+  solver = const_cast<OsiSolverInterface *>(&si);
+  if(solver == NULL) {
+    printf("### WARNING: CglRedSplit2::generateCuts(): no solver available.\n");
+    return 0;    
+  }  
+
+  if(!solver->optimalBasisIsAvailable()) {
+    printf("### WARNING: CglRedSplit2::generateCuts(): no optimal basis available.\n");
+    return 0;
+  }
+
+  // Reset some members of CglRedSplit2
+  card_intBasicVar = 0;
+  card_intBasicVar_frac = 0;
+  card_intNonBasicVar = 0;
+  card_contNonBasicVar = 0;
+  card_nonBasicAtUpper = 0;
+  card_nonBasicAtLower = 0;
+  numRedRows = 0;
+  startTime = CoinCpuTime();
+
+  // Get basic problem information from solver
+  ncol = solver->getNumCols(); 
+  nrow = solver->getNumRows(); 
+  colLower = solver->getColLower();
+  colUpper = solver->getColUpper();
+  rowLower = solver->getRowLower();
+  rowUpper = solver->getRowUpper();
+  rowRhs = solver->getRightHandSide();
+  reducedCost = solver->getReducedCost();
+  rowPrice = solver->getRowPrice();
+  objective = solver->getObjCoefficients();
+
+  xlp = solver->getColSolution();
+  rowActivity = solver->getRowActivity();
+  byRow = solver->getMatrixByRow();
+
+  solver->enableFactorization();
+  if (basicVariables != NULL){
+    solver->getBasics(basicVariables);
+  }
+  int numMultipliers = generateCuts(cs, maxNumMultipliers, lambda);
+  solver->disableFactorization();
+  return numMultipliers;
+} /* generateMultipliers */
+
+/***********************************************************************/
+
+int CglRedSplit2::tiltLandPcut(const OsiSolverInterface* si, 
+			       double* landprow, double landprhs, 
+			       int rownumber, const double* xbar, 
+			       const int* newnonbasics, OsiRowCut* cs,
+			       int* lambda){
+  solver = const_cast<OsiSolverInterface*>(si);
+  if(solver == NULL) {
+    printf("### WARNING: CglRedSplit2::tiltLandPcut(): no solver available.\n");
+    return 0;    
+  }  
+
+  // Reset some members of CglRedSplit2
+  card_intBasicVar = 0;
+  card_intBasicVar_frac = 0;
+  card_intNonBasicVar = 0;
+  card_contNonBasicVar = 0;
+  card_nonBasicAtUpper = 0;
+  card_nonBasicAtLower = 0;
+  numRedRows = 0;
+  startTime = CoinCpuTime();
+
+  // Get basic problem information from solver
+  ncol = solver->getNumCols(); 
+  nrow = solver->getNumRows(); 
+  colLower = solver->getColLower();
+  colUpper = solver->getColUpper();
+  rowLower = solver->getRowLower();
+  rowUpper = solver->getRowUpper();
+  rowRhs = solver->getRightHandSide();
+  reducedCost = solver->getReducedCost();
+  rowPrice = solver->getRowPrice();
+  objective = solver->getObjCoefficients();
+
+  xlp = solver->getColSolution();
+  rowActivity = solver->getRowActivity();
+  byRow = solver->getMatrixByRow();
+
+  int i;
+  is_integer = new int[ncol]; 
+  
+  compute_is_integer();
+
+  int *cstat = new int[ncol];
+  int *rstat = new int[nrow];
+
+
+  solver->getBasisStatus(cstat, rstat);   // 0: free  1: basic  
+                                          // 2: upper 3: lower
+
+  int *basis_index = new int[nrow]; // basis_index[i] = 
+                                    //        index of pivot var in row i
+                                    //        (slack if number >= ncol) 
+
+#ifdef RS2_TRACETAB
+  rs_printvecINT("cstat", cstat, ncol);
+  rs_printvecINT("rstat", rstat, nrow);
+#endif
+  solver->getBasics(basis_index);
+
+  cv_intBasicVar = new int[ncol];  
+  cv_intBasicVar_frac = new int[ncol];  
+  intBasicVar = new int[ncol];                                 
+  intNonBasicVar = new int[ncol];       
+  contNonBasicVar = new int[ncol+nrow]; 
+  nonBasicAtUpper = new int[ncol+nrow]; 
+  nonBasicAtLower = new int[ncol+nrow]; 
+  double dist_int;
+
+  for(i=0; i<ncol; i++) {
+    cv_intBasicVar[i] = 0;
+    cv_intBasicVar_frac[i] = 0;
+
+    switch(cstat[i]) {
+    case 1: // basic variable
+      
+      dist_int = rs_above_integer(xlp[i]);
+      if(is_integer[i]){
+	if ((dist_int > param.getAway()) && (dist_int < 1 - param.getAway())) {
+	  cv_intBasicVar_frac[i] = 1;
+	  card_intBasicVar_frac++;
+
+	  // intBasicVar_frac computed below, 
+	  // as order must be according to selected rows
+	}
+	card_intBasicVar++;
+	cv_intBasicVar[i] = 1;
+
+      }
+      break;
+
+    case 2: // Non basic at upper bound: must be flipped and shifted
+            // so that it becomes non negative with lower bound 0 
+            // It is assumed that bounds for integer variables have been
+            // tightend so that non basic integer structural variables 
+            // have integer values
+
+      nonBasicAtUpper[card_nonBasicAtUpper] = i;
+      card_nonBasicAtUpper++;
+
+      if(is_integer[i]) {
+	intNonBasicVar[card_intNonBasicVar] = i;
+	card_intNonBasicVar++;
+      }
+      else {
+	contNonBasicVar[card_contNonBasicVar] = i;
+	card_contNonBasicVar++;
+      }
+      break;
+
+    case 3 : // non basic at lower bound: must be shifted so that it becomes
+             // non negative with lower bound 0
+      // It is assumed that bounds for integer variables have been
+      // tightend so that they are integer
+
+      nonBasicAtLower[card_nonBasicAtLower] = i;
+      card_nonBasicAtLower++;
+
+      if(is_integer[i]) {
+	intNonBasicVar[card_intNonBasicVar] = i;
+	card_intNonBasicVar++;
+      }
+      else {
+	contNonBasicVar[card_contNonBasicVar] = i;
+	card_contNonBasicVar++;
+      }
+      break;
+
+    default: // free variable ? Don't know how to handle 
+      printf("### ERROR: CglRedSplit2::generateCuts(): cstat[%d]: %d\n",
+	     i, cstat[i]);
+      exit(1);
+      break;
+    } 
+  }
+
+  // Use this instead of rowRhs to allow for ranges
+  double *effective_rhs = new double[nrow];
+
+  for(i=0; i<nrow; i++) {
+    // effective rhs
+    effective_rhs[i] = rowRhs[i];
+    switch(rstat[i]) {
+    case 1: // basic slack
+      break;
+
+    case 2: // non basic slack at upper; flipped and shifted
+      effective_rhs[i] = rowLower[i];
+      nonBasicAtUpper[card_nonBasicAtUpper] = ncol+i;
+      card_nonBasicAtUpper++;
+
+      contNonBasicVar[card_contNonBasicVar] = ncol+i;
+      card_contNonBasicVar++;
+      break;
+
+    case 3: // non basic slack at lower; shifted
+      effective_rhs[i] = rowUpper[i];
+      nonBasicAtLower[card_nonBasicAtLower] = ncol+i;
+      card_nonBasicAtLower++;
+
+      contNonBasicVar[card_contNonBasicVar] = ncol+i;
+      card_contNonBasicVar++;
+      break;
+
+    default: 
+      printf("### ERROR: CglRedSlpit::generateCuts(): rstat[%d]: %d\n",
+	     i, rstat[i]);
+      exit(1);
+      break;
+    }
+    assert (fabs(effective_rhs[i])<1.0e100);
+  }
+
+#ifdef RS2_TRACE
+  printf("CglRedSplit2()::card_intBasicVar_frac %d %d\n", 
+	 card_intBasicVar_frac, card_contNonBasicVar);
+#endif
+  if((card_contNonBasicVar == 0) || (card_intBasicVar == 0)) {
+    delete[] cstat;
+    delete[] rstat;
+    delete[] basis_index;
+
+    delete[] cv_intBasicVar;  
+    delete[] cv_intBasicVar_frac;  
+    delete[] intBasicVar;
+    delete[] intNonBasicVar;
+    delete[] contNonBasicVar;
+    delete[] nonBasicAtUpper;
+    delete[] nonBasicAtLower;
+    delete[] is_integer;
+    delete[] effective_rhs;
+
+    printf("No vars to generate cut\n");
+    return 0; // no cuts can be generated
+  }
+
+  double *z = new double[ncol];  // workspace to get row of the tableau
+  double *slack = new double[nrow];  // workspace to get row of the tableau
+
+#ifdef RS2_TRACETAB
+  printOptTab(solver);
+#endif
+
+  if (rownumber >= 0){
+    // this means that the source row is in the given simplex tableau
+    mTab = card_intBasicVar;
+  }
+  else{
+    // source row is an extra row, so we need extra space
+    mTab = card_intBasicVar + 1;
+  }
+  nTab = card_contNonBasicVar;
+
+  rhsTab = new double[mTab];
+  cv_fracRowsTab = new int[mTab];
+  memset(cv_fracRowsTab, 0, mTab*sizeof(int));
+  int card_rowTab = 0;
+
+  int extraColumns = 0;
+  while (newnonbasics[extraColumns] >= 0){
+    extraColumns++;
+  }
+
+  rs_allocmatDBL(&contNonBasicTab, mTab, card_contNonBasicVar);
+  rs_allocmatDBL(&workNonBasicTab, mTab, card_contNonBasicVar + extraColumns);
+  rs_allocmatDBL(&intNonBasicTab, mTab, card_intNonBasicVar);
+  norm = new double[mTab];
+
+  intBasicVar_frac = new int[ncol];                                 
+
+  card_intBasicVar = 0; // recompute in pivot order
+  card_intBasicVar_frac = 0;
+
+  // write L&P row as first row
+  rhsTab[card_rowTab] = landprhs;
+
+  // flip row: L&P flips the nonbasic at upper bound, but we don't want this
+  for (int ii=0; ii<card_nonBasicAtUpper; ii++){
+    landprow[nonBasicAtUpper[ii]] = -landprow[nonBasicAtUpper[ii]];
+  }
+
+  for (int ii=0; ii<card_contNonBasicVar; ii++) {
+    int locind = contNonBasicVar[ii];
+    contNonBasicTab[card_rowTab][ii] = landprow[locind];
+  }
+
+  for (int ii=0; ii<card_intNonBasicVar; ii++) {
+    int locind = intNonBasicVar[ii];
+    intNonBasicTab[card_rowTab][ii] = landprow[locind];
+  }
+
+  // flip back to restore L&P row as it was given
+  for (int ii=0; ii<card_nonBasicAtUpper; ii++){
+    landprow[nonBasicAtUpper[ii]] = -landprow[nonBasicAtUpper[ii]];
+  }
+
+  card_rowTab++;
+
+  for(i=0; i<nrow; i++) {
+
+    int ind_row = i;
+
+    if(basis_index[ind_row] >= ncol || ind_row == rownumber) {
+      continue;
+    } 
+
+    if(cv_intBasicVar[basis_index[ind_row]] == 1) { 
+      // row used in generation
+      intBasicVar[card_intBasicVar] = basis_index[ind_row];
+      if (cv_intBasicVar_frac[basis_index[ind_row]] == 1){
+	// row is fractional
+	intBasicVar_frac[card_intBasicVar_frac] = basis_index[ind_row];
+	card_intBasicVar_frac++;
+	cv_fracRowsTab[card_intBasicVar] = 1;
+      }
+      card_intBasicVar++;
+      int ii;
+
+      rhsTab[card_rowTab] = xlp[basis_index[ind_row]];
+      solver->getBInvARow(ind_row, z, slack);
+
+      for(ii=0; ii<card_contNonBasicVar; ii++) {
+	int locind = contNonBasicVar[ii];
+	if(locind < ncol) {
+	  contNonBasicTab[card_rowTab][ii] = z[locind];
+	}
+	else {
+	  contNonBasicTab[card_rowTab][ii] = slack[locind - ncol];
+	}
+      }
+
+      for(ii=0; ii<card_intNonBasicVar; ii++) {
+	int locind = intNonBasicVar[ii];
+	if(locind < ncol) {
+	  intNonBasicTab[card_rowTab][ii] = z[locind];
+	}
+	else {
+	  printf("### ERROR: CglRedSplit2::generateCuts(): integer slack unexpected\n");
+	  exit(1);
+	}
+      }
+
+      card_rowTab++;
+    }
+  }
+
+  int pi_mat_rows = 1;
+  rs_allocmatINT(&pi_mat, pi_mat_rows, mTab);
+
+#ifdef RS2_TRACE
+  printf("intBasicVar:\n");
+  for(i=0; i<card_intBasicVar; i++) {
+    printf("%d ", intBasicVar[i]);
+  }
+  printf("\n");
+  printf("intBasicVar_frac:\n");
+  for(i=0; i<card_intBasicVar_frac; i++) {
+    printf("%d ", intBasicVar_frac[i]);
+  }
+  printf("\n");
+  printf("intNonBasicVar:\n");
+  for(i=0; i<card_intNonBasicVar; i++) {
+    printf("%d ", intNonBasicVar[i]);
+  }
+  printf("\n");
+  printf("contNonBasicVar:\n");
+  for(i=0; i<card_contNonBasicVar; i++) {
+    printf("%d ", contNonBasicVar[i]);
+  }
+  printf("\n");
+#endif
+
+  int card_row;
+  double *row = new double[ncol+nrow];
+  int *rowind = new int[ncol];
+  double *rowelem = new double[ncol];
+
+  const double *elements = byRow->getElements();
+  const int *rowStart = byRow->getVectorStarts();
+  const int *indices = byRow->getIndices();
+  const int *rowLength = byRow->getVectorLengths(); 
+
+  CglRedSplit2Param::ColumnSelectionStrategy columnSelection;
+  CglRedSplit2Param::RowSelectionStrategy rowSelection;
+  int numRows;
+
+  int generatedCuts = 0;
+
+  std::vector<CglRedSplit2Param::ColumnSelectionStrategy> listColSel 
+    = param.getColumnSelectionStrategyLAP();
+  std::vector<CglRedSplit2Param::RowSelectionStrategy> listRowSel 
+    = param.getRowSelectionStrategyLAP();
+  std::vector<int> listNumRows = param.getNumRowsReductionLAP();
+
+  for (unsigned int coliter = 0; coliter < listColSel.size(); ++coliter){
+    if (!checkTime()){
+      break;
+    }
+    columnSelection = listColSel[coliter];
+#ifdef RS2_TRACE
+    printf("Filling workNonBasicTab with column strategy %d\n", columnSelection);
+#endif
+    nTab = 0;
+    // select the columns
+    if (columnSelection != CglRedSplit2Param::CS_LAP_NONBASICS){
+      fill_workNonBasicTab(columnSelection, newnonbasics);
+    }
+    fill_workNonBasicTab(newnonbasics, xbar, 
+			 param.getColumnScalingStrategyLAP());
+    for (unsigned int nriter = 0; nriter < listNumRows.size(); ++nriter){
+      if (!checkTime()){
+	break;
+      }
+      numRows = listNumRows[nriter];
+#ifdef RS2_TRACE
+      printf("Applying reduction algorithm with %d rows\n", numRows);
+#endif
+      for (unsigned int rowiter = 0; rowiter < listRowSel.size(); ++rowiter){
+	if (!checkTime()){
+	  break;
+	}
+	rowSelection = listRowSel[rowiter];
+#ifdef RS2_TRACE
+	printf("Reducing norms with row strategy %d\n", rowSelection);
+#endif
+	// new iteration: reinitialize pi_mat
+	for(i=0; i<pi_mat_rows; i++) {
+	  memset(pi_mat[i], 0, mTab*sizeof(int));
+	}
+	// reduce the coefficients
+	reduce_workNonBasicTab(numRows, rowSelection, 1);
+	// now generate cuts
+	for(i=0; i<pi_mat_rows; i++) {
+	  if (pi_mat[i][i] == 0){
+	    // means we did not generate a cut from this row
+	    continue;
+	  }
+	  card_row = 0;
+ 	  generate_row(i, row);
+ 	  flip(row);
+
+	  // compute RHS
+	  double tabrowrhs = rs_dotProd(pi_mat[i], rhsTab, mTab); 
+	  int got_one = 0;
+    
+ 	  got_one = generate_cgcut(row, &tabrowrhs);
+
+	  if (got_one){
+	    // new multipliers found, check if the generated cut is good
+	    unflip(row, &tabrowrhs);
+
+	    eliminate_slacks(row, elements, rowStart, indices, 
+			     rowLength, effective_rhs, &tabrowrhs);
+	    
+	    if(generate_packed_row(xbar, row, rowind, rowelem, &card_row, 
+				   tabrowrhs)) {
+	      // the cut is good, multipliers should be saved;
+	      // first of all, add cut to the collection if needed
+	      cs->setRow(card_row, rowind, rowelem);
+	      cs->setLb(-param.getINFINIT());
+	      double adjust = param.getEPS_RELAX_ABS();
+	      if(param.getEPS_RELAX_REL() > 0.0) {
+		adjust += fabs(tabrowrhs) * param.getEPS_RELAX_REL();
+	      }
+	      cs->setUb(tabrowrhs + adjust);   
+	      if (lambda){
+		// Modify the initial disjunction by adding the new 
+		// coefficients
+		for (int k = 1; k < mTab; ++k){
+		  lambda[intBasicVar[k-1]] += pi_mat[i][k];
+		}
+	      }
+	      generatedCuts++;
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  delete[] cstat;
+  delete[] rstat;
+  delete[] basis_index;
+  delete[] slack;
+  delete[] z;
+  delete[] effective_rhs;
+  delete[] row;
+  delete[] rowind;
+  delete[] rowelem;
+
+  delete[] cv_intBasicVar_frac;  
+  delete[] cv_fracRowsTab;  
+  delete[] intBasicVar;
+  delete[] intBasicVar_frac;
+  delete[] intNonBasicVar;
+  delete[] contNonBasicVar;
+  delete[] nonBasicAtUpper;
+  delete[] nonBasicAtLower;
+  delete[] is_integer;
+  rs_deallocmatDBL(&contNonBasicTab, mTab);
+  rs_deallocmatDBL(&workNonBasicTab, mTab);
+  rs_deallocmatDBL(&intNonBasicTab, mTab);
+  rs_deallocmatINT(&pi_mat, pi_mat_rows);
+  delete[] rhsTab;
+  delete[] norm;
+
+  return generatedCuts;
+  
+} /* tiltLandPcut */
+
+/***************************************************************************/
+void CglRedSplit2::fill_workNonBasicTab(const int* newnonbasics,
+					const double* xbar,
+					CglRedSplit2Param::ColumnScalingStrategy scaling){
+  
+  // See CglRedSplit2Param.hpp for a description of the strategies
+  int i = 0;
+  int currvar, colpos;
+#ifdef RS2_TRACE
+  while (newnonbasics[i] >= 0){
+    printf("Newnonbasic[%d]: %d\n", i, newnonbasics[i]);
+    i++;
+  }
+  i = 0;
+#endif
+  // In workNonBasicTab, we write the new nonbasic columns given by the
+  // Lift & Project algorithm, scaled by the value of the fractional solution.
+  while (newnonbasics[i] >= 0){
+    currvar = newnonbasics[i];
+    if (currvar < ncol && solver->isInteger(currvar)){
+      for (colpos = 0; colpos < card_intNonBasicVar; ++colpos){
+	if (intNonBasicVar[colpos] == currvar){
+#ifdef RS2_TRACE
+	  printf("Found int nonbasic at pos %d: %d %d\n", colpos, intNonBasicVar[colpos], currvar);
+#endif
+	  break;
+	}
+      }
+      double factor = 1.0;
+      if (scaling == CglRedSplit2Param::SC_LINEAR){
+	if (fabs(xbar[currvar]) > factor){
+	  factor = fabs(xbar[currvar]);
+	}
+      }
+      else if (scaling == CglRedSplit2Param::SC_LINEAR_BOUNDED){
+	if (fabs(xbar[currvar]) > factor){
+	  factor = fabs(xbar[currvar]);
+	}
+	if (factor < param.getColumnScalingBoundLAP()){
+	  factor = param.getColumnScalingBoundLAP();
+	}
+      }
+      else if (scaling == CglRedSplit2Param::SC_LOG_BOUNDED){
+	if (log(fabs(xbar[currvar])) > factor){
+	  factor = log(fabs(xbar[currvar]));
+	}
+	if (factor < param.getColumnScalingBoundLAP()){
+	  factor = param.getColumnScalingBoundLAP();
+	}
+      }
+      else if (scaling == CglRedSplit2Param::SC_UNIFORM){
+	factor = param.getColumnScalingBoundLAP();
+      }
+      else if (scaling == CglRedSplit2Param::SC_UNIFORM_NZ){
+	if (fabs(xbar[currvar]) > param.getEPS()){
+	  factor = param.getColumnScalingBoundLAP();
+	}
+      }
+      for (int j = 0; j < mTab; ++j){
+	workNonBasicTab[j][nTab] = intNonBasicTab[j][colpos]*factor;
+      }
+      nTab++;
+    }
+    else{
+      for (colpos = 0; colpos < card_contNonBasicVar; ++colpos){
+	if (contNonBasicVar[colpos] == currvar){
+#ifdef RS2_TRACE
+	  printf("Found cont nonbasic at pos %d: %d %d\n", colpos, contNonBasicVar[colpos], currvar);
+#endif
+	  break;
+	}
+      }
+      double factor = 1.0;
+      if (scaling == CglRedSplit2Param::SC_LINEAR){
+	if (fabs(xbar[currvar]) > factor){
+	  factor = fabs(xbar[currvar]);
+	}
+      }
+      else if (scaling == CglRedSplit2Param::SC_LINEAR_BOUNDED){
+	if (fabs(xbar[currvar]) > factor){
+	  factor = fabs(xbar[currvar]);
+	}
+	if (factor < param.getColumnScalingBoundLAP()){
+	  factor = param.getColumnScalingBoundLAP();
+	}
+      }
+      else if (scaling == CglRedSplit2Param::SC_LOG_BOUNDED){
+	if (log(fabs(xbar[currvar])) > factor){
+	  factor = log(fabs(xbar[currvar]));
+	}
+	if (factor < param.getColumnScalingBoundLAP()){
+	  factor = param.getColumnScalingBoundLAP();
+	}
+      }
+      else if (scaling == CglRedSplit2Param::SC_UNIFORM){
+	factor = param.getColumnScalingBoundLAP();
+      }
+      else if (scaling == CglRedSplit2Param::SC_UNIFORM_NZ){
+	if (fabs(xbar[currvar]) > param.getEPS()){
+	  factor = param.getColumnScalingBoundLAP();
+	}
+      }
+      for (int j = 0; j < mTab; ++j){
+#ifdef RS2_TRACE
+	printf("Col %d Row %d: %f, xbar %f\n", colpos, j, contNonBasicTab[j][colpos], xbar[currvar]);
+#endif	
+	workNonBasicTab[j][nTab] = contNonBasicTab[j][colpos]*factor;
+      }
+      nTab++;
+    }
+    i++;
+  }
+#ifdef RS2_TRACE
+  printf("Printing workNonBasicTab:\n");
+#endif
+#if RS_FAST_WORK 
+  int workOffset = mTab+card_intNonBasicVar+card_contNonBasicVar+2;
+#endif
+  for (i = 0; i < mTab; ++i) {
+#ifdef RS2_TRACE
+    for (int j = 0; j < nTab; ++j){
+      printf("%.6f ", workNonBasicTab[i][j]);
+    }
+    printf("\n");
+#endif
+#if RS_FAST_WORK == 0
+    norm[i] = rs_dotProd(workNonBasicTab[i], workNonBasicTab[i], nTab);
+#elif RS_FAST_WORK == 1
+    norm[i] = rs_dotProd(workNonBasicTab[i], workNonBasicTab[i], nTab);
+    double value = rs_sparseDotProd(workNonBasicTab[i],
+				       workNonBasicTab[i], 
+				       pi_mat[i]+workOffset,
+				       pi_mat[i]+workOffset);
+    assert (value==norm[i]);
+#else
+    norm[i] = rs_sparseDotProd(workNonBasicTab[i],
+				       workNonBasicTab[i], 
+				       pi_mat[i]+workOffset,
+				       pi_mat[i]+workOffset);
+#endif
+  }
+} /* fill_workNonBasicTab */
+
+/***********************************************************************/
+
diff --git a/cbits/coin/CglRedSplit2.hpp b/cbits/coin/CglRedSplit2.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglRedSplit2.hpp
@@ -0,0 +1,494 @@
+// Last edit: 04/03/10
+//
+// Name:     CglRedSplit2.hpp
+// Author:   Giacomo Nannicini
+//           Singapore University of Technology and Design
+//           Singapore
+//           email: nannicini@sutd.edu.sg
+//           based on CglRedSplit by Francois Margot
+// Date:     03/09/09
+//-----------------------------------------------------------------------------
+// Copyright (C) 2010, Giacomo Nannicini and others.  All Rights Reserved.
+
+#ifndef CglRedSplit2_H
+#define CglRedSplit2_H
+
+#include "CglCutGenerator.hpp"
+#include "CglRedSplit2Param.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinTime.hpp"
+
+/** Reduce-and-Split Cut Generator Class; See method generateCuts().
+    Based on the papers "Practical strategies for generating rank-1
+    split cuts in mixed-integer linear programming" by G. Cornuejols
+    and G. Nannicini, published on Mathematical Programming
+    Computation, and "Combining Lift-and-Project and Reduce-and-Split"
+    by E. Balas, G. Cornuejols, T. Kis and G. Nannicini, published on
+    INFORMS Journal on Computing. Part of this code is based on
+    CglRedSplit by F. Margot. */
+
+class CglRedSplit2 : public CglCutGenerator {
+
+  friend void CglRedSplit2UnitTest(const OsiSolverInterface * siP,
+				  const std::string mpdDir);
+public:
+  /**@name generateCuts */
+  //@{
+  /** Generate Reduce-and-Split Mixed Integer Gomory cuts 
+      for the model of the solver interface si.
+
+      Insert the generated cuts into OsiCuts cs.
+
+      This generator currently works only with the Lp solvers Clp or
+      Cplex9.0 or higher. It requires access to the optimal tableau
+      and optimal basis inverse and makes assumptions on the way slack
+      variables are added by the solver. The Osi implementations for
+      Clp and Cplex verify these assumptions.
+
+      When calling the generator, the solver interface si must contain
+      an optimized problem and information related to the optimal
+      basis must be available through the OsiSolverInterface methods
+      (si->optimalBasisIsAvailable() must return 'true'). It is also
+      essential that the integrality of structural variable i can be
+      obtained using si->isInteger(i).
+
+      Reduce-and-Split cuts are a class of split cuts. We compute
+      linear combinations of the rows of the simplex tableau, trying
+      to reduce some of the coefficients on the nonbasic continuous
+      columns.  We have a large number of heuristics to choose which
+      coefficients should be reduced, and by using which rows. The
+      paper explains everything in detail.
+
+      Note that this generator can potentially generate a huge number
+      of cuts, depending on how it is parametered. Default parameters
+      should be good for most situations; if you want to go heavy on
+      split cuts, use more row selection strategies or a different
+      number of rows in the linear combinations. Again, look at the
+      paper for details. If you want to generate a small number of
+      cuts, default parameters are not the best choice.
+
+      A combination of Reduce-and-Split with Lift & Project is
+      described in the paper "Combining Lift-and-Project and
+      Reduce-and-Split". The Reduce-and-Split code for the
+      implementation used in that paper is included here.
+
+      This generator does not generate the same cuts as CglRedSplit,
+      therefore both generators can be used in conjunction.
+
+  */
+
+  virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			    const CglTreeInfo info = CglTreeInfo());
+
+  /// Return true if needs optimal basis to do cuts (will return true)
+  virtual bool needsOptimalBasis() const;
+
+  // Generate the row multipliers computed by Reduce-and-Split from the
+  // given OsiSolverInterface. The multipliers are written in lambda;
+  // lambda should be of size nrow*maxNumMultipliers. We generate at most
+  // maxNumMultipliers m-vectors of row multipliers, and return the number
+  // of m-vectors that were generated.
+  // If the caller wants to know which variables are basic in each row 
+  // (same order as lambda), basicVariables should be non-NULL (size nrow).
+  // This method can also generate the cuts corresponding to the multipliers
+  // returned; it suffices to pass non-NULL OsiCuts.
+  // This method is not needed by the typical user; however, it is useful
+  // in the context of generating Lift & Project cuts.
+  int generateMultipliers(const OsiSolverInterface& si, int* lambda,
+			  int maxNumMultipliers, int* basicVariables = NULL,
+			  OsiCuts* cs = NULL);
+
+  // Try to improve a Lift & Project cut, by employing the
+  // Reduce-and-Split procedure. We start from a row of a L&P tableau,
+  // and generate a cut trying to reduce the coefficients on the
+  // nonbasic variables.  Note that this L&P tableau will in general
+  // have nonbasic variables which are nonzero in the point that we
+  // want to cut off, so we should be careful.  Arguments:
+  // OsiSolverInterface which contains the simplex tableau, initial
+  // row from which the cut is derived, row rhs, row number of the
+  // source row (if it is in the simplex tableau; otherwise, a
+  // negative number; needed to avoid using duplicate rows), point
+  // that we want to cut off (note: this is NOT a basic solution for
+  // the OsiSolverInterace!), list of variables which are basic in
+  // xbar but are nonbasic in the OsiSolverInterface. The computed cut
+  // is written in OsiRowCut* cs. Finally, if a starting disjunction
+  // is provided in the vector lambda (of size ncols, i.e. a
+  // disjunction on the structural variables), the disjunction is
+  // modified according to the cut which is produced.
+  int tiltLandPcut(const OsiSolverInterface* si, double* row, 
+		   double rowRhs, int rownumber, const double* xbar, 
+		   const int* newnonbasics, OsiRowCut* cs, int* lambda = NULL);
+
+  //@}
+  
+  
+  /**@name Public Methods */
+  //@{
+
+  // Set the parameters to the values of the given CglRedSplit2Param object.
+  void setParam(const CglRedSplit2Param &source); 
+  // Return the CglRedSplit2Param object of the generator. 
+  inline CglRedSplit2Param& getParam() {return param;}
+
+  /// Print some of the data members; used for debugging
+  void print() const;
+
+  /// Print the current simplex tableau  
+  void printOptTab(OsiSolverInterface *solver) const;
+  
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglRedSplit2();
+
+  /// Constructor with specified parameters 
+  CglRedSplit2(const CglRedSplit2Param &RS_param);
+ 
+  /// Copy constructor 
+  CglRedSplit2(const CglRedSplit2 &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglRedSplit2 & operator=(const CglRedSplit2& rhs);
+  
+  /// Destructor 
+  virtual ~CglRedSplit2 ();
+
+  //@}
+
+private:
+  
+  // Private member methods
+
+/**@name Private member methods */
+
+  //@{
+
+  // Method generating the cuts after all CglRedSplit2 members are 
+  // properly set. This does the actual work. Returns the number of
+  // generated cuts (or multipliers).
+  // Will generate cuts if cs != NULL, and will generate multipliers
+  // if lambda != NULL. 
+  int generateCuts(OsiCuts* cs, int maxNumCuts, int* lambda = NULL);
+
+  /// Compute the fractional part of value, allowing for small error.
+  inline double rs_above_integer(const double value) const; 
+
+  /// Fill workNonBasicTab, depending on the column selection strategy.
+  /// Accepts a list of variables indices that should be ignored; by
+  /// default, this list is empty (it is only used by Lift & Project).
+  /// The list ignore_list contains -1 as the last element.
+  /// Note that the implementation of the ignore_list is not very efficient
+  /// if the list is long, so it should be used only if its short.
+  void fill_workNonBasicTab(CglRedSplit2Param::ColumnSelectionStrategy 
+			    strategy, const int* ignore_list = NULL);
+
+  /// Fill workNonBasicTab, alternate version for Lift & Project: also
+  /// reduces columns which are now nonbasic but are basic in xbar.
+  /// This function should be called only when CglRedSplit2 is used in
+  /// conjunction with CglLandP to generate L&P+RS cuts.
+  void fill_workNonBasicTab(const int* newnonbasics, const double* xbar,
+			    CglRedSplit2Param::ColumnScalingStrategy scaling);
+
+  /// Reduce rows of workNonBasicTab, i.e. compute integral linear
+  /// combinations of the rows in order to reduce row coefficients on
+  /// workNonBasicTab
+  void reduce_workNonBasicTab(int numRows, 
+			      CglRedSplit2Param::RowSelectionStrategy 
+			      rowSelectionStrategy,
+			      int maxIterations);
+
+  /// Generate a linear combination of the rows of the current LP
+  /// tableau, using the row multipliers stored in the matrix pi_mat
+  /// on the row of index index_row
+  void generate_row(int index_row, double *row);
+
+  /// Generate a mixed integer Gomory cut, when all non basic 
+  /// variables are non negative and at their lower bound.
+  int generate_cgcut(double *row, double *rhs);
+
+  /// Use multiples of the initial inequalities to cancel out the coefficients
+  /// of the slack variables.
+  void eliminate_slacks(double *row, 
+			const double *elements, 
+			const int *start,
+			const int *indices,
+			const int *rowLength,
+			const double *rhs, double *rowrhs);
+
+  /// Change the sign of the coefficients of the continuous non basic
+  /// variables at their upper bound.
+  void flip(double *row);
+
+  /// Change the sign of the coefficients of the continuous non basic
+  /// variables at their upper bound and do the translations restoring
+  /// the original bounds. Modify the right hand side
+  /// accordingly.
+  void unflip(double *row, double *rowrhs);
+
+  /// Returns 1 if the row has acceptable max/min coeff ratio.
+  /// Compute max_coeff: maximum absolute value of the coefficients.
+  /// Compute min_coeff: minimum absolute value of the coefficients
+  /// larger than EPS_COEFF.
+  /// Return 0 if max_coeff/min_coeff > MAXDYN.
+  int check_dynamism(double *row);
+
+  /// Generate the packed cut from the row representation.
+  int generate_packed_row(const double *xlp, double *row,
+			  int *rowind, double *rowelem, 
+			  int *card_row, double & rhs);
+
+  // Compute entries of is_integer.
+  void compute_is_integer();
+
+  // Check that two vectors are different.
+  bool rs_are_different_vectors(const int *vect1, 
+				const int *vect2,
+				const int dim);
+
+  // allocate matrix of integers
+  void rs_allocmatINT(int ***v, int m, int n);
+  // deallocate matrix of integers
+  void rs_deallocmatINT(int ***v, int m);
+  // allocate matrix of doubles
+  void rs_allocmatDBL(double ***v, int m, int n);
+  // deallocate matrix of doubles
+  void rs_deallocmatDBL(double ***v, int m);
+  // print a vector of integers
+  void rs_printvecINT(const char *vecstr, const int *x, int n) const;
+  // print a vector of doubles
+  void rs_printvecDBL(const char *vecstr, const double *x, int n) const;
+  // print a matrix of integers
+  void rs_printmatINT(const char *vecstr, const int * const *x, int m, int n) const;
+  // print a matrix of doubles
+  void rs_printmatDBL(const char *vecstr, const double * const *x, int m, int n) const;
+  // dot product
+  double rs_dotProd(const double *u, const double *v, int dim) const;
+  double rs_dotProd(const int *u, const double *v, int dim) const;
+  // From Numerical Recipes in C: LU decomposition
+  int ludcmp(double **a, int n, int *indx, double *d, double* vv) const;
+  // from Numerical Recipes in C: backward substitution
+  void lubksb(double **a, int n, int *indx, double *b) const;
+
+  // Check if the linear combination given by listOfRows with given multipliers
+  // improves the norm of row #rowindex; note: multipliers are rounded!
+  // Returns the difference with respect to the old norm (if negative there is
+  // an improvement, if positive norm increases)
+  double compute_norm_change(double oldnorm, const int* listOfRows,
+			     int numElemList, const double* multipliers) const;
+
+  // Compute the list of rows that should be used to reduce row #rowIndex
+  int get_list_rows_reduction(int rowIndex, int numRowsReduction, 
+			      int* list, const double* norm, 
+			      CglRedSplit2Param::RowSelectionStrategy 
+			      rowSelectionStrategy) const;
+
+  // Sorts the rows by increasing number of nonzeroes with respect to a given
+  // row (rowIndex), on the nonbasic variables (whichTab == 0 means only
+  // integer, whichTab == 1 means only workTab, whichTab == 2 means both).
+  // The array for sorting must be allocated (and deleted) by caller.
+  // Corresponds to BRS1 in the paper.
+  int sort_rows_by_nonzeroes(struct sortElement* array, int rowIndex, 
+			     int maxRows, int whichTab) const;
+
+  // Greedy variant of the previous function; slower but typically
+  // more effective. Corresponds to BRS2 in the paper.
+  int sort_rows_by_nonzeroes_greedy(struct sortElement* array, int rowIndex, 
+				    int maxRows, int whichTab) const;
+
+  // Sorts the rows by decreasing absolute value of the cosine of the
+  // angle with respect to a given row (rowIndex), on the nonbasic
+  // variables (whichTab == 0 means only integer, whichTab == 1 means
+  // only workTab, whichTab == 2 means both).  The array for sorting
+  // must be allocated (and deleted) by caller. Very effective
+  // strategy in practice. Corresponds to BRS3 in the paper.
+  int sort_rows_by_cosine(struct sortElement* array, int rowIndex, 
+			  int maxRows, int whichTab) const;
+
+  // Did we hit the time limit?
+  inline bool checkTime() const{
+    if ((CoinCpuTime() - startTime) < param.getTimeLimit()){
+      return true;
+    }
+    return false;
+  }
+
+  //@}
+
+  
+  // Private member data
+
+  /**@name Private member data */
+  
+  //@{
+
+  /// Object with CglRedSplit2Param members. 
+  CglRedSplit2Param param;
+
+  /// Number of rows ( = number of slack variables) in the current LP.
+  int nrow; 
+
+  /// Number of structural variables in the current LP.
+  int ncol;
+
+  /// Number of rows which have been reduced
+  int numRedRows;
+
+  /// Lower bounds for structural variables
+  const double *colLower;
+
+  /// Upper bounds for structural variables
+  const double *colUpper;
+  
+  /// Lower bounds for constraints
+  const double *rowLower;
+
+  /// Upper bounds for constraints
+  const double *rowUpper;
+
+  /// Righ hand side for constraints (upper bound for ranged constraints).
+  const double *rowRhs;
+
+  /// Reduced costs for columns
+  const double *reducedCost;
+
+  /// Row price
+  const double *rowPrice;
+
+  /// Objective coefficients
+  const double* objective;
+
+  /// Number of integer basic structural variables 
+  int card_intBasicVar;
+
+  /// Number of integer basic structural variables that are fractional in the
+  /// current lp solution (at least param.away_ from being integer).  
+  int card_intBasicVar_frac;
+
+  /// Number of integer non basic structural variables in the
+  /// current lp solution.  
+  int card_intNonBasicVar; 
+
+  /// Number of continuous non basic variables (structural or slack) in the
+  /// current lp solution.  
+  int card_contNonBasicVar;
+
+  /// Number of continuous non basic variables (structural or slack) in the
+  /// current working set for coefficient reduction
+  int card_workNonBasicVar;
+
+  /// Number of non basic variables (structural or slack) at their
+  /// upper bound in the current lp solution.
+  int card_nonBasicAtUpper; 
+
+  /// Number of non basic variables (structural or slack) at their
+  /// lower bound in the current lp solution.
+  int card_nonBasicAtLower;
+
+  /// Characteristic vector for integer basic structural variables
+  int *cv_intBasicVar;  
+
+  /// Characteristic vector for integer basic structural variables
+  /// with non integer value in the current lp solution.
+  int *cv_intBasicVar_frac;  
+
+  /// Characteristic vector for rows of the tableau selected for reduction
+  /// with non integer value in the current lp solution
+  int *cv_fracRowsTab;  
+
+  /// List of integer structural basic variables 
+  /// (in order of pivot in selected rows for cut generation).
+  int *intBasicVar;
+
+  /// List of integer structural basic variables with fractional value
+  /// (in order of pivot in selected rows for cut generation).
+  int *intBasicVar_frac;
+
+  /// List of integer structural non basic variables.
+  int *intNonBasicVar; 
+
+  /// List of continuous non basic variables (structural or slack). 
+  // slacks are considered continuous (no harm if this is not the case).
+  int *contNonBasicVar;
+
+  /// List of non basic variables (structural or slack) at their 
+  /// upper bound. 
+  int *nonBasicAtUpper;
+
+  /// List of non basic variables (structural or slack) at their lower
+  /// bound.
+  int *nonBasicAtLower;
+
+  /// Number of rows in the reduced tableau (= card_intBasicVar).
+  int mTab;
+
+  /// Number of columns in the reduced tableau (= card_contNonBasicVar)
+  int nTab;
+
+  /// Tableau of multipliers used to alter the rows used in generation.
+  /// Dimensions: mTab by mTab. Initially, pi_mat is the identity matrix.
+  int **pi_mat;
+
+  /// Simplex tableau for continuous non basic variables (structural or slack).
+  /// Only rows used for generation.
+  /// Dimensions: mTab by card_contNonBasicVar.
+  double **contNonBasicTab;
+
+  /// Current tableau for continuous non basic variables (structural or slack).
+  /// Only columns used for coefficient reduction.
+  /// Dimensions: mTab by card_workNonBasicVar.
+  double **workNonBasicTab;
+
+  /// Simplex tableau for integer non basic structural variables.
+  /// Only rows used for generation.
+  // Dimensions: mTab by card_intNonBasicVar.
+  double **intNonBasicTab;
+
+  /// Right hand side of the tableau.
+  /// Only rows used for generation.
+  double *rhsTab;
+
+  /// Norm of rows in workNonBasicTab; needed for faster computations
+  double *norm;
+
+  /// Characteristic vectors of structural integer variables or continuous
+  /// variables currently fixed to integer values. 
+  int *is_integer;
+
+  /// Pointer on solver. Reset by each call to generateCuts().
+  OsiSolverInterface *solver;
+
+  /// Pointer on point to separate. Reset by each call to generateCuts().
+  const double *xlp;
+
+  /// Pointer on row activity. Reset by each call to generateCuts().
+  const double *rowActivity;
+
+  /// Pointer on matrix of coefficient ordered by rows. 
+  /// Reset by each call to generateCuts().
+  const CoinPackedMatrix *byRow;
+
+  /// Time at which cut computations began.
+  /// Reset by each call to generateCuts().
+  double startTime;
+
+  //@}
+};
+
+//#############################################################################
+/** A function that tests some of the methods in the CglRedSplit2
+    class. The only reason for it not to be a member method is that
+    this way it doesn't have to be compiled into the library. And
+    that's a gain, because the library should be compiled with
+    optimization on, but this method should be compiled with
+    debugging. */
+void CglRedSplit2UnitTest(const OsiSolverInterface * siP,
+			 const std::string mpdDir );
+
+
+#endif
diff --git a/cbits/coin/CglRedSplit2Param.cpp b/cbits/coin/CglRedSplit2Param.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglRedSplit2Param.cpp
@@ -0,0 +1,526 @@
+// Name:     CglRedSplit2Param.hpp
+// Author:   Giacomo Nannicini
+//           Singapore University of Technology and Design
+//           Singapore
+//           email: nannicini@sutd.edu.sg
+// Date:     03/09/09
+//-----------------------------------------------------------------------------
+// Copyright (C) 2010, Giacomo Nannicini and others.  All Rights Reserved.
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CglRedSplit2Param.hpp"
+
+/***********************************************************************/
+void CglRedSplit2Param::setAway(double value)
+{
+  if (value > 0.0 && value <= 0.5)
+    away_ = value;
+}
+
+/***********************************************************************/
+void CglRedSplit2Param::setEPS_ELIM(double eps_el)
+{
+  if(eps_el >= 0)
+    EPS_ELIM = eps_el;
+} /* setEPS_ELIM */
+
+/***********************************************************************/
+void CglRedSplit2Param::setEPS_RELAX_ABS(double eps_ra)
+{
+  if(eps_ra >= 0)
+    EPS_RELAX_ABS = eps_ra;
+} /* setEPS_RELAX_ABS */
+
+/***********************************************************************/
+void CglRedSplit2Param::setEPS_RELAX_REL(double eps_rr)
+{
+  if(eps_rr >= 0)
+    EPS_RELAX_REL = eps_rr;
+} /* setEPS_RELAX_REL */
+
+/***********************************************************************/
+void CglRedSplit2Param::setMAXDYN(double value)
+{
+    if (value > 1.0) {
+    MAXDYN = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2::setMAXDYN(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMAXDYN */
+
+/***********************************************************************/
+void CglRedSplit2Param::setMINVIOL(double value)
+{
+  if (value > 0.0 && value <= 0.1) {
+    MINVIOL = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::setMINVIOL(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMINVIOL */
+
+/***********************************************************************/
+void CglRedSplit2Param::setMAX_SUPP_REL(double value)
+{
+  if (value > 0.0 && value <= 0.1) {
+    MINVIOL = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::setMINVIOL(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMAX_SUPP_REL */
+
+/***********************************************************************/
+void CglRedSplit2Param::setUSE_INTSLACKS(int value)
+{
+  USE_INTSLACKS = value;
+} /* setUSE_INTSLACKS */
+
+/***********************************************************************/
+void CglRedSplit2Param::setNormIsZero(double value)
+{
+  if (value > 0.0 && value <= 1) {
+    normIsZero_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::setNormIsZero(): value: %f ignored\n",
+	   value);
+  }
+} /* setNormIsZero */
+
+/***********************************************************************/
+void CglRedSplit2Param::setMinNormReduction(double value)
+{
+  if (value > 0.0 && value <= 1) {
+    minNormReduction_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::setMinNormReduction(): value: %f ignored\n",
+	   value);
+  }
+} /* setMinNormReduction */
+
+/***********************************************************************/
+void CglRedSplit2Param::setMaxSumMultipliers(int value)
+{
+  if (value > 1) {
+    maxSumMultipliers_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::setMaxSumMultipliers(): value: %d ignored\n",
+	   value);
+  }
+} /* setMaxSumMultipliers */
+
+/***********************************************************************/
+void CglRedSplit2Param::setNormalization(double value)
+{
+  if (value >= 0) {
+    normalization_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::setNormalization(): value: %f ignored\n",
+	   value);
+  }
+} /* setNormalization */
+
+/***********************************************************************/
+void CglRedSplit2Param::addNumRowsReduction(int value)
+{
+  if (value >= 0) {
+    numRowsReduction_.push_back(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::addNumRowsReduction(): value: %d ignored\n",
+	   value);
+  }
+} /* addNumRowsReduction */
+
+/***********************************************************************/
+void CglRedSplit2Param::addColumnSelectionStrategy(ColumnSelectionStrategy value)
+{
+  if (value != CS_ALL && value != CS_BEST && value != CS_LAP_NONBASICS) {
+    columnSelectionStrategy_.push_back(value);
+  }
+  else if (value == CS_ALL) {
+    // CS_ALL means all strategies.
+    columnSelectionStrategy_.push_back(CS1);
+    columnSelectionStrategy_.push_back(CS2);
+    columnSelectionStrategy_.push_back(CS3);
+    columnSelectionStrategy_.push_back(CS4);
+    columnSelectionStrategy_.push_back(CS5);
+    columnSelectionStrategy_.push_back(CS6);
+    columnSelectionStrategy_.push_back(CS7);
+    columnSelectionStrategy_.push_back(CS8);
+    columnSelectionStrategy_.push_back(CS9);
+    columnSelectionStrategy_.push_back(CS10);
+    columnSelectionStrategy_.push_back(CS11);
+    columnSelectionStrategy_.push_back(CS12);
+    columnSelectionStrategy_.push_back(CS13);
+    columnSelectionStrategy_.push_back(CS14);
+    columnSelectionStrategy_.push_back(CS15);
+    columnSelectionStrategy_.push_back(CS16);
+    columnSelectionStrategy_.push_back(CS17);
+    columnSelectionStrategy_.push_back(CS18);
+    columnSelectionStrategy_.push_back(CS19);
+    columnSelectionStrategy_.push_back(CS20);
+    columnSelectionStrategy_.push_back(CS21);
+  }
+  else if (value == CS_BEST){
+    // Select C-5P, I-2P-2/3, I-2P-4/5, I-3P
+    columnSelectionStrategy_.push_back(CS4);
+    columnSelectionStrategy_.push_back(CS5);
+    columnSelectionStrategy_.push_back(CS6);
+    columnSelectionStrategy_.push_back(CS7);
+    columnSelectionStrategy_.push_back(CS8);
+
+    columnSelectionStrategy_.push_back(CS9);
+    columnSelectionStrategy_.push_back(CS10);
+    columnSelectionStrategy_.push_back(CS11);
+    columnSelectionStrategy_.push_back(CS12);
+
+    columnSelectionStrategy_.push_back(CS18);
+    columnSelectionStrategy_.push_back(CS19);
+    columnSelectionStrategy_.push_back(CS20);
+    columnSelectionStrategy_.push_back(CS21);
+  }
+
+} /* addColumnSelectionStrategy */
+
+/***********************************************************************/
+void CglRedSplit2Param::addRowSelectionStrategy(RowSelectionStrategy value)
+{
+  if (value != RS_ALL && value != RS_BEST){
+    rowSelectionStrategy_.push_back(value);
+  }
+  else if (value == RS_ALL){
+    rowSelectionStrategy_.push_back(RS1);
+    rowSelectionStrategy_.push_back(RS2);
+    rowSelectionStrategy_.push_back(RS3);
+    rowSelectionStrategy_.push_back(RS4);
+    rowSelectionStrategy_.push_back(RS5);
+    rowSelectionStrategy_.push_back(RS6);
+    rowSelectionStrategy_.push_back(RS7);
+    rowSelectionStrategy_.push_back(RS8);
+  }
+  else if (value == RS_BEST){
+    rowSelectionStrategy_.push_back(RS7);
+    rowSelectionStrategy_.push_back(RS8);
+  }
+} /* addRowSelectionStrategy */
+
+/***********************************************************************/
+
+void CglRedSplit2Param::addNumRowsReductionLAP(int value)
+{
+  if (value >= 0) {
+    numRowsReductionLAP_.push_back(value);
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::addNumRowsReductionLAP(): value: %d ignored\n", value);
+  }
+} /* addNumRowsReductionLAP */
+
+/***********************************************************************/
+void CglRedSplit2Param::addColumnSelectionStrategyLAP(ColumnSelectionStrategy value)
+{
+  if (value != CS_ALL && value != CS_BEST) {
+    columnSelectionStrategyLAP_.push_back(value);
+  }
+  else if (value == CS_BEST){
+    columnSelectionStrategyLAP_.push_back(CS1);
+  }
+  else{
+    printf("### WARNING: CglRedSplit2Param::addColumnSelectionStrategyLAP(): value: %d ignored\n", value);
+  }
+} /* addColumnSelectionStrategyLAP */
+
+/***********************************************************************/
+void CglRedSplit2Param::addRowSelectionStrategyLAP(RowSelectionStrategy value)
+{
+  if (value != RS_ALL && value != RS_BEST){
+    rowSelectionStrategyLAP_.push_back(value);
+  }
+  else if (value == RS_BEST){
+    rowSelectionStrategyLAP_.push_back(RS8);
+  }
+  else{
+    printf("### WARNING: CglRedSplit2Param::addRowSelectionStrategyLAP(): value: %d ignored\n", value);
+  }
+} /* addRowSelectionStrategyLAP */
+
+/***********************************************************************/
+
+void CglRedSplit2Param::setTimeLimit(double value)
+{
+  if (value >= 0.0){
+    timeLimit_ = value;
+  }
+  else {
+    timeLimit_ = 0.0;
+  }
+} /* setTimeLimit */
+
+/***********************************************************************/
+
+void CglRedSplit2Param::setMaxNumCuts(int value)
+{
+  if (value >= 0){
+    maxNumCuts_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::maxNumCuts(): value: %d ignored\n",
+	   value);
+  }
+} /* setMaxNumCuts */
+
+/***********************************************************************/
+
+void CglRedSplit2Param::setMaxNumComputedCuts(int value)
+{
+  if (value >= 0){
+    maxNumComputedCuts_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::maxNumComputedCuts(): value: %d ignored\n",
+	   value);
+  }
+} /* setMaxNumComputedCuts */
+
+/***********************************************************************/
+
+void CglRedSplit2Param::setMaxNonzeroesTab(int value)
+{
+  if (value >= 0){
+    maxNonzeroesTab_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::maxNonzeroesTab(): value: %d ignored\n",
+	   value);
+  }
+} /* setMaxNumComputedCuts */
+
+/***********************************************************************/
+
+void CglRedSplit2Param::setColumnScalingStrategyLAP(ColumnScalingStrategy value)
+{
+  columnScalingStrategyLAP_ = value;
+} /* setColumnScalingStrategyLAP */
+
+/***********************************************************************/
+
+void CglRedSplit2Param::setColumnScalingBoundLAP(double value)
+{
+  if (value >= 0){
+    columnScalingBoundLAP_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit2Param::columnScalingBoundLAP(): value: %f ignored\n",
+	   value);
+  }
+} /* setColumnScalingBoundLAP */
+
+/***********************************************************************/
+
+void CglRedSplit2Param::setSkipGomory(int value)
+{
+  if (value >= 0 && value <= 1){
+    skipGomory_ = value;
+  }
+  else{
+    printf("### WARNING: CglRedSplit2Param::skipGomory(): value: %d ignored\n",
+	   value);
+  }
+}
+
+/***********************************************************************/
+CglRedSplit2Param::CglRedSplit2Param(bool use_default_strategies,
+				     double eps,
+				     double eps_coeff,
+				     double eps_elim,
+				     double eps_relax_abs,
+				     double eps_relax_rel,
+				     double max_dyn,
+				     double min_viol,
+				     int max_supp_abs,
+				     double max_supp_rel,
+				     int use_int_slacks,
+				     double norm_zero,
+				     double minNormReduction,
+				     int maxSumMultipliers,
+				     double normalization,
+				     double away,
+				     double timeLimit,
+				     int maxNumCuts,
+				     int maxNumComputedCuts,
+				     int maxNonzeroesTab,
+				     double columnScalingBoundLAP,
+				     int skipGomory) :
+  CglParam(COIN_DBL_MAX, eps, eps_coeff, max_supp_abs),
+  EPS_ELIM(eps_elim),
+  EPS_RELAX_ABS(eps_relax_abs),
+  EPS_RELAX_REL(eps_relax_rel),
+  MAXDYN(max_dyn),
+  MINVIOL(min_viol),
+  MAX_SUPP_REL(max_supp_rel),
+  USE_INTSLACKS(use_int_slacks),
+  normIsZero_(norm_zero),
+  minNormReduction_(minNormReduction),
+  maxSumMultipliers_(maxSumMultipliers),
+  normalization_(normalization),
+  away_(away),
+  columnScalingBoundLAP_(columnScalingBoundLAP),
+  timeLimit_(timeLimit),
+  maxNumCuts_(maxNumCuts),
+  maxNumComputedCuts_(maxNumComputedCuts),
+  maxNonzeroesTab_(maxNonzeroesTab),
+  skipGomory_(skipGomory)
+{
+  if (use_default_strategies) {
+    addNumRowsReduction(5);
+    addColumnSelectionStrategy(CglRedSplit2Param::CS_BEST);
+    addRowSelectionStrategy(CglRedSplit2Param::RS_BEST);
+    addNumRowsReductionLAP(3);
+    addColumnSelectionStrategyLAP(CglRedSplit2Param::CS1);
+    addRowSelectionStrategyLAP(CglRedSplit2Param::RS8);
+    setColumnScalingStrategyLAP(CglRedSplit2Param::SC_UNIFORM_NZ);
+  }
+}
+
+/***********************************************************************/
+CglRedSplit2Param::CglRedSplit2Param(const CglParam &source,
+				     bool use_default_strategies,
+				     double eps_elim, 
+				     double eps_relax_abs, 
+				     double eps_relax_rel, 
+				     double max_dyn,
+				     double min_viol,
+				     double max_supp_rel,
+				     int use_int_slacks,
+				     double norm_zero,
+				     double minNormReduction,
+				     int maxSumMultipliers,
+				     double normalization,
+				     double away,
+				     double timeLimit,
+				     int maxNumCuts,
+				     int maxNumComputedCuts,
+				     int maxNonzeroesTab,
+				     double columnScalingBoundLAP,
+				     int skipGomory) :
+  CglParam(source),
+  EPS_ELIM(eps_elim),
+  EPS_RELAX_ABS(eps_relax_abs),
+  EPS_RELAX_REL(eps_relax_rel),
+  MAXDYN(max_dyn),
+  MINVIOL(min_viol),
+  MAX_SUPP_REL(max_supp_rel),
+  USE_INTSLACKS(use_int_slacks),
+  normIsZero_(norm_zero),
+  minNormReduction_(minNormReduction),
+  maxSumMultipliers_(maxSumMultipliers),
+  normalization_(normalization),
+  away_(away),
+  columnScalingBoundLAP_(columnScalingBoundLAP),
+  timeLimit_(timeLimit),
+  maxNumCuts_(maxNumCuts),
+  maxNumComputedCuts_(maxNumComputedCuts),
+  maxNonzeroesTab_(maxNonzeroesTab),
+  skipGomory_(skipGomory)
+{
+  if (use_default_strategies) {
+    addNumRowsReduction(5);
+    addColumnSelectionStrategy(CglRedSplit2Param::CS_BEST);
+    addRowSelectionStrategy(CglRedSplit2Param::RS_BEST);
+    addNumRowsReductionLAP(3);
+    addColumnSelectionStrategyLAP(CglRedSplit2Param::CS1);
+    addRowSelectionStrategyLAP(CglRedSplit2Param::RS8);
+    setColumnScalingStrategyLAP(CglRedSplit2Param::SC_UNIFORM_NZ);
+  }
+}
+
+/***********************************************************************/
+CglRedSplit2Param::CglRedSplit2Param(const CglRedSplit2Param &source) :
+  CglParam(source),
+  EPS_ELIM(source.EPS_ELIM),
+  EPS_RELAX_ABS(source.EPS_RELAX_ABS),
+  EPS_RELAX_REL(source.EPS_RELAX_REL),
+  MAXDYN(source.MAXDYN),
+  MINVIOL(source.MINVIOL),
+  MAX_SUPP_REL(source.MAX_SUPP_REL),
+  USE_INTSLACKS(source.USE_INTSLACKS),
+  normIsZero_(source.normIsZero_),
+  minNormReduction_(source.minNormReduction_),
+  maxSumMultipliers_(source.maxSumMultipliers_),
+  normalization_(source.normalization_),
+  away_(source.away_),
+  numRowsReduction_(source.numRowsReduction_),
+  columnSelectionStrategy_(source.columnSelectionStrategy_),
+  rowSelectionStrategy_(source.rowSelectionStrategy_),
+  numRowsReductionLAP_(source.numRowsReductionLAP_),
+  columnSelectionStrategyLAP_(source.columnSelectionStrategyLAP_),
+  rowSelectionStrategyLAP_(source.rowSelectionStrategyLAP_),
+  columnScalingStrategyLAP_(source.columnScalingStrategyLAP_),
+  columnScalingBoundLAP_(source.columnScalingBoundLAP_),
+  timeLimit_(source.timeLimit_),
+  maxNumCuts_(source.maxNumCuts_),
+  maxNumComputedCuts_(source.maxNumComputedCuts_),
+  maxNonzeroesTab_(source.maxNonzeroesTab_),
+  skipGomory_(source.skipGomory_)
+{}
+
+/***********************************************************************/
+CglRedSplit2Param* CglRedSplit2Param::clone() const
+{
+  return new CglRedSplit2Param(*this);
+}
+
+/***********************************************************************/
+CglRedSplit2Param& CglRedSplit2Param::operator=(const CglRedSplit2Param &rhs)
+{
+  if(this != &rhs) {
+    CglParam::operator=(rhs);
+
+    EPS_ELIM = rhs.EPS_ELIM;
+    EPS_RELAX_ABS = rhs.EPS_RELAX_ABS;
+    EPS_RELAX_REL = rhs.EPS_RELAX_REL;
+    MAXDYN = rhs.MAXDYN;
+    MINVIOL = rhs.MINVIOL;
+    MAX_SUPP_REL = rhs.MAX_SUPP_REL;
+    USE_INTSLACKS = rhs.USE_INTSLACKS;
+    normIsZero_ = rhs.normIsZero_;
+    minNormReduction_ = rhs.minNormReduction_;
+    maxSumMultipliers_ = rhs.maxSumMultipliers_;
+    normalization_ = rhs.normalization_;
+    away_ = rhs.away_;
+    numRowsReduction_ = rhs.numRowsReduction_;
+    columnSelectionStrategy_ = rhs.columnSelectionStrategy_;
+    rowSelectionStrategy_ = rhs.rowSelectionStrategy_;
+    numRowsReductionLAP_ = rhs.numRowsReductionLAP_;
+    columnSelectionStrategyLAP_ = rhs.columnSelectionStrategyLAP_;
+    rowSelectionStrategyLAP_ = rhs.rowSelectionStrategyLAP_;
+    columnScalingStrategyLAP_ = rhs.columnScalingStrategyLAP_;
+    columnScalingBoundLAP_ = rhs.columnScalingBoundLAP_;
+    timeLimit_ = rhs.timeLimit_;
+    maxNumCuts_ = rhs.maxNumCuts_;
+    maxNumComputedCuts_ = rhs.maxNumComputedCuts_;
+    maxNonzeroesTab_ = rhs.maxNonzeroesTab_;
+    skipGomory_ = rhs.skipGomory_;
+  }
+  return *this;
+}
+
+/***********************************************************************/
+CglRedSplit2Param::~CglRedSplit2Param()
+{}
diff --git a/cbits/coin/CglRedSplit2Param.hpp b/cbits/coin/CglRedSplit2Param.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglRedSplit2Param.hpp
@@ -0,0 +1,495 @@
+// Name:     CglRedSplit2Param.hpp
+// Author:   Giacomo Nannicini
+//           Singapore University of Technology and Design
+//           Singapore
+//           email: nannicini@sutd.edu.sg
+// Date:     03/09/09
+//-----------------------------------------------------------------------------
+// Copyright (C) 2010, Giacomo Nannicini and others.  All Rights Reserved.
+
+#ifndef CglRedSplit2Param_H
+#define CglRedSplit2Param_H
+
+#include "CglParam.hpp"
+#include <vector>
+
+  /**@name CglRedSplit2 Parameters */
+  //@{
+
+  /** Class collecting parameters the Reduced-and-split cut generator.
+
+      An important thing to note is that the cut generator allows for
+      the selection of a number of strategies that can be combined
+      together. By default, a selection that typically yields a good
+      compromise between speed and cut strenght is made. The selection
+      can be changed by resetting the default choices (see the
+      functions whose name starts with "reset") or by setting the
+      parameter use_default_strategies to false in the
+      constructors. After this, the chosen strategies can be added to
+      the list by using the functions whose name starts with
+      "add". All strategies will be combined together: if we choose 3
+      row selection strategies, 2 column selection strategies, and 2
+      possible numbers of rows, we end up with a total of 3*2*2
+      combinations.
+
+      For a detailed explanation of the parameters and their meaning,
+      see the paper by Cornuejols and Nannicini: "Practical strategies
+      for generating rank-1 split cuts in mixed-integer linear
+      programming", on Mathematical Programming Computation.
+
+      Parameters of the generator are listed below. 
+
+      - MAXDYN: Maximum ratio between largest and smallest non zero 
+                coefficients in a cut. See method setMAXDYN().
+      - EPS_ELIM: Precision for deciding if a coefficient is zero when 
+                  eliminating slack variables. See method setEPS_ELIM().
+      - MINVIOL: Minimum violation for the current basic solution in 
+                 a generated cut. See method setMINVIOL().
+      - EPS_RELAX_ABS: Absolute relaxation of cut rhs.
+      - EPS_RELAX_REL: Relative relaxation of cut rhs.
+      - MAX_SUPP_ABS: Maximum cut support (absolute).
+      - MAX_SUPP_REL: Maximum cut support (relative): the formula to 
+                      compute maximum cut support is 
+		      MAX_SUPP_ABS + ncol*MAX_SUPP_REL.
+      - USE_INTSLACKS: Use integer slacks to generate cuts. (not implemented).
+                       See method setUSE_INTSLACKS().
+      - normIsZero: Norm of a vector is considered zero if smaller than
+                    this value. See method setNormIsZero(). 
+      - minNormReduction: a cut is generated if the new norm of the row on the
+                          continuous nonbasics is reduced by at least
+			  this factor (relative reduction).
+      - away: Look only at basic integer variables whose current value
+              is at least this value from being integer. See method setAway().
+      - maxSumMultipliers: maximum sum (in absolute value) of row multipliers
+      - normalization: normalization factor for the norm of lambda in the
+                       coefficient reduction algorithm (convex min problem)
+      - numRowsReduction: Maximum number of rows in the linear system for
+                          norm reduction.
+      - columnSelectionStrategy: parameter to select which columns should be
+                                 used for coefficient reduction.
+      - rowSelectionStrategy: parameter to select which rows should be
+                              used for coefficient reduction.
+      - timeLimit: Time limit (in seconds) for cut generation.
+      - maxNumCuts: Maximum number of cuts that can be returned at each pass;
+                    we could generate more cuts than this number (see below)
+      - maxNumComputedCuts: Maximum number of cuts that can be computed
+                            by the generator at each pass
+      - maxNonzeroesTab : Rows of the simplex tableau with more than
+                          this number of nonzeroes will not be
+                          considered for reduction. Only works if
+                          RS_FAST_* are defined in CglRedSplit2.
+      - skipGomory: Skip traditional Gomory cuts, i.e. GMI cuts arising from
+                    a single row of the tableau (instead of a combination).
+                    Default is 1 (true), because we assume that they are 
+		    generated by a traditional Gomory generator anyway. 
+  */
+  //@}
+
+class CglRedSplit2Param : public CglParam {
+
+public:
+  /** Enumerations for parameters */
+
+  /** Row selection strategies; same names as in the paper */
+  enum RowSelectionStrategy{
+    /* Pick rows that introduce the fewest nonzeroes on integer nonbasics */
+    RS1, 
+    /* Pick rows that introduce the fewest nonzeroes on the set of working
+       continuous nonbasics */
+    RS2,
+    /* Pick rows that introduce the fewest nonzeroes on both integer and
+       working continuous nonbasics */
+    RS3,
+    /* Same as RS0 but with greedy algorithm */
+    RS4,
+    /* Same as RS1 but with greedy algorithm */
+    RS5,
+    /* Same as RS2 but with greedy algorithm */
+    RS6,
+    /* Pick rows with smallest angle in the space of integer and working
+       continuous nonbasics */
+    RS7,
+    /* Pick rows with smallest angle in the space of working
+       continuous nonbasics */
+    RS8,
+    /* Use all strategies */
+    RS_ALL,
+    /* Use best ones - that is, RS8 and RS7 */
+    RS_BEST
+  };
+
+  /** Column selection strategies; again, look them up in the paper. */
+  enum ColumnSelectionStrategy{
+    /* C-3P */
+    CS1, CS2, CS3,
+    /* C-5P */
+    CS4, CS5, CS6, CS7, CS8,
+    /* I-2P-2/3 */
+    CS9, CS10,
+    /* I-2P-4/5 */
+    CS11, CS12,
+    /* I-2P-1/2 */
+    CS13, CS14,
+    /* I-3P */
+    CS15, CS16, CS17,
+    /* I-4P */
+    CS18, CS19, CS20, CS21,
+    /* Use all strategies up to this point */
+    CS_ALL,
+    /* Use best strategies (same effect as CS_ALL, because it turns out that
+       using all strategies is the best thing to do) */
+    CS_BEST,
+    /* Optimize over all continuous nonbasic columns; this does not give
+       good results, but we use it for testing Lift & Project + RedSplit */
+    CS_ALLCONT,
+    /* Lift & Project specific strategy: only select variables which
+       are nonbasic in the tableau but are basic in the point to cut
+       off.  This strategy cannot be used outside L&P. It is not very
+       effective even with L&P, but is left here for testing.*/
+    CS_LAP_NONBASICS
+  };
+
+  /** Scaling strategies for new nonbasic columns for Lift & Project;
+   *  "factor" is the value of columnScalingBoundLAP_ */
+  enum ColumnScalingStrategy{
+    /* No scaling */
+    SC_NONE,
+    /* Multiply by |xbar[i]| where xbar[i] is the value of the 
+       corresponding component of the point that we want to cut off */
+    SC_LINEAR,
+    /* Multiply by min(factor,|xbar[i]|) */
+    SC_LINEAR_BOUNDED,
+    /* Multiply by min(factor,log(|xbar[i]|)) */
+    SC_LOG_BOUNDED,
+    /* Multiply all new nonbasics by factor */
+    SC_UNIFORM,
+    /* Multiply only nonzero coefficients by factor */
+    SC_UNIFORM_NZ
+  };
+
+  /**@name Set/get methods */
+  //@{
+  /** Set away, the minimum distance from being integer used for selecting 
+      rows for cut generation;  all rows whose pivot variable should be 
+      integer but is more than away from integrality will be selected; 
+      Default: 0.005 */
+  virtual void setAway(double value);
+  /// Get value of away
+  inline double getAway() const {return away_;}
+
+  /** Set the value of EPS_ELIM, epsilon for values of coefficients when 
+      eliminating slack variables;
+      Default: 0.0 */
+  void setEPS_ELIM(double value);
+  /** Get the value of EPS_ELIM */
+  double getEPS_ELIM() const {return EPS_ELIM;}
+  
+  /** Set EPS_RELAX_ABS */
+  virtual void setEPS_RELAX_ABS(double eps_ra);
+  /** Get value of EPS_RELAX_ABS */
+  inline double getEPS_RELAX_ABS() const {return EPS_RELAX_ABS;}
+
+  /** Set EPS_RELAX_REL */
+  virtual void setEPS_RELAX_REL(double eps_rr);
+  /** Get value of EPS_RELAX_REL */
+  inline double getEPS_RELAX_REL() const {return EPS_RELAX_REL;}
+
+  // Set the maximum ratio between largest and smallest non zero 
+  // coefficients in a cut. Default: 1e6.
+  virtual void setMAXDYN(double value);
+  /** Get the value of MAXDYN */
+  inline double getMAXDYN() const {return MAXDYN;}
+
+  /** Set the value of MINVIOL, the minimum violation for the current 
+      basic solution in a generated cut. Default: 1e-3 */
+  virtual void setMINVIOL(double value);
+  /** Get the value of MINVIOL */
+  inline double getMINVIOL() const {return MINVIOL;}
+
+  /** Maximum absolute support of the cutting planes. Default: INT_MAX.
+      Aliases for consistency with our naming scheme. */
+  inline void setMAX_SUPP_ABS(int value) {setMAX_SUPPORT(value);}
+  inline int getMAX_SUPP_ABS() const {return MAX_SUPPORT;}
+
+  /** Maximum relative support of the cutting planes. Default: 0.0.
+      The maximum support is MAX_SUPP_ABS + MAX_SUPPREL*ncols. */
+  inline void setMAX_SUPP_REL(double value); 
+  inline double getMAX_SUPP_REL() const {return MAX_SUPP_REL;}
+
+  /** Set the value of USE_INTSLACKS. Default: 0 */
+  virtual void setUSE_INTSLACKS(int value);
+  /** Get the value of USE_INTSLACKS */
+  inline int getUSE_INTSLACKS() const {return USE_INTSLACKS;}
+
+  /** Set the value of normIsZero, the threshold for considering a norm to be 
+      0; Default: 1e-5 */
+  virtual void setNormIsZero(double value);
+  /** Get the value of normIsZero */
+  inline double getNormIsZero() const {return normIsZero_;}
+
+  /** Set the value of minNormReduction; Default: 0.1 */
+  virtual void setMinNormReduction(double value);
+  /** Get the value of normIsZero */
+  inline double getMinNormReduction() const {return minNormReduction_;}
+
+  /** Set the value of maxSumMultipliers; Default: 10 */
+  virtual void setMaxSumMultipliers(int value);
+  /** Get the value of maxSumMultipliers */
+  inline int getMaxSumMultipliers() const {return maxSumMultipliers_;}
+
+  /** Set the value of normalization; Default: 0.0001 */
+  virtual void setNormalization(double value);
+  /** Get the value of normalization */
+  inline double getNormalization() const {return normalization_;}
+
+  /** Set the value of numRowsReduction, max number of rows that are used
+   *  for each row reduction step. In particular, the linear system will
+   *  involve a numRowsReduction*numRowsReduction matrix */
+  virtual void addNumRowsReduction(int value);
+  /// get the value
+  inline std::vector<int> getNumRowsReduction() const {return numRowsReduction_;}
+  /// reset
+  inline void resetNumRowsReduction() {numRowsReduction_.clear();}
+
+  /** Add the value of columnSelectionStrategy */
+  virtual void addColumnSelectionStrategy(ColumnSelectionStrategy value);
+  /// get the value
+  inline std::vector<ColumnSelectionStrategy> getColumnSelectionStrategy() const {return columnSelectionStrategy_;}
+  /// reset
+  inline void resetColumnSelectionStrategy(){columnSelectionStrategy_.clear();}
+
+  /** Set the value for rowSelectionStrategy, which changes the way we choose
+   *  the rows for the reduction step */
+  virtual void addRowSelectionStrategy(RowSelectionStrategy value);
+  /// get the value
+  inline std::vector<RowSelectionStrategy> getRowSelectionStrategy() const {return rowSelectionStrategy_;};
+  /// reset
+  inline void resetRowSelectionStrategy() {rowSelectionStrategy_.clear();}
+
+  /** Set the value of numRowsReductionLAP, max number of rows that are used
+   *  for each row reduction step during Lift & Project. 
+   *  In particular, the linear system will involve a 
+   *  numRowsReduction*numRowsReduction matrix */
+  virtual void addNumRowsReductionLAP(int value);
+  /// get the value
+  inline std::vector<int> getNumRowsReductionLAP() const {return numRowsReductionLAP_;}
+  /// reset
+  inline void resetNumRowsReductionLAP() {numRowsReductionLAP_.clear();}
+
+  /** Add the value of columnSelectionStrategyLAP */
+  virtual void addColumnSelectionStrategyLAP(ColumnSelectionStrategy value);
+  /// get the value
+  inline std::vector<ColumnSelectionStrategy> getColumnSelectionStrategyLAP() const {return columnSelectionStrategyLAP_;}
+  /// reset
+  inline void resetColumnSelectionStrategyLAP(){columnSelectionStrategyLAP_.clear();}
+
+  /** Set the value for rowSelectionStrategyLAP, which changes the way we 
+   *  choose the rows for the reduction step */
+  virtual void addRowSelectionStrategyLAP(RowSelectionStrategy value);
+  /// get the value
+  inline std::vector<RowSelectionStrategy> getRowSelectionStrategyLAP() const {return rowSelectionStrategyLAP_;};
+  /// reset
+  inline void resetRowSelectionStrategyLAP() {rowSelectionStrategyLAP_.clear();}
+
+  /** Set the value for columnScalingStrategyLAP, which sets the way nonbasic
+   *  columns that are basic in the fractional point to cut off are scaled */
+  virtual void setColumnScalingStrategyLAP(ColumnScalingStrategy value);
+  /// get the value
+  inline ColumnScalingStrategy getColumnScalingStrategyLAP() const {return columnScalingStrategyLAP_; };
+
+  /** Set the value for the bound in the column scaling factor */
+  virtual void setColumnScalingBoundLAP(double value);
+  /// get the value
+  inline double getColumnScalingBoundLAP() const {return columnScalingBoundLAP_;};
+
+  /** Set the value of the time limit for cut generation (in seconds) */
+  virtual void setTimeLimit(double value);
+  /// get the value
+  inline double getTimeLimit() const {return timeLimit_;}
+
+  /** Set the value for the maximum number of cuts that can be returned */
+  virtual void setMaxNumCuts(int value);
+  /// get the value
+  inline int getMaxNumCuts() const {return maxNumCuts_;}
+
+  /** Set the value for the maximum number of cuts that can be computed */
+  virtual void setMaxNumComputedCuts(int value);
+  /// get the value
+  inline int getMaxNumComputedCuts() const {return maxNumComputedCuts_;}
+
+  /** Set the value for the maximum number of nonzeroes in a row of
+   * the simplex tableau for the row to be considered */
+  virtual void setMaxNonzeroesTab(int value);
+  /// get the value
+  inline int getMaxNonzeroesTab() const {return maxNonzeroesTab_;}
+
+  /** Set the value of skipGomory: should we skip simple Gomory cuts,
+   *  i.e. GMI cuts derived from a single row of the simple tableau?
+   *  This is 1 (true) by default: we only generate cuts from linear
+   *  combinations of at least two rows. */
+  virtual void setSkipGomory(int value);
+  /// get the value
+  inline int getSkipGomory() const {return skipGomory_;}
+
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor. If use_default_strategies is true, we add
+  /// to the list of strategies the default ones. If is false, the
+  /// list of strategies is left empty (must be populated before usage!).
+  CglRedSplit2Param(bool use_default_strategies = true,
+		    double eps = 1e-12,
+		    double eps_coeff = 1e-11,
+		    double eps_elim = 0.0,
+		    double eps_relax_abs = 1e-11,
+		    double eps_relax_rel = 1e-13,
+		    double max_dyn = 1e6,
+		    double min_viol = 1e-3,
+		    int max_supp_abs = 1000,
+		    double max_supp_rel = 0.1,
+		    int use_int_slacks = 0,
+		    double norm_zero = 1e-5,
+		    double minNormReduction = 0.1,
+		    int maxSumMultipliers = 10,
+		    double normalization = 0.0001,
+		    double away = 0.005,
+		    double timeLimit = 60,
+		    int maxNumCuts = 10000,
+		    int maxNumComputedCuts = 10000,
+		    int maxNonzeroesTab = 1000,
+		    double columnScalingBoundLAP = 5.0,
+		    int skipGomory = 1);
+
+  /// Constructor from CglParam. If use_default_strategies is true, we
+  /// add to the list of strategies the default ones. If is false, the
+  /// list of strategies is left empty (must be populated before
+  /// usage!).
+  CglRedSplit2Param(const CglParam &source,
+		    bool use_default_strategies = true,
+		    double eps_elim = 0.0,
+		    double eps_relax_abs = 1e-11,
+		    double eps_relax_rel = 1e-13,
+		    double max_dyn = 1e6,
+		    double min_viol = 1e-3,
+		    double max_supp_rel = 0.1,
+		    int use_int_slacks = 0,
+		    double norm_zero = 1e-5,
+		    double minNormReduction = 0.1,
+		    int maxSumMultipliers = 10,
+		    double normalization = 0.0001,
+		    double away = 0.005,
+		    double timeLimit = 60,
+		    int maxNumCuts = 10000,
+		    int maxNumComputedCuts = 10000,
+		    int maxNonzeroesTab = 1000,
+		    double columnScalingBoundLAP = 5.0,
+		    int skipGomory = 1);
+
+  /// Copy constructor 
+  CglRedSplit2Param(const CglRedSplit2Param &source);
+
+  /// Clone
+  virtual CglRedSplit2Param* clone() const;
+
+  /// Assignment operator 
+  virtual CglRedSplit2Param& operator=(const CglRedSplit2Param &rhs);
+
+  /// Destructor 
+  virtual ~CglRedSplit2Param();
+  //@}
+
+protected:
+
+  /**@name Parameters */
+  //@{
+
+  /** Epsilon for value of coefficients when eliminating slack variables. 
+      Default: 0.0. */
+  double EPS_ELIM;
+
+  /** Value added to the right hand side of each generated cut to relax it.
+      Default: 1e-11 */
+  double EPS_RELAX_ABS;
+
+  /** For a generated cut with right hand side rhs_val, 
+      EPS_RELAX_EPS * fabs(rhs_val) is used to relax the constraint.
+      Default: 1e-13 */
+  double EPS_RELAX_REL;
+
+  // Maximum ratio between largest and smallest non zero 
+  // coefficients in a cut. Default: 1e6.
+  double MAXDYN;
+
+  /// Minimum violation for the current basic solution in a generated cut.
+  /// Default: 1e-3.
+  double MINVIOL;
+
+  /// Maximum support - relative part of the formula
+  double MAX_SUPP_REL;
+
+  /// Use integer slacks to generate cuts if USE_INTSLACKS = 1. Default: 0.
+  int USE_INTSLACKS;
+
+  /// Norm of a vector is considered zero if smaller than normIsZero;
+  /// Default: 1e-5.
+  double normIsZero_;
+
+  /// Minimum reduction to accept a new row.
+  double minNormReduction_;
+
+  /// Maximum sum of the vector of row multipliers to generate a cut
+  int maxSumMultipliers_;
+
+  /// Normalization factor for the norm of lambda in the quadratic
+  /// minimization problem that is solved during the coefficient reduction step
+  double normalization_;
+
+  /// Use row only if pivot variable should be integer but is more 
+  /// than away_ from being integer. Default: 0.005
+  double away_;
+  
+  /// Maximum number of rows to use for the reduction of a given row.
+  std::vector<int> numRowsReduction_;
+
+  /// Column selection method
+  std::vector<ColumnSelectionStrategy> columnSelectionStrategy_;
+
+  /// Row selection method
+  std::vector<RowSelectionStrategy> rowSelectionStrategy_;
+
+  /// Maximum number of rows to use for the reduction during Lift & Project
+  std::vector<int> numRowsReductionLAP_;
+
+  /// Column selection method for Lift & Project
+  std::vector<ColumnSelectionStrategy> columnSelectionStrategyLAP_;
+
+  /// Row selection method for Lift & Project
+  std::vector<RowSelectionStrategy> rowSelectionStrategyLAP_;
+
+  /// Column scaling strategy for the nonbasics columns that were basic in
+  /// the point that we want to cut off (Lift & Project only)
+  ColumnScalingStrategy columnScalingStrategyLAP_;
+
+  /// Minimum value for column scaling (Lift & Project only)
+  double columnScalingBoundLAP_;
+
+  /// Time limit
+  double timeLimit_;
+
+  /// Maximum number of returned cuts
+  int maxNumCuts_;
+
+  /// Maximum number of computed cuts
+  int maxNumComputedCuts_;
+
+  /// Maximum number of nonzeroes in tableau row for reduction
+  int maxNonzeroesTab_;
+
+  /// Skip simple Gomory cuts
+  int skipGomory_;
+
+  //@}
+};
+
+#endif
diff --git a/cbits/coin/CglRedSplitParam.cpp b/cbits/coin/CglRedSplitParam.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglRedSplitParam.cpp
@@ -0,0 +1,274 @@
+// Name:     CglRedSplitParam.cpp
+// Author:   Francois Margot                                                  
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     11/24/06
+//
+// $Id: CglRedSplitParam.cpp 1123 2013-04-06 20:47:24Z stefan $
+//---------------------------------------------------------------------------
+// Copyright (C) 2006, Francois Margot and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CglRedSplitParam.hpp"
+
+/***********************************************************************/
+void CglRedSplitParam::setAway(const double value)
+{
+  if (value > 0.0 && value <= 0.5)
+    away_ = value;
+}
+
+/***********************************************************************/
+void CglRedSplitParam::setMaxTab(const double value)
+{
+  if (value > 10) {
+    maxTab_ = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplitParam::setMaxTab(): value: %f ignored\n", 
+	   value);
+  }
+}
+
+/***********************************************************************/
+void CglRedSplitParam::setLUB(const double value)
+{
+  if (value > 0.0) {
+    LUB = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplitParam::setLUB(): value: %f ignored\n", value);
+  }
+} /* setLUB */
+
+/***********************************************************************/
+void CglRedSplitParam::setEPS_ELIM(const double eps_el)
+{
+  if(eps_el >= 0)
+    EPS_ELIM = eps_el;
+} /* setEPS_ELIM */
+
+/***********************************************************************/
+void CglRedSplitParam::setEPS_RELAX_ABS(const double eps_ra)
+{
+  if(eps_ra >= 0)
+    EPS_RELAX_ABS = eps_ra;
+} /* setEPS_RELAX_ABS */
+
+/***********************************************************************/
+void CglRedSplitParam::setEPS_RELAX_REL(const double eps_rr)
+{
+  if(eps_rr >= 0)
+    EPS_RELAX_REL = eps_rr;
+} /* setEPS_RELAX_REL */
+
+/***********************************************************************/
+void CglRedSplitParam::setMAXDYN(double value)
+{
+    if (value > 1.0) {
+    MAXDYN = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setMAXDYN(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMAXDYN */
+
+/***********************************************************************/
+void CglRedSplitParam::setMAXDYN_LUB(double value)
+{
+  if (value > 1.0) {
+    MAXDYN_LUB = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplit::setMAXDYN_LUB(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMAXDYN_LUB */
+
+/***********************************************************************/
+void CglRedSplitParam::setEPS_COEFF_LUB(const double value)
+{
+  if (value > 0.0 && value <= 0.1) {
+    EPS_COEFF_LUB = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplitParam::setEPS_COEFF_LUB(): value: %f ignored\n", 
+	   value);
+  }
+} /* setEPS_COEFF_LUB */
+
+/***********************************************************************/
+void CglRedSplitParam::setMINVIOL(double value)
+{
+  if (value > 0.0 && value <= 0.1) {
+    MINVIOL = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplitParam::setMINVIOL(): value: %f ignored\n", 
+	   value);
+  }
+} /* setMINVIOL */
+
+/***********************************************************************/
+void CglRedSplitParam::setUSE_INTSLACKS(int value)
+{
+  USE_INTSLACKS = value;
+} /* setUSE_INTSLACKS */
+
+/***********************************************************************/
+void CglRedSplitParam::setUSE_CG2(int value)
+{
+  USE_CG2 = value;
+} /* setUSE_CG2 */
+
+/***********************************************************************/
+void CglRedSplitParam::setNormIsZero(const double value)
+{
+  if (value > 0.0 && value <= 1) {
+    normIsZero = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplitParam::setNormIsZero(): value: %f ignored\n",
+	   value);
+  }
+} /* setNormIsZero */
+
+/***********************************************************************/
+void CglRedSplitParam::setMinReduc(const double value)
+{
+  if (value > 0.0 && value <= 1) {
+    minReduc = value;
+  }
+  else {
+    printf("### WARNING: CglRedSplitParam::MinReduc(): value: %f ignored\n",
+	   value);
+  }
+} /* setMinReduc */
+
+/***********************************************************************/
+CglRedSplitParam::CglRedSplitParam(const double lub,
+				   const double eps_el,
+				   const double eps_relax_abs,
+				   const double eps_relax_rel,
+				   const double max_dyn,
+				   const double max_dyn_lub,
+				   const double eps_coeff_lub,
+				   const double min_viol,
+				   const int use_int_slacks,
+				   const int use_cg2,
+				   const double norm_zero,
+				   const double min_reduc,
+				   const double away,
+				   const double max_tab) :
+  CglParam(),
+  LUB(lub),
+  EPS_ELIM(eps_el),
+  EPS_RELAX_ABS(eps_relax_abs),
+  EPS_RELAX_REL(eps_relax_rel),
+  MAXDYN(max_dyn),
+  MAXDYN_LUB(max_dyn_lub),
+  EPS_COEFF_LUB(eps_coeff_lub),
+  MINVIOL(min_viol),
+  USE_INTSLACKS(use_int_slacks),
+  USE_CG2(use_cg2),
+  normIsZero(norm_zero),
+  minReduc(min_reduc),
+  away_(away),
+  maxTab_(max_tab)
+{}
+
+/***********************************************************************/
+CglRedSplitParam::CglRedSplitParam(const CglParam &source,
+				   const double lub,
+				   const double eps_el, 
+				   const double eps_ra, 
+				   const double eps_rr, 
+				   const double max_dyn,
+				   const double max_dyn_lub,
+				   const double eps_coeff_lub,
+				   const double min_viol,
+				   const int use_int_slacks,
+				   const int use_cg2,
+				   const double norm_zero,
+				   const double min_reduc,
+				   const double away,
+				   const double max_tab) :
+
+  CglParam(source), 
+  LUB(lub),
+  EPS_ELIM(eps_el),
+  EPS_RELAX_ABS(eps_ra),
+  EPS_RELAX_REL(eps_rr),
+  MAXDYN(max_dyn),
+  MAXDYN_LUB(max_dyn_lub),
+  EPS_COEFF_LUB(eps_coeff_lub),
+  MINVIOL(min_viol),
+  USE_INTSLACKS(use_int_slacks),
+  USE_CG2(use_cg2),
+  normIsZero(norm_zero),
+  minReduc(min_reduc),
+  away_(away),
+  maxTab_(max_tab)
+{}
+
+/***********************************************************************/
+CglRedSplitParam::CglRedSplitParam(const CglRedSplitParam &source) :
+  CglParam(source),
+  LUB(source.LUB),
+  EPS_ELIM(source.EPS_ELIM),
+  EPS_RELAX_ABS(source.EPS_RELAX_ABS),
+  EPS_RELAX_REL(source.EPS_RELAX_REL),
+  MAXDYN(source.MAXDYN),
+  MAXDYN_LUB(source.MAXDYN_LUB),
+  EPS_COEFF_LUB(source.EPS_COEFF_LUB),
+  MINVIOL(source.MINVIOL),
+  USE_INTSLACKS(source.USE_INTSLACKS),
+  USE_CG2(source.USE_CG2),
+  normIsZero(source.normIsZero),
+  minReduc(source.minReduc),
+  away_(source.away_),
+  maxTab_(source.maxTab_)
+{}
+
+/***********************************************************************/
+CglRedSplitParam* CglRedSplitParam::clone() const
+{
+  return new CglRedSplitParam(*this);
+}
+
+/***********************************************************************/
+CglRedSplitParam& CglRedSplitParam::operator=(const CglRedSplitParam &rhs)
+{
+  if(this != &rhs) {
+    CglParam::operator=(rhs);
+
+    LUB = rhs.LUB;
+    EPS_ELIM = rhs.EPS_ELIM;
+    EPS_RELAX_ABS = rhs.EPS_RELAX_ABS;
+    EPS_RELAX_REL = rhs.EPS_RELAX_REL;
+    MAXDYN = rhs.MAXDYN;
+    MAXDYN_LUB = rhs.MAXDYN_LUB;
+    EPS_COEFF_LUB = rhs.EPS_COEFF_LUB;
+    MINVIOL = rhs.MINVIOL;
+    USE_INTSLACKS = rhs.USE_INTSLACKS;
+    USE_CG2 = rhs.USE_CG2;
+    normIsZero = rhs.normIsZero;
+    minReduc = rhs.minReduc;
+    away_ = rhs.away_;
+    maxTab_ = rhs.maxTab_;
+  }
+  return *this;
+}
+
+/***********************************************************************/
+CglRedSplitParam::~CglRedSplitParam()
+{}
diff --git a/cbits/coin/CglRedSplitParam.hpp b/cbits/coin/CglRedSplitParam.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglRedSplitParam.hpp
@@ -0,0 +1,272 @@
+// Name:     CglRedSplitParam.hpp
+// Author:   Francois Margot
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+//           email: fmargot@andrew.cmu.edu
+// Date:     11/24/06
+//
+// $Id: CglRedSplitParam.hpp 1123 2013-04-06 20:47:24Z stefan $
+//-----------------------------------------------------------------------------
+// Copyright (C) 2006, Francois Margot and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglRedSplitParam_H
+#define CglRedSplitParam_H
+
+#include "CglParam.hpp"
+
+
+  /**@name CglRedSplit Parameters */
+  //@{
+
+  /** Class collecting parameters the Reduced-and-split cut generator.
+
+      Parameters of the generator are listed below. Modifying the default 
+      values for parameters other than the last four might result in 
+      invalid cuts.
+
+      - LUB: Value considered large for the absolute value of a lower or upper
+             bound on a variable. See method setLUB().
+      - MAXDYN: Maximum ratio between largest and smallest non zero 
+                coefficients in a cut. See method setMAXDYN().
+      - MAXDYN_LUB: Maximum ratio between largest and smallest non zero 
+                    coefficients in a cut involving structural variables with
+		    lower or upper bound in absolute value larger than LUB.
+                    Should logically be larger or equal to MAXDYN.
+                    See method setMAXDYN_LUB().
+      - EPS_ELIM: Precision for deciding if a coefficient is zero when 
+                  eliminating slack variables. See method setEPS_ELIM().
+      - EPS_COEFF_LUB: Precision for deciding if a coefficient of a 
+                       generated cut is zero when the corresponding 
+                       variable has a lower or upper bound larger than 
+                       LUB in absolute value. See method setEPS_COEFF_LUB().
+      - MINVIOL: Minimum violation for the current basic solution in 
+                 a generated cut. See method setMINVIOL().
+      - USE_INTSLACKS: Use integer slacks to generate cuts. (not implemented).
+                       See method setUSE_INTSLACKS().
+      - USE_CG2: Use alternative formula to generate a mixed integer Gomory
+                 cut (see methods CglRedSPlit::generate_cgcut() 
+                 and CglRedSPlit::generate_cgcut_2()). See method setUSE_CG2().
+      - normIsZero: Norm of a vector is considered zero if smaller than
+                    this value. See method setNormIsZero(). 
+      - minReduc: Reduction is performed only if the norm of the vector is
+                  reduced by this fraction. See method setMinReduc().
+      - away: Look only at basic integer variables whose current value
+              is at least this value from being integer. See method setAway().
+      - maxTab: Controls the number of rows selected for the generation. See
+                method setMaxTab().
+  */
+  //@}
+
+class CglRedSplitParam : public CglParam {
+
+public:
+
+  /**@name Set/get methods */
+  //@{
+  /** Set away, the minimum distance from being integer used for selecting 
+      rows for cut generation;  all rows whose pivot variable should be 
+      integer but is more than away from integrality will be selected; 
+      Default: 0.05 */
+  virtual void setAway(const double value);
+  /// Get value of away
+  inline double getAway() const {return away_;}
+
+ /** Set the value of LUB, value considered large for the absolute value of
+      a lower or upper bound on a variable;
+      Default: 1000 */
+  virtual void setLUB(const double value);
+  /** Get the value of LUB */
+  inline double getLUB() const {return LUB;}
+
+  /** Set the value of EPS_ELIM, epsilon for values of coefficients when 
+      eliminating slack variables;
+      Default: 1e-12 */
+  void setEPS_ELIM(const double value);
+  /** Get the value of EPS_ELIM */
+  double getEPS_ELIM() const {return EPS_ELIM;}
+  
+  /** Set EPS_RELAX_ABS */
+  virtual void setEPS_RELAX_ABS(const double eps_ra);
+  /** Get value of EPS_RELAX_ABS */
+  inline double getEPS_RELAX_ABS() const {return EPS_RELAX_ABS;}
+
+  /** Set EPS_RELAX_REL */
+  virtual void setEPS_RELAX_REL(const double eps_rr);
+  /** Get value of EPS_RELAX_REL */
+  inline double getEPS_RELAX_REL() const {return EPS_RELAX_REL;}
+
+  // Set the maximum ratio between largest and smallest non zero 
+  // coefficients in a cut. Default: 1e8.
+  virtual void setMAXDYN(double value);
+  /** Get the value of MAXDYN */
+  inline double getMAXDYN() const {return MAXDYN_LUB;}
+
+  // Set the maximum ratio between largest and smallest non zero 
+  // coefficient in a cut involving structural variables with
+  // lower or upper bound in absolute value larger than LUB.
+  // Should logically be larger or equal to MAXDYN. Default: 1e13.
+  virtual void setMAXDYN_LUB(double value);
+  /** Get the value of MAXDYN_LUB */
+  inline double getMAXDYN_LUB() const {return MAXDYN_LUB;}
+
+  /** Set the value of EPS_COEFF_LUB, epsilon for values of coefficients for 
+      variables with absolute value of lower or upper bound larger than LUB;
+      Default: 1e-13 */
+  virtual void setEPS_COEFF_LUB(const double value);
+  /** Get the value of EPS_COEFF_LUB */
+  inline double getEPS_COEFF_LUB() const {return EPS_COEFF_LUB;}
+
+  /** Set the value of MINVIOL, the minimum violation for the current 
+      basic solution in a generated cut. Default: 1e-7 */
+  virtual void setMINVIOL(double value);
+  /** Get the value of MINVIOL */
+  inline double getMINVIOL() const {return MINVIOL;}
+
+  /** Set the value of USE_INTSLACKS. Default: 0 */
+  virtual void setUSE_INTSLACKS(int value);
+  /** Get the value of USE_INTSLACKS */
+  inline int getUSE_INTSLACKS() const {return USE_INTSLACKS;}
+
+  /** Set the value of USE_CG2. Default: 0 */
+  virtual void setUSE_CG2(int value);
+  /** Get the value of USE_CG2 */
+  inline int getUSE_CG2() const {return USE_CG2;}
+
+  /** Set the value of normIsZero, the threshold for considering a norm to be 
+      0; Default: 1e-5 */
+  virtual void setNormIsZero(const double value);
+  /** Get the value of normIsZero */
+  inline double getNormIsZero() const {return normIsZero;}
+
+  /** Set the value of minReduc, threshold for relative norm improvement for
+   performing  a reduction; Default: 0.05 */
+  virtual void setMinReduc(const double value);
+  /// Get the value of minReduc
+  inline double getMinReduc() const {return minReduc;}
+
+  /** Set the maximum allowed value for (mTab * mTab * CoinMax(mTab, nTab)) where 
+      mTab is the number of rows used in the combinations and nTab is the 
+      number of continuous non basic variables. The work of the generator is 
+      proportional to (mTab * mTab * CoinMax(mTab, nTab)). Reducing the value of 
+      maxTab makes the generator faster, but weaker. Default: 1e7. */
+  virtual void setMaxTab(const double value);
+  /// Get the value of maxTab
+  inline double getMaxTab() const {return maxTab_;}
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglRedSplitParam(const double lub = 1000.0,
+		   const double eps_elim = 1e-12,
+		   const double eps_relax_abs = 1e-8,
+		   const double eps_relax_rel = 0.0,
+		   const double max_dyn = 1e8,
+		   const double max_dyn_lub = 1e13,
+		   const double eps_coeff_lub = 1e-13,
+		   const double min_viol = 1e-7,
+		   const int use_int_slacks = 0,
+		   const int use_cg2 = 0,
+		   const double norm_zero = 1e-5,
+		   const double min_reduc = 0.05,
+		   const double away = 0.05,
+		   const double max_tab = 1e7);
+
+   /// Constructor from CglParam
+  CglRedSplitParam(const CglParam &source,
+		   const double lub = 1000.0,
+		   const double eps_elim = 1e-12,
+		   const double eps_relax_abs = 1e-8,
+		   const double eps_relax_rel = 0.0,
+		   const double max_dyn = 1e8,
+		   const double max_dyn_lub = 1e13,
+		   const double eps_coeff_lub = 1e-13,
+		   const double min_viol = 1e-7,
+		   const int use_int_slacks = 0,
+		   const int use_cg2 = 0,
+		   const double norm_zero = 1e-5,
+		   const double min_reduc = 0.05,
+		   const double away = 0.05,
+		   const double max_tab = 1e7);
+
+  /// Copy constructor 
+  CglRedSplitParam(const CglRedSplitParam &source);
+
+  /// Clone
+  virtual CglRedSplitParam* clone() const;
+
+  /// Assignment operator 
+  virtual CglRedSplitParam& operator=(const CglRedSplitParam &rhs);
+
+  /// Destructor 
+  virtual ~CglRedSplitParam();
+  //@}
+
+protected:
+
+  /**@name Parameters */
+  //@{
+
+  /** Value considered large for the absolute value of lower or upper 
+      bound on a variable. Default: 1000. */
+  double LUB;
+
+  /** Epsilon for value of coefficients when eliminating slack variables. 
+      Default: 1e-12. */
+   double EPS_ELIM;
+
+  /** Value added to the right hand side of each generated cut to relax it.
+      Default: 1e-8 */
+  double EPS_RELAX_ABS;
+
+  /** For a generated cut with right hand side rhs_val, 
+      EPS_RELAX_EPS * fabs(rhs_val) is used to relax the constraint.
+      Default: 0 */
+  double EPS_RELAX_REL;
+
+  // Maximum ratio between largest and smallest non zero 
+  // coefficients in a cut. Default: 1e8.
+  double MAXDYN;
+
+  // Maximum ratio between largest and smallest non zero 
+  // coefficients in a cut involving structural variables with
+  // lower or upper bound in absolute value larger than LUB.
+  // Should logically be larger or equal to MAXDYN. Default: 1e13.
+  double MAXDYN_LUB;
+
+  /// Epsilon for value of coefficients for variables with absolute value of
+  /// lower or upper bound larger than LUB. Default: 1e-13.
+  double EPS_COEFF_LUB;
+
+  /// Minimum violation for the current basic solution in a generated cut.
+  /// Default: 1e-7.
+  double MINVIOL;
+
+  /// Use integer slacks to generate cuts if USE_INTSLACKS = 1. Default: 0.
+  int USE_INTSLACKS;
+
+  /// Use second way to generate a mixed integer Gomory cut 
+  /// (see methods generate_cgcut()) and generate_cgcut_2()). Default: 0.
+  int USE_CG2;
+
+  /// Norm of a vector is considered zero if smaller than normIsZero;
+  /// Default: 1e-5.
+  double normIsZero;
+
+  /// Minimum reduction in percent that must be achieved by a potential 
+  /// reduction step in order to be performed; Between 0 and 1, default: 0.05.
+  double minReduc;
+
+  /// Use row only if pivot variable should be integer but is more 
+  /// than away_ from being integer.
+  double away_;
+  
+  /// Maximum value for (mTab * mTab * CoinMax(mTab, nTab)). See method 
+  /// setMaxTab().
+  double maxTab_;
+
+  //@}
+};
+
+#endif
diff --git a/cbits/coin/CglResidualCapacity.cpp b/cbits/coin/CglResidualCapacity.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglResidualCapacity.cpp
@@ -0,0 +1,687 @@
+// LAST EDIT: 
+//-----------------------------------------------------------------------------
+// Implementation of Residual Capacity Inequalities
+// Francisco Barahona (barahon@us.ibm.com)
+//  
+// date: May 18 2006
+//-----------------------------------------------------------------------------
+// Copyright (C) 2004, International Business Machines Corporation and others. 
+// All Rights Reserved.
+// This code is published under the Eclipse Public License.
+
+//#include <cmath>
+//#include <cstdlib>
+#include <cassert>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinPackedVector.hpp"
+
+#include "CglResidualCapacity.hpp"
+//#define CGL_DEBUG 1
+//-----------------------------------------------------------------------------
+// Generate Mixed Integer Rounding inequality
+//------------------------------------------------------------------- 
+void
+CglResidualCapacity::generateCuts(const OsiSolverInterface& si,
+				      OsiCuts& cs,
+				  const CglTreeInfo /*info*/)
+{
+
+  // If the LP or integer presolve is used, then need to redo preprocessing
+  // everytime this function is called. Otherwise, just do once.
+  bool preInit = false;
+  bool preReso = false;
+  si.getHintParam(OsiDoPresolveInInitial, preInit);
+  si.getHintParam(OsiDoPresolveInResolve, preReso);
+  if (preInit == false &&  preReso == false &&
+      doPreproc_ == -1 ) { // Do once
+    if (doneInitPre_ == false) {   
+      resCapPreprocess(si);
+      doneInitPre_ = true;
+    }
+  }
+  else  
+      if ( doPreproc_ == 1 ){ // Do everytime       
+	  resCapPreprocess(si);
+	  doneInitPre_ = true;
+      } else
+	if (doneInitPre_ == false) {   
+	  resCapPreprocess(si);
+	  doneInitPre_ = true;
+	}  
+
+
+  const double* xlp        = si.getColSolution();  // LP solution
+  const double* colUpperBound = si.getColUpper();  // vector of upper bounds
+  const double* colLowerBound = si.getColLower();  // vector of lower bounds
+
+  // get matrix by row
+  const CoinPackedMatrix & tempMatrixByRow = *si.getMatrixByRow();
+  CoinPackedMatrix matrixByRow;
+  matrixByRow.submatrixOf(tempMatrixByRow, numRows_, indRows_);
+
+  const double* LHS        = si.getRowActivity();
+  const double* coefByRow  = matrixByRow.getElements();
+  const int* colInds       = matrixByRow.getIndices();
+  const int* rowStarts     = matrixByRow.getVectorStarts();
+  const int* rowLengths    = matrixByRow.getVectorLengths();
+
+
+  generateResCapCuts(si, xlp, colUpperBound, colLowerBound,
+		     matrixByRow, LHS, coefByRow,
+		     colInds, rowStarts, rowLengths, 
+		     cs);
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglResidualCapacity::CglResidualCapacity ()
+    :
+    CglCutGenerator()
+{ 
+    gutsOfConstruct(1.0e-6);
+}
+
+
+//-------------------------------------------------------------------
+// Alternate Constructor 
+//-------------------------------------------------------------------
+CglResidualCapacity::CglResidualCapacity (const double epsilon)
+  :
+  CglCutGenerator()
+{ 
+  gutsOfConstruct(epsilon);
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglResidualCapacity::CglResidualCapacity ( 
+				 const CglResidualCapacity & rhs)
+  :
+  CglCutGenerator(rhs)
+{ 
+  gutsOfCopy(rhs);
+}
+
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglResidualCapacity::clone() const
+{
+  return new CglResidualCapacity(*this);
+}
+
+//------------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglResidualCapacity &
+CglResidualCapacity::operator=(const CglResidualCapacity& rhs)
+{
+  if (this != &rhs) {
+    gutsOfDelete();
+    CglCutGenerator::operator=(rhs);
+    gutsOfCopy(rhs);
+  }
+  return *this;
+}
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------  
+CglResidualCapacity::~CglResidualCapacity ()
+{
+  gutsOfDelete();
+}
+
+//-------------------------------------------------------------------
+// Construct
+//-------------------------------------------------------------------  
+void
+CglResidualCapacity::gutsOfConstruct (const double epsilon)
+{
+  
+    EPSILON_ = epsilon;
+    TOLERANCE_ = 1.0e-4;
+    doPreproc_ = -1;
+    numRows_ = 0;
+    numCols_ = 0;
+    doneInitPre_ = false;
+    rowTypes_ = 0;
+    indRows_ = 0;
+    sense_=NULL;
+    RHS_=NULL; 
+    numRowL_ = 0;
+    indRowL_ = 0;
+    numRowG_ = 0;
+    indRowG_ = 0;
+}
+
+//-------------------------------------------------------------------
+// Delete
+//-------------------------------------------------------------------  
+void
+CglResidualCapacity::gutsOfDelete ()
+{
+  if (rowTypes_ != 0) { delete [] rowTypes_; rowTypes_ = 0; } 
+  if (indRows_ != 0) { delete [] indRows_; indRows_ = 0; }
+  if (indRowL_ != 0) { delete [] indRowL_; indRowL_ = 0; }
+  if (indRowG_ != 0) { delete [] indRowG_; indRowG_ = 0; }
+  if (sense_ !=NULL) { delete [] sense_; sense_=NULL;}
+  if (RHS_ !=NULL) { delete [] RHS_; RHS_=NULL;}
+}
+
+//-------------------------------------------------------------------
+// Copy
+//-------------------------------------------------------------------  
+void
+CglResidualCapacity::gutsOfCopy (const CglResidualCapacity& rhs)
+{
+  EPSILON_ = rhs.EPSILON_;
+  TOLERANCE_ = rhs.TOLERANCE_;
+  doPreproc_ = rhs.doPreproc_;
+  numRows_ = rhs.numRows_;
+  numCols_ = rhs.numCols_;
+  doneInitPre_ = rhs.doneInitPre_;
+  numRowL_ = rhs.numRowL_;
+  numRowG_ = rhs.numRowG_;
+
+
+  if (numRows_ > 0) {
+    rowTypes_ = new RowType [numRows_];
+    CoinDisjointCopyN(rhs.rowTypes_, numRows_, rowTypes_);
+    indRows_ = new int [numRows_];
+    CoinDisjointCopyN(rhs.indRows_, numRows_, indRows_);
+    sense_ = CoinCopyOfArray(rhs.sense_,numRows_);
+    RHS_ = CoinCopyOfArray(rhs.RHS_,numRows_);
+  }
+  else {
+    rowTypes_ = 0;
+    indRows_ = 0;
+    sense_=NULL;
+    RHS_=NULL;
+  }
+
+  if (numRowL_ > 0) {
+    indRowL_ = new int [numRowL_];
+    CoinDisjointCopyN(rhs.indRowL_, numRowL_, indRowL_);
+  }
+  else {
+    indRowL_ = 0;
+  }
+
+  if (numRowG_ > 0) {
+    indRowG_ = new int [numRowG_];
+    CoinDisjointCopyN(rhs.indRowG_, numRowG_, indRowG_);
+  }
+  else {
+    indRowG_ = 0;
+  }
+
+}
+
+//-------------------------------------------------------------------
+// Do preprocessing
+// It determines the type of each row.
+//-------------------------------------------------------------------  
+void 
+CglResidualCapacity::
+resCapPreprocess(const OsiSolverInterface& si)
+{
+    // get matrix stored by row
+    const CoinPackedMatrix & matrixByRow = *si.getMatrixByRow();
+    numRows_ = si.getNumRows();
+    numCols_ = si.getNumCols();
+    const double* coefByRow  = matrixByRow.getElements();
+    const int* colInds       = matrixByRow.getIndices();
+    const int* rowStarts     = matrixByRow.getVectorStarts();
+    const int* rowLengths    = matrixByRow.getVectorLengths();
+    const double * colLowerBound = si.getColLower();
+    const double * colUpperBound = si.getColUpper();
+    // Get copies of sense and RHS so we can modify if ranges
+    if (sense_) {
+	delete [] sense_;
+	delete [] RHS_;
+    }
+    sense_ = CoinCopyOfArray(si.getRowSense(),numRows_);
+    RHS_  = CoinCopyOfArray(si.getRightHandSide(),numRows_);
+    
+    if (rowTypes_ != 0) {
+	delete [] rowTypes_; rowTypes_ = 0;
+    }
+    rowTypes_ = new RowType [numRows_];     // Destructor will free memory
+    
+    // Summarize the row type infomation.
+    int numOTHER   = 0;
+    int numL       = 0;
+    int numG       = 0;
+    int numB       = 0;
+    
+    int iRow;
+    const double* rowActivity        = si.getRowActivity();
+    const double* rowLower        = si.getRowLower();
+    const double* rowUpper        = si.getRowUpper();
+    for (iRow = 0; iRow < numRows_; ++iRow) {
+	// If range then choose which to use
+	if (sense_[iRow]=='R') {
+	    if (rowActivity[iRow]-rowLower[iRow]<
+		rowUpper[iRow]-rowActivity[iRow]) {
+		// treat as G row
+		RHS_[iRow]=rowLower[iRow];
+		sense_[iRow]='G';
+	    } else {
+		// treat as L row
+		RHS_[iRow]=rowUpper[iRow];
+		sense_[iRow]='L';
+	    }
+	}
+	// get the type of a row
+	const RowType rowType = 
+	    determineRowType(si, rowLengths[iRow], colInds+rowStarts[iRow],
+			     coefByRow+rowStarts[iRow], sense_[iRow], RHS_[iRow],
+			     colLowerBound, colUpperBound);
+	// store the type of the current row
+	rowTypes_[iRow] = rowType;
+	
+	// Summarize information about row types
+	switch(rowType) {
+	case  ROW_OTHER:
+	    ++numOTHER; 
+	    break;
+	case  ROW_L:
+	    ++numL; 
+	    break;
+	case  ROW_G:
+	    ++numG; 
+	    break;
+	case ROW_BOTH:
+	    ++numB;
+	    break;
+	default:
+	    throw CoinError("Unknown row type", "ResidualCapacityPreprocess",
+			    "CglResidualCapacity");
+	}
+    }
+    
+    // allocate memory for vector of indices of all rows
+    if (indRows_ != 0) { delete [] indRows_; indRows_ = 0; }
+    if (numRows_ > 0)
+	indRows_ = new int [numRows_];     // Destructor will free memory
+    // allocate memory for vector of indices of rows of type ROW_L and ROW_BOTH
+    numRowL_ = numL + numB;
+    if (indRowL_ != 0) { delete [] indRowL_; indRowL_ = 0; }
+    if (numRowL_ > 0)
+	indRowL_ = new int [numRowL_];     // Destructor will free memory
+    // allocate memory for vector of indices of rows of type ROW_G and ROW_BOTH
+    numRowG_ = numG + numB;
+    if (indRowG_ != 0) { delete [] indRowG_; indRowG_ = 0; }
+    if (numRowG_ > 0)
+	indRowG_ = new int [numRowG_];     // Destructor will free memory
+    
+    
+#if CGL_DEBUG
+    std::cout << "The num of rows = "  << numRows_        << std::endl;
+    std::cout << "Summary of Row Type" << std::endl;
+    std::cout << "numL          = " << numL        << std::endl;
+    std::cout << "numG          = " << numG        << std::endl;
+#endif
+    
+    
+    int countL = 0;
+    int countG = 0;
+    for ( iRow = 0; iRow < numRows_; ++iRow) {
+	
+	RowType rowType = rowTypes_[iRow];
+	
+	// fill the vector indRows_ with the indices of all rows
+	indRows_[iRow] = iRow;
+	
+	// fill the vector indRowL_ with the indices of the rows of type ROW_L and ROW_BOTH
+	if (rowType == ROW_L || rowType == ROW_BOTH) {
+	    indRowL_[countL] = iRow;
+	    countL++;
+	}
+	// fill the vector indRowG_ with the indices of rows of type ROW_G and ROW_BOTH
+	if (rowType == ROW_G || rowType == ROW_BOTH) {
+	    indRowG_[countG] = iRow;
+	    countG++;
+	}
+    }
+    
+}
+
+//-------------------------------------------------------------------
+// Determine the type of a given row 
+//-------------------------------------------------------------------
+CglResidualCapacity::RowType
+CglResidualCapacity::determineRowType(const OsiSolverInterface& si,
+				      const int rowLen, const int* ind, 
+				      const double* coef, const char sense, 
+				      const double rhs,
+				      const double* colLowerBound,
+				      const double* colUpperBound) const
+{
+    if (rowLen == 0) 
+	return ROW_OTHER;
+    RowType rowType = ROW_OTHER;
+    double *negCoef;
+    bool flagL, flagG, flag1, flag2;
+    switch (sense) {
+    case 'L':
+	flagL=treatAsLessThan(si, rowLen, ind, coef, rhs, colLowerBound,
+				  colUpperBound);
+	if ( flagL ) rowType=ROW_L;
+	break;
+    case 'G':
+	negCoef = new double[rowLen];
+	for ( int i=0; i < rowLen; ++i )
+	    negCoef[i]=-coef[i];
+	flagG=treatAsLessThan(si, rowLen, ind, negCoef, -rhs, colLowerBound,
+				   colUpperBound);
+	if ( flagG ) rowType=ROW_G;
+	delete [] negCoef;
+	break;
+    case 'E':
+	flag1=treatAsLessThan(si, rowLen, ind, coef, rhs, colLowerBound,
+				   colUpperBound);
+	
+	negCoef = new double[rowLen];
+	for ( int i=0; i < rowLen; ++i )
+	    negCoef[i]=-coef[i];
+	flag2=treatAsLessThan(si, rowLen, ind, negCoef, -rhs, colLowerBound,
+				   colUpperBound);
+	delete [] negCoef;
+	if ( flag1 && !flag2 ) rowType=ROW_L;
+	if ( !flag1 && flag2 ) rowType=ROW_G;
+	if ( flag1 && flag2  ) rowType=ROW_BOTH;
+	break;
+    default:
+	throw CoinError("Unknown sense", "determineRowType",
+			"CglResidualCapacity");
+    }
+    return rowType;
+}
+//--------------------------------------------
+// determine if an ineq of type <= is a good candidate
+//--------------------------------------------
+	
+bool
+CglResidualCapacity::treatAsLessThan(const OsiSolverInterface& si,
+				     const int rowLen, const int* ind, 
+				     const double* coef,
+				     const double /*rhs*/,
+				     const double* colLowerBound,
+				     const double* colUpperBound) const
+{
+    bool intFound=false;
+    bool contFound=false;
+    bool goodIneq=true;
+    double intCoef=-1;
+    
+    // look for a_1 c_1 +   + a_k c_k  - d z_1 -   - d z_p <= b
+    // where c_i continuous, z_j integer
+    for ( int i = 0; i < rowLen; ++i ) {
+	if ( coef[i]  > EPSILON_ || !si.isInteger(ind[i]) ) {
+	    if ( colLowerBound[ind[i]] < -EPSILON_ || colUpperBound[ind[i]] > 1.e10 ){
+		// cont var with too big bounds
+		goodIneq=false;
+		break;
+	    } else
+		contFound=true;
+	} else
+	    if ( !intFound &&  coef[i] < -EPSILON_  && si.isInteger(ind[i]) ){
+		intFound=true;
+		intCoef=coef[i];
+		continue;
+	    } else
+		if ( intFound && coef[i] < -EPSILON_  && si.isInteger(ind[i]) &&
+		     fabs( coef[i] - intCoef ) > EPSILON_ ){
+		    goodIneq=false;
+		    break;
+		}
+    }
+    if ( contFound && intFound && goodIneq ) return true;
+    else return false;
+}
+
+//-------------------------------------------------------------------
+// Generate Residual capacity cuts
+//-------------------------------------------------------------------
+void
+CglResidualCapacity::generateResCapCuts( 
+				     const OsiSolverInterface& si,
+				     const double* xlp,
+				     const double* colUpperBound,
+				     const double* colLowerBound,
+				     const CoinPackedMatrix& /*matrixByRow*/,
+				     const double* /*LHS*/,
+				     const double* coefByRow,
+				     const int* colInds,
+				     const int* rowStarts,
+				     const int* rowLengths,
+				     OsiCuts& cs ) const
+{
+    
+#if CGL_DEBUG
+    // OPEN FILE
+    std::ofstream fout("stats.dat");
+#endif
+    
+    for (int iRow = 0; iRow < numRowL_; ++iRow) {
+	int rowToUse=indRowL_[iRow];
+	OsiRowCut resCapCut;
+	// Find a most violated residual capacity ineq
+	bool hasCut = resCapSeparation(si, rowLengths[rowToUse],
+				       colInds+rowStarts[rowToUse],
+				       coefByRow+rowStarts[rowToUse],
+				       RHS_[rowToUse],
+				       xlp, colUpperBound, colLowerBound, 
+				       resCapCut);
+	
+	// if a cut was found, insert it into cs
+	if (hasCut)  {
+#if CGL_DEBUG
+	    std::cout << "Res. cap. cut generated " << std::endl;
+#endif
+	    cs.insert(resCapCut);
+	}
+    }
+    
+    for (int iRow = 0; iRow < numRowG_; ++iRow) {
+	int rowToUse=indRowG_[iRow];
+	OsiRowCut resCapCut;
+	const int rowLen=rowLengths[rowToUse];
+	double *negCoef= new double[rowLen];
+	const int rStart=rowStarts[rowToUse];
+	for ( int i=0; i < rowLen; ++i )
+	    negCoef[i]=-coefByRow[rStart+i];
+	// Find a most violated residual capacity ineq
+	bool hasCut = resCapSeparation(si, rowLengths[rowToUse],
+				       colInds+rowStarts[rowToUse],
+				       negCoef,
+				       -RHS_[rowToUse],
+				       xlp, colUpperBound, colLowerBound, 
+				       resCapCut);
+	delete [] negCoef;
+	// if a cut was found, insert it into cs
+	if (hasCut)  {
+#if CGL_DEBUG
+	    std::cout << "Res. cap. cut generated " << std::endl;
+#endif
+	    cs.insert(resCapCut);
+	}
+    }
+
+#if CGL_DEBUG
+    // CLOSE FILE
+    fout.close();
+#endif
+    
+    return;
+}
+
+//-------------------------------------------------------------------
+// separation algorithm
+//-------------------------------------------------------------------
+bool
+CglResidualCapacity::resCapSeparation(const OsiSolverInterface& si,
+				      const int rowLen, const int* ind, 
+				      const double* coef,
+				      const double rhs,
+				      const double *xlp,  
+				      const double* colUpperBound,
+				      const double* /*colLowerBound*/,
+				      OsiRowCut& resCapCut) const
+{ 
+    // process original row to create row in canonical form
+    std::vector<int> positionIntVar;
+    double ybar=0.0;
+    double *xbar;
+    double intCoef=-1;
+    double *newRowCoef;
+    int *positionContVar;
+    double newRowRHS;
+    int contCount=0;
+
+    for ( int i = 0; i < rowLen; ++i ) {
+	if ( coef[i] < -EPSILON_ && si.isInteger(ind[i]) ){
+	    intCoef=-coef[i];
+	    ybar+=xlp[ind[i]];
+	    positionIntVar.push_back(i);
+	}
+	else 
+	    ++contCount;
+    }
+    xbar = new double [contCount];
+    newRowCoef = new double [contCount];
+    positionContVar = new int [contCount];
+    contCount=0;
+    newRowRHS=rhs;
+    for ( int i = 0; i < rowLen; ++i ) 
+	if ( coef[i] > EPSILON_ || !si.isInteger(ind[i]) ){
+	    newRowCoef[contCount]=coef[i]*colUpperBound[ind[i]];
+	    xbar[contCount]=xlp[ind[i]]/colUpperBound[ind[i]];
+	    if ( newRowCoef[contCount] < -EPSILON_ ){ // complement
+		newRowCoef[contCount] = -newRowCoef[contCount];
+		xbar[contCount] = 1.0 - xbar[contCount];
+		newRowRHS+= newRowCoef[contCount];
+	    }
+	    positionContVar[contCount++]=i;
+	}
+    
+    // now separate
+    std::vector<int> setSbar;
+    const double lambda = ybar - floor(ybar);
+    double sumCoef=0.0;
+    for ( int i = 0; i < contCount; ++i )
+	if ( xbar[i] > lambda ){
+	    setSbar.push_back(i);
+	    sumCoef+=newRowCoef[i];
+	}
+    const int sSize = static_cast<int>(setSbar.size());
+    bool generated;
+    if ( sSize == 0 ) generated=false; // no cut
+    else {
+	// generate cut
+	const double mu= ceil( (sumCoef - newRowRHS)/intCoef );
+	double r = sumCoef - newRowRHS - intCoef * floor( (sumCoef - newRowRHS)/intCoef );
+	const int numInt = static_cast<int>(positionIntVar.size());
+	const int cutLen = sSize + numInt;
+	int* cutInd = new int [cutLen];
+	double* cutCoef = new double [cutLen];
+	double violation=0.0;
+	double complCoef=0.0;
+	// load continuous variables
+	for ( int i = 0; i < sSize; ++i ){
+	    const int newRowPosition=setSbar[i];
+	    const int originalRowPosition=positionContVar[newRowPosition];
+	    cutInd[i]=ind[originalRowPosition];
+	    cutCoef[i]=coef[originalRowPosition];
+	    if ( cutCoef[i] < -EPSILON_ ) 
+		complCoef+= cutCoef[i]*colUpperBound[ind[originalRowPosition]];
+	    violation+=cutCoef[i]*xlp[ind[originalRowPosition]];
+	}
+	// load integer variables
+	for ( int i = 0; i < numInt; ++i ){
+	    const int originalRowPosition=positionIntVar[i];
+	    cutInd[i+sSize]=ind[originalRowPosition];
+	    cutCoef[i+sSize]= - r;
+	    violation+=cutCoef[i+sSize]*xlp[ind[originalRowPosition]];
+	}
+	double cutRHS=(sumCoef - r * mu) + complCoef;
+	violation-=cutRHS;
+	if ( violation > TOLERANCE_ ){
+	    resCapCut.setRow(cutLen, cutInd, cutCoef);
+	    resCapCut.setLb(-1.0 * si.getInfinity());
+	    resCapCut.setUb(cutRHS);
+	    resCapCut.setEffectiveness(violation);
+	    generated=true;
+#if 0
+	    std::cout << "coef ";
+	    for(int i=0; i<cutLen; ++i)
+		std::cout << cutCoef[i] << " ";
+	    std::cout << std::endl << " bounds ";
+	    for(int i=0; i<cutLen; ++i)
+		std::cout << colUpperBound[cutInd[i]] << " ";
+	    std::cout << std::endl << " rhs " << cutRHS << std::endl;
+#endif	    
+	}
+	else
+	    generated=false;
+	delete [] cutCoef;
+	delete [] cutInd;
+    }
+    // free memory	
+    delete [] positionContVar;
+    delete [] newRowCoef; 
+    delete [] xbar;
+    return generated;
+}
+
+
+
+// This can be used to refresh preprocessing
+void 
+CglResidualCapacity::refreshPrep()
+{
+  doneInitPre_ = false;
+}
+
+//
+void CglResidualCapacity::setEpsilon(double value)
+{
+    EPSILON_ = value;  
+}
+double CglResidualCapacity::getEpsilon() const
+{
+    return EPSILON_;
+}
+//
+void CglResidualCapacity::setTolerance(double value)
+{
+    TOLERANCE_ = value;
+}
+double CglResidualCapacity::getTolerance() const
+{
+    return TOLERANCE_;
+}
+//
+void CglResidualCapacity::setDoPreproc(int value)
+{
+    if ( value != -1 && value != 0 && value != 1 )
+	throw CoinError("setDoPrepoc", "invalid value",
+			"CglResidualCapacity");
+    else
+	doPreproc_ = value;  
+}
+bool CglResidualCapacity::getDoPreproc() const
+{
+    return (doPreproc_ != 0);
+}
diff --git a/cbits/coin/CglResidualCapacity.hpp b/cbits/coin/CglResidualCapacity.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglResidualCapacity.hpp
@@ -0,0 +1,240 @@
+// LAST EDIT: 
+//-----------------------------------------------------------------------------
+// Implementation of Residual Capacity Inequalities
+// Francisco Barahona (barahon@us.ibm.com)
+//         
+// date: May 18, 2006
+//-----------------------------------------------------------------------------
+// Copyright (C) 2004, International Business Machines Corporation and others. 
+// All Rights Reserved.
+// This code is published under the Eclipse Public License.
+
+#ifndef CglResidualCapacity_H
+#define CglResidualCapacity_H
+
+#include <iostream>
+#include <fstream>
+//#include <vector>
+
+#include "CoinError.hpp"
+
+#include "CglCutGenerator.hpp"
+
+//=============================================================================
+
+#ifndef CGL_DEBUG
+#define CGL_DEBUG 0
+#endif
+
+//=============================================================================
+
+
+
+
+//=============================================================================
+
+/** Residual Capacity Inequalities Cut Generator Class
+
+ References: 
+    T Magnanti, P Mirchandani, R Vachani,
+    "The convex hull of two core capacitated network design problems,"
+    Math Programming 60 (1993), 233-250.
+    
+    A Atamturk, D Rajan,
+    "On splittable and unsplittable flow capacitated network design 
+    arc-set polyhedra," Math Programming 92 (2002), 315-333. **/
+
+class CglResidualCapacity : public CglCutGenerator {
+    
+    friend void CglResidualCapacityUnitTest(const OsiSolverInterface * siP,
+					    const std::string mpdDir );
+    
+    
+private:
+    //---------------------------------------------------------------------------
+    // Enumeration constants that describe the various types of rows
+    enum RowType {
+	/**   row of the type a_1 c_1 +  + a_k c_k - d z_1 -  - d z_p <= b,
+	      where c_i are continuous variables and z_j are integer variables
+	*/
+	ROW_L,
+	/**  row of the type -a_1 c_1 -  - a_k c_k + d z_1 +  + d z_p >= b,
+	     where c_i are continuous variables and z_j are integer variables
+	*/
+	ROW_G,
+	/** equation that can be treated as ROW_L and ROW_G
+	 */
+	ROW_BOTH,
+	/** Other types of rows
+	 */
+	ROW_OTHER
+    };
+    
+    
+public:
+    /**@name Get and Set Parameters */
+    //@{
+    /// Set Epsilon
+    void setEpsilon(double value);
+    /// Get Epsilon
+    double getEpsilon() const;
+    /// Set Tolerance
+    void setTolerance(double value);
+    /// Get Tolerance
+    double getTolerance() const;
+    /// Set doPreproc
+    void setDoPreproc(int value);
+    /// Get doPreproc
+    bool getDoPreproc() const;
+    //@}
+
+    /**@name Generate Cuts */
+    //@{
+    /** Generate Residual Capacity cuts for the model data 
+	contained in si. The generated cuts are inserted 
+	in the collection of cuts cs. 
+    */
+    virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			      const CglTreeInfo info = CglTreeInfo());
+    //@}
+    
+    //---------------------------------------------------------------------------
+    /**@name Constructors and destructors */
+    //@{
+    /// Default constructor 
+    CglResidualCapacity ();
+    
+    /// Alternate Constructor 
+    CglResidualCapacity ( const double tolerance );
+    
+    /// Copy constructor 
+    CglResidualCapacity (
+			 const CglResidualCapacity &);
+    
+    /// Clone
+    virtual CglCutGenerator * clone() const;
+    
+    /// Assignment operator 
+    CglResidualCapacity &
+    operator=(
+	      const CglResidualCapacity& rhs);
+    
+    /// Destructor 
+    virtual
+    ~CglResidualCapacity ();
+    /// This is to refresh preprocessing
+    virtual void refreshPrep();
+    //@}
+    
+    
+    
+private:
+    //--------------------------------------------------------------------------
+    // Private member methods
+    
+    // Construct
+    void gutsOfConstruct ( const double tolerance);
+    
+    // Delete
+    void gutsOfDelete();
+    
+    // Copy
+    void gutsOfCopy (const CglResidualCapacity& rhs);
+    
+    // Do preprocessing.
+    // It determines the type of each row. 
+    // It may change sense and RHS for ranged rows
+    void resCapPreprocess(const OsiSolverInterface& si);
+    
+    // Determine the type of a given row.
+    RowType determineRowType(const OsiSolverInterface& si,
+			     const int rowLen, const int* ind, 
+			     const double* coef, const char sense, 
+			     const double rhs,
+			     const double* colLowerBound,
+			     const double* colUpperBound) const;
+    // helps the function above
+    bool treatAsLessThan(const OsiSolverInterface& si,
+			 const int rowLen, const int* ind, 
+			 const double* coef,
+			 const double rhs,
+			 const double* colLowerBound,
+			 const double* colUpperBound) const;
+    
+    // Generate Residual Capacity cuts
+    void generateResCapCuts( const OsiSolverInterface& si,
+			     const double* xlp,
+			     const double* colUpperBound,
+			     const double* colLowerBound,
+			     const CoinPackedMatrix& matrixByRow,
+			     const double* LHS,
+			     const double* coefByRow,
+			     const int* colInds,
+			     const int* rowStarts,
+			     const int* rowLengths,
+			     OsiCuts& cs ) const;
+    
+
+    // Residual Capacity separation 
+    bool resCapSeparation(const OsiSolverInterface& si,
+			  const int rowLen, const int* ind, 
+			  const double* coef,
+			  const double rhs,
+			  const double *xlp,  
+			  const double* colUpperBound,
+			  const double* colLowerBound,
+			  OsiRowCut& resCapCut) const;
+    
+      
+
+private:
+    //---------------------------------------------------------------------------
+    // Private member data
+    /** Tolerance used for numerical purposes, default value: 1.e-6 **/
+    double EPSILON_;
+    /** If violation of a cut is greater that this number, 
+	the cut is accepted, default value: 1.e-4 **/
+    double TOLERANCE_;
+    /** Controls the preprocessing of the matrix to identify rows suitable for
+        cut generation.<UL>
+     <LI> -1: preprocess according to solver settings;
+     <LI> 0: Do preprocessing only if it has not yet been done;
+     <LI> 1: Do preprocessing.
+     </UL>
+	 Default value: -1 **/
+    int doPreproc_;
+    // The number of rows of the problem.
+    int numRows_;
+    // The number columns of the problem.
+    int numCols_;
+    // Indicates whether preprocessing has been done.
+    bool doneInitPre_;
+    // Array with the row types of the rows in the model.
+    RowType* rowTypes_;
+    // The indices of the rows of the initial matrix
+    int* indRows_;
+    // Sense of rows (modified if ranges)
+    char * sense_;
+    // RHS of rows (modified if ranges)
+    double * RHS_;
+    // The number of rows of type ROW_L
+    int numRowL_;
+    // The indices of the rows of type ROW_L
+    int* indRowL_;
+    // The number of rows of type ROW_G
+    int numRowG_;
+    // The indices of the rows of type ROW_G
+    int* indRowG_;
+};
+
+//#############################################################################
+/** A function that tests the methods in the CglResidualCapacity class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglResidualCapacityUnitTest(const OsiSolverInterface * siP,
+				 const std::string mpdDir);
+
+  
+#endif
diff --git a/cbits/coin/CglSimpleRounding.cpp b/cbits/coin/CglSimpleRounding.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglSimpleRounding.cpp
@@ -0,0 +1,482 @@
+// $Id: CglSimpleRounding.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cmath>
+#include <cstdio>
+#include <cfloat> 
+#include <cassert>
+
+#include "CoinPragma.hpp"
+#include "CglSimpleRounding.hpp" 
+#include "CoinPackedVector.hpp"
+#include "CoinSort.hpp"
+#include "CoinPackedMatrix.hpp"
+
+//-------------------------------------------------------------
+void
+CglSimpleRounding::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+				const CglTreeInfo /*info*/)
+{
+  int nRows=si.getNumRows(); // number of rows in the coefficient matrix
+  int nCols=si.getNumCols(); // number of columns in the coefficient matrix
+  int rowIndex;             // index into the constraint matrix stored in row
+                            // order 
+  CoinPackedVector irow;     // "integer row": working space to hold the integer
+                            // <= inequality derived from the rowIndex-th
+                            // constraint 
+  double b=0;             // working space for the rhs of integer <= inequality
+  bool * negative= new bool[nCols]; // negative[i]= true if coefficient of the 
+                                    // ith variable is negative and false
+                                    // otherwise 
+  int k;                  // dummy iterator variable 
+  for ( k=0; k<nCols; k++ ) negative[k] = false;
+  
+  const CoinPackedMatrix * rowCopy = 
+    si.getMatrixByRow(); // row copy: matrix stored in row order
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Main loop:                                                              //
+  // For every row in the matrix,                                            //
+  //     if we can derive a valid <= inequality in integer variables, then   //
+  //     try to construct a simple rounding cut from the integer inequality. //
+  //     Add the resulting cut to the set of cuts.                           //
+  /////////////////////////////////////////////////////////////////////////////
+
+  for (rowIndex=0; rowIndex<nRows; rowIndex++){
+
+    // Only look at tight rows
+    // double * pi=ekk_rowduals(model); 
+    // if (fabs(pi[row]) < epsilon_){
+   //  continue;
+    // }
+
+    // Try to derive an <= inequality in integer variables from the row 
+    // by netting out the continuous variables.
+    // Store the value and the sign of the coefficients separately:
+    // irow.getElements() contains the absolute values of the coefficients.
+    // negative is a boolean vector indicating the sign of the coeffcients.
+    // b is the rhs of the <= integer inequality
+
+    if (!deriveAnIntegerRow( si, 
+                             rowIndex, 
+                             rowCopy->getVector(rowIndex),
+                             irow, b, negative))
+    {
+
+      // Reset local data for the next iteration of the rowIndex-loop
+      for(k=0; k<irow.getNumElements(); k++) negative[irow.getIndices()[k]]=false;
+      irow.setVector(0,NULL,NULL);
+      continue;
+    } 
+ 
+    // Euclid's greatest common divisor (gcd) algorithm applies to positive
+    // INTEGERS. 
+    // Determine the power of 10 needed, so that multipylying the integer
+    // inequality through by 10**power makes all coefficients essentially
+    // integral. 
+    int power = power10ToMakeDoubleAnInt(irow.getNumElements(),irow.getElements(),epsilon_*1.0e-4);
+
+    // Now a vector to store the integer-ized values. For instance, 
+    // if x[i] is .66 and power is 1000 then xInt[i] will be 660
+    int * xInt = NULL;
+    if (power >=0) {
+
+      xInt = new int[irow.getNumElements()]; 
+      double dxInt; // a double version of xInt for error trapping
+      
+      
+#ifdef CGL_DEBUG      
+      printf("The (double) coefficients and their integer-ized counterparts:\n");
+#endif
+
+      for (k=0; k<irow.getNumElements(); k++){
+	dxInt = irow.getElements()[k]*pow(10.0,power);
+	xInt[k]= static_cast<int> (dxInt+0.5); // Need to add the 0.5 
+	// so that a dxInt=9.999 will give a xInt=1
+
+#ifdef CGL_DEBUG
+	printf("%g     %g   \n",irow.getElements()[k],dxInt);
+#endif
+
+      }
+
+    } else {
+
+      // If overflow is detected, one warning message is printed and 
+      // the row is skipped.
+#ifdef CGL_DEBUG
+      printf("SimpleRounding: Warning: Overflow detected \n");
+      printf("      on %i of vars in processing row %i. Row skipped.\n",
+	     -power, rowIndex);
+#endif
+      // reset local data for next iteration
+      for(k=0; k<irow.getNumElements(); k++) negative[irow.getIndices()[k]]=false;
+      irow.setVector(0,NULL,NULL);
+      continue;
+    }
+
+    // find greatest common divisor of the irow.elements
+    int gcd = gcdv(irow.getNumElements(), xInt);
+
+#ifdef CGL_DEBUG
+    printf("The gcd of xInt is %i\n",gcd);    
+#endif
+
+    // construct new cut by dividing through by gcd and 
+    // rounding down rhs and accounting for negatives
+    CoinPackedVector cut;
+    for (k=0; k<irow.getNumElements(); k++){
+        cut.insert(irow.getIndices()[k],xInt[k]/gcd);
+    }
+    double cutRhs = floor((b*pow(10.0,power))/gcd);
+
+    // un-negate the negated variables in the cut
+    {
+       const int s = cut.getNumElements();
+       const int * indices = cut.getIndices();
+       double* elements = cut.getElements();
+       for (k=0; k<s; k++){
+	 int column=indices[k];
+	  if (negative[column]) {
+	     elements[k] *= -1;
+	  }
+       }
+    }
+
+    // Create the row cut and add it to the set of cuts
+    // It may not be violated
+    if (fabs(cutRhs*gcd-b)> epsilon_){ // if the cut and row are different. 
+      OsiRowCut rc;
+      rc.setRow(cut.getNumElements(),cut.getIndices(),cut.getElements());
+      rc.setLb(-COIN_DBL_MAX);
+      rc.setUb(cutRhs);   
+      cs.insert(rc);
+
+#ifdef CGL_DEBUG
+      printf("Row %i had a simple rounding cut:\n",rowIndex);
+      printf("Cut size: %i Cut rhs: %g  Index       Element \n",
+	     cut.getNumElements(), cutRhs);
+      for (k=0; k<cut.getNumElements(); k++){
+        printf("%i      %g\n",cut.getIndices()[k], cut.getElements()[k]);
+      }
+      printf("\n");
+#endif
+    }
+
+    // Reset local data for the next iteration of the rowIndex-loop
+    for(k=0; k<irow.getNumElements(); k++) negative[irow.getIndices()[k]]=false;
+    irow.setVector(0,NULL,NULL);
+    delete [] xInt;
+
+
+  }
+
+  delete [] negative;
+}
+
+
+//-------------------------------------------------------------------
+// deriveAnIntegerRow:  dervies a <=  inequality
+//                  in integer variables of the form ax<=b 
+//                  from a row in the model, if possible by
+//                  netting out the continuous variables
+//-------------------------------------------------------------------
+bool
+CglSimpleRounding::deriveAnIntegerRow(
+       const OsiSolverInterface & si, 
+       int rowIndex,
+       const CoinShallowPackedVector & matrixRow,
+       CoinPackedVector & irow, 
+       double & b,
+       bool * negative) const
+{
+  irow.clear();
+  int i;           // dummy iterator variable
+  double sign=1.0; // +1 if le row, -1 if ge row  
+
+  // number of columns in the row
+  int sizeOfRow=matrixRow.getNumElements();
+
+  // Get the sense of the row constraint
+  const char  rowsense = si.getRowSense()[rowIndex];
+
+  // Skip equality rows  
+  if  (rowsense=='E' || rowsense=='N') {
+    return 0; 
+  }
+  // le row  
+  if (rowsense=='L'){
+    b=si.getRightHandSide()[rowIndex];
+  }
+  // ge row
+  // Multiply through by -1 to convert it to a le row 
+  if (rowsense=='G'){
+    b=-si.getRightHandSide()[rowIndex];
+    sign=-1.0;
+  }
+  
+  // Finite, but unequal row bounds  
+  // Could derive an simple rounding inequality from either 
+  // (or from both!) but for expediency, 
+  // use the le relationship as the default for now  
+  if  (rowsense=='R') {
+    b=si.getRightHandSide()[rowIndex];
+  }
+  
+   // Try to net out the continuous variables from the constraint.
+  // Multipy through by sign to convert the inequality to a le inequality  
+  // If the coefficient on a continuous variable is positive, replace
+  // the continous variable with its lower bound 
+  // If the coefficient on a continuous variable is negative, replace
+  // the continuous variable with its upper bound.
+  // example:
+  //                   2.5 <= 3x0-2.8x1+4x2,  0<=x0<=0.2, 0.4<=x1, x2 integer
+  //                         -3x0+2.8x1-4x2 <= -2.5
+  // -3(0.2)+2.8(0.4)-4x3 <= -3x0+2.8x1-4x2 <= -2.5
+  // gives the (weaker, valid) integer inequality
+  //                                   -4x2 <= -2.5+3(0.2)-2.8(0.4)
+  // sign = -1
+  // irow.elements = 4
+  // irow.indices = 2
+  // negative = (true, true, false)
+  // b=-2.5+3(0.2)-2.8(0.4)= -3.02
+
+  const double * colupper = si.getColUpper();
+  const double * collower = si.getColLower();
+
+  for (i=0; i<sizeOfRow; i++){
+    // if the variable is continuous
+    if ( !si.isInteger( matrixRow.getIndices()[i] ) ) {
+      // and the coefficient is strictly negative
+      if((sign*matrixRow.getElements()[i])<-epsilon_){
+        // and the continuous variable has a fintite upper bound
+        if (colupper[matrixRow.getIndices()[i]] < si.getInfinity()){
+          // then replace the variable with its upper bound.
+          b=b-(sign*matrixRow.getElements()[i]*colupper[matrixRow.getIndices()[i]]);
+        } 
+        else 
+          return 0;
+      }
+      // if the coefficient in strictly positive
+      else if((sign*matrixRow.getElements()[i])>epsilon_){
+        // and the continuous variable has a finite lower bound
+        if (collower[matrixRow.getIndices()[i]] > -si.getInfinity()){
+          // then replace the variable with its lower bound.
+          b=b-(sign*matrixRow.getElements()[i]*collower[matrixRow.getIndices()[i]]);
+        }
+        else
+          return 0;
+      }
+      // else the coefficient is essentially an explicitly stored zero; do
+      // nothing   
+    }
+    // else: the variable is integer
+    else{
+      // if the integer variable is fixed, net it out of the integer inequality
+      if (colupper[matrixRow.getIndices()[i]]- collower[matrixRow.getIndices()[i]]<
+	  epsilon_){
+          b=b-(sign*matrixRow.getElements()[i]*colupper[matrixRow.getIndices()[i]]);
+      }
+      // else the variable is a free integer variable and it becomes
+      // part of the integer inequality
+      else {
+        irow.insert(matrixRow.getIndices()[i],sign*matrixRow.getElements()[i]);
+      }
+    }
+  }
+  
+  // if there are no free integer variables, then abandon this row;
+  if(irow.getNumElements() == 0){
+    return 0;
+  }
+  
+  // Store the values and the signs of the coefficients separately.
+  // irow.elements stores the absolute values of the coefficients
+  // negative indicates the sign.
+  // Note: after this point b is essentially the effecitve rhs of a le
+  // contraint
+  {
+     const int s = irow.getNumElements();
+     const int * indices = irow.getIndices();
+     double * elements = irow.getElements();
+     for(i=0; i<s; i++){
+	if (elements[i] < -epsilon_) {
+	   negative[indices[i]]= true; // store indicator of the sign 
+	   elements[i] *= -1;          // store only positive values
+	}
+    }
+  }
+
+  return 1;
+}
+
+
+//-------------------------------------------------------------------
+// power10ToMakeDoubleAnInt: 
+//   given a vector of positive doubles x_i, i=1, size, and a positive
+//   tolerance dataTol, determine the smallest power of 10 needed so that
+//   x[i]*10**power is integer for all i.
+
+//   dataTol_ should be correlated to the accuracy of the data,
+//   and choosen to be the largest value that's tolerable.
+//   
+//   (Easily extended to take an input vector of arbitrary sign)
+//-------------------------------------------------------------------
+//
+int
+CglSimpleRounding::power10ToMakeDoubleAnInt( 
+    int size,             // the length of the input vector x
+    const double * x,     // the input vector of postive values  
+    double dataTol) const // the (strictly postive) precision of the data
+
+{
+  // Assumption: data precision is positive
+  assert( dataTol > 0 );
+
+
+  int i;           // loop iterator 
+  int maxPower=0;  // maximum power of 10 used to convert any x[i] to an
+                   // integer 
+                   // this is the number we are after.
+  int power = 0;   // power of 10 used to convert a particular x[i] to an
+                   // integer 
+
+#ifdef OLD_MULT
+  double intPart;  // the integer part of the number
+#endif
+  double fracPart; // the fractional part of the number
+                   // we keep multiplying by 10 until the fractional part is 0
+                   // (well, really just until the factional part is less than
+                   // dataTol) 
+
+  // JJF - code seems to fail sometimes as multiplying by 10 - so
+  // definition of dataTol changed - see header file
+
+  const double multiplier[16]={1.0,1.0e1,1.0e2,1.0e3,1.0e4,1.0e5,
+			       1.0e6,1.0e7,1.0e8,1.0e9,1.0e10,1.0e11,
+			       1.0e12,1.0e13,1.0e14,1.0e15};
+
+  // Loop through every element in the array in x
+  for (i=0; i<size; i++){
+    power = 0;
+
+#ifdef OLD_MULT 
+    // look at the fractional part of x[i]
+    // FYI: if you want to modify this member function to take an input
+    // vector x of arbitary sign, change this line below to 
+    // fracPart = modf(fabs(x[i]),&intPart);
+    fracPart = modf(x[i],&intPart);
+
+    // if the fractional part is close enough to 0 or 1, we're done with this
+    // value
+    while(!(fracPart < dataTol || 1-fracPart < dataTol )) {
+       // otherwise, multiply by 10 and look at the fractional part of the
+       // result. 
+       ++power;
+       fracPart = fracPart*10.0;
+       fracPart = modf(fracPart,&intPart);     
+    }
+#else
+    // use fabs as safer and does no harm
+    double value = fabs(x[i]);
+    double scaledValue;
+    // Do loop - always using original value to stop round off error.
+    // If we don't find in 15 goes give up
+    for (power=0;power<16;power++) {
+      double tolerance = dataTol*multiplier[power];
+      scaledValue = value*multiplier[power];
+      fracPart = scaledValue-floor(scaledValue);
+      if(fracPart < tolerance || 1.0-fracPart < tolerance ) {
+	break;
+      }
+    }
+    if (power==16||scaledValue>2147483647) {
+#ifdef CGL_DEBUG
+      printf("Overflow %g => %g, power %d\n",x[i],scaledValue,power);
+#endif
+      return -1;
+    }
+#endif    
+#ifdef CGL_DEBUG
+    printf("The smallest power of 10 to make %g  integral = %i\n",x[i],power);
+#endif
+
+    
+    // keep track of the largest power needed so that at the end of the for
+    // loop
+    // x[i]*10**maxPower will be integral for all i
+    if (maxPower < power) maxPower=power;
+  }
+
+  return maxPower;
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglSimpleRounding::CglSimpleRounding ()
+:
+CglCutGenerator(),
+epsilon_(1.0e-08)
+{
+  // nothing to do here
+}
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglSimpleRounding::CglSimpleRounding (
+                  const CglSimpleRounding & source)
+:
+CglCutGenerator(source),
+epsilon_(source.epsilon_)
+{  
+  // Nothing to do here
+}
+
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglSimpleRounding::clone() const
+{
+  return new CglSimpleRounding(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglSimpleRounding::~CglSimpleRounding ()
+{
+  // Nothing to do here
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglSimpleRounding &
+CglSimpleRounding::operator=(
+                   const CglSimpleRounding& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    epsilon_=rhs.epsilon_;
+  }
+  return *this;
+}
+// Create C++ lines to get to current state
+std::string
+CglSimpleRounding::generateCpp( FILE * fp) 
+{
+  CglSimpleRounding other;
+  fprintf(fp,"0#include \"CglSimpleRounding.hpp\"\n");
+  fprintf(fp,"3  CglSimpleRounding simpleRounding;\n");
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  simpleRounding.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  simpleRounding.setAggressiveness(%d);\n",getAggressiveness());
+  return "simpleRounding";
+}
diff --git a/cbits/coin/CglSimpleRounding.hpp b/cbits/coin/CglSimpleRounding.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglSimpleRounding.hpp
@@ -0,0 +1,174 @@
+// $Id: CglSimpleRounding.hpp 1150 2013-10-21 18:24:45Z tkr $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglSimpleRounding_H
+#define CglSimpleRounding_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+#include "CoinPackedMatrix.hpp"
+
+/** Simple Rounding Cut Generator Class
+
+ This class generates simple rounding cuts via the following method:
+    For each contraint,
+      attempt to derive a <= inequality in all integer variables
+      by netting out any continuous variables.
+      Divide the resulting integer inequality through by 
+      the greatest common denomimator (gcd) of the lhs coefficients.
+      Round down the rhs.
+
+ Warning: Use with careful attention to data precision.
+
+ (Reference: Nemhauser and Wolsey, Integer and Combinatorial Optimization, 1988, pg 211.)
+*/
+
+class CglSimpleRounding : public CglCutGenerator {
+   friend void CglSimpleRoundingUnitTest(const OsiSolverInterface * siP,
+					 const std::string mpdDir );
+ 
+public:
+
+  /**@name Generate Cuts */
+  //@{
+  /** Generate simple rounding cuts for the model accessed through the solver interface. 
+  Insert generated cuts into the cut set cs.
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglSimpleRounding ();
+ 
+  /// Copy constructor 
+  CglSimpleRounding (
+    const CglSimpleRounding &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglSimpleRounding &
+    operator=(
+    const CglSimpleRounding& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglSimpleRounding ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  //@}
+
+private:
+  
+  // Private member methods
+   
+  /**@name Private methods */
+  //@{
+  
+  /// Derive a <= inequality in integer variables from the rowIndex-th constraint
+  bool deriveAnIntegerRow(
+                          const OsiSolverInterface & si,
+                          int rowIndex,
+                          const CoinShallowPackedVector & matrixRow, 
+                          CoinPackedVector & irow,
+                          double & b,
+                          bool * negative) const;
+  
+
+  /** Given a vector of doubles, x, with size elements and a positive tolerance,
+     dataTol, this method returns the smallest power of 10 needed so that
+     x[i]*10**power "is integer" for all i=0,...,size-1.
+  
+     ** change of definition of dataTol so that it refers to original
+     data, not to scaled data as that seems to lead to problems.
+
+     So if xScaled is x[i]*10**power and xInt is rounded(xScaled)
+     then fabs(xScaled-xInt) <= dataTol*10**power.  This means that
+     dataTol should be smaller - say 1.0e-12 rather tahn 1.0e-8
+
+     Returns -number of times overflowed  if the power is so big that it will
+     cause overflow (i.e. integer stored will be bigger than 2**31).
+     Test in cut generator.
+  */ 
+  int power10ToMakeDoubleAnInt( 
+       int size,               // the length of the vector x
+       const double * x,   
+       double dataTol ) const; // the precision of the data, i.e. the positive
+                               // epsilon, which is equivalent to zero
+
+  /**@name Greatest common denominators methods */
+  //@{
+  /// Returns the greatest common denominator of two positive integers, a and b.
+  inline  int gcd(int a, int b) const; 
+  
+  /** Returns the greatest common denominator of a vector of
+      positive integers, vi, of length n.
+  */
+  inline  int gcdv(int n, const int * const vi) const; 
+  //@}
+
+  //@}
+  
+  /**@name Private member data */
+  //@{
+  /// A value within an epsilon_ neighborhood of 0  is considered to be 0.
+  double epsilon_;
+  //@}
+};
+
+
+//-------------------------------------------------------------------
+// Returns the greatest common denominator of two 
+// positive integers, a and b, found using Euclid's algorithm 
+//-------------------------------------------------------------------
+int 
+CglSimpleRounding::gcd(int a, int b) const
+{
+  if(a > b) {
+    // Swap a and b
+    int temp = a;
+    a = b;
+    b = temp;
+  }
+  int remainder = b % a;
+  if (remainder == 0) return a;
+  else return gcd(remainder,a);
+}
+
+//-------------------------------------------------------------------
+// Returns the greatest common denominator of a vector of
+// positive integers, vi, of length n.
+//-------------------------------------------------------------------
+int 
+CglSimpleRounding::gcdv(int n, const int* const vi) const
+{
+  if (n==0)
+    abort();
+
+  if (n==1)
+    return vi[0];
+
+  int retval=gcd(vi[0], vi[1]);
+  for (int i=2; i<n; i++){
+     retval=gcd(retval,vi[i]);
+  }
+  return retval;
+}
+
+//#############################################################################
+/** A function that tests the methods in the CglSimpleRounding class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglSimpleRoundingUnitTest(const OsiSolverInterface * siP,
+			       const std::string mpdDir );
+  
+#endif
diff --git a/cbits/coin/CglStored.cpp b/cbits/coin/CglStored.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglStored.cpp
@@ -0,0 +1,397 @@
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+//#define CGL_DEBUG 2
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CglStored.hpp"
+#include "CglTreeInfo.hpp"
+#include "CoinFinite.hpp"
+//-------------------------------------------------------------------
+// Generate Stored cuts
+//------------------------------------------------------------------- 
+void 
+CglStored::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+			const CglTreeInfo /*info*/)
+{
+  // Get basic problem information
+  const double * solution = si.getColSolution();
+  int numberRowCuts = cuts_.sizeRowCuts();
+  for (int i=0;i<numberRowCuts;i++) {
+    const OsiRowCut * rowCutPointer = cuts_.rowCutPtr(i);
+    double violation = rowCutPointer->violated(solution);
+    if (violation>=requiredViolation_)
+      cs.insert(*rowCutPointer);
+  }
+  if (probingInfo_) {
+    int number01 = probingInfo_->numberIntegers();
+    const cliqueEntry * entry = probingInfo_->fixEntries();
+    const int * toZero = probingInfo_->toZero();
+    const int * toOne = probingInfo_->toOne();
+    const int * integerVariable = probingInfo_->integerVariable();
+    const double * lower = si.getColLower();
+    const double * upper = si.getColUpper();
+    OsiRowCut cut;
+    int column[2];
+    double element[2];
+    for (int i=0;i<number01;i++) {
+      int iColumn=integerVariable[i];
+      if (upper[iColumn]==lower[iColumn])
+	continue;
+      double value1 = solution[iColumn];
+      for (int j=toZero[i];j<toOne[i];j++) {
+	int jColumn=sequenceInCliqueEntry(entry[j]);
+	if (jColumn<number01) {
+	  jColumn=integerVariable[jColumn];
+	  assert (jColumn>=0);
+	  double value2 = solution[jColumn];
+	  if (oneFixesInCliqueEntry(entry[j])) {
+	    double violation = 1.0-value1-value2;
+	    if (violation>requiredViolation_) {
+	      //printf("XXX can do %d + %d >=1\n",iColumn,jColumn);
+	      cut.setLb(1.0);
+	      cut.setUb(COIN_DBL_MAX);
+	      column[0]=iColumn;
+	      element[0]=1.0;
+	      column[1]=jColumn;
+	      element[1]= 1.0;
+	      cut.setEffectiveness(violation);
+	      cut.setRow(2,column,element,false);
+	      cs.insert(cut);
+	    }
+	  } else {
+	    double violation = value2-value1;
+	    if (violation>requiredViolation_) {
+	      //printf("XXX can do %d >= %d\n",iColumn,jColumn);
+	      cut.setLb(0.0);
+	      cut.setUb(COIN_DBL_MAX);
+	      column[0]=iColumn;
+	      element[0]=1.0;
+	      column[1]=jColumn;
+	      element[1]= -1.0;
+	      cut.setEffectiveness(violation);
+	      cut.setRow(2,column,element,false);
+	      cs.insert(cut);
+	    }
+	  }
+	} else {
+	  jColumn -= number01; // not 0-1
+	  double value2 = solution[jColumn];
+	  double lowerValue = lower[jColumn];
+	  double upperValue = upper[jColumn];
+	  if (oneFixesInCliqueEntry(entry[j])) {
+	    double violation = upperValue-value1*(upperValue-lowerValue)-value2;
+	    if (violation>requiredViolation_) {
+	      //printf("XXX can do %g*%d + %d >=%g\n",(upperValue-lowerValue),iColumn,jColumn,upperValue);
+	      cut.setLb(upperValue);
+	      cut.setUb(COIN_DBL_MAX);
+	      column[0]=iColumn;
+	      element[0]=upperValue-lowerValue;
+	      column[1]=jColumn;
+	      element[1]= 1.0;
+	      cut.setEffectiveness(violation);
+	      cut.setRow(2,column,element,false);
+	      cs.insert(cut);
+	    }
+	  } else {
+	    double violation = value2-value1*(upperValue-lowerValue)-lowerValue;
+	    if (violation>requiredViolation_) {
+	      //printf("XXX can do %g*%d >= %d -%g\n",(upperValue-lowerValue),iColumn,jColumn,lowerValue);
+	      cut.setLb(-lowerValue);
+	      cut.setUb(COIN_DBL_MAX);
+	      column[0]=iColumn;
+	      element[0]=upperValue-lowerValue;
+	      column[1]=jColumn;
+	      element[1]= -1.0;
+	      cut.setEffectiveness(violation);
+	      cut.setRow(2,column,element,false);
+	      cs.insert(cut);
+	    }
+	  }
+	}
+      }
+      for (int j=toOne[i];j<toZero[i+1];j++) {
+	int jColumn=sequenceInCliqueEntry(entry[j]);
+	if (jColumn<number01) {
+	  jColumn=integerVariable[jColumn];
+	  assert (jColumn>=0);
+	  double value2 = solution[jColumn];
+	  if (oneFixesInCliqueEntry(entry[j])) {
+	    double violation = value1-value2;
+	    if (violation>requiredViolation_) {
+	      //printf("XXX can do %d <= %d\n",iColumn,jColumn);
+	      cut.setLb(-COIN_DBL_MAX);
+	      cut.setUb(0.0);
+	      column[0]=iColumn;
+	      element[0]=1.0;
+	      column[1]=jColumn;
+	      element[1]= -1.0;
+	      cut.setEffectiveness(violation);
+	      cut.setRow(2,column,element,false);
+	      cs.insert(cut);
+	    }
+	  } else {
+	    double violation = value1+value2-1.0;
+	    if (violation>requiredViolation_) {
+	      //printf("XXX can do %d + %d <=1\n",iColumn,jColumn);
+	      cut.setLb(-COIN_DBL_MAX);
+	      cut.setUb(1.0);
+	      column[0]=iColumn;
+	      element[0]=1.0;
+	      column[1]=jColumn;
+	      element[1]= 1.0;
+	      cut.setEffectiveness(violation);
+	      cut.setRow(2,column,element,false);
+	      cs.insert(cut);
+	    }
+	  }
+	} else {
+	  jColumn -= number01; // not 0-1
+	  double value2 = solution[jColumn];
+	  double lowerValue = lower[jColumn];
+	  double upperValue = upper[jColumn];
+	  if (oneFixesInCliqueEntry(entry[j])) {
+	    double violation = lowerValue +(upperValue-lowerValue)*value1-value2;
+	    if (violation>requiredViolation_) {
+	      //printf("XXX can do %g*%d <= %d -%g\n",(upperValue-lowerValue),iColumn,jColumn,lowerValue);
+	      cut.setLb(-COIN_DBL_MAX);
+	      cut.setUb(-lowerValue);
+	      column[0]=iColumn;
+	      element[0]=upperValue-lowerValue;
+	      column[1]=jColumn;
+	      element[1]= -1.0;
+	      cut.setEffectiveness(violation);
+	      cut.setRow(2,column,element,false);
+	      cs.insert(cut);
+	    }
+	  } else {
+	    double violation = (upperValue-lowerValue)*value1+value2-upperValue;
+	    if (violation>requiredViolation_) {
+	      //printf("XXX can do %g*%d + %d <=%g\n",(upperValue-lowerValue),iColumn,jColumn,upperValue);
+	      cut.setLb(-COIN_DBL_MAX);
+	      cut.setUb(upperValue);
+	      column[0]=iColumn;
+	      element[0]=upperValue-lowerValue;
+	      column[1]=jColumn;
+	      element[1]= 1.0;
+	      cut.setEffectiveness(violation);
+	      cut.setRow(2,column,element,false);
+	      cs.insert(cut);
+	    }
+	  }
+	}
+      }
+    }
+  }
+}
+// Add cuts
+void 
+CglStored::addCut(const OsiCuts & cs)
+{
+  int numberRowCuts = cs.sizeRowCuts();
+  for (int i=0;i<numberRowCuts;i++) {
+    cuts_.insert(*cs.rowCutPtr(i));
+  }
+}
+// Add a row cut
+void 
+CglStored::addCut(const OsiRowCut & cut)
+{
+  cuts_.insert(cut);
+}
+// Add a row cut from a packed vector
+void 
+CglStored::addCut(double lb, double ub, const CoinPackedVector & vector)
+{
+  OsiRowCut rc;
+  rc.setRow(vector);
+  rc.mutableRow().setTestForDuplicateIndex(false);
+  rc.setLb(lb);
+  rc.setUb(ub);   
+  cuts_.insert(rc);
+}
+// Add a row cut from elements
+void 
+CglStored::addCut(double lb, double ub, int size, const int * colIndices, const double * elements)
+{
+  OsiRowCut rc;
+  rc.setRow(size,colIndices,elements,false);
+  rc.setLb(lb);
+  rc.setUb(ub);   
+  cuts_.insert(rc);
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglStored::CglStored (int numberColumns)
+:
+  CglCutGenerator(),
+  requiredViolation_(1.0e-5),
+  probingInfo_(NULL),
+  numberColumns_(numberColumns),
+  bestSolution_(NULL),
+  bounds_(NULL)
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglStored::CglStored (const CglStored & source) :
+  CglCutGenerator(source),
+  requiredViolation_(source.requiredViolation_),
+  probingInfo_(NULL),
+  cuts_(source.cuts_),
+  numberColumns_(source.numberColumns_),
+  bestSolution_(NULL),
+  bounds_(NULL)
+{  
+  if (source.probingInfo_)
+    probingInfo_ = new CglTreeProbingInfo(*source.probingInfo_);
+  if (numberColumns_) {
+    bestSolution_ = CoinCopyOfArray(source.bestSolution_,numberColumns_+1);
+    bounds_ = CoinCopyOfArray(source.bounds_,2*numberColumns_);
+  }
+}
+//-------------------------------------------------------------------
+// Constructor from file
+//-------------------------------------------------------------------
+CglStored::CglStored (const char * fileName) :
+  CglCutGenerator(),
+  requiredViolation_(1.0e-5),
+  probingInfo_(NULL),
+  numberColumns_(0),
+  bestSolution_(NULL),
+  bounds_(NULL)
+{  
+  FILE * fp = fopen(fileName,"rb");
+  if (fp) {
+#ifndef NDEBUG
+    size_t numberRead;
+#endif
+    int maxInCut=0;
+    int * index = NULL;
+    double * coefficient = NULL;
+    double rhs[2];
+    int n=0;
+    while (n>=0) {
+#ifndef NDEBUG
+      numberRead = fread(&n,sizeof(int),1,fp);
+      assert (numberRead==1);
+#else
+      fread(&n,sizeof(int),1,fp);
+#endif
+      if (n<0)
+	break;
+      if (n>maxInCut) {
+	maxInCut=n;
+	delete [] index;
+	delete [] coefficient;
+	index = new int [maxInCut];
+	coefficient = new double [maxInCut];
+      }
+#ifndef NDEBUG
+      numberRead = fread(rhs,sizeof(double),2,fp);
+      assert (numberRead==2);
+#else
+      fread(rhs,sizeof(double),2,fp);
+#endif
+      fread(index,sizeof(int),n,fp);
+      fread(coefficient,sizeof(double),n,fp);
+      OsiRowCut rc;
+      rc.setRow(n,index,coefficient,false);
+      rc.setLb(rhs[0]);
+      rc.setUb(rhs[1]);   
+      cuts_.insert(rc);
+    }
+    delete [] index;
+    delete [] coefficient;
+    fclose(fp);
+  }
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglStored::clone() const
+{
+  return new CglStored(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglStored::~CglStored ()
+{
+  delete  probingInfo_;
+  delete [] bestSolution_;
+  delete [] bounds_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglStored &
+CglStored::operator=(const CglStored& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    requiredViolation_=rhs.requiredViolation_;
+    cuts_=rhs.cuts_;
+    delete probingInfo_;
+    if (rhs.probingInfo_)
+      probingInfo_ = new CglTreeProbingInfo(*rhs.probingInfo_);
+    else
+      probingInfo_ = NULL;
+    delete [] bestSolution_;
+    delete [] bounds_;
+    bestSolution_ = NULL;
+    bounds_ = NULL;
+    numberColumns_ = rhs.numberColumns_;
+    if (numberColumns_) {
+      bestSolution_ = CoinCopyOfArray(rhs.bestSolution_,numberColumns_+1);
+      bounds_ = CoinCopyOfArray(rhs.bounds_,2*numberColumns_);
+    }
+  }
+  return *this;
+}
+// Save stuff
+void 
+CglStored::saveStuff(double bestObjective, const double * bestSolution,
+		     const double * lower, const double * upper)
+{
+  assert (numberColumns_);
+  delete [] bestSolution_;
+  delete [] bounds_;
+  if (bestSolution) {
+    bestSolution_ = new double[numberColumns_+1];
+    memcpy(bestSolution_,bestSolution,numberColumns_*sizeof(double));
+    bestSolution_[numberColumns_]=bestObjective;
+  } else {
+    bestSolution_=NULL;
+  }
+  bounds_ = new double [2*numberColumns_];
+  memcpy(bounds_,lower,numberColumns_*sizeof(double));
+  memcpy(bounds_+numberColumns_,upper,numberColumns_*sizeof(double));
+}
+// Best objective
+double 
+CglStored::bestObjective() const
+{
+  if (bestSolution_)
+    return bestSolution_[numberColumns_];
+  else
+    return COIN_DBL_MAX;
+}
diff --git a/cbits/coin/CglStored.hpp b/cbits/coin/CglStored.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglStored.hpp
@@ -0,0 +1,125 @@
+// $Id: CglStored.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglStored_H
+#define CglStored_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+
+class CoinWarmStartBasis;
+class CglTreeProbingInfo;
+/** Stored Cut Generator Class */
+class CglStored : public CglCutGenerator {
+ 
+public:
+    
+  
+  /**@name Generate Cuts */
+  //@{
+  /** Generate Mixed Integer Stored cuts for the model of the 
+      solver interface, si.
+
+      Insert the generated cuts into OsiCut, cs.
+
+      This generator just looks at previously stored cuts
+      and inserts any that are violated by enough
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+  /**@name Change criterion on whether to include cut.
+   Violations of more than this will be added to current cut list
+  (default 1.0e-5) */
+  //@{
+  /// Set
+  inline void setRequiredViolation(double value)
+  { requiredViolation_=value;}
+  /// Get
+  inline double getRequiredViolation() const
+  { return requiredViolation_;}
+  /// Takes over ownership of probing info
+  inline void setProbingInfo(CglTreeProbingInfo * info)
+  { probingInfo_ = info;}
+  //@}
+
+  /**@name Cut stuff */
+  //@{
+  /// Add cuts
+  void addCut(const OsiCuts & cs);
+  /// Add a row cut
+  void addCut(const OsiRowCut & cut);
+  /// Add a row cut from a packed vector
+  void addCut(double lb, double ub, const CoinPackedVector & vector);
+  /// Add a row cut from elements
+  void addCut(double lb, double ub, int size, const int * colIndices, const double * elements);
+  inline int sizeRowCuts() const
+  { return cuts_.sizeRowCuts();}
+  const OsiRowCut * rowCutPointer(int index) const
+  { return cuts_.rowCutPtr(index);}
+  /// Save stuff
+  void saveStuff(double bestObjective, const double * bestSolution,
+		 const double * lower, const double * upper);
+  /// Best solution (or NULL)
+  inline const double * bestSolution() const
+  { return bestSolution_;}
+  /// Best objective
+  double bestObjective() const;
+  /// Tight lower bounds
+  const double * tightLower() const
+  { return bounds_;} 
+  /// Tight upper bounds
+  const double * tightUpper() const
+  { return bounds_+numberColumns_;} 
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglStored (int numberColumns=0);
+ 
+  /// Copy constructor 
+  CglStored (const CglStored & rhs);
+
+  /// Constructor from file
+  CglStored (const char * fileName);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglStored &
+    operator=(const CglStored& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglStored ();
+  //@}
+      
+protected:
+  
+ // Protected member methods
+
+  // Protected member data
+
+  /**@name Protected member data */
+  //@{
+  /// Only add if more than this requiredViolation
+  double requiredViolation_;
+  /// Pointer to probing information
+  CglTreeProbingInfo * probingInfo_;
+  /// Cuts
+  OsiCuts cuts_;
+  /// Number of columns in model
+  int numberColumns_;
+  /// Best solution (objective at end)
+  double * bestSolution_;
+  /// Tight bounds
+  double * bounds_;
+  //@}
+};
+#endif
diff --git a/cbits/coin/CglTreeInfo.cpp b/cbits/coin/CglTreeInfo.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglTreeInfo.cpp
@@ -0,0 +1,1717 @@
+// $Id: CglTreeInfo.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CglTreeInfo.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinSort.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CglStored.hpp"
+#include "OsiRowCut.hpp"
+
+// Default constructor 
+CglTreeInfo::CglTreeInfo ()
+  : level(-1), pass(-1), formulation_rows(-1), options(0), inTree(false),
+    strengthenRow(NULL),randomNumberGenerator(NULL) {}
+
+// Copy constructor 
+CglTreeInfo::CglTreeInfo (const CglTreeInfo & rhs)
+  : level(rhs.level), 
+    pass(rhs.pass), 
+    formulation_rows(rhs.formulation_rows), 
+    options(rhs.options),
+    inTree(rhs.inTree),
+    strengthenRow(rhs.strengthenRow),
+    randomNumberGenerator(rhs.randomNumberGenerator)
+{
+}
+// Clone
+CglTreeInfo * 
+CglTreeInfo::clone() const
+{
+  return new CglTreeInfo(*this);
+}
+
+// Assignment operator 
+CglTreeInfo &
+CglTreeInfo::operator=(const CglTreeInfo& rhs)
+{
+  if (this != &rhs) {
+    //CglCutGenerator::operator=(rhs);
+    level = rhs.level; 
+    pass = rhs.pass; 
+    formulation_rows = rhs.formulation_rows; 
+    options = rhs.options;
+    inTree = rhs.inTree;
+    strengthenRow = rhs.strengthenRow;
+    randomNumberGenerator = rhs.randomNumberGenerator;
+  }
+  return *this;
+}
+  
+ // Destructor 
+CglTreeInfo::~CglTreeInfo ()
+{
+}
+
+// Default constructor 
+CglTreeProbingInfo::CglTreeProbingInfo ()
+  : CglTreeInfo(),
+    fixEntry_(NULL),
+    toZero_(NULL),
+    toOne_(NULL),
+    integerVariable_(NULL),
+    backward_(NULL),
+    fixingEntry_(NULL),
+    numberVariables_(0),
+    numberIntegers_(0),
+    maximumEntries_(0),
+    numberEntries_(-1)
+{
+}
+// Constructor from model
+CglTreeProbingInfo::CglTreeProbingInfo (const OsiSolverInterface * model)
+  : CglTreeInfo(),
+    fixEntry_(NULL),
+    toZero_(NULL),
+    toOne_(NULL),
+    integerVariable_(NULL),
+    backward_(NULL),
+    fixingEntry_(NULL),
+    numberVariables_(0),
+    numberIntegers_(0),
+    maximumEntries_(0),
+    numberEntries_(-1)
+{
+  numberVariables_=model->getNumCols(); 
+  // Too many ... but
+  integerVariable_ = new int [numberVariables_];
+  backward_ = new int [numberVariables_];
+  int i;
+  // Get integer types
+  const char * columnType = model->getColType (true);
+  for (i=0;i<numberVariables_;i++) {
+    backward_[i]=-1;
+    if (columnType[i]) {
+      if (columnType[i]==1) {
+	backward_[i]=numberIntegers_;
+	integerVariable_[numberIntegers_++]=i;
+      } else {
+	backward_[i]=-2;
+      }
+    }
+  }
+  // Set up to arrays
+  toOne_ = new int[numberIntegers_];
+  toZero_ = new int[numberIntegers_+1];
+  // zero out
+  CoinZeroN(toOne_,numberIntegers_);
+  CoinZeroN(toZero_,numberIntegers_+1);
+}
+
+// Copy constructor 
+CglTreeProbingInfo::CglTreeProbingInfo (const CglTreeProbingInfo & rhs)
+  : CglTreeInfo(rhs),
+    fixEntry_(NULL),
+    toZero_(NULL),
+    toOne_(NULL),
+    integerVariable_(NULL),
+    backward_(NULL),
+    fixingEntry_(NULL),
+    numberVariables_(rhs.numberVariables_),
+    numberIntegers_(rhs.numberIntegers_),
+    maximumEntries_(rhs.maximumEntries_),
+    numberEntries_(rhs.numberEntries_)
+{
+  if (numberVariables_) {
+    fixEntry_ = new cliqueEntry [maximumEntries_];
+    memcpy(fixEntry_,rhs.fixEntry_,maximumEntries_*sizeof(cliqueEntry));
+    if (numberEntries_<0) {
+      // in order
+      toZero_ = CoinCopyOfArray(rhs.toZero_,numberIntegers_+1);
+      toOne_ = CoinCopyOfArray(rhs.toOne_,numberIntegers_);
+    } else {
+      // not in order
+      fixingEntry_ = CoinCopyOfArray(rhs.fixingEntry_,maximumEntries_);
+    }
+    integerVariable_ = CoinCopyOfArray(rhs.integerVariable_,numberIntegers_);
+    backward_ = CoinCopyOfArray(rhs.backward_,numberVariables_);
+  }
+}
+// Clone
+CglTreeInfo * 
+CglTreeProbingInfo::clone() const
+{
+  return new CglTreeProbingInfo(*this);
+}
+
+// Assignment operator 
+CglTreeProbingInfo &
+CglTreeProbingInfo::operator=(const CglTreeProbingInfo& rhs)
+{
+  if (this != &rhs) {
+    CglTreeInfo::operator=(rhs);
+    delete [] fixEntry_;
+    delete [] toZero_;
+    delete [] toOne_;
+    delete [] integerVariable_;
+    delete [] backward_;
+    delete [] fixingEntry_;
+    numberVariables_ = rhs.numberVariables_;
+    numberIntegers_ = rhs.numberIntegers_;
+    maximumEntries_ = rhs.maximumEntries_;
+    numberEntries_ = rhs.numberEntries_;
+    if (numberVariables_) {
+      fixEntry_ = new cliqueEntry [maximumEntries_];
+      memcpy(fixEntry_,rhs.fixEntry_,maximumEntries_*sizeof(cliqueEntry));
+      if (numberEntries_<0) {
+	// in order
+	toZero_ = CoinCopyOfArray(rhs.toZero_,numberIntegers_+1);
+	toOne_ = CoinCopyOfArray(rhs.toOne_,numberIntegers_);
+	fixingEntry_ = NULL;
+      } else {
+	// not in order
+	fixingEntry_ = CoinCopyOfArray(rhs.fixingEntry_,maximumEntries_);
+	toZero_ = NULL;
+	toOne_ = NULL;
+      }
+      toZero_ = CoinCopyOfArray(rhs.toZero_,numberIntegers_+1);
+      toOne_ = CoinCopyOfArray(rhs.toOne_,numberIntegers_);
+      integerVariable_ = CoinCopyOfArray(rhs.integerVariable_,numberIntegers_);
+      backward_ = CoinCopyOfArray(rhs.backward_,numberVariables_);
+    } else {
+      fixEntry_ = NULL;
+      toZero_ = NULL;
+      toOne_ = NULL;
+      integerVariable_ = NULL;
+      backward_ = NULL;
+      fixingEntry_ = NULL;
+    }
+  }
+  return *this;
+}
+  
+ // Destructor 
+CglTreeProbingInfo::~CglTreeProbingInfo ()
+{
+  delete [] fixEntry_;
+  delete [] toZero_;
+  delete [] toOne_;
+  delete [] integerVariable_;
+  delete [] backward_;
+  delete [] fixingEntry_;
+}
+static int outDupsEtc(int numberIntegers, int & numberCliques, int & numberMatrixCliques,
+		      int * & cliqueStart, char * & cliqueType, cliqueEntry *& entry, 
+		      int numberLastTime, int printit)
+{
+  bool allNew=false;
+  int * whichP = new int [numberIntegers];
+  int iClique;
+  assert (sizeof(int)==4);
+  assert (sizeof(cliqueEntry)==4);
+  // If lots then get rid of short ones
+#define KEEP_CLIQUES 10000
+  if (numberCliques-numberMatrixCliques>KEEP_CLIQUES) {
+    int * sort = new int [numberCliques];
+    for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) {
+      int j = cliqueStart[iClique];
+      int n = cliqueStart[iClique+1]-j;
+      sort[iClique]=n;
+    }
+    std::sort(sort+numberMatrixCliques,sort+numberCliques);
+    int allow = sort[numberCliques-KEEP_CLIQUES];
+    int nEqual=0;
+    for (iClique=numberCliques-KEEP_CLIQUES;iClique<numberCliques;iClique++) {
+      if (sort[iClique]>allow)
+	break;
+      else
+	nEqual++;
+    }
+    delete [] sort;
+    int j=cliqueStart[numberMatrixCliques];
+    int put=j;
+    int nClique=numberMatrixCliques;
+    for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) {
+      int end = cliqueStart[iClique+1];
+      int n = end-j;
+      bool copy=false;
+      if (n>allow) {
+	copy=true;
+      } else if (n==allow&&nEqual) {
+	copy=true;
+	nEqual--;
+      }
+      if (copy) {
+	cliqueType[nClique++]=cliqueType[iClique];
+	for (;j<end;j++)
+	  entry[put++]=entry[j];
+      }
+      j = cliqueStart[iClique+1];
+      cliqueStart[nClique]=put;
+    }
+    numberCliques = nClique;
+  }
+  // sort
+  for (iClique=0;iClique<numberCliques;iClique++) {
+    int j = cliqueStart[iClique];
+    int n = cliqueStart[iClique+1]-j;
+    for (int i=0;i<n;i++) 
+      whichP[i]=sequenceInCliqueEntry(entry[i+j]);
+    CoinSort_2(whichP,whichP+n,(reinterpret_cast<int *>(entry))+j);
+  }
+  // lexicographic sort
+  int * which = new int [numberCliques];
+  int * position = new int [numberCliques];
+  int * sort = new int [numberCliques];
+  int * value = new int [numberCliques];
+  for (iClique=0;iClique<numberCliques;iClique++) {
+    which[iClique]=iClique;
+    sort[iClique]=sequenceInCliqueEntry(entry[cliqueStart[iClique]]);
+    value[iClique]=sort[iClique];
+    position[iClique]=0;
+  }
+  CoinSort_2(sort,sort+numberCliques,which);
+  int lastDone=-1;
+  int nDup=0;
+  int nSave=0;
+  while (lastDone<numberCliques-1) {
+    int jClique=lastDone+1;
+    int jFirst = jClique;
+    int iFirst = which[jFirst];
+    int iValue = value[iFirst];
+    int iPos = position[iFirst];
+    jClique++;
+    for (;jClique<numberCliques;jClique++) {
+      int kClique = which[jClique];
+      int jValue = value[kClique];
+      if (jValue>iValue||position[kClique]<iPos)
+	break;
+    }
+    if (jClique==jFirst+1) {
+      // done that bit
+      lastDone++;
+    } else {
+      // use next bit to sort and then repeat
+      int jLast=jClique;
+      for (jClique=jFirst;jClique<jLast;jClique++) {
+	int kClique = which[jClique];
+	int iValue = value[kClique];
+	// put at end if finished
+	if (iValue<numberIntegers) {
+	  int kPos=position[kClique]+1;
+	  position[kClique]=kPos;
+	  kPos += cliqueStart[kClique];
+	  if (kPos==cliqueStart[kClique+1]) {
+	    iValue = numberIntegers;
+	  } else {
+	    iValue = sequenceInCliqueEntry(entry[kPos]);
+	  }
+	  value[kClique]=iValue;
+	}
+	sort[jClique]=iValue;
+      }
+      CoinSort_2(sort+jFirst,sort+jLast,which+jFirst);
+      // if duplicate mark and move on
+      int iLowest=numberCliques;
+      for (jClique=jFirst;jClique<jLast;jClique++) {
+	int kClique = which [jClique];
+	int iValue = value[kClique];
+	if (iValue<numberIntegers) 
+	  break;
+	iLowest = CoinMin(iLowest,kClique);
+      }
+      if (jClique>jFirst) {
+	// mark all apart from lowest number as duplicate and move on
+	lastDone =jClique-1;
+	for (jClique=jFirst;jClique<=lastDone;jClique++) {
+	  int kClique = which [jClique];
+	  if (kClique!=iLowest) {
+	    value[kClique]=-2;
+	    nDup++;
+	    nSave += cliqueStart[kClique+1]-cliqueStart[kClique];
+	  }
+	}
+      }
+    }
+  }
+  if (printit)
+    printf("%d duplicates\n",nDup);
+  // Now see if any subset
+  int nOut=0;
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    if (value[jClique]!=-2) {
+      position[jClique]=cliqueStart[jClique];
+      value[jClique]=sequenceInCliqueEntry(entry[cliqueStart[jClique]]);
+    }
+  }
+  nSave=0;
+  int startLooking=0;
+  for (int jClique=0;jClique<numberCliques;jClique++) {
+    int kClique = which[jClique];
+    if (value[kClique]==-2) {
+      nOut++;
+      nSave += cliqueStart[kClique+1]-cliqueStart[kClique];
+      if (jClique==startLooking)
+	startLooking++;
+      continue;
+    }
+    int kValue =value[kClique];
+    for (int iiClique=startLooking;iiClique<jClique;iiClique++) {
+      int iClique = which[iiClique];
+      int iValue = value[iClique];
+      if (iValue==-2||iValue==numberIntegers) {
+	if (iiClique==startLooking)
+	  startLooking++;
+	continue;
+      } else {
+	if (kValue>static_cast<int> (sequenceInCliqueEntry(entry[cliqueStart[iClique+1]-1]))) {
+	  value[iClique]=numberIntegers;
+	  continue;
+	}
+      }
+      if (iValue<kValue) {
+	while (iValue<kValue) {
+	  int iPos=position[iClique]+1;
+	  position[iClique]=iPos;
+	  if (iPos==cliqueStart[iClique+1]) {
+	    iValue = numberIntegers;
+	  } else {
+	    iValue = sequenceInCliqueEntry(entry[iPos]);
+	  }
+	  value[iClique]=iValue;
+	}
+      } 
+      if (iValue>kValue) 
+	continue; // not a candidate
+      // See if subset (remember duplicates have gone)
+      if (cliqueStart[iClique+1]-position[iClique]>
+	  cliqueStart[kClique+1]-cliqueStart[kClique]) {
+	// could be subset ?
+	int offset = cliqueStart[iClique]-position[kClique];
+	int j;
+	bool subset=true;
+	// what about different fixes bool odd=false;
+	for (j=cliqueStart[kClique]+1;j<cliqueStart[kClique+1];j++) {
+	  int kColumn = sequenceInCliqueEntry(entry[j]);
+	  int iColumn = sequenceInCliqueEntry(entry[j+offset]);
+	  if (iColumn>kColumn) {
+	    subset=false;
+	  } else {
+	    while (iColumn<kColumn) {
+	      offset++;
+	      if (j+offset<cliqueStart[iClique+1]) {
+		iColumn = sequenceInCliqueEntry(entry[j+offset]);
+	      } else {
+		subset=false;
+		break;
+	      }
+	    }
+	  }
+	  if (!subset)
+	    break;
+	}
+	if (subset) {
+	  value[kClique]=-2;
+	  if (printit>1)
+	    printf("clique %d is subset of %d\n",kClique,iClique);
+	  nOut++;
+	  break;
+	}
+      }
+    }
+  }
+  if (nOut) {
+    if(printit) 
+      printf("Can get rid of %d cliques\n",nOut);
+    // make new copy
+    int nNewC=numberCliques-nOut;
+    int size = cliqueStart[numberCliques]-nSave;
+    int n=0;
+    int * start = new int [nNewC+1];
+    char * type = new char [nNewC];
+    start[0]=0;
+    cliqueEntry * entryC = new cliqueEntry [size];
+    int nel=0;
+    allNew = true;
+    for (int jClique=0;jClique<numberCliques;jClique++) {
+      int kClique = which[jClique];
+      if (value[kClique]!=-2&&kClique<numberMatrixCliques) {
+	if (kClique>=numberLastTime)
+	  allNew=false;
+	int nn=cliqueStart[kClique+1]-cliqueStart[kClique];
+	memcpy(entryC+nel,entry+cliqueStart[kClique],nn*sizeof(cliqueEntry));
+	nel += nn;
+	type[n++]=cliqueType[kClique];
+	start[n]=nel;
+      }
+    }
+    int nM=n;
+    for (int jClique=0;jClique<numberCliques;jClique++) {
+      int kClique = which[jClique];
+      if (value[kClique]!=-2&&kClique>=numberMatrixCliques) {
+	if (kClique>=numberLastTime)
+	  allNew=false;
+	int nn=cliqueStart[kClique+1]-cliqueStart[kClique];
+	memcpy(entryC+nel,entry+cliqueStart[kClique],nn*sizeof(cliqueEntry));
+	nel += nn;
+	type[n++]=cliqueType[kClique];
+	start[n]=nel;
+      }
+    }
+    // move
+    numberCliques=n;
+    numberMatrixCliques=nM;
+    delete [] cliqueStart;
+    cliqueStart=start;
+    delete [] entry;
+    entry = entryC;
+    delete [] cliqueType;
+    cliqueType = type;
+    if (printit>1) {
+      for (int jClique=0;jClique<numberCliques;jClique++) {
+	printf("%d [ ",jClique);
+	for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++)
+	  printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i]));
+	printf("]\n");
+      }
+    }
+    if (printit)
+      printf("%d matrix cliques and %d found by probing\n",numberMatrixCliques,numberCliques-numberMatrixCliques);
+  }
+  delete [] value;
+  delete [] sort;
+  delete [] which;
+  delete [] position;
+  delete [] whichP;
+  if (!allNew)
+    return nOut;
+  else
+    return -1;
+}
+OsiSolverInterface *
+CglTreeProbingInfo::analyze(const OsiSolverInterface & si,int createSolver)
+{
+  if (!createSolver)
+    return NULL;
+  convert();
+  if (!numberIntegers_)
+    return NULL;
+  bool printit=false;
+  int numberCliques=0;
+  int numberEntries=0;
+  int * cliqueStart = NULL;
+  cliqueEntry * entry = NULL;
+  char * cliqueType=NULL;
+  int * whichP = new int [numberIntegers_];
+  int * whichM = new int [numberIntegers_];
+  int *whichClique=NULL;
+  int numberRows=si.getNumRows(); 
+  int numberMatrixCliques=0;
+  const CoinPackedMatrix * rowCopy = si.getMatrixByRow();
+  assert(numberRows&&si.getNumCols());
+  int iRow;
+  const int * column = rowCopy->getIndices();
+  const double * elementByRow = rowCopy->getElements();
+  const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+  const int * rowLength = rowCopy->getVectorLengths(); 
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+  const double * rowLower = si.getRowLower();
+  const double * rowUpper = si.getRowUpper();
+  for (int iPass=0;iPass<2;iPass++) {
+    if (iPass) {
+      cliqueStart = new int [numberCliques+1];
+      cliqueStart[0]=0;
+      entry = new cliqueEntry [numberEntries];
+      cliqueType = new char [numberCliques];
+      whichClique = new int [numberEntries];
+      numberCliques=0;
+      numberEntries=0;
+    }
+#if 1
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int numberP1=0, numberM1=0;
+      int numberTotal=0;
+      CoinBigIndex j;
+      double upperValue=rowUpper[iRow];
+      double lowerValue=rowLower[iRow];
+      bool good=true;
+      for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) {
+	int iColumn = column[j];
+	double value = elementByRow[j];
+	if (upper[iColumn]-lower[iColumn]<1.0e-8) {
+	  // fixed
+	  upperValue -= lower[iColumn]*value;
+	  lowerValue -= lower[iColumn]*value;
+	  continue;
+	} else if (backward_[iColumn]<0) {
+	  good = false;
+	  break;
+	} else {
+	  iColumn = backward_[iColumn];
+	  numberTotal++;
+	}
+	if (fabs(value)!=1.0) {
+	  good=false;
+	} else if (value>0.0) {
+	  assert (numberP1<numberIntegers_);
+	  whichP[numberP1++]=iColumn;;
+	} else {
+	  assert (numberM1<numberIntegers_);
+	  whichM[numberM1++]=iColumn;
+	}
+      }
+      int iUpper = static_cast<int> (floor(upperValue+1.0e-5));
+      int iLower = static_cast<int> (ceil(lowerValue-1.0e-5));
+      int state=0;
+      if (upperValue<1.0e6) {
+	if (iUpper==1-numberM1)
+	  state=1;
+	else if (iUpper==-numberM1)
+	  state=2;
+	else if (iUpper<-numberM1)
+	  state=3;
+	if (fabs(static_cast<double> (iUpper)-upperValue)>1.0e-9)
+	  state =-1;
+      }
+      if (!state&&lowerValue>-1.0e6) {
+	if (-iLower==1-numberP1)
+	  state=-1;
+	else if (-iLower==-numberP1)
+	  state=-2;
+	else if (-iLower<-numberP1)
+	  state=-3;
+	if (fabs(static_cast<double> (iLower)-lowerValue)>1.0e-9)
+	  state =-1;
+      }
+      if (numberP1+numberM1<2)
+	state=-1;
+      if (good&&state>0) {
+	if (abs(state)==3) {
+	  // infeasible
+	  printf("FFF Infeasible\n");;
+	  //feasible=false;
+	  break;
+	} else if (abs(state)==2) {
+	  // we can fix all
+	  //numberFixed += numberP1+numberM1;
+	  printf("FFF can fix %d\n",numberP1+numberM1);
+	} else {
+	  for (j=0;j<numberP1;j++) {
+	    int iColumn = whichP[j];
+	    if (iPass) {
+	      cliqueEntry temp;
+	      setOneFixesInCliqueEntry(temp,true);
+	      setSequenceInCliqueEntry(temp,iColumn);
+	      entry[numberEntries]=temp;
+	    }
+	    numberEntries++;
+	  }
+	  for (j=0;j<numberM1;j++) {
+	    int iColumn = whichM[j];
+	    if (iPass) {
+	      cliqueEntry temp;
+	      setOneFixesInCliqueEntry(temp,false);
+	      setSequenceInCliqueEntry(temp,iColumn);
+	      entry[numberEntries]=temp;
+	    }
+	    numberEntries++;
+	  }
+	  if (iPass) {
+	    if (iLower!=iUpper) {
+	      // slack
+	      cliqueType[numberCliques]='S';
+	    } else {
+	      cliqueType[numberCliques]='E';
+	    }
+	    cliqueStart[numberCliques+1]=numberEntries;
+	  }
+	  numberCliques++;
+	}
+      }
+    }
+#endif
+    numberMatrixCliques=numberCliques;
+    //int size = toZero_[numberIntegers_];
+    //char * used = new char [size];
+    //memset(used,0,size);
+    // find two cliques
+    int nFix=0;
+    for (int iColumn=0;iColumn<static_cast<int> (numberIntegers_);iColumn++) {
+      int j;
+      for ( j=toZero_[iColumn];j<toOne_[iColumn];j++) {
+	int jColumn=sequenceInCliqueEntry(fixEntry_[j]);
+	// just look at ones beore (this also skips non 0-1)
+	if (jColumn<iColumn) {
+	  int k;
+	  for ( k=toZero_[jColumn];k<toOne_[jColumn];k++) {
+	    if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) {
+	      if (oneFixesInCliqueEntry(fixEntry_[j])) {
+		if (oneFixesInCliqueEntry(fixEntry_[k])) {
+		  if (printit&&!iPass)
+		    printf("%d to zero implies %d to one and %d to zero implies %d to one\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  //0-0 illegal
+		  if (iPass) {
+		    cliqueEntry temp;
+		    setOneFixesInCliqueEntry(temp,false);
+		    setSequenceInCliqueEntry(temp,iColumn);
+		    entry[numberEntries]=temp;
+		  }
+		  numberEntries++;
+		  if (iPass) {
+		    cliqueEntry temp;
+		    setOneFixesInCliqueEntry(temp,false);
+		    setSequenceInCliqueEntry(temp,jColumn);
+		    entry[numberEntries]=temp;
+		  }
+		  numberEntries++;
+		  if (iPass) {
+		    // slack
+		    cliqueType[numberCliques]='S';
+		    cliqueStart[numberCliques+1]=numberEntries;
+		  }
+		  numberCliques++;
+		} else {
+		  if (printit&&!iPass)
+		    printf("%d to zero implies %d to one and %d to zero implies %d to zero\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // jColumn is 1
+		}
+	      } else {
+		if (oneFixesInCliqueEntry(fixEntry_[k])) {
+		  if (printit&&!iPass)
+		    printf("%d to zero implies %d to zero and %d to zero implies %d to one\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // iColumn is 1
+		} else {
+		  if (printit&&!iPass)
+		    printf("%d to zero implies %d to zero and %d to zero implies %d to zero\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // jColumn=iColumn
+		}
+	      }
+	    }
+	  }
+	  for ( k=toOne_[jColumn];k<toZero_[jColumn+1];k++) {
+	    if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) {
+	      if (oneFixesInCliqueEntry(fixEntry_[j])) {
+		if (oneFixesInCliqueEntry(fixEntry_[k])) {
+		  if (printit&&!iPass)
+		    printf("%d to zero implies %d to one and %d to one implies %d to one\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; //iColumn is 1
+		} else {
+		  if (printit&&!iPass)
+		    printf("%d to zero implies %d to one and %d to one implies %d to zero\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // iColumn+jcolumn=1
+		}
+	      } else {
+		if (oneFixesInCliqueEntry(fixEntry_[k])) {
+		  if (printit&&!iPass)
+		    printf("%d to zero implies %d to zero and %d to one implies %d to one\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  // 0-1 illegal
+		  if (iPass) {
+		    cliqueEntry temp;
+		    setOneFixesInCliqueEntry(temp,false);
+		    setSequenceInCliqueEntry(temp,iColumn);
+		    entry[numberEntries]=temp;
+		  }
+		  numberEntries++;
+		  if (iPass) {
+		    cliqueEntry temp;
+		    setOneFixesInCliqueEntry(temp,true);
+		    setSequenceInCliqueEntry(temp,jColumn);
+		    entry[numberEntries]=temp;
+		  }
+		  numberEntries++;
+		  if (iPass) {
+		    // slack
+		    cliqueType[numberCliques]='S';
+		    cliqueStart[numberCliques+1]=numberEntries;
+		  }
+		  numberCliques++;
+		} else {
+		  if (printit&&!iPass)
+		    printf("%d to zero implies %d to zero and %d to one implies %d to zero\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // jColumn is 0
+		}
+	      }
+	    }
+	  }
+	}
+      }
+      for ( j=toOne_[iColumn];j<toZero_[iColumn+1];j++) {
+	int jColumn=sequenceInCliqueEntry(fixEntry_[j]);
+	if (jColumn<iColumn) {
+	  int k;
+	  for ( k=toZero_[jColumn];k<toOne_[jColumn];k++) {
+	    if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) {
+	      if (oneFixesInCliqueEntry(fixEntry_[j])) {
+		if (oneFixesInCliqueEntry(fixEntry_[k])) {
+		  if (printit&&!iPass)
+		    printf("%d to one implies %d to one and %d to zero implies %d to one\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // jColumn is 1
+		} else {
+		  if (printit&&!iPass)
+		    printf("%d to one implies %d to one and %d to zero implies %d to zero\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  // 1-0 illegal
+		  if (iPass) {
+		    cliqueEntry temp;
+		    setOneFixesInCliqueEntry(temp,true);
+		    setSequenceInCliqueEntry(temp,iColumn);
+		    entry[numberEntries]=temp;
+		  }
+		  numberEntries++;
+		  if (iPass) {
+		    cliqueEntry temp;
+		    setOneFixesInCliqueEntry(temp,false);
+		    setSequenceInCliqueEntry(temp,jColumn);
+		    entry[numberEntries]=temp;
+		  }
+		  numberEntries++;
+		  if (iPass) {
+		    // slack
+		    cliqueType[numberCliques]='S';
+		    cliqueStart[numberCliques+1]=numberEntries;
+		  }
+		  numberCliques++;
+		}
+	      } else {
+		if (oneFixesInCliqueEntry(fixEntry_[k])) {
+		  if (printit&&!iPass)
+		    printf("%d to one implies %d to zero and %d to zero implies %d to one\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // iColumn+jColumn=1
+		} else {
+		  if (printit&&!iPass)
+		    printf("%d to one implies %d to zero and %d to zero implies %d to zero\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // iColumn is 0
+		}
+	      }
+	    }
+	  }
+	  for ( k=toOne_[jColumn];k<toZero_[jColumn+1];k++) {
+	    if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) {
+	      if (oneFixesInCliqueEntry(fixEntry_[j])) {
+		if (oneFixesInCliqueEntry(fixEntry_[k])) {
+		  if (printit&&!iPass)
+		    printf("%d to one implies %d to one and %d to one implies %d to one\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // iColumn == jColumn
+		} else {
+		  if (printit&&!iPass)
+		    printf("%d to one implies %d to one and %d to one implies %d to zero\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // iColumn is 0
+		}
+	      } else {
+		if (oneFixesInCliqueEntry(fixEntry_[k])) {
+		  if (printit&&!iPass)
+		    printf("%d to one implies %d to zero and %d to one implies %d to one\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  nFix++; // jColumn is 0
+		} else {
+		  if (printit&&!iPass)
+		    printf("%d to one implies %d to zero and %d to one implies %d to zero\n",
+			   iColumn,jColumn,jColumn,iColumn);
+		  // 1-1 illegal
+		  if (iPass) {
+		    cliqueEntry temp;
+		    setOneFixesInCliqueEntry(temp,true);
+		    setSequenceInCliqueEntry(temp,iColumn);
+		    entry[numberEntries]=temp;
+		  }
+		  numberEntries++;
+		  if (iPass) {
+		    cliqueEntry temp;
+		    setOneFixesInCliqueEntry(temp,true);
+		    setSequenceInCliqueEntry(temp,jColumn);
+		    entry[numberEntries]=temp;
+		  }
+		  numberEntries++;
+		  if (iPass) {
+		    // slack
+		    cliqueType[numberCliques]='S';
+		    cliqueStart[numberCliques+1]=numberEntries;
+		  }
+		  numberCliques++;
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    if (!iPass)
+      printf("%d cliques and %d fixed (%d already from matrix))\n",
+	     numberCliques-numberMatrixCliques,nFix,numberMatrixCliques);
+  }
+  int iClique;
+  outDupsEtc(numberIntegers_, numberCliques, numberMatrixCliques,
+	     cliqueStart, cliqueType, entry, -1, printit ? 2 : 1);
+  printf("%d matrix cliques and %d found by probing\n",numberMatrixCliques,numberCliques-numberMatrixCliques);
+  int * zeroStart = new int [numberIntegers_+1];
+  int * oneStart = new int [numberIntegers_];
+  int * zeroCount = new int [numberIntegers_];
+  int * oneCount = new int [numberIntegers_];
+  char * mark = new char [numberIntegers_];
+  memset(mark,0,numberIntegers_);
+  int nStrengthen=-1;
+  int iPass=0;
+  while (nStrengthen&&iPass<20) {
+    iPass++;
+    int numberLastTime = numberCliques;
+    int * count = new int [numberCliques];
+    int i,iColumn;
+    for (i=0;i<numberCliques;i++) {
+      count[i]=0;
+    }
+    int * whichCount = new int [numberCliques];
+    CoinZeroN(zeroCount,numberIntegers_);
+    CoinZeroN(oneCount,numberIntegers_);
+    for (iClique=0;iClique<numberCliques;iClique++) {
+      for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
+	int iColumn = static_cast<int> (sequenceInCliqueEntry(entry[j]));
+	if (oneFixesInCliqueEntry(entry[j])) {
+	  oneCount[iColumn]++;
+	} else {
+	  zeroCount[iColumn]++;
+	}
+      }
+    }
+    int j;
+    zeroStart[0]=0;
+    cliqueStart[0]=0;
+    for (j=0;j<numberIntegers_;j++) {
+      int n;
+      n=zeroCount[j];
+      zeroCount[j]=0;
+      oneStart[j] = zeroStart[j]+n;
+      n=oneCount[j];
+      oneCount[j]=0;
+      zeroStart[j+1] = oneStart[j]+n;
+    }
+    for (iClique=0;iClique<numberCliques;iClique++) {
+      for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) {
+	int iColumn = static_cast<int> (sequenceInCliqueEntry(entry[j]));
+	if (oneFixesInCliqueEntry(entry[j])) {
+	  int k=oneCount[iColumn];
+	  oneCount[iColumn]++;
+	  int put = oneStart[iColumn]+k;
+	  whichClique[put]=iClique;
+	} else {
+	  int k=zeroCount[iColumn];
+	  zeroCount[iColumn]++;
+	  int put = zeroStart[iColumn]+k;
+	  whichClique[put]=iClique;
+	}
+      }
+    }
+    nStrengthen=0;
+    int numberEntries=cliqueStart[numberCliques];
+    int maximumEntries=numberEntries;
+    int maximumCliques=numberCliques;
+    for (iColumn=0;iColumn<numberIntegers_;iColumn++) {
+      int i;
+      int n;
+      int nCount=0;
+      n=0;
+      for (i=zeroStart[iColumn];i<oneStart[iColumn];i++) {
+	int jClique = whichClique[i];
+	//if (jClique<numberMatrixCliques) 
+	//continue;
+	int j = cliqueStart[jClique];
+	//assert (cliqueStart[jClique+1]==j+2);
+	for (;j<cliqueStart[jClique+1];j++) {
+	  cliqueEntry eJ = entry[j];
+	  int jColumn = sequenceInCliqueEntry(eJ);
+	  if (jColumn>iColumn&&!mark[jColumn]) {
+	    mark[jColumn]=1;
+	    whichP[n++]=jColumn;
+	    assert (n<numberIntegers_);
+	    if (oneFixesInCliqueEntry(eJ)) {
+	      for (int k=oneStart[jColumn];k<zeroStart[jColumn+1];k++) {
+		int jClique = whichClique[k];
+		if (!count[jClique]) 
+		  whichCount[nCount++]=jClique;
+		count[jClique]++;
+	      }
+	    } else {
+	      for (int k=zeroStart[jColumn];k<oneStart[jColumn];k++) {
+		int jClique = whichClique[k];
+		if (!count[jClique]) 
+		  whichCount[nCount++]=jClique;
+		count[jClique]++;
+	      }
+	    }
+	  }
+	}
+      }
+      std::sort(whichP,whichP+n);
+      for (i=0;i<nCount;i++) {
+	int jClique = whichCount[i];
+	int jCount = count[jClique];
+	count[jClique]=0;
+	if (jCount==cliqueStart[jClique+1]-cliqueStart[jClique]) {
+	  printf("Zero can extend %d [ ",jClique);
+	  for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++)
+	    printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i]));
+	  printf("] by %d(0)\n",iColumn);
+	  nStrengthen++;
+	  if (numberEntries+jCount+1>maximumEntries) {
+	    maximumEntries = CoinMax(numberEntries+jCount+1,(maximumEntries*12)/10+100);
+	    cliqueEntry * temp = new cliqueEntry [maximumEntries];
+	    memcpy(temp,entry,numberEntries*sizeof(cliqueEntry));
+	    delete [] entry;
+	    entry=temp;
+	    int * tempI = new int [maximumEntries];
+	    memcpy(tempI,whichClique,numberEntries*sizeof(int));
+	    delete [] whichClique;
+	    whichClique=tempI;
+	  }
+	  if (numberCliques==maximumCliques) {
+	    maximumCliques = (maximumCliques*12)/10+100;
+	    int * temp = new int [maximumCliques+1];
+	    memcpy(temp,cliqueStart,(numberCliques+1)*sizeof(int));
+	    delete [] cliqueStart;
+	    cliqueStart=temp;
+	    char * tempT = new char [maximumCliques];
+	    memcpy(tempT,cliqueType,numberCliques);
+	    delete [] cliqueType;
+	    cliqueType=tempT;
+	  }
+	  cliqueEntry eI;
+	  eI.fixes=0;
+	  setSequenceInCliqueEntry(eI,iColumn);
+	  setOneFixesInCliqueEntry(eI,false);
+	  entry[numberEntries++]=eI;
+	  whichM[0]=iColumn;
+	  int n=1;
+	  for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) {
+	    entry[numberEntries++]=entry[i];
+	    whichM[n++]=sequenceInCliqueEntry(entry[i]);
+	  }
+	  CoinSort_2(whichM,whichM+n,(reinterpret_cast<int *>(entry))+numberEntries-n);
+	  cliqueType[numberCliques]='S';
+	  numberCliques++;
+	  cliqueStart[numberCliques]=numberEntries;
+	}
+      }
+      for (i=0;i<n;i++)
+	mark[whichP[i]]=0;
+      nCount=0;
+      n=0;
+      for (i=oneStart[iColumn];i<zeroStart[iColumn+1];i++) {
+	int jClique = whichClique[i];
+	//if (jClique<numberMatrixCliques) 
+	//continue;
+	int j = cliqueStart[jClique];
+	//assert (cliqueStart[jClique+1]==j+2);
+	for (;j<cliqueStart[jClique+1];j++) {
+	  cliqueEntry eJ = entry[j];
+	  int jColumn = sequenceInCliqueEntry(eJ);
+	  if (jColumn>iColumn&&!mark[jColumn]) {
+	    mark[jColumn]=1;
+	    whichP[n++]=jColumn;
+	    assert (n<numberIntegers_);
+	    if (oneFixesInCliqueEntry(eJ)) {
+	      for (int k=oneStart[jColumn];k<zeroStart[jColumn+1];k++) {
+		int jClique = whichClique[k];
+		if (!count[jClique]) 
+		  whichCount[nCount++]=jClique;
+		count[jClique]++;
+	      }
+	    } else {
+	      for (int k=zeroStart[jColumn];k<oneStart[jColumn];k++) {
+		int jClique = whichClique[k];
+		if (!count[jClique]) 
+		  whichCount[nCount++]=jClique;
+		count[jClique]++;
+	      }
+	    }
+	  }
+	}
+      }
+      std::sort(whichP,whichP+n);
+      for (i=0;i<nCount;i++) {
+	int jClique = whichCount[i];
+	int jCount = count[jClique];
+	count[jClique]=0;
+	if (jCount==cliqueStart[jClique+1]-cliqueStart[jClique]) {
+#if 1
+		if (printit) {
+	    printf("One can extend %d [ ",jClique);
+	    for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++)
+	      printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i]));
+	    printf("] by %d(1)\n",iColumn);
+	  }
+#endif
+	  nStrengthen++;
+	  if (numberEntries+jCount+1>maximumEntries) {
+	    maximumEntries = CoinMax(numberEntries+jCount+1,(maximumEntries*12)/10+100);
+	    cliqueEntry * temp = new cliqueEntry [maximumEntries];
+	    memcpy(temp,entry,numberEntries*sizeof(cliqueEntry));
+	    delete [] entry;
+	    entry=temp;
+	    int * tempI = new int [maximumEntries];
+	    memcpy(tempI,whichClique,numberEntries*sizeof(int));
+	    delete [] whichClique;
+	    whichClique=tempI;
+	  }
+	  if (numberCliques==maximumCliques) {
+	    maximumCliques = (maximumCliques*12)/10+100;
+	    int * temp = new int [maximumCliques+1];
+	    memcpy(temp,cliqueStart,(numberCliques+1)*sizeof(int));
+	    delete [] cliqueStart;
+	    cliqueStart=temp;
+	    char * tempT = new char [maximumCliques];
+	    memcpy(tempT,cliqueType,numberCliques);
+	    delete [] cliqueType;
+	    cliqueType=tempT;
+	  }
+	  cliqueEntry eI;
+	  eI.fixes=0;
+	  setSequenceInCliqueEntry(eI,iColumn);
+	  setOneFixesInCliqueEntry(eI,true);
+	  entry[numberEntries++]=eI;
+	  whichM[0]=iColumn;
+	  int n=1;
+	  for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) {
+	    entry[numberEntries++]=entry[i];
+	    whichM[n++]=sequenceInCliqueEntry(entry[i]);
+	  }
+	  CoinSort_2(whichM,whichM+n,(reinterpret_cast<int *>(entry))+numberEntries-n);
+	  cliqueType[numberCliques]='S';
+	  numberCliques++;
+	  cliqueStart[numberCliques]=numberEntries;
+	}
+      }
+      for (i=0;i<n;i++)
+	mark[whichP[i]]=0;
+    }
+    if (nStrengthen) {
+      int numberDeleted = outDupsEtc(numberIntegers_, numberCliques, numberMatrixCliques,
+		 cliqueStart, cliqueType, entry, numberLastTime,printit ? 2 : 1);
+      if (numberDeleted<0||(iPass>1&&numberCliques-numberDeleted>5000))
+	nStrengthen=0;
+    }
+    delete [] count;
+    delete [] whichCount;
+  }
+#if 0
+  if (numberCliques>numberMatrixCliques) {
+    // should keep as cliques and also use in branching ??
+    double * element = new double [numberIntegers_];
+    for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) {
+      int n=0;
+      double rhs=1.0;
+      for (int i=cliqueStart[iClique];i<cliqueStart[iClique+1];i++) {
+	cliqueEntry eI=entry[i];
+	int iColumn = integerVariable_[sequenceInCliqueEntry(eI)];
+	whichP[n]=iColumn;
+	if (oneFixesInCliqueEntry(eI)) {
+	  element[n++]=1.0;
+	} else {
+	  element[n++]=-1.0;
+	  rhs -= 1.0;
+	}
+      }
+      stored->addCut(-COIN_DBL_MAX,rhs,n,whichP,element);
+    } 
+    delete [] element;
+  }
+#endif
+  OsiSolverInterface * newSolver=NULL; 
+  if (numberCliques>numberMatrixCliques) {
+    newSolver = si.clone();
+    // Delete all rows
+    int * start = new int [ CoinMax(numberRows,numberCliques+1)];
+    int i;
+    for (i=0;i<numberRows;i++)
+      start[i]=i;
+    newSolver->deleteRows(numberRows,start);
+    start[0]=0;
+    int numberElements = cliqueStart[numberCliques];
+    int * column = new int [numberElements];
+    double * element = new double [numberElements];
+    double * lower = new double [numberCliques];
+    double * upper = new double [numberCliques];
+    numberElements=0;
+    for (iClique=0;iClique<numberCliques;iClique++) {
+      double rhs=1.0;
+      for (int i=cliqueStart[iClique];i<cliqueStart[iClique+1];i++) {
+	cliqueEntry eI=entry[i];
+	int iColumn = integerVariable_[sequenceInCliqueEntry(eI)];
+	column[numberElements]=iColumn;
+	if (oneFixesInCliqueEntry(eI)) {
+	  element[numberElements++]=1.0;
+	} else {
+	  element[numberElements++]=-1.0;
+	  rhs -= 1.0;
+	}
+      }
+      start[iClique+1]=numberElements;
+      assert (cliqueType[iClique]=='S'||
+	      cliqueType[iClique]=='E');
+      if (cliqueType[iClique]=='S')
+	lower[iClique]=-COIN_DBL_MAX;
+      else
+	lower[iClique] = rhs;
+      upper[iClique]=rhs;
+    }
+    newSolver->addRows(numberCliques,start,column,element,lower,upper);
+    delete [] start;
+    delete [] column;
+    delete [] element;
+    delete [] lower;
+    delete [] upper;
+  }
+  delete [] mark;
+  delete [] whichP;
+  delete [] whichM;
+  delete [] cliqueStart;
+  delete [] entry;
+  delete [] cliqueType;
+  delete [] zeroStart;
+  delete [] oneStart;
+  delete [] zeroCount;
+  delete [] oneCount;
+  delete [] whichClique;
+  return newSolver;
+}
+// Take action if cut generator can fix a variable (toValue -1 for down, +1 for up)
+bool
+CglTreeProbingInfo::fixes(int variable, int toValue, int fixedVariable,bool fixedToLower)
+{
+  //printf("%d going to %d fixes %d at %g\n",variable,toValue,fixedVariable,fixedToValue);
+  int intVariable = backward_[variable];
+  if (intVariable<0) // off as no longer in order FIX
+    return true; // not 0-1 (well wasn't when constructor was called)
+  int intFix = backward_[fixedVariable];
+  if (intFix<0)
+    intFix = numberIntegers_+fixedVariable; // not 0-1
+  int fixedTo = fixedToLower ? 0 : 1;
+  if (numberEntries_==maximumEntries_) {
+    // See if taking too much memory
+    if (maximumEntries_>=CoinMax(1000000,10*numberIntegers_))
+      return false;
+    maximumEntries_ += 100 +maximumEntries_/2;
+    cliqueEntry * temp1 = new cliqueEntry [maximumEntries_];
+    memcpy(temp1,fixEntry_,numberEntries_*sizeof(cliqueEntry));
+    delete [] fixEntry_;
+    fixEntry_ = temp1;
+    int * temp2 = new int [maximumEntries_];
+    memcpy(temp2,fixingEntry_,numberEntries_*sizeof(int));
+    delete [] fixingEntry_;
+    fixingEntry_ = temp2;
+  }
+  cliqueEntry entry1;
+  entry1.fixes=0;
+  setOneFixesInCliqueEntry(entry1,fixedTo!=0);
+  setSequenceInCliqueEntry(entry1,intFix);
+  fixEntry_[numberEntries_] = entry1;
+  assert (toValue==-1||toValue==1);
+  assert (fixedTo==0||fixedTo==1);
+  if (toValue<0)
+    fixingEntry_[numberEntries_++] = intVariable << 1;
+  else
+    fixingEntry_[numberEntries_++] = (intVariable << 1) | 1;
+  return true;
+}
+// Initalizes fixing arrays etc - returns true if we want to save info
+int
+CglTreeProbingInfo::initializeFixing(const OsiSolverInterface * model) 
+{
+  if (numberEntries_>=0)
+    return 2; // already got arrays
+  else if (numberEntries_==-2)
+    return numberEntries_;
+  delete [] fixEntry_;
+  delete [] toZero_;
+  delete [] toOne_;
+  delete [] integerVariable_;
+  delete [] backward_;
+  delete [] fixingEntry_;
+  numberVariables_=model->getNumCols(); 
+  // Too many ... but
+  integerVariable_ = new int [numberVariables_];
+  backward_ = new int [numberVariables_];
+  numberIntegers_=0;
+  int i;
+  // Get integer types
+  const char * columnType = model->getColType (true);
+  for (i=0;i<numberVariables_;i++) {
+    backward_[i]=-1;
+    if (columnType[i]) {
+      if (columnType[i]==1) {
+	backward_[i]=numberIntegers_;
+	integerVariable_[numberIntegers_++]=i;
+      } else {
+	backward_[i]=-2;
+      }
+    }
+  }
+  toZero_ = NULL;
+  toOne_ = NULL;
+  fixEntry_ = NULL;
+  fixingEntry_ = NULL;
+  maximumEntries_ =0;
+  numberEntries_ = 0;
+  return 1;
+}
+// Converts to ordered and takes out duplicates
+void 
+CglTreeProbingInfo::convert()
+{
+  if (numberEntries_>=0) {
+    CoinSort_2( fixingEntry_, fixingEntry_+numberEntries_, fixEntry_);
+    assert (!toZero_);
+    toZero_ = new int [numberIntegers_+1];
+    toOne_ = new int [numberIntegers_];
+    toZero_[0]=0;
+    int n=0;
+    int put=0;
+    for (int intVariable = 0;intVariable<numberIntegers_;intVariable++) {
+      int last = n;
+      for (;n<numberEntries_;n++) {
+	int value = fixingEntry_[n];
+	int iVar = value>>1;
+	int way = value &1;
+	if (intVariable!=iVar||way)
+	  break;
+      }
+      if (n>last) {
+	// sort
+	assert (sizeof(int)==4);
+	std::sort(reinterpret_cast<unsigned int *> (fixEntry_)+last,
+		  reinterpret_cast<unsigned int *> (fixEntry_)+n);
+	cliqueEntry temp2;
+	temp2.fixes=0;
+	setSequenceInCliqueEntry(temp2,numberVariables_+1);
+	for (int i=last;i<n;i++) {
+	  if (sequenceInCliqueEntry(temp2)!=sequenceInCliqueEntry(fixEntry_[i])||oneFixesInCliqueEntry(temp2)||oneFixesInCliqueEntry(fixEntry_[i])) {
+	    temp2 = fixEntry_[i];
+	    fixEntry_[put++]=temp2;
+	  }
+	}
+      }
+      toOne_[intVariable]=put;
+      last = n;
+      for (;n<numberEntries_;n++) {
+	int value = fixingEntry_[n];
+	int iVar = value>>1;
+	if (intVariable!=iVar)
+	  break;
+      }
+      if (n>last) {
+	// sort
+	assert (sizeof(int)==4);
+	std::sort(reinterpret_cast<unsigned int *> (fixEntry_)+last,
+		  reinterpret_cast<unsigned int *> (fixEntry_)+n);
+	cliqueEntry temp2;
+	temp2.fixes=0;
+	setSequenceInCliqueEntry(temp2,numberVariables_+1);
+	for (int i=last;i<n;i++) {
+	  if (sequenceInCliqueEntry(temp2)!=sequenceInCliqueEntry(fixEntry_[i])||oneFixesInCliqueEntry(temp2)||oneFixesInCliqueEntry(fixEntry_[i])) {
+	    temp2 = fixEntry_[i];
+	    fixEntry_[put++]=temp2;
+	  }
+	}
+	last=n;
+      }
+      toZero_[intVariable+1]=put;
+    }
+    delete [] fixingEntry_;
+    fixingEntry_ = NULL;
+    numberEntries_ = -2;
+  }
+}
+// Fix entries in a solver using implications
+int 
+CglTreeProbingInfo::fixColumns(OsiSolverInterface & si) const
+{
+  int nFix=0;
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+  bool feasible=true;
+  for (int jColumn=0;jColumn<static_cast<int> (numberIntegers_);jColumn++) {
+    int iColumn = integerVariable_[jColumn];
+    if (upper[iColumn]==0.0) {
+      int j;
+      for ( j=toZero_[jColumn];j<toOne_[jColumn];j++) {
+	int kColumn=sequenceInCliqueEntry(fixEntry_[j]);
+	kColumn = integerVariable_[kColumn];
+	bool fixToOne = oneFixesInCliqueEntry(fixEntry_[j]);
+	if (fixToOne) {
+	  if (lower[kColumn]==0.0) {
+	    if (upper[kColumn]==1.0) {
+	      si.setColLower(kColumn,1.0);
+	      nFix++;
+	    } else {
+	      // infeasible!
+	      feasible=false;
+	    }
+	  }
+	} else {
+	  if (upper[kColumn]==1.0) {
+	    if (lower[kColumn]==0.0) {
+	      si.setColUpper(kColumn,0.0);
+	      nFix++;
+	    } else {
+	      // infeasible!
+	      feasible=false;
+	    }
+	  }
+	}
+      }
+    } else if (lower[iColumn]==1.0) {
+      int j;
+      for ( j=toOne_[jColumn];j<toZero_[jColumn+1];j++) {
+	int kColumn=sequenceInCliqueEntry(fixEntry_[j]);
+	kColumn = integerVariable_[kColumn];
+	bool fixToOne = oneFixesInCliqueEntry(fixEntry_[j]);
+	if (fixToOne) {
+	  if (lower[kColumn]==0.0) {
+	    if (upper[kColumn]==1.0) {
+	      si.setColLower(kColumn,1.0);
+	      nFix++;
+	    } else {
+	      // infeasible!
+	      feasible=false;
+	    }
+	  }
+	} else {
+	  if (upper[kColumn]==1.0) {
+	    if (lower[kColumn]==0.0) {
+	      si.setColUpper(kColumn,0.0);
+	      nFix++;
+	    } else {
+	      // infeasible!
+	      feasible=false;
+	    }
+	  }
+	}
+      }
+    }
+  }
+  if (!feasible) {
+#ifdef COIN_DEVELOP
+    printf("treeprobing says infeasible!\n");
+#endif
+    nFix=-1;
+  }
+  return nFix;
+}
+// Fix entries in a solver using implications for one variable
+int 
+CglTreeProbingInfo::fixColumns(int iColumn,int value, OsiSolverInterface & si) const
+{
+  assert (value==0||value==1);
+  int nFix=0;
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+  bool feasible=true;
+  int jColumn = backward_[iColumn];
+  assert (jColumn>=0);
+  if (!value) {
+    int j;
+    for ( j=toZero_[jColumn];j<toOne_[jColumn];j++) {
+      int kColumn=sequenceInCliqueEntry(fixEntry_[j]);
+      kColumn = integerVariable_[kColumn];
+      bool fixToOne = oneFixesInCliqueEntry(fixEntry_[j]);
+      if (fixToOne) {
+	if (lower[kColumn]==0.0) {
+	  if (upper[kColumn]==1.0) {
+	    si.setColLower(kColumn,1.0);
+	    nFix++;
+	  } else {
+	    // infeasible!
+	    feasible=false;
+	  }
+	}
+      } else {
+	if (upper[kColumn]==1.0) {
+	  if (lower[kColumn]==0.0) {
+	    si.setColUpper(kColumn,0.0);
+	    nFix++;
+	  } else {
+	    // infeasible!
+	    feasible=false;
+	  }
+	}
+      }
+    }
+  } else {
+    int j;
+    for ( j=toOne_[jColumn];j<toZero_[jColumn+1];j++) {
+      int kColumn=sequenceInCliqueEntry(fixEntry_[j]);
+      kColumn = integerVariable_[kColumn];
+      bool fixToOne = oneFixesInCliqueEntry(fixEntry_[j]);
+      if (fixToOne) {
+	if (lower[kColumn]==0.0) {
+	  if (upper[kColumn]==1.0) {
+	    si.setColLower(kColumn,1.0);
+	    nFix++;
+	  } else {
+	    // infeasible!
+	    feasible=false;
+	  }
+	}
+      } else {
+	if (upper[kColumn]==1.0) {
+	  if (lower[kColumn]==0.0) {
+	    si.setColUpper(kColumn,0.0);
+	    nFix++;
+	  } else {
+	    // infeasible!
+	    feasible=false;
+	  }
+	}
+      }
+    }
+  }
+  if (!feasible) {
+#ifdef COIN_DEVELOP
+    printf("treeprobing says infeasible!\n");
+#endif
+    nFix=-1;
+  }
+  return nFix;
+}
+// Packs down entries
+int 
+CglTreeProbingInfo::packDown()
+{
+  convert();
+  int iPut=0;
+  int iLast=0;
+  for (int jColumn=0;jColumn<static_cast<int> (numberIntegers_);jColumn++) {
+    int j;
+    for ( j=iLast;j<toOne_[jColumn];j++) {
+      int kColumn=sequenceInCliqueEntry(fixEntry_[j]);
+      if (kColumn<numberIntegers_) 
+	fixEntry_[iPut++]=fixEntry_[j];
+    }
+    iLast=toOne_[jColumn];
+    toOne_[jColumn]=iPut;
+    for ( j=iLast;j<toZero_[jColumn+1];j++) {
+      int kColumn=sequenceInCliqueEntry(fixEntry_[j]);
+      if (kColumn<numberIntegers_) 
+	fixEntry_[iPut++]=fixEntry_[j];
+    }
+    iLast=toZero_[jColumn+1];
+    toZero_[jColumn+1]=iPut;
+  }
+  return iPut;
+}
+void
+CglTreeProbingInfo::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+				 const CglTreeInfo /*info*/) const
+{
+  const double * lower = si.getColLower();
+  const double * upper = si.getColUpper();
+  const double * colsol =si.getColSolution();
+  CoinPackedVector lbs(false);
+  CoinPackedVector ubs(false);
+  int numberFixed=0;
+  char * fixed = NULL;
+  for (int jColumn=0;jColumn<static_cast<int> (numberIntegers_);jColumn++) {
+    int iColumn = integerVariable_[jColumn];
+    assert (iColumn>=0&&iColumn<si.getNumCols());
+    if (lower[iColumn]==0.0&&upper[iColumn]==1.0) {
+      double value1 = colsol[iColumn];
+      int j;
+      for ( j=toZero_[jColumn];j<toOne_[jColumn];j++) {
+	int kColumn=sequenceInCliqueEntry(fixEntry_[j]);
+	kColumn = integerVariable_[kColumn];
+	assert (kColumn>=0&&kColumn<si.getNumCols());
+	assert (kColumn!=iColumn);
+	if (lower[kColumn]==0.0&&upper[kColumn]==1.0) {
+	  double value2 = colsol[kColumn];
+	  bool fixToOne = oneFixesInCliqueEntry(fixEntry_[j]);
+	  if (fixToOne) {
+	    if (value1+value2<0.99999) {
+	      OsiRowCut rc;
+	      int index[2];
+	      double element[2];
+	      index[0]=iColumn;
+	      element[0]=1.0;
+	      index[1]=kColumn;
+	      element[1]= 1.0;
+	      rc.setLb(1.0);
+	      rc.setUb(COIN_DBL_MAX);   
+	      rc.setRow(2,index,element,false);
+	      cs.insert(rc);
+	    }
+	  } else {
+	    if (value1-value2<-0.00001) {
+	      OsiRowCut rc;
+	      int index[2];
+	      double element[2];
+	      index[0]=iColumn;
+	      element[0]=1.0;
+	      index[1]=kColumn;
+	      element[1]= -1.0;
+	      rc.setLb(0.0);
+	      rc.setUb(COIN_DBL_MAX);   
+	      rc.setRow(2,index,element,false);
+	      cs.insert(rc);
+	    }
+	  }
+	}
+      }
+      for ( j=toOne_[jColumn];j<toZero_[jColumn+1];j++) {
+	int kColumn=sequenceInCliqueEntry(fixEntry_[j]);
+	kColumn = integerVariable_[kColumn];
+	assert (kColumn>=0&&kColumn<si.getNumCols());
+	assert (kColumn!=iColumn);
+	if (lower[kColumn]==0.0&&upper[kColumn]==1.0) {
+	  double value2 = colsol[kColumn];
+	  bool fixToOne = oneFixesInCliqueEntry(fixEntry_[j]);
+	  if (fixToOne) {
+	    if (value1-value2>0.00001) {
+	      OsiRowCut rc;
+	      int index[2];
+	      double element[2];
+	      index[0]=iColumn;
+	      element[0]=1.0;
+	      index[1]=kColumn;
+	      element[1]= -1.0;
+	      rc.setLb(-COIN_DBL_MAX);
+	      rc.setUb(0.0);   
+	      rc.setRow(2,index,element,false);
+	      cs.insert(rc);
+	    }
+	  } else {
+	    if (value1+value2>1.00001) {
+	      OsiRowCut rc;
+	      int index[2];
+	      double element[2];
+	      index[0]=iColumn;
+	      element[0]=1.0;
+	      index[1]=kColumn;
+	      element[1]= 1.0;
+	      rc.setLb(-COIN_DBL_MAX);
+	      rc.setUb(1.0);   
+	      rc.setRow(2,index,element,false);
+	      cs.insert(rc);
+	    }
+	  }
+	}
+      }
+    } else if (upper[iColumn]==0.0) {
+      for (int j=toZero_[jColumn];j<toOne_[jColumn];j++) {
+	int kColumn01=sequenceInCliqueEntry(fixEntry_[j]);
+	int kColumn = integerVariable_[kColumn01];
+	assert (kColumn>=0&&kColumn<si.getNumCols());
+	bool fixToOne = oneFixesInCliqueEntry(fixEntry_[j]);
+	if (lower[kColumn]==0.0&&upper[kColumn]==1.0) {
+	  if (!fixed) {
+	    fixed = new char [numberIntegers_];
+	    memset(fixed,0,numberIntegers_);
+	  }
+	  if (fixToOne) {
+	    if ((fixed[kColumn01]&1)==0) {
+	      fixed[kColumn01] |= 1;
+	      lbs.insert(kColumn,1.0);
+	    }
+	  } else {
+	    if ((fixed[kColumn01]&2)==0) {
+	      fixed[kColumn01] |= 2;
+	      ubs.insert(kColumn,0.0);
+	    }
+	  }
+	  numberFixed++;
+	} else if ((fixToOne&&upper[kColumn]==0.0)||
+		   (!fixToOne&&lower[kColumn]==1.0)) {
+	  // infeasible!
+	  // generate infeasible cut and return
+	  OsiRowCut rc;
+	  rc.setLb(COIN_DBL_MAX);
+	  rc.setUb(0.0);   
+	  cs.insert(rc);
+	  //printf("IMPINFEAS!\n");
+	  return;
+	}
+      }
+    } else {
+      for (int j=toOne_[jColumn];j<toZero_[jColumn+1];j++) {
+	int kColumn01=sequenceInCliqueEntry(fixEntry_[j]);
+	int kColumn = integerVariable_[kColumn01];
+	assert (kColumn>=0&&kColumn<si.getNumCols());
+	bool fixToOne = oneFixesInCliqueEntry(fixEntry_[j]);
+	if (lower[kColumn]==0.0&&upper[kColumn]==1.0) {
+	  if (!fixed) {
+	    fixed = new char [numberIntegers_];
+	    memset(fixed,0,numberIntegers_);
+	  }
+	  if (fixToOne) {
+	    if ((fixed[kColumn01]&1)==0) {
+	      fixed[kColumn01] |= 1;
+	      lbs.insert(kColumn,1.0);
+	    }
+	  } else {
+	    if ((fixed[kColumn01]&2)==0) {
+	      fixed[kColumn01] |= 2;
+	      ubs.insert(kColumn,0.0);
+	    }
+	  }
+	  numberFixed++;
+	} else if ((fixToOne&&upper[kColumn]==0.0)||
+		   (!fixToOne&&lower[kColumn]==1.0)) {
+	  // infeasible!
+	  // generate infeasible cut and return
+	  OsiRowCut rc;
+	  rc.setLb(COIN_DBL_MAX);
+	  rc.setUb(0.0);   
+	  cs.insert(rc);
+	  //printf("IMPINFEAS!\n");
+	  return;
+	}
+      }
+    }
+  }
+  if (numberFixed) {
+    int feasible=true;
+    for (int i=0;i<numberIntegers_;i++) {
+      if (fixed[i]==3) {
+	feasible=false;
+	break;
+      }
+    }
+    delete [] fixed;
+    if (feasible) {
+      //printf("IMP fixed %d\n",numberFixed);
+      OsiColCut cc;
+      cc.setUbs(ubs);
+      cc.setLbs(lbs);
+      cc.setEffectiveness(1.0);
+      cs.insert(cc);
+    } else {
+      // infeasible!
+      // generate infeasible cut
+      OsiRowCut rc;
+      rc.setLb(COIN_DBL_MAX);
+      rc.setUb(0.0);   
+      cs.insert(rc);
+      //printf("IMPINFEAS!\n");
+    }
+  }
+}
diff --git a/cbits/coin/CglTreeInfo.hpp b/cbits/coin/CglTreeInfo.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglTreeInfo.hpp
@@ -0,0 +1,178 @@
+// $Id: CglTreeInfo.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglTreeInfo_H
+#define CglTreeInfo_H
+
+#include "OsiCuts.hpp"
+#include "OsiSolverInterface.hpp"
+#include "CoinHelperFunctions.hpp"
+class CglStored;
+/** Information about where the cut generator is invoked from. */
+
+class CglTreeInfo {
+public:
+  /// The level of the search tree node 
+  int level;
+  /** How many times the cut generator was already invoked in this search tree
+      node */
+  int pass;
+  /** The number of rows in the original formulation. Some generators may not
+      want to consider already generated rows when generating new ones. */
+  int formulation_rows;
+  /** Options 
+      1 - treat costed integers as important
+      2 - switch off some stuff as variables semi-integer
+      4 - set global cut flag if at root node
+      8 - set global cut flag if at root node and first pass
+      16 - set global cut flag and make cuts globally valid
+      32 - last round of cuts did nothing - maybe be more aggressive
+      64 - in preprocessing stage
+      128 - looks like solution
+      256 - want alternate cuts
+      512 - in sub tree (i.e. parent model)
+      1024 - in must call again mode or after everything mode
+  */
+  int options;
+  /// Set true if in tree (to avoid ambiguity at first branch)
+  bool inTree;
+  /** Replacement array.  Before Branch and Cut it may be beneficial to strengthen rows
+      rather than adding cuts.  If this array is not NULL then the cut generator can
+      place a pointer to the stronger cut in this array which is number of rows in size.
+
+      A null (i.e. zero elements and free rhs) cut indicates that the row is useless 
+      and can be removed.
+
+      The calling function can then replace those rows.
+  */
+  OsiRowCut ** strengthenRow;
+  /// Optional pointer to thread specific random number generator
+  CoinThreadRandom * randomNumberGenerator;
+  /// Default constructor 
+  CglTreeInfo ();
+ 
+  /// Copy constructor 
+  CglTreeInfo (
+    const CglTreeInfo &);
+  /// Clone
+  virtual CglTreeInfo * clone() const;
+
+  /// Assignment operator 
+  CglTreeInfo &
+    operator=(
+    const CglTreeInfo& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglTreeInfo ();
+  /// Take action if cut generator can fix a variable (toValue -1 for down, +1 for up)
+  virtual bool fixes(int , int , int ,bool) {return false;}
+  /** Initalizes fixing arrays etc - returns >0 if we want to save info
+      0 if we don't and -1 if is to be used */
+  virtual int initializeFixing(const OsiSolverInterface * ) {return 0;}
+  
+};
+
+/** Derived class to pick up probing info. */
+typedef struct {
+  //unsigned int oneFixed:1; //  nonzero if variable to 1 fixes all
+  //unsigned int sequence:31; //  variable (in matrix) (but also see cliqueRow_)
+  unsigned int fixes;
+} cliqueEntry;
+
+class CglTreeProbingInfo : public CglTreeInfo {
+public:
+  /// Default constructor 
+  CglTreeProbingInfo ();
+  /// Constructor from model
+  CglTreeProbingInfo (const OsiSolverInterface * model);
+ 
+  /// Copy constructor 
+  CglTreeProbingInfo (
+    const CglTreeProbingInfo &);
+  /// Clone
+  virtual CglTreeInfo * clone() const;
+
+  /// Assignment operator 
+  CglTreeProbingInfo &
+    operator=(
+    const CglTreeProbingInfo& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglTreeProbingInfo ();
+  OsiSolverInterface * analyze(const OsiSolverInterface & si, int createSolver=0);
+  /** Take action if cut generator can fix a variable 
+      (toValue -1 for down, +1 for up)
+      Returns true if still room, false if not  */
+  virtual bool fixes(int variable, int toValue, int fixedVariable,bool fixedToLower);
+  /** Initalizes fixing arrays etc - returns >0 if we want to save info
+      0 if we don't and -1 if is to be used */
+  virtual int initializeFixing(const OsiSolverInterface * model) ;
+  /// Fix entries in a solver using implications
+  int fixColumns(OsiSolverInterface & si) const;
+  /// Fix entries in a solver using implications for one variable
+  int fixColumns(int iColumn, int value, OsiSolverInterface & si) const;
+  /// Packs down entries
+  int packDown();
+  /// Generate cuts from implications
+  void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+		    const CglTreeInfo info) const;
+  /// Entries for fixing variables
+  inline cliqueEntry * fixEntries()
+  { convert(); return fixEntry_;}
+  /// Starts of integer variable going to zero
+  inline int * toZero()
+  { convert(); return toZero_;}
+  /// Starts of integer variable going to one
+  inline int * toOne()
+  { convert(); return toOne_;}
+  /// List of 0-1 integer variables
+  inline int * integerVariable() const
+  { return integerVariable_;}
+  /// Backward look up
+  inline int * backward() const
+  { return backward_;}
+  /// Number of variables
+  inline int numberVariables() const
+  { return numberVariables_;}
+  /// Number of 0-1 variables
+  inline int numberIntegers() const
+  { return numberIntegers_;}
+private:
+  /// Converts to ordered
+  void convert();
+protected:
+  /// Entries for fixing variables
+  cliqueEntry * fixEntry_;
+  /// Starts of integer variable going to zero
+  int * toZero_;
+  /// Starts of integer variable going to one
+  int * toOne_;
+  /// List of 0-1 integer variables
+  int * integerVariable_;
+  /// Backward look up
+  int * backward_;
+  /// Entries for fixing variable when collecting
+  int * fixingEntry_;
+  /// Number of variables
+  int numberVariables_;
+  /// Number of 0-1 variables
+  int numberIntegers_;
+  /// Maximum number in fixEntry_
+  int maximumEntries_;
+  /// Number entries in fixingEntry_ (and fixEntry_) or -2 if correct style
+  int numberEntries_;
+};
+inline int sequenceInCliqueEntry(const cliqueEntry & cEntry)
+{ return cEntry.fixes&0x7fffffff;}
+inline void setSequenceInCliqueEntry(cliqueEntry & cEntry,int sequence)
+{ cEntry.fixes = sequence|(cEntry.fixes&0x80000000);}
+inline bool oneFixesInCliqueEntry(const cliqueEntry & cEntry)
+{ return (cEntry.fixes&0x80000000)!=0;}
+inline void setOneFixesInCliqueEntry(cliqueEntry & cEntry,bool oneFixes)
+{ cEntry.fixes = (oneFixes ? 0x80000000 : 0)|(cEntry.fixes&0x7fffffff);}
+
+#endif
diff --git a/cbits/coin/CglTwomir.cpp b/cbits/coin/CglTwomir.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglTwomir.cpp
@@ -0,0 +1,2154 @@
+// $Id: CglTwomir.cpp 1132 2013-04-25 18:57:12Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cfloat>
+#include <cassert>
+#include <iostream>
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CoinFactorization.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinFinite.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CglTwomir.hpp"
+class CoinWarmStartBasis;
+#define COIN_HAS_CLP_TWOMIR
+#ifdef COIN_HAS_CLP_TWOMIR
+#include "OsiClpSolverInterface.hpp"
+#endif
+#undef DGG_DEBUG_DGG
+
+//#define DGG_DEBUG_DGG 1
+//#define CGL_DEBUG
+//#define CGL_DEBUG_ZERO
+#define  q_max  data->cparams.q_max
+#define  q_min  data->cparams.q_min
+#define  t_max  data->cparams.t_max
+#define  t_min  data->cparams.t_min
+#define  a_max  data->cparams.a_max
+#define  max_elements  data->cparams.max_elements
+
+#ifdef CGL_DEBUG
+// Declarations and defines for debug build.
+
+#define talk true
+
+namespace {
+  const OsiSolverInterface *six ;
+}
+
+void write_cut( DGG_constraint_t *cut){ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+       printf("2mir_test: cut: !!!!!!!!!!!!!!!!!!!!!!!***********************************\n");
+      for (int i=0; i<cut->nz; i++)
+	{ printf(" %12.10f x[%d] ", cut->coeff[i],cut->index[i]);}
+      printf(" >= %12.10f \n", cut->rhs); 
+}
+
+void testus( DGG_constraint_t *cut){ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  //  const OsiRowCutDebugger debugg(*six, "flugpl.mps"); 
+  const OsiRowCutDebugger debugg(*six, "egout.mps"); 
+  const OsiRowCutDebugger *debugger = &debugg;
+    if (debugger&&!debugger->onOptimalPath(*six))
+      return;
+   
+    OsiRowCut rowcut;
+
+    rowcut.setRow(cut->nz, cut->index, cut->coeff);
+    rowcut.setUb(DBL_MAX);
+    rowcut.setLb(cut->rhs);
+   
+    if(debugger->invalidCut(rowcut)){
+      write_cut(cut);
+      //assert(0); 
+    }
+}
+
+#else	// CGL_DEBUG
+
+#define talk false
+
+#endif	// CGL_DEBUG
+
+
+//-------------------------------------------------------------------
+// Generate  cuts
+//------------------------------------------------------------------- 
+void CglTwomir::generateCuts(const OsiSolverInterface & si, OsiCuts & cs, 
+			     const CglTreeInfo info )
+{
+# ifdef CGL_DEBUG
+  //!!!!!!!!!!!!!!!!!!
+  six = &si;
+# endif
+  const double * colUpper = si.getColUpper();
+  const double * colLower = si.getColLower();
+  const OsiSolverInterface * useSolver;
+#ifdef COIN_HAS_CLP_TWOMIR
+  double * objective = NULL;
+  OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *>(originalSolver_);
+  int numberOriginalRows;
+  int numberColumns=si.getNumCols();
+  int twomirType=0;
+  if (!clpSolver) {
+#endif
+    useSolver=&si;
+    // Temp - check if free variables
+    int ncol = useSolver->getNumCols();
+    int numberFree=0;
+    for (int i=0;i<ncol;i++) {
+      if (colLower[i]<-1.0e20&&colUpper[i]>1.0e20)
+        numberFree++;
+    }
+    if (numberFree) {
+#ifdef COIN_DEVELOP
+      if (!info.inTree&&!info.pass)
+        printf("CglTwoMir - %d free variables - returning\n",numberFree);
+#endif
+      return;
+    }
+#ifdef COIN_HAS_CLP_TWOMIR
+  } else {
+    useSolver = originalSolver_;
+    assert (twomirType_);
+    // check simplex is plausible
+    if (!clpSolver->getNumRows()||numberColumns!=clpSolver->getNumCols()) {
+      delete originalSolver_;
+      originalSolver_=si.clone();
+      clpSolver = dynamic_cast<OsiClpSolverInterface *>(originalSolver_);
+      assert (clpSolver);
+      useSolver = originalSolver_;
+    }
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+    numberOriginalRows = simplex->numberRows();
+    int numberRows = si.getNumRows();
+    assert (numberOriginalRows<=numberRows);
+    // only do if different (unless type 2x)
+    twomirType = twomirType_%10;
+    int whenToDo = twomirType_/10;
+    if (whenToDo==2 ||(numberRows>numberOriginalRows && whenToDo==1
+		       && (info.options&512)==0) ||
+	((info.options&1024)!=0 && (info.options&512)==0)) {
+      // bounds
+      const double * solution = si.getColSolution();
+      memcpy(simplex->columnLower(),colLower,numberColumns*sizeof(double));
+      memcpy(simplex->columnUpper(),colUpper,numberColumns*sizeof(double));
+      for (int i=0;i<numberColumns;i++) {
+	if (colLower[i]<-1.0e20&&colUpper[i]>1.0e20) {
+	  double lower=-COIN_DBL_MAX;
+	  double upper=COIN_DBL_MAX;
+	  if (solution[i]>0.0)
+	    lower=-1.0e10;
+	  else
+	    upper=1.0e10;
+	  originalSolver_->setColLower(i,lower);
+	  originalSolver_->setColUpper(i,upper);
+	}
+      }
+      double * obj = simplex->objective();
+      objective = CoinCopyOfArray(obj,numberColumns);
+      const double * pi = si.getRowPrice();
+      const CoinPackedMatrix * rowCopy = si.getMatrixByRow();
+      const int * column = rowCopy->getIndices();
+      const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+      const int * rowLength = rowCopy->getVectorLengths(); 
+      const double * rowElements = rowCopy->getElements();
+      const double * rowLower = si.getRowLower();
+      const double * rowUpper = si.getRowUpper();
+      int numberCopy;
+      int numberAdd;
+      double * rowLower2 = NULL;
+      double * rowUpper2 = NULL;
+      int * column2 = NULL;
+      CoinBigIndex * rowStart2 = NULL;
+      double * rowElements2 = NULL;
+      char * copy = new char [numberRows-numberOriginalRows];
+      memset(copy,0,numberRows-numberOriginalRows);
+      if (twomirType==2) {
+	numberCopy=0;
+	numberAdd=0;
+	for (int iRow=numberOriginalRows;iRow<numberRows;iRow++) {
+	  bool simple = true;
+	  for (int k=rowStart[iRow];
+	       k<rowStart[iRow]+rowLength[iRow];k++) {
+	    double value = rowElements[k];
+	    if (value!=floor(value+0.5)) {
+	      simple=false;
+	      break;
+	    }
+	  }
+	  if (simple) {
+	    numberCopy++;
+	    numberAdd+=rowLength[iRow];
+	    copy[iRow-numberOriginalRows]=1;
+	  }
+	}
+	if (numberCopy) {
+	  //printf("Using %d rows out of %d\n",numberCopy,numberRows-numberOriginalRows);
+	  rowLower2 = new double [numberCopy];
+	  rowUpper2 = new double [numberCopy];
+	  rowStart2 = new CoinBigIndex [numberCopy+1];
+	  rowStart2[0]=0;
+	  column2 = new int [numberAdd];
+	  rowElements2 = new double [numberAdd];
+	}
+      }
+      numberCopy=0;
+      numberAdd=0;
+      const double * rowSolution = si.getRowActivity();
+      double offset=0.0;
+      for (int iRow=numberOriginalRows;iRow<numberRows;iRow++) {
+	if (!copy[iRow-numberOriginalRows]) {
+	  double value = pi[iRow];
+	  offset += rowSolution[iRow]*value;
+	  for (int k=rowStart[iRow];
+	       k<rowStart[iRow]+rowLength[iRow];k++) {
+	    int iColumn=column[k];
+	    obj[iColumn] -= value*rowElements[k];
+	  }
+	} else {
+	  rowLower2[numberCopy]=rowLower[iRow];
+	  rowUpper2[numberCopy]=rowUpper[iRow];
+	  for (int k=rowStart[iRow];
+	       k<rowStart[iRow]+rowLength[iRow];k++) {
+	    column2[numberAdd]=column[k];
+	    rowElements2[numberAdd++]=rowElements[k];
+	  }
+	  numberCopy++;
+	  rowStart2[numberCopy]=numberAdd;
+	}
+      }
+#if 0
+      CoinThreadRandom randomNumberGenerator;
+      const double * solution = si.getColSolution();
+      for (int i=0;i<numberColumns;i++) {
+	if (intVar[i]==1) {
+	  double randomNumber = randomNumberGenerator.randomDouble();
+	  //randomNumber = 0.001*floor(randomNumber*1000.0);
+	  if (solution[i]>0.5)
+	    obj[i] -= randomNumber*0.001*fabs(obj[i]);
+	  else
+	    obj[i] += randomNumber*0.001*fabs(obj[i]);
+	}
+      }
+#endif
+      if (numberCopy) {
+	clpSolver->addRows(numberCopy,
+			   rowStart2,column2,rowElements2,
+			   rowLower2,rowUpper2);
+	delete [] rowLower2 ;
+	delete [] rowUpper2 ;
+	delete [] column2 ;
+	delete [] rowStart2 ;
+	delete [] rowElements2 ;
+      }
+      delete [] copy;
+      memcpy(simplex->primalColumnSolution(),si.getColSolution(),
+	     numberColumns*sizeof(double));
+      CoinWarmStart * warmstart = si.getWarmStart();
+      CoinWarmStartBasis* warm =
+	dynamic_cast<CoinWarmStartBasis*>(warmstart);
+      warm->resize(simplex->numberRows(),numberColumns);
+      clpSolver->setBasis(*warm);
+      delete warm;
+      simplex->setDualObjectiveLimit(COIN_DBL_MAX);
+      simplex->setLogLevel(0);
+      clpSolver->resolve();
+      //printf("Trying - %d its status %d objs %g %g - with offset %g\n",
+      //     simplex->numberIterations(),simplex->status(),
+      //     simplex->objectiveValue(),si.getObjValue(),simplex->objectiveValue()+offset);
+      //simplex->setLogLevel(0);
+      if (simplex->status()) {
+	//printf("BAD status %d\n",simplex->status());
+	//clpSolver->writeMps("clp");
+	//si.writeMps("si");
+	delete [] objective;
+	objective=NULL;
+	useSolver=&si;
+      }
+    }
+  }
+#endif
+
+  useSolver->getStrParam(OsiProbName,probname_) ;
+  int numberRowCutsBefore = cs.sizeRowCuts();
+  
+  DGG_list_t cut_list;
+  DGG_list_init (&cut_list);
+
+  DGG_data_t* data = DGG_getData(reinterpret_cast<const void *> (useSolver));
+
+  // Note that the lhs variables are hash defines to data->cparams.*
+  q_max = q_max_;
+  q_min = q_min_;
+  t_max = t_max_;
+  t_min = t_min_;
+  a_max = a_max_;
+  max_elements = info.inTree ? max_elements_ : max_elements_root_;
+  data->gomory_threshold = info.inTree ? away_ : awayAtRoot_;
+  if (!info.inTree) {
+    //const CoinPackedMatrix * columnCopy = useSolver->getMatrixByCol();
+    //int numberColumns=columnCopy->getNumCols(); 
+    if (!info.pass||(info.options&32)!=0) {
+      max_elements=useSolver->getNumCols();
+      //} else {
+      //int numberRows=columnCopy.getNumRows();
+      //int numberElements=columnCopy->getNumElements();
+      //if (max_elements>500&&numberElements>10*numberColumns)
+      //max_elements=numberColumns;
+    }
+  }
+
+  if (!do_mir_) t_max = t_min - 1;
+  if (!do_2mir_) q_max = q_min - 1;
+
+  if (do_tab_ && info.level < 1 && info.pass < 6)
+    DGG_generateTabRowCuts( &cut_list, data, reinterpret_cast<const void *> (useSolver) );
+  
+  if (do_form_)
+    DGG_generateFormulationCuts( &cut_list, data, reinterpret_cast<const void *> (useSolver),
+				 info.formulation_rows,
+				 randomNumberGenerator_);
+  
+#ifdef CGL_DEBUG
+  const OsiRowCutDebugger debugg(si,probname_.c_str()) ;
+  const OsiRowCutDebugger *debugger = &debugg;
+  if (debugger&&!debugger->onOptimalPath(si))
+    debugger = NULL;
+  else
+    {if(talk) printf ("2mir_test: debug success\n");}
+#endif
+  
+  int i;
+  for ( i=0; i<cut_list.n; i++){
+    DGG_constraint_t *cut = cut_list.c[i];
+    OsiRowCut rowcut;
+    if (cut->nz<max_elements) {
+      // See if any zero coefficients!!!!!!!
+      int nZero=0;
+      for( int i=0; i < cut->nz; i++) {
+	if (!cut->coeff[i])
+	  nZero++;
+      }
+#ifdef CGL_DEBUG_ZERO
+      if (nZero) {
+	printf("Cut ");
+	for( int i=0; i < cut->nz; i++) {
+	  printf("%d %g ",cut->index[i],cut->coeff[i]);
+	}
+	printf("\n");
+      }
+#endif
+      if (nZero) {
+#ifdef CGL_DEBUG_ZERO
+	printf("TwoMir cut had %d zero coefficients!\n",nZero);
+#endif
+      } else {
+#ifdef CBC_CHECK_CUT
+	double rhs = cut->rhs;
+	int * cutIndex = cut->index;
+	double * packed = cut->coeff;
+	int i,number2=cut->nz;
+	int number=0;
+	double largest=0.0;
+	double smallest=1.0e30;
+	const double *colUpper = useSolver->getColUpper();
+	const double *colLower = useSolver->getColLower();
+	bool goodCut=true;
+	for (i=0;i<number2;i++) {
+	  double value=fabs(packed[i]);
+	  if (value<1.0e-9) {
+	    int iColumn = cutIndex[i];
+	    if (colUpper[iColumn]-colLower[iColumn]<100.0) {
+	      // weaken cut
+	      if (packed[i]>0.0) 
+		rhs -= value*colUpper[iColumn];
+	      else
+	 	rhs += value*colLower[iColumn];
+	    } else {
+	      // throw away
+	      goodCut=false;
+	      break;
+	    }
+	  } else {
+	    int iColumn = cutIndex[i];
+	    if (colUpper[iColumn]!=colLower[iColumn]) {
+	      largest=CoinMax(largest,value);
+	      smallest=CoinMin(smallest,value);
+	      cutIndex[number]=cutIndex[i];
+	      packed[number++]=packed[i];
+	    } else {
+	      // fixed so subtract out
+	      rhs -= packed[i]*colLower[iColumn];
+	    }
+	  }
+	}
+	if (largest<5.0e9*smallest&&goodCut) {
+	  rowcut.setRow(number, cutIndex, packed);
+	  rowcut.setUb(COIN_DBL_MAX);
+	  rowcut.setLb(rhs);
+	  cs.insert(rowcut);
+	}
+#else
+	rowcut.setRow(cut->nz, cut->index, cut->coeff);
+	rowcut.setUb(DBL_MAX);
+	rowcut.setLb(cut->rhs);
+	cs.insert(rowcut);
+#endif
+      }
+    
+#ifdef CGL_DEBUG
+      if (debugger) {
+        if (debugger->invalidCut(rowcut)) {
+          write_cut(cut);
+          printf ("2mir_test: debug failed, mayday, mayday **********************************\n");} 
+	//assert(0);
+      }
+      //assert(!debugger->invalidCut(rowcut));
+#endif
+    }
+  }
+  
+  for ( i=0; i<cut_list.n; i++)
+    DGG_freeConstraint (cut_list.c[i]);
+  DGG_list_free (&cut_list);
+  DGG_freeData (data);
+  if (!info.inTree&&((info.options&4)==4||((info.options&8)&&!info.pass))) {
+    int numberRowCutsAfter = cs.sizeRowCuts();
+    for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++) {
+      int length = cs.rowCutPtr(i)->row().getNumElements();
+      if (length<=max_elements_)
+	cs.rowCutPtr(i)->setGloballyValid();
+    }
+  }
+#ifdef COIN_HAS_CLP_TWOMIR
+  if (objective) {
+    int numberRowCutsAfter = cs.sizeRowCuts();
+    ClpSimplex * simplex = clpSolver->getModelPtr();
+    memcpy(simplex->objective(),objective,numberColumns*sizeof(double));
+    delete [] objective;
+    // take out locally useless cuts
+    const double * solution = si.getColSolution();
+    double primalTolerance = 1.0e-7;
+    for (int k = numberRowCutsAfter - 1; k >= numberRowCutsBefore; k--) {
+      const OsiRowCut * thisCut = cs.rowCutPtr(k) ;
+      double sum = 0.0;
+      int n = thisCut->row().getNumElements();
+      const int * column = thisCut->row().getIndices();
+      const double * element = thisCut->row().getElements();
+      assert (n);
+      for (int i = 0; i < n; i++) {
+	double value = element[i];
+	sum += value * solution[column[i]];
+      }
+      if (sum > thisCut->ub() + primalTolerance) {
+	sum = sum - thisCut->ub();
+      } else if (sum < thisCut->lb() - primalTolerance) {
+	sum = thisCut->lb() - sum;
+      } else {
+	sum = 0.0;
+      }
+      if (!sum) {
+	// take out
+	cs.eraseRowCut(k);
+      }
+    }
+#ifdef CLP_INVESTIGATE2
+    printf("OR %p pass %d inTree %c - %d cuts (but %d deleted)\n",
+       originalSolver_,info.pass,info.inTree?'Y':'N',
+       numberRowCutsAfter-numberRowCutsBefore,
+       numberRowCutsAfter-cs.sizeRowCuts());
+#endif
+  }
+
+  int numberRowCutsAfter = cs.sizeRowCuts();
+  if (!info.inTree) {
+    for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++) {
+      cs.rowCutPtr(i)->setGloballyValid();
+    }
+  }
+  if (twomirType==2) {
+    // back to original
+    int numberRows = clpSolver->getNumRows();
+    if (numberRows>numberOriginalRows) {
+      int numberDelete = numberRows-numberOriginalRows;
+      int * delRow = new int [numberDelete];
+      for (int i=0;i<numberDelete;i++)
+	delRow[i]=i+numberOriginalRows;
+      clpSolver->deleteRows(numberDelete,delRow);
+      delete [] delRow;
+    }
+  }
+#endif
+}
+
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglTwomir::CglTwomir () :
+  CglCutGenerator(),
+  probname_(),
+  randomNumberGenerator_(987654321),originalSolver_(NULL), 
+  away_(0.0005),awayAtRoot_(0.0005),twomirType_(0),
+  do_mir_(true), do_2mir_(true), do_tab_(true), do_form_(true),
+  t_min_(1), t_max_(1), q_min_(1), q_max_(1), a_max_(2),max_elements_(50000),
+  max_elements_root_(50000),form_nrows_(0) {}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglTwomir::CglTwomir (const CglTwomir & source) :
+  CglCutGenerator(source),
+  randomNumberGenerator_(source.randomNumberGenerator_),
+  originalSolver_(NULL),
+  away_(source.away_),
+  awayAtRoot_(source.awayAtRoot_),
+  twomirType_(source.twomirType_),
+  do_mir_(source.do_mir_),
+  do_2mir_(source.do_2mir_),
+  do_tab_(source.do_tab_), 
+  do_form_(source.do_form_),
+  t_min_(source.t_min_),
+  t_max_(source.t_max_),
+  q_min_(source.q_min_),
+  q_max_(source.q_max_),
+  a_max_(source.a_max_),
+  max_elements_(source.max_elements_),
+  max_elements_root_(source.max_elements_root_),
+  form_nrows_(source.form_nrows_)
+{
+  probname_ = source.probname_ ;
+  if (source.originalSolver_)
+    originalSolver_ = source.originalSolver_->clone();
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglTwomir::clone() const
+{
+  return new CglTwomir(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglTwomir::~CglTwomir ()
+{
+  delete originalSolver_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglTwomir &
+CglTwomir::operator=(const CglTwomir& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    randomNumberGenerator_ = rhs.randomNumberGenerator_;
+    away_=rhs.away_;
+    awayAtRoot_=rhs.awayAtRoot_;
+    twomirType_ = rhs.twomirType_;
+    delete originalSolver_;
+    if (rhs.originalSolver_)
+      originalSolver_ = rhs.originalSolver_->clone();
+    else
+      originalSolver_=NULL;
+    do_mir_=rhs.do_mir_;
+    do_2mir_=rhs.do_2mir_;
+    do_tab_=rhs.do_tab_; 
+    do_form_=rhs.do_form_;
+    t_min_=rhs.t_min_;
+    t_max_=rhs.t_max_;
+    q_min_=rhs.q_min_;
+    q_max_=rhs.q_max_;
+    a_max_=rhs.a_max_;
+    max_elements_=rhs.max_elements_;
+    max_elements_root_ = rhs.max_elements_root_;
+    form_nrows_=rhs.form_nrows_;
+  }
+  return *this;
+}
+// Pass in a copy of original solver (clone it)
+void 
+CglTwomir::passInOriginalSolver(OsiSolverInterface * solver)
+{
+  delete originalSolver_;
+  if (solver) {
+    if (!twomirType_)
+      twomirType_=1;
+    originalSolver_ = solver->clone();
+    originalSolver_->setHintParam(OsiDoDualInResolve, false, OsiHintDo);
+    // Temp - check if free variables
+    const double *colUpper = originalSolver_->getColUpper();
+    const double *colLower = originalSolver_->getColLower();
+    int ncol = originalSolver_->getNumCols();
+    int numberFree=0;
+    for (int i=0;i<ncol;i++) {
+      if (colLower[i]<-1.0e20&&colUpper[i]>1.0e20) 
+        numberFree++;
+    }
+    if (numberFree)
+      printf("CglTwoMir - %d free variables - take care\n",numberFree);
+  } else {
+    twomirType_=0;
+    originalSolver_=NULL;
+  }
+}
+
+int DGG_freeData( DGG_data_t *data )
+{
+  free(data->info);
+  free(data->lb);
+  free(data->ub);
+  free(data->x);
+  free(data->rc);
+
+  free(data);
+  return 0;
+}
+
+DGG_data_t* DGG_getData(const void *osi_ptr )
+{
+  DGG_data_t *data = NULL;
+  const OsiSolverInterface *si = reinterpret_cast<const OsiSolverInterface *> (osi_ptr);
+
+  data = reinterpret_cast<DGG_data_t*> (malloc( sizeof(DGG_data_t)) );
+
+  /* retrieve basis information */
+  CoinWarmStart *startbasis = si->getWarmStart();
+  const CoinWarmStartBasis *basis = dynamic_cast<const CoinWarmStartBasis*>(startbasis);
+
+  /* retrieve bounds information */
+  const double *colUpper = si->getColUpper();
+  const double *colLower = si->getColLower();
+  const double *rowUpper = si->getRowUpper();
+  const double *rowLower = si->getRowLower();
+  const double *redCost  = si->getReducedCost();
+  const double *dualVal  = si->getRowPrice();
+
+  /* retrieve current optimal solution */
+  const double *colSolut = si->getColSolution();
+
+  /* retrieve the matrix in row format */
+  const CoinPackedMatrix *rowMatrixPtr = si->getMatrixByRow();
+  const int *rowBeg = 0, *rowCnt = 0, *rowInd = 0;
+  const double *rowMat;
+    
+  rowBeg = rowMatrixPtr->getVectorStarts();
+  rowCnt = rowMatrixPtr->getVectorLengths();
+  rowMat = rowMatrixPtr->getElements();
+  rowInd = rowMatrixPtr->getIndices();
+
+  /* set number of columns and number of rows */
+  data->ncol = si->getNumCols();
+  data->nrow = si->getNumRows();
+
+  /* set ninteger */
+  data->ninteger = 0;
+
+  /* allocate memory for the arrays in 'data' */
+  data->info = reinterpret_cast<int*> (malloc( sizeof(int)*(data->ncol+data->nrow)) );
+  data->lb = reinterpret_cast<double*> (malloc( sizeof(double)*(data->ncol+data->nrow)) );
+  data->ub = reinterpret_cast<double*> (malloc( sizeof(double)*(data->ncol+data->nrow)) );
+  data->x  = reinterpret_cast<double*> (malloc( sizeof(double)*(data->ncol+data->nrow)) );
+  data->rc = reinterpret_cast<double*> (malloc( sizeof(double)*(data->ncol+data->nrow)) );
+
+  memset(data->info, 0, sizeof(int)*(data->ncol+data->nrow));
+
+  /* set parameters for column variables */
+  data->nbasic_col = 0;
+
+  for(int i=0; i < data->ncol; i++){
+    /* is variable basic */
+    if ( basis->getStructStatus(i) == CoinWarmStartBasis::basic ){
+      data->nbasic_col++;
+      DGG_setIsBasic(data,i);
+    }
+
+#if DGG_DEBUG_DGG
+    {
+      int error = 0;
+
+      if ( basis->getStructStatus(i) != CoinWarmStartBasis::basic )
+	if ( fabs(colSolut[i] - colUpper[i]) > DGG_BOUND_THRESH )
+	  if ( fabs(colSolut[i] - colLower[i]) > DGG_BOUND_THRESH ){
+	    fprintf(stdout, "WARNING!!!! : ");
+	    fprintf(stdout, "variable %d non-basic, lb = %f, ub = %f, x = %f\n",
+		    i, colLower[i], colUpper[i], colSolut[i]);
+	    error+=1;
+	  }
+	
+      if (error)
+	fprintf(stdout, "\nFOUND %d errors. BYE.\n", error);
+    }
+#endif
+
+    /* set variable bounds*/
+    data->lb[i] = colLower[i];
+    data->ub[i] = colUpper[i];
+
+
+    /* is variable integer */
+    if ( si->isInteger(i) ){
+      data->ninteger++;
+      DGG_setIsInteger(data,i);
+      /* tighten variable bounds*/
+      data->lb[i] = ceil(colLower[i]);
+      data->ub[i] = floor(colUpper[i]);
+    }
+ 
+    /* set x value */
+    data->x[i] = colSolut[i];
+
+    /* WARNING: remember to set rc!! Its not set!! */
+    data->rc[i] = redCost[i];
+  }
+
+  /* set parameters for row variables */
+
+  /* slack variables (row variables) work as follows:
+     for a ranged constraint, b_dw < ax < b_up, define a variable s so that
+     1) if b_up is not infinity:
+        ax + s = b_up,   0 < s < b_up - b_dw
+     2) if b_up is infinity:
+        ax - s = b_dw,   0 < s < b_up - b_dw
+  */
+  {
+    int i,j;
+    double activity;
+
+    data->nbasic_row = 0;
+    for(i=0, j=data->ncol; i < data->nrow; i++, j++){
+
+      /* check if the row is an equality constraint */ 
+      if ( fabs( rowUpper[i] - rowLower[i] ) <= DGG_BOUND_THRESH )
+        DGG_setEqualityConstraint(data,j);
+      
+      /* check if the row is bounded above/below and define variable bounds */
+      if ( rowUpper[i] < COIN_DBL_MAX )
+        DGG_setIsConstraintBoundedAbove(data,j);
+      if ( rowLower[i] > -1*COIN_DBL_MAX )
+        DGG_setIsConstraintBoundedBelow(data,j);
+
+      data->lb[j] = 0.0;
+      if (DGG_isConstraintBoundedAbove(data,j) && DGG_isConstraintBoundedBelow(data,j)) 
+          data->ub[j] = rowUpper[i] - rowLower[i];
+      else
+          data->ub[j] = COIN_DBL_MAX;
+
+      /* compute row activity. for this we need to go to the row in question,
+         and multiply all the coefficients times their respective variables.
+         For the moment, we will store the inverse of this value in 
+         the 'x' field (since it is in fact a partial computation of it)  */
+      {
+        int k;
+ 
+        activity = 0.0;
+	for(k=rowBeg[i]; k < rowBeg[i]+rowCnt[i]; k++)
+          activity += rowMat[k]*colSolut[rowInd[k]];
+      }
+  
+      /* compute x value */
+      if ( DGG_isConstraintBoundedAbove(data,j) )
+        data->x[j] = rowUpper[i] - activity;
+      else
+        data->x[j] = activity - rowLower[i];
+
+      if ( data->x[j] < -DGG_NULL_SLACK ){
+#if DGG_DEBUG_DGG
+	int k;
+	double norm = 0.0, min = DBL_MAX, amin = DBL_MAX, max = DBL_MIN;
+        printf("** warning: row %d has negative slack!\n", i);
+        for(k=rowBeg[i]; k < rowBeg[i]+rowCnt[i]; k++){
+	  norm += rowMat[k]*rowMat[k];
+	  if ( fabs(rowMat[k]) < amin ) amin = fabs(rowMat[k]);
+	  if ( rowMat[k] < min ) min = rowMat[k];
+	  if ( rowMat[k] > max ) max = rowMat[k];
+	}
+	norm = sqrt(norm);
+	printf("min = %f  amin = %f  max = %f\n", min, amin, max);
+	printf("rlower = %f activity = %f\n", rowLower[i], activity);
+	printf("norm = %f   (b-ax) = %f\n", norm, (rowLower[i] - activity));
+	printf("steepn = %f\n", (rowLower[i] - activity)/norm);
+#endif
+      }
+
+      data->rc[j] = dualVal[i];
+#if DGG_DEBUG_SOLVER
+      DGG_IF_EXIT( !DGG_isConstraintBoundedAbove(data,j) && !DGG_isConstraintBoundedBelow(data,j),
+                   1, "some row is not bounded above or below");
+#endif
+
+      /* is variable basic */
+      if ( basis->getArtifStatus(i) == CoinWarmStartBasis::basic ){
+        data->nbasic_row++;
+        DGG_setIsBasic(data,j);
+      }
+
+      /* is variable integer. For this we need to go to the row in question,
+         and check that the rhs is integer, and that all of the coefficients
+         and variables participating in the constraint are also integer.    */
+      {
+        int k;
+     
+        if( DGG_isConstraintBoundedAbove(data,j)) {
+          if ( frac_part(rowUpper[i]) > DGG_INTEGRALITY_THRESH )
+            goto DONE_ROW; 
+        }
+        else
+          if ( frac_part(rowLower[i]) > DGG_INTEGRALITY_THRESH )
+            goto DONE_ROW;
+ 
+        for(k=rowBeg[i]; k < rowBeg[i]+rowCnt[i]; k++)
+          if ( frac_part(rowMat[k]) > DGG_INTEGRALITY_THRESH || !DGG_isInteger(data, rowInd[k]))
+            goto DONE_ROW;
+        
+        DGG_setIsInteger(data, j); 
+        data->ninteger++;
+      }
+
+    DONE_ROW:;
+ 
+      /* set variable bounds: careful!! Later, remember to adjust 
+         the INFINITY to a DGG standard (to deal with neq solvers). */
+      /* WARNING: remember to set rc!! Its not set!! */
+    }
+  }
+
+  /* CLEANUP */
+  delete basis;
+  return data;
+}
+
+DGG_constraint_t*
+DGG_getSlackExpression(const void *osi_ptr, DGG_data_t* data, int row_index)
+{
+  DGG_constraint_t *row = 0;
+  int i,j;
+
+  /* retrieve the matrix in row format */
+  const OsiSolverInterface *si = reinterpret_cast<const OsiSolverInterface *> (osi_ptr);
+  const CoinPackedMatrix *rowMatrixPtr = si->getMatrixByRow();
+  const int *rowBeg = 0, *rowCnt = 0, *rowInd = 0;
+  const double *rowMat;
+  const double *rowUpper;
+  const double *rowLower;
+    
+  row = DGG_newConstraint(data->ncol);
+
+  rowBeg = rowMatrixPtr->getVectorStarts();
+  rowCnt = rowMatrixPtr->getVectorLengths();
+  rowMat = rowMatrixPtr->getElements();
+  rowInd = rowMatrixPtr->getIndices();
+
+  rowUpper = si->getRowUpper();
+  rowLower = si->getRowLower();
+
+#if DGG_DEBUG_DGG
+  if ( row_index < 0 || row_index > data->nrow )
+    DGG_THROW(0, "bad row index"); 
+#endif
+
+  /* copy the information into the row ADT */
+  row->nz = rowCnt[row_index];
+  for(j=0, i=rowBeg[row_index]; i < rowBeg[row_index]+rowCnt[row_index]; i++, j++){
+    row->coeff[j] = rowMat[i];
+    row->index[j] = rowInd[i];
+    if (DGG_isConstraintBoundedAbove (data, data->ncol + row_index))
+      row->coeff[j] = -row->coeff[j];
+  }
+  
+  row->sense = '?';
+  if ( DGG_isConstraintBoundedAbove(data, data->ncol + row_index) )
+    row->rhs = rowUpper[row_index];
+  else 
+    row->rhs = -rowLower[row_index];
+
+  return row;
+}
+
+int
+DGG_getTableauConstraint( int index,  const void *osi_ptr, DGG_data_t *data,
+                          DGG_constraint_t* tabrow, 
+                          const int * colIsBasic,
+                          const int * /*rowIsBasic*/,
+                          CoinFactorization & factorization,
+                          int mode )
+{
+
+#if DGG_DEBUG_DGG
+  /* ensure that the index corresponds to a basic variable */
+  if ( !DGG_isBasic(data, index) )
+     DGG_THROW(1, "index is non-basic");
+
+  /* ensure that the index corresponds to a column variable */
+  if ( index < 0 || index > (data->ncol - 1) )
+    DGG_THROW(1, "index not a column variable");
+#endif
+
+  /* obtain pointer to solver interface */
+  const OsiSolverInterface *si = reinterpret_cast<const OsiSolverInterface *> (osi_ptr);
+  DGG_TEST(!si, 1, "null OsiSolverInterfave");
+
+  /* obtain address of the LP matrix */
+  const CoinPackedMatrix *colMatrixPtr = si->getMatrixByCol();
+  const int* colBeg = colMatrixPtr->getVectorStarts();
+  const int* colCnt = colMatrixPtr->getVectorLengths();
+  const int* colInd = colMatrixPtr->getIndices();
+  const double* colMat = colMatrixPtr->getElements();
+
+  /* obtain row right-hand-sides */
+  const double *rowUpper = si->getRowUpper();
+  const double *rowLower = si->getRowLower();
+
+  /* allocate memory for constraint in non-sparse form */
+  int nz = 0;
+  double *value = NULL, rhs = 0.0;
+  value = reinterpret_cast<double*>(malloc(sizeof(double)*(data->nrow+data->ncol)));
+  memset(value, 0, sizeof(double)*(data->nrow+data->ncol));
+
+
+  /* obtain the tableau row coefficients for all variables */
+  /* note: we could speed this up by only computing non-basic variables */
+  {
+    int i, j, cnt = 0;
+    double one = 1.0;
+    CoinIndexedVector work;
+    CoinIndexedVector array;
+
+    work.reserve(data->nrow);
+    array.reserve(data->nrow);
+
+    array.setVector(1,&colIsBasic[index],&one);
+ 
+    factorization.updateColumnTranspose ( &work, &array );
+
+    int * arrayRows = array.getIndices();
+    double *arrayElements = array.denseVector();
+    cnt = array.getNumElements();
+
+    /* compute column (structural) variable coefficients */
+    for(j = 0; j < data->ncol; j++) {
+      value[j] = 0.0;
+      for(i=colBeg[j]; i < colBeg[j]+colCnt[j]; i++)
+        value[j] += colMat[i]*arrayElements[ colInd[i] ];
+    }
+
+#if DGG_DEBUG_SOLVER
+    /* check pivot */ 
+    if ( fabs(value[index] - 1.0) > DGG_INTEGRALITY_THRESH )
+       DGG_THROW(1, "pivot is not one"); 
+#endif
+
+    /* compute row variable (slack/logical) variable coefficients */
+
+    for(j = 0; j < cnt; j++){
+      if ( DGG_isEqualityConstraint(data,data->ncol + arrayRows[j]) && !mode )
+        value[ data->ncol + arrayRows[j] ] = 0.0;
+      else if ( DGG_isConstraintBoundedAbove(data, data->ncol + arrayRows[j]) )
+        value[ data->ncol + arrayRows[j] ] = arrayElements[ arrayRows[j] ];
+      else
+        value[ data->ncol + arrayRows[j] ] = -1*arrayElements[ arrayRows[j] ];
+    }
+
+    /* compute rhs */
+    rhs = 0.0;
+    for(i=0; i < cnt; i++){
+      if ( DGG_isConstraintBoundedAbove(data,data->ncol + arrayRows[i]) )
+        rhs += arrayElements[arrayRows[i]]*rowUpper[arrayRows[i]];
+      else
+        rhs += arrayElements[arrayRows[i]]*rowLower[arrayRows[i]];
+    }
+
+   /* free 'work' and 'array' ?? do the empty functions do it?? they are not 
+      cleared in CglGomory. Is that due to a mistake? Is it done on purpose? */ 
+   /*
+   work.empty();
+   array.empty();
+   */
+  }
+
+  /* count non-zeroes */
+  nz = 0; 
+  int j;
+  for( j=0; j<data->ncol+data->nrow; j++){
+    if ( fabs(value[j]) > DGG_MIN_TABLEAU_COEFFICIENT )
+      nz += 1;
+  }
+
+  /* put in sparse constraint format */
+  /* technical issue: should we let max_nz == nz or should we instead 
+     set max_nz == (nrow+ncol). The advantage of the latter approach
+     is that later, when we substitute the slacks, the denser column 
+     will not require us to re-allocate memory */
+
+  tabrow->max_nz = nz;
+
+  if (tabrow->coeff)
+    free(tabrow->coeff);
+  if (tabrow->index)
+    free(tabrow->index);
+  
+  tabrow->coeff = reinterpret_cast<double*> (malloc(sizeof(double)*nz));
+  tabrow->index = reinterpret_cast<int*> (malloc(sizeof(int)*nz));
+ 
+  tabrow->nz = 0;
+  for( j = 0; j < data->ncol + data->nrow; j++)
+    if ( fabs(value[j]) > DGG_MIN_TABLEAU_COEFFICIENT ){
+      tabrow->coeff[tabrow->nz] = value[j];
+      tabrow->index[tabrow->nz] = j;
+      tabrow->nz += 1;    
+    }
+
+  tabrow->sense = 'E';
+  tabrow->rhs = rhs;
+
+  /* CLEANUP */
+  free(value);
+
+  return 0;
+}
+
+int
+DGG_getFormulaConstraint( int da_row,  
+                                  const void *osi_ptr,   
+				  DGG_data_t *data, 
+                                  DGG_constraint_t* form_row )
+{
+  /* ensure that the da_row corresponds to a row */
+  if ( data->nrow <= da_row || 0> da_row)      DGG_THROW(1, "row out of range...");
+  
+  /* obtain pointer to solver interface */
+  const OsiSolverInterface *si = reinterpret_cast<const OsiSolverInterface *> (osi_ptr);
+  //DGG_TEST(!si, 1, "null OsiSolverInterfave");
+  
+  /* obtain address of the LP matrix */
+  const CoinPackedMatrix *rowMatrixPtr = si->getMatrixByRow();
+  const int* rowBeg = rowMatrixPtr->getVectorStarts();
+  const int* rowCnt = rowMatrixPtr->getVectorLengths();
+  const int* rowInd = rowMatrixPtr->getIndices();
+  const double* rowMat = rowMatrixPtr->getElements();
+
+  /* obtain row right-hand-sides */
+  const double *rowUpper = si->getRowUpper();
+  const double *rowLower = si->getRowLower();
+ 
+  int nz = rowCnt[da_row]; 
+
+  form_row->nz = nz; 
+  form_row->max_nz = nz+1;
+ 
+  int i;
+  for( i=0; i < nz; i++) form_row->coeff[i] = rowMat[rowBeg[da_row]+i];
+  for( i=0; i < nz; i++) form_row->index[i] = rowInd[rowBeg[da_row]+i];
+
+  if ( DGG_isConstraintBoundedAbove(data,data->ncol + da_row) ){
+    form_row->rhs = rowUpper[da_row];
+    form_row->sense = 'L';
+  }
+  else{
+    form_row->rhs = rowLower[da_row];
+    form_row->sense = 'G';
+  }
+  if ( DGG_isEqualityConstraint(data,data->ncol + da_row)  )
+    form_row->sense = 'E';
+
+  /* now add slack/surplus if there is one */
+  if ( DGG_isEqualityConstraint(data,data->ncol + da_row) == 0 ){
+    form_row->index[nz] =  data->ncol + da_row; 
+    if ( DGG_isConstraintBoundedAbove(data, data->ncol + da_row) )
+      form_row->coeff[nz] = 1; 
+    else
+      form_row->coeff[nz] = -1; 
+    form_row->nz +=1;
+  }
+
+  return 0;
+
+}
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+//---------------------------------------------------------------
+
+/******************** CONSTRAINT ADTs *****************************************/
+DGG_constraint_t* DGG_newConstraint(int max_arrays)
+{
+   DGG_constraint_t *c = NULL;
+   
+   if (max_arrays <= 0) return NULL;
+   c = reinterpret_cast<DGG_constraint_t*> (malloc(sizeof(DGG_constraint_t)));
+   c->nz = 0;
+   c->max_nz = max_arrays;
+   c->rhs = 0.0;
+   c->sense = '?';
+
+   c->coeff = NULL;
+   c->index = NULL;
+   c->coeff = reinterpret_cast<double*>(malloc(sizeof(double)*max_arrays));
+   c->index = reinterpret_cast<int*>(malloc(sizeof(int)*max_arrays));
+   return c;
+}
+
+void DGG_freeConstraint(DGG_constraint_t *c)
+{
+  if (c == NULL) return;
+  if (c->coeff) free(c->coeff);
+  if (c->index) free(c->index);
+  free(c);
+}
+
+DGG_constraint_t *DGG_copyConstraint(DGG_constraint_t* c)
+{
+  DGG_constraint_t *nc = NULL;
+
+  if (!c || c->max_nz <= 0) return nc;
+  nc = DGG_newConstraint(c->max_nz);
+  if (nc == NULL) return nc;
+
+  nc->nz = c->nz;
+  nc->rhs = c->rhs;
+  nc->sense = c->sense;
+
+  memcpy(nc->coeff, c->coeff, sizeof(double)*nc->nz);
+  memcpy(nc->index, c->index, sizeof(int)*nc->nz);
+
+  return nc;
+}
+
+void DGG_scaleConstraint(DGG_constraint_t *c, int t)
+{
+  int i;
+
+  c->rhs *= t;
+  if (t < 0){
+    if (c->sense == 'G') c->sense = 'L';
+    else if (c->sense == 'L') c->sense = 'G';
+  }
+  for(i=0; i<c->nz; i++)  c->coeff[i] *= t;
+}
+
+void DGG_list_init (DGG_list_t *l)
+{
+  l->n = 0;
+  l->c = NULL;
+  l->ctype = NULL;
+  l->alpha = NULL;
+}
+
+void DGG_list_free(DGG_list_t *l)
+{
+  if (l->c != NULL) free (l->c);
+  if (l->ctype != NULL) free (l->ctype);
+  if (l->alpha != NULL) free (l->alpha);
+}
+
+int DGG_list_addcut (DGG_list_t *l, DGG_constraint_t *cut, int ctype, double alpha)
+{
+  l->n ++;
+  l->c = reinterpret_cast<DGG_constraint_t **>(realloc (l->c, l->n * sizeof(DGG_constraint_t *)));
+  l->ctype = reinterpret_cast<int *>(realloc (l->ctype, l->n * sizeof (int)));
+  l->alpha = reinterpret_cast<double *>(realloc (l->alpha, l->n * sizeof (double)));
+
+  if (l->c == NULL || l->ctype == NULL || l->alpha == NULL){
+    printf ("No memory, bailing out\n");
+    return -1;
+  }
+
+  l->c[l->n - 1] = cut;
+  l->ctype[l->n - 1] = ctype;
+  l->alpha[l->n - 1] = alpha;
+  return 0;
+}
+
+void DGG_list_delcut (DGG_list_t *l, int i)
+{
+  if (i >= l->n && i < 0) return;
+
+  DGG_freeConstraint (l->c[i]);
+  l->c[i] = l->c[l->n - 1];
+  l->ctype[i] = l->ctype[l->n - 1];
+  l->alpha[i] = l->alpha[l->n - 1];
+  l->n --;
+}
+
+/******************* CONSTRAINT MANIPULATION **********************************/
+/* VARIABLES CLOSE TO UPPER BOUNDS:
+ we will substitute: x' = (u - x); hence the constraint will change from ax ~ b
+ to -ax' ~ b - au note: the new bounds of x' will be, 0 <= x' <= u - l
+ VARIABLES  CLOSE TO LOWER BOUNDS:
+ we will substitute: x' = (x - l); hence, the constraint will change from
+ ax ~ b to ax' ~ b - al. note: some variable lower bounds may have changed
+ when doing the complement  in the previous stage - this must be taken into
+ account. note: the new bounds  of x' will be, 0 <= x'  <= u - l */
+
+int DGG_transformConstraint( DGG_data_t *data,
+                             double **x_out,
+			     double **rc_out,
+                             char **isint_out,
+                             DGG_constraint_t *constraint )
+{
+  double half;
+  double *px = reinterpret_cast<double*> (malloc( sizeof(double)*constraint->max_nz ));
+  double *rc = reinterpret_cast<double*> (malloc( sizeof(double)*constraint->max_nz ));
+  char   *pi = reinterpret_cast<char*>   (malloc( sizeof(char)  *constraint->max_nz ));
+
+  {
+    int i, idx;
+
+    for(i=0; i < constraint->nz; i++){
+      idx = constraint->index[i];
+
+      px[i] = data->x[idx];
+      rc[i] = data->rc[idx];
+      pi[i] = static_cast<char>(DGG_isInteger(data, idx)); 
+      half = (data->ub[idx] - data->lb[idx]) / 2;
+
+      if ( data->ub[idx] - data->x[idx] < half ){
+	px[i] = data->ub[idx] - data->x[idx];
+	if (fabs(px[i]) <= DGG_BOUND_THRESH)
+	  px[i] = 0.0;
+	constraint->rhs -= constraint->coeff[i]*data->ub[idx];
+	constraint->coeff[i] *= -1;
+      }
+      else {
+	px[i] = data->x[idx] - data->lb[idx];
+	if (fabs(px[i]) <= DGG_BOUND_THRESH)
+	  px[i] = 0.0;
+	constraint->rhs -= constraint->coeff[i]*data->lb[idx];
+      }
+    }
+  }
+
+  *x_out = px;
+  *rc_out = rc;
+  *isint_out = pi;
+
+#if DGG_DEBUG_DGG
+  DGG_TEST(DGG_isConstraintViolated(data, constraint), 1, "bad transformation");
+#endif
+ 
+  return 0;
+}
+
+int DGG_unTransformConstraint( DGG_data_t *data, 
+                               DGG_constraint_t *constraint )
+{
+  int i, idx;
+  double half;
+  
+  for(i=0; i < constraint->nz; i++){
+    idx = constraint->index[i];
+    half = (data->ub[idx] - data->lb[idx]) / 2;
+    
+    if ( data->ub[idx] - data->x[idx] < half ){
+      constraint->rhs -= constraint->coeff[i]*data->ub[idx];	
+      constraint->coeff[i] *= -1;
+    }
+    else 
+      constraint->rhs += constraint->coeff[i]*data->lb[idx];
+  }
+  return 0;
+}
+
+int
+DGG_substituteSlacks( const void *solver_ptr, 
+                          DGG_data_t *data, 
+                          DGG_constraint_t *cut )
+{
+  int i,j, lnz;
+  double *lcut, lrhs;
+  DGG_constraint_t *row=NULL;
+ 
+  /* lcut will store all the column coefficients. allocate space and init. */
+  lcut = reinterpret_cast<double*>(malloc(sizeof(double)*data->ncol)); 
+  memset(lcut, 0, sizeof(double)*data->ncol);
+ 
+  /* initialize lrhs */
+  lrhs = cut->rhs;
+
+  /* set coefficients in lcut */
+  /* technical: we could speed this up by re-using allocated memory 
+     for row->coeff and row->index                                  */
+  for(i=0; i < cut->nz; i++){
+    if ( cut->index[i] < data->ncol )
+      lcut[ cut->index[i] ] += cut->coeff[i];
+    else{
+      row = DGG_getSlackExpression(solver_ptr, data, (cut->index[i] - data->ncol));
+      
+      for(j=0; j < row->nz; j++)
+	lcut[ row->index[j] ] += row->coeff[j]*cut->coeff[i];
+      lrhs -= row->rhs*cut->coeff[i];
+      DGG_freeConstraint(row);
+    }
+  }
+
+  /* count nz in new constraint */
+  lnz = 0;
+  for(i=0; i < data->ncol; i++)
+    if ( fabs(lcut[i]) > DGG_MIN_TABLEAU_COEFFICIENT )
+      lnz += 1;
+
+  /* free row->coeff and row->index, and re-allocate */
+  free(cut->coeff); cut->coeff = 0;
+  free(cut->index); cut->index = 0;
+
+  cut->nz = lnz;
+  cut->max_nz = lnz;
+  if (lnz)
+    {
+      cut->coeff = reinterpret_cast<double*> (malloc( sizeof(double)*lnz ));
+      cut->index = reinterpret_cast<int*> (malloc( sizeof(int)*lnz ));
+    }
+
+  /* set new constraint */
+  lnz = 0;
+  for(i=0; i < data->ncol; i++){
+    if ( fabs(lcut[i]) > DGG_MIN_TABLEAU_COEFFICIENT ){
+      cut->coeff[lnz] = lcut[i];
+      cut->index[lnz] = i;
+      lnz += 1;
+    }
+  }
+  cut->rhs = lrhs;
+
+  free(lcut);
+  return 0; 
+}
+
+int DGG_nicefyConstraint( const void * /*solver_ptr*/, 
+                          DGG_data_t *data,
+			  DGG_constraint_t *cut)
+													
+{
+  
+  double min_coef = COIN_DBL_MAX, max_coef = COIN_DBL_MIN;
+  
+  DGG_TEST(cut->sense == 'L', 1, "can't nicefy an L constraint");
+  
+  int i;
+  for( i=0; i<cut->nz; i++) // first clean out noise
+    if( fabs(cut->coeff[i]) < DGG_NICEFY_MIN_ABSVALUE)
+      cut->coeff[i] = 0;
+
+  for( i=0; i<cut->nz; i++){
+    
+    if( DGG_isInteger(data, cut->index[i])){// look at integral vars.
+
+      double aht = ABOV(cut->coeff[i]);
+      double ub  = data->ub[ cut->index[i]];
+
+      if(aht <  DGG_NICEFY_MIN_FIX){// coefficient = integer + epsylon
+	
+	cut->coeff[i] = floor( cut->coeff[i]);
+	double ahtu = aht * ub;
+	
+	if(ahtu<DGG_NICEFY_MAX_PADDING)
+	  cut->rhs -= ahtu;// safely remove the fractional part
+       	else 
+	  cut->coeff[i] += DGG_NICEFY_MIN_FIX; // inflate the fractional part
+      }
+      else 
+	if (1-aht <  DGG_NICEFY_MIN_FIX) // coefficient = integer - epsylon
+	  cut->coeff[i] = ceil( cut->coeff[i]);
+      
+    }// done with integers
+    else // now look at continuous variables
+      if ( cut->coeff[i] < DGG_NICEFY_MIN_ABSVALUE) // delete all negative and noise
+	cut->coeff[i] = 0.0;
+      else 
+	if(cut->coeff[i] <  DGG_NICEFY_MIN_FIX) {// coefficient = epsylon
+	  double au = cut->coeff[i] * data->ub[ cut->index[i]];
+	
+	  if(au<DGG_NICEFY_MAX_PADDING){ // safely remove the variable
+	    cut->coeff[i] = 0.0;
+	    cut->rhs -= au;
+	  }
+	  else 
+	    cut->coeff[i] = DGG_NICEFY_MIN_FIX; // inflate the coefficient
+	}// done with continuous variables too
+
+    double abs_coef = fabs(cut->coeff[i]);
+    min_coef = DGG_MIN(min_coef, abs_coef);
+    max_coef = DGG_MAX(max_coef, abs_coef);
+  }
+
+  cut->sense = 'G';
+  /*
+  if ( max_coef > DGG_NICEFY_MAX_RATIO*min_coef ) // kill the cut if numbers are all over the place
+    cut->nz = 0;
+  */
+  return 0;
+
+}
+
+/******************* CUT GENERATION *******************************************/
+int
+DGG_generateTabRowCuts( DGG_list_t *cut_list,
+			    DGG_data_t *data,
+			    const void *solver_ptr )
+
+{
+  int k, rval = 0;
+  DGG_constraint_t *base = NULL;
+  int nc = cut_list->n;
+
+  base = DGG_newConstraint(data->ncol + data->nrow);
+
+  if(talk) printf ("2mir_test: generating tab row cuts\n");
+  /* allocate memory for basic column/row indicators */
+  int *rowIsBasic = 0, *colIsBasic = 0;
+  rowIsBasic = reinterpret_cast<int*>(malloc(sizeof(int)*data->nrow));
+  colIsBasic = reinterpret_cast<int*>(malloc(sizeof(int)*data->ncol));
+    
+  /* initialize the IsBasic arrays with -1 / 1 values indicating 
+     where the basic rows and columns are. NOTE: WE could do this 
+     only once and keep it in osi_data at the expense of space!! */
+
+  int i;
+  for( i=0; i<data->ncol; i++){
+    if ( DGG_isBasic(data,i) ) colIsBasic[i] = 1;
+    else                       colIsBasic[i] = -1;
+  }
+  for( i=0; i<data->nrow; i++){
+    if ( DGG_isBasic(data,i+data->ncol) ) rowIsBasic[i] = 1;
+    else                                  rowIsBasic[i] = -1;
+  }
+
+  /* obtain factorization */
+  CoinFactorization factorization;
+  /* obtain address of the LP matrix */
+  const OsiSolverInterface *si = reinterpret_cast<const OsiSolverInterface *> (solver_ptr);
+  const CoinPackedMatrix *colMatrixPtr = si->getMatrixByCol();
+  rval = factorization.factorize(*colMatrixPtr, rowIsBasic, colIsBasic); 
+  /* 0 = okay. -1 = singular. -2 = too many in basis. -99 = memory. */
+  DGG_TEST2(rval, 1, "factorization error = %d", rval);
+
+  for(k=0; k<data->ncol; k++){
+    if (!(DGG_isBasic(data, k) && DGG_isInteger(data,k))) continue;
+
+    double frac = frac_part (data->x[k]);
+    if (frac < data->gomory_threshold || frac > 1-data->gomory_threshold) continue;
+
+    base->nz = 0;
+    rval = DGG_getTableauConstraint(k, solver_ptr, data, base, 
+                                    colIsBasic,rowIsBasic,factorization,0);
+    DGG_CHECKRVAL(rval, rval);
+
+    if (base->nz == 0){
+      printf ("2mir_test: why does constraint not exist ?\n");
+      continue;
+    }
+
+    if (base->nz > 500) continue;
+    rval = DGG_generateCutsFromBase(base, cut_list, data, solver_ptr);
+    DGG_CHECKRVAL(rval, rval);
+  }
+
+  free(rowIsBasic);
+  free(colIsBasic);
+
+   if(talk) printf ("2mir_test: generated %d tab cuts\n", cut_list->n - nc); fflush (stdout);
+  DGG_freeConstraint(base);
+  return rval;
+}
+
+int DGG_generateFormulationCuts( DGG_list_t *cut_list,
+				 DGG_data_t *data,
+				 const void *solver_ptr,
+				 int nrows,
+				 CoinThreadRandom & generator)
+{
+  int k, rval = 0;
+  DGG_constraint_t *base = NULL;
+  int num_rows = (data->nrow < nrows) ? data->nrow : nrows;
+  int nc = cut_list->n;
+
+  base = DGG_newConstraint(data->ncol + data->nrow);
+
+  if(talk) printf ("2mir_test: generating form row cuts %d\n", num_rows);
+  for(k=0; k<num_rows; k++) {
+    base->nz = 0;
+
+    rval = DGG_getFormulaConstraint(k, solver_ptr, data, base);
+    DGG_CHECKRVAL1(rval, rval);
+
+    //printf ("generating formulation for row %d\n", k);
+    rval = DGG_generateFormulationCutsFromBase(base, data->x[data->ncol+k],
+					       cut_list, data, solver_ptr,
+					       generator);
+    DGG_CHECKRVAL1(rval, rval);
+    if (base->nz == 0){
+#ifdef COIN_DEVELOP
+      printf ("why does constraint not exist ?\n");
+#endif
+      continue;
+    }
+  }
+
+ CLEANUP:
+  if(talk) printf ("2mir_test: generated %d form cuts\n", cut_list->n - nc); fflush (stdout);
+  DGG_freeConstraint(base);
+  return rval;
+}
+
+
+int DGG_generateFormulationCutsFromBase( DGG_constraint_t *base,
+					 double slack,
+					 DGG_list_t *cut_list,
+					 DGG_data_t *data,
+					 const void *solver_ptr,
+					 CoinThreadRandom & generator)
+{
+  int i, p, rval;
+  int int_skala;
+  double skala;
+  int num_inlist = 0;
+  int* skala_list = reinterpret_cast<int*> (malloc( sizeof(int)*base->nz ));
+  char *isint = NULL;
+  double *xout = NULL, *rcout = NULL;
+  DGG_constraint_t *scaled_base = NULL;
+  int tot_int = 0;
+  double prob_choose = 0.0;
+  rval = DGG_transformConstraint(data, &xout, &rcout, &isint, base);
+  DGG_CHECKRVAL1(rval, rval);
+
+  for(p = 0; p < base->nz; p++)  if(isint[p]) tot_int ++;
+  if (tot_int == 0) goto CLEANUP;
+
+  prob_choose = 5.0/tot_int;
+
+  for(p = 0; p < base->nz; p++) {
+    if(isint[p]) if(generator.randomDouble() < prob_choose){
+      if(xout[p]<0.01) continue;
+
+      skala =fabs(base->coeff[p]);
+      if(skala<0.01)  continue;
+
+      // check if slack is too large
+      if (fabs(slack/skala) > 0.5) continue;
+
+      scaled_base = DGG_copyConstraint(base);
+      DGG_CHECKRVAL1((scaled_base == NULL),-1);
+
+      if(base->sense == 'L') {
+	skala = -skala; 
+	scaled_base->sense = 'G';
+      }
+      
+      int_skala = int(100*skala);
+
+      for(i = 0; i< num_inlist; i++) 
+	if(int_skala == skala_list[i]) 
+	  goto END_LOOP;
+
+      skala_list[num_inlist++] = int_skala;
+
+      scaled_base->rhs = base->rhs/skala;
+      for(i = 0; i<base->nz; i++) 
+	scaled_base->coeff[i] = base->coeff[i] / skala;
+ 
+      rval = DGG_unTransformConstraint(data, scaled_base);
+      DGG_CHECKRVAL1(rval, rval);
+
+      rval = DGG_generateCutsFromBase(scaled_base, cut_list,
+				      data, solver_ptr);
+      DGG_CHECKRVAL1(rval, rval);
+      
+    END_LOOP:
+      DGG_freeConstraint(scaled_base);
+      scaled_base = NULL;
+    }      
+  }
+
+ CLEANUP:
+  if (isint) free(isint);    
+  if (xout)  free(xout);   
+  if (rcout)  free(rcout);   
+  if (skala_list) free(skala_list);
+  if (scaled_base != NULL) DGG_freeConstraint (scaled_base);
+  return rval;
+}
+
+int
+DGG_generateCutsFromBase( DGG_constraint_t *orig_base,
+			  DGG_list_t *cut_list,
+			  DGG_data_t *data,
+			  const void *solver_ptr )
+{
+  int rval = 0;
+  int t;
+  double *x = NULL, *rc = NULL;
+  char *isint = NULL;
+  DGG_constraint_t *base = NULL;
+  bool   not_nicefied = true;
+  int new_pos = cut_list->n;
+
+  //  DGG_constraint_t *keep_origbase = DGG_copyConstraint(orig_base); //for debug only ------
+
+  if (orig_base->sense == 'L') return 0;
+  if (orig_base->nz == 0) return 0;
+
+  rval = DGG_transformConstraint(data, &x, &rc, &isint, orig_base);
+  double frac = frac_part(orig_base->rhs);
+  //printf ("frac = %.7f, r %.7f, fr %.7f\n", frac, orig_base->rhs, floor(orig_base->rhs));
+  if (rval || frac < data->gomory_threshold || frac > 1-data->gomory_threshold){
+    free (x); free (rc); free (isint);
+    return 0;
+  }
+
+  int min_t = t_min;
+  int min_q = q_min;
+  if (orig_base->sense == 'G' && min_t < 1) min_t = 1;
+  if (orig_base->sense == 'G' && min_q < 1) min_q = 1;
+  
+  if (min_q > 0 &&  min_t > 0 ) {
+    not_nicefied = false;
+    rval = DGG_nicefyConstraint(solver_ptr, data, orig_base);
+    DGG_CHECKRVAL(rval, rval);
+
+    if (orig_base->nz == 0){
+      if(talk) printf ("2mir_test: Nicefy returns empty constraint\n"); rval = 0; goto CLEANUP;
+    }
+  }
+
+  for(t = min_t; t <= t_max ; t++){
+    if (t == 0) continue;
+
+    base = DGG_copyConstraint(orig_base);
+    DGG_TEST(!base, 1, "error making copy of base");
+
+    DGG_scaleConstraint (base, t);
+
+    if(not_nicefied){
+      rval = DGG_nicefyConstraint(solver_ptr, data, base);
+      DGG_CHECKRVAL(rval, rval);
+      if (base->nz == 0){
+	 if(talk) printf ("2mir_test: Nicefy returns empty constraint\n"); goto MIR_DONE;
+      }
+    }
+    
+    if ( DGG_isBaseTrivial(data, base) ) goto MIR_DONE;
+
+    rval = DGG_addMirToList(base, isint, x, cut_list, data, orig_base);
+    DGG_CHECKRVAL(rval, rval);
+
+  MIR_DONE:
+    DGG_freeConstraint(base);
+  }
+
+  for( t = min_q; t <= q_max; t++ ){
+    if (t == 0) continue;
+
+    base = DGG_copyConstraint(orig_base);
+    DGG_TEST(!base, 1, "error making copy of base");
+
+    DGG_scaleConstraint (base, t);
+
+    if(not_nicefied){
+      rval = DGG_nicefyConstraint(solver_ptr, data, base);
+      DGG_CHECKRVAL(rval, rval);
+      if (base->nz == 0){
+	 if(talk) printf ("2mir_test: Nicefy returns empty constraint\n"); goto TWOMIR_DONE;
+      }
+    }
+    
+    if ( DGG_isBaseTrivial(data, base) ) goto TWOMIR_DONE;
+
+    rval = DGG_add2stepToList(base, isint, x, rc, cut_list, data, orig_base);
+    DGG_CHECKRVAL(rval, rval);
+    
+  TWOMIR_DONE:
+    DGG_freeConstraint(base);
+  }
+
+  int i;
+  for ( i = cut_list->n-1; i>=new_pos; i--){
+    DGG_constraint_t *lcut = cut_list->c[i];
+
+    rval = DGG_unTransformConstraint(data, lcut);
+    DGG_CHECKRVAL(rval, rval);
+    
+    rval = DGG_substituteSlacks(solver_ptr, data, lcut);
+    DGG_CHECKRVAL(rval, rval);
+
+ 
+
+    if ( !DGG_isCutDesirable(lcut, data) ){
+      DGG_list_delcut (cut_list, i);
+      continue;
+    }
+    //else  testus(lcut);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+    /*
+    if ( data->opt_x && DGG_cutsOffPoint(data->opt_x, lcut) ){
+      //DGG_cutDisplay_sparse(data, data->opt_x, lcut, stdout);
+      DGG_TEST(1,1, "new cut is infeasible for optimal solution\n");
+    }
+    */
+  }
+
+ CLEANUP:
+  if (x) free(x);
+  if (rc) free (rc);
+  if (isint) free(isint);
+  return 0;
+}
+
+int
+DGG_addMirToList ( DGG_constraint_t *base, char *isint, double * /*x*/,
+		   DGG_list_t *list, DGG_data_t * /*data*/,
+		   DGG_constraint_t * /*orig_base*/ )
+{
+  int rval = 0;
+  DGG_constraint_t *cut = NULL;
+
+  rval = DGG_buildMir(isint, base, &cut); 
+  DGG_CHECKRVAL(rval, rval);
+
+  DGG_list_addcut(list, cut, DGG_TMIR_CUT, 0.0);
+
+  return 0;
+}
+
+int
+DGG_add2stepToList ( DGG_constraint_t *base, char *isint, double * /*x*/,
+				double *rc, DGG_list_t *list, DGG_data_t *data,
+		     DGG_constraint_t * /*orig_base*/ )
+{
+  int rval;
+  DGG_constraint_t *cut = NULL;
+  int i;
+  double norm_val, best_norm_val, best_norm_alpha=-1.0;
+  double rc_val, best_rc_val,  best_rc_alpha=-1.0;
+  double vht, bht, alpha;
+  
+  best_rc_val = best_norm_val = COIN_DBL_MAX;
+  
+  bht = ABOV(base->rhs);
+
+  double best_rc = 0;
+  for(i=0; i<base->nz; i++) if (isint[i]) best_rc = CoinMax(best_rc, fabs(rc[i]));
+  double  rc_cutoff = best_rc / 10;
+
+  for(i=0; i<base->nz; i++){
+    if (!isint[i]) continue;
+    if (fabs(rc[i]) <= rc_cutoff) continue; //too unimportant
+
+    vht = ABOV(base->coeff[i]);
+    if(vht >= bht)  continue;  // too big
+    if(vht < bht/a_max) continue; // too small
+    alpha = vht;
+    int kk = 1;
+    while ( !DGG_is2stepValid(alpha, bht) &&  bht/alpha <= a_max) {
+      alpha = vht/kk; 
+      kk++;
+      if (kk>1000)
+        break;
+    }
+    if ( !DGG_is2stepValid(alpha, bht) )    continue;
+      
+    rval = DGG_build2step(alpha, isint, base, &cut);
+    DGG_CHECKRVAL(rval, rval);
+
+    rc_val = COIN_DBL_MAX; // this gives a lower bound on obj. fn. improvement
+
+    for(i=0; i<cut->nz; i++) if(cut->coeff[i]> 1E-6){
+      rc_val = CoinMin(rc_val, fabs(rc[i])/cut->coeff[i]);
+    }
+    rc_val *= cut->rhs;
+
+    norm_val = 0; // this is the square of the L2 norm
+ 
+    for(i=0; i<cut->nz; i++) if(cut->coeff[i]> 1E-6){
+      norm_val += (cut->coeff[i]*cut->coeff[i]);
+    }
+
+    norm_val /= cut->rhs * cut->rhs;
+         
+    if (rc_val < best_rc_val )  {	
+      best_rc_val = rc_val; best_rc_alpha = alpha;  }
+
+    if (norm_val < best_norm_val ) {	
+      best_norm_val = norm_val;  best_norm_alpha = alpha;  }
+
+    DGG_freeConstraint(cut);
+  }
+ 
+  if( best_rc_val> 1E-6 && best_rc_alpha != -1.0){
+    rval = DGG_build2step(best_rc_alpha, isint, base, &cut);
+    DGG_CHECKRVAL(rval, rval);
+    DGG_list_addcut(list, cut, DGG_2STEP_CUT, best_rc_alpha);
+  }
+  else if (best_norm_alpha != -1.0){
+    rval = DGG_build2step(best_norm_alpha, isint, base, &cut);
+    DGG_CHECKRVAL(rval, rval);
+    DGG_list_addcut(list, cut, DGG_2STEP_CUT, best_norm_alpha);
+  }
+
+  return 0;
+}
+
+int DGG_buildMir( char *isint,
+		  DGG_constraint_t *base,
+		  DGG_constraint_t **cut_out )
+{
+  int i, lnz = 0;
+  double b   = (base->rhs);
+  double bht = ABOV(b);
+  double bup = ceil(b);
+  DGG_constraint_t *tmir = NULL;
+
+  DGG_TEST( base->sense == 'L', 1, "this form not valid for L");
+  DGG_TEST( base->nz == 0, 1, "base must have some coefficients\n");
+
+  tmir = DGG_newConstraint( base->nz );
+  tmir->sense = 'G';
+  tmir->rhs = bht * bup;
+
+  for(i=0; i<base->nz; i++){
+    double v   = base->coeff[i];
+
+    if (!isint[i]) {
+      if (v > 0.0) tmir->coeff[lnz] = v;
+      else         tmir->coeff[lnz] = 0.0;
+    }
+    else {
+      double vht = ABOV(v); 
+      DGG_IF_EXIT( vht<0, 1, "negative vht");
+      tmir->coeff[lnz]  = bht * floor(v) + DGG_MIN(bht,vht);
+    }
+
+    tmir->index[lnz] = base->index[i];
+    lnz += 1;
+  }
+
+  tmir->nz = lnz;
+  *cut_out = tmir;
+
+  return 0;
+}
+
+int DGG_build2step( double alpha,
+		    char *isint,
+		    DGG_constraint_t *base,
+		    DGG_constraint_t **cut_out )
+
+{
+  DGG_constraint_t *tmir = 0;
+
+  int i,  lnz = 0;
+  double vht, bht, bup, rho, tau, k;
+  double b = (base->rhs);
+
+  DGG_TEST( base->sense == 'L', 1, "this form not valid for L");
+  DGG_TEST( base->nz == 0, 1, "base must have some coefficients\n");
+
+  bht = ABOV(b);  
+  bup = ceil(b); 
+  tau = ceil(bht/alpha); 
+  rho = bht - alpha*floor(bht/alpha);
+
+  /* ensure bht > alpha > 0 */
+  DGG_TEST3( (bht <= alpha) || (alpha <= 0.0), 1, "bad alpha (%f) / bht (%f) pair", alpha, bht);
+  /* ensure that we are not in a limiting case */
+  DGG_TEST( DGG_is_a_multiple_of_b(alpha, bht), 1, "can't generate simple 2mir in limiting case");
+  /* ensure that rho is not zero */
+  DGG_TEST2( rho < DGG_MIN_RHO, 1, "rho (%f) too small", rho);
+
+  /* initialize constraint */
+  tmir = DGG_newConstraint( base->nz );
+
+  tmir->rhs = bup*tau*rho;
+  tmir->sense = 'G';
+
+  /* compute cut coefficients */
+  for(i=0; i<base->nz; i++){
+    double v   = base->coeff[i];
+
+    if (!isint[i]) {
+      if (v > 0.0) tmir->coeff[lnz] = v;
+      else         tmir->coeff[lnz] = 0.0;
+    }
+    else {
+      vht = v - floor(v);
+      DGG_IF_EXIT( vht < 0.0, 1, "negative vht");
+      k   = DGG_MIN(tau-1,floor(vht/alpha));
+      tmir->coeff[lnz]  = floor(v)*tau*rho +  k*rho + DGG_MIN(rho,vht-k*alpha);
+    }
+
+    tmir->index[lnz] = base->index[i];
+    lnz += 1;
+  }
+
+  tmir->nz = lnz;
+  *cut_out = tmir;
+
+  return 0;
+}
+
+/******************* TEST / DEBUGGING ROUTINES ********************************/
+
+/* DGG_is2stepValid:
+   checks that:
+
+   bht > alpha > 0
+   (1/alpha) >= tau > (bht/alpha)
+*/
+int DGG_is2stepValid(double alpha, double bht)
+{
+
+  /* d */
+  double tau;
+
+  /* ensure that alpha is not null or negative */
+  if ( alpha < DGG_MIN_ALPHA )
+    return 0;
+
+  /* compute tau and tau_lim */
+  tau = ceil( bht / alpha );
+
+  /* make sure alpha is not a divisor of bht */
+  if ( DGG_is_a_multiple_of_b(alpha, bht) )
+    return 0;
+
+  /* page 15, definition 12 */
+  /* check if alpha is admissible for simple-2-step-tmir */
+
+  if ( (bht > alpha) && (alpha > 0.0) )
+    if ( (1/alpha) >= tau )
+      return 1;
+
+  /* not admissible */
+  return 0;
+}
+
+/* checks that its worth doing a 1MIR on the constraint. More precisely,
+
+- Is the RHS null? 
+- Are there any integer variables set at fractional values?           */
+
+int DGG_isBaseTrivial(DGG_data_t *d, DGG_constraint_t* c)
+{
+
+  /* is rhs sufficiently fractional */
+  if ( frac_part(ABOV(c->rhs)) < d->gomory_threshold )
+    return 1;
+
+  if ( (1.0 - frac_part(ABOV(c->rhs))) < d->gomory_threshold )
+    return 1;
+
+  return 0;
+}
+
+
+/* tests lhs vs rhs of a constraint */
+int DGG_isConstraintViolated(DGG_data_t *d, DGG_constraint_t *c)
+{
+  double lhs = DGG_cutLHS(c, d->x);
+  double rhs = c->rhs;
+
+  /* compare LHS and RHS */
+  if (c->sense == 'G')
+    if ( lhs > (rhs - DGG_NULL_SLACK) )
+      return 0;
+  if (c->sense == 'L')
+    if ( lhs < (rhs + DGG_NULL_SLACK) )
+      return 0;
+  if (c->sense == 'E')
+    if ( fabs(lhs - rhs) < DGG_NULL_SLACK )
+      return 0;
+
+  return 0;
+
+}
+
+double DGG_cutLHS(DGG_constraint_t *c, double *x)
+{
+
+  int i;
+  double lhs = 0.0;
+
+  for(i=0; i < c->nz; i++)
+    lhs += c->coeff[i]*x[c->index[i]];
+
+  return lhs;
+}
+
+int DGG_isCutDesirable(DGG_constraint_t *c, DGG_data_t *d)
+{
+  double lhs, rhs;
+
+  lhs = DGG_cutLHS(c, d->x);
+  rhs = c->rhs;
+
+  if (c->nz > 500) return 0;
+
+  /* if the cut is not violated, return 0 */
+  if (c->sense == 'G')
+    if ( lhs > (rhs - DGG_NULL_SLACK) )
+      return 0;
+  if (c->sense == 'L')
+    if ( lhs < (rhs + DGG_NULL_SLACK) )
+      return 0;
+  if (c->sense == 'E')
+    if ( fabs(lhs - rhs) < DGG_NULL_SLACK )
+      return 0;
+  return 1;
+}
+
+/******************** SIMPLE MACROS AND FUNCTIONS *****************************/
+
+int DGG_is_even(double vht, double bht, int tau, int q)
+{
+
+  double v2 = V2I(bht, tau, q);
+
+  if ( vht > v2 )
+    return 1;
+
+  return 0;
+}
+
+double frac_part(double value) 
+{
+  return value-floor(value);
+}
+
+int DGG_is_a_multiple_of_b(double a, double b)
+{
+  double c = b/a;
+  
+  if ( (b - a*floor(c)) < DGG_MIN_RHO )
+    return 1;
+
+  return 0;
+}
+
+int DGG_cutsOffPoint(double *x, DGG_constraint_t *cut)
+{
+
+  int i;
+  double LHS = 0.0;
+
+	for(i=0; i < cut->nz; i++)
+	  LHS += cut->coeff[i]*(x[ cut->index[i] ]);
+
+  //fprintf(stdout, "LHS = %f, SENSE = %c, RHS = %f\n", LHS, cut->sense, cut->rhs);
+  if ( cut->sense == 'E' )
+    if ( fabs(LHS - cut->rhs) > DGG_NULL_SLACK )
+      goto BAD;
+  if (cut->sense == 'G' )
+    if ( (cut->rhs - LHS) > DGG_NULL_SLACK )
+      goto BAD;
+  if (cut->sense == 'L' )
+    if ( (LHS - cut->rhs) > DGG_NULL_SLACK )
+      goto BAD;
+
+  return 0;
+
+  BAD:
+
+  fprintf(stdout, "LHS = %f, SENSE = %c, RHS = %f\n", LHS, cut->sense, cut->rhs);
+  DGG_TEST(1, 1, "found a bad cut!");
+  return 0;
+}
+// Returns true if needs optimal basis to do cuts
+bool 
+CglTwomir::needsOptimalBasis() const
+{
+  return true;
+}
+
+// Away stuff
+void CglTwomir::setAway(double value)
+{
+  if (value>0.0&&value<=0.5)
+    away_=value;
+}
+double CglTwomir::getAway() const
+{
+  return away_;
+}
+
+// Away stuff at root
+void CglTwomir::setAwayAtRoot(double value)
+{
+  if (value>0.0&&value<=0.5)
+    awayAtRoot_=value;
+}
+double CglTwomir::getAwayAtRoot() const
+{
+  return awayAtRoot_;
+}
+
+// This can be used to refresh any information
+void 
+CglTwomir::refreshSolver(OsiSolverInterface * solver)
+{
+  if (originalSolver_) {
+    delete originalSolver_;
+    originalSolver_ = solver->clone();
+  }
+}
+// Create C++ lines to get to current state
+std::string
+CglTwomir::generateCpp( FILE * fp) 
+{
+  CglTwomir other;
+  fprintf(fp,"0#include \"CglTwomir.hpp\"\n");
+  fprintf(fp,"3  CglTwomir twomir;\n");
+  if (t_min_!=other.t_min_||t_max_!=other.t_max_)
+    fprintf(fp,"3  twomir.setMirScale(%d,%d);\n",t_min_,t_max_);
+  else
+    fprintf(fp,"4  twomir.setMirScale(%d,%d);\n",t_min_,t_max_);
+  if (q_min_!=other.q_min_||q_max_!=other.q_max_)
+    fprintf(fp,"3  twomir.setTwomirScale(%d,%d);\n",q_min_,q_max_);
+  else
+    fprintf(fp,"4  twomir.setTwomirScale(%d,%d);\n",q_min_,q_max_);
+  if (do_mir_!=other.do_mir_||do_2mir_!=other.do_2mir_||
+      do_tab_!=other.do_tab_||do_form_!=other.do_form_)
+    fprintf(fp,"3  twomir.setCutTypes(%s,%s,%s,%s);\n",
+	    do_mir_ ? "true" : "false",
+	    do_2mir_ ? "true" : "false",
+	    do_tab_ ? "true" : "false",
+	    do_form_ ? "true" : "false");
+  else
+    fprintf(fp,"4  twomir.setCutTypes(%s,%s,%s,%s);\n",
+	    do_mir_ ? "true" : "false",
+	    do_2mir_ ? "true" : "false",
+	    do_tab_ ? "true" : "false",
+	    do_form_ ? "true" : "false");
+  if (a_max_!=other.a_max_)
+    fprintf(fp,"3  twomir.setAMax(%d);\n",a_max_);
+  else
+    fprintf(fp,"4  twomir.setAMax(%d);\n",a_max_);
+  if (max_elements_!=other.max_elements_)
+    fprintf(fp,"3  twomir.setMaxElements(%d);\n",max_elements_);
+  else
+    fprintf(fp,"4  twomir.setMaxElements(%d);\n",max_elements_);
+  if (max_elements_root_!=other.max_elements_root_)
+    fprintf(fp,"3  twomir.setMaxElementsRoot(%d);\n",max_elements_root_);
+  else
+    fprintf(fp,"4  twomir.setMaxElementsRoot(%d);\n",max_elements_root_);
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  twomir.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  twomir.setAggressiveness(%d);\n",getAggressiveness());
+  return "twomir";
+}
diff --git a/cbits/coin/CglTwomir.hpp b/cbits/coin/CglTwomir.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglTwomir.hpp
@@ -0,0 +1,565 @@
+// $Id: CglTwomir.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CglTwomir_H
+#define CglTwomir_H
+#include <string>
+
+#include "CglCutGenerator.hpp"
+#include "CoinFactorization.hpp"
+
+typedef struct
+{
+
+  int nz;             /* current length of arrays index[] and coeff[] */
+  int max_nz;         /* max length of arrays index[] and coeff[] */
+  double *coeff;      /* coefficient of each variable in the constraint */
+  int *index;         /* index of the variable (value in 0 ... nrow+ncol) */
+  double rhs;         /* rhs of the constraint */
+  char sense;         /* ?? is it necessary */
+
+} DGG_constraint_t;
+
+typedef struct{
+  int n;
+  DGG_constraint_t **c;
+  int *ctype;
+  double *alpha;
+} DGG_list_t;
+
+/******************** BASIS INFORMATION ADTs **********************************/
+typedef struct{
+  int q_min;
+  int q_max;
+  int t_min;
+  int t_max;
+  int a_max;
+  int max_elements;
+} cutParams;
+
+typedef struct
+{
+  double gomory_threshold; /* factional variable must be this away from int */
+  int ncol,        /* number of columns in LP */
+    nrow,        /* number of constaints in LP */
+    ninteger;    /* number of integer variables in LP */
+
+  int nbasic_col,  /* number of basic columns in the LP */
+    nbasic_row;  /* number of basic rows in the LP */
+
+  /* the following arrays are all of size (ncol+nrow) */
+  int *info;       /* description of each variable (see below) */
+  double *lb;      /* specifies the lower bound (if any) of each variable */
+  double *ub;      /* specifies the upper bound (if any) of each variable */
+  double *x;       /* current solution */
+  double *rc;      /* current reduced cost */
+  double *opt_x;
+
+  cutParams cparams;
+} DGG_data_t;
+
+/* the following macros allow us to decode the info of the DGG_data
+   type. The encoding is as follows,
+   bit 1 : if the variable is basic or not (non-basic).
+   bit 2 : if the variable is integer or or not (rational).
+   bit 3 : if the variable is structural or not (artifical). 
+   bit 4 : if the variable is non-basic and at its upper bound 
+   (else if non-basic at lower bound). */
+
+#define DGG_isBasic(data,idx) ((data->info[idx])&1)
+#define DGG_isInteger(data,idx) ((data->info[idx] >> 1)&1)
+#define DGG_isStructural(data,idx) ((data->info[idx] >> 2)&1)
+#define DGG_isEqualityConstraint(data,idx) ((data->info[idx] >> 3)&1)
+#define DGG_isNonBasicAtUB(data,idx) ((data->info[idx] >> 4)&1)
+#define DGG_isNonBasicAtLB(data,idx) ((data->info[idx] >> 5)&1)
+#define DGG_isConstraintBoundedAbove(data,idx) ((data->info[idx] >> 6)&1)
+#define DGG_isConstraintBoundedBelow(data,idx) ((data->info[idx] >> 7)&1)
+
+#define DGG_setIsBasic(data,idx) ((data->info[idx]) |= 1)
+#define DGG_setIsInteger(data,idx) ((data->info[idx]) |= (1<<1))
+#define DGG_setIsStructural(data,idx) ((data->info[idx]) |= (1<<2))
+#define DGG_setEqualityConstraint(data,idx) ((data->info[idx]) |= (1<<3))
+#define DGG_setIsNonBasicAtUB(data,idx) ((data->info[idx]) |= (1<<4))
+#define DGG_setIsNonBasicAtLB(data,idx) ((data->info[idx]) |= (1<<5))
+#define DGG_setIsConstraintBoundedAbove(data,idx) ((data->info[idx]) |= (1<<6))
+#define DGG_setIsConstraintBoundedBelow(data,idx) ((data->info[idx]) |= (1<<7))
+
+class CoinWarmStartBasis;
+/** Twostep MIR Cut Generator Class */
+class CglTwomir : public CglCutGenerator {
+
+  friend void CglTwomirUnitTest(const OsiSolverInterface * siP,
+					  const std::string mpdDir );
+
+
+public:
+
+  /// Problem name
+  std::string probname_;
+    
+  /**@name Generate Cuts */
+  //@{
+  /** Generate Two step MIR cuts either from the tableau rows or from the
+      formulation rows
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs, 
+			     const CglTreeInfo info = CglTreeInfo());
+  /// Return true if needs optimal basis to do cuts (will return true)
+  virtual bool needsOptimalBasis() const;
+
+  /**@name Change criterion on which scalings to use (default = 1,1,1,1) */
+  //@{
+  /// Set
+  void setMirScale (int tmin, int tmax) {t_min_ = tmin; t_max_ = tmax;}
+  void setTwomirScale (int qmin, int qmax) {q_min_ = qmin; q_max_ = qmax;}
+  void setAMax (int a) {a_max_ = a;}
+  void setMaxElements (int n) {max_elements_ = n;}
+  void setMaxElementsRoot (int n) {max_elements_root_ = n;}
+  void setCutTypes (bool mir, bool twomir, bool tab, bool form)
+  { do_mir_ = mir; do_2mir_ = twomir; do_tab_ = tab; do_form_ = form;}
+  void setFormulationRows (int n) {form_nrows_ = n;}
+
+  /// Get
+  int getTmin() const {return t_min_;}
+  int getTmax() const {return t_max_;}
+  int getQmin() const {return q_min_;}
+  int getQmax() const {return q_max_;}
+  int getAmax() const {return a_max_;}
+  int getMaxElements() const {return max_elements_;}
+  int getMaxElementsRoot() const {return max_elements_root_;}
+  int getIfMir() const { return do_mir_;}
+  int getIfTwomir() const { return do_2mir_;}
+  int getIfTableau() const { return do_tab_;}
+  int getIfFormulation() const { return do_form_;}
+  //@}
+
+  /**@name Change criterion on which variables to look at.  All ones
+   more than "away" away from integrality will be investigated 
+  (default 0.05) */
+  //@{
+  /// Set away
+  void setAway(double value);
+  /// Get away
+  double getAway() const;
+  /// Set away at root
+  void setAwayAtRoot(double value);
+  /// Get away at root
+  double getAwayAtRoot() const;
+  /// Return maximum length of cut in tree
+  virtual int maximumLengthOfCutInTree() const
+  { return max_elements_;}
+  //@}
+
+  /**@name Change way TwoMir works */
+  //@{
+  /// Pass in a copy of original solver (clone it)
+  void passInOriginalSolver(OsiSolverInterface * solver);
+  /// Returns original solver
+  inline OsiSolverInterface * originalSolver() const
+  { return originalSolver_;}
+  /// Set type - 0 normal, 1 add original matrix one, 2 replace
+  inline void setTwomirType(int type)
+  { twomirType_=type;}
+  /// Return type
+  inline int twomirType() const
+  { return twomirType_;}
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglTwomir ();
+
+  /// Copy constructor 
+  CglTwomir (const CglTwomir &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglTwomir & operator=(const CglTwomir& rhs);
+  
+  /// Destructor 
+  virtual  ~CglTwomir ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  /// This can be used to refresh any inforamtion
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  //@}
+      
+private:
+  // Private member data
+  /**@name Private member data */
+  //@{
+  /// Threadsafe random number generator
+  CoinThreadRandom randomNumberGenerator_;
+  /// Original solver
+  OsiSolverInterface * originalSolver_;
+  /// Only investigate if more than this away from integrality
+  double away_;
+  /// Only investigate if more than this away from integrality (at root)
+  double awayAtRoot_;
+  /// Type - 0 normal, 1 add original matrix one, 2 replace
+  int twomirType_;
+  bool do_mir_;
+  bool do_2mir_;
+  bool do_tab_;
+  bool do_form_;
+
+  int t_min_;  /// t_min - first value of t to use for tMIR inequalities
+  int t_max_;  /// t_max - last value of t to use for tMIR inequalities
+  int q_min_;  /// q_min - first value of t to use for 2-Step tMIR inequalities
+  int q_max_;  /// q_max - last value of t to use for 2-Step tMIR inequalities
+  int a_max_;  /// a_max - maximum value of bhat/alpha
+  int max_elements_; /// Maximum number of elements in cut
+  int max_elements_root_; /// Maximum number of elements in cut at root
+  int form_nrows_; //number of rows on which formulation cuts will be generated
+  //@}
+};
+
+//#############################################################################
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <math.h>
+#include <float.h>
+#include <cassert>
+#include <iostream.h>
+*/
+
+/******************** DEBUG DEFINITIONS ***************************************/
+
+#define DGG_DEBUG_DGG 1
+#define DGG_TRACE_ERRORS 0
+#define DGG_DISPLAY   0
+#define DGG_AUTO_CHECK_CUT_OFF_OPTIMAL 1
+
+/******************** CONFIGURATION DEFAULTS **********************************/
+
+#define DGG_DEFAULT_METHOD 2
+#define DGG_DEFAULT_TMIN 1
+#define DGG_DEFAULT_TMAX 1
+#define DGG_DEFAULT_TAUMIN 2
+#define DGG_DEFAULT_TAUMAX 6
+#define DGG_DEFAULT_MAX_CUTS 500
+#define DGG_DEFAULT_IMPROVEMENT_THRESH 0.001
+#define DGG_DEFAULT_NBELOW_THRESH INT_MAX 
+#define DGG_DEFAULT_NROOT_ROUNDS 2
+#define DGG_DEFAULT_NEGATIVE_SCALED_TWOSTEPS 0
+#define DGG_DEFAULT_ALPHA_RULE 0
+#define DGG_DEFAULT_CUT_INC 250
+#define DGG_DEFAULT_CUT_FORM 0
+#define DGG_DEFAULT_NICEFY 0
+#define DGG_DEFAULT_ONLY_DELAYED 0
+#define DGG_DEFAULT_DELAYED_FREQ 9999999 
+#define DGG_DEFAULT_LPROWS_FREQ 9999999
+#define DGG_DEFAULT_WHICH_FORMULATION_CUTS 2
+
+/******************** SOLVER CONFIGURATION DEFINITIONS ************************/
+
+#define DGG_OSI 0
+#define DGG_CPX 1
+#define DGG_QSO 2
+
+/* determines the solver to be used */
+#define DGG_SOLVER DGG_OSI
+
+/* adds checking routines to make sure solver works as expected */
+#define DGG_DEBUG_SOLVER 0
+
+/* turn off screen output from solver */
+#define DGG_SOLVER_SCREEN_FLAG 0
+
+/******************** CUT DEFINITIONS *****************************************/
+
+/* internal names for cut types */
+#define DGG_TMIR_CUT 1
+#define DGG_2STEP_CUT 2
+
+/* internal names for alpha-selection rules */
+#define DGG_ALPHA_MIN_SUM 0
+#define DGG_ALPHA_RANDOM_01 1
+#define DGG_ALPHA_RANDOM_COEFF 2
+#define DGG_ALPHA_ALL 3
+#define DGG_ALPHA_MAX_STEEP 5
+
+/******************** PRECISION & NUMERICAL ISSUES DEFINITIONS ****************/
+
+/* how steep a cut must be before adding it to the lp */
+#define DGG_MIN_STEEPNESS 1.0e-4
+#define DGG_MAX_L2NORM 1.0e7
+
+/* 0 = min steepness, 1 = max norm */
+#define DGG_NORM_CRITERIA 1
+
+/* internal representation of +infinity */
+#define UB_MAX DBL_MAX
+
+/* used to define how fractional a basic-integer variable must be
+   before choosing to use it to generate a TMIR cut on.
+   OSI's default is 1.0e-7 */
+#define DGG_GOMORY_THRESH 0.005
+
+#define DGG_RHS_THRESH 0.005
+
+/* used for comparing variables to their upper bounds.
+   OSI's default is 1.0e-7.
+   We set it to 1.0e6 because e-7 seems too sensitive. 
+   In fact, with e-7 the problem dsbmip.mps complains. */
+#define DGG_BOUND_THRESH 1.0e-6
+
+/* used for comparing the lhs (activity) value of a tableau row
+   with the rhs. This is only used for debugging purposes. */
+#define DGG_EQUALITY_THRESH 1.0e-5
+
+/* used for comparing a variable's lower bound to 0.0
+   and determining if we need to shift the variable    */
+#define DGG_SHIFT_THRESH 1.0e-6
+
+/* used for determing how far from an integer is still an integer.
+   This value is used for comparing coefficients to integers.
+   OSI's default is 1.0e-10.                               */
+#define DGG_INTEGRALITY_THRESH 1.0e-10
+
+/* the min value that a coeff can have in the tableau row
+   before being set to zero. */
+#define CBC_CHECK_CUT
+#ifndef CBC_CHECK_CUT
+#define DGG_MIN_TABLEAU_COEFFICIENT 1.0e-8
+#else
+#define DGG_MIN_TABLEAU_COEFFICIENT 1.0e-12
+#endif
+
+/* smallest value rho is allowed to have for a simple 2-step MIR
+   (ie: not an extended two-step MIR) */
+#define DGG_MIN_RHO 1.0e-7
+#define DGG_MIN_ALPHA 1.0e-7
+
+/* when a slack is null: used to check if a cut is satisfied or not. */
+#define DGG_NULL_SLACK 1.0e-5
+
+/* nicefy constants */
+#define DGG_NICEFY_MIN_ABSVALUE 1.0e-13
+#define DGG_NICEFY_MIN_FIX 1.0e-7
+#define DGG_NICEFY_MAX_PADDING 1.0e-6
+#define DGG_NICEFY_MAX_RATIO 1.0e9
+
+
+/******************** ERROR-CATCHING MACROS ***********************************/
+#if DGG_TRACE_ERRORS > 0
+
+#define __DGG_PRINT_LOC__(F) fprintf(((F==0)?stdout:F), " in %s (%s:%d)\n", __func__, __FILE__, __LINE__)
+
+#define DGG_THROW(A,REST...) {\
+ fprintf(stdout, ##REST); \
+ __DGG_PRINT_LOC__(stdout); \
+ return (A);}
+
+#define DGG_IF_EXIT(A,B,REST...) {\
+ if(A) {\
+ fprintf(stdout, ##REST); \
+ __DGG_PRINT_LOC__(stdout); \
+ exit(B);}}
+
+#define DGG_CHECKRVAL(A,B) {\
+ if(A) {\
+   __DGG_PRINT_LOC__(stdout); \
+   return B; } }
+
+#define DGG_CHECKRVAL1(A,B) {\
+ if(A) {\
+   __DGG_PRINT_LOC__(stdout); \
+   rval = B; goto CLEANUP; } }
+
+#define DGG_WARNING(A, REST...) {\
+  if(A) {\
+	  fprintf(stdout, ##REST); \
+		__DGG_PRINT_LOC__(stdout); \
+		}}
+
+#define DGG_TEST(A,B,REST...) {\
+ if(A) DGG_THROW(B,##REST) }
+
+#define DGG_TEST2(A,B,C,REST)   {DGG_TEST(A,B,C,REST) }
+#define DGG_TEST3(A,B,C,D,REST) {DGG_TEST(A,B,C,D,REST) }
+
+#else
+
+#define DGG_IF_EXIT(A,B,REST) {if(A) {fprintf(stdout, REST);exit(B);}}
+
+#define DGG_THROW(A,B) return(A)
+
+#define DGG_CHECKRVAL(A,B) {  if(A) return(B); }
+#define DGG_CHECKRVAL1(A,B){ if(A) { rval = B; goto CLEANUP; } }
+
+#define DGG_TEST(A,B,REST) { if(A) return(B);}
+#define DGG_TEST2(A,B,REST,C) { DGG_TEST(A,B,REST) }
+#define DGG_TEST3(A,B,REST,C,D) { DGG_TEST(A,B,REST) }
+
+#endif
+
+/******************** SIMPLE MACROS AND FUNCTIONS *****************************/
+
+#define DGG_MIN(a,b) ( (a<b)?a:b )
+#define DGG_MAX(a,b) ( (a>b)?a:b )
+#define KREM(vht,alpha,tau)  (DGG_MIN( ceil(vht / alpha), tau ) - 1)
+#define LMIN(vht, d, bht) (DGG_MIN( floor(d*bht/bht), d))
+#define ABOV(v) (v - floor(v))
+#define QINT(vht,bht,tau) ( (int)floor( (vht*(tau-1))/bht ) )
+#define V2I(bht,tau,i) ( ((i+1)*bht / tau) )
+
+int DGG_is_even(double vht, double bht, int tau, int q);
+double frac_part(double value);
+int DGG_is_a_multiple_of_b(double a, double b);
+
+
+/* free function for DGG_data_t. Frees internal arrays and data structure */
+int DGG_freeData( DGG_data_t *data );
+
+/******************** CONSTRAINT ADTs *****************************************/
+DGG_constraint_t* DGG_newConstraint(int max_arrays);
+void DGG_freeConstraint(DGG_constraint_t *c);
+DGG_constraint_t *DGG_copyConstraint(DGG_constraint_t *c);
+void DGG_scaleConstraint(DGG_constraint_t *c, int t);
+
+/******************** CONFIGURATION *******************************************/
+void DGG_list_init (DGG_list_t *l);
+int DGG_list_addcut (DGG_list_t *l, DGG_constraint_t *cut, int ctype, double alpha);
+void DGG_list_delcut (DGG_list_t *l, int i);
+void DGG_list_free(DGG_list_t *l);
+
+/******************* SOLVER SPECIFIC METHODS **********************************/
+DGG_data_t *DGG_getData(const void *solver_ptr);
+
+/******************* CONSTRAINT MANIPULATION **********************************/
+
+/* DGG_transformConstraint: manipulates a constraint in the following way: 
+
+packs everything in output
+
+1 - variables at their upper bounds are substituted for their 
+complements. This is done by adjusting the coefficients and 
+the right hand side (simple substitution). 
+
+2 - variables with non-zero lower bounds are shifted.            */
+
+int DGG_transformConstraint( DGG_data_t *data,
+                             double **x_out, 
+			     double **rc_out,
+                             char **isint_out,
+                             DGG_constraint_t *constraint );
+
+/* DGG_unTransformConstraint : 
+
+1 - Undoes step (1) of DGG_transformConstraint 
+2 - Undoes step (2) of DGG_transformConstraint                  */
+ 
+int DGG_unTransformConstraint( DGG_data_t *data, 
+                               DGG_constraint_t *constraint );
+
+/* substitutes each slack variable by the structural variables which 
+   define it. This function, hence, changes the constraint 'cut'.    */
+
+int DGG_substituteSlacks( const void *solver_ptr, 
+                          DGG_data_t *data, 
+                          DGG_constraint_t *cut );
+
+int DGG_nicefyConstraint( const void *solver_ptr, 
+                          DGG_data_t *data,
+			  DGG_constraint_t *cut);
+
+/******************* CUT GENERATION *******************************************/
+int DGG_getFormulaConstraint( int row_idx,  
+                              const void *solver_ptr,   
+			      DGG_data_t *data, 
+                              DGG_constraint_t* row );
+
+int DGG_getTableauConstraint( int index, 
+                              const void *solver_ptr, 
+                              DGG_data_t *data, 
+                              DGG_constraint_t* tabrow,
+                              const int * colIsBasic,
+                              const int * rowIsBasic,
+                              CoinFactorization & factorization,
+                              int mode );
+
+DGG_constraint_t* DGG_getSlackExpression(const void *solver_ptr, DGG_data_t* data, int row_index);
+
+  int DGG_generateTabRowCuts( DGG_list_t *list,
+			      DGG_data_t *data,
+			      const void *solver_ptr );
+
+  int DGG_generateFormulationCuts( DGG_list_t *list,
+				   DGG_data_t *data,
+				   const void *solver_ptr,
+				   int nrows,
+				   CoinThreadRandom & generator);
+
+
+  int DGG_generateFormulationCutsFromBase( DGG_constraint_t *base,
+					   double slack,
+					   DGG_list_t *list,
+					   DGG_data_t *data,
+					   const void *solver_ptr,
+					   CoinThreadRandom & generator);
+
+  int DGG_generateCutsFromBase( DGG_constraint_t *base,
+				DGG_list_t *list,
+				DGG_data_t *data,
+				const void *solver_ptr );
+
+int DGG_buildMir( char *isint,
+                  DGG_constraint_t *base,
+                  DGG_constraint_t **cut_out );
+
+int DGG_build2step( double alpha,
+                    char *isint,
+                    DGG_constraint_t *base,
+                    DGG_constraint_t **cut_out );
+
+  int DGG_addMirToList   ( DGG_constraint_t *base,
+			   char *isint,
+			   double *x,
+			   DGG_list_t *list,
+			   DGG_data_t *data,
+			   DGG_constraint_t *orig_base );
+
+  int DGG_add2stepToList ( DGG_constraint_t *base,
+			   char *isint,
+			   double *x,
+			   double *rc,
+			   DGG_list_t *list,
+			   DGG_data_t *data,
+			   DGG_constraint_t *orig_base );
+
+/******************* CUT INFORMATION ******************************************/
+
+double DGG_cutLHS(DGG_constraint_t *c, double *x);
+int DGG_isCutDesirable(DGG_constraint_t *c, DGG_data_t *d);
+
+/******************* TEST / DEBUGGING ROUTINES ********************************/
+
+int DGG_isConstraintViolated(DGG_data_t *d, DGG_constraint_t *c);
+
+int DGG_isBaseTrivial(DGG_data_t *d, DGG_constraint_t* c);
+int DGG_is2stepValid(double alpha, double bht);
+
+int DGG_cutsOffPoint(double *x, DGG_constraint_t *cut);
+
+//#############################################################################
+/** A function that tests the methods in the CglTwomir class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglTwomirUnitTest(const OsiSolverInterface * siP,
+		       const std::string mpdDir);
+
+
+#endif
+
+
diff --git a/cbits/coin/CglZeroHalf.cpp b/cbits/coin/CglZeroHalf.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglZeroHalf.cpp
@@ -0,0 +1,572 @@
+// $Id: CglZeroHalf.cpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2010, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+#include <cstdlib>
+#include <cmath>
+#include <cstdio>
+#include <cfloat> 
+#include <cassert>
+
+#include "CoinPragma.hpp"
+#include "CglZeroHalf.hpp" 
+#include "CoinPackedVector.hpp"
+#include "CoinSort.hpp"
+#include "CoinPackedMatrix.hpp"
+
+//-------------------------------------------------------------
+void
+CglZeroHalf::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
+				const CglTreeInfo info)
+{
+  if (mnz_) {
+    int cnum=0,cnzcnt=0;
+    int *cbeg=NULL, *ccnt=NULL,*cind=NULL,*cval=NULL,*crhs=NULL;
+    char *csense=NULL;
+    const double * solution = si.getColSolution();
+    if ((flags_&1)==0) {
+      // redo bounds
+      const double * columnLower = si.getColLower();
+      const double * columnUpper = si.getColUpper();
+      int numberColumns = si.getNumCols();
+      for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+	if (vlb_[iColumn]!=COIN_INT_MAX) {
+	  int ilo,iup;
+	  double lo = columnLower[iColumn];
+	  if (lo<-COIN_INT_MAX)
+	    lo=-COIN_INT_MAX;
+	  ilo= static_cast<int> (ceil(lo));
+	  double up = columnUpper[iColumn];
+	  if (up>COIN_INT_MAX)
+	    up=COIN_INT_MAX;
+	  iup= static_cast<int> (floor(up));
+	  vlb_[iColumn]=ilo;
+	  vub_[iColumn]=iup;
+	}
+      }
+    }
+    if (true) {
+    cutInfo_.sep_012_cut(mr_,mc_,mnz_,
+				 mtbeg_,mtcnt_, mtind_, mtval_,
+				 vlb_, vub_,
+				 mrhs_, msense_,
+				 solution,
+				 info.inTree ? false : true,
+				 &cnum,&cnzcnt,
+				 &cbeg,&ccnt,&cind,&cval,&crhs,&csense);
+    } else {
+      int k = 4*mr_+2*mnz_;
+      int * temp = new int[k];
+      int * mtbeg = temp;
+      int * mtcnt = mtbeg + mr_;
+      int * mtind = mtcnt+mr_;
+      int * mtval = mtind+mnz_;
+      int * mrhs = mtval+mnz_;
+      char * msense = reinterpret_cast<char*> (mrhs+mr_);
+      int i;
+      k=0;
+      int kel=0;
+      for (i=0;i<mr_;i++) {
+	int kel2=kel;
+	int rhs = mrhs_[i];
+	for (int j=mtbeg_[i];j<mtbeg_[i]+mtcnt_[i];j++) {
+	  int iColumn=mtind_[j];
+	  int value=mtval_[j];
+	  if (vlb_[iColumn]<vub_[iColumn]) {
+	    mtind[kel]=mtind_[j];
+	    mtval[kel++]=mtval_[j];
+	  } else {
+	    rhs -= vlb_[iColumn]*value;
+	  }
+	}
+	if (kel>kel2) {
+	  mtcnt[k]=kel-kel2;
+	  mtbeg[k]=kel2;
+	  mrhs[k]=rhs;
+	  msense[k++]=msense_[i];
+	}
+      }
+      if (kel) {
+	cutInfo_.sep_012_cut(k,mc_,kel,
+				 mtbeg,mtcnt, mtind, mtval,
+				 vlb_, vub_,
+				 mrhs, msense,
+				 solution,
+				 info.inTree ? false : true,
+				 &cnum,&cnzcnt,
+				 &cbeg,&ccnt,&cind,&cval,&crhs,&csense);
+      }
+      delete [] temp;
+    }
+    if (cnum) {
+      // add cuts
+      double * element = new double[mc_];
+      for (int i=0;i<cnum;i++) {
+	int n = ccnt[i];
+	int start = cbeg[i];
+	for (int j=0;j<n;j++) 
+	  element[j]=cval[start+j];
+	OsiRowCut rc;
+	if (csense[i]=='L') {
+	  rc.setLb(-COIN_DBL_MAX);
+	  rc.setUb(crhs[i]);
+	} else if (csense[i]=='G') {
+	  rc.setLb(crhs[i]);
+	  rc.setUb(COIN_DBL_MAX);
+	} else {
+	  abort();
+	}
+	rc.setRow(n,cind+start,element,false);
+	if ((flags_&1)!=0)
+	  rc.setGloballyValid();
+	//double violation = rc.violated(solution);
+	//if (violation>1.0e-6)
+	  cs.insert(rc);
+	  //else
+	  //printf("violation of %g\n",violation);
+      }
+      delete [] element;
+      free(cbeg); 
+      free(ccnt);
+      free(cind);
+      free(cval);
+      free(crhs);
+      free(csense);
+    }
+  }
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CglZeroHalf::CglZeroHalf ()
+:
+CglCutGenerator(),
+  mr_(0),
+  mc_(0),
+  mnz_(0),
+  mtbeg_(NULL),
+  mtcnt_(NULL),
+  mtind_(NULL),
+  mtval_(NULL),
+  vlb_(NULL),
+  vub_(NULL),
+  mrhs_(NULL),
+  msense_(NULL),
+  flags_(0)
+{
+  // nothing to do here
+}
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CglZeroHalf::CglZeroHalf (
+                  const CglZeroHalf & source)
+:
+  CglCutGenerator(source),
+  mtbeg_(NULL),
+  mtcnt_(NULL),
+  mtind_(NULL),
+  mtval_(NULL),
+  vlb_(NULL),
+  vub_(NULL),
+  mrhs_(NULL),
+  msense_(NULL),
+  flags_(source.flags_)
+{  
+  mr_ = source.mr_;
+  mc_ = source.mc_;
+  mnz_ = source.mnz_;
+  if (mr_) {
+    mtbeg_ = CoinCopyOfArray(source.mtbeg_,mr_);
+    mtcnt_ = CoinCopyOfArray(source.mtcnt_,mr_);
+    mtind_ = CoinCopyOfArray(source.mtind_,mnz_);
+    mtval_ = CoinCopyOfArray(source.mtval_,mnz_);
+    vlb_ = CoinCopyOfArray(source.vlb_,mc_);
+    vub_ = CoinCopyOfArray(source.vub_,mc_);
+    mrhs_ = CoinCopyOfArray(source.mrhs_,mr_);
+    msense_ = CoinCopyOfArray(source.msense_,mr_);
+  }
+}
+
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CglCutGenerator *
+CglZeroHalf::clone() const
+{
+  return new CglZeroHalf(*this);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CglZeroHalf::~CglZeroHalf ()
+{
+  delete []  mtbeg_;
+  delete []  mtcnt_;
+  delete []  mtind_;
+  delete []  mtval_;
+  delete []  vlb_;
+  delete []  vub_;
+  delete []  mrhs_;
+  delete []  msense_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CglZeroHalf &
+CglZeroHalf::operator=(
+                   const CglZeroHalf& rhs)
+{
+  if (this != &rhs) {
+    CglCutGenerator::operator=(rhs);
+    delete []  mtbeg_;
+    delete []  mtcnt_;
+    delete []  mtind_;
+    delete []  mtval_;
+    delete []  vlb_;
+    delete []  vub_;
+    delete []  mrhs_;
+    delete []  msense_;
+    mr_ = rhs.mr_;
+    mc_ = rhs.mc_;
+    mnz_ = rhs.mnz_;
+    flags_ = rhs.flags_;
+    cutInfo_=Cgl012Cut();
+    if (mr_) {
+      mtbeg_ = CoinCopyOfArray(rhs.mtbeg_,mr_);
+      mtcnt_ = CoinCopyOfArray(rhs.mtcnt_,mr_);
+      mtind_ = CoinCopyOfArray(rhs.mtind_,mnz_);
+      mtval_ = CoinCopyOfArray(rhs.mtval_,mnz_);
+      vlb_ = CoinCopyOfArray(rhs.vlb_,mc_);
+      vub_ = CoinCopyOfArray(rhs.vub_,mc_);
+      mrhs_ = CoinCopyOfArray(rhs.mrhs_,mr_);
+      msense_ = CoinCopyOfArray(rhs.msense_,mr_);
+    } else {
+      mtbeg_ = NULL;
+      mtcnt_ = NULL;
+      mtind_ = NULL;
+      mtval_ = NULL;
+      vlb_ = NULL;
+      vub_ = NULL;
+      mrhs_ = NULL;
+      msense_ = NULL;
+    }
+  }
+  return *this;
+}
+void 
+CglZeroHalf::refreshSolver(OsiSolverInterface * solver)
+{
+  if (!solver||!solver->getNumRows())
+    return; // no solver
+  delete []  mtbeg_;
+  delete []  mtcnt_;
+  delete []  mtind_;
+  delete []  mtval_;
+  delete []  vlb_;
+  delete []  vub_;
+  delete []  mrhs_;
+  delete []  msense_;
+  mr_ = 0;
+  mc_ = 0;
+  mnz_ = 0;
+  mtbeg_ = NULL;
+  mtcnt_ = NULL;
+  mtind_ = NULL;
+  mtval_ = NULL;
+  vlb_ = NULL;
+  vub_ = NULL;
+  mrhs_ = NULL;
+  msense_ = NULL;
+  cutInfo_.free_log_var();
+  cutInfo_.free_parity_ilp();
+  cutInfo_.free_ilp();
+  CoinPackedMatrix rowCopy(*solver->getMatrixByRow());
+  const int * column = rowCopy.getIndices();
+  const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+  const int * rowLength = rowCopy.getVectorLengths(); 
+  const double * rowElements = rowCopy.getElements();
+  const double * columnLower = solver->getColLower();
+  const double * columnUpper = solver->getColUpper();
+  const double * rowLower = solver->getRowLower();
+  const double * rowUpper = solver->getRowUpper();
+  int iColumn,iRow;
+  // count number of possible
+  int numberColumns = solver->getNumCols();
+  int numberRows = solver->getNumRows();
+  vlb_ = new int [numberColumns];
+  vub_ = new int [numberColumns];
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    int ilo,iup;
+    if (solver->isInteger(iColumn)) {
+      double lo = columnLower[iColumn];
+      if (lo<-COIN_INT_MAX)
+	lo=-COIN_INT_MAX;
+      ilo= static_cast<int> (ceil(lo));
+      double up = columnUpper[iColumn];
+      if (up>COIN_INT_MAX)
+	up=COIN_INT_MAX;
+      iup= static_cast<int> (floor(up));
+    } else {
+      ilo=COIN_INT_MAX;
+      iup=-COIN_INT_MAX;
+    }
+    vlb_[iColumn]=ilo;
+    vub_[iColumn]=iup;
+  }
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int n = rowLength[iRow];
+    bool good=(n>0);
+    for (CoinBigIndex j=rowStart[iRow];
+	 j<rowStart[iRow]+n;j++) {
+      int jColumn = column[j];
+      if (vlb_[jColumn]==COIN_INT_MAX) {
+	// continuous
+	good=false;
+	break;
+      } else {
+	double value = rowElements[j];
+	if (fabs(value-floor(value+0.5))>1.0e-30) {
+	  // not integer coefficient
+	  good=false;
+	  break;
+	}
+      }
+    }
+    double lo = rowLower[iRow];
+    double up = rowUpper[iRow];
+    int iType=1;
+    double rhs=1.0e20;
+    if (lo>-1.0e20) {
+      if (fabs(lo-floor(lo+0.5))>1.0e-12) {
+	// not integer coefficient
+	good=false;
+      }
+      rhs=fabs(lo);
+      if (up<1.0e20) {
+	rhs=CoinMax(fabs(lo),fabs(up));
+	if (lo!=up)
+	  iType=2; // ranged so make copy
+	if (fabs(up-floor(up+0.5))>1.0e-12) {
+	  // not integer coefficient
+	  good=false;
+	}
+      }
+    } else if (up<1.0e20) {
+      rhs=fabs(up);
+      if (up<1.0e20) {
+	if (fabs(up-floor(up+0.5))>1.0e-12) {
+	  // not integer coefficient
+	  good=false;
+	}
+      }
+    }
+    if (good&&rhs<COIN_INT_MAX) {
+      mr_+=iType;
+      mnz_ += iType*n;
+    }
+  }
+  if (mnz_) {
+    mc_ = numberColumns;
+    mtbeg_ = new int [mr_];
+    mtcnt_ = new int [mr_];
+    mtind_ = new int [mnz_];
+    mtval_ = new int [mnz_];
+    mrhs_ = new int [mr_];
+    msense_ = new char [mr_];
+    mr_=0;
+    mnz_=0;
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int n = rowLength[iRow];
+      bool good=(n>0);
+      for (CoinBigIndex j=rowStart[iRow];
+	   j<rowStart[iRow]+n;j++) {
+	int jColumn = column[j];
+	if (vlb_[jColumn]==COIN_INT_MAX) {
+	  // continuous
+	  good=false;
+	  break;
+	} else {
+	  double value = rowElements[j];
+	  if (fabs(value-floor(value+0.5))>1.0e-12) {
+	    // not integer coefficient
+	    good=false;
+	    break;
+	  }
+	}
+      }
+      double lo = rowLower[iRow];
+      double up = rowUpper[iRow];
+      int iType=1;
+      double rhs=1.0e20;
+      if (lo>-1.0e20) {
+	if (fabs(lo-floor(lo+0.5))>1.0e-30) {
+	  // not integer coefficient
+	  good=false;
+	}
+	rhs=fabs(lo);
+	if (up<1.0e20) {
+	  rhs=CoinMax(fabs(lo),fabs(up));
+	  if (lo!=up)
+	    iType=2; // ranged so make copy
+	  if (fabs(up-floor(up+0.5))>1.0e-12) {
+	    // not integer coefficient
+	    good=false;
+	  }
+	}
+      } else if (up<1.0e20) {
+	rhs=fabs(up);
+	if (up<1.0e20) {
+	  if (fabs(up-floor(up+0.5))>1.0e-12) {
+	    // not integer coefficient
+	    good=false;
+	  }
+	}
+      }
+      if (good&&rhs<COIN_INT_MAX) {
+	mtbeg_[mr_]=mnz_;
+	for (CoinBigIndex j=rowStart[iRow];
+	     j<rowStart[iRow]+n;j++) {
+	  int jColumn = column[j];
+	  double value = rowElements[j];
+	  assert (fabs(value)<COIN_INT_MAX);
+	  int iValue = static_cast<int> (floor(value+0.5));
+	  if (iValue) {
+	    mtind_[mnz_]=jColumn;
+	    mtval_[mnz_++]=iValue;
+	  }
+	}
+	mtcnt_[mr_]=mnz_-mtbeg_[mr_];
+	if (iType==1) {
+	  if (lo>-1.0e20) {
+	    mrhs_[mr_]=static_cast<int> (floor(lo+0.5));
+	    msense_[mr_]='G';
+	  } else {
+	    mrhs_[mr_]=static_cast<int> (floor(up+0.5));
+	    msense_[mr_]='L';
+	  }
+	  mr_++;
+	} else {
+	  // ranged!
+	  mrhs_[mr_]=static_cast<int> (floor(lo+0.5));
+	  msense_[mr_]='G';
+	  int k = mnz_-mtbeg_[mr_]; 
+	  mr_++;
+	  mtbeg_[mr_]=mnz_;
+	  memcpy(mtind_+mnz_,mtind_+mnz_-k,k*sizeof(int));
+	  memcpy(mtval_+mnz_,mtval_+mnz_-k,k*sizeof(int));
+	  mnz_+= mtcnt_[mr_-1];
+	  mtcnt_[mr_]=mnz_-mtbeg_[mr_];
+	  mrhs_[mr_]=static_cast<int> (floor(up+0.5));
+	  msense_[mr_]='L';
+	  mr_++;
+	}
+      }
+    }
+    cutInfo_.ilp_load(mr_,mc_,mnz_,mtbeg_,mtcnt_,mtind_,mtval_,
+	     vlb_,vub_,mrhs_,msense_);
+    cutInfo_.alloc_parity_ilp(mr_,mc_,mnz_);
+    cutInfo_.initialize_log_var();
+  } else {
+    // no good
+    delete [] vlb_;
+    delete [] vub_;
+    vlb_ = NULL;
+    vub_ = NULL;
+    mr_=0;
+    mnz_=0;
+  }
+}
+// Create C++ lines to get to current state
+std::string
+CglZeroHalf::generateCpp( FILE * fp) 
+{
+  CglZeroHalf other;
+  fprintf(fp,"0#include \"CglZeroHalf.hpp\"\n");
+  fprintf(fp,"3  CglZeroHalf zeroHalf;\n");
+  if (getAggressiveness()!=other.getAggressiveness())
+    fprintf(fp,"3  zeroHalf.setAggressiveness(%d);\n",getAggressiveness());
+  else
+    fprintf(fp,"4  zeroHalf.setAggressiveness(%d);\n",getAggressiveness());
+  return "zeroHalf";
+}
+#include <vector>
+#include <algorithm>
+//bool operator() (cgl_node * x, cgl_node * y) {
+bool best(cgl_node * x, cgl_node * y) {
+  return (x->distanceBack>y->distanceBack);
+}
+#ifndef CGL_NEW_SHORT
+void cglShortestPath(cgl_graph * graph, int source, int maximumLength)
+#else
+void cglShortestPath(auxiliary_graph * graph, int source, int maximumLength)
+#endif
+{
+  int numberNodes=graph->nnodes;
+#define HEAP
+#ifndef HEAP
+  int * candidate = new int [numberNodes];
+#endif
+  cgl_node * nodes = graph->nodes;
+  int i;
+  for ( i=0;i<numberNodes;i++) {
+    nodes[i].parentNode=-1;
+    nodes[i].distanceBack=COIN_INT_MAX;
+#ifndef HEAP
+    candidate[i]=i;
+#endif
+  }
+  nodes[source].distanceBack=0;
+#ifdef HEAP
+  std::vector <cgl_node *> nodes_;
+  for ( i=0;i<numberNodes;i++) 
+    nodes_.push_back(nodes+i);
+  // create heap
+  std::make_heap(nodes_.begin(), nodes_.end(), best);
+#endif
+  int numberCandidates = numberNodes;
+  while (numberCandidates>0) {
+#ifdef HEAP
+  cgl_node * bestNode = nodes_.front();
+  int iNode = bestNode->index;
+  std::pop_heap(nodes_.begin(), nodes_.end(), best);
+  nodes_.pop_back();
+  if (nodes[iNode].distanceBack==COIN_INT_MAX)
+    break;
+  numberCandidates--;
+#else
+    int best=-1;
+    int bestDistance=COIN_INT_MAX;
+    for (i=0;i<numberCandidates;i++) {
+      int iNode = candidate[i];
+      if (nodes[iNode].distanceBack<bestDistance) {
+	best=i;
+	bestDistance=nodes[iNode].distanceBack;
+      }
+    }
+    if (best<0)
+      break; // disconnected graph?
+    int iNode = candidate[best];
+    numberCandidates--;
+    candidate[best]=candidate[numberCandidates];
+#endif
+    cgl_arc * nextNode = nodes[iNode+1].firstArc;
+    int thisDistance = nodes[iNode].distanceBack;
+    for (cgl_arc * arc=nodes[iNode].firstArc;arc!=nextNode;arc++) {
+      int toNode = arc->to;
+      int dist = arc->length;
+      if (thisDistance+dist<nodes[toNode].distanceBack) {
+	nodes[toNode].distanceBack=thisDistance+dist;
+	nodes[toNode].parentNode=iNode;
+#ifdef HEAP
+	nodes_.push_back(nodes+toNode);
+	//printf("size %d\n",nodes_.size());
+#endif
+      }
+    }
+  }
+}
diff --git a/cbits/coin/CglZeroHalf.hpp b/cbits/coin/CglZeroHalf.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CglZeroHalf.hpp
@@ -0,0 +1,133 @@
+// $Id: CglZeroHalf.hpp 1123 2013-04-06 20:47:24Z stefan $
+// Copyright (C) 2010, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+#ifndef CglZeroHalf_H
+#define CglZeroHalf_H
+
+#include <string>
+
+#include "CglCutGenerator.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "Cgl012cut.hpp" 
+
+/** Zero Half Cut Generator Class
+
+ This class generates zero half cuts via the following method:
+
+ See - 
+
+G. Andreello, A. Caprara, M. Fischetti,
+ “Embedding Cuts in a Branch and Cut Framework: a Computational Study 
+  with {0,1/2}-Cuts”, INFORMS Journal on Computing 19(2), 229-238, 2007.
+ 
+*/
+
+class CglZeroHalf : public CglCutGenerator {
+   friend void CglZeroHalfUnitTest(const OsiSolverInterface * siP,
+					 const std::string mpdDir );
+ 
+public:
+
+  /**@name Generate Cuts */
+  //@{
+  /** Generate zero half cuts for the model accessed through the solver interface. 
+  Insert generated cuts into the cut set cs.
+  */
+  virtual void generateCuts( const OsiSolverInterface & si, OsiCuts & cs,
+			     const CglTreeInfo info = CglTreeInfo());
+  //@}
+
+  /**@name Sets and Gets */
+  //@{
+  /// Get flags
+  inline int getFlags() const
+  { return flags_;}
+  /// Set flags
+  inline void setFlags(int value)
+  { flags_ = value;}
+  //@}
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default constructor 
+  CglZeroHalf ();
+ 
+  /// Copy constructor 
+  CglZeroHalf (
+    const CglZeroHalf &);
+
+  /// Clone
+  virtual CglCutGenerator * clone() const;
+
+  /// Assignment operator 
+  CglZeroHalf &
+    operator=(
+    const CglZeroHalf& rhs);
+  
+  /// Destructor 
+  virtual
+    ~CglZeroHalf ();
+  /// Create C++ lines to get to current state
+  virtual std::string generateCpp( FILE * fp);
+  /// This can be used to refresh any information
+  virtual void refreshSolver(OsiSolverInterface * solver);
+  //@}
+
+private:
+  
+  // Private member methods
+   
+  /**@name Private methods */
+  //@{
+  //@}
+  
+  
+  /**@name Private member data */
+  //@{
+  /// number of rows in the ILP matrix 
+  int mr_;
+  /// number of columns in the ILP matrix 
+  int mc_;
+  /// number of nonzero's in the ILP matrix 
+  int mnz_;
+  /// starting position of each row in arrays mtind and mtval 
+  int *mtbeg_;
+  /// number of entries of each row in arrays mtind and mtval 
+  int *mtcnt_;
+  /// column indices of the nonzero entries of the ILP matrix 
+  int *mtind_;
+  /// values of the nonzero entries of the ILP matrix 
+  int *mtval_;
+  /// lower bounds on the variables 
+  int *vlb_;
+  /// upper bounds on the variables 
+  int *vub_;
+  /// right hand sides of the constraints 
+  int *mrhs_;
+  /// senses of the constraints: 'L', 'G' or 'E' 
+  char *msense_;
+  /// Cgl012Cut object to make thread safe
+  Cgl012Cut cutInfo_;
+  /** Flags
+      1 bit - global cuts 
+  */
+  int flags_;
+  //@}
+};
+/// A simple Dijkstra shortest path - make better later
+#ifndef CGL_NEW_SHORT
+void cglShortestPath(cgl_graph * graph, int source, int maximumLength);
+#else
+void cglShortestPath(auxiliary_graph * graph, int source, int maximumLength);
+#endif
+//#############################################################################
+/** A function that tests the methods in the CglZeroHalf class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void CglZeroHalfUnitTest(const OsiSolverInterface * siP,
+			       const std::string mpdDir );
+  
+#endif
diff --git a/cbits/coin/ClpCholeskyBase.cpp b/cbits/coin/ClpCholeskyBase.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpCholeskyBase.cpp
@@ -0,0 +1,3905 @@
+/* $Id: ClpCholeskyBase.cpp 1878 2012-08-30 15:43:19Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*----------------------------------------------------------------------------*/
+/*      Ordering code - courtesy of Anshul Gupta                              */
+/*	(C) Copyright IBM Corporation 1997, 2009.  All Rights Reserved.       */
+/*----------------------------------------------------------------------------*/
+
+/*  A compact no-frills Approximate Minimum Local Fill ordering code.
+
+    References:
+
+[1] Ordering Sparse Matrices Using Approximate Minimum Local Fill.
+    Edward Rothberg, SGI Manuscript, April 1996.
+[2] An Approximate Minimum Degree Ordering Algorithm.
+    T. Davis, P. Amestoy, and I. Duff, TR-94-039, CIS Department,
+    University of Florida, December 1994.
+*/
+/*----------------------------------------------------------------------------*/
+
+
+#include "CoinPragma.hpp"
+
+#include <iostream>
+
+#include "ClpCholeskyBase.hpp"
+#include "ClpInterior.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinSort.hpp"
+#include "ClpCholeskyDense.hpp"
+#include "ClpMessage.hpp"
+#include "ClpQuadraticObjective.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpCholeskyBase::ClpCholeskyBase (int denseThreshold) :
+     type_(0),
+     doKKT_(false),
+     goDense_(0.7),
+     choleskyCondition_(0.0),
+     model_(NULL),
+     numberTrials_(),
+     numberRows_(0),
+     status_(0),
+     rowsDropped_(NULL),
+     permuteInverse_(NULL),
+     permute_(NULL),
+     numberRowsDropped_(0),
+     sparseFactor_(NULL),
+     choleskyStart_(NULL),
+     choleskyRow_(NULL),
+     indexStart_(NULL),
+     diagonal_(NULL),
+     workDouble_(NULL),
+     link_(NULL),
+     workInteger_(NULL),
+     clique_(NULL),
+     sizeFactor_(0),
+     sizeIndex_(0),
+     firstDense_(0),
+     rowCopy_(NULL),
+     whichDense_(NULL),
+     denseColumn_(NULL),
+     dense_(NULL),
+     denseThreshold_(denseThreshold)
+{
+     memset(integerParameters_, 0, 64 * sizeof(int));
+     memset(doubleParameters_, 0, 64 * sizeof(double));
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpCholeskyBase::ClpCholeskyBase (const ClpCholeskyBase & rhs) :
+     type_(rhs.type_),
+     doKKT_(rhs.doKKT_),
+     goDense_(rhs.goDense_),
+     choleskyCondition_(rhs.choleskyCondition_),
+     model_(rhs.model_),
+     numberTrials_(rhs.numberTrials_),
+     numberRows_(rhs.numberRows_),
+     status_(rhs.status_),
+     numberRowsDropped_(rhs.numberRowsDropped_)
+{
+     rowsDropped_ = ClpCopyOfArray(rhs.rowsDropped_, numberRows_);
+     permuteInverse_ = ClpCopyOfArray(rhs.permuteInverse_, numberRows_);
+     permute_ = ClpCopyOfArray(rhs.permute_, numberRows_);
+     sizeFactor_ = rhs.sizeFactor_;
+     sizeIndex_ = rhs.sizeIndex_;
+     firstDense_ = rhs.firstDense_;
+     sparseFactor_ = ClpCopyOfArray(rhs.sparseFactor_, rhs.sizeFactor_);
+     choleskyStart_ = ClpCopyOfArray(rhs.choleskyStart_, numberRows_ + 1);
+     indexStart_ = ClpCopyOfArray(rhs.indexStart_, numberRows_);
+     choleskyRow_ = ClpCopyOfArray(rhs.choleskyRow_, sizeIndex_);
+     diagonal_ = ClpCopyOfArray(rhs.diagonal_, numberRows_);
+#if CLP_LONG_CHOLESKY!=1
+     workDouble_ = ClpCopyOfArray(rhs.workDouble_, numberRows_);
+#else
+     // actually long double
+     workDouble_ = reinterpret_cast<double *> (ClpCopyOfArray(reinterpret_cast<CoinWorkDouble *> (rhs.workDouble_), numberRows_));
+#endif
+     link_ = ClpCopyOfArray(rhs.link_, numberRows_);
+     workInteger_ = ClpCopyOfArray(rhs.workInteger_, numberRows_);
+     clique_ = ClpCopyOfArray(rhs.clique_, numberRows_);
+     CoinMemcpyN(rhs.integerParameters_, 64, integerParameters_);
+     CoinMemcpyN(rhs.doubleParameters_, 64, doubleParameters_);
+     rowCopy_ = rhs.rowCopy_->clone();
+     whichDense_ = NULL;
+     denseColumn_ = NULL;
+     dense_ = NULL;
+     denseThreshold_ = rhs.denseThreshold_;
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpCholeskyBase::~ClpCholeskyBase ()
+{
+     delete [] rowsDropped_;
+     delete [] permuteInverse_;
+     delete [] permute_;
+     delete [] sparseFactor_;
+     delete [] choleskyStart_;
+     delete [] choleskyRow_;
+     delete [] indexStart_;
+     delete [] diagonal_;
+     delete [] workDouble_;
+     delete [] link_;
+     delete [] workInteger_;
+     delete [] clique_;
+     delete rowCopy_;
+     delete [] whichDense_;
+     delete [] denseColumn_;
+     delete dense_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpCholeskyBase &
+ClpCholeskyBase::operator=(const ClpCholeskyBase& rhs)
+{
+     if (this != &rhs) {
+          type_ = rhs.type_;
+          doKKT_ = rhs.doKKT_;
+          goDense_ = rhs.goDense_;
+          choleskyCondition_ = rhs.choleskyCondition_;
+          model_ = rhs.model_;
+          numberTrials_ = rhs.numberTrials_;
+          numberRows_ = rhs.numberRows_;
+          status_ = rhs.status_;
+          numberRowsDropped_ = rhs.numberRowsDropped_;
+          delete [] rowsDropped_;
+          delete [] permuteInverse_;
+          delete [] permute_;
+          delete [] sparseFactor_;
+          delete [] choleskyStart_;
+          delete [] choleskyRow_;
+          delete [] indexStart_;
+          delete [] diagonal_;
+          delete [] workDouble_;
+          delete [] link_;
+          delete [] workInteger_;
+          delete [] clique_;
+          delete rowCopy_;
+          delete [] whichDense_;
+          delete [] denseColumn_;
+          delete dense_;
+          rowsDropped_ = ClpCopyOfArray(rhs.rowsDropped_, numberRows_);
+          permuteInverse_ = ClpCopyOfArray(rhs.permuteInverse_, numberRows_);
+          permute_ = ClpCopyOfArray(rhs.permute_, numberRows_);
+          sizeFactor_ = rhs.sizeFactor_;
+          sizeIndex_ = rhs.sizeIndex_;
+          firstDense_ = rhs.firstDense_;
+          sparseFactor_ = ClpCopyOfArray(rhs.sparseFactor_, rhs.sizeFactor_);
+          choleskyStart_ = ClpCopyOfArray(rhs.choleskyStart_, numberRows_ + 1);
+          choleskyRow_ = ClpCopyOfArray(rhs.choleskyRow_, rhs.sizeFactor_);
+          indexStart_ = ClpCopyOfArray(rhs.indexStart_, numberRows_);
+          choleskyRow_ = ClpCopyOfArray(rhs.choleskyRow_, sizeIndex_);
+          diagonal_ = ClpCopyOfArray(rhs.diagonal_, numberRows_);
+#if CLP_LONG_CHOLESKY!=1
+          workDouble_ = ClpCopyOfArray(rhs.workDouble_, numberRows_);
+#else
+          // actually long double
+          workDouble_ = reinterpret_cast<double *> (ClpCopyOfArray(reinterpret_cast<CoinWorkDouble *> (rhs.workDouble_), numberRows_));
+#endif
+          link_ = ClpCopyOfArray(rhs.link_, numberRows_);
+          workInteger_ = ClpCopyOfArray(rhs.workInteger_, numberRows_);
+          clique_ = ClpCopyOfArray(rhs.clique_, numberRows_);
+          delete rowCopy_;
+          rowCopy_ = rhs.rowCopy_->clone();
+          whichDense_ = NULL;
+          denseColumn_ = NULL;
+          dense_ = NULL;
+          denseThreshold_ = rhs.denseThreshold_;
+     }
+     return *this;
+}
+// reset numberRowsDropped and rowsDropped.
+void
+ClpCholeskyBase::resetRowsDropped()
+{
+     numberRowsDropped_ = 0;
+     memset(rowsDropped_, 0, numberRows_);
+}
+/* Uses factorization to solve. - given as if KKT.
+   region1 is rows+columns, region2 is rows */
+void
+ClpCholeskyBase::solveKKT (CoinWorkDouble * region1, CoinWorkDouble * region2, const CoinWorkDouble * diagonal,
+                           CoinWorkDouble diagonalScaleFactor)
+{
+     if (!doKKT_) {
+          int iColumn;
+          int numberColumns = model_->numberColumns();
+          int numberTotal = numberRows_ + numberColumns;
+          CoinWorkDouble * region1Save = new CoinWorkDouble[numberTotal];
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               region1[iColumn] *= diagonal[iColumn];
+               region1Save[iColumn] = region1[iColumn];
+          }
+          multiplyAdd(region1 + numberColumns, numberRows_, -1.0, region2, 1.0);
+          model_->clpMatrix()->times(1.0, region1, region2);
+          CoinWorkDouble maximumRHS = maximumAbsElement(region2, numberRows_);
+          CoinWorkDouble scale = 1.0;
+          CoinWorkDouble unscale = 1.0;
+          if (maximumRHS > 1.0e-30) {
+               if (maximumRHS <= 0.5) {
+                    CoinWorkDouble factor = 2.0;
+                    while (maximumRHS <= 0.5) {
+                         maximumRHS *= factor;
+                         scale *= factor;
+                    } /* endwhile */
+               } else if (maximumRHS >= 2.0 && maximumRHS <= COIN_DBL_MAX) {
+                    CoinWorkDouble factor = 0.5;
+                    while (maximumRHS >= 2.0) {
+                         maximumRHS *= factor;
+                         scale *= factor;
+                    } /* endwhile */
+               }
+               unscale = diagonalScaleFactor / scale;
+          } else {
+               //effectively zero
+               scale = 0.0;
+               unscale = 0.0;
+          }
+          multiplyAdd(NULL, numberRows_, 0.0, region2, scale);
+          solve(region2);
+          multiplyAdd(NULL, numberRows_, 0.0, region2, unscale);
+          multiplyAdd(region2, numberRows_, -1.0, region1 + numberColumns, 0.0);
+          CoinZeroN(region1, numberColumns);
+          model_->clpMatrix()->transposeTimes(1.0, region2, region1);
+          for (iColumn = 0; iColumn < numberTotal; iColumn++)
+               region1[iColumn] = region1[iColumn] * diagonal[iColumn] - region1Save[iColumn];
+          delete [] region1Save;
+     } else {
+          // KKT
+          int numberRowsModel = model_->numberRows();
+          int numberColumns = model_->numberColumns();
+          int numberTotal = numberColumns + numberRowsModel;
+          CoinWorkDouble * array = new CoinWorkDouble [numberRows_];
+          CoinMemcpyN(region1, numberTotal, array);
+          CoinMemcpyN(region2, numberRowsModel, array + numberTotal);
+          assert (numberRows_ >= numberRowsModel + numberTotal);
+          solve(array);
+          int iRow;
+          for (iRow = 0; iRow < numberTotal; iRow++) {
+               if (rowsDropped_[iRow] && CoinAbs(array[iRow]) > 1.0e-8) {
+		 COIN_DETAIL_PRINT(printf("row region1 %d dropped %g\n", iRow, array[iRow]));
+               }
+          }
+          for (; iRow < numberRows_; iRow++) {
+               if (rowsDropped_[iRow] && CoinAbs(array[iRow]) > 1.0e-8) {
+		 COIN_DETAIL_PRINT(printf("row region2 %d dropped %g\n", iRow, array[iRow]));
+               }
+          }
+          CoinMemcpyN(array + numberTotal, numberRowsModel, region2);
+          CoinMemcpyN(array, numberTotal, region1);
+          delete [] array;
+     }
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpCholeskyBase * ClpCholeskyBase::clone() const
+{
+     return new ClpCholeskyBase(*this);
+}
+// Forms ADAT - returns nonzero if not enough memory
+int
+ClpCholeskyBase::preOrder(bool lowerTriangular, bool includeDiagonal, bool doKKT)
+{
+     delete rowCopy_;
+     rowCopy_ = model_->clpMatrix()->reverseOrderedCopy();
+     if (!doKKT) {
+          numberRows_ = model_->numberRows();
+          rowsDropped_ = new char [numberRows_];
+          memset(rowsDropped_, 0, numberRows_);
+          numberRowsDropped_ = 0;
+          // Space for starts
+          choleskyStart_ = new CoinBigIndex[numberRows_+1];
+          const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts();
+          const int * columnLength = model_->clpMatrix()->getVectorLengths();
+          const int * row = model_->clpMatrix()->getIndices();
+          const CoinBigIndex * rowStart = rowCopy_->getVectorStarts();
+          const int * rowLength = rowCopy_->getVectorLengths();
+          const int * column = rowCopy_->getIndices();
+          // We need two arrays for counts
+          int * which = new int [numberRows_];
+          int * used = new int[numberRows_+1];
+          CoinZeroN(used, numberRows_);
+          int iRow;
+          sizeFactor_ = 0;
+          int numberColumns = model_->numberColumns();
+          int numberDense = 0;
+          //denseThreshold_=3;
+          if (denseThreshold_ > 0) {
+               delete [] whichDense_;
+               delete [] denseColumn_;
+               delete dense_;
+               whichDense_ = new char[numberColumns];
+               int iColumn;
+               used[numberRows_] = 0;
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    int length = columnLength[iColumn];
+                    used[length] += 1;
+               }
+               int nLong = 0;
+               int stop = CoinMax(denseThreshold_ / 2, 100);
+               for (iRow = numberRows_; iRow >= stop; iRow--) {
+                    if (used[iRow])
+		      COIN_DETAIL_PRINT(printf("%d columns are of length %d\n", used[iRow], iRow));
+                    nLong += used[iRow];
+                    if (nLong > 50 || nLong > (numberColumns >> 2))
+                         break;
+               }
+               CoinZeroN(used, numberRows_);
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (columnLength[iColumn] < denseThreshold_) {
+                         whichDense_[iColumn] = 0;
+                    } else {
+                         whichDense_[iColumn] = 1;
+                         numberDense++;
+                    }
+               }
+               if (!numberDense || numberDense > 100) {
+                    // free
+                    delete [] whichDense_;
+                    whichDense_ = NULL;
+                    denseColumn_ = NULL;
+                    dense_ = NULL;
+               } else {
+                    // space for dense columns
+                    denseColumn_ = new longDouble [numberDense*numberRows_];
+                    // dense cholesky
+                    dense_ = new ClpCholeskyDense();
+                    dense_->reserveSpace(NULL, numberDense);
+                    COIN_DETAIL_PRINT(printf("Taking %d columns as dense\n", numberDense));
+               }
+          }
+          int offset = includeDiagonal ? 0 : 1;
+          if (lowerTriangular)
+               offset = -offset;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int number = 0;
+               // make sure diagonal exists if includeDiagonal
+               if (!offset) {
+                    which[0] = iRow;
+                    used[iRow] = 1;
+                    number = 1;
+               }
+               CoinBigIndex startRow = rowStart[iRow];
+               CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow];
+               if (lowerTriangular) {
+                    for (CoinBigIndex k = startRow; k < endRow; k++) {
+                         int iColumn = column[k];
+                         if (!whichDense_ || !whichDense_[iColumn]) {
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = row[j];
+                                   if (jRow <= iRow + offset) {
+                                        if (!used[jRow]) {
+                                             used[jRow] = 1;
+                                             which[number++] = jRow;
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               } else {
+                    for (CoinBigIndex k = startRow; k < endRow; k++) {
+                         int iColumn = column[k];
+                         if (!whichDense_ || !whichDense_[iColumn]) {
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = row[j];
+                                   if (jRow >= iRow + offset) {
+                                        if (!used[jRow]) {
+                                             used[jRow] = 1;
+                                             which[number++] = jRow;
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+               sizeFactor_ += number;
+               int j;
+               for (j = 0; j < number; j++)
+                    used[which[j]] = 0;
+          }
+          delete [] which;
+          // Now we have size - create arrays and fill in
+          try {
+               choleskyRow_ = new int [sizeFactor_];
+          } catch (...) {
+               // no memory
+               delete [] choleskyStart_;
+               choleskyStart_ = NULL;
+               return -1;
+          }
+          sizeFactor_ = 0;
+          which = choleskyRow_;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int number = 0;
+               // make sure diagonal exists if includeDiagonal
+               if (!offset) {
+                    which[0] = iRow;
+                    used[iRow] = 1;
+                    number = 1;
+               }
+               choleskyStart_[iRow] = sizeFactor_;
+               CoinBigIndex startRow = rowStart[iRow];
+               CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow];
+               if (lowerTriangular) {
+                    for (CoinBigIndex k = startRow; k < endRow; k++) {
+                         int iColumn = column[k];
+                         if (!whichDense_ || !whichDense_[iColumn]) {
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = row[j];
+                                   if (jRow <= iRow + offset) {
+                                        if (!used[jRow]) {
+                                             used[jRow] = 1;
+                                             which[number++] = jRow;
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               } else {
+                    for (CoinBigIndex k = startRow; k < endRow; k++) {
+                         int iColumn = column[k];
+                         if (!whichDense_ || !whichDense_[iColumn]) {
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = row[j];
+                                   if (jRow >= iRow + offset) {
+                                        if (!used[jRow]) {
+                                             used[jRow] = 1;
+                                             which[number++] = jRow;
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+               sizeFactor_ += number;
+               int j;
+               for (j = 0; j < number; j++)
+                    used[which[j]] = 0;
+               // Sort
+               std::sort(which, which + number);
+               // move which on
+               which += number;
+          }
+          choleskyStart_[numberRows_] = sizeFactor_;
+          delete [] used;
+          return 0;
+     } else {
+          int numberRowsModel = model_->numberRows();
+          int numberColumns = model_->numberColumns();
+          int numberTotal = numberColumns + numberRowsModel;
+          numberRows_ = 2 * numberRowsModel + numberColumns;
+          rowsDropped_ = new char [numberRows_];
+          memset(rowsDropped_, 0, numberRows_);
+          numberRowsDropped_ = 0;
+          CoinPackedMatrix * quadratic = NULL;
+          ClpQuadraticObjective * quadraticObj =
+               (dynamic_cast< ClpQuadraticObjective*>(model_->objectiveAsObject()));
+          if (quadraticObj)
+               quadratic = quadraticObj->quadraticObjective();
+          int numberElements = model_->clpMatrix()->getNumElements();
+          numberElements = numberElements + 2 * numberRowsModel + numberTotal;
+          if (quadratic)
+               numberElements += quadratic->getNumElements();
+          // Space for starts
+          choleskyStart_ = new CoinBigIndex[numberRows_+1];
+          const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts();
+          const int * columnLength = model_->clpMatrix()->getVectorLengths();
+          const int * row = model_->clpMatrix()->getIndices();
+          //const double * element = model_->clpMatrix()->getElements();
+          // Now we have size - create arrays and fill in
+          try {
+               choleskyRow_ = new int [numberElements];
+          } catch (...) {
+               // no memory
+               delete [] choleskyStart_;
+               choleskyStart_ = NULL;
+               return -1;
+          }
+          int iRow, iColumn;
+
+          sizeFactor_ = 0;
+          // matrix
+          if (lowerTriangular) {
+               if (!quadratic) {
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         choleskyStart_[iColumn] = sizeFactor_;
+                         choleskyRow_[sizeFactor_++] = iColumn;
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                         if (!includeDiagonal)
+                              start++;
+                         for (CoinBigIndex j = start; j < end; j++) {
+                              choleskyRow_[sizeFactor_++] = row[j] + numberTotal;
+                         }
+                    }
+               } else {
+                    // Quadratic
+                    const int * columnQuadratic = quadratic->getIndices();
+                    const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+                    const int * columnQuadraticLength = quadratic->getVectorLengths();
+                    //const double * quadraticElement = quadratic->getElements();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         choleskyStart_[iColumn] = sizeFactor_;
+                         if (includeDiagonal)
+                              choleskyRow_[sizeFactor_++] = iColumn;
+                         CoinBigIndex j;
+                         for ( j = columnQuadraticStart[iColumn];
+                                   j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                              int jColumn = columnQuadratic[j];
+                              if (jColumn > iColumn)
+                                   choleskyRow_[sizeFactor_++] = jColumn;
+                         }
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                         for ( j = start; j < end; j++) {
+                              choleskyRow_[sizeFactor_++] = row[j] + numberTotal;
+                         }
+                    }
+               }
+               // slacks
+               for (; iColumn < numberTotal; iColumn++) {
+                    choleskyStart_[iColumn] = sizeFactor_;
+                    if (includeDiagonal)
+                         choleskyRow_[sizeFactor_++] = iColumn;
+                    choleskyRow_[sizeFactor_++] = iColumn - numberColumns + numberTotal;
+               }
+               // Transpose - nonzero diagonal (may regularize)
+               for (iRow = 0; iRow < numberRowsModel; iRow++) {
+                    choleskyStart_[iRow+numberTotal] = sizeFactor_;
+                    // diagonal
+                    if (includeDiagonal)
+                         choleskyRow_[sizeFactor_++] = iRow + numberTotal;
+               }
+               choleskyStart_[numberRows_] = sizeFactor_;
+          } else {
+               // transpose
+               ClpMatrixBase * rowCopy = model_->clpMatrix()->reverseOrderedCopy();
+               const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+               const int * rowLength = rowCopy->getVectorLengths();
+               const int * column = rowCopy->getIndices();
+               if (!quadratic) {
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         choleskyStart_[iColumn] = sizeFactor_;
+                         if (includeDiagonal)
+                              choleskyRow_[sizeFactor_++] = iColumn;
+                    }
+               } else {
+                    // Quadratic
+                    // transpose
+                    CoinPackedMatrix quadraticT;
+                    quadraticT.reverseOrderedCopyOf(*quadratic);
+                    const int * columnQuadratic = quadraticT.getIndices();
+                    const CoinBigIndex * columnQuadraticStart = quadraticT.getVectorStarts();
+                    const int * columnQuadraticLength = quadraticT.getVectorLengths();
+                    //const double * quadraticElement = quadraticT.getElements();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         choleskyStart_[iColumn] = sizeFactor_;
+                         for (CoinBigIndex j = columnQuadraticStart[iColumn];
+                                   j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                              int jColumn = columnQuadratic[j];
+                              if (jColumn < iColumn)
+                                   choleskyRow_[sizeFactor_++] = jColumn;
+                         }
+                         if (includeDiagonal)
+                              choleskyRow_[sizeFactor_++] = iColumn;
+                    }
+               }
+               int iRow;
+               // slacks
+               for (iRow = 0; iRow < numberRowsModel; iRow++) {
+                    choleskyStart_[iRow+numberColumns] = sizeFactor_;
+                    if (includeDiagonal)
+                         choleskyRow_[sizeFactor_++] = iRow + numberColumns;
+               }
+               for (iRow = 0; iRow < numberRowsModel; iRow++) {
+                    choleskyStart_[iRow+numberTotal] = sizeFactor_;
+                    CoinBigIndex start = rowStart[iRow];
+                    CoinBigIndex end = rowStart[iRow] + rowLength[iRow];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         choleskyRow_[sizeFactor_++] = column[j];
+                    }
+                    // slack
+                    choleskyRow_[sizeFactor_++] = numberColumns + iRow;
+                    if (includeDiagonal)
+                         choleskyRow_[sizeFactor_++] = iRow + numberTotal;
+               }
+               choleskyStart_[numberRows_] = sizeFactor_;
+          }
+     }
+     return 0;
+}
+/* Orders rows and saves pointer to matrix.and model */
+int
+ClpCholeskyBase::order(ClpInterior * model)
+{
+     model_ = model;
+#define BASE_ORDER 2
+#if BASE_ORDER>0
+     if (!doKKT_ && model_->numberRows() > 6) {
+          if (preOrder(false, true, false))
+               return -1;
+          //rowsDropped_ = new char [numberRows_];
+          numberRowsDropped_ = 0;
+          memset(rowsDropped_, 0, numberRows_);
+          //rowCopy_ = model->clpMatrix()->reverseOrderedCopy();
+          // approximate minimum degree
+          return orderAMD();
+     }
+#endif
+     int numberRowsModel = model_->numberRows();
+     int numberColumns = model_->numberColumns();
+     int numberTotal = numberColumns + numberRowsModel;
+     CoinPackedMatrix * quadratic = NULL;
+     ClpQuadraticObjective * quadraticObj =
+          (dynamic_cast< ClpQuadraticObjective*>(model_->objectiveAsObject()));
+     if (quadraticObj)
+          quadratic = quadraticObj->quadraticObjective();
+     if (!doKKT_) {
+          numberRows_ = model->numberRows();
+     } else {
+          numberRows_ = 2 * numberRowsModel + numberColumns;
+     }
+     rowsDropped_ = new char [numberRows_];
+     numberRowsDropped_ = 0;
+     memset(rowsDropped_, 0, numberRows_);
+     rowCopy_ = model->clpMatrix()->reverseOrderedCopy();
+     const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts();
+     const int * columnLength = model_->clpMatrix()->getVectorLengths();
+     const int * row = model_->clpMatrix()->getIndices();
+     const CoinBigIndex * rowStart = rowCopy_->getVectorStarts();
+     const int * rowLength = rowCopy_->getVectorLengths();
+     const int * column = rowCopy_->getIndices();
+     // We need arrays for counts
+     int * which = new int [numberRows_];
+     int * used = new int[numberRows_+1];
+     int * count = new int[numberRows_];
+     CoinZeroN(count, numberRows_);
+     CoinZeroN(used, numberRows_);
+     int iRow;
+     sizeFactor_ = 0;
+     permute_ = new int[numberRows_];
+     for (iRow = 0; iRow < numberRows_; iRow++)
+          permute_[iRow] = iRow;
+     if (!doKKT_) {
+          int numberDense = 0;
+          if (denseThreshold_ > 0) {
+               delete [] whichDense_;
+               delete [] denseColumn_;
+               delete dense_;
+               whichDense_ = new char[numberColumns];
+               int iColumn;
+               used[numberRows_] = 0;
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    int length = columnLength[iColumn];
+                    used[length] += 1;
+               }
+               int nLong = 0;
+               int stop = CoinMax(denseThreshold_ / 2, 100);
+               for (iRow = numberRows_; iRow >= stop; iRow--) {
+                    if (used[iRow])
+		      COIN_DETAIL_PRINT(printf("%d columns are of length %d\n", used[iRow], iRow));
+                    nLong += used[iRow];
+                    if (nLong > 50 || nLong > (numberColumns >> 2))
+                         break;
+               }
+               CoinZeroN(used, numberRows_);
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (columnLength[iColumn] < denseThreshold_) {
+                         whichDense_[iColumn] = 0;
+                    } else {
+                         whichDense_[iColumn] = 1;
+                         numberDense++;
+                    }
+               }
+               if (!numberDense || numberDense > 100) {
+                    // free
+                    delete [] whichDense_;
+                    whichDense_ = NULL;
+                    denseColumn_ = NULL;
+                    dense_ = NULL;
+               } else {
+                    // space for dense columns
+                    denseColumn_ = new longDouble [numberDense*numberRows_];
+                    // dense cholesky
+                    dense_ = new ClpCholeskyDense();
+                    dense_->reserveSpace(NULL, numberDense);
+                    COIN_DETAIL_PRINT(printf("Taking %d columns as dense\n", numberDense));
+               }
+          }
+          /*
+             Get row counts and size
+          */
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int number = 1;
+               // make sure diagonal exists
+               which[0] = iRow;
+               used[iRow] = 1;
+               CoinBigIndex startRow = rowStart[iRow];
+               CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow];
+               for (CoinBigIndex k = startRow; k < endRow; k++) {
+                    int iColumn = column[k];
+                    if (!whichDense_ || !whichDense_[iColumn]) {
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                         for (CoinBigIndex j = start; j < end; j++) {
+                              int jRow = row[j];
+                              if (jRow < iRow) {
+                                   if (!used[jRow]) {
+                                        used[jRow] = 1;
+                                        which[number++] = jRow;
+                                        count[jRow]++;
+                                   }
+                              }
+                         }
+                    }
+               }
+               sizeFactor_ += number;
+               count[iRow] += number;
+               int j;
+               for (j = 0; j < number; j++)
+                    used[which[j]] = 0;
+          }
+          CoinSort_2(count, count + numberRows_, permute_);
+     } else {
+          // KKT
+          int numberElements = model_->clpMatrix()->getNumElements();
+          numberElements = numberElements + 2 * numberRowsModel + numberTotal;
+          if (quadratic)
+               numberElements += quadratic->getNumElements();
+          // off diagonal
+          numberElements -= numberRows_;
+          sizeFactor_ = numberElements;
+          // If we sort we need to redo symbolic etc
+     }
+     delete [] which;
+     delete [] used;
+     delete [] count;
+     permuteInverse_ = new int [numberRows_];
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          //permute_[iRow]=iRow; // force no permute
+          //permute_[iRow]=numberRows_-1-iRow; // force odd permute
+          //permute_[iRow]=(iRow+1)%numberRows_; // force odd permute
+          permuteInverse_[permute_[iRow]] = iRow;
+     }
+     return 0;
+}
+#if BASE_ORDER==1
+/* Orders rows and saves pointer to matrix.and model */
+int
+ClpCholeskyBase::orderAMD()
+{
+     permuteInverse_ = new int [numberRows_];
+     permute_ = new int[numberRows_];
+     // Do ordering
+     int returnCode = 0;
+     // get more space and full matrix
+     int space = 6 * sizeFactor_ + 100000;
+     int * temp = new int [space];
+     int * which = new int[2*numberRows_];
+     CoinBigIndex * tempStart = new CoinBigIndex [numberRows_+1];
+     memset(which, 0, numberRows_ * sizeof(int));
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          which[iRow] += choleskyStart_[iRow+1] - choleskyStart_[iRow] - 1;
+          for (CoinBigIndex j = choleskyStart_[iRow] + 1; j < choleskyStart_[iRow+1]; j++) {
+               int jRow = choleskyRow_[j];
+               which[jRow]++;
+          }
+     }
+     CoinBigIndex sizeFactor = 0;
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          int length = which[iRow];
+          permute_[iRow] = length;
+          tempStart[iRow] = sizeFactor;
+          which[iRow] = sizeFactor;
+          sizeFactor += length;
+     }
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          assert (choleskyRow_[choleskyStart_[iRow]] == iRow);
+          for (CoinBigIndex j = choleskyStart_[iRow] + 1; j < choleskyStart_[iRow+1]; j++) {
+               int jRow = choleskyRow_[j];
+               int put = which[iRow];
+               temp[put] = jRow;
+               which[iRow]++;
+               put = which[jRow];
+               temp[put] = iRow;
+               which[jRow]++;
+          }
+     }
+     for (int iRow = 1; iRow < numberRows_; iRow++)
+          assert (which[iRow-1] == tempStart[iRow]);
+     CoinBigIndex lastSpace = sizeFactor;
+     delete [] choleskyRow_;
+     choleskyRow_ = temp;
+     delete [] choleskyStart_;
+     choleskyStart_ = tempStart;
+     // linked lists of sizes and lengths
+     int * first = new int [numberRows_];
+     int * next = new int [numberRows_];
+     int * previous = new int [numberRows_];
+     char * mark = new char[numberRows_];
+     memset(mark, 0, numberRows_);
+     CoinBigIndex * sort = new CoinBigIndex [numberRows_];
+     int * order = new int [numberRows_];
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          first[iRow] = -1;
+          next[iRow] = -1;
+          previous[iRow] = -1;
+          permuteInverse_[iRow] = -1;
+     }
+     int large = 1000 + 2 * numberRows_;
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          int n = permute_[iRow];
+          if (first[n] < 0) {
+               first[n] = iRow;
+               previous[iRow] = n + large;
+               next[iRow] = n + 2 * large;
+          } else {
+               int k = first[n];
+               assert (k < numberRows_);
+               first[n] = iRow;
+               previous[iRow] = n + large;
+               assert (previous[k] == n + large);
+               next[iRow] = k;
+               previous[k] = iRow;
+          }
+     }
+     int smallest = 0;
+     int done = 0;
+     int numberCompressions = 0;
+     int numberExpansions = 0;
+     while (smallest < numberRows_) {
+          if (first[smallest] < 0 || first[smallest] > numberRows_) {
+               smallest++;
+               continue;
+          }
+          int iRow = first[smallest];
+          if (false) {
+               int kRow = -1;
+               int ss = 999999;
+               for (int jRow = numberRows_ - 1; jRow >= 0; jRow--) {
+                    if (permuteInverse_[jRow] < 0) {
+                         int length = permute_[jRow];
+                         assert (length > 0);
+                         for (CoinBigIndex j = choleskyStart_[jRow];
+                                   j < choleskyStart_[jRow] + length; j++) {
+                              int jjRow = choleskyRow_[j];
+                              assert (permuteInverse_[jjRow] < 0);
+                         }
+                         if (length < ss) {
+                              ss = length;
+                              kRow = jRow;
+                         }
+                    }
+               }
+               assert (smallest == ss);
+               printf("list chose %d - full chose %d - length %d\n",
+                      iRow, kRow, ss);
+          }
+          int kNext = next[iRow];
+          first[smallest] = kNext;
+          if (kNext < numberRows_)
+               previous[kNext] = previous[iRow];
+          previous[iRow] = -1;
+          next[iRow] = -1;
+          permuteInverse_[iRow] = done;
+          done++;
+          // Now add edges
+          CoinBigIndex start = choleskyStart_[iRow];
+          CoinBigIndex end = choleskyStart_[iRow] + permute_[iRow];
+          int nSave = 0;
+          for (CoinBigIndex k = start; k < end; k++) {
+               int kRow = choleskyRow_[k];
+               assert (permuteInverse_[kRow] < 0);
+               //if (permuteInverse_[kRow]<0)
+               which[nSave++] = kRow;
+          }
+          for (int i = 0; i < nSave; i++) {
+               int kRow = which[i];
+               int length = permute_[kRow];
+               CoinBigIndex start = choleskyStart_[kRow];
+               CoinBigIndex end = choleskyStart_[kRow] + length;
+               for (CoinBigIndex j = start; j < end; j++) {
+                    int jRow = choleskyRow_[j];
+                    mark[jRow] = 1;
+               }
+               mark[kRow] = 1;
+               int n = nSave;
+               for (int j = 0; j < nSave; j++) {
+                    int jRow = which[j];
+                    if (!mark[jRow]) {
+                         which[n++] = jRow;
+                    }
+               }
+               for (CoinBigIndex j = start; j < end; j++) {
+                    int jRow = choleskyRow_[j];
+                    mark[jRow] = 0;
+               }
+               mark[kRow] = 0;
+               if (n > nSave) {
+                    bool inPlace = (n - nSave == 1);
+                    if (!inPlace) {
+                         // extend
+                         int length = n - nSave + end - start;
+                         if (length + lastSpace > space) {
+                              // need to compress
+                              numberCompressions++;
+                              int newN = 0;
+                              for (int iRow = 0; iRow < numberRows_; iRow++) {
+                                   CoinBigIndex start = choleskyStart_[iRow];
+                                   if (permuteInverse_[iRow] < 0) {
+                                        sort[newN] = start;
+                                        order[newN++] = iRow;
+                                   } else {
+                                        choleskyStart_[iRow] = -1;
+                                        permute_[iRow] = 0;
+                                   }
+                              }
+                              CoinSort_2(sort, sort + newN, order);
+                              sizeFactor = 0;
+                              for (int k = 0; k < newN; k++) {
+                                   int iRow = order[k];
+                                   int length = permute_[iRow];
+                                   CoinBigIndex start = choleskyStart_[iRow];
+                                   choleskyStart_[iRow] = sizeFactor;
+                                   for (int j = 0; j < length; j++)
+                                        choleskyRow_[sizeFactor+j] = choleskyRow_[start+j];
+                                   sizeFactor += length;
+                              }
+                              lastSpace = sizeFactor;
+                              if ((sizeFactor + numberRows_ + 1000) * 4 > 3 * space) {
+                                   // need to expand
+                                   numberExpansions++;
+                                   space = (3 * space) / 2;
+                                   int * temp = new int [space];
+                                   memcpy(temp, choleskyRow_, sizeFactor * sizeof(int));
+                                   delete [] choleskyRow_;
+                                   choleskyRow_ = temp;
+                              }
+                         }
+                    }
+                    // Now add
+                    start = choleskyStart_[kRow];
+                    end = choleskyStart_[kRow] + permute_[kRow];
+                    if (!inPlace)
+                         choleskyStart_[kRow] = lastSpace;
+                    CoinBigIndex put = choleskyStart_[kRow];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         int jRow = choleskyRow_[j];
+                         if (permuteInverse_[jRow] < 0)
+                              choleskyRow_[put++] = jRow;
+                    }
+                    for (int j = nSave; j < n; j++) {
+                         int jRow = which[j];
+                         choleskyRow_[put++] = jRow;
+                    }
+                    if (!inPlace) {
+                         permute_[kRow] = put - lastSpace;
+                         lastSpace = put;
+                    } else {
+                         permute_[kRow] = put - choleskyStart_[kRow];
+                    }
+               } else {
+                    // pack down for new counts
+                    CoinBigIndex put = start;
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         int jRow = choleskyRow_[j];
+                         if (permuteInverse_[jRow] < 0)
+                              choleskyRow_[put++] = jRow;
+                    }
+                    permute_[kRow] = put - start;
+               }
+               // take out
+               int iNext = next[kRow];
+               int iPrevious = previous[kRow];
+               if (iPrevious < numberRows_) {
+                    next[iPrevious] = iNext;
+               } else {
+                    assert (iPrevious == length + large);
+                    first[length] = iNext;
+               }
+               if (iNext < numberRows_) {
+                    previous[iNext] = iPrevious;
+               } else {
+                    assert (iNext == length + 2 * large);
+               }
+               // put in
+               length = permute_[kRow];
+               smallest = CoinMin(smallest, length);
+               if (first[length] < 0 || first[length] > numberRows_) {
+                    first[length] = kRow;
+                    previous[kRow] = length + large;
+                    next[kRow] = length + 2 * large;
+               } else {
+                    int k = first[length];
+                    assert (k < numberRows_);
+                    first[length] = kRow;
+                    previous[kRow] = length + large;
+                    assert (previous[k] == length + large);
+                    next[kRow] = k;
+                    previous[k] = kRow;
+               }
+          }
+     }
+     // do rest
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          if (permuteInverse_[iRow] < 0)
+               permuteInverse_[iRow] = done++;
+     }
+     COIN_DETAIL_PRINT(printf("%d compressions, %d expansions\n",
+			      numberCompressions, numberExpansions));
+     assert (done == numberRows_);
+     delete [] sort;
+     delete [] order;
+     delete [] which;
+     delete [] mark;
+     delete [] first;
+     delete [] next;
+     delete [] previous;
+     delete [] choleskyRow_;
+     choleskyRow_ = NULL;
+     delete [] choleskyStart_;
+     choleskyStart_ = NULL;
+#ifndef NDEBUG
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          permute_[iRow] = -1;
+     }
+#endif
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          permute_[permuteInverse_[iRow]] = iRow;
+     }
+#ifndef NDEBUG
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          assert(permute_[iRow] >= 0 && permute_[iRow] < numberRows_);
+     }
+#endif
+     return returnCode;
+}
+#elif BASE_ORDER==2
+/*----------------------------------------------------------------------------*/
+/*	(C) Copyright IBM Corporation 1997, 2009.  All Rights Reserved.       */
+/*----------------------------------------------------------------------------*/
+
+/*  A compact no-frills Approximate Minimum Local Fill ordering code.
+
+    References:
+
+[1] Ordering Sparse Matrices Using Approximate Minimum Local Fill.
+    Edward Rothberg, SGI Manuscript, April 1996.
+[2] An Approximate Minimum Degree Ordering Algorithm.
+    T. Davis, P. Amestoy, and I. Duff, TR-94-039, CIS Department,
+    University of Florida, December 1994.
+*/
+
+#include <math.h>
+#include <stdlib.h>
+
+typedef int             WSI;
+
+#define NORDTHRESH	7
+#define MAXIW		2147000000
+
+//#define WSSMP_DBG
+#ifdef WSSMP_DBG
+static void chk (WSI ind, WSI i, WSI lim)
+{
+
+     if (i <= 0 || i > lim) {
+          printf("%d: chk: myamlf: WAR**: i, lim = %d, %d\n", ind, i, lim);
+     }
+}
+#endif
+
+static void
+myamlf(WSI n, WSI xadj[], WSI adjncy[], WSI dgree[], WSI varbl[],
+       WSI snxt[], WSI perm[], WSI invp[], WSI head[], WSI lsize[],
+       WSI flag[], WSI erscore[], WSI locaux, WSI adjln, WSI speed)
+{
+     WSI l, i, j, k;
+     double x, y;
+     WSI maxmum, fltag, nodeg, scln, nm1, deg, tn,
+         locatns, ipp, jpp, nnode, numpiv, node,
+         nodeln, currloc, counter, numii, mindeg,
+         i0, i1, i2, i4, i5, i6, i7, i9,
+         j0, j1, j2, j3, j4, j5, j6, j7, j8, j9;
+     /*                                             n cannot be less than NORDTHRESH
+      if (n < 3) {
+         if (n > 0) perm[0] = invp[0] = 1;
+         if (n > 1) perm[1] = invp[1] = 2;
+         return;
+      }
+     */
+#ifdef WSSMP_DBG
+     printf("Myamlf: n, locaux, adjln, speed = %d,%d,%d,%d\n", n, locaux, adjln, speed);
+     for (i = 0; i < n; i++) flag[i] = 0;
+     k = xadj[0];
+     for (i = 1; i <= n; i++) {
+          j = k + dgree[i-1];
+          if (j < k || k < 1) printf("ERR**: myamlf: i, j, k = %d,%d,%d\n", i, j, k);
+          for (l = k; l < j; l++) {
+               if (adjncy[l - 1] < 1 || adjncy[l - 1] > n || adjncy[l - 1] == i)
+                    printf("ERR**: myamlf: i, l, adjj[l] = %d,%d,%d\n", i, l, adjncy[l - 1]);
+               if (flag[adjncy[l - 1] - 1] == i)
+                    printf("ERR**: myamlf: duplicate entry: %d - %d\n", i, adjncy[l - 1]);
+               flag[adjncy[l - 1] - 1] = i;
+               nm1 = adjncy[l - 1] - 1;
+               for (fltag = xadj[nm1]; fltag < xadj[nm1] + dgree[nm1]; fltag++) {
+                    if (adjncy[fltag - 1] == i) goto L100;
+               }
+               printf("ERR**: Unsymmetric %d %d\n", i, fltag);
+L100:
+               ;
+          }
+          k = j;
+          if (k > locaux) printf("ERR**: i, j, k, locaux = %d, %d, %d, %d\n",
+                                      i, j, k, locaux);
+     }
+     if (n*(n - 1) < locaux - 1) printf("ERR**: myamlf: too many nnz, n, ne = %d, %d\n",
+                                             n, adjln);
+     for (i = 0; i < n; i++) flag[i] = 1;
+     if (n > 10000) printf ("Finished error checking in AMF\n");
+     for (i = locaux; i <= adjln; i++) adjncy[i - 1] = -22;
+#endif
+
+     maxmum = 0;
+     mindeg = 1;
+     fltag = 2;
+     locatns = locaux - 1;
+     nm1 = n - 1;
+     counter = 1;
+     for (l = 0; l < n; l++) {
+          j = erscore[l];
+#ifdef WSSMP_DBG
+          chk(1, j, n);
+#endif
+          if (j > 0) {
+               nnode = head[j - 1];
+               if (nnode) perm[nnode - 1] = l + 1;
+               snxt[l] = nnode;
+               head[j - 1] = l + 1;
+          } else {
+               invp[l] = -(counter++);
+               flag[l] = xadj[l] = 0;
+          }
+     }
+     while (counter <= n) {
+          for (deg = mindeg; head[deg - 1] < 1; deg++) {};
+          nodeg = 0;
+#ifdef WSSMP_DBG
+          chk(2, deg, n - 1);
+#endif
+          node = head[deg - 1];
+#ifdef WSSMP_DBG
+          chk(3, node, n);
+#endif
+          mindeg = deg;
+          nnode = snxt[node - 1];
+          if (nnode) perm[nnode - 1] = 0;
+          head[deg - 1] = nnode;
+          nodeln = invp[node - 1];
+          numpiv = varbl[node - 1];
+          invp[node - 1] = -counter;
+          counter += numpiv;
+          varbl[node - 1] = -numpiv;
+          if (nodeln) {
+               j4 = locaux;
+               i5 = lsize[node - 1] - nodeln;
+               i2 = nodeln + 1;
+               l = xadj[node - 1];
+               for (i6 = 1; i6 <= i2; ++i6) {
+                    if (i6 == i2) {
+                         tn = node, i0 = l, scln = i5;
+                    } else {
+#ifdef WSSMP_DBG
+                         chk(4, l, adjln);
+#endif
+                         tn = adjncy[l-1];
+                         l++;
+#ifdef WSSMP_DBG
+                         chk(5, tn, n);
+#endif
+                         i0 = xadj[tn - 1];
+                         scln = lsize[tn - 1];
+                    }
+                    for (i7 = 1; i7 <= scln; ++i7) {
+#ifdef WSSMP_DBG
+                         chk(6, i0, adjln);
+#endif
+                         i = adjncy[i0 - 1];
+                         i0++;
+#ifdef WSSMP_DBG
+                         chk(7, i, n);
+#endif
+                         numii = varbl[i - 1];
+                         if (numii > 0) {
+                              if (locaux > adjln) {
+                                   lsize[node - 1] -= i6;
+                                   xadj[node - 1] = l;
+                                   if (!lsize[node - 1]) xadj[node - 1] = 0;
+                                   xadj[tn - 1] = i0;
+                                   lsize[tn - 1] = scln - i7;
+                                   if (!lsize[tn - 1]) xadj[tn - 1] = 0;
+                                   for (j = 1; j <= n; j++) {
+                                        i4 = xadj[j - 1];
+                                        if (i4 > 0) {
+                                             xadj[j - 1] = adjncy[i4 - 1];
+#ifdef WSSMP_DBG
+                                             chk(8, i4, adjln);
+#endif
+                                             adjncy[i4 - 1] = -j;
+                                        }
+                                   }
+                                   i9 = j4 - 1;
+                                   j6 = j7 = 1;
+                                   while (j6 <= i9) {
+#ifdef WSSMP_DBG
+                                        chk(9, j6, adjln);
+#endif
+                                        j = -adjncy[j6 - 1];
+                                        j6++;
+                                        if (j > 0) {
+#ifdef WSSMP_DBG
+                                             chk(10, j7, adjln);
+                                             chk(11, j, n);
+#endif
+                                             adjncy[j7 - 1] = xadj[j - 1];
+                                             xadj[j - 1] = j7++;
+                                             j8 = lsize[j - 1] - 1 + j7;
+                                             for (; j7 < j8; j7++, j6++) adjncy[j7-1] = adjncy[j6-1];
+                                        }
+                                   }
+                                   for (j0 = j7; j4 < locaux; j4++, j7++) {
+#ifdef WSSMP_DBG
+                                        chk(12, j4, adjln);
+#endif
+                                        adjncy[j7 - 1] = adjncy[j4 - 1];
+                                   }
+                                   j4 = j0;
+                                   locaux = j7;
+                                   i0 = xadj[tn - 1];
+                                   l = xadj[node - 1];
+                              }
+                              adjncy[locaux-1] = i;
+                              locaux++;
+                              varbl[i - 1] = -numii;
+                              nodeg += numii;
+                              ipp = perm[i - 1];
+                              nnode = snxt[i - 1];
+#ifdef WSSMP_DBG
+                              if (ipp) chk(13, ipp, n);
+                              if (nnode) chk(14, nnode, n);
+#endif
+                              if (ipp) snxt[ipp - 1] = nnode;
+                              else head[erscore[i - 1] - 1] = nnode;
+                              if (nnode) perm[nnode - 1] = ipp;
+                         }
+                    }
+                    if (tn != node) {
+                         flag[tn - 1] = 0, xadj[tn - 1] = -node;
+                    }
+               }
+               currloc = (j5 = locaux) - j4;
+               locatns += currloc;
+          } else {
+               i1 = (j4 = xadj[node - 1]) + lsize[node - 1];
+               for (j = j5 = j4; j < i1; j++) {
+#ifdef WSSMP_DBG
+                    chk(15, j, adjln);
+#endif
+                    i = adjncy[j - 1];
+#ifdef WSSMP_DBG
+                    chk(16, i, n);
+#endif
+                    numii = varbl[i - 1];
+                    if (numii > 0) {
+                         nodeg += numii;
+                         varbl[i - 1] = -numii;
+#ifdef WSSMP_DBG
+                         chk(17, j5, adjln);
+#endif
+                         adjncy[j5-1] = i;
+                         ipp = perm[i - 1];
+                         nnode = snxt[i - 1];
+                         j5++;
+#ifdef WSSMP_DBG
+                         if (ipp) chk(18, ipp, n);
+                         if (nnode) chk(19, nnode, n);
+#endif
+                         if (ipp) snxt[ipp - 1] = nnode;
+                         else head[erscore[i - 1] - 1] = nnode;
+                         if (nnode) perm[nnode - 1] = ipp;
+                    }
+               }
+               currloc = 0;
+          }
+#ifdef WSSMP_DBG
+          chk(20, node, n);
+#endif
+          lsize[node - 1] = j5 - (xadj[node - 1] = j4);
+          dgree[node - 1] = nodeg;
+          if (fltag + n < 0 || fltag + n > MAXIW) {
+               for (i = 1; i <= n; i++) if (flag[i - 1]) flag[i - 1] = 1;
+               fltag = 2;
+          }
+          for (j3 = j4; j3 < j5; j3++) {
+#ifdef WSSMP_DBG
+               chk(21, j3, adjln);
+#endif
+               i = adjncy[j3 - 1];
+#ifdef WSSMP_DBG
+               chk(22, i, n);
+#endif
+               j = invp[i - 1];
+               if (j > 0) {
+                    i4 = fltag - (numii = -varbl[i - 1]);
+                    i2 = xadj[i - 1] + j;
+                    for (l = xadj[i - 1]; l < i2; l++) {
+#ifdef WSSMP_DBG
+                         chk(23, l, adjln);
+#endif
+                         tn = adjncy[l - 1];
+#ifdef WSSMP_DBG
+                         chk(24, tn, n);
+#endif
+                         j9 = flag[tn - 1];
+                         if (j9 >= fltag) j9 -= numii;
+                         else if (j9) j9 = dgree[tn - 1] + i4;
+                         flag[tn - 1] = j9;
+                    }
+               }
+          }
+          for (j3 = j4; j3 < j5; j3++) {
+#ifdef WSSMP_DBG
+               chk(25, j3, adjln);
+#endif
+               i = adjncy[j3 - 1];
+               i5 = deg = 0;
+#ifdef WSSMP_DBG
+               chk(26, i, n);
+#endif
+               j1 = (i4 = xadj[i - 1]) + invp[i - 1];
+               for (l = j0 = i4; l < j1; l++) {
+#ifdef WSSMP_DBG
+                    chk(27, l, adjln);
+#endif
+                    tn = adjncy[l - 1];
+#ifdef WSSMP_DBG
+                    chk(70, tn, n);
+#endif
+                    j8 = flag[tn - 1];
+                    if (j8) {
+                         deg += (j8 - fltag);
+#ifdef WSSMP_DBG
+                         chk(28, i4, adjln);
+#endif
+                         adjncy[i4-1] = tn;
+                         i5 += tn;
+                         i4++;
+                         while (i5 >= nm1) i5 -= nm1;
+                    }
+               }
+               invp[i - 1] = (j2 = i4) - j0 + 1;
+               i2 = j0 + lsize[i - 1];
+               for (l = j1; l < i2; l++) {
+#ifdef WSSMP_DBG
+                    chk(29, l, adjln);
+#endif
+                    j = adjncy[l - 1];
+#ifdef WSSMP_DBG
+                    chk(30, j, n);
+#endif
+                    numii = varbl[j - 1];
+                    if (numii > 0) {
+                         deg += numii;
+#ifdef WSSMP_DBG
+                         chk(31, i4, adjln);
+#endif
+                         adjncy[i4-1] = j;
+                         i5 += j;
+                         i4++;
+                         while (i5 >= nm1) i5 -= nm1;
+                    }
+               }
+               if (invp[i - 1] == 1 && j2 == i4) {
+                    numii = -varbl[i - 1];
+                    xadj[i - 1] = -node;
+                    nodeg -= numii;
+                    counter += numii;
+                    numpiv += numii;
+                    invp[i - 1] = varbl[i - 1] = 0;
+               } else {
+                    if (dgree[i - 1] > deg) dgree[i - 1] = deg;
+#ifdef WSSMP_DBG
+                    chk(32, j2, adjln);
+                    chk(33, j0, adjln);
+#endif
+                    adjncy[i4 - 1] = adjncy[j2 - 1];
+                    adjncy[j2 - 1] = adjncy[j0 - 1];
+                    adjncy[j0 - 1] = node;
+                    lsize[i - 1] = i4 - j0 + 1;
+                    i5++;
+#ifdef WSSMP_DBG
+                    chk(35, i5, n);
+#endif
+                    j = head[i5 - 1];
+                    if (j > 0) {
+                         snxt[i - 1] = perm[j - 1];
+                         perm[j - 1] = i;
+                    } else {
+                         snxt[i - 1] = -j;
+                         head[i5 - 1] = -i;
+                    }
+                    perm[i - 1] = i5;
+               }
+          }
+#ifdef WSSMP_DBG
+          chk(36, node, n);
+#endif
+          dgree[node - 1] = nodeg;
+          if (maxmum < nodeg) maxmum = nodeg;
+          fltag += maxmum;
+#ifdef WSSMP_DBG
+          if (fltag + n + 1 < 0) printf("ERR**: fltag = %d (A)\n", fltag);
+#endif
+          for (j3 = j4; j3 < j5; ++j3) {
+#ifdef WSSMP_DBG
+               chk(37, j3, adjln);
+#endif
+               i = adjncy[j3 - 1];
+#ifdef WSSMP_DBG
+               chk(38, i, n);
+#endif
+               if (varbl[i - 1] < 0) {
+                    i5 = perm[i - 1];
+#ifdef WSSMP_DBG
+                    chk(39, i5, n);
+#endif
+                    j = head[i5 - 1];
+                    if (j) {
+                         if (j < 0) {
+                              head[i5 - 1] = 0, i = -j;
+                         } else {
+#ifdef WSSMP_DBG
+                              chk(40, j, n);
+#endif
+                              i = perm[j - 1];
+                              perm[j - 1] = 0;
+                         }
+                         while (i) {
+#ifdef WSSMP_DBG
+                              chk(41, i, n);
+#endif
+                              if (!snxt[i - 1]) {
+                                   i = 0;
+                              } else {
+                                   k = invp[i - 1];
+                                   i2 = xadj[i - 1] + (scln = lsize[i - 1]);
+                                   for (l = xadj[i - 1] + 1; l < i2; l++) {
+#ifdef WSSMP_DBG
+                                        chk(42, l, adjln);
+                                        chk(43, adjncy[l - 1], n);
+#endif
+                                        flag[adjncy[l - 1] - 1] = fltag;
+                                   }
+                                   jpp = i;
+                                   j = snxt[i - 1];
+                                   while (j) {
+#ifdef WSSMP_DBG
+                                        chk(44, j, n);
+#endif
+                                        if (lsize[j - 1] == scln && invp[j - 1] == k) {
+                                             i2 = xadj[j - 1] + scln;
+                                             j8 = 1;
+                                             for (l = xadj[j - 1] + 1; l < i2; l++) {
+#ifdef WSSMP_DBG
+                                                  chk(45, l, adjln);
+                                                  chk(46, adjncy[l - 1], n);
+#endif
+                                                  if (flag[adjncy[l - 1] - 1] != fltag) {
+                                                       j8 = 0;
+                                                       break;
+                                                  }
+                                             }
+                                             if (j8) {
+                                                  xadj[j - 1] = -i;
+                                                  varbl[i - 1] += varbl[j - 1];
+                                                  varbl[j - 1] = invp[j - 1] = 0;
+#ifdef WSSMP_DBG
+                                                  chk(47, j, n);
+                                                  chk(48, jpp, n);
+#endif
+                                                  j = snxt[j - 1];
+                                                  snxt[jpp - 1] = j;
+                                             } else {
+                                                  jpp = j;
+#ifdef WSSMP_DBG
+                                                  chk(49, j, n);
+#endif
+                                                  j = snxt[j - 1];
+                                             }
+                                        } else {
+                                             jpp = j;
+#ifdef WSSMP_DBG
+                                             chk(50, j, n);
+#endif
+                                             j = snxt[j - 1];
+                                        }
+                                   }
+                                   fltag++;
+#ifdef WSSMP_DBG
+                                   if (fltag + n + 1 < 0) printf("ERR**: fltag = %d (B)\n", fltag);
+#endif
+#ifdef WSSMP_DBG
+                                   chk(51, i, n);
+#endif
+                                   i = snxt[i - 1];
+                              }
+                         }
+                    }
+               }
+          }
+          j8 = nm1 - counter;
+          switch (speed) {
+          case 1:
+               for (j = j3 = j4; j3 < j5; j3++) {
+#ifdef WSSMP_DBG
+                    chk(52, j3, adjln);
+#endif
+                    i = adjncy[j3 - 1];
+#ifdef WSSMP_DBG
+                    chk(53, i, n);
+#endif
+                    numii = varbl[i - 1];
+                    if (numii < 0) {
+                         k = 0;
+                         i4 = (l = xadj[i - 1]) + invp[i - 1];
+                         for (; l < i4; l++) {
+#ifdef WSSMP_DBG
+                              chk(54, l, adjln);
+                              chk(55, adjncy[l - 1], n);
+#endif
+                              i5 = dgree[adjncy[l - 1] - 1];
+                              if (k < i5) k = i5;
+                         }
+                         x = static_cast<double> (k - 1);
+                         varbl[i - 1] = abs(numii);
+                         j9 = dgree[i - 1] + nodeg;
+                         deg = (j8 > j9 ? j9 : j8) + numii;
+                         if (deg < 1) deg = 1;
+                         y = static_cast<double> (deg);
+                         dgree[i - 1] = deg;
+                         /*
+                                    printf("%i %f should >= %i %f\n",deg,y,k-1,x);
+                                    if (y < x) printf("** \n"); else printf("\n");
+                         */
+                         y = y * y - y;
+                         x = y - (x * x - x);
+                         if (x < 1.1) x = 1.1;
+                         deg = static_cast<WSI>(sqrt(x));
+                         /*         if (deg < 1) deg = 1; */
+                         erscore[i - 1] = deg;
+#ifdef WSSMP_DBG
+                         chk(56, deg, n - 1);
+#endif
+                         nnode = head[deg - 1];
+                         if (nnode) perm[nnode - 1] = i;
+                         snxt[i - 1] = nnode;
+                         perm[i - 1] = 0;
+#ifdef WSSMP_DBG
+                         chk(57, j, adjln);
+#endif
+                         head[deg - 1] = adjncy[j-1] = i;
+                         j++;
+                         if (deg < mindeg) mindeg = deg;
+                    }
+               }
+               break;
+          case 2:
+               for (j = j3 = j4; j3 < j5; j3++) {
+#ifdef WSSMP_DBG
+                    chk(58, j3, adjln);
+#endif
+                    i = adjncy[j3 - 1];
+#ifdef WSSMP_DBG
+                    chk(59, i, n);
+#endif
+                    numii = varbl[i - 1];
+                    if (numii < 0) {
+                         x = static_cast<double> (dgree[adjncy[xadj[i - 1] - 1] - 1] - 1);
+                         varbl[i - 1] = abs(numii);
+                         j9 = dgree[i - 1] + nodeg;
+                         deg = (j8 > j9 ? j9 : j8) + numii;
+                         if (deg < 1) deg = 1;
+                         y = static_cast<double> (deg);
+                         dgree[i - 1] = deg;
+                         /*
+                                    printf("%i %f should >= %i %f",deg,y,dgree[adjncy[xadj[i - 1] - 1] - 1]-1,x);
+                                    if (y < x) printf("** \n"); else printf("\n");
+                         */
+                         y = y * y - y;
+                         x = y - (x * x - x);
+                         if (x < 1.1) x = 1.1;
+                         deg = static_cast<WSI>(sqrt(x));
+                         /*         if (deg < 1) deg = 1; */
+                         erscore[i - 1] = deg;
+#ifdef WSSMP_DBG
+                         chk(60, deg, n - 1);
+#endif
+                         nnode = head[deg - 1];
+                         if (nnode) perm[nnode - 1] = i;
+                         snxt[i - 1] = nnode;
+                         perm[i - 1] = 0;
+#ifdef WSSMP_DBG
+                         chk(61, j, adjln);
+#endif
+                         head[deg - 1] = adjncy[j-1] = i;
+                         j++;
+                         if (deg < mindeg) mindeg = deg;
+                    }
+               }
+               break;
+          default:
+               for (j = j3 = j4; j3 < j5; j3++) {
+#ifdef WSSMP_DBG
+                    chk(62, j3, adjln);
+#endif
+                    i = adjncy[j3 - 1];
+#ifdef WSSMP_DBG
+                    chk(63, i, n);
+#endif
+                    numii = varbl[i - 1];
+                    if (numii < 0) {
+                         varbl[i - 1] = abs(numii);
+                         j9 = dgree[i - 1] + nodeg;
+                         deg = (j8 > j9 ? j9 : j8) + numii;
+                         if (deg < 1) deg = 1;
+                         dgree[i - 1] = deg;
+#ifdef WSSMP_DBG
+                         chk(64, deg, n - 1);
+#endif
+                         nnode = head[deg - 1];
+                         if (nnode) perm[nnode - 1] = i;
+                         snxt[i - 1] = nnode;
+                         perm[i - 1] = 0;
+#ifdef WSSMP_DBG
+                         chk(65, j, adjln);
+#endif
+                         head[deg - 1] = adjncy[j-1] = i;
+                         j++;
+                         if (deg < mindeg) mindeg = deg;
+                    }
+               }
+               break;
+          }
+          if (currloc) {
+#ifdef WSSMP_DBG
+               chk(66, node, n);
+#endif
+               locatns += (lsize[node - 1] - currloc), locaux = j;
+          }
+          varbl[node - 1] = numpiv + nodeg;
+          lsize[node - 1] = j - j4;
+          if (!lsize[node - 1]) flag[node - 1] = xadj[node - 1] = 0;
+     }
+     for (l = 1; l <= n; l++) {
+          if (!invp[l - 1]) {
+               for (i = -xadj[l - 1]; invp[i - 1] >= 0; i = -xadj[i - 1]) {};
+               tn = i;
+#ifdef WSSMP_DBG
+               chk(67, tn, n);
+#endif
+               k = -invp[tn - 1];
+               i = l;
+#ifdef WSSMP_DBG
+               chk(68, i, n);
+#endif
+               while (invp[i - 1] >= 0) {
+                    nnode = -xadj[i - 1];
+                    xadj[i - 1] = -tn;
+                    if (!invp[i - 1]) invp[i - 1] = k++;
+                    i = nnode;
+               }
+               invp[tn - 1] = -k;
+          }
+     }
+     for (l = 0; l < n; l++) {
+          i = abs(invp[l]);
+#ifdef WSSMP_DBG
+          chk(69, i, n);
+#endif
+          invp[l] = i;
+          perm[i - 1] = l + 1;
+     }
+     return;
+}
+// This code is not needed, but left in in case needed sometime
+#if 0
+/*C--------------------------------------------------------------------------*/
+void amlfdr(WSI *n, WSI xadj[], WSI adjncy[], WSI dgree[], WSI *adjln,
+            WSI *locaux, WSI varbl[], WSI snxt[], WSI perm[],
+            WSI head[], WSI invp[], WSI lsize[], WSI flag[], WSI *ispeed)
+{
+     WSI nn, nlocaux, nadjln, speed, i, j, mx, mxj, *erscore;
+
+#ifdef WSSMP_DBG
+     printf("Calling amlfdr for n, speed = %d, %d\n", *n, *ispeed);
+#endif
+
+     if ((nn = *n) == 0) return;
+
+#ifdef WSSMP_DBG
+     if (nn == 31) {
+          printf("n = %d; adjln = %d; locaux = %d; ispeed = %d\n",
+                 *n, *adjln, *locaux, *ispeed);
+     }
+#endif
+
+     if (nn < NORDTHRESH) {
+          for (i = 0; i < nn; i++) lsize[i] = i;
+          for (i = nn; i > 0; i--) {
+               mx = dgree[0];
+               mxj = 0;
+               for (j = 1; j < i; j++)
+                    if (dgree[j] > mx) {
+                         mx = dgree[j];
+                         mxj = j;
+                    }
+               invp[lsize[mxj]] = i;
+               dgree[mxj] = dgree[i-1];
+               lsize[mxj] = lsize[i-1];
+          }
+          return;
+     }
+     speed = *ispeed;
+     if (speed < 3) {
+          /*
+              erscore = (WSI *)malloc(nn * sizeof(WSI));
+              if (erscore == NULL) speed = 3;
+          */
+          wscmal (&nn, &i, &erscore);
+          if (i != 0) speed = 3;
+     }
+     if (speed > 2) erscore = dgree;
+     if (speed < 3) {
+          for (i = 0; i < nn; i++) {
+               perm[i] = 0;
+               invp[i] = 0;
+               head[i] = 0;
+               flag[i] = 1;
+               varbl[i] = 1;
+               lsize[i] = dgree[i];
+               erscore[i] = dgree[i];
+          }
+     } else {
+          for (i = 0; i < nn; i++) {
+               perm[i] = 0;
+               invp[i] = 0;
+               head[i] = 0;
+               flag[i] = 1;
+               varbl[i] = 1;
+               lsize[i] = dgree[i];
+          }
+     }
+     nlocaux = *locaux;
+     nadjln = *adjln;
+
+     myamlf(nn, xadj, adjncy, dgree, varbl, snxt, perm, invp,
+            head, lsize, flag, erscore, nlocaux, nadjln, speed);
+     /*
+       if (speed < 3) free(erscore);
+     */
+     if (speed < 3) wscfr(&erscore);
+     return;
+}
+#endif // end of taking out amlfdr
+/*C--------------------------------------------------------------------------*/
+#endif
+// Orders rows
+int
+ClpCholeskyBase::orderAMD()
+{
+     permuteInverse_ = new int [numberRows_];
+     permute_ = new int[numberRows_];
+     // Do ordering
+     int returnCode = 0;
+     // get full matrix
+     int space = 2 * sizeFactor_ + 10000 + 4 * numberRows_;
+     int * temp = new int [space];
+     CoinBigIndex * count = new CoinBigIndex [numberRows_];
+     CoinBigIndex * tempStart = new CoinBigIndex [numberRows_+1];
+     memset(count, 0, numberRows_ * sizeof(int));
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          count[iRow] += choleskyStart_[iRow+1] - choleskyStart_[iRow] - 1;
+          for (CoinBigIndex j = choleskyStart_[iRow] + 1; j < choleskyStart_[iRow+1]; j++) {
+               int jRow = choleskyRow_[j];
+               count[jRow]++;
+          }
+     }
+#define OFFSET 1
+     CoinBigIndex sizeFactor = 0;
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          int length = count[iRow];
+          permute_[iRow] = length;
+          // add 1 to starts
+          tempStart[iRow] = sizeFactor + OFFSET;
+          count[iRow] = sizeFactor;
+          sizeFactor += length;
+     }
+     tempStart[numberRows_] = sizeFactor + OFFSET;
+     // add 1 to rows
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          assert (choleskyRow_[choleskyStart_[iRow]] == iRow);
+          for (CoinBigIndex j = choleskyStart_[iRow] + 1; j < choleskyStart_[iRow+1]; j++) {
+               int jRow = choleskyRow_[j];
+               int put = count[iRow];
+               temp[put] = jRow + OFFSET;
+               count[iRow]++;
+               put = count[jRow];
+               temp[put] = iRow + OFFSET;
+               count[jRow]++;
+          }
+     }
+     for (int iRow = 1; iRow < numberRows_; iRow++)
+          assert (count[iRow-1] == tempStart[iRow] - OFFSET);
+     delete [] choleskyRow_;
+     choleskyRow_ = temp;
+     delete [] choleskyStart_;
+     choleskyStart_ = tempStart;
+     int locaux = sizeFactor + OFFSET;
+     delete [] count;
+     int speed = integerParameters_[0];
+     if (speed < 1 || speed > 2)
+          speed = 3;
+     int * use = new int [((speed<3) ? 7 : 6)*numberRows_];
+     int * dgree = use;
+     int * varbl = dgree + numberRows_;
+     int * snxt = varbl + numberRows_;
+     int * head = snxt + numberRows_;
+     int * lsize = head + numberRows_;
+     int * flag = lsize + numberRows_;
+     int * erscore;
+     for (int i = 0; i < numberRows_; i++) {
+          dgree[i] = choleskyStart_[i+1] - choleskyStart_[i];
+          head[i] = dgree[i];
+          snxt[i] = 0;
+          permute_[i] = 0;
+          permuteInverse_[i] = 0;
+          head[i] = 0;
+          flag[i] = 1;
+          varbl[i] = 1;
+          lsize[i] = dgree[i];
+     }
+     if (speed < 3) {
+          erscore = flag + numberRows_;
+          for (int i = 0; i < numberRows_; i++)
+               erscore[i] = dgree[i];
+     } else {
+          erscore = dgree;
+     }
+     myamlf(numberRows_, choleskyStart_, choleskyRow_,
+            dgree, varbl, snxt, permute_, permuteInverse_,
+            head, lsize, flag, erscore, locaux, space, speed);
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          permute_[iRow]--;
+     }
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          permuteInverse_[permute_[iRow]] = iRow;
+     }
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          assert (permuteInverse_[iRow] >= 0 && permuteInverse_[iRow] < numberRows_);
+     }
+     delete [] use;
+     delete [] choleskyRow_;
+     choleskyRow_ = NULL;
+     delete [] choleskyStart_;
+     choleskyStart_ = NULL;
+     return returnCode;
+}
+/* Does Symbolic factorization given permutation.
+   This is called immediately after order.  If user provides this then
+   user must provide factorize and solve.  Otherwise the default factorization is used
+   returns non-zero if not enough memory */
+int
+ClpCholeskyBase::symbolic()
+{
+     const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts();
+     const int * columnLength = model_->clpMatrix()->getVectorLengths();
+     const int * row = model_->clpMatrix()->getIndices();
+     const CoinBigIndex * rowStart = rowCopy_->getVectorStarts();
+     const int * rowLength = rowCopy_->getVectorLengths();
+     const int * column = rowCopy_->getIndices();
+     int numberRowsModel = model_->numberRows();
+     int numberColumns = model_->numberColumns();
+     int numberTotal = numberColumns + numberRowsModel;
+     CoinPackedMatrix * quadratic = NULL;
+     ClpQuadraticObjective * quadraticObj =
+          (dynamic_cast< ClpQuadraticObjective*>(model_->objectiveAsObject()));
+     if (quadraticObj)
+          quadratic = quadraticObj->quadraticObjective();
+     // We need an array for counts
+     int * used = new int[numberRows_+1];
+     // If KKT then re-order so negative first
+     if (doKKT_) {
+          int nn = 0;
+          int np = 0;
+          int iRow;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int originalRow = permute_[iRow];
+               if (originalRow < numberTotal)
+                    permute_[nn++] = originalRow;
+               else
+                    used[np++] = originalRow;
+          }
+          CoinMemcpyN(used, np, permute_ + nn);
+          for (iRow = 0; iRow < numberRows_; iRow++)
+               permuteInverse_[permute_[iRow]] = iRow;
+     }
+     CoinZeroN(used, numberRows_);
+     int iRow;
+     int iColumn;
+     bool noMemory = false;
+     CoinBigIndex * Astart = new CoinBigIndex[numberRows_+1];
+     int * Arow = NULL;
+     try {
+          Arow = new int [sizeFactor_];
+     } catch (...) {
+          // no memory
+          delete [] Astart;
+          return -1;
+     }
+     choleskyStart_ = new int[numberRows_+1];
+     link_ = new int[numberRows_];
+     workInteger_ = new CoinBigIndex[numberRows_];
+     indexStart_ = new CoinBigIndex[numberRows_];
+     clique_ = new int[numberRows_];
+     // Redo so permuted upper triangular
+     sizeFactor_ = 0;
+     int * which = Arow;
+     if (!doKKT_) {
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int number = 0;
+               int iOriginalRow = permute_[iRow];
+               Astart[iRow] = sizeFactor_;
+               CoinBigIndex startRow = rowStart[iOriginalRow];
+               CoinBigIndex endRow = rowStart[iOriginalRow] + rowLength[iOriginalRow];
+               for (CoinBigIndex k = startRow; k < endRow; k++) {
+                    int iColumn = column[k];
+                    if (!whichDense_ || !whichDense_[iColumn]) {
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                         for (CoinBigIndex j = start; j < end; j++) {
+                              int jRow = row[j];
+                              int jNewRow = permuteInverse_[jRow];
+                              if (jNewRow < iRow) {
+                                   if (!used[jNewRow]) {
+                                        used[jNewRow] = 1;
+                                        which[number++] = jNewRow;
+                                   }
+                              }
+                         }
+                    }
+               }
+               sizeFactor_ += number;
+               int j;
+               for (j = 0; j < number; j++)
+                    used[which[j]] = 0;
+               // Sort
+               std::sort(which, which + number);
+               // move which on
+               which += number;
+          }
+     } else {
+          // KKT
+          // transpose
+          ClpMatrixBase * rowCopy = model_->clpMatrix()->reverseOrderedCopy();
+          const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+          const int * rowLength = rowCopy->getVectorLengths();
+          const int * column = rowCopy->getIndices();
+          // temp
+          bool permuted = false;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if (permute_[iRow] != iRow) {
+                    permuted = true;
+                    break;
+               }
+          }
+          if (permuted) {
+               // Need to permute - ugly
+               if (!quadratic) {
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         Astart[iRow] = sizeFactor_;
+                         int iOriginalRow = permute_[iRow];
+                         if (iOriginalRow < numberColumns) {
+                              // A may be upper triangular by mistake
+                              iColumn = iOriginalRow;
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int kRow = row[j] + numberTotal;
+                                   kRow = permuteInverse_[kRow];
+                                   if (kRow < iRow)
+                                        Arow[sizeFactor_++] = kRow;
+                              }
+                         } else if (iOriginalRow < numberTotal) {
+                              int kRow = permuteInverse_[iOriginalRow+numberRowsModel];
+                              if (kRow < iRow)
+                                   Arow[sizeFactor_++] = kRow;
+                         } else {
+                              int kRow = iOriginalRow - numberTotal;
+                              CoinBigIndex start = rowStart[kRow];
+                              CoinBigIndex end = rowStart[kRow] + rowLength[kRow];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = column[j];
+                                   int jNewRow = permuteInverse_[jRow];
+                                   if (jNewRow < iRow)
+                                        Arow[sizeFactor_++] = jNewRow;
+                              }
+                              // slack - should it be permute
+                              kRow = permuteInverse_[kRow+numberColumns];
+                              if (kRow < iRow)
+                                   Arow[sizeFactor_++] = kRow;
+                         }
+                         // Sort
+                         std::sort(Arow + Astart[iRow], Arow + sizeFactor_);
+                    }
+               } else {
+                    // quadratic
+                    // transpose
+                    CoinPackedMatrix quadraticT;
+                    quadraticT.reverseOrderedCopyOf(*quadratic);
+                    const int * columnQuadratic = quadraticT.getIndices();
+                    const CoinBigIndex * columnQuadraticStart = quadraticT.getVectorStarts();
+                    const int * columnQuadraticLength = quadraticT.getVectorLengths();
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         Astart[iRow] = sizeFactor_;
+                         int iOriginalRow = permute_[iRow];
+                         if (iOriginalRow < numberColumns) {
+                              // Quadratic bit
+                              CoinBigIndex j;
+                              for ( j = columnQuadraticStart[iOriginalRow];
+                                        j < columnQuadraticStart[iOriginalRow] + columnQuadraticLength[iOriginalRow]; j++) {
+                                   int jColumn = columnQuadratic[j];
+                                   int jNewColumn = permuteInverse_[jColumn];
+                                   if (jNewColumn < iRow)
+                                        Arow[sizeFactor_++] = jNewColumn;
+                              }
+                              // A may be upper triangular by mistake
+                              iColumn = iOriginalRow;
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (j = start; j < end; j++) {
+                                   int kRow = row[j] + numberTotal;
+                                   kRow = permuteInverse_[kRow];
+                                   if (kRow < iRow)
+                                        Arow[sizeFactor_++] = kRow;
+                              }
+                         } else if (iOriginalRow < numberTotal) {
+                              int kRow = permuteInverse_[iOriginalRow+numberRowsModel];
+                              if (kRow < iRow)
+                                   Arow[sizeFactor_++] = kRow;
+                         } else {
+                              int kRow = iOriginalRow - numberTotal;
+                              CoinBigIndex start = rowStart[kRow];
+                              CoinBigIndex end = rowStart[kRow] + rowLength[kRow];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = column[j];
+                                   int jNewRow = permuteInverse_[jRow];
+                                   if (jNewRow < iRow)
+                                        Arow[sizeFactor_++] = jNewRow;
+                              }
+                              // slack - should it be permute
+                              kRow = permuteInverse_[kRow+numberColumns];
+                              if (kRow < iRow)
+                                   Arow[sizeFactor_++] = kRow;
+                         }
+                         // Sort
+                         std::sort(Arow + Astart[iRow], Arow + sizeFactor_);
+                    }
+               }
+          } else {
+               if (!quadratic) {
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         Astart[iRow] = sizeFactor_;
+                    }
+               } else {
+                    // Quadratic
+                    // transpose
+                    CoinPackedMatrix quadraticT;
+                    quadraticT.reverseOrderedCopyOf(*quadratic);
+                    const int * columnQuadratic = quadraticT.getIndices();
+                    const CoinBigIndex * columnQuadraticStart = quadraticT.getVectorStarts();
+                    const int * columnQuadraticLength = quadraticT.getVectorLengths();
+                    //const double * quadraticElement = quadraticT.getElements();
+                    for (iRow = 0; iRow < numberColumns; iRow++) {
+                         int iOriginalRow = permute_[iRow];
+                         Astart[iRow] = sizeFactor_;
+                         for (CoinBigIndex j = columnQuadraticStart[iOriginalRow];
+                                   j < columnQuadraticStart[iOriginalRow] + columnQuadraticLength[iOriginalRow]; j++) {
+                              int jColumn = columnQuadratic[j];
+                              int jNewColumn = permuteInverse_[jColumn];
+                              if (jNewColumn < iRow)
+                                   Arow[sizeFactor_++] = jNewColumn;
+                         }
+                    }
+               }
+               int iRow;
+               // slacks
+               for (iRow = 0; iRow < numberRowsModel; iRow++) {
+                    Astart[iRow+numberColumns] = sizeFactor_;
+               }
+               for (iRow = 0; iRow < numberRowsModel; iRow++) {
+                    Astart[iRow+numberTotal] = sizeFactor_;
+                    CoinBigIndex start = rowStart[iRow];
+                    CoinBigIndex end = rowStart[iRow] + rowLength[iRow];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         Arow[sizeFactor_++] = column[j];
+                    }
+                    // slack
+                    Arow[sizeFactor_++] = numberColumns + iRow;
+               }
+          }
+          delete rowCopy;
+     }
+     Astart[numberRows_] = sizeFactor_;
+     firstDense_ = numberRows_;
+     symbolic1(Astart, Arow);
+     // Now fill in indices
+     try {
+          // too big
+          choleskyRow_ = new int[sizeFactor_];
+     } catch (...) {
+          // no memory
+          noMemory = true;
+     }
+     double sizeFactor = sizeFactor_;
+     if (!noMemory) {
+          // Do lower triangular
+          sizeFactor_ = 0;
+          int * which = Arow;
+          if (!doKKT_) {
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int number = 0;
+                    int iOriginalRow = permute_[iRow];
+                    Astart[iRow] = sizeFactor_;
+                    if (!rowsDropped_[iOriginalRow]) {
+                         CoinBigIndex startRow = rowStart[iOriginalRow];
+                         CoinBigIndex endRow = rowStart[iOriginalRow] + rowLength[iOriginalRow];
+                         for (CoinBigIndex k = startRow; k < endRow; k++) {
+                              int iColumn = column[k];
+                              if (!whichDense_ || !whichDense_[iColumn]) {
+                                   CoinBigIndex start = columnStart[iColumn];
+                                   CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                                   for (CoinBigIndex j = start; j < end; j++) {
+                                        int jRow = row[j];
+                                        int jNewRow = permuteInverse_[jRow];
+                                        if (jNewRow > iRow && !rowsDropped_[jRow]) {
+                                             if (!used[jNewRow]) {
+                                                  used[jNewRow] = 1;
+                                                  which[number++] = jNewRow;
+                                             }
+                                        }
+                                   }
+                              }
+                         }
+                         sizeFactor_ += number;
+                         int j;
+                         for (j = 0; j < number; j++)
+                              used[which[j]] = 0;
+                         // Sort
+                         std::sort(which, which + number);
+                         // move which on
+                         which += number;
+                    }
+               }
+          } else {
+               // KKT
+               // temp
+               bool permuted = false;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    if (permute_[iRow] != iRow) {
+                         permuted = true;
+                         break;
+                    }
+               }
+               // but fake it
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    //permute_[iRow]=iRow; // force no permute
+                    //permuteInverse_[permute_[iRow]]=iRow;
+               }
+               if (permuted) {
+                    // Need to permute - ugly
+                    if (!quadratic) {
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              Astart[iRow] = sizeFactor_;
+                              int iOriginalRow = permute_[iRow];
+                              if (iOriginalRow < numberColumns) {
+                                   iColumn = iOriginalRow;
+                                   CoinBigIndex start = columnStart[iColumn];
+                                   CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                                   for (CoinBigIndex j = start; j < end; j++) {
+                                        int kRow = row[j] + numberTotal;
+                                        kRow = permuteInverse_[kRow];
+                                        if (kRow > iRow)
+                                             Arow[sizeFactor_++] = kRow;
+                                   }
+                              } else if (iOriginalRow < numberTotal) {
+                                   int kRow = permuteInverse_[iOriginalRow+numberRowsModel];
+                                   if (kRow > iRow)
+                                        Arow[sizeFactor_++] = kRow;
+                              } else {
+                                   int kRow = iOriginalRow - numberTotal;
+                                   CoinBigIndex start = rowStart[kRow];
+                                   CoinBigIndex end = rowStart[kRow] + rowLength[kRow];
+                                   for (CoinBigIndex j = start; j < end; j++) {
+                                        int jRow = column[j];
+                                        int jNewRow = permuteInverse_[jRow];
+                                        if (jNewRow > iRow)
+                                             Arow[sizeFactor_++] = jNewRow;
+                                   }
+                                   // slack - should it be permute
+                                   kRow = permuteInverse_[kRow+numberColumns];
+                                   if (kRow > iRow)
+                                        Arow[sizeFactor_++] = kRow;
+                              }
+                              // Sort
+                              std::sort(Arow + Astart[iRow], Arow + sizeFactor_);
+                         }
+                    } else {
+                         // quadratic
+                         const int * columnQuadratic = quadratic->getIndices();
+                         const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+                         const int * columnQuadraticLength = quadratic->getVectorLengths();
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              Astart[iRow] = sizeFactor_;
+                              int iOriginalRow = permute_[iRow];
+                              if (iOriginalRow < numberColumns) {
+                                   // Quadratic bit
+                                   CoinBigIndex j;
+                                   for ( j = columnQuadraticStart[iOriginalRow];
+                                             j < columnQuadraticStart[iOriginalRow] + columnQuadraticLength[iOriginalRow]; j++) {
+                                        int jColumn = columnQuadratic[j];
+                                        int jNewColumn = permuteInverse_[jColumn];
+                                        if (jNewColumn > iRow)
+                                             Arow[sizeFactor_++] = jNewColumn;
+                                   }
+                                   iColumn = iOriginalRow;
+                                   CoinBigIndex start = columnStart[iColumn];
+                                   CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                                   for (j = start; j < end; j++) {
+                                        int kRow = row[j] + numberTotal;
+                                        kRow = permuteInverse_[kRow];
+                                        if (kRow > iRow)
+                                             Arow[sizeFactor_++] = kRow;
+                                   }
+                              } else if (iOriginalRow < numberTotal) {
+                                   int kRow = permuteInverse_[iOriginalRow+numberRowsModel];
+                                   if (kRow > iRow)
+                                        Arow[sizeFactor_++] = kRow;
+                              } else {
+                                   int kRow = iOriginalRow - numberTotal;
+                                   CoinBigIndex start = rowStart[kRow];
+                                   CoinBigIndex end = rowStart[kRow] + rowLength[kRow];
+                                   for (CoinBigIndex j = start; j < end; j++) {
+                                        int jRow = column[j];
+                                        int jNewRow = permuteInverse_[jRow];
+                                        if (jNewRow > iRow)
+                                             Arow[sizeFactor_++] = jNewRow;
+                                   }
+                                   // slack - should it be permute
+                                   kRow = permuteInverse_[kRow+numberColumns];
+                                   if (kRow > iRow)
+                                        Arow[sizeFactor_++] = kRow;
+                              }
+                              // Sort
+                              std::sort(Arow + Astart[iRow], Arow + sizeFactor_);
+                         }
+                    }
+               } else {
+                    if (!quadratic) {
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              Astart[iColumn] = sizeFactor_;
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   Arow[sizeFactor_++] = row[j] + numberTotal;
+                              }
+                         }
+                    } else {
+                         // Quadratic
+                         const int * columnQuadratic = quadratic->getIndices();
+                         const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+                         const int * columnQuadraticLength = quadratic->getVectorLengths();
+                         //const double * quadraticElement = quadratic->getElements();
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              Astart[iColumn] = sizeFactor_;
+                              CoinBigIndex j;
+                              for ( j = columnQuadraticStart[iColumn];
+                                        j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                   int jColumn = columnQuadratic[j];
+                                   if (jColumn > iColumn)
+                                        Arow[sizeFactor_++] = jColumn;
+                              }
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for ( j = start; j < end; j++) {
+                                   Arow[sizeFactor_++] = row[j] + numberTotal;
+                              }
+                         }
+                    }
+                    // slacks
+                    for (iRow = 0; iRow < numberRowsModel; iRow++) {
+                         Astart[iRow+numberColumns] = sizeFactor_;
+                         Arow[sizeFactor_++] = iRow + numberTotal;
+                    }
+                    // Transpose - nonzero diagonal (may regularize)
+                    for (iRow = 0; iRow < numberRowsModel; iRow++) {
+                         Astart[iRow+numberTotal] = sizeFactor_;
+                    }
+               }
+               Astart[numberRows_] = sizeFactor_;
+          }
+          symbolic2(Astart, Arow);
+          if (sizeIndex_ < sizeFactor_) {
+               int * indices = NULL;
+               try {
+                    indices = new int[sizeIndex_];
+               } catch (...) {
+                    // no memory
+                    noMemory = true;
+               }
+               if (!noMemory)  {
+                    CoinMemcpyN(choleskyRow_, sizeIndex_, indices);
+                    delete [] choleskyRow_;
+                    choleskyRow_ = indices;
+               }
+          }
+     }
+     delete [] used;
+     // Use cholesky regions
+     delete [] Astart;
+     delete [] Arow;
+     double flops = 0.0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          int length = choleskyStart_[iRow+1] - choleskyStart_[iRow];
+          flops += static_cast<double> (length) * (length + 2.0);
+     }
+     if (model_->messageHandler()->logLevel() > 0)
+          std::cout << sizeFactor << " elements in sparse Cholesky, flop count " << flops << std::endl;
+     try {
+          sparseFactor_ = new longDouble [sizeFactor_];
+#if CLP_LONG_CHOLESKY!=1
+          workDouble_ = new longDouble[numberRows_];
+#else
+          // actually long double
+          workDouble_ = reinterpret_cast<double *> (new CoinWorkDouble[numberRows_]);
+#endif
+          diagonal_ = new longDouble[numberRows_];
+     } catch (...) {
+          // no memory
+          noMemory = true;
+     }
+     if (noMemory) {
+          delete [] choleskyRow_;
+          choleskyRow_ = NULL;
+          delete [] choleskyStart_;
+          choleskyStart_ = NULL;
+          delete [] permuteInverse_;
+          permuteInverse_ = NULL;
+          delete [] permute_;
+          permute_ = NULL;
+          delete [] choleskyStart_;
+          choleskyStart_ = NULL;
+          delete [] indexStart_;
+          indexStart_ = NULL;
+          delete [] link_;
+          link_ = NULL;
+          delete [] workInteger_;
+          workInteger_ = NULL;
+          delete [] sparseFactor_;
+          sparseFactor_ = NULL;
+          delete [] workDouble_;
+          workDouble_ = NULL;
+          delete [] diagonal_;
+          diagonal_ = NULL;
+          delete [] clique_;
+          clique_ = NULL;
+          return -1;
+     }
+     return 0;
+}
+int
+ClpCholeskyBase::symbolic1(const CoinBigIndex * Astart, const int * Arow)
+{
+     int * marked = reinterpret_cast<int *> (workInteger_);
+     int iRow;
+     // may not need to do this here but makes debugging easier
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          marked[iRow] = -1;
+          link_[iRow] = -1;
+          choleskyStart_[iRow] = 0; // counts
+     }
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          marked[iRow] = iRow;
+          for (CoinBigIndex j = Astart[iRow]; j < Astart[iRow+1]; j++) {
+               int kRow = Arow[j];
+               while (marked[kRow] != iRow ) {
+                    if (link_[kRow] < 0 )
+                         link_[kRow] = iRow;
+                    choleskyStart_[kRow]++;
+                    marked[kRow] = iRow;
+                    kRow = link_[kRow];
+               }
+          }
+     }
+     sizeFactor_ = 0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          int number = choleskyStart_[iRow];
+          choleskyStart_[iRow] = sizeFactor_;
+          sizeFactor_ += number;
+     }
+     choleskyStart_[numberRows_] = sizeFactor_;
+     return sizeFactor_;;
+}
+void
+ClpCholeskyBase::symbolic2(const CoinBigIndex * Astart, const int * Arow)
+{
+     int * mergeLink = clique_;
+     int * marker = reinterpret_cast<int *> (workInteger_);
+     int iRow;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          marker[iRow] = -1;
+          mergeLink[iRow] = -1;
+          link_[iRow] = -1; // not needed but makes debugging easier
+     }
+     int start = 0;
+     int end = 0;
+     choleskyStart_[0] = 0;
+
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          int nz = 0;
+          int merge = mergeLink[iRow];
+          bool marked = false;
+          if (merge < 0)
+               marker[iRow] = iRow;
+          else
+               marker[iRow] = merge;
+          start = end;
+          int startSub = start;
+          link_[iRow] = numberRows_;
+          CoinBigIndex j;
+          for ( j = Astart[iRow]; j < Astart[iRow+1]; j++) {
+               int kRow = Arow[j];
+               int k = iRow;
+               int linked = link_[iRow];
+#ifndef NDEBUG
+               int count = 0;
+#endif
+               while (linked <= kRow) {
+                    k = linked;
+                    linked = link_[k];
+#ifndef NDEBUG
+                    count++;
+                    assert (count < numberRows_);
+#endif
+               }
+               nz++;
+               link_[k] = kRow;
+               link_[kRow] = linked;
+               if (marker[kRow] != marker[iRow])
+                    marked = true;
+          }
+          bool reuse = false;
+          // Check if we can re-use indices
+          if (!marked && merge >= 0 && mergeLink[merge] < 0) {
+               // can re-use all
+               startSub = indexStart_[merge] + 1;
+               nz = choleskyStart_[merge+1] - (choleskyStart_[merge] + 1);
+               reuse = true;
+          } else {
+               // See if we can re-use any
+               int k = mergeLink[iRow];
+               int maxLength = 0;
+               while (k >= 0) {
+                    int length = choleskyStart_[k+1] - (choleskyStart_[k] + 1);
+                    int start = indexStart_[k] + 1;
+                    int stop = start + length;
+                    if (length > maxLength) {
+                         maxLength = length;
+                         startSub = start;
+                    }
+                    int linked = iRow;
+                    for (CoinBigIndex j = start; j < stop; j++) {
+                         int kRow = choleskyRow_[j];
+                         int kk = linked;
+                         linked = link_[kk];
+                         while (linked < kRow) {
+                              kk = linked;
+                              linked = link_[kk];
+                         }
+                         if (linked != kRow) {
+                              nz++;
+                              link_[kk] = kRow;
+                              link_[kRow] = linked;
+                              linked = kRow;
+                         }
+                    }
+                    k = mergeLink[k];
+               }
+               if (nz == maxLength)
+                    reuse = true; // can re-use
+          }
+          //reuse=false; //temp
+          if (!reuse) {
+               end += nz;
+               startSub = start;
+               int kRow = iRow;
+               for (int j = start; j < end; j++) {
+                    kRow = link_[kRow];
+                    choleskyRow_[j] = kRow;
+                    assert (kRow < numberRows_);
+                    marker[kRow] = iRow;
+               }
+               marker[iRow] = iRow;
+          }
+          indexStart_[iRow] = startSub;
+          choleskyStart_[iRow+1] = choleskyStart_[iRow] + nz;
+          if (nz > 1) {
+               int kRow = choleskyRow_[startSub];
+               mergeLink[iRow] = mergeLink[kRow];
+               mergeLink[kRow] = iRow;
+          }
+          // should not be needed
+          //std::sort(choleskyRow_+indexStart_[iRow]
+          //      ,choleskyRow_+indexStart_[iRow]+nz);
+          //#define CLP_DEBUG
+#ifdef CLP_DEBUG
+          int last = -1;
+          for ( j = indexStart_[iRow]; j < indexStart_[iRow] + nz; j++) {
+               int kRow = choleskyRow_[j];
+               assert (kRow > last);
+               last = kRow;
+          }
+#endif
+     }
+     sizeFactor_ = choleskyStart_[numberRows_];
+     sizeIndex_ = start;
+     // find dense segment here
+     int numberleft = numberRows_;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          CoinBigIndex left = sizeFactor_ - choleskyStart_[iRow];
+          double n = numberleft;
+          double threshold = n * (n - 1.0) * 0.5 * goDense_;
+          if ( left >= threshold)
+               break;
+          numberleft--;
+     }
+     //iRow=numberRows_;
+     int nDense = numberRows_ - iRow;
+#define DENSE_THRESHOLD 8
+     // don't do if dense columns
+     if (nDense >= DENSE_THRESHOLD && !dense_) {
+       COIN_DETAIL_PRINT(printf("Going dense for last %d rows\n", nDense));
+          // make sure we don't disturb any indices
+          CoinBigIndex k = 0;
+          for (int jRow = 0; jRow < iRow; jRow++) {
+               int nz = choleskyStart_[jRow+1] - choleskyStart_[jRow];
+               k = CoinMax(k, indexStart_[jRow] + nz);
+          }
+          indexStart_[iRow] = k;
+          int j;
+          for (j = iRow + 1; j < numberRows_; j++) {
+               choleskyRow_[k++] = j;
+               indexStart_[j] = k;
+          }
+          sizeIndex_ = k;
+          assert (k <= sizeFactor_); // can't happen with any reasonable defaults
+          k = choleskyStart_[iRow];
+          for (j = iRow + 1; j <= numberRows_; j++) {
+               k += numberRows_ - j;
+               choleskyStart_[j] = k;
+          }
+          // allow for blocked dense
+          ClpCholeskyDense dense;
+          sizeFactor_ = choleskyStart_[iRow] + dense.space(nDense);
+          firstDense_ = iRow;
+          if (doKKT_) {
+               // redo permute so negative ones first
+               int putN = firstDense_;
+               int putP = 0;
+               int numberRowsModel = model_->numberRows();
+               int numberColumns = model_->numberColumns();
+               int numberTotal = numberColumns + numberRowsModel;
+               for (iRow = firstDense_; iRow < numberRows_; iRow++) {
+                    int originalRow = permute_[iRow];
+                    if (originalRow < numberTotal)
+                         permute_[putN++] = originalRow;
+                    else
+                         permuteInverse_[putP++] = originalRow;
+               }
+               for (iRow = putN; iRow < numberRows_; iRow++) {
+                    permute_[iRow] = permuteInverse_[iRow-putN];
+               }
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    permuteInverse_[permute_[iRow]] = iRow;
+               }
+          }
+     }
+     // Clean up clique info
+     for (iRow = 0; iRow < numberRows_; iRow++)
+          clique_[iRow] = 0;
+     int lastClique = -1;
+     bool inClique = false;
+     for (iRow = 1; iRow < firstDense_; iRow++) {
+          int sizeLast = choleskyStart_[iRow] - choleskyStart_[iRow-1];
+          int sizeThis = choleskyStart_[iRow+1] - choleskyStart_[iRow];
+          if (indexStart_[iRow] == indexStart_[iRow-1] + 1 &&
+                    sizeThis == sizeLast - 1 &&
+                    sizeThis) {
+               // in clique
+               if (!inClique) {
+                    inClique = true;
+                    lastClique = iRow - 1;
+               }
+          } else if (inClique) {
+               int sizeClique = iRow - lastClique;
+               for (int i = lastClique; i < iRow; i++) {
+                    clique_[i] = sizeClique;
+                    sizeClique--;
+               }
+               inClique = false;
+          }
+     }
+     if (inClique) {
+          int sizeClique = iRow - lastClique;
+          for (int i = lastClique; i < iRow; i++) {
+               clique_[i] = sizeClique;
+               sizeClique--;
+          }
+     }
+     //for (iRow=0;iRow<numberRows_;iRow++)
+     //clique_[iRow]=0;
+}
+/* Factorize - filling in rowsDropped and returning number dropped */
+int
+ClpCholeskyBase::factorize(const CoinWorkDouble * diagonal, int * rowsDropped)
+{
+     const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts();
+     const int * columnLength = model_->clpMatrix()->getVectorLengths();
+     const int * row = model_->clpMatrix()->getIndices();
+     const double * element = model_->clpMatrix()->getElements();
+     const CoinBigIndex * rowStart = rowCopy_->getVectorStarts();
+     const int * rowLength = rowCopy_->getVectorLengths();
+     const int * column = rowCopy_->getIndices();
+     const double * elementByRow = rowCopy_->getElements();
+     int numberColumns = model_->clpMatrix()->getNumCols();
+     //perturbation
+     CoinWorkDouble perturbation = model_->diagonalPerturbation() * model_->diagonalNorm();
+     //perturbation=perturbation*perturbation*100000000.0;
+     if (perturbation > 1.0) {
+#ifdef COIN_DEVELOP
+          //if (model_->model()->logLevel()&4)
+          std::cout << "large perturbation " << perturbation << std::endl;
+#endif
+          perturbation = CoinSqrt(perturbation);
+          perturbation = 1.0;
+     }
+     int iRow;
+     int iColumn;
+     longDouble * work = workDouble_;
+     CoinZeroN(work, numberRows_);
+     int newDropped = 0;
+     CoinWorkDouble largest = 1.0;
+     CoinWorkDouble smallest = COIN_DBL_MAX;
+     int numberDense = 0;
+     if (!doKKT_) {
+          const CoinWorkDouble * diagonalSlack = diagonal + numberColumns;
+          if (dense_)
+               numberDense = dense_->numberRows();
+          if (whichDense_) {
+               longDouble * denseDiagonal = dense_->diagonal();
+               longDouble * dense = denseColumn_;
+               int iDense = 0;
+               for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (whichDense_[iColumn]) {
+                         CoinZeroN(dense, numberRows_);
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                         if (diagonal[iColumn]) {
+                              denseDiagonal[iDense++] = 1.0 / diagonal[iColumn];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = row[j];
+                                   dense[jRow] = element[j];
+                              }
+                         } else {
+                              denseDiagonal[iDense++] = 1.0;
+                         }
+                         dense += numberRows_;
+                    }
+               }
+          }
+          CoinWorkDouble delta2 = model_->delta(); // add delta*delta to diagonal
+          delta2 *= delta2;
+          // largest in initial matrix
+          CoinWorkDouble largest2 = 1.0e-20;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               longDouble * put = sparseFactor_ + choleskyStart_[iRow];
+               int * which = choleskyRow_ + indexStart_[iRow];
+               int iOriginalRow = permute_[iRow];
+               int number = choleskyStart_[iRow+1] - choleskyStart_[iRow];
+               if (!rowLength[iOriginalRow])
+                    rowsDropped_[iOriginalRow] = 1;
+               if (!rowsDropped_[iOriginalRow]) {
+                    CoinBigIndex startRow = rowStart[iOriginalRow];
+                    CoinBigIndex endRow = rowStart[iOriginalRow] + rowLength[iOriginalRow];
+                    work[iRow] = diagonalSlack[iOriginalRow] + delta2;
+                    for (CoinBigIndex k = startRow; k < endRow; k++) {
+                         int iColumn = column[k];
+                         if (!whichDense_ || !whichDense_[iColumn]) {
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              CoinWorkDouble multiplier = diagonal[iColumn] * elementByRow[k];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = row[j];
+                                   int jNewRow = permuteInverse_[jRow];
+                                   if (jNewRow >= iRow && !rowsDropped_[jRow]) {
+                                        CoinWorkDouble value = element[j] * multiplier;
+                                        work[jNewRow] += value;
+                                   }
+                              }
+                         }
+                    }
+                    diagonal_[iRow] = work[iRow];
+                    largest2 = CoinMax(largest2, CoinAbs(work[iRow]));
+                    work[iRow] = 0.0;
+                    int j;
+                    for (j = 0; j < number; j++) {
+                         int jRow = which[j];
+                         put[j] = work[jRow];
+                         largest2 = CoinMax(largest2, CoinAbs(work[jRow]));
+                         work[jRow] = 0.0;
+                    }
+               } else {
+                    // dropped
+                    diagonal_[iRow] = 1.0;
+                    int j;
+                    for (j = 1; j < number; j++) {
+                         put[j] = 0.0;
+                    }
+               }
+          }
+          //check sizes
+          largest2 *= 1.0e-20;
+          largest = CoinMin(largest2, CHOL_SMALL_VALUE);
+          int numberDroppedBefore = 0;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int dropped = rowsDropped_[iRow];
+               // Move to int array
+               rowsDropped[iRow] = dropped;
+               if (!dropped) {
+                    CoinWorkDouble diagonal = diagonal_[iRow];
+                    if (diagonal > largest2) {
+                         diagonal_[iRow] = diagonal + perturbation;
+                    } else {
+                         diagonal_[iRow] = diagonal + perturbation;
+                         rowsDropped[iRow] = 2;
+                         numberDroppedBefore++;
+                         //printf("dropped - small diagonal %g\n",diagonal);
+                    }
+               }
+          }
+          doubleParameters_[10] = CoinMax(1.0e-20, largest);
+          integerParameters_[20] = 0;
+          doubleParameters_[3] = 0.0;
+          doubleParameters_[4] = COIN_DBL_MAX;
+          integerParameters_[34] = 0; // say all must be positive
+          factorizePart2(rowsDropped);
+          newDropped = integerParameters_[20] + numberDroppedBefore;
+          largest = doubleParameters_[3];
+          smallest = doubleParameters_[4];
+          if (model_->messageHandler()->logLevel() > 1)
+               std::cout << "Cholesky - largest " << largest << " smallest " << smallest << std::endl;
+          choleskyCondition_ = largest / smallest;
+          if (whichDense_) {
+               int i;
+               for ( i = 0; i < numberRows_; i++) {
+                    assert (diagonal_[i] >= 0.0);
+                    diagonal_[i] = CoinSqrt(diagonal_[i]);
+               }
+               // Update dense columns (just L)
+               // Zero out dropped rows
+               for (i = 0; i < numberDense; i++) {
+                    longDouble * a = denseColumn_ + i * numberRows_;
+                    for (int j = 0; j < numberRows_; j++) {
+                         if (rowsDropped[j])
+                              a[j] = 0.0;
+                    }
+                    for (i = 0; i < numberRows_; i++) {
+                         int iRow = permute_[i];
+                         workDouble_[i] = a[iRow];
+                    }
+                    for (i = 0; i < numberRows_; i++) {
+                         CoinWorkDouble value = workDouble_[i];
+                         CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+                         CoinBigIndex j;
+                         for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+                              int iRow = choleskyRow_[j+offset];
+                              workDouble_[iRow] -= sparseFactor_[j] * value;
+                         }
+                    }
+                    for (i = 0; i < numberRows_; i++) {
+                         int iRow = permute_[i];
+                         a[iRow] = workDouble_[i] * diagonal_[i];
+                    }
+               }
+               dense_->resetRowsDropped();
+               longDouble * denseBlob = dense_->aMatrix();
+               longDouble * denseDiagonal = dense_->diagonal();
+               // Update dense matrix
+               for (i = 0; i < numberDense; i++) {
+                    const longDouble * a = denseColumn_ + i * numberRows_;
+                    // do diagonal
+                    CoinWorkDouble value = denseDiagonal[i];
+                    const longDouble * b = denseColumn_ + i * numberRows_;
+                    for (int k = 0; k < numberRows_; k++)
+                         value += a[k] * b[k];
+                    denseDiagonal[i] = value;
+                    for (int j = i + 1; j < numberDense; j++) {
+                         CoinWorkDouble value = 0.0;
+                         const longDouble * b = denseColumn_ + j * numberRows_;
+                         for (int k = 0; k < numberRows_; k++)
+                              value += a[k] * b[k];
+                         *denseBlob = value;
+                         denseBlob++;
+                    }
+               }
+               // dense cholesky (? long double)
+               int * dropped = new int [numberDense];
+               dense_->factorizePart2(dropped);
+               delete [] dropped;
+          }
+          // try allowing all every time
+          //printf("trying ?\n");
+          //for (iRow=0;iRow<numberRows_;iRow++) {
+          //rowsDropped[iRow]=0;
+          //rowsDropped_[iRow]=0;
+          //}
+          bool cleanCholesky;
+          //if (model_->numberIterations()<20||(model_->numberIterations()&1)==0)
+          if (model_->numberIterations() < 2000)
+               cleanCholesky = true;
+          else
+               cleanCholesky = false;
+          if (cleanCholesky) {
+               //drop fresh makes some formADAT easier
+               if (newDropped || numberRowsDropped_) {
+                    newDropped = 0;
+                    for (int i = 0; i < numberRows_; i++) {
+                         char dropped = static_cast<char>(rowsDropped[i]);
+                         rowsDropped_[i] = dropped;
+                         rowsDropped_[i] = 0;
+                         if (dropped == 2) {
+                              //dropped this time
+                              rowsDropped[newDropped++] = i;
+                              rowsDropped_[i] = 0;
+                         }
+                    }
+                    numberRowsDropped_ = newDropped;
+                    newDropped = -(2 + newDropped);
+               }
+          } else {
+               if (newDropped) {
+                    newDropped = 0;
+                    for (int i = 0; i < numberRows_; i++) {
+                         char dropped = static_cast<char>(rowsDropped[i]);
+                         rowsDropped_[i] = dropped;
+                         if (dropped == 2) {
+                              //dropped this time
+                              rowsDropped[newDropped++] = i;
+                              rowsDropped_[i] = 1;
+                         }
+                    }
+               }
+               numberRowsDropped_ += newDropped;
+               if (numberRowsDropped_ && 0) {
+                    std::cout << "Rank " << numberRows_ - numberRowsDropped_ << " ( " <<
+                              numberRowsDropped_ << " dropped)";
+                    if (newDropped) {
+                         std::cout << " ( " << newDropped << " dropped this time)";
+                    }
+                    std::cout << std::endl;
+               }
+          }
+     } else {
+          //KKT
+          CoinPackedMatrix * quadratic = NULL;
+          ClpQuadraticObjective * quadraticObj =
+               (dynamic_cast< ClpQuadraticObjective*>(model_->objectiveAsObject()));
+          if (quadraticObj)
+               quadratic = quadraticObj->quadraticObjective();
+          // matrix
+          int numberRowsModel = model_->numberRows();
+          int numberColumns = model_->numberColumns();
+          int numberTotal = numberColumns + numberRowsModel;
+          // temp
+          bool permuted = false;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if (permute_[iRow] != iRow) {
+                    permuted = true;
+                    break;
+               }
+          }
+          // but fake it
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               //permute_[iRow]=iRow; // force no permute
+               //permuteInverse_[permute_[iRow]]=iRow;
+          }
+          if (permuted) {
+               CoinWorkDouble delta2 = model_->delta(); // add delta*delta to bottom
+               delta2 *= delta2;
+               // Need to permute - ugly
+               if (!quadratic) {
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         longDouble * put = sparseFactor_ + choleskyStart_[iRow];
+                         int * which = choleskyRow_ + indexStart_[iRow];
+                         int iOriginalRow = permute_[iRow];
+                         if (iOriginalRow < numberColumns) {
+                              iColumn = iOriginalRow;
+                              CoinWorkDouble value = diagonal[iColumn];
+                              if (CoinAbs(value) > 1.0e-100) {
+                                   value = 1.0 / value;
+                                   largest = CoinMax(largest, CoinAbs(value));
+                                   diagonal_[iRow] = -value;
+                                   CoinBigIndex start = columnStart[iColumn];
+                                   CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                                   for (CoinBigIndex j = start; j < end; j++) {
+                                        int kRow = row[j] + numberTotal;
+                                        kRow = permuteInverse_[kRow];
+                                        if (kRow > iRow) {
+                                             work[kRow] = element[j];
+                                             largest = CoinMax(largest, CoinAbs(element[j]));
+                                        }
+                                   }
+                              } else {
+                                   diagonal_[iRow] = -value;
+                              }
+                         } else if (iOriginalRow < numberTotal) {
+                              CoinWorkDouble value = diagonal[iOriginalRow];
+                              if (CoinAbs(value) > 1.0e-100) {
+                                   value = 1.0 / value;
+                                   largest = CoinMax(largest, CoinAbs(value));
+                              } else {
+                                   value = 1.0e100;
+                              }
+                              diagonal_[iRow] = -value;
+                              int kRow = permuteInverse_[iOriginalRow+numberRowsModel];
+                              if (kRow > iRow)
+                                   work[kRow] = -1.0;
+                         } else {
+                              diagonal_[iRow] = delta2;
+                              int kRow = iOriginalRow - numberTotal;
+                              CoinBigIndex start = rowStart[kRow];
+                              CoinBigIndex end = rowStart[kRow] + rowLength[kRow];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = column[j];
+                                   int jNewRow = permuteInverse_[jRow];
+                                   if (jNewRow > iRow) {
+                                        work[jNewRow] = elementByRow[j];
+                                        largest = CoinMax(largest, CoinAbs(elementByRow[j]));
+                                   }
+                              }
+                              // slack - should it be permute
+                              kRow = permuteInverse_[kRow+numberColumns];
+                              if (kRow > iRow)
+                                   work[kRow] = -1.0;
+                         }
+                         CoinBigIndex j;
+                         int number = choleskyStart_[iRow+1] - choleskyStart_[iRow];
+                         for (j = 0; j < number; j++) {
+                              int jRow = which[j];
+                              put[j] = work[jRow];
+                              work[jRow] = 0.0;
+                         }
+                    }
+               } else {
+                    // quadratic
+                    const int * columnQuadratic = quadratic->getIndices();
+                    const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+                    const int * columnQuadraticLength = quadratic->getVectorLengths();
+                    const double * quadraticElement = quadratic->getElements();
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         longDouble * put = sparseFactor_ + choleskyStart_[iRow];
+                         int * which = choleskyRow_ + indexStart_[iRow];
+                         int iOriginalRow = permute_[iRow];
+                         if (iOriginalRow < numberColumns) {
+                              CoinBigIndex j;
+                              iColumn = iOriginalRow;
+                              CoinWorkDouble value = diagonal[iColumn];
+                              if (CoinAbs(value) > 1.0e-100) {
+                                   value = 1.0 / value;
+                                   for (j = columnQuadraticStart[iColumn];
+                                             j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                        int jColumn = columnQuadratic[j];
+                                        int jNewColumn = permuteInverse_[jColumn];
+                                        if (jNewColumn > iRow) {
+                                             work[jNewColumn] = -quadraticElement[j];
+                                        } else if (iColumn == jColumn) {
+                                             value += quadraticElement[j];
+                                        }
+                                   }
+                                   largest = CoinMax(largest, CoinAbs(value));
+                                   diagonal_[iRow] = -value;
+                                   CoinBigIndex start = columnStart[iColumn];
+                                   CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                                   for (j = start; j < end; j++) {
+                                        int kRow = row[j] + numberTotal;
+                                        kRow = permuteInverse_[kRow];
+                                        if (kRow > iRow) {
+                                             work[kRow] = element[j];
+                                             largest = CoinMax(largest, CoinAbs(element[j]));
+                                        }
+                                   }
+                              } else {
+                                   diagonal_[iRow] = -value;
+                              }
+                         } else if (iOriginalRow < numberTotal) {
+                              CoinWorkDouble value = diagonal[iOriginalRow];
+                              if (CoinAbs(value) > 1.0e-100) {
+                                   value = 1.0 / value;
+                                   largest = CoinMax(largest, CoinAbs(value));
+                              } else {
+                                   value = 1.0e100;
+                              }
+                              diagonal_[iRow] = -value;
+                              int kRow = permuteInverse_[iOriginalRow+numberRowsModel];
+                              if (kRow > iRow)
+                                   work[kRow] = -1.0;
+                         } else {
+                              diagonal_[iRow] = delta2;
+                              int kRow = iOriginalRow - numberTotal;
+                              CoinBigIndex start = rowStart[kRow];
+                              CoinBigIndex end = rowStart[kRow] + rowLength[kRow];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   int jRow = column[j];
+                                   int jNewRow = permuteInverse_[jRow];
+                                   if (jNewRow > iRow) {
+                                        work[jNewRow] = elementByRow[j];
+                                        largest = CoinMax(largest, CoinAbs(elementByRow[j]));
+                                   }
+                              }
+                              // slack - should it be permute
+                              kRow = permuteInverse_[kRow+numberColumns];
+                              if (kRow > iRow)
+                                   work[kRow] = -1.0;
+                         }
+                         CoinBigIndex j;
+                         int number = choleskyStart_[iRow+1] - choleskyStart_[iRow];
+                         for (j = 0; j < number; j++) {
+                              int jRow = which[j];
+                              put[j] = work[jRow];
+                              work[jRow] = 0.0;
+                         }
+                         for (j = 0; j < numberRows_; j++)
+                              assert (!work[j]);
+                    }
+               }
+          } else {
+               if (!quadratic) {
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         longDouble * put = sparseFactor_ + choleskyStart_[iColumn];
+                         int * which = choleskyRow_ + indexStart_[iColumn];
+                         CoinWorkDouble value = diagonal[iColumn];
+                         if (CoinAbs(value) > 1.0e-100) {
+                              value = 1.0 / value;
+                              largest = CoinMax(largest, CoinAbs(value));
+                              diagonal_[iColumn] = -value;
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (CoinBigIndex j = start; j < end; j++) {
+                                   //choleskyRow_[numberElements]=row[j]+numberTotal;
+                                   //sparseFactor_[numberElements++]=element[j];
+                                   work[row[j] + numberTotal] = element[j];
+                                   largest = CoinMax(largest, CoinAbs(element[j]));
+                              }
+                         } else {
+                              diagonal_[iColumn] = -value;
+                         }
+                         CoinBigIndex j;
+                         int number = choleskyStart_[iColumn+1] - choleskyStart_[iColumn];
+                         for (j = 0; j < number; j++) {
+                              int jRow = which[j];
+                              put[j] = work[jRow];
+                              work[jRow] = 0.0;
+                         }
+                    }
+               } else {
+                    // Quadratic
+                    const int * columnQuadratic = quadratic->getIndices();
+                    const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+                    const int * columnQuadraticLength = quadratic->getVectorLengths();
+                    const double * quadraticElement = quadratic->getElements();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         longDouble * put = sparseFactor_ + choleskyStart_[iColumn];
+                         int * which = choleskyRow_ + indexStart_[iColumn];
+                         int number = choleskyStart_[iColumn+1] - choleskyStart_[iColumn];
+                         CoinWorkDouble value = diagonal[iColumn];
+                         CoinBigIndex j;
+                         if (CoinAbs(value) > 1.0e-100) {
+                              value = 1.0 / value;
+                              for (j = columnQuadraticStart[iColumn];
+                                        j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                   int jColumn = columnQuadratic[j];
+                                   if (jColumn > iColumn) {
+                                        work[jColumn] = -quadraticElement[j];
+                                   } else if (iColumn == jColumn) {
+                                        value += quadraticElement[j];
+                                   }
+                              }
+                              largest = CoinMax(largest, CoinAbs(value));
+                              diagonal_[iColumn] = -value;
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                              for (j = start; j < end; j++) {
+                                   work[row[j] + numberTotal] = element[j];
+                                   largest = CoinMax(largest, CoinAbs(element[j]));
+                              }
+                              for (j = 0; j < number; j++) {
+                                   int jRow = which[j];
+                                   put[j] = work[jRow];
+                                   work[jRow] = 0.0;
+                              }
+                         } else {
+                              value = 1.0e100;
+                              diagonal_[iColumn] = -value;
+                              for (j = 0; j < number; j++) {
+                                   int jRow = which[j];
+                                   put[j] = work[jRow];
+                              }
+                         }
+                    }
+               }
+               // slacks
+               for (iColumn = numberColumns; iColumn < numberTotal; iColumn++) {
+                    longDouble * put = sparseFactor_ + choleskyStart_[iColumn];
+                    int * which = choleskyRow_ + indexStart_[iColumn];
+                    CoinWorkDouble value = diagonal[iColumn];
+                    if (CoinAbs(value) > 1.0e-100) {
+                         value = 1.0 / value;
+                         largest = CoinMax(largest, CoinAbs(value));
+                    } else {
+                         value = 1.0e100;
+                    }
+                    diagonal_[iColumn] = -value;
+                    work[iColumn-numberColumns+numberTotal] = -1.0;
+                    CoinBigIndex j;
+                    int number = choleskyStart_[iColumn+1] - choleskyStart_[iColumn];
+                    for (j = 0; j < number; j++) {
+                         int jRow = which[j];
+                         put[j] = work[jRow];
+                         work[jRow] = 0.0;
+                    }
+               }
+               // Finish diagonal
+               CoinWorkDouble delta2 = model_->delta(); // add delta*delta to bottom
+               delta2 *= delta2;
+               for (iRow = 0; iRow < numberRowsModel; iRow++) {
+                    longDouble * put = sparseFactor_ + choleskyStart_[iRow+numberTotal];
+                    diagonal_[iRow+numberTotal] = delta2;
+                    CoinBigIndex j;
+                    int number = choleskyStart_[iRow+numberTotal+1] - choleskyStart_[iRow+numberTotal];
+                    for (j = 0; j < number; j++) {
+                         put[j] = 0.0;
+                    }
+               }
+          }
+          //check sizes
+          largest *= 1.0e-20;
+          largest = CoinMin(largest, CHOL_SMALL_VALUE);
+          doubleParameters_[10] = CoinMax(1.0e-20, largest);
+          integerParameters_[20] = 0;
+          doubleParameters_[3] = 0.0;
+          doubleParameters_[4] = COIN_DBL_MAX;
+          // Set up LDL cutoff
+          integerParameters_[34] = numberTotal;
+          // KKT
+          int * rowsDropped2 = new int[numberRows_];
+          CoinZeroN(rowsDropped2, numberRows_);
+          factorizePart2(rowsDropped2);
+          newDropped = integerParameters_[20];
+          largest = doubleParameters_[3];
+          smallest = doubleParameters_[4];
+          if (model_->messageHandler()->logLevel() > 1)
+               std::cout << "Cholesky - largest " << largest << " smallest " << smallest << std::endl;
+          choleskyCondition_ = largest / smallest;
+          // Should save adjustments in ..R_
+          int n1 = 0, n2 = 0;
+          CoinWorkDouble * primalR = model_->primalR();
+          CoinWorkDouble * dualR = model_->dualR();
+          for (iRow = 0; iRow < numberTotal; iRow++) {
+               if (rowsDropped2[iRow]) {
+                    n1++;
+                    //printf("row region1 %d dropped\n",iRow);
+                    //rowsDropped_[iRow]=1;
+                    rowsDropped_[iRow] = 0;
+                    primalR[iRow] = doubleParameters_[20];
+               } else {
+                    rowsDropped_[iRow] = 0;
+                    primalR[iRow] = 0.0;
+               }
+          }
+          for (; iRow < numberRows_; iRow++) {
+               if (rowsDropped2[iRow]) {
+                    n2++;
+                    //printf("row region2 %d dropped\n",iRow);
+                    //rowsDropped_[iRow]=1;
+                    rowsDropped_[iRow] = 0;
+                    dualR[iRow-numberTotal] = doubleParameters_[34];
+               } else {
+                    rowsDropped_[iRow] = 0;
+                    dualR[iRow-numberTotal] = 0.0;
+               }
+          }
+          delete [] rowsDropped2;
+     }
+     status_ = 0;
+     return newDropped;
+}
+/* Factorize - filling in rowsDropped and returning number dropped
+   in integerParam.
+*/
+void
+ClpCholeskyBase::factorizePart2(int * rowsDropped)
+{
+     CoinWorkDouble largest = doubleParameters_[3];
+     CoinWorkDouble smallest = doubleParameters_[4];
+     // probably done before
+     largest = 0.0;
+     smallest = COIN_DBL_MAX;
+     double dropValue = doubleParameters_[10];
+     int firstPositive = integerParameters_[34];
+     longDouble * d = ClpCopyOfArray(diagonal_, numberRows_);
+     int iRow;
+     // minimum size before clique done
+     //#define MINCLIQUE INT_MAX
+#define MINCLIQUE 3
+     longDouble * work = workDouble_;
+     CoinBigIndex * first = workInteger_;
+
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          link_[iRow] = -1;
+          work[iRow] = 0.0;
+          first[iRow] = choleskyStart_[iRow];
+     }
+
+     int lastClique = -1;
+     bool inClique = false;
+     bool newClique = false;
+     bool endClique = false;
+     int lastRow = 0;
+     int nextRow2 = -1;
+
+     for (iRow = 0; iRow < firstDense_ + 1; iRow++) {
+          if (iRow < firstDense_) {
+               endClique = false;
+               if (clique_[iRow] > 0) {
+                    // this is in a clique
+                    inClique = true;
+                    if (clique_[iRow] > lastClique) {
+                         // new Clique
+                         newClique = true;
+                         // If we have clique going then signal to do old one
+                         endClique = (lastClique > 0);
+                    } else {
+                         // Still in clique
+                         newClique = false;
+                    }
+               } else {
+                    // not in clique
+                    inClique = false;
+                    newClique = false;
+                    // If we have clique going then signal to do old one
+                    endClique = (lastClique > 0);
+               }
+               lastClique = clique_[iRow];
+          } else if (inClique) {
+               // Finish off
+               endClique = true;
+          } else {
+               break;
+          }
+          if (endClique) {
+               // We have just finished updating a clique - do block pivot and clean up
+               int jRow;
+               for ( jRow = lastRow; jRow < iRow; jRow++) {
+                    int jCount = jRow - lastRow;
+                    CoinWorkDouble diagonalValue = diagonal_[jRow];
+                    CoinBigIndex start = choleskyStart_[jRow];
+                    CoinBigIndex end = choleskyStart_[jRow+1];
+                    for (int kRow = lastRow; kRow < jRow; kRow++) {
+                         jCount--;
+                         CoinBigIndex get = choleskyStart_[kRow] + jCount;
+                         CoinWorkDouble a_jk = sparseFactor_[get];
+                         CoinWorkDouble value1 = d[kRow] * a_jk;
+                         diagonalValue -= a_jk * value1;
+                         for (CoinBigIndex j = start; j < end; j++)
+                              sparseFactor_[j] -= value1 * sparseFactor_[++get];
+                    }
+                    // check
+                    int originalRow = permute_[jRow];
+                    if (originalRow < firstPositive) {
+                         // must be negative
+                         if (diagonalValue <= -dropValue) {
+                              smallest = CoinMin(smallest, -diagonalValue);
+                              largest = CoinMax(largest, -diagonalValue);
+                              d[jRow] = diagonalValue;
+                              diagonalValue = 1.0 / diagonalValue;
+                         } else {
+                              rowsDropped[originalRow] = 2;
+                              d[jRow] = -1.0e100;
+                              diagonalValue = 0.0;
+                              integerParameters_[20]++;
+                         }
+                    } else {
+                         // must be positive
+                         if (diagonalValue >= dropValue) {
+                              smallest = CoinMin(smallest, diagonalValue);
+                              largest = CoinMax(largest, diagonalValue);
+                              d[jRow] = diagonalValue;
+                              diagonalValue = 1.0 / diagonalValue;
+                         } else {
+                              rowsDropped[originalRow] = 2;
+                              d[jRow] = 1.0e100;
+                              diagonalValue = 0.0;
+                              integerParameters_[20]++;
+                         }
+                    }
+                    diagonal_[jRow] = diagonalValue;
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         sparseFactor_[j] *= diagonalValue;
+                    }
+               }
+               if (nextRow2 >= 0) {
+                    for ( jRow = lastRow; jRow < iRow - 1; jRow++) {
+                         link_[jRow] = jRow + 1;
+                    }
+                    link_[iRow-1] = link_[nextRow2];
+                    link_[nextRow2] = lastRow;
+               }
+          }
+          if (iRow == firstDense_)
+               break; // we were just cleaning up
+          if (newClique) {
+               // initialize new clique
+               lastRow = iRow;
+          }
+          // for each column L[*,kRow] that affects L[*,iRow]
+          CoinWorkDouble diagonalValue = diagonal_[iRow];
+          int nextRow = link_[iRow];
+          int kRow = 0;
+          while (1) {
+               kRow = nextRow;
+               if (kRow < 0)
+                    break; // out of loop
+               nextRow = link_[kRow];
+               // Modify by outer product of L[*,irow] by L[*,krow] from first
+               CoinBigIndex k = first[kRow];
+               CoinBigIndex end = choleskyStart_[kRow+1];
+               assert(k < end);
+               CoinWorkDouble a_ik = sparseFactor_[k++];
+               CoinWorkDouble value1 = d[kRow] * a_ik;
+               // update first
+               first[kRow] = k;
+               diagonalValue -= value1 * a_ik;
+               CoinBigIndex offset = indexStart_[kRow] - choleskyStart_[kRow];
+               if (k < end) {
+                    int jRow = choleskyRow_[k+offset];
+                    if (clique_[kRow] < MINCLIQUE) {
+                         link_[kRow] = link_[jRow];
+                         link_[jRow] = kRow;
+                         for (; k < end; k++) {
+                              int jRow = choleskyRow_[k+offset];
+                              work[jRow] += sparseFactor_[k] * value1;
+                         }
+                    } else {
+                         // Clique
+                         CoinBigIndex currentIndex = k + offset;
+                         int linkSave = link_[jRow];
+                         link_[jRow] = kRow;
+                         work[kRow] = value1; // ? or a_jk
+                         int last = kRow + clique_[kRow];
+                         for (int kkRow = kRow + 1; kkRow < last; kkRow++) {
+                              CoinBigIndex j = first[kkRow];
+                              //int iiRow = choleskyRow_[j+indexStart_[kkRow]-choleskyStart_[kkRow]];
+                              CoinWorkDouble a = sparseFactor_[j];
+                              CoinWorkDouble dValue = d[kkRow] * a;
+                              diagonalValue -= a * dValue;
+                              work[kkRow] = dValue;
+                              first[kkRow]++;
+                              link_[kkRow-1] = kkRow;
+                         }
+                         nextRow = link_[last-1];
+                         link_[last-1] = linkSave;
+                         int length = end - k;
+                         for (int i = 0; i < length; i++) {
+                              int lRow = choleskyRow_[currentIndex++];
+                              CoinWorkDouble t0 = work[lRow];
+                              for (int kkRow = kRow; kkRow < last; kkRow++) {
+                                   CoinBigIndex j = first[kkRow] + i;
+                                   t0 += work[kkRow] * sparseFactor_[j];
+                              }
+                              work[lRow] = t0;
+                         }
+                    }
+               }
+          }
+          // Now apply
+          if (inClique) {
+               // in clique
+               diagonal_[iRow] = diagonalValue;
+               CoinBigIndex start = choleskyStart_[iRow];
+               CoinBigIndex end = choleskyStart_[iRow+1];
+               CoinBigIndex currentIndex = indexStart_[iRow];
+               nextRow2 = -1;
+               CoinBigIndex get = start + clique_[iRow] - 1;
+               if (get < end) {
+                    nextRow2 = choleskyRow_[currentIndex+get-start];
+                    first[iRow] = get;
+               }
+               for (CoinBigIndex j = start; j < end; j++) {
+                    int kRow = choleskyRow_[currentIndex++];
+                    sparseFactor_[j] -= work[kRow]; // times?
+                    work[kRow] = 0.0;
+               }
+          } else {
+               // not in clique
+               int originalRow = permute_[iRow];
+               if (originalRow < firstPositive) {
+                    // must be negative
+                    if (diagonalValue <= -dropValue) {
+                         smallest = CoinMin(smallest, -diagonalValue);
+                         largest = CoinMax(largest, -diagonalValue);
+                         d[iRow] = diagonalValue;
+                         diagonalValue = 1.0 / diagonalValue;
+                    } else {
+                         rowsDropped[originalRow] = 2;
+                         d[iRow] = -1.0e100;
+                         diagonalValue = 0.0;
+                         integerParameters_[20]++;
+                    }
+               } else {
+                    // must be positive
+                    if (diagonalValue >= dropValue) {
+                         smallest = CoinMin(smallest, diagonalValue);
+                         largest = CoinMax(largest, diagonalValue);
+                         d[iRow] = diagonalValue;
+                         diagonalValue = 1.0 / diagonalValue;
+                    } else {
+                         rowsDropped[originalRow] = 2;
+                         d[iRow] = 1.0e100;
+                         diagonalValue = 0.0;
+                         integerParameters_[20]++;
+                    }
+               }
+               diagonal_[iRow] = diagonalValue;
+               CoinBigIndex offset = indexStart_[iRow] - choleskyStart_[iRow];
+               CoinBigIndex start = choleskyStart_[iRow];
+               CoinBigIndex end = choleskyStart_[iRow+1];
+               assert (first[iRow] == start);
+               if (start < end) {
+                    int nextRow = choleskyRow_[start+offset];
+                    link_[iRow] = link_[nextRow];
+                    link_[nextRow] = iRow;
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         int jRow = choleskyRow_[j+offset];
+                         CoinWorkDouble value = sparseFactor_[j] - work[jRow];
+                         work[jRow] = 0.0;
+                         sparseFactor_[j] = diagonalValue * value;
+                    }
+               }
+          }
+     }
+     if (firstDense_ < numberRows_) {
+          // do dense
+          // update dense part
+          updateDense(d,/*work,*/first);
+          ClpCholeskyDense dense;
+          // just borrow space
+          int nDense = numberRows_ - firstDense_;
+          if (doKKT_) {
+               for (iRow = firstDense_; iRow < numberRows_; iRow++) {
+                    int originalRow = permute_[iRow];
+                    if (originalRow >= firstPositive) {
+                         firstPositive = iRow - firstDense_;
+                         break;
+                    }
+               }
+          }
+          dense.reserveSpace(this, nDense);
+          int * dropped = new int[nDense];
+          memset(dropped, 0, nDense * sizeof(int));
+          dense.setDoubleParameter(3, largest);
+          dense.setDoubleParameter(4, smallest);
+          dense.setDoubleParameter(10, dropValue);
+          dense.setIntegerParameter(20, 0);
+          dense.setIntegerParameter(34, firstPositive);
+          dense.setModel(model_);
+          dense.factorizePart2(dropped);
+          largest = dense.getDoubleParameter(3);
+          smallest = dense.getDoubleParameter(4);
+          integerParameters_[20] += dense.getIntegerParameter(20);
+          for (iRow = firstDense_; iRow < numberRows_; iRow++) {
+               int originalRow = permute_[iRow];
+               rowsDropped[originalRow] = dropped[iRow-firstDense_];
+          }
+          delete [] dropped;
+     }
+     delete [] d;
+     doubleParameters_[3] = largest;
+     doubleParameters_[4] = smallest;
+     return;
+}
+// Updates dense part (broken out for profiling)
+void ClpCholeskyBase::updateDense(longDouble * d, /*longDouble * work,*/ int * first)
+{
+     for (int iRow = 0; iRow < firstDense_; iRow++) {
+          CoinBigIndex start = first[iRow];
+          CoinBigIndex end = choleskyStart_[iRow+1];
+          if (start < end) {
+               CoinBigIndex offset = indexStart_[iRow] - choleskyStart_[iRow];
+               if (clique_[iRow] < 2) {
+                    CoinWorkDouble dValue = d[iRow];
+                    for (CoinBigIndex k = start; k < end; k++) {
+                         int kRow = choleskyRow_[k+offset];
+                         assert(kRow >= firstDense_);
+                         CoinWorkDouble a_ik = sparseFactor_[k];
+                         CoinWorkDouble value1 = dValue * a_ik;
+                         diagonal_[kRow] -= value1 * a_ik;
+                         CoinBigIndex base = choleskyStart_[kRow] - kRow - 1;
+                         for (CoinBigIndex j = k + 1; j < end; j++) {
+                              int jRow = choleskyRow_[j+offset];
+                              CoinWorkDouble a_jk = sparseFactor_[j];
+                              sparseFactor_[base+jRow] -= a_jk * value1;
+                         }
+                    }
+               } else if (clique_[iRow] < 3) {
+                    // do as pair
+                    CoinWorkDouble dValue0 = d[iRow];
+                    CoinWorkDouble dValue1 = d[iRow+1];
+                    int offset1 = first[iRow+1] - start;
+                    // skip row
+                    iRow++;
+                    for (CoinBigIndex k = start; k < end; k++) {
+                         int kRow = choleskyRow_[k+offset];
+                         assert(kRow >= firstDense_);
+                         CoinWorkDouble a_ik0 = sparseFactor_[k];
+                         CoinWorkDouble value0 = dValue0 * a_ik0;
+                         CoinWorkDouble a_ik1 = sparseFactor_[k+offset1];
+                         CoinWorkDouble value1 = dValue1 * a_ik1;
+                         diagonal_[kRow] -= value0 * a_ik0 + value1 * a_ik1;
+                         CoinBigIndex base = choleskyStart_[kRow] - kRow - 1;
+                         for (CoinBigIndex j = k + 1; j < end; j++) {
+                              int jRow = choleskyRow_[j+offset];
+                              CoinWorkDouble a_jk0 = sparseFactor_[j];
+                              CoinWorkDouble a_jk1 = sparseFactor_[j+offset1];
+                              sparseFactor_[base+jRow] -= a_jk0 * value0 + a_jk1 * value1;
+                         }
+                    }
+#define MANY_REGISTERS
+#ifdef MANY_REGISTERS
+               } else if (clique_[iRow] == 3) {
+#else
+               } else {
+#endif
+                    // do as clique
+                    // maybe later get fancy on big cliques and do transpose copy
+                    // seems only worth going to 3 on Intel
+                    CoinWorkDouble dValue0 = d[iRow];
+                    CoinWorkDouble dValue1 = d[iRow+1];
+                    CoinWorkDouble dValue2 = d[iRow+2];
+                    // get offsets and skip rows
+                    int offset1 = first[++iRow] - start;
+                    int offset2 = first[++iRow] - start;
+                    for (CoinBigIndex k = start; k < end; k++) {
+                         int kRow = choleskyRow_[k+offset];
+                         assert(kRow >= firstDense_);
+                         CoinWorkDouble diagonalValue = diagonal_[kRow];
+                         CoinWorkDouble a_ik0 = sparseFactor_[k];
+                         CoinWorkDouble value0 = dValue0 * a_ik0;
+                         CoinWorkDouble a_ik1 = sparseFactor_[k+offset1];
+                         CoinWorkDouble value1 = dValue1 * a_ik1;
+                         CoinWorkDouble a_ik2 = sparseFactor_[k+offset2];
+                         CoinWorkDouble value2 = dValue2 * a_ik2;
+                         CoinBigIndex base = choleskyStart_[kRow] - kRow - 1;
+                         diagonal_[kRow] = diagonalValue - value0 * a_ik0 - value1 * a_ik1 - value2 * a_ik2;
+                         for (CoinBigIndex j = k + 1; j < end; j++) {
+                              int jRow = choleskyRow_[j+offset];
+                              CoinWorkDouble a_jk0 = sparseFactor_[j];
+                              CoinWorkDouble a_jk1 = sparseFactor_[j+offset1];
+                              CoinWorkDouble a_jk2 = sparseFactor_[j+offset2];
+                              sparseFactor_[base+jRow] -= a_jk0 * value0 + a_jk1 * value1 + a_jk2 * value2;
+                         }
+                    }
+#ifdef MANY_REGISTERS
+               }
+               else {
+                    // do as clique
+                    // maybe later get fancy on big cliques and do transpose copy
+                    // maybe only worth going to 3 on Intel (but may have hidden registers)
+                    CoinWorkDouble dValue0 = d[iRow];
+                    CoinWorkDouble dValue1 = d[iRow+1];
+                    CoinWorkDouble dValue2 = d[iRow+2];
+                    CoinWorkDouble dValue3 = d[iRow+3];
+                    // get offsets and skip rows
+                    int offset1 = first[++iRow] - start;
+                    int offset2 = first[++iRow] - start;
+                    int offset3 = first[++iRow] - start;
+                    for (CoinBigIndex k = start; k < end; k++) {
+                         int kRow = choleskyRow_[k+offset];
+                         assert(kRow >= firstDense_);
+                         CoinWorkDouble diagonalValue = diagonal_[kRow];
+                         CoinWorkDouble a_ik0 = sparseFactor_[k];
+                         CoinWorkDouble value0 = dValue0 * a_ik0;
+                         CoinWorkDouble a_ik1 = sparseFactor_[k+offset1];
+                         CoinWorkDouble value1 = dValue1 * a_ik1;
+                         CoinWorkDouble a_ik2 = sparseFactor_[k+offset2];
+                         CoinWorkDouble value2 = dValue2 * a_ik2;
+                         CoinWorkDouble a_ik3 = sparseFactor_[k+offset3];
+                         CoinWorkDouble value3 = dValue3 * a_ik3;
+                         CoinBigIndex base = choleskyStart_[kRow] - kRow - 1;
+                         diagonal_[kRow] = diagonalValue - (value0 * a_ik0 + value1 * a_ik1 + value2 * a_ik2 + value3 * a_ik3);
+                         for (CoinBigIndex j = k + 1; j < end; j++) {
+                              int jRow = choleskyRow_[j+offset];
+                              CoinWorkDouble a_jk0 = sparseFactor_[j];
+                              CoinWorkDouble a_jk1 = sparseFactor_[j+offset1];
+                              CoinWorkDouble a_jk2 = sparseFactor_[j+offset2];
+                              CoinWorkDouble a_jk3 = sparseFactor_[j+offset3];
+                              sparseFactor_[base+jRow] -= a_jk0 * value0 + a_jk1 * value1 + a_jk2 * value2 + a_jk3 * value3;
+                         }
+                    }
+#endif
+               }
+          }
+     }
+}
+/* Uses factorization to solve. */
+void
+ClpCholeskyBase::solve (CoinWorkDouble * region)
+{
+     if (!whichDense_) {
+          solve(region, 3);
+     } else {
+          // dense columns
+          int i;
+          solve(region, 1);
+          // do change;
+          int numberDense = dense_->numberRows();
+          CoinWorkDouble * change = new CoinWorkDouble[numberDense];
+          for (i = 0; i < numberDense; i++) {
+               const longDouble * a = denseColumn_ + i * numberRows_;
+               CoinWorkDouble value = 0.0;
+               for (int iRow = 0; iRow < numberRows_; iRow++)
+                    value += a[iRow] * region[iRow];
+               change[i] = value;
+          }
+          // solve
+          dense_->solve(change);
+          for (i = 0; i < numberDense; i++) {
+               const longDouble * a = denseColumn_ + i * numberRows_;
+               CoinWorkDouble value = change[i];
+               for (int iRow = 0; iRow < numberRows_; iRow++)
+                    region[iRow] -= value * a[iRow];
+          }
+          delete [] change;
+          // and finish off
+          solve(region, 2);
+     }
+}
+/* solve - 1 just first half, 2 just second half - 3 both.
+   If 1 and 2 then diagonal has sqrt of inverse otherwise inverse
+*/
+void
+ClpCholeskyBase::solve(CoinWorkDouble * region, int type)
+{
+#ifdef CLP_DEBUG
+     double * regionX = NULL;
+     if (sizeof(CoinWorkDouble) != sizeof(double) && type == 3) {
+          regionX = ClpCopyOfArray(region, numberRows_);
+     }
+#endif
+     CoinWorkDouble * work = reinterpret_cast<CoinWorkDouble *> (workDouble_);
+     int i;
+     CoinBigIndex j;
+     for (i = 0; i < numberRows_; i++) {
+          int iRow = permute_[i];
+          work[i] = region[iRow];
+     }
+     switch (type) {
+     case 1:
+          for (i = 0; i < numberRows_; i++) {
+               CoinWorkDouble value = work[i];
+               CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+               for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+                    int iRow = choleskyRow_[j+offset];
+                    work[iRow] -= sparseFactor_[j] * value;
+               }
+          }
+          for (i = 0; i < numberRows_; i++) {
+               int iRow = permute_[i];
+               region[iRow] = work[i] * diagonal_[i];
+          }
+          break;
+     case 2:
+          for (i = numberRows_ - 1; i >= 0; i--) {
+               CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+               CoinWorkDouble value = work[i] * diagonal_[i];
+               for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+                    int iRow = choleskyRow_[j+offset];
+                    value -= sparseFactor_[j] * work[iRow];
+               }
+               work[i] = value;
+               int iRow = permute_[i];
+               region[iRow] = value;
+          }
+          break;
+     case 3:
+          for (i = 0; i < firstDense_; i++) {
+               CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+               CoinWorkDouble value = work[i];
+               for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+                    int iRow = choleskyRow_[j+offset];
+                    work[iRow] -= sparseFactor_[j] * value;
+               }
+          }
+          if (firstDense_ < numberRows_) {
+               // do dense
+               ClpCholeskyDense dense;
+               // just borrow space
+               int nDense = numberRows_ - firstDense_;
+               dense.reserveSpace(this, nDense);
+               dense.solve(work + firstDense_);
+               for (i = numberRows_ - 1; i >= firstDense_; i--) {
+                    CoinWorkDouble value = work[i];
+                    int iRow = permute_[i];
+                    region[iRow] = value;
+               }
+          }
+          for (i = firstDense_ - 1; i >= 0; i--) {
+               CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+               CoinWorkDouble value = work[i] * diagonal_[i];
+               for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+                    int iRow = choleskyRow_[j+offset];
+                    value -= sparseFactor_[j] * work[iRow];
+               }
+               work[i] = value;
+               int iRow = permute_[i];
+               region[iRow] = value;
+          }
+          break;
+     }
+#ifdef CLP_DEBUG
+     if (regionX) {
+          longDouble * work = workDouble_;
+          int i;
+          CoinBigIndex j;
+          double largestO = 0.0;
+          for (i = 0; i < numberRows_; i++) {
+               largestO = CoinMax(largestO, CoinAbs(regionX[i]));
+          }
+          for (i = 0; i < numberRows_; i++) {
+               int iRow = permute_[i];
+               work[i] = regionX[iRow];
+          }
+          for (i = 0; i < firstDense_; i++) {
+               CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+               CoinWorkDouble value = work[i];
+               for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+                    int iRow = choleskyRow_[j+offset];
+                    work[iRow] -= sparseFactor_[j] * value;
+               }
+          }
+          if (firstDense_ < numberRows_) {
+               // do dense
+               ClpCholeskyDense dense;
+               // just borrow space
+               int nDense = numberRows_ - firstDense_;
+               dense.reserveSpace(this, nDense);
+               dense.solve(work + firstDense_);
+               for (i = numberRows_ - 1; i >= firstDense_; i--) {
+                    CoinWorkDouble value = work[i];
+                    int iRow = permute_[i];
+                    regionX[iRow] = value;
+               }
+          }
+          for (i = firstDense_ - 1; i >= 0; i--) {
+               CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+               CoinWorkDouble value = work[i] * diagonal_[i];
+               for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+                    int iRow = choleskyRow_[j+offset];
+                    value -= sparseFactor_[j] * work[iRow];
+               }
+               work[i] = value;
+               int iRow = permute_[i];
+               regionX[iRow] = value;
+          }
+          double largest = 0.0;
+          double largestV = 0.0;
+          for (i = 0; i < numberRows_; i++) {
+               largest = CoinMax(largest, CoinAbs(region[i] - regionX[i]));
+               largestV = CoinMax(largestV, CoinAbs(region[i]));
+          }
+          printf("largest difference %g, largest %g, largest original %g\n",
+                 largest, largestV, largestO);
+          delete [] regionX;
+     }
+#endif
+}
+#if 0 //CLP_LONG_CHOLESKY
+/* Uses factorization to solve. */
+void
+ClpCholeskyBase::solve (CoinWorkDouble * region)
+{
+     assert (!whichDense_) ;
+     CoinWorkDouble * work = reinterpret_cast<CoinWorkDouble *> (workDouble_);
+     int i;
+     CoinBigIndex j;
+     for (i = 0; i < numberRows_; i++) {
+          int iRow = permute_[i];
+          work[i] = region[iRow];
+     }
+     for (i = 0; i < firstDense_; i++) {
+          CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+          CoinWorkDouble value = work[i];
+          for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+               int iRow = choleskyRow_[j+offset];
+               work[iRow] -= sparseFactor_[j] * value;
+          }
+     }
+     if (firstDense_ < numberRows_) {
+          // do dense
+          ClpCholeskyDense dense;
+          // just borrow space
+          int nDense = numberRows_ - firstDense_;
+          dense.reserveSpace(this, nDense);
+          dense.solve(work + firstDense_);
+          for (i = numberRows_ - 1; i >= firstDense_; i--) {
+               CoinWorkDouble value = work[i];
+               int iRow = permute_[i];
+               region[iRow] = value;
+          }
+     }
+     for (i = firstDense_ - 1; i >= 0; i--) {
+          CoinBigIndex offset = indexStart_[i] - choleskyStart_[i];
+          CoinWorkDouble value = work[i] * diagonal_[i];
+          for (j = choleskyStart_[i]; j < choleskyStart_[i+1]; j++) {
+               int iRow = choleskyRow_[j+offset];
+               value -= sparseFactor_[j] * work[iRow];
+          }
+          work[i] = value;
+          int iRow = permute_[i];
+          region[iRow] = value;
+     }
+}
+#endif
diff --git a/cbits/coin/ClpCholeskyBase.hpp b/cbits/coin/ClpCholeskyBase.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpCholeskyBase.hpp
@@ -0,0 +1,294 @@
+/* $Id: ClpCholeskyBase.hpp 1722 2011-04-17 09:58:37Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpCholeskyBase_H
+#define ClpCholeskyBase_H
+
+#include "CoinPragma.hpp"
+#include "CoinTypes.hpp"
+//#define CLP_LONG_CHOLESKY 0
+#ifndef CLP_LONG_CHOLESKY
+#define CLP_LONG_CHOLESKY 0
+#endif
+/* valid combinations are
+   CLP_LONG_CHOLESKY 0 and COIN_LONG_WORK 0
+   CLP_LONG_CHOLESKY 1 and COIN_LONG_WORK 1
+   CLP_LONG_CHOLESKY 2 and COIN_LONG_WORK 1
+*/
+#if COIN_LONG_WORK==0
+#if CLP_LONG_CHOLESKY>0
+#define CHOLESKY_BAD_COMBINATION
+#endif
+#else
+#if CLP_LONG_CHOLESKY==0
+#define CHOLESKY_BAD_COMBINATION
+#endif
+#endif
+#ifdef CHOLESKY_BAD_COMBINATION
+#  warning("Bad combination of CLP_LONG_CHOLESKY and COIN_BIG_DOUBLE/COIN_LONG_WORK");
+"Bad combination of CLP_LONG_CHOLESKY and COIN_LONG_WORK"
+#endif
+#if CLP_LONG_CHOLESKY>1
+typedef long double longDouble;
+#define CHOL_SMALL_VALUE 1.0e-15
+#elif CLP_LONG_CHOLESKY==1
+typedef double longDouble;
+#define CHOL_SMALL_VALUE 1.0e-11
+#else
+typedef double longDouble;
+#define CHOL_SMALL_VALUE 1.0e-11
+#endif
+class ClpInterior;
+class ClpCholeskyDense;
+class ClpMatrixBase;
+
+/** Base class for Clp Cholesky factorization
+    Will do better factorization.  very crude ordering
+
+    Derived classes may be using more sophisticated methods
+*/
+
+class ClpCholeskyBase  {
+
+public:
+     /**@name Virtual methods that the derived classes may provide  */
+     //@{
+     /** Orders rows and saves pointer to matrix.and model.
+      returns non-zero if not enough memory.
+      You can use preOrder to set up ADAT
+      If using default symbolic etc then must set sizeFactor_ to
+      size of input matrix to order (and to symbolic).
+      Also just permute_ and permuteInverse_ should be created */
+     virtual int order(ClpInterior * model);
+     /** Does Symbolic factorization given permutation.
+         This is called immediately after order.  If user provides this then
+         user must provide factorize and solve.  Otherwise the default factorization is used
+         returns non-zero if not enough memory */
+     virtual int symbolic();
+     /** Factorize - filling in rowsDropped and returning number dropped.
+         If return code negative then out of memory */
+     virtual int factorize(const CoinWorkDouble * diagonal, int * rowsDropped) ;
+     /** Uses factorization to solve. */
+     virtual void solve (CoinWorkDouble * region) ;
+     /** Uses factorization to solve. - given as if KKT.
+      region1 is rows+columns, region2 is rows */
+     virtual void solveKKT (CoinWorkDouble * region1, CoinWorkDouble * region2, const CoinWorkDouble * diagonal,
+                            CoinWorkDouble diagonalScaleFactor);
+private:
+     /// AMD ordering
+     int orderAMD();
+public:
+     //@}
+
+     /**@name Gets */
+     //@{
+     /// status.  Returns status
+     inline int status() const {
+          return status_;
+     }
+     /// numberRowsDropped.  Number of rows gone
+     inline int numberRowsDropped() const {
+          return numberRowsDropped_;
+     }
+     /// reset numberRowsDropped and rowsDropped.
+     void resetRowsDropped();
+     /// rowsDropped - which rows are gone
+     inline char * rowsDropped() const {
+          return rowsDropped_;
+     }
+     /// choleskyCondition.
+     inline double choleskyCondition() const {
+          return choleskyCondition_;
+     }
+     /// goDense i.e. use dense factoriaztion if > this (default 0.7).
+     inline double goDense() const {
+          return goDense_;
+     }
+     /// goDense i.e. use dense factoriaztion if > this (default 0.7).
+     inline void setGoDense(double value) {
+          goDense_ = value;
+     }
+     /// rank.  Returns rank
+     inline int rank() const {
+          return numberRows_ - numberRowsDropped_;
+     }
+     /// Return number of rows
+     inline int numberRows() const {
+          return numberRows_;
+     }
+     /// Return size
+     inline CoinBigIndex size() const {
+          return sizeFactor_;
+     }
+     /// Return sparseFactor
+     inline longDouble * sparseFactor() const {
+          return sparseFactor_;
+     }
+     /// Return diagonal
+     inline longDouble * diagonal() const {
+          return diagonal_;
+     }
+     /// Return workDouble
+     inline longDouble * workDouble() const {
+          return workDouble_;
+     }
+     /// If KKT on
+     inline bool kkt() const {
+          return doKKT_;
+     }
+     /// Set KKT
+     inline void setKKT(bool yesNo) {
+          doKKT_ = yesNo;
+     }
+     /// Set integer parameter
+     inline void setIntegerParameter(int i, int value) {
+          integerParameters_[i] = value;
+     }
+     /// get integer parameter
+     inline int getIntegerParameter(int i) {
+          return integerParameters_[i];
+     }
+     /// Set double parameter
+     inline void setDoubleParameter(int i, double value) {
+          doubleParameters_[i] = value;
+     }
+     /// get double parameter
+     inline double getDoubleParameter(int i) {
+          return doubleParameters_[i];
+     }
+     //@}
+
+
+public:
+
+     /**@name Constructors, destructor
+      */
+     //@{
+     /** Constructor which has dense columns activated.
+         Default is off. */
+     ClpCholeskyBase(int denseThreshold = -1);
+     /** Destructor (has to be public) */
+     virtual ~ClpCholeskyBase();
+     /// Copy
+     ClpCholeskyBase(const ClpCholeskyBase&);
+     /// Assignment
+     ClpCholeskyBase& operator=(const ClpCholeskyBase&);
+     //@}
+     //@{
+     ///@name Other
+     /// Clone
+     virtual ClpCholeskyBase * clone() const;
+
+     /// Returns type
+     inline int type() const {
+          if (doKKT_) return 100;
+          else return type_;
+     }
+protected:
+     /// Sets type
+     inline void setType(int type) {
+          type_ = type;
+     }
+     /// model.
+     inline void setModel(ClpInterior * model) {
+          model_ = model;
+     }
+     //@}
+
+     /**@name Symbolic, factor and solve */
+     //@{
+     /** Symbolic1  - works out size without clever stuff.
+         Uses upper triangular as much easier.
+         Returns size
+      */
+     int symbolic1(const CoinBigIndex * Astart, const int * Arow);
+     /** Symbolic2  - Fills in indices
+         Uses lower triangular so can do cliques etc
+      */
+     void symbolic2(const CoinBigIndex * Astart, const int * Arow);
+     /** Factorize - filling in rowsDropped and returning number dropped
+         in integerParam.
+      */
+     void factorizePart2(int * rowsDropped) ;
+     /** solve - 1 just first half, 2 just second half - 3 both.
+     If 1 and 2 then diagonal has sqrt of inverse otherwise inverse
+     */
+     void solve(CoinWorkDouble * region, int type);
+     /// Forms ADAT - returns nonzero if not enough memory
+     int preOrder(bool lowerTriangular, bool includeDiagonal, bool doKKT);
+     /// Updates dense part (broken out for profiling)
+     void updateDense(longDouble * d, /*longDouble * work,*/ int * first);
+     //@}
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// type (may be useful) if > 20 do KKT
+     int type_;
+     /// Doing full KKT (only used if default symbolic and factorization)
+     bool doKKT_;
+     /// Go dense at this fraction
+     double goDense_;
+     /// choleskyCondition.
+     double choleskyCondition_;
+     /// model.
+     ClpInterior * model_;
+     /// numberTrials.  Number of trials before rejection
+     int numberTrials_;
+     /// numberRows.  Number of Rows in factorization
+     int numberRows_;
+     /// status.  Status of factorization
+     int status_;
+     /// rowsDropped
+     char * rowsDropped_;
+     /// permute inverse.
+     int * permuteInverse_;
+     /// main permute.
+     int * permute_;
+     /// numberRowsDropped.  Number of rows gone
+     int numberRowsDropped_;
+     /// sparseFactor.
+     longDouble * sparseFactor_;
+     /// choleskyStart - element starts
+     CoinBigIndex * choleskyStart_;
+     /// choleskyRow (can be shorter than sparsefactor)
+     int * choleskyRow_;
+     /// Index starts
+     CoinBigIndex * indexStart_;
+     /// Diagonal
+     longDouble * diagonal_;
+     /// double work array
+     longDouble * workDouble_;
+     /// link array
+     int * link_;
+     // Integer work array
+     CoinBigIndex * workInteger_;
+     // Clique information
+     int * clique_;
+     /// sizeFactor.
+     CoinBigIndex sizeFactor_;
+     /// Size of index array
+     CoinBigIndex sizeIndex_;
+     /// First dense row
+     int firstDense_;
+     /// integerParameters
+     int integerParameters_[64];
+     /// doubleParameters;
+     double doubleParameters_[64];
+     /// Row copy of matrix
+     ClpMatrixBase * rowCopy_;
+     /// Dense indicators
+     char * whichDense_;
+     /// Dense columns (updated)
+     longDouble * denseColumn_;
+     /// Dense cholesky
+     ClpCholeskyDense * dense_;
+     /// Dense threshold (for taking out of Cholesky)
+     int denseThreshold_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpCholeskyDense.cpp b/cbits/coin/ClpCholeskyDense.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpCholeskyDense.cpp
@@ -0,0 +1,1593 @@
+/* $Id: ClpCholeskyDense.cpp 1910 2013-01-27 02:00:13Z stefan $ */
+/*
+  Copyright (C) 2003, International Business Machines Corporation
+  and others.  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "ClpConfig.h"
+#include "ClpHelperFunctions.hpp"
+#include "ClpInterior.hpp"
+#include "ClpCholeskyDense.hpp"
+#include "ClpMessage.hpp"
+#include "ClpQuadraticObjective.hpp"
+#if CLP_HAS_ABC
+#include "CoinAbcCommon.hpp"
+#endif
+#if CLP_HAS_ABC<3
+#undef cilk_for 
+#undef cilk_spawn
+#undef cilk_sync
+#define cilk_for for 
+#define cilk_spawn
+#define cilk_sync
+#endif
+
+/*#############################################################################*/
+/* Constructors / Destructor / Assignment*/
+/*#############################################################################*/
+
+/*-------------------------------------------------------------------*/
+/* Default Constructor */
+/*-------------------------------------------------------------------*/
+ClpCholeskyDense::ClpCholeskyDense ()
+     : ClpCholeskyBase(),
+       borrowSpace_(false)
+{
+     type_ = 11;;
+}
+
+/*-------------------------------------------------------------------*/
+/* Copy constructor */
+/*-------------------------------------------------------------------*/
+ClpCholeskyDense::ClpCholeskyDense (const ClpCholeskyDense & rhs)
+     : ClpCholeskyBase(rhs),
+       borrowSpace_(rhs.borrowSpace_)
+{
+     assert(!rhs.borrowSpace_ || !rhs.sizeFactor_); /* can't do if borrowing space*/
+}
+
+
+/*-------------------------------------------------------------------*/
+/* Destructor */
+/*-------------------------------------------------------------------*/
+ClpCholeskyDense::~ClpCholeskyDense ()
+{
+     if (borrowSpace_) {
+          /* set NULL*/
+          sparseFactor_ = NULL;
+          workDouble_ = NULL;
+          diagonal_ = NULL;
+     }
+}
+
+/*----------------------------------------------------------------*/
+/* Assignment operator */
+/*-------------------------------------------------------------------*/
+ClpCholeskyDense &
+ClpCholeskyDense::operator=(const ClpCholeskyDense& rhs)
+{
+     if (this != &rhs) {
+          assert(!rhs.borrowSpace_ || !rhs.sizeFactor_); /* can't do if borrowing space*/
+          ClpCholeskyBase::operator=(rhs);
+          borrowSpace_ = rhs.borrowSpace_;
+     }
+     return *this;
+}
+/*-------------------------------------------------------------------*/
+/* Clone*/
+/*-------------------------------------------------------------------*/
+ClpCholeskyBase * ClpCholeskyDense::clone() const
+{
+     return new ClpCholeskyDense(*this);
+}
+/* If not power of 2 then need to redo a bit*/
+#define BLOCK 16
+#define BLOCKSHIFT 4
+/* Block unroll if power of 2 and at least 8*/
+#define BLOCKUNROLL
+
+#define BLOCKSQ ( BLOCK*BLOCK )
+#define BLOCKSQSHIFT ( BLOCKSHIFT+BLOCKSHIFT )
+#define number_blocks(x) (((x)+BLOCK-1)>>BLOCKSHIFT)
+#define number_rows(x) ((x)<<BLOCKSHIFT)
+#define number_entries(x) ((x)<<BLOCKSQSHIFT)
+/* Gets space */
+int
+ClpCholeskyDense::reserveSpace(const ClpCholeskyBase * factor, int numberRows)
+{
+     numberRows_ = numberRows;
+     int numberBlocks = (numberRows_ + BLOCK - 1) >> BLOCKSHIFT;
+     /* allow one stripe extra*/
+     numberBlocks = numberBlocks + ((numberBlocks * (numberBlocks + 1)) / 2);
+     sizeFactor_ = numberBlocks * BLOCKSQ;
+     /*#define CHOL_COMPARE*/
+#ifdef CHOL_COMPARE
+     sizeFactor_ += 95000;
+#endif
+     if (!factor) {
+          sparseFactor_ = new longDouble [sizeFactor_];
+          rowsDropped_ = new char [numberRows_];
+          memset(rowsDropped_, 0, numberRows_);
+          workDouble_ = new longDouble[numberRows_];
+          diagonal_ = new longDouble[numberRows_];
+     } else {
+          borrowSpace_ = true;
+          int numberFull = factor->numberRows();
+          sparseFactor_ = factor->sparseFactor() + (factor->size() - sizeFactor_);
+          workDouble_ = factor->workDouble() + (numberFull - numberRows_);
+          diagonal_ = factor->diagonal() + (numberFull - numberRows_);
+     }
+     numberRowsDropped_ = 0;
+     return 0;
+}
+/* Returns space needed */
+CoinBigIndex
+ClpCholeskyDense::space( int numberRows) const
+{
+     int numberBlocks = (numberRows + BLOCK - 1) >> BLOCKSHIFT;
+     /* allow one stripe extra*/
+     numberBlocks = numberBlocks + ((numberBlocks * (numberBlocks + 1)) / 2);
+     CoinBigIndex sizeFactor = numberBlocks * BLOCKSQ;
+#ifdef CHOL_COMPARE
+     sizeFactor += 95000;
+#endif
+     return sizeFactor;
+}
+/* Orders rows and saves pointer to matrix.and model */
+int
+ClpCholeskyDense::order(ClpInterior * model)
+{
+     model_ = model;
+     int numberRows;
+     int numberRowsModel = model_->numberRows();
+     int numberColumns = model_->numberColumns();
+     if (!doKKT_) {
+          numberRows = numberRowsModel;
+     } else {
+          numberRows = 2 * numberRowsModel + numberColumns;
+     }
+     reserveSpace(NULL, numberRows);
+     rowCopy_ = model->clpMatrix()->reverseOrderedCopy();
+     return 0;
+}
+/* Does Symbolic factorization given permutation.
+   This is called immediately after order.  If user provides this then
+   user must provide factorize and solve.  Otherwise the default factorization is used
+   returns non-zero if not enough memory */
+int
+ClpCholeskyDense::symbolic()
+{
+     return 0;
+}
+/* Factorize - filling in rowsDropped and returning number dropped */
+int
+ClpCholeskyDense::factorize(const CoinWorkDouble * diagonal, int * rowsDropped)
+{
+     assert (!borrowSpace_);
+     const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts();
+     const int * columnLength = model_->clpMatrix()->getVectorLengths();
+     const int * row = model_->clpMatrix()->getIndices();
+     const double * element = model_->clpMatrix()->getElements();
+     const CoinBigIndex * rowStart = rowCopy_->getVectorStarts();
+     const int * rowLength = rowCopy_->getVectorLengths();
+     const int * column = rowCopy_->getIndices();
+     const double * elementByRow = rowCopy_->getElements();
+     int numberColumns = model_->clpMatrix()->getNumCols();
+     CoinZeroN(sparseFactor_, sizeFactor_);
+     /*perturbation*/
+     CoinWorkDouble perturbation = model_->diagonalPerturbation() * model_->diagonalNorm();
+     perturbation = perturbation * perturbation;
+     if (perturbation > 1.0) {
+#ifdef COIN_DEVELOP
+          /*if (model_->model()->logLevel()&4) */
+          std::cout << "large perturbation " << perturbation << std::endl;
+#endif
+          perturbation = CoinSqrt(perturbation);;
+          perturbation = 1.0;
+     }
+     int iRow;
+     int newDropped = 0;
+     CoinWorkDouble largest = 1.0;
+     CoinWorkDouble smallest = COIN_DBL_MAX;
+     CoinWorkDouble delta2 = model_->delta(); /* add delta*delta to diagonal*/
+     delta2 *= delta2;
+     if (!doKKT_) {
+          longDouble * work = sparseFactor_;
+          work--; /* skip diagonal*/
+          int addOffset = numberRows_ - 1;
+          const CoinWorkDouble * diagonalSlack = diagonal + numberColumns;
+          /* largest in initial matrix*/
+          CoinWorkDouble largest2 = 1.0e-20;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if (!rowsDropped_[iRow]) {
+                    CoinBigIndex startRow = rowStart[iRow];
+                    CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow];
+                    CoinWorkDouble diagonalValue = diagonalSlack[iRow] + delta2;
+                    for (CoinBigIndex k = startRow; k < endRow; k++) {
+                         int iColumn = column[k];
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                         CoinWorkDouble multiplier = diagonal[iColumn] * elementByRow[k];
+                         for (CoinBigIndex j = start; j < end; j++) {
+                              int jRow = row[j];
+                              if (!rowsDropped_[jRow]) {
+                                   if (jRow > iRow) {
+                                        CoinWorkDouble value = element[j] * multiplier;
+                                        work[jRow] += value;
+                                   } else if (jRow == iRow) {
+                                        CoinWorkDouble value = element[j] * multiplier;
+                                        diagonalValue += value;
+                                   }
+                              }
+                         }
+                    }
+                    for (int j = iRow + 1; j < numberRows_; j++)
+                         largest2 = CoinMax(largest2, CoinAbs(work[j]));
+                    diagonal_[iRow] = diagonalValue;
+                    largest2 = CoinMax(largest2, CoinAbs(diagonalValue));
+               } else {
+                    /* dropped*/
+                    diagonal_[iRow] = 1.0;
+               }
+               addOffset--;
+               work += addOffset;
+          }
+          /*check sizes*/
+          largest2 *= 1.0e-20;
+          largest = CoinMin(largest2, CHOL_SMALL_VALUE);
+          int numberDroppedBefore = 0;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int dropped = rowsDropped_[iRow];
+               /* Move to int array*/
+               rowsDropped[iRow] = dropped;
+               if (!dropped) {
+                    CoinWorkDouble diagonal = diagonal_[iRow];
+                    if (diagonal > largest2) {
+                         diagonal_[iRow] = diagonal + perturbation;
+                    } else {
+                         diagonal_[iRow] = diagonal + perturbation;
+                         rowsDropped[iRow] = 2;
+                         numberDroppedBefore++;
+                    }
+               }
+          }
+          doubleParameters_[10] = CoinMax(1.0e-20, largest);
+          integerParameters_[20] = 0;
+          doubleParameters_[3] = 0.0;
+          doubleParameters_[4] = COIN_DBL_MAX;
+          integerParameters_[34] = 0; /* say all must be positive*/
+#ifdef CHOL_COMPARE
+          if (numberRows_ < 200)
+               factorizePart3(rowsDropped);
+#endif
+          factorizePart2(rowsDropped);
+          newDropped = integerParameters_[20] + numberDroppedBefore;
+          largest = doubleParameters_[3];
+          smallest = doubleParameters_[4];
+          if (model_->messageHandler()->logLevel() > 1)
+               std::cout << "Cholesky - largest " << largest << " smallest " << smallest << std::endl;
+          choleskyCondition_ = largest / smallest;
+          /*drop fresh makes some formADAT easier*/
+          if (newDropped || numberRowsDropped_) {
+               newDropped = 0;
+               for (int i = 0; i < numberRows_; i++) {
+                    char dropped = static_cast<char>(rowsDropped[i]);
+                    rowsDropped_[i] = dropped;
+                    if (dropped == 2) {
+                         /*dropped this time*/
+                         rowsDropped[newDropped++] = i;
+                         rowsDropped_[i] = 0;
+                    }
+               }
+               numberRowsDropped_ = newDropped;
+               newDropped = -(2 + newDropped);
+          }
+     } else {
+          /* KKT*/
+          CoinPackedMatrix * quadratic = NULL;
+          ClpQuadraticObjective * quadraticObj =
+               (dynamic_cast< ClpQuadraticObjective*>(model_->objectiveAsObject()));
+          if (quadraticObj)
+               quadratic = quadraticObj->quadraticObjective();
+          /* matrix*/
+          int numberRowsModel = model_->numberRows();
+          int numberColumns = model_->numberColumns();
+          int numberTotal = numberColumns + numberRowsModel;
+          longDouble * work = sparseFactor_;
+          work--; /* skip diagonal*/
+          int addOffset = numberRows_ - 1;
+          int iColumn;
+          if (!quadratic) {
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    CoinWorkDouble value = diagonal[iColumn];
+                    if (CoinAbs(value) > 1.0e-100) {
+                         value = 1.0 / value;
+                         largest = CoinMax(largest, CoinAbs(value));
+                         diagonal_[iColumn] = -value;
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                         for (CoinBigIndex j = start; j < end; j++) {
+                              /*choleskyRow_[numberElements]=row[j]+numberTotal;*/
+                              /*sparseFactor_[numberElements++]=element[j];*/
+                              work[row[j] + numberTotal] = element[j];
+                              largest = CoinMax(largest, CoinAbs(element[j]));
+                         }
+                    } else {
+                         diagonal_[iColumn] = -value;
+                    }
+                    addOffset--;
+                    work += addOffset;
+               }
+          } else {
+               /* Quadratic*/
+               const int * columnQuadratic = quadratic->getIndices();
+               const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+               const int * columnQuadraticLength = quadratic->getVectorLengths();
+               const double * quadraticElement = quadratic->getElements();
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    CoinWorkDouble value = diagonal[iColumn];
+                    CoinBigIndex j;
+                    if (CoinAbs(value) > 1.0e-100) {
+                         value = 1.0 / value;
+                         for (j = columnQuadraticStart[iColumn];
+                                   j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                              int jColumn = columnQuadratic[j];
+                              if (jColumn > iColumn) {
+                                   work[jColumn] = -quadraticElement[j];
+                              } else if (iColumn == jColumn) {
+                                   value += quadraticElement[j];
+                              }
+                         }
+                         largest = CoinMax(largest, CoinAbs(value));
+                         diagonal_[iColumn] = -value;
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                         for (j = start; j < end; j++) {
+                              work[row[j] + numberTotal] = element[j];
+                              largest = CoinMax(largest, CoinAbs(element[j]));
+                         }
+                    } else {
+                         value = 1.0e100;
+                         diagonal_[iColumn] = -value;
+                    }
+                    addOffset--;
+                    work += addOffset;
+               }
+          }
+          /* slacks*/
+          for (iColumn = numberColumns; iColumn < numberTotal; iColumn++) {
+               CoinWorkDouble value = diagonal[iColumn];
+               if (CoinAbs(value) > 1.0e-100) {
+                    value = 1.0 / value;
+                    largest = CoinMax(largest, CoinAbs(value));
+               } else {
+                    value = 1.0e100;
+               }
+               diagonal_[iColumn] = -value;
+               work[iColumn-numberColumns+numberTotal] = -1.0;
+               addOffset--;
+               work += addOffset;
+          }
+          /* Finish diagonal*/
+          for (iRow = 0; iRow < numberRowsModel; iRow++) {
+               diagonal_[iRow+numberTotal] = delta2;
+          }
+          /*check sizes*/
+          largest *= 1.0e-20;
+          largest = CoinMin(largest, CHOL_SMALL_VALUE);
+          doubleParameters_[10] = CoinMax(1.0e-20, largest);
+          integerParameters_[20] = 0;
+          doubleParameters_[3] = 0.0;
+          doubleParameters_[4] = COIN_DBL_MAX;
+          /* Set up LDL cutoff*/
+          integerParameters_[34] = numberTotal;
+          /* KKT*/
+          int * rowsDropped2 = new int[numberRows_];
+          CoinZeroN(rowsDropped2, numberRows_);
+#ifdef CHOL_COMPARE
+          if (numberRows_ < 200)
+               factorizePart3(rowsDropped2);
+#endif
+          factorizePart2(rowsDropped2);
+          newDropped = integerParameters_[20];
+          largest = doubleParameters_[3];
+          smallest = doubleParameters_[4];
+          if (model_->messageHandler()->logLevel() > 1)
+	    COIN_DETAIL_PRINT(std::cout << "Cholesky - largest " << largest << " smallest " << smallest << std::endl);
+          choleskyCondition_ = largest / smallest;
+          /* Should save adjustments in ..R_*/
+          int n1 = 0, n2 = 0;
+          CoinWorkDouble * primalR = model_->primalR();
+          CoinWorkDouble * dualR = model_->dualR();
+          for (iRow = 0; iRow < numberTotal; iRow++) {
+               if (rowsDropped2[iRow]) {
+                    n1++;
+                    /*printf("row region1 %d dropped\n",iRow);*/
+                    /*rowsDropped_[iRow]=1;*/
+                    rowsDropped_[iRow] = 0;
+                    primalR[iRow] = doubleParameters_[20];
+               } else {
+                    rowsDropped_[iRow] = 0;
+                    primalR[iRow] = 0.0;
+               }
+          }
+          for (; iRow < numberRows_; iRow++) {
+               if (rowsDropped2[iRow]) {
+                    n2++;
+                    /*printf("row region2 %d dropped\n",iRow);*/
+                    /*rowsDropped_[iRow]=1;*/
+                    rowsDropped_[iRow] = 0;
+                    dualR[iRow-numberTotal] = doubleParameters_[34];
+               } else {
+                    rowsDropped_[iRow] = 0;
+                    dualR[iRow-numberTotal] = 0.0;
+               }
+          }
+     }
+     return 0;
+}
+/* Factorize - filling in rowsDropped and returning number dropped */
+void
+ClpCholeskyDense::factorizePart3( int * rowsDropped)
+{
+     int iColumn;
+     longDouble * xx = sparseFactor_;
+     longDouble * yy = diagonal_;
+     diagonal_ = sparseFactor_ + 40000;
+     sparseFactor_ = diagonal_ + numberRows_;
+     /*memcpy(sparseFactor_,xx,sizeFactor_*sizeof(double));*/
+     CoinMemcpyN(xx, 40000, sparseFactor_);
+     CoinMemcpyN(yy, numberRows_, diagonal_);
+     int numberDropped = 0;
+     CoinWorkDouble largest = 0.0;
+     CoinWorkDouble smallest = COIN_DBL_MAX;
+     double dropValue = doubleParameters_[10];
+     int firstPositive = integerParameters_[34];
+     longDouble * work = sparseFactor_;
+     /* Allow for triangular*/
+     int addOffset = numberRows_ - 1;
+     work--;
+     for (iColumn = 0; iColumn < numberRows_; iColumn++) {
+          int iRow;
+          int addOffsetNow = numberRows_ - 1;;
+          longDouble * workNow = sparseFactor_ - 1 + iColumn;
+          CoinWorkDouble diagonalValue = diagonal_[iColumn];
+          for (iRow = 0; iRow < iColumn; iRow++) {
+               double aj = *workNow;
+               addOffsetNow--;
+               workNow += addOffsetNow;
+               diagonalValue -= aj * aj * workDouble_[iRow];
+          }
+          bool dropColumn = false;
+          if (iColumn < firstPositive) {
+               /* must be negative*/
+               if (diagonalValue <= -dropValue) {
+                    smallest = CoinMin(smallest, -diagonalValue);
+                    largest = CoinMax(largest, -diagonalValue);
+                    workDouble_[iColumn] = diagonalValue;
+                    diagonalValue = 1.0 / diagonalValue;
+               } else {
+                    dropColumn = true;
+                    workDouble_[iColumn] = -1.0e100;
+                    diagonalValue = 0.0;
+                    integerParameters_[20]++;
+               }
+          } else {
+               /* must be positive*/
+               if (diagonalValue >= dropValue) {
+                    smallest = CoinMin(smallest, diagonalValue);
+                    largest = CoinMax(largest, diagonalValue);
+                    workDouble_[iColumn] = diagonalValue;
+                    diagonalValue = 1.0 / diagonalValue;
+               } else {
+                    dropColumn = true;
+                    workDouble_[iColumn] = 1.0e100;
+                    diagonalValue = 0.0;
+                    integerParameters_[20]++;
+               }
+          }
+          if (!dropColumn) {
+               diagonal_[iColumn] = diagonalValue;
+               for (iRow = iColumn + 1; iRow < numberRows_; iRow++) {
+                    double value = work[iRow];
+                    workNow = sparseFactor_ - 1;
+                    int addOffsetNow = numberRows_ - 1;;
+                    for (int jColumn = 0; jColumn < iColumn; jColumn++) {
+                         double aj = workNow[iColumn];
+                         double multiplier = workDouble_[jColumn];
+                         double ai = workNow[iRow];
+                         addOffsetNow--;
+                         workNow += addOffsetNow;
+                         value -= aj * ai * multiplier;
+                    }
+                    work[iRow] = value * diagonalValue;
+               }
+          } else {
+               /* drop column*/
+               rowsDropped[iColumn] = 2;
+               numberDropped++;
+               diagonal_[iColumn] = 0.0;
+               for (iRow = iColumn + 1; iRow < numberRows_; iRow++) {
+                    work[iRow] = 0.0;
+               }
+          }
+          addOffset--;
+          work += addOffset;
+     }
+     doubleParameters_[3] = largest;
+     doubleParameters_[4] = smallest;
+     integerParameters_[20] = numberDropped;
+     sparseFactor_ = xx;
+     diagonal_ = yy;
+}
+/*#define POS_DEBUG*/
+#ifdef POS_DEBUG
+static int counter = 0;
+int ClpCholeskyDense::bNumber(const longDouble * array, int &iRow, int &iCol)
+{
+     int numberBlocks = (numberRows_ + BLOCK - 1) >> BLOCKSHIFT;
+     longDouble * a = sparseFactor_ + BLOCKSQ * numberBlocks;
+     int k = array - a;
+     assert ((k % BLOCKSQ) == 0);
+     iCol = 0;
+     int kk = k >> BLOCKSQSHIFT;
+     /*printf("%d %d %d %d\n",k,kk,BLOCKSQ,BLOCKSQSHIFT);*/
+     k = kk;
+     while (k >= numberBlocks) {
+          iCol++;
+          k -= numberBlocks;
+          numberBlocks--;
+     }
+     iRow = iCol + k;
+     counter++;
+     if(counter > 100000)
+          exit(77);
+     return kk;
+}
+#endif
+/* Factorize - filling in rowsDropped and returning number dropped */
+void
+ClpCholeskyDense::factorizePart2( int * rowsDropped)
+{
+     int iColumn;
+     /*longDouble * xx = sparseFactor_;*/
+     /*longDouble * yy = diagonal_;*/
+     /*diagonal_ = sparseFactor_ + 40000;*/
+     /*sparseFactor_=diagonal_ + numberRows_;*/
+     /*memcpy(sparseFactor_,xx,sizeFactor_*sizeof(double));*/
+     /*memcpy(sparseFactor_,xx,40000*sizeof(double));*/
+     /*memcpy(diagonal_,yy,numberRows_*sizeof(double));*/
+     int numberBlocks = (numberRows_ + BLOCK - 1) >> BLOCKSHIFT;
+     /* later align on boundary*/
+     longDouble * a = sparseFactor_ + BLOCKSQ * numberBlocks;
+     int n = numberRows_;
+     int nRound = numberRows_ & (~(BLOCK - 1));
+     /* adjust if exact*/
+     if (nRound == n)
+          nRound -= BLOCK;
+     int sizeLastBlock = n - nRound;
+     int get = n * (n - 1) / 2; /* ? as no diagonal*/
+     int block = numberBlocks * (numberBlocks + 1) / 2;
+     int ifOdd;
+     int rowLast;
+     if (sizeLastBlock != BLOCK) {
+          longDouble * aa = &a[(block-1)*BLOCKSQ];
+          rowLast = nRound - 1;
+          ifOdd = 1;
+          int put = BLOCKSQ;
+          /* do last separately*/
+          put -= (BLOCK - sizeLastBlock) * (BLOCK + 1);
+          for (iColumn = numberRows_ - 1; iColumn >= nRound; iColumn--) {
+               int put2 = put;
+               put -= BLOCK;
+               for (int iRow = numberRows_ - 1; iRow > iColumn; iRow--) {
+                    aa[--put2] = sparseFactor_[--get];
+                    assert (aa + put2 >= sparseFactor_ + get);
+               }
+               /* save diagonal as well*/
+               aa[--put2] = diagonal_[iColumn];
+          }
+          n = nRound;
+          block--;
+     } else {
+          /* exact fit*/
+          rowLast = numberRows_ - 1;
+          ifOdd = 0;
+     }
+     /* Now main loop*/
+     int nBlock = 0;
+     for (; n > 0; n -= BLOCK) {
+          longDouble * aa = &a[(block-1)*BLOCKSQ];
+          longDouble * aaLast = NULL;
+          int put = BLOCKSQ;
+          int putLast = 0;
+          /* see if we have small block*/
+          if (ifOdd) {
+               aaLast = &a[(block-1)*BLOCKSQ];
+               aa = aaLast - BLOCKSQ;
+               putLast = BLOCKSQ - BLOCK + sizeLastBlock;
+          }
+          for (iColumn = n - 1; iColumn >= n - BLOCK; iColumn--) {
+               if (aaLast) {
+                    /* last bit*/
+                    for (int iRow = numberRows_ - 1; iRow > rowLast; iRow--) {
+                         aaLast[--putLast] = sparseFactor_[--get];
+                         assert (aaLast + putLast >= sparseFactor_ + get);
+                    }
+                    putLast -= BLOCK - sizeLastBlock;
+               }
+               longDouble * aPut = aa;
+               int j = rowLast;
+               for (int jBlock = 0; jBlock <= nBlock; jBlock++) {
+                    int put2 = put;
+                    int last = CoinMax(j - BLOCK, iColumn);
+                    for (int iRow = j; iRow > last; iRow--) {
+                         aPut[--put2] = sparseFactor_[--get];
+                         assert (aPut + put2 >= sparseFactor_ + get);
+                    }
+                    if (j - BLOCK < iColumn) {
+                         /* save diagonal as well*/
+                         aPut[--put2] = diagonal_[iColumn];
+                    }
+                    j -= BLOCK;
+                    aPut -= BLOCKSQ;
+               }
+               put -= BLOCK;
+          }
+          nBlock++;
+          block -= nBlock + ifOdd;
+     }
+     ClpCholeskyDenseC  info;
+     info.diagonal_ = diagonal_;
+     info.doubleParameters_[0] = doubleParameters_[10];
+     info.integerParameters_[0] = integerParameters_[34];
+#ifndef CLP_CILK
+     ClpCholeskyCfactor(&info, a, numberRows_, numberBlocks,
+                        diagonal_, workDouble_, rowsDropped);
+#else
+     info.a = a;
+     info.n = numberRows_;
+     info.numberBlocks = numberBlocks;
+     info.work = workDouble_;
+     info.rowsDropped = rowsDropped;
+     info.integerParameters_[1] = model_->numberThreads();
+     ClpCholeskySpawn(&info);
+#endif
+     double largest = 0.0;
+     double smallest = COIN_DBL_MAX;
+     int numberDropped = 0;
+     for (int i = 0; i < numberRows_; i++) {
+          if (diagonal_[i]) {
+               largest = CoinMax(largest, CoinAbs(diagonal_[i]));
+               smallest = CoinMin(smallest, CoinAbs(diagonal_[i]));
+          } else {
+               numberDropped++;
+          }
+     }
+     doubleParameters_[3] = CoinMax(doubleParameters_[3], 1.0 / smallest);
+     doubleParameters_[4] = CoinMin(doubleParameters_[4], 1.0 / largest);
+     integerParameters_[20] += numberDropped;
+}
+/* Non leaf recursive factor*/
+void
+ClpCholeskyCfactor(ClpCholeskyDenseC * thisStruct, longDouble * a, int n, int numberBlocks,
+                   longDouble * diagonal, longDouble * work, int * rowsDropped)
+{
+     if (n <= BLOCK) {
+          ClpCholeskyCfactorLeaf(thisStruct, a, n, diagonal, work, rowsDropped);
+     } else {
+          int nb = number_blocks((n + 1) >> 1);
+          int nThis = number_rows(nb);
+          longDouble * aother;
+          int nLeft = n - nThis;
+          int nintri = (nb * (nb + 1)) >> 1;
+          int nbelow = (numberBlocks - nb) * nb;
+          ClpCholeskyCfactor(thisStruct, a, nThis, numberBlocks, diagonal, work, rowsDropped);
+          ClpCholeskyCtriRec(thisStruct, a, nThis, a + number_entries(nb), diagonal, work, nLeft, nb, 0, numberBlocks);
+          aother = a + number_entries(nintri + nbelow);
+          ClpCholeskyCrecTri(thisStruct, a + number_entries(nb), nLeft, nThis, nb, 0, aother, diagonal, work, numberBlocks);
+          ClpCholeskyCfactor(thisStruct, aother, nLeft,
+                             numberBlocks - nb, diagonal + nThis, work + nThis, rowsDropped);
+     }
+}
+/* Non leaf recursive triangle rectangle update*/
+void
+ClpCholeskyCtriRec(ClpCholeskyDenseC * thisStruct, longDouble * aTri, int nThis, longDouble * aUnder,
+                   longDouble * diagonal, longDouble * work,
+                   int nLeft, int iBlock, int jBlock,
+                   int numberBlocks)
+{
+     if (nThis <= BLOCK && nLeft <= BLOCK) {
+          ClpCholeskyCtriRecLeaf(/*thisStruct,*/ aTri, aUnder, diagonal, work, nLeft);
+     } else if (nThis < nLeft) {
+          int nb = number_blocks((nLeft + 1) >> 1);
+          int nLeft2 = number_rows(nb);
+          cilk_spawn ClpCholeskyCtriRec(thisStruct, aTri, nThis, aUnder, diagonal, work, nLeft2, iBlock, jBlock, numberBlocks);
+          ClpCholeskyCtriRec(thisStruct, aTri, nThis, aUnder + number_entries(nb), diagonal, work, nLeft - nLeft2,
+                             iBlock + nb, jBlock, numberBlocks);
+	  cilk_sync;
+     } else {
+          int nb = number_blocks((nThis + 1) >> 1);
+          int nThis2 = number_rows(nb);
+          longDouble * aother;
+          int kBlock = jBlock + nb;
+          int i;
+          int nintri = (nb * (nb + 1)) >> 1;
+          int nbelow = (numberBlocks - nb) * nb;
+          ClpCholeskyCtriRec(thisStruct, aTri, nThis2, aUnder, diagonal, work, nLeft, iBlock, jBlock, numberBlocks);
+          /* and rectangular update */
+          i = ((numberBlocks - jBlock) * (numberBlocks - jBlock - 1) -
+               (numberBlocks - jBlock - nb) * (numberBlocks - jBlock - nb - 1)) >> 1;
+          aother = aUnder + number_entries(i);
+          ClpCholeskyCrecRec(thisStruct, aTri + number_entries(nb), nThis - nThis2, nLeft, nThis2, aUnder, aother,
+                             work, kBlock, jBlock, numberBlocks);
+          ClpCholeskyCtriRec(thisStruct, aTri + number_entries(nintri + nbelow), nThis - nThis2, aother, diagonal + nThis2,
+                             work + nThis2, nLeft,
+                             iBlock - nb, kBlock - nb, numberBlocks - nb);
+     }
+}
+/* Non leaf recursive rectangle triangle update*/
+void
+ClpCholeskyCrecTri(ClpCholeskyDenseC * thisStruct, longDouble * aUnder, int nTri, int nDo,
+                   int iBlock, int jBlock, longDouble * aTri,
+                   longDouble * diagonal, longDouble * work,
+                   int numberBlocks)
+{
+     if (nTri <= BLOCK && nDo <= BLOCK) {
+          ClpCholeskyCrecTriLeaf(/*thisStruct,*/ aUnder, aTri,/*diagonal,*/work, nTri);
+     } else if (nTri < nDo) {
+          int nb = number_blocks((nDo + 1) >> 1);
+          int nDo2 = number_rows(nb);
+          longDouble * aother;
+          int i;
+          ClpCholeskyCrecTri(thisStruct, aUnder, nTri, nDo2, iBlock, jBlock, aTri, diagonal, work, numberBlocks);
+          i = ((numberBlocks - jBlock) * (numberBlocks - jBlock - 1) -
+               (numberBlocks - jBlock - nb) * (numberBlocks - jBlock - nb - 1)) >> 1;
+          aother = aUnder + number_entries(i);
+          ClpCholeskyCrecTri(thisStruct, aother, nTri, nDo - nDo2, iBlock - nb, jBlock, aTri, diagonal + nDo2,
+                             work + nDo2, numberBlocks - nb);
+     } else {
+          int nb = number_blocks((nTri + 1) >> 1);
+          int nTri2 = number_rows(nb);
+          longDouble * aother;
+          int i;
+          cilk_spawn ClpCholeskyCrecTri(thisStruct, aUnder, nTri2, nDo, iBlock, jBlock, aTri, diagonal, work, numberBlocks);
+          /* and rectangular update */
+          i = ((numberBlocks - iBlock) * (numberBlocks - iBlock + 1) -
+               (numberBlocks - iBlock - nb) * (numberBlocks - iBlock - nb + 1)) >> 1;
+          aother = aTri + number_entries(nb);
+          ClpCholeskyCrecRec(thisStruct, aUnder, nTri2, nTri - nTri2, nDo, aUnder + number_entries(nb), aother,
+                             work, iBlock, jBlock, numberBlocks);
+          ClpCholeskyCrecTri(thisStruct, aUnder + number_entries(nb), nTri - nTri2, nDo, iBlock + nb, jBlock,
+                             aTri + number_entries(i), diagonal, work, numberBlocks);
+	  cilk_sync;
+     }
+}
+/* Non leaf recursive rectangle rectangle update,
+   nUnder is number of rows in iBlock,
+   nUnderK is number of rows in kBlock
+*/
+void
+ClpCholeskyCrecRec(ClpCholeskyDenseC * thisStruct, longDouble * above, int nUnder, int nUnderK,
+                   int nDo, longDouble * aUnder, longDouble *aOther,
+                   longDouble * work,
+                   int iBlock, int jBlock,
+                   int numberBlocks)
+{
+     if (nDo <= BLOCK && nUnder <= BLOCK && nUnderK <= BLOCK) {
+          assert (nDo == BLOCK && nUnder == BLOCK);
+          ClpCholeskyCrecRecLeaf(/*thisStruct,*/ above , aUnder ,  aOther, work, nUnderK);
+     } else if (nDo <= nUnderK && nUnder <= nUnderK) {
+          int nb = number_blocks((nUnderK + 1) >> 1);
+          int nUnder2 = number_rows(nb);
+          cilk_spawn ClpCholeskyCrecRec(thisStruct, above, nUnder, nUnder2, nDo, aUnder, aOther, work,
+                             iBlock, jBlock, numberBlocks);
+          ClpCholeskyCrecRec(thisStruct, above, nUnder, nUnderK - nUnder2, nDo, aUnder + number_entries(nb),
+                             aOther + number_entries(nb), work, iBlock, jBlock, numberBlocks);
+	  cilk_sync;
+     } else if (nUnderK <= nDo && nUnder <= nDo) {
+          int nb = number_blocks((nDo + 1) >> 1);
+          int nDo2 = number_rows(nb);
+          int i;
+          ClpCholeskyCrecRec(thisStruct, above, nUnder, nUnderK, nDo2, aUnder, aOther, work,
+                             iBlock, jBlock, numberBlocks);
+          i = ((numberBlocks - jBlock) * (numberBlocks - jBlock - 1) -
+               (numberBlocks - jBlock - nb) * (numberBlocks - jBlock - nb - 1)) >> 1;
+          ClpCholeskyCrecRec(thisStruct, above + number_entries(i), nUnder, nUnderK, nDo - nDo2,
+                             aUnder + number_entries(i),
+                             aOther, work + nDo2,
+                             iBlock - nb, jBlock, numberBlocks - nb);
+     } else {
+          int nb = number_blocks((nUnder + 1) >> 1);
+          int nUnder2 = number_rows(nb);
+          int i;
+          cilk_spawn ClpCholeskyCrecRec(thisStruct, above, nUnder2, nUnderK, nDo, aUnder, aOther, work,
+                             iBlock, jBlock, numberBlocks);
+          i = ((numberBlocks - iBlock) * (numberBlocks - iBlock - 1) -
+               (numberBlocks - iBlock - nb) * (numberBlocks - iBlock - nb - 1)) >> 1;
+          ClpCholeskyCrecRec(thisStruct, above + number_entries(nb), nUnder - nUnder2, nUnderK, nDo, aUnder,
+                             aOther + number_entries(i), work, iBlock + nb, jBlock, numberBlocks);
+	  cilk_sync;
+     }
+}
+/* Leaf recursive factor*/
+void
+ClpCholeskyCfactorLeaf(ClpCholeskyDenseC * thisStruct, longDouble * a, int n,
+                       longDouble * diagonal, longDouble * work, int * rowsDropped)
+{
+     double dropValue = thisStruct->doubleParameters_[0];
+     int firstPositive = thisStruct->integerParameters_[0];
+     int rowOffset = static_cast<int>(diagonal - thisStruct->diagonal_);
+     int i, j, k;
+     CoinWorkDouble t00, temp1;
+     longDouble * aa;
+     aa = a - BLOCK;
+     for (j = 0; j < n; j ++) {
+          bool dropColumn;
+          CoinWorkDouble useT00;
+          aa += BLOCK;
+          t00 = aa[j];
+          for (k = 0; k < j; ++k) {
+               CoinWorkDouble multiplier = work[k];
+               t00 -= a[j + k * BLOCK] * a[j + k * BLOCK] * multiplier;
+          }
+          dropColumn = false;
+          useT00 = t00;
+          if (j + rowOffset < firstPositive) {
+               /* must be negative*/
+               if (t00 <= -dropValue) {
+                    /*aa[j]=t00;*/
+                    t00 = 1.0 / t00;
+               } else {
+                    dropColumn = true;
+                    /*aa[j]=-1.0e100;*/
+                    useT00 = -1.0e-100;
+                    t00 = 0.0;
+               }
+          } else {
+               /* must be positive*/
+               if (t00 >= dropValue) {
+                    /*aa[j]=t00;*/
+                    t00 = 1.0 / t00;
+               } else {
+                    dropColumn = true;
+                    /*aa[j]=1.0e100;*/
+                    useT00 = 1.0e-100;
+                    t00 = 0.0;
+               }
+          }
+          if (!dropColumn) {
+               diagonal[j] = t00;
+               work[j] = useT00;
+               temp1 = t00;
+               for (i = j + 1; i < n; i++) {
+                    t00 = aa[i];
+                    for (k = 0; k < j; ++k) {
+                         CoinWorkDouble multiplier = work[k];
+                         t00 -= a[i + k * BLOCK] * a[j + k * BLOCK] * multiplier;
+                    }
+                    aa[i] = t00 * temp1;
+               }
+          } else {
+               /* drop column*/
+               rowsDropped[j+rowOffset] = 2;
+               diagonal[j] = 0.0;
+               /*aa[j]=1.0e100;*/
+               work[j] = 1.0e100;
+               for (i = j + 1; i < n; i++) {
+                    aa[i] = 0.0;
+               }
+          }
+     }
+}
+/* Leaf recursive triangle rectangle update*/
+void
+ClpCholeskyCtriRecLeaf(/*ClpCholeskyDenseC * thisStruct,*/ longDouble * aTri, longDouble * aUnder, longDouble * diagonal, longDouble * work,
+          int nUnder)
+{
+#ifdef POS_DEBUG
+     int iru, icu;
+     int iu = bNumber(aUnder, iru, icu);
+     int irt, ict;
+     int it = bNumber(aTri, irt, ict);
+     /*printf("%d %d\n",iu,it);*/
+     printf("trirecleaf  under (%d,%d), tri (%d,%d)\n",
+            iru, icu, irt, ict);
+     assert (diagonal == thisStruct->diagonal_ + ict * BLOCK);
+#endif
+     int j;
+     longDouble * aa;
+#ifdef BLOCKUNROLL
+     if (nUnder == BLOCK) {
+          aa = aTri - 2 * BLOCK;
+          for (j = 0; j < BLOCK; j += 2) {
+               int i;
+               CoinWorkDouble temp0 = diagonal[j];
+               CoinWorkDouble temp1 = diagonal[j+1];
+               aa += 2 * BLOCK;
+               for ( i = 0; i < BLOCK; i += 2) {
+                    CoinWorkDouble at1;
+                    CoinWorkDouble t00 = aUnder[i+j*BLOCK];
+                    CoinWorkDouble t10 = aUnder[i+ BLOCK + j*BLOCK];
+                    CoinWorkDouble t01 = aUnder[i+1+j*BLOCK];
+                    CoinWorkDouble t11 = aUnder[i+1+ BLOCK + j*BLOCK];
+                    int k;
+                    for (k = 0; k < j; ++k) {
+                         CoinWorkDouble multiplier = work[k];
+                         CoinWorkDouble au0 = aUnder[i + k * BLOCK] * multiplier;
+                         CoinWorkDouble au1 = aUnder[i + 1 + k * BLOCK] * multiplier;
+                         CoinWorkDouble at0 = aTri[j + k * BLOCK];
+                         CoinWorkDouble at1 = aTri[j + 1 + k * BLOCK];
+                         t00 -= au0 * at0;
+                         t10 -= au0 * at1;
+                         t01 -= au1 * at0;
+                         t11 -= au1 * at1;
+                    }
+                    t00 *= temp0;
+                    at1 = aTri[j + 1 + j*BLOCK] * work[j];
+                    t10 -= t00 * at1;
+                    t01 *= temp0;
+                    t11 -= t01 * at1;
+                    aUnder[i+j*BLOCK] = t00;
+                    aUnder[i+1+j*BLOCK] = t01;
+                    aUnder[i+ BLOCK + j*BLOCK] = t10 * temp1;
+                    aUnder[i+1+ BLOCK + j*BLOCK] = t11 * temp1;
+               }
+          }
+     } else {
+#endif
+          aa = aTri - BLOCK;
+          for (j = 0; j < BLOCK; j ++) {
+               int i;
+               CoinWorkDouble temp1 = diagonal[j];
+               aa += BLOCK;
+               for (i = 0; i < nUnder; i++) {
+                    int k;
+                    CoinWorkDouble t00 = aUnder[i+j*BLOCK];
+                    for ( k = 0; k < j; ++k) {
+                         CoinWorkDouble multiplier = work[k];
+                         t00 -= aUnder[i + k * BLOCK] * aTri[j + k * BLOCK] * multiplier;
+                    }
+                    aUnder[i+j*BLOCK] = t00 * temp1;
+               }
+          }
+#ifdef BLOCKUNROLL
+     }
+#endif
+}
+/* Leaf recursive rectangle triangle update*/
+void ClpCholeskyCrecTriLeaf(/*ClpCholeskyDenseC * thisStruct,*/ longDouble * aUnder, longDouble * aTri,
+          /*longDouble * diagonal,*/ longDouble * work, int nUnder)
+{
+#ifdef POS_DEBUG
+     int iru, icu;
+     int iu = bNumber(aUnder, iru, icu);
+     int irt, ict;
+     int it = bNumber(aTri, irt, ict);
+     /*printf("%d %d\n",iu,it);*/
+     printf("rectrileaf  under (%d,%d), tri (%d,%d)\n",
+            iru, icu, irt, ict);
+     assert (diagonal == thisStruct->diagonal_ + icu * BLOCK);
+#endif
+     int i, j, k;
+     CoinWorkDouble t00;
+     longDouble * aa;
+#ifdef BLOCKUNROLL
+     if (nUnder == BLOCK) {
+          longDouble * aUnder2 = aUnder - 2;
+          aa = aTri - 2 * BLOCK;
+          for (j = 0; j < BLOCK; j += 2) {
+               CoinWorkDouble t00, t01, t10, t11;
+               aa += 2 * BLOCK;
+               aUnder2 += 2;
+               t00 = aa[j];
+               t01 = aa[j+1];
+               t10 = aa[j+1+BLOCK];
+               for (k = 0; k < BLOCK; ++k) {
+                    CoinWorkDouble multiplier = work[k];
+                    CoinWorkDouble a0 = aUnder2[k * BLOCK];
+                    CoinWorkDouble a1 = aUnder2[1 + k * BLOCK];
+                    CoinWorkDouble x0 = a0 * multiplier;
+                    CoinWorkDouble x1 = a1 * multiplier;
+                    t00 -= a0 * x0;
+                    t01 -= a1 * x0;
+                    t10 -= a1 * x1;
+               }
+               aa[j] = t00;
+               aa[j+1] = t01;
+               aa[j+1+BLOCK] = t10;
+               for (i = j + 2; i < BLOCK; i += 2) {
+                    t00 = aa[i];
+                    t01 = aa[i+BLOCK];
+                    t10 = aa[i+1];
+                    t11 = aa[i+1+BLOCK];
+                    for (k = 0; k < BLOCK; ++k) {
+                         CoinWorkDouble multiplier = work[k];
+                         CoinWorkDouble a0 = aUnder2[k * BLOCK] * multiplier;
+                         CoinWorkDouble a1 = aUnder2[1 + k * BLOCK] * multiplier;
+                         t00 -= aUnder[i + k * BLOCK] * a0;
+                         t01 -= aUnder[i + k * BLOCK] * a1;
+                         t10 -= aUnder[i + 1 + k * BLOCK] * a0;
+                         t11 -= aUnder[i + 1 + k * BLOCK] * a1;
+                    }
+                    aa[i] = t00;
+                    aa[i+BLOCK] = t01;
+                    aa[i+1] = t10;
+                    aa[i+1+BLOCK] = t11;
+               }
+          }
+     } else {
+#endif
+          aa = aTri - BLOCK;
+          for (j = 0; j < nUnder; j ++) {
+               aa += BLOCK;
+               for (i = j; i < nUnder; i++) {
+                    t00 = aa[i];
+                    for (k = 0; k < BLOCK; ++k) {
+                         CoinWorkDouble multiplier = work[k];
+                         t00 -= aUnder[i + k * BLOCK] * aUnder[j + k * BLOCK] * multiplier;
+                    }
+                    aa[i] = t00;
+               }
+          }
+#ifdef BLOCKUNROLL
+     }
+#endif
+}
+/* Leaf recursive rectangle rectangle update,
+   nUnder is number of rows in iBlock,
+   nUnderK is number of rows in kBlock
+*/
+void
+ClpCholeskyCrecRecLeaf(/*ClpCholeskyDenseC * thisStruct,*/
+     const longDouble * COIN_RESTRICT above,
+     const longDouble * COIN_RESTRICT aUnder,
+     longDouble * COIN_RESTRICT aOther,
+     const longDouble * COIN_RESTRICT work,
+     int nUnder)
+{
+#ifdef POS_DEBUG
+     int ira, ica;
+     int ia = bNumber(above, ira, ica);
+     int iru, icu;
+     int iu = bNumber(aUnder, iru, icu);
+     int iro, ico;
+     int io = bNumber(aOther, iro, ico);
+     /*printf("%d %d %d\n",ia,iu,io);*/
+     printf("recrecleaf above (%d,%d), under (%d,%d), other (%d,%d)\n",
+            ira, ica, iru, icu, iro, ico);
+#endif
+     int i, j, k;
+     longDouble * aa;
+#ifdef BLOCKUNROLL
+     aa = aOther - 4 * BLOCK;
+     if (nUnder == BLOCK) {
+          /*#define INTEL*/
+#ifdef INTEL
+          aa += 2 * BLOCK;
+          for (j = 0; j < BLOCK; j += 2) {
+               aa += 2 * BLOCK;
+               for (i = 0; i < BLOCK; i += 2) {
+                    CoinWorkDouble t00 = aa[i+0*BLOCK];
+                    CoinWorkDouble t10 = aa[i+1*BLOCK];
+                    CoinWorkDouble t01 = aa[i+1+0*BLOCK];
+                    CoinWorkDouble t11 = aa[i+1+1*BLOCK];
+                    for (k = 0; k < BLOCK; k++) {
+                         CoinWorkDouble multiplier = work[k];
+                         CoinWorkDouble a00 = aUnder[i+k*BLOCK] * multiplier;
+                         CoinWorkDouble a01 = aUnder[i+1+k*BLOCK] * multiplier;
+                         t00 -= a00 * above[j + 0 + k * BLOCK];
+                         t10 -= a00 * above[j + 1 + k * BLOCK];
+                         t01 -= a01 * above[j + 0 + k * BLOCK];
+                         t11 -= a01 * above[j + 1 + k * BLOCK];
+                    }
+                    aa[i+0*BLOCK] = t00;
+                    aa[i+1*BLOCK] = t10;
+                    aa[i+1+0*BLOCK] = t01;
+                    aa[i+1+1*BLOCK] = t11;
+               }
+          }
+#else
+          for (j = 0; j < BLOCK; j += 4) {
+               aa += 4 * BLOCK;
+               for (i = 0; i < BLOCK; i += 4) {
+                    CoinWorkDouble t00 = aa[i+0+0*BLOCK];
+                    CoinWorkDouble t10 = aa[i+0+1*BLOCK];
+                    CoinWorkDouble t20 = aa[i+0+2*BLOCK];
+                    CoinWorkDouble t30 = aa[i+0+3*BLOCK];
+                    CoinWorkDouble t01 = aa[i+1+0*BLOCK];
+                    CoinWorkDouble t11 = aa[i+1+1*BLOCK];
+                    CoinWorkDouble t21 = aa[i+1+2*BLOCK];
+                    CoinWorkDouble t31 = aa[i+1+3*BLOCK];
+                    CoinWorkDouble t02 = aa[i+2+0*BLOCK];
+                    CoinWorkDouble t12 = aa[i+2+1*BLOCK];
+                    CoinWorkDouble t22 = aa[i+2+2*BLOCK];
+                    CoinWorkDouble t32 = aa[i+2+3*BLOCK];
+                    CoinWorkDouble t03 = aa[i+3+0*BLOCK];
+                    CoinWorkDouble t13 = aa[i+3+1*BLOCK];
+                    CoinWorkDouble t23 = aa[i+3+2*BLOCK];
+                    CoinWorkDouble t33 = aa[i+3+3*BLOCK];
+                    const longDouble * COIN_RESTRICT aUnderNow = aUnder + i;
+                    const longDouble * COIN_RESTRICT aboveNow = above + j;
+                    for (k = 0; k < BLOCK; k++) {
+                         CoinWorkDouble multiplier = work[k];
+                         CoinWorkDouble a00 = aUnderNow[0] * multiplier;
+                         CoinWorkDouble a01 = aUnderNow[1] * multiplier;
+                         CoinWorkDouble a02 = aUnderNow[2] * multiplier;
+                         CoinWorkDouble a03 = aUnderNow[3] * multiplier;
+                         t00 -= a00 * aboveNow[0];
+                         t10 -= a00 * aboveNow[1];
+                         t20 -= a00 * aboveNow[2];
+                         t30 -= a00 * aboveNow[3];
+                         t01 -= a01 * aboveNow[0];
+                         t11 -= a01 * aboveNow[1];
+                         t21 -= a01 * aboveNow[2];
+                         t31 -= a01 * aboveNow[3];
+                         t02 -= a02 * aboveNow[0];
+                         t12 -= a02 * aboveNow[1];
+                         t22 -= a02 * aboveNow[2];
+                         t32 -= a02 * aboveNow[3];
+                         t03 -= a03 * aboveNow[0];
+                         t13 -= a03 * aboveNow[1];
+                         t23 -= a03 * aboveNow[2];
+                         t33 -= a03 * aboveNow[3];
+                         aUnderNow += BLOCK;
+                         aboveNow += BLOCK;
+                    }
+                    aa[i+0+0*BLOCK] = t00;
+                    aa[i+0+1*BLOCK] = t10;
+                    aa[i+0+2*BLOCK] = t20;
+                    aa[i+0+3*BLOCK] = t30;
+                    aa[i+1+0*BLOCK] = t01;
+                    aa[i+1+1*BLOCK] = t11;
+                    aa[i+1+2*BLOCK] = t21;
+                    aa[i+1+3*BLOCK] = t31;
+                    aa[i+2+0*BLOCK] = t02;
+                    aa[i+2+1*BLOCK] = t12;
+                    aa[i+2+2*BLOCK] = t22;
+                    aa[i+2+3*BLOCK] = t32;
+                    aa[i+3+0*BLOCK] = t03;
+                    aa[i+3+1*BLOCK] = t13;
+                    aa[i+3+2*BLOCK] = t23;
+                    aa[i+3+3*BLOCK] = t33;
+               }
+          }
+#endif
+     } else {
+          int odd = nUnder & 1;
+          int n = nUnder - odd;
+          for (j = 0; j < BLOCK; j += 4) {
+               aa += 4 * BLOCK;
+               for (i = 0; i < n; i += 2) {
+                    CoinWorkDouble t00 = aa[i+0*BLOCK];
+                    CoinWorkDouble t10 = aa[i+1*BLOCK];
+                    CoinWorkDouble t20 = aa[i+2*BLOCK];
+                    CoinWorkDouble t30 = aa[i+3*BLOCK];
+                    CoinWorkDouble t01 = aa[i+1+0*BLOCK];
+                    CoinWorkDouble t11 = aa[i+1+1*BLOCK];
+                    CoinWorkDouble t21 = aa[i+1+2*BLOCK];
+                    CoinWorkDouble t31 = aa[i+1+3*BLOCK];
+                    const longDouble * COIN_RESTRICT aUnderNow = aUnder + i;
+                    const longDouble * COIN_RESTRICT aboveNow = above + j;
+                    for (k = 0; k < BLOCK; k++) {
+                         CoinWorkDouble multiplier = work[k];
+                         CoinWorkDouble a00 = aUnderNow[0] * multiplier;
+                         CoinWorkDouble a01 = aUnderNow[1] * multiplier;
+                         t00 -= a00 * aboveNow[0];
+                         t10 -= a00 * aboveNow[1];
+                         t20 -= a00 * aboveNow[2];
+                         t30 -= a00 * aboveNow[3];
+                         t01 -= a01 * aboveNow[0];
+                         t11 -= a01 * aboveNow[1];
+                         t21 -= a01 * aboveNow[2];
+                         t31 -= a01 * aboveNow[3];
+                         aUnderNow += BLOCK;
+                         aboveNow += BLOCK;
+                    }
+                    aa[i+0*BLOCK] = t00;
+                    aa[i+1*BLOCK] = t10;
+                    aa[i+2*BLOCK] = t20;
+                    aa[i+3*BLOCK] = t30;
+                    aa[i+1+0*BLOCK] = t01;
+                    aa[i+1+1*BLOCK] = t11;
+                    aa[i+1+2*BLOCK] = t21;
+                    aa[i+1+3*BLOCK] = t31;
+               }
+               if (odd) {
+                    CoinWorkDouble t0 = aa[n+0*BLOCK];
+                    CoinWorkDouble t1 = aa[n+1*BLOCK];
+                    CoinWorkDouble t2 = aa[n+2*BLOCK];
+                    CoinWorkDouble t3 = aa[n+3*BLOCK];
+                    CoinWorkDouble a0;
+                    for (k = 0; k < BLOCK; k++) {
+                         a0 = aUnder[n+k*BLOCK] * work[k];
+                         t0 -= a0 * above[j + 0 + k * BLOCK];
+                         t1 -= a0 * above[j + 1 + k * BLOCK];
+                         t2 -= a0 * above[j + 2 + k * BLOCK];
+                         t3 -= a0 * above[j + 3 + k * BLOCK];
+                    }
+                    aa[n+0*BLOCK] = t0;
+                    aa[n+1*BLOCK] = t1;
+                    aa[n+2*BLOCK] = t2;
+                    aa[n+3*BLOCK] = t3;
+               }
+          }
+     }
+#else
+     aa = aOther - BLOCK;
+     for (j = 0; j < BLOCK; j ++) {
+          aa += BLOCK;
+          for (i = 0; i < nUnder; i++) {
+               CoinWorkDouble t00 = aa[i+0*BLOCK];
+               for (k = 0; k < BLOCK; k++) {
+                    CoinWorkDouble a00 = aUnder[i+k*BLOCK] * work[k];
+                    t00 -= a00 * above[j + k * BLOCK];
+               }
+               aa[i] = t00;
+          }
+     }
+#endif
+}
+/* Uses factorization to solve. */
+void
+ClpCholeskyDense::solve (CoinWorkDouble * region)
+{
+#ifdef CHOL_COMPARE
+     double * region2 = NULL;
+     if (numberRows_ < 200) {
+          longDouble * xx = sparseFactor_;
+          longDouble * yy = diagonal_;
+          diagonal_ = sparseFactor_ + 40000;
+          sparseFactor_ = diagonal_ + numberRows_;
+          region2 = ClpCopyOfArray(region, numberRows_);
+          int iRow, iColumn;
+          int addOffset = numberRows_ - 1;
+          longDouble * work = sparseFactor_ - 1;
+          for (iColumn = 0; iColumn < numberRows_; iColumn++) {
+               double value = region2[iColumn];
+               for (iRow = iColumn + 1; iRow < numberRows_; iRow++)
+                    region2[iRow] -= value * work[iRow];
+               addOffset--;
+               work += addOffset;
+          }
+          for (iColumn = numberRows_ - 1; iColumn >= 0; iColumn--) {
+               double value = region2[iColumn] * diagonal_[iColumn];
+               work -= addOffset;
+               addOffset++;
+               for (iRow = iColumn + 1; iRow < numberRows_; iRow++)
+                    value -= region2[iRow] * work[iRow];
+               region2[iColumn] = value;
+          }
+          sparseFactor_ = xx;
+          diagonal_ = yy;
+     }
+#endif
+     /*longDouble * xx = sparseFactor_;*/
+     /*longDouble * yy = diagonal_;*/
+     /*diagonal_ = sparseFactor_ + 40000;*/
+     /*sparseFactor_=diagonal_ + numberRows_;*/
+     int numberBlocks = (numberRows_ + BLOCK - 1) >> BLOCKSHIFT;
+     /* later align on boundary*/
+     longDouble * a = sparseFactor_ + BLOCKSQ * numberBlocks;
+     int iBlock;
+     longDouble * aa = a;
+     int iColumn;
+     for (iBlock = 0; iBlock < numberBlocks; iBlock++) {
+          int nChunk;
+          int jBlock;
+          int iDo = iBlock * BLOCK;
+          int base = iDo;
+          if (iDo + BLOCK > numberRows_) {
+               nChunk = numberRows_ - iDo;
+          } else {
+               nChunk = BLOCK;
+          }
+          solveF1(aa, nChunk, region + iDo);
+          for (jBlock = iBlock + 1; jBlock < numberBlocks; jBlock++) {
+               base += BLOCK;
+               aa += BLOCKSQ;
+               if (base + BLOCK > numberRows_) {
+                    nChunk = numberRows_ - base;
+               } else {
+                    nChunk = BLOCK;
+               }
+               solveF2(aa, nChunk, region + iDo, region + base);
+          }
+          aa += BLOCKSQ;
+     }
+     /* do diagonal outside*/
+     for (iColumn = 0; iColumn < numberRows_; iColumn++)
+          region[iColumn] *= diagonal_[iColumn];
+     int offset = ((numberBlocks * (numberBlocks + 1)) >> 1);
+     aa = a + number_entries(offset - 1);
+     int lBase = (numberBlocks - 1) * BLOCK;
+     for (iBlock = numberBlocks - 1; iBlock >= 0; iBlock--) {
+          int nChunk;
+          int jBlock;
+          int triBase = iBlock * BLOCK;
+          int iBase = lBase;
+          for (jBlock = iBlock + 1; jBlock < numberBlocks; jBlock++) {
+               if (iBase + BLOCK > numberRows_) {
+                    nChunk = numberRows_ - iBase;
+               } else {
+                    nChunk = BLOCK;
+               }
+               solveB2(aa, nChunk, region + triBase, region + iBase);
+               iBase -= BLOCK;
+               aa -= BLOCKSQ;
+          }
+          if (triBase + BLOCK > numberRows_) {
+               nChunk = numberRows_ - triBase;
+          } else {
+               nChunk = BLOCK;
+          }
+          solveB1(aa, nChunk, region + triBase);
+          aa -= BLOCKSQ;
+     }
+#ifdef CHOL_COMPARE
+     if (numberRows_ < 200) {
+          for (int i = 0; i < numberRows_; i++) {
+               assert(CoinAbs(region[i] - region2[i]) < 1.0e-3);
+          }
+          delete [] region2;
+     }
+#endif
+}
+/* Forward part of solve 1*/
+void
+ClpCholeskyDense::solveF1(longDouble * a, int n, CoinWorkDouble * region)
+{
+     int j, k;
+     CoinWorkDouble t00;
+     for (j = 0; j < n; j ++) {
+          t00 = region[j];
+          for (k = 0; k < j; ++k) {
+               t00 -= region[k] * a[j + k * BLOCK];
+          }
+          /*t00*=a[j + j * BLOCK];*/
+          region[j] = t00;
+     }
+}
+/* Forward part of solve 2*/
+void
+ClpCholeskyDense::solveF2(longDouble * a, int n, CoinWorkDouble * region, CoinWorkDouble * region2)
+{
+     int j, k;
+#ifdef BLOCKUNROLL
+     if (n == BLOCK) {
+          for (k = 0; k < BLOCK; k += 4) {
+               CoinWorkDouble t0 = region2[0];
+               CoinWorkDouble t1 = region2[1];
+               CoinWorkDouble t2 = region2[2];
+               CoinWorkDouble t3 = region2[3];
+               t0 -= region[0] * a[0 + 0 * BLOCK];
+               t1 -= region[0] * a[1 + 0 * BLOCK];
+               t2 -= region[0] * a[2 + 0 * BLOCK];
+               t3 -= region[0] * a[3 + 0 * BLOCK];
+
+               t0 -= region[1] * a[0 + 1 * BLOCK];
+               t1 -= region[1] * a[1 + 1 * BLOCK];
+               t2 -= region[1] * a[2 + 1 * BLOCK];
+               t3 -= region[1] * a[3 + 1 * BLOCK];
+
+               t0 -= region[2] * a[0 + 2 * BLOCK];
+               t1 -= region[2] * a[1 + 2 * BLOCK];
+               t2 -= region[2] * a[2 + 2 * BLOCK];
+               t3 -= region[2] * a[3 + 2 * BLOCK];
+
+               t0 -= region[3] * a[0 + 3 * BLOCK];
+               t1 -= region[3] * a[1 + 3 * BLOCK];
+               t2 -= region[3] * a[2 + 3 * BLOCK];
+               t3 -= region[3] * a[3 + 3 * BLOCK];
+
+               t0 -= region[4] * a[0 + 4 * BLOCK];
+               t1 -= region[4] * a[1 + 4 * BLOCK];
+               t2 -= region[4] * a[2 + 4 * BLOCK];
+               t3 -= region[4] * a[3 + 4 * BLOCK];
+
+               t0 -= region[5] * a[0 + 5 * BLOCK];
+               t1 -= region[5] * a[1 + 5 * BLOCK];
+               t2 -= region[5] * a[2 + 5 * BLOCK];
+               t3 -= region[5] * a[3 + 5 * BLOCK];
+
+               t0 -= region[6] * a[0 + 6 * BLOCK];
+               t1 -= region[6] * a[1 + 6 * BLOCK];
+               t2 -= region[6] * a[2 + 6 * BLOCK];
+               t3 -= region[6] * a[3 + 6 * BLOCK];
+
+               t0 -= region[7] * a[0 + 7 * BLOCK];
+               t1 -= region[7] * a[1 + 7 * BLOCK];
+               t2 -= region[7] * a[2 + 7 * BLOCK];
+               t3 -= region[7] * a[3 + 7 * BLOCK];
+#if BLOCK>8
+               t0 -= region[8] * a[0 + 8 * BLOCK];
+               t1 -= region[8] * a[1 + 8 * BLOCK];
+               t2 -= region[8] * a[2 + 8 * BLOCK];
+               t3 -= region[8] * a[3 + 8 * BLOCK];
+
+               t0 -= region[9] * a[0 + 9 * BLOCK];
+               t1 -= region[9] * a[1 + 9 * BLOCK];
+               t2 -= region[9] * a[2 + 9 * BLOCK];
+               t3 -= region[9] * a[3 + 9 * BLOCK];
+
+               t0 -= region[10] * a[0 + 10 * BLOCK];
+               t1 -= region[10] * a[1 + 10 * BLOCK];
+               t2 -= region[10] * a[2 + 10 * BLOCK];
+               t3 -= region[10] * a[3 + 10 * BLOCK];
+
+               t0 -= region[11] * a[0 + 11 * BLOCK];
+               t1 -= region[11] * a[1 + 11 * BLOCK];
+               t2 -= region[11] * a[2 + 11 * BLOCK];
+               t3 -= region[11] * a[3 + 11 * BLOCK];
+
+               t0 -= region[12] * a[0 + 12 * BLOCK];
+               t1 -= region[12] * a[1 + 12 * BLOCK];
+               t2 -= region[12] * a[2 + 12 * BLOCK];
+               t3 -= region[12] * a[3 + 12 * BLOCK];
+
+               t0 -= region[13] * a[0 + 13 * BLOCK];
+               t1 -= region[13] * a[1 + 13 * BLOCK];
+               t2 -= region[13] * a[2 + 13 * BLOCK];
+               t3 -= region[13] * a[3 + 13 * BLOCK];
+
+               t0 -= region[14] * a[0 + 14 * BLOCK];
+               t1 -= region[14] * a[1 + 14 * BLOCK];
+               t2 -= region[14] * a[2 + 14 * BLOCK];
+               t3 -= region[14] * a[3 + 14 * BLOCK];
+
+               t0 -= region[15] * a[0 + 15 * BLOCK];
+               t1 -= region[15] * a[1 + 15 * BLOCK];
+               t2 -= region[15] * a[2 + 15 * BLOCK];
+               t3 -= region[15] * a[3 + 15 * BLOCK];
+#endif
+               region2[0] = t0;
+               region2[1] = t1;
+               region2[2] = t2;
+               region2[3] = t3;
+               region2 += 4;
+               a += 4;
+          }
+     } else {
+#endif
+          for (k = 0; k < n; ++k) {
+               CoinWorkDouble t00 = region2[k];
+               for (j = 0; j < BLOCK; j ++) {
+                    t00 -= region[j] * a[k + j * BLOCK];
+               }
+               region2[k] = t00;
+          }
+#ifdef BLOCKUNROLL
+     }
+#endif
+}
+/* Backward part of solve 1*/
+void
+ClpCholeskyDense::solveB1(longDouble * a, int n, CoinWorkDouble * region)
+{
+     int j, k;
+     CoinWorkDouble t00;
+     for (j = n - 1; j >= 0; j --) {
+          t00 = region[j];
+          for (k = j + 1; k < n; ++k) {
+               t00 -= region[k] * a[k + j * BLOCK];
+          }
+          /*t00*=a[j + j * BLOCK];*/
+          region[j] = t00;
+     }
+}
+/* Backward part of solve 2*/
+void
+ClpCholeskyDense::solveB2(longDouble * a, int n, CoinWorkDouble * region, CoinWorkDouble * region2)
+{
+     int j, k;
+#ifdef BLOCKUNROLL
+     if (n == BLOCK) {
+          for (j = 0; j < BLOCK; j += 4) {
+               CoinWorkDouble t0 = region[0];
+               CoinWorkDouble t1 = region[1];
+               CoinWorkDouble t2 = region[2];
+               CoinWorkDouble t3 = region[3];
+               t0 -= region2[0] * a[0 + 0*BLOCK];
+               t1 -= region2[0] * a[0 + 1*BLOCK];
+               t2 -= region2[0] * a[0 + 2*BLOCK];
+               t3 -= region2[0] * a[0 + 3*BLOCK];
+
+               t0 -= region2[1] * a[1 + 0*BLOCK];
+               t1 -= region2[1] * a[1 + 1*BLOCK];
+               t2 -= region2[1] * a[1 + 2*BLOCK];
+               t3 -= region2[1] * a[1 + 3*BLOCK];
+
+               t0 -= region2[2] * a[2 + 0*BLOCK];
+               t1 -= region2[2] * a[2 + 1*BLOCK];
+               t2 -= region2[2] * a[2 + 2*BLOCK];
+               t3 -= region2[2] * a[2 + 3*BLOCK];
+
+               t0 -= region2[3] * a[3 + 0*BLOCK];
+               t1 -= region2[3] * a[3 + 1*BLOCK];
+               t2 -= region2[3] * a[3 + 2*BLOCK];
+               t3 -= region2[3] * a[3 + 3*BLOCK];
+
+               t0 -= region2[4] * a[4 + 0*BLOCK];
+               t1 -= region2[4] * a[4 + 1*BLOCK];
+               t2 -= region2[4] * a[4 + 2*BLOCK];
+               t3 -= region2[4] * a[4 + 3*BLOCK];
+
+               t0 -= region2[5] * a[5 + 0*BLOCK];
+               t1 -= region2[5] * a[5 + 1*BLOCK];
+               t2 -= region2[5] * a[5 + 2*BLOCK];
+               t3 -= region2[5] * a[5 + 3*BLOCK];
+
+               t0 -= region2[6] * a[6 + 0*BLOCK];
+               t1 -= region2[6] * a[6 + 1*BLOCK];
+               t2 -= region2[6] * a[6 + 2*BLOCK];
+               t3 -= region2[6] * a[6 + 3*BLOCK];
+
+               t0 -= region2[7] * a[7 + 0*BLOCK];
+               t1 -= region2[7] * a[7 + 1*BLOCK];
+               t2 -= region2[7] * a[7 + 2*BLOCK];
+               t3 -= region2[7] * a[7 + 3*BLOCK];
+#if BLOCK>8
+
+               t0 -= region2[8] * a[8 + 0*BLOCK];
+               t1 -= region2[8] * a[8 + 1*BLOCK];
+               t2 -= region2[8] * a[8 + 2*BLOCK];
+               t3 -= region2[8] * a[8 + 3*BLOCK];
+
+               t0 -= region2[9] * a[9 + 0*BLOCK];
+               t1 -= region2[9] * a[9 + 1*BLOCK];
+               t2 -= region2[9] * a[9 + 2*BLOCK];
+               t3 -= region2[9] * a[9 + 3*BLOCK];
+
+               t0 -= region2[10] * a[10 + 0*BLOCK];
+               t1 -= region2[10] * a[10 + 1*BLOCK];
+               t2 -= region2[10] * a[10 + 2*BLOCK];
+               t3 -= region2[10] * a[10 + 3*BLOCK];
+
+               t0 -= region2[11] * a[11 + 0*BLOCK];
+               t1 -= region2[11] * a[11 + 1*BLOCK];
+               t2 -= region2[11] * a[11 + 2*BLOCK];
+               t3 -= region2[11] * a[11 + 3*BLOCK];
+
+               t0 -= region2[12] * a[12 + 0*BLOCK];
+               t1 -= region2[12] * a[12 + 1*BLOCK];
+               t2 -= region2[12] * a[12 + 2*BLOCK];
+               t3 -= region2[12] * a[12 + 3*BLOCK];
+
+               t0 -= region2[13] * a[13 + 0*BLOCK];
+               t1 -= region2[13] * a[13 + 1*BLOCK];
+               t2 -= region2[13] * a[13 + 2*BLOCK];
+               t3 -= region2[13] * a[13 + 3*BLOCK];
+
+               t0 -= region2[14] * a[14 + 0*BLOCK];
+               t1 -= region2[14] * a[14 + 1*BLOCK];
+               t2 -= region2[14] * a[14 + 2*BLOCK];
+               t3 -= region2[14] * a[14 + 3*BLOCK];
+
+               t0 -= region2[15] * a[15 + 0*BLOCK];
+               t1 -= region2[15] * a[15 + 1*BLOCK];
+               t2 -= region2[15] * a[15 + 2*BLOCK];
+               t3 -= region2[15] * a[15 + 3*BLOCK];
+#endif
+               region[0] = t0;
+               region[1] = t1;
+               region[2] = t2;
+               region[3] = t3;
+               a += 4 * BLOCK;
+               region += 4;
+          }
+     } else {
+#endif
+          for (j = 0; j < BLOCK; j ++) {
+               CoinWorkDouble t00 = region[j];
+               for (k = 0; k < n; ++k) {
+                    t00 -= region2[k] * a[k + j * BLOCK];
+               }
+               region[j] = t00;
+          }
+#ifdef BLOCKUNROLL
+     }
+#endif
+}
diff --git a/cbits/coin/ClpCholeskyDense.hpp b/cbits/coin/ClpCholeskyDense.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpCholeskyDense.hpp
@@ -0,0 +1,162 @@
+/* $Id: ClpCholeskyDense.hpp 1910 2013-01-27 02:00:13Z stefan $ */
+/*
+  Copyright (C) 2003, International Business Machines Corporation
+  and others.  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+#ifndef ClpCholeskyDense_H
+#define ClpCholeskyDense_H
+
+#include "ClpCholeskyBase.hpp"
+class ClpMatrixBase;
+
+class ClpCholeskyDense : public ClpCholeskyBase {
+
+public:
+     /**@name Virtual methods that the derived classes provides  */
+     /**@{*/
+     /** Orders rows and saves pointer to matrix.and model.
+      Returns non-zero if not enough memory */
+     virtual int order(ClpInterior * model) ;
+     /** Does Symbolic factorization given permutation.
+         This is called immediately after order.  If user provides this then
+         user must provide factorize and solve.  Otherwise the default factorization is used
+         returns non-zero if not enough memory */
+     virtual int symbolic();
+     /** Factorize - filling in rowsDropped and returning number dropped.
+         If return code negative then out of memory */
+     virtual int factorize(const CoinWorkDouble * diagonal, int * rowsDropped) ;
+     /** Uses factorization to solve. */
+     virtual void solve (CoinWorkDouble * region) ;
+     /**@}*/
+
+     /**@name Non virtual methods for ClpCholeskyDense  */
+     /**@{*/
+     /** Reserves space.
+         If factor not NULL then just uses passed space
+      Returns non-zero if not enough memory */
+     int reserveSpace(const ClpCholeskyBase * factor, int numberRows) ;
+     /** Returns space needed */
+     CoinBigIndex space( int numberRows) const;
+     /** part 2 of Factorize - filling in rowsDropped */
+     void factorizePart2(int * rowsDropped) ;
+     /** part 2 of Factorize - filling in rowsDropped - blocked */
+     void factorizePart3(int * rowsDropped) ;
+     /** Forward part of solve */
+     void solveF1(longDouble * a, int n, CoinWorkDouble * region);
+     void solveF2(longDouble * a, int n, CoinWorkDouble * region, CoinWorkDouble * region2);
+     /** Backward part of solve */
+     void solveB1(longDouble * a, int n, CoinWorkDouble * region);
+     void solveB2(longDouble * a, int n, CoinWorkDouble * region, CoinWorkDouble * region2);
+     int bNumber(const longDouble * array, int &, int&);
+     /** A */
+     inline longDouble * aMatrix() const {
+          return sparseFactor_;
+     }
+     /** Diagonal */
+     inline longDouble * diagonal() const {
+          return diagonal_;
+     }
+     /**@}*/
+
+
+     /**@name Constructors, destructor */
+     /**@{*/
+     /** Default constructor. */
+     ClpCholeskyDense();
+     /** Destructor  */
+     virtual ~ClpCholeskyDense();
+     /** Copy */
+     ClpCholeskyDense(const ClpCholeskyDense&);
+     /** Assignment */
+     ClpCholeskyDense& operator=(const ClpCholeskyDense&);
+     /** Clone */
+     virtual ClpCholeskyBase * clone() const ;
+     /**@}*/
+
+
+private:
+     /**@name Data members */
+     /**@{*/
+     /** Just borrowing space */
+     bool borrowSpace_;
+     /**@}*/
+};
+
+/* structure for C */
+typedef struct {
+     longDouble * diagonal_;
+     longDouble * a;
+     longDouble * work;
+     int * rowsDropped;
+     double doubleParameters_[1]; /* corresponds to 10 */
+     int integerParameters_[2]; /* corresponds to 34, nThreads */
+     int n;
+     int numberBlocks;
+} ClpCholeskyDenseC;
+
+extern "C" {
+     void ClpCholeskySpawn(void *);
+}
+/**Non leaf recursive factor */
+void
+ClpCholeskyCfactor(ClpCholeskyDenseC * thisStruct,
+                   longDouble * a, int n, int numberBlocks,
+                   longDouble * diagonal, longDouble * work, int * rowsDropped);
+
+/**Non leaf recursive triangle rectangle update */
+void
+ClpCholeskyCtriRec(ClpCholeskyDenseC * thisStruct,
+                   longDouble * aTri, int nThis,
+                   longDouble * aUnder, longDouble * diagonal,
+                   longDouble * work,
+                   int nLeft, int iBlock, int jBlock,
+                   int numberBlocks);
+/**Non leaf recursive rectangle triangle update */
+void
+ClpCholeskyCrecTri(ClpCholeskyDenseC * thisStruct,
+                   longDouble * aUnder, int nTri, int nDo,
+                   int iBlock, int jBlock, longDouble * aTri,
+                   longDouble * diagonal, longDouble * work,
+                   int numberBlocks);
+/** Non leaf recursive rectangle rectangle update,
+    nUnder is number of rows in iBlock,
+    nUnderK is number of rows in kBlock
+*/
+void
+ClpCholeskyCrecRec(ClpCholeskyDenseC * thisStruct,
+                   longDouble * above, int nUnder, int nUnderK,
+                   int nDo, longDouble * aUnder, longDouble *aOther,
+                   longDouble * work,
+                   int iBlock, int jBlock,
+                   int numberBlocks);
+/**Leaf recursive factor */
+void
+ClpCholeskyCfactorLeaf(ClpCholeskyDenseC * thisStruct,
+                       longDouble * a, int n,
+                       longDouble * diagonal, longDouble * work,
+                       int * rowsDropped);
+/**Leaf recursive triangle rectangle update */
+void
+ClpCholeskyCtriRecLeaf(/*ClpCholeskyDenseC * thisStruct,*/
+     longDouble * aTri, longDouble * aUnder,
+     longDouble * diagonal, longDouble * work,
+     int nUnder);
+/**Leaf recursive rectangle triangle update */
+void
+ClpCholeskyCrecTriLeaf(/*ClpCholeskyDenseC * thisStruct, */
+     longDouble * aUnder, longDouble * aTri,
+     /*longDouble * diagonal,*/ longDouble * work, int nUnder);
+/** Leaf recursive rectangle rectangle update,
+    nUnder is number of rows in iBlock,
+    nUnderK is number of rows in kBlock
+*/
+void
+ClpCholeskyCrecRecLeaf(/*ClpCholeskyDenseC * thisStruct, */
+     const longDouble * COIN_RESTRICT above,
+     const longDouble * COIN_RESTRICT aUnder,
+     longDouble * COIN_RESTRICT aOther,
+     const longDouble * COIN_RESTRICT work,
+     int nUnder);
+#endif
diff --git a/cbits/coin/ClpCholeskyWssmp.hpp b/cbits/coin/ClpCholeskyWssmp.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpCholeskyWssmp.hpp
@@ -0,0 +1,60 @@
+/* $Id: ClpCholeskyWssmp.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpCholeskyWssmp_H
+#define ClpCholeskyWssmp_H
+
+#include "ClpCholeskyBase.hpp"
+class ClpMatrixBase;
+class ClpCholeskyDense;
+
+
+/** Wssmp class for Clp Cholesky factorization
+
+*/
+class ClpCholeskyWssmp : public ClpCholeskyBase {
+
+public:
+     /**@name Virtual methods that the derived classes provides  */
+     //@{
+     /** Orders rows and saves pointer to matrix.and model.
+      Returns non-zero if not enough memory */
+     virtual int order(ClpInterior * model) ;
+     /** Does Symbolic factorization given permutation.
+         This is called immediately after order.  If user provides this then
+         user must provide factorize and solve.  Otherwise the default factorization is used
+         returns non-zero if not enough memory */
+     virtual int symbolic();
+     /** Factorize - filling in rowsDropped and returning number dropped.
+         If return code negative then out of memory */
+     virtual int factorize(const double * diagonal, int * rowsDropped) ;
+     /** Uses factorization to solve. */
+     virtual void solve (double * region) ;
+     //@}
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Constructor which has dense columns activated.
+         Default is off. */
+     ClpCholeskyWssmp(int denseThreshold = -1);
+     /** Destructor  */
+     virtual ~ClpCholeskyWssmp();
+     // Copy
+     ClpCholeskyWssmp(const ClpCholeskyWssmp&);
+     // Assignment
+     ClpCholeskyWssmp& operator=(const ClpCholeskyWssmp&);
+     /// Clone
+     virtual ClpCholeskyBase * clone() const ;
+     //@}
+
+
+private:
+     /**@name Data members */
+     //@{
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpConfig.h b/cbits/coin/ClpConfig.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpConfig.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011
+ * All Rights Reserved.
+ * This code is published under the Eclipse Public License.
+ *
+ * $Id: ClpConfig.h 1734 2011-06-08 17:28:29Z stefan $
+ *
+ * Include file for the configuration of Clp.
+ *
+ * On systems where the code is configured with the configure script
+ * (i.e., compilation is always done with HAVE_CONFIG_H defined), this
+ * header file includes the automatically generated header file.
+ *
+ * On systems that are compiled in other ways (e.g., with the
+ * Developer Studio), a header files is included to define those
+ * macros that depend on the operating system and the compiler.  The
+ * macros that define the configuration of the particular user setting
+ * (e.g., presence of other COIN-OR packages or third party code) are set
+ * by the files config_*default.h. The project maintainer needs to remember
+ * to update these file and choose reasonable defines.
+ * A user can modify the default setting by editing the config_*default.h files.
+ */
+
+#ifndef __CLPCONFIG_H__
+#define __CLPCONFIG_H__
+
+#ifdef HAVE_CONFIG_H
+#ifdef CLP_BUILD
+#include "config.h"
+#else
+#include "config_clp.h"
+#endif
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef CLP_BUILD
+#include "config_default.h"
+#else
+#include "config_clp_default.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+#endif /*__CLPCONFIG_H__*/
diff --git a/cbits/coin/ClpConstraint.cpp b/cbits/coin/ClpConstraint.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpConstraint.cpp
@@ -0,0 +1,80 @@
+/* $Id: ClpConstraint.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpConstraint.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpConstraint::ClpConstraint () :
+     lastGradient_(NULL),
+     functionValue_(0.0),
+     offset_(0.0),
+     type_(-1),
+     rowNumber_(-1)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpConstraint::ClpConstraint (const ClpConstraint & source) :
+     lastGradient_(NULL),
+     functionValue_(source.functionValue_),
+     offset_(source.offset_),
+     type_(source.type_),
+     rowNumber_(source.rowNumber_)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpConstraint::~ClpConstraint ()
+{
+     delete [] lastGradient_;
+
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpConstraint &
+ClpConstraint::operator=(const ClpConstraint& rhs)
+{
+     if (this != &rhs) {
+          functionValue_ = rhs.functionValue_;
+          offset_ = rhs.offset_;
+          type_ = rhs.type_;
+          rowNumber_ = rhs.rowNumber_;
+          delete [] lastGradient_;
+          lastGradient_ = NULL;
+     }
+     return *this;
+}
+// Constraint function value
+double
+ClpConstraint::functionValue (const ClpSimplex * model,
+                              const double * solution,
+                              bool useScaling,
+                              bool refresh) const
+{
+     double offset;
+     double value;
+     int n = model->numberColumns();
+     double * grad = new double [n];
+     gradient(model, solution, grad, value, offset, useScaling, refresh);
+     delete [] grad;
+     return value;
+}
+
diff --git a/cbits/coin/ClpConstraint.hpp b/cbits/coin/ClpConstraint.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpConstraint.hpp
@@ -0,0 +1,125 @@
+/* $Id: ClpConstraint.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpConstraint_H
+#define ClpConstraint_H
+
+
+//#############################################################################
+class ClpSimplex;
+class ClpModel;
+
+/** Constraint Abstract Base Class
+
+Abstract Base Class for describing a constraint or objective function
+
+*/
+class ClpConstraint  {
+
+public:
+
+     ///@name Stuff
+     //@{
+
+     /** Fills gradient.  If Linear then solution may be NULL,
+         also returns true value of function and offset so we can use x not deltaX in constraint
+         If refresh is false then uses last solution
+         Uses model for scaling
+         Returns non-zero if gradient undefined at current solution
+     */
+     virtual int gradient(const ClpSimplex * model,
+                          const double * solution,
+                          double * gradient,
+                          double & functionValue ,
+                          double & offset,
+                          bool useScaling = false,
+                          bool refresh = true) const = 0;
+     /// Constraint function value
+     virtual double functionValue (const ClpSimplex * model,
+                                   const double * solution,
+                                   bool useScaling = false,
+                                   bool refresh = true) const ;
+     /// Resize constraint
+     virtual void resize(int newNumberColumns) = 0;
+     /// Delete columns in  constraint
+     virtual void deleteSome(int numberToDelete, const int * which) = 0;
+     /// Scale constraint
+     virtual void reallyScale(const double * columnScale) = 0;
+     /** Given a zeroed array sets nonlinear columns to 1.
+         Returns number of nonlinear columns
+      */
+     virtual int markNonlinear(char * which) const = 0;
+     /** Given a zeroed array sets possible nonzero coefficients to 1.
+         Returns number of nonzeros
+      */
+     virtual int markNonzero(char * which) const = 0;
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpConstraint();
+
+     /// Copy constructor
+     ClpConstraint(const ClpConstraint &);
+
+     /// Assignment operator
+     ClpConstraint & operator=(const ClpConstraint& rhs);
+
+     /// Destructor
+     virtual ~ClpConstraint ();
+
+     /// Clone
+     virtual ClpConstraint * clone() const = 0;
+
+     //@}
+
+     ///@name Other
+     //@{
+     /// Returns type, 0 linear, 1 nonlinear
+     inline int type() {
+          return type_;
+     }
+     /// Row number (-1 is objective)
+     inline int rowNumber() const {
+          return rowNumber_;
+     }
+
+     /// Number of possible coefficients in gradient
+     virtual int numberCoefficients() const = 0;
+
+     /// Stored constraint function value
+     inline double functionValue () const {
+          return functionValue_;
+     }
+
+     /// Constraint offset
+     inline double offset () const {
+          return offset_;
+     }
+     /// Say we have new primal solution - so may need to recompute
+     virtual void newXValues() {}
+     //@}
+
+     //---------------------------------------------------------------------------
+
+protected:
+     ///@name Protected member data
+     //@{
+     /// Gradient at last evaluation
+     mutable double * lastGradient_;
+     /// Value of non-linear part of constraint
+     mutable double functionValue_;
+     /// Value of offset for constraint
+     mutable double offset_;
+     /// Type of constraint - linear is 1
+     int type_;
+     /// Row number (-1 is objective)
+     int rowNumber_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpConstraintLinear.cpp b/cbits/coin/ClpConstraintLinear.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpConstraintLinear.cpp
@@ -0,0 +1,206 @@
+/* $Id: ClpConstraintLinear.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpConstraintLinear.hpp"
+#include "CoinSort.hpp"
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpConstraintLinear::ClpConstraintLinear ()
+     : ClpConstraint()
+{
+     type_ = 0;
+     column_ = NULL;
+     coefficient_ = NULL;
+     numberColumns_ = 0;
+     numberCoefficients_ = 0;
+}
+
+//-------------------------------------------------------------------
+// Useful Constructor
+//-------------------------------------------------------------------
+ClpConstraintLinear::ClpConstraintLinear (int row, int numberCoefficents ,
+          int numberColumns,
+          const int * column, const double * coefficient)
+     : ClpConstraint()
+{
+     type_ = 0;
+     rowNumber_ = row;
+     numberColumns_ = numberColumns;
+     numberCoefficients_ = numberCoefficents;
+     column_ = CoinCopyOfArray(column, numberCoefficients_);
+     coefficient_ = CoinCopyOfArray(coefficient, numberCoefficients_);
+     CoinSort_2(column_, column_ + numberCoefficients_, coefficient_);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpConstraintLinear::ClpConstraintLinear (const ClpConstraintLinear & rhs)
+     : ClpConstraint(rhs)
+{
+     numberColumns_ = rhs.numberColumns_;
+     numberCoefficients_ = rhs.numberCoefficients_;
+     column_ = CoinCopyOfArray(rhs.column_, numberCoefficients_);
+     coefficient_ = CoinCopyOfArray(rhs.coefficient_, numberCoefficients_);
+}
+
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpConstraintLinear::~ClpConstraintLinear ()
+{
+     delete [] column_;
+     delete [] coefficient_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpConstraintLinear &
+ClpConstraintLinear::operator=(const ClpConstraintLinear& rhs)
+{
+     if (this != &rhs) {
+          delete [] column_;
+          delete [] coefficient_;
+          numberColumns_ = rhs.numberColumns_;
+          numberCoefficients_ = rhs.numberCoefficients_;
+          column_ = CoinCopyOfArray(rhs.column_, numberCoefficients_);
+          coefficient_ = CoinCopyOfArray(rhs.coefficient_, numberCoefficients_);
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpConstraint * ClpConstraintLinear::clone() const
+{
+     return new ClpConstraintLinear(*this);
+}
+
+// Returns gradient
+int
+ClpConstraintLinear::gradient(const ClpSimplex * model,
+                              const double * solution,
+                              double * gradient,
+                              double & functionValue,
+                              double & offset,
+                              bool useScaling,
+                              bool refresh) const
+{
+     if (refresh || !lastGradient_) {
+          functionValue_ = 0.0;
+          if (!lastGradient_)
+               lastGradient_ = new double[numberColumns_];
+          CoinZeroN(lastGradient_, numberColumns_);
+          bool scaling = (model && model->rowScale() && useScaling);
+          if (!scaling) {
+               for (int i = 0; i < numberCoefficients_; i++) {
+                    int iColumn = column_[i];
+                    double value = solution[iColumn];
+                    double coefficient = coefficient_[i];
+                    functionValue_ += value * coefficient;
+                    lastGradient_[iColumn] = coefficient;
+               }
+          } else {
+               // do scaling
+               const double * columnScale = model->columnScale();
+               for (int i = 0; i < numberCoefficients_; i++) {
+                    int iColumn = column_[i];
+                    double value = solution[iColumn]; // already scaled
+                    double coefficient = coefficient_[i] * columnScale[iColumn];
+                    functionValue_ += value * coefficient;
+                    lastGradient_[iColumn] = coefficient;
+               }
+          }
+     }
+     functionValue = functionValue_;
+     offset = 0.0;
+     CoinMemcpyN(lastGradient_, numberColumns_, gradient);
+     return 0;
+}
+// Resize constraint
+void
+ClpConstraintLinear::resize(int newNumberColumns)
+{
+     if (numberColumns_ != newNumberColumns) {
+#ifndef NDEBUG
+          int lastColumn = column_[numberCoefficients_-1];
+#endif
+          assert (newNumberColumns > lastColumn);
+          delete [] lastGradient_;
+          lastGradient_ = NULL;
+          numberColumns_ = newNumberColumns;
+     }
+}
+// Delete columns in  constraint
+void
+ClpConstraintLinear::deleteSome(int numberToDelete, const int * which)
+{
+     if (numberToDelete) {
+          int i ;
+          char * deleted = new char[numberColumns_];
+          memset(deleted, 0, numberColumns_ * sizeof(char));
+          for (i = 0; i < numberToDelete; i++) {
+               int j = which[i];
+               if (j >= 0 && j < numberColumns_ && !deleted[j]) {
+                    deleted[j] = 1;
+               }
+          }
+          int n = 0;
+          for (i = 0; i < numberCoefficients_; i++) {
+               int iColumn = column_[i];
+               if (!deleted[iColumn]) {
+                    column_[n] = iColumn;
+                    coefficient_[n++] = coefficient_[i];
+               }
+          }
+          numberCoefficients_ = n;
+     }
+}
+// Scale constraint
+void
+ClpConstraintLinear::reallyScale(const double * columnScale)
+{
+     for (int i = 0; i < numberCoefficients_; i++) {
+          int iColumn = column_[i];
+          coefficient_[i] *= columnScale[iColumn];
+     }
+}
+/* Given a zeroed array sets nonlinear columns to 1.
+   Returns number of nonlinear columns
+*/
+int
+ClpConstraintLinear::markNonlinear(char *) const
+{
+     return 0;
+}
+/* Given a zeroed array sets possible nonzero coefficients to 1.
+   Returns number of nonzeros
+*/
+int
+ClpConstraintLinear::markNonzero(char * which) const
+{
+     for (int i = 0; i < numberCoefficients_; i++) {
+          int iColumn = column_[i];
+          which[iColumn] = 1;
+     }
+     return numberCoefficients_;
+}
+// Number of coefficients
+int
+ClpConstraintLinear::numberCoefficients() const
+{
+     return numberCoefficients_;
+}
diff --git a/cbits/coin/ClpConstraintLinear.hpp b/cbits/coin/ClpConstraintLinear.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpConstraintLinear.hpp
@@ -0,0 +1,110 @@
+/* $Id: ClpConstraintLinear.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpConstraintLinear_H
+#define ClpConstraintLinear_H
+
+#include "ClpConstraint.hpp"
+
+//#############################################################################
+
+/** Linear Constraint Class
+
+*/
+
+class ClpConstraintLinear : public ClpConstraint {
+
+public:
+
+     ///@name Stuff
+     //@{
+
+
+     /** Fills gradient.  If Linear then solution may be NULL,
+         also returns true value of function and offset so we can use x not deltaX in constraint
+         If refresh is false then uses last solution
+         Uses model for scaling
+         Returns non-zero if gradient udefined at current solution
+     */
+     virtual int gradient(const ClpSimplex * model,
+                          const double * solution,
+                          double * gradient,
+                          double & functionValue ,
+                          double & offset,
+                          bool useScaling = false,
+                          bool refresh = true) const ;
+     /// Resize constraint
+     virtual void resize(int newNumberColumns) ;
+     /// Delete columns in  constraint
+     virtual void deleteSome(int numberToDelete, const int * which) ;
+     /// Scale constraint
+     virtual void reallyScale(const double * columnScale) ;
+     /** Given a zeroed array sets nonlinear columns to 1.
+         Returns number of nonlinear columns
+      */
+     virtual int markNonlinear(char * which) const ;
+     /** Given a zeroed array sets possible nonzero coefficients to 1.
+         Returns number of nonzeros
+      */
+     virtual int markNonzero(char * which) const;
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpConstraintLinear();
+
+     /// Constructor from constraint
+     ClpConstraintLinear(int row, int numberCoefficients, int numberColumns,
+                         const int * column, const double * element);
+
+     /** Copy constructor .
+     */
+     ClpConstraintLinear(const ClpConstraintLinear & rhs);
+
+     /// Assignment operator
+     ClpConstraintLinear & operator=(const ClpConstraintLinear& rhs);
+
+     /// Destructor
+     virtual ~ClpConstraintLinear ();
+
+     /// Clone
+     virtual ClpConstraint * clone() const;
+     //@}
+     ///@name Gets and sets
+     //@{
+     /// Number of coefficients
+     virtual int numberCoefficients() const;
+     /// Number of columns in linear constraint
+     inline int numberColumns() const {
+          return numberColumns_;
+     }
+     /// Columns
+     inline const int * column() const {
+          return column_;
+     }
+     /// Coefficients
+     inline const double * coefficient() const {
+          return coefficient_;
+     }
+     //@}
+
+     //---------------------------------------------------------------------------
+
+private:
+     ///@name Private member data
+     /// Column
+     int * column_;
+     /// Coefficients
+     double * coefficient_;
+     /// Useful to have number of columns about
+     int numberColumns_;
+     /// Number of coefficients
+     int numberCoefficients_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpConstraintQuadratic.cpp b/cbits/coin/ClpConstraintQuadratic.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpConstraintQuadratic.cpp
@@ -0,0 +1,289 @@
+/* $Id: ClpConstraintQuadratic.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpConstraintQuadratic.hpp"
+#include "CoinSort.hpp"
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpConstraintQuadratic::ClpConstraintQuadratic ()
+     : ClpConstraint()
+{
+     type_ = 0;
+     start_ = NULL;
+     column_ = NULL;
+     coefficient_ = NULL;
+     numberColumns_ = 0;
+     numberCoefficients_ = 0;
+     numberQuadraticColumns_ = 0;
+}
+
+//-------------------------------------------------------------------
+// Useful Constructor
+//-------------------------------------------------------------------
+ClpConstraintQuadratic::ClpConstraintQuadratic (int row, int numberQuadraticColumns ,
+          int numberColumns, const CoinBigIndex * start,
+          const int * column, const double * coefficient)
+     : ClpConstraint()
+{
+     type_ = 0;
+     rowNumber_ = row;
+     numberColumns_ = numberColumns;
+     numberQuadraticColumns_ = numberQuadraticColumns;
+     start_ = CoinCopyOfArray(start, numberQuadraticColumns + 1);
+     int numberElements = start_[numberQuadraticColumns_];
+     column_ = CoinCopyOfArray(column, numberElements);
+     coefficient_ = CoinCopyOfArray(coefficient, numberElements);
+     char * mark = new char [numberQuadraticColumns_];
+     memset(mark, 0, numberQuadraticColumns_);
+     int iColumn;
+     for (iColumn = 0; iColumn < numberQuadraticColumns_; iColumn++) {
+          CoinBigIndex j;
+          for (j = start_[iColumn]; j < start_[iColumn+1]; j++) {
+               int jColumn = column_[j];
+               if (jColumn >= 0) {
+                    assert (jColumn < numberQuadraticColumns_);
+                    mark[jColumn] = 1;
+               }
+               mark[iColumn] = 1;
+          }
+     }
+     numberCoefficients_ = 0;
+     for (iColumn = 0; iColumn < numberQuadraticColumns_; iColumn++) {
+          if (mark[iColumn])
+               numberCoefficients_++;
+     }
+     delete [] mark;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpConstraintQuadratic::ClpConstraintQuadratic (const ClpConstraintQuadratic & rhs)
+     : ClpConstraint(rhs)
+{
+     numberColumns_ = rhs.numberColumns_;
+     numberCoefficients_ = rhs.numberCoefficients_;
+     numberQuadraticColumns_ = rhs.numberQuadraticColumns_;
+     start_ = CoinCopyOfArray(rhs.start_, numberQuadraticColumns_ + 1);
+     int numberElements = start_[numberQuadraticColumns_];
+     column_ = CoinCopyOfArray(rhs.column_, numberElements);
+     coefficient_ = CoinCopyOfArray(rhs.coefficient_, numberElements);
+}
+
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpConstraintQuadratic::~ClpConstraintQuadratic ()
+{
+     delete [] start_;
+     delete [] column_;
+     delete [] coefficient_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpConstraintQuadratic &
+ClpConstraintQuadratic::operator=(const ClpConstraintQuadratic& rhs)
+{
+     if (this != &rhs) {
+          delete [] start_;
+          delete [] column_;
+          delete [] coefficient_;
+          numberColumns_ = rhs.numberColumns_;
+          numberCoefficients_ = rhs.numberCoefficients_;
+          numberQuadraticColumns_ = rhs.numberQuadraticColumns_;
+          start_ = CoinCopyOfArray(rhs.start_, numberQuadraticColumns_ + 1);
+          int numberElements = start_[numberQuadraticColumns_];
+          column_ = CoinCopyOfArray(rhs.column_, numberElements);
+          coefficient_ = CoinCopyOfArray(rhs.coefficient_, numberElements);
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpConstraint * ClpConstraintQuadratic::clone() const
+{
+     return new ClpConstraintQuadratic(*this);
+}
+
+// Returns gradient
+int
+ClpConstraintQuadratic::gradient(const ClpSimplex * model,
+                                 const double * solution,
+                                 double * gradient,
+                                 double & functionValue,
+                                 double & offset,
+                                 bool useScaling,
+                                 bool refresh) const
+{
+     if (refresh || !lastGradient_) {
+          offset_ = 0.0;
+          functionValue_ = 0.0;
+          if (!lastGradient_)
+               lastGradient_ = new double[numberColumns_];
+          CoinZeroN(lastGradient_, numberColumns_);
+          bool scaling = (model && model->rowScale() && useScaling);
+          if (!scaling) {
+               int iColumn;
+               for (iColumn = 0; iColumn < numberQuadraticColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    CoinBigIndex j;
+                    for (j = start_[iColumn]; j < start_[iColumn+1]; j++) {
+                         int jColumn = column_[j];
+                         if (jColumn >= 0) {
+                              double valueJ = solution[jColumn];
+                              double elementValue = coefficient_[j];
+                              if (iColumn != jColumn) {
+                                   offset_ -= valueI * valueJ * elementValue;
+                                   double gradientI = valueJ * elementValue;
+                                   double gradientJ = valueI * elementValue;
+                                   lastGradient_[iColumn] += gradientI;
+                                   lastGradient_[jColumn] += gradientJ;
+                              } else {
+                                   offset_ -= 0.5 * valueI * valueI * elementValue;
+                                   double gradientI = valueI * elementValue;
+                                   lastGradient_[iColumn] += gradientI;
+                              }
+                         } else {
+                              // linear part
+                              lastGradient_[iColumn] += coefficient_[j];
+                              functionValue_ += valueI * coefficient_[j];
+                         }
+                    }
+               }
+               functionValue_ -= offset_;
+          } else {
+               abort();
+               // do scaling
+               const double * columnScale = model->columnScale();
+               for (int i = 0; i < numberCoefficients_; i++) {
+                    int iColumn = column_[i];
+                    double value = solution[iColumn]; // already scaled
+                    double coefficient = coefficient_[i] * columnScale[iColumn];
+                    functionValue_ += value * coefficient;
+                    lastGradient_[iColumn] = coefficient;
+               }
+          }
+     }
+     functionValue = functionValue_;
+     offset = offset_;
+     CoinMemcpyN(lastGradient_, numberColumns_, gradient);
+     return 0;
+}
+// Resize constraint
+void
+ClpConstraintQuadratic::resize(int newNumberColumns)
+{
+     if (numberColumns_ != newNumberColumns) {
+          abort();
+#ifndef NDEBUG
+          int lastColumn = column_[numberCoefficients_-1];
+#endif
+          assert (newNumberColumns > lastColumn);
+          delete [] lastGradient_;
+          lastGradient_ = NULL;
+          numberColumns_ = newNumberColumns;
+     }
+}
+// Delete columns in  constraint
+void
+ClpConstraintQuadratic::deleteSome(int numberToDelete, const int * which)
+{
+     if (numberToDelete) {
+          abort();
+          int i ;
+          char * deleted = new char[numberColumns_];
+          memset(deleted, 0, numberColumns_ * sizeof(char));
+          for (i = 0; i < numberToDelete; i++) {
+               int j = which[i];
+               if (j >= 0 && j < numberColumns_ && !deleted[j]) {
+                    deleted[j] = 1;
+               }
+          }
+          int n = 0;
+          for (i = 0; i < numberCoefficients_; i++) {
+               int iColumn = column_[i];
+               if (!deleted[iColumn]) {
+                    column_[n] = iColumn;
+                    coefficient_[n++] = coefficient_[i];
+               }
+          }
+          numberCoefficients_ = n;
+     }
+}
+// Scale constraint
+void
+ClpConstraintQuadratic::reallyScale(const double * )
+{
+     abort();
+}
+/* Given a zeroed array sets nonquadratic columns to 1.
+   Returns number of nonlinear columns
+*/
+int
+ClpConstraintQuadratic::markNonlinear(char * which) const
+{
+     int iColumn;
+     for (iColumn = 0; iColumn < numberQuadraticColumns_; iColumn++) {
+          CoinBigIndex j;
+          for (j = start_[iColumn]; j < start_[iColumn+1]; j++) {
+               int jColumn = column_[j];
+               if (jColumn >= 0) {
+                    assert (jColumn < numberQuadraticColumns_);
+                    which[jColumn] = 1;
+                    which[iColumn] = 1;
+               }
+          }
+     }
+     int numberCoefficients = 0;
+     for (iColumn = 0; iColumn < numberQuadraticColumns_; iColumn++) {
+          if (which[iColumn])
+               numberCoefficients++;
+     }
+     return numberCoefficients;
+}
+/* Given a zeroed array sets possible nonzero coefficients to 1.
+   Returns number of nonzeros
+*/
+int
+ClpConstraintQuadratic::markNonzero(char * which) const
+{
+     int iColumn;
+     for (iColumn = 0; iColumn < numberQuadraticColumns_; iColumn++) {
+          CoinBigIndex j;
+          for (j = start_[iColumn]; j < start_[iColumn+1]; j++) {
+               int jColumn = column_[j];
+               if (jColumn >= 0) {
+                    assert (jColumn < numberQuadraticColumns_);
+                    which[jColumn] = 1;
+               }
+               which[iColumn] = 1;
+          }
+     }
+     int numberCoefficients = 0;
+     for (iColumn = 0; iColumn < numberQuadraticColumns_; iColumn++) {
+          if (which[iColumn])
+               numberCoefficients++;
+     }
+     return numberCoefficients;
+}
+// Number of coefficients
+int
+ClpConstraintQuadratic::numberCoefficients() const
+{
+     return numberCoefficients_;
+}
diff --git a/cbits/coin/ClpConstraintQuadratic.hpp b/cbits/coin/ClpConstraintQuadratic.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpConstraintQuadratic.hpp
@@ -0,0 +1,119 @@
+/* $Id: ClpConstraintQuadratic.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpConstraintQuadratic_H
+#define ClpConstraintQuadratic_H
+
+#include "ClpConstraint.hpp"
+
+//#############################################################################
+
+/** Quadratic Constraint Class
+
+*/
+
+class ClpConstraintQuadratic : public ClpConstraint {
+
+public:
+
+     ///@name Stuff
+     //@{
+
+
+     /** Fills gradient.  If Quadratic then solution may be NULL,
+         also returns true value of function and offset so we can use x not deltaX in constraint
+         If refresh is false then uses last solution
+         Uses model for scaling
+         Returns non-zero if gradient udefined at current solution
+     */
+     virtual int gradient(const ClpSimplex * model,
+                          const double * solution,
+                          double * gradient,
+                          double & functionValue ,
+                          double & offset,
+                          bool useScaling = false,
+                          bool refresh = true) const ;
+     /// Resize constraint
+     virtual void resize(int newNumberColumns) ;
+     /// Delete columns in  constraint
+     virtual void deleteSome(int numberToDelete, const int * which) ;
+     /// Scale constraint
+     virtual void reallyScale(const double * columnScale) ;
+     /** Given a zeroed array sets nonquadratic columns to 1.
+         Returns number of nonquadratic columns
+      */
+     virtual int markNonlinear(char * which) const ;
+     /** Given a zeroed array sets possible nonzero coefficients to 1.
+         Returns number of nonzeros
+      */
+     virtual int markNonzero(char * which) const;
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpConstraintQuadratic();
+
+     /// Constructor from quadratic
+     ClpConstraintQuadratic(int row, int numberQuadraticColumns, int numberColumns,
+                            const CoinBigIndex * start,
+                            const int * column, const double * element);
+
+     /** Copy constructor .
+     */
+     ClpConstraintQuadratic(const ClpConstraintQuadratic & rhs);
+
+     /// Assignment operator
+     ClpConstraintQuadratic & operator=(const ClpConstraintQuadratic& rhs);
+
+     /// Destructor
+     virtual ~ClpConstraintQuadratic ();
+
+     /// Clone
+     virtual ClpConstraint * clone() const;
+     //@}
+     ///@name Gets and sets
+     //@{
+     /// Number of coefficients
+     virtual int numberCoefficients() const;
+     /// Number of columns in constraint
+     inline int numberColumns() const {
+          return numberColumns_;
+     }
+     /// Column starts
+     inline CoinBigIndex * start() const {
+          return start_;
+     }
+     /// Columns
+     inline const int * column() const {
+          return column_;
+     }
+     /// Coefficients
+     inline const double * coefficient() const {
+          return coefficient_;
+     }
+     //@}
+
+     //---------------------------------------------------------------------------
+
+private:
+     ///@name Private member data
+     /// Column starts
+     CoinBigIndex * start_;
+     /// Column (if -1 then linear coefficient)
+     int * column_;
+     /// Coefficients
+     double * coefficient_;
+     /// Useful to have number of columns about
+     int numberColumns_;
+     /// Number of coefficients in gradient
+     int numberCoefficients_;
+     /// Number of quadratic columns
+     int numberQuadraticColumns_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpDualRowDantzig.cpp b/cbits/coin/ClpDualRowDantzig.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDualRowDantzig.cpp
@@ -0,0 +1,180 @@
+/* $Id: ClpDualRowDantzig.cpp 1732 2011-05-31 08:09:41Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpDualRowDantzig.hpp"
+#include "ClpFactorization.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#ifndef CLP_DUAL_COLUMN_MULTIPLIER
+#define CLP_DUAL_COLUMN_MULTIPLIER 1.01
+#endif
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpDualRowDantzig::ClpDualRowDantzig ()
+     : ClpDualRowPivot()
+{
+     type_ = 1;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpDualRowDantzig::ClpDualRowDantzig (const ClpDualRowDantzig & source)
+     : ClpDualRowPivot(source)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpDualRowDantzig::~ClpDualRowDantzig ()
+{
+
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpDualRowDantzig &
+ClpDualRowDantzig::operator=(const ClpDualRowDantzig& rhs)
+{
+     if (this != &rhs) {
+          ClpDualRowPivot::operator=(rhs);
+     }
+     return *this;
+}
+
+// Returns pivot row, -1 if none
+int
+ClpDualRowDantzig::pivotRow()
+{
+     assert(model_);
+     int iRow;
+     const int * pivotVariable = model_->pivotVariable();
+     double tolerance = model_->currentPrimalTolerance();
+     // we can't really trust infeasibilities if there is primal error
+     if (model_->largestPrimalError() > 1.0e-8)
+          tolerance *= model_->largestPrimalError() / 1.0e-8;
+     double largest = 0.0;
+     int chosenRow = -1;
+     int numberRows = model_->numberRows();
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+     int numberColumns = model_->numberColumns();
+#endif
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          int iSequence = pivotVariable[iRow];
+          double value = model_->solution(iSequence);
+          double lower = model_->lower(iSequence);
+          double upper = model_->upper(iSequence);
+	  double infeas = CoinMax(value - upper , lower - value);
+          if (infeas > tolerance) {
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+	      if (iSequence < numberColumns)
+		infeas *= CLP_DUAL_COLUMN_MULTIPLIER;
+#endif
+	      if (infeas > largest) {
+		if (!model_->flagged(iSequence)) {
+		  chosenRow = iRow;
+		  largest = infeas;
+		}
+	      }
+          }
+     }
+     return chosenRow;
+}
+// FT update and returns pivot alpha
+double
+ClpDualRowDantzig::updateWeights(CoinIndexedVector * /*input*/,
+                                 CoinIndexedVector * spare,
+                                 CoinIndexedVector * /*spare2*/,
+                                 CoinIndexedVector * updatedColumn)
+{
+     // Do FT update
+     model_->factorization()->updateColumnFT(spare, updatedColumn);
+     // pivot element
+     double alpha = 0.0;
+     // look at updated column
+     double * work = updatedColumn->denseVector();
+     int number = updatedColumn->getNumElements();
+     int * which = updatedColumn->getIndices();
+     int i;
+     int pivotRow = model_->pivotRow();
+
+     if (updatedColumn->packedMode()) {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               if (iRow == pivotRow) {
+                    alpha = work[i];
+                    break;
+               }
+          }
+     } else {
+          alpha = work[pivotRow];
+     }
+     return alpha;
+}
+
+/* Updates primal solution (and maybe list of candidates)
+   Uses input vector which it deletes
+   Computes change in objective function
+*/
+void
+ClpDualRowDantzig::updatePrimalSolution(CoinIndexedVector * primalUpdate,
+                                        double primalRatio,
+                                        double & objectiveChange)
+{
+     double * work = primalUpdate->denseVector();
+     int number = primalUpdate->getNumElements();
+     int * which = primalUpdate->getIndices();
+     int i;
+     double changeObj = 0.0;
+     const int * pivotVariable = model_->pivotVariable();
+     if (primalUpdate->packedMode()) {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               int iPivot = pivotVariable[iRow];
+               double & value = model_->solutionAddress(iPivot);
+               double cost = model_->cost(iPivot);
+               double change = primalRatio * work[i];
+               value -= change;
+               changeObj -= change * cost;
+               work[i] = 0.0;
+          }
+     } else {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               int iPivot = pivotVariable[iRow];
+               double & value = model_->solutionAddress(iPivot);
+               double cost = model_->cost(iPivot);
+               double change = primalRatio * work[iRow];
+               value -= change;
+               changeObj -= change * cost;
+               work[iRow] = 0.0;
+          }
+     }
+     primalUpdate->setNumElements(0);
+     objectiveChange += changeObj;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpDualRowPivot * ClpDualRowDantzig::clone(bool CopyData) const
+{
+     if (CopyData) {
+          return new ClpDualRowDantzig(*this);
+     } else {
+          return new ClpDualRowDantzig();
+     }
+}
+
diff --git a/cbits/coin/ClpDualRowDantzig.hpp b/cbits/coin/ClpDualRowDantzig.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDualRowDantzig.hpp
@@ -0,0 +1,71 @@
+/* $Id: ClpDualRowDantzig.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpDualRowDantzig_H
+#define ClpDualRowDantzig_H
+
+#include "ClpDualRowPivot.hpp"
+
+//#############################################################################
+
+/** Dual Row Pivot Dantzig Algorithm Class
+
+This is simplest choice - choose largest infeasibility
+
+*/
+
+class ClpDualRowDantzig : public ClpDualRowPivot {
+
+public:
+
+     ///@name Algorithmic methods
+     //@{
+
+     /// Returns pivot row, -1 if none
+     virtual int pivotRow();
+
+     /** Updates weights and returns pivot alpha.
+         Also does FT update */
+     virtual double updateWeights(CoinIndexedVector * input,
+                                  CoinIndexedVector * spare,
+                                  CoinIndexedVector * spare2,
+                                  CoinIndexedVector * updatedColumn);
+     /** Updates primal solution (and maybe list of candidates)
+         Uses input vector which it deletes
+         Computes change in objective function
+     */
+     virtual void updatePrimalSolution(CoinIndexedVector * input,
+                                       double theta,
+                                       double & changeInObjective);
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpDualRowDantzig();
+
+     /// Copy constructor
+     ClpDualRowDantzig(const ClpDualRowDantzig &);
+
+     /// Assignment operator
+     ClpDualRowDantzig & operator=(const ClpDualRowDantzig& rhs);
+
+     /// Destructor
+     virtual ~ClpDualRowDantzig ();
+
+     /// Clone
+     virtual ClpDualRowPivot * clone(bool copyData = true) const;
+
+     //@}
+
+     //---------------------------------------------------------------------------
+
+private:
+     ///@name Private member data
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpDualRowPivot.cpp b/cbits/coin/ClpDualRowPivot.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDualRowPivot.cpp
@@ -0,0 +1,72 @@
+/* $Id: ClpDualRowPivot.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpDualRowPivot.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpDualRowPivot::ClpDualRowPivot () :
+     model_(NULL),
+     type_(-1)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpDualRowPivot::ClpDualRowPivot (const ClpDualRowPivot & source) :
+     model_(source.model_),
+     type_(source.type_)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpDualRowPivot::~ClpDualRowPivot ()
+{
+
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpDualRowPivot &
+ClpDualRowPivot::operator=(const ClpDualRowPivot& rhs)
+{
+     if (this != &rhs) {
+          type_ = rhs.type_;
+          model_ = rhs.model_;
+     }
+     return *this;
+}
+void
+ClpDualRowPivot::saveWeights(ClpSimplex * model, int /*mode*/)
+{
+     model_ = model;
+}
+// checks accuracy and may re-initialize (may be empty)
+void
+ClpDualRowPivot::checkAccuracy()
+{
+}
+void
+ClpDualRowPivot::unrollWeights()
+{
+}
+// Gets rid of all arrays
+void
+ClpDualRowPivot::clearArrays()
+{
+}
diff --git a/cbits/coin/ClpDualRowPivot.hpp b/cbits/coin/ClpDualRowPivot.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDualRowPivot.hpp
@@ -0,0 +1,127 @@
+/* $Id: ClpDualRowPivot.hpp 1732 2011-05-31 08:09:41Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpDualRowPivot_H
+#define ClpDualRowPivot_H
+
+class ClpSimplex;
+class CoinIndexedVector;
+
+//#############################################################################
+
+/** Dual Row Pivot Abstract Base Class
+
+Abstract Base Class for describing an interface to an algorithm
+to choose row pivot in dual simplex algorithm.  For some algorithms
+e.g. Dantzig choice then some functions may be null.
+
+*/
+
+class ClpDualRowPivot  {
+
+public:
+
+     ///@name Algorithmic methods
+     //@{
+
+     /// Returns pivot row, -1 if none
+     virtual int pivotRow() = 0;
+
+     /** Updates weights and returns pivot alpha.
+         Also does FT update */
+     virtual double updateWeights(CoinIndexedVector * input,
+                                  CoinIndexedVector * spare,
+                                  CoinIndexedVector * spare2,
+                                  CoinIndexedVector * updatedColumn) = 0;
+
+     /** Updates primal solution (and maybe list of candidates)
+         Uses input vector which it deletes
+         Computes change in objective function
+         Would be faster if we kept basic regions, but on other hand it
+         means everything is always in sync
+     */
+     /* FIXME: this was pure virtul (=0). Why? */
+     virtual void updatePrimalSolution(CoinIndexedVector * input,
+                                       double theta,
+                                       double & changeInObjective) = 0;
+     /** Saves any weights round factorization as pivot rows may change
+         Will be empty unless steepest edge (will save model)
+         May also recompute infeasibility stuff
+         1) before factorization
+         2) after good factorization (if weights empty may initialize)
+         3) after something happened but no factorization
+            (e.g. check for infeasible)
+         4) as 2 but restore weights from previous snapshot
+         5) for strong branching - initialize  , infeasibilities
+     */
+     virtual void saveWeights(ClpSimplex * model, int mode);
+     /// checks accuracy and may re-initialize (may be empty)
+     virtual void checkAccuracy();
+     /// Gets rid of last update (may be empty)
+     virtual void unrollWeights();
+     /// Gets rid of all arrays (may be empty)
+     virtual void clearArrays();
+     /// Returns true if would not find any row
+     virtual bool looksOptimal() const {
+          return false;
+     }
+     /// Called when maximum pivots changes
+     virtual void maximumPivotsChanged() {}
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpDualRowPivot();
+
+     /// Copy constructor
+     ClpDualRowPivot(const ClpDualRowPivot &);
+
+     /// Assignment operator
+     ClpDualRowPivot & operator=(const ClpDualRowPivot& rhs);
+
+     /// Destructor
+     virtual ~ClpDualRowPivot ();
+
+     /// Clone
+     virtual ClpDualRowPivot * clone(bool copyData = true) const = 0;
+
+     //@}
+
+     ///@name Other
+     //@{
+     /// Returns model
+     inline ClpSimplex * model() {
+          return model_;
+     }
+
+     /// Sets model (normally to NULL)
+     inline void setModel(ClpSimplex * newmodel) {
+          model_ = newmodel;
+     }
+
+     /// Returns type (above 63 is extra information)
+     inline int type() {
+          return type_;
+     }
+
+     //@}
+
+     //---------------------------------------------------------------------------
+
+protected:
+     ///@name Protected member data
+     //@{
+     /// Pointer to model
+     ClpSimplex * model_;
+     /// Type of row pivot algorithm
+     int type_;
+     //@}
+};
+#ifndef CLP_DUAL_COLUMN_MULTIPLIER
+//#define CLP_DUAL_COLUMN_MULTIPLIER 0.99999
+#endif
+#endif
diff --git a/cbits/coin/ClpDualRowSteepest.cpp b/cbits/coin/ClpDualRowSteepest.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDualRowSteepest.cpp
@@ -0,0 +1,1101 @@
+/* $Id: ClpDualRowSteepest.cpp 1732 2011-05-31 08:09:41Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpDualRowSteepest.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpFactorization.hpp"
+#include "CoinHelperFunctions.hpp"
+#include <cstdio>
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+//#define CLP_DEBUG 4
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpDualRowSteepest::ClpDualRowSteepest (int mode)
+     : ClpDualRowPivot(),
+       state_(-1),
+       mode_(mode),
+       persistence_(normal),
+       weights_(NULL),
+       infeasible_(NULL),
+       alternateWeights_(NULL),
+       savedWeights_(NULL),
+       dubiousWeights_(NULL)
+{
+     type_ = 2 + 64 * mode;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpDualRowSteepest::ClpDualRowSteepest (const ClpDualRowSteepest & rhs)
+     : ClpDualRowPivot(rhs)
+{
+     state_ = rhs.state_;
+     mode_ = rhs.mode_;
+     persistence_ = rhs.persistence_;
+     model_ = rhs.model_;
+     if ((model_ && model_->whatsChanged() & 1) != 0) {
+          int number = model_->numberRows();
+          if (rhs.savedWeights_)
+               number = CoinMin(number, rhs.savedWeights_->capacity());
+          if (rhs.infeasible_) {
+               infeasible_ = new CoinIndexedVector(rhs.infeasible_);
+          } else {
+               infeasible_ = NULL;
+          }
+          if (rhs.weights_) {
+               weights_ = new double[number];
+               ClpDisjointCopyN(rhs.weights_, number, weights_);
+          } else {
+               weights_ = NULL;
+          }
+          if (rhs.alternateWeights_) {
+               alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_);
+          } else {
+               alternateWeights_ = NULL;
+          }
+          if (rhs.savedWeights_) {
+               savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
+          } else {
+               savedWeights_ = NULL;
+          }
+          if (rhs.dubiousWeights_) {
+               assert(model_);
+               int number = model_->numberRows();
+               dubiousWeights_ = new int[number];
+               ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_);
+          } else {
+               dubiousWeights_ = NULL;
+          }
+     } else {
+          infeasible_ = NULL;
+          weights_ = NULL;
+          alternateWeights_ = NULL;
+          savedWeights_ = NULL;
+          dubiousWeights_ = NULL;
+     }
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpDualRowSteepest::~ClpDualRowSteepest ()
+{
+     delete [] weights_;
+     delete [] dubiousWeights_;
+     delete infeasible_;
+     delete alternateWeights_;
+     delete savedWeights_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpDualRowSteepest &
+ClpDualRowSteepest::operator=(const ClpDualRowSteepest& rhs)
+{
+     if (this != &rhs) {
+          ClpDualRowPivot::operator=(rhs);
+          state_ = rhs.state_;
+          mode_ = rhs.mode_;
+          persistence_ = rhs.persistence_;
+          model_ = rhs.model_;
+          delete [] weights_;
+          delete [] dubiousWeights_;
+          delete infeasible_;
+          delete alternateWeights_;
+          delete savedWeights_;
+          assert(model_);
+          int number = model_->numberRows();
+          if (rhs.savedWeights_)
+               number = CoinMin(number, rhs.savedWeights_->capacity());
+          if (rhs.infeasible_ != NULL) {
+               infeasible_ = new CoinIndexedVector(rhs.infeasible_);
+          } else {
+               infeasible_ = NULL;
+          }
+          if (rhs.weights_ != NULL) {
+               weights_ = new double[number];
+               ClpDisjointCopyN(rhs.weights_, number, weights_);
+          } else {
+               weights_ = NULL;
+          }
+          if (rhs.alternateWeights_ != NULL) {
+               alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_);
+          } else {
+               alternateWeights_ = NULL;
+          }
+          if (rhs.savedWeights_ != NULL) {
+               savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
+          } else {
+               savedWeights_ = NULL;
+          }
+          if (rhs.dubiousWeights_) {
+               assert(model_);
+               int number = model_->numberRows();
+               dubiousWeights_ = new int[number];
+               ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_);
+          } else {
+               dubiousWeights_ = NULL;
+          }
+     }
+     return *this;
+}
+// Fill most values
+void
+ClpDualRowSteepest::fill(const ClpDualRowSteepest& rhs)
+{
+     state_ = rhs.state_;
+     mode_ = rhs.mode_;
+     persistence_ = rhs.persistence_;
+     assert (model_->numberRows() == rhs.model_->numberRows());
+     model_ = rhs.model_;
+     assert(model_);
+     int number = model_->numberRows();
+     if (rhs.savedWeights_)
+          number = CoinMin(number, rhs.savedWeights_->capacity());
+     if (rhs.infeasible_ != NULL) {
+          if (!infeasible_)
+               infeasible_ = new CoinIndexedVector(rhs.infeasible_);
+          else
+               *infeasible_ = *rhs.infeasible_;
+     } else {
+          delete infeasible_;
+          infeasible_ = NULL;
+     }
+     if (rhs.weights_ != NULL) {
+          if (!weights_)
+               weights_ = new double[number];
+          ClpDisjointCopyN(rhs.weights_, number, weights_);
+     } else {
+          delete [] weights_;
+          weights_ = NULL;
+     }
+     if (rhs.alternateWeights_ != NULL) {
+          if (!alternateWeights_)
+               alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_);
+          else
+               *alternateWeights_ = *rhs.alternateWeights_;
+     } else {
+          delete alternateWeights_;
+          alternateWeights_ = NULL;
+     }
+     if (rhs.savedWeights_ != NULL) {
+          if (!savedWeights_)
+               savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
+          else
+               *savedWeights_ = *rhs.savedWeights_;
+     } else {
+          delete savedWeights_;
+          savedWeights_ = NULL;
+     }
+     if (rhs.dubiousWeights_) {
+          assert(model_);
+          int number = model_->numberRows();
+          if (!dubiousWeights_)
+               dubiousWeights_ = new int[number];
+          ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_);
+     } else {
+          delete [] dubiousWeights_;
+          dubiousWeights_ = NULL;
+     }
+}
+// Returns pivot row, -1 if none
+int
+ClpDualRowSteepest::pivotRow()
+{
+     assert(model_);
+     int i, iRow;
+     double * infeas = infeasible_->denseVector();
+     double largest = 0.0;
+     int * index = infeasible_->getIndices();
+     int number = infeasible_->getNumElements();
+     const int * pivotVariable = model_->pivotVariable();
+     int chosenRow = -1;
+     int lastPivotRow = model_->pivotRow();
+     assert (lastPivotRow < model_->numberRows());
+     double tolerance = model_->currentPrimalTolerance();
+     // we can't really trust infeasibilities if there is primal error
+     // this coding has to mimic coding in checkPrimalSolution
+     double error = CoinMin(1.0e-2, model_->largestPrimalError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     // But cap
+     tolerance = CoinMin(1000.0, tolerance);
+     tolerance *= tolerance; // as we are using squares
+     bool toleranceChanged = false;
+     double * solution = model_->solutionRegion();
+     double * lower = model_->lowerRegion();
+     double * upper = model_->upperRegion();
+     // do last pivot row one here
+     //#define CLP_DUAL_FIXED_COLUMN_MULTIPLIER 10.0
+     if (lastPivotRow >= 0 && lastPivotRow < model_->numberRows()) {
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+          int numberColumns = model_->numberColumns();
+#endif
+          int iPivot = pivotVariable[lastPivotRow];
+          double value = solution[iPivot];
+          double lower = model_->lower(iPivot);
+          double upper = model_->upper(iPivot);
+          if (value > upper + tolerance) {
+               value -= upper;
+               value *= value;
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+               if (iPivot < numberColumns)
+                    value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
+#endif
+               // store square in list
+               if (infeas[lastPivotRow])
+                    infeas[lastPivotRow] = value; // already there
+               else
+                    infeasible_->quickAdd(lastPivotRow, value);
+          } else if (value < lower - tolerance) {
+               value -= lower;
+               value *= value;
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+               if (iPivot < numberColumns)
+                    value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
+#endif
+               // store square in list
+               if (infeas[lastPivotRow])
+                    infeas[lastPivotRow] = value; // already there
+               else
+                    infeasible_->add(lastPivotRow, value);
+          } else {
+               // feasible - was it infeasible - if so set tiny
+               if (infeas[lastPivotRow])
+                    infeas[lastPivotRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+          }
+          number = infeasible_->getNumElements();
+     }
+     if(model_->numberIterations() < model_->lastBadIteration() + 200) {
+          // we can't really trust infeasibilities if there is dual error
+          if (model_->largestDualError() > model_->largestPrimalError()) {
+               tolerance *= CoinMin(model_->largestDualError() / model_->largestPrimalError(), 1000.0);
+               toleranceChanged = true;
+          }
+     }
+     int numberWanted;
+     if (mode_ < 2 ) {
+          numberWanted = number + 1;
+     } else if (mode_ == 2) {
+          numberWanted = CoinMax(2000, number / 8);
+     } else {
+          int numberElements = model_->factorization()->numberElements();
+          double ratio = static_cast<double> (numberElements) /
+                         static_cast<double> (model_->numberRows());
+          numberWanted = CoinMax(2000, number / 8);
+          if (ratio < 1.0) {
+               numberWanted = CoinMax(2000, number / 20);
+          } else if (ratio > 10.0) {
+               ratio = number * (ratio / 80.0);
+               if (ratio > number)
+                    numberWanted = number + 1;
+               else
+                    numberWanted = CoinMax(2000, static_cast<int> (ratio));
+          }
+     }
+     if (model_->largestPrimalError() > 1.0e-3)
+          numberWanted = number + 1; // be safe
+     int iPass;
+     // Setup two passes
+     int start[4];
+     start[1] = number;
+     start[2] = 0;
+     double dstart = static_cast<double> (number) * model_->randomNumberGenerator()->randomDouble();
+     start[0] = static_cast<int> (dstart);
+     start[3] = start[0];
+     //double largestWeight=0.0;
+     //double smallestWeight=1.0e100;
+     for (iPass = 0; iPass < 2; iPass++) {
+          int end = start[2*iPass+1];
+          for (i = start[2*iPass]; i < end; i++) {
+               iRow = index[i];
+               double value = infeas[iRow];
+               if (value > tolerance) {
+                    //#define OUT_EQ
+#ifdef OUT_EQ
+                    {
+                         int iSequence = pivotVariable[iRow];
+                         if (upper[iSequence] == lower[iSequence])
+                              value *= 2.0;
+                    }
+#endif
+                    double weight = CoinMin(weights_[iRow], 1.0e50);
+                    //largestWeight = CoinMax(largestWeight,weight);
+                    //smallestWeight = CoinMin(smallestWeight,weight);
+                    //double dubious = dubiousWeights_[iRow];
+                    //weight *= dubious;
+                    //if (value>2.0*largest*weight||(value>0.5*largest*weight&&value*largestWeight>dubious*largest*weight)) {
+                    if (value > largest * weight) {
+                         // make last pivot row last resort choice
+                         if (iRow == lastPivotRow) {
+                              if (value * 1.0e-10 < largest * weight)
+                                   continue;
+                              else
+                                   value *= 1.0e-10;
+                         }
+                         int iSequence = pivotVariable[iRow];
+                         if (!model_->flagged(iSequence)) {
+                              //#define CLP_DEBUG 3
+#ifdef CLP_DEBUG
+                              double value2 = 0.0;
+                              if (solution[iSequence] > upper[iSequence] + tolerance)
+                                   value2 = solution[iSequence] - upper[iSequence];
+                              else if (solution[iSequence] < lower[iSequence] - tolerance)
+                                   value2 = solution[iSequence] - lower[iSequence];
+                              assert(fabs(value2 * value2 - infeas[iRow]) < 1.0e-8 * CoinMin(value2 * value2, infeas[iRow]));
+#endif
+                              if (solution[iSequence] > upper[iSequence] + tolerance ||
+                                        solution[iSequence] < lower[iSequence] - tolerance) {
+                                   chosenRow = iRow;
+                                   largest = value / weight;
+                                   //largestWeight = dubious;
+                              }
+                         } else {
+                              // just to make sure we don't exit before got something
+                              numberWanted++;
+                         }
+                    }
+                    numberWanted--;
+                    if (!numberWanted)
+                         break;
+               }
+          }
+          if (!numberWanted)
+               break;
+     }
+     //printf("smallest %g largest %g\n",smallestWeight,largestWeight);
+     if (chosenRow < 0 && toleranceChanged) {
+          // won't line up with checkPrimalSolution - do again
+          double saveError = model_->largestDualError();
+          model_->setLargestDualError(0.0);
+          // can't loop
+          chosenRow = pivotRow();
+          model_->setLargestDualError(saveError);
+     }
+     if (chosenRow < 0 && lastPivotRow < 0) {
+          int nLeft = 0;
+          for (int i = 0; i < number; i++) {
+               int iRow = index[i];
+               if (fabs(infeas[iRow]) > 1.0e-50) {
+                    index[nLeft++] = iRow;
+               } else {
+                    infeas[iRow] = 0.0;
+               }
+          }
+          infeasible_->setNumElements(nLeft);
+          model_->setNumberPrimalInfeasibilities(nLeft);
+     }
+     return chosenRow;
+}
+#if 0
+static double ft_count = 0.0;
+static double up_count = 0.0;
+static double ft_count_in = 0.0;
+static double up_count_in = 0.0;
+static int xx_count = 0;
+#endif
+/* Updates weights and returns pivot alpha.
+   Also does FT update */
+double
+ClpDualRowSteepest::updateWeights(CoinIndexedVector * input,
+                                  CoinIndexedVector * spare,
+                                  CoinIndexedVector * spare2,
+                                  CoinIndexedVector * updatedColumn)
+{
+     //#define CLP_DEBUG 3
+#if CLP_DEBUG>2
+     // Very expensive debug
+     {
+          int numberRows = model_->numberRows();
+          CoinIndexedVector * temp = new CoinIndexedVector();
+          temp->reserve(numberRows +
+                        model_->factorization()->maximumPivots());
+          double * array = alternateWeights_->denseVector();
+          int * which = alternateWeights_->getIndices();
+          alternateWeights_->clear();
+          int i;
+          for (i = 0; i < numberRows; i++) {
+               double value = 0.0;
+               array[i] = 1.0;
+               which[0] = i;
+               alternateWeights_->setNumElements(1);
+               model_->factorization()->updateColumnTranspose(temp,
+                         alternateWeights_);
+               int number = alternateWeights_->getNumElements();
+               int j;
+               for (j = 0; j < number; j++) {
+                    int iRow = which[j];
+                    value += array[iRow] * array[iRow];
+                    array[iRow] = 0.0;
+               }
+               alternateWeights_->setNumElements(0);
+               double w = CoinMax(weights_[i], value) * .1;
+               if (fabs(weights_[i] - value) > w) {
+                    printf("%d old %g, true %g\n", i, weights_[i], value);
+                    weights_[i] = value; // to reduce printout
+               }
+               //else
+               //printf("%d matches %g\n",i,value);
+          }
+          delete temp;
+     }
+#endif
+     assert (input->packedMode());
+     if (!updatedColumn->packedMode()) {
+          // I think this means empty
+#ifdef COIN_DEVELOP
+          printf("updatedColumn not packed mode ClpDualRowSteepest::updateWeights\n");
+#endif
+          return 0.0;
+     }
+     double alpha = 0.0;
+     if (!model_->factorization()->networkBasis()) {
+          // clear other region
+          alternateWeights_->clear();
+          double norm = 0.0;
+          int i;
+          double * work = input->denseVector();
+          int numberNonZero = input->getNumElements();
+          int * which = input->getIndices();
+          double * work2 = spare->denseVector();
+          int * which2 = spare->getIndices();
+          // ftran
+          //permute and move indices into index array
+          //also compute norm
+          //int *regionIndex = alternateWeights_->getIndices (  );
+          const int *permute = model_->factorization()->permute();
+          //double * region = alternateWeights_->denseVector();
+          if (permute) {
+               for ( i = 0; i < numberNonZero; i ++ ) {
+                    int iRow = which[i];
+                    double value = work[i];
+                    norm += value * value;
+                    iRow = permute[iRow];
+                    work2[iRow] = value;
+                    which2[i] = iRow;
+               }
+          } else {
+               for ( i = 0; i < numberNonZero; i ++ ) {
+                    int iRow = which[i];
+                    double value = work[i];
+                    norm += value * value;
+                    //iRow = permute[iRow];
+                    work2[iRow] = value;
+                    which2[i] = iRow;
+               }
+          }
+          spare->setNumElements ( numberNonZero );
+          // Do FT update
+#if 0
+          ft_count_in += updatedColumn->getNumElements();
+          up_count_in += spare->getNumElements();
+#endif
+          if (permute || true) {
+#if CLP_DEBUG>2
+               printf("REGION before %d els\n", spare->getNumElements());
+               spare->print();
+#endif
+               model_->factorization()->updateTwoColumnsFT(spare2, updatedColumn,
+                         spare, permute != NULL);
+#if CLP_DEBUG>2
+               printf("REGION after %d els\n", spare->getNumElements());
+               spare->print();
+#endif
+          } else {
+               // Leave as old way
+               model_->factorization()->updateColumnFT(spare2, updatedColumn);
+               model_->factorization()->updateColumn(spare2, spare, false);
+          }
+#undef CLP_DEBUG
+#if 0
+          ft_count += updatedColumn->getNumElements();
+          up_count += spare->getNumElements();
+          xx_count++;
+          if ((xx_count % 1000) == 0)
+               printf("zz %d ft %g up %g (in %g %g)\n", xx_count, ft_count, up_count,
+                      ft_count_in, up_count_in);
+#endif
+          numberNonZero = spare->getNumElements();
+          // alternateWeights_ should still be empty
+          int pivotRow = model_->pivotRow();
+#ifdef CLP_DEBUG
+          if ( model_->logLevel (  ) > 4  &&
+                    fabs(norm - weights_[pivotRow]) > 1.0e-3 * (1.0 + norm))
+               printf("on row %d, true weight %g, old %g\n",
+                      pivotRow, sqrt(norm), sqrt(weights_[pivotRow]));
+#endif
+          // could re-initialize here (could be expensive)
+          norm /= model_->alpha() * model_->alpha();
+          assert(model_->alpha());
+          assert(norm);
+          // pivot element
+          alpha = 0.0;
+          double multiplier = 2.0 / model_->alpha();
+          // look at updated column
+          work = updatedColumn->denseVector();
+          numberNonZero = updatedColumn->getNumElements();
+          which = updatedColumn->getIndices();
+
+          int nSave = 0;
+          double * work3 = alternateWeights_->denseVector();
+          int * which3 = alternateWeights_->getIndices();
+          const int * pivotColumn = model_->factorization()->pivotColumn();
+          for (i = 0; i < numberNonZero; i++) {
+               int iRow = which[i];
+               double theta = work[i];
+               if (iRow == pivotRow)
+                    alpha = theta;
+               double devex = weights_[iRow];
+               work3[nSave] = devex; // save old
+               which3[nSave++] = iRow;
+               // transform to match spare
+               int jRow = permute ? pivotColumn[iRow] : iRow;
+               double value = work2[jRow];
+               devex +=  theta * (theta * norm + value * multiplier);
+               if (devex < DEVEX_TRY_NORM)
+                    devex = DEVEX_TRY_NORM;
+               weights_[iRow] = devex;
+          }
+          alternateWeights_->setPackedMode(true);
+          alternateWeights_->setNumElements(nSave);
+          if (norm < DEVEX_TRY_NORM)
+               norm = DEVEX_TRY_NORM;
+          // Try this to make less likely will happen again and stop cycling
+          //norm *= 1.02;
+          weights_[pivotRow] = norm;
+          spare->clear();
+#ifdef CLP_DEBUG
+          spare->checkClear();
+#endif
+     } else {
+          // Do FT update
+          model_->factorization()->updateColumnFT(spare, updatedColumn);
+          // clear other region
+          alternateWeights_->clear();
+          double norm = 0.0;
+          int i;
+          double * work = input->denseVector();
+          int number = input->getNumElements();
+          int * which = input->getIndices();
+          double * work2 = spare->denseVector();
+          int * which2 = spare->getIndices();
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               double value = work[i];
+               norm += value * value;
+               work2[iRow] = value;
+               which2[i] = iRow;
+          }
+          spare->setNumElements(number);
+          // ftran
+#ifndef NDEBUG
+          alternateWeights_->checkClear();
+#endif
+          model_->factorization()->updateColumn(alternateWeights_, spare);
+          // alternateWeights_ should still be empty
+#ifndef NDEBUG
+          alternateWeights_->checkClear();
+#endif
+          int pivotRow = model_->pivotRow();
+#ifdef CLP_DEBUG
+          if ( model_->logLevel (  ) > 4  &&
+                    fabs(norm - weights_[pivotRow]) > 1.0e-3 * (1.0 + norm))
+               printf("on row %d, true weight %g, old %g\n",
+                      pivotRow, sqrt(norm), sqrt(weights_[pivotRow]));
+#endif
+          // could re-initialize here (could be expensive)
+          norm /= model_->alpha() * model_->alpha();
+
+          assert(norm);
+          //if (norm < DEVEX_TRY_NORM)
+          //norm = DEVEX_TRY_NORM;
+          // pivot element
+          alpha = 0.0;
+          double multiplier = 2.0 / model_->alpha();
+          // look at updated column
+          work = updatedColumn->denseVector();
+          number = updatedColumn->getNumElements();
+          which = updatedColumn->getIndices();
+
+          int nSave = 0;
+          double * work3 = alternateWeights_->denseVector();
+          int * which3 = alternateWeights_->getIndices();
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               double theta = work[i];
+               if (iRow == pivotRow)
+                    alpha = theta;
+               double devex = weights_[iRow];
+               work3[nSave] = devex; // save old
+               which3[nSave++] = iRow;
+               double value = work2[iRow];
+               devex +=  theta * (theta * norm + value * multiplier);
+               if (devex < DEVEX_TRY_NORM)
+                    devex = DEVEX_TRY_NORM;
+               weights_[iRow] = devex;
+          }
+          if (!alpha) {
+               // error - but carry on
+               alpha = 1.0e-50;
+          }
+          alternateWeights_->setPackedMode(true);
+          alternateWeights_->setNumElements(nSave);
+          if (norm < DEVEX_TRY_NORM)
+               norm = DEVEX_TRY_NORM;
+          weights_[pivotRow] = norm;
+          spare->clear();
+     }
+#ifdef CLP_DEBUG
+     spare->checkClear();
+#endif
+     return alpha;
+}
+
+/* Updates primal solution (and maybe list of candidates)
+   Uses input vector which it deletes
+   Computes change in objective function
+*/
+void
+ClpDualRowSteepest::updatePrimalSolution(
+     CoinIndexedVector * primalUpdate,
+     double primalRatio,
+     double & objectiveChange)
+{
+     double * COIN_RESTRICT work = primalUpdate->denseVector();
+     int number = primalUpdate->getNumElements();
+     int * COIN_RESTRICT which = primalUpdate->getIndices();
+     int i;
+     double changeObj = 0.0;
+     double tolerance = model_->currentPrimalTolerance();
+     const int * COIN_RESTRICT pivotVariable = model_->pivotVariable();
+     double * COIN_RESTRICT infeas = infeasible_->denseVector();
+     double * COIN_RESTRICT solution = model_->solutionRegion();
+     const double * COIN_RESTRICT costModel = model_->costRegion();
+     const double * COIN_RESTRICT lowerModel = model_->lowerRegion();
+     const double * COIN_RESTRICT upperModel = model_->upperRegion();
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+     int numberColumns = model_->numberColumns();
+#endif
+     if (primalUpdate->packedMode()) {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               int iPivot = pivotVariable[iRow];
+               double value = solution[iPivot];
+               double cost = costModel[iPivot];
+               double change = primalRatio * work[i];
+               work[i] = 0.0;
+               value -= change;
+               changeObj -= change * cost;
+               double lower = lowerModel[iPivot];
+               double upper = upperModel[iPivot];
+               solution[iPivot] = value;
+               if (value < lower - tolerance) {
+                    value -= lower;
+                    value *= value;
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+                    if (iPivot < numberColumns)
+                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
+#endif
+#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
+                    if (lower == upper)
+                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
+#endif
+                    // store square in list
+                    if (infeas[iRow])
+                         infeas[iRow] = value; // already there
+                    else
+                         infeasible_->quickAdd(iRow, value);
+               } else if (value > upper + tolerance) {
+                    value -= upper;
+                    value *= value;
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+                    if (iPivot < numberColumns)
+                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
+#endif
+#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
+                    if (lower == upper)
+                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
+#endif
+                    // store square in list
+                    if (infeas[iRow])
+                         infeas[iRow] = value; // already there
+                    else
+                         infeasible_->quickAdd(iRow, value);
+               } else {
+                    // feasible - was it infeasible - if so set tiny
+                    if (infeas[iRow])
+                         infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+               }
+          }
+     } else {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               int iPivot = pivotVariable[iRow];
+               double value = solution[iPivot];
+               double cost = costModel[iPivot];
+               double change = primalRatio * work[iRow];
+               value -= change;
+               changeObj -= change * cost;
+               double lower = lowerModel[iPivot];
+               double upper = upperModel[iPivot];
+               solution[iPivot] = value;
+               if (value < lower - tolerance) {
+                    value -= lower;
+                    value *= value;
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+                    if (iPivot < numberColumns)
+                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
+#endif
+#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
+                    if (lower == upper)
+                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
+#endif
+                    // store square in list
+                    if (infeas[iRow])
+                         infeas[iRow] = value; // already there
+                    else
+                         infeasible_->quickAdd(iRow, value);
+               } else if (value > upper + tolerance) {
+                    value -= upper;
+                    value *= value;
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+                    if (iPivot < numberColumns)
+                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
+#endif
+#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
+                    if (lower == upper)
+                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
+#endif
+                    // store square in list
+                    if (infeas[iRow])
+                         infeas[iRow] = value; // already there
+                    else
+                         infeasible_->quickAdd(iRow, value);
+               } else {
+                    // feasible - was it infeasible - if so set tiny
+                    if (infeas[iRow])
+                         infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+               }
+               work[iRow] = 0.0;
+          }
+     }
+     // Do pivot row
+     {
+          int iRow = model_->pivotRow();
+          // feasible - was it infeasible - if so set tiny
+          //assert (infeas[iRow]);
+          if (infeas[iRow])
+               infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+     }
+     primalUpdate->setNumElements(0);
+     objectiveChange += changeObj;
+}
+/* Saves any weights round factorization as pivot rows may change
+   1) before factorization
+   2) after factorization
+   3) just redo infeasibilities
+   4) restore weights
+*/
+void
+ClpDualRowSteepest::saveWeights(ClpSimplex * model, int mode)
+{
+     // alternateWeights_ is defined as indexed but is treated oddly
+     model_ = model;
+     int numberRows = model_->numberRows();
+     int numberColumns = model_->numberColumns();
+     const int * pivotVariable = model_->pivotVariable();
+     int i;
+     if (mode == 1) {
+          if(weights_) {
+               // Check if size has changed
+               if (infeasible_->capacity() == numberRows) {
+                    alternateWeights_->clear();
+                    // change from row numbers to sequence numbers
+                    int * which = alternateWeights_->getIndices();
+                    for (i = 0; i < numberRows; i++) {
+                         int iPivot = pivotVariable[i];
+                         which[i] = iPivot;
+                    }
+                    state_ = 1;
+               } else {
+                    // size has changed - clear everything
+                    delete [] weights_;
+                    weights_ = NULL;
+                    delete [] dubiousWeights_;
+                    dubiousWeights_ = NULL;
+                    delete infeasible_;
+                    infeasible_ = NULL;
+                    delete alternateWeights_;
+                    alternateWeights_ = NULL;
+                    delete savedWeights_;
+                    savedWeights_ = NULL;
+                    state_ = -1;
+               }
+          }
+     } else if (mode == 2 || mode == 4 || mode >= 5) {
+          // restore
+          if (!weights_ || state_ == -1 || mode == 5) {
+               // initialize weights
+               delete [] weights_;
+               delete alternateWeights_;
+               weights_ = new double[numberRows];
+               alternateWeights_ = new CoinIndexedVector();
+               // enough space so can use it for factorization
+               alternateWeights_->reserve(numberRows +
+                                          model_->factorization()->maximumPivots());
+               if (mode_ != 1 || mode == 5) {
+                    // initialize to 1.0 (can we do better?)
+                    for (i = 0; i < numberRows; i++) {
+                         weights_[i] = 1.0;
+                    }
+               } else {
+                    CoinIndexedVector * temp = new CoinIndexedVector();
+                    temp->reserve(numberRows +
+                                  model_->factorization()->maximumPivots());
+                    double * array = alternateWeights_->denseVector();
+                    int * which = alternateWeights_->getIndices();
+                    for (i = 0; i < numberRows; i++) {
+                         double value = 0.0;
+                         array[0] = 1.0;
+                         which[0] = i;
+                         alternateWeights_->setNumElements(1);
+                         alternateWeights_->setPackedMode(true);
+                         model_->factorization()->updateColumnTranspose(temp,
+                                   alternateWeights_);
+                         int number = alternateWeights_->getNumElements();
+                         int j;
+                         for (j = 0; j < number; j++) {
+                              value += array[j] * array[j];
+                              array[j] = 0.0;
+                         }
+                         alternateWeights_->setNumElements(0);
+                         weights_[i] = value;
+                    }
+                    delete temp;
+               }
+               // create saved weights (not really indexedvector)
+               savedWeights_ = new CoinIndexedVector();
+               savedWeights_->reserve(numberRows);
+
+               double * array = savedWeights_->denseVector();
+               int * which = savedWeights_->getIndices();
+               for (i = 0; i < numberRows; i++) {
+                    array[i] = weights_[i];
+                    which[i] = pivotVariable[i];
+               }
+          } else if (mode != 6) {
+               int * which = alternateWeights_->getIndices();
+               CoinIndexedVector * rowArray3 = model_->rowArray(3);
+               rowArray3->clear();
+               int * back = rowArray3->getIndices();
+               // In case something went wrong
+               for (i = 0; i < numberRows + numberColumns; i++)
+                    back[i] = -1;
+               if (mode != 4) {
+                    // save
+                    CoinMemcpyN(which,	numberRows, savedWeights_->getIndices());
+                    CoinMemcpyN(weights_,	numberRows, savedWeights_->denseVector());
+               } else {
+                    // restore
+                    //memcpy(which,savedWeights_->getIndices(),
+                    //     numberRows*sizeof(int));
+                    //memcpy(weights_,savedWeights_->denseVector(),
+                    //     numberRows*sizeof(double));
+                    which = savedWeights_->getIndices();
+               }
+               // restore (a bit slow - but only every re-factorization)
+               double * array = savedWeights_->denseVector();
+               for (i = 0; i < numberRows; i++) {
+                    int iSeq = which[i];
+                    back[iSeq] = i;
+               }
+               for (i = 0; i < numberRows; i++) {
+                    int iPivot = pivotVariable[i];
+                    iPivot = back[iPivot];
+                    if (iPivot >= 0) {
+                         weights_[i] = array[iPivot];
+                         if (weights_[i] < DEVEX_TRY_NORM)
+                              weights_[i] = DEVEX_TRY_NORM; // may need to check more
+                    } else {
+                         // odd
+                         weights_[i] = 1.0;
+                    }
+               }
+          } else {
+               // mode 6 - scale back weights as primal errors
+               double primalError = model_->largestPrimalError();
+               double allowed ;
+               if (primalError > 1.0e3)
+                    allowed = 10.0;
+               else if (primalError > 1.0e2)
+                    allowed = 50.0;
+               else if (primalError > 1.0e1)
+                    allowed = 100.0;
+               else
+                    allowed = 1000.0;
+               double allowedInv = 1.0 / allowed;
+               for (i = 0; i < numberRows; i++) {
+                    double value = weights_[i];
+                    if (value < allowedInv)
+                         value = allowedInv;
+                    else if (value > allowed)
+                         value = allowed;
+                    weights_[i] = allowed;
+               }
+          }
+          state_ = 0;
+          // set up infeasibilities
+          if (!infeasible_) {
+               infeasible_ = new CoinIndexedVector();
+               infeasible_->reserve(numberRows);
+          }
+     }
+     if (mode >= 2) {
+          // Get dubious weights
+          //if (!dubiousWeights_)
+          //dubiousWeights_=new int[numberRows];
+          //model_->factorization()->getWeights(dubiousWeights_);
+          infeasible_->clear();
+          int iRow;
+          const int * pivotVariable = model_->pivotVariable();
+          double tolerance = model_->currentPrimalTolerance();
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               int iPivot = pivotVariable[iRow];
+               double value = model_->solution(iPivot);
+               double lower = model_->lower(iPivot);
+               double upper = model_->upper(iPivot);
+               if (value < lower - tolerance) {
+                    value -= lower;
+                    value *= value;
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+                    if (iPivot < numberColumns)
+                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
+#endif
+#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
+                    if (lower == upper)
+                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
+#endif
+                    // store square in list
+                    infeasible_->quickAdd(iRow, value);
+               } else if (value > upper + tolerance) {
+                    value -= upper;
+                    value *= value;
+#ifdef CLP_DUAL_COLUMN_MULTIPLIER
+                    if (iPivot < numberColumns)
+                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
+#endif
+#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
+                    if (lower == upper)
+                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
+#endif
+                    // store square in list
+                    infeasible_->quickAdd(iRow, value);
+               }
+          }
+     }
+}
+// Gets rid of last update
+void
+ClpDualRowSteepest::unrollWeights()
+{
+     double * saved = alternateWeights_->denseVector();
+     int number = alternateWeights_->getNumElements();
+     int * which = alternateWeights_->getIndices();
+     int i;
+     if (alternateWeights_->packedMode()) {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               weights_[iRow] = saved[i];
+               saved[i] = 0.0;
+          }
+     } else {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               weights_[iRow] = saved[iRow];
+               saved[iRow] = 0.0;
+          }
+     }
+     alternateWeights_->setNumElements(0);
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpDualRowPivot * ClpDualRowSteepest::clone(bool CopyData) const
+{
+     if (CopyData) {
+          return new ClpDualRowSteepest(*this);
+     } else {
+          return new ClpDualRowSteepest();
+     }
+}
+// Gets rid of all arrays
+void
+ClpDualRowSteepest::clearArrays()
+{
+     if (persistence_ == normal) {
+          delete [] weights_;
+          weights_ = NULL;
+          delete [] dubiousWeights_;
+          dubiousWeights_ = NULL;
+          delete infeasible_;
+          infeasible_ = NULL;
+          delete alternateWeights_;
+          alternateWeights_ = NULL;
+          delete savedWeights_;
+          savedWeights_ = NULL;
+     }
+     state_ = -1;
+}
+// Returns true if would not find any row
+bool
+ClpDualRowSteepest::looksOptimal() const
+{
+     int iRow;
+     const int * pivotVariable = model_->pivotVariable();
+     double tolerance = model_->currentPrimalTolerance();
+     // we can't really trust infeasibilities if there is primal error
+     // this coding has to mimic coding in checkPrimalSolution
+     double error = CoinMin(1.0e-2, model_->largestPrimalError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     // But cap
+     tolerance = CoinMin(1000.0, tolerance);
+     int numberRows = model_->numberRows();
+     int numberInfeasible = 0;
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          int iPivot = pivotVariable[iRow];
+          double value = model_->solution(iPivot);
+          double lower = model_->lower(iPivot);
+          double upper = model_->upper(iPivot);
+          if (value < lower - tolerance) {
+               numberInfeasible++;
+          } else if (value > upper + tolerance) {
+               numberInfeasible++;
+          }
+     }
+     return (numberInfeasible == 0);
+}
+// Called when maximum pivots changes
+void
+ClpDualRowSteepest::maximumPivotsChanged()
+{
+     if (alternateWeights_ &&
+               alternateWeights_->capacity() != model_->numberRows() +
+               model_->factorization()->maximumPivots()) {
+          delete alternateWeights_;
+          alternateWeights_ = new CoinIndexedVector();
+          // enough space so can use it for factorization
+          alternateWeights_->reserve(model_->numberRows() +
+                                     model_->factorization()->maximumPivots());
+     }
+}
+
diff --git a/cbits/coin/ClpDualRowSteepest.hpp b/cbits/coin/ClpDualRowSteepest.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDualRowSteepest.hpp
@@ -0,0 +1,144 @@
+/* $Id: ClpDualRowSteepest.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpDualRowSteepest_H
+#define ClpDualRowSteepest_H
+
+#include "ClpDualRowPivot.hpp"
+class CoinIndexedVector;
+
+
+//#############################################################################
+
+/** Dual Row Pivot Steepest Edge Algorithm Class
+
+See Forrest-Goldfarb paper for algorithm
+
+*/
+
+class ClpDualRowSteepest : public ClpDualRowPivot {
+
+public:
+
+     ///@name Algorithmic methods
+     //@{
+
+     /// Returns pivot row, -1 if none
+     virtual int pivotRow();
+
+     /** Updates weights and returns pivot alpha.
+         Also does FT update */
+     virtual double updateWeights(CoinIndexedVector * input,
+                                  CoinIndexedVector * spare,
+                                  CoinIndexedVector * spare2,
+                                  CoinIndexedVector * updatedColumn);
+
+     /** Updates primal solution (and maybe list of candidates)
+         Uses input vector which it deletes
+         Computes change in objective function
+     */
+     virtual void updatePrimalSolution(CoinIndexedVector * input,
+                                       double theta,
+                                       double & changeInObjective);
+
+     /** Saves any weights round factorization as pivot rows may change
+         Save model
+         May also recompute infeasibility stuff
+         1) before factorization
+         2) after good factorization (if weights empty may initialize)
+         3) after something happened but no factorization
+            (e.g. check for infeasible)
+         4) as 2 but restore weights from previous snapshot
+         5) for strong branching - initialize (uninitialized) , infeasibilities
+     */
+     virtual void saveWeights(ClpSimplex * model, int mode);
+     /// Gets rid of last update
+     virtual void unrollWeights();
+     /// Gets rid of all arrays
+     virtual void clearArrays();
+     /// Returns true if would not find any row
+     virtual bool looksOptimal() const;
+     /// Called when maximum pivots changes
+     virtual void maximumPivotsChanged();
+     //@}
+
+     /** enums for persistence
+     */
+     enum Persistence {
+          normal = 0x00, // create (if necessary) and destroy
+          keep = 0x01 // create (if necessary) and leave
+     };
+
+     ///@name Constructors and destructors
+     //@{
+     /** Default Constructor
+         0 is uninitialized, 1 full, 2 is partial uninitialized,
+         3 starts as 2 but may switch to 1.
+         By partial is meant that the weights are updated as normal
+         but only part of the infeasible basic variables are scanned.
+         This can be faster on very easy problems.
+     */
+     ClpDualRowSteepest(int mode = 3);
+
+     /// Copy constructor
+     ClpDualRowSteepest(const ClpDualRowSteepest &);
+
+     /// Assignment operator
+     ClpDualRowSteepest & operator=(const ClpDualRowSteepest& rhs);
+
+     /// Fill most values
+     void fill(const ClpDualRowSteepest& rhs);
+
+     /// Destructor
+     virtual ~ClpDualRowSteepest ();
+
+     /// Clone
+     virtual ClpDualRowPivot * clone(bool copyData = true) const;
+
+     //@}
+     /**@name gets and sets */
+     //@{
+     /// Mode
+     inline int mode() const {
+          return mode_;
+     }
+     /// Set/ get persistence
+     inline void setPersistence(Persistence life) {
+          persistence_ = life;
+     }
+     inline Persistence persistence() const {
+          return persistence_ ;
+     }
+//@}
+
+     //---------------------------------------------------------------------------
+
+private:
+     ///@name Private member data
+     /** Status
+         0) Normal
+         -1) Needs initialization
+         1) Weights are stored by sequence number
+     */
+     int state_;
+     /** If 0 then we are using uninitialized weights, 1 then full,
+         if 2 then uninitialized partial, 3 switchable */
+     int mode_;
+     /// Life of weights
+     Persistence persistence_;
+     /// weight array
+     double * weights_;
+     /// square of infeasibility array (just for infeasible rows)
+     CoinIndexedVector * infeasible_;
+     /// alternate weight array (so we can unroll)
+     CoinIndexedVector * alternateWeights_;
+     /// save weight array (so we can use checkpoint)
+     CoinIndexedVector * savedWeights_;
+     /// Dubious weights
+     int * dubiousWeights_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpDummyMatrix.cpp b/cbits/coin/ClpDummyMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDummyMatrix.cpp
@@ -0,0 +1,263 @@
+/* $Id: ClpDummyMatrix.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdio>
+
+#include "CoinPragma.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpDummyMatrix.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpMessage.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpDummyMatrix::ClpDummyMatrix ()
+     : ClpMatrixBase()
+{
+     setType(14);
+     numberRows_ = 0;
+     numberColumns_ = 0;
+     numberElements_ = 0;
+}
+
+/* Constructor from data */
+ClpDummyMatrix::ClpDummyMatrix(int numberColumns, int numberRows,
+                               int numberElements)
+     : ClpMatrixBase()
+{
+     setType(14);
+     numberRows_ = numberRows;
+     numberColumns_ = numberColumns;
+     numberElements_ = numberElements;
+}
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpDummyMatrix::ClpDummyMatrix (const ClpDummyMatrix & rhs)
+     : ClpMatrixBase(rhs)
+{
+     numberRows_ = rhs.numberRows_;
+     numberColumns_ = rhs.numberColumns_;
+     numberElements_ = rhs.numberElements_;
+}
+
+ClpDummyMatrix::ClpDummyMatrix (const CoinPackedMatrix & )
+     : ClpMatrixBase()
+{
+     std::cerr << "Constructor from CoinPackedMatrix nnot supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpDummyMatrix::~ClpDummyMatrix ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpDummyMatrix &
+ClpDummyMatrix::operator=(const ClpDummyMatrix& rhs)
+{
+     if (this != &rhs) {
+          ClpMatrixBase::operator=(rhs);
+          numberRows_ = rhs.numberRows_;
+          numberColumns_ = rhs.numberColumns_;
+          numberElements_ = rhs.numberElements_;
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpMatrixBase * ClpDummyMatrix::clone() const
+{
+     return new ClpDummyMatrix(*this);
+}
+
+/* Returns a new matrix in reverse order without gaps */
+ClpMatrixBase *
+ClpDummyMatrix::reverseOrderedCopy() const
+{
+     std::cerr << "reverseOrderedCopy not supported - ClpDummyMatrix" << std::endl;
+     abort();
+     return NULL;
+}
+//unscaled versions
+void
+ClpDummyMatrix::times(double ,
+                      const double * , double * ) const
+{
+     std::cerr << "times not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+void
+ClpDummyMatrix::transposeTimes(double ,
+                               const double * , double * ) const
+{
+     std::cerr << "transposeTimes not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+void
+ClpDummyMatrix::times(double ,
+                      const double * , double * ,
+                      const double * ,
+                      const double * ) const
+{
+     std::cerr << "timesnot supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+void
+ClpDummyMatrix::transposeTimes( double,
+                                const double * , double * ,
+                                const double * ,
+                                const double * ) const
+{
+     std::cerr << "transposeTimesnot supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+/* Return <code>x * A + y</code> in <code>z</code>.
+	Squashes small elements and knows about ClpSimplex */
+void
+ClpDummyMatrix::transposeTimes(const ClpSimplex * , double ,
+                               const CoinIndexedVector * ,
+                               CoinIndexedVector * ,
+                               CoinIndexedVector * ) const
+{
+     std::cerr << "transposeTimes not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+/* Return <code>x *A in <code>z</code> but
+   just for indices in y */
+void
+ClpDummyMatrix::subsetTransposeTimes(const ClpSimplex * ,
+                                     const CoinIndexedVector * ,
+                                     const CoinIndexedVector * ,
+                                     CoinIndexedVector * ) const
+{
+     std::cerr << "subsetTransposeTimes not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+/// returns number of elements in column part of basis,
+CoinBigIndex
+ClpDummyMatrix::countBasis(const int * ,
+                           int & )
+{
+     std::cerr << "countBasis not supported - ClpDummyMatrix" << std::endl;
+     abort();
+     return 0;
+}
+void
+ClpDummyMatrix::fillBasis(ClpSimplex * ,
+                          const int * ,
+                          int & ,
+                          int * , int * ,
+                          int * , int * ,
+                          CoinFactorizationDouble * )
+{
+     std::cerr << "fillBasis not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+/* Unpacks a column into an CoinIndexedvector
+ */
+void
+ClpDummyMatrix::unpack(const ClpSimplex * , CoinIndexedVector * ,
+                       int ) const
+{
+     std::cerr << "unpack not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+/* Unpacks a column into an CoinIndexedvector
+** in packed foramt
+Note that model is NOT const.  Bounds and objective could
+be modified if doing column generation (just for this variable) */
+void
+ClpDummyMatrix::unpackPacked(ClpSimplex * ,
+                             CoinIndexedVector * ,
+                             int ) const
+{
+     std::cerr << "unpackPacked not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+/* Adds multiple of a column into an CoinIndexedvector
+      You can use quickAdd to add to vector */
+void
+ClpDummyMatrix::add(const ClpSimplex * , CoinIndexedVector * ,
+                    int , double ) const
+{
+     std::cerr << "add not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+/* Adds multiple of a column into an array */
+void
+ClpDummyMatrix::add(const ClpSimplex * , double * ,
+                    int , double ) const
+{
+     std::cerr << "add not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+
+// Return a complete CoinPackedMatrix
+CoinPackedMatrix *
+ClpDummyMatrix::getPackedMatrix() const
+{
+     std::cerr << "getPackedMatrix not supported - ClpDummyMatrix" << std::endl;
+     abort();
+     return NULL;
+}
+/* A vector containing the elements in the packed matrix. Note that there
+   might be gaps in this list, entries that do not belong to any
+   major-dimension vector. To get the actual elements one should look at
+   this vector together with vectorStarts and vectorLengths. */
+const double *
+ClpDummyMatrix::getElements() const
+{
+     std::cerr << "getElements not supported - ClpDummyMatrix" << std::endl;
+     abort();
+     return NULL;
+}
+
+const CoinBigIndex *
+ClpDummyMatrix::getVectorStarts() const
+{
+     std::cerr << "getVectorStarts not supported - ClpDummyMatrix" << std::endl;
+     abort();
+     return NULL;
+}
+/* The lengths of the major-dimension vectors. */
+const int *
+ClpDummyMatrix::getVectorLengths() const
+{
+     std::cerr << "get VectorLengths not supported - ClpDummyMatrix" << std::endl;
+     abort();
+     return NULL;
+}
+/* Delete the columns whose indices are listed in <code>indDel</code>. */
+void ClpDummyMatrix::deleteCols(const int , const int * )
+{
+     std::cerr << "deleteCols not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+/* Delete the rows whose indices are listed in <code>indDel</code>. */
+void ClpDummyMatrix::deleteRows(const int , const int * )
+{
+     std::cerr << "deleteRows not supported - ClpDummyMatrix" << std::endl;
+     abort();
+}
+const int *
+ClpDummyMatrix::getIndices() const
+{
+     std::cerr << "getIndices not supported - ClpDummyMatrix" << std::endl;
+     abort();
+     return NULL;
+}
diff --git a/cbits/coin/ClpDummyMatrix.hpp b/cbits/coin/ClpDummyMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDummyMatrix.hpp
@@ -0,0 +1,183 @@
+/* $Id: ClpDummyMatrix.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpDummyMatrix_H
+#define ClpDummyMatrix_H
+
+
+#include "CoinPragma.hpp"
+
+#include "ClpMatrixBase.hpp"
+
+/** This implements a dummy matrix as derived from ClpMatrixBase.
+    This is so you can do ClpPdco but may come in useful elsewhere.
+    It just has dimensions but no data
+*/
+
+
+class ClpDummyMatrix : public ClpMatrixBase {
+
+public:
+     /**@name Useful methods */
+     //@{
+     /// Return a complete CoinPackedMatrix
+     virtual CoinPackedMatrix * getPackedMatrix() const;
+     /** Whether the packed matrix is column major ordered or not. */
+     virtual bool isColOrdered() const {
+          return true;
+     }
+     /** Number of entries in the packed matrix. */
+     virtual  CoinBigIndex getNumElements() const {
+          return numberElements_;
+     }
+     /** Number of columns. */
+     virtual int getNumCols() const {
+          return numberColumns_;
+     }
+     /** Number of rows. */
+     virtual int getNumRows() const {
+          return numberRows_;
+     }
+
+     /** A vector containing the elements in the packed matrix. Note that there
+      might be gaps in this list, entries that do not belong to any
+      major-dimension vector. To get the actual elements one should look at
+      this vector together with vectorStarts and vectorLengths. */
+     virtual const double * getElements() const;
+     /** A vector containing the minor indices of the elements in the packed
+          matrix. Note that there might be gaps in this list, entries that do not
+          belong to any major-dimension vector. To get the actual elements one
+          should look at this vector together with vectorStarts and
+          vectorLengths. */
+     virtual const int * getIndices() const;
+
+     virtual const CoinBigIndex * getVectorStarts() const;
+     /** The lengths of the major-dimension vectors. */
+     virtual const int * getVectorLengths() const;
+
+     /** Delete the columns whose indices are listed in <code>indDel</code>. */
+     virtual void deleteCols(const int numDel, const int * indDel);
+     /** Delete the rows whose indices are listed in <code>indDel</code>. */
+     virtual void deleteRows(const int numDel, const int * indDel);
+     /** Returns a new matrix in reverse order without gaps */
+     virtual ClpMatrixBase * reverseOrderedCopy() const;
+     /// Returns number of elements in column part of basis
+     virtual CoinBigIndex countBasis(const int * whichColumn,
+                                     int & numberColumnBasic);
+     /// Fills in column part of basis
+     virtual void fillBasis(ClpSimplex * model,
+                            const int * whichColumn,
+                            int & numberColumnBasic,
+                            int * row, int * start,
+                            int * rowCount, int * columnCount,
+                            CoinFactorizationDouble * element);
+     /** Unpacks a column into an CoinIndexedvector
+      */
+     virtual void unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                         int column) const ;
+     /** Unpacks a column into an CoinIndexedvector
+      ** in packed foramt
+         Note that model is NOT const.  Bounds and objective could
+         be modified if doing column generation (just for this variable) */
+     virtual void unpackPacked(ClpSimplex * model,
+                               CoinIndexedVector * rowArray,
+                               int column) const;
+     /** Adds multiple of a column into an CoinIndexedvector
+         You can use quickAdd to add to vector */
+     virtual void add(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                      int column, double multiplier) const ;
+     /** Adds multiple of a column into an array */
+     virtual void add(const ClpSimplex * model, double * array,
+                      int column, double multiplier) const;
+     /// Allow any parts of a created CoinMatrix to be deleted
+     /// Allow any parts of a created CoinPackedMatrix to be deleted
+     virtual void releasePackedMatrix() const {}
+     //@}
+
+     /**@name Matrix times vector methods */
+     //@{
+     /** Return <code>y + A * scalar *x</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numColumns()</code>
+         @pre <code>y</code> must be of size <code>numRows()</code> */
+     virtual void times(double scalar,
+                        const double * x, double * y) const;
+     /// And for scaling
+     virtual void times(double scalar,
+                        const double * x, double * y,
+                        const double * rowScale,
+                        const double * columnScale) const;
+     /** Return <code>y + x * scalar * A</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numRows()</code>
+         @pre <code>y</code> must be of size <code>numColumns()</code> */
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y) const;
+     /// And for scaling
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y,
+                                 const double * rowScale,
+                                 const double * columnScale) const;
+
+     using ClpMatrixBase::transposeTimes ;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Can use y as temporary array (will be empty at end)
+     Note - If x packed mode - then z packed mode */
+     virtual void transposeTimes(const ClpSimplex * model, double scalar,
+                                 const CoinIndexedVector * x,
+                                 CoinIndexedVector * y,
+                                 CoinIndexedVector * z) const;
+     /** Return <code>x *A</code> in <code>z</code> but
+     just for indices in y.
+     Note - If x packed mode - then z packed mode
+     Squashes small elements and knows about ClpSimplex */
+     virtual void subsetTransposeTimes(const ClpSimplex * model,
+                                       const CoinIndexedVector * x,
+                                       const CoinIndexedVector * y,
+                                       CoinIndexedVector * z) const;
+     //@}
+
+     /**@name Other */
+     //@{
+     //@}
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpDummyMatrix();
+     /// Constructor with data
+     ClpDummyMatrix(int numberColumns, int numberRows,
+                    int numberElements);
+     /** Destructor */
+     virtual ~ClpDummyMatrix();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpDummyMatrix(const ClpDummyMatrix&);
+     /** The copy constructor from an CoinDummyMatrix. */
+     ClpDummyMatrix(const CoinPackedMatrix&);
+
+     ClpDummyMatrix& operator=(const ClpDummyMatrix&);
+     /// Clone
+     virtual ClpMatrixBase * clone() const ;
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Number of rows
+     int numberRows_;
+     /// Number of columns
+     int numberColumns_;
+     /// Number of elements
+     int numberElements_;
+
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpDynamicExampleMatrix.cpp b/cbits/coin/ClpDynamicExampleMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDynamicExampleMatrix.cpp
@@ -0,0 +1,683 @@
+/* $Id: ClpDynamicExampleMatrix.cpp 1941 2013-04-10 16:52:27Z stefan $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdio>
+
+#include "CoinPragma.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpQuadraticObjective.hpp"
+#include "ClpNonLinearCost.hpp"
+// at end to get min/max!
+#include "ClpDynamicExampleMatrix.hpp"
+#include "ClpMessage.hpp"
+//#define CLP_DEBUG
+//#define CLP_DEBUG_PRINT
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpDynamicExampleMatrix::ClpDynamicExampleMatrix ()
+     : ClpDynamicMatrix(),
+       numberColumns_(0),
+       startColumnGen_(NULL),
+       rowGen_(NULL),
+       elementGen_(NULL),
+       costGen_(NULL),
+       fullStartGen_(NULL),
+       dynamicStatusGen_(NULL),
+       idGen_(NULL),
+       columnLowerGen_(NULL),
+       columnUpperGen_(NULL)
+{
+     setType(25);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpDynamicExampleMatrix::ClpDynamicExampleMatrix (const ClpDynamicExampleMatrix & rhs)
+     : ClpDynamicMatrix(rhs)
+{
+     numberColumns_ = rhs.numberColumns_;
+     startColumnGen_ = ClpCopyOfArray(rhs.startColumnGen_, numberColumns_ + 1);
+     CoinBigIndex numberElements = startColumnGen_[numberColumns_];
+     rowGen_ = ClpCopyOfArray(rhs.rowGen_, numberElements);;
+     elementGen_ = ClpCopyOfArray(rhs.elementGen_, numberElements);;
+     costGen_ = ClpCopyOfArray(rhs.costGen_, numberColumns_);
+     fullStartGen_ = ClpCopyOfArray(rhs.fullStartGen_, numberSets_ + 1);
+     dynamicStatusGen_ = ClpCopyOfArray(rhs.dynamicStatusGen_, numberColumns_);
+     idGen_ = ClpCopyOfArray(rhs.idGen_, maximumGubColumns_);
+     columnLowerGen_ = ClpCopyOfArray(rhs.columnLowerGen_, numberColumns_);
+     columnUpperGen_ = ClpCopyOfArray(rhs.columnUpperGen_, numberColumns_);
+}
+
+/* This is the real constructor*/
+ClpDynamicExampleMatrix::ClpDynamicExampleMatrix(ClpSimplex * model, int numberSets,
+          int numberGubColumns, const int * starts,
+          const double * lower, const double * upper,
+          const CoinBigIndex * startColumn, const int * row,
+          const double * element, const double * cost,
+          const double * columnLower, const double * columnUpper,
+          const unsigned char * status,
+          const unsigned char * dynamicStatus,
+          int numberIds, const int *ids)
+     : ClpDynamicMatrix(model, numberSets, 0, NULL, lower, upper, NULL, NULL, NULL, NULL, NULL, NULL,
+                        NULL, NULL)
+{
+     setType(25);
+     numberColumns_ = numberGubColumns;
+     // start with safe values - then experiment
+     maximumGubColumns_ = numberColumns_;
+     maximumElements_ = startColumn[numberColumns_];
+     // delete odd stuff created by ClpDynamicMatrix constructor
+     delete [] startSet_;
+     startSet_ = new int [numberSets_];
+     delete [] next_;
+     next_ = new int [maximumGubColumns_];
+     delete [] row_;
+     delete [] element_;
+     delete [] startColumn_;
+     delete [] cost_;
+     delete [] columnLower_;
+     delete [] columnUpper_;
+     delete [] dynamicStatus_;
+     delete [] status_;
+     delete [] id_;
+     // and size correctly
+     row_ = new int [maximumElements_];
+     element_ = new double [maximumElements_];
+     startColumn_ = new CoinBigIndex [maximumGubColumns_+1];
+     // say no columns yet
+     numberGubColumns_ = 0;
+     startColumn_[0] = 0;
+     cost_ = new double[maximumGubColumns_];
+     dynamicStatus_ = new unsigned char [2*maximumGubColumns_];
+     memset(dynamicStatus_, 0, maximumGubColumns_);
+     id_ = new int[maximumGubColumns_];
+     if (columnLower)
+          columnLower_ = new double[maximumGubColumns_];
+     else
+          columnLower_ = NULL;
+     if (columnUpper)
+          columnUpper_ = new double[maximumGubColumns_];
+     else
+          columnUpper_ = NULL;
+     // space for ids
+     idGen_ = new int [maximumGubColumns_];
+     int iSet;
+     for (iSet = 0; iSet < numberSets_; iSet++)
+          startSet_[iSet] = -1;
+     // This starts code specific to this storage method
+     CoinBigIndex i;
+     fullStartGen_ = ClpCopyOfArray(starts, numberSets_ + 1);
+     startColumnGen_ = ClpCopyOfArray(startColumn, numberColumns_ + 1);
+     CoinBigIndex numberElements = startColumnGen_[numberColumns_];
+     rowGen_ = ClpCopyOfArray(row, numberElements);
+     elementGen_ = new double[numberElements];
+     for (i = 0; i < numberElements; i++)
+          elementGen_[i] = element[i];
+     costGen_ = new double[numberColumns_];
+     for (i = 0; i < numberColumns_; i++) {
+          costGen_[i] = cost[i];
+          // I don't think I need sorted but ...
+          CoinSort_2(rowGen_ + startColumnGen_[i], rowGen_ + startColumnGen_[i+1], elementGen_ + startColumnGen_[i]);
+     }
+     if (columnLower) {
+          columnLowerGen_ = new double[numberColumns_];
+          for (i = 0; i < numberColumns_; i++) {
+               columnLowerGen_[i] = columnLower[i];
+               if (columnLowerGen_[i]) {
+                    printf("Non-zero lower bounds not allowed - subtract from model\n");
+                    abort();
+               }
+          }
+     } else {
+          columnLowerGen_ = NULL;
+     }
+     if (columnUpper) {
+          columnUpperGen_ = new double[numberColumns_];
+          for (i = 0; i < numberColumns_; i++)
+               columnUpperGen_[i] = columnUpper[i];
+     } else {
+          columnUpperGen_ = NULL;
+     }
+     // end specific coding
+     if (columnUpper_) {
+          // set all upper bounds so we have enough space
+          double * columnUpper = model->columnUpper();
+          for(i = firstDynamic_; i < lastDynamic_; i++)
+               columnUpper[i] = 1.0e10;
+     }
+     status_ = new unsigned char [2*numberSets_+4];
+     if (status) {
+          memcpy(status_,status, numberSets_ * sizeof(char));
+          assert (dynamicStatus);
+          CoinMemcpyN(dynamicStatus, numberIds, dynamicStatus_);
+          assert (numberIds);
+     } else {
+          assert (!numberIds);
+          memset(status_, 0, numberSets_);
+          for (i = 0; i < numberSets_; i++) {
+               // make slack key
+               setStatus(i, ClpSimplex::basic);
+          }
+     }
+     dynamicStatusGen_ = new unsigned char [numberColumns_];
+     memset(dynamicStatusGen_, 0, numberColumns_); // for clarity
+     for (i = 0; i < numberColumns_; i++)
+          setDynamicStatusGen(i, atLowerBound);
+     // Populate with enough columns
+     if (!numberIds) {
+          // This could be made more sophisticated
+          for (iSet = 0; iSet < numberSets_; iSet++) {
+               int sequence = fullStartGen_[iSet];
+               CoinBigIndex start = startColumnGen_[sequence];
+               addColumn(startColumnGen_[sequence+1] - start,
+                         rowGen_ + start,
+                         elementGen_ + start,
+                         costGen_[sequence],
+                         columnLowerGen_ ? columnLowerGen_[sequence] : 0,
+                         columnUpperGen_ ? columnUpperGen_[sequence] : 1.0e30,
+                         iSet, getDynamicStatusGen(sequence));
+               idGen_[iSet] = sequence; // say which one in
+               setDynamicStatusGen(sequence, inSmall);
+          }
+     } else {
+          // put back old ones
+          int * set = new int[numberColumns_];
+          for (iSet = 0; iSet < numberSets_; iSet++) {
+               for (CoinBigIndex j = fullStartGen_[iSet]; j < fullStartGen_[iSet+1]; j++)
+                    set[j] = iSet;
+          }
+          for (int i = 0; i < numberIds; i++) {
+               int sequence = ids[i];
+               CoinBigIndex start = startColumnGen_[sequence];
+               addColumn(startColumnGen_[sequence+1] - start,
+                         rowGen_ + start,
+                         elementGen_ + start,
+                         costGen_[sequence],
+                         columnLowerGen_ ? columnLowerGen_[sequence] : 0,
+                         columnUpperGen_ ? columnUpperGen_[sequence] : 1.0e30,
+                         set[sequence], getDynamicStatus(i));
+               idGen_[iSet] = sequence; // say which one in
+               setDynamicStatusGen(sequence, inSmall);
+          }
+          delete [] set;
+     }
+     if (!status) {
+          gubCrash();
+     } else {
+          initialProblem();
+     }
+}
+#if 0
+// This constructor just takes over ownership
+ClpDynamicExampleMatrix::ClpDynamicExampleMatrix(ClpSimplex * model, int numberSets,
+          int numberGubColumns, int * starts,
+          const double * lower, const double * upper,
+          int * startColumn, int * row,
+          double * element, double * cost,
+          double * columnLower, double * columnUpper,
+          const unsigned char * status,
+          const unsigned char * dynamicStatus,
+          int numberIds, const int *ids)
+     : ClpDynamicMatrix(model, numberSets, 0, NULL, lower, upper, NULL, NULL, NULL, NULL, NULL, NULL,
+                        NULL, NULL)
+{
+     setType(25);
+     numberColumns_ = numberGubColumns;
+     // start with safe values - then experiment
+     maximumGubColumns_ = numberColumns_;
+     maximumElements_ = startColumn[numberColumns_];
+     // delete odd stuff created by ClpDynamicMatrix constructor
+     delete [] startSet_;
+     startSet_ = new int [numberSets_];
+     delete [] next_;
+     next_ = new int [maximumGubColumns_];
+     delete [] row_;
+     delete [] element_;
+     delete [] startColumn_;
+     delete [] cost_;
+     delete [] columnLower_;
+     delete [] columnUpper_;
+     delete [] dynamicStatus_;
+     delete [] status_;
+     delete [] id_;
+     // and size correctly
+     row_ = new int [maximumElements_];
+     element_ = new double [maximumElements_];
+     startColumn_ = new CoinBigIndex [maximumGubColumns_+1];
+     // say no columns yet
+     numberGubColumns_ = 0;
+     startColumn_[0] = 0;
+     cost_ = new double[maximumGubColumns_];
+     dynamicStatus_ = new unsigned char [2*maximumGubColumns_];
+     memset(dynamicStatus_, 0, maximumGubColumns_);
+     id_ = new int[maximumGubColumns_];
+     if (columnLower)
+          columnLower_ = new double[maximumGubColumns_];
+     else
+          columnLower_ = NULL;
+     if (columnUpper)
+          columnUpper_ = new double[maximumGubColumns_];
+     else
+          columnUpper_ = NULL;
+     // space for ids
+     idGen_ = new int [maximumGubColumns_];
+     int iSet;
+     for (iSet = 0; iSet < numberSets_; iSet++)
+          startSet_[iSet] = -1;
+     // This starts code specific to this storage method
+     CoinBigIndex i;
+     fullStartGen_ = starts;
+     startColumnGen_ = startColumn;
+     rowGen_ = row;
+     elementGen_ = element;
+     costGen_ = cost;
+     for (i = 0; i < numberColumns_; i++) {
+          // I don't think I need sorted but ...
+          CoinSort_2(rowGen_ + startColumnGen_[i], rowGen_ + startColumnGen_[i+1], elementGen_ + startColumnGen_[i]);
+     }
+     if (columnLower) {
+          columnLowerGen_ = columnLower;
+          for (i = 0; i < numberColumns_; i++) {
+               if (columnLowerGen_[i]) {
+                    printf("Non-zero lower bounds not allowed - subtract from model\n");
+                    abort();
+               }
+          }
+     } else {
+          columnLowerGen_ = NULL;
+     }
+     if (columnUpper) {
+          columnUpperGen_ = columnUpper;
+     } else {
+          columnUpperGen_ = NULL;
+     }
+     // end specific coding
+     if (columnUpper_) {
+          // set all upper bounds so we have enough space
+          double * columnUpper = model->columnUpper();
+          for(i = firstDynamic_; i < lastDynamic_; i++)
+               columnUpper[i] = 1.0e10;
+     }
+     status_ = new unsigned char [2*numberSets_+4];
+     if (status) {
+          memcpy(status_,status, numberSets_ * sizeof(char));
+          assert (dynamicStatus);
+          CoinMemcpyN(dynamicStatus, numberIds, dynamicStatus_);
+          assert (numberIds);
+     } else {
+          assert (!numberIds);
+          memset(status_, 0, numberSets_);
+          for (i = 0; i < numberSets_; i++) {
+               // make slack key
+               setStatus(i, ClpSimplex::basic);
+          }
+     }
+     dynamicStatusGen_ = new unsigned char [numberColumns_];
+     memset(dynamicStatusGen_, 0, numberColumns_); // for clarity
+     for (i = 0; i < numberColumns_; i++)
+          setDynamicStatusGen(i, atLowerBound);
+     // Populate with enough columns
+     if (!numberIds) {
+          // This could be made more sophisticated
+          for (iSet = 0; iSet < numberSets_; iSet++) {
+               int sequence = fullStartGen_[iSet];
+               CoinBigIndex start = startColumnGen_[sequence];
+               addColumn(startColumnGen_[sequence+1] - start,
+                         rowGen_ + start,
+                         elementGen_ + start,
+                         costGen_[sequence],
+                         columnLowerGen_ ? columnLowerGen_[sequence] : 0,
+                         columnUpperGen_ ? columnUpperGen_[sequence] : 1.0e30,
+                         iSet, getDynamicStatusGen(sequence));
+               idGen_[iSet] = sequence; // say which one in
+               setDynamicStatusGen(sequence, inSmall);
+          }
+     } else {
+          // put back old ones
+          int * set = new int[numberColumns_];
+          for (iSet = 0; iSet < numberSets_; iSet++) {
+               for (CoinBigIndex j = fullStartGen_[iSet]; j < fullStartGen_[iSet+1]; j++)
+                    set[j] = iSet;
+          }
+          for (int i = 0; i < numberIds; i++) {
+               int sequence = ids[i];
+               int iSet = set[sequence];
+               CoinBigIndex start = startColumnGen_[sequence];
+               addColumn(startColumnGen_[sequence+1] - start,
+                         rowGen_ + start,
+                         elementGen_ + start,
+                         costGen_[sequence],
+                         columnLowerGen_ ? columnLowerGen_[sequence] : 0,
+                         columnUpperGen_ ? columnUpperGen_[sequence] : 1.0e30,
+                         iSet, getDynamicStatus(i));
+               idGen_[i] = sequence; // say which one in
+               setDynamicStatusGen(sequence, inSmall);
+          }
+          delete [] set;
+     }
+     if (!status) {
+          gubCrash();
+     } else {
+          initialProblem();
+     }
+}
+#endif
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpDynamicExampleMatrix::~ClpDynamicExampleMatrix ()
+{
+     delete [] startColumnGen_;
+     delete [] rowGen_;
+     delete [] elementGen_;
+     delete [] costGen_;
+     delete [] fullStartGen_;
+     delete [] dynamicStatusGen_;
+     delete [] idGen_;
+     delete [] columnLowerGen_;
+     delete [] columnUpperGen_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpDynamicExampleMatrix &
+ClpDynamicExampleMatrix::operator=(const ClpDynamicExampleMatrix& rhs)
+{
+     if (this != &rhs) {
+          ClpDynamicMatrix::operator=(rhs);
+          numberColumns_ = rhs.numberColumns_;
+          delete [] startColumnGen_;
+          delete [] rowGen_;
+          delete [] elementGen_;
+          delete [] costGen_;
+          delete [] fullStartGen_;
+          delete [] dynamicStatusGen_;
+          delete [] idGen_;
+          delete [] columnLowerGen_;
+          delete [] columnUpperGen_;
+          startColumnGen_ = ClpCopyOfArray(rhs.startColumnGen_, numberColumns_ + 1);
+          CoinBigIndex numberElements = startColumnGen_[numberColumns_];
+          rowGen_ = ClpCopyOfArray(rhs.rowGen_, numberElements);;
+          elementGen_ = ClpCopyOfArray(rhs.elementGen_, numberElements);;
+          costGen_ = ClpCopyOfArray(rhs.costGen_, numberColumns_);
+          fullStartGen_ = ClpCopyOfArray(rhs.fullStartGen_, numberSets_ + 1);
+          dynamicStatusGen_ = ClpCopyOfArray(rhs.dynamicStatusGen_, numberColumns_);
+          idGen_ = ClpCopyOfArray(rhs.idGen_, maximumGubColumns_);
+          columnLowerGen_ = ClpCopyOfArray(rhs.columnLowerGen_, numberColumns_);
+          columnUpperGen_ = ClpCopyOfArray(rhs.columnUpperGen_, numberColumns_);
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpMatrixBase * ClpDynamicExampleMatrix::clone() const
+{
+     return new ClpDynamicExampleMatrix(*this);
+}
+// Partial pricing
+void
+ClpDynamicExampleMatrix::partialPricing(ClpSimplex * model, double startFraction, double endFraction,
+                                        int & bestSequence, int & numberWanted)
+{
+     numberWanted = currentWanted_;
+     assert(!model->rowScale());
+     if (!numberSets_) {
+          // no gub
+          ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
+     } else {
+          // and do some proportion of full set
+          int startG2 = static_cast<int> (startFraction * numberSets_);
+          int endG2 = static_cast<int> (endFraction * numberSets_ + 0.1);
+          endG2 = CoinMin(endG2, numberSets_);
+          //printf("gub price - set start %d end %d\n",
+          //   startG2,endG2);
+          double tolerance = model->currentDualTolerance();
+          double * reducedCost = model->djRegion();
+          const double * duals = model->dualRowSolution();
+          double bestDj;
+          int numberRows = model->numberRows();
+          int slackOffset = lastDynamic_ + numberRows;
+          int structuralOffset = slackOffset + numberSets_;
+          int structuralOffset2 = structuralOffset + maximumGubColumns_;
+          // If nothing found yet can go all the way to end
+          int endAll = endG2;
+          if (bestSequence < 0 && !startG2)
+               endAll = numberSets_;
+          if (bestSequence >= 0) {
+               if (bestSequence != savedBestSequence_)
+                    bestDj = fabs(reducedCost[bestSequence]); // dj from slacks or permanent
+               else
+                    bestDj = savedBestDj_;
+          } else {
+               bestDj = tolerance;
+          }
+          int saveSequence = bestSequence;
+          double djMod = 0.0;
+          double bestDjMod = 0.0;
+          //printf("iteration %d start %d end %d - wanted %d\n",model->numberIterations(),
+          //     startG2,endG2,numberWanted);
+          int bestSet = -1;
+          int minSet = minimumObjectsScan_ < 0 ? 5 : minimumObjectsScan_;
+          int minNeg = minimumGoodReducedCosts_ < 0 ? 5 : minimumGoodReducedCosts_;
+          for (int iSet = startG2; iSet < endAll; iSet++) {
+               if (numberWanted + minNeg < originalWanted_ && iSet > startG2 + minSet) {
+                    // give up
+                    numberWanted = 0;
+                    break;
+               } else if (iSet == endG2 && bestSequence >= 0) {
+                    break;
+               }
+               int gubRow = toIndex_[iSet];
+               if (gubRow >= 0) {
+                    djMod = duals[gubRow+numberStaticRows_]; // have I got sign right?
+               } else {
+                    int iBasic = keyVariable_[iSet];
+                    if (iBasic >= numberColumns_) {
+                         djMod = 0.0; // set not in
+                    } else {
+                         // get dj without
+                         djMod = 0.0;
+                         for (CoinBigIndex j = startColumn_[iBasic];
+                                   j < startColumn_[iBasic+1]; j++) {
+                              int jRow = row_[j];
+                              djMod -= duals[jRow] * element_[j];
+                         }
+                         djMod += cost_[iBasic];
+                         // See if gub slack possible - dj is djMod
+                         if (getStatus(iSet) == ClpSimplex::atLowerBound) {
+                              double value = -djMod;
+                              if (value > tolerance) {
+                                   numberWanted--;
+                                   if (value > bestDj) {
+                                        // check flagged variable and correct dj
+                                        if (!flagged(iSet)) {
+                                             bestDj = value;
+                                             bestSequence = slackOffset + iSet;
+                                             bestDjMod = djMod;
+                                             bestSet = iSet;
+                                        } else {
+                                             // just to make sure we don't exit before got something
+                                             numberWanted++;
+                                             abort();
+                                        }
+                                   }
+                              }
+                         } else if (getStatus(iSet) == ClpSimplex::atUpperBound) {
+                              double value = djMod;
+                              if (value > tolerance) {
+                                   numberWanted--;
+                                   if (value > bestDj) {
+                                        // check flagged variable and correct dj
+                                        if (!flagged(iSet)) {
+                                             bestDj = value;
+                                             bestSequence = slackOffset + iSet;
+                                             bestDjMod = djMod;
+                                             bestSet = iSet;
+                                        } else {
+                                             // just to make sure we don't exit before got something
+                                             numberWanted++;
+                                             abort();
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+               // do ones in small
+               int iSequence = startSet_[iSet];
+               while (iSequence >= 0) {
+                    DynamicStatus status = getDynamicStatus(iSequence);
+                    if (status == atLowerBound || status == atUpperBound) {
+                         double value = cost_[iSequence] - djMod;
+                         for (CoinBigIndex j = startColumn_[iSequence];
+                                   j < startColumn_[iSequence+1]; j++) {
+                              int jRow = row_[j];
+                              value -= duals[jRow] * element_[j];
+                         }
+                         // change sign if at lower bound
+                         if (status == atLowerBound)
+                              value = -value;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = structuralOffset + iSequence;
+                                        bestDjMod = djMod;
+                                        bestSet = iSet;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                    }
+                    iSequence = next_[iSequence]; //onto next in set
+               }
+               // and now get best by column generation
+               // If no upper bounds we may not need status test
+               for (iSequence = fullStartGen_[iSet]; iSequence < fullStartGen_[iSet+1]; iSequence++) {
+                    DynamicStatus status = getDynamicStatusGen(iSequence);
+                    assert (status != atUpperBound && status != soloKey);
+                    if (status == atLowerBound) {
+                         double value = costGen_[iSequence] - djMod;
+                         for (CoinBigIndex j = startColumnGen_[iSequence];
+                                   j < startColumnGen_[iSequence+1]; j++) {
+                              int jRow = rowGen_[j];
+                              value -= duals[jRow] * elementGen_[j];
+                         }
+                         // change sign as at lower bound
+                         value = -value;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!flaggedGen(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = structuralOffset2 + iSequence;
+                                        bestDjMod = djMod;
+                                        bestSet = iSet;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                    }
+               }
+               if (numberWanted <= 0) {
+                    numberWanted = 0;
+                    break;
+               }
+          }
+          if (bestSequence != saveSequence) {
+               savedBestGubDual_ = bestDjMod;
+               savedBestDj_ = bestDj;
+               savedBestSequence_ = bestSequence;
+               savedBestSet_ = bestSet;
+          }
+          // Do packed part before gub
+          // always???
+          // Resize so just do to gub
+          numberActiveColumns_ = firstDynamic_;
+          int saveMinNeg = minimumGoodReducedCosts_;
+          if (bestSequence >= 0)
+               minimumGoodReducedCosts_ = -2;
+          currentWanted_ = numberWanted;
+          ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
+          numberActiveColumns_ = matrix_->getNumCols();
+          minimumGoodReducedCosts_ = saveMinNeg;
+          // See if may be finished
+          if (!startG2 && bestSequence < 0)
+               infeasibilityWeight_ = model_->infeasibilityCost();
+          else if (bestSequence >= 0)
+               infeasibilityWeight_ = -1.0;
+          currentWanted_ = numberWanted;
+     }
+}
+/* Creates a variable.  This is called after partial pricing and may modify matrix.
+   May update bestSequence.
+*/
+void
+ClpDynamicExampleMatrix::createVariable(ClpSimplex * model, int & bestSequence)
+{
+     int numberRows = model->numberRows();
+     int slackOffset = lastDynamic_ + numberRows;
+     int structuralOffset = slackOffset + numberSets_;
+     int bestSequence2 = savedBestSequence_ - structuralOffset;
+     if (bestSequence2 >= 0) {
+          // See if needs new
+          if (bestSequence2 >= maximumGubColumns_) {
+               bestSequence2 -= maximumGubColumns_;
+               int sequence = addColumn(startColumnGen_[bestSequence2+1] - startColumnGen_[bestSequence2],
+                                        rowGen_ + startColumnGen_[bestSequence2],
+                                        elementGen_ + startColumnGen_[bestSequence2],
+                                        costGen_[bestSequence2],
+                                        columnLowerGen_ ? columnLowerGen_[bestSequence2] : 0,
+                                        columnUpperGen_ ? columnUpperGen_[bestSequence2] : 1.0e30,
+                                        savedBestSet_, getDynamicStatusGen(bestSequence2));
+               savedBestSequence_ = structuralOffset + sequence;
+               idGen_[sequence] = bestSequence2;
+               setDynamicStatusGen(bestSequence2, inSmall);
+          }
+     }
+     ClpDynamicMatrix::createVariable(model, bestSequence/*, bestSequence2*/);
+     // clear for next iteration
+     savedBestSequence_ = -1;
+}
+/* If addColumn forces compression then this allows descendant to know what to do.
+   If >=0 then entry stayed in, if -1 then entry went out to lower bound.of zero.
+   Entries at upper bound (really nonzero) never go out (at present).
+*/
+void
+ClpDynamicExampleMatrix::packDown(const int * in, int numberToPack)
+{
+     int put = 0;
+     for (int i = 0; i < numberToPack; i++) {
+          int id = idGen_[i];
+          if (in[i] >= 0) {
+               // stays in
+               assert (put == in[i]); // true for now
+               idGen_[put++] = id;
+          } else {
+               // out to lower bound
+               setDynamicStatusGen(id, atLowerBound);
+          }
+     }
+     assert (put == numberGubColumns_);
+}
diff --git a/cbits/coin/ClpDynamicExampleMatrix.hpp b/cbits/coin/ClpDynamicExampleMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDynamicExampleMatrix.hpp
@@ -0,0 +1,186 @@
+/* $Id: ClpDynamicExampleMatrix.hpp 1941 2013-04-10 16:52:27Z stefan $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpDynamicExampleMatrix_H
+#define ClpDynamicExampleMatrix_H
+
+
+#include "CoinPragma.hpp"
+
+#include "ClpDynamicMatrix.hpp"
+class ClpSimplex;
+/** This implements a dynamic matrix when we have a limit on the number of
+    "interesting rows". This version inherits from ClpDynamicMatrix and knows that
+    the real matrix is gub.  This acts just like ClpDynamicMatrix but generates columns.
+    This "generates" columns by choosing from stored set.  It is maent as a starting point
+    as to how you could use shortest path to generate columns.
+
+    So it has its own copy of all data needed.  It populates ClpDynamicWatrix with enough
+    to allow for gub keys and active variables.  In turn ClpDynamicMatrix populates
+    a CoinPackedMatrix with active columns and rows.
+
+    As there is one copy here and one in ClpDynamicmatrix these names end in Gen_
+
+    It is obviously more efficient to just use ClpDynamicMatrix but the ideas is to
+    show how much code a user would have to write.
+
+    This does not work very well with bounds
+
+*/
+
+class ClpDynamicExampleMatrix : public ClpDynamicMatrix {
+
+public:
+     /**@name Main functions provided */
+     //@{
+     /// Partial pricing
+     virtual void partialPricing(ClpSimplex * model, double start, double end,
+                                 int & bestSequence, int & numberWanted);
+
+     /** Creates a variable.  This is called after partial pricing and will modify matrix.
+         Will update bestSequence.
+     */
+     virtual void createVariable(ClpSimplex * model, int & bestSequence);
+     /** If addColumn forces compression then this allows descendant to know what to do.
+         If >= then entry stayed in, if -1 then entry went out to lower bound.of zero.
+         Entries at upper bound (really nonzero) never go out (at present).
+     */
+     virtual void packDown(const int * in, int numberToPack);
+     //@}
+
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpDynamicExampleMatrix();
+     /** This is the real constructor.
+         It assumes factorization frequency will not be changed.
+         This resizes model !!!!
+         The contents of original matrix in model will be taken over and original matrix
+         will be sanitized so can be deleted (to avoid a very small memory leak)
+      */
+     ClpDynamicExampleMatrix(ClpSimplex * model, int numberSets,
+                             int numberColumns, const int * starts,
+                             const double * lower, const double * upper,
+                             const int * startColumn, const int * row,
+                             const double * element, const double * cost,
+                             const double * columnLower = NULL, const double * columnUpper = NULL,
+                             const unsigned char * status = NULL,
+                             const unsigned char * dynamicStatus = NULL,
+                             int numberIds = 0, const int *ids = NULL);
+#if 0
+     /// This constructor just takes over ownership (except for lower, upper)
+     ClpDynamicExampleMatrix(ClpSimplex * model, int numberSets,
+                             int numberColumns, int * starts,
+                             const double * lower, const double * upper,
+                             int * startColumn, int * row,
+                             double * element, double * cost,
+                             double * columnLower = NULL, double * columnUpper = NULL,
+                             const unsigned char * status = NULL,
+                             const unsigned char * dynamicStatus = NULL,
+                             int numberIds = 0, const int *ids = NULL);
+#endif
+     /** Destructor */
+     virtual ~ClpDynamicExampleMatrix();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpDynamicExampleMatrix(const ClpDynamicExampleMatrix&);
+     ClpDynamicExampleMatrix& operator=(const ClpDynamicExampleMatrix&);
+     /// Clone
+     virtual ClpMatrixBase * clone() const ;
+     //@}
+     /**@name gets and sets */
+     //@{
+     /// Starts of each column
+     inline CoinBigIndex * startColumnGen() const {
+          return startColumnGen_;
+     }
+     /// rows
+     inline int * rowGen() const {
+          return rowGen_;
+     }
+     /// elements
+     inline double * elementGen() const {
+          return elementGen_;
+     }
+     /// costs
+     inline double * costGen() const {
+          return costGen_;
+     }
+     /// full starts
+     inline int * fullStartGen() const {
+          return fullStartGen_;
+     }
+     /// ids in next level matrix
+     inline int * idGen() const {
+          return idGen_;
+     }
+     /// Optional lower bounds on columns
+     inline double * columnLowerGen() const {
+          return columnLowerGen_;
+     }
+     /// Optional upper bounds on columns
+     inline double * columnUpperGen() const {
+          return columnUpperGen_;
+     }
+     /// size
+     inline int numberColumns() const {
+          return numberColumns_;
+     }
+     inline void setDynamicStatusGen(int sequence, DynamicStatus status) {
+          unsigned char & st_byte = dynamicStatusGen_[sequence];
+          st_byte = static_cast<unsigned char>(st_byte & ~7);
+          st_byte = static_cast<unsigned char>(st_byte | status);
+     }
+     inline DynamicStatus getDynamicStatusGen(int sequence) const {
+          return static_cast<DynamicStatus> (dynamicStatusGen_[sequence] & 7);
+     }
+     /// Whether flagged
+     inline bool flaggedGen(int i) const {
+          return (dynamicStatusGen_[i] & 8) != 0;
+     }
+     inline void setFlaggedGen(int i) {
+          dynamicStatusGen_[i] = static_cast<unsigned char>(dynamicStatusGen_[i] | 8);
+     }
+     inline void unsetFlagged(int i) {
+          dynamicStatusGen_[i] = static_cast<unsigned char>(dynamicStatusGen_[i] & ~8);
+     }
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// size
+     int numberColumns_;
+     /// Starts of each column
+     CoinBigIndex * startColumnGen_;
+     /// rows
+     int * rowGen_;
+     /// elements
+     double * elementGen_;
+     /// costs
+     double * costGen_;
+     /// start of each set
+     int * fullStartGen_;
+     /// for status and which bound
+     unsigned char * dynamicStatusGen_;
+     /** identifier for each variable up one level (startColumn_, etc).  This is
+         of length maximumGubColumns_.  For this version it is just sequence number
+         at this level */
+     int * idGen_;
+     /// Optional lower bounds on columns
+     double * columnLowerGen_;
+     /// Optional upper bounds on columns
+     double * columnUpperGen_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpDynamicMatrix.cpp b/cbits/coin/ClpDynamicMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDynamicMatrix.cpp
@@ -0,0 +1,2605 @@
+/* $Id: ClpDynamicMatrix.cpp 1941 2013-04-10 16:52:27Z stefan $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include <cstdio>
+
+#include "CoinPragma.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpQuadraticObjective.hpp"
+#include "ClpNonLinearCost.hpp"
+// at end to get min/max!
+#include "ClpDynamicMatrix.hpp"
+#include "ClpMessage.hpp"
+//#define CLP_DEBUG
+//#define CLP_DEBUG_PRINT
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpDynamicMatrix::ClpDynamicMatrix ()
+     : ClpPackedMatrix(),
+       sumDualInfeasibilities_(0.0),
+       sumPrimalInfeasibilities_(0.0),
+       sumOfRelaxedDualInfeasibilities_(0.0),
+       sumOfRelaxedPrimalInfeasibilities_(0.0),
+       savedBestGubDual_(0.0),
+       savedBestSet_(0),
+       backToPivotRow_(NULL),
+       keyVariable_(NULL),
+       toIndex_(NULL),
+       fromIndex_(NULL),
+       numberSets_(0),
+       numberActiveSets_(0),
+       objectiveOffset_(0.0),
+       lowerSet_(NULL),
+       upperSet_(NULL),
+       status_(NULL),
+       model_(NULL),
+       firstAvailable_(0),
+       firstAvailableBefore_(0),
+       firstDynamic_(0),
+       lastDynamic_(0),
+       numberStaticRows_(0),
+       numberElements_(0),
+       numberDualInfeasibilities_(0),
+       numberPrimalInfeasibilities_(0),
+       noCheck_(-1),
+       infeasibilityWeight_(0.0),
+       numberGubColumns_(0),
+       maximumGubColumns_(0),
+       maximumElements_(0),
+       startSet_(NULL),
+       next_(NULL),
+       startColumn_(NULL),
+       row_(NULL),
+       element_(NULL),
+       cost_(NULL),
+       id_(NULL),
+       dynamicStatus_(NULL),
+       columnLower_(NULL),
+       columnUpper_(NULL)
+{
+     setType(15);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpDynamicMatrix::ClpDynamicMatrix (const ClpDynamicMatrix & rhs)
+     : ClpPackedMatrix(rhs)
+{
+     objectiveOffset_ = rhs.objectiveOffset_;
+     numberSets_ = rhs.numberSets_;
+     numberActiveSets_ = rhs.numberActiveSets_;
+     firstAvailable_ = rhs.firstAvailable_;
+     firstAvailableBefore_ = rhs.firstAvailableBefore_;
+     firstDynamic_ = rhs.firstDynamic_;
+     lastDynamic_ = rhs.lastDynamic_;
+     numberStaticRows_ = rhs.numberStaticRows_;
+     numberElements_ = rhs.numberElements_;
+     backToPivotRow_ = ClpCopyOfArray(rhs.backToPivotRow_, lastDynamic_);
+     keyVariable_ = ClpCopyOfArray(rhs.keyVariable_, numberSets_);
+     toIndex_ = ClpCopyOfArray(rhs.toIndex_, numberSets_);
+     fromIndex_ = ClpCopyOfArray(rhs.fromIndex_, getNumRows() + 1 - numberStaticRows_);
+     lowerSet_ = ClpCopyOfArray(rhs.lowerSet_, numberSets_);
+     upperSet_ = ClpCopyOfArray(rhs.upperSet_, numberSets_);
+     status_ = ClpCopyOfArray(rhs.status_, static_cast<int>(2*numberSets_+4*sizeof(int)));
+     model_ = rhs.model_;
+     sumDualInfeasibilities_ = rhs. sumDualInfeasibilities_;
+     sumPrimalInfeasibilities_ = rhs.sumPrimalInfeasibilities_;
+     sumOfRelaxedDualInfeasibilities_ = rhs.sumOfRelaxedDualInfeasibilities_;
+     sumOfRelaxedPrimalInfeasibilities_ = rhs.sumOfRelaxedPrimalInfeasibilities_;
+     numberDualInfeasibilities_ = rhs.numberDualInfeasibilities_;
+     numberPrimalInfeasibilities_ = rhs.numberPrimalInfeasibilities_;
+     savedBestGubDual_ = rhs.savedBestGubDual_;
+     savedBestSet_ = rhs.savedBestSet_;
+     noCheck_ = rhs.noCheck_;
+     infeasibilityWeight_ = rhs.infeasibilityWeight_;
+     // Now secondary data
+     numberGubColumns_ = rhs.numberGubColumns_;
+     maximumGubColumns_ = rhs.maximumGubColumns_;
+     maximumElements_ = rhs.maximumElements_;
+     startSet_ = ClpCopyOfArray(rhs.startSet_, numberSets_+1);
+     next_ = ClpCopyOfArray(rhs.next_, maximumGubColumns_);
+     startColumn_ = ClpCopyOfArray(rhs.startColumn_, maximumGubColumns_ + 1);
+     row_ = ClpCopyOfArray(rhs.row_, maximumElements_);
+     element_ = ClpCopyOfArray(rhs.element_, maximumElements_);
+     cost_ = ClpCopyOfArray(rhs.cost_, maximumGubColumns_);
+     id_ = ClpCopyOfArray(rhs.id_, lastDynamic_ - firstDynamic_);
+     columnLower_ = ClpCopyOfArray(rhs.columnLower_, maximumGubColumns_);
+     columnUpper_ = ClpCopyOfArray(rhs.columnUpper_, maximumGubColumns_);
+     dynamicStatus_ = ClpCopyOfArray(rhs.dynamicStatus_, 2*maximumGubColumns_);
+}
+
+/* This is the real constructor*/
+ClpDynamicMatrix::ClpDynamicMatrix(ClpSimplex * model, int numberSets,
+                                   int numberGubColumns, const int * starts,
+                                   const double * lower, const double * upper,
+                                   const CoinBigIndex * startColumn, const int * row,
+                                   const double * element, const double * cost,
+                                   const double * columnLower, const double * columnUpper,
+                                   const unsigned char * status,
+                                   const unsigned char * dynamicStatus)
+     : ClpPackedMatrix()
+{
+     setType(15);
+     objectiveOffset_ = model->objectiveOffset();
+     model_ = model;
+     numberSets_ = numberSets;
+     numberGubColumns_ = numberGubColumns;
+     maximumGubColumns_ = numberGubColumns_;
+     if (numberGubColumns_)
+          maximumElements_ = startColumn[numberGubColumns_];
+     else
+          maximumElements_ = 0;
+     startSet_ = new int [numberSets_+1];
+     next_ = new int [maximumGubColumns_];
+     // fill in startSet and next
+     int iSet;
+     if (numberGubColumns_) {
+          for (iSet = 0; iSet < numberSets_; iSet++) {
+               int first = starts[iSet];
+               int last = starts[iSet+1] - 1;
+               startSet_[iSet] = first;
+               for (int i = first; i < last; i++)
+                    next_[i] = i + 1;
+               next_[last] = -iSet - 1;
+          }
+	  startSet_[numberSets_] = starts[numberSets_];
+     }
+     int numberColumns = model->numberColumns();
+     int numberRows = model->numberRows();
+     numberStaticRows_ = numberRows;
+     savedBestGubDual_ = 0.0;
+     savedBestSet_ = 0;
+     // Number of columns needed
+     int frequency = model->factorizationFrequency();
+     int numberGubInSmall = numberRows + frequency + CoinMin(frequency, numberSets_) + 4;
+     // But we may have two per row + one for incoming (make it two) 
+     numberGubInSmall = CoinMax(2*numberRows+2,numberGubInSmall);
+     // for small problems this could be too big
+     //numberGubInSmall = CoinMin(numberGubInSmall,numberGubColumns_);
+     int numberNeeded = numberGubInSmall + numberColumns;
+     firstAvailable_ = numberColumns;
+     firstAvailableBefore_ = firstAvailable_;
+     firstDynamic_ = numberColumns;
+     lastDynamic_ = numberNeeded;
+     startColumn_ = ClpCopyOfArray(startColumn, numberGubColumns_ + 1);
+     if (!numberGubColumns_) {
+       if (!startColumn_)
+	 startColumn_ = new CoinBigIndex [1];
+       startColumn_[0] = 0;
+     }
+     CoinBigIndex numberElements = startColumn_[numberGubColumns_];
+     row_ = ClpCopyOfArray(row, numberElements);
+     element_ = new double[numberElements];
+     CoinBigIndex i;
+     for (i = 0; i < numberElements; i++)
+          element_[i] = element[i];
+     cost_ = new double[numberGubColumns_];
+     for (i = 0; i < numberGubColumns_; i++) {
+          cost_[i] = cost[i];
+          // I don't think I need sorted but ...
+          CoinSort_2(row_ + startColumn_[i], row_ + startColumn_[i+1], element_ + startColumn_[i]);
+     }
+     if (columnLower) {
+          columnLower_ = new double[numberGubColumns_];
+          for (i = 0; i < numberGubColumns_; i++)
+               columnLower_[i] = columnLower[i];
+     } else {
+          columnLower_ = NULL;
+     }
+     if (columnUpper) {
+          columnUpper_ = new double[numberGubColumns_];
+          for (i = 0; i < numberGubColumns_; i++)
+               columnUpper_[i] = columnUpper[i];
+     } else {
+          columnUpper_ = NULL;
+     }
+     lowerSet_ = new double[numberSets_];
+     for (i = 0; i < numberSets_; i++) {
+          if (lower[i] > -1.0e20)
+               lowerSet_[i] = lower[i];
+          else
+               lowerSet_[i] = -1.0e30;
+     }
+     upperSet_ = new double[numberSets_];
+     for (i = 0; i < numberSets_; i++) {
+          if (upper[i] < 1.0e20)
+               upperSet_[i] = upper[i];
+          else
+               upperSet_[i] = 1.0e30;
+     }
+     id_ = new int[numberGubInSmall];
+     for (i = 0; i < numberGubInSmall; i++)
+          id_[i] = -1;
+     ClpPackedMatrix* originalMatrixA =
+          dynamic_cast< ClpPackedMatrix*>(model->clpMatrix());
+     assert (originalMatrixA);
+     CoinPackedMatrix * originalMatrix = originalMatrixA->getPackedMatrix();
+     originalMatrixA->setMatrixNull(); // so can be deleted safely
+     // guess how much space needed
+     double guess = numberElements;
+     guess /= static_cast<double> (numberColumns);
+     guess *= 2 * numberGubInSmall;
+     numberElements_ = static_cast<int> (guess);
+     numberElements_ = CoinMin(numberElements_, numberElements) + originalMatrix->getNumElements();
+     matrix_ = originalMatrix;
+     //delete originalMatrixA;
+     flags_ &= ~1;
+     // resize model (matrix stays same)
+     // modify frequency
+     if (frequency>=50)
+       frequency = 50+(frequency-50)/2;
+     int newRowSize = numberRows + CoinMin(numberSets_, frequency+numberRows) + 1;
+     model->resize(newRowSize, numberNeeded);
+     for (i = numberRows; i < newRowSize; i++)
+          model->setRowStatus(i, ClpSimplex::basic);
+     if (columnUpper_) {
+          // set all upper bounds so we have enough space
+          double * columnUpper = model->columnUpper();
+          for(i = firstDynamic_; i < lastDynamic_; i++)
+               columnUpper[i] = 1.0e10;
+     }
+     // resize matrix
+     // extra 1 is so can keep number of elements handy
+     originalMatrix->reserve(numberNeeded, numberElements_, true);
+     originalMatrix->reserve(numberNeeded + 1, numberElements_, false);
+     originalMatrix->getMutableVectorStarts()[numberColumns] = originalMatrix->getNumElements();
+     originalMatrix->setDimensions(newRowSize, -1);
+     numberActiveColumns_ = firstDynamic_;
+     // redo number of columns
+     numberColumns = matrix_->getNumCols();
+     backToPivotRow_ = new int[numberNeeded];
+     keyVariable_ = new int[numberSets_];
+     if (status) {
+          status_ = ClpCopyOfArray(status, static_cast<int>(2*numberSets_+4*sizeof(int)));
+          assert (dynamicStatus);
+          dynamicStatus_ = ClpCopyOfArray(dynamicStatus, 2*numberGubColumns_);
+     } else {
+          status_ = new unsigned char [2*numberSets_+4*sizeof(int)];
+          memset(status_, 0, numberSets_);
+          int i;
+          for (i = 0; i < numberSets_; i++) {
+               // make slack key
+               setStatus(i, ClpSimplex::basic);
+          }
+          dynamicStatus_ = new unsigned char [2*numberGubColumns_];
+          memset(dynamicStatus_, 0, numberGubColumns_); // for clarity
+          for (i = 0; i < numberGubColumns_; i++)
+               setDynamicStatus(i, atLowerBound);
+     }
+     toIndex_ = new int[numberSets_];
+     for (iSet = 0; iSet < numberSets_; iSet++)
+          toIndex_[iSet] = -1;
+     fromIndex_ = new int [newRowSize-numberStaticRows_+1];
+     numberActiveSets_ = 0;
+     rhsOffset_ = NULL;
+     if (numberGubColumns_) {
+          if (!status) {
+               gubCrash();
+          } else {
+               initialProblem();
+          }
+     }
+     noCheck_ = -1;
+     infeasibilityWeight_ = 0.0;
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpDynamicMatrix::~ClpDynamicMatrix ()
+{
+     delete [] backToPivotRow_;
+     delete [] keyVariable_;
+     delete [] toIndex_;
+     delete [] fromIndex_;
+     delete [] lowerSet_;
+     delete [] upperSet_;
+     delete [] status_;
+     delete [] startSet_;
+     delete [] next_;
+     delete [] startColumn_;
+     delete [] row_;
+     delete [] element_;
+     delete [] cost_;
+     delete [] id_;
+     delete [] dynamicStatus_;
+     delete [] columnLower_;
+     delete [] columnUpper_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpDynamicMatrix &
+ClpDynamicMatrix::operator=(const ClpDynamicMatrix& rhs)
+{
+     if (this != &rhs) {
+          ClpPackedMatrix::operator=(rhs);
+          delete [] backToPivotRow_;
+          delete [] keyVariable_;
+          delete [] toIndex_;
+          delete [] fromIndex_;
+          delete [] lowerSet_;
+          delete [] upperSet_;
+          delete [] status_;
+          delete [] startSet_;
+          delete [] next_;
+          delete [] startColumn_;
+          delete [] row_;
+          delete [] element_;
+          delete [] cost_;
+          delete [] id_;
+          delete [] dynamicStatus_;
+          delete [] columnLower_;
+          delete [] columnUpper_;
+          objectiveOffset_ = rhs.objectiveOffset_;
+          numberSets_ = rhs.numberSets_;
+          numberActiveSets_ = rhs.numberActiveSets_;
+          firstAvailable_ = rhs.firstAvailable_;
+          firstAvailableBefore_ = rhs.firstAvailableBefore_;
+          firstDynamic_ = rhs.firstDynamic_;
+          lastDynamic_ = rhs.lastDynamic_;
+          numberStaticRows_ = rhs.numberStaticRows_;
+          numberElements_ = rhs.numberElements_;
+          backToPivotRow_ = ClpCopyOfArray(rhs.backToPivotRow_, lastDynamic_);
+          keyVariable_ = ClpCopyOfArray(rhs.keyVariable_, numberSets_);
+          toIndex_ = ClpCopyOfArray(rhs.toIndex_, numberSets_);
+          fromIndex_ = ClpCopyOfArray(rhs.fromIndex_, getNumRows() + 1 - numberStaticRows_);
+          lowerSet_ = ClpCopyOfArray(rhs.lowerSet_, numberSets_);
+          upperSet_ = ClpCopyOfArray(rhs.upperSet_, numberSets_);
+          status_ = ClpCopyOfArray(rhs.status_, static_cast<int>(2*numberSets_+4*sizeof(int)));
+          model_ = rhs.model_;
+          sumDualInfeasibilities_ = rhs. sumDualInfeasibilities_;
+          sumPrimalInfeasibilities_ = rhs.sumPrimalInfeasibilities_;
+          sumOfRelaxedDualInfeasibilities_ = rhs.sumOfRelaxedDualInfeasibilities_;
+          sumOfRelaxedPrimalInfeasibilities_ = rhs.sumOfRelaxedPrimalInfeasibilities_;
+          numberDualInfeasibilities_ = rhs.numberDualInfeasibilities_;
+          numberPrimalInfeasibilities_ = rhs.numberPrimalInfeasibilities_;
+          savedBestGubDual_ = rhs.savedBestGubDual_;
+          savedBestSet_ = rhs.savedBestSet_;
+          noCheck_ = rhs.noCheck_;
+          infeasibilityWeight_ = rhs.infeasibilityWeight_;
+          // Now secondary data
+          numberGubColumns_ = rhs.numberGubColumns_;
+          maximumGubColumns_ = rhs.maximumGubColumns_;
+          maximumElements_ = rhs.maximumElements_;
+          startSet_ = ClpCopyOfArray(rhs.startSet_, numberSets_+1);
+          next_ = ClpCopyOfArray(rhs.next_, maximumGubColumns_);
+          startColumn_ = ClpCopyOfArray(rhs.startColumn_, maximumGubColumns_ + 1);
+          row_ = ClpCopyOfArray(rhs.row_, maximumElements_);
+          element_ = ClpCopyOfArray(rhs.element_, maximumElements_);
+          cost_ = ClpCopyOfArray(rhs.cost_, maximumGubColumns_);
+          id_ = ClpCopyOfArray(rhs.id_, lastDynamic_ - firstDynamic_);
+          columnLower_ = ClpCopyOfArray(rhs.columnLower_, maximumGubColumns_);
+          columnUpper_ = ClpCopyOfArray(rhs.columnUpper_, maximumGubColumns_);
+          dynamicStatus_ = ClpCopyOfArray(rhs.dynamicStatus_, 2*maximumGubColumns_);
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpMatrixBase * ClpDynamicMatrix::clone() const
+{
+     return new ClpDynamicMatrix(*this);
+}
+// Partial pricing
+void
+ClpDynamicMatrix::partialPricing(ClpSimplex * model, double startFraction, double endFraction,
+                                 int & bestSequence, int & numberWanted)
+{
+     numberWanted = currentWanted_;
+     assert(!model->rowScale());
+     if (numberSets_) {
+          // Do packed part before gub
+          // always???
+          //printf("normal packed price - start %d end %d (passed end %d, first %d)\n",
+          ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
+     } else {
+          // no gub
+          ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
+          return;
+     }
+     if (numberWanted > 0) {
+          // and do some proportion of full set
+          int startG2 = static_cast<int> (startFraction * numberSets_);
+          int endG2 = static_cast<int> (endFraction * numberSets_ + 0.1);
+          endG2 = CoinMin(endG2, numberSets_);
+          //printf("gub price - set start %d end %d\n",
+          //   startG2,endG2);
+          double tolerance = model->currentDualTolerance();
+          double * reducedCost = model->djRegion();
+          const double * duals = model->dualRowSolution();
+          double bestDj;
+          int numberRows = model->numberRows();
+          int slackOffset = lastDynamic_ + numberRows;
+          int structuralOffset = slackOffset + numberSets_;
+          // If nothing found yet can go all the way to end
+          int endAll = endG2;
+          if (bestSequence < 0 && !startG2)
+               endAll = numberSets_;
+          if (bestSequence >= 0) {
+               if (bestSequence != savedBestSequence_)
+                    bestDj = fabs(reducedCost[bestSequence]); // dj from slacks or permanent
+               else
+                    bestDj = savedBestDj_;
+          } else {
+               bestDj = tolerance;
+          }
+          int saveSequence = bestSequence;
+          double djMod = 0.0;
+          double bestDjMod = 0.0;
+          //printf("iteration %d start %d end %d - wanted %d\n",model->numberIterations(),
+          //     startG2,endG2,numberWanted);
+          int bestSet = -1;
+#if 0
+          // make sure first available is clean (in case last iteration rejected)
+          cost[firstAvailable_] = 0.0;
+          length[firstAvailable_] = 0;
+          model->nonLinearCost()->setOne(firstAvailable_, 0.0, 0.0, COIN_DBL_MAX, 0.0);
+          model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
+          {
+               for (int i = firstAvailable_; i < lastDynamic_; i++)
+                    assert(!cost[i]);
+          }
+#endif
+          int minSet = minimumObjectsScan_ < 0 ? 5 : minimumObjectsScan_;
+          int minNeg = minimumGoodReducedCosts_ < 0 ? 5 : minimumGoodReducedCosts_;
+          for (int iSet = startG2; iSet < endAll; iSet++) {
+               if (numberWanted + minNeg < originalWanted_ && iSet > startG2 + minSet) {
+                    // give up
+                    numberWanted = 0;
+                    break;
+               } else if (iSet == endG2 && bestSequence >= 0) {
+                    break;
+               }
+               int gubRow = toIndex_[iSet];
+               if (gubRow >= 0) {
+                    djMod = duals[gubRow+numberStaticRows_]; // have I got sign right?
+               } else {
+                    int iBasic = keyVariable_[iSet];
+                    if (iBasic >= maximumGubColumns_) {
+                         djMod = 0.0; // set not in
+                    } else {
+                         // get dj without
+                         djMod = 0.0;
+                         for (CoinBigIndex j = startColumn_[iBasic];
+                                   j < startColumn_[iBasic+1]; j++) {
+                              int jRow = row_[j];
+                              djMod -= duals[jRow] * element_[j];
+                         }
+                         djMod += cost_[iBasic];
+                         // See if gub slack possible - dj is djMod
+                         if (getStatus(iSet) == ClpSimplex::atLowerBound) {
+                              double value = -djMod;
+                              if (value > tolerance) {
+                                   numberWanted--;
+                                   if (value > bestDj) {
+                                        // check flagged variable and correct dj
+                                        if (!flagged(iSet)) {
+                                             bestDj = value;
+                                             bestSequence = slackOffset + iSet;
+                                             bestDjMod = djMod;
+                                             bestSet = iSet;
+                                        } else {
+                                             // just to make sure we don't exit before got something
+                                             numberWanted++;
+                                             abort();
+                                        }
+                                   }
+                              }
+                         } else if (getStatus(iSet) == ClpSimplex::atUpperBound) {
+                              double value = djMod;
+                              if (value > tolerance) {
+                                   numberWanted--;
+                                   if (value > bestDj) {
+                                        // check flagged variable and correct dj
+                                        if (!flagged(iSet)) {
+                                             bestDj = value;
+                                             bestSequence = slackOffset + iSet;
+                                             bestDjMod = djMod;
+                                             bestSet = iSet;
+                                        } else {
+                                             // just to make sure we don't exit before got something
+                                             numberWanted++;
+                                             abort();
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+               int iSequence = startSet_[iSet];
+               while (iSequence >= 0) {
+                    DynamicStatus status = getDynamicStatus(iSequence);
+                    if (status == atLowerBound || status == atUpperBound) {
+                         double value = cost_[iSequence] - djMod;
+                         for (CoinBigIndex j = startColumn_[iSequence];
+                                   j < startColumn_[iSequence+1]; j++) {
+                              int jRow = row_[j];
+                              value -= duals[jRow] * element_[j];
+                         }
+                         // change sign if at lower bound
+                         if (status == atLowerBound)
+                              value = -value;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!flagged(iSequence)) {
+				     if (false/*status == atLowerBound
+						&&keyValue(iSet)<1.0e-7*/) {
+				       // can't come in because
+				       // of ones at ub
+				       numberWanted++;
+				     } else {
+				     
+                                        bestDj = value;
+                                        bestSequence = structuralOffset + iSequence;
+                                        bestDjMod = djMod;
+                                        bestSet = iSet;
+				     }
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                    }
+                    iSequence = next_[iSequence]; //onto next in set
+               }
+               if (numberWanted <= 0) {
+                    numberWanted = 0;
+                    break;
+               }
+          }
+          if (bestSequence != saveSequence) {
+               savedBestGubDual_ = bestDjMod;
+               savedBestDj_ = bestDj;
+               savedBestSequence_ = bestSequence;
+               savedBestSet_ = bestSet;
+          }
+          // See if may be finished
+          if (!startG2 && bestSequence < 0)
+               infeasibilityWeight_ = model_->infeasibilityCost();
+          else if (bestSequence >= 0)
+               infeasibilityWeight_ = -1.0;
+     }
+     currentWanted_ = numberWanted;
+}
+/* Returns effective RHS if it is being used.  This is used for long problems
+   or big gub or anywhere where going through full columns is
+   expensive.  This may re-compute */
+double *
+ClpDynamicMatrix::rhsOffset(ClpSimplex * model, bool forceRefresh,
+                            bool
+#ifdef CLP_DEBUG
+                            check
+#endif
+                           )
+{
+     // forceRefresh=true;printf("take out forceRefresh\n");
+     if (!model_->numberIterations())
+          forceRefresh = true;
+     //check=false;
+#ifdef CLP_DEBUG
+     double * saveE = NULL;
+     if (rhsOffset_ && check) {
+          int numberRows = model->numberRows();
+          saveE = new double[numberRows];
+     }
+#endif
+     if (rhsOffset_) {
+#ifdef CLP_DEBUG
+          if (check) {
+               // no need - but check anyway
+               int numberRows = model->numberRows();
+               double * rhs = new double[numberRows];
+               int iRow;
+               int iSet;
+               CoinZeroN(rhs, numberRows);
+               // do ones at bounds before gub
+               const double * smallSolution = model->solutionRegion();
+               const double * element = matrix_->getElements();
+               const int * row = matrix_->getIndices();
+               const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+               const int * length = matrix_->getVectorLengths();
+               int iColumn;
+               double objectiveOffset = 0.0;
+               for (iColumn = 0; iColumn < firstDynamic_; iColumn++) {
+                    if (model->getStatus(iColumn) != ClpSimplex::basic) {
+                         double value = smallSolution[iColumn];
+                         for (CoinBigIndex j = startColumn[iColumn];
+                                   j < startColumn[iColumn] + length[iColumn]; j++) {
+                              int jRow = row[j];
+                              rhs[jRow] -= value * element[j];
+                         }
+                    }
+               }
+               if (columnLower_ || columnUpper_) {
+                    double * solution = new double [numberGubColumns_];
+                    for (iSet = 0; iSet < numberSets_; iSet++) {
+                         int j = startSet_[iSet];
+                         while (j >= 0) {
+                              double value = 0.0;
+                              if (getDynamicStatus(j) != inSmall) {
+                                   if (getDynamicStatus(j) == atLowerBound) {
+                                        if (columnLower_)
+                                             value = columnLower_[j];
+                                   } else if (getDynamicStatus(j) == atUpperBound) {
+                                        value = columnUpper_[j];
+                                   } else if (getDynamicStatus(j) == soloKey) {
+                                        value = keyValue(iSet);
+                                   }
+                                   objectiveOffset += value * cost_[j];
+                              }
+                              solution[j] = value;
+                              j = next_[j]; //onto next in set
+                         }
+                    }
+                    // ones in gub and in small problem
+                    for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) {
+                         if (model_->getStatus(iColumn) != ClpSimplex::basic) {
+                              int jFull = id_[iColumn-firstDynamic_];
+                              solution[jFull] = smallSolution[iColumn];
+                         }
+                    }
+                    for (iSet = 0; iSet < numberSets_; iSet++) {
+                         int kRow = toIndex_[iSet];
+                         if (kRow >= 0)
+                              kRow += numberStaticRows_;
+                         int j = startSet_[iSet];
+                         while (j >= 0) {
+                              double value = solution[j];
+                              if (value) {
+                                   for (CoinBigIndex k = startColumn_[j]; k < startColumn_[j+1]; k++) {
+                                        int iRow = row_[k];
+                                        rhs[iRow] -= element_[k] * value;
+                                   }
+                                   if (kRow >= 0)
+                                        rhs[kRow] -= value;
+                              }
+                              j = next_[j]; //onto next in set
+                         }
+                    }
+                    delete [] solution;
+               } else {
+                    // bounds
+                    ClpSimplex::Status iStatus;
+                    for (int iSet = 0; iSet < numberSets_; iSet++) {
+                         int kRow = toIndex_[iSet];
+                         if (kRow < 0) {
+                              int iColumn = keyVariable_[iSet];
+                              if (iColumn < maximumGubColumns_) {
+                                   // key is not treated as basic
+                                   double b = 0.0;
+                                   // key is structural - where is slack
+                                   iStatus = getStatus(iSet);
+                                   assert (iStatus != ClpSimplex::basic);
+                                   if (iStatus == ClpSimplex::atLowerBound)
+                                        b = lowerSet_[iSet];
+                                   else
+                                        b = upperSet_[iSet];
+                                   if (b) {
+                                        objectiveOffset += b * cost_[iColumn];
+                                        for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn+1]; j++) {
+                                             int iRow = row_[j];
+                                             rhs[iRow] -= element_[j] * b;
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+               if (fabs(model->objectiveOffset() - objectiveOffset_ - objectiveOffset) > 1.0e-1)
+                    printf("old offset %g, true %g\n", model->objectiveOffset(),
+                           objectiveOffset_ - objectiveOffset);
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    if (fabs(rhs[iRow] - rhsOffset_[iRow]) > 1.0e-3)
+                         printf("** bad effective %d - true %g old %g\n", iRow, rhs[iRow], rhsOffset_[iRow]);
+               }
+               CoinMemcpyN(rhs, numberRows, saveE);
+               delete [] rhs;
+          }
+#endif
+          if (forceRefresh || (refreshFrequency_ && model->numberIterations() >=
+                               lastRefresh_ + refreshFrequency_)) {
+               int numberRows = model->numberRows();
+               int iSet;
+               CoinZeroN(rhsOffset_, numberRows);
+               // do ones at bounds before gub
+               const double * smallSolution = model->solutionRegion();
+               const double * element = matrix_->getElements();
+               const int * row = matrix_->getIndices();
+               const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+               const int * length = matrix_->getVectorLengths();
+               int iColumn;
+               double objectiveOffset = 0.0;
+               for (iColumn = 0; iColumn < firstDynamic_; iColumn++) {
+                    if (model->getStatus(iColumn) != ClpSimplex::basic) {
+                         double value = smallSolution[iColumn];
+                         for (CoinBigIndex j = startColumn[iColumn];
+                                   j < startColumn[iColumn] + length[iColumn]; j++) {
+                              int jRow = row[j];
+                              rhsOffset_[jRow] -= value * element[j];
+                         }
+                    }
+               }
+               if (columnLower_ || columnUpper_) {
+                    double * solution = new double [numberGubColumns_];
+                    for (iSet = 0; iSet < numberSets_; iSet++) {
+                         int j = startSet_[iSet];
+                         while (j >= 0) {
+                              double value = 0.0;
+                              if (getDynamicStatus(j) != inSmall) {
+                                   if (getDynamicStatus(j) == atLowerBound) {
+                                        if (columnLower_)
+                                             value = columnLower_[j];
+                                   } else if (getDynamicStatus(j) == atUpperBound) {
+                                        value = columnUpper_[j];
+					assert (value<1.0e30);
+                                   } else if (getDynamicStatus(j) == soloKey) {
+                                        value = keyValue(iSet);
+				   }
+                                   objectiveOffset += value * cost_[j];
+                              }
+                              solution[j] = value;
+                              j = next_[j]; //onto next in set
+                         }
+                    }
+                    // ones in gub and in small problem
+                    for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) {
+                         if (model_->getStatus(iColumn) != ClpSimplex::basic) {
+                              int jFull = id_[iColumn-firstDynamic_];
+                              solution[jFull] = smallSolution[iColumn];
+                         }
+                    }
+                    for (iSet = 0; iSet < numberSets_; iSet++) {
+                         int kRow = toIndex_[iSet];
+                         if (kRow >= 0) 
+			   kRow += numberStaticRows_;
+			 int j = startSet_[iSet];
+			 while (j >= 0) {
+			   //? use DynamicStatus status = getDynamicStatus(j);
+			   double value = solution[j];
+			   if (value) {
+			     for (CoinBigIndex k = startColumn_[j]; k < startColumn_[j+1]; k++) {
+			       int iRow = row_[k];
+			       rhsOffset_[iRow] -= element_[k] * value;
+			     }
+			     if (kRow >= 0)
+			       rhsOffset_[kRow] -= value;
+			   }
+			   j = next_[j]; //onto next in set
+			 }
+                    }
+                    delete [] solution;
+               } else {
+                    // bounds
+                    ClpSimplex::Status iStatus;
+                    for (int iSet = 0; iSet < numberSets_; iSet++) {
+                         int kRow = toIndex_[iSet];
+                         if (kRow < 0) {
+                              int iColumn = keyVariable_[iSet];
+                              if (iColumn < maximumGubColumns_) {
+                                   // key is not treated as basic
+                                   double b = 0.0;
+                                   // key is structural - where is slack
+                                   iStatus = getStatus(iSet);
+                                   assert (iStatus != ClpSimplex::basic);
+                                   if (iStatus == ClpSimplex::atLowerBound)
+                                        b = lowerSet_[iSet];
+                                   else
+                                        b = upperSet_[iSet];
+                                   if (b) {
+                                        objectiveOffset += b * cost_[iColumn];
+                                        for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn+1]; j++) {
+                                             int iRow = row_[j];
+                                             rhsOffset_[iRow] -= element_[j] * b;
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+               model->setObjectiveOffset(objectiveOffset_ - objectiveOffset);
+#ifdef CLP_DEBUG
+               if (saveE) {
+                    int iRow;
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         if (fabs(saveE[iRow] - rhsOffset_[iRow]) > 1.0e-3)
+                              printf("** %d - old eff %g new %g\n", iRow, saveE[iRow], rhsOffset_[iRow]);
+                    }
+                    delete [] saveE;
+               }
+#endif
+               lastRefresh_ = model->numberIterations();
+          }
+     }
+     return rhsOffset_;
+}
+/*
+  update information for a pivot (and effective rhs)
+*/
+int
+ClpDynamicMatrix::updatePivot(ClpSimplex * model, double oldInValue, double oldOutValue)
+{
+
+     // now update working model
+     int sequenceIn = model->sequenceIn();
+     int sequenceOut = model->sequenceOut();
+     int numberColumns = model->numberColumns();
+     if (sequenceIn != sequenceOut && sequenceIn < numberColumns)
+          backToPivotRow_[sequenceIn] = model->pivotRow();
+     if (sequenceIn >= firstDynamic_ && sequenceIn < numberColumns) {
+          int bigSequence = id_[sequenceIn-firstDynamic_];
+          if (getDynamicStatus(bigSequence) != inSmall) {
+               firstAvailable_++;
+               setDynamicStatus(bigSequence, inSmall);
+          }
+     }
+     // make sure slack is synchronized
+     if (sequenceIn >= numberColumns + numberStaticRows_) {
+          int iDynamic = sequenceIn - numberColumns - numberStaticRows_;
+          int iSet = fromIndex_[iDynamic];
+          setStatus(iSet, model->getStatus(sequenceIn));
+     }
+     if (sequenceOut >= numberColumns + numberStaticRows_) {
+          int iDynamic = sequenceOut - numberColumns - numberStaticRows_;
+          int iSet = fromIndex_[iDynamic];
+          // out may have gone through barrier - so check
+          double valueOut = model->lowerRegion()[sequenceOut];
+          if (fabs(valueOut - static_cast<double> (lowerSet_[iSet])) <
+                    fabs(valueOut - static_cast<double> (upperSet_[iSet])))
+               setStatus(iSet, ClpSimplex::atLowerBound);
+          else
+               setStatus(iSet, ClpSimplex::atUpperBound);
+          if (lowerSet_[iSet] == upperSet_[iSet])
+               setStatus(iSet, ClpSimplex::isFixed);
+#if 0
+          if (getStatus(iSet) != model->getStatus(sequenceOut))
+               printf("** set %d status %d, var status %d\n", iSet,
+                      getStatus(iSet), model->getStatus(sequenceOut));
+#endif
+     }
+     ClpMatrixBase::updatePivot(model, oldInValue, oldOutValue);
+#ifdef CLP_DEBUG
+     char * inSmall = new char [numberGubColumns_];
+     memset(inSmall, 0, numberGubColumns_);
+     const double * solution = model->solutionRegion();
+     for (int i = 0; i < numberGubColumns_; i++)
+          if (getDynamicStatus(i) == ClpDynamicMatrix::inSmall)
+               inSmall[i] = 1;
+     for (int i = firstDynamic_; i < firstAvailable_; i++) {
+          int k = id_[i-firstDynamic_];
+          inSmall[k] = 0;
+          //if (k>=23289&&k<23357&&solution[i])
+          //printf("var %d (in small %d) has value %g\n",k,i,solution[i]);
+     }
+     for (int i = 0; i < numberGubColumns_; i++)
+          assert (!inSmall[i]);
+     delete [] inSmall;
+#ifndef NDEBUG
+     for (int i = 0; i < numberActiveSets_; i++) {
+          int iSet = fromIndex_[i];
+          assert (toIndex_[iSet] == i);
+          //if (getStatus(iSet)!=model->getRowStatus(i+numberStaticRows_))
+          //printf("*** set %d status %d, var status %d\n",iSet,
+          //     getStatus(iSet),model->getRowStatus(i+numberStaticRows_));
+          //assert (model->getRowStatus(i+numberStaticRows_)==getStatus(iSet));
+          //if (iSet==1035) {
+          //printf("rhs for set %d (%d) is %g %g - cost %g\n",iSet,i,model->lowerRegion(0)[i+numberStaticRows_],
+          //     model->upperRegion(0)[i+numberStaticRows_],model->costRegion(0)[i+numberStaticRows_]);
+          //}
+     }
+#endif
+#endif
+     if (numberStaticRows_+numberActiveSets_<model->numberRows())
+       return 0;
+     else
+       return 1;
+}
+/*
+     utility dual function for dealing with dynamic constraints
+     mode=n see ClpGubMatrix.hpp for definition
+     Remember to update here when settled down
+*/
+void
+ClpDynamicMatrix::dualExpanded(ClpSimplex * model,
+                               CoinIndexedVector * /*array*/,
+                               double * /*other*/, int mode)
+{
+     switch (mode) {
+          // modify costs before transposeUpdate
+     case 0:
+          break;
+          // create duals for key variables (without check on dual infeasible)
+     case 1:
+          break;
+          // as 1 but check slacks and compute djs
+     case 2: {
+          // do pivots
+          int * pivotVariable = model->pivotVariable();
+          int numberRows = numberStaticRows_ + numberActiveSets_;
+          int numberColumns = model->numberColumns();
+          for (int iRow = 0; iRow < numberRows; iRow++) {
+               int iPivot = pivotVariable[iRow];
+               if (iPivot < numberColumns)
+                    backToPivotRow_[iPivot] = iRow;
+          }
+          if (noCheck_ >= 0) {
+               if (infeasibilityWeight_ != model_->infeasibilityCost()) {
+                    // don't bother checking
+                    sumDualInfeasibilities_ = 100.0;
+                    numberDualInfeasibilities_ = 1;
+                    sumOfRelaxedDualInfeasibilities_ = 100.0;
+                    return;
+               }
+          }
+          // In theory we should subtract out ones we have done but ....
+          // If key slack then dual 0.0
+          // If not then slack could be dual infeasible
+          // dj for key is zero so that defines dual on set
+          int i;
+          double * dual = model->dualRowSolution();
+          double dualTolerance = model->dualTolerance();
+          double relaxedTolerance = dualTolerance;
+          // we can't really trust infeasibilities if there is dual error
+          double error = CoinMin(1.0e-2, model->largestDualError());
+          // allow tolerance at least slightly bigger than standard
+          relaxedTolerance = relaxedTolerance +  error;
+          // but we will be using difference
+          relaxedTolerance -= dualTolerance;
+          sumDualInfeasibilities_ = 0.0;
+          numberDualInfeasibilities_ = 0;
+          sumOfRelaxedDualInfeasibilities_ = 0.0;
+          for (i = 0; i < numberSets_; i++) {
+               double value = 0.0;
+               int gubRow = toIndex_[i];
+               if (gubRow < 0) {
+                    int kColumn = keyVariable_[i];
+                    if (kColumn < maximumGubColumns_) {
+                         // dj without set
+                         value = cost_[kColumn];
+                         for (CoinBigIndex j = startColumn_[kColumn];
+                                   j < startColumn_[kColumn+1]; j++) {
+                              int iRow = row_[j];
+                              value -= dual[iRow] * element_[j];
+                         }
+                         double infeasibility = 0.0;
+                         if (getStatus(i) == ClpSimplex::atLowerBound) {
+                              if (-value > dualTolerance)
+                                   infeasibility = -value - dualTolerance;
+                         } else if (getStatus(i) == ClpSimplex::atUpperBound) {
+                              if (value > dualTolerance)
+                                   infeasibility = value - dualTolerance;
+                         }
+                         if (infeasibility > 0.0) {
+                              sumDualInfeasibilities_ += infeasibility;
+                              if (infeasibility > relaxedTolerance)
+                                   sumOfRelaxedDualInfeasibilities_ += infeasibility;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    }
+               } else {
+                    value = dual[gubRow+numberStaticRows_];
+               }
+               // Now subtract out from all
+               int k = startSet_[i];
+               while (k >= 0) {
+                    if (getDynamicStatus(k) != inSmall) {
+                         double djValue = cost_[k] - value;
+                         for (CoinBigIndex j = startColumn_[k];
+                                   j < startColumn_[k+1]; j++) {
+                              int iRow = row_[j];
+                              djValue -= dual[iRow] * element_[j];
+                         }
+                         double infeasibility = 0.0;
+                         if (getDynamicStatus(k) == atLowerBound) {
+                              if (djValue < -dualTolerance)
+                                   infeasibility = -djValue - dualTolerance;
+                         } else if (getDynamicStatus(k) == atUpperBound) {
+                              // at upper bound
+                              if (djValue > dualTolerance)
+                                   infeasibility = djValue - dualTolerance;
+                         }
+                         if (infeasibility > 0.0) {
+                              sumDualInfeasibilities_ += infeasibility;
+                              if (infeasibility > relaxedTolerance)
+                                   sumOfRelaxedDualInfeasibilities_ += infeasibility;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    }
+                    k = next_[k]; //onto next in set
+               }
+          }
+     }
+     infeasibilityWeight_ = -1.0;
+     break;
+     // Report on infeasibilities of key variables
+     case 3: {
+          model->setSumDualInfeasibilities(model->sumDualInfeasibilities() +
+                                           sumDualInfeasibilities_);
+          model->setNumberDualInfeasibilities(model->numberDualInfeasibilities() +
+                                              numberDualInfeasibilities_);
+          model->setSumOfRelaxedDualInfeasibilities(model->sumOfRelaxedDualInfeasibilities() +
+                    sumOfRelaxedDualInfeasibilities_);
+     }
+     break;
+     // modify costs before transposeUpdate for partial pricing
+     case 4:
+          break;
+     }
+}
+/*
+     general utility function for dealing with dynamic constraints
+     mode=n see ClpGubMatrix.hpp for definition
+     Remember to update here when settled down
+*/
+int
+ClpDynamicMatrix::generalExpanded(ClpSimplex * model, int mode, int &number)
+{
+     int returnCode = 0;
+#if 0 //ndef NDEBUG
+     {
+       int numberColumns = model->numberColumns();
+       int numberRows = model->numberRows();
+       int * pivotVariable = model->pivotVariable();
+       if (pivotVariable&&model->numberIterations()) {
+	 for (int i=numberStaticRows_+numberActiveSets_;i<numberRows;i++) {
+	   assert (pivotVariable[i]==i+numberColumns);
+	 }
+       }
+     }
+#endif
+     switch (mode) {
+          // Fill in pivotVariable
+     case 0: {
+          // If no effective rhs - form it
+          if (!rhsOffset_) {
+               rhsOffset_ = new double[model->numberRows()];
+               rhsOffset(model, true);
+          }
+          int i;
+          int numberBasic = number;
+          int numberColumns = model->numberColumns();
+          // Use different array so can build from true pivotVariable_
+          //int * pivotVariable = model->pivotVariable();
+          int * pivotVariable = model->rowArray(0)->getIndices();
+          for (i = 0; i < numberColumns; i++) {
+               if (model->getColumnStatus(i) == ClpSimplex::basic)
+                    pivotVariable[numberBasic++] = i;
+          }
+          number = numberBasic;
+     }
+     break;
+     // Do initial extra rows + maximum basic
+     case 2: {
+          number = model->numberRows();
+     }
+     break;
+     // Before normal replaceColumn
+     case 3: {
+          if (numberActiveSets_ + numberStaticRows_ == model_->numberRows()) {
+               // no space - re-factorize
+               returnCode = 4;
+               number = -1; // say no need for normal replaceColumn
+          }
+     }
+     break;
+     // To see if can dual or primal
+     case 4: {
+          returnCode = 1;
+     }
+     break;
+     // save status
+     case 5: {
+       memcpy(status_+numberSets_,status_,numberSets_);
+       memcpy(status_+2*numberSets_,&numberActiveSets_,sizeof(int));
+       memcpy(dynamicStatus_+maximumGubColumns_,
+	      dynamicStatus_,maximumGubColumns_);
+     }
+     break;
+     // restore status
+     case 6: {
+       memcpy(status_,status_+numberSets_,numberSets_);
+       memcpy(&numberActiveSets_,status_+2*numberSets_,sizeof(int));
+       memcpy(dynamicStatus_,dynamicStatus_+maximumGubColumns_,
+	      maximumGubColumns_);
+       initialProblem();
+     }
+     break;
+     // unflag all variables
+     case 8: {
+          for (int i = 0; i < numberGubColumns_; i++) {
+               if (flagged(i)) {
+                    unsetFlagged(i);
+                    returnCode++;
+               }
+          }
+     }
+     break;
+     // redo costs in primal
+     case 9: {
+          double * cost = model->costRegion();
+          double * solution = model->solutionRegion();
+          double * columnLower = model->lowerRegion();
+          double * columnUpper = model->upperRegion();
+          int i;
+          bool doCosts = (number & 4) != 0;
+          bool doBounds = (number & 1) != 0;
+          for ( i = firstDynamic_; i < firstAvailable_; i++) {
+               int jColumn = id_[i-firstDynamic_];
+               if (doBounds) {
+                    if (!columnLower_ && !columnUpper_) {
+                         columnLower[i] = 0.0;
+                         columnUpper[i] = COIN_DBL_MAX;
+                    }  else {
+                         if (columnLower_)
+                              columnLower[i] = columnLower_[jColumn];
+                         else
+                              columnLower[i] = 0.0;
+                         if (columnUpper_)
+                              columnUpper[i] = columnUpper_[jColumn];
+                         else
+                              columnUpper[i] = COIN_DBL_MAX;
+                    }
+               }
+               if (doCosts) {
+                    cost[i] = cost_[jColumn];
+                    // Original bounds
+                    if (model->nonLinearCost())
+                         model->nonLinearCost()->setOne(i, solution[i],
+                                                        this->columnLower(jColumn),
+                                                        this->columnUpper(jColumn), cost_[jColumn]);
+               }
+          }
+          // and active sets
+          for (i = 0; i < numberActiveSets_; i++ ) {
+               int iSet = fromIndex_[i];
+               int iSequence = lastDynamic_ + numberStaticRows_ + i;
+               if (doBounds) {
+                    if (lowerSet_[iSet] > -1.0e20)
+                         columnLower[iSequence] = lowerSet_[iSet];
+                    else
+                         columnLower[iSequence] = -COIN_DBL_MAX;
+                    if (upperSet_[iSet] < 1.0e20)
+                         columnUpper[iSequence] = upperSet_[iSet];
+                    else
+                         columnUpper[iSequence] = COIN_DBL_MAX;
+               }
+               if (doCosts) {
+                    if (model->nonLinearCost()) {
+                         double trueLower;
+                         if (lowerSet_[iSet] > -1.0e20)
+                              trueLower = lowerSet_[iSet];
+                         else
+                              trueLower = -COIN_DBL_MAX;
+                         double trueUpper;
+                         if (upperSet_[iSet] < 1.0e20)
+                              trueUpper = upperSet_[iSet];
+                         else
+                              trueUpper = COIN_DBL_MAX;
+                         model->nonLinearCost()->setOne(iSequence, solution[iSequence],
+                                                        trueLower, trueUpper, 0.0);
+                    }
+               }
+          }
+     }
+     break;
+     // return 1 if there may be changing bounds on variable (column generation)
+     case 10: {
+          // return 1 as bounds on rhs will change
+          returnCode = 1;
+     }
+     break;
+     // make sure set is clean
+     case 7: {
+          // first flag
+          if (number >= firstDynamic_ && number < lastDynamic_) {
+	    int sequence = id_[number-firstDynamic_];
+	    setFlagged(sequence);
+	    //model->clearFlagged(number);
+	  } else if (number>=model_->numberColumns()+numberStaticRows_) {
+	    // slack
+	    int iSet = fromIndex_[number-model_->numberColumns()-
+				  numberStaticRows_];
+	    setFlaggedSlack(iSet);
+	    //model->clearFlagged(number);
+	  }
+     }
+     case 11: {
+          //int sequenceIn = model->sequenceIn();
+          if (number >= firstDynamic_ && number < lastDynamic_) {
+	    //assert (number == model->sequenceIn());
+               // take out variable (but leave key)
+               double * cost = model->costRegion();
+               double * columnLower = model->lowerRegion();
+               double * columnUpper = model->upperRegion();
+               double * solution = model->solutionRegion();
+               int * length = matrix_->getMutableVectorLengths();
+#ifndef NDEBUG
+               if (length[number]) {
+                    int * row = matrix_->getMutableIndices();
+                    CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+                    int iRow = row[startColumn[number] + length[number] - 1];
+                    int which = iRow - numberStaticRows_;
+                    assert (which >= 0);
+                    int iSet = fromIndex_[which];
+                    assert (toIndex_[iSet] == which);
+               }
+#endif
+               // no need firstAvailable_--;
+               solution[firstAvailable_] = 0.0;
+               cost[firstAvailable_] = 0.0;
+               length[firstAvailable_] = 0;
+               model->nonLinearCost()->setOne(firstAvailable_, 0.0, 0.0, COIN_DBL_MAX, 0.0);
+               model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
+               columnLower[firstAvailable_] = 0.0;
+               columnUpper[firstAvailable_] = COIN_DBL_MAX;
+
+               // not really in small problem
+               int iBig = id_[number-firstDynamic_];
+               if (model->getStatus(number) == ClpSimplex::atLowerBound) {
+                    setDynamicStatus(iBig, atLowerBound);
+                    if (columnLower_)
+                         modifyOffset(number, columnLower_[iBig]);
+               } else {
+                    setDynamicStatus(iBig, atUpperBound);
+                    modifyOffset(number, columnUpper_[iBig]);
+               }
+	  } else if (number>=model_->numberColumns()+numberStaticRows_) {
+	    // slack
+	    int iSet = fromIndex_[number-model_->numberColumns()-
+				  numberStaticRows_];
+	    printf("what now - set %d\n",iSet);
+          }
+     }
+     break;
+     default:
+          break;
+     }
+     return returnCode;
+}
+/* Purely for column generation and similar ideas.  Allows
+   matrix and any bounds or costs to be updated (sensibly).
+   Returns non-zero if any changes.
+*/
+int
+ClpDynamicMatrix::refresh(ClpSimplex * model)
+{
+     // If at beginning then create initial problem
+     if (firstDynamic_ == firstAvailable_) {
+          initialProblem();
+          return 1;
+     } else if (!model->nonLinearCost()) {
+          // will be same as last time
+          return 1;
+     }
+#ifndef NDEBUG
+     {
+       int numberColumns = model->numberColumns();
+       int numberRows = model->numberRows();
+       int * pivotVariable = model->pivotVariable();
+       for (int i=numberStaticRows_+numberActiveSets_;i<numberRows;i++) {
+	 assert (pivotVariable[i]==i+numberColumns);
+       }
+     }
+#endif
+     // lookup array
+     int * active = new int [numberActiveSets_];
+     CoinZeroN(active, numberActiveSets_);
+     int iColumn;
+     int numberColumns = model->numberColumns();
+     double * element =  matrix_->getMutableElements();
+     int * row = matrix_->getMutableIndices();
+     CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+     int * length = matrix_->getMutableVectorLengths();
+     double * cost = model->costRegion();
+     double * columnLower = model->lowerRegion();
+     double * columnUpper = model->upperRegion();
+     CoinBigIndex numberElements = startColumn[firstDynamic_];
+     // first just do lookup and basic stuff
+     int currentNumber = firstAvailable_;
+     firstAvailable_ = firstDynamic_;
+     double objectiveChange = 0.0;
+     double * solution = model->solutionRegion();
+     int currentNumberActiveSets = numberActiveSets_;
+     for (iColumn = firstDynamic_; iColumn < currentNumber; iColumn++) {
+          int iRow = row[startColumn[iColumn] + length[iColumn] - 1];
+          int which = iRow - numberStaticRows_;
+          assert (which >= 0);
+          int iSet = fromIndex_[which];
+          assert (toIndex_[iSet] == which);
+          if (model->getStatus(iColumn) == ClpSimplex::basic) {
+               active[which]++;
+               // may as well make key
+               keyVariable_[iSet] = id_[iColumn-firstDynamic_];
+          }
+     }
+     int i;
+     numberActiveSets_ = 0;
+     int numberDeleted = 0;
+     for (i = 0; i < currentNumberActiveSets; i++) {
+          int iRow = i + numberStaticRows_;
+          int numberActive = active[i];
+          int iSet = fromIndex_[i];
+          if (model->getRowStatus(iRow) == ClpSimplex::basic) {
+               numberActive++;
+               // may as well make key
+               keyVariable_[iSet] = maximumGubColumns_ + iSet;
+          }
+          if (numberActive > 1) {
+               // keep
+               active[i] = numberActiveSets_;
+               numberActiveSets_++;
+          } else {
+               active[i] = -1;
+          }
+     }
+
+     for (iColumn = firstDynamic_; iColumn < currentNumber; iColumn++) {
+          int iRow = row[startColumn[iColumn] + length[iColumn] - 1];
+          int which = iRow - numberStaticRows_;
+          int jColumn = id_[iColumn-firstDynamic_];
+          if (model->getStatus(iColumn) == ClpSimplex::atLowerBound ||
+                    model->getStatus(iColumn) == ClpSimplex::atUpperBound) {
+               double value = solution[iColumn];
+               bool toLowerBound = true;
+	       assert (jColumn>=0);assert (iColumn>=0);
+               if (columnUpper_) {
+                    if (!columnLower_) {
+                         if (fabs(value - columnUpper_[jColumn]) < fabs(value))
+                              toLowerBound = false;
+                    } else if (fabs(value - columnUpper_[jColumn]) < fabs(value - columnLower_[jColumn])) {
+                         toLowerBound = false;
+                    }
+               }
+               if (toLowerBound) {
+                    // throw out to lower bound
+                    if (columnLower_) {
+                         setDynamicStatus(jColumn, atLowerBound);
+                         // treat solution as if exactly at a bound
+                         double value = columnLower[iColumn];
+                         objectiveChange += cost[iColumn] * value;
+                    } else {
+                         setDynamicStatus(jColumn, atLowerBound);
+                    }
+               } else {
+                    // throw out to upper bound
+                    setDynamicStatus(jColumn, atUpperBound);
+                    double value = columnUpper[iColumn];
+                    objectiveChange += cost[iColumn] * value;
+               }
+               numberDeleted++;
+          } else {
+               assert(model->getStatus(iColumn) != ClpSimplex::superBasic); // deal with later
+               int iPut = active[which];
+               if (iPut >= 0) {
+                    // move
+                    id_[firstAvailable_-firstDynamic_] = jColumn;
+                    int numberThis = startColumn_[jColumn+1] - startColumn_[jColumn] + 1;
+                    length[firstAvailable_] = numberThis;
+                    cost[firstAvailable_] = cost[iColumn];
+                    columnLower[firstAvailable_] = columnLower[iColumn];
+                    columnUpper[firstAvailable_] = columnUpper[iColumn];
+                    model->nonLinearCost()->setOne(firstAvailable_, solution[iColumn], 0.0, COIN_DBL_MAX,
+                                                   cost_[jColumn]);
+                    CoinBigIndex base = startColumn_[jColumn];
+                    for (int j = 0; j < numberThis - 1; j++) {
+                         row[numberElements] = row_[base+j];
+                         element[numberElements++] = element_[base+j];
+                    }
+                    row[numberElements] = iPut + numberStaticRows_;
+                    element[numberElements++] = 1.0;
+                    model->setStatus(firstAvailable_, model->getStatus(iColumn));
+                    solution[firstAvailable_] = solution[iColumn];
+                    firstAvailable_++;
+                    startColumn[firstAvailable_] = numberElements;
+               }
+          }
+     }
+     // zero solution
+     CoinZeroN(solution + firstAvailable_, currentNumber - firstAvailable_);
+     // zero cost
+     CoinZeroN(cost + firstAvailable_, currentNumber - firstAvailable_);
+     // zero lengths
+     CoinZeroN(length + firstAvailable_, currentNumber - firstAvailable_);
+     for ( iColumn = firstAvailable_; iColumn < currentNumber; iColumn++) {
+          model->nonLinearCost()->setOne(iColumn, 0.0, 0.0, COIN_DBL_MAX, 0.0);
+          model->setStatus(iColumn, ClpSimplex::atLowerBound);
+          columnLower[iColumn] = 0.0;
+          columnUpper[iColumn] = COIN_DBL_MAX;
+     }
+     // move rhs and set rest to infinite
+     numberActiveSets_ = 0;
+     for (i = 0; i < currentNumberActiveSets; i++) {
+          int iSet = fromIndex_[i];
+          assert (toIndex_[iSet] == i);
+          int iRow = i + numberStaticRows_;
+          int iPut = active[i];
+          if (iPut >= 0) {
+               int in = iRow + numberColumns;
+               int out = iPut + numberColumns + numberStaticRows_;
+               solution[out] = solution[in];
+               columnLower[out] = columnLower[in];
+               columnUpper[out] = columnUpper[in];
+               cost[out] = cost[in];
+               double trueLower;
+               if (lowerSet_[iSet] > -1.0e20)
+                    trueLower = lowerSet_[iSet];
+               else
+                    trueLower = -COIN_DBL_MAX;
+               double trueUpper;
+               if (upperSet_[iSet] < 1.0e20)
+                    trueUpper = upperSet_[iSet];
+               else
+                    trueUpper = COIN_DBL_MAX;
+               model->nonLinearCost()->setOne(out, solution[out],
+                                              trueLower, trueUpper, 0.0);
+               model->setStatus(out, model->getStatus(in));
+               toIndex_[iSet] = numberActiveSets_;
+               rhsOffset_[numberActiveSets_+numberStaticRows_] = rhsOffset_[i+numberStaticRows_];
+               fromIndex_[numberActiveSets_++] = fromIndex_[i];
+          } else {
+               // adjust offset
+               // put out as key
+               int jColumn = keyVariable_[iSet];
+               toIndex_[iSet] = -1;
+               if (jColumn < maximumGubColumns_) {
+                    setDynamicStatus(jColumn, soloKey);
+                    double value = keyValue(iSet);
+                    objectiveChange += cost_[jColumn] * value;
+                    modifyOffset(jColumn, -value);
+               }
+          }
+     }
+     model->setObjectiveOffset(model->objectiveOffset() - objectiveChange);
+     delete [] active;
+     for (i = numberActiveSets_; i < currentNumberActiveSets; i++) {
+          int iSequence = i + numberStaticRows_ + numberColumns;
+          solution[iSequence] = 0.0;
+          columnLower[iSequence] = -COIN_DBL_MAX;
+          columnUpper[iSequence] = COIN_DBL_MAX;
+          cost[iSequence] = 0.0;
+          model->nonLinearCost()->setOne(iSequence, solution[iSequence],
+                                         columnLower[iSequence],
+                                         columnUpper[iSequence], 0.0);
+          model->setStatus(iSequence, ClpSimplex::basic);
+          rhsOffset_[i+numberStaticRows_] = 0.0;
+     }
+     if (currentNumberActiveSets != numberActiveSets_ || numberDeleted) {
+          // deal with pivotVariable
+          int * pivotVariable = model->pivotVariable();
+          int sequence = firstDynamic_;
+          int iRow = 0;
+          int base1 = firstDynamic_;
+          int base2 = lastDynamic_;
+          int base3 = numberColumns + numberStaticRows_;
+          int numberRows = numberStaticRows_ + currentNumberActiveSets;
+          while (sequence < firstAvailable_) {
+               int iPivot = pivotVariable[iRow];
+               while (iPivot < base1 || (iPivot >= base2 && iPivot < base3)) {
+                    iPivot = pivotVariable[++iRow];
+               }
+               pivotVariable[iRow++] = sequence;
+               sequence++;
+          }
+          // move normal basic ones down
+          int iPut = iRow;
+          for (; iRow < numberRows; iRow++) {
+               int iPivot = pivotVariable[iRow];
+               if (iPivot < base1 || (iPivot >= base2 && iPivot < base3)) {
+                    pivotVariable[iPut++] = iPivot;
+               }
+          }
+          // and basic others
+          for (i = 0; i < numberActiveSets_; i++) {
+               if (model->getRowStatus(i + numberStaticRows_) == ClpSimplex::basic) {
+                    pivotVariable[iPut++] = i + base3;
+               }
+          }
+	  if (iPut<numberStaticRows_+numberActiveSets_) {
+	    printf("lost %d sets\n",
+		   numberStaticRows_+numberActiveSets_-iPut);
+	    iPut = numberStaticRows_+numberActiveSets_;
+	  }
+          for (i = numberActiveSets_; i < currentNumberActiveSets; i++) {
+               pivotVariable[iPut++] = i + base3;
+          }
+          //assert (iPut == numberRows);
+     }
+#ifdef CLP_DEBUG
+#if 0
+     printf("row for set 244 is %d, row status %d value %g ", toIndex_[244], status_[244],
+            keyValue(244));
+     int jj = startSet_[244];
+     while (jj >= 0) {
+          printf("var %d status %d ", jj, dynamicStatus_[jj]);
+          jj = next_[jj];
+     }
+     printf("\n");
+#endif
+#ifdef CLP_DEBUG
+     {
+          // debug coding to analyze set
+          int i;
+          int kSet = -6;
+          if (kSet >= 0) {
+               int * back = new int [numberGubColumns_];
+               for (i = 0; i < numberGubColumns_; i++)
+                    back[i] = -1;
+               for (i = firstDynamic_; i < firstAvailable_; i++)
+                    back[id_[i-firstDynamic_]] = i;
+               int sequence = startSet_[kSet];
+               if (toIndex_[kSet] < 0) {
+                    printf("Not in - Set %d - slack status %d, key %d\n", kSet, status_[kSet], keyVariable_[kSet]);
+                    while (sequence >= 0) {
+                         printf("( %d status %d ) ", sequence, getDynamicStatus(sequence));
+                         sequence = next_[sequence];
+                    }
+               } else {
+                    int iRow = numberStaticRows_ + toIndex_[kSet];
+                    printf("In - Set %d - slack status %d, key %d offset %g slack %g\n", kSet, status_[kSet], keyVariable_[kSet],
+                           rhsOffset_[iRow], model->solutionRegion(0)[iRow]);
+                    while (sequence >= 0) {
+                         int iBack = back[sequence];
+                         printf("( %d status %d value %g) ", sequence, getDynamicStatus(sequence), model->solutionRegion()[iBack]);
+                         sequence = next_[sequence];
+                    }
+               }
+               printf("\n");
+               delete [] back;
+          }
+     }
+#endif
+     int n = numberActiveSets_;
+     for (i = 0; i < numberSets_; i++) {
+          if (toIndex_[i] < 0) {
+               //assert(keyValue(i)>=lowerSet_[i]&&keyValue(i)<=upperSet_[i]);
+               n++;
+          }
+	  int k=0;
+	  for (int j=startSet_[i];j<startSet_[i+1];j++) {
+	    if (getDynamicStatus(j)==soloKey)
+	      k++;
+	  }
+	  assert (k<2);
+     }
+     assert (n == numberSets_);
+#endif
+     return 1;
+}
+void
+ClpDynamicMatrix::times(double scalar,
+                        const double * x, double * y) const
+{
+     if (model_->specialOptions() != 16) {
+          ClpPackedMatrix::times(scalar, x, y);
+     } else {
+          int iRow;
+          const double * element =  matrix_->getElements();
+          const int * row = matrix_->getIndices();
+          const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+          const int * length = matrix_->getVectorLengths();
+          int * pivotVariable = model_->pivotVariable();
+          for (iRow = 0; iRow < numberStaticRows_ + numberActiveSets_; iRow++) {
+               y[iRow] -= scalar * rhsOffset_[iRow];
+               int iColumn = pivotVariable[iRow];
+               if (iColumn < lastDynamic_) {
+                    CoinBigIndex j;
+                    double value = scalar * x[iColumn];
+                    if (value) {
+                         for (j = startColumn[iColumn];
+                                   j < startColumn[iColumn] + length[iColumn]; j++) {
+                              int jRow = row[j];
+                              y[jRow] += value * element[j];
+                         }
+                    }
+               }
+          }
+     }
+}
+// Modifies rhs offset
+void
+ClpDynamicMatrix::modifyOffset(int sequence, double amount)
+{
+     if (amount) {
+          assert (rhsOffset_);
+          CoinBigIndex j;
+          for (j = startColumn_[sequence]; j < startColumn_[sequence+1]; j++) {
+               int iRow = row_[j];
+               rhsOffset_[iRow] += amount * element_[j];
+          }
+     }
+}
+// Gets key value when none in small
+double
+ClpDynamicMatrix::keyValue(int iSet) const
+{
+     double value = 0.0;
+     if (toIndex_[iSet] < 0) {
+          int key = keyVariable_[iSet];
+          if (key < maximumGubColumns_) {
+               if (getStatus(iSet) == ClpSimplex::atLowerBound)
+                    value = lowerSet_[iSet];
+               else
+                    value = upperSet_[iSet];
+               int numberKey = 0;
+               int j = startSet_[iSet];
+               while (j >= 0) {
+                    DynamicStatus status = getDynamicStatus(j);
+                    assert (status != inSmall);
+                    if (status == soloKey) {
+                         numberKey++;
+                    } else if (status == atUpperBound) {
+                         value -= columnUpper_[j];
+                    } else if (columnLower_) {
+                         value -= columnLower_[j];
+                    }
+                    j = next_[j]; //onto next in set
+               }
+               assert (numberKey == 1);
+          } else {
+               int j = startSet_[iSet];
+               while (j >= 0) {
+                    DynamicStatus status = getDynamicStatus(j);
+                    assert (status != inSmall);
+                    assert (status != soloKey);
+                    if (status == atUpperBound) {
+                         value += columnUpper_[j];
+                    } else if (columnLower_) {
+                         value += columnLower_[j];
+                    }
+                    j = next_[j]; //onto next in set
+               }
+#if 0
+	       // slack must be feasible
+	       double oldValue=value;
+	       value = CoinMax(value,lowerSet_[iSet]);
+               value = CoinMin(value,upperSet_[iSet]);
+	       if (value!=oldValue)
+		 printf("using %g (not %g) for slack on set %d (%g,%g)\n",
+			value,oldValue,iSet,lowerSet_[iSet],upperSet_[iSet]);
+#endif
+            }
+     }
+     return value;
+}
+// Switches off dj checking each factorization (for BIG models)
+void
+ClpDynamicMatrix::switchOffCheck()
+{
+     noCheck_ = 0;
+     infeasibilityWeight_ = 0.0;
+}
+/* Creates a variable.  This is called after partial pricing and may modify matrix.
+   May update bestSequence.
+*/
+void
+ClpDynamicMatrix::createVariable(ClpSimplex * model, int & bestSequence)
+{
+     int numberRows = model->numberRows();
+     int slackOffset = lastDynamic_ + numberRows;
+     int structuralOffset = slackOffset + numberSets_;
+     int bestSequence2 = savedBestSequence_ - structuralOffset;
+     if (bestSequence >= slackOffset) {
+          double * columnLower = model->lowerRegion();
+          double * columnUpper = model->upperRegion();
+          double * solution = model->solutionRegion();
+          double * reducedCost = model->djRegion();
+          const double * duals = model->dualRowSolution();
+          if (toIndex_[savedBestSet_] < 0) {
+               // need to put key into basis
+               int newRow = numberActiveSets_ + numberStaticRows_;
+               model->dualRowSolution()[newRow] = savedBestGubDual_;
+               double valueOfKey = keyValue(savedBestSet_); // done before toIndex_ set
+               toIndex_[savedBestSet_] = numberActiveSets_;
+               fromIndex_[numberActiveSets_++] = savedBestSet_;
+               int iSequence = lastDynamic_ + newRow;
+               // we need to get lower and upper correct
+               double shift = 0.0;
+               int j = startSet_[savedBestSet_];
+               while (j >= 0) {
+                    if (getDynamicStatus(j) == atUpperBound)
+                         shift += columnUpper_[j];
+                    else if (getDynamicStatus(j) == atLowerBound && columnLower_)
+                         shift += columnLower_[j];
+                    j = next_[j]; //onto next in set
+               }
+               if (lowerSet_[savedBestSet_] > -1.0e20)
+                    columnLower[iSequence] = lowerSet_[savedBestSet_];
+               else
+                    columnLower[iSequence] = -COIN_DBL_MAX;
+               if (upperSet_[savedBestSet_] < 1.0e20)
+                    columnUpper[iSequence] = upperSet_[savedBestSet_];
+               else
+                    columnUpper[iSequence] = COIN_DBL_MAX;
+#ifdef CLP_DEBUG
+               if (model_->logLevel() == 63) {
+                    printf("%d in in set %d, key is %d rhs %g %g - keyvalue %g\n",
+                           bestSequence2, savedBestSet_, keyVariable_[savedBestSet_],
+                           columnLower[iSequence], columnUpper[iSequence], valueOfKey);
+                    int j = startSet_[savedBestSet_];
+                    while (j >= 0) {
+                         if (getDynamicStatus(j) == atUpperBound)
+                              printf("%d atup ", j);
+                         else if (getDynamicStatus(j) == atLowerBound)
+                              printf("%d atlo ", j);
+                         else if (getDynamicStatus(j) == soloKey)
+                              printf("%d solo ", j);
+                         else
+                              abort();
+                         j = next_[j]; //onto next in set
+                    }
+                    printf("\n");
+               }
+#endif
+               if (keyVariable_[savedBestSet_] < maximumGubColumns_) {
+                    // slack not key
+                    model_->pivotVariable()[newRow] = firstAvailable_;
+                    backToPivotRow_[firstAvailable_] = newRow;
+                    model->setStatus(iSequence, getStatus(savedBestSet_));
+                    model->djRegion()[iSequence] = savedBestGubDual_;
+                    solution[iSequence] = valueOfKey;
+		    // create variable and pivot in
+                    int key = keyVariable_[savedBestSet_];
+                    setDynamicStatus(key, inSmall);
+                    double * element =  matrix_->getMutableElements();
+                    int * row = matrix_->getMutableIndices();
+                    CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+                    int * length = matrix_->getMutableVectorLengths();
+                    CoinBigIndex numberElements = startColumn[firstAvailable_];
+                    int numberThis = startColumn_[key+1] - startColumn_[key] + 1;
+                    if (numberElements + numberThis > numberElements_) {
+                         // need to redo
+                         numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis);
+                         matrix_->reserve(lastDynamic_, numberElements_);
+                         element =  matrix_->getMutableElements();
+                         row = matrix_->getMutableIndices();
+                         // these probably okay but be safe
+                         startColumn = matrix_->getMutableVectorStarts();
+                         length = matrix_->getMutableVectorLengths();
+                    }
+                    // already set startColumn[firstAvailable_]=numberElements;
+                    length[firstAvailable_] = numberThis;
+                    model->costRegion()[firstAvailable_] = cost_[key];
+                    CoinBigIndex base = startColumn_[key];
+                    for (int j = 0; j < numberThis - 1; j++) {
+                         row[numberElements] = row_[base+j];
+                         element[numberElements++] = element_[base+j];
+                    }
+                    row[numberElements] = newRow;
+                    element[numberElements++] = 1.0;
+                    id_[firstAvailable_-firstDynamic_] = key;
+                    model->setObjectiveOffset(model->objectiveOffset() + cost_[key]*
+                                              valueOfKey);
+                    model->solutionRegion()[firstAvailable_] = valueOfKey;
+                    model->setStatus(firstAvailable_, ClpSimplex::basic);
+                    // ***** need to adjust effective rhs
+                    if (!columnLower_ && !columnUpper_) {
+                         columnLower[firstAvailable_] = 0.0;
+                         columnUpper[firstAvailable_] = COIN_DBL_MAX;
+                    }  else {
+                         if (columnLower_)
+                              columnLower[firstAvailable_] = columnLower_[key];
+                         else
+                              columnLower[firstAvailable_] = 0.0;
+                         if (columnUpper_)
+                              columnUpper[firstAvailable_] = columnUpper_[key];
+                         else
+                              columnUpper[firstAvailable_] = COIN_DBL_MAX;
+                    }
+                    model->nonLinearCost()->setOne(firstAvailable_, solution[firstAvailable_],
+                                                   columnLower[firstAvailable_],
+                                                   columnUpper[firstAvailable_], cost_[key]);
+                    startColumn[firstAvailable_+1] = numberElements;
+                    reducedCost[firstAvailable_] = 0.0;
+                    modifyOffset(key, valueOfKey);
+                    rhsOffset_[newRow] = -shift; // sign?
+#ifdef CLP_DEBUG
+                    model->rowArray(1)->checkClear();
+#endif
+                    // now pivot in
+                    unpack(model, model->rowArray(1), firstAvailable_);
+                    model->factorization()->updateColumnFT(model->rowArray(2), model->rowArray(1));
+                    double alpha = model->rowArray(1)->denseVector()[newRow];
+                    int updateStatus =
+                         model->factorization()->replaceColumn(model,
+                                   model->rowArray(2),
+                                   model->rowArray(1),
+                                   newRow, alpha);
+                    model->rowArray(1)->clear();
+                    if (updateStatus) {
+                         if (updateStatus == 3) {
+                              // out of memory
+                              // increase space if not many iterations
+                              if (model->factorization()->pivots() <
+                                        0.5 * model->factorization()->maximumPivots() &&
+                                        model->factorization()->pivots() < 400)
+                                   model->factorization()->areaFactor(
+                                        model->factorization()->areaFactor() * 1.1);
+                         } else {
+                              printf("Bad returncode %d from replaceColumn\n", updateStatus);
+                         }
+                         bestSequence = -1;
+                         return;
+                    }
+                    // firstAvailable_ only finally updated if good pivot (in updatePivot)
+                    // otherwise it reverts to firstAvailableBefore_
+                    firstAvailable_++;
+               } else {
+                    // slack key
+                    model->setStatus(iSequence, ClpSimplex::basic);
+                    model->djRegion()[iSequence] = 0.0;
+                    solution[iSequence] = valueOfKey+shift;
+                    rhsOffset_[newRow] = -shift; // sign?
+               }
+               // correct slack
+               model->costRegion()[iSequence] = 0.0;
+               model->nonLinearCost()->setOne(iSequence, solution[iSequence], columnLower[iSequence],
+                                              columnUpper[iSequence], 0.0);
+          }
+          if (savedBestSequence_ >= structuralOffset) {
+               // recompute dj and create
+               double value = cost_[bestSequence2] - savedBestGubDual_;
+               for (CoinBigIndex jBigIndex = startColumn_[bestSequence2];
+                         jBigIndex < startColumn_[bestSequence2+1]; jBigIndex++) {
+                    int jRow = row_[jBigIndex];
+                    value -= duals[jRow] * element_[jBigIndex];
+               }
+               int gubRow = toIndex_[savedBestSet_] + numberStaticRows_;
+               double * element =  matrix_->getMutableElements();
+               int * row = matrix_->getMutableIndices();
+               CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+               int * length = matrix_->getMutableVectorLengths();
+               CoinBigIndex numberElements = startColumn[firstAvailable_];
+               int numberThis = startColumn_[bestSequence2+1] - startColumn_[bestSequence2] + 1;
+               if (numberElements + numberThis > numberElements_) {
+                    // need to redo
+                    numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis);
+                    matrix_->reserve(lastDynamic_, numberElements_);
+                    element =  matrix_->getMutableElements();
+                    row = matrix_->getMutableIndices();
+                    // these probably okay but be safe
+                    startColumn = matrix_->getMutableVectorStarts();
+                    length = matrix_->getMutableVectorLengths();
+               }
+               // already set startColumn[firstAvailable_]=numberElements;
+               length[firstAvailable_] = numberThis;
+               model->costRegion()[firstAvailable_] = cost_[bestSequence2];
+               CoinBigIndex base = startColumn_[bestSequence2];
+               for (int j = 0; j < numberThis - 1; j++) {
+                    row[numberElements] = row_[base+j];
+                    element[numberElements++] = element_[base+j];
+               }
+               row[numberElements] = gubRow;
+               element[numberElements++] = 1.0;
+               id_[firstAvailable_-firstDynamic_] = bestSequence2;
+               //printf("best %d\n",bestSequence2);
+               model->solutionRegion()[firstAvailable_] = 0.0;
+	       model->clearFlagged(firstAvailable_);
+               if (!columnLower_ && !columnUpper_) {
+                    model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
+                    columnLower[firstAvailable_] = 0.0;
+                    columnUpper[firstAvailable_] = COIN_DBL_MAX;
+               }  else {
+                    DynamicStatus status = getDynamicStatus(bestSequence2);
+                    if (columnLower_)
+                         columnLower[firstAvailable_] = columnLower_[bestSequence2];
+                    else
+                         columnLower[firstAvailable_] = 0.0;
+                    if (columnUpper_)
+                         columnUpper[firstAvailable_] = columnUpper_[bestSequence2];
+                    else
+                         columnUpper[firstAvailable_] = COIN_DBL_MAX;
+                    if (status == atLowerBound) {
+                         solution[firstAvailable_] = columnLower[firstAvailable_];
+                         model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
+                    } else {
+                         solution[firstAvailable_] = columnUpper[firstAvailable_];
+                         model->setStatus(firstAvailable_, ClpSimplex::atUpperBound);
+                    }
+               }
+               model->setObjectiveOffset(model->objectiveOffset() + cost_[bestSequence2]*
+                                         solution[firstAvailable_]);
+               model->nonLinearCost()->setOne(firstAvailable_, solution[firstAvailable_],
+                                              columnLower[firstAvailable_],
+                                              columnUpper[firstAvailable_], cost_[bestSequence2]);
+               bestSequence = firstAvailable_;
+               // firstAvailable_ only updated if good pivot (in updatePivot)
+               startColumn[firstAvailable_+1] = numberElements;
+               //printf("price struct %d - dj %g gubpi %g\n",bestSequence,value,savedBestGubDual_);
+               reducedCost[bestSequence] = value;
+          } else {
+               // slack - row must just have been created
+               assert (toIndex_[savedBestSet_] == numberActiveSets_ - 1);
+               int newRow = numberStaticRows_ + numberActiveSets_ - 1;
+               bestSequence = lastDynamic_ + newRow;
+               reducedCost[bestSequence] = savedBestGubDual_;
+          }
+     }
+     // clear for next iteration
+     savedBestSequence_ = -1;
+}
+// Returns reduced cost of a variable
+double
+ClpDynamicMatrix::reducedCost(ClpSimplex * model, int sequence) const
+{
+     int numberRows = model->numberRows();
+     int slackOffset = lastDynamic_ + numberRows;
+     if (sequence < slackOffset)
+          return model->djRegion()[sequence];
+     else
+          return savedBestDj_;
+}
+// Does gub crash
+void
+ClpDynamicMatrix::gubCrash()
+{
+     // Do basis - cheapest or slack if feasible
+     int longestSet = 0;
+     int iSet;
+     for (iSet = 0; iSet < numberSets_; iSet++) {
+          int n = 0;
+          int j = startSet_[iSet];
+          while (j >= 0) {
+               n++;
+               j = next_[j];
+          }
+          longestSet = CoinMax(longestSet, n);
+     }
+     double * upper = new double[longestSet+1];
+     double * cost = new double[longestSet+1];
+     double * lower = new double[longestSet+1];
+     double * solution = new double[longestSet+1];
+     int * back = new int[longestSet+1];
+     double tolerance = model_->primalTolerance();
+     double objectiveOffset = 0.0;
+     for (iSet = 0; iSet < numberSets_; iSet++) {
+          int iBasic = -1;
+          double value = 0.0;
+          // find cheapest
+          int numberInSet = 0;
+          int j = startSet_[iSet];
+          while (j >= 0) {
+               if (!columnLower_)
+                    lower[numberInSet] = 0.0;
+               else
+                    lower[numberInSet] = columnLower_[j];
+               if (!columnUpper_)
+                    upper[numberInSet] = COIN_DBL_MAX;
+               else
+                    upper[numberInSet] = columnUpper_[j];
+               back[numberInSet++] = j;
+               j = next_[j];
+          }
+          CoinFillN(solution, numberInSet, 0.0);
+          // and slack
+          iBasic = numberInSet;
+          solution[iBasic] = -value;
+          lower[iBasic] = -upperSet_[iSet];
+          upper[iBasic] = -lowerSet_[iSet];
+          int kphase;
+          if (value < lowerSet_[iSet] - tolerance || value > upperSet_[iSet] + tolerance) {
+               // infeasible
+               kphase = 0;
+               // remember bounds are flipped so opposite to natural
+               if (value < lowerSet_[iSet] - tolerance)
+                    cost[iBasic] = 1.0;
+               else
+                    cost[iBasic] = -1.0;
+               CoinZeroN(cost, numberInSet);
+               double dualTolerance = model_->dualTolerance();
+               for (int iphase = kphase; iphase < 2; iphase++) {
+                    if (iphase) {
+                         cost[numberInSet] = 0.0;
+                         for (int j = 0; j < numberInSet; j++)
+                              cost[j] = cost_[back[j]];
+                    }
+                    // now do one row lp
+                    bool improve = true;
+                    while (improve) {
+                         improve = false;
+                         double dual = cost[iBasic];
+                         int chosen = -1;
+                         double best = dualTolerance;
+                         int way = 0;
+                         for (int i = 0; i <= numberInSet; i++) {
+                              double dj = cost[i] - dual;
+                              double improvement = 0.0;
+                              if (iphase || i < numberInSet)
+                                   assert (solution[i] >= lower[i] && solution[i] <= upper[i]);
+                              if (dj > dualTolerance)
+                                   improvement = dj * (solution[i] - lower[i]);
+                              else if (dj < -dualTolerance)
+                                   improvement = dj * (solution[i] - upper[i]);
+                              if (improvement > best) {
+                                   best = improvement;
+                                   chosen = i;
+                                   if (dj < 0.0) {
+                                        way = 1;
+                                   } else {
+                                        way = -1;
+                                   }
+                              }
+                         }
+                         if (chosen >= 0) {
+                              improve = true;
+                              // now see how far
+                              if (way > 0) {
+                                   // incoming increasing so basic decreasing
+                                   // if phase 0 then go to nearest bound
+                                   double distance = upper[chosen] - solution[chosen];
+                                   double basicDistance;
+                                   if (!iphase) {
+                                        assert (iBasic == numberInSet);
+                                        assert (solution[iBasic] > upper[iBasic]);
+                                        basicDistance = solution[iBasic] - upper[iBasic];
+                                   } else {
+                                        basicDistance = solution[iBasic] - lower[iBasic];
+                                   }
+                                   // need extra coding for unbounded
+                                   assert (CoinMin(distance, basicDistance) < 1.0e20);
+                                   if (distance > basicDistance) {
+                                        // incoming becomes basic
+                                        solution[chosen] += basicDistance;
+                                        if (!iphase)
+                                             solution[iBasic] = upper[iBasic];
+                                        else
+                                             solution[iBasic] = lower[iBasic];
+                                        iBasic = chosen;
+                                   } else {
+                                        // flip
+                                        solution[chosen] = upper[chosen];
+                                        solution[iBasic] -= distance;
+                                   }
+                              } else {
+                                   // incoming decreasing so basic increasing
+                                   // if phase 0 then go to nearest bound
+                                   double distance = solution[chosen] - lower[chosen];
+                                   double basicDistance;
+                                   if (!iphase) {
+                                        assert (iBasic == numberInSet);
+                                        assert (solution[iBasic] < lower[iBasic]);
+                                        basicDistance = lower[iBasic] - solution[iBasic];
+                                   } else {
+                                        basicDistance = upper[iBasic] - solution[iBasic];
+                                   }
+                                   // need extra coding for unbounded - for now just exit
+                                   if (CoinMin(distance, basicDistance) > 1.0e20) {
+                                        printf("unbounded on set %d\n", iSet);
+                                        iphase = 1;
+                                        iBasic = numberInSet;
+                                        break;
+                                   }
+                                   if (distance > basicDistance) {
+                                        // incoming becomes basic
+                                        solution[chosen] -= basicDistance;
+                                        if (!iphase)
+                                             solution[iBasic] = lower[iBasic];
+                                        else
+                                             solution[iBasic] = upper[iBasic];
+                                        iBasic = chosen;
+                                   } else {
+                                        // flip
+                                        solution[chosen] = lower[chosen];
+                                        solution[iBasic] += distance;
+                                   }
+                              }
+                              if (!iphase) {
+                                   if(iBasic < numberInSet)
+                                        break; // feasible
+                                   else if (solution[iBasic] >= lower[iBasic] &&
+                                             solution[iBasic] <= upper[iBasic])
+                                        break; // feasible (on flip)
+                              }
+                         }
+                    }
+               }
+          }
+          // do solution i.e. bounds
+          if (columnLower_ || columnUpper_) {
+               for (int j = 0; j < numberInSet; j++) {
+                    if (j != iBasic) {
+                         objectiveOffset += solution[j] * cost[j];
+                         if (columnLower_ && columnUpper_) {
+                              if (fabs(solution[j] - columnLower_[back[j]]) >
+                                        fabs(solution[j] - columnUpper_[back[j]]))
+                                   setDynamicStatus(back[j], atUpperBound);
+                         } else if (columnUpper_ && solution[j] > 0.0) {
+                              setDynamicStatus(back[j], atUpperBound);
+                         } else {
+                              setDynamicStatus(back[j], atLowerBound);
+                              assert(!solution[j]);
+                         }
+                    }
+               }
+          }
+          // convert iBasic back and do bounds
+          if (iBasic == numberInSet) {
+               // slack basic
+               setStatus(iSet, ClpSimplex::basic);
+               iBasic = iSet + maximumGubColumns_;
+          } else {
+               iBasic = back[iBasic];
+               setDynamicStatus(iBasic, soloKey);
+               // remember bounds flipped
+               if (upper[numberInSet] == lower[numberInSet])
+                    setStatus(iSet, ClpSimplex::isFixed);
+               else if (solution[numberInSet] == upper[numberInSet])
+                    setStatus(iSet, ClpSimplex::atLowerBound);
+               else if (solution[numberInSet] == lower[numberInSet])
+                    setStatus(iSet, ClpSimplex::atUpperBound);
+               else
+                    abort();
+          }
+          keyVariable_[iSet] = iBasic;
+     }
+     model_->setObjectiveOffset(objectiveOffset_ - objectiveOffset);
+     delete [] lower;
+     delete [] solution;
+     delete [] upper;
+     delete [] cost;
+     delete [] back;
+     // make sure matrix is in good shape
+     matrix_->orderMatrix();
+}
+// Populates initial matrix from dynamic status
+void
+ClpDynamicMatrix::initialProblem()
+{
+     int iSet;
+     double * element =  matrix_->getMutableElements();
+     int * row = matrix_->getMutableIndices();
+     CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+     int * length = matrix_->getMutableVectorLengths();
+     double * cost = model_->objective();
+     double * solution = model_->primalColumnSolution();
+     double * columnLower = model_->columnLower();
+     double * columnUpper = model_->columnUpper();
+     double * rowSolution = model_->primalRowSolution();
+     double * rowLower = model_->rowLower();
+     double * rowUpper = model_->rowUpper();
+     CoinBigIndex numberElements = startColumn[firstDynamic_];
+
+     firstAvailable_ = firstDynamic_;
+     numberActiveSets_ = 0;
+     for (iSet = 0; iSet < numberSets_; iSet++) {
+          toIndex_[iSet] = -1;
+          int numberActive = 0;
+          int whichKey = -1;
+          if (getStatus(iSet) == ClpSimplex::basic) {
+               whichKey = maximumGubColumns_ + iSet;
+	       numberActive = 1;
+          } else {
+               whichKey = -1;
+	  }
+          int j = startSet_[iSet];
+          while (j >= 0) {
+               assert (getDynamicStatus(j) != soloKey || whichKey == -1);
+               if (getDynamicStatus(j) == inSmall) {
+                    numberActive++;
+               } else if (getDynamicStatus(j) == soloKey) {
+                    whichKey = j;
+                    numberActive++;
+	       }
+               j = next_[j]; //onto next in set
+          }
+          if (numberActive > 1) {
+               int iRow = numberActiveSets_ + numberStaticRows_;
+               rowSolution[iRow] = 0.0;
+               double lowerValue;
+               if (lowerSet_[iSet] > -1.0e20)
+                    lowerValue = lowerSet_[iSet];
+               else
+                    lowerValue = -COIN_DBL_MAX;
+               double upperValue;
+               if (upperSet_[iSet] < 1.0e20)
+                    upperValue = upperSet_[iSet];
+               else
+                    upperValue = COIN_DBL_MAX;
+               rowLower[iRow] = lowerValue;
+               rowUpper[iRow] = upperValue;
+               if (getStatus(iSet) == ClpSimplex::basic) {
+                    model_->setRowStatus(iRow, ClpSimplex::basic);
+                    rowSolution[iRow] = 0.0;
+               } else if (getStatus(iSet) == ClpSimplex::atLowerBound) {
+                    model_->setRowStatus(iRow, ClpSimplex::atLowerBound);
+                    rowSolution[iRow] = lowerValue;
+               } else {
+                    model_->setRowStatus(iRow, ClpSimplex::atUpperBound);
+                    rowSolution[iRow] = upperValue;
+               }
+               j = startSet_[iSet];
+               while (j >= 0) {
+                    DynamicStatus status = getDynamicStatus(j);
+                    if (status == inSmall) {
+                         int numberThis = startColumn_[j+1] - startColumn_[j] + 1;
+                         if (numberElements + numberThis > numberElements_) {
+                              // need to redo
+                              numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis);
+                              matrix_->reserve(lastDynamic_, numberElements_);
+                              element =  matrix_->getMutableElements();
+                              row = matrix_->getMutableIndices();
+                              // these probably okay but be safe
+                              startColumn = matrix_->getMutableVectorStarts();
+                              length = matrix_->getMutableVectorLengths();
+                         }
+                         length[firstAvailable_] = numberThis;
+                         cost[firstAvailable_] = cost_[j];
+                         CoinBigIndex base = startColumn_[j];
+                         for (int k = 0; k < numberThis - 1; k++) {
+                              row[numberElements] = row_[base+k];
+                              element[numberElements++] = element_[base+k];
+                         }
+                         row[numberElements] = iRow;
+                         element[numberElements++] = 1.0;
+                         id_[firstAvailable_-firstDynamic_] = j;
+                         solution[firstAvailable_] = 0.0;
+                         model_->setStatus(firstAvailable_, ClpSimplex::basic);
+                         if (!columnLower_ && !columnUpper_) {
+                              columnLower[firstAvailable_] = 0.0;
+                              columnUpper[firstAvailable_] = COIN_DBL_MAX;
+                         }  else {
+                              if (columnLower_)
+                                   columnLower[firstAvailable_] = columnLower_[j];
+                              else
+                                   columnLower[firstAvailable_] = 0.0;
+                              if (columnUpper_)
+                                   columnUpper[firstAvailable_] = columnUpper_[j];
+                              else
+                                   columnUpper[firstAvailable_] = COIN_DBL_MAX;
+                              if (status != atUpperBound) {
+                                   solution[firstAvailable_] = columnLower[firstAvailable_];
+                              } else {
+                                   solution[firstAvailable_] = columnUpper[firstAvailable_];
+                              }
+                         }
+                         firstAvailable_++;
+                         startColumn[firstAvailable_] = numberElements;
+                    }
+                    j = next_[j]; //onto next in set
+               }
+               model_->setRowStatus(numberActiveSets_ + numberStaticRows_, getStatus(iSet));
+               toIndex_[iSet] = numberActiveSets_;
+               fromIndex_[numberActiveSets_++] = iSet;
+	  } else {
+	    // solo key
+	    bool needKey=false;
+	    if (numberActive) {
+	      if (whichKey<maximumGubColumns_) {
+		// structural - assume ok
+		needKey = false;
+	      } else {
+		// slack
+		keyVariable_[iSet] = maximumGubColumns_ + iSet;
+		double value = keyValue(iSet);
+		if (value<lowerSet_[iSet]-1.0e-8||
+		    value>upperSet_[iSet]+1.0e-8)
+		  needKey=true;
+	      }
+	    } else {
+	      needKey = true;
+	    }
+	    if (needKey) {
+	      // all to lb then up some (slack/null if possible)
+	      int length=99999999;
+	      int which=-1;
+	      double sum=0.0;
+	      for (int iColumn=startSet_[iSet];iColumn<startSet_[iSet+1];iColumn++) {
+		setDynamicStatus(iColumn,atLowerBound);
+		sum += columnLower_[iColumn];
+		if (length>startColumn_[iColumn+1]-startColumn_[iColumn]) {
+		  which=iColumn;
+		  length=startColumn_[iColumn+1]-startColumn_[iColumn];
+		}
+	      }
+	      if (sum>lowerSet_[iSet]-1.0e-8) {
+		// slack can be basic
+		setStatus(iSet,ClpSimplex::basic);
+		keyVariable_[iSet] = maximumGubColumns_ + iSet;
+	      } else {
+		// use shortest
+		setDynamicStatus(which,soloKey);
+		keyVariable_[iSet] = which;
+		setStatus(iSet,ClpSimplex::atLowerBound);
+	      }
+	    }
+          }
+          assert (toIndex_[iSet] >= 0 || whichKey >= 0);
+          keyVariable_[iSet] = whichKey;
+     }
+     // clean up pivotVariable
+     int numberColumns = model_->numberColumns();
+     int numberRows = model_->numberRows();
+     int * pivotVariable = model_->pivotVariable();
+     if (pivotVariable) {
+       for (int i=0; i<numberStaticRows_+numberActiveSets_;i++) {
+	 if (model_->getRowStatus(i)!=ClpSimplex::basic)
+	   pivotVariable[i]=-1;
+	 else
+	   pivotVariable[i]=numberColumns+i;
+       }
+       for (int i=numberStaticRows_+numberActiveSets_;i<numberRows;i++) {
+	 pivotVariable[i]=i+numberColumns;
+       }
+       int put=-1;
+       for (int i=0;i<numberColumns;i++) {
+	 if (model_->getColumnStatus(i)==ClpSimplex::basic) {
+	   while(put<numberRows) {
+	     put++;
+	     if (pivotVariable[put]==-1) {
+	       pivotVariable[put]=i;
+	       break;
+	     }
+	   }
+	 }
+       }
+       for (int i=CoinMax(put,0);i<numberRows;i++) {
+	 if (pivotVariable[i]==-1) 
+	   pivotVariable[i]=i+numberColumns;
+       }
+     }
+     if (rhsOffset_) {
+       double * cost = model_->costRegion();
+       double * columnLower = model_->lowerRegion();
+       double * columnUpper = model_->upperRegion();
+       double * solution = model_->solutionRegion();
+       int numberRows = model_->numberRows();
+       for (int i = numberActiveSets_; i < numberRows-numberStaticRows_; i++) {
+	 int iSequence = i + numberStaticRows_ + numberColumns;
+	 solution[iSequence] = 0.0;
+	 columnLower[iSequence] = -COIN_DBL_MAX;
+	 columnUpper[iSequence] = COIN_DBL_MAX;
+	 cost[iSequence] = 0.0;
+	 model_->nonLinearCost()->setOne(iSequence, solution[iSequence],
+					columnLower[iSequence],
+					columnUpper[iSequence], 0.0);
+	 model_->setStatus(iSequence, ClpSimplex::basic);
+	 rhsOffset_[i+numberStaticRows_] = 0.0;
+       }
+#if 0
+       for (int i=0;i<numberStaticRows_;i++)
+	 printf("%d offset %g\n",
+		i,rhsOffset_[i]);
+#endif
+     }
+     numberActiveColumns_ = firstAvailable_;
+#if 0
+     for (iSet = 0; iSet < numberSets_; iSet++) {
+       for (int j=startSet_[iSet];j<startSet_[iSet+1];j++) {
+	 if (getDynamicStatus(j)==soloKey)
+	   printf("%d in set %d is solo key\n",j,iSet);
+	 else if (getDynamicStatus(j)==inSmall)
+	   printf("%d in set %d is in small\n",j,iSet);
+       }
+     }
+#endif
+     return;
+}
+// Writes out model (without names)
+void 
+ClpDynamicMatrix::writeMps(const char * name)
+{
+  int numberTotalRows = numberStaticRows_+numberSets_;
+  int numberTotalColumns = firstDynamic_+numberGubColumns_;
+  // over estimate
+  int numberElements = getNumElements()+startColumn_[numberGubColumns_]
+    + numberGubColumns_;
+  double * columnLower = new double [numberTotalColumns];
+  double * columnUpper = new double [numberTotalColumns];
+  double * cost = new double [numberTotalColumns];
+  double * rowLower = new double [numberTotalRows];
+  double * rowUpper = new double [numberTotalRows];
+  CoinBigIndex * start = new CoinBigIndex[numberTotalColumns+1];
+  int * row = new int [numberElements];
+  double * element = new double [numberElements];
+  // Fill in
+  const CoinBigIndex * startA = getVectorStarts();
+  const int * lengthA = getVectorLengths();
+  const int * rowA = getIndices();
+  const double * elementA = getElements();
+  const double * columnLowerA = model_->columnLower();
+  const double * columnUpperA = model_->columnUpper();
+  const double * costA = model_->objective();
+  const double * rowLowerA = model_->rowLower();
+  const double * rowUpperA = model_->rowUpper();
+  start[0]=0;
+  numberElements=0;
+  for (int i=0;i<firstDynamic_;i++) {
+    columnLower[i] = columnLowerA[i];
+    columnUpper[i] = columnUpperA[i];
+    cost[i] = costA[i];
+    for (CoinBigIndex j = startA[i];j<startA[i]+lengthA[i];j++) {
+      row[numberElements] = rowA[j];
+      element[numberElements++]=elementA[j];
+    }
+    start[i+1]=numberElements;
+  }
+  for (int i=0;i<numberStaticRows_;i++) {
+    rowLower[i] = rowLowerA[i];
+    rowUpper[i] = rowUpperA[i];
+  }
+  int putC=firstDynamic_;
+  int putR=numberStaticRows_;
+  for (int i=0;i<numberSets_;i++) {
+    rowLower[putR]=lowerSet_[i];
+    rowUpper[putR]=upperSet_[i];
+    for (CoinBigIndex k=startSet_[i];k<startSet_[i+1];k++) {
+      columnLower[putC]=columnLower_[k];
+      columnUpper[putC]=columnUpper_[k];
+      cost[putC]=cost_[k];
+      putC++;
+      for (CoinBigIndex j = startColumn_[k];j<startColumn_[k+1];j++) {
+	row[numberElements] = row_[j];
+	element[numberElements++]=element_[j];
+      }
+      row[numberElements] = putR;
+      element[numberElements++]=1.0;
+      start[putC]=numberElements;
+    }
+    putR++;
+  }
+
+  assert (putR==numberTotalRows);
+  assert (putC==numberTotalColumns);
+  ClpSimplex modelOut;
+  modelOut.loadProblem(numberTotalColumns,numberTotalRows,
+		       start,row,element,
+		       columnLower,columnUpper,cost,
+		       rowLower,rowUpper);
+  modelOut.writeMps(name);
+  delete [] columnLower;
+  delete [] columnUpper;
+  delete [] cost;
+  delete [] rowLower;
+  delete [] rowUpper;
+  delete [] start;
+  delete [] row; 
+  delete [] element;
+}
+// Adds in a column to gub structure (called from descendant)
+int
+ClpDynamicMatrix::addColumn(int numberEntries, const int * row, const double * element,
+                            double cost, double lower, double upper, int iSet,
+                            DynamicStatus status)
+{
+     // check if already in
+     int j = startSet_[iSet];
+     while (j >= 0) {
+          if (startColumn_[j+1] - startColumn_[j] == numberEntries) {
+               const int * row2 = row_ + startColumn_[j];
+               const double * element2 = element_ + startColumn_[j];
+               bool same = true;
+               for (int k = 0; k < numberEntries; k++) {
+                    if (row[k] != row2[k] || element[k] != element2[k]) {
+                         same = false;
+                         break;
+                    }
+               }
+               if (same) {
+                    bool odd = false;
+                    if (cost != cost_[j])
+                         odd = true;
+                    if (columnLower_ && lower != columnLower_[j])
+                         odd = true;
+                    if (columnUpper_ && upper != columnUpper_[j])
+                         odd = true;
+                    if (odd) {
+                         printf("seems odd - same els but cost,lo,up are %g,%g,%g and %g,%g,%g\n",
+                                cost, lower, upper, cost_[j],
+                                columnLower_ ? columnLower_[j] : 0.0,
+                                columnUpper_ ? columnUpper_[j] : 1.0e100);
+                    } else {
+		         setDynamicStatus(j, status);
+                         return j;
+		    }
+               }
+          }
+          j = next_[j];
+     }
+
+     if (numberGubColumns_ == maximumGubColumns_ ||
+               startColumn_[numberGubColumns_] + numberEntries > maximumElements_) {
+          CoinBigIndex j;
+          int i;
+          int put = 0;
+          int numberElements = 0;
+          CoinBigIndex start = 0;
+          // compress - leave ones at ub and basic
+          int * which = new int [numberGubColumns_];
+          for (i = 0; i < numberGubColumns_; i++) {
+               CoinBigIndex end = startColumn_[i+1];
+	       // what about ubs if column generation?
+               if (getDynamicStatus(i) != atLowerBound) {
+                    // keep in
+                    for (j = start; j < end; j++) {
+                         row_[numberElements] = row_[j];
+                         element_[numberElements++] = element_[j];
+                    }
+                    startColumn_[put+1] = numberElements;
+                    cost_[put] = cost_[i];
+                    if (columnLower_)
+                         columnLower_[put] = columnLower_[i];
+                    if (columnUpper_)
+                         columnUpper_[put] = columnUpper_[i];
+                    dynamicStatus_[put] = dynamicStatus_[i];
+                    id_[put] = id_[i];
+                    which[i] = put;
+                    put++;
+               } else {
+                    // out
+                    which[i] = -1;
+               }
+               start = end;
+          }
+          // now redo startSet_ and next_
+          int * newNext = new int [maximumGubColumns_];
+          for (int jSet = 0; jSet < numberSets_; jSet++) {
+               int sequence = startSet_[jSet];
+               while (which[sequence] < 0) {
+                    // out
+                    assert (next_[sequence] >= 0);
+                    sequence = next_[sequence];
+               }
+               startSet_[jSet] = which[sequence];
+               int last = which[sequence];
+               while (next_[sequence] >= 0) {
+                    sequence = next_[sequence];
+                    if(which[sequence] >= 0) {
+                         // keep
+                         newNext[last] = which[sequence];
+                         last = which[sequence];
+                    }
+               }
+               newNext[last] = -jSet - 1;
+          }
+          delete [] next_;
+          next_ = newNext;
+          delete [] which;
+          abort();
+     }
+     CoinBigIndex start = startColumn_[numberGubColumns_];
+     CoinMemcpyN(row, numberEntries, row_ + start);
+     CoinMemcpyN(element, numberEntries, element_ + start);
+     startColumn_[numberGubColumns_+1] = start + numberEntries;
+     cost_[numberGubColumns_] = cost;
+     if (columnLower_)
+          columnLower_[numberGubColumns_] = lower;
+     else
+          assert (!lower);
+     if (columnUpper_)
+          columnUpper_[numberGubColumns_] = upper;
+     else
+          assert (upper > 1.0e20);
+     setDynamicStatus(numberGubColumns_, status);
+     // Do next_
+     j = startSet_[iSet];
+     startSet_[iSet] = numberGubColumns_;
+     next_[numberGubColumns_] = j;
+     numberGubColumns_++;
+     return numberGubColumns_ - 1;
+}
+// Returns which set a variable is in
+int
+ClpDynamicMatrix::whichSet (int sequence) const
+{
+     while (next_[sequence] >= 0)
+          sequence = next_[sequence];
+     int iSet = - next_[sequence] - 1;
+     return iSet;
+}
diff --git a/cbits/coin/ClpDynamicMatrix.hpp b/cbits/coin/ClpDynamicMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpDynamicMatrix.hpp
@@ -0,0 +1,381 @@
+/* $Id: ClpDynamicMatrix.hpp 1755 2011-06-28 18:24:31Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpDynamicMatrix_H
+#define ClpDynamicMatrix_H
+
+
+#include "CoinPragma.hpp"
+
+#include "ClpPackedMatrix.hpp"
+class ClpSimplex;
+/** This implements  a dynamic matrix when we have a limit on the number of
+    "interesting rows". This version inherits from ClpPackedMatrix and knows that
+    the real matrix is gub.  A later version could use shortest path to generate columns.
+
+*/
+
+class ClpDynamicMatrix : public ClpPackedMatrix {
+
+public:
+     /// enums for status of various sorts
+     enum DynamicStatus {
+          soloKey = 0x00,
+          inSmall = 0x01,
+          atUpperBound = 0x02,
+          atLowerBound = 0x03
+     };
+     /**@name Main functions provided */
+     //@{
+     /// Partial pricing
+     virtual void partialPricing(ClpSimplex * model, double start, double end,
+                                 int & bestSequence, int & numberWanted);
+
+     /**
+        update information for a pivot (and effective rhs)
+     */
+     virtual int updatePivot(ClpSimplex * model, double oldInValue, double oldOutValue);
+     /** Returns effective RHS offset if it is being used.  This is used for long problems
+         or big dynamic or anywhere where going through full columns is
+         expensive.  This may re-compute */
+     virtual double * rhsOffset(ClpSimplex * model, bool forceRefresh = false,
+                                bool check = false);
+
+     using ClpPackedMatrix::times ;
+     /** Return <code>y + A * scalar *x</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numColumns()</code>
+         @pre <code>y</code> must be of size <code>numRows()</code> */
+     virtual void times(double scalar,
+                        const double * x, double * y) const;
+     /// Modifies rhs offset
+     void modifyOffset(int sequence, double amount);
+     /// Gets key value when none in small
+     double keyValue(int iSet) const;
+     /**
+         mode=0  - Set up before "updateTranspose" and "transposeTimes" for duals using extended
+                   updates array (and may use other if dual values pass)
+         mode=1  - Update dual solution after "transposeTimes" using extended rows.
+         mode=2  - Compute all djs and compute key dual infeasibilities
+         mode=3  - Report on key dual infeasibilities
+         mode=4  - Modify before updateTranspose in partial pricing
+     */
+     virtual void dualExpanded(ClpSimplex * model, CoinIndexedVector * array,
+                               double * other, int mode);
+     /**
+         mode=0  - Create list of non-key basics in pivotVariable_ using
+                   number as numberBasic in and out
+         mode=1  - Set all key variables as basic
+         mode=2  - return number extra rows needed, number gives maximum number basic
+         mode=3  - before replaceColumn
+         mode=4  - return 1 if can do primal, 2 if dual, 3 if both
+         mode=5  - save any status stuff (when in good state)
+         mode=6  - restore status stuff
+         mode=7  - flag given variable (normally sequenceIn)
+         mode=8  - unflag all variables
+         mode=9  - synchronize costs
+         mode=10  - return 1 if there may be changing bounds on variable (column generation)
+         mode=11  - make sure set is clean (used when a variable rejected - but not flagged)
+         mode=12  - after factorize but before permute stuff
+         mode=13  - at end of simplex to delete stuff
+     */
+     virtual int generalExpanded(ClpSimplex * model, int mode, int & number);
+     /** Purely for column generation and similar ideas.  Allows
+         matrix and any bounds or costs to be updated (sensibly).
+         Returns non-zero if any changes.
+     */
+     virtual int refresh(ClpSimplex * model);
+     /** Creates a variable.  This is called after partial pricing and will modify matrix.
+         Will update bestSequence.
+     */
+     virtual void createVariable(ClpSimplex * model, int & bestSequence);
+     /// Returns reduced cost of a variable
+     virtual double reducedCost( ClpSimplex * model, int sequence) const;
+     /// Does gub crash
+     void gubCrash();
+     /// Writes out model (without names)
+     void writeMps(const char * name);
+     /// Populates initial matrix from dynamic status
+     void initialProblem();
+     /** Adds in a column to gub structure (called from descendant) and returns sequence */
+     int addColumn(int numberEntries, const int * row, const double * element,
+                   double cost, double lower, double upper, int iSet,
+                   DynamicStatus status);
+     /** If addColumn forces compression then this allows descendant to know what to do.
+         If >=0 then entry stayed in, if -1 then entry went out to lower bound.of zero.
+         Entries at upper bound (really nonzero) never go out (at present).
+     */
+     virtual void packDown(const int * , int ) {}
+     /// Gets lower bound (to simplify coding)
+     inline double columnLower(int sequence) const {
+          if (columnLower_) return columnLower_[sequence];
+          else return 0.0;
+     }
+     /// Gets upper bound (to simplify coding)
+     inline double columnUpper(int sequence) const {
+          if (columnUpper_) return columnUpper_[sequence];
+          else return COIN_DBL_MAX;
+     }
+
+     //@}
+
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpDynamicMatrix();
+     /** This is the real constructor.
+         It assumes factorization frequency will not be changed.
+         This resizes model !!!!
+         The contents of original matrix in model will be taken over and original matrix
+         will be sanitized so can be deleted (to avoid a very small memory leak)
+      */
+     ClpDynamicMatrix(ClpSimplex * model, int numberSets,
+                      int numberColumns, const int * starts,
+                      const double * lower, const double * upper,
+                      const CoinBigIndex * startColumn, const int * row,
+                      const double * element, const double * cost,
+                      const double * columnLower = NULL, const double * columnUpper = NULL,
+                      const unsigned char * status = NULL,
+                      const unsigned char * dynamicStatus = NULL);
+
+     /** Destructor */
+     virtual ~ClpDynamicMatrix();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpDynamicMatrix(const ClpDynamicMatrix&);
+     /** The copy constructor from an CoinPackedMatrix. */
+     ClpDynamicMatrix(const CoinPackedMatrix&);
+
+     ClpDynamicMatrix& operator=(const ClpDynamicMatrix&);
+     /// Clone
+     virtual ClpMatrixBase * clone() const ;
+     //@}
+     /**@name gets and sets */
+     //@{
+     /// Status of row slacks
+     inline ClpSimplex::Status getStatus(int sequence) const {
+          return static_cast<ClpSimplex::Status> (status_[sequence] & 7);
+     }
+     inline void setStatus(int sequence, ClpSimplex::Status status) {
+          unsigned char & st_byte = status_[sequence];
+          st_byte = static_cast<unsigned char>(st_byte & ~7);
+          st_byte = static_cast<unsigned char>(st_byte | status);
+     }
+     /// Whether flagged slack
+     inline bool flaggedSlack(int i) const {
+          return (status_[i] & 8) != 0;
+     }
+     inline void setFlaggedSlack(int i) {
+          status_[i] = static_cast<unsigned char>(status_[i] | 8);
+     }
+     inline void unsetFlaggedSlack(int i) {
+          status_[i] = static_cast<unsigned char>(status_[i] & ~8);
+     }
+     /// Number of sets (dynamic rows)
+     inline int numberSets() const {
+          return numberSets_;
+     }
+     /// Number of possible gub variables
+     inline int numberGubEntries() const
+     { return startSet_[numberSets_];}
+     /// Sets
+     inline int * startSets() const
+     { return startSet_;}
+     /// Whether flagged
+     inline bool flagged(int i) const {
+          return (dynamicStatus_[i] & 8) != 0;
+     }
+     inline void setFlagged(int i) {
+          dynamicStatus_[i] = static_cast<unsigned char>(dynamicStatus_[i] | 8);
+     }
+     inline void unsetFlagged(int i) {
+          dynamicStatus_[i] = static_cast<unsigned char>(dynamicStatus_[i] & ~8);
+     }
+     inline void setDynamicStatus(int sequence, DynamicStatus status) {
+          unsigned char & st_byte = dynamicStatus_[sequence];
+          st_byte = static_cast<unsigned char>(st_byte & ~7);
+          st_byte = static_cast<unsigned char>(st_byte | status);
+     }
+     inline DynamicStatus getDynamicStatus(int sequence) const {
+          return static_cast<DynamicStatus> (dynamicStatus_[sequence] & 7);
+     }
+     /// Saved value of objective offset
+     inline double objectiveOffset() const {
+          return objectiveOffset_;
+     }
+     /// Starts of each column
+     inline CoinBigIndex * startColumn() const {
+          return startColumn_;
+     }
+     /// rows
+     inline int * row() const {
+          return row_;
+     }
+     /// elements
+     inline double * element() const {
+          return element_;
+     }
+     /// costs
+     inline double * cost() const {
+          return cost_;
+     }
+     /// ids of active columns (just index here)
+     inline int * id() const {
+          return id_;
+     }
+     /// Optional lower bounds on columns
+     inline double * columnLower() const {
+          return columnLower_;
+     }
+     /// Optional upper bounds on columns
+     inline double * columnUpper() const {
+          return columnUpper_;
+     }
+     /// Lower bounds on sets
+     inline double * lowerSet() const {
+          return lowerSet_;
+     }
+     /// Upper bounds on sets
+     inline double * upperSet() const {
+          return upperSet_;
+     }
+     /// size
+     inline int numberGubColumns() const {
+          return numberGubColumns_;
+     }
+     /// first free
+     inline int firstAvailable() const {
+          return firstAvailable_;
+     }
+     /// first dynamic
+     inline int firstDynamic() const {
+          return firstDynamic_;
+     }
+     /// number of columns in dynamic model
+     inline int lastDynamic() const {
+          return lastDynamic_;
+     }
+     /// number of rows in original model
+     inline int numberStaticRows() const {
+          return numberStaticRows_;
+     }
+     /// size of working matrix (max)
+     inline int numberElements() const {
+          return numberElements_;
+     }
+     inline int * keyVariable() const {
+          return keyVariable_;
+     }
+     /// Switches off dj checking each factorization (for BIG models)
+     void switchOffCheck();
+     /// Status region for gub slacks
+     inline unsigned char * gubRowStatus() const {
+          return status_;
+     }
+     /// Status region for gub variables
+     inline unsigned char * dynamicStatus() const {
+          return dynamicStatus_;
+     }
+     /// Returns which set a variable is in
+     int whichSet (int sequence) const;
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Sum of dual infeasibilities
+     double sumDualInfeasibilities_;
+     /// Sum of primal infeasibilities
+     double sumPrimalInfeasibilities_;
+     /// Sum of Dual infeasibilities using tolerance based on error in duals
+     double sumOfRelaxedDualInfeasibilities_;
+     /// Sum of Primal infeasibilities using tolerance based on error in primals
+     double sumOfRelaxedPrimalInfeasibilities_;
+     /// Saved best dual on gub row in pricing
+     double savedBestGubDual_;
+     /// Saved best set in pricing
+     int savedBestSet_;
+     /// Backward pointer to pivot row !!!
+     int * backToPivotRow_;
+     /// Key variable of set (only accurate if none in small problem)
+     mutable int * keyVariable_;
+     /// Backward pointer to extra row
+     int * toIndex_;
+     // Reverse pointer from index to set
+     int * fromIndex_;
+     /// Number of sets (dynamic rows)
+     int numberSets_;
+     /// Number of active sets
+     int numberActiveSets_;
+     /// Saved value of objective offset
+     double objectiveOffset_;
+     /// Lower bounds on sets
+     double * lowerSet_;
+     /// Upper bounds on sets
+     double * upperSet_;
+     /// Status of slack on set
+     unsigned char * status_;
+     /// Pointer back to model
+     ClpSimplex * model_;
+     /// first free
+     int firstAvailable_;
+     /// first free when iteration started
+     int firstAvailableBefore_;
+     /// first dynamic
+     int firstDynamic_;
+     /// number of columns in dynamic model
+     int lastDynamic_;
+     /// number of rows in original model
+     int numberStaticRows_;
+     /// size of working matrix (max)
+     int numberElements_;
+     /// Number of dual infeasibilities
+     int numberDualInfeasibilities_;
+     /// Number of primal infeasibilities
+     int numberPrimalInfeasibilities_;
+     /** If pricing will declare victory (i.e. no check every factorization).
+         -1 - always check
+         0  - don't check
+         1  - in don't check mode but looks optimal
+     */
+     int noCheck_;
+     /// Infeasibility weight when last full pass done
+     double infeasibilityWeight_;
+     /// size
+     int numberGubColumns_;
+     /// current maximum number of columns (then compress)
+     int maximumGubColumns_;
+     /// current maximum number of elemnts (then compress)
+     int maximumElements_;
+     /// Start of each set
+     int * startSet_;
+     /// next in chain
+     int * next_;
+     /// Starts of each column
+     CoinBigIndex * startColumn_;
+     /// rows
+     int * row_;
+     /// elements
+     double * element_;
+     /// costs
+     double * cost_;
+     /// ids of active columns (just index here)
+     int * id_;
+     /// for status and which bound
+     unsigned char * dynamicStatus_;
+     /// Optional lower bounds on columns
+     double * columnLower_;
+     /// Optional upper bounds on columns
+     double * columnUpper_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpEventHandler.cpp b/cbits/coin/ClpEventHandler.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpEventHandler.cpp
@@ -0,0 +1,131 @@
+/* $Id: ClpEventHandler.cpp 1825 2011-11-20 16:02:57Z forrest $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include "ClpEventHandler.hpp"
+#include "ClpSimplex.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpEventHandler::ClpEventHandler (ClpSimplex * model) :
+     model_(model)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpEventHandler::ClpEventHandler (const ClpEventHandler & rhs)
+     : model_(rhs.model_)
+{
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpEventHandler::~ClpEventHandler ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpEventHandler &
+ClpEventHandler::operator=(const ClpEventHandler& rhs)
+{
+     if (this != &rhs) {
+          model_ = rhs.model_;
+     }
+     return *this;
+}
+// Clone
+ClpEventHandler *
+ClpEventHandler::clone() const
+{
+     return new ClpEventHandler(*this);
+}
+// Event
+int
+ClpEventHandler::event(Event whichEvent)
+{
+     if (whichEvent != theta)
+          return -1; // do nothing
+     else
+          return 0; // say normal exit
+}
+/* This can do whatever it likes.  Return code -1 means no action.
+   This passes in something
+*/
+int 
+ClpEventHandler::eventWithInfo(Event whichEvent, void * info) 
+{ 
+  return -1;
+}
+/* set model. */
+void
+ClpEventHandler::setSimplex(ClpSimplex * model)
+{
+     model_ = model;
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpDisasterHandler::ClpDisasterHandler (ClpSimplex * model) :
+     model_(model)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpDisasterHandler::ClpDisasterHandler (const ClpDisasterHandler & rhs)
+     : model_(rhs.model_)
+{
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpDisasterHandler::~ClpDisasterHandler ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpDisasterHandler &
+ClpDisasterHandler::operator=(const ClpDisasterHandler& rhs)
+{
+     if (this != &rhs) {
+          model_ = rhs.model_;
+     }
+     return *this;
+}
+/* set model. */
+void
+ClpDisasterHandler::setSimplex(ClpSimplex * model)
+{
+     model_ = model;
+}
+// Type of disaster 0 can fix, 1 abort
+int
+ClpDisasterHandler::typeOfDisaster()
+{
+     return 0;
+}
+
+
diff --git a/cbits/coin/ClpEventHandler.hpp b/cbits/coin/ClpEventHandler.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpEventHandler.hpp
@@ -0,0 +1,186 @@
+/* $Id: ClpEventHandler.hpp 1825 2011-11-20 16:02:57Z forrest $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpEventHandler_H
+#define ClpEventHandler_H
+
+#include "ClpSimplex.hpp"
+/** Base class for Clp event handling
+
+This is just here to allow for event handling.  By event I mean a Clp event
+e.g. end of values pass.
+
+One use would be to let a user handle a system event e.g. Control-C.  This could be done
+by deriving a class MyEventHandler which knows about such events.  If one occurs
+MyEventHandler::event() could clear event status and return 3 (stopped).
+
+Clp would then return to user code.
+
+As it is called every iteration this should be fine grained enough.
+
+User can derive and construct from CbcModel  - not pretty
+
+*/
+
+class ClpEventHandler  {
+
+public:
+     /** enums for what sort of event.
+
+         These will also be returned in ClpModel::secondaryStatus() as int
+     */
+     enum Event {
+          endOfIteration = 100, // used to set secondary status
+          endOfFactorization, // after gutsOfSolution etc
+          endOfValuesPass,
+          node, // for Cbc
+          treeStatus, // for Cbc
+          solution, // for Cbc
+          theta, // hit in parametrics
+          pivotRow, // used to choose pivot row
+	  presolveStart, // ClpSolve presolve start
+	  presolveSize, // sees if ClpSolve presolve too big or too small
+	  presolveInfeasible, // ClpSolve presolve infeasible
+	  presolveBeforeSolve, // ClpSolve presolve before solve
+	  presolveAfterFirstSolve, // ClpSolve presolve after solve
+	  presolveAfterSolve, // ClpSolve presolve after solve
+	  presolveEnd, // ClpSolve presolve end
+	  goodFactorization, // before gutsOfSolution
+	  complicatedPivotIn, // in modifyCoefficients
+	  noCandidateInPrimal, // tentative end
+	  looksEndInPrimal, // About to declare victory (or defeat)
+	  endInPrimal, // Victory (or defeat)
+	  beforeStatusOfProblemInPrimal,
+	  startOfStatusOfProblemInPrimal,
+	  complicatedPivotOut, // in modifyCoefficients
+	  noCandidateInDual, // tentative end
+	  looksEndInDual, // About to declare victory (or defeat)
+	  endInDual, // Victory (or defeat)
+	  beforeStatusOfProblemInDual,
+	  startOfStatusOfProblemInDual,
+	  startOfIterationInDual,
+	  updateDualsInDual,
+	  endOfCreateRim,
+	  slightlyInfeasible,
+	  modifyMatrixInMiniPresolve,
+	  moreMiniPresolve,
+	  modifyMatrixInMiniPostsolve,
+	  noTheta // At end (because no pivot)
+     };
+     /**@name Virtual method that the derived classes should provide.
+      The base class instance does nothing and as event() is only useful method
+      it would not be very useful NOT providing one!
+     */
+     //@{
+     /** This can do whatever it likes.  If return code -1 then carries on
+         if 0 sets ClpModel::status() to 5 (stopped by event) and will return to user.
+         At present if <-1 carries on and if >0 acts as if 0 - this may change.
+	 For ClpSolve 2 -> too big return status of -2 and -> too small 3
+     */
+     virtual int event(Event whichEvent);
+     /** This can do whatever it likes.  Return code -1 means no action.
+	 This passes in something
+     */
+     virtual int eventWithInfo(Event whichEvent, void * info) ;
+     //@}
+
+
+     /**@name Constructors, destructor */
+
+     //@{
+     /** Default constructor. */
+     ClpEventHandler(ClpSimplex * model = NULL);
+     /** Destructor */
+     virtual ~ClpEventHandler();
+     // Copy
+     ClpEventHandler(const ClpEventHandler&);
+     // Assignment
+     ClpEventHandler& operator=(const ClpEventHandler&);
+     /// Clone
+     virtual ClpEventHandler * clone() const;
+
+     //@}
+
+     /**@name Sets/gets */
+
+     //@{
+     /** set model. */
+     void setSimplex(ClpSimplex * model);
+     /// Get model
+     inline ClpSimplex * simplex() const {
+          return model_;
+     }
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Pointer to simplex
+     ClpSimplex * model_;
+     //@}
+};
+/** Base class for Clp disaster handling
+
+This is here to allow for disaster handling.  By disaster I mean that Clp
+would otherwise give up
+
+*/
+
+class ClpDisasterHandler  {
+
+public:
+     /**@name Virtual methods that the derived classe should provide.
+     */
+     //@{
+     /// Into simplex
+     virtual void intoSimplex() = 0;
+     /// Checks if disaster
+     virtual bool check() const = 0;
+     /// saves information for next attempt
+     virtual void saveInfo() = 0;
+     /// Type of disaster 0 can fix, 1 abort
+     virtual int typeOfDisaster();
+     //@}
+
+
+     /**@name Constructors, destructor */
+
+     //@{
+     /** Default constructor. */
+     ClpDisasterHandler(ClpSimplex * model = NULL);
+     /** Destructor */
+     virtual ~ClpDisasterHandler();
+     // Copy
+     ClpDisasterHandler(const ClpDisasterHandler&);
+     // Assignment
+     ClpDisasterHandler& operator=(const ClpDisasterHandler&);
+     /// Clone
+     virtual ClpDisasterHandler * clone() const = 0;
+
+     //@}
+
+     /**@name Sets/gets */
+
+     //@{
+     /** set model. */
+     void setSimplex(ClpSimplex * model);
+     /// Get model
+     inline ClpSimplex * simplex() const {
+          return model_;
+     }
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Pointer to simplex
+     ClpSimplex * model_;
+     //@}
+};
+#endif
diff --git a/cbits/coin/ClpFactorization.cpp b/cbits/coin/ClpFactorization.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpFactorization.cpp
@@ -0,0 +1,2872 @@
+/* $Id: ClpFactorization.cpp 1903 2013-01-03 22:49:30Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpFactorization.hpp"
+#ifndef SLIM_CLP
+#include "ClpQuadraticObjective.hpp"
+#endif
+#include "CoinHelperFunctions.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpSimplexDual.hpp"
+#include "ClpMatrixBase.hpp"
+#ifndef SLIM_CLP
+#include "ClpNetworkBasis.hpp"
+#include "ClpNetworkMatrix.hpp"
+//#define CHECK_NETWORK
+#ifdef CHECK_NETWORK
+const static bool doCheck = true;
+#else
+const static bool doCheck = false;
+#endif
+#endif
+//#define CLP_FACTORIZATION_INSTRUMENT
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+#include "CoinTime.hpp"
+double factorization_instrument(int type)
+{
+     static int times[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+     static double startTime = 0.0;
+     static double totalTimes [10] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
+     if (type < 0) {
+          assert (!startTime);
+          startTime = CoinCpuTime();
+          return 0.0;
+     } else if (type > 0) {
+          times[type]++;
+          double difference = CoinCpuTime() - startTime;
+          totalTimes[type] += difference;
+          startTime = 0.0;
+          return difference;
+     } else {
+          // report
+          const char * types[10] = {
+               "", "fac=rhs_etc", "factorize", "replace", "update_FT",
+               "update", "update_transpose", "gosparse", "getWeights!", "update2_FT"
+          };
+          double total = 0.0;
+          for (int i = 1; i < 10; i++) {
+               if (times[i]) {
+                    printf("%s was called %d times taking %g seconds\n",
+                           types[i], times[i], totalTimes[i]);
+                    total += totalTimes[i];
+                    times[i] = 0;
+                    totalTimes[i] = 0.0;
+               }
+          }
+          return total;
+     }
+}
+#endif
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+#ifndef CLP_MULTIPLE_FACTORIZATIONS
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpFactorization::ClpFactorization () :
+     CoinFactorization()
+{
+#ifndef SLIM_CLP
+     networkBasis_ = NULL;
+#endif
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpFactorization::ClpFactorization (const ClpFactorization & rhs,
+                                    int dummyDenseIfSmaller) :
+     CoinFactorization(rhs)
+{
+#ifndef SLIM_CLP
+     if (rhs.networkBasis_)
+          networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
+     else
+          networkBasis_ = NULL;
+#endif
+}
+
+ClpFactorization::ClpFactorization (const CoinFactorization & rhs) :
+     CoinFactorization(rhs)
+{
+#ifndef SLIM_CLP
+     networkBasis_ = NULL;
+#endif
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpFactorization::~ClpFactorization ()
+{
+#ifndef SLIM_CLP
+     delete networkBasis_;
+#endif
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpFactorization &
+ClpFactorization::operator=(const ClpFactorization& rhs)
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+     if (this != &rhs) {
+          CoinFactorization::operator=(rhs);
+#ifndef SLIM_CLP
+          delete networkBasis_;
+          if (rhs.networkBasis_)
+               networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
+          else
+               networkBasis_ = NULL;
+#endif
+     }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(1);
+#endif
+     return *this;
+}
+#if 0
+static unsigned int saveList[10000];
+int numberSave = -1;
+inline bool isDense(int i)
+{
+     return ((saveList[i>>5] >> (i & 31)) & 1) != 0;
+}
+inline void setDense(int i)
+{
+     unsigned int & value = saveList[i>>5];
+     int bit = i & 31;
+     value |= (1 << bit);
+}
+#endif
+int
+ClpFactorization::factorize ( ClpSimplex * model,
+                              int solveType, bool valuesPass)
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+     ClpMatrixBase * matrix = model->clpMatrix();
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     if (!numberRows)
+          return 0;
+     // If too many compressions increase area
+     if (numberPivots_ > 1 && numberCompressions_ * 10 > numberPivots_ + 10) {
+          areaFactor_ *= 1.1;
+     }
+     //int numberPivots=numberPivots_;
+#if 0
+     if (model->algorithm() > 0)
+          numberSave = -1;
+#endif
+#ifndef SLIM_CLP
+     if (!networkBasis_ || doCheck) {
+#endif
+          status_ = -99;
+          int * pivotVariable = model->pivotVariable();
+          //returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
+          while (status_ < -98) {
+
+               int i;
+               int numberBasic = 0;
+               int numberRowBasic;
+               // Move pivot variables across if they look good
+               int * pivotTemp = model->rowArray(0)->getIndices();
+               assert (!model->rowArray(0)->getNumElements());
+               if (!matrix->rhsOffset(model)) {
+#if 0
+                    if (numberSave > 0) {
+                         int nStill = 0;
+                         int nAtBound = 0;
+                         int nZeroDual = 0;
+                         CoinIndexedVector * array = model->rowArray(3);
+                         CoinIndexedVector * objArray = model->columnArray(1);
+                         array->clear();
+                         objArray->clear();
+                         double * cost = model->costRegion();
+                         double tolerance = model->primalTolerance();
+                         double offset = 0.0;
+                         for (i = 0; i < numberRows; i++) {
+                              int iPivot = pivotVariable[i];
+                              if (iPivot < numberColumns && isDense(iPivot)) {
+                                   if (model->getColumnStatus(iPivot) == ClpSimplex::basic) {
+                                        nStill++;
+                                        double value = model->solutionRegion()[iPivot];
+                                        double dual = model->dualRowSolution()[i];
+                                        double lower = model->lowerRegion()[iPivot];
+                                        double upper = model->upperRegion()[iPivot];
+                                        ClpSimplex::Status status;
+                                        if (fabs(value - lower) < tolerance) {
+                                             status = ClpSimplex::atLowerBound;
+                                             nAtBound++;
+                                        } else if (fabs(value - upper) < tolerance) {
+                                             nAtBound++;
+                                             status = ClpSimplex::atUpperBound;
+                                        } else if (value > lower && value < upper) {
+                                             status = ClpSimplex::superBasic;
+                                        } else {
+                                             status = ClpSimplex::basic;
+                                        }
+                                        if (status != ClpSimplex::basic) {
+                                             if (model->getRowStatus(i) != ClpSimplex::basic) {
+                                                  model->setColumnStatus(iPivot, ClpSimplex::atLowerBound);
+                                                  model->setRowStatus(i, ClpSimplex::basic);
+                                                  pivotVariable[i] = i + numberColumns;
+                                                  model->dualRowSolution()[i] = 0.0;
+                                                  model->djRegion(0)[i] = 0.0;
+                                                  array->add(i, dual);
+                                                  offset += dual * model->solutionRegion(0)[i];
+                                             }
+                                        }
+                                        if (fabs(dual) < 1.0e-5)
+                                             nZeroDual++;
+                                   }
+                              }
+                         }
+                         printf("out of %d dense, %d still in basis, %d at bound, %d with zero dual - offset %g\n",
+                                numberSave, nStill, nAtBound, nZeroDual, offset);
+                         if (array->getNumElements()) {
+                              // modify costs
+                              model->clpMatrix()->transposeTimes(model, 1.0, array, model->columnArray(0),
+                                                                 objArray);
+                              array->clear();
+                              int n = objArray->getNumElements();
+                              int * indices = objArray->getIndices();
+                              double * elements = objArray->denseVector();
+                              for (i = 0; i < n; i++) {
+                                   int iColumn = indices[i];
+                                   cost[iColumn] -= elements[iColumn];
+                                   elements[iColumn] = 0.0;
+                              }
+                              objArray->setNumElements(0);
+                         }
+                    }
+#endif
+                    // Seems to prefer things in order so quickest
+                    // way is to go though like this
+                    for (i = 0; i < numberRows; i++) {
+                         if (model->getRowStatus(i) == ClpSimplex::basic)
+                              pivotTemp[numberBasic++] = i;
+                    }
+                    numberRowBasic = numberBasic;
+                    /* Put column basic variables into pivotVariable
+                       This is done by ClpMatrixBase to allow override for gub
+                    */
+                    matrix->generalExpanded(model, 0, numberBasic);
+               } else {
+                    // Long matrix - do a different way
+                    bool fullSearch = false;
+                    for (i = 0; i < numberRows; i++) {
+                         int iPivot = pivotVariable[i];
+                         if (iPivot >= numberColumns) {
+                              pivotTemp[numberBasic++] = iPivot - numberColumns;
+                         }
+                    }
+                    numberRowBasic = numberBasic;
+                    for (i = 0; i < numberRows; i++) {
+                         int iPivot = pivotVariable[i];
+                         if (iPivot < numberColumns) {
+                              if (iPivot >= 0) {
+                                   pivotTemp[numberBasic++] = iPivot;
+                              } else {
+                                   // not full basis
+                                   fullSearch = true;
+                                   break;
+                              }
+                         }
+                    }
+                    if (fullSearch) {
+                         // do slow way
+                         numberBasic = 0;
+                         for (i = 0; i < numberRows; i++) {
+                              if (model->getRowStatus(i) == ClpSimplex::basic)
+                                   pivotTemp[numberBasic++] = i;
+                         }
+                         numberRowBasic = numberBasic;
+                         /* Put column basic variables into pivotVariable
+                            This is done by ClpMatrixBase to allow override for gub
+                         */
+                         matrix->generalExpanded(model, 0, numberBasic);
+                    }
+               }
+               if (numberBasic > model->maximumBasic()) {
+#if 0 // ndef NDEBUG
+                    printf("%d basic - should only be %d\n",
+                           numberBasic, numberRows);
+#endif
+                    // Take out some
+                    numberBasic = numberRowBasic;
+                    for (int i = 0; i < numberColumns; i++) {
+                         if (model->getColumnStatus(i) == ClpSimplex::basic) {
+                              if (numberBasic < numberRows)
+                                   numberBasic++;
+                              else
+                                   model->setColumnStatus(i, ClpSimplex::superBasic);
+                         }
+                    }
+                    numberBasic = numberRowBasic;
+                    matrix->generalExpanded(model, 0, numberBasic);
+               }
+#ifndef SLIM_CLP
+               // see if matrix a network
+#ifndef NO_RTTI
+               ClpNetworkMatrix* networkMatrix =
+                    dynamic_cast< ClpNetworkMatrix*>(model->clpMatrix());
+#else
+               ClpNetworkMatrix* networkMatrix = NULL;
+               if (model->clpMatrix()->type() == 11)
+                    networkMatrix =
+                         static_cast< ClpNetworkMatrix*>(model->clpMatrix());
+#endif
+               // If network - still allow ordinary factorization first time for laziness
+               if (networkMatrix)
+                    biasLU_ = 0; // All to U if network
+               //int saveMaximumPivots = maximumPivots();
+               delete networkBasis_;
+               networkBasis_ = NULL;
+               if (networkMatrix && !doCheck)
+                    maximumPivots(1);
+#endif
+               //printf("L, U, R %d %d %d\n",numberElementsL(),numberElementsU(),numberElementsR());
+               while (status_ == -99) {
+                    // maybe for speed will be better to leave as many regions as possible
+                    gutsOfDestructor();
+                    gutsOfInitialize(2);
+                    CoinBigIndex numberElements = numberRowBasic;
+
+                    // compute how much in basis
+
+                    int i;
+                    // can change for gub
+                    int numberColumnBasic = numberBasic - numberRowBasic;
+
+                    numberElements += matrix->countBasis(model,
+                                                         pivotTemp + numberRowBasic,
+                                                         numberRowBasic,
+                                                         numberColumnBasic);
+                    // and recompute as network side say different
+                    if (model->numberIterations())
+                         numberRowBasic = numberBasic - numberColumnBasic;
+                    numberElements = 3 * numberBasic + 3 * numberElements + 20000;
+#if 0
+                    // If iteration not zero then may be compressed
+                    getAreas ( !model->numberIterations() ? numberRows : numberBasic,
+                               numberRowBasic + numberColumnBasic, numberElements,
+                               2 * numberElements );
+#else
+                    getAreas ( numberRows,
+                               numberRowBasic + numberColumnBasic, numberElements,
+                               2 * numberElements );
+#endif
+                    //fill
+                    // Fill in counts so we can skip part of preProcess
+                    int * numberInRow = numberInRow_.array();
+                    int * numberInColumn = numberInColumn_.array();
+                    CoinZeroN ( numberInRow, numberRows_ + 1 );
+                    CoinZeroN ( numberInColumn, maximumColumnsExtra_ + 1 );
+                    double * elementU = elementU_.array();
+                    int * indexRowU = indexRowU_.array();
+                    CoinBigIndex * startColumnU = startColumnU_.array();
+                    for (i = 0; i < numberRowBasic; i++) {
+                         int iRow = pivotTemp[i];
+                         indexRowU[i] = iRow;
+                         startColumnU[i] = i;
+                         elementU[i] = slackValue_;
+                         numberInRow[iRow] = 1;
+                         numberInColumn[i] = 1;
+                    }
+                    startColumnU[numberRowBasic] = numberRowBasic;
+                    // can change for gub so redo
+                    numberColumnBasic = numberBasic - numberRowBasic;
+                    matrix->fillBasis(model,
+                                      pivotTemp + numberRowBasic,
+                                      numberColumnBasic,
+                                      indexRowU,
+                                      startColumnU + numberRowBasic,
+                                      numberInRow,
+                                      numberInColumn + numberRowBasic,
+                                      elementU);
+#if 0
+                    {
+                         printf("%d row basic, %d column basic\n", numberRowBasic, numberColumnBasic);
+                         for (int i = 0; i < numberElements; i++)
+                              printf("row %d col %d value %g\n", indexRowU_.array()[i], indexColumnU_[i],
+                                     elementU_.array()[i]);
+                    }
+#endif
+                    // recompute number basic
+                    numberBasic = numberRowBasic + numberColumnBasic;
+                    if (numberBasic)
+                         numberElements = startColumnU[numberBasic-1]
+                                          + numberInColumn[numberBasic-1];
+                    else
+                         numberElements = 0;
+                    lengthU_ = numberElements;
+                    //saveFactorization("dump.d");
+                    if (biasLU_ >= 3 || numberRows_ != numberColumns_)
+                         preProcess ( 2 );
+                    else
+                         preProcess ( 3 ); // no row copy
+                    factor (  );
+                    if (status_ == -99) {
+                         // get more memory
+                         areaFactor(2.0 * areaFactor());
+                    } else if (status_ == -1 && model->numberIterations() == 0 &&
+                               denseThreshold_) {
+                         // Round again without dense
+                         denseThreshold_ = 0;
+                         status_ = -99;
+                    }
+               }
+               // If we get here status is 0 or -1
+               if (status_ == 0) {
+                    // We may need to tamper with order and redo - e.g. network with side
+                    int useNumberRows = numberRows;
+                    // **** we will also need to add test in dual steepest to do
+                    // as we do for network
+                    matrix->generalExpanded(model, 12, useNumberRows);
+                    const int * permuteBack = permuteBack_.array();
+                    const int * back = pivotColumnBack_.array();
+                    //int * pivotTemp = pivotColumn_.array();
+                    //ClpDisjointCopyN ( pivotVariable, numberRows , pivotTemp  );
+                    // Redo pivot order
+                    for (i = 0; i < numberRowBasic; i++) {
+                         int k = pivotTemp[i];
+                         // so rowIsBasic[k] would be permuteBack[back[i]]
+                         pivotVariable[permuteBack[back[i]]] = k + numberColumns;
+                    }
+                    for (; i < useNumberRows; i++) {
+                         int k = pivotTemp[i];
+                         // so rowIsBasic[k] would be permuteBack[back[i]]
+                         pivotVariable[permuteBack[back[i]]] = k;
+                    }
+#if 0
+                    if (numberSave >= 0) {
+                         numberSave = numberDense_;
+                         memset(saveList, 0, ((numberRows_ + 31) >> 5)*sizeof(int));
+                         for (i = numberRows_ - numberSave; i < numberRows_; i++) {
+                              int k = pivotTemp[pivotColumn_.array()[i]];
+                              setDense(k);
+                         }
+                    }
+#endif
+                    // Set up permutation vector
+                    // these arrays start off as copies of permute
+                    // (and we could use permute_ instead of pivotColumn (not back though))
+                    ClpDisjointCopyN ( permute_.array(), useNumberRows , pivotColumn_.array()  );
+                    ClpDisjointCopyN ( permuteBack_.array(), useNumberRows , pivotColumnBack_.array()  );
+#ifndef SLIM_CLP
+                    if (networkMatrix) {
+                         maximumPivots(CoinMax(2000, maximumPivots()));
+                         // redo arrays
+                         for (int iRow = 0; iRow < 4; iRow++) {
+                              int length = model->numberRows() + maximumPivots();
+                              if (iRow == 3 || model->objectiveAsObject()->type() > 1)
+                                   length += model->numberColumns();
+                              model->rowArray(iRow)->reserve(length);
+                         }
+                         // create network factorization
+                         if (doCheck)
+                              delete networkBasis_; // temp
+                         networkBasis_ = new ClpNetworkBasis(model, numberRows_,
+                                                             pivotRegion_.array(),
+                                                             permuteBack_.array(),
+                                                             startColumnU_.array(),
+                                                             numberInColumn_.array(),
+                                                             indexRowU_.array(),
+                                                             elementU_.array());
+                         // kill off arrays in ordinary factorization
+                         if (!doCheck) {
+                              gutsOfDestructor();
+                              // but make sure numberRows_ set
+                              numberRows_ = model->numberRows();
+                              status_ = 0;
+#if 0
+                              // but put back permute arrays so odd things will work
+                              int numberRows = model->numberRows();
+                              pivotColumnBack_ = new int [numberRows];
+                              permute_ = new int [numberRows];
+                              int i;
+                              for (i = 0; i < numberRows; i++) {
+                                   pivotColumnBack_[i] = i;
+                                   permute_[i] = i;
+                              }
+#endif
+                         }
+                    } else {
+#endif
+                         // See if worth going sparse and when
+                         if (numberFtranCounts_ > 100) {
+                              ftranCountInput_ = CoinMax(ftranCountInput_, 1.0);
+                              ftranAverageAfterL_ = CoinMax(ftranCountAfterL_ / ftranCountInput_, 1.0);
+                              ftranAverageAfterR_ = CoinMax(ftranCountAfterR_ / ftranCountAfterL_, 1.0);
+                              ftranAverageAfterU_ = CoinMax(ftranCountAfterU_ / ftranCountAfterR_, 1.0);
+                              if (btranCountInput_ && btranCountAfterU_ && btranCountAfterR_) {
+                                   btranAverageAfterU_ = CoinMax(btranCountAfterU_ / btranCountInput_, 1.0);
+                                   btranAverageAfterR_ = CoinMax(btranCountAfterR_ / btranCountAfterU_, 1.0);
+                                   btranAverageAfterL_ = CoinMax(btranCountAfterL_ / btranCountAfterR_, 1.0);
+                              } else {
+                                   // we have not done any useful btrans (values pass?)
+                                   btranAverageAfterU_ = 1.0;
+                                   btranAverageAfterR_ = 1.0;
+                                   btranAverageAfterL_ = 1.0;
+                              }
+                         }
+                         // scale back
+
+                         ftranCountInput_ *= 0.8;
+                         ftranCountAfterL_ *= 0.8;
+                         ftranCountAfterR_ *= 0.8;
+                         ftranCountAfterU_ *= 0.8;
+                         btranCountInput_ *= 0.8;
+                         btranCountAfterU_ *= 0.8;
+                         btranCountAfterR_ *= 0.8;
+                         btranCountAfterL_ *= 0.8;
+#ifndef SLIM_CLP
+                    }
+#endif
+               } else if (status_ == -1 && (solveType == 0 || solveType == 2)) {
+                    // This needs redoing as it was merged coding - does not need array
+                    int numberTotal = numberRows + numberColumns;
+                    int * isBasic = new int [numberTotal];
+                    int * rowIsBasic = isBasic + numberColumns;
+                    int * columnIsBasic = isBasic;
+                    for (i = 0; i < numberTotal; i++)
+                         isBasic[i] = -1;
+                    for (i = 0; i < numberRowBasic; i++) {
+                         int iRow = pivotTemp[i];
+                         rowIsBasic[iRow] = 1;
+                    }
+                    for (; i < numberBasic; i++) {
+                         int iColumn = pivotTemp[i];
+                         columnIsBasic[iColumn] = 1;
+                    }
+                    numberBasic = 0;
+                    for (i = 0; i < numberRows; i++)
+                         pivotVariable[i] = -1;
+                    // mark as basic or non basic
+                    const int * pivotColumn = pivotColumn_.array();
+                    for (i = 0; i < numberRows; i++) {
+                         if (rowIsBasic[i] >= 0) {
+                              if (pivotColumn[numberBasic] >= 0) {
+                                   rowIsBasic[i] = pivotColumn[numberBasic];
+                              } else {
+                                   rowIsBasic[i] = -1;
+                                   model->setRowStatus(i, ClpSimplex::superBasic);
+                              }
+                              numberBasic++;
+                         }
+                    }
+                    for (i = 0; i < numberColumns; i++) {
+                         if (columnIsBasic[i] >= 0) {
+                              if (pivotColumn[numberBasic] >= 0)
+                                   columnIsBasic[i] = pivotColumn[numberBasic];
+                              else
+                                   columnIsBasic[i] = -1;
+                              numberBasic++;
+                         }
+                    }
+                    // leave pivotVariable in useful form for cleaning basis
+                    int * pivotVariable = model->pivotVariable();
+                    for (i = 0; i < numberRows; i++) {
+                         pivotVariable[i] = -1;
+                    }
+
+                    for (i = 0; i < numberRows; i++) {
+                         if (model->getRowStatus(i) == ClpSimplex::basic) {
+                              int iPivot = rowIsBasic[i];
+                              if (iPivot >= 0)
+                                   pivotVariable[iPivot] = i + numberColumns;
+                         }
+                    }
+                    for (i = 0; i < numberColumns; i++) {
+                         if (model->getColumnStatus(i) == ClpSimplex::basic) {
+                              int iPivot = columnIsBasic[i];
+                              if (iPivot >= 0)
+                                   pivotVariable[iPivot] = i;
+                         }
+                    }
+                    delete [] isBasic;
+                    double * columnLower = model->lowerRegion();
+                    double * columnUpper = model->upperRegion();
+                    double * columnActivity = model->solutionRegion();
+                    double * rowLower = model->lowerRegion(0);
+                    double * rowUpper = model->upperRegion(0);
+                    double * rowActivity = model->solutionRegion(0);
+                    //redo basis - first take ALL columns out
+                    int iColumn;
+                    double largeValue = model->largeValue();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (model->getColumnStatus(iColumn) == ClpSimplex::basic) {
+                              // take out
+                              if (!valuesPass) {
+                                   double lower = columnLower[iColumn];
+                                   double upper = columnUpper[iColumn];
+                                   double value = columnActivity[iColumn];
+                                   if (lower > -largeValue || upper < largeValue) {
+                                        if (fabs(value - lower) < fabs(value - upper)) {
+                                             model->setColumnStatus(iColumn, ClpSimplex::atLowerBound);
+                                             columnActivity[iColumn] = lower;
+                                        } else {
+                                             model->setColumnStatus(iColumn, ClpSimplex::atUpperBound);
+                                             columnActivity[iColumn] = upper;
+                                        }
+                                   } else {
+                                        model->setColumnStatus(iColumn, ClpSimplex::isFree);
+                                   }
+                              } else {
+                                   model->setColumnStatus(iColumn, ClpSimplex::superBasic);
+                              }
+                         }
+                    }
+                    int iRow;
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         int iSequence = pivotVariable[iRow];
+                         if (iSequence >= 0) {
+                              // basic
+                              if (iSequence >= numberColumns) {
+                                   // slack in - leave
+                                   //assert (iSequence-numberColumns==iRow);
+                              } else {
+                                   assert(model->getRowStatus(iRow) != ClpSimplex::basic);
+                                   // put back structural
+                                   model->setColumnStatus(iSequence, ClpSimplex::basic);
+                              }
+                         } else {
+                              // put in slack
+                              model->setRowStatus(iRow, ClpSimplex::basic);
+                         }
+                    }
+                    // Put back any key variables for gub (status_ not touched)
+                    matrix->generalExpanded(model, 1, status_);
+                    // signal repeat
+                    status_ = -99;
+                    // set fixed if they are
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         if (model->getRowStatus(iRow) != ClpSimplex::basic ) {
+                              if (rowLower[iRow] == rowUpper[iRow]) {
+                                   rowActivity[iRow] = rowLower[iRow];
+                                   model->setRowStatus(iRow, ClpSimplex::isFixed);
+                              }
+                         }
+                    }
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (model->getColumnStatus(iColumn) != ClpSimplex::basic ) {
+                              if (columnLower[iColumn] == columnUpper[iColumn]) {
+                                   columnActivity[iColumn] = columnLower[iColumn];
+                                   model->setColumnStatus(iColumn, ClpSimplex::isFixed);
+                              }
+                         }
+                    }
+               }
+          }
+#ifndef SLIM_CLP
+     } else {
+          // network - fake factorization - do nothing
+          status_ = 0;
+          numberPivots_ = 0;
+     }
+#endif
+#ifndef SLIM_CLP
+     if (!status_) {
+          // take out part if quadratic
+          if (model->algorithm() == 2) {
+               ClpObjective * obj = model->objectiveAsObject();
+#ifndef NDEBUG
+               ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(obj));
+               assert (quadraticObj);
+#else
+               ClpQuadraticObjective * quadraticObj = (static_cast< ClpQuadraticObjective*>(obj));
+#endif
+               CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+               int numberXColumns = quadratic->getNumCols();
+               assert (numberXColumns < numberColumns);
+               int base = numberColumns - numberXColumns;
+               int * which = new int [numberXColumns];
+               int * pivotVariable = model->pivotVariable();
+               int * permute = pivotColumn();
+               int i;
+               int n = 0;
+               for (i = 0; i < numberRows; i++) {
+                    int iSj = pivotVariable[i] - base;
+                    if (iSj >= 0 && iSj < numberXColumns)
+                         which[n++] = permute[i];
+               }
+               if (n)
+                    emptyRows(n, which);
+               delete [] which;
+          }
+     }
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(2);
+#endif
+     return status_;
+}
+/* Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+   If checkBeforeModifying is true will do all accuracy checks
+   before modifying factorization.  Whether to set this depends on
+   speed considerations.  You could just do this on first iteration
+   after factorization and thereafter re-factorize
+   partial update already in U */
+int
+ClpFactorization::replaceColumn ( const ClpSimplex * model,
+                                  CoinIndexedVector * regionSparse,
+                                  CoinIndexedVector * tableauColumn,
+                                  int pivotRow,
+                                  double pivotCheck ,
+                                  bool checkBeforeModifying,
+                                  double acceptablePivot)
+{
+     int returnCode;
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          // see if FT
+          if (doForrestTomlin_) {
+               returnCode = CoinFactorization::replaceColumn(regionSparse,
+                            pivotRow,
+                            pivotCheck,
+                            checkBeforeModifying,
+                            acceptablePivot);
+          } else {
+               returnCode = CoinFactorization::replaceColumnPFI(tableauColumn,
+                            pivotRow, pivotCheck); // Note array
+          }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(3);
+#endif
+
+#ifndef SLIM_CLP
+     } else {
+          if (doCheck) {
+               returnCode = CoinFactorization::replaceColumn(regionSparse,
+                            pivotRow,
+                            pivotCheck,
+                            checkBeforeModifying,
+                            acceptablePivot);
+               networkBasis_->replaceColumn(regionSparse,
+                                            pivotRow);
+          } else {
+               // increase number of pivots
+               numberPivots_++;
+               returnCode = networkBasis_->replaceColumn(regionSparse,
+                            pivotRow);
+          }
+     }
+#endif
+     return returnCode;
+}
+
+/* Updates one column (FTRAN) from region2
+   number returned is negative if no room
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateColumnFT ( CoinIndexedVector * regionSparse,
+                                   CoinIndexedVector * regionSparse2)
+{
+#ifdef CLP_DEBUG
+     regionSparse->checkClear();
+#endif
+     if (!numberRows_)
+          return 0;
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          collectStatistics_ = true;
+          int returnCode = CoinFactorization::updateColumnFT(regionSparse,
+                           regionSparse2);
+          collectStatistics_ = false;
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(4);
+#endif
+          return returnCode;
+#ifndef SLIM_CLP
+     } else {
+#ifdef CHECK_NETWORK
+          CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
+          double * check = new double[numberRows_];
+          int returnCode = CoinFactorization::updateColumnFT(regionSparse,
+                           regionSparse2);
+          networkBasis_->updateColumn(regionSparse, save, -1);
+          int i;
+          double * array = regionSparse2->denseVector();
+          int * indices = regionSparse2->getIndices();
+          int n = regionSparse2->getNumElements();
+          memset(check, 0, numberRows_ * sizeof(double));
+          double * array2 = save->denseVector();
+          int * indices2 = save->getIndices();
+          int n2 = save->getNumElements();
+          assert (n == n2);
+          if (save->packedMode()) {
+               for (i = 0; i < n; i++) {
+                    check[indices[i]] = array[i];
+               }
+               for (i = 0; i < n; i++) {
+                    double value2 = array2[i];
+                    assert (check[indices2[i]] == value2);
+               }
+          } else {
+               for (i = 0; i < numberRows_; i++) {
+                    double value1 = array[i];
+                    double value2 = array2[i];
+                    assert (value1 == value2);
+               }
+          }
+          delete save;
+          delete [] check;
+          return returnCode;
+#else
+          networkBasis_->updateColumn(regionSparse, regionSparse2, -1);
+          return 1;
+#endif
+     }
+#endif
+}
+/* Updates one column (FTRAN) from region2
+   number returned is negative if no room
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateColumn ( CoinIndexedVector * regionSparse,
+                                 CoinIndexedVector * regionSparse2,
+                                 bool noPermute) const
+{
+#ifdef CLP_DEBUG
+     if (!noPermute)
+          regionSparse->checkClear();
+#endif
+     if (!numberRows_)
+          return 0;
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          collectStatistics_ = true;
+          int returnCode = CoinFactorization::updateColumn(regionSparse,
+                           regionSparse2,
+                           noPermute);
+          collectStatistics_ = false;
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(5);
+#endif
+          return returnCode;
+#ifndef SLIM_CLP
+     } else {
+#ifdef CHECK_NETWORK
+          CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
+          double * check = new double[numberRows_];
+          int returnCode = CoinFactorization::updateColumn(regionSparse,
+                           regionSparse2,
+                           noPermute);
+          networkBasis_->updateColumn(regionSparse, save, -1);
+          int i;
+          double * array = regionSparse2->denseVector();
+          int * indices = regionSparse2->getIndices();
+          int n = regionSparse2->getNumElements();
+          memset(check, 0, numberRows_ * sizeof(double));
+          double * array2 = save->denseVector();
+          int * indices2 = save->getIndices();
+          int n2 = save->getNumElements();
+          assert (n == n2);
+          if (save->packedMode()) {
+               for (i = 0; i < n; i++) {
+                    check[indices[i]] = array[i];
+               }
+               for (i = 0; i < n; i++) {
+                    double value2 = array2[i];
+                    assert (check[indices2[i]] == value2);
+               }
+          } else {
+               for (i = 0; i < numberRows_; i++) {
+                    double value1 = array[i];
+                    double value2 = array2[i];
+                    assert (value1 == value2);
+               }
+          }
+          delete save;
+          delete [] check;
+          return returnCode;
+#else
+          networkBasis_->updateColumn(regionSparse, regionSparse2, -1);
+          return 1;
+#endif
+     }
+#endif
+}
+/* Updates one column (FTRAN) from region2
+   Tries to do FT update
+   number returned is negative if no room.
+   Also updates region3
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateTwoColumnsFT ( CoinIndexedVector * regionSparse1,
+                                       CoinIndexedVector * regionSparse2,
+                                       CoinIndexedVector * regionSparse3,
+                                       bool noPermuteRegion3)
+{
+     int returnCode = updateColumnFT(regionSparse1, regionSparse2);
+     updateColumn(regionSparse1, regionSparse3, noPermuteRegion3);
+     return returnCode;
+}
+/* Updates one column (FTRAN) from region2
+   number returned is negative if no room
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateColumnForDebug ( CoinIndexedVector * regionSparse,
+          CoinIndexedVector * regionSparse2,
+          bool noPermute) const
+{
+     if (!noPermute)
+          regionSparse->checkClear();
+     if (!numberRows_)
+          return 0;
+     collectStatistics_ = false;
+     int returnCode = CoinFactorization::updateColumn(regionSparse,
+                      regionSparse2,
+                      noPermute);
+     return returnCode;
+}
+/* Updates one column (BTRAN) from region2
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateColumnTranspose ( CoinIndexedVector * regionSparse,
+          CoinIndexedVector * regionSparse2) const
+{
+     if (!numberRows_)
+          return 0;
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          collectStatistics_ = true;
+          int returnCode = CoinFactorization::updateColumnTranspose(regionSparse,
+                           regionSparse2);
+          collectStatistics_ = false;
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(6);
+#endif
+          return returnCode;
+#ifndef SLIM_CLP
+     } else {
+#ifdef CHECK_NETWORK
+          CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
+          double * check = new double[numberRows_];
+          int returnCode = CoinFactorization::updateColumnTranspose(regionSparse,
+                           regionSparse2);
+          networkBasis_->updateColumnTranspose(regionSparse, save);
+          int i;
+          double * array = regionSparse2->denseVector();
+          int * indices = regionSparse2->getIndices();
+          int n = regionSparse2->getNumElements();
+          memset(check, 0, numberRows_ * sizeof(double));
+          double * array2 = save->denseVector();
+          int * indices2 = save->getIndices();
+          int n2 = save->getNumElements();
+          assert (n == n2);
+          if (save->packedMode()) {
+               for (i = 0; i < n; i++) {
+                    check[indices[i]] = array[i];
+               }
+               for (i = 0; i < n; i++) {
+                    double value2 = array2[i];
+                    assert (check[indices2[i]] == value2);
+               }
+          } else {
+               for (i = 0; i < numberRows_; i++) {
+                    double value1 = array[i];
+                    double value2 = array2[i];
+                    assert (value1 == value2);
+               }
+          }
+          delete save;
+          delete [] check;
+          return returnCode;
+#else
+          return networkBasis_->updateColumnTranspose(regionSparse, regionSparse2);
+#endif
+     }
+#endif
+}
+/* makes a row copy of L for speed and to allow very sparse problems */
+void
+ClpFactorization::goSparse()
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+#ifndef SLIM_CLP
+     if (!networkBasis_)
+#endif
+          CoinFactorization::goSparse();
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(7);
+#endif
+}
+// Cleans up i.e. gets rid of network basis
+void
+ClpFactorization::cleanUp()
+{
+#ifndef SLIM_CLP
+     delete networkBasis_;
+     networkBasis_ = NULL;
+#endif
+     resetStatistics();
+}
+/// Says whether to redo pivot order
+bool
+ClpFactorization::needToReorder() const
+{
+#ifdef CHECK_NETWORK
+     return true;
+#endif
+#ifndef SLIM_CLP
+     if (!networkBasis_)
+#endif
+          return true;
+#ifndef SLIM_CLP
+     else
+          return false;
+#endif
+}
+// Get weighted row list
+void
+ClpFactorization::getWeights(int * weights) const
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+#ifndef SLIM_CLP
+     if (networkBasis_) {
+          // Network - just unit
+          for (int i = 0; i < numberRows_; i++)
+               weights[i] = 1;
+          return;
+     }
+#endif
+     int * numberInRow = numberInRow_.array();
+     int * numberInColumn = numberInColumn_.array();
+     int * permuteBack = pivotColumnBack_.array();
+     int * indexRowU = indexRowU_.array();
+     const CoinBigIndex * startColumnU = startColumnU_.array();
+     const CoinBigIndex * startRowL = startRowL_.array();
+     if (!startRowL || !numberInRow_.array()) {
+          int * temp = new int[numberRows_];
+          memset(temp, 0, numberRows_ * sizeof(int));
+          int i;
+          for (i = 0; i < numberRows_; i++) {
+               // one for pivot
+               temp[i]++;
+               CoinBigIndex j;
+               for (j = startColumnU[i]; j < startColumnU[i] + numberInColumn[i]; j++) {
+                    int iRow = indexRowU[j];
+                    temp[iRow]++;
+               }
+          }
+          CoinBigIndex * startColumnL = startColumnL_.array();
+          int * indexRowL = indexRowL_.array();
+          for (i = baseL_; i < baseL_ + numberL_; i++) {
+               CoinBigIndex j;
+               for (j = startColumnL[i]; j < startColumnL[i+1]; j++) {
+                    int iRow = indexRowL[j];
+                    temp[iRow]++;
+               }
+          }
+          for (i = 0; i < numberRows_; i++) {
+               int number = temp[i];
+               int iPermute = permuteBack[i];
+               weights[iPermute] = number;
+          }
+          delete [] temp;
+     } else {
+          int i;
+          for (i = 0; i < numberRows_; i++) {
+               int number = startRowL[i+1] - startRowL[i] + numberInRow[i] + 1;
+               //number = startRowL[i+1]-startRowL[i]+1;
+               //number = numberInRow[i]+1;
+               int iPermute = permuteBack[i];
+               weights[iPermute] = number;
+          }
+     }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(8);
+#endif
+}
+#else
+// This one allows multiple factorizations
+#if CLP_MULTIPLE_FACTORIZATIONS == 1
+typedef CoinDenseFactorization CoinOtherFactorization;
+typedef CoinOslFactorization CoinOtherFactorization;
+#elif CLP_MULTIPLE_FACTORIZATIONS == 2
+#include "CoinSimpFactorization.hpp"
+typedef CoinSimpFactorization CoinOtherFactorization;
+typedef CoinOslFactorization CoinOtherFactorization;
+#elif CLP_MULTIPLE_FACTORIZATIONS == 3
+#include "CoinSimpFactorization.hpp"
+#define CoinOslFactorization CoinDenseFactorization
+#elif CLP_MULTIPLE_FACTORIZATIONS == 4
+#include "CoinSimpFactorization.hpp"
+//#define CoinOslFactorization CoinDenseFactorization
+#include "CoinOslFactorization.hpp"
+#endif
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpFactorization::ClpFactorization ()
+{
+#ifndef SLIM_CLP
+     networkBasis_ = NULL;
+#endif
+     //coinFactorizationA_ = NULL;
+     coinFactorizationA_ = new CoinFactorization() ;
+     coinFactorizationB_ = NULL;
+     //coinFactorizationB_ = new CoinOtherFactorization();
+     forceB_ = 0;
+     goOslThreshold_ = -1;
+     goDenseThreshold_ = -1;
+     goSmallThreshold_ = -1;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpFactorization::ClpFactorization (const ClpFactorization & rhs,
+                                    int denseIfSmaller)
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+#ifndef SLIM_CLP
+     if (rhs.networkBasis_)
+          networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
+     else
+          networkBasis_ = NULL;
+#endif
+     forceB_ = rhs.forceB_;
+     goOslThreshold_ = rhs.goOslThreshold_;
+     goDenseThreshold_ = rhs.goDenseThreshold_;
+     goSmallThreshold_ = rhs.goSmallThreshold_;
+     int goDense = 0;
+#ifdef CLP_REUSE_ETAS
+     model_=rhs.model_;
+#endif
+     if (denseIfSmaller > 0 && denseIfSmaller <= goDenseThreshold_) {
+          CoinDenseFactorization * denseR =
+               dynamic_cast<CoinDenseFactorization *>(rhs.coinFactorizationB_);
+          if (!denseR)
+               goDense = 1;
+     }
+     if (denseIfSmaller > 0 && !rhs.coinFactorizationB_) {
+          if (denseIfSmaller <= goDenseThreshold_)
+               goDense = 1;
+          else if (denseIfSmaller <= goSmallThreshold_)
+               goDense = 2;
+          else if (denseIfSmaller <= goOslThreshold_)
+               goDense = 3;
+     } else if (denseIfSmaller < 0) {
+          if (-denseIfSmaller <= goDenseThreshold_)
+               goDense = 1;
+          else if (-denseIfSmaller <= goSmallThreshold_)
+               goDense = 2;
+          else if (-denseIfSmaller <= goOslThreshold_)
+               goDense = 3;
+     }
+     if (rhs.coinFactorizationA_ && !goDense)
+          coinFactorizationA_ = new CoinFactorization(*(rhs.coinFactorizationA_));
+     else
+          coinFactorizationA_ = NULL;
+     if (rhs.coinFactorizationB_ && (denseIfSmaller >= 0 || !goDense))
+          coinFactorizationB_ = rhs.coinFactorizationB_->clone();
+     else
+          coinFactorizationB_ = NULL;
+     if (goDense) {
+          delete coinFactorizationB_;
+          if (goDense == 1)
+               coinFactorizationB_ = new CoinDenseFactorization();
+          else if (goDense == 2)
+               coinFactorizationB_ = new CoinSimpFactorization();
+          else
+               coinFactorizationB_ = new CoinOslFactorization();
+          if (rhs.coinFactorizationA_) {
+               coinFactorizationB_->maximumPivots(rhs.coinFactorizationA_->maximumPivots());
+               coinFactorizationB_->pivotTolerance(rhs.coinFactorizationA_->pivotTolerance());
+               coinFactorizationB_->zeroTolerance(rhs.coinFactorizationA_->zeroTolerance());
+          } else {
+               assert (coinFactorizationB_);
+               coinFactorizationB_->maximumPivots(rhs.coinFactorizationB_->maximumPivots());
+               coinFactorizationB_->pivotTolerance(rhs.coinFactorizationB_->pivotTolerance());
+               coinFactorizationB_->zeroTolerance(rhs.coinFactorizationB_->zeroTolerance());
+          }
+     }
+     assert (!coinFactorizationA_ || !coinFactorizationB_);
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(1);
+#endif
+}
+
+ClpFactorization::ClpFactorization (const CoinFactorization & rhs)
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+#ifndef SLIM_CLP
+     networkBasis_ = NULL;
+#endif
+     coinFactorizationA_ = new CoinFactorization(rhs);
+     coinFactorizationB_ = NULL;
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(1);
+#endif
+     forceB_ = 0;
+     goOslThreshold_ = -1;
+     goDenseThreshold_ = -1;
+     goSmallThreshold_ = -1;
+     assert (!coinFactorizationA_ || !coinFactorizationB_);
+}
+
+ClpFactorization::ClpFactorization (const CoinOtherFactorization & rhs)
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+#ifndef SLIM_CLP
+     networkBasis_ = NULL;
+#endif
+     coinFactorizationA_ = NULL;
+     coinFactorizationB_ = rhs.clone();
+     //coinFactorizationB_ = new CoinOtherFactorization(rhs);
+     forceB_ = 0;
+     goOslThreshold_ = -1;
+     goDenseThreshold_ = -1;
+     goSmallThreshold_ = -1;
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(1);
+#endif
+     assert (!coinFactorizationA_ || !coinFactorizationB_);
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpFactorization::~ClpFactorization ()
+{
+#ifndef SLIM_CLP
+     delete networkBasis_;
+#endif
+     delete coinFactorizationA_;
+     delete coinFactorizationB_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpFactorization &
+ClpFactorization::operator=(const ClpFactorization& rhs)
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+     if (this != &rhs) {
+#ifndef SLIM_CLP
+          delete networkBasis_;
+          if (rhs.networkBasis_)
+               networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
+          else
+               networkBasis_ = NULL;
+#endif
+          forceB_ = rhs.forceB_;
+#ifdef CLP_REUSE_ETAS
+	  model_=rhs.model_;
+#endif
+          goOslThreshold_ = rhs.goOslThreshold_;
+          goDenseThreshold_ = rhs.goDenseThreshold_;
+          goSmallThreshold_ = rhs.goSmallThreshold_;
+          if (rhs.coinFactorizationA_) {
+               if (coinFactorizationA_)
+                    *coinFactorizationA_ = *(rhs.coinFactorizationA_);
+               else
+                    coinFactorizationA_ = new CoinFactorization(*rhs.coinFactorizationA_);
+          } else {
+               delete coinFactorizationA_;
+               coinFactorizationA_ = NULL;
+          }
+
+          if (rhs.coinFactorizationB_) {
+               if (coinFactorizationB_) {
+                    CoinDenseFactorization * denseR = dynamic_cast<CoinDenseFactorization *>(rhs.coinFactorizationB_);
+                    CoinDenseFactorization * dense = dynamic_cast<CoinDenseFactorization *>(coinFactorizationB_);
+                    CoinOslFactorization * oslR = dynamic_cast<CoinOslFactorization *>(rhs.coinFactorizationB_);
+                    CoinOslFactorization * osl = dynamic_cast<CoinOslFactorization *>(coinFactorizationB_);
+                    CoinSimpFactorization * simpR = dynamic_cast<CoinSimpFactorization *>(rhs.coinFactorizationB_);
+                    CoinSimpFactorization * simp = dynamic_cast<CoinSimpFactorization *>(coinFactorizationB_);
+                    if (dense && denseR) {
+                         *dense = *denseR;
+                    } else if (osl && oslR) {
+                         *osl = *oslR;
+                    } else if (simp && simpR) {
+                         *simp = *simpR;
+                    } else {
+                         delete coinFactorizationB_;
+                         coinFactorizationB_ = rhs.coinFactorizationB_->clone();
+                    }
+               } else {
+                    coinFactorizationB_ = rhs.coinFactorizationB_->clone();
+               }
+          } else {
+               delete coinFactorizationB_;
+               coinFactorizationB_ = NULL;
+          }
+     }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(1);
+#endif
+     assert (!coinFactorizationA_ || !coinFactorizationB_);
+     return *this;
+}
+// Go over to dense code
+void
+ClpFactorization::goDenseOrSmall(int numberRows)
+{
+     if (!forceB_) {
+          if (numberRows <= goDenseThreshold_) {
+               delete coinFactorizationA_;
+               delete coinFactorizationB_;
+               coinFactorizationA_ = NULL;
+               coinFactorizationB_ = new CoinDenseFactorization();
+               //printf("going dense\n");
+          } else if (numberRows <= goSmallThreshold_) {
+               delete coinFactorizationA_;
+               delete coinFactorizationB_;
+               coinFactorizationA_ = NULL;
+               coinFactorizationB_ = new CoinSimpFactorization();
+               //printf("going small\n");
+          } else if (numberRows <= goOslThreshold_) {
+               delete coinFactorizationA_;
+               delete coinFactorizationB_;
+               coinFactorizationA_ = NULL;
+               coinFactorizationB_ = new CoinOslFactorization();
+               //printf("going small\n");
+          }
+     }
+     assert (!coinFactorizationA_ || !coinFactorizationB_);
+}
+// If nonzero force use of 1,dense 2,small 3,osl
+void
+ClpFactorization::forceOtherFactorization(int which)
+{
+     delete coinFactorizationB_;
+     forceB_ = 0;
+     coinFactorizationB_ = NULL;
+     if (which > 0 && which < 4) {
+          delete coinFactorizationA_;
+          coinFactorizationA_ = NULL;
+          forceB_ = which;
+          switch (which) {
+          case 1:
+               coinFactorizationB_ = new CoinDenseFactorization();
+               goDenseThreshold_ = COIN_INT_MAX;
+               break;
+          case 2:
+               coinFactorizationB_ = new CoinSimpFactorization();
+               goSmallThreshold_ = COIN_INT_MAX;
+               break;
+          case 3:
+               coinFactorizationB_ = new CoinOslFactorization();
+               goOslThreshold_ = COIN_INT_MAX;
+               break;
+          }
+     } else if (!coinFactorizationA_) {
+          coinFactorizationA_ = new CoinFactorization();
+	  goOslThreshold_ = -1;
+	  goDenseThreshold_ = -1;
+	  goSmallThreshold_ = -1;
+     }
+}
+int
+ClpFactorization::factorize ( ClpSimplex * model,
+                              int solveType, bool valuesPass)
+{
+#ifdef CLP_REUSE_ETAS
+     model_= model;
+#endif
+     //if ((model->specialOptions()&16384))
+     //printf("factor at %d iterations\n",model->numberIterations());
+     ClpMatrixBase * matrix = model->clpMatrix();
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     if (!numberRows)
+          return 0;
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+     bool anyChanged = false;
+     if (coinFactorizationB_) {
+          coinFactorizationB_->setStatus(-99);
+          int * pivotVariable = model->pivotVariable();
+          //returns 0 -okay, -1 singular, -2 too many in basis */
+          // allow dense
+          int solveMode = 2;
+          if (model->numberIterations())
+               solveMode += 8;
+          if (valuesPass)
+               solveMode += 4;
+          coinFactorizationB_->setSolveMode(solveMode);
+          while (status() < -98) {
+
+               int i;
+               int numberBasic = 0;
+               int numberRowBasic;
+               // Move pivot variables across if they look good
+               int * pivotTemp = model->rowArray(0)->getIndices();
+               assert (!model->rowArray(0)->getNumElements());
+               if (!matrix->rhsOffset(model)) {
+                    // Seems to prefer things in order so quickest
+                    // way is to go though like this
+                    for (i = 0; i < numberRows; i++) {
+                         if (model->getRowStatus(i) == ClpSimplex::basic)
+                              pivotTemp[numberBasic++] = i;
+                    }
+                    numberRowBasic = numberBasic;
+                    /* Put column basic variables into pivotVariable
+                       This is done by ClpMatrixBase to allow override for gub
+                    */
+                    matrix->generalExpanded(model, 0, numberBasic);
+               } else {
+                    // Long matrix - do a different way
+                    bool fullSearch = false;
+                    for (i = 0; i < numberRows; i++) {
+                         int iPivot = pivotVariable[i];
+                         if (iPivot >= numberColumns) {
+                              pivotTemp[numberBasic++] = iPivot - numberColumns;
+                         }
+                    }
+                    numberRowBasic = numberBasic;
+                    for (i = 0; i < numberRows; i++) {
+                         int iPivot = pivotVariable[i];
+                         if (iPivot < numberColumns) {
+                              if (iPivot >= 0) {
+                                   pivotTemp[numberBasic++] = iPivot;
+                              } else {
+                                   // not full basis
+                                   fullSearch = true;
+                                   break;
+                              }
+                         }
+                    }
+                    if (fullSearch) {
+                         // do slow way
+                         numberBasic = 0;
+                         for (i = 0; i < numberRows; i++) {
+                              if (model->getRowStatus(i) == ClpSimplex::basic)
+                                   pivotTemp[numberBasic++] = i;
+                         }
+                         numberRowBasic = numberBasic;
+                         /* Put column basic variables into pivotVariable
+                            This is done by ClpMatrixBase to allow override for gub
+                         */
+                         matrix->generalExpanded(model, 0, numberBasic);
+                    }
+               }
+               if (numberBasic > model->maximumBasic()) {
+                    // Take out some
+                    numberBasic = numberRowBasic;
+                    for (int i = 0; i < numberColumns; i++) {
+                         if (model->getColumnStatus(i) == ClpSimplex::basic) {
+                              if (numberBasic < numberRows)
+                                   numberBasic++;
+                              else
+                                   model->setColumnStatus(i, ClpSimplex::superBasic);
+                         }
+                    }
+                    numberBasic = numberRowBasic;
+                    matrix->generalExpanded(model, 0, numberBasic);
+               } else if (numberBasic < numberRows) {
+                    // add in some
+                    int needed = numberRows - numberBasic;
+                    // move up columns
+                    for (i = numberBasic - 1; i >= numberRowBasic; i--)
+                         pivotTemp[i+needed] = pivotTemp[i];
+                    numberRowBasic = 0;
+                    numberBasic = numberRows;
+                    for (i = 0; i < numberRows; i++) {
+                         if (model->getRowStatus(i) == ClpSimplex::basic) {
+                              pivotTemp[numberRowBasic++] = i;
+                         } else if (needed) {
+                              needed--;
+                              model->setRowStatus(i, ClpSimplex::basic);
+                              pivotTemp[numberRowBasic++] = i;
+                         }
+                    }
+               }
+               CoinBigIndex numberElements = numberRowBasic;
+
+               // compute how much in basis
+               // can change for gub
+               int numberColumnBasic = numberBasic - numberRowBasic;
+
+               numberElements += matrix->countBasis(pivotTemp + numberRowBasic,
+                                                    numberColumnBasic);
+#ifndef NDEBUG
+//#define CHECK_CLEAN_BASIS
+#ifdef CHECK_CLEAN_BASIS
+	       int saveNumberElements = numberElements;
+#endif
+#endif
+               // Not needed for dense
+               numberElements = 3 * numberBasic + 3 * numberElements + 20000;
+               int numberIterations = model->numberIterations();
+               coinFactorizationB_->setUsefulInformation(&numberIterations, 0);
+               coinFactorizationB_->getAreas ( numberRows,
+                                               numberRowBasic + numberColumnBasic, numberElements,
+                                               2 * numberElements );
+               // Fill in counts so we can skip part of preProcess
+               // This is NOT needed for dense but would be needed for later versions
+               CoinFactorizationDouble * elementU;
+               int * indexRowU;
+               CoinBigIndex * startColumnU;
+               int * numberInRow;
+               int * numberInColumn;
+               elementU = coinFactorizationB_->elements();
+               indexRowU = coinFactorizationB_->indices();
+               startColumnU = coinFactorizationB_->starts();
+#ifdef CHECK_CLEAN_BASIS
+	       for (int i=0;i<saveNumberElements;i++) {
+		 elementU[i]=0.0;
+		 indexRowU[i]=-1;
+	       }
+	       for (int i=0;i<numberRows;i++)
+		 startColumnU[i]=-1;
+#endif
+#ifndef COIN_FAST_CODE
+               double slackValue;
+               slackValue = coinFactorizationB_->slackValue();
+#else
+#define slackValue -1.0
+#endif
+               numberInRow = coinFactorizationB_->numberInRow();
+               numberInColumn = coinFactorizationB_->numberInColumn();
+               CoinZeroN ( numberInRow, numberRows  );
+               CoinZeroN ( numberInColumn, numberRows );
+               for (i = 0; i < numberRowBasic; i++) {
+                    int iRow = pivotTemp[i];
+                    // Change pivotTemp to correct sequence
+                    pivotTemp[i] = iRow + numberColumns;
+                    indexRowU[i] = iRow;
+                    startColumnU[i] = i;
+                    elementU[i] = slackValue;
+                    numberInRow[iRow] = 1;
+                    numberInColumn[i] = 1;
+               }
+               startColumnU[numberRowBasic] = numberRowBasic;
+               // can change for gub so redo
+               numberColumnBasic = numberBasic - numberRowBasic;
+               matrix->fillBasis(model,
+                                 pivotTemp + numberRowBasic,
+                                 numberColumnBasic,
+                                 indexRowU,
+                                 startColumnU + numberRowBasic,
+                                 numberInRow,
+                                 numberInColumn + numberRowBasic,
+                                 elementU);
+               // recompute number basic
+               numberBasic = numberRowBasic + numberColumnBasic;
+               for (i = numberBasic; i < numberRows; i++)
+                    pivotTemp[i] = -1; // mark not there
+               if (numberBasic)
+                    numberElements = startColumnU[numberBasic-1]
+                                     + numberInColumn[numberBasic-1];
+               else
+                    numberElements = 0;
+#ifdef CHECK_CLEAN_BASIS
+	       assert (!startColumnU[0]);
+	       int lastStart=0;
+	       for (int i=0;i<numberRows;i++) {
+		 assert (startColumnU[i+1]>lastStart);
+		 lastStart=startColumnU[i+1];
+	       }
+	       assert (lastStart==saveNumberElements);
+	       for (int i=0;i<saveNumberElements;i++) {
+		 assert(elementU[i]);
+		 assert(indexRowU[i]>=0&&indexRowU[i]<numberRows);
+	       }
+#endif
+               coinFactorizationB_->preProcess ( );
+               coinFactorizationB_->factor (  );
+               if (coinFactorizationB_->status() == -1 &&
+                         (coinFactorizationB_->solveMode() % 3) != 0) {
+                    int solveMode = coinFactorizationB_->solveMode();
+                    solveMode -= solveMode % 3; // so bottom will be 0
+                    coinFactorizationB_->setSolveMode(solveMode);
+                    coinFactorizationB_->setStatus(-99);
+               }
+               if (coinFactorizationB_->status() == -99)
+                    continue;
+               // If we get here status is 0 or -1
+               if (coinFactorizationB_->status() == 0 && numberBasic == numberRows) {
+                    coinFactorizationB_->postProcess(pivotTemp, pivotVariable);
+               } else if (solveType == 0 || solveType == 2/*||solveType==1*/) {
+                    // Change pivotTemp to be correct list
+                    anyChanged = true;
+                    coinFactorizationB_->makeNonSingular(pivotTemp, numberColumns);
+                    double * columnLower = model->lowerRegion();
+                    double * columnUpper = model->upperRegion();
+                    double * columnActivity = model->solutionRegion();
+                    double * rowLower = model->lowerRegion(0);
+                    double * rowUpper = model->upperRegion(0);
+                    double * rowActivity = model->solutionRegion(0);
+                    //redo basis - first take ALL out
+                    int iColumn;
+                    double largeValue = model->largeValue();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (model->getColumnStatus(iColumn) == ClpSimplex::basic) {
+                              // take out
+                              if (!valuesPass) {
+                                   double lower = columnLower[iColumn];
+                                   double upper = columnUpper[iColumn];
+                                   double value = columnActivity[iColumn];
+                                   if (lower > -largeValue || upper < largeValue) {
+                                        if (fabs(value - lower) < fabs(value - upper)) {
+                                             model->setColumnStatus(iColumn, ClpSimplex::atLowerBound);
+                                             columnActivity[iColumn] = lower;
+                                        } else {
+                                             model->setColumnStatus(iColumn, ClpSimplex::atUpperBound);
+                                             columnActivity[iColumn] = upper;
+                                        }
+                                   } else {
+                                        model->setColumnStatus(iColumn, ClpSimplex::isFree);
+                                   }
+                              } else {
+                                   model->setColumnStatus(iColumn, ClpSimplex::superBasic);
+                              }
+                         }
+                    }
+                    int iRow;
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         if (model->getRowStatus(iRow) == ClpSimplex::basic) {
+                              // take out
+                              if (!valuesPass) {
+                                   double lower = columnLower[iRow];
+                                   double upper = columnUpper[iRow];
+                                   double value = columnActivity[iRow];
+                                   if (lower > -largeValue || upper < largeValue) {
+                                        if (fabs(value - lower) < fabs(value - upper)) {
+                                             model->setRowStatus(iRow, ClpSimplex::atLowerBound);
+                                             columnActivity[iRow] = lower;
+                                        } else {
+                                             model->setRowStatus(iRow, ClpSimplex::atUpperBound);
+                                             columnActivity[iRow] = upper;
+                                        }
+                                   } else {
+                                        model->setRowStatus(iRow, ClpSimplex::isFree);
+                                   }
+                              } else {
+                                   model->setRowStatus(iRow, ClpSimplex::superBasic);
+                              }
+                         }
+                    }
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         int iSequence = pivotTemp[iRow];
+                         assert (iSequence >= 0);
+                         // basic
+                         model->setColumnStatus(iSequence, ClpSimplex::basic);
+                    }
+                    // signal repeat
+                    coinFactorizationB_->setStatus(-99);
+                    // set fixed if they are
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         if (model->getRowStatus(iRow) != ClpSimplex::basic ) {
+                              if (rowLower[iRow] == rowUpper[iRow]) {
+                                   rowActivity[iRow] = rowLower[iRow];
+                                   model->setRowStatus(iRow, ClpSimplex::isFixed);
+                              }
+                         }
+                    }
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (model->getColumnStatus(iColumn) != ClpSimplex::basic ) {
+                              if (columnLower[iColumn] == columnUpper[iColumn]) {
+                                   columnActivity[iColumn] = columnLower[iColumn];
+                                   model->setColumnStatus(iColumn, ClpSimplex::isFixed);
+                              }
+                         }
+                    }
+               }
+          }
+#ifdef CLP_DEBUG
+          // check basic
+          CoinIndexedVector region1(2 * numberRows);
+          CoinIndexedVector region2B(2 * numberRows);
+          int iPivot;
+          double * arrayB = region2B.denseVector();
+          int i;
+          for (iPivot = 0; iPivot < numberRows; iPivot++) {
+               int iSequence = pivotVariable[iPivot];
+               model->unpack(&region2B, iSequence);
+               coinFactorizationB_->updateColumn(&region1, &region2B);
+               if (fabs(arrayB[iPivot] - 1.0) < 1.0e-4) {
+                    // OK?
+                    arrayB[iPivot] = 0.0;
+               } else {
+                    assert (fabs(arrayB[iPivot]) < 1.0e-4);
+                    for (i = 0; i < numberRows; i++) {
+                         if (fabs(arrayB[i] - 1.0) < 1.0e-4)
+                              break;
+                    }
+                    assert (i < numberRows);
+                    printf("variable on row %d landed up on row %d\n", iPivot, i);
+                    arrayB[i] = 0.0;
+               }
+               for (i = 0; i < numberRows; i++)
+                    assert (fabs(arrayB[i]) < 1.0e-4);
+               region2B.clear();
+          }
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(2);
+#endif
+          if ( anyChanged && model->algorithm() < 0 && solveType > 0) {
+               double dummyCost;
+               static_cast<ClpSimplexDual *> (model)->changeBounds(3,
+                         NULL, dummyCost);
+          }
+          return coinFactorizationB_->status();
+     }
+     // If too many compressions increase area
+     if (coinFactorizationA_->pivots() > 1 && coinFactorizationA_->numberCompressions() * 10 > coinFactorizationA_->pivots() + 10) {
+          coinFactorizationA_->areaFactor( coinFactorizationA_->areaFactor() * 1.1);
+     }
+     //int numberPivots=coinFactorizationA_->pivots();
+#if 0
+     if (model->algorithm() > 0)
+          numberSave = -1;
+#endif
+#ifndef SLIM_CLP
+     if (!networkBasis_ || doCheck) {
+#endif
+          coinFactorizationA_->setStatus(-99);
+          int * pivotVariable = model->pivotVariable();
+          int nTimesRound = 0;
+          //returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
+          while (coinFactorizationA_->status() < -98) {
+               nTimesRound++;
+
+               int i;
+               int numberBasic = 0;
+               int numberRowBasic;
+               // Move pivot variables across if they look good
+               int * pivotTemp = model->rowArray(0)->getIndices();
+               assert (!model->rowArray(0)->getNumElements());
+               if (!matrix->rhsOffset(model)) {
+#if 0
+                    if (numberSave > 0) {
+                         int nStill = 0;
+                         int nAtBound = 0;
+                         int nZeroDual = 0;
+                         CoinIndexedVector * array = model->rowArray(3);
+                         CoinIndexedVector * objArray = model->columnArray(1);
+                         array->clear();
+                         objArray->clear();
+                         double * cost = model->costRegion();
+                         double tolerance = model->primalTolerance();
+                         double offset = 0.0;
+                         for (i = 0; i < numberRows; i++) {
+                              int iPivot = pivotVariable[i];
+                              if (iPivot < numberColumns && isDense(iPivot)) {
+                                   if (model->getColumnStatus(iPivot) == ClpSimplex::basic) {
+                                        nStill++;
+                                        double value = model->solutionRegion()[iPivot];
+                                        double dual = model->dualRowSolution()[i];
+                                        double lower = model->lowerRegion()[iPivot];
+                                        double upper = model->upperRegion()[iPivot];
+                                        ClpSimplex::Status status;
+                                        if (fabs(value - lower) < tolerance) {
+                                             status = ClpSimplex::atLowerBound;
+                                             nAtBound++;
+                                        } else if (fabs(value - upper) < tolerance) {
+                                             nAtBound++;
+                                             status = ClpSimplex::atUpperBound;
+                                        } else if (value > lower && value < upper) {
+                                             status = ClpSimplex::superBasic;
+                                        } else {
+                                             status = ClpSimplex::basic;
+                                        }
+                                        if (status != ClpSimplex::basic) {
+                                             if (model->getRowStatus(i) != ClpSimplex::basic) {
+                                                  model->setColumnStatus(iPivot, ClpSimplex::atLowerBound);
+                                                  model->setRowStatus(i, ClpSimplex::basic);
+                                                  pivotVariable[i] = i + numberColumns;
+                                                  model->dualRowSolution()[i] = 0.0;
+                                                  model->djRegion(0)[i] = 0.0;
+                                                  array->add(i, dual);
+                                                  offset += dual * model->solutionRegion(0)[i];
+                                             }
+                                        }
+                                        if (fabs(dual) < 1.0e-5)
+                                             nZeroDual++;
+                                   }
+                              }
+                         }
+                         printf("out of %d dense, %d still in basis, %d at bound, %d with zero dual - offset %g\n",
+                                numberSave, nStill, nAtBound, nZeroDual, offset);
+                         if (array->getNumElements()) {
+                              // modify costs
+                              model->clpMatrix()->transposeTimes(model, 1.0, array, model->columnArray(0),
+                                                                 objArray);
+                              array->clear();
+                              int n = objArray->getNumElements();
+                              int * indices = objArray->getIndices();
+                              double * elements = objArray->denseVector();
+                              for (i = 0; i < n; i++) {
+                                   int iColumn = indices[i];
+                                   cost[iColumn] -= elements[iColumn];
+                                   elements[iColumn] = 0.0;
+                              }
+                              objArray->setNumElements(0);
+                         }
+                    }
+#endif
+                    // Seems to prefer things in order so quickest
+                    // way is to go though like this
+                    for (i = 0; i < numberRows; i++) {
+                         if (model->getRowStatus(i) == ClpSimplex::basic)
+                              pivotTemp[numberBasic++] = i;
+                    }
+                    numberRowBasic = numberBasic;
+                    /* Put column basic variables into pivotVariable
+                       This is done by ClpMatrixBase to allow override for gub
+                    */
+                    matrix->generalExpanded(model, 0, numberBasic);
+               } else {
+                    // Long matrix - do a different way
+                    bool fullSearch = false;
+                    for (i = 0; i < numberRows; i++) {
+                         int iPivot = pivotVariable[i];
+                         if (iPivot >= numberColumns) {
+                              pivotTemp[numberBasic++] = iPivot - numberColumns;
+                         }
+                    }
+                    numberRowBasic = numberBasic;
+                    for (i = 0; i < numberRows; i++) {
+                         int iPivot = pivotVariable[i];
+                         if (iPivot < numberColumns) {
+                              if (iPivot >= 0) {
+                                   pivotTemp[numberBasic++] = iPivot;
+                              } else {
+                                   // not full basis
+                                   fullSearch = true;
+                                   break;
+                              }
+                         }
+                    }
+                    if (fullSearch) {
+                         // do slow way
+                         numberBasic = 0;
+                         for (i = 0; i < numberRows; i++) {
+                              if (model->getRowStatus(i) == ClpSimplex::basic)
+                                   pivotTemp[numberBasic++] = i;
+                         }
+                         numberRowBasic = numberBasic;
+                         /* Put column basic variables into pivotVariable
+                            This is done by ClpMatrixBase to allow override for gub
+                         */
+                         matrix->generalExpanded(model, 0, numberBasic);
+                    }
+               }
+               if (numberBasic > model->maximumBasic()) {
+#if 0 // ndef NDEBUG
+                    printf("%d basic - should only be %d\n",
+                           numberBasic, numberRows);
+#endif
+                    // Take out some
+                    numberBasic = numberRowBasic;
+                    for (int i = 0; i < numberColumns; i++) {
+                         if (model->getColumnStatus(i) == ClpSimplex::basic) {
+                              if (numberBasic < numberRows)
+                                   numberBasic++;
+                              else
+                                   model->setColumnStatus(i, ClpSimplex::superBasic);
+                         }
+                    }
+                    numberBasic = numberRowBasic;
+                    matrix->generalExpanded(model, 0, numberBasic);
+               }
+#ifndef SLIM_CLP
+               // see if matrix a network
+#ifndef NO_RTTI
+               ClpNetworkMatrix* networkMatrix =
+                    dynamic_cast< ClpNetworkMatrix*>(model->clpMatrix());
+#else
+ClpNetworkMatrix* networkMatrix = NULL;
+if (model->clpMatrix()->type() == 11)
+     networkMatrix =
+          static_cast< ClpNetworkMatrix*>(model->clpMatrix());
+#endif
+               // If network - still allow ordinary factorization first time for laziness
+               if (networkMatrix)
+                    coinFactorizationA_->setBiasLU(0); // All to U if network
+               //int saveMaximumPivots = maximumPivots();
+               delete networkBasis_;
+               networkBasis_ = NULL;
+               if (networkMatrix && !doCheck)
+                    maximumPivots(1);
+#endif
+               //printf("L, U, R %d %d %d\n",numberElementsL(),numberElementsU(),numberElementsR());
+               while (coinFactorizationA_->status() == -99) {
+                    // maybe for speed will be better to leave as many regions as possible
+                    coinFactorizationA_->gutsOfDestructor();
+                    coinFactorizationA_->gutsOfInitialize(2);
+                    CoinBigIndex numberElements = numberRowBasic;
+
+                    // compute how much in basis
+
+                    int i;
+                    // can change for gub
+                    int numberColumnBasic = numberBasic - numberRowBasic;
+
+                    numberElements += matrix->countBasis( pivotTemp + numberRowBasic,
+                                                          numberColumnBasic);
+                    // and recompute as network side say different
+                    if (model->numberIterations())
+                         numberRowBasic = numberBasic - numberColumnBasic;
+                    numberElements = 3 * numberBasic + 3 * numberElements + 20000;
+                    coinFactorizationA_->getAreas ( numberRows,
+                                                    numberRowBasic + numberColumnBasic, numberElements,
+                                                    2 * numberElements );
+                    //fill
+                    // Fill in counts so we can skip part of preProcess
+                    int * numberInRow = coinFactorizationA_->numberInRow();
+                    int * numberInColumn = coinFactorizationA_->numberInColumn();
+                    CoinZeroN ( numberInRow, coinFactorizationA_->numberRows() + 1 );
+                    CoinZeroN ( numberInColumn, coinFactorizationA_->maximumColumnsExtra() + 1 );
+                    CoinFactorizationDouble * elementU = coinFactorizationA_->elementU();
+                    int * indexRowU = coinFactorizationA_->indexRowU();
+                    CoinBigIndex * startColumnU = coinFactorizationA_->startColumnU();
+#ifndef COIN_FAST_CODE
+                    double slackValue = coinFactorizationA_->slackValue();
+#endif
+                    for (i = 0; i < numberRowBasic; i++) {
+                         int iRow = pivotTemp[i];
+                         indexRowU[i] = iRow;
+                         startColumnU[i] = i;
+                         elementU[i] = slackValue;
+                         numberInRow[iRow] = 1;
+                         numberInColumn[i] = 1;
+                    }
+                    startColumnU[numberRowBasic] = numberRowBasic;
+                    // can change for gub so redo
+                    numberColumnBasic = numberBasic - numberRowBasic;
+                    matrix->fillBasis(model,
+                                      pivotTemp + numberRowBasic,
+                                      numberColumnBasic,
+                                      indexRowU,
+                                      startColumnU + numberRowBasic,
+                                      numberInRow,
+                                      numberInColumn + numberRowBasic,
+                                      elementU);
+#if 0
+                    {
+                         printf("%d row basic, %d column basic\n", numberRowBasic, numberColumnBasic);
+                         for (int i = 0; i < numberElements; i++)
+                              printf("row %d col %d value %g\n", indexRowU[i], indexColumnU_[i],
+                                     elementU[i]);
+                    }
+#endif
+                    // recompute number basic
+                    numberBasic = numberRowBasic + numberColumnBasic;
+                    if (numberBasic)
+                         numberElements = startColumnU[numberBasic-1]
+                                          + numberInColumn[numberBasic-1];
+                    else
+                         numberElements = 0;
+                    coinFactorizationA_->setNumberElementsU(numberElements);
+                    //saveFactorization("dump.d");
+                    if (coinFactorizationA_->biasLU() >= 3 || coinFactorizationA_->numberRows() != coinFactorizationA_->numberColumns())
+                         coinFactorizationA_->preProcess ( 2 );
+                    else
+                         coinFactorizationA_->preProcess ( 3 ); // no row copy
+                    coinFactorizationA_->factor (  );
+                    if (coinFactorizationA_->status() == -99) {
+                         // get more memory
+                         coinFactorizationA_->areaFactor(2.0 * coinFactorizationA_->areaFactor());
+                    } else if (coinFactorizationA_->status() == -1 &&
+                               (model->numberIterations() == 0 || nTimesRound > 2) &&
+                               coinFactorizationA_->denseThreshold()) {
+                         // Round again without dense
+                         coinFactorizationA_->setDenseThreshold(0);
+                         coinFactorizationA_->setStatus(-99);
+                    }
+               }
+               // If we get here status is 0 or -1
+               if (coinFactorizationA_->status() == 0) {
+                    // We may need to tamper with order and redo - e.g. network with side
+                    int useNumberRows = numberRows;
+                    // **** we will also need to add test in dual steepest to do
+                    // as we do for network
+                    matrix->generalExpanded(model, 12, useNumberRows);
+                    const int * permuteBack = coinFactorizationA_->permuteBack();
+                    const int * back = coinFactorizationA_->pivotColumnBack();
+                    //int * pivotTemp = pivotColumn_.array();
+                    //ClpDisjointCopyN ( pivotVariable, numberRows , pivotTemp  );
+#ifndef NDEBUG
+                    CoinFillN(pivotVariable, numberRows, -1);
+#endif
+                    // Redo pivot order
+                    for (i = 0; i < numberRowBasic; i++) {
+                         int k = pivotTemp[i];
+                         // so rowIsBasic[k] would be permuteBack[back[i]]
+                         int j = permuteBack[back[i]];
+                         assert (pivotVariable[j] == -1);
+                         pivotVariable[j] = k + numberColumns;
+                    }
+                    for (; i < useNumberRows; i++) {
+                         int k = pivotTemp[i];
+                         // so rowIsBasic[k] would be permuteBack[back[i]]
+                         int j = permuteBack[back[i]];
+                         assert (pivotVariable[j] == -1);
+                         pivotVariable[j] = k;
+                    }
+#if 0
+                    if (numberSave >= 0) {
+                         numberSave = numberDense_;
+                         memset(saveList, 0, ((coinFactorizationA_->numberRows() + 31) >> 5)*sizeof(int));
+                         for (i = coinFactorizationA_->numberRows() - numberSave; i < coinFactorizationA_->numberRows(); i++) {
+                              int k = pivotTemp[pivotColumn_.array()[i]];
+                              setDense(k);
+                         }
+                    }
+#endif
+                    // Set up permutation vector
+                    // these arrays start off as copies of permute
+                    // (and we could use permute_ instead of pivotColumn (not back though))
+                    ClpDisjointCopyN ( coinFactorizationA_->permute(), useNumberRows , coinFactorizationA_->pivotColumn()  );
+                    ClpDisjointCopyN ( coinFactorizationA_->permuteBack(), useNumberRows , coinFactorizationA_->pivotColumnBack()  );
+#ifndef SLIM_CLP
+                    if (networkMatrix) {
+                         maximumPivots(CoinMax(2000, maximumPivots()));
+                         // redo arrays
+                         for (int iRow = 0; iRow < 4; iRow++) {
+                              int length = model->numberRows() + maximumPivots();
+                              if (iRow == 3 || model->objectiveAsObject()->type() > 1)
+                                   length += model->numberColumns();
+                              model->rowArray(iRow)->reserve(length);
+                         }
+                         // create network factorization
+                         if (doCheck)
+                              delete networkBasis_; // temp
+                         networkBasis_ = new ClpNetworkBasis(model, coinFactorizationA_->numberRows(),
+                                                             coinFactorizationA_->pivotRegion(),
+                                                             coinFactorizationA_->permuteBack(),
+                                                             coinFactorizationA_->startColumnU(),
+                                                             coinFactorizationA_->numberInColumn(),
+                                                             coinFactorizationA_->indexRowU(),
+                                                             coinFactorizationA_->elementU());
+                         // kill off arrays in ordinary factorization
+                         if (!doCheck) {
+                              coinFactorizationA_->gutsOfDestructor();
+                              // but make sure coinFactorizationA_->numberRows() set
+                              coinFactorizationA_->setNumberRows(model->numberRows());
+                              coinFactorizationA_->setStatus(0);
+#if 0
+                              // but put back permute arrays so odd things will work
+                              int numberRows = model->numberRows();
+                              pivotColumnBack_ = new int [numberRows];
+                              permute_ = new int [numberRows];
+                              int i;
+                              for (i = 0; i < numberRows; i++) {
+                                   pivotColumnBack_[i] = i;
+                                   permute_[i] = i;
+                              }
+#endif
+                         }
+                    } else {
+#endif
+                         // See if worth going sparse and when
+                         coinFactorizationA_->checkSparse();
+#ifndef SLIM_CLP
+                    }
+#endif
+               } else if (coinFactorizationA_->status() == -1 && (solveType == 0 || solveType == 2)) {
+                    // This needs redoing as it was merged coding - does not need array
+                    int numberTotal = numberRows + numberColumns;
+                    int * isBasic = new int [numberTotal];
+                    int * rowIsBasic = isBasic + numberColumns;
+                    int * columnIsBasic = isBasic;
+                    for (i = 0; i < numberTotal; i++)
+                         isBasic[i] = -1;
+                    for (i = 0; i < numberRowBasic; i++) {
+                         int iRow = pivotTemp[i];
+                         rowIsBasic[iRow] = 1;
+                    }
+                    for (; i < numberBasic; i++) {
+                         int iColumn = pivotTemp[i];
+                         columnIsBasic[iColumn] = 1;
+                    }
+                    numberBasic = 0;
+                    for (i = 0; i < numberRows; i++)
+                         pivotVariable[i] = -1;
+                    // mark as basic or non basic
+                    const int * pivotColumn = coinFactorizationA_->pivotColumn();
+                    for (i = 0; i < numberRows; i++) {
+                         if (rowIsBasic[i] >= 0) {
+                              if (pivotColumn[numberBasic] >= 0) {
+                                   rowIsBasic[i] = pivotColumn[numberBasic];
+                              } else {
+                                   rowIsBasic[i] = -1;
+                                   model->setRowStatus(i, ClpSimplex::superBasic);
+                              }
+                              numberBasic++;
+                         }
+                    }
+                    for (i = 0; i < numberColumns; i++) {
+                         if (columnIsBasic[i] >= 0) {
+                              if (pivotColumn[numberBasic] >= 0)
+                                   columnIsBasic[i] = pivotColumn[numberBasic];
+                              else
+                                   columnIsBasic[i] = -1;
+                              numberBasic++;
+                         }
+                    }
+                    // leave pivotVariable in useful form for cleaning basis
+                    int * pivotVariable = model->pivotVariable();
+                    for (i = 0; i < numberRows; i++) {
+                         pivotVariable[i] = -1;
+                    }
+
+                    for (i = 0; i < numberRows; i++) {
+                         if (model->getRowStatus(i) == ClpSimplex::basic) {
+                              int iPivot = rowIsBasic[i];
+                              if (iPivot >= 0)
+                                   pivotVariable[iPivot] = i + numberColumns;
+                         }
+                    }
+                    for (i = 0; i < numberColumns; i++) {
+                         if (model->getColumnStatus(i) == ClpSimplex::basic) {
+                              int iPivot = columnIsBasic[i];
+                              if (iPivot >= 0)
+                                   pivotVariable[iPivot] = i;
+                         }
+                    }
+                    delete [] isBasic;
+                    double * columnLower = model->lowerRegion();
+                    double * columnUpper = model->upperRegion();
+                    double * columnActivity = model->solutionRegion();
+                    double * rowLower = model->lowerRegion(0);
+                    double * rowUpper = model->upperRegion(0);
+                    double * rowActivity = model->solutionRegion(0);
+                    //redo basis - first take ALL columns out
+                    int iColumn;
+                    double largeValue = model->largeValue();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (model->getColumnStatus(iColumn) == ClpSimplex::basic) {
+                              // take out
+                              if (!valuesPass) {
+                                   double lower = columnLower[iColumn];
+                                   double upper = columnUpper[iColumn];
+                                   double value = columnActivity[iColumn];
+                                   if (lower > -largeValue || upper < largeValue) {
+                                        if (fabs(value - lower) < fabs(value - upper)) {
+                                             model->setColumnStatus(iColumn, ClpSimplex::atLowerBound);
+                                             columnActivity[iColumn] = lower;
+                                        } else {
+                                             model->setColumnStatus(iColumn, ClpSimplex::atUpperBound);
+                                             columnActivity[iColumn] = upper;
+                                        }
+                                   } else {
+                                        model->setColumnStatus(iColumn, ClpSimplex::isFree);
+                                   }
+                              } else {
+                                   model->setColumnStatus(iColumn, ClpSimplex::superBasic);
+                              }
+                         }
+                    }
+                    int iRow;
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         int iSequence = pivotVariable[iRow];
+                         if (iSequence >= 0) {
+                              // basic
+                              if (iSequence >= numberColumns) {
+                                   // slack in - leave
+                                   //assert (iSequence-numberColumns==iRow);
+                              } else {
+                                   assert(model->getRowStatus(iRow) != ClpSimplex::basic);
+                                   // put back structural
+                                   model->setColumnStatus(iSequence, ClpSimplex::basic);
+                              }
+                         } else {
+                              // put in slack
+                              model->setRowStatus(iRow, ClpSimplex::basic);
+                         }
+                    }
+                    // Put back any key variables for gub
+                    int dummy;
+                    matrix->generalExpanded(model, 1, dummy);
+                    // signal repeat
+                    coinFactorizationA_->setStatus(-99);
+                    // set fixed if they are
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         if (model->getRowStatus(iRow) != ClpSimplex::basic ) {
+                              if (rowLower[iRow] == rowUpper[iRow]) {
+                                   rowActivity[iRow] = rowLower[iRow];
+                                   model->setRowStatus(iRow, ClpSimplex::isFixed);
+                              }
+                         }
+                    }
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (model->getColumnStatus(iColumn) != ClpSimplex::basic ) {
+                              if (columnLower[iColumn] == columnUpper[iColumn]) {
+                                   columnActivity[iColumn] = columnLower[iColumn];
+                                   model->setColumnStatus(iColumn, ClpSimplex::isFixed);
+                              }
+                         }
+                    }
+               }
+          }
+#ifndef SLIM_CLP
+     } else {
+          // network - fake factorization - do nothing
+          coinFactorizationA_->setStatus(0);
+          coinFactorizationA_->setPivots(0);
+     }
+#endif
+#ifndef SLIM_CLP
+     if (!coinFactorizationA_->status()) {
+          // take out part if quadratic
+          if (model->algorithm() == 2) {
+               ClpObjective * obj = model->objectiveAsObject();
+#ifndef NDEBUG
+               ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(obj));
+               assert (quadraticObj);
+#else
+ClpQuadraticObjective * quadraticObj = (static_cast< ClpQuadraticObjective*>(obj));
+#endif
+               CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+               int numberXColumns = quadratic->getNumCols();
+               assert (numberXColumns < numberColumns);
+               int base = numberColumns - numberXColumns;
+               int * which = new int [numberXColumns];
+               int * pivotVariable = model->pivotVariable();
+               int * permute = pivotColumn();
+               int i;
+               int n = 0;
+               for (i = 0; i < numberRows; i++) {
+                    int iSj = pivotVariable[i] - base;
+                    if (iSj >= 0 && iSj < numberXColumns)
+                         which[n++] = permute[i];
+               }
+               if (n)
+                    coinFactorizationA_->emptyRows(n, which);
+               delete [] which;
+          }
+     }
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(2);
+#endif
+     return coinFactorizationA_->status();
+}
+/* Replaces one Column in basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+   If checkBeforeModifying is true will do all accuracy checks
+   before modifying factorization.  Whether to set this depends on
+   speed considerations.  You could just do this on first iteration
+   after factorization and thereafter re-factorize
+   partial update already in U */
+int
+ClpFactorization::replaceColumn ( const ClpSimplex * model,
+                                  CoinIndexedVector * regionSparse,
+                                  CoinIndexedVector * tableauColumn,
+                                  int pivotRow,
+                                  double pivotCheck ,
+                                  bool checkBeforeModifying,
+                                  double acceptablePivot)
+{
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          int returnCode;
+          // see if FT
+          if (!coinFactorizationA_ || coinFactorizationA_->forrestTomlin()) {
+               if (coinFactorizationA_) {
+                    returnCode = coinFactorizationA_->replaceColumn(regionSparse,
+                                 pivotRow,
+                                 pivotCheck,
+                                 checkBeforeModifying,
+                                 acceptablePivot);
+               } else {
+                    bool tab = coinFactorizationB_->wantsTableauColumn();
+#ifdef CLP_REUSE_ETAS
+		    int tempInfo[2];
+		    tempInfo[1] = model_->sequenceOut();
+#else
+		    int tempInfo[1];
+#endif
+		    tempInfo[0] = model->numberIterations();
+		    coinFactorizationB_->setUsefulInformation(tempInfo, 1);
+                    returnCode =
+                         coinFactorizationB_->replaceColumn(tab ? tableauColumn : regionSparse,
+                                                            pivotRow,
+                                                            pivotCheck,
+                                                            checkBeforeModifying,
+                                                            acceptablePivot);
+#ifdef CLP_DEBUG
+                    // check basic
+                    int numberRows = coinFactorizationB_->numberRows();
+                    CoinIndexedVector region1(2 * numberRows);
+                    CoinIndexedVector region2A(2 * numberRows);
+                    CoinIndexedVector region2B(2 * numberRows);
+                    int iPivot;
+                    double * arrayB = region2B.denseVector();
+                    int * pivotVariable = model->pivotVariable();
+                    int i;
+                    for (iPivot = 0; iPivot < numberRows; iPivot++) {
+                         int iSequence = pivotVariable[iPivot];
+                         if (iPivot == pivotRow)
+                              iSequence = model->sequenceIn();
+                         model->unpack(&region2B, iSequence);
+                         coinFactorizationB_->updateColumn(&region1, &region2B);
+                         assert (fabs(arrayB[iPivot] - 1.0) < 1.0e-4);
+                         arrayB[iPivot] = 0.0;
+                         for (i = 0; i < numberRows; i++)
+                              assert (fabs(arrayB[i]) < 1.0e-4);
+                         region2B.clear();
+                    }
+#endif
+               }
+          } else {
+               returnCode = coinFactorizationA_->replaceColumnPFI(tableauColumn,
+                            pivotRow, pivotCheck); // Note array
+          }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(3);
+#endif
+          return returnCode;
+
+#ifndef SLIM_CLP
+     } else {
+          if (doCheck) {
+               int returnCode = coinFactorizationA_->replaceColumn(regionSparse,
+                                pivotRow,
+                                pivotCheck,
+                                checkBeforeModifying,
+                                acceptablePivot);
+               networkBasis_->replaceColumn(regionSparse,
+                                            pivotRow);
+               return returnCode;
+          } else {
+               // increase number of pivots
+               coinFactorizationA_->setPivots(coinFactorizationA_->pivots() + 1);
+               return networkBasis_->replaceColumn(regionSparse,
+                                                   pivotRow);
+          }
+     }
+#endif
+}
+
+/* Updates one column (FTRAN) from region2
+   number returned is negative if no room
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateColumnFT ( CoinIndexedVector * regionSparse,
+                                   CoinIndexedVector * regionSparse2)
+{
+#ifdef CLP_DEBUG
+     regionSparse->checkClear();
+#endif
+     if (!numberRows())
+          return 0;
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          int returnCode;
+          if (coinFactorizationA_) {
+               coinFactorizationA_->setCollectStatistics(true);
+               returnCode = coinFactorizationA_->updateColumnFT(regionSparse,
+                            regionSparse2);
+               coinFactorizationA_->setCollectStatistics(false);
+          } else {
+#ifdef CLP_REUSE_ETAS
+              int tempInfo[2];
+	      tempInfo[0] = model_->numberIterations();
+	      tempInfo[1] = model_->sequenceIn();
+	      coinFactorizationB_->setUsefulInformation(tempInfo, 2);
+#endif
+	      returnCode = coinFactorizationB_->updateColumnFT(regionSparse,
+                            regionSparse2);
+          }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(4);
+#endif
+          return returnCode;
+#ifndef SLIM_CLP
+     } else {
+#ifdef CHECK_NETWORK
+          CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
+          double * check = new double[coinFactorizationA_->numberRows()];
+          int returnCode = coinFactorizationA_->updateColumnFT(regionSparse,
+                           regionSparse2);
+          networkBasis_->updateColumn(regionSparse, save, -1);
+          int i;
+          double * array = regionSparse2->denseVector();
+          int * indices = regionSparse2->getIndices();
+          int n = regionSparse2->getNumElements();
+          memset(check, 0, coinFactorizationA_->numberRows()*sizeof(double));
+          double * array2 = save->denseVector();
+          int * indices2 = save->getIndices();
+          int n2 = save->getNumElements();
+          assert (n == n2);
+          if (save->packedMode()) {
+               for (i = 0; i < n; i++) {
+                    check[indices[i]] = array[i];
+               }
+               for (i = 0; i < n; i++) {
+                    double value2 = array2[i];
+                    assert (check[indices2[i]] == value2);
+               }
+          } else {
+               int numberRows = coinFactorizationA_->numberRows();
+               for (i = 0; i < numberRows; i++) {
+                    double value1 = array[i];
+                    double value2 = array2[i];
+                    assert (value1 == value2);
+               }
+          }
+          delete save;
+          delete [] check;
+          return returnCode;
+#else
+networkBasis_->updateColumn(regionSparse, regionSparse2, -1);
+return 1;
+#endif
+     }
+#endif
+}
+/* Updates one column (FTRAN) from region2
+   number returned is negative if no room
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateColumn ( CoinIndexedVector * regionSparse,
+                                 CoinIndexedVector * regionSparse2,
+                                 bool noPermute) const
+{
+#ifdef CLP_DEBUG
+     if (!noPermute)
+          regionSparse->checkClear();
+#endif
+     if (!numberRows())
+          return 0;
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          int returnCode;
+          if (coinFactorizationA_) {
+               coinFactorizationA_->setCollectStatistics(true);
+               returnCode = coinFactorizationA_->updateColumn(regionSparse,
+                            regionSparse2,
+                            noPermute);
+               coinFactorizationA_->setCollectStatistics(false);
+          } else {
+               returnCode = coinFactorizationB_->updateColumn(regionSparse,
+                            regionSparse2,
+                            noPermute);
+          }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(5);
+#endif
+          //#define PRINT_VECTOR
+#ifdef PRINT_VECTOR
+          printf("Update\n");
+          regionSparse2->print();
+#endif
+          return returnCode;
+#ifndef SLIM_CLP
+     } else {
+#ifdef CHECK_NETWORK
+          CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
+          double * check = new double[coinFactorizationA_->numberRows()];
+          int returnCode = coinFactorizationA_->updateColumn(regionSparse,
+                           regionSparse2,
+                           noPermute);
+          networkBasis_->updateColumn(regionSparse, save, -1);
+          int i;
+          double * array = regionSparse2->denseVector();
+          int * indices = regionSparse2->getIndices();
+          int n = regionSparse2->getNumElements();
+          memset(check, 0, coinFactorizationA_->numberRows()*sizeof(double));
+          double * array2 = save->denseVector();
+          int * indices2 = save->getIndices();
+          int n2 = save->getNumElements();
+          assert (n == n2);
+          if (save->packedMode()) {
+               for (i = 0; i < n; i++) {
+                    check[indices[i]] = array[i];
+               }
+               for (i = 0; i < n; i++) {
+                    double value2 = array2[i];
+                    assert (check[indices2[i]] == value2);
+               }
+          } else {
+               int numberRows = coinFactorizationA_->numberRows();
+               for (i = 0; i < numberRows; i++) {
+                    double value1 = array[i];
+                    double value2 = array2[i];
+                    assert (value1 == value2);
+               }
+          }
+          delete save;
+          delete [] check;
+          return returnCode;
+#else
+networkBasis_->updateColumn(regionSparse, regionSparse2, -1);
+return 1;
+#endif
+     }
+#endif
+}
+/* Updates one column (FTRAN) from region2
+   Tries to do FT update
+   number returned is negative if no room.
+   Also updates region3
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateTwoColumnsFT ( CoinIndexedVector * regionSparse1,
+                                       CoinIndexedVector * regionSparse2,
+                                       CoinIndexedVector * regionSparse3,
+                                       bool noPermuteRegion3)
+{
+#ifdef CLP_DEBUG
+     regionSparse1->checkClear();
+#endif
+     if (!numberRows())
+          return 0;
+     int returnCode = 0;
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          if (coinFactorizationA_) {
+               coinFactorizationA_->setCollectStatistics(true);
+               if (coinFactorizationA_->spaceForForrestTomlin()) {
+                    assert (regionSparse2->packedMode());
+                    assert (!regionSparse3->packedMode());
+                    returnCode = coinFactorizationA_->updateTwoColumnsFT(regionSparse1,
+                                 regionSparse2,
+                                 regionSparse3,
+                                 noPermuteRegion3);
+               } else {
+                    returnCode = coinFactorizationA_->updateColumnFT(regionSparse1,
+                                 regionSparse2);
+                    coinFactorizationA_->updateColumn(regionSparse1,
+                                                      regionSparse3,
+                                                      noPermuteRegion3);
+               }
+               coinFactorizationA_->setCollectStatistics(false);
+          } else {
+#if 0
+               CoinSimpFactorization * fact =
+                    dynamic_cast< CoinSimpFactorization*>(coinFactorizationB_);
+               if (!fact) {
+                    returnCode = coinFactorizationB_->updateColumnFT(regionSparse1,
+                                 regionSparse2);
+                    coinFactorizationB_->updateColumn(regionSparse1,
+                                                      regionSparse3,
+                                                      noPermuteRegion3);
+               } else {
+                    returnCode = fact->updateTwoColumnsFT(regionSparse1,
+                                                          regionSparse2,
+                                                          regionSparse3,
+                                                          noPermuteRegion3);
+               }
+#else
+#ifdef CLP_REUSE_ETAS
+		    int tempInfo[2];
+		    tempInfo[0] = model_->numberIterations();
+		    tempInfo[1] = model_->sequenceIn();
+		    coinFactorizationB_->setUsefulInformation(tempInfo, 3);
+#endif
+		    returnCode = 
+		      coinFactorizationB_->updateTwoColumnsFT(
+							      regionSparse1,
+							      regionSparse2,
+							      regionSparse3,
+							      noPermuteRegion3);
+#endif
+          }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(9);
+#endif
+#ifdef PRINT_VECTOR
+          printf("UpdateTwoFT\n");
+          regionSparse2->print();
+          regionSparse3->print();
+#endif
+          return returnCode;
+#ifndef SLIM_CLP
+     } else {
+          returnCode = updateColumnFT(regionSparse1, regionSparse2);
+          updateColumn(regionSparse1, regionSparse3, noPermuteRegion3);
+     }
+#endif
+     return returnCode;
+}
+/* Updates one column (FTRAN) from region2
+   number returned is negative if no room
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateColumnForDebug ( CoinIndexedVector * regionSparse,
+          CoinIndexedVector * regionSparse2,
+          bool noPermute) const
+{
+     if (!noPermute)
+          regionSparse->checkClear();
+     if (!coinFactorizationA_->numberRows())
+          return 0;
+     coinFactorizationA_->setCollectStatistics(false);
+     int returnCode = coinFactorizationA_->updateColumn(regionSparse,
+                      regionSparse2,
+                      noPermute);
+     return returnCode;
+}
+/* Updates one column (BTRAN) from region2
+   region1 starts as zero and is zero at end */
+int
+ClpFactorization::updateColumnTranspose ( CoinIndexedVector * regionSparse,
+          CoinIndexedVector * regionSparse2) const
+{
+     if (!numberRows())
+          return 0;
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(-1);
+#endif
+          int returnCode;
+
+          if (coinFactorizationA_) {
+               coinFactorizationA_->setCollectStatistics(true);
+               returnCode =  coinFactorizationA_->updateColumnTranspose(regionSparse,
+                             regionSparse2);
+               coinFactorizationA_->setCollectStatistics(false);
+          } else {
+               returnCode = coinFactorizationB_->updateColumnTranspose(regionSparse,
+                            regionSparse2);
+          }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+          factorization_instrument(6);
+#endif
+#ifdef PRINT_VECTOR
+          printf("UpdateTranspose\n");
+          regionSparse2->print();
+#endif
+          return returnCode;
+#ifndef SLIM_CLP
+     } else {
+#ifdef CHECK_NETWORK
+          CoinIndexedVector * save = new CoinIndexedVector(*regionSparse2);
+          double * check = new double[coinFactorizationA_->numberRows()];
+          int returnCode = coinFactorizationA_->updateColumnTranspose(regionSparse,
+                           regionSparse2);
+          networkBasis_->updateColumnTranspose(regionSparse, save);
+          int i;
+          double * array = regionSparse2->denseVector();
+          int * indices = regionSparse2->getIndices();
+          int n = regionSparse2->getNumElements();
+          memset(check, 0, coinFactorizationA_->numberRows()*sizeof(double));
+          double * array2 = save->denseVector();
+          int * indices2 = save->getIndices();
+          int n2 = save->getNumElements();
+          assert (n == n2);
+          if (save->packedMode()) {
+               for (i = 0; i < n; i++) {
+                    check[indices[i]] = array[i];
+               }
+               for (i = 0; i < n; i++) {
+                    double value2 = array2[i];
+                    assert (check[indices2[i]] == value2);
+               }
+          } else {
+               int numberRows = coinFactorizationA_->numberRows();
+               for (i = 0; i < numberRows; i++) {
+                    double value1 = array[i];
+                    double value2 = array2[i];
+                    assert (value1 == value2);
+               }
+          }
+          delete save;
+          delete [] check;
+          return returnCode;
+#else
+return networkBasis_->updateColumnTranspose(regionSparse, regionSparse2);
+#endif
+     }
+#endif
+}
+/* makes a row copy of L for speed and to allow very sparse problems */
+void
+ClpFactorization::goSparse()
+{
+#ifndef SLIM_CLP
+     if (!networkBasis_) {
+#endif
+          if (coinFactorizationA_) {
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+               factorization_instrument(-1);
+#endif
+               coinFactorizationA_->goSparse();
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+               factorization_instrument(7);
+#endif
+          }
+     }
+}
+// Cleans up i.e. gets rid of network basis
+void
+ClpFactorization::cleanUp()
+{
+#ifndef SLIM_CLP
+     delete networkBasis_;
+     networkBasis_ = NULL;
+#endif
+     if (coinFactorizationA_)
+          coinFactorizationA_->resetStatistics();
+}
+/// Says whether to redo pivot order
+bool
+ClpFactorization::needToReorder() const
+{
+#ifdef CHECK_NETWORK
+     return true;
+#endif
+#ifndef SLIM_CLP
+     if (!networkBasis_)
+#endif
+          return true;
+#ifndef SLIM_CLP
+     else
+          return false;
+#endif
+}
+// Get weighted row list
+void
+ClpFactorization::getWeights(int * weights) const
+{
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(-1);
+#endif
+#ifndef SLIM_CLP
+     if (networkBasis_) {
+          // Network - just unit
+          int numberRows = coinFactorizationA_->numberRows();
+          for (int i = 0; i < numberRows; i++)
+               weights[i] = 1;
+          return;
+     }
+#endif
+     int * numberInRow = coinFactorizationA_->numberInRow();
+     int * numberInColumn = coinFactorizationA_->numberInColumn();
+     int * permuteBack = coinFactorizationA_->pivotColumnBack();
+     int * indexRowU = coinFactorizationA_->indexRowU();
+     const CoinBigIndex * startColumnU = coinFactorizationA_->startColumnU();
+     const CoinBigIndex * startRowL = coinFactorizationA_->startRowL();
+     int numberRows = coinFactorizationA_->numberRows();
+     if (!startRowL || !coinFactorizationA_->numberInRow()) {
+          int * temp = new int[numberRows];
+          memset(temp, 0, numberRows * sizeof(int));
+          int i;
+          for (i = 0; i < numberRows; i++) {
+               // one for pivot
+               temp[i]++;
+               CoinBigIndex j;
+               for (j = startColumnU[i]; j < startColumnU[i] + numberInColumn[i]; j++) {
+                    int iRow = indexRowU[j];
+                    temp[iRow]++;
+               }
+          }
+          CoinBigIndex * startColumnL = coinFactorizationA_->startColumnL();
+          int * indexRowL = coinFactorizationA_->indexRowL();
+          int numberL = coinFactorizationA_->numberL();
+          CoinBigIndex baseL = coinFactorizationA_->baseL();
+          for (i = baseL; i < baseL + numberL; i++) {
+               CoinBigIndex j;
+               for (j = startColumnL[i]; j < startColumnL[i+1]; j++) {
+                    int iRow = indexRowL[j];
+                    temp[iRow]++;
+               }
+          }
+          for (i = 0; i < numberRows; i++) {
+               int number = temp[i];
+               int iPermute = permuteBack[i];
+               weights[iPermute] = number;
+          }
+          delete [] temp;
+     } else {
+          int i;
+          for (i = 0; i < numberRows; i++) {
+               int number = startRowL[i+1] - startRowL[i] + numberInRow[i] + 1;
+               //number = startRowL[i+1]-startRowL[i]+1;
+               //number = numberInRow[i]+1;
+               int iPermute = permuteBack[i];
+               weights[iPermute] = number;
+          }
+     }
+#ifdef CLP_FACTORIZATION_INSTRUMENT
+     factorization_instrument(8);
+#endif
+}
+// Set tolerances to safer of existing and given
+void
+ClpFactorization::saferTolerances (  double zeroValue,
+                                     double pivotValue)
+{
+     double newValue;
+     // better to have small tolerance even if slower
+     if (zeroValue > 0.0)
+          newValue = zeroValue;
+     else
+          newValue = -zeroTolerance() * zeroValue;
+     zeroTolerance(CoinMin(zeroTolerance(), zeroValue));
+     // better to have large tolerance even if slower
+     if (pivotValue > 0.0)
+          newValue = pivotValue;
+     else
+          newValue = -pivotTolerance() * pivotValue;
+     pivotTolerance(CoinMin(CoinMax(pivotTolerance(), newValue), 0.999));
+}
+// Sets factorization
+void
+ClpFactorization::setFactorization(ClpFactorization & rhs)
+{
+     ClpFactorization::operator=(rhs);
+}
+#endif
diff --git a/cbits/coin/ClpFactorization.hpp b/cbits/coin/ClpFactorization.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpFactorization.hpp
@@ -0,0 +1,426 @@
+/* $Id: ClpFactorization.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpFactorization_H
+#define ClpFactorization_H
+
+
+#include "CoinPragma.hpp"
+
+#include "CoinFactorization.hpp"
+class ClpMatrixBase;
+class ClpSimplex;
+class ClpNetworkBasis;
+class CoinOtherFactorization;
+#ifndef CLP_MULTIPLE_FACTORIZATIONS
+#define CLP_MULTIPLE_FACTORIZATIONS 4
+#endif
+#ifdef CLP_MULTIPLE_FACTORIZATIONS
+#include "CoinDenseFactorization.hpp"
+#include "ClpSimplex.hpp"
+#endif
+#ifndef COIN_FAST_CODE
+#define COIN_FAST_CODE
+#endif
+
+/** This just implements CoinFactorization when an ClpMatrixBase object
+    is passed.  If a network then has a dummy CoinFactorization and
+    a genuine ClpNetworkBasis object
+*/
+class ClpFactorization
+#ifndef CLP_MULTIPLE_FACTORIZATIONS
+     : public CoinFactorization
+#endif
+{
+
+     //friend class CoinFactorization;
+
+public:
+     /**@name factorization */
+     //@{
+     /** When part of LP - given by basic variables.
+     Actually does factorization.
+     Arrays passed in have non negative value to say basic.
+     If status is okay, basic variables have pivot row - this is only needed
+     if increasingRows_ >1.
+     Allows scaling
+     If status is singular, then basic variables have pivot row
+     and ones thrown out have -1
+     returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
+     int factorize (ClpSimplex * model, int solveType, bool valuesPass);
+     //@}
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpFactorization();
+     /** Destructor */
+     ~ClpFactorization();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor from an CoinFactorization. */
+     ClpFactorization(const CoinFactorization&);
+     /** The copy constructor. */
+     ClpFactorization(const ClpFactorization&, int denseIfSmaller = 0);
+#ifdef CLP_MULTIPLE_FACTORIZATIONS
+     /** The copy constructor from an CoinOtherFactorization. */
+     ClpFactorization(const CoinOtherFactorization&);
+#endif
+     ClpFactorization& operator=(const ClpFactorization&);
+     //@}
+
+     /*  **** below here is so can use networkish basis */
+     /**@name rank one updates which do exist */
+     //@{
+
+     /** Replaces one Column to basis,
+      returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+         If checkBeforeModifying is true will do all accuracy checks
+         before modifying factorization.  Whether to set this depends on
+         speed considerations.  You could just do this on first iteration
+         after factorization and thereafter re-factorize
+      partial update already in U */
+     int replaceColumn ( const ClpSimplex * model,
+                         CoinIndexedVector * regionSparse,
+                         CoinIndexedVector * tableauColumn,
+                         int pivotRow,
+                         double pivotCheck ,
+                         bool checkBeforeModifying = false,
+                         double acceptablePivot = 1.0e-8);
+     //@}
+
+     /**@name various uses of factorization (return code number elements)
+      which user may want to know about */
+     //@{
+     /** Updates one column (FTRAN) from region2
+         Tries to do FT update
+         number returned is negative if no room
+         region1 starts as zero and is zero at end */
+     int updateColumnFT ( CoinIndexedVector * regionSparse,
+                          CoinIndexedVector * regionSparse2);
+     /** Updates one column (FTRAN) from region2
+         region1 starts as zero and is zero at end */
+     int updateColumn ( CoinIndexedVector * regionSparse,
+                        CoinIndexedVector * regionSparse2,
+                        bool noPermute = false) const;
+     /** Updates one column (FTRAN) from region2
+         Tries to do FT update
+         number returned is negative if no room.
+         Also updates region3
+         region1 starts as zero and is zero at end */
+     int updateTwoColumnsFT ( CoinIndexedVector * regionSparse1,
+                              CoinIndexedVector * regionSparse2,
+                              CoinIndexedVector * regionSparse3,
+                              bool noPermuteRegion3 = false) ;
+     /// For debug (no statistics update)
+     int updateColumnForDebug ( CoinIndexedVector * regionSparse,
+                                CoinIndexedVector * regionSparse2,
+                                bool noPermute = false) const;
+     /** Updates one column (BTRAN) from region2
+         region1 starts as zero and is zero at end */
+     int updateColumnTranspose ( CoinIndexedVector * regionSparse,
+                                 CoinIndexedVector * regionSparse2) const;
+     //@}
+#ifdef CLP_MULTIPLE_FACTORIZATIONS
+     /**@name Lifted from CoinFactorization */
+     //@{
+     /// Total number of elements in factorization
+     inline int numberElements (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->numberElements();
+          else return coinFactorizationB_->numberElements() ;
+     }
+     /// Returns address of permute region
+     inline int *permute (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->permute();
+          else return coinFactorizationB_->permute() ;
+     }
+     /// Returns address of pivotColumn region (also used for permuting)
+     inline int *pivotColumn (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->pivotColumn();
+          else return coinFactorizationB_->permute() ;
+     }
+     /// Maximum number of pivots between factorizations
+     inline int maximumPivots (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->maximumPivots();
+          else return coinFactorizationB_->maximumPivots() ;
+     }
+     /// Set maximum number of pivots between factorizations
+     inline void maximumPivots (  int value) {
+          if (coinFactorizationA_) coinFactorizationA_->maximumPivots(value);
+          else coinFactorizationB_->maximumPivots(value);
+     }
+     /// Returns number of pivots since factorization
+     inline int pivots (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->pivots();
+          else return coinFactorizationB_->pivots() ;
+     }
+     /// Whether larger areas needed
+     inline double areaFactor (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->areaFactor();
+          else return 0.0 ;
+     }
+     /// Set whether larger areas needed
+     inline void areaFactor ( double value) {
+          if (coinFactorizationA_) coinFactorizationA_->areaFactor(value);
+     }
+     /// Zero tolerance
+     inline double zeroTolerance (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->zeroTolerance();
+          else return coinFactorizationB_->zeroTolerance() ;
+     }
+     /// Set zero tolerance
+     inline void zeroTolerance (  double value) {
+          if (coinFactorizationA_) coinFactorizationA_->zeroTolerance(value);
+          else coinFactorizationB_->zeroTolerance(value);
+     }
+     /// Set tolerances to safer of existing and given
+     void saferTolerances (  double zeroTolerance, double pivotTolerance);
+     /**  get sparse threshold */
+     inline int sparseThreshold ( ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->sparseThreshold();
+          else return 0 ;
+     }
+     /**  Set sparse threshold */
+     inline void sparseThreshold ( int value) {
+          if (coinFactorizationA_) coinFactorizationA_->sparseThreshold(value);
+     }
+     /// Returns status
+     inline int status (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->status();
+          else return coinFactorizationB_->status() ;
+     }
+     /// Sets status
+     inline void setStatus (  int value) {
+          if (coinFactorizationA_) coinFactorizationA_->setStatus(value);
+          else coinFactorizationB_->setStatus(value) ;
+     }
+     /// Returns number of dense rows
+     inline int numberDense() const {
+          if (coinFactorizationA_) return coinFactorizationA_->numberDense();
+          else return 0 ;
+     }
+#if 1
+     /// Returns number in U area
+     inline CoinBigIndex numberElementsU (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->numberElementsU();
+          else return -1 ;
+     }
+     /// Returns number in L area
+     inline CoinBigIndex numberElementsL (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->numberElementsL();
+          else return -1 ;
+     }
+     /// Returns number in R area
+     inline CoinBigIndex numberElementsR (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->numberElementsR();
+          else return 0 ;
+     }
+#endif
+     inline bool timeToRefactorize() const {
+          if (coinFactorizationA_) {
+               return (coinFactorizationA_->pivots() * 3 > coinFactorizationA_->maximumPivots() * 2 &&
+                       coinFactorizationA_->numberElementsR() * 3 > (coinFactorizationA_->numberElementsL() +
+                                 coinFactorizationA_->numberElementsU()) * 2 + 1000 &&
+                       !coinFactorizationA_->numberDense());
+          } else {
+               return coinFactorizationB_->pivots() > coinFactorizationB_->numberRows() / 2.45 + 20;
+          }
+     }
+     /// Level of detail of messages
+     inline int messageLevel (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->messageLevel();
+          else return 1 ;
+     }
+     /// Set level of detail of messages
+     inline void messageLevel (  int value) {
+          if (coinFactorizationA_) coinFactorizationA_->messageLevel(value);
+     }
+     /// Get rid of all memory
+     inline void clearArrays() {
+          if (coinFactorizationA_)
+               coinFactorizationA_->clearArrays();
+          else if (coinFactorizationB_)
+               coinFactorizationB_->clearArrays();
+     }
+     /// Number of Rows after factorization
+     inline int numberRows (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->numberRows();
+          else return coinFactorizationB_->numberRows() ;
+     }
+     /// Gets dense threshold
+     inline int denseThreshold() const {
+          if (coinFactorizationA_) return coinFactorizationA_->denseThreshold();
+          else return 0 ;
+     }
+     /// Sets dense threshold
+     inline void setDenseThreshold(int value) {
+          if (coinFactorizationA_) coinFactorizationA_->setDenseThreshold(value);
+     }
+     /// Pivot tolerance
+     inline double pivotTolerance (  ) const {
+          if (coinFactorizationA_) return coinFactorizationA_->pivotTolerance();
+          else if (coinFactorizationB_) return coinFactorizationB_->pivotTolerance();
+          return 1.0e-8 ;
+     }
+     /// Set pivot tolerance
+     inline void pivotTolerance (  double value) {
+          if (coinFactorizationA_) coinFactorizationA_->pivotTolerance(value);
+          else if (coinFactorizationB_) coinFactorizationB_->pivotTolerance(value);
+     }
+     /// Allows change of pivot accuracy check 1.0 == none >1.0 relaxed
+     inline void relaxAccuracyCheck(double value) {
+          if (coinFactorizationA_) coinFactorizationA_->relaxAccuracyCheck(value);
+     }
+     /** Array persistence flag
+         If 0 then as now (delete/new)
+         1 then only do arrays if bigger needed
+         2 as 1 but give a bit extra if bigger needed
+     */
+     inline int persistenceFlag() const {
+          if (coinFactorizationA_) return coinFactorizationA_->persistenceFlag();
+          else return 0 ;
+     }
+     inline void setPersistenceFlag(int value) {
+          if (coinFactorizationA_) coinFactorizationA_->setPersistenceFlag(value);
+     }
+     /// Delete all stuff (leaves as after CoinFactorization())
+     inline void almostDestructor() {
+          if (coinFactorizationA_)
+               coinFactorizationA_->almostDestructor();
+          else if (coinFactorizationB_)
+               coinFactorizationB_->clearArrays();
+     }
+     /// Returns areaFactor but adjusted for dense
+     inline double adjustedAreaFactor() const {
+          if (coinFactorizationA_) return coinFactorizationA_->adjustedAreaFactor();
+          else return 0.0 ;
+     }
+     inline void setBiasLU(int value) {
+          if (coinFactorizationA_) coinFactorizationA_->setBiasLU(value);
+     }
+     /// true if Forrest Tomlin update, false if PFI
+     inline void setForrestTomlin(bool value) {
+          if (coinFactorizationA_) coinFactorizationA_->setForrestTomlin(value);
+     }
+     /// Sets default values
+     inline void setDefaultValues() {
+          if (coinFactorizationA_) {
+               // row activities have negative sign
+#ifndef COIN_FAST_CODE
+               coinFactorizationA_->slackValue(-1.0);
+#endif
+               coinFactorizationA_->zeroTolerance(1.0e-13);
+          }
+     }
+     /// If nonzero force use of 1,dense 2,small 3,osl
+     void forceOtherFactorization(int which);
+     /// Get switch to osl if number rows <= this
+     inline int goOslThreshold() const {
+          return goOslThreshold_;
+     }
+     /// Set switch to osl if number rows <= this
+     inline void setGoOslThreshold(int value) {
+          goOslThreshold_ = value;
+     }
+     /// Get switch to dense if number rows <= this
+     inline int goDenseThreshold() const {
+          return goDenseThreshold_;
+     }
+     /// Set switch to dense if number rows <= this
+     inline void setGoDenseThreshold(int value) {
+          goDenseThreshold_ = value;
+     }
+     /// Get switch to small if number rows <= this
+     inline int goSmallThreshold() const {
+          return goSmallThreshold_;
+     }
+     /// Set switch to small if number rows <= this
+     inline void setGoSmallThreshold(int value) {
+          goSmallThreshold_ = value;
+     }
+     /// Go over to dense or small code if small enough
+     void goDenseOrSmall(int numberRows) ;
+     /// Sets factorization
+     void setFactorization(ClpFactorization & factorization);
+     /// Return 1 if dense code
+     inline int isDenseOrSmall() const {
+          return coinFactorizationB_ ? 1 : 0;
+     }
+#else
+     inline bool timeToRefactorize() const {
+          return (pivots() * 3 > maximumPivots() * 2 &&
+                  numberElementsR() * 3 > (numberElementsL() + numberElementsU()) * 2 + 1000 &&
+                  !numberDense());
+     }
+     /// Sets default values
+     inline void setDefaultValues() {
+          // row activities have negative sign
+#ifndef COIN_FAST_CODE
+          slackValue(-1.0);
+#endif
+          zeroTolerance(1.0e-13);
+     }
+     /// Go over to dense code
+     inline void goDense() {}
+#endif
+     //@}
+
+     /**@name other stuff */
+     //@{
+     /** makes a row copy of L for speed and to allow very sparse problems */
+     void goSparse();
+     /// Cleans up i.e. gets rid of network basis
+     void cleanUp();
+     /// Says whether to redo pivot order
+     bool needToReorder() const;
+#ifndef SLIM_CLP
+     /// Says if a network basis
+     inline bool networkBasis() const {
+          return (networkBasis_ != NULL);
+     }
+#else
+     /// Says if a network basis
+     inline bool networkBasis() const {
+          return false;
+     }
+#endif
+     /// Fills weighted row list
+     void getWeights(int * weights) const;
+     //@}
+
+////////////////// data //////////////////
+private:
+
+     /**@name data */
+     //@{
+     /// Pointer to network basis
+#ifndef SLIM_CLP
+     ClpNetworkBasis * networkBasis_;
+#endif
+#ifdef CLP_MULTIPLE_FACTORIZATIONS
+     /// Pointer to CoinFactorization
+     CoinFactorization * coinFactorizationA_;
+     /// Pointer to CoinOtherFactorization
+     CoinOtherFactorization * coinFactorizationB_;
+#ifdef CLP_REUSE_ETAS
+     /// Pointer to model
+     ClpSimplex * model_;
+#endif
+     /// If nonzero force use of 1,dense 2,small 3,osl
+     int forceB_;
+     /// Switch to osl if number rows <= this
+     int goOslThreshold_;
+     /// Switch to small if number rows <= this
+     int goSmallThreshold_;
+     /// Switch to dense if number rows <= this
+     int goDenseThreshold_;
+#endif
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpGubDynamicMatrix.cpp b/cbits/coin/ClpGubDynamicMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpGubDynamicMatrix.cpp
@@ -0,0 +1,2166 @@
+/* $Id: ClpGubDynamicMatrix.cpp 1732 2011-05-31 08:09:41Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include <cstdio>
+
+#include "CoinPragma.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpQuadraticObjective.hpp"
+#include "ClpNonLinearCost.hpp"
+// at end to get min/max!
+#include "ClpGubDynamicMatrix.hpp"
+#include "ClpMessage.hpp"
+//#define CLP_DEBUG
+//#define CLP_DEBUG_PRINT
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpGubDynamicMatrix::ClpGubDynamicMatrix ()
+     : ClpGubMatrix(),
+       objectiveOffset_(0.0),
+       startColumn_(NULL),
+       row_(NULL),
+       element_(NULL),
+       cost_(NULL),
+       fullStart_(NULL),
+       id_(NULL),
+       dynamicStatus_(NULL),
+       lowerColumn_(NULL),
+       upperColumn_(NULL),
+       lowerSet_(NULL),
+       upperSet_(NULL),
+       numberGubColumns_(0),
+       firstAvailable_(0),
+       savedFirstAvailable_(0),
+       firstDynamic_(0),
+       lastDynamic_(0),
+       numberElements_(0)
+{
+     setType(13);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpGubDynamicMatrix::ClpGubDynamicMatrix (const ClpGubDynamicMatrix & rhs)
+     : ClpGubMatrix(rhs)
+{
+     objectiveOffset_ = rhs.objectiveOffset_;
+     numberGubColumns_ = rhs.numberGubColumns_;
+     firstAvailable_ = rhs.firstAvailable_;
+     savedFirstAvailable_ = rhs.savedFirstAvailable_;
+     firstDynamic_ = rhs.firstDynamic_;
+     lastDynamic_ = rhs.lastDynamic_;
+     numberElements_ = rhs.numberElements_;
+     startColumn_ = ClpCopyOfArray(rhs.startColumn_, numberGubColumns_ + 1);
+     CoinBigIndex numberElements = startColumn_[numberGubColumns_];
+     row_ = ClpCopyOfArray(rhs.row_, numberElements);;
+     element_ = ClpCopyOfArray(rhs.element_, numberElements);;
+     cost_ = ClpCopyOfArray(rhs.cost_, numberGubColumns_);
+     fullStart_ = ClpCopyOfArray(rhs.fullStart_, numberSets_ + 1);
+     id_ = ClpCopyOfArray(rhs.id_, lastDynamic_ - firstDynamic_);
+     lowerColumn_ = ClpCopyOfArray(rhs.lowerColumn_, numberGubColumns_);
+     upperColumn_ = ClpCopyOfArray(rhs.upperColumn_, numberGubColumns_);
+     dynamicStatus_ = ClpCopyOfArray(rhs.dynamicStatus_, numberGubColumns_);
+     lowerSet_ = ClpCopyOfArray(rhs.lowerSet_, numberSets_);
+     upperSet_ = ClpCopyOfArray(rhs.upperSet_, numberSets_);
+}
+
+/* This is the real constructor*/
+ClpGubDynamicMatrix::ClpGubDynamicMatrix(ClpSimplex * model, int numberSets,
+          int numberGubColumns, const int * starts,
+          const double * lower, const double * upper,
+          const CoinBigIndex * startColumn, const int * row,
+          const double * element, const double * cost,
+          const double * lowerColumn, const double * upperColumn,
+          const unsigned char * status)
+     : ClpGubMatrix()
+{
+     objectiveOffset_ = model->objectiveOffset();
+     model_ = model;
+     numberSets_ = numberSets;
+     numberGubColumns_ = numberGubColumns;
+     fullStart_ = ClpCopyOfArray(starts, numberSets_ + 1);
+     lower_ = ClpCopyOfArray(lower, numberSets_);
+     upper_ = ClpCopyOfArray(upper, numberSets_);
+     int numberColumns = model->numberColumns();
+     int numberRows = model->numberRows();
+     // Number of columns needed
+     int numberGubInSmall = numberSets_ + numberRows + 2 * model->factorizationFrequency() + 2;
+     // for small problems this could be too big
+     //numberGubInSmall = CoinMin(numberGubInSmall,numberGubColumns_);
+     int numberNeeded = numberGubInSmall + numberColumns;
+     firstAvailable_ = numberColumns;
+     savedFirstAvailable_ = numberColumns;
+     firstDynamic_ = numberColumns;
+     lastDynamic_ = numberNeeded;
+     startColumn_ = ClpCopyOfArray(startColumn, numberGubColumns_ + 1);
+     CoinBigIndex numberElements = startColumn_[numberGubColumns_];
+     row_ = ClpCopyOfArray(row, numberElements);
+     element_ = new double[numberElements];
+     CoinBigIndex i;
+     for (i = 0; i < numberElements; i++)
+          element_[i] = element[i];
+     cost_ = new double[numberGubColumns_];
+     for (i = 0; i < numberGubColumns_; i++) {
+          cost_[i] = cost[i];
+          // need sorted
+          CoinSort_2(row_ + startColumn_[i], row_ + startColumn_[i+1], element_ + startColumn_[i]);
+     }
+     if (lowerColumn) {
+          lowerColumn_ = new double[numberGubColumns_];
+          for (i = 0; i < numberGubColumns_; i++)
+               lowerColumn_[i] = lowerColumn[i];
+     } else {
+          lowerColumn_ = NULL;
+     }
+     if (upperColumn) {
+          upperColumn_ = new double[numberGubColumns_];
+          for (i = 0; i < numberGubColumns_; i++)
+               upperColumn_[i] = upperColumn[i];
+     } else {
+          upperColumn_ = NULL;
+     }
+     if (upperColumn || lowerColumn) {
+          lowerSet_ = new double[numberSets_];
+          for (i = 0; i < numberSets_; i++) {
+               if (lower[i] > -1.0e20)
+                    lowerSet_[i] = lower[i];
+               else
+                    lowerSet_[i] = -1.0e30;
+          }
+          upperSet_ = new double[numberSets_];
+          for (i = 0; i < numberSets_; i++) {
+               if (upper[i] < 1.0e20)
+                    upperSet_[i] = upper[i];
+               else
+                    upperSet_[i] = 1.0e30;
+          }
+     } else {
+          lowerSet_ = NULL;
+          upperSet_ = NULL;
+     }
+     start_ = NULL;
+     end_ = NULL;
+     dynamicStatus_ = NULL;
+     id_ = new int[numberGubInSmall];
+     for (i = 0; i < numberGubInSmall; i++)
+          id_[i] = -1;
+     ClpPackedMatrix* originalMatrixA =
+          dynamic_cast< ClpPackedMatrix*>(model->clpMatrix());
+     assert (originalMatrixA);
+     CoinPackedMatrix * originalMatrix = originalMatrixA->getPackedMatrix();
+     originalMatrixA->setMatrixNull(); // so can be deleted safely
+     // guess how much space needed
+     double guess = originalMatrix->getNumElements() + 10;
+     guess /= static_cast<double> (numberColumns);
+     guess *= 2 * numberGubColumns_;
+     numberElements_ = static_cast<int> (CoinMin(guess, 10000000.0));
+     numberElements_ = CoinMin(numberElements_, numberElements) + originalMatrix->getNumElements();
+     matrix_ = originalMatrix;
+     flags_ &= ~1;
+     // resize model (matrix stays same)
+     model->resize(numberRows, numberNeeded);
+     if (upperColumn_) {
+          // set all upper bounds so we have enough space
+          double * columnUpper = model->columnUpper();
+          for(i = firstDynamic_; i < lastDynamic_; i++)
+               columnUpper[i] = 1.0e10;
+     }
+     // resize matrix
+     // extra 1 is so can keep number of elements handy
+     originalMatrix->reserve(numberNeeded, numberElements_, true);
+     originalMatrix->reserve(numberNeeded + 1, numberElements_, false);
+     originalMatrix->getMutableVectorStarts()[numberColumns] = originalMatrix->getNumElements();
+     // redo number of columns
+     numberColumns = matrix_->getNumCols();
+     backward_ = new int[numberNeeded];
+     backToPivotRow_ = new int[numberNeeded];
+     // We know a bit better
+     delete [] changeCost_;
+     changeCost_ = new double [numberRows+numberSets_];
+     keyVariable_ = new int[numberSets_];
+     // signal to need new ordering
+     next_ = NULL;
+     for (int iColumn = 0; iColumn < numberNeeded; iColumn++)
+          backward_[iColumn] = -1;
+
+     firstGub_ = firstDynamic_;
+     lastGub_ = lastDynamic_;
+     if (!lowerColumn_ && !upperColumn_)
+          gubType_ = 8;
+     if (status) {
+          status_ = ClpCopyOfArray(status, numberSets_);
+     } else {
+          status_ = new unsigned char [numberSets_];
+          memset(status_, 0, numberSets_);
+          int i;
+          for (i = 0; i < numberSets_; i++) {
+               // make slack key
+               setStatus(i, ClpSimplex::basic);
+          }
+     }
+     saveStatus_ = new unsigned char [numberSets_];
+     memset(saveStatus_, 0, numberSets_);
+     savedKeyVariable_ = new int [numberSets_];
+     memset(savedKeyVariable_, 0, numberSets_ * sizeof(int));
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpGubDynamicMatrix::~ClpGubDynamicMatrix ()
+{
+     delete [] startColumn_;
+     delete [] row_;
+     delete [] element_;
+     delete [] cost_;
+     delete [] fullStart_;
+     delete [] id_;
+     delete [] dynamicStatus_;
+     delete [] lowerColumn_;
+     delete [] upperColumn_;
+     delete [] lowerSet_;
+     delete [] upperSet_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpGubDynamicMatrix &
+ClpGubDynamicMatrix::operator=(const ClpGubDynamicMatrix& rhs)
+{
+     if (this != &rhs) {
+          ClpGubMatrix::operator=(rhs);
+          delete [] startColumn_;
+          delete [] row_;
+          delete [] element_;
+          delete [] cost_;
+          delete [] fullStart_;
+          delete [] id_;
+          delete [] dynamicStatus_;
+          delete [] lowerColumn_;
+          delete [] upperColumn_;
+          delete [] lowerSet_;
+          delete [] upperSet_;
+          objectiveOffset_ = rhs.objectiveOffset_;
+          numberGubColumns_ = rhs.numberGubColumns_;
+          firstAvailable_ = rhs.firstAvailable_;
+          savedFirstAvailable_ = rhs.savedFirstAvailable_;
+          firstDynamic_ = rhs.firstDynamic_;
+          lastDynamic_ = rhs.lastDynamic_;
+          numberElements_ = rhs.numberElements_;
+          startColumn_ = ClpCopyOfArray(rhs.startColumn_, numberGubColumns_ + 1);
+          int numberElements = startColumn_[numberGubColumns_];
+          row_ = ClpCopyOfArray(rhs.row_, numberElements);;
+          element_ = ClpCopyOfArray(rhs.element_, numberElements);;
+          cost_ = ClpCopyOfArray(rhs.cost_, numberGubColumns_);
+          fullStart_ = ClpCopyOfArray(rhs.fullStart_, numberSets_ + 1);
+          id_ = ClpCopyOfArray(rhs.id_, lastDynamic_ - firstDynamic_);
+          lowerColumn_ = ClpCopyOfArray(rhs.lowerColumn_, numberGubColumns_);
+          upperColumn_ = ClpCopyOfArray(rhs.upperColumn_, numberGubColumns_);
+          dynamicStatus_ = ClpCopyOfArray(rhs.dynamicStatus_, numberGubColumns_);
+          lowerSet_ = ClpCopyOfArray(rhs.lowerSet_, numberSets_);
+          upperSet_ = ClpCopyOfArray(rhs.upperSet_, numberSets_);
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpMatrixBase * ClpGubDynamicMatrix::clone() const
+{
+     return new ClpGubDynamicMatrix(*this);
+}
+// Partial pricing
+void
+ClpGubDynamicMatrix::partialPricing(ClpSimplex * model, double startFraction, double endFraction,
+                                    int & bestSequence, int & numberWanted)
+{
+     assert(!model->rowScale());
+     numberWanted = currentWanted_;
+     if (!numberSets_) {
+          // no gub
+          ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
+          return;
+     } else {
+          // and do some proportion of full set
+          int startG2 = static_cast<int> (startFraction * numberSets_);
+          int endG2 = static_cast<int> (endFraction * numberSets_ + 0.1);
+          endG2 = CoinMin(endG2, numberSets_);
+          //printf("gub price - set start %d end %d\n",
+          //   startG2,endG2);
+          double tolerance = model->currentDualTolerance();
+          double * reducedCost = model->djRegion();
+          const double * duals = model->dualRowSolution();
+          double * cost = model->costRegion();
+          double bestDj;
+          int numberRows = model->numberRows();
+          int numberColumns = lastDynamic_;
+          // If nothing found yet can go all the way to end
+          int endAll = endG2;
+          if (bestSequence < 0 && !startG2)
+               endAll = numberSets_;
+          if (bestSequence >= 0)
+               bestDj = fabs(reducedCost[bestSequence]);
+          else
+               bestDj = tolerance;
+          int saveSequence = bestSequence;
+          double djMod = 0.0;
+          double infeasibilityCost = model->infeasibilityCost();
+          double bestDjMod = 0.0;
+          //printf("iteration %d start %d end %d - wanted %d\n",model->numberIterations(),
+          //     startG2,endG2,numberWanted);
+          int bestType = -1;
+          int bestSet = -1;
+          const double * element = matrix_->getElements();
+          const int * row = matrix_->getIndices();
+          const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+          int * length = matrix_->getMutableVectorLengths();
+#if 0
+          // make sure first available is clean (in case last iteration rejected)
+          cost[firstAvailable_] = 0.0;
+          length[firstAvailable_] = 0;
+          model->nonLinearCost()->setOne(firstAvailable_, 0.0, 0.0, COIN_DBL_MAX, 0.0);
+          model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
+          {
+               for (int i = firstAvailable_; i < lastDynamic_; i++)
+                    assert(!cost[i]);
+          }
+#endif
+#ifdef CLP_DEBUG
+          {
+               for (int i = firstDynamic_; i < firstAvailable_; i++) {
+                    assert (getDynamicStatus(id_[i-firstDynamic_]) == inSmall);
+               }
+          }
+#endif
+          int minSet = minimumObjectsScan_ < 0 ? 5 : minimumObjectsScan_;
+          int minNeg = minimumGoodReducedCosts_ < 0 ? 5 : minimumGoodReducedCosts_;
+          for (int iSet = startG2; iSet < endAll; iSet++) {
+               if (numberWanted + minNeg < originalWanted_ && iSet > startG2 + minSet) {
+                    // give up
+                    numberWanted = 0;
+                    break;
+               } else if (iSet == endG2 && bestSequence >= 0) {
+                    break;
+               }
+               CoinBigIndex j;
+               int iBasic = keyVariable_[iSet];
+               if (iBasic >= numberColumns) {
+                    djMod = - weight(iSet) * infeasibilityCost;
+               } else {
+                    // get dj without
+                    assert (model->getStatus(iBasic) == ClpSimplex::basic);
+                    djMod = 0.0;
+
+                    for (j = startColumn[iBasic];
+                              j < startColumn[iBasic] + length[iBasic]; j++) {
+                         int jRow = row[j];
+                         djMod -= duals[jRow] * element[j];
+                    }
+                    djMod += cost[iBasic];
+                    // See if gub slack possible - dj is djMod
+                    if (getStatus(iSet) == ClpSimplex::atLowerBound) {
+                         double value = -djMod;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!flagged(iSet)) {
+                                        bestDj = value;
+                                        bestSequence = numberRows + numberColumns + iSet;
+                                        bestDjMod = djMod;
+                                        bestType = 0;
+                                        bestSet = iSet;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                        abort();
+                                   }
+                              }
+                         }
+                    } else if (getStatus(iSet) == ClpSimplex::atUpperBound) {
+                         double value = djMod;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!flagged(iSet)) {
+                                        bestDj = value;
+                                        bestSequence = numberRows + numberColumns + iSet;
+                                        bestDjMod = djMod;
+                                        bestType = 0;
+                                        bestSet = iSet;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                        abort();
+                                   }
+                              }
+                         }
+                    }
+               }
+               for (int iSequence = fullStart_[iSet]; iSequence < fullStart_[iSet+1]; iSequence++) {
+                    DynamicStatus status = getDynamicStatus(iSequence);
+                    if (status != inSmall) {
+                         double value = cost_[iSequence] - djMod;
+                         for (j = startColumn_[iSequence];
+                                   j < startColumn_[iSequence+1]; j++) {
+                              int jRow = row_[j];
+                              value -= duals[jRow] * element_[j];
+                         }
+                         // change sign if at lower bound
+                         if (status == atLowerBound)
+                              value = -value;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                        bestDjMod = djMod;
+                                        bestType = 1;
+                                        bestSet = iSet;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                    }
+               }
+               if (numberWanted <= 0) {
+                    numberWanted = 0;
+                    break;
+               }
+          }
+          // Do packed part before gub and small gub - but lightly
+          int saveMinNeg = minimumGoodReducedCosts_;
+          int saveSequence2 = bestSequence;
+          if (bestSequence >= 0)
+               minimumGoodReducedCosts_ = -2;
+          int saveLast = lastGub_;
+          lastGub_ = firstAvailable_;
+          currentWanted_ = numberWanted;
+          ClpGubMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
+          minimumGoodReducedCosts_ = saveMinNeg;
+          lastGub_ = saveLast;
+          if (bestSequence != saveSequence2) {
+               bestType = -1; // in normal or small gub part
+               saveSequence = bestSequence;
+          }
+          if (bestSequence != saveSequence || bestType >= 0) {
+               double * lowerColumn = model->lowerRegion();
+               double * upperColumn = model->upperRegion();
+               double * solution = model->solutionRegion();
+               if (bestType > 0) {
+                    // recompute dj and create
+                    double value = cost_[bestSequence] - bestDjMod;
+                    for (CoinBigIndex jBigIndex = startColumn_[bestSequence];
+                              jBigIndex < startColumn_[bestSequence+1]; jBigIndex++) {
+                         int jRow = row_[jBigIndex];
+                         value -= duals[jRow] * element_[jBigIndex];
+                    }
+                    double * element =  matrix_->getMutableElements();
+                    int * row = matrix_->getMutableIndices();
+                    CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+                    int * length = matrix_->getMutableVectorLengths();
+                    CoinBigIndex numberElements = startColumn[firstAvailable_];
+                    int numberThis = startColumn_[bestSequence+1] - startColumn_[bestSequence];
+                    if (numberElements + numberThis > numberElements_) {
+                         // need to redo
+                         numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis);
+                         matrix_->reserve(numberColumns, numberElements_);
+                         element =  matrix_->getMutableElements();
+                         row = matrix_->getMutableIndices();
+                         // these probably okay but be safe
+                         startColumn = matrix_->getMutableVectorStarts();
+                         length = matrix_->getMutableVectorLengths();
+                    }
+                    // already set startColumn[firstAvailable_]=numberElements;
+                    length[firstAvailable_] = numberThis;
+                    model->costRegion()[firstAvailable_] = cost_[bestSequence];
+                    CoinBigIndex base = startColumn_[bestSequence];
+                    for (int j = 0; j < numberThis; j++) {
+                         row[numberElements] = row_[base+j];
+                         element[numberElements++] = element_[base+j];
+                    }
+                    id_[firstAvailable_-firstDynamic_] = bestSequence;
+                    //printf("best %d\n",bestSequence);
+                    backward_[firstAvailable_] = bestSet;
+                    model->solutionRegion()[firstAvailable_] = 0.0;
+                    if (!lowerColumn_ && !upperColumn_) {
+                         model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
+                         lowerColumn[firstAvailable_] = 0.0;
+                         upperColumn[firstAvailable_] = COIN_DBL_MAX;
+                    }  else {
+                         DynamicStatus status = getDynamicStatus(bestSequence);
+                         if (lowerColumn_)
+                              lowerColumn[firstAvailable_] = lowerColumn_[bestSequence];
+                         else
+                              lowerColumn[firstAvailable_] = 0.0;
+                         if (upperColumn_)
+                              upperColumn[firstAvailable_] = upperColumn_[bestSequence];
+                         else
+                              upperColumn[firstAvailable_] = COIN_DBL_MAX;
+                         if (status == atLowerBound) {
+                              solution[firstAvailable_] = lowerColumn[firstAvailable_];
+                              model->setStatus(firstAvailable_, ClpSimplex::atLowerBound);
+                         } else {
+                              solution[firstAvailable_] = upperColumn[firstAvailable_];
+                              model->setStatus(firstAvailable_, ClpSimplex::atUpperBound);
+                         }
+                    }
+                    model->nonLinearCost()->setOne(firstAvailable_, solution[firstAvailable_],
+                                                   lowerColumn[firstAvailable_],
+                                                   upperColumn[firstAvailable_], cost_[bestSequence]);
+                    bestSequence = firstAvailable_;
+                    // firstAvailable_ only updated if good pivot (in updatePivot)
+                    startColumn[firstAvailable_+1] = numberElements;
+                    //printf("price struct %d - dj %g gubpi %g\n",bestSequence,value,bestDjMod);
+                    reducedCost[bestSequence] = value;
+                    gubSlackIn_ = -1;
+               } else {
+                    // slack - make last column
+                    gubSlackIn_ = bestSequence - numberRows - numberColumns;
+                    bestSequence = numberColumns + 2 * numberRows;
+                    reducedCost[bestSequence] = bestDjMod;
+                    //printf("price slack %d - gubpi %g\n",gubSlackIn_,bestDjMod);
+                    model->setStatus(bestSequence, getStatus(gubSlackIn_));
+                    if (getStatus(gubSlackIn_) == ClpSimplex::atUpperBound)
+                         solution[bestSequence] = upper_[gubSlackIn_];
+                    else
+                         solution[bestSequence] = lower_[gubSlackIn_];
+                    lowerColumn[bestSequence] = lower_[gubSlackIn_];
+                    upperColumn[bestSequence] = upper_[gubSlackIn_];
+                    model->costRegion()[bestSequence] = 0.0;
+                    model->nonLinearCost()->setOne(bestSequence, solution[bestSequence], lowerColumn[bestSequence],
+                                                   upperColumn[bestSequence], 0.0);
+               }
+               savedBestSequence_ = bestSequence;
+               savedBestDj_ = reducedCost[savedBestSequence_];
+          }
+          // See if may be finished
+          if (!startG2 && bestSequence < 0)
+               infeasibilityWeight_ = model_->infeasibilityCost();
+          else if (bestSequence >= 0)
+               infeasibilityWeight_ = -1.0;
+     }
+     currentWanted_ = numberWanted;
+}
+// This is local to Gub to allow synchronization when status is good
+int
+ClpGubDynamicMatrix::synchronize(ClpSimplex * model, int mode)
+{
+     int returnNumber = 0;
+     switch (mode) {
+     case 0: {
+#ifdef CLP_DEBUG
+          {
+               for (int i = 0; i < numberSets_; i++)
+                    assert(toIndex_[i] == -1);
+          }
+#endif
+          // lookup array
+          int * lookup = new int[lastDynamic_];
+          int iColumn;
+          int numberColumns = model->numberColumns();
+          double * element =  matrix_->getMutableElements();
+          int * row = matrix_->getMutableIndices();
+          CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+          int * length = matrix_->getMutableVectorLengths();
+          double * cost = model->costRegion();
+          double * lowerColumn = model->lowerRegion();
+          double * upperColumn = model->upperRegion();
+          int * pivotVariable = model->pivotVariable();
+          CoinBigIndex numberElements = startColumn[firstDynamic_];
+          // first just do lookup and basic stuff
+          int currentNumber = firstAvailable_;
+          firstAvailable_ = firstDynamic_;
+          int numberToDo = 0;
+          double objectiveChange = 0.0;
+          double * solution = model->solutionRegion();
+          for (iColumn = firstDynamic_; iColumn < currentNumber; iColumn++) {
+               int iSet = backward_[iColumn];
+               if (toIndex_[iSet] < 0) {
+                    toIndex_[iSet] = 0;
+                    fromIndex_[numberToDo++] = iSet;
+               }
+               if (model->getStatus(iColumn) == ClpSimplex::basic || iColumn == keyVariable_[iSet]) {
+                    lookup[iColumn] = firstAvailable_;
+                    if (iColumn != keyVariable_[iSet]) {
+                         int iPivot = backToPivotRow_[iColumn];
+                         backToPivotRow_[firstAvailable_] = iPivot;
+                         pivotVariable[iPivot] = firstAvailable_;
+                    }
+                    firstAvailable_++;
+               } else {
+                    int jColumn = id_[iColumn-firstDynamic_];
+                    setDynamicStatus(jColumn, atLowerBound);
+                    if (lowerColumn_ || upperColumn_) {
+                         if (model->getStatus(iColumn) == ClpSimplex::atUpperBound)
+                              setDynamicStatus(jColumn, atUpperBound);
+                         // treat solution as if exactly at a bound
+                         double value = solution[iColumn];
+                         if (fabs(value - lowerColumn[iColumn]) < fabs(value - upperColumn[iColumn]))
+                              value = lowerColumn[iColumn];
+                         else
+                              value = upperColumn[iColumn];
+                         objectiveChange += cost[iColumn] * value;
+                         // redo lower and upper on sets
+                         double shift = value;
+                         if (lowerSet_[iSet] > -1.0e20)
+                              lower_[iSet] = lowerSet_[iSet] - shift;
+                         if (upperSet_[iSet] < 1.0e20)
+                              upper_[iSet] = upperSet_[iSet] - shift;
+                    }
+                    lookup[iColumn] = -1;
+               }
+          }
+          model->setObjectiveOffset(model->objectiveOffset() + objectiveChange);
+          firstAvailable_ = firstDynamic_;
+          for (iColumn = firstDynamic_; iColumn < currentNumber; iColumn++) {
+               if (lookup[iColumn] >= 0) {
+                    // move
+                    int jColumn = id_[iColumn-firstDynamic_];
+                    id_[firstAvailable_-firstDynamic_] = jColumn;
+                    int numberThis = startColumn_[jColumn+1] - startColumn_[jColumn];
+                    length[firstAvailable_] = numberThis;
+                    cost[firstAvailable_] = cost[iColumn];
+                    lowerColumn[firstAvailable_] = lowerColumn[iColumn];
+                    upperColumn[firstAvailable_] = upperColumn[iColumn];
+                    double originalLower = lowerColumn_ ? lowerColumn_[jColumn] : 0.0;
+                    double originalUpper = upperColumn_ ? upperColumn_[jColumn] : COIN_DBL_MAX;
+                    if (originalUpper > 1.0e30)
+                         originalUpper = COIN_DBL_MAX;
+                    model->nonLinearCost()->setOne(firstAvailable_, solution[iColumn],
+                                                   originalLower, originalUpper,
+                                                   cost_[jColumn]);
+                    CoinBigIndex base = startColumn_[jColumn];
+                    for (int j = 0; j < numberThis; j++) {
+                         row[numberElements] = row_[base+j];
+                         element[numberElements++] = element_[base+j];
+                    }
+                    model->setStatus(firstAvailable_, model->getStatus(iColumn));
+                    backward_[firstAvailable_] = backward_[iColumn];
+                    solution[firstAvailable_] = solution[iColumn];
+                    firstAvailable_++;
+                    startColumn[firstAvailable_] = numberElements;
+               }
+          }
+          // clean up next_
+          int * temp = new int [firstAvailable_];
+          for (int jSet = 0; jSet < numberToDo; jSet++) {
+               int iSet = fromIndex_[jSet];
+               toIndex_[iSet] = -1;
+               int last = keyVariable_[iSet];
+               int j = next_[last];
+               bool setTemp = true;
+               if (last < lastDynamic_) {
+                    last = lookup[last];
+                    assert (last >= 0);
+                    keyVariable_[iSet] = last;
+               } else if (j >= 0) {
+                    int newJ = lookup[j];
+                    assert (newJ >= 0);
+                    j = next_[j];
+                    next_[last] = newJ;
+                    last = newJ;
+               } else {
+                    next_[last] = -(iSet + numberColumns + 1);
+                    setTemp = false;
+               }
+               while (j >= 0) {
+                    int newJ = lookup[j];
+                    assert (newJ >= 0);
+                    temp[last] = newJ;
+                    last = newJ;
+                    j = next_[j];
+               }
+               if (setTemp)
+                    temp[last] = -(keyVariable_[iSet] + 1);
+               if (lowerSet_) {
+                    // we only need to get lower_ and upper_ correct
+                    double shift = 0.0;
+                    for (int j = fullStart_[iSet]; j < fullStart_[iSet+1]; j++)
+                         if (getDynamicStatus(j) == atUpperBound)
+                              shift += upperColumn_[j];
+                         else if (getDynamicStatus(j) == atLowerBound && lowerColumn_)
+                              shift += lowerColumn_[j];
+                    if (lowerSet_[iSet] > -1.0e20)
+                         lower_[iSet] = lowerSet_[iSet] - shift;
+                    if (upperSet_[iSet] < 1.0e20)
+                         upper_[iSet] = upperSet_[iSet] - shift;
+               }
+          }
+          // move to next_
+          CoinMemcpyN(temp + firstDynamic_, (firstAvailable_ - firstDynamic_), next_ + firstDynamic_);
+          // if odd iterations may be one out so adjust currentNumber
+          currentNumber = CoinMin(currentNumber + 1, lastDynamic_);
+          // zero solution
+          CoinZeroN(solution + firstAvailable_, currentNumber - firstAvailable_);
+          // zero cost
+          CoinZeroN(cost + firstAvailable_, currentNumber - firstAvailable_);
+          // zero lengths
+          CoinZeroN(length + firstAvailable_, currentNumber - firstAvailable_);
+          for ( iColumn = firstAvailable_; iColumn < currentNumber; iColumn++) {
+               model->nonLinearCost()->setOne(iColumn, 0.0, 0.0, COIN_DBL_MAX, 0.0);
+               model->setStatus(iColumn, ClpSimplex::atLowerBound);
+               backward_[iColumn] = -1;
+          }
+          delete [] lookup;
+          delete [] temp;
+          // make sure fromIndex clean
+          fromIndex_[0] = -1;
+          //#define CLP_DEBUG
+#ifdef CLP_DEBUG
+          // debug
+          {
+               int i;
+               int numberRows = model->numberRows();
+               char * xxxx = new char[numberColumns];
+               memset(xxxx, 0, numberColumns);
+               for (i = 0; i < numberRows; i++) {
+                    int iPivot = pivotVariable[i];
+                    assert (model->getStatus(iPivot) == ClpSimplex::basic);
+                    if (iPivot < numberColumns && backward_[iPivot] >= 0)
+                         xxxx[iPivot] = 1;
+               }
+               for (i = 0; i < numberSets_; i++) {
+                    int key = keyVariable_[i];
+                    int iColumn = next_[key];
+                    int k = 0;
+                    while(iColumn >= 0) {
+                         k++;
+                         assert (k < 100);
+                         assert (backward_[iColumn] == i);
+                         iColumn = next_[iColumn];
+                    }
+                    int stop = -(key + 1);
+                    while (iColumn != stop) {
+                         assert (iColumn < 0);
+                         iColumn = -iColumn - 1;
+                         k++;
+                         assert (k < 100);
+                         assert (backward_[iColumn] == i);
+                         iColumn = next_[iColumn];
+                    }
+                    iColumn = next_[key];
+                    while (iColumn >= 0) {
+                         assert (xxxx[iColumn]);
+                         xxxx[iColumn] = 0;
+                         iColumn = next_[iColumn];
+                    }
+               }
+               for (i = 0; i < numberColumns; i++) {
+                    if (i < numberColumns && backward_[i] >= 0) {
+                         assert (!xxxx[i] || i == keyVariable_[backward_[i]]);
+                    }
+               }
+               delete [] xxxx;
+          }
+          {
+               for (int i = 0; i < numberSets_; i++)
+                    assert(toIndex_[i] == -1);
+          }
+#endif
+          savedFirstAvailable_ = firstAvailable_;
+     }
+     break;
+     // flag a variable
+     case 1: {
+          // id will be sitting at firstAvailable
+          int sequence = id_[firstAvailable_-firstDynamic_];
+          assert (!flagged(sequence));
+          setFlagged(sequence);
+          model->clearFlagged(firstAvailable_);
+     }
+     break;
+     // unflag all variables
+     case 2: {
+          for (int i = 0; i < numberGubColumns_; i++) {
+               if (flagged(i)) {
+                    unsetFlagged(i);
+                    returnNumber++;
+               }
+          }
+     }
+     break;
+     //  just reset costs and bounds (primal)
+     case 3: {
+          double * cost = model->costRegion();
+          double * solution = model->solutionRegion();
+          double * lowerColumn = model->columnLower();
+          double * upperColumn = model->columnUpper();
+          for (int i = firstDynamic_; i < firstAvailable_; i++) {
+               int jColumn = id_[i-firstDynamic_];
+               cost[i] = cost_[jColumn];
+               if (!lowerColumn_ && !upperColumn_) {
+                    lowerColumn[i] = 0.0;
+                    upperColumn[i] = COIN_DBL_MAX;
+               }  else {
+                    if (lowerColumn_)
+                         lowerColumn[i] = lowerColumn_[jColumn];
+                    else
+                         lowerColumn[i] = 0.0;
+                    if (upperColumn_)
+                         upperColumn[i] = upperColumn_[jColumn];
+                    else
+                         upperColumn[i] = COIN_DBL_MAX;
+               }
+               if (model->nonLinearCost())
+                    model->nonLinearCost()->setOne(i, solution[i],
+                                                   lowerColumn[i],
+                                                   upperColumn[i], cost_[jColumn]);
+          }
+          if (!model->numberIterations() && rhsOffset_) {
+               lastRefresh_ = - refreshFrequency_; // force refresh
+          }
+     }
+     break;
+     // and get statistics for column generation
+     case 4: {
+          // In theory we should subtract out ones we have done but ....
+          // If key slack then dual 0.0
+          // If not then slack could be dual infeasible
+          // dj for key is zero so that defines dual on set
+          int i;
+          int numberColumns = model->numberColumns();
+          double * dual = model->dualRowSolution();
+          double infeasibilityCost = model->infeasibilityCost();
+          double dualTolerance = model->dualTolerance();
+          double relaxedTolerance = dualTolerance;
+          // we can't really trust infeasibilities if there is dual error
+          double error = CoinMin(1.0e-2, model->largestDualError());
+          // allow tolerance at least slightly bigger than standard
+          relaxedTolerance = relaxedTolerance +  error;
+          // but we will be using difference
+          relaxedTolerance -= dualTolerance;
+          double objectiveOffset = 0.0;
+          for (i = 0; i < numberSets_; i++) {
+               int kColumn = keyVariable_[i];
+               double value = 0.0;
+               if (kColumn < numberColumns) {
+                    kColumn = id_[kColumn-firstDynamic_];
+                    // dj without set
+                    value = cost_[kColumn];
+                    for (CoinBigIndex j = startColumn_[kColumn];
+                              j < startColumn_[kColumn+1]; j++) {
+                         int iRow = row_[j];
+                         value -= dual[iRow] * element_[j];
+                    }
+                    double infeasibility = 0.0;
+                    if (getStatus(i) == ClpSimplex::atLowerBound) {
+                         if (-value > dualTolerance)
+                              infeasibility = -value - dualTolerance;
+                    } else if (getStatus(i) == ClpSimplex::atUpperBound) {
+                         if (value > dualTolerance)
+                              infeasibility = value - dualTolerance;
+                    }
+                    if (infeasibility > 0.0) {
+                         sumDualInfeasibilities_ += infeasibility;
+                         if (infeasibility > relaxedTolerance)
+                              sumOfRelaxedDualInfeasibilities_ += infeasibility;
+                         numberDualInfeasibilities_ ++;
+                    }
+               } else {
+                    // slack key - may not be feasible
+                    assert (getStatus(i) == ClpSimplex::basic);
+                    // negative as -1.0 for slack
+                    value = -weight(i) * infeasibilityCost;
+               }
+               // Now subtract out from all
+               for (CoinBigIndex k = fullStart_[i]; k < fullStart_[i+1]; k++) {
+                    if (getDynamicStatus(k) != inSmall) {
+                         double djValue = cost_[k] - value;
+                         for (CoinBigIndex j = startColumn_[k];
+                                   j < startColumn_[k+1]; j++) {
+                              int iRow = row_[j];
+                              djValue -= dual[iRow] * element_[j];
+                         }
+                         double infeasibility = 0.0;
+                         double shift = 0.0;
+                         if (getDynamicStatus(k) == atLowerBound) {
+                              if (lowerColumn_)
+                                   shift = lowerColumn_[k];
+                              if (djValue < -dualTolerance)
+                                   infeasibility = -djValue - dualTolerance;
+                         } else {
+                              // at upper bound
+                              shift = upperColumn_[k];
+                              if (djValue > dualTolerance)
+                                   infeasibility = djValue - dualTolerance;
+                         }
+                         objectiveOffset += shift * cost_[k];
+                         if (infeasibility > 0.0) {
+                              sumDualInfeasibilities_ += infeasibility;
+                              if (infeasibility > relaxedTolerance)
+                                   sumOfRelaxedDualInfeasibilities_ += infeasibility;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    }
+               }
+          }
+          model->setObjectiveOffset(objectiveOffset_ - objectiveOffset);
+     }
+     break;
+     // see if time to re-factorize
+     case 5: {
+          if (firstAvailable_ > numberSets_ + model->numberRows() + model->factorizationFrequency())
+               returnNumber = 4;
+     }
+     break;
+     // return 1 if there may be changing bounds on variable (column generation)
+     case 6: {
+          returnNumber = (lowerColumn_ != NULL || upperColumn_ != NULL) ? 1 : 0;
+#if 0
+          if (!returnNumber) {
+               // may be gub slacks
+               for (int i = 0; i < numberSets_; i++) {
+                    if (upper_[i] > lower_[i]) {
+                         returnNumber = 1;
+                         break;
+                    }
+               }
+          }
+#endif
+     }
+     break;
+     // restore firstAvailable_
+     case 7: {
+          int iColumn;
+          int * length = matrix_->getMutableVectorLengths();
+          double * cost = model->costRegion();
+          double * solution = model->solutionRegion();
+          int currentNumber = firstAvailable_;
+          firstAvailable_ = savedFirstAvailable_;
+          // zero solution
+          CoinZeroN(solution + firstAvailable_, currentNumber - firstAvailable_);
+          // zero cost
+          CoinZeroN(cost + firstAvailable_, currentNumber - firstAvailable_);
+          // zero lengths
+          CoinZeroN(length + firstAvailable_, currentNumber - firstAvailable_);
+          for ( iColumn = firstAvailable_; iColumn < currentNumber; iColumn++) {
+               model->nonLinearCost()->setOne(iColumn, 0.0, 0.0, COIN_DBL_MAX, 0.0);
+               model->setStatus(iColumn, ClpSimplex::atLowerBound);
+               backward_[iColumn] = -1;
+          }
+     }
+     break;
+     // make sure set is clean
+     case 8: {
+          int sequenceIn = model->sequenceIn();
+          if (sequenceIn < model->numberColumns()) {
+               int iSet = backward_[sequenceIn];
+               if (iSet >= 0 && lowerSet_) {
+                    // we only need to get lower_ and upper_ correct
+                    double shift = 0.0;
+                    for (int j = fullStart_[iSet]; j < fullStart_[iSet+1]; j++)
+                         if (getDynamicStatus(j) == atUpperBound)
+                              shift += upperColumn_[j];
+                         else if (getDynamicStatus(j) == atLowerBound && lowerColumn_)
+                              shift += lowerColumn_[j];
+                    if (lowerSet_[iSet] > -1.0e20)
+                         lower_[iSet] = lowerSet_[iSet] - shift;
+                    if (upperSet_[iSet] < 1.0e20)
+                         upper_[iSet] = upperSet_[iSet] - shift;
+               }
+               if (sequenceIn == firstAvailable_) {
+                    // not really in small problem
+                    int iBig = id_[sequenceIn-firstDynamic_];
+                    if (model->getStatus(sequenceIn) == ClpSimplex::atLowerBound)
+                         setDynamicStatus(iBig, atLowerBound);
+                    else
+                         setDynamicStatus(iBig, atUpperBound);
+               }
+          }
+     }
+     break;
+     // adjust lower,upper
+     case 9: {
+          int sequenceIn = model->sequenceIn();
+          if (sequenceIn >= firstDynamic_ && sequenceIn < lastDynamic_ && lowerSet_) {
+               int iSet = backward_[sequenceIn];
+               assert (iSet >= 0);
+               int inBig = id_[sequenceIn-firstDynamic_];
+               const double * solution = model->solutionRegion();
+               setDynamicStatus(inBig, inSmall);
+               if (lowerSet_[iSet] > -1.0e20)
+                    lower_[iSet] += solution[sequenceIn];
+               if (upperSet_[iSet] < 1.0e20)
+                    upper_[iSet] += solution[sequenceIn];
+               model->setObjectiveOffset(model->objectiveOffset() -
+                                         solution[sequenceIn]*cost_[inBig]);
+          }
+     }
+     }
+     return returnNumber;
+}
+// Add a new variable to a set
+void
+ClpGubDynamicMatrix::insertNonBasic(int sequence, int iSet)
+{
+     int last = keyVariable_[iSet];
+     int j = next_[last];
+     while (j >= 0) {
+          last = j;
+          j = next_[j];
+     }
+     next_[last] = -(sequence + 1);
+     next_[sequence] = j;
+}
+// Sets up an effective RHS and does gub crash if needed
+void
+ClpGubDynamicMatrix::useEffectiveRhs(ClpSimplex * model, bool cheapest)
+{
+     // Do basis - cheapest or slack if feasible (unless cheapest set)
+     int longestSet = 0;
+     int iSet;
+     for (iSet = 0; iSet < numberSets_; iSet++)
+          longestSet = CoinMax(longestSet, fullStart_[iSet+1] - fullStart_[iSet]);
+
+     double * upper = new double[longestSet+1];
+     double * cost = new double[longestSet+1];
+     double * lower = new double[longestSet+1];
+     double * solution = new double[longestSet+1];
+     assert (!next_);
+     delete [] next_;
+     int numberColumns = model->numberColumns();
+     next_ = new int[numberColumns+numberSets_+CoinMax(2*longestSet, lastDynamic_-firstDynamic_)];
+     char * mark = new char[numberColumns];
+     memset(mark, 0, numberColumns);
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++)
+          next_[iColumn] = COIN_INT_MAX;
+     int i;
+     int * keys = new int[numberSets_];
+     int * back = new int[numberGubColumns_];
+     CoinFillN(back, numberGubColumns_, -1);
+     for (i = 0; i < numberSets_; i++)
+          keys[i] = COIN_INT_MAX;
+     delete [] dynamicStatus_;
+     dynamicStatus_ = new unsigned char [numberGubColumns_];
+     memset(dynamicStatus_, 0, numberGubColumns_); // for clarity
+     for (i = 0; i < numberGubColumns_; i++)
+          setDynamicStatus(i, atLowerBound);
+     // set up chains
+     for (i = firstDynamic_; i < lastDynamic_; i++) {
+          if (id_[i-firstDynamic_] >= 0) {
+               if (model->getStatus(i) == ClpSimplex::basic)
+                    mark[i] = 1;
+               int iSet = backward_[i];
+               assert (iSet >= 0);
+               int iNext = keys[iSet];
+               next_[i] = iNext;
+               keys[iSet] = i;
+               back[id_[i-firstDynamic_]] = i;
+          } else {
+               model->setStatus(i, ClpSimplex::atLowerBound);
+               backward_[i] = -1;
+          }
+     }
+     double * columnSolution = model->solutionRegion();
+     int numberRows = getNumRows();
+     toIndex_ = new int[numberSets_];
+     for (iSet = 0; iSet < numberSets_; iSet++)
+          toIndex_[iSet] = -1;
+     fromIndex_ = new int [numberRows+numberSets_];
+     double tolerance = model->primalTolerance();
+     double * element =  matrix_->getMutableElements();
+     int * row = matrix_->getMutableIndices();
+     CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+     int * length = matrix_->getMutableVectorLengths();
+     double objectiveOffset = 0.0;
+     for (iSet = 0; iSet < numberSets_; iSet++) {
+          int j;
+          int numberBasic = 0;
+          int iBasic = -1;
+          int iStart = fullStart_[iSet];
+          int iEnd = fullStart_[iSet+1];
+          // find one with smallest length
+          int smallest = numberRows + 1;
+          double value = 0.0;
+          j = keys[iSet];
+          while (j != COIN_INT_MAX) {
+               if (model->getStatus(j) == ClpSimplex::basic) {
+                    if (length[j] < smallest) {
+                         smallest = length[j];
+                         iBasic = j;
+                    }
+                    numberBasic++;
+               }
+               value += columnSolution[j];
+               j = next_[j];
+          }
+          bool done = false;
+          if (numberBasic > 1 || (numberBasic == 1 && getStatus(iSet) == ClpSimplex::basic)) {
+               if (getStatus(iSet) == ClpSimplex::basic)
+                    iBasic = iSet + numberColumns; // slack key - use
+               done = true;
+          } else if (numberBasic == 1) {
+               // see if can be key
+               double thisSolution = columnSolution[iBasic];
+               if (thisSolution < 0.0) {
+                    value -= thisSolution;
+                    thisSolution = 0.0;
+                    columnSolution[iBasic] = thisSolution;
+               }
+               // try setting slack to a bound
+               assert (upper_[iSet] < 1.0e20 || lower_[iSet] > -1.0e20);
+               double cost1 = COIN_DBL_MAX;
+               int whichBound = -1;
+               if (upper_[iSet] < 1.0e20) {
+                    // try slack at ub
+                    double newBasic = thisSolution + upper_[iSet] - value;
+                    if (newBasic >= -tolerance) {
+                         // can go
+                         whichBound = 1;
+                         cost1 = newBasic * cost_[iBasic];
+                         // But if exact then may be good solution
+                         if (fabs(upper_[iSet] - value) < tolerance)
+                              cost1 = -COIN_DBL_MAX;
+                    }
+               }
+               if (lower_[iSet] > -1.0e20) {
+                    // try slack at lb
+                    double newBasic = thisSolution + lower_[iSet] - value;
+                    if (newBasic >= -tolerance) {
+                         // can go but is it cheaper
+                         double cost2 = newBasic * cost_[iBasic];
+                         // But if exact then may be good solution
+                         if (fabs(lower_[iSet] - value) < tolerance)
+                              cost2 = -COIN_DBL_MAX;
+                         if (cost2 < cost1)
+                              whichBound = 0;
+                    }
+               }
+               if (whichBound != -1) {
+                    // key
+                    done = true;
+                    if (whichBound) {
+                         // slack to upper
+                         columnSolution[iBasic] = thisSolution + upper_[iSet] - value;
+                         setStatus(iSet, ClpSimplex::atUpperBound);
+                    } else {
+                         // slack to lower
+                         columnSolution[iBasic] = thisSolution + lower_[iSet] - value;
+                         setStatus(iSet, ClpSimplex::atLowerBound);
+                    }
+               }
+          }
+          if (!done) {
+               if (!cheapest) {
+                    // see if slack can be key
+                    if (value >= lower_[iSet] - tolerance && value <= upper_[iSet] + tolerance) {
+                         done = true;
+                         setStatus(iSet, ClpSimplex::basic);
+                         iBasic = iSet + numberColumns;
+                    }
+               }
+               if (!done) {
+                    // set non basic if there was one
+                    if (iBasic >= 0)
+                         model->setStatus(iBasic, ClpSimplex::atLowerBound);
+                    // find cheapest
+                    int numberInSet = iEnd - iStart;
+                    if (!lowerColumn_) {
+                         CoinZeroN(lower, numberInSet);
+                    } else {
+                         for (int j = 0; j < numberInSet; j++)
+                              lower[j] = lowerColumn_[j+iStart];
+                    }
+                    if (!upperColumn_) {
+                         CoinFillN(upper, numberInSet, COIN_DBL_MAX);
+                    } else {
+                         for (int j = 0; j < numberInSet; j++)
+                              upper[j] = upperColumn_[j+iStart];
+                    }
+                    CoinFillN(solution, numberInSet, 0.0);
+                    // and slack
+                    iBasic = numberInSet;
+                    solution[iBasic] = -value;
+                    lower[iBasic] = -upper_[iSet];
+                    upper[iBasic] = -lower_[iSet];
+                    int kphase;
+                    if (value >= lower_[iSet] - tolerance && value <= upper_[iSet] + tolerance) {
+                         // feasible
+                         kphase = 1;
+                         cost[iBasic] = 0.0;
+                         for (int j = 0; j < numberInSet; j++)
+                              cost[j] = cost_[j+iStart];
+                    } else {
+                         // infeasible
+                         kphase = 0;
+                         // remember bounds are flipped so opposite to natural
+                         if (value < lower_[iSet] - tolerance)
+                              cost[iBasic] = 1.0;
+                         else
+                              cost[iBasic] = -1.0;
+                         CoinZeroN(cost, numberInSet);
+                    }
+                    double dualTolerance = model->dualTolerance();
+                    for (int iphase = kphase; iphase < 2; iphase++) {
+                         if (iphase) {
+                              cost[numberInSet] = 0.0;
+                              for (int j = 0; j < numberInSet; j++)
+                                   cost[j] = cost_[j+iStart];
+                         }
+                         // now do one row lp
+                         bool improve = true;
+                         while (improve) {
+                              improve = false;
+                              double dual = cost[iBasic];
+                              int chosen = -1;
+                              double best = dualTolerance;
+                              int way = 0;
+                              for (int i = 0; i <= numberInSet; i++) {
+                                   double dj = cost[i] - dual;
+                                   double improvement = 0.0;
+                                   if (iphase || i < numberInSet)
+                                        assert (solution[i] >= lower[i] && solution[i] <= upper[i]);
+                                   if (dj > dualTolerance)
+                                        improvement = dj * (solution[i] - lower[i]);
+                                   else if (dj < -dualTolerance)
+                                        improvement = dj * (solution[i] - upper[i]);
+                                   if (improvement > best) {
+                                        best = improvement;
+                                        chosen = i;
+                                        if (dj < 0.0) {
+                                             way = 1;
+                                        } else {
+                                             way = -1;
+                                        }
+                                   }
+                              }
+                              if (chosen >= 0) {
+                                   improve = true;
+                                   // now see how far
+                                   if (way > 0) {
+                                        // incoming increasing so basic decreasing
+                                        // if phase 0 then go to nearest bound
+                                        double distance = upper[chosen] - solution[chosen];
+                                        double basicDistance;
+                                        if (!iphase) {
+                                             assert (iBasic == numberInSet);
+                                             assert (solution[iBasic] > upper[iBasic]);
+                                             basicDistance = solution[iBasic] - upper[iBasic];
+                                        } else {
+                                             basicDistance = solution[iBasic] - lower[iBasic];
+                                        }
+                                        // need extra coding for unbounded
+                                        assert (CoinMin(distance, basicDistance) < 1.0e20);
+                                        if (distance > basicDistance) {
+                                             // incoming becomes basic
+                                             solution[chosen] += basicDistance;
+                                             if (!iphase)
+                                                  solution[iBasic] = upper[iBasic];
+                                             else
+                                                  solution[iBasic] = lower[iBasic];
+                                             iBasic = chosen;
+                                        } else {
+                                             // flip
+                                             solution[chosen] = upper[chosen];
+                                             solution[iBasic] -= distance;
+                                        }
+                                   } else {
+                                        // incoming decreasing so basic increasing
+                                        // if phase 0 then go to nearest bound
+                                        double distance = solution[chosen] - lower[chosen];
+                                        double basicDistance;
+                                        if (!iphase) {
+                                             assert (iBasic == numberInSet);
+                                             assert (solution[iBasic] < lower[iBasic]);
+                                             basicDistance = lower[iBasic] - solution[iBasic];
+                                        } else {
+                                             basicDistance = upper[iBasic] - solution[iBasic];
+                                        }
+                                        // need extra coding for unbounded - for now just exit
+                                        if (CoinMin(distance, basicDistance) > 1.0e20) {
+                                             printf("unbounded on set %d\n", iSet);
+                                             iphase = 1;
+                                             iBasic = numberInSet;
+                                             break;
+                                        }
+                                        if (distance > basicDistance) {
+                                             // incoming becomes basic
+                                             solution[chosen] -= basicDistance;
+                                             if (!iphase)
+                                                  solution[iBasic] = lower[iBasic];
+                                             else
+                                                  solution[iBasic] = upper[iBasic];
+                                             iBasic = chosen;
+                                        } else {
+                                             // flip
+                                             solution[chosen] = lower[chosen];
+                                             solution[iBasic] += distance;
+                                        }
+                                   }
+                                   if (!iphase) {
+                                        if(iBasic < numberInSet)
+                                             break; // feasible
+                                        else if (solution[iBasic] >= lower[iBasic] &&
+                                                  solution[iBasic] <= upper[iBasic])
+                                             break; // feasible (on flip)
+                                   }
+                              }
+                         }
+                    }
+                    // do solution i.e. bounds
+                    if (lowerColumn_ || upperColumn_) {
+                         for (int j = 0; j < numberInSet; j++) {
+                              if (j != iBasic) {
+                                   objectiveOffset += solution[j] * cost[j];
+                                   if (lowerColumn_ && upperColumn_) {
+                                        if (fabs(solution[j] - lowerColumn_[j+iStart]) >
+                                                  fabs(solution[j] - upperColumn_[j+iStart]))
+                                             setDynamicStatus(j + iStart, atUpperBound);
+                                   } else if (upperColumn_ && solution[j] > 0.0) {
+                                        setDynamicStatus(j + iStart, atUpperBound);
+                                   } else {
+                                        setDynamicStatus(j + iStart, atLowerBound);
+                                   }
+                              }
+                         }
+                    }
+                    // convert iBasic back and do bounds
+                    if (iBasic == numberInSet) {
+                         // slack basic
+                         setStatus(iSet, ClpSimplex::basic);
+                         iBasic = iSet + numberColumns;
+                    } else {
+                         iBasic += fullStart_[iSet];
+                         if (back[iBasic] >= 0) {
+                              // exists
+                              iBasic = back[iBasic];
+                         } else {
+                              // create
+                              CoinBigIndex numberElements = startColumn[firstAvailable_];
+                              int numberThis = startColumn_[iBasic+1] - startColumn_[iBasic];
+                              if (numberElements + numberThis > numberElements_) {
+                                   // need to redo
+                                   numberElements_ = CoinMax(3 * numberElements_ / 2, numberElements + numberThis);
+                                   matrix_->reserve(numberColumns, numberElements_);
+                                   element =  matrix_->getMutableElements();
+                                   row = matrix_->getMutableIndices();
+                                   // these probably okay but be safe
+                                   startColumn = matrix_->getMutableVectorStarts();
+                                   length = matrix_->getMutableVectorLengths();
+                              }
+                              length[firstAvailable_] = numberThis;
+                              model->costRegion()[firstAvailable_] = cost_[iBasic];
+                              if (lowerColumn_)
+                                   model->lowerRegion()[firstAvailable_] = lowerColumn_[iBasic];
+                              else
+                                   model->lowerRegion()[firstAvailable_] = 0.0;
+                              if (upperColumn_)
+                                   model->upperRegion()[firstAvailable_] = upperColumn_[iBasic];
+                              else
+                                   model->upperRegion()[firstAvailable_] = COIN_DBL_MAX;
+                              columnSolution[firstAvailable_] = solution[iBasic-fullStart_[iSet]];
+                              CoinBigIndex base = startColumn_[iBasic];
+                              for (int j = 0; j < numberThis; j++) {
+                                   row[numberElements] = row_[base+j];
+                                   element[numberElements++] = element_[base+j];
+                              }
+                              // already set startColumn[firstAvailable_]=numberElements;
+                              id_[firstAvailable_-firstDynamic_] = iBasic;
+                              setDynamicStatus(iBasic, inSmall);
+                              backward_[firstAvailable_] = iSet;
+                              iBasic = firstAvailable_;
+                              firstAvailable_++;
+                              startColumn[firstAvailable_] = numberElements;
+                         }
+                         model->setStatus(iBasic, ClpSimplex::basic);
+                         // remember bounds flipped
+                         if (upper[numberInSet] == lower[numberInSet])
+                              setStatus(iSet, ClpSimplex::isFixed);
+                         else if (solution[numberInSet] == upper[numberInSet])
+                              setStatus(iSet, ClpSimplex::atLowerBound);
+                         else if (solution[numberInSet] == lower[numberInSet])
+                              setStatus(iSet, ClpSimplex::atUpperBound);
+                         else
+                              abort();
+                    }
+                    for (j = iStart; j < iEnd; j++) {
+                         int iBack = back[j];
+                         if (iBack >= 0) {
+                              if (model->getStatus(iBack) != ClpSimplex::basic) {
+                                   int inSet = j - iStart;
+                                   columnSolution[iBack] = solution[inSet];
+                                   if (upper[inSet] == lower[inSet])
+                                        model->setStatus(iBack, ClpSimplex::isFixed);
+                                   else if (solution[inSet] == upper[inSet])
+                                        model->setStatus(iBack, ClpSimplex::atUpperBound);
+                                   else if (solution[inSet] == lower[inSet])
+                                        model->setStatus(iBack, ClpSimplex::atLowerBound);
+                              }
+                         }
+                    }
+               }
+          }
+          keyVariable_[iSet] = iBasic;
+     }
+     model->setObjectiveOffset(objectiveOffset_ - objectiveOffset);
+     delete [] lower;
+     delete [] solution;
+     delete [] upper;
+     delete [] cost;
+     // make sure matrix is in good shape
+     matrix_->orderMatrix();
+     // create effective rhs
+     delete [] rhsOffset_;
+     rhsOffset_ = new double[numberRows];
+     // and redo chains
+     memset(mark, 0, numberColumns);
+     for (int iColumnX = 0; iColumnX < firstAvailable_; iColumnX++)
+          next_[iColumnX] = COIN_INT_MAX;
+     for (i = 0; i < numberSets_; i++) {
+          keys[i] = COIN_INT_MAX;
+          int iKey = keyVariable_[i];
+          if (iKey < numberColumns)
+               model->setStatus(iKey, ClpSimplex::basic);
+     }
+     // set up chains
+     for (i = 0; i < firstAvailable_; i++) {
+          if (model->getStatus(i) == ClpSimplex::basic)
+               mark[i] = 1;
+          int iSet = backward_[i];
+          if (iSet >= 0) {
+               int iNext = keys[iSet];
+               next_[i] = iNext;
+               keys[iSet] = i;
+          }
+     }
+     for (i = 0; i < numberSets_; i++) {
+          if (keys[i] != COIN_INT_MAX) {
+               // something in set
+               int j;
+               if (getStatus(i) != ClpSimplex::basic) {
+                    // make sure fixed if it is
+                    if (upper_[i] == lower_[i])
+                         setStatus(i, ClpSimplex::isFixed);
+                    // slack not key - choose one with smallest length
+                    int smallest = numberRows + 1;
+                    int key = -1;
+                    j = keys[i];
+                    while (1) {
+                         if (mark[j] && length[j] < smallest) {
+                              key = j;
+                              smallest = length[j];
+                         }
+                         if (next_[j] != COIN_INT_MAX) {
+                              j = next_[j];
+                         } else {
+                              // correct end
+                              next_[j] = -(keys[i] + 1);
+                              break;
+                         }
+                    }
+                    if (key >= 0) {
+                         keyVariable_[i] = key;
+                    } else {
+                         // nothing basic - make slack key
+                         //((ClpGubMatrix *)this)->setStatus(i,ClpSimplex::basic);
+                         // fudge to avoid const problem
+                         status_[i] = 1;
+                    }
+               } else {
+                    // slack key
+                    keyVariable_[i] = numberColumns + i;
+                    int j;
+                    double sol = 0.0;
+                    j = keys[i];
+                    while (1) {
+                         sol += columnSolution[j];
+                         if (next_[j] != COIN_INT_MAX) {
+                              j = next_[j];
+                         } else {
+                              // correct end
+                              next_[j] = -(keys[i] + 1);
+                              break;
+                         }
+                    }
+                    if (sol > upper_[i] + tolerance) {
+                         setAbove(i);
+                    } else if (sol < lower_[i] - tolerance) {
+                         setBelow(i);
+                    } else {
+                         setFeasible(i);
+                    }
+               }
+               // Create next_
+               int key = keyVariable_[i];
+               redoSet(model, key, keys[i], i);
+          } else {
+               // nothing in set!
+               next_[i+numberColumns] = -(i + numberColumns + 1);
+               keyVariable_[i] = numberColumns + i;
+               double sol = 0.0;
+               if (sol > upper_[i] + tolerance) {
+                    setAbove(i);
+               } else if (sol < lower_[i] - tolerance) {
+                    setBelow(i);
+               } else {
+                    setFeasible(i);
+               }
+          }
+     }
+     delete [] keys;
+     delete [] mark;
+     delete [] back;
+     rhsOffset(model, true);
+}
+/* Returns effective RHS if it is being used.  This is used for long problems
+   or big gub or anywhere where going through full columns is
+   expensive.  This may re-compute */
+double *
+ClpGubDynamicMatrix::rhsOffset(ClpSimplex * model, bool forceRefresh,
+                               bool
+#ifdef CLP_DEBUG
+                               check
+#endif
+                              )
+{
+     //forceRefresh=true;
+     //check=false;
+#ifdef CLP_DEBUG
+     double * saveE = NULL;
+     if (rhsOffset_ && check) {
+          int numberRows = model->numberRows();
+          saveE = new double[numberRows];
+     }
+#endif
+     if (rhsOffset_) {
+#ifdef CLP_DEBUG
+          if (check) {
+               // no need - but check anyway
+               int numberRows = model->numberRows();
+               double * rhs = new double[numberRows];
+               int numberColumns = model->numberColumns();
+               int iRow;
+               CoinZeroN(rhs, numberRows);
+               // do ones at bounds before gub
+               const double * smallSolution = model->solutionRegion();
+               const double * element = matrix_->getElements();
+               const int * row = matrix_->getIndices();
+               const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+               const int * length = matrix_->getVectorLengths();
+               int iColumn;
+               for (iColumn = 0; iColumn < firstDynamic_; iColumn++) {
+                    if (model->getStatus(iColumn) != ClpSimplex::basic) {
+                         double value = smallSolution[iColumn];
+                         for (CoinBigIndex j = startColumn[iColumn];
+                                   j < startColumn[iColumn] + length[iColumn]; j++) {
+                              int jRow = row[j];
+                              rhs[jRow] -= value * element[j];
+                         }
+                    }
+               }
+               if (lowerColumn_ || upperColumn_) {
+                    double * solution = new double [numberGubColumns_];
+                    for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) {
+                         double value = 0.0;
+                         if(getDynamicStatus(iColumn) == atUpperBound)
+                              value = upperColumn_[iColumn];
+                         else if (lowerColumn_)
+                              value = lowerColumn_[iColumn];
+                         solution[iColumn] = value;
+                    }
+                    // ones at bounds in small and gub
+                    for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) {
+                         int jFull = id_[iColumn-firstDynamic_];
+                         solution[jFull] = smallSolution[iColumn];
+                    }
+                    // zero all basic in small model
+                    int * pivotVariable = model->pivotVariable();
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         int iColumn = pivotVariable[iRow];
+                         if (iColumn >= firstDynamic_ && iColumn < lastDynamic_) {
+                              int iSequence = id_[iColumn-firstDynamic_];
+                              solution[iSequence] = 0.0;
+                         }
+                    }
+                    // and now compute value to use for key
+                    ClpSimplex::Status iStatus;
+                    for (int iSet = 0; iSet < numberSets_; iSet++) {
+                         iColumn = keyVariable_[iSet];
+                         if (iColumn < numberColumns) {
+                              int iSequence = id_[iColumn-firstDynamic_];
+                              solution[iSequence] = 0.0;
+                              double b = 0.0;
+                              // key is structural - where is slack
+                              iStatus = getStatus(iSet);
+                              assert (iStatus != ClpSimplex::basic);
+                              if (iStatus == ClpSimplex::atLowerBound)
+                                   b = lowerSet_[iSet];
+                              else
+                                   b = upperSet_[iSet];
+                              // subtract out others at bounds
+                              for (int j = fullStart_[iSet]; j < fullStart_[iSet+1]; j++)
+                                   b -= solution[j];
+                              solution[iSequence] = b;
+                         }
+                    }
+                    for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) {
+                         double value = solution[iColumn];
+                         if (value) {
+                              for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn+1]; j++) {
+                                   int iRow = row_[j];
+                                   rhs[iRow] -= element_[j] * value;
+                              }
+                         }
+                    }
+                    // now do lower and upper bounds on sets
+                    for (int iSet = 0; iSet < numberSets_; iSet++) {
+                         iColumn = keyVariable_[iSet];
+                         double shift = 0.0;
+                         for (int j = fullStart_[iSet]; j < fullStart_[iSet+1]; j++) {
+                              if (getDynamicStatus(j) != inSmall && j != iColumn) {
+                                   if (getDynamicStatus(j) == atLowerBound) {
+                                        if (lowerColumn_)
+                                             shift += lowerColumn_[j];
+                                   } else {
+                                        shift += upperColumn_[j];
+                                   }
+                              }
+                         }
+                         if (lowerSet_[iSet] > -1.0e20)
+                              assert(fabs(lower_[iSet] - (lowerSet_[iSet] - shift)) < 1.0e-3);
+                         if (upperSet_[iSet] < 1.0e20)
+                              assert(fabs(upper_[iSet] - ( upperSet_[iSet] - shift)) < 1.0e-3);
+                    }
+                    delete [] solution;
+               } else {
+                    // no bounds
+                    ClpSimplex::Status iStatus;
+                    for (int iSet = 0; iSet < numberSets_; iSet++) {
+                         int iColumn = keyVariable_[iSet];
+                         if (iColumn < numberColumns) {
+                              int iSequence = id_[iColumn-firstDynamic_];
+                              double b = 0.0;
+                              // key is structural - where is slack
+                              iStatus = getStatus(iSet);
+                              assert (iStatus != ClpSimplex::basic);
+                              if (iStatus == ClpSimplex::atLowerBound)
+                                   b = lower_[iSet];
+                              else
+                                   b = upper_[iSet];
+                              if (b) {
+                                   for (CoinBigIndex j = startColumn_[iSequence]; j < startColumn_[iSequence+1]; j++) {
+                                        int iRow = row_[j];
+                                        rhs[iRow] -= element_[j] * b;
+                                   }
+                              }
+                         }
+                    }
+               }
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    if (fabs(rhs[iRow] - rhsOffset_[iRow]) > 1.0e-3)
+                         printf("** bad effective %d - true %g old %g\n", iRow, rhs[iRow], rhsOffset_[iRow]);
+               }
+               CoinMemcpyN(rhs, numberRows, saveE);
+               delete [] rhs;
+          }
+#endif
+          if (forceRefresh || (refreshFrequency_ && model->numberIterations() >=
+                               lastRefresh_ + refreshFrequency_)) {
+               int numberRows = model->numberRows();
+               int numberColumns = model->numberColumns();
+               int iRow;
+               CoinZeroN(rhsOffset_, numberRows);
+               // do ones at bounds before gub
+               const double * smallSolution = model->solutionRegion();
+               const double * element = matrix_->getElements();
+               const int * row = matrix_->getIndices();
+               const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+               const int * length = matrix_->getVectorLengths();
+               int iColumn;
+               for (iColumn = 0; iColumn < firstDynamic_; iColumn++) {
+                    if (model->getStatus(iColumn) != ClpSimplex::basic) {
+                         double value = smallSolution[iColumn];
+                         for (CoinBigIndex j = startColumn[iColumn];
+                                   j < startColumn[iColumn] + length[iColumn]; j++) {
+                              int jRow = row[j];
+                              rhsOffset_[jRow] -= value * element[j];
+                         }
+                    }
+               }
+               if (lowerColumn_ || upperColumn_) {
+                    double * solution = new double [numberGubColumns_];
+                    for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) {
+                         double value = 0.0;
+                         if(getDynamicStatus(iColumn) == atUpperBound)
+                              value = upperColumn_[iColumn];
+                         else if (lowerColumn_)
+                              value = lowerColumn_[iColumn];
+                         solution[iColumn] = value;
+                    }
+                    // ones in gub and in small problem
+                    for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) {
+                         int jFull = id_[iColumn-firstDynamic_];
+                         solution[jFull] = smallSolution[iColumn];
+                    }
+                    // zero all basic in small model
+                    int * pivotVariable = model->pivotVariable();
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         int iColumn = pivotVariable[iRow];
+                         if (iColumn >= firstDynamic_ && iColumn < lastDynamic_) {
+                              int iSequence = id_[iColumn-firstDynamic_];
+                              solution[iSequence] = 0.0;
+                         }
+                    }
+                    // and now compute value to use for key
+                    ClpSimplex::Status iStatus;
+                    int iSet;
+                    for ( iSet = 0; iSet < numberSets_; iSet++) {
+                         iColumn = keyVariable_[iSet];
+                         if (iColumn < numberColumns) {
+                              int iSequence = id_[iColumn-firstDynamic_];
+                              solution[iSequence] = 0.0;
+                              double b = 0.0;
+                              // key is structural - where is slack
+                              iStatus = getStatus(iSet);
+                              assert (iStatus != ClpSimplex::basic);
+                              if (iStatus == ClpSimplex::atLowerBound)
+                                   b = lowerSet_[iSet];
+                              else
+                                   b = upperSet_[iSet];
+                              // subtract out others at bounds
+                              for (int j = fullStart_[iSet]; j < fullStart_[iSet+1]; j++)
+                                   b -= solution[j];
+                              solution[iSequence] = b;
+                         }
+                    }
+                    for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) {
+                         double value = solution[iColumn];
+                         if (value) {
+                              for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn+1]; j++) {
+                                   int iRow = row_[j];
+                                   rhsOffset_[iRow] -= element_[j] * value;
+                              }
+                         }
+                    }
+                    // now do lower and upper bounds on sets
+                    // and offset
+                    double objectiveOffset = 0.0;
+                    for ( iSet = 0; iSet < numberSets_; iSet++) {
+                         iColumn = keyVariable_[iSet];
+                         double shift = 0.0;
+                         for (CoinBigIndex j = fullStart_[iSet]; j < fullStart_[iSet+1]; j++) {
+                              if (getDynamicStatus(j) != inSmall) {
+                                   double value = 0.0;
+                                   if (getDynamicStatus(j) == atLowerBound) {
+                                        if (lowerColumn_)
+                                             value = lowerColumn_[j];
+                                   } else {
+                                        value = upperColumn_[j];
+                                   }
+                                   if (j != iColumn)
+                                        shift += value;
+                                   objectiveOffset += value * cost_[j];
+                              }
+                         }
+                         if (lowerSet_[iSet] > -1.0e20)
+                              lower_[iSet] = lowerSet_[iSet] - shift;
+                         if (upperSet_[iSet] < 1.0e20)
+                              upper_[iSet] = upperSet_[iSet] - shift;
+                    }
+                    delete [] solution;
+                    model->setObjectiveOffset(objectiveOffset_ - objectiveOffset);
+               } else {
+                    // no bounds
+                    ClpSimplex::Status iStatus;
+                    for (int iSet = 0; iSet < numberSets_; iSet++) {
+                         int iColumn = keyVariable_[iSet];
+                         if (iColumn < numberColumns) {
+                              int iSequence = id_[iColumn-firstDynamic_];
+                              double b = 0.0;
+                              // key is structural - where is slack
+                              iStatus = getStatus(iSet);
+                              assert (iStatus != ClpSimplex::basic);
+                              if (iStatus == ClpSimplex::atLowerBound)
+                                   b = lower_[iSet];
+                              else
+                                   b = upper_[iSet];
+                              if (b) {
+                                   for (CoinBigIndex j = startColumn_[iSequence]; j < startColumn_[iSequence+1]; j++) {
+                                        int iRow = row_[j];
+                                        rhsOffset_[iRow] -= element_[j] * b;
+                                   }
+                              }
+                         }
+                    }
+               }
+#ifdef CLP_DEBUG
+               if (saveE) {
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         if (fabs(saveE[iRow] - rhsOffset_[iRow]) > 1.0e-3)
+                              printf("** %d - old eff %g new %g\n", iRow, saveE[iRow], rhsOffset_[iRow]);
+                    }
+                    delete [] saveE;
+               }
+#endif
+               lastRefresh_ = model->numberIterations();
+          }
+     }
+     return rhsOffset_;
+}
+/*
+  update information for a pivot (and effective rhs)
+*/
+int
+ClpGubDynamicMatrix::updatePivot(ClpSimplex * model, double oldInValue, double oldOutValue)
+{
+
+     // now update working model
+     int sequenceIn = model->sequenceIn();
+     int sequenceOut = model->sequenceOut();
+     bool doPrinting = (model->messageHandler()->logLevel() == 63);
+     bool print = false;
+     int iSet;
+     int trueIn = -1;
+     int trueOut = -1;
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     if (sequenceIn == firstAvailable_) {
+          if (doPrinting)
+               printf("New variable ");
+          if (sequenceIn != sequenceOut) {
+               insertNonBasic(firstAvailable_, backward_[firstAvailable_]);
+               setDynamicStatus(id_[sequenceIn-firstDynamic_], inSmall);
+               firstAvailable_++;
+          } else {
+               int bigSequence = id_[sequenceIn-firstDynamic_];
+               if (model->getStatus(sequenceIn) == ClpSimplex::atUpperBound)
+                    setDynamicStatus(bigSequence, atUpperBound);
+               else
+                    setDynamicStatus(bigSequence, atLowerBound);
+          }
+          synchronize(model, 8);
+     }
+     if (sequenceIn < lastDynamic_) {
+          iSet = backward_[sequenceIn];
+          if (iSet >= 0) {
+               int bigSequence = id_[sequenceIn-firstDynamic_];
+               trueIn = bigSequence + numberRows + numberColumns + numberSets_;
+               if (doPrinting)
+                    printf(" incoming set %d big seq %d", iSet, bigSequence);
+               print = true;
+          }
+     } else if (sequenceIn >= numberRows + numberColumns) {
+          trueIn = numberRows + numberColumns + gubSlackIn_;
+     }
+     if (sequenceOut < lastDynamic_) {
+          iSet = backward_[sequenceOut];
+          if (iSet >= 0) {
+               int bigSequence = id_[sequenceOut-firstDynamic_];
+               trueOut = bigSequence + firstDynamic_;
+               if (getDynamicStatus(bigSequence) != inSmall) {
+                    if (model->getStatus(sequenceOut) == ClpSimplex::atUpperBound)
+                         setDynamicStatus(bigSequence, atUpperBound);
+                    else
+                         setDynamicStatus(bigSequence, atLowerBound);
+               }
+               if (doPrinting)
+                    printf(" ,outgoing set %d big seq %d,", iSet, bigSequence);
+               print = true;
+               model->setSequenceIn(sequenceOut);
+               synchronize(model, 8);
+               model->setSequenceIn(sequenceIn);
+          }
+     }
+     if (print && doPrinting)
+          printf("\n");
+     ClpGubMatrix::updatePivot(model, oldInValue, oldOutValue);
+     // Redo true in and out
+     if (trueIn >= 0)
+          trueSequenceIn_ = trueIn;
+     if (trueOut >= 0)
+          trueSequenceOut_ = trueOut;
+     if (doPrinting && 0) {
+          for (int i = 0; i < numberSets_; i++) {
+               printf("set %d key %d lower %g upper %g\n", i, keyVariable_[i], lower_[i], upper_[i]);
+               for (int j = fullStart_[i]; j < fullStart_[i+1]; j++)
+                    if (getDynamicStatus(j) == atUpperBound) {
+                         bool print = true;
+                         for (int k = firstDynamic_; k < firstAvailable_; k++) {
+                              if (id_[k-firstDynamic_] == j)
+                                   print = false;
+                              if (id_[k-firstDynamic_] == j)
+                                   assert(getDynamicStatus(j) == inSmall);
+                         }
+                         if (print)
+                              printf("variable %d at ub\n", j);
+                    }
+          }
+     }
+#ifdef CLP_DEBUG
+     char * inSmall = new char [numberGubColumns_];
+     memset(inSmall, 0, numberGubColumns_);
+     for (int i = 0; i < numberGubColumns_; i++)
+          if (getDynamicStatus(i) == ClpGubDynamicMatrix::inSmall)
+               inSmall[i] = 1;
+     for (int i = firstDynamic_; i < firstAvailable_; i++) {
+          int k = id_[i-firstDynamic_];
+          inSmall[k] = 0;
+     }
+     for (int i = 0; i < numberGubColumns_; i++)
+          assert (!inSmall[i]);
+     delete [] inSmall;
+#endif
+     return 0;
+}
+void
+ClpGubDynamicMatrix::times(double scalar,
+                           const double * x, double * y) const
+{
+     if (model_->specialOptions() != 16) {
+          ClpPackedMatrix::times(scalar, x, y);
+     } else {
+          int iRow;
+          int numberColumns = model_->numberColumns();
+          int numberRows = model_->numberRows();
+          const double * element =  matrix_->getElements();
+          const int * row = matrix_->getIndices();
+          const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+          const int * length = matrix_->getVectorLengths();
+          int * pivotVariable = model_->pivotVariable();
+          int numberToDo = 0;
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               y[iRow] -= scalar * rhsOffset_[iRow];
+               int iColumn = pivotVariable[iRow];
+               if (iColumn < numberColumns) {
+                    int iSet = backward_[iColumn];
+                    if (iSet >= 0 && toIndex_[iSet] < 0) {
+                         toIndex_[iSet] = 0;
+                         fromIndex_[numberToDo++] = iSet;
+                    }
+                    CoinBigIndex j;
+                    double value = scalar * x[iColumn];
+                    if (value) {
+                         for (j = startColumn[iColumn];
+                                   j < startColumn[iColumn] + length[iColumn]; j++) {
+                              int jRow = row[j];
+                              y[jRow] += value * element[j];
+                         }
+                    }
+               }
+          }
+          // and gubs which are interacting
+          for (int jSet = 0; jSet < numberToDo; jSet++) {
+               int iSet = fromIndex_[jSet];
+               toIndex_[iSet] = -1;
+               int iKey = keyVariable_[iSet];
+               if (iKey < numberColumns) {
+                    double valueKey;
+                    if (getStatus(iSet) == ClpSimplex::atLowerBound)
+                         valueKey = lower_[iSet];
+                    else
+                         valueKey = upper_[iSet];
+                    double value = scalar * (x[iKey] - valueKey);
+                    if (value) {
+                         for (CoinBigIndex j = startColumn[iKey];
+                                   j < startColumn[iKey] + length[iKey]; j++) {
+                              int jRow = row[j];
+                              y[jRow] += value * element[j];
+                         }
+                    }
+               }
+          }
+     }
+}
+/* Just for debug - may be extended to other matrix types later.
+   Returns number and sum of primal infeasibilities.
+*/
+int
+ClpGubDynamicMatrix::checkFeasible(ClpSimplex * /*model*/, double & sum) const
+{
+     int numberRows = model_->numberRows();
+     double * rhs = new double[numberRows];
+     int numberColumns = model_->numberColumns();
+     int iRow;
+     CoinZeroN(rhs, numberRows);
+     // do ones at bounds before gub
+     const double * smallSolution = model_->solutionRegion();
+     const double * element = matrix_->getElements();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+     const int * length = matrix_->getVectorLengths();
+     int iColumn;
+     int numberInfeasible = 0;
+     const double * rowLower = model_->rowLower();
+     const double * rowUpper = model_->rowUpper();
+     sum = 0.0;
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          double value = smallSolution[numberColumns+iRow];
+          if (value < rowLower[iRow] - 1.0e-5 ||
+                    value > rowUpper[iRow] + 1.0e-5) {
+               //printf("row %d %g %g %g\n",
+               //     iRow,rowLower[iRow],value,rowUpper[iRow]);
+               numberInfeasible++;
+               sum += CoinMax(rowLower[iRow] - value, value - rowUpper[iRow]);
+          }
+          rhs[iRow] = value;
+     }
+     const double * columnLower = model_->columnLower();
+     const double * columnUpper = model_->columnUpper();
+     for (iColumn = 0; iColumn < firstDynamic_; iColumn++) {
+          double value = smallSolution[iColumn];
+          if (value < columnLower[iColumn] - 1.0e-5 ||
+                    value > columnUpper[iColumn] + 1.0e-5) {
+               //printf("column %d %g %g %g\n",
+               //     iColumn,columnLower[iColumn],value,columnUpper[iColumn]);
+               numberInfeasible++;
+               sum += CoinMax(columnLower[iColumn] - value, value - columnUpper[iColumn]);
+          }
+          for (CoinBigIndex j = startColumn[iColumn];
+                    j < startColumn[iColumn] + length[iColumn]; j++) {
+               int jRow = row[j];
+               rhs[jRow] -= value * element[j];
+          }
+     }
+     double * solution = new double [numberGubColumns_];
+     for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) {
+          double value = 0.0;
+          if(getDynamicStatus(iColumn) == atUpperBound)
+               value = upperColumn_[iColumn];
+          else if (lowerColumn_)
+               value = lowerColumn_[iColumn];
+          solution[iColumn] = value;
+     }
+     // ones in small and gub
+     for (iColumn = firstDynamic_; iColumn < firstAvailable_; iColumn++) {
+          int jFull = id_[iColumn-firstDynamic_];
+          solution[jFull] = smallSolution[iColumn];
+     }
+     // fill in all basic in small model
+     int * pivotVariable = model_->pivotVariable();
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          int iColumn = pivotVariable[iRow];
+          if (iColumn >= firstDynamic_ && iColumn < lastDynamic_) {
+               int iSequence = id_[iColumn-firstDynamic_];
+               solution[iSequence] = smallSolution[iColumn];
+          }
+     }
+     // and now compute value to use for key
+     ClpSimplex::Status iStatus;
+     for (int iSet = 0; iSet < numberSets_; iSet++) {
+          iColumn = keyVariable_[iSet];
+          if (iColumn < numberColumns) {
+               int iSequence = id_[iColumn-firstDynamic_];
+               solution[iSequence] = 0.0;
+               double b = 0.0;
+               // key is structural - where is slack
+               iStatus = getStatus(iSet);
+               assert (iStatus != ClpSimplex::basic);
+               if (iStatus == ClpSimplex::atLowerBound)
+                    b = lower_[iSet];
+               else
+                    b = upper_[iSet];
+               // subtract out others at bounds
+               for (int j = fullStart_[iSet]; j < fullStart_[iSet+1]; j++)
+                    b -= solution[j];
+               solution[iSequence] = b;
+          }
+     }
+     for (iColumn = 0; iColumn < numberGubColumns_; iColumn++) {
+          double value = solution[iColumn];
+          if ((lowerColumn_ && value < lowerColumn_[iColumn] - 1.0e-5) ||
+                    (!lowerColumn_ && value < -1.0e-5) ||
+                    (upperColumn_ && value > upperColumn_[iColumn] + 1.0e-5)) {
+               //printf("column %d %g %g %g\n",
+               //     iColumn,lowerColumn_[iColumn],value,upperColumn_[iColumn]);
+               numberInfeasible++;
+          }
+          if (value) {
+               for (CoinBigIndex j = startColumn_[iColumn]; j < startColumn_[iColumn+1]; j++) {
+                    int iRow = row_[j];
+                    rhs[iRow] -= element_[j] * value;
+               }
+          }
+     }
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          if (fabs(rhs[iRow]) > 1.0e-5)
+               printf("rhs mismatch %d %g\n", iRow, rhs[iRow]);
+     }
+     delete [] solution;
+     delete [] rhs;
+     return numberInfeasible;
+}
+// Cleans data after setWarmStart
+void
+ClpGubDynamicMatrix::cleanData(ClpSimplex * model)
+{
+     // and redo chains
+     int numberColumns = model->numberColumns();
+     int iColumn;
+     // do backward
+     int * mark = new int [numberGubColumns_];
+     for (iColumn = 0; iColumn < numberGubColumns_; iColumn++)
+          mark[iColumn] = -1;
+     int i;
+     for (i = 0; i < firstDynamic_; i++) {
+          assert (backward_[i] == -1);
+          next_[i] = -1;
+     }
+     for (i = firstDynamic_; i < firstAvailable_; i++) {
+          iColumn = id_[i-firstDynamic_];
+          mark[iColumn] = i;
+     }
+     for (i = 0; i < numberSets_; i++) {
+          int iKey = keyVariable_[i];
+          int lastNext = -1;
+          int firstNext = -1;
+          for (CoinBigIndex k = fullStart_[i]; k < fullStart_[i+1]; k++) {
+               iColumn = mark[k];
+               if (iColumn >= 0) {
+                    if (iColumn != iKey) {
+                         if (lastNext >= 0)
+                              next_[lastNext] = iColumn;
+                         else
+                              firstNext = iColumn;
+                         lastNext = iColumn;
+                    }
+                    backward_[iColumn] = i;
+               }
+          }
+          setFeasible(i);
+          if (firstNext >= 0) {
+               // others
+               next_[iKey] = firstNext;
+               next_[lastNext] = -(iKey + 1);
+          } else if (iKey < numberColumns) {
+               next_[iKey] = -(iKey + 1);
+          }
+     }
+     delete [] mark;
+     // fill matrix
+     double * element =  matrix_->getMutableElements();
+     int * row = matrix_->getMutableIndices();
+     CoinBigIndex * startColumn = matrix_->getMutableVectorStarts();
+     int * length = matrix_->getMutableVectorLengths();
+     CoinBigIndex numberElements = startColumn[firstDynamic_];
+     for (i = firstDynamic_; i < firstAvailable_; i++) {
+          int iColumn = id_[i-firstDynamic_];
+          int numberThis = startColumn_[iColumn+1] - startColumn_[iColumn];
+          length[i] = numberThis;
+          for (CoinBigIndex jBigIndex = startColumn_[iColumn];
+                    jBigIndex < startColumn_[iColumn+1]; jBigIndex++) {
+               row[numberElements] = row_[jBigIndex];
+               element[numberElements++] = element_[jBigIndex];
+          }
+          startColumn[i+1] = numberElements;
+     }
+}
diff --git a/cbits/coin/ClpGubDynamicMatrix.hpp b/cbits/coin/ClpGubDynamicMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpGubDynamicMatrix.hpp
@@ -0,0 +1,247 @@
+/* $Id: ClpGubDynamicMatrix.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpGubDynamicMatrix_H
+#define ClpGubDynamicMatrix_H
+
+
+#include "CoinPragma.hpp"
+
+#include "ClpGubMatrix.hpp"
+/** This implements Gub rows plus a ClpPackedMatrix.
+    This a dynamic version which stores the gub part and dynamically creates matrix.
+    All bounds are assumed to be zero and infinity
+
+    This is just a simple example for real column generation
+*/
+
+class ClpGubDynamicMatrix : public ClpGubMatrix {
+
+public:
+     /**@name Main functions provided */
+     //@{
+     /// Partial pricing
+     virtual void partialPricing(ClpSimplex * model, double start, double end,
+                                 int & bestSequence, int & numberWanted);
+     /** This is local to Gub to allow synchronization:
+         mode=0 when status of basis is good
+         mode=1 when variable is flagged
+         mode=2 when all variables unflagged (returns number flagged)
+         mode=3 just reset costs (primal)
+         mode=4 correct number of dual infeasibilities
+         mode=5 return 4 if time to re-factorize
+         mode=8  - make sure set is clean
+         mode=9  - adjust lower, upper on set by incoming
+     */
+     virtual int synchronize(ClpSimplex * model, int mode);
+     /// Sets up an effective RHS and does gub crash if needed
+     virtual void useEffectiveRhs(ClpSimplex * model, bool cheapest = true);
+     /**
+        update information for a pivot (and effective rhs)
+     */
+     virtual int updatePivot(ClpSimplex * model, double oldInValue, double oldOutValue);
+     /// Add a new variable to a set
+     void insertNonBasic(int sequence, int iSet);
+     /** Returns effective RHS offset if it is being used.  This is used for long problems
+         or big gub or anywhere where going through full columns is
+         expensive.  This may re-compute */
+     virtual double * rhsOffset(ClpSimplex * model, bool forceRefresh = false,
+                                bool check = false);
+
+     using ClpPackedMatrix::times ;
+     /** Return <code>y + A * scalar *x</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numColumns()</code>
+         @pre <code>y</code> must be of size <code>numRows()</code> */
+     virtual void times(double scalar,
+                        const double * x, double * y) const;
+     /** Just for debug
+         Returns sum and number of primal infeasibilities. Recomputes keys
+     */
+     virtual int checkFeasible(ClpSimplex * model, double & sum) const;
+     /// Cleans data after setWarmStart
+     void cleanData(ClpSimplex * model);
+     //@}
+
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpGubDynamicMatrix();
+     /** Destructor */
+     virtual ~ClpGubDynamicMatrix();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpGubDynamicMatrix(const ClpGubDynamicMatrix&);
+     /** This is the real constructor.
+         It assumes factorization frequency will not be changed.
+         This resizes model !!!!
+      */
+     ClpGubDynamicMatrix(ClpSimplex * model, int numberSets,
+                         int numberColumns, const int * starts,
+                         const double * lower, const double * upper,
+                         const int * startColumn, const int * row,
+                         const double * element, const double * cost,
+                         const double * lowerColumn = NULL, const double * upperColumn = NULL,
+                         const unsigned char * status = NULL);
+
+     ClpGubDynamicMatrix& operator=(const ClpGubDynamicMatrix&);
+     /// Clone
+     virtual ClpMatrixBase * clone() const ;
+     //@}
+     /**@name gets and sets */
+     //@{
+     /// enums for status of various sorts
+     enum DynamicStatus {
+          inSmall = 0x01,
+          atUpperBound = 0x02,
+          atLowerBound = 0x03
+     };
+     /// Whether flagged
+     inline bool flagged(int i) const {
+          return (dynamicStatus_[i] & 8) != 0;
+     }
+     inline void setFlagged(int i) {
+          dynamicStatus_[i] = static_cast<unsigned char>(dynamicStatus_[i] | 8);
+     }
+     inline void unsetFlagged(int i) {
+          dynamicStatus_[i] = static_cast<unsigned char>(dynamicStatus_[i] & ~8);
+     }
+     inline void setDynamicStatus(int sequence, DynamicStatus status) {
+          unsigned char & st_byte = dynamicStatus_[sequence];
+          st_byte = static_cast<unsigned char>(st_byte & ~7);
+          st_byte = static_cast<unsigned char>(st_byte | status);
+     }
+     inline DynamicStatus getDynamicStatus(int sequence) const {
+          return static_cast<DynamicStatus> (dynamicStatus_[sequence] & 7);
+     }
+     /// Saved value of objective offset
+     inline double objectiveOffset() const {
+          return objectiveOffset_;
+     }
+     /// Starts of each column
+     inline CoinBigIndex * startColumn() const {
+          return startColumn_;
+     }
+     /// rows
+     inline int * row() const {
+          return row_;
+     }
+     /// elements
+     inline double * element() const {
+          return element_;
+     }
+     /// costs
+     inline double * cost() const {
+          return cost_;
+     }
+     /// full starts
+     inline int * fullStart() const {
+          return fullStart_;
+     }
+     /// ids of active columns (just index here)
+     inline int * id() const {
+          return id_;
+     }
+     /// Optional lower bounds on columns
+     inline double * lowerColumn() const {
+          return lowerColumn_;
+     }
+     /// Optional upper bounds on columns
+     inline double * upperColumn() const {
+          return upperColumn_;
+     }
+     /// Optional true lower bounds on sets
+     inline double * lowerSet() const {
+          return lowerSet_;
+     }
+     /// Optional true upper bounds on sets
+     inline double * upperSet() const {
+          return upperSet_;
+     }
+     /// size
+     inline int numberGubColumns() const {
+          return numberGubColumns_;
+     }
+     /// first free
+     inline int firstAvailable() const {
+          return firstAvailable_;
+     }
+     /// set first free
+     inline void setFirstAvailable(int value) {
+          firstAvailable_ = value;
+     }
+     /// first dynamic
+     inline int firstDynamic() const {
+          return firstDynamic_;
+     }
+     /// number of columns in dynamic model
+     inline int lastDynamic() const {
+          return lastDynamic_;
+     }
+     /// size of working matrix (max)
+     inline int numberElements() const {
+          return numberElements_;
+     }
+     /// Status region for gub slacks
+     inline unsigned char * gubRowStatus() const {
+          return status_;
+     }
+     /// Status region for gub variables
+     inline unsigned char * dynamicStatus() const {
+          return dynamicStatus_;
+     }
+     /// Returns which set a variable is in
+     int whichSet (int sequence) const;
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Saved value of objective offset
+     double objectiveOffset_;
+     /// Starts of each column
+     CoinBigIndex * startColumn_;
+     /// rows
+     int * row_;
+     /// elements
+     double * element_;
+     /// costs
+     double * cost_;
+     /// full starts
+     int * fullStart_;
+     /// ids of active columns (just index here)
+     int * id_;
+     /// for status and which bound
+     unsigned char * dynamicStatus_;
+     /// Optional lower bounds on columns
+     double * lowerColumn_;
+     /// Optional upper bounds on columns
+     double * upperColumn_;
+     /// Optional true lower bounds on sets
+     double * lowerSet_;
+     /// Optional true upper bounds on sets
+     double * upperSet_;
+     /// size
+     int numberGubColumns_;
+     /// first free
+     int firstAvailable_;
+     /// saved first free
+     int savedFirstAvailable_;
+     /// first dynamic
+     int firstDynamic_;
+     /// number of columns in dynamic model
+     int lastDynamic_;
+     /// size of working matrix (max)
+     int numberElements_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpGubMatrix.cpp b/cbits/coin/ClpGubMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpGubMatrix.cpp
@@ -0,0 +1,4061 @@
+/* $Id: ClpGubMatrix.cpp 1931 2013-04-06 20:44:29Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include <cstdio>
+
+#include "CoinPragma.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpQuadraticObjective.hpp"
+#include "ClpNonLinearCost.hpp"
+// at end to get min/max!
+#include "ClpGubMatrix.hpp"
+//#include "ClpGubDynamicMatrix.hpp"
+#include "ClpMessage.hpp"
+//#define CLP_DEBUG
+//#define CLP_DEBUG_PRINT
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpGubMatrix::ClpGubMatrix ()
+     : ClpPackedMatrix(),
+       sumDualInfeasibilities_(0.0),
+       sumPrimalInfeasibilities_(0.0),
+       sumOfRelaxedDualInfeasibilities_(0.0),
+       sumOfRelaxedPrimalInfeasibilities_(0.0),
+       infeasibilityWeight_(0.0),
+       start_(NULL),
+       end_(NULL),
+       lower_(NULL),
+       upper_(NULL),
+       status_(NULL),
+       saveStatus_(NULL),
+       savedKeyVariable_(NULL),
+       backward_(NULL),
+       backToPivotRow_(NULL),
+       changeCost_(NULL),
+       keyVariable_(NULL),
+       next_(NULL),
+       toIndex_(NULL),
+       fromIndex_(NULL),
+       model_(NULL),
+       numberDualInfeasibilities_(0),
+       numberPrimalInfeasibilities_(0),
+       noCheck_(-1),
+       numberSets_(0),
+       saveNumber_(0),
+       possiblePivotKey_(0),
+       gubSlackIn_(-1),
+       firstGub_(0),
+       lastGub_(0),
+       gubType_(0)
+{
+     setType(16);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpGubMatrix::ClpGubMatrix (const ClpGubMatrix & rhs)
+     : ClpPackedMatrix(rhs)
+{
+     numberSets_ = rhs.numberSets_;
+     saveNumber_ = rhs.saveNumber_;
+     possiblePivotKey_ = rhs.possiblePivotKey_;
+     gubSlackIn_ = rhs.gubSlackIn_;
+     start_ = ClpCopyOfArray(rhs.start_, numberSets_);
+     end_ = ClpCopyOfArray(rhs.end_, numberSets_);
+     lower_ = ClpCopyOfArray(rhs.lower_, numberSets_);
+     upper_ = ClpCopyOfArray(rhs.upper_, numberSets_);
+     status_ = ClpCopyOfArray(rhs.status_, numberSets_);
+     saveStatus_ = ClpCopyOfArray(rhs.saveStatus_, numberSets_);
+     savedKeyVariable_ = ClpCopyOfArray(rhs.savedKeyVariable_, numberSets_);
+     int numberColumns = getNumCols();
+     backward_ = ClpCopyOfArray(rhs.backward_, numberColumns);
+     backToPivotRow_ = ClpCopyOfArray(rhs.backToPivotRow_, numberColumns);
+     changeCost_ = ClpCopyOfArray(rhs.changeCost_, getNumRows() + numberSets_);
+     fromIndex_ = ClpCopyOfArray(rhs.fromIndex_, getNumRows() + numberSets_ + 1);
+     keyVariable_ = ClpCopyOfArray(rhs.keyVariable_, numberSets_);
+     // find longest set
+     int * longest = new int[numberSets_];
+     CoinZeroN(longest, numberSets_);
+     int j;
+     for (j = 0; j < numberColumns; j++) {
+          int iSet = backward_[j];
+          if (iSet >= 0)
+               longest[iSet]++;
+     }
+     int length = 0;
+     for (j = 0; j < numberSets_; j++)
+          length = CoinMax(length, longest[j]);
+     next_ = ClpCopyOfArray(rhs.next_, numberColumns + numberSets_ + 2 * length);
+     toIndex_ = ClpCopyOfArray(rhs.toIndex_, numberSets_);
+     sumDualInfeasibilities_ = rhs. sumDualInfeasibilities_;
+     sumPrimalInfeasibilities_ = rhs.sumPrimalInfeasibilities_;
+     sumOfRelaxedDualInfeasibilities_ = rhs.sumOfRelaxedDualInfeasibilities_;
+     sumOfRelaxedPrimalInfeasibilities_ = rhs.sumOfRelaxedPrimalInfeasibilities_;
+     infeasibilityWeight_ = rhs.infeasibilityWeight_;
+     numberDualInfeasibilities_ = rhs.numberDualInfeasibilities_;
+     numberPrimalInfeasibilities_ = rhs.numberPrimalInfeasibilities_;
+     noCheck_ = rhs.noCheck_;
+     firstGub_ = rhs.firstGub_;
+     lastGub_ = rhs.lastGub_;
+     gubType_ = rhs.gubType_;
+     model_ = rhs.model_;
+}
+
+//-------------------------------------------------------------------
+// assign matrix (for space reasons)
+//-------------------------------------------------------------------
+ClpGubMatrix::ClpGubMatrix (CoinPackedMatrix * rhs)
+     : ClpPackedMatrix(rhs),
+       sumDualInfeasibilities_(0.0),
+       sumPrimalInfeasibilities_(0.0),
+       sumOfRelaxedDualInfeasibilities_(0.0),
+       sumOfRelaxedPrimalInfeasibilities_(0.0),
+       infeasibilityWeight_(0.0),
+       start_(NULL),
+       end_(NULL),
+       lower_(NULL),
+       upper_(NULL),
+       status_(NULL),
+       saveStatus_(NULL),
+       savedKeyVariable_(NULL),
+       backward_(NULL),
+       backToPivotRow_(NULL),
+       changeCost_(NULL),
+       keyVariable_(NULL),
+       next_(NULL),
+       toIndex_(NULL),
+       fromIndex_(NULL),
+       model_(NULL),
+       numberDualInfeasibilities_(0),
+       numberPrimalInfeasibilities_(0),
+       noCheck_(-1),
+       numberSets_(0),
+       saveNumber_(0),
+       possiblePivotKey_(0),
+       gubSlackIn_(-1),
+       firstGub_(0),
+       lastGub_(0),
+       gubType_(0)
+{
+     setType(16);
+}
+
+/* This takes over ownership (for space reasons) and is the
+   real constructor*/
+ClpGubMatrix::ClpGubMatrix(ClpPackedMatrix * matrix, int numberSets,
+                           const int * start, const int * end,
+                           const double * lower, const double * upper,
+                           const unsigned char * status)
+     : ClpPackedMatrix(matrix->matrix()),
+       sumDualInfeasibilities_(0.0),
+       sumPrimalInfeasibilities_(0.0),
+       sumOfRelaxedDualInfeasibilities_(0.0),
+       sumOfRelaxedPrimalInfeasibilities_(0.0),
+       numberDualInfeasibilities_(0),
+       numberPrimalInfeasibilities_(0),
+       saveNumber_(0),
+       possiblePivotKey_(0),
+       gubSlackIn_(-1)
+{
+     model_ = NULL;
+     numberSets_ = numberSets;
+     start_ = ClpCopyOfArray(start, numberSets_);
+     end_ = ClpCopyOfArray(end, numberSets_);
+     lower_ = ClpCopyOfArray(lower, numberSets_);
+     upper_ = ClpCopyOfArray(upper, numberSets_);
+     // Check valid and ordered
+     int last = -1;
+     int numberColumns = matrix_->getNumCols();
+     int numberRows = matrix_->getNumRows();
+     backward_ = new int[numberColumns];
+     backToPivotRow_ = new int[numberColumns];
+     changeCost_ = new double [numberRows+numberSets_];
+     keyVariable_ = new int[numberSets_];
+     // signal to need new ordering
+     next_ = NULL;
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++)
+          backward_[iColumn] = -1;
+
+     int iSet;
+     for (iSet = 0; iSet < numberSets_; iSet++) {
+          // set key variable as slack
+          keyVariable_[iSet] = iSet + numberColumns;
+          if (start_[iSet] < 0 || start_[iSet] >= numberColumns)
+               throw CoinError("Index out of range", "constructor", "ClpGubMatrix");
+          if (end_[iSet] < 0 || end_[iSet] > numberColumns)
+               throw CoinError("Index out of range", "constructor", "ClpGubMatrix");
+          if (end_[iSet] <= start_[iSet])
+               throw CoinError("Empty or negative set", "constructor", "ClpGubMatrix");
+          if (start_[iSet] < last)
+               throw CoinError("overlapping or non-monotonic sets", "constructor", "ClpGubMatrix");
+          last = end_[iSet];
+          int j;
+          for (j = start_[iSet]; j < end_[iSet]; j++)
+               backward_[j] = iSet;
+     }
+     // Find type of gub
+     firstGub_ = numberColumns + 1;
+     lastGub_ = -1;
+     int i;
+     for (i = 0; i < numberColumns; i++) {
+          if (backward_[i] >= 0) {
+               firstGub_ = CoinMin(firstGub_, i);
+               lastGub_ = CoinMax(lastGub_, i);
+          }
+     }
+     gubType_ = 0;
+     // adjust lastGub_
+     if (lastGub_ > 0)
+          lastGub_++;
+     for (i = firstGub_; i < lastGub_; i++) {
+          if (backward_[i] < 0) {
+               gubType_ = 1;
+               printf("interior non gub %d\n", i);
+               break;
+          }
+     }
+     if (status) {
+          status_ = ClpCopyOfArray(status, numberSets_);
+     } else {
+          status_ = new unsigned char [numberSets_];
+          memset(status_, 0, numberSets_);
+          int i;
+          for (i = 0; i < numberSets_; i++) {
+               // make slack key
+               setStatus(i, ClpSimplex::basic);
+          }
+     }
+     saveStatus_ = new unsigned char [numberSets_];
+     memset(saveStatus_, 0, numberSets_);
+     savedKeyVariable_ = new int [numberSets_];
+     memset(savedKeyVariable_, 0, numberSets_ * sizeof(int));
+     noCheck_ = -1;
+     infeasibilityWeight_ = 0.0;
+}
+
+ClpGubMatrix::ClpGubMatrix (const CoinPackedMatrix & rhs)
+     : ClpPackedMatrix(rhs),
+       sumDualInfeasibilities_(0.0),
+       sumPrimalInfeasibilities_(0.0),
+       sumOfRelaxedDualInfeasibilities_(0.0),
+       sumOfRelaxedPrimalInfeasibilities_(0.0),
+       infeasibilityWeight_(0.0),
+       start_(NULL),
+       end_(NULL),
+       lower_(NULL),
+       upper_(NULL),
+       status_(NULL),
+       saveStatus_(NULL),
+       savedKeyVariable_(NULL),
+       backward_(NULL),
+       backToPivotRow_(NULL),
+       changeCost_(NULL),
+       keyVariable_(NULL),
+       next_(NULL),
+       toIndex_(NULL),
+       fromIndex_(NULL),
+       model_(NULL),
+       numberDualInfeasibilities_(0),
+       numberPrimalInfeasibilities_(0),
+       noCheck_(-1),
+       numberSets_(0),
+       saveNumber_(0),
+       possiblePivotKey_(0),
+       gubSlackIn_(-1),
+       firstGub_(0),
+       lastGub_(0),
+       gubType_(0)
+{
+     setType(16);
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpGubMatrix::~ClpGubMatrix ()
+{
+     delete [] start_;
+     delete [] end_;
+     delete [] lower_;
+     delete [] upper_;
+     delete [] status_;
+     delete [] saveStatus_;
+     delete [] savedKeyVariable_;
+     delete [] backward_;
+     delete [] backToPivotRow_;
+     delete [] changeCost_;
+     delete [] keyVariable_;
+     delete [] next_;
+     delete [] toIndex_;
+     delete [] fromIndex_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpGubMatrix &
+ClpGubMatrix::operator=(const ClpGubMatrix& rhs)
+{
+     if (this != &rhs) {
+          ClpPackedMatrix::operator=(rhs);
+          delete [] start_;
+          delete [] end_;
+          delete [] lower_;
+          delete [] upper_;
+          delete [] status_;
+          delete [] saveStatus_;
+          delete [] savedKeyVariable_;
+          delete [] backward_;
+          delete [] backToPivotRow_;
+          delete [] changeCost_;
+          delete [] keyVariable_;
+          delete [] next_;
+          delete [] toIndex_;
+          delete [] fromIndex_;
+          numberSets_ = rhs.numberSets_;
+          saveNumber_ = rhs.saveNumber_;
+          possiblePivotKey_ = rhs.possiblePivotKey_;
+          gubSlackIn_ = rhs.gubSlackIn_;
+          start_ = ClpCopyOfArray(rhs.start_, numberSets_);
+          end_ = ClpCopyOfArray(rhs.end_, numberSets_);
+          lower_ = ClpCopyOfArray(rhs.lower_, numberSets_);
+          upper_ = ClpCopyOfArray(rhs.upper_, numberSets_);
+          status_ = ClpCopyOfArray(rhs.status_, numberSets_);
+          saveStatus_ = ClpCopyOfArray(rhs.saveStatus_, numberSets_);
+          savedKeyVariable_ = ClpCopyOfArray(rhs.savedKeyVariable_, numberSets_);
+          int numberColumns = getNumCols();
+          backward_ = ClpCopyOfArray(rhs.backward_, numberColumns);
+          backToPivotRow_ = ClpCopyOfArray(rhs.backToPivotRow_, numberColumns);
+          changeCost_ = ClpCopyOfArray(rhs.changeCost_, getNumRows() + numberSets_);
+          fromIndex_ = ClpCopyOfArray(rhs.fromIndex_, getNumRows() + numberSets_ + 1);
+          keyVariable_ = ClpCopyOfArray(rhs.keyVariable_, numberSets_);
+          // find longest set
+          int * longest = new int[numberSets_];
+          CoinZeroN(longest, numberSets_);
+          int j;
+          for (j = 0; j < numberColumns; j++) {
+               int iSet = backward_[j];
+               if (iSet >= 0)
+                    longest[iSet]++;
+          }
+          int length = 0;
+          for (j = 0; j < numberSets_; j++)
+               length = CoinMax(length, longest[j]);
+          next_ = ClpCopyOfArray(rhs.next_, numberColumns + numberSets_ + 2 * length);
+          toIndex_ = ClpCopyOfArray(rhs.toIndex_, numberSets_);
+          sumDualInfeasibilities_ = rhs. sumDualInfeasibilities_;
+          sumPrimalInfeasibilities_ = rhs.sumPrimalInfeasibilities_;
+          sumOfRelaxedDualInfeasibilities_ = rhs.sumOfRelaxedDualInfeasibilities_;
+          sumOfRelaxedPrimalInfeasibilities_ = rhs.sumOfRelaxedPrimalInfeasibilities_;
+          infeasibilityWeight_ = rhs.infeasibilityWeight_;
+          numberDualInfeasibilities_ = rhs.numberDualInfeasibilities_;
+          numberPrimalInfeasibilities_ = rhs.numberPrimalInfeasibilities_;
+          noCheck_ = rhs.noCheck_;
+          firstGub_ = rhs.firstGub_;
+          lastGub_ = rhs.lastGub_;
+          gubType_ = rhs.gubType_;
+          model_ = rhs.model_;
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpMatrixBase * ClpGubMatrix::clone() const
+{
+     return new ClpGubMatrix(*this);
+}
+/* Subset clone (without gaps).  Duplicates are allowed
+   and order is as given */
+ClpMatrixBase *
+ClpGubMatrix::subsetClone (int numberRows, const int * whichRows,
+                           int numberColumns,
+                           const int * whichColumns) const
+{
+     return new ClpGubMatrix(*this, numberRows, whichRows,
+                             numberColumns, whichColumns);
+}
+/* Returns a new matrix in reverse order without gaps
+   Is allowed to return NULL if doesn't want to have row copy */
+ClpMatrixBase *
+ClpGubMatrix::reverseOrderedCopy() const
+{
+     return NULL;
+}
+int
+ClpGubMatrix::hiddenRows() const
+{
+     return numberSets_;
+}
+/* Subset constructor (without gaps).  Duplicates are allowed
+   and order is as given */
+ClpGubMatrix::ClpGubMatrix (
+     const ClpGubMatrix & rhs,
+     int numberRows, const int * whichRows,
+     int numberColumns, const int * whichColumns)
+     : ClpPackedMatrix(rhs, numberRows, whichRows, numberColumns, whichColumns)
+{
+     // Assuming no gub rows deleted
+     // We also assume all sets in same order
+     // Get array with backward pointers
+     int numberColumnsOld = rhs.matrix_->getNumCols();
+     int * array = new int [ numberColumnsOld];
+     int i;
+     for (i = 0; i < numberColumnsOld; i++)
+          array[i] = -1;
+     for (int iSet = 0; iSet < numberSets_; iSet++) {
+          for (int j = start_[iSet]; j < end_[iSet]; j++)
+               array[j] = iSet;
+     }
+     numberSets_ = -1;
+     int lastSet = -1;
+     bool inSet = false;
+     for (i = 0; i < numberColumns; i++) {
+          int iColumn = whichColumns[i];
+          int iSet = array[iColumn];
+          if (iSet < 0) {
+               inSet = false;
+          } else {
+               if (!inSet) {
+                    // start of new set but check okay
+                    if (iSet <= lastSet)
+                         throw CoinError("overlapping or non-monotonic sets", "subset constructor", "ClpGubMatrix");
+                    lastSet = iSet;
+                    numberSets_++;
+                    start_[numberSets_] = i;
+                    end_[numberSets_] = i + 1;
+                    lower_[numberSets_] = lower_[iSet];
+                    upper_[numberSets_] = upper_[iSet];
+                    inSet = true;
+               } else {
+                    if (iSet < lastSet) {
+                         throw CoinError("overlapping or non-monotonic sets", "subset constructor", "ClpGubMatrix");
+                    } else if (iSet == lastSet) {
+                         end_[numberSets_] = i + 1;
+                    } else {
+                         // new set
+                         lastSet = iSet;
+                         numberSets_++;
+                         start_[numberSets_] = i;
+                         end_[numberSets_] = i + 1;
+                         lower_[numberSets_] = lower_[iSet];
+                         upper_[numberSets_] = upper_[iSet];
+                    }
+               }
+          }
+     }
+     delete [] array;
+     numberSets_++; // adjust
+     // Find type of gub
+     firstGub_ = numberColumns + 1;
+     lastGub_ = -1;
+     for (i = 0; i < numberColumns; i++) {
+          if (backward_[i] >= 0) {
+               firstGub_ = CoinMin(firstGub_, i);
+               lastGub_ = CoinMax(lastGub_, i);
+          }
+     }
+     if (lastGub_ > 0)
+          lastGub_++;
+     gubType_ = 0;
+     for (i = firstGub_; i < lastGub_; i++) {
+          if (backward_[i] < 0) {
+               gubType_ = 1;
+               break;
+          }
+     }
+
+     // Make sure key is feasible if only key in set
+}
+ClpGubMatrix::ClpGubMatrix (
+     const CoinPackedMatrix & rhs,
+     int numberRows, const int * whichRows,
+     int numberColumns, const int * whichColumns)
+     : ClpPackedMatrix(rhs, numberRows, whichRows, numberColumns, whichColumns),
+       sumDualInfeasibilities_(0.0),
+       sumPrimalInfeasibilities_(0.0),
+       sumOfRelaxedDualInfeasibilities_(0.0),
+       sumOfRelaxedPrimalInfeasibilities_(0.0),
+       start_(NULL),
+       end_(NULL),
+       lower_(NULL),
+       upper_(NULL),
+       backward_(NULL),
+       backToPivotRow_(NULL),
+       changeCost_(NULL),
+       keyVariable_(NULL),
+       next_(NULL),
+       toIndex_(NULL),
+       fromIndex_(NULL),
+       numberDualInfeasibilities_(0),
+       numberPrimalInfeasibilities_(0),
+       numberSets_(0),
+       saveNumber_(0),
+       possiblePivotKey_(0),
+       gubSlackIn_(-1),
+       firstGub_(0),
+       lastGub_(0),
+       gubType_(0)
+{
+     setType(16);
+}
+/* Return <code>x * A + y</code> in <code>z</code>.
+	Squashes small elements and knows about ClpSimplex */
+void
+ClpGubMatrix::transposeTimes(const ClpSimplex * model, double scalar,
+                             const CoinIndexedVector * rowArray,
+                             CoinIndexedVector * y,
+                             CoinIndexedVector * columnArray) const
+{
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     int numberNonZero = 0;
+     int * index = columnArray->getIndices();
+     double * array = columnArray->denseVector();
+     int numberInRowArray = rowArray->getNumElements();
+     // maybe I need one in OsiSimplex
+     double zeroTolerance = model->zeroTolerance();
+     int numberRows = model->numberRows();
+     ClpPackedMatrix* rowCopy =
+          dynamic_cast< ClpPackedMatrix*>(model->rowCopy());
+     bool packed = rowArray->packedMode();
+     double factor = 0.3;
+     // We may not want to do by row if there may be cache problems
+     int numberColumns = model->numberColumns();
+     // It would be nice to find L2 cache size - for moment 512K
+     // Be slightly optimistic
+     if (numberColumns * sizeof(double) > 1000000) {
+          if (numberRows * 10 < numberColumns)
+               factor = 0.1;
+          else if (numberRows * 4 < numberColumns)
+               factor = 0.15;
+          else if (numberRows * 2 < numberColumns)
+               factor = 0.2;
+          //if (model->numberIterations()%50==0)
+          //printf("%d nonzero\n",numberInRowArray);
+     }
+     // reduce for gub
+     factor *= 0.5;
+     assert (!y->getNumElements());
+     if (numberInRowArray > factor * numberRows || !rowCopy) {
+          // do by column
+          int iColumn;
+          // get matrix data pointers
+          const int * row = matrix_->getIndices();
+          const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+          const int * columnLength = matrix_->getVectorLengths();
+          const double * elementByColumn = matrix_->getElements();
+          const double * rowScale = model->rowScale();
+          int numberColumns = model->numberColumns();
+          int iSet = -1;
+          double djMod = 0.0;
+          if (packed) {
+               // need to expand pi into y
+               assert(y->capacity() >= numberRows);
+               double * piOld = pi;
+               pi = y->denseVector();
+               const int * whichRow = rowArray->getIndices();
+               int i;
+               if (!rowScale) {
+                    // modify pi so can collapse to one loop
+                    for (i = 0; i < numberInRowArray; i++) {
+                         int iRow = whichRow[i];
+                         pi[iRow] = scalar * piOld[i];
+                    }
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (backward_[iColumn] != iSet) {
+                              // get pi on gub row
+                              iSet = backward_[iColumn];
+                              if (iSet >= 0) {
+                                   int iBasic = keyVariable_[iSet];
+                                   if (iBasic < numberColumns) {
+                                        // get dj without
+                                        assert (model->getStatus(iBasic) == ClpSimplex::basic);
+                                        djMod = 0.0;
+                                        for (CoinBigIndex j = columnStart[iBasic];
+                                                  j < columnStart[iBasic] + columnLength[iBasic]; j++) {
+                                             int jRow = row[j];
+                                             djMod -= pi[jRow] * elementByColumn[j];
+                                        }
+                                   } else {
+                                        djMod = 0.0;
+                                   }
+                              } else {
+                                   djMod = 0.0;
+                              }
+                         }
+                         double value = -djMod;
+                         CoinBigIndex j;
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              int iRow = row[j];
+                              value += pi[iRow] * elementByColumn[j];
+                         }
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               } else {
+                    // scaled
+                    // modify pi so can collapse to one loop
+                    for (i = 0; i < numberInRowArray; i++) {
+                         int iRow = whichRow[i];
+                         pi[iRow] = scalar * piOld[i] * rowScale[iRow];
+                    }
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (backward_[iColumn] != iSet) {
+                              // get pi on gub row
+                              iSet = backward_[iColumn];
+                              if (iSet >= 0) {
+                                   int iBasic = keyVariable_[iSet];
+                                   if (iBasic < numberColumns) {
+                                        // get dj without
+                                        assert (model->getStatus(iBasic) == ClpSimplex::basic);
+                                        djMod = 0.0;
+                                        // scaled
+                                        for (CoinBigIndex j = columnStart[iBasic];
+                                                  j < columnStart[iBasic] + columnLength[iBasic]; j++) {
+                                             int jRow = row[j];
+                                             djMod -= pi[jRow] * elementByColumn[j] * rowScale[jRow];
+                                        }
+                                   } else {
+                                        djMod = 0.0;
+                                   }
+                              } else {
+                                   djMod = 0.0;
+                              }
+                         }
+                         double value = -djMod;
+                         CoinBigIndex j;
+                         const double * columnScale = model->columnScale();
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              int iRow = row[j];
+                              value += pi[iRow] * elementByColumn[j];
+                         }
+                         value *= columnScale[iColumn];
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+               // zero out
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = 0.0;
+               }
+          } else {
+               // code later
+               assert (packed);
+               if (!rowScale) {
+                    if (scalar == -1.0) {
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j];
+                              }
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = -value;
+                              }
+                         }
+                    } else if (scalar == 1.0) {
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j];
+                              }
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = value;
+                              }
+                         }
+                    } else {
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j];
+                              }
+                              value *= scalar;
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = value;
+                              }
+                         }
+                    }
+               } else {
+                    // scaled
+                    if (scalar == -1.0) {
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              const double * columnScale = model->columnScale();
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                              }
+                              value *= columnScale[iColumn];
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = -value;
+                              }
+                         }
+                    } else if (scalar == 1.0) {
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              const double * columnScale = model->columnScale();
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                              }
+                              value *= columnScale[iColumn];
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = value;
+                              }
+                         }
+                    } else {
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              const double * columnScale = model->columnScale();
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                              }
+                              value *= scalar * columnScale[iColumn];
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = value;
+                              }
+                         }
+                    }
+               }
+          }
+          columnArray->setNumElements(numberNonZero);
+          y->setNumElements(0);
+     } else {
+          // do by row
+          transposeTimesByRow(model, scalar, rowArray, y, columnArray);
+     }
+     if (packed)
+          columnArray->setPackedMode(true);
+     if (0) {
+          columnArray->checkClean();
+          int numberNonZero = columnArray->getNumElements();;
+          int * index = columnArray->getIndices();
+          double * array = columnArray->denseVector();
+          int i;
+          for (i = 0; i < numberNonZero; i++) {
+               int j = index[i];
+               double value;
+               if (packed)
+                    value = array[i];
+               else
+                    value = array[j];
+               printf("Ti %d %d %g\n", i, j, value);
+          }
+     }
+}
+/* Return <code>x * A + y</code> in <code>z</code>.
+	Squashes small elements and knows about ClpSimplex */
+void
+ClpGubMatrix::transposeTimesByRow(const ClpSimplex * model, double scalar,
+                                  const CoinIndexedVector * rowArray,
+                                  CoinIndexedVector * y,
+                                  CoinIndexedVector * columnArray) const
+{
+     // Do packed part
+     ClpPackedMatrix::transposeTimesByRow(model, scalar, rowArray, y, columnArray);
+     if (numberSets_) {
+          /* what we need to do is do by row as normal but get list of sets touched
+             and then update those ones */
+          abort();
+     }
+}
+/* Return <code>x *A in <code>z</code> but
+   just for indices in y. */
+void
+ClpGubMatrix::subsetTransposeTimes(const ClpSimplex * model,
+                                   const CoinIndexedVector * rowArray,
+                                   const CoinIndexedVector * y,
+                                   CoinIndexedVector * columnArray) const
+{
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     double * array = columnArray->denseVector();
+     int jColumn;
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * elementByColumn = matrix_->getElements();
+     const double * rowScale = model->rowScale();
+     int numberToDo = y->getNumElements();
+     const int * which = y->getIndices();
+     assert (!rowArray->packedMode());
+     columnArray->setPacked();
+     int numberTouched = 0;
+     if (!rowScale) {
+          for (jColumn = 0; jColumn < numberToDo; jColumn++) {
+               int iColumn = which[jColumn];
+               double value = 0.0;
+               CoinBigIndex j;
+               for (j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    value += pi[iRow] * elementByColumn[j];
+               }
+               array[jColumn] = value;
+               if (value) {
+                    int iSet = backward_[iColumn];
+                    if (iSet >= 0) {
+                         int iBasic = keyVariable_[iSet];
+                         if (iBasic == iColumn) {
+                              toIndex_[iSet] = jColumn;
+                              fromIndex_[numberTouched++] = iSet;
+                         }
+                    }
+               }
+          }
+     } else {
+          // scaled
+          for (jColumn = 0; jColumn < numberToDo; jColumn++) {
+               int iColumn = which[jColumn];
+               double value = 0.0;
+               CoinBigIndex j;
+               const double * columnScale = model->columnScale();
+               for (j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+               }
+               value *= columnScale[iColumn];
+               array[jColumn] = value;
+               if (value) {
+                    int iSet = backward_[iColumn];
+                    if (iSet >= 0) {
+                         int iBasic = keyVariable_[iSet];
+                         if (iBasic == iColumn) {
+                              toIndex_[iSet] = jColumn;
+                              fromIndex_[numberTouched++] = iSet;
+                         }
+                    }
+               }
+          }
+     }
+     // adjust djs
+     for (jColumn = 0; jColumn < numberToDo; jColumn++) {
+          int iColumn = which[jColumn];
+          int iSet = backward_[iColumn];
+          if (iSet >= 0) {
+               int kColumn = toIndex_[iSet];
+               if (kColumn >= 0)
+                    array[jColumn] -= array[kColumn];
+          }
+     }
+     // and clear basic
+     for (int j = 0; j < numberTouched; j++) {
+          int iSet = fromIndex_[j];
+          int kColumn = toIndex_[iSet];
+          toIndex_[iSet] = -1;
+          array[kColumn] = 0.0;
+     }
+}
+/// returns number of elements in column part of basis,
+CoinBigIndex
+ClpGubMatrix::countBasis(const int * whichColumn,
+                         int & numberColumnBasic)
+{
+     int i;
+     int numberColumns = getNumCols();
+     const int * columnLength = matrix_->getVectorLengths();
+     int numberRows = getNumRows();
+     int numberBasic = 0;
+     CoinBigIndex numberElements = 0;
+     int lastSet = -1;
+     int key = -1;
+     int keyLength = -1;
+     double * work = new double[numberRows];
+     CoinZeroN(work, numberRows);
+     char * mark = new char[numberRows];
+     CoinZeroN(mark, numberRows);
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * row = matrix_->getIndices();
+     const double * elementByColumn = matrix_->getElements();
+     //ClpGubDynamicMatrix* gubx =
+     //dynamic_cast< ClpGubDynamicMatrix*>(this);
+     //int * id = gubx->id();
+     // just count
+     for (i = 0; i < numberColumnBasic; i++) {
+          int iColumn = whichColumn[i];
+          int iSet = backward_[iColumn];
+          int length = columnLength[iColumn];
+          if (iSet < 0 || keyVariable_[iSet] >= numberColumns) {
+               numberElements += length;
+               numberBasic++;
+               //printf("non gub - set %d id %d (column %d) nel %d\n",iSet,id[iColumn-20],iColumn,length);
+          } else {
+               // in gub set
+               if (iColumn != keyVariable_[iSet]) {
+                    numberBasic++;
+                    CoinBigIndex j;
+                    // not key
+                    if (lastSet < iSet) {
+                         // erase work
+                         if (key >= 0) {
+                              for (j = columnStart[key]; j < columnStart[key] + keyLength; j++)
+                                   work[row[j]] = 0.0;
+                         }
+                         key = keyVariable_[iSet];
+                         lastSet = iSet;
+                         keyLength = columnLength[key];
+                         for (j = columnStart[key]; j < columnStart[key] + keyLength; j++)
+                              work[row[j]] = elementByColumn[j];
+                    }
+                    int extra = keyLength;
+                    for (j = columnStart[iColumn]; j < columnStart[iColumn] + length; j++) {
+                         int iRow = row[j];
+                         double keyValue = work[iRow];
+                         double value = elementByColumn[j];
+                         if (!keyValue) {
+                              if (fabs(value) > 1.0e-20)
+                                   extra++;
+                         } else {
+                              value -= keyValue;
+                              if (fabs(value) <= 1.0e-20)
+                                   extra--;
+                         }
+                    }
+                    numberElements += extra;
+                    //printf("gub - set %d id %d (column %d) nel %d\n",iSet,id[iColumn-20],iColumn,extra);
+               }
+          }
+     }
+     delete [] work;
+     delete [] mark;
+     // update number of column basic
+     numberColumnBasic = numberBasic;
+     return numberElements;
+}
+void
+ClpGubMatrix::fillBasis(ClpSimplex * model,
+                        const int * whichColumn,
+                        int & numberColumnBasic,
+                        int * indexRowU, int * start,
+                        int * rowCount, int * columnCount,
+                        CoinFactorizationDouble * elementU)
+{
+     int i;
+     int numberColumns = getNumCols();
+     const int * columnLength = matrix_->getVectorLengths();
+     int numberRows = getNumRows();
+     assert (next_ || !elementU) ;
+     CoinBigIndex numberElements = start[0];
+     int lastSet = -1;
+     int key = -1;
+     int keyLength = -1;
+     double * work = new double[numberRows];
+     CoinZeroN(work, numberRows);
+     char * mark = new char[numberRows];
+     CoinZeroN(mark, numberRows);
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * row = matrix_->getIndices();
+     const double * elementByColumn = matrix_->getElements();
+     const double * rowScale = model->rowScale();
+     int numberBasic = 0;
+     if (0) {
+          printf("%d basiccolumns\n", numberColumnBasic);
+          int i;
+          for (i = 0; i < numberSets_; i++) {
+               int k = keyVariable_[i];
+               if (k < numberColumns) {
+                    printf("key %d on set %d, %d elements\n", k, i, columnStart[k+1] - columnStart[k]);
+                    for (int j = columnStart[k]; j < columnStart[k+1]; j++)
+                         printf("row %d el %g\n", row[j], elementByColumn[j]);
+               } else {
+                    printf("slack key on set %d\n", i);
+               }
+          }
+     }
+     // fill
+     if (!rowScale) {
+          // no scaling
+          for (i = 0; i < numberColumnBasic; i++) {
+               int iColumn = whichColumn[i];
+               int iSet = backward_[iColumn];
+               int length = columnLength[iColumn];
+               if (0) {
+                    int k = iColumn;
+                    printf("column %d in set %d, %d elements\n", k, iSet, columnStart[k+1] - columnStart[k]);
+                    for (int j = columnStart[k]; j < columnStart[k+1]; j++)
+                         printf("row %d el %g\n", row[j], elementByColumn[j]);
+               }
+               CoinBigIndex j;
+               if (iSet < 0 || keyVariable_[iSet] >= numberColumns) {
+                    for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         double value = elementByColumn[j];
+                         if (fabs(value) > 1.0e-20) {
+                              int iRow = row[j];
+                              indexRowU[numberElements] = iRow;
+                              rowCount[iRow]++;
+                              elementU[numberElements++] = value;
+                         }
+                    }
+                    // end of column
+                    columnCount[numberBasic] = numberElements - start[numberBasic];
+                    numberBasic++;
+                    start[numberBasic] = numberElements;
+               } else {
+                    // in gub set
+                    if (iColumn != keyVariable_[iSet]) {
+                         // not key
+                         if (lastSet != iSet) {
+                              // erase work
+                              if (key >= 0) {
+                                   for (j = columnStart[key]; j < columnStart[key] + keyLength; j++) {
+                                        int iRow = row[j];
+                                        work[iRow] = 0.0;
+                                        mark[iRow] = 0;
+                                   }
+                              }
+                              key = keyVariable_[iSet];
+                              lastSet = iSet;
+                              keyLength = columnLength[key];
+                              for (j = columnStart[key]; j < columnStart[key] + keyLength; j++) {
+                                   int iRow = row[j];
+                                   work[iRow] = elementByColumn[j];
+                                   mark[iRow] = 1;
+                              }
+                         }
+                         for (j = columnStart[iColumn]; j < columnStart[iColumn] + length; j++) {
+                              int iRow = row[j];
+                              double value = elementByColumn[j];
+                              if (mark[iRow]) {
+                                   mark[iRow] = 0;
+                                   double keyValue = work[iRow];
+                                   value -= keyValue;
+                              }
+                              if (fabs(value) > 1.0e-20) {
+                                   indexRowU[numberElements] = iRow;
+                                   rowCount[iRow]++;
+                                   elementU[numberElements++] = value;
+                              }
+                         }
+                         for (j = columnStart[key]; j < columnStart[key] + keyLength; j++) {
+                              int iRow = row[j];
+                              if (mark[iRow]) {
+                                   double value = -work[iRow];
+                                   if (fabs(value) > 1.0e-20) {
+                                        indexRowU[numberElements] = iRow;
+                                        rowCount[iRow]++;
+                                        elementU[numberElements++] = value;
+                                   }
+                              } else {
+                                   // just put back mark
+                                   mark[iRow] = 1;
+                              }
+                         }
+                         // end of column
+                         columnCount[numberBasic] = numberElements - start[numberBasic];
+                         numberBasic++;
+                         start[numberBasic] = numberElements;
+                    }
+               }
+          }
+     } else {
+          // scaling
+          const double * columnScale = model->columnScale();
+          for (i = 0; i < numberColumnBasic; i++) {
+               int iColumn = whichColumn[i];
+               int iSet = backward_[iColumn];
+               int length = columnLength[iColumn];
+               CoinBigIndex j;
+               if (iSet < 0 || keyVariable_[iSet] >= numberColumns) {
+                    double scale = columnScale[iColumn];
+                    for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         int iRow = row[j];
+                         double value = elementByColumn[j] * scale * rowScale[iRow];
+                         if (fabs(value) > 1.0e-20) {
+                              indexRowU[numberElements] = iRow;
+                              rowCount[iRow]++;
+                              elementU[numberElements++] = value;
+                         }
+                    }
+                    // end of column
+                    columnCount[numberBasic] = numberElements - start[numberBasic];
+                    numberBasic++;
+                    start[numberBasic] = numberElements;
+               } else {
+                    // in gub set
+                    if (iColumn != keyVariable_[iSet]) {
+                         double scale = columnScale[iColumn];
+                         // not key
+                         if (lastSet < iSet) {
+                              // erase work
+                              if (key >= 0) {
+                                   for (j = columnStart[key]; j < columnStart[key] + keyLength; j++) {
+                                        int iRow = row[j];
+                                        work[iRow] = 0.0;
+                                        mark[iRow] = 0;
+                                   }
+                              }
+                              key = keyVariable_[iSet];
+                              lastSet = iSet;
+                              keyLength = columnLength[key];
+                              double scale = columnScale[key];
+                              for (j = columnStart[key]; j < columnStart[key] + keyLength; j++) {
+                                   int iRow = row[j];
+                                   work[iRow] = elementByColumn[j] * scale * rowScale[iRow];
+                                   mark[iRow] = 1;
+                              }
+                         }
+                         for (j = columnStart[iColumn]; j < columnStart[iColumn] + length; j++) {
+                              int iRow = row[j];
+                              double value = elementByColumn[j] * scale * rowScale[iRow];
+                              if (mark[iRow]) {
+                                   mark[iRow] = 0;
+                                   double keyValue = work[iRow];
+                                   value -= keyValue;
+                              }
+                              if (fabs(value) > 1.0e-20) {
+                                   indexRowU[numberElements] = iRow;
+                                   rowCount[iRow]++;
+                                   elementU[numberElements++] = value;
+                              }
+                         }
+                         for (j = columnStart[key]; j < columnStart[key] + keyLength; j++) {
+                              int iRow = row[j];
+                              if (mark[iRow]) {
+                                   double value = -work[iRow];
+                                   if (fabs(value) > 1.0e-20) {
+                                        indexRowU[numberElements] = iRow;
+                                        rowCount[iRow]++;
+                                        elementU[numberElements++] = value;
+                                   }
+                              } else {
+                                   // just put back mark
+                                   mark[iRow] = 1;
+                              }
+                         }
+                         // end of column
+                         columnCount[numberBasic] = numberElements - start[numberBasic];
+                         numberBasic++;
+                         start[numberBasic] = numberElements;
+                    }
+               }
+          }
+     }
+     delete [] work;
+     delete [] mark;
+     // update number of column basic
+     numberColumnBasic = numberBasic;
+}
+/* Unpacks a column into an CoinIndexedvector
+ */
+void
+ClpGubMatrix::unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                     int iColumn) const
+{
+     assert (iColumn < model->numberColumns());
+     // Do packed part
+     ClpPackedMatrix::unpack(model, rowArray, iColumn);
+     int iSet = backward_[iColumn];
+     if (iSet >= 0) {
+          int iBasic = keyVariable_[iSet];
+          if (iBasic < model->numberColumns()) {
+               add(model, rowArray, iBasic, -1.0);
+          }
+     }
+}
+/* Unpacks a column into a CoinIndexedVector
+** in packed format
+Note that model is NOT const.  Bounds and objective could
+be modified if doing column generation (just for this variable) */
+void
+ClpGubMatrix::unpackPacked(ClpSimplex * model,
+                           CoinIndexedVector * rowArray,
+                           int iColumn) const
+{
+     int numberColumns = model->numberColumns();
+     if (iColumn < numberColumns) {
+          // Do packed part
+          ClpPackedMatrix::unpackPacked(model, rowArray, iColumn);
+          int iSet = backward_[iColumn];
+          if (iSet >= 0) {
+               // columns are in order
+               int iBasic = keyVariable_[iSet];
+               if (iBasic < numberColumns) {
+                    int number = rowArray->getNumElements();
+                    const double * rowScale = model->rowScale();
+                    const int * row = matrix_->getIndices();
+                    const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+                    const int * columnLength = matrix_->getVectorLengths();
+                    const double * elementByColumn = matrix_->getElements();
+                    double * array = rowArray->denseVector();
+                    int * index = rowArray->getIndices();
+                    CoinBigIndex i;
+                    int numberOld = number;
+                    int lastIndex = 0;
+                    int next = index[lastIndex];
+                    if (!rowScale) {
+                         for (i = columnStart[iBasic];
+                                   i < columnStart[iBasic] + columnLength[iBasic]; i++) {
+                              int iRow = row[i];
+                              while (iRow > next) {
+                                   lastIndex++;
+                                   if (lastIndex == numberOld)
+                                        next = matrix_->getNumRows();
+                                   else
+                                        next = index[lastIndex];
+                              }
+                              if (iRow < next) {
+                                   array[number] = -elementByColumn[i];
+                                   index[number++] = iRow;
+                              } else {
+                                   assert (iRow == next);
+                                   array[lastIndex] -= elementByColumn[i];
+                                   if (!array[lastIndex])
+                                        array[lastIndex] = 1.0e-100;
+                              }
+                         }
+                    } else {
+                         // apply scaling
+                         double scale = model->columnScale()[iBasic];
+                         for (i = columnStart[iBasic];
+                                   i < columnStart[iBasic] + columnLength[iBasic]; i++) {
+                              int iRow = row[i];
+                              while (iRow > next) {
+                                   lastIndex++;
+                                   if (lastIndex == numberOld)
+                                        next = matrix_->getNumRows();
+                                   else
+                                        next = index[lastIndex];
+                              }
+                              if (iRow < next) {
+                                   array[number] = -elementByColumn[i] * scale * rowScale[iRow];
+                                   index[number++] = iRow;
+                              } else {
+                                   assert (iRow == next);
+                                   array[lastIndex] -= elementByColumn[i] * scale * rowScale[iRow];
+                                   if (!array[lastIndex])
+                                        array[lastIndex] = 1.0e-100;
+                              }
+                         }
+                    }
+                    rowArray->setNumElements(number);
+               }
+          }
+     } else {
+          // key slack entering
+          int iBasic = keyVariable_[gubSlackIn_];
+          assert (iBasic < numberColumns);
+          int number = 0;
+          const double * rowScale = model->rowScale();
+          const int * row = matrix_->getIndices();
+          const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+          const int * columnLength = matrix_->getVectorLengths();
+          const double * elementByColumn = matrix_->getElements();
+          double * array = rowArray->denseVector();
+          int * index = rowArray->getIndices();
+          CoinBigIndex i;
+          if (!rowScale) {
+               for (i = columnStart[iBasic];
+                         i < columnStart[iBasic] + columnLength[iBasic]; i++) {
+                    int iRow = row[i];
+                    array[number] = elementByColumn[i];
+                    index[number++] = iRow;
+               }
+          } else {
+               // apply scaling
+               double scale = model->columnScale()[iBasic];
+               for (i = columnStart[iBasic];
+                         i < columnStart[iBasic] + columnLength[iBasic]; i++) {
+                    int iRow = row[i];
+                    array[number] = elementByColumn[i] * scale * rowScale[iRow];
+                    index[number++] = iRow;
+               }
+          }
+          rowArray->setNumElements(number);
+          rowArray->setPacked();
+     }
+}
+/* Adds multiple of a column into an CoinIndexedvector
+      You can use quickAdd to add to vector */
+void
+ClpGubMatrix::add(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                  int iColumn, double multiplier) const
+{
+     assert (iColumn < model->numberColumns());
+     // Do packed part
+     ClpPackedMatrix::add(model, rowArray, iColumn, multiplier);
+     int iSet = backward_[iColumn];
+     if (iSet >= 0 && iColumn != keyVariable_[iSet]) {
+          ClpPackedMatrix::add(model, rowArray, keyVariable_[iSet], -multiplier);
+     }
+}
+/* Adds multiple of a column into an array */
+void
+ClpGubMatrix::add(const ClpSimplex * model, double * array,
+                  int iColumn, double multiplier) const
+{
+     assert (iColumn < model->numberColumns());
+     // Do packed part
+     ClpPackedMatrix::add(model, array, iColumn, multiplier);
+     if (iColumn < model->numberColumns()) {
+          int iSet = backward_[iColumn];
+          if (iSet >= 0 && iColumn != keyVariable_[iSet] && keyVariable_[iSet] < model->numberColumns()) {
+               ClpPackedMatrix::add(model, array, keyVariable_[iSet], -multiplier);
+          }
+     }
+}
+// Partial pricing
+void
+ClpGubMatrix::partialPricing(ClpSimplex * model, double startFraction, double endFraction,
+                             int & bestSequence, int & numberWanted)
+{
+     numberWanted = currentWanted_;
+     if (numberSets_) {
+          // Do packed part before gub
+          int numberColumns = matrix_->getNumCols();
+          double ratio = static_cast<double> (firstGub_) /
+                         static_cast<double> (numberColumns);
+          ClpPackedMatrix::partialPricing(model, startFraction * ratio,
+                                          endFraction * ratio, bestSequence, numberWanted);
+          if (numberWanted || minimumGoodReducedCosts_ < -1) {
+               // do gub
+               const double * element = matrix_->getElements();
+               const int * row = matrix_->getIndices();
+               const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+               const int * length = matrix_->getVectorLengths();
+               const double * rowScale = model->rowScale();
+               const double * columnScale = model->columnScale();
+               int iSequence;
+               CoinBigIndex j;
+               double tolerance = model->currentDualTolerance();
+               double * reducedCost = model->djRegion();
+               const double * duals = model->dualRowSolution();
+               const double * cost = model->costRegion();
+               double bestDj;
+               int numberColumns = model->numberColumns();
+               int numberRows = model->numberRows();
+               if (bestSequence >= 0)
+                    bestDj = fabs(this->reducedCost(model, bestSequence));
+               else
+                    bestDj = tolerance;
+               int sequenceOut = model->sequenceOut();
+               int saveSequence = bestSequence;
+               int startG = firstGub_ + static_cast<int> (startFraction * (lastGub_ - firstGub_));
+               int endG = firstGub_ + static_cast<int> (endFraction * (lastGub_ - firstGub_));
+               endG = CoinMin(lastGub_, endG + 1);
+               // If nothing found yet can go all the way to end
+               int endAll = endG;
+               if (bestSequence < 0 && !startG)
+                    endAll = lastGub_;
+               int minSet = minimumObjectsScan_ < 0 ? 5 : minimumObjectsScan_;
+               int minNeg = minimumGoodReducedCosts_ == -1 ? 5 : minimumGoodReducedCosts_;
+               int nSets = 0;
+               int iSet = -1;
+               double djMod = 0.0;
+               double infeasibilityCost = model->infeasibilityCost();
+               if (rowScale) {
+                    double bestDjMod = 0.0;
+                    // scaled
+                    for (iSequence = startG; iSequence < endAll; iSequence++) {
+                         if (numberWanted + minNeg < originalWanted_ && nSets > minSet) {
+                              // give up
+                              numberWanted = 0;
+                              break;
+                         } else if (iSequence == endG && bestSequence >= 0) {
+                              break;
+                         }
+                         if (backward_[iSequence] != iSet) {
+                              // get pi on gub row
+                              iSet = backward_[iSequence];
+                              if (iSet >= 0) {
+                                   nSets++;
+                                   int iBasic = keyVariable_[iSet];
+                                   if (iBasic >= numberColumns) {
+                                        djMod = - weight(iSet) * infeasibilityCost;
+                                   } else {
+                                        // get dj without
+                                        assert (model->getStatus(iBasic) == ClpSimplex::basic);
+                                        djMod = 0.0;
+                                        // scaled
+                                        for (j = startColumn[iBasic];
+                                                  j < startColumn[iBasic] + length[iBasic]; j++) {
+                                             int jRow = row[j];
+                                             djMod -= duals[jRow] * element[j] * rowScale[jRow];
+                                        }
+                                        // allow for scaling
+                                        djMod +=  cost[iBasic] / columnScale[iBasic];
+                                        // See if gub slack possible - dj is djMod
+                                        if (getStatus(iSet) == ClpSimplex::atLowerBound) {
+                                             double value = -djMod;
+                                             if (value > tolerance) {
+                                                  numberWanted--;
+                                                  if (value > bestDj) {
+                                                       // check flagged variable and correct dj
+                                                       if (!flagged(iSet)) {
+                                                            bestDj = value;
+                                                            bestSequence = numberRows + numberColumns + iSet;
+                                                            bestDjMod = djMod;
+                                                       } else {
+                                                            // just to make sure we don't exit before got something
+                                                            numberWanted++;
+                                                            abort();
+                                                       }
+                                                  }
+                                             }
+                                        } else if (getStatus(iSet) == ClpSimplex::atUpperBound) {
+                                             double value = djMod;
+                                             if (value > tolerance) {
+                                                  numberWanted--;
+                                                  if (value > bestDj) {
+                                                       // check flagged variable and correct dj
+                                                       if (!flagged(iSet)) {
+                                                            bestDj = value;
+                                                            bestSequence = numberRows + numberColumns + iSet;
+                                                            bestDjMod = djMod;
+                                                       } else {
+                                                            // just to make sure we don't exit before got something
+                                                            numberWanted++;
+                                                            abort();
+                                                       }
+                                                  }
+                                             }
+                                        }
+                                   }
+                              } else {
+                                   // not in set
+                                   djMod = 0.0;
+                              }
+                         }
+                         if (iSequence != sequenceOut) {
+                              double value;
+                              ClpSimplex::Status status = model->getStatus(iSequence);
+
+                              switch(status) {
+
+                              case ClpSimplex::basic:
+                              case ClpSimplex::isFixed:
+                                   break;
+                              case ClpSimplex::isFree:
+                              case ClpSimplex::superBasic:
+                                   value = -djMod;
+                                   // scaled
+                                   for (j = startColumn[iSequence];
+                                             j < startColumn[iSequence] + length[iSequence]; j++) {
+                                        int jRow = row[j];
+                                        value -= duals[jRow] * element[j] * rowScale[jRow];
+                                   }
+                                   value = fabs(cost[iSequence] + value * columnScale[iSequence]);
+                                   if (value > FREE_ACCEPT * tolerance) {
+                                        numberWanted--;
+                                        // we are going to bias towards free (but only if reasonable)
+                                        value *= FREE_BIAS;
+                                        if (value > bestDj) {
+                                             // check flagged variable and correct dj
+                                             if (!model->flagged(iSequence)) {
+                                                  bestDj = value;
+                                                  bestSequence = iSequence;
+                                                  bestDjMod = djMod;
+                                             } else {
+                                                  // just to make sure we don't exit before got something
+                                                  numberWanted++;
+                                             }
+                                        }
+                                   }
+                                   break;
+                              case ClpSimplex::atUpperBound:
+                                   value = -djMod;
+                                   // scaled
+                                   for (j = startColumn[iSequence];
+                                             j < startColumn[iSequence] + length[iSequence]; j++) {
+                                        int jRow = row[j];
+                                        value -= duals[jRow] * element[j] * rowScale[jRow];
+                                   }
+                                   value = cost[iSequence] + value * columnScale[iSequence];
+                                   if (value > tolerance) {
+                                        numberWanted--;
+                                        if (value > bestDj) {
+                                             // check flagged variable and correct dj
+                                             if (!model->flagged(iSequence)) {
+                                                  bestDj = value;
+                                                  bestSequence = iSequence;
+                                                  bestDjMod = djMod;
+                                             } else {
+                                                  // just to make sure we don't exit before got something
+                                                  numberWanted++;
+                                             }
+                                        }
+                                   }
+                                   break;
+                              case ClpSimplex::atLowerBound:
+                                   value = -djMod;
+                                   // scaled
+                                   for (j = startColumn[iSequence];
+                                             j < startColumn[iSequence] + length[iSequence]; j++) {
+                                        int jRow = row[j];
+                                        value -= duals[jRow] * element[j] * rowScale[jRow];
+                                   }
+                                   value = -(cost[iSequence] + value * columnScale[iSequence]);
+                                   if (value > tolerance) {
+                                        numberWanted--;
+                                        if (value > bestDj) {
+                                             // check flagged variable and correct dj
+                                             if (!model->flagged(iSequence)) {
+                                                  bestDj = value;
+                                                  bestSequence = iSequence;
+                                                  bestDjMod = djMod;
+                                             } else {
+                                                  // just to make sure we don't exit before got something
+                                                  numberWanted++;
+                                             }
+                                        }
+                                   }
+                                   break;
+                              }
+                         }
+                         if (!numberWanted)
+                              break;
+                    }
+                    if (bestSequence != saveSequence) {
+                         if (bestSequence < numberRows + numberColumns) {
+                              // recompute dj
+                              double value = bestDjMod;
+                              // scaled
+                              for (j = startColumn[bestSequence];
+                                        j < startColumn[bestSequence] + length[bestSequence]; j++) {
+                                   int jRow = row[j];
+                                   value -= duals[jRow] * element[j] * rowScale[jRow];
+                              }
+                              reducedCost[bestSequence] = cost[bestSequence] + value * columnScale[bestSequence];
+                              gubSlackIn_ = -1;
+                         } else {
+                              // slack - make last column
+                              gubSlackIn_ = bestSequence - numberRows - numberColumns;
+                              bestSequence = numberColumns + 2 * numberRows;
+                              reducedCost[bestSequence] = bestDjMod;
+                              model->setStatus(bestSequence, getStatus(gubSlackIn_));
+                              if (getStatus(gubSlackIn_) == ClpSimplex::atUpperBound)
+                                   model->solutionRegion()[bestSequence] = upper_[gubSlackIn_];
+                              else
+                                   model->solutionRegion()[bestSequence] = lower_[gubSlackIn_];
+                              model->lowerRegion()[bestSequence] = lower_[gubSlackIn_];
+                              model->upperRegion()[bestSequence] = upper_[gubSlackIn_];
+                              model->costRegion()[bestSequence] = 0.0;
+                         }
+                         savedBestSequence_ = bestSequence;
+                         savedBestDj_ = reducedCost[savedBestSequence_];
+                    }
+               } else {
+                    double bestDjMod = 0.0;
+                    //printf("iteration %d start %d end %d - wanted %d\n",model->numberIterations(),
+                    //     startG,endG,numberWanted);
+                    for (iSequence = startG; iSequence < endG; iSequence++) {
+                         if (numberWanted + minNeg < originalWanted_ && nSets > minSet) {
+                              // give up
+                              numberWanted = 0;
+                              break;
+                         } else if (iSequence == endG && bestSequence >= 0) {
+                              break;
+                         }
+                         if (backward_[iSequence] != iSet) {
+                              // get pi on gub row
+                              iSet = backward_[iSequence];
+                              if (iSet >= 0) {
+                                   nSets++;
+                                   int iBasic = keyVariable_[iSet];
+                                   if (iBasic >= numberColumns) {
+                                        djMod = - weight(iSet) * infeasibilityCost;
+                                   } else {
+                                        // get dj without
+                                        assert (model->getStatus(iBasic) == ClpSimplex::basic);
+                                        djMod = 0.0;
+
+                                        for (j = startColumn[iBasic];
+                                                  j < startColumn[iBasic] + length[iBasic]; j++) {
+                                             int jRow = row[j];
+                                             djMod -= duals[jRow] * element[j];
+                                        }
+                                        djMod += cost[iBasic];
+                                        // See if gub slack possible - dj is djMod
+                                        if (getStatus(iSet) == ClpSimplex::atLowerBound) {
+                                             double value = -djMod;
+                                             if (value > tolerance) {
+                                                  numberWanted--;
+                                                  if (value > bestDj) {
+                                                       // check flagged variable and correct dj
+                                                       if (!flagged(iSet)) {
+                                                            bestDj = value;
+                                                            bestSequence = numberRows + numberColumns + iSet;
+                                                            bestDjMod = djMod;
+                                                       } else {
+                                                            // just to make sure we don't exit before got something
+                                                            numberWanted++;
+                                                            abort();
+                                                       }
+                                                  }
+                                             }
+                                        } else if (getStatus(iSet) == ClpSimplex::atUpperBound) {
+                                             double value = djMod;
+                                             if (value > tolerance) {
+                                                  numberWanted--;
+                                                  if (value > bestDj) {
+                                                       // check flagged variable and correct dj
+                                                       if (!flagged(iSet)) {
+                                                            bestDj = value;
+                                                            bestSequence = numberRows + numberColumns + iSet;
+                                                            bestDjMod = djMod;
+                                                       } else {
+                                                            // just to make sure we don't exit before got something
+                                                            numberWanted++;
+                                                            abort();
+                                                       }
+                                                  }
+                                             }
+                                        }
+                                   }
+                              } else {
+                                   // not in set
+                                   djMod = 0.0;
+                              }
+                         }
+                         if (iSequence != sequenceOut) {
+                              double value;
+                              ClpSimplex::Status status = model->getStatus(iSequence);
+
+                              switch(status) {
+
+                              case ClpSimplex::basic:
+                              case ClpSimplex::isFixed:
+                                   break;
+                              case ClpSimplex::isFree:
+                              case ClpSimplex::superBasic:
+                                   value = cost[iSequence] - djMod;
+                                   for (j = startColumn[iSequence];
+                                             j < startColumn[iSequence] + length[iSequence]; j++) {
+                                        int jRow = row[j];
+                                        value -= duals[jRow] * element[j];
+                                   }
+                                   value = fabs(value);
+                                   if (value > FREE_ACCEPT * tolerance) {
+                                        numberWanted--;
+                                        // we are going to bias towards free (but only if reasonable)
+                                        value *= FREE_BIAS;
+                                        if (value > bestDj) {
+                                             // check flagged variable and correct dj
+                                             if (!model->flagged(iSequence)) {
+                                                  bestDj = value;
+                                                  bestSequence = iSequence;
+                                                  bestDjMod = djMod;
+                                             } else {
+                                                  // just to make sure we don't exit before got something
+                                                  numberWanted++;
+                                             }
+                                        }
+                                   }
+                                   break;
+                              case ClpSimplex::atUpperBound:
+                                   value = cost[iSequence] - djMod;
+                                   for (j = startColumn[iSequence];
+                                             j < startColumn[iSequence] + length[iSequence]; j++) {
+                                        int jRow = row[j];
+                                        value -= duals[jRow] * element[j];
+                                   }
+                                   if (value > tolerance) {
+                                        numberWanted--;
+                                        if (value > bestDj) {
+                                             // check flagged variable and correct dj
+                                             if (!model->flagged(iSequence)) {
+                                                  bestDj = value;
+                                                  bestSequence = iSequence;
+                                                  bestDjMod = djMod;
+                                             } else {
+                                                  // just to make sure we don't exit before got something
+                                                  numberWanted++;
+                                             }
+                                        }
+                                   }
+                                   break;
+                              case ClpSimplex::atLowerBound:
+                                   value = cost[iSequence] - djMod;
+                                   for (j = startColumn[iSequence];
+                                             j < startColumn[iSequence] + length[iSequence]; j++) {
+                                        int jRow = row[j];
+                                        value -= duals[jRow] * element[j];
+                                   }
+                                   value = -value;
+                                   if (value > tolerance) {
+                                        numberWanted--;
+                                        if (value > bestDj) {
+                                             // check flagged variable and correct dj
+                                             if (!model->flagged(iSequence)) {
+                                                  bestDj = value;
+                                                  bestSequence = iSequence;
+                                                  bestDjMod = djMod;
+                                             } else {
+                                                  // just to make sure we don't exit before got something
+                                                  numberWanted++;
+                                             }
+                                        }
+                                   }
+                                   break;
+                              }
+                         }
+                         if (!numberWanted)
+                              break;
+                    }
+                    if (bestSequence != saveSequence) {
+                         if (bestSequence < numberRows + numberColumns) {
+                              // recompute dj
+                              double value = cost[bestSequence] - bestDjMod;
+                              for (j = startColumn[bestSequence];
+                                        j < startColumn[bestSequence] + length[bestSequence]; j++) {
+                                   int jRow = row[j];
+                                   value -= duals[jRow] * element[j];
+                              }
+                              //printf("price struct %d - dj %g gubpi %g\n",bestSequence,value,bestDjMod);
+                              reducedCost[bestSequence] = value;
+                              gubSlackIn_ = -1;
+                         } else {
+                              // slack - make last column
+                              gubSlackIn_ = bestSequence - numberRows - numberColumns;
+                              bestSequence = numberColumns + 2 * numberRows;
+                              reducedCost[bestSequence] = bestDjMod;
+                              //printf("price slack %d - gubpi %g\n",gubSlackIn_,bestDjMod);
+                              model->setStatus(bestSequence, getStatus(gubSlackIn_));
+                              if (getStatus(gubSlackIn_) == ClpSimplex::atUpperBound)
+                                   model->solutionRegion()[bestSequence] = upper_[gubSlackIn_];
+                              else
+                                   model->solutionRegion()[bestSequence] = lower_[gubSlackIn_];
+                              model->lowerRegion()[bestSequence] = lower_[gubSlackIn_];
+                              model->upperRegion()[bestSequence] = upper_[gubSlackIn_];
+                              model->costRegion()[bestSequence] = 0.0;
+                         }
+                    }
+               }
+               // See if may be finished
+               if (startG == firstGub_ && bestSequence < 0)
+                    infeasibilityWeight_ = model_->infeasibilityCost();
+               else if (bestSequence >= 0)
+                    infeasibilityWeight_ = -1.0;
+          }
+          if (numberWanted) {
+               // Do packed part after gub
+               double offset = static_cast<double> (lastGub_) /
+                               static_cast<double> (numberColumns);
+               double ratio = static_cast<double> (numberColumns) /
+                              static_cast<double> (numberColumns) - offset;
+               double start2 = offset + ratio * startFraction;
+               double end2 = CoinMin(1.0, offset + ratio * endFraction + 1.0e-6);
+               ClpPackedMatrix::partialPricing(model, start2, end2, bestSequence, numberWanted);
+          }
+     } else {
+          // no gub
+          ClpPackedMatrix::partialPricing(model, startFraction, endFraction, bestSequence, numberWanted);
+     }
+     if (bestSequence >= 0)
+          infeasibilityWeight_ = -1.0; // not optimal
+     currentWanted_ = numberWanted;
+}
+/* expands an updated column to allow for extra rows which the main
+   solver does not know about and returns number added.
+*/
+int
+ClpGubMatrix::extendUpdated(ClpSimplex * model, CoinIndexedVector * update, int mode)
+{
+     // I think we only need to bother about sets with two in basis or incoming set
+     int number = update->getNumElements();
+     double * array = update->denseVector();
+     int * index = update->getIndices();
+     int i;
+     assert (!number || update->packedMode());
+     int * pivotVariable = model->pivotVariable();
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     int numberTotal = numberRows + numberColumns;
+     int sequenceIn = model->sequenceIn();
+     int returnCode = 0;
+     int iSetIn;
+     if (sequenceIn < numberColumns) {
+          iSetIn = backward_[sequenceIn];
+          gubSlackIn_ = -1; // in case set
+     } else if (sequenceIn < numberRows + numberColumns) {
+          iSetIn = -1;
+          gubSlackIn_ = -1; // in case set
+     } else {
+          iSetIn = gubSlackIn_;
+     }
+     double * lower = model->lowerRegion();
+     double * upper = model->upperRegion();
+     double * cost = model->costRegion();
+     double * solution = model->solutionRegion();
+     int number2 = number;
+     if (!mode) {
+          double primalTolerance = model->primalTolerance();
+          double infeasibilityCost = model->infeasibilityCost();
+          // extend
+          saveNumber_ = number;
+          for (i = 0; i < number; i++) {
+               int iRow = index[i];
+               int iPivot = pivotVariable[iRow];
+               if (iPivot < numberColumns) {
+                    int iSet = backward_[iPivot];
+                    if (iSet >= 0) {
+                         // two (or more) in set
+                         int iIndex = toIndex_[iSet];
+                         double otherValue = array[i];
+                         double value;
+                         if (iIndex < 0) {
+                              toIndex_[iSet] = number2;
+                              int iNew = number2 - number;
+                              fromIndex_[number2-number] = iSet;
+                              iIndex = number2;
+                              index[number2] = numberRows + iNew;
+                              // do key stuff
+                              int iKey = keyVariable_[iSet];
+                              if (iKey < numberColumns) {
+                                   // Save current cost of key
+                                   changeCost_[number2-number] = cost[iKey];
+                                   if (iSet != iSetIn)
+                                        value = 0.0;
+                                   else if (iSetIn != gubSlackIn_)
+                                        value = 1.0;
+                                   else
+                                        value = -1.0;
+                                   pivotVariable[numberRows+iNew] = iKey;
+                                   // Do I need to recompute?
+                                   double sol;
+                                   assert (getStatus(iSet) != ClpSimplex::basic);
+                                   if (getStatus(iSet) == ClpSimplex::atLowerBound)
+                                        sol = lower_[iSet];
+                                   else
+                                        sol = upper_[iSet];
+                                   if ((gubType_ & 8) != 0) {
+                                        int iColumn = next_[iKey];
+                                        // sum all non-key variables
+                                        while(iColumn >= 0) {
+                                             sol -= solution[iColumn];
+                                             iColumn = next_[iColumn];
+                                        }
+                                   } else {
+                                        int stop = -(iKey + 1);
+                                        int iColumn = next_[iKey];
+                                        // sum all non-key variables
+                                        while(iColumn != stop) {
+                                             if (iColumn < 0)
+                                                  iColumn = -iColumn - 1;
+                                             sol -= solution[iColumn];
+                                             iColumn = next_[iColumn];
+                                        }
+                                   }
+                                   solution[iKey] = sol;
+                                   if (model->algorithm() > 0)
+                                        model->nonLinearCost()->setOne(iKey, sol);
+                                   //assert (fabs(sol-solution[iKey])<1.0e-3);
+                              } else {
+                                   // gub slack is basic
+                                   // Save current cost of key
+                                   changeCost_[number2-number] = -weight(iSet) * infeasibilityCost;
+                                   otherValue = - otherValue; //allow for - sign on slack
+                                   if (iSet != iSetIn)
+                                        value = 0.0;
+                                   else
+                                        value = -1.0;
+                                   pivotVariable[numberRows+iNew] = iNew + numberTotal;
+                                   model->djRegion()[iNew+numberTotal] = 0.0;
+                                   double sol = 0.0;
+                                   if ((gubType_ & 8) != 0) {
+                                        int iColumn = next_[iKey];
+                                        // sum all non-key variables
+                                        while(iColumn >= 0) {
+                                             sol += solution[iColumn];
+                                             iColumn = next_[iColumn];
+                                        }
+                                   } else {
+                                        int stop = -(iKey + 1);
+                                        int iColumn = next_[iKey];
+                                        // sum all non-key variables
+                                        while(iColumn != stop) {
+                                             if (iColumn < 0)
+                                                  iColumn = -iColumn - 1;
+                                             sol += solution[iColumn];
+                                             iColumn = next_[iColumn];
+                                        }
+                                   }
+                                   solution[iNew+numberTotal] = sol;
+                                   // and do cost in nonLinearCost
+                                   if (model->algorithm() > 0)
+                                        model->nonLinearCost()->setOne(iNew + numberTotal, sol, lower_[iSet], upper_[iSet]);
+                                   if (sol > upper_[iSet] + primalTolerance) {
+                                        setAbove(iSet);
+                                        lower[iNew+numberTotal] = upper_[iSet];
+                                        upper[iNew+numberTotal] = COIN_DBL_MAX;
+                                   } else if (sol < lower_[iSet] - primalTolerance) {
+                                        setBelow(iSet);
+                                        lower[iNew+numberTotal] = -COIN_DBL_MAX;
+                                        upper[iNew+numberTotal] = lower_[iSet];
+                                   } else {
+                                        setFeasible(iSet);
+                                        lower[iNew+numberTotal] = lower_[iSet];
+                                        upper[iNew+numberTotal] = upper_[iSet];
+                                   }
+                                   cost[iNew+numberTotal] = weight(iSet) * infeasibilityCost;
+                              }
+                              number2++;
+                         } else {
+                              value = array[iIndex];
+                              int iKey = keyVariable_[iSet];
+                              if (iKey >= numberColumns)
+                                   otherValue = - otherValue; //allow for - sign on slack
+                         }
+                         value -= otherValue;
+                         array[iIndex] = value;
+                    }
+               }
+          }
+          if (iSetIn >= 0 && toIndex_[iSetIn] < 0) {
+               // Do incoming
+               update->setPacked(); // just in case no elements
+               toIndex_[iSetIn] = number2;
+               int iNew = number2 - number;
+               fromIndex_[number2-number] = iSetIn;
+               // Save current cost of key
+               double currentCost;
+               int key = keyVariable_[iSetIn];
+               if (key < numberColumns)
+                    currentCost = cost[key];
+               else
+                    currentCost = -weight(iSetIn) * infeasibilityCost;
+               changeCost_[number2-number] = currentCost;
+               index[number2] = numberRows + iNew;
+               // do key stuff
+               int iKey = keyVariable_[iSetIn];
+               if (iKey < numberColumns) {
+                    if (gubSlackIn_ < 0)
+                         array[number2] = 1.0;
+                    else
+                         array[number2] = -1.0;
+                    pivotVariable[numberRows+iNew] = iKey;
+                    // Do I need to recompute?
+                    double sol;
+                    assert (getStatus(iSetIn) != ClpSimplex::basic);
+                    if (getStatus(iSetIn) == ClpSimplex::atLowerBound)
+                         sol = lower_[iSetIn];
+                    else
+                         sol = upper_[iSetIn];
+                    if ((gubType_ & 8) != 0) {
+                         int iColumn = next_[iKey];
+                         // sum all non-key variables
+                         while(iColumn >= 0) {
+                              sol -= solution[iColumn];
+                              iColumn = next_[iColumn];
+                         }
+                    } else {
+                         // bounds exist - sum over all except key
+                         int stop = -(iKey + 1);
+                         int iColumn = next_[iKey];
+                         // sum all non-key variables
+                         while(iColumn != stop) {
+                              if (iColumn < 0)
+                                   iColumn = -iColumn - 1;
+                              sol -= solution[iColumn];
+                              iColumn = next_[iColumn];
+                         }
+                    }
+                    solution[iKey] = sol;
+                    if (model->algorithm() > 0)
+                         model->nonLinearCost()->setOne(iKey, sol);
+                    //assert (fabs(sol-solution[iKey])<1.0e-3);
+               } else {
+                    // gub slack is basic
+                    array[number2] = -1.0;
+                    pivotVariable[numberRows+iNew] = iNew + numberTotal;
+                    model->djRegion()[iNew+numberTotal] = 0.0;
+                    double sol = 0.0;
+                    if ((gubType_ & 8) != 0) {
+                         int iColumn = next_[iKey];
+                         // sum all non-key variables
+                         while(iColumn >= 0) {
+                              sol += solution[iColumn];
+                              iColumn = next_[iColumn];
+                         }
+                    } else {
+                         // bounds exist - sum over all except key
+                         int stop = -(iKey + 1);
+                         int iColumn = next_[iKey];
+                         // sum all non-key variables
+                         while(iColumn != stop) {
+                              if (iColumn < 0)
+                                   iColumn = -iColumn - 1;
+                              sol += solution[iColumn];
+                              iColumn = next_[iColumn];
+                         }
+                    }
+                    solution[iNew+numberTotal] = sol;
+                    // and do cost in nonLinearCost
+                    if (model->algorithm() > 0)
+                         model->nonLinearCost()->setOne(iNew + numberTotal, sol, lower_[iSetIn], upper_[iSetIn]);
+                    if (sol > upper_[iSetIn] + primalTolerance) {
+                         setAbove(iSetIn);
+                         lower[iNew+numberTotal] = upper_[iSetIn];
+                         upper[iNew+numberTotal] = COIN_DBL_MAX;
+                    } else if (sol < lower_[iSetIn] - primalTolerance) {
+                         setBelow(iSetIn);
+                         lower[iNew+numberTotal] = -COIN_DBL_MAX;
+                         upper[iNew+numberTotal] = lower_[iSetIn];
+                    } else {
+                         setFeasible(iSetIn);
+                         lower[iNew+numberTotal] = lower_[iSetIn];
+                         upper[iNew+numberTotal] = upper_[iSetIn];
+                    }
+                    cost[iNew+numberTotal] = weight(iSetIn) * infeasibilityCost;
+               }
+               number2++;
+          }
+          // mark end
+          fromIndex_[number2-number] = -1;
+          returnCode = number2 - number;
+          // make sure lower_ upper_ adjusted
+          synchronize(model, 9);
+     } else {
+          // take off?
+          if (number > saveNumber_) {
+               // clear
+               double theta = model->theta();
+               double * solution = model->solutionRegion();
+               for (i = saveNumber_; i < number; i++) {
+                    int iRow = index[i];
+                    int iColumn = pivotVariable[iRow];
+#ifdef CLP_DEBUG_PRINT
+                    printf("Column %d (set %d) lower %g, upper %g - alpha %g - old value %g, new %g (theta %g)\n",
+                           iColumn, fromIndex_[i-saveNumber_], lower[iColumn], upper[iColumn], array[i],
+                           solution[iColumn], solution[iColumn] - model->theta()*array[i], model->theta());
+#endif
+                    double value = array[i];
+                    array[i] = 0.0;
+                    int iSet = fromIndex_[i-saveNumber_];
+                    toIndex_[iSet] = -1;
+                    if (iSet == iSetIn && iColumn < numberColumns) {
+                         // update as may need value
+                         solution[iColumn] -= theta * value;
+                    }
+               }
+          }
+#ifdef CLP_DEBUG
+          for (i = 0; i < numberSets_; i++)
+               assert(toIndex_[i] == -1);
+#endif
+          number2 = saveNumber_;
+     }
+     update->setNumElements(number2);
+     return returnCode;
+}
+/*
+     utility primal function for dealing with dynamic constraints
+     mode=n see ClpGubMatrix.hpp for definition
+     Remember to update here when settled down
+*/
+void
+ClpGubMatrix::primalExpanded(ClpSimplex * model, int mode)
+{
+     int numberColumns = model->numberColumns();
+     switch (mode) {
+          // If key variable then slot in gub rhs so will get correct contribution
+     case 0: {
+          int i;
+          double * solution = model->solutionRegion();
+          ClpSimplex::Status iStatus;
+          for (i = 0; i < numberSets_; i++) {
+               int iColumn = keyVariable_[i];
+               if (iColumn < numberColumns) {
+                    // key is structural - where is slack
+                    iStatus = getStatus(i);
+                    assert (iStatus != ClpSimplex::basic);
+                    if (iStatus == ClpSimplex::atLowerBound)
+                         solution[iColumn] = lower_[i];
+                    else
+                         solution[iColumn] = upper_[i];
+               }
+          }
+     }
+     break;
+     // Compute values of key variables
+     case 1: {
+          int i;
+          double * solution = model->solutionRegion();
+          //const int * columnLength = matrix_->getVectorLengths();
+          //const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+          //const int * row = matrix_->getIndices();
+          //const double * elementByColumn = matrix_->getElements();
+          //int * pivotVariable = model->pivotVariable();
+          sumPrimalInfeasibilities_ = 0.0;
+          numberPrimalInfeasibilities_ = 0;
+          double primalTolerance = model->primalTolerance();
+          double relaxedTolerance = primalTolerance;
+          // we can't really trust infeasibilities if there is primal error
+          double error = CoinMin(1.0e-2, model->largestPrimalError());
+          // allow tolerance at least slightly bigger than standard
+          relaxedTolerance = relaxedTolerance +  error;
+          // but we will be using difference
+          relaxedTolerance -= primalTolerance;
+          sumOfRelaxedPrimalInfeasibilities_ = 0.0;
+          for (i = 0; i < numberSets_; i++) { // Could just be over basics (esp if no bounds)
+               int kColumn = keyVariable_[i];
+               double value = 0.0;
+               if ((gubType_ & 8) != 0) {
+                    int iColumn = next_[kColumn];
+                    // sum all non-key variables
+                    while(iColumn >= 0) {
+                         value += solution[iColumn];
+                         iColumn = next_[iColumn];
+                    }
+               } else {
+                    // bounds exist - sum over all except key
+                    int stop = -(kColumn + 1);
+                    int iColumn = next_[kColumn];
+                    // sum all non-key variables
+                    while(iColumn != stop) {
+                         if (iColumn < 0)
+                              iColumn = -iColumn - 1;
+                         value += solution[iColumn];
+                         iColumn = next_[iColumn];
+                    }
+               }
+               if (kColumn < numberColumns) {
+                    // make sure key is basic - so will be skipped in values pass
+                    model->setStatus(kColumn, ClpSimplex::basic);
+                    // feasibility will be done later
+                    assert (getStatus(i) != ClpSimplex::basic);
+                    if (getStatus(i) == ClpSimplex::atUpperBound)
+                         solution[kColumn] = upper_[i] - value;
+                    else
+                         solution[kColumn] = lower_[i] - value;
+                    //printf("Value of key structural %d for set %d is %g\n",kColumn,i,solution[kColumn]);
+               } else {
+                    // slack is key
+                    assert (getStatus(i) == ClpSimplex::basic);
+                    double infeasibility = 0.0;
+                    if (value > upper_[i] + primalTolerance) {
+                         infeasibility = value - upper_[i] - primalTolerance;
+                         setAbove(i);
+                    } else if (value < lower_[i] - primalTolerance) {
+                         infeasibility = lower_[i] - value - primalTolerance ;
+                         setBelow(i);
+                    } else {
+                         setFeasible(i);
+                    }
+                    //printf("Value of key slack for set %d is %g\n",i,value);
+                    if (infeasibility > 0.0) {
+                         sumPrimalInfeasibilities_ += infeasibility;
+                         if (infeasibility > relaxedTolerance)
+                              sumOfRelaxedPrimalInfeasibilities_ += infeasibility;
+                         numberPrimalInfeasibilities_ ++;
+                    }
+               }
+          }
+     }
+     break;
+     // Report on infeasibilities of key variables
+     case 2: {
+          model->setSumPrimalInfeasibilities(model->sumPrimalInfeasibilities() +
+                                             sumPrimalInfeasibilities_);
+          model->setNumberPrimalInfeasibilities(model->numberPrimalInfeasibilities() +
+                                                numberPrimalInfeasibilities_);
+          model->setSumOfRelaxedPrimalInfeasibilities(model->sumOfRelaxedPrimalInfeasibilities() +
+                    sumOfRelaxedPrimalInfeasibilities_);
+     }
+     break;
+     }
+}
+/*
+     utility dual function for dealing with dynamic constraints
+     mode=n see ClpGubMatrix.hpp for definition
+     Remember to update here when settled down
+*/
+void
+ClpGubMatrix::dualExpanded(ClpSimplex * model,
+                           CoinIndexedVector * array,
+                           double * /*other*/, int mode)
+{
+     switch (mode) {
+          // modify costs before transposeUpdate
+     case 0: {
+          int i;
+          double * cost = model->costRegion();
+          // not dual values yet
+          //assert (!other);
+          //double * work = array->denseVector();
+          double infeasibilityCost = model->infeasibilityCost();
+          int * pivotVariable = model->pivotVariable();
+          int numberRows = model->numberRows();
+          int numberColumns = model->numberColumns();
+          for (i = 0; i < numberRows; i++) {
+               int iPivot = pivotVariable[i];
+               if (iPivot < numberColumns) {
+                    int iSet = backward_[iPivot];
+                    if (iSet >= 0) {
+                         int kColumn = keyVariable_[iSet];
+                         double costValue;
+                         if (kColumn < numberColumns) {
+                              // structural has cost
+                              costValue = cost[kColumn];
+                         } else {
+                              // slack is key
+                              assert (getStatus(iSet) == ClpSimplex::basic);
+                              // negative as -1.0 for slack
+                              costValue = -weight(iSet) * infeasibilityCost;
+                         }
+                         array->add(i, -costValue); // was work[i]-costValue
+                    }
+               }
+          }
+     }
+     break;
+     // create duals for key variables (without check on dual infeasible)
+     case 1: {
+          // If key slack then dual 0.0 (if feasible)
+          // dj for key is zero so that defines dual on set
+          int i;
+          double * dj = model->djRegion();
+          int numberColumns = model->numberColumns();
+          double infeasibilityCost = model->infeasibilityCost();
+          for (i = 0; i < numberSets_; i++) {
+               int kColumn = keyVariable_[i];
+               if (kColumn < numberColumns) {
+                    // dj without set
+                    double value = dj[kColumn];
+                    // Now subtract out from all
+                    dj[kColumn] = 0.0;
+                    int iColumn = next_[kColumn];
+                    // modify all non-key variables
+                    while(iColumn >= 0) {
+                         dj[iColumn] -= value;
+                         iColumn = next_[iColumn];
+                    }
+               } else {
+                    // slack key - may not be feasible
+                    assert (getStatus(i) == ClpSimplex::basic);
+                    // negative as -1.0 for slack
+                    double value = -weight(i) * infeasibilityCost;
+                    if (value) {
+                         int iColumn = next_[kColumn];
+                         // modify all non-key variables basic
+                         while(iColumn >= 0) {
+                              dj[iColumn] -= value;
+                              iColumn = next_[iColumn];
+                         }
+                    }
+               }
+          }
+     }
+     break;
+     // as 1 but check slacks and compute djs
+     case 2: {
+          // If key slack then dual 0.0
+          // If not then slack could be dual infeasible
+          // dj for key is zero so that defines dual on set
+          int i;
+          // make sure fromIndex will not confuse pricing
+          fromIndex_[0] = -1;
+          possiblePivotKey_ = -1;
+          // Create array
+          int numberColumns = model->numberColumns();
+          int * pivotVariable = model->pivotVariable();
+          int numberRows = model->numberRows();
+          for (i = 0; i < numberRows; i++) {
+               int iPivot = pivotVariable[i];
+               if (iPivot < numberColumns)
+                    backToPivotRow_[iPivot] = i;
+          }
+          if (noCheck_ >= 0) {
+               if (infeasibilityWeight_ != model->infeasibilityCost()) {
+                    // don't bother checking
+                    sumDualInfeasibilities_ = 100.0;
+                    numberDualInfeasibilities_ = 1;
+                    sumOfRelaxedDualInfeasibilities_ = 100.0;
+                    return;
+               }
+          }
+          double * dj = model->djRegion();
+          double * dual = model->dualRowSolution();
+          double * cost = model->costRegion();
+          ClpSimplex::Status iStatus;
+          const int * columnLength = matrix_->getVectorLengths();
+          const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+          const int * row = matrix_->getIndices();
+          const double * elementByColumn = matrix_->getElements();
+          double infeasibilityCost = model->infeasibilityCost();
+          sumDualInfeasibilities_ = 0.0;
+          numberDualInfeasibilities_ = 0;
+          double dualTolerance = model->dualTolerance();
+          double relaxedTolerance = dualTolerance;
+          // we can't really trust infeasibilities if there is dual error
+          double error = CoinMin(1.0e-2, model->largestDualError());
+          // allow tolerance at least slightly bigger than standard
+          relaxedTolerance = relaxedTolerance +  error;
+          // but we will be using difference
+          relaxedTolerance -= dualTolerance;
+          sumOfRelaxedDualInfeasibilities_ = 0.0;
+          for (i = 0; i < numberSets_; i++) {
+               int kColumn = keyVariable_[i];
+               if (kColumn < numberColumns) {
+                    // dj without set
+                    double value = cost[kColumn];
+                    for (CoinBigIndex j = columnStart[kColumn];
+                              j < columnStart[kColumn] + columnLength[kColumn]; j++) {
+                         int iRow = row[j];
+                         value -= dual[iRow] * elementByColumn[j];
+                    }
+                    // Now subtract out from all
+                    dj[kColumn] -= value;
+                    int stop = -(kColumn + 1);
+                    kColumn = next_[kColumn];
+                    while (kColumn != stop) {
+                         if (kColumn < 0)
+                              kColumn = -kColumn - 1;
+                         double djValue = dj[kColumn] - value;
+                         dj[kColumn] = djValue;;
+                         double infeasibility = 0.0;
+                         iStatus = model->getStatus(kColumn);
+                         if (iStatus == ClpSimplex::atLowerBound) {
+                              if (djValue < -dualTolerance)
+                                   infeasibility = -djValue - dualTolerance;
+                         } else if (iStatus == ClpSimplex::atUpperBound) {
+                              // at upper bound
+                              if (djValue > dualTolerance)
+                                   infeasibility = djValue - dualTolerance;
+                         }
+                         if (infeasibility > 0.0) {
+                              sumDualInfeasibilities_ += infeasibility;
+                              if (infeasibility > relaxedTolerance)
+                                   sumOfRelaxedDualInfeasibilities_ += infeasibility;
+                              numberDualInfeasibilities_ ++;
+                         }
+                         kColumn = next_[kColumn];
+                    }
+                    // check slack
+                    iStatus = getStatus(i);
+                    assert (iStatus != ClpSimplex::basic);
+                    double infeasibility = 0.0;
+                    // dj of slack is -(-1.0)value
+                    if (iStatus == ClpSimplex::atLowerBound) {
+                         if (value < -dualTolerance)
+                              infeasibility = -value - dualTolerance;
+                    } else if (iStatus == ClpSimplex::atUpperBound) {
+                         // at upper bound
+                         if (value > dualTolerance)
+                              infeasibility = value - dualTolerance;
+                    }
+                    if (infeasibility > 0.0) {
+                         sumDualInfeasibilities_ += infeasibility;
+                         if (infeasibility > relaxedTolerance)
+                              sumOfRelaxedDualInfeasibilities_ += infeasibility;
+                         numberDualInfeasibilities_ ++;
+                    }
+               } else {
+                    // slack key - may not be feasible
+                    assert (getStatus(i) == ClpSimplex::basic);
+                    // negative as -1.0 for slack
+                    double value = -weight(i) * infeasibilityCost;
+                    if (value) {
+                         // Now subtract out from all
+                         int kColumn = i + numberColumns;
+                         int stop = -(kColumn + 1);
+                         kColumn = next_[kColumn];
+                         while (kColumn != stop) {
+                              if (kColumn < 0)
+                                   kColumn = -kColumn - 1;
+                              double djValue = dj[kColumn] - value;
+                              dj[kColumn] = djValue;;
+                              double infeasibility = 0.0;
+                              iStatus = model->getStatus(kColumn);
+                              if (iStatus == ClpSimplex::atLowerBound) {
+                                   if (djValue < -dualTolerance)
+                                        infeasibility = -djValue - dualTolerance;
+                              } else if (iStatus == ClpSimplex::atUpperBound) {
+                                   // at upper bound
+                                   if (djValue > dualTolerance)
+                                        infeasibility = djValue - dualTolerance;
+                              }
+                              if (infeasibility > 0.0) {
+                                   sumDualInfeasibilities_ += infeasibility;
+                                   if (infeasibility > relaxedTolerance)
+                                        sumOfRelaxedDualInfeasibilities_ += infeasibility;
+                                   numberDualInfeasibilities_ ++;
+                              }
+                              kColumn = next_[kColumn];
+                         }
+                    }
+               }
+          }
+          // and get statistics for column generation
+          synchronize(model, 4);
+          infeasibilityWeight_ = -1.0;
+     }
+     break;
+     // Report on infeasibilities of key variables
+     case 3: {
+          model->setSumDualInfeasibilities(model->sumDualInfeasibilities() +
+                                           sumDualInfeasibilities_);
+          model->setNumberDualInfeasibilities(model->numberDualInfeasibilities() +
+                                              numberDualInfeasibilities_);
+          model->setSumOfRelaxedDualInfeasibilities(model->sumOfRelaxedDualInfeasibilities() +
+                    sumOfRelaxedDualInfeasibilities_);
+     }
+     break;
+     // modify costs before transposeUpdate for partial pricing
+     case 4: {
+          // First compute new costs etc for interesting gubs
+          int iLook = 0;
+          int iSet = fromIndex_[0];
+          double primalTolerance = model->primalTolerance();
+          const double * cost = model->costRegion();
+          double * solution = model->solutionRegion();
+          double infeasibilityCost = model->infeasibilityCost();
+          int numberColumns = model->numberColumns();
+          int numberChanged = 0;
+          int * pivotVariable = model->pivotVariable();
+          while (iSet >= 0) {
+               int key = keyVariable_[iSet];
+               double value = 0.0;
+               // sum over all except key
+               if ((gubType_ & 8) != 0) {
+                    int iColumn = next_[key];
+                    // sum all non-key variables
+                    while(iColumn >= 0) {
+                         value += solution[iColumn];
+                         iColumn = next_[iColumn];
+                    }
+               } else {
+                    // bounds exist - sum over all except key
+                    int stop = -(key + 1);
+                    int iColumn = next_[key];
+                    // sum all non-key variables
+                    while(iColumn != stop) {
+                         if (iColumn < 0)
+                              iColumn = -iColumn - 1;
+                         value += solution[iColumn];
+                         iColumn = next_[iColumn];
+                    }
+               }
+               double costChange;
+               double oldCost = changeCost_[iLook];
+               if (key < numberColumns) {
+                    assert (getStatus(iSet) != ClpSimplex::basic);
+                    double sol;
+                    if (getStatus(iSet) == ClpSimplex::atUpperBound)
+                         sol = upper_[iSet] - value;
+                    else
+                         sol = lower_[iSet] - value;
+                    solution[key] = sol;
+                    // fix up cost
+                    model->nonLinearCost()->setOne(key, sol);
+#ifdef CLP_DEBUG_PRINT
+                    printf("yy Value of key structural %d for set %d is %g - cost %g old cost %g\n", key, iSet, sol,
+                           cost[key], oldCost);
+#endif
+                    costChange = cost[key] - oldCost;
+               } else {
+                    // slack is key
+                    if (value > upper_[iSet] + primalTolerance) {
+                         setAbove(iSet);
+                    } else if (value < lower_[iSet] - primalTolerance) {
+                         setBelow(iSet);
+                    } else {
+                         setFeasible(iSet);
+                    }
+                    // negative as -1.0 for slack
+                    costChange = -weight(iSet) * infeasibilityCost - oldCost;
+#ifdef CLP_DEBUG_PRINT
+                    printf("yy Value of key slack for set %d is %g - cost %g old cost %g\n", iSet, value,
+                           weight(iSet)*infeasibilityCost, oldCost);
+#endif
+               }
+               if (costChange) {
+                    fromIndex_[numberChanged] = iSet;
+                    toIndex_[iSet] = numberChanged;
+                    changeCost_[numberChanged++] = costChange;
+               }
+               iSet = fromIndex_[++iLook];
+          }
+          if (numberChanged || possiblePivotKey_ >= 0) {
+               // first do those in list already
+               int number = array->getNumElements();
+               array->setPacked();
+               int i;
+               double * work = array->denseVector();
+               int * which = array->getIndices();
+               for (i = 0; i < number; i++) {
+                    int iRow = which[i];
+                    int iPivot = pivotVariable[iRow];
+                    if (iPivot < numberColumns) {
+                         int iSet = backward_[iPivot];
+                         if (iSet >= 0 && toIndex_[iSet] >= 0) {
+                              double newValue = work[i] + changeCost_[toIndex_[iSet]];
+                              if (!newValue)
+                                   newValue = 1.0e-100;
+                              work[i] = newValue;
+                              // mark as done
+                              backward_[iPivot] = -1;
+                         }
+                    }
+                    if (possiblePivotKey_ == iRow) {
+                         double newValue = work[i] - model->dualIn();
+                         if (!newValue)
+                              newValue = 1.0e-100;
+                         work[i] = newValue;
+                         possiblePivotKey_ = -1;
+                    }
+               }
+               // now do rest and clean up
+               for (i = 0; i < numberChanged; i++) {
+                    int iSet = fromIndex_[i];
+                    int key = keyVariable_[iSet];
+                    int iColumn = next_[key];
+                    double change = changeCost_[i];
+                    while (iColumn >= 0) {
+                         if (backward_[iColumn] >= 0) {
+                              int iRow = backToPivotRow_[iColumn];
+                              assert (iRow >= 0);
+                              work[number] = change;
+                              if (possiblePivotKey_ == iRow) {
+                                   double newValue = work[number] - model->dualIn();
+                                   if (!newValue)
+                                        newValue = 1.0e-100;
+                                   work[number] = newValue;
+                                   possiblePivotKey_ = -1;
+                              }
+                              which[number++] = iRow;
+                         } else {
+                              // reset
+                              backward_[iColumn] = iSet;
+                         }
+                         iColumn = next_[iColumn];
+                    }
+                    toIndex_[iSet] = -1;
+               }
+               if (possiblePivotKey_ >= 0) {
+                    work[number] = -model->dualIn();
+                    which[number++] = possiblePivotKey_;
+                    possiblePivotKey_ = -1;
+               }
+               fromIndex_[0] = -1;
+               array->setNumElements(number);
+          }
+     }
+     break;
+     }
+}
+// This is local to Gub to allow synchronization when status is good
+int
+ClpGubMatrix::synchronize(ClpSimplex *, int)
+{
+     return 0;
+}
+/*
+     general utility function for dealing with dynamic constraints
+     mode=n see ClpGubMatrix.hpp for definition
+     Remember to update here when settled down
+*/
+int
+ClpGubMatrix::generalExpanded(ClpSimplex * model, int mode, int &number)
+{
+     int returnCode = 0;
+     int numberColumns = model->numberColumns();
+     switch (mode) {
+          // Fill in pivotVariable but not for key variables
+     case 0: {
+          if (!next_ ) {
+               // do ordering
+               assert (!rhsOffset_);
+               // create and do gub crash
+               useEffectiveRhs(model, false);
+          }
+          int i;
+          int numberBasic = number;
+          // Use different array so can build from true pivotVariable_
+          //int * pivotVariable = model->pivotVariable();
+          int * pivotVariable = model->rowArray(0)->getIndices();
+          for (i = 0; i < numberColumns; i++) {
+               if (model->getColumnStatus(i) == ClpSimplex::basic) {
+                    int iSet = backward_[i];
+                    if (iSet < 0 || i != keyVariable_[iSet])
+                         pivotVariable[numberBasic++] = i;
+               }
+          }
+          number = numberBasic;
+          if (model->numberIterations())
+               assert (number == model->numberRows());
+     }
+     break;
+     // Make all key variables basic
+     case 1: {
+          int i;
+          for (i = 0; i < numberSets_; i++) {
+               int iColumn = keyVariable_[i];
+               if (iColumn < numberColumns)
+                    model->setColumnStatus(iColumn, ClpSimplex::basic);
+          }
+     }
+     break;
+     // Do initial extra rows + maximum basic
+     case 2: {
+          returnCode = getNumRows() + 1;
+          number = model->numberRows() + numberSets_;
+     }
+     break;
+     // Before normal replaceColumn
+     case 3: {
+          int sequenceIn = model->sequenceIn();
+          int sequenceOut = model->sequenceOut();
+          int numberColumns = model->numberColumns();
+          int numberRows = model->numberRows();
+          int pivotRow = model->pivotRow();
+          if (gubSlackIn_ >= 0)
+               assert (sequenceIn > numberRows + numberColumns);
+          if (sequenceIn == sequenceOut)
+               return -1;
+          int iSetIn = -1;
+          int iSetOut = -1;
+          if (sequenceOut < numberColumns) {
+               iSetOut = backward_[sequenceOut];
+          } else if (sequenceOut >= numberRows + numberColumns) {
+               assert (pivotRow >= numberRows);
+               int iExtra = pivotRow - numberRows;
+               assert (iExtra >= 0);
+               if (iSetOut < 0)
+                    iSetOut = fromIndex_[iExtra];
+               else
+                    assert(iSetOut == fromIndex_[iExtra]);
+          }
+          if (sequenceIn < numberColumns) {
+               iSetIn = backward_[sequenceIn];
+          } else if (gubSlackIn_ >= 0) {
+               iSetIn = gubSlackIn_;
+          }
+          possiblePivotKey_ = -1;
+          number = 0; // say do ordinary
+          int * pivotVariable = model->pivotVariable();
+          if (pivotRow >= numberRows) {
+               int iExtra = pivotRow - numberRows;
+               //const int * length = matrix_->getVectorLengths();
+
+               assert (sequenceOut >= numberRows + numberColumns ||
+                       sequenceOut == keyVariable_[iSetOut]);
+               int incomingColumn = sequenceIn; // to be used in updates
+               if (iSetIn != iSetOut) {
+                    // We need to find a possible pivot for incoming
+                    // look through rowArray_[1]
+                    int n = model->rowArray(1)->getNumElements();
+                    int * which = model->rowArray(1)->getIndices();
+                    double * array = model->rowArray(1)->denseVector();
+                    double bestAlpha = 1.0e-5;
+                    //int shortest=numberRows+1;
+                    for (int i = 0; i < n; i++) {
+                         int iRow = which[i];
+                         int iPivot = pivotVariable[iRow];
+                         if (iPivot < numberColumns && backward_[iPivot] == iSetOut) {
+                              if (fabs(array[i]) > fabs(bestAlpha)) {
+                                   bestAlpha = array[i];
+                                   possiblePivotKey_ = iRow;
+                              }
+                         }
+                    }
+                    assert (possiblePivotKey_ >= 0); // could set returnCode=4
+                    number = 1;
+                    if (sequenceIn >= numberRows + numberColumns) {
+                         number = 3;
+                         // need swap as gub slack in and must become key
+                         // is this best way
+                         int key = keyVariable_[iSetIn];
+                         assert (key < numberColumns);
+                         // check other basic
+                         int iColumn = next_[key];
+                         // set new key to be used by unpack
+                         keyVariable_[iSetIn] = iSetIn + numberColumns;
+                         // change cost in changeCost
+                         {
+                              int iLook = 0;
+                              int iSet = fromIndex_[0];
+                              while (iSet >= 0) {
+                                   if (iSet == iSetIn) {
+                                        changeCost_[iLook] = 0.0;
+                                        break;
+                                   }
+                                   iSet = fromIndex_[++iLook];
+                              }
+                         }
+                         while (iColumn >= 0) {
+                              if (iColumn != sequenceOut) {
+                                   // need partial ftran and skip accuracy check in replaceColumn
+#ifdef CLP_DEBUG_PRINT
+                                   printf("TTTTTry 5\n");
+#endif
+                                   int iRow = backToPivotRow_[iColumn];
+                                   assert (iRow >= 0);
+                                   unpack(model, model->rowArray(3), iColumn);
+                                   model->factorization()->updateColumnFT(model->rowArray(2), model->rowArray(3));
+                                   double alpha = model->rowArray(3)->denseVector()[iRow];
+                                   //if (!alpha)
+                                   //printf("zero alpha a\n");
+                                   int updateStatus = model->factorization()->replaceColumn(model,
+                                                      model->rowArray(2),
+                                                      model->rowArray(3),
+                                                      iRow, alpha);
+                                   returnCode = CoinMax(updateStatus, returnCode);
+                                   model->rowArray(3)->clear();
+                                   if (returnCode)
+                                        break;
+                              }
+                              iColumn = next_[iColumn];
+                         }
+                         if (!returnCode) {
+                              // now factorization looks as if key is out
+                              // pivot back in
+#ifdef CLP_DEBUG_PRINT
+                              printf("TTTTTry 6\n");
+#endif
+                              unpack(model, model->rowArray(3), key);
+                              model->factorization()->updateColumnFT(model->rowArray(2), model->rowArray(3));
+                              pivotRow = possiblePivotKey_;
+                              double alpha = model->rowArray(3)->denseVector()[pivotRow];
+                              //if (!alpha)
+                              //printf("zero alpha b\n");
+                              int updateStatus = model->factorization()->replaceColumn(model,
+                                                 model->rowArray(2),
+                                                 model->rowArray(3),
+                                                 pivotRow, alpha);
+                              returnCode = CoinMax(updateStatus, returnCode);
+                              model->rowArray(3)->clear();
+                         }
+                         // restore key
+                         keyVariable_[iSetIn] = key;
+                         // now alternate column can replace key on out
+                         incomingColumn = pivotVariable[possiblePivotKey_];
+                    } else {
+#ifdef CLP_DEBUG_PRINT
+                         printf("TTTTTTry 4 %d\n", possiblePivotKey_);
+#endif
+                         int updateStatus = model->factorization()->replaceColumn(model,
+                                            model->rowArray(2),
+                                            model->rowArray(1),
+                                            possiblePivotKey_,
+                                            bestAlpha);
+                         returnCode = CoinMax(updateStatus, returnCode);
+                         incomingColumn = pivotVariable[possiblePivotKey_];
+                    }
+
+                    //returnCode=4; // need swap
+               } else {
+                    // key swap
+                    number = -1;
+               }
+               int key = keyVariable_[iSetOut];
+               if (key < numberColumns)
+                    assert(key == sequenceOut);
+               // check if any other basic
+               int iColumn = next_[key];
+               if (returnCode)
+                    iColumn = -1; // skip if error on previous
+               // set new key to be used by unpack
+               if (incomingColumn < numberColumns)
+                    keyVariable_[iSetOut] = incomingColumn;
+               else
+                    keyVariable_[iSetOut] = iSetIn + numberColumns;
+               double * cost = model->costRegion();
+               if (possiblePivotKey_ < 0) {
+                    double dj = model->djRegion()[sequenceIn] - cost[sequenceIn];
+                    changeCost_[iExtra] = -dj;
+#ifdef CLP_DEBUG_PRINT
+                    printf("modifying changeCost %d by %g - cost %g\n", iExtra, dj, cost[sequenceIn]);
+#endif
+               }
+               while (iColumn >= 0) {
+                    if (iColumn != incomingColumn) {
+                         number = -2;
+                         // need partial ftran and skip accuracy check in replaceColumn
+#ifdef CLP_DEBUG_PRINT
+                         printf("TTTTTTry 1\n");
+#endif
+                         int iRow = backToPivotRow_[iColumn];
+                         assert (iRow >= 0 && iRow < numberRows);
+                         unpack(model, model->rowArray(3), iColumn);
+                         model->factorization()->updateColumnFT(model->rowArray(2), model->rowArray(3));
+                         double * array = model->rowArray(3)->denseVector();
+                         double alpha = array[iRow];
+                         //if (!alpha)
+                         //printf("zero alpha d\n");
+                         int updateStatus = model->factorization()->replaceColumn(model,
+                                            model->rowArray(2),
+                                            model->rowArray(3),
+                                            iRow, alpha);
+                         returnCode = CoinMax(updateStatus, returnCode);
+                         model->rowArray(3)->clear();
+                         if (returnCode)
+                              break;
+                    }
+                    iColumn = next_[iColumn];
+               }
+               // restore key
+               keyVariable_[iSetOut] = key;
+          } else if (sequenceIn >= numberRows + numberColumns) {
+               number = 2;
+               //returnCode=4;
+               // need swap as gub slack in and must become key
+               // is this best way
+               int key = keyVariable_[iSetIn];
+               assert (key < numberColumns);
+               // check other basic
+               int iColumn = next_[key];
+               // set new key to be used by unpack
+               keyVariable_[iSetIn] = iSetIn + numberColumns;
+               // change cost in changeCost
+               {
+                    int iLook = 0;
+                    int iSet = fromIndex_[0];
+                    while (iSet >= 0) {
+                         if (iSet == iSetIn) {
+                              changeCost_[iLook] = 0.0;
+                              break;
+                         }
+                         iSet = fromIndex_[++iLook];
+                    }
+               }
+               while (iColumn >= 0) {
+                    if (iColumn != sequenceOut) {
+                         // need partial ftran and skip accuracy check in replaceColumn
+#ifdef CLP_DEBUG_PRINT
+                         printf("TTTTTry 2\n");
+#endif
+                         int iRow = backToPivotRow_[iColumn];
+                         assert (iRow >= 0);
+                         unpack(model, model->rowArray(3), iColumn);
+                         model->factorization()->updateColumnFT(model->rowArray(2), model->rowArray(3));
+                         double alpha = model->rowArray(3)->denseVector()[iRow];
+                         //if (!alpha)
+                         //printf("zero alpha e\n");
+                         int updateStatus = model->factorization()->replaceColumn(model,
+                                            model->rowArray(2),
+                                            model->rowArray(3),
+                                            iRow, alpha);
+                         returnCode = CoinMax(updateStatus, returnCode);
+                         model->rowArray(3)->clear();
+                         if (returnCode)
+                              break;
+                    }
+                    iColumn = next_[iColumn];
+               }
+               if (!returnCode) {
+                    // now factorization looks as if key is out
+                    // pivot back in
+#ifdef CLP_DEBUG_PRINT
+                    printf("TTTTTry 3\n");
+#endif
+                    unpack(model, model->rowArray(3), key);
+                    model->factorization()->updateColumnFT(model->rowArray(2), model->rowArray(3));
+                    double alpha = model->rowArray(3)->denseVector()[pivotRow];
+                    //if (!alpha)
+                    //printf("zero alpha f\n");
+                    int updateStatus = model->factorization()->replaceColumn(model,
+                                       model->rowArray(2),
+                                       model->rowArray(3),
+                                       pivotRow, alpha);
+                    returnCode = CoinMax(updateStatus, returnCode);
+                    model->rowArray(3)->clear();
+               }
+               // restore key
+               keyVariable_[iSetIn] = key;
+          } else {
+               // normal - but might as well do here
+               returnCode = model->factorization()->replaceColumn(model,
+                            model->rowArray(2),
+                            model->rowArray(1),
+                            model->pivotRow(),
+                            model->alpha());
+          }
+     }
+#ifdef CLP_DEBUG_PRINT
+     printf("Update type after %d - status %d - pivot row %d\n",
+            number, returnCode, model->pivotRow());
+#endif
+     // see if column generation says time to re-factorize
+     returnCode = CoinMax(returnCode, synchronize(model, 5));
+     number = -1; // say no need for normal replaceColumn
+     break;
+     // To see if can dual or primal
+     case 4: {
+          returnCode = 1;
+     }
+     break;
+     // save status
+     case 5: {
+          synchronize(model, 0);
+          CoinMemcpyN(status_, numberSets_, saveStatus_);
+          CoinMemcpyN(keyVariable_, numberSets_, savedKeyVariable_);
+     }
+     break;
+     // restore status
+     case 6: {
+          CoinMemcpyN(saveStatus_, numberSets_, status_);
+          CoinMemcpyN(savedKeyVariable_, numberSets_, keyVariable_);
+          // restore firstAvailable_
+          synchronize(model, 7);
+          // redo next_
+          int i;
+          int * last = new int[numberSets_];
+          for (i = 0; i < numberSets_; i++) {
+               int iKey = keyVariable_[i];
+               assert(iKey >= numberColumns || backward_[iKey] == i);
+               last[i] = iKey;
+               // make sure basic
+               //if (iKey<numberColumns)
+               //model->setStatus(iKey,ClpSimplex::basic);
+          }
+          for (i = 0; i < numberColumns; i++) {
+               int iSet = backward_[i];
+               if (iSet >= 0) {
+                    next_[last[iSet]] = i;
+                    last[iSet] = i;
+               }
+          }
+          for (i = 0; i < numberSets_; i++) {
+               next_[last[i]] = -(keyVariable_[i] + 1);
+               redoSet(model, keyVariable_[i], keyVariable_[i], i);
+          }
+          delete [] last;
+          // redo pivotVariable
+          int * pivotVariable = model->pivotVariable();
+          int iRow;
+          int numberBasic = 0;
+          int numberRows = model->numberRows();
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               if (model->getRowStatus(iRow) == ClpSimplex::basic) {
+                    numberBasic++;
+                    pivotVariable[iRow] = iRow + numberColumns;
+               } else {
+                    pivotVariable[iRow] = -1;
+               }
+          }
+          i = 0;
+          int iColumn;
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               if (model->getStatus(iColumn) == ClpSimplex::basic) {
+                    int iSet = backward_[iColumn];
+                    if (iSet < 0 || keyVariable_[iSet] != iColumn) {
+                         while (pivotVariable[i] >= 0) {
+                              i++;
+                              assert (i < numberRows);
+                         }
+                         pivotVariable[i] = iColumn;
+                         backToPivotRow_[iColumn] = i;
+                         numberBasic++;
+                    }
+               }
+          }
+          assert (numberBasic == numberRows);
+          rhsOffset(model, true);
+     }
+     break;
+     // flag a variable
+     case 7: {
+          assert (number == model->sequenceIn());
+          synchronize(model, 1);
+          synchronize(model, 8);
+     }
+     break;
+     // unflag all variables
+     case 8: {
+          returnCode = synchronize(model, 2);
+     }
+     break;
+     // redo costs in primal
+     case 9: {
+          returnCode = synchronize(model, 3);
+     }
+     break;
+     // return 1 if there may be changing bounds on variable (column generation)
+     case 10: {
+          returnCode = synchronize(model, 6);
+     }
+     break;
+     // make sure set is clean
+     case 11: {
+          assert (number == model->sequenceIn());
+          returnCode = synchronize(model, 8);
+     }
+     break;
+     default:
+          break;
+     }
+     return returnCode;
+}
+// Sets up an effective RHS and does gub crash if needed
+void
+ClpGubMatrix::useEffectiveRhs(ClpSimplex * model, bool cheapest)
+{
+     // Do basis - cheapest or slack if feasible (unless cheapest set)
+     int longestSet = 0;
+     int iSet;
+     for (iSet = 0; iSet < numberSets_; iSet++)
+          longestSet = CoinMax(longestSet, end_[iSet] - start_[iSet]);
+
+     double * upper = new double[longestSet+1];
+     double * cost = new double[longestSet+1];
+     double * lower = new double[longestSet+1];
+     double * solution = new double[longestSet+1];
+     assert (!next_);
+     int numberColumns = getNumCols();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * columnLower = model->lowerRegion();
+     const double * columnUpper = model->upperRegion();
+     double * columnSolution = model->solutionRegion();
+     const double * objective = model->costRegion();
+     int numberRows = getNumRows();
+     toIndex_ = new int[numberSets_];
+     for (iSet = 0; iSet < numberSets_; iSet++)
+          toIndex_[iSet] = -1;
+     fromIndex_ = new int [getNumRows()+1];
+     double tolerance = model->primalTolerance();
+     bool noNormalBounds = true;
+     gubType_ &= ~8;
+     bool gotBasis = false;
+     for (iSet = 0; iSet < numberSets_; iSet++) {
+          if (keyVariable_[iSet] < numberColumns)
+               gotBasis = true;
+          CoinBigIndex j;
+          CoinBigIndex iStart = start_[iSet];
+          CoinBigIndex iEnd = end_[iSet];
+          for (j = iStart; j < iEnd; j++) {
+               if (columnLower[j] && columnLower[j] > -1.0e20)
+                    noNormalBounds = false;
+               if (columnUpper[j] && columnUpper[j] < 1.0e20)
+                    noNormalBounds = false;
+          }
+     }
+     if (noNormalBounds)
+          gubType_ |= 8;
+     if (!gotBasis) {
+          for (iSet = 0; iSet < numberSets_; iSet++) {
+               CoinBigIndex j;
+               int numberBasic = 0;
+               int iBasic = -1;
+               CoinBigIndex iStart = start_[iSet];
+               CoinBigIndex iEnd = end_[iSet];
+               // find one with smallest length
+               int smallest = numberRows + 1;
+               double value = 0.0;
+               for (j = iStart; j < iEnd; j++) {
+                    if (model->getStatus(j) == ClpSimplex::basic) {
+                         if (columnLength[j] < smallest) {
+                              smallest = columnLength[j];
+                              iBasic = j;
+                         }
+                         numberBasic++;
+                    }
+                    value += columnSolution[j];
+               }
+               bool done = false;
+               if (numberBasic > 1 || (numberBasic == 1 && getStatus(iSet) == ClpSimplex::basic)) {
+                    if (getStatus(iSet) == ClpSimplex::basic)
+                         iBasic = iSet + numberColumns; // slack key - use
+                    done = true;
+               } else if (numberBasic == 1) {
+                    // see if can be key
+                    double thisSolution = columnSolution[iBasic];
+                    if (thisSolution > columnUpper[iBasic]) {
+                         value -= thisSolution - columnUpper[iBasic];
+                         thisSolution = columnUpper[iBasic];
+                         columnSolution[iBasic] = thisSolution;
+                    }
+                    if (thisSolution < columnLower[iBasic]) {
+                         value -= thisSolution - columnLower[iBasic];
+                         thisSolution = columnLower[iBasic];
+                         columnSolution[iBasic] = thisSolution;
+                    }
+                    // try setting slack to a bound
+                    assert (upper_[iSet] < 1.0e20 || lower_[iSet] > -1.0e20);
+                    double cost1 = COIN_DBL_MAX;
+                    int whichBound = -1;
+                    if (upper_[iSet] < 1.0e20) {
+                         // try slack at ub
+                         double newBasic = thisSolution + upper_[iSet] - value;
+                         if (newBasic >= columnLower[iBasic] - tolerance &&
+                                   newBasic <= columnUpper[iBasic] + tolerance) {
+                              // can go
+                              whichBound = 1;
+                              cost1 = newBasic * objective[iBasic];
+                              // But if exact then may be good solution
+                              if (fabs(upper_[iSet] - value) < tolerance)
+                                   cost1 = -COIN_DBL_MAX;
+                         }
+                    }
+                    if (lower_[iSet] > -1.0e20) {
+                         // try slack at lb
+                         double newBasic = thisSolution + lower_[iSet] - value;
+                         if (newBasic >= columnLower[iBasic] - tolerance &&
+                                   newBasic <= columnUpper[iBasic] + tolerance) {
+                              // can go but is it cheaper
+                              double cost2 = newBasic * objective[iBasic];
+                              // But if exact then may be good solution
+                              if (fabs(lower_[iSet] - value) < tolerance)
+                                   cost2 = -COIN_DBL_MAX;
+                              if (cost2 < cost1)
+                                   whichBound = 0;
+                         }
+                    }
+                    if (whichBound != -1) {
+                         // key
+                         done = true;
+                         if (whichBound) {
+                              // slack to upper
+                              columnSolution[iBasic] = thisSolution + upper_[iSet] - value;
+                              setStatus(iSet, ClpSimplex::atUpperBound);
+                         } else {
+                              // slack to lower
+                              columnSolution[iBasic] = thisSolution + lower_[iSet] - value;
+                              setStatus(iSet, ClpSimplex::atLowerBound);
+                         }
+                    }
+               }
+               if (!done) {
+                    if (!cheapest) {
+                         // see if slack can be key
+                         if (value >= lower_[iSet] - tolerance && value <= upper_[iSet] + tolerance) {
+                              done = true;
+                              setStatus(iSet, ClpSimplex::basic);
+                              iBasic = iSet + numberColumns;
+                         }
+                    }
+                    if (!done) {
+                         // set non basic if there was one
+                         if (iBasic >= 0)
+                              model->setStatus(iBasic, ClpSimplex::atLowerBound);
+                         // find cheapest
+                         int numberInSet = iEnd - iStart;
+                         CoinMemcpyN(columnLower + iStart, numberInSet, lower);
+                         CoinMemcpyN(columnUpper + iStart, numberInSet, upper);
+                         CoinMemcpyN(columnSolution + iStart, numberInSet, solution);
+                         // and slack
+                         iBasic = numberInSet;
+                         solution[iBasic] = -value;
+                         lower[iBasic] = -upper_[iSet];
+                         upper[iBasic] = -lower_[iSet];
+                         int kphase;
+                         if (value >= lower_[iSet] - tolerance && value <= upper_[iSet] + tolerance) {
+                              // feasible
+                              kphase = 1;
+                              cost[iBasic] = 0.0;
+                              CoinMemcpyN(objective + iStart, numberInSet, cost);
+                         } else {
+                              // infeasible
+                              kphase = 0;
+                              // remember bounds are flipped so opposite to natural
+                              if (value < lower_[iSet] - tolerance)
+                                   cost[iBasic] = 1.0;
+                              else
+                                   cost[iBasic] = -1.0;
+                              CoinZeroN(cost, numberInSet);
+                         }
+                         double dualTolerance = model->dualTolerance();
+                         for (int iphase = kphase; iphase < 2; iphase++) {
+                              if (iphase) {
+                                   cost[numberInSet] = 0.0;
+                                   CoinMemcpyN(objective + iStart, numberInSet, cost);
+                              }
+                              // now do one row lp
+                              bool improve = true;
+                              while (improve) {
+                                   improve = false;
+                                   double dual = cost[iBasic];
+                                   int chosen = -1;
+                                   double best = dualTolerance;
+                                   int way = 0;
+                                   for (int i = 0; i <= numberInSet; i++) {
+                                        double dj = cost[i] - dual;
+                                        double improvement = 0.0;
+                                        if (iphase || i < numberInSet)
+                                             assert (solution[i] >= lower[i] && solution[i] <= upper[i]);
+                                        if (dj > dualTolerance)
+                                             improvement = dj * (solution[i] - lower[i]);
+                                        else if (dj < -dualTolerance)
+                                             improvement = dj * (solution[i] - upper[i]);
+                                        if (improvement > best) {
+                                             best = improvement;
+                                             chosen = i;
+                                             if (dj < 0.0) {
+                                                  way = 1;
+                                             } else {
+                                                  way = -1;
+                                             }
+                                        }
+                                   }
+                                   if (chosen >= 0) {
+                                        improve = true;
+                                        // now see how far
+                                        if (way > 0) {
+                                             // incoming increasing so basic decreasing
+                                             // if phase 0 then go to nearest bound
+                                             double distance = upper[chosen] - solution[chosen];
+                                             double basicDistance;
+                                             if (!iphase) {
+                                                  assert (iBasic == numberInSet);
+                                                  assert (solution[iBasic] > upper[iBasic]);
+                                                  basicDistance = solution[iBasic] - upper[iBasic];
+                                             } else {
+                                                  basicDistance = solution[iBasic] - lower[iBasic];
+                                             }
+                                             // need extra coding for unbounded
+                                             assert (CoinMin(distance, basicDistance) < 1.0e20);
+                                             if (distance > basicDistance) {
+                                                  // incoming becomes basic
+                                                  solution[chosen] += basicDistance;
+                                                  if (!iphase)
+                                                       solution[iBasic] = upper[iBasic];
+                                                  else
+                                                       solution[iBasic] = lower[iBasic];
+                                                  iBasic = chosen;
+                                             } else {
+                                                  // flip
+                                                  solution[chosen] = upper[chosen];
+                                                  solution[iBasic] -= distance;
+                                             }
+                                        } else {
+                                             // incoming decreasing so basic increasing
+                                             // if phase 0 then go to nearest bound
+                                             double distance = solution[chosen] - lower[chosen];
+                                             double basicDistance;
+                                             if (!iphase) {
+                                                  assert (iBasic == numberInSet);
+                                                  assert (solution[iBasic] < lower[iBasic]);
+                                                  basicDistance = lower[iBasic] - solution[iBasic];
+                                             } else {
+                                                  basicDistance = upper[iBasic] - solution[iBasic];
+                                             }
+                                             // need extra coding for unbounded - for now just exit
+                                             if (CoinMin(distance, basicDistance) > 1.0e20) {
+                                                  printf("unbounded on set %d\n", iSet);
+                                                  iphase = 1;
+                                                  iBasic = numberInSet;
+                                                  break;
+                                             }
+                                             if (distance > basicDistance) {
+                                                  // incoming becomes basic
+                                                  solution[chosen] -= basicDistance;
+                                                  if (!iphase)
+                                                       solution[iBasic] = lower[iBasic];
+                                                  else
+                                                       solution[iBasic] = upper[iBasic];
+                                                  iBasic = chosen;
+                                             } else {
+                                                  // flip
+                                                  solution[chosen] = lower[chosen];
+                                                  solution[iBasic] += distance;
+                                             }
+                                        }
+                                        if (!iphase) {
+                                             if(iBasic < numberInSet)
+                                                  break; // feasible
+                                             else if (solution[iBasic] >= lower[iBasic] &&
+                                                       solution[iBasic] <= upper[iBasic])
+                                                  break; // feasible (on flip)
+                                        }
+                                   }
+                              }
+                         }
+                         // convert iBasic back and do bounds
+                         if (iBasic == numberInSet) {
+                              // slack basic
+                              setStatus(iSet, ClpSimplex::basic);
+                              iBasic = iSet + numberColumns;
+                         } else {
+                              iBasic += start_[iSet];
+                              model->setStatus(iBasic, ClpSimplex::basic);
+                              // remember bounds flipped
+                              if (upper[numberInSet] == lower[numberInSet])
+                                   setStatus(iSet, ClpSimplex::isFixed);
+                              else if (solution[numberInSet] == upper[numberInSet])
+                                   setStatus(iSet, ClpSimplex::atLowerBound);
+                              else if (solution[numberInSet] == lower[numberInSet])
+                                   setStatus(iSet, ClpSimplex::atUpperBound);
+                              else
+                                   abort();
+                         }
+                         for (j = iStart; j < iEnd; j++) {
+                              if (model->getStatus(j) != ClpSimplex::basic) {
+                                   int inSet = j - iStart;
+                                   columnSolution[j] = solution[inSet];
+                                   if (upper[inSet] == lower[inSet])
+                                        model->setStatus(j, ClpSimplex::isFixed);
+                                   else if (solution[inSet] == upper[inSet])
+                                        model->setStatus(j, ClpSimplex::atUpperBound);
+                                   else if (solution[inSet] == lower[inSet])
+                                        model->setStatus(j, ClpSimplex::atLowerBound);
+                              }
+                         }
+                    }
+               }
+               keyVariable_[iSet] = iBasic;
+          }
+     }
+     delete [] lower;
+     delete [] solution;
+     delete [] upper;
+     delete [] cost;
+     // make sure matrix is in good shape
+     matrix_->orderMatrix();
+     // create effective rhs
+     delete [] rhsOffset_;
+     rhsOffset_ = new double[numberRows];
+     delete [] next_;
+     next_ = new int[numberColumns+numberSets_+2*longestSet];
+     char * mark = new char[numberColumns];
+     memset(mark, 0, numberColumns);
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++)
+          next_[iColumn] = COIN_INT_MAX;
+     int i;
+     int * keys = new int[numberSets_];
+     for (i = 0; i < numberSets_; i++)
+          keys[i] = COIN_INT_MAX;
+     // set up chains
+     for (i = 0; i < numberColumns; i++) {
+          if (model->getStatus(i) == ClpSimplex::basic)
+               mark[i] = 1;
+          int iSet = backward_[i];
+          if (iSet >= 0) {
+               int iNext = keys[iSet];
+               next_[i] = iNext;
+               keys[iSet] = i;
+          }
+     }
+     for (i = 0; i < numberSets_; i++) {
+          int j;
+          if (getStatus(i) != ClpSimplex::basic) {
+               // make sure fixed if it is
+               if (upper_[i] == lower_[i])
+                    setStatus(i, ClpSimplex::isFixed);
+               // slack not key - choose one with smallest length
+               int smallest = numberRows + 1;
+               int key = -1;
+               j = keys[i];
+               if (j != COIN_INT_MAX) {
+                    while (1) {
+                         if (mark[j] && columnLength[j] < smallest && !gotBasis) {
+                              key = j;
+                              smallest = columnLength[j];
+                         }
+                         if (next_[j] != COIN_INT_MAX) {
+                              j = next_[j];
+                         } else {
+                              // correct end
+                              next_[j] = -(keys[i] + 1);
+                              break;
+                         }
+                    }
+               } else {
+                    next_[i+numberColumns] = -(numberColumns + i + 1);
+               }
+               if (gotBasis)
+                    key = keyVariable_[i];
+               if (key >= 0) {
+                    keyVariable_[i] = key;
+               } else {
+                    // nothing basic - make slack key
+                    //((ClpGubMatrix *)this)->setStatus(i,ClpSimplex::basic);
+                    // fudge to avoid const problem
+                    status_[i] = 1;
+               }
+          } else {
+               // slack key
+               keyVariable_[i] = numberColumns + i;
+               int j;
+               double sol = 0.0;
+               j = keys[i];
+               if (j != COIN_INT_MAX) {
+                    while (1) {
+                         sol += columnSolution[j];
+                         if (next_[j] != COIN_INT_MAX) {
+                              j = next_[j];
+                         } else {
+                              // correct end
+                              next_[j] = -(keys[i] + 1);
+                              break;
+                         }
+                    }
+               } else {
+                    next_[i+numberColumns] = -(numberColumns + i + 1);
+               }
+               if (sol > upper_[i] + tolerance) {
+                    setAbove(i);
+               } else if (sol < lower_[i] - tolerance) {
+                    setBelow(i);
+               } else {
+                    setFeasible(i);
+               }
+          }
+          // Create next_
+          int key = keyVariable_[i];
+          redoSet(model, key, keys[i], i);
+     }
+     delete [] keys;
+     delete [] mark;
+     rhsOffset(model, true);
+}
+// redoes next_ for a set.
+void
+ClpGubMatrix::redoSet(ClpSimplex * model, int newKey, int oldKey, int iSet)
+{
+     int numberColumns = model->numberColumns();
+     int * save = next_ + numberColumns + numberSets_;
+     int number = 0;
+     int stop = -(oldKey + 1);
+     int j = next_[oldKey];
+     while (j != stop) {
+          if (j < 0)
+               j = -j - 1;
+          if (j != newKey)
+               save[number++] = j;
+          j = next_[j];
+     }
+     // and add oldkey
+     if (newKey != oldKey)
+          save[number++] = oldKey;
+     // now do basic
+     int lastMarker = -(newKey + 1);
+     keyVariable_[iSet] = newKey;
+     next_[newKey] = lastMarker;
+     int last = newKey;
+     for ( j = 0; j < number; j++) {
+          int iColumn = save[j];
+          if (iColumn < numberColumns) {
+               if (model->getStatus(iColumn) == ClpSimplex::basic) {
+                    next_[last] = iColumn;
+                    next_[iColumn] = lastMarker;
+                    last = iColumn;
+               }
+          }
+     }
+     // now add in non-basic
+     for ( j = 0; j < number; j++) {
+          int iColumn = save[j];
+          if (iColumn < numberColumns) {
+               if (model->getStatus(iColumn) != ClpSimplex::basic) {
+                    next_[last] = -(iColumn + 1);
+                    next_[iColumn] = lastMarker;
+                    last = iColumn;
+               }
+          }
+     }
+
+}
+/* Returns effective RHS if it is being used.  This is used for long problems
+   or big gub or anywhere where going through full columns is
+   expensive.  This may re-compute */
+double *
+ClpGubMatrix::rhsOffset(ClpSimplex * model, bool forceRefresh, bool
+#ifdef CLP_DEBUG
+                        check
+#endif
+                       )
+{
+     //forceRefresh=true;
+     if (rhsOffset_) {
+#ifdef CLP_DEBUG
+          if (check) {
+               // no need - but check anyway
+               // zero out basic
+               int numberRows = model->numberRows();
+               int numberColumns = model->numberColumns();
+               double * solution = new double [numberColumns];
+               double * rhs = new double[numberRows];
+               CoinMemcpyN(model->solutionRegion(), numberColumns, solution);
+               CoinZeroN(rhs, numberRows);
+               int iRow;
+               for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (model->getColumnStatus(iColumn) == ClpSimplex::basic)
+                         solution[iColumn] = 0.0;
+               }
+               for (int iSet = 0; iSet < numberSets_; iSet++) {
+                    int iColumn = keyVariable_[iSet];
+                    if (iColumn < numberColumns)
+                         solution[iColumn] = 0.0;
+               }
+               times(-1.0, solution, rhs);
+               delete [] solution;
+               const double * columnSolution = model->solutionRegion();
+               // and now subtract out non basic
+               ClpSimplex::Status iStatus;
+               for (int iSet = 0; iSet < numberSets_; iSet++) {
+                    int iColumn = keyVariable_[iSet];
+                    if (iColumn < numberColumns) {
+                         double b = 0.0;
+                         // key is structural - where is slack
+                         iStatus = getStatus(iSet);
+                         assert (iStatus != ClpSimplex::basic);
+                         if (iStatus == ClpSimplex::atLowerBound)
+                              b = lower_[iSet];
+                         else
+                              b = upper_[iSet];
+                         // subtract out others at bounds
+                         if ((gubType_ & 8) == 0) {
+                              int stop = -(iColumn + 1);
+                              int jColumn = next_[iColumn];
+                              // sum all non-basic variables - first skip basic
+                              while(jColumn >= 0)
+                                   jColumn = next_[jColumn];
+                              while(jColumn != stop) {
+                                   assert (jColumn < 0);
+                                   jColumn = -jColumn - 1;
+                                   b -= columnSolution[jColumn];
+                                   jColumn = next_[jColumn];
+                              }
+                         }
+                         // subtract out
+                         ClpPackedMatrix::add(model, rhs, iColumn, -b);
+                    }
+               }
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    if (fabs(rhs[iRow] - rhsOffset_[iRow]) > 1.0e-3)
+                         printf("** bad effective %d - true %g old %g\n", iRow, rhs[iRow], rhsOffset_[iRow]);
+               }
+               delete [] rhs;
+          }
+#endif
+          if (forceRefresh || (refreshFrequency_ && model->numberIterations() >=
+                               lastRefresh_ + refreshFrequency_)) {
+               // zero out basic
+               int numberRows = model->numberRows();
+               int numberColumns = model->numberColumns();
+               double * solution = new double [numberColumns];
+               CoinMemcpyN(model->solutionRegion(), numberColumns, solution);
+               CoinZeroN(rhsOffset_, numberRows);
+               for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (model->getColumnStatus(iColumn) == ClpSimplex::basic)
+                         solution[iColumn] = 0.0;
+               }
+               int iSet;
+               for ( iSet = 0; iSet < numberSets_; iSet++) {
+                    int iColumn = keyVariable_[iSet];
+                    if (iColumn < numberColumns)
+                         solution[iColumn] = 0.0;
+               }
+               times(-1.0, solution, rhsOffset_);
+               delete [] solution;
+               lastRefresh_ = model->numberIterations();
+               const double * columnSolution = model->solutionRegion();
+               // and now subtract out non basic
+               ClpSimplex::Status iStatus;
+               for ( iSet = 0; iSet < numberSets_; iSet++) {
+                    int iColumn = keyVariable_[iSet];
+                    if (iColumn < numberColumns) {
+                         double b = 0.0;
+                         // key is structural - where is slack
+                         iStatus = getStatus(iSet);
+                         assert (iStatus != ClpSimplex::basic);
+                         if (iStatus == ClpSimplex::atLowerBound)
+                              b = lower_[iSet];
+                         else
+                              b = upper_[iSet];
+                         // subtract out others at bounds
+                         if ((gubType_ & 8) == 0) {
+                              int stop = -(iColumn + 1);
+                              int jColumn = next_[iColumn];
+                              // sum all non-basic variables - first skip basic
+                              while(jColumn >= 0)
+                                   jColumn = next_[jColumn];
+                              while(jColumn != stop) {
+                                   assert (jColumn < 0);
+                                   jColumn = -jColumn - 1;
+                                   b -= columnSolution[jColumn];
+                                   jColumn = next_[jColumn];
+                              }
+                         }
+                         // subtract out
+                         if (b)
+                              ClpPackedMatrix::add(model, rhsOffset_, iColumn, -b);
+                    }
+               }
+          }
+     }
+     return rhsOffset_;
+}
+/*
+   update information for a pivot (and effective rhs)
+*/
+int
+ClpGubMatrix::updatePivot(ClpSimplex * model, double oldInValue, double /*oldOutValue*/)
+{
+     int sequenceIn = model->sequenceIn();
+     int sequenceOut = model->sequenceOut();
+     double * solution = model->solutionRegion();
+     int numberColumns = model->numberColumns();
+     int numberRows = model->numberRows();
+     int pivotRow = model->pivotRow();
+     int iSetIn;
+     // Correct sequence in
+     trueSequenceIn_ = sequenceIn;
+     if (sequenceIn < numberColumns) {
+          iSetIn = backward_[sequenceIn];
+     } else if (sequenceIn < numberColumns + numberRows) {
+          iSetIn = -1;
+     } else {
+          iSetIn = gubSlackIn_;
+          trueSequenceIn_ = numberColumns + numberRows + iSetIn;
+     }
+     int iSetOut = -1;
+     trueSequenceOut_ = sequenceOut;
+     if (sequenceOut < numberColumns) {
+          iSetOut = backward_[sequenceOut];
+     } else if (sequenceOut >= numberRows + numberColumns) {
+          assert (pivotRow >= numberRows);
+          int iExtra = pivotRow - numberRows;
+          assert (iExtra >= 0);
+          if (iSetOut < 0)
+               iSetOut = fromIndex_[iExtra];
+          else
+               assert(iSetOut == fromIndex_[iExtra]);
+          trueSequenceOut_ = numberColumns + numberRows + iSetOut;
+     }
+     if (rhsOffset_) {
+          // update effective rhs
+          if (sequenceIn == sequenceOut) {
+               assert (sequenceIn < numberRows + numberColumns); // should be easy to deal with
+               if (sequenceIn < numberColumns)
+                    add(model, rhsOffset_, sequenceIn, oldInValue - solution[sequenceIn]);
+          } else {
+               if (sequenceIn < numberColumns) {
+                    // we need to test if WILL be key
+                    ClpPackedMatrix::add(model, rhsOffset_, sequenceIn, oldInValue);
+                    if (iSetIn >= 0)  {
+                         // old contribution to rhsOffset_
+                         int key = keyVariable_[iSetIn];
+                         if (key < numberColumns) {
+                              double oldB = 0.0;
+                              ClpSimplex::Status iStatus = getStatus(iSetIn);
+                              if (iStatus == ClpSimplex::atLowerBound)
+                                   oldB = lower_[iSetIn];
+                              else
+                                   oldB = upper_[iSetIn];
+                              // subtract out others at bounds
+                              if ((gubType_ & 8) == 0) {
+                                   int stop = -(key + 1);
+                                   int iColumn = next_[key];
+                                   // skip basic
+                                   while (iColumn >= 0)
+                                        iColumn = next_[iColumn];
+                                   // sum all non-key variables
+                                   while(iColumn != stop) {
+                                        assert (iColumn < 0);
+                                        iColumn = -iColumn - 1;
+                                        if (iColumn == sequenceIn)
+                                             oldB -= oldInValue;
+                                        else if ( iColumn != sequenceOut )
+                                             oldB -= solution[iColumn];
+                                        iColumn = next_[iColumn];
+                                   }
+                              }
+                              if (oldB)
+                                   ClpPackedMatrix::add(model, rhsOffset_, key, oldB);
+                         }
+                    }
+               } else if (sequenceIn < numberRows + numberColumns) {
+                    //rhsOffset_[sequenceIn-numberColumns] -= oldInValue;
+               } else {
+#ifdef CLP_DEBUG_PRINT
+                    printf("** in is key slack %d\n", sequenceIn);
+#endif
+                    // old contribution to rhsOffset_
+                    int key = keyVariable_[iSetIn];
+                    if (key < numberColumns) {
+                         double oldB = 0.0;
+                         ClpSimplex::Status iStatus = getStatus(iSetIn);
+                         if (iStatus == ClpSimplex::atLowerBound)
+                              oldB = lower_[iSetIn];
+                         else
+                              oldB = upper_[iSetIn];
+                         // subtract out others at bounds
+                         if ((gubType_ & 8) == 0) {
+                              int stop = -(key + 1);
+                              int iColumn = next_[key];
+                              // skip basic
+                              while (iColumn >= 0)
+                                   iColumn = next_[iColumn];
+                              // sum all non-key variables
+                              while(iColumn != stop) {
+                                   assert (iColumn < 0);
+                                   iColumn = -iColumn - 1;
+                                   if ( iColumn != sequenceOut )
+                                        oldB -= solution[iColumn];
+                                   iColumn = next_[iColumn];
+                              }
+                         }
+                         if (oldB)
+                              ClpPackedMatrix::add(model, rhsOffset_, key, oldB);
+                    }
+               }
+               if (sequenceOut < numberColumns) {
+                    ClpPackedMatrix::add(model, rhsOffset_, sequenceOut, -solution[sequenceOut]);
+                    if (iSetOut >= 0) {
+                         // old contribution to rhsOffset_
+                         int key = keyVariable_[iSetOut];
+                         if (key < numberColumns && iSetIn != iSetOut) {
+                              double oldB = 0.0;
+                              ClpSimplex::Status iStatus = getStatus(iSetOut);
+                              if (iStatus == ClpSimplex::atLowerBound)
+                                   oldB = lower_[iSetOut];
+                              else
+                                   oldB = upper_[iSetOut];
+                              // subtract out others at bounds
+                              if ((gubType_ & 8) == 0) {
+                                   int stop = -(key + 1);
+                                   int iColumn = next_[key];
+                                   // skip basic
+                                   while (iColumn >= 0)
+                                        iColumn = next_[iColumn];
+                                   // sum all non-key variables
+                                   while(iColumn != stop) {
+                                        assert (iColumn < 0);
+                                        iColumn = -iColumn - 1;
+                                        if (iColumn == sequenceIn)
+                                             oldB -= oldInValue;
+                                        else if ( iColumn != sequenceOut )
+                                             oldB -= solution[iColumn];
+                                        iColumn = next_[iColumn];
+                                   }
+                              }
+                              if (oldB)
+                                   ClpPackedMatrix::add(model, rhsOffset_, key, oldB);
+                         }
+                    }
+               } else if (sequenceOut < numberRows + numberColumns) {
+                    //rhsOffset_[sequenceOut-numberColumns] -= -solution[sequenceOut];
+               } else {
+#ifdef CLP_DEBUG_PRINT
+                    printf("** out is key slack %d\n", sequenceOut);
+#endif
+                    assert (pivotRow >= numberRows);
+               }
+          }
+     }
+     int * pivotVariable = model->pivotVariable();
+     // may need to deal with key
+     // Also need coding to mark/allow key slack entering
+     if (pivotRow >= numberRows) {
+          assert (sequenceOut >= numberRows + numberColumns || sequenceOut == keyVariable_[iSetOut]);
+#ifdef CLP_DEBUG_PRINT
+          if (sequenceIn >= numberRows + numberColumns)
+               printf("key slack %d in, set out %d\n", gubSlackIn_, iSetOut);
+          printf("** danger - key out for set %d in %d (set %d)\n", iSetOut, sequenceIn,
+                 iSetIn);
+#endif
+          // if slack out mark correctly
+          if (sequenceOut >= numberRows + numberColumns) {
+               double value = model->valueOut();
+               if (value == upper_[iSetOut]) {
+                    setStatus(iSetOut, ClpSimplex::atUpperBound);
+               } else if (value == lower_[iSetOut]) {
+                    setStatus(iSetOut, ClpSimplex::atLowerBound);
+               } else {
+                    if (fabs(value - upper_[iSetOut]) <
+                              fabs(value - lower_[iSetOut])) {
+                         setStatus(iSetOut, ClpSimplex::atUpperBound);
+                    } else {
+                         setStatus(iSetOut, ClpSimplex::atLowerBound);
+                    }
+               }
+               if (upper_[iSetOut] == lower_[iSetOut])
+                    setStatus(iSetOut, ClpSimplex::isFixed);
+               setFeasible(iSetOut);
+          }
+          if (iSetOut == iSetIn) {
+               // key swap
+               int key;
+               if (sequenceIn >= numberRows + numberColumns) {
+                    key = numberColumns + iSetIn;
+                    setStatus(iSetIn, ClpSimplex::basic);
+               } else {
+                    key = sequenceIn;
+               }
+               redoSet(model, key, keyVariable_[iSetIn], iSetIn);
+          } else {
+               // key was chosen
+               assert (possiblePivotKey_ >= 0 && possiblePivotKey_ < numberRows);
+               int key = pivotVariable[possiblePivotKey_];
+               // and set incoming here
+               if (sequenceIn >= numberRows + numberColumns) {
+                    // slack in - so use old key
+                    sequenceIn = keyVariable_[iSetIn];
+                    model->setStatus(sequenceIn, ClpSimplex::basic);
+                    setStatus(iSetIn, ClpSimplex::basic);
+                    redoSet(model, iSetIn + numberColumns, keyVariable_[iSetIn], iSetIn);
+               }
+               //? do not do if iSetIn<0 ? as will be done later
+               pivotVariable[possiblePivotKey_] = sequenceIn;
+               if (sequenceIn < numberColumns)
+                    backToPivotRow_[sequenceIn] = possiblePivotKey_;
+               redoSet(model, key, keyVariable_[iSetOut], iSetOut);
+          }
+     } else {
+          if (sequenceOut < numberColumns) {
+               if (iSetIn >= 0 && iSetOut == iSetIn) {
+                    // key not out - only problem is if slack in
+                    int key;
+                    if (sequenceIn >= numberRows + numberColumns) {
+                         key = numberColumns + iSetIn;
+                         setStatus(iSetIn, ClpSimplex::basic);
+                         assert (pivotRow < numberRows);
+                         // must swap with current key
+                         int key = keyVariable_[iSetIn];
+                         model->setStatus(key, ClpSimplex::basic);
+                         pivotVariable[pivotRow] = key;
+                         backToPivotRow_[key] = pivotRow;
+                    } else {
+                         key = keyVariable_[iSetIn];
+                    }
+                    redoSet(model, key, keyVariable_[iSetIn], iSetIn);
+               } else if (iSetOut >= 0) {
+                    // just redo set
+                    int key = keyVariable_[iSetOut];;
+                    redoSet(model, key, keyVariable_[iSetOut], iSetOut);
+               }
+          }
+     }
+     if (iSetIn >= 0 && iSetIn != iSetOut) {
+          int key = keyVariable_[iSetIn];
+          if (sequenceIn == numberColumns + 2 * numberRows) {
+               // key slack in
+               assert (pivotRow < numberRows);
+               // must swap with current key
+               model->setStatus(key, ClpSimplex::basic);
+               pivotVariable[pivotRow] = key;
+               backToPivotRow_[key] = pivotRow;
+               setStatus(iSetIn, ClpSimplex::basic);
+               key = iSetIn + numberColumns;
+          }
+          // redo set to allow for new one
+          redoSet(model, key, keyVariable_[iSetIn], iSetIn);
+     }
+     // update pivot
+     if (sequenceIn < numberColumns) {
+          if (pivotRow < numberRows) {
+               backToPivotRow_[sequenceIn] = pivotRow;
+          } else {
+               if (possiblePivotKey_ >= 0) {
+                    assert (possiblePivotKey_ < numberRows);
+                    backToPivotRow_[sequenceIn] = possiblePivotKey_;
+                    pivotVariable[possiblePivotKey_] = sequenceIn;
+               }
+          }
+     } else if (sequenceIn >= numberRows + numberColumns) {
+          // key in - something should have been done before
+          int key = keyVariable_[iSetIn];
+          assert (key == numberColumns + iSetIn);
+          //pivotVariable[pivotRow]=key;
+          //backToPivotRow_[key]=pivotRow;
+          //model->setStatus(key,ClpSimplex::basic);
+          //key=numberColumns+iSetIn;
+          setStatus(iSetIn, ClpSimplex::basic);
+          redoSet(model, key, keyVariable_[iSetIn], iSetIn);
+     }
+#ifdef CLP_DEBUG
+     {
+          char * xx = new char[numberColumns+numberRows];
+          memset(xx, 0, numberRows + numberColumns);
+          for (int i = 0; i < numberRows; i++) {
+               int iPivot = pivotVariable[i];
+               assert (iPivot < numberRows + numberColumns);
+               assert (!xx[iPivot]);
+               xx[iPivot] = 1;
+               if (iPivot < numberColumns) {
+                    int iBack = backToPivotRow_[iPivot];
+                    assert (i == iBack);
+               }
+          }
+          delete [] xx;
+     }
+#endif
+     if (rhsOffset_) {
+          // update effective rhs
+          if (sequenceIn != sequenceOut) {
+               if (sequenceIn < numberColumns) {
+                    if (iSetIn >= 0) {
+                         // new contribution to rhsOffset_
+                         int key = keyVariable_[iSetIn];
+                         if (key < numberColumns) {
+                              double newB = 0.0;
+                              ClpSimplex::Status iStatus = getStatus(iSetIn);
+                              if (iStatus == ClpSimplex::atLowerBound)
+                                   newB = lower_[iSetIn];
+                              else
+                                   newB = upper_[iSetIn];
+                              // subtract out others at bounds
+                              if ((gubType_ & 8) == 0) {
+                                   int stop = -(key + 1);
+                                   int iColumn = next_[key];
+                                   // skip basic
+                                   while (iColumn >= 0)
+                                        iColumn = next_[iColumn];
+                                   // sum all non-key variables
+                                   while(iColumn != stop) {
+                                        assert (iColumn < 0);
+                                        iColumn = -iColumn - 1;
+                                        newB -= solution[iColumn];
+                                        iColumn = next_[iColumn];
+                                   }
+                              }
+                              if (newB)
+                                   ClpPackedMatrix::add(model, rhsOffset_, key, -newB);
+                         }
+                    }
+               }
+               if (iSetOut >= 0) {
+                    // new contribution to rhsOffset_
+                    int key = keyVariable_[iSetOut];
+                    if (key < numberColumns && iSetIn != iSetOut) {
+                         double newB = 0.0;
+                         ClpSimplex::Status iStatus = getStatus(iSetOut);
+                         if (iStatus == ClpSimplex::atLowerBound)
+                              newB = lower_[iSetOut];
+                         else
+                              newB = upper_[iSetOut];
+                         // subtract out others at bounds
+                         if ((gubType_ & 8) == 0) {
+                              int stop = -(key + 1);
+                              int iColumn = next_[key];
+                              // skip basic
+                              while (iColumn >= 0)
+                                   iColumn = next_[iColumn];
+                              // sum all non-key variables
+                              while(iColumn != stop) {
+                                   assert (iColumn < 0);
+                                   iColumn = -iColumn - 1;
+                                   newB -= solution[iColumn];
+                                   iColumn = next_[iColumn];
+                              }
+                         }
+                         if (newB)
+                              ClpPackedMatrix::add(model, rhsOffset_, key, -newB);
+                    }
+               }
+          }
+     }
+#ifdef CLP_DEBUG
+     // debug
+     {
+          int i;
+          char * xxxx = new char[numberColumns];
+          memset(xxxx, 0, numberColumns);
+          for (i = 0; i < numberRows; i++) {
+               int iPivot = pivotVariable[i];
+               assert (model->getStatus(iPivot) == ClpSimplex::basic);
+               if (iPivot < numberColumns && backward_[iPivot] >= 0)
+                    xxxx[iPivot] = 1;
+          }
+          double primalTolerance = model->primalTolerance();
+          for (i = 0; i < numberSets_; i++) {
+               int key = keyVariable_[i];
+               double value = 0.0;
+               // sum over all except key
+               int iColumn = next_[key];
+               // sum all non-key variables
+               int k = 0;
+               int stop = -(key + 1);
+               while (iColumn != stop) {
+                    if (iColumn < 0)
+                         iColumn = -iColumn - 1;
+                    value += solution[iColumn];
+                    k++;
+                    assert (k < 100);
+                    assert (backward_[iColumn] == i);
+                    iColumn = next_[iColumn];
+               }
+               iColumn = next_[key];
+               if (key < numberColumns) {
+                    // feasibility will be done later
+                    assert (getStatus(i) != ClpSimplex::basic);
+                    double sol;
+                    if (getStatus(i) == ClpSimplex::atUpperBound)
+                         sol = upper_[i] - value;
+                    else
+                         sol = lower_[i] - value;
+                    //printf("xx Value of key structural %d for set %d is %g - cost %g\n",key,i,sol,
+                    //     cost[key]);
+                    //if (fabs(sol-solution[key])>1.0e-3)
+                    //printf("** stored value was %g\n",solution[key]);
+               } else {
+                    // slack is key
+                    double infeasibility = 0.0;
+                    if (value > upper_[i] + primalTolerance) {
+                         infeasibility = value - upper_[i] - primalTolerance;
+                         //setAbove(i);
+                    } else if (value < lower_[i] - primalTolerance) {
+                         infeasibility = lower_[i] - value - primalTolerance ;
+                         //setBelow(i);
+                    } else {
+                         //setFeasible(i);
+                    }
+                    //printf("xx Value of key slack for set %d is %g\n",i,value);
+               }
+               while (iColumn >= 0) {
+                    assert (xxxx[iColumn]);
+                    xxxx[iColumn] = 0;
+                    iColumn = next_[iColumn];
+               }
+          }
+          for (i = 0; i < numberColumns; i++) {
+               if (i < numberColumns && backward_[i] >= 0) {
+                    assert (!xxxx[i] || i == keyVariable_[backward_[i]]);
+               }
+          }
+          delete [] xxxx;
+     }
+#endif
+     return 0;
+}
+// Switches off dj checking each factorization (for BIG models)
+void
+ClpGubMatrix::switchOffCheck()
+{
+     noCheck_ = 0;
+     infeasibilityWeight_ = 0.0;
+}
+// Correct sequence in and out to give true value
+void
+ClpGubMatrix::correctSequence(const ClpSimplex * /*model*/, int & sequenceIn, int & sequenceOut)
+{
+     if (sequenceIn != -999) {
+          sequenceIn = trueSequenceIn_;
+          sequenceOut = trueSequenceOut_;
+     }
+}
diff --git a/cbits/coin/ClpGubMatrix.hpp b/cbits/coin/ClpGubMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpGubMatrix.hpp
@@ -0,0 +1,358 @@
+/* $Id: ClpGubMatrix.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpGubMatrix_H
+#define ClpGubMatrix_H
+
+
+#include "CoinPragma.hpp"
+
+#include "ClpPackedMatrix.hpp"
+class ClpSimplex;
+/** This implements Gub rows plus a ClpPackedMatrix.
+
+    There will be a version using ClpPlusMinusOne matrix but
+    there is no point doing one with ClpNetworkMatrix (although
+    an embedded network is attractive).
+
+*/
+
+class ClpGubMatrix : public ClpPackedMatrix {
+
+public:
+     /**@name Main functions provided */
+     //@{
+     /** Returns a new matrix in reverse order without gaps (GUB wants NULL) */
+     virtual ClpMatrixBase * reverseOrderedCopy() const;
+     /// Returns number of elements in column part of basis
+     virtual CoinBigIndex countBasis(const int * whichColumn,
+                                     int & numberColumnBasic);
+     /// Fills in column part of basis
+     virtual void fillBasis(ClpSimplex * model,
+                            const int * whichColumn,
+                            int & numberColumnBasic,
+                            int * row, int * start,
+                            int * rowCount, int * columnCount,
+                            CoinFactorizationDouble * element);
+     /** Unpacks a column into an CoinIndexedvector
+      */
+     virtual void unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                         int column) const ;
+     /** Unpacks a column into an CoinIndexedvector
+      ** in packed foramt
+         Note that model is NOT const.  Bounds and objective could
+         be modified if doing column generation (just for this variable) */
+     virtual void unpackPacked(ClpSimplex * model,
+                               CoinIndexedVector * rowArray,
+                               int column) const;
+     /** Adds multiple of a column into an CoinIndexedvector
+         You can use quickAdd to add to vector */
+     virtual void add(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                      int column, double multiplier) const ;
+     /** Adds multiple of a column into an array */
+     virtual void add(const ClpSimplex * model, double * array,
+                      int column, double multiplier) const;
+     /// Partial pricing
+     virtual void partialPricing(ClpSimplex * model, double start, double end,
+                                 int & bestSequence, int & numberWanted);
+     /// Returns number of hidden rows e.g. gub
+     virtual int hiddenRows() const;
+     //@}
+
+     /**@name Matrix times vector methods */
+     //@{
+
+     using ClpPackedMatrix::transposeTimes ;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Can use y as temporary array (will be empty at end)
+     Note - If x packed mode - then z packed mode
+     Squashes small elements and knows about ClpSimplex */
+     virtual void transposeTimes(const ClpSimplex * model, double scalar,
+                                 const CoinIndexedVector * x,
+                                 CoinIndexedVector * y,
+                                 CoinIndexedVector * z) const;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Can use y as temporary array (will be empty at end)
+     Note - If x packed mode - then z packed mode
+     Squashes small elements and knows about ClpSimplex.
+     This version uses row copy*/
+     virtual void transposeTimesByRow(const ClpSimplex * model, double scalar,
+                                      const CoinIndexedVector * x,
+                                      CoinIndexedVector * y,
+                                      CoinIndexedVector * z) const;
+     /** Return <code>x *A</code> in <code>z</code> but
+     just for indices in y.
+     Note - z always packed mode */
+     virtual void subsetTransposeTimes(const ClpSimplex * model,
+                                       const CoinIndexedVector * x,
+                                       const CoinIndexedVector * y,
+                                       CoinIndexedVector * z) const;
+     /** expands an updated column to allow for extra rows which the main
+         solver does not know about and returns number added if mode 0.
+         If mode 1 deletes extra entries
+
+         This active in Gub
+     */
+     virtual int extendUpdated(ClpSimplex * model, CoinIndexedVector * update, int mode);
+     /**
+        mode=0  - Set up before "update" and "times" for primal solution using extended rows
+        mode=1  - Cleanup primal solution after "times" using extended rows.
+        mode=2  - Check (or report on) primal infeasibilities
+     */
+     virtual void primalExpanded(ClpSimplex * model, int mode);
+     /**
+         mode=0  - Set up before "updateTranspose" and "transposeTimes" for duals using extended
+                   updates array (and may use other if dual values pass)
+         mode=1  - Update dual solution after "transposeTimes" using extended rows.
+         mode=2  - Compute all djs and compute key dual infeasibilities
+         mode=3  - Report on key dual infeasibilities
+         mode=4  - Modify before updateTranspose in partial pricing
+     */
+     virtual void dualExpanded(ClpSimplex * model, CoinIndexedVector * array,
+                               double * other, int mode);
+     /**
+         mode=0  - Create list of non-key basics in pivotVariable_ using
+                   number as numberBasic in and out
+         mode=1  - Set all key variables as basic
+         mode=2  - return number extra rows needed, number gives maximum number basic
+         mode=3  - before replaceColumn
+         mode=4  - return 1 if can do primal, 2 if dual, 3 if both
+         mode=5  - save any status stuff (when in good state)
+         mode=6  - restore status stuff
+         mode=7  - flag given variable (normally sequenceIn)
+         mode=8  - unflag all variables
+         mode=9  - synchronize costs
+         mode=10  - return 1 if there may be changing bounds on variable (column generation)
+         mode=11  - make sure set is clean (used when a variable rejected - but not flagged)
+         mode=12  - after factorize but before permute stuff
+         mode=13  - at end of simplex to delete stuff
+     */
+     virtual int generalExpanded(ClpSimplex * model, int mode, int & number);
+     /**
+        update information for a pivot (and effective rhs)
+     */
+     virtual int updatePivot(ClpSimplex * model, double oldInValue, double oldOutValue);
+     /// Sets up an effective RHS and does gub crash if needed
+     virtual void useEffectiveRhs(ClpSimplex * model, bool cheapest = true);
+     /** Returns effective RHS offset if it is being used.  This is used for long problems
+         or big gub or anywhere where going through full columns is
+         expensive.  This may re-compute */
+     virtual double * rhsOffset(ClpSimplex * model, bool forceRefresh = false,
+                                bool check = false);
+     /** This is local to Gub to allow synchronization:
+         mode=0 when status of basis is good
+         mode=1 when variable is flagged
+         mode=2 when all variables unflagged (returns number flagged)
+         mode=3 just reset costs (primal)
+         mode=4 correct number of dual infeasibilities
+         mode=5 return 4 if time to re-factorize
+         mode=6  - return 1 if there may be changing bounds on variable (column generation)
+         mode=7  - do extra restores for column generation
+         mode=8  - make sure set is clean
+         mode=9  - adjust lower, upper on set by incoming
+     */
+     virtual int synchronize(ClpSimplex * model, int mode);
+     /// Correct sequence in and out to give true value
+     virtual void correctSequence(const ClpSimplex * model, int & sequenceIn, int & sequenceOut) ;
+     //@}
+
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpGubMatrix();
+     /** Destructor */
+     virtual ~ClpGubMatrix();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpGubMatrix(const ClpGubMatrix&);
+     /** The copy constructor from an CoinPackedMatrix. */
+     ClpGubMatrix(const CoinPackedMatrix&);
+     /** Subset constructor (without gaps).  Duplicates are allowed
+         and order is as given */
+     ClpGubMatrix (const ClpGubMatrix & wholeModel,
+                   int numberRows, const int * whichRows,
+                   int numberColumns, const int * whichColumns);
+     ClpGubMatrix (const CoinPackedMatrix & wholeModel,
+                   int numberRows, const int * whichRows,
+                   int numberColumns, const int * whichColumns);
+
+     /** This takes over ownership (for space reasons) */
+     ClpGubMatrix(CoinPackedMatrix * matrix);
+
+     /** This takes over ownership (for space reasons) and is the
+         real constructor*/
+     ClpGubMatrix(ClpPackedMatrix * matrix, int numberSets,
+                  const int * start, const int * end,
+                  const double * lower, const double * upper,
+                  const unsigned char * status = NULL);
+
+     ClpGubMatrix& operator=(const ClpGubMatrix&);
+     /// Clone
+     virtual ClpMatrixBase * clone() const ;
+     /** Subset clone (without gaps).  Duplicates are allowed
+         and order is as given */
+     virtual ClpMatrixBase * subsetClone (
+          int numberRows, const int * whichRows,
+          int numberColumns, const int * whichColumns) const ;
+     /** redoes next_ for a set.  */
+     void redoSet(ClpSimplex * model, int newKey, int oldKey, int iSet);
+     //@}
+     /**@name gets and sets */
+     //@{
+     /// Status
+     inline ClpSimplex::Status getStatus(int sequence) const {
+          return static_cast<ClpSimplex::Status> (status_[sequence] & 7);
+     }
+     inline void setStatus(int sequence, ClpSimplex::Status status) {
+          unsigned char & st_byte = status_[sequence];
+          st_byte = static_cast<unsigned char>(st_byte & ~7);
+          st_byte = static_cast<unsigned char>(st_byte | status);
+     }
+     /// To flag a variable
+     inline void setFlagged( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 64);
+     }
+     inline void clearFlagged( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~64);
+     }
+     inline bool flagged(int sequence) const {
+          return ((status_[sequence] & 64) != 0);
+     }
+     /// To say key is above ub
+     inline void setAbove( int sequence) {
+          unsigned char iStat = status_[sequence];
+          iStat = static_cast<unsigned char>(iStat & ~24);
+          status_[sequence] = static_cast<unsigned char>(iStat | 16);
+     }
+     /// To say key is feasible
+     inline void setFeasible( int sequence) {
+          unsigned char iStat = status_[sequence];
+          iStat = static_cast<unsigned char>(iStat & ~24);
+          status_[sequence] = static_cast<unsigned char>(iStat | 8);
+     }
+     /// To say key is below lb
+     inline void setBelow( int sequence) {
+          unsigned char iStat = status_[sequence];
+          iStat = static_cast<unsigned char>(iStat & ~24);
+          status_[sequence] = iStat;
+     }
+     inline double weight( int sequence) const {
+          int iStat = status_[sequence] & 31;
+          iStat = iStat >> 3;
+          return static_cast<double> (iStat - 1);
+     }
+     /// Starts
+     inline int * start() const {
+          return start_;
+     }
+     /// End
+     inline int * end() const {
+          return end_;
+     }
+     /// Lower bounds on sets
+     inline double * lower() const {
+          return lower_;
+     }
+     /// Upper bounds on sets
+     inline double * upper() const {
+          return upper_;
+     }
+     /// Key variable of set
+     inline int * keyVariable() const {
+          return keyVariable_;
+     }
+     /// Backward pointer to set number
+     inline int * backward() const {
+          return backward_;
+     }
+     /// Number of sets (gub rows)
+     inline int numberSets() const {
+          return numberSets_;
+     }
+     /// Switches off dj checking each factorization (for BIG models)
+     void switchOffCheck();
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Sum of dual infeasibilities
+     double sumDualInfeasibilities_;
+     /// Sum of primal infeasibilities
+     double sumPrimalInfeasibilities_;
+     /// Sum of Dual infeasibilities using tolerance based on error in duals
+     double sumOfRelaxedDualInfeasibilities_;
+     /// Sum of Primal infeasibilities using tolerance based on error in primals
+     double sumOfRelaxedPrimalInfeasibilities_;
+     /// Infeasibility weight when last full pass done
+     double infeasibilityWeight_;
+     /// Starts
+     int * start_;
+     /// End
+     int * end_;
+     /// Lower bounds on sets
+     double * lower_;
+     /// Upper bounds on sets
+     double * upper_;
+     /// Status of slacks
+     mutable unsigned char * status_;
+     /// Saved status of slacks
+     unsigned char * saveStatus_;
+     /// Saved key variables
+     int * savedKeyVariable_;
+     /// Backward pointer to set number
+     int * backward_;
+     /// Backward pointer to pivot row !!!
+     int * backToPivotRow_;
+     /// Change in costs for keys
+     double * changeCost_;
+     /// Key variable of set
+     mutable int * keyVariable_;
+     /** Next basic variable in set - starts at key and end with -(set+1).
+         Now changes to -(nonbasic+1).
+         next_ has extra space for 2* longest set */
+     mutable int * next_;
+     /// Backward pointer to index in CoinIndexedVector
+     int * toIndex_;
+     // Reverse pointer from index to set
+     int * fromIndex_;
+     /// Pointer back to model
+     ClpSimplex * model_;
+     /// Number of dual infeasibilities
+     int numberDualInfeasibilities_;
+     /// Number of primal infeasibilities
+     int numberPrimalInfeasibilities_;
+     /** If pricing will declare victory (i.e. no check every factorization).
+         -1 - always check
+         0  - don't check
+         1  - in don't check mode but looks optimal
+     */
+     int noCheck_;
+     /// Number of sets (gub rows)
+     int numberSets_;
+     /// Number in vector without gub extension
+     int saveNumber_;
+     /// Pivot row of possible next key
+     int possiblePivotKey_;
+     /// Gub slack in (set number or -1)
+     int gubSlackIn_;
+     /// First gub variables (same as start_[0] at present)
+     int firstGub_;
+     /// last gub variable (same as end_[numberSets_-1] at present)
+     int lastGub_;
+     /** type of gub - 0 not contiguous, 1 contiguous
+         add 8 bit to say no ubs on individual variables */
+     int gubType_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpHelperFunctions.cpp b/cbits/coin/ClpHelperFunctions.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpHelperFunctions.cpp
@@ -0,0 +1,273 @@
+/* $Id: ClpHelperFunctions.cpp 1817 2011-11-03 09:26:23Z forrest $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*
+    Note (JJF) I have added some operations on arrays even though they may
+    duplicate CoinDenseVector.  I think the use of templates was a mistake
+    as I don't think inline generic code can take as much advantage of
+    parallelism or machine architectures or memory hierarchies.
+
+*/
+#include <cfloat>
+#include <cstdlib>
+#include <cmath>
+#include "CoinHelperFunctions.hpp"
+#include "CoinTypes.hpp"
+
+double
+maximumAbsElement(const double * region, int size)
+{
+     int i;
+     double maxValue = 0.0;
+     for (i = 0; i < size; i++)
+          maxValue = CoinMax(maxValue, fabs(region[i]));
+     return maxValue;
+}
+void
+setElements(double * region, int size, double value)
+{
+     int i;
+     for (i = 0; i < size; i++)
+          region[i] = value;
+}
+void
+multiplyAdd(const double * region1, int size, double multiplier1,
+            double * region2, double multiplier2)
+{
+     int i;
+     if (multiplier1 == 1.0) {
+          if (multiplier2 == 1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = region1[i] + region2[i];
+          } else if (multiplier2 == -1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = region1[i] - region2[i];
+          } else if (multiplier2 == 0.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = region1[i] ;
+          } else {
+               for (i = 0; i < size; i++)
+                    region2[i] = region1[i] + multiplier2 * region2[i];
+          }
+     } else if (multiplier1 == -1.0) {
+          if (multiplier2 == 1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = -region1[i] + region2[i];
+          } else if (multiplier2 == -1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = -region1[i] - region2[i];
+          } else if (multiplier2 == 0.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = -region1[i] ;
+          } else {
+               for (i = 0; i < size; i++)
+                    region2[i] = -region1[i] + multiplier2 * region2[i];
+          }
+     } else if (multiplier1 == 0.0) {
+          if (multiplier2 == 1.0) {
+               // nothing to do
+          } else if (multiplier2 == -1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] =  -region2[i];
+          } else if (multiplier2 == 0.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] =  0.0;
+          } else {
+               for (i = 0; i < size; i++)
+                    region2[i] =  multiplier2 * region2[i];
+          }
+     } else {
+          if (multiplier2 == 1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = multiplier1 * region1[i] + region2[i];
+          } else if (multiplier2 == -1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = multiplier1 * region1[i] - region2[i];
+          } else if (multiplier2 == 0.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = multiplier1 * region1[i] ;
+          } else {
+               for (i = 0; i < size; i++)
+                    region2[i] = multiplier1 * region1[i] + multiplier2 * region2[i];
+          }
+     }
+}
+double
+innerProduct(const double * region1, int size, const double * region2)
+{
+     int i;
+     double value = 0.0;
+     for (i = 0; i < size; i++)
+          value += region1[i] * region2[i];
+     return value;
+}
+void
+getNorms(const double * region, int size, double & norm1, double & norm2)
+{
+     norm1 = 0.0;
+     norm2 = 0.0;
+     int i;
+     for (i = 0; i < size; i++) {
+          norm2 += region[i] * region[i];
+          norm1 = CoinMax(norm1, fabs(region[i]));
+     }
+}
+#ifndef NDEBUG
+#include "ClpModel.hpp"
+#include "ClpMessage.hpp"
+ClpModel * clpTraceModel=NULL; // Set to trap messages
+void ClpTracePrint(std::string fileName, std::string message, int lineNumber)
+{
+  if (!clpTraceModel) {
+    std::cout<<fileName<<":"<<lineNumber<<" : \'"
+	     <<message<<"\' failed."<<std::endl;	
+  } else {
+    char line[1000];
+    sprintf(line,"%s: %d : \'%s\' failed.",fileName.c_str(),lineNumber,message.c_str());
+    clpTraceModel->messageHandler()->message(CLP_GENERAL_WARNING, clpTraceModel->messages())
+      << line
+      << CoinMessageEol;
+  }
+}
+#endif
+#if COIN_LONG_WORK
+// For long double versions
+CoinWorkDouble
+maximumAbsElement(const CoinWorkDouble * region, int size)
+{
+     int i;
+     CoinWorkDouble maxValue = 0.0;
+     for (i = 0; i < size; i++)
+          maxValue = CoinMax(maxValue, CoinAbs(region[i]));
+     return maxValue;
+}
+void
+setElements(CoinWorkDouble * region, int size, CoinWorkDouble value)
+{
+     int i;
+     for (i = 0; i < size; i++)
+          region[i] = value;
+}
+void
+multiplyAdd(const CoinWorkDouble * region1, int size, CoinWorkDouble multiplier1,
+            CoinWorkDouble * region2, CoinWorkDouble multiplier2)
+{
+     int i;
+     if (multiplier1 == 1.0) {
+          if (multiplier2 == 1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = region1[i] + region2[i];
+          } else if (multiplier2 == -1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = region1[i] - region2[i];
+          } else if (multiplier2 == 0.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = region1[i] ;
+          } else {
+               for (i = 0; i < size; i++)
+                    region2[i] = region1[i] + multiplier2 * region2[i];
+          }
+     } else if (multiplier1 == -1.0) {
+          if (multiplier2 == 1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = -region1[i] + region2[i];
+          } else if (multiplier2 == -1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = -region1[i] - region2[i];
+          } else if (multiplier2 == 0.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = -region1[i] ;
+          } else {
+               for (i = 0; i < size; i++)
+                    region2[i] = -region1[i] + multiplier2 * region2[i];
+          }
+     } else if (multiplier1 == 0.0) {
+          if (multiplier2 == 1.0) {
+               // nothing to do
+          } else if (multiplier2 == -1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] =  -region2[i];
+          } else if (multiplier2 == 0.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] =  0.0;
+          } else {
+               for (i = 0; i < size; i++)
+                    region2[i] =  multiplier2 * region2[i];
+          }
+     } else {
+          if (multiplier2 == 1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = multiplier1 * region1[i] + region2[i];
+          } else if (multiplier2 == -1.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = multiplier1 * region1[i] - region2[i];
+          } else if (multiplier2 == 0.0) {
+               for (i = 0; i < size; i++)
+                    region2[i] = multiplier1 * region1[i] ;
+          } else {
+               for (i = 0; i < size; i++)
+                    region2[i] = multiplier1 * region1[i] + multiplier2 * region2[i];
+          }
+     }
+}
+CoinWorkDouble
+innerProduct(const CoinWorkDouble * region1, int size, const CoinWorkDouble * region2)
+{
+     int i;
+     CoinWorkDouble value = 0.0;
+     for (i = 0; i < size; i++)
+          value += region1[i] * region2[i];
+     return value;
+}
+void
+getNorms(const CoinWorkDouble * region, int size, CoinWorkDouble & norm1, CoinWorkDouble & norm2)
+{
+     norm1 = 0.0;
+     norm2 = 0.0;
+     int i;
+     for (i = 0; i < size; i++) {
+          norm2 += region[i] * region[i];
+          norm1 = CoinMax(norm1, CoinAbs(region[i]));
+     }
+}
+#endif
+#ifdef DEBUG_MEMORY
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef void (*NEW_HANDLER)();
+static NEW_HANDLER new_handler;                        // function to call if `new' fails (cf. ARM p. 281)
+
+// Allocate storage.
+void *
+operator new(size_t size)
+{
+     void * p;
+     for (;;) {
+          p = malloc(size);
+          if      (p)           break;        // success
+          else if (new_handler) new_handler();   // failure - try again (allow user to release some storage first)
+          else                  break;        // failure - no retry
+     }
+     if (size > 1000000)
+          printf("Allocating memory of size %d\n", size);
+     return p;
+}
+
+// Deallocate storage.
+void
+operator delete(void *p)
+{
+     free(p);
+     return;
+}
+void
+operator delete [] (void *p)
+{
+     free(p);
+     return;
+}
+#endif
diff --git a/cbits/coin/ClpHelperFunctions.hpp b/cbits/coin/ClpHelperFunctions.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpHelperFunctions.hpp
@@ -0,0 +1,293 @@
+/* $Id: ClpHelperFunctions.hpp 1817 2011-11-03 09:26:23Z forrest $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpHelperFunctions_H
+#define ClpHelperFunctions_H
+
+#include "ClpConfig.h"
+#ifdef HAVE_CMATH
+# include <cmath>
+#else
+# ifdef HAVE_MATH_H
+#  include <math.h>
+# else
+#  error "don't have header file for math"
+# endif
+#endif
+
+/**
+    Note (JJF) I have added some operations on arrays even though they may
+    duplicate CoinDenseVector.  I think the use of templates was a mistake
+    as I don't think inline generic code can take as much advantage of
+    parallelism or machine architectures or memory hierarchies.
+
+*/
+
+double maximumAbsElement(const double * region, int size);
+void setElements(double * region, int size, double value);
+void multiplyAdd(const double * region1, int size, double multiplier1,
+                 double * region2, double multiplier2);
+double innerProduct(const double * region1, int size, const double * region2);
+void getNorms(const double * region, int size, double & norm1, double & norm2);
+#if COIN_LONG_WORK
+// For long double versions
+CoinWorkDouble maximumAbsElement(const CoinWorkDouble * region, int size);
+void setElements(CoinWorkDouble * region, int size, CoinWorkDouble value);
+void multiplyAdd(const CoinWorkDouble * region1, int size, CoinWorkDouble multiplier1,
+                 CoinWorkDouble * region2, CoinWorkDouble multiplier2);
+CoinWorkDouble innerProduct(const CoinWorkDouble * region1, int size, const CoinWorkDouble * region2);
+void getNorms(const CoinWorkDouble * region, int size, CoinWorkDouble & norm1, CoinWorkDouble & norm2);
+inline void
+CoinMemcpyN(const double * from, const int size, CoinWorkDouble * to)
+{
+     for (int i = 0; i < size; i++)
+          to[i] = from[i];
+}
+inline void
+CoinMemcpyN(const CoinWorkDouble * from, const int size, double * to)
+{
+     for (int i = 0; i < size; i++)
+          to[i] = static_cast<double>(from[i]);
+}
+inline CoinWorkDouble
+CoinMax(const CoinWorkDouble x1, const double x2)
+{
+     return (x1 > x2) ? x1 : x2;
+}
+inline CoinWorkDouble
+CoinMax(double x1, const CoinWorkDouble x2)
+{
+     return (x1 > x2) ? x1 : x2;
+}
+inline CoinWorkDouble
+CoinMin(const CoinWorkDouble x1, const double x2)
+{
+     return (x1 < x2) ? x1 : x2;
+}
+inline CoinWorkDouble
+CoinMin(double x1, const CoinWorkDouble x2)
+{
+     return (x1 < x2) ? x1 : x2;
+}
+inline CoinWorkDouble CoinSqrt(CoinWorkDouble x)
+{
+     return sqrtl(x);
+}
+#else
+inline double CoinSqrt(double x)
+{
+     return sqrt(x);
+}
+#endif
+/// Trace
+#   ifdef NDEBUG
+#      define ClpTraceDebug(expression)		{}
+#   else
+void ClpTracePrint(std::string fileName, std::string message, int line);
+#      define ClpTraceDebug(expression) { \
+       if (!(expression)) { ClpTracePrint(__FILE__,__STRING(expression),__LINE__); } \
+  }
+#   endif
+/// Following only included if ClpPdco defined
+#ifdef ClpPdco_H
+
+
+inline double pdxxxmerit(int nlow, int nupp, int *low, int *upp, CoinDenseVector <double> &r1,
+                         CoinDenseVector <double> &r2, CoinDenseVector <double> &rL,
+                         CoinDenseVector <double> &rU, CoinDenseVector <double> &cL,
+                         CoinDenseVector <double> &cU )
+{
+
+// Evaluate the merit function for Newton's method.
+// It is the 2-norm of the three sets of residuals.
+     double sum1, sum2;
+     CoinDenseVector <double> f(6);
+     f[0] = r1.twoNorm();
+     f[1] = r2.twoNorm();
+     sum1 = sum2 = 0.0;
+     for (int k = 0; k < nlow; k++) {
+          sum1 += rL[low[k]] * rL[low[k]];
+          sum2 += cL[low[k]] * cL[low[k]];
+     }
+     f[2] = sqrt(sum1);
+     f[4] = sqrt(sum2);
+     sum1 = sum2 = 0.0;
+     for (int k = 0; k < nupp; k++) {
+          sum1 += rL[upp[k]] * rL[upp[k]];
+          sum2 += cL[upp[k]] * cL[upp[k]];
+     }
+     f[3] = sqrt(sum1);
+     f[5] = sqrt(sum2);
+
+     return f.twoNorm();
+}
+
+//-----------------------------------------------------------------------
+// End private function pdxxxmerit
+//-----------------------------------------------------------------------
+
+
+//function [r1,r2,rL,rU,Pinf,Dinf] =    ...
+//      pdxxxresid1( Aname,fix,low,upp, ...
+//                   b,bl,bu,d1,d2,grad,rL,rU,x,x1,x2,y,z1,z2 )
+
+inline void pdxxxresid1(ClpPdco *model, const int nlow, const int nupp, const int nfix,
+                        int *low, int *upp, int *fix,
+                        CoinDenseVector <double> &b, double *bl, double *bu, double d1, double d2,
+                        CoinDenseVector <double> &grad, CoinDenseVector <double> &rL,
+                        CoinDenseVector <double> &rU, CoinDenseVector <double> &x,
+                        CoinDenseVector <double> &x1, CoinDenseVector <double> &x2,
+                        CoinDenseVector <double> &y,  CoinDenseVector <double> &z1,
+                        CoinDenseVector <double> &z2, CoinDenseVector <double> &r1,
+                        CoinDenseVector <double> &r2, double *Pinf, double *Dinf)
+{
+
+// Form residuals for the primal and dual equations.
+// rL, rU are output, but we input them as full vectors
+// initialized (permanently) with any relevant zeros.
+
+// Get some element pointers for efficiency
+     double *x_elts  = x.getElements();
+     double *r2_elts = r2.getElements();
+
+     for (int k = 0; k < nfix; k++)
+          x_elts[fix[k]]  = 0;
+
+     r1.clear();
+     r2.clear();
+     model->matVecMult( 1, r1, x );
+     model->matVecMult( 2, r2, y );
+     for (int k = 0; k < nfix; k++)
+          r2_elts[fix[k]]  = 0;
+
+
+     r1      = b    - r1 - d2 * d2 * y;
+     r2      = grad - r2 - z1;              // grad includes d1*d1*x
+     if (nupp > 0)
+          r2    = r2 + z2;
+
+     for (int k = 0; k < nlow; k++)
+          rL[low[k]] = bl[low[k]] - x[low[k]] + x1[low[k]];
+     for (int k = 0; k < nupp; k++)
+          rU[upp[k]] = - bu[upp[k]] + x[upp[k]] + x2[upp[k]];
+
+     double normL = 0.0;
+     double normU = 0.0;
+     for (int k = 0; k < nlow; k++)
+          if (rL[low[k]] > normL) normL = rL[low[k]];
+     for (int k = 0; k < nupp; k++)
+          if (rU[upp[k]] > normU) normU = rU[upp[k]];
+
+     *Pinf    = CoinMax(normL, normU);
+     *Pinf    = CoinMax( r1.infNorm() , *Pinf );
+     *Dinf    = r2.infNorm();
+     *Pinf    = CoinMax( *Pinf, 1e-99 );
+     *Dinf    = CoinMax( *Dinf, 1e-99 );
+}
+
+//-----------------------------------------------------------------------
+// End private function pdxxxresid1
+//-----------------------------------------------------------------------
+
+
+//function [cL,cU,center,Cinf,Cinf0] = ...
+//      pdxxxresid2( mu,low,upp,cL,cU,x1,x2,z1,z2 )
+
+inline void pdxxxresid2(double mu, int nlow, int nupp, int *low, int *upp,
+                        CoinDenseVector <double> &cL, CoinDenseVector <double> &cU,
+                        CoinDenseVector <double> &x1, CoinDenseVector <double> &x2,
+                        CoinDenseVector <double> &z1, CoinDenseVector <double> &z2,
+                        double *center, double *Cinf, double *Cinf0)
+{
+
+// Form residuals for the complementarity equations.
+// cL, cU are output, but we input them as full vectors
+// initialized (permanently) with any relevant zeros.
+// Cinf  is the complementarity residual for X1 z1 = mu e, etc.
+// Cinf0 is the same for mu=0 (i.e., for the original problem).
+
+     double maxXz = -1e20;
+     double minXz = 1e20;
+
+     double *x1_elts = x1.getElements();
+     double *z1_elts = z1.getElements();
+     double *cL_elts = cL.getElements();
+     for (int k = 0; k < nlow; k++) {
+          double x1z1    = x1_elts[low[k]] * z1_elts[low[k]];
+          cL_elts[low[k]] = mu - x1z1;
+          if (x1z1 > maxXz) maxXz = x1z1;
+          if (x1z1 < minXz) minXz = x1z1;
+     }
+
+     double *x2_elts = x2.getElements();
+     double *z2_elts = z2.getElements();
+     double *cU_elts = cU.getElements();
+     for (int k = 0; k < nupp; k++) {
+          double x2z2    = x2_elts[upp[k]] * z2_elts[upp[k]];
+          cU_elts[upp[k]] = mu - x2z2;
+          if (x2z2 > maxXz) maxXz = x2z2;
+          if (x2z2 < minXz) minXz = x2z2;
+     }
+
+     maxXz   = CoinMax( maxXz, 1e-99 );
+     minXz   = CoinMax( minXz, 1e-99 );
+     *center  = maxXz / minXz;
+
+     double normL = 0.0;
+     double normU = 0.0;
+     for (int k = 0; k < nlow; k++)
+          if (cL_elts[low[k]] > normL) normL = cL_elts[low[k]];
+     for (int k = 0; k < nupp; k++)
+          if (cU_elts[upp[k]] > normU) normU = cU_elts[upp[k]];
+     *Cinf    = CoinMax( normL, normU);
+     *Cinf0   = maxXz;
+}
+//-----------------------------------------------------------------------
+// End private function pdxxxresid2
+//-----------------------------------------------------------------------
+
+inline double  pdxxxstep( CoinDenseVector <double> &x, CoinDenseVector <double> &dx )
+{
+
+// Assumes x > 0.
+// Finds the maximum step such that x + step*dx >= 0.
+
+     double step     = 1e+20;
+
+     int n = x.size();
+     double *x_elts = x.getElements();
+     double *dx_elts = dx.getElements();
+     for (int k = 0; k < n; k++)
+          if (dx_elts[k] < 0)
+               if ((x_elts[k] / (-dx_elts[k])) < step)
+                    step = x_elts[k] / (-dx_elts[k]);
+     return step;
+}
+//-----------------------------------------------------------------------
+// End private function pdxxxstep
+//-----------------------------------------------------------------------
+
+inline double  pdxxxstep(int nset, int *set, CoinDenseVector <double> &x, CoinDenseVector <double> &dx )
+{
+
+// Assumes x > 0.
+// Finds the maximum step such that x + step*dx >= 0.
+
+     double step     = 1e+20;
+
+     int n = x.size();
+     double *x_elts = x.getElements();
+     double *dx_elts = dx.getElements();
+     for (int k = 0; k < n; k++)
+          if (dx_elts[k] < 0)
+               if ((x_elts[k] / (-dx_elts[k])) < step)
+                    step = x_elts[k] / (-dx_elts[k]);
+     return step;
+}
+//-----------------------------------------------------------------------
+// End private function pdxxxstep
+//-----------------------------------------------------------------------
+#endif
+#endif
diff --git a/cbits/coin/ClpInterior.cpp b/cbits/coin/ClpInterior.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpInterior.cpp
@@ -0,0 +1,1258 @@
+/* $Id: ClpInterior.cpp 1941 2013-04-10 16:52:27Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include "CoinPragma.hpp"
+
+#include <math.h>
+
+#include "CoinHelperFunctions.hpp"
+#include "ClpInterior.hpp"
+#include "ClpMatrixBase.hpp"
+#include "ClpLsqr.hpp"
+#include "ClpPdcoBase.hpp"
+#include "CoinDenseVector.hpp"
+#include "ClpMessage.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "ClpCholeskyDense.hpp"
+#include "ClpLinearObjective.hpp"
+#include "ClpQuadraticObjective.hpp"
+#include <cfloat>
+
+#include <string>
+#include <stdio.h>
+#include <iostream>
+//#############################################################################
+
+ClpInterior::ClpInterior () :
+
+     ClpModel(),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     worstComplementarity_(0.0),
+     xsize_(0.0),
+     zsize_(0.0),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rhs_(NULL),
+     x_(NULL),
+     y_(NULL),
+     dj_(NULL),
+     lsqrObject_(NULL),
+     pdcoStuff_(NULL),
+     mu_(0.0),
+     objectiveNorm_(1.0e-12),
+     rhsNorm_(1.0e-12),
+     solutionNorm_(1.0e-12),
+     dualObjective_(0.0),
+     primalObjective_(0.0),
+     diagonalNorm_(1.0e-12),
+     stepLength_(0.995),
+     linearPerturbation_(1.0e-12),
+     diagonalPerturbation_(1.0e-15),
+     gamma_(0.0),
+     delta_(0),
+     targetGap_(1.0e-12),
+     projectionTolerance_(1.0e-7),
+     maximumRHSError_(0.0),
+     maximumBoundInfeasibility_(0.0),
+     maximumDualError_(0.0),
+     diagonalScaleFactor_(0.0),
+     scaleFactor_(1.0),
+     actualPrimalStep_(0.0),
+     actualDualStep_(0.0),
+     smallestInfeasibility_(0.0),
+     complementarityGap_(0.0),
+     baseObjectiveNorm_(0.0),
+     worstDirectionAccuracy_(0.0),
+     maximumRHSChange_(0.0),
+     errorRegion_(NULL),
+     rhsFixRegion_(NULL),
+     upperSlack_(NULL),
+     lowerSlack_(NULL),
+     diagonal_(NULL),
+     solution_(NULL),
+     workArray_(NULL),
+     deltaX_(NULL),
+     deltaY_(NULL),
+     deltaZ_(NULL),
+     deltaW_(NULL),
+     deltaSU_(NULL),
+     deltaSL_(NULL),
+     primalR_(NULL),
+     dualR_(NULL),
+     rhsB_(NULL),
+     rhsU_(NULL),
+     rhsL_(NULL),
+     rhsZ_(NULL),
+     rhsW_(NULL),
+     rhsC_(NULL),
+     zVec_(NULL),
+     wVec_(NULL),
+     cholesky_(NULL),
+     numberComplementarityPairs_(0),
+     numberComplementarityItems_(0),
+     maximumBarrierIterations_(200),
+     gonePrimalFeasible_(false),
+     goneDualFeasible_(false),
+     algorithm_(-1)
+{
+     memset(historyInfeasibility_, 0, LENGTH_HISTORY * sizeof(CoinWorkDouble));
+     solveType_ = 3; // say interior based life form
+     cholesky_ = new ClpCholeskyDense(); // put in placeholder
+}
+
+// Subproblem constructor
+ClpInterior::ClpInterior ( const ClpModel * rhs,
+                           int numberRows, const int * whichRow,
+                           int numberColumns, const int * whichColumn,
+                           bool dropNames, bool dropIntegers)
+     : ClpModel(rhs, numberRows, whichRow,
+                numberColumns, whichColumn, dropNames, dropIntegers),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     worstComplementarity_(0.0),
+     xsize_(0.0),
+     zsize_(0.0),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rhs_(NULL),
+     x_(NULL),
+     y_(NULL),
+     dj_(NULL),
+     lsqrObject_(NULL),
+     pdcoStuff_(NULL),
+     mu_(0.0),
+     objectiveNorm_(1.0e-12),
+     rhsNorm_(1.0e-12),
+     solutionNorm_(1.0e-12),
+     dualObjective_(0.0),
+     primalObjective_(0.0),
+     diagonalNorm_(1.0e-12),
+     stepLength_(0.99995),
+     linearPerturbation_(1.0e-12),
+     diagonalPerturbation_(1.0e-15),
+     gamma_(0.0),
+     delta_(0),
+     targetGap_(1.0e-12),
+     projectionTolerance_(1.0e-7),
+     maximumRHSError_(0.0),
+     maximumBoundInfeasibility_(0.0),
+     maximumDualError_(0.0),
+     diagonalScaleFactor_(0.0),
+     scaleFactor_(0.0),
+     actualPrimalStep_(0.0),
+     actualDualStep_(0.0),
+     smallestInfeasibility_(0.0),
+     complementarityGap_(0.0),
+     baseObjectiveNorm_(0.0),
+     worstDirectionAccuracy_(0.0),
+     maximumRHSChange_(0.0),
+     errorRegion_(NULL),
+     rhsFixRegion_(NULL),
+     upperSlack_(NULL),
+     lowerSlack_(NULL),
+     diagonal_(NULL),
+     solution_(NULL),
+     workArray_(NULL),
+     deltaX_(NULL),
+     deltaY_(NULL),
+     deltaZ_(NULL),
+     deltaW_(NULL),
+     deltaSU_(NULL),
+     deltaSL_(NULL),
+     primalR_(NULL),
+     dualR_(NULL),
+     rhsB_(NULL),
+     rhsU_(NULL),
+     rhsL_(NULL),
+     rhsZ_(NULL),
+     rhsW_(NULL),
+     rhsC_(NULL),
+     zVec_(NULL),
+     wVec_(NULL),
+     cholesky_(NULL),
+     numberComplementarityPairs_(0),
+     numberComplementarityItems_(0),
+     maximumBarrierIterations_(200),
+     gonePrimalFeasible_(false),
+     goneDualFeasible_(false),
+     algorithm_(-1)
+{
+     memset(historyInfeasibility_, 0, LENGTH_HISTORY * sizeof(CoinWorkDouble));
+     solveType_ = 3; // say interior based life form
+     cholesky_ = new ClpCholeskyDense();
+}
+
+//-----------------------------------------------------------------------------
+
+ClpInterior::~ClpInterior ()
+{
+     gutsOfDelete();
+}
+//#############################################################################
+/*
+   This does housekeeping
+*/
+int
+ClpInterior::housekeeping()
+{
+     numberIterations_++;
+     return 0;
+}
+// Copy constructor.
+ClpInterior::ClpInterior(const ClpInterior &rhs) :
+     ClpModel(rhs),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     worstComplementarity_(0.0),
+     xsize_(0.0),
+     zsize_(0.0),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rhs_(NULL),
+     x_(NULL),
+     y_(NULL),
+     dj_(NULL),
+     lsqrObject_(NULL),
+     pdcoStuff_(NULL),
+     errorRegion_(NULL),
+     rhsFixRegion_(NULL),
+     upperSlack_(NULL),
+     lowerSlack_(NULL),
+     diagonal_(NULL),
+     solution_(NULL),
+     workArray_(NULL),
+     deltaX_(NULL),
+     deltaY_(NULL),
+     deltaZ_(NULL),
+     deltaW_(NULL),
+     deltaSU_(NULL),
+     deltaSL_(NULL),
+     primalR_(NULL),
+     dualR_(NULL),
+     rhsB_(NULL),
+     rhsU_(NULL),
+     rhsL_(NULL),
+     rhsZ_(NULL),
+     rhsW_(NULL),
+     rhsC_(NULL),
+     zVec_(NULL),
+     wVec_(NULL),
+     cholesky_(NULL)
+{
+     gutsOfDelete();
+     gutsOfCopy(rhs);
+     solveType_ = 3; // say interior based life form
+}
+// Copy constructor from model
+ClpInterior::ClpInterior(const ClpModel &rhs) :
+     ClpModel(rhs),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     worstComplementarity_(0.0),
+     xsize_(0.0),
+     zsize_(0.0),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rhs_(NULL),
+     x_(NULL),
+     y_(NULL),
+     dj_(NULL),
+     lsqrObject_(NULL),
+     pdcoStuff_(NULL),
+     mu_(0.0),
+     objectiveNorm_(1.0e-12),
+     rhsNorm_(1.0e-12),
+     solutionNorm_(1.0e-12),
+     dualObjective_(0.0),
+     primalObjective_(0.0),
+     diagonalNorm_(1.0e-12),
+     stepLength_(0.99995),
+     linearPerturbation_(1.0e-12),
+     diagonalPerturbation_(1.0e-15),
+     gamma_(0.0),
+     delta_(0),
+     targetGap_(1.0e-12),
+     projectionTolerance_(1.0e-7),
+     maximumRHSError_(0.0),
+     maximumBoundInfeasibility_(0.0),
+     maximumDualError_(0.0),
+     diagonalScaleFactor_(0.0),
+     scaleFactor_(0.0),
+     actualPrimalStep_(0.0),
+     actualDualStep_(0.0),
+     smallestInfeasibility_(0.0),
+     complementarityGap_(0.0),
+     baseObjectiveNorm_(0.0),
+     worstDirectionAccuracy_(0.0),
+     maximumRHSChange_(0.0),
+     errorRegion_(NULL),
+     rhsFixRegion_(NULL),
+     upperSlack_(NULL),
+     lowerSlack_(NULL),
+     diagonal_(NULL),
+     solution_(NULL),
+     workArray_(NULL),
+     deltaX_(NULL),
+     deltaY_(NULL),
+     deltaZ_(NULL),
+     deltaW_(NULL),
+     deltaSU_(NULL),
+     deltaSL_(NULL),
+     primalR_(NULL),
+     dualR_(NULL),
+     rhsB_(NULL),
+     rhsU_(NULL),
+     rhsL_(NULL),
+     rhsZ_(NULL),
+     rhsW_(NULL),
+     rhsC_(NULL),
+     zVec_(NULL),
+     wVec_(NULL),
+     cholesky_(NULL),
+     numberComplementarityPairs_(0),
+     numberComplementarityItems_(0),
+     maximumBarrierIterations_(200),
+     gonePrimalFeasible_(false),
+     goneDualFeasible_(false),
+     algorithm_(-1)
+{
+     memset(historyInfeasibility_, 0, LENGTH_HISTORY * sizeof(CoinWorkDouble));
+     solveType_ = 3; // say interior based life form
+     cholesky_ = new ClpCholeskyDense();
+}
+// Assignment operator. This copies the data
+ClpInterior &
+ClpInterior::operator=(const ClpInterior & rhs)
+{
+     if (this != &rhs) {
+          gutsOfDelete();
+          ClpModel::operator=(rhs);
+          gutsOfCopy(rhs);
+     }
+     return *this;
+}
+void
+ClpInterior::gutsOfCopy(const ClpInterior & rhs)
+{
+     lower_ = ClpCopyOfArray(rhs.lower_, numberColumns_ + numberRows_);
+     rowLowerWork_ = lower_ + numberColumns_;
+     columnLowerWork_ = lower_;
+     upper_ = ClpCopyOfArray(rhs.upper_, numberColumns_ + numberRows_);
+     rowUpperWork_ = upper_ + numberColumns_;
+     columnUpperWork_ = upper_;
+     //cost_ = ClpCopyOfArray(rhs.cost_,2*(numberColumns_+numberRows_));
+     cost_ = ClpCopyOfArray(rhs.cost_, numberColumns_);
+     rhs_ = ClpCopyOfArray(rhs.rhs_, numberRows_);
+     x_ = ClpCopyOfArray(rhs.x_, numberColumns_);
+     y_ = ClpCopyOfArray(rhs.y_, numberRows_);
+     dj_ = ClpCopyOfArray(rhs.dj_, numberColumns_ + numberRows_);
+     lsqrObject_ = rhs.lsqrObject_ != NULL ? new ClpLsqr(*rhs.lsqrObject_) : NULL;
+     pdcoStuff_ = rhs.pdcoStuff_ != NULL ? rhs.pdcoStuff_->clone() : NULL;
+     largestPrimalError_ = rhs.largestPrimalError_;
+     largestDualError_ = rhs.largestDualError_;
+     sumDualInfeasibilities_ = rhs.sumDualInfeasibilities_;
+     sumPrimalInfeasibilities_ = rhs.sumPrimalInfeasibilities_;
+     worstComplementarity_ = rhs.worstComplementarity_;
+     xsize_ = rhs.xsize_;
+     zsize_ = rhs.zsize_;
+     solveType_ = rhs.solveType_;
+     mu_ = rhs.mu_;
+     objectiveNorm_ = rhs.objectiveNorm_;
+     rhsNorm_ = rhs.rhsNorm_;
+     solutionNorm_ = rhs.solutionNorm_;
+     dualObjective_ = rhs.dualObjective_;
+     primalObjective_ = rhs.primalObjective_;
+     diagonalNorm_ = rhs.diagonalNorm_;
+     stepLength_ = rhs.stepLength_;
+     linearPerturbation_ = rhs.linearPerturbation_;
+     diagonalPerturbation_ = rhs.diagonalPerturbation_;
+     gamma_ = rhs.gamma_;
+     delta_ = rhs.delta_;
+     targetGap_ = rhs.targetGap_;
+     projectionTolerance_ = rhs.projectionTolerance_;
+     maximumRHSError_ = rhs.maximumRHSError_;
+     maximumBoundInfeasibility_ = rhs.maximumBoundInfeasibility_;
+     maximumDualError_ = rhs.maximumDualError_;
+     diagonalScaleFactor_ = rhs.diagonalScaleFactor_;
+     scaleFactor_ = rhs.scaleFactor_;
+     actualPrimalStep_ = rhs.actualPrimalStep_;
+     actualDualStep_ = rhs.actualDualStep_;
+     smallestInfeasibility_ = rhs.smallestInfeasibility_;
+     complementarityGap_ = rhs.complementarityGap_;
+     baseObjectiveNorm_ = rhs.baseObjectiveNorm_;
+     worstDirectionAccuracy_ = rhs.worstDirectionAccuracy_;
+     maximumRHSChange_ = rhs.maximumRHSChange_;
+     errorRegion_ = ClpCopyOfArray(rhs.errorRegion_, numberRows_);
+     rhsFixRegion_ = ClpCopyOfArray(rhs.rhsFixRegion_, numberRows_);
+     deltaY_ = ClpCopyOfArray(rhs.deltaY_, numberRows_);
+     upperSlack_ = ClpCopyOfArray(rhs.upperSlack_, numberRows_ + numberColumns_);
+     lowerSlack_ = ClpCopyOfArray(rhs.lowerSlack_, numberRows_ + numberColumns_);
+     diagonal_ = ClpCopyOfArray(rhs.diagonal_, numberRows_ + numberColumns_);
+     deltaX_ = ClpCopyOfArray(rhs.deltaX_, numberRows_ + numberColumns_);
+     deltaZ_ = ClpCopyOfArray(rhs.deltaZ_, numberRows_ + numberColumns_);
+     deltaW_ = ClpCopyOfArray(rhs.deltaW_, numberRows_ + numberColumns_);
+     deltaSU_ = ClpCopyOfArray(rhs.deltaSU_, numberRows_ + numberColumns_);
+     deltaSL_ = ClpCopyOfArray(rhs.deltaSL_, numberRows_ + numberColumns_);
+     primalR_ = ClpCopyOfArray(rhs.primalR_, numberRows_ + numberColumns_);
+     dualR_ = ClpCopyOfArray(rhs.dualR_, numberRows_ + numberColumns_);
+     rhsB_ = ClpCopyOfArray(rhs.rhsB_, numberRows_);
+     rhsU_ = ClpCopyOfArray(rhs.rhsU_, numberRows_ + numberColumns_);
+     rhsL_ = ClpCopyOfArray(rhs.rhsL_, numberRows_ + numberColumns_);
+     rhsZ_ = ClpCopyOfArray(rhs.rhsZ_, numberRows_ + numberColumns_);
+     rhsW_ = ClpCopyOfArray(rhs.rhsW_, numberRows_ + numberColumns_);
+     rhsC_ = ClpCopyOfArray(rhs.rhsC_, numberRows_ + numberColumns_);
+     solution_ = ClpCopyOfArray(rhs.solution_, numberRows_ + numberColumns_);
+     workArray_ = ClpCopyOfArray(rhs.workArray_, numberRows_ + numberColumns_);
+     zVec_ = ClpCopyOfArray(rhs.zVec_, numberRows_ + numberColumns_);
+     wVec_ = ClpCopyOfArray(rhs.wVec_, numberRows_ + numberColumns_);
+     cholesky_ = rhs.cholesky_->clone();
+     numberComplementarityPairs_ = rhs.numberComplementarityPairs_;
+     numberComplementarityItems_ = rhs.numberComplementarityItems_;
+     maximumBarrierIterations_ = rhs.maximumBarrierIterations_;
+     gonePrimalFeasible_ = rhs.gonePrimalFeasible_;
+     goneDualFeasible_ = rhs.goneDualFeasible_;
+     algorithm_ = rhs.algorithm_;
+}
+
+void
+ClpInterior::gutsOfDelete()
+{
+     delete [] lower_;
+     lower_ = NULL;
+     rowLowerWork_ = NULL;
+     columnLowerWork_ = NULL;
+     delete [] upper_;
+     upper_ = NULL;
+     rowUpperWork_ = NULL;
+     columnUpperWork_ = NULL;
+     delete [] cost_;
+     cost_ = NULL;
+     delete [] rhs_;
+     rhs_ = NULL;
+     delete [] x_;
+     x_ = NULL;
+     delete [] y_;
+     y_ = NULL;
+     delete [] dj_;
+     dj_ = NULL;
+     delete lsqrObject_;
+     lsqrObject_ = NULL;
+     //delete pdcoStuff_;  // FIXME
+     pdcoStuff_ = NULL;
+     delete [] errorRegion_;
+     errorRegion_ = NULL;
+     delete [] rhsFixRegion_;
+     rhsFixRegion_ = NULL;
+     delete [] deltaY_;
+     deltaY_ = NULL;
+     delete [] upperSlack_;
+     upperSlack_ = NULL;
+     delete [] lowerSlack_;
+     lowerSlack_ = NULL;
+     delete [] diagonal_;
+     diagonal_ = NULL;
+     delete [] deltaX_;
+     deltaX_ = NULL;
+     delete [] deltaZ_;
+     deltaZ_ = NULL;
+     delete [] deltaW_;
+     deltaW_ = NULL;
+     delete [] deltaSU_;
+     deltaSU_ = NULL;
+     delete [] deltaSL_;
+     deltaSL_ = NULL;
+     delete [] primalR_;
+     primalR_ = NULL;
+     delete [] dualR_;
+     dualR_ = NULL;
+     delete [] rhsB_;
+     rhsB_ = NULL;
+     delete [] rhsU_;
+     rhsU_ = NULL;
+     delete [] rhsL_;
+     rhsL_ = NULL;
+     delete [] rhsZ_;
+     rhsZ_ = NULL;
+     delete [] rhsW_;
+     rhsW_ = NULL;
+     delete [] rhsC_;
+     rhsC_ = NULL;
+     delete [] solution_;
+     solution_ = NULL;
+     delete [] workArray_;
+     workArray_ = NULL;
+     delete [] zVec_;
+     zVec_ = NULL;
+     delete [] wVec_;
+     wVec_ = NULL;
+     delete cholesky_;
+}
+bool
+ClpInterior::createWorkingData()
+{
+     bool goodMatrix = true;
+     //check matrix
+     if (!matrix_->allElementsInRange(this, 1.0e-12, 1.0e20)) {
+          problemStatus_ = 4;
+          goodMatrix = false;
+     }
+     int nTotal = numberRows_ + numberColumns_;
+     delete [] solution_;
+     solution_ = new CoinWorkDouble[nTotal];
+     CoinMemcpyN(columnActivity_,	numberColumns_, solution_);
+     CoinMemcpyN(rowActivity_,	numberRows_, solution_ + numberColumns_);
+     delete [] cost_;
+     cost_ = new CoinWorkDouble[nTotal];
+     int i;
+     CoinWorkDouble direction = optimizationDirection_ * objectiveScale_;
+     // direction is actually scale out not scale in
+     if (direction)
+          direction = 1.0 / direction;
+     const double * obj = objective();
+     for (i = 0; i < numberColumns_; i++)
+          cost_[i] = direction * obj[i];
+     memset(cost_ + numberColumns_, 0, numberRows_ * sizeof(CoinWorkDouble));
+     // do scaling if needed
+     if (scalingFlag_ > 0 && !rowScale_) {
+          if (matrix_->scale(this))
+               scalingFlag_ = -scalingFlag_; // not scaled after all
+     }
+     delete [] lower_;
+     delete [] upper_;
+     lower_ = new CoinWorkDouble[nTotal];
+     upper_ = new CoinWorkDouble[nTotal];
+     rowLowerWork_ = lower_ + numberColumns_;
+     columnLowerWork_ = lower_;
+     rowUpperWork_ = upper_ + numberColumns_;
+     columnUpperWork_ = upper_;
+     CoinMemcpyN(rowLower_, numberRows_, rowLowerWork_);
+     CoinMemcpyN(rowUpper_, numberRows_, rowUpperWork_);
+     CoinMemcpyN(columnLower_, numberColumns_, columnLowerWork_);
+     CoinMemcpyN(columnUpper_, numberColumns_, columnUpperWork_);
+     // clean up any mismatches on infinity
+     for (i = 0; i < numberColumns_; i++) {
+          if (columnLowerWork_[i] < -1.0e30)
+               columnLowerWork_[i] = -COIN_DBL_MAX;
+          if (columnUpperWork_[i] > 1.0e30)
+               columnUpperWork_[i] = COIN_DBL_MAX;
+     }
+     // clean up any mismatches on infinity
+     for (i = 0; i < numberRows_; i++) {
+          if (rowLowerWork_[i] < -1.0e30)
+               rowLowerWork_[i] = -COIN_DBL_MAX;
+          if (rowUpperWork_[i] > 1.0e30)
+               rowUpperWork_[i] = COIN_DBL_MAX;
+     }
+     // check rim of problem okay
+     if (!sanityCheck())
+          goodMatrix = false;
+     if(rowScale_) {
+          for (i = 0; i < numberColumns_; i++) {
+               CoinWorkDouble multiplier = rhsScale_ / columnScale_[i];
+               cost_[i] *= columnScale_[i];
+               if (columnLowerWork_[i] > -1.0e50)
+                    columnLowerWork_[i] *= multiplier;
+               if (columnUpperWork_[i] < 1.0e50)
+                    columnUpperWork_[i] *= multiplier;
+
+          }
+          for (i = 0; i < numberRows_; i++) {
+               CoinWorkDouble multiplier = rhsScale_ * rowScale_[i];
+               if (rowLowerWork_[i] > -1.0e50)
+                    rowLowerWork_[i] *= multiplier;
+               if (rowUpperWork_[i] < 1.0e50)
+                    rowUpperWork_[i] *= multiplier;
+          }
+     } else if (rhsScale_ != 1.0) {
+          for (i = 0; i < numberColumns_ + numberRows_; i++) {
+               if (lower_[i] > -1.0e50)
+                    lower_[i] *= rhsScale_;
+               if (upper_[i] < 1.0e50)
+                    upper_[i] *= rhsScale_;
+
+          }
+     }
+     assert (!errorRegion_);
+     errorRegion_ = new CoinWorkDouble [numberRows_];
+     assert (!rhsFixRegion_);
+     rhsFixRegion_ = new CoinWorkDouble [numberRows_];
+     assert (!deltaY_);
+     deltaY_ = new CoinWorkDouble [numberRows_];
+     CoinZeroN(deltaY_, numberRows_);
+     assert (!upperSlack_);
+     upperSlack_ = new CoinWorkDouble [nTotal];
+     assert (!lowerSlack_);
+     lowerSlack_ = new CoinWorkDouble [nTotal];
+     assert (!diagonal_);
+     diagonal_ = new CoinWorkDouble [nTotal];
+     assert (!deltaX_);
+     deltaX_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(deltaX_, nTotal);
+     assert (!deltaZ_);
+     deltaZ_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(deltaZ_, nTotal);
+     assert (!deltaW_);
+     deltaW_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(deltaW_, nTotal);
+     assert (!deltaSU_);
+     deltaSU_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(deltaSU_, nTotal);
+     assert (!deltaSL_);
+     deltaSL_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(deltaSL_, nTotal);
+     assert (!primalR_);
+     assert (!dualR_);
+     // create arrays if we are doing KKT
+     if (cholesky_->type() >= 20) {
+          primalR_ = new CoinWorkDouble [nTotal];
+          CoinZeroN(primalR_, nTotal);
+          dualR_ = new CoinWorkDouble [numberRows_];
+          CoinZeroN(dualR_, numberRows_);
+     }
+     assert (!rhsB_);
+     rhsB_ = new CoinWorkDouble [numberRows_];
+     CoinZeroN(rhsB_, numberRows_);
+     assert (!rhsU_);
+     rhsU_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(rhsU_, nTotal);
+     assert (!rhsL_);
+     rhsL_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(rhsL_, nTotal);
+     assert (!rhsZ_);
+     rhsZ_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(rhsZ_, nTotal);
+     assert (!rhsW_);
+     rhsW_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(rhsW_, nTotal);
+     assert (!rhsC_);
+     rhsC_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(rhsC_, nTotal);
+     assert (!workArray_);
+     workArray_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(workArray_, nTotal);
+     assert (!zVec_);
+     zVec_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(zVec_, nTotal);
+     assert (!wVec_);
+     wVec_ = new CoinWorkDouble [nTotal];
+     CoinZeroN(wVec_, nTotal);
+     assert (!dj_);
+     dj_ = new CoinWorkDouble [nTotal];
+     if (!status_)
+          status_ = new unsigned char [numberRows_+numberColumns_];
+     memset(status_, 0, numberRows_ + numberColumns_);
+     return goodMatrix;
+}
+void
+ClpInterior::deleteWorkingData()
+{
+     int i;
+     if (optimizationDirection_ != 1.0 || objectiveScale_ != 1.0) {
+          CoinWorkDouble scaleC = optimizationDirection_ / objectiveScale_;
+          // and modify all dual signs
+          for (i = 0; i < numberColumns_; i++)
+               reducedCost_[i] = scaleC * dj_[i];
+          for (i = 0; i < numberRows_; i++)
+               dual_[i] *= scaleC;
+     }
+     if (rowScale_) {
+          CoinWorkDouble scaleR = 1.0 / rhsScale_;
+          for (i = 0; i < numberColumns_; i++) {
+               CoinWorkDouble scaleFactor = columnScale_[i];
+               CoinWorkDouble valueScaled = columnActivity_[i];
+               columnActivity_[i] = valueScaled * scaleFactor * scaleR;
+               CoinWorkDouble valueScaledDual = reducedCost_[i];
+               reducedCost_[i] = valueScaledDual / scaleFactor;
+          }
+          for (i = 0; i < numberRows_; i++) {
+               CoinWorkDouble scaleFactor = rowScale_[i];
+               CoinWorkDouble valueScaled = rowActivity_[i];
+               rowActivity_[i] = (valueScaled * scaleR) / scaleFactor;
+               CoinWorkDouble valueScaledDual = dual_[i];
+               dual_[i] = valueScaledDual * scaleFactor;
+          }
+     } else if (rhsScale_ != 1.0) {
+          CoinWorkDouble scaleR = 1.0 / rhsScale_;
+          for (i = 0; i < numberColumns_; i++) {
+               CoinWorkDouble valueScaled = columnActivity_[i];
+               columnActivity_[i] = valueScaled * scaleR;
+          }
+          for (i = 0; i < numberRows_; i++) {
+               CoinWorkDouble valueScaled = rowActivity_[i];
+               rowActivity_[i] = valueScaled * scaleR;
+          }
+     }
+     delete [] cost_;
+     cost_ = NULL;
+     delete [] solution_;
+     solution_ = NULL;
+     delete [] lower_;
+     lower_ = NULL;
+     delete [] upper_;
+     upper_ = NULL;
+     delete [] errorRegion_;
+     errorRegion_ = NULL;
+     delete [] rhsFixRegion_;
+     rhsFixRegion_ = NULL;
+     delete [] deltaY_;
+     deltaY_ = NULL;
+     delete [] upperSlack_;
+     upperSlack_ = NULL;
+     delete [] lowerSlack_;
+     lowerSlack_ = NULL;
+     delete [] diagonal_;
+     diagonal_ = NULL;
+     delete [] deltaX_;
+     deltaX_ = NULL;
+     delete [] workArray_;
+     workArray_ = NULL;
+     delete [] zVec_;
+     zVec_ = NULL;
+     delete [] wVec_;
+     wVec_ = NULL;
+     delete [] dj_;
+     dj_ = NULL;
+}
+// Sanity check on input data - returns true if okay
+bool
+ClpInterior::sanityCheck()
+{
+     // bad if empty
+     if (!numberColumns_ || ((!numberRows_ || !matrix_->getNumElements()) && objective_->type() < 2)) {
+          problemStatus_ = emptyProblem();
+          return false;
+     }
+     int numberBad ;
+     CoinWorkDouble largestBound, smallestBound, minimumGap;
+     CoinWorkDouble smallestObj, largestObj;
+     int firstBad;
+     int modifiedBounds = 0;
+     int i;
+     numberBad = 0;
+     firstBad = -1;
+     minimumGap = 1.0e100;
+     smallestBound = 1.0e100;
+     largestBound = 0.0;
+     smallestObj = 1.0e100;
+     largestObj = 0.0;
+     // If bounds are too close - fix
+     CoinWorkDouble fixTolerance = 1.1 * primalTolerance();
+     for (i = numberColumns_; i < numberColumns_ + numberRows_; i++) {
+          CoinWorkDouble value;
+          value = CoinAbs(cost_[i]);
+          if (value > 1.0e50) {
+               numberBad++;
+               if (firstBad < 0)
+                    firstBad = i;
+          } else if (value) {
+               if (value > largestObj)
+                    largestObj = value;
+               if (value < smallestObj)
+                    smallestObj = value;
+          }
+          value = upper_[i] - lower_[i];
+          if (value < -primalTolerance()) {
+               numberBad++;
+               if (firstBad < 0)
+                    firstBad = i;
+          } else if (value <= fixTolerance) {
+               if (value) {
+                    // modify
+                    upper_[i] = lower_[i];
+                    modifiedBounds++;
+               }
+          } else {
+               if (value < minimumGap)
+                    minimumGap = value;
+          }
+          if (lower_[i] > -1.0e100 && lower_[i]) {
+               value = CoinAbs(lower_[i]);
+               if (value > largestBound)
+                    largestBound = value;
+               if (value < smallestBound)
+                    smallestBound = value;
+          }
+          if (upper_[i] < 1.0e100 && upper_[i]) {
+               value = CoinAbs(upper_[i]);
+               if (value > largestBound)
+                    largestBound = value;
+               if (value < smallestBound)
+                    smallestBound = value;
+          }
+     }
+     if (largestBound)
+          handler_->message(CLP_RIMSTATISTICS3, messages_)
+                    << static_cast<double>(smallestBound)
+                    << static_cast<double>(largestBound)
+                    << static_cast<double>(minimumGap)
+                    << CoinMessageEol;
+     minimumGap = 1.0e100;
+     smallestBound = 1.0e100;
+     largestBound = 0.0;
+     for (i = 0; i < numberColumns_; i++) {
+          CoinWorkDouble value;
+          value = CoinAbs(cost_[i]);
+          if (value > 1.0e50) {
+               numberBad++;
+               if (firstBad < 0)
+                    firstBad = i;
+          } else if (value) {
+               if (value > largestObj)
+                    largestObj = value;
+               if (value < smallestObj)
+                    smallestObj = value;
+          }
+          value = upper_[i] - lower_[i];
+          if (value < -primalTolerance()) {
+               numberBad++;
+               if (firstBad < 0)
+                    firstBad = i;
+          } else if (value <= fixTolerance) {
+               if (value) {
+                    // modify
+                    upper_[i] = lower_[i];
+                    modifiedBounds++;
+               }
+          } else {
+               if (value < minimumGap)
+                    minimumGap = value;
+          }
+          if (lower_[i] > -1.0e100 && lower_[i]) {
+               value = CoinAbs(lower_[i]);
+               if (value > largestBound)
+                    largestBound = value;
+               if (value < smallestBound)
+                    smallestBound = value;
+          }
+          if (upper_[i] < 1.0e100 && upper_[i]) {
+               value = CoinAbs(upper_[i]);
+               if (value > largestBound)
+                    largestBound = value;
+               if (value < smallestBound)
+                    smallestBound = value;
+          }
+     }
+     char rowcol[] = {'R', 'C'};
+     if (numberBad) {
+          handler_->message(CLP_BAD_BOUNDS, messages_)
+                    << numberBad
+                    << rowcol[isColumn(firstBad)] << sequenceWithin(firstBad)
+                    << CoinMessageEol;
+          problemStatus_ = 4;
+          return false;
+     }
+     if (modifiedBounds)
+          handler_->message(CLP_MODIFIEDBOUNDS, messages_)
+                    << modifiedBounds
+                    << CoinMessageEol;
+     handler_->message(CLP_RIMSTATISTICS1, messages_)
+               << static_cast<double>(smallestObj)
+               << static_cast<double>(largestObj)
+               << CoinMessageEol;
+     if (largestBound)
+          handler_->message(CLP_RIMSTATISTICS2, messages_)
+                    << static_cast<double>(smallestBound)
+                    << static_cast<double>(largestBound)
+                    << static_cast<double>(minimumGap)
+                    << CoinMessageEol;
+     return true;
+}
+/* Loads a problem (the constraints on the
+   rows are given by lower and upper bounds). If a pointer is 0 then the
+   following values are the default:
+   <ul>
+   <li> <code>colub</code>: all columns have upper bound infinity
+   <li> <code>collb</code>: all columns have lower bound 0
+   <li> <code>rowub</code>: all rows have upper bound infinity
+   <li> <code>rowlb</code>: all rows have lower bound -infinity
+   <li> <code>obj</code>: all variables have 0 objective coefficient
+   </ul>
+*/
+void
+ClpInterior::loadProblem (  const ClpMatrixBase& matrix,
+                            const double* collb, const double* colub,
+                            const double* obj,
+                            const double* rowlb, const double* rowub,
+                            const double * rowObjective)
+{
+     ClpModel::loadProblem(matrix, collb, colub, obj, rowlb, rowub,
+                           rowObjective);
+}
+void
+ClpInterior::loadProblem (  const CoinPackedMatrix& matrix,
+                            const double* collb, const double* colub,
+                            const double* obj,
+                            const double* rowlb, const double* rowub,
+                            const double * rowObjective)
+{
+     ClpModel::loadProblem(matrix, collb, colub, obj, rowlb, rowub,
+                           rowObjective);
+}
+
+/* Just like the other loadProblem() method except that the matrix is
+   given in a standard column major ordered format (without gaps). */
+void
+ClpInterior::loadProblem (  const int numcols, const int numrows,
+                            const CoinBigIndex* start, const int* index,
+                            const double* value,
+                            const double* collb, const double* colub,
+                            const double* obj,
+                            const double* rowlb, const double* rowub,
+                            const double * rowObjective)
+{
+     ClpModel::loadProblem(numcols, numrows, start, index, value,
+                           collb, colub, obj, rowlb, rowub,
+                           rowObjective);
+}
+void
+ClpInterior::loadProblem (  const int numcols, const int numrows,
+                            const CoinBigIndex* start, const int* index,
+                            const double* value, const int * length,
+                            const double* collb, const double* colub,
+                            const double* obj,
+                            const double* rowlb, const double* rowub,
+                            const double * rowObjective)
+{
+     ClpModel::loadProblem(numcols, numrows, start, index, value, length,
+                           collb, colub, obj, rowlb, rowub,
+                           rowObjective);
+}
+// Read an mps file from the given filename
+int
+ClpInterior::readMps(const char *filename,
+                     bool keepNames,
+                     bool ignoreErrors)
+{
+     int status = ClpModel::readMps(filename, keepNames, ignoreErrors);
+     return status;
+}
+#include "ClpPdco.hpp"
+/* Pdco algorithm - see ClpPdco.hpp for method */
+int
+ClpInterior::pdco()
+{
+     return ((ClpPdco *) this)->pdco();
+}
+// ** Temporary version
+int
+ClpInterior::pdco( ClpPdcoBase * stuff, Options &options, Info &info, Outfo &outfo)
+{
+     return ((ClpPdco *) this)->pdco(stuff, options, info, outfo);
+}
+#include "ClpPredictorCorrector.hpp"
+// Primal-Dual Predictor-Corrector barrier
+int
+ClpInterior::primalDual()
+{
+     return (static_cast<ClpPredictorCorrector *> (this))->solve();
+}
+
+void
+ClpInterior::checkSolution()
+{
+     int iRow, iColumn;
+     CoinWorkDouble * reducedCost = reinterpret_cast<CoinWorkDouble *>(reducedCost_);
+     CoinWorkDouble * dual = reinterpret_cast<CoinWorkDouble *>(dual_);
+     CoinMemcpyN(cost_, numberColumns_, reducedCost);
+     matrix_->transposeTimes(-1.0, dual, reducedCost);
+     // Now modify reduced costs for quadratic
+     CoinWorkDouble quadraticOffset = quadraticDjs(reducedCost,
+                                      solution_, scaleFactor_);
+
+     objectiveValue_ = 0.0;
+     // now look at solution
+     sumPrimalInfeasibilities_ = 0.0;
+     sumDualInfeasibilities_ = 0.0;
+     CoinWorkDouble dualTolerance =  10.0 * dblParam_[ClpDualTolerance];
+     CoinWorkDouble primalTolerance =  dblParam_[ClpPrimalTolerance];
+     CoinWorkDouble primalTolerance2 =  10.0 * dblParam_[ClpPrimalTolerance];
+     worstComplementarity_ = 0.0;
+     complementarityGap_ = 0.0;
+
+     // Done scaled - use permanent regions for output
+     // but internal for bounds
+     const CoinWorkDouble * lower = lower_ + numberColumns_;
+     const CoinWorkDouble * upper = upper_ + numberColumns_;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          CoinWorkDouble infeasibility = 0.0;
+          CoinWorkDouble distanceUp = CoinMin(upper[iRow] -
+                                              rowActivity_[iRow], static_cast<CoinWorkDouble>(1.0e10));
+          CoinWorkDouble distanceDown = CoinMin(rowActivity_[iRow] -
+                                                lower[iRow], static_cast<CoinWorkDouble>(1.0e10));
+          if (distanceUp > primalTolerance2) {
+               CoinWorkDouble value = dual[iRow];
+               // should not be negative
+               if (value < -dualTolerance) {
+                    sumDualInfeasibilities_ += -dualTolerance - value;
+                    value = - value * distanceUp;
+                    if (value > worstComplementarity_)
+                         worstComplementarity_ = value;
+                    complementarityGap_ += value;
+               }
+          }
+          if (distanceDown > primalTolerance2) {
+               CoinWorkDouble value = dual[iRow];
+               // should not be positive
+               if (value > dualTolerance) {
+                    sumDualInfeasibilities_ += value - dualTolerance;
+                    value =  value * distanceDown;
+                    if (value > worstComplementarity_)
+                         worstComplementarity_ = value;
+                    complementarityGap_ += value;
+               }
+          }
+          if (rowActivity_[iRow] > upper[iRow]) {
+               infeasibility = rowActivity_[iRow] - upper[iRow];
+          } else if (rowActivity_[iRow] < lower[iRow]) {
+               infeasibility = lower[iRow] - rowActivity_[iRow];
+          }
+          if (infeasibility > primalTolerance) {
+               sumPrimalInfeasibilities_ += infeasibility - primalTolerance;
+          }
+     }
+     lower = lower_;
+     upper = upper_;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          CoinWorkDouble infeasibility = 0.0;
+          objectiveValue_ += cost_[iColumn] * columnActivity_[iColumn];
+          CoinWorkDouble distanceUp = CoinMin(upper[iColumn] -
+                                              columnActivity_[iColumn], static_cast<CoinWorkDouble>(1.0e10));
+          CoinWorkDouble distanceDown = CoinMin(columnActivity_[iColumn] -
+                                                lower[iColumn], static_cast<CoinWorkDouble>(1.0e10));
+          if (distanceUp > primalTolerance2) {
+               CoinWorkDouble value = reducedCost[iColumn];
+               // should not be negative
+               if (value < -dualTolerance) {
+                    sumDualInfeasibilities_ += -dualTolerance - value;
+                    value = - value * distanceUp;
+                    if (value > worstComplementarity_)
+                         worstComplementarity_ = value;
+                    complementarityGap_ += value;
+               }
+          }
+          if (distanceDown > primalTolerance2) {
+               CoinWorkDouble value = reducedCost[iColumn];
+               // should not be positive
+               if (value > dualTolerance) {
+                    sumDualInfeasibilities_ += value - dualTolerance;
+                    value =  value * distanceDown;
+                    if (value > worstComplementarity_)
+                         worstComplementarity_ = value;
+                    complementarityGap_ += value;
+               }
+          }
+          if (columnActivity_[iColumn] > upper[iColumn]) {
+               infeasibility = columnActivity_[iColumn] - upper[iColumn];
+          } else if (columnActivity_[iColumn] < lower[iColumn]) {
+               infeasibility = lower[iColumn] - columnActivity_[iColumn];
+          }
+          if (infeasibility > primalTolerance) {
+               sumPrimalInfeasibilities_ += infeasibility - primalTolerance;
+          }
+     }
+#if COIN_LONG_WORK
+     // ok as packs down
+     CoinMemcpyN(reducedCost, numberColumns_, reducedCost_);
+#endif
+     // add in offset
+     objectiveValue_ += 0.5 * quadraticOffset;
+}
+// Set cholesky (and delete present one)
+void
+ClpInterior::setCholesky(ClpCholeskyBase * cholesky)
+{
+     delete cholesky_;
+     cholesky_ = cholesky;
+}
+/* Borrow model.  This is so we dont have to copy large amounts
+   of data around.  It assumes a derived class wants to overwrite
+   an empty model with a real one - while it does an algorithm.
+   This is same as ClpModel one. */
+void
+ClpInterior::borrowModel(ClpModel & otherModel)
+{
+     ClpModel::borrowModel(otherModel);
+}
+/* Return model - updates any scalars */
+void
+ClpInterior::returnModel(ClpModel & otherModel)
+{
+     ClpModel::returnModel(otherModel);
+}
+// Return number fixed to see if worth presolving
+int
+ClpInterior::numberFixed() const
+{
+     int i;
+     int nFixed = 0;
+     for (i = 0; i < numberColumns_; i++) {
+          if (columnUpper_[i] < 1.0e20 || columnLower_[i] > -1.0e20) {
+               if (columnUpper_[i] > columnLower_[i]) {
+                    if (fixedOrFree(i))
+                         nFixed++;
+               }
+          }
+     }
+     for (i = 0; i < numberRows_; i++) {
+          if (rowUpper_[i] < 1.0e20 || rowLower_[i] > -1.0e20) {
+               if (rowUpper_[i] > rowLower_[i]) {
+                    if (fixedOrFree(i + numberColumns_))
+                         nFixed++;
+               }
+          }
+     }
+     return nFixed;
+}
+// fix variables interior says should be
+void
+ClpInterior::fixFixed(bool reallyFix)
+{
+     // Arrays for change in columns and rhs
+     CoinWorkDouble * columnChange = new CoinWorkDouble[numberColumns_];
+     CoinWorkDouble * rowChange = new CoinWorkDouble[numberRows_];
+     CoinZeroN(columnChange, numberColumns_);
+     CoinZeroN(rowChange, numberRows_);
+     matrix_->times(1.0, columnChange, rowChange);
+     int i;
+     CoinWorkDouble tolerance = primalTolerance();
+     for (i = 0; i < numberColumns_; i++) {
+          if (columnUpper_[i] < 1.0e20 || columnLower_[i] > -1.0e20) {
+               if (columnUpper_[i] > columnLower_[i]) {
+                    if (fixedOrFree(i)) {
+                         if (columnActivity_[i] - columnLower_[i] < columnUpper_[i] - columnActivity_[i]) {
+                              CoinWorkDouble change = columnLower_[i] - columnActivity_[i];
+                              if (CoinAbs(change) < tolerance) {
+                                   if (reallyFix)
+                                        columnUpper_[i] = columnLower_[i];
+                                   columnChange[i] = change;
+                                   columnActivity_[i] = columnLower_[i];
+                              }
+                         } else {
+                              CoinWorkDouble change = columnUpper_[i] - columnActivity_[i];
+                              if (CoinAbs(change) < tolerance) {
+                                   if (reallyFix)
+                                        columnLower_[i] = columnUpper_[i];
+                                   columnChange[i] = change;
+                                   columnActivity_[i] = columnUpper_[i];
+                              }
+                         }
+                    }
+               }
+          }
+     }
+     CoinZeroN(rowChange, numberRows_);
+     matrix_->times(1.0, columnChange, rowChange);
+     // If makes mess of things then don't do
+     CoinWorkDouble newSum = 0.0;
+     for (i = 0; i < numberRows_; i++) {
+          CoinWorkDouble value = rowActivity_[i] + rowChange[i];
+          if (value > rowUpper_[i] + tolerance)
+               newSum += value - rowUpper_[i] - tolerance;
+          else if (value < rowLower_[i] - tolerance)
+               newSum -= value - rowLower_[i] + tolerance;
+     }
+     if (newSum > 1.0e-5 + 1.5 * sumPrimalInfeasibilities_) {
+          // put back and skip changes
+          for (i = 0; i < numberColumns_; i++)
+               columnActivity_[i] -= columnChange[i];
+     } else {
+          CoinZeroN(rowActivity_, numberRows_);
+          matrix_->times(1.0, columnActivity_, rowActivity_);
+          if (reallyFix) {
+               for (i = 0; i < numberRows_; i++) {
+                    if (rowUpper_[i] < 1.0e20 || rowLower_[i] > -1.0e20) {
+                         if (rowUpper_[i] > rowLower_[i]) {
+                              if (fixedOrFree(i + numberColumns_)) {
+                                   if (rowActivity_[i] - rowLower_[i] < rowUpper_[i] - rowActivity_[i]) {
+                                        CoinWorkDouble change = rowLower_[i] - rowActivity_[i];
+                                        if (CoinAbs(change) < tolerance) {
+                                             if (reallyFix)
+                                                  rowUpper_[i] = rowLower_[i];
+                                             rowActivity_[i] = rowLower_[i];
+                                        }
+                                   } else {
+                                        CoinWorkDouble change = rowLower_[i] - rowActivity_[i];
+                                        if (CoinAbs(change) < tolerance) {
+                                             if (reallyFix)
+                                                  rowLower_[i] = rowUpper_[i];
+                                             rowActivity_[i] = rowUpper_[i];
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+          }
+     }
+     delete [] rowChange;
+     delete [] columnChange;
+}
+/* Modifies djs to allow for quadratic.
+   returns quadratic offset */
+CoinWorkDouble
+ClpInterior::quadraticDjs(CoinWorkDouble * djRegion, const CoinWorkDouble * solution,
+                          CoinWorkDouble scaleFactor)
+{
+     CoinWorkDouble quadraticOffset = 0.0;
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+     if (quadraticObj) {
+          CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+          const int * columnQuadratic = quadratic->getIndices();
+          const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+          const int * columnQuadraticLength = quadratic->getVectorLengths();
+          double * quadraticElement = quadratic->getMutableElements();
+          int numberColumns = quadratic->getNumCols();
+          for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+               CoinWorkDouble value = 0.0;
+               for (CoinBigIndex j = columnQuadraticStart[iColumn];
+                         j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                    int jColumn = columnQuadratic[j];
+                    CoinWorkDouble valueJ = solution[jColumn];
+                    CoinWorkDouble elementValue = quadraticElement[j];
+                    //value += valueI*valueJ*elementValue;
+                    value += valueJ * elementValue;
+                    quadraticOffset += solution[iColumn] * valueJ * elementValue;
+               }
+               djRegion[iColumn] += scaleFactor * value;
+          }
+     }
+     return quadraticOffset;
+}
diff --git a/cbits/coin/ClpInterior.hpp b/cbits/coin/ClpInterior.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpInterior.hpp
@@ -0,0 +1,570 @@
+/* $Id: ClpInterior.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Tomlin (pdco)
+   John Forrest (standard predictor-corrector)
+
+   Note JJF has added arrays - this takes more memory but makes
+   flow easier to understand and hopefully easier to extend
+
+ */
+#ifndef ClpInterior_H
+#define ClpInterior_H
+
+#include <iostream>
+#include <cfloat>
+#include "ClpModel.hpp"
+#include "ClpMatrixBase.hpp"
+#include "ClpSolve.hpp"
+#include "CoinDenseVector.hpp"
+class ClpLsqr;
+class ClpPdcoBase;
+/// ******** DATA to be moved into protected section of ClpInterior
+typedef struct {
+     double  atolmin;
+     double  r3norm;
+     double  LSdamp;
+     double* deltay;
+} Info;
+/// ******** DATA to be moved into protected section of ClpInterior
+
+typedef struct {
+     double  atolold;
+     double  atolnew;
+     double  r3ratio;
+     int   istop;
+     int   itncg;
+} Outfo;
+/// ******** DATA to be moved into protected section of ClpInterior
+
+typedef struct {
+     double  gamma;
+     double  delta;
+     int MaxIter;
+     double  FeaTol;
+     double  OptTol;
+     double  StepTol;
+     double  x0min;
+     double  z0min;
+     double  mu0;
+     int   LSmethod;   // 1=Cholesky    2=QR    3=LSQR
+     int   LSproblem;  // See below
+     int LSQRMaxIter;
+     double  LSQRatol1; // Initial  atol
+     double  LSQRatol2; // Smallest atol (unless atol1 is smaller)
+     double  LSQRconlim;
+     int  wait;
+} Options;
+class Lsqr;
+class ClpCholeskyBase;
+// ***** END
+/** This solves LPs using interior point methods
+
+    It inherits from ClpModel and all its arrays are created at
+    algorithm time.
+
+*/
+
+class ClpInterior : public ClpModel {
+     friend void ClpInteriorUnitTest(const std::string & mpsDir,
+                                     const std::string & netlibDir);
+
+public:
+
+     /**@name Constructors and destructor and copy */
+     //@{
+     /// Default constructor
+     ClpInterior (  );
+
+     /// Copy constructor.
+     ClpInterior(const ClpInterior &);
+     /// Copy constructor from model.
+     ClpInterior(const ClpModel &);
+     /** Subproblem constructor.  A subset of whole model is created from the
+         row and column lists given.  The new order is given by list order and
+         duplicates are allowed.  Name and integer information can be dropped
+     */
+     ClpInterior (const ClpModel * wholeModel,
+                  int numberRows, const int * whichRows,
+                  int numberColumns, const int * whichColumns,
+                  bool dropNames = true, bool dropIntegers = true);
+     /// Assignment operator. This copies the data
+     ClpInterior & operator=(const ClpInterior & rhs);
+     /// Destructor
+     ~ClpInterior (  );
+     // Ones below are just ClpModel with some changes
+     /** Loads a problem (the constraints on the
+           rows are given by lower and upper bounds). If a pointer is 0 then the
+           following values are the default:
+           <ul>
+             <li> <code>colub</code>: all columns have upper bound infinity
+             <li> <code>collb</code>: all columns have lower bound 0
+             <li> <code>rowub</code>: all rows have upper bound infinity
+             <li> <code>rowlb</code>: all rows have lower bound -infinity
+         <li> <code>obj</code>: all variables have 0 objective coefficient
+           </ul>
+       */
+     void loadProblem (  const ClpMatrixBase& matrix,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     void loadProblem (  const CoinPackedMatrix& matrix,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+
+     /** Just like the other loadProblem() method except that the matrix is
+       given in a standard column major ordered format (without gaps). */
+     void loadProblem (  const int numcols, const int numrows,
+                         const CoinBigIndex* start, const int* index,
+                         const double* value,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     /// This one is for after presolve to save memory
+     void loadProblem (  const int numcols, const int numrows,
+                         const CoinBigIndex* start, const int* index,
+                         const double* value, const int * length,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     /// Read an mps file from the given filename
+     int readMps(const char *filename,
+                 bool keepNames = false,
+                 bool ignoreErrors = false);
+     /** Borrow model.  This is so we dont have to copy large amounts
+         of data around.  It assumes a derived class wants to overwrite
+         an empty model with a real one - while it does an algorithm.
+         This is same as ClpModel one. */
+     void borrowModel(ClpModel & otherModel);
+     /** Return model - updates any scalars */
+     void returnModel(ClpModel & otherModel);
+     //@}
+
+     /**@name Functions most useful to user */
+     //@{
+     /** Pdco algorithm - see ClpPdco.hpp for method */
+     int pdco();
+     // ** Temporary version
+     int  pdco( ClpPdcoBase * stuff, Options &options, Info &info, Outfo &outfo);
+     /// Primal-Dual Predictor-Corrector barrier
+     int primalDual();
+     //@}
+
+     /**@name most useful gets and sets */
+     //@{
+     /// If problem is primal feasible
+     inline bool primalFeasible() const {
+          return (sumPrimalInfeasibilities_ <= 1.0e-5);
+     }
+     /// If problem is dual feasible
+     inline bool dualFeasible() const {
+          return (sumDualInfeasibilities_ <= 1.0e-5);
+     }
+     /// Current (or last) algorithm
+     inline int algorithm() const {
+          return algorithm_;
+     }
+     /// Set algorithm
+     inline void setAlgorithm(int value) {
+          algorithm_ = value;
+     }
+     /// Sum of dual infeasibilities
+     inline CoinWorkDouble sumDualInfeasibilities() const {
+          return sumDualInfeasibilities_;
+     }
+     /// Sum of primal infeasibilities
+     inline CoinWorkDouble sumPrimalInfeasibilities() const {
+          return sumPrimalInfeasibilities_;
+     }
+     /// dualObjective.
+     inline CoinWorkDouble dualObjective() const {
+          return dualObjective_;
+     }
+     /// primalObjective.
+     inline CoinWorkDouble primalObjective() const {
+          return primalObjective_;
+     }
+     /// diagonalNorm
+     inline CoinWorkDouble diagonalNorm() const {
+          return diagonalNorm_;
+     }
+     /// linearPerturbation
+     inline CoinWorkDouble linearPerturbation() const {
+          return linearPerturbation_;
+     }
+     inline void setLinearPerturbation(CoinWorkDouble value) {
+          linearPerturbation_ = value;
+     }
+     /// projectionTolerance
+     inline CoinWorkDouble projectionTolerance() const {
+          return projectionTolerance_;
+     }
+     inline void setProjectionTolerance(CoinWorkDouble value) {
+          projectionTolerance_ = value;
+     }
+     /// diagonalPerturbation
+     inline CoinWorkDouble diagonalPerturbation() const {
+          return diagonalPerturbation_;
+     }
+     inline void setDiagonalPerturbation(CoinWorkDouble value) {
+          diagonalPerturbation_ = value;
+     }
+     /// gamma
+     inline CoinWorkDouble gamma() const {
+          return gamma_;
+     }
+     inline void setGamma(CoinWorkDouble value) {
+          gamma_ = value;
+     }
+     /// delta
+     inline CoinWorkDouble delta() const {
+          return delta_;
+     }
+     inline void setDelta(CoinWorkDouble value) {
+          delta_ = value;
+     }
+     /// ComplementarityGap
+     inline CoinWorkDouble complementarityGap() const {
+          return complementarityGap_;
+     }
+     //@}
+
+     /**@name most useful gets and sets */
+     //@{
+     /// Largest error on Ax-b
+     inline CoinWorkDouble largestPrimalError() const {
+          return largestPrimalError_;
+     }
+     /// Largest error on basic duals
+     inline CoinWorkDouble largestDualError() const {
+          return largestDualError_;
+     }
+     /// Maximum iterations
+     inline int maximumBarrierIterations() const {
+          return maximumBarrierIterations_;
+     }
+     inline void setMaximumBarrierIterations(int value) {
+          maximumBarrierIterations_ = value;
+     }
+     /// Set cholesky (and delete present one)
+     void setCholesky(ClpCholeskyBase * cholesky);
+     /// Return number fixed to see if worth presolving
+     int numberFixed() const;
+     /** fix variables interior says should be.  If reallyFix false then just
+         set values to exact bounds */
+     void fixFixed(bool reallyFix = true);
+     /// Primal erturbation vector
+     inline CoinWorkDouble * primalR() const {
+          return primalR_;
+     }
+     /// Dual erturbation vector
+     inline CoinWorkDouble * dualR() const {
+          return dualR_;
+     }
+     //@}
+
+protected:
+     /**@name protected methods */
+     //@{
+     /// Does most of deletion
+     void gutsOfDelete();
+     /// Does most of copying
+     void gutsOfCopy(const ClpInterior & rhs);
+     /// Returns true if data looks okay, false if not
+     bool createWorkingData();
+     void deleteWorkingData();
+     /// Sanity check on input rim data
+     bool sanityCheck();
+     ///  This does housekeeping
+     int housekeeping();
+     //@}
+public:
+     /**@name public methods */
+     //@{
+     /// Raw objective value (so always minimize)
+     inline CoinWorkDouble rawObjectiveValue() const {
+          return objectiveValue_;
+     }
+     /// Returns 1 if sequence indicates column
+     inline int isColumn(int sequence) const {
+          return sequence < numberColumns_ ? 1 : 0;
+     }
+     /// Returns sequence number within section
+     inline int sequenceWithin(int sequence) const {
+          return sequence < numberColumns_ ? sequence : sequence - numberColumns_;
+     }
+     /// Checks solution
+     void checkSolution();
+     /** Modifies djs to allow for quadratic.
+         returns quadratic offset */
+     CoinWorkDouble quadraticDjs(CoinWorkDouble * djRegion, const CoinWorkDouble * solution,
+                                 CoinWorkDouble scaleFactor);
+
+     /// To say a variable is fixed
+     inline void setFixed( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 1) ;
+     }
+     inline void clearFixed( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~1) ;
+     }
+     inline bool fixed(int sequence) const {
+          return ((status_[sequence] & 1) != 0);
+     }
+
+     /// To flag a variable
+     inline void setFlagged( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 2) ;
+     }
+     inline void clearFlagged( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~2) ;
+     }
+     inline bool flagged(int sequence) const {
+          return ((status_[sequence] & 2) != 0);
+     }
+
+     /// To say a variable is fixed OR free
+     inline void setFixedOrFree( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 4) ;
+     }
+     inline void clearFixedOrFree( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~4) ;
+     }
+     inline bool fixedOrFree(int sequence) const {
+          return ((status_[sequence] & 4) != 0);
+     }
+
+     /// To say a variable has lower bound
+     inline void setLowerBound( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 8) ;
+     }
+     inline void clearLowerBound( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~8) ;
+     }
+     inline bool lowerBound(int sequence) const {
+          return ((status_[sequence] & 8) != 0);
+     }
+
+     /// To say a variable has upper bound
+     inline void setUpperBound( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 16) ;
+     }
+     inline void clearUpperBound( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~16) ;
+     }
+     inline bool upperBound(int sequence) const {
+          return ((status_[sequence] & 16) != 0);
+     }
+
+     /// To say a variable has fake lower bound
+     inline void setFakeLower( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 32) ;
+     }
+     inline void clearFakeLower( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~32) ;
+     }
+     inline bool fakeLower(int sequence) const {
+          return ((status_[sequence] & 32) != 0);
+     }
+
+     /// To say a variable has fake upper bound
+     inline void setFakeUpper( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 64) ;
+     }
+     inline void clearFakeUpper( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~64) ;
+     }
+     inline bool fakeUpper(int sequence) const {
+          return ((status_[sequence] & 64) != 0);
+     }
+     //@}
+
+////////////////// data //////////////////
+protected:
+
+     /**@name data.  Many arrays have a row part and a column part.
+      There is a single array with both - columns then rows and
+      then normally two arrays pointing to rows and columns.  The
+      single array is the owner of memory
+     */
+     //@{
+     /// Largest error on Ax-b
+     CoinWorkDouble largestPrimalError_;
+     /// Largest error on basic duals
+     CoinWorkDouble largestDualError_;
+     /// Sum of dual infeasibilities
+     CoinWorkDouble sumDualInfeasibilities_;
+     /// Sum of primal infeasibilities
+     CoinWorkDouble sumPrimalInfeasibilities_;
+     /// Worst complementarity
+     CoinWorkDouble worstComplementarity_;
+     ///
+public:
+     CoinWorkDouble xsize_;
+     CoinWorkDouble zsize_;
+protected:
+     /// Working copy of lower bounds (Owner of arrays below)
+     CoinWorkDouble * lower_;
+     /// Row lower bounds - working copy
+     CoinWorkDouble * rowLowerWork_;
+     /// Column lower bounds - working copy
+     CoinWorkDouble * columnLowerWork_;
+     /// Working copy of upper bounds (Owner of arrays below)
+     CoinWorkDouble * upper_;
+     /// Row upper bounds - working copy
+     CoinWorkDouble * rowUpperWork_;
+     /// Column upper bounds - working copy
+     CoinWorkDouble * columnUpperWork_;
+     /// Working copy of objective
+     CoinWorkDouble * cost_;
+public:
+     /// Rhs
+     CoinWorkDouble * rhs_;
+     CoinWorkDouble * x_;
+     CoinWorkDouble * y_;
+     CoinWorkDouble * dj_;
+protected:
+     /// Pointer to Lsqr object
+     ClpLsqr * lsqrObject_;
+     /// Pointer to stuff
+     ClpPdcoBase * pdcoStuff_;
+     /// Below here is standard barrier stuff
+     /// mu.
+     CoinWorkDouble mu_;
+     /// objectiveNorm.
+     CoinWorkDouble objectiveNorm_;
+     /// rhsNorm.
+     CoinWorkDouble rhsNorm_;
+     /// solutionNorm.
+     CoinWorkDouble solutionNorm_;
+     /// dualObjective.
+     CoinWorkDouble dualObjective_;
+     /// primalObjective.
+     CoinWorkDouble primalObjective_;
+     /// diagonalNorm.
+     CoinWorkDouble diagonalNorm_;
+     /// stepLength
+     CoinWorkDouble stepLength_;
+     /// linearPerturbation
+     CoinWorkDouble linearPerturbation_;
+     /// diagonalPerturbation
+     CoinWorkDouble diagonalPerturbation_;
+     // gamma from Saunders and Tomlin regularized
+     CoinWorkDouble gamma_;
+     // delta from Saunders and Tomlin regularized
+     CoinWorkDouble delta_;
+     /// targetGap
+     CoinWorkDouble targetGap_;
+     /// projectionTolerance
+     CoinWorkDouble projectionTolerance_;
+     /// maximumRHSError.  maximum Ax
+     CoinWorkDouble maximumRHSError_;
+     /// maximumBoundInfeasibility.
+     CoinWorkDouble maximumBoundInfeasibility_;
+     /// maximumDualError.
+     CoinWorkDouble maximumDualError_;
+     /// diagonalScaleFactor.
+     CoinWorkDouble diagonalScaleFactor_;
+     /// scaleFactor.  For scaling objective
+     CoinWorkDouble scaleFactor_;
+     /// actualPrimalStep
+     CoinWorkDouble actualPrimalStep_;
+     /// actualDualStep
+     CoinWorkDouble actualDualStep_;
+     /// smallestInfeasibility
+     CoinWorkDouble smallestInfeasibility_;
+     /// historyInfeasibility.
+#define LENGTH_HISTORY 5
+     CoinWorkDouble historyInfeasibility_[LENGTH_HISTORY];
+     /// complementarityGap.
+     CoinWorkDouble complementarityGap_;
+     /// baseObjectiveNorm
+     CoinWorkDouble baseObjectiveNorm_;
+     /// worstDirectionAccuracy
+     CoinWorkDouble worstDirectionAccuracy_;
+     /// maximumRHSChange
+     CoinWorkDouble maximumRHSChange_;
+     /// errorRegion. i.e. Ax
+     CoinWorkDouble * errorRegion_;
+     /// rhsFixRegion.
+     CoinWorkDouble * rhsFixRegion_;
+     /// upperSlack
+     CoinWorkDouble * upperSlack_;
+     /// lowerSlack
+     CoinWorkDouble * lowerSlack_;
+     /// diagonal
+     CoinWorkDouble * diagonal_;
+     /// solution
+     CoinWorkDouble * solution_;
+     /// work array
+     CoinWorkDouble * workArray_;
+     /// delta X
+     CoinWorkDouble * deltaX_;
+     /// delta Y
+     CoinWorkDouble * deltaY_;
+     /// deltaZ.
+     CoinWorkDouble * deltaZ_;
+     /// deltaW.
+     CoinWorkDouble * deltaW_;
+     /// deltaS.
+     CoinWorkDouble * deltaSU_;
+     CoinWorkDouble * deltaSL_;
+     /// Primal regularization array
+     CoinWorkDouble * primalR_;
+     /// Dual regularization array
+     CoinWorkDouble * dualR_;
+     /// rhs B
+     CoinWorkDouble * rhsB_;
+     /// rhsU.
+     CoinWorkDouble * rhsU_;
+     /// rhsL.
+     CoinWorkDouble * rhsL_;
+     /// rhsZ.
+     CoinWorkDouble * rhsZ_;
+     /// rhsW.
+     CoinWorkDouble * rhsW_;
+     /// rhs C
+     CoinWorkDouble * rhsC_;
+     /// zVec
+     CoinWorkDouble * zVec_;
+     /// wVec
+     CoinWorkDouble * wVec_;
+     /// cholesky.
+     ClpCholeskyBase * cholesky_;
+     /// numberComplementarityPairs i.e. ones with lower and/or upper bounds (not fixed)
+     int numberComplementarityPairs_;
+     /// numberComplementarityItems_ i.e. number of active bounds
+     int numberComplementarityItems_;
+     /// Maximum iterations
+     int maximumBarrierIterations_;
+     /// gonePrimalFeasible.
+     bool gonePrimalFeasible_;
+     /// goneDualFeasible.
+     bool goneDualFeasible_;
+     /// Which algorithm being used
+     int algorithm_;
+     //@}
+};
+//#############################################################################
+/** A function that tests the methods in the ClpInterior class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging.
+
+    It also does some testing of ClpFactorization class
+ */
+void
+ClpInteriorUnitTest(const std::string & mpsDir,
+                    const std::string & netlibDir);
+
+
+#endif
diff --git a/cbits/coin/ClpLinearObjective.cpp b/cbits/coin/ClpLinearObjective.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpLinearObjective.cpp
@@ -0,0 +1,288 @@
+/* $Id: ClpLinearObjective.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpLinearObjective.hpp"
+#include "CoinHelperFunctions.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpLinearObjective::ClpLinearObjective ()
+     : ClpObjective()
+{
+     type_ = 1;
+     objective_ = NULL;
+     numberColumns_ = 0;
+}
+
+//-------------------------------------------------------------------
+// Useful Constructor
+//-------------------------------------------------------------------
+ClpLinearObjective::ClpLinearObjective (const double * objective ,
+                                        int numberColumns)
+     : ClpObjective()
+{
+     type_ = 1;
+     numberColumns_ = numberColumns;
+     objective_ = CoinCopyOfArray(objective, numberColumns_, 0.0);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpLinearObjective::ClpLinearObjective (const ClpLinearObjective & rhs)
+     : ClpObjective(rhs)
+{
+     numberColumns_ = rhs.numberColumns_;
+     objective_ = CoinCopyOfArray(rhs.objective_, numberColumns_);
+}
+/* Subset constructor.  Duplicates are allowed
+   and order is as given.
+*/
+ClpLinearObjective::ClpLinearObjective (const ClpLinearObjective &rhs,
+                                        int numberColumns,
+                                        const int * whichColumn)
+     : ClpObjective(rhs)
+{
+     objective_ = NULL;
+     numberColumns_ = 0;
+     if (numberColumns > 0) {
+          // check valid lists
+          int numberBad = 0;
+          int i;
+          for (i = 0; i < numberColumns; i++)
+               if (whichColumn[i] < 0 || whichColumn[i] >= rhs.numberColumns_)
+                    numberBad++;
+          if (numberBad)
+               throw CoinError("bad column list", "subset constructor",
+                               "ClpLinearObjective");
+          numberColumns_ = numberColumns;
+          objective_ = new double[numberColumns_];
+          for (i = 0; i < numberColumns_; i++)
+               objective_[i] = rhs.objective_[whichColumn[i]];
+     }
+}
+
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpLinearObjective::~ClpLinearObjective ()
+{
+     delete [] objective_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpLinearObjective &
+ClpLinearObjective::operator=(const ClpLinearObjective& rhs)
+{
+     if (this != &rhs) {
+          ClpObjective::operator=(rhs);
+          numberColumns_ = rhs.numberColumns_;
+          delete [] objective_;
+          objective_ = CoinCopyOfArray(rhs.objective_, numberColumns_);
+     }
+     return *this;
+}
+
+// Returns gradient
+double *
+ClpLinearObjective::gradient(const ClpSimplex * /*model*/,
+                             const double * /*solution*/, double & offset,
+                             bool /*refresh*/,
+                             int /*includeLinear*/)
+{
+     // not sure what to do about scaling
+     //assert (!model);
+     //assert (includeLinear==2); //otherwise need to return all zeros
+     offset = 0.0;
+     return objective_;
+}
+
+/* Returns reduced gradient.Returns an offset (to be added to current one).
+ */
+double
+ClpLinearObjective::reducedGradient(ClpSimplex * model, double * region,
+                                    bool /*useFeasibleCosts*/)
+{
+     int numberRows = model->numberRows();
+     //work space
+     CoinIndexedVector  * workSpace = model->rowArray(0);
+
+     CoinIndexedVector arrayVector;
+     arrayVector.reserve(numberRows + 1);
+
+     int iRow;
+#ifdef CLP_DEBUG
+     workSpace->checkClear();
+#endif
+     double * array = arrayVector.denseVector();
+     int * index = arrayVector.getIndices();
+     int number = 0;
+     const double * cost = model->costRegion();
+     //assert (!useFeasibleCosts);
+     const int * pivotVariable = model->pivotVariable();
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          int iPivot = pivotVariable[iRow];
+          double value = cost[iPivot];
+          if (value) {
+               array[iRow] = value;
+               index[number++] = iRow;
+          }
+     }
+     arrayVector.setNumElements(number);
+
+     int numberColumns = model->numberColumns();
+
+     // Btran basic costs
+     double * work = workSpace->denseVector();
+     model->factorization()->updateColumnTranspose(workSpace, &arrayVector);
+     ClpFillN(work, numberRows, 0.0);
+     // now look at dual solution
+     double * rowReducedCost = region + numberColumns;
+     double * dual = rowReducedCost;
+     double * rowCost = model->costRegion(0);
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          dual[iRow] = array[iRow];
+     }
+     double * dj = region;
+     ClpDisjointCopyN(model->costRegion(1), numberColumns, dj);
+     model->transposeTimes(-1.0, dual, dj);
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          // slack
+          double value = dual[iRow];
+          value += rowCost[iRow];
+          rowReducedCost[iRow] = value;
+     }
+     return 0.0;
+}
+/* Returns step length which gives minimum of objective for
+   solution + theta * change vector up to maximum theta.
+
+   arrays are numberColumns+numberRows
+*/
+double
+ClpLinearObjective::stepLength(ClpSimplex * model,
+                               const double * solution,
+                               const double * change,
+                               double maximumTheta,
+                               double & currentObj,
+                               double & predictedObj,
+                               double & thetaObj)
+{
+     const double * cost = model->costRegion();
+     double delta = 0.0;
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     currentObj = 0.0;
+     thetaObj = 0.0;
+     for (int iColumn = 0; iColumn < numberColumns + numberRows; iColumn++) {
+          delta += cost[iColumn] * change[iColumn];
+          currentObj += cost[iColumn] * solution[iColumn];
+     }
+     thetaObj = currentObj + delta * maximumTheta;
+     predictedObj = currentObj + delta * maximumTheta;
+     if (delta < 0.0) {
+          return maximumTheta;
+     } else {
+          printf("odd linear direction %g\n", delta);
+          return 0.0;
+     }
+}
+// Return objective value (without any ClpModel offset) (model may be NULL)
+double
+ClpLinearObjective::objectiveValue(const ClpSimplex * model, const double * solution) const
+{
+     const double * cost = objective_;
+     if (model && model->costRegion())
+          cost = model->costRegion();
+     double currentObj = 0.0;
+     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          currentObj += cost[iColumn] * solution[iColumn];
+     }
+     return currentObj;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpObjective * ClpLinearObjective::clone() const
+{
+     return new ClpLinearObjective(*this);
+}
+/* Subset clone.  Duplicates are allowed
+   and order is as given.
+*/
+ClpObjective *
+ClpLinearObjective::subsetClone (int numberColumns,
+                                 const int * whichColumns) const
+{
+     return new ClpLinearObjective(*this, numberColumns, whichColumns);
+}
+// Resize objective
+void
+ClpLinearObjective::resize(int newNumberColumns)
+{
+     if (numberColumns_ != newNumberColumns) {
+          int i;
+          double * newArray = new double[newNumberColumns];
+          if (objective_)
+               CoinMemcpyN(objective_, CoinMin(newNumberColumns, numberColumns_), newArray);
+          delete [] objective_;
+          objective_ = newArray;
+          for (i = numberColumns_; i < newNumberColumns; i++)
+               objective_[i] = 0.0;
+          numberColumns_ = newNumberColumns;
+     }
+
+}
+// Delete columns in  objective
+void
+ClpLinearObjective::deleteSome(int numberToDelete, const int * which)
+{
+     if (objective_) {
+          int i ;
+          char * deleted = new char[numberColumns_];
+          int numberDeleted = 0;
+          CoinZeroN(deleted, numberColumns_);
+          for (i = 0; i < numberToDelete; i++) {
+               int j = which[i];
+               if (j >= 0 && j < numberColumns_ && !deleted[j]) {
+                    numberDeleted++;
+                    deleted[j] = 1;
+               }
+          }
+          int newNumberColumns = numberColumns_ - numberDeleted;
+          double * newArray = new double[newNumberColumns];
+          int put = 0;
+          for (i = 0; i < numberColumns_; i++) {
+               if (!deleted[i]) {
+                    newArray[put++] = objective_[i];
+               }
+          }
+          delete [] objective_;
+          objective_ = newArray;
+          delete [] deleted;
+          numberColumns_ = newNumberColumns;
+     }
+}
+// Scale objective
+void
+ClpLinearObjective::reallyScale(const double * columnScale)
+{
+     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          objective_[iColumn] *= columnScale[iColumn];
+     }
+}
+
diff --git a/cbits/coin/ClpLinearObjective.hpp b/cbits/coin/ClpLinearObjective.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpLinearObjective.hpp
@@ -0,0 +1,103 @@
+/* $Id: ClpLinearObjective.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpLinearObjective_H
+#define ClpLinearObjective_H
+
+#include "ClpObjective.hpp"
+
+//#############################################################################
+
+/** Linear Objective Class
+
+*/
+
+class ClpLinearObjective : public ClpObjective {
+
+public:
+
+     ///@name Stuff
+     //@{
+
+     /** Returns objective coefficients.
+       
+       Offset is always set to 0.0. All other parameters unused.
+     */
+     virtual double * gradient(const ClpSimplex * model,
+                               const double * solution, double & offset, bool refresh,
+                               int includeLinear = 2);
+     /** Returns reduced gradient.Returns an offset (to be added to current one).
+     */
+     virtual double reducedGradient(ClpSimplex * model, double * region,
+                                    bool useFeasibleCosts);
+     /** Returns step length which gives minimum of objective for
+         solution + theta * change vector up to maximum theta.
+
+         arrays are numberColumns+numberRows
+         Also sets current objective, predicted and at maximumTheta
+     */
+     virtual double stepLength(ClpSimplex * model,
+                               const double * solution,
+                               const double * change,
+                               double maximumTheta,
+                               double & currentObj,
+                               double & predictedObj,
+                               double & thetaObj);
+     /// Return objective value (without any ClpModel offset) (model may be NULL)
+     virtual double objectiveValue(const ClpSimplex * model, const double * solution) const ;
+     /// Resize objective
+     virtual void resize(int newNumberColumns) ;
+     /// Delete columns in  objective
+     virtual void deleteSome(int numberToDelete, const int * which) ;
+     /// Scale objective
+     virtual void reallyScale(const double * columnScale) ;
+
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpLinearObjective();
+
+     /// Constructor from objective
+     ClpLinearObjective(const double * objective, int numberColumns);
+
+     /// Copy constructor
+     ClpLinearObjective(const ClpLinearObjective &);
+     /** Subset constructor.  Duplicates are allowed
+         and order is as given.
+     */
+     ClpLinearObjective (const ClpLinearObjective &rhs, int numberColumns,
+                         const int * whichColumns) ;
+
+     /// Assignment operator
+     ClpLinearObjective & operator=(const ClpLinearObjective& rhs);
+
+     /// Destructor
+     virtual ~ClpLinearObjective ();
+
+     /// Clone
+     virtual ClpObjective * clone() const;
+     /** Subset clone.  Duplicates are allowed
+         and order is as given.
+     */
+     virtual ClpObjective * subsetClone (int numberColumns,
+                                         const int * whichColumns) const;
+
+     //@}
+
+     //---------------------------------------------------------------------------
+
+private:
+     ///@name Private member data
+     /// Objective
+     double * objective_;
+     /// number of columns
+     int numberColumns_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpLsqr.cpp b/cbits/coin/ClpLsqr.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpLsqr.cpp
@@ -0,0 +1,391 @@
+/* $Id: ClpLsqr.cpp 1941 2013-04-10 16:52:27Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "ClpLsqr.hpp"
+#include "ClpPdco.hpp"
+
+
+void ClpLsqr::do_lsqr( CoinDenseVector<double> &b,
+                       double damp, double atol, double btol, double conlim, int itnlim,
+                       bool show, Info info, CoinDenseVector<double> &x , int *istop,
+                       int *itn, Outfo *outfo, bool precon, CoinDenseVector<double> &Pr)
+{
+
+     /**
+     Special version of LSQR for use with pdco.m.
+     It continues with a reduced atol if a pdco-specific test isn't
+     satisfied with the input atol.
+     */
+
+//     Initialize.
+     static char term_msg[8][80] = {
+          "The exact solution is x = 0",
+          "The residual Ax - b is small enough, given ATOL and BTOL",
+          "The least squares error is small enough, given ATOL",
+          "The estimated condition number has exceeded CONLIM",
+          "The residual Ax - b is small enough, given machine precision",
+          "The least squares error is small enough, given machine precision",
+          "The estimated condition number has exceeded machine precision",
+          "The iteration limit has been reached"
+     };
+
+     //  printf("***************** Entering LSQR *************\n");
+     assert (model_);
+
+     char str1[100], str2[100], str3[100], str4[100], head1[100], head2[100];
+
+     int n = ncols_;     // set  m,n from lsqr object
+
+     *itn     = 0;
+     *istop   = 0;
+     double ctol   = 0;
+     if (conlim > 0) ctol = 1 / conlim;
+
+     double anorm  = 0;
+     double acond  = 0;
+     double ddnorm = 0;
+     double xnorm  = 0;
+     double xxnorm = 0;
+     double z      = 0;
+     double cs2    = -1;
+     double sn2    = 0;
+
+     // Set up the first vectors u and v for the bidiagonalization.
+     // These satisfy  beta*u = b,  alfa*v = A'u.
+
+     CoinDenseVector<double> u(b);
+     CoinDenseVector<double> v(n, 0.0);
+     x.clear();
+     double alfa   = 0;
+     double beta = u.twoNorm();
+     if (beta > 0) {
+          u = (1 / beta) * u;
+          matVecMult( 2, v, u );
+          if (precon)
+               v = v * Pr;
+          alfa = v.twoNorm();
+     }
+     if (alfa > 0) {
+          v.scale(1 / alfa);
+     }
+     CoinDenseVector<double> w(v);
+
+     double arnorm = alfa * beta;
+     if (arnorm == 0) {
+          printf("  %s\n\n", term_msg[0]);
+          return;
+     }
+
+     double rhobar = alfa;
+     double phibar = beta;
+     double bnorm  = beta;
+     double rnorm  = beta;
+     sprintf(head1, "   Itn      x(1)      Function");
+     sprintf(head2, " Compatible   LS      Norm A   Cond A");
+
+     if (show) {
+          printf(" %s%s\n", head1, head2);
+          double test1  = 1;
+          double test2  = alfa / beta;
+          sprintf(str1, "%6d %12.5e %10.3e",   *itn, x[0], rnorm );
+          sprintf(str2, "  %8.1e  %8.1e",       test1, test2 );
+          printf("%s%s\n", str1, str2);
+     }
+
+     //----------------------------------------------------------------
+     // Main iteration loop.
+     //----------------------------------------------------------------
+     while (*itn < itnlim) {
+          *itn += 1;
+          // Perform the next step of the bidiagonalization to obtain the
+          // next beta, u, alfa, v.  These satisfy the relations
+          // beta*u  =  a*v   -  alfa*u,
+          // alfa*v  =  A'*u  -  beta*v.
+
+          u.scale((-alfa));
+          if (precon) {
+               CoinDenseVector<double> pv(v * Pr);
+               matVecMult( 1, u, pv);
+          } else {
+               matVecMult( 1, u, v);
+          }
+          beta = u.twoNorm();
+          if (beta > 0) {
+               u.scale((1 / beta));
+               anorm = sqrt(anorm * anorm + alfa * alfa + beta * beta +  damp * damp);
+               v.scale((-beta));
+               CoinDenseVector<double> vv(n);
+               vv.clear();
+               matVecMult( 2, vv, u );
+               if (precon)
+                    vv = vv * Pr;
+               v = v + vv;
+               alfa  = v.twoNorm();
+               if (alfa > 0)
+                    v.scale((1 / alfa));
+          }
+
+          // Use a plane rotation to eliminate the damping parameter.
+          // This alters the diagonal (rhobar) of the lower-bidiagonal matrix.
+
+          double rhobar1 = sqrt(rhobar * rhobar + damp * damp);
+          double cs1     = rhobar / rhobar1;
+          double sn1     = damp   / rhobar1;
+          double psi     = sn1 * phibar;
+          phibar       *= cs1;
+
+          // Use a plane rotation to eliminate the subdiagonal element (beta)
+          // of the lower-bidiagonal matrix, giving an upper-bidiagonal matrix.
+
+          double rho     = sqrt(rhobar1 * rhobar1 +  beta * beta);
+          double cs      =   rhobar1 / rho;
+          double sn      =   beta   / rho;
+          double theta   =   sn * alfa;
+          rhobar  = - cs * alfa;
+          double phi     =   cs * phibar;
+          phibar  =   sn * phibar;
+          double tau     =   sn * phi;
+
+          // Update x and w.
+
+          double t1      =   phi  / rho;
+          double t2      = - theta / rho;
+          //    dk           =   ((1/rho)*w);
+
+          double w_norm = w.twoNorm();
+          x       = x      +  t1 * w;
+          w       = v      +  t2 * w;
+          ddnorm  = ddnorm +  (w_norm / rho) * (w_norm / rho);
+          // if wantvar, var = var  +  dk.*dk; end
+
+          // Use a plane rotation on the right to eliminate the
+          // super-diagonal element (theta) of the upper-bidiagonal matrix.
+          // Then use the result to estimate  norm(x).
+
+          double delta   =   sn2 * rho;
+          double gambar  = - cs2 * rho;
+          double rhs     =   phi  -  delta * z;
+          double zbar    =   rhs / gambar;
+          xnorm   =   sqrt(xxnorm + zbar * zbar);
+          double gamma   =   sqrt(gambar * gambar + theta * theta);
+          cs2     =   gambar / gamma;
+          sn2     =   theta  / gamma;
+          z       =   rhs    / gamma;
+          xxnorm  =   xxnorm  +  z * z;
+
+          // Test for convergence.
+          // First, estimate the condition of the matrix  Abar,
+          // and the norms of  rbar  and  Abar'rbar.
+
+          acond   =   anorm * sqrt( ddnorm );
+          double res1    =   phibar * phibar;
+          double res2    =   res1  +  psi * psi;
+          rnorm   =   sqrt( res1 + res2 );
+          arnorm  =   alfa * fabs( tau );
+
+          // Now use these norms to estimate certain other quantities,
+          // some of which will be small near a solution.
+
+          double test1   =   rnorm / bnorm;
+          double test2   =   arnorm / ( anorm * rnorm );
+          double test3   =       1 / acond;
+          t1      =   test1 / (1    +  anorm * xnorm / bnorm);
+          double rtol    =   btol  +  atol *  anorm * xnorm / bnorm;
+
+          // The following tests guard against extremely small values of
+          // atol, btol  or  ctol.  (The user may have set any or all of
+          // the parameters  atol, btol, conlim  to 0.)
+          // The effect is equivalent to the normal tests using
+          // atol = eps,  btol = eps,  conlim = 1/eps.
+
+          if (*itn >= itnlim)
+               *istop = 7;
+          if (1 + test3  <= 1)
+               *istop = 6;
+          if (1 + test2  <= 1)
+               *istop = 5;
+          if (1 + t1     <= 1)
+               *istop = 4;
+
+          // Allow for tolerances set by the user.
+
+          if  (test3 <= ctol)
+               *istop = 3;
+          if  (test2 <= atol)
+               *istop = 2;
+          if  (test1 <= rtol)
+               *istop = 1;
+
+          //-------------------------------------------------------------------
+          // SPECIAL TEST THAT DEPENDS ON pdco.m.
+          // Aname in pdco   is  iw in lsqr.
+          // dy              is  x
+          // Other stuff     is in info.
+
+          // We allow for diagonal preconditioning in pdDDD3.
+          //-------------------------------------------------------------------
+          if (*istop > 0) {
+               double r3new     = arnorm;
+               double r3ratio   = r3new / info.r3norm;
+               double atolold   = atol;
+               double atolnew   = atol;
+
+               if (atol > info.atolmin) {
+                    if     (r3ratio <= 0.1) {  // dy seems good
+                         // Relax
+                    } else if (r3ratio <= 0.5) { // Accept dy but make next one more accurate.
+                         atolnew = atolnew * 0.1;
+                    } else {                    // Recompute dy more accurately
+                         if (show) {
+                              printf("\n                                ");
+                              printf("                                \n");
+                              printf(" %5.1f%7d%7.3f", log10(atolold), *itn, r3ratio);
+                         }
+                         atol    = atol * 0.1;
+                         atolnew = atol;
+                         *istop   = 0;
+                    }
+
+                    outfo->atolold = atolold;
+                    outfo->atolnew = atolnew;
+                    outfo->r3ratio = r3ratio;
+               }
+
+               //-------------------------------------------------------------------
+               // See if it is time to print something.
+               //-------------------------------------------------------------------
+               int prnt = 0;
+               if (n     <= 40       ) prnt = 1;
+               if (*itn   <= 10       ) prnt = 1;
+               if (*itn   >= itnlim - 10) prnt = 1;
+               if (*itn % 10 == 0  ) prnt = 1;
+               if (test3 <=  2 * ctol  ) prnt = 1;
+               if (test2 <= 10 * atol  ) prnt = 1;
+               if (test1 <= 10 * rtol  ) prnt = 1;
+               if (*istop !=  0       ) prnt = 1;
+
+               if (prnt == 1) {
+                    if (show) {
+                         sprintf(str1, "   %6d %12.5e %10.3e",   *itn, x[0], rnorm );
+                         sprintf(str2, "  %8.1e %8.1e",       test1, test2 );
+                         sprintf(str3, " %8.1e %8.1e",        anorm, acond );
+                         printf("%s%s%s\n", str1, str2, str3);
+                    }
+               }
+               if (*istop > 0)
+                    break;
+          }
+     }
+     // End of iteration loop.
+     // Print the stopping condition.
+
+     if (show) {
+          printf("\n LSQR finished\n");
+          //    disp(msg(istop+1,:))
+          //    disp(' ')
+          printf("%s\n", term_msg[*istop]);
+          sprintf(str1, "istop  =%8d     itn    =%8d",      *istop, *itn    );
+          sprintf(str2, "anorm  =%8.1e   acond  =%8.1e",  anorm, acond  );
+          sprintf(str3, "rnorm  =%8.1e   arnorm =%8.1e",  rnorm, arnorm );
+          sprintf(str4, "bnorm  =%8.1e   xnorm  =%8.1e",  bnorm, xnorm  );
+          printf("%s %s\n", str1, str2);
+          printf("%s %s\n", str3, str4);
+     }
+}
+
+
+
+
+void ClpLsqr::matVecMult( int mode, CoinDenseVector<double> *x, CoinDenseVector<double> *y)
+{
+     int n = model_->numberColumns();
+     int m = model_->numberRows();
+     CoinDenseVector<double> *temp = new CoinDenseVector<double>(n, 0.0);
+     double *t_elts = temp->getElements();
+     double *x_elts = x->getElements();
+     double *y_elts = y->getElements();
+     ClpPdco * pdcoModel = (ClpPdco *) model_;
+     if (mode == 1) {
+          pdcoModel->matVecMult( 2, temp, y);
+          for (int k = 0; k < n; k++)
+               x_elts[k] += (diag1_[k] * t_elts[k]);
+          for (int k = 0; k < m; k++)
+               x_elts[n+k] += (diag2_ * y_elts[k]);
+     } else {
+          for (int k = 0; k < n; k++)
+               t_elts[k] = diag1_[k] * y_elts[k];
+          pdcoModel->matVecMult( 1, x, temp);
+          for (int k = 0; k < m; k++)
+               x_elts[k] += diag2_ * y_elts[n+k];
+     }
+     delete temp;
+     return;
+}
+
+void ClpLsqr::matVecMult( int mode, CoinDenseVector<double> &x, CoinDenseVector<double> &y)
+{
+     matVecMult( mode, &x, &y);
+     return;
+}
+/* Default constructor */
+ClpLsqr::ClpLsqr() :
+     nrows_(0),
+     ncols_(0),
+     model_(NULL),
+     diag1_(NULL),
+     diag2_(0.0)
+{}
+
+/* Constructor for use with Pdco model (note modified for pdco!!!!) */
+ClpLsqr::ClpLsqr(ClpInterior *model) :
+     diag1_(NULL),
+     diag2_(0.0)
+{
+     model_ = model;
+     nrows_ = model->numberRows() + model->numberColumns();
+     ncols_ = model->numberRows();
+}
+/** Destructor */
+ClpLsqr::~ClpLsqr()
+{
+     // delete [] diag1_; no as we just borrowed it
+}
+bool
+ClpLsqr::setParam(char *parmName, int parmValue)
+{
+     std::cout << "Set lsqr integer parameter " << parmName << "to " << parmValue
+               << std::endl;
+     if ( strcmp(parmName, "nrows") == 0) {
+          nrows_ = parmValue;
+          return 1;
+     } else if ( strcmp(parmName, "ncols") == 0) {
+          ncols_ = parmValue;
+          return 1;
+     }
+     std::cout << "Attempt to set unknown integer parameter name " << parmName << std::endl;
+     return 0;
+}
+ClpLsqr::ClpLsqr(const ClpLsqr &rhs) :
+     nrows_(rhs.nrows_),
+     ncols_(rhs.ncols_),
+     model_(rhs.model_),
+     diag2_(rhs.diag2_)
+{
+     diag1_ = ClpCopyOfArray(rhs.diag1_, nrows_);
+}
+// Assignment operator. This copies the data
+ClpLsqr &
+ClpLsqr::operator=(const ClpLsqr & rhs)
+{
+     if (this != &rhs) {
+          delete [] diag1_;
+          diag1_ = ClpCopyOfArray(rhs.diag1_, nrows_);
+          nrows_ = rhs.nrows_;
+          ncols_ = rhs.ncols_;
+          model_ = rhs.model_;
+          diag2_ = rhs.diag2_;
+     }
+     return *this;
+}
diff --git a/cbits/coin/ClpLsqr.hpp b/cbits/coin/ClpLsqr.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpLsqr.hpp
@@ -0,0 +1,134 @@
+/* $Id: ClpLsqr.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpLsqr_H_
+#define ClpLsqr_H_
+
+#include "CoinDenseVector.hpp"
+
+#include "ClpInterior.hpp"
+
+
+/**
+This class implements LSQR
+
+@verbatim
+ LSQR solves  Ax = b  or  min ||b - Ax||_2  if damp = 0,
+ or   min || (b)  -  (  A   )x ||   otherwise.
+          || (0)     (damp I)  ||2
+ A  is an m by n matrix defined by user provided routines
+ matVecMult(mode, y, x)
+ which performs the matrix-vector operations where y and x
+ are references or pointers to CoinDenseVector objects.
+ If mode = 1, matVecMult  must return  y = Ax   without altering x.
+ If mode = 2, matVecMult  must return  y = A'x  without altering x.
+
+-----------------------------------------------------------------------
+ LSQR uses an iterative (conjugate-gradient-like) method.
+ For further information, see
+ 1. C. C. Paige and M. A. Saunders (1982a).
+    LSQR: An algorithm for sparse linear equations and sparse least squares,
+    ACM TOMS 8(1), 43-71.
+ 2. C. C. Paige and M. A. Saunders (1982b).
+    Algorithm 583.  LSQR: Sparse linear equations and least squares problems,
+    ACM TOMS 8(2), 195-209.
+ 3. M. A. Saunders (1995).  Solution of sparse rectangular systems using
+    LSQR and CRAIG, BIT 35, 588-604.
+
+ Input parameters:
+
+ atol, btol  are stopping tolerances.  If both are 1.0e-9 (say),
+             the final residual norm should be accurate to about 9 digits.
+             (The final x will usually have fewer correct digits,
+             depending on cond(A) and the size of damp.)
+ conlim      is also a stopping tolerance.  lsqr terminates if an estimate
+             of cond(A) exceeds conlim.  For compatible systems Ax = b,
+             conlim could be as large as 1.0e+12 (say).  For least-squares
+             problems, conlim should be less than 1.0e+8.
+             Maximum precision can be obtained by setting
+             atol = btol = conlim = zero, but the number of iterations
+             may then be excessive.
+ itnlim      is an explicit limit on iterations (for safety).
+ show = 1    gives an iteration log,
+ show = 0    suppresses output.
+ info        is a structure special to pdco.m, used to test if
+             was small enough, and continuing if necessary with smaller atol.
+
+
+ Output parameters:
+ x           is the final solution.
+ *istop       gives the reason for termination.
+ *istop       = 1 means x is an approximate solution to Ax = b.
+             = 2 means x approximately solves the least-squares problem.
+ rnorm       = norm(r) if damp = 0, where r = b - Ax,
+             = sqrt( norm(r)**2  +  damp**2 * norm(x)**2 ) otherwise.
+ xnorm       = norm(x).
+ var         estimates diag( inv(A'A) ).  Omitted in this special version.
+ outfo       is a structure special to pdco.m, returning information
+             about whether atol had to be reduced.
+
+ Other potential output parameters:
+ anorm, acond, arnorm, xnorm
+@endverbatim
+ */
+class ClpLsqr {
+private:
+     /**@name Private member data */
+     //@{
+     //@}
+
+public:
+     /**@name Public member data */
+     //@{
+     /// Row dimension of matrix
+     int          nrows_;
+     /// Column dimension of matrix
+     int          ncols_;
+     /// Pointer to Model object for this instance
+     ClpInterior        *model_;
+     /// Diagonal array 1
+     double         *diag1_;
+     /// Constant diagonal 2
+     double         diag2_;
+     //@}
+
+     /**@name Constructors and destructors */
+     /** Default constructor */
+     ClpLsqr();
+
+     /** Constructor for use with Pdco model (note modified for pdco!!!!) */
+     ClpLsqr(ClpInterior *model);
+     /// Copy constructor
+     ClpLsqr(const ClpLsqr &);
+     /// Assignment operator. This copies the data
+     ClpLsqr & operator=(const ClpLsqr & rhs);
+     /** Destructor */
+     ~ClpLsqr();
+     //@}
+
+     /**@name Methods */
+     //@{
+     /// Set an int parameter
+     bool setParam(char *parmName, int parmValue);
+     /// Call the Lsqr algorithm
+     void do_lsqr( CoinDenseVector<double> &b,
+                   double damp, double atol, double btol, double conlim, int itnlim,
+                   bool show, Info info, CoinDenseVector<double> &x , int *istop,
+                   int *itn, Outfo *outfo, bool precon, CoinDenseVector<double> &Pr );
+     /// Matrix-vector multiply - implemented by user
+     void matVecMult( int, CoinDenseVector<double> *, CoinDenseVector<double> *);
+
+     void matVecMult( int, CoinDenseVector<double> &, CoinDenseVector<double> &);
+     /// diag1 - we just borrow as it is part of a CoinDenseVector<double>
+     void borrowDiag1(double * array) {
+          diag1_ = array;
+     };
+     //@}
+};
+#endif
+
+
+
+
diff --git a/cbits/coin/ClpMatrixBase.cpp b/cbits/coin/ClpMatrixBase.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpMatrixBase.cpp
@@ -0,0 +1,629 @@
+/* $Id: ClpMatrixBase.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include <iostream>
+
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "ClpMatrixBase.hpp"
+#include "ClpSimplex.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpMatrixBase::ClpMatrixBase () :
+     rhsOffset_(NULL),
+     startFraction_(0.0),
+     endFraction_(1.0),
+     savedBestDj_(0.0),
+     originalWanted_(0),
+     currentWanted_(0),
+     savedBestSequence_(-1),
+     type_(-1),
+     lastRefresh_(-1),
+     refreshFrequency_(0),
+     minimumObjectsScan_(-1),
+     minimumGoodReducedCosts_(-1),
+     trueSequenceIn_(-1),
+     trueSequenceOut_(-1),
+     skipDualCheck_(false)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpMatrixBase::ClpMatrixBase (const ClpMatrixBase & rhs) :
+     type_(rhs.type_),
+     skipDualCheck_(rhs.skipDualCheck_)
+{
+     startFraction_ = rhs.startFraction_;
+     endFraction_ = rhs.endFraction_;
+     savedBestDj_ = rhs.savedBestDj_;
+     originalWanted_ = rhs.originalWanted_;
+     currentWanted_ = rhs.currentWanted_;
+     savedBestSequence_ = rhs.savedBestSequence_;
+     lastRefresh_ = rhs.lastRefresh_;
+     refreshFrequency_ = rhs.refreshFrequency_;
+     minimumObjectsScan_ = rhs.minimumObjectsScan_;
+     minimumGoodReducedCosts_ = rhs.minimumGoodReducedCosts_;
+     trueSequenceIn_ = rhs.trueSequenceIn_;
+     trueSequenceOut_ = rhs.trueSequenceOut_;
+     skipDualCheck_ = rhs.skipDualCheck_;
+     int numberRows = rhs.getNumRows();
+     if (rhs.rhsOffset_ && numberRows) {
+          rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows);
+     } else {
+          rhsOffset_ = NULL;
+     }
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpMatrixBase::~ClpMatrixBase ()
+{
+     delete [] rhsOffset_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpMatrixBase &
+ClpMatrixBase::operator=(const ClpMatrixBase& rhs)
+{
+     if (this != &rhs) {
+          type_ = rhs.type_;
+          delete [] rhsOffset_;
+          int numberRows = rhs.getNumRows();
+          if (rhs.rhsOffset_ && numberRows) {
+               rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows);
+          } else {
+               rhsOffset_ = NULL;
+          }
+          startFraction_ = rhs.startFraction_;
+          endFraction_ = rhs.endFraction_;
+          savedBestDj_ = rhs.savedBestDj_;
+          originalWanted_ = rhs.originalWanted_;
+          currentWanted_ = rhs.currentWanted_;
+          savedBestSequence_ = rhs.savedBestSequence_;
+          lastRefresh_ = rhs.lastRefresh_;
+          refreshFrequency_ = rhs.refreshFrequency_;
+          minimumObjectsScan_ = rhs.minimumObjectsScan_;
+          minimumGoodReducedCosts_ = rhs.minimumGoodReducedCosts_;
+          trueSequenceIn_ = rhs.trueSequenceIn_;
+          trueSequenceOut_ = rhs.trueSequenceOut_;
+          skipDualCheck_ = rhs.skipDualCheck_;
+     }
+     return *this;
+}
+// And for scaling - default aborts for when scaling not supported
+void
+ClpMatrixBase::times(double scalar,
+                     const double * x, double * y,
+                     const double * rowScale,
+                     const double * /*columnScale*/) const
+{
+     if (rowScale) {
+          std::cerr << "Scaling not supported - ClpMatrixBase" << std::endl;
+          abort();
+     } else {
+          times(scalar, x, y);
+     }
+}
+// And for scaling - default aborts for when scaling not supported
+void
+ClpMatrixBase::transposeTimes(double scalar,
+                              const double * x, double * y,
+                              const double * rowScale,
+                              const double * /*columnScale*/,
+                              double * /*spare*/) const
+{
+     if (rowScale) {
+          std::cerr << "Scaling not supported - ClpMatrixBase" << std::endl;
+          abort();
+     } else {
+          transposeTimes(scalar, x, y);
+     }
+}
+/* Subset clone (without gaps).  Duplicates are allowed
+   and order is as given.
+   Derived classes need not provide this as it may not always make
+   sense */
+ClpMatrixBase *
+ClpMatrixBase::subsetClone (
+     int /*numberRows*/, const int * /*whichRows*/,
+     int /*numberColumns*/, const int * /*whichColumns*/) const
+
+
+{
+     std::cerr << "subsetClone not supported - ClpMatrixBase" << std::endl;
+     abort();
+     return NULL;
+}
+/* Given positive integer weights for each row fills in sum of weights
+   for each column (and slack).
+   Returns weights vector
+   Default returns vector of ones
+*/
+CoinBigIndex *
+ClpMatrixBase::dubiousWeights(const ClpSimplex * model, int * /*inputWeights*/) const
+{
+     int number = model->numberRows() + model->numberColumns();
+     CoinBigIndex * weights = new CoinBigIndex[number];
+     int i;
+     for (i = 0; i < number; i++)
+          weights[i] = 1;
+     return weights;
+}
+#ifndef CLP_NO_VECTOR
+// Append Columns
+void
+ClpMatrixBase::appendCols(int /*number*/,
+                          const CoinPackedVectorBase * const * /*columns*/)
+{
+     std::cerr << "appendCols not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+// Append Rows
+void
+ClpMatrixBase::appendRows(int /*number*/,
+                          const CoinPackedVectorBase * const * /*rows*/)
+{
+     std::cerr << "appendRows not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+#endif
+/* Returns largest and smallest elements of both signs.
+   Largest refers to largest absolute value.
+*/
+void
+ClpMatrixBase::rangeOfElements(double & smallestNegative, double & largestNegative,
+                               double & smallestPositive, double & largestPositive)
+{
+     smallestNegative = 0.0;
+     largestNegative = 0.0;
+     smallestPositive = 0.0;
+     largestPositive = 0.0;
+}
+/* The length of a major-dimension vector. */
+int
+ClpMatrixBase::getVectorLength(int index) const
+{
+     return getVectorLengths()[index];
+}
+// Says whether it can do partial pricing
+bool
+ClpMatrixBase::canDoPartialPricing() const
+{
+     return false; // default is no
+}
+/* Return <code>x *A</code> in <code>z</code> but
+   just for number indices in y.
+   Default cheats with fake CoinIndexedVector and
+   then calls subsetTransposeTimes */
+void
+ClpMatrixBase::listTransposeTimes(const ClpSimplex * model,
+                                  double * x,
+                                  int * y,
+                                  int number,
+                                  double * z) const
+{
+     CoinIndexedVector pi;
+     CoinIndexedVector list;
+     CoinIndexedVector output;
+     int * saveIndices = list.getIndices();
+     list.setNumElements(number);
+     list.setIndexVector(y);
+     double * savePi = pi.denseVector();
+     pi.setDenseVector(x);
+     double * saveOutput = output.denseVector();
+     output.setDenseVector(z);
+     output.setPacked();
+     subsetTransposeTimes(model, &pi, &list, &output);
+     // restore settings
+     list.setIndexVector(saveIndices);
+     pi.setDenseVector(savePi);
+     output.setDenseVector(saveOutput);
+}
+// Partial pricing
+void
+ClpMatrixBase::partialPricing(ClpSimplex * , double , double ,
+                              int & , int & )
+{
+     std::cerr << "partialPricing not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+/* expands an updated column to allow for extra rows which the main
+   solver does not know about and returns number added.  If the arrays are NULL
+   then returns number of extra entries needed.
+
+   This will normally be a no-op - it is in for GUB!
+*/
+int
+ClpMatrixBase::extendUpdated(ClpSimplex * , CoinIndexedVector * , int )
+{
+     return 0;
+}
+/*
+     utility primal function for dealing with dynamic constraints
+     mode=n see ClpGubMatrix.hpp for definition
+     Remember to update here when settled down
+*/
+void
+ClpMatrixBase::primalExpanded(ClpSimplex * , int )
+{
+}
+/*
+     utility dual function for dealing with dynamic constraints
+     mode=n see ClpGubMatrix.hpp for definition
+     Remember to update here when settled down
+*/
+void
+ClpMatrixBase::dualExpanded(ClpSimplex * ,
+                            CoinIndexedVector * ,
+                            double * , int )
+{
+}
+/*
+     general utility function for dealing with dynamic constraints
+     mode=n see ClpGubMatrix.hpp for definition
+     Remember to update here when settled down
+*/
+int
+ClpMatrixBase::generalExpanded(ClpSimplex * model, int mode, int &number)
+{
+     int returnCode = 0;
+     switch (mode) {
+          // Fill in pivotVariable but not for key variables
+     case 0: {
+          int i;
+          int numberBasic = number;
+          int numberColumns = model->numberColumns();
+          // Use different array so can build from true pivotVariable_
+          //int * pivotVariable = model->pivotVariable();
+          int * pivotVariable = model->rowArray(0)->getIndices();
+          for (i = 0; i < numberColumns; i++) {
+               if (model->getColumnStatus(i) == ClpSimplex::basic)
+                    pivotVariable[numberBasic++] = i;
+          }
+          number = numberBasic;
+     }
+     break;
+     // Do initial extra rows + maximum basic
+     case 2: {
+          number = model->numberRows();
+     }
+     break;
+     // To see if can dual or primal
+     case 4: {
+          returnCode = 3;
+     }
+     break;
+     default:
+          break;
+     }
+     return returnCode;
+}
+// Sets up an effective RHS
+void
+ClpMatrixBase::useEffectiveRhs(ClpSimplex * )
+{
+     std::cerr << "useEffectiveRhs not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+/* Returns effective RHS if it is being used.  This is used for long problems
+   or big gub or anywhere where going through full columns is
+   expensive.  This may re-compute */
+double *
+ClpMatrixBase::rhsOffset(ClpSimplex * model, bool forceRefresh, bool
+#ifdef CLP_DEBUG
+                         check
+#endif
+                        )
+{
+     if (rhsOffset_) {
+#ifdef CLP_DEBUG
+          if (check) {
+               // no need - but check anyway
+               // zero out basic
+               int numberRows = model->numberRows();
+               int numberColumns = model->numberColumns();
+               double * solution = new double [numberColumns];
+               double * rhs = new double[numberRows];
+               const double * solutionSlack = model->solutionRegion(0);
+               CoinMemcpyN(model->solutionRegion(), numberColumns, solution);
+               int iRow;
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    if (model->getRowStatus(iRow) != ClpSimplex::basic)
+                         rhs[iRow] = solutionSlack[iRow];
+                    else
+                         rhs[iRow] = 0.0;
+               }
+               for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (model->getColumnStatus(iColumn) == ClpSimplex::basic)
+                         solution[iColumn] = 0.0;
+               }
+               times(-1.0, solution, rhs);
+               delete [] solution;
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    if (fabs(rhs[iRow] - rhsOffset_[iRow]) > 1.0e-3)
+                         printf("** bad effective %d - true %g old %g\n", iRow, rhs[iRow], rhsOffset_[iRow]);
+               }
+          }
+#endif
+          if (forceRefresh || (refreshFrequency_ && model->numberIterations() >=
+                               lastRefresh_ + refreshFrequency_)) {
+               // zero out basic
+               int numberRows = model->numberRows();
+               int numberColumns = model->numberColumns();
+               double * solution = new double [numberColumns];
+               const double * solutionSlack = model->solutionRegion(0);
+               CoinMemcpyN(model->solutionRegion(), numberColumns, solution);
+               for (int iRow = 0; iRow < numberRows; iRow++) {
+                    if (model->getRowStatus(iRow) != ClpSimplex::basic)
+                         rhsOffset_[iRow] = solutionSlack[iRow];
+                    else
+                         rhsOffset_[iRow] = 0.0;
+               }
+               for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (model->getColumnStatus(iColumn) == ClpSimplex::basic)
+                         solution[iColumn] = 0.0;
+               }
+               times(-1.0, solution, rhsOffset_);
+               delete [] solution;
+               lastRefresh_ = model->numberIterations();
+          }
+     }
+     return rhsOffset_;
+}
+/*
+   update information for a pivot (and effective rhs)
+*/
+int
+ClpMatrixBase::updatePivot(ClpSimplex * model, double oldInValue, double )
+{
+     if (rhsOffset_) {
+          // update effective rhs
+          int sequenceIn = model->sequenceIn();
+          int sequenceOut = model->sequenceOut();
+          double * solution = model->solutionRegion();
+          int numberColumns = model->numberColumns();
+          if (sequenceIn == sequenceOut) {
+               if (sequenceIn < numberColumns)
+                    add(model, rhsOffset_, sequenceIn, oldInValue - solution[sequenceIn]);
+          } else {
+               if (sequenceIn < numberColumns)
+                    add(model, rhsOffset_, sequenceIn, oldInValue);
+               if (sequenceOut < numberColumns)
+                    add(model, rhsOffset_, sequenceOut, -solution[sequenceOut]);
+          }
+     }
+     return 0;
+}
+int
+ClpMatrixBase::hiddenRows() const
+{
+     return 0;
+}
+/* Creates a variable.  This is called after partial pricing and may modify matrix.
+   May update bestSequence.
+*/
+void
+ClpMatrixBase::createVariable(ClpSimplex *, int &)
+{
+}
+// Returns reduced cost of a variable
+double
+ClpMatrixBase::reducedCost(ClpSimplex * model, int sequence) const
+{
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     if (sequence < numberRows + numberColumns)
+          return model->djRegion()[sequence];
+     else
+          return savedBestDj_;
+}
+/* Just for debug if odd type matrix.
+   Returns number and sum of primal infeasibilities.
+*/
+int
+ClpMatrixBase::checkFeasible(ClpSimplex * model, double & sum) const
+{
+     int numberRows = model->numberRows();
+     double * rhs = new double[numberRows];
+     int numberColumns = model->numberColumns();
+     int iRow;
+     CoinZeroN(rhs, numberRows);
+     times(1.0, model->solutionRegion(), rhs, model->rowScale(), model->columnScale());
+     int iColumn;
+     int logLevel = model->messageHandler()->logLevel();
+     int numberInfeasible = 0;
+     const double * rowLower = model->lowerRegion(0);
+     const double * rowUpper = model->upperRegion(0);
+     const double * solution;
+     solution = model->solutionRegion(0);
+     double tolerance = model->primalTolerance() * 1.01;
+     sum = 0.0;
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          double value = rhs[iRow];
+          double value2 = solution[iRow];
+          if (logLevel > 3) {
+               if (fabs(value - value2) > 1.0e-8)
+                    printf("Row %d stored %g, computed %g\n", iRow, value2, value);
+          }
+          if (value < rowLower[iRow] - tolerance ||
+                    value > rowUpper[iRow] + tolerance) {
+               numberInfeasible++;
+               sum += CoinMax(rowLower[iRow] - value, value - rowUpper[iRow]);
+          }
+          if (value2 > rowLower[iRow] + tolerance &&
+                    value2 < rowUpper[iRow] - tolerance &&
+                    model->getRowStatus(iRow) != ClpSimplex::basic) {
+               assert (model->getRowStatus(iRow) == ClpSimplex::superBasic);
+          }
+     }
+     const double * columnLower = model->lowerRegion(1);
+     const double * columnUpper = model->upperRegion(1);
+     solution = model->solutionRegion(1);
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          double value = solution[iColumn];
+          if (value < columnLower[iColumn] - tolerance ||
+                    value > columnUpper[iColumn] + tolerance) {
+               numberInfeasible++;
+               sum += CoinMax(columnLower[iColumn] - value, value - columnUpper[iColumn]);
+          }
+          if (value > columnLower[iColumn] + tolerance &&
+                    value < columnUpper[iColumn] - tolerance &&
+                    model->getColumnStatus(iColumn) != ClpSimplex::basic) {
+               assert (model->getColumnStatus(iColumn) == ClpSimplex::superBasic);
+          }
+     }
+     delete [] rhs;
+     return numberInfeasible;
+}
+// These have to match ClpPrimalColumnSteepest version
+#define reference(i)  (((reference[i>>5]>>(i&31))&1)!=0)
+// Updates second array for steepest and does devex weights (need not be coded)
+void
+ClpMatrixBase::subsetTimes2(const ClpSimplex * model,
+                            CoinIndexedVector * dj1,
+                            const CoinIndexedVector * pi2, CoinIndexedVector * dj2,
+                            double referenceIn, double devex,
+                            // Array for exact devex to say what is in reference framework
+                            unsigned int * reference,
+                            double * weights, double scaleFactor)
+{
+     // get subset which have nonzero tableau elements
+     subsetTransposeTimes(model, pi2, dj1, dj2);
+     bool killDjs = (scaleFactor == 0.0);
+     if (!scaleFactor)
+          scaleFactor = 1.0;
+     // columns
+
+     int number = dj1->getNumElements();
+     const int * index = dj1->getIndices();
+     double * updateBy = dj1->denseVector();
+     double * updateBy2 = dj2->denseVector();
+
+     for (int j = 0; j < number; j++) {
+          double thisWeight;
+          double pivot;
+          double pivotSquared;
+          int iSequence = index[j];
+          double value2 = updateBy[j];
+          if (killDjs)
+               updateBy[j] = 0.0;
+          double modification = updateBy2[j];
+          updateBy2[j] = 0.0;
+          ClpSimplex::Status status = model->getStatus(iSequence);
+
+          if (status != ClpSimplex::basic && status != ClpSimplex::isFixed) {
+               thisWeight = weights[iSequence];
+               pivot = value2 * scaleFactor;
+               pivotSquared = pivot * pivot;
+
+               thisWeight += pivotSquared * devex + pivot * modification;
+               if (thisWeight < DEVEX_TRY_NORM) {
+                    if (referenceIn < 0.0) {
+                         // steepest
+                         thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                    } else {
+                         // exact
+                         thisWeight = referenceIn * pivotSquared;
+                         if (reference(iSequence))
+                              thisWeight += 1.0;
+                         thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                    }
+               }
+               weights[iSequence] = thisWeight;
+          }
+     }
+     dj2->setNumElements(0);
+}
+// Correct sequence in and out to give true value
+void
+ClpMatrixBase::correctSequence(const ClpSimplex * , int & , int & )
+{
+}
+// Really scale matrix
+void
+ClpMatrixBase::reallyScale(const double * , const double * )
+{
+     std::cerr << "reallyScale not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+// Updates two arrays for steepest
+void
+ClpMatrixBase::transposeTimes2(const ClpSimplex * ,
+                               const CoinIndexedVector * , CoinIndexedVector *,
+                               const CoinIndexedVector * ,
+                               CoinIndexedVector * ,
+                               double , double ,
+                               // Array for exact devex to say what is in reference framework
+                               unsigned int * ,
+                               double * , double )
+{
+     std::cerr << "transposeTimes2 not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+/* Set the dimensions of the matrix. In effect, append new empty
+   columns/rows to the matrix. A negative number for either dimension
+   means that that dimension doesn't change. Otherwise the new dimensions
+   MUST be at least as large as the current ones otherwise an exception
+   is thrown. */
+void
+ClpMatrixBase::setDimensions(int , int )
+{
+     // If odd matrix assume user knows what they are doing
+}
+/* Append a set of rows/columns to the end of the matrix. Returns number of errors
+   i.e. if any of the new rows/columns contain an index that's larger than the
+   number of columns-1/rows-1 (if numberOther>0) or duplicates
+   If 0 then rows, 1 if columns */
+int
+ClpMatrixBase::appendMatrix(int , int ,
+                            const CoinBigIndex * , const int * ,
+                            const double * , int )
+{
+     std::cerr << "appendMatrix not supported - ClpMatrixBase" << std::endl;
+     abort();
+     return -1;
+}
+
+/* Modify one element of packed matrix.  An element may be added.
+   This works for either ordering If the new element is zero it will be
+   deleted unless keepZero true */
+void
+ClpMatrixBase::modifyCoefficient(int , int , double ,
+                                 bool )
+{
+     std::cerr << "modifyCoefficient not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+#if COIN_LONG_WORK
+// For long double versions (aborts if not supported)
+void
+ClpMatrixBase::times(CoinWorkDouble scalar,
+                     const CoinWorkDouble * x, CoinWorkDouble * y) const
+{
+     std::cerr << "long times not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+void
+ClpMatrixBase::transposeTimes(CoinWorkDouble scalar,
+                              const CoinWorkDouble * x, CoinWorkDouble * y) const
+{
+     std::cerr << "long transposeTimes not supported - ClpMatrixBase" << std::endl;
+     abort();
+}
+#endif
diff --git a/cbits/coin/ClpMatrixBase.hpp b/cbits/coin/ClpMatrixBase.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpMatrixBase.hpp
@@ -0,0 +1,516 @@
+/* $Id: ClpMatrixBase.hpp 1722 2011-04-17 09:58:37Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpMatrixBase_H
+#define ClpMatrixBase_H
+
+#include "CoinPragma.hpp"
+#include "CoinTypes.hpp"
+
+#include "CoinPackedMatrix.hpp"
+class CoinIndexedVector;
+class ClpSimplex;
+class ClpModel;
+
+/** Abstract base class for Clp Matrices
+
+Since this class is abstract, no object of this type can be created.
+
+If a derived class provides all methods then all Clp algorithms
+should work.  Some can be very inefficient e.g. getElements etc is
+only used for tightening bounds for dual and the copies are
+deleted.  Many methods can just be dummy i.e. abort(); if not
+all features are being used.  So if column generation was being done
+then it makes no sense to do steepest edge so there would be
+no point providing subsetTransposeTimes.
+*/
+
+class ClpMatrixBase  {
+
+public:
+     /**@name Virtual methods that the derived classes must provide */
+     //@{
+     /// Return a complete CoinPackedMatrix
+     virtual CoinPackedMatrix * getPackedMatrix() const = 0;
+     /** Whether the packed matrix is column major ordered or not. */
+     virtual bool isColOrdered() const = 0;
+     /** Number of entries in the packed matrix. */
+     virtual CoinBigIndex getNumElements() const = 0;
+     /** Number of columns. */
+     virtual int getNumCols() const = 0;
+     /** Number of rows. */
+     virtual int getNumRows() const = 0;
+
+     /** A vector containing the elements in the packed matrix. Note that there
+         might be gaps in this list, entries that do not belong to any
+         major-dimension vector. To get the actual elements one should look at
+         this vector together with vectorStarts and vectorLengths. */
+     virtual const double * getElements() const = 0;
+     /** A vector containing the minor indices of the elements in the packed
+         matrix. Note that there might be gaps in this list, entries that do not
+         belong to any major-dimension vector. To get the actual elements one
+         should look at this vector together with vectorStarts and
+         vectorLengths. */
+     virtual const int * getIndices() const = 0;
+
+     virtual const CoinBigIndex * getVectorStarts() const = 0;
+     /** The lengths of the major-dimension vectors. */
+     virtual const int * getVectorLengths() const = 0 ;
+     /** The length of a single major-dimension vector. */
+     virtual int getVectorLength(int index) const ;
+     /** Delete the columns whose indices are listed in <code>indDel</code>. */
+     virtual void deleteCols(const int numDel, const int * indDel) = 0;
+     /** Delete the rows whose indices are listed in <code>indDel</code>. */
+     virtual void deleteRows(const int numDel, const int * indDel) = 0;
+#ifndef CLP_NO_VECTOR
+     /// Append Columns
+     virtual void appendCols(int number, const CoinPackedVectorBase * const * columns);
+     /// Append Rows
+     virtual void appendRows(int number, const CoinPackedVectorBase * const * rows);
+#endif
+     /** Modify one element of packed matrix.  An element may be added.
+         This works for either ordering If the new element is zero it will be
+         deleted unless keepZero true */
+     virtual void modifyCoefficient(int row, int column, double newElement,
+                                    bool keepZero = false);
+     /** Append a set of rows/columns to the end of the matrix. Returns number of errors
+         i.e. if any of the new rows/columns contain an index that's larger than the
+         number of columns-1/rows-1 (if numberOther>0) or duplicates
+         If 0 then rows, 1 if columns */
+     virtual int appendMatrix(int number, int type,
+                              const CoinBigIndex * starts, const int * index,
+                              const double * element, int numberOther = -1);
+
+     /** Returns a new matrix in reverse order without gaps
+         Is allowed to return NULL if doesn't want to have row copy */
+     virtual ClpMatrixBase * reverseOrderedCopy() const {
+          return NULL;
+     }
+
+     /// Returns number of elements in column part of basis
+     virtual CoinBigIndex countBasis(const int * whichColumn,
+                                     int & numberColumnBasic) = 0;
+     /// Fills in column part of basis
+     virtual void fillBasis(ClpSimplex * model,
+                            const int * whichColumn,
+                            int & numberColumnBasic,
+                            int * row, int * start,
+                            int * rowCount, int * columnCount,
+                            CoinFactorizationDouble * element) = 0;
+     /** Creates scales for column copy (rowCopy in model may be modified)
+         default does not allow scaling
+         returns non-zero if no scaling done */
+     virtual int scale(ClpModel * , const ClpSimplex * = NULL) const {
+          return 1;
+     }
+     /** Scales rowCopy if column copy scaled
+         Only called if scales already exist */
+     virtual void scaleRowCopy(ClpModel * ) const { }
+     /// Returns true if can create row copy
+     virtual bool canGetRowCopy() const {
+          return true;
+     }
+     /** Realy really scales column copy
+         Only called if scales already exist.
+         Up to user to delete */
+     inline virtual ClpMatrixBase * scaledColumnCopy(ClpModel * ) const {
+          return this->clone();
+     }
+
+     /** Checks if all elements are in valid range.  Can just
+         return true if you are not paranoid.  For Clp I will
+         probably expect no zeros.  Code can modify matrix to get rid of
+         small elements.
+         check bits (can be turned off to save time) :
+         1 - check if matrix has gaps
+         2 - check if zero elements
+         4 - check and compress duplicates
+         8 - report on large and small
+     */
+     virtual bool allElementsInRange(ClpModel * ,
+                                     double , double ,
+                                     int = 15) {
+          return true;
+     }
+     /** Set the dimensions of the matrix. In effect, append new empty
+         columns/rows to the matrix. A negative number for either dimension
+         means that that dimension doesn't change. Otherwise the new dimensions
+         MUST be at least as large as the current ones otherwise an exception
+         is thrown. */
+     virtual void setDimensions(int numrows, int numcols);
+     /** Returns largest and smallest elements of both signs.
+         Largest refers to largest absolute value.
+         If returns zeros then can't tell anything */
+     virtual void rangeOfElements(double & smallestNegative, double & largestNegative,
+                                  double & smallestPositive, double & largestPositive);
+
+     /** Unpacks a column into an CoinIndexedvector
+      */
+     virtual void unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                         int column) const = 0;
+     /** Unpacks a column into an CoinIndexedvector
+      ** in packed format
+      Note that model is NOT const.  Bounds and objective could
+      be modified if doing column generation (just for this variable) */
+     virtual void unpackPacked(ClpSimplex * model,
+                               CoinIndexedVector * rowArray,
+                               int column) const = 0;
+     /** Purely for column generation and similar ideas.  Allows
+         matrix and any bounds or costs to be updated (sensibly).
+         Returns non-zero if any changes.
+     */
+     virtual int refresh(ClpSimplex * ) {
+          return 0;
+     }
+
+     // Really scale matrix
+     virtual void reallyScale(const double * rowScale, const double * columnScale);
+     /** Given positive integer weights for each row fills in sum of weights
+         for each column (and slack).
+         Returns weights vector
+         Default returns vector of ones
+     */
+     virtual CoinBigIndex * dubiousWeights(const ClpSimplex * model, int * inputWeights) const;
+     /** Adds multiple of a column into an CoinIndexedvector
+         You can use quickAdd to add to vector */
+     virtual void add(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                      int column, double multiplier) const = 0;
+     /** Adds multiple of a column into an array */
+     virtual void add(const ClpSimplex * model, double * array,
+                      int column, double multiplier) const = 0;
+     /// Allow any parts of a created CoinPackedMatrix to be deleted
+     virtual void releasePackedMatrix() const = 0;
+     /// Says whether it can do partial pricing
+     virtual bool canDoPartialPricing() const;
+     /// Returns number of hidden rows e.g. gub
+     virtual int hiddenRows() const;
+     /// Partial pricing
+     virtual void partialPricing(ClpSimplex * model, double start, double end,
+                                 int & bestSequence, int & numberWanted);
+     /** expands an updated column to allow for extra rows which the main
+         solver does not know about and returns number added.
+
+         This will normally be a no-op - it is in for GUB but may get extended to
+         general non-overlapping and embedded networks.
+
+         mode 0 - extend
+         mode 1 - delete etc
+     */
+     virtual int extendUpdated(ClpSimplex * model, CoinIndexedVector * update, int mode);
+     /**
+        utility primal function for dealing with dynamic constraints
+        mode=0  - Set up before "update" and "times" for primal solution using extended rows
+        mode=1  - Cleanup primal solution after "times" using extended rows.
+        mode=2  - Check (or report on) primal infeasibilities
+     */
+     virtual void primalExpanded(ClpSimplex * model, int mode);
+     /**
+         utility dual function for dealing with dynamic constraints
+         mode=0  - Set up before "updateTranspose" and "transposeTimes" for duals using extended
+                   updates array (and may use other if dual values pass)
+         mode=1  - Update dual solution after "transposeTimes" using extended rows.
+         mode=2  - Compute all djs and compute key dual infeasibilities
+         mode=3  - Report on key dual infeasibilities
+         mode=4  - Modify before updateTranspose in partial pricing
+     */
+     virtual void dualExpanded(ClpSimplex * model, CoinIndexedVector * array,
+                               double * other, int mode);
+     /**
+         general utility function for dealing with dynamic constraints
+         mode=0  - Create list of non-key basics in pivotVariable_ using
+                   number as numberBasic in and out
+         mode=1  - Set all key variables as basic
+         mode=2  - return number extra rows needed, number gives maximum number basic
+         mode=3  - before replaceColumn
+         mode=4  - return 1 if can do primal, 2 if dual, 3 if both
+         mode=5  - save any status stuff (when in good state)
+         mode=6  - restore status stuff
+         mode=7  - flag given variable (normally sequenceIn)
+         mode=8  - unflag all variables
+         mode=9  - synchronize costs and bounds
+         mode=10  - return 1 if there may be changing bounds on variable (column generation)
+         mode=11  - make sure set is clean (used when a variable rejected - but not flagged)
+         mode=12  - after factorize but before permute stuff
+         mode=13  - at end of simplex to delete stuff
+
+     */
+     virtual int generalExpanded(ClpSimplex * model, int mode, int & number);
+     /**
+        update information for a pivot (and effective rhs)
+     */
+     virtual int updatePivot(ClpSimplex * model, double oldInValue, double oldOutValue);
+     /** Creates a variable.  This is called after partial pricing and may modify matrix.
+         May update bestSequence.
+     */
+     virtual void createVariable(ClpSimplex * model, int & bestSequence);
+     /** Just for debug if odd type matrix.
+         Returns number of primal infeasibilities. */
+     virtual int checkFeasible(ClpSimplex * model, double & sum) const ;
+     /// Returns reduced cost of a variable
+     double reducedCost(ClpSimplex * model, int sequence) const;
+     /// Correct sequence in and out to give true value (if both -1 maybe do whole matrix)
+     virtual void correctSequence(const ClpSimplex * model, int & sequenceIn, int & sequenceOut) ;
+     //@}
+
+     //---------------------------------------------------------------------------
+     /**@name Matrix times vector methods
+        They can be faster if scalar is +- 1
+        Also for simplex I am not using basic/non-basic split */
+     //@{
+     /** Return <code>y + A * x * scalar</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numColumns()</code>
+         @pre <code>y</code> must be of size <code>numRows()</code> */
+     virtual void times(double scalar,
+                        const double * x, double * y) const = 0;
+     /** And for scaling - default aborts for when scaling not supported
+         (unless pointers NULL when as normal)
+     */
+     virtual void times(double scalar,
+                        const double * x, double * y,
+                        const double * rowScale,
+                        const double * columnScale) const;
+     /** Return <code>y + x * scalar * A</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numRows()</code>
+         @pre <code>y</code> must be of size <code>numColumns()</code> */
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y) const = 0;
+     /** And for scaling - default aborts for when scaling not supported
+         (unless pointers NULL when as normal)
+     */
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y,
+                                 const double * rowScale,
+                                 const double * columnScale,
+                                 double * spare = NULL) const;
+#if COIN_LONG_WORK
+     // For long double versions (aborts if not supported)
+     virtual void times(CoinWorkDouble scalar,
+                        const CoinWorkDouble * x, CoinWorkDouble * y) const ;
+     virtual void transposeTimes(CoinWorkDouble scalar,
+                                 const CoinWorkDouble * x, CoinWorkDouble * y) const ;
+#endif
+     /** Return <code>x * scalar *A + y</code> in <code>z</code>.
+         Can use y as temporary array (will be empty at end)
+         Note - If x packed mode - then z packed mode
+         Squashes small elements and knows about ClpSimplex */
+     virtual void transposeTimes(const ClpSimplex * model, double scalar,
+                                 const CoinIndexedVector * x,
+                                 CoinIndexedVector * y,
+                                 CoinIndexedVector * z) const = 0;
+     /** Return <code>x *A</code> in <code>z</code> but
+         just for indices in y.
+         This is only needed for primal steepest edge.
+         Note - z always packed mode */
+     virtual void subsetTransposeTimes(const ClpSimplex * model,
+                                       const CoinIndexedVector * x,
+                                       const CoinIndexedVector * y,
+                                       CoinIndexedVector * z) const = 0;
+     /** Returns true if can combine transposeTimes and subsetTransposeTimes
+         and if it would be faster */
+     virtual bool canCombine(const ClpSimplex * ,
+                             const CoinIndexedVector * ) const {
+          return false;
+     }
+     /// Updates two arrays for steepest and does devex weights (need not be coded)
+     virtual void transposeTimes2(const ClpSimplex * model,
+                                  const CoinIndexedVector * pi1, CoinIndexedVector * dj1,
+                                  const CoinIndexedVector * pi2,
+                                  CoinIndexedVector * spare,
+                                  double referenceIn, double devex,
+                                  // Array for exact devex to say what is in reference framework
+                                  unsigned int * reference,
+                                  double * weights, double scaleFactor);
+     /// Updates second array for steepest and does devex weights (need not be coded)
+     virtual void subsetTimes2(const ClpSimplex * model,
+                               CoinIndexedVector * dj1,
+                               const CoinIndexedVector * pi2, CoinIndexedVector * dj2,
+                               double referenceIn, double devex,
+                               // Array for exact devex to say what is in reference framework
+                               unsigned int * reference,
+                               double * weights, double scaleFactor);
+     /** Return <code>x *A</code> in <code>z</code> but
+         just for number indices in y.
+         Default cheats with fake CoinIndexedVector and
+         then calls subsetTransposeTimes */
+     virtual void listTransposeTimes(const ClpSimplex * model,
+                                     double * x,
+                                     int * y,
+                                     int number,
+                                     double * z) const;
+     //@}
+     //@{
+     ///@name Other
+     /// Clone
+     virtual ClpMatrixBase * clone() const = 0;
+     /** Subset clone (without gaps).  Duplicates are allowed
+         and order is as given.
+         Derived classes need not provide this as it may not always make
+         sense */
+     virtual ClpMatrixBase * subsetClone (
+          int numberRows, const int * whichRows,
+          int numberColumns, const int * whichColumns) const;
+     /// Gets rid of any mutable by products
+     virtual void backToBasics() {}
+     /** Returns type.
+         The types which code may need to know about are:
+         1  - ClpPackedMatrix
+         11 - ClpNetworkMatrix
+         12 - ClpPlusMinusOneMatrix
+     */
+     inline int type() const {
+          return type_;
+     }
+     /// Sets type
+     void setType(int newtype) {
+          type_ = newtype;
+     }
+     /// Sets up an effective RHS
+     void useEffectiveRhs(ClpSimplex * model);
+     /** Returns effective RHS offset if it is being used.  This is used for long problems
+         or big gub or anywhere where going through full columns is
+         expensive.  This may re-compute */
+     virtual double * rhsOffset(ClpSimplex * model, bool forceRefresh = false,
+                                bool check = false);
+     /// If rhsOffset used this is iteration last refreshed
+     inline int lastRefresh() const {
+          return lastRefresh_;
+     }
+     /// If rhsOffset used this is refresh frequency (0==off)
+     inline int refreshFrequency() const {
+          return refreshFrequency_;
+     }
+     inline void setRefreshFrequency(int value) {
+          refreshFrequency_ = value;
+     }
+     /// whether to skip dual checks most of time
+     inline bool skipDualCheck() const {
+          return skipDualCheck_;
+     }
+     inline void setSkipDualCheck(bool yes) {
+          skipDualCheck_ = yes;
+     }
+     /** Partial pricing tuning parameter - minimum number of "objects" to scan.
+         e.g. number of Gub sets but could be number of variables */
+     inline int minimumObjectsScan() const {
+          return minimumObjectsScan_;
+     }
+     inline void setMinimumObjectsScan(int value) {
+          minimumObjectsScan_ = value;
+     }
+     /// Partial pricing tuning parameter - minimum number of negative reduced costs to get
+     inline int minimumGoodReducedCosts() const {
+          return minimumGoodReducedCosts_;
+     }
+     inline void setMinimumGoodReducedCosts(int value) {
+          minimumGoodReducedCosts_ = value;
+     }
+     /// Current start of search space in matrix (as fraction)
+     inline double startFraction() const {
+          return startFraction_;
+     }
+     inline void setStartFraction(double value) {
+          startFraction_ = value;
+     }
+     /// Current end of search space in matrix (as fraction)
+     inline double endFraction() const {
+          return endFraction_;
+     }
+     inline void setEndFraction(double value) {
+          endFraction_ = value;
+     }
+     /// Current best reduced cost
+     inline double savedBestDj() const {
+          return savedBestDj_;
+     }
+     inline void setSavedBestDj(double value) {
+          savedBestDj_ = value;
+     }
+     /// Initial number of negative reduced costs wanted
+     inline int originalWanted() const {
+          return originalWanted_;
+     }
+     inline void setOriginalWanted(int value) {
+          originalWanted_ = value;
+     }
+     /// Current number of negative reduced costs which we still need
+     inline int currentWanted() const {
+          return currentWanted_;
+     }
+     inline void setCurrentWanted(int value) {
+          currentWanted_ = value;
+     }
+     /// Current best sequence
+     inline int savedBestSequence() const {
+          return savedBestSequence_;
+     }
+     inline void setSavedBestSequence(int value) {
+          savedBestSequence_ = value;
+     }
+     //@}
+
+
+protected:
+
+     /**@name Constructors, destructor<br>
+        <strong>NOTE</strong>: All constructors are protected. There's no need
+        to expose them, after all, this is an abstract class. */
+     //@{
+     /** Default constructor. */
+     ClpMatrixBase();
+     /** Destructor (has to be public) */
+public:
+     virtual ~ClpMatrixBase();
+protected:
+     // Copy
+     ClpMatrixBase(const ClpMatrixBase&);
+     // Assignment
+     ClpMatrixBase& operator=(const ClpMatrixBase&);
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /** Effective RHS offset if it is being used.  This is used for long problems
+         or big gub or anywhere where going through full columns is
+         expensive */
+     double * rhsOffset_;
+     /// Current start of search space in matrix (as fraction)
+     double startFraction_;
+     /// Current end of search space in matrix (as fraction)
+     double endFraction_;
+     /// Best reduced cost so far
+     double savedBestDj_;
+     /// Initial number of negative reduced costs wanted
+     int originalWanted_;
+     /// Current number of negative reduced costs which we still need
+     int currentWanted_;
+     /// Saved best sequence in pricing
+     int savedBestSequence_;
+     /// type (may be useful)
+     int type_;
+     /// If rhsOffset used this is iteration last refreshed
+     int lastRefresh_;
+     /// If rhsOffset used this is refresh frequency (0==off)
+     int refreshFrequency_;
+     /// Partial pricing tuning parameter - minimum number of "objects" to scan
+     int minimumObjectsScan_;
+     /// Partial pricing tuning parameter - minimum number of negative reduced costs to get
+     int minimumGoodReducedCosts_;
+     /// True sequence in (i.e. from larger problem)
+     int trueSequenceIn_;
+     /// True sequence out (i.e. from larger problem)
+     int trueSequenceOut_;
+     /// whether to skip dual checks most of time
+     bool skipDualCheck_;
+     //@}
+};
+// bias for free variables
+#define FREE_BIAS 1.0e1
+// Acceptance criteria for free variables
+#define FREE_ACCEPT 1.0e2
+
+#endif
diff --git a/cbits/coin/ClpMessage.cpp b/cbits/coin/ClpMessage.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpMessage.cpp
@@ -0,0 +1,163 @@
+/* $Id: ClpMessage.cpp 1928 2013-04-06 12:54:16Z stefan $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpMessage.hpp"
+/// Structure for use by ClpMessage.cpp
+typedef struct {
+     CLP_Message internalNumber;
+     int externalNumber; // or continuation
+     char detail;
+     const char * message;
+} Clp_message;
+static Clp_message clp_us_english[] = {
+     {CLP_SIMPLEX_FINISHED, 0, 1, "Optimal - objective value %g"},
+     {CLP_SIMPLEX_INFEASIBLE, 1, 1, "Primal infeasible - objective value %g"},
+     {CLP_SIMPLEX_UNBOUNDED, 2, 1, "Dual infeasible - objective value %g"},
+     {CLP_SIMPLEX_STOPPED, 3, 1, "Stopped - objective value %g"},
+     {CLP_SIMPLEX_ERROR, 4, 1, "Stopped due to errors - objective value %g"},
+     {CLP_SIMPLEX_INTERRUPT, 5, 1, "Stopped by event handler - objective value %g"},
+     {CLP_SIMPLEX_STATUS, 6, 1, "%d  Obj %g%? Primal inf %g (%d)%? Dual inf %g (%d)%? w.o. free dual inf (%d)"},
+     {CLP_DUAL_BOUNDS, 25, 3, "Looking optimal checking bounds with %g"},
+#if ABC_NORMAL_DEBUG>1
+     {CLP_SIMPLEX_ACCURACY, 60, 1, "Primal error %g, dual error %g"},
+#else
+     {CLP_SIMPLEX_ACCURACY, 60, 3, "Primal error %g, dual error %g"},
+#endif
+     {CLP_SIMPLEX_BADFACTOR, 7, 2, "Singular factorization of basis - status %d"},
+     {CLP_SIMPLEX_BOUNDTIGHTEN, 8, 3, "Bounds were tightened %d times"},
+     {CLP_SIMPLEX_INFEASIBILITIES, 9, 1, "%d infeasibilities"},
+     {CLP_SIMPLEX_FLAG, 10, 3, "Flagging variable %c%d"},
+     {CLP_SIMPLEX_GIVINGUP, 11, 2, "Stopping as close enough"},
+     {CLP_DUAL_CHECKB, 12, 2, "New dual bound of %g"},
+     {CLP_DUAL_ORIGINAL, 13, 3, "Going back to original objective"},
+     {CLP_SIMPLEX_PERTURB, 14, 1, "Perturbing problem by %g %% of %g - largest nonzero change %g (%% %g) - largest zero change %g"},
+     {CLP_PRIMAL_ORIGINAL, 15, 2, "Going back to original tolerance"},
+     {CLP_PRIMAL_WEIGHT, 16, 2, "New infeasibility weight of %g"},
+     {CLP_PRIMAL_OPTIMAL, 17, 2, "Looking optimal with tolerance of %g"},
+     {CLP_SINGULARITIES, 18, 2, "%d total structurals rejected in initial factorization"},
+     {CLP_MODIFIEDBOUNDS, 19, 1, "%d variables/rows fixed as scaled bounds too close"},
+     {CLP_RIMSTATISTICS1, 20, 2, "Absolute values of scaled objective range from %g to %g"},
+     {CLP_RIMSTATISTICS2, 21, 2, "Absolute values of scaled bounds range from %g to %g, minimum gap %g"},
+     {CLP_RIMSTATISTICS3, 22, 2, "Absolute values of scaled rhs range from %g to %g, minimum gap %g"},
+     {CLP_POSSIBLELOOP, 23, 2, "Possible loop - %d matches (%x) after %d checks"},
+     {CLP_SMALLELEMENTS, 24, 1, "Matrix will be packed to eliminate %d small elements"},
+     {CLP_DUPLICATEELEMENTS, 26, 1, "Matrix will be packed to eliminate %d duplicate elements"},
+     {CLP_SIMPLEX_HOUSE1, 101, 32, "dirOut %d, dirIn %d, theta %g, out %g, dj %g, alpha %g"},
+     {CLP_SIMPLEX_HOUSE2, 102, 4, "%d %g In: %c%d Out: %c%d%? dj ratio %g distance %g%? dj %g distance %g"},
+     {CLP_SIMPLEX_NONLINEAR, 103, 4, "Primal nonlinear change %g (%d)"},
+     {CLP_SIMPLEX_FREEIN, 104, 32, "Free column in %d"},
+     {CLP_SIMPLEX_PIVOTROW, 105, 32, "Pivot row %d"},
+     {CLP_DUAL_CHECK, 106, 4, "Btran alpha %g, ftran alpha %g"},
+     {CLP_PRIMAL_DJ, 107, 4, "For %c%d btran dj %g, ftran dj %g"},
+     {CLP_PACKEDSCALE_INITIAL, 1001, 2, "Initial range of elements is %g to %g"},
+     {CLP_PACKEDSCALE_WHILE, 1002, 3, "Range of elements is %g to %g"},
+     {CLP_PACKEDSCALE_FINAL, 1003, 2, "Final range of elements is %g to %g"},
+     {CLP_PACKEDSCALE_FORGET, 1004, 2, "Not bothering to scale as good enough"},
+     {CLP_INITIALIZE_STEEP, 1005, 3, "Initializing steepest edge weights - old %g, new %g"},
+     {CLP_UNABLE_OPEN, 6001, 0, "Unable to open file %s for reading"},
+     {CLP_BAD_BOUNDS, 6002, 1, "%d bad bound pairs or bad objectives were found - first at %c%d"},
+     {CLP_BAD_MATRIX, 6003, 1, "Matrix has %d large values, first at column %d, row %d is %g"},
+     {CLP_LOOP, 6004, 1, "Can't get out of loop - stopping"},
+     {CLP_IMPORT_RESULT, 27, 1, "Model was imported from %s in %g seconds"},
+     {CLP_IMPORT_ERRORS, 3001, 1, " There were %d errors when importing model from %s"},
+     {CLP_EMPTY_PROBLEM, 3002, 1, "Empty problem - %d rows, %d columns and %d elements"},
+     {CLP_CRASH, 28, 1, "Crash put %d variables in basis, %d dual infeasibilities"},
+     {CLP_END_VALUES_PASS, 29, 1, "End of values pass after %d iterations"},
+     {CLP_QUADRATIC_BOTH, 108, 32, "%s %d (%g) and %d (%g) both basic"},
+     {CLP_QUADRATIC_PRIMAL_DETAILS, 109, 32, "coeff %g, %g, %g - dj %g - deriv zero at %g, sj at %g"},
+     {CLP_IDIOT_ITERATION, 30, 1, "%d infeas %g, obj %g - mu %g, its %d, %d interior"},
+     {CLP_INFEASIBLE, 3003, 1, "Analysis indicates model infeasible or unbounded"},
+     {CLP_MATRIX_CHANGE, 31, 2, "Matrix can not be converted into %s"},
+     {CLP_TIMING, 32, 1, "%s objective %.10g - %d iterations time %.2f2%?, Presolve %.2f%?, Idiot %.2f%?"},
+     {CLP_INTERVAL_TIMING, 33, 2, "%s took %.2f seconds (total %.2f)"},
+     {CLP_SPRINT, 34, 1, "Pass %d took %d iterations, objective %g, dual infeasibilities %g( %d)"},
+     {CLP_BARRIER_ITERATION, 35, 1, "%d Primal %g Dual %g Complementarity %g - %d fixed, rank %d"},
+     {CLP_BARRIER_OBJECTIVE_GAP, 36, 3, "Feasible - objective gap %g"},
+     {CLP_BARRIER_GONE_INFEASIBLE, 37, 2, "Infeasible"},
+     {CLP_BARRIER_CLOSE_TO_OPTIMAL, 38, 2, "Close to optimal after %d iterations with complementarity %g"},
+     {CLP_BARRIER_COMPLEMENTARITY, 39, 2, "Complementarity %g - %s"},
+     {CLP_BARRIER_EXIT2, 40, 1, "Exiting - using solution from iteration %d"},
+     {CLP_BARRIER_STOPPING, 41, 1, "Exiting on iterations"},
+     {CLP_BARRIER_EXIT, 42, 1, "Optimal %s"},
+     {CLP_BARRIER_SCALING, 43, 3, "Scaling %s by %g"},
+     {CLP_BARRIER_MU, 44, 3, "Changing mu from %g to %g"},
+     {CLP_BARRIER_INFO, 45, 3, "Detail - %s"},
+     {CLP_BARRIER_END, 46, 1, "At end primal/dual infeasibilities %g/%g, complementarity gap %g, objective %g"},
+     {CLP_BARRIER_ACCURACY, 47, 2, "Relative error in phase %d, %d passes %g => %g"},
+     {CLP_BARRIER_SAFE, 48, 2, "Initial safe primal value %g, objective norm %g"},
+     {CLP_BARRIER_NEGATIVE_GAPS, 49, 3, "%d negative gaps summing to %g"},
+     {CLP_BARRIER_REDUCING, 50, 2, "Reducing %s step from %g to %g"},
+     {CLP_BARRIER_DIAGONAL, 51, 3, "Range of diagonal values is %g to %g"},
+     {CLP_BARRIER_SLACKS, 52, 3, "%d slacks increased, %d decreased this iteration"},
+     {CLP_BARRIER_DUALINF, 53, 3, "Maximum dual infeasibility on fixed is %g"},
+     {CLP_BARRIER_KILLED, 54, 3, "%d variables killed this iteration"},
+     {CLP_BARRIER_ABS_DROPPED, 55, 2, "Absolute error on dropped rows is %g"},
+     {CLP_BARRIER_ABS_ERROR, 56, 2, "Primal error is %g and dual error is %g"},
+     {CLP_BARRIER_FEASIBLE, 57, 2, "Infeasibilities - bound %g , primal %g ,dual %g"},
+     {CLP_BARRIER_STEP, 58, 2, "Steps - primal %g ,dual %g , mu %g"},
+     {CLP_BARRIER_KKT, 6005, 0, "Quadratic barrier needs a KKT factorization"},
+     {CLP_RIM_SCALE, 59, 1, "Automatic rim scaling gives objective scale of %g and rhs/bounds scale of %g"},
+     {CLP_SLP_ITER, 58, 1, "Pass %d objective %g - drop %g, largest delta %g"},
+     {CLP_COMPLICATED_MODEL, 3004, 1, "Can not use addRows or addColumns on CoinModel as mixed, %d rows, %d columns"},
+     {CLP_BAD_STRING_VALUES, 3005, 1, "%d string elements had no values associated with them"},
+     {CLP_CRUNCH_STATS, 61, 2, "Crunch %d (%d) rows, %d (%d) columns and %d (%d) elements"},
+     {CLP_PARAMETRICS_STATS, 62, 1, "Theta %g - objective %g"},
+     {CLP_PARAMETRICS_STATS2, 63, 2, "Theta %g - objective %g, %s in, %s out"},
+#ifndef NO_FATHOM_PRINT
+     {CLP_FATHOM_STATUS, 63, 2, "Fathoming node %d - %d nodes (%d iterations) - current depth %d"},
+     {CLP_FATHOM_SOLUTION, 64, 1, "Fathoming node %d - solution of %g after %d nodes at depth %d"},
+     {CLP_FATHOM_FINISH, 65, 1, "Fathoming node %d (depth %d) took %d nodes (%d iterations) - maximum depth %d"},
+#endif
+     {CLP_GENERAL, 1000, 1, "%s"},
+     {CLP_GENERAL2, 1001, 2, "%s"},
+     {CLP_GENERAL_WARNING, 3006, 1, "%s"},
+     {CLP_DUMMY_END, 999999, 0, ""}
+};
+static Clp_message uk_english[] = {
+     {
+          CLP_SIMPLEX_FINISHED, 0, 1, "Optimal - objective value %g,\
+ okay CLP can solve some LPs but you really need Xpress from Dash Associates :-)"
+     },
+     {CLP_DUMMY_END, 999999, 0, ""}
+};
+/* Constructor */
+ClpMessage::ClpMessage(Language language) :
+     CoinMessages(sizeof(clp_us_english) / sizeof(Clp_message))
+{
+     language_ = language;
+     strcpy(source_, "Clp");
+     class_ = 1; //solver
+     Clp_message * message = clp_us_english;
+
+     while (message->internalNumber != CLP_DUMMY_END) {
+          CoinOneMessage oneMessage(message->externalNumber, message->detail,
+                                    message->message);
+          addMessage(message->internalNumber, oneMessage);
+          message ++;
+     }
+     // Put into compact form
+     toCompact();
+
+     // now override any language ones
+
+     switch (language) {
+     case uk_en:
+          message = uk_english;
+          break;
+
+     default:
+          message = NULL;
+          break;
+     }
+
+     // replace if any found
+     if (message) {
+          while (message->internalNumber != CLP_DUMMY_END) {
+               replaceMessage(message->internalNumber, message->message);
+               message ++;
+          }
+     }
+}
diff --git a/cbits/coin/ClpMessage.hpp b/cbits/coin/ClpMessage.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpMessage.hpp
@@ -0,0 +1,131 @@
+/* $Id: ClpMessage.hpp 1928 2013-04-06 12:54:16Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpMessage_H
+#define ClpMessage_H
+
+
+#include "CoinPragma.hpp"
+#include <cstring>
+
+// This deals with Clp messages (as against Osi messages etc)
+
+#include "CoinMessageHandler.hpp"
+enum CLP_Message {
+     CLP_SIMPLEX_FINISHED,
+     CLP_SIMPLEX_INFEASIBLE,
+     CLP_SIMPLEX_UNBOUNDED,
+     CLP_SIMPLEX_STOPPED,
+     CLP_SIMPLEX_ERROR,
+     CLP_SIMPLEX_INTERRUPT,
+     CLP_SIMPLEX_STATUS,
+     CLP_DUAL_BOUNDS,
+     CLP_SIMPLEX_ACCURACY,
+     CLP_SIMPLEX_BADFACTOR,
+     CLP_SIMPLEX_BOUNDTIGHTEN,
+     CLP_SIMPLEX_INFEASIBILITIES,
+     CLP_SIMPLEX_FLAG,
+     CLP_SIMPLEX_GIVINGUP,
+     CLP_DUAL_CHECKB,
+     CLP_DUAL_ORIGINAL,
+     CLP_SIMPLEX_PERTURB,
+     CLP_PRIMAL_ORIGINAL,
+     CLP_PRIMAL_WEIGHT,
+     CLP_PRIMAL_OPTIMAL,
+     CLP_SINGULARITIES,
+     CLP_MODIFIEDBOUNDS,
+     CLP_RIMSTATISTICS1,
+     CLP_RIMSTATISTICS2,
+     CLP_RIMSTATISTICS3,
+     CLP_POSSIBLELOOP,
+     CLP_SMALLELEMENTS,
+     CLP_DUPLICATEELEMENTS,
+     CLP_SIMPLEX_HOUSE1,
+     CLP_SIMPLEX_HOUSE2,
+     CLP_SIMPLEX_NONLINEAR,
+     CLP_SIMPLEX_FREEIN,
+     CLP_SIMPLEX_PIVOTROW,
+     CLP_DUAL_CHECK,
+     CLP_PRIMAL_DJ,
+     CLP_PACKEDSCALE_INITIAL,
+     CLP_PACKEDSCALE_WHILE,
+     CLP_PACKEDSCALE_FINAL,
+     CLP_PACKEDSCALE_FORGET,
+     CLP_INITIALIZE_STEEP,
+     CLP_UNABLE_OPEN,
+     CLP_BAD_BOUNDS,
+     CLP_BAD_MATRIX,
+     CLP_LOOP,
+     CLP_IMPORT_RESULT,
+     CLP_IMPORT_ERRORS,
+     CLP_EMPTY_PROBLEM,
+     CLP_CRASH,
+     CLP_END_VALUES_PASS,
+     CLP_QUADRATIC_BOTH,
+     CLP_QUADRATIC_PRIMAL_DETAILS,
+     CLP_IDIOT_ITERATION,
+     CLP_INFEASIBLE,
+     CLP_MATRIX_CHANGE,
+     CLP_TIMING,
+     CLP_INTERVAL_TIMING,
+     CLP_SPRINT,
+     CLP_BARRIER_ITERATION,
+     CLP_BARRIER_OBJECTIVE_GAP,
+     CLP_BARRIER_GONE_INFEASIBLE,
+     CLP_BARRIER_CLOSE_TO_OPTIMAL,
+     CLP_BARRIER_COMPLEMENTARITY,
+     CLP_BARRIER_EXIT2,
+     CLP_BARRIER_STOPPING,
+     CLP_BARRIER_EXIT,
+     CLP_BARRIER_SCALING,
+     CLP_BARRIER_MU,
+     CLP_BARRIER_INFO,
+     CLP_BARRIER_END,
+     CLP_BARRIER_ACCURACY,
+     CLP_BARRIER_SAFE,
+     CLP_BARRIER_NEGATIVE_GAPS,
+     CLP_BARRIER_REDUCING,
+     CLP_BARRIER_DIAGONAL,
+     CLP_BARRIER_SLACKS,
+     CLP_BARRIER_DUALINF,
+     CLP_BARRIER_KILLED,
+     CLP_BARRIER_ABS_DROPPED,
+     CLP_BARRIER_ABS_ERROR,
+     CLP_BARRIER_FEASIBLE,
+     CLP_BARRIER_STEP,
+     CLP_BARRIER_KKT,
+     CLP_RIM_SCALE,
+     CLP_SLP_ITER,
+     CLP_COMPLICATED_MODEL,
+     CLP_BAD_STRING_VALUES,
+     CLP_CRUNCH_STATS,
+     CLP_PARAMETRICS_STATS, 
+     CLP_PARAMETRICS_STATS2,
+#ifndef NO_FATHOM_PRINT
+     CLP_FATHOM_STATUS,
+     CLP_FATHOM_SOLUTION,
+     CLP_FATHOM_FINISH,
+#endif
+     CLP_GENERAL,
+     CLP_GENERAL2,
+     CLP_GENERAL_WARNING,
+     CLP_DUMMY_END
+};
+
+/** This deals with Clp messages (as against Osi messages etc)
+ */
+class ClpMessage : public CoinMessages {
+
+public:
+
+     /**@name Constructors etc */
+     //@{
+     /** Constructor */
+     ClpMessage(Language language = us_en);
+     //@}
+
+};
+
+#endif
diff --git a/cbits/coin/ClpModel.cpp b/cbits/coin/ClpModel.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpModel.cpp
@@ -0,0 +1,4574 @@
+/* $Id: ClpModel.cpp 1957 2013-05-15 08:58:19Z forrest $ */
+// copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cmath>
+#include <cassert>
+#include <cfloat>
+#include <string>
+#include <cstdio>
+#include <iostream>
+
+/*
+  CLP_NO_VECTOR
+
+  There's no hint of the motivation for this, so here's a bit of speculation.
+  CLP_NO_VECTOR excises CoinPackedVector from the code. Looking over
+  affected code here, and the much more numerous occurrences of affected
+  code in CoinUtils, it looks to be an efficiency issue.
+
+  One good example is CoinPackedMatrix.isEquivalent. The default version
+  tests equivalence of major dimension vectors by retrieving them as
+  CPVs and invoking CPV.isEquivalent. As pointed out in the documention,
+  CPV.isEquivalent implicitly sorts the nonzeros of each vector (insertion in
+  a map) prior to comparison. As a one-off, this is arguably more efficient
+  than allocating and clearing a full vector, then dropping in the nonzeros,
+  then checking against the second vector (in fact, this is the algorithm
+  for testing a packed vector against a full vector).
+
+  In CPM.isEquivalent, we have a whole sequence of vectors to compare. Better
+  to allocate a full vector sized to match, clear it (one time cost), then
+  edit nonzeros in and out while doing comparisons. The cost of allocating
+  and clearing the full vector is amortised over all columns.
+*/
+
+
+#include "CoinPragma.hpp"
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinTime.hpp"
+#include "ClpModel.hpp"
+#include "ClpEventHandler.hpp"
+#include "ClpPackedMatrix.hpp"
+#ifndef SLIM_CLP
+#include "ClpPlusMinusOneMatrix.hpp"
+#endif
+#ifndef CLP_NO_VECTOR
+#include "CoinPackedVector.hpp"
+#endif
+#include "CoinIndexedVector.hpp"
+#if SLIM_CLP==2
+#define SLIM_NOIO
+#endif
+#ifndef SLIM_NOIO
+#include "CoinMpsIO.hpp"
+#include "CoinFileIO.hpp"
+#include "CoinModel.hpp"
+#endif
+#include "ClpMessage.hpp"
+#include "CoinMessage.hpp"
+#include "ClpLinearObjective.hpp"
+#ifndef SLIM_CLP
+#include "ClpQuadraticObjective.hpp"
+#include "CoinBuild.hpp"
+#endif
+
+//#############################################################################
+ClpModel::ClpModel (bool emptyMessages) :
+
+     optimizationDirection_(1),
+     objectiveValue_(0.0),
+     smallElement_(1.0e-20),
+     objectiveScale_(1.0),
+     rhsScale_(1.0),
+     numberRows_(0),
+     numberColumns_(0),
+     rowActivity_(NULL),
+     columnActivity_(NULL),
+     dual_(NULL),
+     reducedCost_(NULL),
+     rowLower_(NULL),
+     rowUpper_(NULL),
+     objective_(NULL),
+     rowObjective_(NULL),
+     columnLower_(NULL),
+     columnUpper_(NULL),
+     matrix_(NULL),
+     rowCopy_(NULL),
+     scaledMatrix_(NULL),
+     ray_(NULL),
+     rowScale_(NULL),
+     columnScale_(NULL),
+     inverseRowScale_(NULL),
+     inverseColumnScale_(NULL),
+     scalingFlag_(3),
+     status_(NULL),
+     integerType_(NULL),
+     userPointer_(NULL),
+     trustedUserPointer_(NULL),
+     numberIterations_(0),
+     solveType_(0),
+     whatsChanged_(0),
+     problemStatus_(-1),
+     secondaryStatus_(0),
+     lengthNames_(0),
+     numberThreads_(0),
+     specialOptions_(0),
+#ifndef CLP_NO_STD
+     defaultHandler_(true),
+     rowNames_(),
+     columnNames_(),
+#else
+     defaultHandler_(true),
+#endif
+     maximumColumns_(-1),
+     maximumRows_(-1),
+     maximumInternalColumns_(-1),
+     maximumInternalRows_(-1),
+     savedRowScale_(NULL),
+     savedColumnScale_(NULL)
+{
+     intParam_[ClpMaxNumIteration] = 2147483647;
+     intParam_[ClpMaxNumIterationHotStart] = 9999999;
+     intParam_[ClpNameDiscipline] = 1;
+
+     dblParam_[ClpDualObjectiveLimit] = COIN_DBL_MAX;
+     dblParam_[ClpPrimalObjectiveLimit] = COIN_DBL_MAX;
+     dblParam_[ClpDualTolerance] = 1e-7;
+     dblParam_[ClpPrimalTolerance] = 1e-7;
+     dblParam_[ClpObjOffset] = 0.0;
+     dblParam_[ClpMaxSeconds] = -1.0;
+     dblParam_[ClpPresolveTolerance] = 1.0e-8;
+
+#ifndef CLP_NO_STD
+     strParam_[ClpProbName] = "ClpDefaultName";
+#endif
+     handler_ = new CoinMessageHandler();
+     handler_->setLogLevel(1);
+     eventHandler_ = new ClpEventHandler();
+     if (!emptyMessages) {
+          messages_ = ClpMessage();
+          coinMessages_ = CoinMessage();
+     }
+     randomNumberGenerator_.setSeed(1234567);
+}
+
+//-----------------------------------------------------------------------------
+
+ClpModel::~ClpModel ()
+{
+     if (defaultHandler_) {
+          delete handler_;
+          handler_ = NULL;
+     }
+     gutsOfDelete(0);
+}
+// Does most of deletion (0 = all, 1 = most)
+void
+ClpModel::gutsOfDelete(int type)
+{
+     if (!type || !permanentArrays()) {
+          maximumRows_ = -1;
+          maximumColumns_ = -1;
+          delete [] rowActivity_;
+          rowActivity_ = NULL;
+          delete [] columnActivity_;
+          columnActivity_ = NULL;
+          delete [] dual_;
+          dual_ = NULL;
+          delete [] reducedCost_;
+          reducedCost_ = NULL;
+          delete [] rowLower_;
+          delete [] rowUpper_;
+          delete [] rowObjective_;
+          rowLower_ = NULL;
+          rowUpper_ = NULL;
+          rowObjective_ = NULL;
+          delete [] columnLower_;
+          delete [] columnUpper_;
+          delete objective_;
+          columnLower_ = NULL;
+          columnUpper_ = NULL;
+          objective_ = NULL;
+          delete [] savedRowScale_;
+          if (rowScale_ == savedRowScale_)
+               rowScale_ = NULL;
+          savedRowScale_ = NULL;
+          delete [] savedColumnScale_;
+          if (columnScale_ == savedColumnScale_)
+               columnScale_ = NULL;
+          savedColumnScale_ = NULL;
+          delete [] rowScale_;
+          rowScale_ = NULL;
+          delete [] columnScale_;
+          columnScale_ = NULL;
+          delete [] integerType_;
+          integerType_ = NULL;
+          delete [] status_;
+          status_ = NULL;
+          delete eventHandler_;
+          eventHandler_ = NULL;
+     }
+     whatsChanged_ = 0;
+     delete matrix_;
+     matrix_ = NULL;
+     delete rowCopy_;
+     rowCopy_ = NULL;
+     delete scaledMatrix_;
+     scaledMatrix_ = NULL,
+     delete [] ray_;
+     ray_ = NULL;
+     specialOptions_ = 0;
+}
+void
+ClpModel::setRowScale(double * scale)
+{
+     if (!savedRowScale_) {
+          delete [] reinterpret_cast<double *> (rowScale_);
+          rowScale_ = scale;
+     } else {
+          assert (!scale);
+          rowScale_ = NULL;
+     }
+}
+void
+ClpModel::setColumnScale(double * scale)
+{
+     if (!savedColumnScale_) {
+          delete [] reinterpret_cast<double *> (columnScale_);
+          columnScale_ = scale;
+     } else {
+          assert (!scale);
+          columnScale_ = NULL;
+     }
+}
+//#############################################################################
+void ClpModel::setPrimalTolerance( double value)
+{
+     if (value > 0.0 && value < 1.0e10)
+          dblParam_[ClpPrimalTolerance] = value;
+}
+void ClpModel::setDualTolerance( double value)
+{
+     if (value > 0.0 && value < 1.0e10)
+          dblParam_[ClpDualTolerance] = value;
+}
+void ClpModel::setOptimizationDirection( double value)
+{
+     optimizationDirection_ = value;
+}
+void
+ClpModel::gutsOfLoadModel (int numberRows, int numberColumns,
+                           const double* collb, const double* colub,
+                           const double* obj,
+                           const double* rowlb, const double* rowub,
+                           const double * rowObjective)
+{
+     // save event handler in case already set
+     ClpEventHandler * handler = eventHandler_->clone();
+     // Save specialOptions
+     int saveOptions = specialOptions_;
+     gutsOfDelete(0);
+     specialOptions_ = saveOptions;
+     eventHandler_ = handler;
+     numberRows_ = numberRows;
+     numberColumns_ = numberColumns;
+     rowActivity_ = new double[numberRows_];
+     columnActivity_ = new double[numberColumns_];
+     dual_ = new double[numberRows_];
+     reducedCost_ = new double[numberColumns_];
+
+     CoinZeroN(dual_, numberRows_);
+     CoinZeroN(reducedCost_, numberColumns_);
+     int iRow, iColumn;
+
+     rowLower_ = ClpCopyOfArray(rowlb, numberRows_, -COIN_DBL_MAX);
+     rowUpper_ = ClpCopyOfArray(rowub, numberRows_, COIN_DBL_MAX);
+     double * objective = ClpCopyOfArray(obj, numberColumns_, 0.0);
+     objective_ = new ClpLinearObjective(objective, numberColumns_);
+     delete [] objective;
+     rowObjective_ = ClpCopyOfArray(rowObjective, numberRows_);
+     columnLower_ = ClpCopyOfArray(collb, numberColumns_, 0.0);
+     columnUpper_ = ClpCopyOfArray(colub, numberColumns_, COIN_DBL_MAX);
+     // set default solution and clean bounds
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          if (rowLower_[iRow] > 0.0) {
+               rowActivity_[iRow] = rowLower_[iRow];
+          } else if (rowUpper_[iRow] < 0.0) {
+               rowActivity_[iRow] = rowUpper_[iRow];
+          } else {
+               rowActivity_[iRow] = 0.0;
+          }
+          if (rowLower_[iRow] < -1.0e27)
+               rowLower_[iRow] = -COIN_DBL_MAX;
+          if (rowUpper_[iRow] > 1.0e27)
+               rowUpper_[iRow] = COIN_DBL_MAX;
+     }
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (columnLower_[iColumn] > 0.0) {
+               columnActivity_[iColumn] = columnLower_[iColumn];
+          } else if (columnUpper_[iColumn] < 0.0) {
+               columnActivity_[iColumn] = columnUpper_[iColumn];
+          } else {
+               columnActivity_[iColumn] = 0.0;
+          }
+          if (columnLower_[iColumn] < -1.0e27)
+               columnLower_[iColumn] = -COIN_DBL_MAX;
+          if (columnUpper_[iColumn] > 1.0e27)
+               columnUpper_[iColumn] = COIN_DBL_MAX;
+     }
+}
+// This just loads up a row objective
+void ClpModel::setRowObjective(const double * rowObjective)
+{
+     delete [] rowObjective_;
+     rowObjective_ = ClpCopyOfArray(rowObjective, numberRows_);
+     whatsChanged_ = 0;
+}
+void
+ClpModel::loadProblem (  const ClpMatrixBase& matrix,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective)
+{
+     gutsOfLoadModel(matrix.getNumRows(), matrix.getNumCols(),
+                     collb, colub, obj, rowlb, rowub, rowObjective);
+     if (matrix.isColOrdered()) {
+          matrix_ = matrix.clone();
+     } else {
+          // later may want to keep as unknown class
+          CoinPackedMatrix matrix2;
+          matrix2.setExtraGap(0.0);
+          matrix2.setExtraMajor(0.0);
+          matrix2.reverseOrderedCopyOf(*matrix.getPackedMatrix());
+          matrix.releasePackedMatrix();
+          matrix_ = new ClpPackedMatrix(matrix2);
+     }
+     matrix_->setDimensions(numberRows_, numberColumns_);
+}
+void
+ClpModel::loadProblem (  const CoinPackedMatrix& matrix,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective)
+{
+     ClpPackedMatrix* clpMatrix =
+          dynamic_cast< ClpPackedMatrix*>(matrix_);
+     bool special = (clpMatrix) ? clpMatrix->wantsSpecialColumnCopy() : false;
+     gutsOfLoadModel(matrix.getNumRows(), matrix.getNumCols(),
+                     collb, colub, obj, rowlb, rowub, rowObjective);
+     if (matrix.isColOrdered()) {
+          matrix_ = new ClpPackedMatrix(matrix);
+          if (special) {
+               clpMatrix = static_cast< ClpPackedMatrix*>(matrix_);
+               clpMatrix->makeSpecialColumnCopy();
+          }
+     } else {
+          CoinPackedMatrix matrix2;
+          matrix2.setExtraGap(0.0);
+          matrix2.setExtraMajor(0.0);
+          matrix2.reverseOrderedCopyOf(matrix);
+          matrix_ = new ClpPackedMatrix(matrix2);
+     }
+     matrix_->setDimensions(numberRows_, numberColumns_);
+}
+void
+ClpModel::loadProblem (
+     const int numcols, const int numrows,
+     const CoinBigIndex* start, const int* index,
+     const double* value,
+     const double* collb, const double* colub,
+     const double* obj,
+     const double* rowlb, const double* rowub,
+     const double * rowObjective)
+{
+     gutsOfLoadModel(numrows, numcols,
+                     collb, colub, obj, rowlb, rowub, rowObjective);
+     int numberElements = start ? start[numcols] : 0;
+     CoinPackedMatrix matrix(true, numrows, numrows ? numcols : 0, numberElements,
+                             value, index, start, NULL);
+     matrix_ = new ClpPackedMatrix(matrix);
+     matrix_->setDimensions(numberRows_, numberColumns_);
+}
+void
+ClpModel::loadProblem (
+     const int numcols, const int numrows,
+     const CoinBigIndex* start, const int* index,
+     const double* value, const int* length,
+     const double* collb, const double* colub,
+     const double* obj,
+     const double* rowlb, const double* rowub,
+     const double * rowObjective)
+{
+     gutsOfLoadModel(numrows, numcols,
+                     collb, colub, obj, rowlb, rowub, rowObjective);
+     // Compute number of elements
+     int numberElements = 0;
+     int i;
+     for (i = 0; i < numcols; i++)
+          numberElements += length[i];
+     CoinPackedMatrix matrix(true, numrows, numcols, numberElements,
+                             value, index, start, length);
+     matrix_ = new ClpPackedMatrix(matrix);
+}
+#ifndef SLIM_NOIO
+// This loads a model from a coinModel object - returns number of errors
+int
+ClpModel::loadProblem (  CoinModel & modelObject, bool tryPlusMinusOne)
+{
+     if (modelObject.numberColumns() == 0 && modelObject.numberRows() == 0)
+          return 0;
+     int numberErrors = 0;
+     // Set arrays for normal use
+     double * rowLower = modelObject.rowLowerArray();
+     double * rowUpper = modelObject.rowUpperArray();
+     double * columnLower = modelObject.columnLowerArray();
+     double * columnUpper = modelObject.columnUpperArray();
+     double * objective = modelObject.objectiveArray();
+     int * integerType = modelObject.integerTypeArray();
+     double * associated = modelObject.associatedArray();
+     // If strings then do copies
+     if (modelObject.stringsExist()) {
+          numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                                  objective, integerType, associated);
+     }
+     int numberRows = modelObject.numberRows();
+     int numberColumns = modelObject.numberColumns();
+     gutsOfLoadModel(numberRows, numberColumns,
+                     columnLower, columnUpper, objective, rowLower, rowUpper, NULL);
+     setObjectiveOffset(modelObject.objectiveOffset());
+     CoinBigIndex * startPositive = NULL;
+     CoinBigIndex * startNegative = NULL;
+     delete matrix_;
+     if (tryPlusMinusOne) {
+          startPositive = new CoinBigIndex[numberColumns+1];
+          startNegative = new CoinBigIndex[numberColumns];
+          modelObject.countPlusMinusOne(startPositive, startNegative, associated);
+          if (startPositive[0] < 0) {
+               // no good
+               tryPlusMinusOne = false;
+               delete [] startPositive;
+               delete [] startNegative;
+          }
+     }
+#ifndef SLIM_CLP
+     if (!tryPlusMinusOne) {
+#endif
+          CoinPackedMatrix matrix;
+          modelObject.createPackedMatrix(matrix, associated);
+          matrix_ = new ClpPackedMatrix(matrix);
+#ifndef SLIM_CLP
+     } else {
+          // create +-1 matrix
+          CoinBigIndex size = startPositive[numberColumns];
+          int * indices = new int[size];
+          modelObject.createPlusMinusOne(startPositive, startNegative, indices,
+                                         associated);
+          // Get good object
+          ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
+          matrix->passInCopy(numberRows, numberColumns,
+                             true, indices, startPositive, startNegative);
+          matrix_ = matrix;
+     }
+#endif
+#ifndef CLP_NO_STD
+     // Do names if wanted
+     int numberItems;
+     numberItems = modelObject.rowNames()->numberItems();
+     if (numberItems) {
+          const char *const * rowNames = modelObject.rowNames()->names();
+          copyRowNames(rowNames, 0, numberItems);
+     }
+     numberItems = modelObject.columnNames()->numberItems();
+     if (numberItems) {
+          const char *const * columnNames = modelObject.columnNames()->names();
+          copyColumnNames(columnNames, 0, numberItems);
+     }
+#endif
+     // Do integers if wanted
+     assert(integerType);
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+          if (integerType[iColumn])
+               setInteger(iColumn);
+     }
+     if (rowLower != modelObject.rowLowerArray() ||
+               columnLower != modelObject.columnLowerArray()) {
+          delete [] rowLower;
+          delete [] rowUpper;
+          delete [] columnLower;
+          delete [] columnUpper;
+          delete [] objective;
+          delete [] integerType;
+          delete [] associated;
+          if (numberErrors)
+               handler_->message(CLP_BAD_STRING_VALUES, messages_)
+                         << numberErrors
+                         << CoinMessageEol;
+     }
+     matrix_->setDimensions(numberRows_, numberColumns_);
+     return numberErrors;
+}
+#endif
+void
+ClpModel::getRowBound(int iRow, double& lower, double& upper) const
+{
+     lower = -COIN_DBL_MAX;
+     upper = COIN_DBL_MAX;
+     if (rowUpper_)
+          upper = rowUpper_[iRow];
+     if (rowLower_)
+          lower = rowLower_[iRow];
+}
+//------------------------------------------------------------------
+#ifndef NDEBUG
+// For errors to make sure print to screen
+// only called in debug mode
+static void indexError(int index,
+                       std::string methodName)
+{
+     std::cerr << "Illegal index " << index << " in ClpModel::" << methodName << std::endl;
+     throw CoinError("Illegal index", methodName, "ClpModel");
+}
+#endif
+/* Set an objective function coefficient */
+void
+ClpModel::setObjectiveCoefficient( int elementIndex, double elementValue )
+{
+#ifndef NDEBUG
+     if (elementIndex < 0 || elementIndex >= numberColumns_) {
+          indexError(elementIndex, "setObjectiveCoefficient");
+     }
+#endif
+     objective()[elementIndex] = elementValue;
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+}
+/* Set a single row lower bound<br>
+   Use -DBL_MAX for -infinity. */
+void
+ClpModel::setRowLower( int elementIndex, double elementValue )
+{
+     if (elementValue < -1.0e27)
+          elementValue = -COIN_DBL_MAX;
+     rowLower_[elementIndex] = elementValue;
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+}
+
+/* Set a single row upper bound<br>
+   Use DBL_MAX for infinity. */
+void
+ClpModel::setRowUpper( int elementIndex, double elementValue )
+{
+     if (elementValue > 1.0e27)
+          elementValue = COIN_DBL_MAX;
+     rowUpper_[elementIndex] = elementValue;
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+}
+
+/* Set a single row lower and upper bound */
+void
+ClpModel::setRowBounds( int elementIndex,
+                        double lower, double upper )
+{
+     if (lower < -1.0e27)
+          lower = -COIN_DBL_MAX;
+     if (upper > 1.0e27)
+          upper = COIN_DBL_MAX;
+     CoinAssert (upper >= lower);
+     rowLower_[elementIndex] = lower;
+     rowUpper_[elementIndex] = upper;
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+}
+void ClpModel::setRowSetBounds(const int* indexFirst,
+                               const int* indexLast,
+                               const double* boundList)
+{
+#ifndef NDEBUG
+     int n = numberRows_;
+#endif
+     double * lower = rowLower_;
+     double * upper = rowUpper_;
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+     while (indexFirst != indexLast) {
+          const int iRow = *indexFirst++;
+#ifndef NDEBUG
+          if (iRow < 0 || iRow >= n) {
+               indexError(iRow, "setRowSetBounds");
+          }
+#endif
+          lower[iRow] = *boundList++;
+          upper[iRow] = *boundList++;
+          if (lower[iRow] < -1.0e27)
+               lower[iRow] = -COIN_DBL_MAX;
+          if (upper[iRow] > 1.0e27)
+               upper[iRow] = COIN_DBL_MAX;
+          CoinAssert (upper[iRow] >= lower[iRow]);
+     }
+}
+//-----------------------------------------------------------------------------
+/* Set a single column lower bound<br>
+   Use -DBL_MAX for -infinity. */
+void
+ClpModel::setColumnLower( int elementIndex, double elementValue )
+{
+#ifndef NDEBUG
+     int n = numberColumns_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setColumnLower");
+     }
+#endif
+     if (elementValue < -1.0e27)
+          elementValue = -COIN_DBL_MAX;
+     columnLower_[elementIndex] = elementValue;
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+}
+
+/* Set a single column upper bound<br>
+   Use DBL_MAX for infinity. */
+void
+ClpModel::setColumnUpper( int elementIndex, double elementValue )
+{
+#ifndef NDEBUG
+     int n = numberColumns_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setColumnUpper");
+     }
+#endif
+     if (elementValue > 1.0e27)
+          elementValue = COIN_DBL_MAX;
+     columnUpper_[elementIndex] = elementValue;
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+}
+
+/* Set a single column lower and upper bound */
+void
+ClpModel::setColumnBounds( int elementIndex,
+                           double lower, double upper )
+{
+#ifndef NDEBUG
+     int n = numberColumns_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setColumnBounds");
+     }
+#endif
+     if (lower < -1.0e27)
+          lower = -COIN_DBL_MAX;
+     if (upper > 1.0e27)
+          upper = COIN_DBL_MAX;
+     columnLower_[elementIndex] = lower;
+     columnUpper_[elementIndex] = upper;
+     CoinAssert (upper >= lower);
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+}
+void ClpModel::setColumnSetBounds(const int* indexFirst,
+                                  const int* indexLast,
+                                  const double* boundList)
+{
+     double * lower = columnLower_;
+     double * upper = columnUpper_;
+     whatsChanged_ = 0; // Can't be sure (use ClpSimplex to keep)
+#ifndef NDEBUG
+     int n = numberColumns_;
+#endif
+     while (indexFirst != indexLast) {
+          const int iColumn = *indexFirst++;
+#ifndef NDEBUG
+          if (iColumn < 0 || iColumn >= n) {
+               indexError(iColumn, "setColumnSetBounds");
+          }
+#endif
+          lower[iColumn] = *boundList++;
+          upper[iColumn] = *boundList++;
+          CoinAssert (upper[iColumn] >= lower[iColumn]);
+          if (lower[iColumn] < -1.0e27)
+               lower[iColumn] = -COIN_DBL_MAX;
+          if (upper[iColumn] > 1.0e27)
+               upper[iColumn] = COIN_DBL_MAX;
+     }
+}
+//-----------------------------------------------------------------------------
+//#############################################################################
+// Copy constructor.
+ClpModel::ClpModel(const ClpModel &rhs, int scalingMode) :
+     optimizationDirection_(rhs.optimizationDirection_),
+     numberRows_(rhs.numberRows_),
+     numberColumns_(rhs.numberColumns_),
+     specialOptions_(rhs.specialOptions_),
+     maximumColumns_(-1),
+     maximumRows_(-1),
+     maximumInternalColumns_(-1),
+     maximumInternalRows_(-1),
+     savedRowScale_(NULL),
+     savedColumnScale_(NULL)
+{
+     gutsOfCopy(rhs);
+     if (scalingMode >= 0 && matrix_ &&
+               matrix_->allElementsInRange(this, smallElement_, 1.0e20)) {
+          // really do scaling
+          scalingFlag_ = scalingMode;
+          setRowScale(NULL);
+          setColumnScale(NULL);
+          delete rowCopy_; // in case odd
+          rowCopy_ = NULL;
+          delete scaledMatrix_;
+          scaledMatrix_ = NULL;
+          if (scalingMode && !matrix_->scale(this)) {
+               // scaling worked - now apply
+               inverseRowScale_ = rowScale_ + numberRows_;
+               inverseColumnScale_ = columnScale_ + numberColumns_;
+               gutsOfScaling();
+               // pretend not scaled
+               scalingFlag_ = -scalingFlag_;
+          } else {
+               // not scaled
+               scalingFlag_ = 0;
+          }
+     }
+     //randomNumberGenerator_.setSeed(1234567);
+}
+// Assignment operator. This copies the data
+ClpModel &
+ClpModel::operator=(const ClpModel & rhs)
+{
+     if (this != &rhs) {
+          if (defaultHandler_) {
+               //delete handler_;
+               //handler_ = NULL;
+          }
+          gutsOfDelete(1);
+          optimizationDirection_ = rhs.optimizationDirection_;
+          numberRows_ = rhs.numberRows_;
+          numberColumns_ = rhs.numberColumns_;
+          gutsOfCopy(rhs, -1);
+     }
+     return *this;
+}
+/* Does most of copying
+   If trueCopy 0 then just points to arrays
+   If -1 leaves as much as possible */
+void
+ClpModel::gutsOfCopy(const ClpModel & rhs, int trueCopy)
+{
+     defaultHandler_ = rhs.defaultHandler_;
+     randomNumberGenerator_ = rhs.randomNumberGenerator_;
+     if (trueCopy >= 0) {
+          if (defaultHandler_)
+               handler_ = new CoinMessageHandler(*rhs.handler_);
+          else
+               handler_ = rhs.handler_;
+          eventHandler_ = rhs.eventHandler_->clone();
+          messages_ = rhs.messages_;
+          coinMessages_ = rhs.coinMessages_;
+     } else {
+          if (!eventHandler_ && rhs.eventHandler_)
+               eventHandler_ = rhs.eventHandler_->clone();
+     }
+     intParam_[ClpMaxNumIteration] = rhs.intParam_[ClpMaxNumIteration];
+     intParam_[ClpMaxNumIterationHotStart] =
+          rhs.intParam_[ClpMaxNumIterationHotStart];
+     intParam_[ClpNameDiscipline] = rhs.intParam_[ClpNameDiscipline] ;
+
+     dblParam_[ClpDualObjectiveLimit] = rhs.dblParam_[ClpDualObjectiveLimit];
+     dblParam_[ClpPrimalObjectiveLimit] = rhs.dblParam_[ClpPrimalObjectiveLimit];
+     dblParam_[ClpDualTolerance] = rhs.dblParam_[ClpDualTolerance];
+     dblParam_[ClpPrimalTolerance] = rhs.dblParam_[ClpPrimalTolerance];
+     dblParam_[ClpObjOffset] = rhs.dblParam_[ClpObjOffset];
+     dblParam_[ClpMaxSeconds] = rhs.dblParam_[ClpMaxSeconds];
+     dblParam_[ClpPresolveTolerance] = rhs.dblParam_[ClpPresolveTolerance];
+#ifndef CLP_NO_STD
+
+     strParam_[ClpProbName] = rhs.strParam_[ClpProbName];
+#endif
+
+     optimizationDirection_ = rhs.optimizationDirection_;
+     objectiveValue_ = rhs.objectiveValue_;
+     smallElement_ = rhs.smallElement_;
+     objectiveScale_ = rhs.objectiveScale_;
+     rhsScale_ = rhs.rhsScale_;
+     numberIterations_ = rhs.numberIterations_;
+     solveType_ = rhs.solveType_;
+     whatsChanged_ = rhs.whatsChanged_;
+     problemStatus_ = rhs.problemStatus_;
+     secondaryStatus_ = rhs.secondaryStatus_;
+     numberRows_ = rhs.numberRows_;
+     numberColumns_ = rhs.numberColumns_;
+     userPointer_ = rhs.userPointer_;
+     trustedUserPointer_ = rhs.trustedUserPointer_;
+     scalingFlag_ = rhs.scalingFlag_;
+     specialOptions_ = rhs.specialOptions_;
+     if (trueCopy) {
+#ifndef CLP_NO_STD
+          lengthNames_ = rhs.lengthNames_;
+          if (lengthNames_) {
+               rowNames_ = rhs.rowNames_;
+               columnNames_ = rhs.columnNames_;
+          }
+#endif
+          numberThreads_ = rhs.numberThreads_;
+          if (maximumRows_ < 0) {
+               specialOptions_ &= ~65536;
+               savedRowScale_ = NULL;
+               savedColumnScale_ = NULL;
+               integerType_ = CoinCopyOfArray(rhs.integerType_, numberColumns_);
+               rowActivity_ = ClpCopyOfArray(rhs.rowActivity_, numberRows_);
+               columnActivity_ = ClpCopyOfArray(rhs.columnActivity_, numberColumns_);
+               dual_ = ClpCopyOfArray(rhs.dual_, numberRows_);
+               reducedCost_ = ClpCopyOfArray(rhs.reducedCost_, numberColumns_);
+               rowLower_ = ClpCopyOfArray ( rhs.rowLower_, numberRows_ );
+               rowUpper_ = ClpCopyOfArray ( rhs.rowUpper_, numberRows_ );
+               columnLower_ = ClpCopyOfArray ( rhs.columnLower_, numberColumns_ );
+               columnUpper_ = ClpCopyOfArray ( rhs.columnUpper_, numberColumns_ );
+               rowScale_ = ClpCopyOfArray(rhs.rowScale_, numberRows_ * 2);
+               columnScale_ = ClpCopyOfArray(rhs.columnScale_, numberColumns_ * 2);
+               if (rhs.objective_)
+                    objective_  = rhs.objective_->clone();
+               else
+                    objective_ = NULL;
+               rowObjective_ = ClpCopyOfArray ( rhs.rowObjective_, numberRows_ );
+               status_ = ClpCopyOfArray( rhs.status_, numberColumns_ + numberRows_);
+               ray_ = NULL;
+               if (problemStatus_ == 1)
+                    ray_ = ClpCopyOfArray (rhs.ray_, numberRows_);
+               else if (problemStatus_ == 2)
+                    ray_ = ClpCopyOfArray (rhs.ray_, numberColumns_);
+               if (rhs.rowCopy_) {
+                    rowCopy_ = rhs.rowCopy_->clone();
+               } else {
+                    rowCopy_ = NULL;
+               }
+               if (rhs.scaledMatrix_) {
+                    scaledMatrix_ = new ClpPackedMatrix(*rhs.scaledMatrix_);
+               } else {
+                    scaledMatrix_ = NULL;
+               }
+               matrix_ = NULL;
+               if (rhs.matrix_) {
+                    matrix_ = rhs.matrix_->clone();
+               }
+          } else {
+               // This already has arrays - just copy
+               savedRowScale_ = NULL;
+               savedColumnScale_ = NULL;
+               startPermanentArrays();
+               if (rhs.integerType_) {
+                    assert (integerType_);
+                    ClpDisjointCopyN(rhs.integerType_, numberColumns_, integerType_);
+               } else {
+                    integerType_ = NULL;
+               }
+               if (rhs.rowActivity_) {
+                    ClpDisjointCopyN ( rhs.rowActivity_, numberRows_ ,
+                                       rowActivity_);
+                    ClpDisjointCopyN ( rhs.columnActivity_, numberColumns_ ,
+                                       columnActivity_);
+                    ClpDisjointCopyN ( rhs.dual_, numberRows_ ,
+                                       dual_);
+                    ClpDisjointCopyN ( rhs.reducedCost_, numberColumns_ ,
+                                       reducedCost_);
+               } else {
+                    rowActivity_ = NULL;
+                    columnActivity_ = NULL;
+                    dual_ = NULL;
+                    reducedCost_ = NULL;
+               }
+               ClpDisjointCopyN ( rhs.rowLower_, numberRows_, rowLower_ );
+               ClpDisjointCopyN ( rhs.rowUpper_, numberRows_, rowUpper_ );
+               ClpDisjointCopyN ( rhs.columnLower_, numberColumns_, columnLower_ );
+               assert ((specialOptions_ & 131072) == 0);
+               abort();
+               ClpDisjointCopyN ( rhs.columnUpper_, numberColumns_, columnUpper_ );
+               if (rhs.objective_) {
+                    abort(); //check if same
+                    objective_  = rhs.objective_->clone();
+               } else {
+                    objective_ = NULL;
+               }
+               assert (!rhs.rowObjective_);
+               ClpDisjointCopyN( rhs.status_, numberColumns_ + numberRows_, status_);
+               ray_ = NULL;
+               if (problemStatus_ == 1)
+                    ray_ = ClpCopyOfArray (rhs.ray_, numberRows_);
+               else if (problemStatus_ == 2)
+                    ray_ = ClpCopyOfArray (rhs.ray_, numberColumns_);
+               assert (!ray_);
+               delete rowCopy_;
+               if (rhs.rowCopy_) {
+                    rowCopy_ = rhs.rowCopy_->clone();
+               } else {
+                    rowCopy_ = NULL;
+               }
+               delete scaledMatrix_;
+               if (rhs.scaledMatrix_) {
+                    scaledMatrix_ = new ClpPackedMatrix(*rhs.scaledMatrix_);
+               } else {
+                    scaledMatrix_ = NULL;
+               }
+               delete matrix_;
+               matrix_ = NULL;
+               if (rhs.matrix_) {
+                    matrix_ = rhs.matrix_->clone();
+               }
+               if (rhs.savedRowScale_) {
+                    assert (savedRowScale_);
+                    assert (!rowScale_);
+                    ClpDisjointCopyN(rhs.savedRowScale_, 4 * maximumInternalRows_, savedRowScale_);
+                    ClpDisjointCopyN(rhs.savedColumnScale_, 4 * maximumInternalColumns_, savedColumnScale_);
+               } else {
+                    assert (!savedRowScale_);
+                    if (rowScale_) {
+                         ClpDisjointCopyN(rhs.rowScale_, numberRows_, rowScale_);
+                         ClpDisjointCopyN(rhs.columnScale_, numberColumns_, columnScale_);
+                    } else {
+                         rowScale_ = NULL;
+                         columnScale_ = NULL;
+                    }
+               }
+               abort(); // look at resizeDouble and resize
+          }
+     } else {
+          savedRowScale_ = rhs.savedRowScale_;
+          assert (!savedRowScale_);
+          savedColumnScale_ = rhs.savedColumnScale_;
+          rowActivity_ = rhs.rowActivity_;
+          columnActivity_ = rhs.columnActivity_;
+          dual_ = rhs.dual_;
+          reducedCost_ = rhs.reducedCost_;
+          rowLower_ = rhs.rowLower_;
+          rowUpper_ = rhs.rowUpper_;
+          objective_ = rhs.objective_;
+          rowObjective_ = rhs.rowObjective_;
+          columnLower_ = rhs.columnLower_;
+          columnUpper_ = rhs.columnUpper_;
+          matrix_ = rhs.matrix_;
+          rowCopy_ = NULL;
+          scaledMatrix_ = NULL;
+          ray_ = rhs.ray_;
+          //rowScale_ = rhs.rowScale_;
+          //columnScale_ = rhs.columnScale_;
+          lengthNames_ = 0;
+          numberThreads_ = rhs.numberThreads_;
+#ifndef CLP_NO_STD
+          rowNames_ = std::vector<std::string> ();
+          columnNames_ = std::vector<std::string> ();
+#endif
+          integerType_ = NULL;
+          status_ = rhs.status_;
+     }
+     inverseRowScale_ = NULL;
+     inverseColumnScale_ = NULL;
+}
+// Copy contents - resizing if necessary - otherwise re-use memory
+void
+ClpModel::copy(const ClpMatrixBase * from, ClpMatrixBase * & to)
+{
+     assert (from);
+     const ClpPackedMatrix * matrixFrom = (dynamic_cast<const ClpPackedMatrix*>(from));
+     ClpPackedMatrix * matrixTo = (dynamic_cast< ClpPackedMatrix*>(to));
+     if (matrixFrom && matrixTo) {
+          matrixTo->copy(matrixFrom);
+     } else {
+          delete to;
+          to =  from->clone();
+     }
+#if 0
+     delete modelPtr_->matrix_;
+     if (continuousModel_->matrix_) {
+          modelPtr_->matrix_ = continuousModel_->matrix_->clone();
+     } else {
+          modelPtr_->matrix_ = NULL;
+     }
+#endif
+}
+/* Borrow model.  This is so we dont have to copy large amounts
+   of data around.  It assumes a derived class wants to overwrite
+   an empty model with a real one - while it does an algorithm */
+void
+ClpModel::borrowModel(ClpModel & rhs)
+{
+     if (defaultHandler_) {
+          delete handler_;
+          handler_ = NULL;
+     }
+     gutsOfDelete(1);
+     optimizationDirection_ = rhs.optimizationDirection_;
+     numberRows_ = rhs.numberRows_;
+     numberColumns_ = rhs.numberColumns_;
+     delete [] rhs.ray_;
+     rhs.ray_ = NULL;
+     // make sure scaled matrix not copied
+     ClpPackedMatrix * save = rhs.scaledMatrix_;
+     rhs.scaledMatrix_ = NULL;
+     delete scaledMatrix_;
+     scaledMatrix_ = NULL;
+     gutsOfCopy(rhs, 0);
+     rhs.scaledMatrix_ = save;
+     specialOptions_ = rhs.specialOptions_ & ~65536;
+     savedRowScale_ = NULL;
+     savedColumnScale_ = NULL;
+     inverseRowScale_ = NULL;
+     inverseColumnScale_ = NULL;
+}
+// Return model - nulls all arrays so can be deleted safely
+void
+ClpModel::returnModel(ClpModel & otherModel)
+{
+     otherModel.objectiveValue_ = objectiveValue_;
+     otherModel.numberIterations_ = numberIterations_;
+     otherModel.problemStatus_ = problemStatus_;
+     otherModel.secondaryStatus_ = secondaryStatus_;
+     rowActivity_ = NULL;
+     columnActivity_ = NULL;
+     dual_ = NULL;
+     reducedCost_ = NULL;
+     rowLower_ = NULL;
+     rowUpper_ = NULL;
+     objective_ = NULL;
+     rowObjective_ = NULL;
+     columnLower_ = NULL;
+     columnUpper_ = NULL;
+     matrix_ = NULL;
+     if (rowCopy_ != otherModel.rowCopy_)
+       delete rowCopy_;
+     rowCopy_ = NULL;
+     delete scaledMatrix_;
+     scaledMatrix_ = NULL;
+     delete [] otherModel.ray_;
+     otherModel.ray_ = ray_;
+     ray_ = NULL;
+     if (rowScale_ && otherModel.rowScale_ != rowScale_) {
+          delete [] rowScale_;
+          delete [] columnScale_;
+     }
+     rowScale_ = NULL;
+     columnScale_ = NULL;
+     //rowScale_=NULL;
+     //columnScale_=NULL;
+     // do status
+     if (otherModel.status_ != status_) {
+          delete [] otherModel.status_;
+          otherModel.status_ = status_;
+     }
+     status_ = NULL;
+     if (defaultHandler_) {
+          delete handler_;
+          handler_ = NULL;
+     }
+     inverseRowScale_ = NULL;
+     inverseColumnScale_ = NULL;
+}
+//#############################################################################
+// Parameter related methods
+//#############################################################################
+
+bool
+ClpModel::setIntParam(ClpIntParam key, int value)
+{
+     switch (key) {
+     case ClpMaxNumIteration:
+          if (value < 0)
+               return false;
+          break;
+     case ClpMaxNumIterationHotStart:
+          if (value < 0)
+               return false;
+          break;
+     case ClpNameDiscipline:
+          if (value < 0)
+               return false;
+          break;
+     default:
+          return false;
+     }
+     intParam_[key] = value;
+     return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+ClpModel::setDblParam(ClpDblParam key, double value)
+{
+
+     switch (key) {
+     case ClpDualObjectiveLimit:
+          break;
+
+     case ClpPrimalObjectiveLimit:
+          break;
+
+     case ClpDualTolerance:
+          if (value <= 0.0 || value > 1.0e10)
+               return false;
+          break;
+
+     case ClpPrimalTolerance:
+          if (value <= 0.0 || value > 1.0e10)
+               return false;
+          break;
+
+     case ClpObjOffset:
+          break;
+
+     case ClpMaxSeconds:
+          if(value >= 0)
+               value += CoinCpuTime();
+          else
+               value = -1.0;
+          break;
+
+     case ClpPresolveTolerance:
+          if (value <= 0.0 || value > 1.0e10)
+               return false;
+          break;
+
+     default:
+          return false;
+     }
+     dblParam_[key] = value;
+     return true;
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_STD
+
+bool
+ClpModel::setStrParam(ClpStrParam key, const std::string & value)
+{
+
+     switch (key) {
+     case ClpProbName:
+          break;
+
+     default:
+          return false;
+     }
+     strParam_[key] = value;
+     return true;
+}
+#endif
+// Useful routines
+// Returns resized array and deletes incoming
+double * resizeDouble(double * array , int size, int newSize, double fill,
+                      bool createArray)
+{
+     if ((array || createArray) && size < newSize) {
+          int i;
+          double * newArray = new double[newSize];
+          if (array)
+               CoinMemcpyN(array, CoinMin(newSize, size), newArray);
+          delete [] array;
+          array = newArray;
+          for (i = size; i < newSize; i++)
+               array[i] = fill;
+     }
+     return array;
+}
+// Returns resized array and updates size
+double * deleteDouble(double * array , int size,
+                      int number, const int * which, int & newSize)
+{
+     if (array) {
+          int i ;
+          char * deleted = new char[size];
+          int numberDeleted = 0;
+          CoinZeroN(deleted, size);
+          for (i = 0; i < number; i++) {
+               int j = which[i];
+               if (j >= 0 && j < size && !deleted[j]) {
+                    numberDeleted++;
+                    deleted[j] = 1;
+               }
+          }
+          newSize = size - numberDeleted;
+          double * newArray = new double[newSize];
+          int put = 0;
+          for (i = 0; i < size; i++) {
+               if (!deleted[i]) {
+                    newArray[put++] = array[i];
+               }
+          }
+          delete [] array;
+          array = newArray;
+          delete [] deleted;
+     }
+     return array;
+}
+char * deleteChar(char * array , int size,
+                  int number, const int * which, int & newSize,
+                  bool ifDelete)
+{
+     if (array) {
+          int i ;
+          char * deleted = new char[size];
+          int numberDeleted = 0;
+          CoinZeroN(deleted, size);
+          for (i = 0; i < number; i++) {
+               int j = which[i];
+               if (j >= 0 && j < size && !deleted[j]) {
+                    numberDeleted++;
+                    deleted[j] = 1;
+               }
+          }
+          newSize = size - numberDeleted;
+          char * newArray = new char[newSize];
+          int put = 0;
+          for (i = 0; i < size; i++) {
+               if (!deleted[i]) {
+                    newArray[put++] = array[i];
+               }
+          }
+          if (ifDelete)
+               delete [] array;
+          array = newArray;
+          delete [] deleted;
+     }
+     return array;
+}
+// Create empty ClpPackedMatrix
+void
+ClpModel::createEmptyMatrix()
+{
+     delete matrix_;
+     whatsChanged_ = 0;
+     CoinPackedMatrix matrix2;
+     matrix_ = new ClpPackedMatrix(matrix2);
+}
+/* Really clean up matrix.
+   a) eliminate all duplicate AND small elements in matrix
+   b) remove all gaps and set extraGap_ and extraMajor_ to 0.0
+   c) reallocate arrays and make max lengths equal to lengths
+   d) orders elements
+   returns number of elements eliminated or -1 if not ClpMatrix
+*/
+int
+ClpModel::cleanMatrix(double threshold)
+{
+     ClpPackedMatrix * matrix = (dynamic_cast< ClpPackedMatrix*>(matrix_));
+     if (matrix) {
+          return matrix->getPackedMatrix()->cleanMatrix(threshold);
+     } else {
+          return -1;
+     }
+}
+// Resizes
+void
+ClpModel::resize (int newNumberRows, int newNumberColumns)
+{
+     if (newNumberRows == numberRows_ &&
+               newNumberColumns == numberColumns_)
+          return; // nothing to do
+     whatsChanged_ = 0;
+     int numberRows2 = newNumberRows;
+     int numberColumns2 = newNumberColumns;
+     if (numberRows2 < maximumRows_)
+          numberRows2 = maximumRows_;
+     if (numberColumns2 < maximumColumns_)
+          numberColumns2 = maximumColumns_;
+     if (numberRows2 > maximumRows_) {
+          rowActivity_ = resizeDouble(rowActivity_, numberRows_,
+                                      newNumberRows, 0.0, true);
+          dual_ = resizeDouble(dual_, numberRows_,
+                               newNumberRows, 0.0, true);
+          rowObjective_ = resizeDouble(rowObjective_, numberRows_,
+                                       newNumberRows, 0.0, false);
+          rowLower_ = resizeDouble(rowLower_, numberRows_,
+                                   newNumberRows, -COIN_DBL_MAX, true);
+          rowUpper_ = resizeDouble(rowUpper_, numberRows_,
+                                   newNumberRows, COIN_DBL_MAX, true);
+     }
+     if (numberColumns2 > maximumColumns_) {
+          columnActivity_ = resizeDouble(columnActivity_, numberColumns_,
+                                         newNumberColumns, 0.0, true);
+          reducedCost_ = resizeDouble(reducedCost_, numberColumns_,
+                                      newNumberColumns, 0.0, true);
+     }
+     if (savedRowScale_ && numberRows2 > maximumInternalRows_) {
+          double * temp;
+          temp = new double [4*newNumberRows];
+          CoinFillN(temp, 4 * newNumberRows, 1.0);
+          CoinMemcpyN(savedRowScale_, numberRows_, temp);
+          CoinMemcpyN(savedRowScale_ + maximumInternalRows_, numberRows_, temp + newNumberRows);
+          CoinMemcpyN(savedRowScale_ + 2 * maximumInternalRows_, numberRows_, temp + 2 * newNumberRows);
+          CoinMemcpyN(savedRowScale_ + 3 * maximumInternalRows_, numberRows_, temp + 3 * newNumberRows);
+          delete [] savedRowScale_;
+          savedRowScale_ = temp;
+     }
+     if (savedColumnScale_ && numberColumns2 > maximumInternalColumns_) {
+          double * temp;
+          temp = new double [4*newNumberColumns];
+          CoinFillN(temp, 4 * newNumberColumns, 1.0);
+          CoinMemcpyN(savedColumnScale_, numberColumns_, temp);
+          CoinMemcpyN(savedColumnScale_ + maximumInternalColumns_, numberColumns_, temp + newNumberColumns);
+          CoinMemcpyN(savedColumnScale_ + 2 * maximumInternalColumns_, numberColumns_, temp + 2 * newNumberColumns);
+          CoinMemcpyN(savedColumnScale_ + 3 * maximumInternalColumns_, numberColumns_, temp + 3 * newNumberColumns);
+          delete [] savedColumnScale_;
+          savedColumnScale_ = temp;
+     }
+     if (objective_ && numberColumns2 > maximumColumns_)
+          objective_->resize(newNumberColumns);
+     else if (!objective_)
+          objective_ = new ClpLinearObjective(NULL, newNumberColumns);
+     if (numberColumns2 > maximumColumns_) {
+          columnLower_ = resizeDouble(columnLower_, numberColumns_,
+                                      newNumberColumns, 0.0, true);
+          columnUpper_ = resizeDouble(columnUpper_, numberColumns_,
+                                      newNumberColumns, COIN_DBL_MAX, true);
+     }
+     if (newNumberRows < numberRows_) {
+          int * which = new int[numberRows_-newNumberRows];
+          int i;
+          for (i = newNumberRows; i < numberRows_; i++)
+               which[i-newNumberRows] = i;
+          matrix_->deleteRows(numberRows_ - newNumberRows, which);
+          delete [] which;
+     }
+     if (numberRows_ != newNumberRows || numberColumns_ != newNumberColumns) {
+          // set state back to unknown
+          problemStatus_ = -1;
+          secondaryStatus_ = 0;
+          delete [] ray_;
+          ray_ = NULL;
+     }
+     setRowScale(NULL);
+     setColumnScale(NULL);
+     if (status_) {
+          if (newNumberColumns + newNumberRows) {
+               if (newNumberColumns + newNumberRows > maximumRows_ + maximumColumns_) {
+                    unsigned char * tempC = new unsigned char [newNumberColumns+newNumberRows];
+                    unsigned char * tempR = tempC + newNumberColumns;
+                    memset(tempC, 3, newNumberColumns * sizeof(unsigned char));
+                    memset(tempR, 1, newNumberRows * sizeof(unsigned char));
+                    CoinMemcpyN(status_, CoinMin(newNumberColumns, numberColumns_), tempC);
+                    CoinMemcpyN(status_ + numberColumns_, CoinMin(newNumberRows, numberRows_), tempR);
+                    delete [] status_;
+                    status_ = tempC;
+               } else if (newNumberColumns < numberColumns_) {
+                    memmove(status_ + newNumberColumns, status_ + numberColumns_,
+                            newNumberRows);
+               } else if (newNumberColumns > numberColumns_) {
+                    memset(status_ + numberColumns_, 3, newNumberColumns - numberColumns_);
+                    memmove(status_ + newNumberColumns, status_ + numberColumns_,
+                            newNumberRows);
+               }
+          } else {
+               // empty model - some systems don't like new [0]
+               delete [] status_;
+               status_ = NULL;
+          }
+     }
+#ifndef CLP_NO_STD
+     if (lengthNames_) {
+          // redo row and column names
+          if (numberRows_ < newNumberRows) {
+               rowNames_.resize(newNumberRows);
+               lengthNames_ = CoinMax(lengthNames_, 8);
+               char name[9];
+               for (int iRow = numberRows_; iRow < newNumberRows; iRow++) {
+                    sprintf(name, "R%7.7d", iRow);
+                    rowNames_[iRow] = name;
+               }
+          }
+          if (numberColumns_ < newNumberColumns) {
+               columnNames_.resize(newNumberColumns);
+               lengthNames_ = CoinMax(lengthNames_, 8);
+               char name[9];
+               for (int iColumn = numberColumns_; iColumn < newNumberColumns; iColumn++) {
+                    sprintf(name, "C%7.7d", iColumn);
+                    columnNames_[iColumn] = name;
+               }
+          }
+     }
+#endif
+     numberRows_ = newNumberRows;
+     if (newNumberColumns < numberColumns_ && matrix_->getNumCols()) {
+          int * which = new int[numberColumns_-newNumberColumns];
+          int i;
+          for (i = newNumberColumns; i < numberColumns_; i++)
+               which[i-newNumberColumns] = i;
+          matrix_->deleteCols(numberColumns_ - newNumberColumns, which);
+          delete [] which;
+     }
+     if (integerType_ && numberColumns2 > maximumColumns_) {
+          char * temp = new char [newNumberColumns];
+          CoinZeroN(temp, newNumberColumns);
+          CoinMemcpyN(integerType_,
+                      CoinMin(newNumberColumns, numberColumns_), temp);
+          delete [] integerType_;
+          integerType_ = temp;
+     }
+     numberColumns_ = newNumberColumns;
+     if ((specialOptions_ & 65536) != 0) {
+          // leave until next create rim to up numbers
+     }
+     if (maximumRows_ >= 0) {
+          if (numberRows_ > maximumRows_)
+               COIN_DETAIL_PRINT(printf("resize %d rows, %d old maximum rows\n",
+					numberRows_, maximumRows_));
+          maximumRows_ = CoinMax(maximumRows_, numberRows_);
+          maximumColumns_ = CoinMax(maximumColumns_, numberColumns_);
+     }
+}
+// Deletes rows
+void
+ClpModel::deleteRows(int number, const int * which)
+{
+     if (!number)
+          return; // nothing to do
+     whatsChanged_ &= ~(1 + 2 + 4 + 8 + 16 + 32); // all except columns changed
+     int newSize = 0;
+     if (maximumRows_ < 0) {
+          rowActivity_ = deleteDouble(rowActivity_, numberRows_,
+                                      number, which, newSize);
+          dual_ = deleteDouble(dual_, numberRows_,
+                               number, which, newSize);
+          rowObjective_ = deleteDouble(rowObjective_, numberRows_,
+                                       number, which, newSize);
+          rowLower_ = deleteDouble(rowLower_, numberRows_,
+                                   number, which, newSize);
+          rowUpper_ = deleteDouble(rowUpper_, numberRows_,
+                                   number, which, newSize);
+          if (matrix_->getNumRows())
+               matrix_->deleteRows(number, which);
+          //matrix_->removeGaps();
+          // status
+          if (status_) {
+               if (numberColumns_ + newSize) {
+                    unsigned char * tempR  = reinterpret_cast<unsigned char *>
+                                             (deleteChar(reinterpret_cast<char *>(status_) + numberColumns_,
+                                                         numberRows_,
+                                                         number, which, newSize, false));
+                    unsigned char * tempC = new unsigned char [numberColumns_+newSize];
+                    CoinMemcpyN(status_, numberColumns_, tempC);
+                    CoinMemcpyN(tempR, newSize, tempC + numberColumns_);
+                    delete [] tempR;
+                    delete [] status_;
+                    status_ = tempC;
+               } else {
+                    // empty model - some systems don't like new [0]
+                    delete [] status_;
+                    status_ = NULL;
+               }
+          }
+     } else {
+          char * deleted = new char [numberRows_];
+          int i;
+          int numberDeleted = 0;
+          CoinZeroN(deleted, numberRows_);
+          for (i = 0; i < number; i++) {
+               int j = which[i];
+               if (j >= 0 && j < numberRows_ && !deleted[j]) {
+                    numberDeleted++;
+                    deleted[j] = 1;
+               }
+          }
+          assert (!rowObjective_);
+          unsigned char * status2 = status_ + numberColumns_;
+          for (i = 0; i < numberRows_; i++) {
+               if (!deleted[i]) {
+                    rowActivity_[newSize] = rowActivity_[i];
+                    dual_[newSize] = dual_[i];
+                    rowLower_[newSize] = rowLower_[i];
+                    rowUpper_[newSize] = rowUpper_[i];
+                    status2[newSize] = status2[i];
+                    newSize++;
+               }
+          }
+          if (matrix_->getNumRows())
+               matrix_->deleteRows(number, which);
+          //matrix_->removeGaps();
+          delete [] deleted;
+     }
+#ifndef CLP_NO_STD
+     // Now works if which out of order
+     if (lengthNames_) {
+          char * mark = new char [numberRows_];
+          CoinZeroN(mark, numberRows_);
+          int i;
+          for (i = 0; i < number; i++)
+               mark[which[i]] = 1;
+          int k = 0;
+          for ( i = 0; i < numberRows_; ++i) {
+               if (!mark[i])
+                    rowNames_[k++] = rowNames_[i];
+          }
+          rowNames_.erase(rowNames_.begin() + k, rowNames_.end());
+          delete [] mark;
+     }
+#endif
+     numberRows_ = newSize;
+     // set state back to unknown
+     problemStatus_ = -1;
+     secondaryStatus_ = 0;
+     delete [] ray_;
+     ray_ = NULL;
+     if (savedRowScale_ != rowScale_) {
+          delete [] rowScale_;
+          delete [] columnScale_;
+     }
+     rowScale_ = NULL;
+     columnScale_ = NULL;
+     delete scaledMatrix_;
+     scaledMatrix_ = NULL;
+}
+// Deletes columns
+void
+ClpModel::deleteColumns(int number, const int * which)
+{
+     if (!number)
+          return; // nothing to do
+     assert (maximumColumns_ < 0);
+     whatsChanged_ &= ~(1 + 2 + 4 + 8 + 64 + 128 + 256); // all except rows changed
+     int newSize = 0;
+     columnActivity_ = deleteDouble(columnActivity_, numberColumns_,
+                                    number, which, newSize);
+     reducedCost_ = deleteDouble(reducedCost_, numberColumns_,
+                                 number, which, newSize);
+     objective_->deleteSome(number, which);
+     columnLower_ = deleteDouble(columnLower_, numberColumns_,
+                                 number, which, newSize);
+     columnUpper_ = deleteDouble(columnUpper_, numberColumns_,
+                                 number, which, newSize);
+     // possible matrix is not full
+     if (matrix_->getNumCols() < numberColumns_) {
+          int * which2 = new int [number];
+          int n = 0;
+          int nMatrix = matrix_->getNumCols();
+          for (int i = 0; i < number; i++) {
+               if (which[i] < nMatrix)
+                    which2[n++] = which[i];
+          }
+          matrix_->deleteCols(n, which2);
+          delete [] which2;
+     } else {
+          matrix_->deleteCols(number, which);
+     }
+     //matrix_->removeGaps();
+     // status
+     if (status_) {
+          if (numberRows_ + newSize) {
+               unsigned char * tempC  = reinterpret_cast<unsigned char *>
+                                        (deleteChar(reinterpret_cast<char *>(status_),
+                                                    numberColumns_,
+                                                    number, which, newSize, false));
+               unsigned char * temp = new unsigned char [numberRows_+newSize];
+               CoinMemcpyN(tempC, newSize, temp);
+               CoinMemcpyN(status_ + numberColumns_,	numberRows_, temp + newSize);
+               delete [] tempC;
+               delete [] status_;
+               status_ = temp;
+          } else {
+               // empty model - some systems don't like new [0]
+               delete [] status_;
+               status_ = NULL;
+          }
+     }
+     integerType_ = deleteChar(integerType_, numberColumns_,
+                               number, which, newSize, true);
+#ifndef CLP_NO_STD
+     // Now works if which out of order
+     if (lengthNames_) {
+          char * mark = new char [numberColumns_];
+          CoinZeroN(mark, numberColumns_);
+          int i;
+          for (i = 0; i < number; i++)
+               mark[which[i]] = 1;
+          int k = 0;
+          for ( i = 0; i < numberColumns_; ++i) {
+               if (!mark[i])
+                    columnNames_[k++] = columnNames_[i];
+          }
+          columnNames_.erase(columnNames_.begin() + k, columnNames_.end());
+          delete [] mark;
+     }
+#endif
+     numberColumns_ = newSize;
+     // set state back to unknown
+     problemStatus_ = -1;
+     secondaryStatus_ = 0;
+     delete [] ray_;
+     ray_ = NULL;
+     setRowScale(NULL);
+     setColumnScale(NULL);
+}
+// Deletes rows AND columns (does not reallocate)
+void 
+ClpModel::deleteRowsAndColumns(int numberRows, const int * whichRows,
+			       int numberColumns, const int * whichColumns)
+{
+  if (!numberColumns) {
+    deleteRows(numberRows,whichRows);
+  } else if (!numberRows) {
+    deleteColumns(numberColumns,whichColumns);
+  } else {
+    whatsChanged_ &= ~511; // all changed
+    bool doStatus = status_!=NULL;
+    int numberTotal=numberRows_+numberColumns_;
+    int * backRows = new int [numberTotal];
+    int * backColumns = backRows+numberRows_;
+    memset(backRows,0,numberTotal*sizeof(int));
+    int newNumberColumns=0;
+    for (int i=0;i<numberColumns;i++) {
+      int iColumn=whichColumns[i];
+      if (iColumn>=0&&iColumn<numberColumns_)
+	backColumns[iColumn]=-1;
+    }
+    assert (objective_->type()==1);
+    double * obj = objective(); 
+    for (int i=0;i<numberColumns_;i++) {
+      if (!backColumns[i]) {
+	columnActivity_[newNumberColumns] = columnActivity_[i];
+	reducedCost_[newNumberColumns] = reducedCost_[i];
+	obj[newNumberColumns] = obj[i];
+	columnLower_[newNumberColumns] = columnLower_[i];
+	columnUpper_[newNumberColumns] = columnUpper_[i];
+	if (doStatus)
+	  status_[newNumberColumns] = status_[i];
+	backColumns[i]=newNumberColumns++;
+      }
+    }
+    integerType_ = deleteChar(integerType_, numberColumns_,
+			      numberColumns, whichColumns, newNumberColumns, true);
+#ifndef CLP_NO_STD
+    // Now works if which out of order
+    if (lengthNames_) {
+      for (int i=0;i<numberColumns_;i++) {
+	int iColumn=backColumns[i];
+	if (iColumn) 
+	  columnNames_[iColumn] = columnNames_[i];
+      }
+      columnNames_.erase(columnNames_.begin() + newNumberColumns, columnNames_.end());
+    }
+#endif
+    int newNumberRows=0;
+    assert (!rowObjective_);
+    unsigned char * status2 = status_ + numberColumns_;
+    unsigned char * status2a = status_ + newNumberColumns;
+    for (int i=0;i<numberRows;i++) {
+      int iRow=whichRows[i];
+      if (iRow>=0&&iRow<numberRows_)
+	backRows[iRow]=-1;
+    }
+    for (int i=0;i<numberRows_;i++) {
+      if (!backRows[i]) {
+	rowActivity_[newNumberRows] = rowActivity_[i];
+	dual_[newNumberRows] = dual_[i];
+	rowLower_[newNumberRows] = rowLower_[i];
+	rowUpper_[newNumberRows] = rowUpper_[i];
+	if (doStatus)
+	  status2a[newNumberRows] = status2[i];
+	backRows[i]=newNumberRows++;
+      }
+    }
+#ifndef CLP_NO_STD
+    // Now works if which out of order
+    if (lengthNames_) {
+      for (int i=0;i<numberRows_;i++) {
+	int iRow=backRows[i];
+	if (iRow) 
+	  rowNames_[iRow] = rowNames_[i];
+      }
+      rowNames_.erase(rowNames_.begin() + newNumberRows, rowNames_.end());
+    }
+#endif
+    // possible matrix is not full
+    ClpPackedMatrix * clpMatrix = dynamic_cast<ClpPackedMatrix *>(matrix_);
+    CoinPackedMatrix * matrix = clpMatrix ? clpMatrix->matrix() : NULL;
+    if (matrix_->getNumCols() < numberColumns_) {
+      assert (matrix);
+      CoinBigIndex nel=matrix->getNumElements();
+      int n=matrix->getNumCols();
+      matrix->reserve(numberColumns_,nel);
+      CoinBigIndex * columnStart = matrix->getMutableVectorStarts();
+      int * columnLength = matrix->getMutableVectorLengths();
+      for (int i=n;i<numberColumns_;i++) {
+	columnStart[i]=nel;
+	columnLength[i]=0;
+      }
+    }
+    if (matrix) {
+      matrix->setExtraMajor(0.1);
+      //CoinPackedMatrix temp(*matrix);
+      matrix->setExtraGap(0.0);
+      matrix->setExtraMajor(0.0);
+      int * row = matrix->getMutableIndices();
+      CoinBigIndex * columnStart = matrix->getMutableVectorStarts();
+      int * columnLength = matrix->getMutableVectorLengths();
+      double * element = matrix->getMutableElements();
+      newNumberColumns=0;
+      CoinBigIndex n=0;
+      for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+	if (backColumns[iColumn]>=0) {
+	  CoinBigIndex start = columnStart[iColumn];
+	  int nSave=n;
+	  columnStart[newNumberColumns]=n;
+	  for (CoinBigIndex j=start;j<start+columnLength[iColumn];j++) {
+	    int iRow=row[j];
+	    iRow = backRows[iRow];
+	    if (iRow>=0) {
+	      row[n]=iRow;
+	      element[n++]=element[j];
+	    }
+	  }
+	  columnLength[newNumberColumns++]=n-nSave;
+	}
+      }
+      columnStart[newNumberColumns]=n;
+      matrix->setNumElements(n);
+      matrix->setMajorDim(newNumberColumns);
+      matrix->setMinorDim(newNumberRows);
+      clpMatrix->setNumberActiveColumns(newNumberColumns);
+      //temp.deleteRows(numberRows, whichRows);
+      //temp.deleteCols(numberColumns, whichColumns);
+      //assert(matrix->isEquivalent2(temp));
+      //*matrix=temp;
+    } else {
+      matrix_->deleteRows(numberRows, whichRows);
+      matrix_->deleteCols(numberColumns, whichColumns);
+    }
+    numberColumns_ = newNumberColumns;
+    numberRows_ = newNumberRows;
+    delete [] backRows;
+    // set state back to unknown
+    problemStatus_ = -1;
+    secondaryStatus_ = 0;
+    delete [] ray_;
+    ray_ = NULL;
+    if (savedRowScale_ != rowScale_) {
+      delete [] rowScale_;
+      delete [] columnScale_;
+    }
+    rowScale_ = NULL;
+    columnScale_ = NULL;
+    delete scaledMatrix_;
+    scaledMatrix_ = NULL;
+    delete rowCopy_;
+    rowCopy_ = NULL;
+  }
+}
+// Add one row
+void
+ClpModel::addRow(int numberInRow, const int * columns,
+                 const double * elements, double rowLower, double rowUpper)
+{
+     CoinBigIndex starts[2];
+     starts[0] = 0;
+     starts[1] = numberInRow;
+     addRows(1, &rowLower, &rowUpper, starts, columns, elements);
+}
+// Add rows
+void
+ClpModel::addRows(int number, const double * rowLower,
+                  const double * rowUpper,
+                  const CoinBigIndex * rowStarts, const int * columns,
+                  const double * elements)
+{
+     if (number) {
+          whatsChanged_ &= ~(1 + 2 + 8 + 16 + 32); // all except columns changed
+          int numberRowsNow = numberRows_;
+          resize(numberRowsNow + number, numberColumns_);
+          double * lower = rowLower_ + numberRowsNow;
+          double * upper = rowUpper_ + numberRowsNow;
+          int iRow;
+          if (rowLower) {
+               for (iRow = 0; iRow < number; iRow++) {
+                    double value = rowLower[iRow];
+                    if (value < -1.0e20)
+                         value = -COIN_DBL_MAX;
+                    lower[iRow] = value;
+               }
+          } else {
+               for (iRow = 0; iRow < number; iRow++) {
+                    lower[iRow] = -COIN_DBL_MAX;
+               }
+          }
+          if (rowUpper) {
+               for (iRow = 0; iRow < number; iRow++) {
+                    double value = rowUpper[iRow];
+                    if (value > 1.0e20)
+                         value = COIN_DBL_MAX;
+                    upper[iRow] = value;
+               }
+          } else {
+               for (iRow = 0; iRow < number; iRow++) {
+                    upper[iRow] = COIN_DBL_MAX;
+               }
+          }
+          // Deal with matrix
+
+          delete rowCopy_;
+          rowCopy_ = NULL;
+          delete scaledMatrix_;
+          scaledMatrix_ = NULL;
+          if (!matrix_)
+               createEmptyMatrix();
+          setRowScale(NULL);
+          setColumnScale(NULL);
+#ifndef CLP_NO_STD
+          if (lengthNames_) {
+               rowNames_.resize(numberRows_);
+          }
+#endif
+          if (rowStarts) {
+	       // Make sure matrix has correct number of columns
+	       matrix_->getPackedMatrix()->reserve(numberColumns_, 0, true);
+               matrix_->appendMatrix(number, 0, rowStarts, columns, elements);
+          }
+     }
+}
+// Add rows
+void
+ClpModel::addRows(int number, const double * rowLower,
+                  const double * rowUpper,
+                  const CoinBigIndex * rowStarts,
+                  const int * rowLengths, const int * columns,
+                  const double * elements)
+{
+     if (number) {
+          CoinBigIndex numberElements = 0;
+          int iRow;
+          for (iRow = 0; iRow < number; iRow++)
+               numberElements += rowLengths[iRow];
+          int * newStarts = new int[number+1];
+          int * newIndex = new int[numberElements];
+          double * newElements = new double[numberElements];
+          numberElements = 0;
+          newStarts[0] = 0;
+          for (iRow = 0; iRow < number; iRow++) {
+               int iStart = rowStarts[iRow];
+               int length = rowLengths[iRow];
+               CoinMemcpyN(columns + iStart, length, newIndex + numberElements);
+               CoinMemcpyN(elements + iStart, length, newElements + numberElements);
+               numberElements += length;
+               newStarts[iRow+1] = numberElements;
+          }
+          addRows(number, rowLower, rowUpper,
+                  newStarts, newIndex, newElements);
+          delete [] newStarts;
+          delete [] newIndex;
+          delete [] newElements;
+     }
+}
+#ifndef CLP_NO_VECTOR
+void
+ClpModel::addRows(int number, const double * rowLower,
+                  const double * rowUpper,
+                  const CoinPackedVectorBase * const * rows)
+{
+     if (!number)
+          return;
+     whatsChanged_ &= ~(1 + 2 + 8 + 16 + 32); // all except columns changed
+     int numberRowsNow = numberRows_;
+     resize(numberRowsNow + number, numberColumns_);
+     double * lower = rowLower_ + numberRowsNow;
+     double * upper = rowUpper_ + numberRowsNow;
+     int iRow;
+     if (rowLower) {
+          for (iRow = 0; iRow < number; iRow++) {
+               double value = rowLower[iRow];
+               if (value < -1.0e20)
+                    value = -COIN_DBL_MAX;
+               lower[iRow] = value;
+          }
+     } else {
+          for (iRow = 0; iRow < number; iRow++) {
+               lower[iRow] = -COIN_DBL_MAX;
+          }
+     }
+     if (rowUpper) {
+          for (iRow = 0; iRow < number; iRow++) {
+               double value = rowUpper[iRow];
+               if (value > 1.0e20)
+                    value = COIN_DBL_MAX;
+               upper[iRow] = value;
+          }
+     } else {
+          for (iRow = 0; iRow < number; iRow++) {
+               upper[iRow] = COIN_DBL_MAX;
+          }
+     }
+     // Deal with matrix
+
+     delete rowCopy_;
+     rowCopy_ = NULL;
+     delete scaledMatrix_;
+     scaledMatrix_ = NULL;
+     if (!matrix_)
+          createEmptyMatrix();
+     if (rows)
+          matrix_->appendRows(number, rows);
+     setRowScale(NULL);
+     setColumnScale(NULL);
+     if (lengthNames_) {
+          rowNames_.resize(numberRows_);
+     }
+}
+#endif
+#ifndef SLIM_CLP
+// Add rows from a build object
+int
+ClpModel::addRows(const CoinBuild & buildObject, bool tryPlusMinusOne, bool checkDuplicates)
+{
+     CoinAssertHint (buildObject.type() == 0, "Looks as if both addRows and addCols being used"); // check correct
+     int number = buildObject.numberRows();
+     int numberErrors = 0;
+     if (number) {
+          CoinBigIndex size = 0;
+          int iRow;
+          double * lower = new double [number];
+          double * upper = new double [number];
+          if ((!matrix_ || !matrix_->getNumElements()) && tryPlusMinusOne) {
+               // See if can be +-1
+               for (iRow = 0; iRow < number; iRow++) {
+                    const int * columns;
+                    const double * elements;
+                    int numberElements = buildObject.row(iRow, lower[iRow],
+                                                         upper[iRow],
+                                                         columns, elements);
+                    for (int i = 0; i < numberElements; i++) {
+                         // allow for zero elements
+                         if (elements[i]) {
+                              if (fabs(elements[i]) == 1.0) {
+                                   size++;
+                              } else {
+                                   // bad
+                                   tryPlusMinusOne = false;
+                              }
+                         }
+                    }
+                    if (!tryPlusMinusOne)
+                         break;
+               }
+          } else {
+               // Will add to whatever sort of matrix exists
+               tryPlusMinusOne = false;
+          }
+          if (!tryPlusMinusOne) {
+               CoinBigIndex numberElements = buildObject.numberElements();
+               CoinBigIndex * starts = new CoinBigIndex [number+1];
+               int * column = new int[numberElements];
+               double * element = new double[numberElements];
+               starts[0] = 0;
+               numberElements = 0;
+               for (iRow = 0; iRow < number; iRow++) {
+                    const int * columns;
+                    const double * elements;
+                    int numberElementsThis = buildObject.row(iRow, lower[iRow], upper[iRow],
+                                             columns, elements);
+                    CoinMemcpyN(columns, numberElementsThis, column + numberElements);
+                    CoinMemcpyN(elements, numberElementsThis, element + numberElements);
+                    numberElements += numberElementsThis;
+                    starts[iRow+1] = numberElements;
+               }
+               addRows(number, lower, upper, NULL);
+               // make sure matrix has enough columns
+               matrix_->setDimensions(-1, numberColumns_);
+               numberErrors = matrix_->appendMatrix(number, 0, starts, column, element,
+                                                    checkDuplicates ? numberColumns_ : -1);
+               delete [] starts;
+               delete [] column;
+               delete [] element;
+          } else {
+               char * which = NULL; // for duplicates
+               if (checkDuplicates) {
+                    which = new char[numberColumns_];
+                    CoinZeroN(which, numberColumns_);
+               }
+               // build +-1 matrix
+               // arrays already filled in
+               addRows(number, lower, upper, NULL);
+               CoinBigIndex * startPositive = new CoinBigIndex [numberColumns_+1];
+               CoinBigIndex * startNegative = new CoinBigIndex [numberColumns_];
+               int * indices = new int [size];
+               CoinZeroN(startPositive, numberColumns_);
+               CoinZeroN(startNegative, numberColumns_);
+               int maxColumn = -1;
+               // need two passes
+               for (iRow = 0; iRow < number; iRow++) {
+                    const int * columns;
+                    const double * elements;
+                    int numberElements = buildObject.row(iRow, lower[iRow],
+                                                         upper[iRow],
+                                                         columns, elements);
+                    for (int i = 0; i < numberElements; i++) {
+                         int iColumn = columns[i];
+                         if (checkDuplicates) {
+                              if (iColumn >= numberColumns_) {
+                                   if(which[iColumn])
+                                        numberErrors++;
+                                   else
+                                        which[iColumn] = 1;
+                              } else {
+                                   numberErrors++;
+                                   // and may as well switch off
+                                   checkDuplicates = false;
+                              }
+                         }
+                         maxColumn = CoinMax(maxColumn, iColumn);
+                         if (elements[i] == 1.0) {
+                              startPositive[iColumn]++;
+                         } else if (elements[i] == -1.0) {
+                              startNegative[iColumn]++;
+                         }
+                    }
+                    if (checkDuplicates) {
+                         for (int i = 0; i < numberElements; i++) {
+                              int iColumn = columns[i];
+                              which[iColumn] = 0;
+                         }
+                    }
+               }
+               // check size
+               int numberColumns = maxColumn + 1;
+               CoinAssertHint (numberColumns <= numberColumns_,
+                               "rows having column indices >= numberColumns_");
+               size = 0;
+               int iColumn;
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    CoinBigIndex n = startPositive[iColumn];
+                    startPositive[iColumn] = size;
+                    size += n;
+                    n = startNegative[iColumn];
+                    startNegative[iColumn] = size;
+                    size += n;
+               }
+               startPositive[numberColumns_] = size;
+               for (iRow = 0; iRow < number; iRow++) {
+                    const int * columns;
+                    const double * elements;
+                    int numberElements = buildObject.row(iRow, lower[iRow],
+                                                         upper[iRow],
+                                                         columns, elements);
+                    for (int i = 0; i < numberElements; i++) {
+                         int iColumn = columns[i];
+                         maxColumn = CoinMax(maxColumn, iColumn);
+                         if (elements[i] == 1.0) {
+                              CoinBigIndex position = startPositive[iColumn];
+                              indices[position] = iRow;
+                              startPositive[iColumn]++;
+                         } else if (elements[i] == -1.0) {
+                              CoinBigIndex position = startNegative[iColumn];
+                              indices[position] = iRow;
+                              startNegative[iColumn]++;
+                         }
+                    }
+               }
+               // and now redo starts
+               for (iColumn = numberColumns_ - 1; iColumn >= 0; iColumn--) {
+                    startPositive[iColumn+1] = startNegative[iColumn];
+                    startNegative[iColumn] = startPositive[iColumn];
+               }
+               startPositive[0] = 0;
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    CoinBigIndex start = startPositive[iColumn];
+                    CoinBigIndex end = startNegative[iColumn];
+                    std::sort(indices + start, indices + end);
+                    start = startNegative[iColumn];
+                    end = startPositive[iColumn+1];
+                    std::sort(indices + start, indices + end);
+               }
+               // Get good object
+               delete matrix_;
+               ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
+               matrix->passInCopy(numberRows_, numberColumns,
+                                  true, indices, startPositive, startNegative);
+               matrix_ = matrix;
+               delete [] which;
+          }
+          delete [] lower;
+          delete [] upper;
+          // make sure matrix correct size
+          matrix_->setDimensions(numberRows_, numberColumns_);
+     }
+     return numberErrors;
+}
+#endif
+#ifndef SLIM_NOIO
+// Add rows from a model object
+int
+ClpModel::addRows( CoinModel & modelObject, bool tryPlusMinusOne, bool checkDuplicates)
+{
+     if (modelObject.numberElements() == 0)
+          return 0;
+     bool goodState = true;
+     int numberErrors = 0;
+     if (modelObject.columnLowerArray()) {
+          // some column information exists
+          int numberColumns2 = modelObject.numberColumns();
+          const double * columnLower = modelObject.columnLowerArray();
+          const double * columnUpper = modelObject.columnUpperArray();
+          const double * objective = modelObject.objectiveArray();
+          const int * integerType = modelObject.integerTypeArray();
+          for (int i = 0; i < numberColumns2; i++) {
+               if (columnLower[i] != 0.0)
+                    goodState = false;
+               if (columnUpper[i] != COIN_DBL_MAX)
+                    goodState = false;
+               if (objective[i] != 0.0)
+                    goodState = false;
+               if (integerType[i] != 0)
+                    goodState = false;
+          }
+     }
+     if (goodState) {
+          // can do addRows
+          // Set arrays for normal use
+          double * rowLower = modelObject.rowLowerArray();
+          double * rowUpper = modelObject.rowUpperArray();
+          double * columnLower = modelObject.columnLowerArray();
+          double * columnUpper = modelObject.columnUpperArray();
+          double * objective = modelObject.objectiveArray();
+          int * integerType = modelObject.integerTypeArray();
+          double * associated = modelObject.associatedArray();
+          // If strings then do copies
+          if (modelObject.stringsExist()) {
+               numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                                       objective, integerType, associated);
+          }
+          int numberRows = numberRows_; // save number of rows
+          int numberRows2 = modelObject.numberRows();
+          if (numberRows2 && !numberErrors) {
+               CoinBigIndex * startPositive = NULL;
+               CoinBigIndex * startNegative = NULL;
+               int numberColumns = modelObject.numberColumns();
+               if ((!matrix_ || !matrix_->getNumElements()) && !numberRows && tryPlusMinusOne) {
+                    startPositive = new CoinBigIndex[numberColumns+1];
+                    startNegative = new CoinBigIndex[numberColumns];
+                    modelObject.countPlusMinusOne(startPositive, startNegative, associated);
+                    if (startPositive[0] < 0) {
+                         // no good
+                         tryPlusMinusOne = false;
+                         delete [] startPositive;
+                         delete [] startNegative;
+                    }
+               } else {
+                    // Will add to whatever sort of matrix exists
+                    tryPlusMinusOne = false;
+               }
+               assert (rowLower);
+               addRows(numberRows2, rowLower, rowUpper, NULL, NULL, NULL);
+#ifndef SLIM_CLP
+               if (!tryPlusMinusOne) {
+#endif
+                    CoinPackedMatrix matrix;
+                    modelObject.createPackedMatrix(matrix, associated);
+                    assert (!matrix.getExtraGap());
+                    if (matrix_->getNumRows()) {
+                         // matrix by rows
+                         matrix.reverseOrdering();
+                         assert (!matrix.getExtraGap());
+                         const int * column = matrix.getIndices();
+                         //const int * rowLength = matrix.getVectorLengths();
+                         const CoinBigIndex * rowStart = matrix.getVectorStarts();
+                         const double * element = matrix.getElements();
+                         // make sure matrix has enough columns
+                         matrix_->setDimensions(-1, numberColumns_);
+                         numberErrors += matrix_->appendMatrix(numberRows2, 0, rowStart, column, element,
+                                                               checkDuplicates ? numberColumns_ : -1);
+                    } else {
+                         delete matrix_;
+                         matrix_ = new ClpPackedMatrix(matrix);
+                    }
+#ifndef SLIM_CLP
+               } else {
+                    // create +-1 matrix
+                    CoinBigIndex size = startPositive[numberColumns];
+                    int * indices = new int[size];
+                    modelObject.createPlusMinusOne(startPositive, startNegative, indices,
+                                                   associated);
+                    // Get good object
+                    ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
+                    matrix->passInCopy(numberRows2, numberColumns,
+                                       true, indices, startPositive, startNegative);
+                    delete matrix_;
+                    matrix_ = matrix;
+               }
+               // Do names if wanted
+               if (modelObject.rowNames()->numberItems()) {
+                    const char *const * rowNames = modelObject.rowNames()->names();
+                    copyRowNames(rowNames, numberRows, numberRows_);
+               }
+#endif
+          }
+          if (rowLower != modelObject.rowLowerArray()) {
+               delete [] rowLower;
+               delete [] rowUpper;
+               delete [] columnLower;
+               delete [] columnUpper;
+               delete [] objective;
+               delete [] integerType;
+               delete [] associated;
+               if (numberErrors)
+                    handler_->message(CLP_BAD_STRING_VALUES, messages_)
+                              << numberErrors
+                              << CoinMessageEol;
+          }
+          return numberErrors;
+     } else {
+          // not suitable for addRows
+          handler_->message(CLP_COMPLICATED_MODEL, messages_)
+                    << modelObject.numberRows()
+                    << modelObject.numberColumns()
+                    << CoinMessageEol;
+          return -1;
+     }
+}
+#endif
+// Add one column
+void
+ClpModel::addColumn(int numberInColumn,
+                    const int * rows,
+                    const double * elements,
+                    double columnLower,
+                    double  columnUpper,
+                    double  objective)
+{
+     CoinBigIndex starts[2];
+     starts[0] = 0;
+     starts[1] = numberInColumn;
+     addColumns(1, &columnLower, &columnUpper, &objective, starts, rows, elements);
+}
+// Add columns
+void
+ClpModel::addColumns(int number, const double * columnLower,
+                     const double * columnUpper,
+                     const double * objIn,
+                     const int * columnStarts, const int * rows,
+                     const double * elements)
+{
+     // Create a list of CoinPackedVectors
+     if (number) {
+          whatsChanged_ &= ~(1 + 2 + 4 + 64 + 128 + 256); // all except rows changed
+          int numberColumnsNow = numberColumns_;
+          resize(numberRows_, numberColumnsNow + number);
+          double * lower = columnLower_ + numberColumnsNow;
+          double * upper = columnUpper_ + numberColumnsNow;
+          double * obj = objective() + numberColumnsNow;
+          int iColumn;
+          if (columnLower) {
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    double value = columnLower[iColumn];
+                    if (value < -1.0e20)
+                         value = -COIN_DBL_MAX;
+                    lower[iColumn] = value;
+               }
+          } else {
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    lower[iColumn] = 0.0;
+               }
+          }
+          if (columnUpper) {
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    double value = columnUpper[iColumn];
+                    if (value > 1.0e20)
+                         value = COIN_DBL_MAX;
+                    upper[iColumn] = value;
+               }
+          } else {
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    upper[iColumn] = COIN_DBL_MAX;
+               }
+          }
+          if (objIn) {
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    obj[iColumn] = objIn[iColumn];
+               }
+          } else {
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    obj[iColumn] = 0.0;
+               }
+          }
+          // Deal with matrix
+
+          delete rowCopy_;
+          rowCopy_ = NULL;
+          delete scaledMatrix_;
+          scaledMatrix_ = NULL;
+          if (!matrix_)
+               createEmptyMatrix();
+          setRowScale(NULL);
+          setColumnScale(NULL);
+#ifndef CLP_NO_STD
+          if (lengthNames_) {
+               columnNames_.resize(numberColumns_);
+          }
+#endif
+          // Do even if elements NULL (to resize)
+	  matrix_->appendMatrix(number, 1, columnStarts, rows, elements);
+     }
+}
+// Add columns
+void
+ClpModel::addColumns(int number, const double * columnLower,
+                     const double * columnUpper,
+                     const double * objIn,
+                     const int * columnStarts,
+                     const int * columnLengths, const int * rows,
+                     const double * elements)
+{
+     if (number) {
+          CoinBigIndex numberElements = 0;
+          int iColumn;
+          for (iColumn = 0; iColumn < number; iColumn++)
+               numberElements += columnLengths[iColumn];
+          int * newStarts = new int[number+1];
+          int * newIndex = new int[numberElements];
+          double * newElements = new double[numberElements];
+          numberElements = 0;
+          newStarts[0] = 0;
+          for (iColumn = 0; iColumn < number; iColumn++) {
+               int iStart = columnStarts[iColumn];
+               int length = columnLengths[iColumn];
+               CoinMemcpyN(rows + iStart, length, newIndex + numberElements);
+               CoinMemcpyN(elements + iStart, length, newElements + numberElements);
+               numberElements += length;
+               newStarts[iColumn+1] = numberElements;
+          }
+          addColumns(number, columnLower, columnUpper, objIn,
+                     newStarts, newIndex, newElements);
+          delete [] newStarts;
+          delete [] newIndex;
+          delete [] newElements;
+     }
+}
+#ifndef CLP_NO_VECTOR
+void
+ClpModel::addColumns(int number, const double * columnLower,
+                     const double * columnUpper,
+                     const double * objIn,
+                     const CoinPackedVectorBase * const * columns)
+{
+     if (!number)
+          return;
+     whatsChanged_ &= ~(1 + 2 + 4 + 64 + 128 + 256); // all except rows changed
+     int numberColumnsNow = numberColumns_;
+     resize(numberRows_, numberColumnsNow + number);
+     double * lower = columnLower_ + numberColumnsNow;
+     double * upper = columnUpper_ + numberColumnsNow;
+     double * obj = objective() + numberColumnsNow;
+     int iColumn;
+     if (columnLower) {
+          for (iColumn = 0; iColumn < number; iColumn++) {
+               double value = columnLower[iColumn];
+               if (value < -1.0e20)
+                    value = -COIN_DBL_MAX;
+               lower[iColumn] = value;
+          }
+     } else {
+          for (iColumn = 0; iColumn < number; iColumn++) {
+               lower[iColumn] = 0.0;
+          }
+     }
+     if (columnUpper) {
+          for (iColumn = 0; iColumn < number; iColumn++) {
+               double value = columnUpper[iColumn];
+               if (value > 1.0e20)
+                    value = COIN_DBL_MAX;
+               upper[iColumn] = value;
+          }
+     } else {
+          for (iColumn = 0; iColumn < number; iColumn++) {
+               upper[iColumn] = COIN_DBL_MAX;
+          }
+     }
+     if (objIn) {
+          for (iColumn = 0; iColumn < number; iColumn++) {
+               obj[iColumn] = objIn[iColumn];
+          }
+     } else {
+          for (iColumn = 0; iColumn < number; iColumn++) {
+               obj[iColumn] = 0.0;
+          }
+     }
+     // Deal with matrix
+
+     delete rowCopy_;
+     rowCopy_ = NULL;
+     delete scaledMatrix_;
+     scaledMatrix_ = NULL;
+     if (!matrix_)
+          createEmptyMatrix();
+     if (columns)
+          matrix_->appendCols(number, columns);
+     setRowScale(NULL);
+     setColumnScale(NULL);
+     if (lengthNames_) {
+          columnNames_.resize(numberColumns_);
+     }
+}
+#endif
+#ifndef SLIM_CLP
+// Add columns from a build object
+int
+ClpModel::addColumns(const CoinBuild & buildObject, bool tryPlusMinusOne, bool checkDuplicates)
+{
+     CoinAssertHint (buildObject.type() == 1, "Looks as if both addRows and addCols being used"); // check correct
+     int number = buildObject.numberColumns();
+     int numberErrors = 0;
+     if (number) {
+          CoinBigIndex size = 0;
+          int maximumLength = 0;
+          double * lower = new double [number];
+          double * upper = new double [number];
+          int iColumn;
+          double * objective = new double [number];
+          if ((!matrix_ || !matrix_->getNumElements()) && tryPlusMinusOne) {
+               // See if can be +-1
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    const int * rows;
+                    const double * elements;
+                    int numberElements = buildObject.column(iColumn, lower[iColumn],
+                                                            upper[iColumn], objective[iColumn],
+                                                            rows, elements);
+                    maximumLength = CoinMax(maximumLength, numberElements);
+                    for (int i = 0; i < numberElements; i++) {
+                         // allow for zero elements
+                         if (elements[i]) {
+                              if (fabs(elements[i]) == 1.0) {
+                                   size++;
+                              } else {
+                                   // bad
+                                   tryPlusMinusOne = false;
+                              }
+                         }
+                    }
+                    if (!tryPlusMinusOne)
+                         break;
+               }
+          } else {
+               // Will add to whatever sort of matrix exists
+               tryPlusMinusOne = false;
+          }
+          if (!tryPlusMinusOne) {
+               CoinBigIndex numberElements = buildObject.numberElements();
+               CoinBigIndex * starts = new CoinBigIndex [number+1];
+               int * row = new int[numberElements];
+               double * element = new double[numberElements];
+               starts[0] = 0;
+               numberElements = 0;
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    const int * rows;
+                    const double * elements;
+                    int numberElementsThis = buildObject.column(iColumn, lower[iColumn], upper[iColumn],
+                                             objective[iColumn], rows, elements);
+                    CoinMemcpyN(rows, numberElementsThis, row + numberElements);
+                    CoinMemcpyN(elements, numberElementsThis, element + numberElements);
+                    numberElements += numberElementsThis;
+                    starts[iColumn+1] = numberElements;
+               }
+               addColumns(number, lower, upper, objective, NULL);
+               // make sure matrix has enough rows
+               matrix_->setDimensions(numberRows_, -1);
+               numberErrors = matrix_->appendMatrix(number, 1, starts, row, element,
+                                                    checkDuplicates ? numberRows_ : -1);
+               delete [] starts;
+               delete [] row;
+               delete [] element;
+          } else {
+               // arrays already filled in
+               addColumns(number, lower, upper, objective, NULL);
+               char * which = NULL; // for duplicates
+               if (checkDuplicates) {
+                    which = new char[numberRows_];
+                    CoinZeroN(which, numberRows_);
+               }
+               // build +-1 matrix
+               CoinBigIndex * startPositive = new CoinBigIndex [number+1];
+               CoinBigIndex * startNegative = new CoinBigIndex [number];
+               int * indices = new int [size];
+               int * neg = new int[maximumLength];
+               startPositive[0] = 0;
+               size = 0;
+               int maxRow = -1;
+               for (iColumn = 0; iColumn < number; iColumn++) {
+                    const int * rows;
+                    const double * elements;
+                    int numberElements = buildObject.column(iColumn, lower[iColumn],
+                                                            upper[iColumn], objective[iColumn],
+                                                            rows, elements);
+                    int nNeg = 0;
+                    CoinBigIndex start = size;
+                    for (int i = 0; i < numberElements; i++) {
+                         int iRow = rows[i];
+                         if (checkDuplicates) {
+                              if (iRow >= numberRows_) {
+                                   if(which[iRow])
+                                        numberErrors++;
+                                   else
+                                        which[iRow] = 1;
+                              } else {
+                                   numberErrors++;
+                                   // and may as well switch off
+                                   checkDuplicates = false;
+                              }
+                         }
+                         maxRow = CoinMax(maxRow, iRow);
+                         if (elements[i] == 1.0) {
+                              indices[size++] = iRow;
+                         } else if (elements[i] == -1.0) {
+                              neg[nNeg++] = iRow;
+                         }
+                    }
+                    std::sort(indices + start, indices + size);
+                    std::sort(neg, neg + nNeg);
+                    startNegative[iColumn] = size;
+                    CoinMemcpyN(neg, nNeg, indices + size);
+                    size += nNeg;
+                    startPositive[iColumn+1] = size;
+               }
+               delete [] neg;
+               // check size
+               assert (maxRow + 1 <= numberRows_);
+               // Get good object
+               delete matrix_;
+               ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
+               matrix->passInCopy(numberRows_, number, true, indices, startPositive, startNegative);
+               matrix_ = matrix;
+               delete [] which;
+          }
+          delete [] objective;
+          delete [] lower;
+          delete [] upper;
+     }
+     return 0;
+}
+#endif
+#ifndef SLIM_NOIO
+// Add columns from a model object
+int
+ClpModel::addColumns( CoinModel & modelObject, bool tryPlusMinusOne, bool checkDuplicates)
+{
+     if (modelObject.numberElements() == 0)
+          return 0;
+     bool goodState = true;
+     if (modelObject.rowLowerArray()) {
+          // some row information exists
+          int numberRows2 = modelObject.numberRows();
+          const double * rowLower = modelObject.rowLowerArray();
+          const double * rowUpper = modelObject.rowUpperArray();
+          for (int i = 0; i < numberRows2; i++) {
+               if (rowLower[i] != -COIN_DBL_MAX)
+                    goodState = false;
+               if (rowUpper[i] != COIN_DBL_MAX)
+                    goodState = false;
+          }
+     }
+     if (goodState) {
+          // can do addColumns
+          int numberErrors = 0;
+          // Set arrays for normal use
+          double * rowLower = modelObject.rowLowerArray();
+          double * rowUpper = modelObject.rowUpperArray();
+          double * columnLower = modelObject.columnLowerArray();
+          double * columnUpper = modelObject.columnUpperArray();
+          double * objective = modelObject.objectiveArray();
+          int * integerType = modelObject.integerTypeArray();
+          double * associated = modelObject.associatedArray();
+          // If strings then do copies
+          if (modelObject.stringsExist()) {
+               numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                                       objective, integerType, associated);
+          }
+          int numberColumns = numberColumns_; // save number of columns
+          int numberColumns2 = modelObject.numberColumns();
+          if (numberColumns2 && !numberErrors) {
+               CoinBigIndex * startPositive = NULL;
+               CoinBigIndex * startNegative = NULL;
+               if ((!matrix_ || !matrix_->getNumElements()) && !numberColumns && tryPlusMinusOne) {
+                    startPositive = new CoinBigIndex[numberColumns2+1];
+                    startNegative = new CoinBigIndex[numberColumns2];
+                    modelObject.countPlusMinusOne(startPositive, startNegative, associated);
+                    if (startPositive[0] < 0) {
+                         // no good
+                         tryPlusMinusOne = false;
+                         delete [] startPositive;
+                         delete [] startNegative;
+                    }
+               } else {
+                    // Will add to whatever sort of matrix exists
+                    tryPlusMinusOne = false;
+               }
+               assert (columnLower);
+               addColumns(numberColumns2, columnLower, columnUpper, objective, NULL, NULL, NULL);
+#ifndef SLIM_CLP
+               if (!tryPlusMinusOne) {
+#endif
+                    CoinPackedMatrix matrix;
+                    modelObject.createPackedMatrix(matrix, associated);
+                    assert (!matrix.getExtraGap());
+                    if (matrix_->getNumCols()) {
+                         const int * row = matrix.getIndices();
+                         //const int * columnLength = matrix.getVectorLengths();
+                         const CoinBigIndex * columnStart = matrix.getVectorStarts();
+                         const double * element = matrix.getElements();
+                         // make sure matrix has enough rows
+                         matrix_->setDimensions(numberRows_, -1);
+                         numberErrors += matrix_->appendMatrix(numberColumns2, 1, columnStart, row, element,
+                                                               checkDuplicates ? numberRows_ : -1);
+                    } else {
+                         delete matrix_;
+                         matrix_ = new ClpPackedMatrix(matrix);
+                    }
+#ifndef SLIM_CLP
+               } else {
+                    // create +-1 matrix
+                    CoinBigIndex size = startPositive[numberColumns2];
+                    int * indices = new int[size];
+                    modelObject.createPlusMinusOne(startPositive, startNegative, indices,
+                                                   associated);
+                    // Get good object
+                    ClpPlusMinusOneMatrix * matrix = new ClpPlusMinusOneMatrix();
+                    matrix->passInCopy(numberRows_, numberColumns2,
+                                       true, indices, startPositive, startNegative);
+                    delete matrix_;
+                    matrix_ = matrix;
+               }
+#endif
+#ifndef CLP_NO_STD
+               // Do names if wanted
+               if (modelObject.columnNames()->numberItems()) {
+                    const char *const * columnNames = modelObject.columnNames()->names();
+                    copyColumnNames(columnNames, numberColumns, numberColumns_);
+               }
+#endif
+               // Do integers if wanted
+               assert(integerType);
+               for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
+                    if (integerType[iColumn])
+                         setInteger(iColumn + numberColumns);
+               }
+          }
+          if (columnLower != modelObject.columnLowerArray()) {
+               delete [] rowLower;
+               delete [] rowUpper;
+               delete [] columnLower;
+               delete [] columnUpper;
+               delete [] objective;
+               delete [] integerType;
+               delete [] associated;
+               if (numberErrors)
+                    handler_->message(CLP_BAD_STRING_VALUES, messages_)
+                              << numberErrors
+                              << CoinMessageEol;
+          }
+          return numberErrors;
+     } else {
+          // not suitable for addColumns
+          handler_->message(CLP_COMPLICATED_MODEL, messages_)
+                    << modelObject.numberRows()
+                    << modelObject.numberColumns()
+                    << CoinMessageEol;
+          return -1;
+     }
+}
+#endif
+// chgRowLower
+void
+ClpModel::chgRowLower(const double * rowLower)
+{
+     int numberRows = numberRows_;
+     int iRow;
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     if (rowLower) {
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               double value = rowLower[iRow];
+               if (value < -1.0e20)
+                    value = -COIN_DBL_MAX;
+               rowLower_[iRow] = value;
+          }
+     } else {
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               rowLower_[iRow] = -COIN_DBL_MAX;
+          }
+     }
+}
+// chgRowUpper
+void
+ClpModel::chgRowUpper(const double * rowUpper)
+{
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     int numberRows = numberRows_;
+     int iRow;
+     if (rowUpper) {
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               double value = rowUpper[iRow];
+               if (value > 1.0e20)
+                    value = COIN_DBL_MAX;
+               rowUpper_[iRow] = value;
+          }
+     } else {
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               rowUpper_[iRow] = COIN_DBL_MAX;;
+          }
+     }
+}
+// chgColumnLower
+void
+ClpModel::chgColumnLower(const double * columnLower)
+{
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     int numberColumns = numberColumns_;
+     int iColumn;
+     if (columnLower) {
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               double value = columnLower[iColumn];
+               if (value < -1.0e20)
+                    value = -COIN_DBL_MAX;
+               columnLower_[iColumn] = value;
+          }
+     } else {
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               columnLower_[iColumn] = 0.0;
+          }
+     }
+}
+// chgColumnUpper
+void
+ClpModel::chgColumnUpper(const double * columnUpper)
+{
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     int numberColumns = numberColumns_;
+     int iColumn;
+     if (columnUpper) {
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               double value = columnUpper[iColumn];
+               if (value > 1.0e20)
+                    value = COIN_DBL_MAX;
+               columnUpper_[iColumn] = value;
+          }
+     } else {
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               columnUpper_[iColumn] = COIN_DBL_MAX;;
+          }
+     }
+}
+// chgObjCoefficients
+void
+ClpModel::chgObjCoefficients(const double * objIn)
+{
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     double * obj = objective();
+     int numberColumns = numberColumns_;
+     int iColumn;
+     if (objIn) {
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               obj[iColumn] = objIn[iColumn];
+          }
+     } else {
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               obj[iColumn] = 0.0;
+          }
+     }
+}
+// Infeasibility/unbounded ray (NULL returned if none/wrong)
+double *
+ClpModel::infeasibilityRay(bool fullRay) const
+{
+     double * array = NULL;
+     if (problemStatus_ == 1 && ray_) {
+       if (!fullRay) {
+	 array = ClpCopyOfArray(ray_, numberRows_);
+       } else {
+	 array = new double [numberRows_+numberColumns_];
+	 memcpy(array,ray_,numberRows_*sizeof(double));
+	 memset(array+numberRows_,0,numberColumns_*sizeof(double));
+	 transposeTimes(-1.0,array,array+numberRows_);
+       }
+     }
+     return array;
+}
+double *
+ClpModel::unboundedRay() const
+{
+     double * array = NULL;
+     if (problemStatus_ == 2)
+          array = ClpCopyOfArray(ray_, numberColumns_);
+     return array;
+}
+void
+ClpModel::setMaximumIterations(int value)
+{
+     if(value >= 0)
+          intParam_[ClpMaxNumIteration] = value;
+}
+void
+ClpModel::setMaximumSeconds(double value)
+{
+     if(value >= 0)
+          dblParam_[ClpMaxSeconds] = value + CoinCpuTime();
+     else
+          dblParam_[ClpMaxSeconds] = -1.0;
+}
+// Returns true if hit maximum iterations (or time)
+bool
+ClpModel::hitMaximumIterations() const
+{
+     // replaced - compiler error? bool hitMax= (numberIterations_>=maximumIterations());
+     bool hitMax = (numberIterations_ >= intParam_[ClpMaxNumIteration]);
+     if (dblParam_[ClpMaxSeconds] >= 0.0 && !hitMax) {
+          hitMax = (CoinCpuTime() >= dblParam_[ClpMaxSeconds]);
+     }
+     return hitMax;
+}
+// On stopped - sets secondary status
+void
+ClpModel::onStopped()
+{
+     if (problemStatus_ == 3) {
+          secondaryStatus_ = 0;
+          if (CoinCpuTime() >= dblParam_[ClpMaxSeconds] && dblParam_[ClpMaxSeconds] >= 0.0)
+               secondaryStatus_ = 9;
+     }
+}
+// Pass in Message handler (not deleted at end)
+void
+ClpModel::passInMessageHandler(CoinMessageHandler * handler)
+{
+     if (defaultHandler_)
+          delete handler_;
+     defaultHandler_ = false;
+     handler_ = handler;
+}
+// Pass in Message handler (not deleted at end) and return current
+CoinMessageHandler *
+ClpModel::pushMessageHandler(CoinMessageHandler * handler,
+                             bool & oldDefault)
+{
+     CoinMessageHandler * returnValue = handler_;
+     oldDefault = defaultHandler_;
+     defaultHandler_ = false;
+     handler_ = handler;
+     return returnValue;
+}
+// back to previous message handler
+void
+ClpModel::popMessageHandler(CoinMessageHandler * oldHandler, bool oldDefault)
+{
+     if (defaultHandler_)
+          delete handler_;
+     defaultHandler_ = oldDefault;
+     handler_ = oldHandler;
+}
+// Overrides message handler with a default one
+void 
+ClpModel::setDefaultMessageHandler()
+{
+     int logLevel = handler_->logLevel();
+     if (defaultHandler_)
+          delete handler_;
+     defaultHandler_ = true;
+     handler_ = new CoinMessageHandler();
+     handler_->setLogLevel(logLevel);
+}
+// Set language
+void
+ClpModel::newLanguage(CoinMessages::Language language)
+{
+     messages_ = ClpMessage(language);
+}
+#ifndef SLIM_NOIO
+// Read an mps file from the given filename
+int
+ClpModel::readMps(const char *fileName,
+                  bool keepNames,
+                  bool ignoreErrors)
+{
+     if (!strcmp(fileName, "-") || !strcmp(fileName, "stdin")) {
+          // stdin
+     } else {
+          std::string name = fileName;
+          bool readable = fileCoinReadable(name);
+          if (!readable) {
+               handler_->message(CLP_UNABLE_OPEN, messages_)
+                         << fileName << CoinMessageEol;
+               return -1;
+          }
+     }
+     CoinMpsIO m;
+     m.passInMessageHandler(handler_);
+     *m.messagesPointer() = coinMessages();
+     bool savePrefix = m.messageHandler()->prefix();
+     m.messageHandler()->setPrefix(handler_->prefix());
+     m.setSmallElementValue(CoinMax(smallElement_, m.getSmallElementValue()));
+     double time1 = CoinCpuTime(), time2;
+     int status = 0;
+     try {
+          status = m.readMps(fileName, "");
+     } catch (CoinError e) {
+          e.print();
+          status = -1;
+     }
+     m.messageHandler()->setPrefix(savePrefix);
+     if (!status || (ignoreErrors && (status > 0 && status < 100000))) {
+          loadProblem(*m.getMatrixByCol(),
+                      m.getColLower(), m.getColUpper(),
+                      m.getObjCoefficients(),
+                      m.getRowLower(), m.getRowUpper());
+          if (m.integerColumns()) {
+               integerType_ = new char[numberColumns_];
+               CoinMemcpyN(m.integerColumns(), numberColumns_, integerType_);
+          } else {
+               integerType_ = NULL;
+          }
+#ifndef SLIM_CLP
+          // get quadratic part
+          if (m.reader()->whichSection (  ) == COIN_QUAD_SECTION ) {
+               int * start = NULL;
+               int * column = NULL;
+               double * element = NULL;
+               status = m.readQuadraticMps(NULL, start, column, element, 2);
+               if (!status || ignoreErrors)
+                    loadQuadraticObjective(numberColumns_, start, column, element);
+               delete [] start;
+               delete [] column;
+               delete [] element;
+          }
+#endif
+#ifndef CLP_NO_STD
+          // set problem name
+          setStrParam(ClpProbName, m.getProblemName());
+          // do names
+          if (keepNames) {
+               unsigned int maxLength = 0;
+               int iRow;
+               rowNames_ = std::vector<std::string> ();
+               columnNames_ = std::vector<std::string> ();
+               rowNames_.reserve(numberRows_);
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    const char * name = m.rowName(iRow);
+                    maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(name)));
+                    rowNames_.push_back(name);
+               }
+
+               int iColumn;
+               columnNames_.reserve(numberColumns_);
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    const char * name = m.columnName(iColumn);
+                    maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(name)));
+                    columnNames_.push_back(name);
+               }
+               lengthNames_ = static_cast<int> (maxLength);
+          } else {
+               lengthNames_ = 0;
+          }
+#endif
+          setDblParam(ClpObjOffset, m.objectiveOffset());
+          time2 = CoinCpuTime();
+          handler_->message(CLP_IMPORT_RESULT, messages_)
+                    << fileName
+                    << time2 - time1 << CoinMessageEol;
+     } else {
+          // errors
+          handler_->message(CLP_IMPORT_ERRORS, messages_)
+                    << status << fileName << CoinMessageEol;
+     }
+
+     return status;
+}
+// Read GMPL files from the given filenames
+int
+ClpModel::readGMPL(const char *fileName, const char * dataName,
+                   bool keepNames)
+{
+     FILE *fp = fopen(fileName, "r");
+     if (fp) {
+          // can open - lets go for it
+          fclose(fp);
+          if (dataName) {
+               fp = fopen(dataName, "r");
+               if (fp) {
+                    fclose(fp);
+               } else {
+                    handler_->message(CLP_UNABLE_OPEN, messages_)
+                              << dataName << CoinMessageEol;
+                    return -1;
+               }
+          }
+     } else {
+          handler_->message(CLP_UNABLE_OPEN, messages_)
+                    << fileName << CoinMessageEol;
+          return -1;
+     }
+     CoinMpsIO m;
+     m.passInMessageHandler(handler_);
+     *m.messagesPointer() = coinMessages();
+     bool savePrefix = m.messageHandler()->prefix();
+     m.messageHandler()->setPrefix(handler_->prefix());
+     double time1 = CoinCpuTime(), time2;
+     int status = m.readGMPL(fileName, dataName, keepNames);
+     m.messageHandler()->setPrefix(savePrefix);
+     if (!status) {
+          loadProblem(*m.getMatrixByCol(),
+                      m.getColLower(), m.getColUpper(),
+                      m.getObjCoefficients(),
+                      m.getRowLower(), m.getRowUpper());
+          if (m.integerColumns()) {
+               integerType_ = new char[numberColumns_];
+               CoinMemcpyN(m.integerColumns(), numberColumns_, integerType_);
+          } else {
+               integerType_ = NULL;
+          }
+#ifndef CLP_NO_STD
+          // set problem name
+          setStrParam(ClpProbName, m.getProblemName());
+          // do names
+          if (keepNames) {
+               unsigned int maxLength = 0;
+               int iRow;
+               rowNames_ = std::vector<std::string> ();
+               columnNames_ = std::vector<std::string> ();
+               rowNames_.reserve(numberRows_);
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    const char * name = m.rowName(iRow);
+                    maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(name)));
+                    rowNames_.push_back(name);
+               }
+
+               int iColumn;
+               columnNames_.reserve(numberColumns_);
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    const char * name = m.columnName(iColumn);
+                    maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(name)));
+                    columnNames_.push_back(name);
+               }
+               lengthNames_ = static_cast<int> (maxLength);
+          } else {
+               lengthNames_ = 0;
+          }
+#endif
+          setDblParam(ClpObjOffset, m.objectiveOffset());
+          time2 = CoinCpuTime();
+          handler_->message(CLP_IMPORT_RESULT, messages_)
+                    << fileName
+                    << time2 - time1 << CoinMessageEol;
+     } else {
+          // errors
+          handler_->message(CLP_IMPORT_ERRORS, messages_)
+                    << status << fileName << CoinMessageEol;
+     }
+     return status;
+}
+#endif
+bool ClpModel::isPrimalObjectiveLimitReached() const
+{
+     double limit = 0.0;
+     getDblParam(ClpPrimalObjectiveLimit, limit);
+     if (limit > 1e30) {
+          // was not ever set
+          return false;
+     }
+
+     const double obj = objectiveValue();
+     const double maxmin = optimizationDirection();
+
+     if (problemStatus_ == 0) // optimal
+          return maxmin > 0 ? (obj < limit) /*minim*/ : (-obj < limit) /*maxim*/;
+     else if (problemStatus_ == 2)
+          return true;
+     else
+          return false;
+}
+
+bool ClpModel::isDualObjectiveLimitReached() const
+{
+
+     double limit = 0.0;
+     getDblParam(ClpDualObjectiveLimit, limit);
+     if (limit > 1e30) {
+          // was not ever set
+          return false;
+     }
+
+     const double obj = objectiveValue();
+     const double maxmin = optimizationDirection();
+
+     if (problemStatus_ == 0) // optimal
+          return maxmin > 0 ? (obj > limit) /*minim*/ : (-obj > limit) /*maxim*/;
+     else if (problemStatus_ == 1)
+          return true;
+     else
+          return false;
+
+}
+void
+ClpModel::copyInIntegerInformation(const char * information)
+{
+     delete [] integerType_;
+     if (information) {
+          integerType_ = new char[numberColumns_];
+          CoinMemcpyN(information, numberColumns_, integerType_);
+     } else {
+          integerType_ = NULL;
+     }
+}
+void
+ClpModel::setContinuous(int index)
+{
+
+     if (integerType_) {
+#ifndef NDEBUG
+          if (index < 0 || index >= numberColumns_) {
+               indexError(index, "setContinuous");
+          }
+#endif
+          integerType_[index] = 0;
+     }
+}
+//-----------------------------------------------------------------------------
+void
+ClpModel::setInteger(int index)
+{
+     if (!integerType_) {
+          integerType_ = new char[numberColumns_];
+          CoinZeroN ( integerType_, numberColumns_);
+     }
+#ifndef NDEBUG
+     if (index < 0 || index >= numberColumns_) {
+          indexError(index, "setInteger");
+     }
+#endif
+     integerType_[index] = 1;
+}
+/* Return true if the index-th variable is an integer variable */
+bool
+ClpModel::isInteger(int index) const
+{
+     if (!integerType_) {
+          return false;
+     } else {
+#ifndef NDEBUG
+          if (index < 0 || index >= numberColumns_) {
+               indexError(index, "isInteger");
+          }
+#endif
+          return (integerType_[index] != 0);
+     }
+}
+#ifndef CLP_NO_STD
+// Drops names - makes lengthnames 0 and names empty
+void
+ClpModel::dropNames()
+{
+     lengthNames_ = 0;
+     rowNames_ = std::vector<std::string> ();
+     columnNames_ = std::vector<std::string> ();
+}
+#endif
+// Drop integer informations
+void
+ClpModel::deleteIntegerInformation()
+{
+     delete [] integerType_;
+     integerType_ = NULL;
+}
+/* Return copy of status array (char[numberRows+numberColumns]),
+   use delete [] */
+unsigned char *
+ClpModel::statusCopy() const
+{
+     return ClpCopyOfArray(status_, numberRows_ + numberColumns_);
+}
+// Copy in status vector
+void
+ClpModel::copyinStatus(const unsigned char * statusArray)
+{
+     delete [] status_;
+     if (statusArray) {
+          status_ = new unsigned char [numberRows_+numberColumns_];
+          CoinMemcpyN(statusArray, (numberRows_ + numberColumns_), status_);
+     } else {
+          status_ = NULL;
+     }
+}
+#ifndef SLIM_CLP
+// Load up quadratic objective
+void
+ClpModel::loadQuadraticObjective(const int numberColumns, const CoinBigIndex * start,
+                                 const int * column, const double * element)
+{
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     CoinAssert (numberColumns == numberColumns_);
+     assert ((dynamic_cast< ClpLinearObjective*>(objective_)));
+     double offset;
+     ClpObjective * obj = new ClpQuadraticObjective(objective_->gradient(NULL, NULL, offset, false),
+               numberColumns,
+               start, column, element);
+     delete objective_;
+     objective_ = obj;
+
+}
+void
+ClpModel::loadQuadraticObjective (  const CoinPackedMatrix& matrix)
+{
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     CoinAssert (matrix.getNumCols() == numberColumns_);
+     assert ((dynamic_cast< ClpLinearObjective*>(objective_)));
+     double offset;
+     ClpQuadraticObjective * obj =
+          new ClpQuadraticObjective(objective_->gradient(NULL, NULL, offset, false),
+                                    numberColumns_,
+                                    NULL, NULL, NULL);
+     delete objective_;
+     objective_ = obj;
+     obj->loadQuadraticObjective(matrix);
+}
+// Get rid of quadratic objective
+void
+ClpModel::deleteQuadraticObjective()
+{
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     ClpQuadraticObjective * obj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+     if (obj)
+          obj->deleteQuadraticObjective();
+}
+#endif
+void
+ClpModel::setObjective(ClpObjective * objective)
+{
+     whatsChanged_ = 0; // Use ClpSimplex stuff to keep
+     delete objective_;
+     objective_ = objective->clone();
+}
+// Returns resized array and updates size
+double * whichDouble(double * array , int number, const int * which)
+{
+     double * newArray = NULL;
+     if (array && number) {
+          int i ;
+          newArray = new double[number];
+          for (i = 0; i < number; i++)
+               newArray[i] = array[which[i]];
+     }
+     return newArray;
+}
+char * whichChar(char * array , int number, const int * which)
+{
+     char * newArray = NULL;
+     if (array && number) {
+          int i ;
+          newArray = new char[number];
+          for (i = 0; i < number; i++)
+               newArray[i] = array[which[i]];
+     }
+     return newArray;
+}
+unsigned char * whichUnsignedChar(unsigned char * array ,
+                                  int number, const int * which)
+{
+     unsigned char * newArray = NULL;
+     if (array && number) {
+          int i ;
+          newArray = new unsigned char[number];
+          for (i = 0; i < number; i++)
+               newArray[i] = array[which[i]];
+     }
+     return newArray;
+}
+// Replace Clp Matrix (current is not deleted)
+void
+ClpModel::replaceMatrix( ClpMatrixBase * matrix, bool deleteCurrent)
+{
+     if (deleteCurrent)
+          delete matrix_;
+     matrix_ = matrix;
+     whatsChanged_ = 0; // Too big a change
+}
+// Subproblem constructor
+ClpModel::ClpModel ( const ClpModel * rhs,
+                     int numberRows, const int * whichRow,
+                     int numberColumns, const int * whichColumn,
+                     bool dropNames, bool dropIntegers)
+     :  specialOptions_(rhs->specialOptions_),
+        maximumColumns_(-1),
+        maximumRows_(-1),
+        maximumInternalColumns_(-1),
+        maximumInternalRows_(-1),
+        savedRowScale_(NULL),
+        savedColumnScale_(NULL)
+{
+     defaultHandler_ = rhs->defaultHandler_;
+     if (defaultHandler_)
+          handler_ = new CoinMessageHandler(*rhs->handler_);
+     else
+          handler_ = rhs->handler_;
+     eventHandler_ = rhs->eventHandler_->clone();
+     randomNumberGenerator_ = rhs->randomNumberGenerator_;
+     messages_ = rhs->messages_;
+     coinMessages_ = rhs->coinMessages_;
+     maximumColumns_ = -1;
+     maximumRows_ = -1;
+     maximumInternalColumns_ = -1;
+     maximumInternalRows_ = -1;
+     savedRowScale_ = NULL;
+     savedColumnScale_ = NULL;
+     intParam_[ClpMaxNumIteration] = rhs->intParam_[ClpMaxNumIteration];
+     intParam_[ClpMaxNumIterationHotStart] =
+          rhs->intParam_[ClpMaxNumIterationHotStart];
+     intParam_[ClpNameDiscipline] = rhs->intParam_[ClpNameDiscipline] ;
+
+     dblParam_[ClpDualObjectiveLimit] = rhs->dblParam_[ClpDualObjectiveLimit];
+     dblParam_[ClpPrimalObjectiveLimit] = rhs->dblParam_[ClpPrimalObjectiveLimit];
+     dblParam_[ClpDualTolerance] = rhs->dblParam_[ClpDualTolerance];
+     dblParam_[ClpPrimalTolerance] = rhs->dblParam_[ClpPrimalTolerance];
+     dblParam_[ClpObjOffset] = rhs->dblParam_[ClpObjOffset];
+     dblParam_[ClpMaxSeconds] = rhs->dblParam_[ClpMaxSeconds];
+     dblParam_[ClpPresolveTolerance] = rhs->dblParam_[ClpPresolveTolerance];
+#ifndef CLP_NO_STD
+     strParam_[ClpProbName] = rhs->strParam_[ClpProbName];
+#endif
+     specialOptions_ = rhs->specialOptions_;
+     optimizationDirection_ = rhs->optimizationDirection_;
+     objectiveValue_ = rhs->objectiveValue_;
+     smallElement_ = rhs->smallElement_;
+     objectiveScale_ = rhs->objectiveScale_;
+     rhsScale_ = rhs->rhsScale_;
+     numberIterations_ = rhs->numberIterations_;
+     solveType_ = rhs->solveType_;
+     whatsChanged_ = 0; // Too big a change
+     problemStatus_ = rhs->problemStatus_;
+     secondaryStatus_ = rhs->secondaryStatus_;
+     // check valid lists
+     int numberBad = 0;
+     int i;
+     for (i = 0; i < numberRows; i++)
+          if (whichRow[i] < 0 || whichRow[i] >= rhs->numberRows_)
+               numberBad++;
+     CoinAssertHint(!numberBad, "Bad row list for subproblem constructor");
+     numberBad = 0;
+     for (i = 0; i < numberColumns; i++)
+          if (whichColumn[i] < 0 || whichColumn[i] >= rhs->numberColumns_)
+               numberBad++;
+     CoinAssertHint(!numberBad, "Bad Column list for subproblem constructor");
+     numberRows_ = numberRows;
+     numberColumns_ = numberColumns;
+     userPointer_ = rhs->userPointer_;
+     trustedUserPointer_ = rhs->trustedUserPointer_;
+     numberThreads_ = 0;
+#ifndef CLP_NO_STD
+     if (!dropNames) {
+          unsigned int maxLength = 0;
+          int iRow;
+          rowNames_ = std::vector<std::string> ();
+          columnNames_ = std::vector<std::string> ();
+          rowNames_.reserve(numberRows_);
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               rowNames_.push_back(rhs->rowNames_[whichRow[iRow]]);
+               maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(rowNames_[iRow].c_str())));
+          }
+          int iColumn;
+          columnNames_.reserve(numberColumns_);
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               columnNames_.push_back(rhs->columnNames_[whichColumn[iColumn]]);
+               maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(columnNames_[iColumn].c_str())));
+          }
+          lengthNames_ = static_cast<int> (maxLength);
+     } else {
+          lengthNames_ = 0;
+          rowNames_ = std::vector<std::string> ();
+          columnNames_ = std::vector<std::string> ();
+     }
+#endif
+     if (rhs->integerType_ && !dropIntegers) {
+          integerType_ = whichChar(rhs->integerType_, numberColumns, whichColumn);
+     } else {
+          integerType_ = NULL;
+     }
+     if (rhs->rowActivity_) {
+          rowActivity_ = whichDouble(rhs->rowActivity_, numberRows, whichRow);
+          dual_ = whichDouble(rhs->dual_, numberRows, whichRow);
+          columnActivity_ = whichDouble(rhs->columnActivity_, numberColumns,
+                                        whichColumn);
+          reducedCost_ = whichDouble(rhs->reducedCost_, numberColumns,
+                                     whichColumn);
+     } else {
+          rowActivity_ = NULL;
+          columnActivity_ = NULL;
+          dual_ = NULL;
+          reducedCost_ = NULL;
+     }
+     rowLower_ = whichDouble(rhs->rowLower_, numberRows, whichRow);
+     rowUpper_ = whichDouble(rhs->rowUpper_, numberRows, whichRow);
+     columnLower_ = whichDouble(rhs->columnLower_, numberColumns, whichColumn);
+     columnUpper_ = whichDouble(rhs->columnUpper_, numberColumns, whichColumn);
+     if (rhs->objective_)
+          objective_  = rhs->objective_->subsetClone(numberColumns, whichColumn);
+     else
+          objective_ = NULL;
+     rowObjective_ = whichDouble(rhs->rowObjective_, numberRows, whichRow);
+     // status has to be done in two stages
+     if (rhs->status_) {
+       status_ = new unsigned char[numberColumns_+numberRows_];
+       unsigned char * rowStatus = whichUnsignedChar(rhs->status_ + rhs->numberColumns_,
+						     numberRows_, whichRow);
+       unsigned char * columnStatus = whichUnsignedChar(rhs->status_,
+							numberColumns_, whichColumn);
+       CoinMemcpyN(rowStatus, numberRows_, status_ + numberColumns_);
+       delete [] rowStatus;
+       CoinMemcpyN(columnStatus, numberColumns_, status_);
+       delete [] columnStatus;
+     } else {
+       status_=NULL;
+     }
+     ray_ = NULL;
+     if (problemStatus_ == 1)
+          ray_ = whichDouble (rhs->ray_, numberRows, whichRow);
+     else if (problemStatus_ == 2)
+          ray_ = whichDouble (rhs->ray_, numberColumns, whichColumn);
+     rowScale_ = NULL;
+     columnScale_ = NULL;
+     inverseRowScale_ = NULL;
+     inverseColumnScale_ = NULL;
+     scalingFlag_ = rhs->scalingFlag_;
+     rowCopy_ = NULL;
+     scaledMatrix_ = NULL;
+     matrix_ = NULL;
+     if (rhs->matrix_) {
+          matrix_ = rhs->matrix_->subsetClone(numberRows, whichRow,
+                                              numberColumns, whichColumn);
+     }
+     randomNumberGenerator_ = rhs->randomNumberGenerator_;
+}
+#ifndef CLP_NO_STD
+// Copies in names
+void
+ClpModel::copyNames(const std::vector<std::string> & rowNames,
+                    const std::vector<std::string> & columnNames)
+{
+     unsigned int maxLength = 0;
+     int iRow;
+     rowNames_ = std::vector<std::string> ();
+     columnNames_ = std::vector<std::string> ();
+     rowNames_.reserve(numberRows_);
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          rowNames_.push_back(rowNames[iRow]);
+          maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(rowNames_[iRow].c_str())));
+     }
+     int iColumn;
+     columnNames_.reserve(numberColumns_);
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          columnNames_.push_back(columnNames[iColumn]);
+          maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(columnNames_[iColumn].c_str())));
+     }
+     lengthNames_ = static_cast<int> (maxLength);
+}
+// Return name or Rnnnnnnn
+std::string
+ClpModel::getRowName(int iRow) const
+{
+#ifndef NDEBUG
+     if (iRow < 0 || iRow >= numberRows_) {
+          indexError(iRow, "getRowName");
+     }
+#endif
+     int size = static_cast<int>(rowNames_.size());
+     if (size > iRow) {
+          return rowNames_[iRow];
+     } else {
+          char name[9];
+          sprintf(name, "R%7.7d", iRow);
+          std::string rowName(name);
+          return rowName;
+     }
+}
+// Set row name
+void
+ClpModel::setRowName(int iRow, std::string &name)
+{
+#ifndef NDEBUG
+     if (iRow < 0 || iRow >= numberRows_) {
+          indexError(iRow, "setRowName");
+     }
+#endif
+     unsigned int maxLength = lengthNames_;
+     int size = static_cast<int>(rowNames_.size());
+     if (size <= iRow)
+          rowNames_.resize(iRow + 1);
+     rowNames_[iRow] = name;
+     maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(name.c_str())));
+     // May be too big - but we would have to check both rows and columns to be exact
+     lengthNames_ = static_cast<int> (maxLength);
+}
+// Return name or Cnnnnnnn
+std::string
+ClpModel::getColumnName(int iColumn) const
+{
+#ifndef NDEBUG
+     if (iColumn < 0 || iColumn >= numberColumns_) {
+          indexError(iColumn, "getColumnName");
+     }
+#endif
+     int size = static_cast<int>(columnNames_.size());
+     if (size > iColumn) {
+          return columnNames_[iColumn];
+     } else {
+          char name[9];
+          sprintf(name, "C%7.7d", iColumn);
+          std::string columnName(name);
+          return columnName;
+     }
+}
+// Set column name
+void
+ClpModel::setColumnName(int iColumn, std::string &name)
+{
+#ifndef NDEBUG
+     if (iColumn < 0 || iColumn >= numberColumns_) {
+          indexError(iColumn, "setColumnName");
+     }
+#endif
+     unsigned int maxLength = lengthNames_;
+     int size = static_cast<int>(columnNames_.size());
+     if (size <= iColumn)
+          columnNames_.resize(iColumn + 1);
+     columnNames_[iColumn] = name;
+     maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(name.c_str())));
+     // May be too big - but we would have to check both columns and columns to be exact
+     lengthNames_ = static_cast<int> (maxLength);
+}
+// Copies in Row names - modifies names first .. last-1
+void
+ClpModel::copyRowNames(const std::vector<std::string> & rowNames, int first, int last)
+{
+     // Do column names if necessary
+     if (!lengthNames_&&numberColumns_) {
+       lengthNames_=8;
+       copyColumnNames(NULL,0,numberColumns_);
+     }
+     unsigned int maxLength = lengthNames_;
+     int size = static_cast<int>(rowNames_.size());
+     if (size != numberRows_)
+          rowNames_.resize(numberRows_);
+     int iRow;
+     for (iRow = first; iRow < last; iRow++) {
+          rowNames_[iRow] = rowNames[iRow-first];
+          maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(rowNames_[iRow-first].c_str())));
+     }
+     // May be too big - but we would have to check both rows and columns to be exact
+     lengthNames_ = static_cast<int> (maxLength);
+}
+// Copies in Column names - modifies names first .. last-1
+void
+ClpModel::copyColumnNames(const std::vector<std::string> & columnNames, int first, int last)
+{
+     // Do row names if necessary
+     if (!lengthNames_&&numberRows_) {
+       lengthNames_=8;
+       copyRowNames(NULL,0,numberRows_);
+     }
+     unsigned int maxLength = lengthNames_;
+     int size = static_cast<int>(columnNames_.size());
+     if (size != numberColumns_)
+          columnNames_.resize(numberColumns_);
+     int iColumn;
+     for (iColumn = first; iColumn < last; iColumn++) {
+          columnNames_[iColumn] = columnNames[iColumn-first];
+          maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(columnNames_[iColumn-first].c_str())));
+     }
+     // May be too big - but we would have to check both rows and columns to be exact
+     lengthNames_ = static_cast<int> (maxLength);
+}
+// Copies in Row names - modifies names first .. last-1
+void
+ClpModel::copyRowNames(const char * const * rowNames, int first, int last)
+{
+     // Do column names if necessary
+     if (!lengthNames_&&numberColumns_) {
+       lengthNames_=8;
+       copyColumnNames(NULL,0,numberColumns_);
+     }
+     unsigned int maxLength = lengthNames_;
+     int size = static_cast<int>(rowNames_.size());
+     if (size != numberRows_)
+          rowNames_.resize(numberRows_);
+     int iRow;
+     for (iRow = first; iRow < last; iRow++) {
+          if (rowNames && rowNames[iRow-first] && strlen(rowNames[iRow-first])) {
+               rowNames_[iRow] = rowNames[iRow-first];
+               maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(rowNames[iRow-first])));
+          } else {
+               maxLength = CoinMax(maxLength, static_cast<unsigned int> (8));
+               char name[9];
+               sprintf(name, "R%7.7d", iRow);
+               rowNames_[iRow] = name;
+          }
+     }
+     // May be too big - but we would have to check both rows and columns to be exact
+     lengthNames_ = static_cast<int> (maxLength);
+}
+// Copies in Column names - modifies names first .. last-1
+void
+ClpModel::copyColumnNames(const char * const * columnNames, int first, int last)
+{
+     // Do row names if necessary
+     if (!lengthNames_&&numberRows_) {
+       lengthNames_=8;
+       copyRowNames(NULL,0,numberRows_);
+     }
+     unsigned int maxLength = lengthNames_;
+     int size = static_cast<int>(columnNames_.size());
+     if (size != numberColumns_)
+          columnNames_.resize(numberColumns_);
+     int iColumn;
+     for (iColumn = first; iColumn < last; iColumn++) {
+          if (columnNames && columnNames[iColumn-first] && strlen(columnNames[iColumn-first])) {
+               columnNames_[iColumn] = columnNames[iColumn-first];
+               maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(columnNames[iColumn-first])));
+          } else {
+               maxLength = CoinMax(maxLength, static_cast<unsigned int> (8));
+               char name[9];
+               sprintf(name, "C%7.7d", iColumn);
+               columnNames_[iColumn] = name;
+          }
+     }
+     // May be too big - but we would have to check both rows and columns to be exact
+     lengthNames_ = static_cast<int> (maxLength);
+}
+#endif
+// Primal objective limit
+void
+ClpModel::setPrimalObjectiveLimit(double value)
+{
+     dblParam_[ClpPrimalObjectiveLimit] = value;
+}
+// Dual objective limit
+void
+ClpModel::setDualObjectiveLimit(double value)
+{
+     dblParam_[ClpDualObjectiveLimit] = value;
+}
+// Objective offset
+void
+ClpModel::setObjectiveOffset(double value)
+{
+     dblParam_[ClpObjOffset] = value;
+}
+// Solve a problem with no elements - return status
+int ClpModel::emptyProblem(int * infeasNumber, double * infeasSum, bool printMessage)
+{
+     secondaryStatus_ = 6; // so user can see something odd
+     if (printMessage)
+          handler_->message(CLP_EMPTY_PROBLEM, messages_)
+                    << numberRows_
+                    << numberColumns_
+                    << 0
+                    << CoinMessageEol;
+     int returnCode = 0;
+     if (numberRows_ || numberColumns_) {
+          if (!status_) {
+               status_ = new unsigned char[numberRows_+numberColumns_];
+               CoinZeroN(status_, numberRows_ + numberColumns_);
+          }
+     }
+     // status is set directly (as can be used by Interior methods)
+     // check feasible
+     int numberPrimalInfeasibilities = 0;
+     double sumPrimalInfeasibilities = 0.0;
+     int numberDualInfeasibilities = 0;
+     double sumDualInfeasibilities = 0.0;
+     if (numberRows_) {
+          for (int i = 0; i < numberRows_; i++) {
+               dual_[i] = 0.0;
+               if (rowLower_[i] <= rowUpper_[i]) {
+                    if (rowLower_[i] > -1.0e30 || rowUpper_[i] < 1.0e30) {
+                         if (rowLower_[i] <= 0.0 && rowUpper_[i] >= 0.0) {
+                              if (fabs(rowLower_[i]) < fabs(rowUpper_[i]))
+                                   rowActivity_[i] = rowLower_[i];
+                              else
+                                   rowActivity_[i] = rowUpper_[i];
+                         } else {
+                              rowActivity_[i] = 0.0;
+                              numberPrimalInfeasibilities++;
+                              sumPrimalInfeasibilities += CoinMin(rowLower_[i], -rowUpper_[i]);
+                              returnCode = 1;
+                         }
+                    } else {
+                         rowActivity_[i] = 0.0;
+                    }
+               } else {
+                    rowActivity_[i] = 0.0;
+                    numberPrimalInfeasibilities++;
+                    sumPrimalInfeasibilities += rowLower_[i] - rowUpper_[i];
+                    returnCode = 1;
+               }
+               status_[i+numberColumns_] = 1;
+          }
+     }
+     objectiveValue_ = 0.0;
+     if (numberColumns_) {
+          const double * cost = objective();
+          for (int i = 0; i < numberColumns_; i++) {
+               reducedCost_[i] = cost[i];
+               double objValue = cost[i] * optimizationDirection_;
+               if (columnLower_[i] <= columnUpper_[i]) {
+                    if (columnLower_[i] > -1.0e30 || columnUpper_[i] < 1.0e30) {
+                         if (!objValue) {
+                              if (fabs(columnLower_[i]) < fabs(columnUpper_[i])) {
+                                   columnActivity_[i] = columnLower_[i];
+                                   status_[i] = 3;
+                              } else {
+                                   columnActivity_[i] = columnUpper_[i];
+                                   status_[i] = 2;
+                              }
+                         } else if (objValue > 0.0) {
+                              if (columnLower_[i] > -1.0e30) {
+                                   columnActivity_[i] = columnLower_[i];
+                                   status_[i] = 3;
+                              } else {
+                                   columnActivity_[i] = columnUpper_[i];
+                                   status_[i] = 2;
+                                   numberDualInfeasibilities++;;
+                                   sumDualInfeasibilities += fabs(objValue);
+                                   returnCode |= 2;
+                              }
+                              objectiveValue_ += columnActivity_[i] * objValue;
+                         } else {
+                              if (columnUpper_[i] < 1.0e30) {
+                                   columnActivity_[i] = columnUpper_[i];
+                                   status_[i] = 2;
+                              } else {
+                                   columnActivity_[i] = columnLower_[i];
+                                   status_[i] = 3;
+                                   numberDualInfeasibilities++;;
+                                   sumDualInfeasibilities += fabs(objValue);
+                                   returnCode |= 2;
+                              }
+                              objectiveValue_ += columnActivity_[i] * objValue;
+                         }
+                    } else {
+                         columnActivity_[i] = 0.0;
+                         if (objValue) {
+                              numberDualInfeasibilities++;;
+                              sumDualInfeasibilities += fabs(objValue);
+                              returnCode |= 2;
+                         }
+                         status_[i] = 0;
+                    }
+               } else {
+                    if (fabs(columnLower_[i]) < fabs(columnUpper_[i])) {
+                         columnActivity_[i] = columnLower_[i];
+                         status_[i] = 3;
+                    } else {
+                         columnActivity_[i] = columnUpper_[i];
+                         status_[i] = 2;
+                    }
+                    numberPrimalInfeasibilities++;
+                    sumPrimalInfeasibilities += columnLower_[i] - columnUpper_[i];
+                    returnCode |= 1;
+               }
+          }
+     }
+     objectiveValue_ /= (objectiveScale_ * rhsScale_);
+     if (infeasNumber) {
+          infeasNumber[0] = numberDualInfeasibilities;
+          infeasSum[0] = sumDualInfeasibilities;
+          infeasNumber[1] = numberPrimalInfeasibilities;
+          infeasSum[1] = sumPrimalInfeasibilities;
+     }
+     if (returnCode == 3)
+          returnCode = 4;
+     return returnCode;
+}
+#ifndef SLIM_NOIO
+/* Write the problem in MPS format to the specified file.
+
+Row and column names may be null.
+formatType is
+<ul>
+<li> 0 - normal
+<li> 1 - extra accuracy
+<li> 2 - IEEE hex (later)
+</ul>
+
+Returns non-zero on I/O error
+*/
+int
+ClpModel::writeMps(const char *filename,
+                   int formatType, int numberAcross,
+                   double objSense) const
+{
+     matrix_->setDimensions(numberRows_, numberColumns_);
+
+     // Get multiplier for objective function - default 1.0
+     double * objective = new double[numberColumns_];
+     CoinMemcpyN(getObjCoefficients(), numberColumns_, objective);
+     if (objSense * getObjSense() < 0.0) {
+          for (int i = 0; i < numberColumns_; ++i)
+               objective [i] = - objective[i];
+     }
+     // get names
+     const char * const * const rowNames = rowNamesAsChar();
+     const char * const * const columnNames = columnNamesAsChar();
+     CoinMpsIO writer;
+     writer.passInMessageHandler(handler_);
+     *writer.messagesPointer() = coinMessages();
+     writer.setMpsData(*(matrix_->getPackedMatrix()), COIN_DBL_MAX,
+                       getColLower(), getColUpper(),
+                       objective,
+                       reinterpret_cast<const char*> (NULL) /*integrality*/,
+                       getRowLower(), getRowUpper(),
+                       columnNames, rowNames);
+     // Pass in array saying if each variable integer
+     writer.copyInIntegerInformation(integerInformation());
+     writer.setObjectiveOffset(objectiveOffset());
+     delete [] objective;
+     CoinPackedMatrix * quadratic = NULL;
+#ifndef SLIM_CLP
+     // allow for quadratic objective
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+     if (quadraticObj)
+          quadratic = quadraticObj->quadraticObjective();
+#endif
+     int returnCode = writer.writeMps(filename, 0 /* do not gzip it*/, formatType, numberAcross,
+                                      quadratic);
+     if (rowNames) {
+          deleteNamesAsChar(rowNames, numberRows_ + 1);
+          deleteNamesAsChar(columnNames, numberColumns_);
+     }
+     return returnCode;
+}
+#ifndef CLP_NO_STD
+// Create row names as char **
+const char * const *
+ClpModel::rowNamesAsChar() const
+{
+     char ** rowNames = NULL;
+     if (lengthNames()) {
+          rowNames = new char * [numberRows_+1];
+          int numberNames = static_cast<int>(rowNames_.size());
+          numberNames = CoinMin(numberRows_, numberNames);
+          int iRow;
+          for (iRow = 0; iRow < numberNames; iRow++) {
+               if (rowName(iRow) != "") {
+                    rowNames[iRow] =
+                         CoinStrdup(rowName(iRow).c_str());
+               } else {
+                    char name[9];
+                    sprintf(name, "R%7.7d", iRow);
+                    rowNames[iRow] = CoinStrdup(name);
+               }
+#ifdef STRIPBLANKS
+               char * xx = rowNames[iRow];
+               int i;
+               int length = strlen(xx);
+               int n = 0;
+               for (i = 0; i < length; i++) {
+                    if (xx[i] != ' ')
+                         xx[n++] = xx[i];
+               }
+               xx[n] = '\0';
+#endif
+          }
+          char name[9];
+          for ( ; iRow < numberRows_; iRow++) {
+               sprintf(name, "R%7.7d", iRow);
+               rowNames[iRow] = CoinStrdup(name);
+          }
+          rowNames[numberRows_] = CoinStrdup("OBJROW");
+     }
+     return reinterpret_cast<const char * const *>(rowNames);
+}
+// Create column names as char **
+const char * const *
+ClpModel::columnNamesAsChar() const
+{
+     char ** columnNames = NULL;
+     if (lengthNames()) {
+          columnNames = new char * [numberColumns_];
+          int numberNames = static_cast<int>(columnNames_.size());
+          numberNames = CoinMin(numberColumns_, numberNames);
+          int iColumn;
+          for (iColumn = 0; iColumn < numberNames; iColumn++) {
+               if (columnName(iColumn) != "") {
+                    columnNames[iColumn] =
+                         CoinStrdup(columnName(iColumn).c_str());
+               } else {
+                    char name[9];
+                    sprintf(name, "C%7.7d", iColumn);
+                    columnNames[iColumn] = CoinStrdup(name);
+               }
+#ifdef STRIPBLANKS
+               char * xx = columnNames[iColumn];
+               int i;
+               int length = strlen(xx);
+               int n = 0;
+               for (i = 0; i < length; i++) {
+                    if (xx[i] != ' ')
+                         xx[n++] = xx[i];
+               }
+               xx[n] = '\0';
+#endif
+          }
+          char name[9];
+          for ( ; iColumn < numberColumns_; iColumn++) {
+               sprintf(name, "C%7.7d", iColumn);
+               columnNames[iColumn] = CoinStrdup(name);
+          }
+     }
+     return /*reinterpret_cast<const char * const *>*/(columnNames);
+}
+// Delete char * version of names
+void
+ClpModel::deleteNamesAsChar(const char * const * names, int number) const
+{
+     for (int i = 0; i < number; i++) {
+          free(const_cast<char *>(names[i]));
+     }
+     delete [] const_cast<char **>(names);
+}
+#endif
+#endif
+// Pass in Event handler (cloned and deleted at end)
+void
+ClpModel::passInEventHandler(const ClpEventHandler * eventHandler)
+{
+     delete eventHandler_;
+     eventHandler_ = eventHandler->clone();
+}
+// Sets or unsets scaling, 0 -off, 1 on, 2 dynamic(later)
+void
+ClpModel::scaling(int mode)
+{
+     // If mode changes then we treat as new matrix (need new row copy)
+     if (mode != scalingFlag_) {
+          whatsChanged_ &= ~(2 + 4 + 8);
+	  // Get rid of scaled matrix
+	  setClpScaledMatrix(NULL);
+     }
+     if (mode > 0 && mode < 6) {
+          scalingFlag_ = mode;
+     } else if (!mode) {
+          scalingFlag_ = 0;
+          setRowScale(NULL);
+          setColumnScale(NULL);
+     }
+}
+void
+ClpModel::times(double scalar,
+                const double * x, double * y) const
+{
+     if (!scaledMatrix_ || !rowScale_) {
+          if (rowScale_)
+               matrix_->times(scalar, x, y, rowScale_, columnScale_);
+          else
+               matrix_->times(scalar, x, y);
+     } else {
+          scaledMatrix_->times(scalar, x, y);
+     }
+}
+void
+ClpModel::transposeTimes(double scalar,
+                         const double * x, double * y) const
+{
+     if (!scaledMatrix_ || !rowScale_) {
+          if (rowScale_)
+               matrix_->transposeTimes(scalar, x, y, rowScale_, columnScale_, NULL);
+          else
+               matrix_->transposeTimes(scalar, x, y);
+     } else {
+          scaledMatrix_->transposeTimes(scalar, x, y);
+     }
+}
+// Does much of scaling
+void
+ClpModel::gutsOfScaling()
+{
+     int i;
+     if (rowObjective_) {
+          for (i = 0; i < numberRows_; i++)
+               rowObjective_[i] /= rowScale_[i];
+     }
+     for (i = 0; i < numberRows_; i++) {
+          double multiplier = rowScale_[i];
+          double inverseMultiplier = 1.0 / multiplier;
+          rowActivity_[i] *= multiplier;
+          dual_[i] *= inverseMultiplier;
+          if (rowLower_[i] > -1.0e30)
+               rowLower_[i] *= multiplier;
+          else
+               rowLower_[i] = -COIN_DBL_MAX;
+          if (rowUpper_[i] < 1.0e30)
+               rowUpper_[i] *= multiplier;
+          else
+               rowUpper_[i] = COIN_DBL_MAX;
+     }
+     for (i = 0; i < numberColumns_; i++) {
+          double multiplier = 1.0 * inverseColumnScale_[i];
+          columnActivity_[i] *= multiplier;
+          reducedCost_[i] *= columnScale_[i];
+          if (columnLower_[i] > -1.0e30)
+               columnLower_[i] *= multiplier;
+          else
+               columnLower_[i] = -COIN_DBL_MAX;
+          if (columnUpper_[i] < 1.0e30)
+               columnUpper_[i] *= multiplier;
+          else
+               columnUpper_[i] = COIN_DBL_MAX;
+
+     }
+     //now replace matrix
+     //and objective
+     matrix_->reallyScale(rowScale_, columnScale_);
+     objective_->reallyScale(columnScale_);
+}
+/* If we constructed a "really" scaled model then this reverses the operation.
+      Quantities may not be exactly as they were before due to rounding errors */
+void
+ClpModel::unscale()
+{
+     if (rowScale_) {
+          int i;
+          // reverse scaling
+          for (i = 0; i < numberRows_; i++)
+               rowScale_[i] = 1.0 * inverseRowScale_[i];
+          for (i = 0; i < numberColumns_; i++)
+               columnScale_[i] = 1.0 * inverseColumnScale_[i];
+          gutsOfScaling();
+     }
+
+     scalingFlag_ = 0;
+     setRowScale(NULL);
+     setColumnScale(NULL);
+}
+void
+ClpModel::setSpecialOptions(unsigned int value)
+{
+     specialOptions_ = value;
+}
+/* This creates a coinModel object
+ */
+CoinModel *
+ClpModel::createCoinModel() const
+{
+     CoinModel * coinModel = new CoinModel();
+     CoinPackedMatrix matrixByRow;
+     matrixByRow.setExtraGap(0.0);
+     matrixByRow.setExtraMajor(0.0);
+     matrixByRow.reverseOrderedCopyOf(*matrix());
+     coinModel->setObjectiveOffset(objectiveOffset());
+     coinModel->setProblemName(problemName().c_str());
+
+     // Build by row from scratch
+     const double * element = matrixByRow.getElements();
+     const int * column = matrixByRow.getIndices();
+     const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+     const int * rowLength = matrixByRow.getVectorLengths();
+     int i;
+     for (i = 0; i < numberRows_; i++) {
+          coinModel->addRow(rowLength[i], column + rowStart[i],
+                            element + rowStart[i], rowLower_[i], rowUpper_[i]);
+     }
+     // Now do column part
+     const double * objective = this->objective();
+     for (i = 0; i < numberColumns_; i++) {
+          coinModel->setColumnBounds(i, columnLower_[i], columnUpper_[i]);
+          coinModel->setColumnObjective(i, objective[i]);
+     }
+     for ( i = 0; i < numberColumns_; i++) {
+          if (isInteger(i))
+               coinModel->setColumnIsInteger(i, true);
+     }
+     // do names - clear out
+     coinModel->zapRowNames();
+     coinModel->zapColumnNames();
+     for (i = 0; i < numberRows_; i++) {
+          char temp[30];
+          strcpy(temp, rowName(i).c_str());
+          size_t length = strlen(temp);
+          for (size_t j = 0; j < length; j++) {
+               if (temp[j] == '-')
+                    temp[j] = '_';
+          }
+          coinModel->setRowName(i, temp);
+     }
+     for (i = 0; i < numberColumns_; i++) {
+          char temp[30];
+          strcpy(temp, columnName(i).c_str());
+          size_t length = strlen(temp);
+          for (size_t j = 0; j < length; j++) {
+               if (temp[j] == '-')
+                    temp[j] = '_';
+          }
+          coinModel->setColumnName(i, temp);
+     }
+     ClpQuadraticObjective * obj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+     if (obj) {
+          const CoinPackedMatrix * quadObj = obj->quadraticObjective();
+          // add in quadratic
+          const double * element = quadObj->getElements();
+          const int * row = quadObj->getIndices();
+          const CoinBigIndex * columnStart = quadObj->getVectorStarts();
+          const int * columnLength = quadObj->getVectorLengths();
+          for (i = 0; i < numberColumns_; i++) {
+               int nels = columnLength[i];
+               if (nels) {
+                    CoinBigIndex start = columnStart[i];
+                    double constant = coinModel->getColumnObjective(i);
+                    char temp[100000];
+                    char temp2[30];
+                    sprintf(temp, "%g", constant);
+                    for (CoinBigIndex k = start; k < start + nels; k++) {
+                         int kColumn = row[k];
+                         double value = element[k];
+#if 1
+                         // ampl gives twice with assumed 0.5
+                         if (kColumn < i)
+                              continue;
+                         else if (kColumn == i)
+                              value *= 0.5;
+#endif
+                         if (value == 1.0)
+                              sprintf(temp2, "+%s", coinModel->getColumnName(kColumn));
+                         else if (value == -1.0)
+                              sprintf(temp2, "-%s", coinModel->getColumnName(kColumn));
+                         else if (value > 0.0)
+                              sprintf(temp2, "+%g*%s", value, coinModel->getColumnName(kColumn));
+                         else
+                              sprintf(temp2, "%g*%s", value, coinModel->getColumnName(kColumn));
+                         strcat(temp, temp2);
+                         assert (strlen(temp) < 100000);
+                    }
+                    coinModel->setObjective(i, temp);
+                    if (logLevel() > 2)
+                         printf("el for objective column %s is %s\n", coinModel->getColumnName(i), temp);
+               }
+          }
+     }
+     return coinModel;
+}
+// Start or reset using maximumRows_ and Columns_
+void
+ClpModel::startPermanentArrays()
+{
+     COIN_DETAIL_PRINT(printf("startperm a %d rows, %d maximum rows\n",
+			      numberRows_, maximumRows_));
+     if ((specialOptions_ & 65536) != 0) {
+          if (numberRows_ > maximumRows_ || numberColumns_ > maximumColumns_) {
+               if (numberRows_ > maximumRows_) {
+                    if (maximumRows_ > 0)
+                         maximumRows_ = numberRows_ + 10 + numberRows_ / 100;
+                    else
+                         maximumRows_ = numberRows_;
+               }
+               if (numberColumns_ > maximumColumns_) {
+                    if (maximumColumns_ > 0)
+                         maximumColumns_ = numberColumns_ + 10 + numberColumns_ / 100;
+                    else
+                         maximumColumns_ = numberColumns_;
+               }
+               // need to make sure numberRows_ OK and size of matrices
+               resize(maximumRows_, maximumColumns_);
+               COIN_DETAIL_PRINT(printf("startperm b %d rows, %d maximum rows\n",
+					numberRows_, maximumRows_));
+          } else {
+               return;
+          }
+     } else {
+          specialOptions_ |= 65536;
+          maximumRows_ = numberRows_;
+          maximumColumns_ = numberColumns_;
+          baseMatrix_ = *matrix();
+          baseMatrix_.cleanMatrix();
+          baseRowCopy_.setExtraGap(0.0);
+          baseRowCopy_.setExtraMajor(0.0);
+          baseRowCopy_.reverseOrderedCopyOf(baseMatrix_);
+          COIN_DETAIL_PRINT(printf("startperm c %d rows, %d maximum rows\n",
+				   numberRows_, maximumRows_));
+     }
+}
+// Stop using maximumRows_ and Columns_
+void
+ClpModel::stopPermanentArrays()
+{
+     specialOptions_ &= ~65536;
+     maximumRows_ = -1;
+     maximumColumns_ = -1;
+     if (rowScale_ != savedRowScale_) {
+          delete [] savedRowScale_;
+          delete [] savedColumnScale_;
+     }
+     savedRowScale_ = NULL;
+     savedColumnScale_ = NULL;
+}
+// Set new row matrix
+void
+ClpModel::setNewRowCopy(ClpMatrixBase * newCopy)
+{
+     delete rowCopy_;
+     rowCopy_ = newCopy;
+}
+/* Find a network subset.
+   rotate array should be numberRows.  On output
+   -1 not in network
+   0 in network as is
+   1 in network with signs swapped
+  Returns number of network rows (positive if exact network, negative if needs extra row)
+  From Gulpinar, Gutin, Maros and Mitra
+*/
+int
+ClpModel::findNetwork(char * rotate, double fractionNeeded)
+{
+     int * mapping = new int [numberRows_];
+     // Get column copy
+     CoinPackedMatrix * columnCopy = matrix();
+     // Get a row copy in standard format
+     CoinPackedMatrix * copy = new CoinPackedMatrix();
+     copy->setExtraGap(0.0);
+     copy->setExtraMajor(0.0);
+     copy->reverseOrderedCopyOf(*columnCopy);
+     // make sure ordered and no gaps
+     copy->cleanMatrix();
+     // get matrix data pointers
+     const int * columnIn = copy->getIndices();
+     const CoinBigIndex * rowStartIn = copy->getVectorStarts();
+     const int * rowLength = copy->getVectorLengths();
+     const double * elementByRowIn = copy->getElements();
+     int iRow, iColumn;
+     int numberEligible = 0;
+     int numberIn = 0;
+     int numberElements = 0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          bool possible = true;
+          mapping[iRow] = -1;
+          rotate[iRow] = -1;
+          for (CoinBigIndex j = rowStartIn[iRow]; j < rowStartIn[iRow] + rowLength[iRow]; j++) {
+               //int iColumn = column[j];
+               double value = elementByRowIn[j];
+               if (fabs(value) != 1.0) {
+                    possible = false;
+                    break;
+               }
+          }
+          if (rowLength[iRow] && possible) {
+               mapping[iRow] = numberEligible;
+               numberEligible++;
+               numberElements += rowLength[iRow];
+          }
+     }
+     if (numberEligible < fractionNeeded * numberRows_) {
+          delete [] mapping;
+          delete copy;
+          return 0;
+     }
+     // create arrays
+     int * eligible = new int [numberRows_];
+     int * column = new int [numberElements];
+     CoinBigIndex * rowStart = new CoinBigIndex [numberEligible+1];
+     char * elementByRow = new char [numberElements];
+     numberEligible = 0;
+     numberElements = 0;
+     rowStart[0] = 0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          if (mapping[iRow] < 0)
+               continue;
+          assert (numberEligible == mapping[iRow]);
+          rotate[numberEligible] = 0;
+          for (CoinBigIndex j = rowStartIn[iRow]; j < rowStartIn[iRow] + rowLength[iRow]; j++) {
+               column[numberElements] = columnIn[j];
+               double value = elementByRowIn[j];
+               if (value == 1.0)
+                    elementByRow[numberElements++] = 1;
+               else
+                    elementByRow[numberElements++] = -1;
+          }
+          numberEligible++;
+          rowStart[numberEligible] = numberElements;
+     }
+     // get rid of copy to save space
+     delete copy;
+     const int * rowIn = columnCopy->getIndices();
+     const CoinBigIndex * columnStartIn = columnCopy->getVectorStarts();
+     const int * columnLengthIn = columnCopy->getVectorLengths();
+     const double * elementByColumnIn = columnCopy->getElements();
+     int * columnLength = new int [numberColumns_];
+     // May just be that is a network - worth checking
+     bool isNetworkAlready = true;
+     bool trueNetwork = true;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          double product = 1.0;
+          int n = 0;
+          for (CoinBigIndex j = columnStartIn[iColumn]; j < columnStartIn[iColumn] + columnLengthIn[iColumn]; j++) {
+               iRow = mapping[rowIn[j]];
+               if (iRow >= 0) {
+                    n++;
+                    product *= elementByColumnIn[j];
+               }
+          }
+          if (n >= 2) {
+               if (product != -1.0 || n > 2)
+                    isNetworkAlready = false;
+          } else if (n == 1) {
+               trueNetwork = false;
+          }
+          columnLength[iColumn] = n;
+     }
+     if (!isNetworkAlready) {
+          // For sorting
+          double * count = new double [numberRows_];
+          int * which = new int [numberRows_];
+          int numberLast = -1;
+          // Count for columns
+          char * columnCount = new char[numberColumns_];
+          memset(columnCount, 0, numberColumns_);
+          char * currentColumnCount = new char[numberColumns_];
+          // Now do main loop
+          while (numberIn > numberLast) {
+               numberLast = numberIn;
+               int numberLeft = 0;
+               for (iRow = 0; iRow < numberEligible; iRow++) {
+                    if (rotate[iRow] == 0 && rowStart[iRow+1] > rowStart[iRow]) {
+                         which[numberLeft] = iRow;
+                         int merit = 0;
+                         bool OK = true;
+                         bool reflectionOK = true;
+                         for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                              iColumn = column[j];
+                              int iCount = columnCount[iColumn];
+                              int absCount = CoinAbs(iCount);
+                              if (absCount < 2) {
+                                   merit = CoinMax(columnLength[iColumn] - absCount - 1, merit);
+                                   if (elementByRow[j] == iCount)
+                                        OK = false;
+                                   else if (elementByRow[j] == -iCount)
+                                        reflectionOK = false;
+                              } else {
+                                   merit = -2;
+                                   break;
+                              }
+                         }
+                         if (merit > -2 && (OK || reflectionOK) &&
+                                   (!OK || !reflectionOK || !numberIn)) {
+                              //if (!numberLast) merit=1;
+                              count[numberLeft++] = (rowStart[iRow+1] - rowStart[iRow] - 1) *
+                                                    (static_cast<double>(merit));
+                              if (OK)
+                                   rotate[iRow] = 0;
+                              else
+                                   rotate[iRow] = 1;
+                         } else {
+                              // no good
+                              rotate[iRow] = -1;
+                         }
+                    }
+               }
+               CoinSort_2(count, count + numberLeft, which);
+               // Get G
+               memset(currentColumnCount, 0, numberColumns_);
+               for (iRow = 0; iRow < numberLeft; iRow++) {
+                    int jRow = which[iRow];
+                    bool possible = true;
+                    for (int i = 0; i < numberIn; i++) {
+                         for (CoinBigIndex j = rowStart[jRow]; j < rowStart[jRow+1]; j++) {
+                              if (currentColumnCount[column[j]]) {
+                                   possible = false;
+                                   break;
+                              }
+                         }
+                    }
+                    if (possible) {
+                         rotate[jRow] = static_cast<char>(rotate[jRow] + 2);
+                         eligible[numberIn++] = jRow;
+                         char multiplier = static_cast<char>((rotate[jRow] == 2) ? 1 : -1);
+                         for (CoinBigIndex j = rowStart[jRow]; j < rowStart[jRow+1]; j++) {
+                              iColumn = column[j];
+                              currentColumnCount[iColumn]++;
+                              int iCount = columnCount[iColumn];
+                              int absCount = CoinAbs(iCount);
+                              if (!absCount) {
+                                   columnCount[iColumn] = static_cast<char>(elementByRow[j] * multiplier);
+                              } else {
+                                   columnCount[iColumn] = 2;
+                              }
+                         }
+                    }
+               }
+          }
+#ifndef NDEBUG
+          for (iRow = 0; iRow < numberIn; iRow++) {
+               int kRow = eligible[iRow];
+               assert (rotate[kRow] >= 2);
+          }
+#endif
+          trueNetwork = true;
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (CoinAbs(static_cast<int>(columnCount[iColumn])) == 1) {
+                    trueNetwork = false;
+                    break;
+               }
+          }
+          delete [] currentColumnCount;
+          delete [] columnCount;
+          delete [] which;
+          delete [] count;
+     } else {
+          numberIn = numberEligible;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int kRow = mapping[iRow];
+               if (kRow >= 0) {
+                    rotate[kRow] = 2;
+               }
+          }
+     }
+     if (!trueNetwork)
+          numberIn = - numberIn;
+     delete [] column;
+     delete [] rowStart;
+     delete [] elementByRow;
+     delete [] columnLength;
+     // redo rotate
+     char * rotate2 = CoinCopyOfArray(rotate, numberEligible);
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          int kRow = mapping[iRow];
+          if (kRow >= 0) {
+               int iState = rotate2[kRow];
+               if (iState > 1)
+                    iState -= 2;
+               else
+                    iState = -1;
+               rotate[iRow] = static_cast<char>(iState);
+          } else {
+               rotate[iRow] = -1;
+          }
+     }
+     delete [] rotate2;
+     delete [] eligible;
+     delete [] mapping;
+     return numberIn;
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpDataSave::ClpDataSave ()
+{
+     dualBound_ = 0.0;
+     infeasibilityCost_ = 0.0;
+     sparseThreshold_ = 0;
+     pivotTolerance_ = 0.0;
+     zeroFactorizationTolerance_ = 1.0e13;
+     zeroSimplexTolerance_ = 1.0e-13;
+     acceptablePivot_ = 0.0;
+     objectiveScale_ = 1.0;
+     perturbation_ = 0;
+     forceFactorization_ = -1;
+     scalingFlag_ = 0;
+     specialOptions_ = 0;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpDataSave::ClpDataSave (const ClpDataSave & rhs)
+{
+     dualBound_ = rhs.dualBound_;
+     infeasibilityCost_ = rhs.infeasibilityCost_;
+     pivotTolerance_ = rhs.pivotTolerance_;
+     zeroFactorizationTolerance_ = rhs.zeroFactorizationTolerance_;
+     zeroSimplexTolerance_ = rhs.zeroSimplexTolerance_;
+     acceptablePivot_ = rhs.acceptablePivot_;
+     objectiveScale_ = rhs.objectiveScale_;
+     sparseThreshold_ = rhs.sparseThreshold_;
+     perturbation_ = rhs.perturbation_;
+     forceFactorization_ = rhs.forceFactorization_;
+     scalingFlag_ = rhs.scalingFlag_;
+     specialOptions_ = rhs.specialOptions_;
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpDataSave::~ClpDataSave ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpDataSave &
+ClpDataSave::operator=(const ClpDataSave& rhs)
+{
+     if (this != &rhs) {
+          dualBound_ = rhs.dualBound_;
+          infeasibilityCost_ = rhs.infeasibilityCost_;
+          pivotTolerance_ = rhs.pivotTolerance_;
+          zeroFactorizationTolerance_ = zeroFactorizationTolerance_;
+          zeroSimplexTolerance_ = zeroSimplexTolerance_;
+          acceptablePivot_ = rhs.acceptablePivot_;
+          objectiveScale_ = rhs.objectiveScale_;
+          sparseThreshold_ = rhs.sparseThreshold_;
+          perturbation_ = rhs.perturbation_;
+          forceFactorization_ = rhs.forceFactorization_;
+          scalingFlag_ = rhs.scalingFlag_;
+          specialOptions_ = rhs.specialOptions_;
+     }
+     return *this;
+}
+// Create C++ lines to get to current state
+void
+ClpModel::generateCpp( FILE * fp)
+{
+     // Stuff that can't be done easily
+     if (!lengthNames_) {
+          // no names
+          fprintf(fp, "  clpModel->dropNames();\n");
+     }
+     ClpModel defaultModel;
+     ClpModel * other = &defaultModel;
+     int iValue1, iValue2;
+     double dValue1, dValue2;
+     iValue1 = this->maximumIterations();
+     iValue2 = other->maximumIterations();
+     fprintf(fp, "%d  int save_maximumIterations = clpModel->maximumIterations();\n", iValue1 == iValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setMaximumIterations(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+     fprintf(fp, "%d  clpModel->setMaximumIterations(save_maximumIterations);\n", iValue1 == iValue2 ? 7 : 6);
+     dValue1 = this->primalTolerance();
+     dValue2 = other->primalTolerance();
+     fprintf(fp, "%d  double save_primalTolerance = clpModel->primalTolerance();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setPrimalTolerance(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setPrimalTolerance(save_primalTolerance);\n", dValue1 == dValue2 ? 7 : 6);
+     dValue1 = this->dualTolerance();
+     dValue2 = other->dualTolerance();
+     fprintf(fp, "%d  double save_dualTolerance = clpModel->dualTolerance();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setDualTolerance(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setDualTolerance(save_dualTolerance);\n", dValue1 == dValue2 ? 7 : 6);
+     iValue1 = this->numberIterations();
+     iValue2 = other->numberIterations();
+     fprintf(fp, "%d  int save_numberIterations = clpModel->numberIterations();\n", iValue1 == iValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setNumberIterations(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+     fprintf(fp, "%d  clpModel->setNumberIterations(save_numberIterations);\n", iValue1 == iValue2 ? 7 : 6);
+     dValue1 = this->maximumSeconds();
+     dValue2 = other->maximumSeconds();
+     fprintf(fp, "%d  double save_maximumSeconds = clpModel->maximumSeconds();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setMaximumSeconds(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setMaximumSeconds(save_maximumSeconds);\n", dValue1 == dValue2 ? 7 : 6);
+     dValue1 = this->optimizationDirection();
+     dValue2 = other->optimizationDirection();
+     fprintf(fp, "%d  double save_optimizationDirection = clpModel->optimizationDirection();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setOptimizationDirection(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setOptimizationDirection(save_optimizationDirection);\n", dValue1 == dValue2 ? 7 : 6);
+     dValue1 = this->objectiveScale();
+     dValue2 = other->objectiveScale();
+     fprintf(fp, "%d  double save_objectiveScale = clpModel->objectiveScale();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setObjectiveScale(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setObjectiveScale(save_objectiveScale);\n", dValue1 == dValue2 ? 7 : 6);
+     dValue1 = this->rhsScale();
+     dValue2 = other->rhsScale();
+     fprintf(fp, "%d  double save_rhsScale = clpModel->rhsScale();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setRhsScale(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setRhsScale(save_rhsScale);\n", dValue1 == dValue2 ? 7 : 6);
+     iValue1 = this->scalingFlag();
+     iValue2 = other->scalingFlag();
+     fprintf(fp, "%d  int save_scalingFlag = clpModel->scalingFlag();\n", iValue1 == iValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->scaling(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+     fprintf(fp, "%d  clpModel->scaling(save_scalingFlag);\n", iValue1 == iValue2 ? 7 : 6);
+     dValue1 = this->getSmallElementValue();
+     dValue2 = other->getSmallElementValue();
+     fprintf(fp, "%d  double save_getSmallElementValue = clpModel->getSmallElementValue();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setSmallElementValue(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setSmallElementValue(save_getSmallElementValue);\n", dValue1 == dValue2 ? 7 : 6);
+     iValue1 = this->logLevel();
+     iValue2 = other->logLevel();
+     fprintf(fp, "%d  int save_logLevel = clpModel->logLevel();\n", iValue1 == iValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setLogLevel(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+     fprintf(fp, "%d  clpModel->setLogLevel(save_logLevel);\n", iValue1 == iValue2 ? 7 : 6);
+}
diff --git a/cbits/coin/ClpModel.hpp b/cbits/coin/ClpModel.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpModel.hpp
@@ -0,0 +1,1303 @@
+/* $Id: ClpModel.hpp 1941 2013-04-10 16:52:27Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpModel_H
+#define ClpModel_H
+
+#include "ClpConfig.h"
+
+#include <iostream>
+#include <cassert>
+#include <cmath>
+#include <vector>
+#include <string>
+//#ifndef COIN_USE_CLP
+//#define COIN_USE_CLP
+//#endif
+#include "ClpPackedMatrix.hpp"
+#include "CoinMessageHandler.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinTypes.hpp"
+#include "CoinFinite.hpp"
+#include "ClpParameters.hpp"
+#include "ClpObjective.hpp"
+class ClpEventHandler;
+/** This is the base class for Linear and quadratic Models
+    This knows nothing about the algorithm, but it seems to
+    have a reasonable amount of information
+
+    I would welcome suggestions for what should be in this and
+    how it relates to OsiSolverInterface.  Some methods look
+    very similar.
+
+*/
+class CoinBuild;
+class CoinModel;
+class ClpModel {
+
+public:
+
+     /**@name Constructors and destructor
+        Note - copy methods copy ALL data so can chew up memory
+        until other copy is freed
+      */
+     //@{
+     /// Default constructor
+     ClpModel (bool emptyMessages = false  );
+
+     /** Copy constructor. May scale depending on mode
+         -1 leave mode as is
+         0 -off, 1 equilibrium, 2 geometric, 3, auto, 4 auto-but-as-initialSolve-in-bab
+     */
+     ClpModel(const ClpModel & rhs, int scalingMode = -1);
+     /// Assignment operator. This copies the data
+     ClpModel & operator=(const ClpModel & rhs);
+     /** Subproblem constructor.  A subset of whole model is created from the
+         row and column lists given.  The new order is given by list order and
+         duplicates are allowed.  Name and integer information can be dropped
+     */
+     ClpModel (const ClpModel * wholeModel,
+               int numberRows, const int * whichRows,
+               int numberColumns, const int * whichColumns,
+               bool dropNames = true, bool dropIntegers = true);
+     /// Destructor
+     ~ClpModel (  );
+     //@}
+
+     /**@name Load model - loads some stuff and initializes others */
+     //@{
+     /** Loads a problem (the constraints on the
+         rows are given by lower and upper bounds). If a pointer is 0 then the
+         following values are the default:
+         <ul>
+           <li> <code>colub</code>: all columns have upper bound infinity
+           <li> <code>collb</code>: all columns have lower bound 0
+           <li> <code>rowub</code>: all rows have upper bound infinity
+           <li> <code>rowlb</code>: all rows have lower bound -infinity
+       <li> <code>obj</code>: all variables have 0 objective coefficient
+         </ul>
+     */
+     void loadProblem (  const ClpMatrixBase& matrix,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     void loadProblem (  const CoinPackedMatrix& matrix,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+
+     /** Just like the other loadProblem() method except that the matrix is
+       given in a standard column major ordered format (without gaps). */
+     void loadProblem (  const int numcols, const int numrows,
+                         const CoinBigIndex* start, const int* index,
+                         const double* value,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     /** This loads a model from a coinModel object - returns number of errors.
+
+         modelObject not const as may be changed as part of process
+         If tryPlusMinusOne then will try adding as +-1 matrix
+     */
+     int loadProblem (  CoinModel & modelObject, bool tryPlusMinusOne = false);
+     /// This one is for after presolve to save memory
+     void loadProblem (  const int numcols, const int numrows,
+                         const CoinBigIndex* start, const int* index,
+                         const double* value, const int * length,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     /** Load up quadratic objective.  This is stored as a CoinPackedMatrix */
+     void loadQuadraticObjective(const int numberColumns,
+                                 const CoinBigIndex * start,
+                                 const int * column, const double * element);
+     void loadQuadraticObjective (  const CoinPackedMatrix& matrix);
+     /// Get rid of quadratic objective
+     void deleteQuadraticObjective();
+     /// This just loads up a row objective
+     void setRowObjective(const double * rowObjective);
+     /// Read an mps file from the given filename
+     int readMps(const char *filename,
+                 bool keepNames = false,
+                 bool ignoreErrors = false);
+     /// Read GMPL files from the given filenames
+     int readGMPL(const char *filename, const char * dataName,
+                  bool keepNames = false);
+     /// Copy in integer informations
+     void copyInIntegerInformation(const char * information);
+     /// Drop integer informations
+     void deleteIntegerInformation();
+     /** Set the index-th variable to be a continuous variable */
+     void setContinuous(int index);
+     /** Set the index-th variable to be an integer variable */
+     void setInteger(int index);
+     /** Return true if the index-th variable is an integer variable */
+     bool isInteger(int index) const;
+     /// Resizes rim part of model
+     void resize (int newNumberRows, int newNumberColumns);
+     /// Deletes rows
+     void deleteRows(int number, const int * which);
+     /// Add one row
+     void addRow(int numberInRow, const int * columns,
+                 const double * elements, double rowLower = -COIN_DBL_MAX,
+                 double rowUpper = COIN_DBL_MAX);
+     /// Add rows
+     void addRows(int number, const double * rowLower,
+                  const double * rowUpper,
+                  const CoinBigIndex * rowStarts, const int * columns,
+                  const double * elements);
+     /// Add rows
+     void addRows(int number, const double * rowLower,
+                  const double * rowUpper,
+                  const CoinBigIndex * rowStarts, const int * rowLengths,
+                  const int * columns,
+                  const double * elements);
+#ifndef CLP_NO_VECTOR
+     void addRows(int number, const double * rowLower,
+                  const double * rowUpper,
+                  const CoinPackedVectorBase * const * rows);
+#endif
+     /** Add rows from a build object.
+         If tryPlusMinusOne then will try adding as +-1 matrix
+         if no matrix exists.
+         Returns number of errors e.g. duplicates
+     */
+     int addRows(const CoinBuild & buildObject, bool tryPlusMinusOne = false,
+                 bool checkDuplicates = true);
+     /** Add rows from a model object.  returns
+         -1 if object in bad state (i.e. has column information)
+         otherwise number of errors.
+
+         modelObject non const as can be regularized as part of build
+         If tryPlusMinusOne then will try adding as +-1 matrix
+         if no matrix exists.
+     */
+     int addRows(CoinModel & modelObject, bool tryPlusMinusOne = false,
+                 bool checkDuplicates = true);
+
+     /// Deletes columns
+     void deleteColumns(int number, const int * which);
+     /// Deletes rows AND columns (keeps old sizes)
+     void deleteRowsAndColumns(int numberRows, const int * whichRows,
+			       int numberColumns, const int * whichColumns);
+     /// Add one column
+     void addColumn(int numberInColumn,
+                    const int * rows,
+                    const double * elements,
+                    double columnLower = 0.0,
+                    double  columnUpper = COIN_DBL_MAX,
+                    double  objective = 0.0);
+     /// Add columns
+     void addColumns(int number, const double * columnLower,
+                     const double * columnUpper,
+                     const double * objective,
+                     const CoinBigIndex * columnStarts, const int * rows,
+                     const double * elements);
+     void addColumns(int number, const double * columnLower,
+                     const double * columnUpper,
+                     const double * objective,
+                     const CoinBigIndex * columnStarts, const int * columnLengths,
+                     const int * rows,
+                     const double * elements);
+#ifndef CLP_NO_VECTOR
+     void addColumns(int number, const double * columnLower,
+                     const double * columnUpper,
+                     const double * objective,
+                     const CoinPackedVectorBase * const * columns);
+#endif
+     /** Add columns from a build object
+         If tryPlusMinusOne then will try adding as +-1 matrix
+         if no matrix exists.
+         Returns number of errors e.g. duplicates
+     */
+     int addColumns(const CoinBuild & buildObject, bool tryPlusMinusOne = false,
+                    bool checkDuplicates = true);
+     /** Add columns from a model object.  returns
+         -1 if object in bad state (i.e. has row information)
+         otherwise number of errors
+         modelObject non const as can be regularized as part of build
+         If tryPlusMinusOne then will try adding as +-1 matrix
+         if no matrix exists.
+     */
+     int addColumns(CoinModel & modelObject, bool tryPlusMinusOne = false,
+                    bool checkDuplicates = true);
+     /// Modify one element of a matrix
+     inline void modifyCoefficient(int row, int column, double newElement,
+                                   bool keepZero = false) {
+          matrix_->modifyCoefficient(row, column, newElement, keepZero);
+     }
+     /** Change row lower bounds */
+     void chgRowLower(const double * rowLower);
+     /** Change row upper bounds */
+     void chgRowUpper(const double * rowUpper);
+     /** Change column lower bounds */
+     void chgColumnLower(const double * columnLower);
+     /** Change column upper bounds */
+     void chgColumnUpper(const double * columnUpper);
+     /** Change objective coefficients */
+     void chgObjCoefficients(const double * objIn);
+     /** Borrow model.  This is so we don't have to copy large amounts
+         of data around.  It assumes a derived class wants to overwrite
+         an empty model with a real one - while it does an algorithm */
+     void borrowModel(ClpModel & otherModel);
+     /** Return model - nulls all arrays so can be deleted safely
+         also updates any scalars */
+     void returnModel(ClpModel & otherModel);
+
+     /// Create empty ClpPackedMatrix
+     void createEmptyMatrix();
+     /** Really clean up matrix (if ClpPackedMatrix).
+         a) eliminate all duplicate AND small elements in matrix
+         b) remove all gaps and set extraGap_ and extraMajor_ to 0.0
+         c) reallocate arrays and make max lengths equal to lengths
+         d) orders elements
+         returns number of elements eliminated or -1 if not ClpPackedMatrix
+     */
+     int cleanMatrix(double threshold = 1.0e-20);
+     /// Copy contents - resizing if necessary - otherwise re-use memory
+     void copy(const ClpMatrixBase * from, ClpMatrixBase * & to);
+#ifndef CLP_NO_STD
+     /// Drops names - makes lengthnames 0 and names empty
+     void dropNames();
+     /// Copies in names
+     void copyNames(const std::vector<std::string> & rowNames,
+                    const std::vector<std::string> & columnNames);
+     /// Copies in Row names - modifies names first .. last-1
+     void copyRowNames(const std::vector<std::string> & rowNames, int first, int last);
+     /// Copies in Column names - modifies names first .. last-1
+     void copyColumnNames(const std::vector<std::string> & columnNames, int first, int last);
+     /// Copies in Row names - modifies names first .. last-1
+     void copyRowNames(const char * const * rowNames, int first, int last);
+     /// Copies in Column names - modifies names first .. last-1
+     void copyColumnNames(const char * const * columnNames, int first, int last);
+     /// Set name of row
+     void setRowName(int rowIndex, std::string & name) ;
+     /// Set name of col
+     void setColumnName(int colIndex, std::string & name) ;
+#endif
+     /** Find a network subset.
+         rotate array should be numberRows.  On output
+         -1 not in network
+          0 in network as is
+          1 in network with signs swapped
+         Returns number of network rows
+     */
+     int findNetwork(char * rotate, double fractionNeeded = 0.75);
+     /** This creates a coinModel object
+     */
+     CoinModel * createCoinModel() const;
+
+     /** Write the problem in MPS format to the specified file.
+
+     Row and column names may be null.
+     formatType is
+     <ul>
+       <li> 0 - normal
+       <li> 1 - extra accuracy
+       <li> 2 - IEEE hex
+     </ul>
+
+     Returns non-zero on I/O error
+     */
+     int writeMps(const char *filename,
+                  int formatType = 0, int numberAcross = 2,
+                  double objSense = 0.0) const ;
+     //@}
+     /**@name gets and sets */
+     //@{
+     /// Number of rows
+     inline int numberRows() const {
+          return numberRows_;
+     }
+     inline int getNumRows() const {
+          return numberRows_;
+     }
+     /// Number of columns
+     inline int getNumCols() const {
+          return numberColumns_;
+     }
+     inline int numberColumns() const {
+          return numberColumns_;
+     }
+     /// Primal tolerance to use
+     inline double primalTolerance() const {
+          return dblParam_[ClpPrimalTolerance];
+     }
+     void setPrimalTolerance( double value) ;
+     /// Dual tolerance to use
+     inline double dualTolerance() const  {
+          return dblParam_[ClpDualTolerance];
+     }
+     void setDualTolerance( double value) ;
+     /// Primal objective limit
+     inline double primalObjectiveLimit() const {
+          return dblParam_[ClpPrimalObjectiveLimit];
+     }
+     void setPrimalObjectiveLimit(double value);
+     /// Dual objective limit
+     inline double dualObjectiveLimit() const {
+          return dblParam_[ClpDualObjectiveLimit];
+     }
+     void setDualObjectiveLimit(double value);
+     /// Objective offset
+     inline double objectiveOffset() const {
+          return dblParam_[ClpObjOffset];
+     }
+     void setObjectiveOffset(double value);
+     /// Presolve tolerance to use
+     inline double presolveTolerance() const {
+          return dblParam_[ClpPresolveTolerance];
+     }
+#ifndef CLP_NO_STD
+     inline const std::string & problemName() const {
+          return strParam_[ClpProbName];
+     }
+#endif
+     /// Number of iterations
+     inline int numberIterations() const  {
+          return numberIterations_;
+     }
+     inline int getIterationCount() const {
+          return numberIterations_;
+     }
+     inline void setNumberIterations(int numberIterationsNew) {
+          numberIterations_ = numberIterationsNew;
+     }
+     /** Solve type - 1 simplex, 2 simplex interface, 3 Interior.*/
+     inline int solveType() const {
+          return solveType_;
+     }
+     inline void setSolveType(int type) {
+          solveType_ = type;
+     }
+     /// Maximum number of iterations
+     inline int maximumIterations() const {
+          return intParam_[ClpMaxNumIteration];
+     }
+     void setMaximumIterations(int value);
+     /// Maximum time in seconds (from when set called)
+     inline double maximumSeconds() const {
+          return dblParam_[ClpMaxSeconds];
+     }
+     void setMaximumSeconds(double value);
+     /// Returns true if hit maximum iterations (or time)
+     bool hitMaximumIterations() const;
+     /** Status of problem:
+         -1 - unknown e.g. before solve or if postSolve says not optimal
+         0 - optimal
+         1 - primal infeasible
+         2 - dual infeasible
+         3 - stopped on iterations or time
+         4 - stopped due to errors
+         5 - stopped by event handler (virtual int ClpEventHandler::event())
+     */
+     inline int status() const            {
+          return problemStatus_;
+     }
+     inline int problemStatus() const            {
+          return problemStatus_;
+     }
+     /// Set problem status
+     inline void setProblemStatus(int problemStatusNew) {
+          problemStatus_ = problemStatusNew;
+     }
+     /** Secondary status of problem - may get extended
+         0 - none
+         1 - primal infeasible because dual limit reached OR (probably primal
+         infeasible but can't prove it  - main status was 4)
+         2 - scaled problem optimal - unscaled problem has primal infeasibilities
+         3 - scaled problem optimal - unscaled problem has dual infeasibilities
+         4 - scaled problem optimal - unscaled problem has primal and dual infeasibilities
+         5 - giving up in primal with flagged variables
+         6 - failed due to empty problem check
+         7 - postSolve says not optimal
+         8 - failed due to bad element check
+         9 - status was 3 and stopped on time
+         100 up - translation of enum from ClpEventHandler
+     */
+     inline int secondaryStatus() const            {
+          return secondaryStatus_;
+     }
+     inline void setSecondaryStatus(int newstatus) {
+          secondaryStatus_ = newstatus;
+     }
+     /// Are there a numerical difficulties?
+     inline bool isAbandoned() const             {
+          return problemStatus_ == 4;
+     }
+     /// Is optimality proven?
+     inline bool isProvenOptimal() const         {
+          return problemStatus_ == 0;
+     }
+     /// Is primal infeasiblity proven?
+     inline bool isProvenPrimalInfeasible() const {
+          return problemStatus_ == 1;
+     }
+     /// Is dual infeasiblity proven?
+     inline bool isProvenDualInfeasible() const  {
+          return problemStatus_ == 2;
+     }
+     /// Is the given primal objective limit reached?
+     bool isPrimalObjectiveLimitReached() const ;
+     /// Is the given dual objective limit reached?
+     bool isDualObjectiveLimitReached() const ;
+     /// Iteration limit reached?
+     inline bool isIterationLimitReached() const {
+          return problemStatus_ == 3;
+     }
+     /// Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+     inline double optimizationDirection() const {
+          return  optimizationDirection_;
+     }
+     inline double getObjSense() const    {
+          return optimizationDirection_;
+     }
+     void setOptimizationDirection(double value);
+     /// Primal row solution
+     inline double * primalRowSolution() const    {
+          return rowActivity_;
+     }
+     inline const double * getRowActivity() const {
+          return rowActivity_;
+     }
+     /// Primal column solution
+     inline double * primalColumnSolution() const {
+          return columnActivity_;
+     }
+     inline const double * getColSolution() const {
+          return columnActivity_;
+     }
+     inline void setColSolution(const double * input) {
+          memcpy(columnActivity_, input, numberColumns_ * sizeof(double));
+     }
+     /// Dual row solution
+     inline double * dualRowSolution() const      {
+          return dual_;
+     }
+     inline const double * getRowPrice() const    {
+          return dual_;
+     }
+     /// Reduced costs
+     inline double * dualColumnSolution() const   {
+          return reducedCost_;
+     }
+     inline const double * getReducedCost() const {
+          return reducedCost_;
+     }
+     /// Row lower
+     inline double* rowLower() const              {
+          return rowLower_;
+     }
+     inline const double* getRowLower() const     {
+          return rowLower_;
+     }
+     /// Row upper
+     inline double* rowUpper() const              {
+          return rowUpper_;
+     }
+     inline const double* getRowUpper() const     {
+          return rowUpper_;
+     }
+     //-------------------------------------------------------------------------
+     /**@name Changing bounds on variables and constraints */
+     //@{
+     /** Set an objective function coefficient */
+     void setObjectiveCoefficient( int elementIndex, double elementValue );
+     /** Set an objective function coefficient */
+     inline void setObjCoeff( int elementIndex, double elementValue ) {
+          setObjectiveCoefficient( elementIndex, elementValue);
+     }
+
+     /** Set a single column lower bound<br>
+         Use -DBL_MAX for -infinity. */
+     void setColumnLower( int elementIndex, double elementValue );
+
+     /** Set a single column upper bound<br>
+         Use DBL_MAX for infinity. */
+     void setColumnUpper( int elementIndex, double elementValue );
+
+     /** Set a single column lower and upper bound */
+     void setColumnBounds( int elementIndex,
+                           double lower, double upper );
+
+     /** Set the bounds on a number of columns simultaneously<br>
+         The default implementation just invokes setColLower() and
+         setColUpper() over and over again.
+         @param indexFirst,indexLast pointers to the beginning and after the
+            end of the array of the indices of the variables whose
+        <em>either</em> bound changes
+         @param boundList the new lower/upper bound pairs for the variables
+     */
+     void setColumnSetBounds(const int* indexFirst,
+                             const int* indexLast,
+                             const double* boundList);
+
+     /** Set a single column lower bound<br>
+         Use -DBL_MAX for -infinity. */
+     inline void setColLower( int elementIndex, double elementValue ) {
+          setColumnLower(elementIndex, elementValue);
+     }
+     /** Set a single column upper bound<br>
+         Use DBL_MAX for infinity. */
+     inline void setColUpper( int elementIndex, double elementValue ) {
+          setColumnUpper(elementIndex, elementValue);
+     }
+
+     /** Set a single column lower and upper bound */
+     inline void setColBounds( int elementIndex,
+                               double lower, double upper ) {
+          setColumnBounds(elementIndex, lower, upper);
+     }
+
+     /** Set the bounds on a number of columns simultaneously<br>
+         @param indexFirst,indexLast pointers to the beginning and after the
+            end of the array of the indices of the variables whose
+        <em>either</em> bound changes
+         @param boundList the new lower/upper bound pairs for the variables
+     */
+     inline void setColSetBounds(const int* indexFirst,
+                                 const int* indexLast,
+                                 const double* boundList) {
+          setColumnSetBounds(indexFirst, indexLast, boundList);
+     }
+
+     /** Set a single row lower bound<br>
+         Use -DBL_MAX for -infinity. */
+     void setRowLower( int elementIndex, double elementValue );
+
+     /** Set a single row upper bound<br>
+         Use DBL_MAX for infinity. */
+     void setRowUpper( int elementIndex, double elementValue ) ;
+
+     /** Set a single row lower and upper bound */
+     void setRowBounds( int elementIndex,
+                        double lower, double upper ) ;
+
+     /** Set the bounds on a number of rows simultaneously<br>
+         @param indexFirst,indexLast pointers to the beginning and after the
+            end of the array of the indices of the constraints whose
+        <em>either</em> bound changes
+         @param boundList the new lower/upper bound pairs for the constraints
+     */
+     void setRowSetBounds(const int* indexFirst,
+                          const int* indexLast,
+                          const double* boundList);
+
+     //@}
+     /// Scaling
+     inline const double * rowScale() const {
+          return rowScale_;
+     }
+     inline const double * columnScale() const {
+          return columnScale_;
+     }
+     inline const double * inverseRowScale() const {
+          return inverseRowScale_;
+     }
+     inline const double * inverseColumnScale() const {
+          return inverseColumnScale_;
+     }
+     inline double * mutableRowScale() const {
+          return rowScale_;
+     }
+     inline double * mutableColumnScale() const {
+          return columnScale_;
+     }
+     inline double * mutableInverseRowScale() const {
+          return inverseRowScale_;
+     }
+     inline double * mutableInverseColumnScale() const {
+          return inverseColumnScale_;
+     }
+     inline double * swapRowScale(double * newScale) {
+          double * oldScale = rowScale_;
+	  rowScale_ = newScale;
+          return oldScale;
+     }
+     void setRowScale(double * scale) ;
+     void setColumnScale(double * scale);
+     /// Scaling of objective
+     inline double objectiveScale() const {
+          return objectiveScale_;
+     }
+     inline void setObjectiveScale(double value) {
+          objectiveScale_ = value;
+     }
+     /// Scaling of rhs and bounds
+     inline double rhsScale() const {
+          return rhsScale_;
+     }
+     inline void setRhsScale(double value) {
+          rhsScale_ = value;
+     }
+     /// Sets or unsets scaling, 0 -off, 1 equilibrium, 2 geometric, 3 auto, 4 auto-but-as-initialSolve-in-bab
+     void scaling(int mode = 1);
+     /** If we constructed a "really" scaled model then this reverses the operation.
+         Quantities may not be exactly as they were before due to rounding errors */
+     void unscale();
+     /// Gets scalingFlag
+     inline int scalingFlag() const {
+          return scalingFlag_;
+     }
+     /// Objective
+     inline double * objective() const {
+          if (objective_) {
+               double offset;
+               return objective_->gradient(NULL, NULL, offset, false);
+          } else {
+               return NULL;
+          }
+     }
+     inline double * objective(const double * solution, double & offset, bool refresh = true) const {
+          offset = 0.0;
+          if (objective_) {
+               return objective_->gradient(NULL, solution, offset, refresh);
+          } else {
+               return NULL;
+          }
+     }
+     inline const double * getObjCoefficients() const {
+          if (objective_) {
+               double offset;
+               return objective_->gradient(NULL, NULL, offset, false);
+          } else {
+               return NULL;
+          }
+     }
+     /// Row Objective
+     inline double * rowObjective() const         {
+          return rowObjective_;
+     }
+     inline const double * getRowObjCoefficients() const {
+          return rowObjective_;
+     }
+     /// Column Lower
+     inline double * columnLower() const          {
+          return columnLower_;
+     }
+     inline const double * getColLower() const    {
+          return columnLower_;
+     }
+     /// Column Upper
+     inline double * columnUpper() const          {
+          return columnUpper_;
+     }
+     inline const double * getColUpper() const    {
+          return columnUpper_;
+     }
+     /// Matrix (if not ClpPackedmatrix be careful about memory leak
+     inline CoinPackedMatrix * matrix() const {
+          if ( matrix_ == NULL ) return NULL;
+          else return matrix_->getPackedMatrix();
+     }
+     /// Number of elements in matrix
+     inline int getNumElements() const {
+          return matrix_->getNumElements();
+     }
+     /** Small element value - elements less than this set to zero,
+        default is 1.0e-20 */
+     inline double getSmallElementValue() const {
+          return smallElement_;
+     }
+     inline void setSmallElementValue(double value) {
+          smallElement_ = value;
+     }
+     /// Row Matrix
+     inline ClpMatrixBase * rowCopy() const       {
+          return rowCopy_;
+     }
+     /// Set new row matrix
+     void setNewRowCopy(ClpMatrixBase * newCopy);
+     /// Clp Matrix
+     inline ClpMatrixBase * clpMatrix() const     {
+          return matrix_;
+     }
+     /// Scaled ClpPackedMatrix
+     inline ClpPackedMatrix * clpScaledMatrix() const     {
+          return scaledMatrix_;
+     }
+     /// Sets pointer to scaled ClpPackedMatrix
+     inline void setClpScaledMatrix(ClpPackedMatrix * scaledMatrix) {
+          delete scaledMatrix_;
+          scaledMatrix_ = scaledMatrix;
+     }
+     /// Swaps pointer to scaled ClpPackedMatrix
+     inline ClpPackedMatrix * swapScaledMatrix(ClpPackedMatrix * scaledMatrix) {
+          ClpPackedMatrix * oldMatrix = scaledMatrix_;
+          scaledMatrix_ = scaledMatrix;
+	  return oldMatrix;
+     }
+     /** Replace Clp Matrix (current is not deleted unless told to
+         and new is used)
+         So up to user to delete current.  This was used where
+         matrices were being rotated. ClpModel takes ownership.
+     */
+     void replaceMatrix(ClpMatrixBase * matrix, bool deleteCurrent = false);
+     /** Replace Clp Matrix (current is not deleted unless told to
+         and new is used) So up to user to delete current.  This was used where
+         matrices were being rotated.  This version changes CoinPackedMatrix
+         to ClpPackedMatrix.  ClpModel takes ownership.
+     */
+     inline void replaceMatrix(CoinPackedMatrix * newmatrix,
+                               bool deleteCurrent = false) {
+          replaceMatrix(new ClpPackedMatrix(newmatrix), deleteCurrent);
+     }
+     /// Objective value
+     inline double objectiveValue() const {
+          return objectiveValue_ * optimizationDirection_ - dblParam_[ClpObjOffset];
+     }
+     inline void setObjectiveValue(double value) {
+          objectiveValue_ = (value + dblParam_[ClpObjOffset]) / optimizationDirection_;
+     }
+     inline double getObjValue() const {
+          return objectiveValue_ * optimizationDirection_ - dblParam_[ClpObjOffset];
+     }
+     /// Integer information
+     inline char * integerInformation() const     {
+          return integerType_;
+     }
+     /** Infeasibility/unbounded ray (NULL returned if none/wrong)
+         Up to user to use delete [] on these arrays.  */
+     double * infeasibilityRay(bool fullRay=false) const;
+     double * unboundedRay() const;
+     /// For advanced users - no need to delete - sign not changed
+     inline double * ray() const
+     { return ray_;}
+     /// just test if infeasibility or unbounded Ray exists
+     inline bool rayExists() const {
+         return (ray_!=NULL);
+     }
+     /// just delete ray if exists
+     inline void deleteRay() {
+         delete [] ray_;
+         ray_=NULL;
+     }
+	 /// Access internal ray storage. Users should call infeasibilityRay() or unboundedRay() instead.
+	 inline const double * internalRay() const {
+		 return ray_;
+	 }
+     /// See if status (i.e. basis) array exists (partly for OsiClp)
+     inline bool statusExists() const {
+          return (status_ != NULL);
+     }
+     /// Return address of status (i.e. basis) array (char[numberRows+numberColumns])
+     inline unsigned char *  statusArray() const {
+          return status_;
+     }
+     /** Return copy of status (i.e. basis) array (char[numberRows+numberColumns]),
+         use delete [] */
+     unsigned char *  statusCopy() const;
+     /// Copy in status (basis) vector
+     void copyinStatus(const unsigned char * statusArray);
+
+     /// User pointer for whatever reason
+     inline void setUserPointer (void * pointer) {
+          userPointer_ = pointer;
+     }
+     inline void * getUserPointer () const {
+          return userPointer_;
+     }
+     /// Trusted user pointer
+     inline void setTrustedUserPointer (ClpTrustedData * pointer) {
+          trustedUserPointer_ = pointer;
+     }
+     inline ClpTrustedData * getTrustedUserPointer () const {
+          return trustedUserPointer_;
+     }
+     /// What has changed in model (only for masochistic users)
+     inline int whatsChanged() const {
+          return whatsChanged_;
+     }
+     inline void setWhatsChanged(int value) {
+          whatsChanged_ = value;
+     }
+     /// Number of threads (not really being used)
+     inline int numberThreads() const {
+          return numberThreads_;
+     }
+     inline void setNumberThreads(int value) {
+          numberThreads_ = value;
+     }
+     //@}
+     /**@name Message handling */
+     //@{
+     /// Pass in Message handler (not deleted at end)
+     void passInMessageHandler(CoinMessageHandler * handler);
+     /// Pass in Message handler (not deleted at end) and return current
+     CoinMessageHandler * pushMessageHandler(CoinMessageHandler * handler,
+                                             bool & oldDefault);
+     /// back to previous message handler
+     void popMessageHandler(CoinMessageHandler * oldHandler, bool oldDefault);
+     /// Set language
+     void newLanguage(CoinMessages::Language language);
+     inline void setLanguage(CoinMessages::Language language) {
+          newLanguage(language);
+     }
+     /// Overrides message handler with a default one
+     void setDefaultMessageHandler();
+     /// Return handler
+     inline CoinMessageHandler * messageHandler() const       {
+          return handler_;
+     }
+     /// Return messages
+     inline CoinMessages messages() const                     {
+          return messages_;
+     }
+     /// Return pointer to messages
+     inline CoinMessages * messagesPointer()                  {
+          return & messages_;
+     }
+     /// Return Coin messages
+     inline CoinMessages coinMessages() const                  {
+          return coinMessages_;
+     }
+     /// Return pointer to Coin messages
+     inline CoinMessages * coinMessagesPointer()                  {
+          return & coinMessages_;
+     }
+     /** Amount of print out:
+         0 - none
+         1 - just final
+         2 - just factorizations
+         3 - as 2 plus a bit more
+         4 - verbose
+         above that 8,16,32 etc just for selective debug
+     */
+     inline void setLogLevel(int value)    {
+          handler_->setLogLevel(value);
+     }
+     inline int logLevel() const           {
+          return handler_->logLevel();
+     }
+     /// Return true if default handler
+     inline bool defaultHandler() const {
+          return defaultHandler_;
+     }
+     /// Pass in Event handler (cloned and deleted at end)
+     void passInEventHandler(const ClpEventHandler * eventHandler);
+     /// Event handler
+     inline ClpEventHandler * eventHandler() const {
+          return eventHandler_;
+     }
+     /// Thread specific random number generator
+     inline CoinThreadRandom * randomNumberGenerator() {
+          return &randomNumberGenerator_;
+     }
+     /// Thread specific random number generator
+     inline CoinThreadRandom & mutableRandomNumberGenerator() {
+          return randomNumberGenerator_;
+     }
+     /// Set seed for thread specific random number generator
+     inline void setRandomSeed(int value) {
+          randomNumberGenerator_.setSeed(value);
+     }
+     /// length of names (0 means no names0
+     inline int lengthNames() const {
+          return lengthNames_;
+     }
+#ifndef CLP_NO_STD
+     /// length of names (0 means no names0
+     inline void setLengthNames(int value) {
+          lengthNames_ = value;
+     }
+     /// Row names
+     inline const std::vector<std::string> * rowNames() const {
+          return &rowNames_;
+     }
+     inline const std::string& rowName(int iRow) const {
+          return rowNames_[iRow];
+     }
+     /// Return name or Rnnnnnnn
+     std::string getRowName(int iRow) const;
+     /// Column names
+     inline const std::vector<std::string> * columnNames() const {
+          return &columnNames_;
+     }
+     inline const std::string& columnName(int iColumn) const {
+          return columnNames_[iColumn];
+     }
+     /// Return name or Cnnnnnnn
+     std::string getColumnName(int iColumn) const;
+#endif
+     /// Objective methods
+     inline ClpObjective * objectiveAsObject() const {
+          return objective_;
+     }
+     void setObjective(ClpObjective * objective);
+     inline void setObjectivePointer(ClpObjective * newobjective) {
+          objective_ = newobjective;
+     }
+     /** Solve a problem with no elements - return status and
+         dual and primal infeasibilites */
+     int emptyProblem(int * infeasNumber = NULL, double * infeasSum = NULL, bool printMessage = true);
+
+     //@}
+
+     /**@name Matrix times vector methods
+        They can be faster if scalar is +- 1
+        These are covers so user need not worry about scaling
+        Also for simplex I am not using basic/non-basic split */
+     //@{
+     /** Return <code>y + A * x * scalar</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numColumns()</code>
+         @pre <code>y</code> must be of size <code>numRows()</code> */
+     void times(double scalar,
+                const double * x, double * y) const;
+     /** Return <code>y + x * scalar * A</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numRows()</code>
+         @pre <code>y</code> must be of size <code>numColumns()</code> */
+     void transposeTimes(double scalar,
+                         const double * x, double * y) const ;
+     //@}
+
+
+     //---------------------------------------------------------------------------
+     /**@name Parameter set/get methods
+
+        The set methods return true if the parameter was set to the given value,
+        false otherwise. There can be various reasons for failure: the given
+        parameter is not applicable for the solver (e.g., refactorization
+        frequency for the volume algorithm), the parameter is not yet implemented
+        for the solver or simply the value of the parameter is out of the range
+        the solver accepts. If a parameter setting call returns false check the
+        details of your solver.
+
+        The get methods return true if the given parameter is applicable for the
+        solver and is implemented. In this case the value of the parameter is
+        returned in the second argument. Otherwise they return false.
+
+        ** once it has been decided where solver sits this may be redone
+     */
+     //@{
+     /// Set an integer parameter
+     bool setIntParam(ClpIntParam key, int value) ;
+     /// Set an double parameter
+     bool setDblParam(ClpDblParam key, double value) ;
+#ifndef CLP_NO_STD
+     /// Set an string parameter
+     bool setStrParam(ClpStrParam key, const std::string & value);
+#endif
+     // Get an integer parameter
+     inline bool getIntParam(ClpIntParam key, int& value) const {
+          if (key < ClpLastIntParam) {
+               value = intParam_[key];
+               return true;
+          } else {
+               return false;
+          }
+     }
+     // Get an double parameter
+     inline bool getDblParam(ClpDblParam key, double& value) const {
+          if (key < ClpLastDblParam) {
+               value = dblParam_[key];
+               return true;
+          } else {
+               return false;
+          }
+     }
+#ifndef CLP_NO_STD
+     // Get a string parameter
+     inline bool getStrParam(ClpStrParam key, std::string& value) const {
+          if (key < ClpLastStrParam) {
+               value = strParam_[key];
+               return true;
+          } else {
+               return false;
+          }
+     }
+#endif
+     /// Create C++ lines to get to current state
+     void generateCpp( FILE * fp);
+     /** For advanced options
+         1 - Don't keep changing infeasibility weight
+         2 - Keep nonLinearCost round solves
+         4 - Force outgoing variables to exact bound (primal)
+         8 - Safe to use dense initial factorization
+         16 -Just use basic variables for operation if column generation
+         32 -Create ray even in BAB
+         64 -Treat problem as feasible until last minute (i.e. minimize infeasibilities)
+         128 - Switch off all matrix sanity checks
+         256 - No row copy
+         512 - If not in values pass, solution guaranteed, skip as much as possible
+         1024 - In branch and bound
+         2048 - Don't bother to re-factorize if < 20 iterations
+         4096 - Skip some optimality checks
+         8192 - Do Primal when cleaning up primal
+         16384 - In fast dual (so we can switch off things)
+         32768 - called from Osi
+         65536 - keep arrays around as much as possible (also use maximumR/C)
+         131072 - transposeTimes is -1.0 and can skip basic and fixed
+         262144 - extra copy of scaled matrix
+         524288 - Clp fast dual
+         1048576 - don't need to finish dual (can return 3)
+	 2097152 - zero costs!
+         NOTE - many applications can call Clp but there may be some short cuts
+                which are taken which are not guaranteed safe from all applications.
+                Vetted applications will have a bit set and the code may test this
+                At present I expect a few such applications - if too many I will
+                have to re-think.  It is up to application owner to change the code
+                if she/he needs these short cuts.  I will not debug unless in Coin
+                repository.  See COIN_CLP_VETTED comments.
+         0x01000000 is Cbc (and in branch and bound)
+         0x02000000 is in a different branch and bound
+     */
+     inline unsigned int specialOptions() const {
+          return specialOptions_;
+     }
+     void setSpecialOptions(unsigned int value);
+#define COIN_CBC_USING_CLP 0x01000000
+     inline bool inCbcBranchAndBound() const {
+          return (specialOptions_ & COIN_CBC_USING_CLP) != 0;
+     }
+     //@}
+
+     /**@name private or protected methods */
+     //@{
+protected:
+     /// Does most of deletion (0 = all, 1 = most)
+     void gutsOfDelete(int type);
+     /** Does most of copying
+         If trueCopy 0 then just points to arrays
+         If -1 leaves as much as possible */
+     void gutsOfCopy(const ClpModel & rhs, int trueCopy = 1);
+     /// gets lower and upper bounds on rows
+     void getRowBound(int iRow, double& lower, double& upper) const;
+     /// puts in format I like - 4 array matrix - may make row copy
+     void gutsOfLoadModel ( int numberRows, int numberColumns,
+                            const double* collb, const double* colub,
+                            const double* obj,
+                            const double* rowlb, const double* rowub,
+                            const double * rowObjective = NULL);
+     /// Does much of scaling
+     void gutsOfScaling();
+     /// Objective value - always minimize
+     inline double rawObjectiveValue() const {
+          return objectiveValue_;
+     }
+     /// If we are using maximumRows_ and Columns_
+     inline bool permanentArrays() const {
+          return (specialOptions_ & 65536) != 0;
+     }
+     /// Start using maximumRows_ and Columns_
+     void startPermanentArrays();
+     /// Stop using maximumRows_ and Columns_
+     void stopPermanentArrays();
+     /// Create row names as char **
+     const char * const * rowNamesAsChar() const;
+     /// Create column names as char **
+     const char * const * columnNamesAsChar() const;
+     /// Delete char * version of names
+     void deleteNamesAsChar(const char * const * names, int number) const;
+     /// On stopped - sets secondary status
+     void onStopped();
+     //@}
+
+
+////////////////// data //////////////////
+protected:
+
+     /**@name data */
+     //@{
+     /// Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+     double optimizationDirection_;
+     /// Array of double parameters
+     double dblParam_[ClpLastDblParam];
+     /// Objective value
+     double objectiveValue_;
+     /// Small element value
+     double smallElement_;
+     /// Scaling of objective
+     double objectiveScale_;
+     /// Scaling of rhs and bounds
+     double rhsScale_;
+     /// Number of rows
+     int numberRows_;
+     /// Number of columns
+     int numberColumns_;
+     /// Row activities
+     double * rowActivity_;
+     /// Column activities
+     double * columnActivity_;
+     /// Duals
+     double * dual_;
+     /// Reduced costs
+     double * reducedCost_;
+     /// Row lower
+     double* rowLower_;
+     /// Row upper
+     double* rowUpper_;
+     /// Objective
+     ClpObjective * objective_;
+     /// Row Objective (? sign)  - may be NULL
+     double * rowObjective_;
+     /// Column Lower
+     double * columnLower_;
+     /// Column Upper
+     double * columnUpper_;
+     /// Packed matrix
+     ClpMatrixBase * matrix_;
+     /// Row copy if wanted
+     ClpMatrixBase * rowCopy_;
+     /// Scaled packed matrix
+     ClpPackedMatrix * scaledMatrix_;
+     /// Infeasible/unbounded ray
+     double * ray_;
+     /// Row scale factors for matrix
+     double * rowScale_;
+     /// Column scale factors
+     double * columnScale_;
+     /// Inverse row scale factors for matrix (end of rowScale_)
+     double * inverseRowScale_;
+     /// Inverse column scale factors for matrix (end of columnScale_)
+     double * inverseColumnScale_;
+     /** Scale flag, 0 none, 1 equilibrium, 2 geometric, 3, auto, 4 dynamic,
+         5 geometric on rows */
+     int scalingFlag_;
+     /** Status (i.e. basis) Region.  I know that not all algorithms need a status
+         array, but it made sense for things like crossover and put
+         all permanent stuff in one place.  No assumption is made
+         about what is in status array (although it might be good to reserve
+         bottom 3 bits (i.e. 0-7 numeric) for classic status).  This
+         is number of columns + number of rows long (in that order).
+     */
+     unsigned char * status_;
+     /// Integer information
+     char * integerType_;
+     /// User pointer for whatever reason
+     void * userPointer_;
+     /// Trusted user pointer e.g. for heuristics
+     ClpTrustedData * trustedUserPointer_;
+     /// Array of integer parameters
+     int intParam_[ClpLastIntParam];
+     /// Number of iterations
+     int numberIterations_;
+     /** Solve type - 1 simplex, 2 simplex interface, 3 Interior.*/
+     int solveType_;
+     /** Whats changed since last solve.  This is a work in progress
+         It is designed so careful people can make go faster.
+         It is only used when startFinishOptions used in dual or primal.
+         Bit 1 - number of rows/columns has not changed (so work arrays valid)
+             2 - matrix has not changed
+             4 - if matrix has changed only by adding rows
+             8 - if matrix has changed only by adding columns
+            16 - row lbs not changed
+            32 - row ubs not changed
+            64 - column objective not changed
+           128 - column lbs not changed
+           256 - column ubs not changed
+       512 - basis not changed (up to user to set this to 0)
+             top bits may be used internally
+       shift by 65336 is 3 all same, 1 all except col bounds
+     */
+#define ROW_COLUMN_COUNTS_SAME 1
+#define MATRIX_SAME 2
+#define MATRIX_JUST_ROWS_ADDED 4
+#define MATRIX_JUST_COLUMNS_ADDED 8
+#define ROW_LOWER_SAME 16
+#define ROW_UPPER_SAME 32
+#define OBJECTIVE_SAME 64 
+#define COLUMN_LOWER_SAME 128
+#define COLUMN_UPPER_SAME 256
+#define BASIS_SAME 512
+#define ALL_SAME 65339
+#define ALL_SAME_EXCEPT_COLUMN_BOUNDS 65337
+     unsigned int whatsChanged_;
+     /// Status of problem
+     int problemStatus_;
+     /// Secondary status of problem
+     int secondaryStatus_;
+     /// length of names (0 means no names)
+     int lengthNames_;
+     /// Number of threads (not very operational)
+     int numberThreads_;
+     /** For advanced options
+         See get and set for meaning
+     */
+     unsigned int specialOptions_;
+     /// Message handler
+     CoinMessageHandler * handler_;
+     /// Flag to say if default handler (so delete)
+     bool defaultHandler_;
+     /// Thread specific random number generator
+     CoinThreadRandom randomNumberGenerator_;
+     /// Event handler
+     ClpEventHandler * eventHandler_;
+#ifndef CLP_NO_STD
+     /// Row names
+     std::vector<std::string> rowNames_;
+     /// Column names
+     std::vector<std::string> columnNames_;
+#endif
+     /// Messages
+     CoinMessages messages_;
+     /// Coin messages
+     CoinMessages coinMessages_;
+     /// Maximum number of columns in model
+     int maximumColumns_;
+     /// Maximum number of rows in model
+     int maximumRows_;
+     /// Maximum number of columns (internal arrays) in model
+     int maximumInternalColumns_;
+     /// Maximum number of rows (internal arrays) in model
+     int maximumInternalRows_;
+     /// Base packed matrix
+     CoinPackedMatrix baseMatrix_;
+     /// Base row copy
+     CoinPackedMatrix baseRowCopy_;
+     /// Saved row scale factors for matrix
+     double * savedRowScale_;
+     /// Saved column scale factors
+     double * savedColumnScale_;
+#ifndef CLP_NO_STD
+     /// Array of string parameters
+     std::string strParam_[ClpLastStrParam];
+#endif
+     //@}
+};
+/** This is a tiny class where data can be saved round calls.
+ */
+class ClpDataSave {
+
+public:
+     /**@name Constructors and destructor
+      */
+     //@{
+     /// Default constructor
+     ClpDataSave (  );
+
+     /// Copy constructor.
+     ClpDataSave(const ClpDataSave &);
+     /// Assignment operator. This copies the data
+     ClpDataSave & operator=(const ClpDataSave & rhs);
+     /// Destructor
+     ~ClpDataSave (  );
+
+     //@}
+
+////////////////// data //////////////////
+public:
+
+     /**@name data - with same names as in other classes*/
+     //@{
+     double dualBound_;
+     double infeasibilityCost_;
+     double pivotTolerance_;
+     double zeroFactorizationTolerance_;
+     double zeroSimplexTolerance_;
+     double acceptablePivot_;
+     double objectiveScale_;
+     int sparseThreshold_;
+     int perturbation_;
+     int forceFactorization_;
+     int scalingFlag_;
+     unsigned int specialOptions_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpNetworkBasis.cpp b/cbits/coin/ClpNetworkBasis.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpNetworkBasis.cpp
@@ -0,0 +1,1173 @@
+/* $Id: ClpNetworkBasis.cpp 1732 2011-05-31 08:09:41Z forrest $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpNetworkBasis.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpMatrixBase.hpp"
+#include "CoinIndexedVector.hpp"
+
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpNetworkBasis::ClpNetworkBasis ()
+{
+#ifndef COIN_FAST_CODE
+     slackValue_ = -1.0;
+#endif
+     numberRows_ = 0;
+     numberColumns_ = 0;
+     parent_ = NULL;
+     descendant_ = NULL;
+     pivot_ = NULL;
+     rightSibling_ = NULL;
+     leftSibling_ = NULL;
+     sign_ = NULL;
+     stack_ = NULL;
+     permute_ = NULL;
+     permuteBack_ = NULL;
+     stack2_ = NULL;
+     depth_ = NULL;
+     mark_ = NULL;
+     model_ = NULL;
+}
+// Constructor from CoinFactorization
+ClpNetworkBasis::ClpNetworkBasis(const ClpSimplex * model,
+                                 int numberRows, const CoinFactorizationDouble * pivotRegion,
+                                 const int * permuteBack,
+                                 const CoinBigIndex * startColumn,
+                                 const int * numberInColumn,
+                                 const int * indexRow, const CoinFactorizationDouble * /*element*/)
+{
+#ifndef COIN_FAST_CODE
+     slackValue_ = -1.0;
+#endif
+     numberRows_ = numberRows;
+     numberColumns_ = numberRows;
+     parent_ = new int [ numberRows_+1];
+     descendant_ = new int [ numberRows_+1];
+     pivot_ = new int [ numberRows_+1];
+     rightSibling_ = new int [ numberRows_+1];
+     leftSibling_ = new int [ numberRows_+1];
+     sign_ = new double [ numberRows_+1];
+     stack_ = new int [ numberRows_+1];
+     stack2_ = new int[numberRows_+1];
+     depth_ = new int[numberRows_+1];
+     mark_ = new char[numberRows_+1];
+     permute_ = new int [numberRows_ + 1];
+     permuteBack_ = new int [numberRows_ + 1];
+     int i;
+     for (i = 0; i < numberRows_ + 1; i++) {
+          parent_[i] = -1;
+          descendant_[i] = -1;
+          pivot_[i] = -1;
+          rightSibling_[i] = -1;
+          leftSibling_[i] = -1;
+          sign_[i] = -1.0;
+          stack_[i] = -1;
+          permute_[i] = i;
+          permuteBack_[i] = i;
+          stack2_[i] = -1;
+          depth_[i] = -1;
+          mark_[i] = 0;
+     }
+     mark_[numberRows_] = 1;
+     // pivotColumnBack gives order of pivoting into basis
+     // so pivotColumnback[0] is first slack in basis and
+     // it pivots on row permuteBack[0]
+     // a known root is given by permuteBack[numberRows_-1]
+     for (i = 0; i < numberRows_; i++) {
+          int iPivot = permuteBack[i];
+          double sign;
+          if (pivotRegion[i] > 0.0)
+               sign = 1.0;
+          else
+               sign = -1.0;
+          int other;
+          if (numberInColumn[i] > 0) {
+               int iRow = indexRow[startColumn[i]];
+               other = permuteBack[iRow];
+               //assert (parent_[other]!=-1);
+          } else {
+               other = numberRows_;
+          }
+          sign_[iPivot] = sign;
+          int iParent = other;
+          parent_[iPivot] = other;
+          if (descendant_[iParent] >= 0) {
+               // we have a sibling
+               int iRight = descendant_[iParent];
+               rightSibling_[iPivot] = iRight;
+               leftSibling_[iRight] = iPivot;
+          } else {
+               rightSibling_[iPivot] = -1;
+          }
+          descendant_[iParent] = iPivot;
+          leftSibling_[iPivot] = -1;
+     }
+     // do depth
+     int nStack = 1;
+     stack_[0] = descendant_[numberRows_];
+     depth_[numberRows_] = -1; // root
+     while (nStack) {
+          // take off
+          int iNext = stack_[--nStack];
+          if (iNext >= 0) {
+               depth_[iNext] = nStack;
+               int iRight = rightSibling_[iNext];
+               stack_[nStack++] = iRight;
+               if (descendant_[iNext] >= 0)
+                    stack_[nStack++] = descendant_[iNext];
+          }
+     }
+     model_ = model;
+     check();
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpNetworkBasis::ClpNetworkBasis (const ClpNetworkBasis & rhs)
+{
+#ifndef COIN_FAST_CODE
+     slackValue_ = rhs.slackValue_;
+#endif
+     numberRows_ = rhs.numberRows_;
+     numberColumns_ = rhs.numberColumns_;
+     if (rhs.parent_) {
+          parent_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.parent_, (numberRows_ + 1), parent_);
+     } else {
+          parent_ = NULL;
+     }
+     if (rhs.descendant_) {
+          descendant_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.descendant_, (numberRows_ + 1), descendant_);
+     } else {
+          descendant_ = NULL;
+     }
+     if (rhs.pivot_) {
+          pivot_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.pivot_, (numberRows_ + 1), pivot_);
+     } else {
+          pivot_ = NULL;
+     }
+     if (rhs.rightSibling_) {
+          rightSibling_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.rightSibling_, (numberRows_ + 1), rightSibling_);
+     } else {
+          rightSibling_ = NULL;
+     }
+     if (rhs.leftSibling_) {
+          leftSibling_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.leftSibling_, (numberRows_ + 1), leftSibling_);
+     } else {
+          leftSibling_ = NULL;
+     }
+     if (rhs.sign_) {
+          sign_ = new double [numberRows_+1];
+          CoinMemcpyN(rhs.sign_, (numberRows_ + 1), sign_);
+     } else {
+          sign_ = NULL;
+     }
+     if (rhs.stack_) {
+          stack_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.stack_, (numberRows_ + 1), stack_);
+     } else {
+          stack_ = NULL;
+     }
+     if (rhs.permute_) {
+          permute_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.permute_, (numberRows_ + 1), permute_);
+     } else {
+          permute_ = NULL;
+     }
+     if (rhs.permuteBack_) {
+          permuteBack_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.permuteBack_, (numberRows_ + 1), permuteBack_);
+     } else {
+          permuteBack_ = NULL;
+     }
+     if (rhs.stack2_) {
+          stack2_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.stack2_, (numberRows_ + 1), stack2_);
+     } else {
+          stack2_ = NULL;
+     }
+     if (rhs.depth_) {
+          depth_ = new int [numberRows_+1];
+          CoinMemcpyN(rhs.depth_, (numberRows_ + 1), depth_);
+     } else {
+          depth_ = NULL;
+     }
+     if (rhs.mark_) {
+          mark_ = new char [numberRows_+1];
+          CoinMemcpyN(rhs.mark_, (numberRows_ + 1), mark_);
+     } else {
+          mark_ = NULL;
+     }
+     model_ = rhs.model_;
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpNetworkBasis::~ClpNetworkBasis ()
+{
+     delete [] parent_;
+     delete [] descendant_;
+     delete [] pivot_;
+     delete [] rightSibling_;
+     delete [] leftSibling_;
+     delete [] sign_;
+     delete [] stack_;
+     delete [] permute_;
+     delete [] permuteBack_;
+     delete [] stack2_;
+     delete [] depth_;
+     delete [] mark_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpNetworkBasis &
+ClpNetworkBasis::operator=(const ClpNetworkBasis& rhs)
+{
+     if (this != &rhs) {
+          delete [] parent_;
+          delete [] descendant_;
+          delete [] pivot_;
+          delete [] rightSibling_;
+          delete [] leftSibling_;
+          delete [] sign_;
+          delete [] stack_;
+          delete [] permute_;
+          delete [] permuteBack_;
+          delete [] stack2_;
+          delete [] depth_;
+          delete [] mark_;
+#ifndef COIN_FAST_CODE
+          slackValue_ = rhs.slackValue_;
+#endif
+          numberRows_ = rhs.numberRows_;
+          numberColumns_ = rhs.numberColumns_;
+          if (rhs.parent_) {
+               parent_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.parent_, (numberRows_ + 1), parent_);
+          } else {
+               parent_ = NULL;
+          }
+          if (rhs.descendant_) {
+               descendant_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.descendant_, (numberRows_ + 1), descendant_);
+          } else {
+               descendant_ = NULL;
+          }
+          if (rhs.pivot_) {
+               pivot_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.pivot_, (numberRows_ + 1), pivot_);
+          } else {
+               pivot_ = NULL;
+          }
+          if (rhs.rightSibling_) {
+               rightSibling_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.rightSibling_, (numberRows_ + 1), rightSibling_);
+          } else {
+               rightSibling_ = NULL;
+          }
+          if (rhs.leftSibling_) {
+               leftSibling_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.leftSibling_, (numberRows_ + 1), leftSibling_);
+          } else {
+               leftSibling_ = NULL;
+          }
+          if (rhs.sign_) {
+               sign_ = new double [numberRows_+1];
+               CoinMemcpyN(rhs.sign_, (numberRows_ + 1), sign_);
+          } else {
+               sign_ = NULL;
+          }
+          if (rhs.stack_) {
+               stack_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.stack_, (numberRows_ + 1), stack_);
+          } else {
+               stack_ = NULL;
+          }
+          if (rhs.permute_) {
+               permute_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.permute_, (numberRows_ + 1), permute_);
+          } else {
+               permute_ = NULL;
+          }
+          if (rhs.permuteBack_) {
+               permuteBack_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.permuteBack_, (numberRows_ + 1), permuteBack_);
+          } else {
+               permuteBack_ = NULL;
+          }
+          if (rhs.stack2_) {
+               stack2_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.stack2_, (numberRows_ + 1), stack2_);
+          } else {
+               stack2_ = NULL;
+          }
+          if (rhs.depth_) {
+               depth_ = new int [numberRows_+1];
+               CoinMemcpyN(rhs.depth_, (numberRows_ + 1), depth_);
+          } else {
+               depth_ = NULL;
+          }
+          if (rhs.mark_) {
+               mark_ = new char [numberRows_+1];
+               CoinMemcpyN(rhs.mark_, (numberRows_ + 1), mark_);
+          } else {
+               mark_ = NULL;
+          }
+     }
+     return *this;
+}
+// checks looks okay
+void ClpNetworkBasis::check()
+{
+     // check depth
+     int nStack = 1;
+     stack_[0] = descendant_[numberRows_];
+     depth_[numberRows_] = -1; // root
+     while (nStack) {
+          // take off
+          int iNext = stack_[--nStack];
+          if (iNext >= 0) {
+               //assert (depth_[iNext]==nStack);
+               depth_[iNext] = nStack;
+               int iRight = rightSibling_[iNext];
+               stack_[nStack++] = iRight;
+               if (descendant_[iNext] >= 0)
+                    stack_[nStack++] = descendant_[iNext];
+          }
+     }
+}
+// prints
+void ClpNetworkBasis::print()
+{
+     int i;
+     printf("       parent descendant     left    right   sign    depth\n");
+     for (i = 0; i < numberRows_ + 1; i++)
+          printf("%4d  %7d   %8d  %7d  %7d  %5g  %7d\n",
+                 i, parent_[i], descendant_[i], leftSibling_[i], rightSibling_[i],
+                 sign_[i], depth_[i]);
+}
+/* Replaces one Column to basis,
+   returns 0=OK
+*/
+int
+ClpNetworkBasis::replaceColumn ( CoinIndexedVector * regionSparse,
+                                 int pivotRow)
+{
+     // When things have settled down then redo this to make more elegant
+     // I am sure lots of loops can be combined
+     // regionSparse is empty
+     assert (!regionSparse->getNumElements());
+     model_->unpack(regionSparse, model_->sequenceIn());
+     // arc given by pivotRow is leaving basis
+     //int kParent = parent_[pivotRow];
+     // arc coming in has these two nodes
+     int * indices = regionSparse->getIndices();
+     int iRow0 = indices[0];
+     int iRow1;
+     if (regionSparse->getNumElements() == 2)
+          iRow1 = indices[1];
+     else
+          iRow1 = numberRows_;
+     double sign = -regionSparse->denseVector()[iRow0];
+     regionSparse->clear();
+     // and outgoing
+     model_->unpack(regionSparse, model_->pivotVariable()[pivotRow]);
+     int jRow0 = indices[0];
+     int jRow1;
+     if (regionSparse->getNumElements() == 2)
+          jRow1 = indices[1];
+     else
+          jRow1 = numberRows_;
+     regionSparse->clear();
+     // get correct pivotRow
+     //#define FULL_DEBUG
+#ifdef FULL_DEBUG
+     printf ("irow %d %d, jrow %d %d\n",
+             iRow0, iRow1, jRow0, jRow1);
+#endif
+     if (parent_[jRow0] == jRow1) {
+          int newPivot = jRow0;
+          if (newPivot != pivotRow) {
+#ifdef FULL_DEBUG
+               printf("pivot row of %d permuted to %d\n", pivotRow, newPivot);
+#endif
+               pivotRow = newPivot;
+          }
+     } else {
+          //assert (parent_[jRow1]==jRow0);
+          int newPivot = jRow1;
+          if (newPivot != pivotRow) {
+#ifdef FULL_DEBUG
+               printf("pivot row of %d permuted to %d\n", pivotRow, newPivot);
+#endif
+               pivotRow = newPivot;
+          }
+     }
+     bool extraPrint = (model_->numberIterations() > -3) &&
+                       (model_->logLevel() > 10);
+     if (extraPrint)
+          print();
+#ifdef FULL_DEBUG
+     printf("In %d (region= %g, stored %g) %d (%g) pivoting on %d (%g)\n",
+            iRow1, sign, sign_[iRow1], iRow0, sign_[iRow0] , pivotRow, sign_[pivotRow]);
+#endif
+     // see which path outgoing pivot is on
+     int kRow = -1;
+     int jRow = iRow1;
+     while (jRow != numberRows_) {
+          if (jRow == pivotRow) {
+               kRow = iRow1;
+               break;
+          } else {
+               jRow = parent_[jRow];
+          }
+     }
+     if (kRow < 0) {
+          jRow = iRow0;
+          while (jRow != numberRows_) {
+               if (jRow == pivotRow) {
+                    kRow = iRow0;
+                    break;
+               } else {
+                    jRow = parent_[jRow];
+               }
+          }
+     }
+     //assert (kRow>=0);
+     if (iRow0 == kRow) {
+          iRow0 = iRow1;
+          iRow1 = kRow;
+          sign = -sign;
+     }
+     // pivot row is on path from iRow1 back to root
+     // get stack of nodes to change
+     // Also get precursors for cleaning order
+     int nStack = 1;
+     stack_[0] = iRow0;
+     while (kRow != pivotRow) {
+          stack_[nStack++] = kRow;
+          if (sign * sign_[kRow] < 0.0) {
+               sign_[kRow] = -sign_[kRow];
+          } else {
+               sign = -sign;
+          }
+          kRow = parent_[kRow];
+          //sign *= sign_[kRow];
+     }
+     stack_[nStack++] = pivotRow;
+     if (sign * sign_[pivotRow] < 0.0) {
+          sign_[pivotRow] = -sign_[pivotRow];
+     } else {
+          sign = -sign;
+     }
+     int iParent = parent_[pivotRow];
+     while (nStack > 1) {
+          int iLeft;
+          int iRight;
+          kRow = stack_[--nStack];
+          int newParent = stack_[nStack-1];
+#ifdef FULL_DEBUG
+          printf("row %d, old parent %d, new parent %d, pivotrow %d\n", kRow,
+                 iParent, newParent, pivotRow);
+#endif
+          int i1 = permuteBack_[pivotRow];
+          int i2 = permuteBack_[kRow];
+          permuteBack_[pivotRow] = i2;
+          permuteBack_[kRow] = i1;
+          // do Btran permutation
+          permute_[i1] = kRow;
+          permute_[i2] = pivotRow;
+          pivotRow = kRow;
+          // Take out of old parent
+          iLeft = leftSibling_[kRow];
+          iRight = rightSibling_[kRow];
+          if (iLeft < 0) {
+               // take out of tree
+               if (iRight >= 0) {
+                    leftSibling_[iRight] = iLeft;
+                    descendant_[iParent] = iRight;
+               } else {
+#ifdef FULL_DEBUG
+                    printf("Saying %d (old parent of %d) has no descendants\n",
+                           iParent, kRow);
+#endif
+                    descendant_[iParent] = -1;
+               }
+          } else {
+               // take out of tree
+               rightSibling_[iLeft] = iRight;
+               if (iRight >= 0)
+                    leftSibling_[iRight] = iLeft;
+          }
+          leftSibling_[kRow] = -1;
+          rightSibling_[kRow] = -1;
+
+          // now insert new one
+          // make this descendant of that
+          if (descendant_[newParent] >= 0) {
+               // we will have a sibling
+               int jRight = descendant_[newParent];
+               rightSibling_[kRow] = jRight;
+               leftSibling_[jRight] = kRow;
+          } else {
+               rightSibling_[kRow] = -1;
+          }
+          descendant_[newParent] = kRow;
+          leftSibling_[kRow] = -1;
+          parent_[kRow] = newParent;
+
+          iParent = kRow;
+     }
+     // now redo all depths from stack_[1]
+     // This must be possible to combine - but later
+     {
+          int iPivot  = stack_[1];
+          int iDepth = depth_[parent_[iPivot]]; //depth of parent
+          iDepth ++; //correct for this one
+          int nStack = 1;
+          stack_[0] = iPivot;
+          while (nStack) {
+               // take off
+               int iNext = stack_[--nStack];
+               if (iNext >= 0) {
+                    // add stack level
+                    depth_[iNext] = nStack + iDepth;
+                    stack_[nStack++] = rightSibling_[iNext];
+                    if (descendant_[iNext] >= 0)
+                         stack_[nStack++] = descendant_[iNext];
+               }
+          }
+     }
+     if (extraPrint)
+          print();
+     //check();
+     return 0;
+}
+
+/* Updates one column (FTRAN) from region2 */
+double
+ClpNetworkBasis::updateColumn (  CoinIndexedVector * regionSparse,
+                                 CoinIndexedVector * regionSparse2,
+                                 int pivotRow)
+{
+     regionSparse->clear (  );
+     double *region = regionSparse->denseVector (  );
+     double *region2 = regionSparse2->denseVector (  );
+     int *regionIndex2 = regionSparse2->getIndices (  );
+     int numberNonZero = regionSparse2->getNumElements (  );
+     int *regionIndex = regionSparse->getIndices (  );
+     int i;
+     bool doTwo = (numberNonZero == 2);
+     int i0 = -1;
+     int i1 = -1;
+     if (doTwo) {
+          i0 = regionIndex2[0];
+          i1 = regionIndex2[1];
+     }
+     double returnValue = 0.0;
+     bool packed = regionSparse2->packedMode();
+     if (packed) {
+          if (doTwo && region2[0]*region2[1] < 0.0) {
+               region[i0] = region2[0];
+               region2[0] = 0.0;
+               region[i1] = region2[1];
+               region2[1] = 0.0;
+               int iDepth0 = depth_[i0];
+               int iDepth1 = depth_[i1];
+               if (iDepth1 > iDepth0) {
+                    int temp = i0;
+                    i0 = i1;
+                    i1 = temp;
+                    temp = iDepth0;
+                    iDepth0 = iDepth1;
+                    iDepth1 = temp;
+               }
+               numberNonZero = 0;
+               if (pivotRow < 0) {
+                    while (iDepth0 > iDepth1) {
+                         double pivotValue = region[i0];
+                         // put back now ?
+                         int iBack = permuteBack_[i0];
+                         region2[numberNonZero] = pivotValue * sign_[i0];
+                         regionIndex2[numberNonZero++] = iBack;
+                         int otherRow = parent_[i0];
+                         region[i0] = 0.0;
+                         region[otherRow] += pivotValue;
+                         iDepth0--;
+                         i0 = otherRow;
+                    }
+                    while (i0 != i1) {
+                         double pivotValue = region[i0];
+                         // put back now ?
+                         int iBack = permuteBack_[i0];
+                         region2[numberNonZero] = pivotValue * sign_[i0];
+                         regionIndex2[numberNonZero++] = iBack;
+                         int otherRow = parent_[i0];
+                         region[i0] = 0.0;
+                         region[otherRow] += pivotValue;
+                         i0 = otherRow;
+                         double pivotValue1 = region[i1];
+                         // put back now ?
+                         int iBack1 = permuteBack_[i1];
+                         region2[numberNonZero] = pivotValue1 * sign_[i1];
+                         regionIndex2[numberNonZero++] = iBack1;
+                         int otherRow1 = parent_[i1];
+                         region[i1] = 0.0;
+                         region[otherRow1] += pivotValue1;
+                         i1 = otherRow1;
+                    }
+               } else {
+                    while (iDepth0 > iDepth1) {
+                         double pivotValue = region[i0];
+                         // put back now ?
+                         int iBack = permuteBack_[i0];
+                         double value = pivotValue * sign_[i0];
+                         region2[numberNonZero] = value;
+                         regionIndex2[numberNonZero++] = iBack;
+                         if (iBack == pivotRow)
+                              returnValue = value;
+                         int otherRow = parent_[i0];
+                         region[i0] = 0.0;
+                         region[otherRow] += pivotValue;
+                         iDepth0--;
+                         i0 = otherRow;
+                    }
+                    while (i0 != i1) {
+                         double pivotValue = region[i0];
+                         // put back now ?
+                         int iBack = permuteBack_[i0];
+                         double value = pivotValue * sign_[i0];
+                         region2[numberNonZero] = value;
+                         regionIndex2[numberNonZero++] = iBack;
+                         if (iBack == pivotRow)
+                              returnValue = value;
+                         int otherRow = parent_[i0];
+                         region[i0] = 0.0;
+                         region[otherRow] += pivotValue;
+                         i0 = otherRow;
+                         double pivotValue1 = region[i1];
+                         // put back now ?
+                         int iBack1 = permuteBack_[i1];
+                         value = pivotValue1 * sign_[i1];
+                         region2[numberNonZero] = value;
+                         regionIndex2[numberNonZero++] = iBack1;
+                         if (iBack1 == pivotRow)
+                              returnValue = value;
+                         int otherRow1 = parent_[i1];
+                         region[i1] = 0.0;
+                         region[otherRow1] += pivotValue1;
+                         i1 = otherRow1;
+                    }
+               }
+          } else {
+               // set up linked lists at each depth
+               // stack2 is start, stack is next
+               int greatestDepth = -1;
+               //mark_[numberRows_]=1;
+               for (i = 0; i < numberNonZero; i++) {
+                    int j = regionIndex2[i];
+                    double value = region2[i];
+                    region2[i] = 0.0;
+                    region[j] = value;
+                    regionIndex[i] = j;
+                    int iDepth = depth_[j];
+                    if (iDepth > greatestDepth)
+                         greatestDepth = iDepth;
+                    // and back until marked
+                    while (!mark_[j]) {
+                         int iNext = stack2_[iDepth];
+                         stack2_[iDepth] = j;
+                         stack_[j] = iNext;
+                         mark_[j] = 1;
+                         iDepth--;
+                         j = parent_[j];
+                    }
+               }
+               numberNonZero = 0;
+               if (pivotRow < 0) {
+                    for (; greatestDepth >= 0; greatestDepth--) {
+                         int iPivot = stack2_[greatestDepth];
+                         stack2_[greatestDepth] = -1;
+                         while (iPivot >= 0) {
+                              mark_[iPivot] = 0;
+                              double pivotValue = region[iPivot];
+                              if (pivotValue) {
+                                   // put back now ?
+                                   int iBack = permuteBack_[iPivot];
+                                   region2[numberNonZero] = pivotValue * sign_[iPivot];
+                                   regionIndex2[numberNonZero++] = iBack;
+                                   int otherRow = parent_[iPivot];
+                                   region[iPivot] = 0.0;
+                                   region[otherRow] += pivotValue;
+                              }
+                              iPivot = stack_[iPivot];
+                         }
+                    }
+               } else {
+                    for (; greatestDepth >= 0; greatestDepth--) {
+                         int iPivot = stack2_[greatestDepth];
+                         stack2_[greatestDepth] = -1;
+                         while (iPivot >= 0) {
+                              mark_[iPivot] = 0;
+                              double pivotValue = region[iPivot];
+                              if (pivotValue) {
+                                   // put back now ?
+                                   int iBack = permuteBack_[iPivot];
+                                   double value = pivotValue * sign_[iPivot];
+                                   region2[numberNonZero] = value;
+                                   regionIndex2[numberNonZero++] = iBack;
+                                   if (iBack == pivotRow)
+                                        returnValue = value;
+                                   int otherRow = parent_[iPivot];
+                                   region[iPivot] = 0.0;
+                                   region[otherRow] += pivotValue;
+                              }
+                              iPivot = stack_[iPivot];
+                         }
+                    }
+               }
+          }
+     } else {
+          if (doTwo && region2[i0]*region2[i1] < 0.0) {
+               // If just +- 1 then could go backwards on depth until join
+               region[i0] = region2[i0];
+               region2[i0] = 0.0;
+               region[i1] = region2[i1];
+               region2[i1] = 0.0;
+               int iDepth0 = depth_[i0];
+               int iDepth1 = depth_[i1];
+               if (iDepth1 > iDepth0) {
+                    int temp = i0;
+                    i0 = i1;
+                    i1 = temp;
+                    temp = iDepth0;
+                    iDepth0 = iDepth1;
+                    iDepth1 = temp;
+               }
+               numberNonZero = 0;
+               while (iDepth0 > iDepth1) {
+                    double pivotValue = region[i0];
+                    // put back now ?
+                    int iBack = permuteBack_[i0];
+                    regionIndex2[numberNonZero++] = iBack;
+                    int otherRow = parent_[i0];
+                    region2[iBack] = pivotValue * sign_[i0];
+                    region[i0] = 0.0;
+                    region[otherRow] += pivotValue;
+                    iDepth0--;
+                    i0 = otherRow;
+               }
+               while (i0 != i1) {
+                    double pivotValue = region[i0];
+                    // put back now ?
+                    int iBack = permuteBack_[i0];
+                    regionIndex2[numberNonZero++] = iBack;
+                    int otherRow = parent_[i0];
+                    region2[iBack] = pivotValue * sign_[i0];
+                    region[i0] = 0.0;
+                    region[otherRow] += pivotValue;
+                    i0 = otherRow;
+                    double pivotValue1 = region[i1];
+                    // put back now ?
+                    int iBack1 = permuteBack_[i1];
+                    regionIndex2[numberNonZero++] = iBack1;
+                    int otherRow1 = parent_[i1];
+                    region2[iBack1] = pivotValue1 * sign_[i1];
+                    region[i1] = 0.0;
+                    region[otherRow1] += pivotValue1;
+                    i1 = otherRow1;
+               }
+          } else {
+               // set up linked lists at each depth
+               // stack2 is start, stack is next
+               int greatestDepth = -1;
+               //mark_[numberRows_]=1;
+               for (i = 0; i < numberNonZero; i++) {
+                    int j = regionIndex2[i];
+                    double value = region2[j];
+                    region2[j] = 0.0;
+                    region[j] = value;
+                    regionIndex[i] = j;
+                    int iDepth = depth_[j];
+                    if (iDepth > greatestDepth)
+                         greatestDepth = iDepth;
+                    // and back until marked
+                    while (!mark_[j]) {
+                         int iNext = stack2_[iDepth];
+                         stack2_[iDepth] = j;
+                         stack_[j] = iNext;
+                         mark_[j] = 1;
+                         iDepth--;
+                         j = parent_[j];
+                    }
+               }
+               numberNonZero = 0;
+               for (; greatestDepth >= 0; greatestDepth--) {
+                    int iPivot = stack2_[greatestDepth];
+                    stack2_[greatestDepth] = -1;
+                    while (iPivot >= 0) {
+                         mark_[iPivot] = 0;
+                         double pivotValue = region[iPivot];
+                         if (pivotValue) {
+                              // put back now ?
+                              int iBack = permuteBack_[iPivot];
+                              regionIndex2[numberNonZero++] = iBack;
+                              int otherRow = parent_[iPivot];
+                              region2[iBack] = pivotValue * sign_[iPivot];
+                              region[iPivot] = 0.0;
+                              region[otherRow] += pivotValue;
+                         }
+                         iPivot = stack_[iPivot];
+                    }
+               }
+          }
+          if (pivotRow >= 0)
+               returnValue = region2[pivotRow];
+     }
+     region[numberRows_] = 0.0;
+     regionSparse2->setNumElements(numberNonZero);
+#ifdef FULL_DEBUG
+     {
+          int i;
+          for (i = 0; i < numberRows_; i++) {
+               assert(!mark_[i]);
+               assert (stack2_[i] == -1);
+          }
+     }
+#endif
+     return returnValue;
+}
+/* Updates one column (FTRAN) to/from array
+    ** For large problems you should ALWAYS know where the nonzeros
+   are, so please try and migrate to previous method after you
+   have got code working using this simple method - thank you!
+   (the only exception is if you know input is dense e.g. rhs) */
+int
+ClpNetworkBasis::updateColumn (  CoinIndexedVector * regionSparse,
+                                 double region2[] ) const
+{
+     regionSparse->clear (  );
+     double *region = regionSparse->denseVector (  );
+     int numberNonZero = 0;
+     int *regionIndex = regionSparse->getIndices (  );
+     int i;
+     // set up linked lists at each depth
+     // stack2 is start, stack is next
+     int greatestDepth = -1;
+     for (i = 0; i < numberRows_; i++) {
+          double value = region2[i];
+          if (value) {
+               region2[i] = 0.0;
+               region[i] = value;
+               regionIndex[numberNonZero++] = i;
+               int j = i;
+               int iDepth = depth_[j];
+               if (iDepth > greatestDepth)
+                    greatestDepth = iDepth;
+               // and back until marked
+               while (!mark_[j]) {
+                    int iNext = stack2_[iDepth];
+                    stack2_[iDepth] = j;
+                    stack_[j] = iNext;
+                    mark_[j] = 1;
+                    iDepth--;
+                    j = parent_[j];
+               }
+          }
+     }
+     numberNonZero = 0;
+     for (; greatestDepth >= 0; greatestDepth--) {
+          int iPivot = stack2_[greatestDepth];
+          stack2_[greatestDepth] = -1;
+          while (iPivot >= 0) {
+               mark_[iPivot] = 0;
+               double pivotValue = region[iPivot];
+               if (pivotValue) {
+                    // put back now ?
+                    int iBack = permuteBack_[iPivot];
+                    numberNonZero++;
+                    int otherRow = parent_[iPivot];
+                    region2[iBack] = pivotValue * sign_[iPivot];
+                    region[iPivot] = 0.0;
+                    region[otherRow] += pivotValue;
+               }
+               iPivot = stack_[iPivot];
+          }
+     }
+     region[numberRows_] = 0.0;
+     return numberNonZero;
+}
+/* Updates one column transpose (BTRAN)
+   For large problems you should ALWAYS know where the nonzeros
+   are, so please try and migrate to previous method after you
+   have got code working using this simple method - thank you!
+   (the only exception is if you know input is dense e.g. dense objective)
+   returns number of nonzeros */
+int
+ClpNetworkBasis::updateColumnTranspose (  CoinIndexedVector * regionSparse,
+          double region2[] ) const
+{
+     // permute in after copying
+     // so will end up in right place
+     double *region = regionSparse->denseVector (  );
+     int *regionIndex = regionSparse->getIndices (  );
+     int i;
+     int numberNonZero = 0;
+     CoinMemcpyN(region2, numberRows_, region);
+     for (i = 0; i < numberRows_; i++) {
+          double value = region[i];
+          if (value) {
+               int k = permute_[i];
+               region[i] = 0.0;
+               region2[k] = value;
+               regionIndex[numberNonZero++] = k;
+               mark_[k] = 1;
+          }
+     }
+     // copy back
+     // set up linked lists at each depth
+     // stack2 is start, stack is next
+     int greatestDepth = -1;
+     int smallestDepth = numberRows_;
+     for (i = 0; i < numberNonZero; i++) {
+          int j = regionIndex[i];
+          // add in
+          int iDepth = depth_[j];
+          smallestDepth = CoinMin(iDepth, smallestDepth) ;
+          greatestDepth = CoinMax(iDepth, greatestDepth) ;
+          int jNext = stack2_[iDepth];
+          stack2_[iDepth] = j;
+          stack_[j] = jNext;
+          // and put all descendants on list
+          int iChild = descendant_[j];
+          while (iChild >= 0) {
+               if (!mark_[iChild]) {
+                    regionIndex[numberNonZero++] = iChild;
+                    mark_[iChild] = 1;
+               }
+               iChild = rightSibling_[iChild];
+          }
+     }
+     numberNonZero = 0;
+     region2[numberRows_] = 0.0;
+     int iDepth;
+     for (iDepth = smallestDepth; iDepth <= greatestDepth; iDepth++) {
+          int iPivot = stack2_[iDepth];
+          stack2_[iDepth] = -1;
+          while (iPivot >= 0) {
+               mark_[iPivot] = 0;
+               double pivotValue = region2[iPivot];
+               int otherRow = parent_[iPivot];
+               double otherValue = region2[otherRow];
+               pivotValue = sign_[iPivot] * pivotValue + otherValue;
+               region2[iPivot] = pivotValue;
+               if (pivotValue)
+                    numberNonZero++;
+               iPivot = stack_[iPivot];
+          }
+     }
+     return numberNonZero;
+}
+/* Updates one column (BTRAN) from region2 */
+int
+ClpNetworkBasis::updateColumnTranspose (  CoinIndexedVector * regionSparse,
+          CoinIndexedVector * regionSparse2) const
+{
+     // permute in - presume small number so copy back
+     // so will end up in right place
+     regionSparse->clear (  );
+     double *region = regionSparse->denseVector (  );
+     double *region2 = regionSparse2->denseVector (  );
+     int *regionIndex2 = regionSparse2->getIndices (  );
+     int numberNonZero2 = regionSparse2->getNumElements (  );
+     int *regionIndex = regionSparse->getIndices (  );
+     int i;
+     int numberNonZero = 0;
+     bool packed = regionSparse2->packedMode();
+     if (packed) {
+          for (i = 0; i < numberNonZero2; i++) {
+               int k = regionIndex2[i];
+               int j = permute_[k];
+               double value = region2[i];
+               region2[i] = 0.0;
+               region[j] = value;
+               mark_[j] = 1;
+               regionIndex[numberNonZero++] = j;
+          }
+          // set up linked lists at each depth
+          // stack2 is start, stack is next
+          int greatestDepth = -1;
+          int smallestDepth = numberRows_;
+          //mark_[numberRows_]=1;
+          for (i = 0; i < numberNonZero2; i++) {
+               int j = regionIndex[i];
+               regionIndex2[i] = j;
+               // add in
+               int iDepth = depth_[j];
+               smallestDepth = CoinMin(iDepth, smallestDepth) ;
+               greatestDepth = CoinMax(iDepth, greatestDepth) ;
+               int jNext = stack2_[iDepth];
+               stack2_[iDepth] = j;
+               stack_[j] = jNext;
+               // and put all descendants on list
+               int iChild = descendant_[j];
+               while (iChild >= 0) {
+                    if (!mark_[iChild]) {
+                         regionIndex2[numberNonZero++] = iChild;
+                         mark_[iChild] = 1;
+                    }
+                    iChild = rightSibling_[iChild];
+               }
+          }
+          for (; i < numberNonZero; i++) {
+               int j = regionIndex2[i];
+               // add in
+               int iDepth = depth_[j];
+               smallestDepth = CoinMin(iDepth, smallestDepth) ;
+               greatestDepth = CoinMax(iDepth, greatestDepth) ;
+               int jNext = stack2_[iDepth];
+               stack2_[iDepth] = j;
+               stack_[j] = jNext;
+               // and put all descendants on list
+               int iChild = descendant_[j];
+               while (iChild >= 0) {
+                    if (!mark_[iChild]) {
+                         regionIndex2[numberNonZero++] = iChild;
+                         mark_[iChild] = 1;
+                    }
+                    iChild = rightSibling_[iChild];
+               }
+          }
+          numberNonZero2 = 0;
+          region[numberRows_] = 0.0;
+          int iDepth;
+          for (iDepth = smallestDepth; iDepth <= greatestDepth; iDepth++) {
+               int iPivot = stack2_[iDepth];
+               stack2_[iDepth] = -1;
+               while (iPivot >= 0) {
+                    mark_[iPivot] = 0;
+                    double pivotValue = region[iPivot];
+                    int otherRow = parent_[iPivot];
+                    double otherValue = region[otherRow];
+                    pivotValue = sign_[iPivot] * pivotValue + otherValue;
+                    region[iPivot] = pivotValue;
+                    if (pivotValue) {
+                         region2[numberNonZero2] = pivotValue;
+                         regionIndex2[numberNonZero2++] = iPivot;
+                    }
+                    iPivot = stack_[iPivot];
+               }
+          }
+          // zero out
+          for (i = 0; i < numberNonZero2; i++) {
+               int k = regionIndex2[i];
+               region[k] = 0.0;
+          }
+     } else {
+          for (i = 0; i < numberNonZero2; i++) {
+               int k = regionIndex2[i];
+               int j = permute_[k];
+               double value = region2[k];
+               region2[k] = 0.0;
+               region[j] = value;
+               mark_[j] = 1;
+               regionIndex[numberNonZero++] = j;
+          }
+          // copy back
+          // set up linked lists at each depth
+          // stack2 is start, stack is next
+          int greatestDepth = -1;
+          int smallestDepth = numberRows_;
+          //mark_[numberRows_]=1;
+          for (i = 0; i < numberNonZero2; i++) {
+               int j = regionIndex[i];
+               double value = region[j];
+               region[j] = 0.0;
+               region2[j] = value;
+               regionIndex2[i] = j;
+               // add in
+               int iDepth = depth_[j];
+               smallestDepth = CoinMin(iDepth, smallestDepth) ;
+               greatestDepth = CoinMax(iDepth, greatestDepth) ;
+               int jNext = stack2_[iDepth];
+               stack2_[iDepth] = j;
+               stack_[j] = jNext;
+               // and put all descendants on list
+               int iChild = descendant_[j];
+               while (iChild >= 0) {
+                    if (!mark_[iChild]) {
+                         regionIndex2[numberNonZero++] = iChild;
+                         mark_[iChild] = 1;
+                    }
+                    iChild = rightSibling_[iChild];
+               }
+          }
+          for (; i < numberNonZero; i++) {
+               int j = regionIndex2[i];
+               // add in
+               int iDepth = depth_[j];
+               smallestDepth = CoinMin(iDepth, smallestDepth) ;
+               greatestDepth = CoinMax(iDepth, greatestDepth) ;
+               int jNext = stack2_[iDepth];
+               stack2_[iDepth] = j;
+               stack_[j] = jNext;
+               // and put all descendants on list
+               int iChild = descendant_[j];
+               while (iChild >= 0) {
+                    if (!mark_[iChild]) {
+                         regionIndex2[numberNonZero++] = iChild;
+                         mark_[iChild] = 1;
+                    }
+                    iChild = rightSibling_[iChild];
+               }
+          }
+          numberNonZero2 = 0;
+          region2[numberRows_] = 0.0;
+          int iDepth;
+          for (iDepth = smallestDepth; iDepth <= greatestDepth; iDepth++) {
+               int iPivot = stack2_[iDepth];
+               stack2_[iDepth] = -1;
+               while (iPivot >= 0) {
+                    mark_[iPivot] = 0;
+                    double pivotValue = region2[iPivot];
+                    int otherRow = parent_[iPivot];
+                    double otherValue = region2[otherRow];
+                    pivotValue = sign_[iPivot] * pivotValue + otherValue;
+                    region2[iPivot] = pivotValue;
+                    if (pivotValue)
+                         regionIndex2[numberNonZero2++] = iPivot;
+                    iPivot = stack_[iPivot];
+               }
+          }
+     }
+     regionSparse2->setNumElements(numberNonZero2);
+#ifdef FULL_DEBUG
+     {
+          int i;
+          for (i = 0; i < numberRows_; i++) {
+               assert(!mark_[i]);
+               assert (stack2_[i] == -1);
+          }
+     }
+#endif
+     return numberNonZero2;
+}
diff --git a/cbits/coin/ClpNetworkBasis.hpp b/cbits/coin/ClpNetworkBasis.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpNetworkBasis.hpp
@@ -0,0 +1,146 @@
+/* $Id: ClpNetworkBasis.hpp 1722 2011-04-17 09:58:37Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef ClpNetworkBasis_H
+#define ClpNetworkBasis_H
+
+class ClpMatrixBase;
+class CoinIndexedVector;
+class ClpSimplex;
+#include "CoinTypes.hpp"
+#ifndef COIN_FAST_CODE
+#define COIN_FAST_CODE
+#endif
+
+/** This deals with Factorization and Updates for network structures
+ */
+
+
+class ClpNetworkBasis {
+
+public:
+
+     /**@name Constructors and destructor and copy */
+     //@{
+     /// Default constructor
+     ClpNetworkBasis (  );
+     /// Constructor from CoinFactorization
+     ClpNetworkBasis(const ClpSimplex * model,
+                     int numberRows, const CoinFactorizationDouble * pivotRegion,
+                     const int * permuteBack, const CoinBigIndex * startColumn,
+                     const int * numberInColumn,
+                     const int * indexRow, const CoinFactorizationDouble * element);
+     /// Copy constructor
+     ClpNetworkBasis ( const ClpNetworkBasis &other);
+
+     /// Destructor
+     ~ClpNetworkBasis (  );
+     /// = copy
+     ClpNetworkBasis & operator = ( const ClpNetworkBasis & other );
+     //@}
+
+     /**@name Do factorization */
+     //@{
+     /** When part of LP - given by basic variables.
+     Actually does factorization.
+     Arrays passed in have non negative value to say basic.
+     If status is okay, basic variables have pivot row - this is only needed
+     if increasingRows_ >1.
+     If status is singular, then basic variables have pivot row
+     and ones thrown out have -1
+     returns 0 -okay, -1 singular, -2 too many in basis */
+     int factorize ( const ClpMatrixBase * matrix,
+                     int rowIsBasic[], int columnIsBasic[]);
+     //@}
+
+     /**@name rank one updates which do exist */
+     //@{
+
+     /** Replaces one Column to basis,
+      returns 0=OK, 1=Probably OK, 2=singular!!
+     */
+     int replaceColumn ( CoinIndexedVector * column,
+                         int pivotRow);
+     //@}
+
+     /**@name various uses of factorization (return code number elements)
+      which user may want to know about */
+     //@{
+     /** Updates one column (FTRAN) from region,
+         Returns pivot value if "pivotRow" >=0
+     */
+     double updateColumn ( CoinIndexedVector * regionSparse,
+                           CoinIndexedVector * regionSparse2,
+                           int pivotRow);
+     /** Updates one column (FTRAN) to/from array
+         ** For large problems you should ALWAYS know where the nonzeros
+         are, so please try and migrate to previous method after you
+         have got code working using this simple method - thank you!
+         (the only exception is if you know input is dense e.g. rhs) */
+     int updateColumn (  CoinIndexedVector * regionSparse,
+                         double array[] ) const;
+     /** Updates one column transpose (BTRAN)
+         ** For large problems you should ALWAYS know where the nonzeros
+         are, so please try and migrate to previous method after you
+         have got code working using this simple method - thank you!
+         (the only exception is if you know input is dense e.g. dense objective)
+         returns number of nonzeros */
+     int updateColumnTranspose (  CoinIndexedVector * regionSparse,
+                                  double array[] ) const;
+     /** Updates one column (BTRAN) from region2 */
+     int updateColumnTranspose (  CoinIndexedVector * regionSparse,
+                                  CoinIndexedVector * regionSparse2) const;
+     //@}
+////////////////// data //////////////////
+private:
+
+     // checks looks okay
+     void check();
+     // prints data
+     void print();
+     /**@name data */
+     //@{
+#ifndef COIN_FAST_CODE
+     /// Whether slack value is  +1 or -1
+     double slackValue_;
+#endif
+     /// Number of Rows in factorization
+     int numberRows_;
+     /// Number of Columns in factorization
+     int numberColumns_;
+     /// model
+     const ClpSimplex * model_;
+     /// Parent for each column
+     int * parent_;
+     /// Descendant
+     int * descendant_;
+     /// Pivot row
+     int * pivot_;
+     /// Right sibling
+     int * rightSibling_;
+     /// Left sibling
+     int * leftSibling_;
+     /// Sign of pivot
+     double * sign_;
+     /// Stack
+     int * stack_;
+     /// Permute into array
+     int * permute_;
+     /// Permute back array
+     int * permuteBack_;
+     /// Second stack
+     int * stack2_;
+     /// Depth
+     int * depth_;
+     /// To mark rows
+     char * mark_;
+     //@}
+};
+#endif
diff --git a/cbits/coin/ClpNetworkMatrix.cpp b/cbits/coin/ClpNetworkMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpNetworkMatrix.cpp
@@ -0,0 +1,1261 @@
+/* $Id: ClpNetworkMatrix.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include <cstdio>
+
+#include "CoinPragma.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpFactorization.hpp"
+// at end to get min/max!
+#include "ClpNetworkMatrix.hpp"
+#include "ClpPlusMinusOneMatrix.hpp"
+#include "ClpMessage.hpp"
+#include <iostream>
+#include <cassert>
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpNetworkMatrix::ClpNetworkMatrix ()
+     : ClpMatrixBase()
+{
+     setType(11);
+     matrix_ = NULL;
+     lengths_ = NULL;
+     indices_ = NULL;
+     numberRows_ = 0;
+     numberColumns_ = 0;
+     trueNetwork_ = false;
+}
+
+/* Constructor from two arrays */
+ClpNetworkMatrix::ClpNetworkMatrix(int numberColumns, const int * head,
+                                   const int * tail)
+     : ClpMatrixBase()
+{
+     setType(11);
+     matrix_ = NULL;
+     lengths_ = NULL;
+     indices_ = new int[2*numberColumns];;
+     numberRows_ = -1;
+     numberColumns_ = numberColumns;
+     trueNetwork_ = true;
+     int iColumn;
+     CoinBigIndex j = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+          int iRow = head[iColumn];
+          numberRows_ = CoinMax(numberRows_, iRow);
+          indices_[j] = iRow;
+          iRow = tail[iColumn];
+          numberRows_ = CoinMax(numberRows_, iRow);
+          indices_[j+1] = iRow;
+     }
+     numberRows_++;
+}
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpNetworkMatrix::ClpNetworkMatrix (const ClpNetworkMatrix & rhs)
+     : ClpMatrixBase(rhs)
+{
+     matrix_ = NULL;
+     lengths_ = NULL;
+     indices_ = NULL;
+     numberRows_ = rhs.numberRows_;
+     numberColumns_ = rhs.numberColumns_;
+     trueNetwork_ = rhs.trueNetwork_;
+     if (numberColumns_) {
+          indices_ = new int [ 2*numberColumns_];
+          CoinMemcpyN(rhs.indices_, 2 * numberColumns_, indices_);
+     }
+     int numberRows = getNumRows();
+     if (rhs.rhsOffset_ && numberRows) {
+          rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows);
+     } else {
+          rhsOffset_ = NULL;
+     }
+}
+
+ClpNetworkMatrix::ClpNetworkMatrix (const CoinPackedMatrix & rhs)
+     : ClpMatrixBase()
+{
+     setType(11);
+     matrix_ = NULL;
+     lengths_ = NULL;
+     indices_ = NULL;
+     int iColumn;
+     assert (rhs.isColOrdered());
+     // get matrix data pointers
+     const int * row = rhs.getIndices();
+     const CoinBigIndex * columnStart = rhs.getVectorStarts();
+     const int * columnLength = rhs.getVectorLengths();
+     const double * elementByColumn = rhs.getElements();
+     numberColumns_ = rhs.getNumCols();
+     int goodNetwork = 1;
+     numberRows_ = -1;
+     indices_ = new int[2*numberColumns_];
+     CoinBigIndex j = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+          CoinBigIndex k = columnStart[iColumn];
+          int iRow;
+          switch (columnLength[iColumn]) {
+          case 0:
+               goodNetwork = -1; // not classic network
+               indices_[j] = -1;
+               indices_[j+1] = -1;
+               break;
+
+          case 1:
+               goodNetwork = -1; // not classic network
+               if (fabs(elementByColumn[k] - 1.0) < 1.0e-10) {
+                    indices_[j] = -1;
+                    iRow = row[k];
+                    numberRows_ = CoinMax(numberRows_, iRow);
+                    indices_[j+1] = iRow;
+               } else if (fabs(elementByColumn[k] + 1.0) < 1.0e-10) {
+                    indices_[j+1] = -1;
+                    iRow = row[k];
+                    numberRows_ = CoinMax(numberRows_, iRow);
+                    indices_[j] = iRow;
+               } else {
+                    goodNetwork = 0; // not a network
+               }
+               break;
+
+          case 2:
+               if (fabs(elementByColumn[k] - 1.0) < 1.0e-10) {
+                    if (fabs(elementByColumn[k+1] + 1.0) < 1.0e-10) {
+                         iRow = row[k];
+                         numberRows_ = CoinMax(numberRows_, iRow);
+                         indices_[j+1] = iRow;
+                         iRow = row[k+1];
+                         numberRows_ = CoinMax(numberRows_, iRow);
+                         indices_[j] = iRow;
+                    } else {
+                         goodNetwork = 0; // not a network
+                    }
+               } else if (fabs(elementByColumn[k] + 1.0) < 1.0e-10) {
+                    if (fabs(elementByColumn[k+1] - 1.0) < 1.0e-10) {
+                         iRow = row[k];
+                         numberRows_ = CoinMax(numberRows_, iRow);
+                         indices_[j] = iRow;
+                         iRow = row[k+1];
+                         numberRows_ = CoinMax(numberRows_, iRow);
+                         indices_[j+1] = iRow;
+                    } else {
+                         goodNetwork = 0; // not a network
+                    }
+               } else {
+                    goodNetwork = 0; // not a network
+               }
+               break;
+
+          default:
+               goodNetwork = 0; // not a network
+               break;
+          }
+          if (!goodNetwork)
+               break;
+     }
+     if (!goodNetwork) {
+          delete [] indices_;
+          // put in message
+          printf("Not a network - can test if indices_ null\n");
+          indices_ = NULL;
+          numberRows_ = 0;
+          numberColumns_ = 0;
+     } else {
+          numberRows_ ++; //  correct
+          trueNetwork_ = goodNetwork > 0;
+     }
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpNetworkMatrix::~ClpNetworkMatrix ()
+{
+     delete matrix_;
+     delete [] lengths_;
+     delete [] indices_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpNetworkMatrix &
+ClpNetworkMatrix::operator=(const ClpNetworkMatrix& rhs)
+{
+     if (this != &rhs) {
+          ClpMatrixBase::operator=(rhs);
+          delete matrix_;
+          delete [] lengths_;
+          delete [] indices_;
+          matrix_ = NULL;
+          lengths_ = NULL;
+          indices_ = NULL;
+          numberRows_ = rhs.numberRows_;
+          numberColumns_ = rhs.numberColumns_;
+          trueNetwork_ = rhs.trueNetwork_;
+          if (numberColumns_) {
+               indices_ = new int [ 2*numberColumns_];
+               CoinMemcpyN(rhs.indices_, 2 * numberColumns_, indices_);
+          }
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpMatrixBase * ClpNetworkMatrix::clone() const
+{
+     return new ClpNetworkMatrix(*this);
+}
+
+/* Returns a new matrix in reverse order without gaps */
+ClpMatrixBase *
+ClpNetworkMatrix::reverseOrderedCopy() const
+{
+     // count number in each row
+     CoinBigIndex * tempP = new CoinBigIndex [numberRows_];
+     CoinBigIndex * tempN = new CoinBigIndex [numberRows_];
+     memset(tempP, 0, numberRows_ * sizeof(CoinBigIndex));
+     memset(tempN, 0, numberRows_ * sizeof(CoinBigIndex));
+     CoinBigIndex j = 0;
+     int i;
+     for (i = 0; i < numberColumns_; i++, j += 2) {
+          int iRow = indices_[j];
+          tempN[iRow]++;
+          iRow = indices_[j+1];
+          tempP[iRow]++;
+     }
+     int * newIndices = new int [2*numberColumns_];
+     CoinBigIndex * newP = new CoinBigIndex [numberRows_+1];
+     CoinBigIndex * newN = new CoinBigIndex[numberRows_];
+     int iRow;
+     j = 0;
+     // do starts
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          newP[iRow] = j;
+          j += tempP[iRow];
+          tempP[iRow] = newP[iRow];
+          newN[iRow] = j;
+          j += tempN[iRow];
+          tempN[iRow] = newN[iRow];
+     }
+     newP[numberRows_] = j;
+     j = 0;
+     for (i = 0; i < numberColumns_; i++, j += 2) {
+          int iRow = indices_[j];
+          CoinBigIndex put = tempN[iRow];
+          newIndices[put++] = i;
+          tempN[iRow] = put;
+          iRow = indices_[j+1];
+          put = tempP[iRow];
+          newIndices[put++] = i;
+          tempP[iRow] = put;
+     }
+     delete [] tempP;
+     delete [] tempN;
+     ClpPlusMinusOneMatrix * newCopy = new ClpPlusMinusOneMatrix();
+     newCopy->passInCopy(numberRows_, numberColumns_,
+                         false,  newIndices, newP, newN);
+     return newCopy;
+}
+//unscaled versions
+void
+ClpNetworkMatrix::times(double scalar,
+                        const double * x, double * y) const
+{
+     int iColumn;
+     CoinBigIndex j = 0;
+     if (trueNetwork_) {
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+               double value = scalar * x[iColumn];
+               if (value) {
+                    int iRowM = indices_[j];
+                    int iRowP = indices_[j+1];
+                    y[iRowM] -= value;
+                    y[iRowP] += value;
+               }
+          }
+     } else {
+          // skip negative rows
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+               double value = scalar * x[iColumn];
+               if (value) {
+                    int iRowM = indices_[j];
+                    int iRowP = indices_[j+1];
+                    if (iRowM >= 0)
+                         y[iRowM] -= value;
+                    if (iRowP >= 0)
+                         y[iRowP] += value;
+               }
+          }
+     }
+}
+void
+ClpNetworkMatrix::transposeTimes(double scalar,
+                                 const double * x, double * y) const
+{
+     int iColumn;
+     CoinBigIndex j = 0;
+     if (trueNetwork_) {
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+               double value = y[iColumn];
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               value -= scalar * x[iRowM];
+               value += scalar * x[iRowP];
+               y[iColumn] = value;
+          }
+     } else {
+          // skip negative rows
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+               double value = y[iColumn];
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               if (iRowM >= 0)
+                    value -= scalar * x[iRowM];
+               if (iRowP >= 0)
+                    value += scalar * x[iRowP];
+               y[iColumn] = value;
+          }
+     }
+}
+void
+ClpNetworkMatrix::times(double scalar,
+                        const double * x, double * y,
+                        const double * /*rowScale*/,
+                        const double * /*columnScale*/) const
+{
+     // we know it is not scaled
+     times(scalar, x, y);
+}
+void
+ClpNetworkMatrix::transposeTimes( double scalar,
+                                  const double * x, double * y,
+                                  const double * /*rowScale*/,
+                                  const double * /*columnScale*/,
+                                  double * /*spare*/) const
+{
+     // we know it is not scaled
+     transposeTimes(scalar, x, y);
+}
+/* Return <code>x * A + y</code> in <code>z</code>.
+	Squashes small elements and knows about ClpSimplex */
+void
+ClpNetworkMatrix::transposeTimes(const ClpSimplex * model, double scalar,
+                                 const CoinIndexedVector * rowArray,
+                                 CoinIndexedVector * y,
+                                 CoinIndexedVector * columnArray) const
+{
+     // we know it is not scaled
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     int numberNonZero = 0;
+     int * index = columnArray->getIndices();
+     double * array = columnArray->denseVector();
+     int numberInRowArray = rowArray->getNumElements();
+     // maybe I need one in OsiSimplex
+     double zeroTolerance = model->zeroTolerance();
+     int numberRows = model->numberRows();
+#ifndef NO_RTTI
+     ClpPlusMinusOneMatrix* rowCopy =
+          dynamic_cast< ClpPlusMinusOneMatrix*>(model->rowCopy());
+#else
+     ClpPlusMinusOneMatrix* rowCopy =
+          static_cast< ClpPlusMinusOneMatrix*>(model->rowCopy());
+#endif
+     bool packed = rowArray->packedMode();
+     double factor = 0.3;
+     // We may not want to do by row if there may be cache problems
+     int numberColumns = model->numberColumns();
+     // It would be nice to find L2 cache size - for moment 512K
+     // Be slightly optimistic
+     if (numberColumns * sizeof(double) > 1000000) {
+          if (numberRows * 10 < numberColumns)
+               factor = 0.1;
+          else if (numberRows * 4 < numberColumns)
+               factor = 0.15;
+          else if (numberRows * 2 < numberColumns)
+               factor = 0.2;
+          //if (model->numberIterations()%50==0)
+          //printf("%d nonzero\n",numberInRowArray);
+     }
+     if (numberInRowArray > factor * numberRows || !rowCopy) {
+          // do by column
+          int iColumn;
+          assert (!y->getNumElements());
+          CoinBigIndex j = 0;
+          if (packed) {
+               // need to expand pi into y
+               assert(y->capacity() >= numberRows);
+               double * piOld = pi;
+               pi = y->denseVector();
+               const int * whichRow = rowArray->getIndices();
+               int i;
+               // modify pi so can collapse to one loop
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = scalar * piOld[i];
+               }
+               if (trueNetwork_) {
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+                         double value = 0.0;
+                         int iRowM = indices_[j];
+                         int iRowP = indices_[j+1];
+                         value -= pi[iRowM];
+                         value += pi[iRowP];
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               } else {
+                    // skip negative rows
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+                         double value = 0.0;
+                         int iRowM = indices_[j];
+                         int iRowP = indices_[j+1];
+                         if (iRowM >= 0)
+                              value -= pi[iRowM];
+                         if (iRowP >= 0)
+                              value += pi[iRowP];
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = 0.0;
+               }
+          } else {
+               if (trueNetwork_) {
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+                         double value = 0.0;
+                         int iRowM = indices_[j];
+                         int iRowP = indices_[j+1];
+                         value -= scalar * pi[iRowM];
+                         value += scalar * pi[iRowP];
+                         if (fabs(value) > zeroTolerance) {
+                              index[numberNonZero++] = iColumn;
+                              array[iColumn] = value;
+                         }
+                    }
+               } else {
+                    // skip negative rows
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++, j += 2) {
+                         double value = 0.0;
+                         int iRowM = indices_[j];
+                         int iRowP = indices_[j+1];
+                         if (iRowM >= 0)
+                              value -= scalar * pi[iRowM];
+                         if (iRowP >= 0)
+                              value += scalar * pi[iRowP];
+                         if (fabs(value) > zeroTolerance) {
+                              index[numberNonZero++] = iColumn;
+                              array[iColumn] = value;
+                         }
+                    }
+               }
+          }
+          columnArray->setNumElements(numberNonZero);
+     } else {
+          // do by row
+          rowCopy->transposeTimesByRow(model, scalar, rowArray, y, columnArray);
+     }
+}
+/* Return <code>x *A in <code>z</code> but
+   just for indices in y. */
+void
+ClpNetworkMatrix::subsetTransposeTimes(const ClpSimplex * /*model*/,
+                                       const CoinIndexedVector * rowArray,
+                                       const CoinIndexedVector * y,
+                                       CoinIndexedVector * columnArray) const
+{
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     double * array = columnArray->denseVector();
+     int jColumn;
+     int numberToDo = y->getNumElements();
+     const int * which = y->getIndices();
+     assert (!rowArray->packedMode());
+     columnArray->setPacked();
+     if (trueNetwork_) {
+          for (jColumn = 0; jColumn < numberToDo; jColumn++) {
+               int iColumn = which[jColumn];
+               double value = 0.0;
+               CoinBigIndex j = iColumn << 1;
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               value -= pi[iRowM];
+               value += pi[iRowP];
+               array[jColumn] = value;
+          }
+     } else {
+          // skip negative rows
+          for (jColumn = 0; jColumn < numberToDo; jColumn++) {
+               int iColumn = which[jColumn];
+               double value = 0.0;
+               CoinBigIndex j = iColumn << 1;
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               if (iRowM >= 0)
+                    value -= pi[iRowM];
+               if (iRowP >= 0)
+                    value += pi[iRowP];
+               array[jColumn] = value;
+          }
+     }
+}
+/// returns number of elements in column part of basis,
+CoinBigIndex
+ClpNetworkMatrix::countBasis( const int * whichColumn,
+                              int & numberColumnBasic)
+{
+     int i;
+     CoinBigIndex numberElements = 0;
+     if (trueNetwork_) {
+          numberElements = 2 * numberColumnBasic;
+     } else {
+          for (i = 0; i < numberColumnBasic; i++) {
+               int iColumn = whichColumn[i];
+               CoinBigIndex j = iColumn << 1;
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               if (iRowM >= 0)
+                    numberElements ++;
+               if (iRowP >= 0)
+                    numberElements ++;
+          }
+     }
+     return numberElements;
+}
+void
+ClpNetworkMatrix::fillBasis(ClpSimplex * /*model*/,
+                            const int * whichColumn,
+                            int & numberColumnBasic,
+                            int * indexRowU, int * start,
+                            int * rowCount, int * columnCount,
+                            CoinFactorizationDouble * elementU)
+{
+     int i;
+     CoinBigIndex numberElements = start[0];
+     if (trueNetwork_) {
+          for (i = 0; i < numberColumnBasic; i++) {
+               int iColumn = whichColumn[i];
+               CoinBigIndex j = iColumn << 1;
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               indexRowU[numberElements] = iRowM;
+               rowCount[iRowM]++;
+               elementU[numberElements] = -1.0;
+               indexRowU[numberElements+1] = iRowP;
+               rowCount[iRowP]++;
+               elementU[numberElements+1] = 1.0;
+               numberElements += 2;
+               start[i+1] = numberElements;
+               columnCount[i] = 2;
+          }
+     } else {
+          for (i = 0; i < numberColumnBasic; i++) {
+               int iColumn = whichColumn[i];
+               CoinBigIndex j = iColumn << 1;
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               if (iRowM >= 0) {
+                    indexRowU[numberElements] = iRowM;
+                    rowCount[iRowM]++;
+                    elementU[numberElements++] = -1.0;
+               }
+               if (iRowP >= 0) {
+                    indexRowU[numberElements] = iRowP;
+                    rowCount[iRowP]++;
+                    elementU[numberElements++] = 1.0;
+               }
+               start[i+1] = numberElements;
+               columnCount[i] = numberElements - start[i];
+          }
+     }
+}
+/* Unpacks a column into an CoinIndexedvector
+ */
+void
+ClpNetworkMatrix::unpack(const ClpSimplex * /*model*/, CoinIndexedVector * rowArray,
+                         int iColumn) const
+{
+     CoinBigIndex j = iColumn << 1;
+     int iRowM = indices_[j];
+     int iRowP = indices_[j+1];
+     if (iRowM >= 0)
+          rowArray->add(iRowM, -1.0);
+     if (iRowP >= 0)
+          rowArray->add(iRowP, 1.0);
+}
+/* Unpacks a column into an CoinIndexedvector
+** in packed foramt
+Note that model is NOT const.  Bounds and objective could
+be modified if doing column generation (just for this variable) */
+void
+ClpNetworkMatrix::unpackPacked(ClpSimplex * /*model*/,
+                               CoinIndexedVector * rowArray,
+                               int iColumn) const
+{
+     int * index = rowArray->getIndices();
+     double * array = rowArray->denseVector();
+     int number = 0;
+     CoinBigIndex j = iColumn << 1;
+     int iRowM = indices_[j];
+     int iRowP = indices_[j+1];
+     if (iRowM >= 0) {
+          array[number] = -1.0;
+          index[number++] = iRowM;
+     }
+     if (iRowP >= 0) {
+          array[number] = 1.0;
+          index[number++] = iRowP;
+     }
+     rowArray->setNumElements(number);
+     rowArray->setPackedMode(true);
+}
+/* Adds multiple of a column into an CoinIndexedvector
+      You can use quickAdd to add to vector */
+void
+ClpNetworkMatrix::add(const ClpSimplex * /*model*/, CoinIndexedVector * rowArray,
+                      int iColumn, double multiplier) const
+{
+     CoinBigIndex j = iColumn << 1;
+     int iRowM = indices_[j];
+     int iRowP = indices_[j+1];
+     if (iRowM >= 0)
+          rowArray->quickAdd(iRowM, -multiplier);
+     if (iRowP >= 0)
+          rowArray->quickAdd(iRowP, multiplier);
+}
+/* Adds multiple of a column into an array */
+void
+ClpNetworkMatrix::add(const ClpSimplex * /*model*/, double * array,
+                      int iColumn, double multiplier) const
+{
+     CoinBigIndex j = iColumn << 1;
+     int iRowM = indices_[j];
+     int iRowP = indices_[j+1];
+     if (iRowM >= 0)
+          array[iRowM] -= multiplier;
+     if (iRowP >= 0)
+          array[iRowP] += multiplier;
+}
+
+// Return a complete CoinPackedMatrix
+CoinPackedMatrix *
+ClpNetworkMatrix::getPackedMatrix() const
+{
+     if (!matrix_) {
+          assert (trueNetwork_); // fix later
+          int numberElements = 2 * numberColumns_;
+          double * elements = new double [numberElements];
+          CoinBigIndex i;
+          for (i = 0; i < 2 * numberColumns_; i += 2) {
+               elements[i] = -1.0;
+               elements[i+1] = 1.0;
+          }
+          CoinBigIndex * starts = new CoinBigIndex [numberColumns_+1];
+          for (i = 0; i < numberColumns_ + 1; i++) {
+               starts[i] = 2 * i;
+          }
+          // use assignMatrix to save space
+          delete [] lengths_;
+          lengths_ = NULL;
+          matrix_ = new CoinPackedMatrix();
+          int * indices = CoinCopyOfArray(indices_, 2 * numberColumns_);
+          matrix_->assignMatrix(true, numberRows_, numberColumns_,
+                                getNumElements(),
+                                elements, indices,
+                                starts, lengths_);
+          assert(!elements);
+          assert(!starts);
+          assert (!indices);
+          assert (!lengths_);
+     }
+     return matrix_;
+}
+/* A vector containing the elements in the packed matrix. Note that there
+   might be gaps in this list, entries that do not belong to any
+   major-dimension vector. To get the actual elements one should look at
+   this vector together with vectorStarts and vectorLengths. */
+const double *
+ClpNetworkMatrix::getElements() const
+{
+     if (!matrix_)
+          getPackedMatrix();
+     return matrix_->getElements();
+}
+
+const CoinBigIndex *
+ClpNetworkMatrix::getVectorStarts() const
+{
+     if (!matrix_)
+          getPackedMatrix();
+     return matrix_->getVectorStarts();
+}
+/* The lengths of the major-dimension vectors. */
+const int *
+ClpNetworkMatrix::getVectorLengths() const
+{
+     assert (trueNetwork_); // fix later
+     if (!lengths_) {
+          lengths_ = new int [numberColumns_];
+          int i;
+          for (i = 0; i < numberColumns_; i++) {
+               lengths_[i] = 2;
+          }
+     }
+     return lengths_;
+}
+/* Delete the columns whose indices are listed in <code>indDel</code>. */
+void ClpNetworkMatrix::deleteCols(const int numDel, const int * indDel)
+{
+     assert (trueNetwork_);
+     int iColumn;
+     int numberBad = 0;
+     // Use array to make sure we can have duplicates
+     char * which = new char[numberColumns_];
+     memset(which, 0, numberColumns_);
+     int nDuplicate = 0;
+     for (iColumn = 0; iColumn < numDel; iColumn++) {
+          int jColumn = indDel[iColumn];
+          if (jColumn < 0 || jColumn >= numberColumns_) {
+               numberBad++;
+          } else {
+               if (which[jColumn])
+                    nDuplicate++;
+               else
+                    which[jColumn] = 1;
+          }
+     }
+     if (numberBad)
+          throw CoinError("Indices out of range", "deleteCols", "ClpNetworkMatrix");
+     int newNumber = numberColumns_ - numDel + nDuplicate;
+     // Get rid of temporary arrays
+     delete [] lengths_;
+     lengths_ = NULL;
+     delete matrix_;
+     matrix_ = NULL;
+     int newSize = 2 * newNumber;
+     int * newIndices = new int [newSize];
+     newSize = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (!which[iColumn]) {
+               CoinBigIndex start;
+               CoinBigIndex i;
+               start = 2 * iColumn;
+               for (i = start; i < start + 2; i++)
+                    newIndices[newSize++] = indices_[i];
+          }
+     }
+     delete [] which;
+     delete [] indices_;
+     indices_ = newIndices;
+     numberColumns_ = newNumber;
+}
+/* Delete the rows whose indices are listed in <code>indDel</code>. */
+void ClpNetworkMatrix::deleteRows(const int numDel, const int * indDel)
+{
+     int iRow;
+     int numberBad = 0;
+     // Use array to make sure we can have duplicates
+     int * which = new int [numberRows_];
+     memset(which, 0, numberRows_ * sizeof(int));
+     for (iRow = 0; iRow < numDel; iRow++) {
+          int jRow = indDel[iRow];
+          if (jRow < 0 || jRow >= numberRows_) {
+               numberBad++;
+          } else {
+               which[jRow] = 1;
+          }
+     }
+     if (numberBad)
+          throw CoinError("Indices out of range", "deleteRows", "ClpNetworkMatrix");
+     // Only valid of all columns have 0 entries
+     int iColumn;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          CoinBigIndex start;
+          CoinBigIndex i;
+          start = 2 * iColumn;
+          for (i = start; i < start + 2; i++) {
+               int iRow = indices_[i];
+               if (which[iRow])
+                    numberBad++;
+          }
+     }
+     if (numberBad)
+          throw CoinError("Row has entries", "deleteRows", "ClpNetworkMatrix");
+     int newNumber = 0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          if (!which[iRow])
+               which[iRow] = newNumber++;
+          else
+               which[iRow] = -1;
+     }
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          CoinBigIndex start;
+          CoinBigIndex i;
+          start = 2 * iColumn;
+          for (i = start; i < start + 2; i++) {
+               int iRow = indices_[i];
+               indices_[i] = which[iRow];
+          }
+     }
+     delete [] which;
+     numberRows_ = newNumber;
+}
+/* Given positive integer weights for each row fills in sum of weights
+   for each column (and slack).
+   Returns weights vector
+*/
+CoinBigIndex *
+ClpNetworkMatrix::dubiousWeights(const ClpSimplex * model, int * inputWeights) const
+{
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     int number = numberRows + numberColumns;
+     CoinBigIndex * weights = new CoinBigIndex[number];
+     int i;
+     for (i = 0; i < numberColumns; i++) {
+          CoinBigIndex j = i << 1;
+          CoinBigIndex count = 0;
+          int iRowM = indices_[j];
+          int iRowP = indices_[j+1];
+          if (iRowM >= 0) {
+               count += inputWeights[iRowM];
+          }
+          if (iRowP >= 0) {
+               count += inputWeights[iRowP];
+          }
+          weights[i] = count;
+     }
+     for (i = 0; i < numberRows; i++) {
+          weights[i+numberColumns] = inputWeights[i];
+     }
+     return weights;
+}
+/* Returns largest and smallest elements of both signs.
+   Largest refers to largest absolute value.
+*/
+void
+ClpNetworkMatrix::rangeOfElements(double & smallestNegative, double & largestNegative,
+                                  double & smallestPositive, double & largestPositive)
+{
+     smallestNegative = -1.0;
+     largestNegative = -1.0;
+     smallestPositive = 1.0;
+     largestPositive = 1.0;
+}
+// Says whether it can do partial pricing
+bool
+ClpNetworkMatrix::canDoPartialPricing() const
+{
+     return true;
+}
+// Partial pricing
+void
+ClpNetworkMatrix::partialPricing(ClpSimplex * model, double startFraction, double endFraction,
+                                 int & bestSequence, int & numberWanted)
+{
+     numberWanted = currentWanted_;
+     int j;
+     int start = static_cast<int> (startFraction * numberColumns_);
+     int end = CoinMin(static_cast<int> (endFraction * numberColumns_ + 1), numberColumns_);
+     double tolerance = model->currentDualTolerance();
+     double * reducedCost = model->djRegion();
+     const double * duals = model->dualRowSolution();
+     const double * cost = model->costRegion();
+     double bestDj;
+     if (bestSequence >= 0)
+          bestDj = fabs(reducedCost[bestSequence]);
+     else
+          bestDj = tolerance;
+     int sequenceOut = model->sequenceOut();
+     int saveSequence = bestSequence;
+     if (!trueNetwork_) {
+          // Not true network
+          int iSequence;
+          for (iSequence = start; iSequence < end; iSequence++) {
+               if (iSequence != sequenceOut) {
+                    double value;
+                    int iRowM, iRowP;
+                    ClpSimplex::Status status = model->getStatus(iSequence);
+
+                    switch(status) {
+
+                    case ClpSimplex::basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case ClpSimplex::isFree:
+                    case ClpSimplex::superBasic:
+                         value = cost[iSequence];
+                         j = iSequence << 1;
+                         // skip negative rows
+                         iRowM = indices_[j];
+                         iRowP = indices_[j+1];
+                         if (iRowM >= 0)
+                              value += duals[iRowM];
+                         if (iRowP >= 0)
+                              value -= duals[iRowP];
+                         value = fabs(value);
+                         if (value > FREE_ACCEPT * tolerance) {
+                              numberWanted--;
+                              // we are going to bias towards free (but only if reasonable)
+                              value *= FREE_BIAS;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atUpperBound:
+                         value = cost[iSequence];
+                         j = iSequence << 1;
+                         // skip negative rows
+                         iRowM = indices_[j];
+                         iRowP = indices_[j+1];
+                         if (iRowM >= 0)
+                              value += duals[iRowM];
+                         if (iRowP >= 0)
+                              value -= duals[iRowP];
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atLowerBound:
+                         value = cost[iSequence];
+                         j = iSequence << 1;
+                         // skip negative rows
+                         iRowM = indices_[j];
+                         iRowP = indices_[j+1];
+                         if (iRowM >= 0)
+                              value += duals[iRowM];
+                         if (iRowP >= 0)
+                              value -= duals[iRowP];
+                         value = -value;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    }
+               }
+               if (!numberWanted)
+                    break;
+          }
+          if (bestSequence != saveSequence) {
+               // recompute dj
+               double value = cost[bestSequence];
+               j = bestSequence << 1;
+               // skip negative rows
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               if (iRowM >= 0)
+                    value += duals[iRowM];
+               if (iRowP >= 0)
+                    value -= duals[iRowP];
+               reducedCost[bestSequence] = value;
+               savedBestSequence_ = bestSequence;
+               savedBestDj_ = reducedCost[savedBestSequence_];
+          }
+     } else {
+          // true network
+          int iSequence;
+          for (iSequence = start; iSequence < end; iSequence++) {
+               if (iSequence != sequenceOut) {
+                    double value;
+                    int iRowM, iRowP;
+                    ClpSimplex::Status status = model->getStatus(iSequence);
+
+                    switch(status) {
+
+                    case ClpSimplex::basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case ClpSimplex::isFree:
+                    case ClpSimplex::superBasic:
+                         value = cost[iSequence];
+                         j = iSequence << 1;
+                         iRowM = indices_[j];
+                         iRowP = indices_[j+1];
+                         value += duals[iRowM];
+                         value -= duals[iRowP];
+                         value = fabs(value);
+                         if (value > FREE_ACCEPT * tolerance) {
+                              numberWanted--;
+                              // we are going to bias towards free (but only if reasonable)
+                              value *= FREE_BIAS;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atUpperBound:
+                         value = cost[iSequence];
+                         j = iSequence << 1;
+                         iRowM = indices_[j];
+                         iRowP = indices_[j+1];
+                         value += duals[iRowM];
+                         value -= duals[iRowP];
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atLowerBound:
+                         value = cost[iSequence];
+                         j = iSequence << 1;
+                         iRowM = indices_[j];
+                         iRowP = indices_[j+1];
+                         value += duals[iRowM];
+                         value -= duals[iRowP];
+                         value = -value;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    }
+               }
+               if (!numberWanted)
+                    break;
+          }
+          if (bestSequence != saveSequence) {
+               // recompute dj
+               double value = cost[bestSequence];
+               j = bestSequence << 1;
+               int iRowM = indices_[j];
+               int iRowP = indices_[j+1];
+               value += duals[iRowM];
+               value -= duals[iRowP];
+               reducedCost[bestSequence] = value;
+               savedBestSequence_ = bestSequence;
+               savedBestDj_ = reducedCost[savedBestSequence_];
+          }
+     }
+     currentWanted_ = numberWanted;
+}
+// Allow any parts of a created CoinMatrix to be deleted
+void
+ClpNetworkMatrix::releasePackedMatrix() const
+{
+     delete matrix_;
+     delete [] lengths_;
+     matrix_ = NULL;
+     lengths_ = NULL;
+}
+// Append Columns
+void
+ClpNetworkMatrix::appendCols(int number, const CoinPackedVectorBase * const * columns)
+{
+     int iColumn;
+     int numberBad = 0;
+     for (iColumn = 0; iColumn < number; iColumn++) {
+          int n = columns[iColumn]->getNumElements();
+          const double * element = columns[iColumn]->getElements();
+          if (n != 2)
+               numberBad++;
+          if (fabs(element[0]) != 1.0 || fabs(element[1]) != 1.0)
+               numberBad++;
+          else if (element[0]*element[1] != -1.0)
+               numberBad++;
+     }
+     if (numberBad)
+          throw CoinError("Not network", "appendCols", "ClpNetworkMatrix");
+     // Get rid of temporary arrays
+     delete [] lengths_;
+     lengths_ = NULL;
+     delete matrix_;
+     matrix_ = NULL;
+     CoinBigIndex size = 2 * number;
+     int * temp2 = new int [numberColumns_*2+size];
+     CoinMemcpyN(indices_, numberColumns_ * 2, temp2);
+     delete [] indices_;
+     indices_ = temp2;
+     // now add
+     size = 2 * numberColumns_;
+     for (iColumn = 0; iColumn < number; iColumn++) {
+          const int * row = columns[iColumn]->getIndices();
+          const double * element = columns[iColumn]->getElements();
+          if (element[0] == -1.0) {
+               indices_[size++] = row[0];
+               indices_[size++] = row[1];
+          } else {
+               indices_[size++] = row[1];
+               indices_[size++] = row[0];
+          }
+     }
+
+     numberColumns_ += number;
+}
+// Append Rows
+void
+ClpNetworkMatrix::appendRows(int number, const CoinPackedVectorBase * const * rows)
+{
+     // must be zero arrays
+     int numberBad = 0;
+     int iRow;
+     for (iRow = 0; iRow < number; iRow++) {
+          numberBad += rows[iRow]->getNumElements();
+     }
+     if (numberBad)
+          throw CoinError("Not NULL rows", "appendRows", "ClpNetworkMatrix");
+     numberRows_ += number;
+}
+#ifndef SLIM_CLP
+/* Append a set of rows/columns to the end of the matrix. Returns number of errors
+   i.e. if any of the new rows/columns contain an index that's larger than the
+   number of columns-1/rows-1 (if numberOther>0) or duplicates
+   If 0 then rows, 1 if columns */
+int
+ClpNetworkMatrix::appendMatrix(int number, int type,
+                               const CoinBigIndex * starts, const int * index,
+                               const double * element, int /*numberOther*/)
+{
+     int numberErrors = 0;
+     // make into CoinPackedVector
+     CoinPackedVectorBase ** vectors =
+          new CoinPackedVectorBase * [number];
+     int iVector;
+     for (iVector = 0; iVector < number; iVector++) {
+          int iStart = starts[iVector];
+          vectors[iVector] =
+               new CoinPackedVector(starts[iVector+1] - iStart,
+                                    index + iStart, element + iStart);
+     }
+     if (type == 0) {
+          // rows
+          appendRows(number, vectors);
+     } else {
+          // columns
+          appendCols(number, vectors);
+     }
+     for (iVector = 0; iVector < number; iVector++)
+          delete vectors[iVector];
+     delete [] vectors;
+     return numberErrors;
+}
+#endif
+/* Subset clone (without gaps).  Duplicates are allowed
+   and order is as given */
+ClpMatrixBase *
+ClpNetworkMatrix::subsetClone (int numberRows, const int * whichRows,
+                               int numberColumns,
+                               const int * whichColumns) const
+{
+     return new ClpNetworkMatrix(*this, numberRows, whichRows,
+                                 numberColumns, whichColumns);
+}
+/* Subset constructor (without gaps).  Duplicates are allowed
+   and order is as given */
+ClpNetworkMatrix::ClpNetworkMatrix (
+     const ClpNetworkMatrix & rhs,
+     int numberRows, const int * whichRow,
+     int numberColumns, const int * whichColumn)
+     : ClpMatrixBase(rhs)
+{
+     setType(11);
+     matrix_ = NULL;
+     lengths_ = NULL;
+     indices_ = new int[2*numberColumns];;
+     numberRows_ = numberRows;
+     numberColumns_ = numberColumns;
+     trueNetwork_ = true;
+     int iColumn;
+     int numberBad = 0;
+     int * which = new int [rhs.numberRows_];
+     int iRow;
+     for (iRow = 0; iRow < rhs.numberRows_; iRow++)
+          which[iRow] = -1;
+     int n = 0;
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          int jRow = whichRow[iRow];
+          assert (jRow >= 0 && jRow < rhs.numberRows_);
+          which[jRow] = n++;
+     }
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          CoinBigIndex start;
+          CoinBigIndex i;
+          start = 2 * iColumn;
+          CoinBigIndex offset = 2 * whichColumn[iColumn] - start;
+          for (i = start; i < start + 2; i++) {
+               int iRow = rhs.indices_[i+offset];
+               iRow = which[iRow];
+               if (iRow < 0)
+                    numberBad++;
+               else
+                    indices_[i] = iRow;
+          }
+     }
+     if (numberBad)
+          throw CoinError("Invalid rows", "subsetConstructor", "ClpNetworkMatrix");
+}
diff --git a/cbits/coin/ClpNetworkMatrix.hpp b/cbits/coin/ClpNetworkMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpNetworkMatrix.hpp
@@ -0,0 +1,229 @@
+/* $Id: ClpNetworkMatrix.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpNetworkMatrix_H
+#define ClpNetworkMatrix_H
+
+
+#include "CoinPragma.hpp"
+
+#include "ClpMatrixBase.hpp"
+
+/** This implements a simple network matrix as derived from ClpMatrixBase.
+
+If you want more sophisticated version then you could inherit from this.
+Also you might want to allow networks with gain */
+
+class ClpNetworkMatrix : public ClpMatrixBase {
+
+public:
+     /**@name Useful methods */
+     //@{
+     /// Return a complete CoinPackedMatrix
+     virtual CoinPackedMatrix * getPackedMatrix() const;
+     /** Whether the packed matrix is column major ordered or not. */
+     virtual bool isColOrdered() const {
+          return true;
+     }
+     /** Number of entries in the packed matrix. */
+     virtual  CoinBigIndex getNumElements() const {
+          return 2 * numberColumns_;
+     }
+     /** Number of columns. */
+     virtual int getNumCols() const {
+          return numberColumns_;
+     }
+     /** Number of rows. */
+     virtual int getNumRows() const {
+          return numberRows_;
+     }
+
+     /** A vector containing the elements in the packed matrix. Note that there
+      might be gaps in this list, entries that do not belong to any
+      major-dimension vector. To get the actual elements one should look at
+      this vector together with vectorStarts and vectorLengths. */
+     virtual const double * getElements() const;
+     /** A vector containing the minor indices of the elements in the packed
+          matrix. Note that there might be gaps in this list, entries that do not
+          belong to any major-dimension vector. To get the actual elements one
+          should look at this vector together with vectorStarts and
+          vectorLengths. */
+     virtual const int * getIndices() const {
+          return indices_;
+     }
+
+     virtual const CoinBigIndex * getVectorStarts() const;
+     /** The lengths of the major-dimension vectors. */
+     virtual const int * getVectorLengths() const;
+
+     /** Delete the columns whose indices are listed in <code>indDel</code>. */
+     virtual void deleteCols(const int numDel, const int * indDel);
+     /** Delete the rows whose indices are listed in <code>indDel</code>. */
+     virtual void deleteRows(const int numDel, const int * indDel);
+     /// Append Columns
+     virtual void appendCols(int number, const CoinPackedVectorBase * const * columns);
+     /// Append Rows
+     virtual void appendRows(int number, const CoinPackedVectorBase * const * rows);
+#ifndef SLIM_CLP
+     /** Append a set of rows/columns to the end of the matrix. Returns number of errors
+         i.e. if any of the new rows/columns contain an index that's larger than the
+         number of columns-1/rows-1 (if numberOther>0) or duplicates
+         If 0 then rows, 1 if columns */
+     virtual int appendMatrix(int number, int type,
+                              const CoinBigIndex * starts, const int * index,
+                              const double * element, int numberOther = -1);
+#endif
+     /** Returns a new matrix in reverse order without gaps */
+     virtual ClpMatrixBase * reverseOrderedCopy() const;
+     /// Returns number of elements in column part of basis
+     virtual CoinBigIndex countBasis(
+          const int * whichColumn,
+          int & numberColumnBasic);
+     /// Fills in column part of basis
+     virtual void fillBasis(ClpSimplex * model,
+                            const int * whichColumn,
+                            int & numberColumnBasic,
+                            int * row, int * start,
+                            int * rowCount, int * columnCount,
+                            CoinFactorizationDouble * element);
+     /** Given positive integer weights for each row fills in sum of weights
+         for each column (and slack).
+         Returns weights vector
+     */
+     virtual CoinBigIndex * dubiousWeights(const ClpSimplex * model, int * inputWeights) const;
+     /** Returns largest and smallest elements of both signs.
+         Largest refers to largest absolute value.
+     */
+     virtual void rangeOfElements(double & smallestNegative, double & largestNegative,
+                                  double & smallestPositive, double & largestPositive);
+     /** Unpacks a column into an CoinIndexedvector
+      */
+     virtual void unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                         int column) const ;
+     /** Unpacks a column into an CoinIndexedvector
+      ** in packed format
+         Note that model is NOT const.  Bounds and objective could
+         be modified if doing column generation (just for this variable) */
+     virtual void unpackPacked(ClpSimplex * model,
+                               CoinIndexedVector * rowArray,
+                               int column) const;
+     /** Adds multiple of a column into an CoinIndexedvector
+         You can use quickAdd to add to vector */
+     virtual void add(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                      int column, double multiplier) const ;
+     /** Adds multiple of a column into an array */
+     virtual void add(const ClpSimplex * model, double * array,
+                      int column, double multiplier) const;
+     /// Allow any parts of a created CoinMatrix to be deleted
+     virtual void releasePackedMatrix() const ;
+     /// Says whether it can do partial pricing
+     virtual bool canDoPartialPricing() const;
+     /// Partial pricing
+     virtual void partialPricing(ClpSimplex * model, double start, double end,
+                                 int & bestSequence, int & numberWanted);
+     //@}
+
+     /**@name Matrix times vector methods */
+     //@{
+     /** Return <code>y + A * scalar *x</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numColumns()</code>
+         @pre <code>y</code> must be of size <code>numRows()</code> */
+     virtual void times(double scalar,
+                        const double * x, double * y) const;
+     /// And for scaling
+     virtual void times(double scalar,
+                        const double * x, double * y,
+                        const double * rowScale,
+                        const double * columnScale) const;
+     /** Return <code>y + x * scalar * A</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numRows()</code>
+         @pre <code>y</code> must be of size <code>numColumns()</code> */
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y) const;
+     /// And for scaling
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y,
+                                 const double * rowScale,
+                                 const double * columnScale, double * spare = NULL) const;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Can use y as temporary array (will be empty at end)
+     Note - If x packed mode - then z packed mode
+     Squashes small elements and knows about ClpSimplex */
+     virtual void transposeTimes(const ClpSimplex * model, double scalar,
+                                 const CoinIndexedVector * x,
+                                 CoinIndexedVector * y,
+                                 CoinIndexedVector * z) const;
+     /** Return <code>x *A</code> in <code>z</code> but
+     just for indices in y.
+     Note - z always packed mode */
+     virtual void subsetTransposeTimes(const ClpSimplex * model,
+                                       const CoinIndexedVector * x,
+                                       const CoinIndexedVector * y,
+                                       CoinIndexedVector * z) const;
+     //@}
+
+     /**@name Other */
+     //@{
+     /// Return true if really network, false if has slacks
+     inline bool trueNetwork() const {
+          return trueNetwork_;
+     }
+     //@}
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpNetworkMatrix();
+     /** Constructor from two arrays */
+     ClpNetworkMatrix(int numberColumns, const int * head,
+                      const int * tail);
+     /** Destructor */
+     virtual ~ClpNetworkMatrix();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpNetworkMatrix(const ClpNetworkMatrix&);
+     /** The copy constructor from an CoinNetworkMatrix. */
+     ClpNetworkMatrix(const CoinPackedMatrix&);
+
+     ClpNetworkMatrix& operator=(const ClpNetworkMatrix&);
+     /// Clone
+     virtual ClpMatrixBase * clone() const ;
+     /** Subset constructor (without gaps).  Duplicates are allowed
+         and order is as given */
+     ClpNetworkMatrix (const ClpNetworkMatrix & wholeModel,
+                       int numberRows, const int * whichRows,
+                       int numberColumns, const int * whichColumns);
+     /** Subset clone (without gaps).  Duplicates are allowed
+         and order is as given */
+     virtual ClpMatrixBase * subsetClone (
+          int numberRows, const int * whichRows,
+          int numberColumns, const int * whichColumns) const ;
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// For fake CoinPackedMatrix
+     mutable CoinPackedMatrix * matrix_;
+     mutable int * lengths_;
+     /// Data -1, then +1 rows in pairs (row==-1 if one entry)
+     int * indices_;
+     /// Number of rows
+     int numberRows_;
+     /// Number of columns
+     int numberColumns_;
+     /// True if all entries have two elements
+     bool trueNetwork_;
+
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpNode.cpp b/cbits/coin/ClpNode.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpNode.cpp
@@ -0,0 +1,1294 @@
+/* $Id: ClpNode.cpp 1910 2013-01-27 02:00:13Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpNode.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpDualRowSteepest.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpNode::ClpNode () :
+     branchingValue_(0.5),
+     objectiveValue_(0.0),
+     sumInfeasibilities_(0.0),
+     estimatedSolution_(0.0),
+     factorization_(NULL),
+     weights_(NULL),
+     status_(NULL),
+     primalSolution_(NULL),
+     dualSolution_(NULL),
+     lower_(NULL),
+     upper_(NULL),
+     pivotVariables_(NULL),
+     fixed_(NULL),
+     sequence_(1),
+     numberInfeasibilities_(0),
+     depth_(0),
+     numberFixed_(0),
+     flags_(0),
+     maximumFixed_(0),
+     maximumRows_(0),
+     maximumColumns_(0),
+     maximumIntegers_(0)
+{
+     branchState_.firstBranch = 0;
+     branchState_.branch = 0;
+}
+//-------------------------------------------------------------------
+// Useful Constructor from model
+//-------------------------------------------------------------------
+ClpNode::ClpNode (ClpSimplex * model, const ClpNodeStuff * stuff, int depth) :
+     branchingValue_(0.5),
+     objectiveValue_(0.0),
+     sumInfeasibilities_(0.0),
+     estimatedSolution_(0.0),
+     factorization_(NULL),
+     weights_(NULL),
+     status_(NULL),
+     primalSolution_(NULL),
+     dualSolution_(NULL),
+     lower_(NULL),
+     upper_(NULL),
+     pivotVariables_(NULL),
+     fixed_(NULL),
+     sequence_(1),
+     numberInfeasibilities_(0),
+     depth_(0),
+     numberFixed_(0),
+     flags_(0),
+     maximumFixed_(0),
+     maximumRows_(0),
+     maximumColumns_(0),
+     maximumIntegers_(0)
+{
+     branchState_.firstBranch = 0;
+     branchState_.branch = 0;
+     gutsOfConstructor(model, stuff, 0, depth);
+}
+
+//-------------------------------------------------------------------
+// Most of work of constructor from model
+//-------------------------------------------------------------------
+void
+ClpNode::gutsOfConstructor (ClpSimplex * model, const ClpNodeStuff * stuff,
+                            int arraysExist, int depth)
+{
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     int numberTotal = numberRows + numberColumns;
+     int maximumTotal = maximumRows_ + maximumColumns_;
+     depth_ = depth;
+     // save stuff
+     objectiveValue_ = model->objectiveValue() * model->optimizationDirection();
+     estimatedSolution_ = objectiveValue_;
+     flags_ = 1; //say scaled
+     if (!arraysExist) {
+          maximumRows_ = CoinMax(maximumRows_, numberRows);
+          maximumColumns_ = CoinMax(maximumColumns_, numberColumns);
+          maximumTotal = maximumRows_ + maximumColumns_;
+          assert (!factorization_);
+          factorization_ = new ClpFactorization(*model->factorization(), numberRows);
+          status_ = CoinCopyOfArrayPartial(model->statusArray(), maximumTotal, numberTotal);
+          primalSolution_ = CoinCopyOfArrayPartial(model->solutionRegion(), maximumTotal, numberTotal);
+          dualSolution_ = CoinCopyOfArrayPartial(model->djRegion(), maximumTotal, numberTotal); //? has duals as well?
+          pivotVariables_ = CoinCopyOfArrayPartial(model->pivotVariable(), maximumRows_, numberRows);
+          ClpDualRowSteepest* pivot =
+               dynamic_cast< ClpDualRowSteepest*>(model->dualRowPivot());
+          if (pivot) {
+               assert (!weights_);
+               weights_ = new ClpDualRowSteepest(*pivot);
+          }
+     } else {
+          if (arraysExist == 2)
+               assert(lower_);
+          if (numberRows <= maximumRows_ && numberColumns <= maximumColumns_) {
+               CoinMemcpyN(model->statusArray(), numberTotal, status_);
+               if (arraysExist == 1) {
+                    *factorization_ = *model->factorization();
+                    CoinMemcpyN(model->solutionRegion(), numberTotal, primalSolution_);
+                    CoinMemcpyN(model->djRegion(), numberTotal, dualSolution_); //? has duals as well?
+                    ClpDualRowSteepest* pivot =
+                         dynamic_cast< ClpDualRowSteepest*>(model->dualRowPivot());
+                    if (pivot) {
+                         if (weights_) {
+                              //if (weights_->numberRows()==pivot->numberRows()) {
+                              weights_->fill(*pivot);
+                              //} else {
+                              //delete weights_;
+                              //weights_ = new ClpDualRowSteepest(*pivot);
+                              //}
+                         } else {
+                              weights_ = new ClpDualRowSteepest(*pivot);
+                         }
+                    }
+                    CoinMemcpyN(model->pivotVariable(), numberRows, pivotVariables_);
+               } else {
+                    CoinMemcpyN(model->primalColumnSolution(), numberColumns, primalSolution_);
+                    CoinMemcpyN(model->dualColumnSolution(), numberColumns, dualSolution_);
+                    flags_ = 0;
+                    CoinMemcpyN(model->dualRowSolution(), numberRows, dualSolution_ + numberColumns);
+               }
+          } else {
+               // size has changed
+               maximumRows_ = CoinMax(maximumRows_, numberRows);
+               maximumColumns_ = CoinMax(maximumColumns_, numberColumns);
+               maximumTotal = maximumRows_ + maximumColumns_;
+               delete weights_;
+               weights_ = NULL;
+               delete [] status_;
+               delete [] primalSolution_;
+               delete [] dualSolution_;
+               delete [] pivotVariables_;
+               status_ = CoinCopyOfArrayPartial(model->statusArray(), maximumTotal, numberTotal);
+               primalSolution_ = new double [maximumTotal*sizeof(double)];
+               dualSolution_ = new double [maximumTotal*sizeof(double)];
+               if (arraysExist == 1) {
+                    *factorization_ = *model->factorization(); // I think this is OK
+                    CoinMemcpyN(model->solutionRegion(), numberTotal, primalSolution_);
+                    CoinMemcpyN(model->djRegion(), numberTotal, dualSolution_); //? has duals as well?
+                    ClpDualRowSteepest* pivot =
+                         dynamic_cast< ClpDualRowSteepest*>(model->dualRowPivot());
+                    if (pivot) {
+                         assert (!weights_);
+                         weights_ = new ClpDualRowSteepest(*pivot);
+                    }
+               } else {
+                    CoinMemcpyN(model->primalColumnSolution(), numberColumns, primalSolution_);
+                    CoinMemcpyN(model->dualColumnSolution(), numberColumns, dualSolution_);
+                    flags_ = 0;
+                    CoinMemcpyN(model->dualRowSolution(), numberRows, dualSolution_ + numberColumns);
+               }
+               pivotVariables_ = new int [maximumRows_];
+               if (model->pivotVariable() && model->numberRows() == numberRows)
+                    CoinMemcpyN(model->pivotVariable(), numberRows, pivotVariables_);
+               else
+                    CoinFillN(pivotVariables_, numberRows, -1);
+          }
+     }
+     numberFixed_ = 0;
+     const double * lower = model->columnLower();
+     const double * upper = model->columnUpper();
+     const double * solution = model->primalColumnSolution();
+     const char * integerType = model->integerInformation();
+     const double * columnScale = model->columnScale();
+     if (!flags_)
+          columnScale = NULL; // as duals correct
+     int iColumn;
+     sequence_ = -1;
+     double integerTolerance = stuff->integerTolerance_;
+     double mostAway = 0.0;
+     int bestPriority = COIN_INT_MAX;
+     sumInfeasibilities_ = 0.0;
+     numberInfeasibilities_ = 0;
+     int nFix = 0;
+     double gap = CoinMax(model->dualObjectiveLimit() - objectiveValue_, 1.0e-4);
+#define PSEUDO 3
+#if PSEUDO==1||PSEUDO==2
+     // Column copy of matrix
+     ClpPackedMatrix * matrix = model->clpScaledMatrix();
+     const double *objective = model->costRegion() ;
+     if (!objective) {
+          objective = model->objective();
+          //if (!matrix)
+          matrix = dynamic_cast< ClpPackedMatrix*>(model->clpMatrix());
+     } else if (!matrix) {
+          matrix = dynamic_cast< ClpPackedMatrix*>(model->clpMatrix());
+     }
+     const double * element = matrix->getElements();
+     const int * row = matrix->getIndices();
+     const CoinBigIndex * columnStart = matrix->getVectorStarts();
+     const int * columnLength = matrix->getVectorLengths();
+     double direction = model->optimizationDirection();
+     const double * dual = dualSolution_ + numberColumns;
+#if PSEUDO==2
+     double * activeWeight = new double [numberRows];
+     const double * rowLower = model->rowLower();
+     const double * rowUpper = model->rowUpper();
+     const double * rowActivity = model->primalRowSolution();
+     double tolerance = 1.0e-6;
+     for (int iRow = 0; iRow < numberRows; iRow++) {
+          // could use pi to see if active or activity
+          if (rowActivity[iRow] > rowUpper[iRow] - tolerance
+                    || rowActivity[iRow] < rowLower[iRow] + tolerance) {
+               activeWeight[iRow] = 0.0;
+          } else {
+               activeWeight[iRow] = -1.0;
+          }
+     }
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+          if (integerType[iColumn]) {
+               double value = solution[iColumn];
+               if (fabs(value - floor(value + 0.5)) > 1.0e-6) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = start + columnLength[iColumn];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         int iRow = row[j];
+                         if (activeWeight[iRow] >= 0.0)
+                              activeWeight[iRow] += 1.0;
+                    }
+               }
+          }
+     }
+     for (int iRow = 0; iRow < numberRows; iRow++) {
+          if (activeWeight[iRow] > 0.0) {
+               // could use pi
+               activeWeight[iRow] = 1.0 / activeWeight[iRow];
+          } else {
+               activeWeight[iRow] = 0.0;
+          }
+     }
+#endif
+#endif
+     const double * downPseudo = stuff->downPseudo_;
+     const int * numberDown = stuff->numberDown_;
+     const int * numberDownInfeasible = stuff->numberDownInfeasible_;
+     const double * upPseudo = stuff->upPseudo_;
+     const int * priority = stuff->priority_;
+     const int * numberUp = stuff->numberUp_;
+     const int * numberUpInfeasible = stuff->numberUpInfeasible_;
+     int numberBeforeTrust = stuff->numberBeforeTrust_;
+     int stateOfSearch = stuff->stateOfSearch_;
+     int iInteger = 0;
+     // weight at 1.0 is max min (CbcBranch was 0.8,0.1) (ClpNode was 0.9,0.9)
+#define WEIGHT_AFTER 0.9
+#define WEIGHT_BEFORE 0.2
+     //Stolen from Constraint Integer Programming book (with epsilon change)
+#define WEIGHT_PRODUCT
+#ifdef WEIGHT_PRODUCT
+     double smallChange = stuff->smallChange_;
+#endif
+#ifndef INFEAS_MULTIPLIER 
+#define INFEAS_MULTIPLIER 1.0
+#endif
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          if (integerType[iColumn]) {
+               double value = solution[iColumn];
+               value = CoinMax(value, static_cast<double> (lower[iColumn]));
+               value = CoinMin(value, static_cast<double> (upper[iColumn]));
+               double nearest = floor(value + 0.5);
+               if (fabs(value - nearest) > integerTolerance) {
+                    numberInfeasibilities_++;
+                    sumInfeasibilities_ += fabs(value - nearest);
+#if PSEUDO==1 || PSEUDO ==2
+                    double upValue = 0.0;
+                    double downValue = 0.0;
+                    double value2 = direction * objective[iColumn];
+                    //double dj2=value2;
+                    if (value2) {
+                         if (value2 > 0.0)
+                              upValue += 1.5 * value2;
+                         else
+                              downValue -= 1.5 * value2;
+                    }
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn];
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         int iRow = row[j];
+                         value2 = -dual[iRow];
+                         if (value2) {
+                              value2 *= element[j];
+                              //dj2 += value2;
+#if PSEUDO==2
+                              assert (activeWeight[iRow] > 0.0 || fabs(dual[iRow]) < 1.0e-6);
+                              value2 *= activeWeight[iRow];
+#endif
+                              if (value2 > 0.0)
+                                   upValue += value2;
+                              else
+                                   downValue -= value2;
+                         }
+                    }
+                    //assert (fabs(dj2)<1.0e-4);
+                    int nUp = numberUp[iInteger];
+                    double upValue2 = (upPseudo[iInteger] / (1.0 + nUp));
+                    // Extra for infeasible branches
+                    if (nUp) {
+                         double ratio = 1.0 + INFEAS_MULTIPLIER*static_cast<double>(numberUpInfeasible[iInteger]) /
+                                        static_cast<double>(nUp);
+                         upValue2 *= ratio;
+                    }
+                    int nDown = numberDown[iInteger];
+                    double downValue2 = (downPseudo[iInteger] / (1.0 + nDown));
+                    if (nDown) {
+                         double ratio = 1.0 + INFEAS_MULTIPLIER*static_cast<double>(numberDownInfeasible[iInteger]) /
+                                        static_cast<double>(nDown);
+                         downValue2 *= ratio;
+                    }
+                    //printf("col %d - downPi %g up %g, downPs %g up %g\n",
+                    //     iColumn,upValue,downValue,upValue2,downValue2);
+                    upValue = CoinMax(0.1 * upValue, upValue2);
+                    downValue = CoinMax(0.1 * downValue, downValue2);
+                    //upValue = CoinMax(upValue,1.0e-8);
+                    //downValue = CoinMax(downValue,1.0e-8);
+                    upValue *= ceil(value) - value;
+                    downValue *= value - floor(value);
+                    double infeasibility;
+                    //if (depth>1000)
+                    //infeasibility = CoinMax(upValue,downValue)+integerTolerance;
+                    //else
+                    if (stateOfSearch <= 2) {
+                         // no solution
+                         infeasibility = (1.0 - WEIGHT_BEFORE) * CoinMax(upValue, downValue) +
+                                         WEIGHT_BEFORE * CoinMin(upValue, downValue) + integerTolerance;
+                    } else {
+#ifndef WEIGHT_PRODUCT
+                         infeasibility = (1.0 - WEIGHT_AFTER) * CoinMax(upValue, downValue) +
+                                         WEIGHT_AFTER * CoinMin(upValue, downValue) + integerTolerance;
+#else
+                         infeasibility = CoinMax(CoinMax(upValue, downValue), smallChange) *
+                                         CoinMax(CoinMin(upValue, downValue), smallChange);
+#endif
+                    }
+                    estimatedSolution_ += CoinMin(upValue2, downValue2);
+#elif PSEUDO==3
+                    int nUp = numberUp[iInteger];
+                    int nDown = numberDown[iInteger];
+                    // Extra 100% for infeasible branches
+                    double upValue = (ceil(value) - value) * (upPseudo[iInteger] /
+                                     (1.0 + nUp));
+                    if (nUp) {
+                         double ratio = 1.0 + INFEAS_MULTIPLIER*static_cast<double>(numberUpInfeasible[iInteger]) /
+                                        static_cast<double>(nUp);
+                         upValue *= ratio;
+                    }
+                    double downValue = (value - floor(value)) * (downPseudo[iInteger] /
+                                       (1.0 + nDown));
+                    if (nDown) {
+                         double ratio = 1.0 + INFEAS_MULTIPLIER*static_cast<double>(numberDownInfeasible[iInteger]) /
+                                        static_cast<double>(nDown);
+                         downValue *= ratio;
+                    }
+                    if (nUp < numberBeforeTrust || nDown < numberBeforeTrust) {
+                         upValue *= 10.0;
+                         downValue *= 10.0;
+                    }
+
+                    double infeasibility;
+                    //if (depth>1000)
+                    //infeasibility = CoinMax(upValue,downValue)+integerTolerance;
+                    //else
+                    if (stateOfSearch <= 2) {
+                         // no solution
+                         infeasibility = (1.0 - WEIGHT_BEFORE) * CoinMax(upValue, downValue) +
+                                         WEIGHT_BEFORE * CoinMin(upValue, downValue) + integerTolerance;
+                    } else {
+#ifndef WEIGHT_PRODUCT
+                         infeasibility = (1.0 - WEIGHT_AFTER) * CoinMax(upValue, downValue) +
+                                         WEIGHT_AFTER * CoinMin(upValue, downValue) + integerTolerance;
+#else
+                    infeasibility = CoinMax(CoinMax(upValue, downValue), smallChange) *
+                                    CoinMax(CoinMin(upValue, downValue), smallChange);
+                    //infeasibility += CoinMin(upValue,downValue)*smallChange;
+#endif
+                    }
+                    //infeasibility = 0.1*CoinMax(upValue,downValue)+
+                    //0.9*CoinMin(upValue,downValue) + integerTolerance;
+                    estimatedSolution_ += CoinMin(upValue, downValue);
+#else
+                    double infeasibility = fabs(value - nearest);
+#endif
+                    assert (infeasibility > 0.0);
+                    if (priority[iInteger] < bestPriority) {
+                         mostAway = 0.0;
+                         bestPriority = priority[iInteger];
+                    } else if (priority[iInteger] > bestPriority) {
+                         infeasibility = 0.0;
+                    }
+                    if (infeasibility > mostAway) {
+                         mostAway = infeasibility;
+                         sequence_ = iColumn;
+                         branchingValue_ = value;
+                         branchState_.branch = 0;
+#if PSEUDO>0
+                         if (upValue <= downValue)
+                              branchState_.firstBranch = 1; // up
+                         else
+                              branchState_.firstBranch = 0; // down
+#else
+                         if (value <= nearest)
+                              branchState_.firstBranch = 1; // up
+                         else
+                              branchState_.firstBranch = 0; // down
+#endif
+                    }
+               } else if (model->getColumnStatus(iColumn) == ClpSimplex::atLowerBound) {
+                    bool fix = false;
+                    if (columnScale) {
+                         if (dualSolution_[iColumn] > gap * columnScale[iColumn])
+                              fix = true;
+                    } else {
+                         if (dualSolution_[iColumn] > gap)
+                              fix = true;
+                    }
+                    if (fix) {
+                         nFix++;
+                         //printf("fixed %d to zero gap %g dj %g %g\n",iColumn,
+                         // gap,dualSolution_[iColumn], columnScale ? columnScale[iColumn]:1.0);
+                         model->setColumnStatus(iColumn, ClpSimplex::isFixed);
+                    }
+               } else if (model->getColumnStatus(iColumn) == ClpSimplex::atUpperBound) {
+                    bool fix = false;
+                    if (columnScale) {
+                         if (-dualSolution_[iColumn] > gap * columnScale[iColumn])
+                              fix = true;
+                    } else {
+                         if (-dualSolution_[iColumn] > gap)
+                              fix = true;
+                    }
+                    if (fix) {
+                         nFix++;
+                         //printf("fixed %d to one gap %g dj %g %g\n",iColumn,
+                         // gap,dualSolution_[iColumn], columnScale ? columnScale[iColumn]:1.0);
+                         model->setColumnStatus(iColumn, ClpSimplex::isFixed);
+                    }
+               }
+               iInteger++;
+          }
+     }
+     //printf("Choosing %d inf %g pri %d\n",
+     // sequence_,mostAway,bestPriority);
+#if PSEUDO == 2
+     delete [] activeWeight;
+#endif
+     if (lower_) {
+          // save bounds
+          if (iInteger > maximumIntegers_) {
+               delete [] lower_;
+               delete [] upper_;
+               maximumIntegers_ = iInteger;
+               lower_ = new int [maximumIntegers_];
+               upper_ = new int [maximumIntegers_];
+          }
+          iInteger = 0;
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               if (integerType[iColumn]) {
+                    lower_[iInteger] = static_cast<int> (lower[iColumn]);
+                    upper_[iInteger] = static_cast<int> (upper[iColumn]);
+                    iInteger++;
+               }
+          }
+     }
+     // Could omit save of fixed if doing full save of bounds
+     if (sequence_ >= 0 && nFix) {
+          if (nFix > maximumFixed_) {
+               delete [] fixed_;
+               fixed_ = new int [nFix];
+               maximumFixed_ = nFix;
+          }
+          numberFixed_ = 0;
+          unsigned char * status = model->statusArray();
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               if (status[iColumn] != status_[iColumn]) {
+                    if (solution[iColumn] <= lower[iColumn] + 2.0 * integerTolerance) {
+                         model->setColumnUpper(iColumn, lower[iColumn]);
+                         fixed_[numberFixed_++] = iColumn;
+                    } else {
+                         assert (solution[iColumn] >= upper[iColumn] - 2.0 * integerTolerance);
+                         model->setColumnLower(iColumn, upper[iColumn]);
+                         fixed_[numberFixed_++] = iColumn | 0x10000000;
+                    }
+               }
+          }
+          //printf("%d fixed\n",numberFixed_);
+     }
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpNode::ClpNode (const ClpNode & )
+{
+     printf("ClpNode copy not implemented\n");
+     abort();
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpNode::~ClpNode ()
+{
+     delete factorization_;
+     delete weights_;
+     delete [] status_;
+     delete [] primalSolution_;
+     delete [] dualSolution_;
+     delete [] lower_;
+     delete [] upper_;
+     delete [] pivotVariables_;
+     delete [] fixed_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpNode &
+ClpNode::operator=(const ClpNode& rhs)
+{
+     if (this != &rhs) {
+          printf("ClpNode = not implemented\n");
+          abort();
+     }
+     return *this;
+}
+// Create odd arrays
+void
+ClpNode::createArrays(ClpSimplex * model)
+{
+     int numberColumns = model->numberColumns();
+     const char * integerType = model->integerInformation();
+     int iColumn;
+     int numberIntegers = 0;
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          if (integerType[iColumn])
+               numberIntegers++;
+     }
+     if (numberIntegers > maximumIntegers_ || !lower_) {
+          delete [] lower_;
+          delete [] upper_;
+          maximumIntegers_ = numberIntegers;
+          lower_ = new int [numberIntegers];
+          upper_ = new int [numberIntegers];
+     }
+}
+// Clean up as crunch is different model
+void
+ClpNode::cleanUpForCrunch()
+{
+     delete weights_;
+     weights_ = NULL;
+}
+/* Applies node to model
+   0 - just tree bounds
+   1 - tree bounds and basis etc
+   2 - saved bounds and basis etc
+*/
+void
+ClpNode::applyNode(ClpSimplex * model, int doBoundsEtc )
+{
+     int numberColumns = model->numberColumns();
+     const double * lower = model->columnLower();
+     const double * upper = model->columnUpper();
+     if (doBoundsEtc < 2) {
+          // current bound
+          int way = branchState_.firstBranch;
+          if (branchState_.branch > 0)
+               way = 1 - way;
+          if (!way) {
+               // This should also do underlying internal bound
+               model->setColumnUpper(sequence_, floor(branchingValue_));
+          } else {
+               // This should also do underlying internal bound
+               model->setColumnLower(sequence_, ceil(branchingValue_));
+          }
+          // apply dj fixings
+          for (int i = 0; i < numberFixed_; i++) {
+               int iColumn = fixed_[i];
+               if ((iColumn & 0x10000000) != 0) {
+                    iColumn &= 0xfffffff;
+                    model->setColumnLower(iColumn, upper[iColumn]);
+               } else {
+                    model->setColumnUpper(iColumn, lower[iColumn]);
+               }
+          }
+     } else {
+          // restore bounds
+          assert (lower_);
+          int iInteger = -1;
+          const char * integerType = model->integerInformation();
+          for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+               if (integerType[iColumn]) {
+                    iInteger++;
+                    if (lower_[iInteger] != static_cast<int> (lower[iColumn]))
+                         model->setColumnLower(iColumn, lower_[iInteger]);
+                    if (upper_[iInteger] != static_cast<int> (upper[iColumn]))
+                         model->setColumnUpper(iColumn, upper_[iInteger]);
+               }
+          }
+     }
+     if (doBoundsEtc && doBoundsEtc < 3) {
+          //model->copyFactorization(*factorization_);
+          model->copyFactorization(*factorization_);
+          ClpDualRowSteepest* pivot =
+               dynamic_cast< ClpDualRowSteepest*>(model->dualRowPivot());
+          if (pivot && weights_) {
+               pivot->fill(*weights_);
+          }
+          int numberRows = model->numberRows();
+          int numberTotal = numberRows + numberColumns;
+          CoinMemcpyN(status_, numberTotal, model->statusArray());
+          if (doBoundsEtc < 2) {
+               CoinMemcpyN(primalSolution_, numberTotal, model->solutionRegion());
+               CoinMemcpyN(dualSolution_, numberTotal, model->djRegion());
+               CoinMemcpyN(pivotVariables_, numberRows, model->pivotVariable());
+               CoinMemcpyN(dualSolution_ + numberColumns, numberRows, model->dualRowSolution());
+          } else {
+               CoinMemcpyN(primalSolution_, numberColumns, model->primalColumnSolution());
+               CoinMemcpyN(dualSolution_, numberColumns, model->dualColumnSolution());
+               CoinMemcpyN(dualSolution_ + numberColumns, numberRows, model->dualRowSolution());
+               if (model->columnScale()) {
+                    // See if just primal will work
+                    double * solution = model->primalColumnSolution();
+                    const double * columnScale = model->columnScale();
+                    int i;
+                    for (i = 0; i < numberColumns; i++) {
+                         solution[i] *= columnScale[i];
+                    }
+               }
+          }
+          model->setObjectiveValue(objectiveValue_);
+     }
+}
+// Choose a new variable
+void
+ClpNode::chooseVariable(ClpSimplex * , ClpNodeStuff * /*info*/)
+{
+#if 0
+     int way = branchState_.firstBranch;
+     if (branchState_.branch > 0)
+          way = 1 - way;
+     assert (!branchState_.branch);
+     // We need to use pseudo costs to choose a variable
+     int numberColumns = model->numberColumns();
+#endif
+}
+// Fix on reduced costs
+int
+ClpNode::fixOnReducedCosts(ClpSimplex * )
+{
+
+     return 0;
+}
+/* Way for integer variable -1 down , +1 up */
+int
+ClpNode::way() const
+{
+     int way = branchState_.firstBranch;
+     if (branchState_.branch > 0)
+          way = 1 - way;
+     return way == 0 ? -1 : +1;
+}
+// Return true if branch exhausted
+bool
+ClpNode::fathomed() const
+{
+     return branchState_.branch >= 1
+            ;
+}
+// Change state of variable i.e. go other way
+void
+ClpNode::changeState()
+{
+     branchState_.branch++;
+     assert (branchState_.branch <= 2);
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpNodeStuff::ClpNodeStuff () :
+     integerTolerance_(1.0e-7),
+     integerIncrement_(1.0e-8),
+     smallChange_(1.0e-8),
+     downPseudo_(NULL),
+     upPseudo_(NULL),
+     priority_(NULL),
+     numberDown_(NULL),
+     numberUp_(NULL),
+     numberDownInfeasible_(NULL),
+     numberUpInfeasible_(NULL),
+     saveCosts_(NULL),
+     nodeInfo_(NULL),
+     large_(NULL),
+     whichRow_(NULL),
+     whichColumn_(NULL),
+#ifndef NO_FATHOM_PRINT
+     handler_(NULL),
+#endif
+     nBound_(0),
+     saveOptions_(0),
+     solverOptions_(0),
+     maximumNodes_(0),
+     numberBeforeTrust_(0),
+     stateOfSearch_(0),
+     nDepth_(-1),
+     nNodes_(0),
+     numberNodesExplored_(0),
+     numberIterations_(0),
+     presolveType_(0)
+#ifndef NO_FATHOM_PRINT
+     ,startingDepth_(-1),
+     nodeCalled_(-1)
+#endif
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpNodeStuff::ClpNodeStuff (const ClpNodeStuff & rhs)
+     : integerTolerance_(rhs.integerTolerance_),
+       integerIncrement_(rhs.integerIncrement_),
+       smallChange_(rhs.smallChange_),
+       downPseudo_(NULL),
+       upPseudo_(NULL),
+       priority_(NULL),
+       numberDown_(NULL),
+       numberUp_(NULL),
+       numberDownInfeasible_(NULL),
+       numberUpInfeasible_(NULL),
+       saveCosts_(NULL),
+       nodeInfo_(NULL),
+       large_(NULL),
+       whichRow_(NULL),
+       whichColumn_(NULL),
+#ifndef NO_FATHOM_PRINT
+       handler_(rhs.handler_),
+#endif
+       nBound_(0),
+       saveOptions_(rhs.saveOptions_),
+       solverOptions_(rhs.solverOptions_),
+       maximumNodes_(rhs.maximumNodes_),
+       numberBeforeTrust_(rhs.numberBeforeTrust_),
+       stateOfSearch_(rhs.stateOfSearch_),
+       nDepth_(rhs.nDepth_),
+       nNodes_(rhs.nNodes_),
+       numberNodesExplored_(rhs.numberNodesExplored_),
+       numberIterations_(rhs.numberIterations_),
+       presolveType_(rhs.presolveType_)
+#ifndef NO_FATHOM_PRINT
+     ,startingDepth_(rhs.startingDepth_),
+       nodeCalled_(rhs.nodeCalled_)
+#endif
+{
+}
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpNodeStuff &
+ClpNodeStuff::operator=(const ClpNodeStuff& rhs)
+{
+     if (this != &rhs) {
+          integerTolerance_ = rhs.integerTolerance_;
+          integerIncrement_ = rhs.integerIncrement_;
+          smallChange_ = rhs.smallChange_;
+          downPseudo_ = NULL;
+          upPseudo_ = NULL;
+          priority_ = NULL;
+          numberDown_ = NULL;
+          numberUp_ = NULL;
+          numberDownInfeasible_ = NULL;
+          numberUpInfeasible_ = NULL;
+          saveCosts_ = NULL;
+          nodeInfo_ = NULL;
+          large_ = NULL;
+          whichRow_ = NULL;
+          whichColumn_ = NULL;
+          nBound_ = 0;
+          saveOptions_ = rhs.saveOptions_;
+          solverOptions_ = rhs.solverOptions_;
+          maximumNodes_ = rhs.maximumNodes_;
+          numberBeforeTrust_ = rhs.numberBeforeTrust_;
+          stateOfSearch_ = rhs.stateOfSearch_;
+          int n = maximumNodes();
+          if (n) {
+               for (int i = 0; i < n; i++)
+                    delete nodeInfo_[i];
+          }
+          delete [] nodeInfo_;
+          nodeInfo_ = NULL;
+          nDepth_ = rhs.nDepth_;
+          nNodes_ = rhs.nNodes_;
+          numberNodesExplored_ = rhs.numberNodesExplored_;
+          numberIterations_ = rhs.numberIterations_;
+          presolveType_ = rhs.presolveType_;
+#ifndef NO_FATHOM_PRINT
+	  handler_ = rhs.handler_;
+	  startingDepth_ = rhs.startingDepth_;
+	  nodeCalled_ = rhs.nodeCalled_;
+#endif
+     }
+     return *this;
+}
+// Zaps stuff 1 - arrays, 2 ints, 3 both
+void
+ClpNodeStuff::zap(int type)
+{
+     if ((type & 1) != 0) {
+          downPseudo_ = NULL;
+          upPseudo_ = NULL;
+          priority_ = NULL;
+          numberDown_ = NULL;
+          numberUp_ = NULL;
+          numberDownInfeasible_ = NULL;
+          numberUpInfeasible_ = NULL;
+          saveCosts_ = NULL;
+          nodeInfo_ = NULL;
+          large_ = NULL;
+          whichRow_ = NULL;
+          whichColumn_ = NULL;
+     }
+     if ((type & 2) != 0) {
+          nBound_ = 0;
+          saveOptions_ = 0;
+          solverOptions_ = 0;
+          maximumNodes_ = 0;
+          numberBeforeTrust_ = 0;
+          stateOfSearch_ = 0;
+          nDepth_ = -1;
+          nNodes_ = 0;
+          presolveType_ = 0;
+          numberNodesExplored_ = 0;
+          numberIterations_ = 0;
+     }
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpNodeStuff::~ClpNodeStuff ()
+{
+     delete [] downPseudo_;
+     delete [] upPseudo_;
+     delete [] priority_;
+     delete [] numberDown_;
+     delete [] numberUp_;
+     delete [] numberDownInfeasible_;
+     delete [] numberUpInfeasible_;
+     int n = maximumNodes();
+     if (n) {
+          for (int i = 0; i < n; i++)
+               delete nodeInfo_[i];
+     }
+     delete [] nodeInfo_;
+#ifdef CLP_INVESTIGATE
+     // Should be NULL - find out why not?
+     assert (!saveCosts_);
+#endif
+     delete [] saveCosts_;
+}
+// Return maximum number of nodes
+int
+ClpNodeStuff::maximumNodes() const
+{
+     int n = 0;
+#if 0
+     if (nDepth_ != -1) {
+          if ((solverOptions_ & 32) == 0)
+               n = (1 << nDepth_);
+          else if (nDepth_)
+               n = 1;
+     }
+     assert (n == maximumNodes_ - (1 + nDepth_) || n == 0);
+#else
+     if (nDepth_ != -1) {
+          n = maximumNodes_ - (1 + nDepth_);
+          assert (n > 0);
+     }
+#endif
+     return n;
+}
+// Return maximum space for nodes
+int
+ClpNodeStuff::maximumSpace() const
+{
+     return maximumNodes_;
+}
+/* Fill with pseudocosts */
+void
+ClpNodeStuff::fillPseudoCosts(const double * down, const double * up,
+                              const int * priority,
+                              const int * numberDown, const int * numberUp,
+                              const int * numberDownInfeasible,
+                              const int * numberUpInfeasible,
+                              int number)
+{
+     delete [] downPseudo_;
+     delete [] upPseudo_;
+     delete [] priority_;
+     delete [] numberDown_;
+     delete [] numberUp_;
+     delete [] numberDownInfeasible_;
+     delete [] numberUpInfeasible_;
+     downPseudo_ = CoinCopyOfArray(down, number);
+     upPseudo_ = CoinCopyOfArray(up, number);
+     priority_ = CoinCopyOfArray(priority, number);
+     numberDown_ = CoinCopyOfArray(numberDown, number);
+     numberUp_ = CoinCopyOfArray(numberUp, number);
+     numberDownInfeasible_ = CoinCopyOfArray(numberDownInfeasible, number);
+     numberUpInfeasible_ = CoinCopyOfArray(numberUpInfeasible, number);
+     // scale
+     for (int i = 0; i < number; i++) {
+          int n;
+          n = numberDown_[i];
+          if (n)
+               downPseudo_[i] *= n;
+          n = numberUp_[i];
+          if (n)
+               upPseudo_[i] *= n;
+     }
+}
+// Update pseudo costs
+void
+ClpNodeStuff::update(int way, int sequence, double change, bool feasible)
+{
+     assert (numberDown_[sequence] >= numberDownInfeasible_[sequence]);
+     assert (numberUp_[sequence] >= numberUpInfeasible_[sequence]);
+     if (way < 0) {
+          numberDown_[sequence]++;
+          if (!feasible)
+               numberDownInfeasible_[sequence]++;
+          downPseudo_[sequence] += CoinMax(change, 1.0e-12);
+     } else {
+          numberUp_[sequence]++;
+          if (!feasible)
+               numberUpInfeasible_[sequence]++;
+          upPseudo_[sequence] += CoinMax(change, 1.0e-12);
+     }
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpHashValue::ClpHashValue () :
+     hash_(NULL),
+     numberHash_(0),
+     maxHash_(0),
+     lastUsed_(-1)
+{
+}
+//-------------------------------------------------------------------
+// Useful Constructor from model
+//-------------------------------------------------------------------
+ClpHashValue::ClpHashValue (ClpSimplex * model) :
+     hash_(NULL),
+     numberHash_(0),
+     maxHash_(0),
+     lastUsed_(-1)
+{
+     maxHash_ = 1000;
+     int numberColumns = model->numberColumns();
+     const double * columnLower = model->columnLower();
+     const double * columnUpper = model->columnUpper();
+     int numberRows = model->numberRows();
+     const double * rowLower = model->rowLower();
+     const double * rowUpper = model->rowUpper();
+     const double * objective = model->objective();
+     CoinPackedMatrix * matrix = model->matrix();
+     const int * columnLength = matrix->getVectorLengths();
+     const CoinBigIndex * columnStart = matrix->getVectorStarts();
+     const double * elementByColumn = matrix->getElements();
+     int i;
+     int ipos;
+
+     hash_ = new CoinHashLink[maxHash_];
+
+     for ( i = 0; i < maxHash_; i++ ) {
+          hash_[i].value = -1.0e-100;
+          hash_[i].index = -1;
+          hash_[i].next = -1;
+     }
+     // Put in +0
+     hash_[0].value = 0.0;
+     hash_[0].index = 0;
+     numberHash_ = 1;
+     /*
+      * Initialize the hash table.  Only the index of the first value that
+      * hashes to a value is entered in the table; subsequent values that
+      * collide with it are not entered.
+      */
+     for ( i = 0; i < numberColumns; i++ ) {
+          int length = columnLength[i];
+          CoinBigIndex start = columnStart[i];
+          for (CoinBigIndex i = start; i < start + length; i++) {
+               double value = elementByColumn[i];
+               ipos = hash ( value);
+               if ( hash_[ipos].index == -1 ) {
+                    hash_[ipos].index = numberHash_;
+                    numberHash_++;
+                    hash_[ipos].value = elementByColumn[i];
+               }
+          }
+     }
+
+     /*
+      * Now take care of the values that collided in the preceding loop,
+      * Also do other stuff
+      */
+     for ( i = 0; i < numberRows; i++ ) {
+          if (numberHash_ * 2 > maxHash_)
+               resize(true);
+          double value;
+          value = rowLower[i];
+          ipos = index(value);
+          if (ipos < 0)
+               addValue(value);
+          value = rowUpper[i];
+          ipos = index(value);
+          if (ipos < 0)
+               addValue(value);
+     }
+     for ( i = 0; i < numberColumns; i++ ) {
+          int length = columnLength[i];
+          CoinBigIndex start = columnStart[i];
+          if (numberHash_ * 2 > maxHash_)
+               resize(true);
+          double value;
+          value = objective[i];
+          ipos = index(value);
+          if (ipos < 0)
+               addValue(value);
+          value = columnLower[i];
+          ipos = index(value);
+          if (ipos < 0)
+               addValue(value);
+          value = columnUpper[i];
+          ipos = index(value);
+          if (ipos < 0)
+               addValue(value);
+          for (CoinBigIndex j = start; j < start + length; j++) {
+               if (numberHash_ * 2 > maxHash_)
+                    resize(true);
+               value = elementByColumn[j];
+               ipos = index(value);
+               if (ipos < 0)
+                    addValue(value);
+          }
+     }
+     resize(false);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpHashValue::ClpHashValue (const ClpHashValue & rhs) :
+     hash_(NULL),
+     numberHash_(rhs.numberHash_),
+     maxHash_(rhs.maxHash_),
+     lastUsed_(rhs.lastUsed_)
+{
+     if (maxHash_) {
+          CoinHashLink * newHash = new CoinHashLink[maxHash_];
+          int i;
+          for ( i = 0; i < maxHash_; i++ ) {
+               newHash[i].value = rhs.hash_[i].value;
+               newHash[i].index = rhs.hash_[i].index;
+               newHash[i].next = rhs.hash_[i].next;
+          }
+     }
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpHashValue::~ClpHashValue ()
+{
+     delete [] hash_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpHashValue &
+ClpHashValue::operator=(const ClpHashValue& rhs)
+{
+     if (this != &rhs) {
+          numberHash_ = rhs.numberHash_;
+          maxHash_ = rhs.maxHash_;
+          lastUsed_ = rhs.lastUsed_;
+          delete [] hash_;
+          if (maxHash_) {
+               CoinHashLink * newHash = new CoinHashLink[maxHash_];
+               int i;
+               for ( i = 0; i < maxHash_; i++ ) {
+                    newHash[i].value = rhs.hash_[i].value;
+                    newHash[i].index = rhs.hash_[i].index;
+                    newHash[i].next = rhs.hash_[i].next;
+               }
+          } else {
+               hash_ = NULL;
+          }
+     }
+     return *this;
+}
+// Return index or -1 if not found
+int
+ClpHashValue::index(double value) const
+{
+     if (!value)
+          return 0;
+     int ipos = hash ( value);
+     int returnCode = -1;
+     while ( hash_[ipos].index >= 0 ) {
+          if (value == hash_[ipos].value) {
+               returnCode = hash_[ipos].index;
+               break;
+          } else {
+               int k = hash_[ipos].next;
+               if ( k == -1 ) {
+                    break;
+               } else {
+                    ipos = k;
+               }
+          }
+     }
+     return returnCode;
+}
+// Add value to list and return index
+int
+ClpHashValue::addValue(double value)
+{
+     int ipos = hash ( value);
+
+     assert (value != hash_[ipos].value);
+     if (hash_[ipos].index == -1) {
+          // can put in here
+          hash_[ipos].index = numberHash_;
+          numberHash_++;
+          hash_[ipos].value = value;
+          return numberHash_ - 1;
+     }
+     int k = hash_[ipos].next;
+     while (k != -1) {
+          ipos = k;
+          k = hash_[ipos].next;
+     }
+     while ( true ) {
+          ++lastUsed_;
+          assert (lastUsed_ <= maxHash_);
+          if ( hash_[lastUsed_].index == -1 ) {
+               break;
+          }
+     }
+     hash_[ipos].next = lastUsed_;
+     hash_[lastUsed_].index = numberHash_;
+     numberHash_++;
+     hash_[lastUsed_].value = value;
+     return numberHash_ - 1;
+}
+
+namespace {
+  /*
+    Originally a local static variable in ClpHashValue::hash.
+	Local static variables are a problem when building DLLs on Windows, but
+	file-local constants seem to be ok.  -- lh, 101016 --
+  */
+  const int mmult_for_hash[] = {
+          262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
+          241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829,
+          221281, 218849, 216319, 213721, 211093, 208673, 206263, 203773,
+          201233, 198637, 196159, 193603, 191161, 188701, 186149, 183761,
+          181303, 178873, 176389, 173897, 171469, 169049, 166471, 163871,
+          161387, 158941, 156437, 153949, 151531, 149159, 146749, 144299,
+          141709, 139369, 136889, 134591, 132169, 129641, 127343, 124853,
+          122477, 120163, 117757, 115361, 112979, 110567, 108179, 105727,
+          103387, 101021, 98639, 96179, 93911, 91583, 89317, 86939, 84521,
+          82183, 79939, 77587, 75307, 72959, 70793, 68447, 66103
+     };
+}
+int
+ClpHashValue::hash ( double value) const
+{
+     
+     union {
+          double d;
+          char c[8];
+     } v1;
+     assert (sizeof(double) == 8);
+     v1.d = value;
+     int n = 0;
+     int j;
+
+     for ( j = 0; j < 8; ++j ) {
+          int ichar = v1.c[j];
+          n += mmult_for_hash[j] * ichar;
+     }
+     return ( abs ( n ) % maxHash_ );	/* integer abs */
+}
+void
+ClpHashValue::resize(bool increaseMax)
+{
+     int newSize = increaseMax ? ((3 * maxHash_) >> 1) + 1000 : maxHash_;
+     CoinHashLink * newHash = new CoinHashLink[newSize];
+     int i;
+     for ( i = 0; i < newSize; i++ ) {
+          newHash[i].value = -1.0e-100;
+          newHash[i].index = -1;
+          newHash[i].next = -1;
+     }
+     // swap
+     CoinHashLink * oldHash = hash_;
+     hash_ = newHash;
+     int oldSize = maxHash_;
+     maxHash_ = newSize;
+     /*
+      * Initialize the hash table.  Only the index of the first value that
+      * hashes to a value is entered in the table; subsequent values that
+      * collide with it are not entered.
+      */
+     int ipos;
+     int n = 0;
+     for ( i = 0; i < oldSize; i++ ) {
+          if (oldHash[i].index >= 0) {
+               ipos = hash ( oldHash[i].value);
+               if ( hash_[ipos].index == -1 ) {
+                    hash_[ipos].index = n;
+                    n++;
+                    hash_[ipos].value = oldHash[i].value;
+                    // unmark
+                    oldHash[i].index = -1;
+               }
+          }
+     }
+     /*
+      * Now take care of the values that collided in the preceding loop,
+      * by finding some other entry in the table for them.
+      * Since there are as many entries in the table as there are values,
+      * there must be room for them.
+      */
+     lastUsed_ = -1;
+     for ( i = 0; i < oldSize; ++i ) {
+          if (oldHash[i].index >= 0) {
+               double value = oldHash[i].value;
+               ipos = hash ( value);
+               int k;
+               while ( true ) {
+                    assert (value != hash_[ipos].value);
+                    k = hash_[ipos].next;
+                    if ( k == -1 ) {
+                         while ( true ) {
+                              ++lastUsed_;
+                              assert (lastUsed_ <= maxHash_);
+                              if ( hash_[lastUsed_].index == -1 ) {
+                                   break;
+                              }
+                         }
+                         hash_[ipos].next = lastUsed_;
+                         hash_[lastUsed_].index = n;
+                         n++;
+                         hash_[lastUsed_].value = value;
+                         break;
+                    } else {
+                         ipos = k;
+                    }
+               }
+          }
+     }
+     assert (n == numberHash_);
+     delete [] oldHash;
+}
diff --git a/cbits/coin/ClpNode.hpp b/cbits/coin/ClpNode.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpNode.hpp
@@ -0,0 +1,349 @@
+/* $Id: ClpNode.hpp 1910 2013-01-27 02:00:13Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpNode_H
+#define ClpNode_H
+
+#include "CoinPragma.hpp"
+
+// This implements all stuff for Clp fathom
+/** This contains what is in a Clp "node"
+
+ */
+
+class ClpFactorization;
+class ClpDualRowSteepest;
+class ClpNodeStuff;
+class ClpNode {
+
+public:
+     /**@name Useful methods */
+     //@{
+     /** Applies node to model
+         0 - just tree bounds
+         1 - tree bounds and basis etc
+         2 - saved bounds and basis etc
+     */
+     void applyNode(ClpSimplex * model, int doBoundsEtc );
+     /// Choose a new variable
+     void chooseVariable(ClpSimplex * model, ClpNodeStuff * info);
+     /// Fix on reduced costs
+     int fixOnReducedCosts(ClpSimplex * model);
+     /// Create odd arrays
+     void createArrays(ClpSimplex * model);
+     /// Clean up as crunch is different model
+     void cleanUpForCrunch();
+     //@}
+
+     /**@name Gets and sets */
+     //@{
+     /// Objective value
+     inline double objectiveValue() const {
+          return objectiveValue_;
+     }
+     /// Set objective value
+     inline void setObjectiveValue(double value) {
+          objectiveValue_ = value;
+     }
+     /// Primal solution
+     inline const double * primalSolution() const {
+          return primalSolution_;
+     }
+     /// Dual solution
+     inline const double * dualSolution() const {
+          return dualSolution_;
+     }
+     /// Initial value of integer variable
+     inline double branchingValue() const {
+          return branchingValue_;
+     }
+     /// Sum infeasibilities
+     inline double sumInfeasibilities() const {
+          return sumInfeasibilities_;
+     }
+     /// Number infeasibilities
+     inline int numberInfeasibilities() const {
+          return numberInfeasibilities_;
+     }
+     /// Relative depth
+     inline int depth() const {
+          return depth_;
+     }
+     /// Estimated solution value
+     inline double estimatedSolution() const {
+          return estimatedSolution_;
+     }
+     /** Way for integer variable -1 down , +1 up */
+     int way() const;
+     /// Return true if branch exhausted
+     bool fathomed() const;
+     /// Change state of variable i.e. go other way
+     void changeState();
+     /// Sequence number of integer variable (-1 if none)
+     inline int sequence() const {
+          return sequence_;
+     }
+     /// If odd arrays exist
+     inline bool oddArraysExist() const {
+          return lower_ != NULL;
+     }
+     /// Status array
+     inline const unsigned char * statusArray() const {
+          return status_;
+     }
+     //@}
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpNode();
+     /// Constructor from model
+     ClpNode (ClpSimplex * model, const ClpNodeStuff * stuff, int depth);
+     /// Does work of constructor (partly so gdb will work)
+     void gutsOfConstructor(ClpSimplex * model, const ClpNodeStuff * stuff,
+                            int arraysExist, int depth);
+     /** Destructor */
+     virtual ~ClpNode();
+     //@}
+
+     /**@name Copy methods (at present illegal - will abort) */
+     //@{
+     /** The copy constructor. */
+     ClpNode(const ClpNode&);
+     /// Operator =
+     ClpNode& operator=(const ClpNode&);
+     //@}
+
+protected:
+// For state of branch
+     typedef struct {
+          unsigned int firstBranch: 1; //  nonzero if first branch on variable is up
+          unsigned int branch: 2; //  0 means do first branch next, 1 second, 2 finished
+          unsigned int spare: 29;
+     } branchState;
+     /**@name Data */
+     //@{
+     /// Initial value of integer variable
+     double branchingValue_;
+     /// Value of objective
+     double objectiveValue_;
+     /// Sum of infeasibilities
+     double sumInfeasibilities_;
+     /// Estimated solution value
+     double estimatedSolution_;
+     /// Factorization
+     ClpFactorization * factorization_;
+     /// Steepest edge weights
+     ClpDualRowSteepest * weights_;
+     /// Status vector
+     unsigned char * status_;
+     /// Primal solution
+     double * primalSolution_;
+     /// Dual solution
+     double * dualSolution_;
+     /// Integer lower bounds (only used in fathomMany)
+     int * lower_;
+     /// Integer upper bounds (only used in fathomMany)
+     int * upper_;
+     /// Pivot variables for factorization
+     int * pivotVariables_;
+     /// Variables fixed by reduced costs (at end of branch) 0x10000000 added if fixed to UB
+     int * fixed_;
+     /// State of branch
+     branchState branchState_;
+     /// Sequence number of integer variable (-1 if none)
+     int sequence_;
+     /// Number of infeasibilities
+     int numberInfeasibilities_;
+     /// Relative depth
+     int depth_;
+     /// Number fixed by reduced cost
+     int numberFixed_;
+     /// Flags - 1 duals scaled
+     int flags_;
+     /// Maximum number fixed by reduced cost
+     int maximumFixed_;
+     /// Maximum rows so far
+     int maximumRows_;
+     /// Maximum columns so far
+     int maximumColumns_;
+     /// Maximum Integers so far
+     int maximumIntegers_;
+     //@}
+};
+class ClpNodeStuff {
+
+public:
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpNodeStuff();
+     /** Destructor */
+     virtual ~ClpNodeStuff();
+     //@}
+
+     /**@name Copy methods (only copies ints etc, nulls arrays) */
+     //@{
+     /** The copy constructor. */
+     ClpNodeStuff(const ClpNodeStuff&);
+     /// Operator =
+     ClpNodeStuff& operator=(const ClpNodeStuff&);
+     /// Zaps stuff 1 - arrays, 2 ints, 3 both
+     void zap(int type);
+     //@}
+
+
+     /**@name Fill methods */
+     //@{
+     /** Fill with pseudocosts */
+     void fillPseudoCosts(const double * down, const double * up,
+                          const int * priority,
+                          const int * numberDown, const int * numberUp,
+                          const int * numberDownInfeasible, const int * numberUpInfeasible,
+                          int number);
+     /// Update pseudo costs
+     void update(int way, int sequence, double change, bool feasible);
+     /// Return maximum number of nodes
+     int maximumNodes() const;
+     /// Return maximum space for nodes
+     int maximumSpace() const;
+     //@}
+
+public:
+     /**@name Data */
+     //@{
+     /// Integer tolerance
+     double integerTolerance_;
+     /// Integer increment
+     double integerIncrement_;
+     /// Small change in branch
+     double smallChange_;
+     /// Down pseudo costs
+     double * downPseudo_;
+     /// Up pseudo costs
+     double * upPseudo_;
+     /// Priority
+     int * priority_;
+     /// Number of times down
+     int * numberDown_;
+     /// Number of times up
+     int * numberUp_;
+     /// Number of times down infeasible
+     int * numberDownInfeasible_;
+     /// Number of times up infeasible
+     int * numberUpInfeasible_;
+     /// Copy of costs (local)
+     double * saveCosts_;
+     /// Array of ClpNodes
+     ClpNode ** nodeInfo_;
+     /// Large model if crunched
+     ClpSimplex * large_;
+     /// Which rows in large model
+     int * whichRow_;
+     /// Which columns in large model
+     int * whichColumn_;
+#ifndef NO_FATHOM_PRINT
+     /// Cbc's message handler
+     CoinMessageHandler * handler_;
+#endif
+     /// Number bounds in large model
+     int nBound_;
+     /// Save of specialOptions_ (local)
+     int saveOptions_;
+     /** Options to pass to solver
+         1 - create external reduced costs for columns
+         2 - create external reduced costs for rows
+         4 - create external row activity (columns always done)
+         Above only done if feasible
+         32 - just create up to nDepth_+1 nodes
+         65536 - set if activated
+     */
+     int solverOptions_;
+     /// Maximum number of nodes to do
+     int maximumNodes_;
+     /// Number before trust from CbcModel
+     int numberBeforeTrust_;
+     /// State of search from CbcModel
+     int stateOfSearch_;
+     /// Number deep
+     int nDepth_;
+     /// Number nodes returned (-1 if fathom aborted)
+     int nNodes_;
+     /// Number of nodes explored
+     int numberNodesExplored_;
+     /// Number of iterations
+     int numberIterations_;
+     /// Type of presolve - 0 none, 1 crunch
+     int presolveType_;
+#ifndef NO_FATHOM_PRINT
+     /// Depth passed in
+     int startingDepth_;
+     /// Node at which called
+     int nodeCalled_;
+#endif
+     //@}
+};
+class ClpHashValue {
+
+public:
+     /**@name Useful methods */
+     //@{
+     /// Return index or -1 if not found
+     int index(double value) const;
+     /// Add value to list and return index
+     int addValue(double value) ;
+     /// Number of different entries
+     inline int numberEntries() const {
+          return numberHash_;
+     }
+     //@}
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpHashValue();
+     /** Useful constructor. */
+     ClpHashValue(ClpSimplex * model);
+     /** Destructor */
+     virtual ~ClpHashValue();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpHashValue(const ClpHashValue&);
+     /// =
+     ClpHashValue& operator=(const ClpHashValue&);
+     //@}
+private:
+     /**@name private stuff */
+     //@{
+     /** returns hash */
+     int hash(double value) const;
+     /// Resizes
+     void resize(bool increaseMax);
+     //@}
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Data
+     // for hashing
+     typedef struct {
+          double value;
+          int index, next;
+     } CoinHashLink;
+     /// Hash table
+     mutable CoinHashLink *hash_;
+     /// Number of entries in hash table
+     int numberHash_;
+     /// Maximum number of entries in hash table i.e. size
+     int maxHash_;
+     /// Last used space
+     int lastUsed_;
+     //@}
+};
+#endif
diff --git a/cbits/coin/ClpNonLinearCost.cpp b/cbits/coin/ClpNonLinearCost.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpNonLinearCost.cpp
@@ -0,0 +1,2013 @@
+/* $Id: ClpNonLinearCost.cpp 1769 2011-07-26 09:31:51Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include <iostream>
+#include <cassert>
+
+#include "CoinIndexedVector.hpp"
+
+#include "ClpSimplex.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "ClpNonLinearCost.hpp"
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpNonLinearCost::ClpNonLinearCost () :
+     changeCost_(0.0),
+     feasibleCost_(0.0),
+     infeasibilityWeight_(-1.0),
+     largestInfeasibility_(0.0),
+     sumInfeasibilities_(0.0),
+     averageTheta_(0.0),
+     numberRows_(0),
+     numberColumns_(0),
+     start_(NULL),
+     whichRange_(NULL),
+     offset_(NULL),
+     lower_(NULL),
+     cost_(NULL),
+     model_(NULL),
+     infeasible_(NULL),
+     numberInfeasibilities_(-1),
+     status_(NULL),
+     bound_(NULL),
+     cost2_(NULL),
+     method_(1),
+     convex_(true),
+     bothWays_(false)
+{
+
+}
+//#define VALIDATE
+#ifdef VALIDATE
+static double * saveLowerV = NULL;
+static double * saveUpperV = NULL;
+#ifdef NDEBUG
+Validate sgould not be set if no debug
+#endif
+#endif
+/* Constructor from simplex.
+   This will just set up wasteful arrays for linear, but
+   later may do dual analysis and even finding duplicate columns
+*/
+ClpNonLinearCost::ClpNonLinearCost ( ClpSimplex * model, int method)
+{
+     method = 2;
+     model_ = model;
+     numberRows_ = model_->numberRows();
+     //if (numberRows_==402) {
+     //model_->setLogLevel(63);
+     //model_->setMaximumIterations(30000);
+     //}
+     numberColumns_ = model_->numberColumns();
+     // If gub then we need this extra
+     int numberExtra = model_->numberExtraRows();
+     if (numberExtra)
+          method = 1;
+     int numberTotal1 = numberRows_ + numberColumns_;
+     int numberTotal = numberTotal1 + numberExtra;
+     convex_ = true;
+     bothWays_ = false;
+     method_ = method;
+     numberInfeasibilities_ = 0;
+     changeCost_ = 0.0;
+     feasibleCost_ = 0.0;
+     infeasibilityWeight_ = -1.0;
+     double * cost = model_->costRegion();
+     // check if all 0
+     int iSequence;
+     bool allZero = true;
+     for (iSequence = 0; iSequence < numberTotal1; iSequence++) {
+          if (cost[iSequence]) {
+               allZero = false;
+               break;
+          }
+     }
+     if (allZero&&model_->clpMatrix()->type()<15)
+          model_->setInfeasibilityCost(1.0);
+     double infeasibilityCost = model_->infeasibilityCost();
+     sumInfeasibilities_ = 0.0;
+     averageTheta_ = 0.0;
+     largestInfeasibility_ = 0.0;
+     // All arrays NULL to start
+     status_ = NULL;
+     bound_ = NULL;
+     cost2_ = NULL;
+     start_ = NULL;
+     whichRange_ = NULL;
+     offset_ = NULL;
+     lower_ = NULL;
+     cost_ = NULL;
+     infeasible_ = NULL;
+
+     double * upper = model_->upperRegion();
+     double * lower = model_->lowerRegion();
+
+     // See how we are storing things
+     bool always4 = (model_->clpMatrix()->
+                     generalExpanded(model_, 10, iSequence) != 0);
+     if (always4)
+          method_ = 1;
+     if (CLP_METHOD1) {
+          start_ = new int [numberTotal+1];
+          whichRange_ = new int [numberTotal];
+          offset_ = new int [numberTotal];
+          memset(offset_, 0, numberTotal * sizeof(int));
+
+
+          // First see how much space we need
+          int put = 0;
+
+          // For quadratic we need -inf,0,0,+inf
+          for (iSequence = 0; iSequence < numberTotal1; iSequence++) {
+               if (!always4) {
+                    if (lower[iSequence] > -COIN_DBL_MAX)
+                         put++;
+                    if (upper[iSequence] < COIN_DBL_MAX)
+                         put++;
+                    put += 2;
+               } else {
+                    put += 4;
+               }
+          }
+
+          // and for extra
+          put += 4 * numberExtra;
+#ifndef NDEBUG
+          int kPut = put;
+#endif
+          lower_ = new double [put];
+          cost_ = new double [put];
+          infeasible_ = new unsigned int[(put+31)>>5];
+          memset(infeasible_, 0, ((put + 31) >> 5)*sizeof(unsigned int));
+
+          put = 0;
+
+          start_[0] = 0;
+
+          for (iSequence = 0; iSequence < numberTotal1; iSequence++) {
+               if (!always4) {
+                    if (lower[iSequence] > -COIN_DBL_MAX) {
+                         lower_[put] = -COIN_DBL_MAX;
+                         setInfeasible(put, true);
+                         cost_[put++] = cost[iSequence] - infeasibilityCost;
+                    }
+                    whichRange_[iSequence] = put;
+                    lower_[put] = lower[iSequence];
+                    cost_[put++] = cost[iSequence];
+                    lower_[put] = upper[iSequence];
+                    cost_[put++] = cost[iSequence] + infeasibilityCost;
+                    if (upper[iSequence] < COIN_DBL_MAX) {
+                         lower_[put] = COIN_DBL_MAX;
+                         setInfeasible(put - 1, true);
+                         cost_[put++] = 1.0e50;
+                    }
+               } else {
+                    lower_[put] = -COIN_DBL_MAX;
+                    setInfeasible(put, true);
+                    cost_[put++] = cost[iSequence] - infeasibilityCost;
+                    whichRange_[iSequence] = put;
+                    lower_[put] = lower[iSequence];
+                    cost_[put++] = cost[iSequence];
+                    lower_[put] = upper[iSequence];
+                    cost_[put++] = cost[iSequence] + infeasibilityCost;
+                    lower_[put] = COIN_DBL_MAX;
+                    setInfeasible(put - 1, true);
+                    cost_[put++] = 1.0e50;
+               }
+               start_[iSequence+1] = put;
+          }
+          for (; iSequence < numberTotal; iSequence++) {
+
+               lower_[put] = -COIN_DBL_MAX;
+               setInfeasible(put, true);
+               put++;
+               whichRange_[iSequence] = put;
+               lower_[put] = 0.0;
+               cost_[put++] = 0.0;
+               lower_[put] = 0.0;
+               cost_[put++] = 0.0;
+               lower_[put] = COIN_DBL_MAX;
+               setInfeasible(put - 1, true);
+               cost_[put++] = 1.0e50;
+               start_[iSequence+1] = put;
+          }
+          assert (put <= kPut);
+     }
+#ifdef FAST_CLPNON
+     // See how we are storing things
+     CoinAssert (model_->clpMatrix()->
+                 generalExpanded(model_, 10, iSequence) == 0);
+#endif
+     if (CLP_METHOD2) {
+          assert (!numberExtra);
+          bound_ = new double[numberTotal];
+          cost2_ = new double[numberTotal];
+          status_ = new unsigned char[numberTotal];
+#ifdef VALIDATE
+          delete [] saveLowerV;
+          saveLowerV = CoinCopyOfArray(model_->lowerRegion(), numberTotal);
+          delete [] saveUpperV;
+          saveUpperV = CoinCopyOfArray(model_->upperRegion(), numberTotal);
+#endif
+          for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+               bound_[iSequence] = 0.0;
+               cost2_[iSequence] = cost[iSequence];
+               setInitialStatus(status_[iSequence]);
+          }
+     }
+}
+// Refresh - assuming regions OK
+void 
+ClpNonLinearCost::refresh()
+{
+     int numberTotal = numberRows_ + numberColumns_;
+     numberInfeasibilities_ = 0;
+     sumInfeasibilities_ = 0.0;
+     largestInfeasibility_ = 0.0;
+     double infeasibilityCost = model_->infeasibilityCost();
+     double primalTolerance = model_->currentPrimalTolerance();
+     double * cost = model_->costRegion();
+     double * upper = model_->upperRegion();
+     double * lower = model_->lowerRegion();
+     double * solution = model_->solutionRegion();
+     for (int iSequence = 0; iSequence < numberTotal; iSequence++) {
+       cost2_[iSequence] = cost[iSequence];
+       double value = solution[iSequence];
+       double lowerValue = lower[iSequence];
+       double upperValue = upper[iSequence];
+       if (value - upperValue <= primalTolerance) {
+	 if (value - lowerValue >= -primalTolerance) {
+	   // feasible
+	   status_[iSequence] = static_cast<unsigned char>(CLP_FEASIBLE | (CLP_SAME << 4));
+	   bound_[iSequence] = 0.0;
+	 } else {
+	   // below
+	   double infeasibility = lowerValue - value - primalTolerance;
+	   sumInfeasibilities_ += infeasibility;
+	   largestInfeasibility_ = CoinMax(largestInfeasibility_, infeasibility);
+	   cost[iSequence] -= infeasibilityCost;
+	   numberInfeasibilities_++;
+	   status_[iSequence] = static_cast<unsigned char>(CLP_BELOW_LOWER | (CLP_SAME << 4));
+	   bound_[iSequence] = upperValue;
+	   upper[iSequence] = lowerValue;
+	   lower[iSequence] = -COIN_DBL_MAX;
+	 }
+       } else {
+	 // above
+	 double infeasibility = value - upperValue - primalTolerance;
+	 sumInfeasibilities_ += infeasibility;
+	 largestInfeasibility_ = CoinMax(largestInfeasibility_, infeasibility);
+	 cost[iSequence] += infeasibilityCost;
+	 numberInfeasibilities_++;
+	 status_[iSequence] = static_cast<unsigned char>(CLP_ABOVE_UPPER | (CLP_SAME << 4));
+	 bound_[iSequence] = lowerValue;
+	 lower[iSequence] = upperValue;
+	 upper[iSequence] = COIN_DBL_MAX;
+       }
+     }
+     //     checkInfeasibilities(model_->primalTolerance());
+     
+}
+// Refreshes costs always makes row costs zero
+void
+ClpNonLinearCost::refreshCosts(const double * columnCosts)
+{
+     double * cost = model_->costRegion();
+     // zero row costs
+     memset(cost + numberColumns_, 0, numberRows_ * sizeof(double));
+     // copy column costs
+     CoinMemcpyN(columnCosts, numberColumns_, cost);
+     if ((method_ & 1) != 0) {
+          for (int iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
+               int start = start_[iSequence];
+               int end = start_[iSequence+1] - 1;
+               double thisFeasibleCost = cost[iSequence];
+               if (infeasible(start)) {
+                    cost_[start] = thisFeasibleCost - infeasibilityWeight_;
+                    cost_[start+1] = thisFeasibleCost;
+               } else {
+                    cost_[start] = thisFeasibleCost;
+               }
+               if (infeasible(end - 1)) {
+                    cost_[end-1] = thisFeasibleCost + infeasibilityWeight_;
+               }
+          }
+     }
+     if (CLP_METHOD2) {
+          for (int iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
+               cost2_[iSequence] = cost[iSequence];
+          }
+     }
+}
+ClpNonLinearCost::ClpNonLinearCost(ClpSimplex * model, const int * starts,
+                                   const double * lowerNon, const double * costNon)
+{
+#ifndef FAST_CLPNON
+     // what about scaling? - only try without it initially
+     assert(!model->scalingFlag());
+     model_ = model;
+     numberRows_ = model_->numberRows();
+     numberColumns_ = model_->numberColumns();
+     int numberTotal = numberRows_ + numberColumns_;
+     convex_ = true;
+     bothWays_ = true;
+     start_ = new int [numberTotal+1];
+     whichRange_ = new int [numberTotal];
+     offset_ = new int [numberTotal];
+     memset(offset_, 0, numberTotal * sizeof(int));
+
+     double whichWay = model_->optimizationDirection();
+     COIN_DETAIL_PRINT(printf("Direction %g\n", whichWay));
+
+     numberInfeasibilities_ = 0;
+     changeCost_ = 0.0;
+     feasibleCost_ = 0.0;
+     double infeasibilityCost = model_->infeasibilityCost();
+     infeasibilityWeight_ = infeasibilityCost;;
+     largestInfeasibility_ = 0.0;
+     sumInfeasibilities_ = 0.0;
+
+     int iSequence;
+     assert (!model_->rowObjective());
+     double * cost = model_->objective();
+
+     // First see how much space we need
+     // Also set up feasible bounds
+     int put = starts[numberColumns_];
+
+     double * columnUpper = model_->columnUpper();
+     double * columnLower = model_->columnLower();
+     for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+          if (columnLower[iSequence] > -1.0e20)
+               put++;
+          if (columnUpper[iSequence] < 1.0e20)
+               put++;
+     }
+
+     double * rowUpper = model_->rowUpper();
+     double * rowLower = model_->rowLower();
+     for (iSequence = 0; iSequence < numberRows_; iSequence++) {
+          if (rowLower[iSequence] > -1.0e20)
+               put++;
+          if (rowUpper[iSequence] < 1.0e20)
+               put++;
+          put += 2;
+     }
+     lower_ = new double [put];
+     cost_ = new double [put];
+     infeasible_ = new unsigned int[(put+31)>>5];
+     memset(infeasible_, 0, ((put + 31) >> 5)*sizeof(unsigned int));
+
+     // now fill in
+     put = 0;
+
+     start_[0] = 0;
+     for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+          lower_[put] = -COIN_DBL_MAX;
+          whichRange_[iSequence] = put + 1;
+          double thisCost;
+          double lowerValue;
+          double upperValue;
+          if (iSequence >= numberColumns_) {
+               // rows
+               lowerValue = rowLower[iSequence-numberColumns_];
+               upperValue = rowUpper[iSequence-numberColumns_];
+               if (lowerValue > -1.0e30) {
+                    setInfeasible(put, true);
+                    cost_[put++] = -infeasibilityCost;
+                    lower_[put] = lowerValue;
+               }
+               cost_[put++] = 0.0;
+               thisCost = 0.0;
+          } else {
+               // columns - move costs and see if convex
+               lowerValue = columnLower[iSequence];
+               upperValue = columnUpper[iSequence];
+               if (lowerValue > -1.0e30) {
+                    setInfeasible(put, true);
+                    cost_[put++] = whichWay * cost[iSequence] - infeasibilityCost;
+                    lower_[put] = lowerValue;
+               }
+               int iIndex = starts[iSequence];
+               int end = starts[iSequence+1];
+               assert (fabs(columnLower[iSequence] - lowerNon[iIndex]) < 1.0e-8);
+               thisCost = -COIN_DBL_MAX;
+               for (; iIndex < end; iIndex++) {
+                    if (lowerNon[iIndex] < columnUpper[iSequence] - 1.0e-8) {
+                         lower_[put] = lowerNon[iIndex];
+                         cost_[put++] = whichWay * costNon[iIndex];
+                         // check convexity
+                         if (whichWay * costNon[iIndex] < thisCost - 1.0e-12)
+                              convex_ = false;
+                         thisCost = whichWay * costNon[iIndex];
+                    } else {
+                         break;
+                    }
+               }
+          }
+          lower_[put] = upperValue;
+          setInfeasible(put, true);
+          cost_[put++] = thisCost + infeasibilityCost;
+          if (upperValue < 1.0e20) {
+               lower_[put] = COIN_DBL_MAX;
+               cost_[put++] = 1.0e50;
+          }
+          int iFirst = start_[iSequence];
+          if (lower_[iFirst] != -COIN_DBL_MAX) {
+               setInfeasible(iFirst, true);
+               whichRange_[iSequence] = iFirst + 1;
+          } else {
+               whichRange_[iSequence] = iFirst;
+          }
+          start_[iSequence+1] = put;
+     }
+     // can't handle non-convex at present
+     assert(convex_);
+     status_ = NULL;
+     bound_ = NULL;
+     cost2_ = NULL;
+     method_ = 1;
+#else
+     printf("recompile ClpNonLinearCost without FAST_CLPNON\n");
+     abort();
+#endif
+}
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpNonLinearCost::ClpNonLinearCost (const ClpNonLinearCost & rhs) :
+     changeCost_(0.0),
+     feasibleCost_(0.0),
+     infeasibilityWeight_(-1.0),
+     largestInfeasibility_(0.0),
+     sumInfeasibilities_(0.0),
+     averageTheta_(0.0),
+     numberRows_(rhs.numberRows_),
+     numberColumns_(rhs.numberColumns_),
+     start_(NULL),
+     whichRange_(NULL),
+     offset_(NULL),
+     lower_(NULL),
+     cost_(NULL),
+     model_(NULL),
+     infeasible_(NULL),
+     numberInfeasibilities_(-1),
+     status_(NULL),
+     bound_(NULL),
+     cost2_(NULL),
+     method_(rhs.method_),
+     convex_(true),
+     bothWays_(rhs.bothWays_)
+{
+     if (numberRows_) {
+          int numberTotal = numberRows_ + numberColumns_;
+          model_ = rhs.model_;
+          numberInfeasibilities_ = rhs.numberInfeasibilities_;
+          changeCost_ = rhs.changeCost_;
+          feasibleCost_ = rhs.feasibleCost_;
+          infeasibilityWeight_ = rhs.infeasibilityWeight_;
+          largestInfeasibility_ = rhs.largestInfeasibility_;
+          sumInfeasibilities_ = rhs.sumInfeasibilities_;
+          averageTheta_ = rhs.averageTheta_;
+          convex_ = rhs.convex_;
+          if (CLP_METHOD1) {
+               start_ = new int [numberTotal+1];
+               CoinMemcpyN(rhs.start_, (numberTotal + 1), start_);
+               whichRange_ = new int [numberTotal];
+               CoinMemcpyN(rhs.whichRange_, numberTotal, whichRange_);
+               offset_ = new int [numberTotal];
+               CoinMemcpyN(rhs.offset_, numberTotal, offset_);
+               int numberEntries = start_[numberTotal];
+               lower_ = new double [numberEntries];
+               CoinMemcpyN(rhs.lower_, numberEntries, lower_);
+               cost_ = new double [numberEntries];
+               CoinMemcpyN(rhs.cost_, numberEntries, cost_);
+               infeasible_ = new unsigned int[(numberEntries+31)>>5];
+               CoinMemcpyN(rhs.infeasible_, ((numberEntries + 31) >> 5), infeasible_);
+          }
+          if (CLP_METHOD2) {
+               bound_ = CoinCopyOfArray(rhs.bound_, numberTotal);
+               cost2_ = CoinCopyOfArray(rhs.cost2_, numberTotal);
+               status_ = CoinCopyOfArray(rhs.status_, numberTotal);
+          }
+     }
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpNonLinearCost::~ClpNonLinearCost ()
+{
+     delete [] start_;
+     delete [] whichRange_;
+     delete [] offset_;
+     delete [] lower_;
+     delete [] cost_;
+     delete [] infeasible_;
+     delete [] status_;
+     delete [] bound_;
+     delete [] cost2_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpNonLinearCost &
+ClpNonLinearCost::operator=(const ClpNonLinearCost& rhs)
+{
+     if (this != &rhs) {
+          numberRows_ = rhs.numberRows_;
+          numberColumns_ = rhs.numberColumns_;
+          delete [] start_;
+          delete [] whichRange_;
+          delete [] offset_;
+          delete [] lower_;
+          delete [] cost_;
+          delete [] infeasible_;
+          delete [] status_;
+          delete [] bound_;
+          delete [] cost2_;
+          start_ = NULL;
+          whichRange_ = NULL;
+          lower_ = NULL;
+          cost_ = NULL;
+          infeasible_ = NULL;
+          status_ = NULL;
+          bound_ = NULL;
+          cost2_ = NULL;
+          method_ = rhs.method_;
+          if (numberRows_) {
+               int numberTotal = numberRows_ + numberColumns_;
+               if (CLP_METHOD1) {
+                    start_ = new int [numberTotal+1];
+                    CoinMemcpyN(rhs.start_, (numberTotal + 1), start_);
+                    whichRange_ = new int [numberTotal];
+                    CoinMemcpyN(rhs.whichRange_, numberTotal, whichRange_);
+                    offset_ = new int [numberTotal];
+                    CoinMemcpyN(rhs.offset_, numberTotal, offset_);
+                    int numberEntries = start_[numberTotal];
+                    lower_ = new double [numberEntries];
+                    CoinMemcpyN(rhs.lower_, numberEntries, lower_);
+                    cost_ = new double [numberEntries];
+                    CoinMemcpyN(rhs.cost_, numberEntries, cost_);
+                    infeasible_ = new unsigned int[(numberEntries+31)>>5];
+                    CoinMemcpyN(rhs.infeasible_, ((numberEntries + 31) >> 5), infeasible_);
+               }
+               if (CLP_METHOD2) {
+                    bound_ = CoinCopyOfArray(rhs.bound_, numberTotal);
+                    cost2_ = CoinCopyOfArray(rhs.cost2_, numberTotal);
+                    status_ = CoinCopyOfArray(rhs.status_, numberTotal);
+               }
+          }
+          model_ = rhs.model_;
+          numberInfeasibilities_ = rhs.numberInfeasibilities_;
+          changeCost_ = rhs.changeCost_;
+          feasibleCost_ = rhs.feasibleCost_;
+          infeasibilityWeight_ = rhs.infeasibilityWeight_;
+          largestInfeasibility_ = rhs.largestInfeasibility_;
+          sumInfeasibilities_ = rhs.sumInfeasibilities_;
+          averageTheta_ = rhs.averageTheta_;
+          convex_ = rhs.convex_;
+          bothWays_ = rhs.bothWays_;
+     }
+     return *this;
+}
+// Changes infeasible costs and computes number and cost of infeas
+// We will need to re-think objective offsets later
+// We will also need a 2 bit per variable array for some
+// purpose which will come to me later
+void
+ClpNonLinearCost::checkInfeasibilities(double oldTolerance)
+{
+     numberInfeasibilities_ = 0;
+     double infeasibilityCost = model_->infeasibilityCost();
+     changeCost_ = 0.0;
+     largestInfeasibility_ = 0.0;
+     sumInfeasibilities_ = 0.0;
+     double primalTolerance = model_->currentPrimalTolerance();
+     int iSequence;
+     double * solution = model_->solutionRegion();
+     double * upper = model_->upperRegion();
+     double * lower = model_->lowerRegion();
+     double * cost = model_->costRegion();
+     bool toNearest = oldTolerance <= 0.0;
+     feasibleCost_ = 0.0;
+     //bool checkCosts = (infeasibilityWeight_ != infeasibilityCost);
+     infeasibilityWeight_ = infeasibilityCost;
+     int numberTotal = numberColumns_ + numberRows_;
+     //#define NONLIN_DEBUG
+#ifdef NONLIN_DEBUG
+     double * saveSolution = NULL;
+     double * saveLower = NULL;
+     double * saveUpper = NULL;
+     unsigned char * saveStatus = NULL;
+     if (method_ == 3) {
+          // Save solution as we will be checking
+          saveSolution = CoinCopyOfArray(solution, numberTotal);
+          saveLower = CoinCopyOfArray(lower, numberTotal);
+          saveUpper = CoinCopyOfArray(upper, numberTotal);
+          saveStatus = CoinCopyOfArray(model_->statusArray(), numberTotal);
+     }
+#else
+     assert (method_ != 3);
+#endif
+     if (CLP_METHOD1) {
+          // nonbasic should be at a valid bound
+          for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+               double lowerValue;
+               double upperValue;
+               double value = solution[iSequence];
+               int iRange;
+               // get correct place
+               int start = start_[iSequence];
+               int end = start_[iSequence+1] - 1;
+               // correct costs for this infeasibility weight
+               // If free then true cost will be first
+               double thisFeasibleCost = cost_[start];
+               if (infeasible(start)) {
+                    thisFeasibleCost = cost_[start+1];
+                    cost_[start] = thisFeasibleCost - infeasibilityCost;
+               }
+               if (infeasible(end - 1)) {
+                    thisFeasibleCost = cost_[end-2];
+                    cost_[end-1] = thisFeasibleCost + infeasibilityCost;
+               }
+               for (iRange = start; iRange < end; iRange++) {
+                    if (value < lower_[iRange+1] + primalTolerance) {
+                         // put in better range if infeasible
+                         if (value >= lower_[iRange+1] - primalTolerance && infeasible(iRange) && iRange == start)
+                              iRange++;
+                         whichRange_[iSequence] = iRange;
+                         break;
+                    }
+               }
+               assert(iRange < end);
+               lowerValue = lower_[iRange];
+               upperValue = lower_[iRange+1];
+               ClpSimplex::Status status = model_->getStatus(iSequence);
+               if (upperValue == lowerValue && status != ClpSimplex::isFixed) {
+                    if (status != ClpSimplex::basic) {
+                         model_->setStatus(iSequence, ClpSimplex::isFixed);
+                         status = ClpSimplex::isFixed;
+                    }
+               }
+	       //#define PRINT_DETAIL7 2
+#if PRINT_DETAIL7>1
+	       printf("NL %d sol %g bounds %g %g\n",
+		      iSequence,solution[iSequence],
+		      lowerValue,upperValue);
+#endif
+               switch(status) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::superBasic:
+                    // iRange is in correct place
+                    // slot in here
+                    if (infeasible(iRange)) {
+                         if (lower_[iRange] < -1.0e50) {
+                              //cost_[iRange] = cost_[iRange+1]-infeasibilityCost;
+                              // possibly below
+                              lowerValue = lower_[iRange+1];
+                              if (value - lowerValue < -primalTolerance) {
+                                   value = lowerValue - value - primalTolerance;
+#ifndef NDEBUG
+                                   if(value > 1.0e15)
+                                        printf("nonlincostb %d %g %g %g\n",
+                                               iSequence, lowerValue, solution[iSequence], lower_[iRange+2]);
+#endif
+#if PRINT_DETAIL7
+				   printf("**NL %d sol %g below %g\n",
+					  iSequence,solution[iSequence],
+					  lowerValue);
+#endif
+                                   sumInfeasibilities_ += value;
+                                   largestInfeasibility_ = CoinMax(largestInfeasibility_, value);
+                                   changeCost_ -= lowerValue *
+                                                  (cost_[iRange] - cost[iSequence]);
+                                   numberInfeasibilities_++;
+                              }
+                         } else {
+                              //cost_[iRange] = cost_[iRange-1]+infeasibilityCost;
+                              // possibly above
+                              upperValue = lower_[iRange];
+                              if (value - upperValue > primalTolerance) {
+                                   value = value - upperValue - primalTolerance;
+#ifndef NDEBUG
+                                   if(value > 1.0e15)
+                                        printf("nonlincostu %d %g %g %g\n",
+                                               iSequence, lower_[iRange-1], solution[iSequence], upperValue);
+#endif
+#if PRINT_DETAIL7
+				   printf("**NL %d sol %g above %g\n",
+					  iSequence,solution[iSequence],
+					  upperValue);
+#endif
+                                   sumInfeasibilities_ += value;
+                                   largestInfeasibility_ = CoinMax(largestInfeasibility_, value);
+                                   changeCost_ -= upperValue *
+                                                  (cost_[iRange] - cost[iSequence]);
+                                   numberInfeasibilities_++;
+                              }
+                         }
+                    }
+                    //lower[iSequence] = lower_[iRange];
+                    //upper[iSequence] = lower_[iRange+1];
+                    //cost[iSequence] = cost_[iRange];
+                    break;
+               case ClpSimplex::isFree:
+                    //if (toNearest)
+                    //solution[iSequence] = 0.0;
+                    break;
+               case ClpSimplex::atUpperBound:
+                    if (!toNearest) {
+                         // With increasing tolerances - we may be at wrong place
+                         if (fabs(value - upperValue) > oldTolerance * 1.0001) {
+                              if (fabs(value - lowerValue) <= oldTolerance * 1.0001) {
+                                   if  (fabs(value - lowerValue) > primalTolerance)
+                                        solution[iSequence] = lowerValue;
+                                   model_->setStatus(iSequence, ClpSimplex::atLowerBound);
+                              } else {
+                                   model_->setStatus(iSequence, ClpSimplex::superBasic);
+                              }
+                         } else if  (fabs(value - upperValue) > primalTolerance) {
+                              solution[iSequence] = upperValue;
+                         }
+                    } else {
+                         // Set to nearest and make at upper bound
+                         int kRange;
+                         iRange = -1;
+                         double nearest = COIN_DBL_MAX;
+                         for (kRange = start; kRange < end; kRange++) {
+                              if (fabs(lower_[kRange] - value) < nearest) {
+                                   nearest = fabs(lower_[kRange] - value);
+                                   iRange = kRange;
+                              }
+                         }
+                         assert (iRange >= 0);
+                         iRange--;
+                         whichRange_[iSequence] = iRange;
+                         solution[iSequence] = lower_[iRange+1];
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    if (!toNearest) {
+                         // With increasing tolerances - we may be at wrong place
+                         // below stops compiler error with gcc 3.2!!!
+                         if (iSequence == -119)
+                              printf("ZZ %g %g %g %g\n", lowerValue, value, upperValue, oldTolerance);
+                         if (fabs(value - lowerValue) > oldTolerance * 1.0001) {
+                              if (fabs(value - upperValue) <= oldTolerance * 1.0001) {
+                                   if  (fabs(value - upperValue) > primalTolerance)
+                                        solution[iSequence] = upperValue;
+                                   model_->setStatus(iSequence, ClpSimplex::atUpperBound);
+                              } else {
+                                   model_->setStatus(iSequence, ClpSimplex::superBasic);
+                              }
+                         } else if  (fabs(value - lowerValue) > primalTolerance) {
+                              solution[iSequence] = lowerValue;
+                         }
+                    } else {
+                         // Set to nearest and make at lower bound
+                         int kRange;
+                         iRange = -1;
+                         double nearest = COIN_DBL_MAX;
+                         for (kRange = start; kRange < end; kRange++) {
+                              if (fabs(lower_[kRange] - value) < nearest) {
+                                   nearest = fabs(lower_[kRange] - value);
+                                   iRange = kRange;
+                              }
+                         }
+                         assert (iRange >= 0);
+                         whichRange_[iSequence] = iRange;
+                         solution[iSequence] = lower_[iRange];
+                    }
+                    break;
+               case ClpSimplex::isFixed:
+                    if (toNearest) {
+                         // Set to true fixed
+                         for (iRange = start; iRange < end; iRange++) {
+                              if (lower_[iRange] == lower_[iRange+1])
+                                   break;
+                         }
+                         if (iRange == end) {
+                              // Odd - but make sensible
+                              // Set to nearest and make at lower bound
+                              int kRange;
+                              iRange = -1;
+                              double nearest = COIN_DBL_MAX;
+                              for (kRange = start; kRange < end; kRange++) {
+                                   if (fabs(lower_[kRange] - value) < nearest) {
+                                        nearest = fabs(lower_[kRange] - value);
+                                        iRange = kRange;
+                                   }
+                              }
+                              assert (iRange >= 0);
+                              whichRange_[iSequence] = iRange;
+                              if (lower_[iRange] != lower_[iRange+1])
+                                   model_->setStatus(iSequence, ClpSimplex::atLowerBound);
+                              else
+                                   model_->setStatus(iSequence, ClpSimplex::atUpperBound);
+                         }
+                         solution[iSequence] = lower_[iRange];
+                    }
+                    break;
+               }
+               lower[iSequence] = lower_[iRange];
+               upper[iSequence] = lower_[iRange+1];
+               cost[iSequence] = cost_[iRange];
+               feasibleCost_ += thisFeasibleCost * solution[iSequence];
+               //assert (iRange==whichRange_[iSequence]);
+          }
+     }
+#ifdef NONLIN_DEBUG
+     double saveCost = feasibleCost_;
+     if (method_ == 3) {
+          feasibleCost_ = 0.0;
+          // Put back solution as we will be checking
+          unsigned char * statusA = model_->statusArray();
+          for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+               double value = solution[iSequence];
+               solution[iSequence] = saveSolution[iSequence];
+               saveSolution[iSequence] = value;
+               value = lower[iSequence];
+               lower[iSequence] = saveLower[iSequence];
+               saveLower[iSequence] = value;
+               value = upper[iSequence];
+               upper[iSequence] = saveUpper[iSequence];
+               saveUpper[iSequence] = value;
+               unsigned char value2 = statusA[iSequence];
+               statusA[iSequence] = saveStatus[iSequence];
+               saveStatus[iSequence] = value2;
+          }
+     }
+#endif
+     if (CLP_METHOD2) {
+       //#define CLP_NON_JUST_BASIC
+#ifndef CLP_NON_JUST_BASIC
+          // nonbasic should be at a valid bound
+          for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+#else
+	  const int * pivotVariable = model_->pivotVariable();
+	  for (int i=0;i<numberRows_;i++) {
+	    int iSequence = pivotVariable[i];
+#endif
+               double value = solution[iSequence];
+               unsigned char iStatus = status_[iSequence];
+               assert (currentStatus(iStatus) == CLP_SAME);
+               double lowerValue = lower[iSequence];
+               double upperValue = upper[iSequence];
+               double costValue = cost2_[iSequence];
+               double trueCost = costValue;
+               int iWhere = originalStatus(iStatus);
+               if (iWhere == CLP_BELOW_LOWER) {
+                    lowerValue = upperValue;
+                    upperValue = bound_[iSequence];
+                    costValue -= infeasibilityCost;
+               } else if (iWhere == CLP_ABOVE_UPPER) {
+                    upperValue = lowerValue;
+                    lowerValue = bound_[iSequence];
+                    costValue += infeasibilityCost;
+               }
+               // get correct place
+               int newWhere = CLP_FEASIBLE;
+               ClpSimplex::Status status = model_->getStatus(iSequence);
+               if (upperValue == lowerValue && status != ClpSimplex::isFixed) {
+                    if (status != ClpSimplex::basic) {
+                         model_->setStatus(iSequence, ClpSimplex::isFixed);
+                         status = ClpSimplex::isFixed;
+                    }
+               }
+               switch(status) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::superBasic:
+                    if (value - upperValue <= primalTolerance) {
+                         if (value - lowerValue >= -primalTolerance) {
+                              // feasible
+                              //newWhere=CLP_FEASIBLE;
+                         } else {
+                              // below
+                              newWhere = CLP_BELOW_LOWER;
+                              assert (fabs(lowerValue) < 1.0e100);
+                              double infeasibility = lowerValue - value - primalTolerance;
+                              sumInfeasibilities_ += infeasibility;
+                              largestInfeasibility_ = CoinMax(largestInfeasibility_, infeasibility);
+                              costValue = trueCost - infeasibilityCost;
+                              changeCost_ -= lowerValue * (costValue - cost[iSequence]);
+                              numberInfeasibilities_++;
+                         }
+                    } else {
+                         // above
+                         newWhere = CLP_ABOVE_UPPER;
+                         double infeasibility = value - upperValue - primalTolerance;
+                         sumInfeasibilities_ += infeasibility;
+                         largestInfeasibility_ = CoinMax(largestInfeasibility_, infeasibility);
+                         costValue = trueCost + infeasibilityCost;
+                         changeCost_ -= upperValue * (costValue - cost[iSequence]);
+                         numberInfeasibilities_++;
+                    }
+                    break;
+               case ClpSimplex::isFree:
+                    break;
+               case ClpSimplex::atUpperBound:
+                    if (!toNearest) {
+                         // With increasing tolerances - we may be at wrong place
+                         if (fabs(value - upperValue) > oldTolerance * 1.0001) {
+                              if (fabs(value - lowerValue) <= oldTolerance * 1.0001) {
+                                   if  (fabs(value - lowerValue) > primalTolerance) {
+                                        solution[iSequence] = lowerValue;
+                                        value = lowerValue;
+                                   }
+                                   model_->setStatus(iSequence, ClpSimplex::atLowerBound);
+                              } else {
+                                   if (value < upperValue) {
+                                        if (value > lowerValue) {
+                                             model_->setStatus(iSequence, ClpSimplex::superBasic);
+                                        } else {
+                                             // set to lower bound as infeasible
+                                             solution[iSequence] = lowerValue;
+                                             value = lowerValue;
+                                             model_->setStatus(iSequence, ClpSimplex::atLowerBound);
+                                        }
+                                   } else {
+                                        // set to upper bound as infeasible
+                                        solution[iSequence] = upperValue;
+                                        value = upperValue;
+                                   }
+                              }
+                         } else if  (fabs(value - upperValue) > primalTolerance) {
+                              solution[iSequence] = upperValue;
+                              value = upperValue;
+                         }
+                    } else {
+                         // Set to nearest and make at bound
+                         if (fabs(value - lowerValue) < fabs(value - upperValue)) {
+                              solution[iSequence] = lowerValue;
+                              value = lowerValue;
+                              model_->setStatus(iSequence, ClpSimplex::atLowerBound);
+                         } else {
+                              solution[iSequence] = upperValue;
+                              value = upperValue;
+                         }
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    if (!toNearest) {
+                         // With increasing tolerances - we may be at wrong place
+                         if (fabs(value - lowerValue) > oldTolerance * 1.0001) {
+                              if (fabs(value - upperValue) <= oldTolerance * 1.0001) {
+                                   if  (fabs(value - upperValue) > primalTolerance) {
+                                        solution[iSequence] = upperValue;
+                                        value = upperValue;
+                                   }
+                                   model_->setStatus(iSequence, ClpSimplex::atUpperBound);
+                              } else {
+                                   if (value < upperValue) {
+                                        if (value > lowerValue) {
+                                             model_->setStatus(iSequence, ClpSimplex::superBasic);
+                                        } else {
+                                             // set to lower bound as infeasible
+                                             solution[iSequence] = lowerValue;
+                                             value = lowerValue;
+                                        }
+                                   } else {
+                                        // set to upper bound as infeasible
+                                        solution[iSequence] = upperValue;
+                                        value = upperValue;
+                                        model_->setStatus(iSequence, ClpSimplex::atUpperBound);
+                                   }
+                              }
+                         } else if  (fabs(value - lowerValue) > primalTolerance) {
+                              solution[iSequence] = lowerValue;
+                              value = lowerValue;
+                         }
+                    } else {
+                         // Set to nearest and make at bound
+                         if (fabs(value - lowerValue) < fabs(value - upperValue)) {
+                              solution[iSequence] = lowerValue;
+                              value = lowerValue;
+                         } else {
+                              solution[iSequence] = upperValue;
+                              value = upperValue;
+                              model_->setStatus(iSequence, ClpSimplex::atUpperBound);
+                         }
+                    }
+                    break;
+               case ClpSimplex::isFixed:
+                    solution[iSequence] = lowerValue;
+                    value = lowerValue;
+                    break;
+               }
+#ifdef NONLIN_DEBUG
+               double lo = saveLower[iSequence];
+               double up = saveUpper[iSequence];
+               double cc = cost[iSequence];
+               unsigned char ss = saveStatus[iSequence];
+               unsigned char snow = model_->statusArray()[iSequence];
+#endif
+               if (iWhere != newWhere) {
+                    setOriginalStatus(status_[iSequence], newWhere);
+                    if (newWhere == CLP_BELOW_LOWER) {
+                         bound_[iSequence] = upperValue;
+                         upperValue = lowerValue;
+                         lowerValue = -COIN_DBL_MAX;
+                         costValue = trueCost - infeasibilityCost;
+                    } else if (newWhere == CLP_ABOVE_UPPER) {
+                         bound_[iSequence] = lowerValue;
+                         lowerValue = upperValue;
+                         upperValue = COIN_DBL_MAX;
+                         costValue = trueCost + infeasibilityCost;
+                    } else {
+                         costValue = trueCost;
+                    }
+                    lower[iSequence] = lowerValue;
+                    upper[iSequence] = upperValue;
+               }
+               // always do as other things may change
+               cost[iSequence] = costValue;
+#ifdef NONLIN_DEBUG
+               if (method_ == 3) {
+                    assert (ss == snow);
+                    assert (cc == cost[iSequence]);
+                    assert (lo == lower[iSequence]);
+                    assert (up == upper[iSequence]);
+                    assert (value == saveSolution[iSequence]);
+               }
+#endif
+               feasibleCost_ += trueCost * value;
+          }
+     }
+#ifdef NONLIN_DEBUG
+     if (method_ == 3)
+          assert (fabs(saveCost - feasibleCost_) < 0.001 * (1.0 + CoinMax(fabs(saveCost), fabs(feasibleCost_))));
+     delete [] saveSolution;
+     delete [] saveLower;
+     delete [] saveUpper;
+     delete [] saveStatus;
+#endif
+     //feasibleCost_ /= (model_->rhsScale()*model_->objScale());
+}
+// Puts feasible bounds into lower and upper
+void
+ClpNonLinearCost::feasibleBounds()
+{
+     if (CLP_METHOD2) {
+          int iSequence;
+          double * upper = model_->upperRegion();
+          double * lower = model_->lowerRegion();
+          double * cost = model_->costRegion();
+          int numberTotal = numberColumns_ + numberRows_;
+          for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+               unsigned char iStatus = status_[iSequence];
+               assert (currentStatus(iStatus) == CLP_SAME);
+               double lowerValue = lower[iSequence];
+               double upperValue = upper[iSequence];
+               double costValue = cost2_[iSequence];
+               int iWhere = originalStatus(iStatus);
+               if (iWhere == CLP_BELOW_LOWER) {
+                    lowerValue = upperValue;
+                    upperValue = bound_[iSequence];
+                    assert (fabs(lowerValue) < 1.0e100);
+               } else if (iWhere == CLP_ABOVE_UPPER) {
+                    upperValue = lowerValue;
+                    lowerValue = bound_[iSequence];
+               }
+               setOriginalStatus(status_[iSequence], CLP_FEASIBLE);
+               lower[iSequence] = lowerValue;
+               upper[iSequence] = upperValue;
+               cost[iSequence] = costValue;
+          }
+     }
+}
+/* Goes through one bound for each variable.
+   If array[i]*multiplier>0 goes down, otherwise up.
+   The indices are row indices and need converting to sequences
+*/
+void
+ClpNonLinearCost::goThru(int numberInArray, double multiplier,
+                         const int * index, const double * array,
+                         double * rhs)
+{
+     assert (model_ != NULL);
+     abort();
+     const int * pivotVariable = model_->pivotVariable();
+     if (CLP_METHOD1) {
+          for (int i = 0; i < numberInArray; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               double alpha = multiplier * array[iRow];
+               // get where in bound sequence
+               int iRange = whichRange_[iSequence];
+               iRange += offset_[iSequence]; //add temporary bias
+               double value = model_->solution(iSequence);
+               if (alpha > 0.0) {
+                    // down one
+                    iRange--;
+                    assert(iRange >= start_[iSequence]);
+                    rhs[iRow] = value - lower_[iRange];
+               } else {
+                    // up one
+                    iRange++;
+                    assert(iRange < start_[iSequence+1] - 1);
+                    rhs[iRow] = lower_[iRange+1] - value;
+               }
+               offset_[iSequence] = iRange - whichRange_[iSequence];
+          }
+     }
+#ifdef NONLIN_DEBUG
+     double * saveRhs = NULL;
+     if (method_ == 3) {
+          int numberRows = model_->numberRows();
+          saveRhs = CoinCopyOfArray(rhs, numberRows);
+     }
+#endif
+     if (CLP_METHOD2) {
+          const double * solution = model_->solutionRegion();
+          const double * upper = model_->upperRegion();
+          const double * lower = model_->lowerRegion();
+          for (int i = 0; i < numberInArray; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               double alpha = multiplier * array[iRow];
+               double value = solution[iSequence];
+               unsigned char iStatus = status_[iSequence];
+               int iWhere = currentStatus(iStatus);
+               if (iWhere == CLP_SAME)
+                    iWhere = originalStatus(iStatus);
+               if (iWhere == CLP_FEASIBLE) {
+                    if (alpha > 0.0) {
+                         // going below
+                         iWhere = CLP_BELOW_LOWER;
+                         rhs[iRow] = value - lower[iSequence];
+                    } else {
+                         // going above
+                         iWhere = CLP_ABOVE_UPPER;
+                         rhs[iRow] = upper[iSequence] - value;
+                    }
+               } else if(iWhere == CLP_BELOW_LOWER) {
+                    assert (alpha < 0);
+                    // going feasible
+                    iWhere = CLP_FEASIBLE;
+                    rhs[iRow] = upper[iSequence] - value;
+               } else {
+                    assert (iWhere == CLP_ABOVE_UPPER);
+                    // going feasible
+                    iWhere = CLP_FEASIBLE;
+                    rhs[iRow] = value - lower[iSequence];
+               }
+#ifdef NONLIN_DEBUG
+               if (method_ == 3)
+                    assert (rhs[iRow] == saveRhs[iRow]);
+#endif
+               setCurrentStatus(status_[iSequence], iWhere);
+          }
+     }
+#ifdef NONLIN_DEBUG
+     delete [] saveRhs;
+#endif
+}
+/* Takes off last iteration (i.e. offsets closer to 0)
+ */
+void
+ClpNonLinearCost::goBack(int numberInArray, const int * index,
+                         double * rhs)
+{
+     assert (model_ != NULL);
+     abort();
+     const int * pivotVariable = model_->pivotVariable();
+     if (CLP_METHOD1) {
+          for (int i = 0; i < numberInArray; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               // get where in bound sequence
+               int iRange = whichRange_[iSequence];
+               // get closer to original
+               if (offset_[iSequence] > 0) {
+                    offset_[iSequence]--;
+                    assert (offset_[iSequence] >= 0);
+                    iRange += offset_[iSequence]; //add temporary bias
+                    double value = model_->solution(iSequence);
+                    // up one
+                    assert(iRange < start_[iSequence+1] - 1);
+                    rhs[iRow] = lower_[iRange+1] - value; // was earlier lower_[iRange]
+               } else {
+                    offset_[iSequence]++;
+                    assert (offset_[iSequence] <= 0);
+                    iRange += offset_[iSequence]; //add temporary bias
+                    double value = model_->solution(iSequence);
+                    // down one
+                    assert(iRange >= start_[iSequence]);
+                    rhs[iRow] = value - lower_[iRange]; // was earlier lower_[iRange+1]
+               }
+          }
+     }
+#ifdef NONLIN_DEBUG
+     double * saveRhs = NULL;
+     if (method_ == 3) {
+          int numberRows = model_->numberRows();
+          saveRhs = CoinCopyOfArray(rhs, numberRows);
+     }
+#endif
+     if (CLP_METHOD2) {
+          const double * solution = model_->solutionRegion();
+          const double * upper = model_->upperRegion();
+          const double * lower = model_->lowerRegion();
+          for (int i = 0; i < numberInArray; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               double value = solution[iSequence];
+               unsigned char iStatus = status_[iSequence];
+               int iWhere = currentStatus(iStatus);
+               int original = originalStatus(iStatus);
+               assert (iWhere != CLP_SAME);
+               if (iWhere == CLP_FEASIBLE) {
+                    if (original == CLP_BELOW_LOWER) {
+                         // going below
+                         iWhere = CLP_BELOW_LOWER;
+                         rhs[iRow] = lower[iSequence] - value;
+                    } else {
+                         // going above
+                         iWhere = CLP_ABOVE_UPPER;
+                         rhs[iRow] = value - upper[iSequence];
+                    }
+               } else if(iWhere == CLP_BELOW_LOWER) {
+                    // going feasible
+                    iWhere = CLP_FEASIBLE;
+                    rhs[iRow] = value - upper[iSequence];
+               } else {
+                    // going feasible
+                    iWhere = CLP_FEASIBLE;
+                    rhs[iRow] = lower[iSequence] - value;
+               }
+#ifdef NONLIN_DEBUG
+               if (method_ == 3)
+                    assert (rhs[iRow] == saveRhs[iRow]);
+#endif
+               setCurrentStatus(status_[iSequence], iWhere);
+          }
+     }
+#ifdef NONLIN_DEBUG
+     delete [] saveRhs;
+#endif
+}
+void
+ClpNonLinearCost::goBackAll(const CoinIndexedVector * update)
+{
+     assert (model_ != NULL);
+     const int * pivotVariable = model_->pivotVariable();
+     int number = update->getNumElements();
+     const int * index = update->getIndices();
+     if (CLP_METHOD1) {
+          for (int i = 0; i < number; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               offset_[iSequence] = 0;
+          }
+#ifdef CLP_DEBUG
+          for (i = 0; i < numberRows_ + numberColumns_; i++)
+               assert(!offset_[i]);
+#endif
+     }
+     if (CLP_METHOD2) {
+          for (int i = 0; i < number; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               setSameStatus(status_[iSequence]);
+          }
+     }
+}
+void
+ClpNonLinearCost::checkInfeasibilities(int numberInArray, const int * index)
+{
+     assert (model_ != NULL);
+     double primalTolerance = model_->currentPrimalTolerance();
+     const int * pivotVariable = model_->pivotVariable();
+     if (CLP_METHOD1) {
+          for (int i = 0; i < numberInArray; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               // get where in bound sequence
+               int iRange;
+               int currentRange = whichRange_[iSequence];
+               double value = model_->solution(iSequence);
+               int start = start_[iSequence];
+               int end = start_[iSequence+1] - 1;
+               for (iRange = start; iRange < end; iRange++) {
+                    if (value < lower_[iRange+1] + primalTolerance) {
+                         // put in better range
+                         if (value >= lower_[iRange+1] - primalTolerance && infeasible(iRange) && iRange == start)
+                              iRange++;
+                         break;
+                    }
+               }
+               assert(iRange < end);
+               assert(model_->getStatus(iSequence) == ClpSimplex::basic);
+               double & lower = model_->lowerAddress(iSequence);
+               double & upper = model_->upperAddress(iSequence);
+               double & cost = model_->costAddress(iSequence);
+               whichRange_[iSequence] = iRange;
+               if (iRange != currentRange) {
+                    if (infeasible(iRange))
+                         numberInfeasibilities_++;
+                    if (infeasible(currentRange))
+                         numberInfeasibilities_--;
+               }
+               lower = lower_[iRange];
+               upper = lower_[iRange+1];
+               cost = cost_[iRange];
+          }
+     }
+     if (CLP_METHOD2) {
+          double * solution = model_->solutionRegion();
+          double * upper = model_->upperRegion();
+          double * lower = model_->lowerRegion();
+          double * cost = model_->costRegion();
+          for (int i = 0; i < numberInArray; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               double value = solution[iSequence];
+               unsigned char iStatus = status_[iSequence];
+               assert (currentStatus(iStatus) == CLP_SAME);
+               double lowerValue = lower[iSequence];
+               double upperValue = upper[iSequence];
+               double costValue = cost2_[iSequence];
+               int iWhere = originalStatus(iStatus);
+               if (iWhere == CLP_BELOW_LOWER) {
+                    lowerValue = upperValue;
+                    upperValue = bound_[iSequence];
+                    numberInfeasibilities_--;
+                    assert (fabs(lowerValue) < 1.0e100);
+               } else if (iWhere == CLP_ABOVE_UPPER) {
+                    upperValue = lowerValue;
+                    lowerValue = bound_[iSequence];
+                    numberInfeasibilities_--;
+               }
+               // get correct place
+               int newWhere = CLP_FEASIBLE;
+               if (value - upperValue <= primalTolerance) {
+                    if (value - lowerValue >= -primalTolerance) {
+                         // feasible
+                         //newWhere=CLP_FEASIBLE;
+                    } else {
+                         // below
+                         newWhere = CLP_BELOW_LOWER;
+                         assert (fabs(lowerValue) < 1.0e100);
+                         costValue -= infeasibilityWeight_;
+                         numberInfeasibilities_++;
+                    }
+               } else {
+                    // above
+                    newWhere = CLP_ABOVE_UPPER;
+                    costValue += infeasibilityWeight_;
+                    numberInfeasibilities_++;
+               }
+               if (iWhere != newWhere) {
+                    setOriginalStatus(status_[iSequence], newWhere);
+                    if (newWhere == CLP_BELOW_LOWER) {
+                         bound_[iSequence] = upperValue;
+                         upperValue = lowerValue;
+                         lowerValue = -COIN_DBL_MAX;
+                    } else if (newWhere == CLP_ABOVE_UPPER) {
+                         bound_[iSequence] = lowerValue;
+                         lowerValue = upperValue;
+                         upperValue = COIN_DBL_MAX;
+                    }
+                    lower[iSequence] = lowerValue;
+                    upper[iSequence] = upperValue;
+                    cost[iSequence] = costValue;
+               }
+          }
+     }
+}
+/* Puts back correct infeasible costs for each variable
+   The input indices are row indices and need converting to sequences
+   for costs.
+   On input array is empty (but indices exist).  On exit just
+   changed costs will be stored as normal CoinIndexedVector
+*/
+void
+ClpNonLinearCost::checkChanged(int numberInArray, CoinIndexedVector * update)
+{
+     assert (model_ != NULL);
+     double primalTolerance = model_->currentPrimalTolerance();
+     const int * pivotVariable = model_->pivotVariable();
+     int number = 0;
+     int * index = update->getIndices();
+     double * work = update->denseVector();
+     if (CLP_METHOD1) {
+          for (int i = 0; i < numberInArray; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               // get where in bound sequence
+               int iRange;
+               double value = model_->solution(iSequence);
+               int start = start_[iSequence];
+               int end = start_[iSequence+1] - 1;
+               for (iRange = start; iRange < end; iRange++) {
+                    if (value < lower_[iRange+1] + primalTolerance) {
+                         // put in better range
+                         if (value >= lower_[iRange+1] - primalTolerance && infeasible(iRange) && iRange == start)
+                              iRange++;
+                         break;
+                    }
+               }
+               assert(iRange < end);
+               assert(model_->getStatus(iSequence) == ClpSimplex::basic);
+               int jRange = whichRange_[iSequence];
+               if (iRange != jRange) {
+                    // changed
+                    work[iRow] = cost_[jRange] - cost_[iRange];
+                    index[number++] = iRow;
+                    double & lower = model_->lowerAddress(iSequence);
+                    double & upper = model_->upperAddress(iSequence);
+                    double & cost = model_->costAddress(iSequence);
+                    whichRange_[iSequence] = iRange;
+                    if (infeasible(iRange))
+                         numberInfeasibilities_++;
+                    if (infeasible(jRange))
+                         numberInfeasibilities_--;
+                    lower = lower_[iRange];
+                    upper = lower_[iRange+1];
+                    cost = cost_[iRange];
+               }
+          }
+     }
+     if (CLP_METHOD2) {
+          double * solution = model_->solutionRegion();
+          double * upper = model_->upperRegion();
+          double * lower = model_->lowerRegion();
+          double * cost = model_->costRegion();
+          for (int i = 0; i < numberInArray; i++) {
+               int iRow = index[i];
+               int iSequence = pivotVariable[iRow];
+               double value = solution[iSequence];
+               unsigned char iStatus = status_[iSequence];
+               assert (currentStatus(iStatus) == CLP_SAME);
+               double lowerValue = lower[iSequence];
+               double upperValue = upper[iSequence];
+               double costValue = cost2_[iSequence];
+               int iWhere = originalStatus(iStatus);
+               if (iWhere == CLP_BELOW_LOWER) {
+                    lowerValue = upperValue;
+                    upperValue = bound_[iSequence];
+                    numberInfeasibilities_--;
+                    assert (fabs(lowerValue) < 1.0e100);
+               } else if (iWhere == CLP_ABOVE_UPPER) {
+                    upperValue = lowerValue;
+                    lowerValue = bound_[iSequence];
+                    numberInfeasibilities_--;
+               }
+               // get correct place
+               int newWhere = CLP_FEASIBLE;
+               if (value - upperValue <= primalTolerance) {
+                    if (value - lowerValue >= -primalTolerance) {
+                         // feasible
+                         //newWhere=CLP_FEASIBLE;
+                    } else {
+                         // below
+                         newWhere = CLP_BELOW_LOWER;
+                         costValue -= infeasibilityWeight_;
+                         numberInfeasibilities_++;
+                         assert (fabs(lowerValue) < 1.0e100);
+                    }
+               } else {
+                    // above
+                    newWhere = CLP_ABOVE_UPPER;
+                    costValue += infeasibilityWeight_;
+                    numberInfeasibilities_++;
+               }
+               if (iWhere != newWhere) {
+                    work[iRow] = cost[iSequence] - costValue;
+                    index[number++] = iRow;
+                    setOriginalStatus(status_[iSequence], newWhere);
+                    if (newWhere == CLP_BELOW_LOWER) {
+                         bound_[iSequence] = upperValue;
+                         upperValue = lowerValue;
+                         lowerValue = -COIN_DBL_MAX;
+                    } else if (newWhere == CLP_ABOVE_UPPER) {
+                         bound_[iSequence] = lowerValue;
+                         lowerValue = upperValue;
+                         upperValue = COIN_DBL_MAX;
+                    }
+                    lower[iSequence] = lowerValue;
+                    upper[iSequence] = upperValue;
+                    cost[iSequence] = costValue;
+               }
+          }
+     }
+     update->setNumElements(number);
+}
+/* Sets bounds and cost for one variable - returns change in cost*/
+double
+ClpNonLinearCost::setOne(int iSequence, double value)
+{
+     assert (model_ != NULL);
+     double primalTolerance = model_->currentPrimalTolerance();
+     // difference in cost
+     double difference = 0.0;
+     if (CLP_METHOD1) {
+          // get where in bound sequence
+          int iRange;
+          int currentRange = whichRange_[iSequence];
+          int start = start_[iSequence];
+          int end = start_[iSequence+1] - 1;
+          if (!bothWays_) {
+               // If fixed try and get feasible
+               if (lower_[start+1] == lower_[start+2] && fabs(value - lower_[start+1]) < 1.001 * primalTolerance) {
+                    iRange = start + 1;
+               } else {
+                    for (iRange = start; iRange < end; iRange++) {
+                         if (value <= lower_[iRange+1] + primalTolerance) {
+                              // put in better range
+                              if (value >= lower_[iRange+1] - primalTolerance && infeasible(iRange) && iRange == start)
+                                   iRange++;
+                              break;
+                         }
+                    }
+               }
+          } else {
+               // leave in current if possible
+               iRange = whichRange_[iSequence];
+               if (value < lower_[iRange] - primalTolerance || value > lower_[iRange+1] + primalTolerance) {
+                    for (iRange = start; iRange < end; iRange++) {
+                         if (value < lower_[iRange+1] + primalTolerance) {
+                              // put in better range
+                              if (value >= lower_[iRange+1] - primalTolerance && infeasible(iRange) && iRange == start)
+                                   iRange++;
+                              break;
+                         }
+                    }
+               }
+          }
+          assert(iRange < end);
+          whichRange_[iSequence] = iRange;
+          if (iRange != currentRange) {
+               if (infeasible(iRange))
+                    numberInfeasibilities_++;
+               if (infeasible(currentRange))
+                    numberInfeasibilities_--;
+          }
+          double & lower = model_->lowerAddress(iSequence);
+          double & upper = model_->upperAddress(iSequence);
+          double & cost = model_->costAddress(iSequence);
+          lower = lower_[iRange];
+          upper = lower_[iRange+1];
+          ClpSimplex::Status status = model_->getStatus(iSequence);
+          if (upper == lower) {
+               if (status != ClpSimplex::basic) {
+                    model_->setStatus(iSequence, ClpSimplex::isFixed);
+                    status = ClpSimplex::basic; // so will skip
+               }
+          }
+          switch(status) {
+
+          case ClpSimplex::basic:
+          case ClpSimplex::superBasic:
+          case ClpSimplex::isFree:
+               break;
+          case ClpSimplex::atUpperBound:
+          case ClpSimplex::atLowerBound:
+          case ClpSimplex::isFixed:
+               // set correctly
+               if (fabs(value - lower) <= primalTolerance * 1.001) {
+                    model_->setStatus(iSequence, ClpSimplex::atLowerBound);
+               } else if (fabs(value - upper) <= primalTolerance * 1.001) {
+                    model_->setStatus(iSequence, ClpSimplex::atUpperBound);
+               } else {
+                    // set superBasic
+                    model_->setStatus(iSequence, ClpSimplex::superBasic);
+               }
+               break;
+          }
+          difference = cost - cost_[iRange];
+          cost = cost_[iRange];
+     }
+     if (CLP_METHOD2) {
+          double * upper = model_->upperRegion();
+          double * lower = model_->lowerRegion();
+          double * cost = model_->costRegion();
+          unsigned char iStatus = status_[iSequence];
+          assert (currentStatus(iStatus) == CLP_SAME);
+          double lowerValue = lower[iSequence];
+          double upperValue = upper[iSequence];
+          double costValue = cost2_[iSequence];
+          int iWhere = originalStatus(iStatus);
+          if (iWhere == CLP_BELOW_LOWER) {
+               lowerValue = upperValue;
+               upperValue = bound_[iSequence];
+               numberInfeasibilities_--;
+               assert (fabs(lowerValue) < 1.0e100);
+          } else if (iWhere == CLP_ABOVE_UPPER) {
+               upperValue = lowerValue;
+               lowerValue = bound_[iSequence];
+               numberInfeasibilities_--;
+          }
+          // get correct place
+          int newWhere = CLP_FEASIBLE;
+          if (value - upperValue <= primalTolerance) {
+               if (value - lowerValue >= -primalTolerance) {
+                    // feasible
+                    //newWhere=CLP_FEASIBLE;
+               } else {
+                    // below
+                    newWhere = CLP_BELOW_LOWER;
+                    costValue -= infeasibilityWeight_;
+                    numberInfeasibilities_++;
+                    assert (fabs(lowerValue) < 1.0e100);
+               }
+          } else {
+               // above
+               newWhere = CLP_ABOVE_UPPER;
+               costValue += infeasibilityWeight_;
+               numberInfeasibilities_++;
+          }
+          if (iWhere != newWhere) {
+               difference = cost[iSequence] - costValue;
+               setOriginalStatus(status_[iSequence], newWhere);
+               if (newWhere == CLP_BELOW_LOWER) {
+                    bound_[iSequence] = upperValue;
+                    upperValue = lowerValue;
+                    lowerValue = -COIN_DBL_MAX;
+               } else if (newWhere == CLP_ABOVE_UPPER) {
+                    bound_[iSequence] = lowerValue;
+                    lowerValue = upperValue;
+                    upperValue = COIN_DBL_MAX;
+               }
+               lower[iSequence] = lowerValue;
+               upper[iSequence] = upperValue;
+               cost[iSequence] = costValue;
+          }
+          ClpSimplex::Status status = model_->getStatus(iSequence);
+          if (upperValue == lowerValue) {
+               if (status != ClpSimplex::basic) {
+                    model_->setStatus(iSequence, ClpSimplex::isFixed);
+                    status = ClpSimplex::basic; // so will skip
+               }
+          }
+          switch(status) {
+
+          case ClpSimplex::basic:
+          case ClpSimplex::superBasic:
+          case ClpSimplex::isFree:
+               break;
+          case ClpSimplex::atUpperBound:
+          case ClpSimplex::atLowerBound:
+          case ClpSimplex::isFixed:
+               // set correctly
+               if (fabs(value - lowerValue) <= primalTolerance * 1.001) {
+                    model_->setStatus(iSequence, ClpSimplex::atLowerBound);
+               } else if (fabs(value - upperValue) <= primalTolerance * 1.001) {
+                    model_->setStatus(iSequence, ClpSimplex::atUpperBound);
+               } else {
+                    // set superBasic
+                    model_->setStatus(iSequence, ClpSimplex::superBasic);
+               }
+               break;
+          }
+     }
+     changeCost_ += value * difference;
+     return difference;
+}
+/* Sets bounds and infeasible cost and true cost for one variable
+   This is for gub and column generation etc */
+void
+ClpNonLinearCost::setOne(int sequence, double solutionValue, double lowerValue, double upperValue,
+                         double costValue)
+{
+     if (CLP_METHOD1) {
+          int iRange = -1;
+          int start = start_[sequence];
+          double infeasibilityCost = model_->infeasibilityCost();
+          cost_[start] = costValue - infeasibilityCost;
+          lower_[start+1] = lowerValue;
+          cost_[start+1] = costValue;
+          lower_[start+2] = upperValue;
+          cost_[start+2] = costValue + infeasibilityCost;
+          double primalTolerance = model_->currentPrimalTolerance();
+          if (solutionValue - lowerValue >= -primalTolerance) {
+               if (solutionValue - upperValue <= primalTolerance) {
+                    iRange = start + 1;
+               } else {
+                    iRange = start + 2;
+               }
+          } else {
+               iRange = start;
+          }
+          model_->costRegion()[sequence] = cost_[iRange];
+          whichRange_[sequence] = iRange;
+     }
+     if (CLP_METHOD2) {
+       bound_[sequence]=0.0;
+       cost2_[sequence]=costValue;
+       setInitialStatus(status_[sequence]);
+     }
+
+}
+/* Sets bounds and cost for outgoing variable
+   may change value
+   Returns direction */
+int
+ClpNonLinearCost::setOneOutgoing(int iSequence, double & value)
+{
+     assert (model_ != NULL);
+     double primalTolerance = model_->currentPrimalTolerance();
+     // difference in cost
+     double difference = 0.0;
+     int direction = 0;
+     if (CLP_METHOD1) {
+          // get where in bound sequence
+          int iRange;
+          int currentRange = whichRange_[iSequence];
+          int start = start_[iSequence];
+          int end = start_[iSequence+1] - 1;
+          // Set perceived direction out
+          if (value <= lower_[currentRange] + 1.001 * primalTolerance) {
+               direction = 1;
+          } else if (value >= lower_[currentRange+1] - 1.001 * primalTolerance) {
+               direction = -1;
+          } else {
+               // odd
+               direction = 0;
+          }
+          // If fixed try and get feasible
+          if (lower_[start+1] == lower_[start+2] && fabs(value - lower_[start+1]) < 1.001 * primalTolerance) {
+               iRange = start + 1;
+          } else {
+               // See if exact
+               for (iRange = start; iRange < end; iRange++) {
+                    if (value == lower_[iRange+1]) {
+                         // put in better range
+                         if (infeasible(iRange) && iRange == start)
+                              iRange++;
+                         break;
+                    }
+               }
+               if (iRange == end) {
+                    // not exact
+                    for (iRange = start; iRange < end; iRange++) {
+                         if (value <= lower_[iRange+1] + primalTolerance) {
+                              // put in better range
+                              if (value >= lower_[iRange+1] - primalTolerance && infeasible(iRange) && iRange == start)
+                                   iRange++;
+                              break;
+                         }
+                    }
+               }
+          }
+          assert(iRange < end);
+          whichRange_[iSequence] = iRange;
+          if (iRange != currentRange) {
+               if (infeasible(iRange))
+                    numberInfeasibilities_++;
+               if (infeasible(currentRange))
+                    numberInfeasibilities_--;
+          }
+          double & lower = model_->lowerAddress(iSequence);
+          double & upper = model_->upperAddress(iSequence);
+          double & cost = model_->costAddress(iSequence);
+          lower = lower_[iRange];
+          upper = lower_[iRange+1];
+          if (upper == lower) {
+               value = upper;
+          } else {
+               // set correctly
+               if (fabs(value - lower) <= primalTolerance * 1.001) {
+                    value = CoinMin(value, lower + primalTolerance);
+               } else if (fabs(value - upper) <= primalTolerance * 1.001) {
+                    value = CoinMax(value, upper - primalTolerance);
+               } else {
+                    //printf("*** variable wandered off bound %g %g %g!\n",
+                    //     lower,value,upper);
+                    if (value - lower <= upper - value)
+                         value = lower + primalTolerance;
+                    else
+                         value = upper - primalTolerance;
+               }
+          }
+          difference = cost - cost_[iRange];
+          cost = cost_[iRange];
+     }
+     if (CLP_METHOD2) {
+          double * upper = model_->upperRegion();
+          double * lower = model_->lowerRegion();
+          double * cost = model_->costRegion();
+          unsigned char iStatus = status_[iSequence];
+          assert (currentStatus(iStatus) == CLP_SAME);
+          double lowerValue = lower[iSequence];
+          double upperValue = upper[iSequence];
+          double costValue = cost2_[iSequence];
+          // Set perceived direction out
+          if (value <= lowerValue + 1.001 * primalTolerance) {
+               direction = 1;
+          } else if (value >= upperValue - 1.001 * primalTolerance) {
+               direction = -1;
+          } else {
+               // odd
+               direction = 0;
+          }
+          int iWhere = originalStatus(iStatus);
+          if (iWhere == CLP_BELOW_LOWER) {
+               lowerValue = upperValue;
+               upperValue = bound_[iSequence];
+               numberInfeasibilities_--;
+               assert (fabs(lowerValue) < 1.0e100);
+          } else if (iWhere == CLP_ABOVE_UPPER) {
+               upperValue = lowerValue;
+               lowerValue = bound_[iSequence];
+               numberInfeasibilities_--;
+          }
+          // get correct place
+          // If fixed give benefit of doubt
+          if (lowerValue == upperValue)
+               value = lowerValue;
+          int newWhere = CLP_FEASIBLE;
+          if (value - upperValue <= primalTolerance) {
+               if (value - lowerValue >= -primalTolerance) {
+                    // feasible
+                    //newWhere=CLP_FEASIBLE;
+               } else {
+                    // below
+                    newWhere = CLP_BELOW_LOWER;
+                    costValue -= infeasibilityWeight_;
+                    numberInfeasibilities_++;
+                    assert (fabs(lowerValue) < 1.0e100);
+               }
+          } else {
+               // above
+               newWhere = CLP_ABOVE_UPPER;
+               costValue += infeasibilityWeight_;
+               numberInfeasibilities_++;
+          }
+          if (iWhere != newWhere) {
+               difference = cost[iSequence] - costValue;
+               setOriginalStatus(status_[iSequence], newWhere);
+               if (newWhere == CLP_BELOW_LOWER) {
+                    bound_[iSequence] = upperValue;
+                    upper[iSequence] = lowerValue;
+                    lower[iSequence] = -COIN_DBL_MAX;
+               } else if (newWhere == CLP_ABOVE_UPPER) {
+                    bound_[iSequence] = lowerValue;
+                    lower[iSequence] = upperValue;
+                    upper[iSequence] = COIN_DBL_MAX;
+               } else {
+                    lower[iSequence] = lowerValue;
+                    upper[iSequence] = upperValue;
+               }
+               cost[iSequence] = costValue;
+          }
+          // set correctly
+          if (fabs(value - lowerValue) <= primalTolerance * 1.001) {
+               value = CoinMin(value, lowerValue + primalTolerance);
+          } else if (fabs(value - upperValue) <= primalTolerance * 1.001) {
+               value = CoinMax(value, upperValue - primalTolerance);
+          } else {
+               //printf("*** variable wandered off bound %g %g %g!\n",
+               //     lowerValue,value,upperValue);
+               if (value - lowerValue <= upperValue - value)
+                    value = lowerValue + primalTolerance;
+               else
+                    value = upperValue - primalTolerance;
+          }
+     }
+     changeCost_ += value * difference;
+     return direction;
+}
+// Returns nearest bound
+double
+ClpNonLinearCost::nearest(int iSequence, double solutionValue)
+{
+     assert (model_ != NULL);
+     double nearest = 0.0;
+     if (CLP_METHOD1) {
+          // get where in bound sequence
+          int iRange;
+          int start = start_[iSequence];
+          int end = start_[iSequence+1];
+          int jRange = -1;
+          nearest = COIN_DBL_MAX;
+          for (iRange = start; iRange < end; iRange++) {
+               if (fabs(solutionValue - lower_[iRange]) < nearest) {
+                    jRange = iRange;
+                    nearest = fabs(solutionValue - lower_[iRange]);
+               }
+          }
+          assert(jRange < end);
+          nearest = lower_[jRange];
+     }
+     if (CLP_METHOD2) {
+          const double * upper = model_->upperRegion();
+          const double * lower = model_->lowerRegion();
+          double lowerValue = lower[iSequence];
+          double upperValue = upper[iSequence];
+          int iWhere = originalStatus(status_[iSequence]);
+          if (iWhere == CLP_BELOW_LOWER) {
+               lowerValue = upperValue;
+               upperValue = bound_[iSequence];
+               assert (fabs(lowerValue) < 1.0e100);
+          } else if (iWhere == CLP_ABOVE_UPPER) {
+               upperValue = lowerValue;
+               lowerValue = bound_[iSequence];
+          }
+          if (fabs(solutionValue - lowerValue) < fabs(solutionValue - upperValue))
+               nearest = lowerValue;
+          else
+               nearest = upperValue;
+     }
+     return nearest;
+}
+/// Feasible cost with offset and direction (i.e. for reporting)
+double
+ClpNonLinearCost::feasibleReportCost() const
+{
+     double value;
+     model_->getDblParam(ClpObjOffset, value);
+     return (feasibleCost_ + model_->objectiveAsObject()->nonlinearOffset()) * model_->optimizationDirection() /
+            (model_->objectiveScale() * model_->rhsScale()) - value;
+}
+// Get rid of real costs (just for moment)
+void
+ClpNonLinearCost::zapCosts()
+{
+     int iSequence;
+     double infeasibilityCost = model_->infeasibilityCost();
+     // zero out all costs
+     int numberTotal = numberColumns_ + numberRows_;
+     if (CLP_METHOD1) {
+          int n = start_[numberTotal];
+          memset(cost_, 0, n * sizeof(double));
+          for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+               int start = start_[iSequence];
+               int end = start_[iSequence+1] - 1;
+               // correct costs for this infeasibility weight
+               if (infeasible(start)) {
+                    cost_[start] = -infeasibilityCost;
+               }
+               if (infeasible(end - 1)) {
+                    cost_[end-1] = infeasibilityCost;
+               }
+          }
+     }
+     if (CLP_METHOD2) {
+     }
+}
+#ifdef VALIDATE
+// For debug
+void
+ClpNonLinearCost::validate()
+{
+     double primalTolerance = model_->currentPrimalTolerance();
+     int iSequence;
+     const double * solution = model_->solutionRegion();
+     const double * upper = model_->upperRegion();
+     const double * lower = model_->lowerRegion();
+     const double * cost = model_->costRegion();
+     double infeasibilityCost = model_->infeasibilityCost();
+     int numberTotal = numberRows_ + numberColumns_;
+     int numberInfeasibilities = 0;
+     double sumInfeasibilities = 0.0;
+
+     for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+          double value = solution[iSequence];
+          int iStatus = status_[iSequence];
+          assert (currentStatus(iStatus) == CLP_SAME);
+          double lowerValue = lower[iSequence];
+          double upperValue = upper[iSequence];
+          double costValue = cost2_[iSequence];
+          int iWhere = originalStatus(iStatus);
+          if (iWhere == CLP_BELOW_LOWER) {
+               lowerValue = upperValue;
+               upperValue = bound_[iSequence];
+               assert (fabs(lowerValue) < 1.0e100);
+               costValue -= infeasibilityCost;
+               assert (value <= lowerValue - primalTolerance);
+               numberInfeasibilities++;
+               sumInfeasibilities += lowerValue - value - primalTolerance;
+               assert (model_->getStatus(iSequence) == ClpSimplex::basic);
+          } else if (iWhere == CLP_ABOVE_UPPER) {
+               upperValue = lowerValue;
+               lowerValue = bound_[iSequence];
+               costValue += infeasibilityCost;
+               assert (value >= upperValue + primalTolerance);
+               numberInfeasibilities++;
+               sumInfeasibilities += value - upperValue - primalTolerance;
+               assert (model_->getStatus(iSequence) == ClpSimplex::basic);
+          } else {
+               assert (value >= lowerValue - primalTolerance && value <= upperValue + primalTolerance);
+          }
+          assert (lowerValue == saveLowerV[iSequence]);
+          assert (upperValue == saveUpperV[iSequence]);
+          assert (costValue == cost[iSequence]);
+     }
+     if (numberInfeasibilities)
+          printf("JJ %d infeasibilities summing to %g\n",
+                 numberInfeasibilities, sumInfeasibilities);
+}
+#endif
diff --git a/cbits/coin/ClpNonLinearCost.hpp b/cbits/coin/ClpNonLinearCost.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpNonLinearCost.hpp
@@ -0,0 +1,401 @@
+/* $Id: ClpNonLinearCost.hpp 1769 2011-07-26 09:31:51Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpNonLinearCost_H
+#define ClpNonLinearCost_H
+
+
+#include "CoinPragma.hpp"
+
+class ClpSimplex;
+class CoinIndexedVector;
+
+/** Trivial class to deal with non linear costs
+
+    I don't make any explicit assumptions about convexity but I am
+    sure I do make implicit ones.
+
+    One interesting idea for normal LP's will be to allow non-basic
+    variables to come into basis as infeasible i.e. if variable at
+    lower bound has very large positive reduced cost (when problem
+    is infeasible) could it reduce overall problem infeasibility more
+    by bringing it into basis below its lower bound.
+
+    Another feature would be to automatically discover when problems
+    are convex piecewise linear and re-formulate to use non-linear.
+    I did some work on this many years ago on "grade" problems, but
+    while it improved primal interior point algorithms were much better
+    for that particular problem.
+*/
+/* status has original status and current status
+   0 - below lower so stored is upper
+   1 - in range
+   2 - above upper so stored is lower
+   4 - (for current) - same as original
+*/
+#define CLP_BELOW_LOWER 0
+#define CLP_FEASIBLE 1
+#define CLP_ABOVE_UPPER 2
+#define CLP_SAME 4
+inline int originalStatus(unsigned char status)
+{
+     return (status & 15);
+}
+inline int currentStatus(unsigned char status)
+{
+     return (status >> 4);
+}
+inline void setOriginalStatus(unsigned char & status, int value)
+{
+     status = static_cast<unsigned char>(status & ~15);
+     status = static_cast<unsigned char>(status | value);
+}
+inline void setCurrentStatus(unsigned char &status, int value)
+{
+     status = static_cast<unsigned char>(status & ~(15 << 4));
+     status = static_cast<unsigned char>(status | (value << 4));
+}
+inline void setInitialStatus(unsigned char &status)
+{
+     status = static_cast<unsigned char>(CLP_FEASIBLE | (CLP_SAME << 4));
+}
+inline void setSameStatus(unsigned char &status)
+{
+     status = static_cast<unsigned char>(status & ~(15 << 4));
+     status = static_cast<unsigned char>(status | (CLP_SAME << 4));
+}
+// Use second version to get more speed
+//#define FAST_CLPNON
+#ifndef FAST_CLPNON
+#define CLP_METHOD1 ((method_&1)!=0)
+#define CLP_METHOD2 ((method_&2)!=0)
+#else
+#define CLP_METHOD1 (false)
+#define CLP_METHOD2 (true)
+#endif
+class ClpNonLinearCost  {
+
+public:
+
+public:
+
+     /**@name Constructors, destructor */
+     //@{
+     /// Default constructor.
+     ClpNonLinearCost();
+     /** Constructor from simplex.
+         This will just set up wasteful arrays for linear, but
+         later may do dual analysis and even finding duplicate columns .
+     */
+     ClpNonLinearCost(ClpSimplex * model, int method = 1);
+     /** Constructor from simplex and list of non-linearities (columns only)
+         First lower of each column has to match real lower
+         Last lower has to be <= upper (if == then cost ignored)
+         This could obviously be changed to make more user friendly
+     */
+     ClpNonLinearCost(ClpSimplex * model, const int * starts,
+                      const double * lower, const double * cost);
+     /// Destructor
+     ~ClpNonLinearCost();
+     // Copy
+     ClpNonLinearCost(const ClpNonLinearCost&);
+     // Assignment
+     ClpNonLinearCost& operator=(const ClpNonLinearCost&);
+     //@}
+
+
+     /**@name Actual work in primal */
+     //@{
+     /** Changes infeasible costs and computes number and cost of infeas
+         Puts all non-basic (non free) variables to bounds
+         and all free variables to zero if oldTolerance is non-zero
+         - but does not move those <= oldTolerance away*/
+     void checkInfeasibilities(double oldTolerance = 0.0);
+     /** Changes infeasible costs for each variable
+         The indices are row indices and need converting to sequences
+     */
+     void checkInfeasibilities(int numberInArray, const int * index);
+     /** Puts back correct infeasible costs for each variable
+         The input indices are row indices and need converting to sequences
+         for costs.
+         On input array is empty (but indices exist).  On exit just
+         changed costs will be stored as normal CoinIndexedVector
+     */
+     void checkChanged(int numberInArray, CoinIndexedVector * update);
+     /** Goes through one bound for each variable.
+         If multiplier*work[iRow]>0 goes down, otherwise up.
+         The indices are row indices and need converting to sequences
+         Temporary offsets may be set
+         Rhs entries are increased
+     */
+     void goThru(int numberInArray, double multiplier,
+                 const int * index, const double * work,
+                 double * rhs);
+     /** Takes off last iteration (i.e. offsets closer to 0)
+     */
+     void goBack(int numberInArray, const int * index,
+                 double * rhs);
+     /** Puts back correct infeasible costs for each variable
+         The input indices are row indices and need converting to sequences
+         for costs.
+         At the end of this all temporary offsets are zero
+     */
+     void goBackAll(const CoinIndexedVector * update);
+     /// Temporary zeroing of feasible costs
+     void zapCosts();
+     /// Refreshes costs always makes row costs zero
+     void refreshCosts(const double * columnCosts);
+     /// Puts feasible bounds into lower and upper
+     void feasibleBounds();
+     /// Refresh - assuming regions OK
+     void refresh();
+     /** Sets bounds and cost for one variable
+         Returns change in cost
+      May need to be inline for speed */
+     double setOne(int sequence, double solutionValue);
+     /** Sets bounds and infeasible cost and true cost for one variable
+         This is for gub and column generation etc */
+     void setOne(int sequence, double solutionValue, double lowerValue, double upperValue,
+                 double costValue = 0.0);
+     /** Sets bounds and cost for outgoing variable
+         may change value
+         Returns direction */
+     int setOneOutgoing(int sequence, double &solutionValue);
+     /// Returns nearest bound
+     double nearest(int sequence, double solutionValue);
+     /** Returns change in cost - one down if alpha >0.0, up if <0.0
+         Value is current - new
+      */
+     inline double changeInCost(int sequence, double alpha) const {
+          double returnValue = 0.0;
+          if (CLP_METHOD1) {
+               int iRange = whichRange_[sequence] + offset_[sequence];
+               if (alpha > 0.0)
+                    returnValue = cost_[iRange] - cost_[iRange-1];
+               else
+                    returnValue = cost_[iRange] - cost_[iRange+1];
+          }
+          if (CLP_METHOD2) {
+               returnValue = (alpha > 0.0) ? infeasibilityWeight_ : -infeasibilityWeight_;
+          }
+          return returnValue;
+     }
+     inline double changeUpInCost(int sequence) const {
+          double returnValue = 0.0;
+          if (CLP_METHOD1) {
+               int iRange = whichRange_[sequence] + offset_[sequence];
+               if (iRange + 1 != start_[sequence+1] && !infeasible(iRange + 1))
+                    returnValue = cost_[iRange] - cost_[iRange+1];
+               else
+                    returnValue = -1.0e100;
+          }
+          if (CLP_METHOD2) {
+               returnValue = -infeasibilityWeight_;
+          }
+          return returnValue;
+     }
+     inline double changeDownInCost(int sequence) const {
+          double returnValue = 0.0;
+          if (CLP_METHOD1) {
+               int iRange = whichRange_[sequence] + offset_[sequence];
+               if (iRange != start_[sequence] && !infeasible(iRange - 1))
+                    returnValue = cost_[iRange] - cost_[iRange-1];
+               else
+                    returnValue = 1.0e100;
+          }
+          if (CLP_METHOD2) {
+               returnValue = infeasibilityWeight_;
+          }
+          return returnValue;
+     }
+     /// This also updates next bound
+     inline double changeInCost(int sequence, double alpha, double &rhs) {
+          double returnValue = 0.0;
+#ifdef NONLIN_DEBUG
+          double saveRhs = rhs;
+#endif
+          if (CLP_METHOD1) {
+               int iRange = whichRange_[sequence] + offset_[sequence];
+               if (alpha > 0.0) {
+                    assert(iRange - 1 >= start_[sequence]);
+                    offset_[sequence]--;
+                    rhs += lower_[iRange] - lower_[iRange-1];
+                    returnValue = alpha * (cost_[iRange] - cost_[iRange-1]);
+               } else {
+                    assert(iRange + 1 < start_[sequence+1] - 1);
+                    offset_[sequence]++;
+                    rhs += lower_[iRange+2] - lower_[iRange+1];
+                    returnValue = alpha * (cost_[iRange] - cost_[iRange+1]);
+               }
+          }
+          if (CLP_METHOD2) {
+#ifdef NONLIN_DEBUG
+               double saveRhs1 = rhs;
+               rhs = saveRhs;
+#endif
+               unsigned char iStatus = status_[sequence];
+               int iWhere = currentStatus(iStatus);
+               if (iWhere == CLP_SAME)
+                    iWhere = originalStatus(iStatus);
+               // rhs always increases
+               if (iWhere == CLP_FEASIBLE) {
+                    if (alpha > 0.0) {
+                         // going below
+                         iWhere = CLP_BELOW_LOWER;
+                         rhs = COIN_DBL_MAX;
+                    } else {
+                         // going above
+                         iWhere = CLP_ABOVE_UPPER;
+                         rhs = COIN_DBL_MAX;
+                    }
+               } else if (iWhere == CLP_BELOW_LOWER) {
+                    assert (alpha < 0);
+                    // going feasible
+                    iWhere = CLP_FEASIBLE;
+                    rhs += bound_[sequence] - model_->upperRegion()[sequence];
+               } else {
+                    assert (iWhere == CLP_ABOVE_UPPER);
+                    // going feasible
+                    iWhere = CLP_FEASIBLE;
+                    rhs += model_->lowerRegion()[sequence] - bound_[sequence];
+               }
+               setCurrentStatus(status_[sequence], iWhere);
+#ifdef NONLIN_DEBUG
+               assert(saveRhs1 == rhs);
+#endif
+               returnValue = fabs(alpha) * infeasibilityWeight_;
+          }
+          return returnValue;
+     }
+     /// Returns current lower bound
+     inline double lower(int sequence) const {
+          return lower_[whichRange_[sequence] + offset_[sequence]];
+     }
+     /// Returns current upper bound
+     inline double upper(int sequence) const {
+          return lower_[whichRange_[sequence] + offset_[sequence] + 1];
+     }
+     /// Returns current cost
+     inline double cost(int sequence) const {
+          return cost_[whichRange_[sequence] + offset_[sequence]];
+     }
+     //@}
+
+
+     /**@name Gets and sets */
+     //@{
+     /// Number of infeasibilities
+     inline int numberInfeasibilities() const {
+          return numberInfeasibilities_;
+     }
+     /// Change in cost
+     inline double changeInCost() const {
+          return changeCost_;
+     }
+     /// Feasible cost
+     inline double feasibleCost() const {
+          return feasibleCost_;
+     }
+     /// Feasible cost with offset and direction (i.e. for reporting)
+     double feasibleReportCost() const;
+     /// Sum of infeasibilities
+     inline double sumInfeasibilities() const {
+          return sumInfeasibilities_;
+     }
+     /// Largest infeasibility
+     inline double largestInfeasibility() const {
+          return largestInfeasibility_;
+     }
+     /// Average theta
+     inline double averageTheta() const {
+          return averageTheta_;
+     }
+     inline void setAverageTheta(double value) {
+          averageTheta_ = value;
+     }
+     inline void setChangeInCost(double value) {
+          changeCost_ = value;
+     }
+     inline void setMethod(int value) {
+          method_ = value;
+     }
+     /// See if may want to look both ways
+     inline bool lookBothWays() const {
+          return bothWays_;
+     }
+     //@}
+     ///@name Private functions to deal with infeasible regions
+     inline bool infeasible(int i) const {
+          return ((infeasible_[i>>5] >> (i & 31)) & 1) != 0;
+     }
+     inline void setInfeasible(int i, bool trueFalse) {
+          unsigned int & value = infeasible_[i>>5];
+          int bit = i & 31;
+          if (trueFalse)
+               value |= (1 << bit);
+          else
+               value &= ~(1 << bit);
+     }
+     inline unsigned char * statusArray() const {
+          return status_;
+     }
+     /// For debug
+     void validate();
+     //@}
+
+private:
+     /**@name Data members */
+     //@{
+     /// Change in cost because of infeasibilities
+     double changeCost_;
+     /// Feasible cost
+     double feasibleCost_;
+     /// Current infeasibility weight
+     double infeasibilityWeight_;
+     /// Largest infeasibility
+     double largestInfeasibility_;
+     /// Sum of infeasibilities
+     double sumInfeasibilities_;
+     /// Average theta - kept here as only for primal
+     double averageTheta_;
+     /// Number of rows (mainly for checking and copy)
+     int numberRows_;
+     /// Number of columns (mainly for checking and copy)
+     int numberColumns_;
+     /// Starts for each entry (columns then rows)
+     int * start_;
+     /// Range for each entry (columns then rows)
+     int * whichRange_;
+     /// Temporary range offset for each entry (columns then rows)
+     int * offset_;
+     /** Lower bound for each range (upper bound is next lower).
+         For various reasons there is always an infeasible range
+         at bottom - even if lower bound is - infinity */
+     double * lower_;
+     /// Cost for each range
+     double * cost_;
+     /// Model
+     ClpSimplex * model_;
+     // Array to say which regions are infeasible
+     unsigned int * infeasible_;
+     /// Number of infeasibilities found
+     int numberInfeasibilities_;
+     // new stuff
+     /// Contains status at beginning and current
+     unsigned char * status_;
+     /// Bound which has been replaced in lower_ or upper_
+     double * bound_;
+     /// Feasible cost array
+     double * cost2_;
+     /// Method 1 old, 2 new, 3 both!
+     int method_;
+     /// If all non-linear costs convex
+     bool convex_;
+     /// If we should look both ways for djs
+     bool bothWays_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpObjective.cpp b/cbits/coin/ClpObjective.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpObjective.cpp
@@ -0,0 +1,76 @@
+/* $Id: ClpObjective.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpObjective.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpObjective::ClpObjective () :
+     offset_(0.0),
+     type_(-1),
+     activated_(1)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpObjective::ClpObjective (const ClpObjective & source) :
+     offset_(source.offset_),
+     type_(source.type_),
+     activated_(source.activated_)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpObjective::~ClpObjective ()
+{
+
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpObjective &
+ClpObjective::operator=(const ClpObjective& rhs)
+{
+     if (this != &rhs) {
+          offset_ = rhs.offset_;
+          type_ = rhs.type_;
+          activated_ = rhs.activated_;
+     }
+     return *this;
+}
+/* Subset clone.  Duplicates are allowed
+   and order is as given.
+*/
+ClpObjective *
+ClpObjective::subsetClone (int,
+                           const int * ) const
+{
+     std::cerr << "subsetClone not supported - ClpObjective" << std::endl;
+     abort();
+     return NULL;
+}
+/* Given a zeroed array sets nonlinear columns to 1.
+   Returns number of nonlinear columns
+*/
+int
+ClpObjective::markNonlinear(char *)
+{
+     return 0;
+}
+
diff --git a/cbits/coin/ClpObjective.hpp b/cbits/coin/ClpObjective.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpObjective.hpp
@@ -0,0 +1,134 @@
+/* $Id: ClpObjective.hpp 1825 2011-11-20 16:02:57Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpObjective_H
+#define ClpObjective_H
+
+
+//#############################################################################
+class ClpSimplex;
+class ClpModel;
+
+/** Objective Abstract Base Class
+
+Abstract Base Class for describing an objective function
+
+*/
+class ClpObjective  {
+
+public:
+
+     ///@name Stuff
+     //@{
+
+     /** Returns gradient.  If Linear then solution may be NULL,
+         also returns an offset (to be added to current one)
+         If refresh is false then uses last solution
+         Uses model for scaling
+         includeLinear 0 - no, 1 as is, 2 as feasible
+     */
+     virtual double * gradient(const ClpSimplex * model,
+                               const double * solution,
+                               double & offset, bool refresh,
+                               int includeLinear = 2) = 0;
+     /** Returns reduced gradient.Returns an offset (to be added to current one).
+     */
+     virtual double reducedGradient(ClpSimplex * model, double * region,
+                                    bool useFeasibleCosts) = 0;
+     /** Returns step length which gives minimum of objective for
+         solution + theta * change vector up to maximum theta.
+
+         arrays are numberColumns+numberRows
+         Also sets current objective, predicted  and at maximumTheta
+     */
+     virtual double stepLength(ClpSimplex * model,
+                               const double * solution,
+                               const double * change,
+                               double maximumTheta,
+                               double & currentObj,
+                               double & predictedObj,
+                               double & thetaObj) = 0;
+     /// Return objective value (without any ClpModel offset) (model may be NULL)
+     virtual double objectiveValue(const ClpSimplex * model, const double * solution) const = 0;
+     /// Resize objective
+     virtual void resize(int newNumberColumns) = 0;
+     /// Delete columns in  objective
+     virtual void deleteSome(int numberToDelete, const int * which) = 0;
+     /// Scale objective
+     virtual void reallyScale(const double * columnScale) = 0;
+     /** Given a zeroed array sets nonlinear columns to 1.
+         Returns number of nonlinear columns
+      */
+     virtual int markNonlinear(char * which);
+     /// Say we have new primal solution - so may need to recompute
+     virtual void newXValues() {}
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpObjective();
+
+     /// Copy constructor
+     ClpObjective(const ClpObjective &);
+
+     /// Assignment operator
+     ClpObjective & operator=(const ClpObjective& rhs);
+
+     /// Destructor
+     virtual ~ClpObjective ();
+
+     /// Clone
+     virtual ClpObjective * clone() const = 0;
+     /** Subset clone.  Duplicates are allowed
+         and order is as given.
+         Derived classes need not provide this as it may not always make
+         sense */
+     virtual ClpObjective * subsetClone (int numberColumns,
+                                         const int * whichColumns) const;
+
+     //@}
+
+     ///@name Other
+     //@{
+     /// Returns type (above 63 is extra information)
+     inline int type() const {
+          return type_;
+     }
+     /// Sets type (above 63 is extra information)
+     inline void setType(int value) {
+          type_ = value;
+     }
+     /// Whether activated
+     inline int activated() const {
+          return activated_;
+     }
+     /// Set whether activated
+     inline void setActivated(int value) {
+          activated_ = value;
+     }
+
+     /// Objective offset
+     inline double nonlinearOffset () const {
+          return offset_;
+     }
+     //@}
+
+     //---------------------------------------------------------------------------
+
+protected:
+     ///@name Protected member data
+     //@{
+     /// Value of non-linear part of objective
+     double offset_;
+     /// Type of objective - linear is 1
+     int type_;
+     /// Whether activated
+     int activated_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpPackedMatrix.cpp b/cbits/coin/ClpPackedMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPackedMatrix.cpp
@@ -0,0 +1,6627 @@
+/* $Id: ClpPackedMatrix.cpp 1957 2013-05-15 08:58:19Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+
+#include <cstdio>
+
+#include "CoinPragma.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+//#define THREAD
+
+#include "ClpSimplex.hpp"
+#include "ClpSimplexDual.hpp"
+#include "ClpFactorization.hpp"
+#ifndef SLIM_CLP
+#include "ClpQuadraticObjective.hpp"
+#endif
+// at end to get min/max!
+#include "ClpPackedMatrix.hpp"
+#include "ClpMessage.hpp"
+#ifdef INTEL_MKL
+#include "mkl_spblas.h"
+#endif
+//#define DO_CHECK_FLAGS 1
+//=============================================================================
+#ifdef COIN_PREFETCH
+#if 1
+#define coin_prefetch(mem) \
+         __asm__ __volatile__ ("prefetchnta %0" : : "m" (*(reinterpret_cast<char *>(mem))))
+#define coin_prefetch_const(mem) \
+         __asm__ __volatile__ ("prefetchnta %0" : : "m" (*(reinterpret_cast<const char *>(mem))))
+#else
+#define coin_prefetch(mem) \
+         __asm__ __volatile__ ("prefetch %0" : : "m" (*(reinterpret_cast<char *>(mem))))
+#define coin_prefetch_const(mem) \
+         __asm__ __volatile__ ("prefetch %0" : : "m" (*(reinterpret_cast<const char *>(mem))))
+#endif
+#else
+// dummy
+#define coin_prefetch(mem)
+#define coin_prefetch_const(mem)
+#endif
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpPackedMatrix::ClpPackedMatrix ()
+     : ClpMatrixBase(),
+       matrix_(NULL),
+       numberActiveColumns_(0),
+       flags_(2),
+       rowCopy_(NULL),
+       columnCopy_(NULL)
+{
+     setType(1);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpPackedMatrix::ClpPackedMatrix (const ClpPackedMatrix & rhs)
+     : ClpMatrixBase(rhs)
+{
+#ifdef DO_CHECK_FLAGS
+     rhs.checkFlags(0);
+#endif
+#ifndef COIN_SPARSE_MATRIX
+     // Guaranteed no gaps or small elements
+     matrix_ = new CoinPackedMatrix(*(rhs.matrix_),-1,0) ;
+     flags_ = rhs.flags_&(~0x02) ;
+#else
+     // Gaps & small elements preserved
+     matrix_ = new CoinPackedMatrix(*(rhs.matrix_),0,0) ;
+     flags_ = rhs.flags_ ;
+     if (matrix_->hasGaps()) flags_ |= 0x02 ;
+#endif
+     numberActiveColumns_ = rhs.numberActiveColumns_;
+     int numberRows = matrix_->getNumRows();
+     if (rhs.rhsOffset_ && numberRows) {
+          rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows);
+     } else {
+          rhsOffset_ = NULL;
+     }
+     if (rhs.rowCopy_) {
+          assert ((flags_ & 4) != 0);
+          rowCopy_ = new ClpPackedMatrix2(*rhs.rowCopy_);
+     } else {
+          rowCopy_ = NULL;
+     }
+     if (rhs.columnCopy_) {
+          assert ((flags_&(8 + 16)) == 8 + 16);
+          columnCopy_ = new ClpPackedMatrix3(*rhs.columnCopy_);
+     } else {
+          columnCopy_ = NULL;
+     }
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+}
+//-------------------------------------------------------------------
+// assign matrix (for space reasons)
+//-------------------------------------------------------------------
+ClpPackedMatrix::ClpPackedMatrix (CoinPackedMatrix * rhs)
+     : ClpMatrixBase()
+{
+     matrix_ = rhs;
+     flags_ = ((matrix_->hasGaps())?0x02:0) ;
+     numberActiveColumns_ = matrix_->getNumCols();
+     rowCopy_ = NULL;
+     columnCopy_ = NULL;
+     setType(1);
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+
+}
+
+ClpPackedMatrix::ClpPackedMatrix (const CoinPackedMatrix & rhs)
+     : ClpMatrixBase()
+{
+#ifndef COIN_SPARSE_MATRIX
+     matrix_ = new CoinPackedMatrix(rhs,-1,0) ;
+     flags_ = 0 ;
+#else
+     matrix_ = new CoinPackedMatrix(rhs,0,0) ;
+     flags_ = ((matrix_->hasGaps())?0x02:0) ;
+#endif
+     numberActiveColumns_ = matrix_->getNumCols();
+     rowCopy_ = NULL;
+     columnCopy_ = NULL;
+     setType(1);
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpPackedMatrix::~ClpPackedMatrix ()
+{
+     delete matrix_;
+     delete rowCopy_;
+     delete columnCopy_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpPackedMatrix &
+ClpPackedMatrix::operator=(const ClpPackedMatrix& rhs)
+{
+     if (this != &rhs) {
+          ClpMatrixBase::operator=(rhs);
+          delete matrix_;
+#ifndef COIN_SPARSE_MATRIX
+          matrix_ = new CoinPackedMatrix(*(rhs.matrix_),-1,0) ;
+	  flags_ = rhs.flags_&(~0x02) ;
+#else
+	  matrix_ = new CoinPackedMatrix(*(rhs.matrix_),0,0) ;
+	  flags_ = rhs.flags_ ;
+	  if (matrix_->hasGaps()) flags_ |= 0x02 ;
+#endif
+          numberActiveColumns_ = rhs.numberActiveColumns_;
+          delete rowCopy_;
+          delete columnCopy_;
+          if (rhs.rowCopy_) {
+               assert ((flags_ & 4) != 0);
+               rowCopy_ = new ClpPackedMatrix2(*rhs.rowCopy_);
+          } else {
+               rowCopy_ = NULL;
+          }
+          if (rhs.columnCopy_) {
+               assert ((flags_&(8 + 16)) == 8 + 16);
+               columnCopy_ = new ClpPackedMatrix3(*rhs.columnCopy_);
+          } else {
+               columnCopy_ = NULL;
+          }
+#ifdef DO_CHECK_FLAGS
+	  checkFlags(0);
+#endif
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpMatrixBase * ClpPackedMatrix::clone() const
+{
+     return new ClpPackedMatrix(*this);
+}
+// Copy contents - resizing if necessary - otherwise re-use memory
+void
+ClpPackedMatrix::copy(const ClpPackedMatrix * rhs)
+{
+     //*this = *rhs;
+     assert(numberActiveColumns_ == rhs->numberActiveColumns_);
+     assert (matrix_->isColOrdered() == rhs->matrix_->isColOrdered());
+     matrix_->copyReuseArrays(*rhs->matrix_);
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+}
+/* Subset clone (without gaps).  Duplicates are allowed
+   and order is as given */
+ClpMatrixBase *
+ClpPackedMatrix::subsetClone (int numberRows, const int * whichRows,
+                              int numberColumns,
+                              const int * whichColumns) const
+{
+     return new ClpPackedMatrix(*this, numberRows, whichRows,
+                                numberColumns, whichColumns);
+}
+/* Subset constructor (without gaps).  Duplicates are allowed
+   and order is as given */
+ClpPackedMatrix::ClpPackedMatrix (
+     const ClpPackedMatrix & rhs,
+     int numberRows, const int * whichRows,
+     int numberColumns, const int * whichColumns)
+     : ClpMatrixBase(rhs)
+{
+     matrix_ = new CoinPackedMatrix(*(rhs.matrix_), numberRows, whichRows,
+                                    numberColumns, whichColumns);
+     numberActiveColumns_ = matrix_->getNumCols();
+     rowCopy_ = NULL;
+     flags_ = rhs.flags_&(~0x02) ; // no gaps
+     columnCopy_ = NULL;
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+}
+ClpPackedMatrix::ClpPackedMatrix (
+     const CoinPackedMatrix & rhs,
+     int numberRows, const int * whichRows,
+     int numberColumns, const int * whichColumns)
+     : ClpMatrixBase()
+{
+     matrix_ = new CoinPackedMatrix(rhs, numberRows, whichRows,
+                                    numberColumns, whichColumns);
+     numberActiveColumns_ = matrix_->getNumCols();
+     rowCopy_ = NULL;
+     flags_ = 0 ;  // no gaps
+     columnCopy_ = NULL;
+     setType(1);
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+}
+
+/* Returns a new matrix in reverse order without gaps */
+ClpMatrixBase *
+ClpPackedMatrix::reverseOrderedCopy() const
+{
+     ClpPackedMatrix * copy = new ClpPackedMatrix();
+     copy->matrix_ = new CoinPackedMatrix();
+     copy->matrix_->setExtraGap(0.0);
+     copy->matrix_->setExtraMajor(0.0);
+     copy->matrix_->reverseOrderedCopyOf(*matrix_);
+     //copy->matrix_->removeGaps();
+     copy->numberActiveColumns_ = copy->matrix_->getNumCols();
+     copy->flags_ = flags_&(~0x02) ; // no gaps
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+     return copy;
+}
+//unscaled versions
+void
+ClpPackedMatrix::times(double scalar,
+                       const double * x, double * y) const
+{
+     int iRow, iColumn;
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const double * elementByColumn = matrix_->getElements();
+     //memset(y,0,matrix_->getNumRows()*sizeof(double));
+     assert (((flags_&0x02) != 0) == matrix_->hasGaps());
+     if (!(flags_ & 2)) {
+          for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+               CoinBigIndex j;
+               double value = x[iColumn];
+               if (value) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = columnStart[iColumn+1];
+                    value *= scalar;
+                    for (j = start; j < end; j++) {
+                         iRow = row[j];
+                         y[iRow] += value * elementByColumn[j];
+                    }
+               }
+          }
+     } else {
+          const int * columnLength = matrix_->getVectorLengths();
+          for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+               CoinBigIndex j;
+               double value = x[iColumn];
+               if (value) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = start + columnLength[iColumn];
+                    value *= scalar;
+                    for (j = start; j < end; j++) {
+                         iRow = row[j];
+                         y[iRow] += value * elementByColumn[j];
+                    }
+               }
+          }
+     }
+}
+void
+ClpPackedMatrix::transposeTimes(double scalar,
+                                const double * x, double * y) const
+{
+     int iColumn;
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const double * elementByColumn = matrix_->getElements();
+     if (!(flags_ & 2)) {
+          if (scalar == -1.0) {
+               CoinBigIndex start = columnStart[0];
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    CoinBigIndex j;
+                    CoinBigIndex next = columnStart[iColumn+1];
+                    double value = y[iColumn];
+                    for (j = start; j < next; j++) {
+                         int jRow = row[j];
+                         value -= x[jRow] * elementByColumn[j];
+                    }
+                    start = next;
+                    y[iColumn] = value;
+               }
+          } else {
+               CoinBigIndex start = columnStart[0];
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    CoinBigIndex j;
+                    CoinBigIndex next = columnStart[iColumn+1];
+                    double value = 0.0;
+                    for (j = start; j < next; j++) {
+                         int jRow = row[j];
+                         value += x[jRow] * elementByColumn[j];
+                    }
+                    start = next;
+                    y[iColumn] += value * scalar;
+               }
+          }
+     } else {
+          const int * columnLength = matrix_->getVectorLengths();
+          for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+               CoinBigIndex j;
+               double value = 0.0;
+               CoinBigIndex start = columnStart[iColumn];
+               CoinBigIndex end = start + columnLength[iColumn];
+               for (j = start; j < end; j++) {
+                    int jRow = row[j];
+                    value += x[jRow] * elementByColumn[j];
+               }
+               y[iColumn] += value * scalar;
+          }
+     }
+}
+void
+ClpPackedMatrix::times(double scalar,
+                       const double * COIN_RESTRICT x, double * COIN_RESTRICT y,
+                       const double * COIN_RESTRICT rowScale,
+                       const double * COIN_RESTRICT columnScale) const
+{
+     if (rowScale) {
+          int iRow, iColumn;
+          // get matrix data pointers
+          const int * COIN_RESTRICT row = matrix_->getIndices();
+          const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+          const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+          if (!(flags_ & 2)) {
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    double value = x[iColumn];
+                    if (value) {
+                         // scaled
+                         value *= scalar * columnScale[iColumn];
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = columnStart[iColumn+1];
+                         CoinBigIndex j;
+                         for (j = start; j < end; j++) {
+                              iRow = row[j];
+                              y[iRow] += value * elementByColumn[j] * rowScale[iRow];
+                         }
+                    }
+               }
+          } else {
+               const int * COIN_RESTRICT columnLength = matrix_->getVectorLengths();
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    double value = x[iColumn];
+                    if (value) {
+                         // scaled
+                         value *= scalar * columnScale[iColumn];
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = start + columnLength[iColumn];
+                         CoinBigIndex j;
+                         for (j = start; j < end; j++) {
+                              iRow = row[j];
+                              y[iRow] += value * elementByColumn[j] * rowScale[iRow];
+                         }
+                    }
+               }
+          }
+     } else {
+          times(scalar, x, y);
+     }
+}
+void
+ClpPackedMatrix::transposeTimes( double scalar,
+                                 const double * COIN_RESTRICT x, double * COIN_RESTRICT y,
+                                 const double * COIN_RESTRICT rowScale,
+                                 const double * COIN_RESTRICT columnScale,
+                                 double * COIN_RESTRICT spare) const
+{
+     if (rowScale) {
+          int iColumn;
+          // get matrix data pointers
+          const int * COIN_RESTRICT row = matrix_->getIndices();
+          const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+          const int * COIN_RESTRICT columnLength = matrix_->getVectorLengths();
+          const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+          if (!spare) {
+               if (!(flags_ & 2)) {
+                    CoinBigIndex start = columnStart[0];
+                    if (scalar == -1.0) {
+                         for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                              CoinBigIndex j;
+                              CoinBigIndex next = columnStart[iColumn+1];
+                              double value = 0.0;
+                              // scaled
+                              for (j = start; j < next; j++) {
+                                   int jRow = row[j];
+                                   value += x[jRow] * elementByColumn[j] * rowScale[jRow];
+                              }
+                              start = next;
+                              y[iColumn] -= value * columnScale[iColumn];
+                         }
+                    } else {
+                         for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                              CoinBigIndex j;
+                              CoinBigIndex next = columnStart[iColumn+1];
+                              double value = 0.0;
+                              // scaled
+                              for (j = start; j < next; j++) {
+                                   int jRow = row[j];
+                                   value += x[jRow] * elementByColumn[j] * rowScale[jRow];
+                              }
+                              start = next;
+                              y[iColumn] += value * scalar * columnScale[iColumn];
+                         }
+                    }
+               } else {
+                    for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                         CoinBigIndex j;
+                         double value = 0.0;
+                         // scaled
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              int jRow = row[j];
+                              value += x[jRow] * elementByColumn[j] * rowScale[jRow];
+                         }
+                         y[iColumn] += value * scalar * columnScale[iColumn];
+                    }
+               }
+          } else {
+               // can use spare region
+               int iRow;
+               int numberRows = matrix_->getNumRows();
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    double value = x[iRow];
+                    if (value)
+                         spare[iRow] = value * rowScale[iRow];
+                    else
+                         spare[iRow] = 0.0;
+               }
+               if (!(flags_ & 2)) {
+                    CoinBigIndex start = columnStart[0];
+                    for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                         CoinBigIndex j;
+                         CoinBigIndex next = columnStart[iColumn+1];
+                         double value = 0.0;
+                         // scaled
+                         for (j = start; j < next; j++) {
+                              int jRow = row[j];
+                              value += spare[jRow] * elementByColumn[j];
+                         }
+                         start = next;
+                         y[iColumn] += value * scalar * columnScale[iColumn];
+                    }
+               } else {
+                    for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                         CoinBigIndex j;
+                         double value = 0.0;
+                         // scaled
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              int jRow = row[j];
+                              value += spare[jRow] * elementByColumn[j];
+                         }
+                         y[iColumn] += value * scalar * columnScale[iColumn];
+                    }
+               }
+               // no need to zero out
+               //for (iRow=0;iRow<numberRows;iRow++)
+               //spare[iRow] = 0.0;
+          }
+     } else {
+          transposeTimes(scalar, x, y);
+     }
+}
+void
+ClpPackedMatrix::transposeTimesSubset( int number,
+                                       const int * which,
+                                       const double * COIN_RESTRICT x, double * COIN_RESTRICT y,
+                                       const double * COIN_RESTRICT rowScale,
+                                       const double * COIN_RESTRICT columnScale,
+                                       double * COIN_RESTRICT spare) const
+{
+     // get matrix data pointers
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+     if (!spare || !rowScale) {
+          if (rowScale) {
+               for (int jColumn = 0; jColumn < number; jColumn++) {
+                    int iColumn = which[jColumn];
+                    CoinBigIndex j;
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex next = columnStart[iColumn+1];
+                    double value = 0.0;
+                    for (j = start; j < next; j++) {
+                         int jRow = row[j];
+                         value += x[jRow] * elementByColumn[j] * rowScale[jRow];
+                    }
+                    y[iColumn] -= value * columnScale[iColumn];
+               }
+          } else {
+               for (int jColumn = 0; jColumn < number; jColumn++) {
+                    int iColumn = which[jColumn];
+                    CoinBigIndex j;
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex next = columnStart[iColumn+1];
+                    double value = 0.0;
+                    for (j = start; j < next; j++) {
+                         int jRow = row[j];
+                         value += x[jRow] * elementByColumn[j];
+                    }
+                    y[iColumn] -= value;
+               }
+          }
+     } else {
+          // can use spare region
+          int iRow;
+          int numberRows = matrix_->getNumRows();
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               double value = x[iRow];
+               if (value)
+                    spare[iRow] = value * rowScale[iRow];
+               else
+                    spare[iRow] = 0.0;
+          }
+          for (int jColumn = 0; jColumn < number; jColumn++) {
+               int iColumn = which[jColumn];
+               CoinBigIndex j;
+               CoinBigIndex start = columnStart[iColumn];
+               CoinBigIndex next = columnStart[iColumn+1];
+               double value = 0.0;
+               for (j = start; j < next; j++) {
+                    int jRow = row[j];
+                    value += spare[jRow] * elementByColumn[j];
+               }
+               y[iColumn] -= value * columnScale[iColumn];
+          }
+     }
+}
+/* Return <code>x * A + y</code> in <code>z</code>.
+	Squashes small elements and knows about ClpSimplex */
+void
+ClpPackedMatrix::transposeTimes(const ClpSimplex * model, double scalar,
+                                const CoinIndexedVector * rowArray,
+                                CoinIndexedVector * y,
+                                CoinIndexedVector * columnArray) const
+{
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     int numberNonZero = 0;
+     int * index = columnArray->getIndices();
+     double * array = columnArray->denseVector();
+     int numberInRowArray = rowArray->getNumElements();
+     // maybe I need one in OsiSimplex
+     double zeroTolerance = model->zeroTolerance();
+#if 0 //def COIN_DEVELOP
+     if (zeroTolerance != 1.0e-13) {
+          printf("small element in matrix - zero tolerance %g\n", zeroTolerance);
+     }
+#endif
+     int numberRows = model->numberRows();
+     ClpPackedMatrix* rowCopy =
+          static_cast< ClpPackedMatrix*>(model->rowCopy());
+     bool packed = rowArray->packedMode();
+     double factor = (numberRows < 100) ? 0.25 : 0.35;
+     factor = 0.5;
+     // We may not want to do by row if there may be cache problems
+     // It would be nice to find L2 cache size - for moment 512K
+     // Be slightly optimistic
+     if (numberActiveColumns_ * sizeof(double) > 1000000) {
+          if (numberRows * 10 < numberActiveColumns_)
+               factor *= 0.333333333;
+          else if (numberRows * 4 < numberActiveColumns_)
+               factor *= 0.5;
+          else if (numberRows * 2 < numberActiveColumns_)
+               factor *= 0.66666666667;
+          //if (model->numberIterations()%50==0)
+          //printf("%d nonzero\n",numberInRowArray);
+     }
+     // if not packed then bias a bit more towards by column
+     if (!packed)
+          factor *= 0.9;
+     assert (!y->getNumElements());
+     double multiplierX = 0.8;
+     double factor2 = factor * multiplierX;
+     if (packed && rowCopy_ && numberInRowArray > 2 && numberInRowArray > factor2 * numberRows &&
+               numberInRowArray < 0.9 * numberRows && 0) {
+          rowCopy_->transposeTimes(model, rowCopy->matrix_, rowArray, y, columnArray);
+          return;
+     }
+     if (numberInRowArray > factor * numberRows || !rowCopy) {
+          // do by column
+          // If no gaps - can do a bit faster
+          if (!(flags_ & 2) || columnCopy_) {
+               transposeTimesByColumn( model,  scalar,
+                                       rowArray, y, columnArray);
+               return;
+          }
+          int iColumn;
+          // get matrix data pointers
+          const int * row = matrix_->getIndices();
+          const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+          const int * columnLength = matrix_->getVectorLengths();
+          const double * elementByColumn = matrix_->getElements();
+          const double * rowScale = model->rowScale();
+#if 0
+          ClpPackedMatrix * scaledMatrix = model->clpScaledMatrix();
+          if (rowScale && scaledMatrix) {
+               rowScale = NULL;
+               // get matrix data pointers
+               row = scaledMatrix->getIndices();
+               columnStart = scaledMatrix->getVectorStarts();
+               columnLength = scaledMatrix->getVectorLengths();
+               elementByColumn = scaledMatrix->getElements();
+          }
+#endif
+          if (packed) {
+               // need to expand pi into y
+               assert(y->capacity() >= numberRows);
+               double * piOld = pi;
+               pi = y->denseVector();
+               const int * whichRow = rowArray->getIndices();
+               int i;
+               if (!rowScale) {
+                    // modify pi so can collapse to one loop
+                    if (scalar == -1.0) {
+                         for (i = 0; i < numberInRowArray; i++) {
+                              int iRow = whichRow[i];
+                              pi[iRow] = -piOld[i];
+                         }
+                    } else {
+                         for (i = 0; i < numberInRowArray; i++) {
+                              int iRow = whichRow[i];
+                              pi[iRow] = scalar * piOld[i];
+                         }
+                    }
+                    for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                         double value = 0.0;
+                         CoinBigIndex j;
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              int iRow = row[j];
+                              value += pi[iRow] * elementByColumn[j];
+                         }
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               } else {
+#ifdef CLP_INVESTIGATE
+                    if (model->clpScaledMatrix())
+                         printf("scaledMatrix_ at %d of ClpPackedMatrix\n", __LINE__);
+#endif
+                    // scaled
+                    // modify pi so can collapse to one loop
+                    if (scalar == -1.0) {
+                         for (i = 0; i < numberInRowArray; i++) {
+                              int iRow = whichRow[i];
+                              pi[iRow] = -piOld[i] * rowScale[iRow];
+                         }
+                    } else {
+                         for (i = 0; i < numberInRowArray; i++) {
+                              int iRow = whichRow[i];
+                              pi[iRow] = scalar * piOld[i] * rowScale[iRow];
+                         }
+                    }
+                    for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                         double value = 0.0;
+                         CoinBigIndex j;
+                         const double * columnScale = model->columnScale();
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              int iRow = row[j];
+                              value += pi[iRow] * elementByColumn[j];
+                         }
+                         value *= columnScale[iColumn];
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+               // zero out
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = 0.0;
+               }
+          } else {
+               if (!rowScale) {
+                    if (scalar == -1.0) {
+                         for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j];
+                              }
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = -value;
+                              }
+                         }
+                    } else {
+                         for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j];
+                              }
+                              value *= scalar;
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = value;
+                              }
+                         }
+                    }
+               } else {
+#ifdef CLP_INVESTIGATE
+                    if (model->clpScaledMatrix())
+                         printf("scaledMatrix_ at %d of ClpPackedMatrix\n", __LINE__);
+#endif
+                    // scaled
+                    if (scalar == -1.0) {
+                         for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              const double * columnScale = model->columnScale();
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                              }
+                              value *= columnScale[iColumn];
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = -value;
+                              }
+                         }
+                    } else {
+                         for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                              double value = 0.0;
+                              CoinBigIndex j;
+                              const double * columnScale = model->columnScale();
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   int iRow = row[j];
+                                   value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                              }
+                              value *= scalar * columnScale[iColumn];
+                              if (fabs(value) > zeroTolerance) {
+                                   index[numberNonZero++] = iColumn;
+                                   array[iColumn] = value;
+                              }
+                         }
+                    }
+               }
+          }
+          columnArray->setNumElements(numberNonZero);
+          y->setNumElements(0);
+     } else {
+          // do by row
+          rowCopy->transposeTimesByRow(model, scalar, rowArray, y, columnArray);
+     }
+     if (packed)
+          columnArray->setPackedMode(true);
+     if (0) {
+          columnArray->checkClean();
+          int numberNonZero = columnArray->getNumElements();;
+          int * index = columnArray->getIndices();
+          double * array = columnArray->denseVector();
+          int i;
+          for (i = 0; i < numberNonZero; i++) {
+               int j = index[i];
+               double value;
+               if (packed)
+                    value = array[i];
+               else
+                    value = array[j];
+               printf("Ti %d %d %g\n", i, j, value);
+          }
+     }
+}
+//static int xA=0;
+//static int xB=0;
+//static int xC=0;
+//static int xD=0;
+//static double yA=0.0;
+//static double yC=0.0;
+/* Return <code>x * scalar * A + y</code> in <code>z</code>.
+   Note - If x packed mode - then z packed mode
+   This does by column and knows no gaps
+   Squashes small elements and knows about ClpSimplex */
+void
+ClpPackedMatrix::transposeTimesByColumn(const ClpSimplex * model, double scalar,
+                                        const CoinIndexedVector * rowArray,
+                                        CoinIndexedVector * y,
+                                        CoinIndexedVector * columnArray) const
+{
+     double * COIN_RESTRICT pi = rowArray->denseVector();
+     int numberNonZero = 0;
+     int * COIN_RESTRICT index = columnArray->getIndices();
+     double * COIN_RESTRICT array = columnArray->denseVector();
+     int numberInRowArray = rowArray->getNumElements();
+     // maybe I need one in OsiSimplex
+     double zeroTolerance = model->zeroTolerance();
+     bool packed = rowArray->packedMode();
+     // do by column
+     int iColumn;
+     // get matrix data pointers
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+     const double * COIN_RESTRICT rowScale = model->rowScale();
+     assert (!y->getNumElements());
+     assert (numberActiveColumns_ > 0);
+     const ClpPackedMatrix * thisMatrix = this;
+#if 0
+     ClpPackedMatrix * scaledMatrix = model->clpScaledMatrix();
+     if (rowScale && scaledMatrix) {
+          rowScale = NULL;
+          // get matrix data pointers
+          row = scaledMatrix->getIndices();
+          columnStart = scaledMatrix->getVectorStarts();
+          elementByColumn = scaledMatrix->getElements();
+          thisMatrix = scaledMatrix;
+          //printf("scaledMatrix\n");
+     } else if (rowScale) {
+          //printf("no scaledMatrix\n");
+     } else {
+          //printf("no rowScale\n");
+     }
+#endif
+     if (packed) {
+          // need to expand pi into y
+          assert(y->capacity() >= model->numberRows());
+          double * piOld = pi;
+          pi = y->denseVector();
+          const int * COIN_RESTRICT whichRow = rowArray->getIndices();
+          int i;
+          if (!rowScale) {
+               // modify pi so can collapse to one loop
+               if (scalar == -1.0) {
+                    //yA += numberInRowArray;
+                    for (i = 0; i < numberInRowArray; i++) {
+                         int iRow = whichRow[i];
+                         pi[iRow] = -piOld[i];
+                    }
+               } else {
+                    for (i = 0; i < numberInRowArray; i++) {
+                         int iRow = whichRow[i];
+                         pi[iRow] = scalar * piOld[i];
+                    }
+               }
+               if (!columnCopy_) {
+                    if ((model->specialOptions(), 131072) != 0) {
+                         if(model->spareIntArray_[0] > 0) {
+                              CoinIndexedVector * spareArray = model->rowArray(3);
+                              // also do dualColumn stuff
+                              double * spare = spareArray->denseVector();
+                              int * spareIndex = spareArray->getIndices();
+                              const double * reducedCost = model->djRegion(0);
+                              double multiplier[] = { -1.0, 1.0};
+                              double dualT = - model->currentDualTolerance();
+                              double acceptablePivot = model->spareDoubleArray_[0];
+                              // We can also see if infeasible or pivoting on free
+                              double tentativeTheta = 1.0e15;
+                              double upperTheta = 1.0e31;
+                              double bestPossible = 0.0;
+                              int addSequence = model->numberColumns();
+                              const unsigned char * statusArray = model->statusArray() + addSequence;
+                              int numberRemaining = 0;
+                              assert (scalar == -1.0);
+                              for (i = 0; i < numberInRowArray; i++) {
+                                   int iSequence = whichRow[i];
+                                   int iStatus = (statusArray[iSequence] & 3) - 1;
+                                   if (iStatus) {
+                                        double mult = multiplier[iStatus-1];
+                                        double alpha = piOld[i] * mult;
+                                        double oldValue;
+                                        double value;
+                                        if (alpha > 0.0) {
+                                             oldValue = reducedCost[iSequence] * mult;
+                                             value = oldValue - tentativeTheta * alpha;
+                                             if (value < dualT) {
+                                                  bestPossible = CoinMax(bestPossible, alpha);
+                                                  value = oldValue - upperTheta * alpha;
+                                                  if (value < dualT && alpha >= acceptablePivot) {
+                                                       upperTheta = (oldValue - dualT) / alpha;
+                                                       //tentativeTheta = CoinMin(2.0*upperTheta,tentativeTheta);
+                                                  }
+                                                  // add to list
+                                                  spare[numberRemaining] = alpha * mult;
+                                                  spareIndex[numberRemaining++] = iSequence + addSequence;
+                                             }
+                                        }
+                                   }
+                              }
+                              numberNonZero =
+                                   thisMatrix->gutsOfTransposeTimesUnscaled(pi,
+                                             columnArray->getIndices(),
+                                             columnArray->denseVector(),
+                                             model->statusArray(),
+                                             spareIndex,
+                                             spare,
+                                             model->djRegion(1),
+                                             upperTheta,
+                                             bestPossible,
+                                             acceptablePivot,
+                                             model->currentDualTolerance(),
+                                             numberRemaining,
+                                             zeroTolerance);
+                              model->spareDoubleArray_[0] = upperTheta;
+                              model->spareDoubleArray_[1] = bestPossible;
+                              spareArray->setNumElements(numberRemaining);
+                              // signal partially done
+                              model->spareIntArray_[0] = -2;
+                         } else {
+                              numberNonZero =
+                                   thisMatrix->gutsOfTransposeTimesUnscaled(pi,
+                                             columnArray->getIndices(),
+                                             columnArray->denseVector(),
+                                             model->statusArray(),
+                                             zeroTolerance);
+                         }
+                    } else {
+                         numberNonZero =
+                              thisMatrix->gutsOfTransposeTimesUnscaled(pi,
+                                        columnArray->getIndices(),
+                                        columnArray->denseVector(),
+                                        zeroTolerance);
+                    }
+                    columnArray->setNumElements(numberNonZero);
+                    //xA++;
+               } else {
+                    columnCopy_->transposeTimes(model, pi, columnArray);
+                    numberNonZero = columnArray->getNumElements();
+                    //xB++;
+               }
+          } else {
+#ifdef CLP_INVESTIGATE
+               if (model->clpScaledMatrix())
+                    printf("scaledMatrix_ at %d of ClpPackedMatrix\n", __LINE__);
+#endif
+               // scaled
+               // modify pi so can collapse to one loop
+               if (scalar == -1.0) {
+                    //yC += numberInRowArray;
+                    for (i = 0; i < numberInRowArray; i++) {
+                         int iRow = whichRow[i];
+                         pi[iRow] = -piOld[i] * rowScale[iRow];
+                    }
+               } else {
+                    for (i = 0; i < numberInRowArray; i++) {
+                         int iRow = whichRow[i];
+                         pi[iRow] = scalar * piOld[i] * rowScale[iRow];
+                    }
+               }
+               const double * columnScale = model->columnScale();
+               if (!columnCopy_) {
+                    if ((model->specialOptions(), 131072) != 0)
+                         numberNonZero =
+                              gutsOfTransposeTimesScaled(pi, columnScale,
+                                                         columnArray->getIndices(),
+                                                         columnArray->denseVector(),
+                                                         model->statusArray(),
+                                                         zeroTolerance);
+                    else
+                         numberNonZero =
+                              gutsOfTransposeTimesScaled(pi, columnScale,
+                                                         columnArray->getIndices(),
+                                                         columnArray->denseVector(),
+                                                         zeroTolerance);
+                    columnArray->setNumElements(numberNonZero);
+                    //xC++;
+               } else {
+                    columnCopy_->transposeTimes(model, pi, columnArray);
+                    numberNonZero = columnArray->getNumElements();
+                    //xD++;
+               }
+          }
+          // zero out
+          int numberRows = model->numberRows();
+          if (numberInRowArray * 4 < numberRows) {
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = 0.0;
+               }
+          } else {
+               CoinZeroN(pi, numberRows);
+          }
+          //int kA=xA+xB;
+          //int kC=xC+xD;
+          //if ((kA+kC)%10000==0)
+          //printf("AA %d %d %g, CC %d %d %g\n",
+          //     xA,xB,kA ? yA/(double)(kA): 0.0,xC,xD,kC ? yC/(double) (kC) :0.0);
+     } else {
+          if (!rowScale) {
+               if (scalar == -1.0) {
+                    double value = 0.0;
+                    CoinBigIndex j;
+                    CoinBigIndex end = columnStart[1];
+                    for (j = columnStart[0]; j < end; j++) {
+                         int iRow = row[j];
+                         value += pi[iRow] * elementByColumn[j];
+                    }
+                    for (iColumn = 0; iColumn < numberActiveColumns_ - 1; iColumn++) {
+                         CoinBigIndex start = end;
+                         end = columnStart[iColumn+2];
+                         if (fabs(value) > zeroTolerance) {
+                              array[iColumn] = -value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         value = 0.0;
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              value += pi[iRow] * elementByColumn[j];
+                         }
+                    }
+                    if (fabs(value) > zeroTolerance) {
+                         array[iColumn] = -value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               } else {
+                    double value = 0.0;
+                    CoinBigIndex j;
+                    CoinBigIndex end = columnStart[1];
+                    for (j = columnStart[0]; j < end; j++) {
+                         int iRow = row[j];
+                         value += pi[iRow] * elementByColumn[j];
+                    }
+                    for (iColumn = 0; iColumn < numberActiveColumns_ - 1; iColumn++) {
+                         value *= scalar;
+                         CoinBigIndex start = end;
+                         end = columnStart[iColumn+2];
+                         if (fabs(value) > zeroTolerance) {
+                              array[iColumn] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         value = 0.0;
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              value += pi[iRow] * elementByColumn[j];
+                         }
+                    }
+                    value *= scalar;
+                    if (fabs(value) > zeroTolerance) {
+                         array[iColumn] = value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               }
+          } else {
+#ifdef CLP_INVESTIGATE
+               if (model->clpScaledMatrix())
+                    printf("scaledMatrix_ at %d of ClpPackedMatrix\n", __LINE__);
+#endif
+               // scaled
+               if (scalar == -1.0) {
+                    const double * columnScale = model->columnScale();
+                    double value = 0.0;
+                    double scale = columnScale[0];
+                    CoinBigIndex j;
+                    CoinBigIndex end = columnStart[1];
+                    for (j = columnStart[0]; j < end; j++) {
+                         int iRow = row[j];
+                         value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                    }
+                    for (iColumn = 0; iColumn < numberActiveColumns_ - 1; iColumn++) {
+                         value *= scale;
+                         CoinBigIndex start = end;
+                         end = columnStart[iColumn+2];
+                         scale = columnScale[iColumn+1];
+                         if (fabs(value) > zeroTolerance) {
+                              array[iColumn] = -value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         value = 0.0;
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                         }
+                    }
+                    value *= scale;
+                    if (fabs(value) > zeroTolerance) {
+                         array[iColumn] = -value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               } else {
+                    const double * columnScale = model->columnScale();
+                    double value = 0.0;
+                    double scale = columnScale[0] * scalar;
+                    CoinBigIndex j;
+                    CoinBigIndex end = columnStart[1];
+                    for (j = columnStart[0]; j < end; j++) {
+                         int iRow = row[j];
+                         value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                    }
+                    for (iColumn = 0; iColumn < numberActiveColumns_ - 1; iColumn++) {
+                         value *= scale;
+                         CoinBigIndex start = end;
+                         end = columnStart[iColumn+2];
+                         scale = columnScale[iColumn+1] * scalar;
+                         if (fabs(value) > zeroTolerance) {
+                              array[iColumn] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         value = 0.0;
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                         }
+                    }
+                    value *= scale;
+                    if (fabs(value) > zeroTolerance) {
+                         array[iColumn] = value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               }
+          }
+     }
+     columnArray->setNumElements(numberNonZero);
+     y->setNumElements(0);
+     if (packed)
+          columnArray->setPackedMode(true);
+}
+/* Return <code>x * A + y</code> in <code>z</code>.
+	Squashes small elements and knows about ClpSimplex */
+void
+ClpPackedMatrix::transposeTimesByRow(const ClpSimplex * model, double scalar,
+                                     const CoinIndexedVector * rowArray,
+                                     CoinIndexedVector * y,
+                                     CoinIndexedVector * columnArray) const
+{
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     int numberNonZero = 0;
+     int * index = columnArray->getIndices();
+     double * array = columnArray->denseVector();
+     int numberInRowArray = rowArray->getNumElements();
+     // maybe I need one in OsiSimplex
+     double zeroTolerance = model->zeroTolerance();
+     const int * column = matrix_->getIndices();
+     const CoinBigIndex * rowStart = getVectorStarts();
+     const double * element = getElements();
+     const int * whichRow = rowArray->getIndices();
+     bool packed = rowArray->packedMode();
+     if (numberInRowArray > 2) {
+          // do by rows
+          // ** Row copy is already scaled
+          int iRow;
+          int i;
+          int numberOriginal = 0;
+          if (packed) {
+               int * index = columnArray->getIndices();
+               double * array = columnArray->denseVector();
+#if 0
+	       {
+		 double  * array2 = y->denseVector();
+		 int numberColumns = matrix_->getNumCols();
+		 for (int i=0;i<numberColumns;i++) {
+		   assert(!array[i]);
+		   assert(!array2[i]);
+		 }
+	       }
+#endif
+	       //#define COIN_SPARSE_MATRIX 1
+#if COIN_SPARSE_MATRIX
+               assert (!y->getNumElements());
+#if COIN_SPARSE_MATRIX != 2
+               // and set up mark as char array
+               char * marked = reinterpret_cast<char *> (index+columnArray->capacity());
+               int * lookup = y->getIndices();
+#ifndef NDEBUG
+               //int numberColumns = matrix_->getNumCols();
+               //for (int i=0;i<numberColumns;i++)
+               //assert(!marked[i]);
+#endif
+               numberNonZero=gutsOfTransposeTimesByRowGE3a(rowArray,index,array,
+               				   lookup,marked,zeroTolerance,scalar);
+#else
+               double  * array2 = y->denseVector();
+               numberNonZero=gutsOfTransposeTimesByRowGE3(rowArray,index,array,
+               				   array2,zeroTolerance,scalar);
+#endif
+#else
+               int numberColumns = matrix_->getNumCols();
+               numberNonZero = gutsOfTransposeTimesByRowGEK(rowArray, index, array,
+                               numberColumns, zeroTolerance, scalar);
+#endif
+               columnArray->setNumElements(numberNonZero);
+          } else {
+               double * markVector = y->denseVector();
+               numberNonZero = 0;
+               // and set up mark as char array
+               char * marked = reinterpret_cast<char *> (markVector);
+               for (i = 0; i < numberOriginal; i++) {
+                    int iColumn = index[i];
+                    marked[iColumn] = 0;
+               }
+
+               for (i = 0; i < numberInRowArray; i++) {
+                    iRow = whichRow[i];
+                    double value = pi[iRow] * scalar;
+                    CoinBigIndex j;
+                    for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                         int iColumn = column[j];
+                         if (!marked[iColumn]) {
+                              marked[iColumn] = 1;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         array[iColumn] += value * element[j];
+                    }
+               }
+               // get rid of tiny values and zero out marked
+               numberOriginal = numberNonZero;
+               numberNonZero = 0;
+               for (i = 0; i < numberOriginal; i++) {
+                    int iColumn = index[i];
+                    marked[iColumn] = 0;
+                    if (fabs(array[iColumn]) > zeroTolerance) {
+                         index[numberNonZero++] = iColumn;
+                    } else {
+                         array[iColumn] = 0.0;
+                    }
+               }
+          }
+     } else if (numberInRowArray == 2) {
+          // do by rows when two rows
+          int numberOriginal;
+          int i;
+          CoinBigIndex j;
+          numberNonZero = 0;
+
+          double value;
+          if (packed) {
+               gutsOfTransposeTimesByRowEQ2(rowArray, columnArray, y, zeroTolerance, scalar);
+               numberNonZero = columnArray->getNumElements();
+          } else {
+               int iRow = whichRow[0];
+               value = pi[iRow] * scalar;
+               for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                    int iColumn = column[j];
+                    double value2 = value * element[j];
+                    index[numberNonZero++] = iColumn;
+                    array[iColumn] = value2;
+               }
+               iRow = whichRow[1];
+               value = pi[iRow] * scalar;
+               for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                    int iColumn = column[j];
+                    double value2 = value * element[j];
+                    // I am assuming no zeros in matrix
+                    if (array[iColumn])
+                         value2 += array[iColumn];
+                    else
+                         index[numberNonZero++] = iColumn;
+                    array[iColumn] = value2;
+               }
+               // get rid of tiny values and zero out marked
+               numberOriginal = numberNonZero;
+               numberNonZero = 0;
+               for (i = 0; i < numberOriginal; i++) {
+                    int iColumn = index[i];
+                    if (fabs(array[iColumn]) > zeroTolerance) {
+                         index[numberNonZero++] = iColumn;
+                    } else {
+                         array[iColumn] = 0.0;
+                    }
+               }
+          }
+     } else if (numberInRowArray == 1) {
+          // Just one row
+          int iRow = rowArray->getIndices()[0];
+          numberNonZero = 0;
+          CoinBigIndex j;
+          if (packed) {
+               gutsOfTransposeTimesByRowEQ1(rowArray, columnArray, zeroTolerance, scalar);
+               numberNonZero = columnArray->getNumElements();
+          } else {
+               double value = pi[iRow] * scalar;
+               for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                    int iColumn = column[j];
+                    double value2 = value * element[j];
+                    if (fabs(value2) > zeroTolerance) {
+                         index[numberNonZero++] = iColumn;
+                         array[iColumn] = value2;
+                    }
+               }
+          }
+     }
+     columnArray->setNumElements(numberNonZero);
+     y->setNumElements(0);
+}
+// Meat of transposeTimes by column when not scaled
+int
+ClpPackedMatrix::gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
+          int * COIN_RESTRICT index,
+          double * COIN_RESTRICT array,
+          const double zeroTolerance) const
+{
+     int numberNonZero = 0;
+     // get matrix data pointers
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+#if 1 //ndef INTEL_MKL
+     double value = 0.0;
+     CoinBigIndex j;
+     CoinBigIndex end = columnStart[1];
+     for (j = columnStart[0]; j < end; j++) {
+          int iRow = row[j];
+          value += pi[iRow] * elementByColumn[j];
+     }
+     int iColumn;
+     for (iColumn = 0; iColumn < numberActiveColumns_ - 1; iColumn++) {
+          CoinBigIndex start = end;
+          end = columnStart[iColumn+2];
+          if (fabs(value) > zeroTolerance) {
+               array[numberNonZero] = value;
+               index[numberNonZero++] = iColumn;
+          }
+          value = 0.0;
+          for (j = start; j < end; j++) {
+               int iRow = row[j];
+               value += pi[iRow] * elementByColumn[j];
+          }
+     }
+     if (fabs(value) > zeroTolerance) {
+          array[numberNonZero] = value;
+          index[numberNonZero++] = iColumn;
+     }
+#else
+     char transA = 'N';
+     //int numberRows = matrix_->getNumRows();
+     mkl_cspblas_dcsrgemv(&transA, const_cast<int *>(&numberActiveColumns_),
+                          const_cast<double *>(elementByColumn),
+                          const_cast<int *>(columnStart),
+                          const_cast<int *>(row),
+                          const_cast<double *>(pi), array);
+     int iColumn;
+     for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+          double value = array[iColumn];
+          if (value) {
+               array[iColumn] = 0.0;
+               if (fabs(value) > zeroTolerance) {
+                    array[numberNonZero] = value;
+                    index[numberNonZero++] = iColumn;
+               }
+          }
+     }
+#endif
+     return numberNonZero;
+}
+// Meat of transposeTimes by column when scaled
+int
+ClpPackedMatrix::gutsOfTransposeTimesScaled(const double * COIN_RESTRICT pi,
+          const double * COIN_RESTRICT columnScale,
+          int * COIN_RESTRICT index,
+          double * COIN_RESTRICT array,
+          const double zeroTolerance) const
+{
+     int numberNonZero = 0;
+     // get matrix data pointers
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+     double value = 0.0;
+     double scale = columnScale[0];
+     CoinBigIndex j;
+     CoinBigIndex end = columnStart[1];
+     for (j = columnStart[0]; j < end; j++) {
+          int iRow = row[j];
+          value += pi[iRow] * elementByColumn[j];
+     }
+     int iColumn;
+     for (iColumn = 0; iColumn < numberActiveColumns_ - 1; iColumn++) {
+          value *= scale;
+          CoinBigIndex start = end;
+          scale = columnScale[iColumn+1];
+          end = columnStart[iColumn+2];
+          if (fabs(value) > zeroTolerance) {
+               array[numberNonZero] = value;
+               index[numberNonZero++] = iColumn;
+          }
+          value = 0.0;
+          for (j = start; j < end; j++) {
+               int iRow = row[j];
+               value += pi[iRow] * elementByColumn[j];
+          }
+     }
+     value *= scale;
+     if (fabs(value) > zeroTolerance) {
+          array[numberNonZero] = value;
+          index[numberNonZero++] = iColumn;
+     }
+     return numberNonZero;
+}
+// Meat of transposeTimes by column when not scaled
+int
+ClpPackedMatrix::gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
+          int * COIN_RESTRICT index,
+          double * COIN_RESTRICT array,
+          const unsigned char * COIN_RESTRICT status,
+          const double zeroTolerance) const
+{
+     int numberNonZero = 0;
+     // get matrix data pointers
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+     double value = 0.0;
+     int jColumn = -1;
+     for (int iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+          bool wanted = ((status[iColumn] & 3) != 1);
+          if (fabs(value) > zeroTolerance) {
+               array[numberNonZero] = value;
+               index[numberNonZero++] = jColumn;
+          }
+          value = 0.0;
+          if (wanted) {
+               CoinBigIndex start = columnStart[iColumn];
+               CoinBigIndex end = columnStart[iColumn+1];
+               jColumn = iColumn;
+               int n = end - start;
+               bool odd = (n & 1) != 0;
+               n = n >> 1;
+               const int * COIN_RESTRICT rowThis = row + start;
+               const double * COIN_RESTRICT elementThis = elementByColumn + start;
+               for (; n; n--) {
+                    int iRow0 = *rowThis;
+                    int iRow1 = *(rowThis + 1);
+                    rowThis += 2;
+                    value += pi[iRow0] * (*elementThis);
+                    value += pi[iRow1] * (*(elementThis + 1));
+                    elementThis += 2;
+               }
+               if (odd) {
+                    int iRow = *rowThis;
+                    value += pi[iRow] * (*elementThis);
+               }
+          }
+     }
+     if (fabs(value) > zeroTolerance) {
+          array[numberNonZero] = value;
+          index[numberNonZero++] = jColumn;
+     }
+     return numberNonZero;
+}
+/* Meat of transposeTimes by column when not scaled and skipping
+   and doing part of dualColumn */
+int
+ClpPackedMatrix::gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
+          int * COIN_RESTRICT index,
+          double * COIN_RESTRICT array,
+          const unsigned char * COIN_RESTRICT status,
+          int * COIN_RESTRICT spareIndex,
+          double * COIN_RESTRICT spareArray,
+          const double * COIN_RESTRICT reducedCost,
+          double & upperThetaP,
+          double & bestPossibleP,
+          double acceptablePivot,
+          double dualTolerance,
+          int & numberRemainingP,
+          const double zeroTolerance) const
+{
+     double tentativeTheta = 1.0e15;
+     int numberRemaining = numberRemainingP;
+     double upperTheta = upperThetaP;
+     double bestPossible = bestPossibleP;
+     int numberNonZero = 0;
+     // get matrix data pointers
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+     double multiplier[] = { -1.0, 1.0};
+     double dualT = - dualTolerance;
+     for (int iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+          int wanted = (status[iColumn] & 3) - 1;
+          if (wanted) {
+               double value = 0.0;
+               CoinBigIndex start = columnStart[iColumn];
+               CoinBigIndex end = columnStart[iColumn+1];
+               int n = end - start;
+#if 1
+               bool odd = (n & 1) != 0;
+               n = n >> 1;
+               const int * COIN_RESTRICT rowThis = row + start;
+               const double * COIN_RESTRICT elementThis = elementByColumn + start;
+               for (; n; n--) {
+                    int iRow0 = *rowThis;
+                    int iRow1 = *(rowThis + 1);
+                    rowThis += 2;
+                    value += pi[iRow0] * (*elementThis);
+                    value += pi[iRow1] * (*(elementThis + 1));
+                    elementThis += 2;
+               }
+               if (odd) {
+                    int iRow = *rowThis;
+                    value += pi[iRow] * (*elementThis);
+               }
+#else
+               const int * COIN_RESTRICT rowThis = &row[end-16];
+               const double * COIN_RESTRICT elementThis = &elementByColumn[end-16];
+               bool odd = (n & 1) != 0;
+               n = n >> 1;
+               double value2 = 0.0;
+               if (odd) {
+                    int iRow = row[start];
+                    value2 = pi[iRow] * elementByColumn[start];
+               }
+               switch (n) {
+               default: {
+                    if (odd) {
+                         start++;
+                    }
+                    n -= 8;
+                    for (; n; n--) {
+                         int iRow0 = row[start];
+                         int iRow1 = row[start+1];
+                         value += pi[iRow0] * elementByColumn[start];
+                         value2 += pi[iRow1] * elementByColumn[start+1];
+                         start += 2;
+                    }
+                    case 8: {
+                         int iRow0 = rowThis[16-16];
+                         int iRow1 = rowThis[16-15];
+                         value += pi[iRow0] * elementThis[16-16];
+                         value2 += pi[iRow1] * elementThis[16-15];
+                    }
+                    case 7: {
+                         int iRow0 = rowThis[16-14];
+                         int iRow1 = rowThis[16-13];
+                         value += pi[iRow0] * elementThis[16-14];
+                         value2 += pi[iRow1] * elementThis[16-13];
+                    }
+                    case 6: {
+                         int iRow0 = rowThis[16-12];
+                         int iRow1 = rowThis[16-11];
+                         value += pi[iRow0] * elementThis[16-12];
+                         value2 += pi[iRow1] * elementThis[16-11];
+                    }
+                    case 5: {
+                         int iRow0 = rowThis[16-10];
+                         int iRow1 = rowThis[16-9];
+                         value += pi[iRow0] * elementThis[16-10];
+                         value2 += pi[iRow1] * elementThis[16-9];
+                    }
+                    case 4: {
+                         int iRow0 = rowThis[16-8];
+                         int iRow1 = rowThis[16-7];
+                         value += pi[iRow0] * elementThis[16-8];
+                         value2 += pi[iRow1] * elementThis[16-7];
+                    }
+                    case 3: {
+                         int iRow0 = rowThis[16-6];
+                         int iRow1 = rowThis[16-5];
+                         value += pi[iRow0] * elementThis[16-6];
+                         value2 += pi[iRow1] * elementThis[16-5];
+                    }
+                    case 2: {
+                         int iRow0 = rowThis[16-4];
+                         int iRow1 = rowThis[16-3];
+                         value += pi[iRow0] * elementThis[16-4];
+                         value2 += pi[iRow1] * elementThis[16-3];
+                    }
+                    case 1: {
+                         int iRow0 = rowThis[16-2];
+                         int iRow1 = rowThis[16-1];
+                         value += pi[iRow0] * elementThis[16-2];
+                         value2 += pi[iRow1] * elementThis[16-1];
+                    }
+                    case 0:
+                         ;
+                    }
+               }
+               value += value2;
+#endif
+               if (fabs(value) > zeroTolerance) {
+                    double mult = multiplier[wanted-1];
+                    double alpha = value * mult;
+                    array[numberNonZero] = value;
+                    index[numberNonZero++] = iColumn;
+                    if (alpha > 0.0) {
+                         double oldValue = reducedCost[iColumn] * mult;
+                         double value = oldValue - tentativeTheta * alpha;
+                         if (value < dualT) {
+                              bestPossible = CoinMax(bestPossible, alpha);
+                              value = oldValue - upperTheta * alpha;
+                              if (value < dualT && alpha >= acceptablePivot) {
+                                   upperTheta = (oldValue - dualT) / alpha;
+                                   //tentativeTheta = CoinMin(2.0*upperTheta,tentativeTheta);
+                              }
+                              // add to list
+                              spareArray[numberRemaining] = alpha * mult;
+                              spareIndex[numberRemaining++] = iColumn;
+                         }
+                    }
+               }
+          }
+     }
+     numberRemainingP = numberRemaining;
+     upperThetaP = upperTheta;
+     bestPossibleP = bestPossible;
+     return numberNonZero;
+}
+// Meat of transposeTimes by column when scaled
+int
+ClpPackedMatrix::gutsOfTransposeTimesScaled(const double * COIN_RESTRICT pi,
+          const double * COIN_RESTRICT columnScale,
+          int * COIN_RESTRICT index,
+          double * COIN_RESTRICT array,
+          const unsigned char * COIN_RESTRICT status,				 const double zeroTolerance) const
+{
+     int numberNonZero = 0;
+     // get matrix data pointers
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+     double value = 0.0;
+     int jColumn = -1;
+     for (int iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+          bool wanted = ((status[iColumn] & 3) != 1);
+          if (fabs(value) > zeroTolerance) {
+               array[numberNonZero] = value;
+               index[numberNonZero++] = jColumn;
+          }
+          value = 0.0;
+          if (wanted) {
+               double scale = columnScale[iColumn];
+               CoinBigIndex start = columnStart[iColumn];
+               CoinBigIndex end = columnStart[iColumn+1];
+               jColumn = iColumn;
+               for (CoinBigIndex j = start; j < end; j++) {
+                    int iRow = row[j];
+                    value += pi[iRow] * elementByColumn[j];
+               }
+               value *= scale;
+          }
+     }
+     if (fabs(value) > zeroTolerance) {
+          array[numberNonZero] = value;
+          index[numberNonZero++] = jColumn;
+     }
+     return numberNonZero;
+}
+// Meat of transposeTimes by row n > K if packed - returns number nonzero
+int
+ClpPackedMatrix::gutsOfTransposeTimesByRowGEK(const CoinIndexedVector * COIN_RESTRICT piVector,
+          int * COIN_RESTRICT index,
+          double * COIN_RESTRICT output,
+          int numberColumns,
+          const double tolerance,
+          const double scalar) const
+{
+     const double * COIN_RESTRICT pi = piVector->denseVector();
+     int numberInRowArray = piVector->getNumElements();
+     const int * COIN_RESTRICT column = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT rowStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT element = matrix_->getElements();
+     const int * COIN_RESTRICT whichRow = piVector->getIndices();
+     // ** Row copy is already scaled
+     for (int i = 0; i < numberInRowArray; i++) {
+          int iRow = whichRow[i];
+          double value = pi[i] * scalar;
+          CoinBigIndex start = rowStart[iRow];
+          CoinBigIndex end = rowStart[iRow+1];
+          int n = end - start;
+          const int * COIN_RESTRICT columnThis = column + start;
+          const double * COIN_RESTRICT elementThis = element + start;
+
+          // could do by twos
+          for (; n; n--) {
+               int iColumn = *columnThis;
+               columnThis++;
+               double elValue = *elementThis;
+               elementThis++;
+               elValue *= value;
+               output[iColumn] += elValue;
+          }
+     }
+     // get rid of tiny values and count
+     int numberNonZero = 0;
+     for (int i = 0; i < numberColumns; i++) {
+          double value = output[i];
+          if (value) {
+               output[i] = 0.0;
+               if (fabs(value) > tolerance) {
+                    output[numberNonZero] = value;
+                    index[numberNonZero++] = i;
+               }
+          }
+     }
+#ifndef NDEBUG
+     for (int i = numberNonZero; i < numberColumns; i++)
+          assert(!output[i]);
+#endif
+     return numberNonZero;
+}
+// Meat of transposeTimes by row n == 2 if packed
+void
+ClpPackedMatrix::gutsOfTransposeTimesByRowEQ2(const CoinIndexedVector * piVector, CoinIndexedVector * output,
+          CoinIndexedVector * spareVector, const double tolerance, const double scalar) const
+{
+     double * pi = piVector->denseVector();
+     int numberNonZero = 0;
+     int * index = output->getIndices();
+     double * array = output->denseVector();
+     const int * column = matrix_->getIndices();
+     const CoinBigIndex * rowStart = matrix_->getVectorStarts();
+     const double * element = matrix_->getElements();
+     const int * whichRow = piVector->getIndices();
+     int iRow0 = whichRow[0];
+     int iRow1 = whichRow[1];
+     double pi0 = pi[0];
+     double pi1 = pi[1];
+     if (rowStart[iRow0+1] - rowStart[iRow0] >
+               rowStart[iRow1+1] - rowStart[iRow1]) {
+          // do one with fewer first
+          iRow0 = iRow1;
+          iRow1 = whichRow[0];
+          pi0 = pi1;
+          pi1 = pi[0];
+     }
+     // and set up mark as char array
+     char * marked = reinterpret_cast<char *> (index + output->capacity());
+     int * lookup = spareVector->getIndices();
+     double value = pi0 * scalar;
+     CoinBigIndex j;
+     for (j = rowStart[iRow0]; j < rowStart[iRow0+1]; j++) {
+          int iColumn = column[j];
+          double elValue = element[j];
+          double value2 = value * elValue;
+          array[numberNonZero] = value2;
+          marked[iColumn] = 1;
+          lookup[iColumn] = numberNonZero;
+          index[numberNonZero++] = iColumn;
+     }
+     int numberOriginal = numberNonZero;
+     value = pi1 * scalar;
+     for (j = rowStart[iRow1]; j < rowStart[iRow1+1]; j++) {
+          int iColumn = column[j];
+          double elValue = element[j];
+          double value2 = value * elValue;
+          // I am assuming no zeros in matrix
+          if (marked[iColumn]) {
+               int iLookup = lookup[iColumn];
+               array[iLookup] += value2;
+          } else {
+               if (fabs(value2) > tolerance) {
+                    array[numberNonZero] = value2;
+                    index[numberNonZero++] = iColumn;
+               }
+          }
+     }
+     // get rid of tiny values and zero out marked
+     int i;
+     int iFirst = numberNonZero;
+     for (i = 0; i < numberOriginal; i++) {
+          int iColumn = index[i];
+          marked[iColumn] = 0;
+          if (fabs(array[i]) <= tolerance) {
+               if (numberNonZero > numberOriginal) {
+                    numberNonZero--;
+                    double value = array[numberNonZero];
+                    array[numberNonZero] = 0.0;
+                    array[i] = value;
+                    index[i] = index[numberNonZero];
+               } else {
+                    iFirst = i;
+               }
+          }
+     }
+
+     if (iFirst < numberNonZero) {
+          int n = iFirst;
+          for (i = n; i < numberOriginal; i++) {
+               int iColumn = index[i];
+               double value = array[i];
+               array[i] = 0.0;
+               if (fabs(value) > tolerance) {
+                    array[n] = value;
+                    index[n++] = iColumn;
+               }
+          }
+          for (; i < numberNonZero; i++) {
+               int iColumn = index[i];
+               double value = array[i];
+               array[i] = 0.0;
+               array[n] = value;
+               index[n++] = iColumn;
+          }
+          numberNonZero = n;
+     }
+     output->setNumElements(numberNonZero);
+     spareVector->setNumElements(0);
+}
+// Meat of transposeTimes by row n == 1 if packed
+void
+ClpPackedMatrix::gutsOfTransposeTimesByRowEQ1(const CoinIndexedVector * piVector, CoinIndexedVector * output,
+          const double tolerance, const double scalar) const
+{
+     double * pi = piVector->denseVector();
+     int numberNonZero = 0;
+     int * index = output->getIndices();
+     double * array = output->denseVector();
+     const int * column = matrix_->getIndices();
+     const CoinBigIndex * rowStart = matrix_->getVectorStarts();
+     const double * element = matrix_->getElements();
+     int iRow = piVector->getIndices()[0];
+     numberNonZero = 0;
+     CoinBigIndex j;
+     double value = pi[0] * scalar;
+     for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+          int iColumn = column[j];
+          double elValue = element[j];
+          double value2 = value * elValue;
+          if (fabs(value2) > tolerance) {
+               array[numberNonZero] = value2;
+               index[numberNonZero++] = iColumn;
+          }
+     }
+     output->setNumElements(numberNonZero);
+}
+/* Return <code>x *A in <code>z</code> but
+   just for indices in y.
+   Squashes small elements and knows about ClpSimplex */
+void
+ClpPackedMatrix::subsetTransposeTimes(const ClpSimplex * model,
+                                      const CoinIndexedVector * rowArray,
+                                      const CoinIndexedVector * y,
+                                      CoinIndexedVector * columnArray) const
+{
+     columnArray->clear();
+     double * COIN_RESTRICT pi = rowArray->denseVector();
+     double * COIN_RESTRICT array = columnArray->denseVector();
+     int jColumn;
+     // get matrix data pointers
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const int * COIN_RESTRICT columnLength = matrix_->getVectorLengths();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+     const double * COIN_RESTRICT rowScale = model->rowScale();
+     int numberToDo = y->getNumElements();
+     const int * COIN_RESTRICT which = y->getIndices();
+     assert (!rowArray->packedMode());
+     columnArray->setPacked();
+     ClpPackedMatrix * scaledMatrix = model->clpScaledMatrix();
+     int flags = flags_;
+     if (rowScale && scaledMatrix && !(scaledMatrix->flags() & 2)) {
+          flags = 0;
+          rowScale = NULL;
+          // get matrix data pointers
+          row = scaledMatrix->getIndices();
+          columnStart = scaledMatrix->getVectorStarts();
+          elementByColumn = scaledMatrix->getElements();
+     }
+     if (!(flags & 2) && numberToDo>2) {
+          // no gaps
+          if (!rowScale) {
+               int iColumn = which[0];
+               double value = 0.0;
+               CoinBigIndex j;
+	       int columnNext = which[1];
+               CoinBigIndex startNext=columnStart[columnNext];
+	       //coin_prefetch_const(row+startNext); 
+	       //coin_prefetch_const(elementByColumn+startNext); 
+               CoinBigIndex endNext=columnStart[columnNext+1];
+               for (j = columnStart[iColumn];
+                         j < columnStart[iColumn+1]; j++) {
+                    int iRow = row[j];
+                    value += pi[iRow] * elementByColumn[j];
+               }
+               for (jColumn = 0; jColumn < numberToDo - 2; jColumn++) {
+                    CoinBigIndex start = startNext;
+                    CoinBigIndex end = endNext;
+                    columnNext = which[jColumn+2];
+		    startNext=columnStart[columnNext];
+		    //coin_prefetch_const(row+startNext); 
+		    //coin_prefetch_const(elementByColumn+startNext); 
+		    endNext=columnStart[columnNext+1];
+                    array[jColumn] = value;
+                    value = 0.0;
+                    for (j = start; j < end; j++) {
+                         int iRow = row[j];
+                         value += pi[iRow] * elementByColumn[j];
+                    }
+               }
+	       array[jColumn++] = value;
+	       value = 0.0;
+	       for (j = startNext; j < endNext; j++) {
+		 int iRow = row[j];
+		 value += pi[iRow] * elementByColumn[j];
+	       }
+               array[jColumn] = value;
+          } else {
+#ifdef CLP_INVESTIGATE
+               if (model->clpScaledMatrix())
+                    printf("scaledMatrix_ at %d of ClpPackedMatrix\n", __LINE__);
+#endif
+               // scaled
+               const double * columnScale = model->columnScale();
+               int iColumn = which[0];
+               double value = 0.0;
+               double scale = columnScale[iColumn];
+               CoinBigIndex j;
+               for (j = columnStart[iColumn];
+                         j < columnStart[iColumn+1]; j++) {
+                    int iRow = row[j];
+                    value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+               }
+               for (jColumn = 0; jColumn < numberToDo - 1; jColumn++) {
+                    int iColumn = which[jColumn+1];
+                    value *= scale;
+                    scale = columnScale[iColumn];
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = columnStart[iColumn+1];
+                    array[jColumn] = value;
+                    value = 0.0;
+                    for (j = start; j < end; j++) {
+                         int iRow = row[j];
+                         value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                    }
+               }
+               value *= scale;
+               array[jColumn] = value;
+          }
+     } else if (numberToDo) {
+          // gaps
+          if (!rowScale) {
+               for (jColumn = 0; jColumn < numberToDo; jColumn++) {
+                    int iColumn = which[jColumn];
+                    double value = 0.0;
+                    CoinBigIndex j;
+                    for (j = columnStart[iColumn];
+                              j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         int iRow = row[j];
+                         value += pi[iRow] * elementByColumn[j];
+                    }
+                    array[jColumn] = value;
+               }
+          } else {
+#ifdef CLP_INVESTIGATE
+               if (model->clpScaledMatrix())
+                    printf("scaledMatrix_ at %d of ClpPackedMatrix - flags %d (%d) n %d\n",
+                           __LINE__, flags_, model->clpScaledMatrix()->flags(), numberToDo);
+#endif
+               // scaled
+               const double * columnScale = model->columnScale();
+               for (jColumn = 0; jColumn < numberToDo; jColumn++) {
+                    int iColumn = which[jColumn];
+                    double value = 0.0;
+                    CoinBigIndex j;
+                    for (j = columnStart[iColumn];
+                              j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         int iRow = row[j];
+                         value += pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                    }
+                    value *= columnScale[iColumn];
+                    array[jColumn] = value;
+               }
+          }
+     }
+}
+/* Returns true if can combine transposeTimes and subsetTransposeTimes
+   and if it would be faster */
+bool
+ClpPackedMatrix::canCombine(const ClpSimplex * model,
+                            const CoinIndexedVector * pi) const
+{
+     int numberInRowArray = pi->getNumElements();
+     int numberRows = model->numberRows();
+     bool packed = pi->packedMode();
+     // factor should be smaller if doing both with two pi vectors
+     double factor = 0.30;
+     // We may not want to do by row if there may be cache problems
+     // It would be nice to find L2 cache size - for moment 512K
+     // Be slightly optimistic
+     if (numberActiveColumns_ * sizeof(double) > 1000000) {
+          if (numberRows * 10 < numberActiveColumns_)
+               factor *= 0.333333333;
+          else if (numberRows * 4 < numberActiveColumns_)
+               factor *= 0.5;
+          else if (numberRows * 2 < numberActiveColumns_)
+               factor *= 0.66666666667;
+          //if (model->numberIterations()%50==0)
+          //printf("%d nonzero\n",numberInRowArray);
+     }
+     // if not packed then bias a bit more towards by column
+     if (!packed)
+          factor *= 0.9;
+     return ((numberInRowArray > factor * numberRows || !model->rowCopy()) && !(flags_ & 2));
+}
+#ifndef CLP_ALL_ONE_FILE
+// These have to match ClpPrimalColumnSteepest version
+#define reference(i)  (((reference[i>>5]>>(i&31))&1)!=0)
+#endif
+// Updates two arrays for steepest
+void
+ClpPackedMatrix::transposeTimes2(const ClpSimplex * model,
+                                 const CoinIndexedVector * pi1, CoinIndexedVector * dj1,
+                                 const CoinIndexedVector * pi2,
+                                 CoinIndexedVector * spare,
+                                 double referenceIn, double devex,
+                                 // Array for exact devex to say what is in reference framework
+                                 unsigned int * reference,
+                                 double * weights, double scaleFactor)
+{
+     // put row of tableau in dj1
+     double * pi = pi1->denseVector();
+     int numberNonZero = 0;
+     int * index = dj1->getIndices();
+     double * array = dj1->denseVector();
+     int numberInRowArray = pi1->getNumElements();
+     double zeroTolerance = model->zeroTolerance();
+     bool packed = pi1->packedMode();
+     // do by column
+     int iColumn;
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const double * elementByColumn = matrix_->getElements();
+     const double * rowScale = model->rowScale();
+     assert (!spare->getNumElements());
+     assert (numberActiveColumns_ > 0);
+     double * piWeight = pi2->denseVector();
+     assert (!pi2->packedMode());
+     bool killDjs = (scaleFactor == 0.0);
+     if (!scaleFactor)
+          scaleFactor = 1.0;
+     if (packed) {
+          // need to expand pi into y
+          assert(spare->capacity() >= model->numberRows());
+          double * piOld = pi;
+          pi = spare->denseVector();
+          const int * whichRow = pi1->getIndices();
+          int i;
+          ClpPackedMatrix * scaledMatrix = model->clpScaledMatrix();
+          if (rowScale && scaledMatrix) {
+               rowScale = NULL;
+               // get matrix data pointers
+               row = scaledMatrix->getIndices();
+               columnStart = scaledMatrix->getVectorStarts();
+               elementByColumn = scaledMatrix->getElements();
+          }
+          if (!rowScale) {
+               // modify pi so can collapse to one loop
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = piOld[i];
+               }
+               if (!columnCopy_) {
+                    CoinBigIndex j;
+                    CoinBigIndex end = columnStart[0];
+                    for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                         CoinBigIndex start = end;
+                         end = columnStart[iColumn+1];
+                         ClpSimplex::Status status = model->getStatus(iColumn);
+                         if (status == ClpSimplex::basic || status == ClpSimplex::isFixed) continue;
+                         double value = 0.0;
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              value -= pi[iRow] * elementByColumn[j];
+                         }
+                         if (fabs(value) > zeroTolerance) {
+                              // and do other array
+                              double modification = 0.0;
+                              for (j = start; j < end; j++) {
+                                   int iRow = row[j];
+                                   modification += piWeight[iRow] * elementByColumn[j];
+                              }
+                              double thisWeight = weights[iColumn];
+                              double pivot = value * scaleFactor;
+                              double pivotSquared = pivot * pivot;
+                              thisWeight += pivotSquared * devex + pivot * modification;
+                              if (thisWeight < DEVEX_TRY_NORM) {
+                                   if (referenceIn < 0.0) {
+                                        // steepest
+                                        thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                                   } else {
+                                        // exact
+                                        thisWeight = referenceIn * pivotSquared;
+                                        if (reference(iColumn))
+                                             thisWeight += 1.0;
+                                        thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                                   }
+                              }
+                              weights[iColumn] = thisWeight;
+                              if (!killDjs) {
+                                   array[numberNonZero] = value;
+                                   index[numberNonZero++] = iColumn;
+                              }
+                         }
+                    }
+               } else {
+                    // use special column copy
+                    // reset back
+                    if (killDjs)
+                         scaleFactor = 0.0;
+                    columnCopy_->transposeTimes2(model, pi, dj1, piWeight, referenceIn, devex,
+                                                 reference, weights, scaleFactor);
+                    numberNonZero = dj1->getNumElements();
+               }
+          } else {
+               // scaled
+               // modify pi so can collapse to one loop
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = piOld[i] * rowScale[iRow];
+               }
+               // can also scale piWeight as not used again
+               int numberWeight = pi2->getNumElements();
+               const int * indexWeight = pi2->getIndices();
+               for (i = 0; i < numberWeight; i++) {
+                    int iRow = indexWeight[i];
+                    piWeight[iRow] *= rowScale[iRow];
+               }
+               if (!columnCopy_) {
+                    const double * columnScale = model->columnScale();
+                    CoinBigIndex j;
+                    CoinBigIndex end = columnStart[0];
+                    for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                         CoinBigIndex start = end;
+                         end = columnStart[iColumn+1];
+                         ClpSimplex::Status status = model->getStatus(iColumn);
+                         if (status == ClpSimplex::basic || status == ClpSimplex::isFixed) continue;
+                         double scale = columnScale[iColumn];
+                         double value = 0.0;
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              value -= pi[iRow] * elementByColumn[j];
+                         }
+                         value *= scale;
+                         if (fabs(value) > zeroTolerance) {
+                              double modification = 0.0;
+                              for (j = start; j < end; j++) {
+                                   int iRow = row[j];
+                                   modification += piWeight[iRow] * elementByColumn[j];
+                              }
+                              modification *= scale;
+                              double thisWeight = weights[iColumn];
+                              double pivot = value * scaleFactor;
+                              double pivotSquared = pivot * pivot;
+                              thisWeight += pivotSquared * devex + pivot * modification;
+                              if (thisWeight < DEVEX_TRY_NORM) {
+                                   if (referenceIn < 0.0) {
+                                        // steepest
+                                        thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                                   } else {
+                                        // exact
+                                        thisWeight = referenceIn * pivotSquared;
+                                        if (reference(iColumn))
+                                             thisWeight += 1.0;
+                                        thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                                   }
+                              }
+                              weights[iColumn] = thisWeight;
+                              if (!killDjs) {
+                                   array[numberNonZero] = value;
+                                   index[numberNonZero++] = iColumn;
+                              }
+                         }
+                    }
+               } else {
+                    // use special column copy
+                    // reset back
+                    if (killDjs)
+                         scaleFactor = 0.0;
+                    columnCopy_->transposeTimes2(model, pi, dj1, piWeight, referenceIn, devex,
+                                                 reference, weights, scaleFactor);
+                    numberNonZero = dj1->getNumElements();
+               }
+          }
+          // zero out
+          int numberRows = model->numberRows();
+          if (numberInRowArray * 4 < numberRows) {
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = 0.0;
+               }
+          } else {
+               CoinZeroN(pi, numberRows);
+          }
+     } else {
+          if (!rowScale) {
+               CoinBigIndex j;
+               CoinBigIndex end = columnStart[0];
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    CoinBigIndex start = end;
+                    end = columnStart[iColumn+1];
+                    ClpSimplex::Status status = model->getStatus(iColumn);
+                    if (status == ClpSimplex::basic || status == ClpSimplex::isFixed) continue;
+                    double value = 0.0;
+                    for (j = start; j < end; j++) {
+                         int iRow = row[j];
+                         value -= pi[iRow] * elementByColumn[j];
+                    }
+                    if (fabs(value) > zeroTolerance) {
+                         // and do other array
+                         double modification = 0.0;
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              modification += piWeight[iRow] * elementByColumn[j];
+                         }
+                         double thisWeight = weights[iColumn];
+                         double pivot = value * scaleFactor;
+                         double pivotSquared = pivot * pivot;
+                         thisWeight += pivotSquared * devex + pivot * modification;
+                         if (thisWeight < DEVEX_TRY_NORM) {
+                              if (referenceIn < 0.0) {
+                                   // steepest
+                                   thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                              } else {
+                                   // exact
+                                   thisWeight = referenceIn * pivotSquared;
+                                   if (reference(iColumn))
+                                        thisWeight += 1.0;
+                                   thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                              }
+                         }
+                         weights[iColumn] = thisWeight;
+                         if (!killDjs) {
+                              array[iColumn] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+          } else {
+#ifdef CLP_INVESTIGATE
+               if (model->clpScaledMatrix())
+                    printf("scaledMatrix_ at %d of ClpPackedMatrix\n", __LINE__);
+#endif
+               // scaled
+               // can also scale piWeight as not used again
+               int numberWeight = pi2->getNumElements();
+               const int * indexWeight = pi2->getIndices();
+               for (int i = 0; i < numberWeight; i++) {
+                    int iRow = indexWeight[i];
+                    piWeight[iRow] *= rowScale[iRow];
+               }
+               const double * columnScale = model->columnScale();
+               CoinBigIndex j;
+               CoinBigIndex end = columnStart[0];
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    CoinBigIndex start = end;
+                    end = columnStart[iColumn+1];
+                    ClpSimplex::Status status = model->getStatus(iColumn);
+                    if (status == ClpSimplex::basic || status == ClpSimplex::isFixed) continue;
+                    double scale = columnScale[iColumn];
+                    double value = 0.0;
+                    for (j = start; j < end; j++) {
+                         int iRow = row[j];
+                         value -= pi[iRow] * elementByColumn[j] * rowScale[iRow];
+                    }
+                    value *= scale;
+                    if (fabs(value) > zeroTolerance) {
+                         double modification = 0.0;
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              modification += piWeight[iRow] * elementByColumn[j];
+                         }
+                         modification *= scale;
+                         double thisWeight = weights[iColumn];
+                         double pivot = value * scaleFactor;
+                         double pivotSquared = pivot * pivot;
+                         thisWeight += pivotSquared * devex + pivot * modification;
+                         if (thisWeight < DEVEX_TRY_NORM) {
+                              if (referenceIn < 0.0) {
+                                   // steepest
+                                   thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                              } else {
+                                   // exact
+                                   thisWeight = referenceIn * pivotSquared;
+                                   if (reference(iColumn))
+                                        thisWeight += 1.0;
+                                   thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                              }
+                         }
+                         weights[iColumn] = thisWeight;
+                         if (!killDjs) {
+                              array[iColumn] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+          }
+     }
+     dj1->setNumElements(numberNonZero);
+     spare->setNumElements(0);
+     if (packed)
+          dj1->setPackedMode(true);
+}
+// Updates second array for steepest and does devex weights
+void
+ClpPackedMatrix::subsetTimes2(const ClpSimplex * model,
+                              CoinIndexedVector * dj1,
+                              const CoinIndexedVector * pi2, CoinIndexedVector *,
+                              double referenceIn, double devex,
+                              // Array for exact devex to say what is in reference framework
+                              unsigned int * reference,
+                              double * weights, double scaleFactor)
+{
+     int number = dj1->getNumElements();
+     const int * index = dj1->getIndices();
+     double * array = dj1->denseVector();
+     assert( dj1->packedMode());
+
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * elementByColumn = matrix_->getElements();
+     const double * rowScale = model->rowScale();
+     double * piWeight = pi2->denseVector();
+     bool killDjs = (scaleFactor == 0.0);
+     if (!scaleFactor)
+          scaleFactor = 1.0;
+     if (!rowScale) {
+          for (int k = 0; k < number; k++) {
+               int iColumn = index[k];
+               double pivot = array[k] * scaleFactor;
+               if (killDjs)
+                    array[k] = 0.0;
+               // and do other array
+               double modification = 0.0;
+               for (CoinBigIndex j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    modification += piWeight[iRow] * elementByColumn[j];
+               }
+               double thisWeight = weights[iColumn];
+               double pivotSquared = pivot * pivot;
+               thisWeight += pivotSquared * devex + pivot * modification;
+               if (thisWeight < DEVEX_TRY_NORM) {
+                    if (referenceIn < 0.0) {
+                         // steepest
+                         thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                    } else {
+                         // exact
+                         thisWeight = referenceIn * pivotSquared;
+                         if (reference(iColumn))
+                              thisWeight += 1.0;
+                         thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                    }
+               }
+               weights[iColumn] = thisWeight;
+          }
+     } else {
+#ifdef CLP_INVESTIGATE
+          if (model->clpScaledMatrix())
+               printf("scaledMatrix_ at %d of ClpPackedMatrix\n", __LINE__);
+#endif
+          // scaled
+          const double * columnScale = model->columnScale();
+          for (int k = 0; k < number; k++) {
+               int iColumn = index[k];
+               double pivot = array[k] * scaleFactor;
+               double scale = columnScale[iColumn];
+               if (killDjs)
+                    array[k] = 0.0;
+               // and do other array
+               double modification = 0.0;
+               for (CoinBigIndex j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    modification += piWeight[iRow] * elementByColumn[j] * rowScale[iRow];
+               }
+               double thisWeight = weights[iColumn];
+               modification *= scale;
+               double pivotSquared = pivot * pivot;
+               thisWeight += pivotSquared * devex + pivot * modification;
+               if (thisWeight < DEVEX_TRY_NORM) {
+                    if (referenceIn < 0.0) {
+                         // steepest
+                         thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                    } else {
+                         // exact
+                         thisWeight = referenceIn * pivotSquared;
+                         if (reference(iColumn))
+                              thisWeight += 1.0;
+                         thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                    }
+               }
+               weights[iColumn] = thisWeight;
+          }
+     }
+}
+/// returns number of elements in column part of basis,
+CoinBigIndex
+ClpPackedMatrix::countBasis( const int * whichColumn,
+                             int & numberColumnBasic)
+{
+     const int * columnLength = matrix_->getVectorLengths();
+     int i;
+     CoinBigIndex numberElements = 0;
+     // just count - can be over so ignore zero problem
+     for (i = 0; i < numberColumnBasic; i++) {
+          int iColumn = whichColumn[i];
+          numberElements += columnLength[iColumn];
+     }
+     return numberElements;
+}
+void
+ClpPackedMatrix::fillBasis(ClpSimplex * model,
+                           const int * COIN_RESTRICT whichColumn,
+                           int & numberColumnBasic,
+                           int * COIN_RESTRICT indexRowU,
+                           int * COIN_RESTRICT start,
+                           int * COIN_RESTRICT rowCount,
+                           int * COIN_RESTRICT columnCount,
+                           CoinFactorizationDouble * COIN_RESTRICT elementU)
+{
+     const int * COIN_RESTRICT columnLength = matrix_->getVectorLengths();
+     int i;
+     CoinBigIndex numberElements = start[0];
+     // fill
+     const CoinBigIndex * COIN_RESTRICT columnStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT rowScale = model->rowScale();
+     const int * COIN_RESTRICT row = matrix_->getIndices();
+     const double * COIN_RESTRICT elementByColumn = matrix_->getElements();
+     ClpPackedMatrix * scaledMatrix = model->clpScaledMatrix();
+     if (scaledMatrix && true) {
+          columnLength = scaledMatrix->matrix_->getVectorLengths();
+          columnStart = scaledMatrix->matrix_->getVectorStarts();
+          rowScale = NULL;
+          row = scaledMatrix->matrix_->getIndices();
+          elementByColumn = scaledMatrix->matrix_->getElements();
+     }
+     if ((flags_ & 1) == 0) {
+          if (!rowScale) {
+               // no scaling
+               for (i = 0; i < numberColumnBasic; i++) {
+                    int iColumn = whichColumn[i];
+                    int length = columnLength[iColumn];
+                    CoinBigIndex startThis = columnStart[iColumn];
+                    columnCount[i] = length;
+                    CoinBigIndex endThis = startThis + length;
+                    for (CoinBigIndex j = startThis; j < endThis; j++) {
+                         int iRow = row[j];
+                         indexRowU[numberElements] = iRow;
+                         rowCount[iRow]++;
+                         assert (elementByColumn[j]);
+                         elementU[numberElements++] = elementByColumn[j];
+                    }
+                    start[i+1] = numberElements;
+               }
+          } else {
+               // scaling
+               const double * COIN_RESTRICT columnScale = model->columnScale();
+               for (i = 0; i < numberColumnBasic; i++) {
+                    int iColumn = whichColumn[i];
+                    double scale = columnScale[iColumn];
+                    int length = columnLength[iColumn];
+                    CoinBigIndex startThis = columnStart[iColumn];
+                    columnCount[i] = length;
+                    CoinBigIndex endThis = startThis + length;
+                    for (CoinBigIndex j = startThis; j < endThis; j++) {
+                         int iRow = row[j];
+                         indexRowU[numberElements] = iRow;
+                         rowCount[iRow]++;
+                         assert (elementByColumn[j]);
+                         elementU[numberElements++] =
+                              elementByColumn[j] * scale * rowScale[iRow];
+                    }
+                    start[i+1] = numberElements;
+               }
+          }
+     } else {
+          // there are zero elements so need to look more closely
+          if (!rowScale) {
+               // no scaling
+               for (i = 0; i < numberColumnBasic; i++) {
+                    int iColumn = whichColumn[i];
+                    CoinBigIndex j;
+                    for (j = columnStart[iColumn];
+                              j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         double value = elementByColumn[j];
+                         if (value) {
+                              int iRow = row[j];
+                              indexRowU[numberElements] = iRow;
+                              rowCount[iRow]++;
+                              elementU[numberElements++] = value;
+                         }
+                    }
+                    start[i+1] = numberElements;
+                    columnCount[i] = numberElements - start[i];
+               }
+          } else {
+               // scaling
+               const double * columnScale = model->columnScale();
+               for (i = 0; i < numberColumnBasic; i++) {
+                    int iColumn = whichColumn[i];
+                    CoinBigIndex j;
+                    double scale = columnScale[iColumn];
+                    for (j = columnStart[iColumn];
+                              j < columnStart[iColumn] + columnLength[i]; j++) {
+                         double value = elementByColumn[j];
+                         if (value) {
+                              int iRow = row[j];
+                              indexRowU[numberElements] = iRow;
+                              rowCount[iRow]++;
+                              elementU[numberElements++] = value * scale * rowScale[iRow];
+                         }
+                    }
+                    start[i+1] = numberElements;
+                    columnCount[i] = numberElements - start[i];
+               }
+          }
+     }
+}
+#if 0
+int
+ClpPackedMatrix::scale2(ClpModel * model) const
+{
+     ClpSimplex * baseModel = NULL;
+#ifndef NDEBUG
+     //checkFlags();
+#endif
+     int numberRows = model->numberRows();
+     int numberColumns = matrix_->getNumCols();
+     model->setClpScaledMatrix(NULL); // get rid of any scaled matrix
+     // If empty - return as sanityCheck will trap
+     if (!numberRows || !numberColumns) {
+          model->setRowScale(NULL);
+          model->setColumnScale(NULL);
+          return 1;
+     }
+     ClpMatrixBase * rowCopyBase = model->rowCopy();
+     double * rowScale;
+     double * columnScale;
+     //assert (!model->rowScale());
+     bool arraysExist;
+     double * inverseRowScale = NULL;
+     double * inverseColumnScale = NULL;
+     if (!model->rowScale()) {
+          rowScale = new double [numberRows*2];
+          columnScale = new double [numberColumns*2];
+          inverseRowScale = rowScale + numberRows;
+          inverseColumnScale = columnScale + numberColumns;
+          arraysExist = false;
+     } else {
+          rowScale = model->mutableRowScale();
+          columnScale = model->mutableColumnScale();
+          inverseRowScale = model->mutableInverseRowScale();
+          inverseColumnScale = model->mutableInverseColumnScale();
+          arraysExist = true;
+     }
+     assert (inverseRowScale == rowScale + numberRows);
+     assert (inverseColumnScale == columnScale + numberColumns);
+     // we are going to mark bits we are interested in
+     char * usefulRow = new char [numberRows];
+     char * usefulColumn = new char [numberColumns];
+     double * rowLower = model->rowLower();
+     double * rowUpper = model->rowUpper();
+     double * columnLower = model->columnLower();
+     double * columnUpper = model->columnUpper();
+     int iColumn, iRow;
+     //#define LEAVE_FIXED
+     // mark free rows
+     for (iRow = 0; iRow < numberRows; iRow++) {
+#if 0 //ndef LEAVE_FIXED
+          if (rowUpper[iRow] < 1.0e20 ||
+                    rowLower[iRow] > -1.0e20)
+               usefulRow[iRow] = 1;
+          else
+               usefulRow[iRow] = 0;
+#else
+          usefulRow[iRow] = 1;
+#endif
+     }
+     // mark empty and fixed columns
+     // also see if worth scaling
+     assert (model->scalingFlag() <= 4);
+     //  scale_stats[model->scalingFlag()]++;
+     double largest = 0.0;
+     double smallest = 1.0e50;
+     // get matrix data pointers
+     int * row = matrix_->getMutableIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     int * columnLength = matrix_->getMutableVectorLengths();
+     double * elementByColumn = matrix_->getMutableElements();
+     bool deletedElements = false;
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          CoinBigIndex j;
+          char useful = 0;
+          bool deleteSome = false;
+          int start = columnStart[iColumn];
+          int end = start + columnLength[iColumn];
+#ifndef LEAVE_FIXED
+          if (columnUpper[iColumn] >
+                    columnLower[iColumn] + 1.0e-12) {
+#endif
+               for (j = start; j < end; j++) {
+                    iRow = row[j];
+                    double value = fabs(elementByColumn[j]);
+                    if (value > 1.0e-20) {
+                         if(usefulRow[iRow]) {
+                              useful = 1;
+                              largest = CoinMax(largest, fabs(elementByColumn[j]));
+                              smallest = CoinMin(smallest, fabs(elementByColumn[j]));
+                         }
+                    } else {
+                         // small
+                         deleteSome = true;
+                    }
+               }
+#ifndef LEAVE_FIXED
+          } else {
+               // just check values
+               for (j = start; j < end; j++) {
+                    double value = fabs(elementByColumn[j]);
+                    if (value <= 1.0e-20) {
+                         // small
+                         deleteSome = true;
+                    }
+               }
+          }
+#endif
+          usefulColumn[iColumn] = useful;
+          if (deleteSome) {
+               deletedElements = true;
+               CoinBigIndex put = start;
+               for (j = start; j < end; j++) {
+                    double value = elementByColumn[j];
+                    if (fabs(value) > 1.0e-20) {
+                         row[put] = row[j];
+                         elementByColumn[put++] = value;
+                    }
+               }
+               columnLength[iColumn] = put - start;
+          }
+     }
+     model->messageHandler()->message(CLP_PACKEDSCALE_INITIAL, *model->messagesPointer())
+               << smallest << largest
+               << CoinMessageEol;
+     if (smallest >= 0.5 && largest <= 2.0 && !deletedElements) {
+          // don't bother scaling
+          model->messageHandler()->message(CLP_PACKEDSCALE_FORGET, *model->messagesPointer())
+                    << CoinMessageEol;
+          if (!arraysExist) {
+               delete [] rowScale;
+               delete [] columnScale;
+          } else {
+               model->setRowScale(NULL);
+               model->setColumnScale(NULL);
+          }
+          delete [] usefulRow;
+          delete [] usefulColumn;
+          return 1;
+     } else {
+#ifdef CLP_INVESTIGATE
+          if (deletedElements)
+               printf("DEL_ELS\n");
+#endif
+          if (!rowCopyBase) {
+               // temporary copy
+               rowCopyBase = reverseOrderedCopy();
+          } else if (deletedElements) {
+               rowCopyBase = reverseOrderedCopy();
+               model->setNewRowCopy(rowCopyBase);
+          }
+#ifndef NDEBUG
+          ClpPackedMatrix* rowCopy =
+               dynamic_cast< ClpPackedMatrix*>(rowCopyBase);
+          // Make sure it is really a ClpPackedMatrix
+          assert (rowCopy != NULL);
+#else
+          ClpPackedMatrix* rowCopy =
+               static_cast< ClpPackedMatrix*>(rowCopyBase);
+#endif
+
+          const int * column = rowCopy->getIndices();
+          const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+          const double * element = rowCopy->getElements();
+          // need to scale
+          if (largest > 1.0e13 * smallest) {
+               // safer to have smaller zero tolerance
+               double ratio = smallest / largest;
+               ClpSimplex * simplex = static_cast<ClpSimplex *> (model);
+               double newTolerance = CoinMax(ratio * 0.5, 1.0e-18);
+               if (simplex->zeroTolerance() > newTolerance)
+                    simplex->setZeroTolerance(newTolerance);
+          }
+          int scalingMethod = model->scalingFlag();
+          if (scalingMethod == 4) {
+               // As auto
+               scalingMethod = 3;
+          }
+          // and see if there any empty rows
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               if (usefulRow[iRow]) {
+                    CoinBigIndex j;
+                    int useful = 0;
+                    for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                         int iColumn = column[j];
+                         if (usefulColumn[iColumn]) {
+                              useful = 1;
+                              break;
+                         }
+                    }
+                    usefulRow[iRow] = static_cast<char>(useful);
+               }
+          }
+          double savedOverallRatio = 0.0;
+          double tolerance = 5.0 * model->primalTolerance();
+          double overallLargest = -1.0e-20;
+          double overallSmallest = 1.0e20;
+          bool finished = false;
+          // if scalingMethod 3 then may change
+          bool extraDetails = (model->logLevel() > 2);
+          while (!finished) {
+               int numberPass = 3;
+               overallLargest = -1.0e-20;
+               overallSmallest = 1.0e20;
+               if (!baseModel) {
+                    ClpFillN ( rowScale, numberRows, 1.0);
+                    ClpFillN ( columnScale, numberColumns, 1.0);
+               } else {
+                    // Copy scales and do quick scale on extra rows
+                    // Then just one? pass
+                    assert (numberColumns == baseModel->numberColumns());
+                    int numberRows2 = baseModel->numberRows();
+                    assert (numberRows >= numberRows2);
+                    assert (baseModel->rowScale());
+                    CoinMemcpyN(baseModel->rowScale(), numberRows2, rowScale);
+                    CoinMemcpyN(baseModel->columnScale(), numberColumns, columnScale);
+                    if (numberRows > numberRows2) {
+                         numberPass = 1;
+                         // do some scaling
+                         if (scalingMethod == 1 || scalingMethod == 3) {
+                              // Maximum in each row
+                              for (iRow = numberRows2; iRow < numberRows; iRow++) {
+                                   if (usefulRow[iRow]) {
+                                        CoinBigIndex j;
+                                        largest = 1.0e-10;
+                                        for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                                             int iColumn = column[j];
+                                             if (usefulColumn[iColumn]) {
+                                                  double value = fabs(element[j] * columnScale[iColumn]);
+                                                  largest = CoinMax(largest, value);
+                                                  assert (largest < 1.0e40);
+                                             }
+                                        }
+                                        rowScale[iRow] = 1.0 / largest;
+#ifdef COIN_DEVELOP
+                                        if (extraDetails) {
+                                             overallLargest = CoinMax(overallLargest, largest);
+                                             overallSmallest = CoinMin(overallSmallest, largest);
+                                        }
+#endif
+                                   }
+                              }
+                         } else {
+                              overallLargest = 0.0;
+                              overallSmallest = 1.0e50;
+                              // Geometric mean on row scales
+                              for (iRow = 0; iRow < numberRows; iRow++) {
+                                   if (usefulRow[iRow]) {
+                                        CoinBigIndex j;
+                                        largest = 1.0e-20;
+                                        smallest = 1.0e50;
+                                        for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                                             int iColumn = column[j];
+                                             if (usefulColumn[iColumn]) {
+                                                  double value = fabs(element[j]);
+                                                  value *= columnScale[iColumn];
+                                                  largest = CoinMax(largest, value);
+                                                  smallest = CoinMin(smallest, value);
+                                             }
+                                        }
+                                        if (iRow >= numberRows2) {
+                                             rowScale[iRow] = 1.0 / sqrt(smallest * largest);
+                                             //rowScale[iRow]=CoinMax(1.0e-10,CoinMin(1.0e10,rowScale[iRow]));
+                                        }
+#ifdef COIN_DEVELOP
+                                        if (extraDetails) {
+                                             overallLargest = CoinMax(largest * rowScale[iRow], overallLargest);
+                                             overallSmallest = CoinMin(smallest * rowScale[iRow], overallSmallest);
+                                        }
+#endif
+                                   }
+                              }
+                         }
+                    } else {
+                         // just use
+                         numberPass = 0;
+                    }
+               }
+               if (!baseModel && (scalingMethod == 1 || scalingMethod == 3)) {
+                    // Maximum in each row
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         if (usefulRow[iRow]) {
+                              CoinBigIndex j;
+                              largest = 1.0e-10;
+                              for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                                   int iColumn = column[j];
+                                   if (usefulColumn[iColumn]) {
+                                        double value = fabs(element[j]);
+                                        largest = CoinMax(largest, value);
+                                        assert (largest < 1.0e40);
+                                   }
+                              }
+                              rowScale[iRow] = 1.0 / largest;
+#ifdef COIN_DEVELOP
+                              if (extraDetails) {
+                                   overallLargest = CoinMax(overallLargest, largest);
+                                   overallSmallest = CoinMin(overallSmallest, largest);
+                              }
+#endif
+                         }
+                    }
+               } else {
+#ifdef USE_OBJECTIVE
+                    // This will be used to help get scale factors
+                    double * objective = new double[numberColumns];
+                    CoinMemcpyN(model->costRegion(1), numberColumns, objective);
+                    double objScale = 1.0;
+#endif
+                    while (numberPass) {
+                         overallLargest = 0.0;
+                         overallSmallest = 1.0e50;
+                         numberPass--;
+                         // Geometric mean on row scales
+                         for (iRow = 0; iRow < numberRows; iRow++) {
+                              if (usefulRow[iRow]) {
+                                   CoinBigIndex j;
+                                   largest = 1.0e-20;
+                                   smallest = 1.0e50;
+                                   for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                                        int iColumn = column[j];
+                                        if (usefulColumn[iColumn]) {
+                                             double value = fabs(element[j]);
+                                             value *= columnScale[iColumn];
+                                             largest = CoinMax(largest, value);
+                                             smallest = CoinMin(smallest, value);
+                                        }
+                                   }
+
+                                   rowScale[iRow] = 1.0 / sqrt(smallest * largest);
+                                   //rowScale[iRow]=CoinMax(1.0e-10,CoinMin(1.0e10,rowScale[iRow]));
+                                   if (extraDetails) {
+                                        overallLargest = CoinMax(largest * rowScale[iRow], overallLargest);
+                                        overallSmallest = CoinMin(smallest * rowScale[iRow], overallSmallest);
+                                   }
+                              }
+                         }
+#ifdef USE_OBJECTIVE
+                         largest = 1.0e-20;
+                         smallest = 1.0e50;
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              if (usefulColumn[iColumn]) {
+                                   double value = fabs(objective[iColumn]);
+                                   value *= columnScale[iColumn];
+                                   largest = CoinMax(largest, value);
+                                   smallest = CoinMin(smallest, value);
+                              }
+                         }
+                         objScale = 1.0 / sqrt(smallest * largest);
+#endif
+                         model->messageHandler()->message(CLP_PACKEDSCALE_WHILE, *model->messagesPointer())
+                                   << overallSmallest
+                                   << overallLargest
+                                   << CoinMessageEol;
+                         // skip last column round
+                         if (numberPass == 1)
+                              break;
+                         // Geometric mean on column scales
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              if (usefulColumn[iColumn]) {
+                                   CoinBigIndex j;
+                                   largest = 1.0e-20;
+                                   smallest = 1.0e50;
+                                   for (j = columnStart[iColumn];
+                                             j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                        iRow = row[j];
+                                        double value = fabs(elementByColumn[j]);
+                                        if (usefulRow[iRow]) {
+                                             value *= rowScale[iRow];
+                                             largest = CoinMax(largest, value);
+                                             smallest = CoinMin(smallest, value);
+                                        }
+                                   }
+#ifdef USE_OBJECTIVE
+                                   if (fabs(objective[iColumn]) > 1.0e-20) {
+                                        double value = fabs(objective[iColumn]) * objScale;
+                                        largest = CoinMax(largest, value);
+                                        smallest = CoinMin(smallest, value);
+                                   }
+#endif
+                                   columnScale[iColumn] = 1.0 / sqrt(smallest * largest);
+                                   //columnScale[iColumn]=CoinMax(1.0e-10,CoinMin(1.0e10,columnScale[iColumn]));
+                              }
+                         }
+                    }
+#ifdef USE_OBJECTIVE
+                    delete [] objective;
+                    printf("obj scale %g - use it if you want\n", objScale);
+#endif
+               }
+               // If ranges will make horrid then scale
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    if (usefulRow[iRow]) {
+                         double difference = rowUpper[iRow] - rowLower[iRow];
+                         double scaledDifference = difference * rowScale[iRow];
+                         if (scaledDifference > tolerance && scaledDifference < 1.0e-4) {
+                              // make gap larger
+                              rowScale[iRow] *= 1.0e-4 / scaledDifference;
+                              rowScale[iRow] = CoinMax(1.0e-10, CoinMin(1.0e10, rowScale[iRow]));
+                              //printf("Row %d difference %g scaled diff %g => %g\n",iRow,difference,
+                              // scaledDifference,difference*rowScale[iRow]);
+                         }
+                    }
+               }
+               // final pass to scale columns so largest is reasonable
+               // See what smallest will be if largest is 1.0
+               overallSmallest = 1.0e50;
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (usefulColumn[iColumn]) {
+                         CoinBigIndex j;
+                         largest = 1.0e-20;
+                         smallest = 1.0e50;
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              iRow = row[j];
+                              if(elementByColumn[j] && usefulRow[iRow]) {
+                                   double value = fabs(elementByColumn[j] * rowScale[iRow]);
+                                   largest = CoinMax(largest, value);
+                                   smallest = CoinMin(smallest, value);
+                              }
+                         }
+                         if (overallSmallest * largest > smallest)
+                              overallSmallest = smallest / largest;
+                    }
+               }
+               if (scalingMethod == 1 || scalingMethod == 2) {
+                    finished = true;
+               } else if (savedOverallRatio == 0.0 && scalingMethod != 4) {
+                    savedOverallRatio = overallSmallest;
+                    scalingMethod = 4;
+               } else {
+                    assert (scalingMethod == 4);
+                    if (overallSmallest > 2.0 * savedOverallRatio) {
+                         finished = true; // geometric was better
+                         if (model->scalingFlag() == 4) {
+                              // If in Branch and bound change
+                              if ((model->specialOptions() & 1024) != 0) {
+                                   model->scaling(2);
+                              }
+                         }
+                    } else {
+                         scalingMethod = 1; // redo equilibrium
+                         if (model->scalingFlag() == 4) {
+                              // If in Branch and bound change
+                              if ((model->specialOptions() & 1024) != 0) {
+                                   model->scaling(1);
+                              }
+                         }
+                    }
+#if 0
+                    if (extraDetails) {
+                         if (finished)
+                              printf("equilibrium ratio %g, geometric ratio %g , geo chosen\n",
+                                     savedOverallRatio, overallSmallest);
+                         else
+                              printf("equilibrium ratio %g, geometric ratio %g , equi chosen\n",
+                                     savedOverallRatio, overallSmallest);
+                    }
+#endif
+               }
+          }
+          //#define RANDOMIZE
+#ifdef RANDOMIZE
+          // randomize by up to 10%
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               double value = 0.5 - randomNumberGenerator_.randomDouble(); //between -0.5 to + 0.5
+               rowScale[iRow] *= (1.0 + 0.1 * value);
+          }
+#endif
+          overallLargest = 1.0;
+          if (overallSmallest < 1.0e-1)
+               overallLargest = 1.0 / sqrt(overallSmallest);
+          overallLargest = CoinMin(100.0, overallLargest);
+          overallSmallest = 1.0e50;
+          //printf("scaling %d\n",model->scalingFlag());
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               if (columnUpper[iColumn] >
+                         columnLower[iColumn] + 1.0e-12) {
+                    //if (usefulColumn[iColumn]) {
+                    CoinBigIndex j;
+                    largest = 1.0e-20;
+                    smallest = 1.0e50;
+                    for (j = columnStart[iColumn];
+                              j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         iRow = row[j];
+                         if(elementByColumn[j] && usefulRow[iRow]) {
+                              double value = fabs(elementByColumn[j] * rowScale[iRow]);
+                              largest = CoinMax(largest, value);
+                              smallest = CoinMin(smallest, value);
+                         }
+                    }
+                    columnScale[iColumn] = overallLargest / largest;
+                    //columnScale[iColumn]=CoinMax(1.0e-10,CoinMin(1.0e10,columnScale[iColumn]));
+#ifdef RANDOMIZE
+                    double value = 0.5 - randomNumberGenerator_.randomDouble(); //between -0.5 to + 0.5
+                    columnScale[iColumn] *= (1.0 + 0.1 * value);
+#endif
+                    double difference = columnUpper[iColumn] - columnLower[iColumn];
+                    if (difference < 1.0e-5 * columnScale[iColumn]) {
+                         // make gap larger
+                         columnScale[iColumn] = difference / 1.0e-5;
+                         //printf("Column %d difference %g scaled diff %g => %g\n",iColumn,difference,
+                         // scaledDifference,difference*columnScale[iColumn]);
+                    }
+                    double value = smallest * columnScale[iColumn];
+                    if (overallSmallest > value)
+                         overallSmallest = value;
+                    //overallSmallest = CoinMin(overallSmallest,smallest*columnScale[iColumn]);
+               }
+          }
+          model->messageHandler()->message(CLP_PACKEDSCALE_FINAL, *model->messagesPointer())
+                    << overallSmallest
+                    << overallLargest
+                    << CoinMessageEol;
+          if (overallSmallest < 1.0e-13) {
+               // Change factorization zero tolerance
+               double newTolerance = CoinMax(1.0e-15 * (overallSmallest / 1.0e-13),
+                                             1.0e-18);
+               ClpSimplex * simplex = static_cast<ClpSimplex *> (model);
+               if (simplex->factorization()->zeroTolerance() > newTolerance)
+                    simplex->factorization()->zeroTolerance(newTolerance);
+               newTolerance = CoinMax(overallSmallest * 0.5, 1.0e-18);
+               simplex->setZeroTolerance(newTolerance);
+          }
+          delete [] usefulRow;
+          delete [] usefulColumn;
+#ifndef SLIM_CLP
+          // If quadratic then make symmetric
+          ClpObjective * obj = model->objectiveAsObject();
+#ifndef NO_RTTI
+          ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(obj));
+#else
+          ClpQuadraticObjective * quadraticObj = NULL;
+          if (obj->type() == 2)
+               quadraticObj = (static_cast< ClpQuadraticObjective*>(obj));
+#endif
+          if (quadraticObj) {
+               if (!rowCopyBase) {
+                    // temporary copy
+                    rowCopyBase = reverseOrderedCopy();
+               }
+#ifndef NDEBUG
+               ClpPackedMatrix* rowCopy =
+                    dynamic_cast< ClpPackedMatrix*>(rowCopyBase);
+               // Make sure it is really a ClpPackedMatrix
+               assert (rowCopy != NULL);
+#else
+               ClpPackedMatrix* rowCopy =
+                    static_cast< ClpPackedMatrix*>(rowCopyBase);
+#endif
+               const int * column = rowCopy->getIndices();
+               const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+               CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+               int numberXColumns = quadratic->getNumCols();
+               if (numberXColumns < numberColumns) {
+                    // we assume symmetric
+                    int numberQuadraticColumns = 0;
+                    int i;
+                    //const int * columnQuadratic = quadratic->getIndices();
+                    //const int * columnQuadraticStart = quadratic->getVectorStarts();
+                    const int * columnQuadraticLength = quadratic->getVectorLengths();
+                    for (i = 0; i < numberXColumns; i++) {
+                         int length = columnQuadraticLength[i];
+#ifndef CORRECT_COLUMN_COUNTS
+                         length = 1;
+#endif
+                         if (length)
+                              numberQuadraticColumns++;
+                    }
+                    int numberXRows = numberRows - numberQuadraticColumns;
+                    numberQuadraticColumns = 0;
+                    for (i = 0; i < numberXColumns; i++) {
+                         int length = columnQuadraticLength[i];
+#ifndef CORRECT_COLUMN_COUNTS
+                         length = 1;
+#endif
+                         if (length) {
+                              rowScale[numberQuadraticColumns+numberXRows] = columnScale[i];
+                              numberQuadraticColumns++;
+                         }
+                    }
+                    int numberQuadraticRows = 0;
+                    for (i = 0; i < numberXRows; i++) {
+                         // See if any in row quadratic
+                         CoinBigIndex j;
+                         int numberQ = 0;
+                         for (j = rowStart[i]; j < rowStart[i+1]; j++) {
+                              int iColumn = column[j];
+                              if (columnQuadraticLength[iColumn])
+                                   numberQ++;
+                         }
+#ifndef CORRECT_ROW_COUNTS
+                         numberQ = 1;
+#endif
+                         if (numberQ) {
+                              columnScale[numberQuadraticRows+numberXColumns] = rowScale[i];
+                              numberQuadraticRows++;
+                         }
+                    }
+                    // and make sure Sj okay
+                    for (iColumn = numberQuadraticRows + numberXColumns; iColumn < numberColumns; iColumn++) {
+                         CoinBigIndex j = columnStart[iColumn];
+                         assert(columnLength[iColumn] == 1);
+                         int iRow = row[j];
+                         double value = fabs(elementByColumn[j] * rowScale[iRow]);
+                         columnScale[iColumn] = 1.0 / value;
+                    }
+               }
+          }
+#endif
+          // make copy (could do faster by using previous values)
+          // could just do partial
+          for (iRow = 0; iRow < numberRows; iRow++)
+               inverseRowScale[iRow] = 1.0 / rowScale[iRow] ;
+          for (iColumn = 0; iColumn < numberColumns; iColumn++)
+               inverseColumnScale[iColumn] = 1.0 / columnScale[iColumn] ;
+          if (!arraysExist) {
+               model->setRowScale(rowScale);
+               model->setColumnScale(columnScale);
+          }
+          if (model->rowCopy()) {
+               // need to replace row by row
+               ClpPackedMatrix* rowCopy =
+                    static_cast< ClpPackedMatrix*>(model->rowCopy());
+               double * element = rowCopy->getMutableElements();
+               const int * column = rowCopy->getIndices();
+               const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+               // scale row copy
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    CoinBigIndex j;
+                    double scale = rowScale[iRow];
+                    double * elementsInThisRow = element + rowStart[iRow];
+                    const int * columnsInThisRow = column + rowStart[iRow];
+                    int number = rowStart[iRow+1] - rowStart[iRow];
+                    assert (number <= numberColumns);
+                    for (j = 0; j < number; j++) {
+                         int iColumn = columnsInThisRow[j];
+                         elementsInThisRow[j] *= scale * columnScale[iColumn];
+                    }
+               }
+               if ((model->specialOptions() & 262144) != 0) {
+                    //if ((model->specialOptions()&(COIN_CBC_USING_CLP|16384))!=0) {
+                    //if (model->inCbcBranchAndBound()&&false) {
+                    // copy without gaps
+                    CoinPackedMatrix * scaledMatrix = new CoinPackedMatrix(*matrix_, 0, 0);
+                    ClpPackedMatrix * scaled = new ClpPackedMatrix(scaledMatrix);
+                    model->setClpScaledMatrix(scaled);
+                    // get matrix data pointers
+                    const int * row = scaledMatrix->getIndices();
+                    const CoinBigIndex * columnStart = scaledMatrix->getVectorStarts();
+#ifndef NDEBUG
+                    const int * columnLength = scaledMatrix->getVectorLengths();
+#endif
+                    double * elementByColumn = scaledMatrix->getMutableElements();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         CoinBigIndex j;
+                         double scale = columnScale[iColumn];
+                         assert (columnStart[iColumn+1] == columnStart[iColumn] + columnLength[iColumn]);
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn+1]; j++) {
+                              int iRow = row[j];
+                              elementByColumn[j] *= scale * rowScale[iRow];
+                         }
+                    }
+               } else {
+                    //printf("not in b&b\n");
+               }
+          } else {
+               // no row copy
+               delete rowCopyBase;
+          }
+          return 0;
+     }
+}
+#endif
+//#define SQRT_ARRAY
+#ifdef SQRT_ARRAY
+static void doSqrts(double * array, int n)
+{
+     for (int i = 0; i < n; i++)
+          array[i] = 1.0 / sqrt(array[i]);
+}
+#endif
+//static int scale_stats[5]={0,0,0,0,0};
+// Creates scales for column copy (rowCopy in model may be modified)
+int
+ClpPackedMatrix::scale(ClpModel * model, const ClpSimplex * /*baseModel*/) const
+{
+     //const ClpSimplex * baseModel=NULL;
+     //return scale2(model);
+#if 0
+     ClpMatrixBase * rowClone = NULL;
+     if (model->rowCopy())
+          rowClone = model->rowCopy()->clone();
+     assert (!model->rowScale());
+     assert (!model->columnScale());
+     int returnCode = scale2(model);
+     if (returnCode)
+          return returnCode;
+#endif
+#ifndef NDEBUG
+     //checkFlags();
+#endif
+     int numberRows = model->numberRows();
+     int numberColumns = matrix_->getNumCols();
+     model->setClpScaledMatrix(NULL); // get rid of any scaled matrix
+     // If empty - return as sanityCheck will trap
+     if (!numberRows || !numberColumns) {
+          model->setRowScale(NULL);
+          model->setColumnScale(NULL);
+          return 1;
+     }
+#if 0
+     // start fake
+     double * rowScale2 = CoinCopyOfArray(model->rowScale(), numberRows);
+     double * columnScale2 = CoinCopyOfArray(model->columnScale(), numberColumns);
+     model->setRowScale(NULL);
+     model->setColumnScale(NULL);
+     model->setNewRowCopy(rowClone);
+#endif
+     ClpMatrixBase * rowCopyBase = model->rowCopy();
+     double * rowScale;
+     double * columnScale;
+     //assert (!model->rowScale());
+     bool arraysExist;
+     double * inverseRowScale = NULL;
+     double * inverseColumnScale = NULL;
+     if (!model->rowScale()) {
+          rowScale = new double [numberRows*2];
+          columnScale = new double [numberColumns*2];
+          inverseRowScale = rowScale + numberRows;
+          inverseColumnScale = columnScale + numberColumns;
+          arraysExist = false;
+     } else {
+          rowScale = model->mutableRowScale();
+          columnScale = model->mutableColumnScale();
+          inverseRowScale = model->mutableInverseRowScale();
+          inverseColumnScale = model->mutableInverseColumnScale();
+          arraysExist = true;
+     }
+     assert (inverseRowScale == rowScale + numberRows);
+     assert (inverseColumnScale == columnScale + numberColumns);
+     // we are going to mark bits we are interested in
+     char * usefulColumn = new char [numberColumns];
+     double * rowLower = model->rowLower();
+     double * rowUpper = model->rowUpper();
+     double * columnLower = model->columnLower();
+     double * columnUpper = model->columnUpper();
+     int iColumn, iRow;
+     //#define LEAVE_FIXED
+     // mark empty and fixed columns
+     // also see if worth scaling
+     assert (model->scalingFlag() <= 5);
+     //  scale_stats[model->scalingFlag()]++;
+     double largest = 0.0;
+     double smallest = 1.0e50;
+     // get matrix data pointers
+     int * row = matrix_->getMutableIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     int * columnLength = matrix_->getMutableVectorLengths();
+     double * elementByColumn = matrix_->getMutableElements();
+     int deletedElements = 0;
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          CoinBigIndex j;
+          char useful = 0;
+          bool deleteSome = false;
+          int start = columnStart[iColumn];
+          int end = start + columnLength[iColumn];
+#ifndef LEAVE_FIXED
+          if (columnUpper[iColumn] >
+                    columnLower[iColumn] + 1.0e-12) {
+#endif
+               for (j = start; j < end; j++) {
+                    iRow = row[j];
+                    double value = fabs(elementByColumn[j]);
+                    if (value > 1.0e-20) {
+                         useful = 1;
+                         largest = CoinMax(largest, fabs(elementByColumn[j]));
+                         smallest = CoinMin(smallest, fabs(elementByColumn[j]));
+                    } else {
+                         // small
+                         deleteSome = true;
+                    }
+               }
+#ifndef LEAVE_FIXED
+          } else {
+               // just check values
+               for (j = start; j < end; j++) {
+                    double value = fabs(elementByColumn[j]);
+                    if (value <= 1.0e-20) {
+                         // small
+                         deleteSome = true;
+                    }
+               }
+          }
+#endif
+          usefulColumn[iColumn] = useful;
+          if (deleteSome) {
+               CoinBigIndex put = start;
+               for (j = start; j < end; j++) {
+                    double value = elementByColumn[j];
+                    if (fabs(value) > 1.0e-20) {
+                         row[put] = row[j];
+                         elementByColumn[put++] = value;
+                    }
+               }
+               deletedElements += end - put;
+               columnLength[iColumn] = put - start;
+          }
+     }
+     if (deletedElements) {
+       matrix_->setNumElements(matrix_->getNumElements()-deletedElements);
+       flags_ |= 0x02 ;
+     }
+     model->messageHandler()->message(CLP_PACKEDSCALE_INITIAL, *model->messagesPointer())
+               << smallest << largest
+               << CoinMessageEol;
+     if (smallest >= 0.5 && largest <= 2.0 && !deletedElements) {
+          // don't bother scaling
+          model->messageHandler()->message(CLP_PACKEDSCALE_FORGET, *model->messagesPointer())
+                    << CoinMessageEol;
+          if (!arraysExist) {
+               delete [] rowScale;
+               delete [] columnScale;
+          } else {
+               model->setRowScale(NULL);
+               model->setColumnScale(NULL);
+          }
+          delete [] usefulColumn;
+          return 1;
+     } else {
+#ifdef CLP_INVESTIGATE
+          if (deletedElements)
+               printf("DEL_ELS\n");
+#endif
+          if (!rowCopyBase) {
+               // temporary copy
+               rowCopyBase = reverseOrderedCopy();
+          } else if (deletedElements) {
+               rowCopyBase = reverseOrderedCopy();
+               model->setNewRowCopy(rowCopyBase);
+          }
+#ifndef NDEBUG
+          ClpPackedMatrix* rowCopy =
+               dynamic_cast< ClpPackedMatrix*>(rowCopyBase);
+          // Make sure it is really a ClpPackedMatrix
+          assert (rowCopy != NULL);
+#else
+          ClpPackedMatrix* rowCopy =
+               static_cast< ClpPackedMatrix*>(rowCopyBase);
+#endif
+
+          const int * column = rowCopy->getIndices();
+          const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+          const double * element = rowCopy->getElements();
+          // need to scale
+          if (largest > 1.0e13 * smallest) {
+               // safer to have smaller zero tolerance
+               double ratio = smallest / largest;
+               ClpSimplex * simplex = static_cast<ClpSimplex *> (model);
+               double newTolerance = CoinMax(ratio * 0.5, 1.0e-18);
+               if (simplex->zeroTolerance() > newTolerance)
+                    simplex->setZeroTolerance(newTolerance);
+          }
+          int scalingMethod = model->scalingFlag();
+          if (scalingMethod == 4) {
+               // As auto
+               scalingMethod = 3;
+          } else if (scalingMethod == 5) {
+               // As geometric
+               scalingMethod = 2;
+          }
+          double savedOverallRatio = 0.0;
+          double tolerance = 5.0 * model->primalTolerance();
+          double overallLargest = -1.0e-20;
+          double overallSmallest = 1.0e20;
+          bool finished = false;
+          // if scalingMethod 3 then may change
+          bool extraDetails = (model->logLevel() > 2);
+#if 0
+	  for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+	    if (columnUpper[iColumn] >
+		columnLower[iColumn] + 1.0e-12 && columnLength[iColumn]) 
+	      assert(usefulColumn[iColumn]!=0);
+	    else
+	      assert(usefulColumn[iColumn]==0);
+	  }
+#endif
+          while (!finished) {
+               int numberPass = 3;
+               overallLargest = -1.0e-20;
+               overallSmallest = 1.0e20;
+               ClpFillN ( rowScale, numberRows, 1.0);
+               ClpFillN ( columnScale, numberColumns, 1.0);
+               if (scalingMethod == 1 || scalingMethod == 3) {
+                    // Maximum in each row
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         CoinBigIndex j;
+                         largest = 1.0e-10;
+                         for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                              int iColumn = column[j];
+                              if (usefulColumn[iColumn]) {
+                                   double value = fabs(element[j]);
+                                   largest = CoinMax(largest, value);
+                                   assert (largest < 1.0e40);
+                              }
+                         }
+                         rowScale[iRow] = 1.0 / largest;
+#ifdef COIN_DEVELOP
+                         if (extraDetails) {
+                              overallLargest = CoinMax(overallLargest, largest);
+                              overallSmallest = CoinMin(overallSmallest, largest);
+                         }
+#endif
+                    }
+               } else {
+#ifdef USE_OBJECTIVE
+                    // This will be used to help get scale factors
+                    double * objective = new double[numberColumns];
+                    CoinMemcpyN(model->costRegion(1), numberColumns, objective);
+                    double objScale = 1.0;
+#endif
+                    while (numberPass) {
+                         overallLargest = 0.0;
+                         overallSmallest = 1.0e50;
+                         numberPass--;
+                         // Geometric mean on row scales
+                         for (iRow = 0; iRow < numberRows; iRow++) {
+                              CoinBigIndex j;
+                              largest = 1.0e-50;
+                              smallest = 1.0e50;
+                              for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+                                   int iColumn = column[j];
+                                   if (usefulColumn[iColumn]) {
+                                        double value = fabs(element[j]);
+                                        value *= columnScale[iColumn];
+                                        largest = CoinMax(largest, value);
+                                        smallest = CoinMin(smallest, value);
+                                   }
+                              }
+
+#ifdef SQRT_ARRAY
+                              rowScale[iRow] = smallest * largest;
+#else
+                              rowScale[iRow] = 1.0 / sqrt(smallest * largest);
+#endif
+                              //rowScale[iRow]=CoinMax(1.0e-10,CoinMin(1.0e10,rowScale[iRow]));
+                              if (extraDetails) {
+                                   overallLargest = CoinMax(largest * rowScale[iRow], overallLargest);
+                                   overallSmallest = CoinMin(smallest * rowScale[iRow], overallSmallest);
+                              }
+                         }
+                         if (model->scalingFlag() == 5)
+                              break; // just scale rows
+#ifdef SQRT_ARRAY
+                         doSqrts(rowScale, numberRows);
+#endif
+#ifdef USE_OBJECTIVE
+                         largest = 1.0e-20;
+                         smallest = 1.0e50;
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              if (usefulColumn[iColumn]) {
+                                   double value = fabs(objective[iColumn]);
+                                   value *= columnScale[iColumn];
+                                   largest = CoinMax(largest, value);
+                                   smallest = CoinMin(smallest, value);
+                              }
+                         }
+                         objScale = 1.0 / sqrt(smallest * largest);
+#endif
+                         model->messageHandler()->message(CLP_PACKEDSCALE_WHILE, *model->messagesPointer())
+                                   << overallSmallest
+                                   << overallLargest
+                                   << CoinMessageEol;
+                         // skip last column round
+                         if (numberPass == 1)
+                              break;
+                         // Geometric mean on column scales
+                         for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                              if (usefulColumn[iColumn]) {
+                                   CoinBigIndex j;
+                                   largest = 1.0e-50;
+                                   smallest = 1.0e50;
+                                   for (j = columnStart[iColumn];
+                                             j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                        iRow = row[j];
+                                        double value = fabs(elementByColumn[j]);
+                                        value *= rowScale[iRow];
+                                        largest = CoinMax(largest, value);
+                                        smallest = CoinMin(smallest, value);
+                                   }
+#ifdef USE_OBJECTIVE
+                                   if (fabs(objective[iColumn]) > 1.0e-20) {
+                                        double value = fabs(objective[iColumn]) * objScale;
+                                        largest = CoinMax(largest, value);
+                                        smallest = CoinMin(smallest, value);
+                                   }
+#endif
+#ifdef SQRT_ARRAY
+                                   columnScale[iColumn] = smallest * largest;
+#else
+                                   columnScale[iColumn] = 1.0 / sqrt(smallest * largest);
+#endif
+                                   //columnScale[iColumn]=CoinMax(1.0e-10,CoinMin(1.0e10,columnScale[iColumn]));
+                              }
+                         }
+#ifdef SQRT_ARRAY
+                         doSqrts(columnScale, numberColumns);
+#endif
+                    }
+#ifdef USE_OBJECTIVE
+                    delete [] objective;
+                    printf("obj scale %g - use it if you want\n", objScale);
+#endif
+               }
+               // If ranges will make horrid then scale
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    double difference = rowUpper[iRow] - rowLower[iRow];
+                    double scaledDifference = difference * rowScale[iRow];
+                    if (scaledDifference > tolerance && scaledDifference < 1.0e-4) {
+                         // make gap larger
+                         rowScale[iRow] *= 1.0e-4 / scaledDifference;
+                         rowScale[iRow] = CoinMax(1.0e-10, CoinMin(1.0e10, rowScale[iRow]));
+                         //printf("Row %d difference %g scaled diff %g => %g\n",iRow,difference,
+                         // scaledDifference,difference*rowScale[iRow]);
+                    }
+               }
+               // final pass to scale columns so largest is reasonable
+               // See what smallest will be if largest is 1.0
+               if (model->scalingFlag() != 5) {
+                    overallSmallest = 1.0e50;
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (usefulColumn[iColumn]) {
+                              CoinBigIndex j;
+                              largest = 1.0e-20;
+                              smallest = 1.0e50;
+                              for (j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   iRow = row[j];
+                                   double value = fabs(elementByColumn[j] * rowScale[iRow]);
+                                   largest = CoinMax(largest, value);
+                                   smallest = CoinMin(smallest, value);
+                              }
+                              if (overallSmallest * largest > smallest)
+                                   overallSmallest = smallest / largest;
+                         }
+                    }
+               }
+               if (scalingMethod == 1 || scalingMethod == 2) {
+                    finished = true;
+               } else if (savedOverallRatio == 0.0 && scalingMethod != 4) {
+                    savedOverallRatio = overallSmallest;
+                    scalingMethod = 4;
+               } else {
+                    assert (scalingMethod == 4);
+                    if (overallSmallest > 2.0 * savedOverallRatio) {
+                         finished = true; // geometric was better
+                         if (model->scalingFlag() == 4) {
+                              // If in Branch and bound change
+                              if ((model->specialOptions() & 1024) != 0) {
+                                   model->scaling(2);
+                              }
+                         }
+                    } else {
+                         scalingMethod = 1; // redo equilibrium
+                         if (model->scalingFlag() == 4) {
+                              // If in Branch and bound change
+                              if ((model->specialOptions() & 1024) != 0) {
+                                   model->scaling(1);
+                              }
+                         }
+                    }
+#if 0
+                    if (extraDetails) {
+                         if (finished)
+                              printf("equilibrium ratio %g, geometric ratio %g , geo chosen\n",
+                                     savedOverallRatio, overallSmallest);
+                         else
+                              printf("equilibrium ratio %g, geometric ratio %g , equi chosen\n",
+                                     savedOverallRatio, overallSmallest);
+                    }
+#endif
+               }
+          }
+          //#define RANDOMIZE
+#ifdef RANDOMIZE
+          // randomize by up to 10%
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               double value = 0.5 - randomNumberGenerator_.randomDouble(); //between -0.5 to + 0.5
+               rowScale[iRow] *= (1.0 + 0.1 * value);
+          }
+#endif
+          overallLargest = 1.0;
+          if (overallSmallest < 1.0e-1)
+               overallLargest = 1.0 / sqrt(overallSmallest);
+          overallLargest = CoinMin(100.0, overallLargest);
+          overallSmallest = 1.0e50;
+          char * usedRow = reinterpret_cast<char *>(inverseRowScale);
+          memset(usedRow, 0, numberRows);
+          //printf("scaling %d\n",model->scalingFlag());
+          if (model->scalingFlag() != 5) {
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    if (columnUpper[iColumn] >
+                              columnLower[iColumn] + 1.0e-12) {
+                         //if (usefulColumn[iColumn]) {
+                         CoinBigIndex j;
+                         largest = 1.0e-20;
+                         smallest = 1.0e50;
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              iRow = row[j];
+                              usedRow[iRow] = 1;
+                              double value = fabs(elementByColumn[j] * rowScale[iRow]);
+                              largest = CoinMax(largest, value);
+                              smallest = CoinMin(smallest, value);
+                         }
+                         columnScale[iColumn] = overallLargest / largest;
+                         //columnScale[iColumn]=CoinMax(1.0e-10,CoinMin(1.0e10,columnScale[iColumn]));
+#ifdef RANDOMIZE
+                         double value = 0.5 - randomNumberGenerator_.randomDouble(); //between -0.5 to + 0.5
+                         columnScale[iColumn] *= (1.0 + 0.1 * value);
+#endif
+                         double difference = columnUpper[iColumn] - columnLower[iColumn];
+                         if (difference < 1.0e-5 * columnScale[iColumn]) {
+                              // make gap larger
+                              columnScale[iColumn] = difference / 1.0e-5;
+                              //printf("Column %d difference %g scaled diff %g => %g\n",iColumn,difference,
+                              // scaledDifference,difference*columnScale[iColumn]);
+                         }
+                         double value = smallest * columnScale[iColumn];
+                         if (overallSmallest > value)
+                              overallSmallest = value;
+                         //overallSmallest = CoinMin(overallSmallest,smallest*columnScale[iColumn]);
+                    } else {
+		      assert(columnScale[iColumn] == 1.0);
+                         //columnScale[iColumn]=1.0;
+                    }
+               }
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    if (!usedRow[iRow]) {
+                         rowScale[iRow] = 1.0;
+                    }
+               }
+          }
+          model->messageHandler()->message(CLP_PACKEDSCALE_FINAL, *model->messagesPointer())
+                    << overallSmallest
+                    << overallLargest
+                    << CoinMessageEol;
+#if 0
+          {
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    assert (rowScale[iRow] == rowScale2[iRow]);
+               }
+               delete [] rowScale2;
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    assert (columnScale[iColumn] == columnScale2[iColumn]);
+               }
+               delete [] columnScale2;
+          }
+#endif
+          if (overallSmallest < 1.0e-13) {
+               // Change factorization zero tolerance
+               double newTolerance = CoinMax(1.0e-15 * (overallSmallest / 1.0e-13),
+                                             1.0e-18);
+               ClpSimplex * simplex = static_cast<ClpSimplex *> (model);
+               if (simplex->factorization()->zeroTolerance() > newTolerance)
+                    simplex->factorization()->zeroTolerance(newTolerance);
+               newTolerance = CoinMax(overallSmallest * 0.5, 1.0e-18);
+               simplex->setZeroTolerance(newTolerance);
+          }
+          delete [] usefulColumn;
+#ifndef SLIM_CLP
+          // If quadratic then make symmetric
+          ClpObjective * obj = model->objectiveAsObject();
+#ifndef NO_RTTI
+          ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(obj));
+#else
+          ClpQuadraticObjective * quadraticObj = NULL;
+          if (obj->type() == 2)
+               quadraticObj = (static_cast< ClpQuadraticObjective*>(obj));
+#endif
+          if (quadraticObj) {
+               if (!rowCopyBase) {
+                    // temporary copy
+                    rowCopyBase = reverseOrderedCopy();
+               }
+#ifndef NDEBUG
+               ClpPackedMatrix* rowCopy =
+                    dynamic_cast< ClpPackedMatrix*>(rowCopyBase);
+               // Make sure it is really a ClpPackedMatrix
+               assert (rowCopy != NULL);
+#else
+               ClpPackedMatrix* rowCopy =
+                    static_cast< ClpPackedMatrix*>(rowCopyBase);
+#endif
+               const int * column = rowCopy->getIndices();
+               const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+               CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+               int numberXColumns = quadratic->getNumCols();
+               if (numberXColumns < numberColumns) {
+                    // we assume symmetric
+                    int numberQuadraticColumns = 0;
+                    int i;
+                    //const int * columnQuadratic = quadratic->getIndices();
+                    //const int * columnQuadraticStart = quadratic->getVectorStarts();
+                    const int * columnQuadraticLength = quadratic->getVectorLengths();
+                    for (i = 0; i < numberXColumns; i++) {
+                         int length = columnQuadraticLength[i];
+#ifndef CORRECT_COLUMN_COUNTS
+                         length = 1;
+#endif
+                         if (length)
+                              numberQuadraticColumns++;
+                    }
+                    int numberXRows = numberRows - numberQuadraticColumns;
+                    numberQuadraticColumns = 0;
+                    for (i = 0; i < numberXColumns; i++) {
+                         int length = columnQuadraticLength[i];
+#ifndef CORRECT_COLUMN_COUNTS
+                         length = 1;
+#endif
+                         if (length) {
+                              rowScale[numberQuadraticColumns+numberXRows] = columnScale[i];
+                              numberQuadraticColumns++;
+                         }
+                    }
+                    int numberQuadraticRows = 0;
+                    for (i = 0; i < numberXRows; i++) {
+                         // See if any in row quadratic
+                         CoinBigIndex j;
+                         int numberQ = 0;
+                         for (j = rowStart[i]; j < rowStart[i+1]; j++) {
+                              int iColumn = column[j];
+                              if (columnQuadraticLength[iColumn])
+                                   numberQ++;
+                         }
+#ifndef CORRECT_ROW_COUNTS
+                         numberQ = 1;
+#endif
+                         if (numberQ) {
+                              columnScale[numberQuadraticRows+numberXColumns] = rowScale[i];
+                              numberQuadraticRows++;
+                         }
+                    }
+                    // and make sure Sj okay
+                    for (iColumn = numberQuadraticRows + numberXColumns; iColumn < numberColumns; iColumn++) {
+                         CoinBigIndex j = columnStart[iColumn];
+                         assert(columnLength[iColumn] == 1);
+                         int iRow = row[j];
+                         double value = fabs(elementByColumn[j] * rowScale[iRow]);
+                         columnScale[iColumn] = 1.0 / value;
+                    }
+               }
+          }
+#endif
+          // make copy (could do faster by using previous values)
+          // could just do partial
+          for (iRow = 0; iRow < numberRows; iRow++)
+               inverseRowScale[iRow] = 1.0 / rowScale[iRow] ;
+          for (iColumn = 0; iColumn < numberColumns; iColumn++)
+               inverseColumnScale[iColumn] = 1.0 / columnScale[iColumn] ;
+          if (!arraysExist) {
+               model->setRowScale(rowScale);
+               model->setColumnScale(columnScale);
+          }
+          if (model->rowCopy()) {
+               // need to replace row by row
+               ClpPackedMatrix* rowCopy =
+                    static_cast< ClpPackedMatrix*>(model->rowCopy());
+               double * element = rowCopy->getMutableElements();
+               const int * column = rowCopy->getIndices();
+               const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+               // scale row copy
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    CoinBigIndex j;
+                    double scale = rowScale[iRow];
+                    double * elementsInThisRow = element + rowStart[iRow];
+                    const int * columnsInThisRow = column + rowStart[iRow];
+                    int number = rowStart[iRow+1] - rowStart[iRow];
+                    assert (number <= numberColumns);
+                    for (j = 0; j < number; j++) {
+                         int iColumn = columnsInThisRow[j];
+                         elementsInThisRow[j] *= scale * columnScale[iColumn];
+                    }
+               }
+               if ((model->specialOptions() & 262144) != 0) {
+                    //if ((model->specialOptions()&(COIN_CBC_USING_CLP|16384))!=0) {
+                    //if (model->inCbcBranchAndBound()&&false) {
+                    // copy without gaps
+                    CoinPackedMatrix * scaledMatrix = new CoinPackedMatrix(*matrix_, 0, 0);
+                    ClpPackedMatrix * scaled = new ClpPackedMatrix(scaledMatrix);
+                    model->setClpScaledMatrix(scaled);
+                    // get matrix data pointers
+                    const int * row = scaledMatrix->getIndices();
+                    const CoinBigIndex * columnStart = scaledMatrix->getVectorStarts();
+#ifndef NDEBUG
+                    const int * columnLength = scaledMatrix->getVectorLengths();
+#endif
+                    double * elementByColumn = scaledMatrix->getMutableElements();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         CoinBigIndex j;
+                         double scale = columnScale[iColumn];
+                         assert (columnStart[iColumn+1] == columnStart[iColumn] + columnLength[iColumn]);
+                         for (j = columnStart[iColumn];
+                                   j < columnStart[iColumn+1]; j++) {
+                              int iRow = row[j];
+                              elementByColumn[j] *= scale * rowScale[iRow];
+                         }
+                    }
+               } else {
+                    //printf("not in b&b\n");
+               }
+          } else {
+               // no row copy
+               delete rowCopyBase;
+          }
+          return 0;
+     }
+}
+// Creates scaled column copy if scales exist
+void
+ClpPackedMatrix::createScaledMatrix(ClpSimplex * model) const
+{
+     int numberRows = model->numberRows();
+     int numberColumns = matrix_->getNumCols();
+     model->setClpScaledMatrix(NULL); // get rid of any scaled matrix
+     // If empty - return as sanityCheck will trap
+     if (!numberRows || !numberColumns) {
+          model->setRowScale(NULL);
+          model->setColumnScale(NULL);
+          return ;
+     }
+     if (!model->rowScale())
+          return;
+     double * rowScale = model->mutableRowScale();
+     double * columnScale = model->mutableColumnScale();
+     // copy without gaps
+     CoinPackedMatrix * scaledMatrix = new CoinPackedMatrix(*matrix_, 0, 0);
+     ClpPackedMatrix * scaled = new ClpPackedMatrix(scaledMatrix);
+     model->setClpScaledMatrix(scaled);
+     // get matrix data pointers
+     const int * row = scaledMatrix->getIndices();
+     const CoinBigIndex * columnStart = scaledMatrix->getVectorStarts();
+#ifndef NDEBUG
+     const int * columnLength = scaledMatrix->getVectorLengths();
+#endif
+     double * elementByColumn = scaledMatrix->getMutableElements();
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+          CoinBigIndex j;
+          double scale = columnScale[iColumn];
+          assert (columnStart[iColumn+1] == columnStart[iColumn] + columnLength[iColumn]);
+          for (j = columnStart[iColumn];
+                    j < columnStart[iColumn+1]; j++) {
+               int iRow = row[j];
+               elementByColumn[j] *= scale * rowScale[iRow];
+          }
+     }
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+}
+/* Unpacks a column into an CoinIndexedvector
+ */
+void
+ClpPackedMatrix::unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                        int iColumn) const
+{
+     const double * rowScale = model->rowScale();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * elementByColumn = matrix_->getElements();
+     CoinBigIndex i;
+     if (!rowScale) {
+          for (i = columnStart[iColumn];
+                    i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+               rowArray->quickAdd(row[i], elementByColumn[i]);
+          }
+     } else {
+          // apply scaling
+          double scale = model->columnScale()[iColumn];
+          for (i = columnStart[iColumn];
+                    i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+               int iRow = row[i];
+               rowArray->quickAdd(iRow, elementByColumn[i]*scale * rowScale[iRow]);
+          }
+     }
+}
+/* Unpacks a column into a CoinIndexedVector
+** in packed format
+Note that model is NOT const.  Bounds and objective could
+be modified if doing column generation (just for this variable) */
+void
+ClpPackedMatrix::unpackPacked(ClpSimplex * model,
+                              CoinIndexedVector * rowArray,
+                              int iColumn) const
+{
+     const double * rowScale = model->rowScale();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * elementByColumn = matrix_->getElements();
+     CoinBigIndex i;
+     int * index = rowArray->getIndices();
+     double * array = rowArray->denseVector();
+     int number = 0;
+     if (!rowScale) {
+          for (i = columnStart[iColumn];
+                    i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+               int iRow = row[i];
+               double value = elementByColumn[i];
+               if (value) {
+                    array[number] = value;
+                    index[number++] = iRow;
+               }
+          }
+          rowArray->setNumElements(number);
+          rowArray->setPackedMode(true);
+     } else {
+          // apply scaling
+          double scale = model->columnScale()[iColumn];
+          for (i = columnStart[iColumn];
+                    i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+               int iRow = row[i];
+               double value = elementByColumn[i] * scale * rowScale[iRow];
+               if (value) {
+                    array[number] = value;
+                    index[number++] = iRow;
+               }
+          }
+          rowArray->setNumElements(number);
+          rowArray->setPackedMode(true);
+     }
+}
+/* Adds multiple of a column into an CoinIndexedvector
+      You can use quickAdd to add to vector */
+void
+ClpPackedMatrix::add(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                     int iColumn, double multiplier) const
+{
+     const double * rowScale = model->rowScale();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * elementByColumn = matrix_->getElements();
+     CoinBigIndex i;
+     if (!rowScale) {
+          for (i = columnStart[iColumn];
+                    i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+               int iRow = row[i];
+               rowArray->quickAdd(iRow, multiplier * elementByColumn[i]);
+          }
+     } else {
+          // apply scaling
+          double scale = model->columnScale()[iColumn] * multiplier;
+          for (i = columnStart[iColumn];
+                    i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+               int iRow = row[i];
+               rowArray->quickAdd(iRow, elementByColumn[i]*scale * rowScale[iRow]);
+          }
+     }
+}
+/* Adds multiple of a column into an array */
+void
+ClpPackedMatrix::add(const ClpSimplex * model, double * array,
+                     int iColumn, double multiplier) const
+{
+     const double * rowScale = model->rowScale();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * elementByColumn = matrix_->getElements();
+     CoinBigIndex i;
+     if (!rowScale) {
+          for (i = columnStart[iColumn];
+                    i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+               int iRow = row[i];
+               array[iRow] += multiplier * elementByColumn[i];
+          }
+     } else {
+          // apply scaling
+          double scale = model->columnScale()[iColumn] * multiplier;
+          for (i = columnStart[iColumn];
+                    i < columnStart[iColumn] + columnLength[iColumn]; i++) {
+               int iRow = row[i];
+               array[iRow] += elementByColumn[i] * scale * rowScale[iRow];
+          }
+     }
+}
+/* Checks if all elements are in valid range.  Can just
+   return true if you are not paranoid.  For Clp I will
+   probably expect no zeros.  Code can modify matrix to get rid of
+   small elements.
+   check bits (can be turned off to save time) :
+   1 - check if matrix has gaps
+   2 - check if zero elements
+   4 - check and compress duplicates
+   8 - report on large and small
+*/
+bool
+ClpPackedMatrix::allElementsInRange(ClpModel * model,
+                                    double smallest, double largest,
+                                    int check)
+{
+     int iColumn;
+     // make sure matrix correct size
+     assert (matrix_->getNumRows() <= model->numberRows());
+     if (model->clpScaledMatrix())
+          assert (model->clpScaledMatrix()->getNumElements() == matrix_->getNumElements());
+     assert (matrix_->getNumRows() <= model->numberRows());
+     matrix_->setDimensions(model->numberRows(), model->numberColumns());
+     CoinBigIndex numberLarge = 0;;
+     CoinBigIndex numberSmall = 0;;
+     CoinBigIndex numberDuplicate = 0;;
+     int firstBadColumn = -1;
+     int firstBadRow = -1;
+     double firstBadElement = 0.0;
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * elementByColumn = matrix_->getElements();
+     int numberRows = model->numberRows();
+     int numberColumns = matrix_->getNumCols();
+     // Say no gaps
+     flags_ &= ~2;
+     if (type_>=10)
+       return true; // gub
+     if (check == 14 || check == 10) {
+          if (matrix_->getNumElements() < columnStart[numberColumns]) {
+               // pack down!
+#if 0
+               matrix_->removeGaps();
+#else
+               checkGaps();
+#ifdef DO_CHECK_FLAGS
+	       checkFlags(0);
+#endif
+#endif
+#ifdef COIN_DEVELOP
+               //printf("flags set to 2\n");
+#endif
+          } else if (numberColumns) {
+               assert(columnStart[numberColumns] ==
+                      columnStart[numberColumns-1] + columnLength[numberColumns-1]);
+          }
+          return true;
+     }
+     assert (check == 15 || check == 11);
+     if (check == 15) {
+          int * mark = new int [numberRows];
+          int i;
+          for (i = 0; i < numberRows; i++)
+               mark[i] = -1;
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               CoinBigIndex j;
+               CoinBigIndex start = columnStart[iColumn];
+               CoinBigIndex end = start + columnLength[iColumn];
+               if (end != columnStart[iColumn+1])
+                    flags_ |= 2;
+               for (j = start; j < end; j++) {
+                    double value = fabs(elementByColumn[j]);
+                    int iRow = row[j];
+                    if (iRow < 0 || iRow >= numberRows) {
+#ifndef COIN_BIG_INDEX
+                         printf("Out of range %d %d %d %g\n", iColumn, j, row[j], elementByColumn[j]);
+#elif COIN_BIG_INDEX==0
+                         printf("Out of range %d %d %d %g\n", iColumn, j, row[j], elementByColumn[j]);
+#elif COIN_BIG_INDEX==1
+                         printf("Out of range %d %ld %d %g\n", iColumn, j, row[j], elementByColumn[j]);
+#else
+                         printf("Out of range %d %lld %d %g\n", iColumn, j, row[j], elementByColumn[j]);
+#endif
+                         return false;
+                    }
+                    if (mark[iRow] == -1) {
+                         mark[iRow] = j;
+                    } else {
+                         // duplicate
+                         numberDuplicate++;
+                    }
+                    //printf("%d %d %d %g\n",iColumn,j,row[j],elementByColumn[j]);
+                    if (!value)
+                         flags_ |= 1; // there are zero elements
+                    if (value < smallest) {
+                         numberSmall++;
+                    } else if (!(value <= largest)) {
+                         numberLarge++;
+                         if (firstBadColumn < 0) {
+                              firstBadColumn = iColumn;
+                              firstBadRow = row[j];
+                              firstBadElement = elementByColumn[j];
+                         }
+                    }
+               }
+               //clear mark
+               for (j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    mark[iRow] = -1;
+               }
+          }
+          delete [] mark;
+     } else {
+          // just check for out of range - not for duplicates
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               CoinBigIndex j;
+               CoinBigIndex start = columnStart[iColumn];
+               CoinBigIndex end = start + columnLength[iColumn];
+               if (end != columnStart[iColumn+1])
+                    flags_ |= 2;
+               for (j = start; j < end; j++) {
+                    double value = fabs(elementByColumn[j]);
+                    int iRow = row[j];
+                    if (iRow < 0 || iRow >= numberRows) {
+#ifndef COIN_BIG_INDEX
+                         printf("Out of range %d %d %d %g\n", iColumn, j, row[j], elementByColumn[j]);
+#elif COIN_BIG_INDEX==0
+                         printf("Out of range %d %d %d %g\n", iColumn, j, row[j], elementByColumn[j]);
+#elif COIN_BIG_INDEX==1
+                         printf("Out of range %d %ld %d %g\n", iColumn, j, row[j], elementByColumn[j]);
+#else
+                         printf("Out of range %d %lld %d %g\n", iColumn, j, row[j], elementByColumn[j]);
+#endif
+                         return false;
+                    }
+                    if (!value)
+                         flags_ |= 1; // there are zero elements
+                    if (value < smallest) {
+                         numberSmall++;
+                    } else if (!(value <= largest)) {
+                         numberLarge++;
+                         if (firstBadColumn < 0) {
+                              firstBadColumn = iColumn;
+                              firstBadRow = iRow;
+                              firstBadElement = value;
+                         }
+                    }
+               }
+          }
+     }
+     if (numberLarge) {
+          model->messageHandler()->message(CLP_BAD_MATRIX, model->messages())
+                    << numberLarge
+                    << firstBadColumn << firstBadRow << firstBadElement
+                    << CoinMessageEol;
+          return false;
+     }
+     if (numberSmall)
+          model->messageHandler()->message(CLP_SMALLELEMENTS, model->messages())
+                    << numberSmall
+                    << CoinMessageEol;
+     if (numberDuplicate)
+          model->messageHandler()->message(CLP_DUPLICATEELEMENTS, model->messages())
+                    << numberDuplicate
+                    << CoinMessageEol;
+     if (numberDuplicate)
+          matrix_->eliminateDuplicates(smallest);
+     else if (numberSmall)
+          matrix_->compress(smallest);
+     // If smallest >0.0 then there can't be zero elements
+     if (smallest > 0.0)
+          flags_ &= ~1;;
+     if (numberSmall || numberDuplicate)
+          flags_ |= 2; // will have gaps
+     return true;
+}
+int
+ClpPackedMatrix::gutsOfTransposeTimesByRowGE3a(const CoinIndexedVector * COIN_RESTRICT piVector,
+          int * COIN_RESTRICT index,
+          double * COIN_RESTRICT output,
+          int * COIN_RESTRICT lookup,
+          char * COIN_RESTRICT marked,
+          const double tolerance,
+          const double scalar) const
+{
+     const double * COIN_RESTRICT pi = piVector->denseVector();
+     int numberNonZero = 0;
+     int numberInRowArray = piVector->getNumElements();
+     const int * COIN_RESTRICT column = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT rowStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT element = matrix_->getElements();
+     const int * COIN_RESTRICT whichRow = piVector->getIndices();
+     int * fakeRow = const_cast<int *> (whichRow);
+     fakeRow[numberInRowArray]=0; // so can touch
+#ifndef NDEBUG
+     int maxColumn = 0;
+#endif
+     // ** Row copy is already scaled
+     int nextRow=whichRow[0];
+     CoinBigIndex nextStart = rowStart[nextRow]; 
+     CoinBigIndex nextEnd = rowStart[nextRow+1]; 
+     for (int i = 0; i < numberInRowArray; i++) {
+          double value = pi[i] * scalar;
+	  CoinBigIndex start=nextStart;
+	  CoinBigIndex end=nextEnd;
+	  nextRow=whichRow[i+1];
+	  nextStart = rowStart[nextRow]; 
+	  //coin_prefetch_const(column + nextStart);
+	  //coin_prefetch_const(element + nextStart);
+	  nextEnd = rowStart[nextRow+1]; 
+          CoinBigIndex j;
+          for (j = start; j < end; j++) {
+               int iColumn = column[j];
+#ifndef NDEBUG
+               maxColumn = CoinMax(maxColumn, iColumn);
+#endif
+               double elValue = element[j];
+               elValue *= value;
+               if (marked[iColumn]) {
+                    int k = lookup[iColumn];
+                    output[k] += elValue;
+               } else {
+                    output[numberNonZero] = elValue;
+                    marked[iColumn] = 1;
+                    lookup[iColumn] = numberNonZero;
+                    index[numberNonZero++] = iColumn;
+               }
+          }
+     }
+#ifndef NDEBUG
+     int saveN = numberNonZero;
+#endif
+     // get rid of tiny values and zero out lookup
+     for (int i = 0; i < numberNonZero; i++) {
+          int iColumn = index[i];
+          marked[iColumn] = 0;
+          double value = output[i];
+          if (fabs(value) <= tolerance) {
+               while (fabs(value) <= tolerance) {
+                    numberNonZero--;
+                    value = output[numberNonZero];
+                    iColumn = index[numberNonZero];
+                    marked[iColumn] = 0;
+                    if (i < numberNonZero) {
+                         output[numberNonZero] = 0.0;
+                         output[i] = value;
+                         index[i] = iColumn;
+                    } else {
+                         output[i] = 0.0;
+                         value = 1.0; // to force end of while
+                    }
+               }
+          }
+     }
+#ifndef NDEBUG
+     for (int i = numberNonZero; i < saveN; i++)
+          assert(!output[i]);
+     for (int i = 0; i <= maxColumn; i++)
+          assert (!marked[i]);
+#endif
+     return numberNonZero;
+}
+int
+ClpPackedMatrix::gutsOfTransposeTimesByRowGE3(const CoinIndexedVector * COIN_RESTRICT piVector,
+          int * COIN_RESTRICT index,
+          double * COIN_RESTRICT output,
+          double * COIN_RESTRICT array,
+          const double tolerance,
+          const double scalar) const
+{
+     const double * COIN_RESTRICT pi = piVector->denseVector();
+     int numberNonZero = 0;
+     int numberInRowArray = piVector->getNumElements();
+     const int * COIN_RESTRICT column = matrix_->getIndices();
+     const CoinBigIndex * COIN_RESTRICT rowStart = matrix_->getVectorStarts();
+     const double * COIN_RESTRICT element = matrix_->getElements();
+     const int * COIN_RESTRICT whichRow = piVector->getIndices();
+     // ** Row copy is already scaled
+     for (int i = 0; i < numberInRowArray; i++) {
+          int iRow = whichRow[i];
+          double value = pi[i] * scalar;
+          CoinBigIndex j;
+          for (j = rowStart[iRow]; j < rowStart[iRow+1]; j++) {
+               int iColumn = column[j];
+	       double inValue = array[iColumn];
+               double elValue = element[j];
+               elValue *= value;
+	       if (inValue) {
+		 double outValue = inValue + elValue;
+		 if (!outValue)
+		   outValue = COIN_INDEXED_REALLY_TINY_ELEMENT;
+		 array[iColumn] = outValue;
+               } else {
+		 array[iColumn] = elValue;
+		 assert (elValue);
+		 index[numberNonZero++] = iColumn;
+               }
+          }
+     }
+     int saveN = numberNonZero;
+     // get rid of tiny values
+     numberNonZero=0;
+     for (int i = 0; i < saveN; i++) {
+          int iColumn = index[i];
+          double value = array[iColumn];
+	  array[iColumn] =0.0;
+          if (fabs(value) > tolerance) {
+	    output[numberNonZero] = value;
+	    index[numberNonZero++] = iColumn;
+          }
+     }
+     return numberNonZero;
+}
+/* Given positive integer weights for each row fills in sum of weights
+   for each column (and slack).
+   Returns weights vector
+*/
+CoinBigIndex *
+ClpPackedMatrix::dubiousWeights(const ClpSimplex * model, int * inputWeights) const
+{
+     int numberRows = model->numberRows();
+     int numberColumns = matrix_->getNumCols();
+     int number = numberRows + numberColumns;
+     CoinBigIndex * weights = new CoinBigIndex[number];
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     int i;
+     for (i = 0; i < numberColumns; i++) {
+          CoinBigIndex j;
+          CoinBigIndex count = 0;
+          for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+               int iRow = row[j];
+               count += inputWeights[iRow];
+          }
+          weights[i] = count;
+     }
+     for (i = 0; i < numberRows; i++) {
+          weights[i+numberColumns] = inputWeights[i];
+     }
+     return weights;
+}
+/* Returns largest and smallest elements of both signs.
+   Largest refers to largest absolute value.
+*/
+void
+ClpPackedMatrix::rangeOfElements(double & smallestNegative, double & largestNegative,
+                                 double & smallestPositive, double & largestPositive)
+{
+     smallestNegative = -COIN_DBL_MAX;
+     largestNegative = 0.0;
+     smallestPositive = COIN_DBL_MAX;
+     largestPositive = 0.0;
+     // get matrix data pointers
+     const double * elementByColumn = matrix_->getElements();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     int numberColumns = matrix_->getNumCols();
+     int i;
+     for (i = 0; i < numberColumns; i++) {
+          CoinBigIndex j;
+          for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+               double value = elementByColumn[j];
+               if (value > 0.0) {
+                    smallestPositive = CoinMin(smallestPositive, value);
+                    largestPositive = CoinMax(largestPositive, value);
+               } else if (value < 0.0) {
+                    smallestNegative = CoinMax(smallestNegative, value);
+                    largestNegative = CoinMin(largestNegative, value);
+               }
+          }
+     }
+}
+// Says whether it can do partial pricing
+bool
+ClpPackedMatrix::canDoPartialPricing() const
+{
+     return true;
+}
+// Partial pricing
+void
+ClpPackedMatrix::partialPricing(ClpSimplex * model, double startFraction, double endFraction,
+                                int & bestSequence, int & numberWanted)
+{
+     numberWanted = currentWanted_;
+     int start = static_cast<int> (startFraction * numberActiveColumns_);
+     int end = CoinMin(static_cast<int> (endFraction * numberActiveColumns_ + 1), numberActiveColumns_);
+     const double * element = matrix_->getElements();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * startColumn = matrix_->getVectorStarts();
+     const int * length = matrix_->getVectorLengths();
+     const double * rowScale = model->rowScale();
+     const double * columnScale = model->columnScale();
+     int iSequence;
+     CoinBigIndex j;
+     double tolerance = model->currentDualTolerance();
+     double * reducedCost = model->djRegion();
+     const double * duals = model->dualRowSolution();
+     const double * cost = model->costRegion();
+     double bestDj;
+     if (bestSequence >= 0)
+          bestDj = fabs(model->clpMatrix()->reducedCost(model, bestSequence));
+     else
+          bestDj = tolerance;
+     int sequenceOut = model->sequenceOut();
+     int saveSequence = bestSequence;
+     int lastScan = minimumObjectsScan_ < 0 ? end : start + minimumObjectsScan_;
+     int minNeg = minimumGoodReducedCosts_ == -1 ? numberWanted : minimumGoodReducedCosts_;
+     if (rowScale) {
+          // scaled
+          for (iSequence = start; iSequence < end; iSequence++) {
+               if (iSequence != sequenceOut) {
+                    double value;
+                    ClpSimplex::Status status = model->getStatus(iSequence);
+
+                    switch(status) {
+
+                    case ClpSimplex::basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case ClpSimplex::isFree:
+                    case ClpSimplex::superBasic:
+                         value = 0.0;
+                         // scaled
+                         for (j = startColumn[iSequence];
+                                   j < startColumn[iSequence] + length[iSequence]; j++) {
+                              int jRow = row[j];
+                              value -= duals[jRow] * element[j] * rowScale[jRow];
+                         }
+                         value = fabs(cost[iSequence] + value * columnScale[iSequence]);
+                         if (value > FREE_ACCEPT * tolerance) {
+                              numberWanted--;
+                              // we are going to bias towards free (but only if reasonable)
+                              value *= FREE_BIAS;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atUpperBound:
+                         value = 0.0;
+                         // scaled
+                         for (j = startColumn[iSequence];
+                                   j < startColumn[iSequence] + length[iSequence]; j++) {
+                              int jRow = row[j];
+                              value -= duals[jRow] * element[j] * rowScale[jRow];
+                         }
+                         value = cost[iSequence] + value * columnScale[iSequence];
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atLowerBound:
+                         value = 0.0;
+                         // scaled
+                         for (j = startColumn[iSequence];
+                                   j < startColumn[iSequence] + length[iSequence]; j++) {
+                              int jRow = row[j];
+                              value -= duals[jRow] * element[j] * rowScale[jRow];
+                         }
+                         value = -(cost[iSequence] + value * columnScale[iSequence]);
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    }
+               }
+               if (numberWanted + minNeg < originalWanted_ && iSequence > lastScan) {
+                    // give up
+                    break;
+               }
+               if (!numberWanted)
+                    break;
+          }
+          if (bestSequence != saveSequence) {
+               // recompute dj
+               double value = 0.0;
+               // scaled
+               for (j = startColumn[bestSequence];
+                         j < startColumn[bestSequence] + length[bestSequence]; j++) {
+                    int jRow = row[j];
+                    value -= duals[jRow] * element[j] * rowScale[jRow];
+               }
+               reducedCost[bestSequence] = cost[bestSequence] + value * columnScale[bestSequence];
+               savedBestSequence_ = bestSequence;
+               savedBestDj_ = reducedCost[savedBestSequence_];
+          }
+     } else {
+          // not scaled
+          for (iSequence = start; iSequence < end; iSequence++) {
+               if (iSequence != sequenceOut) {
+                    double value;
+                    ClpSimplex::Status status = model->getStatus(iSequence);
+
+                    switch(status) {
+
+                    case ClpSimplex::basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case ClpSimplex::isFree:
+                    case ClpSimplex::superBasic:
+                         value = cost[iSequence];
+                         for (j = startColumn[iSequence];
+                                   j < startColumn[iSequence] + length[iSequence]; j++) {
+                              int jRow = row[j];
+                              value -= duals[jRow] * element[j];
+                         }
+                         value = fabs(value);
+                         if (value > FREE_ACCEPT * tolerance) {
+                              numberWanted--;
+                              // we are going to bias towards free (but only if reasonable)
+                              value *= FREE_BIAS;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atUpperBound:
+                         value = cost[iSequence];
+                         // scaled
+                         for (j = startColumn[iSequence];
+                                   j < startColumn[iSequence] + length[iSequence]; j++) {
+                              int jRow = row[j];
+                              value -= duals[jRow] * element[j];
+                         }
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atLowerBound:
+                         value = cost[iSequence];
+                         for (j = startColumn[iSequence];
+                                   j < startColumn[iSequence] + length[iSequence]; j++) {
+                              int jRow = row[j];
+                              value -= duals[jRow] * element[j];
+                         }
+                         value = -value;
+                         if (value > tolerance) {
+                              numberWanted--;
+                              if (value > bestDj) {
+                                   // check flagged variable and correct dj
+                                   if (!model->flagged(iSequence)) {
+                                        bestDj = value;
+                                        bestSequence = iSequence;
+                                   } else {
+                                        // just to make sure we don't exit before got something
+                                        numberWanted++;
+                                   }
+                              }
+                         }
+                         break;
+                    }
+               }
+               if (numberWanted + minNeg < originalWanted_ && iSequence > lastScan) {
+                    // give up
+                    break;
+               }
+               if (!numberWanted)
+                    break;
+          }
+          if (bestSequence != saveSequence) {
+               // recompute dj
+               double value = cost[bestSequence];
+               for (j = startColumn[bestSequence];
+                         j < startColumn[bestSequence] + length[bestSequence]; j++) {
+                    int jRow = row[j];
+                    value -= duals[jRow] * element[j];
+               }
+               reducedCost[bestSequence] = value;
+               savedBestSequence_ = bestSequence;
+               savedBestDj_ = reducedCost[savedBestSequence_];
+          }
+     }
+     currentWanted_ = numberWanted;
+}
+// Sets up an effective RHS
+void
+ClpPackedMatrix::useEffectiveRhs(ClpSimplex * model)
+{
+     delete [] rhsOffset_;
+     int numberRows = model->numberRows();
+     rhsOffset_ = new double[numberRows];
+     rhsOffset(model, true);
+}
+// Gets rid of special copies
+void
+ClpPackedMatrix::clearCopies()
+{
+     delete rowCopy_;
+     delete columnCopy_;
+     rowCopy_ = NULL;
+     columnCopy_ = NULL;
+     flags_ &= ~(4 + 8);
+     checkGaps();
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+}
+// makes sure active columns correct
+int
+ClpPackedMatrix::refresh(ClpSimplex * )
+{
+     numberActiveColumns_ = matrix_->getNumCols();
+#if 0
+     ClpMatrixBase * rowCopyBase = reverseOrderedCopy();
+     ClpPackedMatrix* rowCopy =
+          dynamic_cast< ClpPackedMatrix*>(rowCopyBase);
+     // Make sure it is really a ClpPackedMatrix
+     assert (rowCopy != NULL);
+
+     const int * column = rowCopy->matrix_->getIndices();
+     const CoinBigIndex * rowStart = rowCopy->matrix_->getVectorStarts();
+     const int * rowLength = rowCopy->matrix_->getVectorLengths();
+     const double * element = rowCopy->matrix_->getElements();
+     int numberRows = rowCopy->matrix_->getNumRows();
+     for (int i = 0; i < numberRows; i++) {
+          if (!rowLength[i])
+               printf("zero row %d\n", i);
+     }
+     delete rowCopy;
+#endif
+     checkGaps();
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+     return 0;
+}
+
+/* Scales rowCopy if column copy scaled
+   Only called if scales already exist */
+void
+ClpPackedMatrix::scaleRowCopy(ClpModel * model) const
+{
+     if (model->rowCopy()) {
+          // need to replace row by row
+          int numberRows = model->numberRows();
+#ifndef NDEBUG
+          int numberColumns = matrix_->getNumCols();
+#endif
+          ClpMatrixBase * rowCopyBase = model->rowCopy();
+#ifndef NDEBUG
+          ClpPackedMatrix* rowCopy =
+               dynamic_cast< ClpPackedMatrix*>(rowCopyBase);
+          // Make sure it is really a ClpPackedMatrix
+          assert (rowCopy != NULL);
+#else
+          ClpPackedMatrix* rowCopy =
+               static_cast< ClpPackedMatrix*>(rowCopyBase);
+#endif
+
+          const int * column = rowCopy->getIndices();
+          const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+          double * element = rowCopy->getMutableElements();
+          const double * rowScale = model->rowScale();
+          const double * columnScale = model->columnScale();
+          // scale row copy
+          for (int iRow = 0; iRow < numberRows; iRow++) {
+               CoinBigIndex j;
+               double scale = rowScale[iRow];
+               double * elementsInThisRow = element + rowStart[iRow];
+               const int * columnsInThisRow = column + rowStart[iRow];
+               int number = rowStart[iRow+1] - rowStart[iRow];
+               assert (number <= numberColumns);
+               for (j = 0; j < number; j++) {
+                    int iColumn = columnsInThisRow[j];
+                    elementsInThisRow[j] *= scale * columnScale[iColumn];
+               }
+          }
+     }
+}
+/* Realy really scales column copy
+   Only called if scales already exist.
+   Up to user ro delete */
+ClpMatrixBase *
+ClpPackedMatrix::scaledColumnCopy(ClpModel * model) const
+{
+     // need to replace column by column
+#ifndef NDEBUG
+     int numberRows = model->numberRows();
+#endif
+     int numberColumns = matrix_->getNumCols();
+     ClpPackedMatrix * copy = new ClpPackedMatrix(*this);
+     const int * row = copy->getIndices();
+     const CoinBigIndex * columnStart = copy->getVectorStarts();
+     const int * length = copy->getVectorLengths();
+     double * element = copy->getMutableElements();
+     const double * rowScale = model->rowScale();
+     const double * columnScale = model->columnScale();
+     // scale column copy
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+          CoinBigIndex j;
+          double scale = columnScale[iColumn];
+          double * elementsInThisColumn = element + columnStart[iColumn];
+          const int * rowsInThisColumn = row + columnStart[iColumn];
+          int number = length[iColumn];
+          assert (number <= numberRows);
+          for (j = 0; j < number; j++) {
+               int iRow = rowsInThisColumn[j];
+               elementsInThisColumn[j] *= scale * rowScale[iRow];
+          }
+     }
+     return copy;
+}
+// Really scale matrix
+void
+ClpPackedMatrix::reallyScale(const double * rowScale, const double * columnScale)
+{
+     clearCopies();
+     int numberColumns = matrix_->getNumCols();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * length = matrix_->getVectorLengths();
+     double * element = matrix_->getMutableElements();
+     // scale
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+          CoinBigIndex j;
+          double scale = columnScale[iColumn];
+          for (j = columnStart[iColumn]; j < columnStart[iColumn] + length[iColumn]; j++) {
+               int iRow = row[j];
+               element[j] *= scale * rowScale[iRow];
+          }
+     }
+}
+/* Delete the columns whose indices are listed in <code>indDel</code>. */
+void
+ClpPackedMatrix::deleteCols(const int numDel, const int * indDel)
+{
+     if (matrix_->getNumCols())
+          matrix_->deleteCols(numDel, indDel);
+     clearCopies();
+     numberActiveColumns_ = matrix_->getNumCols();
+     // may now have gaps
+     checkGaps();
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+     matrix_->setExtraGap(0.0);
+}
+/* Delete the rows whose indices are listed in <code>indDel</code>. */
+void
+ClpPackedMatrix::deleteRows(const int numDel, const int * indDel)
+{
+     if (matrix_->getNumRows())
+          matrix_->deleteRows(numDel, indDel);
+     clearCopies();
+     numberActiveColumns_ = matrix_->getNumCols();
+     // may now have gaps
+     checkGaps();
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+     matrix_->setExtraGap(0.0);
+}
+#ifndef CLP_NO_VECTOR
+// Append Columns
+void
+ClpPackedMatrix::appendCols(int number, const CoinPackedVectorBase * const * columns)
+{
+     matrix_->appendCols(number, columns);
+     numberActiveColumns_ = matrix_->getNumCols();
+     clearCopies();
+}
+// Append Rows
+void
+ClpPackedMatrix::appendRows(int number, const CoinPackedVectorBase * const * rows)
+{
+     matrix_->appendRows(number, rows);
+     numberActiveColumns_ = matrix_->getNumCols();
+     // may now have gaps
+     checkGaps();
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+     clearCopies();
+}
+#endif
+/* Set the dimensions of the matrix. In effect, append new empty
+   columns/rows to the matrix. A negative number for either dimension
+   means that that dimension doesn't change. Otherwise the new dimensions
+   MUST be at least as large as the current ones otherwise an exception
+   is thrown. */
+void
+ClpPackedMatrix::setDimensions(int numrows, int numcols)
+{
+     matrix_->setDimensions(numrows, numcols);
+#ifdef DO_CHECK_FLAGS
+     checkFlags(0);
+#endif
+}
+/* Append a set of rows/columns to the end of the matrix. Returns number of errors
+   i.e. if any of the new rows/columns contain an index that's larger than the
+   number of columns-1/rows-1 (if numberOther>0) or duplicates
+   If 0 then rows, 1 if columns */
+int
+ClpPackedMatrix::appendMatrix(int number, int type,
+                              const CoinBigIndex * starts, const int * index,
+                              const double * element, int numberOther)
+{
+     int numberErrors = 0;
+     // make sure other dimension is big enough
+     if (type == 0) {
+          // rows
+          if (matrix_->isColOrdered() && numberOther > matrix_->getNumCols())
+               matrix_->setDimensions(-1, numberOther);
+          if (!matrix_->isColOrdered() || numberOther >= 0 || matrix_->getExtraGap()) {
+               numberErrors = matrix_->appendRows(number, starts, index, element, numberOther);
+          } else {
+               //CoinPackedMatrix mm(*matrix_);
+               matrix_->appendMinorFast(number, starts, index, element);
+               //mm.appendRows(number,starts,index,element,numberOther);
+               //if (!mm.isEquivalent(*matrix_)) {
+               //printf("bad append\n");
+               //abort();
+               //}
+          }
+     } else {
+          // columns
+          if (!matrix_->isColOrdered() && numberOther > matrix_->getNumRows())
+               matrix_->setDimensions(numberOther, -1);
+	  if (element)
+	    numberErrors = matrix_->appendCols(number, starts, index, element, numberOther);
+	  else
+	    matrix_->setDimensions(-1,matrix_->getNumCols()+number); // resize
+     }
+     clearCopies();
+     numberActiveColumns_ = matrix_->getNumCols();
+     return numberErrors;
+}
+void
+ClpPackedMatrix::specialRowCopy(ClpSimplex * model, const ClpMatrixBase * rowCopy)
+{
+     delete rowCopy_;
+     rowCopy_ = new ClpPackedMatrix2(model, rowCopy->getPackedMatrix());
+     // See if anything in it
+     if (!rowCopy_->usefulInfo()) {
+          delete rowCopy_;
+          rowCopy_ = NULL;
+          flags_ &= ~4;
+     } else {
+          flags_ |= 4;
+     }
+}
+void
+ClpPackedMatrix::specialColumnCopy(ClpSimplex * model)
+{
+     delete columnCopy_;
+     if ((flags_ & 16) != 0) {
+          columnCopy_ = new ClpPackedMatrix3(model, matrix_);
+          flags_ |= 8;
+     } else {
+          columnCopy_ = NULL;
+     }
+}
+// Say we don't want special column copy
+void
+ClpPackedMatrix::releaseSpecialColumnCopy()
+{
+     flags_ &= ~(8 + 16);
+     delete columnCopy_;
+     columnCopy_ = NULL;
+}
+// Correct sequence in and out to give true value
+void
+ClpPackedMatrix::correctSequence(const ClpSimplex * model, int & sequenceIn, int & sequenceOut)
+{
+     if (columnCopy_) {
+          if (sequenceIn != -999) {
+               if (sequenceIn != sequenceOut) {
+                    if (sequenceIn < numberActiveColumns_)
+                         columnCopy_->swapOne(model, this, sequenceIn);
+                    if (sequenceOut < numberActiveColumns_)
+                         columnCopy_->swapOne(model, this, sequenceOut);
+               }
+          } else {
+               // do all
+               columnCopy_->sortBlocks(model);
+          }
+     }
+}
+// Check validity
+void
+ClpPackedMatrix::checkFlags(int type) const
+{
+     int iColumn;
+     // get matrix data pointers
+     //const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * elementByColumn = matrix_->getElements();
+     if (!zeros()) {
+          for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+               CoinBigIndex j;
+               for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    if (!elementByColumn[j])
+                         abort();
+               }
+          }
+     }
+     if ((flags_ & 2) == 0) {
+          for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+               if (columnStart[iColumn+1] != columnStart[iColumn] + columnLength[iColumn]) {
+                    abort();
+               }
+          }
+     }
+     if (type) {
+          if ((flags_ & 2) != 0) {
+               bool ok = true;
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    if (columnStart[iColumn+1] != columnStart[iColumn] + columnLength[iColumn]) {
+                         ok = false;
+                         break;
+                    }
+               }
+               if (ok)
+		 COIN_DETAIL_PRINT(printf("flags_ could be 0\n"));
+          }
+     }
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpPackedMatrix2::ClpPackedMatrix2 ()
+     : numberBlocks_(0),
+       numberRows_(0),
+       offset_(NULL),
+       count_(NULL),
+       rowStart_(NULL),
+       column_(NULL),
+       work_(NULL)
+{
+#ifdef THREAD
+     threadId_ = NULL;
+     info_ = NULL;
+#endif
+}
+//-------------------------------------------------------------------
+// Useful Constructor
+//-------------------------------------------------------------------
+ClpPackedMatrix2::ClpPackedMatrix2 (ClpSimplex * , const CoinPackedMatrix * rowCopy)
+     : numberBlocks_(0),
+       numberRows_(0),
+       offset_(NULL),
+       count_(NULL),
+       rowStart_(NULL),
+       column_(NULL),
+       work_(NULL)
+{
+#ifdef THREAD
+     threadId_ = NULL;
+     info_ = NULL;
+#endif
+     numberRows_ = rowCopy->getNumRows();
+     if (!numberRows_)
+          return;
+     int numberColumns = rowCopy->getNumCols();
+     const int * column = rowCopy->getIndices();
+     const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+     const int * length = rowCopy->getVectorLengths();
+     const double * element = rowCopy->getElements();
+     int chunk = 32768; // tune
+     //chunk=100;
+     // tune
+#if 0
+     int chunkY[7] = {1024, 2048, 4096, 8192, 16384, 32768, 65535};
+     int its = model->maximumIterations();
+     if (its >= 1000000 && its < 1000999) {
+          its -= 1000000;
+          its = its / 10;
+          if (its >= 7) abort();
+          chunk = chunkY[its];
+          printf("chunk size %d\n", chunk);
+#define cpuid(func,ax,bx,cx,dx)\
+    __asm__ __volatile__ ("cpuid":\
+    "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
+          unsigned int a, b, c, d;
+          int func = 0;
+          cpuid(func, a, b, c, d);
+          {
+               int i;
+               unsigned int value;
+               value = b;
+               for (i = 0; i < 4; i++) {
+                    printf("%c", (value & 0xff));
+                    value = value >> 8;
+               }
+               value = d;
+               for (i = 0; i < 4; i++) {
+                    printf("%c", (value & 0xff));
+                    value = value >> 8;
+               }
+               value = c;
+               for (i = 0; i < 4; i++) {
+                    printf("%c", (value & 0xff));
+                    value = value >> 8;
+               }
+               printf("\n");
+               int maxfunc = a;
+               if (maxfunc > 10) {
+                    printf("not intel?\n");
+                    abort();
+               }
+               for (func = 1; func <= maxfunc; func++) {
+                    cpuid(func, a, b, c, d);
+                    printf("func %d, %x %x %x %x\n", func, a, b, c, d);
+               }
+          }
+#else
+     if (numberColumns > 10000 || chunk == 100) {
+#endif
+     } else {
+          //printf("no chunk\n");
+          return;
+     }
+     // Could also analyze matrix to get natural breaks
+     numberBlocks_ = (numberColumns + chunk - 1) / chunk;
+#ifdef THREAD
+     // Get work areas
+     threadId_ = new pthread_t [numberBlocks_];
+     info_ = new dualColumn0Struct[numberBlocks_];
+#endif
+     // Even out
+     chunk = (numberColumns + numberBlocks_ - 1) / numberBlocks_;
+     offset_ = new int[numberBlocks_+1];
+     offset_[numberBlocks_] = numberColumns;
+     int nRow = numberBlocks_ * numberRows_;
+     count_ = new unsigned short[nRow];
+     memset(count_, 0, nRow * sizeof(unsigned short));
+     rowStart_ = new CoinBigIndex[nRow+numberRows_+1];
+     CoinBigIndex nElement = rowStart[numberRows_];
+     rowStart_[nRow+numberRows_] = nElement;
+     column_ = new unsigned short [nElement];
+     // assumes int <= double
+     int sizeWork = 6 * numberBlocks_;
+     work_ = new double[sizeWork];;
+     int iBlock;
+     int nZero = 0;
+     for (iBlock = 0; iBlock < numberBlocks_; iBlock++) {
+          int start = iBlock * chunk;
+          offset_[iBlock] = start;
+          int end = start + chunk;
+          for (int iRow = 0; iRow < numberRows_; iRow++) {
+               if (rowStart[iRow+1] != rowStart[iRow] + length[iRow]) {
+                    printf("not packed correctly - gaps\n");
+                    abort();
+               }
+               bool lastFound = false;
+               int nFound = 0;
+               for (CoinBigIndex j = rowStart[iRow];
+                         j < rowStart[iRow] + length[iRow]; j++) {
+                    int iColumn = column[j];
+                    if (iColumn >= start) {
+                         if (iColumn < end) {
+                              if (!element[j]) {
+                                   printf("not packed correctly - zero element\n");
+                                   abort();
+                              }
+                              column_[j] = static_cast<unsigned short>(iColumn - start);
+                              nFound++;
+                              if (lastFound) {
+                                   printf("not packed correctly - out of order\n");
+                                   abort();
+                              }
+                         } else {
+                              //can't find any more
+                              lastFound = true;
+                         }
+                    }
+               }
+               count_[iRow*numberBlocks_+iBlock] = static_cast<unsigned short>(nFound);
+               if (!nFound)
+                    nZero++;
+          }
+     }
+     //double fraction = ((double) nZero)/((double) (numberBlocks_*numberRows_));
+     //printf("%d empty blocks, %g%%\n",nZero,100.0*fraction);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpPackedMatrix2::ClpPackedMatrix2 (const ClpPackedMatrix2 & rhs)
+     : numberBlocks_(rhs.numberBlocks_),
+       numberRows_(rhs.numberRows_)
+{
+     if (numberBlocks_) {
+          offset_ = CoinCopyOfArray(rhs.offset_, numberBlocks_ + 1);
+          int nRow = numberBlocks_ * numberRows_;
+          count_ = CoinCopyOfArray(rhs.count_, nRow);
+          rowStart_ = CoinCopyOfArray(rhs.rowStart_, nRow + numberRows_ + 1);
+          CoinBigIndex nElement = rowStart_[nRow+numberRows_];
+          column_ = CoinCopyOfArray(rhs.column_, nElement);
+          int sizeWork = 6 * numberBlocks_;
+          work_ = CoinCopyOfArray(rhs.work_, sizeWork);
+#ifdef THREAD
+          threadId_ = new pthread_t [numberBlocks_];
+          info_ = new dualColumn0Struct[numberBlocks_];
+#endif
+     } else {
+          offset_ = NULL;
+          count_ = NULL;
+          rowStart_ = NULL;
+          column_ = NULL;
+          work_ = NULL;
+#ifdef THREAD
+          threadId_ = NULL;
+          info_ = NULL;
+#endif
+     }
+}
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpPackedMatrix2::~ClpPackedMatrix2 ()
+{
+     delete [] offset_;
+     delete [] count_;
+     delete [] rowStart_;
+     delete [] column_;
+     delete [] work_;
+#ifdef THREAD
+     delete [] threadId_;
+     delete [] info_;
+#endif
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpPackedMatrix2 &
+ClpPackedMatrix2::operator=(const ClpPackedMatrix2& rhs)
+{
+     if (this != &rhs) {
+          numberBlocks_ = rhs.numberBlocks_;
+          numberRows_ = rhs.numberRows_;
+          delete [] offset_;
+          delete [] count_;
+          delete [] rowStart_;
+          delete [] column_;
+          delete [] work_;
+#ifdef THREAD
+          delete [] threadId_;
+          delete [] info_;
+#endif
+          if (numberBlocks_) {
+               offset_ = CoinCopyOfArray(rhs.offset_, numberBlocks_ + 1);
+               int nRow = numberBlocks_ * numberRows_;
+               count_ = CoinCopyOfArray(rhs.count_, nRow);
+               rowStart_ = CoinCopyOfArray(rhs.rowStart_, nRow + numberRows_ + 1);
+               CoinBigIndex nElement = rowStart_[nRow+numberRows_];
+               column_ = CoinCopyOfArray(rhs.column_, nElement);
+               int sizeWork = 6 * numberBlocks_;
+               work_ = CoinCopyOfArray(rhs.work_, sizeWork);
+#ifdef THREAD
+               threadId_ = new pthread_t [numberBlocks_];
+               info_ = new dualColumn0Struct[numberBlocks_];
+#endif
+          } else {
+               offset_ = NULL;
+               count_ = NULL;
+               rowStart_ = NULL;
+               column_ = NULL;
+               work_ = NULL;
+#ifdef THREAD
+               threadId_ = NULL;
+               info_ = NULL;
+#endif
+          }
+     }
+     return *this;
+}
+static int dualColumn0(const ClpSimplex * model, double * spare,
+                       int * spareIndex, const double * arrayTemp,
+                       const int * indexTemp, int numberIn,
+                       int offset, double acceptablePivot, double * bestPossiblePtr,
+                       double * upperThetaPtr, int * posFreePtr, double * freePivotPtr)
+{
+     // do dualColumn0
+     int i;
+     int numberRemaining = 0;
+     double bestPossible = 0.0;
+     double upperTheta = 1.0e31;
+     double freePivot = acceptablePivot;
+     int posFree = -1;
+     const double * reducedCost = model->djRegion(1);
+     double dualTolerance = model->dualTolerance();
+     // We can also see if infeasible or pivoting on free
+     double tentativeTheta = 1.0e25;
+     for (i = 0; i < numberIn; i++) {
+          double alpha = arrayTemp[i];
+          int iSequence = indexTemp[i] + offset;
+          double oldValue;
+          double value;
+          bool keep;
+
+          switch(model->getStatus(iSequence)) {
+
+          case ClpSimplex::basic:
+          case ClpSimplex::isFixed:
+               break;
+          case ClpSimplex::isFree:
+          case ClpSimplex::superBasic:
+               bestPossible = CoinMax(bestPossible, fabs(alpha));
+               oldValue = reducedCost[iSequence];
+               // If free has to be very large - should come in via dualRow
+               if (model->getStatus(iSequence) == ClpSimplex::isFree && fabs(alpha) < 1.0e-3)
+                    break;
+               if (oldValue > dualTolerance) {
+                    keep = true;
+               } else if (oldValue < -dualTolerance) {
+                    keep = true;
+               } else {
+                    if (fabs(alpha) > CoinMax(10.0 * acceptablePivot, 1.0e-5))
+                         keep = true;
+                    else
+                         keep = false;
+               }
+               if (keep) {
+                    // free - choose largest
+                    if (fabs(alpha) > freePivot) {
+                         freePivot = fabs(alpha);
+                         posFree = i;
+                    }
+               }
+               break;
+          case ClpSimplex::atUpperBound:
+               oldValue = reducedCost[iSequence];
+               value = oldValue - tentativeTheta * alpha;
+               //assert (oldValue<=dualTolerance*1.0001);
+               if (value > dualTolerance) {
+                    bestPossible = CoinMax(bestPossible, -alpha);
+                    value = oldValue - upperTheta * alpha;
+                    if (value > dualTolerance && -alpha >= acceptablePivot)
+                         upperTheta = (oldValue - dualTolerance) / alpha;
+                    // add to list
+                    spare[numberRemaining] = alpha;
+                    spareIndex[numberRemaining++] = iSequence;
+               }
+               break;
+          case ClpSimplex::atLowerBound:
+               oldValue = reducedCost[iSequence];
+               value = oldValue - tentativeTheta * alpha;
+               //assert (oldValue>=-dualTolerance*1.0001);
+               if (value < -dualTolerance) {
+                    bestPossible = CoinMax(bestPossible, alpha);
+                    value = oldValue - upperTheta * alpha;
+                    if (value < -dualTolerance && alpha >= acceptablePivot)
+                         upperTheta = (oldValue + dualTolerance) / alpha;
+                    // add to list
+                    spare[numberRemaining] = alpha;
+                    spareIndex[numberRemaining++] = iSequence;
+               }
+               break;
+          }
+     }
+     *bestPossiblePtr = bestPossible;
+     *upperThetaPtr = upperTheta;
+     *freePivotPtr = freePivot;
+     *posFreePtr = posFree;
+     return numberRemaining;
+}
+static int doOneBlock(double * array, int * index,
+                      const double * pi, const CoinBigIndex * rowStart, const double * element,
+                      const unsigned short * column, int numberInRowArray, int numberLook)
+{
+     int iWhich = 0;
+     int nextN = 0;
+     CoinBigIndex nextStart = 0;
+     double nextPi = 0.0;
+     for (; iWhich < numberInRowArray; iWhich++) {
+          nextStart = rowStart[0];
+          nextN = rowStart[numberInRowArray] - nextStart;
+          rowStart++;
+          if (nextN) {
+               nextPi = pi[iWhich];
+               break;
+          }
+     }
+     int i;
+     while (iWhich < numberInRowArray) {
+          double value = nextPi;
+          CoinBigIndex j =  nextStart;
+          int n = nextN;
+          // get next
+          iWhich++;
+          for (; iWhich < numberInRowArray; iWhich++) {
+               nextStart = rowStart[0];
+               nextN = rowStart[numberInRowArray] - nextStart;
+               rowStart++;
+               if (nextN) {
+                    //coin_prefetch_const(element + nextStart);
+                    nextPi = pi[iWhich];
+                    break;
+               }
+          }
+          CoinBigIndex end = j + n;
+          //coin_prefetch_const(element+rowStart_[i+1]);
+          //coin_prefetch_const(column_+rowStart_[i+1]);
+          if (n < 100) {
+               if ((n & 1) != 0) {
+                    unsigned int jColumn = column[j];
+                    array[jColumn] -= value * element[j];
+                    j++;
+               }
+               //coin_prefetch_const(column + nextStart);
+               for (; j < end; j += 2) {
+                    unsigned int jColumn0 = column[j];
+                    double value0 = value * element[j];
+                    unsigned int jColumn1 = column[j+1];
+                    double value1 = value * element[j+1];
+                    array[jColumn0] -= value0;
+                    array[jColumn1] -= value1;
+               }
+          } else {
+               if ((n & 1) != 0) {
+                    unsigned int jColumn = column[j];
+                    array[jColumn] -= value * element[j];
+                    j++;
+               }
+               if ((n & 2) != 0) {
+                    unsigned int jColumn0 = column[j];
+                    double value0 = value * element[j];
+                    unsigned int jColumn1 = column[j+1];
+                    double value1 = value * element[j+1];
+                    array[jColumn0] -= value0;
+                    array[jColumn1] -= value1;
+                    j += 2;
+               }
+               if ((n & 4) != 0) {
+                    unsigned int jColumn0 = column[j];
+                    double value0 = value * element[j];
+                    unsigned int jColumn1 = column[j+1];
+                    double value1 = value * element[j+1];
+                    unsigned int jColumn2 = column[j+2];
+                    double value2 = value * element[j+2];
+                    unsigned int jColumn3 = column[j+3];
+                    double value3 = value * element[j+3];
+                    array[jColumn0] -= value0;
+                    array[jColumn1] -= value1;
+                    array[jColumn2] -= value2;
+                    array[jColumn3] -= value3;
+                    j += 4;
+               }
+               //coin_prefetch_const(column+nextStart);
+               for (; j < end; j += 8) {
+                    //coin_prefetch_const(element + j + 16);
+                    unsigned int jColumn0 = column[j];
+                    double value0 = value * element[j];
+                    unsigned int jColumn1 = column[j+1];
+                    double value1 = value * element[j+1];
+                    unsigned int jColumn2 = column[j+2];
+                    double value2 = value * element[j+2];
+                    unsigned int jColumn3 = column[j+3];
+                    double value3 = value * element[j+3];
+                    array[jColumn0] -= value0;
+                    array[jColumn1] -= value1;
+                    array[jColumn2] -= value2;
+                    array[jColumn3] -= value3;
+                    //coin_prefetch_const(column + j + 16);
+                    jColumn0 = column[j+4];
+                    value0 = value * element[j+4];
+                    jColumn1 = column[j+5];
+                    value1 = value * element[j+5];
+                    jColumn2 = column[j+6];
+                    value2 = value * element[j+6];
+                    jColumn3 = column[j+7];
+                    value3 = value * element[j+7];
+                    array[jColumn0] -= value0;
+                    array[jColumn1] -= value1;
+                    array[jColumn2] -= value2;
+                    array[jColumn3] -= value3;
+               }
+          }
+     }
+     // get rid of tiny values
+     int nSmall = numberLook;
+     int numberNonZero = 0;
+     for (i = 0; i < nSmall; i++) {
+          double value = array[i];
+          array[i] = 0.0;
+          if (fabs(value) > 1.0e-12) {
+               array[numberNonZero] = value;
+               index[numberNonZero++] = i;
+          }
+     }
+     for (; i < numberLook; i += 4) {
+          double value0 = array[i+0];
+          double value1 = array[i+1];
+          double value2 = array[i+2];
+          double value3 = array[i+3];
+          array[i+0] = 0.0;
+          array[i+1] = 0.0;
+          array[i+2] = 0.0;
+          array[i+3] = 0.0;
+          if (fabs(value0) > 1.0e-12) {
+               array[numberNonZero] = value0;
+               index[numberNonZero++] = i + 0;
+          }
+          if (fabs(value1) > 1.0e-12) {
+               array[numberNonZero] = value1;
+               index[numberNonZero++] = i + 1;
+          }
+          if (fabs(value2) > 1.0e-12) {
+               array[numberNonZero] = value2;
+               index[numberNonZero++] = i + 2;
+          }
+          if (fabs(value3) > 1.0e-12) {
+               array[numberNonZero] = value3;
+               index[numberNonZero++] = i + 3;
+          }
+     }
+     return numberNonZero;
+}
+#ifdef THREAD
+static void * doOneBlockThread(void * voidInfo)
+{
+     dualColumn0Struct * info = (dualColumn0Struct *) voidInfo;
+     *(info->numberInPtr) =  doOneBlock(info->arrayTemp, info->indexTemp, info->pi,
+                                        info->rowStart, info->element, info->column,
+                                        info->numberInRowArray, info->numberLook);
+     return NULL;
+}
+static void * doOneBlockAnd0Thread(void * voidInfo)
+{
+     dualColumn0Struct * info = (dualColumn0Struct *) voidInfo;
+     *(info->numberInPtr) =  doOneBlock(info->arrayTemp, info->indexTemp, info->pi,
+                                        info->rowStart, info->element, info->column,
+                                        info->numberInRowArray, info->numberLook);
+     *(info->numberOutPtr) =  dualColumn0(info->model, info->spare,
+                                          info->spareIndex, (const double *)info->arrayTemp,
+                                          (const int *) info->indexTemp, *(info->numberInPtr),
+                                          info->offset, info->acceptablePivot, info->bestPossiblePtr,
+                                          info->upperThetaPtr, info->posFreePtr, info->freePivotPtr);
+     return NULL;
+}
+#endif
+/* Return <code>x * scalar * A in <code>z</code>.
+   Note - x packed and z will be packed mode
+   Squashes small elements and knows about ClpSimplex */
+void
+ClpPackedMatrix2::transposeTimes(const ClpSimplex * model,
+                                 const CoinPackedMatrix * rowCopy,
+                                 const CoinIndexedVector * rowArray,
+                                 CoinIndexedVector * spareArray,
+                                 CoinIndexedVector * columnArray) const
+{
+     // See if dualColumn0 coding wanted
+     bool dualColumn = model->spareIntArray_[0] == 1;
+     double acceptablePivot = model->spareDoubleArray_[0];
+     double bestPossible = 0.0;
+     double upperTheta = 1.0e31;
+     double freePivot = acceptablePivot;
+     int posFree = -1;
+     int numberRemaining = 0;
+     //if (model->numberIterations()>=200000) {
+     //printf("time %g\n",CoinCpuTime()-startTime);
+     //exit(77);
+     //}
+     double * pi = rowArray->denseVector();
+     int numberNonZero = 0;
+     int * index = columnArray->getIndices();
+     double * array = columnArray->denseVector();
+     int numberInRowArray = rowArray->getNumElements();
+     const int * whichRow = rowArray->getIndices();
+     double * element = const_cast<double *>(rowCopy->getElements());
+     const CoinBigIndex * rowStart = rowCopy->getVectorStarts();
+     int i;
+     CoinBigIndex * rowStart2 = rowStart_;
+     if (!dualColumn) {
+          for (i = 0; i < numberInRowArray; i++) {
+               int iRow = whichRow[i];
+               CoinBigIndex start = rowStart[iRow];
+               *rowStart2 = start;
+               unsigned short * count1 = count_ + iRow * numberBlocks_;
+               int put = 0;
+               for (int j = 0; j < numberBlocks_; j++) {
+                    put += numberInRowArray;
+                    start += count1[j];
+                    rowStart2[put] = start;
+               }
+               rowStart2 ++;
+          }
+     } else {
+          // also do dualColumn stuff
+          double * spare = spareArray->denseVector();
+          int * spareIndex = spareArray->getIndices();
+          const double * reducedCost = model->djRegion(0);
+          double dualTolerance = model->dualTolerance();
+          // We can also see if infeasible or pivoting on free
+          double tentativeTheta = 1.0e25;
+          int addSequence = model->numberColumns();
+          for (i = 0; i < numberInRowArray; i++) {
+               int iRow = whichRow[i];
+               double alpha = pi[i];
+               double oldValue;
+               double value;
+               bool keep;
+
+               switch(model->getStatus(iRow + addSequence)) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    bestPossible = CoinMax(bestPossible, fabs(alpha));
+                    oldValue = reducedCost[iRow];
+                    // If free has to be very large - should come in via dualRow
+                    if (model->getStatus(iRow + addSequence) == ClpSimplex::isFree && fabs(alpha) < 1.0e-3)
+                         break;
+                    if (oldValue > dualTolerance) {
+                         keep = true;
+                    } else if (oldValue < -dualTolerance) {
+                         keep = true;
+                    } else {
+                         if (fabs(alpha) > CoinMax(10.0 * acceptablePivot, 1.0e-5))
+                              keep = true;
+                         else
+                              keep = false;
+                    }
+                    if (keep) {
+                         // free - choose largest
+                         if (fabs(alpha) > freePivot) {
+                              freePivot = fabs(alpha);
+                              posFree = i + addSequence;
+                         }
+                    }
+                    break;
+               case ClpSimplex::atUpperBound:
+                    oldValue = reducedCost[iRow];
+                    value = oldValue - tentativeTheta * alpha;
+                    //assert (oldValue<=dualTolerance*1.0001);
+                    if (value > dualTolerance) {
+                         bestPossible = CoinMax(bestPossible, -alpha);
+                         value = oldValue - upperTheta * alpha;
+                         if (value > dualTolerance && -alpha >= acceptablePivot)
+                              upperTheta = (oldValue - dualTolerance) / alpha;
+                         // add to list
+                         spare[numberRemaining] = alpha;
+                         spareIndex[numberRemaining++] = iRow + addSequence;
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    oldValue = reducedCost[iRow];
+                    value = oldValue - tentativeTheta * alpha;
+                    //assert (oldValue>=-dualTolerance*1.0001);
+                    if (value < -dualTolerance) {
+                         bestPossible = CoinMax(bestPossible, alpha);
+                         value = oldValue - upperTheta * alpha;
+                         if (value < -dualTolerance && alpha >= acceptablePivot)
+                              upperTheta = (oldValue + dualTolerance) / alpha;
+                         // add to list
+                         spare[numberRemaining] = alpha;
+                         spareIndex[numberRemaining++] = iRow + addSequence;
+                    }
+                    break;
+               }
+               CoinBigIndex start = rowStart[iRow];
+               *rowStart2 = start;
+               unsigned short * count1 = count_ + iRow * numberBlocks_;
+               int put = 0;
+               for (int j = 0; j < numberBlocks_; j++) {
+                    put += numberInRowArray;
+                    start += count1[j];
+                    rowStart2[put] = start;
+               }
+               rowStart2 ++;
+          }
+     }
+     double * spare = spareArray->denseVector();
+     int * spareIndex = spareArray->getIndices();
+     int saveNumberRemaining = numberRemaining;
+     int iBlock;
+     for (iBlock = 0; iBlock < numberBlocks_; iBlock++) {
+          double * dwork = work_ + 6 * iBlock;
+          int * iwork = reinterpret_cast<int *> (dwork + 3);
+          if (!dualColumn) {
+#ifndef THREAD
+               int offset = offset_[iBlock];
+               int offset3 = offset;
+               offset = numberNonZero;
+               double * arrayTemp = array + offset;
+               int * indexTemp = index + offset;
+               iwork[0] = doOneBlock(arrayTemp, indexTemp, pi, rowStart_ + numberInRowArray * iBlock,
+                                     element, column_, numberInRowArray, offset_[iBlock+1] - offset);
+               int number = iwork[0];
+               for (i = 0; i < number; i++) {
+                    //double value = arrayTemp[i];
+                    //arrayTemp[i]=0.0;
+                    //array[numberNonZero]=value;
+                    index[numberNonZero++] = indexTemp[i] + offset3;
+               }
+#else
+               int offset = offset_[iBlock];
+               double * arrayTemp = array + offset;
+               int * indexTemp = index + offset;
+               dualColumn0Struct * infoPtr = info_ + iBlock;
+               infoPtr->arrayTemp = arrayTemp;
+               infoPtr->indexTemp = indexTemp;
+               infoPtr->numberInPtr = &iwork[0];
+               infoPtr->pi = pi;
+               infoPtr->rowStart = rowStart_ + numberInRowArray * iBlock;
+               infoPtr->element = element;
+               infoPtr->column = column_;
+               infoPtr->numberInRowArray = numberInRowArray;
+               infoPtr->numberLook = offset_[iBlock+1] - offset;
+               pthread_create(&threadId_[iBlock], NULL, doOneBlockThread, infoPtr);
+#endif
+          } else {
+#ifndef THREAD
+               int offset = offset_[iBlock];
+               // allow for already saved
+               int offset2 = offset + saveNumberRemaining;
+               int offset3 = offset;
+               offset = numberNonZero;
+               offset2 = numberRemaining;
+               double * arrayTemp = array + offset;
+               int * indexTemp = index + offset;
+               iwork[0] = doOneBlock(arrayTemp, indexTemp, pi, rowStart_ + numberInRowArray * iBlock,
+                                     element, column_, numberInRowArray, offset_[iBlock+1] - offset);
+               iwork[1] = dualColumn0(model, spare + offset2,
+                                      spareIndex + offset2,
+                                      arrayTemp, indexTemp,
+                                      iwork[0], offset3, acceptablePivot,
+                                      &dwork[0], &dwork[1], &iwork[2],
+                                      &dwork[2]);
+               int number = iwork[0];
+               int numberLook = iwork[1];
+#if 1
+               numberRemaining += numberLook;
+#else
+               double * spareTemp = spare + offset2;
+               const int * spareIndexTemp = spareIndex + offset2;
+               for (i = 0; i < numberLook; i++) {
+                    double value = spareTemp[i];
+                    spareTemp[i] = 0.0;
+                    spare[numberRemaining] = value;
+                    spareIndex[numberRemaining++] = spareIndexTemp[i];
+               }
+#endif
+               if (dwork[2] > freePivot) {
+                    freePivot = dwork[2];
+                    posFree = iwork[2] + numberNonZero;
+               }
+               upperTheta =  CoinMin(dwork[1], upperTheta);
+               bestPossible = CoinMax(dwork[0], bestPossible);
+               for (i = 0; i < number; i++) {
+                    // double value = arrayTemp[i];
+                    //arrayTemp[i]=0.0;
+                    //array[numberNonZero]=value;
+                    index[numberNonZero++] = indexTemp[i] + offset3;
+               }
+#else
+               int offset = offset_[iBlock];
+               // allow for already saved
+               int offset2 = offset + saveNumberRemaining;
+               double * arrayTemp = array + offset;
+               int * indexTemp = index + offset;
+               dualColumn0Struct * infoPtr = info_ + iBlock;
+               infoPtr->model = model;
+               infoPtr->spare = spare + offset2;
+               infoPtr->spareIndex = spareIndex + offset2;
+               infoPtr->arrayTemp = arrayTemp;
+               infoPtr->indexTemp = indexTemp;
+               infoPtr->numberInPtr = &iwork[0];
+               infoPtr->offset = offset;
+               infoPtr->acceptablePivot = acceptablePivot;
+               infoPtr->bestPossiblePtr = &dwork[0];
+               infoPtr->upperThetaPtr = &dwork[1];
+               infoPtr->posFreePtr = &iwork[2];
+               infoPtr->freePivotPtr = &dwork[2];
+               infoPtr->numberOutPtr = &iwork[1];
+               infoPtr->pi = pi;
+               infoPtr->rowStart = rowStart_ + numberInRowArray * iBlock;
+               infoPtr->element = element;
+               infoPtr->column = column_;
+               infoPtr->numberInRowArray = numberInRowArray;
+               infoPtr->numberLook = offset_[iBlock+1] - offset;
+               if (iBlock >= 2)
+                    pthread_join(threadId_[iBlock-2], NULL);
+               pthread_create(threadId_ + iBlock, NULL, doOneBlockAnd0Thread, infoPtr);
+               //pthread_join(threadId_[iBlock],NULL);
+#endif
+          }
+     }
+     for ( iBlock = CoinMax(0, numberBlocks_ - 2); iBlock < numberBlocks_; iBlock++) {
+#ifdef THREAD
+          pthread_join(threadId_[iBlock], NULL);
+#endif
+     }
+#ifdef THREAD
+     for ( iBlock = 0; iBlock < numberBlocks_; iBlock++) {
+          //pthread_join(threadId_[iBlock],NULL);
+          int offset = offset_[iBlock];
+          double * dwork = work_ + 6 * iBlock;
+          int * iwork = (int *) (dwork + 3);
+          int number = iwork[0];
+          if (dualColumn) {
+               // allow for already saved
+               int offset2 = offset + saveNumberRemaining;
+               int numberLook = iwork[1];
+               double * spareTemp = spare + offset2;
+               const int * spareIndexTemp = spareIndex + offset2;
+               for (i = 0; i < numberLook; i++) {
+                    double value = spareTemp[i];
+                    spareTemp[i] = 0.0;
+                    spare[numberRemaining] = value;
+                    spareIndex[numberRemaining++] = spareIndexTemp[i];
+               }
+               if (dwork[2] > freePivot) {
+                    freePivot = dwork[2];
+                    posFree = iwork[2] + numberNonZero;
+               }
+               upperTheta =  CoinMin(dwork[1], upperTheta);
+               bestPossible = CoinMax(dwork[0], bestPossible);
+          }
+          double * arrayTemp = array + offset;
+          const int * indexTemp = index + offset;
+          for (i = 0; i < number; i++) {
+               double value = arrayTemp[i];
+               arrayTemp[i] = 0.0;
+               array[numberNonZero] = value;
+               index[numberNonZero++] = indexTemp[i] + offset;
+          }
+     }
+#endif
+     columnArray->setNumElements(numberNonZero);
+     columnArray->setPackedMode(true);
+     if (dualColumn) {
+          model->spareDoubleArray_[0] = upperTheta;
+          model->spareDoubleArray_[1] = bestPossible;
+          // and theta and alpha and sequence
+          if (posFree < 0) {
+               model->spareIntArray_[1] = -1;
+          } else {
+               const double * reducedCost = model->djRegion(0);
+               double alpha;
+               int numberColumns = model->numberColumns();
+               if (posFree < numberColumns) {
+                    alpha = columnArray->denseVector()[posFree];
+                    posFree = columnArray->getIndices()[posFree];
+               } else {
+                    alpha = rowArray->denseVector()[posFree-numberColumns];
+                    posFree = rowArray->getIndices()[posFree-numberColumns] + numberColumns;
+               }
+               model->spareDoubleArray_[2] = fabs(reducedCost[posFree] / alpha);;
+               model->spareDoubleArray_[3] = alpha;
+               model->spareIntArray_[1] = posFree;
+          }
+          spareArray->setNumElements(numberRemaining);
+          // signal done
+          model->spareIntArray_[0] = -1;
+     }
+}
+/* Default constructor. */
+ClpPackedMatrix3::ClpPackedMatrix3()
+     : numberBlocks_(0),
+       numberColumns_(0),
+       column_(NULL),
+       start_(NULL),
+       row_(NULL),
+       element_(NULL),
+       block_(NULL)
+{
+}
+/* Constructor from copy. */
+ClpPackedMatrix3::ClpPackedMatrix3(ClpSimplex * model, const CoinPackedMatrix * columnCopy)
+     : numberBlocks_(0),
+       numberColumns_(0),
+       column_(NULL),
+       start_(NULL),
+       row_(NULL),
+       element_(NULL),
+       block_(NULL)
+{
+#define MINBLOCK 6
+#define MAXBLOCK 100
+#define MAXUNROLL 10
+     numberColumns_ = model->getNumCols();
+     int numberColumns = columnCopy->getNumCols();
+     assert (numberColumns_ >= numberColumns);
+     int numberRows = columnCopy->getNumRows();
+     int * counts = new int[numberRows+1];
+     CoinZeroN(counts, numberRows + 1);
+     CoinBigIndex nels = 0;
+     CoinBigIndex nZeroEl = 0;
+     int iColumn;
+     // get matrix data pointers
+     const int * row = columnCopy->getIndices();
+     const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+     const int * columnLength = columnCopy->getVectorLengths();
+     const double * elementByColumn = columnCopy->getElements();
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          CoinBigIndex start = columnStart[iColumn];
+          int n = columnLength[iColumn];
+          CoinBigIndex end = start + n;
+          int kZero = 0;
+          for (CoinBigIndex j = start; j < end; j++) {
+               if(!elementByColumn[j])
+                    kZero++;
+          }
+          n -= kZero;
+          nZeroEl += kZero;
+          nels += n;
+          counts[n]++;
+     }
+     counts[0] += numberColumns_ - numberColumns;
+     int nZeroColumns = counts[0];
+     counts[0] = -1;
+     numberColumns_ -= nZeroColumns;
+     column_ = new int [2*numberColumns_+nZeroColumns];
+     int * lookup = column_ + numberColumns_;
+     row_ = new int[nels];
+     element_ = new double[nels];
+     int nOdd = 0;
+     CoinBigIndex nInOdd = 0;
+     int i;
+     for (i = 1; i <= numberRows; i++) {
+          int n = counts[i];
+          if (n) {
+               if (n < MINBLOCK || i > MAXBLOCK) {
+                    nOdd += n;
+                    counts[i] = -1;
+                    nInOdd += n * i;
+               } else {
+                    numberBlocks_++;
+               }
+          } else {
+               counts[i] = -1;
+          }
+     }
+     start_ = new CoinBigIndex [nOdd+1];
+     // even if no blocks do a dummy one
+     numberBlocks_ = CoinMax(numberBlocks_, 1);
+     block_ = new blockStruct [numberBlocks_];
+     memset(block_, 0, numberBlocks_ * sizeof(blockStruct));
+     // Fill in what we can
+     int nTotal = nOdd;
+     // in case no blocks
+     block_->startIndices_ = nTotal;
+     nels = nInOdd;
+     int nBlock = 0;
+     for (i = 0; i <= CoinMin(MAXBLOCK, numberRows); i++) {
+          if (counts[i] > 0) {
+               blockStruct * block = block_ + nBlock;
+               int n = counts[i];
+               counts[i] = nBlock; // backward pointer
+               nBlock++;
+               block->startIndices_ = nTotal;
+               block->startElements_ = nels;
+               block->numberElements_ = i;
+               // up counts
+               nTotal += n;
+               nels += n * i;
+          }
+     }
+     for (iColumn = numberColumns; iColumn < numberColumns_; iColumn++)
+          lookup[iColumn] = -1;
+     // fill
+     start_[0] = 0;
+     nOdd = 0;
+     nInOdd = 0;
+     const double * columnScale = model->columnScale();
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          CoinBigIndex start = columnStart[iColumn];
+          int n = columnLength[iColumn];
+          CoinBigIndex end = start + n;
+          int kZero = 0;
+          for (CoinBigIndex j = start; j < end; j++) {
+               if(!elementByColumn[j])
+                    kZero++;
+          }
+          n -= kZero;
+          if (n) {
+               int iBlock = counts[n];
+               if (iBlock >= 0) {
+                    blockStruct * block = block_ + iBlock;
+                    int k = block->numberInBlock_;
+                    block->numberInBlock_ ++;
+                    column_[block->startIndices_+k] = iColumn;
+                    lookup[iColumn] = k;
+                    CoinBigIndex put = block->startElements_ + k * n;
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         double value = elementByColumn[j];
+                         if(value) {
+                              if (columnScale)
+                                   value *= columnScale[iColumn];
+                              element_[put] = value;
+                              row_[put++] = row[j];
+                         }
+                    }
+               } else {
+                    // odd ones
+                    for (CoinBigIndex j = start; j < end; j++) {
+                         double value = elementByColumn[j];
+                         if(value) {
+                              if (columnScale)
+                                   value *= columnScale[iColumn];
+                              element_[nInOdd] = value;
+                              row_[nInOdd++] = row[j];
+                         }
+                    }
+                    column_[nOdd] = iColumn;
+                    lookup[iColumn] = -1;
+                    nOdd++;
+                    start_[nOdd] = nInOdd;
+               }
+          } else {
+               // zero column
+               lookup[iColumn] = -1;
+          }
+     }
+     delete [] counts;
+}
+/* Destructor */
+ClpPackedMatrix3::~ClpPackedMatrix3()
+{
+     delete [] column_;
+     delete [] start_;
+     delete [] row_;
+     delete [] element_;
+     delete [] block_;
+}
+/* The copy constructor. */
+ClpPackedMatrix3::ClpPackedMatrix3(const ClpPackedMatrix3 & rhs)
+     : numberBlocks_(rhs.numberBlocks_),
+       numberColumns_(rhs.numberColumns_),
+       column_(NULL),
+       start_(NULL),
+       row_(NULL),
+       element_(NULL),
+       block_(NULL)
+{
+     if (rhs.numberBlocks_) {
+          block_ = CoinCopyOfArray(rhs.block_, numberBlocks_);
+          column_ = CoinCopyOfArray(rhs.column_, 2 * numberColumns_);
+          int numberOdd = block_->startIndices_;
+          start_ = CoinCopyOfArray(rhs.start_, numberOdd + 1);
+          blockStruct * lastBlock = block_ + (numberBlocks_ - 1);
+          CoinBigIndex numberElements = lastBlock->startElements_ +
+                                        lastBlock->numberInBlock_ * lastBlock->numberElements_;
+          row_ = CoinCopyOfArray(rhs.row_, numberElements);
+          element_ = CoinCopyOfArray(rhs.element_, numberElements);
+     }
+}
+ClpPackedMatrix3&
+ClpPackedMatrix3::operator=(const ClpPackedMatrix3 & rhs)
+{
+     if (this != &rhs) {
+          delete [] column_;
+          delete [] start_;
+          delete [] row_;
+          delete [] element_;
+          delete [] block_;
+          numberBlocks_ = rhs.numberBlocks_;
+          numberColumns_ = rhs.numberColumns_;
+          if (rhs.numberBlocks_) {
+               block_ = CoinCopyOfArray(rhs.block_, numberBlocks_);
+               column_ = CoinCopyOfArray(rhs.column_, 2 * numberColumns_);
+               int numberOdd = block_->startIndices_;
+               start_ = CoinCopyOfArray(rhs.start_, numberOdd + 1);
+               blockStruct * lastBlock = block_ + (numberBlocks_ - 1);
+               CoinBigIndex numberElements = lastBlock->startElements_ +
+                                             lastBlock->numberInBlock_ * lastBlock->numberElements_;
+               row_ = CoinCopyOfArray(rhs.row_, numberElements);
+               element_ = CoinCopyOfArray(rhs.element_, numberElements);
+          } else {
+               column_ = NULL;
+               start_ = NULL;
+               row_ = NULL;
+               element_ = NULL;
+               block_ = NULL;
+          }
+     }
+     return *this;
+}
+/* Sort blocks */
+void
+ClpPackedMatrix3::sortBlocks(const ClpSimplex * model)
+{
+     int * lookup = column_ + numberColumns_;
+     for (int iBlock = 0; iBlock < numberBlocks_; iBlock++) {
+          blockStruct * block = block_ + iBlock;
+          int numberInBlock = block->numberInBlock_;
+          int nel = block->numberElements_;
+          int * row = row_ + block->startElements_;
+          double * element = element_ + block->startElements_;
+          int * column = column_ + block->startIndices_;
+          int lastPrice = 0;
+          int firstNotPrice = numberInBlock - 1;
+          while (lastPrice <= firstNotPrice) {
+               // find first basic or fixed
+               int iColumn = numberInBlock;
+               for (; lastPrice <= firstNotPrice; lastPrice++) {
+                    iColumn = column[lastPrice];
+                    if (model->getColumnStatus(iColumn) == ClpSimplex::basic ||
+                              model->getColumnStatus(iColumn) == ClpSimplex::isFixed)
+                         break;
+               }
+               // find last non basic or fixed
+               int jColumn = -1;
+               for (; firstNotPrice > lastPrice; firstNotPrice--) {
+                    jColumn = column[firstNotPrice];
+                    if (model->getColumnStatus(jColumn) != ClpSimplex::basic &&
+                              model->getColumnStatus(jColumn) != ClpSimplex::isFixed)
+                         break;
+               }
+               if (firstNotPrice > lastPrice) {
+                    assert (column[lastPrice] == iColumn);
+                    assert (column[firstNotPrice] == jColumn);
+                    // need to swap
+                    column[firstNotPrice] = iColumn;
+                    lookup[iColumn] = firstNotPrice;
+                    column[lastPrice] = jColumn;
+                    lookup[jColumn] = lastPrice;
+                    double * elementA = element + lastPrice * nel;
+                    int * rowA = row + lastPrice * nel;
+                    double * elementB = element + firstNotPrice * nel;
+                    int * rowB = row + firstNotPrice * nel;
+                    for (int i = 0; i < nel; i++) {
+                         int temp = rowA[i];
+                         double tempE = elementA[i];
+                         rowA[i] = rowB[i];
+                         elementA[i] = elementB[i];
+                         rowB[i] = temp;
+                         elementB[i] = tempE;
+                    }
+                    firstNotPrice--;
+                    lastPrice++;
+               } else if (lastPrice == firstNotPrice) {
+                    // make sure correct side
+                    iColumn = column[lastPrice];
+                    if (model->getColumnStatus(iColumn) != ClpSimplex::basic &&
+                              model->getColumnStatus(iColumn) != ClpSimplex::isFixed)
+                         lastPrice++;
+                    break;
+               }
+          }
+          block->numberPrice_ = lastPrice;
+#ifndef NDEBUG
+          // check
+          int i;
+          for (i = 0; i < lastPrice; i++) {
+               int iColumn = column[i];
+               assert (model->getColumnStatus(iColumn) != ClpSimplex::basic &&
+                       model->getColumnStatus(iColumn) != ClpSimplex::isFixed);
+               assert (lookup[iColumn] == i);
+          }
+          for (; i < numberInBlock; i++) {
+               int iColumn = column[i];
+               assert (model->getColumnStatus(iColumn) == ClpSimplex::basic ||
+                       model->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+               assert (lookup[iColumn] == i);
+          }
+#endif
+     }
+}
+// Swap one variable
+void
+ClpPackedMatrix3::swapOne(const ClpSimplex * model, const ClpPackedMatrix * matrix,
+                          int iColumn)
+{
+     int * lookup = column_ + numberColumns_;
+     // position in block
+     int kA = lookup[iColumn];
+     if (kA < 0)
+          return; // odd one
+     // get matrix data pointers
+     const CoinPackedMatrix * columnCopy = matrix->getPackedMatrix();
+     //const int * row = columnCopy->getIndices();
+     const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+     const int * columnLength = columnCopy->getVectorLengths();
+     const double * elementByColumn = columnCopy->getElements();
+     CoinBigIndex start = columnStart[iColumn];
+     int n = columnLength[iColumn];
+     if (matrix->zeros()) {
+          CoinBigIndex end = start + n;
+          for (CoinBigIndex j = start; j < end; j++) {
+               if(!elementByColumn[j])
+                    n--;
+          }
+     }
+     // find block - could do binary search
+     int iBlock = CoinMin(n, numberBlocks_) - 1;
+     while (block_[iBlock].numberElements_ != n)
+          iBlock--;
+     blockStruct * block = block_ + iBlock;
+     int nel = block->numberElements_;
+     int * row = row_ + block->startElements_;
+     double * element = element_ + block->startElements_;
+     int * column = column_ + block->startIndices_;
+     assert (column[kA] == iColumn);
+     bool moveUp = (model->getColumnStatus(iColumn) == ClpSimplex::basic ||
+                    model->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+     int lastPrice = block->numberPrice_;
+     int kB;
+     if (moveUp) {
+          // May already be in correct place (e.g. fixed basic leaving basis)
+          if (kA >= lastPrice)
+               return;
+          kB = lastPrice - 1;
+          block->numberPrice_--;
+     } else {
+          assert (kA >= lastPrice);
+          kB = lastPrice;
+          block->numberPrice_++;
+     }
+     int jColumn = column[kB];
+     column[kA] = jColumn;
+     lookup[jColumn] = kA;
+     column[kB] = iColumn;
+     lookup[iColumn] = kB;
+     double * elementA = element + kB * nel;
+     int * rowA = row + kB * nel;
+     double * elementB = element + kA * nel;
+     int * rowB = row + kA * nel;
+     int i;
+     for (i = 0; i < nel; i++) {
+          int temp = rowA[i];
+          double tempE = elementA[i];
+          rowA[i] = rowB[i];
+          elementA[i] = elementB[i];
+          rowB[i] = temp;
+          elementB[i] = tempE;
+     }
+#ifndef NDEBUG
+     // check
+     for (i = 0; i < block->numberPrice_; i++) {
+          int iColumn = column[i];
+          if (iColumn != model->sequenceIn() && iColumn != model->sequenceOut())
+               assert (model->getColumnStatus(iColumn) != ClpSimplex::basic &&
+                       model->getColumnStatus(iColumn) != ClpSimplex::isFixed);
+          assert (lookup[iColumn] == i);
+     }
+     int numberInBlock = block->numberInBlock_;
+     for (; i < numberInBlock; i++) {
+          int iColumn = column[i];
+          if (iColumn != model->sequenceIn() && iColumn != model->sequenceOut())
+               assert (model->getColumnStatus(iColumn) == ClpSimplex::basic ||
+                       model->getColumnStatus(iColumn) == ClpSimplex::isFixed);
+          assert (lookup[iColumn] == i);
+     }
+#endif
+}
+/* Return <code>x * -1 * A in <code>z</code>.
+   Note - x packed and z will be packed mode
+   Squashes small elements and knows about ClpSimplex */
+void
+ClpPackedMatrix3::transposeTimes(const ClpSimplex * model,
+                                 const double * pi,
+                                 CoinIndexedVector * output) const
+{
+     int numberNonZero = 0;
+     int * index = output->getIndices();
+     double * array = output->denseVector();
+     double zeroTolerance = model->zeroTolerance();
+     double value = 0.0;
+     CoinBigIndex j;
+     int numberOdd = block_->startIndices_;
+     if (numberOdd) {
+          // A) as probably long may be worth unrolling
+          CoinBigIndex end = start_[1];
+          for (j = start_[0]; j < end; j++) {
+               int iRow = row_[j];
+               value += pi[iRow] * element_[j];
+          }
+          int iColumn;
+          // int jColumn=column_[0];
+
+          for (iColumn = 0; iColumn < numberOdd - 1; iColumn++) {
+               CoinBigIndex start = end;
+               end = start_[iColumn+2];
+               if (fabs(value) > zeroTolerance) {
+                    array[numberNonZero] = value;
+                    index[numberNonZero++] = column_[iColumn];
+                    //index[numberNonZero++]=jColumn;
+               }
+               // jColumn = column_[iColumn+1];
+               value = 0.0;
+               //if (model->getColumnStatus(jColumn)!=ClpSimplex::basic) {
+               for (j = start; j < end; j++) {
+                    int iRow = row_[j];
+                    value += pi[iRow] * element_[j];
+               }
+               //}
+          }
+          if (fabs(value) > zeroTolerance) {
+               array[numberNonZero] = value;
+               index[numberNonZero++] = column_[iColumn];
+               //index[numberNonZero++]=jColumn;
+          }
+     }
+     for (int iBlock = 0; iBlock < numberBlocks_; iBlock++) {
+          // B) Can sort so just do nonbasic (and nonfixed)
+          // C) Can do two at a time (if so put odd one into start_)
+          // D) can use switch
+          blockStruct * block = block_ + iBlock;
+          //int numberPrice = block->numberInBlock_;
+          int numberPrice = block->numberPrice_;
+          int nel = block->numberElements_;
+          int * row = row_ + block->startElements_;
+          double * element = element_ + block->startElements_;
+          int * column = column_ + block->startIndices_;
+#if 0
+          // two at a time
+          if ((numberPrice & 1) != 0) {
+               double value = 0.0;
+               int nel2 = nel;
+               for (; nel2; nel2--) {
+                    int iRow = *row++;
+                    value += pi[iRow] * (*element++);
+               }
+               if (fabs(value) > zeroTolerance) {
+                    array[numberNonZero] = value;
+                    index[numberNonZero++] = *column;
+               }
+               column++;
+          }
+          numberPrice = numberPrice >> 1;
+          switch ((nel % 2)) {
+               // 2 k +0
+          case 0:
+               for (; numberPrice; numberPrice--) {
+                    double value0 = 0.0;
+                    double value1 = 0.0;
+                    int nel2 = nel;
+                    for (; nel2; nel2--) {
+                         int iRow0 = *row;
+                         int iRow1 = *(row + nel);
+                         row++;
+                         double element0 = *element;
+                         double element1 = *(element + nel);
+                         element++;
+                         value0 += pi[iRow0] * element0;
+                         value1 += pi[iRow1] * element1;
+                    }
+                    row += nel;
+                    element += nel;
+                    if (fabs(value0) > zeroTolerance) {
+                         array[numberNonZero] = value0;
+                         index[numberNonZero++] = *column;
+                    }
+                    column++;
+                    if (fabs(value1) > zeroTolerance) {
+                         array[numberNonZero] = value1;
+                         index[numberNonZero++] = *column;
+                    }
+                    column++;
+               }
+               break;
+               // 2 k +1
+          case 1:
+               for (; numberPrice; numberPrice--) {
+                    double value0;
+                    double value1;
+                    int nel2 = nel - 1;
+                    {
+                         int iRow0 = row[0];
+                         int iRow1 = row[nel];
+                         double pi0 = pi[iRow0];
+                         double pi1 = pi[iRow1];
+                         value0 = pi0 * element[0];
+                         value1 = pi1 * element[nel];
+                         row++;
+                         element++;
+                    }
+                    for (; nel2; nel2--) {
+                         int iRow0 = *row;
+                         int iRow1 = *(row + nel);
+                         row++;
+                         double element0 = *element;
+                         double element1 = *(element + nel);
+                         element++;
+                         value0 += pi[iRow0] * element0;
+                         value1 += pi[iRow1] * element1;
+                    }
+                    row += nel;
+                    element += nel;
+                    if (fabs(value0) > zeroTolerance) {
+                         array[numberNonZero] = value0;
+                         index[numberNonZero++] = *column;
+                    }
+                    column++;
+                    if (fabs(value1) > zeroTolerance) {
+                         array[numberNonZero] = value1;
+                         index[numberNonZero++] = *column;
+                    }
+                    column++;
+               }
+               break;
+          }
+#else
+          for (; numberPrice; numberPrice--) {
+               double value = 0.0;
+               int nel2 = nel;
+               for (; nel2; nel2--) {
+                    int iRow = *row++;
+                    value += pi[iRow] * (*element++);
+               }
+               if (fabs(value) > zeroTolerance) {
+                    array[numberNonZero] = value;
+                    index[numberNonZero++] = *column;
+               }
+               column++;
+          }
+#endif
+     }
+     output->setNumElements(numberNonZero);
+}
+// Updates two arrays for steepest
+void
+ClpPackedMatrix3::transposeTimes2(const ClpSimplex * model,
+                                  const double * pi, CoinIndexedVector * output,
+                                  const double * piWeight,
+                                  double referenceIn, double devex,
+                                  // Array for exact devex to say what is in reference framework
+                                  unsigned int * reference,
+                                  double * weights, double scaleFactor)
+{
+     int numberNonZero = 0;
+     int * index = output->getIndices();
+     double * array = output->denseVector();
+     double zeroTolerance = model->zeroTolerance();
+     double value = 0.0;
+     bool killDjs = (scaleFactor == 0.0);
+     if (!scaleFactor)
+          scaleFactor = 1.0;
+     int numberOdd = block_->startIndices_;
+     int iColumn;
+     CoinBigIndex end = start_[0];
+     for (iColumn = 0; iColumn < numberOdd; iColumn++) {
+          CoinBigIndex start = end;
+          CoinBigIndex j;
+          int jColumn = column_[iColumn];
+          end = start_[iColumn+1];
+          value = 0.0;
+          if (model->getColumnStatus(jColumn) != ClpSimplex::basic) {
+               for (j = start; j < end; j++) {
+                    int iRow = row_[j];
+                    value -= pi[iRow] * element_[j];
+               }
+               if (fabs(value) > zeroTolerance) {
+                    // and do other array
+                    double modification = 0.0;
+                    for (j = start; j < end; j++) {
+                         int iRow = row_[j];
+                         modification += piWeight[iRow] * element_[j];
+                    }
+                    double thisWeight = weights[jColumn];
+                    double pivot = value * scaleFactor;
+                    double pivotSquared = pivot * pivot;
+                    thisWeight += pivotSquared * devex + pivot * modification;
+                    if (thisWeight < DEVEX_TRY_NORM) {
+                         if (referenceIn < 0.0) {
+                              // steepest
+                              thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                         } else {
+                              // exact
+                              thisWeight = referenceIn * pivotSquared;
+                              if (reference(jColumn))
+                                   thisWeight += 1.0;
+                              thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                         }
+                    }
+                    weights[jColumn] = thisWeight;
+                    if (!killDjs) {
+                         array[numberNonZero] = value;
+                         index[numberNonZero++] = jColumn;
+                    }
+               }
+          }
+     }
+     for (int iBlock = 0; iBlock < numberBlocks_; iBlock++) {
+          // B) Can sort so just do nonbasic (and nonfixed)
+          // C) Can do two at a time (if so put odd one into start_)
+          // D) can use switch
+          blockStruct * block = block_ + iBlock;
+          //int numberPrice = block->numberInBlock_;
+          int numberPrice = block->numberPrice_;
+          int nel = block->numberElements_;
+          int * row = row_ + block->startElements_;
+          double * element = element_ + block->startElements_;
+          int * column = column_ + block->startIndices_;
+          for (; numberPrice; numberPrice--) {
+               double value = 0.0;
+               int nel2 = nel;
+               for (; nel2; nel2--) {
+                    int iRow = *row++;
+                    value -= pi[iRow] * (*element++);
+               }
+               if (fabs(value) > zeroTolerance) {
+                    int jColumn = *column;
+                    // back to beginning
+                    row -= nel;
+                    element -= nel;
+                    // and do other array
+                    double modification = 0.0;
+                    nel2 = nel;
+                    for (; nel2; nel2--) {
+                         int iRow = *row++;
+                         modification += piWeight[iRow] * (*element++);
+                    }
+                    double thisWeight = weights[jColumn];
+                    double pivot = value * scaleFactor;
+                    double pivotSquared = pivot * pivot;
+                    thisWeight += pivotSquared * devex + pivot * modification;
+                    if (thisWeight < DEVEX_TRY_NORM) {
+                         if (referenceIn < 0.0) {
+                              // steepest
+                              thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                         } else {
+                              // exact
+                              thisWeight = referenceIn * pivotSquared;
+                              if (reference(jColumn))
+                                   thisWeight += 1.0;
+                              thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                         }
+                    }
+                    weights[jColumn] = thisWeight;
+                    if (!killDjs) {
+                         array[numberNonZero] = value;
+                         index[numberNonZero++] = jColumn;
+                    }
+               }
+               column++;
+          }
+     }
+     output->setNumElements(numberNonZero);
+     output->setPackedMode(true);
+}
+#if COIN_LONG_WORK
+// For long double versions
+void
+ClpPackedMatrix::times(CoinWorkDouble scalar,
+                       const CoinWorkDouble * x, CoinWorkDouble * y) const
+{
+     int iRow, iColumn;
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const double * elementByColumn = matrix_->getElements();
+     //memset(y,0,matrix_->getNumRows()*sizeof(double));
+     assert (((flags_ & 2) != 0) == matrix_->hasGaps());
+     if (!(flags_ & 2)) {
+          for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+               CoinBigIndex j;
+               CoinWorkDouble value = x[iColumn];
+               if (value) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = columnStart[iColumn+1];
+                    value *= scalar;
+                    for (j = start; j < end; j++) {
+                         iRow = row[j];
+                         y[iRow] += value * elementByColumn[j];
+                    }
+               }
+          }
+     } else {
+          const int * columnLength = matrix_->getVectorLengths();
+          for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+               CoinBigIndex j;
+               CoinWorkDouble value = x[iColumn];
+               if (value) {
+                    CoinBigIndex start = columnStart[iColumn];
+                    CoinBigIndex end = start + columnLength[iColumn];
+                    value *= scalar;
+                    for (j = start; j < end; j++) {
+                         iRow = row[j];
+                         y[iRow] += value * elementByColumn[j];
+                    }
+               }
+          }
+     }
+}
+void
+ClpPackedMatrix::transposeTimes(CoinWorkDouble scalar,
+                                const CoinWorkDouble * x, CoinWorkDouble * y) const
+{
+     int iColumn;
+     // get matrix data pointers
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const double * elementByColumn = matrix_->getElements();
+     if (!(flags_ & 2)) {
+          if (scalar == -1.0) {
+               CoinBigIndex start = columnStart[0];
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    CoinBigIndex j;
+                    CoinBigIndex next = columnStart[iColumn+1];
+                    CoinWorkDouble value = y[iColumn];
+                    for (j = start; j < next; j++) {
+                         int jRow = row[j];
+                         value -= x[jRow] * elementByColumn[j];
+                    }
+                    start = next;
+                    y[iColumn] = value;
+               }
+          } else {
+               CoinBigIndex start = columnStart[0];
+               for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+                    CoinBigIndex j;
+                    CoinBigIndex next = columnStart[iColumn+1];
+                    CoinWorkDouble value = 0.0;
+                    for (j = start; j < next; j++) {
+                         int jRow = row[j];
+                         value += x[jRow] * elementByColumn[j];
+                    }
+                    start = next;
+                    y[iColumn] += value * scalar;
+               }
+          }
+     } else {
+          const int * columnLength = matrix_->getVectorLengths();
+          for (iColumn = 0; iColumn < numberActiveColumns_; iColumn++) {
+               CoinBigIndex j;
+               CoinWorkDouble value = 0.0;
+               CoinBigIndex start = columnStart[iColumn];
+               CoinBigIndex end = start + columnLength[iColumn];
+               for (j = start; j < end; j++) {
+                    int jRow = row[j];
+                    value += x[jRow] * elementByColumn[j];
+               }
+               y[iColumn] += value * scalar;
+          }
+     }
+}
+#endif
+#ifdef CLP_ALL_ONE_FILE
+#undef reference
+#endif
diff --git a/cbits/coin/ClpPackedMatrix.hpp b/cbits/coin/ClpPackedMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPackedMatrix.hpp
@@ -0,0 +1,647 @@
+/* $Id: ClpPackedMatrix.hpp 1836 2011-12-15 20:22:39Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpPackedMatrix_H
+#define ClpPackedMatrix_H
+
+#include "CoinPragma.hpp"
+
+#include "ClpMatrixBase.hpp"
+
+// Compilers can produce better code if they know about __restrict
+#ifndef COIN_RESTRICT
+#ifdef COIN_USE_RESTRICT
+#define COIN_RESTRICT __restrict
+#else
+#define COIN_RESTRICT
+#endif
+#endif
+
+/** This implements CoinPackedMatrix as derived from ClpMatrixBase.
+
+    It adds a few methods that know about model as well as matrix
+
+    For details see CoinPackedMatrix */
+
+class ClpPackedMatrix2;
+class ClpPackedMatrix3;
+class ClpPackedMatrix : public ClpMatrixBase {
+
+public:
+     /**@name Useful methods */
+     //@{
+     /// Return a complete CoinPackedMatrix
+     virtual CoinPackedMatrix * getPackedMatrix() const {
+          return matrix_;
+     }
+     /** Whether the packed matrix is column major ordered or not. */
+     virtual bool isColOrdered() const {
+          return matrix_->isColOrdered();
+     }
+     /** Number of entries in the packed matrix. */
+     virtual  CoinBigIndex getNumElements() const {
+          return matrix_->getNumElements();
+     }
+     /** Number of columns. */
+     virtual int getNumCols() const {
+          return matrix_->getNumCols();
+     }
+     /** Number of rows. */
+     virtual int getNumRows() const {
+          return matrix_->getNumRows();
+     }
+
+     /** A vector containing the elements in the packed matrix. Note that there
+         might be gaps in this list, entries that do not belong to any
+         major-dimension vector. To get the actual elements one should look at
+         this vector together with vectorStarts and vectorLengths. */
+     virtual const double * getElements() const {
+          return matrix_->getElements();
+     }
+     /// Mutable elements
+     inline double * getMutableElements() const {
+          return matrix_->getMutableElements();
+     }
+     /** A vector containing the minor indices of the elements in the packed
+          matrix. Note that there might be gaps in this list, entries that do not
+          belong to any major-dimension vector. To get the actual elements one
+          should look at this vector together with vectorStarts and
+          vectorLengths. */
+     virtual const int * getIndices() const {
+          return matrix_->getIndices();
+     }
+
+     virtual const CoinBigIndex * getVectorStarts() const {
+          return matrix_->getVectorStarts();
+     }
+     /** The lengths of the major-dimension vectors. */
+     virtual const int * getVectorLengths() const {
+          return matrix_->getVectorLengths();
+     }
+     /** The length of a single major-dimension vector. */
+     virtual int getVectorLength(int index) const {
+          return matrix_->getVectorSize(index);
+     }
+
+     /** Delete the columns whose indices are listed in <code>indDel</code>. */
+     virtual void deleteCols(const int numDel, const int * indDel);
+     /** Delete the rows whose indices are listed in <code>indDel</code>. */
+     virtual void deleteRows(const int numDel, const int * indDel);
+#ifndef CLP_NO_VECTOR
+     /// Append Columns
+     virtual void appendCols(int number, const CoinPackedVectorBase * const * columns);
+     /// Append Rows
+     virtual void appendRows(int number, const CoinPackedVectorBase * const * rows);
+#endif
+     /** Append a set of rows/columns to the end of the matrix. Returns number of errors
+         i.e. if any of the new rows/columns contain an index that's larger than the
+         number of columns-1/rows-1 (if numberOther>0) or duplicates
+         If 0 then rows, 1 if columns */
+     virtual int appendMatrix(int number, int type,
+                              const CoinBigIndex * starts, const int * index,
+                              const double * element, int numberOther = -1);
+     /** Replace the elements of a vector.  The indices remain the same.
+         This is only needed if scaling and a row copy is used.
+         At most the number specified will be replaced.
+         The index is between 0 and major dimension of matrix */
+     virtual void replaceVector(const int index,
+                                const int numReplace, const double * newElements) {
+          matrix_->replaceVector(index, numReplace, newElements);
+     }
+     /** Modify one element of packed matrix.  An element may be added.
+         This works for either ordering If the new element is zero it will be
+         deleted unless keepZero true */
+     virtual void modifyCoefficient(int row, int column, double newElement,
+                                    bool keepZero = false) {
+          matrix_->modifyCoefficient(row, column, newElement, keepZero);
+     }
+     /** Returns a new matrix in reverse order without gaps */
+     virtual ClpMatrixBase * reverseOrderedCopy() const;
+     /// Returns number of elements in column part of basis
+     virtual CoinBigIndex countBasis(const int * whichColumn,
+                                     int & numberColumnBasic);
+     /// Fills in column part of basis
+     virtual void fillBasis(ClpSimplex * model,
+                            const int * whichColumn,
+                            int & numberColumnBasic,
+                            int * row, int * start,
+                            int * rowCount, int * columnCount,
+                            CoinFactorizationDouble * element);
+     /** Creates scales for column copy (rowCopy in model may be modified)
+         returns non-zero if no scaling done */
+     virtual int scale(ClpModel * model, const ClpSimplex * baseModel = NULL) const ;
+     /** Scales rowCopy if column copy scaled
+         Only called if scales already exist */
+     virtual void scaleRowCopy(ClpModel * model) const ;
+     /// Creates scaled column copy if scales exist
+     void createScaledMatrix(ClpSimplex * model) const;
+     /** Realy really scales column copy
+         Only called if scales already exist.
+         Up to user ro delete */
+     virtual ClpMatrixBase * scaledColumnCopy(ClpModel * model) const ;
+     /** Checks if all elements are in valid range.  Can just
+         return true if you are not paranoid.  For Clp I will
+         probably expect no zeros.  Code can modify matrix to get rid of
+         small elements.
+         check bits (can be turned off to save time) :
+         1 - check if matrix has gaps
+         2 - check if zero elements
+         4 - check and compress duplicates
+         8 - report on large and small
+     */
+     virtual bool allElementsInRange(ClpModel * model,
+                                     double smallest, double largest,
+                                     int check = 15);
+     /** Returns largest and smallest elements of both signs.
+         Largest refers to largest absolute value.
+     */
+     virtual void rangeOfElements(double & smallestNegative, double & largestNegative,
+                                  double & smallestPositive, double & largestPositive);
+
+     /** Unpacks a column into an CoinIndexedvector
+      */
+     virtual void unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                         int column) const ;
+     /** Unpacks a column into an CoinIndexedvector
+      ** in packed foramt
+         Note that model is NOT const.  Bounds and objective could
+         be modified if doing column generation (just for this variable) */
+     virtual void unpackPacked(ClpSimplex * model,
+                               CoinIndexedVector * rowArray,
+                               int column) const;
+     /** Adds multiple of a column into an CoinIndexedvector
+         You can use quickAdd to add to vector */
+     virtual void add(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                      int column, double multiplier) const ;
+     /** Adds multiple of a column into an array */
+     virtual void add(const ClpSimplex * model, double * array,
+                      int column, double multiplier) const;
+     /// Allow any parts of a created CoinPackedMatrix to be deleted
+     virtual void releasePackedMatrix() const { }
+     /** Given positive integer weights for each row fills in sum of weights
+         for each column (and slack).
+         Returns weights vector
+     */
+     virtual CoinBigIndex * dubiousWeights(const ClpSimplex * model, int * inputWeights) const;
+     /// Says whether it can do partial pricing
+     virtual bool canDoPartialPricing() const;
+     /// Partial pricing
+     virtual void partialPricing(ClpSimplex * model, double start, double end,
+                                 int & bestSequence, int & numberWanted);
+     /// makes sure active columns correct
+     virtual int refresh(ClpSimplex * model);
+     // Really scale matrix
+     virtual void reallyScale(const double * rowScale, const double * columnScale);
+     /** Set the dimensions of the matrix. In effect, append new empty
+         columns/rows to the matrix. A negative number for either dimension
+         means that that dimension doesn't change. Otherwise the new dimensions
+         MUST be at least as large as the current ones otherwise an exception
+         is thrown. */
+     virtual void setDimensions(int numrows, int numcols);
+     //@}
+
+     /**@name Matrix times vector methods */
+     //@{
+     /** Return <code>y + A * scalar *x</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numColumns()</code>
+         @pre <code>y</code> must be of size <code>numRows()</code> */
+     virtual void times(double scalar,
+                        const double * x, double * y) const;
+     /// And for scaling
+     virtual void times(double scalar,
+                        const double * x, double * y,
+                        const double * rowScale,
+                        const double * columnScale) const;
+     /** Return <code>y + x * scalar * A</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numRows()</code>
+         @pre <code>y</code> must be of size <code>numColumns()</code> */
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y) const;
+     /// And for scaling
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y,
+                                 const double * rowScale,
+                                 const double * columnScale,
+                                 double * spare = NULL) const;
+     /** Return <code>y - pi * A</code> in <code>y</code>.
+         @pre <code>pi</code> must be of size <code>numRows()</code>
+         @pre <code>y</code> must be of size <code>numColumns()</code>
+     This just does subset (but puts in correct place in y) */
+     void transposeTimesSubset( int number,
+                                const int * which,
+                                const double * pi, double * y,
+                                const double * rowScale,
+                                const double * columnScale,
+                                double * spare = NULL) const;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Can use y as temporary array (will be empty at end)
+     Note - If x packed mode - then z packed mode
+     Squashes small elements and knows about ClpSimplex */
+     virtual void transposeTimes(const ClpSimplex * model, double scalar,
+                                 const CoinIndexedVector * x,
+                                 CoinIndexedVector * y,
+                                 CoinIndexedVector * z) const;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Note - If x packed mode - then z packed mode
+     This does by column and knows no gaps
+     Squashes small elements and knows about ClpSimplex */
+     void transposeTimesByColumn(const ClpSimplex * model, double scalar,
+                                 const CoinIndexedVector * x,
+                                 CoinIndexedVector * y,
+                                 CoinIndexedVector * z) const;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Can use y as temporary array (will be empty at end)
+     Note - If x packed mode - then z packed mode
+     Squashes small elements and knows about ClpSimplex.
+     This version uses row copy*/
+     virtual void transposeTimesByRow(const ClpSimplex * model, double scalar,
+                                      const CoinIndexedVector * x,
+                                      CoinIndexedVector * y,
+                                      CoinIndexedVector * z) const;
+     /** Return <code>x *A</code> in <code>z</code> but
+     just for indices in y.
+     Note - z always packed mode */
+     virtual void subsetTransposeTimes(const ClpSimplex * model,
+                                       const CoinIndexedVector * x,
+                                       const CoinIndexedVector * y,
+                                       CoinIndexedVector * z) const;
+     /** Returns true if can combine transposeTimes and subsetTransposeTimes
+         and if it would be faster */
+     virtual bool canCombine(const ClpSimplex * model,
+                             const CoinIndexedVector * pi) const;
+     /// Updates two arrays for steepest
+     virtual void transposeTimes2(const ClpSimplex * model,
+                                  const CoinIndexedVector * pi1, CoinIndexedVector * dj1,
+                                  const CoinIndexedVector * pi2,
+                                  CoinIndexedVector * spare,
+                                  double referenceIn, double devex,
+                                  // Array for exact devex to say what is in reference framework
+                                  unsigned int * reference,
+                                  double * weights, double scaleFactor);
+     /// Updates second array for steepest and does devex weights
+     virtual void subsetTimes2(const ClpSimplex * model,
+                               CoinIndexedVector * dj1,
+                               const CoinIndexedVector * pi2, CoinIndexedVector * dj2,
+                               double referenceIn, double devex,
+                               // Array for exact devex to say what is in reference framework
+                               unsigned int * reference,
+                               double * weights, double scaleFactor);
+     /// Sets up an effective RHS
+     void useEffectiveRhs(ClpSimplex * model);
+#if COIN_LONG_WORK
+     // For long double versions
+     virtual void times(CoinWorkDouble scalar,
+                        const CoinWorkDouble * x, CoinWorkDouble * y) const ;
+     virtual void transposeTimes(CoinWorkDouble scalar,
+                                 const CoinWorkDouble * x, CoinWorkDouble * y) const ;
+#endif
+//@}
+
+     /**@name Other */
+     //@{
+     /// Returns CoinPackedMatrix (non const)
+     inline CoinPackedMatrix * matrix() const {
+          return matrix_;
+     }
+     /** Just sets matrix_ to NULL so it can be used elsewhere.
+         used in GUB
+     */
+     inline void setMatrixNull() {
+          matrix_ = NULL;
+     }
+     /// Say we want special column copy
+     inline void makeSpecialColumnCopy() {
+          flags_ |= 16;
+     }
+     /// Say we don't want special column copy
+     void releaseSpecialColumnCopy();
+     /// Are there zeros?
+     inline bool zeros() const {
+          return ((flags_ & 1) != 0);
+     }
+     /// Do we want special column copy
+     inline bool wantsSpecialColumnCopy() const {
+          return ((flags_ & 16) != 0);
+     }
+     /// Flags
+     inline int flags() const {
+          return flags_;
+     }
+     /// Sets flags_ correctly
+     inline void checkGaps() {
+          flags_ = (matrix_->hasGaps()) ? (flags_ | 2) : (flags_ & (~2));
+     }
+     /// number of active columns (normally same as number of columns)
+     inline int numberActiveColumns() const
+     { return numberActiveColumns_;}
+     /// Set number of active columns (normally same as number of columns)
+     inline void setNumberActiveColumns(int value)
+     { numberActiveColumns_ = value;}
+     //@}
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpPackedMatrix();
+     /** Destructor */
+     virtual ~ClpPackedMatrix();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpPackedMatrix(const ClpPackedMatrix&);
+     /** The copy constructor from an CoinPackedMatrix. */
+     ClpPackedMatrix(const CoinPackedMatrix&);
+     /** Subset constructor (without gaps).  Duplicates are allowed
+         and order is as given */
+     ClpPackedMatrix (const ClpPackedMatrix & wholeModel,
+                      int numberRows, const int * whichRows,
+                      int numberColumns, const int * whichColumns);
+     ClpPackedMatrix (const CoinPackedMatrix & wholeModel,
+                      int numberRows, const int * whichRows,
+                      int numberColumns, const int * whichColumns);
+
+     /** This takes over ownership (for space reasons) */
+     ClpPackedMatrix(CoinPackedMatrix * matrix);
+
+     ClpPackedMatrix& operator=(const ClpPackedMatrix&);
+     /// Clone
+     virtual ClpMatrixBase * clone() const ;
+     /// Copy contents - resizing if necessary - otherwise re-use memory
+     virtual void copy(const ClpPackedMatrix * from);
+     /** Subset clone (without gaps).  Duplicates are allowed
+         and order is as given */
+     virtual ClpMatrixBase * subsetClone (
+          int numberRows, const int * whichRows,
+          int numberColumns, const int * whichColumns) const ;
+     /// make special row copy
+     void specialRowCopy(ClpSimplex * model, const ClpMatrixBase * rowCopy);
+     /// make special column copy
+     void specialColumnCopy(ClpSimplex * model);
+     /// Correct sequence in and out to give true value
+     virtual void correctSequence(const ClpSimplex * model, int & sequenceIn, int & sequenceOut) ;
+     //@}
+private:
+     /// Meat of transposeTimes by column when not scaled
+     int gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
+                                      int * COIN_RESTRICT index,
+                                      double * COIN_RESTRICT array,
+                                      const double tolerance) const;
+     /// Meat of transposeTimes by column when scaled
+     int gutsOfTransposeTimesScaled(const double * COIN_RESTRICT pi,
+                                    const double * COIN_RESTRICT columnScale,
+                                    int * COIN_RESTRICT index,
+                                    double * COIN_RESTRICT array,
+                                    const double tolerance) const;
+     /// Meat of transposeTimes by column when not scaled and skipping
+     int gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
+                                      int * COIN_RESTRICT index,
+                                      double * COIN_RESTRICT array,
+                                      const unsigned char * status,
+                                      const double tolerance) const;
+     /** Meat of transposeTimes by column when not scaled and skipping
+         and doing part of dualColumn */
+     int gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
+                                      int * COIN_RESTRICT index,
+                                      double * COIN_RESTRICT array,
+                                      const unsigned char * status,
+                                      int * COIN_RESTRICT spareIndex,
+                                      double * COIN_RESTRICT spareArray,
+                                      const double * COIN_RESTRICT reducedCost,
+                                      double & upperTheta,
+                                      double & bestPossible,
+                                      double acceptablePivot,
+                                      double dualTolerance,
+                                      int & numberRemaining,
+                                      const double zeroTolerance) const;
+     /// Meat of transposeTimes by column when scaled and skipping
+     int gutsOfTransposeTimesScaled(const double * COIN_RESTRICT pi,
+                                    const double * COIN_RESTRICT columnScale,
+                                    int * COIN_RESTRICT index,
+                                    double * COIN_RESTRICT array,
+                                    const unsigned char * status,
+                                    const double tolerance) const;
+     /// Meat of transposeTimes by row n > K if packed - returns number nonzero
+     int gutsOfTransposeTimesByRowGEK(const CoinIndexedVector * COIN_RESTRICT piVector,
+                                      int * COIN_RESTRICT index,
+                                      double * COIN_RESTRICT output,
+                                      int numberColumns,
+                                      const double tolerance,
+                                      const double scalar) const;
+     /// Meat of transposeTimes by row n > 2 if packed - returns number nonzero
+     int gutsOfTransposeTimesByRowGE3(const CoinIndexedVector * COIN_RESTRICT piVector,
+                                      int * COIN_RESTRICT index,
+                                      double * COIN_RESTRICT output,
+                                      double * COIN_RESTRICT array2,
+                                      const double tolerance,
+                                      const double scalar) const;
+     /// Meat of transposeTimes by row n > 2 if packed - returns number nonzero
+     int gutsOfTransposeTimesByRowGE3a(const CoinIndexedVector * COIN_RESTRICT piVector,
+                                      int * COIN_RESTRICT index,
+                                      double * COIN_RESTRICT output,
+                                      int * COIN_RESTRICT lookup,
+                                      char * COIN_RESTRICT marked,
+                                      const double tolerance,
+                                      const double scalar) const;
+     /// Meat of transposeTimes by row n == 2 if packed
+     void gutsOfTransposeTimesByRowEQ2(const CoinIndexedVector * piVector, CoinIndexedVector * output,
+                                       CoinIndexedVector * spareVector, const double tolerance, const double scalar) const;
+     /// Meat of transposeTimes by row n == 1 if packed
+     void gutsOfTransposeTimesByRowEQ1(const CoinIndexedVector * piVector, CoinIndexedVector * output,
+                                       const double tolerance, const double scalar) const;
+     /// Gets rid of special copies
+     void clearCopies();
+
+
+protected:
+     /// Check validity
+     void checkFlags(int type) const;
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Data
+     CoinPackedMatrix * matrix_;
+     /// number of active columns (normally same as number of columns)
+     int numberActiveColumns_;
+     /** Flags -
+         1 - has zero elements
+         2 - has gaps
+         4 - has special row copy
+         8 - has special column copy
+         16 - wants special column copy
+     */
+     mutable int flags_;
+     /// Special row copy
+     ClpPackedMatrix2 * rowCopy_;
+     /// Special column copy
+     ClpPackedMatrix3 * columnCopy_;
+     //@}
+};
+#ifdef THREAD
+#include <pthread.h>
+typedef struct {
+     double acceptablePivot;
+     const ClpSimplex * model;
+     double * spare;
+     int * spareIndex;
+     double * arrayTemp;
+     int * indexTemp;
+     int * numberInPtr;
+     double * bestPossiblePtr;
+     double * upperThetaPtr;
+     int * posFreePtr;
+     double * freePivotPtr;
+     int * numberOutPtr;
+     const unsigned short * count;
+     const double * pi;
+     const CoinBigIndex * rowStart;
+     const double * element;
+     const unsigned short * column;
+     int offset;
+     int numberInRowArray;
+     int numberLook;
+} dualColumn0Struct;
+#endif
+class ClpPackedMatrix2 {
+
+public:
+     /**@name Useful methods */
+     //@{
+     /** Return <code>x * -1 * A in <code>z</code>.
+     Note - x packed and z will be packed mode
+     Squashes small elements and knows about ClpSimplex */
+     void transposeTimes(const ClpSimplex * model,
+                         const CoinPackedMatrix * rowCopy,
+                         const CoinIndexedVector * x,
+                         CoinIndexedVector * spareArray,
+                         CoinIndexedVector * z) const;
+     /// Returns true if copy has useful information
+     inline bool usefulInfo() const {
+          return rowStart_ != NULL;
+     }
+     //@}
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpPackedMatrix2();
+     /** Constructor from copy. */
+     ClpPackedMatrix2(ClpSimplex * model, const CoinPackedMatrix * rowCopy);
+     /** Destructor */
+     virtual ~ClpPackedMatrix2();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpPackedMatrix2(const ClpPackedMatrix2&);
+     ClpPackedMatrix2& operator=(const ClpPackedMatrix2&);
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Number of blocks
+     int numberBlocks_;
+     /// Number of rows
+     int numberRows_;
+     /// Column offset for each block (plus one at end)
+     int * offset_;
+     /// Counts of elements in each part of row
+     mutable unsigned short * count_;
+     /// Row starts
+     mutable CoinBigIndex * rowStart_;
+     /// columns within block
+     unsigned short * column_;
+     /// work arrays
+     double * work_;
+#ifdef THREAD
+     pthread_t * threadId_;
+     dualColumn0Struct * info_;
+#endif
+     //@}
+};
+typedef struct {
+     CoinBigIndex startElements_; // point to data
+     int startIndices_; // point to column_
+     int numberInBlock_;
+     int numberPrice_; // at beginning
+     int numberElements_; // number elements per column
+} blockStruct;
+class ClpPackedMatrix3 {
+
+public:
+     /**@name Useful methods */
+     //@{
+     /** Return <code>x * -1 * A in <code>z</code>.
+     Note - x packed and z will be packed mode
+     Squashes small elements and knows about ClpSimplex */
+     void transposeTimes(const ClpSimplex * model,
+                         const double * pi,
+                         CoinIndexedVector * output) const;
+     /// Updates two arrays for steepest
+     void transposeTimes2(const ClpSimplex * model,
+                          const double * pi, CoinIndexedVector * dj1,
+                          const double * piWeight,
+                          double referenceIn, double devex,
+                          // Array for exact devex to say what is in reference framework
+                          unsigned int * reference,
+                          double * weights, double scaleFactor);
+     //@}
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpPackedMatrix3();
+     /** Constructor from copy. */
+     ClpPackedMatrix3(ClpSimplex * model, const CoinPackedMatrix * columnCopy);
+     /** Destructor */
+     virtual ~ClpPackedMatrix3();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpPackedMatrix3(const ClpPackedMatrix3&);
+     ClpPackedMatrix3& operator=(const ClpPackedMatrix3&);
+     //@}
+     /**@name Sort methods */
+     //@{
+     /** Sort blocks */
+     void sortBlocks(const ClpSimplex * model);
+     /// Swap one variable
+     void swapOne(const ClpSimplex * model, const ClpPackedMatrix * matrix,
+                  int iColumn);
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Number of blocks
+     int numberBlocks_;
+     /// Number of columns
+     int numberColumns_;
+     /// Column indices and reverse lookup (within block)
+     int * column_;
+     /// Starts for odd/long vectors
+     CoinBigIndex * start_;
+     /// Rows
+     int * row_;
+     /// Elements
+     double * element_;
+     /// Blocks (ordinary start at 0 and go to first block)
+     blockStruct * block_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpParameters.hpp b/cbits/coin/ClpParameters.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpParameters.hpp
@@ -0,0 +1,124 @@
+/* $Id: ClpParameters.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2000, 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef _ClpParameters_H
+#define _ClpParameters_H
+
+/** This is where to put any useful stuff.
+
+*/
+enum ClpIntParam {
+     /** The maximum number of iterations Clp can execute in the simplex methods
+      */
+     ClpMaxNumIteration = 0,
+     /** The maximum number of iterations Clp can execute in hotstart before
+         terminating */
+     ClpMaxNumIterationHotStart,
+     /** The name discipline; specifies how the solver will handle row and
+         column names.
+       - 0: Auto names: Names cannot be set by the client. Names of the form
+        Rnnnnnnn or Cnnnnnnn are generated on demand when a name for a
+        specific row or column is requested; nnnnnnn is derived from the row
+        or column index. Requests for a vector of names return a vector with
+        zero entries.
+       - 1: Lazy names: Names supplied by the client are retained. Names of the
+        form Rnnnnnnn or Cnnnnnnn are generated on demand if no name has been
+        supplied by the client. Requests for a vector of names return a
+        vector sized to the largest index of a name supplied by the client;
+        some entries in the vector may be null strings.
+       - 2: Full names: Names supplied by the client are retained. Names of the
+        form Rnnnnnnn or Cnnnnnnn are generated on demand if no name has been
+        supplied by the client. Requests for a vector of names return a
+        vector sized to match the constraint system, and all entries will
+        contain either the name specified by the client or a generated name.
+     */
+     ClpNameDiscipline,
+     /** Just a marker, so that we can allocate a static sized array to store
+         parameters. */
+     ClpLastIntParam
+};
+
+enum ClpDblParam {
+     /** Set Dual objective limit. This is to be used as a termination criteria
+         in methods where the dual objective monotonically changes (dual
+         simplex). */
+     ClpDualObjectiveLimit,
+     /** Primal objective limit. This is to be used as a termination
+         criteria in methods where the primal objective monotonically changes
+         (e.g., primal simplex) */
+     ClpPrimalObjectiveLimit,
+     /** The maximum amount the dual constraints can be violated and still be
+         considered feasible. */
+     ClpDualTolerance,
+     /** The maximum amount the primal constraints can be violated and still be
+         considered feasible. */
+     ClpPrimalTolerance,
+     /** Objective function constant. This the value of the constant term in
+         the objective function. */
+     ClpObjOffset,
+     /// Maximum time in seconds - after this action is as max iterations
+     ClpMaxSeconds,
+     /// Tolerance to use in presolve
+     ClpPresolveTolerance,
+     /** Just a marker, so that we can allocate a static sized array to store
+         parameters. */
+     ClpLastDblParam
+};
+
+
+enum ClpStrParam {
+     /** Name of the problem. This is the found on the Name card of
+         an mps file. */
+     ClpProbName = 0,
+     /** Just a marker, so that we can allocate a static sized array to store
+         parameters. */
+     ClpLastStrParam
+};
+
+/// Copy (I don't like complexity of Coin version)
+template <class T> inline void
+ClpDisjointCopyN( const T * array, const int size, T * newArray)
+{
+     memcpy(reinterpret_cast<void *> (newArray), array, size * sizeof(T));
+}
+/// And set
+template <class T> inline void
+ClpFillN( T * array, const int size, T value)
+{
+     int i;
+     for (i = 0; i < size; i++)
+          array[i] = value;
+}
+/// This returns a non const array filled with input from scalar or actual array
+template <class T> inline T*
+ClpCopyOfArray( const T * array, const int size, T value)
+{
+     T * arrayNew = new T[size];
+     if (array)
+          ClpDisjointCopyN(array, size, arrayNew);
+     else
+          ClpFillN ( arrayNew, size, value);
+     return arrayNew;
+}
+
+/// This returns a non const array filled with actual array (or NULL)
+template <class T> inline T*
+ClpCopyOfArray( const T * array, const int size)
+{
+     if (array) {
+          T * arrayNew = new T[size];
+          ClpDisjointCopyN(array, size, arrayNew);
+          return arrayNew;
+     } else {
+          return NULL;
+     }
+}
+/// For a structure to be used by trusted code
+typedef struct {
+     int typeStruct; // allocated as 1,2 etc
+     int typeCall;
+     void * data;
+} ClpTrustedData;
+#endif
diff --git a/cbits/coin/ClpPdco.cpp b/cbits/coin/ClpPdco.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPdco.cpp
@@ -0,0 +1,1014 @@
+/* $Id: ClpPdco.cpp 1941 2013-04-10 16:52:27Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/* Pdco algorithm
+
+Method
+
+
+*/
+
+
+
+#include "CoinPragma.hpp"
+
+#include <math.h>
+
+#include "CoinDenseVector.hpp"
+#include "ClpPdco.hpp"
+#include "ClpPdcoBase.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "ClpLsqr.hpp"
+#include "CoinTime.hpp"
+#include "ClpMessage.hpp"
+#include <cfloat>
+#include <cassert>
+#include <string>
+#include <stdio.h>
+#include <iostream>
+
+int
+ClpPdco::pdco()
+{
+     printf("Dummy pdco solve\n");
+     return 0;
+}
+// ** Temporary version
+int
+ClpPdco::pdco( ClpPdcoBase * stuff, Options &options, Info &info, Outfo &outfo)
+{
+//    D1, D2 are positive-definite diagonal matrices defined from d1, d2.
+//           In particular, d2 indicates the accuracy required for
+//           satisfying each row of Ax = b.
+//
+// D1 and D2 (via d1 and d2) provide primal and dual regularization
+// respectively.  They ensure that the primal and dual solutions
+// (x,r) and (y,z) are unique and bounded.
+//
+// A scalar d1 is equivalent to d1 = ones(n,1), D1 = diag(d1).
+// A scalar d2 is equivalent to d2 = ones(m,1), D2 = diag(d2).
+// Typically, d1 = d2 = 1e-4.
+// These values perturb phi(x) only slightly  (by about 1e-8) and request
+// that A*x = b be satisfied quite accurately (to about 1e-8).
+// Set d1 = 1e-4, d2 = 1 for least-squares problems with bound constraints.
+// The problem is then
+//
+//    minimize    phi(x) + 1/2 norm(d1*x)^2 + 1/2 norm(A*x - b)^2
+//    subject to  bl <= x <= bu.
+//
+// More generally, d1 and d2 may be n and m vectors containing any positive
+// values (preferably not too small, and typically no larger than 1).
+// Bigger elements of d1 and d2 improve the stability of the solver.
+//
+// At an optimal solution, if x(j) is on its lower or upper bound,
+// the corresponding z(j) is positive or negative respectively.
+// If x(j) is between its bounds, z(j) = 0.
+// If bl(j) = bu(j), x(j) is fixed at that value and z(j) may have
+// either sign.
+//
+// Also, r and y satisfy r = D2 y, so that Ax + D2^2 y = b.
+// Thus if d2(i) = 1e-4, the i-th row of Ax = b will be satisfied to
+// approximately 1e-8.  This determines how large d2(i) can safely be.
+//
+//
+// EXTERNAL FUNCTIONS:
+// options         = pdcoSet;                  provided with pdco.m
+// [obj,grad,hess] = pdObj( x );               provided by user
+//               y = pdMat( name,mode,m,n,x ); provided by user if pdMat
+//                                             is a string, not a matrix
+//
+// INPUT ARGUMENTS:
+// pdObj      is a string containing the name of a function pdObj.m
+//            or a function_handle for such a function
+//            such that [obj,grad,hess] = pdObj(x) defines
+//            obj  = phi(x)              : a scalar,
+//            grad = gradient of phi(x)  : an n-vector,
+//            hess = diag(Hessian of phi): an n-vector.
+//         Examples:
+//            If phi(x) is the linear function c"x, pdObj should return
+//               [obj,grad,hess] = [c"*x, c, zeros(n,1)].
+//            If phi(x) is the entropy function E(x) = sum x(j) log x(j),
+//               [obj,grad,hess] = [E(x), log(x)+1, 1./x].
+// pdMat      may be an ifexplicit m x n matrix A (preferably sparse!),
+//            or a string containing the name of a function pdMat.m
+//            or a function_handle for such a function
+//            such that y = pdMat( name,mode,m,n,x )
+//            returns   y = A*x (mode=1)  or  y = A"*x (mode=2).
+//            The input parameter "name" will be the string pdMat.
+// b          is an m-vector.
+// bl         is an n-vector of lower bounds.  Non-existent bounds
+//            may be represented by bl(j) = -Inf or bl(j) <= -1e+20.
+// bu         is an n-vector of upper bounds.  Non-existent bounds
+//            may be represented by bu(j) =  Inf or bu(j) >=  1e+20.
+// d1, d2     may be positive scalars or positive vectors (see above).
+// options    is a structure that may be set and altered by pdcoSet
+//            (type help pdcoSet).
+// x0, y0, z0 provide an initial solution.
+// xsize, zsize are estimates of the biggest x and z at the solution.
+//            They are used to scale (x,y,z).  Good estimates
+//            should improve the performance of the barrier method.
+//
+//
+// OUTPUT ARGUMENTS:
+// x          is the primal solution.
+// y          is the dual solution associated with Ax + D2 r = b.
+// z          is the dual solution associated with bl <= x <= bu.
+// inform = 0 if a solution is found;
+//        = 1 if too many iterations were required;
+//        = 2 if the linesearch failed too often.
+// PDitns     is the number of Primal-Dual Barrier iterations required.
+// CGitns     is the number of Conjugate-Gradient  iterations required
+//            if an iterative solver is used (LSQR).
+// time       is the cpu time used.
+//----------------------------------------------------------------------
+
+// PRIVATE FUNCTIONS:
+//    pdxxxbounds
+//    pdxxxdistrib
+//    pdxxxlsqr
+//    pdxxxlsqrmat
+//    pdxxxmat
+//    pdxxxmerit
+//    pdxxxresid1
+//    pdxxxresid2
+//    pdxxxstep
+//
+// GLOBAL VARIABLES:
+//    global pdDDD1 pdDDD2 pdDDD3
+//
+//
+// NOTES:
+// The matrix A should be reasonably well scaled: norm(A,inf) =~ 1.
+// The vector b and objective phi(x) may be of any size, but ensure that
+// xsize and zsize are reasonably close to norm(x,inf) and norm(z,inf)
+// at the solution.
+//
+// The files defining pdObj  and pdMat
+// must not be called Fname.m or Aname.m!!
+//
+//
+// AUTHOR:
+//    Michael Saunders, Systems Optimization Laboratory (SOL),
+//    Stanford University, Stanford, California, USA.
+//    saunders@stanford.edu
+//
+// CONTRIBUTORS:
+//    Byunggyoo Kim, SOL, Stanford University.
+//    bgkim@stanford.edu
+//
+// DEVELOPMENT:
+// 20 Jun 1997: Original version of pdsco.m derived from pdlp0.m.
+// 29 Sep 2002: Original version of pdco.m  derived from pdsco.m.
+//              Introduced D1, D2 in place of gamma*I, delta*I
+//              and allowed for general bounds bl <= x <= bu.
+// 06 Oct 2002: Allowed for fixed variabes: bl(j) = bu(j) for any j.
+// 15 Oct 2002: Eliminated some work vectors (since m, n might be LARGE).
+//              Modularized residuals, linesearch
+// 16 Oct 2002: pdxxx..., pdDDD... names rationalized.
+//              pdAAA eliminated (global copy of A).
+//              Aname is now used directly as an ifexplicit A or a function.
+//              NOTE: If Aname is a function, it now has an extra parameter.
+// 23 Oct 2002: Fname and Aname can now be function handles.
+// 01 Nov 2002: Bug fixed in feval in pdxxxmat.
+//-----------------------------------------------------------------------
+
+//  global pdDDD1 pdDDD2 pdDDD3
+     double inf = 1.0e30;
+     double eps = 1.0e-15;
+     double atolold = -1.0, r3ratio = -1.0, Pinf, Dinf, Cinf, Cinf0;
+
+     printf("\n   --------------------------------------------------------");
+     printf("\n   pdco.m                            Version of 01 Nov 2002");
+     printf("\n   Primal-dual barrier method to minimize a convex function");
+     printf("\n   subject to linear constraints Ax + r = b,  bl <= x <= bu");
+     printf("\n   --------------------------------------------------------\n");
+
+     int m = numberRows_;
+     int n = numberColumns_;
+     bool ifexplicit = true;
+
+     CoinDenseVector<double> b(m, rhs_);
+     CoinDenseVector<double> x(n, x_);
+     CoinDenseVector<double> y(m, y_);
+     CoinDenseVector<double> z(n, dj_);
+     //delete old arrays
+     delete [] rhs_;
+     delete [] x_;
+     delete [] y_;
+     delete [] dj_;
+     rhs_ = NULL;
+     x_ = NULL;
+     y_ = NULL;
+     dj_ = NULL;
+
+     // Save stuff so available elsewhere
+     pdcoStuff_ = stuff;
+
+     double normb  = b.infNorm();
+     double normx0 = x.infNorm();
+     double normy0 = y.infNorm();
+     double normz0 = z.infNorm();
+
+     printf("\nmax |b | = %8g     max |x0| = %8g", normb , normx0);
+     printf(                "      xsize   = %8g", xsize_);
+     printf("\nmax |y0| = %8g     max |z0| = %8g", normy0, normz0);
+     printf(                "      zsize   = %8g", zsize_);
+
+     //---------------------------------------------------------------------
+     // Initialize.
+     //---------------------------------------------------------------------
+     //true   = 1;
+     //false  = 0;
+     //zn     = zeros(n,1);
+     //int nb     = n + m;
+     int CGitns = 0;
+     int inform = 0;
+     //---------------------------------------------------------------------
+     //  Only allow scalar d1, d2 for now
+     //---------------------------------------------------------------------
+     /*
+     if (d1_->size()==1)
+         d1_->resize(n, d1_->getElements()[0]);  // Allow scalar d1, d2
+     if (d2_->size()==1)
+         d2->resize(m, d2->getElements()[0]);  // to mean dk * unit vector
+      */
+     assert (stuff->sizeD1() == 1);
+     double d1 = stuff->getD1();
+     double d2 = stuff->getD2();
+
+     //---------------------------------------------------------------------
+     // Grab input options.
+     //---------------------------------------------------------------------
+     int  maxitn    = options.MaxIter;
+     double featol    = options.FeaTol;
+     double opttol    = options.OptTol;
+     double steptol   = options.StepTol;
+     int  stepSame  = 1;  /* options.StepSame;   // 1 means stepx == stepz */
+     double x0min     = options.x0min;
+     double z0min     = options.z0min;
+     double mu0       = options.mu0;
+     int  LSproblem = options.LSproblem;  // See below
+     int  LSmethod  = options.LSmethod;   // 1=Cholesky    2=QR    3=LSQR
+     int  itnlim    = options.LSQRMaxIter * CoinMin(m, n);
+     double atol1     = options.LSQRatol1;  // Initial  atol
+     double atol2     = options.LSQRatol2;  // Smallest atol,unless atol1 is smaller
+     double conlim    = options.LSQRconlim;
+     //int  wait      = options.wait;
+
+     // LSproblem:
+     //  1 = dy          2 = dy shifted, DLS
+     // 11 = s          12 =  s shifted, DLS    (dx = Ds)
+     // 21 = dx
+     // 31 = 3x3 system, symmetrized by Z^{1/2}
+     // 32 = 2x2 system, symmetrized by X^{1/2}
+
+     //---------------------------------------------------------------------
+     // Set other parameters.
+     //---------------------------------------------------------------------
+     int  kminor    = 0;      // 1 stops after each iteration
+     double eta       = 1e-4;   // Linesearch tolerance for "sufficient descent"
+     double maxf      = 10;     // Linesearch backtrack limit (function evaluations)
+     double maxfail   = 1;      // Linesearch failure limit (consecutive iterations)
+     double bigcenter = 1e+3;   // mu is reduced if center < bigcenter.
+
+     // Parameters for LSQR.
+     double atolmin   = eps;    // Smallest atol if linesearch back-tracks
+     double btol      = 0;      // Should be small (zero is ok)
+     double show      = false;  // Controls lsqr iteration log
+     /*
+     double gamma     = d1->infNorm();
+     double delta     = d2->infNorm();
+     */
+     double gamma = d1;
+     double delta = d2;
+
+     printf("\n\nx0min    = %8g     featol   = %8.1e", x0min, featol);
+     printf(                  "      d1max   = %8.1e", gamma);
+     printf(  "\nz0min    = %8g     opttol   = %8.1e", z0min, opttol);
+     printf(                  "      d2max   = %8.1e", delta);
+     printf(  "\nmu0      = %8.1e     steptol  = %8g", mu0  , steptol);
+     printf(                  "     bigcenter= %8g"  , bigcenter);
+
+     printf("\n\nLSQR:");
+     printf("\natol1    = %8.1e     atol2    = %8.1e", atol1 , atol2 );
+     printf(                  "      btol    = %8.1e", btol );
+     printf("\nconlim   = %8.1e     itnlim   = %8d"  , conlim, itnlim);
+     printf(                  "      show    = %8g"  , show );
+
+// LSmethod  = 3;  ////// Hardwire LSQR
+// LSproblem = 1;  ////// and LS problem defining "dy".
+     /*
+       if wait
+         printf("\n\nReview parameters... then type "return"\n")
+         keyboard
+       end
+     */
+     if (eta < 0)
+          printf("\n\nLinesearch disabled by eta < 0");
+
+     //---------------------------------------------------------------------
+     // All parameters have now been set.
+     //---------------------------------------------------------------------
+     double time    = CoinCpuTime();
+     //bool useChol = (LSmethod == 1);
+     //bool useQR   = (LSmethod == 2);
+     bool direct  = (LSmethod <= 2 && ifexplicit);
+     char solver[6];
+     strcpy(solver, "  LSQR");
+
+
+     //---------------------------------------------------------------------
+     // Categorize bounds and allow for fixed variables by modifying b.
+     //---------------------------------------------------------------------
+
+     int nlow, nupp, nfix;
+     int *bptrs[3] = {0};
+     getBoundTypes(&nlow, &nupp, &nfix, bptrs );
+     int *low = bptrs[0];
+     int *upp = bptrs[1];
+     int *fix = bptrs[2];
+
+     int nU = n;
+     if (nupp == 0) nU = 1;  //Make dummy vectors if no Upper bounds
+
+     //---------------------------------------------------------------------
+     //  Get pointers to local copy of model bounds
+     //---------------------------------------------------------------------
+
+     CoinDenseVector<double> bl(n, columnLower_);
+     double *bl_elts = bl.getElements();
+     CoinDenseVector<double> bu(nU, columnUpper_);  // this is dummy if no UB
+     double *bu_elts = bu.getElements();
+
+     CoinDenseVector<double> r1(m, 0.0);
+     double *r1_elts = r1.getElements();
+     CoinDenseVector<double> x1(n, 0.0);
+     double *x1_elts = x1.getElements();
+
+     if (nfix > 0) {
+          for (int k = 0; k < nfix; k++)
+               x1_elts[fix[k]] = bl[fix[k]];
+          matVecMult(1, r1, x1);
+          b = b - r1;
+          // At some stage, might want to look at normfix = norm(r1,inf);
+     }
+
+     //---------------------------------------------------------------------
+     // Scale the input data.
+     // The scaled variables are
+     //    xbar     = x/beta,
+     //    ybar     = y/zeta,
+     //    zbar     = z/zeta.
+     // Define
+     //    theta    = beta*zeta;
+     // The scaled function is
+     //    phibar   = ( 1   /theta) fbar(beta*xbar),
+     //    gradient = (beta /theta) grad,
+     //    Hessian  = (beta2/theta) hess.
+     //---------------------------------------------------------------------
+     double beta = xsize_;
+     if (beta == 0) beta = 1; // beta scales b, x.
+     double zeta = zsize_;
+     if (zeta == 0) zeta = 1; // zeta scales y, z.
+     double theta  = beta * zeta;                          // theta scales obj.
+     // (theta could be anything, but theta = beta*zeta makes
+     // scaled grad = grad/zeta = 1 approximately if zeta is chosen right.)
+
+     for (int k = 0; k < nlow; k++)
+          bl_elts[low[k]] = bl_elts[low[k]] / beta;
+     for (int k = 0; k < nupp; k++)
+          bu_elts[upp[k]] = bu_elts[upp[k]] / beta;
+     d1     = d1 * ( beta / sqrt(theta) );
+     d2     = d2 * ( sqrt(theta) / beta );
+
+     double beta2  = beta * beta;
+     b.scale( (1.0 / beta) );
+     y.scale( (1.0 / zeta) );
+     x.scale( (1.0 / beta) );
+     z.scale( (1.0 / zeta) );
+
+     //---------------------------------------------------------------------
+     // Initialize vectors that are not fully used if bounds are missing.
+     //---------------------------------------------------------------------
+     CoinDenseVector<double> rL(n, 0.0);
+     CoinDenseVector<double> cL(n, 0.0);
+     CoinDenseVector<double> z1(n, 0.0);
+     CoinDenseVector<double> dx1(n, 0.0);
+     CoinDenseVector<double> dz1(n, 0.0);
+     CoinDenseVector<double> r2(n, 0.0);
+
+     // Assign upper bd regions (dummy if no UBs)
+
+     CoinDenseVector<double> rU(nU, 0.0);
+     CoinDenseVector<double> cU(nU, 0.0);
+     CoinDenseVector<double> x2(nU, 0.0);
+     CoinDenseVector<double> z2(nU, 0.0);
+     CoinDenseVector<double> dx2(nU, 0.0);
+     CoinDenseVector<double> dz2(nU, 0.0);
+
+     //---------------------------------------------------------------------
+     // Initialize x, y, z, objective, etc.
+     //---------------------------------------------------------------------
+     CoinDenseVector<double> dx(n, 0.0);
+     CoinDenseVector<double> dy(m, 0.0);
+     CoinDenseVector<double> Pr(m);
+     CoinDenseVector<double> D(n);
+     double *D_elts = D.getElements();
+     CoinDenseVector<double> w(n);
+     double *w_elts = w.getElements();
+     CoinDenseVector<double> rhs(m + n);
+
+
+     //---------------------------------------------------------------------
+     // Pull out the element array pointers for efficiency
+     //---------------------------------------------------------------------
+     double *x_elts  = x.getElements();
+     double *x2_elts = x2.getElements();
+     double *z_elts  = z.getElements();
+     double *z1_elts = z1.getElements();
+     double *z2_elts = z2.getElements();
+
+     for (int k = 0; k < nlow; k++) {
+          x_elts[low[k]]  = CoinMax( x_elts[low[k]], bl[low[k]]);
+          x1_elts[low[k]] = CoinMax( x_elts[low[k]] - bl[low[k]], x0min  );
+          z1_elts[low[k]] = CoinMax( z_elts[low[k]], z0min  );
+     }
+     for (int k = 0; k < nupp; k++) {
+          x_elts[upp[k]]  = CoinMin( x_elts[upp[k]], bu[upp[k]]);
+          x2_elts[upp[k]] = CoinMax(bu[upp[k]] -  x_elts[upp[k]], x0min  );
+          z2_elts[upp[k]] = CoinMax(-z_elts[upp[k]], z0min  );
+     }
+     //////////////////// Assume hessian is diagonal. //////////////////////
+
+//  [obj,grad,hess] = feval( Fname, (x*beta) );
+     x.scale(beta);
+     double obj = getObj(x);
+     CoinDenseVector<double> grad(n);
+     getGrad(x, grad);
+     CoinDenseVector<double> H(n);
+     getHessian(x , H);
+     x.scale((1.0 / beta));
+
+     //double * g_elts = grad.getElements();
+     double * H_elts = H.getElements();
+
+     obj /= theta;                       // Scaled obj.
+     grad = grad * (beta / theta) + (d1 * d1) * x; // grad includes x regularization.
+     H  = H * (beta2 / theta) + (d1 * d1)      ; // H    includes x regularization.
+
+
+     /*---------------------------------------------------------------------
+     // Compute primal and dual residuals:
+     // r1 =  b - Aprod(x) - d2*d2*y;
+     // r2 =  grad - Atprod(y) + z2 - z1;
+     //  rL =  bl - x + x1;
+     //  rU =  x + x2 - bu; */
+     //---------------------------------------------------------------------
+     //  [r1,r2,rL,rU,Pinf,Dinf] = ...
+     //      pdxxxresid1( Aname,fix,low,upp, ...
+     //                   b,bl,bu,d1,d2,grad,rL,rU,x,x1,x2,y,z1,z2 );
+     pdxxxresid1( this, nlow, nupp, nfix, low, upp, fix,
+                  b, bl_elts, bu_elts, d1, d2, grad, rL, rU, x, x1, x2, y, z1, z2,
+                  r1, r2, &Pinf, &Dinf);
+     //---------------------------------------------------------------------
+     // Initialize mu and complementarity residuals:
+     //    cL   = mu*e - X1*z1.
+     //    cU   = mu*e - X2*z2.
+     //
+     // 25 Jan 2001: Now that b and obj are scaled (and hence x,y,z),
+     //              we should be able to use mufirst = mu0 (absolute value).
+     //              0.1 worked poorly on StarTest1 with x0min = z0min = 0.1.
+     // 29 Jan 2001: We might as well use mu0 = x0min * z0min;
+     //              so that most variables are centered after a warm start.
+     // 29 Sep 2002: Use mufirst = mu0*(x0min * z0min),
+     //              regarding mu0 as a scaling of the initial center.
+     //---------------------------------------------------------------------
+     //  double mufirst = mu0*(x0min * z0min);
+     double mufirst = mu0;   // revert to absolute value
+     double mulast  = 0.1 * opttol;
+     mulast  = CoinMin( mulast, mufirst );
+     double mu      = mufirst;
+     double center,  fmerit;
+     pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2,
+                  z1, z2, &center, &Cinf, &Cinf0 );
+     fmerit = pdxxxmerit(nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU );
+
+     // Initialize other things.
+
+     bool  precon   = true;
+     double PDitns    = 0;
+     //bool converged = false;
+     double atol      = atol1;
+     atol2     = CoinMax( atol2, atolmin );
+     atolmin   = atol2;
+     //  pdDDD2    = d2;    // Global vector for diagonal matrix D2
+
+     //  Iteration log.
+
+     int nf      = 0;
+     int itncg   = 0;
+     int nfail   = 0;
+
+     printf("\n\nItn   mu   stepx   stepz  Pinf  Dinf");
+     printf("  Cinf   Objective    nf  center");
+     if (direct) {
+          printf("\n");
+     } else {
+          printf("  atol   solver   Inexact\n");
+     }
+
+     double regx = (d1 * x).twoNorm();
+     double regy = (d2 * y).twoNorm();
+     //  regterm = twoNorm(d1.*x)^2  +  norm(d2.*y)^2;
+     double regterm = regx * regx + regy * regy;
+     double objreg  = obj  +  0.5 * regterm;
+     double objtrue = objreg * theta;
+
+     printf("\n%3g                     ", PDitns        );
+     printf("%6.1f%6.1f" , log10(Pinf ), log10(Dinf));
+     printf("%6.1f%15.7e", log10(Cinf0), objtrue    );
+     printf("   %8.1f\n"   , center                   );
+     /*
+     if kminor
+       printf("\n\nStart of first minor itn...\n");
+       keyboard
+     end
+     */
+     //---------------------------------------------------------------------
+     // Main loop.
+     //---------------------------------------------------------------------
+     // Lsqr
+     ClpLsqr  thisLsqr(this);
+     //  while (converged) {
+     while(PDitns < maxitn) {
+          PDitns = PDitns + 1;
+
+          // 31 Jan 2001: Set atol according to progress, a la Inexact Newton.
+          // 07 Feb 2001: 0.1 not small enough for Satellite problem.  Try 0.01.
+          // 25 Apr 2001: 0.01 seems wasteful for Star problem.
+          //              Now that starting conditions are better, go back to 0.1.
+
+          double r3norm = CoinMax(Pinf,   CoinMax(Dinf,  Cinf));
+          atol   = CoinMin(atol,  r3norm * 0.1);
+          atol   = CoinMax(atol,  atolmin   );
+          info.r3norm = r3norm;
+
+          //-------------------------------------------------------------------
+          //  Define a damped Newton iteration for solving f = 0,
+          //  keeping  x1, x2, z1, z2 > 0.  We eliminate dx1, dx2, dz1, dz2
+          //  to obtain the system
+          //
+          //     [-H2  A"  ] [ dx ] = [ w ],   H2 = H + D1^2 + X1inv Z1 + X2inv Z2,
+          //     [ A   D2^2] [ dy ] = [ r1]    w  = r2 - X1inv(cL + Z1 rL)
+          //                                           + X2inv(cU + Z2 rU),
+          //
+          //  which is equivalent to the least-squares problem
+          //
+          //     min || [ D A"]dy  -  [  D w   ] ||,   D = H2^{-1/2}.         (*)
+          //         || [  D2 ]       [D2inv r1] ||
+          //-------------------------------------------------------------------
+          for (int k = 0; k < nlow; k++)
+               H_elts[low[k]]  = H_elts[low[k]] + z1[low[k]] / x1[low[k]];
+          for (int k = 0; k < nupp; k++)
+               H[upp[k]]  = H[upp[k]] + z2[upp[k]] / x2[upp[k]];
+          w = r2;
+          for (int k = 0; k < nlow; k++)
+               w[low[k]]  = w[low[k]] - (cL[low[k]] + z1[low[k]] * rL[low[k]]) / x1[low[k]];
+          for (int k = 0; k < nupp; k++)
+               w[upp[k]]  = w[upp[k]] + (cU[upp[k]] + z2[upp[k]] * rU[upp[k]]) / x2[upp[k]];
+
+          if (LSproblem == 1) {
+               //-----------------------------------------------------------------
+               //  Solve (*) for dy.
+               //-----------------------------------------------------------------
+               H      = 1.0 / H;  // H is now Hinv (NOTE!)
+               for (int k = 0; k < nfix; k++)
+                    H[fix[k]] = 0;
+               for (int k = 0; k < n; k++)
+                    D_elts[k] = sqrt(H_elts[k]);
+               thisLsqr.borrowDiag1(D_elts);
+               thisLsqr.diag2_ = d2;
+
+               if (direct) {
+                    // Omit direct option for now
+               } else {// Iterative solve using LSQR.
+                    //rhs     = [ D.*w; r1./d2 ];
+                    for (int k = 0; k < n; k++)
+                         rhs[k] = D_elts[k] * w_elts[k];
+                    for (int k = 0; k < m; k++)
+                         rhs[n+k] = r1_elts[k] * (1.0 / d2);
+                    double damp    = 0;
+
+                    if (precon) {   // Construct diagonal preconditioner for LSQR
+                         matPrecon(d2, Pr, D);
+                    }
+                    /*
+                    	rw(7)        = precon;
+                            info.atolmin = atolmin;
+                            info.r3norm  = fmerit;  // Must be the 2-norm here.
+
+                            [ dy, istop, itncg, outfo ] = ...
+                       pdxxxlsqr( nb,m,"pdxxxlsqrmat",Aname,rw,rhs,damp, ...
+                                  atol,btol,conlim,itnlim,show,info );
+
+
+                    	thisLsqr.input->rhs_vec = &rhs;
+                    	thisLsqr.input->sol_vec = &dy;
+                    	thisLsqr.input->rel_mat_err = atol;
+                    	thisLsqr.do_lsqr(this);
+                    	*/
+                    //  New version of lsqr
+
+                    int istop;
+                    dy.clear();
+                    show = false;
+                    info.atolmin = atolmin;
+                    info.r3norm  = fmerit;  // Must be the 2-norm here.
+
+                    thisLsqr.do_lsqr( rhs, damp, atol, btol, conlim, itnlim,
+                                      show, info, dy , &istop, &itncg, &outfo, precon, Pr);
+                    if (precon)
+                         dy = dy * Pr;
+
+                    if (!precon && itncg > 999999)
+                         precon = true;
+
+                    if (istop == 3  ||  istop == 7 )  // conlim or itnlim
+                         printf("\n    LSQR stopped early:  istop = //%d", istop);
+
+
+                    atolold   = outfo.atolold;
+                    atol      = outfo.atolnew;
+                    r3ratio   = outfo.r3ratio;
+               }// LSproblem 1
+
+               //      grad      = pdxxxmat( Aname,2,m,n,dy );   // grad = A"dy
+               grad.clear();
+               matVecMult(2, grad, dy);
+               for (int k = 0; k < nfix; k++)
+                    grad[fix[k]] = 0;                            // grad is a work vector
+               dx = H * (grad - w);
+
+          } else {
+               perror( "This LSproblem not yet implemented\n" );
+          }
+          //-------------------------------------------------------------------
+
+          CGitns += itncg;
+
+          //-------------------------------------------------------------------
+          // dx and dy are now known.  Get dx1, dx2, dz1, dz2.
+          //-------------------------------------------------------------------
+          for (int k = 0; k < nlow; k++) {
+               dx1[low[k]] = - rL[low[k]] + dx[low[k]];
+               dz1[low[k]] =  (cL[low[k]] - z1[low[k]] * dx1[low[k]]) / x1[low[k]];
+          }
+          for (int k = 0; k < nupp; k++) {
+               dx2[upp[k]] = - rU[upp[k]] - dx[upp[k]];
+               dz2[upp[k]] =  (cU[upp[k]] - z2[upp[k]] * dx2[upp[k]]) / x2[upp[k]];
+          }
+          //-------------------------------------------------------------------
+          // Find the maximum step.
+          //--------------------------------------------------------------------
+          double stepx1 = pdxxxstep(nlow, low, x1, dx1 );
+          double stepx2 = inf;
+          if (nupp > 0)
+               stepx2 = pdxxxstep(nupp, upp, x2, dx2 );
+          double stepz1 = pdxxxstep( z1     , dz1      );
+          double stepz2 = inf;
+          if (nupp > 0)
+               stepz2 = pdxxxstep( z2     , dz2      );
+          double stepx  = CoinMin( stepx1, stepx2 );
+          double stepz  = CoinMin( stepz1, stepz2 );
+          stepx  = CoinMin( steptol * stepx, 1.0 );
+          stepz  = CoinMin( steptol * stepz, 1.0 );
+          if (stepSame) {                  // For NLPs, force same step
+               stepx = CoinMin( stepx, stepz );   // (true Newton method)
+               stepz = stepx;
+          }
+
+          //-------------------------------------------------------------------
+          // Backtracking linesearch.
+          //-------------------------------------------------------------------
+          bool fail     =  true;
+          nf       =  0;
+
+          while (nf < maxf) {
+               nf      = nf + 1;
+               x       = x        +  stepx * dx;
+               y       = y        +  stepz * dy;
+               for (int k = 0; k < nlow; k++) {
+                    x1[low[k]] = x1[low[k]]  +  stepx * dx1[low[k]];
+                    z1[low[k]] = z1[low[k]]  +  stepz * dz1[low[k]];
+               }
+               for (int k = 0; k < nupp; k++) {
+                    x2[upp[k]] = x2[upp[k]]  +  stepx * dx2[upp[k]];
+                    z2[upp[k]] = z2[upp[k]]  +  stepz * dz2[upp[k]];
+               }
+               //      [obj,grad,hess] = feval( Fname, (x*beta) );
+               x.scale(beta);
+               obj = getObj(x);
+               getGrad(x, grad);
+               getHessian(x, H);
+               x.scale((1.0 / beta));
+
+               obj        /= theta;
+               grad       = grad * (beta / theta)  +  d1 * d1 * x;
+               H          = H * (beta2 / theta)  +  d1 * d1;
+
+               //      [r1,r2,rL,rU,Pinf,Dinf] = ...
+               pdxxxresid1( this, nlow, nupp, nfix, low, upp, fix,
+                            b, bl_elts, bu_elts, d1, d2, grad, rL, rU, x, x1, x2,
+                            y, z1, z2, r1, r2, &Pinf, &Dinf );
+               //double center, Cinf, Cinf0;
+               //      [cL,cU,center,Cinf,Cinf0] = ...
+               pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2, z1, z2,
+                            &center, &Cinf, &Cinf0);
+               double fmeritnew = pdxxxmerit(nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU );
+               double step      = CoinMin( stepx, stepz );
+
+               if (fmeritnew <= (1 - eta * step)*fmerit) {
+                    fail = false;
+                    break;
+               }
+
+               // Merit function didn"t decrease.
+               // Restore variables to previous values.
+               // (This introduces a little error, but save lots of space.)
+
+               x       = x        -  stepx * dx;
+               y       = y        -  stepz * dy;
+               for (int k = 0; k < nlow; k++) {
+                    x1[low[k]] = x1[low[k]]  -  stepx * dx1[low[k]];
+                    z1[low[k]] = z1[low[k]]  -  stepz * dz1[low[k]];
+               }
+               for (int k = 0; k < nupp; k++) {
+                    x2[upp[k]] = x2[upp[k]]  -  stepx * dx2[upp[k]];
+                    z2[upp[k]] = z2[upp[k]]  -  stepz * dz2[upp[k]];
+               }
+               // Back-track.
+               // If it"s the first time,
+               // make stepx and stepz the same.
+
+               if (nf == 1 && stepx != stepz) {
+                    stepx = step;
+               } else if (nf < maxf) {
+                    stepx = stepx / 2;
+               }
+               stepz = stepx;
+          }
+
+          if (fail) {
+               printf("\n     Linesearch failed (nf too big)");
+               nfail += 1;
+          } else {
+               nfail = 0;
+          }
+
+          //-------------------------------------------------------------------
+          // Set convergence measures.
+          //--------------------------------------------------------------------
+          regx = (d1 * x).twoNorm();
+          regy = (d2 * y).twoNorm();
+          regterm = regx * regx + regy * regy;
+          objreg  = obj  +  0.5 * regterm;
+          objtrue = objreg * theta;
+
+          bool primalfeas    = Pinf  <=  featol;
+          bool dualfeas      = Dinf  <=  featol;
+          bool complementary = Cinf0 <=  opttol;
+          bool enough        = PDitns >=       4; // Prevent premature termination.
+          bool converged     = primalfeas  &  dualfeas  &  complementary  &  enough;
+
+          //-------------------------------------------------------------------
+          // Iteration log.
+          //-------------------------------------------------------------------
+          char str1[100], str2[100], str3[100], str4[100], str5[100];
+          sprintf(str1, "\n%3g%5.1f" , PDitns      , log10(mu)   );
+          sprintf(str2, "%8.5f%8.5f" , stepx       , stepz       );
+          if (stepx < 0.0001 || stepz < 0.0001) {
+               sprintf(str2, " %6.1e %6.1e" , stepx       , stepz       );
+          }
+
+          sprintf(str3, "%6.1f%6.1f" , log10(Pinf) , log10(Dinf));
+          sprintf(str4, "%6.1f%15.7e", log10(Cinf0), objtrue     );
+          sprintf(str5, "%3d%8.1f"   , nf          , center      );
+          if (center > 99999) {
+               sprintf(str5, "%3d%8.1e"   , nf          , center      );
+          }
+          printf("%s%s%s%s%s", str1, str2, str3, str4, str5);
+          if (direct) {
+               // relax
+          } else {
+               printf(" %5.1f%7d%7.3f", log10(atolold), itncg, r3ratio);
+          }
+          //-------------------------------------------------------------------
+          // Test for termination.
+          //-------------------------------------------------------------------
+          if (kminor) {
+               printf( "\nStart of next minor itn...\n");
+               //      keyboard;
+          }
+
+          if (converged) {
+               printf("\n   Converged");
+               break;
+          } else if (PDitns >= maxitn) {
+               printf("\n   Too many iterations");
+               inform = 1;
+               break;
+          } else if (nfail  >= maxfail) {
+               printf("\n   Too many linesearch failures");
+               inform = 2;
+               break;
+          } else {
+
+               // Reduce mu, and reset certain residuals.
+
+               double stepmu  = CoinMin( stepx , stepz   );
+               stepmu  = CoinMin( stepmu, steptol );
+               double muold   = mu;
+               mu      = mu   -  stepmu * mu;
+               if (center >= bigcenter)
+                    mu = muold;
+
+               // mutrad = mu0*(sum(Xz)/n); // 24 May 1998: Traditional value, but
+               // mu     = CoinMin(mu,mutrad ); // it seemed to decrease mu too much.
+
+               mu      = CoinMax(mu, mulast); // 13 Jun 1998: No need for smaller mu.
+               //      [cL,cU,center,Cinf,Cinf0] = ...
+               pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2, z1, z2,
+                            &center, &Cinf, &Cinf0 );
+               fmerit = pdxxxmerit( nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU );
+
+               // Reduce atol for LSQR (and SYMMLQ).
+               // NOW DONE AT TOP OF LOOP.
+
+               atolold = atol;
+               // if atol > atol2
+               //   atolfac = (mu/mufirst)^0.25;
+               //   atol    = CoinMax( atol*atolfac, atol2 );
+               // end
+
+               // atol = CoinMin( atol, mu );     // 22 Jan 2001: a la Inexact Newton.
+               // atol = CoinMin( atol, 0.5*mu ); // 30 Jan 2001: A bit tighter
+
+               // If the linesearch took more than one function (nf > 1),
+               // we assume the search direction needed more accuracy
+               // (though this may be true only for LPs).
+               // 12 Jun 1998: Ask for more accuracy if nf > 2.
+               // 24 Nov 2000: Also if the steps are small.
+               // 30 Jan 2001: Small steps might be ok with warm start.
+               // 06 Feb 2001: Not necessarily.  Reinstated tests in next line.
+
+               if (nf > 2  ||  CoinMin( stepx, stepz ) <= 0.01)
+                    atol = atolold * 0.1;
+          }
+          //---------------------------------------------------------------------
+          // End of main loop.
+          //---------------------------------------------------------------------
+     }
+
+
+     for (int k = 0; k < nfix; k++)
+          x[fix[k]] = bl[fix[k]];
+     z      = z1;
+     if (nupp > 0)
+          z = z - z2;
+     printf("\n\nmax |x| =%10.3f", x.infNorm() );
+     printf("    max |y| =%10.3f", y.infNorm() );
+     printf("    max |z| =%10.3f", z.infNorm() );
+     printf("   scaled");
+
+     x.scale(beta);
+     y.scale(zeta);
+     z.scale(zeta);   // Unscale x, y, z.
+
+     printf(  "\nmax |x| =%10.3f", x.infNorm() );
+     printf("    max |y| =%10.3f", y.infNorm() );
+     printf("    max |z| =%10.3f", z.infNorm() );
+     printf(" unscaled\n");
+
+     time   = CoinCpuTime() - time;
+     char str1[100], str2[100];
+     sprintf(str1, "\nPDitns  =%10g", PDitns );
+     sprintf(str2, "itns =%10d", CGitns );
+     //  printf( [str1 " " solver str2] );
+     printf("    time    =%10.1f\n", time);
+     /*
+     pdxxxdistrib( abs(x),abs(z) );   // Private function
+
+     if (wait)
+       keyboard;
+     */
+//-----------------------------------------------------------------------
+// End function pdco.m
+//-----------------------------------------------------------------------
+     /*  printf("Solution x values:\n\n");
+       for (int k=0; k<n; k++)
+         printf(" %d   %e\n", k, x[k]);
+     */
+// Print distribution
+     double thresh[9] = { 0.00000001, 0.0000001, 0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1, 1.00001};
+     int counts[9] = {0};
+     for (int ij = 0; ij < n; ij++) {
+          for (int j = 0; j < 9; j++) {
+               if(x[ij] < thresh[j]) {
+                    counts[j] += 1;
+                    break;
+               }
+          }
+     }
+     printf ("Distribution of Solution Values\n");
+     for (int j = 8; j > 1; j--)
+          printf(" %g  to  %g %d\n", thresh[j-1], thresh[j], counts[j]);
+     printf("   Less than   %g %d\n", thresh[2], counts[0]);
+
+     return inform;
+}
+// LSQR
+void
+ClpPdco::lsqr()
+{
+}
+
+void ClpPdco::matVecMult( int mode, double* x_elts, double* y_elts)
+{
+     pdcoStuff_->matVecMult(this, mode, x_elts, y_elts);
+}
+void ClpPdco::matVecMult( int mode, CoinDenseVector<double> &x, double *y_elts)
+{
+     double *x_elts = x.getElements();
+     matVecMult( mode, x_elts, y_elts);
+     return;
+}
+
+void ClpPdco::matVecMult( int mode, CoinDenseVector<double> &x, CoinDenseVector<double> &y)
+{
+     double *x_elts = x.getElements();
+     double *y_elts = y.getElements();
+     matVecMult( mode, x_elts, y_elts);
+     return;
+}
+
+void ClpPdco::matVecMult( int mode, CoinDenseVector<double> *x, CoinDenseVector<double> *y)
+{
+     double *x_elts = x->getElements();
+     double *y_elts = y->getElements();
+     matVecMult( mode, x_elts, y_elts);
+     return;
+}
+void ClpPdco::matPrecon(double delta, double* x_elts, double* y_elts)
+{
+     pdcoStuff_->matPrecon(this, delta, x_elts, y_elts);
+}
+void ClpPdco::matPrecon(double delta, CoinDenseVector<double> &x, double *y_elts)
+{
+     double *x_elts = x.getElements();
+     matPrecon(delta, x_elts, y_elts);
+     return;
+}
+
+void ClpPdco::matPrecon(double delta, CoinDenseVector<double> &x, CoinDenseVector<double> &y)
+{
+     double *x_elts = x.getElements();
+     double *y_elts = y.getElements();
+     matPrecon(delta, x_elts, y_elts);
+     return;
+}
+
+void ClpPdco::matPrecon(double delta, CoinDenseVector<double> *x, CoinDenseVector<double> *y)
+{
+     double *x_elts = x->getElements();
+     double *y_elts = y->getElements();
+     matPrecon(delta, x_elts, y_elts);
+     return;
+}
+void ClpPdco::getBoundTypes(int *nlow, int *nupp, int *nfix, int **bptrs)
+{
+     *nlow = numberColumns_;
+     *nupp = *nfix = 0;
+     int *low_ = (int *)malloc(numberColumns_ * sizeof(int)) ;
+     for (int k = 0; k < numberColumns_; k++)
+          low_[k] = k;
+     bptrs[0] = low_;
+     return;
+}
+
+double ClpPdco::getObj(CoinDenseVector<double> &x)
+{
+     return pdcoStuff_->getObj(this, x);
+}
+
+void ClpPdco::getGrad(CoinDenseVector<double> &x, CoinDenseVector<double> &g)
+{
+     pdcoStuff_->getGrad(this, x, g);
+}
+
+void ClpPdco::getHessian(CoinDenseVector<double> &x, CoinDenseVector<double> &H)
+{
+     pdcoStuff_->getHessian(this, x, H);
+}
diff --git a/cbits/coin/ClpPdco.hpp b/cbits/coin/ClpPdco.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPdco.hpp
@@ -0,0 +1,72 @@
+/* $Id: ClpPdco.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Tomlin
+
+ */
+#ifndef ClpPdco_H
+#define ClpPdco_H
+
+#include "ClpInterior.hpp"
+
+/** This solves problems in Primal Dual Convex Optimization
+
+    It inherits from ClpInterior.  It has no data of its own and
+    is never created - only cast from a ClpInterior object at algorithm time.
+
+*/
+class ClpPdco : public ClpInterior {
+
+public:
+
+     /**@name Description of algorithm */
+     //@{
+     /** Pdco algorithm
+
+         Method
+
+
+     */
+
+     int pdco();
+     // ** Temporary version
+     int  pdco( ClpPdcoBase * stuff, Options &options, Info &info, Outfo &outfo);
+
+     //@}
+
+     /**@name Functions used in pdco */
+     //@{
+     /// LSQR
+     void lsqr();
+
+     void matVecMult( int, double *, double *);
+
+     void matVecMult( int, CoinDenseVector<double> &, double *);
+
+     void matVecMult( int, CoinDenseVector<double> &, CoinDenseVector<double> &);
+
+     void matVecMult( int, CoinDenseVector<double> *, CoinDenseVector<double> *);
+
+     void getBoundTypes( int *, int *, int *, int**);
+
+     void getGrad(CoinDenseVector<double> &x, CoinDenseVector<double> &grad);
+
+     void getHessian(CoinDenseVector<double> &x, CoinDenseVector<double> &H);
+
+     double getObj(CoinDenseVector<double> &x);
+
+     void matPrecon( double, double *, double *);
+
+     void matPrecon( double, CoinDenseVector<double> &, double *);
+
+     void matPrecon( double, CoinDenseVector<double> &, CoinDenseVector<double> &);
+
+     void matPrecon( double, CoinDenseVector<double> *, CoinDenseVector<double> *);
+     //@}
+
+};
+#endif
diff --git a/cbits/coin/ClpPdcoBase.cpp b/cbits/coin/ClpPdcoBase.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPdcoBase.cpp
@@ -0,0 +1,59 @@
+/* $Id: ClpPdcoBase.cpp 1941 2013-04-10 16:52:27Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include <iostream>
+
+#include "ClpPdcoBase.hpp"
+#include "ClpPdco.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpPdcoBase::ClpPdcoBase () :
+     d1_(0.0),
+     d2_(0.0),
+     type_(-1)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpPdcoBase::ClpPdcoBase (const ClpPdcoBase & source) :
+     d1_(source.d1_),
+     d2_(source.d2_),
+     type_(source.type_)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpPdcoBase::~ClpPdcoBase ()
+{
+
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpPdcoBase &
+ClpPdcoBase::operator=(const ClpPdcoBase& rhs)
+{
+     if (this != &rhs) {
+          d1_ = rhs.d1_;
+          d2_ = rhs.d2_;
+          type_ = rhs.type_;
+     }
+     return *this;
+}
diff --git a/cbits/coin/ClpPdcoBase.hpp b/cbits/coin/ClpPdcoBase.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPdcoBase.hpp
@@ -0,0 +1,103 @@
+/* $Id: ClpPdcoBase.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpPdcoBase_H
+#define ClpPdcoBase_H
+
+#include "CoinPragma.hpp"
+
+#include "CoinPackedMatrix.hpp"
+#include "CoinDenseVector.hpp"
+class ClpInterior;
+
+/** Abstract base class for tailoring everything for Pcdo
+
+    Since this class is abstract, no object of this type can be created.
+
+    If a derived class provides all methods then all ClpPcdo algorithms
+    should work.
+
+    Eventually we should be able to use ClpObjective and ClpMatrixBase.
+*/
+
+class ClpPdcoBase  {
+
+public:
+     /**@name Virtual methods that the derived classes must provide */
+     //@{
+     virtual void matVecMult(ClpInterior * model, int mode, double * x, double * y) const = 0;
+
+     virtual void getGrad(ClpInterior * model, CoinDenseVector<double> &x, CoinDenseVector<double> &grad) const = 0;
+
+     virtual void getHessian(ClpInterior * model, CoinDenseVector<double> &x, CoinDenseVector<double> &H) const = 0;
+
+     virtual double getObj(ClpInterior * model, CoinDenseVector<double> &x) const = 0;
+
+     virtual void matPrecon(ClpInterior * model,  double delta, double * x, double * y) const = 0;
+
+     //@}
+     //@{
+     ///@name Other
+     /// Clone
+     virtual ClpPdcoBase * clone() const = 0;
+     /// Returns type
+     inline int type() const {
+          return type_;
+     };
+     /// Sets type
+     inline void setType(int type) {
+          type_ = type;
+     };
+     /// Returns size of d1
+     inline int sizeD1() const {
+          return 1;
+     };
+     /// Returns d1 as scalar
+     inline double getD1() const {
+          return d1_;
+     };
+     /// Returns size of d2
+     inline int sizeD2() const {
+          return 1;
+     };
+     /// Returns d2 as scalar
+     inline double getD2() const {
+          return d2_;
+     };
+     //@}
+
+
+protected:
+
+     /**@name Constructors, destructor<br>
+        <strong>NOTE</strong>: All constructors are protected. There's no need
+        to expose them, after all, this is an abstract class. */
+     //@{
+     /** Default constructor. */
+     ClpPdcoBase();
+     /** Destructor (has to be public) */
+public:
+     virtual ~ClpPdcoBase();
+protected:
+     // Copy
+     ClpPdcoBase(const ClpPdcoBase&);
+     // Assignment
+     ClpPdcoBase& operator=(const ClpPdcoBase&);
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Should be dense vectors
+     double d1_;
+     double d2_;
+     /// type (may be useful)
+     int type_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpPlusMinusOneMatrix.cpp b/cbits/coin/ClpPlusMinusOneMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPlusMinusOneMatrix.cpp
@@ -0,0 +1,1957 @@
+/* $Id: ClpPlusMinusOneMatrix.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include <cstdio>
+
+#include "CoinPragma.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpFactorization.hpp"
+// at end to get min/max!
+#include "ClpPlusMinusOneMatrix.hpp"
+#include "ClpMessage.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix ()
+     : ClpMatrixBase()
+{
+     setType(12);
+     matrix_ = NULL;
+     startPositive_ = NULL;
+     startNegative_ = NULL;
+     lengths_ = NULL;
+     indices_ = NULL;
+     numberRows_ = 0;
+     numberColumns_ = 0;
+     columnOrdered_ = true;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix (const ClpPlusMinusOneMatrix & rhs)
+     : ClpMatrixBase(rhs)
+{
+     matrix_ = NULL;
+     startPositive_ = NULL;
+     startNegative_ = NULL;
+     lengths_ = NULL;
+     indices_ = NULL;
+     numberRows_ = rhs.numberRows_;
+     numberColumns_ = rhs.numberColumns_;
+     columnOrdered_ = rhs.columnOrdered_;
+     if (numberColumns_) {
+          CoinBigIndex numberElements = rhs.startPositive_[numberColumns_];
+          indices_ = new int [ numberElements];
+          CoinMemcpyN(rhs.indices_, numberElements, indices_);
+          startPositive_ = new CoinBigIndex [ numberColumns_+1];
+          CoinMemcpyN(rhs.startPositive_, (numberColumns_ + 1), startPositive_);
+          startNegative_ = new CoinBigIndex [ numberColumns_];
+          CoinMemcpyN(rhs.startNegative_, numberColumns_, startNegative_);
+     }
+     int numberRows = getNumRows();
+     if (rhs.rhsOffset_ && numberRows) {
+          rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows);
+     } else {
+          rhsOffset_ = NULL;
+     }
+}
+// Constructor from arrays
+ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix(int numberRows, int numberColumns,
+          bool columnOrdered, const int * indices,
+          const CoinBigIndex * startPositive,
+          const CoinBigIndex * startNegative)
+     : ClpMatrixBase()
+{
+     setType(12);
+     matrix_ = NULL;
+     lengths_ = NULL;
+     numberRows_ = numberRows;
+     numberColumns_ = numberColumns;
+     columnOrdered_ = columnOrdered;
+     int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_;
+     int numberElements = startPositive[numberMajor];
+     startPositive_ = ClpCopyOfArray(startPositive, numberMajor + 1);
+     startNegative_ = ClpCopyOfArray(startNegative, numberMajor);
+     indices_ = ClpCopyOfArray(indices, numberElements);
+     // Check valid
+     checkValid(false);
+}
+
+ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix (const CoinPackedMatrix & rhs)
+     : ClpMatrixBase()
+{
+     setType(12);
+     matrix_ = NULL;
+     startPositive_ = NULL;
+     startNegative_ = NULL;
+     lengths_ = NULL;
+     indices_ = NULL;
+     int iColumn;
+     assert (rhs.isColOrdered());
+     // get matrix data pointers
+     const int * row = rhs.getIndices();
+     const CoinBigIndex * columnStart = rhs.getVectorStarts();
+     const int * columnLength = rhs.getVectorLengths();
+     const double * elementByColumn = rhs.getElements();
+     numberColumns_ = rhs.getNumCols();
+     numberRows_ = -1;
+     indices_ = new int[rhs.getNumElements()];
+     startPositive_ = new CoinBigIndex [numberColumns_+1];
+     startNegative_ = new CoinBigIndex [numberColumns_];
+     int * temp = new int [rhs.getNumRows()];
+     CoinBigIndex j = 0;
+     CoinBigIndex numberGoodP = 0;
+     CoinBigIndex numberGoodM = 0;
+     CoinBigIndex numberBad = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          CoinBigIndex k;
+          int iNeg = 0;
+          startPositive_[iColumn] = j;
+          for (k = columnStart[iColumn]; k < columnStart[iColumn] + columnLength[iColumn];
+                    k++) {
+               int iRow;
+               if (fabs(elementByColumn[k] - 1.0) < 1.0e-10) {
+                    iRow = row[k];
+                    numberRows_ = CoinMax(numberRows_, iRow);
+                    indices_[j++] = iRow;
+                    numberGoodP++;
+               } else if (fabs(elementByColumn[k] + 1.0) < 1.0e-10) {
+                    iRow = row[k];
+                    numberRows_ = CoinMax(numberRows_, iRow);
+                    temp[iNeg++] = iRow;
+                    numberGoodM++;
+               } else {
+                    numberBad++;
+               }
+          }
+          // move negative
+          startNegative_[iColumn] = j;
+          for (k = 0; k < iNeg; k++) {
+               indices_[j++] = temp[k];
+          }
+     }
+     startPositive_[numberColumns_] = j;
+     delete [] temp;
+     if (numberBad) {
+          delete [] indices_;
+          indices_ = NULL;
+          numberRows_ = 0;
+          numberColumns_ = 0;
+          delete [] startPositive_;
+          delete [] startNegative_;
+          // Put in statistics
+          startPositive_ = new CoinBigIndex [3];
+          startPositive_[0] = numberGoodP;
+          startPositive_[1] = numberGoodM;
+          startPositive_[2] = numberBad;
+          startNegative_ = NULL;
+     } else {
+          numberRows_ ++; //  correct
+          // but number should be same as rhs
+          assert (numberRows_ <= rhs.getNumRows());
+          numberRows_ = rhs.getNumRows();
+          columnOrdered_ = true;
+     }
+     // Check valid
+     if (!numberBad)
+          checkValid(false);
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpPlusMinusOneMatrix::~ClpPlusMinusOneMatrix ()
+{
+     delete matrix_;
+     delete [] startPositive_;
+     delete [] startNegative_;
+     delete [] lengths_;
+     delete [] indices_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpPlusMinusOneMatrix &
+ClpPlusMinusOneMatrix::operator=(const ClpPlusMinusOneMatrix& rhs)
+{
+     if (this != &rhs) {
+          ClpMatrixBase::operator=(rhs);
+          delete matrix_;
+          delete [] startPositive_;
+          delete [] startNegative_;
+          delete [] lengths_;
+          delete [] indices_;
+          matrix_ = NULL;
+          startPositive_ = NULL;
+          lengths_ = NULL;
+          indices_ = NULL;
+          numberRows_ = rhs.numberRows_;
+          numberColumns_ = rhs.numberColumns_;
+          columnOrdered_ = rhs.columnOrdered_;
+          if (numberColumns_) {
+               CoinBigIndex numberElements = rhs.startPositive_[numberColumns_];
+               indices_ = new int [ numberElements];
+               CoinMemcpyN(rhs.indices_, numberElements, indices_);
+               startPositive_ = new CoinBigIndex [ numberColumns_+1];
+               CoinMemcpyN(rhs.startPositive_, (numberColumns_ + 1), startPositive_);
+               startNegative_ = new CoinBigIndex [ numberColumns_];
+               CoinMemcpyN(rhs.startNegative_, numberColumns_, startNegative_);
+          }
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpMatrixBase * ClpPlusMinusOneMatrix::clone() const
+{
+     return new ClpPlusMinusOneMatrix(*this);
+}
+/* Subset clone (without gaps).  Duplicates are allowed
+   and order is as given */
+ClpMatrixBase *
+ClpPlusMinusOneMatrix::subsetClone (int numberRows, const int * whichRows,
+                                    int numberColumns,
+                                    const int * whichColumns) const
+{
+     return new ClpPlusMinusOneMatrix(*this, numberRows, whichRows,
+                                      numberColumns, whichColumns);
+}
+/* Subset constructor (without gaps).  Duplicates are allowed
+   and order is as given */
+ClpPlusMinusOneMatrix::ClpPlusMinusOneMatrix (
+     const ClpPlusMinusOneMatrix & rhs,
+     int numberRows, const int * whichRow,
+     int numberColumns, const int * whichColumn)
+     : ClpMatrixBase(rhs)
+{
+     matrix_ = NULL;
+     startPositive_ = NULL;
+     startNegative_ = NULL;
+     lengths_ = NULL;
+     indices_ = NULL;
+     numberRows_ = 0;
+     numberColumns_ = 0;
+     columnOrdered_ = rhs.columnOrdered_;
+     if (numberRows <= 0 || numberColumns <= 0) {
+          startPositive_ = new CoinBigIndex [1];
+          startPositive_[0] = 0;
+     } else {
+          numberColumns_ = numberColumns;
+          numberRows_ = numberRows;
+          const int * index1 = rhs.indices_;
+          CoinBigIndex * startPositive1 = rhs.startPositive_;
+
+          int numberMinor = (!columnOrdered_) ? numberColumns_ : numberRows_;
+          int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_;
+          int numberMinor1 = (!columnOrdered_) ? rhs.numberColumns_ : rhs.numberRows_;
+          int numberMajor1 = (columnOrdered_) ? rhs.numberColumns_ : rhs.numberRows_;
+          // Also swap incoming if not column ordered
+          if (!columnOrdered_) {
+               int temp1 = numberRows;
+               numberRows = numberColumns;
+               numberColumns = temp1;
+               const int * temp2;
+               temp2 = whichRow;
+               whichRow = whichColumn;
+               whichColumn = temp2;
+          }
+          // Throw exception if rhs empty
+          if (numberMajor1 <= 0 || numberMinor1 <= 0)
+               throw CoinError("empty rhs", "subset constructor", "ClpPlusMinusOneMatrix");
+          // Array to say if an old row is in new copy
+          int * newRow = new int [numberMinor1];
+          int iRow;
+          for (iRow = 0; iRow < numberMinor1; iRow++)
+               newRow[iRow] = -1;
+          // and array for duplicating rows
+          int * duplicateRow = new int [numberMinor];
+          int numberBad = 0;
+          for (iRow = 0; iRow < numberMinor; iRow++) {
+               duplicateRow[iRow] = -1;
+               int kRow = whichRow[iRow];
+               if (kRow >= 0  && kRow < numberMinor1) {
+                    if (newRow[kRow] < 0) {
+                         // first time
+                         newRow[kRow] = iRow;
+                    } else {
+                         // duplicate
+                         int lastRow = newRow[kRow];
+                         newRow[kRow] = iRow;
+                         duplicateRow[iRow] = lastRow;
+                    }
+               } else {
+                    // bad row
+                    numberBad++;
+               }
+          }
+
+          if (numberBad)
+               throw CoinError("bad minor entries",
+                               "subset constructor", "ClpPlusMinusOneMatrix");
+          // now get size and check columns
+          CoinBigIndex size = 0;
+          int iColumn;
+          numberBad = 0;
+          for (iColumn = 0; iColumn < numberMajor; iColumn++) {
+               int kColumn = whichColumn[iColumn];
+               if (kColumn >= 0  && kColumn < numberMajor1) {
+                    CoinBigIndex i;
+                    for (i = startPositive1[kColumn]; i < startPositive1[kColumn+1]; i++) {
+                         int kRow = index1[i];
+                         kRow = newRow[kRow];
+                         while (kRow >= 0) {
+                              size++;
+                              kRow = duplicateRow[kRow];
+                         }
+                    }
+               } else {
+                    // bad column
+                    numberBad++;
+                    printf("%d %d %d %d\n", iColumn, numberMajor, numberMajor1, kColumn);
+               }
+          }
+          if (numberBad)
+               throw CoinError("bad major entries",
+                               "subset constructor", "ClpPlusMinusOneMatrix");
+          // now create arrays
+          startPositive_ = new CoinBigIndex [numberMajor+1];
+          startNegative_ = new CoinBigIndex [numberMajor];
+          indices_ = new int[size];
+          // and fill them
+          size = 0;
+          startPositive_[0] = 0;
+          CoinBigIndex * startNegative1 = rhs.startNegative_;
+          for (iColumn = 0; iColumn < numberMajor; iColumn++) {
+               int kColumn = whichColumn[iColumn];
+               CoinBigIndex i;
+               for (i = startPositive1[kColumn]; i < startNegative1[kColumn]; i++) {
+                    int kRow = index1[i];
+                    kRow = newRow[kRow];
+                    while (kRow >= 0) {
+                         indices_[size++] = kRow;
+                         kRow = duplicateRow[kRow];
+                    }
+               }
+               startNegative_[iColumn] = size;
+               for (; i < startPositive1[kColumn+1]; i++) {
+                    int kRow = index1[i];
+                    kRow = newRow[kRow];
+                    while (kRow >= 0) {
+                         indices_[size++] = kRow;
+                         kRow = duplicateRow[kRow];
+                    }
+               }
+               startPositive_[iColumn+1] = size;
+          }
+          delete [] newRow;
+          delete [] duplicateRow;
+     }
+     // Check valid
+     checkValid(false);
+}
+
+
+/* Returns a new matrix in reverse order without gaps */
+ClpMatrixBase *
+ClpPlusMinusOneMatrix::reverseOrderedCopy() const
+{
+     int numberMinor = (!columnOrdered_) ? numberColumns_ : numberRows_;
+     int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_;
+     // count number in each row/column
+     CoinBigIndex * tempP = new CoinBigIndex [numberMinor];
+     CoinBigIndex * tempN = new CoinBigIndex [numberMinor];
+     memset(tempP, 0, numberMinor * sizeof(CoinBigIndex));
+     memset(tempN, 0, numberMinor * sizeof(CoinBigIndex));
+     CoinBigIndex j = 0;
+     int i;
+     for (i = 0; i < numberMajor; i++) {
+          for (; j < startNegative_[i]; j++) {
+               int iRow = indices_[j];
+               tempP[iRow]++;
+          }
+          for (; j < startPositive_[i+1]; j++) {
+               int iRow = indices_[j];
+               tempN[iRow]++;
+          }
+     }
+     int * newIndices = new int [startPositive_[numberMajor]];
+     CoinBigIndex * newP = new CoinBigIndex [numberMinor+1];
+     CoinBigIndex * newN = new CoinBigIndex[numberMinor];
+     int iRow;
+     j = 0;
+     // do starts
+     for (iRow = 0; iRow < numberMinor; iRow++) {
+          newP[iRow] = j;
+          j += tempP[iRow];
+          tempP[iRow] = newP[iRow];
+          newN[iRow] = j;
+          j += tempN[iRow];
+          tempN[iRow] = newN[iRow];
+     }
+     newP[numberMinor] = j;
+     j = 0;
+     for (i = 0; i < numberMajor; i++) {
+          for (; j < startNegative_[i]; j++) {
+               int iRow = indices_[j];
+               CoinBigIndex put = tempP[iRow];
+               newIndices[put++] = i;
+               tempP[iRow] = put;
+          }
+          for (; j < startPositive_[i+1]; j++) {
+               int iRow = indices_[j];
+               CoinBigIndex put = tempN[iRow];
+               newIndices[put++] = i;
+               tempN[iRow] = put;
+          }
+     }
+     delete [] tempP;
+     delete [] tempN;
+     ClpPlusMinusOneMatrix * newCopy = new ClpPlusMinusOneMatrix();
+     newCopy->passInCopy(numberMinor, numberMajor,
+                         !columnOrdered_,  newIndices, newP, newN);
+     return newCopy;
+}
+//unscaled versions
+void
+ClpPlusMinusOneMatrix::times(double scalar,
+                             const double * x, double * y) const
+{
+     int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_;
+     int i;
+     CoinBigIndex j;
+     assert (columnOrdered_);
+     for (i = 0; i < numberMajor; i++) {
+          double value = scalar * x[i];
+          if (value) {
+               for (j = startPositive_[i]; j < startNegative_[i]; j++) {
+                    int iRow = indices_[j];
+                    y[iRow] += value;
+               }
+               for (; j < startPositive_[i+1]; j++) {
+                    int iRow = indices_[j];
+                    y[iRow] -= value;
+               }
+          }
+     }
+}
+void
+ClpPlusMinusOneMatrix::transposeTimes(double scalar,
+                                      const double * x, double * y) const
+{
+     int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_;
+     int i;
+     CoinBigIndex j = 0;
+     assert (columnOrdered_);
+     for (i = 0; i < numberMajor; i++) {
+          double value = 0.0;
+          for (; j < startNegative_[i]; j++) {
+               int iRow = indices_[j];
+               value += x[iRow];
+          }
+          for (; j < startPositive_[i+1]; j++) {
+               int iRow = indices_[j];
+               value -= x[iRow];
+          }
+          y[i] += scalar * value;
+     }
+}
+void
+ClpPlusMinusOneMatrix::times(double scalar,
+                             const double * x, double * y,
+                             const double * /*rowScale*/,
+                             const double * /*columnScale*/) const
+{
+     // we know it is not scaled
+     times(scalar, x, y);
+}
+void
+ClpPlusMinusOneMatrix::transposeTimes( double scalar,
+                                       const double * x, double * y,
+                                       const double * /*rowScale*/,
+                                       const double * /*columnScale*/,
+                                       double * /*spare*/) const
+{
+     // we know it is not scaled
+     transposeTimes(scalar, x, y);
+}
+/* Return <code>x * A + y</code> in <code>z</code>.
+	Squashes small elements and knows about ClpSimplex */
+void
+ClpPlusMinusOneMatrix::transposeTimes(const ClpSimplex * model, double scalar,
+                                      const CoinIndexedVector * rowArray,
+                                      CoinIndexedVector * y,
+                                      CoinIndexedVector * columnArray) const
+{
+     // we know it is not scaled
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     int numberNonZero = 0;
+     int * index = columnArray->getIndices();
+     double * array = columnArray->denseVector();
+     int numberInRowArray = rowArray->getNumElements();
+     // maybe I need one in OsiSimplex
+     double zeroTolerance = model->zeroTolerance();
+     int numberRows = model->numberRows();
+     bool packed = rowArray->packedMode();
+#ifndef NO_RTTI
+     ClpPlusMinusOneMatrix* rowCopy =
+          dynamic_cast< ClpPlusMinusOneMatrix*>(model->rowCopy());
+#else
+     ClpPlusMinusOneMatrix* rowCopy =
+          static_cast< ClpPlusMinusOneMatrix*>(model->rowCopy());
+#endif
+     double factor = 0.3;
+     // We may not want to do by row if there may be cache problems
+     int numberColumns = model->numberColumns();
+     // It would be nice to find L2 cache size - for moment 512K
+     // Be slightly optimistic
+     if (numberColumns * sizeof(double) > 1000000) {
+          if (numberRows * 10 < numberColumns)
+               factor = 0.1;
+          else if (numberRows * 4 < numberColumns)
+               factor = 0.15;
+          else if (numberRows * 2 < numberColumns)
+               factor = 0.2;
+     }
+     if (numberInRowArray > factor * numberRows || !rowCopy) {
+          assert (!y->getNumElements());
+          // do by column
+          // Need to expand if packed mode
+          int iColumn;
+          CoinBigIndex j = 0;
+          assert (columnOrdered_);
+          if (packed) {
+               // need to expand pi into y
+               assert(y->capacity() >= numberRows);
+               double * piOld = pi;
+               pi = y->denseVector();
+               const int * whichRow = rowArray->getIndices();
+               int i;
+               // modify pi so can collapse to one loop
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = scalar * piOld[i];
+               }
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double value = 0.0;
+                    for (; j < startNegative_[iColumn]; j++) {
+                         int iRow = indices_[j];
+                         value += pi[iRow];
+                    }
+                    for (; j < startPositive_[iColumn+1]; j++) {
+                         int iRow = indices_[j];
+                         value -= pi[iRow];
+                    }
+                    if (fabs(value) > zeroTolerance) {
+                         array[numberNonZero] = value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               }
+               for (i = 0; i < numberInRowArray; i++) {
+                    int iRow = whichRow[i];
+                    pi[iRow] = 0.0;
+               }
+          } else {
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double value = 0.0;
+                    for (; j < startNegative_[iColumn]; j++) {
+                         int iRow = indices_[j];
+                         value += pi[iRow];
+                    }
+                    for (; j < startPositive_[iColumn+1]; j++) {
+                         int iRow = indices_[j];
+                         value -= pi[iRow];
+                    }
+                    value *= scalar;
+                    if (fabs(value) > zeroTolerance) {
+                         index[numberNonZero++] = iColumn;
+                         array[iColumn] = value;
+                    }
+               }
+          }
+          columnArray->setNumElements(numberNonZero);
+     } else {
+          // do by row
+          rowCopy->transposeTimesByRow(model, scalar, rowArray, y, columnArray);
+     }
+}
+/* Return <code>x * A + y</code> in <code>z</code>.
+	Squashes small elements and knows about ClpSimplex */
+void
+ClpPlusMinusOneMatrix::transposeTimesByRow(const ClpSimplex * model, double scalar,
+          const CoinIndexedVector * rowArray,
+          CoinIndexedVector * y,
+          CoinIndexedVector * columnArray) const
+{
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     int numberNonZero = 0;
+     int * index = columnArray->getIndices();
+     double * array = columnArray->denseVector();
+     int numberInRowArray = rowArray->getNumElements();
+     // maybe I need one in OsiSimplex
+     double zeroTolerance = model->zeroTolerance();
+     const int * column = indices_;
+     const CoinBigIndex * startPositive = startPositive_;
+     const CoinBigIndex * startNegative = startNegative_;
+     const int * whichRow = rowArray->getIndices();
+     bool packed = rowArray->packedMode();
+     if (numberInRowArray > 2) {
+          // do by rows
+          int iRow;
+          double * markVector = y->denseVector(); // probably empty .. but
+          int numberOriginal = 0;
+          int i;
+          if (packed) {
+               numberNonZero = 0;
+               // and set up mark as char array
+               char * marked = reinterpret_cast<char *> (index + columnArray->capacity());
+               double * array2 = y->denseVector();
+#ifdef CLP_DEBUG
+               int numberColumns = model->numberColumns();
+               for (i = 0; i < numberColumns; i++) {
+                    assert(!marked[i]);
+                    assert(!array2[i]);
+               }
+#endif
+               for (i = 0; i < numberInRowArray; i++) {
+                    iRow = whichRow[i];
+                    double value = pi[i] * scalar;
+                    CoinBigIndex j;
+                    for (j = startPositive[iRow]; j < startNegative[iRow]; j++) {
+                         int iColumn = column[j];
+                         if (!marked[iColumn]) {
+                              marked[iColumn] = 1;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         array2[iColumn] += value;
+                    }
+                    for (j = startNegative[iRow]; j < startPositive[iRow+1]; j++) {
+                         int iColumn = column[j];
+                         if (!marked[iColumn]) {
+                              marked[iColumn] = 1;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         array2[iColumn] -= value;
+                    }
+               }
+               // get rid of tiny values and zero out marked
+               numberOriginal = numberNonZero;
+               numberNonZero = 0;
+               for (i = 0; i < numberOriginal; i++) {
+                    int iColumn = index[i];
+                    if (marked[iColumn]) {
+                         double value = array2[iColumn];
+                         array2[iColumn] = 0.0;
+                         marked[iColumn] = 0;
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+          } else {
+               numberNonZero = 0;
+               // and set up mark as char array
+               char * marked = reinterpret_cast<char *> (markVector);
+               for (i = 0; i < numberOriginal; i++) {
+                    int iColumn = index[i];
+                    marked[iColumn] = 0;
+               }
+               for (i = 0; i < numberInRowArray; i++) {
+                    iRow = whichRow[i];
+                    double value = pi[iRow] * scalar;
+                    CoinBigIndex j;
+                    for (j = startPositive[iRow]; j < startNegative[iRow]; j++) {
+                         int iColumn = column[j];
+                         if (!marked[iColumn]) {
+                              marked[iColumn] = 1;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         array[iColumn] += value;
+                    }
+                    for (j = startNegative[iRow]; j < startPositive[iRow+1]; j++) {
+                         int iColumn = column[j];
+                         if (!marked[iColumn]) {
+                              marked[iColumn] = 1;
+                              index[numberNonZero++] = iColumn;
+                         }
+                         array[iColumn] -= value;
+                    }
+               }
+               // get rid of tiny values and zero out marked
+               numberOriginal = numberNonZero;
+               numberNonZero = 0;
+               for (i = 0; i < numberOriginal; i++) {
+                    int iColumn = index[i];
+                    marked[iColumn] = 0;
+                    if (fabs(array[iColumn]) > zeroTolerance) {
+                         index[numberNonZero++] = iColumn;
+                    } else {
+                         array[iColumn] = 0.0;
+                    }
+               }
+          }
+     } else if (numberInRowArray == 2) {
+          /* do by rows when two rows (do longer first when not packed
+             and shorter first if packed */
+          int iRow0 = whichRow[0];
+          int iRow1 = whichRow[1];
+          CoinBigIndex j;
+          if (packed) {
+               double pi0 = pi[0];
+               double pi1 = pi[1];
+               if (startPositive[iRow0+1] - startPositive[iRow0] >
+                         startPositive[iRow1+1] - startPositive[iRow1]) {
+                    int temp = iRow0;
+                    iRow0 = iRow1;
+                    iRow1 = temp;
+                    pi0 = pi1;
+                    pi1 = pi[0];
+               }
+               // and set up mark as char array
+               char * marked = reinterpret_cast<char *> (index + columnArray->capacity());
+               int * lookup = y->getIndices();
+               double value = pi0 * scalar;
+               for (j = startPositive[iRow0]; j < startNegative[iRow0]; j++) {
+                    int iColumn = column[j];
+                    array[numberNonZero] = value;
+                    marked[iColumn] = 1;
+                    lookup[iColumn] = numberNonZero;
+                    index[numberNonZero++] = iColumn;
+               }
+               for (j = startNegative[iRow0]; j < startPositive[iRow0+1]; j++) {
+                    int iColumn = column[j];
+                    array[numberNonZero] = -value;
+                    marked[iColumn] = 1;
+                    lookup[iColumn] = numberNonZero;
+                    index[numberNonZero++] = iColumn;
+               }
+               int numberOriginal = numberNonZero;
+               value = pi1 * scalar;
+               for (j = startPositive[iRow1]; j < startNegative[iRow1]; j++) {
+                    int iColumn = column[j];
+                    if (marked[iColumn]) {
+                         int iLookup = lookup[iColumn];
+                         array[iLookup] += value;
+                    } else {
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+               for (j = startNegative[iRow1]; j < startPositive[iRow1+1]; j++) {
+                    int iColumn = column[j];
+                    if (marked[iColumn]) {
+                         int iLookup = lookup[iColumn];
+                         array[iLookup] -= value;
+                    } else {
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = -value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+               // get rid of tiny values and zero out marked
+               int nDelete = 0;
+               for (j = 0; j < numberOriginal; j++) {
+                    int iColumn = index[j];
+                    marked[iColumn] = 0;
+                    if (fabs(array[j]) <= zeroTolerance)
+                         nDelete++;
+               }
+               if (nDelete) {
+                    numberOriginal = numberNonZero;
+                    numberNonZero = 0;
+                    for (j = 0; j < numberOriginal; j++) {
+                         int iColumn = index[j];
+                         double value = array[j];
+                         array[j] = 0.0;
+                         if (fabs(value) > zeroTolerance) {
+                              array[numberNonZero] = value;
+                              index[numberNonZero++] = iColumn;
+                         }
+                    }
+               }
+          } else {
+               if (startPositive[iRow0+1] - startPositive[iRow0] <
+                         startPositive[iRow1+1] - startPositive[iRow1]) {
+                    int temp = iRow0;
+                    iRow0 = iRow1;
+                    iRow1 = temp;
+               }
+               int numberOriginal;
+               int i;
+               numberNonZero = 0;
+               double value;
+               value = pi[iRow0] * scalar;
+               CoinBigIndex j;
+               for (j = startPositive[iRow0]; j < startNegative[iRow0]; j++) {
+                    int iColumn = column[j];
+                    index[numberNonZero++] = iColumn;
+                    array[iColumn] = value;
+               }
+               for (j = startNegative[iRow0]; j < startPositive[iRow0+1]; j++) {
+                    int iColumn = column[j];
+                    index[numberNonZero++] = iColumn;
+                    array[iColumn] = -value;
+               }
+               value = pi[iRow1] * scalar;
+               for (j = startPositive[iRow1]; j < startNegative[iRow1]; j++) {
+                    int iColumn = column[j];
+                    double value2 = array[iColumn];
+                    if (value2) {
+                         value2 += value;
+                    } else {
+                         value2 = value;
+                         index[numberNonZero++] = iColumn;
+                    }
+                    array[iColumn] = value2;
+               }
+               for (j = startNegative[iRow1]; j < startPositive[iRow1+1]; j++) {
+                    int iColumn = column[j];
+                    double value2 = array[iColumn];
+                    if (value2) {
+                         value2 -= value;
+                    } else {
+                         value2 = -value;
+                         index[numberNonZero++] = iColumn;
+                    }
+                    array[iColumn] = value2;
+               }
+               // get rid of tiny values and zero out marked
+               numberOriginal = numberNonZero;
+               numberNonZero = 0;
+               for (i = 0; i < numberOriginal; i++) {
+                    int iColumn = index[i];
+                    if (fabs(array[iColumn]) > zeroTolerance) {
+                         index[numberNonZero++] = iColumn;
+                    } else {
+                         array[iColumn] = 0.0;
+                    }
+               }
+          }
+     } else if (numberInRowArray == 1) {
+          // Just one row
+          int iRow = rowArray->getIndices()[0];
+          numberNonZero = 0;
+          double value;
+          iRow = whichRow[0];
+          CoinBigIndex j;
+          if (packed) {
+               value = pi[0] * scalar;
+               if (fabs(value) > zeroTolerance) {
+                    for (j = startPositive[iRow]; j < startNegative[iRow]; j++) {
+                         int iColumn = column[j];
+                         array[numberNonZero] = value;
+                         index[numberNonZero++] = iColumn;
+                    }
+                    for (j = startNegative[iRow]; j < startPositive[iRow+1]; j++) {
+                         int iColumn = column[j];
+                         array[numberNonZero] = -value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               }
+          } else {
+               value = pi[iRow] * scalar;
+               if (fabs(value) > zeroTolerance) {
+                    for (j = startPositive[iRow]; j < startNegative[iRow]; j++) {
+                         int iColumn = column[j];
+                         array[iColumn] = value;
+                         index[numberNonZero++] = iColumn;
+                    }
+                    for (j = startNegative[iRow]; j < startPositive[iRow+1]; j++) {
+                         int iColumn = column[j];
+                         array[iColumn] = -value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               }
+          }
+     }
+     columnArray->setNumElements(numberNonZero);
+     if (packed)
+          columnArray->setPacked();
+     y->setNumElements(0);
+}
+/* Return <code>x *A in <code>z</code> but
+   just for indices in y. */
+void
+ClpPlusMinusOneMatrix::subsetTransposeTimes(const ClpSimplex * ,
+          const CoinIndexedVector * rowArray,
+          const CoinIndexedVector * y,
+          CoinIndexedVector * columnArray) const
+{
+     columnArray->clear();
+     double * pi = rowArray->denseVector();
+     double * array = columnArray->denseVector();
+     int jColumn;
+     int numberToDo = y->getNumElements();
+     const int * which = y->getIndices();
+     assert (!rowArray->packedMode());
+     columnArray->setPacked();
+     for (jColumn = 0; jColumn < numberToDo; jColumn++) {
+          int iColumn = which[jColumn];
+          double value = 0.0;
+          CoinBigIndex j = startPositive_[iColumn];
+          for (; j < startNegative_[iColumn]; j++) {
+               int iRow = indices_[j];
+               value += pi[iRow];
+          }
+          for (; j < startPositive_[iColumn+1]; j++) {
+               int iRow = indices_[j];
+               value -= pi[iRow];
+          }
+          array[jColumn] = value;
+     }
+}
+/// returns number of elements in column part of basis,
+CoinBigIndex
+ClpPlusMinusOneMatrix::countBasis(const int * whichColumn,
+                                  int & numberColumnBasic)
+{
+     int i;
+     CoinBigIndex numberElements = 0;
+     for (i = 0; i < numberColumnBasic; i++) {
+          int iColumn = whichColumn[i];
+          numberElements += startPositive_[iColumn+1] - startPositive_[iColumn];
+     }
+     return numberElements;
+}
+void
+ClpPlusMinusOneMatrix::fillBasis(ClpSimplex * ,
+                                 const int * whichColumn,
+                                 int & numberColumnBasic,
+                                 int * indexRowU, int * start,
+                                 int * rowCount, int * columnCount,
+                                 CoinFactorizationDouble * elementU)
+{
+     int i;
+     CoinBigIndex numberElements = start[0];
+     assert (columnOrdered_);
+     for (i = 0; i < numberColumnBasic; i++) {
+          int iColumn = whichColumn[i];
+          CoinBigIndex j = startPositive_[iColumn];
+          for (; j < startNegative_[iColumn]; j++) {
+               int iRow = indices_[j];
+               indexRowU[numberElements] = iRow;
+               rowCount[iRow]++;
+               elementU[numberElements++] = 1.0;
+          }
+          for (; j < startPositive_[iColumn+1]; j++) {
+               int iRow = indices_[j];
+               indexRowU[numberElements] = iRow;
+               rowCount[iRow]++;
+               elementU[numberElements++] = -1.0;
+          }
+          start[i+1] = numberElements;
+          columnCount[i] = numberElements - start[i];
+     }
+}
+/* Unpacks a column into an CoinIndexedvector
+ */
+void
+ClpPlusMinusOneMatrix::unpack(const ClpSimplex * ,
+                              CoinIndexedVector * rowArray,
+                              int iColumn) const
+{
+     CoinBigIndex j = startPositive_[iColumn];
+     for (; j < startNegative_[iColumn]; j++) {
+          int iRow = indices_[j];
+          rowArray->add(iRow, 1.0);
+     }
+     for (; j < startPositive_[iColumn+1]; j++) {
+          int iRow = indices_[j];
+          rowArray->add(iRow, -1.0);
+     }
+}
+/* Unpacks a column into an CoinIndexedvector
+** in packed foramt
+Note that model is NOT const.  Bounds and objective could
+be modified if doing column generation (just for this variable) */
+void
+ClpPlusMinusOneMatrix::unpackPacked(ClpSimplex * ,
+                                    CoinIndexedVector * rowArray,
+                                    int iColumn) const
+{
+     int * index = rowArray->getIndices();
+     double * array = rowArray->denseVector();
+     int number = 0;
+     CoinBigIndex j = startPositive_[iColumn];
+     for (; j < startNegative_[iColumn]; j++) {
+          int iRow = indices_[j];
+          array[number] = 1.0;
+          index[number++] = iRow;
+     }
+     for (; j < startPositive_[iColumn+1]; j++) {
+          int iRow = indices_[j];
+          array[number] = -1.0;
+          index[number++] = iRow;
+     }
+     rowArray->setNumElements(number);
+     rowArray->setPackedMode(true);
+}
+/* Adds multiple of a column into an CoinIndexedvector
+      You can use quickAdd to add to vector */
+void
+ClpPlusMinusOneMatrix::add(const ClpSimplex * , CoinIndexedVector * rowArray,
+                           int iColumn, double multiplier) const
+{
+     CoinBigIndex j = startPositive_[iColumn];
+     for (; j < startNegative_[iColumn]; j++) {
+          int iRow = indices_[j];
+          rowArray->quickAdd(iRow, multiplier);
+     }
+     for (; j < startPositive_[iColumn+1]; j++) {
+          int iRow = indices_[j];
+          rowArray->quickAdd(iRow, -multiplier);
+     }
+}
+/* Adds multiple of a column into an array */
+void
+ClpPlusMinusOneMatrix::add(const ClpSimplex * , double * array,
+                           int iColumn, double multiplier) const
+{
+     CoinBigIndex j = startPositive_[iColumn];
+     for (; j < startNegative_[iColumn]; j++) {
+          int iRow = indices_[j];
+          array[iRow] += multiplier;
+     }
+     for (; j < startPositive_[iColumn+1]; j++) {
+          int iRow = indices_[j];
+          array[iRow] -= multiplier;
+     }
+}
+
+// Return a complete CoinPackedMatrix
+CoinPackedMatrix *
+ClpPlusMinusOneMatrix::getPackedMatrix() const
+{
+     if (!matrix_) {
+          int numberMinor = (!columnOrdered_) ? numberColumns_ : numberRows_;
+          int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_;
+          int numberElements = startPositive_[numberMajor];
+          double * elements = new double [numberElements];
+          CoinBigIndex j = 0;
+          int i;
+          for (i = 0; i < numberMajor; i++) {
+               for (; j < startNegative_[i]; j++) {
+                    elements[j] = 1.0;
+               }
+               for (; j < startPositive_[i+1]; j++) {
+                    elements[j] = -1.0;
+               }
+          }
+          matrix_ =  new CoinPackedMatrix(columnOrdered_, numberMinor, numberMajor,
+                                          getNumElements(),
+                                          elements, indices_,
+                                          startPositive_, getVectorLengths());
+          delete [] elements;
+          delete [] lengths_;
+          lengths_ = NULL;
+     }
+     return matrix_;
+}
+/* A vector containing the elements in the packed matrix. Note that there
+   might be gaps in this list, entries that do not belong to any
+   major-dimension vector. To get the actual elements one should look at
+   this vector together with vectorStarts and vectorLengths. */
+const double *
+ClpPlusMinusOneMatrix::getElements() const
+{
+     if (!matrix_)
+          getPackedMatrix();
+     return matrix_->getElements();
+}
+
+const CoinBigIndex *
+ClpPlusMinusOneMatrix::getVectorStarts() const
+{
+     return startPositive_;
+}
+/* The lengths of the major-dimension vectors. */
+const int *
+ClpPlusMinusOneMatrix::getVectorLengths() const
+{
+     if (!lengths_) {
+          int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_;
+          lengths_ = new int [numberMajor];
+          int i;
+          for (i = 0; i < numberMajor; i++) {
+               lengths_[i] = startPositive_[i+1] - startPositive_[i];
+          }
+     }
+     return lengths_;
+}
+/* Delete the columns whose indices are listed in <code>indDel</code>. */
+void
+ClpPlusMinusOneMatrix::deleteCols(const int numDel, const int * indDel)
+{
+     int iColumn;
+     CoinBigIndex newSize = startPositive_[numberColumns_];;
+     int numberBad = 0;
+     // Use array to make sure we can have duplicates
+     int * which = new int[numberColumns_];
+     memset(which, 0, numberColumns_ * sizeof(int));
+     int nDuplicate = 0;
+     for (iColumn = 0; iColumn < numDel; iColumn++) {
+          int jColumn = indDel[iColumn];
+          if (jColumn < 0 || jColumn >= numberColumns_) {
+               numberBad++;
+          } else {
+               newSize -= startPositive_[jColumn+1] - startPositive_[jColumn];
+               if (which[jColumn])
+                    nDuplicate++;
+               else
+                    which[jColumn] = 1;
+          }
+     }
+     if (numberBad)
+          throw CoinError("Indices out of range", "deleteCols", "ClpPlusMinusOneMatrix");
+     int newNumber = numberColumns_ - numDel + nDuplicate;
+     // Get rid of temporary arrays
+     delete [] lengths_;
+     lengths_ = NULL;
+     delete matrix_;
+     matrix_ = NULL;
+     CoinBigIndex * newPositive = new CoinBigIndex [newNumber+1];
+     CoinBigIndex * newNegative = new CoinBigIndex [newNumber];
+     int * newIndices = new int [newSize];
+     newNumber = 0;
+     newSize = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (!which[iColumn]) {
+               CoinBigIndex start, end;
+               CoinBigIndex i;
+               start = startPositive_[iColumn];
+               end = startNegative_[iColumn];
+               newPositive[newNumber] = newSize;
+               for (i = start; i < end; i++)
+                    newIndices[newSize++] = indices_[i];
+               start = startNegative_[iColumn];
+               end = startPositive_[iColumn+1];
+               newNegative[newNumber++] = newSize;
+               for (i = start; i < end; i++)
+                    newIndices[newSize++] = indices_[i];
+          }
+     }
+     newPositive[newNumber] = newSize;
+     delete [] which;
+     delete [] startPositive_;
+     startPositive_ = newPositive;
+     delete [] startNegative_;
+     startNegative_ = newNegative;
+     delete [] indices_;
+     indices_ = newIndices;
+     numberColumns_ = newNumber;
+}
+/* Delete the rows whose indices are listed in <code>indDel</code>. */
+void
+ClpPlusMinusOneMatrix::deleteRows(const int numDel, const int * indDel)
+{
+     int iRow;
+     int numberBad = 0;
+     // Use array to make sure we can have duplicates
+     int * which = new int[numberRows_];
+     memset(which, 0, numberRows_ * sizeof(int));
+     int nDuplicate = 0;
+     for (iRow = 0; iRow < numDel; iRow++) {
+          int jRow = indDel[iRow];
+          if (jRow < 0 || jRow >= numberRows_) {
+               numberBad++;
+          } else {
+               if (which[jRow])
+                    nDuplicate++;
+               else
+                    which[jRow] = 1;
+          }
+     }
+     if (numberBad)
+          throw CoinError("Indices out of range", "deleteRows", "ClpPlusMinusOneMatrix");
+     CoinBigIndex iElement;
+     CoinBigIndex numberElements = startPositive_[numberColumns_];
+     CoinBigIndex newSize = 0;
+     for (iElement = 0; iElement < numberElements; iElement++) {
+          iRow = indices_[iElement];
+          if (!which[iRow])
+               newSize++;
+     }
+     int newNumber = numberRows_ - numDel + nDuplicate;
+     // Get rid of temporary arrays
+     delete [] lengths_;
+     lengths_ = NULL;
+     delete matrix_;
+     matrix_ = NULL;
+     int * newIndices = new int [newSize];
+     newSize = 0;
+     int iColumn;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          CoinBigIndex start, end;
+          CoinBigIndex i;
+          start = startPositive_[iColumn];
+          end = startNegative_[iColumn];
+          startPositive_[newNumber] = newSize;
+          for (i = start; i < end; i++) {
+               iRow = indices_[i];
+               if (!which[iRow])
+                    newIndices[newSize++] = iRow;
+          }
+          start = startNegative_[iColumn];
+          end = startPositive_[iColumn+1];
+          startNegative_[newNumber] = newSize;
+          for (i = start; i < end; i++) {
+               iRow = indices_[i];
+               if (!which[iRow])
+                    newIndices[newSize++] = iRow;
+          }
+     }
+     startPositive_[numberColumns_] = newSize;
+     delete [] which;
+     delete [] indices_;
+     indices_ = newIndices;
+     numberRows_ = newNumber;
+}
+bool
+ClpPlusMinusOneMatrix::isColOrdered() const
+{
+     return columnOrdered_;
+}
+/* Number of entries in the packed matrix. */
+CoinBigIndex
+ClpPlusMinusOneMatrix::getNumElements() const
+{
+     int numberMajor = (columnOrdered_) ? numberColumns_ : numberRows_;
+     if (startPositive_)
+          return startPositive_[numberMajor];
+     else
+          return 0;
+}
+// pass in copy (object takes ownership)
+void
+ClpPlusMinusOneMatrix::passInCopy(int numberRows, int numberColumns,
+                                  bool columnOrdered, int * indices,
+                                  CoinBigIndex * startPositive, CoinBigIndex * startNegative)
+{
+     columnOrdered_ = columnOrdered;
+     startPositive_ = startPositive;
+     startNegative_ = startNegative;
+     indices_ = indices;
+     numberRows_ = numberRows;
+     numberColumns_ = numberColumns;
+     // Check valid
+     checkValid(false);
+}
+// Just checks matrix valid - will say if dimensions not quite right if detail
+void
+ClpPlusMinusOneMatrix::checkValid(bool detail) const
+{
+     int maxIndex = -1;
+     int minIndex = columnOrdered_ ? numberRows_ : numberColumns_;
+     int number = !columnOrdered_ ? numberRows_ : numberColumns_;
+     int numberElements = getNumElements();
+     CoinBigIndex last = -1;
+     int bad = 0;
+     for (int i = 0; i < number; i++) {
+          if(startPositive_[i] < last)
+               bad++;
+          else
+               last = startPositive_[i];
+          if(startNegative_[i] < last)
+               bad++;
+          else
+               last = startNegative_[i];
+     }
+     if(startPositive_[number] < last)
+          bad++;
+     CoinAssertHint(!bad, "starts are not monotonic");
+     for (CoinBigIndex cbi = 0; cbi < numberElements; cbi++) {
+          maxIndex = CoinMax(indices_[cbi], maxIndex);
+          minIndex = CoinMin(indices_[cbi], minIndex);
+     }
+     CoinAssert(maxIndex < (columnOrdered_ ? numberRows_ : numberColumns_));
+     CoinAssert(minIndex >= 0);
+     if (detail) {
+          if (minIndex > 0 || maxIndex + 1 < (columnOrdered_ ? numberRows_ : numberColumns_))
+               printf("Not full range of indices - %d to %d\n", minIndex, maxIndex);
+     }
+}
+/* Given positive integer weights for each row fills in sum of weights
+   for each column (and slack).
+   Returns weights vector
+*/
+CoinBigIndex *
+ClpPlusMinusOneMatrix::dubiousWeights(const ClpSimplex * model, int * inputWeights) const
+{
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     int number = numberRows + numberColumns;
+     CoinBigIndex * weights = new CoinBigIndex[number];
+     int i;
+     for (i = 0; i < numberColumns; i++) {
+          CoinBigIndex j;
+          CoinBigIndex count = 0;
+          for (j = startPositive_[i]; j < startPositive_[i+1]; j++) {
+               int iRow = indices_[j];
+               count += inputWeights[iRow];
+          }
+          weights[i] = count;
+     }
+     for (i = 0; i < numberRows; i++) {
+          weights[i+numberColumns] = inputWeights[i];
+     }
+     return weights;
+}
+// Append Columns
+void
+ClpPlusMinusOneMatrix::appendCols(int number, const CoinPackedVectorBase * const * columns)
+{
+     int iColumn;
+     CoinBigIndex size = 0;
+     int numberBad = 0;
+     for (iColumn = 0; iColumn < number; iColumn++) {
+          int n = columns[iColumn]->getNumElements();
+          const double * element = columns[iColumn]->getElements();
+          size += n;
+          int i;
+          for (i = 0; i < n; i++) {
+               if (fabs(element[i]) != 1.0)
+                    numberBad++;
+          }
+     }
+     if (numberBad)
+          throw CoinError("Not +- 1", "appendCols", "ClpPlusMinusOneMatrix");
+     // Get rid of temporary arrays
+     delete [] lengths_;
+     lengths_ = NULL;
+     delete matrix_;
+     matrix_ = NULL;
+     int numberNow = startPositive_[numberColumns_];
+     CoinBigIndex * temp;
+     temp = new CoinBigIndex [numberColumns_+1+number];
+     CoinMemcpyN(startPositive_, (numberColumns_ + 1), temp);
+     delete [] startPositive_;
+     startPositive_ = temp;
+     temp = new CoinBigIndex [numberColumns_+number];
+     CoinMemcpyN(startNegative_, numberColumns_, temp);
+     delete [] startNegative_;
+     startNegative_ = temp;
+     int * temp2 = new int [numberNow+size];
+     CoinMemcpyN(indices_, numberNow, temp2);
+     delete [] indices_;
+     indices_ = temp2;
+     // now add
+     size = numberNow;
+     for (iColumn = 0; iColumn < number; iColumn++) {
+          int n = columns[iColumn]->getNumElements();
+          const int * row = columns[iColumn]->getIndices();
+          const double * element = columns[iColumn]->getElements();
+          int i;
+          for (i = 0; i < n; i++) {
+               if (element[i] == 1.0)
+                    indices_[size++] = row[i];
+          }
+          startNegative_[iColumn+numberColumns_] = size;
+          for (i = 0; i < n; i++) {
+               if (element[i] == -1.0)
+                    indices_[size++] = row[i];
+          }
+          startPositive_[iColumn+numberColumns_+1] = size;
+     }
+
+     numberColumns_ += number;
+}
+// Append Rows
+void
+ClpPlusMinusOneMatrix::appendRows(int number, const CoinPackedVectorBase * const * rows)
+{
+     // Allocate arrays to use for counting
+     int * countPositive = new int [numberColumns_+1];
+     memset(countPositive, 0, numberColumns_ * sizeof(int));
+     int * countNegative = new int [numberColumns_];
+     memset(countNegative, 0, numberColumns_ * sizeof(int));
+     int iRow;
+     CoinBigIndex size = 0;
+     int numberBad = 0;
+     for (iRow = 0; iRow < number; iRow++) {
+          int n = rows[iRow]->getNumElements();
+          const int * column = rows[iRow]->getIndices();
+          const double * element = rows[iRow]->getElements();
+          size += n;
+          int i;
+          for (i = 0; i < n; i++) {
+               int iColumn = column[i];
+               if (element[i] == 1.0)
+                    countPositive[iColumn]++;
+               else if (element[i] == -1.0)
+                    countNegative[iColumn]++;
+               else
+                    numberBad++;
+          }
+     }
+     if (numberBad)
+          throw CoinError("Not +- 1", "appendRows", "ClpPlusMinusOneMatrix");
+     // Get rid of temporary arrays
+     delete [] lengths_;
+     lengths_ = NULL;
+     delete matrix_;
+     matrix_ = NULL;
+     int numberNow = startPositive_[numberColumns_];
+     int * newIndices = new int [numberNow+size];
+     // Update starts and turn counts into positions
+     // also move current indices
+     int iColumn;
+     CoinBigIndex numberAdded = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          int n, move;
+          CoinBigIndex now;
+          now = startPositive_[iColumn];
+          move = startNegative_[iColumn] - now;
+          n = countPositive[iColumn];
+          startPositive_[iColumn] += numberAdded;
+          CoinMemcpyN(newIndices + startPositive_[iColumn], move, indices_ + now);
+          countPositive[iColumn] = startNegative_[iColumn] + numberAdded;
+          numberAdded += n;
+          now = startNegative_[iColumn];
+          move = startPositive_[iColumn+1] - now;
+          n = countNegative[iColumn];
+          startNegative_[iColumn] += numberAdded;
+          CoinMemcpyN(newIndices + startNegative_[iColumn], move, indices_ + now);
+          countNegative[iColumn] = startPositive_[iColumn+1] + numberAdded;
+          numberAdded += n;
+     }
+     delete [] indices_;
+     indices_ = newIndices;
+     startPositive_[numberColumns_] += numberAdded;
+     // Now put in
+     for (iRow = 0; iRow < number; iRow++) {
+          int newRow = numberRows_ + iRow;
+          int n = rows[iRow]->getNumElements();
+          const int * column = rows[iRow]->getIndices();
+          const double * element = rows[iRow]->getElements();
+          int i;
+          for (i = 0; i < n; i++) {
+               int iColumn = column[i];
+               int put;
+               if (element[i] == 1.0) {
+                    put = countPositive[iColumn];
+                    countPositive[iColumn] = put + 1;
+               } else {
+                    put = countNegative[iColumn];
+                    countNegative[iColumn] = put + 1;
+               }
+               indices_[put] = newRow;
+          }
+     }
+     delete [] countPositive;
+     delete [] countNegative;
+     numberRows_ += number;
+}
+/* Returns largest and smallest elements of both signs.
+   Largest refers to largest absolute value.
+*/
+void
+ClpPlusMinusOneMatrix::rangeOfElements(double & smallestNegative, double & largestNegative,
+                                       double & smallestPositive, double & largestPositive)
+{
+     int iColumn;
+     bool plusOne = false;
+     bool minusOne = false;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (startNegative_[iColumn] > startPositive_[iColumn])
+               plusOne = true;
+          if (startPositive_[iColumn+1] > startNegative_[iColumn])
+               minusOne = true;
+     }
+     if (minusOne) {
+          smallestNegative = -1.0;
+          largestNegative = -1.0;
+     } else {
+          smallestNegative = 0.0;
+          largestNegative = 0.0;
+     }
+     if (plusOne) {
+          smallestPositive = 1.0;
+          largestPositive = 1.0;
+     } else {
+          smallestPositive = 0.0;
+          largestPositive = 0.0;
+     }
+}
+// Says whether it can do partial pricing
+bool
+ClpPlusMinusOneMatrix::canDoPartialPricing() const
+{
+     return true;
+}
+// Partial pricing
+void
+ClpPlusMinusOneMatrix::partialPricing(ClpSimplex * model, double startFraction, double endFraction,
+                                      int & bestSequence, int & numberWanted)
+{
+     numberWanted = currentWanted_;
+     int start = static_cast<int> (startFraction * numberColumns_);
+     int end = CoinMin(static_cast<int> (endFraction * numberColumns_ + 1), numberColumns_);
+     CoinBigIndex j;
+     double tolerance = model->currentDualTolerance();
+     double * reducedCost = model->djRegion();
+     const double * duals = model->dualRowSolution();
+     const double * cost = model->costRegion();
+     double bestDj;
+     if (bestSequence >= 0)
+          bestDj = fabs(reducedCost[bestSequence]);
+     else
+          bestDj = tolerance;
+     int sequenceOut = model->sequenceOut();
+     int saveSequence = bestSequence;
+     int iSequence;
+     for (iSequence = start; iSequence < end; iSequence++) {
+          if (iSequence != sequenceOut) {
+               double value;
+               ClpSimplex::Status status = model->getStatus(iSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    value = cost[iSequence];
+                    j = startPositive_[iSequence];
+                    for (; j < startNegative_[iSequence]; j++) {
+                         int iRow = indices_[j];
+                         value -= duals[iRow];
+                    }
+                    for (; j < startPositive_[iSequence+1]; j++) {
+                         int iRow = indices_[j];
+                         value += duals[iRow];
+                    }
+                    value = fabs(value);
+                    if (value > FREE_ACCEPT * tolerance) {
+                         numberWanted--;
+                         // we are going to bias towards free (but only if reasonable)
+                         value *= FREE_BIAS;
+                         if (value > bestDj) {
+                              // check flagged variable and correct dj
+                              if (!model->flagged(iSequence)) {
+                                   bestDj = value;
+                                   bestSequence = iSequence;
+                              } else {
+                                   // just to make sure we don't exit before got something
+                                   numberWanted++;
+                              }
+                         }
+                    }
+                    break;
+               case ClpSimplex::atUpperBound:
+                    value = cost[iSequence];
+                    j = startPositive_[iSequence];
+                    for (; j < startNegative_[iSequence]; j++) {
+                         int iRow = indices_[j];
+                         value -= duals[iRow];
+                    }
+                    for (; j < startPositive_[iSequence+1]; j++) {
+                         int iRow = indices_[j];
+                         value += duals[iRow];
+                    }
+                    if (value > tolerance) {
+                         numberWanted--;
+                         if (value > bestDj) {
+                              // check flagged variable and correct dj
+                              if (!model->flagged(iSequence)) {
+                                   bestDj = value;
+                                   bestSequence = iSequence;
+                              } else {
+                                   // just to make sure we don't exit before got something
+                                   numberWanted++;
+                              }
+                         }
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    value = cost[iSequence];
+                    j = startPositive_[iSequence];
+                    for (; j < startNegative_[iSequence]; j++) {
+                         int iRow = indices_[j];
+                         value -= duals[iRow];
+                    }
+                    for (; j < startPositive_[iSequence+1]; j++) {
+                         int iRow = indices_[j];
+                         value += duals[iRow];
+                    }
+                    value = -value;
+                    if (value > tolerance) {
+                         numberWanted--;
+                         if (value > bestDj) {
+                              // check flagged variable and correct dj
+                              if (!model->flagged(iSequence)) {
+                                   bestDj = value;
+                                   bestSequence = iSequence;
+                              } else {
+                                   // just to make sure we don't exit before got something
+                                   numberWanted++;
+                              }
+                         }
+                    }
+                    break;
+               }
+          }
+          if (!numberWanted)
+               break;
+     }
+     if (bestSequence != saveSequence) {
+          // recompute dj
+          double value = cost[bestSequence];
+          j = startPositive_[bestSequence];
+          for (; j < startNegative_[bestSequence]; j++) {
+               int iRow = indices_[j];
+               value -= duals[iRow];
+          }
+          for (; j < startPositive_[bestSequence+1]; j++) {
+               int iRow = indices_[j];
+               value += duals[iRow];
+          }
+          reducedCost[bestSequence] = value;
+          savedBestSequence_ = bestSequence;
+          savedBestDj_ = reducedCost[savedBestSequence_];
+     }
+     currentWanted_ = numberWanted;
+}
+// Allow any parts of a created CoinMatrix to be deleted
+void
+ClpPlusMinusOneMatrix::releasePackedMatrix() const
+{
+     delete matrix_;
+     delete [] lengths_;
+     matrix_ = NULL;
+     lengths_ = NULL;
+}
+/* Returns true if can combine transposeTimes and subsetTransposeTimes
+   and if it would be faster */
+bool
+ClpPlusMinusOneMatrix::canCombine(const ClpSimplex * model,
+                                  const CoinIndexedVector * pi) const
+{
+     int numberInRowArray = pi->getNumElements();
+     int numberRows = model->numberRows();
+     bool packed = pi->packedMode();
+     // factor should be smaller if doing both with two pi vectors
+     double factor = 0.27;
+     // We may not want to do by row if there may be cache problems
+     // It would be nice to find L2 cache size - for moment 512K
+     // Be slightly optimistic
+     if (numberColumns_ * sizeof(double) > 1000000) {
+          if (numberRows * 10 < numberColumns_)
+               factor *= 0.333333333;
+          else if (numberRows * 4 < numberColumns_)
+               factor *= 0.5;
+          else if (numberRows * 2 < numberColumns_)
+               factor *= 0.66666666667;
+          //if (model->numberIterations()%50==0)
+          //printf("%d nonzero\n",numberInRowArray);
+     }
+     // if not packed then bias a bit more towards by column
+     if (!packed)
+          factor *= 0.9;
+     return (numberInRowArray > factor * numberRows || !model->rowCopy());
+}
+// These have to match ClpPrimalColumnSteepest version
+#define reference(i)  (((reference[i>>5]>>(i&31))&1)!=0)
+// Updates two arrays for steepest
+void
+ClpPlusMinusOneMatrix::transposeTimes2(const ClpSimplex * model,
+                                       const CoinIndexedVector * pi1, CoinIndexedVector * dj1,
+                                       const CoinIndexedVector * pi2,
+                                       CoinIndexedVector * spare,
+                                       double referenceIn, double devex,
+                                       // Array for exact devex to say what is in reference framework
+                                       unsigned int * reference,
+                                       double * weights, double scaleFactor)
+{
+     // put row of tableau in dj1
+     double * pi = pi1->denseVector();
+     int numberNonZero = 0;
+     int * index = dj1->getIndices();
+     double * array = dj1->denseVector();
+     int numberInRowArray = pi1->getNumElements();
+     double zeroTolerance = model->zeroTolerance();
+     bool packed = pi1->packedMode();
+     // do by column
+     int iColumn;
+     assert (!spare->getNumElements());
+     double * piWeight = pi2->denseVector();
+     assert (!pi2->packedMode());
+     bool killDjs = (scaleFactor == 0.0);
+     if (!scaleFactor)
+          scaleFactor = 1.0;
+     // Note scale factor was -1.0
+     if (packed) {
+          // need to expand pi into y
+          assert(spare->capacity() >= model->numberRows());
+          double * piOld = pi;
+          pi = spare->denseVector();
+          const int * whichRow = pi1->getIndices();
+          int i;
+          // modify pi so can collapse to one loop
+          for (i = 0; i < numberInRowArray; i++) {
+               int iRow = whichRow[i];
+               pi[iRow] = piOld[i];
+          }
+          CoinBigIndex j;
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               ClpSimplex::Status status = model->getStatus(iColumn);
+               if (status == ClpSimplex::basic || status == ClpSimplex::isFixed) continue;
+               double value = 0.0;
+               for (j = startPositive_[iColumn]; j < startNegative_[iColumn]; j++) {
+                    int iRow = indices_[j];
+                    value -= pi[iRow];
+               }
+               for (; j < startPositive_[iColumn+1]; j++) {
+                    int iRow = indices_[j];
+                    value += pi[iRow];
+               }
+               if (fabs(value) > zeroTolerance) {
+                    // and do other array
+                    double modification = 0.0;
+                    for (j = startPositive_[iColumn]; j < startNegative_[iColumn]; j++) {
+                         int iRow = indices_[j];
+                         modification += piWeight[iRow];
+                    }
+                    for (; j < startPositive_[iColumn+1]; j++) {
+                         int iRow = indices_[j];
+                         modification -= piWeight[iRow];
+                    }
+                    double thisWeight = weights[iColumn];
+                    double pivot = value * scaleFactor;
+                    double pivotSquared = pivot * pivot;
+                    thisWeight += pivotSquared * devex + pivot * modification;
+                    if (thisWeight < DEVEX_TRY_NORM) {
+                         if (referenceIn < 0.0) {
+                              // steepest
+                              thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                         } else {
+                              // exact
+                              thisWeight = referenceIn * pivotSquared;
+                              if (reference(iColumn))
+                                   thisWeight += 1.0;
+                              thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                         }
+                    }
+                    weights[iColumn] = thisWeight;
+                    if (!killDjs) {
+                         array[numberNonZero] = value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               }
+          }
+          // zero out
+          for (i = 0; i < numberInRowArray; i++) {
+               int iRow = whichRow[i];
+               pi[iRow] = 0.0;
+          }
+     } else {
+          CoinBigIndex j;
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               ClpSimplex::Status status = model->getStatus(iColumn);
+               if (status == ClpSimplex::basic || status == ClpSimplex::isFixed) continue;
+               double value = 0.0;
+               for (j = startPositive_[iColumn]; j < startNegative_[iColumn]; j++) {
+                    int iRow = indices_[j];
+                    value -= pi[iRow];
+               }
+               for (; j < startPositive_[iColumn+1]; j++) {
+                    int iRow = indices_[j];
+                    value += pi[iRow];
+               }
+               if (fabs(value) > zeroTolerance) {
+                    // and do other array
+                    double modification = 0.0;
+                    for (j = startPositive_[iColumn]; j < startNegative_[iColumn]; j++) {
+                         int iRow = indices_[j];
+                         modification += piWeight[iRow];
+                    }
+                    for (; j < startPositive_[iColumn+1]; j++) {
+                         int iRow = indices_[j];
+                         modification -= piWeight[iRow];
+                    }
+                    double thisWeight = weights[iColumn];
+                    double pivot = value * scaleFactor;
+                    double pivotSquared = pivot * pivot;
+                    thisWeight += pivotSquared * devex + pivot * modification;
+                    if (thisWeight < DEVEX_TRY_NORM) {
+                         if (referenceIn < 0.0) {
+                              // steepest
+                              thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+                         } else {
+                              // exact
+                              thisWeight = referenceIn * pivotSquared;
+                              if (reference(iColumn))
+                                   thisWeight += 1.0;
+                              thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+                         }
+                    }
+                    weights[iColumn] = thisWeight;
+                    if (!killDjs) {
+                         array[iColumn] = value;
+                         index[numberNonZero++] = iColumn;
+                    }
+               }
+          }
+     }
+     dj1->setNumElements(numberNonZero);
+     spare->setNumElements(0);
+     if (packed)
+          dj1->setPackedMode(true);
+}
+// Updates second array for steepest and does devex weights
+void
+ClpPlusMinusOneMatrix::subsetTimes2(const ClpSimplex * ,
+                                    CoinIndexedVector * dj1,
+                                    const CoinIndexedVector * pi2, CoinIndexedVector *,
+                                    double referenceIn, double devex,
+                                    // Array for exact devex to say what is in reference framework
+                                    unsigned int * reference,
+                                    double * weights, double scaleFactor)
+{
+     int number = dj1->getNumElements();
+     const int * index = dj1->getIndices();
+     double * array = dj1->denseVector();
+     assert( dj1->packedMode());
+
+     double * piWeight = pi2->denseVector();
+     bool killDjs = (scaleFactor == 0.0);
+     if (!scaleFactor)
+          scaleFactor = 1.0;
+     for (int k = 0; k < number; k++) {
+          int iColumn = index[k];
+          double pivot = array[k] * scaleFactor;
+          if (killDjs)
+               array[k] = 0.0;
+          // and do other array
+          double modification = 0.0;
+          CoinBigIndex j;
+          for (j = startPositive_[iColumn]; j < startNegative_[iColumn]; j++) {
+               int iRow = indices_[j];
+               modification += piWeight[iRow];
+          }
+          for (; j < startPositive_[iColumn+1]; j++) {
+               int iRow = indices_[j];
+               modification -= piWeight[iRow];
+          }
+          double thisWeight = weights[iColumn];
+          double pivotSquared = pivot * pivot;
+          thisWeight += pivotSquared * devex + pivot * modification;
+          if (thisWeight < DEVEX_TRY_NORM) {
+               if (referenceIn < 0.0) {
+                    // steepest
+                    thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
+               } else {
+                    // exact
+                    thisWeight = referenceIn * pivotSquared;
+                    if (reference(iColumn))
+                         thisWeight += 1.0;
+                    thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
+               }
+          }
+          weights[iColumn] = thisWeight;
+     }
+}
+/* Set the dimensions of the matrix. In effect, append new empty
+   columns/rows to the matrix. A negative number for either dimension
+   means that that dimension doesn't change. Otherwise the new dimensions
+   MUST be at least as large as the current ones otherwise an exception
+   is thrown. */
+void
+ClpPlusMinusOneMatrix::setDimensions(int newnumrows, int newnumcols)
+{
+     if (newnumrows < 0)
+          newnumrows = numberRows_;
+     if (newnumrows < numberRows_)
+          throw CoinError("Bad new rownum (less than current)",
+                          "setDimensions", "CoinPackedMatrix");
+
+     if (newnumcols < 0)
+          newnumcols = numberColumns_;
+     if (newnumcols < numberColumns_)
+          throw CoinError("Bad new colnum (less than current)",
+                          "setDimensions", "CoinPackedMatrix");
+
+     int number = 0;
+     int length = 0;
+     if (columnOrdered_) {
+          length = numberColumns_;
+          numberColumns_ = newnumcols;
+          number = numberColumns_;
+
+     } else {
+          length = numberRows_;
+          numberRows_ = newnumrows;
+          number = numberRows_;
+     }
+     if (number > length) {
+          CoinBigIndex * temp;
+          int i;
+          CoinBigIndex end = startPositive_[length];
+          temp = new CoinBigIndex [number+1];
+          CoinMemcpyN(startPositive_, (length + 1), temp);
+          delete [] startPositive_;
+          for (i = length + 1; i < number + 1; i++)
+               temp[i] = end;
+          startPositive_ = temp;
+          temp = new CoinBigIndex [number];
+          CoinMemcpyN(startNegative_, length, temp);
+          delete [] startNegative_;
+          for (i = length; i < number; i++)
+               temp[i] = end;
+          startNegative_ = temp;
+     }
+}
+#ifndef SLIM_CLP
+/* Append a set of rows/columns to the end of the matrix. Returns number of errors
+   i.e. if any of the new rows/columns contain an index that's larger than the
+   number of columns-1/rows-1 (if numberOther>0) or duplicates
+   If 0 then rows, 1 if columns */
+int
+ClpPlusMinusOneMatrix::appendMatrix(int number, int type,
+                                    const CoinBigIndex * starts, const int * index,
+                                    const double * element, int /*numberOther*/)
+{
+     int numberErrors = 0;
+     // make into CoinPackedVector
+     CoinPackedVectorBase ** vectors =
+          new CoinPackedVectorBase * [number];
+     int iVector;
+     for (iVector = 0; iVector < number; iVector++) {
+          int iStart = starts[iVector];
+          vectors[iVector] =
+               new CoinPackedVector(starts[iVector+1] - iStart,
+                                    index + iStart, element + iStart);
+     }
+     if (type == 0) {
+          // rows
+          appendRows(number, vectors);
+     } else {
+          // columns
+          appendCols(number, vectors);
+     }
+     for (iVector = 0; iVector < number; iVector++)
+          delete vectors[iVector];
+     delete [] vectors;
+     return numberErrors;
+}
+#endif
diff --git a/cbits/coin/ClpPlusMinusOneMatrix.hpp b/cbits/coin/ClpPlusMinusOneMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPlusMinusOneMatrix.hpp
@@ -0,0 +1,284 @@
+/* $Id: ClpPlusMinusOneMatrix.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpPlusMinusOneMatrix_H
+#define ClpPlusMinusOneMatrix_H
+
+
+#include "CoinPragma.hpp"
+
+#include "ClpMatrixBase.hpp"
+
+/** This implements a simple +- one matrix as derived from ClpMatrixBase.
+
+*/
+
+class ClpPlusMinusOneMatrix : public ClpMatrixBase {
+
+public:
+     /**@name Useful methods */
+     //@{
+     /// Return a complete CoinPackedMatrix
+     virtual CoinPackedMatrix * getPackedMatrix() const;
+     /** Whether the packed matrix is column major ordered or not. */
+     virtual bool isColOrdered() const ;
+     /** Number of entries in the packed matrix. */
+     virtual  CoinBigIndex getNumElements() const;
+     /** Number of columns. */
+     virtual int getNumCols() const {
+          return numberColumns_;
+     }
+     /** Number of rows. */
+     virtual int getNumRows() const {
+          return numberRows_;
+     }
+
+     /** A vector containing the elements in the packed matrix. Note that there
+      might be gaps in this list, entries that do not belong to any
+      major-dimension vector. To get the actual elements one should look at
+      this vector together with vectorStarts and vectorLengths. */
+     virtual const double * getElements() const;
+     /** A vector containing the minor indices of the elements in the packed
+          matrix. Note that there might be gaps in this list, entries that do not
+          belong to any major-dimension vector. To get the actual elements one
+          should look at this vector together with vectorStarts and
+          vectorLengths. */
+     virtual const int * getIndices() const {
+          return indices_;
+     }
+     // and for advanced use
+     int * getMutableIndices() const {
+          return indices_;
+     }
+
+     virtual const CoinBigIndex * getVectorStarts() const;
+     /** The lengths of the major-dimension vectors. */
+     virtual const int * getVectorLengths() const;
+
+     /** Delete the columns whose indices are listed in <code>indDel</code>. */
+     virtual void deleteCols(const int numDel, const int * indDel);
+     /** Delete the rows whose indices are listed in <code>indDel</code>. */
+     virtual void deleteRows(const int numDel, const int * indDel);
+     /// Append Columns
+     virtual void appendCols(int number, const CoinPackedVectorBase * const * columns);
+     /// Append Rows
+     virtual void appendRows(int number, const CoinPackedVectorBase * const * rows);
+#ifndef SLIM_CLP
+     /** Append a set of rows/columns to the end of the matrix. Returns number of errors
+         i.e. if any of the new rows/columns contain an index that's larger than the
+         number of columns-1/rows-1 (if numberOther>0) or duplicates
+         If 0 then rows, 1 if columns */
+     virtual int appendMatrix(int number, int type,
+                              const CoinBigIndex * starts, const int * index,
+                              const double * element, int numberOther = -1);
+#endif
+     /** Returns a new matrix in reverse order without gaps */
+     virtual ClpMatrixBase * reverseOrderedCopy() const;
+     /// Returns number of elements in column part of basis
+     virtual CoinBigIndex countBasis(
+          const int * whichColumn,
+          int & numberColumnBasic);
+     /// Fills in column part of basis
+     virtual void fillBasis(ClpSimplex * model,
+                            const int * whichColumn,
+                            int & numberColumnBasic,
+                            int * row, int * start,
+                            int * rowCount, int * columnCount,
+                            CoinFactorizationDouble * element);
+     /** Given positive integer weights for each row fills in sum of weights
+         for each column (and slack).
+         Returns weights vector
+     */
+     virtual CoinBigIndex * dubiousWeights(const ClpSimplex * model, int * inputWeights) const;
+     /** Returns largest and smallest elements of both signs.
+         Largest refers to largest absolute value.
+     */
+     virtual void rangeOfElements(double & smallestNegative, double & largestNegative,
+                                  double & smallestPositive, double & largestPositive);
+     /** Unpacks a column into an CoinIndexedvector
+      */
+     virtual void unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                         int column) const ;
+     /** Unpacks a column into an CoinIndexedvector
+      ** in packed foramt
+         Note that model is NOT const.  Bounds and objective could
+         be modified if doing column generation (just for this variable) */
+     virtual void unpackPacked(ClpSimplex * model,
+                               CoinIndexedVector * rowArray,
+                               int column) const;
+     /** Adds multiple of a column into an CoinIndexedvector
+         You can use quickAdd to add to vector */
+     virtual void add(const ClpSimplex * model, CoinIndexedVector * rowArray,
+                      int column, double multiplier) const ;
+     /** Adds multiple of a column into an array */
+     virtual void add(const ClpSimplex * model, double * array,
+                      int column, double multiplier) const;
+     /// Allow any parts of a created CoinMatrix to be deleted
+     virtual void releasePackedMatrix() const;
+     /** Set the dimensions of the matrix. In effect, append new empty
+         columns/rows to the matrix. A negative number for either dimension
+         means that that dimension doesn't change. Otherwise the new dimensions
+         MUST be at least as large as the current ones otherwise an exception
+         is thrown. */
+     virtual void setDimensions(int numrows, int numcols);
+     /// Just checks matrix valid - will say if dimensions not quite right if detail
+     void checkValid(bool detail) const;
+     //@}
+
+     /**@name Matrix times vector methods */
+     //@{
+     /** Return <code>y + A * scalar *x</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numColumns()</code>
+         @pre <code>y</code> must be of size <code>numRows()</code> */
+     virtual void times(double scalar,
+                        const double * x, double * y) const;
+     /// And for scaling
+     virtual void times(double scalar,
+                        const double * x, double * y,
+                        const double * rowScale,
+                        const double * columnScale) const;
+     /** Return <code>y + x * scalar * A</code> in <code>y</code>.
+         @pre <code>x</code> must be of size <code>numRows()</code>
+         @pre <code>y</code> must be of size <code>numColumns()</code> */
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y) const;
+     /// And for scaling
+     virtual void transposeTimes(double scalar,
+                                 const double * x, double * y,
+                                 const double * rowScale,
+                                 const double * columnScale, double * spare = NULL) const;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Can use y as temporary array (will be empty at end)
+     Note - If x packed mode - then z packed mode
+     Squashes small elements and knows about ClpSimplex */
+     virtual void transposeTimes(const ClpSimplex * model, double scalar,
+                                 const CoinIndexedVector * x,
+                                 CoinIndexedVector * y,
+                                 CoinIndexedVector * z) const;
+     /** Return <code>x * scalar * A + y</code> in <code>z</code>.
+     Can use y as temporary array (will be empty at end)
+     Note - If x packed mode - then z packed mode
+     Squashes small elements and knows about ClpSimplex.
+     This version uses row copy*/
+     virtual void transposeTimesByRow(const ClpSimplex * model, double scalar,
+                                      const CoinIndexedVector * x,
+                                      CoinIndexedVector * y,
+                                      CoinIndexedVector * z) const;
+     /** Return <code>x *A</code> in <code>z</code> but
+     just for indices in y.
+     Note - z always packed mode */
+     virtual void subsetTransposeTimes(const ClpSimplex * model,
+                                       const CoinIndexedVector * x,
+                                       const CoinIndexedVector * y,
+                                       CoinIndexedVector * z) const;
+     /** Returns true if can combine transposeTimes and subsetTransposeTimes
+         and if it would be faster */
+     virtual bool canCombine(const ClpSimplex * model,
+                             const CoinIndexedVector * pi) const;
+     /// Updates two arrays for steepest
+     virtual void transposeTimes2(const ClpSimplex * model,
+                                  const CoinIndexedVector * pi1, CoinIndexedVector * dj1,
+                                  const CoinIndexedVector * pi2,
+                                  CoinIndexedVector * spare,
+                                  double referenceIn, double devex,
+                                  // Array for exact devex to say what is in reference framework
+                                  unsigned int * reference,
+                                  double * weights, double scaleFactor);
+     /// Updates second array for steepest and does devex weights
+     virtual void subsetTimes2(const ClpSimplex * model,
+                               CoinIndexedVector * dj1,
+                               const CoinIndexedVector * pi2, CoinIndexedVector * dj2,
+                               double referenceIn, double devex,
+                               // Array for exact devex to say what is in reference framework
+                               unsigned int * reference,
+                               double * weights, double scaleFactor);
+     //@}
+
+     /**@name Other */
+     //@{
+     /// Return starts of +1s
+     inline CoinBigIndex * startPositive() const {
+          return startPositive_;
+     }
+     /// Return starts of -1s
+     inline CoinBigIndex * startNegative() const {
+          return startNegative_;
+     }
+     //@}
+
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     ClpPlusMinusOneMatrix();
+     /** Destructor */
+     virtual ~ClpPlusMinusOneMatrix();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     ClpPlusMinusOneMatrix(const ClpPlusMinusOneMatrix&);
+     /** The copy constructor from an CoinPlusMinusOneMatrix.
+         If not a valid matrix then getIndices will be NULL and
+         startPositive[0] will have number of +1,
+         startPositive[1] will have number of -1,
+         startPositive[2] will have number of others,
+     */
+     ClpPlusMinusOneMatrix(const CoinPackedMatrix&);
+     /// Constructor from arrays
+     ClpPlusMinusOneMatrix(int numberRows, int numberColumns,
+                           bool columnOrdered, const int * indices,
+                           const CoinBigIndex * startPositive, const CoinBigIndex * startNegative);
+     /** Subset constructor (without gaps).  Duplicates are allowed
+         and order is as given */
+     ClpPlusMinusOneMatrix (const ClpPlusMinusOneMatrix & wholeModel,
+                            int numberRows, const int * whichRows,
+                            int numberColumns, const int * whichColumns);
+
+     ClpPlusMinusOneMatrix& operator=(const ClpPlusMinusOneMatrix&);
+     /// Clone
+     virtual ClpMatrixBase * clone() const ;
+     /** Subset clone (without gaps).  Duplicates are allowed
+         and order is as given */
+     virtual ClpMatrixBase * subsetClone (
+          int numberRows, const int * whichRows,
+          int numberColumns, const int * whichColumns) const ;
+     /// pass in copy (object takes ownership)
+     void passInCopy(int numberRows, int numberColumns,
+                     bool columnOrdered, int * indices,
+                     CoinBigIndex * startPositive, CoinBigIndex * startNegative);
+     /// Says whether it can do partial pricing
+     virtual bool canDoPartialPricing() const;
+     /// Partial pricing
+     virtual void partialPricing(ClpSimplex * model, double start, double end,
+                                 int & bestSequence, int & numberWanted);
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// For fake CoinPackedMatrix
+     mutable CoinPackedMatrix * matrix_;
+     mutable int * lengths_;
+     /// Start of +1's for each
+     CoinBigIndex * startPositive_;
+     /// Start of -1's for each
+     CoinBigIndex * startNegative_;
+     /// Data -1, then +1 rows in pairs (row==-1 if one entry)
+     int * indices_;
+     /// Number of rows
+     int numberRows_;
+     /// Number of columns
+     int numberColumns_;
+     /// True if column ordered
+     bool columnOrdered_;
+
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpPredictorCorrector.cpp b/cbits/coin/ClpPredictorCorrector.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPredictorCorrector.cpp
@@ -0,0 +1,3950 @@
+/* $Id: ClpPredictorCorrector.cpp 1959 2013-06-14 15:43:10Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*
+   Implements crude primal dual predictor corrector algorithm
+
+ */
+//#define SOME_DEBUG
+
+#include "CoinPragma.hpp"
+#include <math.h>
+
+#include "CoinHelperFunctions.hpp"
+#include "ClpPredictorCorrector.hpp"
+#include "ClpEventHandler.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "ClpMessage.hpp"
+#include "ClpCholeskyBase.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "ClpQuadraticObjective.hpp"
+#include <cfloat>
+#include <cassert>
+#include <string>
+#include <cstdio>
+#include <iostream>
+#if 0
+static int yyyyyy = 0;
+void ClpPredictorCorrector::saveSolution(std::string fileName)
+{
+     FILE * fp = fopen(fileName.c_str(), "wb");
+     if (fp) {
+          int numberRows = numberRows_;
+          int numberColumns = numberColumns_;
+          fwrite(&numberRows, sizeof(int), 1, fp);
+          fwrite(&numberColumns, sizeof(int), 1, fp);
+          CoinWorkDouble dsave[20];
+          memset(dsave, 0, sizeof(dsave));
+          fwrite(dsave, sizeof(CoinWorkDouble), 20, fp);
+          int msave[20];
+          memset(msave, 0, sizeof(msave));
+          msave[0] = numberIterations_;
+          fwrite(msave, sizeof(int), 20, fp);
+          fwrite(dual_, sizeof(CoinWorkDouble), numberRows, fp);
+          fwrite(errorRegion_, sizeof(CoinWorkDouble), numberRows, fp);
+          fwrite(rhsFixRegion_, sizeof(CoinWorkDouble), numberRows, fp);
+          fwrite(solution_, sizeof(CoinWorkDouble), numberColumns, fp);
+          fwrite(solution_ + numberColumns, sizeof(CoinWorkDouble), numberRows, fp);
+          fwrite(diagonal_, sizeof(CoinWorkDouble), numberColumns, fp);
+          fwrite(diagonal_ + numberColumns, sizeof(CoinWorkDouble), numberRows, fp);
+          fwrite(wVec_, sizeof(CoinWorkDouble), numberColumns, fp);
+          fwrite(wVec_ + numberColumns, sizeof(CoinWorkDouble), numberRows, fp);
+          fwrite(zVec_, sizeof(CoinWorkDouble), numberColumns, fp);
+          fwrite(zVec_ + numberColumns, sizeof(CoinWorkDouble), numberRows, fp);
+          fwrite(upperSlack_, sizeof(CoinWorkDouble), numberColumns, fp);
+          fwrite(upperSlack_ + numberColumns, sizeof(CoinWorkDouble), numberRows, fp);
+          fwrite(lowerSlack_, sizeof(CoinWorkDouble), numberColumns, fp);
+          fwrite(lowerSlack_ + numberColumns, sizeof(CoinWorkDouble), numberRows, fp);
+          fclose(fp);
+     } else {
+          std::cout << "Unable to open file " << fileName << std::endl;
+     }
+}
+#endif
+// Could change on CLP_LONG_CHOLESKY or COIN_LONG_WORK?
+static CoinWorkDouble eScale = 1.0e27;
+static CoinWorkDouble eBaseCaution = 1.0e-12;
+static CoinWorkDouble eBase = 1.0e-12;
+static CoinWorkDouble eDiagonal = 1.0e25;
+static CoinWorkDouble eDiagonalCaution = 1.0e18;
+static CoinWorkDouble eExtra = 1.0e-12;
+
+// main function
+
+int ClpPredictorCorrector::solve ( )
+{
+     problemStatus_ = -1;
+     algorithm_ = 1;
+     //create all regions
+     if (!createWorkingData()) {
+          problemStatus_ = 4;
+          return 2;
+     }
+#if COIN_LONG_WORK
+     // reallocate some regions
+     double * dualSave = dual_;
+     dual_ = reinterpret_cast<double *>(new CoinWorkDouble[numberRows_]);
+     double * reducedCostSave = reducedCost_;
+     reducedCost_ = reinterpret_cast<double *>(new CoinWorkDouble[numberColumns_]);
+#endif
+     //diagonalPerturbation_=1.0e-25;
+     ClpMatrixBase * saveMatrix = NULL;
+     // If quadratic then make copy so we can actually scale or normalize
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+     /* If modeSwitch is :
+        0 - normal
+        1 - bit switch off centering
+        2 - bit always do type 2
+        4 - accept corrector nearly always
+     */
+     int modeSwitch = 0;
+     //if (quadraticObj)
+     //modeSwitch |= 1; // switch off centring for now
+     //if (quadraticObj)
+     //modeSwitch |=4;
+     ClpObjective * saveObjective = NULL;
+     if (quadraticObj) {
+          // check KKT is on
+          if (!cholesky_->kkt()) {
+               //No!
+               handler_->message(CLP_BARRIER_KKT, messages_)
+                         << CoinMessageEol;
+               return -1;
+          }
+          saveObjective = objective_;
+          // We are going to make matrix full rather half
+          objective_ = new ClpQuadraticObjective(*quadraticObj, 1);
+     }
+     bool allowIncreasingGap = (modeSwitch & 4) != 0;
+     // If scaled then really scale matrix
+     if (scalingFlag_ > 0 && rowScale_) {
+          saveMatrix = matrix_;
+          matrix_ = matrix_->scaledColumnCopy(this);
+     }
+     //initializeFeasible(); - this just set fixed flag
+     smallestInfeasibility_ = COIN_DBL_MAX;
+     int i;
+     for (i = 0; i < LENGTH_HISTORY; i++)
+          historyInfeasibility_[i] = COIN_DBL_MAX;
+
+     //bool firstTime=true;
+     //firstFactorization(true);
+     int returnCode = cholesky_->order(this);
+     if (returnCode || cholesky_->symbolic()) {
+       COIN_DETAIL_PRINT(printf("Error return from symbolic - probably not enough memory\n"));
+          problemStatus_ = 4;
+          //delete all temporary regions
+          deleteWorkingData();
+          if (saveMatrix) {
+               // restore normal copy
+               delete matrix_;
+               matrix_ = saveMatrix;
+          }
+          // Restore quadratic objective if necessary
+          if (saveObjective) {
+               delete objective_;
+               objective_ = saveObjective;
+          }
+          return -1;
+     }
+     mu_ = 1.0e10;
+     diagonalScaleFactor_ = 1.0;
+     //set iterations
+     numberIterations_ = -1;
+     int numberTotal = numberRows_ + numberColumns_;
+     //initialize solution here
+     if(createSolution() < 0) {
+       COIN_DETAIL_PRINT(printf("Not enough memory\n"));
+          problemStatus_ = 4;
+          //delete all temporary regions
+          deleteWorkingData();
+          if (saveMatrix) {
+               // restore normal copy
+               delete matrix_;
+               matrix_ = saveMatrix;
+          }
+          return -1;
+     }
+     CoinWorkDouble * dualArray = reinterpret_cast<CoinWorkDouble *>(dual_);
+     // Could try centering steps without any original step i.e. just center
+     //firstFactorization(false);
+     CoinZeroN(dualArray, numberRows_);
+     multiplyAdd(solution_ + numberColumns_, numberRows_, -1.0, errorRegion_, 0.0);
+     matrix_->times(1.0, solution_, errorRegion_);
+     maximumRHSError_ = maximumAbsElement(errorRegion_, numberRows_);
+     maximumBoundInfeasibility_ = maximumRHSError_;
+     //CoinWorkDouble maximumDualError_=COIN_DBL_MAX;
+     //initialize
+     actualDualStep_ = 0.0;
+     actualPrimalStep_ = 0.0;
+     gonePrimalFeasible_ = false;
+     goneDualFeasible_ = false;
+     //bool hadGoodSolution=false;
+     diagonalNorm_ = solutionNorm_;
+     mu_ = solutionNorm_;
+     int numberFixed = updateSolution(-COIN_DBL_MAX);
+     int numberFixedTotal = numberFixed;
+     //int numberRows_DroppedBefore=0;
+     //CoinWorkDouble extra=eExtra;
+     //CoinWorkDouble maximumPerturbation=COIN_DBL_MAX;
+     //constants for infeas interior point
+     const CoinWorkDouble beta2 = 0.99995;
+     const CoinWorkDouble tau   = 0.00002;
+     CoinWorkDouble lastComplementarityGap = COIN_DBL_MAX * 1.0e-20;
+     CoinWorkDouble lastStep = 1.0;
+     // use to see if to take affine
+     CoinWorkDouble checkGap = COIN_DBL_MAX;
+     int lastGoodIteration = 0;
+     CoinWorkDouble bestObjectiveGap = COIN_DBL_MAX;
+     CoinWorkDouble bestObjective = COIN_DBL_MAX;
+     int bestKilled = -1;
+     int saveIteration = -1;
+     int saveIteration2 = -1;
+     bool sloppyOptimal = false;
+     // this just to be used to exit
+     bool sloppyOptimal2 = false;
+     CoinWorkDouble * savePi = NULL;
+     CoinWorkDouble * savePrimal = NULL;
+     CoinWorkDouble * savePi2 = NULL;
+     CoinWorkDouble * savePrimal2 = NULL;
+     // Extra regions for centering
+     CoinWorkDouble * saveX = new CoinWorkDouble[numberTotal];
+     CoinWorkDouble * saveY = new CoinWorkDouble[numberRows_];
+     CoinWorkDouble * saveZ = new CoinWorkDouble[numberTotal];
+     CoinWorkDouble * saveW = new CoinWorkDouble[numberTotal];
+     CoinWorkDouble * saveSL = new CoinWorkDouble[numberTotal];
+     CoinWorkDouble * saveSU = new CoinWorkDouble[numberTotal];
+     // Save smallest mu used in primal dual moves
+     CoinWorkDouble objScale = optimizationDirection_ /
+                               (rhsScale_ * objectiveScale_);
+     while (problemStatus_ < 0) {
+          //#define FULL_DEBUG
+#ifdef FULL_DEBUG
+          {
+               int i;
+               printf("row    pi          artvec       rhsfx\n");
+               for (i = 0; i < numberRows_; i++) {
+                    printf("%d %g %g %g\n", i, dual_[i], errorRegion_[i], rhsFixRegion_[i]);
+               }
+               printf(" col  dsol  ddiag  dwvec  dzvec dbdslu dbdsll\n");
+               for (i = 0; i < numberColumns_ + numberRows_; i++) {
+                    printf(" %d %g %g %g %g %g %g\n", i, solution_[i], diagonal_[i], wVec_[i],
+                           zVec_[i], upperSlack_[i], lowerSlack_[i]);
+               }
+          }
+#endif
+          complementarityGap_ = complementarityGap(numberComplementarityPairs_,
+                                numberComplementarityItems_, 0);
+          handler_->message(CLP_BARRIER_ITERATION, messages_)
+                    << numberIterations_
+                    << static_cast<double>(primalObjective_ * objScale - dblParam_[ClpObjOffset])
+                    << static_cast<double>(dualObjective_ * objScale - dblParam_[ClpObjOffset])
+                    << static_cast<double>(complementarityGap_)
+                    << numberFixedTotal
+                    << cholesky_->rank()
+                    << CoinMessageEol;
+	  // Check event
+	  {
+	    int status = eventHandler_->event(ClpEventHandler::endOfIteration);
+	    if (status >= 0) {
+	      problemStatus_ = 5;
+	      secondaryStatus_ = ClpEventHandler::endOfIteration;
+	      break;
+	    }
+	  }
+#if 0
+          if (numberIterations_ == -1) {
+               saveSolution("xxx.sav");
+               if (yyyyyy)
+                    exit(99);
+          }
+#endif
+          // move up history
+          for (i = 1; i < LENGTH_HISTORY; i++)
+               historyInfeasibility_[i-1] = historyInfeasibility_[i];
+          historyInfeasibility_[LENGTH_HISTORY-1] = complementarityGap_;
+          // switch off saved if changes
+          //if (saveIteration+10<numberIterations_&&
+          //complementarityGap_*2.0<historyInfeasibility_[0])
+          //saveIteration=-1;
+          lastStep = CoinMin(actualPrimalStep_, actualDualStep_);
+          CoinWorkDouble goodGapChange;
+          //#define KEEP_GOING_IF_FIXED 5
+#ifndef KEEP_GOING_IF_FIXED
+#define KEEP_GOING_IF_FIXED 10000
+#endif
+          if (!sloppyOptimal) {
+               goodGapChange = 0.93;
+          } else {
+               goodGapChange = 0.7;
+               if (numberFixed > KEEP_GOING_IF_FIXED)
+                    goodGapChange = 0.99; // make more likely to carry on
+          }
+          CoinWorkDouble gapO;
+          CoinWorkDouble lastGood = bestObjectiveGap;
+          if (gonePrimalFeasible_ && goneDualFeasible_) {
+               CoinWorkDouble largestObjective;
+               if (CoinAbs(primalObjective_) > CoinAbs(dualObjective_)) {
+                    largestObjective = CoinAbs(primalObjective_);
+               } else {
+                    largestObjective = CoinAbs(dualObjective_);
+               }
+               if (largestObjective < 1.0) {
+                    largestObjective = 1.0;
+               }
+               gapO = CoinAbs(primalObjective_ - dualObjective_) / largestObjective;
+               handler_->message(CLP_BARRIER_OBJECTIVE_GAP, messages_)
+                         << static_cast<double>(gapO)
+                         << CoinMessageEol;
+               //start saving best
+               bool saveIt = false;
+               if (gapO < bestObjectiveGap) {
+                    bestObjectiveGap = gapO;
+#ifndef SAVE_ON_OBJ
+                    saveIt = true;
+#endif
+               }
+               if (primalObjective_ < bestObjective) {
+                    bestObjective = primalObjective_;
+#ifdef SAVE_ON_OBJ
+                    saveIt = true;
+#endif
+               }
+               if (numberFixedTotal > bestKilled) {
+                    bestKilled = numberFixedTotal;
+#if KEEP_GOING_IF_FIXED<10
+                    saveIt = true;
+#endif
+               }
+               if (saveIt) {
+#if KEEP_GOING_IF_FIXED<10
+		 COIN_DETAIL_PRINT(printf("saving\n"));
+#endif
+                    saveIteration = numberIterations_;
+                    if (!savePi) {
+                         savePi = new CoinWorkDouble[numberRows_];
+                         savePrimal = new CoinWorkDouble [numberTotal];
+                    }
+                    CoinMemcpyN(dualArray, numberRows_, savePi);
+                    CoinMemcpyN(solution_, numberTotal, savePrimal);
+               } else if(gapO > 2.0 * bestObjectiveGap) {
+                    //maybe be more sophisticated e.g. re-initialize having
+                    //fixed variables and dropped rows
+                    //std::cout <<" gap increasing "<<std::endl;
+               }
+               //std::cout <<"could stop"<<std::endl;
+               //gapO=0.0;
+               if (CoinAbs(primalObjective_ - dualObjective_) < dualTolerance()) {
+                    gapO = 0.0;
+               }
+          } else {
+               gapO = COIN_DBL_MAX;
+               if (saveIteration >= 0) {
+                    handler_->message(CLP_BARRIER_GONE_INFEASIBLE, messages_)
+                              << CoinMessageEol;
+                    CoinWorkDouble scaledRHSError = maximumRHSError_ / (solutionNorm_ + 10.0);
+                    // save alternate
+                    if (numberFixedTotal > bestKilled &&
+                              maximumBoundInfeasibility_ < 1.0e-6 &&
+                              scaledRHSError < 1.0e-2) {
+                         bestKilled = numberFixedTotal;
+#if KEEP_GOING_IF_FIXED<10
+                         COIN_DETAIL_PRINT(printf("saving alternate\n"));
+#endif
+                         saveIteration2 = numberIterations_;
+                         if (!savePi2) {
+                              savePi2 = new CoinWorkDouble[numberRows_];
+                              savePrimal2 = new CoinWorkDouble [numberTotal];
+                         }
+                         CoinMemcpyN(dualArray, numberRows_, savePi2);
+                         CoinMemcpyN(solution_, numberTotal, savePrimal2);
+                    }
+                    if (sloppyOptimal2) {
+                         // vaguely optimal
+                         if (maximumBoundInfeasibility_ > 1.0e-2 ||
+                                   scaledRHSError > 1.0e-2 ||
+                                   maximumDualError_ > objectiveNorm_ * 1.0e-2) {
+                              handler_->message(CLP_BARRIER_EXIT2, messages_)
+                                        << saveIteration
+                                        << CoinMessageEol;
+                              problemStatus_ = 0; // benefit of doubt
+                              break;
+                         }
+                    } else {
+                         // not close to optimal but check if getting bad
+                         CoinWorkDouble scaledRHSError = maximumRHSError_ / (solutionNorm_ + 10.0);
+                         if ((maximumBoundInfeasibility_ > 1.0e-1 ||
+                                   scaledRHSError > 1.0e-1 ||
+                                   maximumDualError_ > objectiveNorm_ * 1.0e-1)
+                                   && (numberIterations_ > 50
+                                       && complementarityGap_ > 0.9 * historyInfeasibility_[0])) {
+                              handler_->message(CLP_BARRIER_EXIT2, messages_)
+                                        << saveIteration
+                                        << CoinMessageEol;
+                              break;
+                         }
+                         if (complementarityGap_ > 0.95 * checkGap && bestObjectiveGap < 1.0e-3 &&
+                                   (numberIterations_ > saveIteration + 5 || numberIterations_ > 100)) {
+                              handler_->message(CLP_BARRIER_EXIT2, messages_)
+                                        << saveIteration
+                                        << CoinMessageEol;
+                              break;
+                         }
+                    }
+               }
+               if (complementarityGap_ > 0.5 * checkGap && primalObjective_ >
+                         bestObjective + 1.0e-9 &&
+                         (numberIterations_ > saveIteration + 5 || numberIterations_ > 100)) {
+                    handler_->message(CLP_BARRIER_EXIT2, messages_)
+                              << saveIteration
+                              << CoinMessageEol;
+                    break;
+               }
+          }
+	  // See if we should be thinking about exit if diverging
+	  double relativeMultiplier = 1.0 + fabs(primalObjective_) + fabs(dualObjective_);
+	  // Quadratic coding is rubbish so be more forgiving?
+	  if (quadraticObj)
+	    relativeMultiplier *= 5.0;
+	  if (gapO < 1.0e-5 + 1.0e-9 * relativeMultiplier
+	      || complementarityGap_ < 0.1 + 1.0e-9 * relativeMultiplier)
+	      sloppyOptimal2 = true;
+          if ((gapO < 1.0e-6 || (gapO < 1.0e-4 && complementarityGap_ < 0.1)) && !sloppyOptimal) {
+               sloppyOptimal = true;
+               sloppyOptimal2 = true;
+               handler_->message(CLP_BARRIER_CLOSE_TO_OPTIMAL, messages_)
+                         << numberIterations_ << static_cast<double>(complementarityGap_)
+                         << CoinMessageEol;
+          }
+          int numberBack = quadraticObj ? 10 : 5;
+          //tryJustPredictor=true;
+          //printf("trying just predictor\n");
+          //}
+          if (complementarityGap_ >= 1.05 * lastComplementarityGap) {
+               handler_->message(CLP_BARRIER_COMPLEMENTARITY, messages_)
+                         << static_cast<double>(complementarityGap_) << "increasing"
+                         << CoinMessageEol;
+               if (saveIteration >= 0 && sloppyOptimal2) {
+                    handler_->message(CLP_BARRIER_EXIT2, messages_)
+                              << saveIteration
+                              << CoinMessageEol;
+                    break;
+               } else if (numberIterations_ - lastGoodIteration >= numberBack &&
+                          complementarityGap_ < 1.0e-6) {
+                    break; // not doing very well - give up
+               }
+          } else if (complementarityGap_ < goodGapChange * lastComplementarityGap) {
+               lastGoodIteration = numberIterations_;
+               lastComplementarityGap = complementarityGap_;
+          } else if (numberIterations_ - lastGoodIteration >= numberBack &&
+                     complementarityGap_ < 1.0e-3) {
+               handler_->message(CLP_BARRIER_COMPLEMENTARITY, messages_)
+                         << static_cast<double>(complementarityGap_) << "not decreasing"
+                         << CoinMessageEol;
+               if (gapO > 0.75 * lastGood && numberFixed < KEEP_GOING_IF_FIXED) {
+                    break;
+               }
+          } else if (numberIterations_ - lastGoodIteration >= 2 &&
+                     complementarityGap_ < 1.0e-6) {
+               handler_->message(CLP_BARRIER_COMPLEMENTARITY, messages_)
+                         << static_cast<double>(complementarityGap_) << "not decreasing"
+                         << CoinMessageEol;
+               break;
+          }
+          if (numberIterations_ > maximumBarrierIterations_ || hitMaximumIterations()) {
+               handler_->message(CLP_BARRIER_STOPPING, messages_)
+                         << CoinMessageEol;
+               problemStatus_ = 3;
+               onStopped(); // set secondary status
+               break;
+          }
+          if (gapO < targetGap_) {
+               problemStatus_ = 0;
+               handler_->message(CLP_BARRIER_EXIT, messages_)
+                         << " "
+                         << CoinMessageEol;
+               break;//finished
+          }
+          if (complementarityGap_ < 1.0e-12) {
+               problemStatus_ = 0;
+               handler_->message(CLP_BARRIER_EXIT, messages_)
+                         << "- small complementarity gap"
+                         << CoinMessageEol;
+               break;//finished
+          }
+          if (complementarityGap_ < 1.0e-10 && gapO < 1.0e-10) {
+               problemStatus_ = 0;
+               handler_->message(CLP_BARRIER_EXIT, messages_)
+                         << "- objective gap and complementarity gap both small"
+                         << CoinMessageEol;
+               break;//finished
+          }
+          if (gapO < 1.0e-9) {
+               CoinWorkDouble value = gapO * complementarityGap_;
+               value *= actualPrimalStep_;
+               value *= actualDualStep_;
+               //std::cout<<value<<std::endl;
+               if (value < 1.0e-17 && numberIterations_ > lastGoodIteration) {
+                    problemStatus_ = 0;
+                    handler_->message(CLP_BARRIER_EXIT, messages_)
+                              << "- objective gap and complementarity gap both smallish and small steps"
+                              << CoinMessageEol;
+                    break;//finished
+               }
+          }
+          CoinWorkDouble nextGap = COIN_DBL_MAX;
+          int nextNumber = 0;
+          int nextNumberItems = 0;
+          worstDirectionAccuracy_ = 0.0;
+          int newDropped = 0;
+          //Predictor step
+          //prepare for cholesky.  Set up scaled diagonal in deltaX
+          //  ** for efficiency may be better if scale factor known before
+          CoinWorkDouble norm2 = 0.0;
+          CoinWorkDouble maximumValue;
+          getNorms(diagonal_, numberTotal, maximumValue, norm2);
+          diagonalNorm_ = CoinSqrt(norm2 / numberComplementarityPairs_);
+          diagonalScaleFactor_ = 1.0;
+          CoinWorkDouble maximumAllowable = eScale;
+          //scale so largest is less than allowable ? could do better
+          CoinWorkDouble factor = 0.5;
+          while (maximumValue > maximumAllowable) {
+               diagonalScaleFactor_ *= factor;
+               maximumValue *= factor;
+          } /* endwhile */
+          if (diagonalScaleFactor_ != 1.0) {
+               handler_->message(CLP_BARRIER_SCALING, messages_)
+                         << "diagonal" << static_cast<double>(diagonalScaleFactor_)
+                         << CoinMessageEol;
+               diagonalNorm_ *= diagonalScaleFactor_;
+          }
+          multiplyAdd(NULL, numberTotal, 0.0, diagonal_,
+                      diagonalScaleFactor_);
+          int * rowsDroppedThisTime = new int [numberRows_];
+          newDropped = cholesky_->factorize(diagonal_, rowsDroppedThisTime);
+          if (newDropped) {
+               if (newDropped == -1) {
+		 COIN_DETAIL_PRINT(printf("Out of memory\n"));
+                    problemStatus_ = 4;
+                    //delete all temporary regions
+                    deleteWorkingData();
+                    if (saveMatrix) {
+                         // restore normal copy
+                         delete matrix_;
+                         matrix_ = saveMatrix;
+                    }
+                    return -1;
+               } else {
+#ifndef NDEBUG
+                    //int newDropped2=cholesky_->factorize(diagonal_,rowsDroppedThisTime);
+                    //assert(!newDropped2);
+#endif
+                    if (newDropped < 0 && 0) {
+                         //replace dropped
+                         newDropped = -newDropped;
+                         //off 1 to allow for reset all
+                         newDropped--;
+                         //set all bits false
+                         cholesky_->resetRowsDropped();
+                    }
+               }
+          }
+          delete [] rowsDroppedThisTime;
+          if (cholesky_->status()) {
+               std::cout << "bad cholesky?" << std::endl;
+               abort();
+          }
+          int phase = 0; // predictor, corrector , primal dual
+          CoinWorkDouble directionAccuracy = 0.0;
+          bool doCorrector = true;
+          bool goodMove = true;
+          //set up for affine direction
+          setupForSolve(phase);
+          if ((modeSwitch & 2) == 0) {
+               directionAccuracy = findDirectionVector(phase);
+               if (directionAccuracy > worstDirectionAccuracy_) {
+                    worstDirectionAccuracy_ = directionAccuracy;
+               }
+               if (saveIteration > 0 && directionAccuracy > 1.0) {
+                    handler_->message(CLP_BARRIER_EXIT2, messages_)
+                              << saveIteration
+                              << CoinMessageEol;
+                    break;
+               }
+               findStepLength(phase);
+               nextGap = complementarityGap(nextNumber, nextNumberItems, 1);
+               debugMove(0, actualPrimalStep_, actualDualStep_);
+               debugMove(0, 1.0e-2, 1.0e-2);
+          }
+          CoinWorkDouble affineGap = nextGap;
+          int bestPhase = 0;
+          CoinWorkDouble bestNextGap = nextGap;
+          // ?
+          bestNextGap = CoinMax(nextGap, 0.8 * complementarityGap_);
+          if (quadraticObj)
+               bestNextGap = CoinMax(nextGap, 0.99 * complementarityGap_);
+          if (complementarityGap_ > 1.0e-4 * numberComplementarityPairs_) {
+               //std::cout <<"predicted duality gap "<<nextGap<<std::endl;
+               CoinWorkDouble part1 = nextGap / numberComplementarityPairs_;
+               part1 = nextGap / numberComplementarityItems_;
+               CoinWorkDouble part2 = nextGap / complementarityGap_;
+               mu_ = part1 * part2 * part2;
+#if 0
+               CoinWorkDouble papermu = complementarityGap_ / numberComplementarityPairs_;
+               CoinWorkDouble affmu = nextGap / nextNumber;
+               CoinWorkDouble sigma = pow(affmu / papermu, 3);
+               printf("mu %g, papermu %g, affmu %g, sigma %g sigmamu %g\n",
+                      mu_, papermu, affmu, sigma, sigma * papermu);
+#endif
+               //printf("paper mu %g\n",(nextGap*nextGap*nextGap)/(complementarityGap_*complementarityGap_*
+               //					    (CoinWorkDouble) numberComplementarityPairs_));
+          } else {
+               CoinWorkDouble phi;
+               if (numberComplementarityPairs_ <= 5000) {
+                    phi = pow(static_cast<CoinWorkDouble> (numberComplementarityPairs_), 2.0);
+               } else {
+                    phi = pow(static_cast<CoinWorkDouble> (numberComplementarityPairs_), 1.5);
+                    if (phi < 500.0 * 500.0) {
+                         phi = 500.0 * 500.0;
+                    }
+               }
+               mu_ = complementarityGap_ / phi;
+          }
+          //save information
+          CoinWorkDouble product = affineProduct();
+#if 0
+          //can we do corrector step?
+          CoinWorkDouble xx = complementarityGap_ * (beta2 - tau) + product;
+          if (xx > 0.0) {
+               CoinWorkDouble saveMu = mu_;
+               CoinWorkDouble mu2 = numberComplementarityPairs_;
+               mu2 = xx / mu2;
+               if (mu2 > mu_) {
+                    //std::cout<<" could increase to "<<mu2<<std::endl;
+                    //was mu2=mu2*0.25;
+                    mu2 = mu2 * 0.99;
+                    if (mu2 < mu_) {
+                         mu_ = mu2;
+                         //std::cout<<" changing mu to "<<mu_<<std::endl;
+                    } else {
+                         //std::cout<<std::endl;
+                    }
+               } else {
+                    //std::cout<<" should decrease to "<<mu2<<std::endl;
+                    mu_ = 0.5 * mu2;
+                    //std::cout<<" changing mu to "<<mu_<<std::endl;
+               }
+               handler_->message(CLP_BARRIER_MU, messages_)
+                         << saveMu << mu_
+                         << CoinMessageEol;
+          } else {
+               //std::cout<<" bad by any standards"<<std::endl;
+          }
+#endif
+          if (complementarityGap_*(beta2 - tau) + product - mu_ * numberComplementarityPairs_ < 0.0 && 0) {
+#ifdef SOME_DEBUG
+               printf("failed 1 product %.18g mu %.18g - %.18g < 0.0, nextGap %.18g\n", product, mu_,
+                      complementarityGap_*(beta2 - tau) + product - mu_ * numberComplementarityPairs_,
+                      nextGap);
+#endif
+               doCorrector = false;
+               if (nextGap > 0.9 * complementarityGap_ || 1) {
+                    goodMove = false;
+                    bestNextGap = COIN_DBL_MAX;
+               }
+               //CoinWorkDouble floatNumber = 2.0*numberComplementarityPairs_;
+               //floatNumber = 1.0*numberComplementarityItems_;
+               //mu_=nextGap/floatNumber;
+               handler_->message(CLP_BARRIER_INFO, messages_)
+                         << "no corrector step"
+                         << CoinMessageEol;
+          } else {
+               phase = 1;
+          }
+          // If bad gap - try standard primal dual
+          if (nextGap > complementarityGap_ * 1.001)
+               goodMove = false;
+          if ((modeSwitch & 2) != 0)
+               goodMove = false;
+          if (goodMove && doCorrector) {
+               CoinMemcpyN(deltaX_, numberTotal, saveX);
+               CoinMemcpyN(deltaY_, numberRows_, saveY);
+               CoinMemcpyN(deltaZ_, numberTotal, saveZ);
+               CoinMemcpyN(deltaW_, numberTotal, saveW);
+               CoinMemcpyN(deltaSL_, numberTotal, saveSL);
+               CoinMemcpyN(deltaSU_, numberTotal, saveSU);
+#ifdef HALVE
+               CoinWorkDouble savePrimalStep = actualPrimalStep_;
+               CoinWorkDouble saveDualStep = actualDualStep_;
+               CoinWorkDouble saveMu = mu_;
+#endif
+               //set up for next step
+               setupForSolve(phase);
+               CoinWorkDouble directionAccuracy2 = findDirectionVector(phase);
+               if (directionAccuracy2 > worstDirectionAccuracy_) {
+                    worstDirectionAccuracy_ = directionAccuracy2;
+               }
+               CoinWorkDouble testValue = 1.0e2 * directionAccuracy;
+               if (1.0e2 * projectionTolerance_ > testValue) {
+                    testValue = 1.0e2 * projectionTolerance_;
+               }
+               if (primalTolerance() > testValue) {
+                    testValue = primalTolerance();
+               }
+               if (maximumRHSError_ > testValue) {
+                    testValue = maximumRHSError_;
+               }
+               if (directionAccuracy2 > testValue && numberIterations_ >= -77) {
+                    goodMove = false;
+#ifdef SOME_DEBUG
+                    printf("accuracy %g phase 1 failed, test value %g\n",
+                           directionAccuracy2, testValue);
+#endif
+               }
+               if (goodMove) {
+                    phase = 1;
+                    CoinWorkDouble norm = findStepLength(phase);
+                    nextGap = complementarityGap(nextNumber, nextNumberItems, 1);
+                    debugMove(1, actualPrimalStep_, actualDualStep_);
+                    //debugMove(1,1.0e-7,1.0e-7);
+                    goodMove = checkGoodMove(true, bestNextGap, allowIncreasingGap);
+                    if (norm < 0)
+                         goodMove = false;
+                    if (!goodMove) {
+#ifdef SOME_DEBUG
+                         printf("checkGoodMove failed\n");
+#endif
+                    }
+               }
+#ifdef HALVE
+               int nHalve = 0;
+               // relax test
+               bestNextGap = CoinMax(bestNextGap, 0.9 * complementarityGap_);
+               while (!goodMove) {
+                    mu_ = saveMu;
+                    actualPrimalStep_ = savePrimalStep;
+                    actualDualStep_ = saveDualStep;
+                    int i;
+                    //printf("halve %d\n",nHalve);
+                    nHalve++;
+                    const CoinWorkDouble lambda = 0.5;
+                    for (i = 0; i < numberRows_; i++)
+                         deltaY_[i] = lambda * deltaY_[i] + (1.0 - lambda) * saveY[i];
+                    for (i = 0; i < numberTotal; i++) {
+                         deltaX_[i] = lambda * deltaX_[i] + (1.0 - lambda) * saveX[i];
+                         deltaZ_[i] = lambda * deltaZ_[i] + (1.0 - lambda) * saveZ[i];
+                         deltaW_[i] = lambda * deltaW_[i] + (1.0 - lambda) * saveW[i];
+                         deltaSL_[i] = lambda * deltaSL_[i] + (1.0 - lambda) * saveSL[i];
+                         deltaSU_[i] = lambda * deltaSU_[i] + (1.0 - lambda) * saveSU[i];
+                    }
+                    CoinMemcpyN(saveX, numberTotal, deltaX_);
+                    CoinMemcpyN(saveY, numberRows_, deltaY_);
+                    CoinMemcpyN(saveZ, numberTotal, deltaZ_);
+                    CoinMemcpyN(saveW, numberTotal, deltaW_);
+                    CoinMemcpyN(saveSL, numberTotal, deltaSL_);
+                    CoinMemcpyN(saveSU, numberTotal, deltaSU_);
+                    findStepLength(1);
+                    nextGap = complementarityGap(nextNumber, nextNumberItems, 1);
+                    goodMove = checkGoodMove(true, bestNextGap, allowIncreasingGap);
+                    if (nHalve > 10)
+                         break;
+                    //assert (goodMove);
+               }
+               if (nHalve && handler_->logLevel() > 2)
+                    printf("halved %d times\n", nHalve);
+#endif
+          }
+          //bestPhase=-1;
+          //goodMove=false;
+          if (!goodMove) {
+               // Just primal dual step
+               CoinWorkDouble floatNumber;
+               floatNumber = 2.0 * numberComplementarityPairs_;
+               //floatNumber = numberComplementarityItems_;
+               CoinWorkDouble saveMu = mu_; // use one from predictor corrector
+               mu_ = complementarityGap_ / floatNumber;
+               // If going well try small mu
+               mu_ *= CoinSqrt((1.0 - lastStep) / (1.0 + 10.0 * lastStep));
+               CoinWorkDouble mu1 = mu_;
+               CoinWorkDouble phi;
+               if (numberComplementarityPairs_ <= 500) {
+                    phi = pow(static_cast<CoinWorkDouble> (numberComplementarityPairs_), 2.0);
+               } else {
+                    phi = pow(static_cast<CoinWorkDouble> (numberComplementarityPairs_), 1.5);
+                    if (phi < 500.0 * 500.0) {
+                         phi = 500.0 * 500.0;
+                    }
+               }
+               mu_ = complementarityGap_ / phi;
+               //printf("pd mu %g, alternate %g, smallest\n",mu_,mu1);
+               mu_ = CoinSqrt(mu_ * mu1);
+               mu_ = mu1;
+               if ((numberIterations_ & 1) == 0 || numberIterations_ < 10)
+                    mu_ = saveMu;
+               // Try simpler
+               floatNumber = numberComplementarityItems_;
+               mu_ = 0.5 * complementarityGap_ / floatNumber;
+               //if ((modeSwitch&2)==0) {
+               //if ((numberIterations_&1)==0)
+               //  mu_ *= 0.5;
+               //} else {
+               //mu_ *= 0.8;
+               //}
+               //set up for next step
+               setupForSolve(2);
+               findDirectionVector(2);
+               CoinWorkDouble norm = findStepLength(2);
+               // just for debug
+               bestNextGap = complementarityGap_ * 1.0005;
+               //bestNextGap=COIN_DBL_MAX;
+               nextGap = complementarityGap(nextNumber, nextNumberItems, 2);
+               debugMove(2, actualPrimalStep_, actualDualStep_);
+               //debugMove(2,1.0e-7,1.0e-7);
+               checkGoodMove(false, bestNextGap, allowIncreasingGap);
+               if ((nextGap > 0.9 * complementarityGap_ && bestPhase == 0 && affineGap < nextGap
+                         && (numberIterations_ > 80 || (numberIterations_ > 20 && quadraticObj))) || norm < 0.0) {
+                    // Back to affine
+                    phase = 0;
+                    setupForSolve(phase);
+                    directionAccuracy = findDirectionVector(phase);
+                    findStepLength(phase);
+                    nextGap = complementarityGap(nextNumber, nextNumberItems, 1);
+                    bestNextGap = complementarityGap_;
+                    //checkGoodMove(false, bestNextGap,allowIncreasingGap);
+               }
+          }
+          if (!goodMove)
+               mu_ = nextGap / (static_cast<CoinWorkDouble> (nextNumber) * 1.1);
+          //if (quadraticObj)
+          //goodMove=true;
+          //goodMove=false; //TEMP
+          // Do centering steps
+          int numberTries = 0;
+          int numberGoodTries = 0;
+#ifdef COIN_DETAIL
+          CoinWorkDouble nextCenterGap = 0.0;
+          CoinWorkDouble originalDualStep = actualDualStep_;
+          CoinWorkDouble originalPrimalStep = actualPrimalStep_;
+#endif
+          if (actualDualStep_ > 0.9 && actualPrimalStep_ > 0.9)
+               goodMove = false; // don't bother
+          if ((modeSwitch & 1) != 0)
+               goodMove = false;
+          while (goodMove && numberTries < 5) {
+               goodMove = false;
+               numberTries++;
+               CoinMemcpyN(deltaX_, numberTotal, saveX);
+               CoinMemcpyN(deltaY_, numberRows_, saveY);
+               CoinMemcpyN(deltaZ_, numberTotal, saveZ);
+               CoinMemcpyN(deltaW_, numberTotal, saveW);
+               CoinWorkDouble savePrimalStep = actualPrimalStep_;
+               CoinWorkDouble saveDualStep = actualDualStep_;
+               CoinWorkDouble saveMu = mu_;
+               setupForSolve(3);
+               findDirectionVector(3);
+               findStepLength(3);
+               debugMove(3, actualPrimalStep_, actualDualStep_);
+               //debugMove(3,1.0e-7,1.0e-7);
+               CoinWorkDouble xGap = complementarityGap(nextNumber, nextNumberItems, 3);
+               // If one small then that's the one that counts
+               CoinWorkDouble checkDual = saveDualStep;
+               CoinWorkDouble checkPrimal = savePrimalStep;
+               if (checkDual > 5.0 * checkPrimal) {
+                    checkDual = 2.0 * checkPrimal;
+               } else if (checkPrimal > 5.0 * checkDual) {
+                    checkPrimal = 2.0 * checkDual;
+               }
+               if (actualPrimalStep_ < checkPrimal ||
+                         actualDualStep_ < checkDual ||
+                         (xGap > nextGap && xGap > 0.9 * complementarityGap_)) {
+                    //if (actualPrimalStep_<=checkPrimal||
+                    //actualDualStep_<=checkDual) {
+#ifdef SOME_DEBUG
+                    printf("PP rejected gap %.18g, steps %.18g %.18g, 2 gap %.18g, steps %.18g %.18g\n", xGap,
+                           actualPrimalStep_, actualDualStep_, nextGap, savePrimalStep, saveDualStep);
+#endif
+                    mu_ = saveMu;
+                    actualPrimalStep_ = savePrimalStep;
+                    actualDualStep_ = saveDualStep;
+                    CoinMemcpyN(saveX, numberTotal, deltaX_);
+                    CoinMemcpyN(saveY, numberRows_, deltaY_);
+                    CoinMemcpyN(saveZ, numberTotal, deltaZ_);
+                    CoinMemcpyN(saveW, numberTotal, deltaW_);
+               } else {
+#ifdef SOME_DEBUG
+                    printf("PPphase 3 gap %.18g, steps %.18g %.18g, 2 gap %.18g, steps %.18g %.18g\n", xGap,
+                           actualPrimalStep_, actualDualStep_, nextGap, savePrimalStep, saveDualStep);
+#endif
+                    numberGoodTries++;
+#ifdef COIN_DETAIL
+                    nextCenterGap = xGap;
+#endif
+                    // See if big enough change
+                    if (actualPrimalStep_ < 1.01 * checkPrimal ||
+                              actualDualStep_ < 1.01 * checkDual) {
+                         // stop now
+                    } else {
+                         // carry on
+                         goodMove = true;
+                    }
+               }
+          }
+          if (numberGoodTries && handler_->logLevel() > 1) {
+               COIN_DETAIL_PRINT(printf("%d centering steps moved from (gap %.18g, dual %.18g, primal %.18g) to (gap %.18g, dual %.18g, primal %.18g)\n",
+                      numberGoodTries, static_cast<double>(nextGap), static_cast<double>(originalDualStep),
+                      static_cast<double>(originalPrimalStep),
+                      static_cast<double>(nextCenterGap), static_cast<double>(actualDualStep_),
+					static_cast<double>(actualPrimalStep_)));
+          }
+          // save last gap
+          checkGap = complementarityGap_;
+          numberFixed = updateSolution(nextGap);
+          numberFixedTotal += numberFixed;
+     } /* endwhile */
+     delete [] saveX;
+     delete [] saveY;
+     delete [] saveZ;
+     delete [] saveW;
+     delete [] saveSL;
+     delete [] saveSU;
+     if (savePi) {
+          if (numberIterations_ - saveIteration > 20 &&
+                    numberIterations_ - saveIteration2 < 5) {
+#if KEEP_GOING_IF_FIXED<10
+               std::cout << "Restoring2 from iteration " << saveIteration2 << std::endl;
+#endif
+               CoinMemcpyN(savePi2, numberRows_, dualArray);
+               CoinMemcpyN(savePrimal2, numberTotal, solution_);
+          } else {
+#if KEEP_GOING_IF_FIXED<10
+               std::cout << "Restoring from iteration " << saveIteration << std::endl;
+#endif
+               CoinMemcpyN(savePi, numberRows_, dualArray);
+               CoinMemcpyN(savePrimal, numberTotal, solution_);
+          }
+          delete [] savePi;
+          delete [] savePrimal;
+     }
+     delete [] savePi2;
+     delete [] savePrimal2;
+     //recompute slacks
+     // Split out solution
+     CoinZeroN(rowActivity_, numberRows_);
+     CoinMemcpyN(solution_, numberColumns_, columnActivity_);
+     matrix_->times(1.0, columnActivity_, rowActivity_);
+     //unscale objective
+     multiplyAdd(NULL, numberTotal, 0.0, cost_, scaleFactor_);
+     multiplyAdd(NULL, numberRows_, 0, dualArray, scaleFactor_);
+     checkSolution();
+     //CoinMemcpyN(reducedCost_,numberColumns_,dj_);
+     // If quadratic use last solution
+     // Restore quadratic objective if necessary
+     if (saveObjective) {
+          delete objective_;
+          objective_ = saveObjective;
+          objectiveValue_ = 0.5 * (primalObjective_ + dualObjective_);
+     }
+     handler_->message(CLP_BARRIER_END, messages_)
+               << static_cast<double>(sumPrimalInfeasibilities_)
+               << static_cast<double>(sumDualInfeasibilities_)
+               << static_cast<double>(complementarityGap_)
+               << static_cast<double>(objectiveValue())
+               << CoinMessageEol;
+     //#ifdef SOME_DEBUG
+     if (handler_->logLevel() > 1)
+       COIN_DETAIL_PRINT(printf("ENDRUN status %d after %d iterations\n", problemStatus_, numberIterations_));
+     //#endif
+     //std::cout<<"Absolute primal infeasibility at end "<<sumPrimalInfeasibilities_<<std::endl;
+     //std::cout<<"Absolute dual infeasibility at end "<<sumDualInfeasibilities_<<std::endl;
+     //std::cout<<"Absolute complementarity at end "<<complementarityGap_<<std::endl;
+     //std::cout<<"Primal objective "<<objectiveValue()<<std::endl;
+     //std::cout<<"maximum complementarity "<<worstComplementarity_<<std::endl;
+#if COIN_LONG_WORK
+     // put back dual
+     delete [] dual_;
+     delete [] reducedCost_;
+     dual_ = dualSave;
+     reducedCost_ = reducedCostSave;
+#endif
+     //delete all temporary regions
+     deleteWorkingData();
+#if KEEP_GOING_IF_FIXED<10
+#if 0 //ndef NDEBUG
+     {
+          static int kk = 0;
+          char name[20];
+          sprintf(name, "save.sol.%d", kk);
+          kk++;
+          printf("saving to file %s\n", name);
+          FILE * fp = fopen(name, "wb");
+          int numberWritten;
+          numberWritten = fwrite(&numberColumns_, sizeof(int), 1, fp);
+          assert (numberWritten == 1);
+          numberWritten = fwrite(columnActivity_, sizeof(double), numberColumns_, fp);
+          assert (numberWritten == numberColumns_);
+          fclose(fp);
+     }
+#endif
+#endif
+     if (saveMatrix) {
+          // restore normal copy
+          delete matrix_;
+          matrix_ = saveMatrix;
+     }
+     return problemStatus_;
+}
+// findStepLength.
+//phase  - 0 predictor
+//         1 corrector
+//         2 primal dual
+CoinWorkDouble ClpPredictorCorrector::findStepLength( int phase)
+{
+     CoinWorkDouble directionNorm = 0.0;
+     CoinWorkDouble maximumPrimalStep = COIN_DBL_MAX * 1.0e-20;
+     CoinWorkDouble maximumDualStep = COIN_DBL_MAX;
+     int numberTotal = numberRows_ + numberColumns_;
+     CoinWorkDouble tolerance = 1.0e-12;
+#ifdef SOME_DEBUG
+     int chosenPrimalSequence = -1;
+     int chosenDualSequence = -1;
+     bool lowPrimal = false;
+     bool lowDual = false;
+#endif
+     // If done many iterations then allow to hit boundary
+     CoinWorkDouble hitTolerance;
+     //printf("objective norm %g\n",objectiveNorm_);
+     if (numberIterations_ < 80 || !gonePrimalFeasible_)
+          hitTolerance = COIN_DBL_MAX;
+     else
+          hitTolerance = CoinMax(1.0e3, 1.0e-3 * objectiveNorm_);
+     int iColumn;
+     //printf("dual value %g\n",dual_[0]);
+     //printf("     X     dX      lS     dlS     uS     dUs    dj    Z dZ     t   dT\n");
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!flagged(iColumn)) {
+               CoinWorkDouble directionElement = deltaX_[iColumn];
+               if (directionNorm < CoinAbs(directionElement)) {
+                    directionNorm = CoinAbs(directionElement);
+               }
+               if (lowerBound(iColumn)) {
+                    CoinWorkDouble delta = - deltaSL_[iColumn];
+                    CoinWorkDouble z1 = deltaZ_[iColumn];
+                    CoinWorkDouble newZ = zVec_[iColumn] + z1;
+                    if (zVec_[iColumn] > tolerance) {
+                         if (zVec_[iColumn] < -z1 * maximumDualStep) {
+                              maximumDualStep = -zVec_[iColumn] / z1;
+#ifdef SOME_DEBUG
+                              chosenDualSequence = iColumn;
+                              lowDual = true;
+#endif
+                         }
+                    }
+                    if (lowerSlack_[iColumn] < maximumPrimalStep * delta) {
+                         CoinWorkDouble newStep = lowerSlack_[iColumn] / delta;
+                         if (newStep > 0.2 || newZ < hitTolerance || delta > 1.0e3 || delta <= 1.0e-6 || dj_[iColumn] < hitTolerance) {
+                              maximumPrimalStep = newStep;
+#ifdef SOME_DEBUG
+                              chosenPrimalSequence = iColumn;
+                              lowPrimal = true;
+#endif
+                         } else {
+                              //printf("small %d delta %g newZ %g step %g\n",iColumn,delta,newZ,newStep);
+                         }
+                    }
+               }
+               if (upperBound(iColumn)) {
+                    CoinWorkDouble delta = - deltaSU_[iColumn];;
+                    CoinWorkDouble w1 = deltaW_[iColumn];
+                    CoinWorkDouble newT = wVec_[iColumn] + w1;
+                    if (wVec_[iColumn] > tolerance) {
+                         if (wVec_[iColumn] < -w1 * maximumDualStep) {
+                              maximumDualStep = -wVec_[iColumn] / w1;
+#ifdef SOME_DEBUG
+                              chosenDualSequence = iColumn;
+                              lowDual = false;
+#endif
+                         }
+                    }
+                    if (upperSlack_[iColumn] < maximumPrimalStep * delta) {
+                         CoinWorkDouble newStep = upperSlack_[iColumn] / delta;
+                         if (newStep > 0.2 || newT < hitTolerance || delta > 1.0e3 || delta <= 1.0e-6 || dj_[iColumn] > -hitTolerance) {
+                              maximumPrimalStep = newStep;
+#ifdef SOME_DEBUG
+                              chosenPrimalSequence = iColumn;
+                              lowPrimal = false;
+#endif
+                         } else {
+                              //printf("small %d delta %g newT %g step %g\n",iColumn,delta,newT,newStep);
+                         }
+                    }
+               }
+          }
+     }
+#ifdef SOME_DEBUG
+     printf("new step - phase %d, norm %.18g, dual step %.18g, primal step %.18g\n",
+            phase, directionNorm, maximumDualStep, maximumPrimalStep);
+     if (lowDual)
+          printf("ld %d %g %g => %g (dj %g,sol %g) ",
+                 chosenDualSequence, zVec_[chosenDualSequence],
+                 deltaZ_[chosenDualSequence], zVec_[chosenDualSequence] +
+                 maximumDualStep * deltaZ_[chosenDualSequence], dj_[chosenDualSequence],
+                 solution_[chosenDualSequence]);
+     else
+          printf("ud %d %g %g => %g (dj %g,sol %g) ",
+                 chosenDualSequence, wVec_[chosenDualSequence],
+                 deltaW_[chosenDualSequence], wVec_[chosenDualSequence] +
+                 maximumDualStep * deltaW_[chosenDualSequence], dj_[chosenDualSequence],
+                 solution_[chosenDualSequence]);
+     if (lowPrimal)
+          printf("lp %d %g %g => %g (dj %g,sol %g)\n",
+                 chosenPrimalSequence, lowerSlack_[chosenPrimalSequence],
+                 deltaSL_[chosenPrimalSequence], lowerSlack_[chosenPrimalSequence] +
+                 maximumPrimalStep * deltaSL_[chosenPrimalSequence],
+                 dj_[chosenPrimalSequence], solution_[chosenPrimalSequence]);
+     else
+          printf("up %d %g %g => %g (dj %g,sol %g)\n",
+                 chosenPrimalSequence, upperSlack_[chosenPrimalSequence],
+                 deltaSU_[chosenPrimalSequence], upperSlack_[chosenPrimalSequence] +
+                 maximumPrimalStep * deltaSU_[chosenPrimalSequence],
+                 dj_[chosenPrimalSequence], solution_[chosenPrimalSequence]);
+#endif
+     actualPrimalStep_ = stepLength_ * maximumPrimalStep;
+     if (phase >= 0 && actualPrimalStep_ > 1.0) {
+          actualPrimalStep_ = 1.0;
+     }
+     actualDualStep_ = stepLength_ * maximumDualStep;
+     if (phase >= 0 && actualDualStep_ > 1.0) {
+          actualDualStep_ = 1.0;
+     }
+     // See if quadratic objective
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+     if (quadraticObj) {
+          // Use smaller unless very small
+          CoinWorkDouble smallerStep = CoinMin(actualDualStep_, actualPrimalStep_);
+          if (smallerStep > 0.0001) {
+               actualDualStep_ = smallerStep;
+               actualPrimalStep_ = smallerStep;
+          }
+     }
+#define OFFQ
+#ifndef OFFQ
+     if (quadraticObj) {
+          // Don't bother if phase 0 or 3 or large gap
+          //if ((phase==1||phase==2||phase==0)&&maximumDualError_>0.1*complementarityGap_
+          //&&smallerStep>0.001) {
+          if ((phase == 1 || phase == 2 || phase == 0 || phase == 3)) {
+               // minimize complementarity + norm*dual inf ? primal inf
+               // at first - just check better - if not
+               // Complementarity gap will be a*change*change + b*change +c
+               CoinWorkDouble a = 0.0;
+               CoinWorkDouble b = 0.0;
+               CoinWorkDouble c = 0.0;
+               /* SQUARE of dual infeasibility will be:
+               square of dj - ......
+               */
+               CoinWorkDouble aq = 0.0;
+               CoinWorkDouble bq = 0.0;
+               CoinWorkDouble cq = 0.0;
+               CoinWorkDouble gamma2 = gamma_ * gamma_; // gamma*gamma will be added to diagonal
+               CoinWorkDouble * linearDjChange = new CoinWorkDouble[numberTotal];
+               CoinZeroN(linearDjChange, numberColumns_);
+               multiplyAdd(deltaY_, numberRows_, 1.0, linearDjChange + numberColumns_, 0.0);
+               matrix_->transposeTimes(-1.0, deltaY_, linearDjChange);
+               CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+               const int * columnQuadratic = quadratic->getIndices();
+               const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+               const int * columnQuadraticLength = quadratic->getVectorLengths();
+               CoinWorkDouble * quadraticElement = quadratic->getMutableElements();
+               for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+                    CoinWorkDouble oldPrimal = solution_[iColumn];
+                    if (!flagged(iColumn)) {
+                         if (lowerBound(iColumn)) {
+                              CoinWorkDouble change = oldPrimal + deltaX_[iColumn] - lowerSlack_[iColumn] - lower_[iColumn];
+                              c += lowerSlack_[iColumn] * zVec_[iColumn];
+                              b += lowerSlack_[iColumn] * deltaZ_[iColumn] + zVec_[iColumn] * change;
+                              a += deltaZ_[iColumn] * change;
+                         }
+                         if (upperBound(iColumn)) {
+                              CoinWorkDouble change = upper_[iColumn] - oldPrimal - deltaX_[iColumn] - upperSlack_[iColumn];
+                              c += upperSlack_[iColumn] * wVec_[iColumn];
+                              b += upperSlack_[iColumn] * deltaW_[iColumn] + wVec_[iColumn] * change;
+                              a += deltaW_[iColumn] * change;
+                         }
+                         // new djs are dj_ + change*value
+                         CoinWorkDouble djChange = linearDjChange[iColumn];
+                         if (iColumn < numberColumns_) {
+                              for (CoinBigIndex j = columnQuadraticStart[iColumn];
+                                        j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                   int jColumn = columnQuadratic[j];
+                                   CoinWorkDouble changeJ = deltaX_[jColumn];
+                                   CoinWorkDouble elementValue = quadraticElement[j];
+                                   djChange += changeJ * elementValue;
+                              }
+                         }
+                         CoinWorkDouble gammaTerm = gamma2;
+                         if (primalR_) {
+                              gammaTerm += primalR_[iColumn];
+                         }
+                         djChange += gammaTerm;
+                         // and dual infeasibility
+                         CoinWorkDouble oldInf = dj_[iColumn] - zVec_[iColumn] + wVec_[iColumn] +
+                                                 gammaTerm * solution_[iColumn];
+                         CoinWorkDouble changeInf = djChange - deltaZ_[iColumn] + deltaW_[iColumn];
+                         cq += oldInf * oldInf;
+                         bq += 2.0 * oldInf * changeInf;
+                         aq += changeInf * changeInf;
+                    } else {
+                         // fixed
+                         if (lowerBound(iColumn)) {
+                              c += lowerSlack_[iColumn] * zVec_[iColumn];
+                         }
+                         if (upperBound(iColumn)) {
+                              c += upperSlack_[iColumn] * wVec_[iColumn];
+                         }
+                         // new djs are dj_ + change*value
+                         CoinWorkDouble djChange = linearDjChange[iColumn];
+                         if (iColumn < numberColumns_) {
+                              for (CoinBigIndex j = columnQuadraticStart[iColumn];
+                                        j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                   int jColumn = columnQuadratic[j];
+                                   CoinWorkDouble changeJ = deltaX_[jColumn];
+                                   CoinWorkDouble elementValue = quadraticElement[j];
+                                   djChange += changeJ * elementValue;
+                              }
+                         }
+                         CoinWorkDouble gammaTerm = gamma2;
+                         if (primalR_) {
+                              gammaTerm += primalR_[iColumn];
+                         }
+                         djChange += gammaTerm;
+                         // and dual infeasibility
+                         CoinWorkDouble oldInf = dj_[iColumn] - zVec_[iColumn] + wVec_[iColumn] +
+                                                 gammaTerm * solution_[iColumn];
+                         CoinWorkDouble changeInf = djChange - deltaZ_[iColumn] + deltaW_[iColumn];
+                         cq += oldInf * oldInf;
+                         bq += 2.0 * oldInf * changeInf;
+                         aq += changeInf * changeInf;
+                    }
+               }
+               delete [] linearDjChange;
+               // ? We want to minimize complementarityGap + solutionNorm_*square of inf ??
+               // maybe use inf and do line search
+               // To check see if matches at current step
+               CoinWorkDouble step = actualPrimalStep_;
+               //Current gap + solutionNorm_ * CoinSqrt (sum square inf)
+               CoinWorkDouble multiplier = solutionNorm_;
+               multiplier *= 0.01;
+               multiplier = 1.0;
+               CoinWorkDouble currentInf =  multiplier * CoinSqrt(cq);
+               CoinWorkDouble nextInf = 	multiplier * CoinSqrt(CoinMax(cq + step * bq + step * step * aq, 0.0));
+               CoinWorkDouble allowedIncrease = 1.4;
+#ifdef SOME_DEBUG
+               printf("lin %g %g %g -> %g\n", a, b, c,
+                      c + b * step + a * step * step);
+               printf("quad %g %g %g -> %g\n", aq, bq, cq,
+                      cq + bq * step + aq * step * step);
+               debugMove(7, step, step);
+               printf ("current dualInf %g, with step of %g is %g\n",
+                       currentInf, step, nextInf);
+#endif
+               if (b > -1.0e-6) {
+                    if (phase != 0)
+                         directionNorm = -1.0;
+               }
+               if ((phase == 1 || phase == 2 || phase == 0 || phase == 3) && nextInf > 0.1 * complementarityGap_ &&
+                         nextInf > currentInf * allowedIncrease) {
+                    //cq = CoinMax(cq,10.0);
+                    // convert to (x+q)*(x+q) = w
+                    CoinWorkDouble q = bq / (1.0 * aq);
+                    CoinWorkDouble w = CoinMax(q * q + (cq / aq) * (allowedIncrease - 1.0), 0.0);
+                    w = CoinSqrt(w);
+                    CoinWorkDouble stepX = w - q;
+                    step = stepX;
+                    nextInf =
+                         multiplier * CoinSqrt(CoinMax(cq + step * bq + step * step * aq, 0.0));
+#ifdef SOME_DEBUG
+                    printf ("with step of %g dualInf is %g\n",
+                            step, nextInf);
+#endif
+                    actualDualStep_ = CoinMin(step, actualDualStep_);
+                    actualPrimalStep_ = CoinMin(step, actualPrimalStep_);
+               }
+          }
+     } else {
+          // probably pointless as linear
+          // minimize complementarity
+          // Complementarity gap will be a*change*change + b*change +c
+          CoinWorkDouble a = 0.0;
+          CoinWorkDouble b = 0.0;
+          CoinWorkDouble c = 0.0;
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               CoinWorkDouble oldPrimal = solution_[iColumn];
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         CoinWorkDouble change = oldPrimal + deltaX_[iColumn] - lowerSlack_[iColumn] - lower_[iColumn];
+                         c += lowerSlack_[iColumn] * zVec_[iColumn];
+                         b += lowerSlack_[iColumn] * deltaZ_[iColumn] + zVec_[iColumn] * change;
+                         a += deltaZ_[iColumn] * change;
+                    }
+                    if (upperBound(iColumn)) {
+                         CoinWorkDouble change = upper_[iColumn] - oldPrimal - deltaX_[iColumn] - upperSlack_[iColumn];
+                         c += upperSlack_[iColumn] * wVec_[iColumn];
+                         b += upperSlack_[iColumn] * deltaW_[iColumn] + wVec_[iColumn] * change;
+                         a += deltaW_[iColumn] * change;
+                    }
+               } else {
+                    // fixed
+                    if (lowerBound(iColumn)) {
+                         c += lowerSlack_[iColumn] * zVec_[iColumn];
+                    }
+                    if (upperBound(iColumn)) {
+                         c += upperSlack_[iColumn] * wVec_[iColumn];
+                    }
+               }
+          }
+          // ? We want to minimize complementarityGap;
+          // maybe use inf and do line search
+          // To check see if matches at current step
+          CoinWorkDouble step = CoinMin(actualPrimalStep_, actualDualStep_);
+          CoinWorkDouble next = c + b * step + a * step * step;
+#ifdef SOME_DEBUG
+          printf("lin %g %g %g -> %g\n", a, b, c,
+                 c + b * step + a * step * step);
+          debugMove(7, step, step);
+#endif
+          if (b > -1.0e-6) {
+               if (phase == 0) {
+#ifdef SOME_DEBUG
+                    printf("*** odd phase 0 direction\n");
+#endif
+               } else {
+                    directionNorm = -1.0;
+               }
+          }
+          // and with ratio
+          a = 0.0;
+          b = 0.0;
+          CoinWorkDouble ratio = actualDualStep_ / actualPrimalStep_;
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               CoinWorkDouble oldPrimal = solution_[iColumn];
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         CoinWorkDouble change = oldPrimal + deltaX_[iColumn] - lowerSlack_[iColumn] - lower_[iColumn];
+                         b += lowerSlack_[iColumn] * deltaZ_[iColumn] * ratio + zVec_[iColumn] * change;
+                         a += deltaZ_[iColumn] * change * ratio;
+                    }
+                    if (upperBound(iColumn)) {
+                         CoinWorkDouble change = upper_[iColumn] - oldPrimal - deltaX_[iColumn] - upperSlack_[iColumn];
+                         b += upperSlack_[iColumn] * deltaW_[iColumn] * ratio + wVec_[iColumn] * change;
+                         a += deltaW_[iColumn] * change * ratio;
+                    }
+               }
+          }
+          // ? We want to minimize complementarityGap;
+          // maybe use inf and do line search
+          // To check see if matches at current step
+          step = actualPrimalStep_;
+          CoinWorkDouble next2 = c + b * step + a * step * step;
+          if (next2 > next) {
+               actualPrimalStep_ = CoinMin(actualPrimalStep_, actualDualStep_);
+               actualDualStep_ = actualPrimalStep_;
+          }
+#ifdef SOME_DEBUG
+          printf("linb %g %g %g -> %g\n", a, b, c,
+                 c + b * step + a * step * step);
+          debugMove(7, actualPrimalStep_, actualDualStep_);
+#endif
+          if (b > -1.0e-6) {
+               if (phase == 0) {
+#ifdef SOME_DEBUG
+                    printf("*** odd phase 0 direction\n");
+#endif
+               } else {
+                    directionNorm = -1.0;
+               }
+          }
+     }
+#else
+     //actualPrimalStep_ =0.5*actualDualStep_;
+#endif
+#ifdef FULL_DEBUG
+     if (phase == 3) {
+          CoinWorkDouble minBeta = 0.1 * mu_;
+          CoinWorkDouble maxBeta = 10.0 * mu_;
+          for (iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++) {
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         CoinWorkDouble change = -rhsL_[iColumn] + deltaX_[iColumn];
+                         CoinWorkDouble dualValue = zVec_[iColumn] + actualDualStep_ * deltaZ_[iColumn];
+                         CoinWorkDouble primalValue = lowerSlack_[iColumn] + actualPrimalStep_ * change;
+                         CoinWorkDouble gapProduct = dualValue * primalValue;
+                         if (delta2Z_[iColumn] < minBeta || delta2Z_[iColumn] > maxBeta)
+                              printf("3lower %d primal %g, dual %g, gap %g, old gap %g\n",
+                                     iColumn, primalValue, dualValue, gapProduct, delta2Z_[iColumn]);
+                    }
+                    if (upperBound(iColumn)) {
+                         CoinWorkDouble change = rhsU_[iColumn] - deltaX_[iColumn];
+                         CoinWorkDouble dualValue = wVec_[iColumn] + actualDualStep_ * deltaW_[iColumn];
+                         CoinWorkDouble primalValue = upperSlack_[iColumn] + actualPrimalStep_ * change;
+                         CoinWorkDouble gapProduct = dualValue * primalValue;
+                         if (delta2W_[iColumn] < minBeta || delta2W_[iColumn] > maxBeta)
+                              printf("3upper %d primal %g, dual %g, gap %g, old gap %g\n",
+                                     iColumn, primalValue, dualValue, gapProduct, delta2W_[iColumn]);
+                    }
+               }
+          }
+     }
+#endif
+#ifdef SOME_DEBUG_not
+     {
+          CoinWorkDouble largestL = 0.0;
+          CoinWorkDouble smallestL = COIN_DBL_MAX;
+          CoinWorkDouble largestU = 0.0;
+          CoinWorkDouble smallestU = COIN_DBL_MAX;
+          CoinWorkDouble sumL = 0.0;
+          CoinWorkDouble sumU = 0.0;
+          int nL = 0;
+          int nU = 0;
+          for (iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++) {
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         CoinWorkDouble change = -rhsL_[iColumn] + deltaX_[iColumn];
+                         CoinWorkDouble dualValue = zVec_[iColumn] + actualDualStep_ * deltaZ_[iColumn];
+                         CoinWorkDouble primalValue = lowerSlack_[iColumn] + actualPrimalStep_ * change;
+                         CoinWorkDouble gapProduct = dualValue * primalValue;
+                         largestL = CoinMax(largestL, gapProduct);
+                         smallestL = CoinMin(smallestL, gapProduct);
+                         nL++;
+                         sumL += gapProduct;
+                    }
+                    if (upperBound(iColumn)) {
+                         CoinWorkDouble change = rhsU_[iColumn] - deltaX_[iColumn];
+                         CoinWorkDouble dualValue = wVec_[iColumn] + actualDualStep_ * deltaW_[iColumn];
+                         CoinWorkDouble primalValue = upperSlack_[iColumn] + actualPrimalStep_ * change;
+                         CoinWorkDouble gapProduct = dualValue * primalValue;
+                         largestU = CoinMax(largestU, gapProduct);
+                         smallestU = CoinMin(smallestU, gapProduct);
+                         nU++;
+                         sumU += gapProduct;
+                    }
+               }
+          }
+          CoinWorkDouble mu = (sumL + sumU) / (static_cast<CoinWorkDouble> (nL + nU));
+
+          CoinWorkDouble minBeta = 0.1 * mu;
+          CoinWorkDouble maxBeta = 10.0 * mu;
+          int nBL = 0;
+          int nAL = 0;
+          int nBU = 0;
+          int nAU = 0;
+          for (iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++) {
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         CoinWorkDouble change = -rhsL_[iColumn] + deltaX_[iColumn];
+                         CoinWorkDouble dualValue = zVec_[iColumn] + actualDualStep_ * deltaZ_[iColumn];
+                         CoinWorkDouble primalValue = lowerSlack_[iColumn] + actualPrimalStep_ * change;
+                         CoinWorkDouble gapProduct = dualValue * primalValue;
+                         if (gapProduct < minBeta)
+                              nBL++;
+                         else if (gapProduct > maxBeta)
+                              nAL++;
+                         //if (gapProduct<0.1*minBeta)
+                         //printf("Lsmall one %d dual %g primal %g\n",iColumn,
+                         //   dualValue,primalValue);
+                    }
+                    if (upperBound(iColumn)) {
+                         CoinWorkDouble change = rhsU_[iColumn] - deltaX_[iColumn];
+                         CoinWorkDouble dualValue = wVec_[iColumn] + actualDualStep_ * deltaW_[iColumn];
+                         CoinWorkDouble primalValue = upperSlack_[iColumn] + actualPrimalStep_ * change;
+                         CoinWorkDouble gapProduct = dualValue * primalValue;
+                         if (gapProduct < minBeta)
+                              nBU++;
+                         else if (gapProduct > maxBeta)
+                              nAU++;
+                         //if (gapProduct<0.1*minBeta)
+                         //printf("Usmall one %d dual %g primal %g\n",iColumn,
+                         //   dualValue,primalValue);
+                    }
+               }
+          }
+          printf("phase %d new mu %.18g new gap %.18g\n", phase, mu, sumL + sumU);
+          printf("          %d lower, smallest %.18g, %d below - largest %.18g, %d above\n",
+                 nL, smallestL, nBL, largestL, nAL);
+          printf("          %d upper, smallest %.18g, %d below - largest %.18g, %d above\n",
+                 nU, smallestU, nBU, largestU, nAU);
+     }
+#endif
+     return directionNorm;
+}
+/* Does solve. region1 is for deltaX (columns+rows), region2 for deltaPi (rows) */
+void
+ClpPredictorCorrector::solveSystem(CoinWorkDouble * region1, CoinWorkDouble * region2,
+                                   const CoinWorkDouble * region1In, const CoinWorkDouble * region2In,
+                                   const CoinWorkDouble * saveRegion1, const CoinWorkDouble * saveRegion2,
+                                   bool gentleRefine)
+{
+     int iRow;
+     int numberTotal = numberRows_ + numberColumns_;
+     if (region2In) {
+          // normal
+          for (iRow = 0; iRow < numberRows_; iRow++)
+               region2[iRow] = region2In[iRow];
+     } else {
+          // initial solution - (diagonal is 1 or 0)
+          CoinZeroN(region2, numberRows_);
+     }
+     int iColumn;
+     if (cholesky_->type() < 20) {
+          // not KKT
+          for (iColumn = 0; iColumn < numberTotal; iColumn++)
+               region1[iColumn] = region1In[iColumn] * diagonal_[iColumn];
+          multiplyAdd(region1 + numberColumns_, numberRows_, -1.0, region2, 1.0);
+          matrix_->times(1.0, region1, region2);
+          CoinWorkDouble maximumRHS = maximumAbsElement(region2, numberRows_);
+          CoinWorkDouble scale = 1.0;
+          CoinWorkDouble unscale = 1.0;
+          if (maximumRHS > 1.0e-30) {
+               if (maximumRHS <= 0.5) {
+                    CoinWorkDouble factor = 2.0;
+                    while (maximumRHS <= 0.5) {
+                         maximumRHS *= factor;
+                         scale *= factor;
+                    } /* endwhile */
+               } else if (maximumRHS >= 2.0 && maximumRHS <= COIN_DBL_MAX) {
+                    CoinWorkDouble factor = 0.5;
+                    while (maximumRHS >= 2.0) {
+                         maximumRHS *= factor;
+                         scale *= factor;
+                    } /* endwhile */
+               }
+               unscale = diagonalScaleFactor_ / scale;
+          } else {
+               //effectively zero
+               scale = 0.0;
+               unscale = 0.0;
+          }
+          multiplyAdd(NULL, numberRows_, 0.0, region2, scale);
+          cholesky_->solve(region2);
+          multiplyAdd(NULL, numberRows_, 0.0, region2, unscale);
+          multiplyAdd(region2, numberRows_, -1.0, region1 + numberColumns_, 0.0);
+          CoinZeroN(region1, numberColumns_);
+          matrix_->transposeTimes(1.0, region2, region1);
+          for (iColumn = 0; iColumn < numberTotal; iColumn++)
+               region1[iColumn] = (region1[iColumn] - region1In[iColumn]) * diagonal_[iColumn];
+     } else {
+          for (iColumn = 0; iColumn < numberTotal; iColumn++)
+               region1[iColumn] = region1In[iColumn];
+          cholesky_->solveKKT(region1, region2, diagonal_, diagonalScaleFactor_);
+     }
+     if (saveRegion2) {
+          //refine?
+          CoinWorkDouble scaleX = 1.0;
+          if (gentleRefine)
+               scaleX = 0.8;
+          multiplyAdd(saveRegion2, numberRows_, 1.0, region2, scaleX);
+          assert (saveRegion1);
+          multiplyAdd(saveRegion1, numberTotal, 1.0, region1, scaleX);
+     }
+}
+// findDirectionVector.
+CoinWorkDouble ClpPredictorCorrector::findDirectionVector(const int phase)
+{
+     CoinWorkDouble projectionTolerance = projectionTolerance_;
+     //temporary
+     //projectionTolerance=1.0e-15;
+     CoinWorkDouble errorCheck = 0.9 * maximumRHSError_ / solutionNorm_;
+     if (errorCheck > primalTolerance()) {
+          if (errorCheck < projectionTolerance) {
+               projectionTolerance = errorCheck;
+          }
+     } else {
+          if (primalTolerance() < projectionTolerance) {
+               projectionTolerance = primalTolerance();
+          }
+     }
+     CoinWorkDouble * newError = new CoinWorkDouble [numberRows_];
+     int numberTotal = numberRows_ + numberColumns_;
+     //if flagged then entries zero so can do
+     // For KKT separate out
+     CoinWorkDouble * region1Save = NULL; //for refinement
+     int iColumn;
+     if (cholesky_->type() < 20) {
+          int iColumn;
+          for (iColumn = 0; iColumn < numberTotal; iColumn++)
+               deltaX_[iColumn] = workArray_[iColumn] - solution_[iColumn];
+          multiplyAdd(deltaX_ + numberColumns_, numberRows_, -1.0, deltaY_, 0.0);
+          matrix_->times(1.0, deltaX_, deltaY_);
+     } else {
+          // regions in will be workArray and newError
+          // regions out deltaX_ and deltaY_
+          multiplyAdd(solution_ + numberColumns_, numberRows_, 1.0, newError, 0.0);
+          matrix_->times(-1.0, solution_, newError);
+          // This is inefficient but just for now get values which will be in deltay
+          int iColumn;
+          for (iColumn = 0; iColumn < numberTotal; iColumn++)
+               deltaX_[iColumn] = workArray_[iColumn] - solution_[iColumn];
+          multiplyAdd(deltaX_ + numberColumns_, numberRows_, -1.0, deltaY_, 0.0);
+          matrix_->times(1.0, deltaX_, deltaY_);
+     }
+     bool goodSolve = false;
+     CoinWorkDouble * regionSave = NULL; //for refinement
+     int numberTries = 0;
+     CoinWorkDouble relativeError = COIN_DBL_MAX;
+     CoinWorkDouble tryError = 1.0e31;
+     CoinWorkDouble saveMaximum = 0.0;
+     double firstError = 0.0;
+     double lastError2 = 0.0;
+     while (!goodSolve && numberTries < 30) {
+          CoinWorkDouble lastError = relativeError;
+          goodSolve = true;
+          CoinWorkDouble maximumRHS;
+          maximumRHS = CoinMax(maximumAbsElement(deltaY_, numberRows_), 1.0e-12);
+          if (!numberTries)
+               saveMaximum = maximumRHS;
+          if (cholesky_->type() < 20) {
+               // no kkt
+               CoinWorkDouble scale = 1.0;
+               CoinWorkDouble unscale = 1.0;
+               if (maximumRHS > 1.0e-30) {
+                    if (maximumRHS <= 0.5) {
+                         CoinWorkDouble factor = 2.0;
+                         while (maximumRHS <= 0.5) {
+                              maximumRHS *= factor;
+                              scale *= factor;
+                         } /* endwhile */
+                    } else if (maximumRHS >= 2.0 && maximumRHS <= COIN_DBL_MAX) {
+                         CoinWorkDouble factor = 0.5;
+                         while (maximumRHS >= 2.0) {
+                              maximumRHS *= factor;
+                              scale *= factor;
+                         } /* endwhile */
+                    }
+                    unscale = diagonalScaleFactor_ / scale;
+               } else {
+                    //effectively zero
+                    scale = 0.0;
+                    unscale = 0.0;
+               }
+               //printf("--putting scales to 1.0\n");
+               //scale=1.0;
+               //unscale=1.0;
+               multiplyAdd(NULL, numberRows_, 0.0, deltaY_, scale);
+               cholesky_->solve(deltaY_);
+               multiplyAdd(NULL, numberRows_, 0.0, deltaY_, unscale);
+#if 0
+               {
+                    printf("deltay\n");
+                    for (int i = 0; i < numberRows_; i++)
+                         printf("%d %.18g\n", i, deltaY_[i]);
+               }
+               exit(66);
+#endif
+               if (numberTries) {
+                    //refine?
+                    CoinWorkDouble scaleX = 1.0;
+                    if (lastError > 1.0e-5)
+                         scaleX = 0.8;
+                    multiplyAdd(regionSave, numberRows_, 1.0, deltaY_, scaleX);
+               }
+               //CoinZeroN(newError,numberRows_);
+               multiplyAdd(deltaY_, numberRows_, -1.0, deltaX_ + numberColumns_, 0.0);
+               CoinZeroN(deltaX_, numberColumns_);
+               matrix_->transposeTimes(1.0, deltaY_, deltaX_);
+               //if flagged then entries zero so can do
+               for (iColumn = 0; iColumn < numberTotal; iColumn++)
+                    deltaX_[iColumn] = deltaX_[iColumn] * diagonal_[iColumn]
+                                       - workArray_[iColumn];
+          } else {
+               // KKT
+               solveSystem(deltaX_, deltaY_,
+                           workArray_, newError, region1Save, regionSave, lastError > 1.0e-5);
+          }
+          multiplyAdd(deltaX_ + numberColumns_, numberRows_, -1.0, newError, 0.0);
+          matrix_->times(1.0, deltaX_, newError);
+          numberTries++;
+
+          //now add in old Ax - doing extra checking
+          CoinWorkDouble maximumRHSError = 0.0;
+          CoinWorkDouble maximumRHSChange = 0.0;
+          int iRow;
+          char * dropped = cholesky_->rowsDropped();
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if (!dropped[iRow]) {
+                    CoinWorkDouble newValue = newError[iRow];
+                    CoinWorkDouble oldValue = errorRegion_[iRow];
+                    //severity of errors depend on signs
+                    //**later                                                             */
+                    if (CoinAbs(newValue) > maximumRHSChange) {
+                         maximumRHSChange = CoinAbs(newValue);
+                    }
+                    CoinWorkDouble result = newValue + oldValue;
+                    if (CoinAbs(result) > maximumRHSError) {
+                         maximumRHSError = CoinAbs(result);
+                    }
+                    newError[iRow] = result;
+               } else {
+                    CoinWorkDouble newValue = newError[iRow];
+                    CoinWorkDouble oldValue = errorRegion_[iRow];
+                    if (CoinAbs(newValue) > maximumRHSChange) {
+                         maximumRHSChange = CoinAbs(newValue);
+                    }
+                    CoinWorkDouble result = newValue + oldValue;
+                    newError[iRow] = result;
+                    //newError[iRow]=0.0;
+                    //assert(deltaY_[iRow]==0.0);
+                    deltaY_[iRow] = 0.0;
+               }
+          }
+          relativeError = maximumRHSError / solutionNorm_;
+          relativeError = maximumRHSError / saveMaximum;
+          if (relativeError > tryError)
+               relativeError = tryError;
+          if (numberTries == 1)
+               firstError = relativeError;
+          if (relativeError < lastError) {
+               lastError2 = relativeError;
+               maximumRHSChange_ = maximumRHSChange;
+               if (relativeError > projectionTolerance && numberTries <= 3) {
+                    //try and refine
+                    goodSolve = false;
+               }
+               //*** extra test here
+               if (!goodSolve) {
+                    if (!regionSave) {
+                         regionSave = new CoinWorkDouble [numberRows_];
+                         if (cholesky_->type() >= 20)
+                              region1Save = new CoinWorkDouble [numberTotal];
+                    }
+                    CoinMemcpyN(deltaY_, numberRows_, regionSave);
+                    if (cholesky_->type() < 20) {
+                         // not KKT
+                         multiplyAdd(newError, numberRows_, -1.0, deltaY_, 0.0);
+                    } else {
+                         // KKT
+                         CoinMemcpyN(deltaX_, numberTotal, region1Save);
+                         // and back to input region
+                         CoinMemcpyN(deltaY_, numberRows_, newError);
+                    }
+               }
+          } else {
+               //std::cout <<" worse residual = "<<relativeError;
+               //bring back previous
+               relativeError = lastError;
+               if (regionSave) {
+                    CoinMemcpyN(regionSave, numberRows_, deltaY_);
+                    if (cholesky_->type() < 20) {
+                         // not KKT
+                         multiplyAdd(deltaY_, numberRows_, -1.0, deltaX_ + numberColumns_, 0.0);
+                         CoinZeroN(deltaX_, numberColumns_);
+                         matrix_->transposeTimes(1.0, deltaY_, deltaX_);
+                         //if flagged then entries zero so can do
+                         for (iColumn = 0; iColumn < numberTotal; iColumn++)
+                              deltaX_[iColumn] = deltaX_[iColumn] * diagonal_[iColumn]
+                                                 - workArray_[iColumn];
+                    } else {
+                         // KKT
+                         CoinMemcpyN(region1Save, numberTotal, deltaX_);
+                    }
+               } else {
+                    // disaster
+                    CoinFillN(deltaX_, numberTotal, static_cast<CoinWorkDouble>(1.0));
+                    CoinFillN(deltaY_, numberRows_, static_cast<CoinWorkDouble>(1.0));
+                    COIN_DETAIL_PRINT(printf("bad cholesky\n"));
+               }
+          }
+     } /* endwhile */
+     if (firstError > 1.0e-8 || numberTries > 1) {
+          handler_->message(CLP_BARRIER_ACCURACY, messages_)
+                    << phase << numberTries << static_cast<double>(firstError)
+                    << static_cast<double>(lastError2)
+                    << CoinMessageEol;
+     }
+     delete [] regionSave;
+     delete [] region1Save;
+     delete [] newError;
+     // now rest
+     CoinWorkDouble extra = eExtra;
+     //multiplyAdd(deltaY_,numberRows_,1.0,deltaW_+numberColumns_,0.0);
+     //CoinZeroN(deltaW_,numberColumns_);
+     //matrix_->transposeTimes(-1.0,deltaY_,deltaW_);
+
+     for (iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++) {
+          deltaSU_[iColumn] = 0.0;
+          deltaSL_[iColumn] = 0.0;
+          deltaZ_[iColumn] = 0.0;
+          CoinWorkDouble dd = deltaW_[iColumn];
+          deltaW_[iColumn] = 0.0;
+          if (!flagged(iColumn)) {
+               CoinWorkDouble deltaX = deltaX_[iColumn];
+               if (lowerBound(iColumn)) {
+                    CoinWorkDouble zValue = rhsZ_[iColumn];
+                    CoinWorkDouble gHat = zValue + zVec_[iColumn] * rhsL_[iColumn];
+                    CoinWorkDouble slack = lowerSlack_[iColumn] + extra;
+                    deltaSL_[iColumn] = -rhsL_[iColumn] + deltaX;
+                    deltaZ_[iColumn] = (gHat - zVec_[iColumn] * deltaX) / slack;
+               }
+               if (upperBound(iColumn)) {
+                    CoinWorkDouble wValue = rhsW_[iColumn];
+                    CoinWorkDouble hHat = wValue - wVec_[iColumn] * rhsU_[iColumn];
+                    CoinWorkDouble slack = upperSlack_[iColumn] + extra;
+                    deltaSU_[iColumn] = rhsU_[iColumn] - deltaX;
+                    deltaW_[iColumn] = (hHat + wVec_[iColumn] * deltaX) / slack;
+               }
+               if (0) {
+                    // different way of calculating
+                    CoinWorkDouble gamma2 = gamma_ * gamma_;
+                    CoinWorkDouble dZ = 0.0;
+                    CoinWorkDouble dW = 0.0;
+                    CoinWorkDouble zValue = rhsZ_[iColumn];
+                    CoinWorkDouble gHat = zValue + zVec_[iColumn] * rhsL_[iColumn];
+                    CoinWorkDouble slackL = lowerSlack_[iColumn] + extra;
+                    CoinWorkDouble wValue = rhsW_[iColumn];
+                    CoinWorkDouble hHat = wValue - wVec_[iColumn] * rhsU_[iColumn];
+                    CoinWorkDouble slackU = upperSlack_[iColumn] + extra;
+                    CoinWorkDouble q = rhsC_[iColumn] + gamma2 * deltaX + dd;
+                    if (primalR_)
+                         q += deltaX * primalR_[iColumn];
+                    dW = (gHat + hHat - slackL * q + (wValue - zValue) * deltaX) / (slackL + slackU);
+                    dZ = dW + q;
+                    //printf("B %d old %g %g new %g %g\n",iColumn,deltaZ_[iColumn],
+                    //deltaW_[iColumn],dZ,dW);
+                    if (lowerBound(iColumn)) {
+                         if (upperBound(iColumn)) {
+                              //printf("B %d old %g %g new %g %g\n",iColumn,deltaZ_[iColumn],
+                              //deltaW_[iColumn],dZ,dW);
+                              deltaW_[iColumn] = dW;
+                              deltaZ_[iColumn] = dZ;
+                         } else {
+                              // just lower
+                              //printf("L %d old %g new %g\n",iColumn,deltaZ_[iColumn],
+                              //dZ);
+                         }
+                    } else {
+                         assert (upperBound(iColumn));
+                         //printf("U %d old %g new %g\n",iColumn,deltaW_[iColumn],
+                         //dW);
+                    }
+               }
+          }
+     }
+#if 0
+     CoinWorkDouble * check = new CoinWorkDouble[numberTotal];
+     // Check out rhsC_
+     multiplyAdd(deltaY_, numberRows_, -1.0, check + numberColumns_, 0.0);
+     CoinZeroN(check, numberColumns_);
+     matrix_->transposeTimes(1.0, deltaY_, check);
+     quadraticDjs(check, deltaX_, -1.0);
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          check[iColumn] += deltaZ_[iColumn] - deltaW_[iColumn];
+          if (CoinAbs(check[iColumn] - rhsC_[iColumn]) > 1.0e-3)
+               printf("rhsC %d %g %g\n", iColumn, check[iColumn], rhsC_[iColumn]);
+     }
+     // Check out rhsZ_
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          check[iColumn] += lowerSlack_[iColumn] * deltaZ_[iColumn] +
+                            zVec_[iColumn] * deltaSL_[iColumn];
+          if (CoinAbs(check[iColumn] - rhsZ_[iColumn]) > 1.0e-3)
+               printf("rhsZ %d %g %g\n", iColumn, check[iColumn], rhsZ_[iColumn]);
+     }
+     // Check out rhsW_
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          check[iColumn] += upperSlack_[iColumn] * deltaW_[iColumn] +
+                            wVec_[iColumn] * deltaSU_[iColumn];
+          if (CoinAbs(check[iColumn] - rhsW_[iColumn]) > 1.0e-3)
+               printf("rhsW %d %g %g\n", iColumn, check[iColumn], rhsW_[iColumn]);
+     }
+     delete [] check;
+#endif
+     return relativeError;
+}
+// createSolution.  Creates solution from scratch
+int ClpPredictorCorrector::createSolution()
+{
+     int numberTotal = numberRows_ + numberColumns_;
+     int iColumn;
+     CoinWorkDouble tolerance = primalTolerance();
+     // See if quadratic objective
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+     if (!quadraticObj) {
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               if (upper_[iColumn] - lower_[iColumn] > tolerance)
+                    clearFixed(iColumn);
+               else
+                    setFixed(iColumn);
+          }
+     } else {
+          // try leaving fixed
+          for (iColumn = 0; iColumn < numberTotal; iColumn++)
+               clearFixed(iColumn);
+     }
+
+     CoinWorkDouble maximumObjective = 0.0;
+     CoinWorkDouble objectiveNorm2 = 0.0;
+     getNorms(cost_, numberTotal, maximumObjective, objectiveNorm2);
+     if (!maximumObjective) {
+          maximumObjective = 1.0; // objective all zero
+     }
+     objectiveNorm2 = CoinSqrt(objectiveNorm2) / static_cast<CoinWorkDouble> (numberTotal);
+     objectiveNorm_ = maximumObjective;
+     scaleFactor_ = 1.0;
+     if (maximumObjective > 0.0) {
+          if (maximumObjective < 1.0) {
+               scaleFactor_ = maximumObjective;
+          } else if (maximumObjective > 1.0e4) {
+               scaleFactor_ = maximumObjective / 1.0e4;
+          }
+     }
+     if (scaleFactor_ != 1.0) {
+          objectiveNorm2 *= scaleFactor_;
+          multiplyAdd(NULL, numberTotal, 0.0, cost_, 1.0 / scaleFactor_);
+          objectiveNorm_ = maximumObjective / scaleFactor_;
+     }
+     // See if quadratic objective
+     if (quadraticObj) {
+          // If scaled then really scale matrix
+          CoinWorkDouble scaleFactor =
+               scaleFactor_ * optimizationDirection_ * objectiveScale_ *
+               rhsScale_;
+          if ((scalingFlag_ > 0 && rowScale_) || scaleFactor != 1.0) {
+               CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+               const int * columnQuadratic = quadratic->getIndices();
+               const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+               const int * columnQuadraticLength = quadratic->getVectorLengths();
+               double * quadraticElement = quadratic->getMutableElements();
+               int numberColumns = quadratic->getNumCols();
+               CoinWorkDouble scale = 1.0 / scaleFactor;
+               if (scalingFlag_ > 0 && rowScale_) {
+                    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         CoinWorkDouble scaleI = columnScale_[iColumn] * scale;
+                         for (CoinBigIndex j = columnQuadraticStart[iColumn];
+                                   j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                              int jColumn = columnQuadratic[j];
+                              CoinWorkDouble scaleJ = columnScale_[jColumn];
+                              quadraticElement[j] *= scaleI * scaleJ;
+                              objectiveNorm_ = CoinMax(objectiveNorm_, CoinAbs(quadraticElement[j]));
+                         }
+                    }
+               } else {
+                    // not scaled
+                    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         for (CoinBigIndex j = columnQuadraticStart[iColumn];
+                                   j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                              quadraticElement[j] *= scale;
+                              objectiveNorm_ = CoinMax(objectiveNorm_, CoinAbs(quadraticElement[j]));
+                         }
+                    }
+               }
+          }
+     }
+     baseObjectiveNorm_ = objectiveNorm_;
+     //accumulate fixed in dj region (as spare)
+     //accumulate primal solution in primal region
+     //DZ in lowerDual
+     //DW in upperDual
+     CoinWorkDouble infiniteCheck = 1.0e40;
+     //CoinWorkDouble     fakeCheck=1.0e10;
+     //use deltaX region for work region
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          CoinWorkDouble primalValue = solution_[iColumn];
+          clearFlagged(iColumn);
+          clearFixedOrFree(iColumn);
+          clearLowerBound(iColumn);
+          clearUpperBound(iColumn);
+          clearFakeLower(iColumn);
+          clearFakeUpper(iColumn);
+          if (!fixed(iColumn)) {
+               dj_[iColumn] = 0.0;
+               diagonal_[iColumn] = 1.0;
+               deltaX_[iColumn] = 1.0;
+               CoinWorkDouble lowerValue = lower_[iColumn];
+               CoinWorkDouble upperValue = upper_[iColumn];
+               if (lowerValue > -infiniteCheck) {
+                    if (upperValue < infiniteCheck) {
+                         //upper and lower bounds
+                         setLowerBound(iColumn);
+                         setUpperBound(iColumn);
+                         if (lowerValue >= 0.0) {
+                              solution_[iColumn] = lowerValue;
+                         } else if (upperValue <= 0.0) {
+                              solution_[iColumn] = upperValue;
+                         } else {
+                              solution_[iColumn] = 0.0;
+                         }
+                    } else {
+                         //just lower bound
+                         setLowerBound(iColumn);
+                         if (lowerValue >= 0.0) {
+                              solution_[iColumn] = lowerValue;
+                         } else {
+                              solution_[iColumn] = 0.0;
+                         }
+                    }
+               } else {
+                    if (upperValue < infiniteCheck) {
+                         //just upper bound
+                         setUpperBound(iColumn);
+                         if (upperValue <= 0.0) {
+                              solution_[iColumn] = upperValue;
+                         } else {
+                              solution_[iColumn] = 0.0;
+                         }
+                    } else {
+                         //free
+                         setFixedOrFree(iColumn);
+                         solution_[iColumn] = 0.0;
+                         //std::cout<<" free "<<i<<std::endl;
+                    }
+               }
+          } else {
+               setFlagged(iColumn);
+               setFixedOrFree(iColumn);
+               setLowerBound(iColumn);
+               setUpperBound(iColumn);
+               dj_[iColumn] = primalValue;;
+               solution_[iColumn] = lower_[iColumn];
+               diagonal_[iColumn] = 0.0;
+               deltaX_[iColumn] = 0.0;
+          }
+     }
+     //   modify fixed RHS
+     multiplyAdd(dj_ + numberColumns_, numberRows_, -1.0, rhsFixRegion_, 0.0);
+     //   create plausible RHS?
+     matrix_->times(-1.0, dj_, rhsFixRegion_);
+     multiplyAdd(solution_ + numberColumns_, numberRows_, 1.0, errorRegion_, 0.0);
+     matrix_->times(-1.0, solution_, errorRegion_);
+     rhsNorm_ = maximumAbsElement(errorRegion_, numberRows_);
+     if (rhsNorm_ < 1.0) {
+          rhsNorm_ = 1.0;
+     }
+     int * rowsDropped = new int [numberRows_];
+     int returnCode = cholesky_->factorize(diagonal_, rowsDropped);
+     if (returnCode == -1) {
+       COIN_DETAIL_PRINT(printf("Out of memory\n"));
+          problemStatus_ = 4;
+          return -1;
+     }
+     if (cholesky_->status()) {
+          std::cout << "singular on initial cholesky?" << std::endl;
+          cholesky_->resetRowsDropped();
+          //cholesky_->factorize(rowDropped_);
+          //if (cholesky_->status()) {
+          //std::cout << "bad cholesky??? (after retry)" <<std::endl;
+          //abort();
+          //}
+     }
+     delete [] rowsDropped;
+     if (cholesky_->type() < 20) {
+          // not KKT
+          cholesky_->solve(errorRegion_);
+          //create information for solution
+          multiplyAdd(errorRegion_, numberRows_, -1.0, deltaX_ + numberColumns_, 0.0);
+          CoinZeroN(deltaX_, numberColumns_);
+          matrix_->transposeTimes(1.0, errorRegion_, deltaX_);
+     } else {
+          // KKT
+          // reverse sign on solution
+          multiplyAdd(NULL, numberRows_ + numberColumns_, 0.0, solution_, -1.0);
+          solveSystem(deltaX_, errorRegion_, solution_, NULL, NULL, NULL, false);
+     }
+     CoinWorkDouble initialValue = 1.0e2;
+     if (rhsNorm_ * 1.0e-2 > initialValue) {
+          initialValue = rhsNorm_ * 1.0e-2;
+     }
+     //initialValue = CoinMax(1.0,rhsNorm_);
+     CoinWorkDouble smallestBoundDifference = COIN_DBL_MAX;
+     CoinWorkDouble * fakeSolution = deltaX_;
+     for ( iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!flagged(iColumn)) {
+               if (lower_[iColumn] - fakeSolution[iColumn] > initialValue) {
+                    initialValue = lower_[iColumn] - fakeSolution[iColumn];
+               }
+               if (fakeSolution[iColumn] - upper_[iColumn] > initialValue) {
+                    initialValue = fakeSolution[iColumn] - upper_[iColumn];
+               }
+               if (upper_[iColumn] - lower_[iColumn] < smallestBoundDifference) {
+                    smallestBoundDifference = upper_[iColumn] - lower_[iColumn];
+               }
+          }
+     }
+     solutionNorm_ = 1.0e-12;
+     handler_->message(CLP_BARRIER_SAFE, messages_)
+               << static_cast<double>(initialValue) << static_cast<double>(objectiveNorm_)
+               << CoinMessageEol;
+     CoinWorkDouble extra = 1.0e-10;
+     CoinWorkDouble largeGap = 1.0e15;
+     //CoinWorkDouble safeObjectiveValue=2.0*objectiveNorm_;
+     CoinWorkDouble safeObjectiveValue = objectiveNorm_ + 1.0;
+     CoinWorkDouble safeFree = 1.0e-1 * initialValue;
+     //printf("normal safe dual value of %g, primal value of %g\n",
+     // safeObjectiveValue,initialValue);
+     //safeObjectiveValue=CoinMax(2.0,1.0e-1*safeObjectiveValue);
+     //initialValue=CoinMax(100.0,1.0e-1*initialValue);;
+     //printf("temp safe dual value of %g, primal value of %g\n",
+     // safeObjectiveValue,initialValue);
+     CoinWorkDouble zwLarge = 1.0e2 * initialValue;
+     //zwLarge=1.0e40;
+     if (cholesky_->choleskyCondition() < 0.0 && cholesky_->type() < 20) {
+          // looks bad - play safe
+          initialValue *= 10.0;
+          safeObjectiveValue *= 10.0;
+          safeFree *= 10.0;
+     }
+     CoinWorkDouble gamma2 = gamma_ * gamma_; // gamma*gamma will be added to diagonal
+     // First do primal side
+     for ( iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!flagged(iColumn)) {
+               CoinWorkDouble lowerValue = lower_[iColumn];
+               CoinWorkDouble upperValue = upper_[iColumn];
+               CoinWorkDouble newValue;
+               CoinWorkDouble setPrimal = initialValue;
+               if (quadraticObj) {
+                    // perturb primal solution a bit
+                    //fakeSolution[iColumn]  *= 0.002*CoinDrand48()+0.999;
+               }
+               if (lowerBound(iColumn)) {
+                    if (upperBound(iColumn)) {
+                         //upper and lower bounds
+                         if (upperValue - lowerValue > 2.0 * setPrimal) {
+                              CoinWorkDouble fakeValue = fakeSolution[iColumn];
+                              if (fakeValue < lowerValue + setPrimal) {
+                                   fakeValue = lowerValue + setPrimal;
+                              }
+                              if (fakeValue > upperValue - setPrimal) {
+                                   fakeValue = upperValue - setPrimal;
+                              }
+                              newValue = fakeValue;
+                         } else {
+                              newValue = 0.5 * (upperValue + lowerValue);
+                         }
+                    } else {
+                         //just lower bound
+                         CoinWorkDouble fakeValue = fakeSolution[iColumn];
+                         if (fakeValue < lowerValue + setPrimal) {
+                              fakeValue = lowerValue + setPrimal;
+                         }
+                         newValue = fakeValue;
+                    }
+               } else {
+                    if (upperBound(iColumn)) {
+                         //just upper bound
+                         CoinWorkDouble fakeValue = fakeSolution[iColumn];
+                         if (fakeValue > upperValue - setPrimal) {
+                              fakeValue = upperValue - setPrimal;
+                         }
+                         newValue = fakeValue;
+                    } else {
+                         //free
+                         newValue = fakeSolution[iColumn];
+                         if (newValue >= 0.0) {
+                              if (newValue < safeFree) {
+                                   newValue = safeFree;
+                              }
+                         } else {
+                              if (newValue > -safeFree) {
+                                   newValue = -safeFree;
+                              }
+                         }
+                    }
+               }
+               solution_[iColumn] = newValue;
+          } else {
+               // fixed
+               lowerSlack_[iColumn] = 0.0;
+               upperSlack_[iColumn] = 0.0;
+               solution_[iColumn] = lower_[iColumn];
+               zVec_[iColumn] = 0.0;
+               wVec_[iColumn] = 0.0;
+               diagonal_[iColumn] = 0.0;
+          }
+     }
+     solutionNorm_ =  maximumAbsElement(solution_, numberTotal);
+     // Set bounds and do dj including quadratic
+     largeGap = CoinMax(1.0e7, 1.02 * solutionNorm_);
+     CoinPackedMatrix * quadratic = NULL;
+     const int * columnQuadratic = NULL;
+     const CoinBigIndex * columnQuadraticStart = NULL;
+     const int * columnQuadraticLength = NULL;
+     const double * quadraticElement = NULL;
+     if (quadraticObj) {
+          quadratic = quadraticObj->quadraticObjective();
+          columnQuadratic = quadratic->getIndices();
+          columnQuadraticStart = quadratic->getVectorStarts();
+          columnQuadraticLength = quadratic->getVectorLengths();
+          quadraticElement = quadratic->getElements();
+     }
+     CoinWorkDouble quadraticNorm = 0.0;
+     for ( iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!flagged(iColumn)) {
+               CoinWorkDouble primalValue = solution_[iColumn];
+               CoinWorkDouble lowerValue = lower_[iColumn];
+               CoinWorkDouble upperValue = upper_[iColumn];
+               // Do dj
+               CoinWorkDouble reducedCost = cost_[iColumn];
+               if (lowerBound(iColumn)) {
+                    reducedCost += linearPerturbation_;
+               }
+               if (upperBound(iColumn)) {
+                    reducedCost -= linearPerturbation_;
+               }
+               if (quadraticObj && iColumn < numberColumns_) {
+                    for (CoinBigIndex j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         CoinWorkDouble valueJ = solution_[jColumn];
+                         CoinWorkDouble elementValue = quadraticElement[j];
+                         reducedCost += valueJ * elementValue;
+                    }
+                    quadraticNorm = CoinMax(quadraticNorm, CoinAbs(reducedCost));
+               }
+               dj_[iColumn] = reducedCost;
+               if (primalValue > lowerValue + largeGap && primalValue < upperValue - largeGap) {
+                    clearFixedOrFree(iColumn);
+                    setLowerBound(iColumn);
+                    setUpperBound(iColumn);
+                    lowerValue = CoinMax(lowerValue, primalValue - largeGap);
+                    upperValue = CoinMin(upperValue, primalValue + largeGap);
+                    lower_[iColumn] = lowerValue;
+                    upper_[iColumn] = upperValue;
+               }
+          }
+     }
+     safeObjectiveValue = CoinMax(safeObjectiveValue, quadraticNorm);
+     for ( iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!flagged(iColumn)) {
+               CoinWorkDouble primalValue = solution_[iColumn];
+               CoinWorkDouble lowerValue = lower_[iColumn];
+               CoinWorkDouble upperValue = upper_[iColumn];
+               CoinWorkDouble reducedCost = dj_[iColumn];
+               CoinWorkDouble low = 0.0;
+               CoinWorkDouble high = 0.0;
+               if (lowerBound(iColumn)) {
+                    if (upperBound(iColumn)) {
+                         //upper and lower bounds
+                         if (upperValue - lowerValue > 2.0 * initialValue) {
+                              low = primalValue - lowerValue;
+                              high = upperValue - primalValue;
+                         } else {
+                              low = initialValue;
+                              high = initialValue;
+                         }
+                         CoinWorkDouble s = low + extra;
+                         CoinWorkDouble ratioZ;
+                         if (s < zwLarge) {
+                              ratioZ = 1.0;
+                         } else {
+                              ratioZ = CoinSqrt(zwLarge / s);
+                         }
+                         CoinWorkDouble t = high + extra;
+                         CoinWorkDouble ratioT;
+                         if (t < zwLarge) {
+                              ratioT = 1.0;
+                         } else {
+                              ratioT = CoinSqrt(zwLarge / t);
+                         }
+                         //modify s and t
+                         if (s > largeGap) {
+                              s = largeGap;
+                         }
+                         if (t > largeGap) {
+                              t = largeGap;
+                         }
+                         //modify if long long way away from bound
+                         if (reducedCost >= 0.0) {
+                              zVec_[iColumn] = reducedCost + safeObjectiveValue * ratioZ;
+                              zVec_[iColumn] = CoinMax(reducedCost, safeObjectiveValue * ratioZ);
+                              wVec_[iColumn] = safeObjectiveValue * ratioT;
+                         } else {
+                              zVec_[iColumn] = safeObjectiveValue * ratioZ;
+                              wVec_[iColumn] = -reducedCost + safeObjectiveValue * ratioT;
+                              wVec_[iColumn] = CoinMax(-reducedCost , safeObjectiveValue * ratioT);
+                         }
+                         CoinWorkDouble gammaTerm = gamma2;
+                         if (primalR_)
+                              gammaTerm += primalR_[iColumn];
+                         diagonal_[iColumn] = (t * s) /
+                                              (s * wVec_[iColumn] + t * zVec_[iColumn] + gammaTerm * t * s);
+                    } else {
+                         //just lower bound
+                         low = primalValue - lowerValue;
+                         high = 0.0;
+                         CoinWorkDouble s = low + extra;
+                         CoinWorkDouble ratioZ;
+                         if (s < zwLarge) {
+                              ratioZ = 1.0;
+                         } else {
+                              ratioZ = CoinSqrt(zwLarge / s);
+                         }
+                         //modify s
+                         if (s > largeGap) {
+                              s = largeGap;
+                         }
+                         if (reducedCost >= 0.0) {
+                              zVec_[iColumn] = reducedCost + safeObjectiveValue * ratioZ;
+                              zVec_[iColumn] = CoinMax(reducedCost , safeObjectiveValue * ratioZ);
+                              wVec_[iColumn] = 0.0;
+                         } else {
+                              zVec_[iColumn] = safeObjectiveValue * ratioZ;
+                              wVec_[iColumn] = 0.0;
+                         }
+                         CoinWorkDouble gammaTerm = gamma2;
+                         if (primalR_)
+                              gammaTerm += primalR_[iColumn];
+                         diagonal_[iColumn] = s / (zVec_[iColumn] + s * gammaTerm);
+                    }
+               } else {
+                    if (upperBound(iColumn)) {
+                         //just upper bound
+                         low = 0.0;
+                         high = upperValue - primalValue;
+                         CoinWorkDouble t = high + extra;
+                         CoinWorkDouble ratioT;
+                         if (t < zwLarge) {
+                              ratioT = 1.0;
+                         } else {
+                              ratioT = CoinSqrt(zwLarge / t);
+                         }
+                         //modify t
+                         if (t > largeGap) {
+                              t = largeGap;
+                         }
+                         if (reducedCost >= 0.0) {
+                              zVec_[iColumn] = 0.0;
+                              wVec_[iColumn] = safeObjectiveValue * ratioT;
+                         } else {
+                              zVec_[iColumn] = 0.0;
+                              wVec_[iColumn] = -reducedCost + safeObjectiveValue * ratioT;
+                              wVec_[iColumn] = CoinMax(-reducedCost , safeObjectiveValue * ratioT);
+                         }
+                         CoinWorkDouble gammaTerm = gamma2;
+                         if (primalR_)
+                              gammaTerm += primalR_[iColumn];
+                         diagonal_[iColumn] =  t / (wVec_[iColumn] + t * gammaTerm);
+                    }
+               }
+               lowerSlack_[iColumn] = low;
+               upperSlack_[iColumn] = high;
+          }
+     }
+#if 0
+     if (solution_[0] > 0.0) {
+          for (int i = 0; i < numberTotal; i++)
+               printf("%d %.18g %.18g %.18g %.18g %.18g %.18g %.18g\n", i, CoinAbs(solution_[i]),
+                      diagonal_[i], CoinAbs(dj_[i]),
+                      lowerSlack_[i], zVec_[i],
+                      upperSlack_[i], wVec_[i]);
+     } else {
+          for (int i = 0; i < numberTotal; i++)
+               printf("%d %.18g %.18g %.18g %.18g %.18g %.18g %.18g\n", i, CoinAbs(solution_[i]),
+                      diagonal_[i], CoinAbs(dj_[i]),
+                      upperSlack_[i], wVec_[i],
+                      lowerSlack_[i], zVec_[i] );
+     }
+     exit(66);
+#endif
+     return 0;
+}
+// complementarityGap.  Computes gap
+//phase 0=as is , 1 = after predictor , 2 after corrector
+CoinWorkDouble ClpPredictorCorrector::complementarityGap(int & numberComplementarityPairs,
+          int & numberComplementarityItems,
+          const int phase)
+{
+     CoinWorkDouble gap = 0.0;
+     //seems to be same coding for phase = 1 or 2
+     numberComplementarityPairs = 0;
+     numberComplementarityItems = 0;
+     int numberTotal = numberRows_ + numberColumns_;
+     CoinWorkDouble toleranceGap = 0.0;
+     CoinWorkDouble largestGap = 0.0;
+     CoinWorkDouble smallestGap = COIN_DBL_MAX;
+     //seems to be same coding for phase = 1 or 2
+     int numberNegativeGaps = 0;
+     CoinWorkDouble sumNegativeGap = 0.0;
+     CoinWorkDouble largeGap = 1.0e2 * solutionNorm_;
+     if (largeGap < 1.0e10) {
+          largeGap = 1.0e10;
+     }
+     largeGap = 1.0e30;
+     CoinWorkDouble dualTolerance =  dblParam_[ClpDualTolerance];
+     CoinWorkDouble primalTolerance =  dblParam_[ClpPrimalTolerance];
+     dualTolerance = dualTolerance / scaleFactor_;
+     for (int iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!fixedOrFree(iColumn)) {
+               numberComplementarityPairs++;
+               //can collapse as if no lower bound both zVec and deltaZ 0.0
+               if (lowerBound(iColumn)) {
+                    numberComplementarityItems++;
+                    CoinWorkDouble dualValue;
+                    CoinWorkDouble primalValue;
+                    if (!phase) {
+                         dualValue = zVec_[iColumn];
+                         primalValue = lowerSlack_[iColumn];
+                    } else {
+                         CoinWorkDouble change;
+                         change = solution_[iColumn] + deltaX_[iColumn] - lowerSlack_[iColumn] - lower_[iColumn];
+                         dualValue = zVec_[iColumn] + actualDualStep_ * deltaZ_[iColumn];
+                         primalValue = lowerSlack_[iColumn] + actualPrimalStep_ * change;
+                    }
+                    //reduce primalValue
+                    if (primalValue > largeGap) {
+                         primalValue = largeGap;
+                    }
+                    CoinWorkDouble gapProduct = dualValue * primalValue;
+                    if (gapProduct < 0.0) {
+                         //cout<<"negative gap component "<<iColumn<<" "<<dualValue<<" "<<
+                         //primalValue<<endl;
+                         numberNegativeGaps++;
+                         sumNegativeGap -= gapProduct;
+                         gapProduct = 0.0;
+                    }
+                    gap += gapProduct;
+                    //printf("l %d prim %g dual %g totalGap %g\n",
+                    //   iColumn,primalValue,dualValue,gap);
+                    if (gapProduct > largestGap) {
+                         largestGap = gapProduct;
+                    }
+                    smallestGap = CoinMin(smallestGap, gapProduct);
+                    if (dualValue > dualTolerance && primalValue > primalTolerance) {
+                         toleranceGap += dualValue * primalValue;
+                    }
+               }
+               if (upperBound(iColumn)) {
+                    numberComplementarityItems++;
+                    CoinWorkDouble dualValue;
+                    CoinWorkDouble primalValue;
+                    if (!phase) {
+                         dualValue = wVec_[iColumn];
+                         primalValue = upperSlack_[iColumn];
+                    } else {
+                         CoinWorkDouble change;
+                         change = upper_[iColumn] - solution_[iColumn] - deltaX_[iColumn] - upperSlack_[iColumn];
+                         dualValue = wVec_[iColumn] + actualDualStep_ * deltaW_[iColumn];
+                         primalValue = upperSlack_[iColumn] + actualPrimalStep_ * change;
+                    }
+                    //reduce primalValue
+                    if (primalValue > largeGap) {
+                         primalValue = largeGap;
+                    }
+                    CoinWorkDouble gapProduct = dualValue * primalValue;
+                    if (gapProduct < 0.0) {
+                         //cout<<"negative gap component "<<iColumn<<" "<<dualValue<<" "<<
+                         //primalValue<<endl;
+                         numberNegativeGaps++;
+                         sumNegativeGap -= gapProduct;
+                         gapProduct = 0.0;
+                    }
+                    gap += gapProduct;
+                    //printf("u %d prim %g dual %g totalGap %g\n",
+                    //   iColumn,primalValue,dualValue,gap);
+                    if (gapProduct > largestGap) {
+                         largestGap = gapProduct;
+                    }
+                    if (dualValue > dualTolerance && primalValue > primalTolerance) {
+                         toleranceGap += dualValue * primalValue;
+                    }
+               }
+          }
+     }
+     //if (numberIterations_>4)
+     //exit(9);
+     if (!phase && numberNegativeGaps) {
+          handler_->message(CLP_BARRIER_NEGATIVE_GAPS, messages_)
+                    << numberNegativeGaps << static_cast<double>(sumNegativeGap)
+                    << CoinMessageEol;
+     }
+
+     //in case all free!
+     if (!numberComplementarityPairs) {
+          numberComplementarityPairs = 1;
+     }
+#ifdef SOME_DEBUG
+     printf("with d,p steps %g,%g gap %g - smallest %g, largest %g, pairs %d\n",
+            actualDualStep_, actualPrimalStep_,
+            gap, smallestGap, largestGap, numberComplementarityPairs);
+#endif
+     return gap;
+}
+// setupForSolve.
+//phase 0=affine , 1 = corrector , 2 = primal-dual
+void ClpPredictorCorrector::setupForSolve(const int phase)
+{
+     CoinWorkDouble extra = eExtra;
+     int numberTotal = numberRows_ + numberColumns_;
+     int iColumn;
+#ifdef SOME_DEBUG
+     printf("phase %d in setupForSolve, mu %.18g\n", phase, mu_);
+#endif
+     CoinWorkDouble gamma2 = gamma_ * gamma_; // gamma*gamma will be added to diagonal
+     CoinWorkDouble * dualArray = reinterpret_cast<CoinWorkDouble *>(dual_);
+     switch (phase) {
+     case 0:
+          CoinMemcpyN(errorRegion_, numberRows_, rhsB_);
+          if (delta_ || dualR_) {
+               // add in regularization
+               CoinWorkDouble delta2 = delta_ * delta_;
+               for (int iRow = 0; iRow < numberRows_; iRow++) {
+                    rhsB_[iRow] -= delta2 * dualArray[iRow];
+                    if (dualR_)
+                         rhsB_[iRow] -= dualR_[iRow] * dualArray[iRow];
+               }
+          }
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               rhsC_[iColumn] = 0.0;
+               rhsU_[iColumn] = 0.0;
+               rhsL_[iColumn] = 0.0;
+               rhsZ_[iColumn] = 0.0;
+               rhsW_[iColumn] = 0.0;
+               if (!flagged(iColumn)) {
+                    rhsC_[iColumn] = dj_[iColumn] - zVec_[iColumn] + wVec_[iColumn];
+                    rhsC_[iColumn] += gamma2 * solution_[iColumn];
+                    if (primalR_)
+                         rhsC_[iColumn] += primalR_[iColumn] * solution_[iColumn];
+                    if (lowerBound(iColumn)) {
+                         rhsZ_[iColumn] = -zVec_[iColumn] * (lowerSlack_[iColumn] + extra);
+                         rhsL_[iColumn] = CoinMax(0.0, (lower_[iColumn] + lowerSlack_[iColumn]) - solution_[iColumn]);
+                    }
+                    if (upperBound(iColumn)) {
+                         rhsW_[iColumn] = -wVec_[iColumn] * (upperSlack_[iColumn] + extra);
+                         rhsU_[iColumn] = CoinMin(0.0, (upper_[iColumn] - upperSlack_[iColumn]) - solution_[iColumn]);
+                    }
+               }
+          }
+#if 0
+          for (int i = 0; i < 3; i++) {
+               if (!CoinAbs(rhsZ_[i]))
+                    rhsZ_[i] = 0.0;
+               if (!CoinAbs(rhsW_[i]))
+                    rhsW_[i] = 0.0;
+               if (!CoinAbs(rhsU_[i]))
+                    rhsU_[i] = 0.0;
+               if (!CoinAbs(rhsL_[i]))
+                    rhsL_[i] = 0.0;
+          }
+          if (solution_[0] > 0.0) {
+               for (int i = 0; i < 3; i++)
+                    printf("%d %.18g %.18g %.18g %.18g %.18g %.18g %.18g\n", i, solution_[i],
+                           diagonal_[i], dj_[i],
+                           lowerSlack_[i], zVec_[i],
+                           upperSlack_[i], wVec_[i]);
+               for (int i = 0; i < 3; i++)
+                    printf("%d %.18g %.18g %.18g %.18g %.18g\n", i, rhsC_[i],
+                           rhsZ_[i], rhsL_[i],
+                           rhsW_[i], rhsU_[i]);
+          } else {
+               for (int i = 0; i < 3; i++)
+                    printf("%d %.18g %.18g %.18g %.18g %.18g %.18g %.18g\n", i, solution_[i],
+                           diagonal_[i], dj_[i],
+                           lowerSlack_[i], zVec_[i],
+                           upperSlack_[i], wVec_[i]);
+               for (int i = 0; i < 3; i++)
+                    printf("%d %.18g %.18g %.18g %.18g %.18g\n", i, rhsC_[i],
+                           rhsZ_[i], rhsL_[i],
+                           rhsW_[i], rhsU_[i]);
+          }
+#endif
+          break;
+     case 1:
+          // could be stored in delta2?
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               rhsZ_[iColumn] = 0.0;
+               rhsW_[iColumn] = 0.0;
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         rhsZ_[iColumn] = mu_ - zVec_[iColumn] * (lowerSlack_[iColumn] + extra)
+                                          - deltaZ_[iColumn] * deltaX_[iColumn];
+                         // To bring in line with OSL
+                         rhsZ_[iColumn] += deltaZ_[iColumn] * rhsL_[iColumn];
+                    }
+                    if (upperBound(iColumn)) {
+                         rhsW_[iColumn] = mu_ - wVec_[iColumn] * (upperSlack_[iColumn] + extra)
+                                          + deltaW_[iColumn] * deltaX_[iColumn];
+                         // To bring in line with OSL
+                         rhsW_[iColumn] -= deltaW_[iColumn] * rhsU_[iColumn];
+                    }
+               }
+          }
+#if 0
+          for (int i = 0; i < numberTotal; i++) {
+               if (!CoinAbs(rhsZ_[i]))
+                    rhsZ_[i] = 0.0;
+               if (!CoinAbs(rhsW_[i]))
+                    rhsW_[i] = 0.0;
+               if (!CoinAbs(rhsU_[i]))
+                    rhsU_[i] = 0.0;
+               if (!CoinAbs(rhsL_[i]))
+                    rhsL_[i] = 0.0;
+          }
+          if (solution_[0] > 0.0) {
+               for (int i = 0; i < numberTotal; i++)
+                    printf("%d %.18g %.18g %.18g %.18g %.18g %.18g %.18g\n", i, CoinAbs(solution_[i]),
+                           diagonal_[i], CoinAbs(dj_[i]),
+                           lowerSlack_[i], zVec_[i],
+                           upperSlack_[i], wVec_[i]);
+               for (int i = 0; i < numberTotal; i++)
+                    printf("%d %.18g %.18g %.18g %.18g %.18g\n", i, CoinAbs(rhsC_[i]),
+                           rhsZ_[i], rhsL_[i],
+                           rhsW_[i], rhsU_[i]);
+          } else {
+               for (int i = 0; i < numberTotal; i++)
+                    printf("%d %.18g %.18g %.18g %.18g %.18g %.18g %.18g\n", i, CoinAbs(solution_[i]),
+                           diagonal_[i], CoinAbs(dj_[i]),
+                           upperSlack_[i], wVec_[i],
+                           lowerSlack_[i], zVec_[i] );
+               for (int i = 0; i < numberTotal; i++)
+                    printf("%d %.18g %.18g %.18g %.18g %.18g\n", i, CoinAbs(rhsC_[i]),
+                           rhsW_[i], rhsU_[i],
+                           rhsZ_[i], rhsL_[i]);
+          }
+          exit(66);
+#endif
+          break;
+     case 2:
+          CoinMemcpyN(errorRegion_, numberRows_, rhsB_);
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               rhsZ_[iColumn] = 0.0;
+               rhsW_[iColumn] = 0.0;
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         rhsZ_[iColumn] = mu_ - zVec_[iColumn] * (lowerSlack_[iColumn] + extra);
+                    }
+                    if (upperBound(iColumn)) {
+                         rhsW_[iColumn] = mu_ - wVec_[iColumn] * (upperSlack_[iColumn] + extra);
+                    }
+               }
+          }
+          break;
+     case 3: {
+          CoinWorkDouble minBeta = 0.1 * mu_;
+          CoinWorkDouble maxBeta = 10.0 * mu_;
+          CoinWorkDouble dualStep = CoinMin(1.0, actualDualStep_ + 0.1);
+          CoinWorkDouble primalStep = CoinMin(1.0, actualPrimalStep_ + 0.1);
+#ifdef SOME_DEBUG
+          printf("good complementarity range %g to %g\n", minBeta, maxBeta);
+#endif
+          //minBeta=0.0;
+          //maxBeta=COIN_DBL_MAX;
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         CoinWorkDouble change = -rhsL_[iColumn] + deltaX_[iColumn];
+                         CoinWorkDouble dualValue = zVec_[iColumn] + dualStep * deltaZ_[iColumn];
+                         CoinWorkDouble primalValue = lowerSlack_[iColumn] + primalStep * change;
+                         CoinWorkDouble gapProduct = dualValue * primalValue;
+                         if (gapProduct > 0.0 && dualValue < 0.0)
+                              gapProduct = - gapProduct;
+#ifdef FULL_DEBUG
+                         delta2Z_[iColumn] = gapProduct;
+                         if (delta2Z_[iColumn] < minBeta || delta2Z_[iColumn] > maxBeta)
+                              printf("lower %d primal %g, dual %g, gap %g\n",
+                                     iColumn, primalValue, dualValue, gapProduct);
+#endif
+                         CoinWorkDouble value = 0.0;
+                         if (gapProduct < minBeta) {
+                              value = 2.0 * (minBeta - gapProduct);
+                              value = (mu_ - gapProduct);
+                              value = (minBeta - gapProduct);
+                              assert (value > 0.0);
+                         } else if (gapProduct > maxBeta) {
+                              value = CoinMax(maxBeta - gapProduct, -maxBeta);
+                              assert (value < 0.0);
+                         }
+                         rhsZ_[iColumn] += value;
+                    }
+                    if (upperBound(iColumn)) {
+                         CoinWorkDouble change = rhsU_[iColumn] - deltaX_[iColumn];
+                         CoinWorkDouble dualValue = wVec_[iColumn] + dualStep * deltaW_[iColumn];
+                         CoinWorkDouble primalValue = upperSlack_[iColumn] + primalStep * change;
+                         CoinWorkDouble gapProduct = dualValue * primalValue;
+                         if (gapProduct > 0.0 && dualValue < 0.0)
+                              gapProduct = - gapProduct;
+#ifdef FULL_DEBUG
+                         delta2W_[iColumn] = gapProduct;
+                         if (delta2W_[iColumn] < minBeta || delta2W_[iColumn] > maxBeta)
+                              printf("upper %d primal %g, dual %g, gap %g\n",
+                                     iColumn, primalValue, dualValue, gapProduct);
+#endif
+                         CoinWorkDouble value = 0.0;
+                         if (gapProduct < minBeta) {
+                              value = (minBeta - gapProduct);
+                              assert (value > 0.0);
+                         } else if (gapProduct > maxBeta) {
+                              value = CoinMax(maxBeta - gapProduct, -maxBeta);
+                              assert (value < 0.0);
+                         }
+                         rhsW_[iColumn] += value;
+                    }
+               }
+          }
+     }
+     break;
+     } /* endswitch */
+     if (cholesky_->type() < 20) {
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               CoinWorkDouble value = rhsC_[iColumn];
+               CoinWorkDouble zValue = rhsZ_[iColumn];
+               CoinWorkDouble wValue = rhsW_[iColumn];
+#if 0
+#if 1
+               if (phase == 0) {
+                    // more accurate
+                    value = dj[iColumn];
+                    zValue = 0.0;
+                    wValue = 0.0;
+               } else if (phase == 2) {
+                    // more accurate
+                    value = dj[iColumn];
+                    zValue = mu_;
+                    wValue = mu_;
+               }
+#endif
+               assert (rhsL_[iColumn] >= 0.0);
+               assert (rhsU_[iColumn] <= 0.0);
+               if (lowerBound(iColumn)) {
+                    value += (-zVec_[iColumn] * rhsL_[iColumn] - zValue) /
+                             (lowerSlack_[iColumn] + extra);
+               }
+               if (upperBound(iColumn)) {
+                    value += (wValue - wVec_[iColumn] * rhsU_[iColumn]) /
+                             (upperSlack_[iColumn] + extra);
+               }
+#else
+               if (lowerBound(iColumn)) {
+                    CoinWorkDouble gHat = zValue + zVec_[iColumn] * rhsL_[iColumn];
+                    value -= gHat / (lowerSlack_[iColumn] + extra);
+               }
+               if (upperBound(iColumn)) {
+                    CoinWorkDouble hHat = wValue - wVec_[iColumn] * rhsU_[iColumn];
+                    value += hHat / (upperSlack_[iColumn] + extra);
+               }
+#endif
+               workArray_[iColumn] = diagonal_[iColumn] * value;
+          }
+#if 0
+          if (solution_[0] > 0.0) {
+               for (int i = 0; i < numberTotal; i++)
+                    printf("%d %.18g\n", i, workArray_[i]);
+          } else {
+               for (int i = 0; i < numberTotal; i++)
+                    printf("%d %.18g\n", i, workArray_[i]);
+          }
+          exit(66);
+#endif
+     } else {
+          // KKT
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               CoinWorkDouble value = rhsC_[iColumn];
+               CoinWorkDouble zValue = rhsZ_[iColumn];
+               CoinWorkDouble wValue = rhsW_[iColumn];
+               if (lowerBound(iColumn)) {
+                    CoinWorkDouble gHat = zValue + zVec_[iColumn] * rhsL_[iColumn];
+                    value -= gHat / (lowerSlack_[iColumn] + extra);
+               }
+               if (upperBound(iColumn)) {
+                    CoinWorkDouble hHat = wValue - wVec_[iColumn] * rhsU_[iColumn];
+                    value += hHat / (upperSlack_[iColumn] + extra);
+               }
+               workArray_[iColumn] = value;
+          }
+     }
+}
+//method: sees if looks plausible change in complementarity
+bool ClpPredictorCorrector::checkGoodMove(const bool doCorrector,
+          CoinWorkDouble & bestNextGap,
+          bool allowIncreasingGap)
+{
+     const CoinWorkDouble beta3 = 0.99997;
+     bool goodMove = false;
+     int nextNumber;
+     int nextNumberItems;
+     int numberTotal = numberRows_ + numberColumns_;
+     CoinWorkDouble returnGap = bestNextGap;
+     CoinWorkDouble nextGap = complementarityGap(nextNumber, nextNumberItems, 2);
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+     if (nextGap > bestNextGap && nextGap > 0.9 * complementarityGap_ && doCorrector
+               && !quadraticObj && !allowIncreasingGap) {
+#ifdef SOME_DEBUG
+          printf("checkGood phase 1 next gap %.18g, phase 0 %.18g, old gap %.18g\n",
+                 nextGap, bestNextGap, complementarityGap_);
+#endif
+          return false;
+     } else {
+          returnGap = nextGap;
+     }
+     CoinWorkDouble step;
+     if (actualDualStep_ > actualPrimalStep_) {
+          step = actualDualStep_;
+     } else {
+          step = actualPrimalStep_;
+     }
+     CoinWorkDouble testValue = 1.0 - step * (1.0 - beta3);
+     //testValue=0.0;
+     testValue *= complementarityGap_;
+     if (nextGap < testValue) {
+          //std::cout <<"predicted duality gap "<<nextGap<<std::endl;
+          goodMove = true;
+     } else if(doCorrector) {
+          //if (actualDualStep_<actualPrimalStep_) {
+          //step=actualDualStep_;
+          //} else {
+          //step=actualPrimalStep_;
+          //}
+          CoinWorkDouble gap = bestNextGap;
+          goodMove = checkGoodMove2(step, gap, allowIncreasingGap);
+          if (goodMove)
+               returnGap = gap;
+     } else {
+          goodMove = true;
+     }
+     if (goodMove)
+          goodMove = checkGoodMove2(step, bestNextGap, allowIncreasingGap);
+     // Say good if small
+     //if (quadraticObj) {
+     if (CoinMax(actualDualStep_, actualPrimalStep_) < 1.0e-6)
+          goodMove = true;
+     if (!goodMove) {
+          //try smaller of two
+          if (actualDualStep_ < actualPrimalStep_) {
+               step = actualDualStep_;
+          } else {
+               step = actualPrimalStep_;
+          }
+          if (step > 1.0) {
+               step = 1.0;
+          }
+          actualPrimalStep_ = step;
+          //if (quadraticObj)
+          //actualPrimalStep_ *=0.5;
+          actualDualStep_ = step;
+          goodMove = checkGoodMove2(step, bestNextGap, allowIncreasingGap);
+          int pass = 0;
+          while (!goodMove) {
+               pass++;
+               CoinWorkDouble gap = bestNextGap;
+               goodMove = checkGoodMove2(step, gap, allowIncreasingGap);
+               if (goodMove || pass > 3) {
+                    returnGap = gap;
+                    break;
+               }
+               if (step < 1.0e-4) {
+                    break;
+               }
+               step *= 0.5;
+               actualPrimalStep_ = step;
+               //if (quadraticObj)
+               //actualPrimalStep_ *=0.5;
+               actualDualStep_ = step;
+          } /* endwhile */
+          if (doCorrector) {
+               //say bad move if both small
+               if (numberIterations_ & 1) {
+                    if (actualPrimalStep_ < 1.0e-2 && actualDualStep_ < 1.0e-2) {
+                         goodMove = false;
+                    }
+               } else {
+                    if (actualPrimalStep_ < 1.0e-5 && actualDualStep_ < 1.0e-5) {
+                         goodMove = false;
+                    }
+                    if (actualPrimalStep_ * actualDualStep_ < 1.0e-20) {
+                         goodMove = false;
+                    }
+               }
+          }
+     }
+     if (goodMove) {
+          //compute delta in objectives
+          CoinWorkDouble deltaObjectivePrimal = 0.0;
+          CoinWorkDouble deltaObjectiveDual =
+               innerProduct(deltaY_, numberRows_,
+                            rhsFixRegion_);
+          CoinWorkDouble error = 0.0;
+          CoinWorkDouble * workArray = workArray_;
+          CoinZeroN(workArray, numberColumns_);
+          CoinMemcpyN(deltaY_, numberRows_, workArray + numberColumns_);
+          matrix_->transposeTimes(-1.0, deltaY_, workArray);
+          //CoinWorkDouble sumPerturbCost=0.0;
+          for (int iColumn = 0; iColumn < numberTotal; iColumn++) {
+               if (!flagged(iColumn)) {
+                    if (lowerBound(iColumn)) {
+                         //sumPerturbCost+=deltaX_[iColumn];
+                         deltaObjectiveDual += deltaZ_[iColumn] * lower_[iColumn];
+                    }
+                    if (upperBound(iColumn)) {
+                         //sumPerturbCost-=deltaX_[iColumn];
+                         deltaObjectiveDual -= deltaW_[iColumn] * upper_[iColumn];
+                    }
+                    CoinWorkDouble change = CoinAbs(workArray_[iColumn] - deltaZ_[iColumn] + deltaW_[iColumn]);
+                    error = CoinMax(change, error);
+               }
+               deltaObjectivePrimal += cost_[iColumn] * deltaX_[iColumn];
+          }
+          //deltaObjectivePrimal+=sumPerturbCost*linearPerturbation_;
+          CoinWorkDouble testValue;
+          if (error > 0.0) {
+               testValue = 1.0e1 * CoinMax(maximumDualError_, 1.0e-12) / error;
+          } else {
+               testValue = 1.0e1;
+          }
+          // If quadratic then primal step may compensate
+          if (testValue < actualDualStep_ && !quadraticObj) {
+               handler_->message(CLP_BARRIER_REDUCING, messages_)
+                         << "dual" << static_cast<double>(actualDualStep_)
+                         << static_cast<double>(testValue)
+                         << CoinMessageEol;
+               actualDualStep_ = testValue;
+          }
+     }
+     if (maximumRHSError_ < 1.0e1 * solutionNorm_ * primalTolerance()
+               && maximumRHSChange_ > 1.0e-16 * solutionNorm_) {
+          //check change in AX not too much
+          //??? could be dropped row going infeasible
+          CoinWorkDouble ratio = 1.0e1 * CoinMax(maximumRHSError_, 1.0e-12) / maximumRHSChange_;
+          if (ratio < actualPrimalStep_) {
+               handler_->message(CLP_BARRIER_REDUCING, messages_)
+                         << "primal" << static_cast<double>(actualPrimalStep_)
+                         << static_cast<double>(ratio)
+                         << CoinMessageEol;
+               if (ratio > 1.0e-6) {
+                    actualPrimalStep_ = ratio;
+               } else {
+                    actualPrimalStep_ = ratio;
+                    //std::cout <<"sign we should be stopping"<<std::endl;
+               }
+          }
+     }
+     if (goodMove)
+          bestNextGap = returnGap;
+     return goodMove;
+}
+//:  checks for one step size
+bool ClpPredictorCorrector::checkGoodMove2(CoinWorkDouble move,
+          CoinWorkDouble & bestNextGap,
+          bool allowIncreasingGap)
+{
+     CoinWorkDouble complementarityMultiplier = 1.0 / numberComplementarityPairs_;
+     const CoinWorkDouble gamma = 1.0e-8;
+     const CoinWorkDouble gammap = 1.0e-8;
+     CoinWorkDouble gammad = 1.0e-8;
+     int nextNumber;
+     int nextNumberItems;
+     CoinWorkDouble nextGap = complementarityGap(nextNumber, nextNumberItems, 2);
+     if (nextGap > bestNextGap && !allowIncreasingGap)
+          return false;
+     CoinWorkDouble lowerBoundGap = gamma * nextGap * complementarityMultiplier;
+     bool goodMove = true;
+     int iColumn;
+     for ( iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++) {
+          if (!flagged(iColumn)) {
+               if (lowerBound(iColumn)) {
+                    CoinWorkDouble part1 = lowerSlack_[iColumn] + actualPrimalStep_ * deltaSL_[iColumn];
+                    CoinWorkDouble part2 = zVec_[iColumn] + actualDualStep_ * deltaZ_[iColumn];
+                    if (part1 * part2 < lowerBoundGap) {
+                         goodMove = false;
+                         break;
+                    }
+               }
+               if (upperBound(iColumn)) {
+                    CoinWorkDouble part1 = upperSlack_[iColumn] + actualPrimalStep_ * deltaSU_[iColumn];
+                    CoinWorkDouble part2 = wVec_[iColumn] + actualDualStep_ * deltaW_[iColumn];
+                    if (part1 * part2 < lowerBoundGap) {
+                         goodMove = false;
+                         break;
+                    }
+               }
+          }
+     }
+     CoinWorkDouble * nextDj = NULL;
+     CoinWorkDouble maximumDualError = maximumDualError_;
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+     CoinWorkDouble * dualArray = reinterpret_cast<CoinWorkDouble *>(dual_);
+     if (quadraticObj) {
+          // change gammad
+          gammad = 1.0e-4;
+          CoinWorkDouble gamma2 = gamma_ * gamma_;
+          nextDj = new CoinWorkDouble [numberColumns_];
+          CoinWorkDouble * nextSolution = new CoinWorkDouble [numberColumns_];
+          // put next primal into nextSolution
+          for ( iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (!flagged(iColumn)) {
+                    nextSolution[iColumn] = solution_[iColumn] +
+                                            actualPrimalStep_ * deltaX_[iColumn];
+               } else {
+                    nextSolution[iColumn] = solution_[iColumn];
+               }
+          }
+          // do reduced costs
+          CoinMemcpyN(cost_, numberColumns_, nextDj);
+          matrix_->transposeTimes(-1.0, dualArray, nextDj);
+          matrix_->transposeTimes(-actualDualStep_, deltaY_, nextDj);
+          quadraticDjs(nextDj, nextSolution, 1.0);
+          delete [] nextSolution;
+          CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+          const int * columnQuadraticLength = quadratic->getVectorLengths();
+          for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (!fixedOrFree(iColumn)) {
+                    CoinWorkDouble newZ = 0.0;
+                    CoinWorkDouble newW = 0.0;
+                    if (lowerBound(iColumn)) {
+                         newZ = zVec_[iColumn] + actualDualStep_ * deltaZ_[iColumn];
+                    }
+                    if (upperBound(iColumn)) {
+                         newW = wVec_[iColumn] + actualDualStep_ * deltaW_[iColumn];
+                    }
+                    if (columnQuadraticLength[iColumn]) {
+                         CoinWorkDouble gammaTerm = gamma2;
+                         if (primalR_)
+                              gammaTerm += primalR_[iColumn];
+                         //CoinWorkDouble dualInfeasibility=
+                         //dj_[iColumn]-zVec_[iColumn]+wVec_[iColumn]
+                         //+gammaTerm*solution_[iColumn];
+                         CoinWorkDouble newInfeasibility =
+                              nextDj[iColumn] - newZ + newW
+                              + gammaTerm * (solution_[iColumn] + actualPrimalStep_ * deltaX_[iColumn]);
+                         maximumDualError = CoinMax(maximumDualError, newInfeasibility);
+                         //if (CoinAbs(newInfeasibility)>CoinMax(2000.0*maximumDualError_,1.0e-2)) {
+                         //if (dualInfeasibility*newInfeasibility<0.0) {
+                         //  printf("%d current %g next %g\n",iColumn,dualInfeasibility,
+                         //       newInfeasibility);
+                         //  goodMove=false;
+                         //}
+                         //}
+                    }
+               }
+          }
+          delete [] nextDj;
+     }
+//      Satisfy g_p(alpha)?
+     if (rhsNorm_ > solutionNorm_) {
+          solutionNorm_ = rhsNorm_;
+     }
+     CoinWorkDouble errorCheck = maximumRHSError_ / solutionNorm_;
+     if (errorCheck < maximumBoundInfeasibility_) {
+          errorCheck = maximumBoundInfeasibility_;
+     }
+     // scale back move
+     move = CoinMin(move, 0.95);
+     //scale
+     if ((1.0 - move)*errorCheck > primalTolerance()) {
+          if (nextGap < gammap*(1.0 - move)*errorCheck) {
+               goodMove = false;
+          }
+     }
+     //      Satisfy g_d(alpha)?
+     errorCheck = maximumDualError / objectiveNorm_;
+     if ((1.0 - move)*errorCheck > dualTolerance()) {
+          if (nextGap < gammad*(1.0 - move)*errorCheck) {
+               goodMove = false;
+          }
+     }
+     if (goodMove)
+          bestNextGap = nextGap;
+     return goodMove;
+}
+// updateSolution.  Updates solution at end of iteration
+//returns number fixed
+int ClpPredictorCorrector::updateSolution(CoinWorkDouble /*nextGap*/)
+{
+     CoinWorkDouble * dualArray = reinterpret_cast<CoinWorkDouble *>(dual_);
+     int numberTotal = numberRows_ + numberColumns_;
+     //update pi
+     multiplyAdd(deltaY_, numberRows_, actualDualStep_, dualArray, 1.0);
+     CoinZeroN(errorRegion_, numberRows_);
+     CoinZeroN(rhsFixRegion_, numberRows_);
+     CoinWorkDouble maximumRhsInfeasibility = 0.0;
+     CoinWorkDouble maximumBoundInfeasibility = 0.0;
+     CoinWorkDouble maximumDualError = 1.0e-12;
+     CoinWorkDouble primalObjectiveValue = 0.0;
+     CoinWorkDouble dualObjectiveValue = 0.0;
+     CoinWorkDouble solutionNorm = 1.0e-12;
+     int numberKilled = 0;
+     CoinWorkDouble freeMultiplier = 1.0e6;
+     CoinWorkDouble trueNorm = diagonalNorm_ / diagonalScaleFactor_;
+     if (freeMultiplier < trueNorm) {
+          freeMultiplier = trueNorm;
+     }
+     if (freeMultiplier > 1.0e12) {
+          freeMultiplier = 1.0e12;
+     }
+     freeMultiplier = 0.5 / freeMultiplier;
+     CoinWorkDouble condition = CoinAbs(cholesky_->choleskyCondition());
+     bool caution;
+     if ((condition < 1.0e10 && trueNorm < 1.0e12) || numberIterations_ < 20) {
+          caution = false;
+     } else {
+          caution = true;
+     }
+     CoinWorkDouble extra = eExtra;
+     const CoinWorkDouble largeFactor = 1.0e2;
+     CoinWorkDouble largeGap = largeFactor * solutionNorm_;
+     if (largeGap < largeFactor) {
+          largeGap = largeFactor;
+     }
+     CoinWorkDouble dualFake = 0.0;
+     CoinWorkDouble dualTolerance =  dblParam_[ClpDualTolerance];
+     dualTolerance = dualTolerance / scaleFactor_;
+     if (dualTolerance < 1.0e-12) {
+          dualTolerance = 1.0e-12;
+     }
+     CoinWorkDouble offsetObjective = 0.0;
+     CoinWorkDouble killTolerance = primalTolerance();
+     //CoinWorkDouble nextMu = nextGap/(static_cast<CoinWorkDouble>(2*numberComplementarityPairs_));
+     //printf("using gap of %g\n",nextMu);
+     //largest allowable ratio of lowerSlack/zVec (etc)
+     CoinWorkDouble epsilonBase;
+     CoinWorkDouble diagonalLimit;
+     if (!caution) {
+          epsilonBase = eBase;
+          diagonalLimit = eDiagonal;
+     } else {
+          epsilonBase = eBaseCaution;
+          diagonalLimit = eDiagonalCaution;
+     }
+     CoinWorkDouble maximumDJInfeasibility = 0.0;
+     int numberIncreased = 0;
+     int numberDecreased = 0;
+     CoinWorkDouble largestDiagonal = 0.0;
+     CoinWorkDouble smallestDiagonal = 1.0e50;
+     CoinWorkDouble largeGap2 = CoinMax(1.0e7, 1.0e2 * solutionNorm_);
+     //largeGap2 = 1.0e9;
+     // When to start looking at killing (factor0
+     CoinWorkDouble killFactor;
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+#ifndef CLP_CAUTION
+#define KILL_ITERATION 50
+#else
+#if CLP_CAUTION < 1
+#define KILL_ITERATION 50
+#else
+#define KILL_ITERATION 100
+#endif
+#endif
+     if (!quadraticObj || 1) {
+          if (numberIterations_ < KILL_ITERATION) {
+               killFactor = 1.0;
+          } else if (numberIterations_ < 2 * KILL_ITERATION) {
+               killFactor = 5.0;
+               stepLength_ = CoinMax(stepLength_, 0.9995);
+          } else if (numberIterations_ < 4 * KILL_ITERATION) {
+               killFactor = 20.0;
+               stepLength_ = CoinMax(stepLength_, 0.99995);
+          } else {
+               killFactor = 1.0e2;
+               stepLength_ = CoinMax(stepLength_, 0.999995);
+          }
+     } else {
+          killFactor = 1.0;
+     }
+     // put next primal into deltaSL_
+     int iColumn;
+     int iRow;
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          CoinWorkDouble thisWeight = deltaX_[iColumn];
+          CoinWorkDouble newPrimal = solution_[iColumn] + 1.0 * actualPrimalStep_ * thisWeight;
+          deltaSL_[iColumn] = newPrimal;
+     }
+#if 0
+     // nice idea but doesn't work
+     multiplyAdd(solution_ + numberColumns_, numberRows_, -1.0, errorRegion_, 0.0);
+     matrix_->times(1.0, solution_, errorRegion_);
+     multiplyAdd(deltaSL_ + numberColumns_, numberRows_, -1.0, rhsFixRegion_, 0.0);
+     matrix_->times(1.0, deltaSL_, rhsFixRegion_);
+     CoinWorkDouble newNorm =  maximumAbsElement(deltaSL_, numberTotal);
+     CoinWorkDouble tol = newNorm * primalTolerance();
+     bool goneInf = false;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          CoinWorkDouble value = errorRegion_[iRow];
+          CoinWorkDouble valueNew = rhsFixRegion_[iRow];
+          if (CoinAbs(value) < tol && CoinAbs(valueNew) > tol) {
+               printf("row %d old %g new %g\n", iRow, value, valueNew);
+               goneInf = true;
+          }
+     }
+     if (goneInf) {
+          actualPrimalStep_ *= 0.5;
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               CoinWorkDouble thisWeight = deltaX_[iColumn];
+               CoinWorkDouble newPrimal = solution_[iColumn] + 1.0 * actualPrimalStep_ * thisWeight;
+               deltaSL_[iColumn] = newPrimal;
+          }
+     }
+     CoinZeroN(errorRegion_, numberRows_);
+     CoinZeroN(rhsFixRegion_, numberRows_);
+#endif
+     // do reduced costs
+     CoinMemcpyN(dualArray, numberRows_, dj_ + numberColumns_);
+     CoinMemcpyN(cost_, numberColumns_, dj_);
+     CoinWorkDouble quadraticOffset = quadraticDjs(dj_, deltaSL_, 1.0);
+     // Save modified costs for fixed variables
+     CoinMemcpyN(dj_, numberColumns_, deltaSU_);
+     matrix_->transposeTimes(-1.0, dualArray, dj_);
+     CoinWorkDouble gamma2 = gamma_ * gamma_; // gamma*gamma will be added to diagonal
+     CoinWorkDouble gammaOffset = 0.0;
+#if 0
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const int * row = matrix_->getIndices();
+     const double * element = matrix_->getElements();
+#endif
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!flagged(iColumn)) {
+               CoinWorkDouble reducedCost = dj_[iColumn];
+               bool thisKilled = false;
+               CoinWorkDouble zValue = zVec_[iColumn] + actualDualStep_ * deltaZ_[iColumn];
+               CoinWorkDouble wValue = wVec_[iColumn] + actualDualStep_ * deltaW_[iColumn];
+               zVec_[iColumn] = zValue;
+               wVec_[iColumn] = wValue;
+               CoinWorkDouble thisWeight = deltaX_[iColumn];
+               CoinWorkDouble oldPrimal = solution_[iColumn];
+               CoinWorkDouble newPrimal = solution_[iColumn] + actualPrimalStep_ * thisWeight;
+               CoinWorkDouble dualObjectiveThis = 0.0;
+               CoinWorkDouble sUpper = extra;
+               CoinWorkDouble sLower = extra;
+               CoinWorkDouble kill;
+               if (CoinAbs(newPrimal) > 1.0e4) {
+                    kill = killTolerance * 1.0e-4 * newPrimal;
+               } else {
+                    kill = killTolerance;
+               }
+               kill *= 1.0e-3; //be conservative
+               CoinWorkDouble smallerSlack = COIN_DBL_MAX;
+               bool fakeOldBounds = false;
+               bool fakeNewBounds = false;
+               CoinWorkDouble trueLower;
+               CoinWorkDouble trueUpper;
+               if (iColumn < numberColumns_) {
+                    trueLower = columnLower_[iColumn];
+                    trueUpper = columnUpper_[iColumn];
+               } else {
+                    trueLower = rowLower_[iColumn-numberColumns_];
+                    trueUpper = rowUpper_[iColumn-numberColumns_];
+               }
+               if (oldPrimal > trueLower + largeGap2 &&
+                         oldPrimal < trueUpper - largeGap2)
+                    fakeOldBounds = true;
+               if (newPrimal > trueLower + largeGap2 &&
+                         newPrimal < trueUpper - largeGap2)
+                    fakeNewBounds = true;
+               if (fakeOldBounds) {
+                    if (fakeNewBounds) {
+                         lower_[iColumn] = newPrimal - largeGap2;
+                         lowerSlack_[iColumn] = largeGap2;
+                         upper_[iColumn] = newPrimal + largeGap2;
+                         upperSlack_[iColumn] = largeGap2;
+                    } else {
+                         lower_[iColumn] = trueLower;
+                         setLowerBound(iColumn);
+                         lowerSlack_[iColumn] = CoinMax(newPrimal - trueLower, 1.0);
+                         upper_[iColumn] = trueUpper;
+                         setUpperBound(iColumn);
+                         upperSlack_[iColumn] = CoinMax(trueUpper - newPrimal, 1.0);
+                    }
+               } else if (fakeNewBounds) {
+                    lower_[iColumn] = newPrimal - largeGap2;
+                    lowerSlack_[iColumn] = largeGap2;
+                    upper_[iColumn] = newPrimal + largeGap2;
+                    upperSlack_[iColumn] = largeGap2;
+                    // so we can just have one test
+                    fakeOldBounds = true;
+               }
+               CoinWorkDouble lowerBoundInfeasibility = 0.0;
+               CoinWorkDouble upperBoundInfeasibility = 0.0;
+               //double saveNewPrimal = newPrimal;
+               if (lowerBound(iColumn)) {
+                    CoinWorkDouble oldSlack = lowerSlack_[iColumn];
+                    CoinWorkDouble newSlack;
+                    newSlack =
+                         lowerSlack_[iColumn] + actualPrimalStep_ * (oldPrimal - oldSlack
+                                   + thisWeight - lower_[iColumn]);
+                    if (fakeOldBounds)
+                         newSlack = lowerSlack_[iColumn];
+                    CoinWorkDouble epsilon = CoinAbs(newSlack) * epsilonBase;
+                    epsilon = CoinMin(epsilon, 1.0e-5);
+                    //epsilon=1.0e-14;
+                    //make sure reasonable
+                    if (zValue < epsilon) {
+                         zValue = epsilon;
+                    }
+                    CoinWorkDouble feasibleSlack = newPrimal - lower_[iColumn];
+                    if (feasibleSlack > 0.0 && newSlack > 0.0) {
+                         CoinWorkDouble larger;
+                         if (newSlack > feasibleSlack) {
+                              larger = newSlack;
+                         } else {
+                              larger = feasibleSlack;
+                         }
+                         if (CoinAbs(feasibleSlack - newSlack) < 1.0e-6 * larger) {
+                              newSlack = feasibleSlack;
+                         }
+                    }
+                    if (zVec_[iColumn] > dualTolerance) {
+                         dualObjectiveThis += lower_[iColumn] * zVec_[iColumn];
+                    }
+                    lowerSlack_[iColumn] = newSlack;
+                    if (newSlack < smallerSlack) {
+                         smallerSlack = newSlack;
+                    }
+                    lowerBoundInfeasibility = CoinAbs(newPrimal - lowerSlack_[iColumn] - lower_[iColumn]);
+                    if (lowerSlack_[iColumn] <= kill * killFactor && CoinAbs(newPrimal - lower_[iColumn]) <= kill * killFactor) {
+                         CoinWorkDouble step = CoinMin(actualPrimalStep_ * 1.1, 1.0);
+                         CoinWorkDouble newPrimal2 = solution_[iColumn] + step * thisWeight;
+                         if (newPrimal2 < newPrimal && dj_[iColumn] > 1.0e-5 && numberIterations_ > 50 - 40) {
+                              newPrimal = lower_[iColumn];
+                              lowerSlack_[iColumn] = 0.0;
+                              //printf("fixing %d to lower\n",iColumn);
+                         }
+                    }
+                    if (lowerSlack_[iColumn] <= kill && CoinAbs(newPrimal - lower_[iColumn]) <= kill) {
+                         //may be better to leave at value?
+                         newPrimal = lower_[iColumn];
+                         lowerSlack_[iColumn] = 0.0;
+                         thisKilled = true;
+                         //cout<<j<<" l "<<reducedCost<<" "<<zVec_[iColumn]<<endl;
+                    } else {
+                         sLower += lowerSlack_[iColumn];
+                    }
+               }
+               if (upperBound(iColumn)) {
+                    CoinWorkDouble oldSlack = upperSlack_[iColumn];
+                    CoinWorkDouble newSlack;
+                    newSlack =
+                         upperSlack_[iColumn] + actualPrimalStep_ * (-oldPrimal - oldSlack
+                                   - thisWeight + upper_[iColumn]);
+                    if (fakeOldBounds)
+                         newSlack = upperSlack_[iColumn];
+                    CoinWorkDouble epsilon = CoinAbs(newSlack) * epsilonBase;
+                    epsilon = CoinMin(epsilon, 1.0e-5);
+                    //make sure reasonable
+                    //epsilon=1.0e-14;
+                    if (wValue < epsilon) {
+                         wValue = epsilon;
+                    }
+                    CoinWorkDouble feasibleSlack = upper_[iColumn] - newPrimal;
+                    if (feasibleSlack > 0.0 && newSlack > 0.0) {
+                         CoinWorkDouble larger;
+                         if (newSlack > feasibleSlack) {
+                              larger = newSlack;
+                         } else {
+                              larger = feasibleSlack;
+                         }
+                         if (CoinAbs(feasibleSlack - newSlack) < 1.0e-6 * larger) {
+                              newSlack = feasibleSlack;
+                         }
+                    }
+                    if (wVec_[iColumn] > dualTolerance) {
+                         dualObjectiveThis -= upper_[iColumn] * wVec_[iColumn];
+                    }
+                    upperSlack_[iColumn] = newSlack;
+                    if (newSlack < smallerSlack) {
+                         smallerSlack = newSlack;
+                    }
+                    upperBoundInfeasibility = CoinAbs(newPrimal + upperSlack_[iColumn] - upper_[iColumn]);
+                    if (upperSlack_[iColumn] <= kill * killFactor && CoinAbs(newPrimal - upper_[iColumn]) <= kill * killFactor) {
+                         CoinWorkDouble step = CoinMin(actualPrimalStep_ * 1.1, 1.0);
+                         CoinWorkDouble newPrimal2 = solution_[iColumn] + step * thisWeight;
+                         if (newPrimal2 > newPrimal && dj_[iColumn] < -1.0e-5 && numberIterations_ > 50 - 40) {
+                              newPrimal = upper_[iColumn];
+                              upperSlack_[iColumn] = 0.0;
+                              //printf("fixing %d to upper\n",iColumn);
+                         }
+                    }
+                    if (upperSlack_[iColumn] <= kill && CoinAbs(newPrimal - upper_[iColumn]) <= kill) {
+                         //may be better to leave at value?
+                         newPrimal = upper_[iColumn];
+                         upperSlack_[iColumn] = 0.0;
+                         thisKilled = true;
+                    } else {
+                         sUpper += upperSlack_[iColumn];
+                    }
+               }
+#if 0
+               if (newPrimal != saveNewPrimal && iColumn < numberColumns_) {
+                    // adjust slacks
+                    double movement = newPrimal - saveNewPrimal;
+                    for (CoinBigIndex j = columnStart[iColumn];
+                              j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         int iRow = row[j];
+                         double slackMovement = element[j] * movement;
+                         solution_[iRow+numberColumns_] += slackMovement; // sign?
+                    }
+               }
+#endif
+               solution_[iColumn] = newPrimal;
+               if (CoinAbs(newPrimal) > solutionNorm) {
+                    solutionNorm = CoinAbs(newPrimal);
+               }
+               if (!thisKilled) {
+                    CoinWorkDouble gammaTerm = gamma2;
+                    if (primalR_) {
+                         gammaTerm += primalR_[iColumn];
+                         quadraticOffset += newPrimal * newPrimal * primalR_[iColumn];
+                    }
+                    CoinWorkDouble dualInfeasibility =
+                         reducedCost - zVec_[iColumn] + wVec_[iColumn] + gammaTerm * newPrimal;
+                    if (CoinAbs(dualInfeasibility) > dualTolerance) {
+#if 0
+                         if (dualInfeasibility > 0.0) {
+                              // To improve we could reduce t and/or increase z
+                              if (lowerBound(iColumn)) {
+                                   CoinWorkDouble complementarity = zVec_[iColumn] * lowerSlack_[iColumn];
+                                   if (complementarity < nextMu) {
+                                        CoinWorkDouble change =
+                                             CoinMin(dualInfeasibility,
+                                                     (nextMu - complementarity) / lowerSlack_[iColumn]);
+                                        dualInfeasibility -= change;
+                                        COIN_DETAIL_PRINT(printf("%d lb locomp %g - dual inf from %g to %g\n",
+                                               iColumn, complementarity, dualInfeasibility + change,
+								 dualInfeasibility));
+                                        zVec_[iColumn] += change;
+                                        zValue = CoinMax(zVec_[iColumn], 1.0e-12);
+                                   }
+                              }
+                              if (upperBound(iColumn)) {
+                                   CoinWorkDouble complementarity = wVec_[iColumn] * upperSlack_[iColumn];
+                                   if (complementarity > nextMu) {
+                                        CoinWorkDouble change =
+                                             CoinMin(dualInfeasibility,
+                                                     (complementarity - nextMu) / upperSlack_[iColumn]);
+                                        dualInfeasibility -= change;
+                                        COIN_DETAIL_PRINT(printf("%d ub hicomp %g - dual inf from %g to %g\n",
+                                               iColumn, complementarity, dualInfeasibility + change,
+								 dualInfeasibility));
+                                        wVec_[iColumn] -= change;
+                                        wValue = CoinMax(wVec_[iColumn], 1.0e-12);
+                                   }
+                              }
+                         } else {
+                              // To improve we could reduce z and/or increase t
+                              if (lowerBound(iColumn)) {
+                                   CoinWorkDouble complementarity = zVec_[iColumn] * lowerSlack_[iColumn];
+                                   if (complementarity > nextMu) {
+                                        CoinWorkDouble change =
+                                             CoinMax(dualInfeasibility,
+                                                     (nextMu - complementarity) / lowerSlack_[iColumn]);
+                                        dualInfeasibility -= change;
+                                        COIN_DETAIL_PRINT(printf("%d lb hicomp %g - dual inf from %g to %g\n",
+                                               iColumn, complementarity, dualInfeasibility + change,
+								 dualInfeasibility));
+                                        zVec_[iColumn] += change;
+                                        zValue = CoinMax(zVec_[iColumn], 1.0e-12);
+                                   }
+                              }
+                              if (upperBound(iColumn)) {
+                                   CoinWorkDouble complementarity = wVec_[iColumn] * upperSlack_[iColumn];
+                                   if (complementarity < nextMu) {
+                                        CoinWorkDouble change =
+                                             CoinMax(dualInfeasibility,
+                                                     (complementarity - nextMu) / upperSlack_[iColumn]);
+                                        dualInfeasibility -= change;
+                                        COIN_DETAIL_PRINT(printf("%d ub locomp %g - dual inf from %g to %g\n",
+                                               iColumn, complementarity, dualInfeasibility + change,
+								 dualInfeasibility));
+                                        wVec_[iColumn] -= change;
+                                        wValue = CoinMax(wVec_[iColumn], 1.0e-12);
+                                   }
+                              }
+                         }
+#endif
+                         dualFake += newPrimal * dualInfeasibility;
+                    }
+                    if (lowerBoundInfeasibility > maximumBoundInfeasibility) {
+                         maximumBoundInfeasibility = lowerBoundInfeasibility;
+                    }
+                    if (upperBoundInfeasibility > maximumBoundInfeasibility) {
+                         maximumBoundInfeasibility = upperBoundInfeasibility;
+                    }
+                    dualInfeasibility = CoinAbs(dualInfeasibility);
+                    if (dualInfeasibility > maximumDualError) {
+                         //printf("bad dual %d %g\n",iColumn,
+                         // reducedCost-zVec_[iColumn]+wVec_[iColumn]+gammaTerm*newPrimal);
+                         maximumDualError = dualInfeasibility;
+                    }
+                    dualObjectiveValue += dualObjectiveThis;
+                    gammaOffset += newPrimal * newPrimal;
+                    if (sLower > largeGap) {
+                         sLower = largeGap;
+                    }
+                    if (sUpper > largeGap) {
+                         sUpper = largeGap;
+                    }
+#if 1
+                    CoinWorkDouble divisor = sLower * wValue + sUpper * zValue + gammaTerm * sLower * sUpper;
+                    CoinWorkDouble diagonalValue = (sUpper * sLower) / divisor;
+#else
+                    CoinWorkDouble divisor = sLower * wValue + sUpper * zValue + gammaTerm * sLower * sUpper;
+                    CoinWorkDouble diagonalValue2 = (sUpper * sLower) / divisor;
+                    CoinWorkDouble diagonalValue;
+                    if (!lowerBound(iColumn)) {
+                         diagonalValue = wValue / sUpper + gammaTerm;
+                    } else if (!upperBound(iColumn)) {
+                         diagonalValue = zValue / sLower + gammaTerm;
+                    } else {
+                         diagonalValue = zValue / sLower + wValue / sUpper + gammaTerm;
+                    }
+                    diagonalValue = 1.0 / diagonalValue;
+#endif
+                    diagonal_[iColumn] = diagonalValue;
+                    //FUDGE
+                    if (diagonalValue > diagonalLimit) {
+#ifdef COIN_DEVELOP
+                         std::cout << "large diagonal " << diagonalValue << std::endl;
+#endif
+                         diagonal_[iColumn] = diagonalLimit;
+                    }
+#ifdef COIN_DEVELOP
+                    if (diagonalValue < 1.0e-10) {
+                         //std::cout<<"small diagonal "<<diagonalValue<<std::endl;
+                    }
+#endif
+                    if (diagonalValue > largestDiagonal) {
+                         largestDiagonal = diagonalValue;
+                    }
+                    if (diagonalValue < smallestDiagonal) {
+                         smallestDiagonal = diagonalValue;
+                    }
+                    deltaX_[iColumn] = 0.0;
+               } else {
+                    numberKilled++;
+                    if (solution_[iColumn] != lower_[iColumn] &&
+                              solution_[iColumn] != upper_[iColumn]) {
+                         COIN_DETAIL_PRINT(printf("%d %g %g %g\n", iColumn, static_cast<double>(lower_[iColumn]),
+						  static_cast<double>(solution_[iColumn]), static_cast<double>(upper_[iColumn])));
+                    }
+                    diagonal_[iColumn] = 0.0;
+                    zVec_[iColumn] = 0.0;
+                    wVec_[iColumn] = 0.0;
+                    setFlagged(iColumn);
+                    setFixedOrFree(iColumn);
+                    deltaX_[iColumn] = newPrimal;
+                    offsetObjective += newPrimal * deltaSU_[iColumn];
+               }
+          } else {
+               deltaX_[iColumn] = solution_[iColumn];
+               diagonal_[iColumn] = 0.0;
+               offsetObjective += solution_[iColumn] * deltaSU_[iColumn];
+               if (upper_[iColumn] - lower_[iColumn] > 1.0e-5) {
+                    if (solution_[iColumn] < lower_[iColumn] + 1.0e-8 && dj_[iColumn] < -1.0e-8) {
+                         if (-dj_[iColumn] > maximumDJInfeasibility) {
+                              maximumDJInfeasibility = -dj_[iColumn];
+                         }
+                    }
+                    if (solution_[iColumn] > upper_[iColumn] - 1.0e-8 && dj_[iColumn] > 1.0e-8) {
+                         if (dj_[iColumn] > maximumDJInfeasibility) {
+                              maximumDJInfeasibility = dj_[iColumn];
+                         }
+                    }
+               }
+          }
+          primalObjectiveValue += solution_[iColumn] * cost_[iColumn];
+     }
+     handler_->message(CLP_BARRIER_DIAGONAL, messages_)
+               << static_cast<double>(largestDiagonal) << static_cast<double>(smallestDiagonal)
+               << CoinMessageEol;
+#if 0
+     // If diagonal wild - kill some
+     if (largestDiagonal > 1.0e17 * smallestDiagonal) {
+          CoinWorkDouble killValue = largestDiagonal * 1.0e-17;
+          for (int iColumn = 0; iColumn < numberTotal; iColumn++) {
+               if (CoinAbs(diagonal_[iColumn]) < killValue)
+                    diagonal_[iolumn] = 0.0;
+          }
+     }
+#endif
+     // update rhs region
+     multiplyAdd(deltaX_ + numberColumns_, numberRows_, -1.0, rhsFixRegion_, 1.0);
+     matrix_->times(1.0, deltaX_, rhsFixRegion_);
+     primalObjectiveValue += 0.5 * gamma2 * gammaOffset + 0.5 * quadraticOffset;
+     if (quadraticOffset) {
+          //  printf("gamma offset %g %g, quadoffset %g\n",gammaOffset,gamma2*gammaOffset,quadraticOffset);
+     }
+
+     dualObjectiveValue += offsetObjective + dualFake;
+     dualObjectiveValue -= 0.5 * gamma2 * gammaOffset + 0.5 * quadraticOffset;
+     if (numberIncreased || numberDecreased) {
+          handler_->message(CLP_BARRIER_SLACKS, messages_)
+                    << numberIncreased << numberDecreased
+                    << CoinMessageEol;
+     }
+     if (maximumDJInfeasibility) {
+          handler_->message(CLP_BARRIER_DUALINF, messages_)
+                    << static_cast<double>(maximumDJInfeasibility)
+                    << CoinMessageEol;
+     }
+     // Need to rethink (but it is only for printing)
+     sumPrimalInfeasibilities_ = maximumRhsInfeasibility;
+     sumDualInfeasibilities_ = maximumDualError;
+     maximumBoundInfeasibility_ = maximumBoundInfeasibility;
+     //compute error and fixed RHS
+     multiplyAdd(solution_ + numberColumns_, numberRows_, -1.0, errorRegion_, 0.0);
+     matrix_->times(1.0, solution_, errorRegion_);
+     maximumDualError_ = maximumDualError;
+     maximumBoundInfeasibility_ = maximumBoundInfeasibility;
+     solutionNorm_ = solutionNorm;
+     //finish off objective computation
+     primalObjective_ = primalObjectiveValue * scaleFactor_;
+     CoinWorkDouble dualValue2 = innerProduct(dualArray, numberRows_,
+                                 rhsFixRegion_);
+     dualObjectiveValue -= dualValue2;
+     dualObjective_ = dualObjectiveValue * scaleFactor_;
+     if (numberKilled) {
+          handler_->message(CLP_BARRIER_KILLED, messages_)
+                    << numberKilled
+                    << CoinMessageEol;
+     }
+     CoinWorkDouble maximumRHSError1 = 0.0;
+     CoinWorkDouble maximumRHSError2 = 0.0;
+     CoinWorkDouble primalOffset = 0.0;
+     char * dropped = cholesky_->rowsDropped();
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          CoinWorkDouble value = errorRegion_[iRow];
+          if (!dropped[iRow]) {
+               if (CoinAbs(value) > maximumRHSError1) {
+                    maximumRHSError1 = CoinAbs(value);
+               }
+          } else {
+               if (CoinAbs(value) > maximumRHSError2) {
+                    maximumRHSError2 = CoinAbs(value);
+               }
+               primalOffset += value * dualArray[iRow];
+          }
+     }
+     primalObjective_ -= primalOffset * scaleFactor_;
+     if (maximumRHSError1 > maximumRHSError2) {
+          maximumRHSError_ = maximumRHSError1;
+     } else {
+          maximumRHSError_ = maximumRHSError1; //note change
+          if (maximumRHSError2 > primalTolerance()) {
+               handler_->message(CLP_BARRIER_ABS_DROPPED, messages_)
+                         << static_cast<double>(maximumRHSError2)
+                         << CoinMessageEol;
+          }
+     }
+     objectiveNorm_ = maximumAbsElement(dualArray, numberRows_);
+     if (objectiveNorm_ < 1.0e-12) {
+          objectiveNorm_ = 1.0e-12;
+     }
+     if (objectiveNorm_ < baseObjectiveNorm_) {
+          //std::cout<<" base "<<baseObjectiveNorm_<<" "<<objectiveNorm_<<std::endl;
+          if (objectiveNorm_ < baseObjectiveNorm_ * 1.0e-4) {
+               objectiveNorm_ = baseObjectiveNorm_ * 1.0e-4;
+          }
+     }
+     bool primalFeasible = true;
+     if (maximumRHSError_ > primalTolerance() ||
+               maximumDualError_ > dualTolerance / scaleFactor_) {
+          handler_->message(CLP_BARRIER_ABS_ERROR, messages_)
+                    << static_cast<double>(maximumRHSError_) << static_cast<double>(maximumDualError_)
+                    << CoinMessageEol;
+     }
+     if (rhsNorm_ > solutionNorm_) {
+          solutionNorm_ = rhsNorm_;
+     }
+     CoinWorkDouble scaledRHSError = maximumRHSError_ / (solutionNorm_ + 10.0);
+     bool dualFeasible = true;
+#if KEEP_GOING_IF_FIXED > 5
+     if (maximumBoundInfeasibility_ > primalTolerance() ||
+               scaledRHSError > primalTolerance())
+          primalFeasible = false;
+#else
+     if (maximumBoundInfeasibility_ > primalTolerance() ||
+               scaledRHSError > CoinMax(CoinMin(100.0 * primalTolerance(), 1.0e-5),
+                                        primalTolerance()))
+          primalFeasible = false;
+#endif
+     // relax dual test if obj big and gap smallish
+     CoinWorkDouble gap = CoinAbs(primalObjective_ - dualObjective_);
+     CoinWorkDouble sizeObj = CoinMin(CoinAbs(primalObjective_), CoinAbs(dualObjective_)) + 1.0e-50;
+     //printf("gap %g sizeObj %g ratio %g comp %g\n",
+     //     gap,sizeObj,gap/sizeObj,complementarityGap_);
+     if (numberIterations_ > 100 && gap / sizeObj < 1.0e-9 && complementarityGap_ < 1.0e-7 * sizeObj)
+          dualTolerance *= 1.0e2;
+     if (maximumDualError_ > objectiveNorm_ * dualTolerance)
+          dualFeasible = false;
+     if (!primalFeasible || !dualFeasible) {
+          handler_->message(CLP_BARRIER_FEASIBLE, messages_)
+                    << static_cast<double>(maximumBoundInfeasibility_) << static_cast<double>(scaledRHSError)
+                    << static_cast<double>(maximumDualError_ / objectiveNorm_)
+                    << CoinMessageEol;
+     }
+     if (!gonePrimalFeasible_) {
+          gonePrimalFeasible_ = primalFeasible;
+     } else if (!primalFeasible) {
+          gonePrimalFeasible_ = primalFeasible;
+          if (!numberKilled) {
+               handler_->message(CLP_BARRIER_GONE_INFEASIBLE, messages_)
+                         << CoinMessageEol;
+          }
+     }
+     if (!goneDualFeasible_) {
+          goneDualFeasible_ = dualFeasible;
+     } else if (!dualFeasible) {
+          handler_->message(CLP_BARRIER_GONE_INFEASIBLE, messages_)
+                    << CoinMessageEol;
+          goneDualFeasible_ = dualFeasible;
+     }
+     //objectiveValue();
+     if (solutionNorm_ > 1.0e40) {
+          std::cout << "primal off to infinity" << std::endl;
+          abort();
+     }
+     if (objectiveNorm_ > 1.0e40) {
+          std::cout << "dual off to infinity" << std::endl;
+          abort();
+     }
+     handler_->message(CLP_BARRIER_STEP, messages_)
+               << static_cast<double>(actualPrimalStep_)
+               << static_cast<double>(actualDualStep_)
+               << static_cast<double>(mu_)
+               << CoinMessageEol;
+     numberIterations_++;
+     return numberKilled;
+}
+//  Save info on products of affine deltaSU*deltaW and deltaSL*deltaZ
+CoinWorkDouble
+ClpPredictorCorrector::affineProduct()
+{
+     CoinWorkDouble product = 0.0;
+     //IF zVec starts as 0 then deltaZ always zero
+     //(remember if free then zVec not 0)
+     //I think free can be done with careful use of boundSlacks to zero
+     //out all we want
+     for (int iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++) {
+          CoinWorkDouble w3 = deltaZ_[iColumn] * deltaX_[iColumn];
+          CoinWorkDouble w4 = -deltaW_[iColumn] * deltaX_[iColumn];
+          if (lowerBound(iColumn)) {
+               w3 += deltaZ_[iColumn] * (solution_[iColumn] - lowerSlack_[iColumn] - lower_[iColumn]);
+               product += w3;
+          }
+          if (upperBound(iColumn)) {
+               w4 += deltaW_[iColumn] * (-solution_[iColumn] - upperSlack_[iColumn] + upper_[iColumn]);
+               product += w4;
+          }
+     }
+     return product;
+}
+//See exactly what would happen given current deltas
+void
+ClpPredictorCorrector::debugMove(int /*phase*/,
+                                 CoinWorkDouble primalStep, CoinWorkDouble dualStep)
+{
+#ifndef SOME_DEBUG
+     return;
+#endif
+     CoinWorkDouble * dualArray = reinterpret_cast<CoinWorkDouble *>(dual_);
+     int numberTotal = numberRows_ + numberColumns_;
+     CoinWorkDouble * dualNew = ClpCopyOfArray(dualArray, numberRows_);
+     CoinWorkDouble * errorRegionNew = new CoinWorkDouble [numberRows_];
+     CoinWorkDouble * rhsFixRegionNew = new CoinWorkDouble [numberRows_];
+     CoinWorkDouble * primalNew = ClpCopyOfArray(solution_, numberTotal);
+     CoinWorkDouble * djNew = new CoinWorkDouble[numberTotal];
+     //update pi
+     multiplyAdd(deltaY_, numberRows_, dualStep, dualNew, 1.0);
+     // do reduced costs
+     CoinMemcpyN(dualNew, numberRows_, djNew + numberColumns_);
+     CoinMemcpyN(cost_, numberColumns_, djNew);
+     matrix_->transposeTimes(-1.0, dualNew, djNew);
+     // update x
+     int iColumn;
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!flagged(iColumn))
+               primalNew[iColumn] += primalStep * deltaX_[iColumn];
+     }
+     CoinWorkDouble quadraticOffset = quadraticDjs(djNew, primalNew, 1.0);
+     CoinZeroN(errorRegionNew, numberRows_);
+     CoinZeroN(rhsFixRegionNew, numberRows_);
+     CoinWorkDouble maximumBoundInfeasibility = 0.0;
+     CoinWorkDouble maximumDualError = 1.0e-12;
+     CoinWorkDouble primalObjectiveValue = 0.0;
+     CoinWorkDouble dualObjectiveValue = 0.0;
+     CoinWorkDouble solutionNorm = 1.0e-12;
+     const CoinWorkDouble largeFactor = 1.0e2;
+     CoinWorkDouble largeGap = largeFactor * solutionNorm_;
+     if (largeGap < largeFactor) {
+          largeGap = largeFactor;
+     }
+     CoinWorkDouble dualFake = 0.0;
+     CoinWorkDouble dualTolerance =  dblParam_[ClpDualTolerance];
+     dualTolerance = dualTolerance / scaleFactor_;
+     if (dualTolerance < 1.0e-12) {
+          dualTolerance = 1.0e-12;
+     }
+     CoinWorkDouble newGap = 0.0;
+     CoinWorkDouble offsetObjective = 0.0;
+     CoinWorkDouble gamma2 = gamma_ * gamma_; // gamma*gamma will be added to diagonal
+     CoinWorkDouble gammaOffset = 0.0;
+     CoinWorkDouble maximumDjInfeasibility = 0.0;
+     for ( iColumn = 0; iColumn < numberTotal; iColumn++) {
+          if (!flagged(iColumn)) {
+               CoinWorkDouble reducedCost = djNew[iColumn];
+               CoinWorkDouble zValue = zVec_[iColumn] + dualStep * deltaZ_[iColumn];
+               CoinWorkDouble wValue = wVec_[iColumn] + dualStep * deltaW_[iColumn];
+               CoinWorkDouble thisWeight = deltaX_[iColumn];
+               CoinWorkDouble oldPrimal = solution_[iColumn];
+               CoinWorkDouble newPrimal = primalNew[iColumn];
+               CoinWorkDouble lowerBoundInfeasibility = 0.0;
+               CoinWorkDouble upperBoundInfeasibility = 0.0;
+               if (lowerBound(iColumn)) {
+                    CoinWorkDouble oldSlack = lowerSlack_[iColumn];
+                    CoinWorkDouble newSlack =
+                         lowerSlack_[iColumn] + primalStep * (oldPrimal - oldSlack
+                                   + thisWeight - lower_[iColumn]);
+                    if (zValue > dualTolerance) {
+                         dualObjectiveValue += lower_[iColumn] * zVec_[iColumn];
+                    }
+                    lowerBoundInfeasibility = CoinAbs(newPrimal - newSlack - lower_[iColumn]);
+                    newGap += newSlack * zValue;
+               }
+               if (upperBound(iColumn)) {
+                    CoinWorkDouble oldSlack = upperSlack_[iColumn];
+                    CoinWorkDouble newSlack =
+                         upperSlack_[iColumn] + primalStep * (-oldPrimal - oldSlack
+                                   - thisWeight + upper_[iColumn]);
+                    if (wValue > dualTolerance) {
+                         dualObjectiveValue -= upper_[iColumn] * wVec_[iColumn];
+                    }
+                    upperBoundInfeasibility = CoinAbs(newPrimal + newSlack - upper_[iColumn]);
+                    newGap += newSlack * wValue;
+               }
+               if (CoinAbs(newPrimal) > solutionNorm) {
+                    solutionNorm = CoinAbs(newPrimal);
+               }
+               CoinWorkDouble gammaTerm = gamma2;
+               if (primalR_) {
+                    gammaTerm += primalR_[iColumn];
+                    quadraticOffset += newPrimal * newPrimal * primalR_[iColumn];
+               }
+               CoinWorkDouble dualInfeasibility =
+                    reducedCost - zValue + wValue + gammaTerm * newPrimal;
+               if (CoinAbs(dualInfeasibility) > dualTolerance) {
+                    dualFake += newPrimal * dualInfeasibility;
+               }
+               if (lowerBoundInfeasibility > maximumBoundInfeasibility) {
+                    maximumBoundInfeasibility = lowerBoundInfeasibility;
+               }
+               if (upperBoundInfeasibility > maximumBoundInfeasibility) {
+                    maximumBoundInfeasibility = upperBoundInfeasibility;
+               }
+               dualInfeasibility = CoinAbs(dualInfeasibility);
+               if (dualInfeasibility > maximumDualError) {
+                    //printf("bad dual %d %g\n",iColumn,
+                    // reducedCost-zVec_[iColumn]+wVec_[iColumn]+gammaTerm*newPrimal);
+                    maximumDualError = dualInfeasibility;
+               }
+               gammaOffset += newPrimal * newPrimal;
+               djNew[iColumn] = 0.0;
+          } else {
+               offsetObjective += primalNew[iColumn] * cost_[iColumn];
+               if (upper_[iColumn] - lower_[iColumn] > 1.0e-5) {
+                    if (primalNew[iColumn] < lower_[iColumn] + 1.0e-8 && djNew[iColumn] < -1.0e-8) {
+                         if (-djNew[iColumn] > maximumDjInfeasibility) {
+                              maximumDjInfeasibility = -djNew[iColumn];
+                         }
+                    }
+                    if (primalNew[iColumn] > upper_[iColumn] - 1.0e-8 && djNew[iColumn] > 1.0e-8) {
+                         if (djNew[iColumn] > maximumDjInfeasibility) {
+                              maximumDjInfeasibility = djNew[iColumn];
+                         }
+                    }
+               }
+               djNew[iColumn] = primalNew[iColumn];
+          }
+          primalObjectiveValue += solution_[iColumn] * cost_[iColumn];
+     }
+     // update rhs region
+     multiplyAdd(djNew + numberColumns_, numberRows_, -1.0, rhsFixRegionNew, 1.0);
+     matrix_->times(1.0, djNew, rhsFixRegionNew);
+     primalObjectiveValue += 0.5 * gamma2 * gammaOffset + 0.5 * quadraticOffset;
+     dualObjectiveValue += offsetObjective + dualFake;
+     dualObjectiveValue -= 0.5 * gamma2 * gammaOffset + 0.5 * quadraticOffset;
+     // Need to rethink (but it is only for printing)
+     //compute error and fixed RHS
+     multiplyAdd(primalNew + numberColumns_, numberRows_, -1.0, errorRegionNew, 0.0);
+     matrix_->times(1.0, primalNew, errorRegionNew);
+     //finish off objective computation
+     CoinWorkDouble primalObjectiveNew = primalObjectiveValue * scaleFactor_;
+     CoinWorkDouble dualValue2 = innerProduct(dualNew, numberRows_,
+                                 rhsFixRegionNew);
+     dualObjectiveValue -= dualValue2;
+     //CoinWorkDouble dualObjectiveNew=dualObjectiveValue*scaleFactor_;
+     CoinWorkDouble maximumRHSError1 = 0.0;
+     CoinWorkDouble maximumRHSError2 = 0.0;
+     CoinWorkDouble primalOffset = 0.0;
+     char * dropped = cholesky_->rowsDropped();
+     int iRow;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          CoinWorkDouble value = errorRegionNew[iRow];
+          if (!dropped[iRow]) {
+               if (CoinAbs(value) > maximumRHSError1) {
+                    maximumRHSError1 = CoinAbs(value);
+               }
+          } else {
+               if (CoinAbs(value) > maximumRHSError2) {
+                    maximumRHSError2 = CoinAbs(value);
+               }
+               primalOffset += value * dualNew[iRow];
+          }
+     }
+     primalObjectiveNew -= primalOffset * scaleFactor_;
+     //CoinWorkDouble maximumRHSError;
+     if (maximumRHSError1 > maximumRHSError2) {
+          ;//maximumRHSError = maximumRHSError1;
+     } else {
+          //maximumRHSError = maximumRHSError1; //note change
+          if (maximumRHSError2 > primalTolerance()) {
+               handler_->message(CLP_BARRIER_ABS_DROPPED, messages_)
+                         << static_cast<double>(maximumRHSError2)
+                         << CoinMessageEol;
+          }
+     }
+     /*printf("PH %d %g, %g new comp %g, b %g, p %g, d %g\n",phase,
+      primalStep,dualStep,newGap,maximumBoundInfeasibility,
+      maximumRHSError,maximumDualError);
+     if (handler_->logLevel()>1)
+       printf("       objs %g %g\n",
+        primalObjectiveNew,dualObjectiveNew);
+     if (maximumDjInfeasibility) {
+       printf(" max dj error on fixed %g\n",
+        maximumDjInfeasibility);
+        } */
+     delete [] dualNew;
+     delete [] errorRegionNew;
+     delete [] rhsFixRegionNew;
+     delete [] primalNew;
+     delete [] djNew;
+}
diff --git a/cbits/coin/ClpPredictorCorrector.hpp b/cbits/coin/ClpPredictorCorrector.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPredictorCorrector.hpp
@@ -0,0 +1,92 @@
+/* $Id: ClpPredictorCorrector.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef ClpPredictorCorrector_H
+#define ClpPredictorCorrector_H
+
+#include "ClpInterior.hpp"
+
+/** This solves LPs using the predictor-corrector method due to Mehrotra.
+    It also uses multiple centrality corrections as in Gondzio.
+
+    See;
+    S. Mehrotra, "On the implementation of a primal-dual interior point method",
+    SIAM Journal on optimization, 2 (1992)
+    J. Gondzio, "Multiple centraility corrections in a primal-dual method for linear programming",
+    Computational Optimization and Applications",6 (1996)
+
+
+    It is rather basic as Interior point is not my speciality
+
+    It inherits from ClpInterior.  It has no data of its own and
+    is never created - only cast from a ClpInterior object at algorithm time.
+
+    It can also solve QPs
+
+
+
+*/
+
+class ClpPredictorCorrector : public ClpInterior {
+
+public:
+
+     /**@name Description of algorithm */
+     //@{
+     /** Primal Dual Predictor Corrector algorithm
+
+         Method
+
+         Big TODO
+     */
+
+     int solve();
+     //@}
+
+     /**@name Functions used in algorithm */
+     //@{
+     /// findStepLength.
+     //phase  - 0 predictor
+     //         1 corrector
+     //         2 primal dual
+     CoinWorkDouble findStepLength( int phase);
+     /// findDirectionVector.
+     CoinWorkDouble findDirectionVector(const int phase);
+     /// createSolution.  Creates solution from scratch (- code if no memory)
+     int createSolution();
+     /// complementarityGap.  Computes gap
+     //phase 0=as is , 1 = after predictor , 2 after corrector
+     CoinWorkDouble complementarityGap(int & numberComplementarityPairs, int & numberComplementarityItems,
+                                       const int phase);
+     /// setupForSolve.
+     //phase 0=affine , 1 = corrector , 2 = primal-dual
+     void setupForSolve(const int phase);
+     /** Does solve. region1 is for deltaX (columns+rows), region2 for deltaPi (rows) */
+     void solveSystem(CoinWorkDouble * region1, CoinWorkDouble * region2,
+                      const CoinWorkDouble * region1In, const CoinWorkDouble * region2In,
+                      const CoinWorkDouble * saveRegion1, const CoinWorkDouble * saveRegion2,
+                      bool gentleRefine);
+     /// sees if looks plausible change in complementarity
+     bool checkGoodMove(const bool doCorrector, CoinWorkDouble & bestNextGap,
+                        bool allowIncreasingGap);
+     ///:  checks for one step size
+     bool checkGoodMove2(CoinWorkDouble move, CoinWorkDouble & bestNextGap,
+                         bool allowIncreasingGap);
+     /// updateSolution.  Updates solution at end of iteration
+     //returns number fixed
+     int updateSolution(CoinWorkDouble nextGap);
+     ///  Save info on products of affine deltaT*deltaW and deltaS*deltaZ
+     CoinWorkDouble affineProduct();
+     ///See exactly what would happen given current deltas
+     void debugMove(int phase, CoinWorkDouble primalStep, CoinWorkDouble dualStep);
+     //@}
+
+};
+#endif
diff --git a/cbits/coin/ClpPresolve.cpp b/cbits/coin/ClpPresolve.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPresolve.cpp
@@ -0,0 +1,2554 @@
+/* $Id: ClpPresolve.cpp 1931 2013-04-06 20:44:29Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//#define	PRESOLVE_CONSISTENCY	1
+//#define	PRESOLVE_DEBUG	1
+
+#include <stdio.h>
+
+#include <cassert>
+#include <iostream>
+
+#include "CoinHelperFunctions.hpp"
+#include "ClpConfig.h"
+#ifdef CLP_HAS_ABC
+#include "CoinAbcCommon.hpp"
+#endif
+
+#include "CoinPackedMatrix.hpp"
+#include "ClpPackedMatrix.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpSimplexOther.hpp"
+#ifndef SLIM_CLP
+#include "ClpQuadraticObjective.hpp"
+#endif
+
+#include "ClpPresolve.hpp"
+#include "CoinPresolveMatrix.hpp"
+
+#include "CoinPresolveEmpty.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolvePsdebug.hpp"
+#include "CoinPresolveSingleton.hpp"
+#include "CoinPresolveDoubleton.hpp"
+#include "CoinPresolveTripleton.hpp"
+#include "CoinPresolveZeros.hpp"
+#include "CoinPresolveSubst.hpp"
+#include "CoinPresolveForcing.hpp"
+#include "CoinPresolveDual.hpp"
+#include "CoinPresolveTighten.hpp"
+#include "CoinPresolveUseless.hpp"
+#include "CoinPresolveDupcol.hpp"
+#include "CoinPresolveImpliedFree.hpp"
+#include "CoinPresolveIsolated.hpp"
+#include "CoinMessage.hpp"
+
+
+
+ClpPresolve::ClpPresolve() :
+     originalModel_(NULL),
+     presolvedModel_(NULL),
+     nonLinearValue_(0.0),
+     originalColumn_(NULL),
+     originalRow_(NULL),
+     rowObjective_(NULL),
+     paction_(0),
+     ncols_(0),
+     nrows_(0),
+     nelems_(0),
+#ifdef ABC_INHERIT
+     numberPasses_(20),
+#else
+     numberPasses_(5),
+#endif
+     substitution_(3),
+#ifndef CLP_NO_STD
+     saveFile_(""),
+#endif
+     presolveActions_(0)
+{
+}
+
+ClpPresolve::~ClpPresolve()
+{
+     destroyPresolve();
+}
+// Gets rid of presolve actions (e.g.when infeasible)
+void
+ClpPresolve::destroyPresolve()
+{
+     const CoinPresolveAction *paction = paction_;
+     while (paction) {
+          const CoinPresolveAction *next = paction->next;
+          delete paction;
+          paction = next;
+     }
+     delete [] originalColumn_;
+     delete [] originalRow_;
+     paction_ = NULL;
+     originalColumn_ = NULL;
+     originalRow_ = NULL;
+     delete [] rowObjective_;
+     rowObjective_ = NULL;
+}
+
+/* This version of presolve returns a pointer to a new presolved
+   model.  NULL if infeasible
+*/
+ClpSimplex *
+ClpPresolve::presolvedModel(ClpSimplex & si,
+                            double feasibilityTolerance,
+                            bool keepIntegers,
+                            int numberPasses,
+                            bool dropNames,
+                            bool doRowObjective,
+			    const char * prohibitedRows,
+			    const char * prohibitedColumns)
+{
+     // Check matrix
+     int checkType = ((si.specialOptions() & 128) != 0) ? 14 : 15;
+     if (!si.clpMatrix()->allElementsInRange(&si, si.getSmallElementValue(),
+                                             1.0e20,checkType))
+          return NULL;
+     else
+          return gutsOfPresolvedModel(&si, feasibilityTolerance, keepIntegers, numberPasses, dropNames,
+                                      doRowObjective,
+				      prohibitedRows,
+				      prohibitedColumns);
+}
+#ifndef CLP_NO_STD
+/* This version of presolve updates
+   model and saves original data to file.  Returns non-zero if infeasible
+*/
+int
+ClpPresolve::presolvedModelToFile(ClpSimplex &si, std::string fileName,
+                                  double feasibilityTolerance,
+                                  bool keepIntegers,
+                                  int numberPasses,
+				  bool dropNames,
+                                  bool doRowObjective)
+{
+     // Check matrix
+     if (!si.clpMatrix()->allElementsInRange(&si, si.getSmallElementValue(),
+                                             1.0e20))
+          return 2;
+     saveFile_ = fileName;
+     si.saveModel(saveFile_.c_str());
+     ClpSimplex * model = gutsOfPresolvedModel(&si, feasibilityTolerance, keepIntegers, numberPasses, dropNames,
+                          doRowObjective);
+     if (model == &si) {
+          return 0;
+     } else {
+          si.restoreModel(saveFile_.c_str());
+          remove(saveFile_.c_str());
+          return 1;
+     }
+}
+#endif
+// Return pointer to presolved model
+ClpSimplex *
+ClpPresolve::model() const
+{
+     return presolvedModel_;
+}
+// Return pointer to original model
+ClpSimplex *
+ClpPresolve::originalModel() const
+{
+     return originalModel_;
+}
+// Return presolve status (0,1,2)
+int 
+ClpPresolve::presolveStatus() const
+{
+  if (nelems_>=0) {
+    // feasible (or not done yet)
+    return 0;
+  } else {
+    int presolveStatus = - nelems_;
+    // If both infeasible and unbounded - say infeasible
+    if (presolveStatus>2)
+      presolveStatus = 1;
+    return presolveStatus;
+  }
+}
+void
+ClpPresolve::postsolve(bool updateStatus)
+{
+     // Return at once if no presolved model
+     if (!presolvedModel_)
+          return;
+     // Messages
+     CoinMessages messages = originalModel_->coinMessages();
+     if (!presolvedModel_->isProvenOptimal()) {
+          presolvedModel_->messageHandler()->message(COIN_PRESOLVE_NONOPTIMAL,
+                    messages)
+                    << CoinMessageEol;
+     }
+
+     // this is the size of the original problem
+     const int ncols0  = ncols_;
+     const int nrows0  = nrows_;
+     const CoinBigIndex nelems0 = nelems_;
+
+     // this is the reduced problem
+     int ncols = presolvedModel_->getNumCols();
+     int nrows = presolvedModel_->getNumRows();
+
+     double * acts = NULL;
+     double * sol = NULL;
+     unsigned char * rowstat = NULL;
+     unsigned char * colstat = NULL;
+#ifndef CLP_NO_STD
+     if (saveFile_ == "") {
+#endif
+          // reality check
+          assert(ncols0 == originalModel_->getNumCols());
+          assert(nrows0 == originalModel_->getNumRows());
+          acts = originalModel_->primalRowSolution();
+          sol  = originalModel_->primalColumnSolution();
+          if (updateStatus) {
+               // postsolve does not know about fixed
+               int i;
+               for (i = 0; i < nrows + ncols; i++) {
+                    if (presolvedModel_->getColumnStatus(i) == ClpSimplex::isFixed)
+                         presolvedModel_->setColumnStatus(i, ClpSimplex::atLowerBound);
+               }
+               unsigned char *status = originalModel_->statusArray();
+               if (!status) {
+                    originalModel_->createStatus();
+                    status = originalModel_->statusArray();
+               }
+               rowstat = status + ncols0;
+               colstat = status;
+               CoinMemcpyN( presolvedModel_->statusArray(), ncols, colstat);
+               CoinMemcpyN( presolvedModel_->statusArray() + ncols, nrows, rowstat);
+          }
+#ifndef CLP_NO_STD
+     } else {
+          // from file
+          acts = new double[nrows0];
+          sol  = new double[ncols0];
+          CoinZeroN(acts, nrows0);
+          CoinZeroN(sol, ncols0);
+          if (updateStatus) {
+               unsigned char *status = new unsigned char [nrows0+ncols0];
+               rowstat = status + ncols0;
+               colstat = status;
+               CoinMemcpyN( presolvedModel_->statusArray(), ncols, colstat);
+               CoinMemcpyN( presolvedModel_->statusArray() + ncols, nrows, rowstat);
+          }
+     }
+#endif
+
+     // CoinPostsolveMatrix object assumes ownership of sol, acts, colstat;
+     // will be deleted by ~CoinPostsolveMatrix. delete[] operations below
+     // cause duplicate free. In case where saveFile == "", as best I can see
+     // arrays are owned by originalModel_. fix is to
+     // clear fields in prob to avoid delete[] in ~CoinPostsolveMatrix.
+     CoinPostsolveMatrix prob(presolvedModel_,
+                              ncols0,
+                              nrows0,
+                              nelems0,
+                              presolvedModel_->getObjSense(),
+                              // end prepost
+
+                              sol, acts,
+                              colstat, rowstat);
+
+     postsolve(prob);
+
+#ifndef CLP_NO_STD
+     if (saveFile_ != "") {
+          // From file
+          assert (originalModel_ == presolvedModel_);
+          originalModel_->restoreModel(saveFile_.c_str());
+          remove(saveFile_.c_str());
+          CoinMemcpyN(acts, nrows0, originalModel_->primalRowSolution());
+          // delete [] acts;
+          CoinMemcpyN(sol, ncols0, originalModel_->primalColumnSolution());
+          // delete [] sol;
+          if (updateStatus) {
+               CoinMemcpyN(colstat, nrows0 + ncols0, originalModel_->statusArray());
+               // delete [] colstat;
+          }
+     } else {
+#endif
+          prob.sol_ = 0 ;
+          prob.acts_ = 0 ;
+          prob.colstat_ = 0 ;
+#ifndef CLP_NO_STD
+     }
+#endif 
+     // put back duals
+     CoinMemcpyN(prob.rowduals_,	nrows_, originalModel_->dualRowSolution());
+     double maxmin = originalModel_->getObjSense();
+     if (maxmin < 0.0) {
+          // swap signs
+          int i;
+          double * pi = originalModel_->dualRowSolution();
+          for (i = 0; i < nrows_; i++)
+               pi[i] = -pi[i];
+     }
+     // Now check solution
+     double offset;
+     CoinMemcpyN(originalModel_->objectiveAsObject()->gradient(originalModel_,
+                 originalModel_->primalColumnSolution(), offset, true),
+                 ncols_, originalModel_->dualColumnSolution());
+     originalModel_->clpMatrix()->transposeTimes(-1.0,
+                                    originalModel_->dualRowSolution(),
+                                    originalModel_->dualColumnSolution());
+     memset(originalModel_->primalRowSolution(), 0, nrows_ * sizeof(double));
+     originalModel_->clpMatrix()->times(1.0, 
+					originalModel_->primalColumnSolution(),
+					originalModel_->primalRowSolution());
+     originalModel_->checkSolutionInternal();
+     if (originalModel_->sumDualInfeasibilities() > 1.0e-1) {
+          // See if we can fix easily
+          static_cast<ClpSimplexOther *> (originalModel_)->cleanupAfterPostsolve();
+     }
+     // Messages
+     presolvedModel_->messageHandler()->message(COIN_PRESOLVE_POSTSOLVE,
+               messages)
+               << originalModel_->objectiveValue()
+               << originalModel_->sumDualInfeasibilities()
+               << originalModel_->numberDualInfeasibilities()
+               << originalModel_->sumPrimalInfeasibilities()
+               << originalModel_->numberPrimalInfeasibilities()
+               << CoinMessageEol;
+
+     //originalModel_->objectiveValue_=objectiveValue_;
+     originalModel_->setNumberIterations(presolvedModel_->numberIterations());
+     if (!presolvedModel_->status()) {
+          if (!originalModel_->numberDualInfeasibilities() &&
+                    !originalModel_->numberPrimalInfeasibilities()) {
+               originalModel_->setProblemStatus( 0);
+          } else {
+               originalModel_->setProblemStatus( -1);
+               // Say not optimal after presolve
+               originalModel_->setSecondaryStatus(7);
+               presolvedModel_->messageHandler()->message(COIN_PRESOLVE_NEEDS_CLEANING,
+                         messages)
+                         << CoinMessageEol;
+          }
+     } else {
+          originalModel_->setProblemStatus( presolvedModel_->status());
+	  // but not if close to feasible
+	  if( originalModel_->sumPrimalInfeasibilities()<1.0e-1) {
+               originalModel_->setProblemStatus( -1);
+               // Say not optimal after presolve
+               originalModel_->setSecondaryStatus(7);
+	  }
+     }
+#ifndef CLP_NO_STD
+     if (saveFile_ != "")
+          presolvedModel_ = NULL;
+#endif
+}
+
+// return pointer to original columns
+const int *
+ClpPresolve::originalColumns() const
+{
+     return originalColumn_;
+}
+// return pointer to original rows
+const int *
+ClpPresolve::originalRows() const
+{
+     return originalRow_;
+}
+// Set pointer to original model
+void
+ClpPresolve::setOriginalModel(ClpSimplex * model)
+{
+     originalModel_ = model;
+}
+#if 0
+// A lazy way to restrict which transformations are applied
+// during debugging.
+static int ATOI(const char *name)
+{
+     return true;
+#if	PRESOLVE_DEBUG || PRESOLVE_SUMMARY
+     if (getenv(name)) {
+          int val = atoi(getenv(name));
+          printf("%s = %d\n", name, val);
+          return (val);
+     } else {
+          if (strcmp(name, "off"))
+               return (true);
+          else
+               return (false);
+     }
+#else
+     return (true);
+#endif
+}
+#endif
+//#define PRESOLVE_DEBUG 1
+#if PRESOLVE_DEBUG
+void check_sol(CoinPresolveMatrix *prob, double tol)
+{
+     double *colels	= prob->colels_;
+     int *hrow		= prob->hrow_;
+     int *mcstrt		= prob->mcstrt_;
+     int *hincol		= prob->hincol_;
+     int *hinrow		= prob->hinrow_;
+     int ncols		= prob->ncols_;
+
+
+     double * csol = prob->sol_;
+     double * acts = prob->acts_;
+     double * clo = prob->clo_;
+     double * cup = prob->cup_;
+     int nrows = prob->nrows_;
+     double * rlo = prob->rlo_;
+     double * rup = prob->rup_;
+
+     int colx;
+
+     double * rsol = new double[nrows];
+     memset(rsol, 0, nrows * sizeof(double));
+
+     for (colx = 0; colx < ncols; ++colx) {
+          if (1) {
+               CoinBigIndex k = mcstrt[colx];
+               int nx = hincol[colx];
+               double solutionValue = csol[colx];
+               for (int i = 0; i < nx; ++i) {
+                    int row = hrow[k];
+                    double coeff = colels[k];
+                    k++;
+                    rsol[row] += solutionValue * coeff;
+               }
+               if (csol[colx] < clo[colx] - tol) {
+                    printf("low CSOL:  %d  - %g %g %g\n",
+                           colx, clo[colx], csol[colx], cup[colx]);
+               } else if (csol[colx] > cup[colx] + tol) {
+                    printf("high CSOL:  %d  - %g %g %g\n",
+                           colx, clo[colx], csol[colx], cup[colx]);
+               }
+          }
+     }
+     int rowx;
+     for (rowx = 0; rowx < nrows; ++rowx) {
+          if (hinrow[rowx]) {
+               if (fabs(rsol[rowx] - acts[rowx]) > tol)
+                    printf("inacc RSOL:  %d - %g %g (acts_ %g) %g\n",
+                           rowx,  rlo[rowx], rsol[rowx], acts[rowx], rup[rowx]);
+               if (rsol[rowx] < rlo[rowx] - tol) {
+                    printf("low RSOL:  %d - %g %g %g\n",
+                           rowx,  rlo[rowx], rsol[rowx], rup[rowx]);
+               } else if (rsol[rowx] > rup[rowx] + tol ) {
+                    printf("high RSOL:  %d - %g %g %g\n",
+                           rowx,  rlo[rowx], rsol[rowx], rup[rowx]);
+               }
+          }
+     }
+     delete [] rsol;
+}
+#endif
+static int tightenDoubletons2(CoinPresolveMatrix * prob)
+{
+  // column-major representation
+  const int ncols = prob->ncols_ ;
+  const CoinBigIndex *const mcstrt = prob->mcstrt_ ;
+  const int *const hincol = prob->hincol_ ;
+  const int *const hrow = prob->hrow_ ;
+  double * colels = prob->colels_ ;
+  double * cost = prob->cost_ ;
+
+  // column type, bounds, solution, and status
+  const unsigned char *const integerType = prob->integerType_ ;
+  double * clo = prob->clo_ ;
+  double * cup = prob->cup_ ;
+  // row-major representation
+  //const int nrows = prob->nrows_ ;
+  const CoinBigIndex *const mrstrt = prob->mrstrt_ ;
+  const int *const hinrow = prob->hinrow_ ;
+  const int *const hcol = prob->hcol_ ;
+  double * rowels = prob->rowels_ ;
+
+  // row bounds
+  double *const rlo = prob->rlo_ ;
+  double *const rup = prob->rup_ ;
+
+  // tolerances
+  //const double ekkinf2 = PRESOLVE_SMALL_INF ;
+  //const double ekkinf = ekkinf2*1.0e8 ;
+  //const double ztolcbarj = prob->ztoldj_ ;
+  //const CoinRelFltEq relEq(prob->ztolzb_) ;
+  int numberChanged=0;
+  double bound[2];
+  double alpha[2]={0.0,0.0};
+  double offset=0.0;
+
+  for (int icol=0;icol<ncols;icol++) {
+    if (hincol[icol]==2) {
+      CoinBigIndex start=mcstrt[icol];
+      int row0 = hrow[start];
+      if (hinrow[row0]!=2)
+	continue;
+      int row1 = hrow[start+1];
+      if (hinrow[row1]!=2)
+	continue;
+      double element0 = colels[start];
+      double rowUpper0=rup[row0];
+      bool swapSigns0=false;
+      if (rlo[row0]>-1.0e30) {
+	if (rup[row0]>1.0e30) {
+	  swapSigns0=true;
+	  rowUpper0=-rlo[row0];
+	  element0=-element0;
+	} else {
+	  // range or equality
+	  continue;
+	}
+      } else if (rup[row0]>1.0e30) {
+	// free
+	continue;
+      }
+#if 0
+      // skip here for speed
+      // skip if no cost (should be able to get rid of)
+      if (!cost[icol]) {
+	printf("should be able to get rid of %d with no cost\n",icol);
+	continue;
+      }
+      // skip if negative cost for now
+      if (cost[icol]<0.0) {
+	printf("code for negative cost\n");
+	continue;
+      }
+#endif
+      double element1 = colels[start+1];
+      double rowUpper1=rup[row1];
+      bool swapSigns1=false;
+      if (rlo[row1]>-1.0e30) {
+	if (rup[row1]>1.0e30) {
+	  swapSigns1=true;
+	  rowUpper1=-rlo[row1];
+	  element1=-element1;
+	} else {
+	  // range or equality
+	  continue;
+	}
+      } else if (rup[row1]>1.0e30) {
+	// free
+	continue;
+      }
+      double lowerX=clo[icol];
+      double upperX=cup[icol];
+      int otherCol=-1;
+      CoinBigIndex startRow=mrstrt[row0];
+      for (CoinBigIndex j=startRow;j<startRow+2;j++) {
+	int jcol=hcol[j];
+	if (jcol!=icol) {
+	  alpha[0]=swapSigns0 ? -rowels[j] :rowels[j];
+	  otherCol=jcol;
+	}
+      }
+      startRow=mrstrt[row1];
+      bool possible=true;
+      for (CoinBigIndex j=startRow;j<startRow+2;j++) {
+	int jcol=hcol[j];
+	if (jcol!=icol) {
+	  if (jcol==otherCol) {
+	    alpha[1]=swapSigns1 ? -rowels[j] :rowels[j];
+	  } else {
+	    possible=false;
+	  }
+	}
+      }
+      if (possible) {
+	// skip if no cost (should be able to get rid of)
+	if (!cost[icol]) {
+	  PRESOLVE_DETAIL_PRINT(printf("should be able to get rid of %d with no cost\n",icol));
+	  continue;
+	}
+	// skip if negative cost for now
+	if (cost[icol]<0.0) {
+	  PRESOLVE_DETAIL_PRINT(printf("code for negative cost\n"));
+	  continue;
+	}
+	bound[0]=clo[otherCol];
+	bound[1]=cup[otherCol];
+	double lowestLowest=COIN_DBL_MAX;
+	double highestLowest=-COIN_DBL_MAX;
+	double lowestHighest=COIN_DBL_MAX;
+	double highestHighest=-COIN_DBL_MAX;
+	int binding0=0;
+	int binding1=0;
+	for (int k=0;k<2;k++) {
+	  bool infLow0=false;
+	  bool infLow1=false;
+	  double sum0=0.0;
+	  double sum1=0.0;
+	  double value=bound[k];
+	  if (fabs(value)<1.0e30) {
+	    sum0+=alpha[0]*value;
+	    sum1+=alpha[1]*value;
+	  } else {
+	    if (alpha[0]>0.0) {
+	      if (value<0.0)
+		infLow0 =true;
+	    } else if (alpha[0]<0.0) {
+	      if (value>0.0)
+		infLow0 =true;
+	    }
+	    if (alpha[1]>0.0) {
+	      if (value<0.0)
+		infLow1 =true;
+	    } else if (alpha[1]<0.0) {
+	      if (value>0.0)
+		infLow1 =true;
+	    }
+	  }
+	  /* Got sums
+	   */
+	  double thisLowest0=-COIN_DBL_MAX;
+	  double thisHighest0=COIN_DBL_MAX;
+	  if (element0>0.0) {
+	    // upper bound unless inf&2 !=0
+	    if (!infLow0)
+	      thisHighest0 = (rowUpper0-sum0)/element0;
+	  } else {
+	    // lower bound unless inf&2 !=0
+	    if (!infLow0)
+	      thisLowest0 = (rowUpper0-sum0)/element0;
+	  }
+	  double thisLowest1=-COIN_DBL_MAX;
+	  double thisHighest1=COIN_DBL_MAX;
+	  if (element1>0.0) {
+	    // upper bound unless inf&2 !=0
+	    if (!infLow1)
+	      thisHighest1 = (rowUpper1-sum1)/element1;
+	  } else {
+	    // lower bound unless inf&2 !=0
+	    if (!infLow1)
+	      thisLowest1 = (rowUpper1-sum1)/element1;
+	  }
+	  if (thisLowest0>thisLowest1+1.0e-12) {
+	    if (thisLowest0>lowerX+1.0e-12)
+	      binding0|= 1<<k;
+	  } else if (thisLowest1>thisLowest0+1.0e-12) {
+	    if (thisLowest1>lowerX+1.0e-12)
+	      binding1|= 1<<k;
+	    thisLowest0=thisLowest1;
+	  }
+	  if (thisHighest0<thisHighest1-1.0e-12) {
+	    if (thisHighest0<upperX-1.0e-12)
+	      binding0|= 1<<k;
+	  } else if (thisHighest1<thisHighest0-1.0e-12) {
+	    if (thisHighest1<upperX-1.0e-12)
+	      binding1|= 1<<k;
+	    thisHighest0=thisHighest1;
+	  }
+	  lowestLowest=CoinMin(lowestLowest,thisLowest0);
+	  highestHighest=CoinMax(highestHighest,thisHighest0);
+	  lowestHighest=CoinMin(lowestHighest,thisHighest0);
+	  highestLowest=CoinMax(highestLowest,thisLowest0);
+	}
+	// see if any good
+	//#define PRINT_VALUES
+	if (!binding0||!binding1) {
+	  PRESOLVE_DETAIL_PRINT(printf("Row redundant for column %d\n",icol));
+	} else {
+#ifdef PRINT_VALUES
+	  printf("Column %d bounds %g,%g lowest %g,%g highest %g,%g\n",
+		 icol,lowerX,upperX,lowestLowest,lowestHighest,
+		 highestLowest,highestHighest);
+#endif
+	  // if integer adjust
+	  if (integerType[icol]) {
+	    lowestLowest=ceil(lowestLowest-1.0e-5);
+	    highestLowest=ceil(highestLowest-1.0e-5);
+	    lowestHighest=floor(lowestHighest+1.0e-5);
+	    highestHighest=floor(highestHighest+1.0e-5);
+	  }
+	  // if costed may be able to adjust
+	  if (cost[icol]>=0.0) {
+	    if (highestLowest<upperX&&highestLowest>=lowerX&&highestHighest<1.0e30) {
+	      highestHighest=CoinMin(highestHighest,highestLowest);
+	    }
+	  }
+	  if (cost[icol]<=0.0) {
+	    if (lowestHighest>lowerX&&lowestHighest<=upperX&&lowestHighest>-1.0e30) {
+	      lowestLowest=CoinMax(lowestLowest,lowestHighest);
+	    }
+	  }
+#if 1
+	  if (lowestLowest>lowerX+1.0e-8) {
+#ifdef PRINT_VALUES
+	    printf("Can increase lower bound on %d from %g to %g\n",
+		   icol,lowerX,lowestLowest);
+#endif
+	    lowerX=lowestLowest;
+	  }
+	  if (highestHighest<upperX-1.0e-8) {
+#ifdef PRINT_VALUES
+	    printf("Can decrease upper bound on %d from %g to %g\n",
+		   icol,upperX,highestHighest);
+#endif
+	    upperX=highestHighest;
+	    
+	  }
+#endif
+	  // see if we can move costs
+	  double xValue;
+	  double yValue0;
+	  double yValue1;
+	  double newLower=COIN_DBL_MAX;
+	  double newUpper=-COIN_DBL_MAX;
+#ifdef PRINT_VALUES
+	  double ranges0[2];
+	  double ranges1[2];
+#endif
+	  double costEqual;
+	  double slope[2];
+	  assert (binding0+binding1==3);
+	  // get where equal
+	  xValue=(rowUpper0*element1-rowUpper1*element0)/(alpha[0]*element1-alpha[1]*element0);
+	  yValue0=(rowUpper0-xValue*alpha[0])/element0;
+	  yValue1=(rowUpper1-xValue*alpha[1])/element1;
+	  newLower=CoinMin(newLower,CoinMax(yValue0,yValue1));
+	  newUpper=CoinMax(newUpper,CoinMax(yValue0,yValue1));
+	  double xValueEqual=xValue;
+	  double yValueEqual=yValue0;
+	  costEqual = xValue*cost[otherCol]+yValueEqual*cost[icol];
+	  if (binding0==1) {
+#ifdef PRINT_VALUES
+	    ranges0[0]=bound[0];
+	    ranges0[1]=yValue0;
+	    ranges1[0]=yValue0;
+	    ranges1[1]=bound[1];
+#endif
+	    // take x 1.0 down
+	    double x=xValue-1.0;
+	    double y=(rowUpper0-x*alpha[0])/element0;
+	    double costTotal = x*cost[otherCol]+y*cost[icol];
+	    slope[0] = costEqual-costTotal;
+	    // take x 1.0 up
+	    x=xValue+1.0;
+	    y=(rowUpper1-x*alpha[1])/element0;
+	    costTotal = x*cost[otherCol]+y*cost[icol];
+	    slope[1] = costTotal-costEqual;
+	  } else {
+#ifdef PRINT_VALUES
+	    ranges1[0]=bound[0];
+	    ranges1[1]=yValue0;
+	    ranges0[0]=yValue0;
+	    ranges0[1]=bound[1];
+#endif
+	    // take x 1.0 down
+	    double x=xValue-1.0;
+	    double y=(rowUpper1-x*alpha[1])/element0;
+	    double costTotal = x*cost[otherCol]+y*cost[icol];
+	    slope[1] = costEqual-costTotal;
+	    // take x 1.0 up
+	    x=xValue+1.0;
+	    y=(rowUpper0-x*alpha[0])/element0;
+	    costTotal = x*cost[otherCol]+y*cost[icol];
+	    slope[0] = costTotal-costEqual;
+	  }
+#ifdef PRINT_VALUES
+	  printf("equal value of %d is %g, value of %d is max(%g,%g) - %g\n",
+		 otherCol,xValue,icol,yValue0,yValue1,CoinMax(yValue0,yValue1));
+	  printf("Cost at equality %g for constraint 0 ranges %g -> %g slope %g for constraint 1 ranges %g -> %g slope %g\n",
+		 costEqual,ranges0[0],ranges0[1],slope[0],ranges1[0],ranges1[1],slope[1]);
+#endif
+	  xValue=bound[0];
+	  yValue0=(rowUpper0-xValue*alpha[0])/element0;
+	  yValue1=(rowUpper1-xValue*alpha[1])/element1;
+#ifdef PRINT_VALUES
+	  printf("value of %d is %g, value of %d is max(%g,%g) - %g\n",
+		 otherCol,xValue,icol,yValue0,yValue1,CoinMax(yValue0,yValue1));
+#endif
+	  newLower=CoinMin(newLower,CoinMax(yValue0,yValue1));
+	  // cost>0 so will be at lower
+	  //double yValueAtBound0=newLower;
+	  newUpper=CoinMax(newUpper,CoinMax(yValue0,yValue1));
+	  xValue=bound[1];
+	  yValue0=(rowUpper0-xValue*alpha[0])/element0;
+	  yValue1=(rowUpper1-xValue*alpha[1])/element1;
+#ifdef PRINT_VALUES
+	  printf("value of %d is %g, value of %d is max(%g,%g) - %g\n",
+		 otherCol,xValue,icol,yValue0,yValue1,CoinMax(yValue0,yValue1));
+#endif
+	  newLower=CoinMin(newLower,CoinMax(yValue0,yValue1));
+	  // cost>0 so will be at lower
+	  //double yValueAtBound1=newLower;
+	  newUpper=CoinMax(newUpper,CoinMax(yValue0,yValue1));
+	  lowerX=CoinMax(lowerX,newLower-1.0e-12*fabs(newLower));
+	  upperX=CoinMin(upperX,newUpper+1.0e-12*fabs(newUpper));
+	  // Now make duplicate row
+	  // keep row 0 so need to adjust costs so same
+#ifdef PRINT_VALUES
+	  printf("Costs for x %g,%g,%g are %g,%g,%g\n",
+		 xValueEqual-1.0,xValueEqual,xValueEqual+1.0,
+		 costEqual-slope[0],costEqual,costEqual+slope[1]);
+#endif
+	  double costOther=cost[otherCol]+slope[1];
+	  double costThis=cost[icol]+slope[1]*(element0/alpha[0]);
+	  xValue=xValueEqual;
+	  yValue0=CoinMax((rowUpper0-xValue*alpha[0])/element0,lowerX);
+	  double thisOffset=costEqual-(costOther*xValue+costThis*yValue0);
+	  offset += thisOffset;
+#ifdef PRINT_VALUES
+	  printf("new cost at equal %g\n",costOther*xValue+costThis*yValue0+thisOffset);
+#endif
+	  xValue=xValueEqual-1.0;
+	  yValue0=CoinMax((rowUpper0-xValue*alpha[0])/element0,lowerX);
+#ifdef PRINT_VALUES
+	  printf("new cost at -1 %g\n",costOther*xValue+costThis*yValue0+thisOffset);
+#endif
+	  assert(fabs((costOther*xValue+costThis*yValue0+thisOffset)-(costEqual-slope[0]))<1.0e-5);
+	  xValue=xValueEqual+1.0;
+	  yValue0=CoinMax((rowUpper0-xValue*alpha[0])/element0,lowerX);
+#ifdef PRINT_VALUES
+	  printf("new cost at +1 %g\n",costOther*xValue+costThis*yValue0+thisOffset);
+#endif
+	  assert(fabs((costOther*xValue+costThis*yValue0+thisOffset)-(costEqual+slope[1]))<1.0e-5);
+	  numberChanged++;
+	  //	  continue;
+	  cost[otherCol] = costOther;
+	  cost[icol] = costThis;
+	  clo[icol]=lowerX;
+	  cup[icol]=upperX;
+	  int startCol[2];
+	  int endCol[2];
+	  startCol[0]=mcstrt[icol];
+	  endCol[0]=startCol[0]+2;
+	  startCol[1]=mcstrt[otherCol];
+	  endCol[1]=startCol[1]+hincol[otherCol];
+	  double values[2]={0.0,0.0};
+	  for (int k=0;k<2;k++) {
+	    for (CoinBigIndex i=startCol[k];i<endCol[k];i++) {
+	      if (hrow[i]==row0)
+		values[k]=colels[i];
+	    }
+	    for (CoinBigIndex i=startCol[k];i<endCol[k];i++) {
+	      if (hrow[i]==row1)
+		colels[i]=values[k];
+	    }
+	  }
+	  for (CoinBigIndex i=mrstrt[row1];i<mrstrt[row1]+2;i++) {
+	    if (hcol[i]==icol)
+	      rowels[i]=values[0];
+	    else
+	      rowels[i]=values[1];
+	  }
+	}
+      }
+    }
+  }
+#if ABC_NORMAL_DEBUG>0
+  if (offset)
+    printf("Cost offset %g\n",offset);
+#endif
+  return numberChanged;
+}
+//#define COIN_PRESOLVE_BUG
+#ifdef COIN_PRESOLVE_BUG
+static int counter=1000000;
+static int startEmptyRows=0;
+static int startEmptyColumns=0;
+static bool break2(CoinPresolveMatrix *prob)
+{
+  int droppedRows = prob->countEmptyRows() - startEmptyRows ;
+  int droppedColumns =  prob->countEmptyCols() - startEmptyColumns;
+  startEmptyRows=prob->countEmptyRows();
+  startEmptyColumns=prob->countEmptyCols();
+  printf("Dropped %d rows and %d columns - current empty %d, %d\n",droppedRows,
+	 droppedColumns,startEmptyRows,startEmptyColumns);
+  counter--;
+  if (!counter) {
+    printf("skipping next and all\n");
+  }
+  return (counter<=0);
+}
+#define possibleBreak if (break2(prob)) break
+#define possibleSkip  if (!break2(prob)) 
+#else
+#define possibleBreak
+#define possibleSkip
+#endif
+#define SOME_PRESOLVE_DETAIL
+#ifndef SOME_PRESOLVE_DETAIL
+#define printProgress(x,y) {}
+#else
+#define printProgress(x,y) {if ((presolveActions_ & 0x80000000) != 0)	\
+      printf("%c loop %d %d empty rows, %d empty columns\n",x,y,prob->countEmptyRows(), \
+	   prob->countEmptyCols());}
+#endif
+// This is the presolve loop.
+// It is a separate virtual function so that it can be easily
+// customized by subclassing CoinPresolve.
+const CoinPresolveAction *ClpPresolve::presolve(CoinPresolveMatrix *prob)
+{
+     // Messages
+     CoinMessages messages = CoinMessage(prob->messages().language());
+     paction_ = 0;
+     prob->maxSubstLevel_ = 3 ;
+#ifndef PRESOLVE_DETAIL
+     if (prob->tuning_) {
+#endif
+       int numberEmptyRows=0;
+       for ( int i=0;i<prob->nrows_;i++) {
+	 if (!prob->hinrow_[i]) {
+	   PRESOLVE_DETAIL_PRINT(printf("pre_empty row %d\n",i));
+	   //printf("pre_empty row %d\n",i);
+	   numberEmptyRows++;
+	 }
+       }
+       int numberEmptyCols=0;
+       for ( int i=0;i<prob->ncols_;i++) {
+	 if (!prob->hincol_[i]) {
+	   PRESOLVE_DETAIL_PRINT(printf("pre_empty col %d\n",i));
+	   //printf("pre_empty col %d\n",i);
+	   numberEmptyCols++;
+	 }
+       }
+       printf("CoinPresolve initial state %d empty rows and %d empty columns\n",
+	      numberEmptyRows,numberEmptyCols);
+#ifndef PRESOLVE_DETAIL
+     }
+#endif
+     prob->status_ = 0; // say feasible
+     printProgress('A',0);
+     paction_ = make_fixed(prob, paction_);
+     paction_ = testRedundant(prob,paction_) ;
+     printProgress('B',0);
+     // if integers then switch off dual stuff
+     // later just do individually
+     bool doDualStuff = (presolvedModel_->integerInformation() == NULL);
+     // but allow in some cases
+     if ((presolveActions_ & 512) != 0)
+          doDualStuff = true;
+     if (prob->anyProhibited())
+          doDualStuff = false;
+     if (!doDual())
+          doDualStuff = false;
+#if	PRESOLVE_CONSISTENCY
+//  presolve_links_ok(prob->rlink_, prob->mrstrt_, prob->hinrow_, prob->nrows_);
+     presolve_links_ok(prob, false, true) ;
+#endif
+
+     if (!prob->status_) {
+          bool slackSingleton = doSingletonColumn();
+          slackSingleton = true;
+          const bool slackd = doSingleton();
+          const bool doubleton = doDoubleton();
+          const bool tripleton = doTripleton();
+          //#define NO_FORCING
+#ifndef NO_FORCING
+          const bool forcing = doForcing();
+#endif
+          const bool ifree = doImpliedFree();
+          const bool zerocost = doTighten();
+          const bool dupcol = doDupcol();
+          const bool duprow = doDuprow();
+          const bool dual = doDualStuff;
+
+          // some things are expensive so just do once (normally)
+
+          int i;
+          // say look at all
+          if (!prob->anyProhibited()) {
+               for (i = 0; i < nrows_; i++)
+                    prob->rowsToDo_[i] = i;
+               prob->numberRowsToDo_ = nrows_;
+               for (i = 0; i < ncols_; i++)
+                    prob->colsToDo_[i] = i;
+               prob->numberColsToDo_ = ncols_;
+          } else {
+               // some stuff must be left alone
+               prob->numberRowsToDo_ = 0;
+               for (i = 0; i < nrows_; i++)
+                    if (!prob->rowProhibited(i))
+                         prob->rowsToDo_[prob->numberRowsToDo_++] = i;
+               prob->numberColsToDo_ = 0;
+               for (i = 0; i < ncols_; i++)
+                    if (!prob->colProhibited(i))
+                         prob->colsToDo_[prob->numberColsToDo_++] = i;
+          }
+
+	    // transfer costs (may want to do it in OsiPresolve)
+	    // need a transfer back at end of postsolve transferCosts(prob);
+
+          int iLoop;
+#if	PRESOLVE_DEBUG
+          check_sol(prob, 1.0e0);
+#endif
+          if (dupcol) {
+               // maybe allow integer columns to be checked
+               if ((presolveActions_ & 512) != 0)
+                    prob->setPresolveOptions(prob->presolveOptions() | 1);
+	       possibleSkip;
+               paction_ = dupcol_action::presolve(prob, paction_);
+	       printProgress('C',0);
+          }
+#ifdef ABC_INHERIT
+          if (doTwoxTwo()) {
+	    possibleSkip;
+	    paction_ = twoxtwo_action::presolve(prob, paction_);
+          }
+#endif
+          if (duprow) {
+	    possibleSkip;
+	    if (doTwoxTwo()) {
+	      int nTightened=tightenDoubletons2(prob);
+	      if (nTightened)
+		PRESOLVE_DETAIL_PRINT(printf("%d doubletons tightened\n",
+					     nTightened));
+	    }
+	    paction_ = duprow_action::presolve(prob, paction_);
+	    printProgress('D',0);
+          }
+          if (doGubrow()) {
+	    possibleSkip;
+               paction_ = gubrow_action::presolve(prob, paction_);
+	       printProgress('E',0);
+          }
+
+          if ((presolveActions_ & 16384) != 0)
+               prob->setPresolveOptions(prob->presolveOptions() | 16384);
+	  // For inaccurate data in implied free
+          if ((presolveActions_ & 1024) != 0)
+               prob->setPresolveOptions(prob->presolveOptions() | 0x20000);
+          // Check number rows dropped
+          int lastDropped = 0;
+          prob->pass_ = 0;
+#ifdef ABC_INHERIT
+	  int numberRowsStart=nrows_-prob->countEmptyRows();
+	  int numberColumnsStart=ncols_-prob->countEmptyCols();
+	  int numberRowsLeft=numberRowsStart;
+	  int numberColumnsLeft=numberColumnsStart;
+	  bool lastPassWasGood=true;
+#if ABC_NORMAL_DEBUG
+	  printf("Original rows,columns %d,%d starting first pass with %d,%d\n", 
+		 nrows_,ncols_,numberRowsLeft,numberColumnsLeft);
+#endif
+#endif
+	  if (numberPasses_<=5)
+	      prob->presolveOptions_ |= 0x10000; // say more lightweight
+          for (iLoop = 0; iLoop < numberPasses_; iLoop++) {
+               // See if we want statistics
+               if ((presolveActions_ & 0x80000000) != 0)
+		 printf("Starting major pass %d after %g seconds with %d rows, %d columns\n", iLoop + 1, CoinCpuTime() - prob->startTime_,
+			nrows_-prob->countEmptyRows(),
+			ncols_-prob->countEmptyCols());
+#ifdef PRESOLVE_SUMMARY
+               printf("Starting major pass %d\n", iLoop + 1);
+#endif
+               const CoinPresolveAction * const paction0 = paction_;
+               // look for substitutions with no fill
+               //#define IMPLIED 3
+#ifdef IMPLIED
+               int fill_level = 3;
+#define IMPLIED2 99
+#if IMPLIED!=3
+#if IMPLIED>2&&IMPLIED<11
+               fill_level = IMPLIED;
+               COIN_DETAIL_PRINT(printf("** fill_level == %d !\n", fill_level));
+#endif
+#if IMPLIED>11&&IMPLIED<21
+               fill_level = -(IMPLIED - 10);
+               COIN_DETAIL_PRINT(printf("** fill_level == %d !\n", fill_level));
+#endif
+#endif
+#else
+               int fill_level = prob->maxSubstLevel_;
+#endif
+               int whichPass = 0;
+               while (1) {
+                    whichPass++;
+                    prob->pass_++;
+                    const CoinPresolveAction * const paction1 = paction_;
+
+                    if (slackd) {
+                         bool notFinished = true;
+                         while (notFinished) {
+			   possibleBreak;
+                              paction_ = slack_doubleton_action::presolve(prob, paction_,
+                                         notFinished);
+			 }
+			 printProgress('F',iLoop+1);
+                         if (prob->status_)
+                              break;
+                    }
+                    if (dual && whichPass == 1) {
+                         // this can also make E rows so do one bit here
+		      possibleBreak;
+                         paction_ = remove_dual_action::presolve(prob, paction_);
+                         if (prob->status_)
+                              break;
+			 printProgress('G',iLoop+1);
+                    }
+
+                    if (doubleton) {
+		      possibleBreak;
+                         paction_ = doubleton_action::presolve(prob, paction_);
+                         if (prob->status_)
+                              break;
+			 printProgress('H',iLoop+1);
+                    }
+                    if (tripleton) {
+		      possibleBreak;
+                         paction_ = tripleton_action::presolve(prob, paction_);
+                         if (prob->status_)
+                              break;
+			 printProgress('I',iLoop+1);
+                    }
+
+                    if (zerocost) {
+		      possibleBreak;
+                         paction_ = do_tighten_action::presolve(prob, paction_);
+                         if (prob->status_)
+                              break;
+			 printProgress('J',iLoop+1);
+                    }
+#ifndef NO_FORCING
+                    if (forcing) {
+		      possibleBreak;
+                         paction_ = forcing_constraint_action::presolve(prob, paction_);
+                         if (prob->status_)
+                              break;
+			 printProgress('K',iLoop+1);
+                    }
+#endif
+
+                    if (ifree && (whichPass % 5) == 1) {
+		      possibleBreak;
+                         paction_ = implied_free_action::presolve(prob, paction_, fill_level);
+                         if (prob->status_)
+                              break;
+			 printProgress('L',iLoop+1);
+                    }
+
+#if	PRESOLVE_DEBUG
+                    check_sol(prob, 1.0e0);
+#endif
+
+#if	PRESOLVE_CONSISTENCY
+//	presolve_links_ok(prob->rlink_, prob->mrstrt_, prob->hinrow_,
+//			  prob->nrows_);
+                    presolve_links_ok(prob, false, true) ;
+#endif
+
+//#if	PRESOLVE_DEBUG
+//	presolve_no_zeros(prob->mcstrt_, prob->colels_, prob->hincol_,
+//			  prob->ncols_);
+//#endif
+//#if	PRESOLVE_CONSISTENCY
+//	prob->consistent();
+//#endif
+#if	PRESOLVE_CONSISTENCY
+                    presolve_no_zeros(prob, true, false) ;
+                    presolve_consistent(prob, true) ;
+#endif
+
+		    {
+		      // set up for next pass
+		      // later do faster if many changes i.e. memset and memcpy
+		      const int * count = prob->hinrow_;
+		      const int * nextToDo = prob->nextRowsToDo_;
+		      int * toDo = prob->rowsToDo_;
+		      int nNext = prob->numberNextRowsToDo_;
+		      int n = 0;
+		      for (int i = 0; i < nNext; i++) {
+			int index = nextToDo[i];
+			prob->unsetRowChanged(index);
+			if (count[index]) 
+			  toDo[n++] = index;
+		      }
+		      prob->numberRowsToDo_ = n;
+		      prob->numberNextRowsToDo_ = 0;
+		      count = prob->hincol_;
+		      nextToDo = prob->nextColsToDo_;
+		      toDo = prob->colsToDo_;
+		      nNext = prob->numberNextColsToDo_;
+		      n = 0;
+		      for (int i = 0; i < nNext; i++) {
+			int index = nextToDo[i];
+			prob->unsetColChanged(index);
+			if (count[index]) 
+			  toDo[n++] = index;
+		      }
+		      prob->numberColsToDo_ = n;
+		      prob->numberNextColsToDo_ = 0;
+		    }
+                    if (paction_ == paction1 && fill_level > 0)
+                         break;
+               }
+               // say look at all
+               int i;
+               if (!prob->anyProhibited()) {
+		 const int * count = prob->hinrow_;
+		 int * toDo = prob->rowsToDo_;
+		 int n = 0;
+		 for (int i = 0; i < nrows_; i++) {
+		   prob->unsetRowChanged(i);
+		   if (count[i]) 
+		     toDo[n++] = i;
+		 }
+		 prob->numberRowsToDo_ = n;
+		 prob->numberNextRowsToDo_ = 0;
+		 count = prob->hincol_;
+		 toDo = prob->colsToDo_;
+		 n = 0;
+		 for (int i = 0; i < ncols_; i++) {
+		   prob->unsetColChanged(i);
+		   if (count[i]) 
+		     toDo[n++] = i;
+		 }
+		 prob->numberColsToDo_ = n;
+		 prob->numberNextColsToDo_ = 0;
+               } else {
+                    // some stuff must be left alone
+                    prob->numberRowsToDo_ = 0;
+                    for (i = 0; i < nrows_; i++)
+                         if (!prob->rowProhibited(i))
+                              prob->rowsToDo_[prob->numberRowsToDo_++] = i;
+                    prob->numberColsToDo_ = 0;
+                    for (i = 0; i < ncols_; i++)
+                         if (!prob->colProhibited(i))
+                              prob->colsToDo_[prob->numberColsToDo_++] = i;
+               }
+               // now expensive things
+               // this caused world.mps to run into numerical difficulties
+#ifdef PRESOLVE_SUMMARY
+               printf("Starting expensive\n");
+#endif
+
+               if (dual) {
+                    int itry;
+                    for (itry = 0; itry < 5; itry++) {
+		      possibleBreak;
+                         paction_ = remove_dual_action::presolve(prob, paction_);
+                         if (prob->status_)
+                              break;
+			 printProgress('M',iLoop+1);
+                         const CoinPresolveAction * const paction2 = paction_;
+                         if (ifree) {
+#ifdef IMPLIED
+#if IMPLIED2 ==0
+                              int fill_level = 0; // switches off substitution
+#elif IMPLIED2!=99
+                              int fill_level = IMPLIED2;
+#endif
+#endif
+                              if ((itry & 1) == 0) {
+				possibleBreak;
+                                   paction_ = implied_free_action::presolve(prob, paction_, fill_level);
+			      }
+                              if (prob->status_)
+                                   break;
+			      printProgress('N',iLoop+1);
+                         }
+                         if (paction_ == paction2)
+                              break;
+                    }
+               } else if (ifree) {
+                    // just free
+#ifdef IMPLIED
+#if IMPLIED2 ==0
+                    int fill_level = 0; // switches off substitution
+#elif IMPLIED2!=99
+                    int fill_level = IMPLIED2;
+#endif
+#endif
+		    possibleBreak;
+                    paction_ = implied_free_action::presolve(prob, paction_, fill_level);
+                    if (prob->status_)
+                         break;
+		    printProgress('O',iLoop+1);
+               }
+#if	PRESOLVE_DEBUG
+               check_sol(prob, 1.0e0);
+#endif
+               if (dupcol) {
+                    // maybe allow integer columns to be checked
+                    if ((presolveActions_ & 512) != 0)
+                         prob->setPresolveOptions(prob->presolveOptions() | 1);
+		    possibleBreak;
+                    paction_ = dupcol_action::presolve(prob, paction_);
+                    if (prob->status_)
+                         break;
+		    printProgress('P',iLoop+1);
+               }
+#if	PRESOLVE_DEBUG
+               check_sol(prob, 1.0e0);
+#endif
+
+               if (duprow) {
+		 possibleBreak;
+                    paction_ = duprow_action::presolve(prob, paction_);
+                    if (prob->status_)
+                         break;
+		    printProgress('Q',iLoop+1);
+               }
+	       // Marginally slower on netlib if this call is enabled.
+	       // paction_ = testRedundant(prob,paction_) ;
+#if	PRESOLVE_DEBUG
+               check_sol(prob, 1.0e0);
+#endif
+               bool stopLoop = false;
+               {
+                    int * hinrow = prob->hinrow_;
+                    int numberDropped = 0;
+                    for (i = 0; i < nrows_; i++)
+                         if (!hinrow[i])
+                              numberDropped++;
+
+                    prob->messageHandler()->message(COIN_PRESOLVE_PASS,
+                                                    messages)
+                              << numberDropped << iLoop + 1
+                              << CoinMessageEol;
+                    //printf("%d rows dropped after pass %d\n",numberDropped,
+                    //     iLoop+1);
+                    if (numberDropped == lastDropped)
+                         stopLoop = true;
+                    else
+                         lastDropped = numberDropped;
+               }
+               // Do this here as not very loopy
+               if (slackSingleton) {
+                    // On most passes do not touch costed slacks
+                    if (paction_ != paction0 && !stopLoop) {
+		      possibleBreak;
+                         paction_ = slack_singleton_action::presolve(prob, paction_, NULL);
+                    } else {
+                         // do costed if Clp (at end as ruins rest of presolve)
+		      possibleBreak;
+                         paction_ = slack_singleton_action::presolve(prob, paction_, rowObjective_);
+                         stopLoop = true;
+                    }
+		    printProgress('R',iLoop+1);
+               }
+#if	PRESOLVE_DEBUG
+               check_sol(prob, 1.0e0);
+#endif
+               if (paction_ == paction0 || stopLoop)
+                    break;
+#ifdef ABC_INHERIT
+	       // see whether to stop anyway
+	       int numberRowsNow=nrows_-prob->countEmptyRows();
+	       int numberColumnsNow=ncols_-prob->countEmptyCols();
+#if ABC_NORMAL_DEBUG
+	       printf("Original rows,columns %d,%d - last %d,%d end of pass %d has %d,%d\n", 
+		      nrows_,ncols_,numberRowsLeft,numberColumnsLeft,iLoop+1,numberRowsNow,
+		      numberColumnsNow);
+#endif
+	       int rowsDeleted=numberRowsLeft-numberRowsNow;
+	       int columnsDeleted=numberColumnsLeft-numberColumnsNow;
+ 	       if (iLoop>15) {
+		 if (rowsDeleted*100<numberRowsStart&&
+		     columnsDeleted*100<numberColumnsStart)
+		   break;
+		 lastPassWasGood=true;
+	       } else if (rowsDeleted*100<numberRowsStart&&rowsDeleted<500&&
+			  columnsDeleted*100<numberColumnsStart&&columnsDeleted<500) {
+		 if (!lastPassWasGood)
+		   break;
+		 else
+		   lastPassWasGood=false;
+	       } else {
+		 lastPassWasGood=true;
+	       }
+	       numberRowsLeft=numberRowsNow;
+	       numberColumnsLeft=numberColumnsNow;
+#endif
+          }
+     }
+     prob->presolveOptions_ &= ~0x10000;
+     if (!prob->status_) {
+          paction_ = drop_zero_coefficients(prob, paction_);
+#if	PRESOLVE_DEBUG
+          check_sol(prob, 1.0e0);
+#endif
+
+          paction_ = drop_empty_cols_action::presolve(prob, paction_);
+          paction_ = drop_empty_rows_action::presolve(prob, paction_);
+#if	PRESOLVE_DEBUG
+          check_sol(prob, 1.0e0);
+#endif
+     }
+
+     if (prob->status_) {
+          if (prob->status_ == 1)
+               prob->messageHandler()->message(COIN_PRESOLVE_INFEAS,
+                                               messages)
+                         << prob->feasibilityTolerance_
+                         << CoinMessageEol;
+          else if (prob->status_ == 2)
+               prob->messageHandler()->message(COIN_PRESOLVE_UNBOUND,
+                                               messages)
+                         << CoinMessageEol;
+          else
+               prob->messageHandler()->message(COIN_PRESOLVE_INFEASUNBOUND,
+                                               messages)
+                         << CoinMessageEol;
+          // get rid of data
+          destroyPresolve();
+     }
+     return (paction_);
+}
+
+void check_djs(CoinPostsolveMatrix *prob);
+
+
+// We could have implemented this by having each postsolve routine
+// directly call the next one, but this may make it easier to add debugging checks.
+void ClpPresolve::postsolve(CoinPostsolveMatrix &prob)
+{
+     {
+          // Check activities
+          double *colels	= prob.colels_;
+          int *hrow		= prob.hrow_;
+          CoinBigIndex *mcstrt		= prob.mcstrt_;
+          int *hincol		= prob.hincol_;
+          int *link		= prob.link_;
+          int ncols		= prob.ncols_;
+
+          char *cdone	= prob.cdone_;
+
+          double * csol = prob.sol_;
+          int nrows = prob.nrows_;
+
+          int colx;
+
+          double * rsol = prob.acts_;
+          memset(rsol, 0, nrows * sizeof(double));
+
+          for (colx = 0; colx < ncols; ++colx) {
+               if (cdone[colx]) {
+                    CoinBigIndex k = mcstrt[colx];
+                    int nx = hincol[colx];
+                    double solutionValue = csol[colx];
+                    for (int i = 0; i < nx; ++i) {
+                         int row = hrow[k];
+                         double coeff = colels[k];
+                         k = link[k];
+                         rsol[row] += solutionValue * coeff;
+                    }
+               }
+          }
+     }
+     if (prob.maxmin_<0) {
+       //for (int i=0;i<presolvedModel_->numberRows();i++)
+       //prob.rowduals_[i]=-prob.rowduals_[i];
+       for (int i=0;i<ncols_;i++) {
+	 prob.cost_[i]=-prob.cost_[i];
+	 //prob.rcosts_[i]=-prob.rcosts_[i];
+       }
+       prob.maxmin_=1.0;
+     }
+     const CoinPresolveAction *paction = paction_;
+     //#define PRESOLVE_DEBUG 1
+#if	PRESOLVE_DEBUG
+     // Check only works after first one
+     int checkit = -1;
+#endif
+
+     while (paction) {
+#if PRESOLVE_DEBUG
+          printf("POSTSOLVING %s\n", paction->name());
+#endif
+
+          paction->postsolve(&prob);
+
+#if	PRESOLVE_DEBUG
+#         if 0
+          /*
+	    This check fails (on exmip1 (!) in osiUnitTest) because clp
+	    enters postsolve with a solution that seems to have incorrect
+	    status for a logical. You can see similar behaviour with
+	    column status --- incorrect entering postsolve.
+	    -- lh, 111207 --
+	  */
+          {
+               int nr = 0;
+               int i;
+               for (i = 0; i < prob.nrows_; i++) {
+                    if ((prob.rowstat_[i] & 7) == 1) {
+                         nr++;
+                    } else if ((prob.rowstat_[i] & 7) == 2) {
+                         // at ub
+                         assert (prob.acts_[i] > prob.rup_[i] - 1.0e-6);
+                    } else if ((prob.rowstat_[i] & 7) == 3) {
+                         // at lb
+                         assert (prob.acts_[i] < prob.rlo_[i] + 1.0e-6);
+                    }
+               }
+               int nc = 0;
+               for (i = 0; i < prob.ncols_; i++) {
+                    if ((prob.colstat_[i] & 7) == 1)
+                         nc++;
+               }
+               printf("%d rows (%d basic), %d cols (%d basic)\n", prob.nrows_, nr, prob.ncols_, nc);
+          }
+#         endif   // if 0
+          checkit++;
+          if (prob.colstat_ && checkit > 0) {
+               presolve_check_nbasic(&prob) ;
+               presolve_check_sol(&prob, 2, 2, 1) ;
+          }
+#endif
+          paction = paction->next;
+#if	PRESOLVE_DEBUG
+//  check_djs(&prob);
+          if (checkit > 0)
+               presolve_check_reduced_costs(&prob) ;
+#endif
+     }
+#if	PRESOLVE_DEBUG
+     if (prob.colstat_) {
+          presolve_check_nbasic(&prob) ;
+          presolve_check_sol(&prob, 2, 2, 1) ;
+     }
+#endif
+#undef PRESOLVE_DEBUG
+
+#if	0 && PRESOLVE_DEBUG
+     for (i = 0; i < ncols0; i++) {
+          if (!cdone[i]) {
+               printf("!cdone[%d]\n", i);
+               abort();
+          }
+     }
+
+     for (i = 0; i < nrows0; i++) {
+          if (!rdone[i]) {
+               printf("!rdone[%d]\n", i);
+               abort();
+          }
+     }
+
+
+     for (i = 0; i < ncols0; i++) {
+          if (sol[i] < -1e10 || sol[i] > 1e10)
+               printf("!!!%d %g\n", i, sol[i]);
+
+     }
+
+
+#endif
+
+#if	0 && PRESOLVE_DEBUG
+     // debug check:  make sure we ended up with same original matrix
+     {
+          int identical = 1;
+
+          for (int i = 0; i < ncols0; i++) {
+               PRESOLVEASSERT(hincol[i] == &prob->mcstrt0[i+1] - &prob->mcstrt0[i]);
+               CoinBigIndex kcs0 = &prob->mcstrt0[i];
+               CoinBigIndex kcs = mcstrt[i];
+               int n = hincol[i];
+               for (int k = 0; k < n; k++) {
+                    CoinBigIndex k1 = presolve_find_row1(&prob->hrow0[kcs0+k], kcs, kcs + n, hrow);
+
+                    if (k1 == kcs + n) {
+                         printf("ROW %d NOT IN COL %d\n", &prob->hrow0[kcs0+k], i);
+                         abort();
+                    }
+
+                    if (colels[k1] != &prob->dels0[kcs0+k])
+                         printf("BAD COLEL[%d %d %d]:  %g\n",
+                                k1, i, &prob->hrow0[kcs0+k], colels[k1] - &prob->dels0[kcs0+k]);
+
+                    if (kcs0 + k != k1)
+                         identical = 0;
+               }
+          }
+          printf("identical? %d\n", identical);
+     }
+#endif
+}
+
+
+
+
+
+
+
+
+static inline double getTolerance(const ClpSimplex  *si, ClpDblParam key)
+{
+     double tol;
+     if (! si->getDblParam(key, tol)) {
+          CoinPresolveAction::throwCoinError("getDblParam failed",
+                                             "CoinPrePostsolveMatrix::CoinPrePostsolveMatrix");
+     }
+     return (tol);
+}
+
+
+// Assumptions:
+// 1. nrows>=m.getNumRows()
+// 2. ncols>=m.getNumCols()
+//
+// In presolve, these values are equal.
+// In postsolve, they may be inequal, since the reduced problem
+// may be smaller, but we need room for the large problem.
+// ncols may be larger than si.getNumCols() in postsolve,
+// this at that point si will be the reduced problem,
+// but we need to reserve enough space for the original problem.
+CoinPrePostsolveMatrix::CoinPrePostsolveMatrix(const ClpSimplex * si,
+          int ncols_in,
+          int nrows_in,
+          CoinBigIndex nelems_in,
+          double bulkRatio)
+     : ncols_(si->getNumCols()),
+       nrows_(si->getNumRows()),
+       nelems_(si->getNumElements()),
+       ncols0_(ncols_in),
+       nrows0_(nrows_in),
+       bulkRatio_(bulkRatio),
+       mcstrt_(new CoinBigIndex[ncols_in+1]),
+       hincol_(new int[ncols_in+1]),
+       cost_(new double[ncols_in]),
+       clo_(new double[ncols_in]),
+       cup_(new double[ncols_in]),
+       rlo_(new double[nrows_in]),
+       rup_(new double[nrows_in]),
+       originalColumn_(new int[ncols_in]),
+       originalRow_(new int[nrows_in]),
+       ztolzb_(getTolerance(si, ClpPrimalTolerance)),
+       ztoldj_(getTolerance(si, ClpDualTolerance)),
+       maxmin_(si->getObjSense()),
+       sol_(NULL),
+       rowduals_(NULL),
+       acts_(NULL),
+       rcosts_(NULL),
+       colstat_(NULL),
+       rowstat_(NULL),
+       handler_(NULL),
+       defaultHandler_(false),
+       messages_()
+
+{
+     bulk0_ = static_cast<CoinBigIndex> (bulkRatio_ * nelems_in);
+     hrow_  = new int   [bulk0_];
+     colels_ = new double[bulk0_];
+     si->getDblParam(ClpObjOffset, originalOffset_);
+     int ncols = si->getNumCols();
+     int nrows = si->getNumRows();
+
+     setMessageHandler(si->messageHandler()) ;
+
+     ClpDisjointCopyN(si->getColLower(), ncols, clo_);
+     ClpDisjointCopyN(si->getColUpper(), ncols, cup_);
+     //ClpDisjointCopyN(si->getObjCoefficients(), ncols, cost_);
+     double offset;
+     ClpDisjointCopyN(si->objectiveAsObject()->gradient(si, si->getColSolution(), offset, true), ncols, cost_);
+     ClpDisjointCopyN(si->getRowLower(), nrows,  rlo_);
+     ClpDisjointCopyN(si->getRowUpper(), nrows,  rup_);
+     int i;
+     for (i = 0; i < ncols_in; i++)
+          originalColumn_[i] = i;
+     for (i = 0; i < nrows_in; i++)
+          originalRow_[i] = i;
+     sol_ = NULL;
+     rowduals_ = NULL;
+     acts_ = NULL;
+
+     rcosts_ = NULL;
+     colstat_ = NULL;
+     rowstat_ = NULL;
+}
+
+// I am not familiar enough with CoinPackedMatrix to be confident
+// that I will implement a row-ordered version of toColumnOrderedGapFree
+// properly.
+static bool isGapFree(const CoinPackedMatrix& matrix)
+{
+     const CoinBigIndex * start = matrix.getVectorStarts();
+     const int * length = matrix.getVectorLengths();
+     int i = matrix.getSizeVectorLengths() - 1;
+     // Quick check
+     if (matrix.getNumElements() == start[i]) {
+          return true;
+     } else {
+          for (i = matrix.getSizeVectorLengths() - 1; i >= 0; --i) {
+               if (start[i+1] - start[i] != length[i])
+                    break;
+          }
+          return (! (i >= 0));
+     }
+}
+#if	PRESOLVE_DEBUG
+static void matrix_bounds_ok(const double *lo, const double *up, int n)
+{
+     int i;
+     for (i = 0; i < n; i++) {
+          PRESOLVEASSERT(lo[i] <= up[i]);
+          PRESOLVEASSERT(lo[i] < PRESOLVE_INF);
+          PRESOLVEASSERT(-PRESOLVE_INF < up[i]);
+     }
+}
+#endif
+CoinPresolveMatrix::CoinPresolveMatrix(int ncols0_in,
+                                       double /*maxmin*/,
+                                       // end prepost members
+
+                                       ClpSimplex * si,
+
+                                       // rowrep
+                                       int nrows_in,
+                                       CoinBigIndex nelems_in,
+                                       bool doStatus,
+                                       double nonLinearValue,
+                                       double bulkRatio) :
+
+     CoinPrePostsolveMatrix(si,
+                            ncols0_in, nrows_in, nelems_in, bulkRatio),
+     clink_(new presolvehlink[ncols0_in+1]),
+     rlink_(new presolvehlink[nrows_in+1]),
+
+     dobias_(0.0),
+
+
+     // temporary init
+     integerType_(new unsigned char[ncols0_in]),
+     tuning_(false),
+     startTime_(0.0),
+     feasibilityTolerance_(0.0),
+     status_(-1),
+     colsToDo_(new int [ncols0_in]),
+     numberColsToDo_(0),
+     nextColsToDo_(new int[ncols0_in]),
+     numberNextColsToDo_(0),
+     rowsToDo_(new int [nrows_in]),
+     numberRowsToDo_(0),
+     nextRowsToDo_(new int[nrows_in]),
+     numberNextRowsToDo_(0),
+     presolveOptions_(0)
+{
+     const int bufsize = bulk0_;
+
+     nrows_ = si->getNumRows() ;
+
+     // Set up change bits etc
+     rowChanged_ = new unsigned char[nrows_];
+     memset(rowChanged_, 0, nrows_);
+     colChanged_ = new unsigned char[ncols_];
+     memset(colChanged_, 0, ncols_);
+     CoinPackedMatrix * m = si->matrix();
+
+     // The coefficient matrix is a big hunk of stuff.
+     // Do the copy here to try to avoid running out of memory.
+
+     const CoinBigIndex * start = m->getVectorStarts();
+     const int * row = m->getIndices();
+     const double * element = m->getElements();
+     int icol, nel = 0;
+     mcstrt_[0] = 0;
+     ClpDisjointCopyN(m->getVectorLengths(), ncols_,  hincol_);
+     if (si->getObjSense() < 0.0) {
+       for (int i=0;i<ncols_;i++)
+	 cost_[i]=-cost_[i];
+       maxmin_=1.0;
+     }
+     for (icol = 0; icol < ncols_; icol++) {
+          CoinBigIndex j;
+          for (j = start[icol]; j < start[icol] + hincol_[icol]; j++) {
+               hrow_[nel] = row[j];
+               if (fabs(element[j]) > ZTOLDP)
+                    colels_[nel++] = element[j];
+          }
+          mcstrt_[icol+1] = nel;
+          hincol_[icol] = nel - mcstrt_[icol];
+     }
+
+     // same thing for row rep
+     CoinPackedMatrix * mRow = new CoinPackedMatrix();
+     mRow->setExtraGap(0.0);
+     mRow->setExtraMajor(0.0);
+     mRow->reverseOrderedCopyOf(*m);
+     //mRow->removeGaps();
+     //mRow->setExtraGap(0.0);
+
+     // Now get rid of matrix
+     si->createEmptyMatrix();
+
+     double * el = mRow->getMutableElements();
+     int * ind = mRow->getMutableIndices();
+     CoinBigIndex * strt = mRow->getMutableVectorStarts();
+     int * len = mRow->getMutableVectorLengths();
+     // Do carefully to save memory
+     rowels_ = new double[bulk0_];
+     ClpDisjointCopyN(el,      nelems_, rowels_);
+     mRow->nullElementArray();
+     delete [] el;
+     hcol_ = new int[bulk0_];
+     ClpDisjointCopyN(ind,       nelems_, hcol_);
+     mRow->nullIndexArray();
+     delete [] ind;
+     mrstrt_ = new CoinBigIndex[nrows_in+1];
+     ClpDisjointCopyN(strt,  nrows_,  mrstrt_);
+     mRow->nullStartArray();
+     mrstrt_[nrows_] = nelems_;
+     delete [] strt;
+     hinrow_ = new int[nrows_in+1];
+     ClpDisjointCopyN(len, nrows_,  hinrow_);
+     if (nelems_ > nel) {
+          nelems_ = nel;
+          // Clean any small elements
+          int irow;
+          nel = 0;
+          CoinBigIndex start = 0;
+          for (irow = 0; irow < nrows_; irow++) {
+               CoinBigIndex j;
+               for (j = start; j < start + hinrow_[irow]; j++) {
+                    hcol_[nel] = hcol_[j];
+                    if (fabs(rowels_[j]) > ZTOLDP)
+                         rowels_[nel++] = rowels_[j];
+               }
+               start = mrstrt_[irow+1];
+               mrstrt_[irow+1] = nel;
+               hinrow_[irow] = nel - mrstrt_[irow];
+          }
+     }
+
+     delete mRow;
+     if (si->integerInformation()) {
+          CoinMemcpyN(reinterpret_cast<unsigned char *> (si->integerInformation()), ncols_, integerType_);
+     } else {
+          ClpFillN<unsigned char>(integerType_, ncols_, static_cast<unsigned char> (0));
+     }
+
+#ifndef SLIM_CLP
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(si->objectiveAsObject()));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (si->objectiveAsObject()->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(si->objectiveAsObject()));
+#endif
+#endif
+     // Set up prohibited bits if needed
+     if (nonLinearValue) {
+          anyProhibited_ = true;
+          for (icol = 0; icol < ncols_; icol++) {
+               int j;
+               bool nonLinearColumn = false;
+               if (cost_[icol] == nonLinearValue)
+                    nonLinearColumn = true;
+               for (j = mcstrt_[icol]; j < mcstrt_[icol+1]; j++) {
+                    if (colels_[j] == nonLinearValue) {
+                         nonLinearColumn = true;
+                         setRowProhibited(hrow_[j]);
+                    }
+               }
+               if (nonLinearColumn)
+                    setColProhibited(icol);
+          }
+#ifndef SLIM_CLP
+     } else if (quadraticObj) {
+          CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+          //const int * columnQuadratic = quadratic->getIndices();
+          //const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+          const int * columnQuadraticLength = quadratic->getVectorLengths();
+          //double * quadraticElement = quadratic->getMutableElements();
+          int numberColumns = quadratic->getNumCols();
+          anyProhibited_ = true;
+          for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+               if (columnQuadraticLength[iColumn]) {
+                    setColProhibited(iColumn);
+                    //printf("%d prohib\n",iColumn);
+               }
+          }
+#endif
+     } else {
+          anyProhibited_ = false;
+     }
+
+     if (doStatus) {
+          // allow for status and solution
+          sol_ = new double[ncols_];
+          CoinMemcpyN(si->primalColumnSolution(), ncols_, sol_);;
+          acts_ = new double [nrows_];
+          CoinMemcpyN(si->primalRowSolution(), nrows_, acts_);
+          if (!si->statusArray())
+               si->createStatus();
+          colstat_ = new unsigned char [nrows_+ncols_];
+          CoinMemcpyN(si->statusArray(),	(nrows_ + ncols_), colstat_);
+          rowstat_ = colstat_ + ncols_;
+     }
+
+     // the original model's fields are now unneeded - free them
+
+     si->resize(0, 0);
+
+#if	PRESOLVE_DEBUG
+     matrix_bounds_ok(rlo_, rup_, nrows_);
+     matrix_bounds_ok(clo_, cup_, ncols_);
+#endif
+
+#if 0
+     for (i = 0; i < nrows; ++i)
+          printf("NR: %6d\n", hinrow[i]);
+     for (int i = 0; i < ncols; ++i)
+          printf("NC: %6d\n", hincol[i]);
+#endif
+
+     presolve_make_memlists(/*mcstrt_,*/ hincol_, clink_, ncols_);
+     presolve_make_memlists(/*mrstrt_,*/ hinrow_, rlink_, nrows_);
+
+     // this allows last col/row to expand up to bufsize-1 (22);
+     // this must come after the calls to presolve_prefix
+     mcstrt_[ncols_] = bufsize - 1;
+     mrstrt_[nrows_] = bufsize - 1;
+     // Allocate useful arrays
+     initializeStuff();
+
+#if	PRESOLVE_CONSISTENCY
+//consistent(false);
+     presolve_consistent(this, false) ;
+#endif
+}
+
+// avoid compiler warnings
+#if PRESOLVE_SUMMARY > 0
+void CoinPresolveMatrix::update_model(ClpSimplex * si,
+                                      int nrows0, int ncols0,
+                                      CoinBigIndex nelems0)
+#else
+void CoinPresolveMatrix::update_model(ClpSimplex * si,
+                                      int /*nrows0*/,
+                                      int /*ncols0*/,
+                                      CoinBigIndex /*nelems0*/)
+#endif
+{
+     if (si->getObjSense() < 0.0) {
+       for (int i=0;i<ncols_;i++)
+	 cost_[i]=-cost_[i];
+       dobias_=-dobias_;
+     }
+     si->loadProblem(ncols_, nrows_, mcstrt_, hrow_, colels_, hincol_,
+                     clo_, cup_, cost_, rlo_, rup_);
+     //delete [] si->integerInformation();
+     int numberIntegers = 0;
+     for (int i = 0; i < ncols_; i++) {
+          if (integerType_[i])
+               numberIntegers++;
+     }
+     if (numberIntegers)
+          si->copyInIntegerInformation(reinterpret_cast<const char *> (integerType_));
+     else
+          si->copyInIntegerInformation(NULL);
+
+#if	PRESOLVE_SUMMARY
+     printf("NEW NCOL/NROW/NELS:  %d(-%d) %d(-%d) %d(-%d)\n",
+            ncols_, ncols0 - ncols_,
+            nrows_, nrows0 - nrows_,
+            si->getNumElements(), nelems0 - si->getNumElements());
+#endif
+     si->setDblParam(ClpObjOffset, originalOffset_ - dobias_);
+     if (si->getObjSense() < 0.0) {
+       // put back
+       for (int i=0;i<ncols_;i++)
+	 cost_[i]=-cost_[i];
+       dobias_=-dobias_;
+       maxmin_=-1.0;
+     }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+////////////////  POSTSOLVE
+
+CoinPostsolveMatrix::CoinPostsolveMatrix(ClpSimplex*  si,
+          int ncols0_in,
+          int nrows0_in,
+          CoinBigIndex nelems0,
+
+          double maxmin,
+          // end prepost members
+
+          double *sol_in,
+          double *acts_in,
+
+          unsigned char *colstat_in,
+          unsigned char *rowstat_in) :
+     CoinPrePostsolveMatrix(si,
+                            ncols0_in, nrows0_in, nelems0, 2.0),
+
+     free_list_(0),
+     // link, free_list, maxlink
+     maxlink_(bulk0_),
+     link_(new int[/*maxlink*/ bulk0_]),
+
+     cdone_(new char[ncols0_]),
+     rdone_(new char[nrows0_in])
+
+{
+     bulk0_ = maxlink_ ;
+     nrows_ = si->getNumRows() ;
+     ncols_ = si->getNumCols() ;
+
+     sol_ = sol_in;
+     rowduals_ = NULL;
+     acts_ = acts_in;
+
+     rcosts_ = NULL;
+     colstat_ = colstat_in;
+     rowstat_ = rowstat_in;
+
+     // this is the *reduced* model, which is probably smaller
+     int ncols1 = ncols_ ;
+     int nrows1 = nrows_ ;
+
+     const CoinPackedMatrix * m = si->matrix();
+
+     const CoinBigIndex nelemsr = m->getNumElements();
+     if (m->getNumElements() && !isGapFree(*m)) {
+          // Odd - gaps
+          CoinPackedMatrix mm(*m);
+          mm.removeGaps();
+          mm.setExtraGap(0.0);
+
+          ClpDisjointCopyN(mm.getVectorStarts(), ncols1, mcstrt_);
+          CoinZeroN(mcstrt_ + ncols1, ncols0_ - ncols1);
+          mcstrt_[ncols1] = nelems0;	// ??    (should point to end of bulk store   -- lh --)
+          ClpDisjointCopyN(mm.getVectorLengths(), ncols1,  hincol_);
+          ClpDisjointCopyN(mm.getIndices(),      nelemsr, hrow_);
+          ClpDisjointCopyN(mm.getElements(),     nelemsr, colels_);
+     } else {
+          // No gaps
+
+          ClpDisjointCopyN(m->getVectorStarts(), ncols1, mcstrt_);
+          CoinZeroN(mcstrt_ + ncols1, ncols0_ - ncols1);
+          mcstrt_[ncols1] = nelems0;	// ??    (should point to end of bulk store   -- lh --)
+          ClpDisjointCopyN(m->getVectorLengths(), ncols1,  hincol_);
+          ClpDisjointCopyN(m->getIndices(),      nelemsr, hrow_);
+          ClpDisjointCopyN(m->getElements(),     nelemsr, colels_);
+     }
+
+
+
+#if	0 && PRESOLVE_DEBUG
+     presolve_check_costs(model, &colcopy);
+#endif
+
+     // This determines the size of the data structure that contains
+     // the matrix being postsolved.  Links are taken from the free_list
+     // to recreate matrix entries that were presolved away,
+     // and links are added to the free_list when entries created during
+     // presolve are discarded.  There is never a need to gc this list.
+     // Naturally, it should contain
+     // exactly nelems0 entries "in use" when postsolving is done,
+     // but I don't know whether the matrix could temporarily get
+     // larger during postsolving.  Substitution into more than two
+     // rows could do that, in principle.  I am being very conservative
+     // here by reserving much more than the amount of space I probably need.
+     // If this guess is wrong, check_free_list may be called.
+     //  int bufsize = 2*nelems0;
+
+     memset(cdone_, -1, ncols0_);
+     memset(rdone_, -1, nrows0_);
+
+     rowduals_ = new double[nrows0_];
+     ClpDisjointCopyN(si->getRowPrice(), nrows1, rowduals_);
+
+     rcosts_ = new double[ncols0_];
+     ClpDisjointCopyN(si->getReducedCost(), ncols1, rcosts_);
+     if (maxmin < 0.0) {
+          // change so will look as if minimize
+          int i;
+          for (i = 0; i < nrows1; i++)
+               rowduals_[i] = - rowduals_[i];
+          for (i = 0; i < ncols1; i++) {
+               rcosts_[i] = - rcosts_[i];
+          }
+     }
+
+     //ClpDisjointCopyN(si->getRowUpper(), nrows1, rup_);
+     //ClpDisjointCopyN(si->getRowLower(), nrows1, rlo_);
+
+     ClpDisjointCopyN(si->getColSolution(), ncols1, sol_);
+     si->setDblParam(ClpObjOffset, originalOffset_);
+
+     for (int j = 0; j < ncols1; j++) {
+#ifdef COIN_SLOW_PRESOLVE
+       if (hincol_[j]) {
+#endif
+          CoinBigIndex kcs = mcstrt_[j];
+          CoinBigIndex kce = kcs + hincol_[j];
+          for (CoinBigIndex k = kcs; k < kce; ++k) {
+               link_[k] = k + 1;
+          }
+          link_[kce-1] = NO_LINK ;
+#ifdef COIN_SLOW_PRESOLVE
+       }
+#endif
+     }
+     {
+          int ml = maxlink_;
+          for (CoinBigIndex k = nelemsr; k < ml; ++k)
+               link_[k] = k + 1;
+          if (ml)
+               link_[ml-1] = NO_LINK;
+     }
+     free_list_ = nelemsr;
+# if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
+     /*
+       These are used to track the action of postsolve transforms during debugging.
+     */
+     CoinFillN(cdone_, ncols1, PRESENT_IN_REDUCED) ;
+     CoinZeroN(cdone_ + ncols1, ncols0_in - ncols1) ;
+     CoinFillN(rdone_, nrows1, PRESENT_IN_REDUCED) ;
+     CoinZeroN(rdone_ + nrows1, nrows0_in - nrows1) ;
+# endif
+}
+/* This is main part of Presolve */
+ClpSimplex *
+ClpPresolve::gutsOfPresolvedModel(ClpSimplex * originalModel,
+                                  double feasibilityTolerance,
+                                  bool keepIntegers,
+                                  int numberPasses,
+                                  bool dropNames,
+                                  bool doRowObjective,
+				  const char * prohibitedRows,
+				  const char * prohibitedColumns)
+{
+     ncols_ = originalModel->getNumCols();
+     nrows_ = originalModel->getNumRows();
+     nelems_ = originalModel->getNumElements();
+     numberPasses_ = numberPasses;
+
+     double maxmin = originalModel->getObjSense();
+     originalModel_ = originalModel;
+     delete [] originalColumn_;
+     originalColumn_ = new int[ncols_];
+     delete [] originalRow_;
+     originalRow_ = new int[nrows_];
+     // and fill in case returns early
+     int i;
+     for (i = 0; i < ncols_; i++)
+          originalColumn_[i] = i;
+     for (i = 0; i < nrows_; i++)
+          originalRow_[i] = i;
+     delete [] rowObjective_;
+     if (doRowObjective) {
+          rowObjective_ = new double [nrows_];
+          memset(rowObjective_, 0, nrows_ * sizeof(double));
+     } else {
+          rowObjective_ = NULL;
+     }
+
+     // result is 0 - okay, 1 infeasible, -1 go round again, 2 - original model
+     int result = -1;
+
+     // User may have deleted - its their responsibility
+     presolvedModel_ = NULL;
+     // Messages
+     CoinMessages messages = originalModel->coinMessages();
+     // Only go round 100 times even if integer preprocessing
+     int totalPasses = 100;
+     while (result == -1) {
+
+#ifndef CLP_NO_STD
+          // make new copy
+          if (saveFile_ == "") {
+#endif
+               delete presolvedModel_;
+#ifndef CLP_NO_STD
+               // So won't get names
+               int lengthNames = originalModel->lengthNames();
+               originalModel->setLengthNames(0);
+#endif
+               presolvedModel_ = new ClpSimplex(*originalModel);
+#ifndef CLP_NO_STD
+               originalModel->setLengthNames(lengthNames);
+	       presolvedModel_->dropNames();
+          } else {
+               presolvedModel_ = originalModel;
+	       if (dropNames)
+		 presolvedModel_->dropNames();
+          }
+#endif
+
+          // drop integer information if wanted
+          if (!keepIntegers)
+               presolvedModel_->deleteIntegerInformation();
+          totalPasses--;
+
+          double ratio = 2.0;
+          if (substitution_ > 3)
+               ratio = substitution_;
+          else if (substitution_ == 2)
+               ratio = 1.5;
+          CoinPresolveMatrix prob(ncols_,
+                                  maxmin,
+                                  presolvedModel_,
+                                  nrows_, nelems_, true, nonLinearValue_, ratio);
+	  if (prohibitedRows) {
+	    prob.setAnyProhibited();
+	    for (int i=0;i<nrows_;i++) {
+	      if (prohibitedRows[i])
+		prob.setRowProhibited(i);
+	    }
+	  }
+	  if (prohibitedColumns) {
+	    prob.setAnyProhibited();
+	    for (int i=0;i<ncols_;i++) {
+	      if (prohibitedColumns[i])
+		prob.setColProhibited(i);
+	    }
+	  }
+          prob.setMaximumSubstitutionLevel(substitution_);
+          if (doRowObjective)
+               memset(rowObjective_, 0, nrows_ * sizeof(double));
+          // See if we want statistics
+          if ((presolveActions_ & 0x80000000) != 0)
+               prob.statistics();
+          // make sure row solution correct
+          {
+               double *colels	= prob.colels_;
+               int *hrow		= prob.hrow_;
+               CoinBigIndex *mcstrt		= prob.mcstrt_;
+               int *hincol		= prob.hincol_;
+               int ncols		= prob.ncols_;
+
+
+               double * csol = prob.sol_;
+               double * acts = prob.acts_;
+               int nrows = prob.nrows_;
+
+               int colx;
+
+               memset(acts, 0, nrows * sizeof(double));
+
+               for (colx = 0; colx < ncols; ++colx) {
+                    double solutionValue = csol[colx];
+                    for (int i = mcstrt[colx]; i < mcstrt[colx] + hincol[colx]; ++i) {
+                         int row = hrow[i];
+                         double coeff = colels[i];
+                         acts[row] += solutionValue * coeff;
+                    }
+               }
+          }
+
+          // move across feasibility tolerance
+          prob.feasibilityTolerance_ = feasibilityTolerance;
+
+          // Do presolve
+          paction_ = presolve(&prob);
+          // Get rid of useful arrays
+          prob.deleteStuff();
+
+          result = 0;
+
+	  bool fixInfeasibility = (prob.presolveOptions_&16384)!=0;
+	  bool hasSolution = (prob.presolveOptions_&32768)!=0;
+          if (prob.status_ == 0 && paction_ && (!hasSolution || !fixInfeasibility)) {
+               // Looks feasible but double check to see if anything slipped through
+               int n		= prob.ncols_;
+               double * lo = prob.clo_;
+               double * up = prob.cup_;
+               int i;
+
+               for (i = 0; i < n; i++) {
+                    if (up[i] < lo[i]) {
+                         if (up[i] < lo[i] - feasibilityTolerance && !fixInfeasibility) {
+                              // infeasible
+                              prob.status_ = 1;
+                         } else {
+                              up[i] = lo[i];
+                         }
+                    }
+               }
+
+               n = prob.nrows_;
+               lo = prob.rlo_;
+               up = prob.rup_;
+
+               for (i = 0; i < n; i++) {
+                    if (up[i] < lo[i]) {
+                         if (up[i] < lo[i] - feasibilityTolerance && !fixInfeasibility) {
+                              // infeasible
+                              prob.status_ = 1;
+                         } else {
+                              up[i] = lo[i];
+                         }
+                    }
+               }
+          }
+          if (prob.status_ == 0 && paction_) {
+               // feasible
+
+               prob.update_model(presolvedModel_, nrows_, ncols_, nelems_);
+               // copy status and solution
+               CoinMemcpyN(	     prob.sol_, prob.ncols_, presolvedModel_->primalColumnSolution());
+               CoinMemcpyN(	     prob.acts_, prob.nrows_, presolvedModel_->primalRowSolution());
+               CoinMemcpyN(	     prob.colstat_, prob.ncols_, presolvedModel_->statusArray());
+               CoinMemcpyN(	     prob.rowstat_, prob.nrows_, presolvedModel_->statusArray() + prob.ncols_);
+	       if (fixInfeasibility && hasSolution) {
+		 // Looks feasible but double check to see if anything slipped through
+		 int n		= prob.ncols_;
+		 double * lo = prob.clo_;
+		 double * up = prob.cup_;
+		 double * rsol = prob.acts_;
+		 //memset(prob.acts_,0,prob.nrows_*sizeof(double));
+		 presolvedModel_->matrix()->times(prob.sol_,rsol);
+		 int i;
+		 
+		 for (i = 0; i < n; i++) {
+		   double gap=up[i]-lo[i];
+		   if (rsol[i]<lo[i]-feasibilityTolerance&&fabs(rsol[i]-lo[i])<1.0e-3) {
+		     lo[i]=rsol[i];
+		     if (gap<1.0e5)
+		       up[i]=lo[i]+gap;
+		   } else if (rsol[i]>up[i]+feasibilityTolerance&&fabs(rsol[i]-up[i])<1.0e-3) {
+		     up[i]=rsol[i];
+		     if (gap<1.0e5)
+		       lo[i]=up[i]-gap;
+		   }
+		   if (up[i] < lo[i]) {
+		     up[i] = lo[i];
+		   }
+		 }
+	       }
+
+               int n = prob.nrows_;
+               double * lo = prob.rlo_;
+               double * up = prob.rup_;
+
+               for (i = 0; i < n; i++) {
+                    if (up[i] < lo[i]) {
+                         if (up[i] < lo[i] - feasibilityTolerance && !fixInfeasibility) {
+                              // infeasible
+                              prob.status_ = 1;
+                         } else {
+                              up[i] = lo[i];
+                         }
+                    }
+               }
+               delete [] prob.sol_;
+               delete [] prob.acts_;
+               delete [] prob.colstat_;
+               prob.sol_ = NULL;
+               prob.acts_ = NULL;
+               prob.colstat_ = NULL;
+
+               int ncolsNow = presolvedModel_->getNumCols();
+               CoinMemcpyN(prob.originalColumn_, ncolsNow, originalColumn_);
+#ifndef SLIM_CLP
+#ifndef NO_RTTI
+               ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(originalModel->objectiveAsObject()));
+#else
+               ClpQuadraticObjective * quadraticObj = NULL;
+               if (originalModel->objectiveAsObject()->type() == 2)
+                    quadraticObj = (static_cast< ClpQuadraticObjective*>(originalModel->objectiveAsObject()));
+#endif
+               if (quadraticObj) {
+                    // set up for subset
+                    char * mark = new char [ncols_];
+                    memset(mark, 0, ncols_);
+                    CoinPackedMatrix * quadratic = quadraticObj->quadraticObjective();
+                    //const int * columnQuadratic = quadratic->getIndices();
+                    //const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+                    const int * columnQuadraticLength = quadratic->getVectorLengths();
+                    //double * quadraticElement = quadratic->getMutableElements();
+                    int numberColumns = quadratic->getNumCols();
+                    ClpQuadraticObjective * newObj = new ClpQuadraticObjective(*quadraticObj,
+                              ncolsNow,
+                              originalColumn_);
+                    // and modify linear and check
+                    double * linear = newObj->linearObjective();
+                    CoinMemcpyN(presolvedModel_->objective(), ncolsNow, linear);
+                    int iColumn;
+                    for ( iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (columnQuadraticLength[iColumn])
+                              mark[iColumn] = 1;
+                    }
+                    // and new
+                    quadratic = newObj->quadraticObjective();
+                    columnQuadraticLength = quadratic->getVectorLengths();
+                    int numberColumns2 = quadratic->getNumCols();
+                    for ( iColumn = 0; iColumn < numberColumns2; iColumn++) {
+                         if (columnQuadraticLength[iColumn])
+                              mark[originalColumn_[iColumn]] = 0;
+                    }
+                    presolvedModel_->setObjective(newObj);
+                    delete newObj;
+                    // final check
+                    for ( iColumn = 0; iColumn < numberColumns; iColumn++)
+                         if (mark[iColumn])
+                              printf("Quadratic column %d modified - may be okay\n", iColumn);
+                    delete [] mark;
+               }
+#endif
+               delete [] prob.originalColumn_;
+               prob.originalColumn_ = NULL;
+               int nrowsNow = presolvedModel_->getNumRows();
+               CoinMemcpyN(prob.originalRow_, nrowsNow, originalRow_);
+               delete [] prob.originalRow_;
+               prob.originalRow_ = NULL;
+#ifndef CLP_NO_STD
+               if (!dropNames && originalModel->lengthNames()) {
+                    // Redo names
+                    int iRow;
+                    std::vector<std::string> rowNames;
+                    rowNames.reserve(nrowsNow);
+                    for (iRow = 0; iRow < nrowsNow; iRow++) {
+                         int kRow = originalRow_[iRow];
+                         rowNames.push_back(originalModel->rowName(kRow));
+                    }
+
+                    int iColumn;
+                    std::vector<std::string> columnNames;
+                    columnNames.reserve(ncolsNow);
+                    for (iColumn = 0; iColumn < ncolsNow; iColumn++) {
+                         int kColumn = originalColumn_[iColumn];
+                         columnNames.push_back(originalModel->columnName(kColumn));
+                    }
+                    presolvedModel_->copyNames(rowNames, columnNames);
+               } else {
+                    presolvedModel_->setLengthNames(0);
+               }
+#endif
+               if (rowObjective_) {
+                    int iRow;
+#ifndef NDEBUG
+                    int k = -1;
+#endif
+                    int nObj = 0;
+                    for (iRow = 0; iRow < nrowsNow; iRow++) {
+                         int kRow = originalRow_[iRow];
+#ifndef NDEBUG
+                         assert (kRow > k);
+                         k = kRow;
+#endif
+                         rowObjective_[iRow] = rowObjective_[kRow];
+                         if (rowObjective_[iRow])
+                              nObj++;
+                    }
+                    if (nObj) {
+                         printf("%d costed slacks\n", nObj);
+                         presolvedModel_->setRowObjective(rowObjective_);
+                    }
+               }
+               /* now clean up integer variables.  This can modify original
+               		  Don't do if dupcol added columns together */
+               int i;
+               const char * information = presolvedModel_->integerInformation();
+               if ((prob.presolveOptions_ & 0x80000000) == 0 && information) {
+                    int numberChanges = 0;
+                    double * lower0 = originalModel_->columnLower();
+                    double * upper0 = originalModel_->columnUpper();
+                    double * lower = presolvedModel_->columnLower();
+                    double * upper = presolvedModel_->columnUpper();
+                    for (i = 0; i < ncolsNow; i++) {
+                         if (!information[i])
+                              continue;
+                         int iOriginal = originalColumn_[i];
+                         double lowerValue0 = lower0[iOriginal];
+                         double upperValue0 = upper0[iOriginal];
+                         double lowerValue = ceil(lower[i] - 1.0e-5);
+                         double upperValue = floor(upper[i] + 1.0e-5);
+                         lower[i] = lowerValue;
+                         upper[i] = upperValue;
+                         if (lowerValue > upperValue) {
+                              numberChanges++;
+                              presolvedModel_->messageHandler()->message(COIN_PRESOLVE_COLINFEAS,
+                                        messages)
+                                        << iOriginal
+                                        << lowerValue
+                                        << upperValue
+                                        << CoinMessageEol;
+                              result = 1;
+                         } else {
+                              if (lowerValue > lowerValue0 + 1.0e-8) {
+                                   lower0[iOriginal] = lowerValue;
+                                   numberChanges++;
+                              }
+                              if (upperValue < upperValue0 - 1.0e-8) {
+                                   upper0[iOriginal] = upperValue;
+                                   numberChanges++;
+                              }
+                         }
+                    }
+                    if (numberChanges) {
+                         presolvedModel_->messageHandler()->message(COIN_PRESOLVE_INTEGERMODS,
+                                   messages)
+                                   << numberChanges
+                                   << CoinMessageEol;
+                         if (!result && totalPasses > 0) {
+                              result = -1; // round again
+                              const CoinPresolveAction *paction = paction_;
+                              while (paction) {
+                                   const CoinPresolveAction *next = paction->next;
+                                   delete paction;
+                                   paction = next;
+                              }
+                              paction_ = NULL;
+                         }
+                    }
+               }
+          } else if (prob.status_) {
+               // infeasible or unbounded
+               result = 1;
+	       // Put status in nelems_!
+	       nelems_ = - prob.status_;
+               originalModel->setProblemStatus(prob.status_);
+          } else {
+               // no changes - model needs restoring after Lou's changes
+#ifndef CLP_NO_STD
+               if (saveFile_ == "") {
+#endif
+                    delete presolvedModel_;
+                    presolvedModel_ = new ClpSimplex(*originalModel);
+                    // but we need to remove gaps
+                    ClpPackedMatrix* clpMatrix =
+                         dynamic_cast< ClpPackedMatrix*>(presolvedModel_->clpMatrix());
+                    if (clpMatrix) {
+                         clpMatrix->getPackedMatrix()->removeGaps();
+                    }
+#ifndef CLP_NO_STD
+               } else {
+                    presolvedModel_ = originalModel;
+               }
+               presolvedModel_->dropNames();
+#endif
+
+               // drop integer information if wanted
+               if (!keepIntegers)
+                    presolvedModel_->deleteIntegerInformation();
+               result = 2;
+          }
+     }
+     if (result == 0 || result == 2) {
+          int nrowsAfter = presolvedModel_->getNumRows();
+          int ncolsAfter = presolvedModel_->getNumCols();
+          CoinBigIndex nelsAfter = presolvedModel_->getNumElements();
+          presolvedModel_->messageHandler()->message(COIN_PRESOLVE_STATS,
+                    messages)
+                    << nrowsAfter << -(nrows_ - nrowsAfter)
+                    << ncolsAfter << -(ncols_ - ncolsAfter)
+                    << nelsAfter << -(nelems_ - nelsAfter)
+                    << CoinMessageEol;
+     } else {
+          destroyPresolve();
+          if (presolvedModel_ != originalModel_)
+               delete presolvedModel_;
+          presolvedModel_ = NULL;
+     }
+     return presolvedModel_;
+}
+
+
diff --git a/cbits/coin/ClpPresolve.hpp b/cbits/coin/ClpPresolve.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPresolve.hpp
@@ -0,0 +1,274 @@
+/* $Id: ClpPresolve.hpp 1928 2013-04-06 12:54:16Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpPresolve_H
+#define ClpPresolve_H
+#include "ClpSimplex.hpp"
+
+class CoinPresolveAction;
+#include "CoinPresolveMatrix.hpp"
+/** This is the Clp interface to CoinPresolve
+
+*/
+class ClpPresolve {
+public:
+     /**@name Main Constructor, destructor */
+     //@{
+     /// Default constructor
+     ClpPresolve();
+
+     /// Virtual destructor
+     virtual ~ClpPresolve();
+     //@}
+     /**@name presolve - presolves a model, transforming the model
+      * and saving information in the ClpPresolve object needed for postsolving.
+      * This underlying (protected) method is virtual; the idea is that in the future,
+      * one could override this method to customize how the various
+      * presolve techniques are applied.
+
+      This version of presolve returns a pointer to a new presolved
+         model.  NULL if infeasible or unbounded.
+         This should be paired with postsolve
+         below.  The advantage of going back to original model is that it
+         will be exactly as it was i.e. 0.0 will not become 1.0e-19.
+         If keepIntegers is true then bounds may be tightened in
+         original.  Bounds will be moved by up to feasibilityTolerance
+         to try and stay feasible.
+         Names will be dropped in presolved model if asked
+     */
+     ClpSimplex * presolvedModel(ClpSimplex & si,
+                                 double feasibilityTolerance = 0.0,
+                                 bool keepIntegers = true,
+                                 int numberPasses = 5,
+                                 bool dropNames = false,
+                                 bool doRowObjective = false,
+				 const char * prohibitedRows=NULL,
+				 const char * prohibitedColumns=NULL);
+#ifndef CLP_NO_STD
+     /** This version saves data in a file.  The passed in model
+         is updated to be presolved model.  
+         Returns non-zero if infeasible*/
+     int presolvedModelToFile(ClpSimplex &si, std::string fileName,
+                              double feasibilityTolerance = 0.0,
+                              bool keepIntegers = true,
+                              int numberPasses = 5,
+			      bool dropNames = false,
+                              bool doRowObjective = false);
+#endif
+     /** Return pointer to presolved model,
+         Up to user to destroy */
+     ClpSimplex * model() const;
+     /// Return pointer to original model
+     ClpSimplex * originalModel() const;
+     /// Set pointer to original model
+     void setOriginalModel(ClpSimplex * model);
+
+     /// return pointer to original columns
+     const int * originalColumns() const;
+     /// return pointer to original rows
+     const int * originalRows() const;
+     /** "Magic" number. If this is non-zero then any elements with this value
+         may change and so presolve is very limited in what can be done
+         to the row and column.  This is for non-linear problems.
+     */
+     inline void setNonLinearValue(double value) {
+          nonLinearValue_ = value;
+     }
+     inline double nonLinearValue() const {
+          return nonLinearValue_;
+     }
+     /// Whether we want to do dual part of presolve
+     inline bool doDual() const {
+          return (presolveActions_ & 1) == 0;
+     }
+     inline void setDoDual(bool doDual) {
+          if (doDual) presolveActions_  &= ~1;
+          else presolveActions_ |= 1;
+     }
+     /// Whether we want to do singleton part of presolve
+     inline bool doSingleton() const {
+          return (presolveActions_ & 2) == 0;
+     }
+     inline void setDoSingleton(bool doSingleton) {
+          if (doSingleton) presolveActions_  &= ~2;
+          else presolveActions_ |= 2;
+     }
+     /// Whether we want to do doubleton part of presolve
+     inline bool doDoubleton() const {
+          return (presolveActions_ & 4) == 0;
+     }
+     inline void setDoDoubleton(bool doDoubleton) {
+          if (doDoubleton) presolveActions_  &= ~4;
+          else presolveActions_ |= 4;
+     }
+     /// Whether we want to do tripleton part of presolve
+     inline bool doTripleton() const {
+          return (presolveActions_ & 8) == 0;
+     }
+     inline void setDoTripleton(bool doTripleton) {
+          if (doTripleton) presolveActions_  &= ~8;
+          else presolveActions_ |= 8;
+     }
+     /// Whether we want to do tighten part of presolve
+     inline bool doTighten() const {
+          return (presolveActions_ & 16) == 0;
+     }
+     inline void setDoTighten(bool doTighten) {
+          if (doTighten) presolveActions_  &= ~16;
+          else presolveActions_ |= 16;
+     }
+     /// Whether we want to do forcing part of presolve
+     inline bool doForcing() const {
+          return (presolveActions_ & 32) == 0;
+     }
+     inline void setDoForcing(bool doForcing) {
+          if (doForcing) presolveActions_  &= ~32;
+          else presolveActions_ |= 32;
+     }
+     /// Whether we want to do impliedfree part of presolve
+     inline bool doImpliedFree() const {
+          return (presolveActions_ & 64) == 0;
+     }
+     inline void setDoImpliedFree(bool doImpliedfree) {
+          if (doImpliedfree) presolveActions_  &= ~64;
+          else presolveActions_ |= 64;
+     }
+     /// Whether we want to do dupcol part of presolve
+     inline bool doDupcol() const {
+          return (presolveActions_ & 128) == 0;
+     }
+     inline void setDoDupcol(bool doDupcol) {
+          if (doDupcol) presolveActions_  &= ~128;
+          else presolveActions_ |= 128;
+     }
+     /// Whether we want to do duprow part of presolve
+     inline bool doDuprow() const {
+          return (presolveActions_ & 256) == 0;
+     }
+     inline void setDoDuprow(bool doDuprow) {
+          if (doDuprow) presolveActions_  &= ~256;
+          else presolveActions_ |= 256;
+     }
+     /// Whether we want to do singleton column part of presolve
+     inline bool doSingletonColumn() const {
+          return (presolveActions_ & 512) == 0;
+     }
+     inline void setDoSingletonColumn(bool doSingleton) {
+          if (doSingleton) presolveActions_  &= ~512;
+          else presolveActions_ |= 512;
+     }
+     /// Whether we want to do gubrow part of presolve
+     inline bool doGubrow() const {
+          return (presolveActions_ & 1024) == 0;
+     }
+     inline void setDoGubrow(bool doGubrow) {
+          if (doGubrow) presolveActions_  &= ~1024;
+          else presolveActions_ |= 1024;
+     }
+     /// Whether we want to do twoxtwo part of presolve
+     inline bool doTwoxTwo() const {
+          return (presolveActions_ & 2048) != 0;
+     }
+     inline void setDoTwoxtwo(bool doTwoxTwo) {
+          if (!doTwoxTwo) presolveActions_  &= ~2048;
+          else presolveActions_ |= 2048;
+     }
+     /// Set whole group
+     inline int presolveActions() const {
+          return presolveActions_ & 0xffff;
+     }
+     inline void setPresolveActions(int action) {
+          presolveActions_  = (presolveActions_ & 0xffff0000) | (action & 0xffff);
+     }
+     /// Substitution level
+     inline void setSubstitution(int value) {
+          substitution_ = value;
+     }
+     /// Asks for statistics
+     inline void statistics() {
+          presolveActions_ |= 0x80000000;
+     }
+     /// Return presolve status (0,1,2)
+     int presolveStatus() const;
+
+     /**@name postsolve - postsolve the problem.  If the problem
+       has not been solved to optimality, there are no guarantees.
+      If you are using an algorithm like simplex that has a concept
+      of "basic" rows/cols, then set updateStatus
+
+      Note that if you modified the original problem after presolving,
+      then you must ``undo'' these modifications before calling postsolve.
+     This version updates original*/
+     virtual void postsolve(bool updateStatus = true);
+
+     /// Gets rid of presolve actions (e.g.when infeasible)
+     void destroyPresolve();
+
+     /**@name private or protected data */
+private:
+     /// Original model - must not be destroyed before postsolve
+     ClpSimplex * originalModel_;
+
+     /// ClpPresolved model - up to user to destroy by deleteClpPresolvedModel
+     ClpSimplex * presolvedModel_;
+     /** "Magic" number. If this is non-zero then any elements with this value
+         may change and so presolve is very limited in what can be done
+         to the row and column.  This is for non-linear problems.
+         One could also allow for cases where sign of coefficient is known.
+     */
+     double nonLinearValue_;
+     /// Original column numbers
+     int * originalColumn_;
+     /// Original row numbers
+     int * originalRow_;
+     /// Row objective
+     double * rowObjective_;
+     /// The list of transformations applied.
+     const CoinPresolveAction *paction_;
+
+     /// The postsolved problem will expand back to its former size
+     /// as postsolve transformations are applied.
+     /// It is efficient to allocate data structures for the final size
+     /// of the problem rather than expand them as needed.
+     /// These fields give the size of the original problem.
+     int ncols_;
+     int nrows_;
+     CoinBigIndex nelems_;
+     /// Number of major passes
+     int numberPasses_;
+     /// Substitution level
+     int substitution_;
+#ifndef CLP_NO_STD
+     /// Name of saved model file
+     std::string saveFile_;
+#endif
+     /** Whether we want to skip dual part of presolve etc.
+         512 bit allows duplicate column processing on integer columns
+         and dual stuff on integers
+     */
+     int presolveActions_;
+protected:
+     /// If you want to apply the individual presolve routines differently,
+     /// or perhaps add your own to the mix,
+     /// define a derived class and override this method
+     virtual const CoinPresolveAction *presolve(CoinPresolveMatrix *prob);
+
+     /// Postsolving is pretty generic; just apply the transformations
+     /// in reverse order.
+     /// You will probably only be interested in overriding this method
+     /// if you want to add code to test for consistency
+     /// while debugging new presolve techniques.
+     virtual void postsolve(CoinPostsolveMatrix &prob);
+     /** This is main part of Presolve */
+     virtual ClpSimplex * gutsOfPresolvedModel(ClpSimplex * originalModel,
+               double feasibilityTolerance,
+               bool keepIntegers,
+               int numberPasses,
+               bool dropNames,
+					       bool doRowObjective,
+					       const char * prohibitedRows=NULL,
+					       const char * prohibitedColumns=NULL);
+};
+#endif
diff --git a/cbits/coin/ClpPrimalColumnDantzig.cpp b/cbits/coin/ClpPrimalColumnDantzig.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPrimalColumnDantzig.cpp
@@ -0,0 +1,253 @@
+/* $Id: ClpPrimalColumnDantzig.cpp 1732 2011-05-31 08:09:41Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include <cstdio>
+
+#include "CoinIndexedVector.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpPrimalColumnDantzig.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpPackedMatrix.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpPrimalColumnDantzig::ClpPrimalColumnDantzig ()
+     : ClpPrimalColumnPivot()
+{
+     type_ = 1;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpPrimalColumnDantzig::ClpPrimalColumnDantzig (const ClpPrimalColumnDantzig & source)
+     : ClpPrimalColumnPivot(source)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpPrimalColumnDantzig::~ClpPrimalColumnDantzig ()
+{
+
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpPrimalColumnDantzig &
+ClpPrimalColumnDantzig::operator=(const ClpPrimalColumnDantzig& rhs)
+{
+     if (this != &rhs) {
+          ClpPrimalColumnPivot::operator=(rhs);
+     }
+     return *this;
+}
+
+// Returns pivot column, -1 if none
+int
+ClpPrimalColumnDantzig::pivotColumn(CoinIndexedVector * updates,
+                                    CoinIndexedVector * /*spareRow1*/,
+                                    CoinIndexedVector * spareRow2,
+                                    CoinIndexedVector * spareColumn1,
+                                    CoinIndexedVector * spareColumn2)
+{
+     assert(model_);
+     int iSection, j;
+     int number;
+     int * index;
+     double * updateBy;
+     double * reducedCost;
+
+     bool anyUpdates;
+
+     if (updates->getNumElements()) {
+          anyUpdates = true;
+     } else {
+          // sub flip - nothing to do
+          anyUpdates = false;
+     }
+     if (anyUpdates) {
+          model_->factorization()->updateColumnTranspose(spareRow2, updates);
+          // put row of tableau in rowArray and columnArray
+          model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                              updates, spareColumn2, spareColumn1);
+          for (iSection = 0; iSection < 2; iSection++) {
+
+               reducedCost = model_->djRegion(iSection);
+
+               if (!iSection) {
+                    number = updates->getNumElements();
+                    index = updates->getIndices();
+                    updateBy = updates->denseVector();
+               } else {
+                    number = spareColumn1->getNumElements();
+                    index = spareColumn1->getIndices();
+                    updateBy = spareColumn1->denseVector();
+               }
+
+               for (j = 0; j < number; j++) {
+                    int iSequence = index[j];
+                    double value = reducedCost[iSequence];
+                    value -= updateBy[j];
+                    updateBy[j] = 0.0;
+                    reducedCost[iSequence] = value;
+               }
+
+          }
+          updates->setNumElements(0);
+          spareColumn1->setNumElements(0);
+     }
+
+
+     // update of duals finished - now do pricing
+
+     double largest = model_->currentPrimalTolerance();
+     // we can't really trust infeasibilities if there is primal error
+     if (model_->largestDualError() > 1.0e-8)
+          largest *= model_->largestDualError() / 1.0e-8;
+
+
+
+     double bestDj = model_->dualTolerance();
+     int bestSequence = -1;
+
+     double bestFreeDj = model_->dualTolerance();
+     int bestFreeSequence = -1;
+
+     number = model_->numberRows() + model_->numberColumns();
+     int iSequence;
+     reducedCost = model_->djRegion();
+
+#ifndef CLP_PRIMAL_SLACK_MULTIPLIER 
+     for (iSequence = 0; iSequence < number; iSequence++) {
+          // check flagged variable
+          if (!model_->flagged(iSequence)) {
+               double value = reducedCost[iSequence];
+               ClpSimplex::Status status = model_->getStatus(iSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    if (fabs(value) > bestFreeDj) {
+                         bestFreeDj = fabs(value);
+                         bestFreeSequence = iSequence;
+                    }
+                    break;
+               case ClpSimplex::atUpperBound:
+                    if (value > bestDj) {
+                         bestDj = value;
+                         bestSequence = iSequence;
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    if (value < -bestDj) {
+                         bestDj = -value;
+                         bestSequence = iSequence;
+                    }
+               }
+          }
+     }
+#else
+     // Columns
+     int numberColumns = model_->numberColumns();
+     for (iSequence = 0; iSequence < numberColumns; iSequence++) {
+          // check flagged variable
+          if (!model_->flagged(iSequence)) {
+               double value = reducedCost[iSequence];
+               ClpSimplex::Status status = model_->getStatus(iSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    if (fabs(value) > bestFreeDj) {
+                         bestFreeDj = fabs(value);
+                         bestFreeSequence = iSequence;
+                    }
+                    break;
+               case ClpSimplex::atUpperBound:
+                    if (value > bestDj) {
+                         bestDj = value;
+                         bestSequence = iSequence;
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    if (value < -bestDj) {
+                         bestDj = -value;
+                         bestSequence = iSequence;
+                    }
+               }
+          }
+     }
+     // Rows
+     for ( ; iSequence < number; iSequence++) {
+          // check flagged variable
+          if (!model_->flagged(iSequence)) {
+               double value = reducedCost[iSequence] * CLP_PRIMAL_SLACK_MULTIPLIER;
+               ClpSimplex::Status status = model_->getStatus(iSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    if (fabs(value) > bestFreeDj) {
+                         bestFreeDj = fabs(value);
+                         bestFreeSequence = iSequence;
+                    }
+                    break;
+               case ClpSimplex::atUpperBound:
+                    if (value > bestDj) {
+                         bestDj = value;
+                         bestSequence = iSequence;
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    if (value < -bestDj) {
+                         bestDj = -value;
+                         bestSequence = iSequence;
+                    }
+               }
+          }
+     }
+#endif
+     // bias towards free
+     if (bestFreeSequence >= 0 && bestFreeDj > 0.1 * bestDj)
+          bestSequence = bestFreeSequence;
+     return bestSequence;
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpPrimalColumnPivot * ClpPrimalColumnDantzig::clone(bool CopyData) const
+{
+     if (CopyData) {
+          return new ClpPrimalColumnDantzig(*this);
+     } else {
+          return new ClpPrimalColumnDantzig();
+     }
+}
+
diff --git a/cbits/coin/ClpPrimalColumnDantzig.hpp b/cbits/coin/ClpPrimalColumnDantzig.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPrimalColumnDantzig.hpp
@@ -0,0 +1,72 @@
+/* $Id: ClpPrimalColumnDantzig.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpPrimalColumnDantzig_H
+#define ClpPrimalColumnDantzig_H
+
+#include "ClpPrimalColumnPivot.hpp"
+
+//#############################################################################
+
+/** Primal Column Pivot Dantzig Algorithm Class
+
+This is simplest choice - choose largest infeasibility
+
+*/
+
+class ClpPrimalColumnDantzig : public ClpPrimalColumnPivot {
+
+public:
+
+     ///@name Algorithmic methods
+     //@{
+
+     /** Returns pivot column, -1 if none.
+         Lumbers over all columns - slow
+         The Packed CoinIndexedVector updates has cost updates - for normal LP
+         that is just +-weight where a feasibility changed.  It also has
+         reduced cost from last iteration in pivot row
+         Can just do full price if you really want to be slow
+     */
+     virtual int pivotColumn(CoinIndexedVector * updates,
+                             CoinIndexedVector * spareRow1,
+                             CoinIndexedVector * spareRow2,
+                             CoinIndexedVector * spareColumn1,
+                             CoinIndexedVector * spareColumn2);
+
+     /// Just sets model
+     virtual void saveWeights(ClpSimplex * model, int) {
+          model_ = model;
+     }
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpPrimalColumnDantzig();
+
+     /// Copy constructor
+     ClpPrimalColumnDantzig(const ClpPrimalColumnDantzig &);
+
+     /// Assignment operator
+     ClpPrimalColumnDantzig & operator=(const ClpPrimalColumnDantzig& rhs);
+
+     /// Destructor
+     virtual ~ClpPrimalColumnDantzig ();
+
+     /// Clone
+     virtual ClpPrimalColumnPivot * clone(bool copyData = true) const;
+
+     //@}
+
+     //---------------------------------------------------------------------------
+
+private:
+     ///@name Private member data
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpPrimalColumnPivot.cpp b/cbits/coin/ClpPrimalColumnPivot.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPrimalColumnPivot.cpp
@@ -0,0 +1,87 @@
+/* $Id: ClpPrimalColumnPivot.cpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpPrimalColumnPivot.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpPrimalColumnPivot::ClpPrimalColumnPivot () :
+     model_(NULL),
+     type_(-1),
+     looksOptimal_(false)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpPrimalColumnPivot::ClpPrimalColumnPivot (const ClpPrimalColumnPivot & source) :
+     model_(source.model_),
+     type_(source.type_),
+     looksOptimal_(source.looksOptimal_)
+{
+
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpPrimalColumnPivot::~ClpPrimalColumnPivot ()
+{
+
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpPrimalColumnPivot &
+ClpPrimalColumnPivot::operator=(const ClpPrimalColumnPivot& rhs)
+{
+     if (this != &rhs) {
+          type_ = rhs.type_;
+          model_ = rhs.model_;
+          looksOptimal_ = rhs.looksOptimal_;
+     }
+     return *this;
+}
+void
+ClpPrimalColumnPivot::saveWeights(ClpSimplex * model, int )
+{
+     model_ = model;
+}
+// checks accuracy and may re-initialize (may be empty)
+
+void
+ClpPrimalColumnPivot::updateWeights(CoinIndexedVector *)
+{
+}
+
+// Gets rid of all arrays
+void
+ClpPrimalColumnPivot::clearArrays()
+{
+}
+/* Returns number of extra columns for sprint algorithm - 0 means off.
+   Also number of iterations before recompute
+*/
+int
+ClpPrimalColumnPivot::numberSprintColumns(int & ) const
+{
+     return 0;
+}
+// Switch off sprint idea
+void
+ClpPrimalColumnPivot::switchOffSprint()
+{
+}
diff --git a/cbits/coin/ClpPrimalColumnPivot.hpp b/cbits/coin/ClpPrimalColumnPivot.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPrimalColumnPivot.hpp
@@ -0,0 +1,155 @@
+/* $Id: ClpPrimalColumnPivot.hpp 1732 2011-05-31 08:09:41Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpPrimalcolumnPivot_H
+#define ClpPrimalcolumnPivot_H
+
+class ClpSimplex;
+class CoinIndexedVector;
+
+//#############################################################################
+
+/** Primal Column Pivot Abstract Base Class
+
+Abstract Base Class for describing an interface to an algorithm
+to choose column pivot in primal simplex algorithm.  For some algorithms
+e.g. Dantzig choice then some functions may be null.  For Dantzig
+the only one of any importance is pivotColumn.
+
+If  you wish to inherit from this look at ClpPrimalColumnDantzig.cpp
+as that is simplest version.
+*/
+
+class ClpPrimalColumnPivot  {
+
+public:
+
+     ///@name Algorithmic methods
+     //@{
+
+     /** Returns pivot column, -1 if none
+
+         Normally updates reduced costs using result of last iteration
+         before selecting incoming column.
+
+         The Packed CoinIndexedVector updates has cost updates - for normal LP
+         that is just +-weight where a feasibility changed.  It also has
+         reduced cost from last iteration in pivot row
+
+         Inside pivotColumn the pivotRow_ and reduced cost from last iteration
+         are also used.
+
+         So in the simplest case i.e. feasible we compute the row of the
+         tableau corresponding to last pivot and add a multiple of this
+         to current reduced costs.
+
+         We can use other arrays to help updates
+     */
+     virtual int pivotColumn(CoinIndexedVector * updates,
+                             CoinIndexedVector * spareRow1,
+                             CoinIndexedVector * spareRow2,
+                             CoinIndexedVector * spareColumn1,
+                             CoinIndexedVector * spareColumn2) = 0;
+
+     /// Updates weights - part 1 (may be empty)
+     virtual void updateWeights(CoinIndexedVector * input);
+
+     /** Saves any weights round factorization as pivot rows may change
+         Will be empty unless steepest edge (will save model)
+         May also recompute infeasibility stuff
+         1) before factorization
+         2) after good factorization (if weights empty may initialize)
+         3) after something happened but no factorization
+            (e.g. check for infeasible)
+         4) as 2 but restore weights from previous snapshot
+         5) forces some initialization e.g. weights
+         Also sets model
+     */
+     virtual void saveWeights(ClpSimplex * model, int mode) = 0;
+     /** Signals pivot row choice:
+         -2 (default) - use normal pivot row choice
+         -1 to numberRows-1 - use this (will be checked)
+         way should be -1 to go to lower bound, +1 to upper bound
+     */
+     virtual int pivotRow(double & way) {
+          way = 0;
+          return -2;
+     }
+     /// Gets rid of all arrays (may be empty)
+     virtual void clearArrays();
+     /// Returns true if would not find any column
+     virtual bool looksOptimal() const {
+          return looksOptimal_;
+     }
+     /// Sets optimality flag (for advanced use)
+     virtual void setLooksOptimal(bool flag) {
+          looksOptimal_ = flag;
+     }
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpPrimalColumnPivot();
+
+     /// Copy constructor
+     ClpPrimalColumnPivot(const ClpPrimalColumnPivot &);
+
+     /// Assignment operator
+     ClpPrimalColumnPivot & operator=(const ClpPrimalColumnPivot& rhs);
+
+     /// Destructor
+     virtual ~ClpPrimalColumnPivot ();
+
+     /// Clone
+     virtual ClpPrimalColumnPivot * clone(bool copyData = true) const = 0;
+
+     //@}
+
+     ///@name Other
+     //@{
+     /// Returns model
+     inline ClpSimplex * model() {
+          return model_;
+     }
+     /// Sets model
+     inline void setModel(ClpSimplex * newmodel) {
+          model_ = newmodel;
+     }
+
+     /// Returns type (above 63 is extra information)
+     inline int type() {
+          return type_;
+     }
+
+     /** Returns number of extra columns for sprint algorithm - 0 means off.
+         Also number of iterations before recompute
+     */
+     virtual int numberSprintColumns(int & numberIterations) const;
+     /// Switch off sprint idea
+     virtual void switchOffSprint();
+     /// Called when maximum pivots changes
+     virtual void maximumPivotsChanged() {}
+
+     //@}
+
+     //---------------------------------------------------------------------------
+
+protected:
+     ///@name Protected member data
+     //@{
+     /// Pointer to model
+     ClpSimplex * model_;
+     /// Type of column pivot algorithm
+     int type_;
+     /// Says if looks optimal (normally computed)
+     bool looksOptimal_;
+     //@}
+};
+#ifndef CLP_PRIMAL_SLACK_MULTIPLIER
+#define CLP_PRIMAL_SLACK_MULTIPLIER 1.01
+#endif
+#endif
diff --git a/cbits/coin/ClpPrimalColumnSteepest.cpp b/cbits/coin/ClpPrimalColumnSteepest.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPrimalColumnSteepest.cpp
@@ -0,0 +1,3957 @@
+/* $Id: ClpPrimalColumnSteepest.cpp 1955 2013-05-14 10:10:07Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include "ClpSimplex.hpp"
+#include "ClpPrimalColumnSteepest.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpNonLinearCost.hpp"
+#include "ClpMessage.hpp"
+#include "CoinHelperFunctions.hpp"
+#include <stdio.h>
+//#define CLP_DEBUG
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpPrimalColumnSteepest::ClpPrimalColumnSteepest (int mode)
+     : ClpPrimalColumnPivot(),
+       devex_(0.0),
+       weights_(NULL),
+       infeasible_(NULL),
+       alternateWeights_(NULL),
+       savedWeights_(NULL),
+       reference_(NULL),
+       state_(-1),
+       mode_(mode),
+       persistence_(normal),
+       numberSwitched_(0),
+       pivotSequence_(-1),
+       savedPivotSequence_(-1),
+       savedSequenceOut_(-1),
+       sizeFactorization_(0)
+{
+     type_ = 2 + 64 * mode;
+}
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpPrimalColumnSteepest::ClpPrimalColumnSteepest (const ClpPrimalColumnSteepest & rhs)
+     : ClpPrimalColumnPivot(rhs)
+{
+     state_ = rhs.state_;
+     mode_ = rhs.mode_;
+     persistence_ = rhs.persistence_;
+     numberSwitched_ = rhs.numberSwitched_;
+     model_ = rhs.model_;
+     pivotSequence_ = rhs.pivotSequence_;
+     savedPivotSequence_ = rhs.savedPivotSequence_;
+     savedSequenceOut_ = rhs.savedSequenceOut_;
+     sizeFactorization_ = rhs.sizeFactorization_;
+     devex_ = rhs.devex_;
+     if ((model_ && model_->whatsChanged() & 1) != 0) {
+          if (rhs.infeasible_) {
+               infeasible_ = new CoinIndexedVector(rhs.infeasible_);
+          } else {
+               infeasible_ = NULL;
+          }
+          reference_ = NULL;
+          if (rhs.weights_) {
+               assert(model_);
+               int number = model_->numberRows() + model_->numberColumns();
+               assert (number == rhs.model_->numberRows() + rhs.model_->numberColumns());
+               weights_ = new double[number];
+               CoinMemcpyN(rhs.weights_, number, weights_);
+               savedWeights_ = new double[number];
+               CoinMemcpyN(rhs.savedWeights_, number, savedWeights_);
+               if (mode_ != 1) {
+                    reference_ = CoinCopyOfArray(rhs.reference_, (number + 31) >> 5);
+               }
+          } else {
+               weights_ = NULL;
+               savedWeights_ = NULL;
+          }
+          if (rhs.alternateWeights_) {
+               alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_);
+          } else {
+               alternateWeights_ = NULL;
+          }
+     } else {
+          infeasible_ = NULL;
+          reference_ = NULL;
+          weights_ = NULL;
+          savedWeights_ = NULL;
+          alternateWeights_ = NULL;
+     }
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpPrimalColumnSteepest::~ClpPrimalColumnSteepest ()
+{
+     delete [] weights_;
+     delete infeasible_;
+     delete alternateWeights_;
+     delete [] savedWeights_;
+     delete [] reference_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpPrimalColumnSteepest &
+ClpPrimalColumnSteepest::operator=(const ClpPrimalColumnSteepest& rhs)
+{
+     if (this != &rhs) {
+          ClpPrimalColumnPivot::operator=(rhs);
+          state_ = rhs.state_;
+          mode_ = rhs.mode_;
+          persistence_ = rhs.persistence_;
+          numberSwitched_ = rhs.numberSwitched_;
+          model_ = rhs.model_;
+          pivotSequence_ = rhs.pivotSequence_;
+          savedPivotSequence_ = rhs.savedPivotSequence_;
+          savedSequenceOut_ = rhs.savedSequenceOut_;
+          sizeFactorization_ = rhs.sizeFactorization_;
+          devex_ = rhs.devex_;
+          delete [] weights_;
+          delete [] reference_;
+          reference_ = NULL;
+          delete infeasible_;
+          delete alternateWeights_;
+          delete [] savedWeights_;
+          savedWeights_ = NULL;
+          if (rhs.infeasible_ != NULL) {
+               infeasible_ = new CoinIndexedVector(rhs.infeasible_);
+          } else {
+               infeasible_ = NULL;
+          }
+          if (rhs.weights_ != NULL) {
+               assert(model_);
+               int number = model_->numberRows() + model_->numberColumns();
+               assert (number == rhs.model_->numberRows() + rhs.model_->numberColumns());
+               weights_ = new double[number];
+               CoinMemcpyN(rhs.weights_, number, weights_);
+               savedWeights_ = new double[number];
+               CoinMemcpyN(rhs.savedWeights_, number, savedWeights_);
+               if (mode_ != 1) {
+                    reference_ = CoinCopyOfArray(rhs.reference_, (number + 31) >> 5);
+               }
+          } else {
+               weights_ = NULL;
+          }
+          if (rhs.alternateWeights_ != NULL) {
+               alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_);
+          } else {
+               alternateWeights_ = NULL;
+          }
+     }
+     return *this;
+}
+// These have to match ClpPackedMatrix version
+#define TRY_NORM 1.0e-4
+#define ADD_ONE 1.0
+// Returns pivot column, -1 if none
+/*      The Packed CoinIndexedVector updates has cost updates - for normal LP
+	that is just +-weight where a feasibility changed.  It also has
+	reduced cost from last iteration in pivot row*/
+int
+ClpPrimalColumnSteepest::pivotColumn(CoinIndexedVector * updates,
+                                     CoinIndexedVector * spareRow1,
+                                     CoinIndexedVector * spareRow2,
+                                     CoinIndexedVector * spareColumn1,
+                                     CoinIndexedVector * spareColumn2)
+{
+     assert(model_);
+     if (model_->nonLinearCost()->lookBothWays() || model_->algorithm() == 2) {
+          // Do old way
+          updates->expand();
+          return pivotColumnOldMethod(updates, spareRow1, spareRow2,
+                                      spareColumn1, spareColumn2);
+     }
+     int number = 0;
+     int * index;
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     int pivotRow = model_->pivotRow();
+     int anyUpdates;
+     double * infeas = infeasible_->denseVector();
+
+     // Local copy of mode so can decide what to do
+     int switchType;
+     if (mode_ == 4)
+          switchType = 5 - numberSwitched_;
+     else if (mode_ >= 10)
+          switchType = 3;
+     else
+          switchType = mode_;
+     /* switchType -
+        0 - all exact devex
+        1 - all steepest
+        2 - some exact devex
+        3 - auto some exact devex
+        4 - devex
+        5 - dantzig
+        10 - can go to mini-sprint
+     */
+     // Look at gub
+#if 1
+     model_->clpMatrix()->dualExpanded(model_, updates, NULL, 4);
+#else
+     updates->clear();
+     model_->computeDuals(NULL);
+#endif
+     if (updates->getNumElements() > 1) {
+          // would have to have two goes for devex, three for steepest
+          anyUpdates = 2;
+     } else if (updates->getNumElements()) {
+          if (updates->getIndices()[0] == pivotRow && fabs(updates->denseVector()[0]) > 1.0e-6) {
+               // reasonable size
+               anyUpdates = 1;
+               //if (fabs(model_->dualIn())<1.0e-4||fabs(fabs(model_->dualIn())-fabs(updates->denseVector()[0]))>1.0e-5)
+               //printf("dualin %g pivot %g\n",model_->dualIn(),updates->denseVector()[0]);
+          } else {
+               // too small
+               anyUpdates = 2;
+          }
+     } else if (pivotSequence_ >= 0) {
+          // just after re-factorization
+          anyUpdates = -1;
+     } else {
+          // sub flip - nothing to do
+          anyUpdates = 0;
+     }
+     int sequenceOut = model_->sequenceOut();
+     if (switchType == 5) {
+          // If known matrix then we will do partial pricing
+          if (model_->clpMatrix()->canDoPartialPricing()) {
+               pivotSequence_ = -1;
+               pivotRow = -1;
+               // See if to switch
+               int numberRows = model_->numberRows();
+               int numberWanted = 10;
+               int numberColumns = model_->numberColumns();
+               int numberHiddenRows = model_->clpMatrix()->hiddenRows();
+               double ratio = static_cast<double> (sizeFactorization_ + numberHiddenRows) /
+                              static_cast<double> (numberRows + 2 * numberHiddenRows);
+               // Number of dual infeasibilities at last invert
+               int numberDual = model_->numberDualInfeasibilities();
+               int numberLook = CoinMin(numberDual, numberColumns / 10);
+               if (ratio < 1.0) {
+                    numberWanted = 100;
+                    numberLook /= 20;
+                    numberWanted = CoinMax(numberWanted, numberLook);
+               } else if (ratio < 3.0) {
+                    numberWanted = 500;
+                    numberLook /= 15;
+                    numberWanted = CoinMax(numberWanted, numberLook);
+               } else if (ratio < 4.0 || mode_ == 5) {
+                    numberWanted = 1000;
+                    numberLook /= 10;
+                    numberWanted = CoinMax(numberWanted, numberLook);
+               } else if (mode_ != 5) {
+                    switchType = 4;
+                    // initialize
+                    numberSwitched_++;
+                    // Make sure will re-do
+                    delete [] weights_;
+                    weights_ = NULL;
+                    model_->computeDuals(NULL);
+                    saveWeights(model_, 4);
+                    anyUpdates = 0;
+                    COIN_DETAIL_PRINT(printf("switching to devex %d nel ratio %g\n", sizeFactorization_, ratio));
+               }
+               if (switchType == 5) {
+                    numberLook *= 5; // needs tuning for gub
+                    if (model_->numberIterations() % 1000 == 0 && model_->logLevel() > 1) {
+                         COIN_DETAIL_PRINT(printf("numels %d ratio %g wanted %d look %d\n",
+						  sizeFactorization_, ratio, numberWanted, numberLook));
+                    }
+                    // Update duals and row djs
+                    // Do partial pricing
+                    return partialPricing(updates, spareRow2,
+                                          numberWanted, numberLook);
+               }
+          }
+     }
+     if (switchType == 5) {
+          if (anyUpdates > 0) {
+               justDjs(updates, spareRow2,
+                       spareColumn1, spareColumn2);
+          }
+     } else if (anyUpdates == 1) {
+          if (switchType < 4) {
+               // exact etc when can use dj
+               djsAndSteepest(updates, spareRow2,
+                              spareColumn1, spareColumn2);
+          } else {
+               // devex etc when can use dj
+               djsAndDevex(updates, spareRow2,
+                           spareColumn1, spareColumn2);
+          }
+     } else if (anyUpdates == -1) {
+          if (switchType < 4) {
+               // exact etc when djs okay
+               justSteepest(updates, spareRow2,
+                            spareColumn1, spareColumn2);
+          } else {
+               // devex etc when djs okay
+               justDevex(updates, spareRow2,
+                         spareColumn1, spareColumn2);
+          }
+     } else if (anyUpdates == 2) {
+          if (switchType < 4) {
+               // exact etc when have to use pivot
+               djsAndSteepest2(updates, spareRow2,
+                               spareColumn1, spareColumn2);
+          } else {
+               // devex etc when have to use pivot
+               djsAndDevex2(updates, spareRow2,
+                            spareColumn1, spareColumn2);
+          }
+     }
+#ifdef CLP_DEBUG
+     alternateWeights_->checkClear();
+#endif
+     // make sure outgoing from last iteration okay
+     if (sequenceOut >= 0) {
+          ClpSimplex::Status status = model_->getStatus(sequenceOut);
+          double value = model_->reducedCost(sequenceOut);
+
+          switch(status) {
+
+          case ClpSimplex::basic:
+          case ClpSimplex::isFixed:
+               break;
+          case ClpSimplex::isFree:
+          case ClpSimplex::superBasic:
+               if (fabs(value) > FREE_ACCEPT * tolerance) {
+                    // we are going to bias towards free (but only if reasonable)
+                    value *= FREE_BIAS;
+                    // store square in list
+                    if (infeas[sequenceOut])
+                         infeas[sequenceOut] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(sequenceOut, value * value);
+               } else {
+                    infeasible_->zero(sequenceOut);
+               }
+               break;
+          case ClpSimplex::atUpperBound:
+               if (value > tolerance) {
+                    // store square in list
+                    if (infeas[sequenceOut])
+                         infeas[sequenceOut] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(sequenceOut, value * value);
+               } else {
+                    infeasible_->zero(sequenceOut);
+               }
+               break;
+          case ClpSimplex::atLowerBound:
+               if (value < -tolerance) {
+                    // store square in list
+                    if (infeas[sequenceOut])
+                         infeas[sequenceOut] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(sequenceOut, value * value);
+               } else {
+                    infeasible_->zero(sequenceOut);
+               }
+          }
+     }
+     // update of duals finished - now do pricing
+     // See what sort of pricing
+     int numberWanted = 10;
+     number = infeasible_->getNumElements();
+     int numberColumns = model_->numberColumns();
+     if (switchType == 5) {
+          pivotSequence_ = -1;
+          pivotRow = -1;
+          // See if to switch
+          int numberRows = model_->numberRows();
+          // ratio is done on number of columns here
+          //double ratio = static_cast<double> sizeFactorization_/static_cast<double> numberColumns;
+          double ratio = static_cast<double> (sizeFactorization_) / static_cast<double> (numberRows);
+          //double ratio = static_cast<double> sizeFactorization_/static_cast<double> model_->clpMatrix()->getNumElements();
+          if (ratio < 1.0) {
+               numberWanted = CoinMax(100, number / 200);
+          } else if (ratio < 2.0 - 1.0) {
+               numberWanted = CoinMax(500, number / 40);
+          } else if (ratio < 4.0 - 3.0 || mode_ == 5) {
+               numberWanted = CoinMax(2000, number / 10);
+               numberWanted = CoinMax(numberWanted, numberColumns / 30);
+          } else if (mode_ != 5) {
+               switchType = 4;
+               // initialize
+               numberSwitched_++;
+               // Make sure will re-do
+               delete [] weights_;
+               weights_ = NULL;
+               saveWeights(model_, 4);
+               COIN_DETAIL_PRINT(printf("switching to devex %d nel ratio %g\n", sizeFactorization_, ratio));
+          }
+          //if (model_->numberIterations()%1000==0)
+          //printf("numels %d ratio %g wanted %d\n",sizeFactorization_,ratio,numberWanted);
+     }
+     int numberRows = model_->numberRows();
+     // ratio is done on number of rows here
+     double ratio = static_cast<double> (sizeFactorization_) / static_cast<double> (numberRows);
+     if(switchType == 4) {
+          // Still in devex mode
+          // Go to steepest if lot of iterations?
+          if (ratio < 5.0) {
+               numberWanted = CoinMax(2000, number / 10);
+               numberWanted = CoinMax(numberWanted, numberColumns / 20);
+          } else if (ratio < 7.0) {
+               numberWanted = CoinMax(2000, number / 5);
+               numberWanted = CoinMax(numberWanted, numberColumns / 10);
+          } else {
+               // we can zero out
+               updates->clear();
+               spareColumn1->clear();
+               switchType = 3;
+               // initialize
+               pivotSequence_ = -1;
+               pivotRow = -1;
+               numberSwitched_++;
+               // Make sure will re-do
+               delete [] weights_;
+               weights_ = NULL;
+               saveWeights(model_, 4);
+               COIN_DETAIL_PRINT(printf("switching to exact %d nel ratio %g\n", sizeFactorization_, ratio));
+               updates->clear();
+          }
+          if (model_->numberIterations() % 1000 == 0)
+	    COIN_DETAIL_PRINT(printf("numels %d ratio %g wanted %d type x\n", sizeFactorization_, ratio, numberWanted));
+     }
+     if (switchType < 4) {
+          if (switchType < 2 ) {
+               numberWanted = number + 1;
+          } else if (switchType == 2) {
+               numberWanted = CoinMax(2000, number / 8);
+          } else {
+               if (ratio < 1.0) {
+                    numberWanted = CoinMax(2000, number / 20);
+               } else if (ratio < 5.0) {
+                    numberWanted = CoinMax(2000, number / 10);
+                    numberWanted = CoinMax(numberWanted, numberColumns / 40);
+               } else if (ratio < 10.0) {
+                    numberWanted = CoinMax(2000, number / 8);
+                    numberWanted = CoinMax(numberWanted, numberColumns / 20);
+               } else {
+                    ratio = number * (ratio / 80.0);
+                    if (ratio > number) {
+                         numberWanted = number + 1;
+                    } else {
+                         numberWanted = CoinMax(2000, static_cast<int> (ratio));
+                         numberWanted = CoinMax(numberWanted, numberColumns / 10);
+                    }
+               }
+          }
+          //if (model_->numberIterations()%1000==0)
+          //printf("numels %d ratio %g wanted %d type %d\n",sizeFactorization_,ratio,numberWanted,
+          //switchType);
+     }
+
+
+     double bestDj = 1.0e-30;
+     int bestSequence = -1;
+
+     int i, iSequence;
+     index = infeasible_->getIndices();
+     number = infeasible_->getNumElements();
+     // Re-sort infeasible every 100 pivots
+     // Not a good idea
+     if (0 && model_->factorization()->pivots() > 0 &&
+               (model_->factorization()->pivots() % 100) == 0) {
+          int nLook = model_->numberRows() + numberColumns;
+          number = 0;
+          for (i = 0; i < nLook; i++) {
+               if (infeas[i]) {
+                    if (fabs(infeas[i]) > COIN_INDEXED_TINY_ELEMENT)
+                         index[number++] = i;
+                    else
+                         infeas[i] = 0.0;
+               }
+          }
+          infeasible_->setNumElements(number);
+     }
+     if(model_->numberIterations() < model_->lastBadIteration() + 200 &&
+               model_->factorization()->pivots() > 10) {
+          // we can't really trust infeasibilities if there is dual error
+          double checkTolerance = 1.0e-8;
+          if (model_->largestDualError() > checkTolerance)
+               tolerance *= model_->largestDualError() / checkTolerance;
+          // But cap
+          tolerance = CoinMin(1000.0, tolerance);
+     }
+#ifdef CLP_DEBUG
+     if (model_->numberDualInfeasibilities() == 1)
+          printf("** %g %g %g %x %x %d\n", tolerance, model_->dualTolerance(),
+                 model_->largestDualError(), model_, model_->messageHandler(),
+                 number);
+#endif
+     // stop last one coming immediately
+     double saveOutInfeasibility = 0.0;
+     if (sequenceOut >= 0) {
+          saveOutInfeasibility = infeas[sequenceOut];
+          infeas[sequenceOut] = 0.0;
+     }
+     if (model_->factorization()->pivots() && model_->numberPrimalInfeasibilities())
+          tolerance = CoinMax(tolerance, 1.0e-10 * model_->infeasibilityCost());
+     tolerance *= tolerance; // as we are using squares
+
+     int iPass;
+     // Setup two passes
+     int start[4];
+     start[1] = number;
+     start[2] = 0;
+     double dstart = static_cast<double> (number) * model_->randomNumberGenerator()->randomDouble();
+     start[0] = static_cast<int> (dstart);
+     start[3] = start[0];
+     //double largestWeight=0.0;
+     //double smallestWeight=1.0e100;
+     for (iPass = 0; iPass < 2; iPass++) {
+          int end = start[2*iPass+1];
+          if (switchType < 5) {
+               for (i = start[2*iPass]; i < end; i++) {
+                    iSequence = index[i];
+                    double value = infeas[iSequence];
+                    double weight = weights_[iSequence];
+                    if (value > tolerance) {
+                         //weight=1.0;
+                         if (value > bestDj * weight) {
+                              // check flagged variable and correct dj
+                              if (!model_->flagged(iSequence)) {
+                                   bestDj = value / weight;
+                                   bestSequence = iSequence;
+                              } else {
+                                   // just to make sure we don't exit before got something
+                                   numberWanted++;
+                              }
+                         }
+                         numberWanted--;
+                    }
+                    if (!numberWanted)
+                         break;
+               }
+          } else {
+               // Dantzig
+               for (i = start[2*iPass]; i < end; i++) {
+                    iSequence = index[i];
+                    double value = infeas[iSequence];
+                    if (value > tolerance) {
+                         if (value > bestDj) {
+                              // check flagged variable and correct dj
+                              if (!model_->flagged(iSequence)) {
+                                   bestDj = value;
+                                   bestSequence = iSequence;
+                              } else {
+                                   // just to make sure we don't exit before got something
+                                   numberWanted++;
+                              }
+                         }
+                         numberWanted--;
+                    }
+                    if (!numberWanted)
+                         break;
+               }
+          }
+          if (!numberWanted)
+               break;
+     }
+     model_->clpMatrix()->setSavedBestSequence(bestSequence);
+     if (bestSequence >= 0)
+          model_->clpMatrix()->setSavedBestDj(model_->djRegion()[bestSequence]);
+     if (sequenceOut >= 0) {
+          infeas[sequenceOut] = saveOutInfeasibility;
+     }
+     /*if (model_->numberIterations()%100==0)
+       printf("%d best %g\n",bestSequence,bestDj);*/
+
+#ifndef NDEBUG
+     if (bestSequence >= 0) {
+          if (model_->getStatus(bestSequence) == ClpSimplex::atLowerBound) 
+               assert(model_->reducedCost(bestSequence) < 0.0);
+          if (model_->getStatus(bestSequence) == ClpSimplex::atUpperBound) {
+               assert(model_->reducedCost(bestSequence) > 0.0);
+          }
+     }
+#endif
+#if 0
+     for (int i=0;i<numberRows;i++)
+       printf("row %d weight %g infeas %g\n",i,weights_[i+numberColumns],infeas[i+numberColumns]);
+     for (int i=0;i<numberColumns;i++)
+       printf("column %d weight %g infeas %g\n",i,weights_[i],infeas[i]);
+#endif
+     return bestSequence;
+}
+// Just update djs
+void
+ClpPrimalColumnSteepest::justDjs(CoinIndexedVector * updates,
+                                 CoinIndexedVector * spareRow2,
+                                 CoinIndexedVector * spareColumn1,
+                                 CoinIndexedVector * spareColumn2)
+{
+     int iSection, j;
+     int number = 0;
+     int * index;
+     double * updateBy;
+     double * reducedCost;
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     int pivotRow = model_->pivotRow();
+     double * infeas = infeasible_->denseVector();
+     //updates->scanAndPack();
+     model_->factorization()->updateColumnTranspose(spareRow2, updates);
+
+     // put row of tableau in rowArray and columnArray (packed mode)
+     model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                         updates, spareColumn2, spareColumn1);
+     // normal
+     for (iSection = 0; iSection < 2; iSection++) {
+
+          reducedCost = model_->djRegion(iSection);
+          int addSequence;
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	  double slack_multiplier;
+#endif
+
+          if (!iSection) {
+               number = updates->getNumElements();
+               index = updates->getIndices();
+               updateBy = updates->denseVector();
+               addSequence = model_->numberColumns();
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	       slack_multiplier = CLP_PRIMAL_SLACK_MULTIPLIER;
+#endif
+          } else {
+               number = spareColumn1->getNumElements();
+               index = spareColumn1->getIndices();
+               updateBy = spareColumn1->denseVector();
+               addSequence = 0;
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	       slack_multiplier = 1.0;
+#endif
+          }
+
+          for (j = 0; j < number; j++) {
+               int iSequence = index[j];
+               double value = reducedCost[iSequence];
+               value -= updateBy[j];
+               updateBy[j] = 0.0;
+               reducedCost[iSequence] = value;
+               ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+                    infeasible_->zero(iSequence + addSequence);
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    if (fabs(value) > FREE_ACCEPT * tolerance) {
+                         // we are going to bias towards free (but only if reasonable)
+                         value *= FREE_BIAS;
+                         // store square in list
+                         if (infeas[iSequence+addSequence])
+                              infeas[iSequence+addSequence] = value * value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence + addSequence, value * value);
+                    } else {
+                         infeasible_->zero(iSequence + addSequence);
+                    }
+                    break;
+               case ClpSimplex::atUpperBound:
+	            iSequence += addSequence;
+                    if (value > tolerance) {
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+  		        value *= value*slack_multiplier;
+#else
+		        value *= value;
+#endif
+                         // store square in list
+                         if (infeas[iSequence])
+                              infeas[iSequence] = value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence, value);
+                    } else {
+                         infeasible_->zero(iSequence);
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+	            iSequence += addSequence;
+                    if (value < -tolerance) {
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+  		        value *= value*slack_multiplier;
+#else
+		        value *= value;
+#endif
+                         // store square in list
+                         if (infeas[iSequence])
+                              infeas[iSequence] = value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence, value);
+                    } else {
+                         infeasible_->zero(iSequence);
+                    }
+               }
+          }
+     }
+     updates->setNumElements(0);
+     spareColumn1->setNumElements(0);
+     if (pivotRow >= 0) {
+          // make sure infeasibility on incoming is 0.0
+          int sequenceIn = model_->sequenceIn();
+          infeasible_->zero(sequenceIn);
+     }
+}
+// Update djs, weights for Devex
+void
+ClpPrimalColumnSteepest::djsAndDevex(CoinIndexedVector * updates,
+                                     CoinIndexedVector * spareRow2,
+                                     CoinIndexedVector * spareColumn1,
+                                     CoinIndexedVector * spareColumn2)
+{
+     int j;
+     int number = 0;
+     int * index;
+     double * updateBy;
+     double * reducedCost;
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     // for weights update we use pivotSequence
+     // unset in case sub flip
+     assert (pivotSequence_ >= 0);
+     assert (model_->pivotVariable()[pivotSequence_] == model_->sequenceIn());
+     pivotSequence_ = -1;
+     double * infeas = infeasible_->denseVector();
+     //updates->scanAndPack();
+     model_->factorization()->updateColumnTranspose(spareRow2, updates);
+     // and we can see if reference
+     //double referenceIn = 0.0;
+     int sequenceIn = model_->sequenceIn();
+     //if (mode_ != 1 && reference(sequenceIn))
+     //   referenceIn = 1.0;
+     // save outgoing weight round update
+     double outgoingWeight = 0.0;
+     int sequenceOut = model_->sequenceOut();
+     if (sequenceOut >= 0)
+          outgoingWeight = weights_[sequenceOut];
+
+     double scaleFactor = 1.0 / updates->denseVector()[0]; // as formula is with 1.0
+     // put row of tableau in rowArray and columnArray (packed mode)
+     model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                         updates, spareColumn2, spareColumn1);
+     // update weights
+     double * weight;
+     int numberColumns = model_->numberColumns();
+     // rows
+     reducedCost = model_->djRegion(0);
+     int addSequence = model_->numberColumns();;
+
+     number = updates->getNumElements();
+     index = updates->getIndices();
+     updateBy = updates->denseVector();
+     weight = weights_ + numberColumns;
+     // Devex
+     for (j = 0; j < number; j++) {
+          double thisWeight;
+          double pivot;
+          double value3;
+          int iSequence = index[j];
+          double value = reducedCost[iSequence];
+          double value2 = updateBy[j];
+          updateBy[j] = 0.0;
+          value -= value2;
+          reducedCost[iSequence] = value;
+          ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+
+          switch(status) {
+
+          case ClpSimplex::basic:
+               infeasible_->zero(iSequence + addSequence);
+          case ClpSimplex::isFixed:
+               break;
+          case ClpSimplex::isFree:
+          case ClpSimplex::superBasic:
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               value3 = pivot * pivot * devex_;
+               if (reference(iSequence + numberColumns))
+                    value3 += 1.0;
+               weight[iSequence] = CoinMax(0.99 * thisWeight, value3);
+               if (fabs(value) > FREE_ACCEPT * tolerance) {
+                    // we are going to bias towards free (but only if reasonable)
+                    value *= FREE_BIAS;
+                    // store square in list
+                    if (infeas[iSequence+addSequence])
+                         infeas[iSequence+addSequence] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence + addSequence, value * value);
+               } else {
+                    infeasible_->zero(iSequence + addSequence);
+               }
+               break;
+          case ClpSimplex::atUpperBound:
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               value3 = pivot * pivot * devex_;
+               if (reference(iSequence + numberColumns))
+                    value3 += 1.0;
+               weight[iSequence] = CoinMax(0.99 * thisWeight, value3);
+	       iSequence += addSequence;
+               if (value > tolerance) {
+                    // store square in list
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+    		    value *= value*CLP_PRIMAL_SLACK_MULTIPLIER;
+#else
+		    value *= value;
+#endif
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence , value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+               break;
+          case ClpSimplex::atLowerBound:
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               value3 = pivot * pivot * devex_;
+               if (reference(iSequence + numberColumns))
+                    value3 += 1.0;
+               weight[iSequence] = CoinMax(0.99 * thisWeight, value3);
+	       iSequence += addSequence;
+               if (value < -tolerance) {
+                    // store square in list
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+    		    value *= value*CLP_PRIMAL_SLACK_MULTIPLIER;
+#else
+		    value *= value;
+#endif
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence , value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+          }
+     }
+
+     // columns
+     weight = weights_;
+
+     scaleFactor = -scaleFactor;
+     reducedCost = model_->djRegion(1);
+     number = spareColumn1->getNumElements();
+     index = spareColumn1->getIndices();
+     updateBy = spareColumn1->denseVector();
+
+     // Devex
+
+     for (j = 0; j < number; j++) {
+          double thisWeight;
+          double pivot;
+          double value3;
+          int iSequence = index[j];
+          double value = reducedCost[iSequence];
+          double value2 = updateBy[j];
+          value -= value2;
+          updateBy[j] = 0.0;
+          reducedCost[iSequence] = value;
+          ClpSimplex::Status status = model_->getStatus(iSequence);
+
+          switch(status) {
+
+          case ClpSimplex::basic:
+               infeasible_->zero(iSequence);
+          case ClpSimplex::isFixed:
+               break;
+          case ClpSimplex::isFree:
+          case ClpSimplex::superBasic:
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               value3 = pivot * pivot * devex_;
+               if (reference(iSequence))
+                    value3 += 1.0;
+               weight[iSequence] = CoinMax(0.99 * thisWeight, value3);
+               if (fabs(value) > FREE_ACCEPT * tolerance) {
+                    // we are going to bias towards free (but only if reasonable)
+                    value *= FREE_BIAS;
+                    // store square in list
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence, value * value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+               break;
+          case ClpSimplex::atUpperBound:
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               value3 = pivot * pivot * devex_;
+               if (reference(iSequence))
+                    value3 += 1.0;
+               weight[iSequence] = CoinMax(0.99 * thisWeight, value3);
+               if (value > tolerance) {
+                    // store square in list
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence, value * value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+               break;
+          case ClpSimplex::atLowerBound:
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               value3 = pivot * pivot * devex_;
+               if (reference(iSequence))
+                    value3 += 1.0;
+               weight[iSequence] = CoinMax(0.99 * thisWeight, value3);
+               if (value < -tolerance) {
+                    // store square in list
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence, value * value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+          }
+     }
+     // restore outgoing weight
+     if (sequenceOut >= 0)
+          weights_[sequenceOut] = outgoingWeight;
+     // make sure infeasibility on incoming is 0.0
+     infeasible_->zero(sequenceIn);
+     spareRow2->setNumElements(0);
+     //#define SOME_DEBUG_1
+#ifdef SOME_DEBUG_1
+     // check for accuracy
+     int iCheck = 892;
+     //printf("weight for iCheck is %g\n",weights_[iCheck]);
+     int numberRows = model_->numberRows();
+     //int numberColumns = model_->numberColumns();
+     for (iCheck = 0; iCheck < numberRows + numberColumns; iCheck++) {
+          if (model_->getStatus(iCheck) != ClpSimplex::basic &&
+                    !model_->getStatus(iCheck) != ClpSimplex::isFixed)
+               checkAccuracy(iCheck, 1.0e-1, updates, spareRow2);
+     }
+#endif
+     updates->setNumElements(0);
+     spareColumn1->setNumElements(0);
+}
+// Update djs, weights for Steepest
+void
+ClpPrimalColumnSteepest::djsAndSteepest(CoinIndexedVector * updates,
+                                        CoinIndexedVector * spareRow2,
+                                        CoinIndexedVector * spareColumn1,
+                                        CoinIndexedVector * spareColumn2)
+{
+     int j;
+     int number = 0;
+     int * index;
+     double * updateBy;
+     double * reducedCost;
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     // for weights update we use pivotSequence
+     // unset in case sub flip
+     assert (pivotSequence_ >= 0);
+     assert (model_->pivotVariable()[pivotSequence_] == model_->sequenceIn());
+     double * infeas = infeasible_->denseVector();
+     double scaleFactor = 1.0 / updates->denseVector()[0]; // as formula is with 1.0
+     assert (updates->getIndices()[0] == pivotSequence_);
+     pivotSequence_ = -1;
+     //updates->scanAndPack();
+     model_->factorization()->updateColumnTranspose(spareRow2, updates);
+     //alternateWeights_->scanAndPack();
+     model_->factorization()->updateColumnTranspose(spareRow2,
+               alternateWeights_);
+     // and we can see if reference
+     int sequenceIn = model_->sequenceIn();
+     double referenceIn;
+     if (mode_ != 1) {
+          if(reference(sequenceIn))
+               referenceIn = 1.0;
+          else
+               referenceIn = 0.0;
+     } else {
+          referenceIn = -1.0;
+     }
+     // save outgoing weight round update
+     double outgoingWeight = 0.0;
+     int sequenceOut = model_->sequenceOut();
+     if (sequenceOut >= 0)
+          outgoingWeight = weights_[sequenceOut];
+     // update row weights here so we can scale alternateWeights_
+     // update weights
+     double * weight;
+     double * other = alternateWeights_->denseVector();
+     int numberColumns = model_->numberColumns();
+     // rows
+     reducedCost = model_->djRegion(0);
+     int addSequence = model_->numberColumns();;
+
+     number = updates->getNumElements();
+     index = updates->getIndices();
+     updateBy = updates->denseVector();
+     weight = weights_ + numberColumns;
+
+     for (j = 0; j < number; j++) {
+          double thisWeight;
+          double pivot;
+          double modification;
+          double pivotSquared;
+          int iSequence = index[j];
+          double value2 = updateBy[j];
+          ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+          double value;
+
+          switch(status) {
+
+          case ClpSimplex::basic:
+               infeasible_->zero(iSequence + addSequence);
+               reducedCost[iSequence] = 0.0;
+          case ClpSimplex::isFixed:
+               break;
+          case ClpSimplex::isFree:
+          case ClpSimplex::superBasic:
+               value = reducedCost[iSequence] - value2;
+               modification = other[iSequence];
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               pivotSquared = pivot * pivot;
+
+               thisWeight += pivotSquared * devex_ + pivot * modification;
+               reducedCost[iSequence] = value;
+               if (thisWeight < TRY_NORM) {
+                    if (mode_ == 1) {
+                         // steepest
+                         thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+                    } else {
+                         // exact
+                         thisWeight = referenceIn * pivotSquared;
+                         if (reference(iSequence + numberColumns))
+                              thisWeight += 1.0;
+                         thisWeight = CoinMax(thisWeight, TRY_NORM);
+                    }
+               }
+               weight[iSequence] = thisWeight;
+               if (fabs(value) > FREE_ACCEPT * tolerance) {
+                    // we are going to bias towards free (but only if reasonable)
+                    value *= FREE_BIAS;
+                    // store square in list
+                    if (infeas[iSequence+addSequence])
+                         infeas[iSequence+addSequence] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence + addSequence, value * value);
+               } else {
+                    infeasible_->zero(iSequence + addSequence);
+               }
+               break;
+          case ClpSimplex::atUpperBound:
+               value = reducedCost[iSequence] - value2;
+               modification = other[iSequence];
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               pivotSquared = pivot * pivot;
+
+               thisWeight += pivotSquared * devex_ + pivot * modification;
+               reducedCost[iSequence] = value;
+               if (thisWeight < TRY_NORM) {
+                    if (mode_ == 1) {
+                         // steepest
+                         thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+                    } else {
+                         // exact
+                         thisWeight = referenceIn * pivotSquared;
+                         if (reference(iSequence + numberColumns))
+                              thisWeight += 1.0;
+                         thisWeight = CoinMax(thisWeight, TRY_NORM);
+                    }
+               }
+               weight[iSequence] = thisWeight;
+	       iSequence += addSequence;
+               if (value > tolerance) {
+                    // store square in list
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+    		    value *= value*CLP_PRIMAL_SLACK_MULTIPLIER;
+#else
+		    value *= value;
+#endif
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence , value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+               break;
+          case ClpSimplex::atLowerBound:
+               value = reducedCost[iSequence] - value2;
+               modification = other[iSequence];
+               thisWeight = weight[iSequence];
+               // row has -1
+               pivot = value2 * scaleFactor;
+               pivotSquared = pivot * pivot;
+
+               thisWeight += pivotSquared * devex_ + pivot * modification;
+               reducedCost[iSequence] = value;
+               if (thisWeight < TRY_NORM) {
+                    if (mode_ == 1) {
+                         // steepest
+                         thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+                    } else {
+                         // exact
+                         thisWeight = referenceIn * pivotSquared;
+                         if (reference(iSequence + numberColumns))
+                              thisWeight += 1.0;
+                         thisWeight = CoinMax(thisWeight, TRY_NORM);
+                    }
+               }
+               weight[iSequence] = thisWeight;
+	       iSequence += addSequence;
+               if (value < -tolerance) {
+                    // store square in list
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+    		    value *= value*CLP_PRIMAL_SLACK_MULTIPLIER;
+#else
+		    value *= value;
+#endif
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence, value);
+               } else {
+                    infeasible_->zero(iSequence); 
+               }
+          }
+     }
+     // put row of tableau in rowArray and columnArray (packed)
+     // get subset which have nonzero tableau elements
+     transposeTimes2(updates, spareColumn1, alternateWeights_, spareColumn2, spareRow2,
+                     -scaleFactor);
+     // zero updateBy
+     CoinZeroN(updateBy, number);
+     alternateWeights_->clear();
+     // columns
+     assert (scaleFactor);
+     reducedCost = model_->djRegion(1);
+     number = spareColumn1->getNumElements();
+     index = spareColumn1->getIndices();
+     updateBy = spareColumn1->denseVector();
+
+     for (j = 0; j < number; j++) {
+          int iSequence = index[j];
+          double value = reducedCost[iSequence];
+          double value2 = updateBy[j];
+          updateBy[j] = 0.0;
+          value -= value2;
+          reducedCost[iSequence] = value;
+          ClpSimplex::Status status = model_->getStatus(iSequence);
+
+          switch(status) {
+
+          case ClpSimplex::basic:
+          case ClpSimplex::isFixed:
+               break;
+          case ClpSimplex::isFree:
+          case ClpSimplex::superBasic:
+               if (fabs(value) > FREE_ACCEPT * tolerance) {
+                    // we are going to bias towards free (but only if reasonable)
+                    value *= FREE_BIAS;
+                    // store square in list
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence, value * value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+               break;
+          case ClpSimplex::atUpperBound:
+               if (value > tolerance) {
+                    // store square in list
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence, value * value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+               break;
+          case ClpSimplex::atLowerBound:
+               if (value < -tolerance) {
+                    // store square in list
+                    if (infeas[iSequence])
+                         infeas[iSequence] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(iSequence, value * value);
+               } else {
+                    infeasible_->zero(iSequence);
+               }
+          }
+     }
+     // restore outgoing weight
+     if (sequenceOut >= 0)
+          weights_[sequenceOut] = outgoingWeight;
+     // make sure infeasibility on incoming is 0.0
+     infeasible_->zero(sequenceIn);
+     spareColumn2->setNumElements(0);
+     //#define SOME_DEBUG_1
+#ifdef SOME_DEBUG_1
+     // check for accuracy
+     int iCheck = 892;
+     //printf("weight for iCheck is %g\n",weights_[iCheck]);
+     int numberRows = model_->numberRows();
+     //int numberColumns = model_->numberColumns();
+     for (iCheck = 0; iCheck < numberRows + numberColumns; iCheck++) {
+          if (model_->getStatus(iCheck) != ClpSimplex::basic &&
+                    !model_->getStatus(iCheck) != ClpSimplex::isFixed)
+               checkAccuracy(iCheck, 1.0e-1, updates, spareRow2);
+     }
+#endif
+     updates->setNumElements(0);
+     spareColumn1->setNumElements(0);
+}
+// Update djs, weights for Devex
+void
+ClpPrimalColumnSteepest::djsAndDevex2(CoinIndexedVector * updates,
+                                      CoinIndexedVector * spareRow2,
+                                      CoinIndexedVector * spareColumn1,
+                                      CoinIndexedVector * spareColumn2)
+{
+     int iSection, j;
+     int number = 0;
+     int * index;
+     double * updateBy;
+     double * reducedCost;
+     // dj could be very small (or even zero - take care)
+     double dj = model_->dualIn();
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     int pivotRow = model_->pivotRow();
+     double * infeas = infeasible_->denseVector();
+     //updates->scanAndPack();
+     model_->factorization()->updateColumnTranspose(spareRow2, updates);
+
+     // put row of tableau in rowArray and columnArray
+     model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                         updates, spareColumn2, spareColumn1);
+     // normal
+     for (iSection = 0; iSection < 2; iSection++) {
+
+          reducedCost = model_->djRegion(iSection);
+          int addSequence;
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	  double slack_multiplier;
+#endif
+
+          if (!iSection) {
+               number = updates->getNumElements();
+               index = updates->getIndices();
+               updateBy = updates->denseVector();
+               addSequence = model_->numberColumns();
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	       slack_multiplier = CLP_PRIMAL_SLACK_MULTIPLIER;
+#endif
+          } else {
+               number = spareColumn1->getNumElements();
+               index = spareColumn1->getIndices();
+               updateBy = spareColumn1->denseVector();
+               addSequence = 0;
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	       slack_multiplier = 1.0;
+#endif
+          }
+
+          for (j = 0; j < number; j++) {
+               int iSequence = index[j];
+               double value = reducedCost[iSequence];
+               value -= updateBy[j];
+               updateBy[j] = 0.0;
+               reducedCost[iSequence] = value;
+               ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+                    infeasible_->zero(iSequence + addSequence);
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    if (fabs(value) > FREE_ACCEPT * tolerance) {
+                         // we are going to bias towards free (but only if reasonable)
+                         value *= FREE_BIAS;
+                         // store square in list
+                         if (infeas[iSequence+addSequence])
+                              infeas[iSequence+addSequence] = value * value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence + addSequence, value * value);
+                    } else {
+                         infeasible_->zero(iSequence + addSequence);
+                    }
+                    break;
+               case ClpSimplex::atUpperBound:
+	            iSequence += addSequence;
+                    if (value > tolerance) {
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+  		        value *= value*slack_multiplier;
+#else
+		        value *= value;
+#endif
+                         // store square in list
+                         if (infeas[iSequence])
+                              infeas[iSequence] = value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence, value);
+                    } else {
+                         infeasible_->zero(iSequence);
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+	            iSequence += addSequence;
+                    if (value < -tolerance) {
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+  		        value *= value*slack_multiplier;
+#else
+		        value *= value;
+#endif
+                         // store square in list
+                         if (infeas[iSequence])
+                              infeas[iSequence] = value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence, value);
+                    } else {
+                         infeasible_->zero(iSequence);
+                    }
+               }
+          }
+     }
+     // They are empty
+     updates->setNumElements(0);
+     spareColumn1->setNumElements(0);
+     // make sure infeasibility on incoming is 0.0
+     int sequenceIn = model_->sequenceIn();
+     infeasible_->zero(sequenceIn);
+     // for weights update we use pivotSequence
+     if (pivotSequence_ >= 0) {
+          pivotRow = pivotSequence_;
+          // unset in case sub flip
+          pivotSequence_ = -1;
+          // make sure infeasibility on incoming is 0.0
+          const int * pivotVariable = model_->pivotVariable();
+          sequenceIn = pivotVariable[pivotRow];
+          infeasible_->zero(sequenceIn);
+          // and we can see if reference
+          //double referenceIn = 0.0;
+          //if (mode_ != 1 && reference(sequenceIn))
+	  //   referenceIn = 1.0;
+          // save outgoing weight round update
+          double outgoingWeight = 0.0;
+          int sequenceOut = model_->sequenceOut();
+          if (sequenceOut >= 0)
+               outgoingWeight = weights_[sequenceOut];
+          // update weights
+          updates->setNumElements(0);
+          spareColumn1->setNumElements(0);
+          // might as well set dj to 1
+          dj = 1.0;
+          updates->insert(pivotRow, -dj);
+          model_->factorization()->updateColumnTranspose(spareRow2, updates);
+          // put row of tableau in rowArray and columnArray
+          model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                              updates, spareColumn2, spareColumn1);
+          double * weight;
+          int numberColumns = model_->numberColumns();
+          // rows
+          number = updates->getNumElements();
+          index = updates->getIndices();
+          updateBy = updates->denseVector();
+          weight = weights_ + numberColumns;
+
+          assert (devex_ > 0.0);
+          for (j = 0; j < number; j++) {
+               int iSequence = index[j];
+               double thisWeight = weight[iSequence];
+               // row has -1
+               double pivot = - updateBy[iSequence];
+               updateBy[iSequence] = 0.0;
+               double value = pivot * pivot * devex_;
+               if (reference(iSequence + numberColumns))
+                    value += 1.0;
+               weight[iSequence] = CoinMax(0.99 * thisWeight, value);
+          }
+
+          // columns
+          weight = weights_;
+
+          number = spareColumn1->getNumElements();
+          index = spareColumn1->getIndices();
+          updateBy = spareColumn1->denseVector();
+          for (j = 0; j < number; j++) {
+               int iSequence = index[j];
+               double thisWeight = weight[iSequence];
+               // row has -1
+               double pivot = updateBy[iSequence];
+               updateBy[iSequence] = 0.0;
+               double value = pivot * pivot * devex_;
+               if (reference(iSequence))
+                    value += 1.0;
+               weight[iSequence] = CoinMax(0.99 * thisWeight, value);
+          }
+          // restore outgoing weight
+          if (sequenceOut >= 0)
+               weights_[sequenceOut] = outgoingWeight;
+          spareColumn2->setNumElements(0);
+          //#define SOME_DEBUG_1
+#ifdef SOME_DEBUG_1
+          // check for accuracy
+          int iCheck = 892;
+          //printf("weight for iCheck is %g\n",weights_[iCheck]);
+          int numberRows = model_->numberRows();
+          //int numberColumns = model_->numberColumns();
+          for (iCheck = 0; iCheck < numberRows + numberColumns; iCheck++) {
+               if (model_->getStatus(iCheck) != ClpSimplex::basic &&
+                         !model_->getStatus(iCheck) != ClpSimplex::isFixed)
+                    checkAccuracy(iCheck, 1.0e-1, updates, spareRow2);
+          }
+#endif
+          updates->setNumElements(0);
+          spareColumn1->setNumElements(0);
+     }
+}
+// Update djs, weights for Steepest
+void
+ClpPrimalColumnSteepest::djsAndSteepest2(CoinIndexedVector * updates,
+          CoinIndexedVector * spareRow2,
+          CoinIndexedVector * spareColumn1,
+          CoinIndexedVector * spareColumn2)
+{
+     int iSection, j;
+     int number = 0;
+     int * index;
+     double * updateBy;
+     double * reducedCost;
+     // dj could be very small (or even zero - take care)
+     double dj = model_->dualIn();
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     int pivotRow = model_->pivotRow();
+     double * infeas = infeasible_->denseVector();
+     //updates->scanAndPack();
+     model_->factorization()->updateColumnTranspose(spareRow2, updates);
+
+     // put row of tableau in rowArray and columnArray
+     model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                         updates, spareColumn2, spareColumn1);
+     // normal
+     for (iSection = 0; iSection < 2; iSection++) {
+
+          reducedCost = model_->djRegion(iSection);
+          int addSequence;
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	  double slack_multiplier;
+#endif
+
+          if (!iSection) {
+               number = updates->getNumElements();
+               index = updates->getIndices();
+               updateBy = updates->denseVector();
+               addSequence = model_->numberColumns();
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	       slack_multiplier = CLP_PRIMAL_SLACK_MULTIPLIER;
+#endif
+          } else {
+               number = spareColumn1->getNumElements();
+               index = spareColumn1->getIndices();
+               updateBy = spareColumn1->denseVector();
+               addSequence = 0;
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER 
+	       slack_multiplier = 1.0;
+#endif
+          }
+
+          for (j = 0; j < number; j++) {
+               int iSequence = index[j];
+               double value = reducedCost[iSequence];
+               value -= updateBy[j];
+               updateBy[j] = 0.0;
+               reducedCost[iSequence] = value;
+               ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+                    infeasible_->zero(iSequence + addSequence);
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    if (fabs(value) > FREE_ACCEPT * tolerance) {
+                         // we are going to bias towards free (but only if reasonable)
+                         value *= FREE_BIAS;
+                         // store square in list
+                         if (infeas[iSequence+addSequence])
+                              infeas[iSequence+addSequence] = value * value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence + addSequence, value * value);
+                    } else {
+                         infeasible_->zero(iSequence + addSequence);
+                    }
+                    break;
+               case ClpSimplex::atUpperBound:
+	            iSequence += addSequence;
+                    if (value > tolerance) {
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+  		        value *= value*slack_multiplier;
+#else
+		        value *= value;
+#endif
+                         // store square in list
+                         if (infeas[iSequence])
+                              infeas[iSequence] = value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence, value);
+                    } else {
+                         infeasible_->zero(iSequence);
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+	            iSequence += addSequence;
+                    if (value < -tolerance) {
+#ifdef CLP_PRIMAL_SLACK_MULTIPLIER
+  		        value *= value*slack_multiplier;
+#else
+		        value *= value;
+#endif
+                         // store square in list
+                         if (infeas[iSequence])
+                              infeas[iSequence] = value; // already there
+                         else
+                              infeasible_->quickAdd(iSequence, value);
+                    } else {
+                         infeasible_->zero(iSequence);
+                    }
+               }
+          }
+     }
+     // we can zero out as will have to get pivot row
+     // ***** move
+     updates->setNumElements(0);
+     spareColumn1->setNumElements(0);
+     if (pivotRow >= 0) {
+          // make sure infeasibility on incoming is 0.0
+          int sequenceIn = model_->sequenceIn();
+          infeasible_->zero(sequenceIn);
+     }
+     // for weights update we use pivotSequence
+     pivotRow = pivotSequence_;
+     // unset in case sub flip
+     pivotSequence_ = -1;
+     if (pivotRow >= 0) {
+          // make sure infeasibility on incoming is 0.0
+          const int * pivotVariable = model_->pivotVariable();
+          int sequenceIn = pivotVariable[pivotRow];
+          assert (sequenceIn == model_->sequenceIn());
+          infeasible_->zero(sequenceIn);
+          // and we can see if reference
+          double referenceIn;
+          if (mode_ != 1) {
+               if(reference(sequenceIn))
+                    referenceIn = 1.0;
+               else
+                    referenceIn = 0.0;
+          } else {
+               referenceIn = -1.0;
+          }
+          // save outgoing weight round update
+          double outgoingWeight = 0.0;
+          int sequenceOut = model_->sequenceOut();
+          if (sequenceOut >= 0)
+               outgoingWeight = weights_[sequenceOut];
+          // update weights
+          updates->setNumElements(0);
+          spareColumn1->setNumElements(0);
+          // might as well set dj to 1
+          dj = -1.0;
+          updates->createPacked(1, &pivotRow, &dj);
+          model_->factorization()->updateColumnTranspose(spareRow2, updates);
+          bool needSubset =  (mode_ < 4 || numberSwitched_ > 1 || mode_ >= 10);
+
+          double * weight;
+          double * other = alternateWeights_->denseVector();
+          int numberColumns = model_->numberColumns();
+          // rows
+          number = updates->getNumElements();
+          index = updates->getIndices();
+          updateBy = updates->denseVector();
+          weight = weights_ + numberColumns;
+          if (needSubset) {
+               // now update weight update array
+               model_->factorization()->updateColumnTranspose(spareRow2,
+                         alternateWeights_);
+               // do alternateWeights_ here so can scale
+               for (j = 0; j < number; j++) {
+                    int iSequence = index[j];
+                    assert (iSequence >= 0 && iSequence < model_->numberRows());
+                    double thisWeight = weight[iSequence];
+                    // row has -1
+                    double pivot = - updateBy[j];
+                    double modification = other[iSequence];
+                    double pivotSquared = pivot * pivot;
+
+                    thisWeight += pivotSquared * devex_ + pivot * modification;
+                    if (thisWeight < TRY_NORM) {
+                         if (mode_ == 1) {
+                              // steepest
+                              thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+                         } else {
+                              // exact
+                              thisWeight = referenceIn * pivotSquared;
+                              if (reference(iSequence + numberColumns))
+                                   thisWeight += 1.0;
+                              thisWeight = CoinMax(thisWeight, TRY_NORM);
+                         }
+                    }
+                    weight[iSequence] = thisWeight;
+               }
+               transposeTimes2(updates, spareColumn1, alternateWeights_, spareColumn2, spareRow2, 0.0);
+          } else {
+               // put row of tableau in rowArray and columnArray
+               model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                                   updates, spareColumn2, spareColumn1);
+          }
+
+          if (needSubset) {
+               CoinZeroN(updateBy, number);
+          } else if (mode_ == 4) {
+               // Devex
+               assert (devex_ > 0.0);
+               for (j = 0; j < number; j++) {
+                    int iSequence = index[j];
+                    double thisWeight = weight[iSequence];
+                    // row has -1
+                    double pivot = -updateBy[j];
+                    updateBy[j] = 0.0;
+                    double value = pivot * pivot * devex_;
+                    if (reference(iSequence + numberColumns))
+                         value += 1.0;
+                    weight[iSequence] = CoinMax(0.99 * thisWeight, value);
+               }
+          }
+
+          // columns
+          weight = weights_;
+
+          number = spareColumn1->getNumElements();
+          index = spareColumn1->getIndices();
+          updateBy = spareColumn1->denseVector();
+          if (needSubset) {
+               // Exact - already done
+          } else if (mode_ == 4) {
+               // Devex
+               for (j = 0; j < number; j++) {
+                    int iSequence = index[j];
+                    double thisWeight = weight[iSequence];
+                    // row has -1
+                    double pivot = updateBy[j];
+                    updateBy[j] = 0.0;
+                    double value = pivot * pivot * devex_;
+                    if (reference(iSequence))
+                         value += 1.0;
+                    weight[iSequence] = CoinMax(0.99 * thisWeight, value);
+               }
+          }
+          // restore outgoing weight
+          if (sequenceOut >= 0)
+               weights_[sequenceOut] = outgoingWeight;
+          alternateWeights_->clear();
+          spareColumn2->setNumElements(0);
+          //#define SOME_DEBUG_1
+#ifdef SOME_DEBUG_1
+          // check for accuracy
+          int iCheck = 892;
+          //printf("weight for iCheck is %g\n",weights_[iCheck]);
+          int numberRows = model_->numberRows();
+          //int numberColumns = model_->numberColumns();
+          for (iCheck = 0; iCheck < numberRows + numberColumns; iCheck++) {
+               if (model_->getStatus(iCheck) != ClpSimplex::basic &&
+                         !model_->getStatus(iCheck) != ClpSimplex::isFixed)
+                    checkAccuracy(iCheck, 1.0e-1, updates, spareRow2);
+          }
+#endif
+     }
+     updates->setNumElements(0);
+     spareColumn1->setNumElements(0);
+}
+// Updates two arrays for steepest
+void
+ClpPrimalColumnSteepest::transposeTimes2(const CoinIndexedVector * pi1, CoinIndexedVector * dj1,
+          const CoinIndexedVector * pi2, CoinIndexedVector * dj2,
+          CoinIndexedVector * spare,
+          double scaleFactor)
+{
+     // see if reference
+     int sequenceIn = model_->sequenceIn();
+     double referenceIn;
+     if (mode_ != 1) {
+          if(reference(sequenceIn))
+               referenceIn = 1.0;
+          else
+               referenceIn = 0.0;
+     } else {
+          referenceIn = -1.0;
+     }
+     if (model_->clpMatrix()->canCombine(model_, pi1)) {
+          // put row of tableau in rowArray and columnArray
+          model_->clpMatrix()->transposeTimes2(model_, pi1, dj1, pi2, spare, referenceIn, devex_,
+                                               reference_,
+                                               weights_, scaleFactor);
+     } else {
+          // put row of tableau in rowArray and columnArray
+          model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                              pi1, dj2, dj1);
+          // get subset which have nonzero tableau elements
+          model_->clpMatrix()->subsetTransposeTimes(model_, pi2, dj1, dj2);
+          bool killDjs = (scaleFactor == 0.0);
+          if (!scaleFactor)
+               scaleFactor = 1.0;
+          // columns
+          double * weight = weights_;
+
+          int number = dj1->getNumElements();
+          const int * index = dj1->getIndices();
+          double * updateBy = dj1->denseVector();
+          double * updateBy2 = dj2->denseVector();
+
+          for (int j = 0; j < number; j++) {
+               double thisWeight;
+               double pivot;
+               double pivotSquared;
+               int iSequence = index[j];
+               double value2 = updateBy[j];
+               if (killDjs)
+                    updateBy[j] = 0.0;
+               double modification = updateBy2[j];
+               updateBy2[j] = 0.0;
+               ClpSimplex::Status status = model_->getStatus(iSequence);
+
+               if (status != ClpSimplex::basic && status != ClpSimplex::isFixed) {
+                    thisWeight = weight[iSequence];
+                    pivot = value2 * scaleFactor;
+                    pivotSquared = pivot * pivot;
+
+                    thisWeight += pivotSquared * devex_ + pivot * modification;
+                    if (thisWeight < TRY_NORM) {
+                         if (referenceIn < 0.0) {
+                              // steepest
+                              thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+                         } else {
+                              // exact
+                              thisWeight = referenceIn * pivotSquared;
+                              if (reference(iSequence))
+                                   thisWeight += 1.0;
+                              thisWeight = CoinMax(thisWeight, TRY_NORM);
+                         }
+                    }
+                    weight[iSequence] = thisWeight;
+               }
+          }
+     }
+     dj2->setNumElements(0);
+}
+// Update weights for Devex
+void
+ClpPrimalColumnSteepest::justDevex(CoinIndexedVector * updates,
+                                   CoinIndexedVector * spareRow2,
+                                   CoinIndexedVector * spareColumn1,
+                                   CoinIndexedVector * spareColumn2)
+{
+     int j;
+     int number = 0;
+     int * index;
+     double * updateBy;
+     // dj could be very small (or even zero - take care)
+     double dj = model_->dualIn();
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     int pivotRow = model_->pivotRow();
+     // for weights update we use pivotSequence
+     pivotRow = pivotSequence_;
+     assert (pivotRow >= 0);
+     // make sure infeasibility on incoming is 0.0
+     const int * pivotVariable = model_->pivotVariable();
+     int sequenceIn = pivotVariable[pivotRow];
+     infeasible_->zero(sequenceIn);
+     // and we can see if reference
+     //double referenceIn = 0.0;
+     //if (mode_ != 1 && reference(sequenceIn))
+     //   referenceIn = 1.0;
+     // save outgoing weight round update
+     double outgoingWeight = 0.0;
+     int sequenceOut = model_->sequenceOut();
+     if (sequenceOut >= 0)
+          outgoingWeight = weights_[sequenceOut];
+     assert (!updates->getNumElements());
+     assert (!spareColumn1->getNumElements());
+     // unset in case sub flip
+     pivotSequence_ = -1;
+     // might as well set dj to 1
+     dj = -1.0;
+     updates->createPacked(1, &pivotRow, &dj);
+     model_->factorization()->updateColumnTranspose(spareRow2, updates);
+     // put row of tableau in rowArray and columnArray
+     model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                         updates, spareColumn2, spareColumn1);
+     double * weight;
+     int numberColumns = model_->numberColumns();
+     // rows
+     number = updates->getNumElements();
+     index = updates->getIndices();
+     updateBy = updates->denseVector();
+     weight = weights_ + numberColumns;
+
+     // Devex
+     assert (devex_ > 0.0);
+     for (j = 0; j < number; j++) {
+          int iSequence = index[j];
+          double thisWeight = weight[iSequence];
+          // row has -1
+          double pivot = - updateBy[j];
+          updateBy[j] = 0.0;
+          double value = pivot * pivot * devex_;
+          if (reference(iSequence + numberColumns))
+               value += 1.0;
+          weight[iSequence] = CoinMax(0.99 * thisWeight, value);
+     }
+
+     // columns
+     weight = weights_;
+
+     number = spareColumn1->getNumElements();
+     index = spareColumn1->getIndices();
+     updateBy = spareColumn1->denseVector();
+     // Devex
+     for (j = 0; j < number; j++) {
+          int iSequence = index[j];
+          double thisWeight = weight[iSequence];
+          // row has -1
+          double pivot = updateBy[j];
+          updateBy[j] = 0.0;
+          double value = pivot * pivot * devex_;
+          if (reference(iSequence))
+               value += 1.0;
+          weight[iSequence] = CoinMax(0.99 * thisWeight, value);
+     }
+     // restore outgoing weight
+     if (sequenceOut >= 0)
+          weights_[sequenceOut] = outgoingWeight;
+     spareColumn2->setNumElements(0);
+     //#define SOME_DEBUG_1
+#ifdef SOME_DEBUG_1
+     // check for accuracy
+     int iCheck = 892;
+     //printf("weight for iCheck is %g\n",weights_[iCheck]);
+     int numberRows = model_->numberRows();
+     //int numberColumns = model_->numberColumns();
+     for (iCheck = 0; iCheck < numberRows + numberColumns; iCheck++) {
+          if (model_->getStatus(iCheck) != ClpSimplex::basic &&
+                    !model_->getStatus(iCheck) != ClpSimplex::isFixed)
+               checkAccuracy(iCheck, 1.0e-1, updates, spareRow2);
+     }
+#endif
+     updates->setNumElements(0);
+     spareColumn1->setNumElements(0);
+}
+// Update weights for Steepest
+void
+ClpPrimalColumnSteepest::justSteepest(CoinIndexedVector * updates,
+                                      CoinIndexedVector * spareRow2,
+                                      CoinIndexedVector * spareColumn1,
+                                      CoinIndexedVector * spareColumn2)
+{
+     int j;
+     int number = 0;
+     int * index;
+     double * updateBy;
+     // dj could be very small (or even zero - take care)
+     double dj = model_->dualIn();
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     int pivotRow = model_->pivotRow();
+     // for weights update we use pivotSequence
+     pivotRow = pivotSequence_;
+     // unset in case sub flip
+     pivotSequence_ = -1;
+     assert (pivotRow >= 0);
+     // make sure infeasibility on incoming is 0.0
+     const int * pivotVariable = model_->pivotVariable();
+     int sequenceIn = pivotVariable[pivotRow];
+     infeasible_->zero(sequenceIn);
+     // and we can see if reference
+     double referenceIn = 0.0;
+     if (mode_ != 1 && reference(sequenceIn))
+          referenceIn = 1.0;
+     // save outgoing weight round update
+     double outgoingWeight = 0.0;
+     int sequenceOut = model_->sequenceOut();
+     if (sequenceOut >= 0)
+          outgoingWeight = weights_[sequenceOut];
+     assert (!updates->getNumElements());
+     assert (!spareColumn1->getNumElements());
+     // update weights
+     //updates->setNumElements(0);
+     //spareColumn1->setNumElements(0);
+     // might as well set dj to 1
+     dj = -1.0;
+     updates->createPacked(1, &pivotRow, &dj);
+     model_->factorization()->updateColumnTranspose(spareRow2, updates);
+     // put row of tableau in rowArray and columnArray
+     model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                         updates, spareColumn2, spareColumn1);
+     double * weight;
+     double * other = alternateWeights_->denseVector();
+     int numberColumns = model_->numberColumns();
+     // rows
+     number = updates->getNumElements();
+     index = updates->getIndices();
+     updateBy = updates->denseVector();
+     weight = weights_ + numberColumns;
+
+     // Exact
+     // now update weight update array
+     //alternateWeights_->scanAndPack();
+     model_->factorization()->updateColumnTranspose(spareRow2,
+               alternateWeights_);
+     // get subset which have nonzero tableau elements
+     model_->clpMatrix()->subsetTransposeTimes(model_, alternateWeights_,
+               spareColumn1,
+               spareColumn2);
+     for (j = 0; j < number; j++) {
+          int iSequence = index[j];
+          double thisWeight = weight[iSequence];
+          // row has -1
+          double pivot = -updateBy[j];
+          updateBy[j] = 0.0;
+          double modification = other[iSequence];
+          double pivotSquared = pivot * pivot;
+
+          thisWeight += pivotSquared * devex_ + pivot * modification;
+          if (thisWeight < TRY_NORM) {
+               if (mode_ == 1) {
+                    // steepest
+                    thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+               } else {
+                    // exact
+                    thisWeight = referenceIn * pivotSquared;
+                    if (reference(iSequence + numberColumns))
+                         thisWeight += 1.0;
+                    thisWeight = CoinMax(thisWeight, TRY_NORM);
+               }
+          }
+          weight[iSequence] = thisWeight;
+     }
+
+     // columns
+     weight = weights_;
+
+     number = spareColumn1->getNumElements();
+     index = spareColumn1->getIndices();
+     updateBy = spareColumn1->denseVector();
+     // Exact
+     double * updateBy2 = spareColumn2->denseVector();
+     for (j = 0; j < number; j++) {
+          int iSequence = index[j];
+          double thisWeight = weight[iSequence];
+          double pivot = updateBy[j];
+          updateBy[j] = 0.0;
+          double modification = updateBy2[j];
+          updateBy2[j] = 0.0;
+          double pivotSquared = pivot * pivot;
+
+          thisWeight += pivotSquared * devex_ + pivot * modification;
+          if (thisWeight < TRY_NORM) {
+               if (mode_ == 1) {
+                    // steepest
+                    thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+               } else {
+                    // exact
+                    thisWeight = referenceIn * pivotSquared;
+                    if (reference(iSequence))
+                         thisWeight += 1.0;
+                    thisWeight = CoinMax(thisWeight, TRY_NORM);
+               }
+          }
+          weight[iSequence] = thisWeight;
+     }
+     // restore outgoing weight
+     if (sequenceOut >= 0)
+          weights_[sequenceOut] = outgoingWeight;
+     alternateWeights_->clear();
+     spareColumn2->setNumElements(0);
+     //#define SOME_DEBUG_1
+#ifdef SOME_DEBUG_1
+     // check for accuracy
+     int iCheck = 892;
+     //printf("weight for iCheck is %g\n",weights_[iCheck]);
+     int numberRows = model_->numberRows();
+     //int numberColumns = model_->numberColumns();
+     for (iCheck = 0; iCheck < numberRows + numberColumns; iCheck++) {
+          if (model_->getStatus(iCheck) != ClpSimplex::basic &&
+                    !model_->getStatus(iCheck) != ClpSimplex::isFixed)
+               checkAccuracy(iCheck, 1.0e-1, updates, spareRow2);
+     }
+#endif
+     updates->setNumElements(0);
+     spareColumn1->setNumElements(0);
+}
+// Returns pivot column, -1 if none
+int
+ClpPrimalColumnSteepest::pivotColumnOldMethod(CoinIndexedVector * updates,
+          CoinIndexedVector * ,
+          CoinIndexedVector * spareRow2,
+          CoinIndexedVector * spareColumn1,
+          CoinIndexedVector * spareColumn2)
+{
+     assert(model_);
+     int iSection, j;
+     int number = 0;
+     int * index;
+     double * updateBy;
+     double * reducedCost;
+     // dj could be very small (or even zero - take care)
+     double dj = model_->dualIn();
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     int pivotRow = model_->pivotRow();
+     int anyUpdates;
+     double * infeas = infeasible_->denseVector();
+
+     // Local copy of mode so can decide what to do
+     int switchType;
+     if (mode_ == 4)
+          switchType = 5 - numberSwitched_;
+     else if (mode_ >= 10)
+          switchType = 3;
+     else
+          switchType = mode_;
+     /* switchType -
+        0 - all exact devex
+        1 - all steepest
+        2 - some exact devex
+        3 - auto some exact devex
+        4 - devex
+        5 - dantzig
+     */
+     if (updates->getNumElements()) {
+          // would have to have two goes for devex, three for steepest
+          anyUpdates = 2;
+          // add in pivot contribution
+          if (pivotRow >= 0)
+               updates->add(pivotRow, -dj);
+     } else if (pivotRow >= 0) {
+          if (fabs(dj) > 1.0e-15) {
+               // some dj
+               updates->insert(pivotRow, -dj);
+               if (fabs(dj) > 1.0e-6) {
+                    // reasonable size
+                    anyUpdates = 1;
+               } else {
+                    // too small
+                    anyUpdates = 2;
+               }
+          } else {
+               // zero dj
+               anyUpdates = -1;
+          }
+     } else if (pivotSequence_ >= 0) {
+          // just after re-factorization
+          anyUpdates = -1;
+     } else {
+          // sub flip - nothing to do
+          anyUpdates = 0;
+     }
+
+     if (anyUpdates > 0) {
+          model_->factorization()->updateColumnTranspose(spareRow2, updates);
+
+          // put row of tableau in rowArray and columnArray
+          model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                              updates, spareColumn2, spareColumn1);
+          // normal
+          for (iSection = 0; iSection < 2; iSection++) {
+
+               reducedCost = model_->djRegion(iSection);
+               int addSequence;
+
+               if (!iSection) {
+                    number = updates->getNumElements();
+                    index = updates->getIndices();
+                    updateBy = updates->denseVector();
+                    addSequence = model_->numberColumns();
+               } else {
+                    number = spareColumn1->getNumElements();
+                    index = spareColumn1->getIndices();
+                    updateBy = spareColumn1->denseVector();
+                    addSequence = 0;
+               }
+               if (!model_->nonLinearCost()->lookBothWays()) {
+
+                    for (j = 0; j < number; j++) {
+                         int iSequence = index[j];
+                         double value = reducedCost[iSequence];
+                         value -= updateBy[iSequence];
+                         reducedCost[iSequence] = value;
+                         ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+
+                         switch(status) {
+
+                         case ClpSimplex::basic:
+                              infeasible_->zero(iSequence + addSequence);
+                         case ClpSimplex::isFixed:
+                              break;
+                         case ClpSimplex::isFree:
+                         case ClpSimplex::superBasic:
+                              if (fabs(value) > FREE_ACCEPT * tolerance) {
+                                   // we are going to bias towards free (but only if reasonable)
+                                   value *= FREE_BIAS;
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   infeasible_->zero(iSequence + addSequence);
+                              }
+                              break;
+                         case ClpSimplex::atUpperBound:
+                              if (value > tolerance) {
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   infeasible_->zero(iSequence + addSequence);
+                              }
+                              break;
+                         case ClpSimplex::atLowerBound:
+                              if (value < -tolerance) {
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   infeasible_->zero(iSequence + addSequence);
+                              }
+                         }
+                    }
+               } else {
+                    ClpNonLinearCost * nonLinear = model_->nonLinearCost();
+                    // We can go up OR down
+                    for (j = 0; j < number; j++) {
+                         int iSequence = index[j];
+                         double value = reducedCost[iSequence];
+                         value -= updateBy[iSequence];
+                         reducedCost[iSequence] = value;
+                         ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+
+                         switch(status) {
+
+                         case ClpSimplex::basic:
+                              infeasible_->zero(iSequence + addSequence);
+                         case ClpSimplex::isFixed:
+                              break;
+                         case ClpSimplex::isFree:
+                         case ClpSimplex::superBasic:
+                              if (fabs(value) > FREE_ACCEPT * tolerance) {
+                                   // we are going to bias towards free (but only if reasonable)
+                                   value *= FREE_BIAS;
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   infeasible_->zero(iSequence + addSequence);
+                              }
+                              break;
+                         case ClpSimplex::atUpperBound:
+                              if (value > tolerance) {
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   // look other way - change up should be negative
+                                   value -= nonLinear->changeUpInCost(iSequence + addSequence);
+                                   if (value > -tolerance) {
+                                        infeasible_->zero(iSequence + addSequence);
+                                   } else {
+                                        // store square in list
+                                        if (infeas[iSequence+addSequence])
+                                             infeas[iSequence+addSequence] = value * value; // already there
+                                        else
+                                             infeasible_->quickAdd(iSequence + addSequence, value * value);
+                                   }
+                              }
+                              break;
+                         case ClpSimplex::atLowerBound:
+                              if (value < -tolerance) {
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   // look other way - change down should be positive
+                                   value -= nonLinear->changeDownInCost(iSequence + addSequence);
+                                   if (value < tolerance) {
+                                        infeasible_->zero(iSequence + addSequence);
+                                   } else {
+                                        // store square in list
+                                        if (infeas[iSequence+addSequence])
+                                             infeas[iSequence+addSequence] = value * value; // already there
+                                        else
+                                             infeasible_->quickAdd(iSequence + addSequence, value * value);
+                                   }
+                              }
+                         }
+                    }
+               }
+          }
+          if (anyUpdates == 2) {
+               // we can zero out as will have to get pivot row
+               updates->clear();
+               spareColumn1->clear();
+          }
+          if (pivotRow >= 0) {
+               // make sure infeasibility on incoming is 0.0
+               int sequenceIn = model_->sequenceIn();
+               infeasible_->zero(sequenceIn);
+          }
+     }
+     // make sure outgoing from last iteration okay
+     int sequenceOut = model_->sequenceOut();
+     if (sequenceOut >= 0) {
+          ClpSimplex::Status status = model_->getStatus(sequenceOut);
+          double value = model_->reducedCost(sequenceOut);
+
+          switch(status) {
+
+          case ClpSimplex::basic:
+          case ClpSimplex::isFixed:
+               break;
+          case ClpSimplex::isFree:
+          case ClpSimplex::superBasic:
+               if (fabs(value) > FREE_ACCEPT * tolerance) {
+                    // we are going to bias towards free (but only if reasonable)
+                    value *= FREE_BIAS;
+                    // store square in list
+                    if (infeas[sequenceOut])
+                         infeas[sequenceOut] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(sequenceOut, value * value);
+               } else {
+                    infeasible_->zero(sequenceOut);
+               }
+               break;
+          case ClpSimplex::atUpperBound:
+               if (value > tolerance) {
+                    // store square in list
+                    if (infeas[sequenceOut])
+                         infeas[sequenceOut] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(sequenceOut, value * value);
+               } else {
+                    infeasible_->zero(sequenceOut);
+               }
+               break;
+          case ClpSimplex::atLowerBound:
+               if (value < -tolerance) {
+                    // store square in list
+                    if (infeas[sequenceOut])
+                         infeas[sequenceOut] = value * value; // already there
+                    else
+                         infeasible_->quickAdd(sequenceOut, value * value);
+               } else {
+                    infeasible_->zero(sequenceOut);
+               }
+          }
+     }
+
+     // If in quadratic re-compute all
+     if (model_->algorithm() == 2) {
+          for (iSection = 0; iSection < 2; iSection++) {
+
+               reducedCost = model_->djRegion(iSection);
+               int addSequence;
+               int iSequence;
+
+               if (!iSection) {
+                    number = model_->numberRows();
+                    addSequence = model_->numberColumns();
+               } else {
+                    number = model_->numberColumns();
+                    addSequence = 0;
+               }
+
+               if (!model_->nonLinearCost()->lookBothWays()) {
+                    for (iSequence = 0; iSequence < number; iSequence++) {
+                         double value = reducedCost[iSequence];
+                         ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+
+                         switch(status) {
+
+                         case ClpSimplex::basic:
+                              infeasible_->zero(iSequence + addSequence);
+                         case ClpSimplex::isFixed:
+                              break;
+                         case ClpSimplex::isFree:
+                         case ClpSimplex::superBasic:
+                              if (fabs(value) > tolerance) {
+                                   // we are going to bias towards free (but only if reasonable)
+                                   value *= FREE_BIAS;
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   infeasible_->zero(iSequence + addSequence);
+                              }
+                              break;
+                         case ClpSimplex::atUpperBound:
+                              if (value > tolerance) {
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   infeasible_->zero(iSequence + addSequence);
+                              }
+                              break;
+                         case ClpSimplex::atLowerBound:
+                              if (value < -tolerance) {
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   infeasible_->zero(iSequence + addSequence);
+                              }
+                         }
+                    }
+               } else {
+                    // we can go both ways
+                    ClpNonLinearCost * nonLinear = model_->nonLinearCost();
+                    for (iSequence = 0; iSequence < number; iSequence++) {
+                         double value = reducedCost[iSequence];
+                         ClpSimplex::Status status = model_->getStatus(iSequence + addSequence);
+
+                         switch(status) {
+
+                         case ClpSimplex::basic:
+                              infeasible_->zero(iSequence + addSequence);
+                         case ClpSimplex::isFixed:
+                              break;
+                         case ClpSimplex::isFree:
+                         case ClpSimplex::superBasic:
+                              if (fabs(value) > tolerance) {
+                                   // we are going to bias towards free (but only if reasonable)
+                                   value *= FREE_BIAS;
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   infeasible_->zero(iSequence + addSequence);
+                              }
+                              break;
+                         case ClpSimplex::atUpperBound:
+                              if (value > tolerance) {
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   // look other way - change up should be negative
+                                   value -= nonLinear->changeUpInCost(iSequence + addSequence);
+                                   if (value > -tolerance) {
+                                        infeasible_->zero(iSequence + addSequence);
+                                   } else {
+                                        // store square in list
+                                        if (infeas[iSequence+addSequence])
+                                             infeas[iSequence+addSequence] = value * value; // already there
+                                        else
+                                             infeasible_->quickAdd(iSequence + addSequence, value * value);
+                                   }
+                              }
+                              break;
+                         case ClpSimplex::atLowerBound:
+                              if (value < -tolerance) {
+                                   // store square in list
+                                   if (infeas[iSequence+addSequence])
+                                        infeas[iSequence+addSequence] = value * value; // already there
+                                   else
+                                        infeasible_->quickAdd(iSequence + addSequence, value * value);
+                              } else {
+                                   // look other way - change down should be positive
+                                   value -= nonLinear->changeDownInCost(iSequence + addSequence);
+                                   if (value < tolerance) {
+                                        infeasible_->zero(iSequence + addSequence);
+                                   } else {
+                                        // store square in list
+                                        if (infeas[iSequence+addSequence])
+                                             infeas[iSequence+addSequence] = value * value; // already there
+                                        else
+                                             infeasible_->quickAdd(iSequence + addSequence, value * value);
+                                   }
+                              }
+                         }
+                    }
+               }
+          }
+     }
+     // See what sort of pricing
+     int numberWanted = 10;
+     number = infeasible_->getNumElements();
+     int numberColumns = model_->numberColumns();
+     if (switchType == 5) {
+          // we can zero out
+          updates->clear();
+          spareColumn1->clear();
+          pivotSequence_ = -1;
+          pivotRow = -1;
+          // See if to switch
+          int numberRows = model_->numberRows();
+          // ratio is done on number of columns here
+          //double ratio = static_cast<double> sizeFactorization_/static_cast<double> numberColumns;
+          double ratio = static_cast<double> (sizeFactorization_) / static_cast<double> (numberRows);
+          //double ratio = static_cast<double> sizeFactorization_/static_cast<double> model_->clpMatrix()->getNumElements();
+          if (ratio < 0.1) {
+               numberWanted = CoinMax(100, number / 200);
+          } else if (ratio < 0.3) {
+               numberWanted = CoinMax(500, number / 40);
+          } else if (ratio < 0.5 || mode_ == 5) {
+               numberWanted = CoinMax(2000, number / 10);
+               numberWanted = CoinMax(numberWanted, numberColumns / 30);
+          } else if (mode_ != 5) {
+               switchType = 4;
+               // initialize
+               numberSwitched_++;
+               // Make sure will re-do
+               delete [] weights_;
+               weights_ = NULL;
+               saveWeights(model_, 4);
+               COIN_DETAIL_PRINT(printf("switching to devex %d nel ratio %g\n", sizeFactorization_, ratio));
+               updates->clear();
+          }
+          if (model_->numberIterations() % 1000 == 0)
+	    COIN_DETAIL_PRINT(printf("numels %d ratio %g wanted %d\n", sizeFactorization_, ratio, numberWanted));
+     }
+     if(switchType == 4) {
+          // Still in devex mode
+          int numberRows = model_->numberRows();
+          // ratio is done on number of rows here
+          double ratio = static_cast<double> (sizeFactorization_) / static_cast<double> (numberRows);
+          // Go to steepest if lot of iterations?
+          if (ratio < 1.0) {
+               numberWanted = CoinMax(2000, number / 20);
+          } else if (ratio < 5.0) {
+               numberWanted = CoinMax(2000, number / 10);
+               numberWanted = CoinMax(numberWanted, numberColumns / 20);
+          } else {
+               // we can zero out
+               updates->clear();
+               spareColumn1->clear();
+               switchType = 3;
+               // initialize
+               pivotSequence_ = -1;
+               pivotRow = -1;
+               numberSwitched_++;
+               // Make sure will re-do
+               delete [] weights_;
+               weights_ = NULL;
+               saveWeights(model_, 4);
+               COIN_DETAIL_PRINT(printf("switching to exact %d nel ratio %g\n", sizeFactorization_, ratio));
+               updates->clear();
+          }
+          if (model_->numberIterations() % 1000 == 0)
+	    COIN_DETAIL_PRINT(printf("numels %d ratio %g wanted %d\n", sizeFactorization_, ratio, numberWanted));
+     }
+     if (switchType < 4) {
+          if (switchType < 2 ) {
+               numberWanted = number + 1;
+          } else if (switchType == 2) {
+               numberWanted = CoinMax(2000, number / 8);
+          } else {
+               double ratio = static_cast<double> (sizeFactorization_) / static_cast<double> (model_->numberRows());
+               if (ratio < 1.0) {
+                    numberWanted = CoinMax(2000, number / 20);
+               } else if (ratio < 5.0) {
+                    numberWanted = CoinMax(2000, number / 10);
+                    numberWanted = CoinMax(numberWanted, numberColumns / 20);
+               } else if (ratio < 10.0) {
+                    numberWanted = CoinMax(2000, number / 8);
+                    numberWanted = CoinMax(numberWanted, numberColumns / 20);
+               } else {
+                    ratio = number * (ratio / 80.0);
+                    if (ratio > number) {
+                         numberWanted = number + 1;
+                    } else {
+                         numberWanted = CoinMax(2000, static_cast<int> (ratio));
+                         numberWanted = CoinMax(numberWanted, numberColumns / 10);
+                    }
+               }
+          }
+     }
+     // for weights update we use pivotSequence
+     pivotRow = pivotSequence_;
+     // unset in case sub flip
+     pivotSequence_ = -1;
+     if (pivotRow >= 0) {
+          // make sure infeasibility on incoming is 0.0
+          const int * pivotVariable = model_->pivotVariable();
+          int sequenceIn = pivotVariable[pivotRow];
+          infeasible_->zero(sequenceIn);
+          // and we can see if reference
+          double referenceIn = 0.0;
+          if (switchType != 1 && reference(sequenceIn))
+               referenceIn = 1.0;
+          // save outgoing weight round update
+          double outgoingWeight = 0.0;
+          if (sequenceOut >= 0)
+               outgoingWeight = weights_[sequenceOut];
+          // update weights
+          if (anyUpdates != 1) {
+               updates->setNumElements(0);
+               spareColumn1->setNumElements(0);
+               // might as well set dj to 1
+               dj = 1.0;
+               updates->insert(pivotRow, -dj);
+               model_->factorization()->updateColumnTranspose(spareRow2, updates);
+               // put row of tableau in rowArray and columnArray
+               model_->clpMatrix()->transposeTimes(model_, -1.0,
+                                                   updates, spareColumn2, spareColumn1);
+          }
+          double * weight;
+          double * other = alternateWeights_->denseVector();
+          int numberColumns = model_->numberColumns();
+          double scaleFactor = -1.0 / dj; // as formula is with 1.0
+          // rows
+          number = updates->getNumElements();
+          index = updates->getIndices();
+          updateBy = updates->denseVector();
+          weight = weights_ + numberColumns;
+
+          if (switchType < 4) {
+               // Exact
+               // now update weight update array
+               model_->factorization()->updateColumnTranspose(spareRow2,
+                         alternateWeights_);
+               for (j = 0; j < number; j++) {
+                    int iSequence = index[j];
+                    double thisWeight = weight[iSequence];
+                    // row has -1
+                    double pivot = updateBy[iSequence] * scaleFactor;
+                    updateBy[iSequence] = 0.0;
+                    double modification = other[iSequence];
+                    double pivotSquared = pivot * pivot;
+
+                    thisWeight += pivotSquared * devex_ + pivot * modification;
+                    if (thisWeight < TRY_NORM) {
+                         if (switchType == 1) {
+                              // steepest
+                              thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+                         } else {
+                              // exact
+                              thisWeight = referenceIn * pivotSquared;
+                              if (reference(iSequence + numberColumns))
+                                   thisWeight += 1.0;
+                              thisWeight = CoinMax(thisWeight, TRY_NORM);
+                         }
+                    }
+                    weight[iSequence] = thisWeight;
+               }
+          } else if (switchType == 4) {
+               // Devex
+               assert (devex_ > 0.0);
+               for (j = 0; j < number; j++) {
+                    int iSequence = index[j];
+                    double thisWeight = weight[iSequence];
+                    // row has -1
+                    double pivot = updateBy[iSequence] * scaleFactor;
+                    updateBy[iSequence] = 0.0;
+                    double value = pivot * pivot * devex_;
+                    if (reference(iSequence + numberColumns))
+                         value += 1.0;
+                    weight[iSequence] = CoinMax(0.99 * thisWeight, value);
+               }
+          }
+
+          // columns
+          weight = weights_;
+
+          scaleFactor = -scaleFactor;
+
+          number = spareColumn1->getNumElements();
+          index = spareColumn1->getIndices();
+          updateBy = spareColumn1->denseVector();
+          if (switchType < 4) {
+               // Exact
+               // get subset which have nonzero tableau elements
+               model_->clpMatrix()->subsetTransposeTimes(model_, alternateWeights_,
+                         spareColumn1,
+                         spareColumn2);
+               double * updateBy2 = spareColumn2->denseVector();
+               for (j = 0; j < number; j++) {
+                    int iSequence = index[j];
+                    double thisWeight = weight[iSequence];
+                    double pivot = updateBy[iSequence] * scaleFactor;
+                    updateBy[iSequence] = 0.0;
+                    double modification = updateBy2[j];
+                    updateBy2[j] = 0.0;
+                    double pivotSquared = pivot * pivot;
+
+                    thisWeight += pivotSquared * devex_ + pivot * modification;
+                    if (thisWeight < TRY_NORM) {
+                         if (switchType == 1) {
+                              // steepest
+                              thisWeight = CoinMax(TRY_NORM, ADD_ONE + pivotSquared);
+                         } else {
+                              // exact
+                              thisWeight = referenceIn * pivotSquared;
+                              if (reference(iSequence))
+                                   thisWeight += 1.0;
+                              thisWeight = CoinMax(thisWeight, TRY_NORM);
+                         }
+                    }
+                    weight[iSequence] = thisWeight;
+               }
+          } else if (switchType == 4) {
+               // Devex
+               for (j = 0; j < number; j++) {
+                    int iSequence = index[j];
+                    double thisWeight = weight[iSequence];
+                    // row has -1
+                    double pivot = updateBy[iSequence] * scaleFactor;
+                    updateBy[iSequence] = 0.0;
+                    double value = pivot * pivot * devex_;
+                    if (reference(iSequence))
+                         value += 1.0;
+                    weight[iSequence] = CoinMax(0.99 * thisWeight, value);
+               }
+          }
+          // restore outgoing weight
+          if (sequenceOut >= 0)
+               weights_[sequenceOut] = outgoingWeight;
+          alternateWeights_->clear();
+          spareColumn2->setNumElements(0);
+          //#define SOME_DEBUG_1
+#ifdef SOME_DEBUG_1
+          // check for accuracy
+          int iCheck = 892;
+          //printf("weight for iCheck is %g\n",weights_[iCheck]);
+          int numberRows = model_->numberRows();
+          //int numberColumns = model_->numberColumns();
+          for (iCheck = 0; iCheck < numberRows + numberColumns; iCheck++) {
+               if (model_->getStatus(iCheck) != ClpSimplex::basic &&
+                         !model_->getStatus(iCheck) != ClpSimplex::isFixed)
+                    checkAccuracy(iCheck, 1.0e-1, updates, spareRow2);
+          }
+#endif
+          updates->setNumElements(0);
+          spareColumn1->setNumElements(0);
+     }
+
+     // update of duals finished - now do pricing
+
+
+     double bestDj = 1.0e-30;
+     int bestSequence = -1;
+
+     int i, iSequence;
+     index = infeasible_->getIndices();
+     number = infeasible_->getNumElements();
+     if(model_->numberIterations() < model_->lastBadIteration() + 200) {
+          // we can't really trust infeasibilities if there is dual error
+          double checkTolerance = 1.0e-8;
+          if (!model_->factorization()->pivots())
+               checkTolerance = 1.0e-6;
+          if (model_->largestDualError() > checkTolerance)
+               tolerance *= model_->largestDualError() / checkTolerance;
+          // But cap
+          tolerance = CoinMin(1000.0, tolerance);
+     }
+#ifdef CLP_DEBUG
+     if (model_->numberDualInfeasibilities() == 1)
+          printf("** %g %g %g %x %x %d\n", tolerance, model_->dualTolerance(),
+                 model_->largestDualError(), model_, model_->messageHandler(),
+                 number);
+#endif
+     // stop last one coming immediately
+     double saveOutInfeasibility = 0.0;
+     if (sequenceOut >= 0) {
+          saveOutInfeasibility = infeas[sequenceOut];
+          infeas[sequenceOut] = 0.0;
+     }
+     tolerance *= tolerance; // as we are using squares
+
+     int iPass;
+     // Setup two passes
+     int start[4];
+     start[1] = number;
+     start[2] = 0;
+     double dstart = static_cast<double> (number) * model_->randomNumberGenerator()->randomDouble();
+     start[0] = static_cast<int> (dstart);
+     start[3] = start[0];
+     //double largestWeight=0.0;
+     //double smallestWeight=1.0e100;
+     for (iPass = 0; iPass < 2; iPass++) {
+          int end = start[2*iPass+1];
+          if (switchType < 5) {
+               for (i = start[2*iPass]; i < end; i++) {
+                    iSequence = index[i];
+                    double value = infeas[iSequence];
+                    if (value > tolerance) {
+                         double weight = weights_[iSequence];
+                         //weight=1.0;
+                         if (value > bestDj * weight) {
+                              // check flagged variable and correct dj
+                              if (!model_->flagged(iSequence)) {
+                                   bestDj = value / weight;
+                                   bestSequence = iSequence;
+                              } else {
+                                   // just to make sure we don't exit before got something
+                                   numberWanted++;
+                              }
+                         }
+                    }
+                    numberWanted--;
+                    if (!numberWanted)
+                         break;
+               }
+          } else {
+               // Dantzig
+               for (i = start[2*iPass]; i < end; i++) {
+                    iSequence = index[i];
+                    double value = infeas[iSequence];
+                    if (value > tolerance) {
+                         if (value > bestDj) {
+                              // check flagged variable and correct dj
+                              if (!model_->flagged(iSequence)) {
+                                   bestDj = value;
+                                   bestSequence = iSequence;
+                              } else {
+                                   // just to make sure we don't exit before got something
+                                   numberWanted++;
+                              }
+                         }
+                    }
+                    numberWanted--;
+                    if (!numberWanted)
+                         break;
+               }
+          }
+          if (!numberWanted)
+               break;
+     }
+     if (sequenceOut >= 0) {
+          infeas[sequenceOut] = saveOutInfeasibility;
+     }
+     /*if (model_->numberIterations()%100==0)
+       printf("%d best %g\n",bestSequence,bestDj);*/
+     reducedCost = model_->djRegion();
+     model_->clpMatrix()->setSavedBestSequence(bestSequence);
+     if (bestSequence >= 0)
+          model_->clpMatrix()->setSavedBestDj(reducedCost[bestSequence]);
+
+#ifdef CLP_DEBUG
+     if (bestSequence >= 0) {
+          if (model_->getStatus(bestSequence) == ClpSimplex::atLowerBound)
+               assert(model_->reducedCost(bestSequence) < 0.0);
+          if (model_->getStatus(bestSequence) == ClpSimplex::atUpperBound)
+               assert(model_->reducedCost(bestSequence) > 0.0);
+     }
+#endif
+     return bestSequence;
+}
+// Called when maximum pivots changes
+void
+ClpPrimalColumnSteepest::maximumPivotsChanged()
+{
+     if (alternateWeights_ &&
+               alternateWeights_->capacity() != model_->numberRows() +
+               model_->factorization()->maximumPivots()) {
+          delete alternateWeights_;
+          alternateWeights_ = new CoinIndexedVector();
+          // enough space so can use it for factorization
+          alternateWeights_->reserve(model_->numberRows() +
+                                     model_->factorization()->maximumPivots());
+     }
+}
+/*
+   1) before factorization
+   2) after factorization
+   3) just redo infeasibilities
+   4) restore weights
+   5) at end of values pass (so need initialization)
+*/
+void
+ClpPrimalColumnSteepest::saveWeights(ClpSimplex * model, int mode)
+{
+     model_ = model;
+     if (mode_ == 4 || mode_ == 5) {
+          if (mode == 1 && !weights_)
+               numberSwitched_ = 0; // Reset
+     }
+     // alternateWeights_ is defined as indexed but is treated oddly
+     // at times
+     int numberRows = model_->numberRows();
+     int numberColumns = model_->numberColumns();
+     const int * pivotVariable = model_->pivotVariable();
+     bool doInfeasibilities = true;
+     if (mode == 1) {
+          if(weights_) {
+               // Check if size has changed
+               if (infeasible_->capacity() == numberRows + numberColumns &&
+                         alternateWeights_->capacity() == numberRows +
+                         model_->factorization()->maximumPivots()) {
+                    //alternateWeights_->clear();
+                    if (pivotSequence_ >= 0 && pivotSequence_ < numberRows) {
+                         // save pivot order
+                         CoinMemcpyN(pivotVariable,
+                                     numberRows, alternateWeights_->getIndices());
+                         // change from pivot row number to sequence number
+                         pivotSequence_ = pivotVariable[pivotSequence_];
+                    } else {
+                         pivotSequence_ = -1;
+                    }
+                    state_ = 1;
+               } else {
+                    // size has changed - clear everything
+                    delete [] weights_;
+                    weights_ = NULL;
+                    delete infeasible_;
+                    infeasible_ = NULL;
+                    delete alternateWeights_;
+                    alternateWeights_ = NULL;
+                    delete [] savedWeights_;
+                    savedWeights_ = NULL;
+                    delete [] reference_;
+                    reference_ = NULL;
+                    state_ = -1;
+                    pivotSequence_ = -1;
+               }
+          }
+     } else if (mode == 2 || mode == 4 || mode == 5) {
+          // restore
+          if (!weights_ || state_ == -1 || mode == 5) {
+               // Partial is only allowed with certain types of matrix
+               if ((mode_ != 4 && mode_ != 5) || numberSwitched_ || !model_->clpMatrix()->canDoPartialPricing()) {
+                    // initialize weights
+                    delete [] weights_;
+                    delete alternateWeights_;
+                    weights_ = new double[numberRows+numberColumns];
+                    alternateWeights_ = new CoinIndexedVector();
+                    // enough space so can use it for factorization
+                    alternateWeights_->reserve(numberRows +
+                                               model_->factorization()->maximumPivots());
+                    initializeWeights();
+                    // create saved weights
+                    delete [] savedWeights_;
+                    savedWeights_ = CoinCopyOfArray(weights_, numberRows + numberColumns);
+                    // just do initialization
+                    mode = 3;
+               } else {
+                    // Partial pricing
+                    // use region as somewhere to save non-fixed slacks
+                    // set up infeasibilities
+                    if (!infeasible_) {
+                         infeasible_ = new CoinIndexedVector();
+                         infeasible_->reserve(numberColumns + numberRows);
+                    }
+                    infeasible_->clear();
+                    int number = model_->numberRows() + model_->numberColumns();
+                    int iSequence;
+                    int numberLook = 0;
+                    int * which = infeasible_->getIndices();
+                    for (iSequence = model_->numberColumns(); iSequence < number; iSequence++) {
+                         ClpSimplex::Status status = model_->getStatus(iSequence);
+                         if (status != ClpSimplex::isFixed)
+                              which[numberLook++] = iSequence;
+                    }
+                    infeasible_->setNumElements(numberLook);
+                    doInfeasibilities = false;
+               }
+               savedPivotSequence_ = -2;
+               savedSequenceOut_ = -2;
+
+          } else {
+               if (mode != 4) {
+                    // save
+                    CoinMemcpyN(weights_, (numberRows + numberColumns), savedWeights_);
+                    savedPivotSequence_ = pivotSequence_;
+                    savedSequenceOut_ = model_->sequenceOut();
+               } else {
+                    // restore
+                    CoinMemcpyN(savedWeights_, (numberRows + numberColumns), weights_);
+                    // was - but I think should not be
+                    //pivotSequence_= savedPivotSequence_;
+                    //model_->setSequenceOut(savedSequenceOut_);
+                    pivotSequence_ = -1;
+                    model_->setSequenceOut(-1);
+                    // indices are wrong so clear by hand
+                    //alternateWeights_->clear();
+                    CoinZeroN(alternateWeights_->denseVector(),
+                              alternateWeights_->capacity());
+                    alternateWeights_->setNumElements(0);
+               }
+          }
+          state_ = 0;
+          // set up infeasibilities
+          if (!infeasible_) {
+               infeasible_ = new CoinIndexedVector();
+               infeasible_->reserve(numberColumns + numberRows);
+          }
+     }
+     if (mode >= 2 && mode != 5) {
+          if (mode != 3) {
+               if (pivotSequence_ >= 0) {
+                    // restore pivot row
+                    int iRow;
+                    // permute alternateWeights
+                    double * temp = model_->rowArray(3)->denseVector();;
+                    double * work = alternateWeights_->denseVector();
+                    int * savePivotOrder = model_->rowArray(3)->getIndices();
+                    int * oldPivotOrder = alternateWeights_->getIndices();
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         int iPivot = oldPivotOrder[iRow];
+                         temp[iPivot] = work[iRow];
+                         savePivotOrder[iRow] = iPivot;
+                    }
+                    int number = 0;
+                    int found = -1;
+                    int * which = oldPivotOrder;
+                    // find pivot row and re-create alternateWeights
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         int iPivot = pivotVariable[iRow];
+                         if (iPivot == pivotSequence_)
+                              found = iRow;
+                         work[iRow] = temp[iPivot];
+                         if (work[iRow])
+                              which[number++] = iRow;
+                    }
+                    alternateWeights_->setNumElements(number);
+#ifdef CLP_DEBUG
+                    // Can happen but I should clean up
+                    assert(found >= 0);
+#endif
+                    pivotSequence_ = found;
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         int iPivot = savePivotOrder[iRow];
+                         temp[iPivot] = 0.0;
+                    }
+               } else {
+                    // Just clean up
+                    if (alternateWeights_)
+                         alternateWeights_->clear();
+               }
+          }
+          // Save size of factorization
+          if (!model->factorization()->pivots())
+               sizeFactorization_ = model_->factorization()->numberElements();
+          if(!doInfeasibilities)
+               return; // don't disturb infeasibilities
+          infeasible_->clear();
+          double tolerance = model_->currentDualTolerance();
+          int number = model_->numberRows() + model_->numberColumns();
+          int iSequence;
+
+          double * reducedCost = model_->djRegion();
+	  const double * lower = model_->lowerRegion();
+	  const double * upper = model_->upperRegion();
+	  const double * solution = model_->solutionRegion();
+	  double primalTolerance = model_->currentPrimalTolerance();
+
+          if (!model_->nonLinearCost()->lookBothWays()) {
+#ifndef CLP_PRIMAL_SLACK_MULTIPLIER 
+               for (iSequence = 0; iSequence < number; iSequence++) {
+                    double value = reducedCost[iSequence];
+                    ClpSimplex::Status status = model_->getStatus(iSequence);
+
+                    switch(status) {
+
+                    case ClpSimplex::basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case ClpSimplex::isFree:
+                    case ClpSimplex::superBasic:
+                         if (fabs(value) > FREE_ACCEPT * tolerance) {
+                              // we are going to bias towards free (but only if reasonable)
+                              value *= FREE_BIAS;
+                              // store square in list
+                              infeasible_->quickAdd(iSequence, value * value);
+                         }
+                         break;
+                    case ClpSimplex::atUpperBound:
+                         if (value > tolerance) {
+                              infeasible_->quickAdd(iSequence, value * value);
+                         }
+                         break;
+                    case ClpSimplex::atLowerBound:
+                         if (value < -tolerance) {
+                              infeasible_->quickAdd(iSequence, value * value);
+                         }
+                    }
+               }
+#else
+	       // Columns
+	       int numberColumns = model_->numberColumns();
+               for (iSequence = 0; iSequence < numberColumns; iSequence++) {
+                    double value = reducedCost[iSequence];
+                    ClpSimplex::Status status = model_->getStatus(iSequence);
+
+                    switch(status) {
+
+                    case ClpSimplex::basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case ClpSimplex::isFree:
+                    case ClpSimplex::superBasic:
+                         if (fabs(value) > FREE_ACCEPT * tolerance) {
+			      // check hasn't slipped through
+  			      if (solution[iSequence]<lower[iSequence]+primalTolerance) {
+				model_->setStatus(iSequence,ClpSimplex::atLowerBound);
+				if (value < -tolerance) {
+				  infeasible_->quickAdd(iSequence, value * value);
+				}
+			      } else if (solution[iSequence]>upper[iSequence]-primalTolerance) {
+				model_->setStatus(iSequence,ClpSimplex::atUpperBound);
+				if (value > tolerance) {
+				  infeasible_->quickAdd(iSequence, value * value);
+				}
+			      } else {
+				    // we are going to bias towards free (but only if reasonable)
+				    value *= FREE_BIAS;
+				    // store square in list
+				    infeasible_->quickAdd(iSequence, value * value);
+				  }
+                         }
+                         break;
+                    case ClpSimplex::atUpperBound:
+                         if (value > tolerance) {
+                              infeasible_->quickAdd(iSequence, value * value);
+                         }
+                         break;
+                    case ClpSimplex::atLowerBound:
+                         if (value < -tolerance) {
+                              infeasible_->quickAdd(iSequence, value * value);
+                         }
+                    }
+               }
+	       // Rows
+               for ( ; iSequence < number; iSequence++) {
+                    double value = reducedCost[iSequence];
+                    ClpSimplex::Status status = model_->getStatus(iSequence);
+
+                    switch(status) {
+
+                    case ClpSimplex::basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case ClpSimplex::isFree:
+                    case ClpSimplex::superBasic:
+                         if (fabs(value) > FREE_ACCEPT * tolerance) {
+                              // we are going to bias towards free (but only if reasonable)
+                              value *= FREE_BIAS;
+                              // store square in list
+                              infeasible_->quickAdd(iSequence, value * value);
+                         }
+                         break;
+                    case ClpSimplex::atUpperBound:
+                         if (value > tolerance) {
+                              infeasible_->quickAdd(iSequence, value * value * CLP_PRIMAL_SLACK_MULTIPLIER);
+                         }
+                         break;
+                    case ClpSimplex::atLowerBound:
+                         if (value < -tolerance) {
+                              infeasible_->quickAdd(iSequence, value * value * CLP_PRIMAL_SLACK_MULTIPLIER);
+                         }
+                    }
+               }
+#endif
+          } else {
+               ClpNonLinearCost * nonLinear = model_->nonLinearCost();
+               // can go both ways
+               for (iSequence = 0; iSequence < number; iSequence++) {
+                    double value = reducedCost[iSequence];
+                    ClpSimplex::Status status = model_->getStatus(iSequence);
+
+                    switch(status) {
+
+                    case ClpSimplex::basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case ClpSimplex::isFree:
+                    case ClpSimplex::superBasic:
+                         if (fabs(value) > FREE_ACCEPT * tolerance) {
+                              // we are going to bias towards free (but only if reasonable)
+                              value *= FREE_BIAS;
+                              // store square in list
+                              infeasible_->quickAdd(iSequence, value * value);
+                         }
+                         break;
+                    case ClpSimplex::atUpperBound:
+                         if (value > tolerance) {
+                              infeasible_->quickAdd(iSequence, value * value);
+                         } else {
+                              // look other way - change up should be negative
+                              value -= nonLinear->changeUpInCost(iSequence);
+                              if (value < -tolerance) {
+                                   // store square in list
+                                   infeasible_->quickAdd(iSequence, value * value);
+                              }
+                         }
+                         break;
+                    case ClpSimplex::atLowerBound:
+                         if (value < -tolerance) {
+                              infeasible_->quickAdd(iSequence, value * value);
+                         } else {
+                              // look other way - change down should be positive
+                              value -= nonLinear->changeDownInCost(iSequence);
+                              if (value > tolerance) {
+                                   // store square in list
+                                   infeasible_->quickAdd(iSequence, value * value);
+                              }
+                         }
+                    }
+               }
+          }
+     }
+}
+// Gets rid of last update
+void
+ClpPrimalColumnSteepest::unrollWeights()
+{
+     if ((mode_ == 4 || mode_ == 5) && !numberSwitched_)
+          return;
+     double * saved = alternateWeights_->denseVector();
+     int number = alternateWeights_->getNumElements();
+     int * which = alternateWeights_->getIndices();
+     int i;
+     for (i = 0; i < number; i++) {
+          int iRow = which[i];
+          weights_[iRow] = saved[iRow];
+          saved[iRow] = 0.0;
+     }
+     alternateWeights_->setNumElements(0);
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpPrimalColumnPivot * ClpPrimalColumnSteepest::clone(bool CopyData) const
+{
+     if (CopyData) {
+          return new ClpPrimalColumnSteepest(*this);
+     } else {
+          return new ClpPrimalColumnSteepest();
+     }
+}
+void
+ClpPrimalColumnSteepest::updateWeights(CoinIndexedVector * input)
+{
+     // Local copy of mode so can decide what to do
+     int switchType = mode_;
+     if (mode_ == 4 && numberSwitched_)
+          switchType = 3;
+     else if (mode_ == 4 || mode_ == 5)
+          return;
+     int number = input->getNumElements();
+     int * which = input->getIndices();
+     double * work = input->denseVector();
+     int newNumber = 0;
+     int * newWhich = alternateWeights_->getIndices();
+     double * newWork = alternateWeights_->denseVector();
+     int i;
+     int sequenceIn = model_->sequenceIn();
+     int sequenceOut = model_->sequenceOut();
+     const int * pivotVariable = model_->pivotVariable();
+
+     int pivotRow = model_->pivotRow();
+     pivotSequence_ = pivotRow;
+
+     devex_ = 0.0;
+     // Can't create alternateWeights_ as packed as needed unpacked
+     if (!input->packedMode()) {
+          if (pivotRow >= 0) {
+               if (switchType == 1) {
+                    for (i = 0; i < number; i++) {
+                         int iRow = which[i];
+                         devex_ += work[iRow] * work[iRow];
+                         newWork[iRow] = -2.0 * work[iRow];
+                    }
+                    newWork[pivotRow] = -2.0 * CoinMax(devex_, 0.0);
+                    devex_ += ADD_ONE;
+                    weights_[sequenceOut] = 1.0 + ADD_ONE;
+                    CoinMemcpyN(which, number, newWhich);
+                    alternateWeights_->setNumElements(number);
+               } else {
+                    if ((mode_ != 4 && mode_ != 5) || numberSwitched_ > 1) {
+                         for (i = 0; i < number; i++) {
+                              int iRow = which[i];
+                              int iPivot = pivotVariable[iRow];
+                              if (reference(iPivot)) {
+                                   devex_ += work[iRow] * work[iRow];
+                                   newWork[iRow] = -2.0 * work[iRow];
+                                   newWhich[newNumber++] = iRow;
+                              }
+                         }
+                         if (!newWork[pivotRow] && devex_ > 0.0)
+                              newWhich[newNumber++] = pivotRow; // add if not already in
+                         newWork[pivotRow] = -2.0 * CoinMax(devex_, 0.0);
+                    } else {
+                         for (i = 0; i < number; i++) {
+                              int iRow = which[i];
+                              int iPivot = pivotVariable[iRow];
+                              if (reference(iPivot))
+                                   devex_ += work[iRow] * work[iRow];
+                         }
+                    }
+                    if (reference(sequenceIn)) {
+                         devex_ += 1.0;
+                    } else {
+                    }
+                    if (reference(sequenceOut)) {
+                         weights_[sequenceOut] = 1.0 + 1.0;
+                    } else {
+                         weights_[sequenceOut] = 1.0;
+                    }
+                    alternateWeights_->setNumElements(newNumber);
+               }
+          } else {
+               if (switchType == 1) {
+                    for (i = 0; i < number; i++) {
+                         int iRow = which[i];
+                         devex_ += work[iRow] * work[iRow];
+                    }
+                    devex_ += ADD_ONE;
+               } else {
+                    for (i = 0; i < number; i++) {
+                         int iRow = which[i];
+                         int iPivot = pivotVariable[iRow];
+                         if (reference(iPivot)) {
+                              devex_ += work[iRow] * work[iRow];
+                         }
+                    }
+                    if (reference(sequenceIn))
+                         devex_ += 1.0;
+               }
+          }
+     } else {
+          // packed input
+          if (pivotRow >= 0) {
+               if (switchType == 1) {
+                    for (i = 0; i < number; i++) {
+                         int iRow = which[i];
+                         devex_ += work[i] * work[i];
+                         newWork[iRow] = -2.0 * work[i];
+                    }
+                    newWork[pivotRow] = -2.0 * CoinMax(devex_, 0.0);
+                    devex_ += ADD_ONE;
+                    weights_[sequenceOut] = 1.0 + ADD_ONE;
+                    CoinMemcpyN(which, number, newWhich);
+                    alternateWeights_->setNumElements(number);
+               } else {
+                    if ((mode_ != 4 && mode_ != 5) || numberSwitched_ > 1) {
+                         for (i = 0; i < number; i++) {
+                              int iRow = which[i];
+                              int iPivot = pivotVariable[iRow];
+                              if (reference(iPivot)) {
+                                   devex_ += work[i] * work[i];
+                                   newWork[iRow] = -2.0 * work[i];
+                                   newWhich[newNumber++] = iRow;
+                              }
+                         }
+                         if (!newWork[pivotRow] && devex_ > 0.0)
+                              newWhich[newNumber++] = pivotRow; // add if not already in
+                         newWork[pivotRow] = -2.0 * CoinMax(devex_, 0.0);
+                    } else {
+                         for (i = 0; i < number; i++) {
+                              int iRow = which[i];
+                              int iPivot = pivotVariable[iRow];
+                              if (reference(iPivot))
+                                   devex_ += work[i] * work[i];
+                         }
+                    }
+                    if (reference(sequenceIn)) {
+                         devex_ += 1.0;
+                    } else {
+                    }
+                    if (reference(sequenceOut)) {
+                         weights_[sequenceOut] = 1.0 + 1.0;
+                    } else {
+                         weights_[sequenceOut] = 1.0;
+                    }
+                    alternateWeights_->setNumElements(newNumber);
+               }
+          } else {
+               if (switchType == 1) {
+                    for (i = 0; i < number; i++) {
+                         devex_ += work[i] * work[i];
+                    }
+                    devex_ += ADD_ONE;
+               } else {
+                    for (i = 0; i < number; i++) {
+                         int iRow = which[i];
+                         int iPivot = pivotVariable[iRow];
+                         if (reference(iPivot)) {
+                              devex_ += work[i] * work[i];
+                         }
+                    }
+                    if (reference(sequenceIn))
+                         devex_ += 1.0;
+               }
+          }
+     }
+     double oldDevex = weights_[sequenceIn];
+#ifdef CLP_DEBUG
+     if ((model_->messageHandler()->logLevel() & 32))
+          printf("old weight %g, new %g\n", oldDevex, devex_);
+#endif
+     double check = CoinMax(devex_, oldDevex) + 0.1;
+     weights_[sequenceIn] = devex_;
+     double testValue = 0.1;
+     if (mode_ == 4 && numberSwitched_ == 1)
+          testValue = 0.5;
+     if ( fabs ( devex_ - oldDevex ) > testValue * check ) {
+#ifdef CLP_DEBUG
+          if ((model_->messageHandler()->logLevel() & 48) == 16)
+               printf("old weight %g, new %g\n", oldDevex, devex_);
+#endif
+          //printf("old weight %g, new %g\n",oldDevex,devex_);
+          testValue = 0.99;
+          if (mode_ == 1)
+               testValue = 1.01e1; // make unlikely to do if steepest
+          else if (mode_ == 4 && numberSwitched_ == 1)
+               testValue = 0.9;
+          double difference = fabs(devex_ - oldDevex);
+          if ( difference > testValue * check ) {
+               // need to redo
+               model_->messageHandler()->message(CLP_INITIALIZE_STEEP,
+                                                 *model_->messagesPointer())
+                         << oldDevex << devex_
+                         << CoinMessageEol;
+               initializeWeights();
+          }
+     }
+     if (pivotRow >= 0) {
+          // set outgoing weight here
+          weights_[model_->sequenceOut()] = devex_ / (model_->alpha() * model_->alpha());
+     }
+}
+// Checks accuracy - just for debug
+void
+ClpPrimalColumnSteepest::checkAccuracy(int sequence,
+                                       double relativeTolerance,
+                                       CoinIndexedVector * rowArray1,
+                                       CoinIndexedVector * rowArray2)
+{
+     if ((mode_ == 4 || mode_ == 5) && !numberSwitched_)
+          return;
+     model_->unpack(rowArray1, sequence);
+     model_->factorization()->updateColumn(rowArray2, rowArray1);
+     int number = rowArray1->getNumElements();
+     int * which = rowArray1->getIndices();
+     double * work = rowArray1->denseVector();
+     const int * pivotVariable = model_->pivotVariable();
+
+     double devex = 0.0;
+     int i;
+
+     if (mode_ == 1) {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               devex += work[iRow] * work[iRow];
+               work[iRow] = 0.0;
+          }
+          devex += ADD_ONE;
+     } else {
+          for (i = 0; i < number; i++) {
+               int iRow = which[i];
+               int iPivot = pivotVariable[iRow];
+               if (reference(iPivot)) {
+                    devex += work[iRow] * work[iRow];
+               }
+               work[iRow] = 0.0;
+          }
+          if (reference(sequence))
+               devex += 1.0;
+     }
+
+     double oldDevex = weights_[sequence];
+     double check = CoinMax(devex, oldDevex);;
+     if ( fabs ( devex - oldDevex ) > relativeTolerance * check ) {
+       COIN_DETAIL_PRINT(printf("check %d old weight %g, new %g\n", sequence, oldDevex, devex));
+          // update so won't print again
+          weights_[sequence] = devex;
+     }
+     rowArray1->setNumElements(0);
+}
+
+// Initialize weights
+void
+ClpPrimalColumnSteepest::initializeWeights()
+{
+     int numberRows = model_->numberRows();
+     int numberColumns = model_->numberColumns();
+     int number = numberRows + numberColumns;
+     int iSequence;
+     if (mode_ != 1) {
+          // initialize to 1.0
+          // and set reference framework
+          if (!reference_) {
+               int nWords = (number + 31) >> 5;
+               reference_ = new unsigned int[nWords];
+               CoinZeroN(reference_, nWords);
+          }
+
+          for (iSequence = 0; iSequence < number; iSequence++) {
+               weights_[iSequence] = 1.0;
+               if (model_->getStatus(iSequence) == ClpSimplex::basic) {
+                    setReference(iSequence, false);
+               } else {
+                    setReference(iSequence, true);
+               }
+          }
+     } else {
+          CoinIndexedVector * temp = new CoinIndexedVector();
+          temp->reserve(numberRows +
+                        model_->factorization()->maximumPivots());
+          double * array = alternateWeights_->denseVector();
+          int * which = alternateWeights_->getIndices();
+
+          for (iSequence = 0; iSequence < number; iSequence++) {
+               weights_[iSequence] = 1.0 + ADD_ONE;
+               if (model_->getStatus(iSequence) != ClpSimplex::basic &&
+                         model_->getStatus(iSequence) != ClpSimplex::isFixed) {
+                    model_->unpack(alternateWeights_, iSequence);
+                    double value = ADD_ONE;
+                    model_->factorization()->updateColumn(temp, alternateWeights_);
+                    int number = alternateWeights_->getNumElements();
+                    int j;
+                    for (j = 0; j < number; j++) {
+                         int iRow = which[j];
+                         value += array[iRow] * array[iRow];
+                         array[iRow] = 0.0;
+                    }
+                    alternateWeights_->setNumElements(0);
+                    weights_[iSequence] = value;
+               }
+          }
+          delete temp;
+     }
+}
+// Gets rid of all arrays
+void
+ClpPrimalColumnSteepest::clearArrays()
+{
+     if (persistence_ == normal) {
+          delete [] weights_;
+          weights_ = NULL;
+          delete infeasible_;
+          infeasible_ = NULL;
+          delete alternateWeights_;
+          alternateWeights_ = NULL;
+          delete [] savedWeights_;
+          savedWeights_ = NULL;
+          delete [] reference_;
+          reference_ = NULL;
+     }
+     pivotSequence_ = -1;
+     state_ = -1;
+     savedPivotSequence_ = -1;
+     savedSequenceOut_ = -1;
+     devex_ = 0.0;
+}
+// Returns true if would not find any column
+bool
+ClpPrimalColumnSteepest::looksOptimal() const
+{
+     if (looksOptimal_)
+          return true; // user overrode
+     //**** THIS MUST MATCH the action coding above
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     if(model_->numberIterations() < model_->lastBadIteration() + 200) {
+          // we can't really trust infeasibilities if there is dual error
+          double checkTolerance = 1.0e-8;
+          if (!model_->factorization()->pivots())
+               checkTolerance = 1.0e-6;
+          if (model_->largestDualError() > checkTolerance)
+               tolerance *= model_->largestDualError() / checkTolerance;
+          // But cap
+          tolerance = CoinMin(1000.0, tolerance);
+     }
+     int number = model_->numberRows() + model_->numberColumns();
+     int iSequence;
+
+     double * reducedCost = model_->djRegion();
+     int numberInfeasible = 0;
+     if (!model_->nonLinearCost()->lookBothWays()) {
+          for (iSequence = 0; iSequence < number; iSequence++) {
+               double value = reducedCost[iSequence];
+               ClpSimplex::Status status = model_->getStatus(iSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    if (fabs(value) > FREE_ACCEPT * tolerance)
+                         numberInfeasible++;
+                    break;
+               case ClpSimplex::atUpperBound:
+                    if (value > tolerance)
+                         numberInfeasible++;
+                    break;
+               case ClpSimplex::atLowerBound:
+                    if (value < -tolerance)
+                         numberInfeasible++;
+               }
+          }
+     } else {
+          ClpNonLinearCost * nonLinear = model_->nonLinearCost();
+          // can go both ways
+          for (iSequence = 0; iSequence < number; iSequence++) {
+               double value = reducedCost[iSequence];
+               ClpSimplex::Status status = model_->getStatus(iSequence);
+
+               switch(status) {
+
+               case ClpSimplex::basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case ClpSimplex::isFree:
+               case ClpSimplex::superBasic:
+                    if (fabs(value) > FREE_ACCEPT * tolerance)
+                         numberInfeasible++;
+                    break;
+               case ClpSimplex::atUpperBound:
+                    if (value > tolerance) {
+                         numberInfeasible++;
+                    } else {
+                         // look other way - change up should be negative
+                         value -= nonLinear->changeUpInCost(iSequence);
+                         if (value < -tolerance)
+                              numberInfeasible++;
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    if (value < -tolerance) {
+                         numberInfeasible++;
+                    } else {
+                         // look other way - change down should be positive
+                         value -= nonLinear->changeDownInCost(iSequence);
+                         if (value > tolerance)
+                              numberInfeasible++;
+                    }
+               }
+          }
+     }
+     return numberInfeasible == 0;
+}
+/* Returns number of extra columns for sprint algorithm - 0 means off.
+   Also number of iterations before recompute
+*/
+int
+ClpPrimalColumnSteepest::numberSprintColumns(int & numberIterations) const
+{
+     numberIterations = 0;
+     int numberAdd = 0;
+     if (!numberSwitched_ && mode_ >= 10) {
+          numberIterations = CoinMin(2000, model_->numberRows() / 5);
+          numberIterations = CoinMax(numberIterations, model_->factorizationFrequency());
+          numberIterations = CoinMax(numberIterations, 500);
+          if (mode_ == 10) {
+               numberAdd = CoinMax(300, model_->numberColumns() / 10);
+               numberAdd = CoinMax(numberAdd, model_->numberRows() / 5);
+               // fake all
+               //numberAdd=1000000;
+               numberAdd = CoinMin(numberAdd, model_->numberColumns());
+          } else {
+               abort();
+          }
+     }
+     return numberAdd;
+}
+// Switch off sprint idea
+void
+ClpPrimalColumnSteepest::switchOffSprint()
+{
+     numberSwitched_ = 10;
+}
+// Update djs doing partial pricing (dantzig)
+int
+ClpPrimalColumnSteepest::partialPricing(CoinIndexedVector * updates,
+                                        CoinIndexedVector * spareRow2,
+                                        int numberWanted,
+                                        int numberLook)
+{
+     int number = 0;
+     int * index;
+     double * updateBy;
+     double * reducedCost;
+     double saveTolerance = model_->currentDualTolerance();
+     double tolerance = model_->currentDualTolerance();
+     // we can't really trust infeasibilities if there is dual error
+     // this coding has to mimic coding in checkDualSolution
+     double error = CoinMin(1.0e-2, model_->largestDualError());
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+     if(model_->numberIterations() < model_->lastBadIteration() + 200) {
+          // we can't really trust infeasibilities if there is dual error
+          double checkTolerance = 1.0e-8;
+          if (!model_->factorization()->pivots())
+               checkTolerance = 1.0e-6;
+          if (model_->largestDualError() > checkTolerance)
+               tolerance *= model_->largestDualError() / checkTolerance;
+          // But cap
+          tolerance = CoinMin(1000.0, tolerance);
+     }
+     if (model_->factorization()->pivots() && model_->numberPrimalInfeasibilities())
+          tolerance = CoinMax(tolerance, 1.0e-10 * model_->infeasibilityCost());
+     // So partial pricing can use
+     model_->setCurrentDualTolerance(tolerance);
+     model_->factorization()->updateColumnTranspose(spareRow2, updates);
+     int numberColumns = model_->numberColumns();
+
+     // Rows
+     reducedCost = model_->djRegion(0);
+
+     number = updates->getNumElements();
+     index = updates->getIndices();
+     updateBy = updates->denseVector();
+     int j;
+     double * duals = model_->dualRowSolution();
+     for (j = 0; j < number; j++) {
+          int iSequence = index[j];
+          double value = duals[iSequence];
+          value -= updateBy[j];
+          updateBy[j] = 0.0;
+          duals[iSequence] = value;
+     }
+     //#define CLP_DEBUG
+#ifdef CLP_DEBUG
+     // check duals
+     {
+          int numberRows = model_->numberRows();
+          //work space
+          CoinIndexedVector arrayVector;
+          arrayVector.reserve(numberRows + 1000);
+          CoinIndexedVector workSpace;
+          workSpace.reserve(numberRows + 1000);
+
+
+          int iRow;
+          double * array = arrayVector.denseVector();
+          int * index = arrayVector.getIndices();
+          int number = 0;
+          int * pivotVariable = model_->pivotVariable();
+          double * cost = model_->costRegion();
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               int iPivot = pivotVariable[iRow];
+               double value = cost[iPivot];
+               if (value) {
+                    array[iRow] = value;
+                    index[number++] = iRow;
+               }
+          }
+          arrayVector.setNumElements(number);
+          // Extended duals before "updateTranspose"
+          model_->clpMatrix()->dualExpanded(model_, &arrayVector, NULL, 0);
+
+          // Btran basic costs
+          model_->factorization()->updateColumnTranspose(&workSpace, &arrayVector);
+
+          // now look at dual solution
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               // slack
+               double value = array[iRow];
+               if (fabs(duals[iRow] - value) > 1.0e-3)
+                    printf("bad row %d old dual %g new %g\n", iRow, duals[iRow], value);
+               //duals[iRow]=value;
+          }
+     }
+#endif
+#undef CLP_DEBUG
+     double bestDj = tolerance;
+     int bestSequence = -1;
+
+     const double * cost = model_->costRegion(1);
+
+     model_->clpMatrix()->setOriginalWanted(numberWanted);
+     model_->clpMatrix()->setCurrentWanted(numberWanted);
+     int iPassR = 0, iPassC = 0;
+     // Setup two passes
+     // This biases towards picking row variables
+     // This probably should be fixed
+     int startR[4];
+     const int * which = infeasible_->getIndices();
+     int nSlacks = infeasible_->getNumElements();
+     startR[1] = nSlacks;
+     startR[2] = 0;
+     double randomR = model_->randomNumberGenerator()->randomDouble();
+     double dstart = static_cast<double> (nSlacks) * randomR;
+     startR[0] = static_cast<int> (dstart);
+     startR[3] = startR[0];
+     double startC[4];
+     startC[1] = 1.0;
+     startC[2] = 0;
+     double randomC = model_->randomNumberGenerator()->randomDouble();
+     startC[0] = randomC;
+     startC[3] = randomC;
+     reducedCost = model_->djRegion(1);
+     int sequenceOut = model_->sequenceOut();
+     double * duals2 = duals - numberColumns;
+     int chunk = CoinMin(1024, (numberColumns + nSlacks) / 32);
+#ifdef COIN_DETAIL
+     if (model_->numberIterations() % 1000 == 0 && model_->logLevel() > 1) {
+          printf("%d wanted, nSlacks %d, chunk %d\n", numberWanted, nSlacks, chunk);
+          int i;
+          for (i = 0; i < 4; i++)
+               printf("start R %d C %g ", startR[i], startC[i]);
+          printf("\n");
+     }
+#endif
+     chunk = CoinMax(chunk, 256);
+     bool finishedR = false, finishedC = false;
+     bool doingR = randomR > randomC;
+     //doingR=false;
+     int saveNumberWanted = numberWanted;
+     while (!finishedR || !finishedC) {
+          if (finishedR)
+               doingR = false;
+          if (doingR) {
+               int saveSequence = bestSequence;
+               int start = startR[iPassR];
+               int end = CoinMin(startR[iPassR+1], start + chunk / 2);
+               int jSequence;
+               for (jSequence = start; jSequence < end; jSequence++) {
+                    int iSequence = which[jSequence];
+                    if (iSequence != sequenceOut) {
+                         double value;
+                         ClpSimplex::Status status = model_->getStatus(iSequence);
+
+                         switch(status) {
+
+                         case ClpSimplex::basic:
+                         case ClpSimplex::isFixed:
+                              break;
+                         case ClpSimplex::isFree:
+                         case ClpSimplex::superBasic:
+                              value = fabs(cost[iSequence] + duals2[iSequence]);
+                              if (value > FREE_ACCEPT * tolerance) {
+                                   numberWanted--;
+                                   // we are going to bias towards free (but only if reasonable)
+                                   value *= FREE_BIAS;
+                                   if (value > bestDj) {
+                                        // check flagged variable and correct dj
+                                        if (!model_->flagged(iSequence)) {
+                                             bestDj = value;
+                                             bestSequence = iSequence;
+                                        } else {
+                                             // just to make sure we don't exit before got something
+                                             numberWanted++;
+                                        }
+                                   }
+                              }
+                              break;
+                         case ClpSimplex::atUpperBound:
+                              value = cost[iSequence] + duals2[iSequence];
+                              if (value > tolerance) {
+                                   numberWanted--;
+                                   if (value > bestDj) {
+                                        // check flagged variable and correct dj
+                                        if (!model_->flagged(iSequence)) {
+                                             bestDj = value;
+                                             bestSequence = iSequence;
+                                        } else {
+                                             // just to make sure we don't exit before got something
+                                             numberWanted++;
+                                        }
+                                   }
+                              }
+                              break;
+                         case ClpSimplex::atLowerBound:
+                              value = -(cost[iSequence] + duals2[iSequence]);
+                              if (value > tolerance) {
+                                   numberWanted--;
+                                   if (value > bestDj) {
+                                        // check flagged variable and correct dj
+                                        if (!model_->flagged(iSequence)) {
+                                             bestDj = value;
+                                             bestSequence = iSequence;
+                                        } else {
+                                             // just to make sure we don't exit before got something
+                                             numberWanted++;
+                                        }
+                                   }
+                              }
+                              break;
+                         }
+                    }
+                    if (!numberWanted)
+                         break;
+               }
+               numberLook -= (end - start);
+               if (numberLook < 0 && (10 * (saveNumberWanted - numberWanted) > saveNumberWanted))
+                    numberWanted = 0; // give up
+               if (saveSequence != bestSequence) {
+                    // dj
+                    reducedCost[bestSequence] = cost[bestSequence] + duals[bestSequence-numberColumns];
+                    bestDj = fabs(reducedCost[bestSequence]);
+                    model_->clpMatrix()->setSavedBestSequence(bestSequence);
+                    model_->clpMatrix()->setSavedBestDj(reducedCost[bestSequence]);
+               }
+               model_->clpMatrix()->setCurrentWanted(numberWanted);
+               if (!numberWanted)
+                    break;
+               doingR = false;
+               // update start
+               startR[iPassR] = jSequence;
+               if (jSequence >= startR[iPassR+1]) {
+                    if (iPassR)
+                         finishedR = true;
+                    else
+                         iPassR = 2;
+               }
+          }
+          if (finishedC)
+               doingR = true;
+          if (!doingR) {
+               int saveSequence = bestSequence;
+               // Columns
+               double start = startC[iPassC];
+               // If we put this idea back then each function needs to update endFraction **
+#if 0
+               double dchunk = (static_cast<double> chunk) / (static_cast<double> numberColumns);
+               double end = CoinMin(startC[iPassC+1], start + dchunk);;
+#else
+               double end = startC[iPassC+1]; // force end
+#endif
+               model_->clpMatrix()->partialPricing(model_, start, end, bestSequence, numberWanted);
+               numberWanted = model_->clpMatrix()->currentWanted();
+               numberLook -= static_cast<int> ((end - start) * numberColumns);
+               if (numberLook < 0 && (10 * (saveNumberWanted - numberWanted) > saveNumberWanted))
+                    numberWanted = 0; // give up
+               if (saveSequence != bestSequence) {
+                    // dj
+                    bestDj = fabs(model_->clpMatrix()->reducedCost(model_, bestSequence));
+               }
+               if (!numberWanted)
+                    break;
+               doingR = true;
+               // update start
+               startC[iPassC] = end;
+               if (end >= startC[iPassC+1] - 1.0e-8) {
+                    if (iPassC)
+                         finishedC = true;
+                    else
+                         iPassC = 2;
+               }
+          }
+     }
+     updates->setNumElements(0);
+
+     // Restore tolerance
+     model_->setCurrentDualTolerance(saveTolerance);
+     // Now create variable if column generation
+     model_->clpMatrix()->createVariable(model_, bestSequence);
+#ifndef NDEBUG
+     if (bestSequence >= 0) {
+          if (model_->getStatus(bestSequence) == ClpSimplex::atLowerBound)
+               assert(model_->reducedCost(bestSequence) < 0.0);
+          if (model_->getStatus(bestSequence) == ClpSimplex::atUpperBound)
+               assert(model_->reducedCost(bestSequence) > 0.0);
+     }
+#endif
+     return bestSequence;
+}
diff --git a/cbits/coin/ClpPrimalColumnSteepest.hpp b/cbits/coin/ClpPrimalColumnSteepest.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpPrimalColumnSteepest.hpp
@@ -0,0 +1,247 @@
+/* $Id: ClpPrimalColumnSteepest.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpPrimalColumnSteepest_H
+#define ClpPrimalColumnSteepest_H
+
+#include "ClpPrimalColumnPivot.hpp"
+#include <bitset>
+
+//#############################################################################
+class CoinIndexedVector;
+
+
+/** Primal Column Pivot Steepest Edge Algorithm Class
+
+See Forrest-Goldfarb paper for algorithm
+
+*/
+
+
+class ClpPrimalColumnSteepest : public ClpPrimalColumnPivot {
+
+public:
+
+     ///@name Algorithmic methods
+     //@{
+
+     /** Returns pivot column, -1 if none.
+         The Packed CoinIndexedVector updates has cost updates - for normal LP
+         that is just +-weight where a feasibility changed.  It also has
+         reduced cost from last iteration in pivot row
+         Parts of operation split out into separate functions for
+         profiling and speed
+     */
+     virtual int pivotColumn(CoinIndexedVector * updates,
+                             CoinIndexedVector * spareRow1,
+                             CoinIndexedVector * spareRow2,
+                             CoinIndexedVector * spareColumn1,
+                             CoinIndexedVector * spareColumn2);
+     /// For quadratic or funny nonlinearities
+     int pivotColumnOldMethod(CoinIndexedVector * updates,
+                              CoinIndexedVector * spareRow1,
+                              CoinIndexedVector * spareRow2,
+                              CoinIndexedVector * spareColumn1,
+                              CoinIndexedVector * spareColumn2);
+     /// Just update djs
+     void justDjs(CoinIndexedVector * updates,
+                  CoinIndexedVector * spareRow2,
+                  CoinIndexedVector * spareColumn1,
+                  CoinIndexedVector * spareColumn2);
+     /// Update djs doing partial pricing (dantzig)
+     int partialPricing(CoinIndexedVector * updates,
+                        CoinIndexedVector * spareRow2,
+                        int numberWanted,
+                        int numberLook);
+     /// Update djs, weights for Devex using djs
+     void djsAndDevex(CoinIndexedVector * updates,
+                      CoinIndexedVector * spareRow2,
+                      CoinIndexedVector * spareColumn1,
+                      CoinIndexedVector * spareColumn2);
+     /// Update djs, weights for Steepest using djs
+     void djsAndSteepest(CoinIndexedVector * updates,
+                         CoinIndexedVector * spareRow2,
+                         CoinIndexedVector * spareColumn1,
+                         CoinIndexedVector * spareColumn2);
+     /// Update djs, weights for Devex using pivot row
+     void djsAndDevex2(CoinIndexedVector * updates,
+                       CoinIndexedVector * spareRow2,
+                       CoinIndexedVector * spareColumn1,
+                       CoinIndexedVector * spareColumn2);
+     /// Update djs, weights for Steepest using pivot row
+     void djsAndSteepest2(CoinIndexedVector * updates,
+                          CoinIndexedVector * spareRow2,
+                          CoinIndexedVector * spareColumn1,
+                          CoinIndexedVector * spareColumn2);
+     /// Update weights for Devex
+     void justDevex(CoinIndexedVector * updates,
+                    CoinIndexedVector * spareRow2,
+                    CoinIndexedVector * spareColumn1,
+                    CoinIndexedVector * spareColumn2);
+     /// Update weights for Steepest
+     void justSteepest(CoinIndexedVector * updates,
+                       CoinIndexedVector * spareRow2,
+                       CoinIndexedVector * spareColumn1,
+                       CoinIndexedVector * spareColumn2);
+     /// Updates two arrays for steepest
+     void transposeTimes2(const CoinIndexedVector * pi1, CoinIndexedVector * dj1,
+                          const CoinIndexedVector * pi2, CoinIndexedVector * dj2,
+                          CoinIndexedVector * spare, double scaleFactor);
+
+     /// Updates weights - part 1 - also checks accuracy
+     virtual void updateWeights(CoinIndexedVector * input);
+
+     /// Checks accuracy - just for debug
+     void checkAccuracy(int sequence, double relativeTolerance,
+                        CoinIndexedVector * rowArray1,
+                        CoinIndexedVector * rowArray2);
+
+     /// Initialize weights
+     void initializeWeights();
+
+     /** Save weights - this may initialize weights as well
+         mode is -
+         1) before factorization
+         2) after factorization
+         3) just redo infeasibilities
+         4) restore weights
+         5) at end of values pass (so need initialization)
+     */
+     virtual void saveWeights(ClpSimplex * model, int mode);
+     /// Gets rid of last update
+     virtual void unrollWeights();
+     /// Gets rid of all arrays
+     virtual void clearArrays();
+     /// Returns true if would not find any column
+     virtual bool looksOptimal() const;
+     /// Called when maximum pivots changes
+     virtual void maximumPivotsChanged();
+     //@}
+
+     /**@name gets and sets */
+     //@{
+     /// Mode
+     inline int mode() const {
+          return mode_;
+     }
+     /** Returns number of extra columns for sprint algorithm - 0 means off.
+         Also number of iterations before recompute
+     */
+     virtual int numberSprintColumns(int & numberIterations) const;
+     /// Switch off sprint idea
+     virtual void switchOffSprint();
+
+//@}
+
+     /** enums for persistence
+     */
+     enum Persistence {
+          normal = 0x00, // create (if necessary) and destroy
+          keep = 0x01 // create (if necessary) and leave
+     };
+
+     ///@name Constructors and destructors
+     //@{
+     /** Default Constructor
+         0 is exact devex, 1 full steepest, 2 is partial exact devex
+         3 switches between 0 and 2 depending on factorization
+         4 starts as partial dantzig/devex but then may switch between 0 and 2.
+         By partial exact devex is meant that the weights are updated as normal
+         but only part of the nonbasic variables are scanned.
+         This can be faster on very easy problems.
+     */
+     ClpPrimalColumnSteepest(int mode = 3);
+
+     /// Copy constructor
+     ClpPrimalColumnSteepest(const ClpPrimalColumnSteepest & rhs);
+
+     /// Assignment operator
+     ClpPrimalColumnSteepest & operator=(const ClpPrimalColumnSteepest& rhs);
+
+     /// Destructor
+     virtual ~ClpPrimalColumnSteepest ();
+
+     /// Clone
+     virtual ClpPrimalColumnPivot * clone(bool copyData = true) const;
+
+     //@}
+
+     ///@name Private functions to deal with devex
+     /** reference would be faster using ClpSimplex's status_,
+         but I prefer to keep modularity.
+     */
+     inline bool reference(int i) const {
+          return ((reference_[i>>5] >> (i & 31)) & 1) != 0;
+     }
+     inline void setReference(int i, bool trueFalse) {
+          unsigned int & value = reference_[i>>5];
+          int bit = i & 31;
+          if (trueFalse)
+               value |= (1 << bit);
+          else
+               value &= ~(1 << bit);
+     }
+     /// Set/ get persistence
+     inline void setPersistence(Persistence life) {
+          persistence_ = life;
+     }
+     inline Persistence persistence() const {
+          return persistence_ ;
+     }
+
+     //@}
+     //---------------------------------------------------------------------------
+
+private:
+     ///@name Private member data
+     // Update weight
+     double devex_;
+     /// weight array
+     double * weights_;
+     /// square of infeasibility array (just for infeasible columns)
+     CoinIndexedVector * infeasible_;
+     /// alternate weight array (so we can unroll)
+     CoinIndexedVector * alternateWeights_;
+     /// save weight array (so we can use checkpoint)
+     double * savedWeights_;
+     // Array for exact devex to say what is in reference framework
+     unsigned int * reference_;
+     /** Status
+         0) Normal
+         -1) Needs initialization
+         1) Weights are stored by sequence number
+     */
+     int state_;
+     /**
+         0 is exact devex, 1 full steepest, 2 is partial exact devex
+         3 switches between 0 and 2 depending on factorization
+         4 starts as partial dantzig/devex but then may switch between 0 and 2.
+         5 is always partial dantzig
+         By partial exact devex is meant that the weights are updated as normal
+         but only part of the nonbasic variables are scanned.
+         This can be faster on very easy problems.
+
+         New dubious option is >=10 which does mini-sprint
+
+     */
+     int mode_;
+     /// Life of weights
+     Persistence persistence_;
+     /// Number of times switched from partial dantzig to 0/2
+     int numberSwitched_;
+     // This is pivot row (or pivot sequence round re-factorization)
+     int pivotSequence_;
+     // This is saved pivot sequence
+     int savedPivotSequence_;
+     // This is saved outgoing variable
+     int savedSequenceOut_;
+     // Iteration when last rectified
+     int lastRectified_;
+     // Size of factorization at invert (used to decide algorithm)
+     int sizeFactorization_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpQuadraticObjective.cpp b/cbits/coin/ClpQuadraticObjective.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpQuadraticObjective.cpp
@@ -0,0 +1,1059 @@
+/* $Id: ClpQuadraticObjective.cpp 1723 2011-04-17 15:07:10Z forrest $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpQuadraticObjective.hpp"
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+ClpQuadraticObjective::ClpQuadraticObjective ()
+     : ClpObjective()
+{
+     type_ = 2;
+     objective_ = NULL;
+     quadraticObjective_ = NULL;
+     gradient_ = NULL;
+     numberColumns_ = 0;
+     numberExtendedColumns_ = 0;
+     activated_ = 0;
+     fullMatrix_ = false;
+}
+
+//-------------------------------------------------------------------
+// Useful Constructor
+//-------------------------------------------------------------------
+ClpQuadraticObjective::ClpQuadraticObjective (const double * objective ,
+          int numberColumns,
+          const CoinBigIndex * start,
+          const int * column, const double * element,
+          int numberExtendedColumns)
+     : ClpObjective()
+{
+     type_ = 2;
+     numberColumns_ = numberColumns;
+     if (numberExtendedColumns >= 0)
+          numberExtendedColumns_ = CoinMax(numberColumns_, numberExtendedColumns);
+     else
+          numberExtendedColumns_ = numberColumns_;
+     if (objective) {
+          objective_ = new double [numberExtendedColumns_];
+          CoinMemcpyN(objective, numberColumns_, objective_);
+          memset(objective_ + numberColumns_, 0, (numberExtendedColumns_ - numberColumns_)*sizeof(double));
+     } else {
+          objective_ = new double [numberExtendedColumns_];
+          memset(objective_, 0, numberExtendedColumns_ * sizeof(double));
+     }
+     if (start)
+          quadraticObjective_ = new CoinPackedMatrix(true, numberColumns, numberColumns,
+                    start[numberColumns], element, column, start, NULL);
+     else
+          quadraticObjective_ = NULL;
+     gradient_ = NULL;
+     activated_ = 1;
+     fullMatrix_ = false;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+ClpQuadraticObjective::ClpQuadraticObjective (const ClpQuadraticObjective & rhs,
+          int type)
+     : ClpObjective(rhs)
+{
+     numberColumns_ = rhs.numberColumns_;
+     numberExtendedColumns_ = rhs.numberExtendedColumns_;
+     fullMatrix_ = rhs.fullMatrix_;
+     if (rhs.objective_) {
+          objective_ = new double [numberExtendedColumns_];
+          CoinMemcpyN(rhs.objective_, numberExtendedColumns_, objective_);
+     } else {
+          objective_ = NULL;
+     }
+     if (rhs.gradient_) {
+          gradient_ = new double [numberExtendedColumns_];
+          CoinMemcpyN(rhs.gradient_, numberExtendedColumns_, gradient_);
+     } else {
+          gradient_ = NULL;
+     }
+     if (rhs.quadraticObjective_) {
+          // see what type of matrix wanted
+          if (type == 0) {
+               // just copy
+               quadraticObjective_ = new CoinPackedMatrix(*rhs.quadraticObjective_);
+          } else if (type == 1) {
+               // expand to full symmetric
+               fullMatrix_ = true;
+               const int * columnQuadratic1 = rhs.quadraticObjective_->getIndices();
+               const CoinBigIndex * columnQuadraticStart1 = rhs.quadraticObjective_->getVectorStarts();
+               const int * columnQuadraticLength1 = rhs.quadraticObjective_->getVectorLengths();
+               const double * quadraticElement1 = rhs.quadraticObjective_->getElements();
+               CoinBigIndex * columnQuadraticStart2 = new CoinBigIndex [numberExtendedColumns_+1];
+               int * columnQuadraticLength2 = new int [numberExtendedColumns_];
+               int iColumn;
+               int numberColumns = rhs.quadraticObjective_->getNumCols();
+               int numberBelow = 0;
+               int numberAbove = 0;
+               int numberDiagonal = 0;
+               CoinZeroN(columnQuadraticLength2, numberExtendedColumns_);
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    for (CoinBigIndex j = columnQuadraticStart1[iColumn];
+                              j < columnQuadraticStart1[iColumn] + columnQuadraticLength1[iColumn]; j++) {
+                         int jColumn = columnQuadratic1[j];
+                         if (jColumn > iColumn) {
+                              numberBelow++;
+                              columnQuadraticLength2[jColumn]++;
+                              columnQuadraticLength2[iColumn]++;
+                         } else if (jColumn == iColumn) {
+                              numberDiagonal++;
+                              columnQuadraticLength2[iColumn]++;
+                         } else {
+                              numberAbove++;
+                         }
+                    }
+               }
+               if (numberAbove > 0) {
+                    if (numberAbove == numberBelow) {
+                         // already done
+                         quadraticObjective_ = new CoinPackedMatrix(*rhs.quadraticObjective_);
+                         delete [] columnQuadraticStart2;
+                         delete [] columnQuadraticLength2;
+                    } else {
+                         printf("number above = %d, number below = %d, error\n",
+                                numberAbove, numberBelow);
+                         abort();
+                    }
+               } else {
+                    int numberElements = numberDiagonal + 2 * numberBelow;
+                    int * columnQuadratic2 = new int [numberElements];
+                    double * quadraticElement2 = new double [numberElements];
+                    columnQuadraticStart2[0] = 0;
+                    numberElements = 0;
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         int n = columnQuadraticLength2[iColumn];
+                         columnQuadraticLength2[iColumn] = 0;
+                         numberElements += n;
+                         columnQuadraticStart2[iColumn+1] = numberElements;
+                    }
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         for (CoinBigIndex j = columnQuadraticStart1[iColumn];
+                                   j < columnQuadraticStart1[iColumn] + columnQuadraticLength1[iColumn]; j++) {
+                              int jColumn = columnQuadratic1[j];
+                              if (jColumn > iColumn) {
+                                   // put in two places
+                                   CoinBigIndex put = columnQuadraticLength2[jColumn] + columnQuadraticStart2[jColumn];
+                                   columnQuadraticLength2[jColumn]++;
+                                   quadraticElement2[put] = quadraticElement1[j];
+                                   columnQuadratic2[put] = iColumn;
+                                   put = columnQuadraticLength2[iColumn] + columnQuadraticStart2[iColumn];
+                                   columnQuadraticLength2[iColumn]++;
+                                   quadraticElement2[put] = quadraticElement1[j];
+                                   columnQuadratic2[put] = jColumn;
+                              } else if (jColumn == iColumn) {
+                                   CoinBigIndex put = columnQuadraticLength2[iColumn] + columnQuadraticStart2[iColumn];
+                                   columnQuadraticLength2[iColumn]++;
+                                   quadraticElement2[put] = quadraticElement1[j];
+                                   columnQuadratic2[put] = iColumn;
+                              } else {
+                                   abort();
+                              }
+                         }
+                    }
+                    // Now create
+                    quadraticObjective_ =
+                         new CoinPackedMatrix (true,
+                                               rhs.numberExtendedColumns_,
+                                               rhs.numberExtendedColumns_,
+                                               numberElements,
+                                               quadraticElement2,
+                                               columnQuadratic2,
+                                               columnQuadraticStart2,
+                                               columnQuadraticLength2, 0.0, 0.0);
+                    delete [] columnQuadraticStart2;
+                    delete [] columnQuadraticLength2;
+                    delete [] columnQuadratic2;
+                    delete [] quadraticElement2;
+               }
+          } else {
+               fullMatrix_ = false;
+               abort(); // code when needed
+          }
+
+     } else {
+          quadraticObjective_ = NULL;
+     }
+}
+/* Subset constructor.  Duplicates are allowed
+   and order is as given.
+*/
+ClpQuadraticObjective::ClpQuadraticObjective (const ClpQuadraticObjective &rhs,
+          int numberColumns,
+          const int * whichColumn)
+     : ClpObjective(rhs)
+{
+     fullMatrix_ = rhs.fullMatrix_;
+     objective_ = NULL;
+     int extra = rhs.numberExtendedColumns_ - rhs.numberColumns_;
+     numberColumns_ = 0;
+     numberExtendedColumns_ = numberColumns + extra;
+     if (numberColumns > 0) {
+          // check valid lists
+          int numberBad = 0;
+          int i;
+          for (i = 0; i < numberColumns; i++)
+               if (whichColumn[i] < 0 || whichColumn[i] >= rhs.numberColumns_)
+                    numberBad++;
+          if (numberBad)
+               throw CoinError("bad column list", "subset constructor",
+                               "ClpQuadraticObjective");
+          numberColumns_ = numberColumns;
+          objective_ = new double[numberExtendedColumns_];
+          for (i = 0; i < numberColumns_; i++)
+               objective_[i] = rhs.objective_[whichColumn[i]];
+          CoinMemcpyN(rhs.objective_ + rhs.numberColumns_,	(numberExtendedColumns_ - numberColumns_),
+                      objective_ + numberColumns_);
+          if (rhs.gradient_) {
+               gradient_ = new double[numberExtendedColumns_];
+               for (i = 0; i < numberColumns_; i++)
+                    gradient_[i] = rhs.gradient_[whichColumn[i]];
+               CoinMemcpyN(rhs.gradient_ + rhs.numberColumns_,	(numberExtendedColumns_ - numberColumns_),
+                           gradient_ + numberColumns_);
+          } else {
+               gradient_ = NULL;
+          }
+     } else {
+          gradient_ = NULL;
+          objective_ = NULL;
+     }
+     if (rhs.quadraticObjective_) {
+          quadraticObjective_ = new CoinPackedMatrix(*rhs.quadraticObjective_,
+                    numberColumns, whichColumn,
+                    numberColumns, whichColumn);
+     } else {
+          quadraticObjective_ = NULL;
+     }
+}
+
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+ClpQuadraticObjective::~ClpQuadraticObjective ()
+{
+     delete [] objective_;
+     delete [] gradient_;
+     delete quadraticObjective_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+ClpQuadraticObjective &
+ClpQuadraticObjective::operator=(const ClpQuadraticObjective& rhs)
+{
+     if (this != &rhs) {
+          fullMatrix_ = rhs.fullMatrix_;
+          delete quadraticObjective_;
+          quadraticObjective_ = NULL;
+          delete [] objective_;
+          delete [] gradient_;
+          ClpObjective::operator=(rhs);
+          numberColumns_ = rhs.numberColumns_;
+          numberExtendedColumns_ = rhs.numberExtendedColumns_;
+          if (rhs.objective_) {
+               objective_ = new double [numberExtendedColumns_];
+               CoinMemcpyN(rhs.objective_, numberExtendedColumns_, objective_);
+          } else {
+               objective_ = NULL;
+          }
+          if (rhs.gradient_) {
+               gradient_ = new double [numberExtendedColumns_];
+               CoinMemcpyN(rhs.gradient_, numberExtendedColumns_, gradient_);
+          } else {
+               gradient_ = NULL;
+          }
+          if (rhs.quadraticObjective_) {
+               quadraticObjective_ = new CoinPackedMatrix(*rhs.quadraticObjective_);
+          } else {
+               quadraticObjective_ = NULL;
+          }
+     }
+     return *this;
+}
+
+// Returns gradient
+double *
+ClpQuadraticObjective::gradient(const ClpSimplex * model,
+                                const double * solution, double & offset, bool refresh,
+                                int includeLinear)
+{
+     offset = 0.0;
+     bool scaling = false;
+     if (model && (model->rowScale() ||
+                   model->objectiveScale() != 1.0 || model->optimizationDirection() != 1.0))
+          scaling = true;
+     const double * cost = NULL;
+     if (model)
+          cost = model->costRegion();
+     if (!cost) {
+          // not in solve
+          cost = objective_;
+          scaling = false;
+     }
+     if (!scaling) {
+          if (!quadraticObjective_ || !solution || !activated_) {
+               return objective_;
+          } else {
+               if (refresh || !gradient_) {
+                    if (!gradient_)
+                         gradient_ = new double[numberExtendedColumns_];
+                    const int * columnQuadratic = quadraticObjective_->getIndices();
+                    const CoinBigIndex * columnQuadraticStart = quadraticObjective_->getVectorStarts();
+                    const int * columnQuadraticLength = quadraticObjective_->getVectorLengths();
+                    const double * quadraticElement = quadraticObjective_->getElements();
+                    offset = 0.0;
+                    // use current linear cost region
+                    if (includeLinear == 1)
+                         CoinMemcpyN(cost, numberExtendedColumns_, gradient_);
+                    else if (includeLinear == 2)
+                         CoinMemcpyN(objective_, numberExtendedColumns_, gradient_);
+                    else
+                         memset(gradient_, 0, numberExtendedColumns_ * sizeof(double));
+                    if (activated_) {
+                         if (!fullMatrix_) {
+                              int iColumn;
+                              for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                                   double valueI = solution[iColumn];
+                                   CoinBigIndex j;
+                                   for (j = columnQuadraticStart[iColumn];
+                                             j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                        int jColumn = columnQuadratic[j];
+                                        double valueJ = solution[jColumn];
+                                        double elementValue = quadraticElement[j];
+                                        if (iColumn != jColumn) {
+                                             offset += valueI * valueJ * elementValue;
+                                             //if (fabs(valueI*valueJ*elementValue)>1.0e-12)
+                                             //printf("%d %d %g %g %g -> %g\n",
+                                             //       iColumn,jColumn,valueI,valueJ,elementValue,
+                                             //       valueI*valueJ*elementValue);
+                                             double gradientI = valueJ * elementValue;
+                                             double gradientJ = valueI * elementValue;
+                                             gradient_[iColumn] += gradientI;
+                                             gradient_[jColumn] += gradientJ;
+                                        } else {
+                                             offset += 0.5 * valueI * valueI * elementValue;
+                                             //if (fabs(valueI*valueI*elementValue)>1.0e-12)
+                                             //printf("XX %d %g %g -> %g\n",
+                                             //       iColumn,valueI,elementValue,
+                                             //       0.5*valueI*valueI*elementValue);
+                                             double gradientI = valueI * elementValue;
+                                             gradient_[iColumn] += gradientI;
+                                        }
+                                   }
+                              }
+                         } else {
+                              // full matrix
+                              int iColumn;
+                              offset *= 2.0;
+                              for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                                   CoinBigIndex j;
+                                   double value = 0.0;
+                                   double current = gradient_[iColumn];
+                                   for (j = columnQuadraticStart[iColumn];
+                                             j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                        int jColumn = columnQuadratic[j];
+                                        double valueJ = solution[jColumn] * quadraticElement[j];
+                                        value += valueJ;
+                                   }
+                                   offset += value * solution[iColumn];
+                                   gradient_[iColumn] = current + value;
+                              }
+                              offset *= 0.5;
+                         }
+                    }
+               }
+               if (model)
+                    offset *= model->optimizationDirection() * model->objectiveScale();
+               return gradient_;
+          }
+     } else {
+          // do scaling
+          assert (solution);
+          // for now only if half
+          assert (!fullMatrix_);
+          if (refresh || !gradient_) {
+               if (!gradient_)
+                    gradient_ = new double[numberExtendedColumns_];
+               double direction = model->optimizationDirection() * model->objectiveScale();
+               // direction is actually scale out not scale in
+               //if (direction)
+               //direction = 1.0/direction;
+               const int * columnQuadratic = quadraticObjective_->getIndices();
+               const CoinBigIndex * columnQuadraticStart = quadraticObjective_->getVectorStarts();
+               const int * columnQuadraticLength = quadraticObjective_->getVectorLengths();
+               const double * quadraticElement = quadraticObjective_->getElements();
+               int iColumn;
+               const double * columnScale = model->columnScale();
+               // use current linear cost region (already scaled)
+               if (includeLinear == 1) {
+                    CoinMemcpyN(model->costRegion(), numberExtendedColumns_, gradient_);
+               }	else if (includeLinear == 2) {
+                    memset(gradient_ + numberColumns_, 0, (numberExtendedColumns_ - numberColumns_)*sizeof(double));
+                    if (!columnScale) {
+                         for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                              gradient_[iColumn] = objective_[iColumn] * direction;
+                         }
+                    } else {
+                         for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                              gradient_[iColumn] = objective_[iColumn] * direction * columnScale[iColumn];
+                         }
+                    }
+               } else {
+                    memset(gradient_, 0, numberExtendedColumns_ * sizeof(double));
+               }
+               if (!columnScale) {
+                    if (activated_) {
+                         for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                              double valueI = solution[iColumn];
+                              CoinBigIndex j;
+                              for (j = columnQuadraticStart[iColumn];
+                                        j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                   int jColumn = columnQuadratic[j];
+                                   double valueJ = solution[jColumn];
+                                   double elementValue = quadraticElement[j];
+                                   elementValue *= direction;
+                                   if (iColumn != jColumn) {
+                                        offset += valueI * valueJ * elementValue;
+                                        double gradientI = valueJ * elementValue;
+                                        double gradientJ = valueI * elementValue;
+                                        gradient_[iColumn] += gradientI;
+                                        gradient_[jColumn] += gradientJ;
+                                   } else {
+                                        offset += 0.5 * valueI * valueI * elementValue;
+                                        double gradientI = valueI * elementValue;
+                                        gradient_[iColumn] += gradientI;
+                                   }
+                              }
+                         }
+                    }
+               } else {
+                    // scaling
+                    if (activated_) {
+                         for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                              double valueI = solution[iColumn];
+                              double scaleI = columnScale[iColumn] * direction;
+                              CoinBigIndex j;
+                              for (j = columnQuadraticStart[iColumn];
+                                        j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                                   int jColumn = columnQuadratic[j];
+                                   double valueJ = solution[jColumn];
+                                   double elementValue = quadraticElement[j];
+                                   double scaleJ = columnScale[jColumn];
+                                   elementValue *= scaleI * scaleJ;
+                                   if (iColumn != jColumn) {
+                                        offset += valueI * valueJ * elementValue;
+                                        double gradientI = valueJ * elementValue;
+                                        double gradientJ = valueI * elementValue;
+                                        gradient_[iColumn] += gradientI;
+                                        gradient_[jColumn] += gradientJ;
+                                   } else {
+                                        offset += 0.5 * valueI * valueI * elementValue;
+                                        double gradientI = valueI * elementValue;
+                                        gradient_[iColumn] += gradientI;
+                                   }
+                              }
+                         }
+                    }
+               }
+          }
+          if (model)
+               offset *= model->optimizationDirection();
+          return gradient_;
+     }
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpObjective * ClpQuadraticObjective::clone() const
+{
+     return new ClpQuadraticObjective(*this);
+}
+/* Subset clone.  Duplicates are allowed
+   and order is as given.
+*/
+ClpObjective *
+ClpQuadraticObjective::subsetClone (int numberColumns,
+                                    const int * whichColumns) const
+{
+     return new ClpQuadraticObjective(*this, numberColumns, whichColumns);
+}
+// Resize objective
+void
+ClpQuadraticObjective::resize(int newNumberColumns)
+{
+     if (numberColumns_ != newNumberColumns) {
+          int newExtended = newNumberColumns + (numberExtendedColumns_ - numberColumns_);
+          int i;
+          double * newArray = new double[newExtended];
+          if (objective_)
+               CoinMemcpyN(objective_,	CoinMin(newExtended, numberExtendedColumns_), newArray);
+          delete [] objective_;
+          objective_ = newArray;
+          for (i = numberColumns_; i < newNumberColumns; i++)
+               objective_[i] = 0.0;
+          if (gradient_) {
+               newArray = new double[newExtended];
+               if (gradient_)
+                    CoinMemcpyN(gradient_,	CoinMin(newExtended, numberExtendedColumns_), newArray);
+               delete [] gradient_;
+               gradient_ = newArray;
+               for (i = numberColumns_; i < newNumberColumns; i++)
+                    gradient_[i] = 0.0;
+          }
+          if (quadraticObjective_) {
+               if (newNumberColumns < numberColumns_) {
+                    int * which = new int[numberColumns_-newNumberColumns];
+                    int i;
+                    for (i = newNumberColumns; i < numberColumns_; i++)
+                         which[i-newNumberColumns] = i;
+                    quadraticObjective_->deleteRows(numberColumns_ - newNumberColumns, which);
+                    quadraticObjective_->deleteCols(numberColumns_ - newNumberColumns, which);
+                    delete [] which;
+               } else {
+                    quadraticObjective_->setDimensions(newNumberColumns, newNumberColumns);
+               }
+          }
+          numberColumns_ = newNumberColumns;
+          numberExtendedColumns_ = newExtended;
+     }
+
+}
+// Delete columns in  objective
+void
+ClpQuadraticObjective::deleteSome(int numberToDelete, const int * which)
+{
+     int newNumberColumns = numberColumns_ - numberToDelete;
+     int newExtended = numberExtendedColumns_ - numberToDelete;
+     if (objective_) {
+          int i ;
+          char * deleted = new char[numberColumns_];
+          int numberDeleted = 0;
+          memset(deleted, 0, numberColumns_ * sizeof(char));
+          for (i = 0; i < numberToDelete; i++) {
+               int j = which[i];
+               if (j >= 0 && j < numberColumns_ && !deleted[j]) {
+                    numberDeleted++;
+                    deleted[j] = 1;
+               }
+          }
+          newNumberColumns = numberColumns_ - numberDeleted;
+          newExtended = numberExtendedColumns_ - numberDeleted;
+          double * newArray = new double[newExtended];
+          int put = 0;
+          for (i = 0; i < numberColumns_; i++) {
+               if (!deleted[i]) {
+                    newArray[put++] = objective_[i];
+               }
+          }
+          delete [] objective_;
+          objective_ = newArray;
+          delete [] deleted;
+          CoinMemcpyN(objective_ + numberColumns_,	(numberExtendedColumns_ - numberColumns_),
+                      objective_ + newNumberColumns);
+     }
+     if (gradient_) {
+          int i ;
+          char * deleted = new char[numberColumns_];
+          int numberDeleted = 0;
+          memset(deleted, 0, numberColumns_ * sizeof(char));
+          for (i = 0; i < numberToDelete; i++) {
+               int j = which[i];
+               if (j >= 0 && j < numberColumns_ && !deleted[j]) {
+                    numberDeleted++;
+                    deleted[j] = 1;
+               }
+          }
+          newNumberColumns = numberColumns_ - numberDeleted;
+          newExtended = numberExtendedColumns_ - numberDeleted;
+          double * newArray = new double[newExtended];
+          int put = 0;
+          for (i = 0; i < numberColumns_; i++) {
+               if (!deleted[i]) {
+                    newArray[put++] = gradient_[i];
+               }
+          }
+          delete [] gradient_;
+          gradient_ = newArray;
+          delete [] deleted;
+          CoinMemcpyN(gradient_ + numberColumns_,	(numberExtendedColumns_ - numberColumns_),
+                      gradient_ + newNumberColumns);
+     }
+     numberColumns_ = newNumberColumns;
+     numberExtendedColumns_ = newExtended;
+     if (quadraticObjective_) {
+          quadraticObjective_->deleteCols(numberToDelete, which);
+          quadraticObjective_->deleteRows(numberToDelete, which);
+     }
+}
+
+// Load up quadratic objective
+void
+ClpQuadraticObjective::loadQuadraticObjective(const int numberColumns, const CoinBigIndex * start,
+          const int * column, const double * element, int numberExtended)
+{
+     fullMatrix_ = false;
+     delete quadraticObjective_;
+     quadraticObjective_ = new CoinPackedMatrix(true, numberColumns, numberColumns,
+               start[numberColumns], element, column, start, NULL);
+     numberColumns_ = numberColumns;
+     if (numberExtended > numberExtendedColumns_) {
+          if (objective_) {
+               // make correct size
+               double * newArray = new double[numberExtended];
+               CoinMemcpyN(objective_, numberColumns_, newArray);
+               delete [] objective_;
+               objective_ = newArray;
+               memset(objective_ + numberColumns_, 0, (numberExtended - numberColumns_)*sizeof(double));
+          }
+          if (gradient_) {
+               // make correct size
+               double * newArray = new double[numberExtended];
+               CoinMemcpyN(gradient_, numberColumns_, newArray);
+               delete [] gradient_;
+               gradient_ = newArray;
+               memset(gradient_ + numberColumns_, 0, (numberExtended - numberColumns_)*sizeof(double));
+          }
+          numberExtendedColumns_ = numberExtended;
+     } else {
+          numberExtendedColumns_ = numberColumns_;
+     }
+}
+void
+ClpQuadraticObjective::loadQuadraticObjective (  const CoinPackedMatrix& matrix)
+{
+     delete quadraticObjective_;
+     quadraticObjective_ = new CoinPackedMatrix(matrix);
+}
+// Get rid of quadratic objective
+void
+ClpQuadraticObjective::deleteQuadraticObjective()
+{
+     delete quadraticObjective_;
+     quadraticObjective_ = NULL;
+}
+/* Returns reduced gradient.Returns an offset (to be added to current one).
+ */
+double
+ClpQuadraticObjective::reducedGradient(ClpSimplex * model, double * region,
+                                       bool useFeasibleCosts)
+{
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+
+     //work space
+     CoinIndexedVector  * workSpace = model->rowArray(0);
+
+     CoinIndexedVector arrayVector;
+     arrayVector.reserve(numberRows + 1);
+
+     int iRow;
+#ifdef CLP_DEBUG
+     workSpace->checkClear();
+#endif
+     double * array = arrayVector.denseVector();
+     int * index = arrayVector.getIndices();
+     int number = 0;
+     const double * costNow = gradient(model, model->solutionRegion(), offset_,
+                                       true, useFeasibleCosts ? 2 : 1);
+     double * cost = model->costRegion();
+     const int * pivotVariable = model->pivotVariable();
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          int iPivot = pivotVariable[iRow];
+          double value;
+          if (iPivot < numberColumns)
+               value = costNow[iPivot];
+          else if (!useFeasibleCosts)
+               value = cost[iPivot];
+          else
+               value = 0.0;
+          if (value) {
+               array[iRow] = value;
+               index[number++] = iRow;
+          }
+     }
+     arrayVector.setNumElements(number);
+
+     // Btran basic costs
+     model->factorization()->updateColumnTranspose(workSpace, &arrayVector);
+     double * work = workSpace->denseVector();
+     ClpFillN(work, numberRows, 0.0);
+     // now look at dual solution
+     double * rowReducedCost = region + numberColumns;
+     double * dual = rowReducedCost;
+     const double * rowCost = cost + numberColumns;
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          dual[iRow] = array[iRow];
+     }
+     double * dj = region;
+     ClpDisjointCopyN(costNow, numberColumns, dj);
+
+     model->transposeTimes(-1.0, dual, dj);
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          // slack
+          double value = dual[iRow];
+          value += rowCost[iRow];
+          rowReducedCost[iRow] = value;
+     }
+     return offset_;
+}
+/* Returns step length which gives minimum of objective for
+   solution + theta * change vector up to maximum theta.
+
+   arrays are numberColumns+numberRows
+*/
+double
+ClpQuadraticObjective::stepLength(ClpSimplex * model,
+                                  const double * solution,
+                                  const double * change,
+                                  double maximumTheta,
+                                  double & currentObj,
+                                  double & predictedObj,
+                                  double & thetaObj)
+{
+     const double * cost = model->costRegion();
+     bool inSolve = true;
+     if (!cost) {
+          // not in solve
+          cost = objective_;
+          inSolve = false;
+     }
+     double delta = 0.0;
+     double linearCost = 0.0;
+     int numberRows = model->numberRows();
+     int numberColumns = model->numberColumns();
+     int numberTotal = numberColumns;
+     if (inSolve)
+          numberTotal += numberRows;
+     currentObj = 0.0;
+     thetaObj = 0.0;
+     for (int iColumn = 0; iColumn < numberTotal; iColumn++) {
+          delta += cost[iColumn] * change[iColumn];
+          linearCost += cost[iColumn] * solution[iColumn];
+     }
+     if (!activated_ || !quadraticObjective_) {
+          currentObj = linearCost;
+          thetaObj = currentObj + delta * maximumTheta;
+          if (delta < 0.0) {
+               return maximumTheta;
+          } else {
+	    COIN_DETAIL_PRINT(printf("odd linear direction %g\n", delta));
+               return 0.0;
+          }
+     }
+     assert (model);
+     bool scaling = false;
+     if ((model->rowScale() ||
+               model->objectiveScale() != 1.0 || model->optimizationDirection() != 1.0) && inSolve)
+          scaling = true;
+     const int * columnQuadratic = quadraticObjective_->getIndices();
+     const CoinBigIndex * columnQuadraticStart = quadraticObjective_->getVectorStarts();
+     const int * columnQuadraticLength = quadraticObjective_->getVectorLengths();
+     const double * quadraticElement = quadraticObjective_->getElements();
+     double a = 0.0;
+     double b = delta;
+     double c = 0.0;
+     if (!scaling) {
+          if (!fullMatrix_) {
+               int iColumn;
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    double changeI = change[iColumn];
+                    CoinBigIndex j;
+                    for (j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         double valueJ = solution[jColumn];
+                         double changeJ = change[jColumn];
+                         double elementValue = quadraticElement[j];
+                         if (iColumn != jColumn) {
+                              a += changeI * changeJ * elementValue;
+                              b += (changeI * valueJ + changeJ * valueI) * elementValue;
+                              c += valueI * valueJ * elementValue;
+                         } else {
+                              a += 0.5 * changeI * changeI * elementValue;
+                              b += changeI * valueI * elementValue;
+                              c += 0.5 * valueI * valueI * elementValue;
+                         }
+                    }
+               }
+          } else {
+               // full matrix stored
+               int iColumn;
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    double changeI = change[iColumn];
+                    CoinBigIndex j;
+                    for (j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         double valueJ = solution[jColumn];
+                         double changeJ = change[jColumn];
+                         double elementValue = quadraticElement[j];
+                         valueJ *= elementValue;
+                         a += changeI * changeJ * elementValue;
+                         b += changeI * valueJ;
+                         c += valueI * valueJ;
+                    }
+               }
+               a *= 0.5;
+               c *= 0.5;
+          }
+     } else {
+          // scaling
+          // for now only if half
+          assert (!fullMatrix_);
+          const double * columnScale = model->columnScale();
+          double direction = model->optimizationDirection() * model->objectiveScale();
+          // direction is actually scale out not scale in
+          if (direction)
+               direction = 1.0 / direction;
+          if (!columnScale) {
+               for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    double changeI = change[iColumn];
+                    CoinBigIndex j;
+                    for (j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         double valueJ = solution[jColumn];
+                         double changeJ = change[jColumn];
+                         double elementValue = quadraticElement[j];
+                         elementValue *= direction;
+                         if (iColumn != jColumn) {
+                              a += changeI * changeJ * elementValue;
+                              b += (changeI * valueJ + changeJ * valueI) * elementValue;
+                              c += valueI * valueJ * elementValue;
+                         } else {
+                              a += 0.5 * changeI * changeI * elementValue;
+                              b += changeI * valueI * elementValue;
+                              c += 0.5 * valueI * valueI * elementValue;
+                         }
+                    }
+               }
+          } else {
+               // scaling
+               for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    double changeI = change[iColumn];
+                    double scaleI = columnScale[iColumn] * direction;
+                    CoinBigIndex j;
+                    for (j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         double valueJ = solution[jColumn];
+                         double changeJ = change[jColumn];
+                         double elementValue = quadraticElement[j];
+                         elementValue *= scaleI * columnScale[jColumn];
+                         if (iColumn != jColumn) {
+                              a += changeI * changeJ * elementValue;
+                              b += (changeI * valueJ + changeJ * valueI) * elementValue;
+                              c += valueI * valueJ * elementValue;
+                         } else {
+                              a += 0.5 * changeI * changeI * elementValue;
+                              b += changeI * valueI * elementValue;
+                              c += 0.5 * valueI * valueI * elementValue;
+                         }
+                    }
+               }
+          }
+     }
+     double theta;
+     //printf("Current cost %g\n",c+linearCost);
+     currentObj = c + linearCost;
+     thetaObj = currentObj + a * maximumTheta * maximumTheta + b * maximumTheta;
+     // minimize a*x*x + b*x + c
+     if (a <= 0.0) {
+          theta = maximumTheta;
+     } else {
+          theta = -0.5 * b / a;
+     }
+     predictedObj = currentObj + a * theta * theta + b * theta;
+     if (b > 0.0) {
+          if (model->messageHandler()->logLevel() & 32)
+               printf("a %g b %g c %g => %g\n", a, b, c, theta);
+          b = 0.0;
+     }
+     return CoinMin(theta, maximumTheta);
+}
+// Return objective value (without any ClpModel offset) (model may be NULL)
+double
+ClpQuadraticObjective::objectiveValue(const ClpSimplex * model, const double * solution) const
+{
+     bool scaling = false;
+     if (model && (model->rowScale() ||
+                   model->objectiveScale() != 1.0))
+          scaling = true;
+     const double * cost = NULL;
+     if (model)
+          cost = model->costRegion();
+     if (!cost) {
+          // not in solve
+          cost = objective_;
+          scaling = false;
+     }
+     double linearCost = 0.0;
+     int numberColumns = model->numberColumns();
+     int numberTotal = numberColumns;
+     double currentObj = 0.0;
+     for (int iColumn = 0; iColumn < numberTotal; iColumn++) {
+          linearCost += cost[iColumn] * solution[iColumn];
+     }
+     if (!activated_ || !quadraticObjective_) {
+          currentObj = linearCost;
+          return currentObj;
+     }
+     assert (model);
+     const int * columnQuadratic = quadraticObjective_->getIndices();
+     const CoinBigIndex * columnQuadraticStart = quadraticObjective_->getVectorStarts();
+     const int * columnQuadraticLength = quadraticObjective_->getVectorLengths();
+     const double * quadraticElement = quadraticObjective_->getElements();
+     double c = 0.0;
+     if (!scaling) {
+          if (!fullMatrix_) {
+               int iColumn;
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    CoinBigIndex j;
+                    for (j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         double valueJ = solution[jColumn];
+                         double elementValue = quadraticElement[j];
+                         if (iColumn != jColumn) {
+                              c += valueI * valueJ * elementValue;
+                         } else {
+                              c += 0.5 * valueI * valueI * elementValue;
+                         }
+                    }
+               }
+          } else {
+               // full matrix stored
+               int iColumn;
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    CoinBigIndex j;
+                    for (j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         double valueJ = solution[jColumn];
+                         double elementValue = quadraticElement[j];
+                         valueJ *= elementValue;
+                         c += valueI * valueJ;
+                    }
+               }
+               c *= 0.5;
+          }
+     } else {
+          // scaling
+          // for now only if half
+          assert (!fullMatrix_);
+          const double * columnScale = model->columnScale();
+          double direction = model->objectiveScale();
+          // direction is actually scale out not scale in
+          if (direction)
+               direction = 1.0 / direction;
+          if (!columnScale) {
+               for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    CoinBigIndex j;
+                    for (j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         double valueJ = solution[jColumn];
+                         double elementValue = quadraticElement[j];
+                         elementValue *= direction;
+                         if (iColumn != jColumn) {
+                              c += valueI * valueJ * elementValue;
+                         } else {
+                              c += 0.5 * valueI * valueI * elementValue;
+                         }
+                    }
+               }
+          } else {
+               // scaling
+               for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double valueI = solution[iColumn];
+                    double scaleI = columnScale[iColumn] * direction;
+                    CoinBigIndex j;
+                    for (j = columnQuadraticStart[iColumn];
+                              j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+                         int jColumn = columnQuadratic[j];
+                         double valueJ = solution[jColumn];
+                         double elementValue = quadraticElement[j];
+                         elementValue *= scaleI * columnScale[jColumn];
+                         if (iColumn != jColumn) {
+                              c += valueI * valueJ * elementValue;
+                         } else {
+                              c += 0.5 * valueI * valueI * elementValue;
+                         }
+                    }
+               }
+          }
+     }
+     currentObj = c + linearCost;
+     return currentObj;
+}
+// Scale objective
+void
+ClpQuadraticObjective::reallyScale(const double * columnScale)
+{
+     const int * columnQuadratic = quadraticObjective_->getIndices();
+     const CoinBigIndex * columnQuadraticStart = quadraticObjective_->getVectorStarts();
+     const int * columnQuadraticLength = quadraticObjective_->getVectorLengths();
+     double * quadraticElement = quadraticObjective_->getMutableElements();
+     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          double scaleI = columnScale[iColumn];
+          objective_[iColumn] *= scaleI;
+          CoinBigIndex j;
+          for (j = columnQuadraticStart[iColumn];
+                    j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+               int jColumn = columnQuadratic[j];
+               quadraticElement[j] *= scaleI * columnScale[jColumn];
+          }
+     }
+}
+/* Given a zeroed array sets nonlinear columns to 1.
+   Returns number of nonlinear columns
+*/
+int
+ClpQuadraticObjective::markNonlinear(char * which)
+{
+     int iColumn;
+     const int * columnQuadratic = quadraticObjective_->getIndices();
+     const CoinBigIndex * columnQuadraticStart = quadraticObjective_->getVectorStarts();
+     const int * columnQuadraticLength = quadraticObjective_->getVectorLengths();
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          CoinBigIndex j;
+          for (j = columnQuadraticStart[iColumn];
+                    j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
+               int jColumn = columnQuadratic[j];
+               which[jColumn] = 1;
+               which[iColumn] = 1;
+          }
+     }
+     int numberNonLinearColumns = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if(which[iColumn])
+               numberNonLinearColumns++;
+     }
+     return numberNonLinearColumns;
+}
diff --git a/cbits/coin/ClpQuadraticObjective.hpp b/cbits/coin/ClpQuadraticObjective.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpQuadraticObjective.hpp
@@ -0,0 +1,155 @@
+/* $Id: ClpQuadraticObjective.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef ClpQuadraticObjective_H
+#define ClpQuadraticObjective_H
+
+#include "ClpObjective.hpp"
+#include "CoinPackedMatrix.hpp"
+
+//#############################################################################
+
+/** Quadratic Objective Class
+
+*/
+
+class ClpQuadraticObjective : public ClpObjective {
+
+public:
+
+     ///@name Stuff
+     //@{
+
+     /** Returns gradient.  If Quadratic then solution may be NULL,
+         also returns an offset (to be added to current one)
+         If refresh is false then uses last solution
+         Uses model for scaling
+         includeLinear 0 - no, 1 as is, 2 as feasible
+     */
+     virtual double * gradient(const ClpSimplex * model,
+                               const double * solution, double & offset, bool refresh,
+                               int includeLinear = 2);
+     /// Resize objective
+     /** Returns reduced gradient.Returns an offset (to be added to current one).
+     */
+     virtual double reducedGradient(ClpSimplex * model, double * region,
+                                    bool useFeasibleCosts);
+     /** Returns step length which gives minimum of objective for
+         solution + theta * change vector up to maximum theta.
+
+         arrays are numberColumns+numberRows
+         Also sets current objective, predicted and at maximumTheta
+     */
+     virtual double stepLength(ClpSimplex * model,
+                               const double * solution,
+                               const double * change,
+                               double maximumTheta,
+                               double & currentObj,
+                               double & predictedObj,
+                               double & thetaObj);
+     /// Return objective value (without any ClpModel offset) (model may be NULL)
+     virtual double objectiveValue(const ClpSimplex * model, const double * solution) const ;
+     virtual void resize(int newNumberColumns) ;
+     /// Delete columns in  objective
+     virtual void deleteSome(int numberToDelete, const int * which) ;
+     /// Scale objective
+     virtual void reallyScale(const double * columnScale) ;
+     /** Given a zeroed array sets nonlinear columns to 1.
+         Returns number of nonlinear columns
+      */
+     virtual int markNonlinear(char * which);
+
+     //@}
+
+
+     ///@name Constructors and destructors
+     //@{
+     /// Default Constructor
+     ClpQuadraticObjective();
+
+     /// Constructor from objective
+     ClpQuadraticObjective(const double * linearObjective, int numberColumns,
+                           const CoinBigIndex * start,
+                           const int * column, const double * element,
+                           int numberExtendedColumns_ = -1);
+
+     /** Copy constructor .
+         If type is -1 then make sure half symmetric,
+         if +1 then make sure full
+     */
+     ClpQuadraticObjective(const ClpQuadraticObjective & rhs, int type = 0);
+     /** Subset constructor.  Duplicates are allowed
+         and order is as given.
+     */
+     ClpQuadraticObjective (const ClpQuadraticObjective &rhs, int numberColumns,
+                            const int * whichColumns) ;
+
+     /// Assignment operator
+     ClpQuadraticObjective & operator=(const ClpQuadraticObjective& rhs);
+
+     /// Destructor
+     virtual ~ClpQuadraticObjective ();
+
+     /// Clone
+     virtual ClpObjective * clone() const;
+     /** Subset clone.  Duplicates are allowed
+         and order is as given.
+     */
+     virtual ClpObjective * subsetClone (int numberColumns,
+                                         const int * whichColumns) const;
+
+     /** Load up quadratic objective.  This is stored as a CoinPackedMatrix */
+     void loadQuadraticObjective(const int numberColumns,
+                                 const CoinBigIndex * start,
+                                 const int * column, const double * element,
+                                 int numberExtendedColumns = -1);
+     void loadQuadraticObjective (  const CoinPackedMatrix& matrix);
+     /// Get rid of quadratic objective
+     void deleteQuadraticObjective();
+     //@}
+     ///@name Gets and sets
+     //@{
+     /// Quadratic objective
+     inline CoinPackedMatrix * quadraticObjective() const     {
+          return quadraticObjective_;
+     }
+     /// Linear objective
+     inline double * linearObjective() const     {
+          return objective_;
+     }
+     /// Length of linear objective which could be bigger
+     inline int numberExtendedColumns() const {
+          return numberExtendedColumns_;
+     }
+     /// Number of columns in quadratic objective
+     inline int numberColumns() const {
+          return numberColumns_;
+     }
+     /// If a full or half matrix
+     inline bool fullMatrix() const {
+          return fullMatrix_;
+     }
+     //@}
+
+     //---------------------------------------------------------------------------
+
+private:
+     ///@name Private member data
+     /// Quadratic objective
+     CoinPackedMatrix * quadraticObjective_;
+     /// Objective
+     double * objective_;
+     /// Gradient
+     double * gradient_;
+     /// Useful to have number of columns about
+     int numberColumns_;
+     /// Also length of linear objective which could be bigger
+     int numberExtendedColumns_;
+     /// True if full symmetric matrix, false if half
+     bool fullMatrix_;
+     //@}
+};
+
+#endif
diff --git a/cbits/coin/ClpSimplex.cpp b/cbits/coin/ClpSimplex.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplex.cpp
@@ -0,0 +1,12040 @@
+/* $Id: ClpSimplex.cpp 1989 2013-11-11 17:27:32Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+//#undef NDEBUG
+
+#include "ClpConfig.h"
+
+#include "CoinPragma.hpp"
+#include <math.h>
+
+#if SLIM_CLP==2
+#define SLIM_NOIO
+#endif
+#include "CoinHelperFunctions.hpp"
+#include "CoinFloatEqual.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpDualRowDantzig.hpp"
+#include "ClpDualRowSteepest.hpp"
+#include "ClpPrimalColumnDantzig.hpp"
+#include "ClpPrimalColumnSteepest.hpp"
+#include "ClpNonLinearCost.hpp"
+#include "ClpMessage.hpp"
+#include "ClpEventHandler.hpp"
+#include "ClpLinearObjective.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "CoinModel.hpp"
+#include "CoinLpIO.hpp"
+#include <cfloat>
+#if CLP_HAS_ABC
+#include "CoinAbcCommon.hpp"
+#endif
+
+#include <string>
+#include <stdio.h>
+#include <iostream>
+//#############################################################################
+
+ClpSimplex::ClpSimplex (bool emptyMessages) :
+
+     ClpModel(emptyMessages),
+     bestPossibleImprovement_(0.0),
+     zeroTolerance_(1.0e-13),
+     columnPrimalSequence_(-2),
+     rowPrimalSequence_(-2),
+     bestObjectiveValue_(-COIN_DBL_MAX),
+     moreSpecialOptions_(2),
+     baseIteration_(0),
+     primalToleranceToGetOptimal_(-1.0),
+     largeValue_(1.0e15),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     alphaAccuracy_(-1.0),
+     dualBound_(1.0e10),
+     alpha_(0.0),
+     theta_(0.0),
+     lowerIn_(0.0),
+     valueIn_(0.0),
+     upperIn_(-COIN_DBL_MAX),
+     dualIn_(0.0),
+     lowerOut_(-1),
+     valueOut_(-1),
+     upperOut_(-1),
+     dualOut_(-1),
+     dualTolerance_(1.0e-7),
+     primalTolerance_(1.0e-7),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     infeasibilityCost_(1.0e10),
+     sumOfRelaxedDualInfeasibilities_(0.0),
+     sumOfRelaxedPrimalInfeasibilities_(0.0),
+     acceptablePivot_(1.0e-8),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rowObjectiveWork_(NULL),
+     objectiveWork_(NULL),
+     sequenceIn_(-1),
+     directionIn_(-1),
+     sequenceOut_(-1),
+     directionOut_(-1),
+     pivotRow_(-1),
+     lastGoodIteration_(-100),
+     dj_(NULL),
+     rowReducedCost_(NULL),
+     reducedCostWork_(NULL),
+     solution_(NULL),
+     rowActivityWork_(NULL),
+     columnActivityWork_(NULL),
+     numberDualInfeasibilities_(0),
+     numberDualInfeasibilitiesWithoutFree_(0),
+     numberPrimalInfeasibilities_(100),
+     numberRefinements_(0),
+     pivotVariable_(NULL),
+     factorization_(NULL),
+     savedSolution_(NULL),
+     numberTimesOptimal_(0),
+     disasterArea_(NULL),
+     changeMade_(1),
+     algorithm_(0),
+     forceFactorization_(-1),
+     perturbation_(100),
+     nonLinearCost_(NULL),
+     lastBadIteration_(-999999),
+     lastFlaggedIteration_(-999999),
+     numberFake_(0),
+     numberChanged_(0),
+     progressFlag_(0),
+     firstFree_(-1),
+     numberExtraRows_(0),
+     maximumBasic_(0),
+     dontFactorizePivots_(0),
+     incomingInfeasibility_(1.0),
+     allowedInfeasibility_(10.0),
+     automaticScale_(0),
+     maximumPerturbationSize_(0),
+     perturbationArray_(NULL),
+     baseModel_(NULL)
+#ifdef ABC_INHERIT
+     ,abcSimplex_(NULL),
+     abcState_(0)
+#endif
+{
+     int i;
+     for (i = 0; i < 6; i++) {
+          rowArray_[i] = NULL;
+          columnArray_[i] = NULL;
+     }
+     for (i = 0; i < 4; i++) {
+          spareIntArray_[i] = 0;
+          spareDoubleArray_[i] = 0.0;
+     }
+     saveStatus_ = NULL;
+     // get an empty factorization so we can set tolerances etc
+     getEmptyFactorization();
+     // Say sparse
+     factorization_->sparseThreshold(1);
+     // say Steepest pricing
+     dualRowPivot_ = new ClpDualRowSteepest();
+     // say Steepest pricing
+     primalColumnPivot_ = new ClpPrimalColumnSteepest();
+     solveType_ = 1; // say simplex based life form
+
+}
+
+// Subproblem constructor
+ClpSimplex::ClpSimplex ( const ClpModel * rhs,
+                         int numberRows, const int * whichRow,
+                         int numberColumns, const int * whichColumn,
+                         bool dropNames, bool dropIntegers, bool fixOthers)
+     : ClpModel(rhs, numberRows, whichRow,
+                numberColumns, whichColumn, dropNames, dropIntegers),
+     bestPossibleImprovement_(0.0),
+     zeroTolerance_(1.0e-13),
+     columnPrimalSequence_(-2),
+     rowPrimalSequence_(-2),
+     bestObjectiveValue_(-COIN_DBL_MAX),
+     moreSpecialOptions_(2),
+     baseIteration_(0),
+     primalToleranceToGetOptimal_(-1.0),
+     largeValue_(1.0e15),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     alphaAccuracy_(-1.0),
+     dualBound_(1.0e10),
+     alpha_(0.0),
+     theta_(0.0),
+     lowerIn_(0.0),
+     valueIn_(0.0),
+     upperIn_(-COIN_DBL_MAX),
+     dualIn_(0.0),
+     lowerOut_(-1),
+     valueOut_(-1),
+     upperOut_(-1),
+     dualOut_(-1),
+     dualTolerance_(1.0e-7),
+     primalTolerance_(1.0e-7),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     infeasibilityCost_(1.0e10),
+     sumOfRelaxedDualInfeasibilities_(0.0),
+     sumOfRelaxedPrimalInfeasibilities_(0.0),
+     acceptablePivot_(1.0e-8),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rowObjectiveWork_(NULL),
+     objectiveWork_(NULL),
+     sequenceIn_(-1),
+     directionIn_(-1),
+     sequenceOut_(-1),
+     directionOut_(-1),
+     pivotRow_(-1),
+     lastGoodIteration_(-100),
+     dj_(NULL),
+     rowReducedCost_(NULL),
+     reducedCostWork_(NULL),
+     solution_(NULL),
+     rowActivityWork_(NULL),
+     columnActivityWork_(NULL),
+     numberDualInfeasibilities_(0),
+     numberDualInfeasibilitiesWithoutFree_(0),
+     numberPrimalInfeasibilities_(100),
+     numberRefinements_(0),
+     pivotVariable_(NULL),
+     factorization_(NULL),
+     savedSolution_(NULL),
+     numberTimesOptimal_(0),
+     disasterArea_(NULL),
+     changeMade_(1),
+     algorithm_(0),
+     forceFactorization_(-1),
+     perturbation_(100),
+     nonLinearCost_(NULL),
+     lastBadIteration_(-999999),
+     lastFlaggedIteration_(-999999),
+     numberFake_(0),
+     numberChanged_(0),
+     progressFlag_(0),
+     firstFree_(-1),
+     numberExtraRows_(0),
+     maximumBasic_(0),
+     dontFactorizePivots_(0),
+     incomingInfeasibility_(1.0),
+     allowedInfeasibility_(10.0),
+     automaticScale_(0),
+     maximumPerturbationSize_(0),
+     perturbationArray_(NULL),
+     baseModel_(NULL)
+#ifdef ABC_INHERIT
+     ,abcSimplex_(NULL),
+     abcState_(0)
+#endif
+{
+     int i;
+     for (i = 0; i < 6; i++) {
+          rowArray_[i] = NULL;
+          columnArray_[i] = NULL;
+     }
+     for (i = 0; i < 4; i++) {
+          spareIntArray_[i] = 0;
+          spareDoubleArray_[i] = 0.0;
+     }
+     saveStatus_ = NULL;
+     // get an empty factorization so we can set tolerances etc
+     getEmptyFactorization();
+     // say Steepest pricing
+     dualRowPivot_ = new ClpDualRowSteepest();
+     // say Steepest pricing
+     primalColumnPivot_ = new ClpPrimalColumnSteepest();
+     solveType_ = 1; // say simplex based life form
+     if (fixOthers) {
+          int numberOtherColumns = rhs->numberColumns();
+          int numberOtherRows = rhs->numberRows();
+          double * solution = new double [numberOtherColumns];
+          CoinZeroN(solution, numberOtherColumns);
+          int i;
+          for (i = 0; i < numberColumns; i++) {
+               int iColumn = whichColumn[i];
+               if (solution[iColumn])
+                    fixOthers = false; // duplicates
+               solution[iColumn] = 1.0;
+          }
+          if (fixOthers) {
+               const double * otherSolution = rhs->primalColumnSolution();
+               const double * objective = rhs->objective();
+               double offset = 0.0;
+               for (i = 0; i < numberOtherColumns; i++) {
+                    if (solution[i]) {
+                         solution[i] = 0.0; // in
+                    } else {
+                         solution[i] = otherSolution[i];
+                         offset += objective[i] * otherSolution[i];
+                    }
+               }
+               double * rhsModification = new double [numberOtherRows];
+               CoinZeroN(rhsModification, numberOtherRows);
+               rhs->matrix()->times(solution, rhsModification) ;
+               for ( i = 0; i < numberRows; i++) {
+                    int iRow = whichRow[i];
+                    if (rowLower_[i] > -1.0e20)
+                         rowLower_[i] -= rhsModification[iRow];
+                    if (rowUpper_[i] < 1.0e20)
+                         rowUpper_[i] -= rhsModification[iRow];
+               }
+               delete [] rhsModification;
+               setObjectiveOffset(rhs->objectiveOffset() - offset);
+               // And set objective value to match
+               setObjectiveValue(rhs->objectiveValue());
+          }
+          delete [] solution;
+     }
+}
+// Subproblem constructor
+ClpSimplex::ClpSimplex ( const ClpSimplex * rhs,
+                         int numberRows, const int * whichRow,
+                         int numberColumns, const int * whichColumn,
+                         bool dropNames, bool dropIntegers, bool fixOthers)
+     : ClpModel(rhs, numberRows, whichRow,
+                numberColumns, whichColumn, dropNames, dropIntegers),
+     bestPossibleImprovement_(0.0),
+     zeroTolerance_(1.0e-13),
+     columnPrimalSequence_(-2),
+     rowPrimalSequence_(-2),
+     bestObjectiveValue_(-COIN_DBL_MAX),
+     moreSpecialOptions_(2),
+     baseIteration_(0),
+     primalToleranceToGetOptimal_(-1.0),
+     largeValue_(1.0e15),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     alphaAccuracy_(-1.0),
+     dualBound_(1.0e10),
+     alpha_(0.0),
+     theta_(0.0),
+     lowerIn_(0.0),
+     valueIn_(0.0),
+     upperIn_(-COIN_DBL_MAX),
+     dualIn_(0.0),
+     lowerOut_(-1),
+     valueOut_(-1),
+     upperOut_(-1),
+     dualOut_(-1),
+     dualTolerance_(rhs->dualTolerance_),
+     primalTolerance_(rhs->primalTolerance_),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     infeasibilityCost_(1.0e10),
+     sumOfRelaxedDualInfeasibilities_(0.0),
+     sumOfRelaxedPrimalInfeasibilities_(0.0),
+     acceptablePivot_(1.0e-8),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rowObjectiveWork_(NULL),
+     objectiveWork_(NULL),
+     sequenceIn_(-1),
+     directionIn_(-1),
+     sequenceOut_(-1),
+     directionOut_(-1),
+     pivotRow_(-1),
+     lastGoodIteration_(-100),
+     dj_(NULL),
+     rowReducedCost_(NULL),
+     reducedCostWork_(NULL),
+     solution_(NULL),
+     rowActivityWork_(NULL),
+     columnActivityWork_(NULL),
+     numberDualInfeasibilities_(0),
+     numberDualInfeasibilitiesWithoutFree_(0),
+     numberPrimalInfeasibilities_(100),
+     numberRefinements_(0),
+     pivotVariable_(NULL),
+     factorization_(NULL),
+     savedSolution_(NULL),
+     numberTimesOptimal_(0),
+     disasterArea_(NULL),
+     changeMade_(1),
+     algorithm_(0),
+     forceFactorization_(-1),
+     perturbation_(100),
+     nonLinearCost_(NULL),
+     lastBadIteration_(-999999),
+     lastFlaggedIteration_(-999999),
+     numberFake_(0),
+     numberChanged_(0),
+     progressFlag_(0),
+     firstFree_(-1),
+     numberExtraRows_(0),
+     maximumBasic_(0),
+     dontFactorizePivots_(0),
+     incomingInfeasibility_(1.0),
+     allowedInfeasibility_(10.0),
+     automaticScale_(0),
+     maximumPerturbationSize_(0),
+     perturbationArray_(NULL),
+     baseModel_(NULL)
+#ifdef ABC_INHERIT
+     ,abcSimplex_(NULL),
+     abcState_(rhs->abcState_)
+#endif
+{
+     int i;
+     for (i = 0; i < 6; i++) {
+          rowArray_[i] = NULL;
+          columnArray_[i] = NULL;
+     }
+     for (i = 0; i < 4; i++) {
+          spareIntArray_[i] = 0;
+          spareDoubleArray_[i] = 0.0;
+     }
+     saveStatus_ = NULL;
+     factorization_ = new ClpFactorization(*rhs->factorization_, -numberRows_);
+     //factorization_ = new ClpFactorization(*rhs->factorization_,
+     //				rhs->factorization_->goDenseThreshold());
+     ClpDualRowDantzig * pivot =
+          dynamic_cast< ClpDualRowDantzig*>(rhs->dualRowPivot_);
+     // say Steepest pricing
+     if (!pivot)
+          dualRowPivot_ = new ClpDualRowSteepest();
+     else
+          dualRowPivot_ = new ClpDualRowDantzig();
+     // say Steepest pricing
+     primalColumnPivot_ = new ClpPrimalColumnSteepest();
+     solveType_ = 1; // say simplex based life form
+     if (fixOthers) {
+          int numberOtherColumns = rhs->numberColumns();
+          int numberOtherRows = rhs->numberRows();
+          double * solution = new double [numberOtherColumns];
+          CoinZeroN(solution, numberOtherColumns);
+          int i;
+          for (i = 0; i < numberColumns; i++) {
+               int iColumn = whichColumn[i];
+               if (solution[iColumn])
+                    fixOthers = false; // duplicates
+               solution[iColumn] = 1.0;
+          }
+          if (fixOthers) {
+               const double * otherSolution = rhs->primalColumnSolution();
+               const double * objective = rhs->objective();
+               double offset = 0.0;
+               for (i = 0; i < numberOtherColumns; i++) {
+                    if (solution[i]) {
+                         solution[i] = 0.0; // in
+                    } else {
+                         solution[i] = otherSolution[i];
+                         offset += objective[i] * otherSolution[i];
+                    }
+               }
+               double * rhsModification = new double [numberOtherRows];
+               CoinZeroN(rhsModification, numberOtherRows);
+               rhs->matrix()->times(solution, rhsModification) ;
+               for ( i = 0; i < numberRows; i++) {
+                    int iRow = whichRow[i];
+                    if (rowLower_[i] > -1.0e20)
+                         rowLower_[i] -= rhsModification[iRow];
+                    if (rowUpper_[i] < 1.0e20)
+                         rowUpper_[i] -= rhsModification[iRow];
+               }
+               delete [] rhsModification;
+               setObjectiveOffset(rhs->objectiveOffset() - offset);
+               // And set objective value to match
+               setObjectiveValue(rhs->objectiveValue());
+          }
+          delete [] solution;
+     }
+     if (rhs->maximumPerturbationSize_) {
+          maximumPerturbationSize_ = 2 * numberColumns;
+          perturbationArray_ = new double [maximumPerturbationSize_];
+          for (i = 0; i < numberColumns; i++) {
+               int iColumn = whichColumn[i];
+               perturbationArray_[2*i] = rhs->perturbationArray_[2*iColumn];
+               perturbationArray_[2*i+1] = rhs->perturbationArray_[2*iColumn+1];
+          }
+     }
+}
+// Puts solution back small model
+void
+ClpSimplex::getbackSolution(const ClpSimplex & smallModel, const int * whichRow, const int * whichColumn)
+{
+     setSumDualInfeasibilities(smallModel.sumDualInfeasibilities());
+     setNumberDualInfeasibilities(smallModel.numberDualInfeasibilities());
+     setSumPrimalInfeasibilities(smallModel.sumPrimalInfeasibilities());
+     setNumberPrimalInfeasibilities(smallModel.numberPrimalInfeasibilities());
+     setNumberIterations(smallModel.numberIterations());
+     setProblemStatus(smallModel.status());
+     setObjectiveValue(smallModel.objectiveValue());
+     const double * solution2 = smallModel.primalColumnSolution();
+     int i;
+     int numberRows2 = smallModel.numberRows();
+     int numberColumns2 = smallModel.numberColumns();
+     const double * dj2 = smallModel.dualColumnSolution();
+     for ( i = 0; i < numberColumns2; i++) {
+          int iColumn = whichColumn[i];
+          columnActivity_[iColumn] = solution2[i];
+          reducedCost_[iColumn] = dj2[i];
+          setStatus(iColumn, smallModel.getStatus(i));
+     }
+     const double * dual2 = smallModel.dualRowSolution();
+     memset(dual_, 0, numberRows_ * sizeof(double));
+     for (i = 0; i < numberRows2; i++) {
+          int iRow = whichRow[i];
+          setRowStatus(iRow, smallModel.getRowStatus(i));
+          dual_[iRow] = dual2[i];
+     }
+     CoinZeroN(rowActivity_, numberRows_);
+#if 0
+     if (!problemStatus_) {
+          ClpDisjointCopyN(smallModel.objective(), smallModel.numberColumns_, smallModel.reducedCost_);
+          smallModel.matrix_->transposeTimes(-1.0, smallModel.dual_, smallModel.reducedCost_);
+          for (int i = 0; i < smallModel.numberColumns_; i++) {
+               if (smallModel.getColumnStatus(i) == basic)
+                    assert (fabs(smallModel.reducedCost_[i]) < 1.0e-5);
+          }
+          ClpDisjointCopyN(objective(), numberColumns_, reducedCost_);
+          matrix_->transposeTimes(-1.0, dual_, reducedCost_);
+          for (int i = 0; i < numberColumns_; i++) {
+               if (getColumnStatus(i) == basic)
+                    assert (fabs(reducedCost_[i]) < 1.0e-5);
+          }
+     }
+#endif
+     matrix()->times(columnActivity_, rowActivity_) ;
+}
+
+//-----------------------------------------------------------------------------
+
+ClpSimplex::~ClpSimplex ()
+{
+     setPersistenceFlag(0);
+     gutsOfDelete(0);
+     delete nonLinearCost_;
+}
+//#############################################################################
+void ClpSimplex::setLargeValue( double value)
+{
+     if (value > 0.0 && value < COIN_DBL_MAX)
+          largeValue_ = value;
+}
+int
+ClpSimplex::gutsOfSolution ( double * givenDuals,
+                             const double * givenPrimals,
+                             bool valuesPass)
+{
+
+
+     // if values pass, save values of basic variables
+     double * save = NULL;
+     double oldValue = 0.0;
+     if (valuesPass) {
+          assert(algorithm_ > 0); // only primal at present
+          assert(nonLinearCost_);
+          int iRow;
+          checkPrimalSolution( rowActivityWork_, columnActivityWork_);
+          // get correct bounds on all variables
+          nonLinearCost_->checkInfeasibilities(primalTolerance_);
+          oldValue = nonLinearCost_->largestInfeasibility();
+          save = new double[numberRows_];
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int iPivot = pivotVariable_[iRow];
+               save[iRow] = solution_[iPivot];
+          }
+     }
+     // do work
+     computePrimals(rowActivityWork_, columnActivityWork_);
+     // If necessary - override results
+     if (givenPrimals) {
+          CoinMemcpyN(givenPrimals, numberColumns_, columnActivityWork_);
+          memset(rowActivityWork_, 0, numberRows_ * sizeof(double));
+          times(-1.0, columnActivityWork_, rowActivityWork_);
+     }
+     double objectiveModification = 0.0;
+     if (algorithm_ > 0 && nonLinearCost_ != NULL) {
+          // primal algorithm
+          // get correct bounds on all variables
+          // If  4 bit set - Force outgoing variables to exact bound (primal)
+          if ((specialOptions_ & 4) == 0)
+               nonLinearCost_->checkInfeasibilities(primalTolerance_);
+          else
+               nonLinearCost_->checkInfeasibilities(0.0);
+          objectiveModification += nonLinearCost_->changeInCost();
+          if (nonLinearCost_->numberInfeasibilities())
+               if (handler_->detail(CLP_SIMPLEX_NONLINEAR, messages_) < 100) {
+                    handler_->message(CLP_SIMPLEX_NONLINEAR, messages_)
+                              << nonLinearCost_->changeInCost()
+                              << nonLinearCost_->numberInfeasibilities()
+                              << CoinMessageEol;
+               }
+     }
+     if (valuesPass) {
+          double badInfeasibility = nonLinearCost_->largestInfeasibility();
+#ifdef CLP_DEBUG
+          std::cout << "Largest given infeasibility " << oldValue
+                    << " now " << nonLinearCost_->largestInfeasibility() << std::endl;
+#endif
+          int numberOut = 0;
+          // But may be very large rhs etc
+          double useError = CoinMin(largestPrimalError_,
+                                    1.0e5 / maximumAbsElement(solution_, numberRows_ + numberColumns_));
+          if ((oldValue < incomingInfeasibility_ || badInfeasibility >
+                    (CoinMax(10.0 * allowedInfeasibility_, 100.0 * oldValue)))
+                    && (badInfeasibility > CoinMax(incomingInfeasibility_, allowedInfeasibility_) ||
+                        useError > 1.0e-3)) {
+	       if (algorithm_>1) {
+		 // nonlinear
+		 //printf("Original largest infeas %g, now %g, primalError %g\n",
+		 //	oldValue,nonLinearCost_->largestInfeasibility(),
+		 //	largestPrimalError_);
+		 //printf("going to all slack\n");
+		 allSlackBasis(true);
+		 CoinIotaN(pivotVariable_, numberRows_, numberColumns_);
+		 return 1;
+	       }
+               //printf("Original largest infeas %g, now %g, primalError %g\n",
+               //     oldValue,nonLinearCost_->largestInfeasibility(),
+               //     largestPrimalError_);
+               // throw out up to 1000 structurals
+	       int maxOut = (allowedInfeasibility_==10.0) ? 1000 : 100;
+               int iRow;
+               int * sort = new int[numberRows_];
+               // first put back solution and store difference
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    double difference = fabs(solution_[iPivot] - save[iRow]);
+                    solution_[iPivot] = save[iRow];
+                    save[iRow] = difference;
+               }
+               int numberBasic = 0;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+
+                    if (iPivot < numberColumns_) {
+                         // column
+                         double difference = save[iRow];
+                         if (difference > 1.0e-4) {
+                              sort[numberOut] = iRow;
+                              save[numberOut++] = -difference;
+                              if (getStatus(iPivot) == basic)
+                                   numberBasic++;
+                         }
+                    }
+               }
+               if (!numberBasic) {
+                    //printf("no errors on basic - going to all slack - numberOut %d\n",numberOut);
+#if 0
+                    allSlackBasis(true);
+                    CoinIotaN(pivotVariable_, numberRows_, numberColumns_);
+#else
+                    // allow
+                    numberOut = 0;
+#endif
+               }
+               CoinSort_2(save, save + numberOut, sort);
+               numberOut = CoinMin(maxOut, numberOut);
+               for (iRow = 0; iRow < numberOut; iRow++) {
+                    int jRow = sort[iRow];
+                    int iColumn = pivotVariable_[jRow];
+                    setColumnStatus(iColumn, superBasic);
+                    setRowStatus(jRow, basic);
+                    pivotVariable_[jRow] = jRow + numberColumns_;
+                    if (fabs(solution_[iColumn]) > 1.0e10) {
+                         if (upper_[iColumn] < 0.0) {
+                              solution_[iColumn] = upper_[iColumn];
+                         } else if (lower_[iColumn] > 0.0) {
+                              solution_[iColumn] = lower_[iColumn];
+                         } else {
+                              solution_[iColumn] = 0.0;
+                         }
+                    }
+               }
+               delete [] sort;
+          }
+          delete [] save;
+          if (numberOut)
+               return numberOut;
+     }
+     if ((moreSpecialOptions_ & 128) != 0 && !numberIterations_) {
+          //printf("trying feas pump\n");
+          const char * integerType = integerInformation();
+          assert (integerType);
+          assert (perturbationArray_);
+          CoinZeroN(cost_, numberRows_ + numberColumns_);
+          for (int i = 0; i < numberRows_ - numberRows_; i++) {
+               int iSequence = pivotVariable_[i];
+               if (iSequence < numberColumns_ && integerType[iSequence]) {
+                    double lower = lower_[iSequence];
+                    double upper = upper_[iSequence];
+                    double value = solution_[iSequence];
+                    if (value >= lower - primalTolerance_ &&
+                              value <= upper + primalTolerance_) {
+                         double sign;
+                         if (value - lower < upper - value)
+                              sign = 1.0;
+                         else
+                              sign = -1.0;
+                         cost_[iSequence] = sign * perturbationArray_[iSequence];
+                    }
+               }
+          }
+     }
+#if CAN_HAVE_ZERO_OBJ>1
+     if ((specialOptions_&2097152)==0) {
+#endif
+     computeDuals(givenDuals);
+     if ((moreSpecialOptions_ & 128) != 0 && !numberIterations_) {
+          const char * integerType = integerInformation();
+          // Need to do columns and rows to stay dual feasible
+          for (int iSequence = 0; iSequence < numberColumns_; iSequence++) {
+               if (integerType[iSequence] && getStatus(iSequence) != basic) {
+                    double djValue = dj_[iSequence];
+                    double change = 0.0;
+                    if (getStatus(iSequence) == atLowerBound)
+                         change = CoinMax(-djValue, 10.0 * perturbationArray_[iSequence]);
+                    else if (getStatus(iSequence) == atUpperBound)
+                         change = CoinMin(-djValue, -10.0 * perturbationArray_[iSequence]);
+                    cost_[iSequence] = change;
+                    dj_[iSequence] += change;
+               }
+          }
+     }
+
+     // now check solutions
+     //checkPrimalSolution( rowActivityWork_, columnActivityWork_);
+     //checkDualSolution();
+     checkBothSolutions();
+     objectiveValue_ += objectiveModification / (objectiveScale_ * rhsScale_);
+#if CAN_HAVE_ZERO_OBJ>1
+     } else {
+       checkPrimalSolution( rowActivityWork_, columnActivityWork_);
+#ifndef COIN_REUSE_RANDOM
+       memset(dj_,0,(numberRows_+numberColumns_)*sizeof(double));
+#else
+       for (int iSequence=0;iSequence<numberRows_+numberColumns_;iSequence++) {
+	 double value;
+	 switch (getStatus(iSequence)) {
+	 case atLowerBound:
+	   value=1.0e-9*(1.0+CoinDrand48());
+	   break;
+	 case atUpperBound:
+	   value=-1.0e-9*(1.0+CoinDrand48());
+	   break;
+	 default:
+	   value=0.0;
+	   break;
+	 }
+       }
+#endif
+       objectiveValue_=0.0;
+     }
+#endif
+     if (handler_->logLevel() > 3 || (largestPrimalError_ > 1.0e-2 ||
+                                      largestDualError_ > 1.0e-2))
+          handler_->message(CLP_SIMPLEX_ACCURACY, messages_)
+                    << largestPrimalError_
+                    << largestDualError_
+                    << CoinMessageEol;
+     if (largestPrimalError_ > 1.0e-1 && numberRows_ > 100 && numberIterations_) {
+          // Change factorization tolerance
+          if (factorization_->zeroTolerance() > 1.0e-18)
+               factorization_->zeroTolerance(1.0e-18);
+     }
+     // Switch off false values pass indicator
+     if (!valuesPass && algorithm_ > 0)
+          firstFree_ = -1;
+     return 0;
+}
+void
+ClpSimplex::computePrimals ( const double * rowActivities,
+                             const double * columnActivities)
+{
+
+     //work space
+     CoinIndexedVector  * workSpace = rowArray_[0];
+
+     CoinIndexedVector * arrayVector = rowArray_[1];
+     arrayVector->clear();
+     CoinIndexedVector * previousVector = rowArray_[2];
+     previousVector->clear();
+     // accumulate non basic stuff
+
+     int iRow;
+     // order is this way for scaling
+     if (columnActivities != columnActivityWork_)
+          ClpDisjointCopyN(columnActivities, numberColumns_, columnActivityWork_);
+     if (rowActivities != rowActivityWork_)
+          ClpDisjointCopyN(rowActivities, numberRows_, rowActivityWork_);
+     double * array = arrayVector->denseVector();
+     int * index = arrayVector->getIndices();
+     int number = 0;
+     const double * rhsOffset = matrix_->rhsOffset(this, false, true);
+     if (!rhsOffset) {
+          // Use whole matrix every time to make it easier for ClpMatrixBase
+          // So zero out basic
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int iPivot = pivotVariable_[iRow];
+               assert (iPivot >= 0);
+               solution_[iPivot] = 0.0;
+#ifdef CLP_INVESTIGATE
+               assert (getStatus(iPivot) == basic);
+#endif
+          }
+          // Extended solution before "update"
+          matrix_->primalExpanded(this, 0);
+          times(-1.0, columnActivityWork_, array);
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               double value = array[iRow] + rowActivityWork_[iRow];
+               if (value) {
+                    array[iRow] = value;
+                    index[number++] = iRow;
+               } else {
+                    array[iRow] = 0.0;
+               }
+          }
+     } else {
+          // we have an effective rhs lying around
+          // zero out basic (really just for slacks)
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int iPivot = pivotVariable_[iRow];
+               solution_[iPivot] = 0.0;
+          }
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               double value = rhsOffset[iRow] + rowActivityWork_[iRow];
+               if (value) {
+                    array[iRow] = value;
+                    index[number++] = iRow;
+               } else {
+                    array[iRow] = 0.0;
+               }
+          }
+     }
+     arrayVector->setNumElements(number);
+#ifdef CLP_DEBUG
+     if (numberIterations_ == -3840) {
+          int i;
+          for (i = 0; i < numberRows_ + numberColumns_; i++)
+               printf("%d status %d\n", i, status_[i]);
+          printf("xxxxx1\n");
+          for (i = 0; i < numberRows_; i++)
+               if (array[i])
+                    printf("%d rhs %g\n", i, array[i]);
+          printf("xxxxx2\n");
+          for (i = 0; i < numberRows_ + numberColumns_; i++)
+               if (getStatus(i) != basic)
+                    printf("%d non basic %g %g %g\n", i, lower_[i], solution_[i], upper_[i]);
+          printf("xxxxx3\n");
+     }
+#endif
+     // Ftran adjusted RHS and iterate to improve accuracy
+     double lastError = COIN_DBL_MAX;
+     int iRefine;
+     CoinIndexedVector * thisVector = arrayVector;
+     CoinIndexedVector * lastVector = previousVector;
+     if (number)
+          factorization_->updateColumn(workSpace, thisVector);
+     double * work = workSpace->denseVector();
+#ifdef CLP_DEBUG
+     if (numberIterations_ == -3840) {
+          int i;
+          for (i = 0; i < numberRows_; i++)
+               if (array[i])
+                    printf("%d after rhs %g\n", i, array[i]);
+          printf("xxxxx4\n");
+     }
+#endif
+     bool goodSolution = true;
+     for (iRefine = 0; iRefine < numberRefinements_ + 1; iRefine++) {
+
+          int numberIn = thisVector->getNumElements();
+          int * indexIn = thisVector->getIndices();
+          double * arrayIn = thisVector->denseVector();
+          // put solution in correct place
+          if (!rhsOffset) {
+               int j;
+               for (j = 0; j < numberIn; j++) {
+                    iRow = indexIn[j];
+                    int iPivot = pivotVariable_[iRow];
+                    solution_[iPivot] = arrayIn[iRow];
+                    //assert (fabs(solution_[iPivot])<1.0e100);
+               }
+          } else {
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    solution_[iPivot] = arrayIn[iRow];
+                    //assert (fabs(solution_[iPivot])<1.0e100);
+               }
+          }
+          // Extended solution after "update"
+          matrix_->primalExpanded(this, 1);
+          // check Ax == b  (for all)
+          // signal column generated matrix to just do basic (and gub)
+          unsigned int saveOptions = specialOptions();
+          setSpecialOptions(16);
+          times(-1.0, columnActivityWork_, work);
+          setSpecialOptions(saveOptions);
+          largestPrimalError_ = 0.0;
+          double multiplier = 131072.0;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               double value = work[iRow] + rowActivityWork_[iRow];
+               work[iRow] = value * multiplier;
+               if (fabs(value) > largestPrimalError_) {
+                    largestPrimalError_ = fabs(value);
+               }
+          }
+          if (largestPrimalError_ >= lastError) {
+               // restore
+               CoinIndexedVector * temp = thisVector;
+               thisVector = lastVector;
+               lastVector = temp;
+               goodSolution = false;
+               break;
+          }
+          if (iRefine < numberRefinements_ && largestPrimalError_ > 1.0e-10) {
+               // try and make better
+               // save this
+               CoinIndexedVector * temp = thisVector;
+               thisVector = lastVector;
+               lastVector = temp;
+               int * indexOut = thisVector->getIndices();
+               int number = 0;
+               array = thisVector->denseVector();
+               thisVector->clear();
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    double value = work[iRow];
+                    if (value) {
+                         array[iRow] = value;
+                         indexOut[number++] = iRow;
+                         work[iRow] = 0.0;
+                    }
+               }
+               thisVector->setNumElements(number);
+               lastError = largestPrimalError_;
+               factorization_->updateColumn(workSpace, thisVector);
+               multiplier = 1.0 / multiplier;
+               double * previous = lastVector->denseVector();
+               number = 0;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    double value = previous[iRow] + multiplier * array[iRow];
+                    if (value) {
+                         array[iRow] = value;
+                         indexOut[number++] = iRow;
+                    } else {
+                         array[iRow] = 0.0;
+                    }
+               }
+               thisVector->setNumElements(number);
+          } else {
+               break;
+          }
+     }
+
+     // solution as accurate as we are going to get
+     ClpFillN(work, numberRows_, 0.0);
+     if (!goodSolution) {
+          array = thisVector->denseVector();
+          // put solution in correct place
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int iPivot = pivotVariable_[iRow];
+               solution_[iPivot] = array[iRow];
+               //assert (fabs(solution_[iPivot])<1.0e100);
+          }
+     }
+     arrayVector->clear();
+     previousVector->clear();
+#ifdef CLP_DEBUG
+     if (numberIterations_ == -3840) {
+          exit(77);
+     }
+#endif
+}
+// now dual side
+void
+ClpSimplex::computeDuals(double * givenDjs)
+{
+#ifndef SLIM_CLP
+     if (objective_->type() == 1 || !objective_->activated()) {
+#endif
+          // Linear
+          //work space
+          CoinIndexedVector  * workSpace = rowArray_[0];
+
+          CoinIndexedVector * arrayVector = rowArray_[1];
+          arrayVector->clear();
+          CoinIndexedVector * previousVector = rowArray_[2];
+          previousVector->clear();
+          int iRow;
+#ifdef CLP_DEBUG
+          workSpace->checkClear();
+#endif
+          double * array = arrayVector->denseVector();
+          int * index = arrayVector->getIndices();
+          int number = 0;
+          if (!givenDjs) {
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    double value = cost_[iPivot];
+                    if (value) {
+                         array[iRow] = value;
+                         index[number++] = iRow;
+                    }
+               }
+          } else {
+               // dual values pass - djs may not be zero
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    // make sure zero if done
+                    if (!pivoted(iPivot))
+                         givenDjs[iPivot] = 0.0;
+                    double value = cost_[iPivot] - givenDjs[iPivot];
+                    if (value) {
+                         array[iRow] = value;
+                         index[number++] = iRow;
+                    }
+               }
+          }
+          arrayVector->setNumElements(number);
+          // Extended duals before "updateTranspose"
+          matrix_->dualExpanded(this, arrayVector, givenDjs, 0);
+
+          // Btran basic costs and get as accurate as possible
+          double lastError = COIN_DBL_MAX;
+          int iRefine;
+          double * work = workSpace->denseVector();
+          CoinIndexedVector * thisVector = arrayVector;
+          CoinIndexedVector * lastVector = previousVector;
+          factorization_->updateColumnTranspose(workSpace, thisVector);
+
+          for (iRefine = 0; iRefine < numberRefinements_ + 1; iRefine++) {
+               // check basic reduced costs zero
+               largestDualError_ = 0.0;
+               if (!numberExtraRows_) {
+                    // Just basic
+                    int * index2 = workSpace->getIndices();
+                    // use reduced costs for slacks as work array
+                    double * work2 = reducedCostWork_ + numberColumns_;
+                    int numberStructurals = 0;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         int iPivot = pivotVariable_[iRow];
+                         if (iPivot < numberColumns_)
+                              index2[numberStructurals++] = iPivot;
+                    }
+                    matrix_->listTransposeTimes(this, array, index2, numberStructurals, work2);
+                    numberStructurals = 0;
+                    if (!givenDjs) {
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              int iPivot = pivotVariable_[iRow];
+                              double value;
+                              if (iPivot >= numberColumns_) {
+                                   // slack
+                                   value = rowObjectiveWork_[iPivot-numberColumns_]
+                                           + array[iPivot-numberColumns_];
+                              } else {
+                                   // column
+                                   value = objectiveWork_[iPivot] - work2[numberStructurals++];
+                              }
+                              work[iRow] = value;
+                              if (fabs(value) > largestDualError_) {
+                                   largestDualError_ = fabs(value);
+                              }
+                         }
+                    } else {
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              int iPivot = pivotVariable_[iRow];
+                              if (iPivot >= numberColumns_) {
+                                   // slack
+                                   work[iRow] = rowObjectiveWork_[iPivot-numberColumns_]
+                                                + array[iPivot-numberColumns_] - givenDjs[iPivot];
+                              } else {
+                                   // column
+                                   work[iRow] = objectiveWork_[iPivot] - work2[numberStructurals++]
+                                                - givenDjs[iPivot];
+                              }
+                              if (fabs(work[iRow]) > largestDualError_) {
+                                   largestDualError_ = fabs(work[iRow]);
+                                   //assert (largestDualError_<1.0e-7);
+                                   //if (largestDualError_>1.0e-7)
+                                   //printf("large dual error %g\n",largestDualError_);
+                              }
+                         }
+                    }
+               } else {
+                    // extra rows - be more careful
+#if 1
+                    // would be faster to do just for basic but this reduces code
+                    ClpDisjointCopyN(objectiveWork_, numberColumns_, reducedCostWork_);
+                    transposeTimes(-1.0, array, reducedCostWork_);
+#else
+                    // Just basic
+                    int * index2 = workSpace->getIndices();
+                    int numberStructurals = 0;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         int iPivot = pivotVariable_[iRow];
+                         if (iPivot < numberColumns_)
+                              index2[numberStructurals++] = iPivot;
+                    }
+                    matrix_->listTransposeTimes(this, array, index2, numberStructurals, work);
+                    for (iRow = 0; iRow < numberStructurals; iRow++) {
+                         int iPivot = index2[iRow];
+                         reducedCostWork_[iPivot] = objectiveWork_[iPivot] - work[iRow];
+                    }
+#endif
+                    // update by duals on sets
+                    matrix_->dualExpanded(this, NULL, NULL, 1);
+                    if (!givenDjs) {
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              int iPivot = pivotVariable_[iRow];
+                              double value;
+                              if (iPivot >= numberColumns_) {
+                                   // slack
+                                   value = rowObjectiveWork_[iPivot-numberColumns_]
+                                           + array[iPivot-numberColumns_];
+                              } else {
+                                   // column
+                                   value = reducedCostWork_[iPivot];
+                              }
+                              work[iRow] = value;
+                              if (fabs(value) > largestDualError_) {
+                                   largestDualError_ = fabs(value);
+                              }
+                         }
+                    } else {
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              int iPivot = pivotVariable_[iRow];
+                              if (iPivot >= numberColumns_) {
+                                   // slack
+                                   work[iRow] = rowObjectiveWork_[iPivot-numberColumns_]
+                                                + array[iPivot-numberColumns_] - givenDjs[iPivot];
+                              } else {
+                                   // column
+                                   work[iRow] = reducedCostWork_[iPivot] - givenDjs[iPivot];
+                              }
+                              if (fabs(work[iRow]) > largestDualError_) {
+                                   largestDualError_ = fabs(work[iRow]);
+                                   //assert (largestDualError_<1.0e-7);
+                                   //if (largestDualError_>1.0e-7)
+                                   //printf("large dual error %g\n",largestDualError_);
+                              }
+                         }
+                    }
+               }
+               if (largestDualError_ >= lastError) {
+                    // restore
+                    CoinIndexedVector * temp = thisVector;
+                    thisVector = lastVector;
+                    lastVector = temp;
+                    break;
+               }
+               if (iRefine < numberRefinements_ && largestDualError_ > 1.0e-10
+                         && !givenDjs) {
+                    // try and make better
+                    // save this
+                    CoinIndexedVector * temp = thisVector;
+                    thisVector = lastVector;
+                    lastVector = temp;
+                    int * indexOut = thisVector->getIndices();
+                    int number = 0;
+                    array = thisVector->denseVector();
+                    thisVector->clear();
+                    double multiplier = 131072.0;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         double value = multiplier * work[iRow];
+                         if (value) {
+                              array[iRow] = value;
+                              indexOut[number++] = iRow;
+                              work[iRow] = 0.0;
+                         }
+                         work[iRow] = 0.0;
+                    }
+                    thisVector->setNumElements(number);
+                    lastError = largestDualError_;
+                    factorization_->updateColumnTranspose(workSpace, thisVector);
+                    multiplier = 1.0 / multiplier;
+                    double * previous = lastVector->denseVector();
+                    number = 0;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         double value = previous[iRow] + multiplier * array[iRow];
+                         if (value) {
+                              array[iRow] = value;
+                              indexOut[number++] = iRow;
+                         } else {
+                              array[iRow] = 0.0;
+                         }
+                    }
+                    thisVector->setNumElements(number);
+               } else {
+                    break;
+               }
+          }
+          // now look at dual solution
+          array = thisVector->denseVector();
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               // slack
+               double value = array[iRow];
+               dual_[iRow] = value;
+               value += rowObjectiveWork_[iRow];
+               rowReducedCost_[iRow] = value;
+          }
+          // can use work if problem scaled (for better cache)
+          ClpPackedMatrix* clpMatrix =
+               dynamic_cast< ClpPackedMatrix*>(matrix_);
+          double * saveRowScale = rowScale_;
+          //double * saveColumnScale = columnScale_;
+          if (scaledMatrix_) {
+               rowScale_ = NULL;
+               clpMatrix = scaledMatrix_;
+          }
+          if (clpMatrix && (clpMatrix->flags() & 2) == 0) {
+               CoinIndexedVector * cVector = columnArray_[0];
+               int * whichColumn = cVector->getIndices();
+               assert (!cVector->getNumElements());
+               int n = 0;
+               for (int i = 0; i < numberColumns_; i++) {
+                    if (getColumnStatus(i) != basic) {
+                         whichColumn[n++] = i;
+                         reducedCostWork_[i] = objectiveWork_[i];
+                    } else {
+                         reducedCostWork_[i] = 0.0;
+                    }
+               }
+               if (numberRows_ > 4000)
+                    clpMatrix->transposeTimesSubset(n, whichColumn, dual_, reducedCostWork_,
+                                                    rowScale_, columnScale_, work);
+               else
+                    clpMatrix->transposeTimesSubset(n, whichColumn, dual_, reducedCostWork_,
+                                                    rowScale_, columnScale_, NULL);
+          } else {
+               ClpDisjointCopyN(objectiveWork_, numberColumns_, reducedCostWork_);
+               if (numberRows_ > 4000)
+                    matrix_->transposeTimes(-1.0, dual_, reducedCostWork_,
+                                            rowScale_, columnScale_, work);
+               else
+                    matrix_->transposeTimes(-1.0, dual_, reducedCostWork_,
+                                            rowScale_, columnScale_, NULL);
+          }
+          rowScale_ = saveRowScale;
+          //columnScale_ = saveColumnScale;
+          ClpFillN(work, numberRows_, 0.0);
+          // Extended duals and check dual infeasibility
+          if (!matrix_->skipDualCheck() || algorithm_ < 0 || problemStatus_ != -2)
+               matrix_->dualExpanded(this, NULL, NULL, 2);
+          // If necessary - override results
+          if (givenDjs) {
+               // restore accurate duals
+               CoinMemcpyN(dj_, (numberRows_ + numberColumns_), givenDjs);
+          }
+          arrayVector->clear();
+          previousVector->clear();
+#ifndef SLIM_CLP
+     } else {
+          // Nonlinear
+          objective_->reducedGradient(this, dj_, false);
+          // get dual_ by moving from reduced costs for slacks
+          CoinMemcpyN(dj_ + numberColumns_, numberRows_, dual_);
+     }
+#endif
+}
+/* Given an existing factorization computes and checks
+   primal and dual solutions.  Uses input arrays for variables at
+   bounds.  Returns feasibility states */
+int ClpSimplex::getSolution ( const double * /*rowActivities*/,
+                              const double * /*columnActivities*/)
+{
+     if (!factorization_->status()) {
+          // put in standard form
+          createRim(7 + 8 + 16 + 32, false, -1);
+          if (pivotVariable_[0] < 0)
+               internalFactorize(0);
+          // do work
+          gutsOfSolution ( NULL, NULL);
+          // release extra memory
+          deleteRim(0);
+     }
+     return factorization_->status();
+}
+/* Given an existing factorization computes and checks
+   primal and dual solutions.  Uses current problem arrays for
+   bounds.  Returns feasibility states */
+int ClpSimplex::getSolution ( )
+{
+     double * rowActivities = new double[numberRows_];
+     double * columnActivities = new double[numberColumns_];
+     ClpDisjointCopyN ( rowActivityWork_, numberRows_ , rowActivities);
+     ClpDisjointCopyN ( columnActivityWork_, numberColumns_ , columnActivities);
+     int status = getSolution( rowActivities, columnActivities);
+     delete [] rowActivities;
+     delete [] columnActivities;
+     return status;
+}
+// Factorizes using current basis.  This is for external use
+// Return codes are as from ClpFactorization
+int ClpSimplex::factorize ()
+{
+     // put in standard form
+     createRim(7 + 8 + 16 + 32, false);
+     // do work
+     int status = internalFactorize(-1);
+     // release extra memory
+     deleteRim(0);
+
+     return status;
+}
+// Clean up status
+void
+ClpSimplex::cleanStatus()
+{
+     int iRow, iColumn;
+     int numberBasic = 0;
+     // make row activities correct
+     memset(rowActivityWork_, 0, numberRows_ * sizeof(double));
+     times(1.0, columnActivityWork_, rowActivityWork_);
+     if (!status_)
+          createStatus();
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          if (getRowStatus(iRow) == basic)
+               numberBasic++;
+          else {
+               setRowStatus(iRow, superBasic);
+               // but put to bound if close
+               if (fabs(rowActivityWork_[iRow] - rowLowerWork_[iRow])
+                         <= primalTolerance_) {
+                    rowActivityWork_[iRow] = rowLowerWork_[iRow];
+                    setRowStatus(iRow, atLowerBound);
+               } else if (fabs(rowActivityWork_[iRow] - rowUpperWork_[iRow])
+                          <= primalTolerance_) {
+                    rowActivityWork_[iRow] = rowUpperWork_[iRow];
+                    setRowStatus(iRow, atUpperBound);
+               }
+          }
+     }
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (getColumnStatus(iColumn) == basic) {
+               if (numberBasic == numberRows_) {
+                    // take out of basis
+                    setColumnStatus(iColumn, superBasic);
+                    // but put to bound if close
+                    if (fabs(columnActivityWork_[iColumn] - columnLowerWork_[iColumn])
+                              <= primalTolerance_) {
+                         columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                         setColumnStatus(iColumn, atLowerBound);
+                    } else if (fabs(columnActivityWork_[iColumn]
+                                    - columnUpperWork_[iColumn])
+                               <= primalTolerance_) {
+                         columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                         setColumnStatus(iColumn, atUpperBound);
+                    }
+               } else
+                    numberBasic++;
+          } else {
+               setColumnStatus(iColumn, superBasic);
+               // but put to bound if close
+               if (fabs(columnActivityWork_[iColumn] - columnLowerWork_[iColumn])
+                         <= primalTolerance_) {
+                    columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                    setColumnStatus(iColumn, atLowerBound);
+               } else if (fabs(columnActivityWork_[iColumn]
+                               - columnUpperWork_[iColumn])
+                          <= primalTolerance_) {
+                    columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                    setColumnStatus(iColumn, atUpperBound);
+               }
+          }
+     }
+}
+
+/* Factorizes using current basis.
+   solveType - 1 iterating, 0 initial, -1 external
+   - 2 then iterating but can throw out of basis
+   If 10 added then in primal values pass
+   Return codes are as from ClpFactorization unless initial factorization
+   when total number of singularities is returned.
+   Special case is numberRows_+1 -> all slack basis.
+*/
+int ClpSimplex::internalFactorize ( int solveType)
+{
+     int iRow, iColumn;
+     int totalSlacks = numberRows_;
+     if (!status_)
+          createStatus();
+
+     bool valuesPass = false;
+     if (solveType >= 10) {
+          valuesPass = true;
+          solveType -= 10;
+     }
+#ifdef CLP_DEBUG
+     if (solveType > 0) {
+          int numberFreeIn = 0, numberFreeOut = 0;
+          double biggestDj = 0.0;
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               switch(getColumnStatus(iColumn)) {
+
+               case basic:
+                    if (columnLower_[iColumn] < -largeValue_
+                              && columnUpper_[iColumn] > largeValue_)
+                         numberFreeIn++;
+                    break;
+               default:
+                    if (columnLower_[iColumn] < -largeValue_
+                              && columnUpper_[iColumn] > largeValue_) {
+                         numberFreeOut++;
+                         biggestDj = CoinMax(fabs(dj_[iColumn]), biggestDj);
+                    }
+                    break;
+               }
+          }
+          if (numberFreeIn + numberFreeOut)
+               printf("%d in basis, %d out - largest dj %g\n",
+                      numberFreeIn, numberFreeOut, biggestDj);
+     }
+#endif
+     if (solveType <= 0) {
+          // Make sure everything is clean
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if(getRowStatus(iRow) == isFixed) {
+                    // double check fixed
+                    if (rowUpperWork_[iRow] > rowLowerWork_[iRow])
+                         setRowStatus(iRow, atLowerBound);
+               } else if (getRowStatus(iRow) == isFree) {
+                    // may not be free after all
+                    if (rowLowerWork_[iRow] > -largeValue_ || rowUpperWork_[iRow] < largeValue_)
+                         setRowStatus(iRow, superBasic);
+               }
+          }
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if(getColumnStatus(iColumn) == isFixed) {
+                    // double check fixed
+                    if (columnUpperWork_[iColumn] > columnLowerWork_[iColumn])
+                         setColumnStatus(iColumn, atLowerBound);
+               } else if (getColumnStatus(iColumn) == isFree) {
+                    // may not be free after all
+                    if (columnLowerWork_[iColumn] > -largeValue_ || columnUpperWork_[iColumn] < largeValue_)
+                         setColumnStatus(iColumn, superBasic);
+               }
+          }
+          if (!valuesPass) {
+               // not values pass so set to bounds
+               bool allSlack = true;
+               if (status_) {
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         if (getRowStatus(iRow) != basic) {
+                              allSlack = false;
+                              break;
+                         }
+                    }
+               }
+               if (!allSlack) {
+                    //#define CLP_INVESTIGATE2
+#ifdef CLP_INVESTIGATE3
+                    int numberTotal = numberRows_ + numberColumns_;
+                    double * saveSol = valuesPass ?
+                                       CoinCopyOfArray(solution_, numberTotal) : NULL;
+#endif
+                    // set values from warm start (if sensible)
+                    int numberBasic = 0;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         switch(getRowStatus(iRow)) {
+
+                         case basic:
+                              numberBasic++;
+                              break;
+                         case atUpperBound:
+                              rowActivityWork_[iRow] = rowUpperWork_[iRow];
+                              if (rowActivityWork_[iRow] > largeValue_) {
+                                   if (rowLowerWork_[iRow] > -largeValue_) {
+                                        rowActivityWork_[iRow] = rowLowerWork_[iRow];
+                                        setRowStatus(iRow, atLowerBound);
+                                   } else {
+                                        // say free
+                                        setRowStatus(iRow, isFree);
+                                        rowActivityWork_[iRow] = 0.0;
+                                   }
+                              }
+                              break;
+                         case ClpSimplex::isFixed:
+                         case atLowerBound:
+                              rowActivityWork_[iRow] = rowLowerWork_[iRow];
+                              if (rowActivityWork_[iRow] < -largeValue_) {
+                                   if (rowUpperWork_[iRow] < largeValue_) {
+                                        rowActivityWork_[iRow] = rowUpperWork_[iRow];
+                                        setRowStatus(iRow, atUpperBound);
+                                   } else {
+                                        // say free
+                                        setRowStatus(iRow, isFree);
+                                        rowActivityWork_[iRow] = 0.0;
+                                   }
+                              }
+                              break;
+                         case isFree:
+                              break;
+                              // not really free - fall through to superbasic
+                         case superBasic:
+                              if (rowUpperWork_[iRow] > largeValue_) {
+                                   if (rowLowerWork_[iRow] > -largeValue_) {
+                                        rowActivityWork_[iRow] = rowLowerWork_[iRow];
+                                        setRowStatus(iRow, atLowerBound);
+                                   } else {
+                                        // say free
+                                        setRowStatus(iRow, isFree);
+                                        rowActivityWork_[iRow] = 0.0;
+                                   }
+                              } else {
+                                   if (rowLowerWork_[iRow] > -largeValue_) {
+                                        // set to nearest
+                                        if (fabs(rowActivityWork_[iRow] - rowLowerWork_[iRow])
+                                                  < fabs(rowActivityWork_[iRow] - rowLowerWork_[iRow])) {
+                                             rowActivityWork_[iRow] = rowLowerWork_[iRow];
+                                             setRowStatus(iRow, atLowerBound);
+                                        } else {
+                                             rowActivityWork_[iRow] = rowUpperWork_[iRow];
+                                             setRowStatus(iRow, atUpperBound);
+                                        }
+                                   } else {
+                                        rowActivityWork_[iRow] = rowUpperWork_[iRow];
+                                        setRowStatus(iRow, atUpperBound);
+                                   }
+                              }
+                              break;
+                         }
+                    }
+                    totalSlacks = numberBasic;
+
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         switch(getColumnStatus(iColumn)) {
+
+                         case basic:
+                              if (numberBasic == maximumBasic_) {
+                                   // take out of basis
+                                   if (columnLowerWork_[iColumn] > -largeValue_) {
+                                        if (columnActivityWork_[iColumn] - columnLowerWork_[iColumn] <
+                                                  columnUpperWork_[iColumn] - columnActivityWork_[iColumn]) {
+                                             columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                                             setColumnStatus(iColumn, atLowerBound);
+                                        } else {
+                                             columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                                             setColumnStatus(iColumn, atUpperBound);
+                                        }
+                                   } else if (columnUpperWork_[iColumn] < largeValue_) {
+                                        columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                                        setColumnStatus(iColumn, atUpperBound);
+                                   } else {
+                                        columnActivityWork_[iColumn] = 0.0;
+                                        setColumnStatus(iColumn, isFree);
+                                   }
+                              } else {
+                                   numberBasic++;
+                              }
+                              break;
+                         case atUpperBound:
+                              columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                              if (columnActivityWork_[iColumn] > largeValue_) {
+                                   if (columnLowerWork_[iColumn] < -largeValue_) {
+                                        columnActivityWork_[iColumn] = 0.0;
+                                        setColumnStatus(iColumn, isFree);
+                                   } else {
+                                        columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                                        setColumnStatus(iColumn, atLowerBound);
+                                   }
+                              }
+                              break;
+                         case isFixed:
+                         case atLowerBound:
+                              columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                              if (columnActivityWork_[iColumn] < -largeValue_) {
+                                   if (columnUpperWork_[iColumn] > largeValue_) {
+                                        columnActivityWork_[iColumn] = 0.0;
+                                        setColumnStatus(iColumn, isFree);
+                                   } else {
+                                        columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                                        setColumnStatus(iColumn, atUpperBound);
+                                   }
+                              }
+                              break;
+                         case isFree:
+                              break;
+                              // not really free - fall through to superbasic
+                         case superBasic:
+                              if (columnUpperWork_[iColumn] > largeValue_) {
+                                   if (columnLowerWork_[iColumn] > -largeValue_) {
+                                        columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                                        setColumnStatus(iColumn, atLowerBound);
+                                   } else {
+                                        // say free
+                                        setColumnStatus(iColumn, isFree);
+                                        columnActivityWork_[iColumn] = 0.0;
+                                   }
+                              } else {
+                                   if (columnLowerWork_[iColumn] > -largeValue_) {
+                                        // set to nearest
+                                        if (fabs(columnActivityWork_[iColumn] - columnLowerWork_[iColumn])
+                                                  < fabs(columnActivityWork_[iColumn] - columnLowerWork_[iColumn])) {
+                                             columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                                             setColumnStatus(iColumn, atLowerBound);
+                                        } else {
+                                             columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                                             setColumnStatus(iColumn, atUpperBound);
+                                        }
+                                   } else {
+                                        columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                                        setColumnStatus(iColumn, atUpperBound);
+                                   }
+                              }
+                              break;
+                         }
+                    }
+#ifdef CLP_INVESTIGATE3
+                    if (saveSol) {
+                         int numberChanged = 0;
+                         double largestChanged = 0.0;
+                         for (int i = 0; i < numberTotal; i++) {
+                              double difference = fabs(solution_[i] - saveSol[i]);
+                              if (difference > 1.0e-7) {
+                                   numberChanged++;
+                                   if (difference > largestChanged)
+                                        largestChanged = difference;
+                              }
+                         }
+                         if (numberChanged)
+                              printf("%d changed, largest %g\n", numberChanged, largestChanged);
+                         delete [] saveSol;
+                    }
+#endif
+#if 0
+                    if (numberBasic < numberRows_) {
+                         // add some slacks in case odd warmstart
+#ifdef CLP_INVESTIGATE
+                         printf("BAD %d basic, %d rows %d slacks\n",
+                                numberBasic, numberRows_, totalSlacks);
+#endif
+                         int iRow = numberRows_ - 1;
+                         while (numberBasic < numberRows_) {
+                              if (getRowStatus(iRow) != basic) {
+                                   setRowStatus(iRow, basic);
+                                   numberBasic++;
+                                   totalSlacks++;
+                                   iRow--;
+                              } else {
+                                   break;
+                              }
+                         }
+                    }
+#endif
+               } else {
+                    // all slack basis
+                    int numberBasic = 0;
+                    if (!status_) {
+                         createStatus();
+                    }
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         double lower = rowLowerWork_[iRow];
+                         double upper = rowUpperWork_[iRow];
+                         if (lower > -largeValue_ || upper < largeValue_) {
+                              if (fabs(lower) <= fabs(upper)) {
+                                   rowActivityWork_[iRow] = lower;
+                              } else {
+                                   rowActivityWork_[iRow] = upper;
+                              }
+                         } else {
+                              rowActivityWork_[iRow] = 0.0;
+                         }
+                         setRowStatus(iRow, basic);
+                         numberBasic++;
+                    }
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         double lower = columnLowerWork_[iColumn];
+                         double upper = columnUpperWork_[iColumn];
+                         double big_bound = largeValue_;
+                         if (lower > -big_bound || upper < big_bound) {
+                              if ((getColumnStatus(iColumn) == atLowerBound &&
+                                        columnActivityWork_[iColumn] == lower) ||
+                                        (getColumnStatus(iColumn) == atUpperBound &&
+                                         columnActivityWork_[iColumn] == upper)) {
+                                   // status looks plausible
+                              } else {
+                                   // set to sensible
+                                   if (fabs(lower) <= fabs(upper)) {
+                                        setColumnStatus(iColumn, atLowerBound);
+                                        columnActivityWork_[iColumn] = lower;
+                                   } else {
+                                        setColumnStatus(iColumn, atUpperBound);
+                                        columnActivityWork_[iColumn] = upper;
+                                   }
+                              }
+                         } else {
+                              setColumnStatus(iColumn, isFree);
+                              columnActivityWork_[iColumn] = 0.0;
+                         }
+                    }
+               }
+          } else {
+               // values pass has less coding
+               // make row activities correct and clean basis a bit
+               cleanStatus();
+               if (status_) {
+                    int numberBasic = 0;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         if (getRowStatus(iRow) == basic)
+                              numberBasic++;
+                    }
+                    totalSlacks = numberBasic;
+#if 0
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         if (getColumnStatus(iColumn) == basic)
+                              numberBasic++;
+                    }
+#endif
+               } else {
+                    // all slack basis
+                    int numberBasic = 0;
+                    if (!status_) {
+                         createStatus();
+                    }
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         setRowStatus(iRow, basic);
+                         numberBasic++;
+                    }
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         setColumnStatus(iColumn, superBasic);
+                         // but put to bound if close
+                         if (fabs(columnActivityWork_[iColumn] - columnLowerWork_[iColumn])
+                                   <= primalTolerance_) {
+                              columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                              setColumnStatus(iColumn, atLowerBound);
+                         } else if (fabs(columnActivityWork_[iColumn]
+                                         - columnUpperWork_[iColumn])
+                                    <= primalTolerance_) {
+                              columnActivityWork_[iColumn] = columnUpperWork_[iColumn];
+                              setColumnStatus(iColumn, atUpperBound);
+                         }
+                    }
+               }
+          }
+          numberRefinements_ = 1;
+          // set fixed if they are
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if (getRowStatus(iRow) != basic ) {
+                    if (rowLowerWork_[iRow] == rowUpperWork_[iRow]) {
+                         rowActivityWork_[iRow] = rowLowerWork_[iRow];
+                         setRowStatus(iRow, isFixed);
+                    }
+               }
+          }
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (getColumnStatus(iColumn) != basic ) {
+                    if (columnLowerWork_[iColumn] == columnUpperWork_[iColumn]) {
+                         columnActivityWork_[iColumn] = columnLowerWork_[iColumn];
+                         setColumnStatus(iColumn, isFixed);
+                    }
+               }
+          }
+     }
+     //for (iRow=0;iRow<numberRows_+numberColumns_;iRow++) {
+     //if (fabs(solution_[iRow])>1.0e10) {
+     //  printf("large %g at %d - status %d\n",
+     //         solution_[iRow],iRow,status_[iRow]);
+     //}
+     //}
+#    if 0 //ndef _MSC_VER
+	 // The local static var k is a problem when trying to build a DLL. Since this is
+	 // just for debugging (likely done on *nix), just hide it from Windows
+	 // -- lh, 101016 --
+     if (0)  {
+          static int k = 0;
+          printf("start basis\n");
+          int i;
+          for (i = 0; i < numberRows_; i++)
+               printf ("xx %d %d\n", i, pivotVariable_[i]);
+          for (i = 0; i < numberRows_ + numberColumns_; i++)
+               if (getColumnStatus(i) == basic)
+                    printf ("yy %d basic\n", i);
+          if (k > 20)
+               exit(0);
+          k++;
+     }
+#    endif
+#if 0 //ndef NDEBUG
+  // Make sure everything is clean
+  double sumOutside=0.0;
+  int numberOutside=0;
+  //double sumOutsideLarge=0.0;
+  int numberOutsideLarge=0;
+  double sumInside=0.0;
+  int numberInside=0;
+  //double sumInsideLarge=0.0;
+  int numberInsideLarge=0;
+  int numberTotal=numberRows_+numberColumns_;
+  for (int iSequence = 0; iSequence < numberTotal; iSequence++) {
+    if(getStatus(iSequence) == isFixed) {
+      // double check fixed
+      assert (upper_[iSequence] == lower_[iSequence]);
+      assert (fabs(solution_[iSequence]-lower_[iSequence])<primalTolerance_);
+    } else if (getStatus(iSequence) == isFree) {
+      assert (upper_[iSequence] == COIN_DBL_MAX && lower_[iSequence]==-COIN_DBL_MAX);
+    } else if (getStatus(iSequence) == atLowerBound) {
+      assert (fabs(solution_[iSequence]-lower_[iSequence])<1000.0*primalTolerance_);
+      if (solution_[iSequence]<lower_[iSequence]) {
+	numberOutside++;
+	sumOutside-=solution_[iSequence]-lower_[iSequence];
+	if (solution_[iSequence]<lower_[iSequence]-primalTolerance_) 
+	  numberOutsideLarge++;
+      } else if (solution_[iSequence]>lower_[iSequence]) {
+	numberInside++;
+	sumInside+=solution_[iSequence]-lower_[iSequence];
+	if (solution_[iSequence]>lower_[iSequence]+primalTolerance_) 
+	  numberInsideLarge++;
+      }
+    } else if (getStatus(iSequence) == atUpperBound) {
+      assert (fabs(solution_[iSequence]-upper_[iSequence])<1000.0*primalTolerance_);
+      if (solution_[iSequence]>upper_[iSequence]) {
+	numberOutside++;
+	sumOutside+=solution_[iSequence]-upper_[iSequence];
+	if (solution_[iSequence]>upper_[iSequence]+primalTolerance_) 
+	  numberOutsideLarge++;
+      } else if (solution_[iSequence]<upper_[iSequence]) {
+	numberInside++;
+	sumInside-=solution_[iSequence]-upper_[iSequence];
+	if (solution_[iSequence]<upper_[iSequence]-primalTolerance_) 
+	  numberInsideLarge++;
+      }
+    } else if (getStatus(iSequence) == superBasic) {
+      //assert (!valuesPass);
+    }
+  }
+  if (numberInside+numberOutside)
+    printf("%d outside summing to %g (%d large), %d inside summing to %g (%d large)\n",
+	   numberOutside,sumOutside,numberOutsideLarge,
+	   numberInside,sumInside,numberInsideLarge);
+#endif
+     int status = factorization_->factorize(this, solveType, valuesPass);
+     if (status) {
+          handler_->message(CLP_SIMPLEX_BADFACTOR, messages_)
+                    << status
+                    << CoinMessageEol;
+          return -1;
+     } else if (!solveType) {
+          // Initial basis - return number of singularities
+          int numberSlacks = 0;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if (getRowStatus(iRow) == basic)
+                    numberSlacks++;
+          }
+          status = CoinMax(numberSlacks - totalSlacks, 0);
+          // special case if all slack
+          if (numberSlacks == numberRows_) {
+               status = numberRows_ + 1;
+          }
+     }
+
+     // sparse methods
+     //if (factorization_->sparseThreshold()) {
+     // get default value
+     factorization_->sparseThreshold(0);
+     if (!(moreSpecialOptions_&1024))
+       factorization_->goSparse();
+     //}
+
+     return status;
+}
+/*
+   This does basis housekeeping and does values for in/out variables.
+   Can also decide to re-factorize
+*/
+int
+ClpSimplex::housekeeping(double objectiveChange)
+{
+     // save value of incoming and outgoing
+     double oldIn = solution_[sequenceIn_];
+     double oldOut = solution_[sequenceOut_];
+     numberIterations_++;
+     changeMade_++; // something has happened
+     // incoming variable
+     if (handler_->logLevel() > 7) {
+          //if (handler_->detail(CLP_SIMPLEX_HOUSE1,messages_)<100) {
+          handler_->message(CLP_SIMPLEX_HOUSE1, messages_)
+                    << directionOut_
+                    << directionIn_ << theta_
+                    << dualOut_ << dualIn_ << alpha_
+                    << CoinMessageEol;
+          if (getStatus(sequenceIn_) == isFree) {
+               handler_->message(CLP_SIMPLEX_FREEIN, messages_)
+                         << sequenceIn_
+                         << CoinMessageEol;
+          }
+     }
+#if 0
+     printf("h1 %d %d %g %g %g %g",
+            directionOut_
+            , directionIn_, theta_
+            , dualOut_, dualIn_, alpha_);
+#endif
+     // change of incoming
+     char rowcol[] = {'R', 'C'};
+     if (pivotRow_ >= 0)
+          pivotVariable_[pivotRow_] = sequenceIn();
+     if (upper_[sequenceIn_] > 1.0e20 && lower_[sequenceIn_] < -1.0e20)
+          progressFlag_ |= 2; // making real progress
+     solution_[sequenceIn_] = valueIn_;
+     if (upper_[sequenceOut_] - lower_[sequenceOut_] < 1.0e-12)
+          progressFlag_ |= 1; // making real progress
+     if (sequenceIn_ != sequenceOut_) {
+          if (alphaAccuracy_ > 0.0) {
+               double value = fabs(alpha_);
+               if (value > 1.0)
+                    alphaAccuracy_ *= value;
+               else
+                    alphaAccuracy_ /= value;
+          }
+          //assert( getStatus(sequenceOut_)== basic);
+          setStatus(sequenceIn_, basic);
+          if (upper_[sequenceOut_] - lower_[sequenceOut_] > 0) {
+               // As Nonlinear costs may have moved bounds (to more feasible)
+               // Redo using value
+               if (fabs(valueOut_ - lower_[sequenceOut_]) < fabs(valueOut_ - upper_[sequenceOut_])) {
+                    // going to lower
+                    setStatus(sequenceOut_, atLowerBound);
+                    oldOut = lower_[sequenceOut_];
+               } else {
+                    // going to upper
+                    setStatus(sequenceOut_, atUpperBound);
+                    oldOut = upper_[sequenceOut_];
+               }
+          } else {
+               // fixed
+               setStatus(sequenceOut_, isFixed);
+          }
+          solution_[sequenceOut_] = valueOut_;
+     } else {
+          //if (objective_->type()<2)
+          //assert (fabs(theta_)>1.0e-13);
+          // flip from bound to bound
+          // As Nonlinear costs may have moved bounds (to more feasible)
+          // Redo using value
+          if (fabs(valueIn_ - lower_[sequenceIn_]) < fabs(valueIn_ - upper_[sequenceIn_])) {
+               // as if from upper bound
+               setStatus(sequenceIn_, atLowerBound);
+          } else {
+               // as if from lower bound
+               setStatus(sequenceIn_, atUpperBound);
+          }
+     }
+
+     // Update hidden stuff e.g. effective RHS and gub
+     int invertNow=matrix_->updatePivot(this, oldIn, oldOut);
+     objectiveValue_ += objectiveChange / (objectiveScale_ * rhsScale_);
+     if (handler_->logLevel() > 7) {
+          //if (handler_->detail(CLP_SIMPLEX_HOUSE2,messages_)<100) {
+          handler_->message(CLP_SIMPLEX_HOUSE2, messages_)
+                    << numberIterations_ << objectiveValue()
+                    << rowcol[isColumn(sequenceIn_)] << sequenceWithin(sequenceIn_)
+                    << rowcol[isColumn(sequenceOut_)] << sequenceWithin(sequenceOut_);
+          handler_->printing(algorithm_ < 0) << dualOut_ << theta_;
+          handler_->printing(algorithm_ > 0) << dualIn_ << theta_;
+          handler_->message() << CoinMessageEol;
+     }
+#if 0
+     if (numberIterations_ > 10000)
+          printf(" it %d %g %c%d %c%d\n"
+                 , numberIterations_, objectiveValue()
+                 , rowcol[isColumn(sequenceIn_)], sequenceWithin(sequenceIn_)
+                 , rowcol[isColumn(sequenceOut_)], sequenceWithin(sequenceOut_));
+#endif
+     if (trustedUserPointer_ && trustedUserPointer_->typeStruct == 1) {
+          if (algorithm_ > 0 && integerType_ && !nonLinearCost_->numberInfeasibilities()) {
+               if (fabs(theta_) > 1.0e-6 || !numberIterations_) {
+                    // For saving solutions
+                    typedef struct {
+                         int numberSolutions;
+                         int maximumSolutions;
+                         int numberColumns;
+                         double ** solution;
+                         int * numberUnsatisfied;
+                    } clpSolution;
+                    clpSolution * solution = reinterpret_cast<clpSolution *> (trustedUserPointer_->data);
+                    if (solution->numberSolutions == solution->maximumSolutions) {
+                         int n =  solution->maximumSolutions;
+                         int n2 = (n * 3) / 2 + 10;
+                         solution->maximumSolutions = n2;
+                         double ** temp = new double * [n2];
+                         for (int i = 0; i < n; i++)
+                              temp[i] = solution->solution[i];
+                         delete [] solution->solution;
+                         solution->solution = temp;
+                         int * tempN = new int [n2];
+                         for (int i = 0; i < n; i++)
+                              tempN[i] = solution->numberUnsatisfied[i];
+                         delete [] solution->numberUnsatisfied;
+                         solution->numberUnsatisfied = tempN;
+                    }
+                    assert (numberColumns_ == solution->numberColumns);
+                    double * sol = new double [numberColumns_];
+                    solution->solution[solution->numberSolutions] = sol;
+                    int numberFixed = 0;
+                    int numberUnsat = 0;
+                    int numberSat = 0;
+                    double sumUnsat = 0.0;
+                    double tolerance = 10.0 * primalTolerance_;
+                    double mostAway = 0.0;
+                    for (int i = 0; i < numberColumns_; i++) {
+                         // Save anyway
+                         sol[i] = columnScale_ ? solution_[i] * columnScale_[i] : solution_[i];
+                         // rest is optional
+                         if (upper_[i] > lower_[i]) {
+                              double value = solution_[i];
+                              if (value > lower_[i] + tolerance &&
+                                        value < upper_[i] - tolerance && integerType_[i]) {
+                                   // may have to modify value if scaled
+                                   if (columnScale_)
+                                        value *= columnScale_[i];
+                                   double closest = floor(value + 0.5);
+                                   // problem may be perturbed so relax test
+                                   if (fabs(value - closest) > 1.0e-4) {
+                                        numberUnsat++;
+                                        sumUnsat += fabs(value - closest);
+                                        if (mostAway < fabs(value - closest)) {
+                                             mostAway = fabs(value - closest);
+                                        }
+                                   } else {
+                                        numberSat++;
+                                   }
+                              } else {
+                                   numberSat++;
+                              }
+                         } else {
+                              numberFixed++;
+                         }
+                    }
+                    solution->numberUnsatisfied[solution->numberSolutions++] = numberUnsat;
+                    COIN_DETAIL_PRINT(printf("iteration %d, %d unsatisfied (%g,%g), %d fixed, %d satisfied\n",
+					     numberIterations_, numberUnsat, sumUnsat, mostAway, numberFixed, numberSat));
+               }
+          }
+     }
+     if (hitMaximumIterations())
+          return 2;
+#if 1
+     //if (numberIterations_>14000)
+     //handler_->setLogLevel(63);
+     //if (numberIterations_>24000)
+     //exit(77);
+     // check for small cycles
+     int in = sequenceIn_;
+     int out = sequenceOut_;
+     matrix_->correctSequence(this, in, out);
+     int cycle = progress_.cycle(in, out,
+                                 directionIn_, directionOut_);
+     if (cycle > 0 && objective_->type() < 2 && matrix_->type() < 15) {
+          //if (cycle>0) {
+          if (handler_->logLevel() >= 63)
+               printf("Cycle of %d\n", cycle);
+          // reset
+          progress_.startCheck();
+          double random = randomNumberGenerator_.randomDouble();
+          int extra = static_cast<int> (9.999 * random);
+          int off[] = {1, 1, 1, 1, 2, 2, 2, 3, 3, 4};
+          if (factorization_->pivots() > cycle) {
+               forceFactorization_ = CoinMax(1, cycle - off[extra]);
+          } else {
+	    /* need to reject something
+	       should be better if don't reject incoming
+	       as it is in basis */
+               int iSequence;
+               //if (algorithm_ > 0)
+	       //   iSequence = sequenceIn_;
+               //else
+                    iSequence = sequenceOut_;
+               char x = isColumn(iSequence) ? 'C' : 'R';
+               if (handler_->logLevel() >= 63)
+                    handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                              << x << sequenceWithin(iSequence)
+                              << CoinMessageEol;
+               setFlagged(iSequence);
+               //printf("flagging %d\n",iSequence);
+          }
+          return 1;
+     }
+#endif
+     // only time to re-factorize if one before real time
+     // this is so user won't be surprised that maximumPivots has exact meaning
+     int numberPivots = factorization_->pivots();
+     int maximumPivots = factorization_->maximumPivots();
+     int numberDense = factorization_->numberDense();
+     bool dontInvert = ((specialOptions_ & 16384) != 0 && numberIterations_ * 3 >
+                        2 * maximumIterations());
+     if (numberPivots == maximumPivots ||
+               maximumPivots < 2) {
+          // If dense then increase
+          if (maximumPivots > 100 && numberDense > 1.5 * maximumPivots) {
+               factorization_->maximumPivots(numberDense);
+               dualRowPivot_->maximumPivotsChanged();
+               primalColumnPivot_->maximumPivotsChanged();
+               // and redo arrays
+               for (int iRow = 0; iRow < 4; iRow++) {
+                    int length = rowArray_[iRow]->capacity() + numberDense - maximumPivots;
+                    rowArray_[iRow]->reserve(length);
+               }
+          }
+          return 1;
+     } else if ((factorization_->timeToRefactorize() && !dontInvert)
+		||invertNow) {
+          //printf("ret after %d pivots\n",factorization_->pivots());
+          return 1;
+     } else if (forceFactorization_ > 0 &&
+                factorization_->pivots() == forceFactorization_) {
+          // relax
+          forceFactorization_ = (3 + 5 * forceFactorization_) / 4;
+          if (forceFactorization_ > factorization_->maximumPivots())
+               forceFactorization_ = -1; //off
+          return 1;
+     } else if (numberIterations_ > 1000 + 10 * (numberRows_ + (numberColumns_ >> 2)) && matrix_->type()<15) {
+          double random = randomNumberGenerator_.randomDouble();
+          int maxNumber = (forceFactorization_ < 0) ? maximumPivots : CoinMin(forceFactorization_, maximumPivots);
+          if (factorization_->pivots() >= random * maxNumber) {
+               return 1;
+          } else if (numberIterations_ > 1000000 + 10 * (numberRows_ + (numberColumns_ >> 2)) &&
+                     numberIterations_ < 1001000 + 10 * (numberRows_ + (numberColumns_ >> 2))) {
+               return 1;
+          } else {
+               // carry on iterating
+               return 0;
+          }
+     } else {
+          // carry on iterating
+          return 0;
+     }
+}
+// Copy constructor.
+ClpSimplex::ClpSimplex(const ClpSimplex &rhs, int scalingMode) :
+     ClpModel(rhs, scalingMode),
+     bestPossibleImprovement_(0.0),
+     zeroTolerance_(1.0e-13),
+     columnPrimalSequence_(-2),
+     rowPrimalSequence_(-2),
+     bestObjectiveValue_(rhs.bestObjectiveValue_),
+     moreSpecialOptions_(2),
+     baseIteration_(0),
+     primalToleranceToGetOptimal_(-1.0),
+     largeValue_(1.0e15),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     alphaAccuracy_(-1.0),
+     dualBound_(1.0e10),
+     alpha_(0.0),
+     theta_(0.0),
+     lowerIn_(0.0),
+     valueIn_(0.0),
+     upperIn_(-COIN_DBL_MAX),
+     dualIn_(0.0),
+     lowerOut_(-1),
+     valueOut_(-1),
+     upperOut_(-1),
+     dualOut_(-1),
+     dualTolerance_(1.0e-7),
+     primalTolerance_(1.0e-7),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     infeasibilityCost_(1.0e10),
+     sumOfRelaxedDualInfeasibilities_(0.0),
+     sumOfRelaxedPrimalInfeasibilities_(0.0),
+     acceptablePivot_(1.0e-8),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rowObjectiveWork_(NULL),
+     objectiveWork_(NULL),
+     sequenceIn_(-1),
+     directionIn_(-1),
+     sequenceOut_(-1),
+     directionOut_(-1),
+     pivotRow_(-1),
+     lastGoodIteration_(-100),
+     dj_(NULL),
+     rowReducedCost_(NULL),
+     reducedCostWork_(NULL),
+     solution_(NULL),
+     rowActivityWork_(NULL),
+     columnActivityWork_(NULL),
+     numberDualInfeasibilities_(0),
+     numberDualInfeasibilitiesWithoutFree_(0),
+     numberPrimalInfeasibilities_(100),
+     numberRefinements_(0),
+     pivotVariable_(NULL),
+     factorization_(NULL),
+     savedSolution_(NULL),
+     numberTimesOptimal_(0),
+     disasterArea_(NULL),
+     changeMade_(1),
+     algorithm_(0),
+     forceFactorization_(-1),
+     perturbation_(100),
+     nonLinearCost_(NULL),
+     lastBadIteration_(-999999),
+     lastFlaggedIteration_(-999999),
+     numberFake_(0),
+     numberChanged_(0),
+     progressFlag_(0),
+     firstFree_(-1),
+     numberExtraRows_(0),
+     maximumBasic_(0),
+     dontFactorizePivots_(0),
+     incomingInfeasibility_(1.0),
+     allowedInfeasibility_(10.0),
+     automaticScale_(0),
+     maximumPerturbationSize_(0),
+     perturbationArray_(NULL),
+     baseModel_(NULL)
+#ifdef ABC_INHERIT
+     ,abcSimplex_(NULL),
+     abcState_(0)
+#endif
+{
+     int i;
+     for (i = 0; i < 6; i++) {
+          rowArray_[i] = NULL;
+          columnArray_[i] = NULL;
+     }
+     for (i = 0; i < 4; i++) {
+          spareIntArray_[i] = 0;
+          spareDoubleArray_[i] = 0.0;
+     }
+     saveStatus_ = NULL;
+     factorization_ = NULL;
+     dualRowPivot_ = NULL;
+     primalColumnPivot_ = NULL;
+     gutsOfDelete(0);
+     delete nonLinearCost_;
+     nonLinearCost_ = NULL;
+     gutsOfCopy(rhs);
+     solveType_ = 1; // say simplex based life form
+}
+// Copy constructor from model
+ClpSimplex::ClpSimplex(const ClpModel &rhs, int scalingMode) :
+     ClpModel(rhs, scalingMode),
+     bestPossibleImprovement_(0.0),
+     zeroTolerance_(1.0e-13),
+     columnPrimalSequence_(-2),
+     rowPrimalSequence_(-2),
+     bestObjectiveValue_(-COIN_DBL_MAX),
+     moreSpecialOptions_(2),
+     baseIteration_(0),
+     primalToleranceToGetOptimal_(-1.0),
+     largeValue_(1.0e15),
+     largestPrimalError_(0.0),
+     largestDualError_(0.0),
+     alphaAccuracy_(-1.0),
+     dualBound_(1.0e10),
+     alpha_(0.0),
+     theta_(0.0),
+     lowerIn_(0.0),
+     valueIn_(0.0),
+     upperIn_(-COIN_DBL_MAX),
+     dualIn_(0.0),
+     lowerOut_(-1),
+     valueOut_(-1),
+     upperOut_(-1),
+     dualOut_(-1),
+     dualTolerance_(1.0e-7),
+     primalTolerance_(1.0e-7),
+     sumDualInfeasibilities_(0.0),
+     sumPrimalInfeasibilities_(0.0),
+     infeasibilityCost_(1.0e10),
+     sumOfRelaxedDualInfeasibilities_(0.0),
+     sumOfRelaxedPrimalInfeasibilities_(0.0),
+     acceptablePivot_(1.0e-8),
+     lower_(NULL),
+     rowLowerWork_(NULL),
+     columnLowerWork_(NULL),
+     upper_(NULL),
+     rowUpperWork_(NULL),
+     columnUpperWork_(NULL),
+     cost_(NULL),
+     rowObjectiveWork_(NULL),
+     objectiveWork_(NULL),
+     sequenceIn_(-1),
+     directionIn_(-1),
+     sequenceOut_(-1),
+     directionOut_(-1),
+     pivotRow_(-1),
+     lastGoodIteration_(-100),
+     dj_(NULL),
+     rowReducedCost_(NULL),
+     reducedCostWork_(NULL),
+     solution_(NULL),
+     rowActivityWork_(NULL),
+     columnActivityWork_(NULL),
+     numberDualInfeasibilities_(0),
+     numberDualInfeasibilitiesWithoutFree_(0),
+     numberPrimalInfeasibilities_(100),
+     numberRefinements_(0),
+     pivotVariable_(NULL),
+     factorization_(NULL),
+     savedSolution_(NULL),
+     numberTimesOptimal_(0),
+     disasterArea_(NULL),
+     changeMade_(1),
+     algorithm_(0),
+     forceFactorization_(-1),
+     perturbation_(100),
+     nonLinearCost_(NULL),
+     lastBadIteration_(-999999),
+     lastFlaggedIteration_(-999999),
+     numberFake_(0),
+     numberChanged_(0),
+     progressFlag_(0),
+     firstFree_(-1),
+     numberExtraRows_(0),
+     maximumBasic_(0),
+     dontFactorizePivots_(0),
+     incomingInfeasibility_(1.0),
+     allowedInfeasibility_(10.0),
+     automaticScale_(0),
+     maximumPerturbationSize_(0),
+     perturbationArray_(NULL),
+     baseModel_(NULL)
+#ifdef ABC_INHERIT
+     ,abcSimplex_(NULL),
+     abcState_(0)
+#endif
+{
+     int i;
+     for (i = 0; i < 6; i++) {
+          rowArray_[i] = NULL;
+          columnArray_[i] = NULL;
+     }
+     for (i = 0; i < 4; i++) {
+          spareIntArray_[i] = 0;
+          spareDoubleArray_[i] = 0.0;
+     }
+     saveStatus_ = NULL;
+     // get an empty factorization so we can set tolerances etc
+     getEmptyFactorization();
+     // say Steepest pricing
+     dualRowPivot_ = new ClpDualRowSteepest();
+     // say Steepest pricing
+     primalColumnPivot_ = new ClpPrimalColumnSteepest();
+     solveType_ = 1; // say simplex based life form
+
+}
+// Assignment operator. This copies the data
+ClpSimplex &
+ClpSimplex::operator=(const ClpSimplex & rhs)
+{
+     if (this != &rhs) {
+          gutsOfDelete(0);
+          delete nonLinearCost_;
+          nonLinearCost_ = NULL;
+          ClpModel::operator=(rhs);
+          gutsOfCopy(rhs);
+     }
+     return *this;
+}
+void
+ClpSimplex::gutsOfCopy(const ClpSimplex & rhs)
+{
+     assert (numberRows_ == rhs.numberRows_);
+     assert (numberColumns_ == rhs.numberColumns_);
+     numberExtraRows_ = rhs.numberExtraRows_;
+     maximumBasic_ = rhs.maximumBasic_;
+     dontFactorizePivots_ = rhs.dontFactorizePivots_;
+     int numberRows2 = numberRows_ + numberExtraRows_;
+     moreSpecialOptions_ = rhs.moreSpecialOptions_;
+     if ((whatsChanged_ & 1) != 0) {
+          int numberTotal = numberColumns_ + numberRows2;
+          if ((specialOptions_ & 65536) != 0 && maximumRows_ >= 0) {
+               assert (maximumInternalRows_ >= numberRows2);
+               assert (maximumInternalColumns_ >= numberColumns_);
+               numberTotal = 2 * (maximumInternalColumns_ + maximumInternalRows_);
+          }
+          lower_ = ClpCopyOfArray(rhs.lower_, numberTotal);
+          rowLowerWork_ = lower_ + numberColumns_;
+          columnLowerWork_ = lower_;
+          upper_ = ClpCopyOfArray(rhs.upper_, numberTotal);
+          rowUpperWork_ = upper_ + numberColumns_;
+          columnUpperWork_ = upper_;
+          cost_ = ClpCopyOfArray(rhs.cost_, numberTotal);
+          objectiveWork_ = cost_;
+          rowObjectiveWork_ = cost_ + numberColumns_;
+          dj_ = ClpCopyOfArray(rhs.dj_, numberTotal);
+          if (dj_) {
+               reducedCostWork_ = dj_;
+               rowReducedCost_ = dj_ + numberColumns_;
+          }
+          solution_ = ClpCopyOfArray(rhs.solution_, numberTotal);
+          if (solution_) {
+               columnActivityWork_ = solution_;
+               rowActivityWork_ = solution_ + numberColumns_;
+          }
+          if (rhs.pivotVariable_) {
+               pivotVariable_ = new int[numberRows2];
+               CoinMemcpyN ( rhs.pivotVariable_, numberRows2 , pivotVariable_);
+          } else {
+               pivotVariable_ = NULL;
+          }
+          savedSolution_ = ClpCopyOfArray(rhs.savedSolution_, numberTotal);
+          int i;
+          for (i = 0; i < 6; i++) {
+               rowArray_[i] = NULL;
+               if (rhs.rowArray_[i])
+                    rowArray_[i] = new CoinIndexedVector(*rhs.rowArray_[i]);
+               columnArray_[i] = NULL;
+               if (rhs.columnArray_[i])
+                    columnArray_[i] = new CoinIndexedVector(*rhs.columnArray_[i]);
+          }
+          if (rhs.saveStatus_) {
+               saveStatus_ = ClpCopyOfArray( rhs.saveStatus_, numberTotal);
+          }
+     } else {
+          lower_ = NULL;
+          rowLowerWork_ = NULL;
+          columnLowerWork_ = NULL;
+          upper_ = NULL;
+          rowUpperWork_ = NULL;
+          columnUpperWork_ = NULL;
+          cost_ = NULL;
+          objectiveWork_ = NULL;
+          rowObjectiveWork_ = NULL;
+          dj_ = NULL;
+          reducedCostWork_ = NULL;
+          rowReducedCost_ = NULL;
+          solution_ = NULL;
+          columnActivityWork_ = NULL;
+          rowActivityWork_ = NULL;
+          pivotVariable_ = NULL;
+          savedSolution_ = NULL;
+          int i;
+          for (i = 0; i < 6; i++) {
+               rowArray_[i] = NULL;
+               columnArray_[i] = NULL;
+          }
+          saveStatus_ = NULL;
+     }
+     if (rhs.factorization_) {
+          setFactorization(*rhs.factorization_);
+     } else {
+          delete factorization_;
+          factorization_ = NULL;
+     }
+     bestPossibleImprovement_ = rhs.bestPossibleImprovement_;
+     columnPrimalSequence_ = rhs.columnPrimalSequence_;
+     zeroTolerance_ = rhs.zeroTolerance_;
+     rowPrimalSequence_ = rhs.rowPrimalSequence_;
+     bestObjectiveValue_ = rhs.bestObjectiveValue_;
+     baseIteration_ = rhs.baseIteration_;
+     primalToleranceToGetOptimal_ = rhs.primalToleranceToGetOptimal_;
+     largeValue_ = rhs.largeValue_;
+     largestPrimalError_ = rhs.largestPrimalError_;
+     largestDualError_ = rhs.largestDualError_;
+     alphaAccuracy_ = rhs.alphaAccuracy_;
+     dualBound_ = rhs.dualBound_;
+     alpha_ = rhs.alpha_;
+     theta_ = rhs.theta_;
+     lowerIn_ = rhs.lowerIn_;
+     valueIn_ = rhs.valueIn_;
+     upperIn_ = rhs.upperIn_;
+     dualIn_ = rhs.dualIn_;
+     sequenceIn_ = rhs.sequenceIn_;
+     directionIn_ = rhs.directionIn_;
+     lowerOut_ = rhs.lowerOut_;
+     valueOut_ = rhs.valueOut_;
+     upperOut_ = rhs.upperOut_;
+     dualOut_ = rhs.dualOut_;
+     sequenceOut_ = rhs.sequenceOut_;
+     directionOut_ = rhs.directionOut_;
+     pivotRow_ = rhs.pivotRow_;
+     lastGoodIteration_ = rhs.lastGoodIteration_;
+     numberRefinements_ = rhs.numberRefinements_;
+     dualTolerance_ = rhs.dualTolerance_;
+     primalTolerance_ = rhs.primalTolerance_;
+     sumDualInfeasibilities_ = rhs.sumDualInfeasibilities_;
+     numberDualInfeasibilities_ = rhs.numberDualInfeasibilities_;
+     numberDualInfeasibilitiesWithoutFree_ =
+          rhs.numberDualInfeasibilitiesWithoutFree_;
+     sumPrimalInfeasibilities_ = rhs.sumPrimalInfeasibilities_;
+     numberPrimalInfeasibilities_ = rhs.numberPrimalInfeasibilities_;
+     dualRowPivot_ = rhs.dualRowPivot_->clone(true);
+     dualRowPivot_->setModel(this);
+     primalColumnPivot_ = rhs.primalColumnPivot_->clone(true);
+     primalColumnPivot_->setModel(this);
+     numberTimesOptimal_ = rhs.numberTimesOptimal_;
+     disasterArea_ = NULL;
+     changeMade_ = rhs.changeMade_;
+     algorithm_ = rhs.algorithm_;
+     forceFactorization_ = rhs.forceFactorization_;
+     perturbation_ = rhs.perturbation_;
+     infeasibilityCost_ = rhs.infeasibilityCost_;
+     lastBadIteration_ = rhs.lastBadIteration_;
+     lastFlaggedIteration_ = rhs.lastFlaggedIteration_;
+     numberFake_ = rhs.numberFake_;
+     numberChanged_ = rhs.numberChanged_;
+     progressFlag_ = rhs.progressFlag_;
+     firstFree_ = rhs.firstFree_;
+     incomingInfeasibility_ = rhs.incomingInfeasibility_;
+     allowedInfeasibility_ = rhs.allowedInfeasibility_;
+     automaticScale_ = rhs.automaticScale_;
+#ifdef ABC_INHERIT
+     abcSimplex_ = NULL;
+     abcState_ = rhs.abcState_;
+#endif
+     maximumPerturbationSize_ = rhs.maximumPerturbationSize_;
+     if (maximumPerturbationSize_ && maximumPerturbationSize_ >= 2 * numberColumns_) {
+          perturbationArray_ = CoinCopyOfArray(rhs.perturbationArray_,
+                                               maximumPerturbationSize_);
+     } else {
+          maximumPerturbationSize_ = 0;
+          perturbationArray_ = NULL;
+     }
+     if (rhs.baseModel_) {
+          baseModel_ = new ClpSimplex(*rhs.baseModel_);
+     } else {
+          baseModel_ = NULL;
+     }
+     progress_ = rhs.progress_;
+     for (int i = 0; i < 4; i++) {
+          spareIntArray_[i] = rhs.spareIntArray_[i];
+          spareDoubleArray_[i] = rhs.spareDoubleArray_[i];
+     }
+     sumOfRelaxedDualInfeasibilities_ = rhs.sumOfRelaxedDualInfeasibilities_;
+     sumOfRelaxedPrimalInfeasibilities_ = rhs.sumOfRelaxedPrimalInfeasibilities_;
+     acceptablePivot_ = rhs.acceptablePivot_;
+     if (rhs.nonLinearCost_ != NULL)
+          nonLinearCost_ = new ClpNonLinearCost(*rhs.nonLinearCost_);
+     else
+          nonLinearCost_ = NULL;
+     solveType_ = rhs.solveType_;
+}
+// type == 0 do everything, most + pivot data, 2 factorization data as well
+void
+ClpSimplex::gutsOfDelete(int type)
+{
+     if (!type || (specialOptions_ & 65536) == 0) {
+          maximumInternalColumns_ = -1;
+          maximumInternalRows_ = -1;
+          delete [] lower_;
+          lower_ = NULL;
+          rowLowerWork_ = NULL;
+          columnLowerWork_ = NULL;
+          delete [] upper_;
+          upper_ = NULL;
+          rowUpperWork_ = NULL;
+          columnUpperWork_ = NULL;
+          delete [] cost_;
+          cost_ = NULL;
+          objectiveWork_ = NULL;
+          rowObjectiveWork_ = NULL;
+          delete [] dj_;
+          dj_ = NULL;
+          reducedCostWork_ = NULL;
+          rowReducedCost_ = NULL;
+          delete [] solution_;
+          solution_ = NULL;
+          rowActivityWork_ = NULL;
+          columnActivityWork_ = NULL;
+          delete [] savedSolution_;
+          savedSolution_ = NULL;
+     }
+     if ((specialOptions_ & 2) == 0) {
+          delete nonLinearCost_;
+          nonLinearCost_ = NULL;
+     }
+     int i;
+     if ((specialOptions_ & 65536) == 0) {
+          for (i = 0; i < 6; i++) {
+               delete rowArray_[i];
+               rowArray_[i] = NULL;
+               delete columnArray_[i];
+               columnArray_[i] = NULL;
+          }
+     }
+     delete [] saveStatus_;
+     saveStatus_ = NULL;
+     if (type != 1) {
+          delete rowCopy_;
+          rowCopy_ = NULL;
+     }
+     if (!type) {
+          // delete everything
+          setEmptyFactorization();
+          delete [] pivotVariable_;
+          pivotVariable_ = NULL;
+          delete dualRowPivot_;
+          dualRowPivot_ = NULL;
+          delete primalColumnPivot_;
+          primalColumnPivot_ = NULL;
+          delete baseModel_;
+          baseModel_ = NULL;
+          delete [] perturbationArray_;
+          perturbationArray_ = NULL;
+          maximumPerturbationSize_ = 0;
+     } else {
+          // delete any size information in methods
+          if (type > 1) {
+               //assert (factorization_);
+               if (factorization_)
+                    factorization_->clearArrays();
+               delete [] pivotVariable_;
+               pivotVariable_ = NULL;
+          }
+          dualRowPivot_->clearArrays();
+          primalColumnPivot_->clearArrays();
+     }
+}
+// This sets largest infeasibility and most infeasible
+void
+ClpSimplex::checkPrimalSolution(const double * rowActivities,
+                                const double * columnActivities)
+{
+     double * solution;
+     int iRow, iColumn;
+
+     objectiveValue_ = 0.0;
+     // now look at primal solution
+     solution = rowActivityWork_;
+     sumPrimalInfeasibilities_ = 0.0;
+     numberPrimalInfeasibilities_ = 0;
+     double primalTolerance = primalTolerance_;
+     double relaxedTolerance = primalTolerance_;
+     // we can't really trust infeasibilities if there is primal error
+     double error = CoinMin(1.0e-2, largestPrimalError_);
+     // allow tolerance at least slightly bigger than standard
+     relaxedTolerance = relaxedTolerance +  error;
+     sumOfRelaxedPrimalInfeasibilities_ = 0.0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          //assert (fabs(solution[iRow])<1.0e15||getRowStatus(iRow) == basic);
+          double infeasibility = 0.0;
+          objectiveValue_ += solution[iRow] * rowObjectiveWork_[iRow];
+          if (solution[iRow] > rowUpperWork_[iRow]) {
+               infeasibility = solution[iRow] - rowUpperWork_[iRow];
+          } else if (solution[iRow] < rowLowerWork_[iRow]) {
+               infeasibility = rowLowerWork_[iRow] - solution[iRow];
+          }
+          if (infeasibility > primalTolerance) {
+               sumPrimalInfeasibilities_ += infeasibility - primalTolerance_;
+               if (infeasibility > relaxedTolerance)
+                    sumOfRelaxedPrimalInfeasibilities_ += infeasibility - relaxedTolerance;
+               numberPrimalInfeasibilities_ ++;
+          }
+          infeasibility = fabs(rowActivities[iRow] - solution[iRow]);
+     }
+     // Check any infeasibilities from dynamic rows
+     matrix_->primalExpanded(this, 2);
+     solution = columnActivityWork_;
+     if (!matrix_->rhsOffset(this)) {
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               //assert (fabs(solution[iColumn])<1.0e15||getColumnStatus(iColumn) == basic);
+               double infeasibility = 0.0;
+               objectiveValue_ += objectiveWork_[iColumn] * solution[iColumn];
+               if (solution[iColumn] > columnUpperWork_[iColumn]) {
+                    infeasibility = solution[iColumn] - columnUpperWork_[iColumn];
+               } else if (solution[iColumn] < columnLowerWork_[iColumn]) {
+                    infeasibility = columnLowerWork_[iColumn] - solution[iColumn];
+               }
+               if (infeasibility > primalTolerance) {
+                    sumPrimalInfeasibilities_ += infeasibility - primalTolerance_;
+                    if (infeasibility > relaxedTolerance)
+                         sumOfRelaxedPrimalInfeasibilities_ += infeasibility - relaxedTolerance;
+                    numberPrimalInfeasibilities_ ++;
+               }
+               infeasibility = fabs(columnActivities[iColumn] - solution[iColumn]);
+          }
+     } else {
+          // as we are using effective rhs we only check basics
+          // But we do need to get objective
+          objectiveValue_ += innerProduct(objectiveWork_, numberColumns_, solution);
+          for (int j = 0; j < numberRows_; j++) {
+               int iColumn = pivotVariable_[j];
+               //assert (fabs(solution[iColumn])<1.0e15||getColumnStatus(iColumn) == basic);
+               double infeasibility = 0.0;
+               if (solution[iColumn] > columnUpperWork_[iColumn]) {
+                    infeasibility = solution[iColumn] - columnUpperWork_[iColumn];
+               } else if (solution[iColumn] < columnLowerWork_[iColumn]) {
+                    infeasibility = columnLowerWork_[iColumn] - solution[iColumn];
+               }
+               if (infeasibility > primalTolerance) {
+                    sumPrimalInfeasibilities_ += infeasibility - primalTolerance_;
+                    if (infeasibility > relaxedTolerance)
+                         sumOfRelaxedPrimalInfeasibilities_ += infeasibility - relaxedTolerance;
+                    numberPrimalInfeasibilities_ ++;
+               }
+               infeasibility = fabs(columnActivities[iColumn] - solution[iColumn]);
+          }
+     }
+     objectiveValue_ += objective_->nonlinearOffset();
+     objectiveValue_ /= (objectiveScale_ * rhsScale_);
+}
+void
+ClpSimplex::checkDualSolution()
+{
+
+     int iRow, iColumn;
+     sumDualInfeasibilities_ = 0.0;
+     numberDualInfeasibilities_ = 0;
+     numberDualInfeasibilitiesWithoutFree_ = 0;
+     if (matrix_->skipDualCheck() && algorithm_ > 0 && problemStatus_ == -2) {
+          // pretend we found dual infeasibilities
+          sumOfRelaxedDualInfeasibilities_ = 1.0;
+          sumDualInfeasibilities_ = 1.0;
+          numberDualInfeasibilities_ = 1;
+          return;
+     }
+     int firstFreePrimal = -1;
+     int firstFreeDual = -1;
+     int numberSuperBasicWithDj = 0;
+     bestPossibleImprovement_ = 0.0;
+     // we can't really trust infeasibilities if there is dual error
+     double error = CoinMin(1.0e-2, largestDualError_);
+     // allow tolerance at least slightly bigger than standard
+     double relaxedTolerance = dualTolerance_ +  error;
+     // allow bigger tolerance for possible improvement
+     double possTolerance = 5.0 * relaxedTolerance;
+     sumOfRelaxedDualInfeasibilities_ = 0.0;
+
+     // Check any djs from dynamic rows
+     matrix_->dualExpanded(this, NULL, NULL, 3);
+     numberDualInfeasibilitiesWithoutFree_ = numberDualInfeasibilities_;
+     objectiveValue_ = 0.0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          objectiveValue_ += objectiveWork_[iColumn] * columnActivityWork_[iColumn];
+          if (getColumnStatus(iColumn) != basic && !flagged(iColumn)) {
+               // not basic
+               double distanceUp = columnUpperWork_[iColumn] -
+                                   columnActivityWork_[iColumn];
+               double distanceDown = columnActivityWork_[iColumn] -
+                                     columnLowerWork_[iColumn];
+               if (distanceUp > primalTolerance_) {
+                    double value = reducedCostWork_[iColumn];
+                    // Check if "free"
+                    if (distanceDown > primalTolerance_) {
+                         if (fabs(value) > 1.0e2 * relaxedTolerance) {
+                              numberSuperBasicWithDj++;
+                              if (firstFreeDual < 0)
+                                   firstFreeDual = iColumn;
+                         }
+                         if (firstFreePrimal < 0)
+                              firstFreePrimal = iColumn;
+                    }
+                    // should not be negative
+                    if (value < 0.0) {
+                         value = - value;
+                         if (value > dualTolerance_) {
+                              if (getColumnStatus(iColumn) != isFree) {
+                                   numberDualInfeasibilitiesWithoutFree_ ++;
+                                   sumDualInfeasibilities_ += value - dualTolerance_;
+                                   if (value > possTolerance)
+                                        bestPossibleImprovement_ += CoinMin(distanceUp, 1.0e10) * value;
+                                   if (value > relaxedTolerance)
+                                        sumOfRelaxedDualInfeasibilities_ += value - relaxedTolerance;
+                                   numberDualInfeasibilities_ ++;
+                              } else {
+                                   // free so relax a lot
+                                   value *= 0.01;
+                                   if (value > dualTolerance_) {
+                                        sumDualInfeasibilities_ += value - dualTolerance_;
+                                        if (value > possTolerance)
+                                             bestPossibleImprovement_ = 1.0e100;
+                                        if (value > relaxedTolerance)
+                                             sumOfRelaxedDualInfeasibilities_ += value - relaxedTolerance;
+                                        numberDualInfeasibilities_ ++;
+                                   }
+                              }
+                         }
+                    }
+               }
+               if (distanceDown > primalTolerance_) {
+                    double value = reducedCostWork_[iColumn];
+                    // should not be positive
+                    if (value > 0.0) {
+                         if (value > dualTolerance_) {
+                              sumDualInfeasibilities_ += value - dualTolerance_;
+                              if (value > possTolerance)
+                                   bestPossibleImprovement_ += value * CoinMin(distanceDown, 1.0e10);
+                              if (value > relaxedTolerance)
+                                   sumOfRelaxedDualInfeasibilities_ += value - relaxedTolerance;
+                              numberDualInfeasibilities_ ++;
+                              if (getColumnStatus(iColumn) != isFree)
+                                   numberDualInfeasibilitiesWithoutFree_ ++;
+                              // maybe we can make feasible by increasing tolerance
+                         }
+                    }
+               }
+          }
+     }
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          objectiveValue_ += rowActivityWork_[iRow] * rowObjectiveWork_[iRow];
+          if (getRowStatus(iRow) != basic && !flagged(iRow + numberColumns_)) {
+               // not basic
+               double distanceUp = rowUpperWork_[iRow] - rowActivityWork_[iRow];
+               double distanceDown = rowActivityWork_[iRow] - rowLowerWork_[iRow];
+               if (distanceUp > primalTolerance_) {
+                    double value = rowReducedCost_[iRow];
+                    // Check if "free"
+                    if (distanceDown > primalTolerance_) {
+                         if (fabs(value) > 1.0e2 * relaxedTolerance) {
+                              numberSuperBasicWithDj++;
+                              if (firstFreeDual < 0)
+                                   firstFreeDual = iRow + numberColumns_;
+                         }
+                         if (firstFreePrimal < 0)
+                              firstFreePrimal = iRow + numberColumns_;
+                    }
+                    // should not be negative
+                    if (value < 0.0) {
+                         value = - value;
+                         if (value > dualTolerance_) {
+                              sumDualInfeasibilities_ += value - dualTolerance_;
+                              if (value > possTolerance)
+                                   bestPossibleImprovement_ += value * CoinMin(distanceUp, 1.0e10);
+                              if (value > relaxedTolerance)
+                                   sumOfRelaxedDualInfeasibilities_ += value - relaxedTolerance;
+                              numberDualInfeasibilities_ ++;
+                              if (getRowStatus(iRow) != isFree)
+                                   numberDualInfeasibilitiesWithoutFree_ ++;
+                         }
+                    }
+               }
+               if (distanceDown > primalTolerance_) {
+                    double value = rowReducedCost_[iRow];
+                    // should not be positive
+                    if (value > 0.0) {
+                         if (value > dualTolerance_) {
+                              sumDualInfeasibilities_ += value - dualTolerance_;
+                              if (value > possTolerance)
+                                   bestPossibleImprovement_ += value * CoinMin(distanceDown, 1.0e10);
+                              if (value > relaxedTolerance)
+                                   sumOfRelaxedDualInfeasibilities_ += value - relaxedTolerance;
+                              numberDualInfeasibilities_ ++;
+                              if (getRowStatus(iRow) != isFree)
+                                   numberDualInfeasibilitiesWithoutFree_ ++;
+                              // maybe we can make feasible by increasing tolerance
+                         }
+                    }
+               }
+          }
+     }
+     if (algorithm_ < 0 && firstFreeDual >= 0) {
+          // dual
+          firstFree_ = firstFreeDual;
+     } else if (numberSuperBasicWithDj ||
+                (progress_.lastIterationNumber(0) <= 0)) {
+          firstFree_ = firstFreePrimal;
+     }
+     objectiveValue_ += objective_->nonlinearOffset();
+     objectiveValue_ /= (objectiveScale_ * rhsScale_);
+}
+/* This sets sum and number of infeasibilities (Dual and Primal) */
+void
+ClpSimplex::checkBothSolutions()
+{
+     if ((matrix_->skipDualCheck() && algorithm_ > 0 && problemStatus_ == -2) ||
+               matrix_->rhsOffset(this)) {
+          // Say may be free or superbasic
+          moreSpecialOptions_ &= ~8;
+          // old way
+          checkPrimalSolution(rowActivityWork_, columnActivityWork_);
+          checkDualSolution();
+          return;
+     }
+     int iSequence;
+     assert (dualTolerance_ > 0.0 && dualTolerance_ < 1.0e10);
+     assert (primalTolerance_ > 0.0 && primalTolerance_ < 1.0e10);
+     objectiveValue_ = 0.0;
+     sumPrimalInfeasibilities_ = 0.0;
+     numberPrimalInfeasibilities_ = 0;
+     double primalTolerance = primalTolerance_;
+     double relaxedToleranceP = primalTolerance_;
+     // we can't really trust infeasibilities if there is primal error
+     double error = CoinMin(1.0e-2, largestPrimalError_);
+     // allow tolerance at least slightly bigger than standard
+     relaxedToleranceP = relaxedToleranceP +  error;
+     sumOfRelaxedPrimalInfeasibilities_ = 0.0;
+     sumDualInfeasibilities_ = 0.0;
+     numberDualInfeasibilities_ = 0;
+     double dualTolerance = dualTolerance_;
+     double relaxedToleranceD = dualTolerance;
+     // we can't really trust infeasibilities if there is dual error
+     error = CoinMin(1.0e-2, largestDualError_);
+     // allow tolerance at least slightly bigger than standard
+     relaxedToleranceD = relaxedToleranceD +  error;
+     // allow bigger tolerance for possible improvement
+     double possTolerance = 5.0 * relaxedToleranceD;
+     sumOfRelaxedDualInfeasibilities_ = 0.0;
+     bestPossibleImprovement_ = 0.0;
+
+     // Check any infeasibilities from dynamic rows
+     matrix_->primalExpanded(this, 2);
+     // Check any djs from dynamic rows
+     matrix_->dualExpanded(this, NULL, NULL, 3);
+     int numberDualInfeasibilitiesFree = 0;
+     int firstFreePrimal = -1;
+     int firstFreeDual = -1;
+     int numberSuperBasicWithDj = 0;
+
+     int numberTotal = numberRows_ + numberColumns_;
+     // Say no free or superbasic
+     moreSpecialOptions_ |= 8;
+     //#define PRINT_INFEAS
+#ifdef PRINT_INFEAS
+     int seqInf[10];
+#endif
+     for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+          double value = solution_[iSequence];
+#ifdef COIN_DEBUG
+          if (fabs(value) > 1.0e20)
+               printf("%d values %g %g %g - status %d\n", iSequence, lower_[iSequence],
+                      solution_[iSequence], upper_[iSequence], status_[iSequence]);
+#endif
+          objectiveValue_ += value * cost_[iSequence];
+          double distanceUp = upper_[iSequence] - value;
+          double distanceDown = value - lower_[iSequence];
+          if (distanceUp < -primalTolerance) {
+               double infeasibility = -distanceUp;
+               sumPrimalInfeasibilities_ += infeasibility - primalTolerance_;
+               if (infeasibility > relaxedToleranceP)
+                    sumOfRelaxedPrimalInfeasibilities_ += infeasibility - relaxedToleranceP;
+#ifdef PRINT_INFEAS
+	       if (numberPrimalInfeasibilities_<10) {
+		 seqInf[numberPrimalInfeasibilities_]=iSequence;
+	       }
+#endif
+               numberPrimalInfeasibilities_ ++;
+          } else if (distanceDown < -primalTolerance) {
+               double infeasibility = -distanceDown;
+               sumPrimalInfeasibilities_ += infeasibility - primalTolerance_;
+               if (infeasibility > relaxedToleranceP)
+                    sumOfRelaxedPrimalInfeasibilities_ += infeasibility - relaxedToleranceP;
+#ifdef PRINT_INFEAS
+	       if (numberPrimalInfeasibilities_<10) {
+		 seqInf[numberPrimalInfeasibilities_]=iSequence;
+	       }
+#endif
+               numberPrimalInfeasibilities_ ++;
+          } else {
+               // feasible (so could be free)
+               if (getStatus(iSequence) != basic && !flagged(iSequence)) {
+                    // not basic
+                    double djValue = dj_[iSequence];
+                    if (distanceDown < primalTolerance) {
+                         if (distanceUp > primalTolerance && djValue < -dualTolerance) {
+                              sumDualInfeasibilities_ -= djValue + dualTolerance;
+                              if (djValue < -possTolerance)
+                                   bestPossibleImprovement_ -= distanceUp * djValue;
+                              if (djValue < -relaxedToleranceD)
+                                   sumOfRelaxedDualInfeasibilities_ -= djValue + relaxedToleranceD;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    } else if (distanceUp < primalTolerance) {
+                         if (djValue > dualTolerance) {
+                              sumDualInfeasibilities_ += djValue - dualTolerance;
+                              if (djValue > possTolerance)
+                                   bestPossibleImprovement_ += distanceDown * djValue;
+                              if (djValue > relaxedToleranceD)
+                                   sumOfRelaxedDualInfeasibilities_ += djValue - relaxedToleranceD;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    } else {
+                         // may be free
+                         // Say free or superbasic
+                         moreSpecialOptions_ &= ~8;
+                         djValue *= 0.01;
+                         if (fabs(djValue) > dualTolerance) {
+                              if (getStatus(iSequence) == isFree)
+                                   numberDualInfeasibilitiesFree++;
+                              sumDualInfeasibilities_ += fabs(djValue) - dualTolerance;
+                              bestPossibleImprovement_ = 1.0e100;
+                              numberDualInfeasibilities_ ++;
+                              if (fabs(djValue) > relaxedToleranceD) {
+                                   sumOfRelaxedDualInfeasibilities_ += value - relaxedToleranceD;
+                                   numberSuperBasicWithDj++;
+                                   if (firstFreeDual < 0)
+                                        firstFreeDual = iSequence;
+                              }
+                         }
+                         if (firstFreePrimal < 0)
+                              firstFreePrimal = iSequence;
+                    }
+               }
+          }
+     }
+     objectiveValue_ += objective_->nonlinearOffset();
+     objectiveValue_ /= (objectiveScale_ * rhsScale_);
+     numberDualInfeasibilitiesWithoutFree_ = numberDualInfeasibilities_ -
+                                             numberDualInfeasibilitiesFree;
+#ifdef PRINT_INFEAS
+     if (numberPrimalInfeasibilities_<=10) {
+       printf("---------------start-----------\n");
+       if (!rowScale_) {
+	 for (int i=0;i<numberPrimalInfeasibilities_;i++) {
+	   int iSeq = seqInf[i];
+	   double infeas;
+	   if (solution_[iSeq]<lower_[iSeq])
+	     infeas = lower_[iSeq]-solution_[iSeq];
+	   else
+	     infeas = solution_[iSeq]-upper_[iSeq];
+	   if (iSeq<numberColumns_) {
+	     printf("INF C%d %.10g <= %.10g <= %.10g - infeas %g\n",
+		    iSeq,lower_[iSeq],solution_[iSeq],upper_[iSeq],infeas);
+	   } else {
+	     printf("INF R%d %.10g <= %.10g <= %.10g - infeas %g\n",
+		    iSeq-numberColumns_,lower_[iSeq],solution_[iSeq],upper_[iSeq],infeas);
+	   }
+	 }
+       } else {
+	 for (int i=0;i<numberPrimalInfeasibilities_;i++) {
+	   int iSeq = seqInf[i];
+	   double infeas;
+	   if (solution_[iSeq]<lower_[iSeq])
+	     infeas = lower_[iSeq]-solution_[iSeq];
+	   else
+	     infeas = solution_[iSeq]-upper_[iSeq];
+	   double unscaled = infeas;
+	   if (iSeq<numberColumns_) {
+	     unscaled *= columnScale_[iSeq];
+	     printf("INF C%d %.10g <= %.10g <= %.10g - infeas %g - unscaled %g\n",
+		    iSeq,lower_[iSeq],solution_[iSeq],upper_[iSeq],infeas,unscaled);
+	   } else {
+	     unscaled /= rowScale_[iSeq-numberColumns_];
+	     printf("INF R%d %.10g <= %.10g <= %.10g - infeas %g - unscaled %g\n",
+		    iSeq-numberColumns_,lower_[iSeq],solution_[iSeq],upper_[iSeq],infeas,unscaled);
+	   }
+	 }
+       }
+     }
+#endif
+     if (algorithm_ < 0 && firstFreeDual >= 0) {
+          // dual
+          firstFree_ = firstFreeDual;
+     } else if (numberSuperBasicWithDj ||
+                (progress_.lastIterationNumber(0) <= 0)) {
+          firstFree_ = firstFreePrimal;
+     }
+}
+/* Adds multiple of a column into an array */
+void
+ClpSimplex::add(double * array,
+                int sequence, double multiplier) const
+{
+     if (sequence >= numberColumns_ && sequence < numberColumns_ + numberRows_) {
+          //slack
+          array [sequence-numberColumns_] -= multiplier;
+     } else {
+          // column
+          matrix_->add(this, array, sequence, multiplier);
+     }
+}
+/*
+  Unpacks one column of the matrix into indexed array
+*/
+void
+ClpSimplex::unpack(CoinIndexedVector * rowArray) const
+{
+     rowArray->clear();
+     if (sequenceIn_ >= numberColumns_ && sequenceIn_ < numberColumns_ + numberRows_) {
+          //slack
+          rowArray->insert(sequenceIn_ - numberColumns_, -1.0);
+     } else {
+          // column
+          matrix_->unpack(this, rowArray, sequenceIn_);
+     }
+}
+void
+ClpSimplex::unpack(CoinIndexedVector * rowArray, int sequence) const
+{
+     rowArray->clear();
+     if (sequence >= numberColumns_ && sequence < numberColumns_ + numberRows_) {
+          //slack
+          rowArray->insert(sequence - numberColumns_, -1.0);
+     } else {
+          // column
+          matrix_->unpack(this, rowArray, sequence);
+     }
+}
+/*
+  Unpacks one column of the matrix into indexed array
+*/
+void
+ClpSimplex::unpackPacked(CoinIndexedVector * rowArray)
+{
+     rowArray->clear();
+     if (sequenceIn_ >= numberColumns_ && sequenceIn_ < numberColumns_ + numberRows_) {
+          //slack
+          int * index = rowArray->getIndices();
+          double * array = rowArray->denseVector();
+          array[0] = -1.0;
+          index[0] = sequenceIn_ - numberColumns_;
+          rowArray->setNumElements(1);
+          rowArray->setPackedMode(true);
+     } else {
+          // column
+          matrix_->unpackPacked(this, rowArray, sequenceIn_);
+     }
+}
+void
+ClpSimplex::unpackPacked(CoinIndexedVector * rowArray, int sequence)
+{
+     rowArray->clear();
+     if (sequence >= numberColumns_ && sequence < numberColumns_ + numberRows_) {
+          //slack
+          int * index = rowArray->getIndices();
+          double * array = rowArray->denseVector();
+          array[0] = -1.0;
+          index[0] = sequence - numberColumns_;
+          rowArray->setNumElements(1);
+          rowArray->setPackedMode(true);
+     } else {
+          // column
+          matrix_->unpackPacked(this, rowArray, sequence);
+     }
+}
+//static int x_gaps[4]={0,0,0,0};
+//static int scale_times[]={0,0,0,0};
+bool
+ClpSimplex::createRim(int what, bool makeRowCopy, int startFinishOptions)
+{
+     bool goodMatrix = true;
+     int saveLevel = handler_->logLevel();
+     spareIntArray_[0] = 0;
+     if (!matrix_->canGetRowCopy())
+          makeRowCopy = false; // switch off row copy if can't produce
+     // Arrays will be there and correct size unless what is 63
+     bool newArrays = (what == 63);
+     // We may be restarting with same size
+     bool keepPivots = false;
+     if (startFinishOptions == -1) {
+          startFinishOptions = 0;
+          keepPivots = true;
+     }
+     bool oldMatrix = ((startFinishOptions & 4) != 0 && (whatsChanged_ & 1) != 0);
+     if (what == 63) {
+          pivotRow_ = -1;
+          if (!status_)
+               createStatus();
+          if (oldMatrix)
+               newArrays = false;
+          if (problemStatus_ == 10) {
+               handler_->setLogLevel(0); // switch off messages
+               if (rowArray_[0]) {
+                    // stuff is still there
+                    oldMatrix = true;
+                    newArrays = false;
+                    keepPivots = true;
+                    for (int iRow = 0; iRow < 4; iRow++) {
+                         rowArray_[iRow]->clear();
+                    }
+                    for (int iColumn = 0; iColumn < 2; iColumn++) {
+                         columnArray_[iColumn]->clear();
+                    }
+               }
+          } else if (factorization_) {
+               // match up factorization messages
+               if (handler_->logLevel() < 3)
+                    factorization_->messageLevel(0);
+               else
+                    factorization_->messageLevel(CoinMax(3, factorization_->messageLevel()));
+               /* Faster to keep pivots rather than re-scan matrix.  Matrix may have changed
+                  i.e. oldMatrix false but okay as long as same number rows and status array exists
+               */
+               if ((startFinishOptions & 2) != 0 && factorization_->numberRows() == numberRows_ && status_)
+                    keepPivots = true;
+          }
+          numberExtraRows_ = matrix_->generalExpanded(this, 2, maximumBasic_);
+          if (numberExtraRows_ && newArrays) {
+               // make sure status array large enough
+               assert (status_);
+               int numberOld = numberRows_ + numberColumns_;
+               int numberNew = numberRows_ + numberColumns_ + numberExtraRows_;
+               unsigned char * newStatus = new unsigned char [numberNew];
+               memset(newStatus + numberOld, 0, numberExtraRows_);
+               CoinMemcpyN(status_, numberOld, newStatus);
+               delete [] status_;
+               status_ = newStatus;
+          }
+     }
+     int numberRows2 = numberRows_ + numberExtraRows_;
+     int numberTotal = numberRows2 + numberColumns_;
+     if ((specialOptions_ & 65536) != 0) {
+          assert (!numberExtraRows_);
+          if (!cost_ || numberRows2 > maximumInternalRows_ ||
+                    numberColumns_ > maximumInternalColumns_) {
+               newArrays = true;
+               keepPivots = false;
+               COIN_DETAIL_PRINT(printf("createrim a %d rows, %d maximum rows %d maxinternal\n",
+					numberRows_, maximumRows_, maximumInternalRows_));
+               int oldMaximumRows = maximumInternalRows_;
+               int oldMaximumColumns = maximumInternalColumns_;
+               if (cost_) {
+                    if (numberRows2 > maximumInternalRows_)
+                         maximumInternalRows_ = numberRows2;
+                    if (numberColumns_ > maximumInternalColumns_)
+                         maximumInternalColumns_ = numberColumns_;
+               } else {
+                    maximumInternalRows_ = numberRows2;
+                    maximumInternalColumns_ = numberColumns_;
+               }
+               //maximumRows_=CoinMax(maximumInternalRows_,maximumRows_);
+               //maximumColumns_=CoinMax(maximumInternalColumns_,maximumColumns_);
+               assert(maximumInternalRows_ == maximumRows_);
+               assert(maximumInternalColumns_ == maximumColumns_);
+               COIN_DETAIL_PRINT(printf("createrim b %d rows, %d maximum rows, %d maxinternal\n",
+					numberRows_, maximumRows_, maximumInternalRows_));
+               int numberTotal2 = (maximumInternalRows_ + maximumInternalColumns_) * 2;
+               delete [] cost_;
+               cost_ = new double[numberTotal2];
+               delete [] lower_;
+               delete [] upper_;
+               lower_ = new double[numberTotal2];
+               upper_ = new double[numberTotal2];
+               delete [] dj_;
+               dj_ = new double[numberTotal2];
+               delete [] solution_;
+               solution_ = new double[numberTotal2];
+               // ***** should be non NULL but seems to be too much
+               //printf("resize %d savedRowScale %x\n",maximumRows_,savedRowScale_);
+               if (savedRowScale_) {
+                    assert (oldMaximumRows > 0);
+                    double * temp;
+                    temp = new double [4*maximumRows_];
+                    CoinFillN(temp, 4 * maximumRows_, 1.0);
+                    CoinMemcpyN(savedRowScale_, numberRows_, temp);
+                    CoinMemcpyN(savedRowScale_ + oldMaximumRows, numberRows_, temp + maximumRows_);
+                    CoinMemcpyN(savedRowScale_ + 2 * oldMaximumRows, numberRows_, temp + 2 * maximumRows_);
+                    CoinMemcpyN(savedRowScale_ + 3 * oldMaximumRows, numberRows_, temp + 3 * maximumRows_);
+                    delete [] savedRowScale_;
+                    savedRowScale_ = temp;
+                    temp = new double [4*maximumColumns_];
+                    CoinFillN(temp, 4 * maximumColumns_, 1.0);
+                    CoinMemcpyN(savedColumnScale_, numberColumns_, temp);
+                    CoinMemcpyN(savedColumnScale_ + oldMaximumColumns, numberColumns_, temp + maximumColumns_);
+                    CoinMemcpyN(savedColumnScale_ + 2 * oldMaximumColumns, numberColumns_, temp + 2 * maximumColumns_);
+                    CoinMemcpyN(savedColumnScale_ + 3 * oldMaximumColumns, numberColumns_, temp + 3 * maximumColumns_);
+                    delete [] savedColumnScale_;
+                    savedColumnScale_ = temp;
+               }
+          }
+     }
+     int i;
+     bool doSanityCheck = true;
+     if (what == 63) {
+          // We may want to switch stuff off for speed
+          if ((specialOptions_ & 256) != 0)
+               makeRowCopy = false; // no row copy
+          if ((specialOptions_ & 128) != 0)
+               doSanityCheck = false; // no sanity check
+          //check matrix
+          if (!matrix_)
+               matrix_ = new ClpPackedMatrix();
+          int checkType = (doSanityCheck) ? 15 : 14;
+          if (oldMatrix)
+               checkType = 14;
+          bool inCbcOrOther = (specialOptions_ & 0x03000000) != 0;
+          if (inCbcOrOther)
+               checkType -= 4; // don't check for duplicates
+          if (!matrix_->allElementsInRange(this, smallElement_, 1.0e20, checkType)) {
+               problemStatus_ = 4;
+               secondaryStatus_ = 8;
+               //goodMatrix= false;
+               return false;
+          }
+          bool rowCopyIsScaled;
+          if (makeRowCopy) {
+               if(!oldMatrix || !rowCopy_) {
+                    delete rowCopy_;
+                    // may return NULL if can't give row copy
+                    rowCopy_ = matrix_->reverseOrderedCopy();
+                    rowCopyIsScaled = false;
+               } else {
+                    rowCopyIsScaled = true;
+               }
+          }
+#if 0
+          if (what == 63) {
+               int k = rowScale_ ? 1 : 0;
+               if (oldMatrix)
+                    k += 2;
+               scale_times[k]++;
+               if ((scale_times[0] + scale_times[1] + scale_times[2] + scale_times[3]) % 1000 == 0)
+                    printf("scale counts %d %d %d %d\n",
+                           scale_times[0], scale_times[1], scale_times[2], scale_times[3]);
+          }
+#endif
+          // do scaling if needed
+          if (!oldMatrix && scalingFlag_ < 0) {
+               if (scalingFlag_ < 0 && rowScale_) {
+                    //if (handler_->logLevel()>0)
+                    printf("How did we get scalingFlag_ %d and non NULL rowScale_? - switching off scaling\n",
+                           scalingFlag_);
+                    scalingFlag_ = 0;
+               }
+               delete [] rowScale_;
+               delete [] columnScale_;
+               rowScale_ = NULL;
+               columnScale_ = NULL;
+          }
+          inverseRowScale_ = NULL;
+          inverseColumnScale_ = NULL;
+          if (scalingFlag_ > 0 &&(specialOptions_ & 65536) != 0&&
+	      rowScale_&&rowScale_==savedRowScale_) 
+	    rowScale_=NULL;
+          if (scalingFlag_ > 0 && !rowScale_) {
+               if ((specialOptions_ & 65536) != 0) {
+                    assert (!rowScale_);
+                    rowScale_ = savedRowScale_;
+                    columnScale_ = savedColumnScale_;
+                    // put back original
+                    if (savedRowScale_) {
+                         inverseRowScale_ = savedRowScale_ + maximumInternalRows_;
+                         inverseColumnScale_ = savedColumnScale_ + maximumInternalColumns_;
+                         CoinMemcpyN(savedRowScale_ + 2 * maximumInternalRows_,
+                                     numberRows2, savedRowScale_);
+                         CoinMemcpyN(savedRowScale_ + 3 * maximumInternalRows_,
+                                     numberRows2, inverseRowScale_);
+                         CoinMemcpyN(savedColumnScale_ + 2 * maximumColumns_,
+                                     numberColumns_, savedColumnScale_);
+                         CoinMemcpyN(savedColumnScale_ + 3 * maximumColumns_,
+                                     numberColumns_, inverseColumnScale_);
+                    }
+               }
+               if (matrix_->scale(this))
+                    scalingFlag_ = -scalingFlag_; // not scaled after all
+               if (rowScale_ && automaticScale_) {
+		    if (!savedRowScale_) {
+		      inverseRowScale_ = rowScale_ + numberRows2;
+		      inverseColumnScale_ = columnScale_ + numberColumns_;
+		    }
+                    // try automatic scaling
+                    double smallestObj = 1.0e100;
+                    double largestObj = 0.0;
+                    double largestRhs = 0.0;
+                    const double * obj = objective();
+                    for (i = 0; i < numberColumns_; i++) {
+                         double value = fabs(obj[i]);
+                         value *= columnScale_[i];
+                         if (value && columnLower_[i] != columnUpper_[i]) {
+                              smallestObj = CoinMin(smallestObj, value);
+                              largestObj = CoinMax(largestObj, value);
+                         }
+                         if (columnLower_[i] > 0.0 || columnUpper_[i] < 0.0) {
+                              double scale = 1.0 * inverseColumnScale_[i];
+                              //printf("%d %g %g %g %g\n",i,scale,lower_[i],upper_[i],largestRhs);
+                              if (columnLower_[i] > 0)
+                                   largestRhs = CoinMax(largestRhs, columnLower_[i] * scale);
+                              if (columnUpper_[i] < 0.0)
+                                   largestRhs = CoinMax(largestRhs, -columnUpper_[i] * scale);
+                         }
+                    }
+                    for (i = 0; i < numberRows_; i++) {
+                         if (rowLower_[i] > 0.0 || rowUpper_[i] < 0.0) {
+                              double scale = rowScale_[i];
+                              //printf("%d %g %g %g %g\n",i,scale,lower_[i],upper_[i],largestRhs);
+                              if (rowLower_[i] > 0)
+                                   largestRhs = CoinMax(largestRhs, rowLower_[i] * scale);
+                              if (rowUpper_[i] < 0.0)
+                                   largestRhs = CoinMax(largestRhs, -rowUpper_[i] * scale);
+                         }
+                    }
+                    COIN_DETAIL_PRINT(printf("small obj %g, large %g - rhs %g\n", smallestObj, largestObj, largestRhs));
+                    bool scalingDone = false;
+                    // look at element range
+                    double smallestNegative;
+                    double largestNegative;
+                    double smallestPositive;
+                    double largestPositive;
+                    matrix_->rangeOfElements(smallestNegative, largestNegative,
+                                             smallestPositive, largestPositive);
+                    smallestPositive = CoinMin(fabs(smallestNegative), smallestPositive);
+                    largestPositive = CoinMax(fabs(largestNegative), largestPositive);
+                    if (largestObj) {
+                         double ratio = largestObj / smallestObj;
+                         double scale = 1.0;
+                         if (ratio < 1.0e8) {
+                              // reasonable
+                              if (smallestObj < 1.0e-4) {
+                                   // may as well scale up
+                                   scalingDone = true;
+                                   scale = 1.0e-3 / smallestObj;
+                              } else if (largestObj < 1.0e6 || (algorithm_ > 0 && largestObj < 1.0e-4 * infeasibilityCost_)) {
+                                   //done=true;
+                              } else {
+                                   scalingDone = true;
+                                   if (algorithm_ < 0) {
+                                        scale = 1.0e6 / largestObj;
+                                   } else {
+                                        scale = CoinMax(1.0e6, 1.0e-4 * infeasibilityCost_) / largestObj;
+                                   }
+                              }
+                         } else if (ratio < 1.0e12) {
+                              // not so good
+                              if (smallestObj < 1.0e-7) {
+                                   // may as well scale up
+                                   scalingDone = true;
+                                   scale = 1.0e-6 / smallestObj;
+                              } else if (largestObj < 1.0e7 || (algorithm_ > 0 && largestObj < 1.0e-3 * infeasibilityCost_)) {
+                                   //done=true;
+                              } else {
+                                   scalingDone = true;
+                                   if (algorithm_ < 0) {
+                                        scale = 1.0e7 / largestObj;
+                                   } else {
+                                        scale = CoinMax(1.0e7, 1.0e-3 * infeasibilityCost_) / largestObj;
+                                   }
+                              }
+                         } else {
+                              // Really nasty problem
+                              if (smallestObj < 1.0e-8) {
+                                   // may as well scale up
+                                   scalingDone = true;
+                                   scale = 1.0e-7 / smallestObj;
+                                   largestObj *= scale;
+                              }
+                              if (largestObj < 1.0e7 || (algorithm_ > 0 && largestObj < 1.0e-3 * infeasibilityCost_)) {
+                                   //done=true;
+                              } else {
+                                   scalingDone = true;
+                                   if (algorithm_ < 0) {
+                                        scale = 1.0e7 / largestObj;
+                                   } else {
+                                        scale = CoinMax(1.0e7, 1.0e-3 * infeasibilityCost_) / largestObj;
+                                   }
+                              }
+                         }
+                         objectiveScale_ = scale;
+                    }
+                    if (largestRhs > 1.0e12) {
+                         scalingDone = true;
+                         rhsScale_ = 1.0e9 / largestRhs;
+                    } else if (largestPositive > 1.0e-14 * smallestPositive && largestRhs > 1.0e6) {
+                         scalingDone = true;
+                         rhsScale_ = 1.0e6 / largestRhs;
+                    } else {
+                         rhsScale_ = 1.0;
+                    }
+                    if (scalingDone) {
+                         handler_->message(CLP_RIM_SCALE, messages_)
+                                   << objectiveScale_ << rhsScale_
+                                   << CoinMessageEol;
+                    }
+               }
+          } else if (makeRowCopy && scalingFlag_ > 0 && !rowCopyIsScaled) {
+               matrix_->scaleRowCopy(this);
+          }
+          if (rowScale_ && !savedRowScale_) {
+               inverseRowScale_ = rowScale_ + numberRows2;
+               inverseColumnScale_ = columnScale_ + numberColumns_;
+          }
+          // See if we can try for faster row copy
+          if (makeRowCopy && !oldMatrix) {
+               ClpPackedMatrix* clpMatrix =
+                    dynamic_cast< ClpPackedMatrix*>(matrix_);
+               if (clpMatrix && numberThreads_)
+                    clpMatrix->specialRowCopy(this, rowCopy_);
+               if (clpMatrix)
+                    clpMatrix->specialColumnCopy(this);
+          }
+     }
+     if (what == 63) {
+#if 0
+          {
+               x_gaps[0]++;
+               ClpPackedMatrix* clpMatrix =
+               dynamic_cast< ClpPackedMatrix*>(matrix_);
+               if (clpMatrix) {
+                    if (!clpMatrix->getPackedMatrix()->hasGaps())
+                         x_gaps[1]++;
+                    if ((clpMatrix->flags() & 2) == 0)
+                         x_gaps[3]++;
+               } else {
+                    x_gaps[2]++;
+               }
+               if ((x_gaps[0] % 1000) == 0)
+                    printf("create %d times, no gaps %d times - not clp %d times - flagged %d\n",
+                           x_gaps[0], x_gaps[1], x_gaps[2], x_gaps[3]);
+          }
+#endif
+          if (newArrays && (specialOptions_ & 65536) == 0) {
+               delete [] cost_;
+               cost_ = new double[2*numberTotal];
+               delete [] lower_;
+               delete [] upper_;
+               lower_ = new double[numberTotal];
+               upper_ = new double[numberTotal];
+               delete [] dj_;
+               dj_ = new double[numberTotal];
+               delete [] solution_;
+               solution_ = new double[numberTotal];
+          }
+          reducedCostWork_ = dj_;
+          rowReducedCost_ = dj_ + numberColumns_;
+          columnActivityWork_ = solution_;
+          rowActivityWork_ = solution_ + numberColumns_;
+          objectiveWork_ = cost_;
+          rowObjectiveWork_ = cost_ + numberColumns_;
+          rowLowerWork_ = lower_ + numberColumns_;
+          columnLowerWork_ = lower_;
+          rowUpperWork_ = upper_ + numberColumns_;
+          columnUpperWork_ = upper_;
+     }
+     if ((what & 4) != 0) {
+          double direction = optimizationDirection_ * objectiveScale_;
+          const double * obj = objective();
+          const double * rowScale = rowScale_;
+          const double * columnScale = columnScale_;
+          // and also scale by scale factors
+          if (rowScale) {
+               if (rowObjective_) {
+                    for (i = 0; i < numberRows_; i++)
+                         rowObjectiveWork_[i] = rowObjective_[i] * direction / rowScale[i];
+               } else {
+                    memset(rowObjectiveWork_, 0, numberRows_ * sizeof(double));
+               }
+               // If scaled then do all columns later in one loop
+               if (what != 63) {
+                    for (i = 0; i < numberColumns_; i++) {
+                         CoinAssert(fabs(obj[i]) < 1.0e25);
+                         objectiveWork_[i] = obj[i] * direction * columnScale[i];
+                    }
+               }
+          } else {
+               if (rowObjective_) {
+                    for (i = 0; i < numberRows_; i++)
+                         rowObjectiveWork_[i] = rowObjective_[i] * direction;
+               } else {
+                    memset(rowObjectiveWork_, 0, numberRows_ * sizeof(double));
+               }
+               for (i = 0; i < numberColumns_; i++) {
+                    CoinAssert(fabs(obj[i]) < 1.0e25);
+                    objectiveWork_[i] = obj[i] * direction;
+               }
+          }
+     }
+     if ((what & 1) != 0) {
+          const double * rowScale = rowScale_;
+          // clean up any mismatches on infinity
+          // and fix any variables with tiny gaps
+          double primalTolerance = dblParam_[ClpPrimalTolerance];
+          if(rowScale) {
+               // If scaled then do all columns later in one loop
+               if (what != 63) {
+                    const double * inverseScale = inverseColumnScale_;
+                    for (i = 0; i < numberColumns_; i++) {
+                         double multiplier = rhsScale_ * inverseScale[i];
+                         double lowerValue = columnLower_[i];
+                         double upperValue = columnUpper_[i];
+                         if (lowerValue > -1.0e20) {
+                              columnLowerWork_[i] = lowerValue * multiplier;
+                              if (upperValue >= 1.0e20) {
+                                   columnUpperWork_[i] = COIN_DBL_MAX;
+                              } else {
+                                   columnUpperWork_[i] = upperValue * multiplier;
+                                   if (fabs(columnUpperWork_[i] - columnLowerWork_[i]) <= primalTolerance) {
+                                        if (columnLowerWork_[i] >= 0.0) {
+                                             columnUpperWork_[i] = columnLowerWork_[i];
+                                        } else if (columnUpperWork_[i] <= 0.0) {
+                                             columnLowerWork_[i] = columnUpperWork_[i];
+                                        } else {
+                                             columnUpperWork_[i] = 0.0;
+                                             columnLowerWork_[i] = 0.0;
+                                        }
+                                   }
+                              }
+                         } else if (upperValue < 1.0e20) {
+                              columnLowerWork_[i] = -COIN_DBL_MAX;
+                              columnUpperWork_[i] = upperValue * multiplier;
+                         } else {
+                              // free
+                              columnLowerWork_[i] = -COIN_DBL_MAX;
+                              columnUpperWork_[i] = COIN_DBL_MAX;
+                         }
+                    }
+               }
+               for (i = 0; i < numberRows_; i++) {
+                    double multiplier = rhsScale_ * rowScale[i];
+                    double lowerValue = rowLower_[i];
+                    double upperValue = rowUpper_[i];
+                    if (lowerValue > -1.0e20) {
+                         rowLowerWork_[i] = lowerValue * multiplier;
+                         if (upperValue >= 1.0e20) {
+                              rowUpperWork_[i] = COIN_DBL_MAX;
+                         } else {
+                              rowUpperWork_[i] = upperValue * multiplier;
+                              if (fabs(rowUpperWork_[i] - rowLowerWork_[i]) <= primalTolerance) {
+                                   if (rowLowerWork_[i] >= 0.0) {
+                                        rowUpperWork_[i] = rowLowerWork_[i];
+                                   } else if (rowUpperWork_[i] <= 0.0) {
+                                        rowLowerWork_[i] = rowUpperWork_[i];
+                                   } else {
+                                        rowUpperWork_[i] = 0.0;
+                                        rowLowerWork_[i] = 0.0;
+                                   }
+                              }
+                         }
+                    } else if (upperValue < 1.0e20) {
+                         rowLowerWork_[i] = -COIN_DBL_MAX;
+                         rowUpperWork_[i] = upperValue * multiplier;
+                    } else {
+                         // free
+                         rowLowerWork_[i] = -COIN_DBL_MAX;
+                         rowUpperWork_[i] = COIN_DBL_MAX;
+                    }
+               }
+          } else if (rhsScale_ != 1.0) {
+               for (i = 0; i < numberColumns_; i++) {
+                    double lowerValue = columnLower_[i];
+                    double upperValue = columnUpper_[i];
+                    if (lowerValue > -1.0e20) {
+                         columnLowerWork_[i] = lowerValue * rhsScale_;
+                         if (upperValue >= 1.0e20) {
+                              columnUpperWork_[i] = COIN_DBL_MAX;
+                         } else {
+                              columnUpperWork_[i] = upperValue * rhsScale_;
+                              if (fabs(columnUpperWork_[i] - columnLowerWork_[i]) <= primalTolerance) {
+                                   if (columnLowerWork_[i] >= 0.0) {
+                                        columnUpperWork_[i] = columnLowerWork_[i];
+                                   } else if (columnUpperWork_[i] <= 0.0) {
+                                        columnLowerWork_[i] = columnUpperWork_[i];
+                                   } else {
+                                        columnUpperWork_[i] = 0.0;
+                                        columnLowerWork_[i] = 0.0;
+                                   }
+                              }
+                         }
+                    } else if (upperValue < 1.0e20) {
+                         columnLowerWork_[i] = -COIN_DBL_MAX;
+                         columnUpperWork_[i] = upperValue * rhsScale_;
+                    } else {
+                         // free
+                         columnLowerWork_[i] = -COIN_DBL_MAX;
+                         columnUpperWork_[i] = COIN_DBL_MAX;
+                    }
+               }
+               for (i = 0; i < numberRows_; i++) {
+                    double lowerValue = rowLower_[i];
+                    double upperValue = rowUpper_[i];
+                    if (lowerValue > -1.0e20) {
+                         rowLowerWork_[i] = lowerValue * rhsScale_;
+                         if (upperValue >= 1.0e20) {
+                              rowUpperWork_[i] = COIN_DBL_MAX;
+                         } else {
+                              rowUpperWork_[i] = upperValue * rhsScale_;
+                              if (fabs(rowUpperWork_[i] - rowLowerWork_[i]) <= primalTolerance) {
+                                   if (rowLowerWork_[i] >= 0.0) {
+                                        rowUpperWork_[i] = rowLowerWork_[i];
+                                   } else if (rowUpperWork_[i] <= 0.0) {
+                                        rowLowerWork_[i] = rowUpperWork_[i];
+                                   } else {
+                                        rowUpperWork_[i] = 0.0;
+                                        rowLowerWork_[i] = 0.0;
+                                   }
+                              }
+                         }
+                    } else if (upperValue < 1.0e20) {
+                         rowLowerWork_[i] = -COIN_DBL_MAX;
+                         rowUpperWork_[i] = upperValue * rhsScale_;
+                    } else {
+                         // free
+                         rowLowerWork_[i] = -COIN_DBL_MAX;
+                         rowUpperWork_[i] = COIN_DBL_MAX;
+                    }
+               }
+          } else {
+               for (i = 0; i < numberColumns_; i++) {
+                    double lowerValue = columnLower_[i];
+                    double upperValue = columnUpper_[i];
+                    if (lowerValue > -1.0e20) {
+                         columnLowerWork_[i] = lowerValue;
+                         if (upperValue >= 1.0e20) {
+                              columnUpperWork_[i] = COIN_DBL_MAX;
+                         } else {
+                              columnUpperWork_[i] = upperValue;
+                              if (fabs(columnUpperWork_[i] - columnLowerWork_[i]) <= primalTolerance) {
+                                   if (columnLowerWork_[i] >= 0.0) {
+                                        columnUpperWork_[i] = columnLowerWork_[i];
+                                   } else if (columnUpperWork_[i] <= 0.0) {
+                                        columnLowerWork_[i] = columnUpperWork_[i];
+                                   } else {
+                                        columnUpperWork_[i] = 0.0;
+                                        columnLowerWork_[i] = 0.0;
+                                   }
+                              }
+                         }
+                    } else if (upperValue < 1.0e20) {
+                         columnLowerWork_[i] = -COIN_DBL_MAX;
+                         columnUpperWork_[i] = upperValue;
+                    } else {
+                         // free
+                         columnLowerWork_[i] = -COIN_DBL_MAX;
+                         columnUpperWork_[i] = COIN_DBL_MAX;
+                    }
+               }
+               for (i = 0; i < numberRows_; i++) {
+                    double lowerValue = rowLower_[i];
+                    double upperValue = rowUpper_[i];
+                    if (lowerValue > -1.0e20) {
+                         rowLowerWork_[i] = lowerValue;
+                         if (upperValue >= 1.0e20) {
+                              rowUpperWork_[i] = COIN_DBL_MAX;
+                         } else {
+                              rowUpperWork_[i] = upperValue;
+                              if (fabs(rowUpperWork_[i] - rowLowerWork_[i]) <= primalTolerance) {
+                                   if (rowLowerWork_[i] >= 0.0) {
+                                        rowUpperWork_[i] = rowLowerWork_[i];
+                                   } else if (rowUpperWork_[i] <= 0.0) {
+                                        rowLowerWork_[i] = rowUpperWork_[i];
+                                   } else {
+                                        rowUpperWork_[i] = 0.0;
+                                        rowLowerWork_[i] = 0.0;
+                                   }
+                              }
+                         }
+                    } else if (upperValue < 1.0e20) {
+                         rowLowerWork_[i] = -COIN_DBL_MAX;
+                         rowUpperWork_[i] = upperValue;
+                    } else {
+                         // free
+                         rowLowerWork_[i] = -COIN_DBL_MAX;
+                         rowUpperWork_[i] = COIN_DBL_MAX;
+                    }
+               }
+          }
+     }
+     if (what == 63) {
+          // move information to work arrays
+          double direction = optimizationDirection_;
+          // direction is actually scale out not scale in
+          if (direction)
+               direction = 1.0 / direction;
+          if (direction != 1.0) {
+               // reverse all dual signs
+               for (i = 0; i < numberColumns_; i++)
+                    reducedCost_[i] *= direction;
+               for (i = 0; i < numberRows_; i++)
+                    dual_[i] *= direction;
+          }
+          for (i = 0; i < numberRows_ + numberColumns_; i++) {
+               setFakeBound(i, noFake);
+          }
+          if (rowScale_) {
+               const double * obj = objective();
+               double direction = optimizationDirection_ * objectiveScale_;
+               // clean up any mismatches on infinity
+               // and fix any variables with tiny gaps
+               double primalTolerance = dblParam_[ClpPrimalTolerance];
+               // on entry
+               const double * inverseScale = inverseColumnScale_;
+               for (i = 0; i < numberColumns_; i++) {
+                    CoinAssert(fabs(obj[i]) < 1.0e25);
+                    double scaleFactor = columnScale_[i];
+                    double multiplier = rhsScale_ * inverseScale[i];
+                    scaleFactor *= direction;
+                    objectiveWork_[i] = obj[i] * scaleFactor;
+                    reducedCostWork_[i] = reducedCost_[i] * scaleFactor;
+                    double lowerValue = columnLower_[i];
+                    double upperValue = columnUpper_[i];
+                    if (lowerValue > -1.0e20) {
+                         columnLowerWork_[i] = lowerValue * multiplier;
+                         if (upperValue >= 1.0e20) {
+                              columnUpperWork_[i] = COIN_DBL_MAX;
+                         } else {
+                              columnUpperWork_[i] = upperValue * multiplier;
+                              if (fabs(columnUpperWork_[i] - columnLowerWork_[i]) <= primalTolerance) {
+                                   if (columnLowerWork_[i] >= 0.0) {
+                                        columnUpperWork_[i] = columnLowerWork_[i];
+                                   } else if (columnUpperWork_[i] <= 0.0) {
+                                        columnLowerWork_[i] = columnUpperWork_[i];
+                                   } else {
+                                        columnUpperWork_[i] = 0.0;
+                                        columnLowerWork_[i] = 0.0;
+                                   }
+                              }
+                         }
+                    } else if (upperValue < 1.0e20) {
+                         columnLowerWork_[i] = -COIN_DBL_MAX;
+                         columnUpperWork_[i] = upperValue * multiplier;
+                    } else {
+                         // free
+                         columnLowerWork_[i] = -COIN_DBL_MAX;
+                         columnUpperWork_[i] = COIN_DBL_MAX;
+                    }
+                    double value = columnActivity_[i] * multiplier;
+                    if (fabs(value) > 1.0e20) {
+                         //printf("bad value of %g for column %d\n",value,i);
+                         setColumnStatus(i, superBasic);
+                         if (columnUpperWork_[i] < 0.0) {
+                              value = columnUpperWork_[i];
+                         } else if (columnLowerWork_[i] > 0.0) {
+                              value = columnLowerWork_[i];
+                         } else {
+                              value = 0.0;
+                         }
+                    }
+                    columnActivityWork_[i] = value;
+               }
+               inverseScale = inverseRowScale_;
+               for (i = 0; i < numberRows_; i++) {
+                    dual_[i] *= inverseScale[i];
+                    dual_[i] *= objectiveScale_;
+                    rowReducedCost_[i] = dual_[i];
+                    double multiplier = rhsScale_ * rowScale_[i];
+                    double value = rowActivity_[i] * multiplier;
+                    if (fabs(value) > 1.0e20) {
+                         //printf("bad value of %g for row %d\n",value,i);
+                         setRowStatus(i, superBasic);
+                         if (rowUpperWork_[i] < 0.0) {
+                              value = rowUpperWork_[i];
+                         } else if (rowLowerWork_[i] > 0.0) {
+                              value = rowLowerWork_[i];
+                         } else {
+                              value = 0.0;
+                         }
+                    }
+                    rowActivityWork_[i] = value;
+               }
+          } else if (objectiveScale_ != 1.0 || rhsScale_ != 1.0) {
+               // on entry
+               for (i = 0; i < numberColumns_; i++) {
+                    double value = columnActivity_[i];
+                    value *= rhsScale_;
+                    if (fabs(value) > 1.0e20) {
+                         //printf("bad value of %g for column %d\n",value,i);
+                         setColumnStatus(i, superBasic);
+                         if (columnUpperWork_[i] < 0.0) {
+                              value = columnUpperWork_[i];
+                         } else if (columnLowerWork_[i] > 0.0) {
+                              value = columnLowerWork_[i];
+                         } else {
+                              value = 0.0;
+                         }
+                    }
+                    columnActivityWork_[i] = value;
+                    reducedCostWork_[i] = reducedCost_[i] * objectiveScale_;
+               }
+               for (i = 0; i < numberRows_; i++) {
+                    double value = rowActivity_[i];
+                    value *= rhsScale_;
+                    if (fabs(value) > 1.0e20) {
+                         //printf("bad value of %g for row %d\n",value,i);
+                         setRowStatus(i, superBasic);
+                         if (rowUpperWork_[i] < 0.0) {
+                              value = rowUpperWork_[i];
+                         } else if (rowLowerWork_[i] > 0.0) {
+                              value = rowLowerWork_[i];
+                         } else {
+                              value = 0.0;
+                         }
+                    }
+                    rowActivityWork_[i] = value;
+                    dual_[i] *= objectiveScale_;
+                    rowReducedCost_[i] = dual_[i];
+               }
+          } else {
+               // on entry
+               for (i = 0; i < numberColumns_; i++) {
+                    double value = columnActivity_[i];
+                    if (fabs(value) > 1.0e20) {
+                         //printf("bad value of %g for column %d\n",value,i);
+                         setColumnStatus(i, superBasic);
+                         if (columnUpperWork_[i] < 0.0) {
+                              value = columnUpperWork_[i];
+                         } else if (columnLowerWork_[i] > 0.0) {
+                              value = columnLowerWork_[i];
+                         } else {
+                              value = 0.0;
+                         }
+                    }
+                    columnActivityWork_[i] = value;
+                    reducedCostWork_[i] = reducedCost_[i];
+               }
+               for (i = 0; i < numberRows_; i++) {
+                    double value = rowActivity_[i];
+                    if (fabs(value) > 1.0e20) {
+                         //printf("bad value of %g for row %d\n",value,i);
+                         setRowStatus(i, superBasic);
+                         if (rowUpperWork_[i] < 0.0) {
+                              value = rowUpperWork_[i];
+                         } else if (rowLowerWork_[i] > 0.0) {
+                              value = rowLowerWork_[i];
+                         } else {
+                              value = 0.0;
+                         }
+                    }
+                    rowActivityWork_[i] = value;
+                    rowReducedCost_[i] = dual_[i];
+               }
+          }
+     }
+
+     if (what == 63 && doSanityCheck) {
+          // check rim of problem okay
+          if (!sanityCheck())
+               goodMatrix = false;
+     }
+     // we need to treat matrix as if each element by rowScaleIn and columnScaleout??
+     // maybe we need to move scales to SimplexModel for factorization?
+     if ((what == 63 && !pivotVariable_) || (newArrays && !keepPivots)) {
+          delete [] pivotVariable_;
+          pivotVariable_ = new int[numberRows2];
+          for (int i = 0; i < numberRows2; i++)
+               pivotVariable_[i] = -1;
+     } else if (what == 63 && !keepPivots) {
+          // just reset
+          for (int i = 0; i < numberRows2; i++)
+               pivotVariable_[i] = -1;
+     } else if (what == 63) {
+          // check pivots
+          for (int i = 0; i < numberRows2; i++) {
+               int iSequence = pivotVariable_[i];
+               if (iSequence<0||(iSequence < numberRows_ + numberColumns_ &&
+				 getStatus(iSequence) != basic)) {
+                    keepPivots = false;
+                    break;
+               }
+          }
+          if (!keepPivots) {
+               // reset
+               for (int i = 0; i < numberRows2; i++)
+                    pivotVariable_[i] = -1;
+          } else {
+               // clean
+               for (int i = 0; i < numberColumns_ + numberRows_; i++) {
+                    Status status = getStatus(i);
+                    if (status != basic) {
+                         if (upper_[i] == lower_[i]) {
+                              setStatus(i, isFixed);
+                              solution_[i] = lower_[i];
+                         } else if (status == atLowerBound) {
+                              if (lower_[i] > -1.0e20) {
+                                   solution_[i] = lower_[i];
+                              } else {
+                                   //printf("seq %d at lower of %g\n",i,lower_[i]);
+                                   if (upper_[i] < 1.0e20) {
+                                        solution_[i] = upper_[i];
+                                        setStatus(i, atUpperBound);
+                                   } else {
+                                        setStatus(i, isFree);
+                                   }
+                              }
+                         } else if (status == atUpperBound) {
+                              if (upper_[i] < 1.0e20) {
+                                   solution_[i] = upper_[i];
+                              } else {
+                                   //printf("seq %d at upper of %g\n",i,upper_[i]);
+                                   if (lower_[i] > -1.0e20) {
+                                        solution_[i] = lower_[i];
+                                        setStatus(i, atLowerBound);
+                                   } else {
+                                        setStatus(i, isFree);
+                                   }
+                              }
+                         } else if (status == isFixed && upper_[i] > lower_[i]) {
+                              // was fixed - not now
+                              if (solution_[i] <= lower_[i]) {
+                                   setStatus(i, atLowerBound);
+                              } else if (solution_[i] >= upper_[i]) {
+                                   setStatus(i, atUpperBound);
+                              } else {
+                                   setStatus(i, superBasic);
+                              }
+                         }
+                    }
+               }
+          }
+     }
+
+     if (what == 63) {
+          if (newArrays) {
+               // get some arrays
+               int iRow, iColumn;
+               // these are "indexed" arrays so we always know where nonzeros are
+               /**********************************************************
+               rowArray_[3] is long enough for rows+columns
+               rowArray_[1] is long enough for max(rows,columns)
+               *********************************************************/
+               for (iRow = 0; iRow < 4; iRow++) {
+                    int length = numberRows2 + factorization_->maximumPivots();
+                    if (iRow == 3 || objective_->type() > 1)
+                         length += numberColumns_;
+                    else if (iRow == 1)
+                         length = CoinMax(length, numberColumns_);
+                    if ((specialOptions_ & 65536) == 0 || !rowArray_[iRow]) {
+                         delete rowArray_[iRow];
+                         rowArray_[iRow] = new CoinIndexedVector();
+                    }
+                    rowArray_[iRow]->reserve(length);
+               }
+
+               for (iColumn = 0; iColumn < 2; iColumn++) {
+                    if ((specialOptions_ & 65536) == 0 || !columnArray_[iColumn]) {
+                         delete columnArray_[iColumn];
+                         columnArray_[iColumn] = new CoinIndexedVector();
+                    }
+		    columnArray_[iColumn]->reserve(numberColumns_+numberRows2);
+               }
+          } else {
+               int iRow, iColumn;
+               for (iRow = 0; iRow < 4; iRow++) {
+                    int length = numberRows2 + factorization_->maximumPivots();
+                    if (iRow == 3 || objective_->type() > 1)
+                         length += numberColumns_;
+                    if(rowArray_[iRow]->capacity() >= length) {
+                         rowArray_[iRow]->clear();
+                    } else {
+                         // model size or maxinv changed
+                         rowArray_[iRow]->reserve(length);
+                    }
+#ifndef NDEBUG
+                    rowArray_[iRow]->checkClear();
+#endif
+               }
+
+               for (iColumn = 0; iColumn < 2; iColumn++) {
+                    int length = numberColumns_;
+                    if (iColumn)
+                         length = CoinMax(numberRows2, numberColumns_);
+                    if(columnArray_[iColumn]->capacity() >= length) {
+                         columnArray_[iColumn]->clear();
+                    } else {
+                         // model size or maxinv changed
+                         columnArray_[iColumn]->reserve(length);
+                    }
+#ifndef NDEBUG
+                    columnArray_[iColumn]->checkClear();
+#endif
+               }
+          }
+     }
+     if (problemStatus_ == 10) {
+          problemStatus_ = -1;
+          handler_->setLogLevel(saveLevel); // switch back messages
+     }
+     if ((what & 5) != 0)
+          matrix_->generalExpanded(this, 9, what); // update costs and bounds if necessary
+     if (goodMatrix && (specialOptions_ & 65536) != 0) {
+          int save = maximumColumns_ + maximumRows_;
+          CoinMemcpyN(cost_, numberTotal, cost_ + save);
+          CoinMemcpyN(lower_, numberTotal, lower_ + save);
+          CoinMemcpyN(upper_, numberTotal, upper_ + save);
+          CoinMemcpyN(dj_, numberTotal, dj_ + save);
+          CoinMemcpyN(solution_, numberTotal, solution_ + save);
+          if (rowScale_ && !savedRowScale_) {
+               double * temp;
+               temp = new double [4*maximumRows_];
+               CoinFillN(temp, 4 * maximumRows_, 1.0);
+               CoinMemcpyN(rowScale_, numberRows2, temp);
+               CoinMemcpyN(rowScale_ + numberRows2, numberRows2, temp + maximumRows_);
+               CoinMemcpyN(rowScale_, numberRows2, temp + 2 * maximumRows_);
+               CoinMemcpyN(rowScale_ + numberRows2, numberRows2, temp + 3 * maximumRows_);
+               delete [] rowScale_;
+               savedRowScale_ = temp;
+               rowScale_ = savedRowScale_;
+               inverseRowScale_ = savedRowScale_ + maximumInternalRows_;
+               temp = new double [4*maximumColumns_];
+               CoinFillN(temp, 4 * maximumColumns_, 1.0);
+               CoinMemcpyN(columnScale_, numberColumns_, temp);
+               CoinMemcpyN(columnScale_ + numberColumns_, numberColumns_, temp + maximumColumns_);
+               CoinMemcpyN(columnScale_, numberColumns_, temp + 2 * maximumColumns_);
+               CoinMemcpyN(columnScale_ + numberColumns_, numberColumns_, temp + 3 * maximumColumns_);
+               delete [] columnScale_;
+               savedColumnScale_ = temp;
+               columnScale_ = savedColumnScale_;
+               inverseColumnScale_ = savedColumnScale_ + maximumInternalColumns_;
+          }
+     }
+#ifdef CLP_USER_DRIVEN
+     eventHandler_->event(ClpEventHandler::endOfCreateRim);
+#endif
+     return goodMatrix;
+}
+// Does rows and columns
+void
+ClpSimplex::createRim1(bool initial)
+{
+     int i;
+     int numberRows2 = numberRows_ + numberExtraRows_;
+     int numberTotal = numberRows2 + numberColumns_;
+     if ((specialOptions_ & 65536) != 0 && true) {
+          assert (!initial);
+          int save = maximumColumns_ + maximumRows_;
+          CoinMemcpyN(lower_ + save, numberTotal, lower_);
+          CoinMemcpyN(upper_ + save, numberTotal, upper_);
+          return;
+     }
+     const double * rowScale = rowScale_;
+     // clean up any mismatches on infinity
+     // and fix any variables with tiny gaps
+     double primalTolerance = dblParam_[ClpPrimalTolerance];
+     if(rowScale) {
+          // If scaled then do all columns later in one loop
+          if (!initial) {
+               const double * inverseScale = inverseColumnScale_;
+               for (i = 0; i < numberColumns_; i++) {
+                    double multiplier = rhsScale_ * inverseScale[i];
+                    double lowerValue = columnLower_[i];
+                    double upperValue = columnUpper_[i];
+                    if (lowerValue > -1.0e20) {
+                         columnLowerWork_[i] = lowerValue * multiplier;
+                         if (upperValue >= 1.0e20) {
+                              columnUpperWork_[i] = COIN_DBL_MAX;
+                         } else {
+                              columnUpperWork_[i] = upperValue * multiplier;
+                              if (fabs(columnUpperWork_[i] - columnLowerWork_[i]) <= primalTolerance) {
+                                   if (columnLowerWork_[i] >= 0.0) {
+                                        columnUpperWork_[i] = columnLowerWork_[i];
+                                   } else if (columnUpperWork_[i] <= 0.0) {
+                                        columnLowerWork_[i] = columnUpperWork_[i];
+                                   } else {
+                                        columnUpperWork_[i] = 0.0;
+                                        columnLowerWork_[i] = 0.0;
+                                   }
+                              }
+                         }
+                    } else if (upperValue < 1.0e20) {
+                         columnLowerWork_[i] = -COIN_DBL_MAX;
+                         columnUpperWork_[i] = upperValue * multiplier;
+                    } else {
+                         // free
+                         columnLowerWork_[i] = -COIN_DBL_MAX;
+                         columnUpperWork_[i] = COIN_DBL_MAX;
+                    }
+               }
+          }
+          for (i = 0; i < numberRows_; i++) {
+               double multiplier = rhsScale_ * rowScale[i];
+               double lowerValue = rowLower_[i];
+               double upperValue = rowUpper_[i];
+               if (lowerValue > -1.0e20) {
+                    rowLowerWork_[i] = lowerValue * multiplier;
+                    if (upperValue >= 1.0e20) {
+                         rowUpperWork_[i] = COIN_DBL_MAX;
+                    } else {
+                         rowUpperWork_[i] = upperValue * multiplier;
+                         if (fabs(rowUpperWork_[i] - rowLowerWork_[i]) <= primalTolerance) {
+                              if (rowLowerWork_[i] >= 0.0) {
+                                   rowUpperWork_[i] = rowLowerWork_[i];
+                              } else if (rowUpperWork_[i] <= 0.0) {
+                                   rowLowerWork_[i] = rowUpperWork_[i];
+                              } else {
+                                   rowUpperWork_[i] = 0.0;
+                                   rowLowerWork_[i] = 0.0;
+                              }
+                         }
+                    }
+               } else if (upperValue < 1.0e20) {
+                    rowLowerWork_[i] = -COIN_DBL_MAX;
+                    rowUpperWork_[i] = upperValue * multiplier;
+               } else {
+                    // free
+                    rowLowerWork_[i] = -COIN_DBL_MAX;
+                    rowUpperWork_[i] = COIN_DBL_MAX;
+               }
+          }
+     } else if (rhsScale_ != 1.0) {
+          for (i = 0; i < numberColumns_; i++) {
+               double lowerValue = columnLower_[i];
+               double upperValue = columnUpper_[i];
+               if (lowerValue > -1.0e20) {
+                    columnLowerWork_[i] = lowerValue * rhsScale_;
+                    if (upperValue >= 1.0e20) {
+                         columnUpperWork_[i] = COIN_DBL_MAX;
+                    } else {
+                         columnUpperWork_[i] = upperValue * rhsScale_;
+                         if (fabs(columnUpperWork_[i] - columnLowerWork_[i]) <= primalTolerance) {
+                              if (columnLowerWork_[i] >= 0.0) {
+                                   columnUpperWork_[i] = columnLowerWork_[i];
+                              } else if (columnUpperWork_[i] <= 0.0) {
+                                   columnLowerWork_[i] = columnUpperWork_[i];
+                              } else {
+                                   columnUpperWork_[i] = 0.0;
+                                   columnLowerWork_[i] = 0.0;
+                              }
+                         }
+                    }
+               } else if (upperValue < 1.0e20) {
+                    columnLowerWork_[i] = -COIN_DBL_MAX;
+                    columnUpperWork_[i] = upperValue * rhsScale_;
+               } else {
+                    // free
+                    columnLowerWork_[i] = -COIN_DBL_MAX;
+                    columnUpperWork_[i] = COIN_DBL_MAX;
+               }
+          }
+          for (i = 0; i < numberRows_; i++) {
+               double lowerValue = rowLower_[i];
+               double upperValue = rowUpper_[i];
+               if (lowerValue > -1.0e20) {
+                    rowLowerWork_[i] = lowerValue * rhsScale_;
+                    if (upperValue >= 1.0e20) {
+                         rowUpperWork_[i] = COIN_DBL_MAX;
+                    } else {
+                         rowUpperWork_[i] = upperValue * rhsScale_;
+                         if (fabs(rowUpperWork_[i] - rowLowerWork_[i]) <= primalTolerance) {
+                              if (rowLowerWork_[i] >= 0.0) {
+                                   rowUpperWork_[i] = rowLowerWork_[i];
+                              } else if (rowUpperWork_[i] <= 0.0) {
+                                   rowLowerWork_[i] = rowUpperWork_[i];
+                              } else {
+                                   rowUpperWork_[i] = 0.0;
+                                   rowLowerWork_[i] = 0.0;
+                              }
+                         }
+                    }
+               } else if (upperValue < 1.0e20) {
+                    rowLowerWork_[i] = -COIN_DBL_MAX;
+                    rowUpperWork_[i] = upperValue * rhsScale_;
+               } else {
+                    // free
+                    rowLowerWork_[i] = -COIN_DBL_MAX;
+                    rowUpperWork_[i] = COIN_DBL_MAX;
+               }
+          }
+     } else {
+          for (i = 0; i < numberColumns_; i++) {
+               double lowerValue = columnLower_[i];
+               double upperValue = columnUpper_[i];
+               if (lowerValue > -1.0e20) {
+                    columnLowerWork_[i] = lowerValue;
+                    if (upperValue >= 1.0e20) {
+                         columnUpperWork_[i] = COIN_DBL_MAX;
+                    } else {
+                         columnUpperWork_[i] = upperValue;
+                         if (fabs(columnUpperWork_[i] - columnLowerWork_[i]) <= primalTolerance) {
+                              if (columnLowerWork_[i] >= 0.0) {
+                                   columnUpperWork_[i] = columnLowerWork_[i];
+                              } else if (columnUpperWork_[i] <= 0.0) {
+                                   columnLowerWork_[i] = columnUpperWork_[i];
+                              } else {
+                                   columnUpperWork_[i] = 0.0;
+                                   columnLowerWork_[i] = 0.0;
+                              }
+                         }
+                    }
+               } else if (upperValue < 1.0e20) {
+                    columnLowerWork_[i] = -COIN_DBL_MAX;
+                    columnUpperWork_[i] = upperValue;
+               } else {
+                    // free
+                    columnLowerWork_[i] = -COIN_DBL_MAX;
+                    columnUpperWork_[i] = COIN_DBL_MAX;
+               }
+          }
+          for (i = 0; i < numberRows_; i++) {
+               double lowerValue = rowLower_[i];
+               double upperValue = rowUpper_[i];
+               if (lowerValue > -1.0e20) {
+                    rowLowerWork_[i] = lowerValue;
+                    if (upperValue >= 1.0e20) {
+                         rowUpperWork_[i] = COIN_DBL_MAX;
+                    } else {
+                         rowUpperWork_[i] = upperValue;
+                         if (fabs(rowUpperWork_[i] - rowLowerWork_[i]) <= primalTolerance) {
+                              if (rowLowerWork_[i] >= 0.0) {
+                                   rowUpperWork_[i] = rowLowerWork_[i];
+                              } else if (rowUpperWork_[i] <= 0.0) {
+                                   rowLowerWork_[i] = rowUpperWork_[i];
+                              } else {
+                                   rowUpperWork_[i] = 0.0;
+                                   rowLowerWork_[i] = 0.0;
+                              }
+                         }
+                    }
+               } else if (upperValue < 1.0e20) {
+                    rowLowerWork_[i] = -COIN_DBL_MAX;
+                    rowUpperWork_[i] = upperValue;
+               } else {
+                    // free
+                    rowLowerWork_[i] = -COIN_DBL_MAX;
+                    rowUpperWork_[i] = COIN_DBL_MAX;
+               }
+          }
+     }
+#ifndef NDEBUG
+     if ((specialOptions_ & 65536) != 0 && false) {
+          assert (!initial);
+          int save = maximumColumns_ + maximumRows_;
+          for (int i = 0; i < numberTotal; i++) {
+               assert (fabs(lower_[i] - lower_[i+save]) < 1.0e-5);
+               assert (fabs(upper_[i] - upper_[i+save]) < 1.0e-5);
+          }
+     }
+#endif
+}
+// Does objective
+void
+ClpSimplex::createRim4(bool initial)
+{
+     int i;
+     int numberRows2 = numberRows_ + numberExtraRows_;
+     int numberTotal = numberRows2 + numberColumns_;
+     if ((specialOptions_ & 65536) != 0 && true) {
+          assert (!initial);
+          int save = maximumColumns_ + maximumRows_;
+          CoinMemcpyN(cost_ + save, numberTotal, cost_);
+          return;
+     }
+     double direction = optimizationDirection_ * objectiveScale_;
+     const double * obj = objective();
+     const double * rowScale = rowScale_;
+     const double * columnScale = columnScale_;
+     // and also scale by scale factors
+     if (rowScale) {
+          if (rowObjective_) {
+               for (i = 0; i < numberRows_; i++)
+                    rowObjectiveWork_[i] = rowObjective_[i] * direction / rowScale[i];
+          } else {
+               memset(rowObjectiveWork_, 0, numberRows_ * sizeof(double));
+          }
+          // If scaled then do all columns later in one loop
+          if (!initial) {
+               for (i = 0; i < numberColumns_; i++) {
+                    CoinAssert(fabs(obj[i]) < 1.0e25);
+                    objectiveWork_[i] = obj[i] * direction * columnScale[i];
+               }
+          }
+     } else {
+          if (rowObjective_) {
+               for (i = 0; i < numberRows_; i++)
+                    rowObjectiveWork_[i] = rowObjective_[i] * direction;
+          } else {
+               memset(rowObjectiveWork_, 0, numberRows_ * sizeof(double));
+          }
+          for (i = 0; i < numberColumns_; i++) {
+               CoinAssert(fabs(obj[i]) < 1.0e25);
+               objectiveWork_[i] = obj[i] * direction;
+          }
+     }
+}
+// Does rows and columns and objective
+void
+ClpSimplex::createRim5(bool initial)
+{
+     createRim4(initial);
+     createRim1(initial);
+}
+void
+ClpSimplex::deleteRim(int getRidOfFactorizationData)
+{
+     // Just possible empty problem
+     int numberRows = numberRows_;
+     int numberColumns = numberColumns_;
+     if (!numberRows || !numberColumns) {
+          numberRows = 0;
+          if (objective_->type() < 2)
+               numberColumns = 0;
+     }
+     int i;
+     if (problemStatus_ != 1 && problemStatus_ != 2) {
+          delete [] ray_;
+          ray_ = NULL;
+     }
+     // set upperOut_ to furthest away from bound so can use in dual for dualBound_
+     upperOut_ = 1.0;
+#if 0
+     {
+          int nBad = 0;
+          for (i = 0; i < numberColumns; i++) {
+               if (lower_[i] == upper_[i] && getColumnStatus(i) == basic)
+                    nBad++;
+          }
+          if (nBad)
+               printf("yy %d basic fixed\n", nBad);
+     }
+#endif
+     // ray may be null if in branch and bound
+     if (rowScale_) {
+          // Collect infeasibilities
+          int numberPrimalScaled = 0;
+          int numberPrimalUnscaled = 0;
+          int numberDualScaled = 0;
+          int numberDualUnscaled = 0;
+          double scaleC = 1.0 / objectiveScale_;
+          double scaleR = 1.0 / rhsScale_;
+          const double * inverseScale = inverseColumnScale_;
+          for (i = 0; i < numberColumns; i++) {
+               double scaleFactor = columnScale_[i];
+               double valueScaled = columnActivityWork_[i];
+               double lowerScaled = columnLowerWork_[i];
+               double upperScaled = columnUpperWork_[i];
+               if (lowerScaled > -1.0e20 || upperScaled < 1.0e20) {
+                    if (valueScaled < lowerScaled - primalTolerance_ ||
+                              valueScaled > upperScaled + primalTolerance_)
+                         numberPrimalScaled++;
+                    else
+                         upperOut_ = CoinMax(upperOut_, CoinMin(valueScaled - lowerScaled, upperScaled - valueScaled));
+               }
+               columnActivity_[i] = valueScaled * scaleFactor * scaleR;
+               double value = columnActivity_[i];
+               if (value < columnLower_[i] - primalTolerance_)
+                    numberPrimalUnscaled++;
+               else if (value > columnUpper_[i] + primalTolerance_)
+                    numberPrimalUnscaled++;
+               double valueScaledDual = reducedCostWork_[i];
+               if (valueScaled > columnLowerWork_[i] + primalTolerance_ && valueScaledDual > dualTolerance_)
+                    numberDualScaled++;
+               if (valueScaled < columnUpperWork_[i] - primalTolerance_ && valueScaledDual < -dualTolerance_)
+                    numberDualScaled++;
+               reducedCost_[i] = (valueScaledDual * scaleC) * inverseScale[i];
+               double valueDual = reducedCost_[i];
+               if (value > columnLower_[i] + primalTolerance_ && valueDual > dualTolerance_)
+                    numberDualUnscaled++;
+               if (value < columnUpper_[i] - primalTolerance_ && valueDual < -dualTolerance_)
+                    numberDualUnscaled++;
+          }
+          inverseScale = inverseRowScale_;
+          for (i = 0; i < numberRows; i++) {
+               double scaleFactor = rowScale_[i];
+               double valueScaled = rowActivityWork_[i];
+               double lowerScaled = rowLowerWork_[i];
+               double upperScaled = rowUpperWork_[i];
+               if (lowerScaled > -1.0e20 || upperScaled < 1.0e20) {
+                    if (valueScaled < lowerScaled - primalTolerance_ ||
+                              valueScaled > upperScaled + primalTolerance_)
+                         numberPrimalScaled++;
+                    else
+                         upperOut_ = CoinMax(upperOut_, CoinMin(valueScaled - lowerScaled, upperScaled - valueScaled));
+               }
+               rowActivity_[i] = (valueScaled * scaleR) * inverseScale[i];
+               double value = rowActivity_[i];
+               if (value < rowLower_[i] - primalTolerance_)
+                    numberPrimalUnscaled++;
+               else if (value > rowUpper_[i] + primalTolerance_)
+                    numberPrimalUnscaled++;
+               double valueScaledDual = dual_[i] + rowObjectiveWork_[i];;
+               if (valueScaled > rowLowerWork_[i] + primalTolerance_ && valueScaledDual > dualTolerance_)
+                    numberDualScaled++;
+               if (valueScaled < rowUpperWork_[i] - primalTolerance_ && valueScaledDual < -dualTolerance_)
+                    numberDualScaled++;
+               dual_[i] *= scaleFactor * scaleC;
+               double valueDual = dual_[i];
+               if (rowObjective_)
+                    valueDual += rowObjective_[i];
+               if (value > rowLower_[i] + primalTolerance_ && valueDual > dualTolerance_)
+                    numberDualUnscaled++;
+               if (value < rowUpper_[i] - primalTolerance_ && valueDual < -dualTolerance_)
+                    numberDualUnscaled++;
+          }
+          if (!problemStatus_ && !secondaryStatus_) {
+               // See if we need to set secondary status
+               if (numberPrimalUnscaled) {
+                    if (numberDualUnscaled)
+                         secondaryStatus_ = 4;
+                    else
+                         secondaryStatus_ = 2;
+               } else {
+                    if (numberDualUnscaled)
+                         secondaryStatus_ = 3;
+               }
+          }
+          if (problemStatus_ == 2 && ray_) {
+               for (i = 0; i < numberColumns; i++) {
+                    ray_[i] *= columnScale_[i];
+               }
+          } else if (problemStatus_ == 1 && ray_) {
+               for (i = 0; i < numberRows; i++) {
+                    ray_[i] *= rowScale_[i];
+               }
+          }
+     } else if (rhsScale_ != 1.0 || objectiveScale_ != 1.0) {
+          // Collect infeasibilities
+          int numberPrimalScaled = 0;
+          int numberPrimalUnscaled = 0;
+          int numberDualScaled = 0;
+          int numberDualUnscaled = 0;
+          double scaleC = 1.0 / objectiveScale_;
+          double scaleR = 1.0 / rhsScale_;
+          for (i = 0; i < numberColumns; i++) {
+               double valueScaled = columnActivityWork_[i];
+               double lowerScaled = columnLowerWork_[i];
+               double upperScaled = columnUpperWork_[i];
+               if (lowerScaled > -1.0e20 || upperScaled < 1.0e20) {
+                    if (valueScaled < lowerScaled - primalTolerance_ ||
+                              valueScaled > upperScaled + primalTolerance_)
+                         numberPrimalScaled++;
+                    else
+                         upperOut_ = CoinMax(upperOut_, CoinMin(valueScaled - lowerScaled, upperScaled - valueScaled));
+               }
+               columnActivity_[i] = valueScaled * scaleR;
+               double value = columnActivity_[i];
+               if (value < columnLower_[i] - primalTolerance_)
+                    numberPrimalUnscaled++;
+               else if (value > columnUpper_[i] + primalTolerance_)
+                    numberPrimalUnscaled++;
+               double valueScaledDual = reducedCostWork_[i];
+               if (valueScaled > columnLowerWork_[i] + primalTolerance_ && valueScaledDual > dualTolerance_)
+                    numberDualScaled++;
+               if (valueScaled < columnUpperWork_[i] - primalTolerance_ && valueScaledDual < -dualTolerance_)
+                    numberDualScaled++;
+               reducedCost_[i] = valueScaledDual * scaleC;
+               double valueDual = reducedCost_[i];
+               if (value > columnLower_[i] + primalTolerance_ && valueDual > dualTolerance_)
+                    numberDualUnscaled++;
+               if (value < columnUpper_[i] - primalTolerance_ && valueDual < -dualTolerance_)
+                    numberDualUnscaled++;
+          }
+          for (i = 0; i < numberRows; i++) {
+               double valueScaled = rowActivityWork_[i];
+               double lowerScaled = rowLowerWork_[i];
+               double upperScaled = rowUpperWork_[i];
+               if (lowerScaled > -1.0e20 || upperScaled < 1.0e20) {
+                    if (valueScaled < lowerScaled - primalTolerance_ ||
+                              valueScaled > upperScaled + primalTolerance_)
+                         numberPrimalScaled++;
+                    else
+                         upperOut_ = CoinMax(upperOut_, CoinMin(valueScaled - lowerScaled, upperScaled - valueScaled));
+               }
+               rowActivity_[i] = valueScaled * scaleR;
+               double value = rowActivity_[i];
+               if (value < rowLower_[i] - primalTolerance_)
+                    numberPrimalUnscaled++;
+               else if (value > rowUpper_[i] + primalTolerance_)
+                    numberPrimalUnscaled++;
+               double valueScaledDual = dual_[i] + rowObjectiveWork_[i];;
+               if (valueScaled > rowLowerWork_[i] + primalTolerance_ && valueScaledDual > dualTolerance_)
+                    numberDualScaled++;
+               if (valueScaled < rowUpperWork_[i] - primalTolerance_ && valueScaledDual < -dualTolerance_)
+                    numberDualScaled++;
+               dual_[i] *= scaleC;
+               double valueDual = dual_[i];
+               if (rowObjective_)
+                    valueDual += rowObjective_[i];
+               if (value > rowLower_[i] + primalTolerance_ && valueDual > dualTolerance_)
+                    numberDualUnscaled++;
+               if (value < rowUpper_[i] - primalTolerance_ && valueDual < -dualTolerance_)
+                    numberDualUnscaled++;
+          }
+          if (!problemStatus_ && !secondaryStatus_) {
+               // See if we need to set secondary status
+               if (numberPrimalUnscaled) {
+                    if (numberDualUnscaled)
+                         secondaryStatus_ = 4;
+                    else
+                         secondaryStatus_ = 2;
+               } else {
+                    if (numberDualUnscaled)
+                         secondaryStatus_ = 3;
+               }
+          }
+     } else {
+          if (columnActivityWork_) {
+               for (i = 0; i < numberColumns; i++) {
+                    double value = columnActivityWork_[i];
+                    double lower = columnLowerWork_[i];
+                    double upper = columnUpperWork_[i];
+                    if (lower > -1.0e20 || upper < 1.0e20) {
+                         if (value > lower && value < upper)
+                              upperOut_ = CoinMax(upperOut_, CoinMin(value - lower, upper - value));
+                    }
+                    columnActivity_[i] = columnActivityWork_[i];
+                    reducedCost_[i] = reducedCostWork_[i];
+               }
+               for (i = 0; i < numberRows; i++) {
+                    double value = rowActivityWork_[i];
+                    double lower = rowLowerWork_[i];
+                    double upper = rowUpperWork_[i];
+                    if (lower > -1.0e20 || upper < 1.0e20) {
+                         if (value > lower && value < upper)
+                              upperOut_ = CoinMax(upperOut_, CoinMin(value - lower, upper - value));
+                    }
+                    rowActivity_[i] = rowActivityWork_[i];
+               }
+          }
+     }
+     // switch off scalefactor if auto
+     if (automaticScale_) {
+          rhsScale_ = 1.0;
+          objectiveScale_ = 1.0;
+     }
+     if (optimizationDirection_ != 1.0) {
+          // and modify all dual signs
+          for (i = 0; i < numberColumns; i++)
+               reducedCost_[i] *= optimizationDirection_;
+          for (i = 0; i < numberRows; i++)
+               dual_[i] *= optimizationDirection_;
+     }
+     // scaling may have been turned off
+     scalingFlag_ = abs(scalingFlag_);
+     if(getRidOfFactorizationData > 0) {
+          gutsOfDelete(getRidOfFactorizationData + 1);
+     } else {
+          // at least get rid of nonLinearCost_
+          delete nonLinearCost_;
+          nonLinearCost_ = NULL;
+     }
+     if (!rowObjective_ && problemStatus_ == 0 && objective_->type() == 1 &&
+               numberRows && numberColumns) {
+          // Redo objective value
+          double objectiveValue = 0.0;
+          const double * cost = objective();
+          for (int i = 0; i < numberColumns; i++) {
+               double value = columnActivity_[i];
+               objectiveValue += value * cost[i];
+          }
+          //if (fabs(objectiveValue_ -objectiveValue*optimizationDirection())>1.0e-5)
+          //printf("old obj %g new %g\n",objectiveValue_, objectiveValue*optimizationDirection());
+          objectiveValue_ = objectiveValue * optimizationDirection();
+     }
+     // get rid of data
+     matrix_->generalExpanded(this, 13, scalingFlag_);
+}
+void
+ClpSimplex::setDualBound(double value)
+{
+     if (value > 0.0)
+          dualBound_ = value;
+}
+void
+ClpSimplex::setInfeasibilityCost(double value)
+{
+     if (value > 0.0)
+          infeasibilityCost_ = value;
+}
+void ClpSimplex::setNumberRefinements( int value)
+{
+     if (value >= 0 && value < 10)
+          numberRefinements_ = value;
+}
+// Sets row pivot choice algorithm in dual
+void
+ClpSimplex::setDualRowPivotAlgorithm(ClpDualRowPivot & choice)
+{
+     delete dualRowPivot_;
+     dualRowPivot_ = choice.clone(true);
+     dualRowPivot_->setModel(this);
+}
+// Sets row pivot choice algorithm in dual
+void
+ClpSimplex::setPrimalColumnPivotAlgorithm(ClpPrimalColumnPivot & choice)
+{
+     delete primalColumnPivot_;
+     primalColumnPivot_ = choice.clone(true);
+     primalColumnPivot_->setModel(this);
+}
+void
+ClpSimplex::setFactorization( ClpFactorization & factorization)
+{
+     if (factorization_)
+          factorization_->setFactorization(factorization);
+     else
+          factorization_ = new ClpFactorization(factorization,
+                                                numberRows_);
+}
+
+// Swaps factorization
+ClpFactorization *
+ClpSimplex::swapFactorization( ClpFactorization * factorization)
+{
+     ClpFactorization * swap = factorization_;
+     factorization_ = factorization;
+     return swap;
+}
+// Copies in factorization to existing one
+void
+ClpSimplex::copyFactorization( ClpFactorization & factorization)
+{
+     *factorization_ = factorization;
+}
+/* Perturbation:
+   -50 to +50 - perturb by this power of ten (-6 sounds good)
+   100 - auto perturb if takes too long (1.0e-6 largest nonzero)
+   101 - we are perturbed
+   102 - don't try perturbing again
+   default is 100
+*/
+void
+ClpSimplex::setPerturbation(int value)
+{
+     if(value <= 100 && value >= -1000) {
+          perturbation_ = value;
+     }
+}
+// Sparsity on or off
+bool
+ClpSimplex::sparseFactorization() const
+{
+     return factorization_->sparseThreshold() != 0;
+}
+void
+ClpSimplex::setSparseFactorization(bool value)
+{
+     if (value) {
+          if (!factorization_->sparseThreshold())
+               factorization_->goSparse();
+     } else {
+          factorization_->sparseThreshold(0);
+     }
+}
+void checkCorrect(ClpSimplex * /*model*/, int iRow,
+                  const double * element, const int * rowStart, const int * rowLength,
+                  const int * column,
+                  const double * columnLower_, const double * columnUpper_,
+                  int /*infiniteUpperC*/,
+                  int /*infiniteLowerC*/,
+                  double &maximumUpC,
+                  double &maximumDownC)
+{
+     int infiniteUpper = 0;
+     int infiniteLower = 0;
+     double maximumUp = 0.0;
+     double maximumDown = 0.0;
+     CoinBigIndex rStart = rowStart[iRow];
+     CoinBigIndex rEnd = rowStart[iRow] + rowLength[iRow];
+     CoinBigIndex j;
+     double large = 1.0e15;
+     int iColumn;
+     // Compute possible lower and upper ranges
+
+     for (j = rStart; j < rEnd; ++j) {
+          double value = element[j];
+          iColumn = column[j];
+          if (value > 0.0) {
+               if (columnUpper_[iColumn] >= large) {
+                    ++infiniteUpper;
+               } else {
+                    maximumUp += columnUpper_[iColumn] * value;
+               }
+               if (columnLower_[iColumn] <= -large) {
+                    ++infiniteLower;
+               } else {
+                    maximumDown += columnLower_[iColumn] * value;
+               }
+          } else if (value < 0.0) {
+               if (columnUpper_[iColumn] >= large) {
+                    ++infiniteLower;
+               } else {
+                    maximumDown += columnUpper_[iColumn] * value;
+               }
+               if (columnLower_[iColumn] <= -large) {
+                    ++infiniteUpper;
+               } else {
+                    maximumUp += columnLower_[iColumn] * value;
+               }
+          }
+     }
+     //assert (infiniteLowerC==infiniteLower);
+     //assert (infiniteUpperC==infiniteUpper);
+     if (fabs(maximumUp - maximumUpC) > 1.0e-12 * CoinMax(fabs(maximumUp), fabs(maximumUpC)))
+          COIN_DETAIL_PRINT(printf("row %d comp up %g, true up %g\n", iRow,
+				   maximumUpC, maximumUp));
+     if (fabs(maximumDown - maximumDownC) > 1.0e-12 * CoinMax(fabs(maximumDown), fabs(maximumDownC)))
+          COIN_DETAIL_PRINT(printf("row %d comp down %g, true down %g\n", iRow,
+                 maximumDownC, maximumDown));
+     maximumUpC = maximumUp;
+     maximumDownC = maximumDown;
+}
+
+/* Tightens primal bounds to make dual faster.  Unless
+   fixed, bounds are slightly looser than they could be.
+   This is to make dual go faster and is probably not needed
+   with a presolve.  Returns non-zero if problem infeasible
+
+   Fudge for branch and bound - put bounds on columns of factor *
+   largest value (at continuous) - should improve stability
+   in branch and bound on infeasible branches (0.0 is off)
+*/
+int
+ClpSimplex::tightenPrimalBounds(double factor, int doTight, bool tightIntegers)
+{
+
+     // Get a row copy in standard format
+     CoinPackedMatrix copy;
+     copy.setExtraGap(0.0);
+     copy.setExtraMajor(0.0);
+     copy.reverseOrderedCopyOf(*matrix());
+     // Matrix may have been created so get rid of it
+     matrix_->releasePackedMatrix();
+     // get matrix data pointers
+     const int * column = copy.getIndices();
+     const CoinBigIndex * rowStart = copy.getVectorStarts();
+     const int * rowLength = copy.getVectorLengths();
+     const double * element = copy.getElements();
+     int numberChanged = 1, iPass = 0;
+     double large = largeValue(); // treat bounds > this as infinite
+#ifndef NDEBUG
+     double large2 = 1.0e10 * large;
+#endif
+     int numberInfeasible = 0;
+     int totalTightened = 0;
+
+     double tolerance = primalTolerance();
+
+
+     // Save column bounds
+     double * saveLower = new double [numberColumns_];
+     CoinMemcpyN(columnLower_, numberColumns_, saveLower);
+     double * saveUpper = new double [numberColumns_];
+     CoinMemcpyN(columnUpper_, numberColumns_, saveUpper);
+
+     int iRow, iColumn;
+     // If wanted compute a reasonable dualBound_
+     if (factor == COIN_DBL_MAX) {
+          factor = 0.0;
+          if (dualBound_ == 1.0e10) {
+               // get largest scaled away from bound
+               double largest = 1.0e-12;
+               double largestScaled = 1.0e-12;
+               int iRow;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    double value = rowActivity_[iRow];
+                    double above = value - rowLower_[iRow];
+                    double below = rowUpper_[iRow] - value;
+                    if (above < 1.0e12) {
+                         largest = CoinMax(largest, above);
+                    }
+                    if (below < 1.0e12) {
+                         largest = CoinMax(largest, below);
+                    }
+                    if (rowScale_) {
+                         double multiplier = rowScale_[iRow];
+                         above *= multiplier;
+                         below *= multiplier;
+                    }
+                    if (above < 1.0e12) {
+                         largestScaled = CoinMax(largestScaled, above);
+                    }
+                    if (below < 1.0e12) {
+                         largestScaled = CoinMax(largestScaled, below);
+                    }
+               }
+
+               int iColumn;
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double value = columnActivity_[iColumn];
+                    double above = value - columnLower_[iColumn];
+                    double below = columnUpper_[iColumn] - value;
+                    if (above < 1.0e12) {
+                         largest = CoinMax(largest, above);
+                    }
+                    if (below < 1.0e12) {
+                         largest = CoinMax(largest, below);
+                    }
+                    if (columnScale_) {
+                         double multiplier = 1.0 / columnScale_[iColumn];
+                         above *= multiplier;
+                         below *= multiplier;
+                    }
+                    if (above < 1.0e12) {
+                         largestScaled = CoinMax(largestScaled, above);
+                    }
+                    if (below < 1.0e12) {
+                         largestScaled = CoinMax(largestScaled, below);
+                    }
+               }
+               std::cout << "Largest (scaled) away from bound " << largestScaled
+                         << " unscaled " << largest << std::endl;
+               dualBound_ = CoinMax(1.0001e7, CoinMin(100.0 * largest, 1.00001e10));
+          }
+     }
+
+     // If wanted - tighten column bounds using solution
+     if (factor) {
+          double largest = 0.0;
+          if (factor > 0.0) {
+               assert (factor > 1.0);
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    if (columnUpper_[iColumn] - columnLower_[iColumn] > tolerance) {
+                         largest = CoinMax(largest, fabs(columnActivity_[iColumn]));
+                    }
+               }
+               largest *= factor;
+          } else {
+               // absolute
+               largest = - factor;
+          }
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (columnUpper_[iColumn] - columnLower_[iColumn] > tolerance) {
+                    columnUpper_[iColumn] = CoinMin(columnUpper_[iColumn], largest);
+                    columnLower_[iColumn] = CoinMax(columnLower_[iColumn], -largest);
+               }
+          }
+     }
+#define MAXPASS 10
+
+     // Loop round seeing if we can tighten bounds
+     // Would be faster to have a stack of possible rows
+     // and we put altered rows back on stack
+     int numberCheck = -1;
+     while(numberChanged > numberCheck) {
+
+          numberChanged = 0; // Bounds tightened this pass
+
+          if (iPass == MAXPASS) break;
+          iPass++;
+
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+
+               if (rowLower_[iRow] > -large || rowUpper_[iRow] < large) {
+
+                    // possible row
+                    int infiniteUpper = 0;
+                    int infiniteLower = 0;
+                    double maximumUp = 0.0;
+                    double maximumDown = 0.0;
+                    double newBound;
+                    CoinBigIndex rStart = rowStart[iRow];
+                    CoinBigIndex rEnd = rowStart[iRow] + rowLength[iRow];
+                    CoinBigIndex j;
+                    // Compute possible lower and upper ranges
+
+                    for (j = rStart; j < rEnd; ++j) {
+                         double value = element[j];
+                         iColumn = column[j];
+                         if (value > 0.0) {
+                              if (columnUpper_[iColumn] >= large) {
+                                   ++infiniteUpper;
+                              } else {
+                                   maximumUp += columnUpper_[iColumn] * value;
+                              }
+                              if (columnLower_[iColumn] <= -large) {
+                                   ++infiniteLower;
+                              } else {
+                                   maximumDown += columnLower_[iColumn] * value;
+                              }
+                         } else if (value < 0.0) {
+                              if (columnUpper_[iColumn] >= large) {
+                                   ++infiniteLower;
+                              } else {
+                                   maximumDown += columnUpper_[iColumn] * value;
+                              }
+                              if (columnLower_[iColumn] <= -large) {
+                                   ++infiniteUpper;
+                              } else {
+                                   maximumUp += columnLower_[iColumn] * value;
+                              }
+                         }
+                    }
+                    // Build in a margin of error
+                    maximumUp += 1.0e-8 * fabs(maximumUp);
+                    maximumDown -= 1.0e-8 * fabs(maximumDown);
+                    double maxUp = maximumUp + infiniteUpper * 1.0e31;
+                    double maxDown = maximumDown - infiniteLower * 1.0e31;
+                    if (maxUp <= rowUpper_[iRow] + tolerance &&
+                              maxDown >= rowLower_[iRow] - tolerance) {
+
+                         // Row is redundant - make totally free
+                         // NO - can't do this for postsolve
+                         // rowLower_[iRow]=-COIN_DBL_MAX;
+                         // rowUpper_[iRow]=COIN_DBL_MAX;
+                         //printf("Redundant row in presolveX %d\n",iRow);
+
+                    } else {
+                         if (maxUp < rowLower_[iRow] - 100.0 * tolerance ||
+                                   maxDown > rowUpper_[iRow] + 100.0 * tolerance) {
+                              // problem is infeasible - exit at once
+                              numberInfeasible++;
+                              break;
+                         }
+                         double lower = rowLower_[iRow];
+                         double upper = rowUpper_[iRow];
+                         for (j = rStart; j < rEnd; ++j) {
+                              double value = element[j];
+                              iColumn = column[j];
+                              double nowLower = columnLower_[iColumn];
+                              double nowUpper = columnUpper_[iColumn];
+                              if (value > 0.0) {
+                                   // positive value
+                                   if (lower > -large) {
+                                        if (!infiniteUpper) {
+                                             assert(nowUpper < large2);
+                                             newBound = nowUpper +
+                                                        (lower - maximumUp) / value;
+                                             // relax if original was large
+                                             if (fabs(maximumUp) > 1.0e8)
+                                                  newBound -= 1.0e-12 * fabs(maximumUp);
+                                        } else if (infiniteUpper == 1 && nowUpper > large) {
+                                             newBound = (lower - maximumUp) / value;
+                                             // relax if original was large
+                                             if (fabs(maximumUp) > 1.0e8)
+                                                  newBound -= 1.0e-12 * fabs(maximumUp);
+                                        } else {
+                                             newBound = -COIN_DBL_MAX;
+                                        }
+                                        if (newBound > nowLower + 1.0e-12 && newBound > -large) {
+                                             // Tighten the lower bound
+                                             numberChanged++;
+                                             // check infeasible (relaxed)
+                                             if (nowUpper < newBound) {
+                                                  if (nowUpper - newBound <
+                                                            -100.0 * tolerance)
+                                                       numberInfeasible++;
+                                                  else
+                                                       newBound = nowUpper;
+                                             }
+                                             columnLower_[iColumn] = newBound;
+                                             // adjust
+                                             double now;
+                                             if (nowLower < -large) {
+                                                  now = 0.0;
+                                                  infiniteLower--;
+                                             } else {
+                                                  now = nowLower;
+                                             }
+                                             maximumDown += (newBound - now) * value;
+                                             nowLower = newBound;
+#ifdef DEBUG
+                                             checkCorrect(this, iRow,
+                                                          element, rowStart, rowLength,
+                                                          column,
+                                                          columnLower_,  columnUpper_,
+                                                          infiniteUpper,
+                                                          infiniteLower,
+                                                          maximumUp,
+                                                          maximumDown);
+#endif
+                                        }
+                                   }
+                                   if (upper < large) {
+                                        if (!infiniteLower) {
+                                             assert(nowLower > - large2);
+                                             newBound = nowLower +
+                                                        (upper - maximumDown) / value;
+                                             // relax if original was large
+                                             if (fabs(maximumDown) > 1.0e8)
+                                                  newBound += 1.0e-12 * fabs(maximumDown);
+                                        } else if (infiniteLower == 1 && nowLower < -large) {
+                                             newBound =   (upper - maximumDown) / value;
+                                             // relax if original was large
+                                             if (fabs(maximumDown) > 1.0e8)
+                                                  newBound += 1.0e-12 * fabs(maximumDown);
+                                        } else {
+                                             newBound = COIN_DBL_MAX;
+                                        }
+                                        if (newBound < nowUpper - 1.0e-12 && newBound < large) {
+                                             // Tighten the upper bound
+                                             numberChanged++;
+                                             // check infeasible (relaxed)
+                                             if (nowLower > newBound) {
+                                                  if (newBound - nowLower <
+                                                            -100.0 * tolerance)
+                                                       numberInfeasible++;
+                                                  else
+                                                       newBound = nowLower;
+                                             }
+                                             columnUpper_[iColumn] = newBound;
+                                             // adjust
+                                             double now;
+                                             if (nowUpper > large) {
+                                                  now = 0.0;
+                                                  infiniteUpper--;
+                                             } else {
+                                                  now = nowUpper;
+                                             }
+                                             maximumUp += (newBound - now) * value;
+                                             nowUpper = newBound;
+#ifdef DEBUG
+                                             checkCorrect(this, iRow,
+                                                          element, rowStart, rowLength,
+                                                          column,
+                                                          columnLower_,  columnUpper_,
+                                                          infiniteUpper,
+                                                          infiniteLower,
+                                                          maximumUp,
+                                                          maximumDown);
+#endif
+                                        }
+                                   }
+                              } else {
+                                   // negative value
+                                   if (lower > -large) {
+                                        if (!infiniteUpper) {
+                                             assert(nowLower < large2);
+                                             newBound = nowLower +
+                                                        (lower - maximumUp) / value;
+                                             // relax if original was large
+                                             if (fabs(maximumUp) > 1.0e8)
+                                                  newBound += 1.0e-12 * fabs(maximumUp);
+                                        } else if (infiniteUpper == 1 && nowLower < -large) {
+                                             newBound = (lower - maximumUp) / value;
+                                             // relax if original was large
+                                             if (fabs(maximumUp) > 1.0e8)
+                                                  newBound += 1.0e-12 * fabs(maximumUp);
+                                        } else {
+                                             newBound = COIN_DBL_MAX;
+                                        }
+                                        if (newBound < nowUpper - 1.0e-12 && newBound < large) {
+                                             // Tighten the upper bound
+                                             numberChanged++;
+                                             // check infeasible (relaxed)
+                                             if (nowLower > newBound) {
+                                                  if (newBound - nowLower <
+                                                            -100.0 * tolerance)
+                                                       numberInfeasible++;
+                                                  else
+                                                       newBound = nowLower;
+                                             }
+                                             columnUpper_[iColumn] = newBound;
+                                             // adjust
+                                             double now;
+                                             if (nowUpper > large) {
+                                                  now = 0.0;
+                                                  infiniteLower--;
+                                             } else {
+                                                  now = nowUpper;
+                                             }
+                                             maximumDown += (newBound - now) * value;
+                                             nowUpper = newBound;
+#ifdef DEBUG
+                                             checkCorrect(this, iRow,
+                                                          element, rowStart, rowLength,
+                                                          column,
+                                                          columnLower_,  columnUpper_,
+                                                          infiniteUpper,
+                                                          infiniteLower,
+                                                          maximumUp,
+                                                          maximumDown);
+#endif
+                                        }
+                                   }
+                                   if (upper < large) {
+                                        if (!infiniteLower) {
+                                             assert(nowUpper < large2);
+                                             newBound = nowUpper +
+                                                        (upper - maximumDown) / value;
+                                             // relax if original was large
+                                             if (fabs(maximumDown) > 1.0e8)
+                                                  newBound -= 1.0e-12 * fabs(maximumDown);
+                                        } else if (infiniteLower == 1 && nowUpper > large) {
+                                             newBound =   (upper - maximumDown) / value;
+                                             // relax if original was large
+                                             if (fabs(maximumDown) > 1.0e8)
+                                                  newBound -= 1.0e-12 * fabs(maximumDown);
+                                        } else {
+                                             newBound = -COIN_DBL_MAX;
+                                        }
+                                        if (newBound > nowLower + 1.0e-12 && newBound > -large) {
+                                             // Tighten the lower bound
+                                             numberChanged++;
+                                             // check infeasible (relaxed)
+                                             if (nowUpper < newBound) {
+                                                  if (nowUpper - newBound <
+                                                            -100.0 * tolerance)
+                                                       numberInfeasible++;
+                                                  else
+                                                       newBound = nowUpper;
+                                             }
+                                             columnLower_[iColumn] = newBound;
+                                             // adjust
+                                             double now;
+                                             if (nowLower < -large) {
+                                                  now = 0.0;
+                                                  infiniteUpper--;
+                                             } else {
+                                                  now = nowLower;
+                                             }
+                                             maximumUp += (newBound - now) * value;
+                                             nowLower = newBound;
+#ifdef DEBUG
+                                             checkCorrect(this, iRow,
+                                                          element, rowStart, rowLength,
+                                                          column,
+                                                          columnLower_,  columnUpper_,
+                                                          infiniteUpper,
+                                                          infiniteLower,
+                                                          maximumUp,
+                                                          maximumDown);
+#endif
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+          }
+          totalTightened += numberChanged;
+          if (iPass == 1)
+               numberCheck = numberChanged >> 4;
+          if (numberInfeasible) break;
+     }
+     if (!numberInfeasible) {
+          handler_->message(CLP_SIMPLEX_BOUNDTIGHTEN, messages_)
+                    << totalTightened
+                    << CoinMessageEol;
+          // Set bounds slightly loose
+          double useTolerance = 1.0e-3;
+          if (doTight > 0) {
+               if (doTight > 10) {
+                    useTolerance = 0.0;
+               } else {
+                    while (doTight) {
+                         useTolerance *= 0.1;
+                         doTight--;
+                    }
+               }
+          }
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (saveUpper[iColumn] > saveLower[iColumn] + useTolerance) {
+                    // Make large bounds stay infinite
+                    if (saveUpper[iColumn] > 1.0e30 && columnUpper_[iColumn] > 1.0e10) {
+                         columnUpper_[iColumn] = COIN_DBL_MAX;
+                    }
+                    if (saveLower[iColumn] < -1.0e30 && columnLower_[iColumn] < -1.0e10) {
+                         columnLower_[iColumn] = -COIN_DBL_MAX;
+                    }
+#ifdef KEEP_GOING_IF_FIXED
+                    double multiplier = 5.0e-3 * floor(100.0 * randomNumberGenerator_.randomDouble()) + 1.0;
+                    multiplier *= 100.0;
+#else
+                    double multiplier = 100.0;
+#endif
+                    if (columnUpper_[iColumn] - columnLower_[iColumn] < useTolerance + 1.0e-8) {
+                         // relax enough so will have correct dj
+#if 1
+                         columnLower_[iColumn] = CoinMax(saveLower[iColumn],
+                                                         columnLower_[iColumn] - multiplier * useTolerance);
+                         columnUpper_[iColumn] = CoinMin(saveUpper[iColumn],
+                                                         columnUpper_[iColumn] + multiplier * useTolerance);
+#else
+                         if (fabs(columnUpper_[iColumn]) < fabs(columnLower_[iColumn])) {
+                              if (columnUpper_[iColumn] - multiplier * useTolerance > saveLower[iColumn]) {
+                                   columnLower_[iColumn] = columnUpper_[iColumn] - multiplier * useTolerance;
+                              } else {
+                                   columnLower_[iColumn] = saveLower[iColumn];
+                                   columnUpper_[iColumn] = CoinMin(saveUpper[iColumn],
+                                                                   saveLower[iColumn] + multiplier * useTolerance);
+                              }
+                         } else {
+                              if (columnLower_[iColumn] + multiplier * useTolerance < saveUpper[iColumn]) {
+                                   columnUpper_[iColumn] = columnLower_[iColumn] + multiplier * useTolerance;
+                              } else {
+                                   columnUpper_[iColumn] = saveUpper[iColumn];
+                                   columnLower_[iColumn] = CoinMax(saveLower[iColumn],
+                                                                   saveUpper[iColumn] - multiplier * useTolerance);
+                              }
+                         }
+#endif
+                    } else {
+                         if (columnUpper_[iColumn] < saveUpper[iColumn]) {
+                              // relax a bit
+                              columnUpper_[iColumn] = CoinMin(columnUpper_[iColumn] + multiplier * useTolerance,
+                                                              saveUpper[iColumn]);
+                         }
+                         if (columnLower_[iColumn] > saveLower[iColumn]) {
+                              // relax a bit
+                              columnLower_[iColumn] = CoinMax(columnLower_[iColumn] - multiplier * useTolerance,
+                                                              saveLower[iColumn]);
+                         }
+                    }
+               }
+          }
+          if (tightIntegers && integerType_) {
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    if (integerType_[iColumn]) {
+                         double value;
+                         value = floor(columnLower_[iColumn] + 0.5);
+                         if (fabs(value - columnLower_[iColumn]) > primalTolerance_)
+                              value = ceil(columnLower_[iColumn]);
+                         columnLower_[iColumn] = value;
+                         value = floor(columnUpper_[iColumn] + 0.5);
+                         if (fabs(value - columnUpper_[iColumn]) > primalTolerance_)
+                              value = floor(columnUpper_[iColumn]);
+                         columnUpper_[iColumn] = value;
+                         if (columnLower_[iColumn] > columnUpper_[iColumn])
+                              numberInfeasible++;
+                    }
+               }
+               if (numberInfeasible) {
+                    handler_->message(CLP_SIMPLEX_INFEASIBILITIES, messages_)
+                              << numberInfeasible
+                              << CoinMessageEol;
+                    // restore column bounds
+                    CoinMemcpyN(saveLower, numberColumns_, columnLower_);
+                    CoinMemcpyN(saveUpper, numberColumns_, columnUpper_);
+               }
+          }
+     } else {
+          handler_->message(CLP_SIMPLEX_INFEASIBILITIES, messages_)
+                    << numberInfeasible
+                    << CoinMessageEol;
+          // restore column bounds
+          CoinMemcpyN(saveLower, numberColumns_, columnLower_);
+          CoinMemcpyN(saveUpper, numberColumns_, columnUpper_);
+     }
+     delete [] saveLower;
+     delete [] saveUpper;
+     return (numberInfeasible);
+}
+//#define SAVE_AND_RESTORE
+// dual
+#include "ClpSimplexDual.hpp"
+#include "ClpSimplexPrimal.hpp"
+#ifndef SAVE_AND_RESTORE
+int ClpSimplex::dual (int ifValuesPass , int startFinishOptions)
+#else
+int ClpSimplex::dual (int ifValuesPass , int startFinishOptions)
+{
+     // May be empty problem
+     if (numberRows_ && numberColumns_) {
+          // Save on file for debug
+          int returnCode;
+          returnCode = saveModel("debug.sav");
+          if (returnCode) {
+               printf("** Unable to save model to debug.sav\n");
+               abort();
+          }
+          ClpSimplex temp;
+          returnCode = temp.restoreModel("debug.sav");
+          if (returnCode) {
+               printf("** Unable to restore model from debug.sav\n");
+               abort();
+          }
+          temp.setLogLevel(handler_->logLevel());
+          // Now do dual
+          returnCode = temp.dualDebug(ifValuesPass, startFinishOptions);
+          // Move status and solution back
+          int numberTotal = numberRows_ + numberColumns_;
+          CoinMemcpyN(temp.statusArray(), numberTotal, status_);
+          CoinMemcpyN(temp.primalColumnSolution(), numberColumns_, columnActivity_);
+          CoinMemcpyN(temp.primalRowSolution(), numberRows_, rowActivity_);
+          CoinMemcpyN(temp.dualColumnSolution(), numberColumns_, reducedCost_);
+          CoinMemcpyN(temp.dualRowSolution(), numberRows_, dual_);
+          problemStatus_ = temp.problemStatus_;
+          setObjectiveValue(temp.objectiveValue());
+          setSumDualInfeasibilities(temp.sumDualInfeasibilities());
+          setNumberDualInfeasibilities(temp.numberDualInfeasibilities());
+          setSumPrimalInfeasibilities(temp.sumPrimalInfeasibilities());
+          setNumberPrimalInfeasibilities(temp.numberPrimalInfeasibilities());
+          setNumberIterations(temp.numberIterations());
+          onStopped(); // set secondary status if stopped
+          return returnCode;
+     } else {
+          // empty
+          return dualDebug(ifValuesPass, startFinishOptions);
+     }
+}
+int ClpSimplex::dualDebug (int ifValuesPass , int startFinishOptions)
+#endif
+{
+     //double savedPivotTolerance = factorization_->pivotTolerance();
+     int saveQuadraticActivated = 0;
+     if (objective_) {
+          saveQuadraticActivated = objective_->activated();
+          objective_->setActivated(0);
+     } else {
+          // create dummy stuff
+          assert (!numberColumns_);
+          if (!numberRows_)
+               problemStatus_ = 0; // say optimal
+          return 0;
+     }
+     ClpObjective * saveObjective = objective_;
+     CoinAssert (ifValuesPass >= 0 && ifValuesPass < 3);
+     /*  Note use of "down casting".  The only class the user sees is ClpSimplex.
+         Classes ClpSimplexDual, ClpSimplexPrimal, (ClpSimplexNonlinear)
+         and ClpSimplexOther all exist and inherit from ClpSimplex but have no
+         additional data and have no destructor or (non-default) constructor.
+
+         This is to stop classes becoming too unwieldy and so I (JJF) can use e.g. "perturb"
+         in primal and dual.
+
+         As far as I can see this is perfectly safe.
+     */
+#ifdef COIN_DEVELOP
+     //#define EXPENSIVE
+#endif
+#ifdef EXPENSIVE
+     static int dualCount = 0;
+     static int dualCheckCount = -1;
+     dualCount++;
+     if (dualCount == dualCheckCount) {
+          printf("Bad dual coming up\n");
+     }
+     ClpSimplex saveModel = *this;
+#endif
+     int returnCode = static_cast<ClpSimplexDual *> (this)->dual(ifValuesPass, startFinishOptions);
+#ifdef EXPENSIVE
+     if (problemStatus_ == 1) {
+          saveModel.allSlackBasis(true);
+          static_cast<ClpSimplexDual *> (&saveModel)->dual(0, 0);
+          if (saveModel.problemStatus_ == 0) {
+               if (saveModel.objectiveValue() < dblParam_[0] - 1.0e-8 * (1.0 + fabs(dblParam_[0]))) {
+                    if (objectiveValue() < dblParam_[0] - 1.0e-6 * (1.0 + fabs(dblParam_[0]))) {
+                         printf("BAD dual - objs %g ,savemodel %g cutoff %g at count %d\n",
+                                objectiveValue(), saveModel.objectiveValue(), dblParam_[0], dualCount);
+                         saveModel = *this;
+                         saveModel.setLogLevel(63);
+                         static_cast<ClpSimplexDual *> (&saveModel)->dual(0, 0);
+                         // flatten solution and try again
+                         int iRow, iColumn;
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              if (getRowStatus(iRow) != basic) {
+                                   setRowStatus(iRow, superBasic);
+                                   // but put to bound if close
+                                   if (fabs(rowActivity_[iRow] - rowLower_[iRow])
+                                             <= primalTolerance_) {
+                                        rowActivity_[iRow] = rowLower_[iRow];
+                                        setRowStatus(iRow, atLowerBound);
+                                   } else if (fabs(rowActivity_[iRow] - rowUpper_[iRow])
+                                              <= primalTolerance_) {
+                                        rowActivity_[iRow] = rowUpper_[iRow];
+                                        setRowStatus(iRow, atUpperBound);
+                                   }
+                              }
+                         }
+                         for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                              if (getColumnStatus(iColumn) != basic) {
+                                   setColumnStatus(iColumn, superBasic);
+                                   // but put to bound if close
+                                   if (fabs(columnActivity_[iColumn] - columnLower_[iColumn])
+                                             <= primalTolerance_) {
+                                        columnActivity_[iColumn] = columnLower_[iColumn];
+                                        setColumnStatus(iColumn, atLowerBound);
+                                   } else if (fabs(columnActivity_[iColumn]
+                                                   - columnUpper_[iColumn])
+                                              <= primalTolerance_) {
+                                        columnActivity_[iColumn] = columnUpper_[iColumn];
+                                        setColumnStatus(iColumn, atUpperBound);
+                                   }
+                              }
+                         }
+                         static_cast<ClpSimplexPrimal *> (&saveModel)->primal(0, 0);
+                    } else {
+                         printf("bad? dual - objs %g ,savemodel %g cutoff %g at count %d\n",
+                                objectiveValue(), saveModel.objectiveValue(), dblParam_[0], dualCount);
+                    }
+                    if (dualCount > dualCheckCount && dualCheckCount >= 0)
+                         abort();
+               }
+          }
+     }
+#endif
+     //int lastAlgorithm = -1;
+     if ((specialOptions_ & 2048) != 0 && problemStatus_ == 10 && !numberPrimalInfeasibilities_
+               && sumDualInfeasibilities_ < 1000.0 * dualTolerance_ && perturbation_ >= 100)
+          problemStatus_ = 0; // ignore
+     if (problemStatus_==1&&((specialOptions_&(1024 | 4096)) == 0 || (specialOptions_ & 32) != 0)
+	 &&numberFake_) {
+       problemStatus_ = 10; // clean up in primal as fake bounds
+     }
+     if (problemStatus_ == 10) {
+          //printf("Cleaning up with primal\n");
+#ifdef COIN_DEVELOP
+          int saveNumberIterations = numberIterations_;
+#endif
+          //lastAlgorithm=1;
+          int savePerturbation = perturbation_;
+          int saveLog = handler_->logLevel();
+          //handler_->setLogLevel(63);
+          perturbation_ = 100;
+          bool denseFactorization = initialDenseFactorization();
+          // It will be safe to allow dense
+          setInitialDenseFactorization(true);
+          // Allow for catastrophe
+          int saveMax = intParam_[ClpMaxNumIteration];
+          if (numberIterations_) {
+               // normal
+               if (intParam_[ClpMaxNumIteration] > 100000 + numberIterations_)
+                    intParam_[ClpMaxNumIteration]
+                    = numberIterations_ + 1000 + 2 * numberRows_ + numberColumns_;
+          } else {
+               // Not normal allow more
+               baseIteration_ += 2 * (numberRows_ + numberColumns_);
+          }
+          // check which algorithms allowed
+          int dummy;
+	  ClpPackedMatrix * ordinary =
+	    dynamic_cast< ClpPackedMatrix*>(matrix_);
+          if (problemStatus_ == 10 && saveObjective == objective_ &&
+	      ordinary)
+               startFinishOptions |= 2;
+          baseIteration_ = numberIterations_;
+          // Say second call
+          moreSpecialOptions_ |= 256;
+          if ((matrix_->generalExpanded(this, 4, dummy) & 1) != 0)
+               returnCode = static_cast<ClpSimplexPrimal *> (this)->primal(1, startFinishOptions);
+          else
+               returnCode = static_cast<ClpSimplexDual *> (this)->dual(0, startFinishOptions);
+          // Say not second call
+          moreSpecialOptions_ &= ~256;
+          baseIteration_ = 0;
+          if (saveObjective != objective_) {
+               // We changed objective to see if infeasible
+               delete objective_;
+               objective_ = saveObjective;
+               if (!problemStatus_) {
+                    // carry on
+                    returnCode = static_cast<ClpSimplexPrimal *> (this)->primal(1, startFinishOptions);
+               }
+          }
+          if (problemStatus_ == 3 && numberIterations_ < saveMax) {
+#ifdef COIN_DEVELOP
+               if (handler_->logLevel() > 0)
+                    printf("looks like trouble - too many iterations in clean up - trying again\n");
+#endif
+               // flatten solution and try again
+               int iRow, iColumn;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    if (getRowStatus(iRow) != basic) {
+                         setRowStatus(iRow, superBasic);
+                         // but put to bound if close
+                         if (fabs(rowActivity_[iRow] - rowLower_[iRow])
+                                   <= primalTolerance_) {
+                              rowActivity_[iRow] = rowLower_[iRow];
+                              setRowStatus(iRow, atLowerBound);
+                         } else if (fabs(rowActivity_[iRow] - rowUpper_[iRow])
+                                    <= primalTolerance_) {
+                              rowActivity_[iRow] = rowUpper_[iRow];
+                              setRowStatus(iRow, atUpperBound);
+                         }
+                    }
+               }
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    if (getColumnStatus(iColumn) != basic) {
+                         setColumnStatus(iColumn, superBasic);
+                         // but put to bound if close
+                         if (fabs(columnActivity_[iColumn] - columnLower_[iColumn])
+                                   <= primalTolerance_) {
+                              columnActivity_[iColumn] = columnLower_[iColumn];
+                              setColumnStatus(iColumn, atLowerBound);
+                         } else if (fabs(columnActivity_[iColumn]
+                                         - columnUpper_[iColumn])
+                                    <= primalTolerance_) {
+                              columnActivity_[iColumn] = columnUpper_[iColumn];
+                              setColumnStatus(iColumn, atUpperBound);
+                         }
+                    }
+               }
+               problemStatus_ = -1;
+               intParam_[ClpMaxNumIteration] = CoinMin(numberIterations_ + 1000 +
+                                                       2 * numberRows_ + numberColumns_, saveMax);
+               perturbation_ = savePerturbation;
+               baseIteration_ = numberIterations_;
+	       // Say second call
+	       moreSpecialOptions_ |= 256;
+               returnCode = static_cast<ClpSimplexPrimal *> (this)->primal(0, startFinishOptions);
+	       // Say not second call
+	       moreSpecialOptions_ &= ~256;
+               baseIteration_ = 0;
+               computeObjectiveValue();
+               // can't rely on djs either
+               memset(reducedCost_, 0, numberColumns_ * sizeof(double));
+#ifdef COIN_DEVELOP
+               if (problemStatus_ == 3 && numberIterations_ < saveMax &&
+                         handler_->logLevel() > 0)
+                    printf("looks like real trouble - too many iterations in second clean up - giving up\n");
+#endif
+          }
+          intParam_[ClpMaxNumIteration] = saveMax;
+
+          setInitialDenseFactorization(denseFactorization);
+          perturbation_ = savePerturbation;
+          if (problemStatus_ == 10) {
+               if (!numberPrimalInfeasibilities_)
+                    problemStatus_ = 0;
+               else
+                    problemStatus_ = 4;
+          }
+          handler_->setLogLevel(saveLog);
+#ifdef COIN_DEVELOP
+          if (numberIterations_ > 200)
+               printf("after primal status %d - %d iterations (save %d)\n",
+                      problemStatus_, numberIterations_, saveNumberIterations);
+#endif
+     }
+     objective_->setActivated(saveQuadraticActivated);
+     //factorization_->pivotTolerance(savedPivotTolerance);
+     onStopped(); // set secondary status if stopped
+     //if (problemStatus_==1&&lastAlgorithm==1)
+     //returnCode=10; // so will do primal after postsolve
+     if (!problemStatus_) {
+          //assert (!numberPrimalInfeasibilities_);
+          //if (returnCode!=10)
+          //assert (!numberDualInfeasibilities_);
+     }
+     return returnCode;
+}
+// primal
+int ClpSimplex::primal (int ifValuesPass , int startFinishOptions)
+{
+     //double savedPivotTolerance = factorization_->pivotTolerance();
+#ifndef SLIM_CLP
+     // See if nonlinear
+     if (objective_->type() > 1 && objective_->activated())
+          return reducedGradient();
+#endif
+     CoinAssert ((ifValuesPass >= 0 && ifValuesPass < 3) ||
+                 (ifValuesPass >= 12 && ifValuesPass < 100) ||
+                 (ifValuesPass >= 112 && ifValuesPass < 200));
+     if (ifValuesPass >= 12) {
+          int numberProblems = (ifValuesPass - 10) % 100;
+          ifValuesPass = (ifValuesPass < 100) ? 1 : 2;
+          // Go parallel to do solve
+          // Only if all slack basis
+          int i;
+          for ( i = 0; i < numberColumns_; i++) {
+               if (getColumnStatus(i) == basic)
+                    break;
+          }
+          if (i == numberColumns_) {
+               // try if vaguely feasible
+               CoinZeroN(rowActivity_, numberRows_);
+               const int * row = matrix_->getIndices();
+               const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+               const int * columnLength = matrix_->getVectorLengths();
+               const double * element = matrix_->getElements();
+               for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    CoinBigIndex j;
+                    double value = columnActivity_[iColumn];
+                    if (value) {
+                         CoinBigIndex start = columnStart[iColumn];
+                         CoinBigIndex end = start + columnLength[iColumn];
+                         for (j = start; j < end; j++) {
+                              int iRow = row[j];
+                              rowActivity_[iRow] += value * element[j];
+                         }
+                    }
+               }
+               checkSolutionInternal();
+               if (sumPrimalInfeasibilities_ * sqrt(static_cast<double>(numberRows_)) < 1.0) {
+                    // Could do better if can decompose
+                    // correction to get feasible
+                    double scaleFactor = 1.0 / numberProblems;
+                    double * correction = new double [numberRows_];
+                    for (int iRow = 0; iRow < numberRows_; iRow++) {
+                         double value = rowActivity_[iRow];
+                         if (value > rowUpper_[iRow])
+                              value = rowUpper_[iRow] - value;
+                         else if (value < rowLower_[iRow])
+                              value = rowLower_[iRow] - value;
+                         else
+                              value = 0.0;
+                         correction[iRow] = value * scaleFactor;
+                    }
+                    int numberColumns = (numberColumns_ + numberProblems - 1) / numberProblems;
+                    int * whichRows = new int [numberRows_];
+                    for (int i = 0; i < numberRows_; i++)
+                         whichRows[i] = i;
+                    int * whichColumns = new int [numberColumns_];
+                    ClpSimplex ** model = new ClpSimplex * [numberProblems];
+                    int startColumn = 0;
+                    double * saveLower = CoinCopyOfArray(rowLower_, numberRows_);
+                    double * saveUpper = CoinCopyOfArray(rowUpper_, numberRows_);
+                    for (int i = 0; i < numberProblems; i++) {
+                         int endColumn = CoinMin(startColumn + numberColumns, numberColumns_);
+                         CoinZeroN(rowActivity_, numberRows_);
+                         for (int iColumn = startColumn; iColumn < endColumn; iColumn++) {
+                              whichColumns[iColumn-startColumn] = iColumn;
+                              CoinBigIndex j;
+                              double value = columnActivity_[iColumn];
+                              if (value) {
+                                   CoinBigIndex start = columnStart[iColumn];
+                                   CoinBigIndex end = start + columnLength[iColumn];
+                                   for (j = start; j < end; j++) {
+                                        int iRow = row[j];
+                                        rowActivity_[iRow] += value * element[j];
+                                   }
+                              }
+                         }
+                         // adjust rhs
+                         for (int iRow = 0; iRow < numberRows_; iRow++) {
+                              double value = rowActivity_[iRow] + correction[iRow];
+                              if (saveUpper[iRow] < 1.0e30)
+                                   rowUpper_[iRow] = value;
+                              if (saveLower[iRow] > -1.0e30)
+                                   rowLower_[iRow] = value;
+                         }
+                         model[i] = new ClpSimplex(this, numberRows_, whichRows,
+                                                   endColumn - startColumn, whichColumns);
+                         //#define FEB_TRY
+#ifdef FEB_TRY
+                         model[i]->setPerturbation(perturbation_);
+#endif
+                         startColumn = endColumn;
+                    }
+                    memcpy(rowLower_, saveLower, numberRows_ * sizeof(double));
+                    memcpy(rowUpper_, saveUpper, numberRows_ * sizeof(double));
+                    delete [] saveLower;
+                    delete [] saveUpper;
+                    delete [] correction;
+                    // solve (in parallel)
+                    for (int i = 0; i < numberProblems; i++) {
+                         model[i]->primal(1/*ifValuesPass*/);
+                    }
+                    startColumn = 0;
+                    int numberBasic = 0;
+                    // use whichRows as counter
+                    for (int iRow = 0; iRow < numberRows_; iRow++) {
+                         int startValue = 0;
+                         if (rowUpper_[iRow] > rowLower_[iRow])
+                              startValue++;
+                         if (rowUpper_[iRow] > 1.0e30)
+                              startValue++;
+                         if (rowLower_[iRow] < -1.0e30)
+                              startValue++;
+                         whichRows[iRow] = 1000 * startValue;
+                    }
+                    for (int i = 0; i < numberProblems; i++) {
+                         int endColumn = CoinMin(startColumn + numberColumns, numberColumns_);
+                         ClpSimplex * simplex = model[i];
+                         const double * solution = simplex->columnActivity_;
+                         for (int iColumn = startColumn; iColumn < endColumn; iColumn++) {
+                              columnActivity_[iColumn] = solution[iColumn-startColumn];
+                              Status status = simplex->getColumnStatus(iColumn - startColumn);
+                              setColumnStatus(iColumn, status);
+                              if (status == basic)
+                                   numberBasic++;
+                         }
+                         for (int iRow = 0; iRow < numberRows_; iRow++) {
+                              if (simplex->getRowStatus(iRow) == basic)
+                                   whichRows[iRow]++;
+                         }
+                         delete model[i];
+                         startColumn = endColumn;
+                    }
+                    delete [] model;
+                    for (int iRow = 0; iRow < numberRows_; iRow++)
+                         setRowStatus(iRow, superBasic);
+                    CoinZeroN(rowActivity_, numberRows_);
+                    for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         CoinBigIndex j;
+                         double value = columnActivity_[iColumn];
+                         if (value) {
+                              CoinBigIndex start = columnStart[iColumn];
+                              CoinBigIndex end = start + columnLength[iColumn];
+                              for (j = start; j < end; j++) {
+                                   int iRow = row[j];
+                                   rowActivity_[iRow] += value * element[j];
+                              }
+                         }
+                    }
+                    checkSolutionInternal();
+                    if (numberBasic < numberRows_) {
+                         int * order = new int [numberRows_];
+                         for (int iRow = 0; iRow < numberRows_; iRow++) {
+                              setRowStatus(iRow, superBasic);
+                              int nTimes = whichRows[iRow] % 1000;
+                              if (nTimes)
+                                   nTimes += whichRows[iRow] / 500;
+                              whichRows[iRow] = -nTimes;
+                              order[iRow] = iRow;
+                         }
+                         CoinSort_2(whichRows, whichRows + numberRows_, order);
+                         int nPut = numberRows_ - numberBasic;
+                         for (int i = 0; i < nPut; i++) {
+                              int iRow = order[i];
+                              setRowStatus(iRow, basic);
+                         }
+                         delete [] order;
+                    } else if (numberBasic > numberRows_) {
+                         double * away = new double [numberBasic];
+                         numberBasic = 0;
+                         for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                              if (getColumnStatus(iColumn) == basic) {
+                                   double value = columnActivity_[iColumn];
+                                   value = CoinMin(value - columnLower_[iColumn],
+                                                   columnUpper_[iColumn] - value);
+                                   away[numberBasic] = value;
+                                   whichColumns[numberBasic++] = iColumn;
+                              }
+                         }
+                         CoinSort_2(away, away + numberBasic, whichColumns);
+                         int nPut = numberBasic - numberRows_;
+                         for (int i = 0; i < nPut; i++) {
+                              int iColumn = whichColumns[i];
+                              double value = columnActivity_[iColumn];
+                              if (value - columnLower_[iColumn] <
+                                        columnUpper_[iColumn] - value)
+                                   setColumnStatus(iColumn, atLowerBound);
+                              else
+                                   setColumnStatus(iColumn, atUpperBound);
+                         }
+                         delete [] away;
+                    }
+                    delete [] whichColumns;
+                    delete [] whichRows;
+               }
+          }
+     }
+     //firstFree_=-1;
+     /*  Note use of "down casting".  The only class the user sees is ClpSimplex.
+         Classes ClpSimplexDual, ClpSimplexPrimal, (ClpSimplexNonlinear)
+         and ClpSimplexOther all exist and inherit from ClpSimplex but have no
+         additional data and have no destructor or (non-default) constructor.
+
+         This is to stop classes becoming too unwieldy and so I (JJF) can use e.g. "perturb"
+         in primal and dual.
+
+         As far as I can see this is perfectly safe.
+     */
+     int returnCode = static_cast<ClpSimplexPrimal *> (this)->primal(ifValuesPass, startFinishOptions);
+     //int lastAlgorithm=1;
+     if (problemStatus_ == 10) {
+          //lastAlgorithm=-1;
+          //printf("Cleaning up with dual\n");
+          int savePerturbation = perturbation_;
+          perturbation_ = 100;
+          bool denseFactorization = initialDenseFactorization();
+          // It will be safe to allow dense
+          setInitialDenseFactorization(true);
+          // check which algorithms allowed
+          int dummy;
+          baseIteration_ = numberIterations_;
+          // Say second call
+          moreSpecialOptions_ |= 256;
+          if ((matrix_->generalExpanded(this, 4, dummy) & 2) != 0 && (specialOptions_ & 8192) == 0) {
+               double saveBound = dualBound_;
+               // upperOut_ has largest away from bound
+               dualBound_ = CoinMin(CoinMax(2.0 * upperOut_, 1.0e8), dualBound_);
+               returnCode = static_cast<ClpSimplexDual *> (this)->dual(0, startFinishOptions);
+               dualBound_ = saveBound;
+          } else {
+               returnCode = static_cast<ClpSimplexPrimal *> (this)->primal(0, startFinishOptions);
+          }
+          // Say not second call
+          moreSpecialOptions_ &= ~256;
+          baseIteration_ = 0;
+          setInitialDenseFactorization(denseFactorization);
+          perturbation_ = savePerturbation;
+          if (problemStatus_ == 10) {
+	      if (!numberPrimalInfeasibilities_) {
+                    problemStatus_ = 0;
+		    numberDualInfeasibilities_ = 0;
+	      } else {
+                    problemStatus_ = 4;
+	      }
+          }
+     }
+     //factorization_->pivotTolerance(savedPivotTolerance);
+     onStopped(); // set secondary status if stopped
+     //if (problemStatus_==1&&lastAlgorithm==1)
+     //returnCode=10; // so will do primal after postsolve
+     return returnCode;
+}
+#ifndef SLIM_CLP
+#include "ClpQuadraticObjective.hpp"
+/* Dual ranging.
+   This computes increase/decrease in cost for each given variable and corresponding
+   sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
+   and numberColumns.. for artificials/slacks.
+   For non-basic variables the sequence number will be that of the non-basic variables.
+
+   Up to user to provide correct length arrays.
+
+   Returns non-zero if infeasible unbounded etc
+*/
+#include "ClpSimplexOther.hpp"
+int ClpSimplex::dualRanging(int numberCheck, const int * which,
+                            double * costIncrease, int * sequenceIncrease,
+                            double * costDecrease, int * sequenceDecrease,
+                            double * valueIncrease, double * valueDecrease)
+{
+     int savePerturbation = perturbation_;
+     perturbation_ = 100;
+     /*int returnCode =*/ static_cast<ClpSimplexPrimal *> (this)->primal(0, 1);
+     if (problemStatus_ == 10) {
+          //printf("Cleaning up with dual\n");
+          bool denseFactorization = initialDenseFactorization();
+          // It will be safe to allow dense
+          setInitialDenseFactorization(true);
+          // check which algorithms allowed
+          int dummy;
+          if ((matrix_->generalExpanded(this, 4, dummy) & 2) != 0) {
+               // upperOut_ has largest away from bound
+               double saveBound = dualBound_;
+               if (upperOut_ > 0.0)
+                    dualBound_ = 2.0 * upperOut_;
+               /*returnCode =*/ static_cast<ClpSimplexDual *> (this)->dual(0, 1);
+               dualBound_ = saveBound;
+          } else {
+	        /*returnCode =*/ static_cast<ClpSimplexPrimal *> (this)->primal(0, 1);
+          }
+          setInitialDenseFactorization(denseFactorization);
+          if (problemStatus_ == 10)
+               problemStatus_ = 0;
+     }
+     perturbation_ = savePerturbation;
+     if (problemStatus_ || secondaryStatus_ == 6) {
+          finish(); // get rid of arrays
+          return 1; // odd status
+     }
+     static_cast<ClpSimplexOther *> (this)->dualRanging(numberCheck, which,
+               costIncrease, sequenceIncrease,
+               costDecrease, sequenceDecrease,
+               valueIncrease, valueDecrease);
+     finish(); // get rid of arrays
+     return 0;
+}
+/* Primal ranging.
+   This computes increase/decrease in value for each given variable and corresponding
+   sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
+   and numberColumns.. for artificials/slacks.
+   For basic variables the sequence number will be that of the basic variables.
+
+   Up to user to providen correct length arrays.
+
+   Returns non-zero if infeasible unbounded etc
+*/
+int ClpSimplex::primalRanging(int numberCheck, const int * which,
+                              double * valueIncrease, int * sequenceIncrease,
+                              double * valueDecrease, int * sequenceDecrease)
+{
+     int savePerturbation = perturbation_;
+     perturbation_ = 100;
+     /*int returnCode =*/ static_cast<ClpSimplexPrimal *> (this)->primal(0, 1);
+     if (problemStatus_ == 10) {
+          //printf("Cleaning up with dual\n");
+          bool denseFactorization = initialDenseFactorization();
+          // It will be safe to allow dense
+          setInitialDenseFactorization(true);
+          // check which algorithms allowed
+          int dummy;
+          if ((matrix_->generalExpanded(this, 4, dummy) & 2) != 0) {
+               // upperOut_ has largest away from bound
+               double saveBound = dualBound_;
+               if (upperOut_ > 0.0)
+                    dualBound_ = 2.0 * upperOut_;
+               /*returnCode =*/ static_cast<ClpSimplexDual *> (this)->dual(0, 1);
+               dualBound_ = saveBound;
+          } else {
+	        /*returnCode =*/ static_cast<ClpSimplexPrimal *> (this)->primal(0, 1);
+          }
+          setInitialDenseFactorization(denseFactorization);
+          if (problemStatus_ == 10)
+               problemStatus_ = 0;
+     }
+     perturbation_ = savePerturbation;
+     if (problemStatus_ || secondaryStatus_ == 6) {
+          finish(); // get rid of arrays
+          return 1; // odd status
+     }
+     static_cast<ClpSimplexOther *> (this)->primalRanging(numberCheck, which,
+               valueIncrease, sequenceIncrease,
+               valueDecrease, sequenceDecrease);
+     finish(); // get rid of arrays
+     return 0;
+}
+/* Write the basis in MPS format to the specified file.
+   If writeValues true writes values of structurals
+   (and adds VALUES to end of NAME card)
+
+   Row and column names may be null.
+   formatType is
+   <ul>
+   <li> 0 - normal
+   <li> 1 - extra accuracy
+   <li> 2 - IEEE hex (later)
+   </ul>
+
+   Returns non-zero on I/O error
+*/
+int
+ClpSimplex::writeBasis(const char *filename,
+                       bool writeValues,
+                       int formatType) const
+{
+     return static_cast<const ClpSimplexOther *> (this)->writeBasis(filename, writeValues,
+               formatType);
+}
+// Read a basis from the given filename
+int
+ClpSimplex::readBasis(const char *filename)
+{
+     return static_cast<ClpSimplexOther *> (this)->readBasis(filename);
+}
+#include "ClpSimplexNonlinear.hpp"
+/* Solves nonlinear problem using SLP - may be used as crash
+   for other algorithms when number of iterations small
+*/
+int
+ClpSimplex::nonlinearSLP(int numberPasses, double deltaTolerance)
+{
+     return static_cast<ClpSimplexNonlinear *> (this)->primalSLP(numberPasses, deltaTolerance);
+}
+/* Solves problem with nonlinear constraints using SLP - may be used as crash
+   for other algorithms when number of iterations small.
+   Also exits if all problematical variables are changing
+   less than deltaTolerance
+*/
+int
+ClpSimplex::nonlinearSLP(int numberConstraints, ClpConstraint ** constraints,
+                         int numberPasses, double deltaTolerance)
+{
+     return static_cast<ClpSimplexNonlinear *> (this)->primalSLP(numberConstraints, constraints, numberPasses, deltaTolerance);
+}
+// Solves non-linear using reduced gradient
+int ClpSimplex::reducedGradient(int phase)
+{
+     if (objective_->type() < 2 || !objective_->activated()) {
+          // no quadratic part
+          return primal(0);
+     }
+     // get feasible
+     if ((this->status() < 0 || numberPrimalInfeasibilities()) && phase == 0) {
+          objective_->setActivated(0);
+          double saveDirection = optimizationDirection();
+          setOptimizationDirection(0.0);
+          primal(1);
+          setOptimizationDirection(saveDirection);
+          objective_->setActivated(1);
+          // still infeasible
+          if (numberPrimalInfeasibilities())
+               return 0;
+     }
+     // Now enter method
+     int returnCode = static_cast<ClpSimplexNonlinear *> (this)->primal();
+     return returnCode;
+}
+#include "ClpPredictorCorrector.hpp"
+#include "ClpCholeskyBase.hpp"
+#include "ClpPresolve.hpp"
+/* Solves using barrier (assumes you have good cholesky factor code).
+   Does crossover to simplex if asked*/
+int
+ClpSimplex::barrier(bool crossover)
+{
+     ClpSimplex * model2 = this;
+     int savePerturbation = perturbation_;
+     ClpInterior barrier;
+     barrier.borrowModel(*model2);
+     // See if quadratic objective
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+     // If Quadratic we need KKT
+     bool doKKT = (quadraticObj != NULL);
+     // Preference is WSSMP, UFL, MUMPS, TAUCS then base
+#ifdef WSSMP_BARRIER
+     if (!doKKT) {
+          ClpCholeskyWssmp * cholesky = new ClpCholeskyWssmp(CoinMax(100, model2->numberRows() / 10));
+          barrier.setCholesky(cholesky);
+     } else {
+          //ClpCholeskyWssmp * cholesky = new ClpCholeskyWssmp();
+          ClpCholeskyWssmpKKT * cholesky = new ClpCholeskyWssmpKKT(CoinMax(100, model2->numberRows() / 10));
+          barrier.setCholesky(cholesky);
+     }
+#elif defined(COIN_HAS_AMD) || defined(COIN_HAS_CHOLMOD)
+     if (!doKKT) {
+          ClpCholeskyUfl * cholesky = new ClpCholeskyUfl();
+          barrier.setCholesky(cholesky);
+     } else {
+          ClpCholeskyBase * cholesky = new ClpCholeskyBase();
+          // not yetClpCholeskyUfl * cholesky = new ClpCholeskyUfl();
+          cholesky->setKKT(true);
+          barrier.setCholesky(cholesky);
+     }
+#elif TAUCS_BARRIER
+     assert (!doKKT);
+     ClpCholeskyTaucs * cholesky = new ClpCholeskyTaucs();
+     barrier.setCholesky(cholesky);
+#elifdef COIN_HAS_MUMPS
+     if (!doKKT) {
+          ClpCholeskyMumps * cholesky = new ClpCholeskyMumps();
+          barrier.setCholesky(cholesky);
+     } else {
+          printf("***** Unable to do Mumps with KKT\n");
+          ClpCholeskyBase * cholesky = new ClpCholeskyBase();
+          cholesky->setKKT(true);
+          barrier.setCholesky(cholesky);
+     }
+#else
+     if (!doKKT) {
+          ClpCholeskyBase * cholesky = new ClpCholeskyBase();
+          barrier.setCholesky(cholesky);
+     } else {
+          ClpCholeskyBase * cholesky = new ClpCholeskyBase();
+          cholesky->setKKT(true);
+          barrier.setCholesky(cholesky);
+     }
+#endif
+     barrier.setDiagonalPerturbation(1.0e-14);
+     int numberRows = model2->numberRows();
+     int numberColumns = model2->numberColumns();
+     int saveMaxIts = model2->maximumIterations();
+     if (saveMaxIts < 1000) {
+          barrier.setMaximumBarrierIterations(saveMaxIts);
+          model2->setMaximumIterations(1000000);
+     }
+     barrier.primalDual();
+     int barrierStatus = barrier.status();
+     double gap = static_cast<double>(barrier.complementarityGap());
+     // get which variables are fixed
+     double * saveLower = NULL;
+     double * saveUpper = NULL;
+     ClpPresolve pinfo2;
+     ClpSimplex * saveModel2 = NULL;
+     int numberFixed = barrier.numberFixed();
+     if (numberFixed * 20 > barrier.numberRows() && numberFixed > 5000 && crossover && 0) {
+          // may as well do presolve
+          int numberRows = barrier.numberRows();
+          int numberColumns = barrier.numberColumns();
+          int numberTotal = numberRows + numberColumns;
+          saveLower = new double [numberTotal];
+          saveUpper = new double [numberTotal];
+          CoinMemcpyN(barrier.columnLower(), numberColumns, saveLower);
+          CoinMemcpyN(barrier.rowLower(), numberRows, saveLower + numberColumns);
+          CoinMemcpyN(barrier.columnUpper(), numberColumns, saveUpper);
+          CoinMemcpyN(barrier.rowUpper(), numberRows, saveUpper + numberColumns);
+          barrier.fixFixed();
+          saveModel2 = model2;
+     }
+     barrier.returnModel(*model2);
+     double * rowPrimal = new double [numberRows];
+     double * columnPrimal = new double [numberColumns];
+     double * rowDual = new double [numberRows];
+     double * columnDual = new double [numberColumns];
+     // move solutions other way
+     CoinMemcpyN(model2->primalRowSolution(),
+                 numberRows, rowPrimal);
+     CoinMemcpyN(model2->dualRowSolution(),
+                 numberRows, rowDual);
+     CoinMemcpyN(model2->primalColumnSolution(),
+                 numberColumns, columnPrimal);
+     CoinMemcpyN(model2->dualColumnSolution(),
+                 numberColumns, columnDual);
+     if (saveModel2) {
+          // do presolve
+          model2 = pinfo2.presolvedModel(*model2, 1.0e-8,
+                                         false, 5, true);
+     }
+     if (barrierStatus < 4 && crossover) {
+          // make sure no status left
+          model2->createStatus();
+          // solve
+          model2->setPerturbation(100);
+          // throw some into basis
+          {
+               int numberRows = model2->numberRows();
+               int numberColumns = model2->numberColumns();
+               double * dsort = new double[numberColumns];
+               int * sort = new int[numberColumns];
+               int n = 0;
+               const double * columnLower = model2->columnLower();
+               const double * columnUpper = model2->columnUpper();
+               const double * primalSolution = model2->primalColumnSolution();
+               double tolerance = 10.0 * primalTolerance_;
+               int i;
+               for ( i = 0; i < numberRows; i++)
+                    model2->setRowStatus(i, superBasic);
+               for ( i = 0; i < numberColumns; i++) {
+                    double distance = CoinMin(columnUpper[i] - primalSolution[i],
+                                              primalSolution[i] - columnLower[i]);
+                    if (distance > tolerance) {
+                         dsort[n] = -distance;
+                         sort[n++] = i;
+                         model2->setStatus(i, superBasic);
+                    } else if (distance > primalTolerance_) {
+                         model2->setStatus(i, superBasic);
+                    } else if (primalSolution[i] <= columnLower[i] + primalTolerance_) {
+                         model2->setStatus(i, atLowerBound);
+                    } else {
+                         model2->setStatus(i, atUpperBound);
+                    }
+               }
+               CoinSort_2(dsort, dsort + n, sort);
+               n = CoinMin(numberRows, n);
+               for ( i = 0; i < n; i++) {
+                    int iColumn = sort[i];
+                    model2->setStatus(iColumn, basic);
+               }
+               delete [] sort;
+               delete [] dsort;
+          }
+          if (gap < 1.0e-3 * (static_cast<double> (numberRows + numberColumns))) {
+               int numberRows = model2->numberRows();
+               int numberColumns = model2->numberColumns();
+               // just primal values pass
+               double saveScale = model2->objectiveScale();
+               model2->setObjectiveScale(1.0e-3);
+               model2->primal(2);
+               model2->setObjectiveScale(saveScale);
+               // save primal solution and copy back dual
+               CoinMemcpyN(model2->primalRowSolution(),
+                           numberRows, rowPrimal);
+               CoinMemcpyN(rowDual,
+                           numberRows, model2->dualRowSolution());
+               CoinMemcpyN(model2->primalColumnSolution(),
+                           numberColumns, columnPrimal);
+               CoinMemcpyN(columnDual,
+                           numberColumns, model2->dualColumnSolution());
+               //model2->primal(1);
+               // clean up reduced costs and flag variables
+               {
+                    double * dj = model2->dualColumnSolution();
+                    double * cost = model2->objective();
+                    double * saveCost = new double[numberColumns];
+                    CoinMemcpyN(cost, numberColumns, saveCost);
+                    double * saveLower = new double[numberColumns];
+                    double * lower = model2->columnLower();
+                    CoinMemcpyN(lower, numberColumns, saveLower);
+                    double * saveUpper = new double[numberColumns];
+                    double * upper = model2->columnUpper();
+                    CoinMemcpyN(upper, numberColumns, saveUpper);
+                    int i;
+                    double tolerance = 10.0 * dualTolerance_;
+                    for ( i = 0; i < numberColumns; i++) {
+                         if (model2->getStatus(i) == basic) {
+                              dj[i] = 0.0;
+                         } else if (model2->getStatus(i) == atLowerBound) {
+                              if (optimizationDirection_ * dj[i] < tolerance) {
+                                   if (optimizationDirection_ * dj[i] < 0.0) {
+                                        //if (dj[i]<-1.0e-3)
+                                        //printf("bad dj at lb %d %g\n",i,dj[i]);
+                                        cost[i] -= dj[i];
+                                        dj[i] = 0.0;
+                                   }
+                              } else {
+                                   upper[i] = lower[i];
+                              }
+                         } else if (model2->getStatus(i) == atUpperBound) {
+                              if (optimizationDirection_ * dj[i] > tolerance) {
+                                   if (optimizationDirection_ * dj[i] > 0.0) {
+                                        //if (dj[i]>1.0e-3)
+                                        //printf("bad dj at ub %d %g\n",i,dj[i]);
+                                        cost[i] -= dj[i];
+                                        dj[i] = 0.0;
+                                   }
+                              } else {
+                                   lower[i] = upper[i];
+                              }
+                         }
+                    }
+                    // just dual values pass
+                    //model2->setLogLevel(63);
+                    //model2->setFactorizationFrequency(1);
+                    model2->dual(2);
+                    CoinMemcpyN(saveCost, numberColumns, cost);
+                    delete [] saveCost;
+                    CoinMemcpyN(saveLower, numberColumns, lower);
+                    delete [] saveLower;
+                    CoinMemcpyN(saveUpper, numberColumns, upper);
+                    delete [] saveUpper;
+               }
+               // and finish
+               // move solutions
+               CoinMemcpyN(rowPrimal,
+                           numberRows, model2->primalRowSolution());
+               CoinMemcpyN(columnPrimal,
+                           numberColumns, model2->primalColumnSolution());
+          }
+//     double saveScale = model2->objectiveScale();
+//     model2->setObjectiveScale(1.0e-3);
+//     model2->primal(2);
+//    model2->setObjectiveScale(saveScale);
+          model2->primal(1);
+     } else if (barrierStatus == 4 && crossover) {
+          // memory problems
+          model2->setPerturbation(savePerturbation);
+          model2->createStatus();
+          model2->dual();
+     }
+     model2->setMaximumIterations(saveMaxIts);
+     delete [] rowPrimal;
+     delete [] columnPrimal;
+     delete [] rowDual;
+     delete [] columnDual;
+     if (saveLower) {
+          pinfo2.postsolve(true);
+          delete model2;
+          model2 = saveModel2;
+          int numberRows = model2->numberRows();
+          int numberColumns = model2->numberColumns();
+          CoinMemcpyN(saveLower, numberColumns, model2->columnLower());
+          CoinMemcpyN(saveLower + numberColumns, numberRows, model2->rowLower());
+          delete [] saveLower;
+          CoinMemcpyN(saveUpper, numberColumns, model2->columnUpper());
+          CoinMemcpyN(saveUpper + numberColumns, numberRows, model2->rowUpper());
+          delete [] saveUpper;
+          model2->primal(1);
+     }
+     model2->setPerturbation(savePerturbation);
+     return model2->status();
+}
+/* For strong branching.  On input lower and upper are new bounds
+   while on output they are objective function values (>1.0e50 infeasible).
+   Return code is 0 if nothing interesting, -1 if infeasible both
+   ways and +1 if infeasible one way (check values to see which one(s))
+*/
+int ClpSimplex::strongBranching(int numberVariables, const int * variables,
+                                double * newLower, double * newUpper,
+                                double ** outputSolution,
+                                int * outputStatus, int * outputIterations,
+                                bool stopOnFirstInfeasible,
+                                bool alwaysFinish,
+                                int startFinishOptions)
+{
+     return static_cast<ClpSimplexDual *> (this)->strongBranching(numberVariables, variables,
+               newLower,  newUpper, outputSolution,
+               outputStatus, outputIterations,
+               stopOnFirstInfeasible,
+               alwaysFinish, startFinishOptions);
+}
+#endif
+/* Borrow model.  This is so we dont have to copy large amounts
+   of data around.  It assumes a derived class wants to overwrite
+   an empty model with a real one - while it does an algorithm.
+   This is same as ClpModel one, but sets scaling on etc. */
+void
+ClpSimplex::borrowModel(ClpModel & otherModel)
+{
+     ClpModel::borrowModel(otherModel);
+     createStatus();
+     //ClpDualRowSteepest steep1;
+     //setDualRowPivotAlgorithm(steep1);
+     //ClpPrimalColumnSteepest steep2;
+     //setPrimalColumnPivotAlgorithm(steep2);
+}
+void
+ClpSimplex::borrowModel(ClpSimplex & otherModel)
+{
+     ClpModel::borrowModel(otherModel);
+     createStatus();
+     dualBound_ = otherModel.dualBound_;
+     dualTolerance_ = otherModel.dualTolerance_;
+     primalTolerance_ = otherModel.primalTolerance_;
+     delete dualRowPivot_;
+     dualRowPivot_ = otherModel.dualRowPivot_->clone(true);
+     dualRowPivot_->setModel(this);
+     delete primalColumnPivot_;
+     primalColumnPivot_ = otherModel.primalColumnPivot_->clone(true);
+     primalColumnPivot_->setModel(this);
+     perturbation_ = otherModel.perturbation_;
+     moreSpecialOptions_ = otherModel.moreSpecialOptions_;
+     automaticScale_ = otherModel.automaticScale_;
+     maximumPerturbationSize_ = otherModel.maximumPerturbationSize_;
+     perturbationArray_ = otherModel.perturbationArray_;
+}
+/// Saves scalars for ClpSimplex
+typedef struct {
+     double optimizationDirection;
+     double dblParam[ClpLastDblParam];
+     double objectiveValue;
+     double dualBound;
+     double dualTolerance;
+     double primalTolerance;
+     double sumDualInfeasibilities;
+     double sumPrimalInfeasibilities;
+     double infeasibilityCost;
+     int numberRows;
+     int numberColumns;
+     int intParam[ClpLastIntParam];
+     int numberIterations;
+     int problemStatus;
+     int maximumIterations;
+     int lengthNames;
+     int numberDualInfeasibilities;
+     int numberDualInfeasibilitiesWithoutFree;
+     int numberPrimalInfeasibilities;
+     int numberRefinements;
+     int scalingFlag;
+     int algorithm;
+     unsigned int specialOptions;
+     int dualPivotChoice;
+     int primalPivotChoice;
+     int matrixStorageChoice;
+} Clp_scalars;
+#ifndef SLIM_NOIO
+int outDoubleArray(double * array, int length, FILE * fp)
+{
+     size_t numberWritten;
+     if (array && length) {
+          numberWritten = fwrite(&length, sizeof(int), 1, fp);
+          if (numberWritten != 1)
+               return 1;
+          numberWritten = fwrite(array, sizeof(double), length, fp);
+          if (numberWritten != static_cast<size_t>(length))
+               return 1;
+     } else {
+          length = 0;
+          numberWritten = fwrite(&length, sizeof(int), 1, fp);
+          if (numberWritten != 1)
+               return 1;
+     }
+     return 0;
+}
+// Save model to file, returns 0 if success
+int
+ClpSimplex::saveModel(const char * fileName)
+{
+     FILE * fp = fopen(fileName, "wb");
+     if (fp) {
+          Clp_scalars scalars;
+          size_t numberWritten;
+          // Fill in scalars
+          scalars.optimizationDirection = optimizationDirection_;
+          CoinMemcpyN( dblParam_, ClpLastDblParam, scalars.dblParam);
+          scalars.objectiveValue = objectiveValue_;
+          scalars.dualBound = dualBound_;
+          scalars.dualTolerance = dualTolerance_;
+          scalars.primalTolerance = primalTolerance_;
+          scalars.sumDualInfeasibilities = sumDualInfeasibilities_;
+          scalars.sumPrimalInfeasibilities = sumPrimalInfeasibilities_;
+          scalars.infeasibilityCost = infeasibilityCost_;
+          scalars.numberRows = numberRows_;
+          scalars.numberColumns = numberColumns_;
+          CoinMemcpyN( intParam_, ClpLastIntParam, scalars.intParam);
+          scalars.numberIterations = numberIterations_;
+          scalars.problemStatus = problemStatus_;
+          scalars.maximumIterations = maximumIterations();
+          scalars.lengthNames = lengthNames_;
+          scalars.numberDualInfeasibilities = numberDualInfeasibilities_;
+          scalars.numberDualInfeasibilitiesWithoutFree
+          = numberDualInfeasibilitiesWithoutFree_;
+          scalars.numberPrimalInfeasibilities = numberPrimalInfeasibilities_;
+          scalars.numberRefinements = numberRefinements_;
+          scalars.scalingFlag = scalingFlag_;
+          scalars.algorithm = algorithm_;
+          scalars.specialOptions = specialOptions_;
+          scalars.dualPivotChoice = dualRowPivot_->type();
+          scalars.primalPivotChoice = primalColumnPivot_->type();
+          scalars.matrixStorageChoice = matrix_->type();
+
+          // put out scalars
+          numberWritten = fwrite(&scalars, sizeof(Clp_scalars), 1, fp);
+          if (numberWritten != 1)
+               return 1;
+          size_t length;
+#ifndef CLP_NO_STD
+          int i;
+          // strings
+          for (i = 0; i < ClpLastStrParam; i++) {
+               length = strParam_[i].size();
+               numberWritten = fwrite(&length, sizeof(int), 1, fp);
+               if (numberWritten != 1)
+                    return 1;
+               if (length) {
+                    numberWritten = fwrite(strParam_[i].c_str(), length, 1, fp);
+                    if (numberWritten != 1)
+                         return 1;
+               }
+          }
+#endif
+          // arrays - in no particular order
+          if (outDoubleArray(rowActivity_, numberRows_, fp))
+               return 1;
+          if (outDoubleArray(columnActivity_, numberColumns_, fp))
+               return 1;
+          if (outDoubleArray(dual_, numberRows_, fp))
+               return 1;
+          if (outDoubleArray(reducedCost_, numberColumns_, fp))
+               return 1;
+          if (outDoubleArray(rowLower_, numberRows_, fp))
+               return 1;
+          if (outDoubleArray(rowUpper_, numberRows_, fp))
+               return 1;
+          if (outDoubleArray(objective(), numberColumns_, fp))
+               return 1;
+          if (outDoubleArray(rowObjective_, numberRows_, fp))
+               return 1;
+          if (outDoubleArray(columnLower_, numberColumns_, fp))
+               return 1;
+          if (outDoubleArray(columnUpper_, numberColumns_, fp))
+               return 1;
+          if (ray_) {
+               if (problemStatus_ == 1) {
+                    if (outDoubleArray(ray_, numberRows_, fp))
+                         return 1;
+               } else if (problemStatus_ == 2) {
+                    if (outDoubleArray(ray_, numberColumns_, fp))
+                         return 1;
+               } else {
+                    if (outDoubleArray(NULL, 0, fp))
+                         return 1;
+               }
+          } else {
+               if (outDoubleArray(NULL, 0, fp))
+                    return 1;
+          }
+          if (status_ && (numberRows_ + numberColumns_) > 0) {
+               length = numberRows_ + numberColumns_;
+               numberWritten = fwrite(&length, sizeof(int), 1, fp);
+               if (numberWritten != 1)
+                    return 1;
+               numberWritten = fwrite(status_, sizeof(char), length, fp);
+               if (numberWritten != length)
+                    return 1;
+          } else {
+               length = 0;
+               numberWritten = fwrite(&length, sizeof(int), 1, fp);
+               if (numberWritten != 1)
+                    return 1;
+          }
+#ifndef CLP_NO_STD
+          if (lengthNames_) {
+               char * array =
+                    new char[CoinMax(numberRows_, numberColumns_)*(lengthNames_+1)];
+               char * put = array;
+               CoinAssert (numberRows_ == static_cast<int> (rowNames_.size()));
+               for (i = 0; i < numberRows_; i++) {
+                    assert(static_cast<int>(rowNames_[i].size()) <= lengthNames_);
+                    strcpy(put, rowNames_[i].c_str());
+                    put += lengthNames_ + 1;
+               }
+               numberWritten = fwrite(array, lengthNames_ + 1, numberRows_, fp);
+               if (numberWritten != static_cast<size_t>(numberRows_))
+                    return 1;
+               put = array;
+               CoinAssert (numberColumns_ == static_cast<int> (columnNames_.size()));
+               for (i = 0; i < numberColumns_; i++) {
+                    assert(static_cast<int> (columnNames_[i].size()) <= lengthNames_);
+                    strcpy(put, columnNames_[i].c_str());
+                    put += lengthNames_ + 1;
+               }
+               numberWritten = fwrite(array, lengthNames_ + 1, numberColumns_, fp);
+               if (numberWritten != static_cast<size_t>(numberColumns_))
+                    return 1;
+               delete [] array;
+          }
+#endif
+          // integers
+          if (integerType_) {
+               int marker = 1;
+               numberWritten = fwrite(&marker, sizeof(int), 1, fp);
+               numberWritten = fwrite(integerType_, 1, numberColumns_, fp);
+               if (numberWritten != static_cast<size_t>(numberColumns_))
+                    return 1;
+          } else {
+               int marker = 0;
+               numberWritten = fwrite(&marker, sizeof(int), 1, fp);
+          }
+          // just standard type at present
+          assert (matrix_->type() == 1);
+          CoinAssert (matrix_->getNumCols() == numberColumns_);
+          CoinAssert (matrix_->getNumRows() == numberRows_);
+          // we are going to save with gaps
+          length = matrix_->getVectorStarts()[numberColumns_-1]
+                   + matrix_->getVectorLengths()[numberColumns_-1];
+          numberWritten = fwrite(&length, sizeof(int), 1, fp);
+          if (numberWritten != 1)
+               return 1;
+          numberWritten = fwrite(matrix_->getElements(),
+                                 sizeof(double), length, fp);
+          if (numberWritten != length)
+               return 1;
+          numberWritten = fwrite(matrix_->getIndices(),
+                                 sizeof(int), length, fp);
+          if (numberWritten != length)
+               return 1;
+          numberWritten = fwrite(matrix_->getVectorStarts(),
+                                 sizeof(int), numberColumns_ + 1, fp);
+          if (numberWritten != static_cast<size_t>(numberColumns_) + 1)
+               return 1;
+          numberWritten = fwrite(matrix_->getVectorLengths(),
+                                 sizeof(int), numberColumns_, fp);
+          if (numberWritten != static_cast<size_t>(numberColumns_))
+               return 1;
+          // finished
+          fclose(fp);
+          return 0;
+     } else {
+          return -1;
+     }
+}
+
+int inDoubleArray(double * &array, int length, FILE * fp)
+{
+     size_t numberRead;
+     int length2;
+     numberRead = fread(&length2, sizeof(int), 1, fp);
+     if (numberRead != 1)
+          return 1;
+     if (length2) {
+          // lengths must match
+          if (length != length2)
+               return 2;
+          array = new double[length];
+          numberRead = fread(array, sizeof(double), length, fp);
+          if (numberRead != static_cast<size_t>(length))
+               return 1;
+     }
+     return 0;
+}
+/* Restore model from file, returns 0 if success,
+   deletes current model */
+int
+ClpSimplex::restoreModel(const char * fileName)
+{
+     FILE * fp = fopen(fileName, "rb");
+     if (fp) {
+          // Get rid of current model
+          // save event handler in case already set
+          ClpEventHandler * handler = eventHandler_->clone();
+          ClpModel::gutsOfDelete(0);
+          eventHandler_ = handler;
+          gutsOfDelete(0);
+          int i;
+          for (i = 0; i < 6; i++) {
+               rowArray_[i] = NULL;
+               columnArray_[i] = NULL;
+          }
+          // get an empty factorization so we can set tolerances etc
+          getEmptyFactorization();
+          // Say sparse
+          factorization_->sparseThreshold(1);
+          Clp_scalars scalars;
+          size_t numberRead;
+
+          // get scalars
+          numberRead = fread(&scalars, sizeof(Clp_scalars), 1, fp);
+          if (numberRead != 1)
+               return 1;
+          // Fill in scalars
+          optimizationDirection_ = scalars.optimizationDirection;
+          CoinMemcpyN( scalars.dblParam, ClpLastDblParam, dblParam_);
+          objectiveValue_ = scalars.objectiveValue;
+          dualBound_ = scalars.dualBound;
+          dualTolerance_ = scalars.dualTolerance;
+          primalTolerance_ = scalars.primalTolerance;
+          sumDualInfeasibilities_ = scalars.sumDualInfeasibilities;
+          sumPrimalInfeasibilities_ = scalars.sumPrimalInfeasibilities;
+          infeasibilityCost_ = scalars.infeasibilityCost;
+          numberRows_ = scalars.numberRows;
+          numberColumns_ = scalars.numberColumns;
+          CoinMemcpyN( scalars.intParam, ClpLastIntParam, intParam_);
+          numberIterations_ = scalars.numberIterations;
+          problemStatus_ = scalars.problemStatus;
+          setMaximumIterations(scalars.maximumIterations);
+          lengthNames_ = scalars.lengthNames;
+          numberDualInfeasibilities_ = scalars.numberDualInfeasibilities;
+          numberDualInfeasibilitiesWithoutFree_
+          = scalars.numberDualInfeasibilitiesWithoutFree;
+          numberPrimalInfeasibilities_ = scalars.numberPrimalInfeasibilities;
+          numberRefinements_ = scalars.numberRefinements;
+          scalingFlag_ = scalars.scalingFlag;
+          algorithm_ = scalars.algorithm;
+          specialOptions_ = scalars.specialOptions;
+          // strings
+          CoinBigIndex length;
+#ifndef CLP_NO_STD
+          for (i = 0; i < ClpLastStrParam; i++) {
+               numberRead = fread(&length, sizeof(int), 1, fp);
+               if (numberRead != 1)
+                    return 1;
+               if (length) {
+                    char * array = new char[length+1];
+                    numberRead = fread(array, length, 1, fp);
+                    if (numberRead != 1)
+                         return 1;
+                    array[length] = '\0';
+                    strParam_[i] = array;
+                    delete [] array;
+               }
+          }
+#endif
+          // arrays - in no particular order
+          if (inDoubleArray(rowActivity_, numberRows_, fp))
+               return 1;
+          if (inDoubleArray(columnActivity_, numberColumns_, fp))
+               return 1;
+          if (inDoubleArray(dual_, numberRows_, fp))
+               return 1;
+          if (inDoubleArray(reducedCost_, numberColumns_, fp))
+               return 1;
+          if (inDoubleArray(rowLower_, numberRows_, fp))
+               return 1;
+          if (inDoubleArray(rowUpper_, numberRows_, fp))
+               return 1;
+          double * objective = NULL;
+          if (inDoubleArray(objective, numberColumns_, fp))
+               return 1;
+          delete objective_;
+          objective_ = new ClpLinearObjective(objective, numberColumns_);
+          delete [] objective;
+          if (inDoubleArray(rowObjective_, numberRows_, fp))
+               return 1;
+          if (inDoubleArray(columnLower_, numberColumns_, fp))
+               return 1;
+          if (inDoubleArray(columnUpper_, numberColumns_, fp))
+               return 1;
+          if (problemStatus_ == 1) {
+               if (inDoubleArray(ray_, numberRows_, fp))
+                    return 1;
+          } else if (problemStatus_ == 2) {
+               if (inDoubleArray(ray_, numberColumns_, fp))
+                    return 1;
+          } else {
+               // ray should be null
+               numberRead = fread(&length, sizeof(int), 1, fp);
+               if (numberRead != 1)
+                    return 1;
+               if (length)
+                    return 2;
+          }
+          delete [] status_;
+          status_ = NULL;
+          // status region
+          numberRead = fread(&length, sizeof(int), 1, fp);
+          if (numberRead != 1)
+               return 1;
+          if (length) {
+               if (length != numberRows_ + numberColumns_)
+                    return 1;
+               status_ = new char unsigned[length];
+               numberRead = fread(status_, sizeof(char), length, fp);
+               if (numberRead != static_cast<size_t>(length))
+                    return 1;
+          }
+#ifndef CLP_NO_STD
+          if (lengthNames_) {
+               char * array =
+                    new char[CoinMax(numberRows_, numberColumns_)*(lengthNames_+1)];
+               char * get = array;
+               numberRead = fread(array, lengthNames_ + 1, numberRows_, fp);
+               if (numberRead != static_cast<size_t>(numberRows_))
+                    return 1;
+               rowNames_ = std::vector<std::string> ();
+               rowNames_.resize(numberRows_);
+               for (i = 0; i < numberRows_; i++) {
+                    rowNames_.push_back(get);
+                    get += lengthNames_ + 1;
+               }
+               get = array;
+               numberRead = fread(array, lengthNames_ + 1, numberColumns_, fp);
+               if (numberRead != static_cast<size_t>(numberColumns_))
+                    return 1;
+               columnNames_ = std::vector<std::string> ();
+               columnNames_.resize(numberColumns_);
+               for (i = 0; i < numberColumns_; i++) {
+                    columnNames_.push_back(get);
+                    get += lengthNames_ + 1;
+               }
+               delete [] array;
+          }
+#endif
+          // integers
+          int ifInteger;
+          delete [] integerType_;
+          numberRead = fread(&ifInteger, sizeof(int), 1, fp);
+          // But try and stay compatible with previous version
+          bool alreadyGotLength = false;
+          if (numberRead != 1)
+               return 1;
+          if (ifInteger == 1) {
+               integerType_ = new char [numberColumns_];
+               numberRead = fread(integerType_, 1, numberColumns_, fp);
+               if (numberRead != static_cast<size_t>(numberColumns_))
+                    return 1;
+          } else {
+               integerType_ = NULL;
+               if (ifInteger) {
+                    // probably old style save
+                    alreadyGotLength = true;
+                    length = ifInteger;
+               }
+          }
+          // Pivot choices
+          assert(scalars.dualPivotChoice > 0 && (scalars.dualPivotChoice & 63) < 3);
+          delete dualRowPivot_;
+          switch ((scalars.dualPivotChoice & 63)) {
+          default:
+               printf("Need another dualPivot case %d\n", scalars.dualPivotChoice & 63);
+          case 1:
+               // Dantzig
+               dualRowPivot_ = new ClpDualRowDantzig();
+               break;
+          case 2:
+               // Steepest - use mode
+               dualRowPivot_ = new ClpDualRowSteepest(scalars.dualPivotChoice >> 6);
+               break;
+          }
+          assert(scalars.primalPivotChoice > 0 && (scalars.primalPivotChoice & 63) < 3);
+          delete primalColumnPivot_;
+          switch ((scalars.primalPivotChoice & 63)) {
+          default:
+               printf("Need another primalPivot case %d\n",
+                      scalars.primalPivotChoice & 63);
+          case 1:
+               // Dantzig
+               primalColumnPivot_ = new ClpPrimalColumnDantzig();
+               break;
+          case 2:
+               // Steepest - use mode
+               primalColumnPivot_
+               = new ClpPrimalColumnSteepest(scalars.primalPivotChoice >> 6);
+               break;
+          }
+          assert(scalars.matrixStorageChoice == 1);
+          delete matrix_;
+          // get arrays
+          if (!alreadyGotLength) {
+               numberRead = fread(&length, sizeof(int), 1, fp);
+               if (numberRead != 1)
+                    return 1;
+          }
+          double * elements = new double[length];
+          int * indices = new int[length];
+          CoinBigIndex * starts = new CoinBigIndex[numberColumns_+1];
+          int * lengths = new int[numberColumns_];
+          numberRead = fread(elements, sizeof(double), length, fp);
+          if (numberRead != static_cast<size_t>(length))
+               return 1;
+          numberRead = fread(indices, sizeof(int), length, fp);
+          if (numberRead != static_cast<size_t>(length))
+               return 1;
+          numberRead = fread(starts, sizeof(int), numberColumns_ + 1, fp);
+          if (numberRead != static_cast<size_t>(numberColumns_) + 1)
+               return 1;
+          numberRead = fread(lengths, sizeof(int), numberColumns_, fp);
+          if (numberRead != static_cast<size_t>(numberColumns_))
+               return 1;
+          // assign matrix
+          CoinPackedMatrix * matrix = new CoinPackedMatrix();
+          matrix->setExtraGap(0.0);
+          matrix->setExtraMajor(0.0);
+          // Pack down
+          length = 0;
+          for (i = 0; i < numberColumns_; i++) {
+               int start = starts[i];
+               starts[i] = length;
+               for (CoinBigIndex j = start; j < start + lengths[i]; j++) {
+                    elements[length] = elements[j];
+                    indices[length++] = indices[j];
+               }
+               lengths[i] = length - starts[i];
+          }
+          starts[numberColumns_] = length;
+          matrix->assignMatrix(true, numberRows_, numberColumns_,
+                               length, elements, indices, starts, lengths);
+          // and transfer to Clp
+          matrix_ = new ClpPackedMatrix(matrix);
+          // finished
+          fclose(fp);
+          return 0;
+     } else {
+          return -1;
+     }
+     return 0;
+}
+#endif
+// value of incoming variable (in Dual)
+double
+ClpSimplex::valueIncomingDual() const
+{
+     // Need value of incoming for list of infeasibilities as may be infeasible
+     double valueIncoming = (dualOut_ / alpha_) * directionOut_;
+     if (directionIn_ == -1)
+          valueIncoming = upperIn_ - valueIncoming;
+     else
+          valueIncoming = lowerIn_ - valueIncoming;
+     return valueIncoming;
+}
+// Sanity check on input data - returns true if okay
+bool
+ClpSimplex::sanityCheck()
+{
+     // bad if empty
+     if (!numberColumns_ || ((!numberRows_ || !matrix_->getNumElements()) && objective_->type() < 2)) {
+          int infeasNumber[2];
+          double infeasSum[2];
+          problemStatus_ = emptyProblem(infeasNumber, infeasSum, false);
+          numberDualInfeasibilities_ = infeasNumber[0];
+          sumDualInfeasibilities_ = infeasSum[0];
+          numberPrimalInfeasibilities_ = infeasNumber[1];
+          sumPrimalInfeasibilities_ = infeasSum[1];
+          return false;
+     }
+     int numberBad ;
+     double largestBound, smallestBound, minimumGap;
+     double smallestObj, largestObj;
+     int firstBad;
+     int modifiedBounds = 0;
+     int i;
+     numberBad = 0;
+     firstBad = -1;
+     minimumGap = 1.0e100;
+     smallestBound = 1.0e100;
+     largestBound = 0.0;
+     smallestObj = 1.0e100;
+     largestObj = 0.0;
+     // If bounds are too close - fix
+     double fixTolerance = primalTolerance_;
+     if (fixTolerance < 2.0e-8)
+          fixTolerance *= 1.1;
+     for (i = numberColumns_; i < numberColumns_ + numberRows_; i++) {
+          double value;
+          value = fabs(cost_[i]);
+          if (value > 1.0e50) {
+               numberBad++;
+               if (firstBad < 0)
+                    firstBad = i;
+          } else if (value) {
+               if (value > largestObj)
+                    largestObj = value;
+               if (value < smallestObj)
+                    smallestObj = value;
+          }
+          value = upper_[i] - lower_[i];
+          if (value < -primalTolerance_) {
+               numberBad++;
+               if (firstBad < 0)
+                    firstBad = i;
+          } else if (value <= fixTolerance) {
+               if (value) {
+                    // modify
+                    upper_[i] = lower_[i];
+                    modifiedBounds++;
+               }
+          } else {
+               if (value < minimumGap)
+                    minimumGap = value;
+          }
+          if (lower_[i] > -1.0e100 && lower_[i]) {
+               value = fabs(lower_[i]);
+               if (value > largestBound)
+                    largestBound = value;
+               if (value < smallestBound)
+                    smallestBound = value;
+          }
+          if (upper_[i] < 1.0e100 && upper_[i]) {
+               value = fabs(upper_[i]);
+               if (value > largestBound)
+                    largestBound = value;
+               if (value < smallestBound)
+                    smallestBound = value;
+          }
+     }
+     if (largestBound)
+          handler_->message(CLP_RIMSTATISTICS3, messages_)
+                    << smallestBound
+                    << largestBound
+                    << minimumGap
+                    << CoinMessageEol;
+     minimumGap = 1.0e100;
+     smallestBound = 1.0e100;
+     largestBound = 0.0;
+     for (i = 0; i < numberColumns_; i++) {
+          double value;
+          value = fabs(cost_[i]);
+          if (value > 1.0e50) {
+               numberBad++;
+               if (firstBad < 0)
+                    firstBad = i;
+          } else if (value) {
+               if (value > largestObj)
+                    largestObj = value;
+               if (value < smallestObj)
+                    smallestObj = value;
+          }
+          value = upper_[i] - lower_[i];
+          if (value < -primalTolerance_) {
+               numberBad++;
+               if (firstBad < 0)
+                    firstBad = i;
+          } else if (value <= fixTolerance) {
+               if (value) {
+                    // modify
+                    upper_[i] = lower_[i];
+                    modifiedBounds++;
+               }
+          } else {
+               if (value < minimumGap)
+                    minimumGap = value;
+          }
+          if (lower_[i] > -1.0e100 && lower_[i]) {
+               value = fabs(lower_[i]);
+               if (value > largestBound)
+                    largestBound = value;
+               if (value < smallestBound)
+                    smallestBound = value;
+          }
+          if (upper_[i] < 1.0e100 && upper_[i]) {
+               value = fabs(upper_[i]);
+               if (value > largestBound)
+                    largestBound = value;
+               if (value < smallestBound)
+                    smallestBound = value;
+          }
+     }
+     char rowcol[] = {'R', 'C'};
+     if (numberBad) {
+          handler_->message(CLP_BAD_BOUNDS, messages_)
+                    << numberBad
+                    << rowcol[isColumn(firstBad)] << sequenceWithin(firstBad)
+                    << CoinMessageEol;
+          problemStatus_ = 4;
+          return false;
+     }
+     if (modifiedBounds)
+          handler_->message(CLP_MODIFIEDBOUNDS, messages_)
+                    << modifiedBounds
+                    << CoinMessageEol;
+     handler_->message(CLP_RIMSTATISTICS1, messages_)
+               << smallestObj
+               << largestObj
+               << CoinMessageEol;
+     if (largestBound)
+          handler_->message(CLP_RIMSTATISTICS2, messages_)
+                    << smallestBound
+                    << largestBound
+                    << minimumGap
+                    << CoinMessageEol;
+     return true;
+}
+// Set up status array (for OsiClp)
+void
+ClpSimplex::createStatus()
+{
+     if(!status_)
+          status_ = new unsigned char [numberColumns_+numberRows_];
+     memset(status_, 0, (numberColumns_ + numberRows_)*sizeof(char));
+     int i;
+     // set column status to one nearest zero
+     for (i = 0; i < numberColumns_; i++) {
+#if 0
+          if (columnLower_[i] >= 0.0) {
+               setColumnStatus(i, atLowerBound);
+          } else if (columnUpper_[i] <= 0.0) {
+               setColumnStatus(i, atUpperBound);
+          } else if (columnLower_[i] < -1.0e20 && columnUpper_[i] > 1.0e20) {
+               // free
+               setColumnStatus(i, isFree);
+          } else if (fabs(columnLower_[i]) < fabs(columnUpper_[i])) {
+               setColumnStatus(i, atLowerBound);
+          } else {
+               setColumnStatus(i, atUpperBound);
+          }
+#else
+          setColumnStatus(i, atLowerBound);
+#endif
+     }
+     for (i = 0; i < numberRows_; i++) {
+          setRowStatus(i, basic);
+     }
+}
+/* Sets up all slack basis and resets solution to
+   as it was after initial load or readMps */
+void ClpSimplex::allSlackBasis(bool resetSolution)
+{
+     createStatus();
+     if (resetSolution) {
+          // put back to as it was originally
+          int i;
+          // set column status to one nearest zero
+          // But set value to zero if lb <0.0 and ub>0.0
+          for (i = 0; i < numberColumns_; i++) {
+               if (columnLower_[i] >= 0.0) {
+                    columnActivity_[i] = columnLower_[i];
+                    setColumnStatus(i, atLowerBound);
+               } else if (columnUpper_[i] <= 0.0) {
+                    columnActivity_[i] = columnUpper_[i];
+                    setColumnStatus(i, atUpperBound);
+               } else if (columnLower_[i] < -1.0e20 && columnUpper_[i] > 1.0e20) {
+                    // free
+                    columnActivity_[i] = 0.0;
+                    setColumnStatus(i, isFree);
+               } else if (fabs(columnLower_[i]) < fabs(columnUpper_[i])) {
+                    columnActivity_[i] = 0.0;
+                    setColumnStatus(i, atLowerBound);
+               } else {
+                    columnActivity_[i] = 0.0;
+                    setColumnStatus(i, atUpperBound);
+               }
+          }
+          if (solution_) {
+               // do that as well
+               if (!columnScale_) {
+                    for (i = 0; i < numberColumns_; i++) {
+                         solution_[i] = columnActivity_[i];
+                    }
+               } else {
+                    double * inverseColumnScale = columnScale_ + numberColumns_;
+                    for (i = 0; i < numberColumns_; i++) {
+                         solution_[i] = columnActivity_[i] * (rhsScale_ * inverseColumnScale[i]);
+                    }
+               }
+          }
+     }
+}
+/* Loads a problem (the constraints on the
+   rows are given by lower and upper bounds). If a pointer is 0 then the
+   following values are the default:
+   <ul>
+   <li> <code>colub</code>: all columns have upper bound infinity
+   <li> <code>collb</code>: all columns have lower bound 0
+   <li> <code>rowub</code>: all rows have upper bound infinity
+   <li> <code>rowlb</code>: all rows have lower bound -infinity
+   <li> <code>obj</code>: all variables have 0 objective coefficient
+   </ul>
+*/
+void
+ClpSimplex::loadProblem (  const ClpMatrixBase& matrix,
+                           const double* collb, const double* colub,
+                           const double* obj,
+                           const double* rowlb, const double* rowub,
+                           const double * rowObjective)
+{
+     ClpModel::loadProblem(matrix, collb, colub, obj, rowlb, rowub,
+                           rowObjective);
+     createStatus();
+}
+void
+ClpSimplex::loadProblem (  const CoinPackedMatrix& matrix,
+                           const double* collb, const double* colub,
+                           const double* obj,
+                           const double* rowlb, const double* rowub,
+                           const double * rowObjective)
+{
+     ClpModel::loadProblem(matrix, collb, colub, obj, rowlb, rowub,
+                           rowObjective);
+     createStatus();
+}
+
+/* Just like the other loadProblem() method except that the matrix is
+   given in a standard column major ordered format (without gaps). */
+void
+ClpSimplex::loadProblem (  const int numcols, const int numrows,
+                           const CoinBigIndex* start, const int* index,
+                           const double* value,
+                           const double* collb, const double* colub,
+                           const double* obj,
+                           const double* rowlb, const double* rowub,
+                           const double * rowObjective)
+{
+     ClpModel::loadProblem(numcols, numrows, start, index, value,
+                           collb, colub, obj, rowlb, rowub,
+                           rowObjective);
+     createStatus();
+}
+#ifndef SLIM_NOIO
+// This loads a model from a coinModel object - returns number of errors
+int
+ClpSimplex::loadProblem (  CoinModel & modelObject, bool /*keepSolution*/)
+{
+     unsigned char * status = NULL;
+     double * psol = NULL;
+     double * dsol = NULL;
+     if (status_ && numberRows_ && numberRows_ == modelObject.numberRows() &&
+               numberColumns_ == modelObject.numberColumns()) {
+          status = new unsigned char [numberRows_+numberColumns_];
+          CoinMemcpyN(status_, numberRows_ + numberColumns_, status);
+          psol = new double [numberRows_+numberColumns_];
+          CoinMemcpyN(columnActivity_, numberColumns_, psol);
+          CoinMemcpyN(rowActivity_, numberRows_, psol + numberColumns_);
+          dsol = new double [numberRows_+numberColumns_];
+          CoinMemcpyN(reducedCost_, numberColumns_, dsol);
+          CoinMemcpyN(dual_, numberRows_, dsol + numberColumns_);
+     }
+     int returnCode = ClpModel::loadProblem(modelObject);
+     const int * integerType = modelObject.integerTypeArray();
+     if (integerType) {
+          for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (integerType[iColumn])
+                    setInteger(iColumn);
+          }
+     }
+     createStatus();
+     if (status) {
+          // copy back
+          CoinMemcpyN(status, numberRows_ + numberColumns_, status_);
+          CoinMemcpyN(psol, numberColumns_, columnActivity_);
+          CoinMemcpyN(psol + numberColumns_, numberRows_, rowActivity_);
+          CoinMemcpyN(dsol, numberColumns_, reducedCost_);
+          CoinMemcpyN(dsol + numberColumns_, numberRows_, dual_);
+          delete [] status;
+          delete [] psol;
+          delete [] dsol;
+     }
+     optimizationDirection_ = modelObject.optimizationDirection();
+     return returnCode;
+}
+#endif
+void
+ClpSimplex::loadProblem (  const int numcols, const int numrows,
+                           const CoinBigIndex* start, const int* index,
+                           const double* value, const int * length,
+                           const double* collb, const double* colub,
+                           const double* obj,
+                           const double* rowlb, const double* rowub,
+                           const double * rowObjective)
+{
+     ClpModel::loadProblem(numcols, numrows, start, index, value, length,
+                           collb, colub, obj, rowlb, rowub,
+                           rowObjective);
+     createStatus();
+}
+#ifndef SLIM_NOIO
+// Read an mps file from the given filename
+int
+ClpSimplex::readMps(const char *filename,
+                    bool keepNames,
+                    bool ignoreErrors)
+{
+     int status = ClpModel::readMps(filename, keepNames, ignoreErrors);
+     createStatus();
+     return status;
+}
+// Read GMPL files from the given filenames
+int
+ClpSimplex::readGMPL(const char *filename, const char * dataName,
+                     bool keepNames)
+{
+     int status = ClpModel::readGMPL(filename, dataName, keepNames);
+     createStatus();
+     return status;
+}
+// Read file in LP format from file with name filename.
+int
+ClpSimplex::readLp(const char *filename, const double epsilon )
+{
+  FILE *fp;
+  if (strcmp(filename,"-"))
+    fp = fopen(filename, "r");
+  else
+    fp = stdin;
+
+     if(!fp) {
+          printf("### ERROR: ClpSimplex::readLp():  Unable to open file %s for reading\n",
+                 filename);
+          return(1);
+     }
+     CoinLpIO m;
+     m.readLp(fp, epsilon);
+     fclose(fp);
+
+     // set problem name
+     setStrParam(ClpProbName, m.getProblemName());
+     // no errors
+     loadProblem(*m.getMatrixByRow(), m.getColLower(), m.getColUpper(),
+                 m.getObjCoefficients(), m.getRowLower(), m.getRowUpper());
+
+     if (m.integerColumns()) {
+          integerType_ = new char[numberColumns_];
+          CoinMemcpyN(m.integerColumns(), numberColumns_, integerType_);
+     } else {
+          integerType_ = NULL;
+     }
+     createStatus();
+     unsigned int maxLength = 0;
+     int iRow;
+     rowNames_ = std::vector<std::string> ();
+     columnNames_ = std::vector<std::string> ();
+     rowNames_.reserve(numberRows_);
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          const char * name = m.rowName(iRow);
+          if (name) {
+               maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(name)));
+               rowNames_.push_back(name);
+          } else {
+               rowNames_.push_back("");
+          }
+     }
+
+     int iColumn;
+     columnNames_.reserve(numberColumns_);
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          const char * name = m.columnName(iColumn);
+          if (name) {
+               maxLength = CoinMax(maxLength, static_cast<unsigned int> (strlen(name)));
+               columnNames_.push_back(name);
+          } else {
+               columnNames_.push_back("");
+          }
+     }
+     lengthNames_ = static_cast<int> (maxLength);
+
+     return 0;
+}
+#endif
+// Just check solution (for external use)
+void
+ClpSimplex::checkSolution(int setToBounds)
+{
+     if (setToBounds) {
+          // Set all ones that look at bounds to bounds
+          bool changed = false;
+          int i;
+          for (i = 0; i < numberRows_; i++) {
+               double newValue = 0.0;
+               switch(getRowStatus(i)) {
+
+               case basic:
+                    newValue = rowActivity_[i];
+                    break;
+               case atUpperBound:
+                    newValue = rowUpper_[i];
+                    if (newValue > largeValue_) {
+                         if (rowLower_[i] > -largeValue_) {
+                              newValue = rowLower_[i];
+                              setRowStatus(i, atLowerBound);
+                         } else {
+                              // say free
+                              setRowStatus(i, isFree);
+                              newValue = 0.0;
+                         }
+                    }
+                    break;
+               case ClpSimplex::isFixed:
+               case atLowerBound:
+                    newValue = rowLower_[i];
+                    if (newValue < -largeValue_) {
+                         if (rowUpper_[i] < largeValue_) {
+                              newValue = rowUpper_[i];
+                              setRowStatus(i, atUpperBound);
+                         } else {
+                              // say free
+                              setRowStatus(i, isFree);
+                              newValue = 0.0;
+                         }
+                    }
+                    break;
+               case isFree:
+                    newValue = rowActivity_[i];
+                    break;
+                    // not really free - fall through to superbasic
+               case superBasic:
+                    if (rowUpper_[i] > largeValue_) {
+                         if (rowLower_[i] > -largeValue_) {
+                              newValue = rowLower_[i];
+                              setRowStatus(i, atLowerBound);
+                         } else {
+                              // say free
+                              setRowStatus(i, isFree);
+                              newValue = 0.0;
+                         }
+                    } else {
+                         if (rowLower_[i] > -largeValue_) {
+                              // set to nearest
+                              if (fabs(newValue - rowLower_[i])
+                                        < fabs(newValue - rowUpper_[i])) {
+                                   newValue = rowLower_[i];
+                                   setRowStatus(i, atLowerBound);
+                              } else {
+                                   newValue = rowUpper_[i];
+                                   setRowStatus(i, atUpperBound);
+                              }
+                         } else {
+                              newValue = rowUpper_[i];
+                              setRowStatus(i, atUpperBound);
+                         }
+                    }
+                    break;
+               }
+               if (fabs(newValue - rowActivity_[i]) > 1.0e-12) {
+                    changed = true;
+                    rowActivity_[i] = newValue;
+               }
+          }
+          for (i = 0; i < numberColumns_; i++) {
+               double newValue = 0.0;
+               switch(getColumnStatus(i)) {
+
+               case basic:
+                    newValue = columnActivity_[i];
+                    break;
+               case atUpperBound:
+                    newValue = columnUpper_[i];
+                    if (newValue > largeValue_) {
+                         if (columnLower_[i] > -largeValue_) {
+                              newValue = columnLower_[i];
+                              setColumnStatus(i, atLowerBound);
+                         } else {
+                              // say free
+                              setColumnStatus(i, isFree);
+                              newValue = 0.0;
+                         }
+                    }
+                    break;
+               case ClpSimplex::isFixed:
+               case atLowerBound:
+                    newValue = columnLower_[i];
+                    if (newValue < -largeValue_) {
+                         if (columnUpper_[i] < largeValue_) {
+                              newValue = columnUpper_[i];
+                              setColumnStatus(i, atUpperBound);
+                         } else {
+                              // say free
+                              setColumnStatus(i, isFree);
+                              newValue = 0.0;
+                         }
+                    }
+                    break;
+               case isFree:
+                    newValue = columnActivity_[i];
+                    break;
+                    // not really free - fall through to superbasic
+               case superBasic:
+                    if (columnUpper_[i] > largeValue_) {
+                         if (columnLower_[i] > -largeValue_) {
+                              newValue = columnLower_[i];
+                              setColumnStatus(i, atLowerBound);
+                         } else {
+                              // say free
+                              setColumnStatus(i, isFree);
+                              newValue = 0.0;
+                         }
+                    } else {
+                         if (columnLower_[i] > -largeValue_) {
+                              // set to nearest
+                              if (fabs(newValue - columnLower_[i])
+                                        < fabs(newValue - columnUpper_[i])) {
+                                   newValue = columnLower_[i];
+                                   setColumnStatus(i, atLowerBound);
+                              } else {
+                                   newValue = columnUpper_[i];
+                                   setColumnStatus(i, atUpperBound);
+                              }
+                         } else {
+                              newValue = columnUpper_[i];
+                              setColumnStatus(i, atUpperBound);
+                         }
+                    }
+                    break;
+               }
+               if (fabs(newValue - columnActivity_[i]) > 1.0e-12) {
+                    changed = true;
+                    columnActivity_[i] = newValue;
+               }
+          }
+          if (!changed && setToBounds == 1)
+               // no need to do anything
+               setToBounds = 0;
+     }
+     if (!setToBounds) {
+          // Just use column solution
+          CoinZeroN(rowActivity_, numberRows_);
+          matrix()->times(columnActivity_, rowActivity_) ;
+          // put in standard form
+          createRim(7 + 8 + 16 + 32);
+          dualTolerance_ = dblParam_[ClpDualTolerance];
+          primalTolerance_ = dblParam_[ClpPrimalTolerance];
+          checkPrimalSolution( rowActivityWork_, columnActivityWork_);
+          checkDualSolution();
+     } else {
+          startup(0, 0);
+          gutsOfSolution(NULL, NULL);
+     }
+     if (!numberDualInfeasibilities_ &&
+               !numberPrimalInfeasibilities_)
+          problemStatus_ = 0;
+     else
+          problemStatus_ = -1;
+#ifdef CLP_DEBUG
+     int i;
+     double value = 0.0;
+     for (i = 0; i < numberRows_ + numberColumns_; i++)
+          value += dj_[i] * solution_[i];
+     printf("dual value %g, primal %g\n", value, objectiveValue());
+#endif
+     // release extra memory
+     deleteRim(0);
+}
+// Check unscaled primal solution but allow for rounding error
+void 
+ClpSimplex::checkUnscaledSolution()
+{
+  if (problemStatus_==1 && matrix_->getNumElements()) {
+    const double * element = matrix_->getElements();
+    const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+    const int * columnLength = matrix_->getVectorLengths();
+    const int * row = matrix_->getIndices();
+    memset(rowActivity_,0,numberRows_*sizeof(double));
+    double * sum = new double [numberRows_+100000];
+    memset(sum,0,numberRows_*sizeof(double));
+    // clean column activity
+    for (int i=0;i<numberColumns_;i++) {
+      double value = columnActivity_[i];
+      value = CoinMax(value,columnLower_[i]);
+      value = CoinMin(value,columnUpper_[i]);
+      //columnActivity_[i]=value;
+      if (value) {
+	for (CoinBigIndex j=columnStart[i];
+	     j<columnStart[i]+columnLength[i];j++) {
+	  double value2 = value*element[j];
+	  int iRow = row[j];
+	  assert (iRow>=0&&iRow<numberRows_);
+	  rowActivity_[iRow] += value2;
+	  sum[iRow]+=fabs(value2);
+	}
+      }
+    }
+    sumPrimalInfeasibilities_ = 0.0;
+    numberPrimalInfeasibilities_ = 0;
+    double sumPrimalInfeasibilities2 = 0.0;
+    int numberPrimalInfeasibilities2 = 0;
+    double fudgeFactor = 1.0e-12;
+    double fudgeFactor2 = 1.0e-12;
+    double tolerance = primalTolerance_;
+    for (int i=0;i<numberRows_;i++) {
+      double useTolerance = CoinMax(tolerance,fudgeFactor*sum[i]);
+      double value = rowActivity_[i];
+      useTolerance = CoinMax(useTolerance,fudgeFactor2*fabs(value));
+      if (value>rowUpper_[i]) {
+	sumPrimalInfeasibilities2 += value - rowUpper_[i];
+	numberPrimalInfeasibilities2++;
+	if (value>rowUpper_[i]+useTolerance) {
+	  sumPrimalInfeasibilities_ += value - (rowUpper_[i]+useTolerance);
+	  numberPrimalInfeasibilities_++;
+	}
+      } else if (value<rowLower_[i]) {
+	sumPrimalInfeasibilities2 -= value - rowLower_[i];
+	numberPrimalInfeasibilities2++;
+	if (value<rowLower_[i]-useTolerance) {
+	  sumPrimalInfeasibilities_ -= value - (rowLower_[i]-useTolerance);
+	  numberPrimalInfeasibilities_++;
+	} 
+      }
+    }
+    char line[1000];
+    if (!numberPrimalInfeasibilities2) {
+      sprintf(line,"%d unscaled row infeasibilities - summing to %g",
+	      numberPrimalInfeasibilities2,
+	      sumPrimalInfeasibilities2);
+      handler_->message(CLP_GENERAL, messages_)
+	<< line
+	<< CoinMessageEol;
+    }
+    if (!numberPrimalInfeasibilities_) {
+      if (!numberDualInfeasibilities_) 
+	problemStatus_=0;
+    } else {
+      sprintf(line,"%d relaxed row infeasibilities - summing to %g",
+	    numberPrimalInfeasibilities_,
+	    sumPrimalInfeasibilities_);
+    handler_->message(CLP_GENERAL, messages_)
+                              << line
+                              << CoinMessageEol;
+    }
+    delete [] sum;
+  }
+}
+/* Crash - at present just aimed at dual, returns
+   -2 if dual preferred and crash basis created
+   -1 if dual preferred and all slack basis preferred
+   0 if basis going in was not all slack
+   1 if primal preferred and all slack basis preferred
+   2 if primal preferred and crash basis created.
+
+   if gap between bounds <="gap" variables can be flipped
+   ( If pivot -1 then can be made super basic!)
+
+   If "pivot" is
+   -1 No pivoting - always primal
+   0 No pivoting (so will just be choice of algorithm)
+   1 Simple pivoting e.g. gub
+   2 Mini iterations
+   3 Just throw all free variables in basis
+*/
+int
+ClpSimplex::crash(double gap, int pivot)
+{
+     //CoinAssert(!rowObjective_); // not coded
+     int iColumn;
+     int numberBad = 0;
+     int numberBasic = 0;
+     double dualTolerance = dblParam_[ClpDualTolerance];
+     //double primalTolerance=dblParam_[ClpPrimalTolerance];
+     int returnCode = 0;
+     // If no basis then make all slack one
+     if (!status_)
+          createStatus();
+
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (getColumnStatus(iColumn) == basic)
+               numberBasic++;
+     }
+     if (!numberBasic || pivot == 3) {
+#if 0
+          int nFree=0;
+	  for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+	    if (columnLower_[iColumn] < -1.0e20 && columnUpper_[iColumn] > 1.0e20) 
+	      nFree++;
+	  }
+	  if (nFree>numberColumns_/10)
+	    pivot=3;
+#endif
+          if (pivot == 3) {
+	    // Get column copy
+	    CoinPackedMatrix * columnCopy = matrix();
+	    const int * row = columnCopy->getIndices();
+	    const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+	    const int * columnLength = columnCopy->getVectorLengths();
+	    const double * element = columnCopy->getElements();
+	    int nFree=0;
+	    for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+	      if (columnLower_[iColumn] < -1.0e20 && columnUpper_[iColumn] > 1.0e20) {
+		// find triangular row
+		int kRow=-1;
+		double largest=0.0;
+		double largestOther=0.0;
+		for (CoinBigIndex j=columnStart[iColumn];
+		     j<columnStart[iColumn]+columnLength[iColumn];j++) {
+		  int iSequence=row[j]+numberColumns_;
+		  if (!flagged(iSequence)) {
+		    if (fabs(element[j])>largest) {
+		      kRow=row[j];
+		      largest=fabs(element[j]);
+		    }
+		  } else {
+		    if (fabs(element[j])>largestOther) {
+		      largestOther=fabs(element[j]);
+		    }
+		  }
+		}
+		if (kRow>=0&&largest*2.5>=largestOther) {
+		  nFree++;
+		  setColumnStatus(iColumn, basic);
+		  if (fabs(rowLower_[kRow]) < fabs(rowUpper_[kRow]))
+		    setRowStatus(kRow, atLowerBound);
+		  else
+		    setRowStatus(kRow, atUpperBound);
+		  for (CoinBigIndex j=columnStart[iColumn];
+		       j<columnStart[iColumn]+columnLength[iColumn];j++) {
+		    int iSequence=row[j]+numberColumns_;
+		    setFlagged(iSequence);
+		  }
+		}
+	      }
+	    }
+	    if (nFree) {
+	      for (int i=0;i<numberRows_;i++)
+		clearFlagged(i);
+	      printf("%d free variables put in basis\n",nFree);
+	      return 0;
+	    }
+          }
+          // all slack
+          double * dj = new double [numberColumns_];
+          double * solution = columnActivity_;
+          const double * linearObjective = objective();
+          //double objectiveValue=0.0;
+          int iColumn;
+          double direction = optimizationDirection_;
+          // direction is actually scale out not scale in
+          if (direction)
+               direction = 1.0 / direction;
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++)
+               dj[iColumn] = direction * linearObjective[iColumn];
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               // assume natural place is closest to zero
+               double lowerBound = columnLower_[iColumn];
+               double upperBound = columnUpper_[iColumn];
+               if (lowerBound > -1.0e20 || upperBound < 1.0e20) {
+                    bool atLower;
+                    if (fabs(upperBound) < fabs(lowerBound)) {
+                         atLower = false;
+                         setColumnStatus(iColumn, atUpperBound);
+                         solution[iColumn] = upperBound;
+                    } else {
+                         atLower = true;
+                         setColumnStatus(iColumn, atLowerBound);
+                         solution[iColumn] = lowerBound;
+                    }
+                    if (dj[iColumn] < -dualTolerance_) {
+                         // should be at upper bound
+                         if (atLower) {
+                              // can we flip
+                              if (upperBound - lowerBound <= gap) {
+                                   columnActivity_[iColumn] = upperBound;
+                                   setColumnStatus(iColumn, atUpperBound);
+                              } else if (pivot < 0) {
+                                   // set superbasic
+                                   columnActivity_[iColumn] = lowerBound + gap;
+                                   setColumnStatus(iColumn, superBasic);
+                              } else if (dj[iColumn] < -dualTolerance) {
+                                   numberBad++;
+                              }
+                         }
+                    } else if (dj[iColumn] > dualTolerance_) {
+                         // should be at lower bound
+                         if (!atLower) {
+                              // can we flip
+                              if (upperBound - lowerBound <= gap) {
+                                   columnActivity_[iColumn] = lowerBound;
+                                   setColumnStatus(iColumn, atLowerBound);
+                              } else if (pivot < 0) {
+                                   // set superbasic
+                                   columnActivity_[iColumn] = upperBound - gap;
+                                   setColumnStatus(iColumn, superBasic);
+                              } else if (dj[iColumn] > dualTolerance) {
+                                   numberBad++;
+                              }
+                         }
+                    }
+               } else {
+                    // free
+                    setColumnStatus(iColumn, isFree);
+                    if (fabs(dj[iColumn]) > dualTolerance)
+                         numberBad++;
+               }
+          }
+          if (numberBad || pivot) {
+               if (pivot <= 0) {
+                    delete [] dj;
+                    returnCode = 1;
+               } else {
+                    // see if can be made dual feasible with gubs etc
+                    double * pi = new double[numberRows_];
+                    memset (pi, 0, numberRows_ * sizeof(double));
+                    int * way = new int[numberColumns_];
+                    int numberIn = 0;
+
+                    // Get column copy
+                    CoinPackedMatrix * columnCopy = matrix();
+                    // Get a row copy in standard format
+                    CoinPackedMatrix copy;
+                    copy.setExtraGap(0.0);
+                    copy.setExtraMajor(0.0);
+                    copy.reverseOrderedCopyOf(*columnCopy);
+                    // get matrix data pointers
+                    const int * column = copy.getIndices();
+                    const CoinBigIndex * rowStart = copy.getVectorStarts();
+                    const int * rowLength = copy.getVectorLengths();
+                    const double * elementByRow = copy.getElements();
+                    //const int * row = columnCopy->getIndices();
+                    //const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+                    //const int * columnLength = columnCopy->getVectorLengths();
+                    //const double * element = columnCopy->getElements();
+
+
+                    // if equality row and bounds mean artificial in basis bad
+                    // then do anyway
+
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         // - if we want to reduce dj, + if we want to increase
+                         int thisWay = 100;
+                         double lowerBound = columnLower_[iColumn];
+                         double upperBound = columnUpper_[iColumn];
+                         if (upperBound > lowerBound) {
+                              switch(getColumnStatus(iColumn)) {
+
+                              case basic:
+                                   thisWay = 0;
+                              case ClpSimplex::isFixed:
+                                   break;
+                              case isFree:
+                              case superBasic:
+                                   if (dj[iColumn] < -dualTolerance)
+                                        thisWay = 1;
+                                   else if (dj[iColumn] > dualTolerance)
+                                        thisWay = -1;
+                                   else
+                                        thisWay = 0;
+                                   break;
+                              case atUpperBound:
+                                   if (dj[iColumn] > dualTolerance)
+                                        thisWay = -1;
+                                   else if (dj[iColumn] < -dualTolerance)
+                                        thisWay = -3;
+                                   else
+                                        thisWay = -2;
+                                   break;
+                              case atLowerBound:
+                                   if (dj[iColumn] < -dualTolerance)
+                                        thisWay = 1;
+                                   else if (dj[iColumn] > dualTolerance)
+                                        thisWay = 3;
+                                   else
+                                        thisWay = 2;
+                                   break;
+                              }
+                         }
+                         way[iColumn] = thisWay;
+                    }
+                    /*if (!numberBad)
+                      printf("Was dual feasible before passes - rows %d\n",
+                      numberRows_);*/
+                    int lastNumberIn = -100000;
+                    int numberPasses = 5;
+                    while (numberIn > lastNumberIn + numberRows_ / 100) {
+                         lastNumberIn = numberIn;
+                         // we need to maximize chance of doing good
+                         int iRow;
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              double lowerBound = rowLower_[iRow];
+                              double upperBound = rowUpper_[iRow];
+                              if (getRowStatus(iRow) == basic) {
+                                   // see if we can find a column to pivot on
+                                   int j;
+                                   // down is amount pi can go down
+                                   double maximumDown = COIN_DBL_MAX;
+                                   double maximumUp = COIN_DBL_MAX;
+                                   double minimumDown = 0.0;
+                                   double minimumUp = 0.0;
+                                   int iUp = -1;
+                                   int iDown = -1;
+                                   int iUpB = -1;
+                                   int iDownB = -1;
+                                   if (lowerBound < -1.0e20)
+                                        maximumUp = -1.0;
+                                   if (upperBound > 1.0e20)
+                                        maximumDown = -1.0;
+                                   for (j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+                                        int iColumn = column[j];
+                                        double value = elementByRow[j];
+                                        double djValue = dj[iColumn];
+                                        /* way -
+                                           -3 - okay at upper bound with negative dj
+                                           -2 - marginal at upper bound with zero dj - can only decrease
+                                           -1 - bad at upper bound
+                                           0 - we can never pivot on this row
+                                           1 - bad at lower bound
+                                           2 - marginal at lower bound with zero dj - can only increase
+                                           3 - okay at lower bound with positive dj
+                                           100 - fine we can just ignore
+                                        */
+                                        if (way[iColumn] != 100) {
+                                             switch(way[iColumn]) {
+
+                                             case -3:
+                                                  if (value > 0.0) {
+                                                       if (maximumDown * value > -djValue) {
+                                                            maximumDown = -djValue / value;
+                                                            iDown = iColumn;
+                                                       }
+                                                  } else {
+                                                       if (-maximumUp * value > -djValue) {
+                                                            maximumUp = djValue / value;
+                                                            iUp = iColumn;
+                                                       }
+                                                  }
+                                                  break;
+                                             case -2:
+                                                  if (value > 0.0) {
+                                                       maximumDown = 0.0;
+                                                  } else {
+                                                       maximumUp = 0.0;
+                                                  }
+                                                  break;
+                                             case -1:
+                                                  // see if could be satisfied
+                                                  // dj value > 0
+                                                  if (value > 0.0) {
+                                                       maximumDown = 0.0;
+                                                       if (maximumUp * value < djValue - dualTolerance) {
+                                                            maximumUp = 0.0; // would improve but not enough
+                                                       } else {
+                                                            if (minimumUp * value < djValue) {
+                                                                 minimumUp = djValue / value;
+                                                                 iUpB = iColumn;
+                                                            }
+                                                       }
+                                                  } else {
+                                                       maximumUp = 0.0;
+                                                       if (-maximumDown * value < djValue - dualTolerance) {
+                                                            maximumDown = 0.0; // would improve but not enough
+                                                       } else {
+                                                            if (-minimumDown * value < djValue) {
+                                                                 minimumDown = -djValue / value;
+                                                                 iDownB = iColumn;
+                                                            }
+                                                       }
+                                                  }
+
+                                                  break;
+                                             case 0:
+                                                  maximumDown = -1.0;
+                                                  maximumUp = -1.0;
+                                                  break;
+                                             case 1:
+                                                  // see if could be satisfied
+                                                  // dj value < 0
+                                                  if (value > 0.0) {
+                                                       maximumUp = 0.0;
+                                                       if (maximumDown * value < -djValue - dualTolerance) {
+                                                            maximumDown = 0.0; // would improve but not enough
+                                                       } else {
+                                                            if (minimumDown * value < -djValue) {
+                                                                 minimumDown = -djValue / value;
+                                                                 iDownB = iColumn;
+                                                            }
+                                                       }
+                                                  } else {
+                                                       maximumDown = 0.0;
+                                                       if (-maximumUp * value < -djValue - dualTolerance) {
+                                                            maximumUp = 0.0; // would improve but not enough
+                                                       } else {
+                                                            if (-minimumUp * value < -djValue) {
+                                                                 minimumUp = djValue / value;
+                                                                 iUpB = iColumn;
+                                                            }
+                                                       }
+                                                  }
+
+                                                  break;
+                                             case 2:
+                                                  if (value > 0.0) {
+                                                       maximumUp = 0.0;
+                                                  } else {
+                                                       maximumDown = 0.0;
+                                                  }
+
+                                                  break;
+                                             case 3:
+                                                  if (value > 0.0) {
+                                                       if (maximumUp * value > djValue) {
+                                                            maximumUp = djValue / value;
+                                                            iUp = iColumn;
+                                                       }
+                                                  } else {
+                                                       if (-maximumDown * value > djValue) {
+                                                            maximumDown = -djValue / value;
+                                                            iDown = iColumn;
+                                                       }
+                                                  }
+
+                                                  break;
+                                             default:
+                                                  break;
+                                             }
+                                        }
+                                   }
+                                   if (iUpB >= 0)
+                                        iUp = iUpB;
+                                   if (maximumUp <= dualTolerance || maximumUp < minimumUp)
+                                        iUp = -1;
+                                   if (iDownB >= 0)
+                                        iDown = iDownB;
+                                   if (maximumDown <= dualTolerance || maximumDown < minimumDown)
+                                        iDown = -1;
+                                   if (iUp >= 0 || iDown >= 0) {
+                                        // do something
+                                        if (iUp >= 0 && iDown >= 0) {
+                                             if (maximumDown > maximumUp)
+                                                  iUp = -1;
+                                        }
+                                        double change;
+                                        int kColumn;
+                                        if (iUp >= 0) {
+                                             kColumn = iUp;
+                                             change = maximumUp;
+                                             // just do minimum if was dual infeasible
+                                             // ? only if maximum large?
+                                             if (minimumUp > 0.0)
+                                                  change = minimumUp;
+                                             setRowStatus(iRow, atUpperBound);
+                                        } else {
+                                             kColumn = iDown;
+                                             change = -maximumDown;
+                                             // just do minimum if was dual infeasible
+                                             // ? only if maximum large?
+                                             if (minimumDown > 0.0)
+                                                  change = -minimumDown;
+                                             setRowStatus(iRow, atLowerBound);
+                                        }
+                                        assert (fabs(change) < 1.0e200);
+                                        setColumnStatus(kColumn, basic);
+                                        numberIn++;
+                                        pi[iRow] = change;
+                                        for (j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+                                             int iColumn = column[j];
+                                             double value = elementByRow[j];
+                                             double djValue = dj[iColumn] - change * value;
+                                             dj[iColumn] = djValue;
+                                             if (abs(way[iColumn]) == 1) {
+                                                  numberBad--;
+                                                  /*if (!numberBad)
+                                                    printf("Became dual feasible at row %d out of %d\n",
+                                                    iRow, numberRows_);*/
+                                                  lastNumberIn = -1000000;
+                                             }
+                                             int thisWay = 100;
+                                             double lowerBound = columnLower_[iColumn];
+                                             double upperBound = columnUpper_[iColumn];
+                                             if (upperBound > lowerBound) {
+                                                  switch(getColumnStatus(iColumn)) {
+
+                                                  case basic:
+                                                       thisWay = 0;
+                                                  case isFixed:
+                                                       break;
+                                                  case isFree:
+                                                  case superBasic:
+                                                       if (djValue < -dualTolerance)
+                                                            thisWay = 1;
+                                                       else if (djValue > dualTolerance)
+                                                            thisWay = -1;
+                                                       else {
+                                                            thisWay = 0;
+                                                       }
+                                                       break;
+                                                  case atUpperBound:
+                                                       if (djValue > dualTolerance) {
+                                                            thisWay = -1;
+                                                       } else if (djValue < -dualTolerance)
+                                                            thisWay = -3;
+                                                       else
+                                                            thisWay = -2;
+                                                       break;
+                                                  case atLowerBound:
+                                                       if (djValue < -dualTolerance) {
+                                                            thisWay = 1;
+                                                       } else if (djValue > dualTolerance)
+                                                            thisWay = 3;
+                                                       else
+                                                            thisWay = 2;
+                                                       break;
+                                                  }
+                                             }
+                                             way[iColumn] = thisWay;
+                                        }
+                                   }
+                              }
+                         }
+                         if (numberIn == lastNumberIn || numberBad || pivot < 2)
+                              break;
+                         if (!(--numberPasses))
+                              break;
+                         //printf("%d put in so far\n",numberIn);
+                    }
+                    // last attempt to flip
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         double lowerBound = columnLower_[iColumn];
+                         double upperBound = columnUpper_[iColumn];
+                         if (upperBound - lowerBound <= gap && upperBound > lowerBound) {
+                              double djValue = dj[iColumn];
+                              switch(getColumnStatus(iColumn)) {
+
+                              case basic:
+                              case ClpSimplex::isFixed:
+                                   break;
+                              case isFree:
+                              case superBasic:
+                                   break;
+                              case atUpperBound:
+                                   if (djValue > dualTolerance) {
+                                        setColumnStatus(iColumn, atUpperBound);
+                                        solution[iColumn] = upperBound;
+                                   }
+                                   break;
+                              case atLowerBound:
+                                   if (djValue < -dualTolerance) {
+                                        setColumnStatus(iColumn, atUpperBound);
+                                        solution[iColumn] = upperBound;
+                                   }
+                                   break;
+                              }
+                         }
+                    }
+                    delete [] pi;
+                    delete [] dj;
+                    delete [] way;
+                    handler_->message(CLP_CRASH, messages_)
+                              << numberIn
+                              << numberBad
+                              << CoinMessageEol;
+		    // could do elsewhere and could even if something done
+		    // see if some MUST be in basis
+		    if (!numberIn) {
+		    }
+                    returnCode =  -1;
+               }
+          } else {
+               delete [] dj;
+               returnCode =  -1;
+          }
+          //cleanStatus();
+     }
+     return returnCode;
+}
+/* Pivot in a variable and out a variable.  Returns 0 if okay,
+   1 if inaccuracy forced re-factorization, -1 if would be singular.
+   Also updates primal/dual infeasibilities.
+   Assumes sequenceIn_ and pivotRow_ set and also directionIn and Out.
+*/
+int ClpSimplex::pivot()
+{
+     // scaling not allowed
+     assert (!scalingFlag_);
+     // assume In_ and Out_ are correct and directionOut_ set
+     // (or In_ if flip
+     lowerIn_ = lower_[sequenceIn_];
+     valueIn_ = solution_[sequenceIn_];
+     upperIn_ = upper_[sequenceIn_];
+     dualIn_ = dj_[sequenceIn_];
+     lowerOut_ = lower_[sequenceOut_];
+     valueOut_ = solution_[sequenceOut_];
+     upperOut_ = upper_[sequenceOut_];
+     // for now assume primal is feasible (or in dual)
+     dualOut_ = dj_[sequenceOut_];
+     assert(fabs(dualOut_) < 1.0e-5);
+     bool roundAgain = true;
+     int returnCode = 0;
+     bool updateSolution = true;
+     while (roundAgain) {
+          roundAgain = false;
+          unpack(rowArray_[1]);
+          factorization_->updateColumnFT(rowArray_[2], rowArray_[1]);
+          alpha_ = 0.0;
+          int i;
+          int * index = rowArray_[1]->getIndices();
+          int number = rowArray_[1]->getNumElements();
+          double * element = rowArray_[1]->denseVector();
+          assert ( !rowArray_[3]->getNumElements());
+          double * saveSolution = rowArray_[3]->denseVector();
+          for (i = 0; i < number; i++) {
+               int ii = index[i];
+               if ( pivotVariable_[ii] == sequenceOut_) {
+                    pivotRow_ = ii;
+                    alpha_ = element[pivotRow_];
+                    break;
+               }
+          }
+          if (fabs(alpha_) < 1.0e-8) {
+               // be on safe side and clear arrays
+               rowArray_[0]->clear();
+               rowArray_[1]->clear();
+               return -1; // will be singular
+          }
+          // we are going to subtract movement from current basic
+          double movement;
+          // see where incoming will go to
+          if (sequenceOut_ < 0 || sequenceIn_ == sequenceOut_) {
+               // flip so go to bound
+               movement  = ((directionIn_ > 0) ? upperIn_ : lowerIn_) - valueIn_;
+          } else {
+               // get where outgoing needs to get to
+               double outValue = (directionOut_ < 0) ? upperOut_ : lowerOut_;
+               // solutionOut_ - movement*alpha_ == outValue
+               movement = (valueOut_ - outValue) / alpha_;
+               // set directionIn_ correctly
+               directionIn_ = (movement > 0) ? 1 : -1;
+          }
+          theta_ = movement;
+          double oldValueIn = valueIn_;
+          // update primal solution
+          for (i = 0; i < number; i++) {
+               int ii = index[i];
+               // get column
+               int ij = pivotVariable_[ii];
+               double value = element[ii];
+               saveSolution[ii] = solution_[ij];
+               solution_[ij] -= movement * value;
+          }
+          //rowArray_[1]->setNumElements(0);
+          // see where something went to
+#ifndef NDEBUG
+          CoinRelFltEq eq(1.0e-7);
+#endif
+          if (sequenceOut_ < 0) {
+               if (directionIn_ < 0) {
+                    assert (eq(solution_[sequenceIn_], upperIn_));
+                    solution_[sequenceIn_] = upperIn_;
+               } else {
+                    assert (eq(solution_[sequenceIn_], lowerIn_));
+                    solution_[sequenceIn_] = lowerIn_;
+               }
+          } else {
+               if (directionOut_ < 0) {
+                    assert (eq(solution_[sequenceOut_], upperOut_));
+                    solution_[sequenceOut_] = upperOut_;
+               } else {
+                    assert (eq(solution_[sequenceOut_], lowerOut_));
+                    solution_[sequenceOut_] = lowerOut_;
+               }
+               valueOut_ = solution_[sequenceOut_];
+               solution_[sequenceIn_] = valueIn_ + movement;
+          }
+          valueIn_ = solution_[sequenceIn_];
+          double objectiveChange = dualIn_ * movement;
+          // update duals
+          if (pivotRow_ >= 0) {
+               if (fabs(alpha_) < 1.0e-8) {
+                    // be on safe side and clear arrays
+                    rowArray_[0]->clear();
+                    rowArray_[1]->clear();
+                    return -1; // will be singular
+               }
+               double multiplier = dualIn_ / alpha_;
+               rowArray_[0]->insert(pivotRow_, multiplier);
+               factorization_->updateColumnTranspose(rowArray_[2], rowArray_[0]);
+               // put row of tableau in rowArray[0] and columnArray[0]
+               matrix_->transposeTimes(this, -1.0,
+                                       rowArray_[0], columnArray_[1], columnArray_[0]);
+               // update column djs
+               int i;
+               int * index = columnArray_[0]->getIndices();
+               int number = columnArray_[0]->getNumElements();
+               double * element = columnArray_[0]->denseVector();
+               for (i = 0; i < number; i++) {
+                    int ii = index[i];
+                    dj_[ii] += element[ii];
+                    reducedCost_[ii] = dj_[ii];
+                    element[ii] = 0.0;
+               }
+               columnArray_[0]->setNumElements(0);
+               // and row djs
+               index = rowArray_[0]->getIndices();
+               number = rowArray_[0]->getNumElements();
+               element = rowArray_[0]->denseVector();
+               for (i = 0; i < number; i++) {
+                    int ii = index[i];
+                    dj_[ii+numberColumns_] += element[ii];
+                    dual_[ii] = dj_[ii+numberColumns_];
+                    element[ii] = 0.0;
+               }
+               rowArray_[0]->setNumElements(0);
+               // check incoming
+               assert (fabs(dj_[sequenceIn_]) < 1.0e-6 || CoinAbs(solveType_) == 2);
+          }
+
+          // if stable replace in basis
+          int updateStatus = factorization_->replaceColumn(this,
+                             rowArray_[2],
+                             rowArray_[1],
+                             pivotRow_,
+                             alpha_);
+          bool takePivot = true;
+          // See if Factorization updated
+          if (updateStatus) {
+               updateSolution = false;
+               returnCode = 1;
+          }
+          // if no pivots, bad update but reasonable alpha - take and invert
+          if (updateStatus == 2 &&
+                    lastGoodIteration_ == numberIterations_ && fabs(alpha_) > 1.0e-5)
+               updateStatus = 4;
+          if (updateStatus == 1 || updateStatus == 4 || fabs(alpha_) < 1.0e-6) {
+               // slight error
+               if (factorization_->pivots() > 5 || updateStatus == 4) {
+                    returnCode = 1;
+               }
+          } else if (updateStatus == 2) {
+               // major error - put back solution
+               valueIn_ = oldValueIn;
+               solution_[sequenceIn_] = valueIn_;
+               int * index = rowArray_[1]->getIndices();
+               int number = rowArray_[1]->getNumElements();
+               for (i = 0; i < number; i++) {
+                    int ii = index[i];
+                    // get column
+                    int ij = pivotVariable_[ii];
+                    solution_[ij] = saveSolution[ii];
+               }
+               if (sequenceOut_ >= 0)
+                    valueOut_ = solution_[sequenceOut_];
+               takePivot = false;
+               if (factorization_->pivots()) {
+                    // refactorize here
+                    int factorStatus = internalFactorize(1);
+                    if (factorStatus) {
+                         printf("help in user pivot\n");
+                         abort();
+                    }
+                    gutsOfSolution(NULL, NULL);
+                    valueIn_ = solution_[sequenceIn_];
+                    if (sequenceOut_ >= 0)
+                         valueOut_ = solution_[sequenceOut_];
+                    roundAgain = true;
+               } else {
+                    returnCode = -1;
+               }
+          } else if (updateStatus == 3) {
+               // out of memory
+               // increase space if not many iterations
+               if (factorization_->pivots() <
+                         0.5 * factorization_->maximumPivots() &&
+                         factorization_->pivots() < 200)
+                    factorization_->areaFactor(
+                         factorization_->areaFactor() * 1.1);
+               returnCode = 1; // factorize now
+          }
+          {
+               // clear saveSolution
+               int * index = rowArray_[1]->getIndices();
+               int number = rowArray_[1]->getNumElements();
+               for (i = 0; i < number; i++) {
+                    int ii = index[i];
+                    saveSolution[ii] = 0.0;
+               }
+          }
+          rowArray_[1]->clear();
+          if (takePivot) {
+               int save = algorithm_;
+               // make simple so always primal
+               algorithm_ = 1;
+               housekeeping(objectiveChange);
+               algorithm_ = save;
+          }
+     }
+     if (returnCode == 1) {
+          // refactorize here
+          int factorStatus = internalFactorize(1);
+          if (factorStatus) {
+               printf("help in user pivot\n");
+               abort();
+          }
+          updateSolution = true;
+     }
+     if (updateSolution) {
+          // just for now - recompute anyway
+          gutsOfSolution(NULL, NULL);
+     }
+     return returnCode;
+}
+
+/* Pivot in a variable and choose an outgoing one.  Assumes primal
+   feasible - will not go through a bound.  Returns step length in theta
+   Returns ray in ray_ (or NULL if no pivot)
+   Return codes as before but -1 means no acceptable pivot
+*/
+int ClpSimplex::primalPivotResult()
+{
+     assert (sequenceIn_ >= 0);
+     valueIn_ = solution_[sequenceIn_];
+     lowerIn_ = lower_[sequenceIn_];
+     upperIn_ = upper_[sequenceIn_];
+     dualIn_ = dj_[sequenceIn_];
+     if (!nonLinearCost_)
+       nonLinearCost_ = new ClpNonLinearCost(this);
+      
+
+     int returnCode = static_cast<ClpSimplexPrimal *> (this)->pivotResult();
+     if (returnCode < 0 && returnCode > -4) {
+          return 0;
+     } else {
+          COIN_DETAIL_PRINT(printf("Return code of %d from ClpSimplexPrimal::pivotResult\n",
+				   returnCode));
+          return -1;
+     }
+}
+// Factorization frequency
+int
+ClpSimplex::factorizationFrequency() const
+{
+     if (factorization_)
+          return factorization_->maximumPivots();
+     else
+          return -1;
+}
+void
+ClpSimplex::setFactorizationFrequency(int value)
+{
+     if (factorization_)
+          factorization_->maximumPivots(value);
+}
+// Common bits of coding for dual and primal
+int
+ClpSimplex::startup(int ifValuesPass, int startFinishOptions)
+{
+     // Get rid of some arrays and empty factorization
+     int useFactorization = false;
+     if ((startFinishOptions & 2) != 0 && (whatsChanged_&(2 + 512)) == 2 + 512)
+          useFactorization = true; // Keep factorization if possible
+#if 0
+     // seems to be needed if rows deleted later in CbcModel!
+     if (!solution_ && scaledMatrix_) {
+          // get rid of scaled matrix
+          if (scaledMatrix_->getNumRows() != numberRows_) {
+               delete scaledMatrix_;
+               scaledMatrix_ = NULL;
+          }
+     }
+#endif
+     // sanity check
+     // bad if empty (trap here to avoid using bad matrix_)
+#if 0
+     // but also check bounds
+     {
+          int badProblem = 0;
+          int i;
+          for (i = 0; i < numberColumns_; i++) {
+               if (columnLower_[i] > columnUpper_[i])
+                    badProblem++;
+          }
+          for (i = 0; i < numberRows_; i++) {
+               if (rowLower_[i] > rowUpper_[i])
+                    badProblem++;
+          }
+          if (badProblem) {
+               numberDualInfeasibilities_ = 0;
+               sumDualInfeasibilities_ = 0.0;
+               numberPrimalInfeasibilities_ = badProblem;
+               sumPrimalInfeasibilities_ = badProblem;
+               secondaryStatus_ = 6; // so user can see something odd
+               problemStatus_ = 1;
+               bool printIt = (specialOptions_ & 32768) == 0 ? true : false; // no message if from Osi
+               if (printIt)
+                    handler_->message(CLP_INFEASIBLE, messages_)
+                              << CoinMessageEol;
+               return 2;
+          }
+     }
+#endif
+     if (!matrix_ || (!matrix_->getNumElements() && objective_->type() < 2)) {
+          int infeasNumber[2];
+          double infeasSum[2];
+          bool printIt = (specialOptions_ & 32768) == 0 ? true : false; // no message if from Osi
+          problemStatus_ = emptyProblem(infeasNumber, infeasSum, printIt);
+          if ((startFinishOptions & 1) != 0) {
+               // User may expect user data - fill in as required
+               if (numberRows_) {
+                    if (!pivotVariable_)
+                         pivotVariable_ = new int [numberRows_];
+                    CoinIotaN(pivotVariable_, numberRows_, numberColumns_);
+               }
+          }
+          numberDualInfeasibilities_ = infeasNumber[0];
+          sumDualInfeasibilities_ = infeasSum[0];
+          numberPrimalInfeasibilities_ = infeasNumber[1];
+          sumPrimalInfeasibilities_ = infeasSum[1];
+          return 2;
+     }
+     pivotRow_ = -1;
+     sequenceIn_ = -1;
+     sequenceOut_ = -1;
+     secondaryStatus_ = 0;
+
+     primalTolerance_ = dblParam_[ClpPrimalTolerance];
+     dualTolerance_ = dblParam_[ClpDualTolerance];
+     if (problemStatus_ != 10)
+          numberIterations_ = 0;
+
+     // put in standard form (and make row copy)
+     // create modifiable copies of model rim and do optional scaling
+     bool goodMatrix = createRim(7 + 8 + 16 + 32, true, startFinishOptions);
+
+     if (goodMatrix) {
+          // switch off factorization if bad
+          if (pivotVariable_[0] < 0)
+               useFactorization = false;
+          // Model looks okay
+          // Do initial factorization
+          // and set certain stuff
+          // We can either set increasing rows so ...IsBasic gives pivot row
+          // or we can just increment iBasic one by one
+          // for now let ...iBasic give pivot row
+          int saveThreshold = factorization_->denseThreshold();
+          if (!useFactorization || factorization_->numberRows() != numberRows_) {
+               useFactorization = false;
+               factorization_->setDefaultValues();
+               // Switch off dense (unless special option set)
+               if ((specialOptions_ & 8) == 0)
+                    factorization_->setDenseThreshold(0);
+          }
+          // If values pass then perturb (otherwise may be optimal so leave a bit)
+          if (ifValuesPass) {
+               // do perturbation if asked for
+
+               if (perturbation_ < 100) {
+                    if (algorithm_ > 0 && (objective_->type() < 2 || !objective_->activated())) {
+#ifndef FEB_TRY
+		      //static_cast<ClpSimplexPrimal *> (this)->perturb(0);
+#endif
+                    } else if (algorithm_ < 0) {
+                         static_cast<ClpSimplexDual *> (this)->perturb();
+                    }
+               }
+          }
+          // for primal we will change bounds using infeasibilityCost_
+          if (nonLinearCost_ == NULL && algorithm_ > 0) {
+               // get a valid nonlinear cost function
+               nonLinearCost_ = new ClpNonLinearCost(this);
+          }
+
+          // loop round to clean up solution if values pass
+          int numberThrownOut = -1;
+          int totalNumberThrownOut = 0;
+          problemStatus_ = -1;
+          // see if we are re-using factorization
+          if (!useFactorization) {
+               while(numberThrownOut) {
+                    int status = internalFactorize(ifValuesPass ? 10 : 0);
+                    if (status < 0)
+                         return 1; // some error
+                    else
+                         numberThrownOut = status;
+
+                    // for this we need clean basis so it is after factorize
+                    if (!numberThrownOut || numberThrownOut == numberRows_ + 1) {
+                         // solution will be done again - skip if absolutely sure
+                         if ((specialOptions_ & 512) == 0 || numberThrownOut == numberRows_ + 1) {
+                              //int saveFirstFree=firstFree_;
+                              numberThrownOut = gutsOfSolution(  NULL, NULL,
+                                                                 ifValuesPass != 0);
+                              //firstFree_=saveFirstFree;
+                              if (largestPrimalError_ > 10.0 && !ifValuesPass && !numberThrownOut) {
+                                   // throw out up to 1000 structurals
+                                   int iRow;
+                                   int * sort = new int[numberRows_];
+                                   double * array = rowArray_[0]->denseVector();
+                                   memset(array, 0, numberRows_ * sizeof(double));
+                                   times(-1.0, columnActivityWork_, array);
+                                   int numberBasic = 0;
+                                   for (iRow = 0; iRow < numberRows_; iRow++) {
+                                        int iPivot = pivotVariable_[iRow];
+                                        if (iPivot < numberColumns_) {
+                                             // column
+                                             double difference = fabs(array[iRow] + rowActivityWork_[iRow]);
+                                             if (difference > 1.0e-4) {
+                                                  sort[numberThrownOut] = iPivot;
+                                                  array[numberThrownOut++] = difference;
+                                                  if (getStatus(iPivot) == basic)
+                                                       numberBasic++;
+                                             }
+                                        }
+                                   }
+                                   if (!numberBasic) {
+                                        allSlackBasis(true);
+                                        numberThrownOut = 1; // force another go
+                                   } else {
+                                        CoinSort_2(array, array + numberThrownOut, sort);
+                                        numberThrownOut = CoinMin(1000, numberThrownOut);
+                                        for (iRow = 0; iRow < numberThrownOut; iRow++) {
+                                             int iColumn = sort[iRow];
+                                             setColumnStatus(iColumn, superBasic);
+                                             if (fabs(solution_[iColumn]) > 1.0e10) {
+                                                  if (upper_[iColumn] < 0.0) {
+                                                       solution_[iColumn] = upper_[iColumn];
+                                                  } else if (lower_[iColumn] > 0.0) {
+                                                       solution_[iColumn] = lower_[iColumn];
+                                                  } else {
+                                                       solution_[iColumn] = 0.0;
+                                                  }
+                                             }
+                                        }
+                                   }
+                                   CoinZeroN(array, numberRows_);
+                                   delete [] sort;
+                              }
+                         } else {
+                              // make sure not optimal at once
+                              numberPrimalInfeasibilities_ = 1;
+                              numberThrownOut = 0;
+                         }
+                    } else {
+                         matrix_->rhsOffset(this, true); // redo rhs offset
+                    }
+                    totalNumberThrownOut += numberThrownOut;
+
+               }
+          } else {
+               // using previous factorization - we assume fine
+               if ((moreSpecialOptions_ & 8) == 0) {
+                    // but we need to say not optimal
+                    numberPrimalInfeasibilities_ = 1;
+                    numberDualInfeasibilities_ = 1;
+               }
+               matrix_->rhsOffset(this, true); // redo rhs offset
+          }
+          if (totalNumberThrownOut)
+               handler_->message(CLP_SINGULARITIES, messages_)
+                         << totalNumberThrownOut
+                         << CoinMessageEol;
+          // Switch back dense
+          factorization_->setDenseThreshold(saveThreshold);
+
+          if (!numberPrimalInfeasibilities_ && !numberDualInfeasibilities_
+                    && !ifValuesPass &&
+                    (!nonLinearCost_ || !nonLinearCost_->numberInfeasibilities()))
+               problemStatus_ = 0;
+          else
+               assert(problemStatus_ == -1);
+
+          // number of times we have declared optimality
+          numberTimesOptimal_ = 0;
+          if (disasterArea_)
+               disasterArea_->intoSimplex();
+
+          return 0;
+     } else {
+          // bad matrix
+          return 2;
+     }
+
+}
+
+/* Get a clean factorization - i.e. throw out singularities
+    may do more later */
+int
+ClpSimplex::cleanFactorization(int ifValuesPass)
+{
+  int status = internalFactorize(ifValuesPass ? 10 : 0);
+  if (status < 0) {
+    return 1; // some error
+  } else {
+    firstFree_=0;
+    return 0;
+  }
+}
+
+void
+ClpSimplex::finish(int startFinishOptions)
+{
+     // Get rid of some arrays and empty factorization
+     int getRidOfData = 1;
+     if (upper_ && ((startFinishOptions & 1) != 0 || problemStatus_ == 10)) {
+          getRidOfData = 0; // Keep stuff
+          // mark all as current
+          whatsChanged_ = 0x3ffffff;
+     } else {
+          whatsChanged_ &= ~0xffff;
+     }
+     double saveObjValue = objectiveValue_;
+     deleteRim(getRidOfData);
+     if (matrix_->type()>=15)
+       objectiveValue_ = saveObjValue;
+     // Skip message if changing algorithms
+     if (problemStatus_ != 10) {
+          if (problemStatus_ == -1)
+               problemStatus_ = 4;
+          assert(problemStatus_ >= 0 && problemStatus_ < 6);
+          if (handler_->detail(CLP_SIMPLEX_FINISHED, messages_) < 100) {
+               handler_->message(CLP_SIMPLEX_FINISHED + problemStatus_, messages_)
+                         << objectiveValue()
+                         << CoinMessageEol;
+          }
+     }
+     factorization_->relaxAccuracyCheck(1.0);
+     // get rid of any network stuff - could do more
+     factorization_->cleanUp();
+}
+// Save data
+ClpDataSave
+ClpSimplex::saveData()
+{
+     ClpDataSave saved;
+     saved.dualBound_ = dualBound_;
+     saved.infeasibilityCost_ = infeasibilityCost_;
+     saved.sparseThreshold_ = factorization_->sparseThreshold();
+     saved.pivotTolerance_ = factorization_->pivotTolerance();
+     saved.zeroFactorizationTolerance_ = factorization_->zeroTolerance();
+     saved.zeroSimplexTolerance_ = zeroTolerance_;
+     saved.perturbation_ = perturbation_;
+     saved.forceFactorization_ = forceFactorization_;
+     saved.acceptablePivot_ = acceptablePivot_;
+     saved.objectiveScale_ = objectiveScale_;
+     // Progress indicator
+     progress_.fillFromModel (this);
+     return saved;
+}
+// Restore data
+void
+ClpSimplex::restoreData(ClpDataSave saved)
+{
+     //factorization_->sparseThreshold(saved.sparseThreshold_);
+     factorization_->pivotTolerance(saved.pivotTolerance_);
+     factorization_->zeroTolerance(saved.zeroFactorizationTolerance_);
+     zeroTolerance_ = saved.zeroSimplexTolerance_;
+     perturbation_ = saved.perturbation_;
+     infeasibilityCost_ = saved.infeasibilityCost_;
+     dualBound_ = saved.dualBound_;
+     forceFactorization_ = saved.forceFactorization_;
+     objectiveScale_ = saved.objectiveScale_;
+     acceptablePivot_ = saved.acceptablePivot_;
+}
+// To flag a variable (not inline to allow for column generation)
+void
+ClpSimplex::setFlagged( int sequence)
+{
+     status_[sequence] |= 64;
+     matrix_->generalExpanded(this, 7, sequence);
+     lastFlaggedIteration_ = numberIterations_;
+}
+/* Factorizes and returns true if optimal.  Used by user */
+bool
+ClpSimplex::statusOfProblem(bool initial)
+{
+     // We don't want scaling
+     int saveFlag = scalingFlag_;
+     if (!rowScale_)
+          scalingFlag_ = 0;
+     bool goodMatrix = createRim(7 + 8 + 16 + 32);
+     if (!goodMatrix) {
+          problemStatus_ = 4;
+          scalingFlag_ = saveFlag;
+          return false;
+     }
+     // is factorization okay?
+     if (initial) {
+          // First time - allow singularities
+          int numberThrownOut = -1;
+          int totalNumberThrownOut = 0;
+          while(numberThrownOut) {
+               int status = internalFactorize(0);
+               if (status == numberRows_ + 1)
+                    status = 0; // all slack
+               if (status < 0) {
+                    deleteRim(-1);
+                    scalingFlag_ = saveFlag;
+                    return false; // some error
+               } else {
+                    numberThrownOut = status;
+               }
+
+               // for this we need clean basis so it is after factorize
+               //if (!numberThrownOut)
+               //numberThrownOut = gutsOfSolution(  NULL,NULL,
+               //				   false);
+               //else
+               //matrix_->rhsOffset(this,true); // redo rhs offset
+               totalNumberThrownOut += numberThrownOut;
+
+          }
+
+          if (totalNumberThrownOut)
+               handler_->message(CLP_SINGULARITIES, messages_)
+                         << totalNumberThrownOut
+                         << CoinMessageEol;
+     } else {
+#ifndef NDEBUG
+          int returnCode = internalFactorize(1);
+          assert (!returnCode);
+#else
+          internalFactorize(1);
+#endif
+     }
+     CoinMemcpyN(rowActivity_, numberRows_, rowActivityWork_);
+     CoinMemcpyN(columnActivity_, numberColumns_, columnActivityWork_);
+     gutsOfSolution(NULL, NULL);
+     CoinMemcpyN(rowActivityWork_, numberRows_, rowActivity_);
+     CoinMemcpyN(columnActivityWork_, numberColumns_, columnActivity_);
+     CoinMemcpyN(dj_, numberColumns_, reducedCost_);
+     deleteRim(-1);
+     scalingFlag_ = saveFlag;
+     return (primalFeasible() && dualFeasible());
+}
+/* Return model - updates any scalars */
+void
+ClpSimplex::returnModel(ClpSimplex & otherModel)
+{
+     ClpModel::returnModel(otherModel);
+     otherModel.bestPossibleImprovement_ = bestPossibleImprovement_;
+     otherModel.columnPrimalSequence_ = columnPrimalSequence_;
+     otherModel.zeroTolerance_ = zeroTolerance_;
+     otherModel.rowPrimalSequence_ = rowPrimalSequence_;
+     otherModel.bestObjectiveValue_ = bestObjectiveValue_;
+     otherModel.moreSpecialOptions_ = moreSpecialOptions_;
+     otherModel.baseIteration_ = baseIteration_;
+     otherModel.primalToleranceToGetOptimal_ = primalToleranceToGetOptimal_;
+     otherModel.largestPrimalError_ = largestPrimalError_;
+     otherModel.largestDualError_ = largestDualError_;
+     otherModel.alphaAccuracy_ = alphaAccuracy_;
+     otherModel.alpha_ = alpha_;
+     otherModel.theta_ = theta_;
+     otherModel.lowerIn_ = lowerIn_;
+     otherModel.valueIn_ = valueIn_;
+     otherModel.upperIn_ = upperIn_;
+     otherModel.dualIn_ = dualIn_;
+     otherModel.sequenceIn_ = sequenceIn_;
+     otherModel.directionIn_ = directionIn_;
+     otherModel.lowerOut_ = lowerOut_;
+     otherModel.valueOut_ = valueOut_;
+     otherModel.upperOut_ = upperOut_;
+     otherModel.dualOut_ = dualOut_;
+     otherModel.sequenceOut_ = sequenceOut_;
+     otherModel.directionOut_ = directionOut_;
+     otherModel.pivotRow_ = pivotRow_;
+     otherModel.algorithm_ = algorithm_;
+     otherModel.sumDualInfeasibilities_ = sumDualInfeasibilities_;
+     otherModel.numberDualInfeasibilities_ = numberDualInfeasibilities_;
+     otherModel.numberDualInfeasibilitiesWithoutFree_ =
+          numberDualInfeasibilitiesWithoutFree_;
+     otherModel.sumPrimalInfeasibilities_ = sumPrimalInfeasibilities_;
+     otherModel.numberPrimalInfeasibilities_ = numberPrimalInfeasibilities_;
+     otherModel.numberTimesOptimal_ = numberTimesOptimal_;
+     otherModel.disasterArea_ = NULL;
+     otherModel.sumOfRelaxedDualInfeasibilities_ = sumOfRelaxedDualInfeasibilities_;
+     otherModel.sumOfRelaxedPrimalInfeasibilities_ = sumOfRelaxedPrimalInfeasibilities_;
+     if (perturbationArray_ != otherModel.perturbationArray_)
+          delete [] perturbationArray_;
+     perturbationArray_ = NULL;
+
+}
+/* Constructs a non linear cost from list of non-linearities (columns only)
+   First lower of each column is taken as real lower
+   Last lower is taken as real upper and cost ignored
+
+   Returns nonzero if bad data e.g. lowers not monotonic
+*/
+int
+ClpSimplex::createPiecewiseLinearCosts(const int * starts,
+                                       const double * lower, const double * gradient)
+{
+     delete nonLinearCost_;
+     // Set up feasible bounds and check monotonicity
+     int iColumn;
+     int returnCode = 0;
+
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          int iIndex = starts[iColumn];
+          int end = starts[iColumn+1] - 1;
+          columnLower_[iColumn] = lower[iIndex];
+          columnUpper_[iColumn] = lower[end];
+          double value = columnLower_[iColumn];
+          iIndex++;
+          for (; iIndex < end; iIndex++) {
+               if (lower[iIndex] < value)
+                    returnCode++; // not monotonic
+               value = lower[iIndex];
+          }
+     }
+     nonLinearCost_ = new ClpNonLinearCost(this, starts, lower, gradient);
+     specialOptions_ |= 2; // say keep
+     return returnCode;
+}
+/* For advanced use.  When doing iterative solves things can get
+   nasty so on values pass if incoming solution has largest
+   infeasibility < incomingInfeasibility throw out variables
+   from basis until largest infeasibility < allowedInfeasibility
+   or incoming largest infeasibility.
+   If allowedInfeasibility>= incomingInfeasibility this is
+   always possible altough you may end up with an all slack basis.
+
+   Defaults are 1.0,10.0
+*/
+void
+ClpSimplex::setValuesPassAction(double incomingInfeasibility,
+                                double allowedInfeasibility)
+{
+     incomingInfeasibility_ = incomingInfeasibility;
+     allowedInfeasibility_ = allowedInfeasibility;
+     CoinAssert(incomingInfeasibility_ >= 0.0);
+     CoinAssert(allowedInfeasibility_ >= incomingInfeasibility_);
+}
+// Allow initial dense factorization
+void
+ClpSimplex::setInitialDenseFactorization(bool onOff)
+{
+     if (onOff)
+          specialOptions_ |= 8;
+     else
+          specialOptions_ &= ~8;
+}
+bool
+ClpSimplex::initialDenseFactorization() const
+{
+     return (specialOptions_ & 8) != 0;
+}
+/* This constructor modifies original ClpSimplex and stores
+   original stuff in created ClpSimplex.  It is only to be used in
+   conjunction with originalModel */
+ClpSimplex::ClpSimplex (ClpSimplex * wholeModel,
+                        int numberColumns, const int * whichColumns)
+{
+
+     // Set up dummy row selection list
+     numberRows_ = wholeModel->numberRows_;
+     int * whichRow = new int [numberRows_];
+     int iRow;
+     for (iRow = 0; iRow < numberRows_; iRow++)
+          whichRow[iRow] = iRow;
+     // ClpModel stuff (apart from numberColumns_)
+     matrix_ = wholeModel->matrix_;
+     rowCopy_ = wholeModel->rowCopy_;
+     if (wholeModel->rowCopy_) {
+          // note reversal of order
+          wholeModel->rowCopy_ = wholeModel->rowCopy_->subsetClone(numberRows_, whichRow,
+                                 numberColumns, whichColumns);
+     } else {
+          wholeModel->rowCopy_ = NULL;
+     }
+     whatsChanged_ &= ~0xffff;
+     CoinAssert (wholeModel->matrix_);
+     wholeModel->matrix_ = wholeModel->matrix_->subsetClone(numberRows_, whichRow,
+                           numberColumns, whichColumns);
+     delete [] whichRow;
+     numberColumns_ = wholeModel->numberColumns_;
+     // Now ClpSimplex stuff and status_
+     delete  wholeModel->primalColumnPivot_;
+     wholeModel->primalColumnPivot_ = new ClpPrimalColumnSteepest(0);
+     nonLinearCost_ = wholeModel->nonLinearCost_;
+
+     // Now main arrays
+     int iColumn;
+     int numberTotal = numberRows_ + numberColumns;
+     COIN_DETAIL_PRINT(printf("%d %d %d\n", numberTotal, numberRows_, numberColumns));
+     // mapping
+     int * mapping = new int[numberRows_+numberColumns_];
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++)
+          mapping[iColumn] = -1;
+     for (iRow = 0; iRow < numberRows_; iRow++)
+          mapping[iRow+numberColumns_] = iRow + numberColumns;
+     // Redo costs and bounds of whole model
+     wholeModel->createRim(1 + 4, false);
+     lower_ = wholeModel->lower_;
+     wholeModel->lower_ = new double [numberTotal];
+     CoinMemcpyN(lower_ + numberColumns_, numberRows_, wholeModel->lower_ + numberColumns);
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          int jColumn = whichColumns[iColumn];
+          wholeModel->lower_[iColumn] = lower_[jColumn];
+          // and pointer back
+          mapping[jColumn] = iColumn;
+     }
+#ifdef CLP_DEBUG
+     for (iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++)
+          printf("mapx %d %d\n", iColumn, mapping[iColumn]);
+#endif
+     // Re-define pivotVariable_
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          int iPivot = wholeModel->pivotVariable_[iRow];
+          wholeModel->pivotVariable_[iRow] = mapping[iPivot];
+#ifdef CLP_DEBUG
+          printf("p row %d, pivot %d -> %d\n", iRow, iPivot, mapping[iPivot]);
+#endif
+          assert (wholeModel->pivotVariable_[iRow] >= 0);
+     }
+     // Reverse mapping (so extended version of whichColumns)
+     for (iColumn = 0; iColumn < numberColumns; iColumn++)
+          mapping[iColumn] = whichColumns[iColumn];
+     for (; iColumn < numberRows_ + numberColumns; iColumn++)
+          mapping[iColumn] = iColumn + (numberColumns_ - numberColumns);
+#ifdef CLP_DEBUG
+     for (iColumn = 0; iColumn < numberRows_ + numberColumns; iColumn++)
+          printf("map %d %d\n", iColumn, mapping[iColumn]);
+#endif
+     // Save mapping somewhere - doesn't matter
+     rowUpper_ = reinterpret_cast<double *> (mapping);
+     upper_ = wholeModel->upper_;
+     wholeModel->upper_ = new double [numberTotal];
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          int jColumn = mapping[iColumn];
+          wholeModel->upper_[iColumn] = upper_[jColumn];
+     }
+     cost_ = wholeModel->cost_;
+     wholeModel->cost_ = new double [numberTotal];
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          int jColumn = mapping[iColumn];
+          wholeModel->cost_[iColumn] = cost_[jColumn];
+     }
+     dj_ = wholeModel->dj_;
+     wholeModel->dj_ = new double [numberTotal];
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          int jColumn = mapping[iColumn];
+          wholeModel->dj_[iColumn] = dj_[jColumn];
+     }
+     solution_ = wholeModel->solution_;
+     wholeModel->solution_ = new double [numberTotal];
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          int jColumn = mapping[iColumn];
+          wholeModel->solution_[iColumn] = solution_[jColumn];
+     }
+     // now see what variables left out do to row solution
+     double * rowSolution = wholeModel->solution_ + numberColumns;
+     double * fullSolution = solution_;
+     double * sumFixed = new double[numberRows_];
+     memset (sumFixed, 0, numberRows_ * sizeof(double));
+     // zero out ones in small problem
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          int jColumn = mapping[iColumn];
+          fullSolution[jColumn] = 0.0;
+     }
+     // Get objective offset
+     double originalOffset;
+     wholeModel->getDblParam(ClpObjOffset, originalOffset);
+     double offset = 0.0;
+     const double * cost = cost_;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++)
+          offset += fullSolution[iColumn] * cost[iColumn];
+     wholeModel->setDblParam(ClpObjOffset, originalOffset - offset);
+     setDblParam(ClpObjOffset, originalOffset);
+     matrix_->times(1.0, fullSolution, sumFixed, wholeModel->rowScale_, wholeModel->columnScale_);
+
+     double * lower = lower_ + numberColumns;
+     double * upper = upper_ + numberColumns;
+     double fixed = 0.0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          fixed += fabs(sumFixed[iRow]);
+          if (lower[iRow] > -1.0e50)
+               lower[iRow] -= sumFixed[iRow];
+          if (upper[iRow] < 1.0e50)
+               upper[iRow] -= sumFixed[iRow];
+          rowSolution[iRow] -= sumFixed[iRow];
+     }
+     COIN_DETAIL_PRINT(printf("offset %g sumfixed %g\n", offset, fixed));
+     delete [] sumFixed;
+     columnScale_ = wholeModel->columnScale_;
+     if (columnScale_) {
+          wholeModel->columnScale_ = new double [numberTotal];
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               int jColumn = mapping[iColumn];
+               wholeModel->columnScale_[iColumn] = columnScale_[jColumn];
+          }
+     }
+     status_ = wholeModel->status_;
+     wholeModel->status_ = new unsigned char [numberTotal];
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          int jColumn = mapping[iColumn];
+          wholeModel->status_[iColumn] = status_[jColumn];
+     }
+     savedSolution_ = wholeModel->savedSolution_;
+     if (savedSolution_) {
+          wholeModel->savedSolution_ = new double [numberTotal];
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               int jColumn = mapping[iColumn];
+               wholeModel->savedSolution_[iColumn] = savedSolution_[jColumn];
+          }
+     }
+     saveStatus_ = wholeModel->saveStatus_;
+     if (saveStatus_) {
+          wholeModel->saveStatus_ = new unsigned char [numberTotal];
+          for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+               int jColumn = mapping[iColumn];
+               wholeModel->saveStatus_[iColumn] = saveStatus_[jColumn];
+          }
+     }
+
+     wholeModel->numberColumns_ = numberColumns;
+     // Initialize weights
+     wholeModel->primalColumnPivot_->saveWeights(wholeModel, 2);
+     // Costs
+     wholeModel->nonLinearCost_ = new ClpNonLinearCost(wholeModel);
+     wholeModel->nonLinearCost_->checkInfeasibilities();
+     COIN_DETAIL_PRINT(printf("after contraction %d infeasibilities summing to %g\n",
+			      nonLinearCost_->numberInfeasibilities(), nonLinearCost_->sumInfeasibilities()));
+     // Redo some stuff
+     wholeModel->reducedCostWork_ = wholeModel->dj_;
+     wholeModel->rowReducedCost_ = wholeModel->dj_ + wholeModel->numberColumns_;
+     wholeModel->columnActivityWork_ = wholeModel->solution_;
+     wholeModel->rowActivityWork_ = wholeModel->solution_ + wholeModel->numberColumns_;
+     wholeModel->objectiveWork_ = wholeModel->cost_;
+     wholeModel->rowObjectiveWork_ = wholeModel->cost_ + wholeModel->numberColumns_;
+     wholeModel->rowLowerWork_ = wholeModel->lower_ + wholeModel->numberColumns_;
+     wholeModel->columnLowerWork_ = wholeModel->lower_;
+     wholeModel->rowUpperWork_ = wholeModel->upper_ + wholeModel->numberColumns_;
+     wholeModel->columnUpperWork_ = wholeModel->upper_;
+#ifndef NDEBUG
+     // Check status
+     ClpSimplex * xxxx = wholeModel;
+     int nBasic = 0;
+     for (iColumn = 0; iColumn < xxxx->numberRows_ + xxxx->numberColumns_; iColumn++)
+          if (xxxx->getStatus(iColumn) == basic)
+               nBasic++;
+     assert (nBasic == xxxx->numberRows_);
+     for (iRow = 0; iRow < xxxx->numberRows_; iRow++) {
+          int iPivot = xxxx->pivotVariable_[iRow];
+          assert (xxxx->getStatus(iPivot) == basic);
+     }
+#endif
+}
+/* This copies back stuff from miniModel and then deletes miniModel.
+   Only to be used with mini constructor */
+void
+ClpSimplex::originalModel(ClpSimplex * miniModel)
+{
+     int numberSmall = numberColumns_;
+     numberColumns_ = miniModel->numberColumns_;
+     int numberTotal = numberSmall + numberRows_;
+     // copy back
+     int iColumn;
+     int * mapping = reinterpret_cast<int *> (miniModel->rowUpper_);
+#ifdef CLP_DEBUG
+     for (iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++)
+          printf("mapb %d %d\n", iColumn, mapping[iColumn]);
+#endif
+     // miniModel actually has full arrays
+     // now see what variables left out do to row solution
+     double * fullSolution = miniModel->solution_;
+     double * sumFixed = new double[numberRows_];
+     memset (sumFixed, 0, numberRows_ * sizeof(double));
+     miniModel->matrix_->times(1.0, fullSolution, sumFixed, rowScale_, miniModel->columnScale_);
+
+     for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+          int jColumn = mapping[iColumn];
+          miniModel->lower_[jColumn] = lower_[iColumn];
+          miniModel->upper_[jColumn] = upper_[iColumn];
+          miniModel->cost_[jColumn] = cost_[iColumn];
+          miniModel->dj_[jColumn] = dj_[iColumn];
+          miniModel->solution_[jColumn] = solution_[iColumn];
+          miniModel->status_[jColumn] = status_[iColumn];
+#ifdef CLP_DEBUG
+          printf("%d in small -> %d in original\n", iColumn, jColumn);
+#endif
+     }
+     delete [] lower_;
+     lower_ =  miniModel->lower_;
+     delete [] upper_;
+     upper_ =  miniModel->upper_;
+     delete [] cost_;
+     cost_ =  miniModel->cost_;
+     delete [] dj_;
+     dj_ =  miniModel->dj_;
+     delete [] solution_;
+     solution_ =  miniModel->solution_;
+     delete [] status_;
+     status_ =  miniModel->status_;
+     if (columnScale_) {
+          for (iColumn = 0; iColumn < numberSmall; iColumn++) {
+               int jColumn = mapping[iColumn];
+               miniModel->columnScale_[jColumn] = columnScale_[iColumn];
+          }
+          delete [] columnScale_;
+          columnScale_ =  miniModel->columnScale_;
+     }
+     if (savedSolution_) {
+          if (!miniModel->savedSolution_) {
+               miniModel->savedSolution_ = ClpCopyOfArray(solution_, numberColumns_ + numberRows_);
+          } else {
+               for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+                    int jColumn = mapping[iColumn];
+                    miniModel->savedSolution_[jColumn] = savedSolution_[iColumn];
+               }
+          }
+          delete [] savedSolution_;
+          savedSolution_ =  miniModel->savedSolution_;
+     }
+     if (saveStatus_) {
+          if (!miniModel->saveStatus_) {
+               miniModel->saveStatus_ = ClpCopyOfArray(status_, numberColumns_ + numberRows_);
+          } else {
+               for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+                    int jColumn = mapping[iColumn];
+                    miniModel->saveStatus_[jColumn] = saveStatus_[iColumn];
+               }
+          }
+          delete [] saveStatus_;
+          saveStatus_ =  miniModel->saveStatus_;
+     }
+     // Re-define pivotVariable_
+     int iRow;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          int iPivot = pivotVariable_[iRow];
+#ifdef CLP_DEBUG
+          printf("pb row %d, pivot %d -> %d\n", iRow, iPivot, mapping[iPivot]);
+#endif
+          pivotVariable_[iRow] = mapping[iPivot];
+          assert (pivotVariable_[iRow] >= 0);
+     }
+     // delete stuff and move back
+     delete matrix_;
+     delete rowCopy_;
+     delete primalColumnPivot_;
+     delete nonLinearCost_;
+     matrix_ = miniModel->matrix_;
+     rowCopy_ = miniModel->rowCopy_;
+     nonLinearCost_ = miniModel->nonLinearCost_;
+     double originalOffset;
+     miniModel->getDblParam(ClpObjOffset, originalOffset);
+     setDblParam(ClpObjOffset, originalOffset);
+     // Redo some stuff
+     reducedCostWork_ = dj_;
+     rowReducedCost_ = dj_ + numberColumns_;
+     columnActivityWork_ = solution_;
+     rowActivityWork_ = solution_ + numberColumns_;
+     objectiveWork_ = cost_;
+     rowObjectiveWork_ = cost_ + numberColumns_;
+     rowLowerWork_ = lower_ + numberColumns_;
+     columnLowerWork_ = lower_;
+     rowUpperWork_ = upper_ + numberColumns_;
+     columnUpperWork_ = upper_;
+     // Cleanup
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          double value = rowActivityWork_[iRow] + sumFixed[iRow];
+          rowActivityWork_[iRow] = value;
+          switch(getRowStatus(iRow)) {
+
+          case basic:
+               break;
+          case atUpperBound:
+               //rowActivityWork_[iRow]=rowUpperWork_[iRow];
+               break;
+          case ClpSimplex::isFixed:
+          case atLowerBound:
+               //rowActivityWork_[iRow]=rowLowerWork_[iRow];
+               break;
+          case isFree:
+               break;
+               // superbasic
+          case superBasic:
+               break;
+          }
+     }
+     delete [] sumFixed;
+     nonLinearCost_->checkInfeasibilities();
+     COIN_DETAIL_PRINT(printf("in original %d infeasibilities summing to %g\n",
+			      nonLinearCost_->numberInfeasibilities(), nonLinearCost_->sumInfeasibilities()));
+     // Initialize weights
+     primalColumnPivot_ = new ClpPrimalColumnSteepest(10);
+     primalColumnPivot_->saveWeights(this, 2);
+#ifndef NDEBUG
+     // Check status
+     ClpSimplex * xxxx = this;
+     int nBasic = 0;
+     for (iColumn = 0; iColumn < xxxx->numberRows_ + xxxx->numberColumns_; iColumn++)
+          if (xxxx->getStatus(iColumn) == basic)
+               nBasic++;
+     assert (nBasic == xxxx->numberRows_);
+     for (iRow = 0; iRow < xxxx->numberRows_; iRow++) {
+          int iPivot = xxxx->pivotVariable_[iRow];
+          assert (xxxx->getStatus(iPivot) == basic);
+     }
+#endif
+}
+// Pass in Event handler (cloned and deleted at end)
+void
+ClpSimplex::passInEventHandler(const ClpEventHandler * eventHandler)
+{
+     delete eventHandler_;
+     eventHandler_ = eventHandler->clone();
+     eventHandler_->setSimplex(this);
+}
+#ifndef NDEBUG
+// For errors to make sure print to screen
+// only called in debug mode
+static void indexError(int index,
+                       std::string methodName)
+{
+     std::cerr << "Illegal index " << index << " in ClpSimplex::" << methodName << std::endl;
+     throw CoinError("Illegal index", methodName, "ClpSimplex");
+}
+#endif
+// These are only to be used using startFinishOptions (ClpSimplexDual, ClpSimplexPrimal)
+//Get a row of the tableau (slack part in slack if not NULL)
+void
+ClpSimplex::getBInvARow(int row, double* z, double * slack)
+{
+#ifndef NDEBUG
+     int n = numberRows();
+     if (row < 0 || row >= n) {
+          indexError(row, "getBInvARow");
+     }
+#endif
+     if (!rowArray_[0]) {
+          printf("ClpSimplexPrimal or ClpSimplexDual must have been called with correct startFinishOption\n");
+          abort();
+     }
+     CoinIndexedVector * rowArray0 = rowArray(0);
+     CoinIndexedVector * rowArray1 = rowArray(1);
+     CoinIndexedVector * columnArray0 = columnArray(0);
+     CoinIndexedVector * columnArray1 = columnArray(1);
+     rowArray0->clear();
+     rowArray1->clear();
+     columnArray0->clear();
+     columnArray1->clear();
+     // put +1 in row
+     // But swap if pivot variable was slack as clp stores slack as -1.0
+     int pivot = pivotVariable_[row];
+     double value;
+     // And if scaled then adjust
+     if (!rowScale_) {
+          if (pivot < numberColumns_)
+               value = 1.0;
+          else
+               value = -1.0;
+     } else {
+          if (pivot < numberColumns_)
+               value = columnScale_[pivot];
+          else
+               value = -1.0 * inverseRowScale_[pivot-numberColumns_];
+     }
+     rowArray1->insert(row, value);
+     factorization_->updateColumnTranspose(rowArray0, rowArray1);
+     // put row of tableau in rowArray1 and columnArray0
+     clpMatrix()->transposeTimes(this, 1.0,
+                                 rowArray1, columnArray1, columnArray0);
+     if (!rowScale_) {
+          CoinMemcpyN(columnArray0->denseVector(),	numberColumns_, z);
+     } else {
+          double * array = columnArray0->denseVector();
+          for (int i = 0; i < numberColumns_; i++)
+               z[i] = array[i] * inverseColumnScale_[i];
+     }
+     if (slack) {
+          if (!rowScale_) {
+               CoinMemcpyN(rowArray1->denseVector(),	numberRows_, slack);
+          } else {
+               double * array = rowArray1->denseVector();
+               for (int i = 0; i < numberRows_; i++)
+                    slack[i] = array[i] * rowScale_[i];
+          }
+     }
+     // don't need to clear everything always, but doesn't cost
+     rowArray0->clear();
+     rowArray1->clear();
+     columnArray0->clear();
+     columnArray1->clear();
+}
+
+//Get a row of the basis inverse
+void
+ClpSimplex::getBInvRow(int row, double* z)
+
+{
+#ifndef NDEBUG
+     int n = numberRows();
+     if (row < 0 || row >= n) {
+          indexError(row, "getBInvRow");
+     }
+#endif
+     if (!rowArray_[0]) {
+          printf("ClpSimplexPrimal or ClpSimplexDual must have been called with correct startFinishOption\n");
+          abort();
+     }
+     ClpFactorization * factorization = factorization_;
+     CoinIndexedVector * rowArray0 = rowArray(0);
+     CoinIndexedVector * rowArray1 = rowArray(1);
+     rowArray0->clear();
+     rowArray1->clear();
+     // put +1 in row
+     // But swap if pivot variable was slack as clp stores slack as -1.0
+     double value = (pivotVariable_[row] < numberColumns_) ? 1.0 : -1.0;
+     // but scale
+     if (rowScale_) {
+          int pivot = pivotVariable_[row];
+          if (pivot < numberColumns_)
+               value *= columnScale_[pivot];
+          else
+               value /= rowScale_[pivot-numberColumns_];
+     }
+     rowArray1->insert(row, value);
+     factorization->updateColumnTranspose(rowArray0, rowArray1);
+     if (!rowScale_) {
+          CoinMemcpyN(rowArray1->denseVector(), numberRows_, z);
+     } else {
+          double * array = rowArray1->denseVector();
+          for (int i = 0; i < numberRows_; i++) {
+               z[i] = array[i] * rowScale_[i];
+          }
+     }
+     rowArray1->clear();
+}
+
+//Get a column of the tableau
+void
+ClpSimplex::getBInvACol(int col, double* vec)
+{
+     if (!rowArray_[0]) {
+          printf("ClpSimplexPrimal or ClpSimplexDual should have been called with correct startFinishOption\n");
+          abort();
+     }
+     CoinIndexedVector * rowArray0 = rowArray(0);
+     CoinIndexedVector * rowArray1 = rowArray(1);
+     rowArray0->clear();
+     rowArray1->clear();
+     // get column of matrix
+#ifndef NDEBUG
+     int n = numberColumns_ + numberRows_;
+     if (col < 0 || col >= n) {
+          indexError(col, "getBInvACol");
+     }
+#endif
+     if (!rowScale_) {
+          if (col < numberColumns_) {
+               unpack(rowArray1, col);
+          } else {
+               rowArray1->insert(col - numberColumns_, 1.0);
+          }
+     } else {
+          if (col < numberColumns_) {
+               unpack(rowArray1, col);
+               double multiplier = 1.0 * inverseColumnScale_[col];
+               int number = rowArray1->getNumElements();
+               int * index = rowArray1->getIndices();
+               double * array = rowArray1->denseVector();
+               for (int i = 0; i < number; i++) {
+                    int iRow = index[i];
+                    // make sure not packed
+                    assert (array[iRow]);
+                    array[iRow] *= multiplier;
+               }
+          } else {
+               rowArray1->insert(col - numberColumns_, rowScale_[col-numberColumns_]);
+          }
+     }
+     factorization_->updateColumn(rowArray0, rowArray1, false);
+     // But swap if pivot variable was slack as clp stores slack as -1.0
+     double * array = rowArray1->denseVector();
+     if (!rowScale_) {
+          for (int i = 0; i < numberRows_; i++) {
+               double multiplier = (pivotVariable_[i] < numberColumns_) ? 1.0 : -1.0;
+               vec[i] = multiplier * array[i];
+          }
+     } else {
+          for (int i = 0; i < numberRows_; i++) {
+               int pivot = pivotVariable_[i];
+               if (pivot < numberColumns_)
+                    vec[i] = array[i] * columnScale_[pivot];
+               else
+                    vec[i] = - array[i] / rowScale_[pivot-numberColumns_];
+          }
+     }
+     rowArray1->clear();
+}
+
+//Get a column of the basis inverse
+void
+ClpSimplex::getBInvCol(int col, double* vec)
+{
+     if (!rowArray_[0]) {
+          printf("ClpSimplexPrimal or ClpSimplexDual must have been called with correct startFinishOption\n");
+          abort();
+     }
+     CoinIndexedVector * rowArray0 = rowArray(0);
+     CoinIndexedVector * rowArray1 = rowArray(1);
+     rowArray0->clear();
+     rowArray1->clear();
+#ifndef NDEBUG
+     int n = numberRows();
+     if (col < 0 || col >= n) {
+          indexError(col, "getBInvCol");
+     }
+#endif
+     // put +1 in row
+     // but scale
+     double value;
+     if (!rowScale_) {
+          value = 1.0;
+     } else {
+          value = rowScale_[col];
+     }
+     rowArray1->insert(col, value);
+     factorization_->updateColumn(rowArray0, rowArray1, false);
+     // But swap if pivot variable was slack as clp stores slack as -1.0
+     double * array = rowArray1->denseVector();
+     if (!rowScale_) {
+          for (int i = 0; i < numberRows_; i++) {
+               double multiplier = (pivotVariable_[i] < numberColumns_) ? 1.0 : -1.0;
+               vec[i] = multiplier * array[i];
+          }
+     } else {
+          for (int i = 0; i < numberRows_; i++) {
+               int pivot = pivotVariable_[i];
+               double value = array[i];
+               if (pivot < numberColumns_)
+                    vec[i] = value * columnScale_[pivot];
+               else
+                    vec[i] = - value / rowScale_[pivot-numberColumns_];
+          }
+     }
+     rowArray1->clear();
+}
+
+/* Get basic indices (order of indices corresponds to the
+   order of elements in a vector retured by getBInvACol() and
+   getBInvCol()).
+*/
+void
+ClpSimplex::getBasics(int* index)
+{
+     if (!rowArray_[0]) {
+          printf("ClpSimplexPrimal or ClpSimplexDual must have been called with correct startFinishOption\n");
+          abort();
+     }
+     CoinAssert (index);
+     CoinMemcpyN(pivotVariable(),	numberRows(), index);
+}
+/* Set an objective function coefficient */
+void
+ClpSimplex::setObjectiveCoefficient( int elementIndex, double elementValue )
+{
+#ifndef NDEBUG
+     if (elementIndex < 0 || elementIndex >= numberColumns_) {
+          indexError(elementIndex, "setObjectiveCoefficient");
+     }
+#endif
+     if (objective()[elementIndex] != elementValue) {
+          objective()[elementIndex] = elementValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~64;
+               double direction = optimizationDirection_ * objectiveScale_;
+               if (!rowScale_) {
+                    objectiveWork_[elementIndex] = direction * elementValue;
+               } else {
+                    objectiveWork_[elementIndex] = direction * elementValue
+                                                   * columnScale_[elementIndex];
+               }
+          }
+     }
+}
+/* Set a single row lower bound<br>
+   Use -DBL_MAX for -infinity. */
+void
+ClpSimplex::setRowLower( int elementIndex, double elementValue )
+{
+#ifndef NDEBUG
+     int n = numberRows_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setRowLower");
+     }
+#endif
+     if (elementValue < -1.0e27)
+          elementValue = -COIN_DBL_MAX;
+     if (rowLower_[elementIndex] != elementValue) {
+          rowLower_[elementIndex] = elementValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~16;
+               if (rowLower_[elementIndex] == -COIN_DBL_MAX) {
+                    rowLowerWork_[elementIndex] = -COIN_DBL_MAX;
+               } else if (!rowScale_) {
+                    rowLowerWork_[elementIndex] = elementValue * rhsScale_;
+               } else {
+                    rowLowerWork_[elementIndex] = elementValue * rhsScale_
+                                                  * rowScale_[elementIndex];
+               }
+          }
+     }
+}
+
+/* Set a single row upper bound<br>
+   Use DBL_MAX for infinity. */
+void
+ClpSimplex::setRowUpper( int elementIndex, double elementValue )
+{
+#ifndef NDEBUG
+     int n = numberRows_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setRowUpper");
+     }
+#endif
+     if (elementValue > 1.0e27)
+          elementValue = COIN_DBL_MAX;
+     if (rowUpper_[elementIndex] != elementValue) {
+          rowUpper_[elementIndex] = elementValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~32;
+               if (rowUpper_[elementIndex] == COIN_DBL_MAX) {
+                    rowUpperWork_[elementIndex] = COIN_DBL_MAX;
+               } else if (!rowScale_) {
+                    rowUpperWork_[elementIndex] = elementValue * rhsScale_;
+               } else {
+                    rowUpperWork_[elementIndex] = elementValue * rhsScale_
+                                                  * rowScale_[elementIndex];
+               }
+          }
+     }
+}
+
+/* Set a single row lower and upper bound */
+void
+ClpSimplex::setRowBounds( int elementIndex,
+                          double lowerValue, double upperValue )
+{
+#ifndef NDEBUG
+     int n = numberRows_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setRowBounds");
+     }
+#endif
+     if (lowerValue < -1.0e27)
+          lowerValue = -COIN_DBL_MAX;
+     if (upperValue > 1.0e27)
+          upperValue = COIN_DBL_MAX;
+     //CoinAssert (upperValue>=lowerValue);
+     if (rowLower_[elementIndex] != lowerValue) {
+          rowLower_[elementIndex] = lowerValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~16;
+               if (rowLower_[elementIndex] == -COIN_DBL_MAX) {
+                    rowLowerWork_[elementIndex] = -COIN_DBL_MAX;
+               } else if (!rowScale_) {
+                    rowLowerWork_[elementIndex] = lowerValue * rhsScale_;
+               } else {
+                    rowLowerWork_[elementIndex] = lowerValue * rhsScale_
+                                                  * rowScale_[elementIndex];
+               }
+          }
+     }
+     if (rowUpper_[elementIndex] != upperValue) {
+          rowUpper_[elementIndex] = upperValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~32;
+               if (rowUpper_[elementIndex] == COIN_DBL_MAX) {
+                    rowUpperWork_[elementIndex] = COIN_DBL_MAX;
+               } else if (!rowScale_) {
+                    rowUpperWork_[elementIndex] = upperValue * rhsScale_;
+               } else {
+                    rowUpperWork_[elementIndex] = upperValue * rhsScale_
+                                                  * rowScale_[elementIndex];
+               }
+          }
+     }
+}
+void ClpSimplex::setRowSetBounds(const int* indexFirst,
+                                 const int* indexLast,
+                                 const double* boundList)
+{
+#ifndef NDEBUG
+     int n = numberRows_;
+#endif
+     int numberChanged = 0;
+     const int * saveFirst = indexFirst;
+     while (indexFirst != indexLast) {
+          const int iRow = *indexFirst++;
+#ifndef NDEBUG
+          if (iRow < 0 || iRow >= n) {
+               indexError(iRow, "setRowSetBounds");
+          }
+#endif
+          double lowerValue = *boundList++;
+          double upperValue = *boundList++;
+          if (lowerValue < -1.0e27)
+               lowerValue = -COIN_DBL_MAX;
+          if (upperValue > 1.0e27)
+               upperValue = COIN_DBL_MAX;
+          //CoinAssert (upperValue>=lowerValue);
+          if (rowLower_[iRow] != lowerValue) {
+               rowLower_[iRow] = lowerValue;
+               whatsChanged_ &= ~16;
+               numberChanged++;
+          }
+          if (rowUpper_[iRow] != upperValue) {
+               rowUpper_[iRow] = upperValue;
+               whatsChanged_ &= ~32;
+               numberChanged++;
+          }
+     }
+     if (numberChanged && (whatsChanged_ & 1) != 0) {
+          indexFirst = saveFirst;
+          while (indexFirst != indexLast) {
+               const int iRow = *indexFirst++;
+               if (rowLower_[iRow] == -COIN_DBL_MAX) {
+                    rowLowerWork_[iRow] = -COIN_DBL_MAX;
+               } else if (!rowScale_) {
+                    rowLowerWork_[iRow] = rowLower_[iRow] * rhsScale_;
+               } else {
+                    rowLowerWork_[iRow] = rowLower_[iRow] * rhsScale_
+                                          * rowScale_[iRow];
+               }
+               if (rowUpper_[iRow] == COIN_DBL_MAX) {
+                    rowUpperWork_[iRow] = COIN_DBL_MAX;
+               } else if (!rowScale_) {
+                    rowUpperWork_[iRow] = rowUpper_[iRow] * rhsScale_;
+               } else {
+                    rowUpperWork_[iRow] = rowUpper_[iRow] * rhsScale_
+                                          * rowScale_[iRow];
+               }
+          }
+     }
+}
+//-----------------------------------------------------------------------------
+/* Set a single column lower bound<br>
+   Use -DBL_MAX for -infinity. */
+void
+ClpSimplex::setColumnLower( int elementIndex, double elementValue )
+{
+#ifndef NDEBUG
+     int n = numberColumns_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setColumnLower");
+     }
+#endif
+     if (elementValue < -1.0e27)
+          elementValue = -COIN_DBL_MAX;
+     if (columnLower_[elementIndex] != elementValue) {
+          columnLower_[elementIndex] = elementValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~128;
+               double value;
+               if (columnLower_[elementIndex] == -COIN_DBL_MAX) {
+                    value = -COIN_DBL_MAX;
+               } else if (!columnScale_) {
+                    value = elementValue * rhsScale_;
+               } else {
+                    value = elementValue * rhsScale_
+                            / columnScale_[elementIndex];
+               }
+               lower_[elementIndex] = value;
+               if (maximumRows_ >= 0)
+                    lower_[elementIndex+maximumRows_+maximumColumns_] = value;
+          }
+     }
+}
+
+/* Set a single column upper bound<br>
+   Use DBL_MAX for infinity. */
+void
+ClpSimplex::setColumnUpper( int elementIndex, double elementValue )
+{
+#ifndef NDEBUG
+     int n = numberColumns_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setColumnUpper");
+     }
+#endif
+     if (elementValue > 1.0e27)
+          elementValue = COIN_DBL_MAX;
+     if (columnUpper_[elementIndex] != elementValue) {
+          columnUpper_[elementIndex] = elementValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~256;
+               double value;
+               if (columnUpper_[elementIndex] == COIN_DBL_MAX) {
+                    value = COIN_DBL_MAX;
+               } else if (!columnScale_) {
+                    value = elementValue * rhsScale_;
+               } else {
+                    value = elementValue * rhsScale_
+                            / columnScale_[elementIndex];
+               }
+               //assert (columnUpperWork_==upper_);
+               upper_[elementIndex] = value;
+               if (maximumRows_ >= 0)
+                    upper_[elementIndex+maximumRows_+maximumColumns_] = value;
+          }
+     }
+}
+
+/* Set a single column lower and upper bound */
+void
+ClpSimplex::setColumnBounds( int elementIndex,
+                             double lowerValue, double upperValue )
+{
+#ifndef NDEBUG
+     int n = numberColumns_;
+     if (elementIndex < 0 || elementIndex >= n) {
+          indexError(elementIndex, "setColumnBounds");
+     }
+#endif
+     if (lowerValue < -1.0e27)
+          lowerValue = -COIN_DBL_MAX;
+     if (columnLower_[elementIndex] != lowerValue) {
+          columnLower_[elementIndex] = lowerValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~128;
+               if (columnLower_[elementIndex] == -COIN_DBL_MAX) {
+                    lower_[elementIndex] = -COIN_DBL_MAX;
+               } else if (!columnScale_) {
+                    lower_[elementIndex] = lowerValue * rhsScale_;
+               } else {
+                    lower_[elementIndex] = lowerValue * rhsScale_
+                                           / columnScale_[elementIndex];
+               }
+          }
+     }
+     if (upperValue > 1.0e27)
+          upperValue = COIN_DBL_MAX;
+     //CoinAssert (upperValue>=lowerValue);
+     if (columnUpper_[elementIndex] != upperValue) {
+          columnUpper_[elementIndex] = upperValue;
+          if ((whatsChanged_ & 1) != 0) {
+               // work arrays exist - update as well
+               whatsChanged_ &= ~256;
+               if (columnUpper_[elementIndex] == COIN_DBL_MAX) {
+                    upper_[elementIndex] = COIN_DBL_MAX;
+               } else if (!columnScale_) {
+                    upper_[elementIndex] = upperValue * rhsScale_;
+               } else {
+                    upper_[elementIndex] = upperValue * rhsScale_
+                                           / columnScale_[elementIndex];
+               }
+          }
+     }
+}
+void ClpSimplex::setColumnSetBounds(const int* indexFirst,
+                                    const int* indexLast,
+                                    const double* boundList)
+{
+#ifndef NDEBUG
+     int n = numberColumns_;
+#endif
+     int numberChanged = 0;
+     const int * saveFirst = indexFirst;
+     while (indexFirst != indexLast) {
+          const int iColumn = *indexFirst++;
+#ifndef NDEBUG
+          if (iColumn < 0 || iColumn >= n) {
+               indexError(iColumn, "setColumnSetBounds");
+          }
+#endif
+          double lowerValue = *boundList++;
+          double upperValue = *boundList++;
+          if (lowerValue < -1.0e27)
+               lowerValue = -COIN_DBL_MAX;
+          if (upperValue > 1.0e27)
+               upperValue = COIN_DBL_MAX;
+          //CoinAssert (upperValue>=lowerValue);
+          if (columnLower_[iColumn] != lowerValue) {
+               columnLower_[iColumn] = lowerValue;
+               whatsChanged_ &= ~16;
+               numberChanged++;
+          }
+          if (columnUpper_[iColumn] != upperValue) {
+               columnUpper_[iColumn] = upperValue;
+               whatsChanged_ &= ~32;
+               numberChanged++;
+          }
+     }
+     if (numberChanged && (whatsChanged_ & 1) != 0) {
+          indexFirst = saveFirst;
+          while (indexFirst != indexLast) {
+               const int iColumn = *indexFirst++;
+               if (columnLower_[iColumn] == -COIN_DBL_MAX) {
+                    lower_[iColumn] = -COIN_DBL_MAX;
+               } else if (!columnScale_) {
+                    lower_[iColumn] = columnLower_[iColumn] * rhsScale_;
+               } else {
+                    lower_[iColumn] = columnLower_[iColumn] * rhsScale_
+                                      / columnScale_[iColumn];
+               }
+               if (columnUpper_[iColumn] == COIN_DBL_MAX) {
+                    upper_[iColumn] = COIN_DBL_MAX;
+               } else if (!columnScale_) {
+                    upper_[iColumn] = columnUpper_[iColumn] * rhsScale_;
+               } else {
+                    upper_[iColumn] = columnUpper_[iColumn] * rhsScale_
+                                      / columnScale_[iColumn];
+               }
+          }
+     }
+}
+/* Just check solution (for internal use) - sets sum of
+   infeasibilities etc. */
+void
+ClpSimplex::checkSolutionInternal()
+{
+     double dualTolerance = dblParam_[ClpDualTolerance];
+     double primalTolerance = dblParam_[ClpPrimalTolerance];
+     double nonLinearOffset = 0.0;
+     const double * objective = objective_->gradient(this, columnActivity_,
+                                nonLinearOffset, true);
+     int iRow, iColumn;
+     assert (!rowObjective_);
+
+     objectiveValue_ = -nonLinearOffset;
+     // now look at solution
+     sumPrimalInfeasibilities_ = 0.0;
+     numberPrimalInfeasibilities_ = 0;
+
+     sumDualInfeasibilities_ = 0.0;
+     numberDualInfeasibilities_ = 0;
+     double maxmin = optimizationDirection_;
+
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          double dualValue = dual_[iRow] * maxmin;
+          double primalValue = rowActivity_[iRow];
+          double lower = rowLower_[iRow];
+          double upper = rowUpper_[iRow];
+          ClpSimplex::Status status = getRowStatus(iRow);
+          if (status != basic) {
+               if (lower == upper) {
+                    status = ClpSimplex::isFixed;
+               } else if (primalValue > upper - primalTolerance) {
+                    status = ClpSimplex::atUpperBound;
+               } else if (primalValue < lower + primalTolerance) {
+                    status = ClpSimplex::atLowerBound;
+               }
+               setRowStatus(iRow, status);
+          }
+          if (primalValue > upper + primalTolerance) {
+               sumPrimalInfeasibilities_ += primalValue - upper - primalTolerance;
+               numberPrimalInfeasibilities_ ++;
+          } else if (primalValue < lower - primalTolerance) {
+               sumPrimalInfeasibilities_ += lower - primalValue - primalTolerance;
+               numberPrimalInfeasibilities_ ++;
+          } else {
+               switch(status) {
+
+               case basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case atUpperBound:
+                    // dual should not be positive
+                    if (dualValue > dualTolerance) {
+                         sumDualInfeasibilities_ += dualValue - dualTolerance_;
+                         numberDualInfeasibilities_ ++;
+                    }
+                    break;
+               case atLowerBound:
+                    // dual should not be negative
+                    if (dualValue < -dualTolerance) {
+                         sumDualInfeasibilities_ -= dualValue + dualTolerance_;
+                         numberDualInfeasibilities_ ++;
+                    }
+                    break;
+               case superBasic:
+               case isFree:
+                    if (primalValue < upper - primalTolerance) {
+                         // dual should not be negative
+                         if (dualValue < -dualTolerance) {
+                              sumDualInfeasibilities_ -= dualValue + dualTolerance_;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    }
+                    if (primalValue > lower + primalTolerance) {
+                         // dual should not be positive
+                         if (dualValue > dualTolerance) {
+                              sumDualInfeasibilities_ += dualValue - dualTolerance_;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    }
+                    break;
+               }
+          }
+     }
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          double dualValue = reducedCost_[iColumn] * maxmin;
+          double primalValue = columnActivity_[iColumn];
+          objectiveValue_ += objective[iColumn] * primalValue;
+          double lower = columnLower_[iColumn];
+          double upper = columnUpper_[iColumn];
+          ClpSimplex::Status status = getColumnStatus(iColumn);
+          if (status != basic && lower == upper) {
+               status = ClpSimplex::isFixed;
+               setColumnStatus(iColumn, ClpSimplex::isFixed);
+          }
+          if (primalValue > upper + primalTolerance) {
+               sumPrimalInfeasibilities_ += primalValue - upper - primalTolerance;
+               numberPrimalInfeasibilities_ ++;
+          } else if (primalValue < lower - primalTolerance) {
+               sumPrimalInfeasibilities_ += lower - primalValue - primalTolerance;
+               numberPrimalInfeasibilities_ ++;
+          } else {
+               switch(status) {
+
+               case basic:
+                    // dual should be zero
+                    if (fabs(dualValue) > 10.0 * dualTolerance) {
+		      sumDualInfeasibilities_ += fabs(dualValue) - dualTolerance_;
+                         numberDualInfeasibilities_ ++;
+			 //if (fabs(dualValue) > 1000.0 * dualTolerance) 
+			 //setColumnStatus(iColumn,superBasic); Maybe on a switch
+                    }
+                    break;
+               case ClpSimplex::isFixed:
+                    break;
+               case atUpperBound:
+                    // dual should not be positive
+                    if (dualValue > dualTolerance) {
+                         sumDualInfeasibilities_ += dualValue - dualTolerance_;
+                         numberDualInfeasibilities_ ++;
+                    }
+                    break;
+               case atLowerBound:
+                    // dual should not be negative
+                    if (dualValue < -dualTolerance) {
+                         sumDualInfeasibilities_ -= dualValue + dualTolerance_;
+                         numberDualInfeasibilities_ ++;
+                    }
+                    break;
+               case superBasic:
+               case isFree:
+                    if (primalValue < upper - primalTolerance) {
+                         // dual should not be negative
+                         if (dualValue < -dualTolerance) {
+                              sumDualInfeasibilities_ -= dualValue + dualTolerance_;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    }
+                    if (primalValue > lower + primalTolerance) {
+                         // dual should not be positive
+                         if (dualValue > dualTolerance) {
+                              sumDualInfeasibilities_ += dualValue - dualTolerance_;
+                              numberDualInfeasibilities_ ++;
+                         }
+                    }
+                    break;
+               }
+          }
+     }
+     objectiveValue_ += objective_->nonlinearOffset();
+     // But do direction
+     objectiveValue_ *= optimizationDirection_;
+
+     if (!numberDualInfeasibilities_ &&
+               !numberPrimalInfeasibilities_)
+          problemStatus_ = 0;
+     else
+          problemStatus_ = -1;
+}
+/*
+  When scaling is on it is possible that the scaled problem
+  is feasible but the unscaled is not.  Clp returns a secondary
+  status code to that effect.  This option allows for a cleanup.
+  If you use it I would suggest 1.
+  This only affects actions when scaled optimal
+  0 - no action
+  1 - clean up using dual if primal infeasibility
+  2 - clean up using dual if dual infeasibility
+  3 - clean up using dual if primal or dual infeasibility
+  11,12,13 - as 1,2,3 but use primal
+*/
+#ifdef COUNT_CLEANUPS
+static int n1 = 0;
+static int n2 = 0;
+static int n3 = 0;
+#endif
+int
+ClpSimplex::cleanup(int cleanupScaling)
+{
+#ifdef COUNT_CLEANUPS
+     n1++;
+#endif
+     int returnCode = 0;
+     if (!problemStatus_ && cleanupScaling) {
+          int check = cleanupScaling % 10;
+          bool primal = (secondaryStatus_ == 2 || secondaryStatus_ == 4);
+          bool dual = (secondaryStatus_ == 3 || secondaryStatus_ == 4);
+          if (((check & 1) != 0 && primal) || (((check & 2) != 0) && dual)) {
+               // need cleanup
+               int saveScalingFlag = scalingFlag_;
+               // say matrix changed
+               whatsChanged_ |= 1;
+               scaling(0);
+               if (cleanupScaling < 10) {
+                    // dual
+                    returnCode = this->dual();
+               } else {
+                    // primal
+                    returnCode = this->primal();
+               }
+#ifdef COUNT_CLEANUPS
+               n2++;
+               n3 += numberIterations_;
+               //printf("**cleanup took %d iterations\n",numberIterations_);
+#endif
+               scaling(saveScalingFlag);
+          }
+     }
+     return returnCode;
+}
+#ifdef COUNT_CLEANUPS
+void printHowMany()
+{
+     printf("There were %d cleanups out of %d solves and %d iterations\n",
+            n2, n1, n3);
+}
+#endif
+#ifndef SLIM_CLP
+#include "CoinWarmStartBasis.hpp"
+
+// Returns a basis (to be deleted by user)
+CoinWarmStartBasis *
+ClpSimplex::getBasis() const
+{
+     int iRow, iColumn;
+     CoinWarmStartBasis * basis = new CoinWarmStartBasis();
+     basis->setSize(numberColumns_, numberRows_);
+
+     if (statusExists()) {
+          // Flip slacks
+          int lookupA[] = {0, 1, 3, 2, 0, 2};
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int iStatus = getRowStatus(iRow);
+               iStatus = lookupA[iStatus];
+               basis->setArtifStatus(iRow, static_cast<CoinWarmStartBasis::Status> (iStatus));
+          }
+          int lookupS[] = {0, 1, 2, 3, 0, 3};
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               int iStatus = getColumnStatus(iColumn);
+               iStatus = lookupS[iStatus];
+               basis->setStructStatus(iColumn, static_cast<CoinWarmStartBasis::Status> (iStatus));
+          }
+     }
+     return basis;
+}
+#endif
+// Compute objective value from solution
+void
+ClpSimplex::computeObjectiveValue(bool useInternalArrays)
+{
+     int iSequence;
+     objectiveValue_ = 0.0;
+     const double * obj = objective();
+     if (!useInternalArrays) {
+          for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+               double value = columnActivity_[iSequence];
+               objectiveValue_ += value * obj[iSequence];
+          }
+          // But remember direction as we are using external objective
+          objectiveValue_ *= optimizationDirection_;
+     } else if (!columnScale_) {
+          for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+               double value = columnActivityWork_[iSequence];
+               objectiveValue_ += value * obj[iSequence];
+          }
+          // But remember direction as we are using external objective
+          objectiveValue_ *= optimizationDirection_;
+          objectiveValue_ += objective_->nonlinearOffset();
+          objectiveValue_ /= (objectiveScale_ * rhsScale_);
+     } else {
+          for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+               double scaleFactor = columnScale_[iSequence];
+               double valueScaled = columnActivityWork_[iSequence];
+               objectiveValue_ += valueScaled * scaleFactor * obj[iSequence];
+          }
+          // But remember direction as we are using external objective
+          objectiveValue_ *= optimizationDirection_;
+          objectiveValue_ += objective_->nonlinearOffset();
+          objectiveValue_ /= (objectiveScale_ * rhsScale_);
+     }
+}
+// Compute minimization objective value from internal solution
+double
+ClpSimplex::computeInternalObjectiveValue()
+{
+     int iSequence;
+     //double oldObj = objectiveValue_;
+     double objectiveValue = 0.0;
+     const double * obj = objective();
+     if (!columnScale_) {
+          for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+               double value = solution_[iSequence];
+               objectiveValue += value * obj[iSequence];
+          }
+     } else {
+          for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+               double value = solution_[iSequence] * columnScale_[iSequence];
+               objectiveValue += value * obj[iSequence];
+          }
+     }
+     objectiveValue *= optimizationDirection_ / rhsScale_;
+     objectiveValue -= dblParam_[ClpObjOffset];
+     return objectiveValue;
+}
+// Infeasibility/unbounded ray (NULL returned if none/wrong)
+double *
+ClpSimplex::infeasibilityRay(bool fullRay) const
+{
+     double * array = NULL;
+     if (problemStatus_ == 1 && ray_) {
+       if (!fullRay) {
+	 array = ClpCopyOfArray(ray_, numberRows_);
+       } else {
+	 array = new double [numberRows_+numberColumns_];
+	 memcpy(array,ray_,numberRows_*sizeof(double));
+	 memset(array+numberRows_,0,numberColumns_*sizeof(double));
+	 transposeTimes(-1.0,array,array+numberRows_);
+       }
+#ifdef PRINT_RAY_METHOD
+       printf("Infeasibility ray obtained by algorithm %s - direction out %d\n",algorithm_>0 ?
+	      "primal" : "dual",directionOut_);
+#endif
+     }
+     return array;
+}
+// If user left factorization frequency then compute
+void
+ClpSimplex::defaultFactorizationFrequency()
+{
+     if (factorizationFrequency() == 200) {
+          // User did not touch preset
+          const int cutoff1 = 10000;
+          const int base = 75;
+          const int freq0 = 50;
+          int frequency;
+#ifndef ABC_INHERIT
+          const int cutoff2 = 100000;
+          const int freq1 = 200;
+          const int freq2 = 400;
+          const int maximum = 1000;
+          if (numberRows_ < cutoff1)
+               frequency = base + numberRows_ / freq0;
+          else if (numberRows_ < cutoff2)
+               frequency = base + cutoff1 / freq0 + (numberRows_ - cutoff1) / freq1;
+          else
+               frequency = base + cutoff1 / freq0 + (cutoff2 - cutoff1) / freq1 + (numberRows_ - cutoff2) / freq2;
+#else
+          const int freq1 = 150;
+          const int maximum = 10000;
+          if (numberRows_ < cutoff1)
+               frequency = base + numberRows_ / freq0;
+          else
+               frequency = base + cutoff1 / freq0 + (numberRows_ - cutoff1) / freq1;
+#endif
+          setFactorizationFrequency(CoinMin(maximum, frequency));
+     }
+}
+// Gets clean and emptyish factorization
+ClpFactorization *
+ClpSimplex::getEmptyFactorization()
+{
+     if ((specialOptions_ & 65536) == 0) {
+          assert (!factorization_);
+          factorization_ = new ClpFactorization();
+     } else if (!factorization_) {
+          factorization_ = new ClpFactorization();
+          factorization_->setPersistenceFlag(1);
+     }
+     return factorization_;
+}
+// May delete or may make clean and emptyish factorization
+void
+ClpSimplex::setEmptyFactorization()
+{
+     if (factorization_) {
+          factorization_->cleanUp();
+          if ((specialOptions_ & 65536) == 0) {
+               delete factorization_;
+               factorization_ = NULL;
+          } else if (factorization_) {
+               factorization_->almostDestructor();
+          }
+     }
+}
+/* Array persistence flag
+   If 0 then as now (delete/new)
+   1 then only do arrays if bigger needed
+   2 as 1 but give a bit extra if bigger needed
+*/
+void
+ClpSimplex::setPersistenceFlag(int value)
+{
+     if (value) {
+          //specialOptions_|=65536;
+          startPermanentArrays();
+     } else {
+          specialOptions_ &= ~65536;
+     }
+     if (factorization_)
+          factorization_->setPersistenceFlag(value);
+}
+// Move status and solution across
+void
+ClpSimplex::moveInfo(const ClpSimplex & rhs, bool justStatus)
+{
+     objectiveValue_ = rhs.objectiveValue_;
+     numberIterations_ = rhs. numberIterations_;
+     problemStatus_ = rhs. problemStatus_;
+     secondaryStatus_ = rhs. secondaryStatus_;
+     if (numberRows_ == rhs.numberRows_ && numberColumns_ == rhs.numberColumns_ && !justStatus) {
+          if (rhs.status_) {
+               if (status_)
+                    CoinMemcpyN(rhs.status_, numberRows_ + numberColumns_, status_);
+               else
+                    status_ = CoinCopyOfArray(rhs.status_, numberRows_ + numberColumns_);
+          } else {
+               delete [] status_;
+               status_ = NULL;
+          }
+          CoinMemcpyN(rhs.columnActivity_, numberColumns_, columnActivity_);
+          CoinMemcpyN(rhs.reducedCost_, numberColumns_, reducedCost_);
+          CoinMemcpyN(rhs.rowActivity_, numberRows_, rowActivity_);
+          CoinMemcpyN(rhs.dual_, numberRows_, dual_);
+     }
+}
+// Save a copy of model with certain state - normally without cuts
+void
+ClpSimplex::makeBaseModel()
+{
+     delete baseModel_;
+     baseModel_ = new ClpSimplex(*this);
+}
+// Switch off base model
+void
+ClpSimplex::deleteBaseModel()
+{
+     delete baseModel_;
+     baseModel_ = NULL;
+}
+// Reset to base model
+void
+ClpSimplex::setToBaseModel(ClpSimplex * model)
+{
+     if (!model)
+          model = baseModel_;
+     assert (model);
+     int multiplier = ((model->specialOptions_ & 65536) != 0) ? 2 : 1;
+     assert (multiplier == 2);
+     if (multiplier == 2) {
+          assert (model->maximumRows_ >= 0);
+          if (maximumRows_ < 0) {
+               specialOptions_ |= 65536;
+               maximumRows_ = model->maximumRows_;
+               maximumColumns_ = model->maximumColumns_;
+          }
+     }
+     COIN_DETAIL_PRINT(printf("resetbase a %d rows, %d maximum rows\n",
+			      numberRows_, maximumRows_));
+     // temporary - later use maximumRows_ for rowUpper_ etc
+     assert (numberRows_ >= model->numberRows_);
+     abort();
+}
+// Start or reset using maximumRows_ and Columns_
+bool
+ClpSimplex::startPermanentArrays()
+{
+     int maximumRows = maximumRows_;
+     int maximumColumns = maximumColumns_;
+     ClpModel::startPermanentArrays();
+     if (maximumRows != maximumRows_ ||
+               maximumColumns != maximumColumns_) {
+#if 0
+          maximumInternalRows_ = maximumRows_;
+          maximumInternalColumns_ = maximumColumns_;
+          int numberTotal2 = (maximumRows_ + maximumColumns_) * 2;
+          delete [] cost_;
+          cost_ = new double[numberTotal2];
+          delete [] lower_;
+          delete [] upper_;
+          lower_ = new double[numberTotal2];
+          upper_ = new double[numberTotal2];
+          delete [] dj_;
+          dj_ = new double[numberTotal2];
+          delete [] solution_;
+          solution_ = new double[numberTotal2];
+          assert (scalingFlag_ > 0);
+          if (rowScale_ && rowScale_ != savedRowScale_)
+               delete [] rowScale_;
+          rowScale_ = NULL;
+          // Do initial scaling
+          delete [] savedRowScale_;
+          savedRowScale_ = new double [4*maximumRows_];
+          delete [] savedColumnScale_;
+          savedColumnScale_ = new double [4*maximumColumns_];
+          if (scalingFlag_ > 0) {
+               rowScale_ = savedRowScale_;
+               columnScale_ = savedColumnScale_;
+               if (matrix_->scale(this)) {
+                    scalingFlag_ = -scalingFlag_; // not scaled after all
+                    assert (!rowScale_);
+               }
+               int numberRows2 = numberRows_ + numberExtraRows_;
+               if (rowScale_) {
+                    CoinMemcpyN(rowScale_, 2 * numberRows2, savedRowScale_ + 2 * maximumRows_);
+                    CoinMemcpyN(columnScale_, 2 * numberColumns_, savedColumnScale_ + 2 * maximumColumns_);
+               } else {
+                    abort();
+                    CoinFillN(savedRowScale_ + 2 * maximumRows_, 2 * numberRows2, 1.0);
+                    CoinFillN(savedColumnScale_ + 2 * maximumColumns_, 2 * numberColumns_, 1.0);
+               }
+          }
+#else
+          createRim(63);
+#endif
+          return true;
+     } else {
+          return false;
+     }
+}
+#include "ClpNode.hpp"
+//#define COIN_DEVELOP
+// Fathom - 1 if solution
+int
+ClpSimplex::fathom(void * stuff)
+{
+     assert (stuff);
+     ClpNodeStuff * info = reinterpret_cast<ClpNodeStuff *> (stuff);
+     info->nNodes_ = 0;
+     // say can declare optimal
+     moreSpecialOptions_ |= 8;
+     int saveMaxIterations = maximumIterations();
+     setMaximumIterations((((moreSpecialOptions_&2048)==0) ? 100 : 2000)
+			  + 5 * (numberRows_ + numberColumns_));
+     double saveObjLimit;
+     getDblParam(ClpDualObjectiveLimit, saveObjLimit);
+     if (perturbation_<100) {
+       double limit = saveObjLimit * optimizationDirection_;
+       setDblParam(ClpDualObjectiveLimit, 
+		   (limit+1.0e-2+1.0e-7*fabs(limit))*optimizationDirection_);
+     }
+ #if 0
+     bool onOptimal = (numberColumns_==100);
+     double optVal[133];
+     {
+          memset(optVal, 0, sizeof(optVal));
+#if 0
+          int intIndicesV[] = {61, 62, 65, 66, 67, 68, 69, 70};
+          double intSolnV[] = {4., 21., 4., 4., 6., 1., 25., 8.};
+          int vecLen = sizeof(intIndicesV) / sizeof(int);
+          for (int i = 0; i < vecLen; i++) {
+               optVal[intIndicesV[i]] = intSolnV[i];
+          }
+#else
+          int intIndicesAt1[] = { 0, 18, 25, 36, 44, 59, 61, 77, 82, 93 };
+          int vecLen = sizeof(intIndicesAt1) / sizeof(int);
+          for (int i = 0; i < vecLen; i++) {
+               optVal[intIndicesAt1[i]] = 1;
+          }
+#endif
+     }
+     if (numberColumns_ == 100) {
+          const char * integerType = integerInformation();
+          for (int i = 0; i < 100; i++) {
+               if (integerType[i]) {
+                    if (columnLower_[i] > optVal[i] || columnUpper_[i] < optVal[i]) {
+                         onOptimal = false;
+                         break;
+                    }
+               }
+          }
+          if (onOptimal) {
+               printf("On optimal path fathom\n");
+	  }
+     }
+#endif
+     if (info->presolveType_) {
+          // crunch down
+          bool feasible = true;
+          // Use dual region
+          double * rhs = dual_;
+          int * whichRow = new int[3*numberRows_];
+          int * whichColumn = new int[2*numberColumns_];
+          int nBound;
+          bool tightenBounds = ((specialOptions_ & 64) == 0) ? false : true;
+          ClpSimplex * small =
+               static_cast<ClpSimplexOther *> (this)->crunch(rhs, whichRow, whichColumn,
+                         nBound, false, tightenBounds);
+          if (small) {
+               //double limit = 0.0;
+               //getDblParam(ClpDualObjectiveLimit, limit);
+               //printf("objlimit a %g",limit);
+               //small->getDblParam(ClpDualObjectiveLimit, limit);
+               //printf(" %g\n",limit);
+               // pack down pseudocosts
+	       small->moreSpecialOptions_ = moreSpecialOptions_;
+               if (info->upPseudo_) {
+                    const char * integerType2 = small->integerInformation();
+                    int n = small->numberColumns();
+                    int k = 0;
+                    int jColumn = 0;
+                    int j = 0;
+                    for (int i = 0; i < n; i++) {
+                         if (integerType2[i]) {
+                              int iColumn = whichColumn[i];
+                              // find
+                              while (jColumn != iColumn) {
+                                   if (integerType_[jColumn])
+                                        j++;
+                                   jColumn++;
+                              }
+                              info->priority_[k] = info->priority_[j];
+                              info->upPseudo_[k] = info->upPseudo_[j];
+                              info->numberUp_[k] = info->numberUp_[j];
+                              info->numberUpInfeasible_[k] = info->numberUpInfeasible_[j];
+                              info->downPseudo_[k] = info->downPseudo_[j];
+                              info->numberDown_[k] = info->numberDown_[j];
+                              info->numberDownInfeasible_[k] = info->numberDownInfeasible_[j];
+                              assert (info->upPseudo_[k] > 1.0e-40 && info->upPseudo_[k] < 1.0e40);
+                              assert (info->downPseudo_[k] > 1.0e-40 && info->downPseudo_[k] < 1.0e40);
+                              k++;
+                         }
+                    }
+               }
+#if 0
+               small->dual();
+               if (small->problemStatus() == 0) {
+                    //problemStatus_ = 0;
+               } else if (small->problemStatus() != 3) {
+                    feasible = false;
+               } else {
+                    if (small->problemStatus_ == 3) {
+                         // may be problems
+                         printf("need coding from OsiClp for crunch\n");
+                         abort();
+                    }
+               }
+#endif
+          } else {
+               feasible = false;
+          }
+          int returnCode = 0;
+          if (feasible) {
+               info->presolveType_ = 0;
+               // save and move pseudo costs
+               returnCode = small->fathom(stuff);
+               // restore pseudocosts
+               if (info->upPseudo_) {
+                    int n = small->numberColumns();
+                    int * back = new int [numberColumns_];
+                    int numberIntegers = 0;
+                    for (int i = 0; i < numberColumns_; i++) {
+                         if (integerType_[i]) {
+                              back[i] = -10 - numberIntegers;
+                              numberIntegers++;
+                         } else {
+                              back[i] = -1;
+                         }
+                    }
+                    const char * integerType2 = small->integerInformation();
+                    int numberIntegers2 = 0;
+                    for (int i = 0; i < n; i++) {
+                         int iColumn = whichColumn[i];
+                         if (integerType2[i]) {
+                              int iBack = -back[iColumn];
+                              assert (iBack >= 10);
+                              iBack -= 10;
+                              back[iColumn] = iBack;
+                              numberIntegers2++;
+                         }
+                    }
+                    int k = numberIntegers2;
+                    for (int i = numberColumns_ - 1; i >= 0; i--) {
+                         int iBack = back[i];
+                         if (iBack <= -10) {
+                              // fixed integer
+                              numberIntegers--;
+                              info->numberUp_[numberIntegers] = -1; // say not updated
+                         } else if (iBack >= 0) {
+                              // not fixed integer
+                              numberIntegers--;
+                              k--;
+                              assert (info->upPseudo_[k] > 1.0e-40 && info->upPseudo_[k] < 1.0e40);
+                              assert (info->downPseudo_[k] > 1.0e-40 && info->downPseudo_[k] < 1.0e40);
+                              info->upPseudo_[numberIntegers] = info->upPseudo_[k];
+                              info->numberUp_[numberIntegers] = info->numberUp_[k];
+                              info->numberUpInfeasible_[numberIntegers] = info->numberUpInfeasible_[k];
+                              info->downPseudo_[numberIntegers] = info->downPseudo_[k];
+                              info->numberDown_[numberIntegers] = info->numberDown_[k];
+                              info->numberDownInfeasible_[numberIntegers] = info->numberDownInfeasible_[k];
+                         }
+                    }
+                    delete [] back;
+               }
+               if (returnCode) {
+                    bool fixBounds = (info->nNodes_ >= 0) ? true : false;
+                    //check this does everything
+                    static_cast<ClpSimplexOther *> (this)->afterCrunch(*small,
+                              whichRow, whichColumn, nBound);
+                    bool badSolution = false;
+                    for (int i = 0; i < numberColumns_; i++) {
+                         if (integerType_[i]) {
+                              double value = columnActivity_[i];
+                              double value2 = floor(value + 0.5);
+                              if (fabs(value - value2) >= 1.0e-4) {
+                                   // Very odd - can't use
+                                   badSolution = true;
+                              }
+                              columnActivity_[i] = value2;
+                              if (fixBounds) {
+                                   columnLower_[i] = value2;
+                                   columnUpper_[i] = value2;
+                              }
+                         }
+                    }
+                    if (badSolution) {
+                         info->nNodes_ = -1;
+                         returnCode = 0;
+                    }
+                    //setLogLevel(63);
+                    //double objectiveValue=doubleCheck();
+                    //printf("Solution of %g\n",objectiveValue);
+               }
+               delete small;
+          }
+          delete [] whichRow;
+          delete [] whichColumn;
+          setMaximumIterations(saveMaxIterations);
+	  setDblParam(ClpDualObjectiveLimit, saveObjLimit);
+          return returnCode;
+     }
+     int returnCode = startFastDual2(info);
+     if (returnCode) {
+          stopFastDual2(info);
+          setMaximumIterations(saveMaxIterations);
+	  setDblParam(ClpDualObjectiveLimit, saveObjLimit);
+          return returnCode;
+     }
+     // Get fake bounds correctly
+     //(static_cast<ClpSimplexDual *>(this))->resetFakeBounds(1);
+     gutsOfSolution ( NULL, NULL);
+     double dummyChange;
+     (static_cast<ClpSimplexDual *>(this))->changeBounds(3, NULL, dummyChange);
+     int saveNumberFake = numberFake_;
+     int status = fastDual2(info);
+#if 0
+     {
+          int iPivot;
+          double * array = rowArray_[3]->denseVector();
+          int i;
+          for (iPivot = 0; iPivot < numberRows_; iPivot++) {
+               int iSequence = pivotVariable_[iPivot];
+               unpack(rowArray_[3], iSequence);
+               factorization_->updateColumn(rowArray_[2], rowArray_[3]);
+               assert (fabs(array[iPivot] - 1.0) < 1.0e-4);
+               array[iPivot] = 0.0;
+               for (i = 0; i < numberRows_; i++)
+                    assert (fabs(array[i]) < 1.0e-4);
+               rowArray_[3]->clear();
+          }
+     }
+#endif
+     CoinAssert (problemStatus_ || objectiveValue_ < 1.0e50);
+     if (status && problemStatus_ != 3) {
+          // not finished - might be optimal
+          checkPrimalSolution(rowActivityWork_, columnActivityWork_);
+          double limit = 0.0;
+          getDblParam(ClpDualObjectiveLimit, limit);
+          //printf("objlimit b %g\n",limit);
+          if (!numberPrimalInfeasibilities_ && objectiveValue()*optimizationDirection_ < limit) {
+               problemStatus_ = 0;
+          }
+          status = problemStatus_;
+     }
+     if (problemStatus_ != 0 && problemStatus_ != 1) {
+#ifdef COIN_DEVELOP
+          printf("bad status %d on initial fast dual %d its\n", problemStatus_,
+                 numberIterations_);
+#endif
+          info->nNodes_ = -1;
+          setMaximumIterations(saveMaxIterations);
+	  setDblParam(ClpDualObjectiveLimit, saveObjLimit);
+          return 0;
+     }
+     int numberNodes = 1;
+     int numberIterations = numberIterations_;
+#if defined(COIN_DEVELOP) || !defined(NO_FATHOM_PRINT)
+     int printFrequency = 2000;
+#endif
+     if (problemStatus_ == 1) {
+          //printf("fathom infeasible on initial\n");
+          stopFastDual2(info);
+          info->numberNodesExplored_ = 1;
+          info->numberIterations_ = numberIterations;
+          setMaximumIterations(saveMaxIterations);
+	  setDblParam(ClpDualObjectiveLimit, saveObjLimit);
+          return 0;
+     } else if (problemStatus_ != 0) {
+          stopFastDual2(info);
+          info->numberNodesExplored_ = 1;
+          info->numberIterations_ = numberIterations;
+          setMaximumIterations(saveMaxIterations);
+	  setDblParam(ClpDualObjectiveLimit, saveObjLimit);
+          // say bad
+          info->nNodes_ = -1;
+          return 0;
+     }
+     if (!columnScale_) {
+          CoinMemcpyN(solution_, numberColumns_, columnActivity_);
+     } else {
+          assert(columnActivity_);
+          assert(columnScale_);
+          assert(solution_);
+          int j;
+          for (j = 0; j < numberColumns_; j++)
+               columnActivity_[j] = solution_[j] * columnScale_[j];
+     }
+     double increment = info->integerIncrement_;
+     int maxDepthSize = 10;
+     int maxDepth = 0;
+     int depth = 0;
+     // Get fake bounds correctly
+     (static_cast<ClpSimplexDual *>(this))->changeBounds(3, NULL, dummyChange);
+     saveNumberFake = numberFake_;
+     ClpNode ** nodes = new ClpNode * [maxDepthSize];
+     int numberTotal = numberRows_ + numberColumns_;
+     double * saveLower = CoinCopyOfArray(columnLower_, numberColumns_);
+     double * saveUpper = CoinCopyOfArray(columnUpper_, numberColumns_);
+     double * saveLowerInternal = CoinCopyOfArray(lower_, numberTotal);
+     double * saveUpperInternal = CoinCopyOfArray(upper_, numberTotal);
+     double * bestLower = NULL;
+     double * bestUpper = NULL;
+     int * back = new int [numberColumns_];
+     int numberIntegers = 0;
+     double sumChanges = 1.0e-5;
+     int numberChanges = 1;
+     for (int i = 0; i < numberColumns_; i++) {
+          if (integerType_[i])
+               back[i] = numberIntegers++;
+          else
+               back[i] = -1;
+     }
+     unsigned char * bestStatus = NULL;
+     double bestObjective;
+     getDblParam(ClpDualObjectiveLimit, bestObjective);
+     double saveBestObjective = bestObjective;
+     bool backtrack = false;
+     bool printing = handler_->logLevel() > 0;
+     while (depth >= 0) {
+          // If backtrack get to correct depth
+          if (backtrack) {
+               depth--;
+               while (depth >= 0) {
+                    if (!nodes[depth]->fathomed()) {
+                         nodes[depth]->changeState();
+                         break;
+                    }
+                    //if (printing)
+                    //printf("deleting node at depth %d\n",depth);
+                    //delete nodes[depth];
+                    //nodes[depth]=NULL;
+                    depth--;
+               }
+               if (depth < 0)
+                    break;
+               // apply
+               // First if backtracking we need to restore factorization, bounds and weights
+               CoinMemcpyN(saveLowerInternal, numberTotal, lower_);
+               CoinMemcpyN(saveUpperInternal, numberTotal, upper_);
+               CoinMemcpyN(saveLower, numberColumns_, columnLower_);
+               CoinMemcpyN(saveUpper, numberColumns_, columnUpper_);
+               for (int i = 0; i < depth; i++) {
+                    nodes[i]->applyNode(this, 0);
+               }
+               nodes[depth]->applyNode(this, 1);
+               int iColumn = nodes[depth]->sequence();
+               if (printing)
+                    printf("after backtracking - applying node at depth %d - variable %d (%g,%g)\n",
+                           depth, iColumn,
+                           columnLower_[iColumn], columnUpper_[iColumn]);
+               depth++;
+          } else {
+               // just bounds
+               if (depth > 0) {
+                    nodes[depth-1]->applyNode(this, 0);
+                    int iColumn = nodes[depth-1]->sequence();
+                    if (printing)
+                         printf("No backtracking - applying node at depth-m %d - variable %d (%g,%g)\n",
+                                depth - 1, iColumn,
+                                columnLower_[iColumn], columnUpper_[iColumn]);
+               }
+          }
+          // solve
+#if 0
+          {
+               int iPivot;
+               double * array = rowArray_[3]->denseVector();
+               int i;
+               for (iPivot = 0; iPivot < numberRows_; iPivot++) {
+                    int iSequence = pivotVariable_[iPivot];
+                    unpack(rowArray_[3], iSequence);
+                    factorization_->updateColumn(rowArray_[2], rowArray_[3]);
+                    assert (fabs(array[iPivot] - 1.0) < 1.0e-4);
+                    array[iPivot] = 0.0;
+                    for (i = 0; i < numberRows_; i++)
+                         assert (fabs(array[i]) < 1.0e-4);
+                    rowArray_[3]->clear();
+               }
+          }
+#endif
+#ifdef COIN_DEVELOP
+	  static int zzzzzz=0;
+	  zzzzzz++;
+	  if ((zzzzzz%100000)==0)
+	    printf("%d fathom solves\n",zzzzzz);
+	  if (zzzzzz==-1) {
+	    printf("TROUBLE\n");
+	  }
+#endif
+          // Get fake bounds correctly
+          (static_cast<ClpSimplexDual *>(this))->changeBounds(3, NULL, dummyChange);
+          fastDual2(info);
+#if 0
+          {
+               int iPivot;
+               double * array = rowArray_[3]->denseVector();
+               int i;
+               for (iPivot = 0; iPivot < numberRows_; iPivot++) {
+                    int iSequence = pivotVariable_[iPivot];
+                    unpack(rowArray_[3], iSequence);
+                    factorization_->updateColumn(rowArray_[2], rowArray_[3]);
+                    assert (fabs(array[iPivot] - 1.0) < 1.0e-4);
+                    array[iPivot] = 0.0;
+                    for (i = 0; i < numberRows_; i++)
+                         assert (fabs(array[i]) < 1.0e-4);
+                    rowArray_[3]->clear();
+               }
+          }
+#endif
+          // give up if odd
+          if (problemStatus_ > 1) {
+               info->nNodes_ = -1;
+#ifdef COIN_DEVELOP
+               printf("OUCH giving up on loop! %d %d %d %d - zzzzzz %d - max %d\n",
+                      numberNodes, numberIterations, problemStatus_, numberIterations_,zzzzzz,intParam_[0]);
+               printf("xx %d\n", numberIterations*(numberRows_ + numberColumns_));
+               //abort();
+#endif
+               break;
+          }
+          numberNodes++;
+          numberIterations += numberIterations_;
+          if ((numberNodes % 1000) == 0) {
+#ifdef COIN_DEVELOP
+               if ((numberNodes % printFrequency) == 0) {
+                    printf("Fathoming from node %d - %d nodes (%d iterations) - current depth %d\n",
+                           info->nodeCalled_,numberNodes, 
+			   numberIterations, depth+info->startingDepth_);
+                    printFrequency *= 2;
+               }
+#elif !defined(NO_FATHOM_PRINT)
+               if ((numberNodes % printFrequency) == 0) {
+		 if ((moreSpecialOptions_&2048)!=0)
+		   info->handler_->message(CLP_FATHOM_STATUS, messages_)
+		     << info->nodeCalled_ << numberNodes 
+		     << numberIterations << depth+info->startingDepth_
+		     << CoinMessageEol;
+		 printFrequency *= 2;
+               }
+#endif
+               if ((numberIterations*(numberRows_ + numberColumns_) > 5.0e10 ||
+		    numberNodes > 2.0e4) &&
+		   (moreSpecialOptions_&4096)==0) {
+                    // give up
+                    info->nNodes_ = -1;
+#ifdef COIN_DEVELOP
+                    printf("OUCH giving up on nodes %d %d\n", numberNodes, numberIterations);
+                    printf("xx %d\n", numberIterations*(numberRows_ + numberColumns_));
+                    //abort();
+#endif
+                    break;
+               }
+          }
+          if (problemStatus_ == 1 ||
+                    (problemStatus_ == 0 && objectiveValue()*optimizationDirection_ > bestObjective)) {
+               backtrack = true;
+               if (printing)
+                    printf("infeasible at depth %d\n", depth);
+               if (depth > 0) {
+                    int way = nodes[depth-1]->way();
+                    int sequence = nodes[depth-1]->sequence();
+#ifndef NDEBUG
+                    double branchingValue = nodes[depth-1]->branchingValue();
+                    if (way > 0)
+                         assert (columnLower_[sequence] == ceil(branchingValue));
+                    else
+                         assert (columnUpper_[sequence] == floor(branchingValue));
+#endif
+                    sequence = back[sequence];
+                    double change = bestObjective - nodes[depth-1]->objectiveValue();
+                    if (change > 1.0e10)
+                         change = 10.0 * sumChanges / (1.0 + numberChanges);
+                    info->update(way, sequence, change, false);
+               }
+          } else if (problemStatus_ != 0) {
+               abort();
+          } else {
+               // Create node
+               ClpNode * node;
+               computeDuals(NULL);
+               if (depth > 0) {
+                    int way = nodes[depth-1]->way();
+                    int sequence = nodes[depth-1]->sequence();
+#ifndef NDEBUG
+                    double branchingValue = nodes[depth-1]->branchingValue();
+                    if (way > 0)
+                         assert (columnLower_[sequence] == ceil(branchingValue));
+                    else
+                         assert (columnUpper_[sequence] == floor(branchingValue));
+#endif
+                    sequence = back[sequence];
+                    info->update(way, sequence,
+                                 objectiveValue() - nodes[depth-1]->objectiveValue(),
+                                 true);
+                    numberChanges++;
+                    sumChanges += objectiveValue() - nodes[depth-1]->objectiveValue();
+               }
+               if (depth < maxDepth) {
+                    node = nodes[depth];
+                    node->gutsOfConstructor(this, info, 1, depth);
+               } else {
+                    node = new ClpNode(this, info, depth);
+                    if (depth == maxDepthSize) {
+                         maxDepthSize = 2 * maxDepthSize + 10;
+                         ClpNode ** temp = new ClpNode * [maxDepthSize];
+                         for (int i = 0; i < depth; i++)
+                              temp[i] = nodes[i];
+                         delete [] nodes;
+                         nodes = temp;
+                    }
+                    nodes[maxDepth++] = node;
+               }
+#if 0
+               if (numberColumns_ == 100 && onOptimal) {
+                    const char * integerType = integerInformation();
+		    bool localOptimal=true;
+                    for (int i = 0; i < 100; i++) {
+                         if (integerType[i]) {
+                              if (columnLower_[i] > optVal[i] || columnUpper_[i] < optVal[i]) {
+				localOptimal = false;
+                                   printf("bad %d %g %g %g\n", i, columnLower_[i], optVal[i],
+                                          columnUpper_[i]);
+				   break;
+                              }
+                         }
+                    }
+		    if (localOptimal) {
+		      printf("still on optimal\n");
+		    }
+                    assert (onOptimal);
+               }
+#endif
+	       double objectiveValue=0.0;
+               if (node->sequence() < 0) {
+		 objectiveValue = doubleCheck();
+		 node->gutsOfConstructor(this, info, 1, depth);
+	       }
+               if (node->sequence() < 0) {
+                    // solution
+                    //double objectiveValue = doubleCheck();
+                    if (objectiveValue < bestObjective) {
+#ifdef COIN_DEVELOP
+		      printf("Fathoming from node %d - solution of %g after %d nodes at depth %d\n",
+			     info->nodeCalled_,objectiveValue, 
+			     numberNodes, depth+info->startingDepth_);
+#elif !defined(NO_FATHOM_PRINT)
+		      if ((moreSpecialOptions_&2048)!=0)
+			info->handler_->message(CLP_FATHOM_SOLUTION, messages_)
+			  << info->nodeCalled_ << objectiveValue 
+			  << numberNodes << depth+info->startingDepth_
+			  << CoinMessageEol;
+#endif
+                         // later then lower_ not columnLower_ (and total?)
+                         delete [] bestLower;
+                         bestLower = CoinCopyOfArray(columnLower_, numberColumns_);
+                         delete [] bestUpper;
+                         bestUpper = CoinCopyOfArray(columnUpper_, numberColumns_);
+                         delete [] bestStatus;
+                         bestStatus = CoinCopyOfArray(status_, numberTotal);
+                         bestObjective = objectiveValue - increment;
+			 if (perturbation_<100) 
+			   bestObjective += 1.0e-2+1.0e-7*fabs(bestObjective);
+                         setDblParam(ClpDualObjectiveLimit, bestObjective * optimizationDirection_);
+                    } else {
+                         //#define CLP_INVESTIGATE
+#ifdef COIN_DEVELOP
+                         printf("why bad solution feasible\n");
+#endif
+                    }
+                    //delete node;
+                    backtrack = true;
+               } else {
+                    if (printing)
+                         printf("depth %d variable %d\n", depth, node->sequence());
+                    depth++;
+                    backtrack = false;
+                    //nodes[depth++] = new ClpNode (this,info);
+               }
+          }
+     }
+     if (!info->nNodes_)
+          assert (depth == -1);
+     for (int i = 0; i < maxDepth; i++)
+          delete nodes[i];
+     delete [] nodes;
+     delete [] back;
+     stopFastDual2(info);
+#ifndef NO_FATHOM_PRINT
+     if ((moreSpecialOptions_&2048)!=0 && numberNodes >= 10000)
+       info->handler_->message(CLP_FATHOM_FINISH, messages_)
+	 << info->nodeCalled_ << info->startingDepth_
+	 << numberNodes << numberIterations << maxDepth+info->startingDepth_
+	 << CoinMessageEol;
+#endif
+     //printf("fathom finished after %d nodes\n",numberNodes);
+     if (bestStatus) {
+          CoinMemcpyN(bestLower, numberColumns_, columnLower_);
+          CoinMemcpyN(bestUpper, numberColumns_, columnUpper_);
+          CoinMemcpyN(bestStatus, numberTotal, status_);
+          delete [] bestLower;
+          delete [] bestUpper;
+          delete [] bestStatus;
+          setDblParam(ClpDualObjectiveLimit, saveBestObjective);
+	  saveObjLimit = saveBestObjective;
+          int saveOptions = specialOptions_;
+          specialOptions_ &= ~65536;
+          dual();
+          specialOptions_ = saveOptions;
+          info->numberNodesExplored_ = numberNodes;
+          info->numberIterations_ = numberIterations;
+          returnCode = 1;
+     } else {
+          info->numberNodesExplored_ = numberNodes;
+          info->numberIterations_ = numberIterations;
+          returnCode = 0;
+     }
+     if (info->nNodes_ < 0) {
+          if (lower_) {
+               CoinMemcpyN(saveLowerInternal, numberTotal, lower_);
+               CoinMemcpyN(saveUpperInternal, numberTotal, upper_);
+               numberFake_ = saveNumberFake;
+          }
+          CoinMemcpyN(saveLower, numberColumns_, columnLower_);
+          CoinMemcpyN(saveUpper, numberColumns_, columnUpper_);
+     }
+     delete [] saveLower;
+     delete [] saveUpper;
+     delete [] saveLowerInternal;
+     delete [] saveUpperInternal;
+     setMaximumIterations(saveMaxIterations);
+     setDblParam(ClpDualObjectiveLimit, saveObjLimit);
+     return returnCode;
+}
+//#define CHECK_PATH
+#ifdef CHECK_PATH
+const double * debuggerSolution_Z = NULL;
+int numberColumns_Z = -1;
+int gotGoodNode_Z = -1;
+#endif
+/* Do up to N deep - returns
+   -1 - no solution nNodes_ valid nodes
+   >= if solution and that node gives solution
+   ClpNode array is 2**N long.  Values for N and
+   array are in stuff (nNodes_ also in stuff) */
+int
+ClpSimplex::fathomMany(void * stuff)
+{
+     assert (stuff);
+     ClpNodeStuff * info = reinterpret_cast<ClpNodeStuff *> (stuff);
+     int nNodes = info->maximumNodes();
+     int putNode = info->maximumSpace();
+     int goodNodes = 0;
+     info->nNodes_ = 0;
+     ClpNode ** nodeInfo = info->nodeInfo_;
+     assert (nodeInfo);
+     // say can declare optimal
+     moreSpecialOptions_ |= 8;
+     double limit = 0.0;
+     getDblParam(ClpDualObjectiveLimit, limit);
+     for (int j = 0; j < putNode; j++) {
+          if (nodeInfo[j]) {
+               nodeInfo[j]->setObjectiveValue(limit);
+               if (info->large_)
+                    nodeInfo[j]->cleanUpForCrunch();
+          }
+     }
+#ifdef CHECK_PATH
+     // Note - if code working can get assert on startOptimal==2 (if finds)
+     int startOptimal = 0;
+     if (numberColumns_ == numberColumns_Z) {
+          assert (debuggerSolution_Z);
+          startOptimal = 1;
+          for (int i = 0; i < numberColumns_; i++) {
+               if (columnUpper_[i] < debuggerSolution_Z[i] || columnLower_[i] > debuggerSolution_Z[i]) {
+                    startOptimal = 0;
+                    break;
+               }
+          }
+          if (startOptimal) {
+               printf("starting on optimal\n");
+          }
+     } else if (info->large_ && info->large_->numberColumns_ == numberColumns_Z) {
+          assert (debuggerSolution_Z);
+          startOptimal = 1;
+          for (int i = 0; i < info->large_->numberColumns_; i++) {
+               if (info->large_->columnUpper_[i] < debuggerSolution_Z[i] || info->large_->columnLower_[i] > debuggerSolution_Z[i]) {
+                    startOptimal = 0;
+                    break;
+               }
+          }
+          if (startOptimal) {
+               printf("starting on optimal (presolved) %d\n", numberColumns_);
+          }
+     }
+#endif
+     int whichSolution = -1;
+     if (info->presolveType_) {
+          // crunch down
+          bool feasible = true;
+          // Use dual region
+          double * rhs = dual_;
+          int * whichRow = new int[3*numberRows_];
+          int * whichColumn = new int[2*numberColumns_];
+          int nBound;
+          bool tightenBounds = ((specialOptions_ & 64) == 0) ? false : true;
+          ClpSimplex * small =
+               static_cast<ClpSimplexOther *> (this)->crunch(rhs, whichRow, whichColumn,
+                         nBound, false, tightenBounds);
+          if (small) {
+               info->large_ = this;
+               info->whichRow_ = whichRow;
+               info->whichColumn_ = whichColumn;
+               info->nBound_ = nBound;
+               //double limit = 0.0;
+               //getDblParam(ClpDualObjectiveLimit, limit);
+               //printf("objlimit a %g",limit);
+               //small->getDblParam(ClpDualObjectiveLimit, limit);
+               //printf(" %g\n",limit);
+               // pack down pseudocosts
+               if (info->upPseudo_) {
+                    const char * integerType2 = small->integerInformation();
+                    int n = small->numberColumns();
+                    int k = 0;
+                    int jColumn = 0;
+                    int j = 0;
+                    for (int i = 0; i < n; i++) {
+                         if (integerType2[i]) {
+                              int iColumn = whichColumn[i];
+                              // find
+                              while (jColumn != iColumn) {
+                                   if (integerType_[jColumn])
+                                        j++;
+                                   jColumn++;
+                              }
+                              info->upPseudo_[k] = info->upPseudo_[j];
+                              info->numberUp_[k] = info->numberUp_[j];
+                              info->numberUpInfeasible_[k] = info->numberUpInfeasible_[j];
+                              info->downPseudo_[k] = info->downPseudo_[j];
+                              info->numberDown_[k] = info->numberDown_[j];
+                              info->numberDownInfeasible_[k] = info->numberDownInfeasible_[j];
+                              assert (info->upPseudo_[k] > 1.0e-40 && info->upPseudo_[k] < 1.0e40);
+                              assert (info->downPseudo_[k] > 1.0e-40 && info->downPseudo_[k] < 1.0e40);
+                              k++;
+                         }
+                    }
+               }
+          } else {
+               feasible = false;
+          }
+          if (feasible) {
+               info->presolveType_ = 0;
+               // save and move pseudo costs
+               whichSolution = small->fathomMany(stuff);
+               // restore pseudocosts
+               if (info->upPseudo_) {
+                    int n = small->numberColumns();
+                    int * back = new int [numberColumns_];
+                    int numberIntegers = 0;
+                    for (int i = 0; i < numberColumns_; i++) {
+                         if (integerType_[i]) {
+                              back[i] = -10 - numberIntegers;
+                              numberIntegers++;
+                         } else {
+                              back[i] = -1;
+                         }
+                    }
+                    const char * integerType2 = small->integerInformation();
+                    int numberIntegers2 = 0;
+                    for (int i = 0; i < n; i++) {
+                         int iColumn = whichColumn[i];
+                         if (integerType2[i]) {
+                              int iBack = -back[iColumn];
+                              assert (iBack >= 10);
+                              iBack -= 10;
+                              back[iColumn] = iBack;
+                              numberIntegers2++;
+                         }
+                    }
+                    int k = numberIntegers2;
+                    for (int i = numberColumns_ - 1; i >= 0; i--) {
+                         int iBack = back[i];
+                         if (iBack <= -10) {
+                              // fixed integer
+                              numberIntegers--;
+                              info->numberUp_[numberIntegers] = -1; // say not updated
+                         } else if (iBack >= 0) {
+                              // not fixed integer
+                              numberIntegers--;
+                              k--;
+                              assert (info->upPseudo_[k] > 1.0e-40 && info->upPseudo_[k] < 1.0e40);
+                              assert (info->downPseudo_[k] > 1.0e-40 && info->downPseudo_[k] < 1.0e40);
+                              info->upPseudo_[numberIntegers] = info->upPseudo_[k];
+                              info->numberUp_[numberIntegers] = info->numberUp_[k];
+                              info->numberUpInfeasible_[numberIntegers] = info->numberUpInfeasible_[k];
+                              info->downPseudo_[numberIntegers] = info->downPseudo_[k];
+                              info->numberDown_[numberIntegers] = info->numberDown_[k];
+                              info->numberDownInfeasible_[numberIntegers] = info->numberDownInfeasible_[k];
+                         }
+                    }
+                    delete [] back;
+               }
+               delete small;
+          }
+          info->large_ = NULL;
+          info->whichRow_ = NULL;
+          info->whichColumn_ = NULL;
+          delete [] whichRow;
+          delete [] whichColumn;
+          return whichSolution;
+     }
+#ifndef DEBUG
+     {
+          int nBasic = 0;
+          int i;
+          for (i = 0; i < numberRows_ + numberColumns_; i++) {
+               if (getColumnStatus(i) == basic)
+                    nBasic++;
+          }
+          assert (nBasic == numberRows_);
+     }
+#endif
+     int returnCode = startFastDual2(info);
+     if (returnCode) {
+          stopFastDual2(info);
+          abort();
+          return -1;
+     }
+     gutsOfSolution ( NULL, NULL);
+     int status = fastDual2(info);
+     CoinAssert (problemStatus_ || objectiveValue_ < 1.0e50);
+     if (status && problemStatus_ != 3) {
+          // not finished - might be optimal
+          checkPrimalSolution(rowActivityWork_, columnActivityWork_);
+          double limit = 0.0;
+          getDblParam(ClpDualObjectiveLimit, limit);
+          //printf("objlimit b %g\n",limit);
+          if (!numberPrimalInfeasibilities_ && objectiveValue()*optimizationDirection_ < limit) {
+               problemStatus_ = 0;
+          }
+          status = problemStatus_;
+     }
+     assert (problemStatus_ == 0 || problemStatus_ == 1); //(static_cast<ClpSimplexDual *> this)->dual(0,0);
+     if (problemStatus_ == 10) {
+          printf("Cleaning up with primal - need coding without createRim!\n");
+          abort();
+     }
+     int numberNodes = 0;
+     int numberIterations = numberIterations_;
+     if (problemStatus_ == 1) {
+          //printf("fathom infeasible on initial\n");
+          stopFastDual2(info);
+          info->nNodes_ = 0;
+          info->numberNodesExplored_ = 0;
+          info->numberIterations_ = numberIterations;
+          return -1;
+     } else if (problemStatus_ != 0) {
+          abort();
+     }
+     if (!columnScale_) {
+          CoinMemcpyN(solution_, numberColumns_, columnActivity_);
+     } else {
+          assert(columnActivity_);
+          assert(columnScale_);
+          assert(solution_);
+          int j;
+          for (j = 0; j < numberColumns_; j++)
+               columnActivity_[j] = solution_[j] * columnScale_[j];
+     }
+     double increment = info->integerIncrement_;
+     int depth = 0;
+     int numberTotal = numberRows_ + numberColumns_;
+     double * saveLower = CoinCopyOfArray(columnLower_, numberColumns_);
+     double * saveUpper = CoinCopyOfArray(columnUpper_, numberColumns_);
+     double * saveLowerInternal = CoinCopyOfArray(lower_, numberTotal);
+     double * saveUpperInternal = CoinCopyOfArray(upper_, numberTotal);
+     //double * bestLower = NULL;
+     //double * bestUpper = NULL;
+     int * back = new int [numberColumns_];
+     int numberIntegers = 0;
+     double sumChanges = 1.0e-5;
+     int numberChanges = 1;
+     for (int i = 0; i < numberColumns_; i++) {
+          if (integerType_[i])
+               back[i] = numberIntegers++;
+          else
+               back[i] = -1;
+     }
+     //unsigned char * bestStatus = NULL;
+     double bestObjective;
+     getDblParam(ClpDualObjectiveLimit, bestObjective);
+     double saveBestObjective = bestObjective;
+     bool backtrack = false;
+     bool printing = handler_->logLevel() > 0;
+#ifdef CHECK_PATH
+     if (startOptimal)
+          printing = true;
+#endif
+     /* Use nodeInfo for storage
+        depth 0 will be putNode-1, 1 putNode-2 etc */
+     int useDepth = putNode - 1;
+     bool justDive = (info->solverOptions_ & 32) != 0;
+     //printf("putNode %d nDepth %d\n");
+     while (depth >= 0) {
+          bool stopAtOnce = false;
+          // If backtrack get to correct depth
+          if (backtrack) {
+               depth--;
+               useDepth++;
+               while (depth >= 0) {
+                    if (!nodeInfo[useDepth]->fathomed()) {
+                         nodeInfo[useDepth]->changeState();
+                         break;
+                    }
+                    //if (printing)
+                    //printf("deleting node at depth %d\n",depth);
+                    //delete nodes[useDepth];
+                    //nodes[useDepth]=NULL;
+                    depth--;
+                    useDepth++;
+               }
+               if (depth < 0)
+                    break;
+               // apply
+               // First if backtracking we need to restore factorization, bounds and weights
+               CoinMemcpyN(saveLowerInternal, numberTotal, lower_);
+               CoinMemcpyN(saveUpperInternal, numberTotal, upper_);
+               CoinMemcpyN(saveLower, numberColumns_, columnLower_);
+               CoinMemcpyN(saveUpper, numberColumns_, columnUpper_);
+               for (int i = 0; i < depth; i++) {
+                    nodeInfo[putNode-1-i]->applyNode(this, 0);
+               }
+               nodeInfo[useDepth]->applyNode(this, 1);
+               if (justDive)
+                    stopAtOnce = true;
+               int iColumn = nodeInfo[useDepth]->sequence();
+               if (printing)
+                    printf("after backtracking - applying node at depth %d - variable %d (%g,%g)\n",
+                           depth, iColumn,
+                           columnLower_[iColumn], columnUpper_[iColumn]);
+               depth++;
+               useDepth--;
+          } else {
+               // just bounds
+               if (depth > 0) {
+                    // Choose variable here!!
+                    nodeInfo[useDepth+1]->chooseVariable(this, info);
+                    nodeInfo[useDepth+1]->applyNode(this, 0);
+                    int iColumn = nodeInfo[useDepth+1]->sequence();
+                    if (printing)
+                         printf("No backtracking - applying node at depth-m %d - variable %d (%g,%g)\n",
+                                depth - 1, iColumn,
+                                columnLower_[iColumn], columnUpper_[iColumn]);
+               }
+          }
+          // solve
+          double dummyChange;
+          (static_cast<ClpSimplexDual *>(this))->changeBounds(3, NULL, dummyChange);
+          //int saveNumberFake = numberFake_;
+          fastDual2(info);
+          numberNodes++;
+          numberIterations += numberIterations_;
+          if ((numberNodes % 1000) == 0 && printing)
+               printf("After %d nodes (%d iterations) - best solution %g - current depth %d\n",
+                      numberNodes, numberIterations, bestObjective, depth);
+          if (problemStatus_ == 1 ||
+                    (problemStatus_ == 0 && objectiveValue()*optimizationDirection_ > bestObjective)) {
+               backtrack = true;
+               if (printing)
+                    printf("infeasible at depth %d\n", depth);
+#ifdef CHECK_PATH
+               if (startOptimal && numberColumns_ == numberColumns_Z) {
+                    bool onOptimal = true;
+                    for (int i = 0; i < numberColumns_; i++) {
+                         if (columnUpper_[i] < debuggerSolution_Z[i] || columnLower_[i] > debuggerSolution_Z[i]) {
+                              onOptimal = false;
+                              break;
+                         }
+                    }
+                    if (onOptimal) {
+                         printf("INF on optimal fathom at depth %d\n", depth);
+                         abort();
+                    }
+               } else if (info->large_ && startOptimal && info->large_->numberColumns_ == numberColumns_Z) {
+                    bool onOptimal = true;
+                    for (int i = 0; i < info->large_->numberColumns_; i++) {
+                         if (info->large_->columnUpper_[i] < debuggerSolution_Z[i] || info->large_->columnLower_[i] > debuggerSolution_Z[i]) {
+                              onOptimal = false;
+                              break;
+                         }
+                    }
+                    if (onOptimal) {
+                         printf("INF on optimal (pre) fathom at depth %d\n", depth);
+                         writeMps("fathom_pre.mps");
+                         abort();
+                    }
+               }
+#endif
+               if (depth > 0) {
+                    int way = nodeInfo[useDepth+1]->way();
+                    int sequence = nodeInfo[useDepth+1]->sequence();
+#ifndef NDEBUG
+                    double branchingValue = nodeInfo[useDepth+1]->branchingValue();
+                    if (way > 0)
+                         assert (columnLower_[sequence] == ceil(branchingValue));
+                    else
+                         assert (columnUpper_[sequence] == floor(branchingValue));
+#endif
+                    sequence = back[sequence];
+                    double change = bestObjective - nodeInfo[useDepth+1]->objectiveValue();
+                    if (change > 1.0e10)
+                         change = 10.0 * sumChanges / (1.0 + numberChanges);
+                    info->update(way, sequence, change, false);
+               }
+          } else if (problemStatus_ != 0) {
+               abort();
+          } else {
+               // Create node
+               ClpNode * node;
+               computeDuals(NULL);
+               if (depth > 0) {
+                    int way = nodeInfo[useDepth+1]->way();
+                    int sequence = nodeInfo[useDepth+1]->sequence();
+#ifndef NDEBUG
+                    double branchingValue = nodeInfo[useDepth+1]->branchingValue();
+                    if (way > 0)
+                         assert (columnLower_[sequence] == ceil(branchingValue));
+                    else
+                         assert (columnUpper_[sequence] == floor(branchingValue));
+#endif
+                    sequence = back[sequence];
+                    info->update(way, sequence,
+                                 objectiveValue() - nodeInfo[useDepth+1]->objectiveValue(),
+                                 true);
+                    numberChanges++;
+                    sumChanges += objectiveValue() - nodeInfo[useDepth+1]->objectiveValue();
+               }
+#ifdef CHECK_PATH
+               if (startOptimal && numberColumns_ == numberColumns_Z) {
+                    bool onOptimal = true;
+                    for (int i = 0; i < numberColumns_; i++) {
+                         if (columnUpper_[i] < debuggerSolution_Z[i] || columnLower_[i] > debuggerSolution_Z[i]) {
+                              onOptimal = false;
+                              break;
+                         }
+                    }
+                    if (onOptimal) {
+                         if (depth >= info->nDepth_) {
+                              printf("on optimal fathom at full depth %d %d %g\n",
+                                     depth, goodNodes, objectiveValue());
+                              gotGoodNode_Z = goodNodes;
+                              startOptimal = 2;
+                         } else {
+                              printf("on optimal fathom at depth %d\n", depth);
+                         }
+                    }
+               } else if (info->large_ && startOptimal && info->large_->numberColumns_ == numberColumns_Z) {
+                    bool onOptimal = true;
+                    // Fix bounds in large
+                    for (int i = 0; i < numberColumns_; i++) {
+                         if (integerType_[i]) {
+                              int iColumn = info->whichColumn_[i];
+                              info->large_->columnUpper_[iColumn] = columnUpper_[i];
+                              info->large_->columnLower_[iColumn] = columnLower_[i];
+                              COIN_DETAIL_PRINT(printf("%d dj %g dual %g scale %g\n",
+						       iColumn, dj_[i], reducedCost_[i], columnScale_[i]));
+
+                         }
+                    }
+                    for (int i = 0; i < info->large_->numberColumns_; i++) {
+                         if (info->large_->columnUpper_[i] < debuggerSolution_Z[i] || info->large_->columnLower_[i] > debuggerSolution_Z[i]) {
+                              onOptimal = false;
+                              break;
+                         }
+                    }
+                    if (onOptimal) {
+                         if (depth >= info->nDepth_) {
+                              printf("on (pre) tentative optimal fathom at full depth %d %d %g\n",
+                                     depth, goodNodes, objectiveValue());
+                              for (int i = 0; i < info->large_->numberColumns_; i++)
+                                   printf("fathomA %d %g %g\n", i, info->large_->columnLower_[i],
+                                          info->large_->columnUpper_[i]);
+                         } else {
+                              printf("on (pre) optimal fathom at depth %d\n", depth);
+                         }
+                    }
+               }
+#endif
+               if (depth < info->nDepth_ && !stopAtOnce) {
+                    node = nodeInfo[useDepth];
+                    if (node) {
+                         node->gutsOfConstructor(this, info, 1, depth);
+                    } else {
+                         node = new ClpNode(this, info, depth);
+                         nodeInfo[useDepth] = node;
+                    }
+               } else {
+                    // save
+                    node = nodeInfo[goodNodes];
+                    if (!node) {
+                         node = new ClpNode(this, info, depth);
+                         nodeInfo[goodNodes] = node;
+                    }
+                    if (!node->oddArraysExist())
+                         node->createArrays(this);
+                    node->gutsOfConstructor(this, info, 2, depth);
+               }
+               if (node->sequence() < 0) {
+                    // solution
+                    double objectiveValue = doubleCheck();
+                    if (printing)
+                         printf("Solution of %g after %d nodes at depth %d\n",
+                                objectiveValue, numberNodes, depth);
+                    if (objectiveValue < bestObjective && !problemStatus_) {
+                         // make sure node exists
+                         node = nodeInfo[goodNodes];
+                         if (!node) {
+                              node = new ClpNode(this, info, depth);
+                              nodeInfo[goodNodes] = node;
+                         }
+                         if (info->large_) {
+                              //check this does everything
+                              // Fix bounds in large
+                              for (int i = 0; i < numberColumns_; i++) {
+                                   if (integerType_[i]) {
+                                        int iColumn = info->whichColumn_[i];
+                                        info->large_->columnUpper_[iColumn] = columnUpper_[i];
+                                        info->large_->columnLower_[iColumn] = columnLower_[i];
+                                   }
+                              }
+                              static_cast<ClpSimplexOther *> (info->large_)->afterCrunch(*this,
+                                        info->whichRow_, info->whichColumn_, info->nBound_);
+                              // do as for large
+                              if (!node->oddArraysExist())
+                                   node->createArrays(info->large_);
+                              node->gutsOfConstructor(info->large_, info, 2, depth);
+                         } else {
+                              if (!node->oddArraysExist())
+                                   node->createArrays(this);
+                              node->gutsOfConstructor(this, info, 2, depth);
+                         }
+                         whichSolution = goodNodes;
+                         goodNodes++;
+                         if (goodNodes >= nNodes)
+                              justDive = true; // clean up phase
+                         assert (node->sequence() < 0);
+                         bestObjective = objectiveValue - increment;
+                         setDblParam(ClpDualObjectiveLimit, bestObjective * optimizationDirection_);
+                    } else {
+#ifdef CLP_INVESTIGATE
+                         printf("why bad solution feasible\n");
+                         abort();
+#endif
+                    }
+                    backtrack = true;
+               } else {
+                    //if (printing)
+                    //printf("depth %d variable %d\n",depth,node->sequence());
+                    if (depth == info->nDepth_ || stopAtOnce) {
+                         if (info->large_) {
+                              //check this does everything
+                              // Fix bounds in large
+                              for (int i = 0; i < numberColumns_; i++) {
+                                   if (integerType_[i]) {
+                                        int iColumn = info->whichColumn_[i];
+                                        info->large_->columnUpper_[iColumn] = columnUpper_[i];
+                                        info->large_->columnLower_[iColumn] = columnLower_[i];
+                                   }
+                              }
+#ifdef CHECK_PATH
+                              if (startOptimal)
+                                   for (int i = 0; i < info->large_->numberColumns_; i++)
+                                        printf("fathomB %d %g %g %g\n", i, info->large_->columnLower_[i],
+                                               info->large_->columnUpper_[i],
+                                               node->dualSolution()[i]);
+#endif
+                              static_cast<ClpSimplexOther *> (info->large_)->afterCrunch(*this,
+                                        info->whichRow_, info->whichColumn_, info->nBound_);
+#ifdef CHECK_PATH
+                              if (startOptimal) {
+                                   bool onOptimal = true;
+                                   for (int i = 0; i < info->large_->numberColumns_; i++)
+                                        printf("fathomC %d %g %g\n", i, info->large_->columnLower_[i],
+                                               info->large_->columnUpper_[i]);
+                                   for (int i = 0; i < info->large_->numberColumns_; i++) {
+                                        if (info->large_->columnUpper_[i] < debuggerSolution_Z[i] || info->large_->columnLower_[i] > debuggerSolution_Z[i]) {
+                                             onOptimal = false;
+                                             break;
+                                        }
+                                   }
+                                   if (onOptimal) {
+                                        printf("on (pre) optimal fathom at full depth %d %d %g\n",
+                                               depth, goodNodes, info->large_->objectiveValue());
+                                        startOptimal = 2;
+                                        gotGoodNode_Z = goodNodes;
+                                        for (int i = 0; i < info->large_->numberColumns_; i++)
+                                             printf("fathom %d %g %g\n", i, info->large_->columnLower_[i],
+                                                    info->large_->columnUpper_[i]);
+                                   }
+                              }
+#endif
+                              // do as for large
+                              node->gutsOfConstructor(info->large_, info, 2, depth);
+                         }
+                         goodNodes++;
+                         if (goodNodes >= nNodes)
+                              justDive = true; // clean up phase
+                         backtrack = true;
+                    } else {
+                         depth++;
+                         useDepth--;
+                         backtrack = false;
+                    }
+               }
+          }
+     }
+     //printf("nNodes %d nDepth %d, useDepth %d goodNodes %d\n",
+     // nNodes,info->nDepth_,useDepth,goodNodes);
+#ifdef CHECK_PATH
+     if (startOptimal) {
+          assert(startOptimal == 2);
+          printf("got fathomed optimal at end %d\n", startOptimal);
+          if (startOptimal != 2)
+               abort();
+     }
+#endif
+     assert (depth == -1);
+     delete [] saveLower;
+     delete [] saveUpper;
+     delete [] saveLowerInternal;
+     delete [] saveUpperInternal;
+     delete [] back;
+     //printf("fathom finished after %d nodes\n",numberNodes);
+     if (whichSolution >= 0) {
+          setDblParam(ClpDualObjectiveLimit, saveBestObjective);
+     }
+     stopFastDual2(info);
+     info->nNodes_ = goodNodes;
+     info->numberNodesExplored_ = numberNodes;
+     info->numberIterations_ = numberIterations;
+     return whichSolution;
+}
+// Double checks OK
+double
+ClpSimplex::doubleCheck()
+{
+#if 0
+     double * solution = CoinCopyOfArray(solution_, numberColumns_ + numberRows_);
+     gutsOfSolution ( NULL, NULL);
+     for (int i = 0; i < numberColumns_; i++) {
+          if (fabs(solution[i] - solution_[i]) > 1.0e-7)
+               printf("bada %d bad %g good %g\n",
+                      i, solution[i], solution_[i]);
+     }
+     //abort();
+#endif
+     // make sure clean
+     whatsChanged_=0;
+     dual(0, 7);
+#if 0
+     for (int i = 0; i < numberColumns_; i++) {
+          if (fabs(solution[i] - solution_[i]) > 1.0e-7)
+               printf("badb %d bad %g good %g\n",
+                      i, solution[i], solution_[i]);
+     }
+     dual(0, 1);
+     for (int i = 0; i < numberColumns_; i++) {
+          if (fabs(solution[i] - solution_[i]) > 1.0e-7)
+               printf("badc %d bad %g good %g\n",
+                      i, solution[i], solution_[i]);
+     }
+     delete [] solution;
+#endif
+     return objectiveValue() * optimizationDirection_;
+}
+// Start Fast dual
+int
+ClpSimplex::startFastDual2(ClpNodeStuff * info)
+{
+     info->saveOptions_ = specialOptions_;
+     assert ((info->solverOptions_ & 65536) == 0);
+     info->solverOptions_ |= 65536;
+     if ((specialOptions_ & 65536) == 0) {
+          factorization_->setPersistenceFlag(2);
+     } else {
+          factorization_->setPersistenceFlag(2);
+          startPermanentArrays();
+     }
+     //assert (!lower_);
+     // create modifiable copies of model rim and do optional scaling
+     createRim(7 + 8 + 16 + 32, true, 0);
+#ifndef NDEBUG
+     ClpPackedMatrix* clpMatrix =
+          dynamic_cast< ClpPackedMatrix*>(matrix_);
+     assert (clpMatrix && (clpMatrix->flags() & 1) == 0);
+#endif
+     // mark all as current
+     whatsChanged_ = 0x3ffffff;
+
+     // change newLower and newUpper if scaled
+
+     // Do initial factorization
+     // and set certain stuff
+     // We can either set increasing rows so ...IsBasic gives pivot row
+     // or we can just increment iBasic one by one
+     // for now let ...iBasic give pivot row
+     int factorizationStatus = internalFactorize(0);
+     if (factorizationStatus < 0 ||
+               (factorizationStatus && factorizationStatus <= numberRows_)) {
+          // some error
+#if 0
+          // we should either debug or ignore
+#ifdef CLP_INVESTIGATE
+          //#ifndef NDEBUG
+          printf("***** ClpDual strong branching factorization error - debug\n");
+          abort();
+          //#endif
+#endif
+          return -2;
+#else
+          dual(0, 7);
+          createRim(7 + 8 + 16 + 32, true, 0);
+          int factorizationStatus = internalFactorize(0);
+          assert (factorizationStatus == 0);
+          if (factorizationStatus)
+               abort();
+#endif
+     }
+     // Start of fast iterations
+     factorization_->sparseThreshold(0);
+     factorization_->goSparse();
+     assert (!info->saveCosts_);
+     int numberTotal = numberRows_ + numberColumns_;
+     double * save = new double [4*numberTotal];
+     CoinMemcpyN(cost_, numberTotal, save+3*numberTotal);
+     if (perturbation_<100) {
+       int saveIterations = numberIterations_;
+       //int saveOptions = moreSpecialOptions_;
+       int savePerturbation = perturbation_;
+       numberIterations_ = 0;
+       //moreSpecialOptions_ |= 128;
+       bool allZero = true;
+       for (int i=0;i<numberColumns_;i++) {
+	 if (cost_[i]) {
+	   if (upper_[i]>lower_[i]) {
+	     allZero=false;
+	     break;
+	   }
+	 }
+       }
+       if (allZero)
+	 perturbation_ = 58;
+       static_cast< ClpSimplexDual *>(this)->perturb();
+       numberIterations_ = saveIterations;
+       //moreSpecialOptions_ = saveOptions;
+       perturbation_ = savePerturbation;
+     }
+     info->saveCosts_ = save;
+     CoinMemcpyN(cost_, numberTotal, save);
+     return 0;
+}
+// Like Fast dual
+int
+ClpSimplex::fastDual2(ClpNodeStuff * info)
+{
+     assert ((info->solverOptions_ & 65536) != 0);
+     int numberTotal = numberRows_ + numberColumns_;
+     assert (info->saveCosts_);
+     double * save = info->saveCosts_;
+     CoinMemcpyN(save, numberTotal, cost_);
+     save += numberTotal;
+     CoinMemcpyN(lower_, numberTotal, save);
+     save += numberTotal;
+     CoinMemcpyN(upper_, numberTotal, save);
+     double dummyChange;
+     (static_cast<ClpSimplexDual *>(this))->changeBounds(3, NULL, dummyChange);
+     numberPrimalInfeasibilities_ = 1;
+     sumPrimalInfeasibilities_ = 0.5;
+     sumOfRelaxedDualInfeasibilities_ = 0.0;
+     sumOfRelaxedPrimalInfeasibilities_ = 0.5;
+     checkDualSolution();
+     //if (xxxxxx)
+     //checkPrimalSolution(rowActivityWork_,columnActivityWork_);
+     assert((specialOptions_ & 16384) == 0);
+     specialOptions_ |= 524288; // say use solution
+     ClpObjective * saveObjective = objective_;
+#ifndef NDEBUG
+     //(static_cast<ClpSimplexDual *>(this))->resetFakeBounds(-1);
+#endif
+     //int saveNumberFake = numberFake_;
+     int status = static_cast<ClpSimplexDual *> (this)->fastDual(true);
+     //numberFake_ = saveNumberFake;
+     specialOptions_ &= ~524288; // say dont use solution
+     CoinAssert (problemStatus_ || objectiveValue_ < 1.0e50);
+     if (status && problemStatus_ != 3) {
+          // not finished - might be optimal
+          checkPrimalSolution(rowActivityWork_, columnActivityWork_);
+          double limit = 0.0;
+          getDblParam(ClpDualObjectiveLimit, limit);
+          if (!numberPrimalInfeasibilities_ && objectiveValue()*optimizationDirection_ < limit) {
+               problemStatus_ = 0;
+          }
+     }
+     if (problemStatus_ == 10) {
+          // Say second call
+          moreSpecialOptions_ |= 256;
+          //printf("Cleaning up with primal\n");
+          //lastAlgorithm=1;
+          int savePerturbation = perturbation_;
+          int saveLog = handler_->logLevel();
+          //handler_->setLogLevel(63);
+          perturbation_ = 100;
+          bool denseFactorization = initialDenseFactorization();
+          // It will be safe to allow dense
+          setInitialDenseFactorization(true);
+          // Allow for catastrophe
+          int saveMax = intParam_[ClpMaxNumIteration];
+          if (intParam_[ClpMaxNumIteration] > 100000 + numberIterations_)
+               intParam_[ClpMaxNumIteration] = numberIterations_ + 1000 + 2 * numberRows_ + numberColumns_;
+          // check which algorithms allowed
+          baseIteration_ = numberIterations_;
+          status = static_cast<ClpSimplexPrimal *> (this)->primal(1, 7);
+          baseIteration_ = 0;
+          if (saveObjective != objective_) {
+               // We changed objective to see if infeasible
+               delete objective_;
+               objective_ = saveObjective;
+               if (!problemStatus_) {
+                    // carry on
+                    status = static_cast<ClpSimplexPrimal *> (this)->primal(1, 7);
+               }
+          }
+          if (problemStatus_ == 3 && numberIterations_ < saveMax) {
+#ifdef COIN_DEVELOP
+               if (handler_->logLevel() > 0)
+                    printf("looks like trouble - too many iterations in clean up - trying again\n");
+#endif
+               // flatten solution and try again
+               int iColumn;
+               for (iColumn = 0; iColumn < numberTotal; iColumn++) {
+                    if (getStatus(iColumn) != basic) {
+                         setStatus(iColumn, superBasic);
+                         // but put to bound if close
+                         if (fabs(solution_[iColumn] - lower_[iColumn])
+                                   <= primalTolerance_) {
+                              solution_[iColumn] = lower_[iColumn];
+                              setStatus(iColumn, atLowerBound);
+                         } else if (fabs(solution_[iColumn]
+                                         - upper_[iColumn])
+                                    <= primalTolerance_) {
+                              solution_[iColumn] = upper_[iColumn];
+                              setStatus(iColumn, atUpperBound);
+                         }
+                    }
+               }
+               problemStatus_ = -1;
+               intParam_[ClpMaxNumIteration] = CoinMin(numberIterations_ + 1000 +
+                                                       2 * numberRows_ + numberColumns_, saveMax);
+               perturbation_ = savePerturbation;
+               baseIteration_ = numberIterations_;
+               status = static_cast<ClpSimplexPrimal *> (this)->primal(0);
+               baseIteration_ = 0;
+               computeObjectiveValue();
+               // can't rely on djs either
+               memset(reducedCost_, 0, numberColumns_ * sizeof(double));
+#ifdef COIN_DEVELOP
+               if (problemStatus_ == 3 && numberIterations_ < saveMax && handler_->logLevel() > 0)
+                    printf("looks like real trouble - too many iterations in second clean up - giving up\n");
+#endif
+          }
+          // Say not second call
+          moreSpecialOptions_ &= ~256;
+          intParam_[ClpMaxNumIteration] = saveMax;
+
+          setInitialDenseFactorization(denseFactorization);
+          perturbation_ = savePerturbation;
+          if (problemStatus_ == 10) {
+               if (!numberPrimalInfeasibilities_)
+                    problemStatus_ = 0;
+               else
+                    problemStatus_ = 4;
+          }
+          handler_->setLogLevel(saveLog);
+	  // if done primal arrays may be rubbish
+	  save = info->saveCosts_ + numberTotal;
+	  CoinMemcpyN(save, numberTotal, lower_);
+	  save += numberTotal;
+	  CoinMemcpyN(save, numberTotal, upper_);
+     }
+     status = problemStatus_;
+     if (!problemStatus_) {
+          int j;
+          // Move solution to external array
+          if (!columnScale_) {
+               CoinMemcpyN(solution_, numberColumns_, columnActivity_);
+          } else {
+               for (j = 0; j < numberColumns_; j++)
+                    columnActivity_[j] = solution_[j] * columnScale_[j];
+          }
+          if ((info->solverOptions_ & 1) != 0) {
+               // reduced costs
+               if (!columnScale_) {
+                    CoinMemcpyN(dj_, numberColumns_, reducedCost_);
+               } else {
+                    for (j = 0; j < numberColumns_; j++)
+                         reducedCost_[j] = dj_[j] * columnScale_[j+numberColumns_];
+               }
+          }
+          if ((info->solverOptions_ & 2) != 0) {
+               // dual
+               if (!rowScale_) {
+                    //CoinMemcpyN(dual_,numberRows_,dj_+numberColumns_);
+               } else {
+                    for (j = 0; j < numberRows_; j++)
+                         dual_[j] = dj_[j+numberColumns_] * rowScale_[j];
+               }
+          }
+          if ((info->solverOptions_ & 4) != 0) {
+               // row activity
+               if (!rowScale_) {
+                    CoinMemcpyN(solution_ + numberColumns_, numberRows_, rowActivity_);
+               } else {
+                    for (j = 0; j < numberRows_; j++)
+                         rowActivity_[j] = solution_[j+numberColumns_] * rowScale_[j+numberRows_];
+               }
+          }
+     }
+     save = info->saveCosts_;
+     CoinMemcpyN(save, numberTotal, cost_);
+#if 0
+     save += numberTotal;
+     CoinMemcpyN(save, numberTotal, lower_);
+     save += numberTotal;
+     CoinMemcpyN(save, numberTotal, upper_);
+#endif
+     return status;
+}
+// Stop Fast dual
+void
+ClpSimplex::stopFastDual2(ClpNodeStuff * info)
+{
+     delete [] info->saveCosts_;
+     info->saveCosts_ = NULL;
+     specialOptions_ = info->saveOptions_;
+     // try just factorization
+     if ((specialOptions_ & 65536) == 0)
+          factorization_->setPersistenceFlag(0);
+     deleteRim(1);
+     whatsChanged_ &= ~0xffff;
+     assert ((info->solverOptions_ & 65536) != 0);
+     info->solverOptions_ &= ~65536;
+}
+// Deals with crunch aspects
+ClpSimplex *
+ClpSimplex::fastCrunch(ClpNodeStuff * info, int mode)
+{
+     ClpSimplex * small = NULL;
+     if (mode == 0) {
+          // before crunch
+          // crunch down
+          // Use dual region
+          double * rhs = dual_;
+          int * whichRow = new int[3*numberRows_];
+          int * whichColumn = new int[2*numberColumns_];
+          int nBound;
+          bool tightenBounds = ((specialOptions_ & 64) == 0) ? false : true;
+          small =
+               static_cast<ClpSimplexOther *> (this)->crunch(rhs, whichRow, whichColumn,
+                         nBound, false, tightenBounds);
+          if (small) {
+               info->large_ = this;
+               info->whichRow_ = whichRow;
+               info->whichColumn_ = whichColumn;
+               info->nBound_ = nBound;
+               if (info->upPseudo_) {
+                    const char * integerType2 = small->integerInformation();
+                    int n = small->numberColumns();
+                    int k = 0;
+                    int jColumn = 0;
+                    int j = 0;
+                    for (int i = 0; i < n; i++) {
+                         if (integerType2[i]) {
+                              int iColumn = whichColumn[i];
+                              // find
+                              while (jColumn != iColumn) {
+                                   if (integerType_[jColumn])
+                                        j++;
+                                   jColumn++;
+                              }
+                              info->upPseudo_[k] = info->upPseudo_[j];
+                              info->numberUp_[k] = info->numberUp_[j];
+                              info->numberUpInfeasible_[k] = info->numberUpInfeasible_[j];
+                              info->downPseudo_[k] = info->downPseudo_[j];
+                              info->numberDown_[k] = info->numberDown_[j];
+                              info->numberDownInfeasible_[k] = info->numberDownInfeasible_[j];
+                              assert (info->upPseudo_[k] > 1.0e-40 && info->upPseudo_[k] < 1.0e40);
+                              assert (info->downPseudo_[k] > 1.0e-40 && info->downPseudo_[k] < 1.0e40);
+                              k++;
+                         }
+                    }
+               }
+          } else {
+               delete [] whichRow;
+               delete [] whichColumn;
+          }
+     } else {
+          // after crunch
+          if (mode == 1) {
+               // has solution
+               ClpSimplex * other = info->large_;
+               assert (other != this);
+               static_cast<ClpSimplexOther *> (other)->afterCrunch(*this,
+                         info->whichRow_,
+                         info->whichColumn_, info->nBound_);
+               for (int i = 0; i < other->numberColumns_; i++) {
+                    if (other->integerType_[i]) {
+                         double value = other->columnActivity_[i];
+                         double value2 = floor(value + 0.5);
+                         assert (fabs(value - value2) < 1.0e-4);
+                         other->columnActivity_[i] = value2;
+                         other->columnLower_[i] = value2;
+                         other->columnUpper_[i] = value2;
+                    }
+               }
+          }
+          delete [] info->whichRow_;
+          delete [] info->whichColumn_;
+     }
+     return small;
+}
+// Resizes rim part of model
+void
+ClpSimplex::resize (int newNumberRows, int newNumberColumns)
+{
+     ClpModel::resize(newNumberRows, newNumberColumns);
+     delete [] perturbationArray_;
+     perturbationArray_ = NULL;
+     maximumPerturbationSize_=0;
+     if (saveStatus_) {
+          // delete arrays
+          int saveOptions = specialOptions_;
+          specialOptions_ = 0;
+          gutsOfDelete(2);
+          specialOptions_ = saveOptions;
+     }
+}
+// Return true if the objective limit test can be relied upon
+bool
+ClpSimplex::isObjectiveLimitTestValid() const
+{
+     if (problemStatus_ == 0) {
+          return true;
+     } else if (problemStatus_ == 1) {
+          // ok if dual
+          return (algorithm_ < 0);
+     } else if (problemStatus_ == 2) {
+          // ok if primal
+          return (algorithm_ > 0);
+     } else {
+          return false;
+     }
+}
+// Create C++ lines to get to current state
+void
+ClpSimplex::generateCpp( FILE * fp, bool defaultFactor)
+{
+     ClpModel::generateCpp(fp);
+     ClpSimplex defaultModel;
+     ClpSimplex * other = &defaultModel;
+     int iValue1, iValue2;
+     double dValue1, dValue2;
+     // Stuff that can't be done easily
+     if (factorizationFrequency() == other->factorizationFrequency()) {
+          if (defaultFactor) {
+               fprintf(fp, "3  // For branchAndBound this may help\n");
+               fprintf(fp, "3  clpModel->defaultFactorizationFrequency();\n");
+          } else {
+               // tell user about default
+               fprintf(fp, "3  // For initialSolve you don't need below but ...\n");
+               fprintf(fp, "3  // clpModel->defaultFactorizationFrequency();\n");
+          }
+     }
+     iValue1 = this->factorizationFrequency();
+     iValue2 = other->factorizationFrequency();
+     fprintf(fp, "%d  int save_factorizationFrequency = clpModel->factorizationFrequency();\n", iValue1 == iValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setFactorizationFrequency(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+     fprintf(fp, "%d  clpModel->setFactorizationFrequency(save_factorizationFrequency);\n", iValue1 == iValue2 ? 7 : 6);
+     dValue1 = this->dualBound();
+     dValue2 = other->dualBound();
+     fprintf(fp, "%d  double save_dualBound = clpModel->dualBound();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setDualBound(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setDualBound(save_dualBound);\n", dValue1 == dValue2 ? 7 : 6);
+     dValue1 = this->infeasibilityCost();
+     dValue2 = other->infeasibilityCost();
+     fprintf(fp, "%d  double save_infeasibilityCost = clpModel->infeasibilityCost();\n", dValue1 == dValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setInfeasibilityCost(%g);\n", dValue1 == dValue2 ? 4 : 3, dValue1);
+     fprintf(fp, "%d  clpModel->setInfeasibilityCost(save_infeasibilityCost);\n", dValue1 == dValue2 ? 7 : 6);
+     iValue1 = this->perturbation();
+     iValue2 = other->perturbation();
+     fprintf(fp, "%d  int save_perturbation = clpModel->perturbation();\n", iValue1 == iValue2 ? 2 : 1);
+     fprintf(fp, "%d  clpModel->setPerturbation(%d);\n", iValue1 == iValue2 ? 4 : 3, iValue1);
+     fprintf(fp, "%d  clpModel->setPerturbation(save_perturbation);\n", iValue1 == iValue2 ? 7 : 6);
+}
+// Copy across enabled stuff from one solver to another
+void 
+ClpSimplex::copyEnabledStuff(const ClpSimplex * rhs)
+{
+  solveType_=rhs->solveType_; 
+  if (rhs->solution_) {
+    int numberTotal = numberRows_+numberColumns_;
+    assert (!solution_);
+    solution_ = CoinCopyOfArray(rhs->solution_,numberTotal);
+    lower_ = CoinCopyOfArray(rhs->lower_,numberTotal);
+    upper_ = CoinCopyOfArray(rhs->upper_,numberTotal);
+    dj_ = CoinCopyOfArray(rhs->dj_,numberTotal);
+    cost_ = CoinCopyOfArray(rhs->cost_,2*numberTotal);
+    reducedCostWork_ = dj_;
+    rowReducedCost_ = dj_ + numberColumns_;
+    columnActivityWork_ = solution_;
+    rowActivityWork_ = solution_ + numberColumns_;
+    objectiveWork_ = cost_;
+    rowObjectiveWork_ = cost_ + numberColumns_;
+    rowLowerWork_ = lower_ + numberColumns_;
+    columnLowerWork_ = lower_;
+    rowUpperWork_ = upper_ + numberColumns_;
+    columnUpperWork_ = upper_;
+  }
+  if (rhs->factorization_) {
+    delete factorization_;
+    factorization_ = new ClpFactorization(*rhs->factorization_);
+    delete [] pivotVariable_;
+    pivotVariable_ = CoinCopyOfArray(rhs->pivotVariable_,numberRows_);
+  }
+  for (int i = 0; i < 6; i++) {
+    if (rhs->rowArray_[i])
+      rowArray_[i] = new CoinIndexedVector(*rhs->rowArray_[i]);
+    if (rhs->columnArray_[i])
+      columnArray_[i] = new CoinIndexedVector(*rhs->columnArray_[i]);
+  }
+  if (rhs->nonLinearCost_)
+    nonLinearCost_=new ClpNonLinearCost(*rhs->nonLinearCost_);
+  if (rhs->dualRowPivot_)
+    dualRowPivot_ = rhs->dualRowPivot_->clone();
+  if (rhs->primalColumnPivot_)
+    primalColumnPivot_ = rhs->primalColumnPivot_->clone();
+}
diff --git a/cbits/coin/ClpSimplex.hpp b/cbits/coin/ClpSimplex.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplex.hpp
@@ -0,0 +1,1684 @@
+/* $Id: ClpSimplex.hpp 1989 2013-11-11 17:27:32Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef ClpSimplex_H
+#define ClpSimplex_H
+
+#include <iostream>
+#include <cfloat>
+#include "ClpModel.hpp"
+#include "ClpMatrixBase.hpp"
+#include "ClpSolve.hpp"
+#include "ClpConfig.h"
+class ClpDualRowPivot;
+class ClpPrimalColumnPivot;
+class ClpFactorization;
+class CoinIndexedVector;
+class ClpNonLinearCost;
+class ClpNodeStuff;
+class CoinStructuredModel;
+class OsiClpSolverInterface;
+class CoinWarmStartBasis;
+class ClpDisasterHandler;
+class ClpConstraint;
+#ifdef CLP_HAS_ABC
+#include "AbcCommon.hpp"
+class AbcTolerancesEtc;
+class AbcSimplex;
+#include "CoinAbcCommon.hpp"
+#endif
+/** This solves LPs using the simplex method
+
+    It inherits from ClpModel and all its arrays are created at
+    algorithm time. Originally I tried to work with model arrays
+    but for simplicity of coding I changed to single arrays with
+    structural variables then row variables.  Some coding is still
+    based on old style and needs cleaning up.
+
+    For a description of algorithms:
+
+    for dual see ClpSimplexDual.hpp and at top of ClpSimplexDual.cpp
+    for primal see ClpSimplexPrimal.hpp and at top of ClpSimplexPrimal.cpp
+
+    There is an algorithm data member.  + for primal variations
+    and - for dual variations
+
+*/
+
+class ClpSimplex : public ClpModel {
+     friend void ClpSimplexUnitTest(const std::string & mpsDir);
+
+public:
+     /** enums for status of various sorts.
+         First 4 match CoinWarmStartBasis,
+         isFixed means fixed at lower bound and out of basis
+     */
+     enum Status {
+          isFree = 0x00,
+          basic = 0x01,
+          atUpperBound = 0x02,
+          atLowerBound = 0x03,
+          superBasic = 0x04,
+          isFixed = 0x05
+     };
+     // For Dual
+     enum FakeBound {
+          noFake = 0x00,
+          lowerFake = 0x01,
+          upperFake = 0x02,
+          bothFake = 0x03
+     };
+
+     /**@name Constructors and destructor and copy */
+     //@{
+     /// Default constructor
+     ClpSimplex (bool emptyMessages = false  );
+
+     /** Copy constructor. May scale depending on mode
+         -1 leave mode as is
+         0 -off, 1 equilibrium, 2 geometric, 3, auto, 4 dynamic(later)
+     */
+     ClpSimplex(const ClpSimplex & rhs, int scalingMode = -1);
+     /** Copy constructor from model. May scale depending on mode
+         -1 leave mode as is
+         0 -off, 1 equilibrium, 2 geometric, 3, auto, 4 dynamic(later)
+     */
+     ClpSimplex(const ClpModel & rhs, int scalingMode = -1);
+     /** Subproblem constructor.  A subset of whole model is created from the
+         row and column lists given.  The new order is given by list order and
+         duplicates are allowed.  Name and integer information can be dropped
+         Can optionally modify rhs to take into account variables NOT in list
+         in this case duplicates are not allowed (also see getbackSolution)
+     */
+     ClpSimplex (const ClpModel * wholeModel,
+                 int numberRows, const int * whichRows,
+                 int numberColumns, const int * whichColumns,
+                 bool dropNames = true, bool dropIntegers = true,
+                 bool fixOthers = false);
+     /** Subproblem constructor.  A subset of whole model is created from the
+         row and column lists given.  The new order is given by list order and
+         duplicates are allowed.  Name and integer information can be dropped
+         Can optionally modify rhs to take into account variables NOT in list
+         in this case duplicates are not allowed (also see getbackSolution)
+     */
+     ClpSimplex (const ClpSimplex * wholeModel,
+                 int numberRows, const int * whichRows,
+                 int numberColumns, const int * whichColumns,
+                 bool dropNames = true, bool dropIntegers = true,
+                 bool fixOthers = false);
+     /** This constructor modifies original ClpSimplex and stores
+         original stuff in created ClpSimplex.  It is only to be used in
+         conjunction with originalModel */
+     ClpSimplex (ClpSimplex * wholeModel,
+                 int numberColumns, const int * whichColumns);
+     /** This copies back stuff from miniModel and then deletes miniModel.
+         Only to be used with mini constructor */
+     void originalModel(ClpSimplex * miniModel);
+  inline int abcState() const
+  { return abcState_;}
+  inline void setAbcState(int state)
+  { abcState_=state;}
+#ifdef ABC_INHERIT
+  inline AbcSimplex * abcSimplex() const
+  { return abcSimplex_;}
+  inline void setAbcSimplex(AbcSimplex * simplex)
+  { abcSimplex_=simplex;}
+  /// Returns 0 if dual can be skipped
+  int doAbcDual();
+  /// Returns 0 if primal can be skipped
+  int doAbcPrimal(int ifValuesPass);
+#endif
+     /** Array persistence flag
+         If 0 then as now (delete/new)
+         1 then only do arrays if bigger needed
+         2 as 1 but give a bit extra if bigger needed
+     */
+     void setPersistenceFlag(int value);
+     /// Save a copy of model with certain state - normally without cuts
+     void makeBaseModel();
+     /// Switch off base model
+     void deleteBaseModel();
+     /// See if we have base model
+     inline ClpSimplex *  baseModel() const {
+          return baseModel_;
+     }
+     /** Reset to base model (just size and arrays needed)
+         If model NULL use internal copy
+     */
+     void setToBaseModel(ClpSimplex * model = NULL);
+     /// Assignment operator. This copies the data
+     ClpSimplex & operator=(const ClpSimplex & rhs);
+     /// Destructor
+     ~ClpSimplex (  );
+     // Ones below are just ClpModel with some changes
+     /** Loads a problem (the constraints on the
+           rows are given by lower and upper bounds). If a pointer is 0 then the
+           following values are the default:
+           <ul>
+             <li> <code>colub</code>: all columns have upper bound infinity
+             <li> <code>collb</code>: all columns have lower bound 0
+             <li> <code>rowub</code>: all rows have upper bound infinity
+             <li> <code>rowlb</code>: all rows have lower bound -infinity
+         <li> <code>obj</code>: all variables have 0 objective coefficient
+           </ul>
+       */
+     void loadProblem (  const ClpMatrixBase& matrix,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     void loadProblem (  const CoinPackedMatrix& matrix,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+
+     /** Just like the other loadProblem() method except that the matrix is
+       given in a standard column major ordered format (without gaps). */
+     void loadProblem (  const int numcols, const int numrows,
+                         const CoinBigIndex* start, const int* index,
+                         const double* value,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     /// This one is for after presolve to save memory
+     void loadProblem (  const int numcols, const int numrows,
+                         const CoinBigIndex* start, const int* index,
+                         const double* value, const int * length,
+                         const double* collb, const double* colub,
+                         const double* obj,
+                         const double* rowlb, const double* rowub,
+                         const double * rowObjective = NULL);
+     /** This loads a model from a coinModel object - returns number of errors.
+         If keepSolution true and size is same as current then
+         keeps current status and solution
+     */
+     int loadProblem (  CoinModel & modelObject, bool keepSolution = false);
+     /// Read an mps file from the given filename
+     int readMps(const char *filename,
+                 bool keepNames = false,
+                 bool ignoreErrors = false);
+     /// Read GMPL files from the given filenames
+     int readGMPL(const char *filename, const char * dataName,
+                  bool keepNames = false);
+     /// Read file in LP format from file with name filename.
+     /// See class CoinLpIO for description of this format.
+     int readLp(const char *filename, const double epsilon = 1e-5);
+     /** Borrow model.  This is so we dont have to copy large amounts
+         of data around.  It assumes a derived class wants to overwrite
+         an empty model with a real one - while it does an algorithm.
+         This is same as ClpModel one, but sets scaling on etc. */
+     void borrowModel(ClpModel & otherModel);
+     void borrowModel(ClpSimplex & otherModel);
+     /// Pass in Event handler (cloned and deleted at end)
+     void passInEventHandler(const ClpEventHandler * eventHandler);
+     /// Puts solution back into small model
+     void getbackSolution(const ClpSimplex & smallModel, const int * whichRow, const int * whichColumn);
+     /** Load nonlinear part of problem from AMPL info
+         Returns 0 if linear
+         1 if quadratic objective
+         2 if quadratic constraints
+         3 if nonlinear objective
+         4 if nonlinear constraints
+         -1 on failure
+     */
+     int loadNonLinear(void * info, int & numberConstraints,
+                       ClpConstraint ** & constraints);
+#ifdef ABC_INHERIT
+  /// Loads tolerances etc
+  void loadTolerancesEtc(const AbcTolerancesEtc & data);
+  /// Unloads tolerances etc
+  void unloadTolerancesEtc(AbcTolerancesEtc & data);
+#endif
+     //@}
+
+     /**@name Functions most useful to user */
+     //@{
+     /** General solve algorithm which can do presolve.
+         See  ClpSolve.hpp for options
+      */
+     int initialSolve(ClpSolve & options);
+     /// Default initial solve
+     int initialSolve();
+     /// Dual initial solve
+     int initialDualSolve();
+     /// Primal initial solve
+     int initialPrimalSolve();
+/// Barrier initial solve
+     int initialBarrierSolve();
+     /// Barrier initial solve, not to be followed by crossover
+     int initialBarrierNoCrossSolve();
+     /** Dual algorithm - see ClpSimplexDual.hpp for method.
+         ifValuesPass==2 just does values pass and then stops.
+
+         startFinishOptions - bits
+         1 - do not delete work areas and factorization at end
+         2 - use old factorization if same number of rows
+         4 - skip as much initialization of work areas as possible
+             (based on whatsChanged in clpmodel.hpp) ** work in progress
+         maybe other bits later
+     */
+     int dual(int ifValuesPass = 0, int startFinishOptions = 0);
+     // If using Debug
+     int dualDebug(int ifValuesPass = 0, int startFinishOptions = 0);
+     /** Primal algorithm - see ClpSimplexPrimal.hpp for method.
+         ifValuesPass==2 just does values pass and then stops.
+
+         startFinishOptions - bits
+         1 - do not delete work areas and factorization at end
+         2 - use old factorization if same number of rows
+         4 - skip as much initialization of work areas as possible
+             (based on whatsChanged in clpmodel.hpp) ** work in progress
+         maybe other bits later
+     */
+     int primal(int ifValuesPass = 0, int startFinishOptions = 0);
+     /** Solves nonlinear problem using SLP - may be used as crash
+         for other algorithms when number of iterations small.
+         Also exits if all problematical variables are changing
+         less than deltaTolerance
+     */
+     int nonlinearSLP(int numberPasses, double deltaTolerance);
+     /** Solves problem with nonlinear constraints using SLP - may be used as crash
+         for other algorithms when number of iterations small.
+         Also exits if all problematical variables are changing
+         less than deltaTolerance
+     */
+     int nonlinearSLP(int numberConstraints, ClpConstraint ** constraints,
+                      int numberPasses, double deltaTolerance);
+     /** Solves using barrier (assumes you have good cholesky factor code).
+         Does crossover to simplex if asked*/
+     int barrier(bool crossover = true);
+     /** Solves non-linear using reduced gradient.  Phase = 0 get feasible,
+         =1 use solution */
+     int reducedGradient(int phase = 0);
+     /// Solve using structure of model and maybe in parallel
+     int solve(CoinStructuredModel * model);
+#ifdef ABC_INHERIT
+  /** solvetype 0 for dual, 1 for primal
+      startup 1 for values pass
+      interrupt whether to pass across interrupt handler
+  */
+  void dealWithAbc(int solveType,int startUp,bool interrupt=false);
+#endif
+     /** This loads a model from a CoinStructuredModel object - returns number of errors.
+         If originalOrder then keep to order stored in blocks,
+         otherwise first column/rows correspond to first block - etc.
+         If keepSolution true and size is same as current then
+         keeps current status and solution
+     */
+     int loadProblem (  CoinStructuredModel & modelObject,
+                        bool originalOrder = true, bool keepSolution = false);
+     /**
+        When scaling is on it is possible that the scaled problem
+        is feasible but the unscaled is not.  Clp returns a secondary
+        status code to that effect.  This option allows for a cleanup.
+        If you use it I would suggest 1.
+        This only affects actions when scaled optimal
+        0 - no action
+        1 - clean up using dual if primal infeasibility
+        2 - clean up using dual if dual infeasibility
+        3 - clean up using dual if primal or dual infeasibility
+        11,12,13 - as 1,2,3 but use primal
+
+        return code as dual/primal
+     */
+     int cleanup(int cleanupScaling);
+     /** Dual ranging.
+         This computes increase/decrease in cost for each given variable and corresponding
+         sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
+         and numberColumns.. for artificials/slacks.
+         For non-basic variables the information is trivial to compute and the change in cost is just minus the
+         reduced cost and the sequence number will be that of the non-basic variables.
+         For basic variables a ratio test is between the reduced costs for non-basic variables
+         and the row of the tableau corresponding to the basic variable.
+         The increase/decrease value is always >= 0.0
+
+         Up to user to provide correct length arrays where each array is of length numberCheck.
+         which contains list of variables for which information is desired.  All other
+         arrays will be filled in by function.  If fifth entry in which is variable 7 then fifth entry in output arrays
+         will be information for variable 7.
+
+         If valueIncrease/Decrease not NULL (both must be NULL or both non NULL) then these are filled with
+         the value of variable if such a change in cost were made (the existing bounds are ignored)
+
+         Returns non-zero if infeasible unbounded etc
+     */
+     int dualRanging(int numberCheck, const int * which,
+                     double * costIncrease, int * sequenceIncrease,
+                     double * costDecrease, int * sequenceDecrease,
+                     double * valueIncrease = NULL, double * valueDecrease = NULL);
+     /** Primal ranging.
+         This computes increase/decrease in value for each given variable and corresponding
+         sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
+         and numberColumns.. for artificials/slacks.
+         This should only be used for non-basic variabls as otherwise information is pretty useless
+         For basic variables the sequence number will be that of the basic variables.
+
+         Up to user to provide correct length arrays where each array is of length numberCheck.
+         which contains list of variables for which information is desired.  All other
+         arrays will be filled in by function.  If fifth entry in which is variable 7 then fifth entry in output arrays
+         will be information for variable 7.
+
+         Returns non-zero if infeasible unbounded etc
+     */
+     int primalRanging(int numberCheck, const int * which,
+                       double * valueIncrease, int * sequenceIncrease,
+                       double * valueDecrease, int * sequenceDecrease);
+     /**
+	Modifies coefficients etc and if necessary pivots in and out.
+	All at same status will be done (basis may go singular).
+	User can tell which others have been done (i.e. if status matches).
+	If called from outside will change status and return 0.
+	If called from event handler returns non-zero if user has to take action.
+	indices>=numberColumns are slacks (obviously no coefficients)
+	status array is (char) Status enum
+     */
+     int modifyCoefficientsAndPivot(int number,
+				 const int * which,
+				 const CoinBigIndex * start,
+				 const int * row,
+				 const double * newCoefficient,
+				 const unsigned char * newStatus=NULL,
+				 const double * newLower=NULL,
+				 const double * newUpper=NULL,
+				 const double * newObjective=NULL);
+     /** Take out duplicate rows (includes scaled rows and intersections).
+	 On exit whichRows has rows to delete - return code is number can be deleted 
+	 or -1 if would be infeasible.
+	 If tolerance is -1.0 use primalTolerance for equality rows and infeasibility
+	 If cleanUp not zero then spend more time trying to leave more stable row
+	 and make row bounds exact multiple of cleanUp if close enough
+     */
+     int outDuplicateRows(int numberLook,int * whichRows, bool noOverlaps=false, double tolerance=-1.0,
+			  double cleanUp=0.0);
+     /** Try simple crash like techniques to get closer to primal feasibility
+	 returns final sum of infeasibilities */
+     double moveTowardsPrimalFeasible();
+     /** Try simple crash like techniques to remove super basic slacks
+	 but only if > threshold */
+     void removeSuperBasicSlacks(int threshold=0);
+     /** Mini presolve (faster)
+	 Char arrays must be numberRows and numberColumns long
+	 on entry second part must be filled in as follows -
+	 0 - possible
+	 >0 - take out and do something (depending on value - TBD)
+	 -1 row/column can't vanish but can have entries removed/changed
+	 -2 don't touch at all
+	 on exit <=0 ones will be in presolved problem
+	 struct will be created and will be long enough
+	 (information on length etc in first entry)
+	 user must delete struct
+     */
+     ClpSimplex * miniPresolve(char * rowType, char * columnType,void ** info);
+     /// After mini presolve
+     void miniPostsolve(const ClpSimplex * presolvedModel,void * info);
+     /** Write the basis in MPS format to the specified file.
+         If writeValues true writes values of structurals
+         (and adds VALUES to end of NAME card)
+
+         Row and column names may be null.
+         formatType is
+         <ul>
+         <li> 0 - normal
+         <li> 1 - extra accuracy
+         <li> 2 - IEEE hex (later)
+         </ul>
+
+         Returns non-zero on I/O error
+     */
+     int writeBasis(const char *filename,
+                    bool writeValues = false,
+                    int formatType = 0) const;
+     /** Read a basis from the given filename,
+         returns -1 on file error, 0 if no values, 1 if values */
+     int readBasis(const char *filename);
+     /// Returns a basis (to be deleted by user)
+     CoinWarmStartBasis * getBasis() const;
+     /// Passes in factorization
+     void setFactorization( ClpFactorization & factorization);
+     // Swaps factorization
+     ClpFactorization * swapFactorization( ClpFactorization * factorization);
+     /// Copies in factorization to existing one
+     void copyFactorization( ClpFactorization & factorization);
+     /** Tightens primal bounds to make dual faster.  Unless
+         fixed or doTight>10, bounds are slightly looser than they could be.
+         This is to make dual go faster and is probably not needed
+         with a presolve.  Returns non-zero if problem infeasible.
+
+         Fudge for branch and bound - put bounds on columns of factor *
+         largest value (at continuous) - should improve stability
+         in branch and bound on infeasible branches (0.0 is off)
+     */
+     int tightenPrimalBounds(double factor = 0.0, int doTight = 0, bool tightIntegers = false);
+     /** Crash - at present just aimed at dual, returns
+         -2 if dual preferred and crash basis created
+         -1 if dual preferred and all slack basis preferred
+          0 if basis going in was not all slack
+          1 if primal preferred and all slack basis preferred
+          2 if primal preferred and crash basis created.
+
+          if gap between bounds <="gap" variables can be flipped
+          ( If pivot -1 then can be made super basic!)
+
+          If "pivot" is
+          -1 No pivoting - always primal
+          0 No pivoting (so will just be choice of algorithm)
+          1 Simple pivoting e.g. gub
+          2 Mini iterations
+     */
+     int crash(double gap, int pivot);
+     /// Sets row pivot choice algorithm in dual
+     void setDualRowPivotAlgorithm(ClpDualRowPivot & choice);
+     /// Sets column pivot choice algorithm in primal
+     void setPrimalColumnPivotAlgorithm(ClpPrimalColumnPivot & choice);
+     /** For strong branching.  On input lower and upper are new bounds
+         while on output they are change in objective function values
+         (>1.0e50 infeasible).
+         Return code is 0 if nothing interesting, -1 if infeasible both
+         ways and +1 if infeasible one way (check values to see which one(s))
+         Solutions are filled in as well - even down, odd up - also
+         status and number of iterations
+     */
+     int strongBranching(int numberVariables, const int * variables,
+                         double * newLower, double * newUpper,
+                         double ** outputSolution,
+                         int * outputStatus, int * outputIterations,
+                         bool stopOnFirstInfeasible = true,
+                         bool alwaysFinish = false,
+                         int startFinishOptions = 0);
+     /// Fathom - 1 if solution
+     int fathom(void * stuff);
+     /** Do up to N deep - returns
+         -1 - no solution nNodes_ valid nodes
+         >= if solution and that node gives solution
+         ClpNode array is 2**N long.  Values for N and
+         array are in stuff (nNodes_ also in stuff) */
+     int fathomMany(void * stuff);
+     /// Double checks OK
+     double doubleCheck();
+     /// Starts Fast dual2
+     int startFastDual2(ClpNodeStuff * stuff);
+     /// Like Fast dual
+     int fastDual2(ClpNodeStuff * stuff);
+     /// Stops Fast dual2
+     void stopFastDual2(ClpNodeStuff * stuff);
+     /** Deals with crunch aspects
+         mode 0 - in
+              1 - out with solution
+          2 - out without solution
+         returns small model or NULL
+     */
+     ClpSimplex * fastCrunch(ClpNodeStuff * stuff, int mode);
+     //@}
+
+     /**@name Needed for functionality of OsiSimplexInterface */
+     //@{
+     /** Pivot in a variable and out a variable.  Returns 0 if okay,
+         1 if inaccuracy forced re-factorization, -1 if would be singular.
+         Also updates primal/dual infeasibilities.
+         Assumes sequenceIn_ and pivotRow_ set and also directionIn and Out.
+     */
+     int pivot();
+
+     /** Pivot in a variable and choose an outgoing one.  Assumes primal
+         feasible - will not go through a bound.  Returns step length in theta
+         Returns ray in ray_ (or NULL if no pivot)
+         Return codes as before but -1 means no acceptable pivot
+     */
+     int primalPivotResult();
+
+     /** Pivot out a variable and choose an incoing one.  Assumes dual
+         feasible - will not go through a reduced cost.
+         Returns step length in theta
+         Return codes as before but -1 means no acceptable pivot
+     */
+     int dualPivotResultPart1();
+     /** Do actual pivot
+	 state is 0 if need tableau column, 1 if in rowArray_[1]
+     */
+  int pivotResultPart2(int algorithm,int state);
+
+     /** Common bits of coding for dual and primal.  Return 0 if okay,
+         1 if bad matrix, 2 if very bad factorization
+
+         startFinishOptions - bits
+         1 - do not delete work areas and factorization at end
+         2 - use old factorization if same number of rows
+         4 - skip as much initialization of work areas as possible
+             (based on whatsChanged in clpmodel.hpp) ** work in progress
+         maybe other bits later
+
+     */
+     int startup(int ifValuesPass, int startFinishOptions = 0);
+     void finish(int startFinishOptions = 0);
+
+     /** Factorizes and returns true if optimal.  Used by user */
+     bool statusOfProblem(bool initial = false);
+     /// If user left factorization frequency then compute
+     void defaultFactorizationFrequency();
+     /// Copy across enabled stuff from one solver to another
+     void copyEnabledStuff(const ClpSimplex * rhs);
+     //@}
+
+     /**@name most useful gets and sets */
+     //@{
+     /// If problem is primal feasible
+     inline bool primalFeasible() const {
+          return (numberPrimalInfeasibilities_ == 0);
+     }
+     /// If problem is dual feasible
+     inline bool dualFeasible() const {
+          return (numberDualInfeasibilities_ == 0);
+     }
+     /// factorization
+     inline ClpFactorization * factorization() const {
+          return factorization_;
+     }
+     /// Sparsity on or off
+     bool sparseFactorization() const;
+     void setSparseFactorization(bool value);
+     /// Factorization frequency
+     int factorizationFrequency() const;
+     void setFactorizationFrequency(int value);
+     /// Dual bound
+     inline double dualBound() const {
+          return dualBound_;
+     }
+     void setDualBound(double value);
+     /// Infeasibility cost
+     inline double infeasibilityCost() const {
+          return infeasibilityCost_;
+     }
+     void setInfeasibilityCost(double value);
+     /** Amount of print out:
+         0 - none
+         1 - just final
+         2 - just factorizations
+         3 - as 2 plus a bit more
+         4 - verbose
+         above that 8,16,32 etc just for selective debug
+     */
+     /** Perturbation:
+         50  - switch on perturbation
+         100 - auto perturb if takes too long (1.0e-6 largest nonzero)
+         101 - we are perturbed
+         102 - don't try perturbing again
+         default is 100
+         others are for playing
+     */
+     inline int perturbation() const {
+          return perturbation_;
+     }
+     void setPerturbation(int value);
+     /// Current (or last) algorithm
+     inline int algorithm() const {
+          return algorithm_;
+     }
+     /// Set algorithm
+     inline void setAlgorithm(int value) {
+          algorithm_ = value;
+     }
+     /// Return true if the objective limit test can be relied upon
+     bool isObjectiveLimitTestValid() const ;
+     /// Sum of dual infeasibilities
+     inline double sumDualInfeasibilities() const {
+          return sumDualInfeasibilities_;
+     }
+     inline void setSumDualInfeasibilities(double value) {
+          sumDualInfeasibilities_ = value;
+     }
+     /// Sum of relaxed dual infeasibilities
+     inline double sumOfRelaxedDualInfeasibilities() const {
+          return sumOfRelaxedDualInfeasibilities_;
+     }
+     inline void setSumOfRelaxedDualInfeasibilities(double value) {
+          sumOfRelaxedDualInfeasibilities_ = value;
+     }
+     /// Number of dual infeasibilities
+     inline int numberDualInfeasibilities() const {
+          return numberDualInfeasibilities_;
+     }
+     inline void setNumberDualInfeasibilities(int value) {
+          numberDualInfeasibilities_ = value;
+     }
+     /// Number of dual infeasibilities (without free)
+     inline int numberDualInfeasibilitiesWithoutFree() const {
+          return numberDualInfeasibilitiesWithoutFree_;
+     }
+     /// Sum of primal infeasibilities
+     inline double sumPrimalInfeasibilities() const {
+          return sumPrimalInfeasibilities_;
+     }
+     inline void setSumPrimalInfeasibilities(double value) {
+          sumPrimalInfeasibilities_ = value;
+     }
+     /// Sum of relaxed primal infeasibilities
+     inline double sumOfRelaxedPrimalInfeasibilities() const {
+          return sumOfRelaxedPrimalInfeasibilities_;
+     }
+     inline void setSumOfRelaxedPrimalInfeasibilities(double value) {
+          sumOfRelaxedPrimalInfeasibilities_ = value;
+     }
+     /// Number of primal infeasibilities
+     inline int numberPrimalInfeasibilities() const {
+          return numberPrimalInfeasibilities_;
+     }
+     inline void setNumberPrimalInfeasibilities(int value) {
+          numberPrimalInfeasibilities_ = value;
+     }
+     /** Save model to file, returns 0 if success.  This is designed for
+         use outside algorithms so does not save iterating arrays etc.
+     It does not save any messaging information.
+     Does not save scaling values.
+     It does not know about all types of virtual functions.
+     */
+     int saveModel(const char * fileName);
+     /** Restore model from file, returns 0 if success,
+         deletes current model */
+     int restoreModel(const char * fileName);
+
+     /** Just check solution (for external use) - sets sum of
+         infeasibilities etc.
+         If setToBounds 0 then primal column values not changed
+         and used to compute primal row activity values.  If 1 or 2
+         then status used - so all nonbasic variables set to
+         indicated bound and if any values changed (or ==2)  basic values re-computed.
+     */
+     void checkSolution(int setToBounds = 0);
+     /** Just check solution (for internal use) - sets sum of
+         infeasibilities etc. */
+     void checkSolutionInternal();
+     /// Check unscaled primal solution but allow for rounding error
+     void checkUnscaledSolution();
+     /// Useful row length arrays (0,1,2,3,4,5)
+     inline CoinIndexedVector * rowArray(int index) const {
+          return rowArray_[index];
+     }
+     /// Useful column length arrays (0,1,2,3,4,5)
+     inline CoinIndexedVector * columnArray(int index) const {
+          return columnArray_[index];
+     }
+     //@}
+
+     /******************** End of most useful part **************/
+     /**@name Functions less likely to be useful to casual user */
+     //@{
+     /** Given an existing factorization computes and checks
+         primal and dual solutions.  Uses input arrays for variables at
+         bounds.  Returns feasibility states */
+     int getSolution (  const double * rowActivities,
+                        const double * columnActivities);
+     /** Given an existing factorization computes and checks
+         primal and dual solutions.  Uses current problem arrays for
+         bounds.  Returns feasibility states */
+     int getSolution ();
+     /** Constructs a non linear cost from list of non-linearities (columns only)
+         First lower of each column is taken as real lower
+         Last lower is taken as real upper and cost ignored
+
+         Returns nonzero if bad data e.g. lowers not monotonic
+     */
+     int createPiecewiseLinearCosts(const int * starts,
+                                    const double * lower, const double * gradient);
+     /// dual row pivot choice
+     inline ClpDualRowPivot * dualRowPivot() const {
+          return dualRowPivot_;
+     }
+     /// primal column pivot choice
+     inline ClpPrimalColumnPivot * primalColumnPivot() const {
+          return primalColumnPivot_;
+     }
+     /// Returns true if model looks OK
+     inline bool goodAccuracy() const {
+          return (largestPrimalError_ < 1.0e-7 && largestDualError_ < 1.0e-7);
+     }
+     /** Return model - updates any scalars */
+     void returnModel(ClpSimplex & otherModel);
+     /** Factorizes using current basis.
+         solveType - 1 iterating, 0 initial, -1 external
+         If 10 added then in primal values pass
+         Return codes are as from ClpFactorization unless initial factorization
+         when total number of singularities is returned.
+         Special case is numberRows_+1 -> all slack basis.
+     */
+     int internalFactorize(int solveType);
+     /// Save data
+     ClpDataSave saveData() ;
+     /// Restore data
+     void restoreData(ClpDataSave saved);
+     /// Clean up status
+     void cleanStatus();
+     /// Factorizes using current basis. For external use
+     int factorize();
+     /** Computes duals from scratch. If givenDjs then
+         allows for nonzero basic djs */
+     void computeDuals(double * givenDjs);
+     /// Computes primals from scratch
+     void computePrimals (  const double * rowActivities,
+                            const double * columnActivities);
+     /** Adds multiple of a column into an array */
+     void add(double * array,
+              int column, double multiplier) const;
+     /**
+        Unpacks one column of the matrix into indexed array
+        Uses sequenceIn_
+        Also applies scaling if needed
+     */
+     void unpack(CoinIndexedVector * rowArray) const ;
+     /**
+        Unpacks one column of the matrix into indexed array
+        Slack if sequence>= numberColumns
+        Also applies scaling if needed
+     */
+     void unpack(CoinIndexedVector * rowArray, int sequence) const;
+     /**
+        Unpacks one column of the matrix into indexed array
+        ** as packed vector
+        Uses sequenceIn_
+        Also applies scaling if needed
+     */
+     void unpackPacked(CoinIndexedVector * rowArray) ;
+     /**
+        Unpacks one column of the matrix into indexed array
+        ** as packed vector
+        Slack if sequence>= numberColumns
+        Also applies scaling if needed
+     */
+     void unpackPacked(CoinIndexedVector * rowArray, int sequence);
+#ifndef CLP_USER_DRIVEN
+protected:
+#endif
+     /**
+         This does basis housekeeping and does values for in/out variables.
+         Can also decide to re-factorize
+     */
+     int housekeeping(double objectiveChange);
+     /** This sets largest infeasibility and most infeasible and sum
+         and number of infeasibilities (Primal) */
+     void checkPrimalSolution(const double * rowActivities = NULL,
+                              const double * columnActivies = NULL);
+     /** This sets largest infeasibility and most infeasible and sum
+         and number of infeasibilities (Dual) */
+     void checkDualSolution();
+     /** This sets sum and number of infeasibilities (Dual and Primal) */
+     void checkBothSolutions();
+     /**  If input negative scales objective so maximum <= -value
+          and returns scale factor used.  If positive unscales and also
+          redoes dual stuff
+     */
+     double scaleObjective(double value);
+     /// Solve using Dantzig-Wolfe decomposition and maybe in parallel
+     int solveDW(CoinStructuredModel * model);
+     /// Solve using Benders decomposition and maybe in parallel
+     int solveBenders(CoinStructuredModel * model);
+public:
+     /** For advanced use.  When doing iterative solves things can get
+         nasty so on values pass if incoming solution has largest
+         infeasibility < incomingInfeasibility throw out variables
+         from basis until largest infeasibility < allowedInfeasibility
+         or incoming largest infeasibility.
+         If allowedInfeasibility>= incomingInfeasibility this is
+         always possible altough you may end up with an all slack basis.
+
+         Defaults are 1.0,10.0
+     */
+     void setValuesPassAction(double incomingInfeasibility,
+                              double allowedInfeasibility);
+     /** Get a clean factorization - i.e. throw out singularities
+	 may do more later */
+     int cleanFactorization(int ifValuesPass);
+     //@}
+     /**@name most useful gets and sets */
+     //@{
+public:
+     /// Initial value for alpha accuracy calculation (-1.0 off)
+     inline double alphaAccuracy() const {
+          return alphaAccuracy_;
+     }
+     inline void setAlphaAccuracy(double value) {
+          alphaAccuracy_ = value;
+     }
+public:
+     /// Objective value
+     //inline double objectiveValue() const {
+     //return (objectiveValue_-bestPossibleImprovement_)*optimizationDirection_ - dblParam_[ClpObjOffset];
+     //}
+     /// Set disaster handler
+     inline void setDisasterHandler(ClpDisasterHandler * handler) {
+          disasterArea_ = handler;
+     }
+     /// Get disaster handler
+     inline ClpDisasterHandler * disasterHandler() const {
+          return disasterArea_;
+     }
+     /// Large bound value (for complementarity etc)
+     inline double largeValue() const {
+          return largeValue_;
+     }
+     void setLargeValue( double value) ;
+     /// Largest error on Ax-b
+     inline double largestPrimalError() const {
+          return largestPrimalError_;
+     }
+     /// Largest error on basic duals
+     inline double largestDualError() const {
+          return largestDualError_;
+     }
+     /// Largest error on Ax-b
+     inline void setLargestPrimalError(double value) {
+          largestPrimalError_ = value;
+     }
+     /// Largest error on basic duals
+     inline void setLargestDualError(double value) {
+          largestDualError_ = value;
+     }
+     /// Get zero tolerance
+     inline double zeroTolerance() const {
+          return zeroTolerance_;/*factorization_->zeroTolerance();*/
+     }
+     /// Set zero tolerance
+     inline void setZeroTolerance( double value) {
+          zeroTolerance_ = value;
+     }
+     /// Basic variables pivoting on which rows
+     inline int * pivotVariable() const {
+          return pivotVariable_;
+     }
+     /// If automatic scaling on
+     inline bool automaticScaling() const {
+          return automaticScale_ != 0;
+     }
+     inline void setAutomaticScaling(bool onOff) {
+          automaticScale_ = onOff ? 1 : 0;
+     }
+     /// Current dual tolerance
+     inline double currentDualTolerance() const {
+          return dualTolerance_;
+     }
+     inline void setCurrentDualTolerance(double value) {
+          dualTolerance_ = value;
+     }
+     /// Current primal tolerance
+     inline double currentPrimalTolerance() const {
+          return primalTolerance_;
+     }
+     inline void setCurrentPrimalTolerance(double value) {
+          primalTolerance_ = value;
+     }
+     /// How many iterative refinements to do
+     inline int numberRefinements() const {
+          return numberRefinements_;
+     }
+     void setNumberRefinements( int value) ;
+     /// Alpha (pivot element) for use by classes e.g. steepestedge
+     inline double alpha() const {
+          return alpha_;
+     }
+     inline void setAlpha(double value) {
+          alpha_ = value;
+     }
+     /// Reduced cost of last incoming for use by classes e.g. steepestedge
+     inline double dualIn() const {
+          return dualIn_;
+     }
+     /// Set reduced cost of last incoming to force error
+     inline void setDualIn(double value) {
+          dualIn_ = value;
+     }
+     /// Pivot Row for use by classes e.g. steepestedge
+     inline int pivotRow() const {
+          return pivotRow_;
+     }
+     inline void setPivotRow(int value) {
+          pivotRow_ = value;
+     }
+     /// value of incoming variable (in Dual)
+     double valueIncomingDual() const;
+     //@}
+
+#ifndef CLP_USER_DRIVEN
+protected:
+#endif
+     /**@name protected methods */
+     //@{
+     /** May change basis and then returns number changed.
+         Computation of solutions may be overriden by given pi and solution
+     */
+     int gutsOfSolution ( double * givenDuals,
+                          const double * givenPrimals,
+                          bool valuesPass = false);
+     /// Does most of deletion (0 = all, 1 = most, 2 most + factorization)
+     void gutsOfDelete(int type);
+     /// Does most of copying
+     void gutsOfCopy(const ClpSimplex & rhs);
+     /** puts in format I like (rowLower,rowUpper) also see StandardMatrix
+         1 bit does rows (now and columns), (2 bit does column bounds), 4 bit does objective(s).
+         8 bit does solution scaling in
+         16 bit does rowArray and columnArray indexed vectors
+         and makes row copy if wanted, also sets columnStart_ etc
+         Also creates scaling arrays if needed.  It does scaling if needed.
+         16 also moves solutions etc in to work arrays
+         On 16 returns false if problem "bad" i.e. matrix or bounds bad
+         If startFinishOptions is -1 then called by user in getSolution
+         so do arrays but keep pivotVariable_
+     */
+     bool createRim(int what, bool makeRowCopy = false, int startFinishOptions = 0);
+     /// Does rows and columns
+     void createRim1(bool initial);
+     /// Does objective
+     void createRim4(bool initial);
+     /// Does rows and columns and objective
+     void createRim5(bool initial);
+     /** releases above arrays and does solution scaling out.  May also
+         get rid of factorization data -
+         0 get rid of nothing, 1 get rid of arrays, 2 also factorization
+     */
+     void deleteRim(int getRidOfFactorizationData = 2);
+     /// Sanity check on input rim data (after scaling) - returns true if okay
+     bool sanityCheck();
+     //@}
+public:
+     /**@name public methods */
+     //@{
+     /** Return row or column sections - not as much needed as it
+         once was.  These just map into single arrays */
+     inline double * solutionRegion(int section) const {
+          if (!section) return rowActivityWork_;
+          else return columnActivityWork_;
+     }
+     inline double * djRegion(int section) const {
+          if (!section) return rowReducedCost_;
+          else return reducedCostWork_;
+     }
+     inline double * lowerRegion(int section) const {
+          if (!section) return rowLowerWork_;
+          else return columnLowerWork_;
+     }
+     inline double * upperRegion(int section) const {
+          if (!section) return rowUpperWork_;
+          else return columnUpperWork_;
+     }
+     inline double * costRegion(int section) const {
+          if (!section) return rowObjectiveWork_;
+          else return objectiveWork_;
+     }
+     /// Return region as single array
+     inline double * solutionRegion() const {
+          return solution_;
+     }
+     inline double * djRegion() const {
+          return dj_;
+     }
+     inline double * lowerRegion() const {
+          return lower_;
+     }
+     inline double * upperRegion() const {
+          return upper_;
+     }
+     inline double * costRegion() const {
+          return cost_;
+     }
+     inline Status getStatus(int sequence) const {
+          return static_cast<Status> (status_[sequence] & 7);
+     }
+     inline void setStatus(int sequence, Status newstatus) {
+          unsigned char & st_byte = status_[sequence];
+          st_byte = static_cast<unsigned char>(st_byte & ~7);
+          st_byte = static_cast<unsigned char>(st_byte | newstatus);
+     }
+     /// Start or reset using maximumRows_ and Columns_ - true if change
+     bool startPermanentArrays();
+     /** Normally the first factorization does sparse coding because
+         the factorization could be singular.  This allows initial dense
+         factorization when it is known to be safe
+     */
+     void setInitialDenseFactorization(bool onOff);
+     bool  initialDenseFactorization() const;
+     /** Return sequence In or Out */
+     inline int sequenceIn() const {
+          return sequenceIn_;
+     }
+     inline int sequenceOut() const {
+          return sequenceOut_;
+     }
+     /** Set sequenceIn or Out */
+     inline void  setSequenceIn(int sequence) {
+          sequenceIn_ = sequence;
+     }
+     inline void  setSequenceOut(int sequence) {
+          sequenceOut_ = sequence;
+     }
+     /** Return direction In or Out */
+     inline int directionIn() const {
+          return directionIn_;
+     }
+     inline int directionOut() const {
+          return directionOut_;
+     }
+     /** Set directionIn or Out */
+     inline void  setDirectionIn(int direction) {
+          directionIn_ = direction;
+     }
+     inline void  setDirectionOut(int direction) {
+          directionOut_ = direction;
+     }
+     /// Value of Out variable
+     inline double valueOut() const {
+          return valueOut_;
+     }
+     /// Set value of out variable
+     inline void setValueOut(double value) {
+          valueOut_ = value;
+     }
+     /// Dual value of Out variable
+     inline double dualOut() const {
+          return dualOut_;
+     }
+     /// Set dual value of out variable
+     inline void setDualOut(double value) {
+          dualOut_ = value;
+     }
+     /// Set lower of out variable
+     inline void setLowerOut(double value) {
+          lowerOut_ = value;
+     }
+     /// Set upper of out variable
+     inline void setUpperOut(double value) {
+          upperOut_ = value;
+     }
+     /// Set theta of out variable
+     inline void setTheta(double value) {
+          theta_ = value;
+     }
+     /// Returns 1 if sequence indicates column
+     inline int isColumn(int sequence) const {
+          return sequence < numberColumns_ ? 1 : 0;
+     }
+     /// Returns sequence number within section
+     inline int sequenceWithin(int sequence) const {
+          return sequence < numberColumns_ ? sequence : sequence - numberColumns_;
+     }
+     /// Return row or column values
+     inline double solution(int sequence) {
+          return solution_[sequence];
+     }
+     /// Return address of row or column values
+     inline double & solutionAddress(int sequence) {
+          return solution_[sequence];
+     }
+     inline double reducedCost(int sequence) {
+          return dj_[sequence];
+     }
+     inline double & reducedCostAddress(int sequence) {
+          return dj_[sequence];
+     }
+     inline double lower(int sequence) {
+          return lower_[sequence];
+     }
+     /// Return address of row or column lower bound
+     inline double & lowerAddress(int sequence) {
+          return lower_[sequence];
+     }
+     inline double upper(int sequence) {
+          return upper_[sequence];
+     }
+     /// Return address of row or column upper bound
+     inline double & upperAddress(int sequence) {
+          return upper_[sequence];
+     }
+     inline double cost(int sequence) {
+          return cost_[sequence];
+     }
+     /// Return address of row or column cost
+     inline double & costAddress(int sequence) {
+          return cost_[sequence];
+     }
+     /// Return original lower bound
+     inline double originalLower(int iSequence) const {
+          if (iSequence < numberColumns_) return columnLower_[iSequence];
+          else
+               return rowLower_[iSequence-numberColumns_];
+     }
+     /// Return original lower bound
+     inline double originalUpper(int iSequence) const {
+          if (iSequence < numberColumns_) return columnUpper_[iSequence];
+          else
+               return rowUpper_[iSequence-numberColumns_];
+     }
+     /// Theta (pivot change)
+     inline double theta() const {
+          return theta_;
+     }
+     /** Best possible improvement using djs (primal) or
+         obj change by flipping bounds to make dual feasible (dual) */
+     inline double bestPossibleImprovement() const {
+          return bestPossibleImprovement_;
+     }
+     /// Return pointer to details of costs
+     inline ClpNonLinearCost * nonLinearCost() const {
+          return nonLinearCost_;
+     }
+     /** Return more special options
+         1 bit - if presolve says infeasible in ClpSolve return
+         2 bit - if presolved problem infeasible return
+         4 bit - keep arrays like upper_ around
+         8 bit - if factorization kept can still declare optimal at once
+         16 bit - if checking replaceColumn accuracy before updating
+         32 bit - say optimal if primal feasible!
+         64 bit - give up easily in dual (and say infeasible)
+         128 bit - no objective, 0-1 and in B&B
+         256 bit - in primal from dual or vice versa
+         512 bit - alternative use of solveType_
+         1024 bit - don't do row copy of factorization
+	 2048 bit - perturb in complete fathoming
+	 4096 bit - try more for complete fathoming
+	 8192 bit - don't even think of using primal if user asks for dual (and vv)
+	 16384 bit - in initialSolve so be more flexible
+	 debug
+	 32768 bit - do dual in netlibd
+	 65536 (*3) initial stateDualColumn
+     */
+     inline int moreSpecialOptions() const {
+          return moreSpecialOptions_;
+     }
+     /** Set more special options
+         1 bit - if presolve says infeasible in ClpSolve return
+         2 bit - if presolved problem infeasible return
+         4 bit - keep arrays like upper_ around
+         8 bit - no free or superBasic variables
+         16 bit - if checking replaceColumn accuracy before updating
+         32 bit - say optimal if primal feasible!
+         64 bit - give up easily in dual (and say infeasible)
+         128 bit - no objective, 0-1 and in B&B
+         256 bit - in primal from dual or vice versa
+         512 bit - alternative use of solveType_
+         1024 bit - don't do row copy of factorization
+	 2048 bit - perturb in complete fathoming
+	 4096 bit - try more for complete fathoming
+	 8192 bit - don't even think of using primal if user asks for dual (and vv)
+	 16384 bit - in initialSolve so be more flexible
+	 32768 bit - don't swap algorithms from dual if small infeasibility
+	 65536 bit - perturb in postsolve cleanup (even if < 10000 rows)
+     */
+     inline void setMoreSpecialOptions(int value) {
+          moreSpecialOptions_ = value;
+     }
+     //@}
+     /**@name status methods */
+     //@{
+     inline void setFakeBound(int sequence, FakeBound fakeBound) {
+          unsigned char & st_byte = status_[sequence];
+          st_byte = static_cast<unsigned char>(st_byte & ~24);
+          st_byte = static_cast<unsigned char>(st_byte | (fakeBound << 3));
+     }
+     inline FakeBound getFakeBound(int sequence) const {
+          return static_cast<FakeBound> ((status_[sequence] >> 3) & 3);
+     }
+     inline void setRowStatus(int sequence, Status newstatus) {
+          unsigned char & st_byte = status_[sequence+numberColumns_];
+          st_byte = static_cast<unsigned char>(st_byte & ~7);
+          st_byte = static_cast<unsigned char>(st_byte | newstatus);
+     }
+     inline Status getRowStatus(int sequence) const {
+          return static_cast<Status> (status_[sequence+numberColumns_] & 7);
+     }
+     inline void setColumnStatus(int sequence, Status newstatus) {
+          unsigned char & st_byte = status_[sequence];
+          st_byte = static_cast<unsigned char>(st_byte & ~7);
+          st_byte = static_cast<unsigned char>(st_byte | newstatus);
+     }
+     inline Status getColumnStatus(int sequence) const {
+          return static_cast<Status> (status_[sequence] & 7);
+     }
+     inline void setPivoted( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] | 32);
+     }
+     inline void clearPivoted( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~32);
+     }
+     inline bool pivoted(int sequence) const {
+          return (((status_[sequence] >> 5) & 1) != 0);
+     }
+     /// To flag a variable (not inline to allow for column generation)
+     void setFlagged( int sequence);
+     inline void clearFlagged( int sequence) {
+          status_[sequence] = static_cast<unsigned char>(status_[sequence] & ~64);
+     }
+     inline bool flagged(int sequence) const {
+          return ((status_[sequence] & 64) != 0);
+     }
+     /// To say row active in primal pivot row choice
+     inline void setActive( int iRow) {
+          status_[iRow] = static_cast<unsigned char>(status_[iRow] | 128);
+     }
+     inline void clearActive( int iRow) {
+          status_[iRow] = static_cast<unsigned char>(status_[iRow] & ~128);
+     }
+     inline bool active(int iRow) const {
+          return ((status_[iRow] & 128) != 0);
+     }
+     /** Set up status array (can be used by OsiClp).
+         Also can be used to set up all slack basis */
+     void createStatus() ;
+     /** Sets up all slack basis and resets solution to
+         as it was after initial load or readMps */
+     void allSlackBasis(bool resetSolution = false);
+
+     /// So we know when to be cautious
+     inline int lastBadIteration() const {
+          return lastBadIteration_;
+     }
+     /// Set so we know when to be cautious
+     inline void setLastBadIteration(int value) {
+          lastBadIteration_=value;
+     }
+     /// Progress flag - at present 0 bit says artificials out
+     inline int progressFlag() const {
+          return (progressFlag_ & 3);
+     }
+     /// For dealing with all issues of cycling etc
+     inline ClpSimplexProgress * progress()
+     { return &progress_;}
+     /// Force re-factorization early value
+     inline int forceFactorization() const {
+          return forceFactorization_ ;
+     }
+     /// Force re-factorization early
+     inline void forceFactorization(int value) {
+          forceFactorization_ = value;
+     }
+     /// Raw objective value (so always minimize in primal)
+     inline double rawObjectiveValue() const {
+          return objectiveValue_;
+     }
+     /// Compute objective value from solution and put in objectiveValue_
+     void computeObjectiveValue(bool useWorkingSolution = false);
+     /// Compute minimization objective value from internal solution without perturbation
+     double computeInternalObjectiveValue();
+     /** Infeasibility/unbounded ray (NULL returned if none/wrong)
+         Up to user to use delete [] on these arrays.  */
+     double * infeasibilityRay(bool fullRay=false) const;
+     /** Number of extra rows.  These are ones which will be dynamically created
+         each iteration.  This is for GUB but may have other uses.
+     */
+     inline int numberExtraRows() const {
+          return numberExtraRows_;
+     }
+     /** Maximum number of basic variables - can be more than number of rows if GUB
+     */
+     inline int maximumBasic() const {
+          return maximumBasic_;
+     }
+     /// Iteration when we entered dual or primal
+     inline int baseIteration() const {
+          return baseIteration_;
+     }
+     /// Create C++ lines to get to current state
+     void generateCpp( FILE * fp, bool defaultFactor = false);
+     /// Gets clean and emptyish factorization
+     ClpFactorization * getEmptyFactorization();
+     /// May delete or may make clean and emptyish factorization
+     void setEmptyFactorization();
+     /// Move status and solution across
+     void moveInfo(const ClpSimplex & rhs, bool justStatus = false);
+     //@}
+
+     ///@name Basis handling
+     // These are only to be used using startFinishOptions (ClpSimplexDual, ClpSimplexPrimal)
+     // *** At present only without scaling
+     // *** Slacks havve -1.0 element (so == row activity) - take care
+     ///Get a row of the tableau (slack part in slack if not NULL)
+     void getBInvARow(int row, double* z, double * slack = NULL);
+
+     ///Get a row of the basis inverse
+     void getBInvRow(int row, double* z);
+
+     ///Get a column of the tableau
+     void getBInvACol(int col, double* vec);
+
+     ///Get a column of the basis inverse
+     void getBInvCol(int col, double* vec);
+
+     /** Get basic indices (order of indices corresponds to the
+         order of elements in a vector retured by getBInvACol() and
+         getBInvCol()).
+     */
+     void getBasics(int* index);
+
+     //@}
+     //-------------------------------------------------------------------------
+     /**@name Changing bounds on variables and constraints */
+     //@{
+     /** Set an objective function coefficient */
+     void setObjectiveCoefficient( int elementIndex, double elementValue );
+     /** Set an objective function coefficient */
+     inline void setObjCoeff( int elementIndex, double elementValue ) {
+          setObjectiveCoefficient( elementIndex, elementValue);
+     }
+
+     /** Set a single column lower bound<br>
+         Use -DBL_MAX for -infinity. */
+     void setColumnLower( int elementIndex, double elementValue );
+
+     /** Set a single column upper bound<br>
+         Use DBL_MAX for infinity. */
+     void setColumnUpper( int elementIndex, double elementValue );
+
+     /** Set a single column lower and upper bound */
+     void setColumnBounds( int elementIndex,
+                           double lower, double upper );
+
+     /** Set the bounds on a number of columns simultaneously<br>
+         The default implementation just invokes setColLower() and
+         setColUpper() over and over again.
+         @param indexFirst,indexLast pointers to the beginning and after the
+            end of the array of the indices of the variables whose
+        <em>either</em> bound changes
+         @param boundList the new lower/upper bound pairs for the variables
+     */
+     void setColumnSetBounds(const int* indexFirst,
+                             const int* indexLast,
+                             const double* boundList);
+
+     /** Set a single column lower bound<br>
+         Use -DBL_MAX for -infinity. */
+     inline void setColLower( int elementIndex, double elementValue ) {
+          setColumnLower(elementIndex, elementValue);
+     }
+     /** Set a single column upper bound<br>
+         Use DBL_MAX for infinity. */
+     inline void setColUpper( int elementIndex, double elementValue ) {
+          setColumnUpper(elementIndex, elementValue);
+     }
+
+     /** Set a single column lower and upper bound */
+     inline void setColBounds( int elementIndex,
+                               double newlower, double newupper ) {
+          setColumnBounds(elementIndex, newlower, newupper);
+     }
+
+     /** Set the bounds on a number of columns simultaneously<br>
+         @param indexFirst,indexLast pointers to the beginning and after the
+            end of the array of the indices of the variables whose
+        <em>either</em> bound changes
+         @param boundList the new lower/upper bound pairs for the variables
+     */
+     inline void setColSetBounds(const int* indexFirst,
+                                 const int* indexLast,
+                                 const double* boundList) {
+          setColumnSetBounds(indexFirst, indexLast, boundList);
+     }
+
+     /** Set a single row lower bound<br>
+         Use -DBL_MAX for -infinity. */
+     void setRowLower( int elementIndex, double elementValue );
+
+     /** Set a single row upper bound<br>
+         Use DBL_MAX for infinity. */
+     void setRowUpper( int elementIndex, double elementValue ) ;
+
+     /** Set a single row lower and upper bound */
+     void setRowBounds( int elementIndex,
+                        double lower, double upper ) ;
+
+     /** Set the bounds on a number of rows simultaneously<br>
+         @param indexFirst,indexLast pointers to the beginning and after the
+            end of the array of the indices of the constraints whose
+        <em>either</em> bound changes
+         @param boundList the new lower/upper bound pairs for the constraints
+     */
+     void setRowSetBounds(const int* indexFirst,
+                          const int* indexLast,
+                          const double* boundList);
+     /// Resizes rim part of model
+     void resize (int newNumberRows, int newNumberColumns);
+
+     //@}
+
+////////////////// data //////////////////
+protected:
+
+     /**@name data.  Many arrays have a row part and a column part.
+      There is a single array with both - columns then rows and
+      then normally two arrays pointing to rows and columns.  The
+      single array is the owner of memory
+     */
+     //@{
+     /** Best possible improvement using djs (primal) or
+         obj change by flipping bounds to make dual feasible (dual) */
+     double bestPossibleImprovement_;
+     /// Zero tolerance
+     double zeroTolerance_;
+     /// Sequence of worst (-1 if feasible)
+     int columnPrimalSequence_;
+     /// Sequence of worst (-1 if feasible)
+     int rowPrimalSequence_;
+     /// "Best" objective value
+     double bestObjectiveValue_;
+     /// More special options - see set for details
+     int moreSpecialOptions_;
+     /// Iteration when we entered dual or primal
+     int baseIteration_;
+     /// Primal tolerance needed to make dual feasible (<largeTolerance)
+     double primalToleranceToGetOptimal_;
+     /// Large bound value (for complementarity etc)
+     double largeValue_;
+     /// Largest error on Ax-b
+     double largestPrimalError_;
+     /// Largest error on basic duals
+     double largestDualError_;
+     /// For computing whether to re-factorize
+     double alphaAccuracy_;
+     /// Dual bound
+     double dualBound_;
+     /// Alpha (pivot element)
+     double alpha_;
+     /// Theta (pivot change)
+     double theta_;
+     /// Lower Bound on In variable
+     double lowerIn_;
+     /// Value of In variable
+     double valueIn_;
+     /// Upper Bound on In variable
+     double upperIn_;
+     /// Reduced cost of In variable
+     double dualIn_;
+     /// Lower Bound on Out variable
+     double lowerOut_;
+     /// Value of Out variable
+     double valueOut_;
+     /// Upper Bound on Out variable
+     double upperOut_;
+     /// Infeasibility (dual) or ? (primal) of Out variable
+     double dualOut_;
+     /// Current dual tolerance for algorithm
+     double dualTolerance_;
+     /// Current primal tolerance for algorithm
+     double primalTolerance_;
+     /// Sum of dual infeasibilities
+     double sumDualInfeasibilities_;
+     /// Sum of primal infeasibilities
+     double sumPrimalInfeasibilities_;
+     /// Weight assigned to being infeasible in primal
+     double infeasibilityCost_;
+     /// Sum of Dual infeasibilities using tolerance based on error in duals
+     double sumOfRelaxedDualInfeasibilities_;
+     /// Sum of Primal infeasibilities using tolerance based on error in primals
+     double sumOfRelaxedPrimalInfeasibilities_;
+     /// Acceptable pivot value just after factorization
+     double acceptablePivot_;
+     /// Working copy of lower bounds (Owner of arrays below)
+     double * lower_;
+     /// Row lower bounds - working copy
+     double * rowLowerWork_;
+     /// Column lower bounds - working copy
+     double * columnLowerWork_;
+     /// Working copy of upper bounds (Owner of arrays below)
+     double * upper_;
+     /// Row upper bounds - working copy
+     double * rowUpperWork_;
+     /// Column upper bounds - working copy
+     double * columnUpperWork_;
+     /// Working copy of objective (Owner of arrays below)
+     double * cost_;
+     /// Row objective - working copy
+     double * rowObjectiveWork_;
+     /// Column objective - working copy
+     double * objectiveWork_;
+     /// Useful row length arrays
+     CoinIndexedVector * rowArray_[6];
+     /// Useful column length arrays
+     CoinIndexedVector * columnArray_[6];
+     /// Sequence of In variable
+     int sequenceIn_;
+     /// Direction of In, 1 going up, -1 going down, 0 not a clude
+     int directionIn_;
+     /// Sequence of Out variable
+     int sequenceOut_;
+     /// Direction of Out, 1 to upper bound, -1 to lower bound, 0 - superbasic
+     int directionOut_;
+     /// Pivot Row
+     int pivotRow_;
+     /// Last good iteration (immediately after a re-factorization)
+     int lastGoodIteration_;
+     /// Working copy of reduced costs (Owner of arrays below)
+     double * dj_;
+     /// Reduced costs of slacks not same as duals (or - duals)
+     double * rowReducedCost_;
+     /// Possible scaled reduced costs
+     double * reducedCostWork_;
+     /// Working copy of primal solution (Owner of arrays below)
+     double * solution_;
+     /// Row activities - working copy
+     double * rowActivityWork_;
+     /// Column activities - working copy
+     double * columnActivityWork_;
+     /// Number of dual infeasibilities
+     int numberDualInfeasibilities_;
+     /// Number of dual infeasibilities (without free)
+     int numberDualInfeasibilitiesWithoutFree_;
+     /// Number of primal infeasibilities
+     int numberPrimalInfeasibilities_;
+     /// How many iterative refinements to do
+     int numberRefinements_;
+     /// dual row pivot choice
+     ClpDualRowPivot * dualRowPivot_;
+     /// primal column pivot choice
+     ClpPrimalColumnPivot * primalColumnPivot_;
+     /// Basic variables pivoting on which rows
+     int * pivotVariable_;
+     /// factorization
+     ClpFactorization * factorization_;
+     /// Saved version of solution
+     double * savedSolution_;
+     /// Number of times code has tentatively thought optimal
+     int numberTimesOptimal_;
+     /// Disaster handler
+     ClpDisasterHandler * disasterArea_;
+     /// If change has been made (first attempt at stopping looping)
+     int changeMade_;
+     /// Algorithm >0 == Primal, <0 == Dual
+     int algorithm_;
+     /** Now for some reliability aids
+         This forces re-factorization early */
+     int forceFactorization_;
+     /** Perturbation:
+         -50 to +50 - perturb by this power of ten (-6 sounds good)
+         100 - auto perturb if takes too long (1.0e-6 largest nonzero)
+         101 - we are perturbed
+         102 - don't try perturbing again
+         default is 100
+     */
+     int perturbation_;
+     /// Saved status regions
+     unsigned char * saveStatus_;
+     /** Very wasteful way of dealing with infeasibilities in primal.
+         However it will allow non-linearities and use of dual
+         analysis.  If it doesn't work it can easily be replaced.
+     */
+     ClpNonLinearCost * nonLinearCost_;
+     /// So we know when to be cautious
+     int lastBadIteration_;
+     /// So we know when to open up again
+     int lastFlaggedIteration_;
+     /// Can be used for count of fake bounds (dual) or fake costs (primal)
+     int numberFake_;
+     /// Can be used for count of changed costs (dual) or changed bounds (primal)
+     int numberChanged_;
+     /// Progress flag - at present 0 bit says artificials out, 1 free in
+     int progressFlag_;
+     /// First free/super-basic variable (-1 if none)
+     int firstFree_;
+     /** Number of extra rows.  These are ones which will be dynamically created
+         each iteration.  This is for GUB but may have other uses.
+     */
+     int numberExtraRows_;
+     /** Maximum number of basic variables - can be more than number of rows if GUB
+     */
+     int maximumBasic_;
+     /// If may skip final factorize then allow up to this pivots (default 20)
+     int dontFactorizePivots_;
+     /** For advanced use.  When doing iterative solves things can get
+         nasty so on values pass if incoming solution has largest
+         infeasibility < incomingInfeasibility throw out variables
+         from basis until largest infeasibility < allowedInfeasibility.
+         if allowedInfeasibility>= incomingInfeasibility this is
+         always possible altough you may end up with an all slack basis.
+
+         Defaults are 1.0,10.0
+     */
+     double incomingInfeasibility_;
+     double allowedInfeasibility_;
+     /// Automatic scaling of objective and rhs and bounds
+     int automaticScale_;
+     /// Maximum perturbation array size (take out when code rewritten)
+     int maximumPerturbationSize_;
+     /// Perturbation array (maximumPerturbationSize_)
+     double * perturbationArray_;
+     /// A copy of model with certain state - normally without cuts
+     ClpSimplex * baseModel_;
+     /// For dealing with all issues of cycling etc
+     ClpSimplexProgress progress_;
+#ifdef ABC_INHERIT
+  AbcSimplex * abcSimplex_;
+#define CLP_ABC_WANTED 1
+#define CLP_ABC_WANTED_PARALLEL 2
+#define CLP_ABC_FULL_DONE 8
+  // bits 256,512,1024 for crash
+#endif
+#define CLP_ABC_BEEN_FEASIBLE 65536
+  int abcState_;
+public:
+     /// Spare int array for passing information [0]!=0 switches on
+     mutable int spareIntArray_[4];
+     /// Spare double array for passing information [0]!=0 switches on
+     mutable double spareDoubleArray_[4];
+protected:
+     /// Allow OsiClp certain perks
+     friend class OsiClpSolverInterface;
+     //@}
+};
+//#############################################################################
+/** A function that tests the methods in the ClpSimplex class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging.
+
+    It also does some testing of ClpFactorization class
+ */
+void
+ClpSimplexUnitTest(const std::string & mpsDir);
+
+// For Devex stuff
+#define DEVEX_TRY_NORM 1.0e-4
+#define DEVEX_ADD_ONE 1.0
+#endif
diff --git a/cbits/coin/ClpSimplexDual.cpp b/cbits/coin/ClpSimplexDual.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplexDual.cpp
@@ -0,0 +1,7536 @@
+/* $Id: ClpSimplexDual.cpp 1931 2013-04-06 20:44:29Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+/* Notes on implementation of dual simplex algorithm.
+
+   When dual feasible:
+
+   If primal feasible, we are optimal.  Otherwise choose an infeasible
+   basic variable to leave basis (normally going to nearest bound) (B).  We
+   now need to find an incoming variable which will leave problem
+   dual feasible so we get the row of the tableau corresponding to
+   the basic variable (with the correct sign depending if basic variable
+   above or below feasibility region - as that affects whether reduced
+   cost on outgoing variable has to be positive or negative).
+
+   We now perform a ratio test to determine which incoming variable will
+   preserve dual feasibility (C).  If no variable found then problem
+   is infeasible (in primal sense).  If there is a variable, we then
+   perform pivot and repeat.  Trivial?
+
+   -------------------------------------------
+
+   A) How do we get dual feasible?  If all variables have bounds then
+   it is trivial to get feasible by putting non-basic variables to
+   correct bounds.  OSL did not have a phase 1/phase 2 approach but
+   instead effectively put fake bounds on variables and this is the
+   approach here, although I had hoped to make it cleaner.
+
+   If there is a weight of X on getting dual feasible:
+     Non-basic variables with negative reduced costs are put to
+     lesser of their upper bound and their lower bound + X.
+     Similarly, mutatis mutandis, for positive reduced costs.
+
+   Free variables should normally be in basis, otherwise I have
+   coding which may be able to come out (and may not be correct).
+
+   In OSL, this weight was changed heuristically, here at present
+   it is only increased if problem looks finished.  If problem is
+   feasible I check for unboundedness.  If not unbounded we
+   could play with going into primal.  As long as weights increase
+   any algorithm would be finite.
+
+   B) Which outgoing variable to choose is a virtual base class.
+   For difficult problems steepest edge is preferred while for
+   very easy (large) problems we will need partial scan.
+
+   C) Sounds easy, but this is hardest part of algorithm.
+      1) Instead of stopping at first choice, we may be able
+      to flip that variable to other bound and if objective
+      still improving choose again.  These mini iterations can
+      increase speed by orders of magnitude but we may need to
+      go to more of a bucket choice of variable rather than looking
+      at them one by one (for speed).
+      2) Accuracy.  Reduced costs may be of wrong sign but less than
+      tolerance.  Pivoting on these makes objective go backwards.
+      OSL modified cost so a zero move was made, Gill et al
+      (in primal analogue) modified so a strictly positive move was
+      made.  It is not quite as neat in dual but that is what we
+      try and do.  The two problems are that re-factorizations can
+      change reduced costs above and below tolerances and that when
+      finished we need to reset costs and try again.
+      3) Degeneracy.  Gill et al helps but may not be enough.  We
+      may need more.  Also it can improve speed a lot if we perturb
+      the costs significantly.
+
+  References:
+     Forrest and Goldfarb, Steepest-edge simplex algorithms for
+       linear programming - Mathematical Programming 1992
+     Forrest and Tomlin, Implementing the simplex method for
+       the Optimization Subroutine Library - IBM Systems Journal 1992
+     Gill, Murray, Saunders, Wright A Practical Anti-Cycling
+       Procedure for Linear and Nonlinear Programming SOL report 1988
+
+
+  TODO:
+
+  a) Better recovery procedures.  At present I never check on forward
+     progress.  There is checkpoint/restart with reducing
+     re-factorization frequency, but this is only on singular
+     factorizations.
+  b) Fast methods for large easy problems (and also the option for
+     the code to automatically choose which method).
+  c) We need to be able to stop in various ways for OSI - this
+     is fairly easy.
+
+ */
+#ifdef COIN_DEVELOP
+#undef COIN_DEVELOP
+#define COIN_DEVELOP 2
+#endif
+
+#include "CoinPragma.hpp"
+
+#include <math.h>
+
+#include "CoinHelperFunctions.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "ClpSimplexDual.hpp"
+#include "ClpEventHandler.hpp"
+#include "ClpFactorization.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinFloatEqual.hpp"
+#include "ClpDualRowDantzig.hpp"
+#include "ClpMessage.hpp"
+#include "ClpLinearObjective.hpp"
+#include <cfloat>
+#include <cassert>
+#include <string>
+#include <stdio.h>
+#include <iostream>
+//#define CLP_DEBUG 1
+// To force to follow another run put logfile name here and define
+//#define FORCE_FOLLOW
+#ifdef FORCE_FOLLOW
+static FILE * fpFollow = NULL;
+static char * forceFile = "old.log";
+static int force_in = -1;
+static int force_out = -1;
+static int force_iteration = 0;
+#endif
+//#define VUB
+#ifdef VUB
+extern int * vub;
+extern int * toVub;
+extern int * nextDescendent;
+#endif
+#ifdef NDEBUG
+#define NDEBUG_CLP
+#endif
+#ifndef CLP_INVESTIGATE
+#define NDEBUG_CLP
+#endif
+// dual
+
+/* *** Method
+   This is a vanilla version of dual simplex.
+
+   It tries to be a single phase approach with a weight of 1.0 being
+   given to getting optimal and a weight of dualBound_ being
+   given to getting dual feasible.  In this version I have used the
+   idea that this weight can be thought of as a fake bound.  If the
+   distance between the lower and upper bounds on a variable is less
+   than the feasibility weight then we are always better off flipping
+   to other bound to make dual feasible.  If the distance is greater
+   then we make up a fake bound dualBound_ away from one bound.
+   If we end up optimal or primal infeasible, we check to see if
+   bounds okay.  If so we have finished, if not we increase dualBound_
+   and continue (after checking if unbounded). I am undecided about
+   free variables - there is coding but I am not sure about it.  At
+   present I put them in basis anyway.
+
+   The code is designed to take advantage of sparsity so arrays are
+   seldom zeroed out from scratch or gone over in their entirety.
+   The only exception is a full scan to find outgoing variable.  This
+   will be changed to keep an updated list of infeasibilities (or squares
+   if steepest edge).  Also on easy problems we don't need full scan - just
+   pick first reasonable.
+
+   One problem is how to tackle degeneracy and accuracy.  At present
+   I am using the modification of costs which I put in OSL and which was
+   extended by Gill et al.  I am still not sure of the exact details.
+
+   The flow of dual is three while loops as follows:
+
+   while (not finished) {
+
+     while (not clean solution) {
+
+        Factorize and/or clean up solution by flipping variables so
+  dual feasible.  If looks finished check fake dual bounds.
+  Repeat until status is iterating (-1) or finished (0,1,2)
+
+     }
+
+     while (status==-1) {
+
+       Iterate until no pivot in or out or time to re-factorize.
+
+       Flow is:
+
+       choose pivot row (outgoing variable).  if none then
+ we are primal feasible so looks as if done but we need to
+ break and check bounds etc.
+
+ Get pivot row in tableau
+
+       Choose incoming column.  If we don't find one then we look
+ primal infeasible so break and check bounds etc.  (Also the
+ pivot tolerance is larger after any iterations so that may be
+ reason)
+
+       If we do find incoming column, we may have to adjust costs to
+ keep going forwards (anti-degeneracy).  Check pivot will be stable
+ and if unstable throw away iteration (we will need to implement
+ flagging of basic variables sometime) and break to re-factorize.
+ If minor error re-factorize after iteration.
+
+ Update everything (this may involve flipping variables to stay
+ dual feasible.
+
+     }
+
+   }
+
+   At present we never check we are going forwards.  I overdid that in
+   OSL so will try and make a last resort.
+
+   Needs partial scan pivot out option.
+   Needs dantzig, uninitialized and full steepest edge options (can still
+   use partial scan)
+
+   May need other anti-degeneracy measures, especially if we try and use
+   loose tolerances as a way to solve in fewer iterations.
+
+   I like idea of dynamic scaling.  This gives opportunity to decouple
+   different implications of scaling for accuracy, iteration count and
+   feasibility tolerance.
+
+*/
+#define CLEAN_FIXED 0
+// Startup part of dual (may be extended to other algorithms)
+int
+ClpSimplexDual::startupSolve(int ifValuesPass, double * saveDuals, int startFinishOptions)
+{
+     // If values pass then save given duals round check solution
+     // sanity check
+     // initialize - no values pass and algorithm_ is -1
+     // put in standard form (and make row copy)
+     // create modifiable copies of model rim and do optional scaling
+     // If problem looks okay
+     // Do initial factorization
+     // If user asked for perturbation - do it
+     numberFake_ = 0; // Number of variables at fake bounds
+     numberChanged_ = 0; // Number of variables with changed costs
+     if (!startup(0, startFinishOptions)) {
+          int usePrimal = 0;
+          // looks okay
+          // Superbasic variables not allowed
+          // If values pass then scale pi
+          if (ifValuesPass) {
+               if (problemStatus_ && perturbation_ < 100)
+                    usePrimal = perturb();
+               int i;
+               if (scalingFlag_ > 0) {
+                    for (i = 0; i < numberRows_; i++) {
+                         dual_[i] = saveDuals[i] * inverseRowScale_[i];
+                    }
+               } else {
+                    CoinMemcpyN(saveDuals, numberRows_, dual_);
+               }
+               // now create my duals
+               for (i = 0; i < numberRows_; i++) {
+                    // slack
+                    double value = dual_[i];
+                    value += rowObjectiveWork_[i];
+                    saveDuals[i+numberColumns_] = value;
+               }
+               CoinMemcpyN(objectiveWork_, numberColumns_, saveDuals);
+               transposeTimes(-1.0, dual_, saveDuals);
+               // make reduced costs okay
+               for (i = 0; i < numberColumns_; i++) {
+                    if (getStatus(i) == atLowerBound) {
+                         if (saveDuals[i] < 0.0) {
+                              //if (saveDuals[i]<-1.0e-3)
+                              //printf("bad dj at lb %d %g\n",i,saveDuals[i]);
+                              saveDuals[i] = 0.0;
+                         }
+                    } else if (getStatus(i) == atUpperBound) {
+                         if (saveDuals[i] > 0.0) {
+                              //if (saveDuals[i]>1.0e-3)
+                              //printf("bad dj at ub %d %g\n",i,saveDuals[i]);
+                              saveDuals[i] = 0.0;
+                         }
+                    }
+               }
+               CoinMemcpyN(saveDuals, (numberColumns_ + numberRows_), dj_);
+               // set up possible ones
+               for (i = 0; i < numberRows_ + numberColumns_; i++)
+                    clearPivoted(i);
+               int iRow;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    if (fabs(saveDuals[iPivot]) > dualTolerance_) {
+                         if (getStatus(iPivot) != isFree)
+                              setPivoted(iPivot);
+                    }
+               }
+          } else if ((specialOptions_ & 1024) != 0 && CLEAN_FIXED) {
+               // set up possible ones
+               for (int i = 0; i < numberRows_ + numberColumns_; i++)
+                    clearPivoted(i);
+               int iRow;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    if (iPivot < numberColumns_ && lower_[iPivot] == upper_[iPivot]) {
+                         setPivoted(iPivot);
+                    }
+               }
+          }
+
+          double objectiveChange;
+          assert (!numberFake_);
+          assert (numberChanged_ == 0);
+          if (!numberFake_) // if nonzero then adjust
+               changeBounds(1, NULL, objectiveChange);
+
+          if (!ifValuesPass) {
+               // Check optimal
+               if (!numberDualInfeasibilities_ && !numberPrimalInfeasibilities_)
+                    problemStatus_ = 0;
+          }
+          if (problemStatus_ < 0 && perturbation_ < 100) {
+               bool inCbcOrOther = (specialOptions_ & 0x03000000) != 0;
+               if (!inCbcOrOther)
+                    usePrimal = perturb();
+               // Can't get here if values pass
+               gutsOfSolution(NULL, NULL);
+#ifdef CLP_INVESTIGATE
+               if (numberDualInfeasibilities_)
+                    printf("ZZZ %d primal %d dual - sumdinf %g\n",
+                           numberPrimalInfeasibilities_,
+                           numberDualInfeasibilities_, sumDualInfeasibilities_);
+#endif
+               if (handler_->logLevel() > 2) {
+                    handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                              << numberIterations_ << objectiveValue();
+                    handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                              << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+                    handler_->printing(sumDualInfeasibilities_ > 0.0)
+                              << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+                    handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                                       < numberDualInfeasibilities_)
+                              << numberDualInfeasibilitiesWithoutFree_;
+                    handler_->message() << CoinMessageEol;
+               }
+               if (inCbcOrOther) {
+                    if (numberPrimalInfeasibilities_) {
+                         usePrimal = perturb();
+                         if (perturbation_ >= 101) {
+                              computeDuals(NULL);
+                              //gutsOfSolution(NULL,NULL);
+                              checkDualSolution(); // recompute objective
+                         }
+                    } else if (numberDualInfeasibilities_) {
+                         problemStatus_ = 10;
+                         if ((moreSpecialOptions_ & 32) != 0 && false)
+                              problemStatus_ = 0; // say optimal!!
+#if COIN_DEVELOP>2
+
+                         printf("returning at %d\n", __LINE__);
+#endif
+                         return 1; // to primal
+                    }
+               }
+          } else if (!ifValuesPass) {
+               gutsOfSolution(NULL, NULL);
+               // double check
+               if (numberDualInfeasibilities_ || numberPrimalInfeasibilities_)
+                    problemStatus_ = -1;
+          }
+          if (usePrimal) {
+               problemStatus_ = 10;
+#if COIN_DEVELOP>2
+               printf("returning to use primal (no obj) at %d\n", __LINE__);
+#endif
+          }
+          return usePrimal;
+     } else {
+          return 1;
+     }
+}
+void
+ClpSimplexDual::finishSolve(int startFinishOptions)
+{
+     assert (problemStatus_ || !sumPrimalInfeasibilities_);
+
+     // clean up
+     finish(startFinishOptions);
+}
+//#define CLP_REPORT_PROGRESS
+#ifdef CLP_REPORT_PROGRESS
+static int ixxxxxx = 0;
+static int ixxyyyy = 90;
+#endif
+#ifdef CLP_INVESTIGATE_SERIAL
+static int z_reason[7] = {0, 0, 0, 0, 0, 0, 0};
+static int z_thinks = -1;
+#endif
+void
+ClpSimplexDual::gutsOfDual(int ifValuesPass, double * & saveDuals, int initialStatus,
+                           ClpDataSave & data)
+{
+#ifdef CLP_INVESTIGATE_SERIAL
+     z_reason[0]++;
+     z_thinks = -1;
+     int nPivots = 9999;
+#endif
+     double largestPrimalError = 0.0;
+     double largestDualError = 0.0;
+     // Start can skip some things in transposeTimes
+     specialOptions_ |= 131072;
+     int lastCleaned = 0; // last time objective or bounds cleaned up
+
+     // This says whether to restore things etc
+     // startup will have factorized so can skip
+     int factorType = 0;
+     // Start check for cycles
+     progress_.startCheck();
+     // Say change made on first iteration
+     changeMade_ = 1;
+     // Say last objective infinite
+     //lastObjectiveValue_=-COIN_DBL_MAX;
+     progressFlag_ = 0;
+     /*
+       Status of problem:
+       0 - optimal
+       1 - infeasible
+       2 - unbounded
+       -1 - iterating
+       -2 - factorization wanted
+       -3 - redo checking without factorization
+       -4 - looks infeasible
+     */
+     while (problemStatus_ < 0) {
+          int iRow, iColumn;
+          // clear
+          for (iRow = 0; iRow < 4; iRow++) {
+               rowArray_[iRow]->clear();
+          }
+
+          for (iColumn = 0; iColumn < 2; iColumn++) {
+               columnArray_[iColumn]->clear();
+          }
+
+          // give matrix (and model costs and bounds a chance to be
+          // refreshed (normally null)
+          matrix_->refresh(this);
+          // If getting nowhere - why not give it a kick
+          // does not seem to work too well - do some more work
+          if (perturbation_ < 101 && numberIterations_ > 2 * (numberRows_ + numberColumns_)
+                    && initialStatus != 10) {
+               perturb();
+               // Can't get here if values pass
+               gutsOfSolution(NULL, NULL);
+               if (handler_->logLevel() > 2) {
+                    handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                              << numberIterations_ << objectiveValue();
+                    handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                              << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+                    handler_->printing(sumDualInfeasibilities_ > 0.0)
+                              << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+                    handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                                       < numberDualInfeasibilities_)
+                              << numberDualInfeasibilitiesWithoutFree_;
+                    handler_->message() << CoinMessageEol;
+               }
+          }
+          // see if in Cbc etc
+          bool inCbcOrOther = (specialOptions_ & 0x03000000) != 0;
+#if 0
+          bool gotoPrimal = false;
+          if (inCbcOrOther && numberIterations_ > disasterArea_ + numberRows_ &&
+                    numberDualInfeasibilitiesWithoutFree_ && largestDualError_ > 1.0e-1) {
+               if (!disasterArea_) {
+                    printf("trying all slack\n");
+                    // try all slack basis
+                    allSlackBasis(true);
+                    disasterArea_ = 2 * numberRows_;
+               } else {
+                    printf("going to primal\n");
+                    // go to primal
+                    gotoPrimal = true;
+                    allSlackBasis(true);
+               }
+          }
+#endif
+          bool disaster = false;
+          if (disasterArea_ && inCbcOrOther && disasterArea_->check()) {
+               disasterArea_->saveInfo();
+               disaster = true;
+          }
+          // may factorize, checks if problem finished
+          statusOfProblemInDual(lastCleaned, factorType, saveDuals, data,
+                                ifValuesPass);
+          largestPrimalError = CoinMax(largestPrimalError, largestPrimalError_);
+          largestDualError = CoinMax(largestDualError, largestDualError_);
+          if (disaster)
+               problemStatus_ = 3;
+          // If values pass then do easy ones on first time
+          if (ifValuesPass &&
+                    progress_.lastIterationNumber(0) < 0 && saveDuals) {
+               doEasyOnesInValuesPass(saveDuals);
+          }
+
+          // Say good factorization
+          factorType = 1;
+          if (data.sparseThreshold_) {
+               // use default at present
+               factorization_->sparseThreshold(0);
+               factorization_->goSparse();
+          }
+
+          // exit if victory declared
+          if (problemStatus_ >= 0)
+               break;
+
+          // test for maximum iterations
+          if (hitMaximumIterations() || (ifValuesPass == 2 && !saveDuals)) {
+               problemStatus_ = 3;
+               break;
+          }
+          if (ifValuesPass && !saveDuals) {
+               // end of values pass
+               ifValuesPass = 0;
+               int status = eventHandler_->event(ClpEventHandler::endOfValuesPass);
+               if (status >= 0) {
+                    problemStatus_ = 5;
+                    secondaryStatus_ = ClpEventHandler::endOfValuesPass;
+                    break;
+               }
+          }
+          // Check event
+          {
+               int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
+               if (status >= 0) {
+                    problemStatus_ = 5;
+                    secondaryStatus_ = ClpEventHandler::endOfFactorization;
+                    break;
+               }
+          }
+          // Do iterations
+          int returnCode = whileIterating(saveDuals, ifValuesPass);
+	  if (problemStatus_ == 1 && (progressFlag_&8) != 0 &&
+	      fabs(objectiveValue_) > 1.0e10 )
+	    problemStatus_ = 10; // infeasible - but has looked feasible
+#ifdef CLP_INVESTIGATE_SERIAL
+          nPivots = factorization_->pivots();
+#endif
+          if (!problemStatus_ && factorization_->pivots())
+               computeDuals(NULL); // need to compute duals
+          if (returnCode == -2)
+               factorType = 3;
+     }
+#ifdef CLP_INVESTIGATE_SERIAL
+     // NOTE - can fail if parallel
+     if (z_thinks != -1) {
+          assert (z_thinks < 4);
+          if ((!factorization_->pivots() && nPivots < 20) && z_thinks >= 0 && z_thinks < 2)
+               z_thinks += 4;
+          z_reason[1+z_thinks]++;
+     }
+     if ((z_reason[0] % 1000) == 0) {
+          printf("Reason");
+          for (int i = 0; i < 7; i++)
+               printf(" %d", z_reason[i]);
+          printf("\n");
+     }
+#endif
+     // Stop can skip some things in transposeTimes
+     specialOptions_ &= ~131072;
+     largestPrimalError_ = largestPrimalError;
+     largestDualError_ = largestDualError;
+}
+int
+ClpSimplexDual::dual(int ifValuesPass, int startFinishOptions)
+{
+  //handler_->setLogLevel(63);
+  //yprintf("STARTing dual %d rows\n",numberRows_);
+     bestObjectiveValue_ = -COIN_DBL_MAX;
+     algorithm_ = -1;
+     moreSpecialOptions_ &= ~16; // clear check replaceColumn accuracy
+     // save data
+     ClpDataSave data = saveData();
+     double * saveDuals = NULL;
+     int saveDont = dontFactorizePivots_;
+     if ((specialOptions_ & 2048) == 0)
+          dontFactorizePivots_ = 0;
+     else if(!dontFactorizePivots_)
+          dontFactorizePivots_ = 20;
+     if (ifValuesPass) {
+          saveDuals = new double [numberRows_+numberColumns_];
+          CoinMemcpyN(dual_, numberRows_, saveDuals);
+     }
+     if (alphaAccuracy_ != -1.0)
+          alphaAccuracy_ = 1.0;
+     int returnCode = startupSolve(ifValuesPass, saveDuals, startFinishOptions);
+     // Save so can see if doing after primal
+     int initialStatus = problemStatus_;
+     if (!returnCode && !numberDualInfeasibilities_ &&
+               !numberPrimalInfeasibilities_ && perturbation_ < 101) {
+          returnCode = 1; // to skip gutsOfDual
+          problemStatus_ = 0;
+     }
+
+     if (!returnCode)
+          gutsOfDual(ifValuesPass, saveDuals, initialStatus, data);
+     if (!problemStatus_) {
+          // see if cutoff reached
+          double limit = 0.0;
+          getDblParam(ClpDualObjectiveLimit, limit);
+          if(fabs(limit) < 1.0e30 && objectiveValue()*optimizationDirection_ >
+                    limit + 1.0e-7 + 1.0e-8 * fabs(limit)) {
+               // actually infeasible on objective
+               problemStatus_ = 1;
+               secondaryStatus_ = 1;
+          }
+     }
+     // If infeasible but primal errors - try dual
+     if (problemStatus_==1 && numberPrimalInfeasibilities_) {
+       bool inCbcOrOther = (specialOptions_ & 0x03000000) != 0;
+       double factor = (!inCbcOrOther) ? 1.0 : 0.3;
+       double averageInfeasibility = sumPrimalInfeasibilities_/
+	 static_cast<double>(numberPrimalInfeasibilities_);
+       if (averageInfeasibility<factor*largestPrimalError_)
+	 problemStatus_= 10;
+     }
+       
+     if (problemStatus_ == 10)
+          startFinishOptions |= 1;
+     finishSolve(startFinishOptions);
+     delete [] saveDuals;
+
+     // Restore any saved stuff
+     restoreData(data);
+     dontFactorizePivots_ = saveDont;
+     if (problemStatus_ == 3)
+          objectiveValue_ = CoinMax(bestObjectiveValue_, objectiveValue_ - bestPossibleImprovement_);
+     return problemStatus_;
+}
+// old way
+#if 0
+int ClpSimplexDual::dual (int ifValuesPass , int startFinishOptions)
+{
+     algorithm_ = -1;
+
+     // save data
+     ClpDataSave data = saveData();
+     // Save so can see if doing after primal
+     int initialStatus = problemStatus_;
+
+     // If values pass then save given duals round check solution
+     double * saveDuals = NULL;
+     if (ifValuesPass) {
+          saveDuals = new double [numberRows_+numberColumns_];
+          CoinMemcpyN(dual_, numberRows_, saveDuals);
+     }
+     // sanity check
+     // initialize - no values pass and algorithm_ is -1
+     // put in standard form (and make row copy)
+     // create modifiable copies of model rim and do optional scaling
+     // If problem looks okay
+     // Do initial factorization
+     // If user asked for perturbation - do it
+     if (!startup(0, startFinishOptions)) {
+          // looks okay
+          // Superbasic variables not allowed
+          // If values pass then scale pi
+          if (ifValuesPass) {
+               if (problemStatus_ && perturbation_ < 100)
+                    perturb();
+               int i;
+               if (scalingFlag_ > 0) {
+                    for (i = 0; i < numberRows_; i++) {
+                         dual_[i] = saveDuals[i] * inverseRowScale_[i];
+                    }
+               } else {
+                    CoinMemcpyN(saveDuals, numberRows_, dual_);
+               }
+               // now create my duals
+               for (i = 0; i < numberRows_; i++) {
+                    // slack
+                    double value = dual_[i];
+                    value += rowObjectiveWork_[i];
+                    saveDuals[i+numberColumns_] = value;
+               }
+               CoinMemcpyN(objectiveWork_, numberColumns_, saveDuals);
+               transposeTimes(-1.0, dual_, saveDuals);
+               // make reduced costs okay
+               for (i = 0; i < numberColumns_; i++) {
+                    if (getStatus(i) == atLowerBound) {
+                         if (saveDuals[i] < 0.0) {
+                              //if (saveDuals[i]<-1.0e-3)
+                              //printf("bad dj at lb %d %g\n",i,saveDuals[i]);
+                              saveDuals[i] = 0.0;
+                         }
+                    } else if (getStatus(i) == atUpperBound) {
+                         if (saveDuals[i] > 0.0) {
+                              //if (saveDuals[i]>1.0e-3)
+                              //printf("bad dj at ub %d %g\n",i,saveDuals[i]);
+                              saveDuals[i] = 0.0;
+                         }
+                    }
+               }
+               CoinMemcpyN(saveDuals, numberColumns_ + numberRows_, dj_);
+               // set up possible ones
+               for (i = 0; i < numberRows_ + numberColumns_; i++)
+                    clearPivoted(i);
+               int iRow;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    if (fabs(saveDuals[iPivot]) > dualTolerance_) {
+                         if (getStatus(iPivot) != isFree)
+                              setPivoted(iPivot);
+                    }
+               }
+          } else if ((specialOptions_ & 1024) != 0 && CLEAN_FIXED) {
+               // set up possible ones
+               for (int i = 0; i < numberRows_ + numberColumns_; i++)
+                    clearPivoted(i);
+               int iRow;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    if (iPivot < numberColumns_ && lower_[iPivot] == upper_[iPivot]) {
+                         setPivoted(iPivot);
+                    }
+               }
+          }
+
+          double objectiveChange;
+          numberFake_ = 0; // Number of variables at fake bounds
+          numberChanged_ = 0; // Number of variables with changed costs
+          changeBounds(1, NULL, objectiveChange);
+
+          int lastCleaned = 0; // last time objective or bounds cleaned up
+
+          if (!ifValuesPass) {
+               // Check optimal
+               if (!numberDualInfeasibilities_ && !numberPrimalInfeasibilities_)
+                    problemStatus_ = 0;
+          }
+          if (problemStatus_ < 0 && perturbation_ < 100) {
+               perturb();
+               // Can't get here if values pass
+               gutsOfSolution(NULL, NULL);
+               if (handler_->logLevel() > 2) {
+                    handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                              << numberIterations_ << objectiveValue();
+                    handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                              << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+                    handler_->printing(sumDualInfeasibilities_ > 0.0)
+                              << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+                    handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                                       < numberDualInfeasibilities_)
+                              << numberDualInfeasibilitiesWithoutFree_;
+                    handler_->message() << CoinMessageEol;
+               }
+          }
+
+          // This says whether to restore things etc
+          // startup will have factorized so can skip
+          int factorType = 0;
+          // Start check for cycles
+          progress_.startCheck();
+          // Say change made on first iteration
+          changeMade_ = 1;
+          /*
+            Status of problem:
+            0 - optimal
+            1 - infeasible
+            2 - unbounded
+            -1 - iterating
+            -2 - factorization wanted
+            -3 - redo checking without factorization
+            -4 - looks infeasible
+          */
+          while (problemStatus_ < 0) {
+               int iRow, iColumn;
+               // clear
+               for (iRow = 0; iRow < 4; iRow++) {
+                    rowArray_[iRow]->clear();
+               }
+
+               for (iColumn = 0; iColumn < 2; iColumn++) {
+                    columnArray_[iColumn]->clear();
+               }
+
+               // give matrix (and model costs and bounds a chance to be
+               // refreshed (normally null)
+               matrix_->refresh(this);
+               // If getting nowhere - why not give it a kick
+               // does not seem to work too well - do some more work
+               if (perturbation_ < 101 && numberIterations_ > 2 * (numberRows_ + numberColumns_)
+                         && initialStatus != 10) {
+                    perturb();
+                    // Can't get here if values pass
+                    gutsOfSolution(NULL, NULL);
+                    if (handler_->logLevel() > 2) {
+                         handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                                   << numberIterations_ << objectiveValue();
+                         handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                                   << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+                         handler_->printing(sumDualInfeasibilities_ > 0.0)
+                                   << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+                         handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                                            < numberDualInfeasibilities_)
+                                   << numberDualInfeasibilitiesWithoutFree_;
+                         handler_->message() << CoinMessageEol;
+                    }
+               }
+               // may factorize, checks if problem finished
+               statusOfProblemInDual(lastCleaned, factorType, saveDuals, data,
+                                     ifValuesPass);
+               // If values pass then do easy ones on first time
+               if (ifValuesPass &&
+                         progress_.lastIterationNumber(0) < 0 && saveDuals) {
+                    doEasyOnesInValuesPass(saveDuals);
+               }
+
+               // Say good factorization
+               factorType = 1;
+               if (data.sparseThreshold_) {
+                    // use default at present
+                    factorization_->sparseThreshold(0);
+                    factorization_->goSparse();
+               }
+
+               // exit if victory declared
+               if (problemStatus_ >= 0)
+                    break;
+
+               // test for maximum iterations
+               if (hitMaximumIterations() || (ifValuesPass == 2 && !saveDuals)) {
+                    problemStatus_ = 3;
+                    break;
+               }
+               if (ifValuesPass && !saveDuals) {
+                    // end of values pass
+                    ifValuesPass = 0;
+                    int status = eventHandler_->event(ClpEventHandler::endOfValuesPass);
+                    if (status >= 0) {
+                         problemStatus_ = 5;
+                         secondaryStatus_ = ClpEventHandler::endOfValuesPass;
+                         break;
+                    }
+               }
+               // Check event
+               {
+                    int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
+                    if (status >= 0) {
+                         problemStatus_ = 5;
+                         secondaryStatus_ = ClpEventHandler::endOfFactorization;
+                         break;
+                    }
+               }
+               // Do iterations
+               whileIterating(saveDuals, ifValuesPass);
+          }
+     }
+
+     assert (problemStatus_ || !sumPrimalInfeasibilities_);
+
+     // clean up
+     finish(startFinishOptions);
+     delete [] saveDuals;
+
+     // Restore any saved stuff
+     restoreData(data);
+     return problemStatus_;
+}
+#endif
+//#define CHECK_ACCURACY
+#ifdef CHECK_ACCURACY
+static double zzzzzz[100000];
+#endif
+/* Reasons to come out:
+   -1 iterations etc
+   -2 inaccuracy
+   -3 slight inaccuracy (and done iterations)
+   +0 looks optimal (might be unbounded - but we will investigate)
+   +1 looks infeasible
+   +3 max iterations
+ */
+int
+ClpSimplexDual::whileIterating(double * & givenDuals, int ifValuesPass)
+{
+#ifdef CLP_INVESTIGATE_SERIAL
+     z_thinks = -1;
+#endif
+#ifdef CLP_DEBUG
+     int debugIteration = -1;
+#endif
+     {
+          int i;
+          for (i = 0; i < 4; i++) {
+               rowArray_[i]->clear();
+          }
+          for (i = 0; i < 2; i++) {
+               columnArray_[i]->clear();
+          }
+     }
+#ifdef CLP_REPORT_PROGRESS
+     double * savePSol = new double [numberRows_+numberColumns_];
+     double * saveDj = new double [numberRows_+numberColumns_];
+     double * saveCost = new double [numberRows_+numberColumns_];
+     unsigned char * saveStat = new unsigned char [numberRows_+numberColumns_];
+#endif
+     // if can't trust much and long way from optimal then relax
+     if (largestPrimalError_ > 10.0)
+          factorization_->relaxAccuracyCheck(CoinMin(1.0e2, largestPrimalError_ / 10.0));
+     else
+          factorization_->relaxAccuracyCheck(1.0);
+     // status stays at -1 while iterating, >=0 finished, -2 to invert
+     // status -3 to go to top without an invert
+     int returnCode = -1;
+     double saveSumDual = sumDualInfeasibilities_; // so we know to be careful
+
+#if 0
+     // compute average infeasibility for backward test
+     double averagePrimalInfeasibility = sumPrimalInfeasibilities_ /
+                                         ((double ) (numberPrimalInfeasibilities_ + 1));
+#endif
+
+     // Get dubious weights
+     CoinBigIndex * dubiousWeights = NULL;
+#ifdef DUBIOUS_WEIGHTS
+     factorization_->getWeights(rowArray_[0]->getIndices());
+     dubiousWeights = matrix_->dubiousWeights(this, rowArray_[0]->getIndices());
+#endif
+     // If values pass then get list of candidates
+     int * candidateList = NULL;
+     int numberCandidates = 0;
+#ifdef CLP_DEBUG
+     bool wasInValuesPass = (givenDuals != NULL);
+#endif
+     int candidate = -1;
+     if (givenDuals) {
+          assert (ifValuesPass);
+          ifValuesPass = 1;
+          candidateList = new int[numberRows_];
+          // move reduced costs across
+          CoinMemcpyN(givenDuals, numberRows_ + numberColumns_, dj_);
+          int iRow;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int iPivot = pivotVariable_[iRow];
+               if (flagged(iPivot))
+                    continue;
+               if (fabs(dj_[iPivot]) > dualTolerance_) {
+                    // for now safer to ignore free ones
+                    if (lower_[iPivot] > -1.0e50 || upper_[iPivot] < 1.0e50)
+                         if (pivoted(iPivot))
+                              candidateList[numberCandidates++] = iRow;
+               } else {
+                    clearPivoted(iPivot);
+               }
+          }
+          // and set first candidate
+          if (!numberCandidates) {
+               delete [] candidateList;
+               delete [] givenDuals;
+               givenDuals = NULL;
+               candidateList = NULL;
+               int iRow;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    int iPivot = pivotVariable_[iRow];
+                    clearPivoted(iPivot);
+               }
+          }
+     } else {
+          assert (!ifValuesPass);
+     }
+#ifdef CHECK_ACCURACY
+     {
+          if (numberIterations_) {
+               int il = -1;
+               double largest = 1.0e-1;
+               int ilnb = -1;
+               double largestnb = 1.0e-8;
+               for (int i = 0; i < numberRows_ + numberColumns_; i++) {
+                    double diff = fabs(solution_[i] - zzzzzz[i]);
+                    if (diff > largest) {
+                         largest = diff;
+                         il = i;
+                    }
+                    if (getColumnStatus(i) != basic) {
+                         if (diff > largestnb) {
+                              largestnb = diff;
+                              ilnb = i;
+                         }
+                    }
+               }
+               if (il >= 0 && ilnb < 0)
+                    printf("largest diff of %g at %d, nonbasic %g at %d\n",
+                           largest, il, largestnb, ilnb);
+          }
+     }
+#endif
+     while (problemStatus_ == -1) {
+          //if (numberIterations_>=101624)
+          //resetFakeBounds(-1);
+#ifdef CLP_DEBUG
+          if (givenDuals) {
+               double value5 = 0.0;
+               int i;
+               for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                    if (dj_[i] < -1.0e-6)
+                         if (upper_[i] < 1.0e20)
+                              value5 += dj_[i] * upper_[i];
+                         else
+                              printf("bad dj %g on %d with large upper status %d\n",
+                                     dj_[i], i, status_[i] & 7);
+                    else if (dj_[i] > 1.0e-6)
+                         if (lower_[i] > -1.0e20)
+                              value5 += dj_[i] * lower_[i];
+                         else
+                              printf("bad dj %g on %d with large lower status %d\n",
+                                     dj_[i], i, status_[i] & 7);
+               }
+               printf("Values objective Value %g\n", value5);
+          }
+          if ((handler_->logLevel() & 32) && wasInValuesPass) {
+               double value5 = 0.0;
+               int i;
+               for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                    if (dj_[i] < -1.0e-6)
+                         if (upper_[i] < 1.0e20)
+                              value5 += dj_[i] * upper_[i];
+                         else if (dj_[i] > 1.0e-6)
+                              if (lower_[i] > -1.0e20)
+                                   value5 += dj_[i] * lower_[i];
+               }
+               printf("Values objective Value %g\n", value5);
+               {
+                    int i;
+                    for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                         int iSequence = i;
+                         double oldValue;
+
+                         switch(getStatus(iSequence)) {
+
+                         case basic:
+                         case ClpSimplex::isFixed:
+                              break;
+                         case isFree:
+                         case superBasic:
+                              abort();
+                              break;
+                         case atUpperBound:
+                              oldValue = dj_[iSequence];
+                              //assert (oldValue<=tolerance);
+                              assert (fabs(solution_[iSequence] - upper_[iSequence]) < 1.0e-7);
+                              break;
+                         case atLowerBound:
+                              oldValue = dj_[iSequence];
+                              //assert (oldValue>=-tolerance);
+                              assert (fabs(solution_[iSequence] - lower_[iSequence]) < 1.0e-7);
+                              break;
+                         }
+                    }
+               }
+          }
+#endif
+#ifdef CLP_DEBUG
+          {
+               int i;
+               for (i = 0; i < 4; i++) {
+                    rowArray_[i]->checkClear();
+               }
+               for (i = 0; i < 2; i++) {
+                    columnArray_[i]->checkClear();
+               }
+          }
+#endif
+#if CLP_DEBUG>2
+          // very expensive
+          if (numberIterations_ > 3063 && numberIterations_ < 30700) {
+               //handler_->setLogLevel(63);
+               double saveValue = objectiveValue_;
+               double * saveRow1 = new double[numberRows_];
+               double * saveRow2 = new double[numberRows_];
+               CoinMemcpyN(rowReducedCost_, numberRows_, saveRow1);
+               CoinMemcpyN(rowActivityWork_, numberRows_, saveRow2);
+               double * saveColumn1 = new double[numberColumns_];
+               double * saveColumn2 = new double[numberColumns_];
+               CoinMemcpyN(reducedCostWork_, numberColumns_, saveColumn1);
+               CoinMemcpyN(columnActivityWork_, numberColumns_, saveColumn2);
+               gutsOfSolution(NULL, NULL);
+               printf("xxx %d old obj %g, recomputed %g, sum dual inf %g\n",
+                      numberIterations_,
+                      saveValue, objectiveValue_, sumDualInfeasibilities_);
+               if (saveValue > objectiveValue_ + 1.0e-2)
+                    printf("**bad**\n");
+               CoinMemcpyN(saveRow1, numberRows_, rowReducedCost_);
+               CoinMemcpyN(saveRow2, numberRows_, rowActivityWork_);
+               CoinMemcpyN(saveColumn1, numberColumns_, reducedCostWork_);
+               CoinMemcpyN(saveColumn2, numberColumns_, columnActivityWork_);
+               delete [] saveRow1;
+               delete [] saveRow2;
+               delete [] saveColumn1;
+               delete [] saveColumn2;
+               objectiveValue_ = saveValue;
+          }
+#endif
+#if 0
+          //    if (factorization_->pivots()){
+          {
+               int iPivot;
+               double * array = rowArray_[3]->denseVector();
+               int i;
+               for (iPivot = 0; iPivot < numberRows_; iPivot++) {
+                    int iSequence = pivotVariable_[iPivot];
+                    unpack(rowArray_[3], iSequence);
+                    factorization_->updateColumn(rowArray_[2], rowArray_[3]);
+                    assert (fabs(array[iPivot] - 1.0) < 1.0e-4);
+                    array[iPivot] = 0.0;
+                    for (i = 0; i < numberRows_; i++)
+                         assert (fabs(array[i]) < 1.0e-4);
+                    rowArray_[3]->clear();
+               }
+          }
+#endif
+#ifdef CLP_DEBUG
+          {
+               int iSequence, number = numberRows_ + numberColumns_;
+               for (iSequence = 0; iSequence < number; iSequence++) {
+                    double lowerValue = lower_[iSequence];
+                    double upperValue = upper_[iSequence];
+                    double value = solution_[iSequence];
+                    if(getStatus(iSequence) != basic && getStatus(iSequence) != isFree) {
+                         assert(lowerValue > -1.0e20);
+                         assert(upperValue < 1.0e20);
+                    }
+                    switch(getStatus(iSequence)) {
+
+                    case basic:
+                         break;
+                    case isFree:
+                    case superBasic:
+                         break;
+                    case atUpperBound:
+                         assert (fabs(value - upperValue) <= primalTolerance_) ;
+                         break;
+                    case atLowerBound:
+                    case ClpSimplex::isFixed:
+                         assert (fabs(value - lowerValue) <= primalTolerance_) ;
+                         break;
+                    }
+               }
+          }
+          if(numberIterations_ == debugIteration) {
+               printf("dodgy iteration coming up\n");
+          }
+#endif
+#if 0
+          printf("checking nz\n");
+          for (int i = 0; i < 3; i++) {
+               if (!rowArray_[i]->getNumElements())
+                    rowArray_[i]->checkClear();
+          }
+#endif
+          // choose row to go out
+          // dualRow will go to virtual row pivot choice algorithm
+          // make sure values pass off if it should be
+          if (numberCandidates)
+               candidate = candidateList[--numberCandidates];
+          else
+               candidate = -1;
+          dualRow(candidate);
+          if (pivotRow_ >= 0) {
+               // we found a pivot row
+               if (handler_->detail(CLP_SIMPLEX_PIVOTROW, messages_) < 100) {
+                    handler_->message(CLP_SIMPLEX_PIVOTROW, messages_)
+                              << pivotRow_
+                              << CoinMessageEol;
+               }
+               // check accuracy of weights
+               dualRowPivot_->checkAccuracy();
+               // Get good size for pivot
+               // Allow first few iterations to take tiny
+               double acceptablePivot = 1.0e-1 * acceptablePivot_;
+               if (numberIterations_ > 100)
+                    acceptablePivot = acceptablePivot_;
+               if (factorization_->pivots() > 10 ||
+                         (factorization_->pivots() && saveSumDual))
+                    acceptablePivot = 1.0e+3 * acceptablePivot_; // if we have iterated be more strict
+               else if (factorization_->pivots() > 5)
+                    acceptablePivot = 1.0e+2 * acceptablePivot_; // if we have iterated be slightly more strict
+               else if (factorization_->pivots())
+                    acceptablePivot = acceptablePivot_; // relax
+               // But factorizations complain if <1.0e-8
+               //acceptablePivot=CoinMax(acceptablePivot,1.0e-8);
+               double bestPossiblePivot = 1.0;
+               // get sign for finding row of tableau
+               if (candidate < 0) {
+                    // normal iteration
+                    // create as packed
+                    double direction = directionOut_;
+                    rowArray_[0]->createPacked(1, &pivotRow_, &direction);
+                    factorization_->updateColumnTranspose(rowArray_[1], rowArray_[0]);
+                    // Allow to do dualColumn0
+                    if (numberThreads_ < -1)
+                         spareIntArray_[0] = 1;
+                    spareDoubleArray_[0] = acceptablePivot;
+                    rowArray_[3]->clear();
+                    sequenceIn_ = -1;
+                    // put row of tableau in rowArray[0] and columnArray[0]
+                    assert (!rowArray_[1]->getNumElements());
+                    if (!scaledMatrix_) {
+                         if ((moreSpecialOptions_ & 8) != 0 && !rowScale_)
+                              spareIntArray_[0] = 1;
+                         matrix_->transposeTimes(this, -1.0,
+                                                 rowArray_[0], rowArray_[1], columnArray_[0]);
+                    } else {
+                         double * saveR = rowScale_;
+                         double * saveC = columnScale_;
+                         rowScale_ = NULL;
+                         columnScale_ = NULL;
+                         if ((moreSpecialOptions_ & 8) != 0)
+                              spareIntArray_[0] = 1;
+                         scaledMatrix_->transposeTimes(this, -1.0,
+                                                       rowArray_[0], rowArray_[1], columnArray_[0]);
+                         rowScale_ = saveR;
+                         columnScale_ = saveC;
+                    }
+#ifdef CLP_REPORT_PROGRESS
+                    memcpy(savePSol, solution_, (numberColumns_ + numberRows_)*sizeof(double));
+                    memcpy(saveDj, dj_, (numberColumns_ + numberRows_)*sizeof(double));
+                    memcpy(saveCost, cost_, (numberColumns_ + numberRows_)*sizeof(double));
+                    memcpy(saveStat, status_, (numberColumns_ + numberRows_)*sizeof(char));
+#endif
+                    // do ratio test for normal iteration
+                    bestPossiblePivot = dualColumn(rowArray_[0], columnArray_[0], rowArray_[3],
+                                                   columnArray_[1], acceptablePivot, dubiousWeights);
+#if CAN_HAVE_ZERO_OBJ>1
+		    if ((specialOptions_&2097152)!=0) 
+		      theta_=0.0;
+#endif
+               } else {
+                    // Make sure direction plausible
+                    CoinAssert (upperOut_ < 1.0e50 || lowerOut_ > -1.0e50);
+                    // If in integer cleanup do direction using duals
+                    // may be wrong way round
+                    if(ifValuesPass == 2) {
+                         if (dual_[pivotRow_] > 0.0) {
+                              // this will give a -1 in pivot row (as slacks are -1.0)
+                              directionOut_ = 1;
+                         } else {
+                              directionOut_ = -1;
+                         }
+                    }
+                    if (directionOut_ < 0 && fabs(valueOut_ - upperOut_) > dualBound_ + primalTolerance_) {
+                         if (fabs(valueOut_ - upperOut_) > fabs(valueOut_ - lowerOut_))
+                              directionOut_ = 1;
+                    } else if (directionOut_ > 0 && fabs(valueOut_ - lowerOut_) > dualBound_ + primalTolerance_) {
+                         if (fabs(valueOut_ - upperOut_) < fabs(valueOut_ - lowerOut_))
+                              directionOut_ = -1;
+                    }
+                    double direction = directionOut_;
+                    rowArray_[0]->createPacked(1, &pivotRow_, &direction);
+                    factorization_->updateColumnTranspose(rowArray_[1], rowArray_[0]);
+                    // put row of tableau in rowArray[0] and columnArray[0]
+                    if (!scaledMatrix_) {
+                         matrix_->transposeTimes(this, -1.0,
+                                                 rowArray_[0], rowArray_[3], columnArray_[0]);
+                    } else {
+                         double * saveR = rowScale_;
+                         double * saveC = columnScale_;
+                         rowScale_ = NULL;
+                         columnScale_ = NULL;
+                         scaledMatrix_->transposeTimes(this, -1.0,
+                                                       rowArray_[0], rowArray_[3], columnArray_[0]);
+                         rowScale_ = saveR;
+                         columnScale_ = saveC;
+                    }
+                    acceptablePivot *= 10.0;
+                    // do ratio test
+                    if (ifValuesPass == 1) {
+                         checkPossibleValuesMove(rowArray_[0], columnArray_[0],
+                                                 acceptablePivot);
+                    } else {
+                         checkPossibleCleanup(rowArray_[0], columnArray_[0],
+                                              acceptablePivot);
+                         if (sequenceIn_ < 0) {
+                              rowArray_[0]->clear();
+                              columnArray_[0]->clear();
+                              continue; // can't do anything
+                         }
+                    }
+
+                    // recompute true dualOut_
+                    if (directionOut_ < 0) {
+                         dualOut_ = valueOut_ - upperOut_;
+                    } else {
+                         dualOut_ = lowerOut_ - valueOut_;
+                    }
+                    // check what happened if was values pass
+                    // may want to move part way i.e. movement
+                    bool normalIteration = (sequenceIn_ != sequenceOut_);
+
+                    clearPivoted(sequenceOut_);  // make sure won't be done again
+                    // see if end of values pass
+                    if (!numberCandidates) {
+                         int iRow;
+                         delete [] candidateList;
+                         delete [] givenDuals;
+                         candidate = -2; // -2 signals end
+                         givenDuals = NULL;
+                         candidateList = NULL;
+                         ifValuesPass = 1;
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              int iPivot = pivotVariable_[iRow];
+                              //assert (fabs(dj_[iPivot]),1.0e-5);
+                              clearPivoted(iPivot);
+                         }
+                    }
+                    if (!normalIteration) {
+                         //rowArray_[0]->cleanAndPackSafe(1.0e-60);
+                         //columnArray_[0]->cleanAndPackSafe(1.0e-60);
+                         updateDualsInValuesPass(rowArray_[0], columnArray_[0], theta_);
+                         if (candidate == -2)
+                              problemStatus_ = -2;
+                         continue; // skip rest of iteration
+                    } else {
+                         // recompute dualOut_
+                         if (directionOut_ < 0) {
+                              dualOut_ = valueOut_ - upperOut_;
+                         } else {
+                              dualOut_ = lowerOut_ - valueOut_;
+                         }
+                    }
+               }
+               if (sequenceIn_ >= 0) {
+                    // normal iteration
+                    // update the incoming column
+                    double btranAlpha = -alpha_ * directionOut_; // for check
+                    unpackPacked(rowArray_[1]);
+                    // moved into updateWeights - factorization_->updateColumnFT(rowArray_[2],rowArray_[1]);
+                    // and update dual weights (can do in parallel - with extra array)
+                    alpha_ = dualRowPivot_->updateWeights(rowArray_[0],
+                                                          rowArray_[2],
+                                                          rowArray_[3],
+                                                          rowArray_[1]);
+                    // see if update stable
+#ifdef CLP_DEBUG
+                    if ((handler_->logLevel() & 32))
+                         printf("btran alpha %g, ftran alpha %g\n", btranAlpha, alpha_);
+#endif
+                    double checkValue = 1.0e-7;
+                    // if can't trust much and long way from optimal then relax
+                    if (largestPrimalError_ > 10.0)
+                         checkValue = CoinMin(1.0e-4, 1.0e-8 * largestPrimalError_);
+                    if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
+                              fabs(btranAlpha - alpha_) > checkValue*(1.0 + fabs(alpha_))) {
+                         handler_->message(CLP_DUAL_CHECK, messages_)
+                                   << btranAlpha
+                                   << alpha_
+                                   << CoinMessageEol;
+                         if (factorization_->pivots()) {
+                              dualRowPivot_->unrollWeights();
+                              problemStatus_ = -2; // factorize now
+                              rowArray_[0]->clear();
+                              rowArray_[1]->clear();
+                              columnArray_[0]->clear();
+                              returnCode = -2;
+                              break;
+                         } else {
+                              // take on more relaxed criterion
+                              double test;
+                              if (fabs(btranAlpha) < 1.0e-8 || fabs(alpha_) < 1.0e-8)
+                                   test = 1.0e-1 * fabs(alpha_);
+                              else
+                                   test = 1.0e-4 * (1.0 + fabs(alpha_));
+                              if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
+                                        fabs(btranAlpha - alpha_) > test) {
+                                   dualRowPivot_->unrollWeights();
+                                   // need to reject something
+                                   char x = isColumn(sequenceOut_) ? 'C' : 'R';
+                                   handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                             << x << sequenceWithin(sequenceOut_)
+                                             << CoinMessageEol;
+#ifdef COIN_DEVELOP
+                                   printf("flag a %g %g\n", btranAlpha, alpha_);
+#endif
+				   //#define FEB_TRY
+#if 1 //def FEB_TRY
+                                   // Make safer?
+                                   factorization_->saferTolerances (-0.99, -1.03);
+#endif
+                                   setFlagged(sequenceOut_);
+                                   progress_.clearBadTimes();
+                                   lastBadIteration_ = numberIterations_; // say be more cautious
+                                   rowArray_[0]->clear();
+                                   rowArray_[1]->clear();
+                                   columnArray_[0]->clear();
+                                   if (fabs(alpha_) < 1.0e-10 && fabs(btranAlpha) < 1.0e-8 && numberIterations_ > 100) {
+                                        //printf("I think should declare infeasible\n");
+                                        problemStatus_ = 1;
+                                        returnCode = 1;
+                                        break;
+                                   }
+                                   continue;
+                              }
+                         }
+                    }
+                    // update duals BEFORE replaceColumn so can do updateColumn
+                    double objectiveChange = 0.0;
+                    // do duals first as variables may flip bounds
+                    // rowArray_[0] and columnArray_[0] may have flips
+                    // so use rowArray_[3] for work array from here on
+                    int nswapped = 0;
+                    //rowArray_[0]->cleanAndPackSafe(1.0e-60);
+                    //columnArray_[0]->cleanAndPackSafe(1.0e-60);
+                    if (candidate == -1) {
+#if CLP_CAN_HAVE_ZERO_OBJ>1
+		    if ((specialOptions_&2097152)==0) {
+#endif
+                         // make sure incoming doesn't count
+                         Status saveStatus = getStatus(sequenceIn_);
+                         setStatus(sequenceIn_, basic);
+                         nswapped = updateDualsInDual(rowArray_[0], columnArray_[0],
+                                                      rowArray_[2], theta_,
+                                                      objectiveChange, false);
+                         setStatus(sequenceIn_, saveStatus);
+#if CLP_CAN_HAVE_ZERO_OBJ>1
+		    } else {
+		      rowArray_[0]->clear();
+		      rowArray_[2]->clear();
+		      columnArray_[0]->clear();
+		    }
+#endif
+                    } else {
+                         updateDualsInValuesPass(rowArray_[0], columnArray_[0], theta_);
+                    }
+                    double oldDualOut = dualOut_;
+                    // which will change basic solution
+                    if (nswapped) {
+                         if (rowArray_[2]->getNumElements()) {
+                              factorization_->updateColumn(rowArray_[3], rowArray_[2]);
+                              dualRowPivot_->updatePrimalSolution(rowArray_[2],
+                                                                  1.0, objectiveChange);
+                         }
+                         // recompute dualOut_
+                         valueOut_ = solution_[sequenceOut_];
+                         if (directionOut_ < 0) {
+                              dualOut_ = valueOut_ - upperOut_;
+                         } else {
+                              dualOut_ = lowerOut_ - valueOut_;
+                         }
+#if 0
+                         if (dualOut_ < 0.0) {
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32) {
+                                   printf(" dualOut_ %g %g save %g\n", dualOut_, averagePrimalInfeasibility, saveDualOut);
+                                   printf("values %g %g %g %g %g %g %g\n", lowerOut_, valueOut_, upperOut_,
+                                          objectiveChange,);
+                              }
+#endif
+                              if (upperOut_ == lowerOut_)
+                                   dualOut_ = 0.0;
+                         }
+                         if(dualOut_ < -CoinMax(1.0e-12 * averagePrimalInfeasibility, 1.0e-8)
+                                   && factorization_->pivots() > 100 &&
+                                   getStatus(sequenceIn_) != isFree) {
+                              // going backwards - factorize
+                              dualRowPivot_->unrollWeights();
+                              problemStatus_ = -2; // factorize now
+                              returnCode = -2;
+                              break;
+                         }
+#endif
+                    }
+                    // amount primal will move
+                    double movement = -dualOut_ * directionOut_ / alpha_;
+                    double movementOld = oldDualOut * directionOut_ / alpha_;
+                    // so objective should increase by fabs(dj)*movement
+                    // but we already have objective change - so check will be good
+                    if (objectiveChange + fabs(movementOld * dualIn_) < -CoinMax(1.0e-5, 1.0e-12 * fabs(objectiveValue_))) {
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("movement %g, swap change %g, rest %g  * %g\n",
+                                     objectiveChange + fabs(movement * dualIn_),
+                                     objectiveChange, movement, dualIn_);
+#endif
+                         if(factorization_->pivots()) {
+                              // going backwards - factorize
+                              dualRowPivot_->unrollWeights();
+                              problemStatus_ = -2; // factorize now
+                              returnCode = -2;
+                              break;
+                         }
+                    }
+                    // if stable replace in basis
+                    int updateStatus = factorization_->replaceColumn(this,
+                                       rowArray_[2],
+                                       rowArray_[1],
+                                       pivotRow_,
+                                       alpha_,
+                                       (moreSpecialOptions_ & 16) != 0,
+                                       acceptablePivot);
+                    // If looks like bad pivot - refactorize
+                    if (fabs(dualOut_) > 1.0e50)
+                         updateStatus = 2;
+                    // if no pivots, bad update but reasonable alpha - take and invert
+                    if (updateStatus == 2 &&
+                              !factorization_->pivots() && fabs(alpha_) > 1.0e-5)
+                         updateStatus = 4;
+                    if (updateStatus == 1 || updateStatus == 4) {
+                         // slight error
+                         if (factorization_->pivots() > 5 || updateStatus == 4) {
+                              problemStatus_ = -2; // factorize now
+                              returnCode = -3;
+                         }
+                    } else if (updateStatus == 2) {
+                         // major error
+                         dualRowPivot_->unrollWeights();
+                         // later we may need to unwind more e.g. fake bounds
+                         if (factorization_->pivots() &&
+                                   ((moreSpecialOptions_ & 16) == 0 || factorization_->pivots() > 4)) {
+                              problemStatus_ = -2; // factorize now
+                              returnCode = -2;
+                              moreSpecialOptions_ |= 16;
+                              break;
+                         } else {
+                              // need to reject something
+                              char x = isColumn(sequenceOut_) ? 'C' : 'R';
+                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                        << x << sequenceWithin(sequenceOut_)
+                                        << CoinMessageEol;
+#ifdef COIN_DEVELOP
+                              printf("flag b %g\n", alpha_);
+#endif
+                              setFlagged(sequenceOut_);
+                              progress_.clearBadTimes();
+                              lastBadIteration_ = numberIterations_; // say be more cautious
+                              rowArray_[0]->clear();
+                              rowArray_[1]->clear();
+                              columnArray_[0]->clear();
+                              // make sure dual feasible
+                              // look at all rows and columns
+                              double objectiveChange = 0.0;
+                              updateDualsInDual(rowArray_[0], columnArray_[0], rowArray_[1],
+                                                0.0, objectiveChange, true);
+                              rowArray_[1]->clear();
+                              columnArray_[0]->clear();
+                              continue;
+                         }
+                    } else if (updateStatus == 3) {
+                         // out of memory
+                         // increase space if not many iterations
+                         if (factorization_->pivots() <
+                                   0.5 * factorization_->maximumPivots() &&
+                                   factorization_->pivots() < 200)
+                              factorization_->areaFactor(
+                                   factorization_->areaFactor() * 1.1);
+                         problemStatus_ = -2; // factorize now
+                    } else if (updateStatus == 5) {
+                         problemStatus_ = -2; // factorize now
+                    }
+                    // update primal solution
+                    if (theta_ < 0.0 && candidate == -1) {
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("negative theta %g\n", theta_);
+#endif
+                         theta_ = 0.0;
+                    }
+                    // do actual flips
+                    flipBounds(rowArray_[0], columnArray_[0]);
+                    //rowArray_[1]->expand();
+                    dualRowPivot_->updatePrimalSolution(rowArray_[1],
+                                                        movement,
+                                                        objectiveChange);
+#ifdef CLP_DEBUG
+                    double oldobj = objectiveValue_;
+#endif
+                    // modify dualout
+                    dualOut_ /= alpha_;
+                    dualOut_ *= -directionOut_;
+                    //setStatus(sequenceIn_,basic);
+                    dj_[sequenceIn_] = 0.0;
+                    double oldValue = valueIn_;
+                    if (directionIn_ == -1) {
+                         // as if from upper bound
+                         valueIn_ = upperIn_ + dualOut_;
+                    } else {
+                         // as if from lower bound
+                         valueIn_ = lowerIn_ + dualOut_;
+                    }
+                    objectiveChange += cost_[sequenceIn_] * (valueIn_ - oldValue);
+                    // outgoing
+                    // set dj to zero unless values pass
+                    if (directionOut_ > 0) {
+                         valueOut_ = lowerOut_;
+                         if (candidate == -1)
+                              dj_[sequenceOut_] = theta_;
+                    } else {
+                         valueOut_ = upperOut_;
+                         if (candidate == -1)
+                              dj_[sequenceOut_] = -theta_;
+                    }
+                    solution_[sequenceOut_] = valueOut_;
+                    int whatNext = housekeeping(objectiveChange);
+#if 0
+		    for (int i=0;i<numberRows_+numberColumns_;i++) {
+		      if (getStatus(i)==atLowerBound) {
+			assert (dj_[i]>-1.0e-5);
+			assert (solution_[i]<=lower_[i]+1.0e-5);
+		      } else if (getStatus(i)==atUpperBound) {
+			assert (dj_[i]<1.0e-5);
+			assert (solution_[i]>=upper_[i]-1.0e-5);
+		      }
+		    }
+#endif
+#ifdef CLP_REPORT_PROGRESS
+                    if (ixxxxxx > ixxyyyy - 5) {
+                         handler_->setLogLevel(63);
+                         int nTotal = numberColumns_ + numberRows_;
+                         double oldObj = 0.0;
+                         double newObj = 0.0;
+                         for (int i = 0; i < nTotal; i++) {
+                              if (savePSol[i])
+                                   oldObj += savePSol[i] * saveCost[i];
+                              if (solution_[i])
+                                   newObj += solution_[i] * cost_[i];
+                              bool printIt = false;
+                              if (cost_[i] != saveCost[i])
+                                   printIt = true;
+                              if (status_[i] != saveStat[i])
+                                   printIt = true;
+                              if (printIt)
+                                   printf("%d old %d cost %g sol %g, new %d cost %g sol %g\n",
+                                          i, saveStat[i], saveCost[i], savePSol[i],
+                                          status_[i], cost_[i], solution_[i]);
+                              // difference
+                              savePSol[i] = solution_[i] - savePSol[i];
+                         }
+                         printf("pivots %d, old obj %g new %g\n",
+                                factorization_->pivots(),
+                                oldObj, newObj);
+                         memset(saveDj, 0, numberRows_ * sizeof(double));
+                         times(1.0, savePSol, saveDj);
+                         double largest = 1.0e-6;
+                         int k = -1;
+                         for (int i = 0; i < numberRows_; i++) {
+                              saveDj[i] -= savePSol[i+numberColumns_];
+                              if (fabs(saveDj[i]) > largest) {
+                                   largest = fabs(saveDj[i]);
+                                   k = i;
+                              }
+                         }
+                         if (k >= 0)
+                              printf("Not null %d %g\n", k, largest);
+                    }
+#endif
+#ifdef VUB
+                    {
+                         if ((sequenceIn_ < numberColumns_ && vub[sequenceIn_] >= 0) || toVub[sequenceIn_] >= 0 ||
+                                   (sequenceOut_ < numberColumns_ && vub[sequenceOut_] >= 0) || toVub[sequenceOut_] >= 0) {
+                              int inSequence = sequenceIn_;
+                              int inVub = -1;
+                              if (sequenceIn_ < numberColumns_)
+                                   inVub = vub[sequenceIn_];
+                              int inBack = toVub[inSequence];
+                              int inSlack = -1;
+                              if (inSequence >= numberColumns_ && inBack >= 0) {
+                                   inSlack = inSequence - numberColumns_;
+                                   inSequence = inBack;
+                                   inBack = toVub[inSequence];
+                              }
+                              if (inVub >= 0)
+                                   printf("Vub %d in ", inSequence);
+                              if (inBack >= 0 && inSlack < 0)
+                                   printf("%d (descendent of %d) in ", inSequence, inBack);
+                              if (inSlack >= 0)
+                                   printf("slack for row %d -> %d (descendent of %d) in ", inSlack, inSequence, inBack);
+                              int outSequence = sequenceOut_;
+                              int outVub = -1;
+                              if (sequenceOut_ < numberColumns_)
+                                   outVub = vub[sequenceOut_];
+                              int outBack = toVub[outSequence];
+                              int outSlack = -1;
+                              if (outSequence >= numberColumns_ && outBack >= 0) {
+                                   outSlack = outSequence - numberColumns_;
+                                   outSequence = outBack;
+                                   outBack = toVub[outSequence];
+                              }
+                              if (outVub >= 0)
+                                   printf("Vub %d out ", outSequence);
+                              if (outBack >= 0 && outSlack < 0)
+                                   printf("%d (descendent of %d) out ", outSequence, outBack);
+                              if (outSlack >= 0)
+                                   printf("slack for row %d -> %d (descendent of %d) out ", outSlack, outSequence, outBack);
+                              printf("\n");
+                         }
+                    }
+#endif
+#if 0
+                    if (numberIterations_ > 206033)
+                         handler_->setLogLevel(63);
+                    if (numberIterations_ > 210567)
+                         exit(77);
+#endif
+                    if (!givenDuals && ifValuesPass && ifValuesPass != 2) {
+                         handler_->message(CLP_END_VALUES_PASS, messages_)
+                                   << numberIterations_;
+                         whatNext = 1;
+                    }
+#ifdef CHECK_ACCURACY
+                    if (whatNext) {
+                         CoinMemcpyN(solution_, (numberRows_ + numberColumns_), zzzzzz);
+                    }
+#endif
+                    //if (numberIterations_==1890)
+                    //whatNext=1;
+                    //if (numberIterations_>2000)
+                    //exit(77);
+                    // and set bounds correctly
+                    originalBound(sequenceIn_);
+                    changeBound(sequenceOut_);
+#ifdef CLP_DEBUG
+                    if (objectiveValue_ < oldobj - 1.0e-5 && (handler_->logLevel() & 16))
+                         printf("obj backwards %g %g\n", objectiveValue_, oldobj);
+#endif
+#if 0
+                    {
+                         for (int i = 0; i < numberRows_ + numberColumns_; i++) {
+                              FakeBound bound = getFakeBound(i);
+                              if (bound == ClpSimplexDual::upperFake) {
+                                   assert (upper_[i] < 1.0e20);
+                              } else if (bound == ClpSimplexDual::lowerFake) {
+                                   assert (lower_[i] > -1.0e20);
+                              } else if (bound == ClpSimplexDual::bothFake) {
+                                   assert (upper_[i] < 1.0e20);
+                                   assert (lower_[i] > -1.0e20);
+                              }
+                         }
+                    }
+#endif
+                    if (whatNext == 1 || candidate == -2) {
+                         problemStatus_ = -2; // refactorize
+                    } else if (whatNext == 2) {
+                         // maximum iterations or equivalent
+                         problemStatus_ = 3;
+                         returnCode = 3;
+                         break;
+                    }
+                    // Check event
+                    {
+                         int status = eventHandler_->event(ClpEventHandler::endOfIteration);
+                         if (status >= 0) {
+                              problemStatus_ = 5;
+                              secondaryStatus_ = ClpEventHandler::endOfIteration;
+                              returnCode = 4;
+                              break;
+                         }
+                    }
+               } else {
+#ifdef CLP_INVESTIGATE_SERIAL
+                    z_thinks = 1;
+#endif
+                    // no incoming column is valid
+		    spareIntArray_[3]=pivotRow_;
+                    pivotRow_ = -1;
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("** no column pivot\n");
+#endif
+                    if (factorization_->pivots() < 2 && acceptablePivot_ <= 1.0e-8) {
+                         //&&goodAccuracy()) {
+                         // If not in branch and bound etc save ray
+                         delete [] ray_;
+                         if ((specialOptions_&(1024 | 4096)) == 0 || (specialOptions_ & 32) != 0) {
+                              // create ray anyway
+#ifdef PRINT_RAY_METHOD
+			   printf("Dual creating infeasibility ray direction out %d - pivRow %d seqOut %d lower %g,val %g,upper %g\n",
+				  directionOut_,spareIntArray_[3],sequenceOut_,lowerOut_,valueOut_,upperOut_);
+#endif
+                              ray_ = new double [ numberRows_];
+                              rowArray_[0]->expand(); // in case packed
+			      const double * array = rowArray_[0]->denseVector();
+			      for (int i=0;i<numberRows_;i++) 
+				ray_[i] = array[i];
+                         } else {
+                              ray_ = NULL;
+                         }
+                         // If we have just factorized and infeasibility reasonable say infeas
+                         double dualTest = ((specialOptions_ & 4096) != 0) ? 1.0e8 : 1.0e13;
+                         if (((specialOptions_ & 4096) != 0 || bestPossiblePivot < 1.0e-11) && dualBound_ > dualTest) {
+                              double testValue = 1.0e-4;
+                              if (!factorization_->pivots() && numberPrimalInfeasibilities_ == 1)
+                                   testValue = 1.0e-6;
+                              if (valueOut_ > upperOut_ + testValue || valueOut_ < lowerOut_ - testValue
+                                        || (specialOptions_ & 64) == 0) {
+                                   // say infeasible
+                                   problemStatus_ = 1;
+                                   // unless primal feasible!!!!
+                                   //printf("%d %g %d %g\n",numberPrimalInfeasibilities_,sumPrimalInfeasibilities_,
+                                   //   numberDualInfeasibilities_,sumDualInfeasibilities_);
+                                   //#define TEST_CLP_NODE
+#ifndef TEST_CLP_NODE
+                                   // Should be correct - but ...
+                                   int numberFake = numberAtFakeBound();
+                                   double sumPrimal =  (!numberFake) ? 2.0e5 : sumPrimalInfeasibilities_;
+                                   if (sumPrimalInfeasibilities_ < 1.0e-3 || sumDualInfeasibilities_ > 1.0e-5 ||
+                                             (sumPrimal < 1.0e5 && (specialOptions_ & 1024) != 0 && factorization_->pivots())) {
+                                        if (sumPrimal > 50.0 && factorization_->pivots() > 2) {
+                                             problemStatus_ = -4;
+#ifdef COIN_DEVELOP
+                                             printf("status to -4 at %d - primalinf %g pivots %d\n",
+                                                    __LINE__, sumPrimalInfeasibilities_,
+                                                    factorization_->pivots());
+#endif
+                                        } else {
+                                             problemStatus_ = 10;
+#if COIN_DEVELOP>1
+                                             printf("returning at %d - primal %d %g - dual %d %g fake %d weight %g - pivs %d - options (1024-16384) %d %d %d %d %d\n",
+                                                    __LINE__, numberPrimalInfeasibilities_,
+                                                    sumPrimalInfeasibilities_,
+                                                    numberDualInfeasibilities_, sumDualInfeasibilities_,
+                                                    numberFake_, dualBound_, factorization_->pivots(),
+                                                    (specialOptions_ & 1024) != 0 ? 1 : 0,
+                                                    (specialOptions_ & 2048) != 0 ? 1 : 0,
+                                                    (specialOptions_ & 4096) != 0 ? 1 : 0,
+                                                    (specialOptions_ & 8192) != 0 ? 1 : 0,
+                                                    (specialOptions_ & 16384) != 0 ? 1 : 0
+                                                   );
+#endif
+                                             // Get rid of objective
+                                             if ((specialOptions_ & 16384) == 0)
+                                                  objective_ = new ClpLinearObjective(NULL, numberColumns_);
+                                        }
+                                   }
+#else
+                                   if (sumPrimalInfeasibilities_ < 1.0e-3 || sumDualInfeasibilities_ > 1.0e-6) {
+#ifdef COIN_DEVELOP
+                                        printf("at %d - primal %d %g - dual %d %g fake %d weight %g - pivs %d\n",
+                                               __LINE__, numberPrimalInfeasibilities_,
+                                               sumPrimalInfeasibilities_,
+                                               numberDualInfeasibilities_, sumDualInfeasibilities_,
+                                               numberFake_, dualBound_, factorization_->pivots());
+#endif
+                                        if ((specialOptions_ & 1024) != 0 && factorization_->pivots()) {
+                                             problemStatus_ = 10;
+#if COIN_DEVELOP>1
+                                             printf("returning at %d\n", __LINE__);
+#endif
+                                             // Get rid of objective
+                                             if ((specialOptions_ & 16384) == 0)
+                                                  objective_ = new ClpLinearObjective(NULL, numberColumns_);
+                                        }
+                                   }
+#endif
+                                   rowArray_[0]->clear();
+                                   columnArray_[0]->clear();
+                                   returnCode = 1;
+                                   break;
+                              }
+                         }
+                         // If special option set - put off as long as possible
+                         if ((specialOptions_ & 64) == 0 || (moreSpecialOptions_ & 64) != 0) {
+                              if (factorization_->pivots() == 0)
+                                   problemStatus_ = -4; //say looks infeasible
+                         } else {
+                              // flag
+                              char x = isColumn(sequenceOut_) ? 'C' : 'R';
+                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                        << x << sequenceWithin(sequenceOut_)
+                                        << CoinMessageEol;
+#ifdef COIN_DEVELOP
+                              printf("flag c\n");
+#endif
+                              setFlagged(sequenceOut_);
+                              if (!factorization_->pivots()) {
+                                   rowArray_[0]->clear();
+                                   columnArray_[0]->clear();
+                                   continue;
+                              }
+                         }
+                    }
+                    if (factorization_->pivots() < 5 && acceptablePivot_ > 1.0e-8)
+                         acceptablePivot_ = 1.0e-8;
+                    rowArray_[0]->clear();
+                    columnArray_[0]->clear();
+                    returnCode = 1;
+                    break;
+               }
+          } else {
+#ifdef CLP_INVESTIGATE_SERIAL
+               z_thinks = 0;
+#endif
+               // no pivot row
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32)
+                    printf("** no row pivot\n");
+#endif
+               // If in branch and bound try and get rid of fixed variables
+               if ((specialOptions_ & 1024) != 0 && CLEAN_FIXED) {
+                    assert (!candidateList);
+                    candidateList = new int[numberRows_];
+                    int iRow;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         int iPivot = pivotVariable_[iRow];
+                         if (flagged(iPivot) || !pivoted(iPivot))
+                              continue;
+                         assert (iPivot < numberColumns_ && lower_[iPivot] == upper_[iPivot]);
+                         candidateList[numberCandidates++] = iRow;
+                    }
+                    // and set first candidate
+                    if (!numberCandidates) {
+                         delete [] candidateList;
+                         candidateList = NULL;
+                         int iRow;
+                         for (iRow = 0; iRow < numberRows_; iRow++) {
+                              int iPivot = pivotVariable_[iRow];
+                              clearPivoted(iPivot);
+                         }
+                    } else {
+                         ifValuesPass = 2;
+                         continue;
+                    }
+               }
+               int numberPivots = factorization_->pivots();
+               bool specialCase;
+               int useNumberFake;
+               returnCode = 0;
+               if (numberPivots <= CoinMax(dontFactorizePivots_, 20) &&
+                         (specialOptions_ & 2048) != 0 && (true || !numberChanged_ || perturbation_ == 101)
+                         && dualBound_ >= 1.0e8) {
+                    specialCase = true;
+                    // as dual bound high - should be okay
+                    useNumberFake = 0;
+               } else {
+                    specialCase = false;
+                    useNumberFake = numberFake_;
+               }
+               if (!numberPivots || specialCase) {
+                    // may have crept through - so may be optimal
+                    // check any flagged variables
+                    int iRow;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         int iPivot = pivotVariable_[iRow];
+                         if (flagged(iPivot))
+                              break;
+                    }
+                    if (iRow < numberRows_ && numberPivots) {
+                         // try factorization
+                         returnCode = -2;
+                    }
+
+                    if (useNumberFake || numberDualInfeasibilities_) {
+                         // may be dual infeasible
+                         if ((specialOptions_ & 1024) == 0)
+                              problemStatus_ = -5;
+                         else if (!useNumberFake && numberPrimalInfeasibilities_
+                                   && !numberPivots)
+                              problemStatus_ = 1;
+                    } else {
+                         if (iRow < numberRows_) {
+#ifdef COIN_DEVELOP
+                              std::cout << "Flagged variables at end - infeasible?" << std::endl;
+                              printf("Probably infeasible - pivot was %g\n", alpha_);
+#endif
+                              //if (fabs(alpha_)<1.0e-4) {
+                              //problemStatus_=1;
+                              //} else {
+#ifdef CLP_DEBUG
+                              abort();
+#endif
+                              //}
+                              problemStatus_ = -5;
+                         } else {
+                              problemStatus_ = 0;
+#ifndef CLP_CHECK_NUMBER_PIVOTS
+#define CLP_CHECK_NUMBER_PIVOTS 10
+#endif
+#if CLP_CHECK_NUMBER_PIVOTS < 20
+                              if (numberPivots > CLP_CHECK_NUMBER_PIVOTS) {
+#ifndef NDEBUG_CLP
+                                   int nTotal = numberRows_ + numberColumns_;
+                                   double * comp = CoinCopyOfArray(solution_, nTotal);
+#endif
+                                   computePrimals(rowActivityWork_, columnActivityWork_);
+#ifndef NDEBUG_CLP
+                                   double largest = 1.0e-5;
+                                   int bad = -1;
+                                   for (int i = 0; i < nTotal; i++) {
+                                        double value = solution_[i];
+                                        double larger = CoinMax(fabs(value), fabs(comp[i]));
+                                        double tol = 1.0e-5 + 1.0e-5 * larger;
+                                        double diff = fabs(value - comp[i]);
+                                        if (diff - tol > largest) {
+                                             bad = i;
+                                             largest = diff - tol;
+                                        }
+                                   }
+                                   if (bad >= 0)
+				     COIN_DETAIL_PRINT(printf("bad %d old %g new %g\n", bad, comp[bad], solution_[bad]));
+#endif
+                                   checkPrimalSolution(rowActivityWork_, columnActivityWork_);
+                                   if (numberPrimalInfeasibilities_) {
+#ifdef CLP_INVESTIGATE
+                                        printf("XXX Infeas ? %d inf summing to %g\n", numberPrimalInfeasibilities_,
+                                               sumPrimalInfeasibilities_);
+#endif
+                                        problemStatus_ = -1;
+                                        returnCode = -2;
+                                   }
+#ifndef NDEBUG_CLP
+                                   memcpy(solution_, comp, nTotal * sizeof(double));
+                                   delete [] comp;
+#endif
+                              }
+#endif
+                              if (!problemStatus_) {
+                                   // make it look OK
+                                   numberPrimalInfeasibilities_ = 0;
+                                   sumPrimalInfeasibilities_ = 0.0;
+                                   numberDualInfeasibilities_ = 0;
+                                   sumDualInfeasibilities_ = 0.0;
+                                   // May be perturbed
+                                   if (perturbation_ == 101 || numberChanged_) {
+                                        numberChanged_ = 0; // Number of variables with changed costs
+                                        perturbation_ = 102; // stop any perturbations
+                                        //double changeCost;
+                                        //changeBounds(1,NULL,changeCost);
+                                        createRim4(false);
+                                        // make sure duals are current
+                                        computeDuals(givenDuals);
+                                        checkDualSolution();
+                                        progress_.modifyObjective(-COIN_DBL_MAX);
+                                        if (numberDualInfeasibilities_) {
+                                             problemStatus_ = 10; // was -3;
+                                        } else {
+                                             computeObjectiveValue(true);
+                                        }
+                                   } else if (numberPivots) {
+                                        computeObjectiveValue(true);
+                                   }
+                                   if (numberPivots < -1000) {
+                                        // objective may be wrong
+                                        objectiveValue_ = innerProduct(cost_, numberColumns_ + numberRows_, solution_);
+                                        objectiveValue_ += objective_->nonlinearOffset();
+                                        objectiveValue_ /= (objectiveScale_ * rhsScale_);
+                                        if ((specialOptions_ & 16384) == 0) {
+                                             // and dual_ may be wrong (i.e. for fixed or basic)
+                                             CoinIndexedVector * arrayVector = rowArray_[1];
+                                             arrayVector->clear();
+                                             int iRow;
+                                             double * array = arrayVector->denseVector();
+                                             /* Use dual_ instead of array
+                                                Even though dual_ is only numberRows_ long this is
+                                                okay as gets permuted to longer rowArray_[2]
+                                             */
+                                             arrayVector->setDenseVector(dual_);
+                                             int * index = arrayVector->getIndices();
+                                             int number = 0;
+                                             for (iRow = 0; iRow < numberRows_; iRow++) {
+                                                  int iPivot = pivotVariable_[iRow];
+                                                  double value = cost_[iPivot];
+                                                  dual_[iRow] = value;
+                                                  if (value) {
+                                                       index[number++] = iRow;
+                                                  }
+                                             }
+                                             arrayVector->setNumElements(number);
+                                             // Extended duals before "updateTranspose"
+                                             matrix_->dualExpanded(this, arrayVector, NULL, 0);
+                                             // Btran basic costs
+                                             rowArray_[2]->clear();
+                                             factorization_->updateColumnTranspose(rowArray_[2], arrayVector);
+                                             // and return vector
+                                             arrayVector->setDenseVector(array);
+                                        }
+                                   }
+                                   sumPrimalInfeasibilities_ = 0.0;
+                              }
+                              if ((specialOptions_&(1024 + 16384)) != 0 && !problemStatus_) {
+                                   CoinIndexedVector * arrayVector = rowArray_[1];
+                                   arrayVector->clear();
+                                   double * rhs = arrayVector->denseVector();
+                                   times(1.0, solution_, rhs);
+#ifdef CHECK_ACCURACY
+                                   bool bad = false;
+#endif
+                                   bool bad2 = false;
+                                   int i;
+                                   for ( i = 0; i < numberRows_; i++) {
+                                        if (rhs[i] < rowLowerWork_[i] - primalTolerance_ ||
+                                                  rhs[i] > rowUpperWork_[i] + primalTolerance_) {
+                                             bad2 = true;
+#ifdef CHECK_ACCURACY
+                                             printf("row %d out of bounds %g, %g correct %g bad %g\n", i,
+                                                    rowLowerWork_[i], rowUpperWork_[i],
+                                                    rhs[i], rowActivityWork_[i]);
+#endif
+                                        } else if (fabs(rhs[i] - rowActivityWork_[i]) > 1.0e-3) {
+#ifdef CHECK_ACCURACY
+                                             bad = true;
+                                             printf("row %d correct %g bad %g\n", i, rhs[i], rowActivityWork_[i]);
+#endif
+                                        }
+                                        rhs[i] = 0.0;
+                                   }
+                                   for ( i = 0; i < numberColumns_; i++) {
+                                        if (solution_[i] < columnLowerWork_[i] - primalTolerance_ ||
+                                                  solution_[i] > columnUpperWork_[i] + primalTolerance_) {
+                                             bad2 = true;
+#ifdef CHECK_ACCURACY
+                                             printf("column %d out of bounds %g, %g correct %g bad %g\n", i,
+                                                    columnLowerWork_[i], columnUpperWork_[i],
+                                                    solution_[i], columnActivityWork_[i]);
+#endif
+                                        }
+                                   }
+                                   if (bad2) {
+                                        problemStatus_ = -3;
+                                        returnCode = -2;
+                                        // Force to re-factorize early next time
+                                        int numberPivots = factorization_->pivots();
+                                        forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
+                                   }
+                              }
+                         }
+                    }
+               } else {
+                    problemStatus_ = -3;
+                    returnCode = -2;
+                    // Force to re-factorize early next time
+                    int numberPivots = factorization_->pivots();
+                    forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
+               }
+               break;
+          }
+     }
+     if (givenDuals) {
+          CoinMemcpyN(dj_, numberRows_ + numberColumns_, givenDuals);
+          // get rid of any values pass array
+          delete [] candidateList;
+     }
+     delete [] dubiousWeights;
+#ifdef CLP_REPORT_PROGRESS
+     if (ixxxxxx > ixxyyyy - 5) {
+          int nTotal = numberColumns_ + numberRows_;
+          double oldObj = 0.0;
+          double newObj = 0.0;
+          for (int i = 0; i < nTotal; i++) {
+               if (savePSol[i])
+                    oldObj += savePSol[i] * saveCost[i];
+               if (solution_[i])
+                    newObj += solution_[i] * cost_[i];
+               bool printIt = false;
+               if (cost_[i] != saveCost[i])
+                    printIt = true;
+               if (status_[i] != saveStat[i])
+                    printIt = true;
+               if (printIt)
+                    printf("%d old %d cost %g sol %g, new %d cost %g sol %g\n",
+                           i, saveStat[i], saveCost[i], savePSol[i],
+                           status_[i], cost_[i], solution_[i]);
+               // difference
+               savePSol[i] = solution_[i] - savePSol[i];
+          }
+          printf("exit pivots %d, old obj %g new %g\n",
+                 factorization_->pivots(),
+                 oldObj, newObj);
+          memset(saveDj, 0, numberRows_ * sizeof(double));
+          times(1.0, savePSol, saveDj);
+          double largest = 1.0e-6;
+          int k = -1;
+          for (int i = 0; i < numberRows_; i++) {
+               saveDj[i] -= savePSol[i+numberColumns_];
+               if (fabs(saveDj[i]) > largest) {
+                    largest = fabs(saveDj[i]);
+                    k = i;
+               }
+          }
+          if (k >= 0)
+               printf("Not null %d %g\n", k, largest);
+     }
+     delete [] savePSol ;
+     delete [] saveDj ;
+     delete [] saveCost ;
+     delete [] saveStat ;
+#endif
+     return returnCode;
+}
+/* The duals are updated by the given arrays.
+   Returns number of infeasibilities.
+   rowArray and columnarray will have flipped
+   The output vector has movement (row length array) */
+int
+ClpSimplexDual::updateDualsInDual(CoinIndexedVector * rowArray,
+                                  CoinIndexedVector * columnArray,
+                                  CoinIndexedVector * outputArray,
+                                  double theta,
+                                  double & objectiveChange,
+                                  bool fullRecompute)
+{
+
+     outputArray->clear();
+
+
+     int numberInfeasibilities = 0;
+     int numberRowInfeasibilities = 0;
+
+     // get a tolerance
+     double tolerance = dualTolerance_;
+     // we can't really trust infeasibilities if there is dual error
+     double error = CoinMin(1.0e-2, largestDualError_);
+     // allow tolerance at least slightly bigger than standard
+     tolerance = tolerance +  error;
+
+     double changeObj = 0.0;
+
+     // Coding is very similar but we can save a bit by splitting
+     // Do rows
+     if (!fullRecompute) {
+          int i;
+          double * COIN_RESTRICT reducedCost = djRegion(0);
+          const double * COIN_RESTRICT lower = lowerRegion(0);
+          const double * COIN_RESTRICT upper = upperRegion(0);
+          const double * COIN_RESTRICT cost = costRegion(0);
+          double * COIN_RESTRICT work;
+          int number;
+          int * COIN_RESTRICT which;
+          const unsigned char * COIN_RESTRICT statusArray = status_ + numberColumns_;
+          assert(rowArray->packedMode());
+          work = rowArray->denseVector();
+          number = rowArray->getNumElements();
+          which = rowArray->getIndices();
+          double multiplier[] = { -1.0, 1.0};
+          for (i = 0; i < number; i++) {
+               int iSequence = which[i];
+               double alphaI = work[i];
+               work[i] = 0.0;
+               int iStatus = (statusArray[iSequence] & 3) - 1;
+               if (iStatus) {
+                    double value = reducedCost[iSequence] - theta * alphaI;
+                    reducedCost[iSequence] = value;
+                    double mult = multiplier[iStatus-1];
+                    value *= mult;
+                    if (value < -tolerance) {
+                         // flipping bounds
+                         double movement = mult * (lower[iSequence] - upper[iSequence]);
+                         which[numberInfeasibilities++] = iSequence;
+#ifndef NDEBUG
+                         if (fabs(movement) >= 1.0e30)
+                              resetFakeBounds(-1000 - iSequence);
+#endif
+#ifdef CLP_DEBUG
+                         if ((handler_->logLevel() & 32))
+                              printf("%d %d, new dj %g, alpha %g, movement %g\n",
+                                     0, iSequence, value, alphaI, movement);
+#endif
+                         changeObj -= movement * cost[iSequence];
+                         outputArray->quickAdd(iSequence, movement);
+                    }
+               }
+          }
+          // Do columns
+          reducedCost = djRegion(1);
+          lower = lowerRegion(1);
+          upper = upperRegion(1);
+          cost = costRegion(1);
+          // set number of infeasibilities in row array
+          numberRowInfeasibilities = numberInfeasibilities;
+          rowArray->setNumElements(numberInfeasibilities);
+          numberInfeasibilities = 0;
+          work = columnArray->denseVector();
+          number = columnArray->getNumElements();
+          which = columnArray->getIndices();
+          if ((moreSpecialOptions_ & 8) != 0) {
+               const unsigned char * COIN_RESTRICT statusArray = status_;
+               for (i = 0; i < number; i++) {
+                    int iSequence = which[i];
+                    double alphaI = work[i];
+                    work[i] = 0.0;
+
+                    int iStatus = (statusArray[iSequence] & 3) - 1;
+                    if (iStatus) {
+                         double value = reducedCost[iSequence] - theta * alphaI;
+                         reducedCost[iSequence] = value;
+                         double mult = multiplier[iStatus-1];
+                         value *= mult;
+                         if (value < -tolerance) {
+                              // flipping bounds
+                              double movement = mult * (upper[iSequence] - lower[iSequence]);
+                              which[numberInfeasibilities++] = iSequence;
+#ifndef NDEBUG
+                              if (fabs(movement) >= 1.0e30)
+                                   resetFakeBounds(-1000 - iSequence);
+#endif
+#ifdef CLP_DEBUG
+                              if ((handler_->logLevel() & 32))
+                                   printf("%d %d, new dj %g, alpha %g, movement %g\n",
+                                          1, iSequence, value, alphaI, movement);
+#endif
+                              changeObj += movement * cost[iSequence];
+                              matrix_->add(this, outputArray, iSequence, movement);
+                         }
+                    }
+               }
+          } else {
+               for (i = 0; i < number; i++) {
+                    int iSequence = which[i];
+                    double alphaI = work[i];
+                    work[i] = 0.0;
+
+                    Status status = getStatus(iSequence);
+                    if (status == atLowerBound) {
+                         double value = reducedCost[iSequence] - theta * alphaI;
+                         reducedCost[iSequence] = value;
+                         double movement = 0.0;
+
+                         if (value < -tolerance) {
+                              // to upper bound
+                              which[numberInfeasibilities++] = iSequence;
+                              movement = upper[iSequence] - lower[iSequence];
+#ifndef NDEBUG
+                              if (fabs(movement) >= 1.0e30)
+                                   resetFakeBounds(-1000 - iSequence);
+#endif
+#ifdef CLP_DEBUG
+                              if ((handler_->logLevel() & 32))
+                                   printf("%d %d, new dj %g, alpha %g, movement %g\n",
+                                          1, iSequence, value, alphaI, movement);
+#endif
+                              changeObj += movement * cost[iSequence];
+                              matrix_->add(this, outputArray, iSequence, movement);
+                         }
+                    } else if (status == atUpperBound) {
+                         double value = reducedCost[iSequence] - theta * alphaI;
+                         reducedCost[iSequence] = value;
+                         double movement = 0.0;
+
+                         if (value > tolerance) {
+                              // to lower bound (if swap)
+                              which[numberInfeasibilities++] = iSequence;
+                              movement = lower[iSequence] - upper[iSequence];
+#ifndef NDEBUG
+                              if (fabs(movement) >= 1.0e30)
+                                   resetFakeBounds(-1000 - iSequence);
+#endif
+#ifdef CLP_DEBUG
+                              if ((handler_->logLevel() & 32))
+                                   printf("%d %d, new dj %g, alpha %g, movement %g\n",
+                                          1, iSequence, value, alphaI, movement);
+#endif
+                              changeObj += movement * cost[iSequence];
+                              matrix_->add(this, outputArray, iSequence, movement);
+                         }
+                    } else if (status == isFree) {
+                         double value = reducedCost[iSequence] - theta * alphaI;
+                         reducedCost[iSequence] = value;
+                    }
+               }
+          }
+     } else  {
+          double * COIN_RESTRICT solution = solutionRegion(0);
+          double * COIN_RESTRICT reducedCost = djRegion(0);
+          const double * COIN_RESTRICT lower = lowerRegion(0);
+          const double * COIN_RESTRICT upper = upperRegion(0);
+          const double * COIN_RESTRICT cost = costRegion(0);
+          int * COIN_RESTRICT which;
+          which = rowArray->getIndices();
+          int iSequence;
+          for (iSequence = 0; iSequence < numberRows_; iSequence++) {
+               double value = reducedCost[iSequence];
+
+               Status status = getStatus(iSequence + numberColumns_);
+               // more likely to be at upper bound ?
+               if (status == atUpperBound) {
+                    double movement = 0.0;
+                    //#define NO_SWAP7
+                    if (value > tolerance) {
+                         // to lower bound (if swap)
+                         // put back alpha
+                         which[numberInfeasibilities++] = iSequence;
+                         movement = lower[iSequence] - upper[iSequence];
+                         changeObj += movement * cost[iSequence];
+                         outputArray->quickAdd(iSequence, -movement);
+#ifndef NDEBUG
+                         if (fabs(movement) >= 1.0e30)
+                              resetFakeBounds(-1000 - iSequence);
+#endif
+#ifndef NO_SWAP7
+                    } else if (value > -tolerance) {
+                         // at correct bound but may swap
+                         FakeBound bound = getFakeBound(iSequence + numberColumns_);
+                         if (bound == ClpSimplexDual::upperFake) {
+                              movement = lower[iSequence] - upper[iSequence];
+#ifndef NDEBUG
+                              if (fabs(movement) >= 1.0e30)
+                                   resetFakeBounds(-1000 - iSequence);
+#endif
+                              setStatus(iSequence + numberColumns_, atLowerBound);
+                              solution[iSequence] = lower[iSequence];
+                              changeObj += movement * cost[iSequence];
+                              //numberFake_--;
+                              //setFakeBound(iSequence+numberColumns_,noFake);
+                         }
+#endif
+                    }
+               } else if (status == atLowerBound) {
+                    double movement = 0.0;
+
+                    if (value < -tolerance) {
+                         // to upper bound
+                         // put back alpha
+                         which[numberInfeasibilities++] = iSequence;
+                         movement = upper[iSequence] - lower[iSequence];
+#ifndef NDEBUG
+                         if (fabs(movement) >= 1.0e30)
+                              resetFakeBounds(-1000 - iSequence);
+#endif
+                         changeObj += movement * cost[iSequence];
+                         outputArray->quickAdd(iSequence, -movement);
+#ifndef NO_SWAP7
+                    } else if (value < tolerance) {
+                         // at correct bound but may swap
+                         FakeBound bound = getFakeBound(iSequence + numberColumns_);
+                         if (bound == ClpSimplexDual::lowerFake) {
+                              movement = upper[iSequence] - lower[iSequence];
+#ifndef NDEBUG
+                              if (fabs(movement) >= 1.0e30)
+                                   resetFakeBounds(-1000 - iSequence);
+#endif
+                              setStatus(iSequence + numberColumns_, atUpperBound);
+                              solution[iSequence] = upper[iSequence];
+                              changeObj += movement * cost[iSequence];
+                              //numberFake_--;
+                              //setFakeBound(iSequence+numberColumns_,noFake);
+                         }
+#endif
+                    }
+               }
+          }
+          // Do columns
+          solution = solutionRegion(1);
+          reducedCost = djRegion(1);
+          lower = lowerRegion(1);
+          upper = upperRegion(1);
+          cost = costRegion(1);
+          // set number of infeasibilities in row array
+          numberRowInfeasibilities = numberInfeasibilities;
+          rowArray->setNumElements(numberInfeasibilities);
+          numberInfeasibilities = 0;
+          which = columnArray->getIndices();
+          for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+               double value = reducedCost[iSequence];
+
+               Status status = getStatus(iSequence);
+               if (status == atLowerBound) {
+                    double movement = 0.0;
+
+                    if (value < -tolerance) {
+                         // to upper bound
+                         // put back alpha
+                         which[numberInfeasibilities++] = iSequence;
+                         movement = upper[iSequence] - lower[iSequence];
+#ifndef NDEBUG
+                         if (fabs(movement) >= 1.0e30)
+                              resetFakeBounds(-1000 - iSequence);
+#endif
+                         changeObj += movement * cost[iSequence];
+                         matrix_->add(this, outputArray, iSequence, movement);
+#ifndef NO_SWAP7
+                    } else if (value < tolerance) {
+                         // at correct bound but may swap
+                         FakeBound bound = getFakeBound(iSequence);
+                         if (bound == ClpSimplexDual::lowerFake) {
+                              movement = upper[iSequence] - lower[iSequence];
+#ifndef NDEBUG
+                              if (fabs(movement) >= 1.0e30)
+                                   resetFakeBounds(-1000 - iSequence);
+#endif
+                              setStatus(iSequence, atUpperBound);
+                              solution[iSequence] = upper[iSequence];
+                              changeObj += movement * cost[iSequence];
+                              //numberFake_--;
+                              //setFakeBound(iSequence,noFake);
+                         }
+#endif
+                    }
+               } else if (status == atUpperBound) {
+                    double movement = 0.0;
+
+                    if (value > tolerance) {
+                         // to lower bound (if swap)
+                         // put back alpha
+                         which[numberInfeasibilities++] = iSequence;
+                         movement = lower[iSequence] - upper[iSequence];
+#ifndef NDEBUG
+                         if (fabs(movement) >= 1.0e30)
+                              resetFakeBounds(-1000 - iSequence);
+#endif
+                         changeObj += movement * cost[iSequence];
+                         matrix_->add(this, outputArray, iSequence, movement);
+#ifndef NO_SWAP7
+                    } else if (value > -tolerance) {
+                         // at correct bound but may swap
+                         FakeBound bound = getFakeBound(iSequence);
+                         if (bound == ClpSimplexDual::upperFake) {
+                              movement = lower[iSequence] - upper[iSequence];
+#ifndef NDEBUG
+                              if (fabs(movement) >= 1.0e30)
+                                   resetFakeBounds(-1000 - iSequence);
+#endif
+                              setStatus(iSequence, atLowerBound);
+                              solution[iSequence] = lower[iSequence];
+                              changeObj += movement * cost[iSequence];
+                              //numberFake_--;
+                              //setFakeBound(iSequence,noFake);
+                         }
+#endif
+                    }
+               }
+          }
+     }
+
+#ifdef CLP_DEBUG
+     if (fullRecompute && numberFake_ && (handler_->logLevel() & 16) != 0)
+          printf("%d fake after full update\n", numberFake_);
+#endif
+     // set number of infeasibilities
+     columnArray->setNumElements(numberInfeasibilities);
+     numberInfeasibilities += numberRowInfeasibilities;
+     if (fullRecompute) {
+          // do actual flips
+          flipBounds(rowArray, columnArray);
+     }
+     objectiveChange += changeObj;
+     return numberInfeasibilities;
+}
+void
+ClpSimplexDual::updateDualsInValuesPass(CoinIndexedVector * rowArray,
+                                        CoinIndexedVector * columnArray,
+                                        double theta)
+{
+
+     // use a tighter tolerance except for all being okay
+     double tolerance = dualTolerance_;
+
+     // Coding is very similar but we can save a bit by splitting
+     // Do rows
+     {
+          int i;
+          double * reducedCost = djRegion(0);
+          double * work;
+          int number;
+          int * which;
+          work = rowArray->denseVector();
+          number = rowArray->getNumElements();
+          which = rowArray->getIndices();
+          for (i = 0; i < number; i++) {
+               int iSequence = which[i];
+               double alphaI = work[i];
+               double value = reducedCost[iSequence] - theta * alphaI;
+               work[i] = 0.0;
+               reducedCost[iSequence] = value;
+
+               Status status = getStatus(iSequence + numberColumns_);
+               // more likely to be at upper bound ?
+               if (status == atUpperBound) {
+
+                    if (value > tolerance)
+                         reducedCost[iSequence] = 0.0;
+               } else if (status == atLowerBound) {
+
+                    if (value < -tolerance) {
+                         reducedCost[iSequence] = 0.0;
+                    }
+               }
+          }
+     }
+     rowArray->setNumElements(0);
+
+     // Do columns
+     {
+          int i;
+          double * reducedCost = djRegion(1);
+          double * work;
+          int number;
+          int * which;
+          work = columnArray->denseVector();
+          number = columnArray->getNumElements();
+          which = columnArray->getIndices();
+
+          for (i = 0; i < number; i++) {
+               int iSequence = which[i];
+               double alphaI = work[i];
+               double value = reducedCost[iSequence] - theta * alphaI;
+               work[i] = 0.0;
+               reducedCost[iSequence] = value;
+
+               Status status = getStatus(iSequence);
+               if (status == atLowerBound) {
+                    if (value < -tolerance)
+                         reducedCost[iSequence] = 0.0;
+               } else if (status == atUpperBound) {
+                    if (value > tolerance)
+                         reducedCost[iSequence] = 0.0;
+               }
+          }
+     }
+     columnArray->setNumElements(0);
+}
+/*
+   Chooses dual pivot row
+   Would be faster with separate region to scan
+   and will have this (with square of infeasibility) when steepest
+   For easy problems we can just choose one of the first rows we look at
+*/
+void
+ClpSimplexDual::dualRow(int alreadyChosen)
+{
+     // get pivot row using whichever method it is
+     int chosenRow = -1;
+#ifdef FORCE_FOLLOW
+     bool forceThis = false;
+     if (!fpFollow && strlen(forceFile)) {
+          fpFollow = fopen(forceFile, "r");
+          assert (fpFollow);
+     }
+     if (fpFollow) {
+          if (numberIterations_ <= force_iteration) {
+               // read to next Clp0102
+               char temp[300];
+               while (fgets(temp, 250, fpFollow)) {
+                    if (strncmp(temp, "Clp0102", 7))
+                         continue;
+                    char cin, cout;
+                    sscanf(temp + 9, "%d%*f%*s%*c%c%d%*s%*c%c%d",
+                           &force_iteration, &cin, &force_in, &cout, &force_out);
+                    if (cin == 'R')
+                         force_in += numberColumns_;
+                    if (cout == 'R')
+                         force_out += numberColumns_;
+                    forceThis = true;
+                    assert (numberIterations_ == force_iteration - 1);
+                    printf("Iteration %d will force %d out and %d in\n",
+                           force_iteration, force_out, force_in);
+                    alreadyChosen = force_out;
+                    break;
+               }
+          } else {
+               // use old
+               forceThis = true;
+          }
+          if (!forceThis) {
+               fclose(fpFollow);
+               fpFollow = NULL;
+               forceFile = "";
+          }
+     }
+#endif
+     //double freeAlpha = 0.0;
+     if (alreadyChosen < 0) {
+          // first see if any free variables and put them in basis
+          int nextFree = nextSuperBasic();
+          //nextFree=-1; //off
+          if (nextFree >= 0) {
+               // unpack vector and find a good pivot
+               unpack(rowArray_[1], nextFree);
+               factorization_->updateColumn(rowArray_[2], rowArray_[1]);
+
+               double * work = rowArray_[1]->denseVector();
+               int number = rowArray_[1]->getNumElements();
+               int * which = rowArray_[1]->getIndices();
+               double bestFeasibleAlpha = 0.0;
+               int bestFeasibleRow = -1;
+               double bestInfeasibleAlpha = 0.0;
+               int bestInfeasibleRow = -1;
+               int i;
+
+               for (i = 0; i < number; i++) {
+                    int iRow = which[i];
+                    double alpha = fabs(work[iRow]);
+                    if (alpha > 1.0e-3) {
+                         int iSequence = pivotVariable_[iRow];
+                         double value = solution_[iSequence];
+                         double lower = lower_[iSequence];
+                         double upper = upper_[iSequence];
+                         double infeasibility = 0.0;
+                         if (value > upper)
+                              infeasibility = value - upper;
+                         else if (value < lower)
+                              infeasibility = lower - value;
+                         if (infeasibility * alpha > bestInfeasibleAlpha && alpha > 1.0e-1) {
+                              if (!flagged(iSequence)) {
+                                   bestInfeasibleAlpha = infeasibility * alpha;
+                                   bestInfeasibleRow = iRow;
+                              }
+                         }
+                         if (alpha > bestFeasibleAlpha && (lower > -1.0e20 || upper < 1.0e20)) {
+                              bestFeasibleAlpha = alpha;
+                              bestFeasibleRow = iRow;
+                         }
+                    }
+               }
+               if (bestInfeasibleRow >= 0)
+                    chosenRow = bestInfeasibleRow;
+               else if (bestFeasibleAlpha > 1.0e-2)
+                    chosenRow = bestFeasibleRow;
+               if (chosenRow >= 0) {
+                    pivotRow_ = chosenRow;
+                    //freeAlpha = work[chosenRow];
+               }
+               rowArray_[1]->clear();
+          }
+     } else {
+          // in values pass
+          chosenRow = alreadyChosen;
+#ifdef FORCE_FOLLOW
+          if(forceThis) {
+               alreadyChosen = -1;
+               chosenRow = -1;
+               for (int i = 0; i < numberRows_; i++) {
+                    if (pivotVariable_[i] == force_out) {
+                         chosenRow = i;
+                         break;
+                    }
+               }
+               assert (chosenRow >= 0);
+          }
+#endif
+          pivotRow_ = chosenRow;
+     }
+     if (chosenRow < 0)
+          pivotRow_ = dualRowPivot_->pivotRow();
+
+     if (pivotRow_ >= 0) {
+          sequenceOut_ = pivotVariable_[pivotRow_];
+          valueOut_ = solution_[sequenceOut_];
+          lowerOut_ = lower_[sequenceOut_];
+          upperOut_ = upper_[sequenceOut_];
+          if (alreadyChosen < 0) {
+               // if we have problems we could try other way and hope we get a
+               // zero pivot?
+               if (valueOut_ > upperOut_) {
+                    directionOut_ = -1;
+                    dualOut_ = valueOut_ - upperOut_;
+               } else if (valueOut_ < lowerOut_) {
+                    directionOut_ = 1;
+                    dualOut_ = lowerOut_ - valueOut_;
+               } else {
+#if 1
+                    // odd (could be free) - it's feasible - go to nearest
+                    if (valueOut_ - lowerOut_ < upperOut_ - valueOut_) {
+                         directionOut_ = 1;
+                         dualOut_ = lowerOut_ - valueOut_;
+                    } else {
+                         directionOut_ = -1;
+                         dualOut_ = valueOut_ - upperOut_;
+                    }
+#else
+                    // odd (could be free) - it's feasible - improve obj
+                    printf("direction from alpha of %g is %d\n",
+                           freeAlpha, freeAlpha > 0.0 ? 1 : -1);
+                    if (valueOut_ - lowerOut_ > 1.0e20)
+                         freeAlpha = 1.0;
+                    else if(upperOut_ - valueOut_ > 1.0e20)
+                         freeAlpha = -1.0;
+                    //if (valueOut_-lowerOut_<upperOut_-valueOut_) {
+                    if (freeAlpha < 0.0) {
+                         directionOut_ = 1;
+                         dualOut_ = lowerOut_ - valueOut_;
+                    } else {
+                         directionOut_ = -1;
+                         dualOut_ = valueOut_ - upperOut_;
+                    }
+                    printf("direction taken %d - bounds %g %g %g\n",
+                           directionOut_, lowerOut_, valueOut_, upperOut_);
+#endif
+               }
+#ifdef CLP_DEBUG
+               assert(dualOut_ >= 0.0);
+#endif
+          } else {
+               // in values pass so just use sign of dj
+               // We don't want to go through any barriers so set dualOut low
+               // free variables will never be here
+               dualOut_ = 1.0e-6;
+               if (dj_[sequenceOut_] > 0.0) {
+                    // this will give a -1 in pivot row (as slacks are -1.0)
+                    directionOut_ = 1;
+               } else {
+                    directionOut_ = -1;
+               }
+          }
+     }
+     return ;
+}
+// Checks if any fake bounds active - if so returns number and modifies
+// dualBound_ and everything.
+// Free variables will be left as free
+// Returns number of bounds changed if >=0
+// Returns -1 if not initialize and no effect
+// Fills in changeVector which can be used to see if unbounded
+// and cost of change vector
+int
+ClpSimplexDual::changeBounds(int initialize,
+                             CoinIndexedVector * outputArray,
+                             double & changeCost)
+{
+     numberFake_ = 0;
+     if (!initialize) {
+          int numberInfeasibilities;
+          double newBound;
+          newBound = 5.0 * dualBound_;
+          numberInfeasibilities = 0;
+          changeCost = 0.0;
+          // put back original bounds and then check
+          createRim1(false);
+          int iSequence;
+          // bounds will get bigger - just look at ones at bounds
+          for (iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
+               double lowerValue = lower_[iSequence];
+               double upperValue = upper_[iSequence];
+               double value = solution_[iSequence];
+               setFakeBound(iSequence, ClpSimplexDual::noFake);
+               switch(getStatus(iSequence)) {
+
+               case basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case isFree:
+               case superBasic:
+                    break;
+               case atUpperBound:
+                    if (fabs(value - upperValue) > primalTolerance_)
+                         numberInfeasibilities++;
+                    break;
+               case atLowerBound:
+                    if (fabs(value - lowerValue) > primalTolerance_)
+                         numberInfeasibilities++;
+                    break;
+               }
+          }
+          // If dual infeasible then carry on
+          if (numberInfeasibilities) {
+               handler_->message(CLP_DUAL_CHECKB, messages_)
+                         << newBound
+                         << CoinMessageEol;
+               int iSequence;
+               for (iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
+                    double lowerValue = lower_[iSequence];
+                    double upperValue = upper_[iSequence];
+                    double newLowerValue;
+                    double newUpperValue;
+                    Status status = getStatus(iSequence);
+                    if (status == atUpperBound ||
+                              status == atLowerBound) {
+                         double value = solution_[iSequence];
+                         if (value - lowerValue <= upperValue - value) {
+                              newLowerValue = CoinMax(lowerValue, value - 0.666667 * newBound);
+                              newUpperValue = CoinMin(upperValue, newLowerValue + newBound);
+                         } else {
+                              newUpperValue = CoinMin(upperValue, value + 0.666667 * newBound);
+                              newLowerValue = CoinMax(lowerValue, newUpperValue - newBound);
+                         }
+                         lower_[iSequence] = newLowerValue;
+                         upper_[iSequence] = newUpperValue;
+                         if (newLowerValue > lowerValue) {
+                              if (newUpperValue < upperValue) {
+                                   setFakeBound(iSequence, ClpSimplexDual::bothFake);
+#ifdef CLP_INVESTIGATE
+                                   abort(); // No idea what should happen here - I have never got here
+#endif
+                                   numberFake_++;
+                              } else {
+                                   setFakeBound(iSequence, ClpSimplexDual::lowerFake);
+                                   numberFake_++;
+                              }
+                         } else {
+                              if (newUpperValue < upperValue) {
+                                   setFakeBound(iSequence, ClpSimplexDual::upperFake);
+                                   numberFake_++;
+                              }
+                         }
+                         if (status == atUpperBound)
+                              solution_[iSequence] = newUpperValue;
+                         else
+                              solution_[iSequence] = newLowerValue;
+                         double movement = solution_[iSequence] - value;
+                         if (movement && outputArray) {
+                              if (iSequence >= numberColumns_) {
+                                   outputArray->quickAdd(iSequence, -movement);
+                                   changeCost += movement * cost_[iSequence];
+                              } else {
+                                   matrix_->add(this, outputArray, iSequence, movement);
+                                   changeCost += movement * cost_[iSequence];
+                              }
+                         }
+                    }
+               }
+               dualBound_ = newBound;
+          } else {
+               numberInfeasibilities = -1;
+          }
+          return numberInfeasibilities;
+     } else if (initialize == 1 || initialize == 3) {
+          int iSequence;
+          if (initialize == 3) {
+               for (iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
+                    setFakeBound(iSequence, ClpSimplexDual::noFake);
+               }
+          }
+          double testBound = 0.999999 * dualBound_;
+          for (iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
+               Status status = getStatus(iSequence);
+               if (status == atUpperBound ||
+                         status == atLowerBound) {
+                    double lowerValue = lower_[iSequence];
+                    double upperValue = upper_[iSequence];
+                    double value = solution_[iSequence];
+                    if (lowerValue > -largeValue_ || upperValue < largeValue_) {
+                         if (true || lowerValue - value > -0.5 * dualBound_ ||
+                                   upperValue - value < 0.5 * dualBound_) {
+                              if (fabs(lowerValue - value) <= fabs(upperValue - value)) {
+                                   if (upperValue > lowerValue + testBound) {
+                                        if (getFakeBound(iSequence) == ClpSimplexDual::noFake)
+                                             numberFake_++;
+                                        upper_[iSequence] = lowerValue + dualBound_;
+                                        setFakeBound(iSequence, ClpSimplexDual::upperFake);
+                                   }
+                              } else {
+                                   if (lowerValue < upperValue - testBound) {
+                                        if (getFakeBound(iSequence) == ClpSimplexDual::noFake)
+                                             numberFake_++;
+                                        lower_[iSequence] = upperValue - dualBound_;
+                                        setFakeBound(iSequence, ClpSimplexDual::lowerFake);
+                                   }
+                              }
+                         } else {
+                              if (getFakeBound(iSequence) == ClpSimplexDual::noFake)
+                                   numberFake_++;
+                              lower_[iSequence] = -0.5 * dualBound_;
+                              upper_[iSequence] = 0.5 * dualBound_;
+                              setFakeBound(iSequence, ClpSimplexDual::bothFake);
+                              abort();
+                         }
+                         if (status == atUpperBound)
+                              solution_[iSequence] = upper_[iSequence];
+                         else
+                              solution_[iSequence] = lower_[iSequence];
+                    } else {
+                         // set non basic free variables to fake bounds
+                         // I don't think we should ever get here
+                         CoinAssert(!("should not be here"));
+                         lower_[iSequence] = -0.5 * dualBound_;
+                         upper_[iSequence] = 0.5 * dualBound_;
+                         setFakeBound(iSequence, ClpSimplexDual::bothFake);
+                         numberFake_++;
+                         setStatus(iSequence, atUpperBound);
+                         solution_[iSequence] = 0.5 * dualBound_;
+                    }
+               } else if (status == basic) {
+                    // make sure not at fake bound and bounds correct
+                    setFakeBound(iSequence, ClpSimplexDual::noFake);
+                    double gap = upper_[iSequence] - lower_[iSequence];
+                    if (gap > 0.5 * dualBound_ && gap < 2.0 * dualBound_) {
+                         if (iSequence < numberColumns_) {
+                              if (columnScale_) {
+                                   double multiplier = rhsScale_ * inverseColumnScale_[iSequence];
+                                   // lower
+                                   double value = columnLower_[iSequence];
+                                   if (value > -1.0e30) {
+                                        value *= multiplier;
+                                   }
+                                   lower_[iSequence] = value;
+                                   // upper
+                                   value = columnUpper_[iSequence];
+                                   if (value < 1.0e30) {
+                                        value *= multiplier;
+                                   }
+                                   upper_[iSequence] = value;
+                              } else {
+                                   lower_[iSequence] = columnLower_[iSequence];;
+                                   upper_[iSequence] = columnUpper_[iSequence];;
+                              }
+                         } else {
+                              int iRow = iSequence - numberColumns_;
+                              if (rowScale_) {
+                                   // lower
+                                   double multiplier = rhsScale_ * rowScale_[iRow];
+                                   double value = rowLower_[iRow];
+                                   if (value > -1.0e30) {
+                                        value *= multiplier;
+                                   }
+                                   lower_[iSequence] = value;
+                                   // upper
+                                   value = rowUpper_[iRow];
+                                   if (value < 1.0e30) {
+                                        value *= multiplier;
+                                   }
+                                   upper_[iSequence] = value;
+                              } else {
+                                   lower_[iSequence] = rowLower_[iRow];;
+                                   upper_[iSequence] = rowUpper_[iRow];;
+                              }
+                         }
+                    }
+               }
+          }
+
+          return 1;
+     } else {
+          // just reset changed ones
+          if (columnScale_) {
+               int iSequence;
+               for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+                    FakeBound fakeStatus = getFakeBound(iSequence);
+                    if (fakeStatus != noFake) {
+                         if ((static_cast<int> (fakeStatus) & 1) != 0) {
+                              // lower
+                              double value = columnLower_[iSequence];
+                              if (value > -1.0e30) {
+                                   double multiplier = rhsScale_ * inverseColumnScale_[iSequence];
+                                   value *= multiplier;
+                              }
+                              columnLowerWork_[iSequence] = value;
+                         }
+                         if ((static_cast<int> (fakeStatus) & 2) != 0) {
+                              // upper
+                              double value = columnUpper_[iSequence];
+                              if (value < 1.0e30) {
+                                   double multiplier = rhsScale_ * inverseColumnScale_[iSequence];
+                                   value *= multiplier;
+                              }
+                              columnUpperWork_[iSequence] = value;
+                         }
+                    }
+               }
+               for (iSequence = 0; iSequence < numberRows_; iSequence++) {
+                    FakeBound fakeStatus = getFakeBound(iSequence + numberColumns_);
+                    if (fakeStatus != noFake) {
+                         if ((static_cast<int> (fakeStatus) & 1) != 0) {
+                              // lower
+                              double value = rowLower_[iSequence];
+                              if (value > -1.0e30) {
+                                   double multiplier = rhsScale_ * rowScale_[iSequence];
+                                   value *= multiplier;
+                              }
+                              rowLowerWork_[iSequence] = value;
+                         }
+                         if ((static_cast<int> (fakeStatus) & 2) != 0) {
+                              // upper
+                              double value = rowUpper_[iSequence];
+                              if (value < 1.0e30) {
+                                   double multiplier = rhsScale_ * rowScale_[iSequence];
+                                   value *= multiplier;
+                              }
+                              rowUpperWork_[iSequence] = value;
+                         }
+                    }
+               }
+          } else {
+               int iSequence;
+               for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+                    FakeBound fakeStatus = getFakeBound(iSequence);
+                    if ((static_cast<int> (fakeStatus) & 1) != 0) {
+                         // lower
+                         columnLowerWork_[iSequence] = columnLower_[iSequence];
+                    }
+                    if ((static_cast<int> (fakeStatus) & 2) != 0) {
+                         // upper
+                         columnUpperWork_[iSequence] = columnUpper_[iSequence];
+                    }
+               }
+               for (iSequence = 0; iSequence < numberRows_; iSequence++) {
+                    FakeBound fakeStatus = getFakeBound(iSequence + numberColumns_);
+                    if ((static_cast<int> (fakeStatus) & 1) != 0) {
+                         // lower
+                         rowLowerWork_[iSequence] = rowLower_[iSequence];
+                    }
+                    if ((static_cast<int> (fakeStatus) & 2) != 0) {
+                         // upper
+                         rowUpperWork_[iSequence] = rowUpper_[iSequence];
+                    }
+               }
+          }
+          return 0;
+     }
+}
+int
+ClpSimplexDual::dualColumn0(const CoinIndexedVector * rowArray,
+                            const CoinIndexedVector * columnArray,
+                            CoinIndexedVector * spareArray,
+                            double acceptablePivot,
+                            double & upperReturn, double &bestReturn, double & badFree)
+{
+     // do first pass to get possibles
+     double * spare = spareArray->denseVector();
+     int * index = spareArray->getIndices();
+     const double * work;
+     int number;
+     const int * which;
+     const double * reducedCost;
+     // We can also see if infeasible or pivoting on free
+     double tentativeTheta = 1.0e15;
+     double upperTheta = 1.0e31;
+     double freePivot = acceptablePivot;
+     double bestPossible = 0.0;
+     int numberRemaining = 0;
+     int i;
+     badFree = 0.0;
+     if ((moreSpecialOptions_ & 8) != 0) {
+          // No free or super basic
+          double multiplier[] = { -1.0, 1.0};
+          double dualT = - dualTolerance_;
+          for (int iSection = 0; iSection < 2; iSection++) {
+
+               int addSequence;
+               unsigned char * statusArray;
+               if (!iSection) {
+                    work = rowArray->denseVector();
+                    number = rowArray->getNumElements();
+                    which = rowArray->getIndices();
+                    reducedCost = rowReducedCost_;
+                    addSequence = numberColumns_;
+                    statusArray = status_ + numberColumns_;
+               } else {
+                    work = columnArray->denseVector();
+                    number = columnArray->getNumElements();
+                    which = columnArray->getIndices();
+                    reducedCost = reducedCostWork_;
+                    addSequence = 0;
+                    statusArray = status_;
+               }
+
+               for (i = 0; i < number; i++) {
+                    int iSequence = which[i];
+                    double alpha;
+                    double oldValue;
+                    double value;
+
+                    assert (getStatus(iSequence + addSequence) != isFree
+                            && getStatus(iSequence + addSequence) != superBasic);
+                    int iStatus = (statusArray[iSequence] & 3) - 1;
+                    if (iStatus) {
+                         double mult = multiplier[iStatus-1];
+                         alpha = work[i] * mult;
+                         if (alpha > 0.0) {
+                              oldValue = reducedCost[iSequence] * mult;
+                              value = oldValue - tentativeTheta * alpha;
+                              if (value < dualT) {
+                                   bestPossible = CoinMax(bestPossible, alpha);
+                                   value = oldValue - upperTheta * alpha;
+                                   if (value < dualT && alpha >= acceptablePivot) {
+                                        upperTheta = (oldValue - dualT) / alpha;
+                                        //tentativeTheta = CoinMin(2.0*upperTheta,tentativeTheta);
+                                   }
+                                   // add to list
+                                   spare[numberRemaining] = alpha * mult;
+                                   index[numberRemaining++] = iSequence + addSequence;
+                              }
+                         }
+                    }
+               }
+          }
+     } else {
+          // some free or super basic
+          for (int iSection = 0; iSection < 2; iSection++) {
+
+               int addSequence;
+
+               if (!iSection) {
+                    work = rowArray->denseVector();
+                    number = rowArray->getNumElements();
+                    which = rowArray->getIndices();
+                    reducedCost = rowReducedCost_;
+                    addSequence = numberColumns_;
+               } else {
+                    work = columnArray->denseVector();
+                    number = columnArray->getNumElements();
+                    which = columnArray->getIndices();
+                    reducedCost = reducedCostWork_;
+                    addSequence = 0;
+               }
+
+               for (i = 0; i < number; i++) {
+                    int iSequence = which[i];
+                    double alpha;
+                    double oldValue;
+                    double value;
+                    bool keep;
+
+                    switch(getStatus(iSequence + addSequence)) {
+
+                    case basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case isFree:
+                    case superBasic:
+                         alpha = work[i];
+                         bestPossible = CoinMax(bestPossible, fabs(alpha));
+                         oldValue = reducedCost[iSequence];
+                         // If free has to be very large - should come in via dualRow
+                         //if (getStatus(iSequence+addSequence)==isFree&&fabs(alpha)<1.0e-3)
+                         //break;
+                         if (oldValue > dualTolerance_) {
+                              keep = true;
+                         } else if (oldValue < -dualTolerance_) {
+                              keep = true;
+                         } else {
+                              if (fabs(alpha) > CoinMax(10.0 * acceptablePivot, 1.0e-5)) {
+                                   keep = true;
+                              } else {
+                                   keep = false;
+                                   badFree = CoinMax(badFree, fabs(alpha));
+                              }
+                         }
+                         if (keep) {
+                              // free - choose largest
+                              if (fabs(alpha) > freePivot) {
+                                   freePivot = fabs(alpha);
+                                   sequenceIn_ = iSequence + addSequence;
+                                   theta_ = oldValue / alpha;
+                                   alpha_ = alpha;
+                              }
+                         }
+                         break;
+                    case atUpperBound:
+                         alpha = work[i];
+                         oldValue = reducedCost[iSequence];
+                         value = oldValue - tentativeTheta * alpha;
+                         //assert (oldValue<=dualTolerance_*1.0001);
+                         if (value > dualTolerance_) {
+                              bestPossible = CoinMax(bestPossible, -alpha);
+                              value = oldValue - upperTheta * alpha;
+                              if (value > dualTolerance_ && -alpha >= acceptablePivot) {
+                                   upperTheta = (oldValue - dualTolerance_) / alpha;
+                                   //tentativeTheta = CoinMin(2.0*upperTheta,tentativeTheta);
+                              }
+                              // add to list
+                              spare[numberRemaining] = alpha;
+                              index[numberRemaining++] = iSequence + addSequence;
+                         }
+                         break;
+                    case atLowerBound:
+                         alpha = work[i];
+                         oldValue = reducedCost[iSequence];
+                         value = oldValue - tentativeTheta * alpha;
+                         //assert (oldValue>=-dualTolerance_*1.0001);
+                         if (value < -dualTolerance_) {
+                              bestPossible = CoinMax(bestPossible, alpha);
+                              value = oldValue - upperTheta * alpha;
+                              if (value < -dualTolerance_ && alpha >= acceptablePivot) {
+                                   upperTheta = (oldValue + dualTolerance_) / alpha;
+                                   //tentativeTheta = CoinMin(2.0*upperTheta,tentativeTheta);
+                              }
+                              // add to list
+                              spare[numberRemaining] = alpha;
+                              index[numberRemaining++] = iSequence + addSequence;
+                         }
+                         break;
+                    }
+               }
+          }
+     }
+     upperReturn = upperTheta;
+     bestReturn = bestPossible;
+     return numberRemaining;
+}
+/*
+   Row array has row part of pivot row (as duals so sign may be switched)
+   Column array has column part.
+   This chooses pivot column.
+   Spare array will be needed when we start getting clever.
+   We will check for basic so spare array will never overflow.
+   If necessary will modify costs
+*/
+double
+ClpSimplexDual::dualColumn(CoinIndexedVector * rowArray,
+                           CoinIndexedVector * columnArray,
+                           CoinIndexedVector * spareArray,
+                           CoinIndexedVector * spareArray2,
+                           double acceptablePivot,
+                           CoinBigIndex * /*dubiousWeights*/)
+{
+     int numberPossiblySwapped = 0;
+     int numberRemaining = 0;
+
+     double totalThru = 0.0; // for when variables flip
+     //double saveAcceptable=acceptablePivot;
+     //acceptablePivot=1.0e-9;
+
+     double bestEverPivot = acceptablePivot;
+     int lastSequence = -1;
+     double lastPivot = 0.0;
+     double upperTheta;
+     double newTolerance = dualTolerance_;
+     //newTolerance = dualTolerance_+1.0e-6*dblParam_[ClpDualTolerance];
+     // will we need to increase tolerance
+     //bool thisIncrease = false;
+     // If we think we need to modify costs (not if something from broad sweep)
+     bool modifyCosts = false;
+     // Increase in objective due to swapping bounds (may be negative)
+     double increaseInObjective = 0.0;
+
+     // use spareArrays to put ones looked at in
+     // we are going to flip flop between
+     int iFlip = 0;
+     // Possible list of pivots
+     int interesting[2];
+     // where possible swapped ones are
+     int swapped[2];
+     // for zeroing out arrays after
+     int marker[2][2];
+     // pivot elements
+     double * array[2], * spare, * spare2;
+     // indices
+     int * indices[2], * index, * index2;
+     spareArray2->clear();
+     array[0] = spareArray->denseVector();
+     indices[0] = spareArray->getIndices();
+     spare = array[0];
+     index = indices[0];
+     array[1] = spareArray2->denseVector();
+     indices[1] = spareArray2->getIndices();
+     int i;
+
+     // initialize lists
+     for (i = 0; i < 2; i++) {
+          interesting[i] = 0;
+          swapped[i] = numberColumns_;
+          marker[i][0] = 0;
+          marker[i][1] = numberColumns_;
+     }
+     /*
+       First we get a list of possible pivots.  We can also see if the
+       problem looks infeasible or whether we want to pivot in free variable.
+       This may make objective go backwards but can only happen a finite
+       number of times and I do want free variables basic.
+
+       Then we flip back and forth.  At the start of each iteration
+       interesting[iFlip] should have possible candidates and swapped[iFlip]
+       will have pivots if we decide to take a previous pivot.
+       At end of each iteration interesting[1-iFlip] should have
+       candidates if we go through this theta and swapped[1-iFlip]
+       pivots if we don't go through.
+
+       At first we increase theta and see what happens.  We start
+       theta at a reasonable guess.  If in right area then we do bit by bit.
+
+      */
+
+     // do first pass to get possibles
+     upperTheta = 1.0e31;
+     double bestPossible = 0.0;
+     double badFree = 0.0;
+     alpha_ = 0.0;
+     if (spareIntArray_[0] >= 0) {
+          numberRemaining = dualColumn0(rowArray, columnArray, spareArray,
+                                        acceptablePivot, upperTheta, bestPossible, badFree);
+     } else {
+          // already done
+          numberRemaining = spareArray->getNumElements();
+          spareArray->setNumElements(0);
+          upperTheta = spareDoubleArray_[0];
+          bestPossible = spareDoubleArray_[1];
+          if (spareIntArray_[0] == -1) {
+               theta_ = spareDoubleArray_[2];
+               alpha_ = spareDoubleArray_[3];
+               sequenceIn_ = spareIntArray_[1];
+          } else {
+#if 0
+               int n = numberRemaining;
+               double u = upperTheta;
+               double b = bestPossible;
+               upperTheta = 1.0e31;
+               bestPossible = 0.0;
+               numberRemaining = dualColumn0(rowArray, columnArray, spareArray,
+                                             acceptablePivot, upperTheta, bestPossible, badFree);
+               assert (n == numberRemaining);
+               assert (fabs(b - bestPossible) < 1.0e-7);
+               assert (fabs(u - upperTheta) < 1.0e-7);
+#endif
+          }
+     }
+     // switch off
+     spareIntArray_[0] = 0;
+     // We can also see if infeasible or pivoting on free
+     double tentativeTheta = 1.0e25;
+     interesting[0] = numberRemaining;
+     marker[0][0] = numberRemaining;
+
+     if (!numberRemaining && sequenceIn_ < 0)
+          return 0.0; // Looks infeasible
+
+     // If sum of bad small pivots too much
+#define MORE_CAREFUL
+#ifdef MORE_CAREFUL
+     bool badSumPivots = false;
+#endif
+     if (sequenceIn_ >= 0) {
+          // free variable - always choose
+     } else {
+
+          theta_ = 1.0e50;
+          // now flip flop between spare arrays until reasonable theta
+          tentativeTheta = CoinMax(10.0 * upperTheta, 1.0e-7);
+
+          // loops increasing tentative theta until can't go through
+
+          while (tentativeTheta < 1.0e22) {
+               double thruThis = 0.0;
+
+               double bestPivot = acceptablePivot;
+               int bestSequence = -1;
+
+               numberPossiblySwapped = numberColumns_;
+               numberRemaining = 0;
+
+               upperTheta = 1.0e50;
+
+               spare = array[iFlip];
+               index = indices[iFlip];
+               spare2 = array[1-iFlip];
+               index2 = indices[1-iFlip];
+
+               // try 3 different ways
+               // 1 bias increase by ones with slightly wrong djs
+               // 2 bias by all
+               // 3 bias by all - tolerance
+#define TRYBIAS 3
+
+
+               double increaseInThis = 0.0; //objective increase in this loop
+
+               for (i = 0; i < interesting[iFlip]; i++) {
+                    int iSequence = index[i];
+                    double alpha = spare[i];
+                    double oldValue = dj_[iSequence];
+                    double value = oldValue - tentativeTheta * alpha;
+
+                    if (alpha < 0.0) {
+                         //at upper bound
+                         if (value > newTolerance) {
+                              double range = upper_[iSequence] - lower_[iSequence];
+                              thruThis -= range * alpha;
+#if TRYBIAS==1
+                              if (oldValue > 0.0)
+                                   increaseInThis -= oldValue * range;
+#elif TRYBIAS==2
+                              increaseInThis -= oldValue * range;
+#else
+                              increaseInThis -= (oldValue + dualTolerance_) * range;
+#endif
+                              // goes on swapped list (also means candidates if too many)
+                              spare2[--numberPossiblySwapped] = alpha;
+                              index2[numberPossiblySwapped] = iSequence;
+                              if (fabs(alpha) > bestPivot) {
+                                   bestPivot = fabs(alpha);
+                                   bestSequence = numberPossiblySwapped;
+                              }
+                         } else {
+                              value = oldValue - upperTheta * alpha;
+                              if (value > newTolerance && -alpha >= acceptablePivot)
+                                   upperTheta = (oldValue - newTolerance) / alpha;
+                              spare2[numberRemaining] = alpha;
+                              index2[numberRemaining++] = iSequence;
+                         }
+                    } else {
+                         // at lower bound
+                         if (value < -newTolerance) {
+                              double range = upper_[iSequence] - lower_[iSequence];
+                              thruThis += range * alpha;
+                              //?? is this correct - and should we look at good ones
+#if TRYBIAS==1
+                              if (oldValue < 0.0)
+                                   increaseInThis += oldValue * range;
+#elif TRYBIAS==2
+                              increaseInThis += oldValue * range;
+#else
+                              increaseInThis += (oldValue - dualTolerance_) * range;
+#endif
+                              // goes on swapped list (also means candidates if too many)
+                              spare2[--numberPossiblySwapped] = alpha;
+                              index2[numberPossiblySwapped] = iSequence;
+                              if (fabs(alpha) > bestPivot) {
+                                   bestPivot = fabs(alpha);
+                                   bestSequence = numberPossiblySwapped;
+                              }
+                         } else {
+                              value = oldValue - upperTheta * alpha;
+                              if (value < -newTolerance && alpha >= acceptablePivot)
+                                   upperTheta = (oldValue + newTolerance) / alpha;
+                              spare2[numberRemaining] = alpha;
+                              index2[numberRemaining++] = iSequence;
+                         }
+                    }
+               }
+               swapped[1-iFlip] = numberPossiblySwapped;
+               interesting[1-iFlip] = numberRemaining;
+               marker[1-iFlip][0] = CoinMax(marker[1-iFlip][0], numberRemaining);
+               marker[1-iFlip][1] = CoinMin(marker[1-iFlip][1], numberPossiblySwapped);
+
+               if (totalThru + thruThis >= fabs(dualOut_) ||
+                         increaseInObjective + increaseInThis < 0.0) {
+                    // We should be pivoting in this batch
+                    // so compress down to this lot
+                    numberRemaining = 0;
+                    for (i = numberColumns_ - 1; i >= swapped[1-iFlip]; i--) {
+                         spare[numberRemaining] = spare2[i];
+                         index[numberRemaining++] = index2[i];
+                    }
+                    interesting[iFlip] = numberRemaining;
+                    int iTry;
+#define MAXTRY 100
+                    // first get ratio with tolerance
+                    for (iTry = 0; iTry < MAXTRY; iTry++) {
+
+                         upperTheta = 1.0e50;
+                         numberPossiblySwapped = numberColumns_;
+                         numberRemaining = 0;
+
+                         increaseInThis = 0.0; //objective increase in this loop
+
+                         thruThis = 0.0;
+
+                         spare = array[iFlip];
+                         index = indices[iFlip];
+                         spare2 = array[1-iFlip];
+                         index2 = indices[1-iFlip];
+                         for (i = 0; i < interesting[iFlip]; i++) {
+                              int iSequence = index[i];
+                              double alpha = spare[i];
+                              double oldValue = dj_[iSequence];
+                              double value = oldValue - upperTheta * alpha;
+
+                              if (alpha < 0.0) {
+                                   //at upper bound
+                                   if (value > newTolerance) {
+                                        if (-alpha >= acceptablePivot) {
+                                             upperTheta = (oldValue - newTolerance) / alpha;
+                                        }
+                                   }
+                              } else {
+                                   // at lower bound
+                                   if (value < -newTolerance) {
+                                        if (alpha >= acceptablePivot) {
+                                             upperTheta = (oldValue + newTolerance) / alpha;
+                                        }
+                                   }
+                              }
+                         }
+                         bestPivot = acceptablePivot;
+                         sequenceIn_ = -1;
+#ifdef DUBIOUS_WEIGHTS
+                         double bestWeight = COIN_DBL_MAX;
+#endif
+                         double largestPivot = acceptablePivot;
+                         // now choose largest and sum all ones which will go through
+                         //printf("XX it %d number %d\n",numberIterations_,interesting[iFlip]);
+                         // Sum of bad small pivots
+#ifdef MORE_CAREFUL
+                         double sumBadPivots = 0.0;
+                         badSumPivots = false;
+#endif
+                         // Make sure upperTheta will work (-O2 and above gives problems)
+                         upperTheta *= 1.0000000001;
+                         for (i = 0; i < interesting[iFlip]; i++) {
+                              int iSequence = index[i];
+                              double alpha = spare[i];
+                              double value = dj_[iSequence] - upperTheta * alpha;
+                              double badDj = 0.0;
+
+                              bool addToSwapped = false;
+
+                              if (alpha < 0.0) {
+                                   //at upper bound
+                                   if (value >= 0.0) {
+                                        addToSwapped = true;
+#if TRYBIAS==1
+                                        badDj = -CoinMax(dj_[iSequence], 0.0);
+#elif TRYBIAS==2
+                                        badDj = -dj_[iSequence];
+#else
+                                        badDj = -dj_[iSequence] - dualTolerance_;
+#endif
+                                   }
+                              } else {
+                                   // at lower bound
+                                   if (value <= 0.0) {
+                                        addToSwapped = true;
+#if TRYBIAS==1
+                                        badDj = CoinMin(dj_[iSequence], 0.0);
+#elif TRYBIAS==2
+                                        badDj = dj_[iSequence];
+#else
+                                        badDj = dj_[iSequence] - dualTolerance_;
+#endif
+                                   }
+                              }
+                              if (!addToSwapped) {
+                                   // add to list of remaining
+                                   spare2[numberRemaining] = alpha;
+                                   index2[numberRemaining++] = iSequence;
+                              } else {
+                                   // add to list of swapped
+                                   spare2[--numberPossiblySwapped] = alpha;
+                                   index2[numberPossiblySwapped] = iSequence;
+                                   // select if largest pivot
+                                   bool take = false;
+                                   double absAlpha = fabs(alpha);
+#ifdef DUBIOUS_WEIGHTS
+                                   // User could do anything to break ties here
+                                   double weight;
+                                   if (dubiousWeights)
+                                        weight = dubiousWeights[iSequence];
+                                   else
+                                        weight = 1.0;
+                                   weight += randomNumberGenerator_.randomDouble() * 1.0e-2;
+                                   if (absAlpha > 2.0 * bestPivot) {
+                                        take = true;
+                                   } else if (absAlpha > largestPivot) {
+                                        // could multiply absAlpha and weight
+                                        if (weight * bestPivot < bestWeight * absAlpha)
+                                             take = true;
+                                   }
+#else
+                                   if (absAlpha > bestPivot)
+                                        take = true;
+#endif
+#ifdef MORE_CAREFUL
+                                   if (absAlpha < acceptablePivot && upperTheta < 1.0e20) {
+                                        if (alpha < 0.0) {
+                                             //at upper bound
+                                             if (value > dualTolerance_) {
+                                                  double gap = upper_[iSequence] - lower_[iSequence];
+                                                  if (gap < 1.0e20)
+                                                       sumBadPivots += value * gap;
+                                                  else
+                                                       sumBadPivots += 1.0e20;
+                                                  //printf("bad %d alpha %g dj at upper %g\n",
+                                                  //     iSequence,alpha,value);
+                                             }
+                                        } else {
+                                             //at lower bound
+                                             if (value < -dualTolerance_) {
+                                                  double gap = upper_[iSequence] - lower_[iSequence];
+                                                  if (gap < 1.0e20)
+                                                       sumBadPivots -= value * gap;
+                                                  else
+                                                       sumBadPivots += 1.0e20;
+                                                  //printf("bad %d alpha %g dj at lower %g\n",
+                                                  //     iSequence,alpha,value);
+                                             }
+                                        }
+                                   }
+#endif
+#ifdef FORCE_FOLLOW
+                                   if (iSequence == force_in) {
+                                        printf("taking %d - alpha %g best %g\n", force_in, absAlpha, largestPivot);
+                                        take = true;
+                                   }
+#endif
+                                   if (take) {
+                                        sequenceIn_ = numberPossiblySwapped;
+                                        bestPivot =  absAlpha;
+                                        theta_ = dj_[iSequence] / alpha;
+                                        largestPivot = CoinMax(largestPivot, 0.5 * bestPivot);
+#ifdef DUBIOUS_WEIGHTS
+                                        bestWeight = weight;
+#endif
+                                        //printf(" taken seq %d alpha %g weight %d\n",
+                                        //   iSequence,absAlpha,dubiousWeights[iSequence]);
+                                   } else {
+                                        //printf(" not taken seq %d alpha %g weight %d\n",
+                                        //   iSequence,absAlpha,dubiousWeights[iSequence]);
+                                   }
+                                   double range = upper_[iSequence] - lower_[iSequence];
+                                   thruThis += range * fabs(alpha);
+                                   increaseInThis += badDj * range;
+                              }
+                         }
+                         marker[1-iFlip][0] = CoinMax(marker[1-iFlip][0], numberRemaining);
+                         marker[1-iFlip][1] = CoinMin(marker[1-iFlip][1], numberPossiblySwapped);
+#ifdef MORE_CAREFUL
+                         // If we have done pivots and things look bad set alpha_ 0.0 to force factorization
+                         if (sumBadPivots > 1.0e4) {
+                              if (handler_->logLevel() > 1)
+                                   printf("maybe forcing re-factorization - sum %g  %d pivots\n", sumBadPivots,
+                                          factorization_->pivots());
+                              if(factorization_->pivots() > 3) {
+                                   badSumPivots = true;
+                                   break;
+                              }
+                         }
+#endif
+                         swapped[1-iFlip] = numberPossiblySwapped;
+                         interesting[1-iFlip] = numberRemaining;
+                         // If we stop now this will be increase in objective (I think)
+                         double increase = (fabs(dualOut_) - totalThru) * theta_;
+                         increase += increaseInObjective;
+                         if (theta_ < 0.0)
+                              thruThis += fabs(dualOut_); // force using this one
+                         if (increaseInObjective < 0.0 && increase < 0.0 && lastSequence >= 0) {
+                              // back
+                              // We may need to be more careful - we could do by
+                              // switch so we always do fine grained?
+                              bestPivot = 0.0;
+                         } else {
+                              // add in
+                              totalThru += thruThis;
+                              increaseInObjective += increaseInThis;
+                         }
+                         if (bestPivot < 0.1 * bestEverPivot &&
+                                   bestEverPivot > 1.0e-6 &&
+                                   (bestPivot < 1.0e-3 || totalThru * 2.0 > fabs(dualOut_))) {
+                              // back to previous one
+                              sequenceIn_ = lastSequence;
+                              // swap regions
+                              iFlip = 1 - iFlip;
+                              break;
+                         } else if (sequenceIn_ == -1 && upperTheta > largeValue_) {
+                              if (lastPivot > acceptablePivot) {
+                                   // back to previous one
+                                   sequenceIn_ = lastSequence;
+                                   // swap regions
+                                   iFlip = 1 - iFlip;
+                              } else {
+                                   // can only get here if all pivots too small
+                              }
+                              break;
+                         } else if (totalThru >= fabs(dualOut_)) {
+                              modifyCosts = true; // fine grain - we can modify costs
+                              break; // no point trying another loop
+                         } else {
+                              lastSequence = sequenceIn_;
+                              if (bestPivot > bestEverPivot)
+                                   bestEverPivot = bestPivot;
+                              iFlip = 1 - iFlip;
+                              modifyCosts = true; // fine grain - we can modify costs
+                         }
+                    }
+                    if (iTry == MAXTRY)
+                         iFlip = 1 - iFlip; // flip back
+                    break;
+               } else {
+                    // skip this lot
+                    if (bestPivot > 1.0e-3 || bestPivot > bestEverPivot) {
+                         bestEverPivot = bestPivot;
+                         lastSequence = bestSequence;
+                    } else {
+                         // keep old swapped
+                         CoinMemcpyN(array[iFlip] + swapped[iFlip],
+                                     numberColumns_ - swapped[iFlip], array[1-iFlip] + swapped[iFlip]);
+                         CoinMemcpyN(indices[iFlip] + swapped[iFlip],
+                                     numberColumns_ - swapped[iFlip], indices[1-iFlip] + swapped[iFlip]);
+                         marker[1-iFlip][1] = CoinMin(marker[1-iFlip][1], swapped[iFlip]);
+                         swapped[1-iFlip] = swapped[iFlip];
+                    }
+                    increaseInObjective += increaseInThis;
+                    iFlip = 1 - iFlip; // swap regions
+                    tentativeTheta = 2.0 * upperTheta;
+                    totalThru += thruThis;
+               }
+          }
+
+          // can get here without sequenceIn_ set but with lastSequence
+          if (sequenceIn_ < 0 && lastSequence >= 0) {
+               // back to previous one
+               sequenceIn_ = lastSequence;
+               // swap regions
+               iFlip = 1 - iFlip;
+          }
+
+#define MINIMUMTHETA 1.0e-18
+          // Movement should be minimum for anti-degeneracy - unless
+          // fixed variable out
+          double minimumTheta;
+          if (upperOut_ > lowerOut_)
+               minimumTheta = MINIMUMTHETA;
+          else
+               minimumTheta = 0.0;
+          if (sequenceIn_ >= 0) {
+               // at this stage sequenceIn_ is just pointer into index array
+               // flip just so we can use iFlip
+               iFlip = 1 - iFlip;
+               spare = array[iFlip];
+               index = indices[iFlip];
+               double oldValue;
+               alpha_ = spare[sequenceIn_];
+               sequenceIn_ = indices[iFlip][sequenceIn_];
+               oldValue = dj_[sequenceIn_];
+               theta_ = CoinMax(oldValue / alpha_, 0.0);
+               if (theta_ < minimumTheta && fabs(alpha_) < 1.0e5 && 1) {
+                    // can't pivot to zero
+#if 0
+                    if (oldValue - minimumTheta*alpha_ >= -dualTolerance_) {
+                         theta_ = minimumTheta;
+                    } else if (oldValue - minimumTheta*alpha_ >= -newTolerance) {
+                         theta_ = minimumTheta;
+                         thisIncrease = true;
+                    } else {
+                         theta_ = CoinMax((oldValue + newTolerance) / alpha_, 0.0);
+                         thisIncrease = true;
+                    }
+#else
+                    theta_ = minimumTheta;
+#endif
+               }
+               // may need to adjust costs so all dual feasible AND pivoted is exactly 0
+               //int costOffset = numberRows_+numberColumns_;
+               if (modifyCosts && !badSumPivots) {
+                    int i;
+                    for (i = numberColumns_ - 1; i >= swapped[iFlip]; i--) {
+                         int iSequence = index[i];
+                         double alpha = spare[i];
+                         double value = dj_[iSequence] - theta_ * alpha;
+
+                         // can't be free here
+
+                         if (alpha < 0.0) {
+                              //at upper bound
+                              if (value > dualTolerance_) {
+                                   //thisIncrease = true;
+#if CLP_CAN_HAVE_ZERO_OBJ<2
+#define MODIFYCOST 2
+#endif
+#if MODIFYCOST
+                                   // modify cost to hit new tolerance
+                                   double modification = alpha * theta_ - dj_[iSequence]
+                                                         + newTolerance;
+                                   if ((specialOptions_&(2048 + 4096 + 16384)) != 0) {
+                                        if ((specialOptions_ & 16384) != 0) {
+                                             if (fabs(modification) < 1.0e-8)
+                                                  modification = 0.0;
+                                        } else if ((specialOptions_ & 2048) != 0) {
+                                             if (fabs(modification) < 1.0e-10)
+                                                  modification = 0.0;
+                                        } else {
+                                             if (fabs(modification) < 1.0e-12)
+                                                  modification = 0.0;
+                                        }
+                                   }
+                                   dj_[iSequence] += modification;
+                                   cost_[iSequence] +=  modification;
+                                   if (modification)
+                                        numberChanged_ ++; // Say changed costs
+                                   //cost_[iSequence+costOffset] += modification; // save change
+#endif
+                              }
+                         } else {
+                              // at lower bound
+                              if (-value > dualTolerance_) {
+                                   //thisIncrease = true;
+#if MODIFYCOST
+                                   // modify cost to hit new tolerance
+                                   double modification = alpha * theta_ - dj_[iSequence]
+                                                         - newTolerance;
+                                   //modification = CoinMax(modification,-dualTolerance_);
+                                   //assert (fabs(modification)<1.0e-7);
+                                   if ((specialOptions_&(2048 + 4096)) != 0) {
+                                        if ((specialOptions_ & 2048) != 0) {
+                                             if (fabs(modification) < 1.0e-10)
+                                                  modification = 0.0;
+                                        } else {
+                                             if (fabs(modification) < 1.0e-12)
+                                                  modification = 0.0;
+                                        }
+                                   }
+                                   dj_[iSequence] += modification;
+                                   cost_[iSequence] +=  modification;
+                                   if (modification)
+                                        numberChanged_ ++; // Say changed costs
+                                   //cost_[iSequence+costOffset] += modification; // save change
+#endif
+                              }
+                         }
+                    }
+               }
+          }
+     }
+
+#ifdef MORE_CAREFUL
+     // If we have done pivots and things look bad set alpha_ 0.0 to force factorization
+     if ((badSumPivots ||
+               fabs(theta_ * badFree) > 10.0 * dualTolerance_) && factorization_->pivots()) {
+          if (handler_->logLevel() > 1)
+               printf("forcing re-factorization\n");
+          sequenceIn_ = -1;
+     }
+#endif
+     if (sequenceIn_ >= 0) {
+          lowerIn_ = lower_[sequenceIn_];
+          upperIn_ = upper_[sequenceIn_];
+          valueIn_ = solution_[sequenceIn_];
+          dualIn_ = dj_[sequenceIn_];
+
+          if (numberTimesOptimal_) {
+               // can we adjust cost back closer to original
+               //*** add coding
+          }
+#if MODIFYCOST>1
+          // modify cost to hit zero exactly
+          // so (dualIn_+modification)==theta_*alpha_
+          double modification = theta_ * alpha_ - dualIn_;
+          // But should not move objective too much ??
+#define DONT_MOVE_OBJECTIVE
+#ifdef DONT_MOVE_OBJECTIVE
+          double moveObjective = fabs(modification * solution_[sequenceIn_]);
+          double smallMove = CoinMax(fabs(objectiveValue_), 1.0e-3);
+          if (moveObjective > smallMove) {
+               if (handler_->logLevel() > 1)
+                    printf("would move objective by %g - original mod %g sol value %g\n", moveObjective,
+                           modification, solution_[sequenceIn_]);
+               modification *= smallMove / moveObjective;
+          }
+#endif
+          if (badSumPivots)
+               modification = 0.0;
+          if ((specialOptions_&(2048 + 4096)) != 0) {
+               if ((specialOptions_ & 16384) != 0) {
+                    // in fast dual
+                    if (fabs(modification) < 1.0e-7)
+                         modification = 0.0;
+               } else if ((specialOptions_ & 2048) != 0) {
+                    if (fabs(modification) < 1.0e-10)
+                         modification = 0.0;
+               } else {
+                    if (fabs(modification) < 1.0e-12)
+                         modification = 0.0;
+               }
+          }
+          dualIn_ += modification;
+          dj_[sequenceIn_] = dualIn_;
+          cost_[sequenceIn_] += modification;
+          if (modification)
+               numberChanged_ ++; // Say changed costs
+          //int costOffset = numberRows_+numberColumns_;
+          //cost_[sequenceIn_+costOffset] += modification; // save change
+          //assert (fabs(modification)<1.0e-6);
+#ifdef CLP_DEBUG
+          if ((handler_->logLevel() & 32) && fabs(modification) > 1.0e-15)
+               printf("exact %d new cost %g, change %g\n", sequenceIn_,
+                      cost_[sequenceIn_], modification);
+#endif
+#endif
+
+          if (alpha_ < 0.0) {
+               // as if from upper bound
+               directionIn_ = -1;
+               upperIn_ = valueIn_;
+          } else {
+               // as if from lower bound
+               directionIn_ = 1;
+               lowerIn_ = valueIn_;
+          }
+     } else {
+          // no pivot
+          bestPossible = 0.0;
+          alpha_ = 0.0;
+     }
+     //if (thisIncrease)
+     //dualTolerance_+= 1.0e-6*dblParam_[ClpDualTolerance];
+
+     // clear arrays
+
+     for (i = 0; i < 2; i++) {
+          CoinZeroN(array[i], marker[i][0]);
+          CoinZeroN(array[i] + marker[i][1], numberColumns_ - marker[i][1]);
+     }
+     return bestPossible;
+}
+#ifdef CLP_ALL_ONE_FILE
+#undef MAXTRY
+#endif
+/* Checks if tentative optimal actually means unbounded
+   Returns -3 if not, 2 if is unbounded */
+int
+ClpSimplexDual::checkUnbounded(CoinIndexedVector * ray,
+                               CoinIndexedVector * spare,
+                               double changeCost)
+{
+     int status = 2; // say unbounded
+     factorization_->updateColumn(spare, ray);
+     // get reduced cost
+     int i;
+     int number = ray->getNumElements();
+     int * index = ray->getIndices();
+     double * array = ray->denseVector();
+     for (i = 0; i < number; i++) {
+          int iRow = index[i];
+          int iPivot = pivotVariable_[iRow];
+          changeCost -= cost(iPivot) * array[iRow];
+     }
+     double way;
+     if (changeCost > 0.0) {
+          //try going down
+          way = 1.0;
+     } else if (changeCost < 0.0) {
+          //try going up
+          way = -1.0;
+     } else {
+#ifdef CLP_DEBUG
+          printf("can't decide on up or down\n");
+#endif
+          way = 0.0;
+          status = -3;
+     }
+     double movement = 1.0e10 * way; // some largish number
+     double zeroTolerance = 1.0e-14 * dualBound_;
+     for (i = 0; i < number; i++) {
+          int iRow = index[i];
+          int iPivot = pivotVariable_[iRow];
+          double arrayValue = array[iRow];
+          if (fabs(arrayValue) < zeroTolerance)
+               arrayValue = 0.0;
+          double newValue = solution(iPivot) + movement * arrayValue;
+          if (newValue > upper(iPivot) + primalTolerance_ ||
+                    newValue < lower(iPivot) - primalTolerance_)
+               status = -3; // not unbounded
+     }
+     if (status == 2) {
+          // create ray
+          delete [] ray_;
+          ray_ = new double [numberColumns_];
+          CoinZeroN(ray_, numberColumns_);
+          for (i = 0; i < number; i++) {
+               int iRow = index[i];
+               int iPivot = pivotVariable_[iRow];
+               double arrayValue = array[iRow];
+               if (iPivot < numberColumns_ && fabs(arrayValue) >= zeroTolerance)
+                    ray_[iPivot] = way * array[iRow];
+          }
+     }
+     ray->clear();
+     return status;
+}
+//static int count_alpha=0;
+/* Checks if finished.  Updates status */
+void
+ClpSimplexDual::statusOfProblemInDual(int & lastCleaned, int type,
+                                      double * givenDuals, ClpDataSave & saveData,
+                                      int ifValuesPass)
+{
+#ifdef CLP_INVESTIGATE_SERIAL
+     if (z_thinks > 0 && z_thinks < 2)
+          z_thinks += 2;
+#endif
+     bool arraysNotCreated = (type==0);
+     // If lots of iterations then adjust costs if large ones
+     if (numberIterations_ > 4 * (numberRows_ + numberColumns_) && objectiveScale_ == 1.0) {
+          double largest = 0.0;
+          for (int i = 0; i < numberRows_; i++) {
+               int iColumn = pivotVariable_[i];
+               largest = CoinMax(largest, fabs(cost_[iColumn]));
+          }
+          if (largest > 1.0e6) {
+               objectiveScale_ = 1.0e6 / largest;
+               for (int i = 0; i < numberRows_ + numberColumns_; i++)
+                    cost_[i] *= objectiveScale_;
+          }
+     }
+     int numberPivots = factorization_->pivots();
+     double realDualInfeasibilities = 0.0;
+     if (type == 2) {
+          if (alphaAccuracy_ != -1.0)
+               alphaAccuracy_ = -2.0;
+          // trouble - restore solution
+          CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+          CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                      numberRows_, rowActivityWork_);
+          CoinMemcpyN(savedSolution_ ,
+                      numberColumns_, columnActivityWork_);
+          // restore extra stuff
+          int dummy;
+          matrix_->generalExpanded(this, 6, dummy);
+          forceFactorization_ = 1; // a bit drastic but ..
+          changeMade_++; // say something changed
+          // get correct bounds on all variables
+          resetFakeBounds(0);
+     }
+     int tentativeStatus = problemStatus_;
+     double changeCost;
+     bool unflagVariables = true;
+     bool weightsSaved = false;
+     bool weightsSaved2 = numberIterations_ && !numberPrimalInfeasibilities_;
+     int dontFactorizePivots = dontFactorizePivots_;
+     if (type == 3) {
+          type = 1;
+          dontFactorizePivots = 1;
+     }
+     if (alphaAccuracy_ < 0.0 || !numberPivots || alphaAccuracy_ > 1.0e4 || numberPivots > 20) {
+          if (problemStatus_ > -3 || numberPivots > dontFactorizePivots) {
+               // factorize
+               // later on we will need to recover from singularities
+               // also we could skip if first time
+               // save dual weights
+               dualRowPivot_->saveWeights(this, 1);
+               weightsSaved = true;
+               if (type) {
+                    // is factorization okay?
+                    if (internalFactorize(1)) {
+                         // no - restore previous basis
+                         unflagVariables = false;
+                         assert (type == 1);
+                         changeMade_++; // say something changed
+                         // Keep any flagged variables
+                         int i;
+                         for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                              if (flagged(i))
+                                   saveStatus_[i] |= 64; //say flagged
+                         }
+                         CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+                         CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                                     numberRows_, rowActivityWork_);
+                         CoinMemcpyN(savedSolution_ ,
+                                     numberColumns_, columnActivityWork_);
+                         // restore extra stuff
+                         int dummy;
+                         matrix_->generalExpanded(this, 6, dummy);
+                         // get correct bounds on all variables
+                         resetFakeBounds(1);
+                         // need to reject something
+                         char x = isColumn(sequenceOut_) ? 'C' : 'R';
+                         handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                   << x << sequenceWithin(sequenceOut_)
+                                   << CoinMessageEol;
+#ifdef COIN_DEVELOP
+                         printf("flag d\n");
+#endif
+                         setFlagged(sequenceOut_);
+                         progress_.clearBadTimes();
+
+                         // Go to safe
+                         factorization_->pivotTolerance(0.99);
+                         forceFactorization_ = 1; // a bit drastic but ..
+                         type = 2;
+                         //assert (internalFactorize(1)==0);
+                         if (internalFactorize(1)) {
+                              CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+                              CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                                          numberRows_, rowActivityWork_);
+                              CoinMemcpyN(savedSolution_ ,
+                                          numberColumns_, columnActivityWork_);
+                              // restore extra stuff
+                              int dummy;
+                              matrix_->generalExpanded(this, 6, dummy);
+                              // debug
+                              int returnCode = internalFactorize(1);
+                              while (returnCode) {
+                                   // ouch
+                                   // switch off dense
+                                   int saveDense = factorization_->denseThreshold();
+                                   factorization_->setDenseThreshold(0);
+                                   // Go to safe
+                                   factorization_->pivotTolerance(0.99);
+                                   // make sure will do safe factorization
+                                   pivotVariable_[0] = -1;
+                                   returnCode = internalFactorize(2);
+                                   factorization_->setDenseThreshold(saveDense);
+                              }
+                              // get correct bounds on all variables
+                              resetFakeBounds(1);
+                         }
+                    }
+               }
+               if (problemStatus_ != -4 || numberPivots > 10)
+                    problemStatus_ = -3;
+          }
+     } else {
+          //printf("testing with accuracy of %g and status of %d\n",alphaAccuracy_,problemStatus_);
+          //count_alpha++;
+          //if ((count_alpha%5000)==0)
+          //printf("count alpha %d\n",count_alpha);
+     }
+     // at this stage status is -3 or -4 if looks infeasible
+     // get primal and dual solutions
+#if 0
+     {
+          int numberTotal = numberRows_ + numberColumns_;
+          double * saveSol = CoinCopyOfArray(solution_, numberTotal);
+          double * saveDj = CoinCopyOfArray(dj_, numberTotal);
+          double tolerance = type ? 1.0e-4 : 1.0e-8;
+          // always if values pass
+          double saveObj = objectiveValue_;
+          double sumPrimal = sumPrimalInfeasibilities_;
+          int numberPrimal = numberPrimalInfeasibilities_;
+          double sumDual = sumDualInfeasibilities_;
+          int numberDual = numberDualInfeasibilities_;
+          gutsOfSolution(givenDuals, NULL);
+          int j;
+          double largestPrimal = tolerance;
+          int iPrimal = -1;
+          for (j = 0; j < numberTotal; j++) {
+               double difference = solution_[j] - saveSol[j];
+               if (fabs(difference) > largestPrimal) {
+                    iPrimal = j;
+                    largestPrimal = fabs(difference);
+               }
+          }
+          double largestDual = tolerance;
+          int iDual = -1;
+          for (j = 0; j < numberTotal; j++) {
+               double difference = dj_[j] - saveDj[j];
+               if (fabs(difference) > largestDual && upper_[j] > lower_[j]) {
+                    iDual = j;
+                    largestDual = fabs(difference);
+               }
+          }
+          if (!type) {
+               if (fabs(saveObj - objectiveValue_) > 1.0e-5 ||
+                         numberPrimal != numberPrimalInfeasibilities_ || numberPrimal != 1 ||
+                         fabs(sumPrimal - sumPrimalInfeasibilities_) > 1.0e-5 || iPrimal >= 0 ||
+                         numberDual != numberDualInfeasibilities_ || numberDual != 0 ||
+                         fabs(sumDual - sumDualInfeasibilities_) > 1.0e-5 || iDual >= 0)
+                    printf("type %d its %d pivots %d primal n(%d,%d) s(%g,%g) diff(%g,%d) dual n(%d,%d) s(%g,%g) diff(%g,%d) obj(%g,%g)\n",
+                           type, numberIterations_, numberPivots,
+                           numberPrimal, numberPrimalInfeasibilities_, sumPrimal, sumPrimalInfeasibilities_,
+                           largestPrimal, iPrimal,
+                           numberDual, numberDualInfeasibilities_, sumDual, sumDualInfeasibilities_,
+                           largestDual, iDual,
+                           saveObj, objectiveValue_);
+          } else {
+               if (fabs(saveObj - objectiveValue_) > 1.0e-5 ||
+                         numberPrimalInfeasibilities_ || iPrimal >= 0 ||
+                         numberDualInfeasibilities_ || iDual >= 0)
+                    printf("type %d its %d pivots %d primal n(%d,%d) s(%g,%g) diff(%g,%d) dual n(%d,%d) s(%g,%g) diff(%g,%d) obj(%g,%g)\n",
+                           type, numberIterations_, numberPivots,
+                           numberPrimal, numberPrimalInfeasibilities_, sumPrimal, sumPrimalInfeasibilities_,
+                           largestPrimal, iPrimal,
+                           numberDual, numberDualInfeasibilities_, sumDual, sumDualInfeasibilities_,
+                           largestDual, iDual,
+                           saveObj, objectiveValue_);
+          }
+          delete [] saveSol;
+          delete [] saveDj;
+     }
+#else
+     if (type || ifValuesPass)
+          gutsOfSolution(givenDuals, NULL);
+#endif
+     // If bad accuracy treat as singular
+     if ((largestPrimalError_ > 1.0e15 || largestDualError_ > 1.0e15) && numberIterations_) {
+          // restore previous basis
+          unflagVariables = false;
+          changeMade_++; // say something changed
+          // Keep any flagged variables
+          int i;
+          for (i = 0; i < numberRows_ + numberColumns_; i++) {
+               if (flagged(i))
+                    saveStatus_[i] |= 64; //say flagged
+          }
+          CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+          CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                      numberRows_, rowActivityWork_);
+          CoinMemcpyN(savedSolution_ ,
+                      numberColumns_, columnActivityWork_);
+          // restore extra stuff
+          int dummy;
+          matrix_->generalExpanded(this, 6, dummy);
+          // get correct bounds on all variables
+          resetFakeBounds(1);
+          // need to reject something
+          char x = isColumn(sequenceOut_) ? 'C' : 'R';
+          handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                    << x << sequenceWithin(sequenceOut_)
+                    << CoinMessageEol;
+#ifdef COIN_DEVELOP
+          printf("flag e\n");
+#endif
+          setFlagged(sequenceOut_);
+          progress_.clearBadTimes();
+
+          // Go to safer
+          double newTolerance = CoinMin(1.1 * factorization_->pivotTolerance(), 0.99);
+          factorization_->pivotTolerance(newTolerance);
+          forceFactorization_ = 1; // a bit drastic but ..
+          if (alphaAccuracy_ != -1.0)
+               alphaAccuracy_ = -2.0;
+          type = 2;
+          //assert (internalFactorize(1)==0);
+          if (internalFactorize(1)) {
+               CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+               CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                           numberRows_, rowActivityWork_);
+               CoinMemcpyN(savedSolution_ ,
+                           numberColumns_, columnActivityWork_);
+               // restore extra stuff
+               int dummy;
+               matrix_->generalExpanded(this, 6, dummy);
+               // debug
+               int returnCode = internalFactorize(1);
+               while (returnCode) {
+                    // ouch
+                    // switch off dense
+                    int saveDense = factorization_->denseThreshold();
+                    factorization_->setDenseThreshold(0);
+                    // Go to safe
+                    factorization_->pivotTolerance(0.99);
+                    // make sure will do safe factorization
+                    pivotVariable_[0] = -1;
+                    returnCode = internalFactorize(2);
+                    factorization_->setDenseThreshold(saveDense);
+               }
+               // get correct bounds on all variables
+               resetFakeBounds(1);
+          }
+          // get primal and dual solutions
+          gutsOfSolution(givenDuals, NULL);
+     } else if (goodAccuracy()) {
+          // Can reduce tolerance
+          double newTolerance = CoinMax(0.99 * factorization_->pivotTolerance(), saveData.pivotTolerance_);
+          factorization_->pivotTolerance(newTolerance);
+     }
+     bestObjectiveValue_ = CoinMax(bestObjectiveValue_,
+                                   objectiveValue_ - bestPossibleImprovement_);
+     bool reallyBadProblems = false;
+     // Double check infeasibility if no action
+     if (progress_.lastIterationNumber(0) == numberIterations_) {
+          if (dualRowPivot_->looksOptimal()) {
+               numberPrimalInfeasibilities_ = 0;
+               sumPrimalInfeasibilities_ = 0.0;
+          }
+#if 1
+     } else {
+          double thisObj = objectiveValue_ - bestPossibleImprovement_;
+#ifdef CLP_INVESTIGATE
+          assert (bestPossibleImprovement_ > -1000.0 && objectiveValue_ > -1.0e100);
+          if (bestPossibleImprovement_)
+               printf("obj %g add in %g -> %g\n", objectiveValue_, bestPossibleImprovement_,
+                      thisObj);
+#endif
+          double lastObj = progress_.lastObjective(0);
+#ifndef NDEBUG
+#ifdef COIN_DEVELOP
+          resetFakeBounds(-1);
+#endif
+#endif
+#ifdef CLP_REPORT_PROGRESS
+          ixxxxxx++;
+          if (ixxxxxx >= ixxyyyy - 4 && ixxxxxx <= ixxyyyy) {
+               char temp[20];
+               sprintf(temp, "sol%d.out", ixxxxxx);
+               printf("sol%d.out\n", ixxxxxx);
+               FILE * fp = fopen(temp, "w");
+               int nTotal = numberRows_ + numberColumns_;
+               for (int i = 0; i < nTotal; i++)
+                    fprintf(fp, "%d %d %g %g %g %g %g\n",
+                            i, status_[i], lower_[i], solution_[i], upper_[i], cost_[i], dj_[i]);
+               fclose(fp);
+          }
+#endif
+          if(!ifValuesPass && firstFree_ < 0) {
+               double testTol = 5.0e-3;
+               if (progress_.timesFlagged() > 10) {
+                    testTol *= pow(2.0, progress_.timesFlagged() - 8);
+               } else if (progress_.timesFlagged() > 5) {
+                    testTol *= 5.0;
+               }
+               if (lastObj > thisObj +
+                         testTol*(fabs(thisObj) + fabs(lastObj)) + testTol) {
+                    int maxFactor = factorization_->maximumPivots();
+                    if ((specialOptions_ & 1048576) == 0) {
+                         if (progress_.timesFlagged() > 10)
+                              progress_.incrementReallyBadTimes();
+                         if (maxFactor > 10 - 9) {
+#ifdef COIN_DEVELOP
+                              printf("lastobj %g thisobj %g\n", lastObj, thisObj);
+#endif
+                              //if (forceFactorization_<0)
+                              //forceFactorization_= maxFactor;
+                              //forceFactorization_ = CoinMax(1,(forceFactorization_>>1));
+                              if ((progressFlag_ & 4) == 0 && lastObj < thisObj + 1.0e4 &&
+                                        largestPrimalError_ < 1.0e2) {
+                                   // Just save costs
+                                   // save extra copy of cost_
+                                   int nTotal = numberRows_ + numberColumns_;
+                                   double * temp = new double [2*nTotal];
+                                   memcpy(temp, cost_, nTotal * sizeof(double));
+                                   memcpy(temp + nTotal, cost_, nTotal * sizeof(double));
+                                   delete [] cost_;
+                                   cost_ = temp;
+                                   objectiveWork_ = cost_;
+                                   rowObjectiveWork_ = cost_ + numberColumns_;
+                                   progressFlag_ |= 4;
+                              } else {
+                                   forceFactorization_ = 1;
+#ifdef COIN_DEVELOP
+                                   printf("Reducing factorization frequency - bad backwards\n");
+#endif
+#if 1
+                                   unflagVariables = false;
+                                   changeMade_++; // say something changed
+                                   int nTotal = numberRows_ + numberColumns_;
+                                   CoinMemcpyN(saveStatus_, nTotal, status_);
+                                   CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                                               numberRows_, rowActivityWork_);
+                                   CoinMemcpyN(savedSolution_ ,
+                                               numberColumns_, columnActivityWork_);
+                                   if ((progressFlag_ & 4) == 0) {
+                                        // save extra copy of cost_
+                                        double * temp = new double [2*nTotal];
+                                        memcpy(temp, cost_, nTotal * sizeof(double));
+                                        memcpy(temp + nTotal, cost_, nTotal * sizeof(double));
+                                        delete [] cost_;
+                                        cost_ = temp;
+                                        objectiveWork_ = cost_;
+                                        rowObjectiveWork_ = cost_ + numberColumns_;
+                                        progressFlag_ |= 4;
+                                   } else {
+                                        memcpy(cost_, cost_ + nTotal, nTotal * sizeof(double));
+                                   }
+                                   // restore extra stuff
+                                   int dummy;
+                                   matrix_->generalExpanded(this, 6, dummy);
+                                   double pivotTolerance = factorization_->pivotTolerance();
+                                   if(pivotTolerance < 0.2)
+                                        factorization_->pivotTolerance(0.2);
+                                   else if(progress_.timesFlagged() > 2)
+                                        factorization_->pivotTolerance(CoinMin(pivotTolerance * 1.1, 0.99));
+                                   if (alphaAccuracy_ != -1.0)
+                                        alphaAccuracy_ = -2.0;
+                                   if (internalFactorize(1)) {
+                                        CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+                                        CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                                                    numberRows_, rowActivityWork_);
+                                        CoinMemcpyN(savedSolution_ ,
+                                                    numberColumns_, columnActivityWork_);
+                                        // restore extra stuff
+                                        int dummy;
+                                        matrix_->generalExpanded(this, 6, dummy);
+                                        // debug
+                                        int returnCode = internalFactorize(1);
+                                        while (returnCode) {
+                                             // ouch
+                                             // switch off dense
+                                             int saveDense = factorization_->denseThreshold();
+                                             factorization_->setDenseThreshold(0);
+                                             // Go to safe
+                                             factorization_->pivotTolerance(0.99);
+                                             // make sure will do safe factorization
+                                             pivotVariable_[0] = -1;
+                                             returnCode = internalFactorize(2);
+                                             factorization_->setDenseThreshold(saveDense);
+                                        }
+                                   }
+                                   resetFakeBounds(0);
+                                   type = 2; // so will restore weights
+                                   // get primal and dual solutions
+                                   gutsOfSolution(givenDuals, NULL);
+                                   if (numberPivots < 2) {
+                                        // need to reject something
+                                        char x = isColumn(sequenceOut_) ? 'C' : 'R';
+                                        handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                                  << x << sequenceWithin(sequenceOut_)
+                                                  << CoinMessageEol;
+#ifdef COIN_DEVELOP
+                                        printf("flag d\n");
+#endif
+                                        setFlagged(sequenceOut_);
+                                        progress_.clearBadTimes();
+                                        progress_.incrementTimesFlagged();
+                                   }
+                                   if (numberPivots < 10)
+                                        reallyBadProblems = true;
+#ifdef COIN_DEVELOP
+                                   printf("obj now %g\n", objectiveValue_);
+#endif
+                                   progress_.modifyObjective(objectiveValue_
+                                                             - bestPossibleImprovement_);
+#endif
+                              }
+                         }
+                    } else {
+                         // in fast dual give up
+#ifdef COIN_DEVELOP
+                         printf("In fast dual?\n");
+#endif
+                         problemStatus_ = 3;
+                    }
+               } else if (lastObj < thisObj - 1.0e-5 * CoinMax(fabs(thisObj), fabs(lastObj)) - 1.0e-3) {
+                    numberTimesOptimal_ = 0;
+               }
+          }
+#endif
+     }
+     // Up tolerance if looks a bit odd
+     if (numberIterations_ > CoinMax(1000, numberRows_ >> 4) && (specialOptions_ & 64) != 0) {
+          if (sumPrimalInfeasibilities_ && sumPrimalInfeasibilities_ < 1.0e5) {
+               int backIteration = progress_.lastIterationNumber(CLP_PROGRESS - 1);
+               if (backIteration > 0 && numberIterations_ - backIteration < 9 * CLP_PROGRESS) {
+                    if (factorization_->pivotTolerance() < 0.9) {
+                         // up tolerance
+                         factorization_->pivotTolerance(CoinMin(factorization_->pivotTolerance() * 1.05 + 0.02, 0.91));
+                         //printf("tol now %g\n",factorization_->pivotTolerance());
+                         progress_.clearIterationNumbers();
+                    }
+               }
+          }
+     }
+     // Check if looping
+     int loop;
+     if (!givenDuals && type != 2)
+          loop = progress_.looping();
+     else
+          loop = -1;
+     if (progress_.reallyBadTimes() > 10) {
+          problemStatus_ = 10; // instead - try other algorithm
+#if COIN_DEVELOP>2
+          printf("returning at %d\n", __LINE__);
+#endif
+     }
+     int situationChanged = 0;
+     if (loop >= 0) {
+          problemStatus_ = loop; //exit if in loop
+          if (!problemStatus_) {
+               // declaring victory
+               numberPrimalInfeasibilities_ = 0;
+               sumPrimalInfeasibilities_ = 0.0;
+          } else {
+               problemStatus_ = 10; // instead - try other algorithm
+#if COIN_DEVELOP>2
+               printf("returning at %d\n", __LINE__);
+#endif
+          }
+          return;
+     } else if (loop < -1) {
+          // something may have changed
+          gutsOfSolution(NULL, NULL);
+          situationChanged = 1;
+     }
+     // really for free variables in
+     if((progressFlag_ & 2) != 0) {
+          situationChanged = 2;
+     }
+     progressFlag_ &= (~3); //reset progress flag
+     if ((progressFlag_ & 4) != 0) {
+          // save copy of cost_
+          int nTotal = numberRows_ + numberColumns_;
+          memcpy(cost_ + nTotal, cost_, nTotal * sizeof(double));
+     }
+     /*if (!numberIterations_&&sumDualInfeasibilities_)
+       printf("OBJ %g sumPinf %g sumDinf %g\n",
+        objectiveValue(),sumPrimalInfeasibilities_,
+        sumDualInfeasibilities_);*/
+     // mark as having gone optimal if looks like it
+     if (!numberPrimalInfeasibilities_&&
+	 !numberDualInfeasibilities_)
+       progressFlag_ |= 8;
+     if (handler_->detail(CLP_SIMPLEX_STATUS, messages_) < 100) {
+          handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                    << numberIterations_ << objectiveValue();
+          handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                    << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+          handler_->printing(sumDualInfeasibilities_ > 0.0)
+                    << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+          handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                             < numberDualInfeasibilities_)
+                    << numberDualInfeasibilitiesWithoutFree_;
+          handler_->message() << CoinMessageEol;
+     }
+#if 0
+     printf("IT %d %g %g(%d) %g(%d)\n",
+            numberIterations_, objectiveValue(),
+            sumPrimalInfeasibilities_, numberPrimalInfeasibilities_,
+            sumDualInfeasibilities_, numberDualInfeasibilities_);
+#endif
+     double approximateObjective = objectiveValue_;
+#ifdef CLP_REPORT_PROGRESS
+     if (ixxxxxx >= ixxyyyy - 4 && ixxxxxx <= ixxyyyy) {
+          char temp[20];
+          sprintf(temp, "x_sol%d.out", ixxxxxx);
+          FILE * fp = fopen(temp, "w");
+          int nTotal = numberRows_ + numberColumns_;
+          for (int i = 0; i < nTotal; i++)
+               fprintf(fp, "%d %d %g %g %g %g %g\n",
+                       i, status_[i], lower_[i], solution_[i], upper_[i], cost_[i], dj_[i]);
+          fclose(fp);
+          if (ixxxxxx == ixxyyyy)
+               exit(6);
+     }
+#endif
+     realDualInfeasibilities = sumDualInfeasibilities_;
+     double saveTolerance = dualTolerance_;
+     // If we need to carry on cleaning variables
+     if (!numberPrimalInfeasibilities_ && (specialOptions_ & 1024) != 0 && CLEAN_FIXED) {
+          for (int iRow = 0; iRow < numberRows_; iRow++) {
+               int iPivot = pivotVariable_[iRow];
+               if (!flagged(iPivot) && pivoted(iPivot)) {
+                    // carry on
+                    numberPrimalInfeasibilities_ = -1;
+                    sumOfRelaxedPrimalInfeasibilities_ = 1.0;
+                    sumPrimalInfeasibilities_ = 1.0;
+                    break;
+               }
+          }
+     }
+     /* If we are primal feasible and any dual infeasibilities are on
+        free variables then it is better to go to primal */
+     if (!numberPrimalInfeasibilities_ && !numberDualInfeasibilitiesWithoutFree_ &&
+               numberDualInfeasibilities_)
+          problemStatus_ = 10;
+     // dual bound coming in
+     //double saveDualBound = dualBound_;
+     bool needCleanFake = false;
+     while (problemStatus_ <= -3) {
+          int cleanDuals = 0;
+          if (situationChanged != 0)
+               cleanDuals = 1;
+          int numberChangedBounds = 0;
+          int doOriginalTolerance = 0;
+          if ( lastCleaned == numberIterations_)
+               doOriginalTolerance = 1;
+          // check optimal
+          // give code benefit of doubt
+          if (sumOfRelaxedDualInfeasibilities_ == 0.0 &&
+                    sumOfRelaxedPrimalInfeasibilities_ == 0.0) {
+               // say optimal (with these bounds etc)
+               numberDualInfeasibilities_ = 0;
+               sumDualInfeasibilities_ = 0.0;
+               numberPrimalInfeasibilities_ = 0;
+               sumPrimalInfeasibilities_ = 0.0;
+          }
+          //if (dualFeasible()||problemStatus_==-4||(primalFeasible()&&!numberDualInfeasibilitiesWithoutFree_)) {
+          if (dualFeasible() || problemStatus_ == -4) {
+               progress_.modifyObjective(objectiveValue_
+                                         - bestPossibleImprovement_);
+#ifdef COIN_DEVELOP
+               if (sumDualInfeasibilities_ || bestPossibleImprovement_)
+                    printf("improve %g dualinf %g -> %g\n",
+                           bestPossibleImprovement_, sumDualInfeasibilities_,
+                           sumDualInfeasibilities_ * dualBound_);
+#endif
+               // see if cutoff reached
+               double limit = 0.0;
+               getDblParam(ClpDualObjectiveLimit, limit);
+#if 0
+               if(fabs(limit) < 1.0e30 && objectiveValue()*optimizationDirection_ >
+                         limit + 1.0e-7 + 1.0e-8 * fabs(limit) && !numberAtFakeBound()) {
+                    //looks infeasible on objective
+                    if (perturbation_ == 101) {
+                         cleanDuals = 1;
+                         // Save costs
+                         int numberTotal = numberRows_ + numberColumns_;
+                         double * saveCost = CoinCopyOfArray(cost_, numberTotal);
+                         // make sure fake bounds are back
+                         changeBounds(1, NULL, changeCost);
+                         createRim4(false);
+                         // make sure duals are current
+                         computeDuals(givenDuals);
+                         checkDualSolution();
+                         if(objectiveValue()*optimizationDirection_ >
+                                   limit + 1.0e-7 + 1.0e-8 * fabs(limit) && !numberDualInfeasibilities_) {
+                              perturbation_ = 102; // stop any perturbations
+                              printf("cutoff test succeeded\n");
+                         } else {
+                              printf("cutoff test failed\n");
+                              // put back
+                              memcpy(cost_, saveCost, numberTotal * sizeof(double));
+                              // make sure duals are current
+                              computeDuals(givenDuals);
+                              checkDualSolution();
+                              progress_.modifyObjective(-COIN_DBL_MAX);
+                              problemStatus_ = -1;
+                         }
+                         delete [] saveCost;
+                    }
+               }
+#endif
+               if (primalFeasible() && !givenDuals) {
+                    // may be optimal - or may be bounds are wrong
+                    handler_->message(CLP_DUAL_BOUNDS, messages_)
+                              << dualBound_
+                              << CoinMessageEol;
+                    // save solution in case unbounded
+                    double * saveColumnSolution = NULL;
+                    double * saveRowSolution = NULL;
+                    bool inCbc = (specialOptions_ & (0x01000000 | 16384)) != 0;
+                    if (!inCbc) {
+                         saveColumnSolution = CoinCopyOfArray(columnActivityWork_, numberColumns_);
+                         saveRowSolution = CoinCopyOfArray(rowActivityWork_, numberRows_);
+                    }
+                    numberChangedBounds = changeBounds(0, rowArray_[3], changeCost);
+                    if (numberChangedBounds <= 0 && !numberDualInfeasibilities_) {
+                         //looks optimal - do we need to reset tolerance
+                         if (perturbation_ == 101) {
+                              perturbation_ = 102; // stop any perturbations
+                              cleanDuals = 1;
+                              // make sure fake bounds are back
+                              //computeObjectiveValue();
+                              changeBounds(1, NULL, changeCost);
+                              //computeObjectiveValue();
+                              createRim4(false);
+                              // make sure duals are current
+                              computeDuals(givenDuals);
+                              checkDualSolution();
+                              progress_.modifyObjective(-COIN_DBL_MAX);
+#define DUAL_TRY_FASTER
+#ifdef DUAL_TRY_FASTER
+                              if (numberDualInfeasibilities_) {
+#endif
+                                   numberChanged_ = 1; // force something to happen
+                                   lastCleaned = numberIterations_ - 1;
+#ifdef DUAL_TRY_FASTER
+                              } else {
+                                   //double value = objectiveValue_;
+                                   computeObjectiveValue(true);
+                                   //printf("old %g new %g\n",value,objectiveValue_);
+                                   //numberChanged_=1;
+                              }
+#endif
+                         }
+                         if (lastCleaned < numberIterations_ && numberTimesOptimal_ < 4 &&
+                                   (numberChanged_ || (specialOptions_ & 4096) == 0)) {
+#if CLP_CAN_HAVE_ZERO_OBJ
+			   if ((specialOptions_&2097152)==0) {
+#endif
+                              doOriginalTolerance = 2;
+                              numberTimesOptimal_++;
+                              changeMade_++; // say something changed
+                              if (numberTimesOptimal_ == 1) {
+                                   dualTolerance_ = dblParam_[ClpDualTolerance];
+                              } else {
+                                   if (numberTimesOptimal_ == 2) {
+                                        // better to have small tolerance even if slower
+                                        factorization_->zeroTolerance(CoinMin(factorization_->zeroTolerance(), 1.0e-15));
+                                   }
+                                   dualTolerance_ = dblParam_[ClpDualTolerance];
+                                   dualTolerance_ *= pow(2.0, numberTimesOptimal_ - 1);
+                              }
+                              cleanDuals = 2; // If nothing changed optimal else primal
+#if CLP_CAN_HAVE_ZERO_OBJ
+			   } else {
+			     // no cost - skip checks
+			     problemStatus_=0;
+			   }
+#endif
+                         } else {
+                              problemStatus_ = 0; // optimal
+                              if (lastCleaned < numberIterations_ && numberChanged_) {
+                                   handler_->message(CLP_SIMPLEX_GIVINGUP, messages_)
+                                             << CoinMessageEol;
+                              }
+                         }
+                    } else {
+                         cleanDuals = 1;
+                         if (doOriginalTolerance == 1) {
+                              // check unbounded
+                              // find a variable with bad dj
+                              int iSequence;
+                              int iChosen = -1;
+                              if (!inCbc) {
+                                   double largest = 100.0 * primalTolerance_;
+                                   for (iSequence = 0; iSequence < numberRows_ + numberColumns_;
+                                             iSequence++) {
+                                        double djValue = dj_[iSequence];
+                                        double originalLo = originalLower(iSequence);
+                                        double originalUp = originalUpper(iSequence);
+                                        if (fabs(djValue) > fabs(largest)) {
+                                             if (getStatus(iSequence) != basic) {
+                                                  if (djValue > 0 && originalLo < -1.0e20) {
+                                                       if (djValue > fabs(largest)) {
+                                                            largest = djValue;
+                                                            iChosen = iSequence;
+                                                       }
+                                                  } else if (djValue < 0 && originalUp > 1.0e20) {
+                                                       if (-djValue > fabs(largest)) {
+                                                            largest = djValue;
+                                                            iChosen = iSequence;
+                                                       }
+                                                  }
+                                             }
+                                        }
+                                   }
+                              }
+                              if (iChosen >= 0) {
+                                   int iSave = sequenceIn_;
+                                   sequenceIn_ = iChosen;
+                                   unpack(rowArray_[1]);
+                                   sequenceIn_ = iSave;
+                                   // if dual infeasibilities then must be free vector so add in dual
+                                   if (numberDualInfeasibilities_) {
+                                        if (fabs(changeCost) > 1.0e-5)
+					  COIN_DETAIL_PRINT(printf("Odd free/unbounded combo\n"));
+                                        changeCost += cost_[iChosen];
+                                   }
+                                   problemStatus_ = checkUnbounded(rowArray_[1], rowArray_[0],
+                                                                   changeCost);
+                                   rowArray_[1]->clear();
+                              } else {
+                                   problemStatus_ = -3;
+                              }
+                              if (problemStatus_ == 2 && perturbation_ == 101) {
+                                   perturbation_ = 102; // stop any perturbations
+                                   cleanDuals = 1;
+                                   createRim4(false);
+                                   progress_.modifyObjective(-COIN_DBL_MAX);
+                                   problemStatus_ = -1;
+                              }
+                              if (problemStatus_ == 2) {
+                                   // it is unbounded - restore solution
+                                   // but first add in changes to non-basic
+                                   int iColumn;
+                                   double * original = columnArray_[0]->denseVector();
+                                   for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                                        if(getColumnStatus(iColumn) != basic)
+                                             ray_[iColumn] +=
+                                                  saveColumnSolution[iColumn] - original[iColumn];
+                                        columnActivityWork_[iColumn] = original[iColumn];
+                                   }
+                                   CoinMemcpyN(saveRowSolution, numberRows_,
+                                               rowActivityWork_);
+                              }
+                         } else {
+                              doOriginalTolerance = 2;
+                              rowArray_[0]->clear();
+                         }
+                    }
+                    delete [] saveColumnSolution;
+                    delete [] saveRowSolution;
+               }
+               if (problemStatus_ == -4 || problemStatus_ == -5) {
+                    // may be infeasible - or may be bounds are wrong
+                    numberChangedBounds = changeBounds(0, NULL, changeCost);
+                    needCleanFake = true;
+                    /* Should this be here as makes no difference to being feasible.
+                       But seems to make a difference to run times. */
+                    if (perturbation_ == 101 && 0) {
+                         perturbation_ = 102; // stop any perturbations
+                         cleanDuals = 1;
+                         numberChangedBounds = 1;
+                         // make sure fake bounds are back
+                         changeBounds(1, NULL, changeCost);
+                         needCleanFake = true;
+                         createRim4(false);
+                         progress_.modifyObjective(-COIN_DBL_MAX);
+                    }
+                    if ((numberChangedBounds <= 0 || dualBound_ > 1.0e20 ||
+                              (largestPrimalError_ > 1.0 && dualBound_ > 1.0e17)) &&
+                              (numberPivots < 4 || sumPrimalInfeasibilities_ > 1.0e-6)) {
+                         problemStatus_ = 1; // infeasible
+                         if (perturbation_ == 101) {
+                              perturbation_ = 102; // stop any perturbations
+                              //cleanDuals=1;
+                              //numberChangedBounds=1;
+                              //createRim4(false);
+                         }
+                    } else {
+                         problemStatus_ = -1; //iterate
+                         cleanDuals = 1;
+                         if (numberChangedBounds <= 0)
+                              doOriginalTolerance = 2;
+                         // and delete ray which has been created
+                         delete [] ray_;
+                         ray_ = NULL;
+                    }
+
+               }
+          } else {
+               cleanDuals = 1;
+          }
+          if (problemStatus_ < 0) {
+               if (doOriginalTolerance == 2) {
+                    // put back original tolerance
+                    lastCleaned = numberIterations_;
+                    numberChanged_ = 0; // Number of variables with changed costs
+                    handler_->message(CLP_DUAL_ORIGINAL, messages_)
+                              << CoinMessageEol;
+                    perturbation_ = 102; // stop any perturbations
+#if 0
+                    double * xcost = new double[numberRows_+numberColumns_];
+                    double * xlower = new double[numberRows_+numberColumns_];
+                    double * xupper = new double[numberRows_+numberColumns_];
+                    double * xdj = new double[numberRows_+numberColumns_];
+                    double * xsolution = new double[numberRows_+numberColumns_];
+                    CoinMemcpyN(cost_, (numberRows_ + numberColumns_), xcost);
+                    CoinMemcpyN(lower_, (numberRows_ + numberColumns_), xlower);
+                    CoinMemcpyN(upper_, (numberRows_ + numberColumns_), xupper);
+                    CoinMemcpyN(dj_, (numberRows_ + numberColumns_), xdj);
+                    CoinMemcpyN(solution_, (numberRows_ + numberColumns_), xsolution);
+#endif
+                    createRim4(false);
+                    progress_.modifyObjective(-COIN_DBL_MAX);
+                    // make sure duals are current
+                    computeDuals(givenDuals);
+                    checkDualSolution();
+#if 0
+                    int i;
+                    for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                         if (cost_[i] != xcost[i])
+                              printf("** %d old cost %g new %g sol %g\n",
+                                     i, xcost[i], cost_[i], solution_[i]);
+                         if (lower_[i] != xlower[i])
+                              printf("** %d old lower %g new %g sol %g\n",
+                                     i, xlower[i], lower_[i], solution_[i]);
+                         if (upper_[i] != xupper[i])
+                              printf("** %d old upper %g new %g sol %g\n",
+                                     i, xupper[i], upper_[i], solution_[i]);
+                         if (dj_[i] != xdj[i])
+                              printf("** %d old dj %g new %g sol %g\n",
+                                     i, xdj[i], dj_[i], solution_[i]);
+                         if (solution_[i] != xsolution[i])
+                              printf("** %d old solution %g new %g sol %g\n",
+                                     i, xsolution[i], solution_[i], solution_[i]);
+                    }
+                    //delete [] xcost;
+                    //delete [] xupper;
+                    //delete [] xlower;
+                    //delete [] xdj;
+                    //delete [] xsolution;
+#endif
+                    // put back bounds as they were if was optimal
+                    if (doOriginalTolerance == 2 && cleanDuals != 2) {
+                         changeMade_++; // say something changed
+                         /* We may have already changed some bounds in this function
+                            so save numberFake_ and add in.
+
+                            Worst that can happen is that we waste a bit of time  - but it must be finite.
+                         */
+                         //int saveNumberFake = numberFake_;
+                         //resetFakeBounds(-1);
+                         changeBounds(3, NULL, changeCost);
+                         needCleanFake = true;
+                         //numberFake_ += saveNumberFake;
+                         //resetFakeBounds(-1);
+                         cleanDuals = 2;
+                         //cleanDuals=1;
+                    }
+#if 0
+                    //int i;
+                    for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                         if (cost_[i] != xcost[i])
+                              printf("** %d old cost %g new %g sol %g\n",
+                                     i, xcost[i], cost_[i], solution_[i]);
+                         if (lower_[i] != xlower[i])
+                              printf("** %d old lower %g new %g sol %g\n",
+                                     i, xlower[i], lower_[i], solution_[i]);
+                         if (upper_[i] != xupper[i])
+                              printf("** %d old upper %g new %g sol %g\n",
+                                     i, xupper[i], upper_[i], solution_[i]);
+                         if (dj_[i] != xdj[i])
+                              printf("** %d old dj %g new %g sol %g\n",
+                                     i, xdj[i], dj_[i], solution_[i]);
+                         if (solution_[i] != xsolution[i])
+                              printf("** %d old solution %g new %g sol %g\n",
+                                     i, xsolution[i], solution_[i], solution_[i]);
+                    }
+                    delete [] xcost;
+                    delete [] xupper;
+                    delete [] xlower;
+                    delete [] xdj;
+                    delete [] xsolution;
+#endif
+               }
+               if (cleanDuals == 1 || (cleanDuals == 2 && !numberDualInfeasibilities_)) {
+                    // make sure dual feasible
+                    // look at all rows and columns
+                    rowArray_[0]->clear();
+                    columnArray_[0]->clear();
+                    double objectiveChange = 0.0;
+		    double savePrimalInfeasibilities = sumPrimalInfeasibilities_;
+		    if (!numberIterations_) {
+		      int nTotal = numberRows_ + numberColumns_;
+		      if (arraysNotCreated) {
+			// create save arrays
+			delete [] saveStatus_;
+			delete [] savedSolution_;
+			saveStatus_ = new unsigned char [nTotal];
+			savedSolution_ = new double [nTotal];
+			arraysNotCreated = false;
+		      }
+		      // save arrays
+		      CoinMemcpyN(status_, nTotal, saveStatus_);
+		      CoinMemcpyN(rowActivityWork_,
+				  numberRows_, savedSolution_ + numberColumns_);
+		      CoinMemcpyN(columnActivityWork_, numberColumns_, savedSolution_);
+		    }
+#if 0
+                    double * xcost = new double[numberRows_+numberColumns_];
+                    double * xlower = new double[numberRows_+numberColumns_];
+                    double * xupper = new double[numberRows_+numberColumns_];
+                    double * xdj = new double[numberRows_+numberColumns_];
+                    double * xsolution = new double[numberRows_+numberColumns_];
+                    CoinMemcpyN(cost_, (numberRows_ + numberColumns_), xcost);
+                    CoinMemcpyN(lower_, (numberRows_ + numberColumns_), xlower);
+                    CoinMemcpyN(upper_, (numberRows_ + numberColumns_), xupper);
+                    CoinMemcpyN(dj_, (numberRows_ + numberColumns_), xdj);
+                    CoinMemcpyN(solution_, (numberRows_ + numberColumns_), xsolution);
+#endif
+                    if (givenDuals)
+                         dualTolerance_ = 1.0e50;
+#if CLP_CAN_HAVE_ZERO_OBJ>1
+		    if ((specialOptions_&2097152)==0) {
+#endif
+                    updateDualsInDual(rowArray_[0], columnArray_[0], rowArray_[1],
+                                      0.0, objectiveChange, true);
+#if CLP_CAN_HAVE_ZERO_OBJ>1
+		    } else {
+		      rowArray_[0]->clear();
+		      rowArray_[1]->clear();
+		      columnArray_[0]->clear();
+		    }
+#endif
+                    dualTolerance_ = saveTolerance;
+#if 0
+                    int i;
+                    for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                         if (cost_[i] != xcost[i])
+                              printf("** %d old cost %g new %g sol %g\n",
+                                     i, xcost[i], cost_[i], solution_[i]);
+                         if (lower_[i] != xlower[i])
+                              printf("** %d old lower %g new %g sol %g\n",
+                                     i, xlower[i], lower_[i], solution_[i]);
+                         if (upper_[i] != xupper[i])
+                              printf("** %d old upper %g new %g sol %g\n",
+                                     i, xupper[i], upper_[i], solution_[i]);
+                         if (dj_[i] != xdj[i])
+                              printf("** %d old dj %g new %g sol %g\n",
+                                     i, xdj[i], dj_[i], solution_[i]);
+                         if (solution_[i] != xsolution[i])
+                              printf("** %d old solution %g new %g sol %g\n",
+                                     i, xsolution[i], solution_[i], solution_[i]);
+                    }
+                    delete [] xcost;
+                    delete [] xupper;
+                    delete [] xlower;
+                    delete [] xdj;
+                    delete [] xsolution;
+#endif
+                    // for now - recompute all
+                    gutsOfSolution(NULL, NULL);
+                    if (givenDuals)
+                         dualTolerance_ = 1.0e50;
+#if CLP_CAN_HAVE_ZERO_OBJ>1
+		    if ((specialOptions_&2097152)==0) {
+#endif
+                    updateDualsInDual(rowArray_[0], columnArray_[0], rowArray_[1],
+                                      0.0, objectiveChange, true);
+#if CLP_CAN_HAVE_ZERO_OBJ>1
+		    } else {
+		      rowArray_[0]->clear();
+		      rowArray_[1]->clear();
+		      columnArray_[0]->clear();
+		    }
+#endif
+                    dualTolerance_ = saveTolerance;
+		    if (!numberIterations_ && sumPrimalInfeasibilities_ >
+			1.0e5*(savePrimalInfeasibilities+1.0e3) &&
+			(moreSpecialOptions_ & (256|8192)) == 0) {
+		      // Use primal
+		      int nTotal = numberRows_ + numberColumns_;
+		      CoinMemcpyN(saveStatus_, nTotal, status_);
+		      CoinMemcpyN(savedSolution_ + numberColumns_ ,
+				  numberRows_, rowActivityWork_);
+		      CoinMemcpyN(savedSolution_ ,
+				  numberColumns_, columnActivityWork_);
+		      problemStatus_ = 10;
+		      situationChanged = 0;
+		    }
+                    //assert(numberDualInfeasibilitiesWithoutFree_==0);
+                    if (numberDualInfeasibilities_) {
+		        if ((numberPrimalInfeasibilities_ || numberPivots)
+			    && problemStatus_!=10) {
+                              problemStatus_ = -1; // carry on as normal
+                         } else {
+                              problemStatus_ = 10; // try primal
+#if COIN_DEVELOP>1
+                              printf("returning at %d\n", __LINE__);
+#endif
+                         }
+                    } else if (situationChanged == 2) {
+                         problemStatus_ = -1; // carry on as normal
+                         // need to reset bounds
+                         changeBounds(3, NULL, changeCost);
+                    }
+                    situationChanged = 0;
+               } else {
+                    // iterate
+                    if (cleanDuals != 2) {
+                         problemStatus_ = -1;
+                    } else {
+                         problemStatus_ = 10; // try primal
+#if COIN_DEVELOP>2
+                         printf("returning at %d\n", __LINE__);
+#endif
+                    }
+               }
+          }
+     }
+     // unflag all variables (we may want to wait a bit?)
+     if ((tentativeStatus != -2 && tentativeStatus != -1) && unflagVariables) {
+          int iRow;
+          int numberFlagged = 0;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int iPivot = pivotVariable_[iRow];
+               if (flagged(iPivot)) {
+                    numberFlagged++;
+                    clearFlagged(iPivot);
+               }
+          }
+#ifdef COIN_DEVELOP
+          if (numberFlagged) {
+               printf("unflagging %d variables - tentativeStatus %d probStat %d ninf %d nopt %d\n", numberFlagged, tentativeStatus,
+                      problemStatus_, numberPrimalInfeasibilities_,
+                      numberTimesOptimal_);
+          }
+#endif
+          unflagVariables = numberFlagged > 0;
+          if (numberFlagged && !numberPivots) {
+               /* looks like trouble as we have not done any iterations.
+               Try changing pivot tolerance then give it a few goes and give up */
+               if (factorization_->pivotTolerance() < 0.9) {
+                    factorization_->pivotTolerance(0.99);
+                    problemStatus_ = -1;
+               } else if (numberTimesOptimal_ < 3) {
+                    numberTimesOptimal_++;
+                    problemStatus_ = -1;
+               } else {
+                    unflagVariables = false;
+                    //secondaryStatus_ = 1; // and say probably infeasible
+                    if ((moreSpecialOptions_ & 256) == 0) {
+                         // try primal
+                         problemStatus_ = 10;
+                    } else {
+                         // almost certainly infeasible
+                         problemStatus_ = 1;
+                    }
+#if COIN_DEVELOP>1
+                    printf("returning at %d\n", __LINE__);
+#endif
+               }
+          }
+     }
+     if (problemStatus_ < 0) {
+          if (needCleanFake) {
+               double dummyChangeCost = 0.0;
+               changeBounds(3, NULL, dummyChangeCost);
+          }
+#if 0
+          if (objectiveValue_ < lastObjectiveValue_ - 1.0e-8 *
+                    CoinMax(fabs(objectivevalue_), fabs(lastObjectiveValue_))) {
+          } else {
+               lastObjectiveValue_ = objectiveValue_;
+          }
+#endif
+          if (type == 0 || type == 1) {
+               if (!type && arraysNotCreated) {
+                    // create save arrays
+                    delete [] saveStatus_;
+                    delete [] savedSolution_;
+                    saveStatus_ = new unsigned char [numberRows_+numberColumns_];
+                    savedSolution_ = new double [numberRows_+numberColumns_];
+               }
+               // save arrays
+               CoinMemcpyN(status_, numberColumns_ + numberRows_, saveStatus_);
+               CoinMemcpyN(rowActivityWork_,
+                           numberRows_, savedSolution_ + numberColumns_);
+               CoinMemcpyN(columnActivityWork_, numberColumns_, savedSolution_);
+               // save extra stuff
+               int dummy;
+               matrix_->generalExpanded(this, 5, dummy);
+          }
+          if (weightsSaved) {
+               // restore weights (if saved) - also recompute infeasibility list
+               if (!reallyBadProblems && (largestPrimalError_ < 100.0 || numberPivots > 10)) {
+                    if (tentativeStatus > -3)
+                         dualRowPivot_->saveWeights(this, (type < 2) ? 2 : 4);
+                    else
+                         dualRowPivot_->saveWeights(this, 3);
+               } else {
+                    // reset weights or scale back
+                    dualRowPivot_->saveWeights(this, 6);
+               }
+          } else if (weightsSaved2 && numberPrimalInfeasibilities_) {
+               dualRowPivot_->saveWeights(this, 3);
+          }
+     }
+     // see if cutoff reached
+     double limit = 0.0;
+     getDblParam(ClpDualObjectiveLimit, limit);
+#if 0
+     if(fabs(limit) < 1.0e30 && objectiveValue()*optimizationDirection_ >
+               limit + 100.0) {
+          printf("lim %g obj %g %g - wo perturb %g sum dual %g\n",
+                 limit, objectiveValue_, objectiveValue(), computeInternalObjectiveValue(), sumDualInfeasibilities_);
+     }
+#endif
+     if(fabs(limit) < 1.0e30 && objectiveValue()*optimizationDirection_ >
+               limit && !numberAtFakeBound()) {
+          bool looksInfeasible = !numberDualInfeasibilities_;
+          if (objectiveValue()*optimizationDirection_ > limit + fabs(0.1 * limit) + 1.0e2 * sumDualInfeasibilities_ + 1.0e4 &&
+                    sumDualInfeasibilities_ < largestDualError_ && numberIterations_ > 0.5 * numberRows_ + 1000)
+               looksInfeasible = true;
+          if (looksInfeasible) {
+               // Even if not perturbed internal costs may have changed
+               // be careful
+               if (true || numberIterations_) {
+                    if(computeInternalObjectiveValue() > limit) {
+                         problemStatus_ = 1;
+                         secondaryStatus_ = 1; // and say was on cutoff
+                    }
+               } else {
+                    problemStatus_ = 1;
+                    secondaryStatus_ = 1; // and say was on cutoff
+               }
+          }
+     }
+     // If we are in trouble and in branch and bound give up
+     if ((specialOptions_ & 1024) != 0) {
+          int looksBad = 0;
+          if (largestPrimalError_ * largestDualError_ > 1.0e2) {
+               looksBad = 1;
+          } else if (largestPrimalError_ > 1.0e-2
+                     && objectiveValue_ > CoinMin(1.0e15, 1.0e3 * limit)) {
+               looksBad = 2;
+          }
+          if (looksBad) {
+               if (factorization_->pivotTolerance() < 0.9) {
+                    // up tolerance
+                    factorization_->pivotTolerance(CoinMin(factorization_->pivotTolerance() * 1.05 + 0.02, 0.91));
+               } else if (numberIterations_ > 10000) {
+                    if (handler_->logLevel() > 2)
+                         printf("bad dual - saying infeasible %d\n", looksBad);
+                    problemStatus_ = 1;
+                    secondaryStatus_ = 1; // and say was on cutoff
+               } else if (largestPrimalError_ > 1.0e5) {
+                    {
+		      //int iBigB = -1;
+                         double bigB = 0.0;
+                         //int iBigN = -1;
+                         double bigN = 0.0;
+                         for (int i = 0; i < numberRows_ + numberColumns_; i++) {
+                              double value = fabs(solution_[i]);
+                              if (getStatus(i) == basic) {
+                                   if (value > bigB) {
+                                        bigB = value;
+                                        //iBigB = i;
+                                   }
+                              } else {
+                                   if (value > bigN) {
+                                        bigN = value;
+                                        //iBigN = i;
+                                   }
+                              }
+                         }
+#ifdef CLP_INVESTIGATE
+                         if (bigB > 1.0e8 || bigN > 1.0e8) {
+                              if (handler_->logLevel() > 0)
+                                   printf("it %d - basic %d %g, nonbasic %d %g\n",
+                                          numberIterations_, iBigB, bigB, iBigN, bigN);
+                         }
+#endif
+                    }
+#if COIN_DEVELOP!=2
+                    if (handler_->logLevel() > 2)
+#endif
+                         printf("bad dual - going to primal %d %g\n", looksBad, largestPrimalError_);
+                    allSlackBasis(true);
+                    problemStatus_ = 10;
+               }
+          }
+     }
+     if (problemStatus_ < 0 && !changeMade_) {
+          problemStatus_ = 4; // unknown
+     }
+     lastGoodIteration_ = numberIterations_;
+     if (numberIterations_ > lastBadIteration_ + 100)
+          moreSpecialOptions_ &= ~16; // clear check accuracy flag
+     if (problemStatus_ < 0) {
+          sumDualInfeasibilities_ = realDualInfeasibilities; // back to say be careful
+          if (sumDualInfeasibilities_)
+               numberDualInfeasibilities_ = 1;
+     }
+#ifdef CLP_REPORT_PROGRESS
+     if (ixxxxxx > ixxyyyy - 3) {
+          printf("objectiveValue_ %g\n", objectiveValue_);
+          handler_->setLogLevel(63);
+          int nTotal = numberColumns_ + numberRows_;
+          double newObj = 0.0;
+          for (int i = 0; i < nTotal; i++) {
+               if (solution_[i])
+                    newObj += solution_[i] * cost_[i];
+          }
+          printf("xxx obj %g\n", newObj);
+          // for now - recompute all
+          gutsOfSolution(NULL, NULL);
+          newObj = 0.0;
+          for (int i = 0; i < nTotal; i++) {
+               if (solution_[i])
+                    newObj += solution_[i] * cost_[i];
+          }
+          printf("yyy obj %g %g\n", newObj, objectiveValue_);
+          progress_.modifyObjective(objectiveValue_
+                                    - bestPossibleImprovement_);
+     }
+#endif
+#if 1
+     double thisObj = progress_.lastObjective(0);
+     double lastObj = progress_.lastObjective(1);
+     if (lastObj > thisObj + 1.0e-4 * CoinMax(fabs(thisObj), fabs(lastObj)) + 1.0e-4
+               && givenDuals == NULL && firstFree_ < 0) {
+          int maxFactor = factorization_->maximumPivots();
+          if (maxFactor > 10) {
+               if (forceFactorization_ < 0)
+                    forceFactorization_ = maxFactor;
+               forceFactorization_ = CoinMax(1, (forceFactorization_ >> 1));
+               //printf("Reducing factorization frequency\n");
+          }
+     }
+#endif
+     // Allow matrices to be sorted etc
+     int fake = -999; // signal sort
+     matrix_->correctSequence(this, fake, fake);
+     if (alphaAccuracy_ > 0.0)
+          alphaAccuracy_ = 1.0;
+     // If we are stopping - use plausible objective
+     // Maybe only in fast dual
+     if (problemStatus_ > 2)
+          objectiveValue_ = approximateObjective;
+     if (problemStatus_ == 1 && (progressFlag_&8) != 0 &&
+	 fabs(objectiveValue_) > 1.0e10 )
+       problemStatus_ = 10; // infeasible - but has looked feasible
+}
+/* While updateDualsInDual sees what effect is of flip
+   this does actual flipping.
+   If change >0.0 then value in array >0.0 => from lower to upper
+*/
+void
+ClpSimplexDual::flipBounds(CoinIndexedVector * rowArray,
+                           CoinIndexedVector * columnArray)
+{
+     int number;
+     int * which;
+
+     int iSection;
+
+     for (iSection = 0; iSection < 2; iSection++) {
+          int i;
+          double * solution = solutionRegion(iSection);
+          double * lower = lowerRegion(iSection);
+          double * upper = upperRegion(iSection);
+          int addSequence;
+          if (!iSection) {
+               number = rowArray->getNumElements();
+               which = rowArray->getIndices();
+               addSequence = numberColumns_;
+          } else {
+               number = columnArray->getNumElements();
+               which = columnArray->getIndices();
+               addSequence = 0;
+          }
+
+          for (i = 0; i < number; i++) {
+               int iSequence = which[i];
+               Status status = getStatus(iSequence + addSequence);
+
+               switch(status) {
+
+               case basic:
+               case isFree:
+               case superBasic:
+               case ClpSimplex::isFixed:
+                    break;
+               case atUpperBound:
+                    // to lower bound
+                    setStatus(iSequence + addSequence, atLowerBound);
+                    solution[iSequence] = lower[iSequence];
+                    break;
+               case atLowerBound:
+                    // to upper bound
+                    setStatus(iSequence + addSequence, atUpperBound);
+                    solution[iSequence] = upper[iSequence];
+                    break;
+               }
+          }
+     }
+     rowArray->setNumElements(0);
+     columnArray->setNumElements(0);
+}
+// Restores bound to original bound
+void
+ClpSimplexDual::originalBound( int iSequence)
+{
+     if (getFakeBound(iSequence) != noFake) {
+          numberFake_--;;
+          setFakeBound(iSequence, noFake);
+          if (iSequence >= numberColumns_) {
+               // rows
+               int iRow = iSequence - numberColumns_;
+               rowLowerWork_[iRow] = rowLower_[iRow];
+               rowUpperWork_[iRow] = rowUpper_[iRow];
+               if (rowScale_) {
+                    if (rowLowerWork_[iRow] > -1.0e50)
+                         rowLowerWork_[iRow] *= rowScale_[iRow] * rhsScale_;
+                    if (rowUpperWork_[iRow] < 1.0e50)
+                         rowUpperWork_[iRow] *= rowScale_[iRow] * rhsScale_;
+               } else if (rhsScale_ != 1.0) {
+                    if (rowLowerWork_[iRow] > -1.0e50)
+                         rowLowerWork_[iRow] *= rhsScale_;
+                    if (rowUpperWork_[iRow] < 1.0e50)
+                         rowUpperWork_[iRow] *= rhsScale_;
+               }
+          } else {
+               // columns
+               columnLowerWork_[iSequence] = columnLower_[iSequence];
+               columnUpperWork_[iSequence] = columnUpper_[iSequence];
+               if (rowScale_) {
+                    double multiplier = 1.0 * inverseColumnScale_[iSequence];
+                    if (columnLowerWork_[iSequence] > -1.0e50)
+                         columnLowerWork_[iSequence] *= multiplier * rhsScale_;
+                    if (columnUpperWork_[iSequence] < 1.0e50)
+                         columnUpperWork_[iSequence] *= multiplier * rhsScale_;
+               } else if (rhsScale_ != 1.0) {
+                    if (columnLowerWork_[iSequence] > -1.0e50)
+                         columnLowerWork_[iSequence] *= rhsScale_;
+                    if (columnUpperWork_[iSequence] < 1.0e50)
+                         columnUpperWork_[iSequence] *= rhsScale_;
+               }
+          }
+     }
+}
+/* As changeBounds but just changes new bounds for a single variable.
+   Returns true if change */
+bool
+ClpSimplexDual::changeBound( int iSequence)
+{
+     // old values
+     double oldLower = lower_[iSequence];
+     double oldUpper = upper_[iSequence];
+     double value = solution_[iSequence];
+     bool modified = false;
+     originalBound(iSequence);
+     // original values
+     double lowerValue = lower_[iSequence];
+     double upperValue = upper_[iSequence];
+     // back to altered values
+     lower_[iSequence] = oldLower;
+     upper_[iSequence] = oldUpper;
+     assert (getFakeBound(iSequence) == noFake);
+     //if (getFakeBound(iSequence)!=noFake)
+     //numberFake_--;;
+     if (value == oldLower) {
+          if (upperValue > oldLower + dualBound_) {
+               upper_[iSequence] = oldLower + dualBound_;
+               setFakeBound(iSequence, upperFake);
+               modified = true;
+               numberFake_++;
+          }
+     } else if (value == oldUpper) {
+          if (lowerValue < oldUpper - dualBound_) {
+               lower_[iSequence] = oldUpper - dualBound_;
+               setFakeBound(iSequence, lowerFake);
+               modified = true;
+               numberFake_++;
+          }
+     } else {
+          assert(value == oldLower || value == oldUpper);
+     }
+     return modified;
+}
+#if ABC_NORMAL_DEBUG>0
+//#define PERT_STATISTICS
+#endif
+#ifdef PERT_STATISTICS
+static void breakdown(const char * name, int numberLook, const double * region)
+{
+     double range[] = {
+          -COIN_DBL_MAX,
+          -1.0e15, -1.0e11, -1.0e8, -1.0e5, -1.0e4, -1.0e3, -1.0e2, -1.0e1,
+          -1.0,
+          -1.0e-1, -1.0e-2, -1.0e-3, -1.0e-4, -1.0e-5, -1.0e-8, -1.0e-11, -1.0e-15,
+          0.0,
+          1.0e-15, 1.0e-11, 1.0e-8, 1.0e-5, 1.0e-4, 1.0e-3, 1.0e-2, 1.0e-1,
+          1.0,
+          1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e8, 1.0e11, 1.0e15,
+          COIN_DBL_MAX
+     };
+     int nRanges = static_cast<int> (sizeof(range) / sizeof(double));
+     int * number = new int[nRanges];
+     memset(number, 0, nRanges * sizeof(int));
+     int * numberExact = new int[nRanges];
+     memset(numberExact, 0, nRanges * sizeof(int));
+     int i;
+     for ( i = 0; i < numberLook; i++) {
+          double value = region[i];
+          for (int j = 0; j < nRanges; j++) {
+               if (value == range[j]) {
+                    numberExact[j]++;
+                    break;
+               } else if (value < range[j]) {
+                    number[j]++;
+                    break;
+               }
+          }
+     }
+     printf("\n%s has %d entries\n", name, numberLook);
+     for (i = 0; i < nRanges; i++) {
+          if (number[i])
+               printf("%d between %g and %g", number[i], range[i-1], range[i]);
+          if (numberExact[i]) {
+               if (number[i])
+                    printf(", ");
+               printf("%d exactly at %g", numberExact[i], range[i]);
+          }
+          if (number[i] + numberExact[i])
+               printf("\n");
+     }
+     delete [] number;
+     delete [] numberExact;
+}
+#endif
+// Perturbs problem
+int
+ClpSimplexDual::perturb()
+{
+     if (perturbation_ > 100)
+          return 0; //perturbed already
+     if (perturbation_ == 100)
+          perturbation_ = 50; // treat as normal
+     int savePerturbation = perturbation_;
+     bool modifyRowCosts = false;
+     // dual perturbation
+     double perturbation = 1.0e-20;
+     // maximum fraction of cost to perturb
+     double maximumFraction = 1.0e-5;
+     double constantPerturbation = 100.0 * dualTolerance_;
+     int maxLength = 0;
+     int minLength = numberRows_;
+     double averageCost = 0.0;
+#if 0
+     // look at element range
+     double smallestNegative;
+     double largestNegative;
+     double smallestPositive;
+     double largestPositive;
+     matrix_->rangeOfElements(smallestNegative, largestNegative,
+                              smallestPositive, largestPositive);
+     smallestPositive = CoinMin(fabs(smallestNegative), smallestPositive);
+     largestPositive = CoinMax(fabs(largestNegative), largestPositive);
+     double elementRatio = largestPositive / smallestPositive;
+#endif
+     int numberNonZero = 0;
+     if (!numberIterations_ && perturbation_ >= 50) {
+          // See if we need to perturb
+          double * sort = new double[numberColumns_];
+          // Use objective BEFORE scaling
+          const double * obj = ((moreSpecialOptions_ & 128) == 0) ? objective() : cost_;
+          int i;
+          for (i = 0; i < numberColumns_; i++) {
+               double value = fabs(obj[i]);
+               sort[i] = value;
+               averageCost += value;
+               if (value)
+                    numberNonZero++;
+          }
+          if (numberNonZero)
+               averageCost /= static_cast<double> (numberNonZero);
+          else
+               averageCost = 1.0;
+          std::sort(sort, sort + numberColumns_);
+          int number = 1;
+          double last = sort[0];
+          for (i = 1; i < numberColumns_; i++) {
+               if (last != sort[i])
+                    number++;
+               last = sort[i];
+          }
+          delete [] sort;
+          if (!numberNonZero && perturbation_ < 55)
+               return 1; // safer to use primal
+#if 0
+          printf("nnz %d percent %d", number, (number * 100) / numberColumns_);
+          if (number * 4 > numberColumns_)
+               printf(" - Would not perturb\n");
+          else
+               printf(" - Would perturb\n");
+          //exit(0);
+#endif
+          //printf("ratio number diff costs %g, element ratio %g\n",((double)number)/((double) numberColumns_),
+          //								      elementRatio);
+          //number=0;
+          //if (number*4>numberColumns_||elementRatio>1.0e12) {
+          if (number * 4 > numberColumns_) {
+               perturbation_ = 100;
+               return 0; // good enough
+          }
+     }
+     int iColumn;
+     const int * columnLength = matrix_->getVectorLengths();
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (columnLowerWork_[iColumn] < columnUpperWork_[iColumn]) {
+               int length = columnLength[iColumn];
+               if (length > 2) {
+                    maxLength = CoinMax(maxLength, length);
+                    minLength = CoinMin(minLength, length);
+               }
+          }
+     }
+     // If > 70 then do rows
+     if (perturbation_ >= 70) {
+          modifyRowCosts = true;
+          perturbation_ -= 20;
+          printf("Row costs modified, ");
+     }
+     bool uniformChange = false;
+     bool inCbcOrOther = (specialOptions_ & 0x03000000) != 0;
+     if (perturbation_ > 50) {
+          // Experiment
+          // maximumFraction could be 1.0e-10 to 1.0
+          double m[] = {1.0e-10, 1.0e-9, 1.0e-8, 1.0e-7, 1.0e-6, 1.0e-5, 1.0e-4, 1.0e-3, 1.0e-2, 1.0e-1, 1.0};
+          int whichOne = perturbation_ - 51;
+          //if (inCbcOrOther&&whichOne>0)
+          //whichOne--;
+          maximumFraction = m[CoinMin(whichOne, 10)];
+     } else if (inCbcOrOther) {
+          //maximumFraction = 1.0e-6;
+     }
+     int iRow;
+     double smallestNonZero = 1.0e100;
+     numberNonZero = 0;
+     if (perturbation_ >= 50) {
+          perturbation = 1.0e-8;
+	  if (perturbation_ > 50 && perturbation_ < 60) 
+	    perturbation = CoinMax(1.0e-8,maximumFraction);
+          bool allSame = true;
+          double lastValue = 0.0;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               double lo = rowLowerWork_[iRow];
+               double up = rowUpperWork_[iRow];
+               if (lo < up) {
+                    double value = fabs(rowObjectiveWork_[iRow]);
+                    perturbation = CoinMax(perturbation, value);
+                    if (value) {
+                         modifyRowCosts = true;
+                         smallestNonZero = CoinMin(smallestNonZero, value);
+                    }
+               }
+               if (lo && lo > -1.0e10) {
+                    numberNonZero++;
+                    lo = fabs(lo);
+                    if (!lastValue)
+                         lastValue = lo;
+                    else if (fabs(lo - lastValue) > 1.0e-7)
+                         allSame = false;
+               }
+               if (up && up < 1.0e10) {
+                    numberNonZero++;
+                    up = fabs(up);
+                    if (!lastValue)
+                         lastValue = up;
+                    else if (fabs(up - lastValue) > 1.0e-7)
+                         allSame = false;
+               }
+          }
+          double lastValue2 = 0.0;
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               double lo = columnLowerWork_[iColumn];
+               double up = columnUpperWork_[iColumn];
+               if (lo < up) {
+                    double value =
+                         fabs(objectiveWork_[iColumn]);
+                    perturbation = CoinMax(perturbation, value);
+                    if (value) {
+                         smallestNonZero = CoinMin(smallestNonZero, value);
+                    }
+               }
+               if (lo && lo > -1.0e10) {
+                    //numberNonZero++;
+                    lo = fabs(lo);
+                    if (!lastValue2)
+                         lastValue2 = lo;
+                    else if (fabs(lo - lastValue2) > 1.0e-7)
+                         allSame = false;
+               }
+               if (up && up < 1.0e10) {
+                    //numberNonZero++;
+                    up = fabs(up);
+                    if (!lastValue2)
+                         lastValue2 = up;
+                    else if (fabs(up - lastValue2) > 1.0e-7)
+                         allSame = false;
+               }
+          }
+          if (allSame) {
+               // Check elements
+               double smallestNegative;
+               double largestNegative;
+               double smallestPositive;
+               double largestPositive;
+               matrix_->rangeOfElements(smallestNegative, largestNegative,
+                                        smallestPositive, largestPositive);
+               if (smallestNegative == largestNegative &&
+                         smallestPositive == largestPositive) {
+                    // Really hit perturbation
+                    double adjust = CoinMin(100.0 * maximumFraction, 1.0e-3 * CoinMax(lastValue, lastValue2));
+                    maximumFraction = CoinMax(adjust, maximumFraction);
+               }
+          }
+          perturbation = CoinMin(perturbation, smallestNonZero / maximumFraction);
+     } else {
+          // user is in charge
+          maximumFraction = 1.0e-1;
+          // but some experiments
+          if (perturbation_ <= -900) {
+               modifyRowCosts = true;
+               perturbation_ += 1000;
+               printf("Row costs modified, ");
+          }
+          if (perturbation_ <= -10) {
+               perturbation_ += 10;
+               maximumFraction = 1.0;
+               if ((-perturbation_) % 100 >= 10) {
+                    uniformChange = true;
+                    perturbation_ += 20;
+               }
+               while (perturbation_ < -10) {
+                    perturbation_ += 100;
+                    maximumFraction *= 1.0e-1;
+               }
+          }
+          perturbation = pow(10.0, perturbation_);
+     }
+     double largestZero = 0.0;
+     double largest = 0.0;
+     double largestPerCent = 0.0;
+     // modify costs
+     bool printOut = (handler_->logLevel() == 63);
+     printOut = false;
+     //assert (!modifyRowCosts);
+     modifyRowCosts = false;
+     if (modifyRowCosts) {
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if (rowLowerWork_[iRow] < rowUpperWork_[iRow]) {
+                    double value = perturbation;
+                    double currentValue = rowObjectiveWork_[iRow];
+                    value = CoinMin(value, maximumFraction * (fabs(currentValue) + 1.0e-1 * perturbation + 1.0e-3));
+                    if (rowLowerWork_[iRow] > -largeValue_) {
+                         if (fabs(rowLowerWork_[iRow]) < fabs(rowUpperWork_[iRow]))
+                              value *= randomNumberGenerator_.randomDouble();
+                         else
+                              value *= -randomNumberGenerator_.randomDouble();
+                    } else if (rowUpperWork_[iRow] < largeValue_) {
+                         value *= -randomNumberGenerator_.randomDouble();
+                    } else {
+                         value = 0.0;
+                    }
+                    if (currentValue) {
+                         largest = CoinMax(largest, fabs(value));
+                         if (fabs(value) > fabs(currentValue)*largestPerCent)
+                              largestPerCent = fabs(value / currentValue);
+                    } else {
+                         largestZero = CoinMax(largestZero, fabs(value));
+                    }
+                    if (printOut)
+                         printf("row %d cost %g change %g\n", iRow, rowObjectiveWork_[iRow], value);
+                    rowObjectiveWork_[iRow] += value;
+               }
+          }
+     }
+     // more its but faster double weight[]={1.0e-4,1.0e-2,1.0e-1,1.0,2.0,10.0,100.0,200.0,400.0,600.0,1000.0};
+     // good its double weight[]={1.0e-4,1.0e-2,5.0e-1,1.0,2.0,5.0,10.0,20.0,30.0,40.0,100.0};
+     double weight[] = {1.0e-4, 1.0e-2, 5.0e-1, 1.0, 2.0, 5.0, 10.0, 20.0, 30.0, 40.0, 100.0};
+     //double weight[]={1.0e-4,1.0e-2,5.0e-1,1.0,20.0,50.0,100.0,120.0,130.0,140.0,200.0};
+     //double extraWeight = 10.0;
+     // Scale back if wanted
+     double weight2[] = {1.0e-4, 1.0e-2, 5.0e-1, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
+     if (constantPerturbation < 99.0 * dualTolerance_) {
+          perturbation *= 0.1;
+          //extraWeight = 0.5;
+          memcpy(weight, weight2, sizeof(weight2));
+     }
+     // adjust weights if all columns long
+     double factor = 1.0;
+     if (maxLength) {
+          factor = 3.0 / static_cast<double> (minLength);
+     }
+     // Make variables with more elements more expensive
+     const double m1 = 0.5;
+     double smallestAllowed = CoinMin(1.0e-2 * dualTolerance_, maximumFraction);
+     double largestAllowed = CoinMax(1.0e3 * dualTolerance_, maximumFraction * averageCost);
+     // smaller if in BAB
+     //if (inCbcOrOther)
+     //largestAllowed=CoinMin(largestAllowed,1.0e-5);
+     //smallestAllowed = CoinMin(smallestAllowed,0.1*largestAllowed);
+#define SAVE_PERT
+#ifdef SAVE_PERT
+     if (2 * numberColumns_ > maximumPerturbationSize_) {
+          delete [] perturbationArray_;
+          maximumPerturbationSize_ = 2 * numberColumns_;
+          perturbationArray_ = new double [maximumPerturbationSize_];
+          for (iColumn = 0; iColumn < maximumPerturbationSize_; iColumn++) {
+               perturbationArray_[iColumn] = randomNumberGenerator_.randomDouble();
+          }
+     }
+#endif
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (columnLowerWork_[iColumn] < columnUpperWork_[iColumn] && getStatus(iColumn) != basic) {
+               double value = perturbation;
+               double currentValue = objectiveWork_[iColumn];
+               value = CoinMin(value, constantPerturbation + maximumFraction * (fabs(currentValue) + 1.0e-1 * perturbation + 1.0e-8));
+               //value = CoinMin(value,constantPerturbation;+maximumFraction*fabs(currentValue));
+               double value2 = constantPerturbation + 1.0e-1 * smallestNonZero;
+               if (uniformChange) {
+                    value = maximumFraction;
+                    value2 = maximumFraction;
+               }
+               if (columnLowerWork_[iColumn] > -largeValue_) {
+                    if (fabs(columnLowerWork_[iColumn]) <
+                              fabs(columnUpperWork_[iColumn])) {
+#ifndef SAVE_PERT
+                         value *= (1.0 - m1 + m1 * randomNumberGenerator_.randomDouble());
+                         value2 *= (1.0 - m1 + m1 * randomNumberGenerator_.randomDouble());
+#else
+                         value *= (1.0 - m1 + m1 * perturbationArray_[2*iColumn]);
+                         value2 *= (1.0 - m1 + m1 * perturbationArray_[2*iColumn+1]);
+#endif
+                    } else {
+                         //value *= -(1.0-m1+m1*randomNumberGenerator_.randomDouble());
+                         //value2 *= -(1.0-m1+m1*randomNumberGenerator_.randomDouble());
+                         value = 0.0;
+                    }
+               } else if (columnUpperWork_[iColumn] < largeValue_) {
+#ifndef SAVE_PERT
+                    value *= -(1.0 - m1 + m1 * randomNumberGenerator_.randomDouble());
+                    value2 *= -(1.0 - m1 + m1 * randomNumberGenerator_.randomDouble());
+#else
+                    value *= -(1.0 - m1 + m1 * perturbationArray_[2*iColumn]);
+                    value2 *= -(1.0 - m1 + m1 * perturbationArray_[2*iColumn+1]);
+#endif
+               } else {
+                    value = 0.0;
+               }
+               if (value) {
+                    int length = columnLength[iColumn];
+                    if (length > 3) {
+                         length = static_cast<int> (static_cast<double> (length) * factor);
+                         length = CoinMax(3, length);
+                    }
+                    double multiplier;
+#if 1
+                    if (length < 10)
+                         multiplier = weight[length];
+                    else
+                         multiplier = weight[10];
+#else
+                    if (length < 10)
+                         multiplier = weight[length];
+                    else
+                         multiplier = weight[10] + extraWeight * (length - 10);
+                    multiplier *= 0.5;
+#endif
+                    value *= multiplier;
+                    value = CoinMin(value, value2);
+                    if (savePerturbation < 50 || savePerturbation > 60) {
+                         if (fabs(value) <= dualTolerance_)
+                              value = 0.0;
+                    } else if (value) {
+                         // get in range
+                         if (fabs(value) <= smallestAllowed) {
+                              value *= 10.0;
+                              while (fabs(value) <= smallestAllowed)
+                                   value *= 10.0;
+                         } else if (fabs(value) > largestAllowed) {
+                              value *= 0.1;
+                              while (fabs(value) > largestAllowed)
+                                   value *= 0.1;
+                         }
+                    }
+                    if (currentValue) {
+                         largest = CoinMax(largest, fabs(value));
+                         if (fabs(value) > fabs(currentValue)*largestPerCent)
+                              largestPerCent = fabs(value / currentValue);
+                    } else {
+                         largestZero = CoinMax(largestZero, fabs(value));
+                    }
+                    // but negative if at ub
+                    if (getStatus(iColumn) == atUpperBound)
+                         value = -value;
+                    if (printOut)
+                         printf("col %d cost %g change %g\n", iColumn, objectiveWork_[iColumn], value);
+                    objectiveWork_[iColumn] += value;
+               }
+          }
+     }
+     handler_->message(CLP_SIMPLEX_PERTURB, messages_)
+               << 100.0 * maximumFraction << perturbation << largest << 100.0 * largestPerCent << largestZero
+               << CoinMessageEol;
+     // and zero changes
+     //int nTotal = numberRows_+numberColumns_;
+     //CoinZeroN(cost_+nTotal,nTotal);
+     // say perturbed
+#ifdef PERT_STATISTICS
+  {
+    double averageCost = 0.0;
+    int numberNonZero = 0;
+    double * COIN_RESTRICT sort = new double[numberColumns_];
+    for (int i = 0; i < numberColumns_; i++) {
+      double value = fabs(cost_[i]);
+      sort[i] = value;
+      averageCost += value;
+      if (value)
+	numberNonZero++;
+    }
+    if (numberNonZero)
+      averageCost /= static_cast<double> (numberNonZero);
+    else
+      averageCost = 1.0;
+    std::sort(sort, sort + numberColumns_);
+    int number = 1;
+    double last = sort[0];
+    for (int i = 1; i < numberColumns_; i++) {
+      if (last != sort[i])
+	number++;
+    last = sort[i];
+    }
+    printf("nnz %d percent %d", number, (number * 100) / numberColumns_);
+    delete [] sort;
+    breakdown("Objective", numberColumns_+numberRows_, cost_);
+  }
+#endif
+     perturbation_ = 101;
+     return 0;
+}
+/* For strong branching.  On input lower and upper are new bounds
+   while on output they are change in objective function values
+   (>1.0e50 infeasible).
+   Return code is 0 if nothing interesting, -1 if infeasible both
+   ways and +1 if infeasible one way (check values to see which one(s))
+   Returns -2 if bad factorization
+*/
+int ClpSimplexDual::strongBranching(int numberVariables, const int * variables,
+                                    double * newLower, double * newUpper,
+                                    double ** outputSolution,
+                                    int * outputStatus, int * outputIterations,
+                                    bool stopOnFirstInfeasible,
+                                    bool alwaysFinish,
+                                    int startFinishOptions)
+{
+     int i;
+     int returnCode = 0;
+     double saveObjectiveValue = objectiveValue_;
+     algorithm_ = -1;
+
+     //scaling(false);
+
+     // put in standard form (and make row copy)
+     // create modifiable copies of model rim and do optional scaling
+     createRim(7 + 8 + 16 + 32, true, startFinishOptions);
+
+     // change newLower and newUpper if scaled
+
+     // Do initial factorization
+     // and set certain stuff
+     // We can either set increasing rows so ...IsBasic gives pivot row
+     // or we can just increment iBasic one by one
+     // for now let ...iBasic give pivot row
+     int useFactorization = false;
+     if ((startFinishOptions & 2) != 0 && (whatsChanged_&(2 + 512)) == 2 + 512)
+          useFactorization = true; // Keep factorization if possible
+     // switch off factorization if bad
+     if (pivotVariable_[0] < 0)
+          useFactorization = false;
+     if (!useFactorization || factorization_->numberRows() != numberRows_) {
+          useFactorization = false;
+          factorization_->setDefaultValues();
+
+          int factorizationStatus = internalFactorize(0);
+          if (factorizationStatus < 0) {
+               // some error
+               // we should either debug or ignore
+#ifndef NDEBUG
+               printf("***** ClpDual strong branching factorization error - debug\n");
+#endif
+               return -2;
+          } else if (factorizationStatus && factorizationStatus <= numberRows_) {
+               handler_->message(CLP_SINGULARITIES, messages_)
+                         << factorizationStatus
+                         << CoinMessageEol;
+          }
+     }
+     // save stuff
+     ClpFactorization saveFactorization(*factorization_);
+     // Get fake bounds correctly
+     double changeCost;
+     changeBounds(3, NULL, changeCost);
+     int saveNumberFake = numberFake_;
+     // save basis and solution
+     double * saveSolution = new double[numberRows_+numberColumns_];
+     CoinMemcpyN(solution_,
+                 numberRows_ + numberColumns_, saveSolution);
+     unsigned char * saveStatus =
+          new unsigned char [numberRows_+numberColumns_];
+     CoinMemcpyN(status_, numberColumns_ + numberRows_, saveStatus);
+     // save bounds as createRim makes clean copies
+     double * saveLower = new double[numberRows_+numberColumns_];
+     CoinMemcpyN(lower_,
+                 numberRows_ + numberColumns_, saveLower);
+     double * saveUpper = new double[numberRows_+numberColumns_];
+     CoinMemcpyN(upper_,
+                 numberRows_ + numberColumns_, saveUpper);
+     double * saveObjective = new double[numberRows_+numberColumns_];
+     CoinMemcpyN(cost_,
+                 numberRows_ + numberColumns_, saveObjective);
+     int * savePivot = new int [numberRows_];
+     CoinMemcpyN(pivotVariable_, numberRows_, savePivot);
+     // need to save/restore weights.
+
+     int iSolution = 0;
+     for (i = 0; i < numberVariables; i++) {
+          int iColumn = variables[i];
+          double objectiveChange;
+          double saveBound;
+
+          // try down
+
+          saveBound = columnUpper_[iColumn];
+          // external view - in case really getting optimal
+          columnUpper_[iColumn] = newUpper[i];
+          assert (inverseColumnScale_ || scalingFlag_ <= 0);
+          if (scalingFlag_ <= 0)
+               upper_[iColumn] = newUpper[i] * rhsScale_;
+          else
+               upper_[iColumn] = (newUpper[i] * inverseColumnScale_[iColumn]) * rhsScale_; // scale
+          // Start of fast iterations
+          int status = fastDual(alwaysFinish);
+          CoinAssert (problemStatus_ || objectiveValue_ < 1.0e50);
+#ifdef CLP_DEBUG
+	  printf("first status %d obj %g\n",problemStatus_,objectiveValue_);
+#endif
+	  if(problemStatus_==10) 
+ 	      problemStatus_=3;
+          // make sure plausible
+          double obj = CoinMax(objectiveValue_, saveObjectiveValue);
+          if (status && problemStatus_ != 3) {
+               // not finished - might be optimal
+               checkPrimalSolution(rowActivityWork_, columnActivityWork_);
+               double limit = 0.0;
+               getDblParam(ClpDualObjectiveLimit, limit);
+               if (!numberPrimalInfeasibilities_ && obj < limit) {
+                    problemStatus_ = 0;
+               }
+               status = problemStatus_;
+          }
+          if (problemStatus_ == 3)
+               status = 2;
+          if (status || (problemStatus_ == 0 && !isDualObjectiveLimitReached())) {
+               objectiveChange = obj - saveObjectiveValue;
+          } else {
+               objectiveChange = 1.0e100;
+               status = 1;
+          }
+
+          if (scalingFlag_ <= 0) {
+               CoinMemcpyN(solution_, numberColumns_, outputSolution[iSolution]);
+          } else {
+               int j;
+               double * sol = outputSolution[iSolution];
+               for (j = 0; j < numberColumns_; j++)
+                    sol[j] = solution_[j] * columnScale_[j];
+          }
+          outputStatus[iSolution] = status;
+          outputIterations[iSolution] = numberIterations_;
+          iSolution++;
+          // restore
+          numberFake_ = saveNumberFake;
+          CoinMemcpyN(saveSolution,
+                      numberRows_ + numberColumns_, solution_);
+          CoinMemcpyN(saveStatus, numberColumns_ + numberRows_, status_);
+          CoinMemcpyN(saveLower,
+                      numberRows_ + numberColumns_, lower_);
+          CoinMemcpyN(saveUpper,
+                      numberRows_ + numberColumns_, upper_);
+          CoinMemcpyN(saveObjective,
+                      numberRows_ + numberColumns_, cost_);
+          columnUpper_[iColumn] = saveBound;
+          CoinMemcpyN(savePivot, numberRows_, pivotVariable_);
+          //delete factorization_;
+          //factorization_ = new ClpFactorization(saveFactorization,numberRows_);
+          setFactorization(saveFactorization);
+          newUpper[i] = objectiveChange;
+#ifdef CLP_DEBUG
+          printf("down on %d costs %g\n", iColumn, objectiveChange);
+#endif
+
+          // try up
+
+          saveBound = columnLower_[iColumn];
+          // external view - in case really getting optimal
+          columnLower_[iColumn] = newLower[i];
+          assert (inverseColumnScale_ || scalingFlag_ <= 0);
+          if (scalingFlag_ <= 0)
+               lower_[iColumn] = newLower[i] * rhsScale_;
+          else
+               lower_[iColumn] = (newLower[i] * inverseColumnScale_[iColumn]) * rhsScale_; // scale
+          // Start of fast iterations
+          status = fastDual(alwaysFinish);
+	  CoinAssert (problemStatus_||objectiveValue_<1.0e50);
+#ifdef CLP_DEBUG
+	  printf("second status %d obj %g\n",problemStatus_,objectiveValue_);
+#endif
+	  if(problemStatus_==10) 
+	      problemStatus_=3;
+          // make sure plausible
+          obj = CoinMax(objectiveValue_, saveObjectiveValue);
+          if (status && problemStatus_ != 3) {
+               // not finished - might be optimal
+               checkPrimalSolution(rowActivityWork_, columnActivityWork_);
+               double limit = 0.0;
+               getDblParam(ClpDualObjectiveLimit, limit);
+               if (!numberPrimalInfeasibilities_ && obj < limit) {
+                    problemStatus_ = 0;
+               }
+               status = problemStatus_;
+          }
+          if (problemStatus_ == 3)
+               status = 2;
+          if (status || (problemStatus_ == 0 && !isDualObjectiveLimitReached())) {
+               objectiveChange = obj - saveObjectiveValue;
+          } else {
+               objectiveChange = 1.0e100;
+               status = 1;
+          }
+          if (scalingFlag_ <= 0) {
+               CoinMemcpyN(solution_, numberColumns_, outputSolution[iSolution]);
+          } else {
+               int j;
+               double * sol = outputSolution[iSolution];
+               for (j = 0; j < numberColumns_; j++)
+                    sol[j] = solution_[j] * columnScale_[j];
+          }
+          outputStatus[iSolution] = status;
+          outputIterations[iSolution] = numberIterations_;
+          iSolution++;
+
+          // restore
+          numberFake_ = saveNumberFake;
+          CoinMemcpyN(saveSolution,
+                      numberRows_ + numberColumns_, solution_);
+          CoinMemcpyN(saveStatus, numberColumns_ + numberRows_, status_);
+          CoinMemcpyN(saveLower,
+                      numberRows_ + numberColumns_, lower_);
+          CoinMemcpyN(saveUpper,
+                      numberRows_ + numberColumns_, upper_);
+          CoinMemcpyN(saveObjective,
+                      numberRows_ + numberColumns_, cost_);
+          columnLower_[iColumn] = saveBound;
+          CoinMemcpyN(savePivot, numberRows_, pivotVariable_);
+          //delete factorization_;
+          //factorization_ = new ClpFactorization(saveFactorization,numberRows_);
+          setFactorization(saveFactorization);
+
+          newLower[i] = objectiveChange;
+#ifdef CLP_DEBUG
+          printf("up on %d costs %g\n", iColumn, objectiveChange);
+#endif
+
+          /* Possibilities are:
+             Both sides feasible - store
+             Neither side feasible - set objective high and exit if desired
+             One side feasible - change bounds and resolve
+          */
+          if (newUpper[i] < 1.0e100) {
+               if(newLower[i] < 1.0e100) {
+                    // feasible - no action
+               } else {
+                    // up feasible, down infeasible
+                    returnCode = 1;
+                    if (stopOnFirstInfeasible)
+                         break;
+               }
+          } else {
+               if(newLower[i] < 1.0e100) {
+                    // down feasible, up infeasible
+                    returnCode = 1;
+                    if (stopOnFirstInfeasible)
+                         break;
+               } else {
+                    // neither side feasible
+                    returnCode = -1;
+                    break;
+               }
+          }
+     }
+     delete [] saveSolution;
+     delete [] saveLower;
+     delete [] saveUpper;
+     delete [] saveObjective;
+     delete [] saveStatus;
+     delete [] savePivot;
+     if ((startFinishOptions & 1) == 0) {
+          deleteRim(1);
+          whatsChanged_ &= ~0xffff;
+     } else {
+          // Original factorization will have been put back by last loop
+          //delete factorization_;
+          //factorization_ = new ClpFactorization(saveFactorization);
+          deleteRim(0);
+          // mark all as current
+          whatsChanged_ = 0x3ffffff;
+     }
+     objectiveValue_ = saveObjectiveValue;
+     return returnCode;
+}
+// treat no pivot as finished (unless interesting)
+int ClpSimplexDual::fastDual(bool alwaysFinish)
+{
+     progressFlag_ = 0;
+     bestObjectiveValue_ = objectiveValue_;
+     algorithm_ = -1;
+     secondaryStatus_ = 0;
+     // Say in fast dual
+     if (!alwaysFinish)
+          specialOptions_ |= 1048576;
+     specialOptions_ |= 16384;
+     int saveDont = dontFactorizePivots_;
+     if ((specialOptions_ & 2048) == 0)
+          dontFactorizePivots_ = 0;
+     else if(!dontFactorizePivots_)
+          dontFactorizePivots_ = 20;
+     //handler_->setLogLevel(63);
+     // save data
+     ClpDataSave data = saveData();
+     dualTolerance_ = dblParam_[ClpDualTolerance];
+     primalTolerance_ = dblParam_[ClpPrimalTolerance];
+
+     // save dual bound
+     double saveDualBound = dualBound_;
+
+     // Start can skip some things in transposeTimes
+     specialOptions_ |= 131072;
+     if (alphaAccuracy_ != -1.0)
+          alphaAccuracy_ = 1.0;
+     // for dual we will change bounds using dualBound_
+     // for this we need clean basis so it is after factorize
+#if 0
+     {
+          int numberTotal = numberRows_ + numberColumns_;
+          double * saveSol = CoinCopyOfArray(solution_, numberTotal);
+          double * saveDj = CoinCopyOfArray(dj_, numberTotal);
+          double tolerance = 1.0e-8;
+          gutsOfSolution(NULL, NULL);
+          int j;
+          double largestPrimal = tolerance;
+          int iPrimal = -1;
+          for (j = 0; j < numberTotal; j++) {
+               double difference = solution_[j] - saveSol[j];
+               if (fabs(difference) > largestPrimal) {
+                    iPrimal = j;
+                    largestPrimal = fabs(difference);
+               }
+          }
+          double largestDual = tolerance;
+          int iDual = -1;
+          for (j = 0; j < numberTotal; j++) {
+               double difference = dj_[j] - saveDj[j];
+               if (fabs(difference) > largestDual && upper_[j] > lower_[j]) {
+                    iDual = j;
+                    largestDual = fabs(difference);
+               }
+          }
+          if (iPrimal >= 0 || iDual >= 0)
+               printf("pivots %d primal diff(%g,%d) dual diff(%g,%d)\n",
+                      factorization_->pivots(),
+                      largestPrimal, iPrimal,
+                      largestDual, iDual);
+          delete [] saveSol;
+          delete [] saveDj;
+     }
+#else
+     if ((specialOptions_ & 524288) == 0)
+          gutsOfSolution(NULL, NULL);
+#endif
+#if 0
+     if (numberPrimalInfeasibilities_ != 1 ||
+               numberDualInfeasibilities_)
+          printf("dual %g (%d) primal %g (%d)\n",
+                 sumDualInfeasibilities_, numberDualInfeasibilities_,
+                 sumPrimalInfeasibilities_, numberPrimalInfeasibilities_);
+#endif
+#ifndef NDEBUG
+#ifdef COIN_DEVELOP
+     resetFakeBounds(-1);
+#endif
+#endif
+     //numberFake_ =0; // Number of variables at fake bounds
+     numberChanged_ = 0; // Number of variables with changed costs
+     //changeBounds(1,NULL,objectiveChange);
+
+     problemStatus_ = -1;
+     numberIterations_ = 0;
+     if ((specialOptions_ & 524288) == 0) {
+          factorization_->sparseThreshold(0);
+          factorization_->goSparse();
+     }
+
+     int lastCleaned = 0; // last time objective or bounds cleaned up
+
+     // number of times we have declared optimality
+     numberTimesOptimal_ = 0;
+
+     // This says whether to restore things etc
+     int factorType = 0;
+     /*
+       Status of problem:
+       0 - optimal
+       1 - infeasible
+       2 - unbounded
+       -1 - iterating
+       -2 - factorization wanted
+       -3 - redo checking without factorization
+       -4 - looks infeasible
+
+       BUT also from whileIterating return code is:
+
+      -1 iterations etc
+      -2 inaccuracy
+      -3 slight inaccuracy (and done iterations)
+      +0 looks optimal (might be unbounded - but we will investigate)
+      +1 looks infeasible
+      +3 max iterations
+
+     */
+
+     int returnCode = 0;
+
+     int iRow, iColumn;
+     int maxPass = maximumIterations();
+     while (problemStatus_ < 0) {
+          // clear
+          for (iRow = 0; iRow < 4; iRow++) {
+               rowArray_[iRow]->clear();
+          }
+
+          for (iColumn = 0; iColumn < 2; iColumn++) {
+               columnArray_[iColumn]->clear();
+          }
+
+          // give matrix (and model costs and bounds a chance to be
+          // refreshed (normally null)
+          matrix_->refresh(this);
+          // If getting nowhere - why not give it a kick
+          // does not seem to work too well - do some more work
+          if ((specialOptions_ & 524288) != 0 && (moreSpecialOptions_&2048) == 0 &&
+                    perturbation_ < 101 && numberIterations_ > 2 * (numberRows_ + numberColumns_)) {
+               perturb();
+               // Can't get here if values pass
+               gutsOfSolution(NULL, NULL);
+               if (handler_->logLevel() > 2) {
+                    handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                              << numberIterations_ << objectiveValue();
+                    handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                              << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+                    handler_->printing(sumDualInfeasibilities_ > 0.0)
+                              << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+                    handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                                       < numberDualInfeasibilities_)
+                              << numberDualInfeasibilitiesWithoutFree_;
+                    handler_->message() << CoinMessageEol;
+               }
+          }
+          // may factorize, checks if problem finished
+          // should be able to speed this up on first time
+          statusOfProblemInDual(lastCleaned, factorType, NULL, data, 0);
+
+          // Say good factorization
+          factorType = 1;
+          maxPass--;
+          if (maxPass < -10) {
+               // odd
+               returnCode = 1;
+               problemStatus_ = 3;
+               // can't say anything interesting - might as well return
+#ifdef CLP_DEBUG
+               printf("returning from fastDual after %d iterations with code %d because of loop\n",
+                      numberIterations_, returnCode);
+#endif
+               break;
+          }
+
+          // Do iterations
+          if (problemStatus_ < 0) {
+               double * givenPi = NULL;
+               returnCode = whileIterating(givenPi, 0);
+               if ((!alwaysFinish && returnCode < 0) || returnCode == 3) {
+                    if (returnCode != 3)
+                         assert (problemStatus_ < 0);
+                    returnCode = 1;
+                    problemStatus_ = 3;
+                    // can't say anything interesting - might as well return
+#ifdef CLP_DEBUG
+                    printf("returning from fastDual after %d iterations with code %d\n",
+                           numberIterations_, returnCode);
+#endif
+                    break;
+               }
+               if (returnCode == -2)
+                    factorType = 3;
+               returnCode = 0;
+          }
+     }
+
+     // clear
+     for (iRow = 0; iRow < 4; iRow++) {
+          rowArray_[iRow]->clear();
+     }
+
+     for (iColumn = 0; iColumn < 2; iColumn++) {
+          columnArray_[iColumn]->clear();
+     }
+     // Say not in fast dual
+     specialOptions_ &= ~(16384 | 1048576);
+     assert(!numberFake_ || ((specialOptions_&(2048 | 4096)) != 0 && dualBound_ >= 1.0e8)
+            || returnCode || problemStatus_); // all bounds should be okay
+     if (numberFake_ > 0 && false) {
+          // Set back
+          double dummy;
+          changeBounds(2, NULL, dummy);
+     }
+     // Restore any saved stuff
+     restoreData(data);
+     dontFactorizePivots_ = saveDont;
+     dualBound_ = saveDualBound;
+     // Stop can skip some things in transposeTimes
+     specialOptions_ &= ~131072;
+     if (!problemStatus_) {
+          // see if cutoff reached
+          double limit = 0.0;
+          getDblParam(ClpDualObjectiveLimit, limit);
+          if(fabs(limit) < 1.0e30 && objectiveValue()*optimizationDirection_ >
+                    limit + 1.0e-7 + 1.0e-8 * fabs(limit)) {
+               // actually infeasible on objective
+               problemStatus_ = 1;
+               secondaryStatus_ = 1;
+          }
+     }
+     if (problemStatus_ == 3)
+          objectiveValue_ = CoinMax(bestObjectiveValue_, objectiveValue_ - bestPossibleImprovement_);
+     return returnCode;
+}
+// This does first part of StrongBranching
+ClpFactorization *
+ClpSimplexDual::setupForStrongBranching(char * arrays, int numberRows,
+                                        int numberColumns, bool solveLp)
+{
+     if (solveLp) {
+          // make sure won't create fake objective
+          int saveOptions = specialOptions_;
+          specialOptions_ |= 16384;
+          // solve
+	  int saveMaximumIterations = intParam_[ClpMaxNumIteration];
+	  intParam_[ClpMaxNumIteration] = 100+numberRows_+numberColumns_;
+          dual(0, 7);
+          if (problemStatus_ == 10) {
+               ClpSimplex::dual(0, 0);
+               assert (problemStatus_ != 10);
+               if (problemStatus_ == 0) {
+                    dual(0, 7);
+                    //assert (problemStatus_!=10);
+               }
+          }
+	  intParam_[ClpMaxNumIteration] = saveMaximumIterations;
+          specialOptions_ = saveOptions;
+          if (problemStatus_ != 0 && problemStatus_ != 10)
+               return NULL; // say infeasible or odd
+          // May be empty
+          solveLp = (solution_ != NULL && problemStatus_ == 0);
+     }
+     problemStatus_ = 0;
+     if (!solveLp) {
+          algorithm_ = -1;
+          // put in standard form (and make row copy)
+          // create modifiable copies of model rim and do optional scaling
+          int startFinishOptions;
+          if((specialOptions_ & 4096) == 0) {
+               startFinishOptions = 0;
+          } else {
+               startFinishOptions = 1 + 2 + 4;
+          }
+          createRim(7 + 8 + 16 + 32, true, startFinishOptions);
+          // Do initial factorization
+          // and set certain stuff
+          // We can either set increasing rows so ...IsBasic gives pivot row
+          // or we can just increment iBasic one by one
+          // for now let ...iBasic give pivot row
+          bool useFactorization = false;
+          if ((startFinishOptions & 2) != 0 && (whatsChanged_&(2 + 512)) == 2 + 512) {
+               useFactorization = true; // Keep factorization if possible
+               // switch off factorization if bad
+               if (pivotVariable_[0] < 0 || factorization_->numberRows() != numberRows_)
+                    useFactorization = false;
+          }
+          if (!useFactorization) {
+               factorization_->setDefaultValues();
+
+               int factorizationStatus = internalFactorize(0);
+               if (factorizationStatus < 0) {
+                    // some error
+                    // we should either debug or ignore
+#ifndef NDEBUG
+                    printf("***** ClpDual strong branching factorization error - debug\n");
+#endif
+               } else if (factorizationStatus && factorizationStatus <= numberRows_) {
+                    handler_->message(CLP_SINGULARITIES, messages_)
+                              << factorizationStatus
+                              << CoinMessageEol;
+               }
+          }
+     }
+     // Get fake bounds correctly
+     double dummyChangeCost;
+     changeBounds(3, NULL, dummyChangeCost);
+     double * arrayD = reinterpret_cast<double *> (arrays);
+     arrayD[0] = objectiveValue() * optimizationDirection_;
+     double * saveSolution = arrayD + 1;
+     double * saveLower = saveSolution + (numberRows + numberColumns);
+     double * saveUpper = saveLower + (numberRows + numberColumns);
+     double * saveObjective = saveUpper + (numberRows + numberColumns);
+     double * saveLowerOriginal = saveObjective + (numberRows + numberColumns);
+     double * saveUpperOriginal = saveLowerOriginal + numberColumns;
+     arrayD = saveUpperOriginal + numberColumns;
+     int * savePivot = reinterpret_cast<int *> (arrayD);
+     int * whichRow = savePivot + numberRows;
+     int * whichColumn = whichRow + 3 * numberRows;
+     int * arrayI = whichColumn + 2 * numberColumns;
+     unsigned char * saveStatus = reinterpret_cast<unsigned char *> (arrayI + 1);
+     // save stuff
+     // save basis and solution
+     CoinMemcpyN(solution_,
+                 numberRows_ + numberColumns_, saveSolution);
+     CoinMemcpyN(status_, numberColumns_ + numberRows_, saveStatus);
+     CoinMemcpyN(lower_,
+                 numberRows_ + numberColumns_, saveLower);
+     CoinMemcpyN(upper_,
+                 numberRows_ + numberColumns_, saveUpper);
+     CoinMemcpyN(cost_,
+                 numberRows_ + numberColumns_, saveObjective);
+     CoinMemcpyN(pivotVariable_, numberRows_, savePivot);
+     ClpFactorization * factorization = factorization_;
+     factorization_ = NULL;
+     return factorization;
+}
+// This cleans up after strong branching
+void
+ClpSimplexDual::cleanupAfterStrongBranching(ClpFactorization * factorization)
+{
+     int startFinishOptions;
+     /*  COIN_CLP_VETTED
+         Looks safe for Cbc
+     */
+     if((specialOptions_ & 4096) == 0) {
+          startFinishOptions = 0;
+     } else {
+          startFinishOptions = 1 + 2 + 4;
+     }
+     if ((startFinishOptions & 1) == 0 && cost_) {
+          deleteRim(1);
+     } else {
+          // Original factorization will have been put back by last loop
+          delete factorization_;
+          factorization_ = factorization;
+          //deleteRim(0);
+          // mark all as current
+     }
+     whatsChanged_ &= ~0xffff;
+}
+/* Checks number of variables at fake bounds.  This is used by fastDual
+   so can exit gracefully before end */
+int
+ClpSimplexDual::numberAtFakeBound()
+{
+     int iSequence;
+     int numberFake = 0;
+
+     for (iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
+          FakeBound bound = getFakeBound(iSequence);
+          switch(getStatus(iSequence)) {
+
+          case basic:
+               break;
+          case isFree:
+          case superBasic:
+          case ClpSimplex::isFixed:
+               //setFakeBound (iSequence, noFake);
+               break;
+          case atUpperBound:
+               if (bound == upperFake || bound == bothFake)
+                    numberFake++;
+               break;
+          case atLowerBound:
+               if (bound == lowerFake || bound == bothFake)
+                    numberFake++;
+               break;
+          }
+     }
+     //numberFake_ = numberFake;
+     return numberFake;
+}
+/* Pivot out a variable and choose an incoing one.  Assumes dual
+   feasible - will not go through a reduced cost.
+   Returns step length in theta
+   Return codes as before but -1 means no acceptable pivot
+*/
+int
+ClpSimplexDual::pivotResultPart1()
+{
+  // Get good size for pivot
+  // Allow first few iterations to take tiny
+  double acceptablePivot = 1.0e-1 * acceptablePivot_;
+  if (numberIterations_ > 100)
+    acceptablePivot = acceptablePivot_;
+  if (factorization_->pivots() > 10)
+    acceptablePivot = 1.0e+3 * acceptablePivot_; // if we have iterated be more strict
+  else if (factorization_->pivots() > 5)
+    acceptablePivot = 1.0e+2 * acceptablePivot_; // if we have iterated be slightly more strict
+  else if (factorization_->pivots())
+    acceptablePivot = acceptablePivot_; // relax
+  // But factorizations complain if <1.0e-8
+  //acceptablePivot=CoinMax(acceptablePivot,1.0e-8);
+  double bestPossiblePivot = 1.0;
+  // get sign for finding row of tableau
+  // create as packed
+  double direction = directionOut_;
+  assert (!rowArray_[0]->getNumElements());
+  rowArray_[1]->clear(); //assert (!rowArray_[1]->getNumElements());
+  assert (!columnArray_[0]->getNumElements());
+  assert (!columnArray_[1]->getNumElements());
+  rowArray_[0]->createPacked(1, &pivotRow_, &direction);
+  factorization_->updateColumnTranspose(rowArray_[1], rowArray_[0]);
+  // Allow to do dualColumn0
+  if (numberThreads_ < -1)
+    spareIntArray_[0] = 1;
+  spareDoubleArray_[0] = acceptablePivot;
+  rowArray_[3]->clear();
+  sequenceIn_ = -1;
+  // put row of tableau in rowArray[0] and columnArray[0]
+  assert (!rowArray_[1]->getNumElements());
+  if (!scaledMatrix_) {
+    if ((moreSpecialOptions_ & 8) != 0 && !rowScale_)
+      spareIntArray_[0] = 1;
+    matrix_->transposeTimes(this, -1.0,
+			    rowArray_[0], rowArray_[1], columnArray_[0]);
+  } else {
+    double * saveR = rowScale_;
+    double * saveC = columnScale_;
+    rowScale_ = NULL;
+    columnScale_ = NULL;
+    if ((moreSpecialOptions_ & 8) != 0)
+      spareIntArray_[0] = 1;
+    scaledMatrix_->transposeTimes(this, -1.0,
+				  rowArray_[0], rowArray_[1], columnArray_[0]);
+    rowScale_ = saveR;
+    columnScale_ = saveC;
+  }
+  // do ratio test for normal iteration
+  dualOut_ *= 1.0e-8;
+  bestPossiblePivot = dualColumn(rowArray_[0], columnArray_[0], rowArray_[3],
+				 columnArray_[1], acceptablePivot, 
+				 NULL/*dubiousWeights*/);
+  dualOut_ *= 1.0e8;
+  if (fabs(bestPossiblePivot)<1.0e-6)
+    return -1;
+  else
+    return 0;
+}
+/*
+   Row array has row part of pivot row
+   Column array has column part.
+   This is used in dual values pass
+*/
+void
+ClpSimplexDual::checkPossibleValuesMove(CoinIndexedVector * rowArray,
+                                        CoinIndexedVector * columnArray,
+                                        double acceptablePivot)
+{
+     double * work;
+     int number;
+     int * which;
+     int iSection;
+
+     double tolerance = dualTolerance_ * 1.001;
+
+     double thetaDown = 1.0e31;
+     double changeDown ;
+     double thetaUp = 1.0e31;
+     double bestAlphaDown = acceptablePivot * 0.99999;
+     double bestAlphaUp = acceptablePivot * 0.99999;
+     int sequenceDown = -1;
+     int sequenceUp = sequenceOut_;
+
+     double djBasic = dj_[sequenceOut_];
+     if (djBasic > 0.0) {
+          // basic at lower bound so directionOut_ 1 and -1 in pivot row
+          // dj will go to zero on other way
+          thetaUp = djBasic;
+          changeDown = -lower_[sequenceOut_];
+     } else {
+          // basic at upper bound so directionOut_ -1 and 1 in pivot row
+          // dj will go to zero on other way
+          thetaUp = -djBasic;
+          changeDown = upper_[sequenceOut_];
+     }
+     bestAlphaUp = 1.0;
+     int addSequence;
+
+     double alphaUp = 0.0;
+     double alphaDown = 0.0;
+
+     for (iSection = 0; iSection < 2; iSection++) {
+
+          int i;
+          if (!iSection) {
+               work = rowArray->denseVector();
+               number = rowArray->getNumElements();
+               which = rowArray->getIndices();
+               addSequence = numberColumns_;
+          } else {
+               work = columnArray->denseVector();
+               number = columnArray->getNumElements();
+               which = columnArray->getIndices();
+               addSequence = 0;
+          }
+
+          for (i = 0; i < number; i++) {
+               int iSequence = which[i];
+               int iSequence2 = iSequence + addSequence;
+               double alpha;
+               double oldValue;
+               double value;
+
+               switch(getStatus(iSequence2)) {
+
+               case basic:
+                    break;
+               case ClpSimplex::isFixed:
+                    alpha = work[i];
+                    changeDown += alpha * upper_[iSequence2];
+                    break;
+               case isFree:
+               case superBasic:
+                    alpha = work[i];
+                    // dj must be effectively zero as dual feasible
+                    if (fabs(alpha) > bestAlphaUp) {
+                         thetaDown = 0.0;
+                         thetaUp = 0.0;
+                         bestAlphaDown = fabs(alpha);
+                         bestAlphaUp = bestAlphaDown;
+                         sequenceDown = iSequence2;
+                         sequenceUp = sequenceDown;
+                         alphaUp = alpha;
+                         alphaDown = alpha;
+                    }
+                    break;
+               case atUpperBound:
+                    alpha = work[i];
+                    oldValue = dj_[iSequence2];
+                    changeDown += alpha * upper_[iSequence2];
+                    if (alpha >= acceptablePivot) {
+                         // might do other way
+                         value = oldValue + thetaUp * alpha;
+                         if (value > -tolerance) {
+                              if (value > tolerance || fabs(alpha) > bestAlphaUp) {
+                                   thetaUp = -oldValue / alpha;
+                                   bestAlphaUp = fabs(alpha);
+                                   sequenceUp = iSequence2;
+                                   alphaUp = alpha;
+                              }
+                         }
+                    } else if (alpha <= -acceptablePivot) {
+                         // might do this way
+                         value = oldValue - thetaDown * alpha;
+                         if (value > -tolerance) {
+                              if (value > tolerance || fabs(alpha) > bestAlphaDown) {
+                                   thetaDown = oldValue / alpha;
+                                   bestAlphaDown = fabs(alpha);
+                                   sequenceDown = iSequence2;
+                                   alphaDown = alpha;
+                              }
+                         }
+                    }
+                    break;
+               case atLowerBound:
+                    alpha = work[i];
+                    oldValue = dj_[iSequence2];
+                    changeDown += alpha * lower_[iSequence2];
+                    if (alpha <= -acceptablePivot) {
+                         // might do other way
+                         value = oldValue + thetaUp * alpha;
+                         if (value < tolerance) {
+                              if (value < -tolerance || fabs(alpha) > bestAlphaUp) {
+                                   thetaUp = -oldValue / alpha;
+                                   bestAlphaUp = fabs(alpha);
+                                   sequenceUp = iSequence2;
+                                   alphaUp = alpha;
+                              }
+                         }
+                    } else if (alpha >= acceptablePivot) {
+                         // might do this way
+                         value = oldValue - thetaDown * alpha;
+                         if (value < tolerance) {
+                              if (value < -tolerance || fabs(alpha) > bestAlphaDown) {
+                                   thetaDown = oldValue / alpha;
+                                   bestAlphaDown = fabs(alpha);
+                                   sequenceDown = iSequence2;
+                                   alphaDown = alpha;
+                              }
+                         }
+                    }
+                    break;
+               }
+          }
+     }
+     thetaUp *= -1.0;
+     double changeUp = -thetaUp * changeDown;
+     changeDown = -thetaDown * changeDown;
+     if (CoinMax(fabs(thetaDown), fabs(thetaUp)) < 1.0e-8) {
+          // largest
+          if (fabs(alphaDown) < fabs(alphaUp)) {
+               sequenceDown = -1;
+          }
+     }
+     // choose
+     sequenceIn_ = -1;
+     if (changeDown > changeUp && sequenceDown >= 0) {
+          theta_ = thetaDown;
+          if (fabs(changeDown) < 1.0e30)
+               sequenceIn_ = sequenceDown;
+          alpha_ = alphaDown;
+#ifdef CLP_DEBUG
+          if ((handler_->logLevel() & 32))
+               printf("predicted way - dirout %d, change %g,%g theta %g\n",
+                      directionOut_, changeDown, changeUp, theta_);
+#endif
+     } else {
+          theta_ = thetaUp;
+          if (fabs(changeUp) < 1.0e30)
+               sequenceIn_ = sequenceUp;
+          alpha_ = alphaUp;
+          if (sequenceIn_ != sequenceOut_) {
+#ifdef CLP_DEBUG
+               if ((handler_->logLevel() & 32))
+                    printf("opposite way - dirout %d, change %g,%g theta %g\n",
+                           directionOut_, changeDown, changeUp, theta_);
+#endif
+          } else {
+#ifdef CLP_DEBUG
+               if ((handler_->logLevel() & 32))
+                    printf("opposite way to zero dj - dirout %d, change %g,%g theta %g\n",
+                           directionOut_, changeDown, changeUp, theta_);
+#endif
+          }
+     }
+     if (sequenceIn_ >= 0) {
+          lowerIn_ = lower_[sequenceIn_];
+          upperIn_ = upper_[sequenceIn_];
+          valueIn_ = solution_[sequenceIn_];
+          dualIn_ = dj_[sequenceIn_];
+
+          if (alpha_ < 0.0) {
+               // as if from upper bound
+               directionIn_ = -1;
+               upperIn_ = valueIn_;
+          } else {
+               // as if from lower bound
+               directionIn_ = 1;
+               lowerIn_ = valueIn_;
+          }
+     }
+}
+/*
+   Row array has row part of pivot row
+   Column array has column part.
+   This is used in cleanup
+*/
+void
+ClpSimplexDual::checkPossibleCleanup(CoinIndexedVector * rowArray,
+                                     CoinIndexedVector * columnArray,
+                                     double acceptablePivot)
+{
+     double * work;
+     int number;
+     int * which;
+     int iSection;
+
+     double tolerance = dualTolerance_ * 1.001;
+
+     double thetaDown = 1.0e31;
+     double thetaUp = 1.0e31;
+     double bestAlphaDown = acceptablePivot * 10.0;
+     double bestAlphaUp = acceptablePivot * 10.0;
+     int sequenceDown = -1;
+     int sequenceUp = -1;
+
+     double djSlack = dj_[pivotRow_];
+     if (getRowStatus(pivotRow_) == basic)
+          djSlack = COIN_DBL_MAX;
+     if (fabs(djSlack) < tolerance)
+          djSlack = 0.0;
+     int addSequence;
+
+     double alphaUp = 0.0;
+     double alphaDown = 0.0;
+     for (iSection = 0; iSection < 2; iSection++) {
+
+          int i;
+          if (!iSection) {
+               work = rowArray->denseVector();
+               number = rowArray->getNumElements();
+               which = rowArray->getIndices();
+               addSequence = numberColumns_;
+          } else {
+               work = columnArray->denseVector();
+               number = columnArray->getNumElements();
+               which = columnArray->getIndices();
+               addSequence = 0;
+          }
+
+          for (i = 0; i < number; i++) {
+               int iSequence = which[i];
+               int iSequence2 = iSequence + addSequence;
+               double alpha;
+               double oldValue;
+               double value;
+
+               switch(getStatus(iSequence2)) {
+
+               case basic:
+                    break;
+               case ClpSimplex::isFixed:
+                    alpha = work[i];
+                    if (addSequence) {
+		      COIN_DETAIL_PRINT(printf("possible - pivot row %d this %d\n", pivotRow_, iSequence));
+                         oldValue = dj_[iSequence2];
+                         if (alpha <= -acceptablePivot) {
+                              // might do other way
+                              value = oldValue + thetaUp * alpha;
+                              if (value < tolerance) {
+                                   if (value < -tolerance || fabs(alpha) > bestAlphaUp) {
+                                        thetaUp = -oldValue / alpha;
+                                        bestAlphaUp = fabs(alpha);
+                                        sequenceUp = iSequence2;
+                                        alphaUp = alpha;
+                                   }
+                              }
+                         } else if (alpha >= acceptablePivot) {
+                              // might do this way
+                              value = oldValue - thetaDown * alpha;
+                              if (value < tolerance) {
+                                   if (value < -tolerance || fabs(alpha) > bestAlphaDown) {
+                                        thetaDown = oldValue / alpha;
+                                        bestAlphaDown = fabs(alpha);
+                                        sequenceDown = iSequence2;
+                                        alphaDown = alpha;
+                                   }
+                              }
+                         }
+                    }
+                    break;
+               case isFree:
+               case superBasic:
+                    alpha = work[i];
+                    // dj must be effectively zero as dual feasible
+                    if (fabs(alpha) > bestAlphaUp) {
+                         thetaDown = 0.0;
+                         thetaUp = 0.0;
+                         bestAlphaDown = fabs(alpha);
+                         bestAlphaUp = bestAlphaDown;
+                         sequenceDown = iSequence2;
+                         sequenceUp = sequenceDown;
+                         alphaUp = alpha;
+                         alphaDown = alpha;
+                    }
+                    break;
+               case atUpperBound:
+                    alpha = work[i];
+                    oldValue = dj_[iSequence2];
+                    if (alpha >= acceptablePivot) {
+                         // might do other way
+                         value = oldValue + thetaUp * alpha;
+                         if (value > -tolerance) {
+                              if (value > tolerance || fabs(alpha) > bestAlphaUp) {
+                                   thetaUp = -oldValue / alpha;
+                                   bestAlphaUp = fabs(alpha);
+                                   sequenceUp = iSequence2;
+                                   alphaUp = alpha;
+                              }
+                         }
+                    } else if (alpha <= -acceptablePivot) {
+                         // might do this way
+                         value = oldValue - thetaDown * alpha;
+                         if (value > -tolerance) {
+                              if (value > tolerance || fabs(alpha) > bestAlphaDown) {
+                                   thetaDown = oldValue / alpha;
+                                   bestAlphaDown = fabs(alpha);
+                                   sequenceDown = iSequence2;
+                                   alphaDown = alpha;
+                              }
+                         }
+                    }
+                    break;
+               case atLowerBound:
+                    alpha = work[i];
+                    oldValue = dj_[iSequence2];
+                    if (alpha <= -acceptablePivot) {
+                         // might do other way
+                         value = oldValue + thetaUp * alpha;
+                         if (value < tolerance) {
+                              if (value < -tolerance || fabs(alpha) > bestAlphaUp) {
+                                   thetaUp = -oldValue / alpha;
+                                   bestAlphaUp = fabs(alpha);
+                                   sequenceUp = iSequence2;
+                                   alphaUp = alpha;
+                              }
+                         }
+                    } else if (alpha >= acceptablePivot) {
+                         // might do this way
+                         value = oldValue - thetaDown * alpha;
+                         if (value < tolerance) {
+                              if (value < -tolerance || fabs(alpha) > bestAlphaDown) {
+                                   thetaDown = oldValue / alpha;
+                                   bestAlphaDown = fabs(alpha);
+                                   sequenceDown = iSequence2;
+                                   alphaDown = alpha;
+                              }
+                         }
+                    }
+                    break;
+               }
+          }
+     }
+     thetaUp *= -1.0;
+     // largest
+     if (bestAlphaDown < bestAlphaUp)
+          sequenceDown = -1;
+     else
+          sequenceUp = -1;
+
+     sequenceIn_ = -1;
+
+     if (sequenceDown >= 0) {
+          theta_ = thetaDown;
+          sequenceIn_ = sequenceDown;
+          alpha_ = alphaDown;
+#ifdef CLP_DEBUG
+          if ((handler_->logLevel() & 32))
+               printf("predicted way - dirout %d, theta %g\n",
+                      directionOut_, theta_);
+#endif
+     } else if (sequenceUp >= 0) {
+          theta_ = thetaUp;
+          sequenceIn_ = sequenceUp;
+          alpha_ = alphaUp;
+#ifdef CLP_DEBUG
+          if ((handler_->logLevel() & 32))
+               printf("opposite way - dirout %d,theta %g\n",
+                      directionOut_, theta_);
+#endif
+     }
+     if (sequenceIn_ >= 0) {
+          lowerIn_ = lower_[sequenceIn_];
+          upperIn_ = upper_[sequenceIn_];
+          valueIn_ = solution_[sequenceIn_];
+          dualIn_ = dj_[sequenceIn_];
+
+          if (alpha_ < 0.0) {
+               // as if from upper bound
+               directionIn_ = -1;
+               upperIn_ = valueIn_;
+          } else {
+               // as if from lower bound
+               directionIn_ = 1;
+               lowerIn_ = valueIn_;
+          }
+     }
+}
+/*
+   This sees if we can move duals in dual values pass.
+   This is done before any pivoting
+*/
+void ClpSimplexDual::doEasyOnesInValuesPass(double * dj)
+{
+     // Get column copy
+     CoinPackedMatrix * columnCopy = matrix();
+     // Get a row copy in standard format
+     CoinPackedMatrix copy;
+     copy.setExtraGap(0.0);
+     copy.setExtraMajor(0.0);
+     copy.reverseOrderedCopyOf(*columnCopy);
+     // get matrix data pointers
+     const int * column = copy.getIndices();
+     const CoinBigIndex * rowStart = copy.getVectorStarts();
+     const int * rowLength = copy.getVectorLengths();
+     const double * elementByRow = copy.getElements();
+     double tolerance = dualTolerance_ * 1.001;
+
+     int iRow;
+#ifdef CLP_DEBUG
+     {
+          double value5 = 0.0;
+          int i;
+          for (i = 0; i < numberRows_ + numberColumns_; i++) {
+               if (dj[i] < -1.0e-6)
+                    value5 += dj[i] * upper_[i];
+               else if (dj[i] > 1.0e-6)
+                    value5 += dj[i] * lower_[i];
+          }
+          printf("Values objective Value before %g\n", value5);
+     }
+#endif
+     // for scaled row
+     double * scaled = NULL;
+     if (rowScale_)
+          scaled = new double[numberColumns_];
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+
+          int iSequence = iRow + numberColumns_;
+          double djBasic = dj[iSequence];
+          if (getRowStatus(iRow) == basic && fabs(djBasic) > tolerance) {
+
+               double changeUp ;
+               // always -1 in pivot row
+               if (djBasic > 0.0) {
+                    // basic at lower bound
+                    changeUp = -lower_[iSequence];
+               } else {
+                    // basic at upper bound
+                    changeUp = upper_[iSequence];
+               }
+               bool canMove = true;
+               int i;
+               const double * thisElements = elementByRow + rowStart[iRow];
+               const int * thisIndices = column + rowStart[iRow];
+               if (rowScale_) {
+                    // scale row
+                    double scale = rowScale_[iRow];
+                    for (i = 0; i < rowLength[iRow]; i++) {
+                         int iColumn = thisIndices[i];
+                         double alpha = thisElements[i];
+                         scaled[i] = scale * alpha * columnScale_[iColumn];
+                    }
+                    thisElements = scaled;
+               }
+               for (i = 0; i < rowLength[iRow]; i++) {
+                    int iColumn = thisIndices[i];
+                    double alpha = thisElements[i];
+                    double oldValue = dj[iColumn];;
+                    double value;
+
+                    switch(getStatus(iColumn)) {
+
+                    case basic:
+                         if (dj[iColumn] < -tolerance &&
+                                   fabs(solution_[iColumn] - upper_[iColumn]) < 1.0e-8) {
+                              // at ub
+                              changeUp += alpha * upper_[iColumn];
+                              // might do other way
+                              value = oldValue + djBasic * alpha;
+                              if (value > tolerance)
+                                   canMove = false;
+                         } else if (dj[iColumn] > tolerance &&
+                                    fabs(solution_[iColumn] - lower_[iColumn]) < 1.0e-8) {
+                              changeUp += alpha * lower_[iColumn];
+                              // might do other way
+                              value = oldValue + djBasic * alpha;
+                              if (value < -tolerance)
+                                   canMove = false;
+                         } else {
+                              canMove = false;
+                         }
+                         break;
+                    case ClpSimplex::isFixed:
+                         changeUp += alpha * upper_[iColumn];
+                         break;
+                    case isFree:
+                    case superBasic:
+                         canMove = false;
+                         break;
+                    case atUpperBound:
+                         changeUp += alpha * upper_[iColumn];
+                         // might do other way
+                         value = oldValue + djBasic * alpha;
+                         if (value > tolerance)
+                              canMove = false;
+                         break;
+                    case atLowerBound:
+                         changeUp += alpha * lower_[iColumn];
+                         // might do other way
+                         value = oldValue + djBasic * alpha;
+                         if (value < -tolerance)
+                              canMove = false;
+                         break;
+                    }
+               }
+               if (canMove) {
+                    if (changeUp * djBasic > 1.0e-12 || fabs(changeUp) < 1.0e-8) {
+                         // move
+                         for (i = 0; i < rowLength[iRow]; i++) {
+                              int iColumn = thisIndices[i];
+                              double alpha = thisElements[i];
+                              dj[iColumn] += djBasic * alpha;
+                         }
+                         dj[iSequence] = 0.0;
+#ifdef CLP_DEBUG
+                         {
+                              double value5 = 0.0;
+                              int i;
+                              for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                                   if (dj[i] < -1.0e-6)
+                                        value5 += dj[i] * upper_[i];
+                                   else if (dj[i] > 1.0e-6)
+                                        value5 += dj[i] * lower_[i];
+                              }
+                              printf("Values objective Value after row %d old dj %g %g\n",
+                                     iRow, djBasic, value5);
+                         }
+#endif
+                    }
+               }
+          }
+     }
+     delete [] scaled;
+}
+int
+ClpSimplexDual::nextSuperBasic()
+{
+     if (firstFree_ >= 0) {
+          int returnValue = firstFree_;
+          int iColumn = firstFree_ + 1;
+          for (; iColumn < numberRows_ + numberColumns_; iColumn++) {
+               if (getStatus(iColumn) == isFree)
+                    if (fabs(dj_[iColumn]) > 1.0e2 * dualTolerance_)
+                         break;
+          }
+          firstFree_ = iColumn;
+          if (firstFree_ == numberRows_ + numberColumns_)
+               firstFree_ = -1;
+          return returnValue;
+     } else {
+          return -1;
+     }
+}
+void
+ClpSimplexDual::resetFakeBounds(int type)
+{
+     if (type == 0) {
+          // put back original bounds and then check
+          createRim1(false);
+          double dummyChangeCost = 0.0;
+          changeBounds(3, NULL, dummyChangeCost);
+     } else if (type < 0) {
+#ifndef NDEBUG
+          // just check
+          int nTotal = numberRows_ + numberColumns_;
+          double * tempLower = CoinCopyOfArray(lower_, nTotal);
+          double * tempUpper = CoinCopyOfArray(upper_, nTotal);
+          int iSequence;
+          // Get scaled true bounds
+          if (columnScale_) {
+               for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+                    // lower
+                    double value = columnLower_[iSequence];
+                    if (value > -1.0e30) {
+                         double multiplier = rhsScale_ * inverseColumnScale_[iSequence];
+                         value *= multiplier;
+                    }
+                    tempLower[iSequence] = value;
+                    // upper
+                    value = columnUpper_[iSequence];
+                    if (value < 1.0e30) {
+                         double multiplier = rhsScale_ * inverseColumnScale_[iSequence];
+                         value *= multiplier;
+                    }
+                    tempUpper[iSequence] = value;
+               }
+               for (iSequence = 0; iSequence < numberRows_; iSequence++) {
+                    // lower
+                    double value = rowLower_[iSequence];
+                    if (value > -1.0e30) {
+                         double multiplier = rhsScale_ * rowScale_[iSequence];
+                         value *= multiplier;
+                    }
+                    tempLower[iSequence+numberColumns_] = value;
+                    // upper
+                    value = rowUpper_[iSequence];
+                    if (value < 1.0e30) {
+                         double multiplier = rhsScale_ * rowScale_[iSequence];
+                         value *= multiplier;
+                    }
+                    tempUpper[iSequence+numberColumns_] = value;
+               }
+          } else {
+               for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+                    // lower
+                    tempLower[iSequence] = columnLower_[iSequence];
+                    // upper
+                    tempUpper[iSequence] = columnUpper_[iSequence];
+               }
+               for (iSequence = 0; iSequence < numberRows_; iSequence++) {
+                    // lower
+                    tempLower[iSequence+numberColumns_] = rowLower_[iSequence];
+                    // upper
+                    tempUpper[iSequence+numberColumns_] = rowUpper_[iSequence];
+               }
+          }
+          int nFake = 0;
+          int nErrors = 0;
+          int nSuperBasic = 0;
+          int nWarnings = 0;
+          for (iSequence = 0; iSequence < nTotal; iSequence++) {
+               FakeBound fakeStatus = getFakeBound(iSequence);
+               Status status = getStatus(iSequence);
+               bool isFake = false;
+#ifdef CLP_INVESTIGATE
+               char RC = 'C';
+#endif
+               int jSequence = iSequence;
+               if (jSequence >= numberColumns_) {
+#ifdef CLP_INVESTIGATE
+                    RC = 'R';
+#endif
+                    jSequence -= numberColumns_;
+               }
+               double lowerValue = tempLower[iSequence];
+               double upperValue = tempUpper[iSequence];
+               double value = solution_[iSequence];
+               CoinRelFltEq equal;
+               if (status == atUpperBound ||
+                         status == atLowerBound) {
+                    if (fakeStatus == ClpSimplexDual::upperFake) {
+                         if(!equal(upper_[iSequence], (lowerValue + dualBound_)) ||
+                                   !(equal(upper_[iSequence], value) ||
+                                     equal(lower_[iSequence], value))) {
+                              nErrors++;
+#ifdef CLP_INVESTIGATE
+                              printf("** upperFake %c%d %g <= %g <= %g true %g, %g\n",
+                                     RC, jSequence, lower_[iSequence], solution_[iSequence],
+                                     upper_[iSequence], lowerValue, upperValue);
+#endif
+                         }
+                         isFake = true;;
+                    } else if (fakeStatus == ClpSimplexDual::lowerFake) {
+                         if(!equal(lower_[iSequence], (upperValue - dualBound_)) ||
+                                   !(equal(upper_[iSequence], value) ||
+                                     equal(lower_[iSequence], value))) {
+                              nErrors++;
+#ifdef CLP_INVESTIGATE
+                              printf("** lowerFake %c%d %g <= %g <= %g true %g, %g\n",
+                                     RC, jSequence, lower_[iSequence], solution_[iSequence],
+                                     upper_[iSequence], lowerValue, upperValue);
+#endif
+                         }
+                         isFake = true;;
+                    } else if (fakeStatus == ClpSimplexDual::bothFake) {
+                         nWarnings++;
+#ifdef CLP_INVESTIGATE
+                         printf("** %d at bothFake?\n", iSequence);
+#endif
+                    } else if (upper_[iSequence] - lower_[iSequence] > 2.0 * dualBound_) {
+                         nErrors++;
+#ifdef CLP_INVESTIGATE
+                         printf("** noFake! %c%d %g <= %g <= %g true %g, %g\n",
+                                RC, jSequence, lower_[iSequence], solution_[iSequence],
+                                upper_[iSequence], lowerValue, upperValue);
+#endif
+                    }
+               } else if (status == superBasic || status == isFree) {
+                    nSuperBasic++;
+                    //printf("** free or superbasic %c%d %g <= %g <= %g true %g, %g - status %d\n",
+                    //     RC,jSequence,lower_[iSequence],solution_[iSequence],
+                    //     upper_[iSequence],lowerValue,upperValue,status);
+               } else if (status == basic) {
+                    bool odd = false;
+                    if (!equal(lower_[iSequence], lowerValue))
+                         odd = true;
+                    if (!equal(upper_[iSequence], upperValue))
+                         odd = true;
+                    if (odd) {
+#ifdef CLP_INVESTIGATE
+                         printf("** basic %c%d %g <= %g <= %g true %g, %g\n",
+                                RC, jSequence, lower_[iSequence], solution_[iSequence],
+                                upper_[iSequence], lowerValue, upperValue);
+#endif
+                         nWarnings++;
+                    }
+               } else if (status == isFixed) {
+                    if (!equal(upper_[iSequence], lower_[iSequence])) {
+                         nErrors++;
+#ifdef CLP_INVESTIGATE
+                         printf("** fixed! %c%d %g <= %g <= %g true %g, %g\n",
+                                RC, jSequence, lower_[iSequence], solution_[iSequence],
+                                upper_[iSequence], lowerValue, upperValue);
+#endif
+                    }
+               }
+               if (isFake) {
+                    nFake++;
+               } else {
+                    if (fakeStatus != ClpSimplexDual::noFake) {
+                         nErrors++;
+#ifdef CLP_INVESTIGATE
+                         printf("** bad fake status %c%d %d\n",
+                                RC, jSequence, fakeStatus);
+#endif
+                    }
+               }
+          }
+          if (nFake != numberFake_) {
+#ifdef CLP_INVESTIGATE
+               printf("nfake %d numberFake %d\n", nFake, numberFake_);
+#endif
+               nErrors++;
+          }
+          if (nErrors || type <= -1000) {
+#ifdef CLP_INVESTIGATE
+               printf("%d errors, %d warnings, %d free/superbasic, %d fake\n",
+                      nErrors, nWarnings, nSuperBasic, numberFake_);
+               printf("dualBound %g\n",
+                      dualBound_);
+#endif
+               if (type <= -1000) {
+                    iSequence = -type;
+                    iSequence -= 1000;
+#ifdef CLP_INVESTIGATE
+                    char RC = 'C';
+#endif
+                    int jSequence = iSequence;
+                    if (jSequence >= numberColumns_) {
+#ifdef CLP_INVESTIGATE
+                         RC = 'R';
+#endif
+                         jSequence -= numberColumns_;
+                    }
+#ifdef CLP_INVESTIGATE
+                    double lowerValue = tempLower[iSequence];
+                    double upperValue = tempUpper[iSequence];
+                    printf("*** movement>1.0e30 for  %c%d %g <= %g <= %g true %g, %g - status %d\n",
+                           RC, jSequence, lower_[iSequence], solution_[iSequence],
+                           upper_[iSequence], lowerValue, upperValue, status_[iSequence]);
+#endif
+                    assert (nErrors); // should have been picked up
+               }
+               assert (!nErrors);
+          }
+          delete [] tempLower;
+          delete [] tempUpper;
+#endif
+     } else if (lower_) {
+          // reset using status
+          int nTotal = numberRows_ + numberColumns_;
+          int iSequence;
+          if (columnScale_) {
+               for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+                    double multiplier = rhsScale_ * inverseColumnScale_[iSequence];
+                    // lower
+                    double value = columnLower_[iSequence];
+                    if (value > -1.0e30) {
+                         value *= multiplier;
+                    }
+                    lower_[iSequence] = value;
+                    // upper
+                    value = columnUpper_[iSequence];
+                    if (value < 1.0e30) {
+                         value *= multiplier;
+                    }
+                    upper_[iSequence] = value;
+               }
+               for (iSequence = 0; iSequence < numberRows_; iSequence++) {
+                    // lower
+                    double multiplier = rhsScale_ * rowScale_[iSequence];
+                    double value = rowLower_[iSequence];
+                    if (value > -1.0e30) {
+                         value *= multiplier;
+                    }
+                    lower_[iSequence+numberColumns_] = value;
+                    // upper
+                    value = rowUpper_[iSequence];
+                    if (value < 1.0e30) {
+                         value *= multiplier;
+                    }
+                    upper_[iSequence+numberColumns_] = value;
+               }
+          } else {
+               memcpy(lower_, columnLower_, numberColumns_ * sizeof(double));
+               memcpy(upper_, columnUpper_, numberColumns_ * sizeof(double));
+               memcpy(lower_ + numberColumns_, rowLower_, numberRows_ * sizeof(double));
+               memcpy(upper_ + numberColumns_, rowUpper_, numberRows_ * sizeof(double));
+          }
+          numberFake_ = 0;
+          for (iSequence = 0; iSequence < nTotal; iSequence++) {
+               FakeBound fakeStatus = getFakeBound(iSequence);
+               if (fakeStatus != ClpSimplexDual::noFake) {
+                    Status status = getStatus(iSequence);
+                    if (status == basic || status == isFixed) {
+                         setFakeBound(iSequence, ClpSimplexDual::noFake);
+                         continue;
+                    }
+                    double lowerValue = lower_[iSequence];
+                    double upperValue = upper_[iSequence];
+                    double value = solution_[iSequence];
+                    numberFake_++;
+                    if (fakeStatus == ClpSimplexDual::upperFake) {
+		         upper_[iSequence] = lowerValue + dualBound_;
+                         if (status == ClpSimplex::atLowerBound) {
+			      solution_[iSequence] = lowerValue;
+                         } else if (status == ClpSimplex::atUpperBound) {
+                              solution_[iSequence] = upper_[iSequence];
+                         } else {
+			      printf("Unknown status %d for variable %d in %s line %d\n",
+				  status,iSequence,__FILE__,__LINE__);
+			      abort();
+                         }
+                    } else if (fakeStatus == ClpSimplexDual::lowerFake) {
+		         lower_[iSequence] = upperValue - dualBound_;
+                         if (status == ClpSimplex::atLowerBound) {
+			      solution_[iSequence] = lower_[iSequence];
+                         } else if (status == ClpSimplex::atUpperBound) {
+                              solution_[iSequence] = upperValue;
+                         } else {
+			      printf("Unknown status %d for variable %d in %s line %d\n",
+				  status,iSequence,__FILE__,__LINE__);
+			      abort();
+                         }
+		    } else {
+		         assert (fakeStatus == ClpSimplexDual::bothFake);
+                         if (status == ClpSimplex::atLowerBound) {
+                              lower_[iSequence] = value;
+                              upper_[iSequence] = value + dualBound_;
+                         } else if (status == ClpSimplex::atUpperBound) {
+                              upper_[iSequence] = value;
+                              lower_[iSequence] = value - dualBound_;
+                         } else if (status == ClpSimplex::isFree ||
+                                    status == ClpSimplex::superBasic) {
+                              lower_[iSequence] = value - 0.5 * dualBound_;
+                              upper_[iSequence] = value + 0.5 * dualBound_;
+                         } else {
+			      printf("Unknown status %d for variable %d in %s line %d\n",
+				  status,iSequence,__FILE__,__LINE__);
+			      abort();
+                         }
+		    }
+               }
+          }
+#ifndef NDEBUG
+     } else {
+       COIN_DETAIL_PRINT(printf("NULL lower\n"));
+#endif
+     }
+}
diff --git a/cbits/coin/ClpSimplexDual.hpp b/cbits/coin/ClpSimplexDual.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplexDual.hpp
@@ -0,0 +1,300 @@
+/* $Id: ClpSimplexDual.hpp 1761 2011-07-06 16:06:24Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef ClpSimplexDual_H
+#define ClpSimplexDual_H
+
+#include "ClpSimplex.hpp"
+
+/** This solves LPs using the dual simplex method
+
+    It inherits from ClpSimplex.  It has no data of its own and
+    is never created - only cast from a ClpSimplex object at algorithm time.
+
+*/
+
+class ClpSimplexDual : public ClpSimplex {
+
+public:
+
+     /**@name Description of algorithm */
+     //@{
+     /** Dual algorithm
+
+         Method
+
+        It tries to be a single phase approach with a weight of 1.0 being
+        given to getting optimal and a weight of updatedDualBound_ being
+        given to getting dual feasible.  In this version I have used the
+        idea that this weight can be thought of as a fake bound.  If the
+        distance between the lower and upper bounds on a variable is less
+        than the feasibility weight then we are always better off flipping
+        to other bound to make dual feasible.  If the distance is greater
+        then we make up a fake bound updatedDualBound_ away from one bound.
+        If we end up optimal or primal infeasible, we check to see if
+        bounds okay.  If so we have finished, if not we increase updatedDualBound_
+        and continue (after checking if unbounded). I am undecided about
+        free variables - there is coding but I am not sure about it.  At
+        present I put them in basis anyway.
+
+        The code is designed to take advantage of sparsity so arrays are
+        seldom zeroed out from scratch or gone over in their entirety.
+        The only exception is a full scan to find outgoing variable for
+        Dantzig row choice.  For steepest edge we keep an updated list
+        of infeasibilities (actually squares).
+        On easy problems we don't need full scan - just
+        pick first reasonable.
+
+        One problem is how to tackle degeneracy and accuracy.  At present
+        I am using the modification of costs which I put in OSL and some
+        of what I think is the dual analog of Gill et al.
+        I am still not sure of the exact details.
+
+        The flow of dual is three while loops as follows:
+
+        while (not finished) {
+
+          while (not clean solution) {
+
+             Factorize and/or clean up solution by flipping variables so
+         dual feasible.  If looks finished check fake dual bounds.
+         Repeat until status is iterating (-1) or finished (0,1,2)
+
+          }
+
+          while (status==-1) {
+
+            Iterate until no pivot in or out or time to re-factorize.
+
+            Flow is:
+
+            choose pivot row (outgoing variable).  if none then
+        we are primal feasible so looks as if done but we need to
+        break and check bounds etc.
+
+        Get pivot row in tableau
+
+            Choose incoming column.  If we don't find one then we look
+        primal infeasible so break and check bounds etc.  (Also the
+        pivot tolerance is larger after any iterations so that may be
+        reason)
+
+            If we do find incoming column, we may have to adjust costs to
+        keep going forwards (anti-degeneracy).  Check pivot will be stable
+        and if unstable throw away iteration and break to re-factorize.
+        If minor error re-factorize after iteration.
+
+        Update everything (this may involve flipping variables to stay
+        dual feasible.
+
+          }
+
+        }
+
+        TODO's (or maybe not)
+
+        At present we never check we are going forwards.  I overdid that in
+        OSL so will try and make a last resort.
+
+        Needs partial scan pivot out option.
+
+        May need other anti-degeneracy measures, especially if we try and use
+        loose tolerances as a way to solve in fewer iterations.
+
+        I like idea of dynamic scaling.  This gives opportunity to decouple
+        different implications of scaling for accuracy, iteration count and
+        feasibility tolerance.
+
+        for use of exotic parameter startFinishoptions see Clpsimplex.hpp
+     */
+
+     int dual(int ifValuesPass, int startFinishOptions = 0);
+     /** For strong branching.  On input lower and upper are new bounds
+         while on output they are change in objective function values
+         (>1.0e50 infeasible).
+         Return code is 0 if nothing interesting, -1 if infeasible both
+         ways and +1 if infeasible one way (check values to see which one(s))
+         Solutions are filled in as well - even down, odd up - also
+         status and number of iterations
+     */
+     int strongBranching(int numberVariables, const int * variables,
+                         double * newLower, double * newUpper,
+                         double ** outputSolution,
+                         int * outputStatus, int * outputIterations,
+                         bool stopOnFirstInfeasible = true,
+                         bool alwaysFinish = false,
+                         int startFinishOptions = 0);
+     /// This does first part of StrongBranching
+     ClpFactorization * setupForStrongBranching(char * arrays, int numberRows,
+               int numberColumns, bool solveLp = false);
+     /// This cleans up after strong branching
+     void cleanupAfterStrongBranching(ClpFactorization * factorization);
+     //@}
+
+     /**@name Functions used in dual */
+     //@{
+     /** This has the flow between re-factorizations
+         Broken out for clarity and will be used by strong branching
+
+         Reasons to come out:
+         -1 iterations etc
+         -2 inaccuracy
+         -3 slight inaccuracy (and done iterations)
+         +0 looks optimal (might be unbounded - but we will investigate)
+         +1 looks infeasible
+         +3 max iterations
+
+         If givenPi not NULL then in values pass
+      */
+     int whileIterating(double * & givenPi, int ifValuesPass);
+     /** The duals are updated by the given arrays.
+         Returns number of infeasibilities.
+         After rowArray and columnArray will just have those which
+         have been flipped.
+         Variables may be flipped between bounds to stay dual feasible.
+         The output vector has movement of primal
+         solution (row length array) */
+     int updateDualsInDual(CoinIndexedVector * rowArray,
+                           CoinIndexedVector * columnArray,
+                           CoinIndexedVector * outputArray,
+                           double theta,
+                           double & objectiveChange,
+                           bool fullRecompute);
+     /** The duals are updated by the given arrays.
+         This is in values pass - so no changes to primal is made
+     */
+     void updateDualsInValuesPass(CoinIndexedVector * rowArray,
+                                  CoinIndexedVector * columnArray,
+                                  double theta);
+     /** While updateDualsInDual sees what effect is of flip
+         this does actual flipping.
+     */
+     void flipBounds(CoinIndexedVector * rowArray,
+                     CoinIndexedVector * columnArray);
+     /**
+         Row array has row part of pivot row
+         Column array has column part.
+         This chooses pivot column.
+         Spare arrays are used to save pivots which will go infeasible
+         We will check for basic so spare array will never overflow.
+         If necessary will modify costs
+         For speed, we may need to go to a bucket approach when many
+         variables are being flipped.
+         Returns best possible pivot value
+     */
+     double dualColumn(CoinIndexedVector * rowArray,
+                       CoinIndexedVector * columnArray,
+                       CoinIndexedVector * spareArray,
+                       CoinIndexedVector * spareArray2,
+                       double accpetablePivot,
+                       CoinBigIndex * dubiousWeights);
+     /// Does first bit of dualColumn
+     int dualColumn0(const CoinIndexedVector * rowArray,
+                     const CoinIndexedVector * columnArray,
+                     CoinIndexedVector * spareArray,
+                     double acceptablePivot,
+                     double & upperReturn, double &bestReturn, double & badFree);
+     /**
+         Row array has row part of pivot row
+         Column array has column part.
+         This sees what is best thing to do in dual values pass
+         if sequenceIn==sequenceOut can change dual on chosen row and leave variable in basis
+     */
+     void checkPossibleValuesMove(CoinIndexedVector * rowArray,
+                                  CoinIndexedVector * columnArray,
+                                  double acceptablePivot);
+     /**
+         Row array has row part of pivot row
+         Column array has column part.
+         This sees what is best thing to do in branch and bound cleanup
+         If sequenceIn_ < 0 then can't do anything
+     */
+     void checkPossibleCleanup(CoinIndexedVector * rowArray,
+                               CoinIndexedVector * columnArray,
+                               double acceptablePivot);
+     /**
+         This sees if we can move duals in dual values pass.
+         This is done before any pivoting
+     */
+     void doEasyOnesInValuesPass(double * givenReducedCosts);
+     /**
+         Chooses dual pivot row
+         Would be faster with separate region to scan
+         and will have this (with square of infeasibility) when steepest
+         For easy problems we can just choose one of the first rows we look at
+
+         If alreadyChosen >=0 then in values pass and that row has been
+         selected
+     */
+     void dualRow(int alreadyChosen);
+     /** Checks if any fake bounds active - if so returns number and modifies
+         updatedDualBound_ and everything.
+         Free variables will be left as free
+         Returns number of bounds changed if >=0
+         Returns -1 if not initialize and no effect
+         Fills in changeVector which can be used to see if unbounded
+         and cost of change vector
+         If 2 sets to original (just changed)
+     */
+     int changeBounds(int initialize, CoinIndexedVector * outputArray,
+                      double & changeCost);
+     /** As changeBounds but just changes new bounds for a single variable.
+         Returns true if change */
+     bool changeBound( int iSequence);
+     /// Restores bound to original bound
+     void originalBound(int iSequence);
+     /** Checks if tentative optimal actually means unbounded in dual
+         Returns -3 if not, 2 if is unbounded */
+     int checkUnbounded(CoinIndexedVector * ray, CoinIndexedVector * spare,
+                        double changeCost);
+     /**  Refactorizes if necessary
+          Checks if finished.  Updates status.
+          lastCleaned refers to iteration at which some objective/feasibility
+          cleaning too place.
+
+          type - 0 initial so set up save arrays etc
+               - 1 normal -if good update save
+           - 2 restoring from saved
+     */
+     void statusOfProblemInDual(int & lastCleaned, int type,
+                                double * givenDjs, ClpDataSave & saveData,
+                                int ifValuesPass);
+     /** Perturbs problem (method depends on perturbation())
+         returns nonzero if should go to dual */
+     int perturb();
+     /** Fast iterations.  Misses out a lot of initialization.
+         Normally stops on maximum iterations, first re-factorization
+         or tentative optimum.  If looks interesting then continues as
+         normal.  Returns 0 if finished properly, 1 otherwise.
+     */
+     int fastDual(bool alwaysFinish = false);
+     /** Checks number of variables at fake bounds.  This is used by fastDual
+         so can exit gracefully before end */
+     int numberAtFakeBound();
+
+     /** Pivot in a variable and choose an outgoing one.  Assumes dual
+         feasible - will not go through a reduced cost.  Returns step length in theta
+         Return codes as before but -1 means no acceptable pivot
+     */
+     int pivotResultPart1();
+     /** Get next free , -1 if none */
+     int nextSuperBasic();
+     /** Startup part of dual (may be extended to other algorithms)
+         returns 0 if good, 1 if bad */
+     int startupSolve(int ifValuesPass, double * saveDuals, int startFinishOptions);
+     void finishSolve(int startFinishOptions);
+     void gutsOfDual(int ifValuesPass, double * & saveDuals, int initialStatus,
+                     ClpDataSave & saveData);
+     //int dual2(int ifValuesPass,int startFinishOptions=0);
+     void resetFakeBounds(int type);
+
+     //@}
+};
+#endif
diff --git a/cbits/coin/ClpSimplexNonlinear.cpp b/cbits/coin/ClpSimplexNonlinear.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplexNonlinear.cpp
@@ -0,0 +1,4159 @@
+/* $Id: ClpSimplexNonlinear.cpp 1931 2013-04-06 20:44:29Z stefan $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include <math.h>
+#include "CoinHelperFunctions.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "ClpSimplexNonlinear.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpNonLinearCost.hpp"
+#include "ClpLinearObjective.hpp"
+#include "ClpConstraint.hpp"
+#include "ClpQuadraticObjective.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpPrimalColumnPivot.hpp"
+#include "ClpMessage.hpp"
+#include "ClpEventHandler.hpp"
+#include <cfloat>
+#include <cassert>
+#include <string>
+#include <stdio.h>
+#include <iostream>
+#ifndef NDEBUG
+#define CLP_DEBUG 1
+#endif
+// primal
+int ClpSimplexNonlinear::primal ()
+{
+
+     int ifValuesPass = 1;
+     algorithm_ = +3;
+
+     // save data
+     ClpDataSave data = saveData();
+     matrix_->refresh(this); // make sure matrix okay
+
+     // Save objective
+     ClpObjective * saveObjective = NULL;
+     if (objective_->type() > 1) {
+          // expand to full if quadratic
+#ifndef NO_RTTI
+          ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objective_));
+#else
+          ClpQuadraticObjective * quadraticObj = NULL;
+          if (objective_->type() == 2)
+               quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+          // for moment only if no scaling
+          // May be faster if switched off - but can't see why
+          if (!quadraticObj->fullMatrix() && (!rowScale_ && !scalingFlag_) && objectiveScale_ == 1.0) {
+               saveObjective = objective_;
+               objective_ = new ClpQuadraticObjective(*quadraticObj, 1);
+          }
+     }
+     double bestObjectiveWhenFlagged = COIN_DBL_MAX;
+     int pivotMode = 15;
+     //pivotMode=20;
+
+     // initialize - maybe values pass and algorithm_ is +1
+     // true does something (? perturbs)
+     if (!startup(true)) {
+
+          // Set average theta
+          nonLinearCost_->setAverageTheta(1.0e3);
+          int lastCleaned = 0; // last time objective or bounds cleaned up
+
+          // Say no pivot has occurred (for steepest edge and updates)
+          pivotRow_ = -2;
+
+          // This says whether to restore things etc
+          int factorType = 0;
+          // Start check for cycles
+          progress_.startCheck();
+          /*
+            Status of problem:
+            0 - optimal
+            1 - infeasible
+            2 - unbounded
+            -1 - iterating
+            -2 - factorization wanted
+            -3 - redo checking without factorization
+            -4 - looks infeasible
+            -5 - looks unbounded
+          */
+          while (problemStatus_ < 0) {
+               int iRow, iColumn;
+               // clear
+               for (iRow = 0; iRow < 4; iRow++) {
+                    rowArray_[iRow]->clear();
+               }
+
+               for (iColumn = 0; iColumn < 2; iColumn++) {
+                    columnArray_[iColumn]->clear();
+               }
+
+               // give matrix (and model costs and bounds a chance to be
+               // refreshed (normally null)
+               matrix_->refresh(this);
+               // If getting nowhere - why not give it a kick
+               // If we have done no iterations - special
+               if (lastGoodIteration_ == numberIterations_ && factorType)
+                    factorType = 3;
+
+               // may factorize, checks if problem finished
+               if (objective_->type() > 1 && lastFlaggedIteration_ >= 0 &&
+                         numberIterations_ > lastFlaggedIteration_ + 507) {
+                    unflag();
+                    lastFlaggedIteration_ = numberIterations_;
+                    if (pivotMode >= 10) {
+                         pivotMode--;
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("pivot mode now %d\n", pivotMode);
+#endif
+                         if (pivotMode == 9)
+                              pivotMode = 0;	// switch off fast attempt
+                    }
+               }
+               statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true,
+                                       bestObjectiveWhenFlagged);
+
+               // Say good factorization
+               factorType = 1;
+
+               // Say no pivot has occurred (for steepest edge and updates)
+               pivotRow_ = -2;
+
+               // exit if victory declared
+               if (problemStatus_ >= 0)
+                    break;
+
+               // test for maximum iterations
+               if (hitMaximumIterations() || (ifValuesPass == 2 && firstFree_ < 0)) {
+                    problemStatus_ = 3;
+                    break;
+               }
+
+               if (firstFree_ < 0) {
+                    if (ifValuesPass) {
+                         // end of values pass
+                         ifValuesPass = 0;
+                         int status = eventHandler_->event(ClpEventHandler::endOfValuesPass);
+                         if (status >= 0) {
+                              problemStatus_ = 5;
+                              secondaryStatus_ = ClpEventHandler::endOfValuesPass;
+                              break;
+                         }
+                    }
+               }
+               // Check event
+               {
+                    int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
+                    if (status >= 0) {
+                         problemStatus_ = 5;
+                         secondaryStatus_ = ClpEventHandler::endOfFactorization;
+                         break;
+                    }
+               }
+               // Iterate
+               whileIterating(pivotMode);
+          }
+     }
+     // if infeasible get real values
+     if (problemStatus_ == 1) {
+          infeasibilityCost_ = 0.0;
+          createRim(1 + 4);
+          delete nonLinearCost_;
+          nonLinearCost_ = new ClpNonLinearCost(this);
+          nonLinearCost_->checkInfeasibilities(0.0);
+          sumPrimalInfeasibilities_ = nonLinearCost_->sumInfeasibilities();
+          numberPrimalInfeasibilities_ = nonLinearCost_->numberInfeasibilities();
+          // and get good feasible duals
+          computeDuals(NULL);
+     }
+     // correct objective value
+     if (numberColumns_)
+          objectiveValue_ = nonLinearCost_->feasibleCost() + objective_->nonlinearOffset();
+     objectiveValue_ /= (objectiveScale_ * rhsScale_);
+     // clean up
+     unflag();
+     finish();
+     restoreData(data);
+     // restore objective if full
+     if (saveObjective) {
+          delete objective_;
+          objective_ = saveObjective;
+     }
+     return problemStatus_;
+}
+/*  Refactorizes if necessary
+    Checks if finished.  Updates status.
+    lastCleaned refers to iteration at which some objective/feasibility
+    cleaning too place.
+
+    type - 0 initial so set up save arrays etc
+    - 1 normal -if good update save
+    - 2 restoring from saved
+*/
+void
+ClpSimplexNonlinear::statusOfProblemInPrimal(int & lastCleaned, int type,
+          ClpSimplexProgress * progress,
+          bool doFactorization,
+          double & bestObjectiveWhenFlagged)
+{
+     int dummy; // for use in generalExpanded
+     if (type == 2) {
+          // trouble - restore solution
+          CoinMemcpyN(saveStatus_, (numberColumns_ + numberRows_), status_ );
+          CoinMemcpyN(savedSolution_ + numberColumns_ ,	numberRows_, rowActivityWork_);
+          CoinMemcpyN(savedSolution_ ,	numberColumns_, columnActivityWork_);
+          // restore extra stuff
+          matrix_->generalExpanded(this, 6, dummy);
+          forceFactorization_ = 1; // a bit drastic but ..
+          pivotRow_ = -1; // say no weights update
+          changeMade_++; // say change made
+     }
+     int saveThreshold = factorization_->sparseThreshold();
+     int tentativeStatus = problemStatus_;
+     int numberThrownOut = 1; // to loop round on bad factorization in values pass
+     while (numberThrownOut) {
+          if (problemStatus_ > -3 || problemStatus_ == -4) {
+               // factorize
+               // later on we will need to recover from singularities
+               // also we could skip if first time
+               // do weights
+               // This may save pivotRow_ for use
+               if (doFactorization)
+                    primalColumnPivot_->saveWeights(this, 1);
+
+               if (type && doFactorization) {
+                    // is factorization okay?
+                    int factorStatus = internalFactorize(1);
+                    if (factorStatus) {
+                         if (type != 1 || largestPrimalError_ > 1.0e3
+                                   || largestDualError_ > 1.0e3) {
+                              // was ||largestDualError_>1.0e3||objective_->type()>1) {
+                              // switch off dense
+                              int saveDense = factorization_->denseThreshold();
+                              factorization_->setDenseThreshold(0);
+                              // make sure will do safe factorization
+                              pivotVariable_[0] = -1;
+                              internalFactorize(2);
+                              factorization_->setDenseThreshold(saveDense);
+                              // Go to safe
+                              factorization_->pivotTolerance(0.99);
+                              // restore extra stuff
+                              matrix_->generalExpanded(this, 6, dummy);
+                         } else {
+                              // no - restore previous basis
+                              CoinMemcpyN(saveStatus_, (numberColumns_ + numberRows_), status_ );
+                              CoinMemcpyN(savedSolution_ + numberColumns_ ,		numberRows_, rowActivityWork_);
+                              CoinMemcpyN(savedSolution_ ,		numberColumns_, columnActivityWork_);
+                              // restore extra stuff
+                              matrix_->generalExpanded(this, 6, dummy);
+                              matrix_->generalExpanded(this, 5, dummy);
+                              forceFactorization_ = 1; // a bit drastic but ..
+                              type = 2;
+                              // Go to safe
+                              factorization_->pivotTolerance(0.99);
+                              if (internalFactorize(1) != 0)
+                                   largestPrimalError_ = 1.0e4; // force other type
+                         }
+                         // flag incoming
+                         if (sequenceIn_ >= 0 && getStatus(sequenceIn_) != basic) {
+                              setFlagged(sequenceIn_);
+                              saveStatus_[sequenceIn_] = status_[sequenceIn_];
+                         }
+                         changeMade_++; // say change made
+                    }
+               }
+               if (problemStatus_ != -4)
+                    problemStatus_ = -3;
+          }
+          // at this stage status is -3 or -5 if looks unbounded
+          // get primal and dual solutions
+          // put back original costs and then check
+          createRim(4);
+          // May need to do more if column generation
+          dummy = 4;
+          matrix_->generalExpanded(this, 9, dummy);
+          numberThrownOut = gutsOfSolution(NULL, NULL, (firstFree_ >= 0));
+          if (numberThrownOut) {
+               problemStatus_ = tentativeStatus;
+               doFactorization = true;
+          }
+     }
+     // Double check reduced costs if no action
+     if (progress->lastIterationNumber(0) == numberIterations_) {
+          if (primalColumnPivot_->looksOptimal()) {
+               numberDualInfeasibilities_ = 0;
+               sumDualInfeasibilities_ = 0.0;
+          }
+     }
+     // Check if looping
+     int loop;
+     if (type != 2)
+          loop = progress->looping();
+     else
+          loop = -1;
+     if (loop >= 0) {
+          if (!problemStatus_) {
+               // declaring victory
+               numberPrimalInfeasibilities_ = 0;
+               sumPrimalInfeasibilities_ = 0.0;
+          } else {
+               problemStatus_ = loop; //exit if in loop
+               problemStatus_ = 10; // instead - try other algorithm
+          }
+          problemStatus_ = 10; // instead - try other algorithm
+          return ;
+     } else if (loop < -1) {
+          // Is it time for drastic measures
+          if (nonLinearCost_->numberInfeasibilities() && progress->badTimes() > 5 &&
+                    progress->oddState() < 10 && progress->oddState() >= 0) {
+               progress->newOddState();
+               nonLinearCost_->zapCosts();
+          }
+          // something may have changed
+          gutsOfSolution(NULL, NULL, true);
+     }
+     // If progress then reset costs
+     if (loop == -1 && !nonLinearCost_->numberInfeasibilities() && progress->oddState() < 0) {
+          createRim(4, false); // costs back
+          delete nonLinearCost_;
+          nonLinearCost_ = new ClpNonLinearCost(this);
+          progress->endOddState();
+          gutsOfSolution(NULL, NULL, true);
+     }
+     // Flag to say whether to go to dual to clean up
+     //bool goToDual = false;
+     // really for free variables in
+     //if((progressFlag_&2)!=0)
+     //problemStatus_=-1;;
+     progressFlag_ = 0; //reset progress flag
+
+     handler_->message(CLP_SIMPLEX_STATUS, messages_)
+               << numberIterations_ << nonLinearCost_->feasibleReportCost();
+     handler_->printing(nonLinearCost_->numberInfeasibilities() > 0)
+               << nonLinearCost_->sumInfeasibilities() << nonLinearCost_->numberInfeasibilities();
+     handler_->printing(sumDualInfeasibilities_ > 0.0)
+               << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+     handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                        < numberDualInfeasibilities_)
+               << numberDualInfeasibilitiesWithoutFree_;
+     handler_->message() << CoinMessageEol;
+     if (!primalFeasible()) {
+          nonLinearCost_->checkInfeasibilities(primalTolerance_);
+          gutsOfSolution(NULL, NULL, true);
+          nonLinearCost_->checkInfeasibilities(primalTolerance_);
+     }
+     double trueInfeasibility = nonLinearCost_->sumInfeasibilities();
+     if (trueInfeasibility > 1.0) {
+          // If infeasibility going up may change weights
+          double testValue = trueInfeasibility - 1.0e-4 * (10.0 + trueInfeasibility);
+          if(progress->lastInfeasibility() < testValue) {
+               if (infeasibilityCost_ < 1.0e14) {
+                    infeasibilityCost_ *= 1.5;
+                    if (handler_->logLevel() == 63)
+                         printf("increasing weight to %g\n", infeasibilityCost_);
+                    gutsOfSolution(NULL, NULL, true);
+               }
+          }
+     }
+     // we may wish to say it is optimal even if infeasible
+     bool alwaysOptimal = (specialOptions_ & 1) != 0;
+     // give code benefit of doubt
+     if (sumOfRelaxedDualInfeasibilities_ == 0.0 &&
+               sumOfRelaxedPrimalInfeasibilities_ == 0.0) {
+          // say optimal (with these bounds etc)
+          numberDualInfeasibilities_ = 0;
+          sumDualInfeasibilities_ = 0.0;
+          numberPrimalInfeasibilities_ = 0;
+          sumPrimalInfeasibilities_ = 0.0;
+     }
+     // had ||(type==3&&problemStatus_!=-5) -- ??? why ????
+     if (dualFeasible() || problemStatus_ == -4) {
+          // see if extra helps
+          if (nonLinearCost_->numberInfeasibilities() &&
+                    (nonLinearCost_->sumInfeasibilities() > 1.0e-3 || sumOfRelaxedPrimalInfeasibilities_)
+                    && !alwaysOptimal) {
+               //may need infeasiblity cost changed
+               // we can see if we can construct a ray
+               // make up a new objective
+               double saveWeight = infeasibilityCost_;
+               // save nonlinear cost as we are going to switch off costs
+               ClpNonLinearCost * nonLinear = nonLinearCost_;
+               // do twice to make sure Primal solution has settled
+               // put non-basics to bounds in case tolerance moved
+               // put back original costs
+               createRim(4);
+               nonLinearCost_->checkInfeasibilities(0.0);
+               gutsOfSolution(NULL, NULL, true);
+
+               infeasibilityCost_ = 1.0e100;
+               // put back original costs
+               createRim(4);
+               nonLinearCost_->checkInfeasibilities(primalTolerance_);
+               // may have fixed infeasibilities - double check
+               if (nonLinearCost_->numberInfeasibilities() == 0) {
+                    // carry on
+                    problemStatus_ = -1;
+                    infeasibilityCost_ = saveWeight;
+                    nonLinearCost_->checkInfeasibilities(primalTolerance_);
+               } else {
+                    nonLinearCost_ = NULL;
+                    // scale
+                    int i;
+                    for (i = 0; i < numberRows_ + numberColumns_; i++)
+                         cost_[i] *= 1.0e-95;
+                    gutsOfSolution(NULL, NULL, false);
+                    nonLinearCost_ = nonLinear;
+                    infeasibilityCost_ = saveWeight;
+                    if ((infeasibilityCost_ >= 1.0e18 ||
+                              numberDualInfeasibilities_ == 0) && perturbation_ == 101) {
+                         /* goToDual = unPerturb(); // stop any further perturbation
+                         if (nonLinearCost_->sumInfeasibilities() > 1.0e-1)
+                              goToDual = false;
+                         */
+                         unPerturb();
+                         nonLinearCost_->checkInfeasibilities(primalTolerance_);
+                         numberDualInfeasibilities_ = 1; // carry on
+                         problemStatus_ = -1;
+                    }
+                    if (infeasibilityCost_ >= 1.0e20 ||
+                              numberDualInfeasibilities_ == 0) {
+                         // we are infeasible - use as ray
+                         delete [] ray_;
+                         ray_ = new double [numberRows_];
+                         CoinMemcpyN(dual_, numberRows_, ray_);
+                         // and get feasible duals
+                         infeasibilityCost_ = 0.0;
+                         createRim(4);
+                         nonLinearCost_->checkInfeasibilities(primalTolerance_);
+                         gutsOfSolution(NULL, NULL, true);
+                         // so will exit
+                         infeasibilityCost_ = 1.0e30;
+                         // reset infeasibilities
+                         sumPrimalInfeasibilities_ = nonLinearCost_->sumInfeasibilities();;
+                         numberPrimalInfeasibilities_ =
+                              nonLinearCost_->numberInfeasibilities();
+                    }
+                    if (infeasibilityCost_ < 1.0e20) {
+                         infeasibilityCost_ *= 5.0;
+                         changeMade_++; // say change made
+                         unflag();
+                         handler_->message(CLP_PRIMAL_WEIGHT, messages_)
+                                   << infeasibilityCost_
+                                   << CoinMessageEol;
+                         // put back original costs and then check
+                         createRim(4);
+                         nonLinearCost_->checkInfeasibilities(0.0);
+                         gutsOfSolution(NULL, NULL, true);
+                         problemStatus_ = -1; //continue
+                         //goToDual = false;
+                    } else {
+                         // say infeasible
+                         problemStatus_ = 1;
+                    }
+               }
+          } else {
+               // may be optimal
+               if (perturbation_ == 101) {
+                    /* goToDual =*/ unPerturb(); // stop any further perturbation
+                    lastCleaned = -1; // carry on
+               }
+               bool unflagged = unflag() != 0;
+               if ( lastCleaned != numberIterations_ || unflagged) {
+                    handler_->message(CLP_PRIMAL_OPTIMAL, messages_)
+                              << primalTolerance_
+                              << CoinMessageEol;
+                    double current = nonLinearCost_->feasibleReportCost();
+                    if (numberTimesOptimal_ < 4) {
+                         if (bestObjectiveWhenFlagged <= current) {
+                              numberTimesOptimal_++;
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32)
+                                   printf("%d times optimal, current %g best %g\n", numberTimesOptimal_,
+                                          current, bestObjectiveWhenFlagged);
+#endif
+                         } else {
+                              bestObjectiveWhenFlagged = current;
+                         }
+                         changeMade_++; // say change made
+                         if (numberTimesOptimal_ == 1) {
+                              // better to have small tolerance even if slower
+                              factorization_->zeroTolerance(CoinMin(factorization_->zeroTolerance(), 1.0e-15));
+                         }
+                         lastCleaned = numberIterations_;
+                         if (primalTolerance_ != dblParam_[ClpPrimalTolerance])
+                              handler_->message(CLP_PRIMAL_ORIGINAL, messages_)
+                                        << CoinMessageEol;
+                         double oldTolerance = primalTolerance_;
+                         primalTolerance_ = dblParam_[ClpPrimalTolerance];
+                         // put back original costs and then check
+                         createRim(4);
+                         nonLinearCost_->checkInfeasibilities(oldTolerance);
+                         gutsOfSolution(NULL, NULL, true);
+                         if (sumOfRelaxedDualInfeasibilities_ == 0.0 &&
+                                   sumOfRelaxedPrimalInfeasibilities_ == 0.0) {
+                              // say optimal (with these bounds etc)
+                              numberDualInfeasibilities_ = 0;
+                              sumDualInfeasibilities_ = 0.0;
+                              numberPrimalInfeasibilities_ = 0;
+                              sumPrimalInfeasibilities_ = 0.0;
+                         }
+                         if (dualFeasible() && !nonLinearCost_->numberInfeasibilities() && lastCleaned >= 0)
+                              problemStatus_ = 0;
+                         else
+                              problemStatus_ = -1;
+                    } else {
+                         problemStatus_ = 0; // optimal
+                         if (lastCleaned < numberIterations_) {
+                              handler_->message(CLP_SIMPLEX_GIVINGUP, messages_)
+                                        << CoinMessageEol;
+                         }
+                    }
+               } else {
+                    problemStatus_ = 0; // optimal
+               }
+          }
+     } else {
+          // see if looks unbounded
+          if (problemStatus_ == -5) {
+               if (nonLinearCost_->numberInfeasibilities()) {
+                    if (infeasibilityCost_ > 1.0e18 && perturbation_ == 101) {
+                         // back off weight
+                         infeasibilityCost_ = 1.0e13;
+                         unPerturb(); // stop any further perturbation
+                    }
+                    //we need infeasiblity cost changed
+                    if (infeasibilityCost_ < 1.0e20) {
+                         infeasibilityCost_ *= 5.0;
+                         changeMade_++; // say change made
+                         unflag();
+                         handler_->message(CLP_PRIMAL_WEIGHT, messages_)
+                                   << infeasibilityCost_
+                                   << CoinMessageEol;
+                         // put back original costs and then check
+                         createRim(4);
+                         gutsOfSolution(NULL, NULL, true);
+                         problemStatus_ = -1; //continue
+                    } else {
+                         // say unbounded
+                         problemStatus_ = 2;
+                    }
+               } else {
+                    // say unbounded
+                    problemStatus_ = 2;
+               }
+          } else {
+               if(type == 3 && problemStatus_ != -5)
+                    unflag(); // odd
+               // carry on
+               problemStatus_ = -1;
+          }
+     }
+     // save extra stuff
+     matrix_->generalExpanded(this, 5, dummy);
+     if (type == 0 || type == 1) {
+          if (type != 1 || !saveStatus_) {
+               // create save arrays
+               delete [] saveStatus_;
+               delete [] savedSolution_;
+               saveStatus_ = new unsigned char [numberRows_+numberColumns_];
+               savedSolution_ = new double [numberRows_+numberColumns_];
+          }
+          // save arrays
+          CoinMemcpyN(status_, (numberColumns_ + numberRows_), saveStatus_);
+          CoinMemcpyN(rowActivityWork_,	numberRows_, savedSolution_ + numberColumns_ );
+          CoinMemcpyN(columnActivityWork_, numberColumns_, savedSolution_ );
+     }
+     if (doFactorization) {
+          // restore weights (if saved) - also recompute infeasibility list
+          if (tentativeStatus > -3)
+               primalColumnPivot_->saveWeights(this, (type < 2) ? 2 : 4);
+          else
+               primalColumnPivot_->saveWeights(this, 3);
+          if (saveThreshold) {
+               // use default at present
+               factorization_->sparseThreshold(0);
+               factorization_->goSparse();
+          }
+     }
+     if (problemStatus_ < 0 && !changeMade_) {
+          problemStatus_ = 4; // unknown
+     }
+     lastGoodIteration_ = numberIterations_;
+     //if (goToDual)
+     //problemStatus_=10; // try dual
+     // Allow matrices to be sorted etc
+     int fake = -999; // signal sort
+     matrix_->correctSequence(this, fake, fake);
+}
+/*
+  Reasons to come out:
+  -1 iterations etc
+  -2 inaccuracy
+  -3 slight inaccuracy (and done iterations)
+  -4 end of values pass and done iterations
+  +0 looks optimal (might be infeasible - but we will investigate)
+  +2 looks unbounded
+  +3 max iterations
+*/
+int
+ClpSimplexNonlinear::whileIterating(int & pivotMode)
+{
+     // Say if values pass
+     //int ifValuesPass=(firstFree_>=0) ? 1 : 0;
+     int ifValuesPass = 1;
+     int returnCode = -1;
+     // status stays at -1 while iterating, >=0 finished, -2 to invert
+     // status -3 to go to top without an invert
+     int numberInterior = 0;
+     int nextUnflag = 10;
+     int nextUnflagIteration = numberIterations_ + 10;
+     // get two arrays
+     double * array1 = new double[2*(numberRows_+numberColumns_)];
+     double solutionError = -1.0;
+     while (problemStatus_ == -1) {
+          int result;
+          rowArray_[1]->clear();
+          //#define CLP_DEBUG
+#if CLP_DEBUG > 1
+          rowArray_[0]->checkClear();
+          rowArray_[1]->checkClear();
+          rowArray_[2]->checkClear();
+          rowArray_[3]->checkClear();
+          columnArray_[0]->checkClear();
+#endif
+          if (numberInterior >= 5) {
+               // this can go when we have better minimization
+               if (pivotMode < 10)
+                    pivotMode = 1;
+               unflag();
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32)
+                    printf("interior unflag\n");
+#endif
+               numberInterior = 0;
+               nextUnflag = 10;
+               nextUnflagIteration = numberIterations_ + 10;
+          } else {
+               if (numberInterior > nextUnflag &&
+                         numberIterations_ > nextUnflagIteration) {
+                    nextUnflagIteration = numberIterations_ + 10;
+                    nextUnflag += 10;
+                    unflag();
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("unflagging as interior\n");
+#endif
+               }
+          }
+          pivotRow_ = -1;
+          result = pivotColumn(rowArray_[3], rowArray_[0],
+                               columnArray_[0], rowArray_[1], pivotMode, solutionError,
+                               array1);
+          if (result) {
+               if (result == 2 && sequenceIn_ < 0) {
+                    // does not look good
+                    double currentObj;
+                    double thetaObj;
+                    double predictedObj;
+                    objective_->stepLength(this, solution_, solution_, 0.0,
+                                           currentObj, thetaObj, predictedObj);
+                    if (currentObj == predictedObj) {
+#ifdef CLP_INVESTIGATE
+                         printf("looks bad - no change in obj %g\n", currentObj);
+#endif
+                         if (factorization_->pivots())
+                              result = 3;
+                         else
+                              problemStatus_ = 0;
+                    }
+               }
+               if (result == 3)
+                    break; // null vector not accurate
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32) {
+                    double currentObj;
+                    double thetaObj;
+                    double predictedObj;
+                    objective_->stepLength(this, solution_, solution_, 0.0,
+                                           currentObj, thetaObj, predictedObj);
+                    printf("obj %g after interior move\n", currentObj);
+               }
+#endif
+               // just move and try again
+               if (pivotMode < 10) {
+                    pivotMode = result - 1;
+                    numberInterior++;
+               }
+               continue;
+          } else {
+               if (pivotMode < 10) {
+                    if (theta_ > 0.001)
+                         pivotMode = 0;
+                    else if (pivotMode == 2)
+                         pivotMode = 1;
+               }
+               numberInterior = 0;
+               nextUnflag = 10;
+               nextUnflagIteration = numberIterations_ + 10;
+          }
+          sequenceOut_ = -1;
+          rowArray_[1]->clear();
+          if (sequenceIn_ >= 0) {
+               // we found a pivot column
+               assert (!flagged(sequenceIn_));
+#ifdef CLP_DEBUG
+               if ((handler_->logLevel() & 32)) {
+                    char x = isColumn(sequenceIn_) ? 'C' : 'R';
+                    std::cout << "pivot column " <<
+                              x << sequenceWithin(sequenceIn_) << std::endl;
+               }
+#endif
+               // do second half of iteration
+               if (pivotRow_ < 0 && theta_ < 1.0e-8) {
+                    assert (sequenceIn_ >= 0);
+                    returnCode = pivotResult(ifValuesPass);
+               } else {
+                    // specialized code
+                    returnCode = pivotNonlinearResult();
+                    //printf("odd pivrow %d\n",sequenceOut_);
+                    if (sequenceOut_ >= 0 && theta_ < 1.0e-5) {
+                         if (getStatus(sequenceOut_) != isFixed) {
+                              if (getStatus(sequenceOut_) == atUpperBound)
+                                   solution_[sequenceOut_] = upper_[sequenceOut_];
+                              else if (getStatus(sequenceOut_) == atLowerBound)
+                                   solution_[sequenceOut_] = lower_[sequenceOut_];
+                              setFlagged(sequenceOut_);
+                         }
+                    }
+               }
+               if (returnCode < -1 && returnCode > -5) {
+                    problemStatus_ = -2; //
+               } else if (returnCode == -5) {
+                    // something flagged - continue;
+               } else if (returnCode == 2) {
+                    problemStatus_ = -5; // looks unbounded
+               } else if (returnCode == 4) {
+                    problemStatus_ = -2; // looks unbounded but has iterated
+               } else if (returnCode != -1) {
+                    assert(returnCode == 3);
+                    problemStatus_ = 3;
+               }
+          } else {
+               // no pivot column
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32)
+                    printf("** no column pivot\n");
+#endif
+               if (pivotMode < 10) {
+                    // looks optimal
+                    primalColumnPivot_->setLooksOptimal(true);
+               } else {
+                    pivotMode--;
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("pivot mode now %d\n", pivotMode);
+#endif
+                    if (pivotMode == 9)
+                         pivotMode = 0;	// switch off fast attempt
+                    unflag();
+               }
+               if (nonLinearCost_->numberInfeasibilities())
+                    problemStatus_ = -4; // might be infeasible
+               returnCode = 0;
+               break;
+          }
+     }
+     delete [] array1;
+     return returnCode;
+}
+// Creates direction vector
+void
+ClpSimplexNonlinear::directionVector (CoinIndexedVector * vectorArray,
+                                      CoinIndexedVector * spare1, CoinIndexedVector * spare2,
+                                      int pivotMode2,
+                                      double & normFlagged, double & normUnflagged,
+                                      int & numberNonBasic)
+{
+#if CLP_DEBUG > 1
+     vectorArray->checkClear();
+     spare1->checkClear();
+     spare2->checkClear();
+#endif
+     double *array = vectorArray->denseVector();
+     int * index = vectorArray->getIndices();
+     int number = 0;
+     sequenceIn_ = -1;
+     normFlagged = 0.0;
+     normUnflagged = 1.0;
+     double dualTolerance2 = CoinMin(1.0e-8, 1.0e-2 * dualTolerance_);
+     double dualTolerance3 = CoinMin(1.0e-2, 1.0e3 * dualTolerance_);
+     if (!numberNonBasic) {
+          //if (nonLinearCost_->sumInfeasibilities()>1.0e-4)
+          //printf("infeasible\n");
+          if (!pivotMode2 || pivotMode2 >= 10) {
+               normUnflagged = 0.0;
+               double bestDj = 0.0;
+               double bestSuper = 0.0;
+               double sumSuper = 0.0;
+               sequenceIn_ = -1;
+               int nSuper = 0;
+               for (int iSequence = 0; iSequence < numberColumns_ + numberRows_; iSequence++) {
+                    array[iSequence] = 0.0;
+                    if (flagged(iSequence)) {
+                         // accumulate  norm
+                         switch(getStatus(iSequence)) {
+
+                         case basic:
+                         case ClpSimplex::isFixed:
+                              break;
+                         case atUpperBound:
+                              if (dj_[iSequence] > dualTolerance3)
+                                   normFlagged += dj_[iSequence] * dj_[iSequence];
+                              break;
+                         case atLowerBound:
+                              if (dj_[iSequence] < -dualTolerance3)
+                                   normFlagged += dj_[iSequence] * dj_[iSequence];
+                              break;
+                         case isFree:
+                         case superBasic:
+                              if (fabs(dj_[iSequence]) > dualTolerance3)
+                                   normFlagged += dj_[iSequence] * dj_[iSequence];
+                              break;
+                         }
+                         continue;
+                    }
+                    switch(getStatus(iSequence)) {
+
+                    case basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case atUpperBound:
+                         if (dj_[iSequence] > dualTolerance_) {
+                              if (dj_[iSequence] > dualTolerance3)
+                                   normUnflagged += dj_[iSequence] * dj_[iSequence];
+                              if (pivotMode2 < 10) {
+                                   array[iSequence] = -dj_[iSequence];
+                                   index[number++] = iSequence;
+                              } else {
+                                   if (dj_[iSequence] > bestDj) {
+                                        bestDj = dj_[iSequence];
+                                        sequenceIn_ = iSequence;
+                                   }
+                              }
+                         }
+                         break;
+                    case atLowerBound:
+                         if (dj_[iSequence] < -dualTolerance_) {
+                              if (dj_[iSequence] < -dualTolerance3)
+                                   normUnflagged += dj_[iSequence] * dj_[iSequence];
+                              if (pivotMode2 < 10) {
+                                   array[iSequence] = -dj_[iSequence];
+                                   index[number++] = iSequence;
+                              } else {
+                                   if (-dj_[iSequence] > bestDj) {
+                                        bestDj = -dj_[iSequence];
+                                        sequenceIn_ = iSequence;
+                                   }
+                              }
+                         }
+                         break;
+                    case isFree:
+                    case superBasic:
+                         //#define ALLSUPER
+#define NOSUPER
+#ifndef ALLSUPER
+                         if (fabs(dj_[iSequence]) > dualTolerance_) {
+                              if (fabs(dj_[iSequence]) > dualTolerance3)
+                                   normUnflagged += dj_[iSequence] * dj_[iSequence];
+                              nSuper++;
+                              bestSuper = CoinMax(fabs(dj_[iSequence]), bestSuper);
+                              sumSuper += fabs(dj_[iSequence]);
+                         }
+                         if (fabs(dj_[iSequence]) > dualTolerance2) {
+                              array[iSequence] = -dj_[iSequence];
+                              index[number++] = iSequence;
+                         }
+#else
+                         array[iSequence] = -dj_[iSequence];
+                         index[number++] = iSequence;
+                         if (pivotMode2 >= 10)
+                              bestSuper = CoinMax(fabs(dj_[iSequence]), bestSuper);
+#endif
+                         break;
+                    }
+               }
+#ifdef NOSUPER
+               // redo
+               bestSuper = sumSuper;
+               if(sequenceIn_ >= 0 && bestDj > bestSuper) {
+                    int j;
+                    // get rid of superbasics
+                    for (j = 0; j < number; j++) {
+                         int iSequence = index[j];
+                         array[iSequence] = 0.0;
+                    }
+                    number = 0;
+                    array[sequenceIn_] = -dj_[sequenceIn_];
+                    index[number++] = sequenceIn_;
+               } else {
+                    sequenceIn_ = -1;
+               }
+#else
+               if (pivotMode2 >= 10 || !nSuper) {
+                    bool takeBest = true;
+                    if (pivotMode2 == 100 && nSuper > 1)
+                         takeBest = false;
+                    if(sequenceIn_ >= 0 && takeBest) {
+                         if (fabs(dj_[sequenceIn_]) > bestSuper) {
+                              array[sequenceIn_] = -dj_[sequenceIn_];
+                              index[number++] = sequenceIn_;
+                         } else {
+                              sequenceIn_ = -1;
+                         }
+                    } else {
+                         sequenceIn_ = -1;
+                    }
+               }
+#endif
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32) {
+                    if (sequenceIn_ >= 0)
+                         printf("%d superBasic, chosen %d - dj %g\n", nSuper, sequenceIn_,
+                                dj_[sequenceIn_]);
+                    else
+                         printf("%d superBasic - none chosen\n", nSuper);
+               }
+#endif
+          } else {
+               double bestDj = 0.0;
+               double saveDj = 0.0;
+               if (sequenceOut_ >= 0) {
+                    saveDj = dj_[sequenceOut_];
+                    dj_[sequenceOut_] = 0.0;
+                    switch(getStatus(sequenceOut_)) {
+
+                    case basic:
+                         sequenceOut_ = -1;
+                    case ClpSimplex::isFixed:
+                         break;
+                    case atUpperBound:
+                         if (dj_[sequenceOut_] > dualTolerance_) {
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32)
+                                   printf("after pivot out %d values %g %g %g, dj %g\n",
+                                          sequenceOut_, lower_[sequenceOut_], solution_[sequenceOut_],
+                                          upper_[sequenceOut_], dj_[sequenceOut_]);
+#endif
+                         }
+                         break;
+                    case atLowerBound:
+                         if (dj_[sequenceOut_] < -dualTolerance_) {
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32)
+                                   printf("after pivot out %d values %g %g %g, dj %g\n",
+                                          sequenceOut_, lower_[sequenceOut_], solution_[sequenceOut_],
+                                          upper_[sequenceOut_], dj_[sequenceOut_]);
+#endif
+                         }
+                         break;
+                    case isFree:
+                    case superBasic:
+                         if (dj_[sequenceOut_] > dualTolerance_) {
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32)
+                                   printf("after pivot out %d values %g %g %g, dj %g\n",
+                                          sequenceOut_, lower_[sequenceOut_], solution_[sequenceOut_],
+                                          upper_[sequenceOut_], dj_[sequenceOut_]);
+#endif
+                         } else if (dj_[sequenceOut_] < -dualTolerance_) {
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32)
+                                   printf("after pivot out %d values %g %g %g, dj %g\n",
+                                          sequenceOut_, lower_[sequenceOut_], solution_[sequenceOut_],
+                                          upper_[sequenceOut_], dj_[sequenceOut_]);
+#endif
+                         }
+                         break;
+                    }
+               }
+               // Go for dj
+               pivotMode2 = 3;
+               for (int iSequence = 0; iSequence < numberColumns_ + numberRows_; iSequence++) {
+                    array[iSequence] = 0.0;
+                    if (flagged(iSequence))
+                         continue;
+                    switch(getStatus(iSequence)) {
+
+                    case basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case atUpperBound:
+                         if (dj_[iSequence] > dualTolerance_) {
+                              double distance = CoinMin(1.0e-2, solution_[iSequence] - lower_[iSequence]);
+                              double merit = distance * dj_[iSequence];
+                              if (pivotMode2 == 1)
+                                   merit *= 1.0e-20; // discourage
+                              if (pivotMode2 == 3)
+                                   merit = fabs(dj_[iSequence]);
+                              if (merit > bestDj) {
+                                   sequenceIn_ = iSequence;
+                                   bestDj = merit;
+                              }
+                         }
+                         break;
+                    case atLowerBound:
+                         if (dj_[iSequence] < -dualTolerance_) {
+                              double distance = CoinMin(1.0e-2, upper_[iSequence] - solution_[iSequence]);
+                              double merit = -distance * dj_[iSequence];
+                              if (pivotMode2 == 1)
+                                   merit *= 1.0e-20; // discourage
+                              if (pivotMode2 == 3)
+                                   merit = fabs(dj_[iSequence]);
+                              if (merit > bestDj) {
+                                   sequenceIn_ = iSequence;
+                                   bestDj = merit;
+                              }
+                         }
+                         break;
+                    case isFree:
+                    case superBasic:
+                         if (dj_[iSequence] > dualTolerance_) {
+                              double distance = CoinMin(1.0e-2, solution_[iSequence] - lower_[iSequence]);
+                              distance = CoinMin(solution_[iSequence] - lower_[iSequence],
+                                                 upper_[iSequence] - solution_[iSequence]);
+                              double merit = distance * dj_[iSequence];
+                              if (pivotMode2 == 1)
+                                   merit = distance;
+                              if (pivotMode2 == 3)
+                                   merit = fabs(dj_[iSequence]);
+                              if (merit > bestDj) {
+                                   sequenceIn_ = iSequence;
+                                   bestDj = merit;
+                              }
+                         } else if (dj_[iSequence] < -dualTolerance_) {
+                              double distance = CoinMin(1.0e-2, upper_[iSequence] - solution_[iSequence]);
+                              distance = CoinMin(solution_[iSequence] - lower_[iSequence],
+                                                 upper_[iSequence] - solution_[iSequence]);
+                              double merit = -distance * dj_[iSequence];
+                              if (pivotMode2 == 1)
+                                   merit = distance;
+                              if (pivotMode2 == 3)
+                                   merit = fabs(dj_[iSequence]);
+                              if (merit > bestDj) {
+                                   sequenceIn_ = iSequence;
+                                   bestDj = merit;
+                              }
+                         }
+                         break;
+                    }
+               }
+               if (sequenceOut_ >= 0) {
+                    dj_[sequenceOut_] = saveDj;
+                    sequenceOut_ = -1;
+               }
+               if (sequenceIn_ >= 0) {
+                    array[sequenceIn_] = -dj_[sequenceIn_];
+                    index[number++] = sequenceIn_;
+               }
+          }
+          numberNonBasic = number;
+     } else {
+          // compute norms
+          normUnflagged = 0.0;
+          for (int iSequence = 0; iSequence < numberColumns_ + numberRows_; iSequence++) {
+               if (flagged(iSequence)) {
+                    // accumulate  norm
+                    switch(getStatus(iSequence)) {
+
+                    case basic:
+                    case ClpSimplex::isFixed:
+                         break;
+                    case atUpperBound:
+                         if (dj_[iSequence] > dualTolerance_)
+                              normFlagged += dj_[iSequence] * dj_[iSequence];
+                         break;
+                    case atLowerBound:
+                         if (dj_[iSequence] < -dualTolerance_)
+                              normFlagged += dj_[iSequence] * dj_[iSequence];
+                         break;
+                    case isFree:
+                    case superBasic:
+                         if (fabs(dj_[iSequence]) > dualTolerance_)
+                              normFlagged += dj_[iSequence] * dj_[iSequence];
+                         break;
+                    }
+               }
+          }
+          // re-use list
+          number = 0;
+          int j;
+          for (j = 0; j < numberNonBasic; j++) {
+               int iSequence = index[j];
+               if (flagged(iSequence))
+                    continue;
+               switch(getStatus(iSequence)) {
+
+               case basic:
+               case ClpSimplex::isFixed:
+                    continue; //abort();
+                    break;
+               case atUpperBound:
+                    if (dj_[iSequence] > dualTolerance_) {
+                         number++;
+                         normUnflagged += dj_[iSequence] * dj_[iSequence];
+                    }
+                    break;
+               case atLowerBound:
+                    if (dj_[iSequence] < -dualTolerance_) {
+                         number++;
+                         normUnflagged += dj_[iSequence] * dj_[iSequence];
+                    }
+                    break;
+               case isFree:
+               case superBasic:
+                    if (fabs(dj_[iSequence]) > dualTolerance_) {
+                         number++;
+                         normUnflagged += dj_[iSequence] * dj_[iSequence];
+                    }
+                    break;
+               }
+               array[iSequence] = -dj_[iSequence];
+          }
+          // switch to large
+          normUnflagged = 1.0;
+          if (!number) {
+               for (j = 0; j < numberNonBasic; j++) {
+                    int iSequence = index[j];
+                    array[iSequence] = 0.0;
+               }
+               numberNonBasic = 0;
+          }
+          number = numberNonBasic;
+     }
+     if (number) {
+          int j;
+          // Now do basic ones - how do I compensate for small basic infeasibilities?
+          int iRow;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               int iPivot = pivotVariable_[iRow];
+               double value = 0.0;
+               if (solution_[iPivot] > upper_[iPivot]) {
+                    value = upper_[iPivot] - solution_[iPivot];
+               } else if (solution_[iPivot] < lower_[iPivot]) {
+                    value = lower_[iPivot] - solution_[iPivot];
+               }
+               //if (value)
+               //printf("inf %d %g %g %g\n",iPivot,lower_[iPivot],solution_[iPivot],
+               //     upper_[iPivot]);
+               //value=0.0;
+               value *= -1.0e0;
+               if (value) {
+                    array[iPivot] = value;
+                    index[number++] = iPivot;
+               }
+          }
+          double * array2 = spare1->denseVector();
+          int * index2 = spare1->getIndices();
+          int number2 = 0;
+          times(-1.0, array, array2);
+          array = array + numberColumns_;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               double value = array2[iRow] + array[iRow];
+               if (value) {
+                    array2[iRow] = value;
+                    index2[number2++] = iRow;
+               } else {
+                    array2[iRow] = 0.0;
+               }
+          }
+          array -= numberColumns_;
+          spare1->setNumElements(number2);
+          // Ftran
+          factorization_->updateColumn(spare2, spare1);
+          number2 = spare1->getNumElements();
+          for (j = 0; j < number2; j++) {
+               int iSequence = index2[j];
+               double value = array2[iSequence];
+               array2[iSequence] = 0.0;
+               if (value) {
+                    int iPivot = pivotVariable_[iSequence];
+                    double oldValue = array[iPivot];
+                    if (!oldValue) {
+                         array[iPivot] = value;
+                         index[number++] = iPivot;
+                    } else {
+                         // something already there
+                         array[iPivot] = value + oldValue;
+                    }
+               }
+          }
+          spare1->setNumElements(0);
+     }
+     vectorArray->setNumElements(number);
+}
+#define MINTYPE 1
+#if MINTYPE==2
+static double
+innerProductIndexed(const double * region1, int size, const double * region2, const int * which)
+{
+     int i;
+     double value = 0.0;
+     for (i = 0; i < size; i++) {
+          int j = which[i];
+          value += region1[j] * region2[j];
+     }
+     return value;
+}
+#endif
+/*
+   Row array and column array have direction
+   Returns 0 - can do normal iteration (basis change)
+   1 - no basis change
+*/
+int
+ClpSimplexNonlinear::pivotColumn(CoinIndexedVector * longArray,
+                                 CoinIndexedVector * rowArray,
+                                 CoinIndexedVector * columnArray,
+                                 CoinIndexedVector * spare,
+                                 int & pivotMode,
+                                 double & solutionError,
+                                 double * dArray)
+{
+     // say not optimal
+     primalColumnPivot_->setLooksOptimal(false);
+     double acceptablePivot = 1.0e-10;
+     int lastSequenceIn = -1;
+     if (pivotMode && pivotMode < 10) {
+          acceptablePivot = 1.0e-6;
+          if (factorization_->pivots())
+               acceptablePivot = 1.0e-5; // if we have iterated be more strict
+     }
+     double acceptableBasic = 1.0e-7;
+
+     int number = longArray->getNumElements();
+     int numberTotal = numberRows_ + numberColumns_;
+     int bestSequence = -1;
+     int bestBasicSequence = -1;
+     double eps = 1.0e-1;
+     eps = 1.0e-6;
+     double basicTheta = 1.0e30;
+     double objTheta = 0.0;
+     bool finished = false;
+     sequenceIn_ = -1;
+     int nPasses = 0;
+     int nTotalPasses = 0;
+     int nBigPasses = 0;
+     double djNorm0 = 0.0;
+     double djNorm = 0.0;
+     double normFlagged = 0.0;
+     double normUnflagged = 0.0;
+     int localPivotMode = pivotMode;
+     bool allFinished = false;
+     bool justOne = false;
+     int returnCode = 1;
+     double currentObj;
+     double predictedObj;
+     double thetaObj;
+     objective_->stepLength(this, solution_, solution_, 0.0,
+                            currentObj, predictedObj, thetaObj);
+     double saveObj = currentObj;
+#if MINTYPE ==2
+     // try Shanno's method
+     //would be memory leak
+     //double * saveY=new double[numberTotal];
+     //double * saveS=new double[numberTotal];
+     //double * saveY2=new double[numberTotal];
+     //double * saveS2=new double[numberTotal];
+     double saveY[100];
+     double saveS[100];
+     double saveY2[100];
+     double saveS2[100];
+     double zz[10000];
+#endif
+     double * dArray2 = dArray + numberTotal;
+     // big big loop
+     while (!allFinished) {
+          double * work = longArray->denseVector();
+          int * which = longArray->getIndices();
+          allFinished = true;
+          // CONJUGATE 0 - never, 1 as pivotMode, 2 as localPivotMode, 3 always
+          //#define SMALLTHETA1 1.0e-25
+          //#define SMALLTHETA2 1.0e-25
+#define SMALLTHETA1 1.0e-10
+#define SMALLTHETA2 1.0e-10
+#define CONJUGATE 2
+#if CONJUGATE == 0
+          int conjugate = 0;
+#elif CONJUGATE == 1
+          int conjugate = (pivotMode < 10) ? MINTYPE : 0;
+#elif CONJUGATE == 2
+          int conjugate = MINTYPE;
+#else
+          int conjugate = MINTYPE;
+#endif
+
+          //if (pivotMode==1)
+          //localPivotMode=11;;
+#if CLP_DEBUG > 1
+          longArray->checkClear();
+#endif
+          int numberNonBasic = 0;
+          int startLocalMode = -1;
+          while (!finished) {
+               double simpleObjective = COIN_DBL_MAX;
+               returnCode = 1;
+               int iSequence;
+               objective_->reducedGradient(this, dj_, false);
+               // get direction vector in longArray
+               longArray->clear();
+               // take out comment to try slightly different idea
+               if (nPasses + nTotalPasses > 3000 || nBigPasses > 100) {
+                    if (factorization_->pivots())
+                         returnCode = 3;
+                    break;
+               }
+               if (!nPasses) {
+                    numberNonBasic = 0;
+                    nBigPasses++;
+               }
+               // just do superbasic if in cleanup mode
+               int local = localPivotMode;
+               if (!local && pivotMode >= 10 && nBigPasses < 10) {
+                    local = 100;
+               } else if (local == -1 || nBigPasses >= 10) {
+                    local = 0;
+                    localPivotMode = 0;
+               }
+               if (justOne) {
+                    local = 2;
+                    //local=100;
+                    justOne = false;
+               }
+               if (!nPasses)
+                    startLocalMode = local;
+               directionVector(longArray, spare, rowArray, local,
+                               normFlagged, normUnflagged, numberNonBasic);
+               {
+                    // check null vector
+                    double * rhs = spare->denseVector();
+#if CLP_DEBUG > 1
+                    spare->checkClear();
+#endif
+                    int iRow;
+                    multiplyAdd(solution_ + numberColumns_, numberRows_, -1.0, rhs, 0.0);
+                    matrix_->times(1.0, solution_, rhs, rowScale_, columnScale_);
+                    double largest = 0.0;
+#if CLP_DEBUG > 0
+                    int iLargest = -1;
+#endif
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         double value = fabs(rhs[iRow]);
+                         rhs[iRow] = 0.0;
+                         if (value > largest) {
+                              largest = value;
+#if CLP_DEBUG > 0
+                              iLargest = iRow;
+#endif
+                         }
+                    }
+#if CLP_DEBUG > 0
+                    if ((handler_->logLevel() & 32) && largest > 1.0e-8)
+                         printf("largest rhs error %g on row %d\n", largest, iLargest);
+#endif
+                    if (solutionError < 0.0) {
+                         solutionError = largest;
+                    } else if (largest > CoinMax(1.0e-8, 1.0e2 * solutionError) &&
+                               factorization_->pivots()) {
+                         longArray->clear();
+                         pivotRow_ = -1;
+                         theta_ = 0.0;
+                         return 3;
+                    }
+               }
+               if (sequenceIn_ >= 0)
+                    lastSequenceIn = sequenceIn_;
+#if MINTYPE!=2
+               double djNormSave = djNorm;
+#endif
+               djNorm = 0.0;
+               int iIndex;
+               for (iIndex = 0; iIndex < numberNonBasic; iIndex++) {
+                    int iSequence = which[iIndex];
+                    double alpha = work[iSequence];
+                    djNorm += alpha * alpha;
+               }
+               // go to conjugate gradient if necessary
+               if (numberNonBasic && localPivotMode >= 10 && (nPasses > 4 || sequenceIn_ < 0)) {
+                    localPivotMode = 0;
+                    nTotalPasses += nPasses;
+                    nPasses = 0;
+               }
+#if CONJUGATE == 2
+               conjugate = (localPivotMode < 10) ? MINTYPE : 0;
+#endif
+               //printf("bigP %d pass %d nBasic %d norm %g normI %g normF %g\n",
+               //     nBigPasses,nPasses,numberNonBasic,normUnflagged,normFlagged);
+               if (!nPasses) {
+                    //printf("numberNon %d\n",numberNonBasic);
+#if MINTYPE==2
+                    assert (numberNonBasic < 100);
+                    memset(zz, 0, numberNonBasic * numberNonBasic * sizeof(double));
+                    int put = 0;
+                    for (int iVariable = 0; iVariable < numberNonBasic; iVariable++) {
+                         zz[put] = 1.0;
+                         put += numberNonBasic + 1;
+                    }
+#endif
+                    djNorm0 = CoinMax(djNorm, 1.0e-20);
+                    CoinMemcpyN(work, numberTotal, dArray);
+                    CoinMemcpyN(work, numberTotal, dArray2);
+                    if (sequenceIn_ >= 0 && numberNonBasic == 1) {
+                         // see if simple move
+                         double objTheta2 = objective_->stepLength(this, solution_, work, 1.0e30,
+                                            currentObj, predictedObj, thetaObj);
+                         rowArray->clear();
+
+                         // update the incoming column
+                         unpackPacked(rowArray);
+                         factorization_->updateColumnFT(spare, rowArray);
+                         theta_ = 0.0;
+                         double * work2 = rowArray->denseVector();
+                         int number = rowArray->getNumElements();
+                         int * which2 = rowArray->getIndices();
+                         int iIndex;
+                         bool easyMove = false;
+                         double way;
+                         if (dj_[sequenceIn_] > 0.0)
+                              way = -1.0;
+                         else
+                              way = 1.0;
+                         double largest = COIN_DBL_MAX;
+#ifdef CLP_DEBUG
+                         int kPivot = -1;
+#endif
+                         for (iIndex = 0; iIndex < number; iIndex++) {
+                              int iRow = which2[iIndex];
+                              double alpha = way * work2[iIndex];
+                              int iPivot = pivotVariable_[iRow];
+                              if (alpha < -1.0e-5) {
+                                   double distance = upper_[iPivot] - solution_[iPivot];
+                                   if (distance < -largest * alpha) {
+#ifdef CLP_DEBUG
+                                        kPivot = iPivot;
+#endif
+                                        largest = CoinMax(0.0, -distance / alpha);
+                                   }
+                                   if (distance < -1.0e-12 * alpha) {
+                                        easyMove = true;
+                                        break;
+                                   }
+                              } else if (alpha > 1.0e-5) {
+                                   double distance = solution_[iPivot] - lower_[iPivot];
+                                   if (distance < largest * alpha) {
+#ifdef CLP_DEBUG
+                                        kPivot = iPivot;
+#endif
+                                        largest = CoinMax(0.0, distance / alpha);
+                                   }
+                                   if (distance < 1.0e-12 * alpha) {
+                                        easyMove = true;
+                                        break;
+                                   }
+                              }
+                         }
+                         // But largest has to match up with change
+                         assert (work[sequenceIn_]);
+                         largest /= fabs(work[sequenceIn_]);
+                         if (largest < objTheta2) {
+                              easyMove = true;
+                         } else if (!easyMove) {
+                              double objDrop = currentObj - predictedObj;
+                              double th = objective_->stepLength(this, solution_, work, largest,
+                                                                 currentObj, predictedObj, simpleObjective);
+                              simpleObjective = CoinMax(simpleObjective, predictedObj);
+                              double easyDrop = currentObj - simpleObjective;
+                              if (easyDrop > 1.0e-8 && easyDrop > 0.5 * objDrop) {
+                                   easyMove = true;
+#ifdef CLP_DEBUG
+                                   if (handler_->logLevel() & 32)
+                                        printf("easy - obj drop %g, easy drop %g\n", objDrop, easyDrop);
+#endif
+                                   if (easyDrop > objDrop) {
+                                        // debug
+                                        printf("****** th %g simple %g\n", th, simpleObjective);
+                                        objective_->stepLength(this, solution_, work, 1.0e30,
+                                                               currentObj, predictedObj, simpleObjective);
+                                        objective_->stepLength(this, solution_, work, largest,
+                                                               currentObj, predictedObj, simpleObjective);
+                                   }
+                              }
+                         }
+                         rowArray->clear();
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("largest %g piv %d\n", largest, kPivot);
+#endif
+                         if (easyMove) {
+                              valueIn_ = solution_[sequenceIn_];
+                              dualIn_ = dj_[sequenceIn_];
+                              lowerIn_ = lower_[sequenceIn_];
+                              upperIn_ = upper_[sequenceIn_];
+                              if (dualIn_ > 0.0)
+                                   directionIn_ = -1;
+                              else
+                                   directionIn_ = 1;
+                              longArray->clear();
+                              pivotRow_ = -1;
+                              theta_ = 0.0;
+                              return 0;
+                         }
+                    }
+               } else {
+#if MINTYPE==1
+                    if (conjugate) {
+                         double djNorm2 = djNorm;
+                         if (numberNonBasic && 0) {
+                              int iIndex;
+                              djNorm2 = 0.0;
+                              for (iIndex = 0; iIndex < numberNonBasic; iIndex++) {
+                                   int iSequence = which[iIndex];
+                                   double alpha = work[iSequence];
+                                   //djNorm2 += alpha*alpha;
+                                   double alpha2 = work[iSequence] - dArray2[iSequence];
+                                   djNorm2 += alpha * alpha2;
+                              }
+                              //printf("a %.18g b %.18g\n",djNorm,djNorm2);
+                         }
+                         djNorm = djNorm2;
+                         double beta = djNorm2 / djNormSave;
+                         // reset beta every so often
+                         //if (numberNonBasic&&nPasses>numberNonBasic&&(nPasses%(3*numberNonBasic))==1)
+                         //beta=0.0;
+                         //printf("current norm %g, old %g - beta %g\n",
+                         //     djNorm,djNormSave,beta);
+                         for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+                              dArray[iSequence] = work[iSequence] + beta * dArray[iSequence];
+                              dArray2[iSequence] = work[iSequence];
+                         }
+                    } else {
+                         for (iSequence = 0; iSequence < numberTotal; iSequence++)
+                              dArray[iSequence] = work[iSequence];
+                    }
+#else
+                    int number2 = numberNonBasic;
+                    if (number2) {
+                         // pack down into dArray
+                         int jLast = -1;
+                         for (iSequence = 0; iSequence < numberNonBasic; iSequence++) {
+                              int j = which[iSequence];
+                              assert(j > jLast);
+                              jLast = j;
+                              double value = work[j];
+                              dArray[iSequence] = -value;
+                         }
+                         // see whether to restart
+                         // check signs - gradient
+                         double g1 = innerProduct(dArray, number2, dArray);
+                         double g2 = innerProduct(dArray, number2, saveY2);
+                         // Get differences
+                         for (iSequence = 0; iSequence < numberNonBasic; iSequence++) {
+                              saveY2[iSequence] = dArray[iSequence] - saveY2[iSequence];
+                              saveS2[iSequence] = solution_[iSequence] - saveS2[iSequence];
+                         }
+                         double g3 = innerProduct(saveS2, number2, saveY2);
+                         printf("inner %g\n", g3);
+                         //assert(g3>0);
+                         double zzz[10000];
+                         int iVariable;
+                         g2 = 1.0e50; // temp
+                         if (fabs(g2) >= 0.2 * fabs(g1)) {
+                              // restart
+                              double delta = innerProduct(saveY2, number2, saveS2) /
+                                             innerProduct(saveY2, number2, saveY2);
+                              delta = 1.0; //temp
+                              memset(zz, 0, number2 * sizeof(double));
+                              int put = 0;
+                              for (iVariable = 0; iVariable < number2; iVariable++) {
+                                   zz[put] = delta;
+                                   put += number2 + 1;
+                              }
+                         } else {
+                         }
+                         CoinMemcpyN(zz, number2 * number2, zzz);
+                         double ww[100];
+                         // get sk -Hkyk
+                         for (iVariable = 0; iVariable < number2; iVariable++) {
+                              double value = 0.0;
+                              for (int jVariable = 0; jVariable < number2; jVariable++) {
+                                   value += saveY2[jVariable] * zzz[iVariable+number2*jVariable];
+                              }
+                              ww[iVariable] = saveS2[iVariable] - value;
+                         }
+                         double ys = innerProduct(saveY2, number2, saveS2);
+                         double multiplier1 = 1.0 / ys;
+                         double multiplier2 = innerProduct(saveY2, number2, ww) / (ys * ys);
+#if 1
+                         // and second way
+                         // Hy
+                         double h[100];
+                         for (iVariable = 0; iVariable < number2; iVariable++) {
+                              double value = 0.0;
+                              for (int jVariable = 0; jVariable < number2; jVariable++) {
+                                   value += saveY2[jVariable] * zzz[iVariable+number2*jVariable];
+                              }
+                              h[iVariable] = value;
+                         }
+                         double hh[10000];
+                         double yhy1 = innerProduct(h, number2, saveY2) * multiplier1 + 1.0;
+                         yhy1 *= multiplier1;
+                         for (iVariable = 0; iVariable < number2; iVariable++) {
+                              for (int jVariable = 0; jVariable < number2; jVariable++) {
+                                   int put = iVariable + number2 * jVariable;
+                                   double value = zzz[put];
+                                   value += yhy1 * saveS2[iVariable] * saveS2[jVariable];
+                                   hh[put] = value;
+                              }
+                         }
+                         for (iVariable = 0; iVariable < number2; iVariable++) {
+                              for (int jVariable = 0; jVariable < number2; jVariable++) {
+                                   int put = iVariable + number2 * jVariable;
+                                   double value = hh[put];
+                                   value -= multiplier1 * (saveS2[iVariable] * h[jVariable]);
+                                   value -= multiplier1 * (saveS2[jVariable] * h[iVariable]);
+                                   hh[put] = value;
+                              }
+                         }
+#endif
+                         // now update H
+                         for (iVariable = 0; iVariable < number2; iVariable++) {
+                              for (int jVariable = 0; jVariable < number2; jVariable++) {
+                                   int put = iVariable + number2 * jVariable;
+                                   double value = zzz[put];
+                                   value += multiplier1 * (ww[iVariable] * saveS2[jVariable]
+                                                           + ww[jVariable] * saveS2[iVariable]);
+                                   value -= multiplier2 * saveS2[iVariable] * saveS2[jVariable];
+                                   zzz[put] = value;
+                              }
+                         }
+                         //memcpy(zzz,hh,size*sizeof(double));
+                         // do search direction
+                         memset(dArray, 0, numberTotal * sizeof(double));
+                         for (iVariable = 0; iVariable < numberNonBasic; iVariable++) {
+                              double value = 0.0;
+                              for (int jVariable = 0; jVariable < number2; jVariable++) {
+                                   int k = which[jVariable];
+                                   value += work[k] * zzz[iVariable+number2*jVariable];
+                              }
+                              int i = which[iVariable];
+                              dArray[i] = value;
+                         }
+                         // Now fill out dArray
+                         {
+                              int j;
+                              // Now do basic ones
+                              int iRow;
+                              CoinIndexedVector * spare1 = spare;
+                              CoinIndexedVector * spare2 = rowArray;
+#if CLP_DEBUG > 1
+                              spare1->checkClear();
+                              spare2->checkClear();
+#endif
+                              double * array2 = spare1->denseVector();
+                              int * index2 = spare1->getIndices();
+                              int number2 = 0;
+                              times(-1.0, dArray, array2);
+                              dArray = dArray + numberColumns_;
+                              for (iRow = 0; iRow < numberRows_; iRow++) {
+                                   double value = array2[iRow] + dArray[iRow];
+                                   if (value) {
+                                        array2[iRow] = value;
+                                        index2[number2++] = iRow;
+                                   } else {
+                                        array2[iRow] = 0.0;
+                                   }
+                              }
+                              dArray -= numberColumns_;
+                              spare1->setNumElements(number2);
+                              // Ftran
+                              factorization_->updateColumn(spare2, spare1);
+                              number2 = spare1->getNumElements();
+                              for (j = 0; j < number2; j++) {
+                                   int iSequence = index2[j];
+                                   double value = array2[iSequence];
+                                   array2[iSequence] = 0.0;
+                                   if (value) {
+                                        int iPivot = pivotVariable_[iSequence];
+                                        double oldValue = dArray[iPivot];
+                                        dArray[iPivot] = value + oldValue;
+                                   }
+                              }
+                              spare1->setNumElements(0);
+                         }
+                         //assert (innerProductIndexed(dArray,number2,work,which)>0);
+                         //printf ("innerP1 %g\n",innerProduct(dArray,numberTotal,work));
+                         printf ("innerP1 %g innerP2 %g\n", innerProduct(dArray, numberTotal, work),
+                                 innerProductIndexed(dArray, numberNonBasic, work, which));
+                         assert (innerProduct(dArray, numberTotal, work) > 0);
+#if 1
+                         {
+                              // check null vector
+                              int iRow;
+                              double qq[10];
+                              memset(qq, 0, numberRows_ * sizeof(double));
+                              multiplyAdd(dArray + numberColumns_, numberRows_, -1.0, qq, 0.0);
+                              matrix_->times(1.0, dArray, qq, rowScale_, columnScale_);
+                              double largest = 0.0;
+                              int iLargest = -1;
+                              for (iRow = 0; iRow < numberRows_; iRow++) {
+                                   double value = fabs(qq[iRow]);
+                                   if (value > largest) {
+                                        largest = value;
+                                        iLargest = iRow;
+                                   }
+                              }
+                              printf("largest null error %g on row %d\n", largest, iLargest);
+                              for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+                                   if (getStatus(iSequence) == basic)
+                                        assert (fabs(dj_[iSequence]) < 1.0e-3);
+                              }
+                         }
+#endif
+                         CoinMemcpyN(saveY2, numberNonBasic, saveY);
+                         CoinMemcpyN(saveS2, numberNonBasic, saveS);
+                    }
+#endif
+               }
+#if MINTYPE==2
+               for (iSequence = 0; iSequence < numberNonBasic; iSequence++) {
+                    int j = which[iSequence];
+                    saveY2[iSequence] = -work[j];
+                    saveS2[iSequence] = solution_[j];
+               }
+#endif
+               if (djNorm < eps * djNorm0 || (nPasses > 100 && djNorm < CoinMin(1.0e-1 * djNorm0, 1.0e-12))) {
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("dj norm reduced from %g to %g\n", djNorm0, djNorm);
+#endif
+                    if (pivotMode < 10 || !numberNonBasic) {
+                         finished = true;
+                    } else {
+                         localPivotMode = pivotMode;
+                         nTotalPasses += nPasses;
+                         nPasses = 0;
+                         continue;
+                    }
+               }
+               //if (nPasses==100||nPasses==50)
+               //printf("pass %d dj norm reduced from %g to %g - flagged norm %g\n",nPasses,djNorm0,djNorm,
+               //	 normFlagged);
+               if (nPasses > 100 && djNorm < 1.0e-2 * normFlagged && !startLocalMode) {
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("dj norm reduced from %g to %g - flagged norm %g - unflagging\n", djNorm0, djNorm,
+                                normFlagged);
+#endif
+                    unflag();
+                    localPivotMode = 0;
+                    nTotalPasses += nPasses;
+                    nPasses = 0;
+                    continue;
+               }
+               if (djNorm > 0.99 * djNorm0 && nPasses > 1500) {
+                    finished = true;
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("dj norm NOT reduced from %g to %g\n", djNorm0, djNorm);
+#endif
+                    djNorm = 1.2345e-20;
+               }
+               number = longArray->getNumElements();
+               if (!numberNonBasic) {
+                    // looks optimal
+                    // check if any dj look plausible
+                    int nSuper = 0;
+                    int nFlagged = 0;
+                    int nNormal = 0;
+                    for (int iSequence = 0; iSequence < numberColumns_ + numberRows_; iSequence++) {
+                         if (flagged(iSequence)) {
+                              switch(getStatus(iSequence)) {
+
+                              case basic:
+                              case ClpSimplex::isFixed:
+                                   break;
+                              case atUpperBound:
+                                   if (dj_[iSequence] > dualTolerance_)
+                                        nFlagged++;
+                                   break;
+                              case atLowerBound:
+                                   if (dj_[iSequence] < -dualTolerance_)
+                                        nFlagged++;
+                                   break;
+                              case isFree:
+                              case superBasic:
+                                   if (fabs(dj_[iSequence]) > dualTolerance_)
+                                        nFlagged++;
+                                   break;
+                              }
+                              continue;
+                         }
+                         switch(getStatus(iSequence)) {
+
+                         case basic:
+                         case ClpSimplex::isFixed:
+                              break;
+                         case atUpperBound:
+                              if (dj_[iSequence] > dualTolerance_)
+                                   nNormal++;
+                              break;
+                         case atLowerBound:
+                              if (dj_[iSequence] < -dualTolerance_)
+                                   nNormal++;
+                              break;
+                         case isFree:
+                         case superBasic:
+                              if (fabs(dj_[iSequence]) > dualTolerance_)
+                                   nSuper++;
+                              break;
+                         }
+                    }
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("%d super, %d normal, %d flagged\n",
+                                nSuper, nNormal, nFlagged);
+#endif
+
+                    int nFlagged2 = 1;
+                    if (lastSequenceIn < 0 && !nNormal && !nSuper) {
+                         nFlagged2 = unflag();
+                         if (pivotMode >= 10) {
+                              pivotMode--;
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32)
+                                   printf("pivot mode now %d\n", pivotMode);
+#endif
+                              if (pivotMode == 9)
+                                   pivotMode = 0;	// switch off fast attempt
+                         }
+                    } else {
+                         lastSequenceIn = -1;
+                    }
+                    if (!nFlagged2 || (normFlagged + normUnflagged < 1.0e-8)) {
+                         primalColumnPivot_->setLooksOptimal(true);
+                         return 0;
+                    } else {
+                         localPivotMode = -1;
+                         nTotalPasses += nPasses;
+                         nPasses = 0;
+                         finished = false;
+                         continue;
+                    }
+               }
+               bestSequence = -1;
+               bestBasicSequence = -1;
+
+               // temp
+               nPasses++;
+               if (nPasses > 2000)
+                    finished = true;
+               double theta = 1.0e30;
+               basicTheta = 1.0e30;
+               theta_ = 1.0e30;
+               double basicTolerance = 1.0e-4 * primalTolerance_;
+               for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+                    //if (flagged(iSequence)
+                    //  continue;
+                    double alpha = dArray[iSequence];
+                    Status thisStatus = getStatus(iSequence);
+                    double oldValue = solution_[iSequence];
+                    if (thisStatus != basic) {
+                         if (fabs(alpha) >= acceptablePivot) {
+                              if (alpha < 0.0) {
+                                   // variable going towards lower bound
+                                   double bound = lower_[iSequence];
+                                   oldValue -= bound;
+                                   if (oldValue + theta * alpha < 0.0) {
+                                        bestSequence = iSequence;
+                                        theta = CoinMax(0.0, oldValue / (-alpha));
+                                   }
+                              } else {
+                                   // variable going towards upper bound
+                                   double bound = upper_[iSequence];
+                                   oldValue = bound - oldValue;
+                                   if (oldValue - theta * alpha < 0.0) {
+                                        bestSequence = iSequence;
+                                        theta = CoinMax(0.0, oldValue / alpha);
+                                   }
+                              }
+                         }
+                    } else {
+                         if (fabs(alpha) >= acceptableBasic) {
+                              if (alpha < 0.0) {
+                                   // variable going towards lower bound
+                                   double bound = lower_[iSequence];
+                                   oldValue -= bound;
+                                   if (oldValue + basicTheta * alpha < -basicTolerance) {
+                                        bestBasicSequence = iSequence;
+                                        basicTheta = CoinMax(0.0, (oldValue + basicTolerance) / (-alpha));
+                                   }
+                              } else {
+                                   // variable going towards upper bound
+                                   double bound = upper_[iSequence];
+                                   oldValue = bound - oldValue;
+                                   if (oldValue - basicTheta * alpha < -basicTolerance) {
+                                        bestBasicSequence = iSequence;
+                                        basicTheta = CoinMax(0.0, (oldValue + basicTolerance) / alpha);
+                                   }
+                              }
+                         }
+                    }
+               }
+               theta_ = CoinMin(theta, basicTheta);
+               // Now find minimum of function
+               double objTheta2 = objective_->stepLength(this, solution_, dArray, CoinMin(theta, basicTheta),
+                                  currentObj, predictedObj, thetaObj);
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32)
+                    printf("current obj %g thetaObj %g, predictedObj %g\n", currentObj, thetaObj, predictedObj);
+#endif
+	       objTheta2=CoinMin(objTheta2,1.0e29);
+#if MINTYPE==1
+               if (conjugate) {
+                    double offset;
+                    const double * gradient = objective_->gradient(this,
+                                              dArray, offset,
+                                              true, 0);
+                    double product = 0.0;
+                    for (iSequence = 0; iSequence < numberColumns_; iSequence++) {
+                         double alpha = dArray[iSequence];
+                         double value = alpha * gradient[iSequence];
+                         product += value;
+                    }
+                    //#define INCLUDESLACK
+#ifdef INCLUDESLACK
+                    for (; iSequence < numberColumns_ + numberRows_; iSequence++) {
+                         double alpha = dArray[iSequence];
+                         double value = alpha * cost_[iSequence];
+                         product += value;
+                    }
+#endif
+                    if (product > 0.0)
+                         objTheta = djNorm / product;
+                    else
+                         objTheta = COIN_DBL_MAX;
+#ifndef NDEBUG
+                    if (product < -1.0e-8 && handler_->logLevel() > 1)
+                         printf("bad product %g\n", product);
+#endif
+                    product = CoinMax(product, 0.0);
+               } else {
+                    objTheta = objTheta2;
+               }
+#else
+               objTheta = objTheta2;
+#endif
+               // if very small difference then take pivot (depends on djNorm?)
+               // distinguish between basic and non-basic
+               bool chooseObjTheta = objTheta < theta_;
+               if (chooseObjTheta) {
+                    if (thetaObj < currentObj - 1.0e-12 && objTheta + 1.0e-10 > theta_)
+                         chooseObjTheta = false;
+                    //if (thetaObj<currentObj+1.0e-12&&objTheta+1.0e-5>theta_)
+                    //chooseObjTheta=false;
+               }
+               //if (objTheta+SMALLTHETA1<theta_||(thetaObj>currentObj+difference&&objTheta<theta_)) {
+               if (chooseObjTheta) {
+                    theta_ = objTheta;
+               } else {
+                    objTheta = CoinMax(objTheta, 1.00000001 * theta_ + 1.0e-12);
+                    //if (theta+1.0e-13>basicTheta) {
+                    //theta = CoinMax(theta,1.00000001*basicTheta);
+                    //theta_ = basicTheta;
+                    //}
+               }
+               // always out if one variable in and zero move
+               if (theta_ == basicTheta || (sequenceIn_ >= 0 && theta_ < 1.0e-10))
+                    finished = true; // come out
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32) {
+                    printf("%d pass,", nPasses);
+                    if (sequenceIn_ >= 0)
+                         printf (" Sin %d,", sequenceIn_);
+                    if (basicTheta == theta_)
+                         printf(" X(%d) basicTheta %g", bestBasicSequence, basicTheta);
+                    else
+                         printf(" basicTheta %g", basicTheta);
+                    if (theta == theta_)
+                         printf(" X(%d) non-basicTheta %g", bestSequence, theta);
+                    else
+                         printf(" non-basicTheta %g", theta);
+                    printf(" %s objTheta %g", objTheta == theta_ ? "X" : "", objTheta);
+                    printf(" djNorm %g\n", djNorm);
+               }
+#endif
+               if (handler_->logLevel() > 3 && objTheta != theta_) {
+                    printf("%d pass obj %g,", nPasses, currentObj);
+                    if (sequenceIn_ >= 0)
+                         printf (" Sin %d,", sequenceIn_);
+                    if (basicTheta == theta_)
+                         printf(" X(%d) basicTheta %g", bestBasicSequence, basicTheta);
+                    else
+                         printf(" basicTheta %g", basicTheta);
+                    if (theta == theta_)
+                         printf(" X(%d) non-basicTheta %g", bestSequence, theta);
+                    else
+                         printf(" non-basicTheta %g", theta);
+                    printf(" %s objTheta %g", objTheta == theta_ ? "X" : "", objTheta);
+                    printf(" djNorm %g\n", djNorm);
+               }
+               if (objTheta != theta_) {
+                    //printf("hit boundary after %d passes\n",nPasses);
+                    nTotalPasses += nPasses;
+                    nPasses = 0; // start again
+               }
+               if (localPivotMode < 10 || lastSequenceIn == bestSequence) {
+                    if (theta_ == theta && theta_ < basicTheta && theta_ < 1.0e-5)
+                         setFlagged(bestSequence); // out of active set
+               }
+               // Update solution
+               for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+                    //for (iIndex=0;iIndex<number;iIndex++) {
+
+                    //int iSequence = which[iIndex];
+                    double alpha = dArray[iSequence];
+                    if (alpha) {
+                         double value = solution_[iSequence] + theta_ * alpha;
+                         solution_[iSequence] = value;
+                         switch(getStatus(iSequence)) {
+
+                         case basic:
+                         case isFixed:
+                         case isFree:
+                         case atUpperBound:
+                         case atLowerBound:
+                              nonLinearCost_->setOne(iSequence, value);
+                              break;
+                         case superBasic:
+                              // To get correct action
+                              setStatus(iSequence, isFixed);
+                              nonLinearCost_->setOne(iSequence, value);
+                              //assert (getStatus(iSequence)!=isFixed);
+                              break;
+                         }
+                    }
+               }
+               if (objTheta < SMALLTHETA2 && objTheta == theta_) {
+                    if (sequenceIn_ >= 0 && basicTheta < 1.0e-9) {
+                         // try just one
+                         localPivotMode = 0;
+                         sequenceIn_ = -1;
+                         nTotalPasses += nPasses;
+                         nPasses = 0;
+                         //finished=true;
+                         //objTheta=0.0;
+                         //theta_=0.0;
+                    } else if (sequenceIn_ < 0 && nTotalPasses > 10) {
+                         if (objTheta < 1.0e-10) {
+                              finished = true;
+                              //printf("zero move\n");
+                              break;
+                         }
+                    }
+               }
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32) {
+                    objective_->stepLength(this, solution_, work, 0.0,
+                                           currentObj, predictedObj, thetaObj);
+                    printf("current obj %g after update - simple was %g\n", currentObj, simpleObjective);
+               }
+#endif
+               if (sequenceIn_ >= 0 && !finished && objTheta > 1.0e-4) {
+                    // we made some progress - back to normal
+                    if (localPivotMode < 10) {
+                         localPivotMode = 0;
+                         sequenceIn_ = -1;
+                         nTotalPasses += nPasses;
+                         nPasses = 0;
+                    }
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("some progress?\n");
+#endif
+               }
+#if CLP_DEBUG > 1
+               longArray->checkClean();
+#endif
+          }
+#ifdef CLP_DEBUG
+          if (handler_->logLevel() & 32)
+               printf("out of loop after %d (%d) passes\n", nPasses, nTotalPasses);
+#endif
+          if (nTotalPasses >= 1000 || (nTotalPasses > 10 && sequenceIn_ < 0 && theta_ < 1.0e-10))
+               returnCode = 2;
+          bool ordinaryDj = false;
+          //if(sequenceIn_>=0&&numberNonBasic==1&&theta_<1.0e-7&&theta_==basicTheta)
+          //printf("could try ordinary iteration %g\n",theta_);
+          if(sequenceIn_ >= 0 && numberNonBasic == 1 && theta_ < 1.0e-15) {
+               //printf("trying ordinary iteration\n");
+               ordinaryDj = true;
+          }
+          if (!basicTheta && !ordinaryDj) {
+               //returnCode=2;
+               //objTheta=-1.0; // so we fall through
+          }
+          assert (theta_ < 1.0e30); // for now
+          // See if we need to pivot
+          if (theta_ == basicTheta || ordinaryDj) {
+               if (!ordinaryDj) {
+                    // find an incoming column which will force pivot
+                    int iRow;
+                    pivotRow_ = -1;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         if (pivotVariable_[iRow] == bestBasicSequence) {
+                              pivotRow_ = iRow;
+                              break;
+                         }
+                    }
+                    assert (pivotRow_ >= 0);
+                    // Get good size for pivot
+                    double acceptablePivot = 1.0e-7;
+                    if (factorization_->pivots() > 10)
+                         acceptablePivot = 1.0e-5; // if we have iterated be more strict
+                    else if (factorization_->pivots() > 5)
+                         acceptablePivot = 1.0e-6; // if we have iterated be slightly more strict
+                    // should be dArray but seems better this way!
+                    double direction = work[bestBasicSequence] > 0.0 ? -1.0 : 1.0;
+                    // create as packed
+                    rowArray->createPacked(1, &pivotRow_, &direction);
+                    factorization_->updateColumnTranspose(spare, rowArray);
+                    // put row of tableau in rowArray and columnArray
+                    matrix_->transposeTimes(this, -1.0,
+                                            rowArray, spare, columnArray);
+                    // choose one futhest away from bound which has reasonable pivot
+                    // If increasing we want negative alpha
+
+                    double * work2;
+                    int iSection;
+
+                    sequenceIn_ = -1;
+                    double bestValue = -1.0;
+                    double bestDirection = 0.0;
+                    // First pass we take correct direction and large pivots
+                    // then correct direction
+                    // then any
+                    double check[] = {1.0e-8, -1.0e-12, -1.0e30};
+                    double mult[] = {100.0, 1.0, 1.0};
+                    for (int iPass = 0; iPass < 3; iPass++) {
+                         //if (!bestValue&&iPass==2)
+                         //bestValue=-1.0;
+                         double acceptable = acceptablePivot * mult[iPass];
+                         double checkValue = check[iPass];
+                         for (iSection = 0; iSection < 2; iSection++) {
+
+                              int addSequence;
+
+                              if (!iSection) {
+                                   work2 = rowArray->denseVector();
+                                   number = rowArray->getNumElements();
+                                   which = rowArray->getIndices();
+                                   addSequence = numberColumns_;
+                              } else {
+                                   work2 = columnArray->denseVector();
+                                   number = columnArray->getNumElements();
+                                   which = columnArray->getIndices();
+                                   addSequence = 0;
+                              }
+                              int i;
+
+                              for (i = 0; i < number; i++) {
+                                   int iSequence = which[i] + addSequence;
+                                   if (flagged(iSequence))
+                                        continue;
+                                   //double distance = CoinMin(solution_[iSequence]-lower_[iSequence],
+                                   //		  upper_[iSequence]-solution_[iSequence]);
+                                   double alpha = work2[i];
+                                   // should be dArray but seems better this way!
+                                   double change = work[iSequence];
+                                   Status thisStatus = getStatus(iSequence);
+                                   double direction = 0;;
+                                   switch(thisStatus) {
+
+                                   case basic:
+                                   case ClpSimplex::isFixed:
+                                        break;
+                                   case isFree:
+                                   case superBasic:
+                                        if (alpha < -acceptable && change > checkValue)
+                                             direction = 1.0;
+                                        else if (alpha > acceptable && change < -checkValue)
+                                             direction = -1.0;
+                                        break;
+                                   case atUpperBound:
+                                        if (alpha > acceptable && change < -checkValue)
+                                             direction = -1.0;
+                                        else if (iPass == 2 && alpha < -acceptable && change < -checkValue)
+                                             direction = 1.0;
+                                        break;
+                                   case atLowerBound:
+                                        if (alpha < -acceptable && change > checkValue)
+                                             direction = 1.0;
+                                        else if (iPass == 2 && alpha > acceptable && change > checkValue)
+                                             direction = -1.0;
+                                        break;
+                                   }
+                                   if (direction) {
+                                        if (sequenceIn_ != lastSequenceIn || localPivotMode < 10) {
+                                             if (CoinMin(solution_[iSequence] - lower_[iSequence],
+                                                         upper_[iSequence] - solution_[iSequence]) > bestValue) {
+                                                  bestValue = CoinMin(solution_[iSequence] - lower_[iSequence],
+                                                                      upper_[iSequence] - solution_[iSequence]);
+                                                  sequenceIn_ = iSequence;
+                                                  bestDirection = direction;
+                                             }
+                                        } else {
+                                             // choose
+                                             bestValue = COIN_DBL_MAX;
+                                             sequenceIn_ = iSequence;
+                                             bestDirection = direction;
+                                        }
+                                   }
+                              }
+                         }
+                         if (sequenceIn_ >= 0 && bestValue > 0.0)
+                              break;
+                    }
+                    if (sequenceIn_ >= 0) {
+                         valueIn_ = solution_[sequenceIn_];
+                         dualIn_ = dj_[sequenceIn_];
+                         if (bestDirection < 0.0) {
+                              // we want positive dj
+                              if (dualIn_ <= 0.0) {
+                                   //printf("bad dj - xx %g\n",dualIn_);
+                                   dualIn_ = 1.0;
+                              }
+                         } else {
+                              // we want negative dj
+                              if (dualIn_ >= 0.0) {
+                                   //printf("bad dj - xx %g\n",dualIn_);
+                                   dualIn_ = -1.0;
+                              }
+                         }
+                         lowerIn_ = lower_[sequenceIn_];
+                         upperIn_ = upper_[sequenceIn_];
+                         if (dualIn_ > 0.0)
+                              directionIn_ = -1;
+                         else
+                              directionIn_ = 1;
+                    } else {
+                         //ordinaryDj=true;
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32) {
+                              printf("no easy pivot - norm %g mode %d\n", djNorm, localPivotMode);
+                              if (rowArray->getNumElements() + columnArray->getNumElements() < 12) {
+                                   for (iSection = 0; iSection < 2; iSection++) {
+
+                                        int addSequence;
+
+                                        if (!iSection) {
+                                             work2 = rowArray->denseVector();
+                                             number = rowArray->getNumElements();
+                                             which = rowArray->getIndices();
+                                             addSequence = numberColumns_;
+                                        } else {
+                                             work2 = columnArray->denseVector();
+                                             number = columnArray->getNumElements();
+                                             which = columnArray->getIndices();
+                                             addSequence = 0;
+                                        }
+                                        int i;
+                                        char section[] = {'R', 'C'};
+                                        for (i = 0; i < number; i++) {
+                                             int iSequence = which[i] + addSequence;
+                                             if (flagged(iSequence)) {
+                                                  printf("%c%d flagged\n", section[iSection], which[i]);
+                                                  continue;
+                                             } else {
+                                                  printf("%c%d status %d sol %g %g %g alpha %g change %g\n",
+                                                         section[iSection], which[i], status_[iSequence],
+                                                         lower_[iSequence], solution_[iSequence], upper_[iSequence],
+                                                         work2[i], work[iSequence]);
+                                             }
+                                        }
+                                   }
+                              }
+                         }
+#endif
+                         assert (sequenceIn_ < 0);
+                         justOne = true;
+                         allFinished = false; // Round again
+                         finished = false;
+                         nTotalPasses += nPasses;
+                         nPasses = 0;
+                         if (djNorm < 0.9 * djNorm0 && djNorm < 1.0e-3 && !localPivotMode) {
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32)
+                                   printf("no pivot - mode %d norms %g %g - unflagging\n",
+                                          localPivotMode, djNorm0, djNorm);
+#endif
+                              unflag(); //unflagging
+                              returnCode = 1;
+                         } else {
+                              returnCode = 2; // do single incoming
+                              returnCode = 1;
+                         }
+                    }
+               }
+               rowArray->clear();
+               columnArray->clear();
+               longArray->clear();
+               if (ordinaryDj) {
+                    valueIn_ = solution_[sequenceIn_];
+                    dualIn_ = dj_[sequenceIn_];
+                    lowerIn_ = lower_[sequenceIn_];
+                    upperIn_ = upper_[sequenceIn_];
+                    if (dualIn_ > 0.0)
+                         directionIn_ = -1;
+                    else
+                         directionIn_ = 1;
+               }
+               if (returnCode == 1)
+                    returnCode = 0;
+          } else {
+               // round again
+               longArray->clear();
+               if (djNorm < 1.0e-3 && !localPivotMode) {
+                    if (djNorm == 1.2345e-20 && djNorm0 > 1.0e-4) {
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("slow convergence djNorm0 %g, %d passes, mode %d, result %d\n", djNorm0, nPasses,
+                                     localPivotMode, returnCode);
+#endif
+                         //if (!localPivotMode)
+                         //returnCode=2; // force singleton
+                    } else {
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("unflagging as djNorm %g %g, %d passes\n", djNorm, djNorm0, nPasses);
+#endif
+                         if (pivotMode >= 10) {
+                              pivotMode--;
+#ifdef CLP_DEBUG
+                              if (handler_->logLevel() & 32)
+                                   printf("pivot mode now %d\n", pivotMode);
+#endif
+                              if (pivotMode == 9)
+                                   pivotMode = 0;	// switch off fast attempt
+                         }
+                         bool unflagged = unflag() != 0;
+                         if (!unflagged && djNorm < 1.0e-10) {
+                              // ? declare victory
+                              sequenceIn_ = -1;
+                              returnCode = 0;
+                         }
+                    }
+               }
+          }
+     }
+     if (djNorm0 < 1.0e-12 * normFlagged) {
+#ifdef CLP_DEBUG
+          if (handler_->logLevel() & 32)
+               printf("unflagging as djNorm %g %g and flagged norm %g\n", djNorm, djNorm0, normFlagged);
+#endif
+          unflag();
+     }
+     if (saveObj - currentObj < 1.0e-5 && nTotalPasses > 2000) {
+          normUnflagged = 0.0;
+          double dualTolerance3 = CoinMin(1.0e-2, 1.0e3 * dualTolerance_);
+          for (int iSequence = 0; iSequence < numberColumns_ + numberRows_; iSequence++) {
+               switch(getStatus(iSequence)) {
+
+               case basic:
+               case ClpSimplex::isFixed:
+                    break;
+               case atUpperBound:
+                    if (dj_[iSequence] > dualTolerance3)
+                         normFlagged += dj_[iSequence] * dj_[iSequence];
+                    break;
+               case atLowerBound:
+                    if (dj_[iSequence] < -dualTolerance3)
+                         normFlagged += dj_[iSequence] * dj_[iSequence];
+                    break;
+               case isFree:
+               case superBasic:
+                    if (fabs(dj_[iSequence]) > dualTolerance3)
+                         normFlagged += dj_[iSequence] * dj_[iSequence];
+                    break;
+               }
+          }
+          if (handler_->logLevel() > 2)
+               printf("possible optimal  %d %d %g %g\n",
+                      nBigPasses, nTotalPasses, saveObj - currentObj, normFlagged);
+          if (normFlagged < 1.0e-5) {
+               unflag();
+               primalColumnPivot_->setLooksOptimal(true);
+               returnCode = 0;
+          }
+     }
+     return returnCode;
+}
+/* Do last half of an iteration.
+   Return codes
+   Reasons to come out normal mode
+   -1 normal
+   -2 factorize now - good iteration
+   -3 slight inaccuracy - refactorize - iteration done
+   -4 inaccuracy - refactorize - no iteration
+   -5 something flagged - go round again
+   +2 looks unbounded
+   +3 max iterations (iteration done)
+
+*/
+int
+ClpSimplexNonlinear::pivotNonlinearResult()
+{
+
+     int returnCode = -1;
+
+     rowArray_[1]->clear();
+
+     // we found a pivot column
+     // update the incoming column
+     unpackPacked(rowArray_[1]);
+     factorization_->updateColumnFT(rowArray_[2], rowArray_[1]);
+     theta_ = 0.0;
+     double * work = rowArray_[1]->denseVector();
+     int number = rowArray_[1]->getNumElements();
+     int * which = rowArray_[1]->getIndices();
+     bool keepValue = false;
+     double saveValue = 0.0;
+     if (pivotRow_ >= 0) {
+          sequenceOut_ = pivotVariable_[pivotRow_];;
+          valueOut_ = solution(sequenceOut_);
+          keepValue = true;
+          saveValue = valueOut_;
+          lowerOut_ = lower_[sequenceOut_];
+          upperOut_ = upper_[sequenceOut_];
+          int iIndex;
+          for (iIndex = 0; iIndex < number; iIndex++) {
+
+               int iRow = which[iIndex];
+               if (iRow == pivotRow_) {
+                    alpha_ = work[iIndex];
+                    break;
+               }
+          }
+     } else {
+          int iIndex;
+          double smallest = COIN_DBL_MAX;
+          for (iIndex = 0; iIndex < number; iIndex++) {
+               int iRow = which[iIndex];
+               double alpha = work[iIndex];
+               if (fabs(alpha) > 1.0e-6) {
+                    int iPivot = pivotVariable_[iRow];
+                    double distance = CoinMin(upper_[iPivot] - solution_[iPivot],
+                                              solution_[iPivot] - lower_[iPivot]);
+                    if (distance < smallest) {
+                         pivotRow_ = iRow;
+                         alpha_ = alpha;
+                         smallest = distance;
+                    }
+               }
+          }
+          if (smallest > primalTolerance_) {
+               smallest = COIN_DBL_MAX;
+               for (iIndex = 0; iIndex < number; iIndex++) {
+                    int iRow = which[iIndex];
+                    double alpha = work[iIndex];
+                    if (fabs(alpha) > 1.0e-6) {
+                         double distance = randomNumberGenerator_.randomDouble();
+                         if (distance < smallest) {
+                              pivotRow_ = iRow;
+                              alpha_ = alpha;
+                              smallest = distance;
+                         }
+                    }
+               }
+          }
+          assert (pivotRow_ >= 0);
+          sequenceOut_ = pivotVariable_[pivotRow_];;
+          valueOut_ = solution(sequenceOut_);
+          lowerOut_ = lower_[sequenceOut_];
+          upperOut_ = upper_[sequenceOut_];
+     }
+     double newValue = valueOut_ - theta_ * alpha_;
+     bool isSuperBasic = false;
+     if (valueOut_ >= upperOut_ - primalTolerance_) {
+          directionOut_ = -1;    // to upper bound
+          upperOut_ = nonLinearCost_->nearest(sequenceOut_, newValue);
+          upperOut_ = newValue;
+     } else if (valueOut_ <= lowerOut_ + primalTolerance_) {
+          directionOut_ = 1;    // to lower bound
+          lowerOut_ = nonLinearCost_->nearest(sequenceOut_, newValue);
+     } else {
+          lowerOut_ = valueOut_;
+          upperOut_ = valueOut_;
+          isSuperBasic = true;
+          //printf("XX superbasic out\n");
+     }
+     dualOut_ = dj_[sequenceOut_];
+     // if stable replace in basis
+
+     int updateStatus = factorization_->replaceColumn(this,
+                        rowArray_[2],
+                        rowArray_[1],
+                        pivotRow_,
+                        alpha_);
+
+     // if no pivots, bad update but reasonable alpha - take and invert
+     if (updateStatus == 2 &&
+               lastGoodIteration_ == numberIterations_ && fabs(alpha_) > 1.0e-5)
+          updateStatus = 4;
+     if (updateStatus == 1 || updateStatus == 4) {
+          // slight error
+          if (factorization_->pivots() > 5 || updateStatus == 4) {
+               returnCode = -3;
+          }
+     } else if (updateStatus == 2) {
+          // major error
+          // better to have small tolerance even if slower
+          factorization_->zeroTolerance(CoinMin(factorization_->zeroTolerance(), 1.0e-15));
+          int maxFactor = factorization_->maximumPivots();
+          if (maxFactor > 10) {
+               if (forceFactorization_ < 0)
+                    forceFactorization_ = maxFactor;
+               forceFactorization_ = CoinMax(1, (forceFactorization_ >> 1));
+          }
+          // later we may need to unwind more e.g. fake bounds
+          if(lastGoodIteration_ != numberIterations_) {
+               clearAll();
+               pivotRow_ = -1;
+               returnCode = -4;
+          } else {
+               // need to reject something
+               char x = isColumn(sequenceIn_) ? 'C' : 'R';
+               handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                         << x << sequenceWithin(sequenceIn_)
+                         << CoinMessageEol;
+               setFlagged(sequenceIn_);
+               progress_.clearBadTimes();
+               lastBadIteration_ = numberIterations_; // say be more cautious
+               clearAll();
+               pivotRow_ = -1;
+               sequenceOut_ = -1;
+               returnCode = -5;
+
+          }
+          return returnCode;
+     } else if (updateStatus == 3) {
+          // out of memory
+          // increase space if not many iterations
+          if (factorization_->pivots() <
+                    0.5 * factorization_->maximumPivots() &&
+                    factorization_->pivots() < 200)
+               factorization_->areaFactor(
+                    factorization_->areaFactor() * 1.1);
+          returnCode = -2; // factorize now
+     } else if (updateStatus == 5) {
+          problemStatus_ = -2; // factorize now
+     }
+
+     // update primal solution
+
+     double objectiveChange = 0.0;
+     // after this rowArray_[1] is not empty - used to update djs
+     // If pivot row >= numberRows then may be gub
+     updatePrimalsInPrimal(rowArray_[1], theta_, objectiveChange, 1);
+
+     double oldValue = valueIn_;
+     if (directionIn_ == -1) {
+          // as if from upper bound
+          if (sequenceIn_ != sequenceOut_) {
+               // variable becoming basic
+               valueIn_ -= fabs(theta_);
+          } else {
+               valueIn_ = lowerIn_;
+          }
+     } else {
+          // as if from lower bound
+          if (sequenceIn_ != sequenceOut_) {
+               // variable becoming basic
+               valueIn_ += fabs(theta_);
+          } else {
+               valueIn_ = upperIn_;
+          }
+     }
+     objectiveChange += dualIn_ * (valueIn_ - oldValue);
+     // outgoing
+     if (sequenceIn_ != sequenceOut_) {
+          if (directionOut_ > 0) {
+               valueOut_ = lowerOut_;
+          } else {
+               valueOut_ = upperOut_;
+          }
+          if(valueOut_ < lower_[sequenceOut_] - primalTolerance_)
+               valueOut_ = lower_[sequenceOut_] - 0.9 * primalTolerance_;
+          else if (valueOut_ > upper_[sequenceOut_] + primalTolerance_)
+               valueOut_ = upper_[sequenceOut_] + 0.9 * primalTolerance_;
+          // may not be exactly at bound and bounds may have changed
+          // Make sure outgoing looks feasible
+          if (!isSuperBasic)
+               directionOut_ = nonLinearCost_->setOneOutgoing(sequenceOut_, valueOut_);
+          solution_[sequenceOut_] = valueOut_;
+     }
+     // change cost and bounds on incoming if primal
+     nonLinearCost_->setOne(sequenceIn_, valueIn_);
+     int whatNext = housekeeping(objectiveChange);
+     if (keepValue)
+          solution_[sequenceOut_] = saveValue;
+     if (isSuperBasic)
+          setStatus(sequenceOut_, superBasic);
+     //#define CLP_DEBUG
+#if CLP_DEBUG > 1
+     {
+          int ninf = matrix_->checkFeasible(this);
+          if (ninf)
+               printf("infeas %d\n", ninf);
+     }
+#endif
+     if (whatNext == 1) {
+          returnCode = -2; // refactorize
+     } else if (whatNext == 2) {
+          // maximum iterations or equivalent
+          returnCode = 3;
+     } else if(numberIterations_ == lastGoodIteration_
+               + 2 * factorization_->maximumPivots()) {
+          // done a lot of flips - be safe
+          returnCode = -2; // refactorize
+     }
+     // Check event
+     {
+          int status = eventHandler_->event(ClpEventHandler::endOfIteration);
+          if (status >= 0) {
+               problemStatus_ = 5;
+               secondaryStatus_ = ClpEventHandler::endOfIteration;
+               returnCode = 4;
+          }
+     }
+     return returnCode;
+}
+// A sequential LP method
+int
+ClpSimplexNonlinear::primalSLP(int numberPasses, double deltaTolerance)
+{
+     // Are we minimizing or maximizing
+     double whichWay = optimizationDirection();
+     if (whichWay < 0.0)
+          whichWay = -1.0;
+     else if (whichWay > 0.0)
+          whichWay = 1.0;
+
+
+     int numberColumns = this->numberColumns();
+     int numberRows = this->numberRows();
+     double * columnLower = this->columnLower();
+     double * columnUpper = this->columnUpper();
+     double * solution = this->primalColumnSolution();
+
+     if (objective_->type() < 2) {
+          // no nonlinear part
+          return ClpSimplex::primal(0);
+     }
+     // Get list of non linear columns
+     char * markNonlinear = new char[numberColumns];
+     memset(markNonlinear, 0, numberColumns);
+     int numberNonLinearColumns = objective_->markNonlinear(markNonlinear);
+
+     if (!numberNonLinearColumns) {
+          delete [] markNonlinear;
+          // no nonlinear part
+          return ClpSimplex::primal(0);
+     }
+     int iColumn;
+     int * listNonLinearColumn = new int[numberNonLinearColumns];
+     numberNonLinearColumns = 0;
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          if(markNonlinear[iColumn])
+               listNonLinearColumn[numberNonLinearColumns++] = iColumn;
+     }
+     // Replace objective
+     ClpObjective * trueObjective = objective_;
+     objective_ = new ClpLinearObjective(NULL, numberColumns);
+     double * objective = this->objective();
+
+     // get feasible
+     if (this->status() < 0 || numberPrimalInfeasibilities())
+          ClpSimplex::primal(1);
+     // still infeasible
+     if (numberPrimalInfeasibilities()) {
+          delete [] listNonLinearColumn;
+          return 0;
+     }
+     algorithm_ = 1;
+     int jNon;
+     int * last[3];
+
+     double * trust = new double[numberNonLinearColumns];
+     double * trueLower = new double[numberNonLinearColumns];
+     double * trueUpper = new double[numberNonLinearColumns];
+     for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+          iColumn = listNonLinearColumn[jNon];
+          trust[jNon] = 0.5;
+          trueLower[jNon] = columnLower[iColumn];
+          trueUpper[jNon] = columnUpper[iColumn];
+          if (solution[iColumn] < trueLower[jNon])
+               solution[iColumn] = trueLower[jNon];
+          else if (solution[iColumn] > trueUpper[jNon])
+               solution[iColumn] = trueUpper[jNon];
+     }
+     int saveLogLevel = logLevel();
+     int iPass;
+     double lastObjective = 1.0e31;
+     double * saveSolution = new double [numberColumns];
+     double * saveRowSolution = new double [numberRows];
+     memset(saveRowSolution, 0, numberRows * sizeof(double));
+     double * savePi = new double [numberRows];
+     double * safeSolution = new double [numberColumns];
+     unsigned char * saveStatus = new unsigned char[numberRows+numberColumns];
+#define MULTIPLE 0
+#if MULTIPLE>2
+     // Duplication but doesn't really matter
+     double * saveSolutionM[MULTIPLE
+                       };
+for (jNon=0; jNon<MULTIPLE; jNon++)
+{
+     saveSolutionM[jNon] = new double[numberColumns];
+     CoinMemcpyN(solution, numberColumns, saveSolutionM);
+}
+#endif
+double targetDrop = 1.0e31;
+double objectiveOffset;
+getDblParam(ClpObjOffset, objectiveOffset);
+// 1 bound up, 2 up, -1 bound down, -2 down, 0 no change
+for (iPass = 0; iPass < 3; iPass++)
+{
+     last[iPass] = new int[numberNonLinearColumns];
+     for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+          last[iPass][jNon] = 0;
+}
+// goodMove +1 yes, 0 no, -1 last was bad - just halve gaps, -2 do nothing
+int goodMove = -2;
+char * statusCheck = new char[numberColumns];
+double * changeRegion = new double [numberColumns];
+double offset = 0.0;
+double objValue = 0.0;
+int exitPass = 2 * numberPasses + 10;
+for (iPass = 0; iPass < numberPasses; iPass++)
+{
+     exitPass--;
+     // redo objective
+     offset = 0.0;
+     objValue = -objectiveOffset;
+     // make sure x updated
+     trueObjective->newXValues();
+     double theta = -1.0;
+     double maxTheta = COIN_DBL_MAX;
+     //maxTheta=1.0;
+     if (iPass) {
+          int jNon = 0;
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               changeRegion[iColumn] = solution[iColumn] - saveSolution[iColumn];
+               double alpha = changeRegion[iColumn];
+               double oldValue = saveSolution[iColumn];
+               if (markNonlinear[iColumn] == 0) {
+                    // linear
+                    if (alpha < -1.0e-15) {
+                         // variable going towards lower bound
+                         double bound = columnLower[iColumn];
+                         oldValue -= bound;
+                         if (oldValue + maxTheta * alpha < 0.0) {
+                              maxTheta = CoinMax(0.0, oldValue / (-alpha));
+                         }
+                    } else if (alpha > 1.0e-15) {
+                         // variable going towards upper bound
+                         double bound = columnUpper[iColumn];
+                         oldValue = bound - oldValue;
+                         if (oldValue - maxTheta * alpha < 0.0) {
+                              maxTheta = CoinMax(0.0, oldValue / alpha);
+                         }
+                    }
+               } else {
+                    // nonlinear
+                    if (alpha < -1.0e-15) {
+                         // variable going towards lower bound
+                         double bound = trueLower[jNon];
+                         oldValue -= bound;
+                         if (oldValue + maxTheta * alpha < 0.0) {
+                              maxTheta = CoinMax(0.0, oldValue / (-alpha));
+                         }
+                    } else if (alpha > 1.0e-15) {
+                         // variable going towards upper bound
+                         double bound = trueUpper[jNon];
+                         oldValue = bound - oldValue;
+                         if (oldValue - maxTheta * alpha < 0.0) {
+                              maxTheta = CoinMax(0.0, oldValue / alpha);
+                         }
+                    }
+                    jNon++;
+               }
+          }
+          // make sure both accurate
+          memset(rowActivity_, 0, numberRows_ * sizeof(double));
+          times(1.0, solution, rowActivity_);
+          memset(saveRowSolution, 0, numberRows_ * sizeof(double));
+          times(1.0, saveSolution, saveRowSolution);
+          for (int iRow = 0; iRow < numberRows; iRow++) {
+               double alpha = rowActivity_[iRow] - saveRowSolution[iRow];
+               double oldValue = saveRowSolution[iRow];
+               if (alpha < -1.0e-15) {
+                    // variable going towards lower bound
+                    double bound = rowLower_[iRow];
+                    oldValue -= bound;
+                    if (oldValue + maxTheta * alpha < 0.0) {
+                         maxTheta = CoinMax(0.0, oldValue / (-alpha));
+                    }
+               } else if (alpha > 1.0e-15) {
+                    // variable going towards upper bound
+                    double bound = rowUpper_[iRow];
+                    oldValue = bound - oldValue;
+                    if (oldValue - maxTheta * alpha < 0.0) {
+                         maxTheta = CoinMax(0.0, oldValue / alpha);
+                    }
+               }
+          }
+     } else {
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               changeRegion[iColumn] = 0.0;
+               saveSolution[iColumn] = solution[iColumn];
+          }
+          CoinMemcpyN(rowActivity_, numberRows, saveRowSolution);
+     }
+     // get current value anyway
+     double predictedObj, thetaObj;
+     double maxTheta2 = 2.0; // to work out a b c
+     double theta2 = trueObjective->stepLength(this, saveSolution, changeRegion, maxTheta2,
+                     objValue, predictedObj, thetaObj);
+     int lastMoveStatus = goodMove;
+     if (goodMove >= 0) {
+          theta = CoinMin(theta2, maxTheta);
+#ifdef CLP_DEBUG
+          if (handler_->logLevel() & 32)
+               printf("theta %g, current %g, at maxtheta %g, predicted %g\n",
+                      theta, objValue, thetaObj, predictedObj);
+#endif
+          if (theta > 0.0 && theta <= 1.0) {
+               // update solution
+               double lambda = 1.0 - theta;
+               for (iColumn = 0; iColumn < numberColumns; iColumn++)
+                    solution[iColumn] = lambda * saveSolution[iColumn]
+                                        + theta * solution[iColumn];
+               memset(rowActivity_, 0, numberRows_ * sizeof(double));
+               times(1.0, solution, rowActivity_);
+               if (lambda > 0.999) {
+                    CoinMemcpyN(savePi, numberRows, this->dualRowSolution());
+                    CoinMemcpyN(saveStatus, numberRows + numberColumns, status_);
+               }
+               // Do local minimization
+#define LOCAL
+#ifdef LOCAL
+               bool absolutelyOptimal = false;
+               int saveScaling = scalingFlag();
+               scaling(0);
+               int savePerturbation = perturbation_;
+               perturbation_ = 100;
+               if (saveLogLevel == 1)
+                    setLogLevel(0);
+               int status = startup(1);
+               if (!status) {
+                    int numberTotal = numberRows_ + numberColumns_;
+                    // resize arrays
+                    for (int i = 0; i < 4; i++) {
+                         rowArray_[i]->reserve(CoinMax(numberRows_ + numberColumns_, rowArray_[i]->capacity()));
+                    }
+                    CoinIndexedVector * longArray = rowArray_[3];
+                    CoinIndexedVector * rowArray = rowArray_[0];
+                    //CoinIndexedVector * columnArray = columnArray_[0];
+                    CoinIndexedVector * spare = rowArray_[1];
+                    double * work = longArray->denseVector();
+                    int * which = longArray->getIndices();
+                    int nPass = 100;
+                    //bool conjugate=false;
+                    // Put back true bounds
+                    for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                         int iColumn = listNonLinearColumn[jNon];
+                         double value;
+                         value = trueLower[jNon];
+                         trueLower[jNon] = lower_[iColumn];
+                         lower_[iColumn] = value;
+                         value = trueUpper[jNon];
+                         trueUpper[jNon] = upper_[iColumn];
+                         upper_[iColumn] = value;
+                         switch(getStatus(iColumn)) {
+
+                         case basic:
+                         case isFree:
+                         case superBasic:
+                              break;
+                         case isFixed:
+                         case atUpperBound:
+                         case atLowerBound:
+                              if (solution_[iColumn] > lower_[iColumn] + primalTolerance_) {
+                                   if(solution_[iColumn] < upper_[iColumn] - primalTolerance_) {
+                                        setStatus(iColumn, superBasic);
+                                   } else {
+                                        setStatus(iColumn, atUpperBound);
+                                   }
+                              } else {
+                                   if(solution_[iColumn] < upper_[iColumn] - primalTolerance_) {
+                                        setStatus(iColumn, atLowerBound);
+                                   } else {
+                                        setStatus(iColumn, isFixed);
+                                   }
+                              }
+                              break;
+                         }
+                    }
+                    for (int jPass = 0; jPass < nPass; jPass++) {
+                         trueObjective->reducedGradient(this, dj_, true);
+                         // get direction vector in longArray
+                         longArray->clear();
+                         double normFlagged = 0.0;
+                         double normUnflagged = 0.0;
+                         int numberNonBasic = 0;
+                         directionVector(longArray, spare, rowArray, 0,
+                                         normFlagged, normUnflagged, numberNonBasic);
+                         if (normFlagged + normUnflagged < 1.0e-8) {
+                              absolutelyOptimal = true;
+                              break;  //looks optimal
+                         }
+                         double djNorm = 0.0;
+                         int iIndex;
+                         for (iIndex = 0; iIndex < numberNonBasic; iIndex++) {
+                              int iSequence = which[iIndex];
+                              double alpha = work[iSequence];
+                              djNorm += alpha * alpha;
+                         }
+                         //if (!jPass)
+                         //printf("dj norm %g - %d \n",djNorm,numberNonBasic);
+                         //int number=longArray->getNumElements();
+                         if (!numberNonBasic) {
+                              // looks optimal
+                              absolutelyOptimal = true;
+                              break;
+                         }
+                         double theta = 1.0e30;
+                         int iSequence;
+                         for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+                              double alpha = work[iSequence];
+                              double oldValue = solution_[iSequence];
+                              if (alpha < -1.0e-15) {
+                                   // variable going towards lower bound
+                                   double bound = lower_[iSequence];
+                                   oldValue -= bound;
+                                   if (oldValue + theta * alpha < 0.0) {
+                                        theta = CoinMax(0.0, oldValue / (-alpha));
+                                   }
+                              } else if (alpha > 1.0e-15) {
+                                   // variable going towards upper bound
+                                   double bound = upper_[iSequence];
+                                   oldValue = bound - oldValue;
+                                   if (oldValue - theta * alpha < 0.0) {
+                                        theta = CoinMax(0.0, oldValue / alpha);
+                                   }
+                              }
+                         }
+                         // Now find minimum of function
+                         double currentObj;
+                         double predictedObj;
+                         double thetaObj;
+                         // need to use true objective
+                         double * saveCost = cost_;
+                         cost_ = NULL;
+                         double objTheta = trueObjective->stepLength(this, solution_, work, theta,
+                                           currentObj, predictedObj, thetaObj);
+                         cost_ = saveCost;
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("current obj %g thetaObj %g, predictedObj %g\n", currentObj, thetaObj, predictedObj);
+#endif
+                         //printf("current obj %g thetaObj %g, predictedObj %g\n",currentObj,thetaObj,predictedObj);
+                         //printf("objTheta %g theta %g\n",objTheta,theta);
+                         if (theta > objTheta) {
+                              theta = objTheta;
+                              thetaObj = predictedObj;
+                         }
+                         // update one used outside
+                         objValue = currentObj;
+                         if (theta > 1.0e-9 &&
+                                   (currentObj - thetaObj < -CoinMax(1.0e-8, 1.0e-15 * fabs(currentObj)) || jPass < 5)) {
+                              // Update solution
+                              for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+                                   double alpha = work[iSequence];
+                                   if (alpha) {
+                                        double value = solution_[iSequence] + theta * alpha;
+                                        solution_[iSequence] = value;
+                                        switch(getStatus(iSequence)) {
+
+                                        case basic:
+                                        case isFixed:
+                                        case isFree:
+                                             break;
+                                        case atUpperBound:
+                                        case atLowerBound:
+                                        case superBasic:
+                                             if (value > lower_[iSequence] + primalTolerance_) {
+                                                  if(value < upper_[iSequence] - primalTolerance_) {
+                                                       setStatus(iSequence, superBasic);
+                                                  } else {
+                                                       setStatus(iSequence, atUpperBound);
+                                                  }
+                                             } else {
+                                                  if(value < upper_[iSequence] - primalTolerance_) {
+                                                       setStatus(iSequence, atLowerBound);
+                                                  } else {
+                                                       setStatus(iSequence, isFixed);
+                                                  }
+                                             }
+                                             break;
+                                        }
+                                   }
+                              }
+                         } else {
+                              break;
+                         }
+                    }
+                    // Put back fake bounds
+                    for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                         int iColumn = listNonLinearColumn[jNon];
+                         double value;
+                         value = trueLower[jNon];
+                         trueLower[jNon] = lower_[iColumn];
+                         lower_[iColumn] = value;
+                         value = trueUpper[jNon];
+                         trueUpper[jNon] = upper_[iColumn];
+                         upper_[iColumn] = value;
+                    }
+               }
+               problemStatus_ = 0;
+               finish();
+               scaling(saveScaling);
+               perturbation_ = savePerturbation;
+               setLogLevel(saveLogLevel);
+#endif
+               // redo rowActivity
+               memset(rowActivity_, 0, numberRows_ * sizeof(double));
+               times(1.0, solution, rowActivity_);
+               if (theta > 0.99999 && theta2 < 1.9 && !absolutelyOptimal) {
+                    // If big changes then tighten
+                    /*  thetaObj is objvalue + a*2*2 +b*2
+                        predictedObj is objvalue + a*theta2*theta2 +b*theta2
+                    */
+                    double rhs1 = thetaObj - objValue;
+                    double rhs2 = predictedObj - objValue;
+                    double subtractB = theta2 * 0.5;
+                    double a = (rhs2 - subtractB * rhs1) / (theta2 * theta2 - 4.0 * subtractB);
+                    double b = 0.5 * (rhs1 - 4.0 * a);
+                    if (fabs(a + b) > 1.0e-2) {
+                         // tighten all
+                         goodMove = -1;
+                    }
+               }
+          }
+     }
+     CoinMemcpyN(trueObjective->gradient(this, solution, offset, true, 2),	numberColumns,
+                 objective);
+     //printf("offset comp %g orig %g\n",offset,objectiveOffset);
+     // could do faster
+     trueObjective->stepLength(this, solution, changeRegion, 0.0,
+                               objValue, predictedObj, thetaObj);
+#ifdef CLP_INVESTIGATE
+     printf("offset comp %g orig %g - obj from stepLength %g\n", offset, objectiveOffset, objValue);
+#endif
+     setDblParam(ClpObjOffset, objectiveOffset + offset);
+     int * temp = last[2];
+     last[2] = last[1];
+     last[1] = last[0];
+     last[0] = temp;
+     for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+          iColumn = listNonLinearColumn[jNon];
+          double change = solution[iColumn] - saveSolution[iColumn];
+          if (change < -1.0e-5) {
+               if (fabs(change + trust[jNon]) < 1.0e-5)
+                    temp[jNon] = -1;
+               else
+                    temp[jNon] = -2;
+          } else if(change > 1.0e-5) {
+               if (fabs(change - trust[jNon]) < 1.0e-5)
+                    temp[jNon] = 1;
+               else
+                    temp[jNon] = 2;
+          } else {
+               temp[jNon] = 0;
+          }
+     }
+     // goodMove +1 yes, 0 no, -1 last was bad - just halve gaps, -2 do nothing
+     double maxDelta = 0.0;
+     if (goodMove >= 0) {
+          if (objValue - lastObjective <= 1.0e-15 * fabs(lastObjective))
+               goodMove = 1;
+          else
+               goodMove = 0;
+     } else {
+          maxDelta = 1.0e10;
+     }
+     double maxGap = 0.0;
+     int numberSmaller = 0;
+     int numberSmaller2 = 0;
+     int numberLarger = 0;
+     for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+          iColumn = listNonLinearColumn[jNon];
+          maxDelta = CoinMax(maxDelta,
+                             fabs(solution[iColumn] - saveSolution[iColumn]));
+          if (goodMove > 0) {
+               if (last[0][jNon]*last[1][jNon] < 0) {
+                    // halve
+                    trust[jNon] *= 0.5;
+                    numberSmaller2++;
+               } else {
+                    if (last[0][jNon] == last[1][jNon] &&
+                              last[0][jNon] == last[2][jNon])
+                         trust[jNon] = CoinMin(1.5 * trust[jNon], 1.0e6);
+                    numberLarger++;
+               }
+          } else if (goodMove != -2 && trust[jNon] > 10.0 * deltaTolerance) {
+               trust[jNon] *= 0.2;
+               numberSmaller++;
+          }
+          maxGap = CoinMax(maxGap, trust[jNon]);
+     }
+#ifdef CLP_DEBUG
+     if (handler_->logLevel() & 32)
+          std::cout << "largest gap is " << maxGap << " "
+                    << numberSmaller + numberSmaller2 << " reduced ("
+                    << numberSmaller << " badMove ), "
+                    << numberLarger << " increased" << std::endl;
+#endif
+     if (iPass > 10000) {
+          for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+               trust[jNon] *= 0.0001;
+     }
+     if(lastMoveStatus == -1 && goodMove == -1)
+          goodMove = 1; // to force solve
+     if (goodMove > 0) {
+          double drop = lastObjective - objValue;
+          handler_->message(CLP_SLP_ITER, messages_)
+                    << iPass << objValue - objectiveOffset
+                    << drop << maxDelta
+                    << CoinMessageEol;
+          if (iPass > 20 && drop < 1.0e-12 * fabs(objValue))
+               drop = 0.999e-4; // so will exit
+          if (maxDelta < deltaTolerance && drop < 1.0e-4 && goodMove && theta < 0.99999) {
+               if (handler_->logLevel() > 1)
+                    std::cout << "Exiting as maxDelta < tolerance and small drop" << std::endl;
+               break;
+          }
+     } else if (!numberSmaller && iPass > 1) {
+          if (handler_->logLevel() > 1)
+               std::cout << "Exiting as all gaps small" << std::endl;
+          break;
+     }
+     if (!iPass)
+          goodMove = 1;
+     targetDrop = 0.0;
+     double * r = this->dualColumnSolution();
+     for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+          iColumn = listNonLinearColumn[jNon];
+          columnLower[iColumn] = CoinMax(solution[iColumn]
+                                         - trust[jNon],
+                                         trueLower[jNon]);
+          columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                         + trust[jNon],
+                                         trueUpper[jNon]);
+     }
+     if (iPass) {
+          // get reduced costs
+          this->matrix()->transposeTimes(savePi,
+                                         this->dualColumnSolution());
+          for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+               iColumn = listNonLinearColumn[jNon];
+               double dj = objective[iColumn] - r[iColumn];
+               r[iColumn] = dj;
+               if (dj < -dualTolerance_)
+                    targetDrop -= dj * (columnUpper[iColumn] - solution[iColumn]);
+               else if (dj > dualTolerance_)
+                    targetDrop -= dj * (columnLower[iColumn] - solution[iColumn]);
+          }
+     } else {
+          memset(r, 0, numberColumns * sizeof(double));
+     }
+#if 0
+     for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+          iColumn = listNonLinearColumn[jNon];
+          if (statusCheck[iColumn] == 'L' && r[iColumn] < -1.0e-4) {
+               columnLower[iColumn] = CoinMax(solution[iColumn],
+                                              trueLower[jNon]);
+               columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                              + trust[jNon],
+                                              trueUpper[jNon]);
+          } else if (statusCheck[iColumn] == 'U' && r[iColumn] > 1.0e-4) {
+               columnLower[iColumn] = CoinMax(solution[iColumn]
+                                              - trust[jNon],
+                                              trueLower[jNon]);
+               columnUpper[iColumn] = CoinMin(solution[iColumn],
+                                              trueUpper[jNon]);
+          } else {
+               columnLower[iColumn] = CoinMax(solution[iColumn]
+                                              - trust[jNon],
+                                              trueLower[jNon]);
+               columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                              + trust[jNon],
+                                              trueUpper[jNon]);
+          }
+     }
+#endif
+     if (goodMove > 0) {
+          CoinMemcpyN(solution, numberColumns, saveSolution);
+          CoinMemcpyN(rowActivity_, numberRows, saveRowSolution);
+          CoinMemcpyN(this->dualRowSolution(), numberRows, savePi);
+          CoinMemcpyN(status_, numberRows + numberColumns, saveStatus);
+#if MULTIPLE>2
+          double * tempSol = saveSolutionM[0];
+          for (jNon = 0; jNon < MULTIPLE - 1; jNon++) {
+               saveSolutionM[jNon] = saveSolutionM[jNon+1];
+          }
+          saveSolutionM[MULTIPLE-1] = tempSol;
+          CoinMemcpyN(solution, numberColumns, tempSol);
+
+#endif
+
+#ifdef CLP_DEBUG
+          if (handler_->logLevel() & 32)
+               std::cout << "Pass - " << iPass
+                         << ", target drop is " << targetDrop
+                         << std::endl;
+#endif
+          lastObjective = objValue;
+          if (targetDrop < CoinMax(1.0e-8, CoinMin(1.0e-6, 1.0e-6 * fabs(objValue))) && goodMove && iPass > 3) {
+               if (handler_->logLevel() > 1)
+                    printf("Exiting on target drop %g\n", targetDrop);
+               break;
+          }
+#ifdef CLP_DEBUG
+          {
+               double * r = this->dualColumnSolution();
+               for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                    iColumn = listNonLinearColumn[jNon];
+                    if (handler_->logLevel() & 32)
+                         printf("Trust %d %g - solution %d %g obj %g dj %g state %c - bounds %g %g\n",
+                                jNon, trust[jNon], iColumn, solution[iColumn], objective[iColumn],
+                                r[iColumn], statusCheck[iColumn], columnLower[iColumn],
+                                columnUpper[iColumn]);
+               }
+          }
+#endif
+          //setLogLevel(63);
+          this->scaling(false);
+          if (saveLogLevel == 1)
+               setLogLevel(0);
+          ClpSimplex::primal(1);
+          algorithm_ = 1;
+          setLogLevel(saveLogLevel);
+#ifdef CLP_DEBUG
+          if (this->status()) {
+               writeMps("xx.mps");
+          }
+#endif
+          if (this->status() == 1) {
+               // not feasible ! - backtrack and exit
+               // use safe solution
+               CoinMemcpyN(safeSolution, numberColumns, solution);
+               CoinMemcpyN(solution, numberColumns, saveSolution);
+               memset(rowActivity_, 0, numberRows_ * sizeof(double));
+               times(1.0, solution, rowActivity_);
+               CoinMemcpyN(rowActivity_, numberRows, saveRowSolution);
+               CoinMemcpyN(savePi, numberRows, this->dualRowSolution());
+               CoinMemcpyN(saveStatus, numberRows + numberColumns, status_);
+               for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                    iColumn = listNonLinearColumn[jNon];
+                    columnLower[iColumn] = CoinMax(solution[iColumn]
+                                                   - trust[jNon],
+                                                   trueLower[jNon]);
+                    columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                                   + trust[jNon],
+                                                   trueUpper[jNon]);
+               }
+               break;
+          } else {
+               // save in case problems
+               CoinMemcpyN(solution, numberColumns, safeSolution);
+          }
+          if (problemStatus_ == 3)
+               break; // probably user interrupt
+          goodMove = 1;
+     } else {
+          // bad pass - restore solution
+#ifdef CLP_DEBUG
+          if (handler_->logLevel() & 32)
+               printf("Backtracking\n");
+#endif
+          CoinMemcpyN(saveSolution, numberColumns, solution);
+          CoinMemcpyN(saveRowSolution, numberRows, rowActivity_);
+          CoinMemcpyN(savePi, numberRows, this->dualRowSolution());
+          CoinMemcpyN(saveStatus, numberRows + numberColumns, status_);
+          iPass--;
+          assert (exitPass > 0);
+          goodMove = -1;
+     }
+}
+#if MULTIPLE>2
+for (jNon = 0; jNon < MULTIPLE; jNon++)
+{
+     delete [] saveSolutionM[jNon];
+}
+#endif
+// restore solution
+CoinMemcpyN(saveSolution, numberColumns, solution);
+CoinMemcpyN(saveRowSolution, numberRows, rowActivity_);
+for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+{
+     iColumn = listNonLinearColumn[jNon];
+     columnLower[iColumn] = CoinMax(solution[iColumn],
+                                    trueLower[jNon]);
+     columnUpper[iColumn] = CoinMin(solution[iColumn],
+                                    trueUpper[jNon]);
+}
+delete [] markNonlinear;
+delete [] statusCheck;
+delete [] savePi;
+delete [] saveStatus;
+// redo objective
+CoinMemcpyN(trueObjective->gradient(this, solution, offset, true, 2),	numberColumns,
+            objective);
+ClpSimplex::primal(1);
+delete objective_;
+objective_ = trueObjective;
+// redo values
+setDblParam(ClpObjOffset, objectiveOffset);
+objectiveValue_ += whichWay * offset;
+for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+{
+     iColumn = listNonLinearColumn[jNon];
+     columnLower[iColumn] = trueLower[jNon];
+     columnUpper[iColumn] = trueUpper[jNon];
+}
+delete [] saveSolution;
+delete [] safeSolution;
+delete [] saveRowSolution;
+for (iPass = 0; iPass < 3; iPass++)
+     delete [] last[iPass];
+delete [] trust;
+delete [] trueUpper;
+delete [] trueLower;
+delete [] listNonLinearColumn;
+delete [] changeRegion;
+// temp
+//setLogLevel(63);
+return 0;
+}
+/* Primal algorithm for nonlinear constraints
+   Using a semi-trust region approach as for pooling problem
+   This is in because I have it lying around
+
+*/
+int
+ClpSimplexNonlinear::primalSLP(int numberConstraints, ClpConstraint ** constraints,
+                               int numberPasses, double deltaTolerance)
+{
+     if (!numberConstraints) {
+          // no nonlinear constraints - may be nonlinear objective
+          return primalSLP(numberPasses, deltaTolerance);
+     }
+     // Are we minimizing or maximizing
+     double whichWay = optimizationDirection();
+     if (whichWay < 0.0)
+          whichWay = -1.0;
+     else if (whichWay > 0.0)
+          whichWay = 1.0;
+     // check all matrix for odd rows is empty
+     int iConstraint;
+     int numberBad = 0;
+     CoinPackedMatrix * columnCopy = matrix();
+     // Get a row copy in standard format
+     CoinPackedMatrix copy;
+     copy.reverseOrderedCopyOf(*columnCopy);
+     // get matrix data pointers
+     //const int * column = copy.getIndices();
+     //const CoinBigIndex * rowStart = copy.getVectorStarts();
+     const int * rowLength = copy.getVectorLengths();
+     //const double * elementByRow = copy.getElements();
+     int numberArtificials = 0;
+     // We could use nonlinearcost to do segments - maybe later
+#define SEGMENTS 3
+     // Penalties may be adjusted by duals
+     // Both these should be modified depending on problem
+     // Possibly start with big bounds
+     //double penalties[]={1.0e-3,1.0e7,1.0e9};
+     double penalties[] = {1.0e7, 1.0e8, 1.0e9};
+     double bounds[] = {1.0e-2, 1.0e2, COIN_DBL_MAX};
+     // see how many extra we need
+     CoinBigIndex numberExtra = 0;
+     for (iConstraint = 0; iConstraint < numberConstraints; iConstraint++) {
+          ClpConstraint * constraint = constraints[iConstraint];
+          int iRow = constraint->rowNumber();
+          assert (iRow >= 0);
+          int n = constraint->numberCoefficients() - rowLength[iRow];
+          numberExtra += n;
+          if (iRow >= numberRows_)
+               numberBad++;
+          else if (rowLength[iRow] && n)
+               numberBad++;
+          if (rowLower_[iRow] > -1.0e20)
+               numberArtificials++;
+          if (rowUpper_[iRow] < 1.0e20)
+               numberArtificials++;
+     }
+     if (numberBad)
+          return numberBad;
+     ClpObjective * trueObjective = NULL;
+     if (objective_->type() >= 2) {
+          // Replace objective
+          trueObjective = objective_;
+          objective_ = new ClpLinearObjective(NULL, numberColumns_);
+     }
+     ClpSimplex newModel(*this);
+     // we can put back true objective
+     if (trueObjective) {
+          // Replace objective
+          delete objective_;
+          objective_ = trueObjective;
+     }
+     int numberColumns2 = numberColumns_;
+     int numberSmallGap = numberArtificials;
+     if (numberArtificials) {
+          numberArtificials *= SEGMENTS;
+          numberColumns2 += numberArtificials;
+          int * addStarts = new int [numberArtificials+1];
+          int * addRow = new int[numberArtificials];
+          double * addElement = new double[numberArtificials];
+          double * addUpper = new double[numberArtificials];
+          addStarts[0] = 0;
+          double * addCost = new double [numberArtificials];
+          numberArtificials = 0;
+          for (iConstraint = 0; iConstraint < numberConstraints; iConstraint++) {
+               ClpConstraint * constraint = constraints[iConstraint];
+               int iRow = constraint->rowNumber();
+               if (rowLower_[iRow] > -1.0e20) {
+                    for (int k = 0; k < SEGMENTS; k++) {
+                         addRow[numberArtificials] = iRow;
+                         addElement[numberArtificials] = 1.0;
+                         addCost[numberArtificials] = penalties[k];
+                         addUpper[numberArtificials] = bounds[k];
+                         numberArtificials++;
+                         addStarts[numberArtificials] = numberArtificials;
+                    }
+               }
+               if (rowUpper_[iRow] < 1.0e20) {
+                    for (int k = 0; k < SEGMENTS; k++) {
+                         addRow[numberArtificials] = iRow;
+                         addElement[numberArtificials] = -1.0;
+                         addCost[numberArtificials] = penalties[k];
+                         addUpper[numberArtificials] = bounds[k];
+                         numberArtificials++;
+                         addStarts[numberArtificials] = numberArtificials;
+                    }
+               }
+          }
+          newModel.addColumns(numberArtificials, NULL, addUpper, addCost,
+                              addStarts, addRow, addElement);
+          delete [] addStarts;
+          delete [] addRow;
+          delete [] addElement;
+          delete [] addUpper;
+          delete [] addCost;
+          //    newModel.primal(1);
+     }
+     // find nonlinear columns
+     int * listNonLinearColumn = new int [numberColumns_+numberSmallGap];
+     char * mark = new char[numberColumns_];
+     memset(mark, 0, numberColumns_);
+     for (iConstraint = 0; iConstraint < numberConstraints; iConstraint++) {
+          ClpConstraint * constraint = constraints[iConstraint];
+          constraint->markNonlinear(mark);
+     }
+     if (trueObjective)
+          trueObjective->markNonlinear(mark);
+     int iColumn;
+     int numberNonLinearColumns = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          if (mark[iColumn])
+               listNonLinearColumn[numberNonLinearColumns++] = iColumn;
+     }
+     // and small gap artificials
+     for (iColumn = numberColumns_; iColumn < numberColumns2; iColumn += SEGMENTS) {
+          listNonLinearColumn[numberNonLinearColumns++] = iColumn;
+     }
+     // build row copy of matrix with space for nonzeros
+     // Get column copy
+     columnCopy = newModel.matrix();
+     copy.reverseOrderedCopyOf(*columnCopy);
+     // get matrix data pointers
+     const int * column = copy.getIndices();
+     const CoinBigIndex * rowStart = copy.getVectorStarts();
+     rowLength = copy.getVectorLengths();
+     const double * elementByRow = copy.getElements();
+     numberExtra += copy.getNumElements();
+     CoinBigIndex * newStarts = new CoinBigIndex [numberRows_+1];
+     int * newColumn = new int[numberExtra];
+     double * newElement = new double[numberExtra];
+     newStarts[0] = 0;
+     int * backRow = new int [numberRows_];
+     int iRow;
+     for (iRow = 0; iRow < numberRows_; iRow++)
+          backRow[iRow] = -1;
+     for (iConstraint = 0; iConstraint < numberConstraints; iConstraint++) {
+          ClpConstraint * constraint = constraints[iConstraint];
+          iRow = constraint->rowNumber();
+          backRow[iRow] = iConstraint;
+     }
+     numberExtra = 0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          if (backRow[iRow] < 0) {
+               // copy normal
+               for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow];
+                         j++) {
+                    newColumn[numberExtra] = column[j];
+                    newElement[numberExtra++] = elementByRow[j];
+               }
+          } else {
+               ClpConstraint * constraint = constraints[backRow[iRow]];
+               assert(iRow == constraint->rowNumber());
+               int numberArtificials = 0;
+               if (rowLower_[iRow] > -1.0e20)
+                    numberArtificials += SEGMENTS;
+               if (rowUpper_[iRow] < 1.0e20)
+                    numberArtificials += SEGMENTS;
+               if (numberArtificials == rowLength[iRow]) {
+                    // all possible
+                    memset(mark, 0, numberColumns_);
+                    constraint->markNonzero(mark);
+                    for (int k = 0; k < numberColumns_; k++) {
+                         if (mark[k]) {
+                              newColumn[numberExtra] = k;
+                              newElement[numberExtra++] = 1.0;
+                         }
+                    }
+                    // copy artificials
+                    for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow];
+                              j++) {
+                         newColumn[numberExtra] = column[j];
+                         newElement[numberExtra++] = elementByRow[j];
+                    }
+               } else {
+                    // there already
+                    // copy
+                    for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow];
+                              j++) {
+                         newColumn[numberExtra] = column[j];
+                         assert (elementByRow[j]);
+                         newElement[numberExtra++] = elementByRow[j];
+                    }
+               }
+          }
+          newStarts[iRow+1] = numberExtra;
+     }
+     delete [] backRow;
+     CoinPackedMatrix saveMatrix(false, numberColumns2, numberRows_,
+                                 numberExtra, newElement, newColumn, newStarts, NULL, 0.0, 0.0);
+     delete [] newStarts;
+     delete [] newColumn;
+     delete [] newElement;
+     delete [] mark;
+     // get feasible
+     if (whichWay < 0.0) {
+          newModel.setOptimizationDirection(1.0);
+          double * objective = newModel.objective();
+          for (int iColumn = 0; iColumn < numberColumns_; iColumn++)
+               objective[iColumn] = - objective[iColumn];
+     }
+     newModel.primal(1);
+     // still infeasible
+     if (newModel.problemStatus() == 1) {
+          delete [] listNonLinearColumn;
+          return 0;
+     } else if (newModel.problemStatus() == 2) {
+          // unbounded - add bounds
+          double * columnLower = newModel.columnLower();
+          double * columnUpper = newModel.columnUpper();
+          for (int i = 0; i < numberColumns_; i++) {
+               columnLower[i] = CoinMax(-1.0e8, columnLower[i]);
+               columnUpper[i] = CoinMin(1.0e8, columnUpper[i]);
+          }
+          newModel.primal(1);
+     }
+     int numberRows = newModel.numberRows();
+     double * columnLower = newModel.columnLower();
+     double * columnUpper = newModel.columnUpper();
+     double * objective = newModel.objective();
+     double * rowLower = newModel.rowLower();
+     double * rowUpper = newModel.rowUpper();
+     double * solution = newModel.primalColumnSolution();
+     int jNon;
+     int * last[3];
+
+     double * trust = new double[numberNonLinearColumns];
+     double * trueLower = new double[numberNonLinearColumns];
+     double * trueUpper = new double[numberNonLinearColumns];
+     double objectiveOffset;
+     double objectiveOffset2;
+     getDblParam(ClpObjOffset, objectiveOffset);
+     objectiveOffset *= whichWay;
+     for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+          iColumn = listNonLinearColumn[jNon];
+          double upper = columnUpper[iColumn];
+          double lower = columnLower[iColumn];
+          if (solution[iColumn] < lower)
+               solution[iColumn] = lower;
+          else if (solution[iColumn] > upper)
+               solution[iColumn] = upper;
+#if 0
+          double large = CoinMax(1000.0, 10.0 * fabs(solution[iColumn]));
+          if (upper > 1.0e10)
+               upper = solution[iColumn] + large;
+          if (lower < -1.0e10)
+               lower = solution[iColumn] - large;
+#else
+          upper = solution[iColumn] + 0.5;
+          lower = solution[iColumn] - 0.5;
+#endif
+          //columnUpper[iColumn]=upper;
+          trust[jNon] = 0.05 * (1.0 + upper - lower);
+          trueLower[jNon] = columnLower[iColumn];
+          //trueUpper[jNon]=upper;
+          trueUpper[jNon] = columnUpper[iColumn];
+     }
+     bool tryFix = false;
+     int iPass;
+     double lastObjective = 1.0e31;
+     double lastGoodObjective = 1.0e31;
+     double * bestSolution = NULL;
+     double * saveSolution = new double [numberColumns2+numberRows];
+     char * saveStatus = new char [numberColumns2+numberRows];
+     double targetDrop = 1.0e31;
+     // 1 bound up, 2 up, -1 bound down, -2 down, 0 no change
+     for (iPass = 0; iPass < 3; iPass++) {
+          last[iPass] = new int[numberNonLinearColumns];
+          for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+               last[iPass][jNon] = 0;
+     }
+     int numberZeroPasses = 0;
+     bool zeroTargetDrop = false;
+     double * gradient = new double [numberColumns_];
+     bool goneFeasible = false;
+     // keep sum of artificials
+#define KEEP_SUM 5
+     double sumArt[KEEP_SUM];
+     for (jNon = 0; jNon < KEEP_SUM; jNon++)
+          sumArt[jNon] = COIN_DBL_MAX;
+#define SMALL_FIX 0.0
+     for (iPass = 0; iPass < numberPasses; iPass++) {
+          objectiveOffset2 = objectiveOffset;
+          for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+               iColumn = listNonLinearColumn[jNon];
+               if (solution[iColumn] < trueLower[jNon])
+                    solution[iColumn] = trueLower[jNon];
+               else if (solution[iColumn] > trueUpper[jNon])
+                    solution[iColumn] = trueUpper[jNon];
+               columnLower[iColumn] = CoinMax(solution[iColumn]
+                                              - trust[jNon],
+                                              trueLower[jNon]);
+               if (!trueLower[jNon] && columnLower[iColumn] < SMALL_FIX)
+                    columnLower[iColumn] = SMALL_FIX;
+               columnUpper[iColumn] = CoinMin(solution[iColumn]
+                                              + trust[jNon],
+                                              trueUpper[jNon]);
+               if (!trueLower[jNon])
+                    columnUpper[iColumn] = CoinMax(columnUpper[iColumn],
+                                                   columnLower[iColumn] + SMALL_FIX);
+               if (!trueLower[jNon] && tryFix &&
+                         columnLower[iColumn] == SMALL_FIX &&
+                         columnUpper[iColumn] < 3.0 * SMALL_FIX) {
+                    columnLower[iColumn] = 0.0;
+                    solution[iColumn] = 0.0;
+                    columnUpper[iColumn] = 0.0;
+                    printf("fixing %d\n", iColumn);
+               }
+          }
+          // redo matrix
+          double offset;
+          CoinPackedMatrix newMatrix(saveMatrix);
+          // get matrix data pointers
+          column = newMatrix.getIndices();
+          rowStart = newMatrix.getVectorStarts();
+          rowLength = newMatrix.getVectorLengths();
+          // make sure x updated
+          if (numberConstraints)
+               constraints[0]->newXValues();
+          else
+               trueObjective->newXValues();
+          double * changeableElement = newMatrix.getMutableElements();
+          if (trueObjective) {
+               CoinMemcpyN(trueObjective->gradient(this, solution, offset, true, 2),	numberColumns_,
+                           objective);
+          } else {
+               CoinMemcpyN(objective_->gradient(this, solution, offset, true, 2),	numberColumns_,
+                           objective);
+          }
+          if (whichWay < 0.0) {
+               for (int iColumn = 0; iColumn < numberColumns_; iColumn++)
+                    objective[iColumn] = - objective[iColumn];
+          }
+          for (iConstraint = 0; iConstraint < numberConstraints; iConstraint++) {
+               ClpConstraint * constraint = constraints[iConstraint];
+               int iRow = constraint->rowNumber();
+               double functionValue;
+#ifndef NDEBUG
+               int numberErrors =
+#endif
+                    constraint->gradient(&newModel, solution, gradient, functionValue, offset);
+               assert (!numberErrors);
+               // double dualValue = newModel.dualRowSolution()[iRow];
+               int numberCoefficients = constraint->numberCoefficients();
+               for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow] + numberCoefficients; j++) {
+                    int iColumn = column[j];
+                    changeableElement[j] = gradient[iColumn];
+                    //objective[iColumn] -= dualValue*gradient[iColumn];
+                    gradient[iColumn] = 0.0;
+               }
+               for (int k = 0; k < numberColumns_; k++)
+                    assert (!gradient[k]);
+               if (rowLower_[iRow] > -1.0e20)
+                    rowLower[iRow] = rowLower_[iRow] - offset;
+               if (rowUpper_[iRow] < 1.0e20)
+                    rowUpper[iRow] = rowUpper_[iRow] - offset;
+          }
+          // Replace matrix
+          // Get a column copy in standard format
+          CoinPackedMatrix * columnCopy = new CoinPackedMatrix();;
+          columnCopy->reverseOrderedCopyOf(newMatrix);
+          newModel.replaceMatrix(columnCopy, true);
+          // solve
+          newModel.primal(1);
+          if (newModel.status() == 1) {
+               // Infeasible!
+               newModel.allSlackBasis();
+               newModel.primal();
+               newModel.writeMps("infeas.mps");
+               assert(!newModel.status());
+          }
+          double sumInfeas = 0.0;
+          int numberInfeas = 0;
+          for (iColumn = numberColumns_; iColumn < numberColumns2; iColumn++) {
+               if (solution[iColumn] > 1.0e-8) {
+                    numberInfeas++;
+                    sumInfeas += solution[iColumn];
+               }
+          }
+          printf("%d artificial infeasibilities - summing to %g\n",
+                 numberInfeas, sumInfeas);
+          for (jNon = 0; jNon < KEEP_SUM - 1; jNon++)
+               sumArt[jNon] = sumArt[jNon+1];
+          sumArt[KEEP_SUM-1] = sumInfeas;
+          if (sumInfeas > 0.01 && sumInfeas * 1.1 > sumArt[0] && penalties[1] < 1.0e7) {
+               // not doing very well - increase - be more sophisticated later
+               lastObjective = COIN_DBL_MAX;
+               for (jNon = 0; jNon < KEEP_SUM; jNon++)
+                    sumArt[jNon] = COIN_DBL_MAX;
+               //for (iColumn=numberColumns_;iColumn<numberColumns2;iColumn+=SEGMENTS) {
+               //objective[iColumn+1] *= 1.5;
+               //}
+               penalties[1] *= 1.5;
+               for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+                    if (trust[jNon] > 0.1)
+                         trust[jNon] *= 2.0;
+                    else
+                         trust[jNon] = 0.1;
+          }
+          if (sumInfeas < 0.001 && !goneFeasible) {
+               goneFeasible = true;
+               penalties[0] = 1.0e-3;
+               penalties[1] = 1.0e6;
+               printf("Got feasible\n");
+          }
+          double infValue = 0.0;
+          double objValue = 0.0;
+          // make sure x updated
+          if (numberConstraints)
+               constraints[0]->newXValues();
+          else
+               trueObjective->newXValues();
+          if (trueObjective) {
+               objValue = trueObjective->objectiveValue(this, solution);
+               printf("objective offset %g\n", offset);
+               objectiveOffset2 = objectiveOffset + offset; // ? sign
+               newModel.setObjectiveOffset(objectiveOffset2);
+          } else {
+               objValue = objective_->objectiveValue(this, solution);
+          }
+          objValue *= whichWay;
+          double infPenalty = 0.0;
+          // This penalty is for target drop
+          double infPenalty2 = 0.0;
+          //const int * row = columnCopy->getIndices();
+          //const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+          //const int * columnLength = columnCopy->getVectorLengths();
+          //const double * element = columnCopy->getElements();
+          double * cost = newModel.objective();
+          column = newMatrix.getIndices();
+          rowStart = newMatrix.getVectorStarts();
+          rowLength = newMatrix.getVectorLengths();
+          elementByRow = newMatrix.getElements();
+          int jColumn = numberColumns_;
+          double objectiveAdjustment = 0.0;
+          for (iConstraint = 0; iConstraint < numberConstraints; iConstraint++) {
+               ClpConstraint * constraint = constraints[iConstraint];
+               int iRow = constraint->rowNumber();
+               double functionValue = constraint->functionValue(this, solution);
+               double dualValue = newModel.dualRowSolution()[iRow];
+               if (numberConstraints < -50)
+                    printf("For row %d current value is %g (row activity %g) , dual is %g\n", iRow, functionValue,
+                           newModel.primalRowSolution()[iRow],
+                           dualValue);
+               double movement = newModel.primalRowSolution()[iRow] + constraint->offset();
+               movement = fabs((movement - functionValue) * dualValue);
+               infPenalty2 += movement;
+               double sumOfActivities = 0.0;
+               for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+                    int iColumn = column[j];
+                    sumOfActivities += fabs(solution[iColumn] * elementByRow[j]);
+               }
+               if (rowLower_[iRow] > -1.0e20) {
+                    if (functionValue < rowLower_[iRow] - 1.0e-5) {
+                         double infeasibility = rowLower_[iRow] - functionValue;
+                         double thisPenalty = 0.0;
+                         infValue += infeasibility;
+                         int k;
+                         assert (dualValue >= -1.0e-5);
+                         dualValue = CoinMax(dualValue, 0.0);
+                         for ( k = 0; k < SEGMENTS; k++) {
+                              if (infeasibility <= 0)
+                                   break;
+                              double thisPart = CoinMin(infeasibility, bounds[k]);
+                              thisPenalty += thisPart * cost[jColumn+k];
+                              infeasibility -= thisPart;
+                         }
+                         infeasibility = functionValue - rowUpper_[iRow];
+                         double newPenalty = 0.0;
+                         for ( k = 0; k < SEGMENTS; k++) {
+                              double thisPart = CoinMin(infeasibility, bounds[k]);
+                              cost[jColumn+k] = CoinMax(penalties[k], dualValue + 1.0e-3);
+                              newPenalty += thisPart * cost[jColumn+k];
+                              infeasibility -= thisPart;
+                         }
+                         infPenalty += thisPenalty;
+                         objectiveAdjustment += CoinMax(0.0, newPenalty - thisPenalty);
+                    }
+                    jColumn += SEGMENTS;
+               }
+               if (rowUpper_[iRow] < 1.0e20) {
+                    if (functionValue > rowUpper_[iRow] + 1.0e-5) {
+                         double infeasibility = functionValue - rowUpper_[iRow];
+                         double thisPenalty = 0.0;
+                         infValue += infeasibility;
+                         int k;
+                         dualValue = -dualValue;
+                         assert (dualValue >= -1.0e-5);
+                         dualValue = CoinMax(dualValue, 0.0);
+                         for ( k = 0; k < SEGMENTS; k++) {
+                              if (infeasibility <= 0)
+                                   break;
+                              double thisPart = CoinMin(infeasibility, bounds[k]);
+                              thisPenalty += thisPart * cost[jColumn+k];
+                              infeasibility -= thisPart;
+                         }
+                         infeasibility = functionValue - rowUpper_[iRow];
+                         double newPenalty = 0.0;
+                         for ( k = 0; k < SEGMENTS; k++) {
+                              double thisPart = CoinMin(infeasibility, bounds[k]);
+                              cost[jColumn+k] = CoinMax(penalties[k], dualValue + 1.0e-3);
+                              newPenalty += thisPart * cost[jColumn+k];
+                              infeasibility -= thisPart;
+                         }
+                         infPenalty += thisPenalty;
+                         objectiveAdjustment += CoinMax(0.0, newPenalty - thisPenalty);
+                    }
+                    jColumn += SEGMENTS;
+               }
+          }
+          // adjust last objective value
+          lastObjective += objectiveAdjustment;
+          if (infValue)
+               printf("Sum infeasibilities %g - penalty %g ", infValue, infPenalty);
+          if (objectiveOffset2)
+               printf("offset2 %g ", objectiveOffset2);
+          objValue -= objectiveOffset2;
+          printf("True objective %g or maybe %g (with penalty %g) -pen2 %g %g\n", objValue,
+                 objValue + objectiveOffset2, objValue + objectiveOffset2 + infPenalty, infPenalty2, penalties[1]);
+          double useObjValue = objValue + objectiveOffset2 + infPenalty;
+          objValue += infPenalty + infPenalty2;
+          objValue = useObjValue;
+          if (iPass) {
+               double drop = lastObjective - objValue;
+               std::cout << "True drop was " << drop << std::endl;
+               if (drop < -0.05 * fabs(objValue) - 1.0e-4) {
+                    // pretty bad - go back and halve
+                    CoinMemcpyN(saveSolution, numberColumns2, solution);
+                    CoinMemcpyN(saveSolution + numberColumns2,
+                                numberRows, newModel.primalRowSolution());
+                    CoinMemcpyN(reinterpret_cast<unsigned char *> (saveStatus),
+                                numberColumns2 + numberRows, newModel.statusArray());
+                    for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+                         if (trust[jNon] > 0.1)
+                              trust[jNon] *= 0.5;
+                         else
+                              trust[jNon] *= 0.9;
+
+                    printf("** Halving trust\n");
+                    objValue = lastObjective;
+                    continue;
+               } else if ((iPass % 25) == -1) {
+                    for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+                         trust[jNon] *= 2.0;
+                    printf("** Doubling trust\n");
+               }
+               int * temp = last[2];
+               last[2] = last[1];
+               last[1] = last[0];
+               last[0] = temp;
+               for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                    iColumn = listNonLinearColumn[jNon];
+                    double change = solution[iColumn] - saveSolution[iColumn];
+                    if (change < -1.0e-5) {
+                         if (fabs(change + trust[jNon]) < 1.0e-5)
+                              temp[jNon] = -1;
+                         else
+                              temp[jNon] = -2;
+                    } else if(change > 1.0e-5) {
+                         if (fabs(change - trust[jNon]) < 1.0e-5)
+                              temp[jNon] = 1;
+                         else
+                              temp[jNon] = 2;
+                    } else {
+                         temp[jNon] = 0;
+                    }
+               }
+               double maxDelta = 0.0;
+               double smallestTrust = 1.0e31;
+               double smallestNonLinearGap = 1.0e31;
+               double smallestGap = 1.0e31;
+               bool increasing = false;
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    double gap = columnUpper[iColumn] - columnLower[iColumn];
+                    assert (gap >= 0.0);
+                    if (gap)
+                         smallestGap = CoinMin(smallestGap, gap);
+               }
+               for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                    iColumn = listNonLinearColumn[jNon];
+                    double gap = columnUpper[iColumn] - columnLower[iColumn];
+                    assert (gap >= 0.0);
+                    if (gap) {
+                         smallestNonLinearGap = CoinMin(smallestNonLinearGap, gap);
+                         if (gap < 1.0e-7 && iPass == 1) {
+                              printf("Small gap %d %d %g %g %g\n",
+                                     jNon, iColumn, columnLower[iColumn], columnUpper[iColumn],
+                                     gap);
+                              //trueUpper[jNon]=trueLower[jNon];
+                              //columnUpper[iColumn]=columnLower[iColumn];
+                         }
+                    }
+                    maxDelta = CoinMax(maxDelta,
+                                       fabs(solution[iColumn] - saveSolution[iColumn]));
+                    if (last[0][jNon]*last[1][jNon] < 0) {
+                         // halve
+                         if (trust[jNon] > 1.0)
+                              trust[jNon] *= 0.5;
+                         else
+                              trust[jNon] *= 0.7;
+                    } else {
+                         // ? only increase if +=1 ?
+                         if (last[0][jNon] == last[1][jNon] &&
+                                   last[0][jNon] == last[2][jNon] &&
+                                   last[0][jNon]) {
+                              trust[jNon] *= 1.8;
+                              increasing = true;
+                         }
+                    }
+                    smallestTrust = CoinMin(smallestTrust, trust[jNon]);
+               }
+               std::cout << "largest delta is " << maxDelta
+                         << ", smallest trust is " << smallestTrust
+                         << ", smallest gap is " << smallestGap
+                         << ", smallest nonlinear gap is " << smallestNonLinearGap
+                         << std::endl;
+               if (iPass > 200) {
+                    //double useObjValue = objValue+objectiveOffset2+infPenalty;
+                    if (useObjValue + 1.0e-4 >	lastGoodObjective && iPass > 250) {
+                         std::cout << "Exiting as objective not changing much" << std::endl;
+                         break;
+                    } else if (useObjValue < lastGoodObjective) {
+                         lastGoodObjective = useObjValue;
+                         if (!bestSolution)
+                              bestSolution = new double [numberColumns2];
+                         CoinMemcpyN(solution, numberColumns2, bestSolution);
+                    }
+               }
+               if (maxDelta < deltaTolerance && !increasing && iPass > 100) {
+                    numberZeroPasses++;
+                    if (numberZeroPasses == 3) {
+                         if (tryFix) {
+                              std::cout << "Exiting" << std::endl;
+                              break;
+                         } else {
+                              tryFix = true;
+                              for (jNon = 0; jNon < numberNonLinearColumns; jNon++)
+                                   trust[jNon] = CoinMax(trust[jNon], 1.0e-1);
+                              numberZeroPasses = 0;
+                         }
+                    }
+               } else {
+                    numberZeroPasses = 0;
+               }
+          }
+          CoinMemcpyN(solution, numberColumns2, saveSolution);
+          CoinMemcpyN(newModel.primalRowSolution(),
+                      numberRows, saveSolution + numberColumns2);
+          CoinMemcpyN(newModel.statusArray(),
+                      numberColumns2 + numberRows,
+                      reinterpret_cast<unsigned char *> (saveStatus));
+
+          targetDrop = infPenalty + infPenalty2;
+          if (iPass) {
+               // get reduced costs
+               const double * pi = newModel.dualRowSolution();
+               newModel.matrix()->transposeTimes(pi,
+                                                 newModel.dualColumnSolution());
+               double * r = newModel.dualColumnSolution();
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++)
+                    r[iColumn] = objective[iColumn] - r[iColumn];
+               for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+                    iColumn = listNonLinearColumn[jNon];
+                    double dj = r[iColumn];
+                    if (dj < -1.0e-6) {
+                         double drop = -dj * (columnUpper[iColumn] - solution[iColumn]);
+                         //double upper = CoinMin(trueUpper[jNon],solution[iColumn]+0.1);
+                         //double drop2 = -dj*(upper-solution[iColumn]);
+#if 0
+                         if (drop > 1.0e8 || drop2 > 100.0 * drop || (drop > 1.0e-2 && iPass > 100))
+                              printf("Big drop %d %g %g %g %g T %g\n",
+                                     iColumn, columnLower[iColumn], solution[iColumn],
+                                     columnUpper[iColumn], dj, trueUpper[jNon]);
+#endif
+                         targetDrop += drop;
+                         if (dj < -1.0e-1 && trust[jNon] < 1.0e-3
+                                   && trueUpper[jNon] - solution[iColumn] > 1.0e-2) {
+                              trust[jNon] *= 1.5;
+                              //printf("Increasing trust on %d to %g\n",
+                              //     iColumn,trust[jNon]);
+                         }
+                    } else if (dj > 1.0e-6) {
+                         double drop = -dj * (columnLower[iColumn] - solution[iColumn]);
+                         //double lower = CoinMax(trueLower[jNon],solution[iColumn]-0.1);
+                         //double drop2 = -dj*(lower-solution[iColumn]);
+#if 0
+                         if (drop > 1.0e8 || drop2 > 100.0 * drop || (drop > 1.0e-2))
+                              printf("Big drop %d %g %g %g %g T %g\n",
+                                     iColumn, columnLower[iColumn], solution[iColumn],
+                                     columnUpper[iColumn], dj, trueLower[jNon]);
+#endif
+                         targetDrop += drop;
+                         if (dj > 1.0e-1 && trust[jNon] < 1.0e-3
+                                   && solution[iColumn] - trueLower[jNon] > 1.0e-2) {
+                              trust[jNon] *= 1.5;
+                              printf("Increasing trust on %d to %g\n",
+                                     iColumn, trust[jNon]);
+                         }
+                    }
+               }
+          }
+          std::cout << "Pass - " << iPass
+                    << ", target drop is " << targetDrop
+                    << std::endl;
+          if (iPass > 1 && targetDrop < 1.0e-5 && zeroTargetDrop)
+               break;
+          if (iPass > 1 && targetDrop < 1.0e-5)
+               zeroTargetDrop = true;
+          else
+               zeroTargetDrop = false;
+          //if (iPass==5)
+          //newModel.setLogLevel(63);
+          lastObjective = objValue;
+          // take out when ClpPackedMatrix changed
+          //newModel.scaling(false);
+#if 0
+          CoinMpsIO writer;
+          writer.setMpsData(*newModel.matrix(), COIN_DBL_MAX,
+                            newModel.getColLower(), newModel.getColUpper(),
+                            newModel.getObjCoefficients(),
+                            (const char*) 0 /*integrality*/,
+                            newModel.getRowLower(), newModel.getRowUpper(),
+                            NULL, NULL);
+          writer.writeMps("xx.mps");
+#endif
+     }
+     delete [] saveSolution;
+     delete [] saveStatus;
+     for (iPass = 0; iPass < 3; iPass++)
+          delete [] last[iPass];
+     for (jNon = 0; jNon < numberNonLinearColumns; jNon++) {
+          iColumn = listNonLinearColumn[jNon];
+          columnLower[iColumn] = trueLower[jNon];
+          columnUpper[iColumn] = trueUpper[jNon];
+     }
+     delete [] trust;
+     delete [] trueUpper;
+     delete [] trueLower;
+     objectiveValue_ = newModel.objectiveValue();
+     if (bestSolution) {
+          CoinMemcpyN(bestSolution, numberColumns2, solution);
+          delete [] bestSolution;
+          printf("restoring objective of %g\n", lastGoodObjective);
+          objectiveValue_ = lastGoodObjective;
+     }
+     // Simplest way to get true row activity ?
+     double * rowActivity = newModel.primalRowSolution();
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          double difference;
+          if (fabs(rowLower_[iRow]) < fabs(rowUpper_[iRow]))
+               difference = rowLower_[iRow] - rowLower[iRow];
+          else
+               difference = rowUpper_[iRow] - rowUpper[iRow];
+          rowLower[iRow] = rowLower_[iRow];
+          rowUpper[iRow] = rowUpper_[iRow];
+          if (difference) {
+               if (numberRows < 50)
+                    printf("For row %d activity changes from %g to %g\n",
+                           iRow, rowActivity[iRow], rowActivity[iRow] + difference);
+               rowActivity[iRow] += difference;
+          }
+     }
+     delete [] listNonLinearColumn;
+     delete [] gradient;
+     printf("solution still in newModel - do objective etc!\n");
+     numberIterations_ = newModel.numberIterations();
+     problemStatus_ = newModel.problemStatus();
+     secondaryStatus_ = newModel.secondaryStatus();
+     CoinMemcpyN(newModel.primalColumnSolution(), numberColumns_, columnActivity_);
+     // should do status region
+     CoinZeroN(rowActivity_, numberRows_);
+     matrix_->times(1.0, columnActivity_, rowActivity_);
+     return 0;
+}
diff --git a/cbits/coin/ClpSimplexNonlinear.hpp b/cbits/coin/ClpSimplexNonlinear.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplexNonlinear.hpp
@@ -0,0 +1,115 @@
+/* $Id: ClpSimplexNonlinear.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef ClpSimplexNonlinear_H
+#define ClpSimplexNonlinear_H
+
+class ClpNonlinearInfo;
+class ClpQuadraticObjective;
+class ClpConstraint;
+
+#include "ClpSimplexPrimal.hpp"
+
+/** This solves non-linear LPs using the primal simplex method
+
+    It inherits from ClpSimplexPrimal.  It has no data of its own and
+    is never created - only cast from a ClpSimplexPrimal object at algorithm time.
+    If needed create new class and pass around
+
+*/
+
+class ClpSimplexNonlinear : public ClpSimplexPrimal {
+
+public:
+
+     /**@name Description of algorithm */
+     //@{
+     /** Primal algorithms for reduced gradient
+         At present we have two algorithms:
+
+     */
+     /// A reduced gradient method.
+     int primal();
+     /** Primal algorithm for quadratic
+         Using a semi-trust region approach as for pooling problem
+         This is in because I have it lying around
+
+     */
+     int primalSLP(int numberPasses, double deltaTolerance);
+     /** Primal algorithm for nonlinear constraints
+         Using a semi-trust region approach as for pooling problem
+         This is in because I have it lying around
+
+     */
+     int primalSLP(int numberConstraints, ClpConstraint ** constraints,
+                   int numberPasses, double deltaTolerance);
+
+     /** Creates direction vector.  note longArray is long enough
+         for rows and columns.  If numberNonBasic 0 then is updated
+         otherwise mode is ignored and those are used.
+         Norms are only for those > 1.0e3*dualTolerance
+         If mode is nonzero then just largest dj */
+     void directionVector (CoinIndexedVector * longArray,
+                           CoinIndexedVector * spare1, CoinIndexedVector * spare2,
+                           int mode,
+                           double & normFlagged, double & normUnflagged,
+                           int & numberNonBasic);
+     /// Main part.
+     int whileIterating (int & pivotMode);
+     /**
+         longArray has direction
+         pivotMode -
+               0 - use all dual infeasible variables
+           1 - largest dj
+           while >= 10 trying startup phase
+         Returns 0 - can do normal iteration (basis change)
+         1 - no basis change
+         2 - if wants singleton
+         3 - if time to re-factorize
+         If sequenceIn_ >=0 then that will be incoming variable
+     */
+     int pivotColumn(CoinIndexedVector * longArray,
+                     CoinIndexedVector * rowArray,
+                     CoinIndexedVector * columnArray,
+                     CoinIndexedVector * spare,
+                     int & pivotMode,
+                     double & solutionError,
+                     double * array1);
+     /**  Refactorizes if necessary
+          Checks if finished.  Updates status.
+          lastCleaned refers to iteration at which some objective/feasibility
+          cleaning too place.
+
+          type - 0 initial so set up save arrays etc
+               - 1 normal -if good update save
+           - 2 restoring from saved
+     */
+     void statusOfProblemInPrimal(int & lastCleaned, int type,
+                                  ClpSimplexProgress * progress,
+                                  bool doFactorization,
+                                  double & bestObjectiveWhenFlagged);
+     /** Do last half of an iteration.
+         Return codes
+         Reasons to come out normal mode
+         -1 normal
+         -2 factorize now - good iteration
+         -3 slight inaccuracy - refactorize - iteration done
+         -4 inaccuracy - refactorize - no iteration
+         -5 something flagged - go round again
+         +2 looks unbounded
+         +3 max iterations (iteration done)
+
+     */
+     int pivotNonlinearResult();
+     //@}
+
+};
+#endif
+
diff --git a/cbits/coin/ClpSimplexOther.cpp b/cbits/coin/ClpSimplexOther.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplexOther.cpp
@@ -0,0 +1,10445 @@
+/* $Id: ClpSimplexOther.cpp 1931 2013-04-06 20:44:29Z stefan $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include <math.h>
+
+#include "CoinHelperFunctions.hpp"
+#include "ClpSimplexOther.hpp"
+#include "ClpSimplexDual.hpp"
+#include "ClpSimplexPrimal.hpp"
+#include "ClpEventHandler.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpDualRowDantzig.hpp"
+#include "ClpNonLinearCost.hpp"
+#include "ClpDynamicMatrix.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinBuild.hpp"
+#include "CoinMpsIO.hpp"
+#include "CoinFloatEqual.hpp"
+#include "ClpMessage.hpp"
+#include <cfloat>
+#include <cassert>
+#include <string>
+#include <stdio.h>
+#include <iostream>
+#ifdef INT_IS_8
+#define COIN_ANY_BITS_PER_INT 64
+#define COIN_ANY_SHIFT_PER_INT 6
+#define COIN_ANY_MASK_PER_INT 0x3f
+#else
+#define COIN_ANY_BITS_PER_INT 32
+#define COIN_ANY_SHIFT_PER_INT 5
+#define COIN_ANY_MASK_PER_INT 0x1f
+#endif
+/* Dual ranging.
+   This computes increase/decrease in cost for each given variable and corresponding
+   sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
+   and numberColumns.. for artificials/slacks.
+   For non-basic variables the sequence number will be that of the non-basic variables.
+
+   Up to user to provide correct length arrays.
+
+*/
+void ClpSimplexOther::dualRanging(int numberCheck, const int * which,
+                                  double * costIncreased, int * sequenceIncreased,
+                                  double * costDecreased, int * sequenceDecreased,
+                                  double * valueIncrease, double * valueDecrease)
+{
+     rowArray_[1]->clear();
+     columnArray_[1]->clear();
+     // long enough for rows+columns
+     assert(rowArray_[3]->capacity() >= numberRows_ + numberColumns_);
+     rowArray_[3]->clear();
+     int * backPivot = rowArray_[3]->getIndices();
+     int i;
+     for ( i = 0; i < numberRows_ + numberColumns_; i++) {
+          backPivot[i] = -1;
+     }
+     for (i = 0; i < numberRows_; i++) {
+          int iSequence = pivotVariable_[i];
+          backPivot[iSequence] = i;
+     }
+     // dualTolerance may be zero if from CBC.  In fact use that fact
+     bool inCBC = !dualTolerance_;
+     if (inCBC)
+          assert (integerType_);
+     dualTolerance_ = dblParam_[ClpDualTolerance];
+     double * arrayX = rowArray_[0]->denseVector();
+     for ( i = 0; i < numberCheck; i++) {
+          rowArray_[0]->clear();
+          //rowArray_[0]->checkClear();
+          //rowArray_[1]->checkClear();
+          //columnArray_[1]->checkClear();
+          columnArray_[0]->clear();
+          //columnArray_[0]->checkClear();
+          int iSequence = which[i];
+          if (iSequence < 0) {
+               costIncreased[i] = 0.0;
+               sequenceIncreased[i] = -1;
+               costDecreased[i] = 0.0;
+               sequenceDecreased[i] = -1;
+               continue;
+          }
+          double costIncrease = COIN_DBL_MAX;
+          double costDecrease = COIN_DBL_MAX;
+          int sequenceIncrease = -1;
+          int sequenceDecrease = -1;
+          if (valueIncrease) {
+               assert (valueDecrease);
+               valueIncrease[i] = iSequence < numberColumns_ ? columnActivity_[iSequence] : rowActivity_[iSequence-numberColumns_];
+               valueDecrease[i] = valueIncrease[i];
+          }
+
+          switch(getStatus(iSequence)) {
+
+          case basic: {
+               // non-trvial
+               // Get pivot row
+               int iRow = backPivot[iSequence];
+               assert (iRow >= 0);
+#ifndef COIN_FAC_NEW
+               double plusOne = 1.0;
+               rowArray_[0]->createPacked(1, &iRow, &plusOne);
+#else
+               rowArray_[0]->createOneUnpackedElement( iRow, 1.0);
+#endif
+               factorization_->updateColumnTranspose(rowArray_[1], rowArray_[0]);
+               // put row of tableau in rowArray[0] and columnArray[0]
+               matrix_->transposeTimes(this, -1.0,
+                                       rowArray_[0], columnArray_[1], columnArray_[0]);
+#ifdef COIN_FAC_NEW
+	       assert (!rowArray_[0]->packedMode());
+#endif
+               double alphaIncrease;
+               double alphaDecrease;
+               // do ratio test up and down
+               checkDualRatios(rowArray_[0], columnArray_[0], costIncrease, sequenceIncrease, alphaIncrease,
+                               costDecrease, sequenceDecrease, alphaDecrease);
+               if (!inCBC) {
+                    if (valueIncrease) {
+                         if (sequenceIncrease >= 0)
+                              valueIncrease[i] = primalRanging1(sequenceIncrease, iSequence);
+                         if (sequenceDecrease >= 0)
+                              valueDecrease[i] = primalRanging1(sequenceDecrease, iSequence);
+                    }
+               } else {
+                    int number = rowArray_[0]->getNumElements();
+#ifdef COIN_FAC_NEW
+		    const int * index = rowArray_[0]->getIndices();
+#endif
+                    double scale2 = 0.0;
+                    int j;
+                    for (j = 0; j < number; j++) {
+#ifndef COIN_FAC_NEW
+                         scale2 += arrayX[j] * arrayX[j];
+#else
+			 int iRow=index[j];
+                         scale2 += arrayX[iRow] * arrayX[iRow];
+#endif
+                    }
+                    scale2 = 1.0 / sqrt(scale2);
+                    //valueIncrease[i] = scale2;
+                    if (sequenceIncrease >= 0) {
+                         double djValue = dj_[sequenceIncrease];
+                         if (fabs(djValue) > 10.0 * dualTolerance_) {
+                              // we are going to use for cutoff so be exact
+                              costIncrease = fabs(djValue / alphaIncrease);
+                              /* Not sure this is good idea as I don't think correct e.g.
+                                 suppose a continuous variable has dj slightly greater. */
+                              if(false && sequenceIncrease < numberColumns_ && integerType_[sequenceIncrease]) {
+                                   // can improve
+                                   double movement = (columnScale_ == NULL) ? 1.0 :
+                                                     rhsScale_ * inverseColumnScale_[sequenceIncrease];
+                                   costIncrease = CoinMax(fabs(djValue * movement), costIncrease);
+                              }
+                         } else {
+                              costIncrease = 0.0;
+                         }
+                    }
+                    if (sequenceDecrease >= 0) {
+                         double djValue = dj_[sequenceDecrease];
+                         if (fabs(djValue) > 10.0 * dualTolerance_) {
+                              // we are going to use for cutoff so be exact
+                              costDecrease = fabs(djValue / alphaDecrease);
+                              if(sequenceDecrease < numberColumns_ && integerType_[sequenceDecrease]) {
+                                   // can improve
+                                   double movement = (columnScale_ == NULL) ? 1.0 :
+                                                     rhsScale_ * inverseColumnScale_[sequenceDecrease];
+                                   costDecrease = CoinMax(fabs(djValue * movement), costDecrease);
+                              }
+                         } else {
+                              costDecrease = 0.0;
+                         }
+                    }
+                    costIncrease *= scale2;
+                    costDecrease *= scale2;
+               }
+          }
+          break;
+          case isFixed:
+               break;
+          case isFree:
+          case superBasic:
+               costIncrease = 0.0;
+               costDecrease = 0.0;
+               sequenceIncrease = iSequence;
+               sequenceDecrease = iSequence;
+               break;
+          case atUpperBound:
+               costIncrease = CoinMax(0.0, -dj_[iSequence]);
+               sequenceIncrease = iSequence;
+               if (valueIncrease)
+                    valueIncrease[i] = primalRanging1(iSequence, iSequence);
+               break;
+          case atLowerBound:
+               costDecrease = CoinMax(0.0, dj_[iSequence]);
+               sequenceDecrease = iSequence;
+               if (valueIncrease)
+                    valueDecrease[i] = primalRanging1(iSequence, iSequence);
+               break;
+          }
+          double scaleFactor;
+          if (rowScale_) {
+               if (iSequence < numberColumns_)
+                    scaleFactor = 1.0 / (objectiveScale_ * columnScale_[iSequence]);
+               else
+                    scaleFactor = rowScale_[iSequence-numberColumns_] / objectiveScale_;
+          } else {
+               scaleFactor = 1.0 / objectiveScale_;
+          }
+          if (costIncrease < 1.0e30)
+               costIncrease *= scaleFactor;
+          if (costDecrease < 1.0e30)
+               costDecrease *= scaleFactor;
+          if (optimizationDirection_ == 1.0) {
+               costIncreased[i] = costIncrease;
+               sequenceIncreased[i] = sequenceIncrease;
+               costDecreased[i] = costDecrease;
+               sequenceDecreased[i] = sequenceDecrease;
+          } else if (optimizationDirection_ == -1.0) {
+               costIncreased[i] = costDecrease;
+               sequenceIncreased[i] = sequenceDecrease;
+               costDecreased[i] = costIncrease;
+               sequenceDecreased[i] = sequenceIncrease;
+               if (valueIncrease) {
+                    double temp = valueIncrease[i];
+                    valueIncrease[i] = valueDecrease[i];
+                    valueDecrease[i] = temp;
+               }
+          } else if (optimizationDirection_ == 0.0) {
+               // !!!!!! ???
+               costIncreased[i] = COIN_DBL_MAX;
+               sequenceIncreased[i] = -1;
+               costDecreased[i] = COIN_DBL_MAX;
+               sequenceDecreased[i] = -1;
+          } else {
+               abort();
+          }
+     }
+     rowArray_[0]->clear();
+     //rowArray_[1]->clear();
+     //columnArray_[1]->clear();
+     columnArray_[0]->clear();
+     //rowArray_[3]->clear();
+     if (!optimizationDirection_)
+          printf("*** ????? Ranging with zero optimization costs\n");
+}
+/*
+   Row array has row part of pivot row
+   Column array has column part.
+   This is used in dual ranging
+*/
+void
+ClpSimplexOther::checkDualRatios(CoinIndexedVector * rowArray,
+                                 CoinIndexedVector * columnArray,
+                                 double & costIncrease, int & sequenceIncrease, double & alphaIncrease,
+                                 double & costDecrease, int & sequenceDecrease, double & alphaDecrease)
+{
+     double acceptablePivot = 1.0e-9;
+     double * work;
+     int number;
+     int * which;
+     int iSection;
+
+     double thetaDown = 1.0e31;
+     double thetaUp = 1.0e31;
+     int sequenceDown = -1;
+     int sequenceUp = -1;
+     double alphaDown = 0.0;
+     double alphaUp = 0.0;
+
+     int addSequence;
+
+     for (iSection = 0; iSection < 2; iSection++) {
+
+          int i;
+          if (!iSection) {
+               work = rowArray->denseVector();
+               number = rowArray->getNumElements();
+               which = rowArray->getIndices();
+               addSequence = numberColumns_;
+          } else {
+               work = columnArray->denseVector();
+               number = columnArray->getNumElements();
+               which = columnArray->getIndices();
+               addSequence = 0;
+          }
+
+          for (i = 0; i < number; i++) {
+               int iSequence = which[i];
+               int iSequence2 = iSequence + addSequence;
+#ifndef COIN_FAC_NEW
+               double alpha = work[i];
+#else
+               double alpha = !addSequence ? work[i] : work[iSequence];
+#endif
+               if (fabs(alpha) < acceptablePivot)
+                    continue;
+               double oldValue = dj_[iSequence2];
+
+               switch(getStatus(iSequence2)) {
+
+               case basic:
+                    break;
+               case ClpSimplex::isFixed:
+                    break;
+               case isFree:
+               case superBasic:
+                    // treat dj as if zero
+                    thetaDown = 0.0;
+                    thetaUp = 0.0;
+                    sequenceDown = iSequence2;
+                    sequenceUp = iSequence2;
+                    break;
+               case atUpperBound:
+                    if (alpha > 0.0) {
+                         // test up
+                         if (oldValue + thetaUp * alpha > dualTolerance_) {
+                              thetaUp = (dualTolerance_ - oldValue) / alpha;
+                              sequenceUp = iSequence2;
+                              alphaUp = alpha;
+                         }
+                    } else {
+                         // test down
+                         if (oldValue - thetaDown * alpha > dualTolerance_) {
+                              thetaDown = -(dualTolerance_ - oldValue) / alpha;
+                              sequenceDown = iSequence2;
+                              alphaDown = alpha;
+                         }
+                    }
+                    break;
+               case atLowerBound:
+                    if (alpha < 0.0) {
+                         // test up
+                         if (oldValue + thetaUp * alpha < - dualTolerance_) {
+                              thetaUp = -(dualTolerance_ + oldValue) / alpha;
+                              sequenceUp = iSequence2;
+                              alphaUp = alpha;
+                         }
+                    } else {
+                         // test down
+                         if (oldValue - thetaDown * alpha < -dualTolerance_) {
+                              thetaDown = (dualTolerance_ + oldValue) / alpha;
+                              sequenceDown = iSequence2;
+                              alphaDown = alpha;
+                         }
+                    }
+                    break;
+               }
+          }
+     }
+     if (sequenceUp >= 0) {
+          costIncrease = thetaUp;
+          sequenceIncrease = sequenceUp;
+          alphaIncrease = alphaUp;
+     }
+     if (sequenceDown >= 0) {
+          costDecrease = thetaDown;
+          sequenceDecrease = sequenceDown;
+          alphaDecrease = alphaDown;
+     }
+}
+/** Primal ranging.
+    This computes increase/decrease in value for each given variable and corresponding
+    sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
+    and numberColumns.. for artificials/slacks.
+    For basic variables the sequence number will be that of the basic variables.
+
+    Up to user to provide correct length arrays.
+
+    When here - guaranteed optimal
+*/
+void
+ClpSimplexOther::primalRanging(int numberCheck, const int * which,
+                               double * valueIncreased, int * sequenceIncreased,
+                               double * valueDecreased, int * sequenceDecreased)
+{
+     rowArray_[0]->clear();
+     rowArray_[1]->clear();
+     lowerIn_ = -COIN_DBL_MAX;
+     upperIn_ = COIN_DBL_MAX;
+     valueIn_ = 0.0;
+     for ( int i = 0; i < numberCheck; i++) {
+          int iSequence = which[i];
+          double valueIncrease = COIN_DBL_MAX;
+          double valueDecrease = COIN_DBL_MAX;
+          int sequenceIncrease = -1;
+          int sequenceDecrease = -1;
+
+          switch(getStatus(iSequence)) {
+
+          case basic:
+          case isFree:
+          case superBasic:
+               // Easy
+               valueDecrease = CoinMax(0.0, upper_[iSequence] - solution_[iSequence]);
+               valueIncrease = CoinMax(0.0, solution_[iSequence] - lower_[iSequence]);
+               sequenceDecrease = iSequence;
+               sequenceIncrease = iSequence;
+               break;
+          case isFixed:
+          case atUpperBound:
+          case atLowerBound: {
+               // Non trivial
+               // Other bound is ignored
+#ifndef COIN_FAC_NEW
+               unpackPacked(rowArray_[1], iSequence);
+#else
+               unpack(rowArray_[1], iSequence);
+#endif
+               factorization_->updateColumn(rowArray_[2], rowArray_[1]);
+               // Get extra rows
+               matrix_->extendUpdated(this, rowArray_[1], 0);
+               // do ratio test
+               checkPrimalRatios(rowArray_[1], 1);
+               if (pivotRow_ >= 0) {
+                    valueIncrease = theta_;
+                    sequenceIncrease = pivotVariable_[pivotRow_];
+               }
+               checkPrimalRatios(rowArray_[1], -1);
+               if (pivotRow_ >= 0) {
+                    valueDecrease = theta_;
+                    sequenceDecrease = pivotVariable_[pivotRow_];
+               }
+               rowArray_[1]->clear();
+          }
+          break;
+          }
+          double scaleFactor;
+          if (rowScale_) {
+               if (iSequence < numberColumns_)
+                    scaleFactor = columnScale_[iSequence] / rhsScale_;
+               else
+                    scaleFactor = 1.0 / (rowScale_[iSequence-numberColumns_] * rhsScale_);
+          } else {
+               scaleFactor = 1.0 / rhsScale_;
+          }
+          if (valueIncrease < 1.0e30)
+               valueIncrease *= scaleFactor;
+          else
+               valueIncrease = COIN_DBL_MAX;
+          if (valueDecrease < 1.0e30)
+               valueDecrease *= scaleFactor;
+          else
+               valueDecrease = COIN_DBL_MAX;
+          valueIncreased[i] = valueIncrease;
+          sequenceIncreased[i] = sequenceIncrease;
+          valueDecreased[i] = valueDecrease;
+          sequenceDecreased[i] = sequenceDecrease;
+     }
+}
+// Returns new value of whichOther when whichIn enters basis
+double
+ClpSimplexOther::primalRanging1(int whichIn, int whichOther)
+{
+     rowArray_[0]->clear();
+     rowArray_[1]->clear();
+     int iSequence = whichIn;
+     double newValue = solution_[whichOther];
+     double alphaOther = 0.0;
+     Status status = getStatus(iSequence);
+     assert (status == atLowerBound || status == atUpperBound);
+     int wayIn = (status == atLowerBound) ? 1 : -1;
+
+     switch(getStatus(iSequence)) {
+
+     case basic:
+     case isFree:
+     case superBasic:
+          assert (whichIn == whichOther);
+          // Easy
+          newValue = wayIn > 0 ? upper_[iSequence] : lower_[iSequence];
+          break;
+     case isFixed:
+     case atUpperBound:
+     case atLowerBound:
+          // Non trivial
+     {
+          // Other bound is ignored
+#ifndef COIN_FAC_NEW
+          unpackPacked(rowArray_[1], iSequence);
+#else
+          unpack(rowArray_[1], iSequence);
+#endif
+          factorization_->updateColumn(rowArray_[2], rowArray_[1]);
+          // Get extra rows
+          matrix_->extendUpdated(this, rowArray_[1], 0);
+          // do ratio test
+          double acceptablePivot = 1.0e-7;
+          double * work = rowArray_[1]->denseVector();
+          int number = rowArray_[1]->getNumElements();
+          int * which = rowArray_[1]->getIndices();
+
+          // we may need to swap sign
+          double way = wayIn;
+          double theta = 1.0e30;
+          for (int iIndex = 0; iIndex < number; iIndex++) {
+
+               int iRow = which[iIndex];
+#ifndef COIN_FAC_NEW
+               double alpha = work[iIndex] * way;
+#else
+               double alpha = work[iRow] * way;
+#endif
+               int iPivot = pivotVariable_[iRow];
+               if (iPivot == whichOther) {
+                    alphaOther = alpha;
+                    continue;
+               }
+               double oldValue = solution_[iPivot];
+               if (fabs(alpha) > acceptablePivot) {
+                    if (alpha > 0.0) {
+                         // basic variable going towards lower bound
+                         double bound = lower_[iPivot];
+                         oldValue -= bound;
+                         if (oldValue - theta * alpha < 0.0) {
+                              theta = CoinMax(0.0, oldValue / alpha);
+                         }
+                    } else {
+                         // basic variable going towards upper bound
+                         double bound = upper_[iPivot];
+                         oldValue = oldValue - bound;
+                         if (oldValue - theta * alpha > 0.0) {
+                              theta = CoinMax(0.0, oldValue / alpha);
+                         }
+                    }
+               }
+          }
+          if (whichIn != whichOther) {
+               if (theta < 1.0e30)
+                    newValue -= theta * alphaOther;
+               else
+                    newValue = alphaOther > 0.0 ? -1.0e30 : 1.0e30;
+          } else {
+               newValue += theta * wayIn;
+          }
+     }
+     rowArray_[1]->clear();
+     break;
+     }
+     double scaleFactor;
+     if (rowScale_) {
+          if (whichOther < numberColumns_)
+               scaleFactor = columnScale_[whichOther] / rhsScale_;
+          else
+               scaleFactor = 1.0 / (rowScale_[whichOther-numberColumns_] * rhsScale_);
+     } else {
+          scaleFactor = 1.0 / rhsScale_;
+     }
+     if (newValue < 1.0e29)
+          if (newValue > -1.0e29)
+               newValue *= scaleFactor;
+          else
+               newValue = -COIN_DBL_MAX;
+     else
+          newValue = COIN_DBL_MAX;
+     return newValue;
+}
+/*
+   Row array has pivot column
+   This is used in primal ranging
+*/
+void
+ClpSimplexOther::checkPrimalRatios(CoinIndexedVector * rowArray,
+                                   int direction)
+{
+     // sequence stays as row number until end
+     pivotRow_ = -1;
+     double acceptablePivot = 1.0e-7;
+     double * work = rowArray->denseVector();
+     int number = rowArray->getNumElements();
+     int * which = rowArray->getIndices();
+
+     // we need to swap sign if going down
+     double way = direction;
+     theta_ = 1.0e30;
+     for (int iIndex = 0; iIndex < number; iIndex++) {
+
+          int iRow = which[iIndex];
+#ifndef COIN_FAC_NEW
+          double alpha = work[iIndex] * way;
+#else
+          double alpha = work[iRow] * way;
+#endif
+          int iPivot = pivotVariable_[iRow];
+          double oldValue = solution_[iPivot];
+          if (fabs(alpha) > acceptablePivot) {
+               if (alpha > 0.0) {
+                    // basic variable going towards lower bound
+                    double bound = lower_[iPivot];
+                    oldValue -= bound;
+                    if (oldValue - theta_ * alpha < 0.0) {
+                         pivotRow_ = iRow;
+                         theta_ = CoinMax(0.0, oldValue / alpha);
+                    }
+               } else {
+                    // basic variable going towards upper bound
+                    double bound = upper_[iPivot];
+                    oldValue = oldValue - bound;
+                    if (oldValue - theta_ * alpha > 0.0) {
+                         pivotRow_ = iRow;
+                         theta_ = CoinMax(0.0, oldValue / alpha);
+                    }
+               }
+          }
+     }
+}
+/* Write the basis in MPS format to the specified file.
+   If writeValues true writes values of structurals
+   (and adds VALUES to end of NAME card)
+
+   Row and column names may be null.
+   formatType is
+   <ul>
+   <li> 0 - normal
+   <li> 1 - extra accuracy
+   <li> 2 - IEEE hex (later)
+   </ul>
+
+   Returns non-zero on I/O error
+
+   This is based on code contributed by Thorsten Koch
+*/
+int
+ClpSimplexOther::writeBasis(const char *filename,
+                            bool writeValues,
+                            int formatType) const
+{
+     formatType = CoinMax(0, formatType);
+     formatType = CoinMin(2, formatType);
+     if (!writeValues)
+          formatType = 0;
+     // See if INTEL if IEEE
+     if (formatType == 2) {
+          // test intel here and add 1 if not intel
+          double value = 1.0;
+          char x[8];
+          memcpy(x, &value, 8);
+          if (x[0] == 63) {
+               formatType ++; // not intel
+          } else {
+               assert (x[0] == 0);
+          }
+     }
+
+     char number[20];
+     FILE * fp = fopen(filename, "w");
+     if (!fp)
+          return -1;
+
+     // NAME card
+
+     if (strcmp(strParam_[ClpProbName].c_str(), "") == 0) {
+          fprintf(fp, "NAME          BLANK      ");
+     } else {
+          fprintf(fp, "NAME          %s       ", strParam_[ClpProbName].c_str());
+     }
+     if (formatType >= 2)
+          fprintf(fp, "FREEIEEE");
+     else if (writeValues)
+          fprintf(fp, "VALUES");
+     // finish off name
+     fprintf(fp, "\n");
+     int iRow = 0;
+     for(int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          bool printit = false;
+          if( getColumnStatus(iColumn) == ClpSimplex::basic) {
+               printit = true;
+               // Find non basic row
+               for(; iRow < numberRows_; iRow++) {
+                    if (getRowStatus(iRow) != ClpSimplex::basic)
+                         break;
+               }
+               if (lengthNames_) {
+                    if (iRow != numberRows_) {
+                         fprintf(fp, " %s %-8s       %s",
+                                 getRowStatus(iRow) == ClpSimplex::atUpperBound ? "XU" : "XL",
+                                 columnNames_[iColumn].c_str(),
+                                 rowNames_[iRow].c_str());
+                         iRow++;
+                    } else {
+                         // Allow for too many basics!
+                         fprintf(fp, " BS %-8s       ",
+                                 columnNames_[iColumn].c_str());
+                         // Dummy row name if values
+                         if (writeValues)
+                              fprintf(fp, "      _dummy_");
+                    }
+               } else {
+                    // no names
+                    if (iRow != numberRows_) {
+                         fprintf(fp, " %s C%7.7d     R%7.7d",
+                                 getRowStatus(iRow) == ClpSimplex::atUpperBound ? "XU" : "XL",
+                                 iColumn, iRow);
+                         iRow++;
+                    } else {
+                         // Allow for too many basics!
+                         fprintf(fp, " BS C%7.7d", iColumn);
+                         // Dummy row name if values
+                         if (writeValues)
+                              fprintf(fp, "      _dummy_");
+                    }
+               }
+          } else  {
+               if( getColumnStatus(iColumn) == ClpSimplex::atUpperBound) {
+                    printit = true;
+                    if (lengthNames_)
+                         fprintf(fp, " UL %s", columnNames_[iColumn].c_str());
+                    else
+                         fprintf(fp, " UL C%7.7d", iColumn);
+                    // Dummy row name if values
+                    if (writeValues)
+                         fprintf(fp, "      _dummy_");
+               }
+          }
+          if (printit && writeValues) {
+               // add value
+               CoinConvertDouble(0, formatType, columnActivity_[iColumn], number);
+               fprintf(fp, "     %s", number);
+          }
+          if (printit)
+               fprintf(fp, "\n");
+     }
+     fprintf(fp, "ENDATA\n");
+     fclose(fp);
+     return 0;
+}
+// Read a basis from the given filename
+int
+ClpSimplexOther::readBasis(const char *fileName)
+{
+     int status = 0;
+     if (strcmp(fileName, "-") != 0 && strcmp(fileName, "stdin") != 0) {
+          FILE *fp = fopen(fileName, "r");
+          if (fp) {
+               // can open - lets go for it
+               fclose(fp);
+          } else {
+               handler_->message(CLP_UNABLE_OPEN, messages_)
+                         << fileName << CoinMessageEol;
+               return -1;
+          }
+     }
+     CoinMpsIO m;
+     m.passInMessageHandler(handler_);
+     *m.messagesPointer() = coinMessages();
+     bool savePrefix = m.messageHandler()->prefix();
+     m.messageHandler()->setPrefix(handler_->prefix());
+     status = m.readBasis(fileName, "", columnActivity_, status_ + numberColumns_,
+                          status_,
+                          columnNames_, numberColumns_,
+                          rowNames_, numberRows_);
+     m.messageHandler()->setPrefix(savePrefix);
+     if (status >= 0) {
+          if (!status) {
+               // set values
+               int iColumn, iRow;
+               for (iRow = 0; iRow < numberRows_; iRow++) {
+                    if (getRowStatus(iRow) == atLowerBound)
+                         rowActivity_[iRow] = rowLower_[iRow];
+                    else if (getRowStatus(iRow) == atUpperBound)
+                         rowActivity_[iRow] = rowUpper_[iRow];
+               }
+               for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                    if (getColumnStatus(iColumn) == atLowerBound)
+                         columnActivity_[iColumn] = columnLower_[iColumn];
+                    else if (getColumnStatus(iColumn) == atUpperBound)
+                         columnActivity_[iColumn] = columnUpper_[iColumn];
+               }
+          } else {
+               memset(rowActivity_, 0, numberRows_ * sizeof(double));
+               matrix_->times(-1.0, columnActivity_, rowActivity_);
+          }
+     } else {
+          // errors
+          handler_->message(CLP_IMPORT_ERRORS, messages_)
+                    << status << fileName << CoinMessageEol;
+     }
+     return status;
+}
+/* Creates dual of a problem if looks plausible
+   (defaults will always create model)
+   fractionRowRanges is fraction of rows allowed to have ranges
+   fractionColumnRanges is fraction of columns allowed to have ranges
+*/
+ClpSimplex *
+ClpSimplexOther::dualOfModel(double fractionRowRanges, double fractionColumnRanges) const
+{
+     const ClpSimplex * model2 = static_cast<const ClpSimplex *> (this);
+     bool changed = false;
+     int numberChanged = 0;
+     int numberFreeColumnsInPrimal=0;
+     int iColumn;
+     // check if we need to change bounds to rows
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+       if (columnUpper_[iColumn] < 1.0e20) {
+	 if (columnLower_[iColumn] > -1.0e20) {
+               changed = true;
+               numberChanged++;
+          }
+       } else if (columnLower_[iColumn] < -1.0e20) {
+	 numberFreeColumnsInPrimal++;
+       }
+     }
+     int iRow;
+     int numberExtraRows = 0;
+     int numberFreeColumnsInDual=0;
+     if (numberChanged <= fractionColumnRanges * numberColumns_) {
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               if (rowLower_[iRow] > -1.0e20 &&
+                         rowUpper_[iRow] < 1.0e20) {
+                    if (rowUpper_[iRow] != rowLower_[iRow])
+                         numberExtraRows++;
+		    else
+		      numberFreeColumnsInDual++;
+               }
+          }
+          if (numberExtraRows > fractionRowRanges * numberRows_)
+               return NULL;
+     } else {
+          return NULL;
+     }
+     printf("would have %d free columns in primal, %d in dual\n",
+	    numberFreeColumnsInPrimal,numberFreeColumnsInDual);
+     if (4*(numberFreeColumnsInDual-numberFreeColumnsInPrimal)>
+	 numberColumns_&&fractionRowRanges<1.0)
+       return NULL; //dangerous (well anyway in dual)
+     if (changed) {
+          ClpSimplex * model3 = new ClpSimplex(*model2);
+          CoinBuild build;
+          double one = 1.0;
+          int numberColumns = model3->numberColumns();
+          const double * columnLower = model3->columnLower();
+          const double * columnUpper = model3->columnUpper();
+          for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+               if (columnUpper[iColumn] < 1.0e20 &&
+                         columnLower[iColumn] > -1.0e20) {
+                    if (fabs(columnLower[iColumn]) < fabs(columnUpper[iColumn])) {
+                         double value = columnUpper[iColumn];
+                         model3->setColumnUpper(iColumn, COIN_DBL_MAX);
+                         build.addRow(1, &iColumn, &one, -COIN_DBL_MAX, value);
+                    } else {
+                         double value = columnLower[iColumn];
+                         model3->setColumnLower(iColumn, -COIN_DBL_MAX);
+                         build.addRow(1, &iColumn, &one, value, COIN_DBL_MAX);
+                    }
+               }
+          }
+          model3->addRows(build);
+          model2 = model3;
+     }
+     int numberColumns = model2->numberColumns();
+     const double * columnLower = model2->columnLower();
+     const double * columnUpper = model2->columnUpper();
+     int numberRows = model2->numberRows();
+     double * rowLower = CoinCopyOfArray(model2->rowLower(), numberRows);
+     double * rowUpper = CoinCopyOfArray(model2->rowUpper(), numberRows);
+
+     const double * objective = model2->objective();
+     CoinPackedMatrix * matrix = model2->matrix();
+     // get transpose
+     CoinPackedMatrix rowCopy = *matrix;
+     const int * row = matrix->getIndices();
+     const int * columnLength = matrix->getVectorLengths();
+     const CoinBigIndex * columnStart = matrix->getVectorStarts();
+     const double * elementByColumn = matrix->getElements();
+     double objOffset = 0.0;
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          double offset = 0.0;
+          double objValue = optimizationDirection_ * objective[iColumn];
+          if (columnUpper[iColumn] > 1.0e20) {
+               if (columnLower[iColumn] > -1.0e20)
+                    offset = columnLower[iColumn];
+          } else if (columnLower[iColumn] < -1.0e20) {
+               offset = columnUpper[iColumn];
+          } else {
+               // taken care of before
+               abort();
+          }
+          if (offset) {
+               objOffset += offset * objValue;
+               for (CoinBigIndex j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    if (rowLower[iRow] > -1.0e20)
+                         rowLower[iRow] -= offset * elementByColumn[j];
+                    if (rowUpper[iRow] < 1.0e20)
+                         rowUpper[iRow] -= offset * elementByColumn[j];
+               }
+          }
+     }
+     int * which = new int[numberRows+numberExtraRows];
+     rowCopy.reverseOrdering();
+     rowCopy.transpose();
+     double * fromRowsLower = new double[numberRows+numberExtraRows];
+     double * fromRowsUpper = new double[numberRows+numberExtraRows];
+     double * newObjective = new double[numberRows+numberExtraRows];
+     double * fromColumnsLower = new double[numberColumns];
+     double * fromColumnsUpper = new double[numberColumns];
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          double objValue = optimizationDirection_ * objective[iColumn];
+          // Offset is already in
+          if (columnUpper[iColumn] > 1.0e20) {
+               if (columnLower[iColumn] > -1.0e20) {
+                    fromColumnsLower[iColumn] = -COIN_DBL_MAX;
+                    fromColumnsUpper[iColumn] = objValue;
+               } else {
+                    // free
+                    fromColumnsLower[iColumn] = objValue;
+                    fromColumnsUpper[iColumn] = objValue;
+               }
+          } else if (columnLower[iColumn] < -1.0e20) {
+               fromColumnsLower[iColumn] = objValue;
+               fromColumnsUpper[iColumn] = COIN_DBL_MAX;
+          } else {
+               abort();
+          }
+     }
+     int kRow = 0;
+     int kExtraRow = numberRows;
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          if (rowLower[iRow] < -1.0e20) {
+               assert (rowUpper[iRow] < 1.0e20);
+               newObjective[kRow] = -rowUpper[iRow];
+               fromRowsLower[kRow] = -COIN_DBL_MAX;
+               fromRowsUpper[kRow] = 0.0;
+               which[kRow] = iRow;
+               kRow++;
+          } else if (rowUpper[iRow] > 1.0e20) {
+               newObjective[kRow] = -rowLower[iRow];
+               fromRowsLower[kRow] = 0.0;
+               fromRowsUpper[kRow] = COIN_DBL_MAX;
+               which[kRow] = iRow;
+               kRow++;
+          } else {
+               if (rowUpper[iRow] == rowLower[iRow]) {
+                    newObjective[kRow] = -rowLower[iRow];
+                    fromRowsLower[kRow] = -COIN_DBL_MAX;;
+                    fromRowsUpper[kRow] = COIN_DBL_MAX;
+                    which[kRow] = iRow;
+                    kRow++;
+               } else {
+                    // range
+                    newObjective[kRow] = -rowUpper[iRow];
+                    fromRowsLower[kRow] = -COIN_DBL_MAX;
+                    fromRowsUpper[kRow] = 0.0;
+                    which[kRow] = iRow;
+                    kRow++;
+                    newObjective[kExtraRow] = -rowLower[iRow];
+                    fromRowsLower[kExtraRow] = 0.0;
+                    fromRowsUpper[kExtraRow] = COIN_DBL_MAX;
+                    which[kExtraRow] = iRow;
+                    kExtraRow++;
+               }
+          }
+     }
+     if (numberExtraRows) {
+          CoinPackedMatrix newCopy;
+          newCopy.setExtraGap(0.0);
+          newCopy.setExtraMajor(0.0);
+          newCopy.submatrixOfWithDuplicates(rowCopy, kExtraRow, which);
+          rowCopy = newCopy;
+     }
+     ClpSimplex * modelDual = new ClpSimplex();
+     modelDual->loadProblem(rowCopy, fromRowsLower, fromRowsUpper, newObjective,
+                            fromColumnsLower, fromColumnsUpper);
+     modelDual->setObjectiveOffset(objOffset);
+     modelDual->setDualBound(model2->dualBound());
+     modelDual->setInfeasibilityCost(model2->infeasibilityCost());
+     modelDual->setDualTolerance(model2->dualTolerance());
+     modelDual->setPrimalTolerance(model2->primalTolerance());
+     modelDual->setPerturbation(model2->perturbation());
+     modelDual->setSpecialOptions(model2->specialOptions());
+     modelDual->setMoreSpecialOptions(model2->moreSpecialOptions());
+     modelDual->setMaximumIterations(model2->maximumIterations());
+     modelDual->setFactorizationFrequency(model2->factorizationFrequency());
+     modelDual->setLogLevel(model2->logLevel());
+     delete [] fromRowsLower;
+     delete [] fromRowsUpper;
+     delete [] fromColumnsLower;
+     delete [] fromColumnsUpper;
+     delete [] newObjective;
+     delete [] which;
+     delete [] rowLower;
+     delete [] rowUpper;
+     if (changed)
+          delete model2;
+     modelDual->createStatus();
+     return modelDual;
+}
+// Restores solution from dualized problem
+int
+ClpSimplexOther::restoreFromDual(const ClpSimplex * dualProblem,
+				 bool checkAccuracy)
+{
+     int returnCode = 0;;
+     createStatus();
+     // Number of rows in dual problem was original number of columns
+     assert (numberColumns_ == dualProblem->numberRows());
+     // If slack on d-row basic then column at bound otherwise column basic
+     // If d-column basic then rhs tight
+     int numberBasic = 0;
+     int iRow, iColumn = 0;
+     // Get number of extra rows from ranges
+     int numberExtraRows = 0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          if (rowLower_[iRow] > -1.0e20 &&
+                    rowUpper_[iRow] < 1.0e20) {
+               if (rowUpper_[iRow] != rowLower_[iRow])
+                    numberExtraRows++;
+          }
+     }
+     const double * objective = this->objective();
+     const double * dualDual = dualProblem->dualRowSolution();
+     const double * dualDj = dualProblem->dualColumnSolution();
+     const double * dualSol = dualProblem->primalColumnSolution();
+     const double * dualActs = dualProblem->primalRowSolution();
+#if 0
+     ClpSimplex thisCopy = *this;
+     thisCopy.dual(); // for testing
+     const double * primalDual = thisCopy.dualRowSolution();
+     const double * primalDj = thisCopy.dualColumnSolution();
+     const double * primalSol = thisCopy.primalColumnSolution();
+     const double * primalActs = thisCopy.primalRowSolution();
+     char ss[] = {'F', 'B', 'U', 'L', 'S', 'F'};
+     printf ("Dual problem row info %d rows\n", dualProblem->numberRows());
+     for (iRow = 0; iRow < dualProblem->numberRows(); iRow++)
+          printf("%d at %c primal %g dual %g\n",
+                 iRow, ss[dualProblem->getRowStatus(iRow)],
+                 dualActs[iRow], dualDual[iRow]);
+     printf ("Dual problem column info %d columns\n", dualProblem->numberColumns());
+     for (iColumn = 0; iColumn < dualProblem->numberColumns(); iColumn++)
+          printf("%d at %c primal %g dual %g\n",
+                 iColumn, ss[dualProblem->getColumnStatus(iColumn)],
+                 dualSol[iColumn], dualDj[iColumn]);
+     printf ("Primal problem row info %d rows\n", thisCopy.numberRows());
+     for (iRow = 0; iRow < thisCopy.numberRows(); iRow++)
+          printf("%d at %c primal %g dual %g\n",
+                 iRow, ss[thisCopy.getRowStatus(iRow)],
+                 primalActs[iRow], primalDual[iRow]);
+     printf ("Primal problem column info %d columns\n", thisCopy.numberColumns());
+     for (iColumn = 0; iColumn < thisCopy.numberColumns(); iColumn++)
+          printf("%d at %c primal %g dual %g\n",
+                 iColumn, ss[thisCopy.getColumnStatus(iColumn)],
+                 primalSol[iColumn], primalDj[iColumn]);
+#endif
+     // position at bound information
+     int jColumn = numberRows_;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          double objValue = optimizationDirection_ * objective[iColumn];
+          Status status = dualProblem->getRowStatus(iColumn);
+          double otherValue = COIN_DBL_MAX;
+          if (columnUpper_[iColumn] < 1.0e20 &&
+                    columnLower_[iColumn] > -1.0e20) {
+               if (fabs(columnLower_[iColumn]) < fabs(columnUpper_[iColumn])) {
+                    otherValue = columnUpper_[iColumn] + dualDj[jColumn];
+               } else {
+                    otherValue = columnLower_[iColumn] + dualDj[jColumn];
+               }
+               jColumn++;
+          }
+          if (status == basic) {
+               // column is at bound
+               if (otherValue == COIN_DBL_MAX) {
+                    reducedCost_[iColumn] = objValue - dualActs[iColumn];
+                    if (columnUpper_[iColumn] > 1.0e20) {
+                         if (columnLower_[iColumn] > -1.0e20) {
+                              if (columnUpper_[iColumn] > columnLower_[iColumn])
+                                   setColumnStatus(iColumn, atLowerBound);
+                              else
+                                   setColumnStatus(iColumn, isFixed);
+                              columnActivity_[iColumn] = columnLower_[iColumn];
+                         } else {
+                              // free
+                              setColumnStatus(iColumn, isFree);
+                              columnActivity_[iColumn] = 0.0;
+                         }
+                    } else {
+                         setColumnStatus(iColumn, atUpperBound);
+                         columnActivity_[iColumn] = columnUpper_[iColumn];
+                    }
+               } else {
+                    reducedCost_[iColumn] = objValue - dualActs[iColumn];
+                    //printf("other dual sol %g\n",otherValue);
+                    if (fabs(otherValue - columnLower_[iColumn]) < 1.0e-5) {
+                         if (columnUpper_[iColumn] > columnLower_[iColumn])
+                              setColumnStatus(iColumn, atLowerBound);
+                         else
+                              setColumnStatus(iColumn, isFixed);
+                         columnActivity_[iColumn] = columnLower_[iColumn];
+                    } else if (fabs(otherValue - columnUpper_[iColumn]) < 1.0e-5) {
+                         if (columnUpper_[iColumn] > columnLower_[iColumn])
+                              setColumnStatus(iColumn, atUpperBound);
+                         else
+                              setColumnStatus(iColumn, isFixed);
+                         columnActivity_[iColumn] = columnUpper_[iColumn];
+                    } else {
+                         abort();
+                    }
+               }
+          } else {
+               if (otherValue == COIN_DBL_MAX) {
+                    // column basic
+                    setColumnStatus(iColumn, basic);
+                    numberBasic++;
+                    if (columnLower_[iColumn] > -1.0e20) {
+                         columnActivity_[iColumn] = -dualDual[iColumn] + columnLower_[iColumn];
+                    } else if (columnUpper_[iColumn] < 1.0e20) {
+                         columnActivity_[iColumn] = -dualDual[iColumn] + columnUpper_[iColumn];
+                    } else {
+                         columnActivity_[iColumn] = -dualDual[iColumn];
+                    }
+                    reducedCost_[iColumn] = 0.0;
+               } else {
+                    // may be at other bound
+                    //printf("xx %d %g jcol %d\n",iColumn,otherValue,jColumn-1);
+                    if (dualProblem->getColumnStatus(jColumn - 1) != basic) {
+                         // column basic
+                         setColumnStatus(iColumn, basic);
+                         numberBasic++;
+                         //printf("Col %d otherV %g dualDual %g\n",iColumn,
+                         // otherValue,dualDual[iColumn]);
+                         columnActivity_[iColumn] = -dualDual[iColumn];
+                         columnActivity_[iColumn] = otherValue;
+                         reducedCost_[iColumn] = 0.0;
+                    } else {
+                         reducedCost_[iColumn] = objValue - dualActs[iColumn];
+                         if (fabs(otherValue - columnLower_[iColumn]) < 1.0e-5) {
+                              if (columnUpper_[iColumn] > columnLower_[iColumn])
+                                   setColumnStatus(iColumn, atLowerBound);
+                              else
+                                   setColumnStatus(iColumn, isFixed);
+                              columnActivity_[iColumn] = columnLower_[iColumn];
+                         } else if (fabs(otherValue - columnUpper_[iColumn]) < 1.0e-5) {
+                              if (columnUpper_[iColumn] > columnLower_[iColumn])
+                                   setColumnStatus(iColumn, atUpperBound);
+                              else
+                                   setColumnStatus(iColumn, isFixed);
+                              columnActivity_[iColumn] = columnUpper_[iColumn];
+                         } else {
+                              abort();
+                         }
+                    }
+               }
+          }
+     }
+     // now rows
+     int kExtraRow = jColumn;
+     int numberRanges = 0;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          Status status = dualProblem->getColumnStatus(iRow);
+          if (status == basic) {
+               // row is at bound
+               dual_[iRow] = dualSol[iRow];;
+          } else {
+               // row basic
+               setRowStatus(iRow, basic);
+               numberBasic++;
+               dual_[iRow] = 0.0;
+          }
+          if (rowLower_[iRow] < -1.0e20) {
+               if (status == basic) {
+                    rowActivity_[iRow] = rowUpper_[iRow];
+                    setRowStatus(iRow, atUpperBound);
+               } else {
+                    // might be stopped assert (dualDj[iRow] < 1.0e-5);
+                    rowActivity_[iRow] = rowUpper_[iRow] + dualDj[iRow];
+               }
+          } else if (rowUpper_[iRow] > 1.0e20) {
+               if (status == basic) {
+                    rowActivity_[iRow] = rowLower_[iRow];
+                    setRowStatus(iRow, atLowerBound);
+               } else {
+                    rowActivity_[iRow] = rowLower_[iRow] + dualDj[iRow];
+                    // might be stopped assert (dualDj[iRow] > -1.0e-5);
+               }
+          } else {
+               if (rowUpper_[iRow] == rowLower_[iRow]) {
+                    rowActivity_[iRow] = rowLower_[iRow];
+                    if (status == basic) {
+                         setRowStatus(iRow, isFixed);
+                    }
+               } else {
+                    // range
+                    numberRanges++;
+                    Status statusL = dualProblem->getColumnStatus(kExtraRow);
+                    //printf("range row %d (%d), extra %d (%d) - dualSol %g,%g dualDj %g,%g\n",
+                    //     iRow,status,kExtraRow,statusL, dualSol[iRow],
+                    //     dualSol[kExtraRow],dualDj[iRow],dualDj[kExtraRow]);
+                    if (status == basic) {
+                         // might be stopped assert (statusL != basic);
+                         rowActivity_[iRow] = rowUpper_[iRow];
+                         setRowStatus(iRow, atUpperBound);
+                    } else if (statusL == basic) {
+                         numberBasic--; // already counted
+                         rowActivity_[iRow] = rowLower_[iRow];
+                         setRowStatus(iRow, atLowerBound);
+                         dual_[iRow] = dualSol[kExtraRow];;
+                    } else {
+                         rowActivity_[iRow] = rowLower_[iRow] - dualDj[iRow];
+                         // might be stopped assert (dualDj[iRow] < 1.0e-5);
+                         // row basic
+                         //setRowStatus(iRow,basic);
+                         //numberBasic++;
+                         dual_[iRow] = 0.0;
+                    }
+                    kExtraRow++;
+               }
+          }
+     }
+     if (numberBasic != numberRows_) {
+          printf("Bad basis - ranges - coding needed\n");
+          assert (numberRanges);
+          abort();
+     }
+     if (optimizationDirection_ < 0.0) {
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               dual_[iRow] = -dual_[iRow];
+          }
+     }
+     // redo row activities
+     memset(rowActivity_, 0, numberRows_ * sizeof(double));
+     matrix_->times(1.0, columnActivity_, rowActivity_);
+     // redo reduced costs
+     memcpy(reducedCost_, this->objective(), numberColumns_ * sizeof(double));
+     matrix_->transposeTimes(-1.0, dual_, reducedCost_);
+     checkSolutionInternal();
+     if (sumDualInfeasibilities_ > 1.0e-5 || sumPrimalInfeasibilities_ > 1.0e-5) {
+          returnCode = 1;
+#ifdef CLP_INVESTIGATE
+          printf("There are %d dual infeasibilities summing to %g ",
+                 numberDualInfeasibilities_, sumDualInfeasibilities_);
+          printf("and %d primal infeasibilities summing to %g\n",
+                 numberPrimalInfeasibilities_, sumPrimalInfeasibilities_);
+#endif
+     }
+     // Below will go to ..DEBUG later
+#if 1 //ndef NDEBUG
+     if (checkAccuracy) {
+       // Check if correct
+       double * columnActivity = CoinCopyOfArray(columnActivity_, numberColumns_);
+       double * rowActivity = CoinCopyOfArray(rowActivity_, numberRows_);
+       double * reducedCost = CoinCopyOfArray(reducedCost_, numberColumns_);
+       double * dual = CoinCopyOfArray(dual_, numberRows_);
+       this->dual(); //primal();
+       CoinRelFltEq eq(1.0e-5);
+       for (iRow = 0; iRow < numberRows_; iRow++) {
+	 assert(eq(dual[iRow], dual_[iRow]));
+       }
+       for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+	 assert(eq(columnActivity[iColumn], columnActivity_[iColumn]));
+       }
+       for (iRow = 0; iRow < numberRows_; iRow++) {
+	 assert(eq(rowActivity[iRow], rowActivity_[iRow]));
+       }
+       for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+	 assert(eq(reducedCost[iColumn], reducedCost_[iColumn]));
+       }
+       delete [] columnActivity;
+       delete [] rowActivity;
+       delete [] reducedCost;
+       delete [] dual;
+     }
+#endif
+     return returnCode;
+}
+/* Does very cursory presolve.
+   rhs is numberRows, whichRows is 3*numberRows and whichColumns is 2*numberColumns
+*/
+ClpSimplex *
+ClpSimplexOther::crunch(double * rhs, int * whichRow, int * whichColumn,
+                        int & nBound, bool moreBounds, bool tightenBounds)
+{
+     //#define CHECK_STATUS
+#ifdef CHECK_STATUS
+     {
+          int n = 0;
+          int i;
+          for (i = 0; i < numberColumns_; i++)
+               if (getColumnStatus(i) == ClpSimplex::basic)
+                    n++;
+          for (i = 0; i < numberRows_; i++)
+               if (getRowStatus(i) == ClpSimplex::basic)
+                    n++;
+          assert (n == numberRows_);
+     }
+#endif
+
+     const double * element = matrix_->getElements();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+
+     CoinZeroN(rhs, numberRows_);
+     int iColumn;
+     int iRow;
+     CoinZeroN(whichRow, numberRows_);
+     int * backColumn = whichColumn + numberColumns_;
+     int numberRows2 = 0;
+     int numberColumns2 = 0;
+     double offset = 0.0;
+     const double * objective = this->objective();
+     double * solution = columnActivity_;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          double lower = columnLower_[iColumn];
+          double upper = columnUpper_[iColumn];
+          if (upper > lower || getColumnStatus(iColumn) == ClpSimplex::basic) {
+               backColumn[iColumn] = numberColumns2;
+               whichColumn[numberColumns2++] = iColumn;
+               for (CoinBigIndex j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    int n = whichRow[iRow];
+                    if (n == 0 && element[j])
+                         whichRow[iRow] = -iColumn - 1;
+                    else if (n < 0)
+                         whichRow[iRow] = 2;
+               }
+          } else {
+               // fixed
+               backColumn[iColumn] = -1;
+               solution[iColumn] = upper;
+               if (upper) {
+                    offset += objective[iColumn] * upper;
+                    for (CoinBigIndex j = columnStart[iColumn];
+                              j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         int iRow = row[j];
+                         double value = element[j];
+                         rhs[iRow] += upper * value;
+                    }
+               }
+          }
+     }
+     int returnCode = 0;
+     double tolerance = primalTolerance();
+     nBound = 2 * numberRows_;
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          int n = whichRow[iRow];
+          if (n > 0) {
+               whichRow[numberRows2++] = iRow;
+          } else if (n < 0) {
+               //whichRow[numberRows2++]=iRow;
+               //continue;
+               // Can only do in certain circumstances as we don't know current value
+               if (rowLower_[iRow] == rowUpper_[iRow] || getRowStatus(iRow) == ClpSimplex::basic) {
+                    // save row and column for bound
+                    whichRow[--nBound] = iRow;
+                    whichRow[nBound+numberRows_] = -n - 1;
+               } else if (moreBounds) {
+                    // save row and column for bound
+                    whichRow[--nBound] = iRow;
+                    whichRow[nBound+numberRows_] = -n - 1;
+               } else {
+                    whichRow[numberRows2++] = iRow;
+               }
+          } else {
+               // empty
+               double rhsValue = rhs[iRow];
+               if (rhsValue < rowLower_[iRow] - tolerance || rhsValue > rowUpper_[iRow] + tolerance) {
+                    returnCode = 1; // infeasible
+               }
+          }
+     }
+     ClpSimplex * small = NULL;
+     if (!returnCode) {
+       //printf("CRUNCH from (%d,%d) to (%d,%d)\n",
+       //     numberRows_,numberColumns_,numberRows2,numberColumns2);
+          small = new ClpSimplex(this, numberRows2, whichRow,
+                                 numberColumns2, whichColumn, true, false);
+#if 0
+          ClpPackedMatrix * rowCopy = dynamic_cast<ClpPackedMatrix *>(rowCopy_);
+          if (rowCopy) {
+               assert(!small->rowCopy());
+               small->setNewRowCopy(new ClpPackedMatrix(*rowCopy, numberRows2, whichRow,
+                                    numberColumns2, whichColumn));
+          }
+#endif
+          // Set some stuff
+          small->setDualBound(dualBound_);
+          small->setInfeasibilityCost(infeasibilityCost_);
+          small->setSpecialOptions(specialOptions_);
+          small->setPerturbation(perturbation_);
+          small->defaultFactorizationFrequency();
+          small->setAlphaAccuracy(alphaAccuracy_);
+          // If no rows left then no tightening!
+          if (!numberRows2 || !numberColumns2)
+               tightenBounds = false;
+
+          int numberElements = getNumElements();
+          int numberElements2 = small->getNumElements();
+          small->setObjectiveOffset(objectiveOffset() - offset);
+          handler_->message(CLP_CRUNCH_STATS, messages_)
+                    << numberRows2 << -(numberRows_ - numberRows2)
+                    << numberColumns2 << -(numberColumns_ - numberColumns2)
+                    << numberElements2 << -(numberElements - numberElements2)
+                    << CoinMessageEol;
+          // And set objective value to match
+          small->setObjectiveValue(this->objectiveValue());
+          double * rowLower2 = small->rowLower();
+          double * rowUpper2 = small->rowUpper();
+          int jRow;
+          for (jRow = 0; jRow < numberRows2; jRow++) {
+               iRow = whichRow[jRow];
+               if (rowLower2[jRow] > -1.0e20)
+                    rowLower2[jRow] -= rhs[iRow];
+               if (rowUpper2[jRow] < 1.0e20)
+                    rowUpper2[jRow] -= rhs[iRow];
+          }
+          // and bounds
+          double * columnLower2 = small->columnLower();
+          double * columnUpper2 = small->columnUpper();
+          const char * integerInformation = integerType_;
+          for (jRow = nBound; jRow < 2 * numberRows_; jRow++) {
+               iRow = whichRow[jRow];
+               iColumn = whichRow[jRow+numberRows_];
+               double lowerRow = rowLower_[iRow];
+               if (lowerRow > -1.0e20)
+                    lowerRow -= rhs[iRow];
+               double upperRow = rowUpper_[iRow];
+               if (upperRow < 1.0e20)
+                    upperRow -= rhs[iRow];
+               int jColumn = backColumn[iColumn];
+               double lower = columnLower2[jColumn];
+               double upper = columnUpper2[jColumn];
+               double value = 0.0;
+               for (CoinBigIndex j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    if (iRow == row[j]) {
+                         value = element[j];
+                         break;
+                    }
+               }
+               assert (value);
+               // convert rowLower and Upper to implied bounds on column
+               double newLower = -COIN_DBL_MAX;
+               double newUpper = COIN_DBL_MAX;
+               if (value > 0.0) {
+                    if (lowerRow > -1.0e20)
+                         newLower = lowerRow / value;
+                    if (upperRow < 1.0e20)
+                         newUpper = upperRow / value;
+               } else {
+                    if (upperRow < 1.0e20)
+                         newLower = upperRow / value;
+                    if (lowerRow > -1.0e20)
+                         newUpper = lowerRow / value;
+               }
+               if (integerInformation && integerInformation[iColumn]) {
+                    if (newLower - floor(newLower) < 10.0 * tolerance)
+                         newLower = floor(newLower);
+                    else
+                         newLower = ceil(newLower);
+                    if (ceil(newUpper) - newUpper < 10.0 * tolerance)
+                         newUpper = ceil(newUpper);
+                    else
+                         newUpper = floor(newUpper);
+               }
+               newLower = CoinMax(lower, newLower);
+               newUpper = CoinMin(upper, newUpper);
+               if (newLower > newUpper + tolerance) {
+                    //printf("XXYY inf on bound\n");
+                    returnCode = 1;
+               }
+               columnLower2[jColumn] = newLower;
+               columnUpper2[jColumn] = CoinMax(newLower, newUpper);
+               if (getRowStatus(iRow) != ClpSimplex::basic) {
+                    if (getColumnStatus(iColumn) == ClpSimplex::basic) {
+                         if (columnLower2[jColumn] == columnUpper2[jColumn]) {
+                              // can only get here if will be fixed
+                              small->setColumnStatus(jColumn, ClpSimplex::isFixed);
+                         } else {
+                              // solution is valid
+                              if (fabs(columnActivity_[iColumn] - columnLower2[jColumn]) <
+                                        fabs(columnActivity_[iColumn] - columnUpper2[jColumn]))
+                                   small->setColumnStatus(jColumn, ClpSimplex::atLowerBound);
+                              else
+                                   small->setColumnStatus(jColumn, ClpSimplex::atUpperBound);
+                         }
+                    } else {
+                         //printf("what now neither basic\n");
+                    }
+               }
+          }
+          if (returnCode) {
+               delete small;
+               small = NULL;
+          } else if (tightenBounds && integerInformation) {
+               // See if we can tighten any bounds
+               // use rhs for upper and small duals for lower
+               double * up = rhs;
+               double * lo = small->dualRowSolution();
+               const double * element = small->clpMatrix()->getElements();
+               const int * row = small->clpMatrix()->getIndices();
+               const CoinBigIndex * columnStart = small->clpMatrix()->getVectorStarts();
+               //const int * columnLength = small->clpMatrix()->getVectorLengths();
+               CoinZeroN(lo, numberRows2);
+               CoinZeroN(up, numberRows2);
+               for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
+                    double upper = columnUpper2[iColumn];
+                    double lower = columnLower2[iColumn];
+                    //assert (columnLength[iColumn]==columnStart[iColumn+1]-columnStart[iColumn]);
+                    for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn+1]; j++) {
+                         int iRow = row[j];
+                         double value = element[j];
+                         if (value > 0.0) {
+                              if (upper < 1.0e20)
+                                   up[iRow] += upper * value;
+                              else
+                                   up[iRow] = COIN_DBL_MAX;
+                              if (lower > -1.0e20)
+                                   lo[iRow] += lower * value;
+                              else
+                                   lo[iRow] = -COIN_DBL_MAX;
+                         } else {
+                              if (upper < 1.0e20)
+                                   lo[iRow] += upper * value;
+                              else
+                                   lo[iRow] = -COIN_DBL_MAX;
+                              if (lower > -1.0e20)
+                                   up[iRow] += lower * value;
+                              else
+                                   up[iRow] = COIN_DBL_MAX;
+                         }
+                    }
+               }
+               double * rowLower2 = small->rowLower();
+               double * rowUpper2 = small->rowUpper();
+               bool feasible = true;
+               // make safer
+               for (int iRow = 0; iRow < numberRows2; iRow++) {
+                    double lower = lo[iRow];
+                    if (lower > rowUpper2[iRow] + tolerance) {
+                         feasible = false;
+                         break;
+                    } else {
+                         lo[iRow] = CoinMin(lower - rowUpper2[iRow], 0.0) - tolerance;
+                    }
+                    double upper = up[iRow];
+                    if (upper < rowLower2[iRow] - tolerance) {
+                         feasible = false;
+                         break;
+                    } else {
+                         up[iRow] = CoinMax(upper - rowLower2[iRow], 0.0) + tolerance;
+                    }
+               }
+               if (!feasible) {
+                    delete small;
+                    small = NULL;
+               } else {
+                    // and tighten
+                    for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
+                         if (integerInformation[whichColumn[iColumn]]) {
+                              double upper = columnUpper2[iColumn];
+                              double lower = columnLower2[iColumn];
+                              double newUpper = upper;
+                              double newLower = lower;
+                              double difference = upper - lower;
+                              if (lower > -1000.0 && upper < 1000.0) {
+                                   for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn+1]; j++) {
+                                        int iRow = row[j];
+                                        double value = element[j];
+                                        if (value > 0.0) {
+                                             double upWithOut = up[iRow] - value * difference;
+                                             if (upWithOut < 0.0) {
+                                                  newLower = CoinMax(newLower, lower - (upWithOut + tolerance) / value);
+                                             }
+                                             double lowWithOut = lo[iRow] + value * difference;
+                                             if (lowWithOut > 0.0) {
+                                                  newUpper = CoinMin(newUpper, upper - (lowWithOut - tolerance) / value);
+                                             }
+                                        } else {
+                                             double upWithOut = up[iRow] + value * difference;
+                                             if (upWithOut < 0.0) {
+                                                  newUpper = CoinMin(newUpper, upper - (upWithOut + tolerance) / value);
+                                             }
+                                             double lowWithOut = lo[iRow] - value * difference;
+                                             if (lowWithOut > 0.0) {
+                                                  newLower = CoinMax(newLower, lower - (lowWithOut - tolerance) / value);
+                                             }
+                                        }
+                                   }
+                                   if (newLower > lower || newUpper < upper) {
+                                        if (fabs(newUpper - floor(newUpper + 0.5)) > 1.0e-6)
+                                             newUpper = floor(newUpper);
+                                        else
+                                             newUpper = floor(newUpper + 0.5);
+                                        if (fabs(newLower - ceil(newLower - 0.5)) > 1.0e-6)
+                                             newLower = ceil(newLower);
+                                        else
+                                             newLower = ceil(newLower - 0.5);
+                                        // change may be too small - check
+                                        if (newLower > lower || newUpper < upper) {
+                                             if (newUpper >= newLower) {
+                                                  // Could also tighten in this
+                                                  //printf("%d bounds %g %g tightened to %g %g\n",
+                                                  //     iColumn,columnLower2[iColumn],columnUpper2[iColumn],
+                                                  //     newLower,newUpper);
+#if 1
+                                                  columnUpper2[iColumn] = newUpper;
+                                                  columnLower2[iColumn] = newLower;
+                                                  columnUpper_[whichColumn[iColumn]] = newUpper;
+                                                  columnLower_[whichColumn[iColumn]] = newLower;
+#endif
+                                                  // and adjust bounds on rows
+                                                  newUpper -= upper;
+                                                  newLower -= lower;
+                                                  for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn+1]; j++) {
+                                                       int iRow = row[j];
+                                                       double value = element[j];
+                                                       if (value > 0.0) {
+                                                            up[iRow] += newUpper * value;
+                                                            lo[iRow] += newLower * value;
+                                                       } else {
+                                                            lo[iRow] += newUpper * value;
+                                                            up[iRow] += newLower * value;
+                                                       }
+                                                  }
+                                             } else {
+                                                  // infeasible
+                                                  //printf("%d bounds infeasible %g %g tightened to %g %g\n",
+                                                  //     iColumn,columnLower2[iColumn],columnUpper2[iColumn],
+                                                  //     newLower,newUpper);
+#if 1
+                                                  delete small;
+                                                  small = NULL;
+                                                  break;
+#endif
+                                             }
+                                        }
+                                   }
+                              }
+                         }
+                    }
+               }
+          }
+     }
+#if 0
+     if (small) {
+          static int which = 0;
+          which++;
+          char xxxx[20];
+          sprintf(xxxx, "bad%d.mps", which);
+          small->writeMps(xxxx, 0, 1);
+          sprintf(xxxx, "largebad%d.mps", which);
+          writeMps(xxxx, 0, 1);
+          printf("bad%d %x old size %d %d new %d %d\n", which, small,
+                 numberRows_, numberColumns_, small->numberRows(), small->numberColumns());
+#if 0
+          for (int i = 0; i < numberColumns_; i++)
+               printf("Bound %d %g %g\n", i, columnLower_[i], columnUpper_[i]);
+          for (int i = 0; i < numberRows_; i++)
+               printf("Row bound %d %g %g\n", i, rowLower_[i], rowUpper_[i]);
+#endif
+     }
+#endif
+#ifdef CHECK_STATUS
+     {
+          int n = 0;
+          int i;
+          for (i = 0; i < small->numberColumns(); i++)
+               if (small->getColumnStatus(i) == ClpSimplex::basic)
+                    n++;
+          for (i = 0; i < small->numberRows(); i++)
+               if (small->getRowStatus(i) == ClpSimplex::basic)
+                    n++;
+          assert (n == small->numberRows());
+     }
+#endif
+     return small;
+}
+/* After very cursory presolve.
+   rhs is numberRows, whichRows is 3*numberRows and whichColumns is 2*numberColumns.
+*/
+void
+ClpSimplexOther::afterCrunch(const ClpSimplex & small,
+                             const int * whichRow,
+                             const int * whichColumn, int nBound)
+{
+#ifndef NDEBUG
+     for (int i = 0; i < small.numberRows(); i++)
+          assert (whichRow[i] >= 0 && whichRow[i] < numberRows_);
+     for (int i = 0; i < small.numberColumns(); i++)
+          assert (whichColumn[i] >= 0 && whichColumn[i] < numberColumns_);
+#endif
+     getbackSolution(small, whichRow, whichColumn);
+     // and deal with status for bounds
+     const double * element = matrix_->getElements();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     double tolerance = primalTolerance();
+     double djTolerance = dualTolerance();
+     for (int jRow = nBound; jRow < 2 * numberRows_; jRow++) {
+          int iRow = whichRow[jRow];
+          int iColumn = whichRow[jRow+numberRows_];
+          if (getColumnStatus(iColumn) != ClpSimplex::basic) {
+               double lower = columnLower_[iColumn];
+               double upper = columnUpper_[iColumn];
+               double value = columnActivity_[iColumn];
+               double djValue = reducedCost_[iColumn];
+               dual_[iRow] = 0.0;
+               if (upper > lower) {
+                    if (value < lower + tolerance && djValue > -djTolerance) {
+                         setColumnStatus(iColumn, ClpSimplex::atLowerBound);
+                         setRowStatus(iRow, ClpSimplex::basic);
+                    } else if (value > upper - tolerance && djValue < djTolerance) {
+                         setColumnStatus(iColumn, ClpSimplex::atUpperBound);
+                         setRowStatus(iRow, ClpSimplex::basic);
+                    } else {
+                         // has to be basic
+                         setColumnStatus(iColumn, ClpSimplex::basic);
+                         reducedCost_[iColumn] = 0.0;
+                         double value = 0.0;
+                         for (CoinBigIndex j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              if (iRow == row[j]) {
+                                   value = element[j];
+                                   break;
+                              }
+                         }
+                         dual_[iRow] = djValue / value;
+                         if (rowUpper_[iRow] > rowLower_[iRow]) {
+                              if (fabs(rowActivity_[iRow] - rowLower_[iRow]) <
+                                        fabs(rowActivity_[iRow] - rowUpper_[iRow]))
+                                   setRowStatus(iRow, ClpSimplex::atLowerBound);
+                              else
+                                   setRowStatus(iRow, ClpSimplex::atUpperBound);
+                         } else {
+                              setRowStatus(iRow, ClpSimplex::isFixed);
+                         }
+                    }
+               } else {
+                    // row can always be basic
+                    setRowStatus(iRow, ClpSimplex::basic);
+               }
+          } else {
+               // row can always be basic
+               setRowStatus(iRow, ClpSimplex::basic);
+          }
+     }
+     //#ifndef NDEBUG
+#if 0
+     if  (small.status() == 0) {
+          int n = 0;
+          int i;
+          for (i = 0; i < numberColumns; i++)
+               if (getColumnStatus(i) == ClpSimplex::basic)
+                    n++;
+          for (i = 0; i < numberRows; i++)
+               if (getRowStatus(i) == ClpSimplex::basic)
+                    n++;
+          assert (n == numberRows);
+     }
+#endif
+}
+/* Tightens integer bounds - returns number tightened or -1 if infeasible
+ */
+int
+ClpSimplexOther::tightenIntegerBounds(double * rhsSpace)
+{
+     // See if we can tighten any bounds
+     // use rhs for upper and small duals for lower
+     double * up = rhsSpace;
+     double * lo = dual_;
+     const double * element = matrix_->getElements();
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     CoinZeroN(lo, numberRows_);
+     CoinZeroN(up, numberRows_);
+     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          double upper = columnUpper_[iColumn];
+          double lower = columnLower_[iColumn];
+          //assert (columnLength[iColumn]==columnStart[iColumn+1]-columnStart[iColumn]);
+          for (CoinBigIndex j = columnStart[iColumn];
+                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+               int iRow = row[j];
+               double value = element[j];
+               if (value > 0.0) {
+                    if (upper < 1.0e20)
+                         up[iRow] += upper * value;
+                    else
+                         up[iRow] = COIN_DBL_MAX;
+                    if (lower > -1.0e20)
+                         lo[iRow] += lower * value;
+                    else
+                         lo[iRow] = -COIN_DBL_MAX;
+               } else {
+                    if (upper < 1.0e20)
+                         lo[iRow] += upper * value;
+                    else
+                         lo[iRow] = -COIN_DBL_MAX;
+                    if (lower > -1.0e20)
+                         up[iRow] += lower * value;
+                    else
+                         up[iRow] = COIN_DBL_MAX;
+               }
+          }
+     }
+     bool feasible = true;
+     // make safer
+     double tolerance = primalTolerance();
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          double lower = lo[iRow];
+          if (lower > rowUpper_[iRow] + tolerance) {
+               feasible = false;
+               break;
+          } else {
+               lo[iRow] = CoinMin(lower - rowUpper_[iRow], 0.0) - tolerance;
+          }
+          double upper = up[iRow];
+          if (upper < rowLower_[iRow] - tolerance) {
+               feasible = false;
+               break;
+          } else {
+               up[iRow] = CoinMax(upper - rowLower_[iRow], 0.0) + tolerance;
+          }
+     }
+     int numberTightened = 0;
+     if (!feasible) {
+          return -1;
+     } else if (integerType_) {
+          // and tighten
+          for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (integerType_[iColumn]) {
+                    double upper = columnUpper_[iColumn];
+                    double lower = columnLower_[iColumn];
+                    double newUpper = upper;
+                    double newLower = lower;
+                    double difference = upper - lower;
+                    if (lower > -1000.0 && upper < 1000.0) {
+                         for (CoinBigIndex j = columnStart[iColumn];
+                                   j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                              int iRow = row[j];
+                              double value = element[j];
+                              if (value > 0.0) {
+                                   double upWithOut = up[iRow] - value * difference;
+                                   if (upWithOut < 0.0) {
+                                        newLower = CoinMax(newLower, lower - (upWithOut + tolerance) / value);
+                                   }
+                                   double lowWithOut = lo[iRow] + value * difference;
+                                   if (lowWithOut > 0.0) {
+                                        newUpper = CoinMin(newUpper, upper - (lowWithOut - tolerance) / value);
+                                   }
+                              } else {
+                                   double upWithOut = up[iRow] + value * difference;
+                                   if (upWithOut < 0.0) {
+                                        newUpper = CoinMin(newUpper, upper - (upWithOut + tolerance) / value);
+                                   }
+                                   double lowWithOut = lo[iRow] - value * difference;
+                                   if (lowWithOut > 0.0) {
+                                        newLower = CoinMax(newLower, lower - (lowWithOut - tolerance) / value);
+                                   }
+                              }
+                         }
+                         if (newLower > lower || newUpper < upper) {
+                              if (fabs(newUpper - floor(newUpper + 0.5)) > 1.0e-6)
+                                   newUpper = floor(newUpper);
+                              else
+                                   newUpper = floor(newUpper + 0.5);
+                              if (fabs(newLower - ceil(newLower - 0.5)) > 1.0e-6)
+                                   newLower = ceil(newLower);
+                              else
+                                   newLower = ceil(newLower - 0.5);
+                              // change may be too small - check
+                              if (newLower > lower || newUpper < upper) {
+                                   if (newUpper >= newLower) {
+                                        numberTightened++;
+                                        //printf("%d bounds %g %g tightened to %g %g\n",
+                                        //     iColumn,columnLower_[iColumn],columnUpper_[iColumn],
+                                        //     newLower,newUpper);
+                                        columnUpper_[iColumn] = newUpper;
+                                        columnLower_[iColumn] = newLower;
+                                        // and adjust bounds on rows
+                                        newUpper -= upper;
+                                        newLower -= lower;
+                                        for (CoinBigIndex j = columnStart[iColumn];
+                                                  j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                             int iRow = row[j];
+                                             double value = element[j];
+                                             if (value > 0.0) {
+                                                  up[iRow] += newUpper * value;
+                                                  lo[iRow] += newLower * value;
+                                             } else {
+                                                  lo[iRow] += newUpper * value;
+                                                  up[iRow] += newLower * value;
+                                             }
+                                        }
+                                   } else {
+                                        // infeasible
+                                        //printf("%d bounds infeasible %g %g tightened to %g %g\n",
+                                        //     iColumn,columnLower_[iColumn],columnUpper_[iColumn],
+                                        //     newLower,newUpper);
+                                        return -1;
+                                   }
+                              }
+                         }
+                    }
+               }
+          }
+     }
+     return numberTightened;
+}
+/* Parametrics
+   This is an initial slow version.
+   The code uses current bounds + theta * change (if change array not NULL)
+   and similarly for objective.
+   It starts at startingTheta and returns ending theta in endingTheta.
+   If reportIncrement 0.0 it will report on any movement
+   If reportIncrement >0.0 it will report at startingTheta+k*reportIncrement.
+   If it can not reach input endingTheta return code will be 1 for infeasible,
+   2 for unbounded, if error on ranges -1,  otherwise 0.
+   Normal report is just theta and objective but
+   if event handler exists it may do more
+   On exit endingTheta is maximum reached (can be used for next startingTheta)
+*/
+int
+ClpSimplexOther::parametrics(double startingTheta, double & endingTheta, double reportIncrement,
+                             const double * lowerChangeBound, const double * upperChangeBound,
+                             const double * lowerChangeRhs, const double * upperChangeRhs,
+                             const double * changeObjective)
+{
+     bool needToDoSomething = true;
+     bool canTryQuick = (reportIncrement) ? true : false;
+     // Save copy of model
+     ClpSimplex copyModel = *this;
+     int savePerturbation = perturbation_;
+     perturbation_ = 102; // switch off
+     while (needToDoSomething) {
+          needToDoSomething = false;
+          algorithm_ = -1;
+
+          // save data
+          ClpDataSave data = saveData();
+	  // Dantzig 
+	  ClpDualRowPivot * savePivot = dualRowPivot_;
+	  dualRowPivot_ = new ClpDualRowDantzig();
+	  dualRowPivot_->setModel(this);
+          int returnCode = reinterpret_cast<ClpSimplexDual *> (this)->startupSolve(0, NULL, 0);
+          int iRow, iColumn;
+          double * chgUpper = NULL;
+          double * chgLower = NULL;
+          double * chgObjective = NULL;
+
+
+          if (!returnCode) {
+               // Find theta when bounds will cross over and create arrays
+               int numberTotal = numberRows_ + numberColumns_;
+               chgLower = new double[numberTotal];
+               memset(chgLower, 0, numberTotal * sizeof(double));
+               chgUpper = new double[numberTotal];
+               memset(chgUpper, 0, numberTotal * sizeof(double));
+               chgObjective = new double[numberTotal];
+               memset(chgObjective, 0, numberTotal * sizeof(double));
+               assert (!rowScale_);
+               double maxTheta = 1.0e50;
+               if (lowerChangeRhs || upperChangeRhs) {
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         double lower = rowLower_[iRow];
+                         double upper = rowUpper_[iRow];
+                         if (lower > upper) {
+                              maxTheta = -1.0;
+                              break;
+                         }
+                         double lowerChange = (lowerChangeRhs) ? lowerChangeRhs[iRow] : 0.0;
+                         double upperChange = (upperChangeRhs) ? upperChangeRhs[iRow] : 0.0;
+                         if (lower > -1.0e20 && upper < 1.0e20) {
+                              if (lower + maxTheta * lowerChange > upper + maxTheta * upperChange) {
+                                   maxTheta = (upper - lower) / (lowerChange - upperChange);
+                              }
+                         }
+                         if (lower > -1.0e20) {
+                              lower_[numberColumns_+iRow] += startingTheta * lowerChange;
+                              chgLower[numberColumns_+iRow] = lowerChange;
+                         }
+                         if (upper < 1.0e20) {
+                              upper_[numberColumns_+iRow] += startingTheta * upperChange;
+                              chgUpper[numberColumns_+iRow] = upperChange;
+                         }
+                    }
+               }
+               if (maxTheta > 0.0) {
+                    if (lowerChangeBound || upperChangeBound) {
+                         for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                              double lower = columnLower_[iColumn];
+                              double upper = columnUpper_[iColumn];
+                              if (lower > upper) {
+                                   maxTheta = -1.0;
+                                   break;
+                              }
+                              double lowerChange = (lowerChangeBound) ? lowerChangeBound[iColumn] : 0.0;
+                              double upperChange = (upperChangeBound) ? upperChangeBound[iColumn] : 0.0;
+                              if (lower > -1.0e20 && upper < 1.0e20) {
+                                   if (lower + maxTheta * lowerChange > upper + maxTheta * upperChange) {
+                                        maxTheta = (upper - lower) / (lowerChange - upperChange);
+                                   }
+                              }
+                              if (lower > -1.0e20) {
+                                   lower_[iColumn] += startingTheta * lowerChange;
+                                   chgLower[iColumn] = lowerChange;
+                              }
+                              if (upper < 1.0e20) {
+                                   upper_[iColumn] += startingTheta * upperChange;
+                                   chgUpper[iColumn] = upperChange;
+                              }
+                         }
+                    }
+                    if (maxTheta == 1.0e50)
+                         maxTheta = COIN_DBL_MAX;
+               }
+               if (maxTheta < 0.0) {
+                    // bad ranges or initial
+                    returnCode = -1;
+               }
+	       if (maxTheta < endingTheta) {
+		 char line[100];
+		 sprintf(line,"Crossover considerations reduce ending  theta from %g to %g\n", 
+			 endingTheta,maxTheta);
+		 handler_->message(CLP_GENERAL,messages_)
+		   << line << CoinMessageEol;
+		 endingTheta = maxTheta;
+	       }
+               if (endingTheta < startingTheta) {
+                    // bad initial
+                    returnCode = -2;
+               }
+          }
+          double saveEndingTheta = endingTheta;
+          if (!returnCode) {
+               if (changeObjective) {
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         chgObjective[iColumn] = changeObjective[iColumn];
+                         cost_[iColumn] += startingTheta * changeObjective[iColumn];
+                    }
+               }
+               double * saveDuals = NULL;
+               reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(0, saveDuals, -1, data);
+               assert (!problemStatus_);
+	       for (int i=0;i<numberRows_+numberColumns_;i++)
+		 setFakeBound(i, noFake);
+               // Now do parametrics
+	       handler_->message(CLP_PARAMETRICS_STATS, messages_)
+		 << startingTheta << objectiveValue() << CoinMessageEol;
+               while (!returnCode) {
+		    //assert (reportIncrement);
+		 parametricsData paramData;
+		 paramData.startingTheta=startingTheta;
+		 paramData.endingTheta=endingTheta;
+		 paramData.maxTheta=COIN_DBL_MAX;
+		 paramData.lowerChange = chgLower;
+		 paramData.upperChange = chgUpper;
+                    returnCode = parametricsLoop(paramData, reportIncrement,
+                                                 chgLower, chgUpper, chgObjective, data,
+                                                 canTryQuick);
+		 startingTheta=paramData.startingTheta;
+		 endingTheta=paramData.endingTheta;
+                    if (!returnCode) {
+                         //double change = endingTheta-startingTheta;
+                         startingTheta = endingTheta;
+                         endingTheta = saveEndingTheta;
+                         //for (int i=0;i<numberTotal;i++) {
+                         //lower_[i] += change*chgLower[i];
+                         //upper_[i] += change*chgUpper[i];
+                         //cost_[i] += change*chgObjective[i];
+                         //}
+			 handler_->message(CLP_PARAMETRICS_STATS, messages_)
+			   << startingTheta << objectiveValue() << CoinMessageEol;
+                         if (startingTheta >= endingTheta)
+                              break;
+                    } else if (returnCode == -1) {
+                         // trouble - do external solve
+                         needToDoSomething = true;
+		    } else if (problemStatus_==1) {
+		      // can't move any further
+		      if (!canTryQuick) {
+			handler_->message(CLP_PARAMETRICS_STATS, messages_)
+			  << endingTheta << objectiveValue() << CoinMessageEol;
+			problemStatus_=0;
+		      }
+                    } else {
+                         abort();
+                    }
+               }
+          }
+          reinterpret_cast<ClpSimplexDual *> (this)->finishSolve(0);
+
+          delete dualRowPivot_;
+          dualRowPivot_ = savePivot;
+          // Restore any saved stuff
+          restoreData(data);
+          if (needToDoSomething) {
+               double saveStartingTheta = startingTheta; // known to be feasible
+               int cleanedUp = 1;
+               while (cleanedUp) {
+                    // tweak
+                    if (cleanedUp == 1) {
+                         if (!reportIncrement)
+                              startingTheta = CoinMin(startingTheta + 1.0e-5, saveEndingTheta);
+                         else
+                              startingTheta = CoinMin(startingTheta + reportIncrement, saveEndingTheta);
+                    } else {
+                         // restoring to go slowly
+                         startingTheta = saveStartingTheta;
+                    }
+                    // only works if not scaled
+                    int i;
+                    const double * obj1 = objective();
+                    double * obj2 = copyModel.objective();
+                    const double * lower1 = columnLower_;
+                    double * lower2 = copyModel.columnLower();
+                    const double * upper1 = columnUpper_;
+                    double * upper2 = copyModel.columnUpper();
+                    for (i = 0; i < numberColumns_; i++) {
+                         obj2[i] = obj1[i] + startingTheta * chgObjective[i];
+                         lower2[i] = lower1[i] + startingTheta * chgLower[i];
+                         upper2[i] = upper1[i] + startingTheta * chgUpper[i];
+                    }
+                    lower1 = rowLower_;
+                    lower2 = copyModel.rowLower();
+                    upper1 = rowUpper_;
+                    upper2 = copyModel.rowUpper();
+                    for (i = 0; i < numberRows_; i++) {
+                         lower2[i] = lower1[i] + startingTheta * chgLower[i+numberColumns_];
+                         upper2[i] = upper1[i] + startingTheta * chgUpper[i+numberColumns_];
+                    }
+                    copyModel.dual();
+                    if (copyModel.problemStatus()) {
+		      char line[100];
+		      sprintf(line,"Can not get to theta of %g\n", startingTheta);
+		      handler_->message(CLP_GENERAL,messages_)
+			<< line << CoinMessageEol;
+                         canTryQuick = false; // do slowly to get exact amount
+                         // back to last known good
+                         if (cleanedUp == 1)
+                              cleanedUp = 2;
+                         else
+                              abort();
+                    } else {
+                         // and move stuff back
+                         int numberTotal = numberRows_ + numberColumns_;
+                         CoinMemcpyN(copyModel.statusArray(), numberTotal, status_);
+                         CoinMemcpyN(copyModel.primalColumnSolution(), numberColumns_, columnActivity_);
+                         CoinMemcpyN(copyModel.primalRowSolution(), numberRows_, rowActivity_);
+                         cleanedUp = 0;
+                    }
+               }
+          }
+          delete [] chgLower;
+          delete [] chgUpper;
+          delete [] chgObjective;
+     }
+     perturbation_ = savePerturbation;
+     char line[100];
+     sprintf(line,"Ending theta %g\n", endingTheta);
+     handler_->message(CLP_GENERAL,messages_)
+       << line << CoinMessageEol;
+     return problemStatus_;
+}
+/* Version of parametrics which reads from file
+   See CbcClpParam.cpp for details of format
+   Returns -2 if unable to open file */
+int 
+ClpSimplexOther::parametrics(const char * dataFile)
+{
+  int returnCode=-2;
+  FILE *fp = fopen(dataFile, "r");
+  char line[200];
+  if (!fp) {
+    handler_->message(CLP_UNABLE_OPEN, messages_)
+      << dataFile << CoinMessageEol;
+    return -2;
+  }
+
+  if (!fgets(line, 200, fp)) {
+    sprintf(line,"Empty parametrics file %s?",dataFile);
+    handler_->message(CLP_GENERAL,messages_)
+      << line << CoinMessageEol;
+    fclose(fp);
+    return -2;
+  }
+  char * pos = line;
+  char * put = line;
+  while (*pos >= ' ' && *pos != '\n') {
+    if (*pos != ' ' && *pos != '\t') {
+      *put = static_cast<char>(tolower(*pos));
+      put++;
+    }
+    pos++;
+  }
+  *put = '\0';
+  pos = line;
+  double startTheta=0.0;
+  double endTheta=0.0;
+  double intervalTheta=COIN_DBL_MAX;
+  int detail=0;
+  bool good = true;
+  while (good) {
+    good=false;
+    // check ROWS
+    char * comma = strchr(pos, ',');
+    if (!comma)
+      break;
+    *comma = '\0';
+    if (strcmp(pos,"rows"))
+      break;
+    *comma = ',';
+    pos = comma+1;
+    // check lower theta
+    comma = strchr(pos, ',');
+    if (!comma)
+      break;
+    *comma = '\0';
+    startTheta = atof(pos);
+    *comma = ',';
+    pos = comma+1;
+    // check upper theta
+    comma = strchr(pos, ',');
+    good=true;
+    if (comma)
+      *comma = '\0';
+    endTheta = atof(pos);
+    if (comma) {
+      *comma = ',';
+      pos = comma+1;
+      comma = strchr(pos, ',');
+      if (comma)
+	*comma = '\0';
+      intervalTheta = atof(pos);
+      if (comma) {
+	*comma = ',';
+	pos = comma+1;
+	comma = strchr(pos, ',');
+	if (comma)
+	  *comma = '\0';
+	detail = atoi(pos);
+	if (comma) 
+	*comma = ',';
+      }
+    }
+    break;
+  }
+  if (good) {
+    if (startTheta<0.0||
+	startTheta>endTheta||
+	intervalTheta<0.0)
+      good=false;
+    if (detail<0||detail>1)
+      good=false;
+  }
+  if (intervalTheta>=endTheta)
+    intervalTheta=0.0;
+  if (!good) {
+    sprintf(line,"Odd first line %s on file %s?",line,dataFile);
+    handler_->message(CLP_GENERAL,messages_)
+      << line << CoinMessageEol;
+    fclose(fp);
+    return -2;
+  }
+  if (!fgets(line, 200, fp)) {
+    sprintf(line,"Not enough records on parametrics file %s?",dataFile);
+    handler_->message(CLP_GENERAL,messages_)
+      << line << CoinMessageEol;
+    fclose(fp);
+    return -2;
+  }
+  double * lowerRowMove = NULL;
+  double * upperRowMove = NULL;
+  double * lowerColumnMove = NULL;
+  double * upperColumnMove = NULL;
+  double * objectiveMove = NULL;
+  char saveLine[200];
+  saveLine[0]='\0';
+  std::string headingsRow[] = {"name", "number", "lower", "upper", "rhs"};
+  int gotRow[] = { -1, -1, -1, -1, -1};
+  int orderRow[5];
+  assert(sizeof(gotRow) == sizeof(orderRow));
+  int nAcross = 0;
+  pos = line;
+  put = line;
+  while (*pos >= ' ' && *pos != '\n') {
+    if (*pos != ' ' && *pos != '\t') {
+      *put = static_cast<char>(tolower(*pos));
+      put++;
+    }
+    pos++;
+  }
+  *put = '\0';
+  pos = line;
+  int i;
+  good = true;
+  if (strncmp(line,"column",6)) {
+    while (pos) {
+      char * comma = strchr(pos, ',');
+      if (comma)
+	*comma = '\0';
+      for (i = 0; i < static_cast<int> (sizeof(gotRow) / sizeof(int)); i++) {
+	if (headingsRow[i] == pos) {
+	  if (gotRow[i] < 0) {
+	    orderRow[nAcross] = i;
+	    gotRow[i] = nAcross++;
+	  } else {
+	    // duplicate
+	    good = false;
+	  }
+	  break;
+	}
+      }
+      if (i == static_cast<int> (sizeof(gotRow) / sizeof(int)))
+	good = false;
+      if (comma) {
+	*comma = ',';
+	pos = comma + 1;
+      } else {
+	break;
+      }
+    }
+    if (gotRow[0] < 0 && gotRow[1] < 0)
+      good = false;
+    if (gotRow[0] >= 0 && gotRow[1] >= 0)
+      good = false;
+    if (gotRow[0] >= 0 && !lengthNames())
+      good = false;
+    if (gotRow[4]<0) {
+      if (gotRow[2] < 0 && gotRow[3] >= 0)
+	good = false;
+      else if (gotRow[3] < 0 && gotRow[2] >= 0)
+	good = false;
+    } else if (gotRow[2]>=0||gotRow[3]>=0) {
+      good = false;
+    }
+    if (good) {
+      char ** rowNames = new char * [numberRows_];
+      int iRow;
+      for (iRow = 0; iRow < numberRows_; iRow++) {
+	rowNames[iRow] =
+	  CoinStrdup(rowName(iRow).c_str());
+      }
+      lowerRowMove = new double [numberRows_];
+      memset(lowerRowMove,0,numberRows_*sizeof(double));
+      upperRowMove = new double [numberRows_];
+      memset(upperRowMove,0,numberRows_*sizeof(double));
+      int nLine = 0;
+      int nBadLine = 0;
+      int nBadName = 0;
+      while (fgets(line, 200, fp)) {
+	if (!strncmp(line, "ENDATA", 6)||
+	    !strncmp(line, "COLUMN",6))
+	  break;
+	nLine++;
+	iRow = -1;
+	double upper = 0.0;
+	double lower = 0.0;
+	char * pos = line;
+	char * put = line;
+	while (*pos >= ' ' && *pos != '\n') {
+	  if (*pos != ' ' && *pos != '\t') {
+	    *put = *pos;
+	    put++;
+	  }
+	  pos++;
+	}
+	*put = '\0';
+	pos = line;
+	for (int i = 0; i < nAcross; i++) {
+	  char * comma = strchr(pos, ',');
+	  if (comma) {
+	    *comma = '\0';
+	  } else if (i < nAcross - 1) {
+	    nBadLine++;
+	    break;
+	  }
+	  switch (orderRow[i]) {
+	    // name
+	  case 0:
+	    // For large problems this could be slow
+	    for (iRow = 0; iRow < numberRows_; iRow++) {
+	      if (!strcmp(rowNames[iRow], pos))
+		break;
+	    }
+	    if (iRow == numberRows_)
+	      iRow = -1;
+	    break;
+	    // number
+	  case 1:
+	    iRow = atoi(pos);
+	    if (iRow < 0 || iRow >= numberRows_)
+	      iRow = -1;
+	    break;
+	    // lower
+	  case 2:
+	    upper = atof(pos);
+	    break;
+	    // upper
+	  case 3:
+	    lower = atof(pos);
+	    break;
+	    // rhs
+	  case 4:
+	    lower = atof(pos);
+	    upper = lower;
+	    break;
+	  }
+	  if (comma) {
+	    *comma = ',';
+	    pos = comma + 1;
+	  }
+	}
+	if (iRow >= 0) {
+	  if (rowLower_[iRow]>-1.0e20)
+	    lowerRowMove[iRow] = lower;
+	  else
+	    lowerRowMove[iRow]=0.0;
+	  if (rowUpper_[iRow]<1.0e20)
+	    upperRowMove[iRow] = upper;
+	  else
+	    upperRowMove[iRow] = lower;
+	} else {
+	  nBadName++;
+	  if(saveLine[0]=='\0')
+	    strcpy(saveLine,line);
+	}
+      }
+      sprintf(line,"%d Row fields and %d records", nAcross, nLine);
+      handler_->message(CLP_GENERAL,messages_)
+	<< line << CoinMessageEol;
+      if (nBadName) {
+	sprintf(line," ** %d records did not match on name/sequence, first bad %s", nBadName,saveLine);
+	handler_->message(CLP_GENERAL,messages_)
+	  << line << CoinMessageEol;
+	returnCode=-1;
+	good=false;
+      }
+      for (iRow = 0; iRow < numberRows_; iRow++) {
+	free(rowNames[iRow]);
+      }
+      delete [] rowNames;
+    } else {
+      sprintf(line,"Duplicate or unknown keyword - or name/number fields wrong");
+      handler_->message(CLP_GENERAL,messages_)
+	<< line << CoinMessageEol;
+      returnCode=-1;
+      good=false;
+    }
+  }
+  if (good&&(!strncmp(line, "COLUMN",6)||!strncmp(line, "column",6))) {
+    if (!fgets(line, 200, fp)) {
+      sprintf(line,"Not enough records on parametrics file %s after COLUMNS?",dataFile);
+      handler_->message(CLP_GENERAL,messages_)
+	<< line << CoinMessageEol;
+      fclose(fp);
+      return -2;
+    }
+    std::string headingsColumn[] = {"name", "number", "lower", "upper", "objective"};
+    saveLine[0]='\0';
+    int gotColumn[] = { -1, -1, -1, -1, -1};
+    int orderColumn[5];
+    assert(sizeof(gotColumn) == sizeof(orderColumn));
+    nAcross = 0;
+    pos = line;
+    put = line;
+    while (*pos >= ' ' && *pos != '\n') {
+      if (*pos != ' ' && *pos != '\t') {
+	*put = static_cast<char>(tolower(*pos));
+	put++;
+      }
+      pos++;
+    }
+    *put = '\0';
+    pos = line;
+    int i;
+    if (strncmp(line,"endata",6)&&good) {
+      while (pos) {
+	char * comma = strchr(pos, ',');
+	if (comma)
+	  *comma = '\0';
+	for (i = 0; i < static_cast<int> (sizeof(gotColumn) / sizeof(int)); i++) {
+	  if (headingsColumn[i] == pos) {
+	    if (gotColumn[i] < 0) {
+	      orderColumn[nAcross] = i;
+	      gotColumn[i] = nAcross++;
+	    } else {
+	      // duplicate
+	      good = false;
+	    }
+	    break;
+	  }
+	}
+	if (i == static_cast<int> (sizeof(gotColumn) / sizeof(int)))
+	  good = false;
+	if (comma) {
+	  *comma = ',';
+	  pos = comma + 1;
+	} else {
+	  break;
+	}
+      }
+      if (gotColumn[0] < 0 && gotColumn[1] < 0)
+	good = false;
+      if (gotColumn[0] >= 0 && gotColumn[1] >= 0)
+	good = false;
+      if (gotColumn[0] >= 0 && !lengthNames())
+	good = false;
+      if (good) {
+	char ** columnNames = new char * [numberColumns_];
+	int iColumn;
+	for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+	  columnNames[iColumn] =
+	    CoinStrdup(columnName(iColumn).c_str());
+	}
+	lowerColumnMove = reinterpret_cast<double *> (malloc(numberColumns_ * sizeof(double)));
+	memset(lowerColumnMove,0,numberColumns_*sizeof(double));
+	upperColumnMove = reinterpret_cast<double *> (malloc(numberColumns_ * sizeof(double)));
+	memset(upperColumnMove,0,numberColumns_*sizeof(double));
+	objectiveMove = reinterpret_cast<double *> (malloc(numberColumns_ * sizeof(double)));
+	memset(objectiveMove,0,numberColumns_*sizeof(double));
+	int nLine = 0;
+	int nBadLine = 0;
+	int nBadName = 0;
+	while (fgets(line, 200, fp)) {
+	  if (!strncmp(line, "ENDATA", 6))
+	    break;
+	  nLine++;
+	  iColumn = -1;
+	  double upper = 0.0;
+	  double lower = 0.0;
+	  double obj =0.0;
+	  char * pos = line;
+	  char * put = line;
+	  while (*pos >= ' ' && *pos != '\n') {
+	    if (*pos != ' ' && *pos != '\t') {
+	      *put = *pos;
+	      put++;
+	    }
+	    pos++;
+	  }
+	  *put = '\0';
+	  pos = line;
+	  for (int i = 0; i < nAcross; i++) {
+	    char * comma = strchr(pos, ',');
+	    if (comma) {
+	      *comma = '\0';
+	    } else if (i < nAcross - 1) {
+	      nBadLine++;
+	      break;
+	    }
+	    switch (orderColumn[i]) {
+	      // name
+	    case 0:
+	      // For large problems this could be slow
+	      for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+		if (!strcmp(columnNames[iColumn], pos))
+		  break;
+	      }
+	      if (iColumn == numberColumns_)
+		iColumn = -1;
+	      break;
+	      // number
+	    case 1:
+	      iColumn = atoi(pos);
+	      if (iColumn < 0 || iColumn >= numberColumns_)
+		iColumn = -1;
+	      break;
+	      // lower
+	    case 2:
+	      upper = atof(pos);
+	      break;
+	      // upper
+	    case 3:
+	      lower = atof(pos);
+	      break;
+	      // objective
+	    case 4:
+	      obj = atof(pos);
+	      upper = lower;
+	      break;
+	    }
+	    if (comma) {
+	      *comma = ',';
+	      pos = comma + 1;
+	    }
+	  }
+	  if (iColumn >= 0) {
+	    if (columnLower_[iColumn]>-1.0e20)
+	      lowerColumnMove[iColumn] = lower;
+	    else
+	      lowerColumnMove[iColumn]=0.0;
+	    if (columnUpper_[iColumn]<1.0e20)
+	      upperColumnMove[iColumn] = upper;
+	    else
+	      upperColumnMove[iColumn] = lower;
+	    objectiveMove[iColumn] = obj;
+	  } else {
+	    nBadName++;
+	    if(saveLine[0]=='\0')
+	      strcpy(saveLine,line);
+	  }
+	}
+	sprintf(line,"%d Column fields and %d records", nAcross, nLine);
+	handler_->message(CLP_GENERAL,messages_)
+	  << line << CoinMessageEol;
+	if (nBadName) {
+	  sprintf(line," ** %d records did not match on name/sequence, first bad %s", nBadName,saveLine);
+	  handler_->message(CLP_GENERAL,messages_)
+	    << line << CoinMessageEol;
+	  returnCode=-1;
+	  good=false;
+	}
+	for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+	  free(columnNames[iColumn]);
+	}
+	delete [] columnNames;
+      } else {
+	sprintf(line,"Duplicate or unknown keyword - or name/number fields wrong");
+	handler_->message(CLP_GENERAL,messages_)
+	  << line << CoinMessageEol;
+	returnCode=-1;
+	good=false;
+      }
+    }
+  }
+  returnCode=-1;
+  if (good) {
+    // clean arrays
+    if (lowerRowMove) {
+      bool empty=true;
+      for (int i=0;i<numberRows_;i++) {
+	if (lowerRowMove[i]) {
+	  empty=false;
+	break;
+	}
+      }
+      if (empty) {
+	delete [] lowerRowMove;
+	lowerRowMove=NULL;
+      }
+    }
+    if (upperRowMove) {
+      bool empty=true;
+      for (int i=0;i<numberRows_;i++) {
+	if (upperRowMove[i]) {
+	  empty=false;
+	break;
+	}
+      }
+      if (empty) {
+	delete [] upperRowMove;
+	upperRowMove=NULL;
+      }
+    }
+    if (lowerColumnMove) {
+      bool empty=true;
+      for (int i=0;i<numberColumns_;i++) {
+	if (lowerColumnMove[i]) {
+	  empty=false;
+	break;
+	}
+      }
+      if (empty) {
+	delete [] lowerColumnMove;
+	lowerColumnMove=NULL;
+      }
+    }
+    if (upperColumnMove) {
+      bool empty=true;
+      for (int i=0;i<numberColumns_;i++) {
+	if (upperColumnMove[i]) {
+	  empty=false;
+	break;
+	}
+      }
+      if (empty) {
+	delete [] upperColumnMove;
+	upperColumnMove=NULL;
+      }
+    }
+    if (objectiveMove) {
+      bool empty=true;
+      for (int i=0;i<numberColumns_;i++) {
+	if (objectiveMove[i]) {
+	  empty=false;
+	break;
+	}
+      }
+      if (empty) {
+	delete [] objectiveMove;
+	objectiveMove=NULL;
+      }
+    }
+    int saveScaling = scalingFlag_;
+    scalingFlag_ = 0;
+    int saveLogLevel = handler_->logLevel();
+    if (detail>0&&!intervalTheta)
+      handler_->setLogLevel(3);
+    else
+      handler_->setLogLevel(1);
+    returnCode = parametrics(startTheta,endTheta,intervalTheta,
+			     lowerColumnMove,upperColumnMove,
+			     lowerRowMove,upperRowMove,
+			     objectiveMove);
+    scalingFlag_ = saveScaling;
+    handler_->setLogLevel(saveLogLevel);
+  }
+  delete [] lowerRowMove;
+  delete [] upperRowMove;
+  delete [] lowerColumnMove;
+  delete [] upperColumnMove;
+  delete [] objectiveMove;
+  fclose(fp);
+  return returnCode;
+}
+int
+ClpSimplexOther::parametricsLoop(parametricsData & paramData,double reportIncrement,
+                                 const double * lowerChange, const double * upperChange,
+                                 const double * changeObjective, ClpDataSave & data,
+                                 bool canTryQuick)
+{
+  double startingTheta = paramData.startingTheta;
+  double & endingTheta = paramData.endingTheta;
+     // stuff is already at starting
+     // For this crude version just try and go to end
+     double change = 0.0;
+     if (reportIncrement && canTryQuick) {
+          endingTheta = CoinMin(endingTheta, startingTheta + reportIncrement);
+          change = endingTheta - startingTheta;
+     }
+     int numberTotal = numberRows_ + numberColumns_;
+     int i;
+     for ( i = 0; i < numberTotal; i++) {
+          lower_[i] += change * lowerChange[i];
+          upper_[i] += change * upperChange[i];
+          switch(getStatus(i)) {
+
+          case basic:
+          case isFree:
+          case superBasic:
+               break;
+          case isFixed:
+          case atUpperBound:
+               solution_[i] = upper_[i];
+               break;
+          case atLowerBound:
+               solution_[i] = lower_[i];
+               break;
+          }
+          cost_[i] += change * changeObjective[i];
+     }
+     problemStatus_ = -1;
+
+     // This says whether to restore things etc
+     // startup will have factorized so can skip
+     int factorType = 0;
+     // Start check for cycles
+     progress_.startCheck();
+     // Say change made on first iteration
+     changeMade_ = 1;
+     /*
+       Status of problem:
+       0 - optimal
+       1 - infeasible
+       2 - unbounded
+       -1 - iterating
+       -2 - factorization wanted
+       -3 - redo checking without factorization
+       -4 - looks infeasible
+     */
+     while (problemStatus_ < 0) {
+          int iRow, iColumn;
+          // clear
+          for (iRow = 0; iRow < 4; iRow++) {
+               rowArray_[iRow]->clear();
+          }
+
+          for (iColumn = 0; iColumn < 2; iColumn++) {
+               columnArray_[iColumn]->clear();
+          }
+
+          // give matrix (and model costs and bounds a chance to be
+          // refreshed (normally null)
+          matrix_->refresh(this);
+          // may factorize, checks if problem finished
+          statusOfProblemInParametrics(factorType, data);
+          // Say good factorization
+          factorType = 1;
+          if (data.sparseThreshold_) {
+               // use default at present
+               factorization_->sparseThreshold(0);
+               factorization_->goSparse();
+          }
+
+          // exit if victory declared
+          if (problemStatus_ >= 0 && 
+	      (canTryQuick || startingTheta>=endingTheta-1.0e-7) )
+               break;
+
+          // test for maximum iterations
+          if (hitMaximumIterations()) {
+               problemStatus_ = 3;
+               break;
+          }
+          // Check event
+          {
+               int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
+               if (status >= 0) {
+                    problemStatus_ = 5;
+                    secondaryStatus_ = ClpEventHandler::endOfFactorization;
+                    break;
+               }
+          }
+          // Do iterations
+	  problemStatus_=-1;
+          if (canTryQuick) {
+               double * saveDuals = NULL;
+               reinterpret_cast<ClpSimplexDual *> (this)->whileIterating(saveDuals, 0);
+          } else {
+               whileIterating(paramData, reportIncrement,
+                              changeObjective);
+	       startingTheta = endingTheta;
+          }
+     }
+     if (!problemStatus_) {
+          theta_ = change + startingTheta;
+          eventHandler_->event(ClpEventHandler::theta);
+          return 0;
+     } else if (problemStatus_ == 10) {
+          return -1;
+     } else {
+          return problemStatus_;
+     }
+}
+/* Parametrics
+   The code uses current bounds + theta * change (if change array not NULL)
+   It starts at startingTheta and returns ending theta in endingTheta.
+   If it can not reach input endingTheta return code will be 1 for infeasible,
+   2 for unbounded, if error on ranges -1,  otherwise 0.
+   Event handler may do more
+   On exit endingTheta is maximum reached (can be used for next startingTheta)
+*/
+int
+ClpSimplexOther::parametrics(double startingTheta, double & endingTheta,
+                             const double * lowerChangeBound, const double * upperChangeBound,
+                             const double * lowerChangeRhs, const double * upperChangeRhs)
+{
+  int savePerturbation = perturbation_;
+  perturbation_ = 102; // switch off
+  algorithm_ = -1;
+  // extra region
+  int maximumPivots = factorization_->maximumPivots();
+  int numberDense = factorization_->numberDense();
+  int length = numberRows_ + numberDense + maximumPivots;
+  assert (!rowArray_[4]);
+  rowArray_[4]=new CoinIndexedVector(length);
+  assert (!rowArray_[5]);
+  rowArray_[5]=new CoinIndexedVector(length);
+
+  // save data
+  ClpDataSave data = saveData();
+  int numberTotal = numberRows_ + numberColumns_;
+  int ratio = (2*sizeof(int))/sizeof(double);
+  assert (ratio==1||ratio==2);
+  // allow for unscaled - even if not needed
+  int lengthArrays = 4*numberTotal+(3*numberTotal+2)*ratio+2*numberRows_+1;
+  int unscaledChangesOffset=lengthArrays; // need extra copy of change
+  lengthArrays += numberTotal;
+  
+  /*
+    Save information and modify
+  */
+  double * saveLower = new double [lengthArrays];
+  double * saveUpper = new double [lengthArrays];
+  double * lowerCopy = saveLower+2*numberTotal;
+  double * upperCopy = saveUpper+2*numberTotal;
+  double * lowerChange = saveLower+numberTotal;
+  double * upperChange = saveUpper+numberTotal;
+  double * lowerGap = saveLower+4*numberTotal;
+  double * lowerCoefficient = lowerGap+numberRows_;
+  double * upperGap = saveUpper+4*numberTotal;
+  double * upperCoefficient = upperGap+numberRows_;
+  int * lowerList = (reinterpret_cast<int *>(saveLower+4*numberTotal+2*numberRows_))+2;
+  int * upperList = (reinterpret_cast<int *>(saveUpper+4*numberTotal+2*numberRows_))+2;
+  int * lowerActive = lowerList+numberTotal+1;
+  int * upperActive = upperList+numberTotal+1;
+  // To mark as odd
+  char * markDone = reinterpret_cast<char *>(lowerActive+numberTotal);
+  //memset(markDone,0,numberTotal);
+  int * backwardBasic = upperActive+numberTotal;
+  parametricsData paramData;
+  paramData.lowerChange = lowerChange;
+  paramData.lowerList=lowerList;
+  paramData.upperChange = upperChange;
+  paramData.upperList=upperList;
+  paramData.markDone=markDone;
+  paramData.backwardBasic=backwardBasic;
+  paramData.lowerActive = lowerActive;
+  paramData.lowerGap = lowerGap;
+  paramData.lowerCoefficient = lowerCoefficient;
+  paramData.upperActive = upperActive;
+  paramData.upperGap = upperGap;
+  paramData.upperCoefficient = upperCoefficient;
+  paramData.unscaledChangesOffset = unscaledChangesOffset-numberTotal;
+  paramData.firstIteration=true;
+  // Find theta when bounds will cross over and create arrays
+  memset(lowerChange, 0, numberTotal * sizeof(double));
+  memset(upperChange, 0, numberTotal * sizeof(double));
+  if (lowerChangeBound)
+    memcpy(lowerChange,lowerChangeBound,numberColumns_*sizeof(double));
+  if (upperChangeBound)
+    memcpy(upperChange,upperChangeBound,numberColumns_*sizeof(double));
+  if (lowerChangeRhs)
+    memcpy(lowerChange+numberColumns_,
+	   lowerChangeRhs,numberRows_*sizeof(double));
+  if (upperChangeRhs)
+    memcpy(upperChange+numberColumns_,
+	   upperChangeRhs,numberRows_*sizeof(double));
+  // clean
+  for (int iRow = 0; iRow < numberRows_; iRow++) {
+    double lower = rowLower_[iRow];
+    double upper = rowUpper_[iRow];
+    if (lower<-1.0e30)
+      lowerChange[numberColumns_+iRow]=0.0;
+    if (upper>1.0e30)
+      upperChange[numberColumns_+iRow]=0.0;
+  }
+  for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+    double lower = columnLower_[iColumn];
+    double upper = columnUpper_[iColumn];
+    if (lower<-1.0e30)
+      lowerChange[iColumn]=0.0;
+    if (upper>1.0e30)
+      upperChange[iColumn]=0.0;
+  }
+  // save unscaled version of changes
+  memcpy(saveLower+unscaledChangesOffset,lowerChange,numberTotal*sizeof(double));
+  memcpy(saveUpper+unscaledChangesOffset,upperChange,numberTotal*sizeof(double));
+  int nLowerChange=0;
+  int nUpperChange=0;
+  for (int i=0;i<numberColumns_;i++) {
+    if (lowerChange[i]) { 
+      lowerList[nLowerChange++]=i;
+    }
+    if (upperChange[i]) { 
+      upperList[nUpperChange++]=i;
+    }
+  }
+  lowerList[-2]=nLowerChange;
+  upperList[-2]=nUpperChange;
+  for (int i=numberColumns_;i<numberTotal;i++) {
+    if (lowerChange[i]) { 
+      lowerList[nLowerChange++]=i;
+    }
+    if (upperChange[i]) { 
+      upperList[nUpperChange++]=i;
+    }
+  }
+  lowerList[-1]=nLowerChange;
+  upperList[-1]=nUpperChange;
+  memcpy(lowerCopy,columnLower_,numberColumns_*sizeof(double));
+  memcpy(upperCopy,columnUpper_,numberColumns_*sizeof(double));
+  memcpy(lowerCopy+numberColumns_,
+	 rowLower_,numberRows_*sizeof(double));
+  memcpy(upperCopy+numberColumns_,
+	 rowUpper_,numberRows_*sizeof(double));
+  {
+    //  extra for unscaled
+    double * unscaledCopy;
+    unscaledCopy = lowerCopy + numberTotal; 
+    memcpy(unscaledCopy,columnLower_,numberColumns_*sizeof(double));
+    memcpy(unscaledCopy+numberColumns_,
+	   rowLower_,numberRows_*sizeof(double));
+    unscaledCopy = upperCopy + numberTotal; 
+    memcpy(unscaledCopy,columnUpper_,numberColumns_*sizeof(double));
+    memcpy(unscaledCopy+numberColumns_,
+	   rowUpper_,numberRows_*sizeof(double));
+  }
+  int returnCode=0;
+  paramData.startingTheta=startingTheta;
+  paramData.endingTheta=endingTheta;
+  paramData.maxTheta=endingTheta;
+  computeRhsEtc(paramData);
+  bool swapped=false;
+  // Dantzig 
+#define ALL_DANTZIG
+#ifdef ALL_DANTZIG
+  ClpDualRowPivot * savePivot = dualRowPivot_;
+  dualRowPivot_ = new ClpDualRowDantzig();
+  dualRowPivot_->setModel(this);
+#else
+  ClpDualRowPivot * savePivot = NULL;
+#endif
+  if (!returnCode) {
+    assert (objective_->type()==1);
+    objective_->setType(2); // in case matrix empty
+    returnCode = reinterpret_cast<ClpSimplexDual *> (this)->startupSolve(0, NULL, 0);
+    objective_->setType(1);
+    if (!returnCode) {
+      double saveDualBound=dualBound_;
+      dualBound_=CoinMax(dualBound_,1.0e15);
+      swapped=true;
+      double * temp;
+      memcpy(saveLower,lower_,numberTotal*sizeof(double));
+      temp=saveLower;
+      saveLower=lower_;
+      lower_=temp;
+      //columnLowerWork_ = lower_;
+      //rowLowerWork_ = lower_ + numberColumns_;
+      memcpy(saveUpper,upper_,numberTotal*sizeof(double));
+      temp=saveUpper;
+      saveUpper=upper_;
+      upper_=temp;
+      //columnUpperWork_ = upper_;
+      //rowUpperWork_ = upper_ + numberColumns_;
+      if (rowScale_) {
+	// scale saved and change arrays
+	double * lowerChange = lower_+numberTotal;
+	double * upperChange = upper_+numberTotal;
+	double * lowerSave = lowerChange+numberTotal;
+	double * upperSave = upperChange+numberTotal;
+	for (int i=0;i<numberColumns_;i++) {
+	  double multiplier = inverseColumnScale_[i];
+	  if (lowerSave[i]>-1.0e20)
+	    lowerSave[i] *= multiplier;
+	  if (upperSave[i]<1.0e20)
+	    upperSave[i] *= multiplier;
+	  lowerChange[i] *= multiplier;
+	  upperChange[i] *= multiplier;
+	}
+	lowerChange += numberColumns_;
+	upperChange += numberColumns_;
+	lowerSave += numberColumns_;
+	upperSave += numberColumns_;
+	for (int i=0;i<numberRows_;i++) {
+	  double multiplier = rowScale_[i];
+	  if (lowerSave[i]>-1.0e20)
+	    lowerSave[i] *= multiplier;
+	  if (upperSave[i]<1.0e20)
+	    upperSave[i] *= multiplier;
+	  lowerChange[i] *= multiplier;
+	  upperChange[i] *= multiplier;
+	}
+      }
+      //double saveEndingTheta = endingTheta;
+      double * saveDuals = NULL;
+      reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(0, saveDuals, -1, data);
+      if (numberPrimalInfeasibilities_&&sumPrimalInfeasibilities_<1.0e-4) {
+	// probably can get rid of this if we adjust every change in theta
+	//printf("INFEAS_A %d %g\n",numberPrimalInfeasibilities_,
+	//   sumPrimalInfeasibilities_);
+	int pass=100;
+	while(sumPrimalInfeasibilities_) {
+	  pass--;
+	  if (!pass)
+	    break;
+	  problemStatus_=-1;
+	  for (int iSequence=numberColumns_;iSequence<numberTotal;iSequence++) {
+	    double value=solution_[iSequence];
+	    // remember scaling
+	    if (value<lower_[iSequence]-1.0e-9) {
+	      lower_[iSequence]=value;
+	      lowerCopy[iSequence]=value;
+	    } else if (value>upper_[iSequence]+1.0e-9) {
+	      upper_[iSequence]=value;
+	      upperCopy[iSequence]=value;
+	    }
+	  }
+	  reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(1, saveDuals, -1, data);
+	}
+      }
+      if (!problemStatus_) {
+	if (nLowerChange||nUpperChange) {
+#ifndef ALL_DANTZIG
+	  // Dantzig 
+	  savePivot = dualRowPivot_;
+	  dualRowPivot_ = new ClpDualRowDantzig();
+	  dualRowPivot_->setModel(this);
+#endif
+	  //for (int i=0;i<numberRows_+numberColumns_;i++)
+	  //setFakeBound(i, noFake);
+	  // Now do parametrics
+	  handler_->message(CLP_PARAMETRICS_STATS, messages_)
+	    << startingTheta << objectiveValue() << CoinMessageEol;
+	  bool canSkipFactorization=true;
+	  while (!returnCode) {
+	    paramData.startingTheta=startingTheta;
+	    paramData.endingTheta=endingTheta;
+	    returnCode = parametricsLoop(paramData,
+					 data,canSkipFactorization);
+	    startingTheta=paramData.startingTheta;
+	    endingTheta=paramData.endingTheta;
+	    canSkipFactorization=false;
+	    if (!returnCode) {
+	      //startingTheta = endingTheta;
+	      //endingTheta = saveEndingTheta;
+	      handler_->message(CLP_PARAMETRICS_STATS, messages_)
+		<< startingTheta << objectiveValue() << CoinMessageEol;
+	      if (startingTheta >= endingTheta-primalTolerance_
+		  ||problemStatus_==2)
+		break;
+	    } else if (returnCode == -1) {
+	      // trouble - do external solve
+	      abort(); //needToDoSomething = true;
+	    } else if (problemStatus_==1) {
+	      // can't move any further
+	      handler_->message(CLP_PARAMETRICS_STATS, messages_)
+		<< endingTheta << objectiveValue() << CoinMessageEol;
+	      problemStatus_=0;
+	    }
+	  }
+	}
+	dualBound_ = saveDualBound;
+	//reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(0, saveDuals, -1, data);
+      } else {
+	// check if empty
+	//if (!numberRows_||!matrix_->getNumElements()) {
+	// success
+#ifdef CLP_USER_DRIVEN
+	//theta_ = endingTheta;
+	//eventHandler_->event(ClpEventHandler::theta);
+#endif
+	//}
+      }
+    }
+    if (problemStatus_==2) {
+      delete [] ray_;
+      ray_ = new double [numberColumns_];
+    }
+    if (swapped&&lower_) {
+      double * temp=saveLower;
+      saveLower=lower_;
+      lower_=temp;
+      temp=saveUpper;
+      saveUpper=upper_;
+      upper_=temp;
+    }
+    reinterpret_cast<ClpSimplexDual *> (this)->finishSolve(0);
+  }    
+  if (!scalingFlag_) {
+    memcpy(columnLower_,lowerCopy,numberColumns_*sizeof(double));
+    memcpy(columnUpper_,upperCopy,numberColumns_*sizeof(double));
+    memcpy(rowLower_,lowerCopy+numberColumns_,
+	   numberRows_*sizeof(double));
+    memcpy(rowUpper_,upperCopy+numberColumns_,
+	   numberRows_*sizeof(double));
+  } else {
+    //  extra for unscaled
+    double * unscaledCopy;
+    unscaledCopy = lowerCopy + numberTotal; 
+    memcpy(columnLower_,unscaledCopy,numberColumns_*sizeof(double));
+    memcpy(rowLower_,unscaledCopy+numberColumns_,
+	   numberRows_*sizeof(double));
+    unscaledCopy = upperCopy + numberTotal; 
+    memcpy(columnUpper_,unscaledCopy,numberColumns_*sizeof(double));
+    memcpy(rowUpper_,unscaledCopy+numberColumns_,
+	   numberRows_*sizeof(double));
+  }
+  delete [] saveLower;
+  delete [] saveUpper;
+#ifdef ALL_DANTZIG
+  if (savePivot) {
+#endif
+    delete dualRowPivot_;
+    dualRowPivot_ = savePivot;
+#ifdef ALL_DANTZIG
+  }
+#endif
+  // Restore any saved stuff
+  restoreData(data);
+  perturbation_ = savePerturbation;
+  delete rowArray_[4];
+  rowArray_[4]=NULL;
+  delete rowArray_[5];
+  rowArray_[5]=NULL;
+  char line[100];
+  sprintf(line,"Ending theta %g\n", endingTheta);
+  handler_->message(CLP_GENERAL,messages_)
+    << line << CoinMessageEol;
+  return problemStatus_;
+}
+int
+ClpSimplexOther::parametricsLoop(parametricsData & paramData,
+                                 ClpDataSave & data,bool canSkipFactorization)
+{
+  double & startingTheta = paramData.startingTheta;
+  double & endingTheta = paramData.endingTheta;
+  int numberTotal = numberRows_+numberColumns_;
+  // stuff is already at starting
+  const int * lowerList = paramData.lowerList;
+  const int * upperList = paramData.upperList;
+  problemStatus_ = -1;
+  //double saveEndingTheta=endingTheta;
+
+  // This says whether to restore things etc
+  // startup will have factorized so can skip
+  int factorType = 0;
+  // Start check for cycles
+  progress_.startCheck();
+  // Say change made on first iteration
+  changeMade_ = 1;
+  /*
+    Status of problem:
+    0 - optimal
+    1 - infeasible
+    2 - unbounded
+    -1 - iterating
+    -2 - factorization wanted
+    -3 - redo checking without factorization
+    -4 - looks infeasible
+  */
+  while (problemStatus_ < 0) {
+    int iRow, iColumn;
+    // clear
+    for (iRow = 0; iRow < 6; iRow++) {
+      rowArray_[iRow]->clear();
+    }
+    
+    for (iColumn = 0; iColumn < 2; iColumn++) {
+      columnArray_[iColumn]->clear();
+    }
+    
+    // give matrix (and model costs and bounds a chance to be
+    // refreshed (normally null)
+    matrix_->refresh(this);
+    // may factorize, checks if problem finished
+    if (!canSkipFactorization)
+      statusOfProblemInParametrics(factorType, data);
+    canSkipFactorization=false;
+    if (numberPrimalInfeasibilities_) {
+      if (largestPrimalError_>1.0e3&&startingTheta>1.0e10) {
+	// treat as success
+	problemStatus_=0;
+	endingTheta=startingTheta;
+	break;
+      }
+      // probably can get rid of this if we adjust every change in theta
+      //printf("INFEAS %d %g\n",numberPrimalInfeasibilities_,
+      //     sumPrimalInfeasibilities_);
+      const double * lowerChange = lower_+numberTotal;
+      const double * upperChange = upper_+numberTotal;
+      const double * startLower = lowerChange+numberTotal;
+      const double * startUpper = upperChange+numberTotal;
+      //startingTheta -= 1.0e-7;
+      int nLowerChange = lowerList[-1];
+      for (int i = 0; i < nLowerChange; i++) {
+	int iSequence = lowerList[i];
+	lower_[iSequence] = startLower[iSequence] + startingTheta * lowerChange[iSequence];
+      }
+      int nUpperChange = upperList[-1];
+      for (int i = 0; i < nUpperChange; i++) {
+	int iSequence = upperList[i];
+	upper_[iSequence] = startUpper[iSequence] + startingTheta * upperChange[iSequence];
+      }
+      // adjust rhs in case dual uses
+      memcpy(columnLower_,lower_,numberColumns_*sizeof(double));
+      memcpy(rowLower_,lower_+numberColumns_,numberRows_*sizeof(double));
+      memcpy(columnUpper_,upper_,numberColumns_*sizeof(double));
+      memcpy(rowUpper_,upper_+numberColumns_,numberRows_*sizeof(double));
+      if (rowScale_) {
+	for (int i=0;i<numberColumns_;i++) {
+	  double multiplier = columnScale_[i];
+	  if (columnLower_[i]>-1.0e20)
+	    columnLower_[i] *= multiplier;
+	  if (columnUpper_[i]<1.0e20)
+	    columnUpper_[i] *= multiplier;
+	}
+	for (int i=0;i<numberRows_;i++) {
+	  double multiplier = inverseRowScale_[i];
+	  if (rowLower_[i]>-1.0e20)
+	    rowLower_[i] *= multiplier;
+	  if (rowUpper_[i]<1.0e20)
+	    rowUpper_[i] *= multiplier;
+	}
+      }
+      double * saveDuals = NULL;
+      problemStatus_=-1;
+      ClpObjective * saveObjective = objective_;
+      reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(0, saveDuals, -1, data);
+      if (saveObjective!=objective_) {
+	delete objective_;
+	objective_=saveObjective;
+      }
+      int pass=100;
+      double moved=0.0;
+      while(sumPrimalInfeasibilities_) {
+	//printf("INFEAS pass %d %d %g\n",100-pass,numberPrimalInfeasibilities_,
+	//     sumPrimalInfeasibilities_);
+	pass--;
+	if (!pass)
+	  break;
+	problemStatus_=-1;
+	for (int iSequence=numberColumns_;iSequence<numberTotal;iSequence++) {
+	  double value=solution_[iSequence];
+	  if (value<lower_[iSequence]-1.0e-9) {
+	    moved += lower_[iSequence]-value;
+	    lower_[iSequence]=value;
+	  } else if (value>upper_[iSequence]+1.0e-9) {
+	    moved += upper_[iSequence]-value;
+	    upper_[iSequence]=value;
+	  }
+	}
+	if (!moved) {
+	  for (int iSequence=0;iSequence<numberColumns_;iSequence++) {
+	    double value=solution_[iSequence];
+	    if (value<lower_[iSequence]-1.0e-9) {
+	      moved += lower_[iSequence]-value;
+	      lower_[iSequence]=value;
+	    } else if (value>upper_[iSequence]+1.0e-9) {
+	      moved += upper_[iSequence]-value;
+	      upper_[iSequence]=value;
+	    }
+	  }
+	}
+	assert (moved);
+	reinterpret_cast<ClpSimplexDual *> (this)->gutsOfDual(1, saveDuals, -1, data);
+      }
+      // adjust
+      //printf("Should adjust - moved %g\n",moved);
+    }
+    // Say good factorization
+    factorType = 1;
+    if (data.sparseThreshold_) {
+      // use default at present
+      factorization_->sparseThreshold(0);
+      factorization_->goSparse();
+    }
+    
+    // exit if victory declared
+    if (problemStatus_ >= 0 && startingTheta>=endingTheta-1.0e-7 )
+      break;
+    
+    // test for maximum iterations
+    if (hitMaximumIterations()) {
+      problemStatus_ = 3;
+      break;
+    }
+#ifdef CLP_USER_DRIVEN
+    // Check event
+    {
+      int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
+      if (status >= 0) {
+	problemStatus_ = 5;
+	secondaryStatus_ = ClpEventHandler::endOfFactorization;
+	break;
+      }
+    }
+#endif
+    // Do iterations
+    problemStatus_=-1;
+    whileIterating(paramData, 0.0,
+		   NULL);
+    //startingTheta = endingTheta;
+    //endingTheta = saveEndingTheta;
+  }
+  if (!problemStatus_/*||problemStatus_==2*/) {
+    theta_ = endingTheta;
+#ifdef CLP_USER_DRIVEN
+    {
+      double saveTheta=theta_;
+      theta_ = endingTheta;
+      int status=eventHandler_->event(ClpEventHandler::theta);
+      if (status>=0&&status<10) {
+	endingTheta=theta_;
+	theta_=saveTheta;
+	problemStatus_=-1;
+      } else {
+	if (status>=10) {
+	  problemStatus_=status-10;
+	  startingTheta=endingTheta;
+	}
+	theta_=saveTheta;
+      }
+    }
+#endif
+    return 0;
+  } else if (problemStatus_ == 10) {
+    return -1;
+  } else {
+    return problemStatus_;
+  }
+}
+/* Checks if finished.  Updates status */
+void
+ClpSimplexOther::statusOfProblemInParametrics(int type, ClpDataSave & saveData)
+{
+     if (type == 2) {
+          // trouble - go to recovery
+          problemStatus_ = 10;
+          return;
+     }
+     if (problemStatus_ > -3 || factorization_->pivots()) {
+          // factorize
+          // later on we will need to recover from singularities
+          // also we could skip if first time
+          if (type) {
+               // is factorization okay?
+               if (internalFactorize(1)) {
+                    // trouble - go to recovery
+                    problemStatus_ = 10;
+                    return;
+               }
+          }
+          if (problemStatus_ != -4 || factorization_->pivots() > 10)
+               problemStatus_ = -3;
+     }
+     // at this stage status is -3 or -4 if looks infeasible
+     // get primal and dual solutions
+     gutsOfSolution(NULL, NULL);
+     double realDualInfeasibilities = sumDualInfeasibilities_;
+     // If bad accuracy treat as singular
+     if ((largestPrimalError_ > 1.0e15 || largestDualError_ > 1.0e15) && numberIterations_) {
+          // trouble - go to recovery
+          problemStatus_ = 10;
+          return;
+     } else if (largestPrimalError_ < 1.0e-7 && largestDualError_ < 1.0e-7) {
+          // Can reduce tolerance
+          double newTolerance = CoinMax(0.99 * factorization_->pivotTolerance(), saveData.pivotTolerance_);
+          factorization_->pivotTolerance(newTolerance);
+     }
+     // Check if looping
+     int loop;
+     if (type != 2)
+          loop = progress_.looping();
+     else
+          loop = -1;
+     if (loop >= 0) {
+          problemStatus_ = loop; //exit if in loop
+          if (!problemStatus_) {
+               // declaring victory
+               numberPrimalInfeasibilities_ = 0;
+               sumPrimalInfeasibilities_ = 0.0;
+          } else {
+               problemStatus_ = 10; // instead - try other algorithm
+          }
+          return;
+     } else if (loop < -1) {
+          // something may have changed
+          gutsOfSolution(NULL, NULL);
+     }
+     progressFlag_ = 0; //reset progress flag
+     if (handler_->detail(CLP_SIMPLEX_STATUS, messages_) < 100) {
+          handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                    << numberIterations_ << objectiveValue();
+          handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                    << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+          handler_->printing(sumDualInfeasibilities_ > 0.0)
+                    << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+          handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                             < numberDualInfeasibilities_)
+                    << numberDualInfeasibilitiesWithoutFree_;
+          handler_->message() << CoinMessageEol;
+     }
+#ifdef CLP_USER_DRIVEN
+     if (sumPrimalInfeasibilities_&&sumPrimalInfeasibilities_<1.0e-7) {
+       int status=eventHandler_->event(ClpEventHandler::slightlyInfeasible);
+       if (status>=0) {
+	 // fix up
+	 for (int iSequence=0;iSequence<numberRows_+numberColumns_;iSequence++) {
+	   double value=solution_[iSequence];
+	   if (value<=lower_[iSequence]-primalTolerance_) {
+	     lower_[iSequence]=value;
+	   } else if (value>=upper_[iSequence]+primalTolerance_) {
+	     upper_[iSequence]=value;
+	   }
+	 }
+	 numberPrimalInfeasibilities_ = 0;
+	 sumPrimalInfeasibilities_ = 0.0;
+       }
+     }
+#endif
+     /* If we are primal feasible and any dual infeasibilities are on
+        free variables then it is better to go to primal */
+     if (!numberPrimalInfeasibilities_ && !numberDualInfeasibilitiesWithoutFree_ &&
+               numberDualInfeasibilities_) {
+          problemStatus_ = 10;
+          return;
+     }
+
+     // check optimal
+     // give code benefit of doubt
+     if (sumOfRelaxedDualInfeasibilities_ == 0.0 &&
+               sumOfRelaxedPrimalInfeasibilities_ == 0.0) {
+          // say optimal (with these bounds etc)
+          numberDualInfeasibilities_ = 0;
+          sumDualInfeasibilities_ = 0.0;
+          numberPrimalInfeasibilities_ = 0;
+          sumPrimalInfeasibilities_ = 0.0;
+     }
+     if (dualFeasible() || problemStatus_ == -4) {
+          progress_.modifyObjective(objectiveValue_
+                                    - sumDualInfeasibilities_ * dualBound_);
+     }
+     if (numberPrimalInfeasibilities_) {
+          if (problemStatus_ == -4 || problemStatus_ == -5) {
+               problemStatus_ = 1; // infeasible
+          }
+     } else if (numberDualInfeasibilities_) {
+          // clean up
+          problemStatus_ = 10;
+     } else {
+          problemStatus_ = 0;
+     }
+     lastGoodIteration_ = numberIterations_;
+     if (problemStatus_ < 0) {
+          sumDualInfeasibilities_ = realDualInfeasibilities; // back to say be careful
+          if (sumDualInfeasibilities_)
+               numberDualInfeasibilities_ = 1;
+     }
+     // Allow matrices to be sorted etc
+     int fake = -999; // signal sort
+     matrix_->correctSequence(this, fake, fake);
+}
+//static double lastThetaX=0.0;
+/* This has the flow between re-factorizations
+   Reasons to come out:
+   -1 iterations etc
+   -2 inaccuracy
+   -3 slight inaccuracy (and done iterations)
+   +0 looks optimal (might be unbounded - but we will investigate)
+   +1 looks infeasible
+   +3 max iterations
+   +4 accuracy problems
+*/
+int
+ClpSimplexOther::whileIterating(parametricsData & paramData, double /*reportIncrement*/,
+                                const double * /*changeObjective*/)
+{
+  double & startingTheta = paramData.startingTheta;
+  double & endingTheta = paramData.endingTheta;
+  const double * lowerChange = paramData.lowerChange;
+  const double * upperChange = paramData.upperChange;
+  int numberTotal = numberColumns_ + numberRows_;
+  const int * lowerList = paramData.lowerList;
+  const int * upperList = paramData.upperList;
+  //#define CLP_PARAMETRIC_DENSE_ARRAYS 2
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+  double * lowerGap = paramData.lowerGap;
+  double * upperGap = paramData.upperGap;
+  double * lowerCoefficient = paramData.lowerCoefficient;
+  double * upperCoefficient = paramData.upperCoefficient;
+#endif
+  // do basic pointers
+  int * backwardBasic = paramData.backwardBasic;
+  for (int i=0;i<numberTotal;i++)
+    backwardBasic[i]=-1;
+  for (int i=0;i<numberRows_;i++) {
+    int iPivot=pivotVariable_[i];
+    backwardBasic[iPivot]=i;
+  }
+     {
+          int i;
+          for (i = 0; i < 4; i++) {
+               rowArray_[i]->clear();
+          }
+          for (i = 0; i < 2; i++) {
+               columnArray_[i]->clear();
+          }
+     }
+     // if can't trust much and long way from optimal then relax
+     if (largestPrimalError_ > 10.0)
+          factorization_->relaxAccuracyCheck(CoinMin(1.0e2, largestPrimalError_ / 10.0));
+     else
+          factorization_->relaxAccuracyCheck(1.0);
+     // status stays at -1 while iterating, >=0 finished, -2 to invert
+     // status -3 to go to top without an invert
+     int returnCode = -1;
+     double lastTheta = startingTheta;
+     double useTheta = startingTheta;
+     while (problemStatus_ == -1) {
+          double increaseTheta = CoinMin(endingTheta - lastTheta, 1.0e50);
+          // Get theta for bounds - we know can't crossover
+          int pivotType = nextTheta(1, increaseTheta, paramData,
+                                     NULL);
+	  useTheta += theta_;
+	  double change = useTheta - lastTheta;
+	  if (paramData.firstIteration) {
+	    // redo rhs etc to make as accurate as possible
+	    paramData.firstIteration=false;
+	    if (change>1.0e-14) {
+	      startingTheta=useTheta;
+	      lastTheta=startingTheta;
+	      change=0.0;
+	      // restore rhs
+	      const double * saveLower = paramData.lowerChange+2*numberTotal;
+	      memcpy(columnLower_,saveLower,numberColumns_*sizeof(double));
+	      memcpy(rowLower_,saveLower+numberColumns_,numberRows_*sizeof(double));
+	      const double * saveUpper = paramData.upperChange+2*numberTotal;
+	      memcpy(columnUpper_,saveUpper,numberColumns_*sizeof(double));
+	      memcpy(rowUpper_,saveUpper+numberColumns_,numberRows_*sizeof(double));
+	      paramData.startingTheta=startingTheta;
+	      computeRhsEtc(paramData);
+	      redoInternalArrays();
+	      // Update solution
+	      rowArray_[4]->clear();
+	      for (int i=0;i<numberTotal;i++) {
+		if (getStatus(i)==atLowerBound||getStatus(i)==isFixed)
+		  solution_[i]=lower_[i];
+		else if (getStatus(i)==atUpperBound)
+		  solution_[i]=upper_[i];
+	      }
+	      gutsOfSolution(NULL,NULL);
+	    }
+	  }
+	  if (change>1.0e-14) {
+	    int n;
+	    n=lowerList[-1];
+	    for (int i=0;i<n;i++) {
+	      int iSequence = lowerList[i];
+	      double thisChange = change * lowerChange[iSequence];
+	      double newValue = lower_[iSequence] + thisChange;
+	      lower_[iSequence] = newValue;
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+	      if (getStatus(iSequence)==basic) {
+		int iRow=backwardBasic[iSequence];
+		lowerGap[iRow] -= thisChange;
+	      } else if(getStatus(iSequence)==atLowerBound) {
+		solution_[iSequence] = newValue;
+	      }
+#else
+	      if(getStatus(iSequence)==atLowerBound) {
+		solution_[iSequence] = newValue;
+	      }
+#endif
+#if 0
+	      // may have to adjust other bound
+	      double otherValue = upper_[iSequence];
+	      if (otherValue-newValue<dualBound_) {
+		//originalBound(iSequence,useTheta,lowerChange,upperChange);
+		//reinterpret_cast<ClpSimplexDual *> ( this)->changeBound(iSequence);
+		//ClpTraceDebug (fabs(lower_[iSequence]-newValue)<1.0e-5);
+	      }
+#endif
+	    }
+	    n=upperList[-1];
+	    for (int i=0;i<n;i++) {
+	      int iSequence = upperList[i];
+	      double thisChange = change * upperChange[iSequence];
+	      double newValue = upper_[iSequence] + thisChange;
+	      upper_[iSequence] = newValue;
+	      if(getStatus(iSequence)==atUpperBound||
+		 getStatus(iSequence)==isFixed) {
+		solution_[iSequence] = newValue;
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+	      } else if (getStatus(iSequence)==basic) {
+		int iRow=backwardBasic[iSequence];
+		upperGap[iRow] += thisChange;
+#endif
+	      }
+	      // may have to adjust other bound
+	      double otherValue = lower_[iSequence];
+	      if (newValue-otherValue<dualBound_) {
+		//originalBound(iSequence,useTheta,lowerChange,upperChange);
+		//reinterpret_cast<ClpSimplexDual *> ( this)->changeBound(iSequence);
+		//ClpTraceDebug (fabs(upper_[iSequence]-newValue)<1.0e-5);
+	      }
+	    }
+	  }
+	  sequenceIn_=-1;
+          if (pivotType) {
+	    if (useTheta>lastTheta+1.0e-9) {
+	      handler_->message(CLP_PARAMETRICS_STATS, messages_)
+		<< useTheta << objectiveValue() << CoinMessageEol;
+	      lastTheta = useTheta;
+	    }
+	    problemStatus_ = -2;
+	    if (!factorization_->pivots()&&pivotRow_<0)
+	      problemStatus_=2;
+#ifdef CLP_USER_DRIVEN
+	    {
+	      double saveTheta=theta_;
+	      theta_ = endingTheta;
+	      if (problemStatus_==2&&theta_>paramData.acceptableMaxTheta)
+		theta_=COIN_DBL_MAX; // we have finished
+	      int status=eventHandler_->event(ClpEventHandler::theta);
+	      if (status>=0&&status<10) {
+		endingTheta=theta_;
+		problemStatus_=-1;
+		continue;
+	      } else {
+		if (status>=10)
+		  problemStatus_=status-10;
+		if (status<0)
+		  startingTheta = useTheta;
+	      }
+	      theta_=saveTheta;
+	    }
+#else
+	    startingTheta = useTheta;
+#endif
+	    return 4;
+	  }
+          // choose row to go out
+          //reinterpret_cast<ClpSimplexDual *> ( this)->dualRow(-1);
+          if (pivotRow_ >= 0) {
+               // we found a pivot row
+               if (handler_->detail(CLP_SIMPLEX_PIVOTROW, messages_) < 100) {
+                    handler_->message(CLP_SIMPLEX_PIVOTROW, messages_)
+                              << pivotRow_
+                              << CoinMessageEol;
+               }
+               // check accuracy of weights
+               dualRowPivot_->checkAccuracy();
+               // do ratio test for normal iteration
+               double bestPossiblePivot = bestPivot();
+               if (sequenceIn_ >= 0) {
+                    // normal iteration
+                    // update the incoming column
+                    double btranAlpha = -alpha_ * directionOut_; // for check
+#ifndef COIN_FAC_NEW
+                    unpackPacked(rowArray_[1]);
+#else
+                    unpack(rowArray_[1]);
+#endif
+                    // and update dual weights (can do in parallel - with extra array)
+		    rowArray_[2]->clear();
+                    alpha_ = dualRowPivot_->updateWeights(rowArray_[0],
+                                                          rowArray_[2],
+                                                          rowArray_[3],
+                                                          rowArray_[1]);
+                    // see if update stable
+#ifdef CLP_DEBUG
+                    if ((handler_->logLevel() & 32))
+                         printf("btran alpha %g, ftran alpha %g\n", btranAlpha, alpha_);
+#endif
+                    double checkValue = 1.0e-7;
+                    // if can't trust much and long way from optimal then relax
+                    if (largestPrimalError_ > 10.0)
+                         checkValue = CoinMin(1.0e-4, 1.0e-8 * largestPrimalError_);
+                    if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
+                              fabs(btranAlpha - alpha_) > checkValue*(1.0 + fabs(alpha_))) {
+                         handler_->message(CLP_DUAL_CHECK, messages_)
+                                   << btranAlpha
+                                   << alpha_
+                                   << CoinMessageEol;
+			 // clear arrays
+			 rowArray_[4]->clear();
+                         if (factorization_->pivots()) {
+                              dualRowPivot_->unrollWeights();
+                              problemStatus_ = -2; // factorize now
+                              rowArray_[0]->clear();
+                              rowArray_[1]->clear();
+                              columnArray_[0]->clear();
+                              returnCode = -2;
+                              break;
+                         } else {
+                              // take on more relaxed criterion
+                              double test;
+                              if (fabs(btranAlpha) < 1.0e-8 || fabs(alpha_) < 1.0e-8)
+                                   test = 1.0e-1 * fabs(alpha_);
+                              else
+                                   test = 1.0e-4 * (1.0 + fabs(alpha_));
+                              if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
+                                        fabs(btranAlpha - alpha_) > test) {
+                                   dualRowPivot_->unrollWeights();
+                                   // need to reject something
+                                   char x = isColumn(sequenceOut_) ? 'C' : 'R';
+                                   handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                             << x << sequenceWithin(sequenceOut_)
+                                             << CoinMessageEol;
+                                   setFlagged(sequenceOut_);
+                                   progress_.clearBadTimes();
+                                   lastBadIteration_ = numberIterations_; // say be more cautious
+                                   rowArray_[0]->clear();
+                                   rowArray_[1]->clear();
+                                   columnArray_[0]->clear();
+                                   if (fabs(alpha_) < 1.0e-10 && fabs(btranAlpha) < 1.0e-8 && numberIterations_ > 100) {
+                                        //printf("I think should declare infeasible\n");
+                                        problemStatus_ = 1;
+                                        returnCode = 1;
+                                        break;
+                                   }
+                                   continue;
+                              }
+                         }
+                    }
+                    // update duals BEFORE replaceColumn so can do updateColumn
+                    double objectiveChange = 0.0;
+                    // do duals first as variables may flip bounds
+                    // rowArray_[0] and columnArray_[0] may have flips
+                    // so use rowArray_[3] for work array from here on
+                    int nswapped = 0;
+                    //rowArray_[0]->cleanAndPackSafe(1.0e-60);
+                    //columnArray_[0]->cleanAndPackSafe(1.0e-60);
+#if CLP_CAN_HAVE_ZERO_OBJ
+		    if ((specialOptions_&2097152)==0) {
+#endif
+		      nswapped = reinterpret_cast<ClpSimplexDual *> ( this)->updateDualsInDual(rowArray_[0], columnArray_[0],
+											       rowArray_[2], theta_,
+											       objectiveChange, false);
+		      assert (!nswapped);
+#if CLP_CAN_HAVE_ZERO_OBJ
+		    } else {
+		      rowArray_[0]->clear();
+		      rowArray_[2]->clear();
+		      columnArray_[0]->clear();
+		    }
+#endif
+                    // which will change basic solution
+                    if (nswapped) {
+		      abort(); //needs testing
+                         factorization_->updateColumn(rowArray_[3], rowArray_[2]);
+                         dualRowPivot_->updatePrimalSolution(rowArray_[2],
+                                                             1.0, objectiveChange);
+                         // recompute dualOut_
+                         valueOut_ = solution_[sequenceOut_];
+                         if (directionOut_ < 0) {
+                              dualOut_ = valueOut_ - upperOut_;
+                         } else {
+                              dualOut_ = lowerOut_ - valueOut_;
+                         }
+                    }
+                    // amount primal will move
+                    double movement = -dualOut_ * directionOut_ / alpha_;
+                    // so objective should increase by fabs(dj)*movement
+                    // but we already have objective change - so check will be good
+                    if (objectiveChange + fabs(movement * dualIn_) < -1.0e-5) {
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("movement %g, swap change %g, rest %g  * %g\n",
+                                     objectiveChange + fabs(movement * dualIn_),
+                                     objectiveChange, movement, dualIn_);
+#endif
+			 assert (objectiveChange + fabs(movement * dualIn_) >= -1.0e-5);
+                         if(factorization_->pivots()) {
+                              // going backwards - factorize
+                              dualRowPivot_->unrollWeights();
+                              problemStatus_ = -2; // factorize now
+                              returnCode = -2;
+                              break;
+                         }
+                    }
+                    CoinAssert(fabs(dualOut_) < 1.0e50);
+                    // if stable replace in basis
+                    int updateStatus = factorization_->replaceColumn(this,
+                                       rowArray_[2],
+                                       rowArray_[1],
+                                       pivotRow_,
+                                       alpha_);
+                    // if no pivots, bad update but reasonable alpha - take and invert
+                    if (updateStatus == 2 &&
+                              !factorization_->pivots() && fabs(alpha_) > 1.0e-5)
+                         updateStatus = 4;
+                    if (updateStatus == 1 || updateStatus == 4) {
+                         // slight error
+                         if (factorization_->pivots() > 5 || updateStatus == 4) {
+                              problemStatus_ = -2; // factorize now
+                              returnCode = -3;
+                         }
+                    } else if (updateStatus == 2) {
+                         // major error
+                         dualRowPivot_->unrollWeights();
+                         // later we may need to unwind more e.g. fake bounds
+                         if (factorization_->pivots()) {
+                              problemStatus_ = -2; // factorize now
+                              returnCode = -2;
+                              break;
+                         } else {
+                              // need to reject something
+                              char x = isColumn(sequenceOut_) ? 'C' : 'R';
+                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                        << x << sequenceWithin(sequenceOut_)
+                                        << CoinMessageEol;
+                              setFlagged(sequenceOut_);
+                              progress_.clearBadTimes();
+                              lastBadIteration_ = numberIterations_; // say be more cautious
+                              rowArray_[0]->clear();
+                              rowArray_[1]->clear();
+                              columnArray_[0]->clear();
+                              // make sure dual feasible
+                              // look at all rows and columns
+                              double objectiveChange = 0.0;
+                              reinterpret_cast<ClpSimplexDual *> ( this)->updateDualsInDual(rowArray_[0], columnArray_[0], rowArray_[1],
+                                        0.0, objectiveChange, true);
+                              continue;
+                         }
+                    } else if (updateStatus == 3) {
+                         // out of memory
+                         // increase space if not many iterations
+                         if (factorization_->pivots() <
+                                   0.5 * factorization_->maximumPivots() &&
+                                   factorization_->pivots() < 200)
+                              factorization_->areaFactor(
+                                   factorization_->areaFactor() * 1.1);
+                         problemStatus_ = -2; // factorize now
+                    } else if (updateStatus == 5) {
+                         problemStatus_ = -2; // factorize now
+                    }
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+		    int * lowerActive = paramData.lowerActive;
+		    int * upperActive = paramData.upperActive;
+#endif
+		    // update change vector
+		    {
+		      double * work = rowArray_[1]->denseVector();
+		      int number = rowArray_[1]->getNumElements();
+		      int * which = rowArray_[1]->getIndices();
+		      assert (!rowArray_[4]->packedMode());
+#ifndef COIN_FAC_NEW
+		      assert (rowArray_[1]->packedMode());
+#else
+		      assert (!rowArray_[1]->packedMode());
+#endif
+		      double pivotValue = rowArray_[4]->denseVector()[pivotRow_];
+		      double multiplier = -pivotValue/alpha_;
+		      double * array=rowArray_[4]->denseVector();
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+		      int lowerN=lowerActive[-1];
+		      int upperN=upperActive[-1];
+#endif
+		      if (multiplier) {
+			for (int i = 0; i < number; i++) {
+			  int iRow = which[i];
+#ifndef COIN_FAC_NEW
+			  double alpha=multiplier*work[i];
+#else
+			  double alpha=multiplier*work[iRow];
+#endif
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+			  double alpha3 = alpha+array[iRow];
+			  int iSequence = pivotVariable_[iRow];
+			  double oldLower = lowerCoefficient[iRow];
+			  double oldUpper = upperCoefficient[iRow];
+			  if (lower_[iSequence]>-1.0e30) {
+			    //lowerGap[iRow]=value-lower_[iSequence];
+			    double alpha2 = alpha3 + lowerChange[iSequence];
+			    if (alpha2>1.0e-8)  {
+			      lowerCoefficient[iRow]=alpha2;
+			      if (!oldLower)
+				lowerActive[lowerN++]=iRow;
+			    } else {
+			      if (oldLower)
+				lowerCoefficient[iRow]=COIN_DBL_MIN;
+			    }
+			  } else {
+			    if (oldLower)
+			      lowerCoefficient[iRow]=COIN_DBL_MIN;
+			  }
+			  if (upper_[iSequence]<1.0e30) {
+			    //upperGap[iRow]=-(value-upper_[iSequence]);
+			    double alpha2 = -(alpha3+upperChange[iSequence]);
+			    if (alpha2>1.0e-8) {
+			      upperCoefficient[iRow]=alpha2;
+			      if (!oldUpper)
+				upperActive[upperN++]=iRow;
+			    } else {
+			      if (oldUpper)
+				upperCoefficient[iRow]=COIN_DBL_MIN;
+			    }
+			  } else {
+			    if (oldUpper)
+			      upperCoefficient[iRow]=COIN_DBL_MIN;
+			  }
+#endif
+			  rowArray_[4]->quickAdd(iRow,alpha);
+			}
+		      }
+		      pivotValue = array[pivotRow_];
+		      // we want pivot to be -multiplier
+		      rowArray_[4]->quickAdd(pivotRow_,-multiplier-pivotValue);
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+		      assert (lowerN>=0&&lowerN<=numberRows_);
+		      lowerActive[-1]=lowerN;
+		      upperActive[-1]=upperN;
+#endif
+		    }
+                    // update primal solution
+#if CLP_CAN_HAVE_ZERO_OBJ
+		    if ((specialOptions_&2097152)!=0) 
+		      theta_=0.0;
+#endif
+                    if (theta_ < 0.0) {
+#ifdef CLP_DEBUG
+                         if (handler_->logLevel() & 32)
+                              printf("negative theta %g\n", theta_);
+#endif
+                         theta_ = 0.0;
+                    }
+                    // do actual flips
+                    reinterpret_cast<ClpSimplexDual *> ( this)->flipBounds(rowArray_[0], columnArray_[0]);
+                    //rowArray_[1]->expand();
+#ifndef CLP_PARAMETRIC_DENSE_ARRAYS
+                    dualRowPivot_->updatePrimalSolution(rowArray_[1],
+                                                        movement,
+                                                        objectiveChange);
+#else
+		    // do by hand
+		    {
+		      double * work = rowArray_[1]->denseVector();
+		      int number = rowArray_[1]->getNumElements();
+		      int * which = rowArray_[1]->getIndices();
+		      int i;
+		      if (rowArray_[1]->packedMode()) {
+			for (i = 0; i < number; i++) {
+			  int iRow = which[i];
+			  int iSequence = pivotVariable_[iRow];
+			  double value = solution_[iSequence];
+			  double change = movement * work[i];
+			  value -= change;
+			  if (lower_[iSequence]>-1.0e30)
+			    lowerGap[iRow]=value-lower_[iSequence];
+			  if (upper_[iSequence]<1.0e30)
+			    upperGap[iRow]=-(value-upper_[iSequence]);
+			  solution_[iSequence] = value;
+			  objectiveChange -= change * cost_[iSequence];
+			  work[i] = 0.0;
+			}
+		      } else {
+			for (i = 0; i < number; i++) {
+			  int iRow = which[i];
+			  int iSequence = pivotVariable_[iRow];
+			  double value = solution_[iSequence];
+			  double change = movement * work[iRow];
+			  value -= change;
+			  solution_[iSequence] = value;
+			  objectiveChange -= change * cost_[iSequence];
+			  work[iRow] = 0.0;
+			}
+		      }
+		      rowArray_[1]->setNumElements(0);
+		    }
+#endif
+                    // modify dualout
+                    dualOut_ /= alpha_;
+                    dualOut_ *= -directionOut_;
+                    //setStatus(sequenceIn_,basic);
+                    dj_[sequenceIn_] = 0.0;
+                    //double oldValue = valueIn_;
+                    if (directionIn_ == -1) {
+                         // as if from upper bound
+                         valueIn_ = upperIn_ + dualOut_;
+                    } else {
+                         // as if from lower bound
+                         valueIn_ = lowerIn_ + dualOut_;
+                    }
+		    objectiveChange = 0.0;
+#if CLP_CAN_HAVE_ZERO_OBJ
+		    if ((specialOptions_&2097152)==0) {
+#endif
+		      for (int i=0;i<numberTotal;i++)
+			objectiveChange += solution_[i]*cost_[i];
+		      objectiveChange -= objectiveValue_;
+#if CLP_CAN_HAVE_ZERO_OBJ
+		    }
+#endif
+                    // outgoing
+                    originalBound(sequenceOut_,useTheta,lowerChange,upperChange);
+		    lowerOut_=lower_[sequenceOut_];
+		    upperOut_=upper_[sequenceOut_];
+                    // set dj to zero unless values pass
+                    if (directionOut_ > 0) {
+                         valueOut_ = lowerOut_;
+                         dj_[sequenceOut_] = theta_;
+#if CLP_CAN_HAVE_ZERO_OBJ>1
+#ifdef COIN_REUSE_RANDOM
+			 if ((specialOptions_&2097152)!=0) {
+			   dj_[sequenceOut_] = 1.0e-9*(1.0+CoinDrand48());;
+			 }
+#endif
+#endif
+                    } else {
+                         valueOut_ = upperOut_;
+                         dj_[sequenceOut_] = -theta_;
+#if CLP_CAN_HAVE_ZERO_OBJ>1
+#ifdef COIN_REUSE_RANDOM
+			 if ((specialOptions_&2097152)!=0) {
+			   dj_[sequenceOut_] = -1.0e-9*(1.0+CoinDrand48());;
+			 }
+#endif
+#endif
+                    }
+                    solution_[sequenceOut_] = valueOut_;
+                    int whatNext = housekeeping(objectiveChange);
+		    reinterpret_cast<ClpSimplexDual *>(this)->originalBound(sequenceIn_);
+		    assert (backwardBasic[sequenceOut_]==pivotRow_);
+		    backwardBasic[sequenceOut_]=-1;
+		    backwardBasic[sequenceIn_]=pivotRow_;
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+		    double value = solution_[sequenceIn_];
+		    double alpha = rowArray_[4]->denseVector()[pivotRow_];
+		    double oldLower = lowerCoefficient[pivotRow_];
+		    double oldUpper = upperCoefficient[pivotRow_];
+		    if (lower_[sequenceIn_]>-1.0e30) {
+		      lowerGap[pivotRow_]=value-lower_[sequenceIn_];
+		      double alpha2 = alpha + lowerChange[sequenceIn_];
+		      if (alpha2>1.0e-8)  {
+			lowerCoefficient[pivotRow_]=alpha2;
+			if (!oldLower) {
+			  int lowerN=lowerActive[-1];
+			  assert (lowerN>=0&&lowerN<numberRows_);
+			  lowerActive[lowerN]=pivotRow_;
+			  lowerActive[-1]=lowerN+1;
+			}
+		      } else {
+			if (oldLower)
+			  lowerCoefficient[pivotRow_]=COIN_DBL_MIN;
+		      }
+		    } else {
+		      if (oldLower)
+			lowerCoefficient[pivotRow_]=COIN_DBL_MIN;
+		    }
+		    if (upper_[sequenceIn_]<1.0e30) {
+		      upperGap[pivotRow_]=-(value-upper_[sequenceIn_]);
+		      double alpha2 = -(alpha+upperChange[sequenceIn_]);
+		      if (alpha2>1.0e-8) {
+			upperCoefficient[pivotRow_]=alpha2;
+			if (!oldUpper) {
+			  int upperN=upperActive[-1];
+			  assert (upperN>=0&&upperN<numberRows_);
+			  upperActive[upperN]=pivotRow_;
+			  upperActive[-1]=upperN+1;
+			}
+		      } else {
+			if (oldUpper)
+			  upperCoefficient[pivotRow_]=COIN_DBL_MIN;
+		      }
+		    } else {
+		      if (oldUpper)
+			upperCoefficient[pivotRow_]=COIN_DBL_MIN;
+		    }
+#endif
+		    {
+		      char in[200],out[200];
+		      int iSequence=sequenceIn_;
+		      if (iSequence<numberColumns_) {
+			if (lengthNames_) 
+			  strcpy(in,columnNames_[iSequence].c_str());
+			 else 
+			  sprintf(in,"C%7.7d",iSequence);
+		      } else {
+			iSequence -= numberColumns_;
+			if (lengthNames_) 
+			  strcpy(in,rowNames_[iSequence].c_str());
+			 else 
+			  sprintf(in,"R%7.7d",iSequence);
+		      }
+		      iSequence=sequenceOut_;
+		      if (iSequence<numberColumns_) {
+			if (lengthNames_) 
+			  strcpy(out,columnNames_[iSequence].c_str());
+			 else 
+			  sprintf(out,"C%7.7d",iSequence);
+		      } else {
+			iSequence -= numberColumns_;
+			if (lengthNames_) 
+			  strcpy(out,rowNames_[iSequence].c_str());
+			 else 
+			  sprintf(out,"R%7.7d",iSequence);
+		      }
+		      handler_->message(CLP_PARAMETRICS_STATS2, messages_)
+			<< useTheta << objectiveValue() 
+			<< in << out << CoinMessageEol;
+		    }
+		    if (useTheta>lastTheta+1.0e-9) {
+		      handler_->message(CLP_PARAMETRICS_STATS, messages_)
+			<< useTheta << objectiveValue() << CoinMessageEol;
+		      lastTheta = useTheta;
+		    }
+                    // and set bounds correctly
+                    originalBound(sequenceIn_,useTheta,lowerChange,upperChange);
+                    reinterpret_cast<ClpSimplexDual *> ( this)->changeBound(sequenceOut_);
+                    if (whatNext == 1) {
+                         problemStatus_ = -2; // refactorize
+                    } else if (whatNext == 2) {
+                         // maximum iterations or equivalent
+                         problemStatus_ = 3;
+                         returnCode = 3;
+                         break;
+                    }
+#ifdef CLP_USER_DRIVEN
+                    // Check event
+                    {
+                         int status = eventHandler_->event(ClpEventHandler::endOfIteration);
+                         if (status >= 0) {
+                              problemStatus_ = 5;
+                              secondaryStatus_ = ClpEventHandler::endOfIteration;
+                              returnCode = 4;
+                              break;
+                         }
+                    }
+#endif
+               } else {
+                    // no incoming column is valid
+#ifdef CLP_USER_DRIVEN
+		 rowArray_[0]->clear();
+		 columnArray_[0]->clear();
+		 theta_ = useTheta;
+		 lastTheta = useTheta;
+		 int action = eventHandler_->event(ClpEventHandler::noTheta);
+		 if (action>=0) {
+		   endingTheta=theta_;
+		   theta_ = 0.0;
+		   //adjust [4] from handler - but
+		   //rowArray_[4]->clear(); // temp
+		   if (action>=0&&action<10)
+		     problemStatus_=-1; // carry on
+		   else if (action==15)
+		     problemStatus_ =5; // say stopped
+		   returnCode = 1;
+		   if (action==0||action>=10) 
+		     break;
+		   else
+		     continue;
+		 } else {
+		 theta_ = 0.0;
+		 }
+#endif
+                    pivotRow_ = -1;
+#ifdef CLP_DEBUG
+                    if (handler_->logLevel() & 32)
+                         printf("** no column pivot\n");
+#endif
+                    if (factorization_->pivots() < 10) { 
+                         // If we have just factorized and infeasibility reasonable say infeas
+                         if (((specialOptions_ & 4096) != 0 || bestPossiblePivot < 1.0e-11) && dualBound_ > 1.0e8) {
+                              if (valueOut_ > upperOut_ + 1.0e-3 || valueOut_ < lowerOut_ - 1.0e-3
+                                        || (specialOptions_ & 64) == 0) {
+                                   // say infeasible
+                                   problemStatus_ = 1;
+                                   // unless primal feasible!!!!
+                                   //printf("%d %g %d %g\n",numberPrimalInfeasibilities_,sumPrimalInfeasibilities_,
+                                   //     numberDualInfeasibilities_,sumDualInfeasibilities_);
+                                   if (numberDualInfeasibilities_)
+                                        problemStatus_ = 10;
+                                   rowArray_[0]->clear();
+                                   columnArray_[0]->clear();
+                              }
+                         }
+                         // If special option set - put off as long as possible
+                         if ((specialOptions_ & 64) == 0) {
+                              problemStatus_ = -4; //say looks infeasible
+                         } else {
+                              // flag
+                              char x = isColumn(sequenceOut_) ? 'C' : 'R';
+                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                        << x << sequenceWithin(sequenceOut_)
+                                        << CoinMessageEol;
+                              setFlagged(sequenceOut_);
+                              if (!factorization_->pivots()) {
+                                   rowArray_[0]->clear();
+                                   columnArray_[0]->clear();
+                                   continue;
+                              }
+                         }
+                    }
+                    rowArray_[0]->clear();
+                    columnArray_[0]->clear();
+                    returnCode = 1;
+                    break;
+               }
+          } else {
+               // no pivot row
+#ifdef CLP_USER_DRIVEN
+	    {
+	      double saveTheta=theta_;
+	      theta_ = endingTheta;
+	      int status=eventHandler_->event(ClpEventHandler::theta);
+	      if (status>=0&&status<10) {
+		endingTheta=theta_;
+		theta_=saveTheta;
+		continue;
+	      } else {
+		theta_=saveTheta;
+	      }
+	    }
+#endif
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32)
+                    printf("** no row pivot\n");
+#endif
+               int numberPivots = factorization_->pivots();
+               bool specialCase;
+               int useNumberFake;
+               returnCode = 0;
+               if (numberPivots < 20 &&
+                         (specialOptions_ & 2048) != 0 && !numberChanged_ && perturbation_ >= 100
+                         && dualBound_ > 1.0e8) {
+                    specialCase = true;
+                    // as dual bound high - should be okay
+                    useNumberFake = 0;
+               } else {
+                    specialCase = false;
+                    useNumberFake = numberFake_;
+               }
+               if (!numberPivots || specialCase) {
+                    // may have crept through - so may be optimal
+                    // check any flagged variables
+                    int iRow;
+                    for (iRow = 0; iRow < numberRows_; iRow++) {
+                         int iPivot = pivotVariable_[iRow];
+                         if (flagged(iPivot))
+                              break;
+                    }
+                    if (iRow < numberRows_ && numberPivots) {
+                         // try factorization
+                         returnCode = -2;
+                    }
+
+                    if (useNumberFake || numberDualInfeasibilities_) {
+                         // may be dual infeasible
+                         problemStatus_ = -5;
+                    } else {
+                         if (iRow < numberRows_) {
+                              problemStatus_ = -5;
+                         } else {
+                              if (numberPivots) {
+                                   // objective may be wrong
+                                   objectiveValue_ = innerProduct(cost_,
+                                                                  numberColumns_ + numberRows_,
+                                                                  solution_);
+                                   objectiveValue_ += objective_->nonlinearOffset();
+                                   objectiveValue_ /= (objectiveScale_ * rhsScale_);
+                                   if ((specialOptions_ & 16384) == 0) {
+                                        // and dual_ may be wrong (i.e. for fixed or basic)
+                                        CoinIndexedVector * arrayVector = rowArray_[1];
+                                        arrayVector->clear();
+                                        int iRow;
+                                        double * array = arrayVector->denseVector();
+                                        /* Use dual_ instead of array
+                                           Even though dual_ is only numberRows_ long this is
+                                           okay as gets permuted to longer rowArray_[2]
+                                        */
+                                        arrayVector->setDenseVector(dual_);
+                                        int * index = arrayVector->getIndices();
+                                        int number = 0;
+                                        for (iRow = 0; iRow < numberRows_; iRow++) {
+                                             int iPivot = pivotVariable_[iRow];
+                                             double value = cost_[iPivot];
+                                             dual_[iRow] = value;
+                                             if (value) {
+                                                  index[number++] = iRow;
+                                             }
+                                        }
+                                        arrayVector->setNumElements(number);
+                                        // Extended duals before "updateTranspose"
+                                        matrix_->dualExpanded(this, arrayVector, NULL, 0);
+                                        // Btran basic costs
+                                        rowArray_[2]->clear();
+                                        factorization_->updateColumnTranspose(rowArray_[2], arrayVector);
+                                        // and return vector
+                                        arrayVector->setDenseVector(array);
+                                   }
+                              }
+                              problemStatus_ = 0;
+                              sumPrimalInfeasibilities_ = 0.0;
+                              if ((specialOptions_&(1024 + 16384)) != 0) {
+                                   CoinIndexedVector * arrayVector = rowArray_[1];
+                                   arrayVector->clear();
+                                   double * rhs = arrayVector->denseVector();
+                                   times(1.0, solution_, rhs);
+                                   bool bad2 = false;
+                                   int i;
+                                   for ( i = 0; i < numberRows_; i++) {
+                                        if (rhs[i] < rowLowerWork_[i] - primalTolerance_ ||
+                                                  rhs[i] > rowUpperWork_[i] + primalTolerance_) {
+                                             bad2 = true;
+                                        } else if (fabs(rhs[i] - rowActivityWork_[i]) > 1.0e-3) {
+                                        }
+                                        rhs[i] = 0.0;
+                                   }
+                                   for ( i = 0; i < numberColumns_; i++) {
+                                        if (solution_[i] < columnLowerWork_[i] - primalTolerance_ ||
+                                                  solution_[i] > columnUpperWork_[i] + primalTolerance_) {
+                                             bad2 = true;
+                                        }
+                                   }
+                                   if (bad2) {
+                                        problemStatus_ = -3;
+                                        returnCode = -2;
+                                        // Force to re-factorize early next time
+                                        int numberPivots = factorization_->pivots();
+                                        forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
+                                   }
+                              }
+                         }
+                    }
+               } else {
+                    problemStatus_ = -3;
+                    returnCode = -2;
+                    // Force to re-factorize early next time
+                    int numberPivots = factorization_->pivots();
+                    forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
+               }
+               break;
+          }
+     }
+     startingTheta = lastTheta+theta_;
+     return returnCode;
+}
+// Compute new rowLower_ etc (return negative if infeasible - otherwise largest change)
+double 
+ClpSimplexOther::computeRhsEtc( parametricsData & paramData)
+{
+  double maxTheta = COIN_DBL_MAX;
+  double largestChange=0.0;
+  double startingTheta = paramData.startingTheta;
+  const double * lowerChange = paramData.lowerChange+
+    paramData.unscaledChangesOffset;
+  const double * upperChange = paramData.upperChange+
+    paramData.unscaledChangesOffset;
+  for (int iRow = 0; iRow < numberRows_; iRow++) {
+    double lower = rowLower_[iRow];
+    double upper = rowUpper_[iRow];
+    double chgLower = lowerChange[numberColumns_+iRow];
+    largestChange=CoinMax(largestChange,fabs(chgLower));
+    double chgUpper = upperChange[numberColumns_+iRow];
+    largestChange=CoinMax(largestChange,fabs(chgUpper));
+    if (lower > -1.0e30 && upper < 1.0e30) {
+      if (lower + maxTheta * chgLower > upper + maxTheta * chgUpper) {
+	maxTheta = (upper - lower) / (chgLower - chgUpper);
+      }
+    }
+    lower+=startingTheta*chgLower;
+    upper+=startingTheta*chgUpper;
+#ifndef CLP_USER_DRIVEN
+    if (lower > upper) {
+      maxTheta = -1.0;
+      break;
+    }
+#endif
+    rowLower_[iRow]=lower;
+    rowUpper_[iRow]=upper;
+  }
+  for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+    double lower = columnLower_[iColumn];
+    double upper = columnUpper_[iColumn];
+    double chgLower = lowerChange[iColumn];
+    largestChange=CoinMax(largestChange,fabs(chgLower));
+    double chgUpper = upperChange[iColumn];
+    largestChange=CoinMax(largestChange,fabs(chgUpper));
+    if (lower > -1.0e30 && upper < 1.0e30) {
+      if (lower + maxTheta * chgLower > upper + maxTheta * chgUpper) {
+	maxTheta = (upper - lower) / (chgLower - chgUpper);
+      }
+    }
+    lower+=startingTheta*chgLower;
+    upper+=startingTheta*chgUpper;
+#ifndef CLP_USER_DRIVEN
+    if (lower > upper) {
+      maxTheta = -1.0;
+      break;
+    }
+#endif
+    columnLower_[iColumn]=lower;
+    columnUpper_[iColumn]=upper;
+  }
+#ifndef CLP_USER_DRIVEN
+  paramData.maxTheta=maxTheta;
+  if (maxTheta<0)
+    largestChange=-1.0; // signal infeasible
+#else
+  // maxTheta already set
+  /* given largest change element choose acceptable end
+     be safe and make sure difference < 0.1*tolerance */
+  double acceptableDifference=0.1*primalTolerance_/
+    CoinMax(largestChange,1.0);
+  paramData.acceptableMaxTheta=maxTheta-acceptableDifference;
+#endif
+  return largestChange;
+}
+// Redo lower_ from rowLower_ etc
+void 
+ClpSimplexOther::redoInternalArrays()
+{
+  double * lowerSave = lower_;
+  double * upperSave = upper_;
+  memcpy(lowerSave,columnLower_,numberColumns_*sizeof(double));
+  memcpy(lowerSave+numberColumns_,rowLower_,numberRows_*sizeof(double));
+  memcpy(upperSave,columnUpper_,numberColumns_*sizeof(double));
+  memcpy(upperSave+numberColumns_,rowUpper_,numberRows_*sizeof(double));
+  if (rowScale_) {
+    // scale arrays
+    for (int i=0;i<numberColumns_;i++) {
+      double multiplier = inverseColumnScale_[i];
+      if (lowerSave[i]>-1.0e20)
+	lowerSave[i] *= multiplier;
+      if (upperSave[i]<1.0e20)
+	upperSave[i] *= multiplier;
+    }
+    lowerSave += numberColumns_;
+    upperSave += numberColumns_;
+    for (int i=0;i<numberRows_;i++) {
+      double multiplier = rowScale_[i];
+      if (lowerSave[i]>-1.0e20)
+	lowerSave[i] *= multiplier;
+      if (upperSave[i]<1.0e20)
+	upperSave[i] *= multiplier;
+    }
+  }
+}
+#if 0
+static int zzzzzz=0;
+int zzzzzzOther=0;
+#endif
+// Finds best possible pivot
+double 
+ClpSimplexOther::bestPivot(bool justColumns)
+{
+  // Get good size for pivot
+  // Allow first few iterations to take tiny
+  double acceptablePivot = 1.0e-9;
+  if (numberIterations_ > 100)
+    acceptablePivot = 1.0e-8;
+  if (factorization_->pivots() > 10 ||
+      (factorization_->pivots() && sumDualInfeasibilities_))
+    acceptablePivot = 1.0e-5; // if we have iterated be more strict
+  else if (factorization_->pivots() > 5)
+    acceptablePivot = 1.0e-6; // if we have iterated be slightly more strict
+  else if (factorization_->pivots())
+    acceptablePivot = 1.0e-8; // relax
+  double bestPossiblePivot = 1.0;
+  // get sign for finding row of tableau
+  // normal iteration
+  // create as packed
+  double direction = directionOut_;
+#ifndef COIN_FAC_NEW
+  rowArray_[0]->createPacked(1, &pivotRow_, &direction);
+#else
+  rowArray_[0]->createOneUnpackedElement(pivotRow_, direction);
+#endif
+  factorization_->updateColumnTranspose(rowArray_[1], rowArray_[0]);
+  // put row of tableau in rowArray[0] and columnArray[0]
+  matrix_->transposeTimes(this, -1.0,
+			  rowArray_[0], rowArray_[3], columnArray_[0]);
+  sequenceIn_=-1;
+  if (justColumns)
+    rowArray_[0]->clear();
+  // do ratio test for normal iteration
+  bestPossiblePivot = 
+    reinterpret_cast<ClpSimplexDual *> 
+    ( this)->dualColumn(rowArray_[0],
+			columnArray_[0], columnArray_[1],
+			rowArray_[3], acceptablePivot, NULL);
+  return bestPossiblePivot;
+}
+// Computes next theta and says if objective or bounds (0= bounds, 1 objective, -1 none)
+int
+ClpSimplexOther::nextTheta(int /*type*/, double maxTheta, parametricsData & paramData,
+                           const double * /*changeObjective*/)
+{
+  const double * lowerChange = paramData.lowerChange;
+  const double * upperChange = paramData.upperChange;
+  const int * lowerList = paramData.lowerList;
+  const int * upperList = paramData.upperList;
+  int iSequence;
+  bool toLower = false;
+  //assert (type==1);
+  // may need to decide based on model?
+  bool needFullUpdate = rowArray_[4]->getNumElements()==0;
+  double * array = rowArray_[4]->denseVector();
+  //rowArray_[4]->checkClean();
+  const int * row = matrix_->getIndices();
+  const int * columnLength = matrix_->getVectorLengths();
+  const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+  const double * elementByColumn = matrix_->getElements();
+#if 0
+  double tempArray[5000];
+  bool checkIt=false;
+  if (factorization_->pivots()&&!needFullUpdate&&sequenceIn_<0) {
+    memcpy(tempArray,array,numberRows_*sizeof(double));
+    checkIt=true;
+    needFullUpdate=true;
+  }
+#endif
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+  double * lowerGap = paramData.lowerGap;
+  double * upperGap = paramData.upperGap;
+  double * lowerCoefficient = paramData.lowerCoefficient;
+  double * upperCoefficient = paramData.upperCoefficient;
+  int * lowerActive=paramData.lowerActive;
+  int * upperActive=paramData.upperActive;
+#endif
+  if (!factorization_->pivots()||needFullUpdate) {
+    //zzzzzz=0;
+    rowArray_[4]->clear();
+    // get change
+    if (!rowScale_) {
+      int n;
+      n=lowerList[-2];
+      int i;
+      for (i=0;i<n;i++) {
+	int iSequence = lowerList[i];
+	assert (iSequence<numberColumns_);
+	if (getColumnStatus(iSequence)==atLowerBound) {
+	  double value=lowerChange[iSequence];
+	  for (CoinBigIndex j = columnStart[iSequence];
+	       j < columnStart[iSequence] + columnLength[iSequence]; j++) {
+	    rowArray_[4]->quickAdd(row[j], elementByColumn[j]*value);
+	  }
+	}
+      }
+      n=lowerList[-1];
+      const double * change = lowerChange+numberColumns_;
+      for (;i<n;i++) {
+	int iSequence = lowerList[i]-numberColumns_;
+	assert (iSequence>=0);
+	if (getRowStatus(iSequence)==atLowerBound) {
+	  double value=change[iSequence];
+	  rowArray_[4]->quickAdd(iSequence, -value);
+	}
+      }
+      n=upperList[-2];
+      for (i=0;i<n;i++) {
+	int iSequence = upperList[i];
+	assert (iSequence<numberColumns_);
+	if (getColumnStatus(iSequence)==atUpperBound) {
+	  double value=upperChange[iSequence];
+	  for (CoinBigIndex j = columnStart[iSequence];
+	       j < columnStart[iSequence] + columnLength[iSequence]; j++) {
+	    rowArray_[4]->quickAdd(row[j], elementByColumn[j]*value);
+	  }
+	}
+      }
+      n=upperList[-1];
+      change = upperChange+numberColumns_;
+      for (;i<n;i++) {
+	int iSequence = upperList[i]-numberColumns_;
+	assert (iSequence>=0);
+	if (getRowStatus(iSequence)==atUpperBound) {
+	  double value=change[iSequence];
+	  rowArray_[4]->quickAdd(iSequence, -value);
+	}
+      }
+    } else {
+      int n;
+      n=lowerList[-2];
+      int i;
+      for (i=0;i<n;i++) {
+	int iSequence = lowerList[i];
+	assert (iSequence<numberColumns_);
+	if (getColumnStatus(iSequence)==atLowerBound) {
+	  double value=lowerChange[iSequence];
+	  // apply scaling
+	  double scale = columnScale_[iSequence];
+	  for (CoinBigIndex j = columnStart[iSequence];
+	       j < columnStart[iSequence] + columnLength[iSequence]; j++) {
+	    int iRow = row[j];
+	    rowArray_[4]->quickAdd(iRow, elementByColumn[j]*scale * rowScale_[iRow]*value);
+	  }
+	}
+      }
+      n=lowerList[-1];
+      const double * change = lowerChange+numberColumns_;
+      for (;i<n;i++) {
+	int iSequence = lowerList[i]-numberColumns_;
+	assert (iSequence>=0);
+	if (getRowStatus(iSequence)==atLowerBound) {
+	  double value=change[iSequence];
+	  rowArray_[4]->quickAdd(iSequence, -value);
+	}
+      }
+      n=upperList[-2];
+      for (i=0;i<n;i++) {
+	int iSequence = upperList[i];
+	assert (iSequence<numberColumns_);
+	if (getColumnStatus(iSequence)==atUpperBound) {
+	  double value=upperChange[iSequence];
+	  // apply scaling
+	  double scale = columnScale_[iSequence];
+	  for (CoinBigIndex j = columnStart[iSequence];
+	       j < columnStart[iSequence] + columnLength[iSequence]; j++) {
+	    int iRow = row[j];
+	    rowArray_[4]->quickAdd(iRow, elementByColumn[j]*scale * rowScale_[iRow]*value);
+	  }
+	}
+      }
+      n=upperList[-1];
+      change = upperChange+numberColumns_;
+      for (;i<n;i++) {
+	int iSequence = upperList[i]-numberColumns_;
+	assert (iSequence>=0);
+	if (getRowStatus(iSequence)==atUpperBound) {
+	  double value=change[iSequence];
+	  rowArray_[4]->quickAdd(iSequence, -value);
+	}
+      }
+    }
+    // ftran it
+    factorization_->updateColumn(rowArray_[0], rowArray_[4]);
+#if 0
+    if (checkIt) {
+      for (int i=0;i<numberRows_;i++) {
+	assert (fabs(tempArray[i]-array[i])<1.0e-8);
+      }
+    }
+#endif
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+    /* later for sparse - keep like CoinIndexedvector
+       and just redo here */
+    int lowerN=0;
+    int upperN=0;
+    memset(lowerCoefficient,0,numberRows_*sizeof(double));
+    memset(upperCoefficient,0,numberRows_*sizeof(double));
+    for (int iRow=0;iRow<numberRows_;iRow++) {
+      iSequence = pivotVariable_[iRow];
+      double currentSolution = solution_[iSequence];
+      double alpha = array[iRow];
+      double thetaCoefficientLower = lowerChange[iSequence] + alpha;
+      double thetaCoefficientUpper = upperChange[iSequence] + alpha;
+      if (thetaCoefficientLower > 1.0e-8&&lower_[iSequence]>-1.0e30) {
+	double currentLower = lower_[iSequence];
+	ClpTraceDebug (currentSolution >= currentLower - 100.0*primalTolerance_);
+	double gap=currentSolution-currentLower;
+	lowerGap[iRow]=gap;
+	lowerCoefficient[iRow]=thetaCoefficientLower;
+	lowerActive[lowerN++]=iRow;
+	//} else {
+	//lowerCoefficient[iRow]=0.0;
+      }
+      if (thetaCoefficientUpper < -1.0e-8&&upper_[iSequence]<1.0e30) {
+	double currentUpper = upper_[iSequence];
+	ClpTraceDebug (currentSolution <= currentUpper + 100.0*primalTolerance_);
+	double gap2=-(currentSolution-currentUpper); //positive
+	upperGap[iRow]=gap2;
+	upperCoefficient[iRow]=-thetaCoefficientUpper;
+	upperActive[upperN++]=iRow;
+      }
+    }
+    assert (lowerN>=0&&lowerN<=numberRows_);
+    lowerActive[-1]=lowerN;
+    upperActive[-1]=upperN;
+#endif
+  } else if (sequenceIn_>=0) {
+    //assert (sequenceIn_>=0);
+    assert (sequenceOut_>=0);
+    assert (sequenceIn_!=sequenceOut_);
+    double change = (directionIn_>0) ? -lowerChange[sequenceIn_] : -upperChange[sequenceIn_];
+    int needed=0;
+    assert (!rowArray_[5]->getNumElements());
+    if (change) {
+      if (sequenceIn_<numberColumns_) {
+	if (!rowScale_) {
+	  for (CoinBigIndex i = columnStart[sequenceIn_];
+	       i < columnStart[sequenceIn_] + columnLength[sequenceIn_]; i++) {
+	    rowArray_[5]->quickAdd(row[i], elementByColumn[i]*change);
+	  }
+	} else {
+	  // apply scaling
+	  double scale = columnScale_[sequenceIn_];
+	  for (CoinBigIndex i = columnStart[sequenceIn_];
+	       i < columnStart[sequenceIn_] + columnLength[sequenceIn_]; i++) {
+	    int iRow = row[i];
+	    rowArray_[5]->quickAdd(iRow, elementByColumn[i]*scale * rowScale_[iRow]*change);
+	  }
+	}
+      } else {
+	rowArray_[5]->insert(sequenceIn_-numberColumns_,-change);
+      }
+      needed++;
+    }
+    if (getStatus(sequenceOut_)==atLowerBound)
+      change=lowerChange[sequenceOut_];
+    else
+      change=upperChange[sequenceOut_];
+    if (change) {
+      if (sequenceOut_<numberColumns_) {
+	if (!rowScale_) {
+	  for (CoinBigIndex i = columnStart[sequenceOut_];
+	       i < columnStart[sequenceOut_] + columnLength[sequenceOut_]; i++) {
+	    rowArray_[5]->quickAdd(row[i], elementByColumn[i]*change);
+	  }
+	} else {
+	  // apply scaling
+	  double scale = columnScale_[sequenceOut_];
+	  for (CoinBigIndex i = columnStart[sequenceOut_];
+	       i < columnStart[sequenceOut_] + columnLength[sequenceOut_]; i++) {
+	    int iRow = row[i];
+	    rowArray_[5]->quickAdd(iRow, elementByColumn[i]*scale * rowScale_[iRow]*change);
+	  }
+	}
+      } else {
+	rowArray_[5]->quickAdd(sequenceOut_-numberColumns_,-change);
+      }
+      needed++;
+    }
+    //printf("seqin %d seqout %d needed %d\n",
+    //	   sequenceIn_,sequenceOut_,needed);
+    if (needed) {
+      // ftran it
+      factorization_->updateColumn(rowArray_[0], rowArray_[5]);
+      // add
+      double * array5 = rowArray_[5]->denseVector();
+      int * index5 = rowArray_[5]->getIndices();
+      int number5 = rowArray_[5]->getNumElements();
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+      int lowerN=lowerActive[-1];
+      int upperN=upperActive[-1];
+      int nIn4=rowArray_[4]->getNumElements();
+      int * index4 = rowArray_[4]->getIndices();
+#endif
+      for (int i = 0; i < number5; i++) {
+	int iPivot = index5[i];
+#ifndef CLP_PARAMETRIC_DENSE_ARRAYS
+	rowArray_[4]->quickAdd(iPivot,array5[iPivot]);
+#else
+	/* later for sparse - modify here */
+	int iSequence = pivotVariable_[iPivot];
+	double currentSolution = solution_[iSequence];
+	double currentAlpha = array[iPivot];
+	double alpha5 = array5[iPivot];
+	double alpha = currentAlpha+alpha5;
+	if (currentAlpha) {
+	  if (alpha) {
+	    array[iPivot] = alpha;
+	  } else {
+	    array[iPivot] = COIN_DBL_MIN;
+	  }
+	} else {
+	  index4[nIn4++] = iPivot;
+	  array[iPivot] = alpha;
+	}
+	double thetaCoefficientLower = lowerChange[iSequence] + alpha;
+	double thetaCoefficientUpper = upperChange[iSequence] + alpha;
+	double oldLower = lowerCoefficient[iPivot];
+	double oldUpper = upperCoefficient[iPivot];
+	if (thetaCoefficientLower > 1.0e-8&&lower_[iSequence]>-1.0e30) {
+	  double currentLower = lower_[iSequence];
+	  ClpTraceDebug (currentSolution >= currentLower - 100.0*primalTolerance_);
+	  double gap=currentSolution-currentLower;
+	  lowerGap[iPivot]=gap;
+	  lowerCoefficient[iPivot]=thetaCoefficientLower;
+	  if (!oldLower)
+	    lowerActive[lowerN++]=iPivot;
+	} else {
+	  if (oldLower)
+	    lowerCoefficient[iPivot]=COIN_DBL_MIN;
+	}
+	if (thetaCoefficientUpper < -1.0e-8&&upper_[iSequence]<1.0e30) {
+	  double currentUpper = upper_[iSequence];
+	  ClpTraceDebug (currentSolution <= currentUpper + 100.0*primalTolerance_);
+	  double gap2=-(currentSolution-currentUpper); //positive
+	  upperGap[iPivot]=gap2;
+	  upperCoefficient[iPivot]=-thetaCoefficientUpper;
+	  if (!oldUpper)
+	    upperActive[upperN++]=iPivot;
+	} else {
+	  if (oldUpper)
+	    upperCoefficient[iPivot]=COIN_DBL_MIN;
+	}
+#endif
+	array5[iPivot]=0.0;
+      }
+      rowArray_[5]->setNumElements(0);
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+      rowArray_[4]->setNumElements(nIn4);
+      assert (lowerN>=0&&lowerN<=numberRows_);
+      lowerActive[-1]=lowerN;
+      upperActive[-1]=upperN;
+#endif
+    }
+  }
+  const int * index = rowArray_[4]->getIndices();
+  int number = rowArray_[4]->getNumElements();
+#define TESTXX 0
+#ifndef CLP_PARAMETRIC_DENSE_ARRAYS //TESTXX
+  int * markDone = reinterpret_cast<int *>(paramData.markDone);
+  int nToZero=(numberRows_+numberColumns_+COIN_ANY_BITS_PER_INT-1)>>COIN_ANY_SHIFT_PER_INT;
+  memset(markDone,0,nToZero*sizeof(int));
+  const int * backwardBasic = paramData.backwardBasic;
+#endif
+  // first ones with alpha
+  double theta1=maxTheta;
+  int pivotRow1=-1;
+#ifndef CLP_PARAMETRIC_DENSE_ARRAYS //TESTXX
+  int pivotRow2=-1;
+  double theta2=maxTheta;
+#endif
+#ifndef CLP_PARAMETRIC_DENSE_ARRAYS //TESTXX
+  for (int i=0;i<number;i++) {
+    int iPivot=index[i];
+    iSequence = pivotVariable_[iPivot];
+    //assert(!markDone[iSequence]);
+    int word = iSequence >> COIN_ANY_SHIFT_PER_INT;
+    int bit = iSequence & COIN_ANY_MASK_PER_INT;
+    markDone[word] |= ( 1 << bit );
+    // solution value will be sol - theta*alpha
+    // bounds will be bounds + change *theta
+    double currentSolution = solution_[iSequence];
+    double alpha = array[iPivot];
+    double thetaCoefficientLower = lowerChange[iSequence] + alpha;
+    double thetaCoefficientUpper = upperChange[iSequence] + alpha;
+    if (thetaCoefficientLower > 1.0e-8) {
+      double currentLower = lower_[iSequence];
+      ClpTraceDebug (currentSolution >= currentLower - 100.0*primalTolerance_);
+      assert (currentSolution >= currentLower - 100.0*primalTolerance_);
+      double gap=currentSolution-currentLower;
+      if (thetaCoefficientLower*theta1>gap) {
+	theta1 = gap/thetaCoefficientLower;
+	//toLower=true;
+	pivotRow1=iPivot;
+      }
+    }
+    if (thetaCoefficientUpper < -1.0e-8) {
+      double currentUpper = upper_[iSequence];
+      ClpTraceDebug (currentSolution <= currentUpper + 100.0*primalTolerance_);
+      assert (currentSolution <= currentUpper + 100.0*primalTolerance_);
+      double gap2=currentSolution-currentUpper; //negative
+      if (thetaCoefficientUpper*theta2<gap2) {
+	theta2 = gap2/thetaCoefficientUpper;
+	//toLower=false;
+	pivotRow2=iPivot;
+      }
+    }
+  }
+  // now others
+  int nLook=lowerList[-1];
+  for (int i=0;i<nLook;i++) {
+    int iSequence = lowerList[i];
+    int word = iSequence >> COIN_ANY_SHIFT_PER_INT;
+    int bit = iSequence & COIN_ANY_MASK_PER_INT;
+    if (getColumnStatus(iSequence)==basic&&(markDone[word]&(1<<bit))==0) {
+      double currentSolution = solution_[iSequence];
+      double currentLower = lower_[iSequence];
+      ClpTraceDebug (currentSolution >= currentLower - 100.0*primalTolerance_);
+      double thetaCoefficient = lowerChange[iSequence];
+      if (thetaCoefficient > 0.0) {
+	double gap=currentSolution-currentLower;
+	if (thetaCoefficient*theta1>gap) {
+	  theta1 = gap/thetaCoefficient;
+	  //toLower=true;
+	  pivotRow1 = backwardBasic[iSequence];
+	}
+      }
+    }
+  }
+  nLook=upperList[-1];
+  for (int i=0;i<nLook;i++) {
+    int iSequence = upperList[i];
+    int word = iSequence >> COIN_ANY_SHIFT_PER_INT;
+    int bit = iSequence & COIN_ANY_MASK_PER_INT;
+    if (getColumnStatus(iSequence)==basic&&(markDone[word]&(1<<bit))==0) {
+      double currentSolution = solution_[iSequence];
+      double currentUpper = upper_[iSequence];
+      ClpTraceDebug (currentSolution <= currentUpper + 100.0*primalTolerance_);
+      double thetaCoefficient = upperChange[iSequence];
+      if (thetaCoefficient < 0) {
+	double gap=currentSolution-currentUpper; //negative
+	if (thetaCoefficient*theta2<gap) {
+	  theta2 = gap/thetaCoefficient;
+	  //toLower=false;
+	  pivotRow2 = backwardBasic[iSequence];
+	}
+      }
+    }
+  }
+  if (theta2<theta1) {
+    theta_=theta2;
+    toLower=false;
+    pivotRow_=pivotRow2;
+  } else {
+    theta_=theta1;
+    toLower=true;
+    pivotRow_=pivotRow1;
+  }
+#if 0 //TESTXX
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+  {
+    double * checkArray = new double[numberRows_];
+    memcpy(checkArray,lowerCoefficient,numberRows_*sizeof(double));
+    int lowerN=lowerActive[-1];
+    for (int i=0;i<lowerN;i++) {
+      int iRow=lowerActive[i];
+      int iSequence = pivotVariable_[iRow];
+      double alpha = array[iRow];
+      double thetaCoefficient = lowerChange[iSequence] + alpha;
+      if (thetaCoefficient > 1.0e-8&&lower_[iSequence]>-1.0e30) {
+	assert(fabs(checkArray[iRow]-thetaCoefficient)<1.0e-5);
+	if(fabs(checkArray[iRow]-thetaCoefficient)>1.0e-5) {
+	  abort();
+	}
+      } else {
+	assert (fabs(checkArray[iRow])<1.0e-12);
+	if (fabs(checkArray[iRow])>1.0e-12) {
+	  abort();
+	}
+      }
+      checkArray[iRow]=0.0;
+    }
+    for (int i=0;i<numberRows_;i++) {
+      assert (!checkArray[i]);
+      if (checkArray[i])
+	abort();
+    }
+    memcpy(checkArray,upperCoefficient,numberRows_*sizeof(double));
+    int upperN=upperActive[-1];
+    for (int i=0;i<upperN;i++) {
+      int iRow=upperActive[i];
+      int iSequence = pivotVariable_[iRow];
+      double alpha = array[iRow];
+      double thetaCoefficient = -(upperChange[iSequence] + alpha);
+      if (thetaCoefficient > 1.0e-8&&upper_[iSequence]<1.0e30) {
+	assert(fabs(checkArray[iRow]-thetaCoefficient)<1.0e-5);
+	if(fabs(checkArray[iRow]-thetaCoefficient)>1.0e-5) {
+	  abort();
+	}
+      } else {
+	assert (fabs(checkArray[iRow])<1.0e-12);
+	if (fabs(checkArray[iRow])>1.0e-12) {
+	  abort();
+	}
+      }
+      checkArray[iRow]=0.0;
+    }
+    for (int i=0;i<numberRows_;i++) {
+      assert (!checkArray[i]);
+      if (checkArray[i])
+	abort();
+    }
+    delete [] checkArray;
+  }
+  double theta3=maxTheta;
+  int pivotRow3=-1;
+  int lowerN=lowerActive[-1];
+  for (int i=0;i<lowerN;i++) {
+    int iRow=lowerActive[i];
+    double lowerC = lowerCoefficient[iRow];
+    double gap=lowerGap[iRow];
+    if (toLower&&iRow==pivotRow_) {
+      assert (lowerC*theta3>gap-1.0e-8);
+      if (lowerC*theta3<gap-1.0e-8)
+	abort();
+    }
+    if (lowerC*theta3>gap&&lowerC!=COIN_DBL_MIN) {
+      theta3 = gap/lowerC;
+      pivotRow3=iRow;
+    }
+  }
+  int pivotRow4=pivotRow3;
+  double theta4=theta3;
+  int upperN=upperActive[-1];
+  for (int i=0;i<upperN;i++) {
+    int iRow=upperActive[i];
+    double upperC = upperCoefficient[iRow];
+    double gap=upperGap[iRow];
+    if (!toLower&&iRow==pivotRow_) {
+      assert (upperC*theta3>gap-1.0e-8);
+      if (upperC*theta3<gap-1.0e-8)
+	abort();
+    }
+    if (upperC*theta4>gap&&upperC!=COIN_DBL_MIN) {
+      theta4 = gap/upperC;
+      pivotRow4=iRow;
+    }
+  }
+  bool toLower3;
+  if (theta4<theta3) {
+    theta3=theta4;
+    toLower3=false;
+    pivotRow3=pivotRow4;
+  } else {
+    toLower3=true;
+  }
+  if (fabs(theta3-theta_)>1.0e-8)
+    abort();
+  if (toLower!=toLower3||pivotRow_!=pivotRow3) {
+    printf("bad piv - good %d %g %s, bad %d %g %s\n",pivotRow_,theta_,toLower ? "toLower" : "toUpper",
+	   pivotRow3,theta3,toLower3 ? "toLower" : "toUpper");
+    //zzzzzz++;
+    if (true/*zzzzzz>zzzzzzOther*/) {
+      printf("Swapping\n");
+      pivotRow_=pivotRow3;
+      theta_=theta3;
+      toLower=toLower3;
+    }
+  }
+#endif
+#endif
+#else
+#if 0 //CLP_PARAMETRIC_DENSE_ARRAYS==2
+  {
+    double * checkArray = new double[numberRows_];
+    memcpy(checkArray,lowerCoefficient,numberRows_*sizeof(double));
+    int lowerN=lowerActive[-1];
+    for (int i=0;i<lowerN;i++) {
+      int iRow=lowerActive[i];
+      checkArray[iRow]=0.0;
+    }
+    for (int i=0;i<numberRows_;i++) {
+      assert (!checkArray[i]);
+      if (checkArray[i])
+	abort();
+    }
+    memcpy(checkArray,upperCoefficient,numberRows_*sizeof(double));
+    int upperN=upperActive[-1];
+    for (int i=0;i<upperN;i++) {
+      int iRow=upperActive[i];
+      checkArray[iRow]=0.0;
+    }
+    for (int i=0;i<numberRows_;i++) {
+      assert (!checkArray[i]);
+      if (checkArray[i])
+	abort();
+    }
+    delete [] checkArray;
+  }
+#endif
+  int lowerN=lowerActive[-1];
+  for (int i=0;i<lowerN;i++) {
+    int iRow=lowerActive[i];
+    double lowerC = lowerCoefficient[iRow];
+    double gap=lowerGap[iRow];
+    if (lowerC*theta1>gap&&lowerC!=COIN_DBL_MIN) {
+      theta1 = gap/lowerC;
+      pivotRow1=iRow;
+    }
+  }
+  pivotRow_=pivotRow1;
+  theta_=theta1;
+  int upperN=upperActive[-1];
+  for (int i=0;i<upperN;i++) {
+    int iRow=upperActive[i];
+    double upperC = upperCoefficient[iRow];
+    double gap=upperGap[iRow];
+    if (upperC*theta1>gap&&upperC!=COIN_DBL_MIN) {
+      theta1 = gap/upperC;
+      pivotRow1=iRow;
+    }
+  }
+  if (theta1<theta_) {
+    theta_=theta1;
+    toLower=false;
+    pivotRow_=pivotRow1;
+  } else {
+    toLower=true;
+  }
+#endif
+  theta_ = CoinMax(theta_,0.0);
+  if (theta_>1.0e-15) {
+    // update solution
+    for (int iRow = 0; iRow < number; iRow++) {
+      int iPivot = index[iRow];
+      iSequence = pivotVariable_[iPivot];
+      // solution value will be sol - theta*alpha
+      double alpha = array[iPivot];
+      double currentSolution = solution_[iSequence] - theta_ * alpha;
+      solution_[iSequence] =currentSolution;
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS 
+      if (lower_[iSequence]>-1.0e30)
+	lowerGap[iPivot]=currentSolution-lower_[iSequence];
+      if (upper_[iSequence]<1.0e30)
+	upperGap[iPivot]=-(currentSolution-upper_[iSequence]);
+#endif
+    }
+  }
+#ifdef CLP_PARAMETRIC_DENSE_ARRAYS
+  if (pivotRow_>=0&&false) {
+    double oldValue = upperCoefficient[pivotRow_];
+    double value = array[pivotRow_];
+    if (value) {
+      if (!oldValue) {
+	int upperN=upperActive[-1];
+	assert (upperN>=0&&upperN<numberRows_);
+	upperActive[upperN]=pivotRow_;
+	upperActive[-1]=upperN+1;
+      }
+    } else {
+      if (oldValue)
+	upperCoefficient[pivotRow_]=COIN_DBL_MIN;
+    }
+  }
+#endif
+#if 0
+  for (int i=0;i<numberTotal;i++)
+    assert(!markDone[i]);
+#endif
+  if (pivotRow_ >= 0) {
+    sequenceOut_ = pivotVariable_[pivotRow_];
+    valueOut_ = solution_[sequenceOut_];
+    lowerOut_ = lower_[sequenceOut_]+theta_*lowerChange[sequenceOut_];
+    upperOut_ = upper_[sequenceOut_]+theta_*upperChange[sequenceOut_];
+    if (!toLower) {
+      directionOut_ = -1;
+      dualOut_ = valueOut_ - upperOut_;
+    } else {
+      directionOut_ = 1;
+      dualOut_ = lowerOut_ - valueOut_;
+    }
+    return 0;
+  } else {
+    //theta_=0.0;
+    return -1;
+  }
+}
+// Restores bound to original bound
+void 
+ClpSimplexOther::originalBound(int iSequence, double theta, 
+			       const double * lowerChange,
+			       const double * upperChange)
+{
+     if (getFakeBound(iSequence) != noFake) {
+          numberFake_--;
+          setFakeBound(iSequence, noFake);
+          if (iSequence >= numberColumns_) {
+               // rows
+               int iRow = iSequence - numberColumns_;
+               rowLowerWork_[iRow] = rowLower_[iRow]+theta*lowerChange[iSequence];
+               rowUpperWork_[iRow] = rowUpper_[iRow]+theta*upperChange[iSequence];
+               if (rowScale_) {
+                    if (rowLowerWork_[iRow] > -1.0e50)
+                         rowLowerWork_[iRow] *= rowScale_[iRow] * rhsScale_;
+                    if (rowUpperWork_[iRow] < 1.0e50)
+                         rowUpperWork_[iRow] *= rowScale_[iRow] * rhsScale_;
+               } else if (rhsScale_ != 1.0) {
+                    if (rowLowerWork_[iRow] > -1.0e50)
+                         rowLowerWork_[iRow] *= rhsScale_;
+                    if (rowUpperWork_[iRow] < 1.0e50)
+                         rowUpperWork_[iRow] *= rhsScale_;
+               }
+          } else {
+               // columns
+               columnLowerWork_[iSequence] = columnLower_[iSequence]+theta*lowerChange[iSequence];
+               columnUpperWork_[iSequence] = columnUpper_[iSequence]+theta*upperChange[iSequence];
+               if (rowScale_) {
+                    double multiplier = 1.0 * inverseColumnScale_[iSequence];
+                    if (columnLowerWork_[iSequence] > -1.0e50)
+                         columnLowerWork_[iSequence] *= multiplier * rhsScale_;
+                    if (columnUpperWork_[iSequence] < 1.0e50)
+                         columnUpperWork_[iSequence] *= multiplier * rhsScale_;
+               } else if (rhsScale_ != 1.0) {
+                    if (columnLowerWork_[iSequence] > -1.0e50)
+                         columnLowerWork_[iSequence] *= rhsScale_;
+                    if (columnUpperWork_[iSequence] < 1.0e50)
+                         columnUpperWork_[iSequence] *= rhsScale_;
+               }
+          }
+     }
+}
+/* Expands out all possible combinations for a knapsack
+   If buildObj NULL then just computes space needed - returns number elements
+   On entry numberOutput is maximum allowed, on exit it is number needed or
+   -1 (as will be number elements) if maximum exceeded.  numberOutput will have at
+   least space to return values which reconstruct input.
+   Rows returned will be original rows but no entries will be returned for
+   any rows all of whose entries are in knapsack.  So up to user to allow for this.
+   If reConstruct >=0 then returns number of entrie which make up item "reConstruct"
+   in expanded knapsack.  Values in buildRow and buildElement;
+*/
+int
+ClpSimplexOther::expandKnapsack(int knapsackRow, int & numberOutput,
+                                double * buildObj, CoinBigIndex * buildStart,
+                                int * buildRow, double * buildElement, int reConstruct) const
+{
+     int iRow;
+     int iColumn;
+     // Get column copy
+     CoinPackedMatrix * columnCopy = matrix();
+     // Get a row copy in standard format
+     CoinPackedMatrix matrixByRow;
+     matrixByRow.reverseOrderedCopyOf(*columnCopy);
+     const double * elementByRow = matrixByRow.getElements();
+     const int * column = matrixByRow.getIndices();
+     const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+     const int * rowLength = matrixByRow.getVectorLengths();
+     CoinBigIndex j;
+     int * whichColumn = new int [numberColumns_];
+     int * whichRow = new int [numberRows_];
+     int numJ = 0;
+     // Get what other columns can compensate for
+     double * lo = new double [numberRows_];
+     double * high = new double [numberRows_];
+     {
+          // Use to get tight column bounds
+          ClpSimplex tempModel(*this);
+          tempModel.tightenPrimalBounds(0.0, 0, true);
+          // Now another model without knapsacks
+          int nCol = 0;
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               whichRow[iRow] = iRow;
+          }
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++)
+               whichColumn[iColumn] = -1;
+          for (j = rowStart[knapsackRow]; j < rowStart[knapsackRow] + rowLength[knapsackRow]; j++) {
+               int iColumn = column[j];
+               if (columnUpper_[iColumn] > columnLower_[iColumn]) {
+                    whichColumn[iColumn] = 0;
+               } else {
+                    assert (!columnLower_[iColumn]); // fix later
+               }
+          }
+          for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (whichColumn[iColumn] < 0)
+                    whichColumn[nCol++] = iColumn;
+          }
+          ClpSimplex tempModel2(&tempModel, numberRows_, whichRow, nCol, whichColumn, false, false, false);
+          // Row copy
+          CoinPackedMatrix matrixByRow;
+          matrixByRow.reverseOrderedCopyOf(*tempModel2.matrix());
+          const double * elementByRow = matrixByRow.getElements();
+          const int * column = matrixByRow.getIndices();
+          const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+          const int * rowLength = matrixByRow.getVectorLengths();
+          const double * columnLower = tempModel2.getColLower();
+          const double * columnUpper = tempModel2.getColUpper();
+          for (iRow = 0; iRow < numberRows_; iRow++) {
+               lo[iRow] = -COIN_DBL_MAX;
+               high[iRow] = COIN_DBL_MAX;
+               if (rowLower_[iRow] > -1.0e20 || rowUpper_[iRow] < 1.0e20) {
+
+                    // possible row
+                    int infiniteUpper = 0;
+                    int infiniteLower = 0;
+                    double maximumUp = 0.0;
+                    double maximumDown = 0.0;
+                    CoinBigIndex rStart = rowStart[iRow];
+                    CoinBigIndex rEnd = rowStart[iRow] + rowLength[iRow];
+                    CoinBigIndex j;
+                    // Compute possible lower and upper ranges
+
+                    for (j = rStart; j < rEnd; ++j) {
+                         double value = elementByRow[j];
+                         iColumn = column[j];
+                         if (value > 0.0) {
+                              if (columnUpper[iColumn] >= 1.0e20) {
+                                   ++infiniteUpper;
+                              } else {
+                                   maximumUp += columnUpper[iColumn] * value;
+                              }
+                              if (columnLower[iColumn] <= -1.0e20) {
+                                   ++infiniteLower;
+                              } else {
+                                   maximumDown += columnLower[iColumn] * value;
+                              }
+                         } else if (value < 0.0) {
+                              if (columnUpper[iColumn] >= 1.0e20) {
+                                   ++infiniteLower;
+                              } else {
+                                   maximumDown += columnUpper[iColumn] * value;
+                              }
+                              if (columnLower[iColumn] <= -1.0e20) {
+                                   ++infiniteUpper;
+                              } else {
+                                   maximumUp += columnLower[iColumn] * value;
+                              }
+                         }
+                    }
+                    // Build in a margin of error
+                    maximumUp += 1.0e-8 * fabs(maximumUp) + 1.0e-7;
+                    maximumDown -= 1.0e-8 * fabs(maximumDown) + 1.0e-7;
+                    // we want to save effective rhs
+                    double up = (infiniteUpper) ? COIN_DBL_MAX : maximumUp;
+                    double down = (infiniteLower) ? -COIN_DBL_MAX : maximumDown;
+                    if (up == COIN_DBL_MAX || rowLower_[iRow] == -COIN_DBL_MAX) {
+                         // However low we go it doesn't matter
+                         lo[iRow] = -COIN_DBL_MAX;
+                    } else {
+                         // If we go below this then can not be feasible
+                         lo[iRow] = rowLower_[iRow] - up;
+                    }
+                    if (down == -COIN_DBL_MAX || rowUpper_[iRow] == COIN_DBL_MAX) {
+                         // However high we go it doesn't matter
+                         high[iRow] = COIN_DBL_MAX;
+                    } else {
+                         // If we go above this then can not be feasible
+                         high[iRow] = rowUpper_[iRow] - down;
+                    }
+               }
+          }
+     }
+     numJ = 0;
+     for (iColumn = 0; iColumn < numberColumns_; iColumn++)
+          whichColumn[iColumn] = -1;
+     int * markRow = new int [numberRows_];
+     for (iRow = 0; iRow < numberRows_; iRow++)
+          markRow[iRow] = 1;
+     for (j = rowStart[knapsackRow]; j < rowStart[knapsackRow] + rowLength[knapsackRow]; j++) {
+          int iColumn = column[j];
+          if (columnUpper_[iColumn] > columnLower_[iColumn]) {
+               whichColumn[iColumn] = numJ;
+               numJ++;
+          }
+     }
+     /* mark rows
+        -n in knapsack and n other variables
+        1 no entries
+        n+1000 not involved in knapsack but n entries
+        0 only in knapsack
+     */
+     for (iRow = 0; iRow < numberRows_; iRow++) {
+          int type = 1;
+          for (j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+               int iColumn = column[j];
+               if (whichColumn[iColumn] >= 0) {
+                    if (type == 1) {
+                         type = 0;
+                    } else if (type > 0) {
+                         assert (type > 1000);
+                         type = -(type - 1000);
+                    }
+               } else if (type == 1) {
+                    type = 1001;
+               } else if (type < 0) {
+                    type --;
+               } else if (type == 0) {
+                    type = -1;
+               } else {
+                    assert (type > 1000);
+                    type++;
+               }
+          }
+          markRow[iRow] = type;
+          if (type < 0 && type > -30 && false)
+               printf("markrow on row %d is %d\n", iRow, markRow[iRow]);
+     }
+     int * bound = new int [numberColumns_+1];
+     int * stack = new int [numberColumns_+1];
+     int * flip = new int [numberColumns_+1];
+     double * offset = new double[numberColumns_+1];
+     double * size = new double [numberColumns_+1];
+     double * rhsOffset = new double[numberRows_];
+     int * build = new int[numberColumns_];
+     int maxNumber = numberOutput;
+     numJ = 0;
+     double minSize = rowLower_[knapsackRow];
+     double maxSize = rowUpper_[knapsackRow];
+     double knapsackOffset = 0.0;
+     for (j = rowStart[knapsackRow]; j < rowStart[knapsackRow] + rowLength[knapsackRow]; j++) {
+          int iColumn = column[j];
+          double lowerColumn = columnLower_[iColumn];
+          double upperColumn = columnUpper_[iColumn];
+          if (lowerColumn == upperColumn)
+               continue;
+          double gap = upperColumn - lowerColumn;
+          if (gap > 1.0e8)
+               gap = 1.0e8;
+          assert (fabs(floor(gap + 0.5) - gap) < 1.0e-5);
+          whichColumn[numJ] = iColumn;
+          bound[numJ] = static_cast<int> (gap);
+          if (elementByRow[j] > 0.0) {
+               flip[numJ] = 1;
+               offset[numJ] = lowerColumn;
+               size[numJ++] = elementByRow[j];
+          } else {
+               flip[numJ] = -1;
+               offset[numJ] = upperColumn;
+               size[numJ++] = -elementByRow[j];
+               lowerColumn = upperColumn;
+          }
+          knapsackOffset += elementByRow[j] * lowerColumn;
+     }
+     int jRow;
+     for (iRow = 0; iRow < numberRows_; iRow++)
+          whichRow[iRow] = iRow;
+     ClpSimplex smallModel(this, numberRows_, whichRow, numJ, whichColumn, true, true, true);
+     // modify rhs to allow for nonzero lower bounds
+     //double * rowLower = smallModel.rowLower();
+     //double * rowUpper = smallModel.rowUpper();
+     //const double * columnLower = smallModel.columnLower();
+     //const double * columnUpper = smallModel.columnUpper();
+     const CoinPackedMatrix * matrix = smallModel.matrix();
+     const double * element = matrix->getElements();
+     const int * row = matrix->getIndices();
+     const CoinBigIndex * columnStart = matrix->getVectorStarts();
+     const int * columnLength = matrix->getVectorLengths();
+     const double * objective = smallModel.objective();
+     //double objectiveOffset=0.0;
+     // would use for fixed?
+     CoinZeroN(rhsOffset, numberRows_);
+     double * rowActivity = smallModel.primalRowSolution();
+     CoinZeroN(rowActivity, numberRows_);
+     maxSize -= knapsackOffset;
+     minSize -= knapsackOffset;
+     // now generate
+     int i;
+     int iStack = numJ;
+     for (i = 0; i < numJ; i++) {
+          stack[i] = 0;
+     }
+     double tooMuch = 10.0 * maxSize + 10000;
+     stack[numJ] = 1;
+     size[numJ] = tooMuch;
+     bound[numJ] = 0;
+     double sum = tooMuch;
+     // allow for all zero being OK
+     stack[numJ-1] = -1;
+     sum -= size[numJ-1];
+     numberOutput = 0;
+     int nelCreate = 0;
+     /* typeRun is - 0 for initial sizes
+                     1 for build
+     	  2 for reconstruct
+     */
+     int typeRun = buildObj ? 1 : 0;
+     if (reConstruct >= 0) {
+          assert (buildRow && buildElement);
+          typeRun = 2;
+     }
+     if (typeRun == 1)
+          buildStart[0] = 0;
+     while (iStack >= 0) {
+          if (sum >= minSize && sum <= maxSize) {
+               double checkSize = 0.0;
+               bool good = true;
+               int nRow = 0;
+               double obj = 0.0;
+               CoinZeroN(rowActivity, numberRows_);
+               for (iColumn = 0; iColumn < numJ; iColumn++) {
+                    int iValue = stack[iColumn];
+                    if (iValue > bound[iColumn]) {
+                         good = false;
+                         break;
+                    } else {
+                         double realValue = offset[iColumn] + flip[iColumn] * iValue;
+                         if (realValue) {
+                              obj += objective[iColumn] * realValue;
+                              for (CoinBigIndex j = columnStart[iColumn];
+                                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                                   double value = element[j] * realValue;
+                                   int kRow = row[j];
+                                   if (rowActivity[kRow]) {
+                                        rowActivity[kRow] += value;
+                                        if (!rowActivity[kRow])
+                                             rowActivity[kRow] = 1.0e-100;
+                                   } else {
+                                        build[nRow++] = kRow;
+                                        rowActivity[kRow] = value;
+                                   }
+                              }
+                         }
+                    }
+               }
+               if (good) {
+                    for (jRow = 0; jRow < nRow; jRow++) {
+                         int kRow = build[jRow];
+                         double value = rowActivity[kRow];
+                         if (value > high[kRow] || value < lo[kRow]) {
+                              good = false;
+                              break;
+                         }
+                    }
+               }
+               if (good) {
+                    if (typeRun == 1) {
+                         buildObj[numberOutput] = obj;
+                         for (jRow = 0; jRow < nRow; jRow++) {
+                              int kRow = build[jRow];
+                              double value = rowActivity[kRow];
+                              if (markRow[kRow] < 0 && fabs(value) > 1.0e-13) {
+                                   buildElement[nelCreate] = value;
+                                   buildRow[nelCreate++] = kRow;
+                              }
+                         }
+                         buildStart[numberOutput+1] = nelCreate;
+                    } else if (!typeRun) {
+                         for (jRow = 0; jRow < nRow; jRow++) {
+                              int kRow = build[jRow];
+                              double value = rowActivity[kRow];
+                              if (markRow[kRow] < 0 && fabs(value) > 1.0e-13) {
+                                   nelCreate++;
+                              }
+                         }
+                    }
+                    if (typeRun == 2 && reConstruct == numberOutput) {
+                         // build and exit
+                         nelCreate = 0;
+                         for (iColumn = 0; iColumn < numJ; iColumn++) {
+                              int iValue = stack[iColumn];
+                              double realValue = offset[iColumn] + flip[iColumn] * iValue;
+                              if (realValue) {
+                                   buildRow[nelCreate] = whichColumn[iColumn];
+                                   buildElement[nelCreate++] = realValue;
+                              }
+                         }
+                         numberOutput = 1;
+                         for (i = 0; i < numJ; i++) {
+                              bound[i] = 0;
+                         }
+                         break;
+                    }
+                    numberOutput++;
+                    if (numberOutput > maxNumber) {
+                         nelCreate = -numberOutput;
+                         numberOutput = -1;
+                         for (i = 0; i < numJ; i++) {
+                              bound[i] = 0;
+                         }
+                         break;
+                    } else if (typeRun == 1 && numberOutput == maxNumber) {
+                         // On second run
+                         for (i = 0; i < numJ; i++) {
+                              bound[i] = 0;
+                         }
+                         break;
+                    }
+                    for (int j = 0; j < numJ; j++) {
+                         checkSize += stack[j] * size[j];
+                    }
+                    assert (fabs(sum - checkSize) < 1.0e-3);
+               }
+               for (jRow = 0; jRow < nRow; jRow++) {
+                    int kRow = build[jRow];
+                    rowActivity[kRow] = 0.0;
+               }
+          }
+          if (sum > maxSize || stack[iStack] > bound[iStack]) {
+               sum -= size[iStack] * stack[iStack];
+               stack[iStack--] = 0;
+               if (iStack >= 0) {
+                    stack[iStack] ++;
+                    sum += size[iStack];
+               }
+          } else {
+               // must be less
+               // add to last possible
+               iStack = numJ - 1;
+               sum += size[iStack];
+               stack[iStack]++;
+          }
+     }
+     //printf("%d will be created\n",numberOutput);
+     delete [] whichColumn;
+     delete [] whichRow;
+     delete [] bound;
+     delete [] stack;
+     delete [] flip;
+     delete [] size;
+     delete [] offset;
+     delete [] rhsOffset;
+     delete [] build;
+     delete [] markRow;
+     delete [] lo;
+     delete [] high;
+     return nelCreate;
+}
+// Quick try at cleaning up duals if postsolve gets wrong
+void
+ClpSimplexOther::cleanupAfterPostsolve()
+{
+     // First mark singleton equality rows
+     char * mark = new char [ numberRows_];
+     memset(mark, 0, numberRows_);
+     const int * row = matrix_->getIndices();
+     const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+     const int * columnLength = matrix_->getVectorLengths();
+     const double * element = matrix_->getElements();
+     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          for (CoinBigIndex j = columnStart[iColumn];
+                    j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+               int iRow = row[j];
+               if (mark[iRow])
+                    mark[iRow] = 2;
+               else
+                    mark[iRow] = 1;
+          }
+     }
+     // for now just == rows
+     for (int iRow = 0; iRow < numberRows_; iRow++) {
+          if (rowUpper_[iRow] > rowLower_[iRow])
+               mark[iRow] = 3;
+     }
+     double dualTolerance = dblParam_[ClpDualTolerance];
+     double primalTolerance = dblParam_[ClpPrimalTolerance];
+     int numberCleaned = 0;
+     double maxmin = optimizationDirection_;
+     for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+          double dualValue = reducedCost_[iColumn] * maxmin;
+          double primalValue = columnActivity_[iColumn];
+          double lower = columnLower_[iColumn];
+          double upper = columnUpper_[iColumn];
+          int way = 0;
+          switch(getColumnStatus(iColumn)) {
+
+          case basic:
+               // dual should be zero
+               if (dualValue > dualTolerance) {
+                    way = -1;
+               } else if (dualValue < -dualTolerance) {
+                    way = 1;
+               }
+               break;
+          case ClpSimplex::isFixed:
+               break;
+          case atUpperBound:
+               // dual should not be positive
+               if (dualValue > dualTolerance) {
+                    way = -1;
+               }
+               break;
+          case atLowerBound:
+               // dual should not be negative
+               if (dualValue < -dualTolerance) {
+                    way = 1;
+               }
+               break;
+          case superBasic:
+          case isFree:
+               if (primalValue < upper - primalTolerance) {
+                    // dual should not be negative
+                    if (dualValue < -dualTolerance) {
+                         way = 1;
+                    }
+               }
+               if (primalValue > lower + primalTolerance) {
+                    // dual should not be positive
+                    if (dualValue > dualTolerance) {
+                         way = -1;
+                    }
+               }
+               break;
+          }
+          if (way) {
+               // see if can find singleton row
+               for (CoinBigIndex j = columnStart[iColumn];
+                         j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                    int iRow = row[j];
+                    if (mark[iRow] == 1) {
+                         double value = element[j];
+                         // dj - addDual*value == 0.0
+                         double addDual = dualValue / value;
+                         dual_[iRow] += addDual;
+                         reducedCost_[iColumn] = 0.0;
+                         numberCleaned++;
+                         break;
+                    }
+               }
+          }
+     }
+     delete [] mark;
+#ifdef CLP_INVESTIGATE
+     printf("cleanupAfterPostsolve cleaned up %d columns\n", numberCleaned);
+#endif
+     // Redo
+     memcpy(reducedCost_, this->objective(), numberColumns_ * sizeof(double));
+     matrix_->transposeTimes(-1.0, dual_, reducedCost_);
+     checkSolutionInternal();
+}
+// Returns gub version of model or NULL
+ClpSimplex * 
+ClpSimplexOther::gubVersion(int * whichRows, int * whichColumns,
+			    int neededGub,
+			    int factorizationFrequency)
+{
+  // find gub
+  int numberRows = this->numberRows();
+  int numberColumns = this->numberColumns();
+  int iRow, iColumn;
+  int * columnIsGub = new int [numberColumns];
+  const double * columnLower = this->columnLower();
+  const double * columnUpper = this->columnUpper();
+  int numberFixed=0;
+  for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+    if (columnUpper[iColumn] == columnLower[iColumn]) {
+      columnIsGub[iColumn]=-2;
+      numberFixed++;
+    } else if (columnLower[iColumn]>=0) {
+      columnIsGub[iColumn]=-1;
+    } else {
+      columnIsGub[iColumn]=-3;
+    }
+  }
+  CoinPackedMatrix * matrix = this->matrix();
+  // get row copy
+  CoinPackedMatrix rowCopy = *matrix;
+  rowCopy.reverseOrdering();
+  const int * column = rowCopy.getIndices();
+  const int * rowLength = rowCopy.getVectorLengths();
+  const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+  const double * element = rowCopy.getElements();
+  int numberNonGub = 0;
+  int numberEmpty = numberRows;
+  int * rowIsGub = new int [numberRows];
+  int smallestGubRow=-1;
+  int count=numberColumns+1;
+  double * rowLower = this->rowLower();
+  double * rowUpper = this->rowUpper();
+  // make sure we can get rid of upper bounds
+  double * fixedRow = new double [numberRows];
+  for (iRow = 0 ; iRow < numberRows ; iRow++) {
+    double sumFixed=0.0;
+    for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+      int iColumn = column[j];
+      double value = columnLower[iColumn];
+      if (value) 
+	sumFixed += element[j] * value;
+    }
+    fixedRow[iRow]=rowUpper[iRow]-sumFixed;
+  }
+  for (iRow = numberRows - 1; iRow >= 0; iRow--) {
+    bool gubRow = true;
+    int numberInRow=0;
+    double sumFixed=0.0;
+    double gap = fixedRow[iRow]-1.0e-12;
+    for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+      int iColumn = column[j];
+      if (columnIsGub[iColumn]!=-2) {
+	if (element[j] != 1.0||columnIsGub[iColumn]==-3||
+	    columnUpper[iColumn]-columnLower[iColumn]<gap) {
+	  gubRow = false;
+	  break;
+	} else {
+	  numberInRow++;
+	  if (columnIsGub[iColumn] >= 0) {
+	    gubRow = false;
+	    break;
+	  }
+	}
+      } else {
+	sumFixed += columnLower[iColumn]*element[j];
+      }
+    }
+    if (!gubRow) {
+      whichRows[numberNonGub++] = iRow;
+      rowIsGub[iRow] = -1;
+    } else if (numberInRow) {
+      if (numberInRow<count) {
+	count = numberInRow;
+	smallestGubRow=iRow;
+      }
+      for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) {
+	int iColumn = column[j];
+	if (columnIsGub[iColumn]!=-2) 
+	  columnIsGub[iColumn] = iRow;
+      }
+      rowIsGub[iRow] = 0;
+    } else {
+      // empty row!
+      whichRows[--numberEmpty] = iRow;
+      rowIsGub[iRow] = -2;
+      if (sumFixed>rowUpper[iRow]+1.0e-4||
+	  sumFixed<rowLower[iRow]-1.0e-4) {
+	fprintf(stderr,"******** No infeasible empty rows - please!\n");
+	abort();
+      }
+    }
+  }
+  delete [] fixedRow;
+  char message[100];
+  int numberGub = numberEmpty - numberNonGub;
+  if (numberGub >= neededGub) { 
+    sprintf(message,"%d gub rows", numberGub);
+    handler_->message(CLP_GENERAL2, messages_)
+      << message << CoinMessageEol;
+    int numberNormal = 0;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+      if (columnIsGub[iColumn] < 0  && columnIsGub[iColumn] !=-2) {
+	whichColumns[numberNormal++] = iColumn;
+      }
+    }
+    if (!numberNormal) {
+      sprintf(message,"Putting back one gub row to make non-empty");
+      handler_->message(CLP_GENERAL2, messages_)
+	<< message << CoinMessageEol;
+      rowIsGub[smallestGubRow]=-1;
+      whichRows[numberNonGub++] = smallestGubRow;
+      for (int j = rowStart[smallestGubRow]; 
+	   j < rowStart[smallestGubRow] + rowLength[smallestGubRow]; j++) {
+	int iColumn = column[j];
+	if (columnIsGub[iColumn]>=0) {
+	  columnIsGub[iColumn]=-4;
+	  whichColumns[numberNormal++] = iColumn;
+	}
+      }
+    }
+    std::sort(whichRows,whichRows+numberNonGub);
+    std::sort(whichColumns,whichColumns+numberNormal);
+    double * lower = CoinCopyOfArray(this->rowLower(),numberRows);
+    double * upper = CoinCopyOfArray(this->rowUpper(),numberRows);
+    // leave empty rows at end
+    numberEmpty = numberRows-numberEmpty;
+    const int * row = matrix->getIndices();
+    const int * columnLength = matrix->getVectorLengths();
+    const CoinBigIndex * columnStart = matrix->getVectorStarts();
+    const double * elementByColumn = matrix->getElements();
+    // Fixed at end
+    int put2 = numberColumns-numberFixed;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+      if (columnIsGub[iColumn] ==-2) {
+	whichColumns[put2++] = iColumn;
+	double value = columnLower[iColumn];
+	for (int j = columnStart[iColumn]; 
+	     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	  int iRow = row[j];
+	  if (lower[iRow]>-1.0e20)
+	    lower[iRow] -= value*element[j];
+	  if (upper[iRow]<1.0e20)
+	    upper[iRow] -= value*element[j];
+	}
+      }
+    }
+    int put = numberNormal;
+    ClpSimplex * model2 =
+      new ClpSimplex(this, numberNonGub, whichRows , numberNormal, whichColumns);
+    // scale
+    double * scaleArray = new double [numberRows];
+    for (int i=0;i<numberRows;i++) {
+      scaleArray[i]=1.0;
+      if (rowIsGub[i]==-1) {
+	double largest = 1.0e-30;
+	double smallest = 1.0e30;
+	for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) {
+	  int iColumn = column[j];
+	  if (columnIsGub[iColumn]!=-2) {
+	    double value =fabs(element[j]);
+	    largest = CoinMax(value,largest);
+	    smallest = CoinMin(value,smallest);
+	  }
+	}
+	double scale = CoinMax(0.001,1.0/sqrt(largest*smallest));
+	scaleArray[i]=scale;
+	if (lower[i]>-1.0e30)
+	  lower[i] *= scale;
+	if (upper[i]<1.0e30)
+	  upper[i] *= scale;
+      }
+    }
+    // scale partial matrix
+    {
+      CoinPackedMatrix * matrix = model2->matrix();
+      const int * row = matrix->getIndices();
+      const int * columnLength = matrix->getVectorLengths();
+      const CoinBigIndex * columnStart = matrix->getVectorStarts();
+      double * element = matrix->getMutableElements();
+      for (int i=0;i<numberNormal;i++) {
+	for (int j = columnStart[i]; 
+	     j < columnStart[i] + columnLength[i]; j++) {
+	  int iRow = row[j];
+	  iRow = whichRows[iRow];
+	  double scaleBy = scaleArray[iRow];
+	  element[j] *= scaleBy;
+	}
+      }
+    }
+    // adjust rhs
+    double * rowLower = model2->rowLower();
+    double * rowUpper = model2->rowUpper();
+    for (int i=0;i<numberNonGub;i++) {
+      int iRow = whichRows[i];
+      rowLower[i] = lower[iRow];
+      rowUpper[i] = upper[iRow];
+    }
+    int numberGubColumns = numberColumns - put - numberFixed;
+    CoinBigIndex numberElements=0;
+    int * temp1 = new int [numberRows+1];
+    // get counts
+    memset(temp1,0,numberRows*sizeof(int));
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+      int iGub = columnIsGub[iColumn];
+      if (iGub>=0) {
+	numberElements += columnLength[iColumn]-1;
+	temp1[iGub]++;
+      }
+    }
+    /* Optional but means can eventually simplify coding
+       could even add in fixed slacks to deal with
+       singularities - but should not be necessary */
+    int numberSlacks=0;
+    for (int i = 0; i < numberRows; i++) {
+      if (rowIsGub[i]>=0) {
+	if (lower[i]<upper[i]) {
+	  numberSlacks++;
+	  temp1[i]++;
+	}
+      }
+    }
+    int * gubStart = new int [numberGub+1];
+    numberGub=0;
+    gubStart[0]=0;
+    for (int i = 0; i < numberRows; i++) {
+      if (rowIsGub[i]>=0) {
+	rowIsGub[i]=numberGub;
+	gubStart[numberGub+1]=gubStart[numberGub]+temp1[i];
+	temp1[numberGub]=0;
+	lower[numberGub]=lower[i];
+	upper[numberGub]=upper[i];
+	whichRows[numberNonGub+numberGub]=i;
+	numberGub++;
+      }
+    }
+    int numberGubColumnsPlus = numberGubColumns + numberSlacks;
+    double * lowerColumn2 = new double [numberGubColumnsPlus];
+    CoinFillN(lowerColumn2, numberGubColumnsPlus, 0.0);
+    double * upperColumn2 = new double [numberGubColumnsPlus];
+    CoinFillN(upperColumn2, numberGubColumnsPlus, COIN_DBL_MAX);
+    int * start2 = new int[numberGubColumnsPlus+1];
+    int * row2 = new int[numberElements];
+    double * element2 = new double[numberElements];
+    double * cost2 = new double [numberGubColumnsPlus];
+    CoinFillN(cost2, numberGubColumnsPlus, 0.0);
+    const double * cost = this->objective();
+    put = numberNormal;
+    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+      int iGub = columnIsGub[iColumn];
+      if (iGub>=0) {
+	// TEMP
+	//this->setColUpper(iColumn,COIN_DBL_MAX);
+	iGub = rowIsGub[iGub];
+	assert (iGub>=0);
+	int kPut = put+gubStart[iGub]+temp1[iGub];
+	temp1[iGub]++;
+	whichColumns[kPut]=iColumn;
+      }
+    }
+    for (int i = 0; i < numberRows; i++) {
+      if (rowIsGub[i]>=0) {
+	int iGub = rowIsGub[i];
+	if (lower[iGub]<upper[iGub]) {
+	  int kPut = put+gubStart[iGub]+temp1[iGub];
+	  temp1[iGub]++;
+	  whichColumns[kPut]=iGub+numberColumns;
+	}
+      }
+    }
+    //this->primal(1); // TEMP
+    // redo rowIsGub to give lookup
+    for (int i=0;i<numberRows;i++)
+      rowIsGub[i]=-1;
+    for (int i=0;i<numberNonGub;i++) 
+      rowIsGub[whichRows[i]]=i;
+    start2[0]=0;
+    numberElements = 0;
+    for (int i=0;i<numberGubColumnsPlus;i++) {
+      int iColumn = whichColumns[put++];
+      if (iColumn<numberColumns) {
+	cost2[i] = cost[iColumn];
+	lowerColumn2[i] = columnLower[iColumn];
+	upperColumn2[i] = columnUpper[iColumn];
+	upperColumn2[i] = COIN_DBL_MAX; 
+	for (int j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+	  int iRow = row[j];
+	  double scaleBy = scaleArray[iRow];
+	  iRow = rowIsGub[iRow];
+	  if (iRow >= 0) {
+	    row2[numberElements] = iRow;
+	    element2[numberElements++] = elementByColumn[j]*scaleBy;
+	  }
+	}
+      } else {
+	// slack
+	int iGub = iColumn-numberColumns;
+	double slack = upper[iGub]-lower[iGub];
+	assert (upper[iGub]<1.0e20);
+	lower[iGub]=upper[iGub];
+	cost2[i] = 0;
+	lowerColumn2[i] = 0;
+	upperColumn2[i] = slack;
+	upperColumn2[i] = COIN_DBL_MAX;
+      }
+      start2[i+1] = numberElements;
+    }
+    // clean up bounds on variables
+    for (int iSet=0;iSet<numberGub;iSet++) {
+      double lowerValue=0.0;
+      for (int i=gubStart[iSet];i<gubStart[iSet+1];i++) {
+	lowerValue += lowerColumn2[i];
+      }
+      assert (lowerValue<upper[iSet]+1.0e-6);
+      double gap = CoinMax(0.0,upper[iSet]-lowerValue);
+      for (int i=gubStart[iSet];i<gubStart[iSet+1];i++) {
+	if (upperColumn2[i]<1.0e30) {
+	  upperColumn2[i] = CoinMin(upperColumn2[i],
+				    lowerColumn2[i]+gap);
+	}
+      }
+    }
+    sprintf(message,"** Before adding matrix there are %d rows and %d columns",
+	   model2->numberRows(), model2->numberColumns());
+    handler_->message(CLP_GENERAL2, messages_)
+      << message << CoinMessageEol;
+    delete [] scaleArray;
+    delete [] temp1;
+    model2->setFactorizationFrequency(factorizationFrequency);
+    ClpDynamicMatrix * newMatrix = 
+      new ClpDynamicMatrix(model2, numberGub,
+				  numberGubColumnsPlus, gubStart,
+				  lower, upper,
+				  start2, row2, element2, cost2,
+				  lowerColumn2, upperColumn2);
+    delete [] gubStart;
+    delete [] lowerColumn2;
+    delete [] upperColumn2;
+    delete [] start2;
+    delete [] row2;
+    delete [] element2;
+    delete [] cost2;
+    delete [] lower;
+    delete [] upper;
+    model2->replaceMatrix(newMatrix,true);
+#ifdef EVERY_ITERATION
+    {
+      ClpDynamicMatrix * gubMatrix =
+	dynamic_cast< ClpDynamicMatrix*>(model2->clpMatrix());
+      assert(gubMatrix);
+      gubMatrix->writeMps("gub.mps");
+    }
+#endif
+    delete [] columnIsGub;
+    delete [] rowIsGub;
+    newMatrix->switchOffCheck();
+#ifdef EVERY_ITERATION
+    newMatrix->setRefreshFrequency(1/*000*/);
+#else
+    newMatrix->setRefreshFrequency(1000);
+#endif
+    sprintf(message,
+	    "** While after adding matrix there are %d rows and %d columns",
+	    model2->numberRows(), model2->numberColumns());
+    handler_->message(CLP_GENERAL2, messages_)
+      << message << CoinMessageEol;
+    model2->setSpecialOptions(4);    // exactly to bound
+    // Scaling off (done by hand)
+    model2->scaling(0);
+    return model2;
+  } else {
+    delete [] columnIsGub;
+    delete [] rowIsGub;
+    return NULL;
+  }
+}
+// Sets basis from original
+void 
+ClpSimplexOther::setGubBasis(ClpSimplex &original,const int * whichRows,
+			     const int * whichColumns)
+{
+  ClpDynamicMatrix * gubMatrix =
+    dynamic_cast< ClpDynamicMatrix*>(clpMatrix());
+  assert(gubMatrix);
+  int numberGubColumns = gubMatrix->numberGubColumns();
+  int numberNormal = gubMatrix->firstDynamic();
+  //int lastOdd = gubMatrix->firstAvailable();
+  //int numberTotalColumns = numberNormal + numberGubColumns;
+  //assert (numberTotalColumns==numberColumns+numberSlacks);
+  int numberRows = original.numberRows();
+  int numberColumns = original.numberColumns();
+  int * columnIsGub = new int [numberColumns];
+  int numberNonGub = gubMatrix->numberStaticRows();
+  //assert (firstOdd==numberNormal);
+  double * solution = primalColumnSolution();
+  double * originalSolution = original.primalColumnSolution();
+  const double * upperSet = gubMatrix->upperSet();
+  // Column copy of GUB part
+  int numberSets = gubMatrix->numberSets();
+  const int * startSet = gubMatrix->startSets();
+  const CoinBigIndex * columnStart = gubMatrix->startColumn();
+  const double * columnLower = gubMatrix->columnLower();
+#ifdef TRY_IMPROVE
+  const double * columnUpper = gubMatrix->columnUpper();
+  const double * lowerSet = gubMatrix->lowerSet();
+  const double * element = gubMatrix->element();
+  const int * row = gubMatrix->row();
+  bool allPositive=true;
+  double * rowActivity = new double[numberNonGub];
+  memset(rowActivity, 0, numberNonGub*sizeof(double));
+  {
+    // Non gub contribution
+    const double * element = matrix_->getElements();
+    const int * row = matrix_->getIndices();
+    const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+    const int * columnLength = matrix_->getVectorLengths();
+    for (int i=0;i<numberNormal;i++) {
+      int iColumn = whichColumns[i];
+      double value = originalSolution[iColumn];
+      if (value) {
+	for (CoinBigIndex j = columnStart[i];
+	     j < columnStart[i] + columnLength[i]; j++) {
+	  int iRow = row[j];
+	  rowActivity[iRow] += value*element[j];
+	}
+      }
+    }
+  }
+  double * newSolution = new double [numberGubColumns];
+  int * slacks = new int [numberSets];
+  for (int i=0;i<numberSets;i++) {
+    double sum=0.0;
+    int iSlack=-1;
+    for (int j=startSet[i];j<startSet[i+1];j++) {
+      gubMatrix->setDynamicStatus(j,ClpDynamicMatrix::atLowerBound);
+      int iColumn = whichColumns[j+numberNormal];
+      if (iColumn<numberColumns) {
+	columnIsGub[iColumn] = whichRows[numberNonGub+i];
+	double value = originalSolution[iColumn];
+	sum += value;
+	newSolution[j]=value;
+	for (CoinBigIndex k = columnStart[j]; k < columnStart[j+1] ; k++) {
+	  int iRow = row[k];
+	  rowActivity[iRow] += value*element[k];
+	  if (element[k] < 0.0)
+	    allPositive=false;
+	}
+	if (columnStart[j]==columnStart[j+1])
+	  iSlack=j;
+      } else {
+	newSolution[j]=0.0;
+	iSlack=j;
+	allPositive=false; // for now
+      }
+    }
+    slacks[i]=iSlack;
+    if (sum>upperSet[i]+1.0e-8) {
+      double gap = sum-upperSet[i];
+      if (iSlack>=0) {
+	double value=newSolution[iSlack];
+	if (value>0.0) {
+	  double down = CoinMin(gap,value);
+	  gap -= down;
+	  sum -= down;
+	  newSolution[iSlack] = value-down;
+	}
+      }
+      if (gap>1.0e-8) {
+	for (int j=startSet[i];j<startSet[i+1];j++) {
+	  int iColumn = whichColumns[j+numberNormal];
+	  if (newSolution[j]>0.0&&iColumn<numberColumns) {
+	    double value = newSolution[j];
+	    double down = CoinMin(gap,value);
+	    gap -= down;
+	    sum -= down;
+	    newSolution[iSlack] = value-down;
+	    for (CoinBigIndex k = columnStart[j]; k < columnStart[j+1] ; k++) {
+	      int iRow = row[k];
+	      rowActivity[iRow] -= down*element[k];
+	    }
+	  }
+	}
+      }
+      assert (gap<1.0e-8);
+    } else if (sum<lowerSet[i]-1.0e-8) {
+      double gap = lowerSet[i]-sum;
+      if (iSlack>=0) {
+	double value=newSolution[iSlack];
+	if (value<columnUpper[iSlack]) {
+	  double up = CoinMin(gap,columnUpper[iSlack]-value);
+	  gap -= up;
+	  sum += up;
+	  newSolution[iSlack] = value+up;
+	}
+      }
+      if (gap>1.0e-8) {
+	for (int j=startSet[i];j<startSet[i+1];j++) {
+	  int iColumn = whichColumns[j+numberNormal];
+	  if (newSolution[j]<columnUpper[j]&&iColumn<numberColumns) {
+	    double value = newSolution[j];
+	    double up = CoinMin(gap,columnUpper[j]-value);
+	    gap -= up;
+	    sum += up;
+	    newSolution[iSlack] = value+up;
+	    for (CoinBigIndex k = columnStart[j]; k < columnStart[j+1] ; k++) {
+	      int iRow = row[k];
+	      rowActivity[iRow] += up*element[k];
+	    }
+	  }
+	}
+      }
+      assert (gap<1.0e-8);
+    } 
+    if (fabs(sum-upperSet[i])>1.0e-7)
+      printf("Sum for set %d is %g - lower %g, upper %g\n",i,
+	     sum,lowerSet[i],upperSet[i]);
+  }
+  if (allPositive) {
+    // See if we can improve solution
+    // first reduce if over
+    double * gaps = new double [numberNonGub];
+    double direction = optimizationDirection_; 
+    const double * cost = gubMatrix->cost();
+    bool over=false;
+    for (int i=0;i<numberNonGub;i++) {
+      double activity = rowActivity[i];
+      gaps[i]=0.0;
+      if (activity>rowUpper_[i]+1.0e-6) {
+	gaps[i]=activity-rowUpper_[i];
+	over=true;
+      }
+    }
+    double * weights = new double [numberGubColumns];
+    int * which = new int [numberGubColumns];
+    int * whichSet = new int [numberGubColumns];
+    if (over) {
+      int n=0;
+      for (int i=0;i<numberSets;i++) {
+	int iSlack = slacks[i];
+	if (iSlack<0||newSolution[iSlack]>upperSet[i]-1.0e-8)
+	  continue;
+	double slackCost = cost[iSlack]*direction;
+	for (int j=startSet[i];j<startSet[i+1];j++) {
+	  whichSet[j]=i;
+	  double value = newSolution[j];
+	  double thisCost = cost[j]*direction;
+	  if (value>columnLower[j]&&j!=iSlack) {
+	    if(thisCost<slackCost) {
+	      double sum = 1.0e-30;
+	      for (CoinBigIndex k = columnStart[j]; 
+		   k < columnStart[j+1] ; k++) {
+		int iRow = row[k];
+		sum += gaps[iRow]*element[k];
+	      }
+	      which[n]=j;
+	      // big drop and small difference in cost better
+	      weights[n++]=(slackCost-thisCost)/sum;
+	    } else {
+	      // slack better anyway
+	      double move = value-columnLower[j];
+	      newSolution[iSlack]=CoinMin(upperSet[i],
+					  newSolution[iSlack]+move);
+	      newSolution[j]=columnLower[j];
+	      for (CoinBigIndex k = columnStart[j]; 
+		   k < columnStart[j+1] ; k++) {
+		int iRow = row[k];
+		rowActivity[iRow] -= move*element[k];
+	      }
+	    }
+	  }
+	}
+      }
+      // sort
+      CoinSort_2(weights,weights+n,which);
+      for (int i=0;i<n;i++) {
+	int j= which[i];
+	int iSet = whichSet[j];
+	int iSlack = slacks[iSet];
+	assert (iSlack>=0);
+	double move = 0.0;
+	for (CoinBigIndex k = columnStart[j]; 
+	     k < columnStart[j+1] ; k++) {
+	  int iRow = row[k];
+	  if(rowActivity[iRow]-rowUpper_[iRow]>move*element[k]) {
+	    move = (rowActivity[iRow]-rowUpper_[iRow])/element[k];
+	  }
+	}
+	move=CoinMin(move,newSolution[j]-columnLower[j]);
+	if (move) {
+	  newSolution[j] -= move;
+	  newSolution[iSlack] += move;
+	  for (CoinBigIndex k = columnStart[j]; 
+	       k < columnStart[j+1] ; k++) {
+	    int iRow = row[k];
+	    rowActivity[iRow] -= move*element[k];
+	  }
+	}
+      }
+    }
+    delete [] whichSet;
+    delete [] which;
+    delete [] weights;
+    delete [] gaps;
+    // redo original status!
+    for (int i=0;i<numberSets;i++) {
+      int numberBasic=0;
+      int numberNewBasic=0;
+      int j1=-1;
+      int j2=-1;
+      for (int j=startSet[i];j<startSet[i+1];j++) {
+	if (newSolution[j]>columnLower[j]) {
+	  numberNewBasic++;
+	  j2=j;
+	}
+	int iOrig = whichColumns[j+numberNormal];
+	if (iOrig<numberColumns) {
+	  if (original.getColumnStatus(iOrig)!=ClpSimplex::atLowerBound) {
+	    numberBasic++;
+	    j1=j;
+	  }
+	} else {
+	  int iSet = iOrig - numberColumns;
+	  int iRow = whichRows[iSet+numberNonGub];
+	  if (original.getRowStatus(iRow)==ClpSimplex::basic) {
+	    numberBasic++;
+	    j1=j;
+	    abort();
+	  }
+	}
+      }
+      if (numberBasic==1&&numberNewBasic==1&&
+	  j1!=j2) {
+	int iOrig1=whichColumns[j1+numberNormal];
+	int iOrig2=whichColumns[j2+numberNormal];
+	ClpSimplex::Status status1 = original.getColumnStatus(iOrig1);
+	ClpSimplex::Status status2 = original.getColumnStatus(iOrig2);
+	originalSolution[iOrig1] = newSolution[j1];
+	originalSolution[iOrig2] = newSolution[j2];
+	original.setColumnStatus(iOrig1,status2);
+	original.setColumnStatus(iOrig2,status1);
+      }
+    }
+  }
+  delete [] newSolution;
+  delete [] slacks;
+  delete [] rowActivity;
+#else
+  for (int i=0;i<numberSets;i++) {
+    for (int j=startSet[i];j<startSet[i+1];j++) {
+      gubMatrix->setDynamicStatus(j,ClpDynamicMatrix::atLowerBound);
+      int iColumn = whichColumns[j+numberNormal];
+      if (iColumn<numberColumns) {
+	columnIsGub[iColumn] = whichRows[numberNonGub+i];
+      }
+    }
+  }
+#endif
+  int * numberKey = new int [numberRows];
+  memset(numberKey,0,numberRows*sizeof(int));
+  for (int i=0;i<numberGubColumns;i++) {
+    int iOrig = whichColumns[i+numberNormal];
+    if (iOrig<numberColumns) {
+      if (original.getColumnStatus(iOrig)==ClpSimplex::basic) {
+	int iRow = columnIsGub[iOrig];
+	assert (iRow>=0);
+	numberKey[iRow]++;
+      }
+    } else {
+      // Set slack
+      int iSet = iOrig - numberColumns;
+      int iRow = whichRows[iSet+numberNonGub];
+      if (original.getRowStatus(iRow)==ClpSimplex::basic) 
+	numberKey[iRow]++;
+    }
+  }
+  /* Before going into cleanMatrix we need
+     gub status set (inSmall just means basic and active)
+     row status set
+  */
+  for (int i = 0; i < numberSets; i++) {
+    gubMatrix->setStatus(i,ClpSimplex::isFixed);
+  }
+  for (int i = 0; i < numberGubColumns; i++) {
+    int iOrig = whichColumns[i+numberNormal];
+    if (iOrig<numberColumns) {
+      ClpSimplex::Status status = original.getColumnStatus(iOrig);
+      if (status==ClpSimplex::atUpperBound) {
+	gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::atUpperBound);
+      } else if (status==ClpSimplex::atLowerBound) {
+	gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::atLowerBound);
+      } else if (status==ClpSimplex::basic) {
+	int iRow = columnIsGub[iOrig];
+	assert (iRow>=0);
+	assert(numberKey[iRow]);
+	if (numberKey[iRow]==1)
+	  gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::soloKey);
+	else
+	  gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::inSmall);
+      }
+    } else {
+      // slack
+      int iSet = iOrig - numberColumns;
+      int iRow = whichRows[iSet+numberNonGub];
+      if (original.getRowStatus(iRow)==ClpSimplex::basic
+#ifdef TRY_IMPROVE
+	  ||newSolution[i]>columnLower[i]+1.0e-8
+#endif
+	  ) {
+	assert(numberKey[iRow]);
+	if (numberKey[iRow]==1)
+	  gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::soloKey);
+	else
+	  gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::inSmall);
+      } else {
+	gubMatrix->setDynamicStatus(i,ClpDynamicMatrix::atLowerBound);
+      }
+    }
+  }
+  // deal with sets without key
+  for (int i = 0; i < numberSets; i++) {
+    int iRow = whichRows[numberNonGub+i];
+    if (!numberKey[iRow]) {
+      double upper = upperSet[i]-1.0e-7;
+      if (original.getRowStatus(iRow)==ClpSimplex::basic) 
+	gubMatrix->setStatus(i,ClpSimplex::basic);
+      // If not at lb make key otherwise one with smallest number els
+      double largest=0.0;
+      int fewest=numberRows+1;
+      int chosen=-1;
+      for (int j=startSet[i];j<startSet[i+1];j++) {
+	int length=columnStart[j+1]-columnStart[j];
+	int iOrig = whichColumns[j+numberNormal];
+	double value;
+	if (iOrig<numberColumns) {
+#ifdef TRY_IMPROVE
+	  value=newSolution[j]-columnLower[j];
+#else
+	  value = originalSolution[iOrig]-columnLower[j];
+#endif
+	  if (value>upper)
+	    gubMatrix->setStatus(i,ClpSimplex::atLowerBound);
+	} else {
+	  // slack - take value as 0.0 as will win on length
+	  value=0.0;
+	}
+	if (value>largest+1.0e-8) {
+	  largest=value;
+	  fewest=length;
+	  chosen=j;
+	} else if (fabs(value-largest)<=1.0e-8&&length<fewest) {
+	  largest=value;
+	  fewest=length;
+	  chosen=j;
+	}
+      }
+      assert(chosen>=0);
+      if (gubMatrix->getStatus(i)!=ClpSimplex::basic) {
+	// set as key
+	for (int j=startSet[i];j<startSet[i+1];j++) {
+	  if (j!=chosen)
+	    gubMatrix->setDynamicStatus(j,ClpDynamicMatrix::atLowerBound);
+	  else
+	    gubMatrix->setDynamicStatus(j,ClpDynamicMatrix::soloKey);
+	}
+      }
+    }
+  }
+  for (int i = 0; i < numberNormal; i++) {
+    int iOrig = whichColumns[i];
+    setColumnStatus(i,original.getColumnStatus(iOrig));
+    solution[i]=originalSolution[iOrig];
+  }
+  for (int i = 0; i < numberNonGub; i++) {
+    int iOrig = whichRows[i];
+    setRowStatus(i,original.getRowStatus(iOrig));
+  }
+  // Fill in current matrix
+  gubMatrix->initialProblem();
+  delete [] numberKey;
+  delete [] columnIsGub;
+}
+// Restores basis to original
+void 
+ClpSimplexOther::getGubBasis(ClpSimplex &original,const int * whichRows,
+			     const int * whichColumns) const
+{
+  ClpDynamicMatrix * gubMatrix =
+    dynamic_cast< ClpDynamicMatrix*>(clpMatrix());
+  assert(gubMatrix);
+  int numberGubColumns = gubMatrix->numberGubColumns();
+  int numberNormal = gubMatrix->firstDynamic();
+  //int lastOdd = gubMatrix->firstAvailable();
+  //int numberRows = original.numberRows();
+  int numberColumns = original.numberColumns();
+  int numberNonGub = gubMatrix->numberStaticRows();
+  //assert (firstOdd==numberNormal);
+  double * solution = primalColumnSolution();
+  double * originalSolution = original.primalColumnSolution();
+  int numberSets = gubMatrix->numberSets();
+  const double * cost = original.objective();
+  int lastOdd = gubMatrix->firstAvailable();
+  //assert (numberTotalColumns==numberColumns+numberSlacks);
+  int numberRows = original.numberRows();
+  //int numberStaticRows = gubMatrix->numberStaticRows();
+  const int * startSet = gubMatrix->startSets();
+  unsigned char * status = original.statusArray();
+  unsigned char * rowStatus = status+numberColumns;
+  //assert (firstOdd==numberNormal);
+  for (int i=0;i<numberSets;i++) {
+    int iRow = whichRows[i+numberNonGub];
+    original.setRowStatus(iRow,ClpSimplex::atLowerBound);
+  }
+  const int * id = gubMatrix->id();
+  const double * columnLower = gubMatrix->columnLower();
+  const double * columnUpper = gubMatrix->columnUpper();
+  for (int i = 0; i < numberGubColumns; i++) {
+    int iOrig = whichColumns[i+numberNormal];
+    if (iOrig<numberColumns) {
+      if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atUpperBound) {
+	originalSolution[iOrig] = columnUpper[i];
+	status[iOrig] = 2;
+      } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atLowerBound && columnLower) {
+	originalSolution[iOrig] = columnLower[i];
+	status[iOrig] = 3;
+      } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::soloKey) {
+	int iSet = gubMatrix->whichSet(i);
+	originalSolution[iOrig] = gubMatrix->keyValue(iSet);
+	status[iOrig] = 1;
+      } else {
+	originalSolution[iOrig] = 0.0;
+	status[iOrig] = 4;
+      }
+    } else {
+      // slack
+      int iSet = iOrig - numberColumns;
+      int iRow = whichRows[iSet+numberNonGub];
+      if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atUpperBound) {
+	original.setRowStatus(iRow,ClpSimplex::atLowerBound);
+      } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atLowerBound) {
+	original.setRowStatus(iRow,ClpSimplex::atUpperBound);
+      } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::soloKey) {
+	original.setRowStatus(iRow,ClpSimplex::basic);
+      }
+    }
+  }
+  for (int i = 0; i < numberNormal; i++) {
+    int iOrig = whichColumns[i];
+    ClpSimplex::Status thisStatus = getStatus(i);
+    if (thisStatus == ClpSimplex::basic)
+      status[iOrig] = 1;
+    else if (thisStatus == ClpSimplex::atLowerBound)
+      status[iOrig] = 3;
+    else if (thisStatus == ClpSimplex::atUpperBound)
+      status[iOrig] = 2;
+    else if (thisStatus == ClpSimplex::isFixed)
+      status[iOrig] = 5;
+    else
+      abort();
+    originalSolution[iOrig] = solution[i];
+  }
+  for (int i = numberNormal; i < lastOdd; i++) {
+    int iOrig = whichColumns[id[i-numberNormal] + numberNormal];
+    if (iOrig<numberColumns) {
+      ClpSimplex::Status thisStatus = getStatus(i);
+      if (thisStatus == ClpSimplex::basic)
+	status[iOrig] = 1;
+      else if (thisStatus == ClpSimplex::atLowerBound)
+	status[iOrig] = 3;
+      else if (thisStatus == ClpSimplex::atUpperBound)
+	status[iOrig] = 2;
+      else if (thisStatus == ClpSimplex::isFixed)
+	status[iOrig] = 5;
+      else
+	abort();
+      originalSolution[iOrig] = solution[i];
+    } else {
+      // slack (basic probably)
+      int iSet = iOrig - numberColumns;
+      int iRow = whichRows[iSet+numberNonGub];
+      ClpSimplex::Status thisStatus = getStatus(i);
+      if (thisStatus == ClpSimplex::atLowerBound)
+	thisStatus = ClpSimplex::atUpperBound;
+      else if (thisStatus == ClpSimplex::atUpperBound)
+	thisStatus = ClpSimplex::atLowerBound;
+      original.setRowStatus(iRow,thisStatus);
+    }
+  }
+  for (int i = 0; i < numberNonGub; i++) {
+    int iOrig = whichRows[i];
+    ClpSimplex::Status thisStatus = getRowStatus(i);
+    if (thisStatus == ClpSimplex::basic)
+      rowStatus[iOrig] = 1;
+    else if (thisStatus == ClpSimplex::atLowerBound)
+      rowStatus[iOrig] = 3;
+    else if (thisStatus == ClpSimplex::atUpperBound)
+      rowStatus[iOrig] = 2;
+    else if (thisStatus == ClpSimplex::isFixed)
+      rowStatus[iOrig] = 5;
+    else
+      abort();
+  }
+  int * numberKey = new int [numberRows];
+  memset(numberKey,0,numberRows*sizeof(int));
+  for (int i=0;i<numberSets;i++) {
+    int iRow = whichRows[i+numberNonGub];
+    for (int j=startSet[i];j<startSet[i+1];j++) {
+      int iOrig = whichColumns[j+numberNormal];
+      if (iOrig<numberColumns) {
+	if (original.getColumnStatus(iOrig)==ClpSimplex::basic) {
+	  numberKey[iRow]++;
+	}
+      } else {
+	// slack
+	if (original.getRowStatus(iRow)==ClpSimplex::basic) 
+	  numberKey[iRow]++;
+      }
+    }
+  }
+  for (int i=0;i<numberSets;i++) {
+    int iRow = whichRows[i+numberNonGub];
+    if (!numberKey[iRow]) {
+      original.setRowStatus(iRow,ClpSimplex::basic);
+    }
+  }
+  delete [] numberKey;
+  double objValue = 0.0;
+  for (int i = 0; i < numberColumns; i++)
+    objValue += cost[i] * originalSolution[i];
+  //printf("objective value is %g\n", objValue);
+}
+/*
+  Modifies coefficients etc and if necessary pivots in and out.
+  All at same status will be done (basis may go singular).
+  User can tell which others have been done (i.e. if status matches).
+  If called from outside will change status and return 0 (-1 if not ClpPacked)
+  If called from event handler returns non-zero if user has to take action.
+  -1 - not ClpPackedMatrix
+  0 - no pivots
+  1 - pivoted
+  2 - pivoted and optimal
+  3 - refactorize
+  4 - worse than that
+  indices>=numberColumns are slacks (obviously no coefficients)
+  status array is (char) Status enum
+*/
+int 
+ClpSimplex::modifyCoefficientsAndPivot(int number,
+				       const int * which,
+				       const CoinBigIndex * start,
+				       const int * row,
+				       const double * newCoefficient,
+				       const unsigned char * newStatus,
+				       const double * newLower,
+				       const double * newUpper,
+				       const double * newObjective)
+{
+  ClpPackedMatrix* clpMatrix =
+    dynamic_cast< ClpPackedMatrix*>(matrix_);
+  bool canPivot = lower_!=NULL && factorization_!=NULL;
+  int returnCode=0;
+  if (!clpMatrix) {
+    canPivot=false;
+    returnCode=-1;
+    // very slow
+    for (int i=0;i<number;i++) {
+      int iSequence=which[i];
+      if (iSequence<numberColumns_) {
+	for (CoinBigIndex j=start[i];j<start[i+1];j++) {
+ 	  matrix_->modifyCoefficient(row[j],iSequence,newCoefficient[j]);
+	}
+      } else {
+	assert (start[i]==start[i+1]);
+      }
+    }
+  } else {
+#if 0
+    // when in stable
+    CoinPackedMatrix * matrix = clpMatrix->getPackedMatrix();
+    matrix->modifyCoefficients(number,which,start,
+			       row,newCoefficient);
+#else
+    // Copy and sort which
+    int * which2 = new int [2*number+2];
+    int * sort = which2+number+1;
+    int n=0;
+    for (int i=0;i<number;i++) {
+      int iSequence=which[i];
+      if (iSequence<numberColumns_) {
+	which2[n]=iSequence;
+	sort[n++]=i;
+      } else {
+	assert (start[i]==start[i+1]);
+      }
+    }
+    if (n) {
+      CoinIndexedVector * rowVector=NULL;
+      for (int i=0;i<4;i++) {
+	if (rowArray_[i]&&!rowArray_[i]->getNumElements()) {
+	  rowVector = rowArray_[i];
+	  break;
+	}
+      }
+      bool tempVector=false;
+      if (!rowVector) {
+	tempVector=true;
+	rowVector=new CoinIndexedVector(numberRows_);
+      }
+      CoinSort_2(which2,which2+n,sort);
+      // Stop at end
+      which2[n]=numberColumns_;
+      sort[n]=n;
+      CoinPackedMatrix * matrix = clpMatrix->getPackedMatrix();
+      int * rowNow = matrix->getMutableIndices();
+      CoinBigIndex * columnStart = matrix->getMutableVectorStarts();
+      int * columnLength = matrix->getMutableVectorLengths();
+      double * elementByColumn = matrix->getMutableElements();
+      double * array = rowVector->denseVector();
+      //int * index = rowVector->getIndices();
+      int needed=0;
+      bool moveUp=false;
+      for (int i=0;i<n;i++) {
+	int inWhich=sort[i];
+	int iSequence=which2[inWhich];
+	int nZeroNew=0;
+	int nZeroOld=0;
+	for (CoinBigIndex j=start[inWhich];j<start[inWhich+1];j++) {
+	  int iRow=row[j];
+	  double newValue=newCoefficient[j];
+	  if (!newValue) {
+	    newValue = COIN_INDEXED_REALLY_TINY_ELEMENT;
+	    nZeroNew++;
+	  }
+	  array[iRow]=newValue;
+	}
+	for (CoinBigIndex j=columnStart[iSequence];
+	     j<columnStart[iSequence]+columnLength[iSequence];j++) {
+	  int iRow=rowNow[j];
+	  double oldValue=elementByColumn[j];
+	  if (fabs(oldValue)>COIN_INDEXED_REALLY_TINY_ELEMENT) {
+	    double newValue=array[iRow];
+	    if (oldValue!=newValue) {
+	      if (newValue) {
+		array[iRow]=0.0;
+		if (newValue==COIN_INDEXED_REALLY_TINY_ELEMENT) {
+		  needed--;
+		}
+	      }
+	    }
+	  } else {
+	    nZeroOld++;
+	  }
+	}
+	assert (!nZeroOld);
+	for (CoinBigIndex j=start[inWhich];j<start[inWhich+1];j++) {
+	  int iRow=row[j];
+	  double newValue=array[iRow];
+	  if (newValue) {
+	    array[iRow]=0.0;
+	    needed++;
+	    if (needed>0)
+	      moveUp=true;
+	  }
+	}
+      }
+      int numberElements = matrix->getNumElements();
+      assert (numberElements==columnStart[numberColumns_]);
+      if (needed>0) {
+	// need more space
+	matrix->reserve(numberColumns_, numberElements+needed);
+	rowNow = matrix->getMutableIndices();
+	elementByColumn = matrix->getMutableElements();
+      }
+      if (moveUp) {
+	// move up from top
+	CoinBigIndex top = numberElements+needed;
+	for (int iColumn=numberColumns_-1;iColumn>=0;iColumn--) {
+	  CoinBigIndex end = columnStart[iColumn+1];
+	  columnStart[iColumn+1]=top;
+	  CoinBigIndex startThis = columnStart[iColumn];
+	  for (CoinBigIndex j=end-1;j>=startThis;j--) {
+	    if (elementByColumn[j]) {
+	      top--;
+	      elementByColumn[top]=elementByColumn[j];
+	      rowNow[top]=rowNow[j];
+	    }
+	  }
+	}
+	columnStart[0]=top;
+      }
+      // now move down and insert
+      CoinBigIndex put=0;
+      int iColumn=0;
+      for (int i=0;i<n+1;i++) {
+	int inWhich=sort[i];
+	int nextMod=which2[inWhich];
+	for (;iColumn<nextMod;iColumn++) {
+	  CoinBigIndex startThis = columnStart[iColumn];
+	  columnStart[iColumn]=put;
+	  for (CoinBigIndex j=startThis;
+	       j<columnStart[iColumn+1];j++) {
+	    int iRow=rowNow[j];
+	    double oldValue=elementByColumn[j];
+	    if (oldValue) {
+	      rowNow[put]=iRow;
+	      elementByColumn[put++]=oldValue;
+	    }
+	  }
+	}
+	if (i==n) {
+	  columnStart[iColumn]=put;
+	  break;
+	}
+	// Now 
+	for (CoinBigIndex j=start[inWhich];j<start[inWhich+1];j++) {
+	  int iRow=row[j];
+	  double newValue=newCoefficient[j];
+	  if (!newValue) {
+	    newValue = COIN_INDEXED_REALLY_TINY_ELEMENT;
+	  }
+	  array[iRow]=newValue;
+	}
+	CoinBigIndex startThis = columnStart[iColumn];
+	columnStart[iColumn]=put;
+	for (CoinBigIndex j=startThis;
+	     j<columnStart[iColumn+1];j++) {
+	  int iRow=rowNow[j];
+	  double oldValue=elementByColumn[j];
+	  if (array[iRow]) {
+	    oldValue=array[iRow];
+	    if (oldValue==COIN_INDEXED_REALLY_TINY_ELEMENT) 
+	      oldValue=0.0;
+	    array[iRow]=0.0;
+	  }
+	  if (fabs(oldValue)>COIN_INDEXED_REALLY_TINY_ELEMENT) {
+	    rowNow[put]=iRow;
+	    elementByColumn[put++]=oldValue;
+	  }
+	}
+	for (CoinBigIndex j=start[inWhich];j<start[inWhich+1];j++) {
+	  int iRow=row[j];
+	  double newValue=array[iRow];
+	  if (newValue) {
+	    array[iRow]=0.0;
+	    rowNow[put]=iRow;
+	    elementByColumn[put++]=newValue;
+	  }
+	}
+	iColumn++;
+      }
+      matrix->setNumElements(put);
+      if (tempVector)
+	delete rowVector;
+      for (int i=0;i<numberColumns_;i++) {
+	columnLength[i]=columnStart[i+1]-columnStart[i];
+      }
+    }
+#endif
+    if (canPivot) {
+      // ? faster to modify row copy??
+      if (rowCopy_&&start[number]) {
+	delete rowCopy_;
+	rowCopy_ = clpMatrix->reverseOrderedCopy();
+      }
+      assert (!newStatus); // do later
+      int numberPivots = factorization_->pivots();
+      int needed=0;
+      for (int i=0;i<number;i++) {
+	int iSequence=which[i];
+	if (start[i+1]>start[i]&&getStatus(iSequence)==basic)
+	  needed++;
+      }
+      if (needed&&numberPivots+needed<20&&needed<-2) {
+	// update factorization
+	int saveIn = sequenceIn_;
+	int savePivot = pivotRow_;
+	int nArray=0;
+	CoinIndexedVector * vec[2];
+	for (int i=0;i<4;i++) {
+	  if (!rowArray_[i]->getNumElements()) {
+	    vec[nArray++]=rowArray_[i];
+	    if (nArray==2)
+	      break;
+	  }
+	}
+	assert (nArray==2); // could use temp array
+	for (int i=0;i<number;i++) {
+	  int sequenceIn_=which[i];
+	  if (start[i+1]>start[i]&&getStatus(sequenceIn_)==basic) {
+	    // find pivot row
+	    for (pivotRow_=0;pivotRow_<numberRows_;pivotRow_++) {
+	      if (pivotVariable_[pivotRow_]==sequenceIn_) 
+		break;
+	    }
+	    assert(pivotRow_<numberRows_);
+	    // unpack column
+	    assert(!vec[0]->getNumElements());
+#ifndef COIN_FAC_NEW
+	    unpackPacked(vec[0]);
+#else
+	    unpack(vec[0]);
+#endif
+	    // update
+	    assert(!vec[1]->getNumElements());
+	    factorization_->updateColumnFT(vec[1], vec[0]);
+	    const double * array = vec[0]->denseVector();
+#ifndef COIN_FAC_NEW
+	    // Find alpha
+	    const int * indices = vec[0]->getIndices();
+	    int n=vec[0]->getNumElements();
+	    alpha_=0.0;
+	    for (int i=0;i<n;i++) {
+	      if (indices[i]==pivotRow_) {
+		alpha_ = array[i];
+		break;
+	      }
+	    }
+#else
+	    alpha_ = array[pivotRow_];
+#endif
+	    int updateStatus=2;
+	    if (fabs(alpha_)>1.0e-7) 
+	      updateStatus = factorization_->replaceColumn(this,
+							   vec[1],
+							   vec[0],
+							   pivotRow_,
+							   alpha_);
+	    assert(!vec[1]->getNumElements());
+	    vec[0]->clear();
+	    if (updateStatus) {
+	      returnCode=3;
+	      break;
+	    }
+	  }
+	}
+	sequenceIn_=saveIn;
+	pivotRow_ = savePivot;
+	if (!returnCode)
+	  returnCode=100; // say can do more
+      } else if (needed) {
+	returnCode=3; // refactorize
+      }
+    }
+  }
+  if (newStatus) {
+    for (int i=0;i<number;i++) {
+      int iSequence=which[i];
+      status_[iSequence]=newStatus[i];
+    }
+  }
+  if (newLower) {
+    for (int i=0;i<number;i++) {
+      int iSequence=which[i];
+      if (iSequence<numberColumns_) {
+	if (columnLower_[iSequence]!=newLower[i]) {
+	  columnLower_[iSequence]=newLower[i];
+	}
+      } else {
+	iSequence -= numberColumns_;
+	if (rowLower_[iSequence]!=newLower[i]) {
+	  rowLower_[iSequence]=newLower[i];
+	}
+      }
+    }
+  }
+  if (newLower) {
+    for (int i=0;i<number;i++) {
+      int iSequence=which[i];
+      if (iSequence<numberColumns_) {
+	if (columnLower_[iSequence]!=newLower[i]) {
+	  columnLower_[iSequence]=newLower[i];
+	}
+      } else {
+	iSequence -= numberColumns_;
+	if (rowLower_[iSequence]!=newLower[i]) {
+	  rowLower_[iSequence]=newLower[i];
+	}
+      }
+    }
+  }
+  if (newUpper) {
+    for (int i=0;i<number;i++) {
+      int iSequence=which[i];
+      if (iSequence<numberColumns_) {
+	if (columnUpper_[iSequence]!=newUpper[i]) {
+	  columnUpper_[iSequence]=newUpper[i];
+	}
+      } else {
+	iSequence -= numberColumns_;
+	if (rowUpper_[iSequence]!=newUpper[i]) {
+	  rowUpper_[iSequence]=newUpper[i];
+	}
+      }
+    }
+  }
+  if (newObjective) {
+    double * obj = objective();
+    for (int i=0;i<number;i++) {
+      int iSequence=which[i];
+      if (iSequence<numberColumns_) {
+	if (obj[iSequence]!=newObjective[i]) {
+	  obj[iSequence]=newObjective[i];
+	}
+      } else {
+	  assert (!newObjective[i]);
+      }
+    }
+  }
+  if (canPivot) {
+    // update lower, upper, objective and nonLinearCost
+    assert (!rowScale_); // for now
+    memcpy(lower_,columnLower_,numberColumns_*sizeof(double));
+    memcpy(lower_+numberColumns_,rowLower_,numberRows_*sizeof(double));
+    memcpy(upper_,columnUpper_,numberColumns_*sizeof(double));
+    memcpy(upper_+numberColumns_,rowUpper_,numberRows_*sizeof(double));
+    memcpy(cost_,objective(),numberColumns_*sizeof(double));
+    memset(cost_+numberColumns_,0,numberRows_*sizeof(double));
+    // ? parameter to say no gutsOfSolution needed
+    // make sure slacks have correct value
+    // see if still optimal
+    if (returnCode==100) {
+      // is this needed
+      if (nonLinearCost_) {
+	// speed up later
+	//nonLinearCost_->checkInfeasibilities(oldTolerance);
+	delete nonLinearCost_;
+	nonLinearCost_ = new ClpNonLinearCost(this);
+      }
+      gutsOfSolution(NULL,NULL,false);
+      assert (!newStatus);
+      printf("%d primal %d dual\n",numberPrimalInfeasibilities_,
+	     numberDualInfeasibilities_);
+      returnCode=3;
+    } else {
+      // is this needed
+      if (nonLinearCost_) {
+	// speed up later
+#if 1
+	for (int i=0;i<number;i++) {
+	  int iSequence=which[i];
+	  nonLinearCost_->setOne(iSequence,solution_[iSequence],
+				 lower_[iSequence],upper_[iSequence],
+				 cost_[iSequence]);
+	}
+#else	
+	//nonLinearCost_->checkInfeasibilities(oldTolerance);
+	delete nonLinearCost_;
+	nonLinearCost_ = new ClpNonLinearCost(this);
+	//nonLinearCost_->checkInfeasibilities(0.0);
+#endif
+	//gutsOfSolution(NULL,NULL,false);
+	assert (!newStatus);
+      }
+    }
+  }
+  return returnCode;
+}
+
+/* Pivot out a variable and choose an incoing one.  Assumes dual
+   feasible - will not go through a reduced cost.
+   Returns step length in theta
+   Return codes as before but -1 means no acceptable pivot
+*/
+int
+ClpSimplex::dualPivotResultPart1()
+{
+     return static_cast<ClpSimplexDual *> (this)->pivotResultPart1();
+}
+/* Do actual pivot
+   state is 1,3 if got tableau column in rowArray_[1]
+   2,3 if got tableau row in rowArray_[0] and columnArray_[0]
+*/
+int 
+ClpSimplex::pivotResultPart2(int algorithm,int state)
+{
+  if (!(state&1)) {
+    // update the incoming column
+#ifndef COIN_FAC_NEW
+    unpackPacked(rowArray_[1]);
+#else
+    unpack(rowArray_[1]);
+#endif
+    factorization_->updateColumnFT(rowArray_[2], rowArray_[1]);
+  }
+#define CHECK_TABLEAU 0
+  if (!(state&2)||CHECK_TABLEAU) {
+    // get tableau row
+    // create as packed
+    double direction = directionOut_;
+    assert (!rowArray_[2]->getNumElements());
+    assert (!columnArray_[1]->getNumElements());
+#if CHECK_TABLEAU
+    printf("rowArray0 old\n");
+    rowArray_[0]->print();
+    rowArray_[0]->clear();
+    printf("columnArray0 old\n");
+    columnArray_[0]->print();
+    columnArray_[0]->clear();
+#else
+    assert (!columnArray_[0]->getNumElements());
+    assert (!rowArray_[0]->getNumElements());
+#endif
+#ifndef COIN_FAC_NEW
+    rowArray_[0]->createPacked(1, &pivotRow_, &direction);
+#else
+    rowArray_[0]->createOneUnpackedElement(pivotRow_, direction);
+#endif
+    factorization_->updateColumnTranspose(rowArray_[2], rowArray_[0]);
+    rowArray_[3]->clear();
+    // put row of tableau in rowArray[0] and columnArray[0]
+    assert (!rowArray_[2]->getNumElements());
+    matrix_->transposeTimes(this, -1.0,
+			    rowArray_[0], rowArray_[2], columnArray_[0]);
+#if CHECK_TABLEAU
+    printf("rowArray0 new\n");
+    rowArray_[0]->print();
+    printf("columnArray0 new\n");
+    columnArray_[0]->print();
+#endif
+  }
+  assert (pivotRow_>=0);
+  assert (sequenceIn_>=0);
+  assert (sequenceOut_>=0);
+  int returnCode=-1;
+  if (algorithm>0) {
+    // replace in basis
+    int updateStatus = factorization_->replaceColumn(this,
+						     rowArray_[2],
+						     rowArray_[1],
+						     pivotRow_,
+						     alpha_);
+    if (!updateStatus) {
+      dualIn_ = cost_[sequenceIn_];
+      double * work = rowArray_[1]->denseVector();
+      int number = rowArray_[1]->getNumElements();
+      int * which = rowArray_[1]->getIndices();
+      for (int i = 0; i < number; i++) {
+	int iRow = which[i];
+#ifndef COIN_FAC_NEW
+	double alpha = work[i];
+#else
+	double alpha = work[iRow];
+#endif
+	int iPivot = pivotVariable_[iRow];
+	dualIn_ -= alpha * cost_[iPivot];
+      }
+      returnCode=0;
+      double multiplier = dualIn_ / alpha_;
+      // update column djs
+      int i;
+      int * index = columnArray_[0]->getIndices();
+      number = columnArray_[0]->getNumElements();
+      double * element = columnArray_[0]->denseVector();
+      assert (columnArray_[0]->packedMode());
+      for (i = 0; i < number; i++) {
+	int iSequence = index[i];
+	dj_[iSequence] += multiplier*element[i];
+	reducedCost_[iSequence] = dj_[iSequence];
+	element[i] = 0.0;
+      }
+      columnArray_[0]->setNumElements(0);
+      // and row djs
+      index = rowArray_[0]->getIndices();
+      number = rowArray_[0]->getNumElements();
+      element = rowArray_[0]->denseVector();
+#ifndef COIN_FAC_NEW
+      assert (rowArray_[0]->packedMode());
+      for (i = 0; i < number; i++) {
+	int iSequence = index[i];
+	dj_[iSequence+numberColumns_] += multiplier*element[i];
+	dual_[iSequence] = dj_[iSequence+numberColumns_];
+	element[i] = 0.0;
+      }
+#else
+      assert (!rowArray_[0]->packedMode());
+      for (i = 0; i < number; i++) {
+	int iSequence = index[i];
+	dj_[iSequence+numberColumns_] += multiplier*element[iSequence];
+	dual_[iSequence] = dj_[iSequence+numberColumns_];
+	element[iSequence] = 0.0;
+      }
+#endif
+      rowArray_[0]->setNumElements(0);
+      double oldCost = cost_[sequenceOut_];
+      // update primal solution
+      
+      double objectiveChange = 0.0;
+      // after this rowArray_[1] is not empty - used to update djs
+      static_cast<ClpSimplexPrimal *>(this)->updatePrimalsInPrimal(rowArray_[1], theta_, objectiveChange, 0);
+      double oldValue = valueIn_;
+      if (directionIn_ == -1) {
+	// as if from upper bound
+	if (sequenceIn_ != sequenceOut_) {
+	  // variable becoming basic
+	  valueIn_ -= fabs(theta_);
+	} else {
+	  valueIn_ = lowerIn_;
+	}
+      } else {
+	// as if from lower bound
+	if (sequenceIn_ != sequenceOut_) {
+	  // variable becoming basic
+	  valueIn_ += fabs(theta_);
+	} else {
+	  valueIn_ = upperIn_;
+	}
+      }
+      objectiveChange += dualIn_ * (valueIn_ - oldValue);
+      // outgoing
+      if (sequenceIn_ != sequenceOut_) {
+	if (directionOut_ > 0) {
+	  valueOut_ = lowerOut_;
+	} else {
+	  valueOut_ = upperOut_;
+	}
+	if(valueOut_ < lower_[sequenceOut_] - primalTolerance_)
+	  valueOut_ = lower_[sequenceOut_] - 0.9 * primalTolerance_;
+	else if (valueOut_ > upper_[sequenceOut_] + primalTolerance_)
+	  valueOut_ = upper_[sequenceOut_] + 0.9 * primalTolerance_;
+	// may not be exactly at bound and bounds may have changed
+	// Make sure outgoing looks feasible
+	directionOut_ = nonLinearCost_->setOneOutgoing(sequenceOut_, valueOut_);
+	// May have got inaccurate
+	//if (oldCost!=cost_[sequenceOut_])
+	//printf("costchange on %d from %g to %g\n",sequenceOut_,
+	//       oldCost,cost_[sequenceOut_]);
+	dj_[sequenceOut_] = cost_[sequenceOut_] - oldCost; // normally updated next iteration
+	solution_[sequenceOut_] = valueOut_;
+      }
+      // change cost and bounds on incoming if primal
+      nonLinearCost_->setOne(sequenceIn_, valueIn_);
+      progress_.startCheck(); // make sure won't worry about cycling
+      int whatNext = housekeeping(objectiveChange);
+      if (whatNext == 1) {
+	returnCode = -2; // refactorize
+      } else if (whatNext == 2) {
+	// maximum iterations or equivalent
+	returnCode = 3;
+      } else if(numberIterations_ == lastGoodIteration_
+		+ 2 * factorization_->maximumPivots()) {
+	// done a lot of flips - be safe
+	returnCode = -2; // refactorize
+      }
+    } else {
+      // ?
+      abort();
+    }
+  } else {
+    // dual
+    // recompute dualOut_
+    if (directionOut_ < 0) {
+      dualOut_ = valueOut_ - upperOut_;
+    } else {
+      dualOut_ = lowerOut_ - valueOut_;
+    }
+    // update the incoming column
+    double btranAlpha = -alpha_ * directionOut_; // for check
+    rowArray_[1]->clear();
+#ifndef COIN_FAC_NEW
+    unpackPacked(rowArray_[1]);
+#else
+    unpack(rowArray_[1]);
+#endif
+    // moved into updateWeights - factorization_->updateColumnFT(rowArray_[2],rowArray_[1]);
+    // and update dual weights (can do in parallel - with extra array)
+    alpha_ = dualRowPivot_->updateWeights(rowArray_[0],
+					  rowArray_[2],
+					  rowArray_[3],
+					  rowArray_[1]);
+    // see if update stable
+#ifdef CLP_DEBUG
+    if ((handler_->logLevel() & 32))
+      printf("btran alpha %g, ftran alpha %g\n", btranAlpha, alpha_);
+#endif
+    double checkValue = 1.0e-7;
+    // if can't trust much and long way from optimal then relax
+    if (largestPrimalError_ > 10.0)
+      checkValue = CoinMin(1.0e-4, 1.0e-8 * largestPrimalError_);
+    if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
+	fabs(btranAlpha - alpha_) > checkValue*(1.0 + fabs(alpha_))) {
+      handler_->message(CLP_DUAL_CHECK, messages_)
+	<< btranAlpha
+	<< alpha_
+	<< CoinMessageEol;
+      if (factorization_->pivots()) {
+	dualRowPivot_->unrollWeights();
+	problemStatus_ = -2; // factorize now
+	rowArray_[0]->clear();
+	rowArray_[1]->clear();
+	columnArray_[0]->clear();
+	returnCode = -2;
+	abort();
+	return returnCode;
+      } else {
+	// take on more relaxed criterion
+	double test;
+	if (fabs(btranAlpha) < 1.0e-8 || fabs(alpha_) < 1.0e-8)
+	  test = 1.0e-1 * fabs(alpha_);
+	else
+	  test = 1.0e-4 * (1.0 + fabs(alpha_));
+	if (fabs(btranAlpha) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
+	    fabs(btranAlpha - alpha_) > test) {
+	  abort();
+	}
+      }
+    }
+    // update duals BEFORE replaceColumn so can do updateColumn
+    double objectiveChange = 0.0;
+    // do duals first as variables may flip bounds
+    // rowArray_[0] and columnArray_[0] may have flips
+    // so use rowArray_[3] for work array from here on
+    int nswapped = 0;
+    //rowArray_[0]->cleanAndPackSafe(1.0e-60);
+    //columnArray_[0]->cleanAndPackSafe(1.0e-60);
+    // make sure incoming doesn't count
+    Status saveStatus = getStatus(sequenceIn_);
+    setStatus(sequenceIn_, basic);
+    nswapped = 
+      static_cast<ClpSimplexDual *>(this)->updateDualsInDual(rowArray_[0], columnArray_[0],
+				 rowArray_[2], theta_,
+				 objectiveChange, false);
+    assert (!nswapped);
+    setStatus(sequenceIn_, saveStatus);
+    double oldDualOut = dualOut_;
+    // which will change basic solution
+    if (nswapped) {
+      if (rowArray_[2]->getNumElements()) {
+	factorization_->updateColumn(rowArray_[3], rowArray_[2]);
+	dualRowPivot_->updatePrimalSolution(rowArray_[2],
+					    1.0, objectiveChange);
+      }
+      // recompute dualOut_
+      valueOut_ = solution_[sequenceOut_];
+      if (directionOut_ < 0) {
+	dualOut_ = valueOut_ - upperOut_;
+      } else {
+	dualOut_ = lowerOut_ - valueOut_;
+      }
+    }
+    // amount primal will move
+    double movement = -dualOut_ * directionOut_ / alpha_;
+    double movementOld = oldDualOut * directionOut_ / alpha_;
+    // so objective should increase by fabs(dj)*movement
+    // but we already have objective change - so check will be good
+    if (objectiveChange + fabs(movementOld * dualIn_) < -CoinMax(1.0e-5, 1.0e-12 * fabs(objectiveValue_))) {
+      if (handler_->logLevel() & 32)
+	printf("movement %g, swap change %g, rest %g  * %g\n",
+	       objectiveChange + fabs(movement * dualIn_),
+	       objectiveChange, movement, dualIn_);
+    }
+    // if stable replace in basis
+    int updateStatus = factorization_->replaceColumn(this,
+						     rowArray_[2],
+						     rowArray_[1],
+						     pivotRow_,
+						     alpha_);
+    // If looks like bad pivot - refactorize
+    if (fabs(dualOut_) > 1.0e50)
+      updateStatus = 2;
+    // if no pivots, bad update but reasonable alpha - take and invert
+    if (updateStatus == 2 &&
+	!factorization_->pivots() && fabs(alpha_) > 1.0e-5)
+      updateStatus = 4;
+    if (updateStatus == 1 || updateStatus == 4) {
+      // slight error
+      if (factorization_->pivots() > 5 || updateStatus == 4) {
+	problemStatus_ = -2; // factorize now
+	returnCode = -3;
+      }
+    } else if (updateStatus == 2) {
+      // major error
+      dualRowPivot_->unrollWeights();
+      // later we may need to unwind more e.g. fake bounds
+      if (factorization_->pivots() &&
+	  ((moreSpecialOptions_ & 16) == 0 || factorization_->pivots() > 4)) {
+	problemStatus_ = -2; // factorize now
+	returnCode = -2;
+	moreSpecialOptions_ |= 16;
+	return returnCode;
+      } else {
+	// need to reject something
+	abort();
+      }
+    } else if (updateStatus == 3) {
+      // out of memory
+      // increase space if not many iterations
+      if (factorization_->pivots() <
+	  0.5 * factorization_->maximumPivots() &&
+	  factorization_->pivots() < 200)
+	factorization_->areaFactor(
+				   factorization_->areaFactor() * 1.1);
+      problemStatus_ = -2; // factorize now
+    } else if (updateStatus == 5) {
+      problemStatus_ = -2; // factorize now
+    }
+    // update primal solution
+    if (theta_ < 0.0) {
+      if (handler_->logLevel() & 32)
+	printf("negative theta %g\n", theta_);
+      theta_ = 0.0;
+    }
+    // do actual flips (should not be any?)
+    static_cast<ClpSimplexDual *>(this)->flipBounds(rowArray_[0], columnArray_[0]);
+      //rowArray_[1]->expand();
+    dualRowPivot_->updatePrimalSolution(rowArray_[1],
+					movement,
+					objectiveChange);
+    // modify dualout
+    dualOut_ /= alpha_;
+    dualOut_ *= -directionOut_;
+    //setStatus(sequenceIn_,basic);
+    dj_[sequenceIn_] = 0.0;
+    double oldValue = valueIn_;
+    if (directionIn_ == -1) {
+      // as if from upper bound
+      valueIn_ = upperIn_ + dualOut_;
+    } else {
+      // as if from lower bound
+      valueIn_ = lowerIn_ + dualOut_;
+    }
+    objectiveChange += cost_[sequenceIn_] * (valueIn_ - oldValue);
+    // outgoing
+    // set dj to zero unless values pass
+    if (directionOut_ > 0) {
+      valueOut_ = lowerOut_;
+      dj_[sequenceOut_] = theta_;
+    } else {
+      valueOut_ = upperOut_;
+      dj_[sequenceOut_] = -theta_;
+    }
+    solution_[sequenceOut_] = valueOut_;
+    int whatNext = housekeeping(objectiveChange);
+    // and set bounds correctly
+    static_cast<ClpSimplexDual *>(this)->originalBound(sequenceIn_);
+    static_cast<ClpSimplexDual *>(this)->changeBound(sequenceOut_);
+    if (whatNext == 1) {
+      problemStatus_ = -2; // refactorize
+    } else if (whatNext == 2) {
+      // maximum iterations or equivalent
+      problemStatus_ = 3;
+      returnCode = 3;
+      abort();
+    }
+  }
+  // Check event
+  {
+    int status = eventHandler_->event(ClpEventHandler::endOfIteration);
+    if (status >= 0) {
+      problemStatus_ = 5;
+      secondaryStatus_ = ClpEventHandler::endOfIteration;
+      returnCode = 3;
+    }
+  }
+  // need to be able to refactoriza
+  //printf("return code %d problem status %d\n",
+  //	 returnCode,problemStatus_);
+  return returnCode;
+}
+#ifdef COIN_SHORT_SORT
+#define USE_HASH 1
+#else
+#define USE_HASH 0
+#endif
+#if USE_HASH==2
+static const unsigned int mmult[] = {
+  262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247};
+// Returns a hash value
+inline unsigned int 
+hashValue(double value, unsigned int maxHash) 
+{
+  const char * name = reinterpret_cast<char *>(&value);
+  unsigned int n = 0;
+  for (int j = 0; j < 8; ++j ) {
+    n += mmult[j] * name[j];
+  }
+  return ( n  % maxHash );
+}
+/*
+ */
+static int sameTogether(unsigned int nin,int * which, double * weights,
+			int * which2, double * weights2, unsigned int * hash)
+{
+  if (nin<=1)
+    return nin;
+  // move up and fill hash
+  unsigned int maxHash=4*nin;
+  memset(hash,0xf0,maxHash*sizeof(int));
+  int * spare=which2+maxHash;
+  int n2=0;
+  unsigned int iNext = hashValue (weights[0],maxHash);
+  unsigned int endMarker=0x80000000+maxHash;
+  hash[iNext]=endMarker;
+  unsigned int iLast=iNext;
+  weights2[iNext]=weights[0];
+  which2[iNext]=which[0];
+  for (unsigned int i=1;i<nin;i++) {
+    double value = weights[i];
+    unsigned int ipos = hashValue (value,maxHash);
+    if ( hash[ipos] == 0xf0f0f0f0 ) {
+      hash[iLast] = ipos+0x80000000;
+      hash[ipos]=endMarker;
+      weights2[ipos]=value;
+      which2[ipos]=which[i];
+      iLast=ipos;
+    } else {
+      spare[n2++]=i;
+    }
+  }
+  unsigned int lastSlot = 0;
+  for (int j = 0; j < n2; ++j ) {
+    int i = spare[j];
+    double value=weights[i];
+    unsigned int ipos = hashValue ( value , maxHash);
+    iLast=ipos;
+    while ( hash[ipos] <= 0x80000000) {
+      iLast=ipos;
+      ipos=hash[ipos];
+    }
+    while (hash[lastSlot]!=0xf0f0f0f0)
+      lastSlot++;
+    assert (lastSlot<maxHash);
+    hash[lastSlot] = hash[ipos];
+    hash[iLast] = lastSlot;
+    weights2[lastSlot]=value;
+    which2[lastSlot]=which[i];
+  }
+  int put=0;
+  //unsigned int iNext=0;
+  int savePut=0;
+  while (iNext!=maxHash) {
+    weights[put]=weights2[iNext];
+    assert (iNext<maxHash);
+    which[put++]=which2[iNext];
+    iNext = hash[iNext];
+    if (iNext>0x7fffffff) {
+      // end 
+      if (put>savePut+1) {
+	CoinShortSort_2(weights+savePut,weights+put,which+savePut);
+	// keep
+#if 0
+	printf("DUP2 value %g ",weights[savePut]);
+	for (int i=savePut;i<put;i++)
+	  printf("%d (%g) ",which[i],weights[i]);
+	printf("\n");
+#endif
+	savePut=put;
+      } else {
+	// no
+	put=savePut;
+      }
+      iNext -= 0x80000000;
+    }
+  }
+  return savePut;
+}
+#endif
+#include "CoinPresolveMatrix.hpp"
+/* Take out duplicate rows (includes scaled rows and intersections).
+   On exit whichRows has rows to delete - return code is number can be deleted 
+   or -1 if would be infeasible.
+   If tolerance is -1.0 use primalTolerance for equality rows and infeasibility
+   If cleanUp not zero then spend more time trying to leave more stable row
+   and make row bounds exact multiple of cleanUp if close enough
+   moves status to try and delete a basic slack
+*/
+int 
+ClpSimplex::outDuplicateRows(int numberLook,int * whichRows, bool noOverlaps,
+			     double tolerance,double cleanUp) 
+{
+#if USE_HASH<2
+  double * weights = new double [numberLook+numberColumns_];
+#else
+  int numberAlloc=5*numberLook+numberColumns_+((9*numberLook+1)/(sizeof(double)/sizeof(int)));
+  double * weights = new double [numberAlloc];
+  double * weights2=weights+numberLook+numberColumns_;
+#endif
+  double * columnWeights = weights+numberLook;
+#ifndef COIN_REUSE_RANDOM
+  coin_init_random_vec(columnWeights,numberColumns_);
+#else
+  for (int i=0;i<numberColumns_;i++)
+    columnWeights[i]=CoinDrand48();
+#endif
+#if USE_HASH==1
+  typedef struct {
+#define INTEL // need way to find out at compile time
+#ifdef INTEL
+    int which;
+    float value;
+#else
+    float value;
+    int which;
+#endif
+  } hash_1;
+  typedef struct {
+    union {
+      double d;
+      hash_1 hash;
+    } item;
+  } hash;
+  assert (sizeof(double) == 8);
+  hash * hashWeights = reinterpret_cast<hash *>(weights);
+#endif
+#if 0
+  int counts[5]={0,0,0,0,0};
+  int countsEq[5]={0,0,0,0,0};
+#endif
+  // get row copy
+  CoinPackedMatrix rowCopy = *matrix();
+  rowCopy.reverseOrdering();
+  int * column = rowCopy.getMutableIndices();
+  CoinBigIndex * rowStart = rowCopy.getMutableVectorStarts();
+  int * rowLength = rowCopy.getMutableVectorLengths();
+  double * element = rowCopy.getMutableElements();
+  //double wwww[200];
+  //assert (numberLook<=200);
+  //int iiii[200];
+  for (int i=0;i<numberLook;i++) {
+    int iRow=whichRows[i];
+    double value = 0.0;
+    CoinBigIndex start=rowStart[iRow];
+    CoinBigIndex end = start+rowLength[iRow];
+    // sort (probably in order anyway)
+#ifdef COIN_SHORT_SORT
+    CoinShortSort_2(column+start,column+end,element+start);
+#else
+    CoinSort_2(column+start,column+end,element+start);
+#endif
+    for (CoinBigIndex j=start;j<end;j++) {
+      int iColumn = column[j];
+      value += columnWeights[iColumn];
+    }
+#if USE_HASH ==1
+    //printf("iLook %d weight %g (before)\n",i,value);
+    hash temp;
+    temp.item.d=value;
+    temp.item.hash.which=iRow;
+    hashWeights[i]=temp;
+    //wwww[i]=value;
+    //iiii[i]=iRow;
+#else
+    weights[i]=value;
+#endif
+  }
+  //#define PRINT_DUP
+#if USE_HASH == 0
+#if 0
+  if (false) {
+    double * w =CoinCopyOfArray(weights,numberLook);
+    int * ind = CoinCopyOfArray(whichRows,numberLook);
+    double * weights2=new double[50000];
+    int * which2 = reinterpret_cast<int *>(weights2+4*numberLook);
+    unsigned int * hash = reinterpret_cast<unsigned int *>(which2+5*numberLook);
+    int n=sameTogether(numberLook,ind,w,which2,weights2,hash);
+    printf("Reduced length of %d\n",n);
+    delete [] weights2;
+    delete [] w;
+    delete [] ind;
+  }
+#endif
+  CoinSort_2(weights,weights+numberLook,whichRows);
+#if 0
+  {
+    double value = weights[0];
+    int firstSame=-1;
+    int lastSame=-1;
+    for (int iLook = 1; iLook < numberLook; iLook++) {
+      if (weights[iLook]==value) {
+	if (firstSame<0) {
+	  /* see how many same - if >2 but < ? may be 
+	     worth looking at all combinations
+	  */
+	  firstSame=iLook-1;
+	  printf("DUPS weight %g first row %d ",value,whichRows[firstSame]);
+	  for (lastSame=iLook;lastSame<numberLook;lastSame++) {
+	    if (weights[lastSame]!=value)
+	      break;
+	    else
+	      printf(", %d ",whichRows[lastSame]);
+	  }
+	  printf("\n");
+	  //printf("dupsame %d rows have same weight",lastSame-firstSame);
+	}
+      } else {
+	firstSame=-1;
+	value=weights[iLook];
+      }
+    }
+  }
+#endif
+#elif USE_HASH==1
+  std::sort(weights,weights+numberLook);
+#ifdef PRINT_DUP
+  //CoinSort_2(wwww,wwww+numberLook,iiii);
+  for (int i=0;i<numberLook;i++) {
+    hash * temp = reinterpret_cast<hash *>(weights+i);
+    whichRows[i]=temp->item.hash.which;
+    weights[i]=temp->item.hash.value;
+    //printf("iLook %d weight %g (after) - true %d %g\n",
+    //	   whichRows[i],weights[i],iiii[i],wwww[i]);
+  }
+#undef USE_HASH
+#define USE_HASH 0
+#endif
+#else
+  int * which2 = reinterpret_cast<int *>(weights2+4*numberLook);
+  unsigned int * hash = reinterpret_cast<unsigned int *>(which2+5*numberLook);
+  numberLook=sameTogether(numberLook,whichRows,weights,which2,weights2,hash);
+  printf("Reduced length of %d\n",numberLook);
+#endif
+  if (tolerance<0.0)
+    tolerance = primalTolerance_;
+  int nPossible=0;
+  int nDelete=0;
+#if USE_HASH==1
+  hash * temp = reinterpret_cast<hash *>(weights);
+  int iLast=temp->item.hash.which;
+  float value=temp->item.hash.value;
+#else
+  double value = weights[0];
+  int iLast = whichRows[0];
+#endif
+  double inverseCleanup = (cleanUp>0.0) ? 1.0/cleanUp : 0.0;
+  //#define PRINT_DUP
+#ifdef PRINT_DUP
+  int firstSame=-1;
+  int lastSame=-1;
+#endif
+  for (int iLook = 1; iLook < numberLook; iLook++) {
+#if USE_HASH==1
+    hash * temp = reinterpret_cast<hash *>(weights+iLook);
+    int iThis=temp->item.hash.which;
+    float valueThis=temp->item.hash.value;
+#else
+    int iThis=whichRows[iLook];
+    double valueThis=weights[iLook];
+#endif
+    if (valueThis==value) {
+#ifdef PRINT_DUP
+      if (firstSame<0) {
+	/* see how many same - if >2 but < ? may be 
+	   worth looking at all combinations
+	*/
+	firstSame=iLook-1;
+	printf("DUPS weight %g first row %d ",value,whichRows[firstSame]);
+	for (lastSame=iLook;lastSame<numberLook;lastSame++) {
+	  if (weights[lastSame]!=value)
+	    break;
+	  else
+	    printf(", %d ",whichRows[lastSame]);
+	}
+	printf("\n");
+#endif
+      CoinBigIndex start = rowStart[iThis];
+      CoinBigIndex end = start + rowLength[iThis];
+      if (rowLength[iThis] == rowLength[iLast]) {
+	nPossible++;
+#ifdef PRINT_DUP
+	char line[520],temp[50];
+#endif
+	int ishift = rowStart[iLast] - start;
+	CoinBigIndex k;
+#ifdef PRINT_DUP
+	sprintf(line,"dupj %d,%d %d els ",
+		iThis,iLast,rowLength[iLast]);
+	int n=strlen(line);
+#endif
+	bool bad=false;
+	double multiplier=0.0;
+	for (k=start;k<end;k++) {
+	  if (column[k] != column[k+ishift]) {
+	    bad=true;
+	    break;
+	  } else {
+#ifdef PRINT_DUP
+	    sprintf(temp,"(%g,%g) ",element[k],element[k+ishift]);
+#endif
+	    if (!multiplier) {
+	      multiplier = element[k]/element[k+ishift];
+	    } else if(fabs(element[k+ishift]*multiplier-element[k])>1.0e-8) {
+	      bad=true;
+	    }
+#ifdef PRINT_DUP
+	    int n2=strlen(temp);
+	    if (n+n2<500) {
+	      strcat(line,temp);
+	      n += n2;
+	    } else {
+	      strcat(line,"...");
+	      break;
+	    }
+#endif
+	  }
+	}
+	if (!bad) {
+#ifdef PRINT_DUP
+	  printf("%s lo (%g,%g) up (%g,%g) - multiplier %g\n",line,rowLower_[iThis],rowUpper_[iThis],
+		 rowLower_[iLast],rowUpper_[iLast],multiplier);
+#endif
+	  double rlo1=rowLower_[iLast];
+	  double rup1=rowUpper_[iLast];
+	  double rlo2=rowLower_[iThis];
+	  double rup2=rowUpper_[iThis];
+	  // scale
+	  rlo1 *= multiplier;
+	  rup1 *= multiplier;
+	  //swap bounds if neg
+	  if (multiplier<0.0) {
+	    double temp = rup1;
+	    rup1=rlo1;
+	    rlo1=temp;
+	  }
+	  /* now check rhs to see what is what */
+#ifdef PRINT_DUP
+	  printf("duplicate row %g %g, %g %g\n",
+		 rlo1,rup1,rlo2,rup2);
+#endif
+	  if (!noOverlaps) {
+	    /* we always keep this and delete last 
+	       later maybe keep better formed one */
+	    rlo2 = CoinMax(rlo1,rlo2);
+	    if (rlo2<-1.0e30)
+	      rlo2=-COIN_DBL_MAX;
+	    rup2 = CoinMin(rup1,rup2);
+	    if (rup2>1.0e30)
+	      rup2=COIN_DBL_MAX;
+	  } else {
+	    /* keep better formed one */
+	    if (rlo2>=rlo1-1.0e-8&&rup2<=rup1+1.0e-8) {
+	      // ok
+	      rlo2 = CoinMax(rlo1,rlo2);
+	      if (rlo2<-1.0e30)
+		rlo2=-COIN_DBL_MAX;
+	      rup2 = CoinMin(rup1,rup2);
+	      if (rup2>1.0e30)
+		rup2=COIN_DBL_MAX;
+	    } else if (rlo1>=rlo2-1.0e-8&&rup1<=rup2+1.0e-8) {
+	      rlo2 = CoinMax(rlo1,rlo2);
+	      if (rlo2<-1.0e30)
+		rlo2=-COIN_DBL_MAX;
+	      rup2 = CoinMin(rup1,rup2);
+	      if (rup2>1.0e30)
+		rup2=COIN_DBL_MAX;
+	      // swap
+	      int temp=iLast;
+	      iLast=iThis;
+	      iThis=temp;
+	    } else {
+	      // leave (for now)
+#if DEBUG_SOME>0
+	      printf("row %d %g %g row %d %g %g\n",iLast,rlo1,rup1,iThis,rlo2,rup2);
+#endif
+	      iLast=iThis;
+	      continue;
+	    }
+	  }
+#ifdef PRINT_DUP
+	  printf("pre_duprow %dR %dR keep this\n",iLast,iThis);
+#endif
+#if 0
+	  if (rowLength[iThis]<4)
+	    counts[rowLength[iThis]]++;
+	  else
+	    counts[4]++;
+#endif
+	  if (rup2<rlo2-tolerance) {
+	    // infeasible
+	    nDelete=-1;
+	    break;
+	  } else if (fabs(rup2-rlo2)<=tolerance) {
+	    // equal - choose closer to zero
+	    if (fabs(rup2)<fabs(rlo2))
+	      rlo2=rup2;
+	    else
+	      rup2=rlo2;
+#if 0
+	  if (rowLength[iThis]<4)
+	    countsEq[rowLength[iThis]]++;
+	  else
+	    countsEq[4]++;
+#endif
+#ifdef PRINT_DUP
+	    printf("Row %d has %d elements == %g\n",
+		   iThis,end-start,rlo2);
+#endif
+	  }
+	  if (cleanUp>0.0) {
+	    /* see if close to multiple
+	       always allow integer values */
+	    if (rlo2>-1.0e30) {
+	      double value = rlo2;
+	      double value2 = floor(value+0.5);
+	      if (fabs(value-value2)<1.0e-9) {
+		rlo2=value2;
+	      } else {
+		value = rlo2*inverseCleanup;
+		value2 = floor(value+0.5);
+		if (fabs(value-value2)<1.0e-9)
+		  rlo2=value2*cleanUp;
+	      }
+	    }
+	    if (rup2<1.0e30) {
+	      double value = rup2;
+	      double value2 = floor(value+0.5);
+	      if (fabs(value-value2)<1.0e-9) {
+		rup2=value2;
+	      } else {
+		value = rup2*inverseCleanup;
+		value2 = floor(value+0.5);
+		if (fabs(value-value2)<1.0e-9)
+		  rup2=value2*cleanUp;
+	      }
+	    }
+	  }
+	  rowLower_[iThis]=rlo2;
+	  rowUpper_[iThis]=rup2;
+	  whichRows[nDelete++]=iLast;
+	  if (getRowStatus(iLast)!=basic) {
+	    if (getRowStatus(iThis)==basic) {
+	      setRowStatus(iThis,superBasic);
+	      setRowStatus(iLast,basic);
+	    }
+	  }
+	} else {
+#ifdef PRINT_DUP
+	  printf("%s lo (%g,%g) up (%g,%g) - ODD\n",line,rowLower_[iThis],rowUpper_[iThis],
+		 rowLower_[iLast],rowUpper_[iLast]);
+#endif
+	}
+      }
+    } else {
+#ifdef PRINT_DUP
+      // say no match
+      firstSame=-1;
+#endif
+      value=valueThis;
+    }
+    iLast=iThis;
+  }
+#ifdef PRINT_DUP
+  printf("%d possible duplicate rows - deleting %d\n",
+	 nPossible,nDelete);
+#endif
+#if 0
+  for (int i=0;i<5;i++) {
+    if (counts[i])
+      printf("CC counts %d %d times of which %d were equalities\n",i,counts[i],countsEq[i]);
+  }
+#endif
+  delete [] weights;
+  return nDelete;
+}
+/* Try simple crash like techniques to get closer to primal feasibility
+   returns final sum of infeasibilities */
+double 
+ClpSimplex::moveTowardsPrimalFeasible()
+{
+  memset (rowActivity_,0,numberRows_*sizeof(double));
+  matrix()->times(columnActivity_,rowActivity_);
+  double sum=0.0;
+  int * which = new int[numberRows_];
+  int numberLook=0;
+  for (int iRow=0;iRow<numberRows_;iRow++) {
+    double value = rowActivity_[iRow];
+    double infeasibility = 0.0;
+    if (value<rowLower_[iRow]-primalTolerance_) 
+      infeasibility = rowLower_[iRow]-value;
+    else if (value>rowUpper_[iRow]+primalTolerance_) 
+      infeasibility = value-rowUpper_[iRow];
+    if (infeasibility) {
+      sum += infeasibility;
+      which[numberLook++]=iRow;
+    }
+  }
+  if (numberLook) {
+    const int * row = matrix_->getIndices();
+    const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+    const int * columnLength = matrix_->getVectorLengths();
+    const double * element = matrix_->getElements();
+    // get row copy
+    CoinPackedMatrix rowCopy = *matrix();
+    rowCopy.reverseOrdering();
+    const int * column = rowCopy.getIndices();
+    const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+    const int * rowLength = rowCopy.getVectorLengths();
+    const double * elementByRow = rowCopy.getElements();
+    double lastSum=COIN_DBL_MAX;
+    while (sum>primalTolerance_&&numberLook) {
+      sum =0.0;
+      double worst=primalTolerance_;
+      int iWorst=-1;
+      int n=numberLook;
+      numberLook=0;
+      for (int iLook=0;iLook<n;iLook++) {
+	int iRow=which[iLook];
+	double value = rowActivity_[iRow];
+	double infeasibility = 0.0;
+	if (value<rowLower_[iRow]-primalTolerance_) 
+	  infeasibility = rowLower_[iRow]-value;
+	else if (value>rowUpper_[iRow]+primalTolerance_) 
+	  infeasibility = value-rowUpper_[iRow];
+	if (infeasibility) {
+	  sum += infeasibility;
+	  which[numberLook++]=iRow;
+	  if (infeasibility>worst) {
+	    worst = infeasibility;
+	    iWorst=iRow;
+	  }
+	}
+      }
+      if (sum==0.0||sum>=lastSum-1.0e-8)
+	break;
+      lastSum=sum;
+      double direction;
+      if (rowActivity_[iWorst]<rowLower_[iWorst])
+	direction=1.0; // increase
+      else
+	direction=-1.0;
+      for (CoinBigIndex k=rowStart[iWorst];
+	   k<rowStart[iWorst]+rowLength[iWorst];k++) {
+	if (worst<primalTolerance_) 
+	  break;
+	int iColumn = column[k];
+	double value=elementByRow[k]*direction;
+	double distance=worst;
+	double multiplier = (value>0.0) ? 1.0 : -1.0;
+	// but allow for column bounds
+	double currentValue = columnActivity_[iColumn];
+	if (multiplier>0.0)
+	  distance = CoinMin(worst,columnUpper_[iColumn]-currentValue);
+	else
+	  distance = CoinMin(worst,currentValue-columnLower_[iColumn]);
+	distance /= fabs(value);
+	for (CoinBigIndex i=columnStart[iColumn];
+	     i<columnStart[iColumn]+columnLength[iColumn];i++) {
+	  int iRow=row[i];
+	  if (iRow!=iWorst) {
+	    double value2=element[i]*multiplier;
+	    if (value2>0.0) {
+	      double distance2 = rowUpper_[iRow]-rowActivity_[iRow]; 
+	      if (value2*distance>distance2)
+		distance = distance2/value2;
+	    } else {
+	      double distance2 = rowLower_[iRow]-rowActivity_[iRow]; 
+	      if (value2*distance<distance2)
+		distance = distance2/value2;
+	    }
+	  }
+	}
+	if (distance>1.0e-12) {
+	  worst-=distance*fabs(value);
+	  distance *= multiplier;
+	  columnActivity_[iColumn] = currentValue+distance;
+	  for (CoinBigIndex i=columnStart[iColumn];
+	       i<columnStart[iColumn]+columnLength[iColumn];i++) {
+	    int iRow=row[i];
+	    rowActivity_[iRow] += distance*element[i];
+	  }
+	}
+      }
+    }
+  }
+  delete [] which;
+  return sum;
+}
+/* Try simple crash like techniques to remove super basic slacks
+   but only if > threshold */
+void 
+ClpSimplex::removeSuperBasicSlacks(int threshold)
+{
+  // could try going both ways - for first attempt to nearer bound
+  memset (rowActivity_,0,numberRows_*sizeof(double));
+  matrix()->times(columnActivity_,rowActivity_);
+  double * distance = new double [numberRows_];
+  int * whichRows = new int [numberRows_];
+  int numberLook=0;
+  for (int iRow=0;iRow<numberRows_;iRow++) {
+    if (getRowStatus(iRow)!=basic) {
+      double value = rowActivity_[iRow];
+      if (value>rowLower_[iRow]+primalTolerance_&&
+	  value<rowUpper_[iRow]-primalTolerance_) {
+	setRowStatus(iRow,superBasic);
+	distance[numberLook]=CoinMin(value-rowLower_[iRow],
+				      rowUpper_[iRow]-value);
+	whichRows[numberLook++]=iRow;
+      }
+    }
+  }
+  if (numberLook>threshold) {
+    CoinSort_2(distance,distance+numberLook,whichRows);
+    const int * row = matrix_->getIndices();
+    const CoinBigIndex * columnStart = matrix_->getVectorStarts();
+    const int * columnLength = matrix_->getVectorLengths();
+    const double * element = matrix_->getElements();
+    // get row copy
+    CoinPackedMatrix rowCopy = *matrix();
+    rowCopy.reverseOrdering();
+    const int * column = rowCopy.getIndices();
+    const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+    const int * rowLength = rowCopy.getVectorLengths();
+    const double * elementByRow = rowCopy.getElements();
+    int nMoved=0;
+    for (int iLook=0;iLook<numberLook;iLook++) {
+      int kRow = whichRows[iLook];
+      double direction;
+      double needed;
+      if (rowUpper_[kRow]-rowActivity_[kRow]<rowActivity_[kRow]-rowLower_[kRow]) {
+	direction=1.0; // increase
+	needed = rowUpper_[kRow]-rowActivity_[kRow];
+      } else {
+	direction=-1.0;
+	needed = rowActivity_[kRow]-rowLower_[kRow];
+      }
+      for (CoinBigIndex k=rowStart[kRow];
+	 k<rowStart[kRow]+rowLength[kRow];k++) {
+	if (needed<primalTolerance_) 
+	  break;
+	int iColumn = column[k];
+	if (getColumnStatus(iColumn)!=basic)
+	  continue;
+	double value=elementByRow[k]*direction;
+	double distance;
+	double multiplier = (value>0.0) ? 1.0 : -1.0;
+	// but allow for column bounds
+	double currentValue = columnActivity_[iColumn];
+	if (multiplier>0.0)
+	  distance = columnUpper_[iColumn]-currentValue;
+	else
+	  distance = currentValue-columnLower_[iColumn];
+	for (CoinBigIndex i=columnStart[iColumn];
+	     i<columnStart[iColumn]+columnLength[iColumn];i++) {
+	  int iRow=row[i];
+	  double value2=element[i]*multiplier;
+	  if (value2>0.0) {
+	    double distance2 = rowUpper_[iRow]-rowActivity_[iRow]; 
+	    if (value2*distance>distance2)
+	      distance = distance2/value2;
+	  } else {
+	    double distance2 = rowLower_[iRow]-rowActivity_[iRow]; 
+	    if (value2*distance<distance2)
+	      distance = distance2/value2;
+	  }
+	}
+	if (distance>1.0e-12) {
+	  distance *= multiplier;
+	  columnActivity_[iColumn] = currentValue+distance;
+	  for (CoinBigIndex i=columnStart[iColumn];
+	       i<columnStart[iColumn]+columnLength[iColumn];i++) {
+	    int iRow=row[i];
+	    rowActivity_[iRow] += distance*element[i];
+	  }
+	  if (direction>0.0) {
+	    needed = rowUpper_[kRow]-rowActivity_[kRow];
+	  } else {
+	    needed = rowActivity_[kRow]-rowLower_[kRow];
+	  }
+	}
+      }
+      if (needed<primalTolerance_) {
+	nMoved++;
+	if (rowUpper_[kRow]-rowActivity_[kRow]<primalTolerance_) 
+	  setRowStatus(kRow,atUpperBound);
+	else if (rowActivity_[kRow]-rowLower_[kRow]<primalTolerance_)
+	  setRowStatus(kRow,atLowerBound);
+	else
+	  assert (rowUpper_[kRow]-rowActivity_[kRow]<primalTolerance_||
+		  rowActivity_[kRow]-rowLower_[kRow]<primalTolerance_);
+      }
+    }
+    char line[100];
+    sprintf(line,"Threshold %d found %d fixed %d",threshold,numberLook,nMoved);
+    handler_->message(CLP_GENERAL,messages_)
+      << line << CoinMessageEol;
+  }
+  delete [] distance;
+  delete [] whichRows;
+}
+/*
+  1 (and 4) redundant (and 8 is user)
+  2 sub
+  11 movable column
+  13 empty (or initially fixed) column
+  14 doubleton
+*/
+typedef struct {
+  double oldRowLower;
+  double oldRowUpper;
+  int row;
+  int lengthRow;
+} clpPresolveInfo1_4_8;
+// can be used instead of 1_4_8
+typedef struct {
+  double oldRowLower;
+  double oldRowUpper;
+  int row;
+  int lengthRow;
+  double * rowLowerX;
+  double * rowUpperX;
+  double * tempElement;
+  int * tempIndex;
+  int otherRow;
+} clpPresolveInfo8;
+typedef struct {
+  double oldRowLower;
+  double oldRowUpper;
+  double oldColumnLower;
+  double oldColumnUpper;
+  double coefficient;
+  // 2 is upper
+  double oldRowLower2;
+  double oldRowUpper2;
+  double coefficient2;
+  int row;
+  int row2;
+  int column;
+} clpPresolveInfo2;
+typedef struct {
+  double oldColumnLower;
+  double oldColumnUpper;
+  double fixedTo;
+  int column;
+  int lengthColumn;
+} clpPresolveInfo11;
+typedef struct {
+  double oldColumnLower;
+  double oldColumnUpper;
+  int column;
+} clpPresolveInfo13;
+typedef struct {
+  double oldColumnLower;
+  double oldColumnUpper;
+  double oldColumnLower2;
+  double oldColumnUpper2;
+  double oldObjective2;
+  double value1;
+  double rhs;
+  int type;
+  int row;
+  int column;
+  int column2;
+  int lengthColumn2;
+} clpPresolveInfo14;
+typedef struct {
+  int infoOffset;
+  int type;
+} clpPresolveInfo;
+typedef struct {
+  int numberEntries;
+  int maximumEntries;
+  int numberInitial;
+  clpPresolveInfo * start; 
+} listInfo;
+typedef struct {
+  char * putStuff;
+  char * startStuff;
+  CoinBigIndex maxStuff;
+} saveInfo;
+typedef struct {
+  double * elements;
+  int * indices;
+  char * startStuff;
+} restoreInfo;
+// struct must match in handler
+typedef struct {
+  ClpSimplex * model;
+  CoinPackedMatrix * rowCopy;
+  char * rowType;
+  char * columnType;
+  saveInfo * stuff;
+  clpPresolveInfo * info;
+  int * nActions;
+} clpPresolveMore;
+void ClpCopyToMiniSave(saveInfo & where, const char * info, unsigned int sizeInfo,int numberElements,
+			 const int * indices, const double * elements)
+{
+  char * put = where.putStuff;
+  int n = numberElements*static_cast<int>(sizeof(int)+sizeof(double))+static_cast<int>(sizeInfo);
+  if (n+(put-where.startStuff)>where.maxStuff) {
+    where.maxStuff += CoinMax(where.maxStuff/2 + 10000, 2*n);
+    char * temp = new char[where.maxStuff];
+    long k = put-where.startStuff;
+    memcpy(temp,where.startStuff,k);
+    delete [] where.startStuff;
+    where.startStuff=temp;
+    put = temp+k;
+  }
+  memcpy(put,info,sizeInfo);
+  put += sizeInfo;
+  memcpy(put,indices,numberElements*sizeof(int));
+  put += numberElements*sizeof(int);
+  memcpy(put,elements,numberElements*sizeof(double));
+  put += numberElements*sizeof(double);
+  where.putStuff=put;
+}
+static void copyFromSave(restoreInfo & where, clpPresolveInfo & info, void * thisInfoX)
+{
+  char * get = where.startStuff+info.infoOffset;
+  int type = info.type;
+  int n=0;
+  switch(type) {
+    case 1:
+    case 4:
+      // redundant
+      {
+	clpPresolveInfo1_4_8  thisInfo;
+	memcpy(&thisInfo,get,sizeof(clpPresolveInfo1_4_8));
+	memcpy(thisInfoX,get,sizeof(clpPresolveInfo1_4_8));
+	get += sizeof(clpPresolveInfo1_4_8);
+	n = thisInfo.lengthRow;
+      }
+      break;
+    case 8:
+    case 9:
+      // redundant
+      {
+	clpPresolveInfo8  thisInfo;
+	memcpy(&thisInfo,get,sizeof(clpPresolveInfo8));
+	memcpy(thisInfoX,get,sizeof(clpPresolveInfo8));
+	get += sizeof(clpPresolveInfo8);
+	n = thisInfo.lengthRow;
+      }
+      break;
+    case 2: 
+      // sub
+      {
+	clpPresolveInfo2 thisInfo;
+	memcpy(&thisInfo,get,sizeof(clpPresolveInfo2));
+	memcpy(thisInfoX,get,sizeof(clpPresolveInfo2));
+	get += sizeof(clpPresolveInfo2);
+      }
+      break;
+    case 11: 
+      // movable column
+      {
+	clpPresolveInfo11 thisInfo;
+	memcpy(&thisInfo,get,sizeof(clpPresolveInfo11));
+	memcpy(thisInfoX,get,sizeof(clpPresolveInfo11));
+	get += sizeof(clpPresolveInfo11);
+	n = thisInfo.lengthColumn;
+      }
+      break;
+    case 13: 
+      // empty (or initially fixed) column
+      {
+	clpPresolveInfo13 thisInfo;
+	memcpy(&thisInfo,get,sizeof(clpPresolveInfo13));
+	memcpy(thisInfoX,get,sizeof(clpPresolveInfo13));
+	get += sizeof(clpPresolveInfo13);
+      }
+      break;
+    case 14: 
+      // doubleton
+      {
+	clpPresolveInfo14 thisInfo;
+	memcpy(&thisInfo,get,sizeof(clpPresolveInfo14));
+	memcpy(thisInfoX,get,sizeof(clpPresolveInfo14));
+	get += sizeof(clpPresolveInfo14);
+	n = thisInfo.lengthColumn2;
+      }
+      break;
+  }
+  if (n) {
+    memcpy(where.indices,get,n*sizeof(int));
+    get += n*sizeof(int);
+    memcpy(where.elements,get,n*sizeof(double));
+  }
+}
+#define DEBUG_SOME 0
+// need more space
+static
+void moveAround(int numberColumns,CoinBigIndex numberElementsOriginal,
+		int iColumn,int lengthNeeded,
+		int * forward,int * backward,
+		CoinBigIndex * columnStart,int * columnLength,
+		int * row,double * element)
+{
+  // we only get here if can't fit so if iColumn is last one need shuffle
+  int last=backward[numberColumns];
+  bool needCompaction=false;
+  CoinBigIndex lastElement=columnStart[numberColumns];
+  //assert(lastElement==2*(numberElementsOriginal+numberColumns));
+  // save length
+  int length=columnLength[iColumn];
+  if (iColumn!=last) {
+    CoinBigIndex put=columnStart[last]+columnLength[last]+3;
+    if (put+lengthNeeded<=lastElement) {
+      // copy
+      CoinBigIndex start = columnStart[iColumn];
+      columnStart[iColumn]=put;
+      memcpy(element+put,element+start,length*sizeof(double));
+      memcpy(row+put,row+start,length*sizeof(int));
+      // forward backward
+      int iLast=backward[iColumn];
+      int iNext=forward[iColumn];
+      forward[iLast]=iNext;
+      backward[iNext]=iLast;
+      forward[last]=iColumn;
+      backward[iColumn]=last;
+      forward[iColumn]=numberColumns;
+      backward[numberColumns]=iColumn;
+    } else {
+      needCompaction=true;
+    }
+  } else {
+    needCompaction=true;
+  }
+  if (needCompaction) {
+    printf("compacting\n");
+    // size is lastElement+numberElementsOriginal
+#ifndef NDEBUG
+    CoinBigIndex total=lengthNeeded-columnLength[iColumn];
+    for (int i=0;i<numberColumns;i++)
+      total += columnLength[i];
+    assert (total<=numberElementsOriginal+lengthNeeded);
+#endif
+    CoinBigIndex put=lastElement;
+    for (int i=0;i<numberColumns;i++) {
+      CoinBigIndex start = columnStart[i];
+      columnStart[i]=put;
+      int n=columnLength[i];
+      memcpy(element+put,element+start,n*sizeof(double));
+      memcpy(row+put,row+start,n*sizeof(int));
+      put += n;
+    }
+    // replace length (may mean copying uninitialized)
+    columnLength[iColumn]=lengthNeeded;
+    int spare = (2*lastElement-put-(lengthNeeded-length)-numberElementsOriginal)/numberColumns;
+    assert (spare>=0);
+    // copy back
+    put=0;
+    for (int i=0;i<numberColumns;i++) {
+      CoinBigIndex start = columnStart[i];
+      columnStart[i]=put;
+      int n=columnLength[i];
+      memcpy(element+put,element+start,n*sizeof(double));
+      memcpy(row+put,row+start,n*sizeof(int));
+      put += n+spare;
+    }
+    assert (put<=lastElement);
+    columnLength[iColumn]=length;
+    // redo forward,backward
+    for (int i=-1;i<numberColumns;i++)
+      forward[i]=i+1;
+    forward[numberColumns]=-1;
+    for (int i=0;i<=numberColumns;i++)
+      backward[i]=i-1;
+    backward[-1]=-1;
+  }
+  //abort();
+#if DEBUG_SOME > 0
+  printf("moved column %d\n",iColumn);
+#endif
+}
+#if DEBUG_SOME > 0
+#ifndef NDEBUG
+static void checkBasis(ClpSimplex * model,char * rowType, char * columnType)
+{
+  int numberRows=model->numberRows();
+  int nRowBasic=0;
+  int nRows=0;
+  for (int i=0;i<numberRows;i++) {
+    if (rowType[i]<=0||rowType[i]==55) {
+      nRows++;
+      if(model->getRowStatus(i)==ClpSimplex::basic)
+	nRowBasic++;
+    }
+  }
+  int numberColumns=model->numberColumns();
+  int nColumnBasic=0;
+  for (int i=0;i<numberColumns;i++) {
+    if ((columnType[i]<11||columnType[i]==55)&&model->getColumnStatus(i)==ClpSimplex::basic)
+      nColumnBasic++;
+  }
+  ClpTraceDebug (nRowBasic+nColumnBasic==nRows);
+} 
+#endif
+#endif
+#if DEBUG_SOME > 0
+static int xxxxxx=2999999;
+#endif
+/* Mini presolve (faster)
+   Char arrays must be numberRows and numberColumns long
+   on entry second part must be filled in as follows -
+   0 - possible
+   >0 - take out and do something (depending on value - TBD)
+	       1 - redundant row
+	       2 - sub
+	       11 - column can be moved to bound
+	       4 - row redundant (duplicate)
+	       13 - empty (or initially fixed) column
+	       14 - == row (also column deleted by row)
+	       3 - column altered by a 14
+	       5 - temporary marker for truly redundant sub row
+	       8 - other
+   -1 row/column can't vanish but can have entries removed/changed
+   -2 don't touch at all
+   on exit <=0 ones will be in presolved problem
+   struct will be created and will be long enough
+   (information on length etc in first entry)
+   user must delete struct
+*/
+ClpSimplex * 
+ClpSimplex::miniPresolve(char * rowType, char * columnType,void ** infoOut)
+{
+  // Big enough structure
+  int numberTotal=numberRows_+numberColumns_;
+  CoinBigIndex lastElement = matrix_->getNumElements();
+  int maxInfoStuff = 5*lastElement*static_cast<int>(sizeof(double))+numberTotal*static_cast<int>(sizeof(clpPresolveInfo2));
+  clpPresolveInfo * infoA = new clpPresolveInfo[numberTotal];
+  char * startStuff = new char [maxInfoStuff];
+  memset(infoA,'B',numberTotal*sizeof(clpPresolveInfo));
+  memset(startStuff,'B',maxInfoStuff);
+  int nActions=0;
+  int * whichRows = new int [2*numberRows_+numberColumns_];
+  int * whichColumns = whichRows + numberRows_;
+  int * whichRows2 = whichColumns + numberColumns_;
+  double * array = new double [numberRows_];
+  memset(array,0,numberRows_*sizeof(double));
+  // New model (put in modification to increase size of matrix) and pack
+  bool needExtension=numberColumns_>matrix_->getNumCols();
+  if (needExtension) {
+    matrix()->reserve(numberColumns_,lastElement,true);
+    CoinBigIndex * columnStart = matrix()->getMutableVectorStarts();
+    for (int i=numberColumns_;i>=0;i--) {
+      if (columnStart[i]==0)
+	columnStart[i]=lastElement;
+      else
+	break;
+    }
+    assert (lastElement==columnStart[numberColumns_]);
+  }
+#define TWOFER
+#ifdef TWOFER
+  ClpSimplex * newModel = NULL;
+  CoinBigIndex lastPossible=3*lastElement;
+  CoinBigIndex lastGood=2*lastElement;
+  clpPresolveMore moreInfo;
+  moreInfo.model=NULL;
+  moreInfo.rowType=rowType;
+  moreInfo.columnType=columnType;
+  int addColumns = eventHandler_->eventWithInfo(ClpEventHandler::modifyMatrixInMiniPresolve,&moreInfo);
+  if (moreInfo.model) {
+    newModel = moreInfo.model;
+  } else {
+    newModel = new ClpSimplex(*this);
+    newModel->matrix()->reserve(numberColumns_+addColumns,lastPossible,true);
+  }
+#else
+  ClpSimplex * newModel = new ClpSimplex(*this);
+  //newModel->matrix()->reserve(numberColumns_,lastElement,true);
+#endif
+  newModel->dropNames();
+  double * rowLower = newModel->rowLower();
+  double * rowUpper = newModel->rowUpper();
+  //double * rowActivity = newModel->primalRowSolution();
+  unsigned char * rowStatus = newModel->statusArray()+numberColumns_;
+  // use top bit of status as marker for whichRows update
+  for (int i=0;i<numberRows_;i++)
+    rowStatus[i] &= 127;
+  double * columnLower = newModel->columnLower();
+  double * columnUpper = newModel->columnUpper();
+  //double * columnActivity = newModel->primalColumnSolution();
+  //unsigned char * columnStatus = newModel->statusArray();
+  // Take out marked stuff
+  saveInfo stuff;
+  stuff.putStuff=startStuff;
+  stuff.startStuff=startStuff;
+  stuff.maxStuff=maxInfoStuff;
+  CoinPackedMatrix * matrix = newModel->matrix();
+  int * row = matrix->getMutableIndices();
+  CoinBigIndex * columnStart = matrix->getMutableVectorStarts();
+  int * columnLength = matrix->getMutableVectorLengths();
+  double * element = matrix->getMutableElements();
+  // get row copy
+  CoinPackedMatrix rowCopy = *matrix;
+  rowCopy.reverseOrdering();
+  int * column = rowCopy.getMutableIndices();
+  CoinBigIndex * rowStart = rowCopy.getMutableVectorStarts();
+  double * elementByRow = rowCopy.getMutableElements();
+  int * rowLength = rowCopy.getMutableVectorLengths();
+  for (int iRow=0;iRow<numberRows_;iRow++) {
+    if (rowType[iRow]>0) {
+      clpPresolveInfo1_4_8  thisInfo;
+      thisInfo.row=iRow;
+      thisInfo.oldRowLower=(rowLower_[iRow]>-1.0e30) ? rowLower_[iRow]-rowLower[iRow] : rowLower[iRow];
+      thisInfo.oldRowUpper=(rowUpper_[iRow]<1.0e30) ? rowUpper_[iRow]-rowUpper[iRow] : rowUpper[iRow];
+      int n=rowLength[iRow];
+      CoinBigIndex start=rowStart[iRow];
+      thisInfo.lengthRow=n;
+      //thisInfo.column=-1;
+      infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
+      infoA[nActions].type=4; //rowType[iRow];
+      nActions++;
+      ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo1_4_8),
+			  n,column+start,elementByRow+start);
+    }
+  } 
+  CoinBigIndex put=0;
+  bool anyDeleted=false;
+  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+    CoinBigIndex start=columnStart[iColumn];
+    int length = columnLength[iColumn];
+    if (columnType[iColumn]>0||(columnType[iColumn]==0&&
+				(!length||columnLower_[iColumn]==columnUpper_[iColumn]))) {
+      clpPresolveInfo13 thisInfo;
+      //thisInfo.row=-1;
+      thisInfo.oldColumnLower=columnLower[iColumn];
+      thisInfo.oldColumnUpper=columnUpper[iColumn];
+      thisInfo.column=iColumn;
+      CoinBigIndex start=columnStart[iColumn];
+      infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
+      infoA[nActions].type=(columnType[iColumn]>0) ? columnType[iColumn] : 13;
+      nActions++;
+      ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo13),
+		 0,NULL,NULL);
+      columnType[iColumn]=13;
+      if (length) {
+	double solValue=columnLower[iColumn];
+	if (solValue) {
+	  for (int j=start;j<start+length;j++) {
+	    int iRow=row[j];
+	    double value = element[j]*solValue;
+	    double lower = rowLower[iRow];
+	    if (lower>-1.0e20)
+	      rowLower[iRow]=lower-value;
+	    double upper = rowUpper[iRow];
+	    if (upper<1.0e20)
+	    rowUpper[iRow]=upper-value;
+	  }	  
+	}
+	anyDeleted=true;
+	length=0;
+      }
+    }
+    columnStart[iColumn]=put;
+    for (CoinBigIndex i=start;i<start+length;i++) {
+      int iRow=row[i];
+      if (rowType[iRow]<=0) {
+	row[put]=iRow;
+	element[put++]=element[i];
+      }
+    }
+    columnLength[iColumn]=put-columnStart[iColumn];
+  }
+  int numberInitial=nActions;
+  columnStart[numberColumns_]=put;
+  matrix->setNumElements(put);
+  // get row copy if changed
+  if (anyDeleted) {
+    rowCopy = *matrix;
+    rowCopy.reverseOrdering();
+    column = rowCopy.getMutableIndices();
+    rowStart = rowCopy.getMutableVectorStarts();
+    elementByRow = rowCopy.getMutableElements();
+    rowLength = rowCopy.getMutableVectorLengths();
+  }
+  double * objective = newModel->objective();
+  double offset = objectiveOffset();
+  int numberRowsLook=0;
+#ifdef TWOFER
+  bool orderedMatrix=true;
+#endif
+  int nChanged = 1;
+  bool feasible=true;
+  //#define CLP_NO_SUBS
+  for (int iRow=0;iRow<numberRows_;iRow++) {
+#if DEBUG_SOME>0
+#ifndef NDEBUG
+    checkBasis(newModel, rowType, columnType);
+#endif
+#endif
+    int nPoss=2;
+#if DEBUG_SOME > 0
+    xxxxxx--;
+    if (xxxxxx<=0)
+      nPoss=1;
+    if (xxxxxx<-1000)
+      nPoss=-1;
+    if (xxxxxx==1) {
+      printf("bad\n");
+    }
+#endif
+    if (rowLength[iRow]<=nPoss&&!rowType[iRow]) {
+      if (rowLength[iRow]<=1) {
+	if (rowLength[iRow]==1)  {
+#ifndef CLP_NO_SUBS
+	  // See if already marked
+	  if ((rowStatus[iRow]&128)==0) {
+	    rowStatus[iRow] |= 128;
+	    whichRows[numberRowsLook++]=iRow;
+	    assert (numberRowsLook<=numberRows_);
+	  }
+#endif
+	} else {
+#if DEBUG_SOME > 0
+	  printf("Dropping null row %d (status %d) - nActions %d\n",
+		 iRow,getRowStatus(iRow),nActions);
+#endif
+	  if (rowLower[iRow] > primalTolerance_ ||
+	      rowUpper[iRow] <-primalTolerance_) {
+	    feasible=false;
+	    nChanged=-1;
+	    numberRowsLook=0;
+	    break;
+	  }
+	  rowType[iRow]=1;
+	  clpPresolveInfo1_4_8  thisInfo;
+	  thisInfo.oldRowLower=(rowLower_[iRow]>-1.0e30) ? rowLower_[iRow]-rowLower[iRow] : rowLower[iRow];
+	  thisInfo.oldRowUpper=(rowUpper_[iRow]<1.0e30) ? rowUpper_[iRow]-rowUpper[iRow] : rowUpper[iRow];
+	  thisInfo.row=iRow;
+	  int n=rowLength[iRow];
+	  CoinBigIndex start=rowStart[iRow];
+	  thisInfo.lengthRow=n;
+	  //thisInfo.column=-1;
+	  infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
+	  infoA[nActions].type=1;
+	  nActions++;
+	  ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo1_4_8),
+		     n,column+start,elementByRow+start);
+	}
+#ifdef TWOFER
+      } else if (rowLower[iRow]==rowUpper[iRow]) {
+#ifndef CLP_NO_SUBS
+	// See if already marked
+	if ((rowStatus[iRow]&128)==0) {
+	  rowStatus[iRow] |= 128;
+	  whichRows[numberRowsLook++]=iRow;
+	  assert (numberRowsLook<=numberRows_);
+	}
+#endif
+	CoinBigIndex start = rowStart[iRow];
+	int iColumn1 = column[start];
+	double value1 = elementByRow[start];
+	int iColumn2 = column[start+1];
+	double value2 = elementByRow[start+1];
+	bool swap=false;
+	double ratio = fabs(value1/value2);
+	if (ratio<0.001||ratio>1000.0) {
+	  if (fabs(value1)<fabs(value2)) {
+	    swap=true;
+	  } 
+	} else if (columnLength[iColumn1]<columnLength[iColumn2]) {
+	  swap=true;
+	}
+	if(swap) {
+	  iColumn1 = iColumn2;
+	  value1 = value2;
+	  iColumn2 = column[start];
+	  value2 = elementByRow[start];
+	}
+	// column bounds
+	double dropLower = columnLower[iColumn2];
+	double dropUpper = columnUpper[iColumn2];
+	double newLower;
+	double newUpper;
+	double rhs = rowLower[iRow]/value1;
+	double multiplier = value2/value1;
+	if (multiplier>0.0) {
+	  newLower = (dropUpper<1.0e30) ? rhs - multiplier*dropUpper : -COIN_DBL_MAX;
+	  newUpper = (dropLower>-1.0e30) ? rhs - multiplier*dropLower : COIN_DBL_MAX;
+	} else {
+	  newUpper = (dropUpper<1.0e30) ? rhs - multiplier*dropUpper : COIN_DBL_MAX;
+	  newLower = (dropLower>-1.0e30) ? rhs - multiplier*dropLower : -COIN_DBL_MAX;
+	}
+	//columnType[iColumn1]=3;
+	columnType[iColumn2]=14;
+	rowType[iRow]=14;
+	rhs = rowLower[iRow]/value2;
+	multiplier = value1/value2;
+	clpPresolveInfo14 thisInfo;
+	thisInfo.oldColumnLower=columnLower[iColumn1];
+	thisInfo.oldColumnUpper=columnUpper[iColumn1];
+	thisInfo.oldColumnLower2=columnLower[iColumn2];
+	thisInfo.oldColumnUpper2=columnUpper[iColumn2];
+	thisInfo.oldObjective2=objective[iColumn2];
+	thisInfo.value1=value1;
+	thisInfo.rhs=rowLower[iRow];
+	thisInfo.row=iRow;
+	thisInfo.column=iColumn1;
+	thisInfo.column2=iColumn2;
+	int nel=columnLength[iColumn2];
+	CoinBigIndex startCol=columnStart[iColumn2];
+	thisInfo.lengthColumn2=nel;
+	infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
+	infoA[nActions].type=14;
+	nActions++;
+	ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo14),
+			  nel,row+startCol,element+startCol);
+	newLower = CoinMax(newLower,columnLower[iColumn1]);
+	newUpper = CoinMin(newUpper,columnUpper[iColumn1]);
+	if (newLower>newUpper+primalTolerance_) {
+	  feasible=false;
+	  nChanged=-1;
+	  numberRowsLook=0;
+	  break;
+	}
+	columnLower[iColumn1]=newLower;
+	columnUpper[iColumn1]=newUpper;
+#if DEBUG_SOME > 0
+	printf("Dropping doubleton row %d (status %d) keeping column %d (status %d) dropping %d (status %d) (mult,rhs %g %g) - nActions %d\n",
+	       iRow,getRowStatus(iRow),iColumn1,getColumnStatus(iColumn1),iColumn2,getColumnStatus(iColumn2),multiplier,rhs,nActions);
+#endif
+	objective[iColumn1] -= objective[iColumn2]*multiplier;
+	offset -= rowLower[iRow]*(objective[iColumn2]*multiplier);
+	bool needDrop=false;
+	if (newModel->getRowStatus(iRow)!=basic) {
+	  if (newModel->getColumnStatus(iColumn2)!=basic) {
+	    // On way back may as well have column basic
+	    newModel->setColumnStatus(iColumn2,basic);
+	    // need to drop basic
+	    if (newModel->getColumnStatus(iColumn1)==basic) { 
+	      //setColumnStatus(iColumn1,superBasic);
+	      newModel->setColumnStatus(iColumn1,superBasic);
+	    } else {
+	      // not much we can do
+#if DEBUG_SOME > 0
+	      printf("dropping but no basic a\n");
+#endif
+	    }
+	  } else {
+	    // looks good
+	  }
+	} else {
+	  if (newModel->getColumnStatus(iColumn2)!=basic) {
+	    // looks good
+	  } else {
+	    // need to keep a basic
+	    if (newModel->getColumnStatus(iColumn1)!=basic) { 
+	      //setColumnStatus(iColumn2,superBasic);
+	      //setColumnStatus(iColumn1,basic);
+	      newModel->setColumnStatus(iColumn1,basic);
+	    } else {
+	      // not much we can do
+#if DEBUG_SOME > 0
+	      printf("dropping but all basic a\n");
+#endif
+	      needDrop=true;
+	      //setColumnStatus(iColumn2,superBasic);
+	    }
+	  }
+	}
+	int n=0;
+	start = columnStart[iColumn1];
+	for (int i=start;i<start+columnLength[iColumn1];
+	     i++) {
+	  int jRow=row[i];
+	  if (jRow!=iRow) {
+	    array[jRow]=element[i];
+	    whichRows2[n++]=jRow;
+	  }
+	}
+	rowLength[iRow]=0;
+	start = columnStart[iColumn2];
+	for (int i=start;i<start+columnLength[iColumn2];
+	     i++) {
+	  int jRow=row[i];
+	  if (jRow!=iRow) {
+	    double value = array[jRow];
+	    double valueNew = value -multiplier*element[i];
+	    double rhsMod = rhs*element[i];
+	    if (rowLower[jRow]>-1.0e30)
+	      rowLower[jRow] -= rhsMod;
+	    if (rowUpper[jRow]<1.0e30)
+	      rowUpper[jRow] -= rhsMod;
+	    if (!value) {
+	      array[jRow]=valueNew;
+	      whichRows2[n++]=jRow;
+	    } else {
+	      if (!valueNew)
+		valueNew=1.0e-100;
+	      array[jRow]=valueNew;
+	    }
+	  }
+	}
+	columnLength[iColumn2]=0;
+	start = columnStart[iColumn1];
+	if (n>columnLength[iColumn1]) {
+	  orderedMatrix=false;
+	  if (lastElement+n>lastGood) {
+	    // pack down
+	    CoinBigIndex put=lastElement;
+	    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+	      CoinBigIndex start = columnStart[iColumn];
+	      columnStart[iColumn]=put-lastElement;
+	      int length=columnLength[iColumn];
+	      for (CoinBigIndex j=start;j<start+length;j++) {
+		row[put]=row[j];
+		element[put++]=element[j];
+	      }
+	    }
+	    int numberElements = put-lastElement;
+	    columnStart[numberColumns_]=numberElements;
+	    memcpy(row,row+lastElement,numberElements*sizeof(int));
+	    memcpy(element,element+lastElement,numberElements*sizeof(double));
+	    lastElement=numberElements;
+	  }
+	  start=lastElement;
+	  columnStart[iColumn1]=start;
+	}
+	CoinBigIndex put = start;
+	for (int i=0;i<n;i++) {
+	  int jRow = whichRows2[i];
+	  double value = array[jRow];
+	  //#define FUNNY_CHECK
+#ifdef FUNNY_CHECK
+	  if (rowType[jRow]==-2)
+	    printf("iColumn1 %d iColumn2 %d row %d value %g\n",
+		   iColumn1,iColumn2,jRow,value);
+#endif
+	  array[jRow]=0.0;
+	  if (fabs(value)<1.0e-13) 
+	    value=0.0;
+	  if (value) {
+	    row[put] = jRow;
+	    element[put++]=value;
+	    if(needDrop&&newModel->getRowStatus(jRow)!=basic) {
+	      newModel->setRowStatus(jRow,basic);
+	      needDrop=false;
+	    }
+	  }
+	  // take out of row copy
+	  int startR = rowStart[jRow];
+	  int putR=startR;
+	  for (int i=startR;i<startR+rowLength[jRow];i++) {
+	    int iColumn = column[i];
+	    if (iColumn!=iColumn1&&iColumn!=iColumn2) {
+	      column[putR]=iColumn;
+	      elementByRow[putR++]=elementByRow[i];
+	    } else if (value) {
+	      column[putR]=iColumn1;
+	      elementByRow[putR++]=value;
+	      value=0.0;
+	    }
+	  }
+	  int rowLength2=putR-startR;
+#ifndef CLP_NO_SUBS
+	  if (rowLength2<=1&&rowLength[jRow]>1&&jRow<iRow) {
+	    // may be interesting
+	    // See if already marked
+	    if ((rowStatus[jRow]&128)==0) {
+	      rowStatus[jRow] |= 128;
+	      whichRows[numberRowsLook++]=jRow;
+	      assert (numberRowsLook<=numberRows_);
+	    }
+	  }
+#endif
+	  rowLength[jRow]=rowLength2;
+	}
+	columnLength[iColumn1]=put-start;
+	lastElement=CoinMax(lastElement,put);
+#endif
+      }
+    } else if (true&&rowLower[iRow]==-COIN_DBL_MAX&&rowUpper[iRow]==COIN_DBL_MAX) {
+#if DEBUG_SOME > 0
+      printf("Dropping null free row %d (status %d) - nActions %d\n",
+	     iRow,getRowStatus(iRow),nActions);
+#endif
+      rowType[iRow]=1;
+      clpPresolveInfo1_4_8  thisInfo;
+      thisInfo.oldRowLower=(rowLower_[iRow]>-1.0e30) ? rowLower_[iRow]-rowLower[iRow] : rowLower[iRow];
+      thisInfo.oldRowUpper=(rowUpper_[iRow]<1.0e30) ? rowUpper_[iRow]-rowUpper[iRow] : rowUpper[iRow];
+      thisInfo.row=iRow;
+      int n=rowLength[iRow];
+      CoinBigIndex start=rowStart[iRow];
+      thisInfo.lengthRow=n;
+      //thisInfo.column=-1;
+      infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
+      infoA[nActions].type=1;
+      nActions++;
+      ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo1_4_8),
+			n,column+start,elementByRow+start);
+      // need to take out row
+      CoinBigIndex end=start+n;
+      rowLength[iRow]=0;
+      for (CoinBigIndex k=start;k<end;k++) {
+	int iColumn=column[k];
+	CoinBigIndex startColumn=columnStart[iColumn];
+	int n=columnLength[iColumn];
+	CoinBigIndex endColumn=startColumn+n;
+	columnLength[iColumn]=n-1;
+	for (CoinBigIndex j=startColumn;j<endColumn;j++) {
+	  int jRow=row[j];
+	  if (jRow==iRow) {
+	    endColumn--;
+	    row[j]=row[endColumn];
+	    element[j]=element[endColumn];
+	    break;
+	  }
+	}
+	assert (endColumn==startColumn+n-1);
+      }
+    }
+  }
+#if DEBUG_SOME>0
+  if (xxxxxx<-1000)
+    nChanged=-1;
+#endif
+  while (nChanged>0) {
+    nChanged=0;
+    int numberColumnsLook=0;
+    for (int i=0;i<numberRowsLook;i++) {
+#if DEBUG_SOME>0
+#ifndef NDEBUG
+      checkBasis(newModel, rowType, columnType);
+#endif
+#endif
+      int iRow = whichRows[i];
+      // unmark
+      assert ((rowStatus[iRow]&128)!=0);
+      rowStatus[iRow] &= 127;
+      if (rowLength[iRow]==1) {
+	//rowType[iRow]=55;
+	int iColumn =  column[rowStart[iRow]];
+	if (/*columnType[iColumn]==14||*/columnType[iColumn]<-1) 
+	  continue;
+	if (!columnType[iColumn]) {
+	  columnType[iColumn]=55;
+	  whichColumns[numberColumnsLook++]=iColumn;
+	  nChanged++;
+	}
+#if 0
+      } else if (rowLength[iRow]==2) {
+	if (rowLower[iRow]==rowUpper[iRow]) {
+	  CoinBigIndex start = rowStart[iRow];
+	  int iColumn1 =  column[start];
+	  int iColumn2 =  column[start+1];
+	  if (!columnType[iColumn1]&&!columnType[iColumn2]) {
+	    if (fabs(elementByRow[start])<fabs(elementByRow[start+1])) {
+	      iColumn1 = iColumn2;
+	      iColumn2 = column[start];
+	    }
+	    // iColumn2 will be deleted
+	    columnType[iColumn1]=56;
+	    columnType[iColumn2]=56;
+	  }
+	} else {
+	  printf("why here in miniPresolve row %d\n",iRow);
+	}
+#endif
+      }
+    }
+    // mark one row as ub and take out row in column copy
+    numberRowsLook=0;
+    for (int iLook=0;iLook<numberColumnsLook;iLook++) {
+#if DEBUG_SOME>0
+#ifndef NDEBUG
+      checkBasis(newModel, rowType, columnType);
+#endif
+#endif
+      nChanged++;
+      int iColumn = whichColumns[iLook];
+      if (columnType[iColumn]!=55&&columnType[iColumn]>10)
+	continue;
+      if (columnType[iColumn]==55)
+	columnType[iColumn]=0;
+      CoinBigIndex start=columnStart[iColumn];
+      int jRowLower=-1;
+      double newLower=columnLower[iColumn];
+      int jRowUpper=-1;
+      double newUpper=columnUpper[iColumn];
+      double coefficientLower=0.0;
+      double coefficientUpper=0.0;
+      for (CoinBigIndex i=start;i<start+columnLength[iColumn];
+	   i++) {
+	int iRow=row[i];
+	if (rowLength[iRow]==1&&rowType[iRow]==0) {
+	  rowType[iRow]=1;
+	  assert(columnType[iColumn]>=0);
+	  // adjust bounds
+	  double value = elementByRow[rowStart[iRow]];
+	  double lower = newLower;
+	  double upper = newUpper;
+	  if (value>0.0) {
+	    if (rowUpper[iRow]<1.0e30)
+	      upper = rowUpper[iRow]/value;
+	    if (rowLower[iRow]>-1.0e30)
+	      lower = rowLower[iRow]/value;
+	  } else {
+	    if (rowUpper[iRow]<1.0e30)
+	      lower = rowUpper[iRow]/value;
+	    if (rowLower[iRow]>-1.0e30)
+	      upper = rowLower[iRow]/value;
+	  }
+	  if (lower>newLower+primalTolerance_) {
+	    if (lower>newUpper+primalTolerance_) {
+	      feasible=false;
+	      nChanged=-1;
+	      numberColumnsLook=0;
+	      break;
+	    } else if (lower>newUpper-primalTolerance_) {
+	      newLower=newUpper;
+	    } else {
+	      newLower = CoinMax(lower,newLower);
+	    }
+	    jRowLower=iRow;
+	    coefficientLower=value;
+	  } 
+	  if (upper<newUpper-primalTolerance_) {
+	    if (upper<newLower-primalTolerance_) {
+	      feasible=false;
+	      nChanged=-1;
+	      numberColumnsLook=0;
+	      break;
+	    } else if (upper<newLower+primalTolerance_) {
+	      newUpper = newLower;
+	    } else {
+	      newUpper = CoinMin(upper,newUpper);
+	    }
+	    jRowUpper=iRow;
+	    coefficientUpper=value;
+	  }
+	}
+      }
+      int put=start;
+      int iFlag=0;
+      int nonFree=0;
+      int numberNonBasicSlacksOut=0;
+      if (jRowLower>=0||jRowUpper>=0) {
+	clpPresolveInfo2 thisInfo;
+	if (jRowLower>=0) {
+	  thisInfo.oldRowLower=(rowLower_[jRowLower]>-1.0e30) ? rowLower_[jRowLower]-rowLower[jRowLower] : rowLower[jRowLower];
+	  thisInfo.oldRowUpper=(rowUpper_[jRowLower]<1.0e30) ? rowUpper_[jRowLower]-rowUpper[jRowLower] : rowUpper[jRowLower];
+	  thisInfo.row=jRowLower;
+	  thisInfo.coefficient=coefficientLower;
+	} else {
+	  thisInfo.row=-1;
+#ifndef NDEBUG
+	  thisInfo.oldRowLower=COIN_DBL_MAX;
+	  thisInfo.oldRowUpper=-COIN_DBL_MAX;
+	  thisInfo.coefficient=0.0;
+#endif
+	}
+	if (jRowUpper>=0&&jRowLower!=jRowUpper) {
+	  thisInfo.oldRowLower2=(rowLower_[jRowUpper]>-1.0e30) ? rowLower_[jRowUpper]-rowLower[jRowUpper] : rowLower[jRowUpper];
+	  thisInfo.oldRowUpper2=(rowUpper_[jRowUpper]<1.0e30) ? rowUpper_[jRowUpper]-rowUpper[jRowUpper] : rowUpper[jRowUpper];
+	  thisInfo.row2=jRowUpper;
+	  thisInfo.coefficient2=coefficientUpper;
+	} else {
+	  thisInfo.row2=-1;
+#ifndef NDEBUG
+	  thisInfo.oldRowLower2=COIN_DBL_MAX;
+	  thisInfo.oldRowUpper2=-COIN_DBL_MAX;
+	  thisInfo.coefficient2=0.0;
+#endif
+	}
+	thisInfo.oldColumnLower=columnLower[iColumn];
+	thisInfo.oldColumnUpper=columnUpper[iColumn];
+	columnLower[iColumn]=newLower;
+	columnUpper[iColumn]=newUpper;
+	thisInfo.column=iColumn;
+	infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
+	ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo2),
+		   0,NULL,NULL);
+	infoA[nActions].type=2;
+	nActions++;
+      }
+      for (CoinBigIndex i=start;i<start+columnLength[iColumn];
+	   i++) {
+	int iRow=row[i];
+	if (rowLength[iRow]==1&&rowType[iRow]>=0&&rowType[iRow]!=5) {
+#if DEBUG_SOME > 0
+	  printf("Dropping singleton row %d (status %d) because of column %d (status %d) - jRow lower/upper %d/%d - nActions %d\n",
+		 iRow,getRowStatus(iRow),iColumn,
+		 getColumnStatus(iColumn),jRowLower,jRowUpper,nActions);
+#endif
+	  if (newModel->getRowStatus(iRow)!=basic) {
+	    //newModel->setRowStatus(iRow,basic);
+	    numberNonBasicSlacksOut++;
+	  }
+	  rowType[iRow]=1;
+	  if (iRow!=jRowLower&&iRow!=jRowUpper) {
+	    // mark as redundant
+	    infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
+	    clpPresolveInfo1_4_8 thisInfo;
+	    thisInfo.oldRowLower=(rowLower_[iRow]>-1.0e30) ? rowLower_[iRow]-rowLower[iRow] : rowLower[iRow];
+	    thisInfo.oldRowUpper=(rowUpper_[iRow]<1.0e30) ? rowUpper_[iRow]-rowUpper[iRow] : rowUpper[iRow];
+	    thisInfo.row=iRow;
+	    int n=rowLength[iRow];
+	    CoinBigIndex start=rowStart[iRow];
+	    thisInfo.lengthRow=n;
+	    ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo1_4_8),
+		       n,column+start,elementByRow+start);
+	    infoA[nActions].type=1;
+	    nActions++;
+	  }
+	  rowLength[iRow]=0;
+	} else if (rowType[iRow]<=0) {
+	  row[put]=iRow;
+	  double value = element[i];
+	  element[put++]=value;
+	  if (rowType[iRow]>=0&&iFlag<3) {
+	    assert(rowType[iRow]==0);
+	    double lower = rowLower[iRow];
+	    double upper = rowUpper[iRow];
+	    if (-1.0e20 < lower && upper < 1.0e20) {
+	      // bounded - we lose
+	      iFlag=-1;
+	      //break;
+	    } else if (-1.0e20 < lower || upper < 1.0e20) {
+	      nonFree++;
+	    }
+	    // see what this particular row says
+	    // jFlag == 2 ==> up is towards feasibility
+	    int jFlag = (value > 0.0
+			 ? (upper >  1.0e20 ? 2 : 1)
+			 : (lower < -1.0e20 ? 2 : 1));
+	    
+	    if (iFlag) {
+	      // check that it agrees with iFlag.
+	      if (iFlag!=jFlag) {
+		iFlag=-1;
+	      }
+	    } else {
+	      // first row -- initialize iFlag
+	      iFlag=jFlag;
+	    }
+	  } else if (rowType[iRow]<0) {
+	    iFlag=-1; // be safe
+	  }
+	}
+      }
+      // Do we need to switch status of iColumn?
+      if (numberNonBasicSlacksOut>0) {
+	// make iColumn non basic if possible
+	if (newModel->getColumnStatus(iColumn)==basic) {
+	  newModel->setColumnStatus(iColumn,superBasic);
+	}
+      }
+      double cost = objective[iColumn]*optimizationDirection_;
+      int length = put-columnStart[iColumn];
+      if (!length) {
+	if (!cost) {
+	  // put to closest to zero
+	  if (fabs(columnLower[iColumn])<fabs(columnUpper[iColumn]))
+	    iFlag=1;
+	  else
+	    iFlag=2;
+	} else if (cost>0.0) {
+	  iFlag=1;
+	} else {
+	  iFlag=2;
+	}
+      } else {
+	if (cost>0.0&&iFlag==2)
+	  iFlag=-1;
+	else if (cost<0.0&&iFlag==1)
+	  iFlag=-1;
+      }
+      columnLength[iColumn]=length;
+      //#define NO_MOVABLE
+#ifdef NO_MOVABLE
+      iFlag=-1;
+#endif
+      if (iFlag>0&&nonFree) {
+	double newValue;
+	if (iFlag==2) {
+	  // fix to upper
+	  newValue =CoinMin(columnUpper[iColumn],1.0e20);
+	} else {
+	  // fix to lower 
+	  newValue =CoinMax(columnLower[iColumn],-1.0e20);
+	}
+	columnActivity_[iColumn]=newValue;
+#if DEBUG_SOME > 0
+	if (newModel->getColumnStatus(iColumn)==
+	    basic) {
+	  // ? move basic back onto sub if can?
+	  iFlag += 2;
+	}
+	printf("Dropping movable column %d - iFlag %d - jRow lower/upper %d/%d - nActions %d\n",
+	       iColumn,iFlag,jRowLower,jRowUpper,nActions);
+#endif
+	columnType[iColumn]=11;
+	if (newModel->getColumnStatus(iColumn)==
+	    basic) {
+	  // need to put status somewhere else
+	  int shortestNumber=numberColumns_;
+	  int shortest=-1;
+	  for (int j=start;j<start+length;j++) {
+	    int iRow=row[j];
+	    if (rowLength[iRow]<shortestNumber&&
+		newModel->getRowStatus(iRow)!=
+		basic) {
+	      shortest=iRow;
+	      shortestNumber = rowLength[iRow];
+	    }
+	  }
+	  if (shortest>=0) {
+	    // make basic
+	    newModel->setRowStatus(shortest,basic);
+	    newModel->setColumnStatus(iColumn,superBasic);
+	  } else {
+	    // put on a column
+	    shortestNumber=numberColumns_;
+	    shortest=-1;
+	    for (int j=start;j<start+length;j++) {
+	      int iRow=row[j];
+	      if (rowLength[iRow]<shortestNumber) {
+		int start = rowStart[iRow];
+		for (int i=start;i<start+rowLength[iRow];i++) {
+		  int jColumn = column[i];
+		  if (iColumn!=jColumn&&
+		      newModel->getColumnStatus(jColumn)!=
+		      basic) {
+		    shortest=jColumn;
+		    shortestNumber = rowLength[iRow];
+		  }
+		}
+	      }
+	    }
+	    if (shortest>=0) {
+	      // make basic
+	      newModel->setColumnStatus(shortest,basic);
+	    } else {
+#if DEBUG_SOME > 0
+	      printf("what now - dropping - basic\n");
+#endif
+	    }
+	  }
+	}
+	clpPresolveInfo11 thisInfo;
+	thisInfo.oldColumnLower=columnLower[iColumn];
+	thisInfo.oldColumnUpper=columnUpper[iColumn];
+	thisInfo.fixedTo=newValue;
+	columnLower[iColumn]=newValue;
+	columnUpper[iColumn]=newValue;
+	thisInfo.column=iColumn;
+	int n=columnLength[iColumn];
+	CoinBigIndex start=columnStart[iColumn];
+	thisInfo.lengthColumn=n;
+	infoA[nActions].infoOffset=static_cast<int>(stuff.putStuff-startStuff);
+	infoA[nActions].type=11;
+	nActions++;
+	ClpCopyToMiniSave(stuff,reinterpret_cast<char *>(&thisInfo),sizeof(clpPresolveInfo11),
+			  n,row+start,element+start);
+	// adjust rhs and take out of rows
+	columnLength[iColumn]=0;
+	nChanged++;
+	for (int j=start;j<start+length;j++) {
+	  int iRow=row[j];
+	  double value = element[j]*newValue;
+	  double lower = rowLower[iRow];
+	  if (lower>-1.0e20)
+	    rowLower[iRow]=lower-value;
+	  double upper = rowUpper[iRow];
+	  if (upper<1.0e20)
+	    rowUpper[iRow]=upper-value;
+	  // take out of row copy (and put on list)
+	  assert (rowType[iRow]<=0&&rowType[iRow]>-2);
+	  // See if already marked (will get to row later in loop
+	  if ((rowStatus[iRow]&128)==0) {
+	    rowStatus[iRow] |= 128;
+	    whichRows[numberRowsLook++]=iRow;
+	    assert (numberRowsLook<=numberRows_);
+	  }
+	  int start = rowStart[iRow];
+	  int put=start;
+	  for (int i=start;i<start+rowLength[iRow];i++) {
+	    int jColumn = column[i];
+	    if (iColumn!=jColumn) {
+	      column[put]=jColumn;
+	      elementByRow[put++]=elementByRow[i];
+	    }
+	  }
+	  rowLength[iRow]=put-start;
+	}
+      }
+    }
+  }
+  if (feasible) {
+    clpPresolveMore moreInfo;
+    moreInfo.model=newModel;
+    moreInfo.rowCopy=&rowCopy;
+    moreInfo.rowType=rowType;
+    moreInfo.columnType=columnType;
+    moreInfo.stuff=&stuff;
+    moreInfo.info=infoA;
+    moreInfo.nActions=&nActions;
+    eventHandler_->eventWithInfo(ClpEventHandler::moreMiniPresolve,&moreInfo);
+    newModel->setObjectiveOffset(offset);
+    int nChar2 = nActions*static_cast<int>(sizeof(clpPresolveInfo))+static_cast<int>(stuff.putStuff-startStuff);
+    clpPresolveInfo * infoData = reinterpret_cast<clpPresolveInfo *>(new char[nChar2]);
+    memcpy(infoData,infoA,nActions*sizeof(clpPresolveInfo));
+    char * info2 = reinterpret_cast<char *>(infoData+nActions);
+    memcpy(info2,startStuff,stuff.putStuff-startStuff);
+    listInfo * infoNew = new listInfo; 
+    infoNew->numberEntries=nActions;
+    infoNew->maximumEntries=nActions;
+    infoNew->start=infoData;
+    infoNew->numberInitial=numberInitial;
+    *infoOut=infoNew;
+    int nRows=0;
+    for (int iRow=0;iRow<numberRows_;iRow++) {
+      if (rowType[iRow]>0) 
+	whichRows[nRows++]=iRow;
+    }
+    int nColumns=0;
+    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+      if (columnType[iColumn]>10) 
+	whichColumns[nColumns++]=iColumn;
+    }
+#ifdef FUNNY_CHECK
+    {
+      CoinPackedMatrix rowCopy2 = *this->matrix();
+      rowCopy2.reverseOrdering();
+      int * column2 = rowCopy2.getMutableIndices();
+      CoinBigIndex * rowStart2 = rowCopy2.getMutableVectorStarts();
+      double * elementByRow2 = rowCopy2.getMutableElements();
+      int * rowLength2 = rowCopy2.getMutableVectorLengths();
+      printf("Odd rows\n");
+      for (int iRow=0;iRow<numberRows_;iRow++) {
+	if (rowType[iRow]==-2) {
+	  CoinBigIndex start = rowStart[iRow];
+	  int length=rowLength[iRow];
+	  printf("Odd row %d -> ",iRow);
+	  for (CoinBigIndex j=start;j<start+length;j++) {
+	    int iColumn=column[j];
+	    printf("(%d %g) ",iColumn,elementByRow[j]);
+	  }
+	  printf("Original ");
+	  start = rowStart2[iRow];
+	  length=rowLength2[iRow];
+	  for (CoinBigIndex j=start;j<start+length;j++) {
+	    int iColumn=column2[j];
+	    printf("(%d %g) ",iColumn,elementByRow2[j]);
+	  }
+	  printf(">= %g/%g\n",rowLower[iRow],rowLower_[iRow]);
+	}
+      }
+      printf("now columns\n");
+      for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+	CoinBigIndex start = columnStart[iColumn];
+	int length=columnLength[iColumn];
+	for (CoinBigIndex j=start;j<start+length;j++) {
+	  int iRow=row[j];
+	  if (rowType[iRow]==-2)
+	    printf("Column %d row %d value %g\n",
+		   iColumn,iRow,element[j]);
+	}
+      }
+    }
+#endif
+#ifdef TWOFER
+    if (!orderedMatrix) {
+      //lastElement;
+      // move up
+      CoinBigIndex put=lastElement;
+      for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+	CoinBigIndex start = columnStart[iColumn];
+	columnStart[iColumn]=put-lastElement;
+	int length=columnLength[iColumn];
+	for (CoinBigIndex j=start;j<start+length;j++) {
+	  row[put]=row[j];
+	  element[put++]=element[j];
+	}
+      }
+      int numberElements = put-lastElement;
+      columnStart[numberColumns_]=numberElements;
+      memcpy(row,row+lastElement,numberElements*sizeof(int));
+      memcpy(element,element+lastElement,numberElements*sizeof(double));
+    }
+#endif
+    // could just shrink - would be faster
+#if DEBUG_SOME > 0
+    printf("%d Row types and lookup\n",nRows);
+    int nBNew=0;
+    int iNew=0;
+    for (int iRow=0;iRow<numberRows_;iRow++) {
+      int type=rowType[iRow];
+      char xNew='O';
+      if (type<=0) {
+	xNew='N';
+	if (newModel->getRowStatus(iRow)==basic) {
+	  nBNew++;
+	  xNew='B';
+	} 
+	printf("%d -> %d type %d - new status %c\n",iRow,iNew,rowType[iRow],xNew);
+	iNew++;
+      }
+    }
+    printf("%d Column types and lookup\n",nColumns);
+    iNew=0;
+    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+      int type=columnType[iColumn];
+      char xNew='O';
+      if (type<=10) {
+	xNew='N';
+	if (newModel->getColumnStatus(iColumn)==basic) {
+	  nBNew++;
+	  xNew='B';
+	} 
+	printf("%d -> %d type %d - new status %c\n",iColumn,iNew,columnType[iColumn],xNew);
+	iNew++;
+      }
+    }
+    printf("Deleting %d rows (now %d) and %d columns (%d basic)\n",nRows,numberRows_-nRows,
+	   nColumns,nBNew);
+#else
+#if DEBUG_SOME >0
+    printf("Deleting %d rows (now %d) and %d columns\n",nRows,numberRows_-nRows,
+	   nColumns);
+#endif
+#endif
+#if 0
+    newModel->deleteRows(nRows,whichRows);
+    newModel->deleteColumns(nColumns,whichColumns);
+#else
+    newModel->deleteRowsAndColumns(nRows,whichRows,nColumns,whichColumns);
+#endif
+  } else {
+    delete newModel;
+    newModel=NULL;
+    *infoOut=NULL;
+  }
+  delete [] whichRows;
+  delete [] infoA;
+  delete [] startStuff;
+  delete [] array;
+  return newModel;
+}
+// After mini presolve
+void 
+ClpSimplex::miniPostsolve(const ClpSimplex * presolvedModel, void * infoIn)
+{
+  int numberTotal=numberRows_+numberColumns_;
+  listInfo * infoX = reinterpret_cast<listInfo *>(infoIn);
+  int nActions=infoX->numberEntries;
+#if DEBUG_SOME > 0
+#ifndef NDEBUG
+  int numberInitial=infoX->numberInitial;
+#endif
+#endif
+  clpPresolveInfo * infoA = infoX->start;
+  char * startStuff = reinterpret_cast<char *>(infoA+nActions);
+  // move status and solution across
+  int numberColumns2=presolvedModel->numberColumns();
+  const double * solution2 = presolvedModel->primalColumnSolution();
+  unsigned char * rowStatus2 = presolvedModel->statusArray()+numberColumns2;
+  unsigned char * columnStatus2 = presolvedModel->statusArray();
+  unsigned char * rowStatus = status_+numberColumns_;
+  unsigned char * columnStatus = status_;
+  char * rowType = new char [numberTotal];
+  memset(rowType,0,numberTotal);
+  char * columnType = rowType+numberRows_;
+  double * rowLowerX = new double [3*numberRows_+3*numberColumns_+CoinMax(numberRows_,numberColumns_)];
+  double * rowUpperX = rowLowerX+numberRows_;
+  double * columnLowerX = rowUpperX+numberRows_;
+  double * columnUpperX = columnLowerX+numberColumns_;
+  double * objectiveX = columnUpperX+numberColumns_;
+  double * tempElement = objectiveX+numberColumns_;
+  double * array = tempElement+CoinMax(numberRows_,numberColumns_);
+  memset(array,0,numberRows_*sizeof(double));
+  int * tempIndex = new int [CoinMax(numberRows_,numberColumns_)+4+2*numberColumns_+numberRows_];
+  int * forward = tempIndex+CoinMax(numberRows_,numberColumns_)+1;
+  int * backward = forward + numberColumns_+2;
+  int * whichRows2 = backward + numberColumns_+1;
+  for (int i=-1;i<numberColumns_;i++)
+    forward[i]=i+1;
+  forward[numberColumns_]=-1;
+  for (int i=0;i<=numberColumns_;i++)
+    backward[i]=i-1;
+  backward[-1]=-1;
+  restoreInfo restore;
+  restore.elements=tempElement;
+  restore.indices=tempIndex;
+  restore.startStuff=startStuff;
+#ifndef NDEBUG
+  for (int i=0;i<numberRows_;i++) {
+    rowLowerX[i]=COIN_DBL_MAX;
+    rowUpperX[i]=-COIN_DBL_MAX;
+  }
+  for (int i=0;i<numberColumns_;i++) {
+    columnLowerX[i]=COIN_DBL_MAX;
+    columnUpperX[i]=-COIN_DBL_MAX;
+  }
+#endif
+  memset(rowActivity_,0,numberRows_*sizeof(double));
+  memset(dual_,0,numberRows_*sizeof(double));
+  // Get presolved contribution
+  const int * row = matrix()->getIndices();
+  const CoinBigIndex * columnStart = matrix()->getVectorStarts();
+  const int * columnLength = matrix()->getVectorLengths();
+  const double * element = matrix()->getElements();
+  // forwards so dropped column at end
+  for (int i=0;i<nActions;i++) {
+    int type=infoA[i].type;
+    char * getStuff = startStuff+infoA[i].infoOffset;
+    int iRow=-1;
+    int iColumn=-1;
+    switch (type) {
+    case 1:
+    case 4:
+    case 8:
+    case 9:
+      // redundant
+      {
+	clpPresolveInfo1_4_8  thisInfo;
+	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo1_4_8));
+	iRow = thisInfo.row;
+	rowType[iRow]=static_cast<char>(type);
+      }
+      break;
+    case 2: 
+      // sub
+      {
+	clpPresolveInfo2 thisInfo;
+	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo2));
+	iRow = thisInfo.row;
+	if (iRow>=0)
+	  rowType[iRow]=2;
+	iRow = thisInfo.row2;
+	if (iRow>=0)
+	  rowType[iRow]=2;
+	iColumn = thisInfo.column;
+	columnType[iColumn]=2;
+      }
+      break;
+    case 11: 
+      // movable column
+      {
+	clpPresolveInfo11 thisInfo;
+	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo11));
+	iColumn = thisInfo.column;
+	columnType[iColumn]=11;
+      }
+      break;
+    case 13: 
+      // empty column
+      {
+	clpPresolveInfo13 thisInfo;
+	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo13));
+	iColumn = thisInfo.column;
+	columnType[iColumn]=13;
+      }
+      break;
+    case 14: 
+      // doubleton
+      {
+	clpPresolveInfo14 thisInfo;
+	memcpy(&thisInfo,getStuff,sizeof(clpPresolveInfo14));
+	iRow = thisInfo.row;
+	iColumn = thisInfo.column;
+	int iColumn2 = thisInfo.column2;
+	columnType[iColumn]=3;
+	columnType[iColumn2]=14;
+	rowType[iRow]=3;
+      }
+      break;
+    }
+#if DEBUG_SOME > 0
+    printf("Action %d type %d row %d column %d\n",
+	   i,type,iRow,iColumn);
+#endif
+  }
+  int iGet=0;
+  const double * rowLowerY = presolvedModel->rowLower();
+  const double * rowUpperY = presolvedModel->rowUpper();
+  for (int iRow=0;iRow<numberRows_;iRow++) {
+    if (!rowType[iRow]) {
+      rowStatus[iRow]=rowStatus2[iGet];
+      rowActivity_[iRow]=presolvedModel->rowActivity_[iGet];
+      dual_[iRow]=presolvedModel->dual_[iGet];
+      rowLowerX[iRow]=rowLowerY[iGet];
+      rowUpperX[iRow]=rowUpperY[iGet];
+      tempIndex[iGet]=iRow;
+      iGet++;
+    } else {
+      setRowStatus(iRow,basic);
+    } 
+  }
+  assert (iGet==presolvedModel->numberRows());
+  CoinPackedMatrix matrixX;
+  int numberElementsOriginal=matrix_->getNumElements();
+  const int * rowY = presolvedModel->matrix()->getIndices();
+  const CoinBigIndex * columnStartY = presolvedModel->matrix()->getVectorStarts();
+  const int * columnLengthY = presolvedModel->matrix()->getVectorLengths();
+  const double * elementY = presolvedModel->matrix()->getElements();
+  iGet=0;
+  CoinBigIndex put=0;
+  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+    if (columnType[iColumn]<11) {
+      put += CoinMax(columnLength[iColumn],columnLengthY[iGet]);
+      iGet++;
+    } else {
+      put += columnLength[iColumn];
+    }
+  }
+  int lastElement=2*(put+numberColumns_)+1000;
+  int spare = (lastElement-put)/numberColumns_;
+  //printf("spare %d\n",spare);
+  matrixX.reserve(numberColumns_,lastElement+2*numberElementsOriginal);
+  int * rowX = matrixX.getMutableIndices();
+  CoinBigIndex * columnStartX = matrixX.getMutableVectorStarts();
+  int * columnLengthX = matrixX.getMutableVectorLengths();
+  double * elementX = matrixX.getMutableElements();
+  const double * columnLowerY = presolvedModel->columnLower();
+  const double * columnUpperY = presolvedModel->columnUpper();
+  iGet=0;
+  put=0;
+  memcpy(objectiveX,this->objective(),numberColumns_*sizeof(double));
+  const double * objectiveY=presolvedModel->objective();
+  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+    columnStartX[iColumn]=put;
+    if (columnType[iColumn]<11) {
+      CoinBigIndex next=put+columnLengthY[iGet];
+      if (spare>=0) 
+	next += CoinMax(columnLength[iColumn]-columnLengthY[iGet],0)+spare;
+      columnStatus[iColumn]=columnStatus2[iGet];
+      columnActivity_[iColumn]=solution2[iGet];
+      columnLowerX[iColumn]=columnLowerY[iGet];
+      columnUpperX[iColumn]=columnUpperY[iGet];
+      columnLengthX[iColumn]=columnLengthY[iGet];
+      objectiveX[iColumn]=objectiveY[iGet];
+      for (CoinBigIndex j=columnStartY[iGet];j<columnStartY[iGet]+columnLengthY[iGet];j++) {
+	rowX[put]=tempIndex[rowY[j]];
+	elementX[put++]=elementY[j];
+      }
+      columnActivity_[iColumn]=presolvedModel->columnActivity_[iGet];
+      iGet++;
+      columnType[iColumn]=0;
+      put = next;
+    } else {
+      put += CoinMax(columnLength[iColumn]+spare,0);
+      columnActivity_[iColumn]=0.0;
+      columnType[iColumn]=1;
+      columnLengthX[iColumn]=0;
+      setColumnStatus(iColumn,superBasic);
+    }
+  }
+  assert (put<=lastElement);
+  columnStartX[numberColumns_]=lastElement+numberElementsOriginal;
+  assert (put<=lastElement);
+  assert (iGet==numberColumns2);
+  matrixX.times(columnActivity_,rowActivity_);
+  if (optimizationDirection_<0) {
+    for (int i=0;i<numberColumns_;i++)
+      objectiveX[i]=-objectiveX[i];
+  }
+#if 0
+  // get row copy
+  CoinPackedMatrix rowCopy = *matrix();
+  rowCopy.reverseOrdering();
+  const int * column = rowCopy.getIndices();
+  const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+  const int * rowLength = rowCopy.getVectorLengths();
+  const double * elementByRow = rowCopy.getElements();
+#endif
+#if 1 //DEBUG_SOME > 0
+  double * tempRhs=new double[numberRows_];
+#endif
+#ifndef NDEBUG
+  bool checkMatrixAtEnd=true;
+#endif
+  for (int i=nActions-1;i>=0;i--) {
+#if DEBUG_SOME > 0
+#if 1 //ndef NDEBUG
+    memset(tempRhs,0,numberRows_*sizeof(double));
+    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+      //if (columnActivity_[iColumn]<columnLower_[iColumn]-1.0e-5||
+      //      columnActivity_[iColumn]>columnUpper_[iColumn]+1.0e-5)
+      //printf ("Bad column %d %g <= %g <= %g\n",iColumn,
+      //	columnLower_[iColumn],columnActivity_[iColumn],columnUpper_[iColumn]);
+      double value=columnActivity_[iColumn];
+      for (CoinBigIndex j=columnStartX[iColumn];
+	   j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
+	int jRow=rowX[j];
+	tempRhs[jRow] += value*elementX[j];
+      }
+    }
+    int nBadRow=0;
+    for (int iRow=0;iRow<numberRows_;iRow++) {
+      if (rowLowerX[iRow]==COIN_DBL_MAX)
+	continue;
+      if (fabs(tempRhs[iRow]-rowActivity_[iRow])>1.0e-4)
+	printf("Row %d temprhs %g rowActivity_ %g\n",iRow,tempRhs[iRow],
+	       rowActivity_[iRow]);
+      if (tempRhs[iRow]<rowLowerX[iRow]-1.0e-4||
+	  tempRhs[iRow]>rowUpperX[iRow]+1.0e-4) {
+	printf("Row %d %g %g %g\n",iRow,rowLowerX[iRow],
+	       tempRhs[iRow],rowUpperX[iRow]);
+	nBadRow++;
+      }
+    }
+    assert (!nBadRow);
+#endif
+#ifndef NDEBUG
+    if (i>=numberInitial&&true) {
+      for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+	if (columnLengthX[iColumn]) {
+	  double djValue = objectiveX[iColumn];
+	  for (CoinBigIndex j=columnStartX[iColumn];
+	       j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
+	    int jRow=rowX[j];
+	    djValue -= dual_[jRow]*elementX[j];
+	  }
+	  char inOut=columnType[iColumn] ? 'O' : 'I';
+	  if (djValue>10.0*dualTolerance_&&
+	      columnActivity_[iColumn]>columnLowerX[iColumn]+primalTolerance_)
+	    printf("bad dj on column %d lb dj %g in/out %c\n",iColumn,djValue,inOut);
+	  else if (djValue<-10.0*dualTolerance_&&
+		   columnActivity_[iColumn]<columnUpperX[iColumn]-primalTolerance_)
+	    printf("bad dj on column %d ub dj %g in/out %c\n",iColumn,djValue,inOut);
+	}
+      }
+    }
+#endif
+#endif
+    int type=infoA[i].type;
+    int iRow=-1;
+    int iColumn=-1;
+#if DEBUG_SOME>0
+    printf("Action %d type %d\n",i,type);
+#ifndef NDEBUG
+      checkBasis(this, rowType, columnType);
+#endif
+#endif
+    switch (type) {
+    case 1:
+    case 4:
+    case 8:
+    case 9:
+      // redundant
+      {
+#ifndef NDEBUG
+	if (type==4)
+	  checkMatrixAtEnd=false;
+#endif
+	clpPresolveInfo8  thisInfo;
+	copyFromSave(restore,infoA[i],&thisInfo);
+	iRow = thisInfo.row;
+	// Insert row and modify RHS
+#ifdef CLP_USER_DRIVEN
+	if (type>=8) {
+	  thisInfo.tempElement=tempElement;
+	  thisInfo.tempIndex=tempIndex;
+	  thisInfo.rowLowerX=rowLowerX;
+	  thisInfo.rowUpperX=rowUpperX;
+	  eventHandler_->eventWithInfo(ClpEventHandler::modifyMatrixInMiniPostsolve,&thisInfo);
+	} else {
+#endif
+	if (rowLower_[iRow]>-1.0e30)
+	  rowLowerX[iRow]=rowLower_[iRow]-thisInfo.oldRowLower;
+	else
+	  rowLowerX[iRow]=thisInfo.oldRowLower;
+	if (rowUpper_[iRow]<1.0e30)
+	  rowUpperX[iRow]=rowUpper_[iRow]-thisInfo.oldRowUpper;
+	else
+	  rowUpperX[iRow]=thisInfo.oldRowUpper;
+#ifdef CLP_USER_DRIVEN
+	}
+#endif
+	int n=thisInfo.lengthRow;
+	double rhs=0.0;
+	for (int i=0;i<n;i++) {
+	  int iColumn = tempIndex[i];
+	  double value = tempElement[i];
+	  rhs += value*columnActivity_[iColumn];
+	  int length=columnLengthX[iColumn];
+	  CoinBigIndex start=columnStartX[iColumn];
+	  int nextColumn=forward[iColumn];
+	  CoinBigIndex startNext=columnStartX[nextColumn];
+	  if (start+length==startNext) {
+	    // need more
+	    moveAround(numberColumns_,numberElementsOriginal,
+		       iColumn,length+1,
+		       forward,backward,columnStartX,columnLengthX,
+		       rowX,elementX);
+	    start=columnStartX[iColumn];
+	  }
+	  columnLengthX[iColumn]++;
+	  rowX[start+length]=iRow;
+	  elementX[start+length]=value;
+	}
+	rowActivity_[iRow]=rhs;
+	rowType[iRow]=0;
+	assert (getRowStatus(iRow)==basic);
+      }
+      break;
+    case 2: 
+      // sub
+      {
+	clpPresolveInfo2 thisInfo;
+	copyFromSave(restore,infoA[i],&thisInfo);
+	iColumn = thisInfo.column;
+	columnType[iColumn]=0;
+	int jRowLower=thisInfo.row;
+	int jRowUpper=thisInfo.row2;
+	int length=columnLengthX[iColumn];
+	CoinBigIndex start=columnStartX[iColumn];
+	int nextColumn=forward[iColumn];
+	CoinBigIndex startNext=columnStartX[nextColumn];
+	if (start+length==startNext) {
+	  // need more
+	  moveAround(numberColumns_,numberElementsOriginal,
+		     iColumn,length+(jRowLower<0||jRowUpper<0) ? 1 : 2,
+		     forward,backward,columnStartX,columnLengthX,
+		     rowX,elementX);
+	  start=columnStartX[iColumn];
+	}
+	// modify
+	double valueLower=thisInfo.coefficient;
+	double valueUpper=thisInfo.coefficient2;
+	if (jRowLower>=0) {
+	  rowType[jRowLower]=0;
+	  if (rowLower_[jRowLower]>-1.0e30)
+	    rowLowerX[jRowLower]=rowLower_[jRowLower]-thisInfo.oldRowLower;
+	  else
+	    rowLowerX[jRowLower]=thisInfo.oldRowLower;
+	  if (rowUpper_[jRowLower]<1.0e30)
+	    rowUpperX[jRowLower]=rowUpper_[jRowLower]-thisInfo.oldRowUpper;
+	  else
+	    rowUpperX[jRowLower]=thisInfo.oldRowUpper;
+	  columnLengthX[iColumn]++;
+	  rowX[start+length]=jRowLower;
+	  elementX[start+length]=valueLower;
+	  rowActivity_[jRowLower]=valueLower*columnActivity_[iColumn];
+	  // start off with slack basic
+	  setRowStatus(jRowLower,basic);
+	  length++;
+	}
+	if (jRowUpper>=0) {
+	  rowType[jRowUpper]=0;
+	  if (rowLower_[jRowUpper]>-1.0e30)
+	    rowLowerX[jRowUpper]=rowLower_[jRowUpper]-thisInfo.oldRowLower2;
+	  else
+	    rowLowerX[jRowUpper]=thisInfo.oldRowLower2;
+	  if (rowUpper_[jRowUpper]<1.0e30)
+	    rowUpperX[jRowUpper]=rowUpper_[jRowUpper]-thisInfo.oldRowUpper2;
+	  else
+	    rowUpperX[jRowUpper]=thisInfo.oldRowUpper2;
+	  columnLengthX[iColumn]++;
+	  rowX[start+length]=jRowUpper;
+	  elementX[start+length]=valueUpper;
+	  rowActivity_[jRowUpper]=valueUpper*columnActivity_[iColumn];
+	  // start off with slack basic
+	  setRowStatus(jRowUpper,basic);
+	  length++;
+	}
+	double djValue = objectiveX[iColumn];
+	for (CoinBigIndex j=columnStartX[iColumn];
+	     j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
+	  int jRow=rowX[j];
+	  djValue -= dual_[jRow]*elementX[j];
+	}
+	if (thisInfo.oldColumnLower==thisInfo.oldColumnUpper)
+	  djValue=0.0;
+	if (getColumnStatus(iColumn)!=basic) {
+	  setColumnStatus(iColumn,superBasic);
+	  double solValue = columnActivity_[iColumn];
+	  bool hasToBeBasic=false;
+	  if (getColumnStatus(iColumn)!=isFree) {
+	    if (solValue>thisInfo.oldColumnLower+primalTolerance_&&
+		solValue<thisInfo.oldColumnUpper-primalTolerance_)
+	      hasToBeBasic=true;
+	  } else {
+	    hasToBeBasic=fabs(djValue)>dualTolerance_;
+	  }
+	  if (solValue<=thisInfo.oldColumnLower+primalTolerance_&&djValue<-dualTolerance_) {
+#if DEBUG_SOME > 1
+	    printf("odd column %d at lb of %g has dj of %g\n",
+		   iColumn,thisInfo.oldColumnLower,djValue);
+#endif
+	    hasToBeBasic=true;
+	  } else if (solValue>=thisInfo.oldColumnUpper-primalTolerance_&&djValue>dualTolerance_) {
+#if DEBUG_SOME > 1
+	    printf("odd column %d at ub of %g has dj of %g\n",
+		   iColumn,thisInfo.oldColumnUpper,djValue);
+#endif
+	    hasToBeBasic=true;
+	  }
+	  if (hasToBeBasic) {
+	    if (jRowLower>=0&&jRowUpper>=0) {
+	      // choose
+#if DEBUG_SOME > 1
+	      printf("lower row %d %g <= %g <= %g\n",
+		     jRowLower,rowLowerX[jRowLower],rowActivity_[jRowLower],
+		     rowUpperX[jRowLower]);
+#endif
+	      double awayLower = CoinMin(rowActivity_[jRowLower]-rowLowerX[jRowLower],
+					 rowUpperX[jRowLower]-rowActivity_[jRowLower]);
+#if DEBUG_SOME > 1
+	      printf("upper row %d %g <= %g <= %g\n",
+		     jRowUpper,rowLowerX[jRowUpper],rowActivity_[jRowUpper],
+		     rowUpperX[jRowUpper]);
+#endif
+	      double awayUpper = CoinMin(rowActivity_[jRowUpper]-rowLowerX[jRowUpper],
+					 rowUpperX[jRowUpper]-rowActivity_[jRowUpper]);
+	      if (awayLower>awayUpper)
+		jRowLower=-1;
+	    }
+	    if (jRowLower<0) {
+	      setRowStatus(jRowUpper,superBasic);
+	      setColumnStatus(iColumn,basic);
+	      dual_[jRowUpper]=djValue/valueUpper;
+	    } else {
+	      setRowStatus(jRowLower,superBasic);
+	      setColumnStatus(iColumn,basic);
+	      dual_[jRowLower]=djValue/valueLower;
+	    }
+	  }
+	}
+	columnLowerX[iColumn]=thisInfo.oldColumnLower;
+	columnUpperX[iColumn]=thisInfo.oldColumnUpper;
+      }
+      break;
+    case 11: 
+      // movable column
+      {
+	clpPresolveInfo11 thisInfo;
+	copyFromSave(restore,infoA[i],&thisInfo);
+	iColumn = thisInfo.column;
+	columnType[iColumn]=0;
+	assert (!columnLengthX[iColumn]);
+	int newLength=thisInfo.lengthColumn;
+	CoinBigIndex start=columnStartX[iColumn];
+	int nextColumn=forward[iColumn];
+	CoinBigIndex startNext=columnStartX[nextColumn];
+	if (start+newLength>startNext) {
+	  // need more
+	  moveAround(numberColumns_,numberElementsOriginal,
+		     iColumn,newLength,
+		     forward,backward,columnStartX,columnLengthX,
+		     rowX,elementX);
+	  start=columnStartX[iColumn];
+	}
+	columnLengthX[iColumn]=newLength;
+	memcpy(rowX+start,tempIndex,newLength*sizeof(int));
+	memcpy(elementX+start,tempElement,newLength*sizeof(double));
+	double solValue=thisInfo.fixedTo;
+	columnActivity_[iColumn]=solValue;
+	if (solValue) { 
+	  for (int j=columnStartX[iColumn];
+	       j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
+	    int jRow=rowX[j];
+	    double value=elementX[j]*solValue;
+	    rowActivity_[jRow] += value;
+	    if (rowLowerX[jRow]>-1.0e30)
+	      rowLowerX[jRow] += value;
+	    if (rowUpperX[jRow]<1.0e30)
+	      rowUpperX[jRow] += value;
+	  }
+	}
+	double djValue = objectiveX[iColumn];
+	for (CoinBigIndex j=columnStartX[iColumn];
+	     j<columnStartX[iColumn]+columnLengthX[iColumn];j++) {
+	  int jRow=rowX[j];
+	  djValue -= dual_[jRow]*elementX[j];
+	}
+	if (thisInfo.oldColumnLower==thisInfo.oldColumnUpper)
+	  djValue=0.0;
+	if (getColumnStatus(iColumn)!=basic) {
+	  setColumnStatus(iColumn,superBasic);
+	  bool hasToBeBasic=false;
+	  if (getColumnStatus(iColumn)!=isFree) {
+	    if (solValue>thisInfo.oldColumnLower+primalTolerance_&&
+		solValue<thisInfo.oldColumnUpper-primalTolerance_)
+	      hasToBeBasic=true;
+	  } else {
+	    hasToBeBasic=fabs(djValue)>dualTolerance_;
+	  }
+	  if (solValue<=thisInfo.oldColumnLower+primalTolerance_&&djValue<-dualTolerance_) {
+#if DEBUG_SOME > 1
+	    printf("odd column %d at lb of %g has dj of %g\n",
+		   iColumn,thisInfo.oldColumnLower,djValue);
+#endif
+	    hasToBeBasic=true;
+	  } else if (solValue>=thisInfo.oldColumnUpper-primalTolerance_&&djValue>dualTolerance_) {
+#if DEBUG_SOME > 1
+	    printf("odd column %d at ub of %g has dj of %g\n",
+		   iColumn,thisInfo.oldColumnUpper,djValue);
+#endif
+	    hasToBeBasic=true;
+	  }
+	  if (hasToBeBasic) {
+	    //abort();
+	    //setRowStatus(iRow,superBasic);
+	    setColumnStatus(iColumn,basic);
+	    //dual_[iRow]=djValue/value;
+	  }
+	}
+	columnLowerX[iColumn]=thisInfo.oldColumnLower;
+	columnUpperX[iColumn]=thisInfo.oldColumnUpper;
+      }
+      break;
+    case 13: 
+      // empty (or initially fixed) column
+      {
+	clpPresolveInfo13 thisInfo;
+	copyFromSave(restore,infoA[i],&thisInfo);
+	iColumn = thisInfo.column;
+	columnType[iColumn]=0;
+	columnLowerX[iColumn]=thisInfo.oldColumnLower;
+	columnUpperX[iColumn]=thisInfo.oldColumnUpper;
+	assert (!columnLengthX[iColumn]);
+	int newLength=columnLength[iColumn];
+	CoinBigIndex startOriginal = columnStart[iColumn];
+	double solValue=columnLower_[iColumn];
+	columnActivity_[iColumn]=solValue;
+	if (newLength&&solValue) {
+	  for (int j=startOriginal;j<startOriginal+newLength;j++) {
+	    int iRow=row[j];
+	    double value = element[j]*solValue;
+	    rowActivity_[iRow] += value;
+	    double lower = rowLowerX[iRow];
+	    if (lower>-1.0e20)
+	      rowLowerX[iRow]=lower+value;
+	    double upper = rowUpperX[iRow];
+	    if (upper<1.0e20)
+	      rowUpperX[iRow]=upper+value;
+	  }	  
+	}
+#ifndef NDEBUG
+	// copy from original
+	CoinBigIndex start=columnStartX[iColumn];
+	int nextColumn=forward[iColumn];
+	CoinBigIndex startNext=columnStartX[nextColumn];
+	if (start+newLength>startNext) {
+	  // need more
+	  moveAround(numberColumns_,numberElementsOriginal,
+		     iColumn,newLength,
+		     forward,backward,columnStartX,columnLengthX,
+		     rowX,elementX);
+	  start=columnStartX[iColumn];
+	}
+	columnLengthX[iColumn]=newLength;
+	memcpy(rowX+start,row+startOriginal,newLength*sizeof(int));
+	memcpy(elementX+start,element+startOriginal,newLength*sizeof(double));
+#endif
+      }
+      break;
+    case 14: 
+      // doubleton
+      {
+	clpPresolveInfo14 thisInfo;
+	copyFromSave(restore,infoA[i],&thisInfo);
+	iRow = thisInfo.row;
+	rowType[iRow]=0;
+	int iColumn1 = thisInfo.column;
+	int iColumn2 = thisInfo.column2;
+	columnType[iColumn2]=0;
+	double value1=thisInfo.value1;
+	int length=columnLengthX[iColumn1];
+	CoinBigIndex start=columnStartX[iColumn1];
+	for (int i=0;i<length;i++) {
+	  int jRow=rowX[i+start];
+	  array[jRow]=elementX[i+start];
+	  whichRows2[i]=jRow;
+	}
+	int n=length;
+	length=columnLengthX[iColumn2];
+	assert (!length);
+	int newLength=thisInfo.lengthColumn2;
+	start=columnStartX[iColumn2];
+	int nextColumn=forward[iColumn2];
+	CoinBigIndex startNext=columnStartX[nextColumn];
+	if (start+newLength>startNext) {
+	  // need more
+	  moveAround(numberColumns_,numberElementsOriginal,
+		     iColumn2,newLength,
+		     forward,backward,columnStartX,columnLengthX,
+		     rowX,elementX);
+	  start=columnStartX[iColumn2];
+	}
+	columnLengthX[iColumn2]=newLength;
+	memcpy(rowX+start,tempIndex,newLength*sizeof(int));
+	memcpy(elementX+start,tempElement,newLength*sizeof(double));
+	double value2=0.0;
+	for (int i=0;i<newLength;i++) {
+	  int jRow=tempIndex[i];
+	  double value=tempElement[i];
+	  if (jRow==iRow) {
+	    value2=value;
+	    break;
+	  }
+	}
+	assert (value2);
+	double rhs=thisInfo.rhs;
+	double multiplier1 = rhs/value2;
+	double multiplier = value1/value2;
+	for (int i=0;i<newLength;i++) {
+	  int jRow=tempIndex[i];
+	  double value = array[jRow];
+	  double valueNew = value + multiplier*tempElement[i];
+	  double rhsMod = multiplier1*tempElement[i];
+	  if (rowLowerX[jRow]>-1.0e30)
+	    rowLowerX[jRow] += rhsMod;
+	  if (rowUpperX[jRow]<1.0e30)
+	    rowUpperX[jRow] += rhsMod;
+	  rowActivity_[jRow] += rhsMod;
+	  if (!value) {
+	    array[jRow]=valueNew;
+	    whichRows2[n++]=jRow;
+	  } else {
+	    if (!valueNew)
+	      valueNew=1.0e-100;
+	    array[jRow]=valueNew;
+	  }
+	}
+	length=0;
+	for (int i=0;i<n;i++) {
+	  int jRow = whichRows2[i];
+	  double value = array[jRow];
+	  array[jRow]=0.0;
+	  if (fabs(value)<1.0e-13) 
+	    value=0.0;
+	  if (value) {
+	    tempIndex[length] = jRow;
+	    tempElement[length++]=value;
+	  }
+	}
+	start=columnStartX[iColumn1];
+	nextColumn=forward[iColumn1];
+	startNext=columnStartX[nextColumn];
+	if (start+length>startNext) {
+	  // need more
+	  moveAround(numberColumns_,numberElementsOriginal,
+		     iColumn1,length,
+		     forward,backward,columnStartX,columnLengthX,
+		     rowX,elementX);
+	  start=columnStartX[iColumn1];
+	}
+	columnLengthX[iColumn1]=length;
+	memcpy(rowX+start,tempIndex,length*sizeof(int));
+	memcpy(elementX+start,tempElement,length*sizeof(double));
+	objectiveX[iColumn2]=thisInfo.oldObjective2;
+	objectiveX[iColumn1] += objectiveX[iColumn2]*multiplier;
+	//offset += rhs*(objectiveX[iColumn2]*multiplier);
+	double value = multiplier1-columnActivity_[iColumn1]*multiplier;
+#if DEBUG_SOME > 0
+	printf("type14 column2 %d rhs %g value1 %g - value %g\n",
+	       iColumn2,thisInfo.rhs,thisInfo.value1,value);
+#endif
+	columnActivity_[iColumn2]=value;
+	double djValue1 = objectiveX[iColumn1];
+	for (CoinBigIndex j=columnStartX[iColumn1];
+	     j<columnStartX[iColumn1]+columnLengthX[iColumn1];j++) {
+	  int jRow=rowX[j];
+	  djValue1 -= dual_[jRow]*elementX[j];
+	}
+	bool fixed = (thisInfo.oldColumnLower==thisInfo.oldColumnUpper);
+	columnLowerX[iColumn1]=thisInfo.oldColumnLower;
+	columnUpperX[iColumn1]=thisInfo.oldColumnUpper;
+	double djValue2 = objectiveX[iColumn2];
+	for (CoinBigIndex j=columnStartX[iColumn2];
+	     j<columnStartX[iColumn2]+columnLengthX[iColumn2];j++) {
+	  int jRow=rowX[j];
+	  djValue2 -= dual_[jRow]*elementX[j];
+	}
+	bool fixed2 = (thisInfo.oldColumnLower2==thisInfo.oldColumnUpper2);
+	columnLowerX[iColumn2]=thisInfo.oldColumnLower2;
+	columnUpperX[iColumn2]=thisInfo.oldColumnUpper2;
+	if (getColumnStatus(iColumn1)!=basic) {
+	  setColumnStatus(iColumn1,superBasic);
+	  double solValue = columnActivity_[iColumn1];
+	  double lowerValue = columnLowerX[iColumn1];
+	  double upperValue = columnUpperX[iColumn1];
+	  setColumnStatus(iColumn2,superBasic);
+	  double solValue2 = columnActivity_[iColumn2];
+	  double lowerValue2 = columnLowerX[iColumn2];
+	  double upperValue2 = columnUpperX[iColumn2];
+	  int choice=-1;
+	  double best=COIN_DBL_MAX;
+	  for (int iTry=0;iTry<3;iTry++) {
+	    double pi=0.0;
+	    switch (iTry) {
+	      // leave
+	    case 0:
+	      break;
+	      // iColumn1 basic
+	    case 1:
+	      pi=djValue1/value1;
+	      break;
+	      // iColumn2 basic
+	    case 2:
+	      pi=djValue2/value2;
+	      break;
+	    }
+	    // djs
+	    double dj1 = djValue1-value1*pi;;
+	    double bad1=0.0;
+	    if (!fixed) {
+	      if (dj1<-dualTolerance_&&solValue<=lowerValue+primalTolerance_)
+		bad1=-dj1;
+	      else if (dj1>dualTolerance_&&solValue>=upperValue-primalTolerance_)
+		bad1=dj1;
+	    }
+	    double dj2 = djValue2-value2*pi;
+	    double bad2=0.0;
+	    if (!fixed2) {
+	      if (dj2<-dualTolerance_&&solValue2<=lowerValue2+primalTolerance_)
+		bad2=-dj2;
+	      else if (dj2>dualTolerance_&&solValue2>=upperValue2-primalTolerance_)
+		bad2=dj2;
+	    }
+	    if (CoinMax(bad1,bad2)<best) {
+	      best=CoinMax(bad1,bad2);
+	      choice=iTry;
+	    }
+	  }
+	  // but values override
+	  if (solValue>lowerValue+primalTolerance_&&
+	      solValue<upperValue-primalTolerance_) {
+	    if (getColumnStatus(iColumn1)!=isFree||
+		fabs(djValue1)>dualTolerance_)
+	      choice=1;
+	  } else if (solValue2>lowerValue2+primalTolerance_&&
+	      solValue2<upperValue2-primalTolerance_) {
+	    if (getColumnStatus(iColumn2)!=isFree||
+		fabs(djValue2)>dualTolerance_)
+	      choice=2;
+	  }
+	  if (choice==1) {
+	    // iColumn1 in basis
+	    setRowStatus(iRow,superBasic);
+	    setColumnStatus(iColumn1,basic);
+	    dual_[iRow]=djValue1/value1;
+	  } else if (choice==2) {
+	    // iColumn2 in basis
+	    setRowStatus(iRow,superBasic);
+	    setColumnStatus(iColumn2,basic);
+	    dual_[iRow]=djValue2/value2;
+	  }
+	} else {
+	  if (fabs(djValue1)>10.0*dualTolerance_) {
+	    // iColumn2 in basis
+	    setRowStatus(iRow,superBasic);
+	    setColumnStatus(iColumn2,basic);
+	    dual_[iRow]=djValue2/value2;
+	  } else {
+	    // do we need iColumn2 in basis
+	    double solValue2 = columnActivity_[iColumn2];
+	    double lowerValue2 = columnLowerX[iColumn2];
+	    double upperValue2 = columnUpperX[iColumn2];
+	    if (solValue2>lowerValue2+primalTolerance_&&
+		solValue2<upperValue2-primalTolerance_&&
+		getColumnStatus(iColumn2)!=isFree) {
+	      // iColumn2 in basis
+	      setRowStatus(iRow,superBasic);
+	      setColumnStatus(iColumn2,basic);
+	      dual_[iRow]=djValue2/value2;
+	    }
+	  }
+	}
+	rowLowerX[iRow]=rhs;
+	rowUpperX[iRow]=rhs;
+	//abort();
+      }
+      break;
+    }
+  }
+#ifndef NDEBUG
+#ifndef CLP_USER_DRIVEN
+      // otherwise user may be fudging rhs
+  for (int iRow=0;iRow<numberRows_;iRow++) {
+#ifndef CLP_USER_DRIVEN
+    assert (fabs(rowLower_[iRow]-rowLowerX[iRow])<1.0e-4);
+    assert (fabs(rowUpper_[iRow]-rowUpperX[iRow])<1.0e-4);
+#else
+    if (fabs(rowLower_[iRow]-rowLowerX[iRow])>1.0e-4||
+	fabs(rowUpper_[iRow]-rowUpperX[iRow])>1.0e-4)
+      printf("USER row %d lower,x %g %g upper,x %g %g\n",iRow,rowLower_[iRow],rowLowerX[iRow],
+	     rowUpper_[iRow],rowUpperX[iRow]);
+      
+#endif
+  }
+  double * objective = this->objective();
+  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+    assert (columnLower_[iColumn]==columnLowerX[iColumn]);
+    assert (columnUpper_[iColumn]==columnUpperX[iColumn]);
+    assert (fabs(objective[iColumn]-objectiveX[iColumn]*optimizationDirection_)<1.0e-3);
+  }
+#endif
+  if (checkMatrixAtEnd) {
+    for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+      assert (columnLength[iColumn]==columnLengthX[iColumn]);
+      int length=columnLengthX[iColumn];
+      CoinBigIndex startX=columnStartX[iColumn];
+      CoinSort_2(rowX+startX,rowX+startX+length,elementX+startX);
+      CoinBigIndex start=columnStart[iColumn];
+      memcpy(tempIndex,row+start,length*sizeof(int));
+      memcpy(tempElement,element+start,length*sizeof(double));
+      CoinSort_2(tempIndex,tempIndex+length,tempElement);
+      for (int i=0;i<length;i++) {
+	assert (rowX[i+startX]==tempIndex[i]);
+	assert (fabs(elementX[i+startX]-tempElement[i])<1.0e-5);
+      }
+    }
+  }
+#endif
+  delete [] rowType;
+  delete [] tempIndex;
+  // use temp matrix and do this every action
+#if DEBUG_SOME>0
+  matrix()->times(columnActivity_,rowActivity_);
+  for (int i=0;i<numberColumns_;i++)
+    assert (columnActivity_[i]>=columnLower_[i]-1.0e-5&&
+	    columnActivity_[i]<=columnUpper_[i]+1.0e-5);
+  int nBad=0;
+  for (int i=0;i<numberRows_;i++) {
+    if (rowActivity_[i]<rowLower_[i]-1.0e-5||
+	rowActivity_[i]>rowUpper_[i]+1.0e-5) {
+      printf("Row %d %g %g %g\n",i,rowLower_[i],
+	     rowActivity_[i],rowUpper_[i]);
+      nBad++;
+    }
+  }
+  ClpTraceDebug (!nBad);
+#endif
+#if 1 //DEBUG_SOME > 0
+  delete [] tempRhs;
+#endif
+  delete infoX;
+  delete [] infoA;
+  delete [] rowLowerX;
+}
diff --git a/cbits/coin/ClpSimplexOther.hpp b/cbits/coin/ClpSimplexOther.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplexOther.hpp
@@ -0,0 +1,273 @@
+/* $Id: ClpSimplexOther.hpp 1884 2012-11-05 17:38:48Z forrest $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef ClpSimplexOther_H
+#define ClpSimplexOther_H
+
+#include "ClpSimplex.hpp"
+
+/** This is for Simplex stuff which is neither dual nor primal
+
+    It inherits from ClpSimplex.  It has no data of its own and
+    is never created - only cast from a ClpSimplex object at algorithm time.
+
+*/
+
+class ClpSimplexOther : public ClpSimplex {
+
+public:
+
+     /**@name Methods */
+     //@{
+     /** Dual ranging.
+         This computes increase/decrease in cost for each given variable and corresponding
+         sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
+         and numberColumns.. for artificials/slacks.
+         For non-basic variables the information is trivial to compute and the change in cost is just minus the
+         reduced cost and the sequence number will be that of the non-basic variables.
+         For basic variables a ratio test is between the reduced costs for non-basic variables
+         and the row of the tableau corresponding to the basic variable.
+         The increase/decrease value is always >= 0.0
+
+         Up to user to provide correct length arrays where each array is of length numberCheck.
+         which contains list of variables for which information is desired.  All other
+         arrays will be filled in by function.  If fifth entry in which is variable 7 then fifth entry in output arrays
+         will be information for variable 7.
+
+         If valueIncrease/Decrease not NULL (both must be NULL or both non NULL) then these are filled with
+         the value of variable if such a change in cost were made (the existing bounds are ignored)
+
+         When here - guaranteed optimal
+     */
+     void dualRanging(int numberCheck, const int * which,
+                      double * costIncrease, int * sequenceIncrease,
+                      double * costDecrease, int * sequenceDecrease,
+                      double * valueIncrease = NULL, double * valueDecrease = NULL);
+     /** Primal ranging.
+         This computes increase/decrease in value for each given variable and corresponding
+         sequence numbers which would change basis.  Sequence numbers are 0..numberColumns
+         and numberColumns.. for artificials/slacks.
+         This should only be used for non-basic variabls as otherwise information is pretty useless
+         For basic variables the sequence number will be that of the basic variables.
+
+         Up to user to provide correct length arrays where each array is of length numberCheck.
+         which contains list of variables for which information is desired.  All other
+         arrays will be filled in by function.  If fifth entry in which is variable 7 then fifth entry in output arrays
+         will be information for variable 7.
+
+         When here - guaranteed optimal
+     */
+     void primalRanging(int numberCheck, const int * which,
+                        double * valueIncrease, int * sequenceIncrease,
+                        double * valueDecrease, int * sequenceDecrease);
+     /** Parametrics
+         This is an initial slow version.
+         The code uses current bounds + theta * change (if change array not NULL)
+         and similarly for objective.
+         It starts at startingTheta and returns ending theta in endingTheta.
+         If reportIncrement 0.0 it will report on any movement
+         If reportIncrement >0.0 it will report at startingTheta+k*reportIncrement.
+         If it can not reach input endingTheta return code will be 1 for infeasible,
+         2 for unbounded, if error on ranges -1,  otherwise 0.
+         Normal report is just theta and objective but
+         if event handler exists it may do more
+         On exit endingTheta is maximum reached (can be used for next startingTheta)
+     */
+     int parametrics(double startingTheta, double & endingTheta, double reportIncrement,
+                     const double * changeLowerBound, const double * changeUpperBound,
+                     const double * changeLowerRhs, const double * changeUpperRhs,
+                     const double * changeObjective);
+     /** Version of parametrics which reads from file
+	 See CbcClpParam.cpp for details of format
+	 Returns -2 if unable to open file */
+     int parametrics(const char * dataFile);
+     /** Parametrics
+         This is an initial slow version.
+         The code uses current bounds + theta * change (if change array not NULL)
+         It starts at startingTheta and returns ending theta in endingTheta.
+         If it can not reach input endingTheta return code will be 1 for infeasible,
+         2 for unbounded, if error on ranges -1,  otherwise 0.
+         Event handler may do more
+         On exit endingTheta is maximum reached (can be used for next startingTheta)
+     */
+     int parametrics(double startingTheta, double & endingTheta, 
+                     const double * changeLowerBound, const double * changeUpperBound,
+                     const double * changeLowerRhs, const double * changeUpperRhs);
+     int parametricsObj(double startingTheta, double & endingTheta, 
+			const double * changeObjective);
+    /// Finds best possible pivot
+    double bestPivot(bool justColumns=false);
+  typedef struct {
+    double startingTheta;
+    double endingTheta;
+    double maxTheta;
+    double acceptableMaxTheta; // if this far then within tolerances
+    double * lowerChange; // full array of lower bound changes
+    int * lowerList; // list of lower bound changes
+    double * upperChange; // full array of upper bound changes
+    int * upperList; // list of upper bound changes
+    char * markDone; // mark which ones looked at
+    int * backwardBasic; // from sequence to pivot row
+    int * lowerActive;
+    double * lowerGap;
+    double * lowerCoefficient;
+    int * upperActive;
+    double * upperGap;
+    double * upperCoefficient;
+    int unscaledChangesOffset; 
+    bool firstIteration; // so can update rhs for accuracy
+  } parametricsData;
+
+private:
+     /** Parametrics - inner loop
+         This first attempt is when reportIncrement non zero and may
+         not report endingTheta correctly
+         If it can not reach input endingTheta return code will be 1 for infeasible,
+         2 for unbounded,  otherwise 0.
+         Normal report is just theta and objective but
+         if event handler exists it may do more
+     */
+     int parametricsLoop(parametricsData & paramData, double reportIncrement,
+                         const double * changeLower, const double * changeUpper,
+                         const double * changeObjective, ClpDataSave & data,
+                         bool canTryQuick);
+     int parametricsLoop(parametricsData & paramData,
+                         ClpDataSave & data,bool canSkipFactorization=false);
+     int parametricsObjLoop(parametricsData & paramData,
+                         ClpDataSave & data,bool canSkipFactorization=false);
+     /**  Refactorizes if necessary
+          Checks if finished.  Updates status.
+
+          type - 0 initial so set up save arrays etc
+               - 1 normal -if good update save
+           - 2 restoring from saved
+     */
+     void statusOfProblemInParametrics(int type, ClpDataSave & saveData);
+     void statusOfProblemInParametricsObj(int type, ClpDataSave & saveData);
+     /** This has the flow between re-factorizations
+
+         Reasons to come out:
+         -1 iterations etc
+         -2 inaccuracy
+         -3 slight inaccuracy (and done iterations)
+         +0 looks optimal (might be unbounded - but we will investigate)
+         +1 looks infeasible
+         +3 max iterations
+      */
+     int whileIterating(parametricsData & paramData, double reportIncrement,
+                        const double * changeObjective);
+     /** Computes next theta and says if objective or bounds (0= bounds, 1 objective, -1 none).
+         theta is in theta_.
+         type 1 bounds, 2 objective, 3 both.
+     */
+     int nextTheta(int type, double maxTheta, parametricsData & paramData,
+                   const double * changeObjective);
+     int whileIteratingObj(parametricsData & paramData);
+     int nextThetaObj(double maxTheta, parametricsData & paramData);
+     /// Restores bound to original bound
+     void originalBound(int iSequence, double theta, const double * changeLower,
+		     const double * changeUpper);
+     /// Compute new rowLower_ etc (return negative if infeasible - otherwise largest change)
+     double computeRhsEtc(parametricsData & paramData);
+     /// Redo lower_ from rowLower_ etc
+     void redoInternalArrays();
+     /**
+         Row array has row part of pivot row
+         Column array has column part.
+         This is used in dual ranging
+     */
+     void checkDualRatios(CoinIndexedVector * rowArray,
+                          CoinIndexedVector * columnArray,
+                          double & costIncrease, int & sequenceIncrease, double & alphaIncrease,
+                          double & costDecrease, int & sequenceDecrease, double & alphaDecrease);
+     /**
+         Row array has pivot column
+         This is used in primal ranging
+     */
+     void checkPrimalRatios(CoinIndexedVector * rowArray,
+                            int direction);
+     /// Returns new value of whichOther when whichIn enters basis
+     double primalRanging1(int whichIn, int whichOther);
+
+public:
+     /** Write the basis in MPS format to the specified file.
+     If writeValues true writes values of structurals
+     (and adds VALUES to end of NAME card)
+
+     Row and column names may be null.
+     formatType is
+     <ul>
+       <li> 0 - normal
+       <li> 1 - extra accuracy
+       <li> 2 - IEEE hex (later)
+     </ul>
+
+     Returns non-zero on I/O error
+     */
+     int writeBasis(const char *filename,
+                    bool writeValues = false,
+                    int formatType = 0) const;
+     /// Read a basis from the given filename
+     int readBasis(const char *filename);
+     /** Creates dual of a problem if looks plausible
+         (defaults will always create model)
+         fractionRowRanges is fraction of rows allowed to have ranges
+         fractionColumnRanges is fraction of columns allowed to have ranges
+     */
+     ClpSimplex * dualOfModel(double fractionRowRanges = 1.0, double fractionColumnRanges = 1.0) const;
+     /** Restores solution from dualized problem
+         non-zero return code indicates minor problems
+     */
+  int restoreFromDual(const ClpSimplex * dualProblem,
+		      bool checkAccuracy=false);
+     /** Does very cursory presolve.
+         rhs is numberRows, whichRows is 3*numberRows and whichColumns is 2*numberColumns.
+     */
+     ClpSimplex * crunch(double * rhs, int * whichRows, int * whichColumns,
+                         int & nBound, bool moreBounds = false, bool tightenBounds = false);
+     /** After very cursory presolve.
+         rhs is numberRows, whichRows is 3*numberRows and whichColumns is 2*numberColumns.
+     */
+     void afterCrunch(const ClpSimplex & small,
+                      const int * whichRows, const int * whichColumns,
+                      int nBound);
+     /** Returns gub version of model or NULL
+	 whichRows has to be numberRows
+	 whichColumns has to be numberRows+numberColumns */
+     ClpSimplex * gubVersion(int * whichRows, int * whichColumns,
+			     int neededGub,
+			     int factorizationFrequency=50);
+     /// Sets basis from original
+     void setGubBasis(ClpSimplex &original,const int * whichRows,
+		      const int * whichColumns);
+     /// Restores basis to original
+     void getGubBasis(ClpSimplex &original,const int * whichRows,
+		      const int * whichColumns) const;
+     /// Quick try at cleaning up duals if postsolve gets wrong
+     void cleanupAfterPostsolve();
+     /** Tightens integer bounds - returns number tightened or -1 if infeasible
+     */
+     int tightenIntegerBounds(double * rhsSpace);
+     /** Expands out all possible combinations for a knapsack
+         If buildObj NULL then just computes space needed - returns number elements
+         On entry numberOutput is maximum allowed, on exit it is number needed or
+         -1 (as will be number elements) if maximum exceeded.  numberOutput will have at
+         least space to return values which reconstruct input.
+         Rows returned will be original rows but no entries will be returned for
+         any rows all of whose entries are in knapsack.  So up to user to allow for this.
+         If reConstruct >=0 then returns number of entrie which make up item "reConstruct"
+         in expanded knapsack.  Values in buildRow and buildElement;
+     */
+     int expandKnapsack(int knapsackRow, int & numberOutput,
+                        double * buildObj, CoinBigIndex * buildStart,
+                        int * buildRow, double * buildElement, int reConstruct = -1) const;
+     //@}
+};
+#endif
diff --git a/cbits/coin/ClpSimplexPrimal.cpp b/cbits/coin/ClpSimplexPrimal.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplexPrimal.cpp
@@ -0,0 +1,3803 @@
+/* $Id: ClpSimplexPrimal.cpp 1931 2013-04-06 20:44:29Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/* Notes on implementation of primal simplex algorithm.
+
+   When primal feasible(A):
+
+   If dual feasible, we are optimal.  Otherwise choose an infeasible
+   basic variable to enter basis from a bound (B).  We now need to find an
+   outgoing variable which will leave problem primal feasible so we get
+   the column of the tableau corresponding to the incoming variable
+   (with the correct sign depending if variable will go up or down).
+
+   We now perform a ratio test to determine which outgoing variable will
+   preserve primal feasibility (C).  If no variable found then problem
+   is unbounded (in primal sense).  If there is a variable, we then
+   perform pivot and repeat.  Trivial?
+
+   -------------------------------------------
+
+   A) How do we get primal feasible?  All variables have fake costs
+   outside their feasible region so it is trivial to declare problem
+   feasible.  OSL did not have a phase 1/phase 2 approach but
+   instead effectively put an extra cost on infeasible basic variables
+   I am taking the same approach here, although it is generalized
+   to allow for non-linear costs and dual information.
+
+   In OSL, this weight was changed heuristically, here at present
+   it is only increased if problem looks finished.  If problem is
+   feasible I check for unboundedness.  If not unbounded we
+   could play with going into dual.  As long as weights increase
+   any algorithm would be finite.
+
+   B) Which incoming variable to choose is a virtual base class.
+   For difficult problems steepest edge is preferred while for
+   very easy (large) problems we will need partial scan.
+
+   C) Sounds easy, but this is hardest part of algorithm.
+      1) Instead of stopping at first choice, we may be able
+      to allow that variable to go through bound and if objective
+      still improving choose again.  These mini iterations can
+      increase speed by orders of magnitude but we may need to
+      go to more of a bucket choice of variable rather than looking
+      at them one by one (for speed).
+      2) Accuracy.  Basic infeasibilities may be less than
+      tolerance.  Pivoting on these makes objective go backwards.
+      OSL modified cost so a zero move was made, Gill et al
+      modified so a strictly positive move was made.
+      The two problems are that re-factorizations can
+      change rinfeasibilities above and below tolerances and that when
+      finished we need to reset costs and try again.
+      3) Degeneracy.  Gill et al helps but may not be enough.  We
+      may need more.  Also it can improve speed a lot if we perturb
+      the rhs and bounds significantly.
+
+  References:
+     Forrest and Goldfarb, Steepest-edge simplex algorithms for
+       linear programming - Mathematical Programming 1992
+     Forrest and Tomlin, Implementing the simplex method for
+       the Optimization Subroutine Library - IBM Systems Journal 1992
+     Gill, Murray, Saunders, Wright A Practical Anti-Cycling
+       Procedure for Linear and Nonlinear Programming SOL report 1988
+
+
+  TODO:
+
+  a) Better recovery procedures.  At present I never check on forward
+     progress.  There is checkpoint/restart with reducing
+     re-factorization frequency, but this is only on singular
+     factorizations.
+  b) Fast methods for large easy problems (and also the option for
+     the code to automatically choose which method).
+  c) We need to be able to stop in various ways for OSI - this
+     is fairly easy.
+
+ */
+
+
+#include "CoinPragma.hpp"
+
+#include <math.h>
+
+#include "CoinHelperFunctions.hpp"
+#include "ClpSimplexPrimal.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpNonLinearCost.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinIndexedVector.hpp"
+#include "ClpPrimalColumnPivot.hpp"
+#include "ClpMessage.hpp"
+#include "ClpEventHandler.hpp"
+#include <cfloat>
+#include <cassert>
+#include <string>
+#include <stdio.h>
+#include <iostream>
+#ifdef CLP_USER_DRIVEN1
+/* Returns true if variable sequenceOut can leave basis when
+   model->sequenceIn() enters.
+   This function may be entered several times for each sequenceOut.  
+   The first time realAlpha will be positive if going to lower bound
+   and negative if going to upper bound (scaled bounds in lower,upper) - then will be zero.
+   currentValue is distance to bound.
+   currentTheta is current theta.
+   alpha is fabs(pivot element).
+   Variable will change theta if currentValue - currentTheta*alpha < 0.0
+*/
+bool userChoiceValid1(const ClpSimplex * model,
+		      int sequenceOut,
+		      double currentValue,
+		      double currentTheta,
+		      double alpha,
+		      double realAlpha);
+/* This returns true if chosen in/out pair valid.
+   The main thing to check would be variable flipping bounds may be
+   OK.  This would be signaled by reasonable theta_ and valueOut_.
+   If you return false sequenceIn_ will be flagged as ineligible.
+*/
+bool userChoiceValid2(const ClpSimplex * model);
+/* If a good pivot then you may wish to unflag some variables.
+ */
+void userChoiceWasGood(ClpSimplex * model);
+#endif
+// primal
+int ClpSimplexPrimal::primal (int ifValuesPass , int startFinishOptions)
+{
+
+     /*
+         Method
+
+        It tries to be a single phase approach with a weight of 1.0 being
+        given to getting optimal and a weight of infeasibilityCost_ being
+        given to getting primal feasible.  In this version I have tried to
+        be clever in a stupid way.  The idea of fake bounds in dual
+        seems to work so the primal analogue would be that of getting
+        bounds on reduced costs (by a presolve approach) and using
+        these for being above or below feasible region.  I decided to waste
+        memory and keep these explicitly.  This allows for non-linear
+        costs!
+
+        The code is designed to take advantage of sparsity so arrays are
+        seldom zeroed out from scratch or gone over in their entirety.
+        The only exception is a full scan to find incoming variable for
+        Dantzig row choice.  For steepest edge we keep an updated list
+        of dual infeasibilities (actually squares).
+        On easy problems we don't need full scan - just
+        pick first reasonable.
+
+        One problem is how to tackle degeneracy and accuracy.  At present
+        I am using the modification of costs which I put in OSL and which was
+        extended by Gill et al.  I am still not sure of the exact details.
+
+        The flow of primal is three while loops as follows:
+
+        while (not finished) {
+
+          while (not clean solution) {
+
+             Factorize and/or clean up solution by changing bounds so
+       primal feasible.  If looks finished check fake primal bounds.
+       Repeat until status is iterating (-1) or finished (0,1,2)
+
+          }
+
+          while (status==-1) {
+
+            Iterate until no pivot in or out or time to re-factorize.
+
+            Flow is:
+
+            choose pivot column (incoming variable).  if none then
+      we are primal feasible so looks as if done but we need to
+      break and check bounds etc.
+
+      Get pivot column in tableau
+
+            Choose outgoing row.  If we don't find one then we look
+      primal unbounded so break and check bounds etc.  (Also the
+      pivot tolerance is larger after any iterations so that may be
+      reason)
+
+            If we do find outgoing row, we may have to adjust costs to
+      keep going forwards (anti-degeneracy).  Check pivot will be stable
+      and if unstable throw away iteration and break to re-factorize.
+      If minor error re-factorize after iteration.
+
+      Update everything (this may involve changing bounds on
+      variables to stay primal feasible.
+
+          }
+
+        }
+
+        At present we never check we are going forwards.  I overdid that in
+        OSL so will try and make a last resort.
+
+        Needs partial scan pivot in option.
+
+        May need other anti-degeneracy measures, especially if we try and use
+        loose tolerances as a way to solve in fewer iterations.
+
+        I like idea of dynamic scaling.  This gives opportunity to decouple
+        different implications of scaling for accuracy, iteration count and
+        feasibility tolerance.
+
+     */
+
+     algorithm_ = +1;
+     moreSpecialOptions_ &= ~16; // clear check replaceColumn accuracy
+
+     // save data
+     ClpDataSave data = saveData();
+     matrix_->refresh(this); // make sure matrix okay
+
+     // Save so can see if doing after dual
+     int initialStatus = problemStatus_;
+     int initialIterations = numberIterations_;
+     int initialNegDjs = -1;
+     // initialize - maybe values pass and algorithm_ is +1
+#if 0
+     // if so - put in any superbasic costed slacks
+     if (ifValuesPass && specialOptions_ < 0x01000000) {
+          // Get column copy
+          const CoinPackedMatrix * columnCopy = matrix();
+          const int * row = columnCopy->getIndices();
+          const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+          const int * columnLength = columnCopy->getVectorLengths();
+          //const double * element = columnCopy->getElements();
+          int n = 0;
+          for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (columnLength[iColumn] == 1) {
+                    Status status = getColumnStatus(iColumn);
+                    if (status != basic && status != isFree) {
+                         double value = columnActivity_[iColumn];
+                         if (fabs(value - columnLower_[iColumn]) > primalTolerance_ &&
+                                   fabs(value - columnUpper_[iColumn]) > primalTolerance_) {
+                              int iRow = row[columnStart[iColumn]];
+                              if (getRowStatus(iRow) == basic) {
+                                   setRowStatus(iRow, superBasic);
+                                   setColumnStatus(iColumn, basic);
+                                   n++;
+                              }
+                         }
+                    }
+               }
+          }
+          printf("%d costed slacks put in basis\n", n);
+     }
+#endif
+     // Start can skip some things in transposeTimes
+     specialOptions_ |= 131072;
+     if (!startup(ifValuesPass, startFinishOptions)) {
+
+          // Set average theta
+          nonLinearCost_->setAverageTheta(1.0e3);
+          int lastCleaned = 0; // last time objective or bounds cleaned up
+
+          // Say no pivot has occurred (for steepest edge and updates)
+          pivotRow_ = -2;
+
+          // This says whether to restore things etc
+          int factorType = 0;
+          if (problemStatus_ < 0 && perturbation_ < 100 && !ifValuesPass) {
+               perturb(0);
+               // Can't get here if values pass
+               assert (!ifValuesPass);
+               gutsOfSolution(NULL, NULL);
+               if (handler_->logLevel() > 2) {
+                    handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                              << numberIterations_ << objectiveValue();
+                    handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                              << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+                    handler_->printing(sumDualInfeasibilities_ > 0.0)
+                              << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+                    handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                                       < numberDualInfeasibilities_)
+                              << numberDualInfeasibilitiesWithoutFree_;
+                    handler_->message() << CoinMessageEol;
+               }
+          }
+          ClpSimplex * saveModel = NULL;
+          int stopSprint = -1;
+          int sprintPass = 0;
+          int reasonableSprintIteration = 0;
+          int lastSprintIteration = 0;
+          double lastObjectiveValue = COIN_DBL_MAX;
+          // Start check for cycles
+          progress_.fillFromModel(this);
+          progress_.startCheck();
+          /*
+            Status of problem:
+            0 - optimal
+            1 - infeasible
+            2 - unbounded
+            -1 - iterating
+            -2 - factorization wanted
+            -3 - redo checking without factorization
+            -4 - looks infeasible
+            -5 - looks unbounded
+          */
+          while (problemStatus_ < 0) {
+               int iRow, iColumn;
+               // clear
+               for (iRow = 0; iRow < 4; iRow++) {
+                    rowArray_[iRow]->clear();
+               }
+
+               for (iColumn = 0; iColumn < 2; iColumn++) {
+                    columnArray_[iColumn]->clear();
+               }
+
+               // give matrix (and model costs and bounds a chance to be
+               // refreshed (normally null)
+               matrix_->refresh(this);
+               // If getting nowhere - why not give it a kick
+#if 1
+               if (perturbation_ < 101 && numberIterations_ > 2 * (numberRows_ + numberColumns_) && (specialOptions_ & 4) == 0
+                         && initialStatus != 10) {
+                    perturb(1);
+                    matrix_->rhsOffset(this, true, false);
+               }
+#endif
+               // If we have done no iterations - special
+               if (lastGoodIteration_ == numberIterations_ && factorType)
+                    factorType = 3;
+               if (saveModel) {
+                    // Doing sprint
+                    if (sequenceIn_ < 0 || numberIterations_ >= stopSprint) {
+                         problemStatus_ = -1;
+                         originalModel(saveModel);
+                         saveModel = NULL;
+                         if (sequenceIn_ < 0 && numberIterations_ < reasonableSprintIteration &&
+                                   sprintPass > 100)
+                              primalColumnPivot_->switchOffSprint();
+                         //lastSprintIteration=numberIterations_;
+                         COIN_DETAIL_PRINT(printf("End small model\n"));
+                    }
+               }
+
+               // may factorize, checks if problem finished
+               statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true, ifValuesPass, saveModel);
+               if (initialStatus == 10) {
+                    // cleanup phase
+                    if(initialIterations != numberIterations_) {
+                         if (numberDualInfeasibilities_ > 10000 && numberDualInfeasibilities_ > 10 * initialNegDjs) {
+                              // getting worse - try perturbing
+                              if (perturbation_ < 101 && (specialOptions_ & 4) == 0) {
+                                   perturb(1);
+                                   matrix_->rhsOffset(this, true, false);
+                                   statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true, ifValuesPass, saveModel);
+                              }
+                         }
+                    } else {
+                         // save number of negative djs
+                         if (!numberPrimalInfeasibilities_)
+                              initialNegDjs = numberDualInfeasibilities_;
+                         // make sure weight won't be changed
+                         if (infeasibilityCost_ == 1.0e10)
+                              infeasibilityCost_ = 1.000001e10;
+                    }
+               }
+               // See if sprint says redo because of problems
+               if (numberDualInfeasibilities_ == -776) {
+                    // Need new set of variables
+                    problemStatus_ = -1;
+                    originalModel(saveModel);
+                    saveModel = NULL;
+                    //lastSprintIteration=numberIterations_;
+                    COIN_DETAIL_PRINT(printf("End small model after\n"));
+                    statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true, ifValuesPass, saveModel);
+               }
+               int numberSprintIterations = 0;
+               int numberSprintColumns = primalColumnPivot_->numberSprintColumns(numberSprintIterations);
+               if (problemStatus_ == 777) {
+                    // problems so do one pass with normal
+                    problemStatus_ = -1;
+                    originalModel(saveModel);
+                    saveModel = NULL;
+                    // Skip factorization
+                    //statusOfProblemInPrimal(lastCleaned,factorType,&progress_,false,saveModel);
+                    statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true, ifValuesPass, saveModel);
+               } else if (problemStatus_ < 0 && !saveModel && numberSprintColumns && firstFree_ < 0) {
+                    int numberSort = 0;
+                    int numberFixed = 0;
+                    int numberBasic = 0;
+                    reasonableSprintIteration = numberIterations_ + 100;
+                    int * whichColumns = new int[numberColumns_];
+                    double * weight = new double[numberColumns_];
+                    int numberNegative = 0;
+                    double sumNegative = 0.0;
+                    // now massage weight so all basic in plus good djs
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         double dj = dj_[iColumn];
+                         switch(getColumnStatus(iColumn)) {
+
+                         case basic:
+                              dj = -1.0e50;
+                              numberBasic++;
+                              break;
+                         case atUpperBound:
+                              dj = -dj;
+                              break;
+                         case isFixed:
+                              dj = 1.0e50;
+                              numberFixed++;
+                              break;
+                         case atLowerBound:
+                              dj = dj;
+                              break;
+                         case isFree:
+                              dj = -100.0 * fabs(dj);
+                              break;
+                         case superBasic:
+                              dj = -100.0 * fabs(dj);
+                              break;
+                         }
+                         if (dj < -dualTolerance_ && dj > -1.0e50) {
+                              numberNegative++;
+                              sumNegative -= dj;
+                         }
+                         weight[iColumn] = dj;
+                         whichColumns[iColumn] = iColumn;
+                    }
+                    handler_->message(CLP_SPRINT, messages_)
+                              << sprintPass << numberIterations_ - lastSprintIteration << objectiveValue() << sumNegative
+                              << numberNegative
+                              << CoinMessageEol;
+                    sprintPass++;
+                    lastSprintIteration = numberIterations_;
+                    if (objectiveValue()*optimizationDirection_ > lastObjectiveValue - 1.0e-7 && sprintPass > 5) {
+                         // switch off
+		      COIN_DETAIL_PRINT(printf("Switching off sprint\n"));
+                         primalColumnPivot_->switchOffSprint();
+                    } else {
+                         lastObjectiveValue = objectiveValue() * optimizationDirection_;
+                         // sort
+                         CoinSort_2(weight, weight + numberColumns_, whichColumns);
+                         numberSort = CoinMin(numberColumns_ - numberFixed, numberBasic + numberSprintColumns);
+                         // Sort to make consistent ?
+                         std::sort(whichColumns, whichColumns + numberSort);
+                         saveModel = new ClpSimplex(this, numberSort, whichColumns);
+                         delete [] whichColumns;
+                         delete [] weight;
+                         // Skip factorization
+                         //statusOfProblemInPrimal(lastCleaned,factorType,&progress_,false,saveModel);
+                         //statusOfProblemInPrimal(lastCleaned,factorType,&progress_,true,saveModel);
+                         stopSprint = numberIterations_ + numberSprintIterations;
+                         COIN_DETAIL_PRINT(printf("Sprint with %d columns for %d iterations\n",
+						  numberSprintColumns, numberSprintIterations));
+                    }
+               }
+
+               // Say good factorization
+               factorType = 1;
+
+               // Say no pivot has occurred (for steepest edge and updates)
+               pivotRow_ = -2;
+
+               // exit if victory declared
+	       if (problemStatus_ >= 0) {
+#ifdef CLP_USER_DRIVEN
+		 int status = 
+		   eventHandler_->event(ClpEventHandler::endInPrimal);
+		 if (status>=0&&status<10) {
+		   // carry on
+		   problemStatus_=-1;
+		   if (status==0)
+		     continue; // re-factorize
+		 } else if (status>=10) {
+		   problemStatus_=status-10;
+		   break;
+		 } else {
+		   break;
+		 }
+#else
+		 break;
+#endif
+	       }
+
+               // test for maximum iterations
+               if (hitMaximumIterations() || (ifValuesPass == 2 && firstFree_ < 0)) {
+                    problemStatus_ = 3;
+                    break;
+               }
+
+               if (firstFree_ < 0) {
+                    if (ifValuesPass) {
+                         // end of values pass
+                         ifValuesPass = 0;
+                         int status = eventHandler_->event(ClpEventHandler::endOfValuesPass);
+                         if (status >= 0) {
+                              problemStatus_ = 5;
+                              secondaryStatus_ = ClpEventHandler::endOfValuesPass;
+                              break;
+                         }
+                         //#define FEB_TRY
+#if 1 //def FEB_TRY
+                         if (perturbation_ < 100)
+                              perturb(0);
+#endif
+                    }
+               }
+               // Check event
+               {
+                    int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
+                    if (status >= 0) {
+                         problemStatus_ = 5;
+                         secondaryStatus_ = ClpEventHandler::endOfFactorization;
+                         break;
+                    }
+               }
+               // Iterate
+               whileIterating(ifValuesPass ? 1 : 0);
+          }
+     }
+     // if infeasible get real values
+     //printf("XXXXY final cost %g\n",infeasibilityCost_);
+     progress_.initialWeight_ = 0.0;
+     if (problemStatus_ == 1 && secondaryStatus_ != 6) {
+          infeasibilityCost_ = 0.0;
+          createRim(1 + 4);
+          delete nonLinearCost_;
+          nonLinearCost_ = new ClpNonLinearCost(this);
+          nonLinearCost_->checkInfeasibilities(0.0);
+          sumPrimalInfeasibilities_ = nonLinearCost_->sumInfeasibilities();
+          numberPrimalInfeasibilities_ = nonLinearCost_->numberInfeasibilities();
+          // and get good feasible duals
+          computeDuals(NULL);
+     }
+     // Stop can skip some things in transposeTimes
+     specialOptions_ &= ~131072;
+     // clean up
+     unflag();
+     finish(startFinishOptions);
+     restoreData(data);
+     return problemStatus_;
+}
+/*
+  Reasons to come out:
+  -1 iterations etc
+  -2 inaccuracy
+  -3 slight inaccuracy (and done iterations)
+  -4 end of values pass and done iterations
+  +0 looks optimal (might be infeasible - but we will investigate)
+  +2 looks unbounded
+  +3 max iterations
+*/
+int
+ClpSimplexPrimal::whileIterating(int valuesOption)
+{
+     // Say if values pass
+     int ifValuesPass = (firstFree_ >= 0) ? 1 : 0;
+     int returnCode = -1;
+     int superBasicType = 1;
+     if (valuesOption > 1)
+          superBasicType = 3;
+     // delete any rays
+     delete [] ray_;
+     ray_ = NULL;
+     // status stays at -1 while iterating, >=0 finished, -2 to invert
+     // status -3 to go to top without an invert
+     while (problemStatus_ == -1) {
+          //#define CLP_DEBUG 1
+#ifdef CLP_DEBUG
+          {
+               int i;
+               // not [1] as has information
+               for (i = 0; i < 4; i++) {
+                    if (i != 1)
+                         rowArray_[i]->checkClear();
+               }
+               for (i = 0; i < 2; i++) {
+                    columnArray_[i]->checkClear();
+               }
+          }
+#endif
+#if 0
+          {
+               int iPivot;
+               double * array = rowArray_[3]->denseVector();
+               int * index = rowArray_[3]->getIndices();
+               int i;
+               for (iPivot = 0; iPivot < numberRows_; iPivot++) {
+                    int iSequence = pivotVariable_[iPivot];
+                    unpackPacked(rowArray_[3], iSequence);
+                    factorization_->updateColumn(rowArray_[2], rowArray_[3]);
+                    int number = rowArray_[3]->getNumElements();
+                    for (i = 0; i < number; i++) {
+                         int iRow = index[i];
+                         if (iRow == iPivot)
+                              assert (fabs(array[i] - 1.0) < 1.0e-4);
+                         else
+                              assert (fabs(array[i]) < 1.0e-4);
+                    }
+                    rowArray_[3]->clear();
+               }
+          }
+#endif
+#if 0
+          nonLinearCost_->checkInfeasibilities(primalTolerance_);
+          printf("suminf %g number %d\n", nonLinearCost_->sumInfeasibilities(),
+                 nonLinearCost_->numberInfeasibilities());
+#endif
+#if CLP_DEBUG>2
+          // very expensive
+          if (numberIterations_ > 0 && numberIterations_ < 100 && !ifValuesPass) {
+               handler_->setLogLevel(63);
+               double saveValue = objectiveValue_;
+               double * saveRow1 = new double[numberRows_];
+               double * saveRow2 = new double[numberRows_];
+               CoinMemcpyN(rowReducedCost_, numberRows_, saveRow1);
+               CoinMemcpyN(rowActivityWork_, numberRows_, saveRow2);
+               double * saveColumn1 = new double[numberColumns_];
+               double * saveColumn2 = new double[numberColumns_];
+               CoinMemcpyN(reducedCostWork_, numberColumns_, saveColumn1);
+               CoinMemcpyN(columnActivityWork_, numberColumns_, saveColumn2);
+               gutsOfSolution(NULL, NULL, false);
+               printf("xxx %d old obj %g, recomputed %g, sum primal inf %g\n",
+                      numberIterations_,
+                      saveValue, objectiveValue_, sumPrimalInfeasibilities_);
+               CoinMemcpyN(saveRow1, numberRows_, rowReducedCost_);
+               CoinMemcpyN(saveRow2, numberRows_, rowActivityWork_);
+               CoinMemcpyN(saveColumn1, numberColumns_, reducedCostWork_);
+               CoinMemcpyN(saveColumn2, numberColumns_, columnActivityWork_);
+               delete [] saveRow1;
+               delete [] saveRow2;
+               delete [] saveColumn1;
+               delete [] saveColumn2;
+               objectiveValue_ = saveValue;
+          }
+#endif
+          if (!ifValuesPass) {
+               // choose column to come in
+               // can use pivotRow_ to update weights
+               // pass in list of cost changes so can do row updates (rowArray_[1])
+               // NOTE rowArray_[0] is used by computeDuals which is a
+               // slow way of getting duals but might be used
+               primalColumn(rowArray_[1], rowArray_[2], rowArray_[3],
+                            columnArray_[0], columnArray_[1]);
+          } else {
+               // in values pass
+               int sequenceIn = nextSuperBasic(superBasicType, columnArray_[0]);
+               if (valuesOption > 1)
+                    superBasicType = 2;
+               if (sequenceIn < 0) {
+                    // end of values pass - initialize weights etc
+                    handler_->message(CLP_END_VALUES_PASS, messages_)
+                              << numberIterations_;
+                    primalColumnPivot_->saveWeights(this, 5);
+                    problemStatus_ = -2; // factorize now
+                    pivotRow_ = -1; // say no weights update
+                    returnCode = -4;
+                    // Clean up
+                    int i;
+                    for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                         if (getColumnStatus(i) == atLowerBound || getColumnStatus(i) == isFixed)
+                              solution_[i] = lower_[i];
+                         else if (getColumnStatus(i) == atUpperBound)
+                              solution_[i] = upper_[i];
+                    }
+                    break;
+               } else {
+                    // normal
+                    sequenceIn_ = sequenceIn;
+                    valueIn_ = solution_[sequenceIn_];
+                    lowerIn_ = lower_[sequenceIn_];
+                    upperIn_ = upper_[sequenceIn_];
+                    dualIn_ = dj_[sequenceIn_];
+               }
+          }
+          pivotRow_ = -1;
+          sequenceOut_ = -1;
+          rowArray_[1]->clear();
+          if (sequenceIn_ >= 0) {
+               // we found a pivot column
+               assert (!flagged(sequenceIn_));
+#ifdef CLP_DEBUG
+               if ((handler_->logLevel() & 32)) {
+                    char x = isColumn(sequenceIn_) ? 'C' : 'R';
+                    std::cout << "pivot column " <<
+                              x << sequenceWithin(sequenceIn_) << std::endl;
+               }
+#endif
+#ifdef CLP_DEBUG
+               {
+                    int checkSequence = -2077;
+                    if (checkSequence >= 0 && checkSequence < numberRows_ + numberColumns_ && !ifValuesPass) {
+                         rowArray_[2]->checkClear();
+                         rowArray_[3]->checkClear();
+                         double * array = rowArray_[3]->denseVector();
+                         int * index = rowArray_[3]->getIndices();
+                         unpackPacked(rowArray_[3], checkSequence);
+                         factorization_->updateColumnForDebug(rowArray_[2], rowArray_[3]);
+                         int number = rowArray_[3]->getNumElements();
+                         double dualIn = cost_[checkSequence];
+                         int i;
+                         for (i = 0; i < number; i++) {
+                              int iRow = index[i];
+                              int iPivot = pivotVariable_[iRow];
+                              double alpha = array[i];
+                              dualIn -= alpha * cost_[iPivot];
+                         }
+                         printf("old dj for %d was %g, recomputed %g\n", checkSequence,
+                                dj_[checkSequence], dualIn);
+                         rowArray_[3]->clear();
+                         if (numberIterations_ > 2000)
+                              exit(1);
+                    }
+               }
+#endif
+               // do second half of iteration
+               returnCode = pivotResult(ifValuesPass);
+               if (returnCode < -1 && returnCode > -5) {
+                    problemStatus_ = -2; //
+               } else if (returnCode == -5) {
+                    if ((moreSpecialOptions_ & 16) == 0 && factorization_->pivots()) {
+                         moreSpecialOptions_ |= 16;
+                         problemStatus_ = -2;
+                    }
+                    // otherwise something flagged - continue;
+               } else if (returnCode == 2) {
+                    problemStatus_ = -5; // looks unbounded
+               } else if (returnCode == 4) {
+                    problemStatus_ = -2; // looks unbounded but has iterated
+               } else if (returnCode != -1) {
+                    assert(returnCode == 3);
+                    if (problemStatus_ != 5)
+                         problemStatus_ = 3;
+               }
+          } else {
+               // no pivot column
+#ifdef CLP_DEBUG
+               if (handler_->logLevel() & 32)
+                    printf("** no column pivot\n");
+#endif
+               if (nonLinearCost_->numberInfeasibilities())
+                    problemStatus_ = -4; // might be infeasible
+               // Force to re-factorize early next time
+               int numberPivots = factorization_->pivots();
+	       returnCode = 0;
+#ifdef CLP_USER_DRIVEN
+	       // If large number of pivots trap later?
+	       if (problemStatus_==-1 && numberPivots<1000000) {
+		 int status = eventHandler_->event(ClpEventHandler::noCandidateInPrimal);
+		 if (status>=0&&status<10) {
+		   // carry on
+		   problemStatus_=-1;
+		   if (status==0) 
+		     break;
+		 } else if (status>=10) {
+		     problemStatus_=status-10;
+		     break;
+		 } else {
+		   forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
+		   break;
+		 }
+	       }
+#else
+		   forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
+		   break;
+#endif
+          }
+     }
+     if (valuesOption > 1)
+          columnArray_[0]->setNumElements(0);
+     return returnCode;
+}
+/* Checks if finished.  Updates status */
+void
+ClpSimplexPrimal::statusOfProblemInPrimal(int & lastCleaned, int type,
+          ClpSimplexProgress * progress,
+          bool doFactorization,
+          int ifValuesPass,
+          ClpSimplex * originalModel)
+{
+     int dummy; // for use in generalExpanded
+     int saveFirstFree = firstFree_;
+     // number of pivots done
+     int numberPivots = factorization_->pivots();
+     if (type == 2) {
+          // trouble - restore solution
+          CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+          CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                      numberRows_, rowActivityWork_);
+          CoinMemcpyN(savedSolution_ ,
+                      numberColumns_, columnActivityWork_);
+          // restore extra stuff
+          matrix_->generalExpanded(this, 6, dummy);
+          forceFactorization_ = 1; // a bit drastic but ..
+          pivotRow_ = -1; // say no weights update
+          changeMade_++; // say change made
+     }
+     int saveThreshold = factorization_->sparseThreshold();
+     int tentativeStatus = problemStatus_;
+     int numberThrownOut = 1; // to loop round on bad factorization in values pass
+     double lastSumInfeasibility = COIN_DBL_MAX;
+     if (numberIterations_)
+          lastSumInfeasibility = nonLinearCost_->sumInfeasibilities();
+     int nPass = 0;
+     while (numberThrownOut) {
+          int nSlackBasic = 0;
+          if (nPass) {
+               for (int i = 0; i < numberRows_; i++) {
+                    if (getRowStatus(i) == basic)
+                         nSlackBasic++;
+               }
+          }
+          nPass++;
+          if (problemStatus_ > -3 || problemStatus_ == -4) {
+               // factorize
+               // later on we will need to recover from singularities
+               // also we could skip if first time
+               // do weights
+               // This may save pivotRow_ for use
+               if (doFactorization)
+                    primalColumnPivot_->saveWeights(this, 1);
+
+               if ((type && doFactorization) || nSlackBasic == numberRows_) {
+                    // is factorization okay?
+                    int factorStatus = internalFactorize(1);
+                    if (factorStatus) {
+                         if (solveType_ == 2 + 8) {
+                              // say odd
+                              problemStatus_ = 5;
+                              return;
+                         }
+                         if (type != 1 || largestPrimalError_ > 1.0e3
+                                   || largestDualError_ > 1.0e3) {
+                              // switch off dense
+                              int saveDense = factorization_->denseThreshold();
+                              factorization_->setDenseThreshold(0);
+                              // Go to safe
+                              factorization_->pivotTolerance(0.99);
+                              // make sure will do safe factorization
+                              pivotVariable_[0] = -1;
+                              internalFactorize(2);
+                              factorization_->setDenseThreshold(saveDense);
+                              // restore extra stuff
+                              matrix_->generalExpanded(this, 6, dummy);
+                         } else {
+                              // no - restore previous basis
+                              // Keep any flagged variables
+                              int i;
+                              for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                                   if (flagged(i))
+                                        saveStatus_[i] |= 64; //say flagged
+                              }
+                              CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+                              if (numberPivots <= 1) {
+                                   // throw out something
+                                   if (sequenceIn_ >= 0 && getStatus(sequenceIn_) != basic) {
+                                        setFlagged(sequenceIn_);
+                                   } else if (sequenceOut_ >= 0 && getStatus(sequenceOut_) != basic) {
+                                        setFlagged(sequenceOut_);
+                                   }
+                                   double newTolerance = CoinMax(0.5 + 0.499 * randomNumberGenerator_.randomDouble(), factorization_->pivotTolerance());
+                                   factorization_->pivotTolerance(newTolerance);
+                              } else {
+                                   // Go to safe
+                                   factorization_->pivotTolerance(0.99);
+                              }
+                              CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                                          numberRows_, rowActivityWork_);
+                              CoinMemcpyN(savedSolution_ ,
+                                          numberColumns_, columnActivityWork_);
+                              // restore extra stuff
+                              matrix_->generalExpanded(this, 6, dummy);
+                              matrix_->generalExpanded(this, 5, dummy);
+                              forceFactorization_ = 1; // a bit drastic but ..
+                              type = 2;
+                              if (internalFactorize(2) != 0) {
+                                   largestPrimalError_ = 1.0e4; // force other type
+                              }
+                         }
+                         changeMade_++; // say change made
+                    }
+               }
+               if (problemStatus_ != -4)
+                    problemStatus_ = -3;
+          }
+          // at this stage status is -3 or -5 if looks unbounded
+          // get primal and dual solutions
+          // put back original costs and then check
+          // createRim(4); // costs do not change
+          // May need to do more if column generation
+          dummy = 4;
+          matrix_->generalExpanded(this, 9, dummy);
+#ifndef CLP_CAUTION
+#define CLP_CAUTION 1
+#endif
+#if CLP_CAUTION
+          double lastAverageInfeasibility = sumDualInfeasibilities_ /
+                                            static_cast<double>(numberDualInfeasibilities_ + 10);
+#endif
+#ifdef CLP_USER_DRIVEN
+	  int status = eventHandler_->event(ClpEventHandler::goodFactorization);
+	  if (status >= 0) {
+	    lastSumInfeasibility = COIN_DBL_MAX;
+	  }
+#endif
+          numberThrownOut = gutsOfSolution(NULL, NULL, (firstFree_ >= 0));
+          double sumInfeasibility =  nonLinearCost_->sumInfeasibilities();
+          int reason2 = 0;
+#if CLP_CAUTION
+#if CLP_CAUTION==2
+          double test2 = 1.0e5;
+#else
+          double test2 = 1.0e-1;
+#endif
+          if (!lastSumInfeasibility && sumInfeasibility &&
+                    lastAverageInfeasibility < test2 && numberPivots > 10)
+               reason2 = 3;
+          if (lastSumInfeasibility < 1.0e-6 && sumInfeasibility > 1.0e-3 &&
+                    numberPivots > 10)
+               reason2 = 4;
+#endif
+          if (numberThrownOut)
+               reason2 = 1;
+          if ((sumInfeasibility > 1.0e7 && sumInfeasibility > 100.0 * lastSumInfeasibility
+                    && factorization_->pivotTolerance() < 0.11) ||
+                    (largestPrimalError_ > 1.0e10 && largestDualError_ > 1.0e10))
+               reason2 = 2;
+          if (reason2) {
+               problemStatus_ = tentativeStatus;
+               doFactorization = true;
+               if (numberPivots) {
+                    // go back
+                    // trouble - restore solution
+                    CoinMemcpyN(saveStatus_, numberColumns_ + numberRows_, status_);
+                    CoinMemcpyN(savedSolution_ + numberColumns_ ,
+                                numberRows_, rowActivityWork_);
+                    CoinMemcpyN(savedSolution_ ,
+                                numberColumns_, columnActivityWork_);
+                    // restore extra stuff
+                    matrix_->generalExpanded(this, 6, dummy);
+                    if (reason2 < 3) {
+                         // Go to safe
+                         factorization_->pivotTolerance(CoinMin(0.99, 1.01 * factorization_->pivotTolerance()));
+                         forceFactorization_ = 1; // a bit drastic but ..
+                    } else if (forceFactorization_ < 0) {
+                         forceFactorization_ = CoinMin(numberPivots / 2, 100);
+                    } else {
+                         forceFactorization_ = CoinMin(forceFactorization_,
+                                                       CoinMax(3, numberPivots / 2));
+                    }
+                    pivotRow_ = -1; // say no weights update
+                    changeMade_++; // say change made
+                    if (numberPivots == 1) {
+                         // throw out something
+                         if (sequenceIn_ >= 0 && getStatus(sequenceIn_) != basic) {
+                              setFlagged(sequenceIn_);
+                         } else if (sequenceOut_ >= 0 && getStatus(sequenceOut_) != basic) {
+                              setFlagged(sequenceOut_);
+                         }
+                    }
+                    type = 2; // so will restore weights
+                    if (internalFactorize(2) != 0) {
+                         largestPrimalError_ = 1.0e4; // force other type
+                    }
+                    numberPivots = 0;
+                    numberThrownOut = gutsOfSolution(NULL, NULL, (firstFree_ >= 0));
+                    assert (!numberThrownOut);
+                    sumInfeasibility =  nonLinearCost_->sumInfeasibilities();
+               }
+          }
+     }
+     // Double check reduced costs if no action
+     if (progress->lastIterationNumber(0) == numberIterations_) {
+          if (primalColumnPivot_->looksOptimal()) {
+               numberDualInfeasibilities_ = 0;
+               sumDualInfeasibilities_ = 0.0;
+          }
+     }
+     // If in primal and small dj give up
+     if ((specialOptions_ & 1024) != 0 && !numberPrimalInfeasibilities_ && numberDualInfeasibilities_) {
+          double average = sumDualInfeasibilities_ / (static_cast<double> (numberDualInfeasibilities_));
+          if (numberIterations_ > 300 && average < 1.0e-4) {
+               numberDualInfeasibilities_ = 0;
+               sumDualInfeasibilities_ = 0.0;
+          }
+     }
+     // Check if looping
+     int loop;
+     if (type != 2 && !ifValuesPass)
+          loop = progress->looping();
+     else
+          loop = -1;
+     if (loop >= 0) {
+          if (!problemStatus_) {
+               // declaring victory
+               numberPrimalInfeasibilities_ = 0;
+               sumPrimalInfeasibilities_ = 0.0;
+          } else {
+               problemStatus_ = loop; //exit if in loop
+               problemStatus_ = 10; // instead - try other algorithm
+               numberPrimalInfeasibilities_ = nonLinearCost_->numberInfeasibilities();
+          }
+          problemStatus_ = 10; // instead - try other algorithm
+          return ;
+     } else if (loop < -1) {
+          // Is it time for drastic measures
+          if (nonLinearCost_->numberInfeasibilities() && progress->badTimes() > 5 &&
+                    progress->oddState() < 10 && progress->oddState() >= 0) {
+               progress->newOddState();
+               nonLinearCost_->zapCosts();
+          }
+          // something may have changed
+          gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+     }
+     // If progress then reset costs
+     if (loop == -1 && !nonLinearCost_->numberInfeasibilities() && progress->oddState() < 0) {
+          createRim(4, false); // costs back
+          delete nonLinearCost_;
+          nonLinearCost_ = new ClpNonLinearCost(this);
+          progress->endOddState();
+          gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+     }
+     // Flag to say whether to go to dual to clean up
+     bool goToDual = false;
+     // really for free variables in
+     //if((progressFlag_&2)!=0)
+     //problemStatus_=-1;;
+     progressFlag_ = 0; //reset progress flag
+
+     handler_->message(CLP_SIMPLEX_STATUS, messages_)
+               << numberIterations_ << nonLinearCost_->feasibleReportCost();
+     handler_->printing(nonLinearCost_->numberInfeasibilities() > 0)
+               << nonLinearCost_->sumInfeasibilities() << nonLinearCost_->numberInfeasibilities();
+     handler_->printing(sumDualInfeasibilities_ > 0.0)
+               << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+     handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                        < numberDualInfeasibilities_)
+               << numberDualInfeasibilitiesWithoutFree_;
+     handler_->message() << CoinMessageEol;
+     if (!primalFeasible()) {
+          nonLinearCost_->checkInfeasibilities(primalTolerance_);
+          gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+          nonLinearCost_->checkInfeasibilities(primalTolerance_);
+     }
+     if (nonLinearCost_->numberInfeasibilities() > 0 && !progress->initialWeight_ && !ifValuesPass && infeasibilityCost_ == 1.0e10) {
+          // first time infeasible - start up weight computation
+          double * oldDj = dj_;
+          double * oldCost = cost_;
+          int numberRows2 = numberRows_ + numberExtraRows_;
+          int numberTotal = numberRows2 + numberColumns_;
+          dj_ = new double[numberTotal];
+          cost_ = new double[numberTotal];
+          reducedCostWork_ = dj_;
+          rowReducedCost_ = dj_ + numberColumns_;
+          objectiveWork_ = cost_;
+          rowObjectiveWork_ = cost_ + numberColumns_;
+          double direction = optimizationDirection_ * objectiveScale_;
+          const double * obj = objective();
+          memset(rowObjectiveWork_, 0, numberRows_ * sizeof(double));
+          int iSequence;
+          if (columnScale_)
+               for (iSequence = 0; iSequence < numberColumns_; iSequence++)
+                    cost_[iSequence] = obj[iSequence] * direction * columnScale_[iSequence];
+          else
+               for (iSequence = 0; iSequence < numberColumns_; iSequence++)
+                    cost_[iSequence] = obj[iSequence] * direction;
+          computeDuals(NULL);
+          int numberSame = 0;
+          int numberDifferent = 0;
+          int numberZero = 0;
+          int numberFreeSame = 0;
+          int numberFreeDifferent = 0;
+          int numberFreeZero = 0;
+          int n = 0;
+          for (iSequence = 0; iSequence < numberTotal; iSequence++) {
+               if (getStatus(iSequence) != basic && !flagged(iSequence)) {
+                    // not basic
+                    double distanceUp = upper_[iSequence] - solution_[iSequence];
+                    double distanceDown = solution_[iSequence] - lower_[iSequence];
+                    double feasibleDj = dj_[iSequence];
+                    double infeasibleDj = oldDj[iSequence] - feasibleDj;
+                    double value = feasibleDj * infeasibleDj;
+                    if (distanceUp > primalTolerance_) {
+                         // Check if "free"
+                         if (distanceDown > primalTolerance_) {
+                              // free
+                              if (value > dualTolerance_) {
+                                   numberFreeSame++;
+                              } else if(value < -dualTolerance_) {
+                                   numberFreeDifferent++;
+                                   dj_[n++] = feasibleDj / infeasibleDj;
+                              } else {
+                                   numberFreeZero++;
+                              }
+                         } else {
+                              // should not be negative
+                              if (value > dualTolerance_) {
+                                   numberSame++;
+                              } else if(value < -dualTolerance_) {
+                                   numberDifferent++;
+                                   dj_[n++] = feasibleDj / infeasibleDj;
+                              } else {
+                                   numberZero++;
+                              }
+                         }
+                    } else if (distanceDown > primalTolerance_) {
+                         // should not be positive
+                         if (value > dualTolerance_) {
+                              numberSame++;
+                         } else if(value < -dualTolerance_) {
+                              numberDifferent++;
+                              dj_[n++] = feasibleDj / infeasibleDj;
+                         } else {
+                              numberZero++;
+                         }
+                    }
+               }
+               progress->initialWeight_ = -1.0;
+          }
+          //printf("XXXX %d same, %d different, %d zero, -- free %d %d %d\n",
+          //   numberSame,numberDifferent,numberZero,
+          //   numberFreeSame,numberFreeDifferent,numberFreeZero);
+          // we want most to be same
+          if (n) {
+               double most = 0.95;
+               std::sort(dj_, dj_ + n);
+               int which = static_cast<int> ((1.0 - most) * static_cast<double> (n));
+               double take = -dj_[which] * infeasibilityCost_;
+               //printf("XXXXZ inf cost %g take %g (range %g %g)\n",infeasibilityCost_,take,-dj_[0]*infeasibilityCost_,-dj_[n-1]*infeasibilityCost_);
+               take = -dj_[0] * infeasibilityCost_;
+               infeasibilityCost_ = CoinMin(CoinMax(1000.0 * take, 1.0e8), 1.0000001e10);;
+               //printf("XXXX increasing weight to %g\n",infeasibilityCost_);
+          }
+          delete [] dj_;
+          delete [] cost_;
+          dj_ = oldDj;
+          cost_ = oldCost;
+          reducedCostWork_ = dj_;
+          rowReducedCost_ = dj_ + numberColumns_;
+          objectiveWork_ = cost_;
+          rowObjectiveWork_ = cost_ + numberColumns_;
+          if (n||matrix_->type()>=15)
+               gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+     }
+     double trueInfeasibility = nonLinearCost_->sumInfeasibilities();
+     if (!nonLinearCost_->numberInfeasibilities() && infeasibilityCost_ == 1.0e10 && !ifValuesPass && true) {
+          // relax if default
+          infeasibilityCost_ = CoinMin(CoinMax(100.0 * sumDualInfeasibilities_, 1.0e8), 1.00000001e10);
+          // reset looping criterion
+          progress->reset();
+          trueInfeasibility = 1.123456e10;
+     }
+     if (trueInfeasibility > 1.0) {
+          // If infeasibility going up may change weights
+          double testValue = trueInfeasibility - 1.0e-4 * (10.0 + trueInfeasibility);
+          double lastInf = progress->lastInfeasibility(1);
+          double lastInf3 = progress->lastInfeasibility(3);
+          double thisObj = progress->lastObjective(0);
+          double thisInf = progress->lastInfeasibility(0);
+          thisObj += infeasibilityCost_ * 2.0 * thisInf;
+          double lastObj = progress->lastObjective(1);
+          lastObj += infeasibilityCost_ * 2.0 * lastInf;
+          double lastObj3 = progress->lastObjective(3);
+          lastObj3 += infeasibilityCost_ * 2.0 * lastInf3;
+          if (lastObj < thisObj - 1.0e-5 * CoinMax(fabs(thisObj), fabs(lastObj)) - 1.0e-7
+                    && firstFree_ < 0) {
+               if (handler_->logLevel() == 63)
+                    printf("lastobj %g this %g force %d\n", lastObj, thisObj, forceFactorization_);
+               int maxFactor = factorization_->maximumPivots();
+               if (maxFactor > 10) {
+                    if (forceFactorization_ < 0)
+                         forceFactorization_ = maxFactor;
+                    forceFactorization_ = CoinMax(1, (forceFactorization_ >> 2));
+                    if (handler_->logLevel() == 63)
+                         printf("Reducing factorization frequency to %d\n", forceFactorization_);
+               }
+          } else if (lastObj3 < thisObj - 1.0e-5 * CoinMax(fabs(thisObj), fabs(lastObj3)) - 1.0e-7
+                     && firstFree_ < 0) {
+               if (handler_->logLevel() == 63)
+                    printf("lastobj3 %g this3 %g force %d\n", lastObj3, thisObj, forceFactorization_);
+               int maxFactor = factorization_->maximumPivots();
+               if (maxFactor > 10) {
+                    if (forceFactorization_ < 0)
+                         forceFactorization_ = maxFactor;
+                    forceFactorization_ = CoinMax(1, (forceFactorization_ * 2) / 3);
+                    if (handler_->logLevel() == 63)
+                         printf("Reducing factorization frequency to %d\n", forceFactorization_);
+               }
+          } else if(lastInf < testValue || trueInfeasibility == 1.123456e10) {
+               if (infeasibilityCost_ < 1.0e14) {
+                    infeasibilityCost_ *= 1.5;
+                    // reset looping criterion
+                    progress->reset();
+                    if (handler_->logLevel() == 63)
+                         printf("increasing weight to %g\n", infeasibilityCost_);
+                    gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+               }
+          }
+     }
+     // we may wish to say it is optimal even if infeasible
+     bool alwaysOptimal = (specialOptions_ & 1) != 0;
+     // give code benefit of doubt
+     if (sumOfRelaxedDualInfeasibilities_ == 0.0 &&
+               sumOfRelaxedPrimalInfeasibilities_ == 0.0) {
+          // say optimal (with these bounds etc)
+          numberDualInfeasibilities_ = 0;
+          sumDualInfeasibilities_ = 0.0;
+          numberPrimalInfeasibilities_ = 0;
+          sumPrimalInfeasibilities_ = 0.0;
+          // But check if in sprint
+          if (originalModel) {
+               // Carry on and re-do
+               numberDualInfeasibilities_ = -776;
+          }
+          // But if real primal infeasibilities nonzero carry on
+          if (nonLinearCost_->numberInfeasibilities()) {
+               // most likely to happen if infeasible
+               double relaxedToleranceP = primalTolerance_;
+               // we can't really trust infeasibilities if there is primal error
+               double error = CoinMin(1.0e-2, largestPrimalError_);
+               // allow tolerance at least slightly bigger than standard
+               relaxedToleranceP = relaxedToleranceP +  error;
+               int ninfeas = nonLinearCost_->numberInfeasibilities();
+               double sum = nonLinearCost_->sumInfeasibilities();
+               double average = sum / static_cast<double> (ninfeas);
+#ifdef COIN_DEVELOP
+               if (handler_->logLevel() > 0)
+                    printf("nonLinearCost says infeasible %d summing to %g\n",
+                           ninfeas, sum);
+#endif
+               if (average > relaxedToleranceP) {
+                    sumOfRelaxedPrimalInfeasibilities_ = sum;
+                    numberPrimalInfeasibilities_ = ninfeas;
+                    sumPrimalInfeasibilities_ = sum;
+#ifdef COIN_DEVELOP
+                    bool unflagged =
+#endif
+                         unflag();
+#ifdef COIN_DEVELOP
+                    if (unflagged && handler_->logLevel() > 0)
+                         printf(" - but flagged variables\n");
+#endif
+               }
+          }
+     }
+     // had ||(type==3&&problemStatus_!=-5) -- ??? why ????
+     if ((dualFeasible() || problemStatus_ == -4) && !ifValuesPass) {
+          // see if extra helps
+          if (nonLinearCost_->numberInfeasibilities() &&
+                    (nonLinearCost_->sumInfeasibilities() > 1.0e-3 || sumOfRelaxedPrimalInfeasibilities_)
+                    && !alwaysOptimal) {
+               //may need infeasiblity cost changed
+               // we can see if we can construct a ray
+               // make up a new objective
+               double saveWeight = infeasibilityCost_;
+               // save nonlinear cost as we are going to switch off costs
+               ClpNonLinearCost * nonLinear = nonLinearCost_;
+               // do twice to make sure Primal solution has settled
+               // put non-basics to bounds in case tolerance moved
+               // put back original costs
+               createRim(4);
+               nonLinearCost_->checkInfeasibilities(0.0);
+               gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+
+               infeasibilityCost_ = 1.0e100;
+               // put back original costs
+               createRim(4);
+               nonLinearCost_->checkInfeasibilities(primalTolerance_);
+               // may have fixed infeasibilities - double check
+               if (nonLinearCost_->numberInfeasibilities() == 0) {
+                    // carry on
+                    problemStatus_ = -1;
+                    infeasibilityCost_ = saveWeight;
+                    nonLinearCost_->checkInfeasibilities(primalTolerance_);
+               } else {
+                    nonLinearCost_ = NULL;
+                    // scale
+                    int i;
+                    for (i = 0; i < numberRows_ + numberColumns_; i++)
+                         cost_[i] *= 1.0e-95;
+                    gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+                    nonLinearCost_ = nonLinear;
+                    infeasibilityCost_ = saveWeight;
+                    if ((infeasibilityCost_ >= 1.0e18 ||
+                              numberDualInfeasibilities_ == 0) && perturbation_ == 101) {
+                         goToDual = unPerturb(); // stop any further perturbation
+                         if (nonLinearCost_->sumInfeasibilities() > 1.0e-1)
+			   goToDual = false;
+                         nonLinearCost_->checkInfeasibilities(primalTolerance_);
+                         numberDualInfeasibilities_ = 1; // carry on
+                         problemStatus_ = -1;
+                    } else if (numberDualInfeasibilities_ == 0 && largestDualError_ > 1.0e-2 &&
+                               (moreSpecialOptions_ & (256|8192)) == 0) {
+                         goToDual = true;
+                         factorization_->pivotTolerance(CoinMax(0.9, factorization_->pivotTolerance()));
+                    }
+                    if (!goToDual) {
+                         if (infeasibilityCost_ >= 1.0e20 ||
+                                   numberDualInfeasibilities_ == 0) {
+                              // we are infeasible - use as ray
+                              delete [] ray_;
+                              ray_ = new double [numberRows_];
+			      // swap sign
+			      for (int i=0;i<numberRows_;i++) 
+				ray_[i] = -dual_[i];
+#ifdef PRINT_RAY_METHOD
+			      printf("Primal creating infeasibility ray\n");
+#endif
+                              // and get feasible duals
+                              infeasibilityCost_ = 0.0;
+                              createRim(4);
+                              nonLinearCost_->checkInfeasibilities(primalTolerance_);
+                              gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+                              // so will exit
+                              infeasibilityCost_ = 1.0e30;
+                              // reset infeasibilities
+                              sumPrimalInfeasibilities_ = nonLinearCost_->sumInfeasibilities();;
+                              numberPrimalInfeasibilities_ =
+                                   nonLinearCost_->numberInfeasibilities();
+                         }
+                         if (infeasibilityCost_ < 1.0e20) {
+                              infeasibilityCost_ *= 5.0;
+                              // reset looping criterion
+                              progress->reset();
+                              changeMade_++; // say change made
+                              handler_->message(CLP_PRIMAL_WEIGHT, messages_)
+                                        << infeasibilityCost_
+                                        << CoinMessageEol;
+                              // put back original costs and then check
+                              createRim(4);
+                              nonLinearCost_->checkInfeasibilities(0.0);
+                              gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+                              problemStatus_ = -1; //continue
+                              goToDual = false;
+                         } else {
+                              // say infeasible
+                              problemStatus_ = 1;
+                         }
+                    }
+               }
+          } else {
+               // may be optimal
+               if (perturbation_ == 101) {
+                    goToDual = unPerturb(); // stop any further perturbation
+                    if ((numberRows_ > 20000 || numberDualInfeasibilities_) && !numberTimesOptimal_)
+                         goToDual = false; // Better to carry on a bit longer
+                    lastCleaned = -1; // carry on
+               }
+               bool unflagged = (unflag() != 0);
+               if ( lastCleaned != numberIterations_ || unflagged) {
+                    handler_->message(CLP_PRIMAL_OPTIMAL, messages_)
+                              << primalTolerance_
+                              << CoinMessageEol;
+                    if (numberTimesOptimal_ < 4) {
+                         numberTimesOptimal_++;
+                         changeMade_++; // say change made
+                         if (numberTimesOptimal_ == 1) {
+                              // better to have small tolerance even if slower
+                              factorization_->zeroTolerance(CoinMin(factorization_->zeroTolerance(), 1.0e-15));
+                         }
+                         lastCleaned = numberIterations_;
+                         if (primalTolerance_ != dblParam_[ClpPrimalTolerance])
+                              handler_->message(CLP_PRIMAL_ORIGINAL, messages_)
+                                        << CoinMessageEol;
+                         double oldTolerance = primalTolerance_;
+                         primalTolerance_ = dblParam_[ClpPrimalTolerance];
+#if 0
+                         double * xcost = new double[numberRows_+numberColumns_];
+                         double * xlower = new double[numberRows_+numberColumns_];
+                         double * xupper = new double[numberRows_+numberColumns_];
+                         double * xdj = new double[numberRows_+numberColumns_];
+                         double * xsolution = new double[numberRows_+numberColumns_];
+                         CoinMemcpyN(cost_, (numberRows_ + numberColumns_), xcost);
+                         CoinMemcpyN(lower_, (numberRows_ + numberColumns_), xlower);
+                         CoinMemcpyN(upper_, (numberRows_ + numberColumns_), xupper);
+                         CoinMemcpyN(dj_, (numberRows_ + numberColumns_), xdj);
+                         CoinMemcpyN(solution_, (numberRows_ + numberColumns_), xsolution);
+#endif
+                         // put back original costs and then check
+                         createRim(4);
+                         nonLinearCost_->checkInfeasibilities(oldTolerance);
+#if 0
+                         int i;
+                         for (i = 0; i < numberRows_ + numberColumns_; i++) {
+                              if (cost_[i] != xcost[i])
+                                   printf("** %d old cost %g new %g sol %g\n",
+                                          i, xcost[i], cost_[i], solution_[i]);
+                              if (lower_[i] != xlower[i])
+                                   printf("** %d old lower %g new %g sol %g\n",
+                                          i, xlower[i], lower_[i], solution_[i]);
+                              if (upper_[i] != xupper[i])
+                                   printf("** %d old upper %g new %g sol %g\n",
+                                          i, xupper[i], upper_[i], solution_[i]);
+                              if (dj_[i] != xdj[i])
+                                   printf("** %d old dj %g new %g sol %g\n",
+                                          i, xdj[i], dj_[i], solution_[i]);
+                              if (solution_[i] != xsolution[i])
+                                   printf("** %d old solution %g new %g sol %g\n",
+                                          i, xsolution[i], solution_[i], solution_[i]);
+                         }
+                         delete [] xcost;
+                         delete [] xupper;
+                         delete [] xlower;
+                         delete [] xdj;
+                         delete [] xsolution;
+#endif
+                         gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+                         if (sumOfRelaxedDualInfeasibilities_ == 0.0 &&
+                                   sumOfRelaxedPrimalInfeasibilities_ == 0.0) {
+                              // say optimal (with these bounds etc)
+                              numberDualInfeasibilities_ = 0;
+                              sumDualInfeasibilities_ = 0.0;
+                              numberPrimalInfeasibilities_ = 0;
+                              sumPrimalInfeasibilities_ = 0.0;
+                         }
+                         if (dualFeasible() && !nonLinearCost_->numberInfeasibilities() && lastCleaned >= 0)
+                              problemStatus_ = 0;
+                         else
+                              problemStatus_ = -1;
+                    } else {
+                         problemStatus_ = 0; // optimal
+                         if (lastCleaned < numberIterations_) {
+                              handler_->message(CLP_SIMPLEX_GIVINGUP, messages_)
+                                        << CoinMessageEol;
+                         }
+                    }
+               } else {
+                    if (!alwaysOptimal || !sumOfRelaxedPrimalInfeasibilities_)
+                         problemStatus_ = 0; // optimal
+                    else
+                         problemStatus_ = 1; // infeasible
+               }
+          }
+     } else {
+          // see if looks unbounded
+          if (problemStatus_ == -5) {
+               if (nonLinearCost_->numberInfeasibilities()) {
+                    if (infeasibilityCost_ > 1.0e18 && perturbation_ == 101) {
+                         // back off weight
+                         infeasibilityCost_ = 1.0e13;
+                         // reset looping criterion
+                         progress->reset();
+                         unPerturb(); // stop any further perturbation
+                    }
+                    //we need infeasiblity cost changed
+                    if (infeasibilityCost_ < 1.0e20) {
+                         infeasibilityCost_ *= 5.0;
+                         // reset looping criterion
+                         progress->reset();
+                         changeMade_++; // say change made
+                         handler_->message(CLP_PRIMAL_WEIGHT, messages_)
+                                   << infeasibilityCost_
+                                   << CoinMessageEol;
+                         // put back original costs and then check
+                         createRim(4);
+                         gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+                         problemStatus_ = -1; //continue
+                    } else {
+                         // say infeasible
+                         problemStatus_ = 1;
+                         // we are infeasible - use as ray
+                         delete [] ray_;
+                         ray_ = new double [numberRows_];
+                         CoinMemcpyN(dual_, numberRows_, ray_);
+                    }
+               } else {
+                    // say unbounded
+                    problemStatus_ = 2;
+               }
+          } else {
+               // carry on
+               problemStatus_ = -1;
+               if(type == 3 && !ifValuesPass) {
+                    //bool unflagged =
+                    unflag();
+                    if (sumDualInfeasibilities_ < 1.0e-3 ||
+                              (sumDualInfeasibilities_ / static_cast<double> (numberDualInfeasibilities_)) < 1.0e-5 ||
+                              progress->lastIterationNumber(0) == numberIterations_) {
+                         if (!numberPrimalInfeasibilities_) {
+                              if (numberTimesOptimal_ < 4) {
+                                   numberTimesOptimal_++;
+                                   changeMade_++; // say change made
+                              } else {
+                                   problemStatus_ = 0;
+                                   secondaryStatus_ = 5;
+                              }
+                         }
+                    }
+               }
+          }
+     }
+     if (problemStatus_ == 0) {
+          double objVal = (nonLinearCost_->feasibleCost()
+			+ objective_->nonlinearOffset());
+	  objVal /= (objectiveScale_ * rhsScale_);
+          double tol = 1.0e-10 * CoinMax(fabs(objVal), fabs(objectiveValue_)) + 1.0e-8;
+          if (fabs(objVal - objectiveValue_) > tol) {
+#ifdef COIN_DEVELOP
+               if (handler_->logLevel() > 0)
+                    printf("nonLinearCost has feasible obj of %g, objectiveValue_ is %g\n",
+                           objVal, objectiveValue_);
+#endif
+               objectiveValue_ = objVal;
+          }
+     }
+     // save extra stuff
+     matrix_->generalExpanded(this, 5, dummy);
+     if (type == 0 || type == 1) {
+          if (type != 1 || !saveStatus_) {
+               // create save arrays
+               delete [] saveStatus_;
+               delete [] savedSolution_;
+               saveStatus_ = new unsigned char [numberRows_+numberColumns_];
+               savedSolution_ = new double [numberRows_+numberColumns_];
+          }
+          // save arrays
+          CoinMemcpyN(status_, numberColumns_ + numberRows_, saveStatus_);
+          CoinMemcpyN(rowActivityWork_,
+                      numberRows_, savedSolution_ + numberColumns_);
+          CoinMemcpyN(columnActivityWork_, numberColumns_, savedSolution_);
+     }
+     // see if in Cbc etc
+     bool inCbcOrOther = (specialOptions_ & 0x03000000) != 0;
+     bool disaster = false;
+     if (disasterArea_ && inCbcOrOther && disasterArea_->check()) {
+          disasterArea_->saveInfo();
+          disaster = true;
+     }
+     if (disaster)
+          problemStatus_ = 3;
+     if (problemStatus_ < 0 && !changeMade_) {
+          problemStatus_ = 4; // unknown
+     }
+     lastGoodIteration_ = numberIterations_;
+     if (numberIterations_ > lastBadIteration_ + 100)
+          moreSpecialOptions_ &= ~16; // clear check accuracy flag
+     if ((moreSpecialOptions_ & 256) != 0)
+       goToDual=false;
+     if (goToDual || (numberIterations_ > 1000 && largestPrimalError_ > 1.0e6
+                      && largestDualError_ > 1.0e6)) {
+          problemStatus_ = 10; // try dual
+          // See if second call
+          if ((moreSpecialOptions_ & 256) != 0||nonLinearCost_->sumInfeasibilities()>1.0e2) {
+               numberPrimalInfeasibilities_ = nonLinearCost_->numberInfeasibilities();
+               sumPrimalInfeasibilities_ = nonLinearCost_->sumInfeasibilities();
+               // say infeasible
+               if (numberPrimalInfeasibilities_)
+                    problemStatus_ = 1;
+          }
+     }
+     // make sure first free monotonic
+     if (firstFree_ >= 0 && saveFirstFree >= 0) {
+          firstFree_ = (numberIterations_) ? saveFirstFree : -1;
+          nextSuperBasic(1, NULL);
+     }
+     if (doFactorization) {
+          // restore weights (if saved) - also recompute infeasibility list
+          if (tentativeStatus > -3)
+               primalColumnPivot_->saveWeights(this, (type < 2) ? 2 : 4);
+          else
+               primalColumnPivot_->saveWeights(this, 3);
+          if (saveThreshold) {
+               // use default at present
+               factorization_->sparseThreshold(0);
+               factorization_->goSparse();
+          }
+     }
+     // Allow matrices to be sorted etc
+     int fake = -999; // signal sort
+     matrix_->correctSequence(this, fake, fake);
+}
+/*
+   Row array has pivot column
+   This chooses pivot row.
+   For speed, we may need to go to a bucket approach when many
+   variables go through bounds
+   On exit rhsArray will have changes in costs of basic variables
+*/
+void
+ClpSimplexPrimal::primalRow(CoinIndexedVector * rowArray,
+                            CoinIndexedVector * rhsArray,
+                            CoinIndexedVector * spareArray,
+                            int valuesPass)
+{
+     double saveDj = dualIn_;
+     if (valuesPass && objective_->type() < 2) {
+          dualIn_ = cost_[sequenceIn_];
+
+          double * work = rowArray->denseVector();
+          int number = rowArray->getNumElements();
+          int * which = rowArray->getIndices();
+
+          int iIndex;
+          for (iIndex = 0; iIndex < number; iIndex++) {
+
+               int iRow = which[iIndex];
+               double alpha = work[iIndex];
+               int iPivot = pivotVariable_[iRow];
+               dualIn_ -= alpha * cost_[iPivot];
+          }
+          // determine direction here
+          if (dualIn_ < -dualTolerance_) {
+               directionIn_ = 1;
+          } else if (dualIn_ > dualTolerance_) {
+               directionIn_ = -1;
+          } else {
+               // towards nearest bound
+               if (valueIn_ - lowerIn_ < upperIn_ - valueIn_) {
+                    directionIn_ = -1;
+                    dualIn_ = dualTolerance_;
+               } else {
+                    directionIn_ = 1;
+                    dualIn_ = -dualTolerance_;
+               }
+          }
+     }
+
+     // sequence stays as row number until end
+     pivotRow_ = -1;
+     int numberRemaining = 0;
+
+     double totalThru = 0.0; // for when variables flip
+     // Allow first few iterations to take tiny
+     double acceptablePivot = 1.0e-1 * acceptablePivot_;
+     if (numberIterations_ > 100)
+          acceptablePivot = acceptablePivot_;
+     if (factorization_->pivots() > 10)
+          acceptablePivot = 1.0e+3 * acceptablePivot_; // if we have iterated be more strict
+     else if (factorization_->pivots() > 5)
+          acceptablePivot = 1.0e+2 * acceptablePivot_; // if we have iterated be slightly more strict
+     else if (factorization_->pivots())
+          acceptablePivot = acceptablePivot_; // relax
+     double bestEverPivot = acceptablePivot;
+     int lastPivotRow = -1;
+     double lastPivot = 0.0;
+     double lastTheta = 1.0e50;
+
+     // use spareArrays to put ones looked at in
+     // First one is list of candidates
+     // We could compress if we really know we won't need any more
+     // Second array has current set of pivot candidates
+     // with a backup list saved in double * part of indexed vector
+
+     // pivot elements
+     double * spare;
+     // indices
+     int * index;
+     spareArray->clear();
+     spare = spareArray->denseVector();
+     index = spareArray->getIndices();
+
+     // we also need somewhere for effective rhs
+     double * rhs = rhsArray->denseVector();
+     // and we can use indices to point to alpha
+     // that way we can store fabs(alpha)
+     int * indexPoint = rhsArray->getIndices();
+     //int numberFlip=0; // Those which may change if flips
+
+     /*
+       First we get a list of possible pivots.  We can also see if the
+       problem looks unbounded.
+
+       At first we increase theta and see what happens.  We start
+       theta at a reasonable guess.  If in right area then we do bit by bit.
+       We save possible pivot candidates
+
+      */
+
+     // do first pass to get possibles
+     // We can also see if unbounded
+
+     double * work = rowArray->denseVector();
+     int number = rowArray->getNumElements();
+     int * which = rowArray->getIndices();
+
+     // we need to swap sign if coming in from ub
+     double way = directionIn_;
+     double maximumMovement;
+     if (way > 0.0)
+          maximumMovement = CoinMin(1.0e30, upperIn_ - valueIn_);
+     else
+          maximumMovement = CoinMin(1.0e30, valueIn_ - lowerIn_);
+
+     double averageTheta = nonLinearCost_->averageTheta();
+     double tentativeTheta = CoinMin(10.0 * averageTheta, maximumMovement);
+     double upperTheta = maximumMovement;
+     if (tentativeTheta > 0.5 * maximumMovement)
+          tentativeTheta = maximumMovement;
+     bool thetaAtMaximum = tentativeTheta == maximumMovement;
+     // In case tiny bounds increase
+     if (maximumMovement < 1.0)
+          tentativeTheta *= 1.1;
+     double dualCheck = fabs(dualIn_);
+     // but make a bit more pessimistic
+     dualCheck = CoinMax(dualCheck - 100.0 * dualTolerance_, 0.99 * dualCheck);
+
+     int iIndex;
+     int pivotOne = -1;
+     //#define CLP_DEBUG
+#ifdef CLP_DEBUG
+     if (numberIterations_ == -3839 || numberIterations_ == -3840) {
+          double dj = cost_[sequenceIn_];
+          printf("cost in on %d is %g, dual in %g\n", sequenceIn_, dj, dualIn_);
+          for (iIndex = 0; iIndex < number; iIndex++) {
+
+               int iRow = which[iIndex];
+               double alpha = work[iIndex];
+               int iPivot = pivotVariable_[iRow];
+               dj -= alpha * cost_[iPivot];
+               printf("row %d var %d current %g %g %g, alpha %g so sol => %g (cost %g, dj %g)\n",
+                      iRow, iPivot, lower_[iPivot], solution_[iPivot], upper_[iPivot],
+                      alpha, solution_[iPivot] - 1.0e9 * alpha, cost_[iPivot], dj);
+          }
+     }
+#endif
+     while (true) {
+          pivotOne = -1;
+          totalThru = 0.0;
+          // We also re-compute reduced cost
+          numberRemaining = 0;
+          dualIn_ = cost_[sequenceIn_];
+#ifndef NDEBUG
+          //double tolerance = primalTolerance_ * 1.002;
+#endif
+          for (iIndex = 0; iIndex < number; iIndex++) {
+
+               int iRow = which[iIndex];
+               double alpha = work[iIndex];
+               int iPivot = pivotVariable_[iRow];
+               if (cost_[iPivot])
+                    dualIn_ -= alpha * cost_[iPivot];
+               alpha *= way;
+               double oldValue = solution_[iPivot];
+               // get where in bound sequence
+               // note that after this alpha is actually fabs(alpha)
+               bool possible;
+               // do computation same way as later on in primal
+               if (alpha > 0.0) {
+                    // basic variable going towards lower bound
+                    double bound = lower_[iPivot];
+                    // must be exactly same as when used
+                    double change = tentativeTheta * alpha;
+                    possible = (oldValue - change) <= bound + primalTolerance_;
+                    oldValue -= bound;
+               } else {
+                    // basic variable going towards upper bound
+                    double bound = upper_[iPivot];
+                    // must be exactly same as when used
+                    double change = tentativeTheta * alpha;
+                    possible = (oldValue - change) >= bound - primalTolerance_;
+                    oldValue = bound - oldValue;
+                    alpha = - alpha;
+               }
+               double value;
+               //assert (oldValue >= -10.0*tolerance);
+               if (possible) {
+                    value = oldValue - upperTheta * alpha;
+#ifdef CLP_USER_DRIVEN1
+		    if(!userChoiceValid1(this,iPivot,oldValue,
+					 upperTheta,alpha,work[iIndex]*way))
+		      value =0.0; // say can't use
+#endif
+                    if (value < -primalTolerance_ && alpha >= acceptablePivot) {
+                         upperTheta = (oldValue + primalTolerance_) / alpha;
+                         pivotOne = numberRemaining;
+                    }
+                    // add to list
+                    spare[numberRemaining] = alpha;
+                    rhs[numberRemaining] = oldValue;
+                    indexPoint[numberRemaining] = iIndex;
+                    index[numberRemaining++] = iRow;
+                    totalThru += alpha;
+                    setActive(iRow);
+                    //} else if (value<primalTolerance_*1.002) {
+                    // May change if is a flip
+                    //indexRhs[numberFlip++]=iRow;
+               }
+          }
+          if (upperTheta < maximumMovement && totalThru*infeasibilityCost_ >= 1.0001 * dualCheck) {
+               // Can pivot here
+               break;
+          } else if (!thetaAtMaximum) {
+               //printf("Going round with average theta of %g\n",averageTheta);
+               tentativeTheta = maximumMovement;
+               thetaAtMaximum = true; // seems to be odd compiler error
+          } else {
+               break;
+          }
+     }
+     totalThru = 0.0;
+
+     theta_ = maximumMovement;
+
+     bool goBackOne = false;
+     if (objective_->type() > 1)
+          dualIn_ = saveDj;
+
+     //printf("%d remain out of %d\n",numberRemaining,number);
+     int iTry = 0;
+#define MAXTRY 1000
+     if (numberRemaining && upperTheta < maximumMovement) {
+          // First check if previously chosen one will work
+          if (pivotOne >= 0 && 0) {
+               double thruCost = infeasibilityCost_ * spare[pivotOne];
+               if (thruCost >= 0.99 * fabs(dualIn_))
+                    COIN_DETAIL_PRINT(printf("Could pivot on %d as change %g dj %g\n",
+					     index[pivotOne], thruCost, dualIn_));
+               double alpha = spare[pivotOne];
+               double oldValue = rhs[pivotOne];
+               theta_ = oldValue / alpha;
+               pivotRow_ = pivotOne;
+               // Stop loop
+               iTry = MAXTRY;
+          }
+
+          // first get ratio with tolerance
+          for ( ; iTry < MAXTRY; iTry++) {
+
+               upperTheta = maximumMovement;
+               int iBest = -1;
+               for (iIndex = 0; iIndex < numberRemaining; iIndex++) {
+
+                    double alpha = spare[iIndex];
+                    double oldValue = rhs[iIndex];
+                    double value = oldValue - upperTheta * alpha;
+
+#ifdef CLP_USER_DRIVEN1
+		    int sequenceOut=pivotVariable_[index[iIndex]];
+		    if(!userChoiceValid1(this,sequenceOut,oldValue,
+					 upperTheta,alpha, 0.0))
+		      value =0.0; // say can't use
+#endif
+                    if (value < -primalTolerance_ && alpha >= acceptablePivot) {
+                         upperTheta = (oldValue + primalTolerance_) / alpha;
+                         iBest = iIndex; // just in case weird numbers
+                    }
+               }
+
+               // now look at best in this lot
+               // But also see how infeasible small pivots will make
+               double sumInfeasibilities = 0.0;
+               double bestPivot = acceptablePivot;
+               pivotRow_ = -1;
+               for (iIndex = 0; iIndex < numberRemaining; iIndex++) {
+
+                    int iRow = index[iIndex];
+                    double alpha = spare[iIndex];
+                    double oldValue = rhs[iIndex];
+                    double value = oldValue - upperTheta * alpha;
+
+                    if (value <= 0 || iBest == iIndex) {
+                         // how much would it cost to go thru and modify bound
+                         double trueAlpha = way * work[indexPoint[iIndex]];
+                         totalThru += nonLinearCost_->changeInCost(pivotVariable_[iRow], trueAlpha, rhs[iIndex]);
+                         setActive(iRow);
+                         if (alpha > bestPivot) {
+                              bestPivot = alpha;
+                              theta_ = oldValue / bestPivot;
+                              pivotRow_ = iIndex;
+                         } else if (alpha < acceptablePivot
+#ifdef CLP_USER_DRIVEN1
+		      ||!userChoiceValid1(this,pivotVariable_[index[iIndex]],
+					  oldValue,upperTheta,alpha,0.0)
+#endif
+				    ) {
+                              if (value < -primalTolerance_)
+                                   sumInfeasibilities += -value - primalTolerance_;
+                         }
+                    }
+               }
+               if (bestPivot < 0.1 * bestEverPivot &&
+                         bestEverPivot > 1.0e-6 && bestPivot < 1.0e-3) {
+                    // back to previous one
+                    goBackOne = true;
+                    break;
+               } else if (pivotRow_ == -1 && upperTheta > largeValue_) {
+                    if (lastPivot > acceptablePivot) {
+                         // back to previous one
+                         goBackOne = true;
+                    } else {
+                         // can only get here if all pivots so far too small
+                    }
+                    break;
+               } else if (totalThru >= dualCheck) {
+                    if (sumInfeasibilities > primalTolerance_ && !nonLinearCost_->numberInfeasibilities()) {
+                         // Looks a bad choice
+                         if (lastPivot > acceptablePivot) {
+                              goBackOne = true;
+                         } else {
+                              // say no good
+                              dualIn_ = 0.0;
+                         }
+                    }
+                    break; // no point trying another loop
+               } else {
+                    lastPivotRow = pivotRow_;
+                    lastTheta = theta_;
+                    if (bestPivot > bestEverPivot)
+                         bestEverPivot = bestPivot;
+               }
+          }
+          // can get here without pivotRow_ set but with lastPivotRow
+          if (goBackOne || (pivotRow_ < 0 && lastPivotRow >= 0)) {
+               // back to previous one
+               pivotRow_ = lastPivotRow;
+               theta_ = lastTheta;
+          }
+     } else if (pivotRow_ < 0 && maximumMovement > 1.0e20) {
+          // looks unbounded
+          valueOut_ = COIN_DBL_MAX; // say odd
+          if (nonLinearCost_->numberInfeasibilities()) {
+               // but infeasible??
+               // move variable but don't pivot
+               tentativeTheta = 1.0e50;
+               for (iIndex = 0; iIndex < number; iIndex++) {
+                    int iRow = which[iIndex];
+                    double alpha = work[iIndex];
+                    int iPivot = pivotVariable_[iRow];
+                    alpha *= way;
+                    double oldValue = solution_[iPivot];
+                    // get where in bound sequence
+                    // note that after this alpha is actually fabs(alpha)
+                    if (alpha > 0.0) {
+                         // basic variable going towards lower bound
+                         double bound = lower_[iPivot];
+                         oldValue -= bound;
+                    } else {
+                         // basic variable going towards upper bound
+                         double bound = upper_[iPivot];
+                         oldValue = bound - oldValue;
+                         alpha = - alpha;
+                    }
+                    if (oldValue - tentativeTheta * alpha < 0.0) {
+                         tentativeTheta = oldValue / alpha;
+                    }
+               }
+               // If free in then see if we can get to 0.0
+               if (lowerIn_ < -1.0e20 && upperIn_ > 1.0e20) {
+                    if (dualIn_ * valueIn_ > 0.0) {
+                         if (fabs(valueIn_) < 1.0e-2 && (tentativeTheta < fabs(valueIn_) || tentativeTheta > 1.0e20)) {
+                              tentativeTheta = fabs(valueIn_);
+                         }
+                    }
+               }
+               if (tentativeTheta < 1.0e10)
+                    valueOut_ = valueIn_ + way * tentativeTheta;
+          }
+     }
+     //if (iTry>50)
+     //printf("** %d tries\n",iTry);
+     if (pivotRow_ >= 0) {
+          int position = pivotRow_; // position in list
+          pivotRow_ = index[position];
+          alpha_ = work[indexPoint[position]];
+          // translate to sequence
+          sequenceOut_ = pivotVariable_[pivotRow_];
+          valueOut_ = solution(sequenceOut_);
+          lowerOut_ = lower_[sequenceOut_];
+          upperOut_ = upper_[sequenceOut_];
+#define MINIMUMTHETA 1.0e-12
+          // Movement should be minimum for anti-degeneracy - unless
+          // fixed variable out
+          double minimumTheta;
+          if (upperOut_ > lowerOut_)
+               minimumTheta = MINIMUMTHETA;
+          else
+               minimumTheta = 0.0;
+          // But can't go infeasible
+          double distance;
+          if (alpha_ * way > 0.0)
+               distance = valueOut_ - lowerOut_;
+          else
+               distance = upperOut_ - valueOut_;
+          if (distance - minimumTheta * fabs(alpha_) < -primalTolerance_)
+               minimumTheta = CoinMax(0.0, (distance + 0.5 * primalTolerance_) / fabs(alpha_));
+          // will we need to increase tolerance
+          //#define CLP_DEBUG
+          double largestInfeasibility = primalTolerance_;
+          if (theta_ < minimumTheta && (specialOptions_ & 4) == 0 && !valuesPass) {
+               theta_ = minimumTheta;
+               for (iIndex = 0; iIndex < numberRemaining - numberRemaining; iIndex++) {
+                    largestInfeasibility = CoinMax(largestInfeasibility,
+                                                   -(rhs[iIndex] - spare[iIndex] * theta_));
+               }
+//#define CLP_DEBUG
+#ifdef CLP_DEBUG
+               if (largestInfeasibility > primalTolerance_ && (handler_->logLevel() & 32) > -1)
+                    printf("Primal tolerance increased from %g to %g\n",
+                           primalTolerance_, largestInfeasibility);
+#endif
+//#undef CLP_DEBUG
+               primalTolerance_ = CoinMax(primalTolerance_, largestInfeasibility);
+          }
+          // Need to look at all in some cases
+          if (theta_ > tentativeTheta) {
+               for (iIndex = 0; iIndex < number; iIndex++)
+                    setActive(which[iIndex]);
+          }
+          if (way < 0.0)
+               theta_ = - theta_;
+          double newValue = valueOut_ - theta_ * alpha_;
+          // If  4 bit set - Force outgoing variables to exact bound (primal)
+          if (alpha_ * way < 0.0) {
+               directionOut_ = -1;    // to upper bound
+               if (fabs(theta_) > 1.0e-6 || (specialOptions_ & 4) != 0) {
+                    upperOut_ = nonLinearCost_->nearest(sequenceOut_, newValue);
+               } else {
+                    upperOut_ = newValue;
+               }
+          } else {
+               directionOut_ = 1;    // to lower bound
+               if (fabs(theta_) > 1.0e-6 || (specialOptions_ & 4) != 0) {
+                    lowerOut_ = nonLinearCost_->nearest(sequenceOut_, newValue);
+               } else {
+                    lowerOut_ = newValue;
+               }
+          }
+          dualOut_ = reducedCost(sequenceOut_);
+     } else if (maximumMovement < 1.0e20) {
+          // flip
+          pivotRow_ = -2; // so we can tell its a flip
+          sequenceOut_ = sequenceIn_;
+          valueOut_ = valueIn_;
+          dualOut_ = dualIn_;
+          lowerOut_ = lowerIn_;
+          upperOut_ = upperIn_;
+          alpha_ = 0.0;
+          if (way < 0.0) {
+               directionOut_ = 1;    // to lower bound
+               theta_ = lowerOut_ - valueOut_;
+          } else {
+               directionOut_ = -1;    // to upper bound
+               theta_ = upperOut_ - valueOut_;
+          }
+     }
+
+     double theta1 = CoinMax(theta_, 1.0e-12);
+     double theta2 = numberIterations_ * nonLinearCost_->averageTheta();
+     // Set average theta
+     nonLinearCost_->setAverageTheta((theta1 + theta2) / (static_cast<double> (numberIterations_ + 1)));
+     //if (numberIterations_%1000==0)
+     //printf("average theta is %g\n",nonLinearCost_->averageTheta());
+
+     // clear arrays
+
+     CoinZeroN(spare, numberRemaining);
+
+     // put back original bounds etc
+     CoinMemcpyN(index, numberRemaining, rhsArray->getIndices());
+     rhsArray->setNumElements(numberRemaining);
+     rhsArray->setPacked();
+     nonLinearCost_->goBackAll(rhsArray);
+     rhsArray->clear();
+
+}
+/*
+   Chooses primal pivot column
+   updateArray has cost updates (also use pivotRow_ from last iteration)
+   Would be faster with separate region to scan
+   and will have this (with square of infeasibility) when steepest
+   For easy problems we can just choose one of the first columns we look at
+*/
+void
+ClpSimplexPrimal::primalColumn(CoinIndexedVector * updates,
+                               CoinIndexedVector * spareRow1,
+                               CoinIndexedVector * spareRow2,
+                               CoinIndexedVector * spareColumn1,
+                               CoinIndexedVector * spareColumn2)
+{
+
+     ClpMatrixBase * saveMatrix = matrix_;
+     double * saveRowScale = rowScale_;
+     if (scaledMatrix_) {
+          rowScale_ = NULL;
+          matrix_ = scaledMatrix_;
+     }
+     sequenceIn_ = primalColumnPivot_->pivotColumn(updates, spareRow1,
+                   spareRow2, spareColumn1,
+                   spareColumn2);
+     if (scaledMatrix_) {
+          matrix_ = saveMatrix;
+          rowScale_ = saveRowScale;
+     }
+     if (sequenceIn_ >= 0) {
+          valueIn_ = solution_[sequenceIn_];
+          dualIn_ = dj_[sequenceIn_];
+          if (nonLinearCost_->lookBothWays()) {
+               // double check
+               ClpSimplex::Status status = getStatus(sequenceIn_);
+
+               switch(status) {
+               case ClpSimplex::atUpperBound:
+                    if (dualIn_ < 0.0) {
+                         // move to other side
+                         COIN_DETAIL_PRINT(printf("For %d U (%g, %g, %g) dj changed from %g",
+                                sequenceIn_, lower_[sequenceIn_], solution_[sequenceIn_],
+						  upper_[sequenceIn_], dualIn_));
+                         dualIn_ -= nonLinearCost_->changeUpInCost(sequenceIn_);
+                         COIN_DETAIL_PRINT(printf(" to %g\n", dualIn_));
+                         nonLinearCost_->setOne(sequenceIn_, upper_[sequenceIn_] + 2.0 * currentPrimalTolerance());
+                         setStatus(sequenceIn_, ClpSimplex::atLowerBound);
+                    }
+                    break;
+               case ClpSimplex::atLowerBound:
+                    if (dualIn_ > 0.0) {
+                         // move to other side
+                         COIN_DETAIL_PRINT(printf("For %d L (%g, %g, %g) dj changed from %g",
+                                sequenceIn_, lower_[sequenceIn_], solution_[sequenceIn_],
+						  upper_[sequenceIn_], dualIn_));
+                         dualIn_ -= nonLinearCost_->changeDownInCost(sequenceIn_);
+                         COIN_DETAIL_PRINT(printf(" to %g\n", dualIn_));
+                         nonLinearCost_->setOne(sequenceIn_, lower_[sequenceIn_] - 2.0 * currentPrimalTolerance());
+                         setStatus(sequenceIn_, ClpSimplex::atUpperBound);
+                    }
+                    break;
+               default:
+                    break;
+               }
+          }
+          lowerIn_ = lower_[sequenceIn_];
+          upperIn_ = upper_[sequenceIn_];
+          if (dualIn_ > 0.0)
+               directionIn_ = -1;
+          else
+               directionIn_ = 1;
+     } else {
+          sequenceIn_ = -1;
+     }
+}
+/* The primals are updated by the given array.
+   Returns number of infeasibilities.
+   After rowArray will have list of cost changes
+*/
+int
+ClpSimplexPrimal::updatePrimalsInPrimal(CoinIndexedVector * rowArray,
+                                        double theta,
+                                        double & objectiveChange,
+                                        int valuesPass)
+{
+     // Cost on pivot row may change - may need to change dualIn
+     double oldCost = 0.0;
+     if (pivotRow_ >= 0)
+          oldCost = cost_[sequenceOut_];
+     //rowArray->scanAndPack();
+     double * work = rowArray->denseVector();
+     int number = rowArray->getNumElements();
+     int * which = rowArray->getIndices();
+
+     int newNumber = 0;
+     int pivotPosition = -1;
+     nonLinearCost_->setChangeInCost(0.0);
+     //printf("XX 4138 sol %g lower %g upper %g cost %g status %d\n",
+     //   solution_[4138],lower_[4138],upper_[4138],cost_[4138],status_[4138]);
+     // allow for case where bound+tolerance == bound
+     //double tolerance = 0.999999*primalTolerance_;
+     double relaxedTolerance = 1.001 * primalTolerance_;
+     int iIndex;
+     if (!valuesPass) {
+          for (iIndex = 0; iIndex < number; iIndex++) {
+
+               int iRow = which[iIndex];
+               double alpha = work[iIndex];
+               work[iIndex] = 0.0;
+               int iPivot = pivotVariable_[iRow];
+               double change = theta * alpha;
+               double value = solution_[iPivot] - change;
+               solution_[iPivot] = value;
+#ifndef NDEBUG
+               // check if not active then okay
+               if (!active(iRow) && (specialOptions_ & 4) == 0 && pivotRow_ != -1) {
+                    // But make sure one going out is feasible
+                    if (change > 0.0) {
+                         // going down
+                         if (value <= lower_[iPivot] + primalTolerance_) {
+                              if (iPivot == sequenceOut_ && value > lower_[iPivot] - relaxedTolerance)
+                                   value = lower_[iPivot];
+                              //double difference = nonLinearCost_->setOne(iPivot, value);
+                              //assert (!difference || fabs(change) > 1.0e9);
+                         }
+                    } else {
+                         // going up
+                         if (value >= upper_[iPivot] - primalTolerance_) {
+                              if (iPivot == sequenceOut_ && value < upper_[iPivot] + relaxedTolerance)
+                                   value = upper_[iPivot];
+                              //double difference = nonLinearCost_->setOne(iPivot, value);
+                              //assert (!difference || fabs(change) > 1.0e9);
+                         }
+                    }
+               }
+#endif
+               if (active(iRow) || theta_ < 0.0) {
+                    clearActive(iRow);
+                    // But make sure one going out is feasible
+                    if (change > 0.0) {
+                         // going down
+                         if (value <= lower_[iPivot] + primalTolerance_) {
+                              if (iPivot == sequenceOut_ && value >= lower_[iPivot] - relaxedTolerance)
+                                   value = lower_[iPivot];
+                              double difference = nonLinearCost_->setOne(iPivot, value);
+                              if (difference) {
+                                   if (iRow == pivotRow_)
+                                        pivotPosition = newNumber;
+                                   work[newNumber] = difference;
+                                   //change reduced cost on this
+                                   dj_[iPivot] = -difference;
+                                   which[newNumber++] = iRow;
+                              }
+                         }
+                    } else {
+                         // going up
+                         if (value >= upper_[iPivot] - primalTolerance_) {
+                              if (iPivot == sequenceOut_ && value < upper_[iPivot] + relaxedTolerance)
+                                   value = upper_[iPivot];
+                              double difference = nonLinearCost_->setOne(iPivot, value);
+                              if (difference) {
+                                   if (iRow == pivotRow_)
+                                        pivotPosition = newNumber;
+                                   work[newNumber] = difference;
+                                   //change reduced cost on this
+                                   dj_[iPivot] = -difference;
+                                   which[newNumber++] = iRow;
+                              }
+                         }
+                    }
+               }
+          }
+     } else {
+          // values pass so look at all
+          for (iIndex = 0; iIndex < number; iIndex++) {
+
+               int iRow = which[iIndex];
+               double alpha = work[iIndex];
+               work[iIndex] = 0.0;
+               int iPivot = pivotVariable_[iRow];
+               double change = theta * alpha;
+               double value = solution_[iPivot] - change;
+               solution_[iPivot] = value;
+               clearActive(iRow);
+               // But make sure one going out is feasible
+               if (change > 0.0) {
+                    // going down
+                    if (value <= lower_[iPivot] + primalTolerance_) {
+                         if (iPivot == sequenceOut_ && value > lower_[iPivot] - relaxedTolerance)
+                              value = lower_[iPivot];
+                         double difference = nonLinearCost_->setOne(iPivot, value);
+                         if (difference) {
+                              if (iRow == pivotRow_)
+                                   pivotPosition = newNumber;
+                              work[newNumber] = difference;
+                              //change reduced cost on this
+                              dj_[iPivot] = -difference;
+                              which[newNumber++] = iRow;
+                         }
+                    }
+               } else {
+                    // going up
+                    if (value >= upper_[iPivot] - primalTolerance_) {
+                         if (iPivot == sequenceOut_ && value < upper_[iPivot] + relaxedTolerance)
+                              value = upper_[iPivot];
+                         double difference = nonLinearCost_->setOne(iPivot, value);
+                         if (difference) {
+                              if (iRow == pivotRow_)
+                                   pivotPosition = newNumber;
+                              work[newNumber] = difference;
+                              //change reduced cost on this
+                              dj_[iPivot] = -difference;
+                              which[newNumber++] = iRow;
+                         }
+                    }
+               }
+          }
+     }
+     objectiveChange += nonLinearCost_->changeInCost();
+     rowArray->setPacked();
+#if 0
+     rowArray->setNumElements(newNumber);
+     rowArray->expand();
+     if (pivotRow_ >= 0) {
+          dualIn_ += (oldCost - cost_[sequenceOut_]);
+          // update change vector to include pivot
+          rowArray->add(pivotRow_, -dualIn_);
+          // and convert to packed
+          rowArray->scanAndPack();
+     } else {
+          // and convert to packed
+          rowArray->scanAndPack();
+     }
+#else
+     if (pivotRow_ >= 0) {
+          double dualIn = dualIn_ + (oldCost - cost_[sequenceOut_]);
+          // update change vector to include pivot
+          if (pivotPosition >= 0) {
+               work[pivotPosition] -= dualIn;
+          } else {
+               work[newNumber] = -dualIn;
+               which[newNumber++] = pivotRow_;
+          }
+     }
+     rowArray->setNumElements(newNumber);
+#endif
+     return 0;
+}
+// Perturbs problem
+void
+ClpSimplexPrimal::perturb(int type)
+{
+     if (perturbation_ > 100)
+          return; //perturbed already
+     if (perturbation_ == 100)
+          perturbation_ = 50; // treat as normal
+     int savePerturbation = perturbation_;
+     int i;
+     if (!numberIterations_)
+          cleanStatus(); // make sure status okay
+     // Make sure feasible bounds
+     if (nonLinearCost_) {
+       nonLinearCost_->checkInfeasibilities();
+       //nonLinearCost_->feasibleBounds();
+     }
+     // look at element range
+     double smallestNegative;
+     double largestNegative;
+     double smallestPositive;
+     double largestPositive;
+     matrix_->rangeOfElements(smallestNegative, largestNegative,
+                              smallestPositive, largestPositive);
+     smallestPositive = CoinMin(fabs(smallestNegative), smallestPositive);
+     largestPositive = CoinMax(fabs(largestNegative), largestPositive);
+     double elementRatio = largestPositive / smallestPositive;
+     if (!numberIterations_ && perturbation_ == 50) {
+          // See if we need to perturb
+          int numberTotal = CoinMax(numberRows_, numberColumns_);
+          double * sort = new double[numberTotal];
+          int nFixed = 0;
+          for (i = 0; i < numberRows_; i++) {
+               double lo = fabs(rowLower_[i]);
+               double up = fabs(rowUpper_[i]);
+               double value = 0.0;
+               if (lo && lo < 1.0e20) {
+                    if (up && up < 1.0e20) {
+                         value = 0.5 * (lo + up);
+                         if (lo == up)
+                              nFixed++;
+                    } else {
+                         value = lo;
+                    }
+               } else {
+                    if (up && up < 1.0e20)
+                         value = up;
+               }
+               sort[i] = value;
+          }
+          std::sort(sort, sort + numberRows_);
+          int number = 1;
+          double last = sort[0];
+          for (i = 1; i < numberRows_; i++) {
+               if (last != sort[i])
+                    number++;
+               last = sort[i];
+          }
+#ifdef KEEP_GOING_IF_FIXED
+          //printf("ratio number diff rhs %g (%d %d fixed), element ratio %g\n",((double)number)/((double) numberRows_),
+          //   numberRows_,nFixed,elementRatio);
+#endif
+          if (number * 4 > numberRows_ || elementRatio > 1.0e12) {
+               perturbation_ = 100;
+               delete [] sort;
+               return; // good enough
+          }
+          number = 0;
+#ifdef KEEP_GOING_IF_FIXED
+          if (!integerType_) {
+               // look at columns
+               nFixed = 0;
+               for (i = 0; i < numberColumns_; i++) {
+                    double lo = fabs(columnLower_[i]);
+                    double up = fabs(columnUpper_[i]);
+                    double value = 0.0;
+                    if (lo && lo < 1.0e20) {
+                         if (up && up < 1.0e20) {
+                              value = 0.5 * (lo + up);
+                              if (lo == up)
+                                   nFixed++;
+                         } else {
+                              value = lo;
+                         }
+                    } else {
+                         if (up && up < 1.0e20)
+                              value = up;
+                    }
+                    sort[i] = value;
+               }
+               std::sort(sort, sort + numberColumns_);
+               number = 1;
+               last = sort[0];
+               for (i = 1; i < numberColumns_; i++) {
+                    if (last != sort[i])
+                         number++;
+                    last = sort[i];
+               }
+               //printf("cratio number diff bounds %g (%d %d fixed)\n",((double)number)/((double) numberColumns_),
+               //     numberColumns_,nFixed);
+          }
+#endif
+          delete [] sort;
+          if (number * 4 > numberColumns_) {
+               perturbation_ = 100;
+               return; // good enough
+          }
+     }
+     // primal perturbation
+     double perturbation = 1.0e-20;
+     double bias = 1.0;
+     int numberNonZero = 0;
+     // maximum fraction of rhs/bounds to perturb
+     double maximumFraction = 1.0e-5;
+     if (perturbation_ >= 50) {
+          perturbation = 1.0e-4;
+          for (i = 0; i < numberColumns_ + numberRows_; i++) {
+               if (upper_[i] > lower_[i] + primalTolerance_) {
+                    double lowerValue, upperValue;
+                    if (lower_[i] > -1.0e20)
+                         lowerValue = fabs(lower_[i]);
+                    else
+                         lowerValue = 0.0;
+                    if (upper_[i] < 1.0e20)
+                         upperValue = fabs(upper_[i]);
+                    else
+                         upperValue = 0.0;
+                    double value = CoinMax(fabs(lowerValue), fabs(upperValue));
+                    value = CoinMin(value, upper_[i] - lower_[i]);
+#if 1
+                    if (value) {
+                         perturbation += value;
+                         numberNonZero++;
+                    }
+#else
+                    perturbation = CoinMax(perturbation, value);
+#endif
+               }
+          }
+          if (numberNonZero)
+               perturbation /= static_cast<double> (numberNonZero);
+          else
+               perturbation = 1.0e-1;
+          if (perturbation_ > 50 && perturbation_ < 55) {
+               // reduce
+               while (perturbation_ > 50) {
+                    perturbation_--;
+                    perturbation *= 0.25;
+                    bias *= 0.25;
+               }
+          } else if (perturbation_ >= 55 && perturbation_ < 60) {
+               // increase
+               while (perturbation_ > 55) {
+                    perturbation_--;
+                    perturbation *= 4.0;
+               }
+               perturbation_ = 50;
+          }
+     } else if (perturbation_ < 100) {
+          perturbation = pow(10.0, perturbation_);
+          // user is in charge
+          maximumFraction = 1.0;
+     }
+     double largestZero = 0.0;
+     double largest = 0.0;
+     double largestPerCent = 0.0;
+     bool printOut = (handler_->logLevel() == 63);
+     printOut = false; //off
+     // Check if all slack
+     int number = 0;
+     int iSequence;
+     for (iSequence = 0; iSequence < numberRows_; iSequence++) {
+          if (getRowStatus(iSequence) == basic)
+               number++;
+     }
+     if (rhsScale_ > 100.0) {
+          // tone down perturbation
+          maximumFraction *= 0.1;
+     }
+     if (savePerturbation==51) {
+       perturbation = CoinMin(0.1,perturbation);
+       maximumFraction *=0.1;
+     }
+     if (number != numberRows_)
+          type = 1;
+     // modify bounds
+     // Change so at least 1.0e-5 and no more than 0.1
+     // For now just no more than 0.1
+     // printf("Pert type %d perturbation %g, maxF %g\n",type,perturbation,maximumFraction);
+     // seems much slower???#define SAVE_PERT
+#ifdef SAVE_PERT
+     if (2 * numberColumns_ > maximumPerturbationSize_) {
+          delete [] perturbationArray_;
+          maximumPerturbationSize_ = 2 * numberColumns_;
+          perturbationArray_ = new double [maximumPerturbationSize_];
+          for (int iColumn = 0; iColumn < maximumPerturbationSize_; iColumn++) {
+               perturbationArray_[iColumn] = randomNumberGenerator_.randomDouble();
+          }
+     }
+#endif
+     if (type == 1) {
+          double tolerance = 100.0 * primalTolerance_;
+          //double multiplier = perturbation*maximumFraction;
+          for (iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
+               if (getStatus(iSequence) == basic) {
+                    double lowerValue = lower_[iSequence];
+                    double upperValue = upper_[iSequence];
+                    if (upperValue > lowerValue + tolerance) {
+                         double solutionValue = solution_[iSequence];
+                         double difference = upperValue - lowerValue;
+                         difference = CoinMin(difference, perturbation);
+                         difference = CoinMin(difference, fabs(solutionValue) + 1.0);
+                         double value = maximumFraction * (difference + bias);
+                         value = CoinMin(value, 0.1);
+			 value = CoinMax(value,primalTolerance_);
+#ifndef SAVE_PERT
+                         value *= randomNumberGenerator_.randomDouble();
+#else
+                         value *= perturbationArray_[2*iSequence];
+#endif
+                         if (solutionValue - lowerValue <= primalTolerance_) {
+                              lower_[iSequence] -= value;
+                         } else if (upperValue - solutionValue <= primalTolerance_) {
+                              upper_[iSequence] += value;
+                         } else {
+#if 0
+                              if (iSequence >= numberColumns_) {
+                                   // may not be at bound - but still perturb (unless free)
+                                   if (upperValue > 1.0e30 && lowerValue < -1.0e30)
+                                        value = 0.0;
+                                   else
+                                        value = - value; // as -1.0 in matrix
+                              } else {
+                                   value = 0.0;
+                              }
+#else
+                              value = 0.0;
+#endif
+                         }
+                         if (value) {
+                              if (printOut)
+                                   printf("col %d lower from %g to %g, upper from %g to %g\n",
+                                          iSequence, lower_[iSequence], lowerValue, upper_[iSequence], upperValue);
+                              if (solutionValue) {
+                                   largest = CoinMax(largest, value);
+                                   if (value > (fabs(solutionValue) + 1.0)*largestPerCent)
+                                        largestPerCent = value / (fabs(solutionValue) + 1.0);
+                              } else {
+                                   largestZero = CoinMax(largestZero, value);
+                              }
+                         }
+                    }
+               }
+          }
+     } else {
+          double tolerance = 100.0 * primalTolerance_;
+          for (i = 0; i < numberColumns_; i++) {
+               double lowerValue = lower_[i], upperValue = upper_[i];
+               if (upperValue > lowerValue + primalTolerance_) {
+                    double value = perturbation * maximumFraction;
+                    value = CoinMin(value, 0.1);
+#ifndef SAVE_PERT
+                    value *= randomNumberGenerator_.randomDouble();
+#else
+                    value *= perturbationArray_[2*i+1];
+#endif
+                    value *= randomNumberGenerator_.randomDouble();
+                    if (savePerturbation != 50) {
+                         if (fabs(value) <= primalTolerance_)
+                              value = 0.0;
+                         if (lowerValue > -1.0e20 && lowerValue)
+                              lowerValue -= value * (CoinMax(1.0e-2, 1.0e-5 * fabs(lowerValue)));
+                         if (upperValue < 1.0e20 && upperValue)
+                              upperValue += value * (CoinMax(1.0e-2, 1.0e-5 * fabs(upperValue)));
+                    } else if (value) {
+                         double valueL = value * (CoinMax(1.0e-2, 1.0e-5 * fabs(lowerValue)));
+                         // get in range
+                         if (valueL <= tolerance) {
+                              valueL *= 10.0;
+                              while (valueL <= tolerance)
+                                   valueL *= 10.0;
+                         } else if (valueL > 1.0) {
+                              valueL *= 0.1;
+                              while (valueL > 1.0)
+                                   valueL *= 0.1;
+                         }
+                         if (lowerValue > -1.0e20 && lowerValue)
+                              lowerValue -= valueL;
+                         double valueU = value * (CoinMax(1.0e-2, 1.0e-5 * fabs(upperValue)));
+                         // get in range
+                         if (valueU <= tolerance) {
+                              valueU *= 10.0;
+                              while (valueU <= tolerance)
+                                   valueU *= 10.0;
+                         } else if (valueU > 1.0) {
+                              valueU *= 0.1;
+                              while (valueU > 1.0)
+                                   valueU *= 0.1;
+                         }
+                         if (upperValue < 1.0e20 && upperValue)
+                              upperValue += valueU;
+                    }
+                    if (lowerValue != lower_[i]) {
+                         double difference = fabs(lowerValue - lower_[i]);
+                         largest = CoinMax(largest, difference);
+                         if (difference > fabs(lower_[i])*largestPerCent)
+                              largestPerCent = fabs(difference / lower_[i]);
+                    }
+                    if (upperValue != upper_[i]) {
+                         double difference = fabs(upperValue - upper_[i]);
+                         largest = CoinMax(largest, difference);
+                         if (difference > fabs(upper_[i])*largestPerCent)
+                              largestPerCent = fabs(difference / upper_[i]);
+                    }
+                    if (printOut)
+                         printf("col %d lower from %g to %g, upper from %g to %g\n",
+                                i, lower_[i], lowerValue, upper_[i], upperValue);
+               }
+               lower_[i] = lowerValue;
+               upper_[i] = upperValue;
+          }
+          for (; i < numberColumns_ + numberRows_; i++) {
+               double lowerValue = lower_[i], upperValue = upper_[i];
+               double value = perturbation * maximumFraction;
+               value = CoinMin(value, 0.1);
+               value *= randomNumberGenerator_.randomDouble();
+               if (upperValue > lowerValue + tolerance) {
+                    if (savePerturbation != 50) {
+                         if (fabs(value) <= primalTolerance_)
+                              value = 0.0;
+                         if (lowerValue > -1.0e20 && lowerValue)
+                              lowerValue -= value * (CoinMax(1.0e-2, 1.0e-5 * fabs(lowerValue)));
+                         if (upperValue < 1.0e20 && upperValue)
+                              upperValue += value * (CoinMax(1.0e-2, 1.0e-5 * fabs(upperValue)));
+                    } else if (value) {
+                         double valueL = value * (CoinMax(1.0e-2, 1.0e-5 * fabs(lowerValue)));
+                         // get in range
+                         if (valueL <= tolerance) {
+                              valueL *= 10.0;
+                              while (valueL <= tolerance)
+                                   valueL *= 10.0;
+                         } else if (valueL > 1.0) {
+                              valueL *= 0.1;
+                              while (valueL > 1.0)
+                                   valueL *= 0.1;
+                         }
+                         if (lowerValue > -1.0e20 && lowerValue)
+                              lowerValue -= valueL;
+                         double valueU = value * (CoinMax(1.0e-2, 1.0e-5 * fabs(upperValue)));
+                         // get in range
+                         if (valueU <= tolerance) {
+                              valueU *= 10.0;
+                              while (valueU <= tolerance)
+                                   valueU *= 10.0;
+                         } else if (valueU > 1.0) {
+                              valueU *= 0.1;
+                              while (valueU > 1.0)
+                                   valueU *= 0.1;
+                         }
+                         if (upperValue < 1.0e20 && upperValue)
+                              upperValue += valueU;
+                    }
+               } else if (upperValue > 0.0) {
+                    upperValue -= value * (CoinMax(1.0e-2, 1.0e-5 * fabs(lowerValue)));
+                    lowerValue -= value * (CoinMax(1.0e-2, 1.0e-5 * fabs(lowerValue)));
+               } else if (upperValue < 0.0) {
+                    upperValue += value * (CoinMax(1.0e-2, 1.0e-5 * fabs(lowerValue)));
+                    lowerValue += value * (CoinMax(1.0e-2, 1.0e-5 * fabs(lowerValue)));
+               } else {
+               }
+               if (lowerValue != lower_[i]) {
+                    double difference = fabs(lowerValue - lower_[i]);
+                    largest = CoinMax(largest, difference);
+                    if (difference > fabs(lower_[i])*largestPerCent)
+                         largestPerCent = fabs(difference / lower_[i]);
+               }
+               if (upperValue != upper_[i]) {
+                    double difference = fabs(upperValue - upper_[i]);
+                    largest = CoinMax(largest, difference);
+                    if (difference > fabs(upper_[i])*largestPerCent)
+                         largestPerCent = fabs(difference / upper_[i]);
+               }
+               if (printOut)
+                    printf("row %d lower from %g to %g, upper from %g to %g\n",
+                           i - numberColumns_, lower_[i], lowerValue, upper_[i], upperValue);
+               lower_[i] = lowerValue;
+               upper_[i] = upperValue;
+          }
+     }
+     // Clean up
+     for (i = 0; i < numberColumns_ + numberRows_; i++) {
+          switch(getStatus(i)) {
+
+          case basic:
+               break;
+          case atUpperBound:
+               solution_[i] = upper_[i];
+               break;
+          case isFixed:
+          case atLowerBound:
+               solution_[i] = lower_[i];
+               break;
+          case isFree:
+               break;
+          case superBasic:
+               break;
+          }
+     }
+     handler_->message(CLP_SIMPLEX_PERTURB, messages_)
+               << 100.0 * maximumFraction << perturbation << largest << 100.0 * largestPerCent << largestZero
+               << CoinMessageEol;
+     // redo nonlinear costs
+     // say perturbed
+     perturbation_ = 101;
+}
+// un perturb
+bool
+ClpSimplexPrimal::unPerturb()
+{
+     if (perturbation_ != 101)
+          return false;
+     // put back original bounds and costs
+     createRim(1 + 4);
+     sanityCheck();
+     // unflag
+     unflag();
+     // get a valid nonlinear cost function
+     delete nonLinearCost_;
+     nonLinearCost_ = new ClpNonLinearCost(this);
+     perturbation_ = 102; // stop any further perturbation
+     // move non basic variables to new bounds
+     nonLinearCost_->checkInfeasibilities(0.0);
+#if 1
+     // Try using dual
+     return true;
+#else
+     gutsOfSolution(NULL, NULL, ifValuesPass != 0);
+     return false;
+#endif
+
+}
+// Unflag all variables and return number unflagged
+int
+ClpSimplexPrimal::unflag()
+{
+     int i;
+     int number = numberRows_ + numberColumns_;
+     int numberFlagged = 0;
+     // we can't really trust infeasibilities if there is dual error
+     // allow tolerance bigger than standard to check on duals
+     double relaxedToleranceD = dualTolerance_ + CoinMin(1.0e-2, 10.0 * largestDualError_);
+     for (i = 0; i < number; i++) {
+          if (flagged(i)) {
+               clearFlagged(i);
+               // only say if reasonable dj
+               if (fabs(dj_[i]) > relaxedToleranceD)
+                    numberFlagged++;
+          }
+     }
+     numberFlagged += matrix_->generalExpanded(this, 8, i);
+     if (handler_->logLevel() > 2 && numberFlagged && objective_->type() > 1)
+          printf("%d unflagged\n", numberFlagged);
+     return numberFlagged;
+}
+// Do not change infeasibility cost and always say optimal
+void
+ClpSimplexPrimal::alwaysOptimal(bool onOff)
+{
+     if (onOff)
+          specialOptions_ |= 1;
+     else
+          specialOptions_ &= ~1;
+}
+bool
+ClpSimplexPrimal::alwaysOptimal() const
+{
+     return (specialOptions_ & 1) != 0;
+}
+// Flatten outgoing variables i.e. - always to exact bound
+void
+ClpSimplexPrimal::exactOutgoing(bool onOff)
+{
+     if (onOff)
+          specialOptions_ |= 4;
+     else
+          specialOptions_ &= ~4;
+}
+bool
+ClpSimplexPrimal::exactOutgoing() const
+{
+     return (specialOptions_ & 4) != 0;
+}
+/*
+  Reasons to come out (normal mode/user mode):
+  -1 normal
+  -2 factorize now - good iteration/ NA
+  -3 slight inaccuracy - refactorize - iteration done/ same but factor done
+  -4 inaccuracy - refactorize - no iteration/ NA
+  -5 something flagged - go round again/ pivot not possible
+  +2 looks unbounded
+  +3 max iterations (iteration done)
+*/
+int
+ClpSimplexPrimal::pivotResult(int ifValuesPass)
+{
+
+     bool roundAgain = true;
+     int returnCode = -1;
+
+     // loop round if user setting and doing refactorization
+     while (roundAgain) {
+          roundAgain = false;
+          returnCode = -1;
+          pivotRow_ = -1;
+          sequenceOut_ = -1;
+          rowArray_[1]->clear();
+#if 0
+          {
+               int seq[] = {612, 643};
+               int k;
+               for (k = 0; k < sizeof(seq) / sizeof(int); k++) {
+                    int iSeq = seq[k];
+                    if (getColumnStatus(iSeq) != basic) {
+                         double djval;
+                         double * work;
+                         int number;
+                         int * which;
+
+                         int iIndex;
+                         unpack(rowArray_[1], iSeq);
+                         factorization_->updateColumn(rowArray_[2], rowArray_[1]);
+                         djval = cost_[iSeq];
+                         work = rowArray_[1]->denseVector();
+                         number = rowArray_[1]->getNumElements();
+                         which = rowArray_[1]->getIndices();
+
+                         for (iIndex = 0; iIndex < number; iIndex++) {
+
+                              int iRow = which[iIndex];
+                              double alpha = work[iRow];
+                              int iPivot = pivotVariable_[iRow];
+                              djval -= alpha * cost_[iPivot];
+                         }
+                         double comp = 1.0e-8 + 1.0e-7 * (CoinMax(fabs(dj_[iSeq]), fabs(djval)));
+                         if (fabs(djval - dj_[iSeq]) > comp)
+                              printf("Bad dj %g for %d - true is %g\n",
+                                     dj_[iSeq], iSeq, djval);
+                         assert (fabs(djval) < 1.0e-3 || djval * dj_[iSeq] > 0.0);
+                         rowArray_[1]->clear();
+                    }
+               }
+          }
+#endif
+
+          // we found a pivot column
+          // update the incoming column
+          unpackPacked(rowArray_[1]);
+          // save reduced cost
+          double saveDj = dualIn_;
+          factorization_->updateColumnFT(rowArray_[2], rowArray_[1]);
+          // Get extra rows
+          matrix_->extendUpdated(this, rowArray_[1], 0);
+          // do ratio test and re-compute dj
+#ifdef CLP_USER_DRIVEN
+          if (solveType_ != 2 || (moreSpecialOptions_ & 512) == 0) {
+#endif
+               primalRow(rowArray_[1], rowArray_[3], rowArray_[2],
+                         ifValuesPass);
+#ifdef CLP_USER_DRIVEN
+	       // user can tell which use it is
+               int status = eventHandler_->event(ClpEventHandler::pivotRow);
+               if (status >= 0) {
+                    problemStatus_ = 5;
+                    secondaryStatus_ = ClpEventHandler::pivotRow;
+                    break;
+               }
+          } else {
+               int status = eventHandler_->event(ClpEventHandler::pivotRow);
+               if (status >= 0) {
+                    problemStatus_ = 5;
+                    secondaryStatus_ = ClpEventHandler::pivotRow;
+                    break;
+               }
+          }
+#endif
+          if (ifValuesPass) {
+               saveDj = dualIn_;
+               //assert (fabs(alpha_)>=1.0e-5||(objective_->type()<2||!objective_->activated())||pivotRow_==-2);
+               if (pivotRow_ == -1 || (pivotRow_ >= 0 && fabs(alpha_) < 1.0e-5)) {
+                    if(fabs(dualIn_) < 1.0e2 * dualTolerance_ && objective_->type() < 2) {
+                         // try other way
+                         directionIn_ = -directionIn_;
+                         primalRow(rowArray_[1], rowArray_[3], rowArray_[2],
+                                   0);
+                    }
+                    if (pivotRow_ == -1 || (pivotRow_ >= 0 && fabs(alpha_) < 1.0e-5)) {
+                         if (solveType_ == 1) {
+                              // reject it
+                              char x = isColumn(sequenceIn_) ? 'C' : 'R';
+                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                        << x << sequenceWithin(sequenceIn_)
+                                        << CoinMessageEol;
+                              setFlagged(sequenceIn_);
+                              progress_.clearBadTimes();
+                              lastBadIteration_ = numberIterations_; // say be more cautious
+                              clearAll();
+                              pivotRow_ = -1;
+                         }
+                         returnCode = -5;
+                         break;
+                    }
+               }
+          }
+          // need to clear toIndex_ in gub
+          // ? when can I clear stuff
+          // Clean up any gub stuff
+          matrix_->extendUpdated(this, rowArray_[1], 1);
+          double checkValue = 1.0e-2;
+          if (largestDualError_ > 1.0e-5)
+               checkValue = 1.0e-1;
+          double test2 = dualTolerance_;
+          double test1 = 1.0e-20;
+#if 0 //def FEB_TRY
+          if (factorization_->pivots() < 1) {
+               test1 = -1.0e-4;
+               if ((saveDj < 0.0 && dualIn_ < -1.0e-5 * dualTolerance_) ||
+                         (saveDj > 0.0 && dualIn_ > 1.0e-5 * dualTolerance_))
+                    test2 = 0.0; // allow through
+          }
+#endif
+          if (!ifValuesPass && solveType_ == 1 && (saveDj * dualIn_ < test1 ||
+                    fabs(saveDj - dualIn_) > checkValue*(1.0 + fabs(saveDj)) ||
+                    fabs(dualIn_) < test2)) {
+               if (!(saveDj * dualIn_ > 0.0 && CoinMin(fabs(saveDj), fabs(dualIn_)) >
+                         1.0e5)) {
+                    char x = isColumn(sequenceIn_) ? 'C' : 'R';
+                    handler_->message(CLP_PRIMAL_DJ, messages_)
+                              << x << sequenceWithin(sequenceIn_)
+                              << saveDj << dualIn_
+                              << CoinMessageEol;
+                    if(lastGoodIteration_ != numberIterations_) {
+                         clearAll();
+                         pivotRow_ = -1; // say no weights update
+                         returnCode = -4;
+                         if(lastGoodIteration_ + 1 == numberIterations_) {
+                              // not looking wonderful - try cleaning bounds
+                              // put non-basics to bounds in case tolerance moved
+                              nonLinearCost_->checkInfeasibilities(0.0);
+                         }
+                         sequenceOut_ = -1;
+                         break;
+                    } else {
+                         // take on more relaxed criterion
+                         if (saveDj * dualIn_ < test1 ||
+                                   fabs(saveDj - dualIn_) > 2.0e-1 * (1.0 + fabs(dualIn_)) ||
+                                   fabs(dualIn_) < test2) {
+                              // need to reject something
+                              char x = isColumn(sequenceIn_) ? 'C' : 'R';
+                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                        << x << sequenceWithin(sequenceIn_)
+                                        << CoinMessageEol;
+                              setFlagged(sequenceIn_);
+#if 1 //def FEB_TRY
+                              // Make safer?
+                              factorization_->saferTolerances (-0.99, -1.03);
+#endif
+                              progress_.clearBadTimes();
+                              lastBadIteration_ = numberIterations_; // say be more cautious
+                              clearAll();
+                              pivotRow_ = -1;
+                              returnCode = -5;
+                              sequenceOut_ = -1;
+                              break;
+                         }
+                    }
+               } else {
+                    //printf("%d %g %g\n",numberIterations_,saveDj,dualIn_);
+               }
+          }
+          if (pivotRow_ >= 0) {
+ #ifdef CLP_USER_DRIVEN1
+	       // Got good pivot - may need to unflag stuff
+	       userChoiceWasGood(this);
+ #endif
+               if (solveType_ >= 2 && (moreSpecialOptions_ & 512) == 0) {
+                    // **** Coding for user interface
+                    // do ray
+		    if (solveType_==2)
+                      primalRay(rowArray_[1]);
+                    // update duals
+                    // as packed need to find pivot row
+                    //assert (rowArray_[1]->packedMode());
+                    //int i;
+
+                    //alpha_ = rowArray_[1]->denseVector()[pivotRow_];
+                    CoinAssert (fabs(alpha_) > 1.0e-12);
+                    double multiplier = dualIn_ / alpha_;
+#ifndef NDEBUG
+		    rowArray_[0]->checkClear();
+#endif
+                    rowArray_[0]->insert(pivotRow_, multiplier);
+                    factorization_->updateColumnTranspose(rowArray_[2], rowArray_[0]);
+                    // put row of tableau in rowArray[0] and columnArray[0]
+                    matrix_->transposeTimes(this, -1.0,
+                                            rowArray_[0], columnArray_[1], columnArray_[0]);
+                    // update column djs
+                    int i;
+                    int * index = columnArray_[0]->getIndices();
+                    int number = columnArray_[0]->getNumElements();
+                    double * element = columnArray_[0]->denseVector();
+                    for (i = 0; i < number; i++) {
+                         int ii = index[i];
+                         dj_[ii] += element[ii];
+                         reducedCost_[ii] = dj_[ii];
+                         element[ii] = 0.0;
+                    }
+                    columnArray_[0]->setNumElements(0);
+                    // and row djs
+                    index = rowArray_[0]->getIndices();
+                    number = rowArray_[0]->getNumElements();
+                    element = rowArray_[0]->denseVector();
+                    for (i = 0; i < number; i++) {
+                         int ii = index[i];
+                         dj_[ii+numberColumns_] += element[ii];
+                         dual_[ii] = dj_[ii+numberColumns_];
+                         element[ii] = 0.0;
+                    }
+                    rowArray_[0]->setNumElements(0);
+                    // check incoming
+                    CoinAssert (fabs(dj_[sequenceIn_]) < 1.0e-1);
+               }
+               // if stable replace in basis
+               // If gub or odd then alpha and pivotRow may change
+               int updateType = 0;
+               int updateStatus = matrix_->generalExpanded(this, 3, updateType);
+               if (updateType >= 0)
+                    updateStatus = factorization_->replaceColumn(this,
+                                   rowArray_[2],
+                                   rowArray_[1],
+                                   pivotRow_,
+                                   alpha_,
+                                   (moreSpecialOptions_ & 16) != 0);
+
+               // if no pivots, bad update but reasonable alpha - take and invert
+               if (updateStatus == 2 &&
+                         lastGoodIteration_ == numberIterations_ && fabs(alpha_) > 1.0e-5)
+                    updateStatus = 4;
+               if (updateStatus == 1 || updateStatus == 4) {
+                    // slight error
+                    if (factorization_->pivots() > 5 || updateStatus == 4) {
+                         returnCode = -3;
+                    }
+               } else if (updateStatus == 2) {
+                    // major error
+                    // better to have small tolerance even if slower
+                    factorization_->zeroTolerance(CoinMin(factorization_->zeroTolerance(), 1.0e-15));
+                    int maxFactor = factorization_->maximumPivots();
+                    if (maxFactor > 10) {
+                         if (forceFactorization_ < 0)
+                              forceFactorization_ = maxFactor;
+                         forceFactorization_ = CoinMax(1, (forceFactorization_ >> 1));
+                    }
+                    // later we may need to unwind more e.g. fake bounds
+                    if(lastGoodIteration_ != numberIterations_) {
+                         clearAll();
+                         pivotRow_ = -1;
+                         if (solveType_ == 1 || (moreSpecialOptions_ & 512) != 0) {
+                              returnCode = -4;
+                              break;
+                         } else {
+                              // user in charge - re-factorize
+                              int lastCleaned = 0;
+                              ClpSimplexProgress dummyProgress;
+                              if (saveStatus_)
+                                   statusOfProblemInPrimal(lastCleaned, 1, &dummyProgress, true, ifValuesPass);
+                              else
+                                   statusOfProblemInPrimal(lastCleaned, 0, &dummyProgress, true, ifValuesPass);
+                              roundAgain = true;
+                              continue;
+                         }
+                    } else {
+                         // need to reject something
+                         if (solveType_ == 1) {
+                              char x = isColumn(sequenceIn_) ? 'C' : 'R';
+                              handler_->message(CLP_SIMPLEX_FLAG, messages_)
+                                        << x << sequenceWithin(sequenceIn_)
+                                        << CoinMessageEol;
+                              setFlagged(sequenceIn_);
+                              progress_.clearBadTimes();
+                         }
+                         lastBadIteration_ = numberIterations_; // say be more cautious
+                         clearAll();
+                         pivotRow_ = -1;
+                         sequenceOut_ = -1;
+                         returnCode = -5;
+                         break;
+
+                    }
+               } else if (updateStatus == 3) {
+                    // out of memory
+                    // increase space if not many iterations
+                    if (factorization_->pivots() <
+                              0.5 * factorization_->maximumPivots() &&
+                              factorization_->pivots() < 200)
+                         factorization_->areaFactor(
+                              factorization_->areaFactor() * 1.1);
+                    returnCode = -2; // factorize now
+               } else if (updateStatus == 5) {
+                    problemStatus_ = -2; // factorize now
+               }
+               // here do part of steepest - ready for next iteration
+               if (!ifValuesPass)
+                    primalColumnPivot_->updateWeights(rowArray_[1]);
+          } else {
+               if (pivotRow_ == -1) {
+                    // no outgoing row is valid
+                    if (valueOut_ != COIN_DBL_MAX) {
+                         double objectiveChange = 0.0;
+                         theta_ = valueOut_ - valueIn_;
+                         updatePrimalsInPrimal(rowArray_[1], theta_, objectiveChange, ifValuesPass);
+                         solution_[sequenceIn_] += theta_;
+                    }
+                    rowArray_[0]->clear();
+ #ifdef CLP_USER_DRIVEN1
+		    /* Note if valueOut_ < COIN_DBL_MAX and
+		       theta_ reasonable then this may be a valid sub flip */
+		    if(!userChoiceValid2(this)) {
+		      if (factorization_->pivots()<5) {
+			// flag variable
+			char x = isColumn(sequenceIn_) ? 'C' : 'R';
+			handler_->message(CLP_SIMPLEX_FLAG, messages_)
+			  << x << sequenceWithin(sequenceIn_)
+			  << CoinMessageEol;
+			setFlagged(sequenceIn_);
+			progress_.clearBadTimes();
+			roundAgain = true;
+			continue;
+		      } else {
+			// try refactorizing first
+			returnCode = 4; //say looks odd but has iterated
+			break;
+		      }
+		    }
+ #endif
+                    if (!factorization_->pivots() && acceptablePivot_ <= 1.0e-8 ) {
+                         returnCode = 2; //say looks unbounded
+                         // do ray
+			 if (!nonLinearCost_->sumInfeasibilities())
+			   primalRay(rowArray_[1]);
+                    } else if (solveType_ == 2 && (moreSpecialOptions_ & 512) == 0) {
+                         // refactorize
+                         int lastCleaned = 0;
+                         ClpSimplexProgress dummyProgress;
+                         if (saveStatus_)
+                              statusOfProblemInPrimal(lastCleaned, 1, &dummyProgress, true, ifValuesPass);
+                         else
+                              statusOfProblemInPrimal(lastCleaned, 0, &dummyProgress, true, ifValuesPass);
+                         roundAgain = true;
+                         continue;
+                    } else {
+                         acceptablePivot_ = 1.0e-8;
+                         returnCode = 4; //say looks unbounded but has iterated
+                    }
+                    break;
+               } else {
+                    // flipping from bound to bound
+               }
+          }
+
+          double oldCost = 0.0;
+          if (sequenceOut_ >= 0)
+               oldCost = cost_[sequenceOut_];
+          // update primal solution
+
+          double objectiveChange = 0.0;
+          // after this rowArray_[1] is not empty - used to update djs
+          // If pivot row >= numberRows then may be gub
+          int savePivot = pivotRow_;
+          if (pivotRow_ >= numberRows_)
+               pivotRow_ = -1;
+#ifdef CLP_USER_DRIVEN
+	  if (theta_<0.0) {
+	    if (theta_>=-1.0e-12)
+	      theta_=0.0;
+	    //else
+	    //printf("negative theta %g\n",theta_);
+	  }
+#endif
+          updatePrimalsInPrimal(rowArray_[1], theta_, objectiveChange, ifValuesPass);
+          pivotRow_ = savePivot;
+
+          double oldValue = valueIn_;
+          if (directionIn_ == -1) {
+               // as if from upper bound
+               if (sequenceIn_ != sequenceOut_) {
+                    // variable becoming basic
+                    valueIn_ -= fabs(theta_);
+               } else {
+                    valueIn_ = lowerIn_;
+               }
+          } else {
+               // as if from lower bound
+               if (sequenceIn_ != sequenceOut_) {
+                    // variable becoming basic
+                    valueIn_ += fabs(theta_);
+               } else {
+                    valueIn_ = upperIn_;
+               }
+          }
+          objectiveChange += dualIn_ * (valueIn_ - oldValue);
+          // outgoing
+          if (sequenceIn_ != sequenceOut_) {
+               if (directionOut_ > 0) {
+                    valueOut_ = lowerOut_;
+               } else {
+                    valueOut_ = upperOut_;
+               }
+               if(valueOut_ < lower_[sequenceOut_] - primalTolerance_)
+                    valueOut_ = lower_[sequenceOut_] - 0.9 * primalTolerance_;
+               else if (valueOut_ > upper_[sequenceOut_] + primalTolerance_)
+                    valueOut_ = upper_[sequenceOut_] + 0.9 * primalTolerance_;
+               // may not be exactly at bound and bounds may have changed
+               // Make sure outgoing looks feasible
+               directionOut_ = nonLinearCost_->setOneOutgoing(sequenceOut_, valueOut_);
+               // May have got inaccurate
+               //if (oldCost!=cost_[sequenceOut_])
+               //printf("costchange on %d from %g to %g\n",sequenceOut_,
+               //       oldCost,cost_[sequenceOut_]);
+               if (solveType_ < 2)
+                    dj_[sequenceOut_] = cost_[sequenceOut_] - oldCost; // normally updated next iteration
+               solution_[sequenceOut_] = valueOut_;
+          }
+          // change cost and bounds on incoming if primal
+          nonLinearCost_->setOne(sequenceIn_, valueIn_);
+          int whatNext = housekeeping(objectiveChange);
+          //nonLinearCost_->validate();
+#if CLP_DEBUG >1
+          {
+               double sum;
+               int ninf = matrix_->checkFeasible(this, sum);
+               if (ninf)
+                    printf("infeas %d\n", ninf);
+          }
+#endif
+          if (whatNext == 1) {
+               returnCode = -2; // refactorize
+          } else if (whatNext == 2) {
+               // maximum iterations or equivalent
+               returnCode = 3;
+          } else if(numberIterations_ == lastGoodIteration_
+                    + 2 * factorization_->maximumPivots()) {
+               // done a lot of flips - be safe
+               returnCode = -2; // refactorize
+          }
+          // Check event
+          {
+               int status = eventHandler_->event(ClpEventHandler::endOfIteration);
+               if (status >= 0) {
+                    problemStatus_ = 5;
+                    secondaryStatus_ = ClpEventHandler::endOfIteration;
+                    returnCode = 3;
+               }
+          }
+     }
+     if ((solveType_ == 2 && (moreSpecialOptions_ & 512) == 0) &&
+               (returnCode == -2 || returnCode == -3)) {
+          // refactorize here
+          int lastCleaned = 0;
+          ClpSimplexProgress dummyProgress;
+          if (saveStatus_)
+               statusOfProblemInPrimal(lastCleaned, 1, &dummyProgress, true, ifValuesPass);
+          else
+               statusOfProblemInPrimal(lastCleaned, 0, &dummyProgress, true, ifValuesPass);
+          if (problemStatus_ == 5) {
+	    COIN_DETAIL_PRINT(printf("Singular basis\n"));
+               problemStatus_ = -1;
+               returnCode = 5;
+          }
+     }
+#ifdef CLP_DEBUG
+     {
+          int i;
+          // not [1] as may have information
+          for (i = 0; i < 4; i++) {
+               if (i != 1)
+                    rowArray_[i]->checkClear();
+          }
+          for (i = 0; i < 2; i++) {
+               columnArray_[i]->checkClear();
+          }
+     }
+#endif
+     return returnCode;
+}
+// Create primal ray
+void
+ClpSimplexPrimal::primalRay(CoinIndexedVector * rowArray)
+{
+     delete [] ray_;
+     ray_ = new double [numberColumns_];
+     CoinZeroN(ray_, numberColumns_);
+     int number = rowArray->getNumElements();
+     int * index = rowArray->getIndices();
+     double * array = rowArray->denseVector();
+     double way = -directionIn_;
+     int i;
+     double zeroTolerance = 1.0e-12;
+     if (sequenceIn_ < numberColumns_)
+          ray_[sequenceIn_] = directionIn_;
+     if (!rowArray->packedMode()) {
+          for (i = 0; i < number; i++) {
+               int iRow = index[i];
+               int iPivot = pivotVariable_[iRow];
+               double arrayValue = array[iRow];
+               if (iPivot < numberColumns_ && fabs(arrayValue) >= zeroTolerance)
+                    ray_[iPivot] = way * arrayValue;
+          }
+     } else {
+          for (i = 0; i < number; i++) {
+               int iRow = index[i];
+               int iPivot = pivotVariable_[iRow];
+               double arrayValue = array[i];
+               if (iPivot < numberColumns_ && fabs(arrayValue) >= zeroTolerance)
+                    ray_[iPivot] = way * arrayValue;
+          }
+     }
+}
+/* Get next superbasic -1 if none,
+   Normal type is 1
+   If type is 3 then initializes sorted list
+   if 2 uses list.
+*/
+int
+ClpSimplexPrimal::nextSuperBasic(int superBasicType,
+                                 CoinIndexedVector * columnArray)
+{
+     int returnValue = -1;
+     bool finished = false;
+     while (!finished) {
+          returnValue = firstFree_;
+          int iColumn = firstFree_ + 1;
+          if (superBasicType > 1) {
+               if (superBasicType > 2) {
+                    // Initialize list
+                    // Wild guess that lower bound more natural than upper
+                    int number = 0;
+                    double * work = columnArray->denseVector();
+                    int * which = columnArray->getIndices();
+                    for (iColumn = 0; iColumn < numberRows_ + numberColumns_; iColumn++) {
+                         if (!flagged(iColumn)) {
+                              if (getStatus(iColumn) == superBasic) {
+                                   if (fabs(solution_[iColumn] - lower_[iColumn]) <= primalTolerance_) {
+                                        solution_[iColumn] = lower_[iColumn];
+                                        setStatus(iColumn, atLowerBound);
+                                   } else if (fabs(solution_[iColumn] - upper_[iColumn])
+                                              <= primalTolerance_) {
+                                        solution_[iColumn] = upper_[iColumn];
+                                        setStatus(iColumn, atUpperBound);
+                                   } else if (lower_[iColumn] < -1.0e20 && upper_[iColumn] > 1.0e20) {
+                                        setStatus(iColumn, isFree);
+                                        break;
+                                   } else if (!flagged(iColumn)) {
+                                        // put ones near bounds at end after sorting
+                                        work[number] = - CoinMin(0.1 * (solution_[iColumn] - lower_[iColumn]),
+                                                                 upper_[iColumn] - solution_[iColumn]);
+                                        which[number++] = iColumn;
+                                   }
+                              }
+                         }
+                    }
+                    CoinSort_2(work, work + number, which);
+                    columnArray->setNumElements(number);
+                    CoinZeroN(work, number);
+               }
+               int * which = columnArray->getIndices();
+               int number = columnArray->getNumElements();
+               if (!number) {
+                    // finished
+                    iColumn = numberRows_ + numberColumns_;
+                    returnValue = -1;
+               } else {
+                    number--;
+                    returnValue = which[number];
+                    iColumn = returnValue;
+                    columnArray->setNumElements(number);
+               }
+          } else {
+               for (; iColumn < numberRows_ + numberColumns_; iColumn++) {
+                    if (!flagged(iColumn)) {
+                         if (getStatus(iColumn) == superBasic) {
+                              if (fabs(solution_[iColumn] - lower_[iColumn]) <= primalTolerance_) {
+                                   solution_[iColumn] = lower_[iColumn];
+                                   setStatus(iColumn, atLowerBound);
+                              } else if (fabs(solution_[iColumn] - upper_[iColumn])
+                                         <= primalTolerance_) {
+                                   solution_[iColumn] = upper_[iColumn];
+                                   setStatus(iColumn, atUpperBound);
+                              } else if (lower_[iColumn] < -1.0e20 && upper_[iColumn] > 1.0e20) {
+                                   setStatus(iColumn, isFree);
+				   if (fabs(dj_[iColumn])>dualTolerance_)
+				     break;
+                              } else {
+                                   break;
+                              }
+                         }
+                    }
+               }
+          }
+          firstFree_ = iColumn;
+          finished = true;
+          if (firstFree_ == numberRows_ + numberColumns_)
+               firstFree_ = -1;
+          if (returnValue >= 0 && getStatus(returnValue) != superBasic && getStatus(returnValue) != isFree)
+               finished = false; // somehow picked up odd one
+     }
+     return returnValue;
+}
+void
+ClpSimplexPrimal::clearAll()
+{
+     // Clean up any gub stuff
+     matrix_->extendUpdated(this, rowArray_[1], 1);
+     int number = rowArray_[1]->getNumElements();
+     int * which = rowArray_[1]->getIndices();
+
+     int iIndex;
+     for (iIndex = 0; iIndex < number; iIndex++) {
+
+          int iRow = which[iIndex];
+          clearActive(iRow);
+     }
+     rowArray_[1]->clear();
+     // make sure any gub sets are clean
+     matrix_->generalExpanded(this, 11, sequenceIn_);
+
+}
+// Sort of lexicographic resolve
+int
+ClpSimplexPrimal::lexSolve()
+{
+     algorithm_ = +1;
+     //specialOptions_ |= 4;
+
+     // save data
+     ClpDataSave data = saveData();
+     matrix_->refresh(this); // make sure matrix okay
+
+     // Save so can see if doing after dual
+     int initialStatus = problemStatus_;
+     int initialIterations = numberIterations_;
+     int initialNegDjs = -1;
+     // initialize - maybe values pass and algorithm_ is +1
+     int ifValuesPass = 0;
+#if 0
+     // if so - put in any superbasic costed slacks
+     // Start can skip some things in transposeTimes
+     specialOptions_ |= 131072;
+     if (ifValuesPass && specialOptions_ < 0x01000000) {
+          // Get column copy
+          const CoinPackedMatrix * columnCopy = matrix();
+          const int * row = columnCopy->getIndices();
+          const CoinBigIndex * columnStart = columnCopy->getVectorStarts();
+          const int * columnLength = columnCopy->getVectorLengths();
+          //const double * element = columnCopy->getElements();
+          int n = 0;
+          for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
+               if (columnLength[iColumn] == 1) {
+                    Status status = getColumnStatus(iColumn);
+                    if (status != basic && status != isFree) {
+                         double value = columnActivity_[iColumn];
+                         if (fabs(value - columnLower_[iColumn]) > primalTolerance_ &&
+                                   fabs(value - columnUpper_[iColumn]) > primalTolerance_) {
+                              int iRow = row[columnStart[iColumn]];
+                              if (getRowStatus(iRow) == basic) {
+                                   setRowStatus(iRow, superBasic);
+                                   setColumnStatus(iColumn, basic);
+                                   n++;
+                              }
+                         }
+                    }
+               }
+          }
+          printf("%d costed slacks put in basis\n", n);
+     }
+#endif
+     double * originalCost = NULL;
+     double * originalLower = NULL;
+     double * originalUpper = NULL;
+     if (!startup(0, 0)) {
+
+          // Set average theta
+          nonLinearCost_->setAverageTheta(1.0e3);
+          int lastCleaned = 0; // last time objective or bounds cleaned up
+
+          // Say no pivot has occurred (for steepest edge and updates)
+          pivotRow_ = -2;
+
+          // This says whether to restore things etc
+          int factorType = 0;
+          if (problemStatus_ < 0 && perturbation_ < 100) {
+               perturb(0);
+               // Can't get here if values pass
+               assert (!ifValuesPass);
+               gutsOfSolution(NULL, NULL);
+               if (handler_->logLevel() > 2) {
+                    handler_->message(CLP_SIMPLEX_STATUS, messages_)
+                              << numberIterations_ << objectiveValue();
+                    handler_->printing(sumPrimalInfeasibilities_ > 0.0)
+                              << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
+                    handler_->printing(sumDualInfeasibilities_ > 0.0)
+                              << sumDualInfeasibilities_ << numberDualInfeasibilities_;
+                    handler_->printing(numberDualInfeasibilitiesWithoutFree_
+                                       < numberDualInfeasibilities_)
+                              << numberDualInfeasibilitiesWithoutFree_;
+                    handler_->message() << CoinMessageEol;
+               }
+          }
+          ClpSimplex * saveModel = NULL;
+          int stopSprint = -1;
+          int sprintPass = 0;
+          int reasonableSprintIteration = 0;
+          int lastSprintIteration = 0;
+          double lastObjectiveValue = COIN_DBL_MAX;
+          // Start check for cycles
+          progress_.fillFromModel(this);
+          progress_.startCheck();
+          /*
+            Status of problem:
+            0 - optimal
+            1 - infeasible
+            2 - unbounded
+            -1 - iterating
+            -2 - factorization wanted
+            -3 - redo checking without factorization
+            -4 - looks infeasible
+            -5 - looks unbounded
+          */
+          originalCost = CoinCopyOfArray(cost_, numberColumns_ + numberRows_);
+          originalLower = CoinCopyOfArray(lower_, numberColumns_ + numberRows_);
+          originalUpper = CoinCopyOfArray(upper_, numberColumns_ + numberRows_);
+          while (problemStatus_ < 0) {
+               int iRow, iColumn;
+               // clear
+               for (iRow = 0; iRow < 4; iRow++) {
+                    rowArray_[iRow]->clear();
+               }
+
+               for (iColumn = 0; iColumn < 2; iColumn++) {
+                    columnArray_[iColumn]->clear();
+               }
+
+               // give matrix (and model costs and bounds a chance to be
+               // refreshed (normally null)
+               matrix_->refresh(this);
+               // If getting nowhere - why not give it a kick
+#if 1
+               if (perturbation_ < 101 && numberIterations_ > 2 * (numberRows_ + numberColumns_) && (specialOptions_ & 4) == 0
+                         && initialStatus != 10) {
+                    perturb(1);
+                    matrix_->rhsOffset(this, true, false);
+               }
+#endif
+               // If we have done no iterations - special
+               if (lastGoodIteration_ == numberIterations_ && factorType)
+                    factorType = 3;
+               if (saveModel) {
+                    // Doing sprint
+                    if (sequenceIn_ < 0 || numberIterations_ >= stopSprint) {
+                         problemStatus_ = -1;
+                         originalModel(saveModel);
+                         saveModel = NULL;
+                         if (sequenceIn_ < 0 && numberIterations_ < reasonableSprintIteration &&
+                                   sprintPass > 100)
+                              primalColumnPivot_->switchOffSprint();
+                         //lastSprintIteration=numberIterations_;
+                         COIN_DETAIL_PRINT(printf("End small model\n"));
+                    }
+               }
+
+               // may factorize, checks if problem finished
+               statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true, ifValuesPass, saveModel);
+               if (initialStatus == 10) {
+                    // cleanup phase
+                    if(initialIterations != numberIterations_) {
+                         if (numberDualInfeasibilities_ > 10000 && numberDualInfeasibilities_ > 10 * initialNegDjs) {
+                              // getting worse - try perturbing
+                              if (perturbation_ < 101 && (specialOptions_ & 4) == 0) {
+                                   perturb(1);
+                                   matrix_->rhsOffset(this, true, false);
+                                   statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true, ifValuesPass, saveModel);
+                              }
+                         }
+                    } else {
+                         // save number of negative djs
+                         if (!numberPrimalInfeasibilities_)
+                              initialNegDjs = numberDualInfeasibilities_;
+                         // make sure weight won't be changed
+                         if (infeasibilityCost_ == 1.0e10)
+                              infeasibilityCost_ = 1.000001e10;
+                    }
+               }
+               // See if sprint says redo because of problems
+               if (numberDualInfeasibilities_ == -776) {
+                    // Need new set of variables
+                    problemStatus_ = -1;
+                    originalModel(saveModel);
+                    saveModel = NULL;
+                    //lastSprintIteration=numberIterations_;
+                    COIN_DETAIL_PRINT(printf("End small model after\n"));
+                    statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true, ifValuesPass, saveModel);
+               }
+               int numberSprintIterations = 0;
+               int numberSprintColumns = primalColumnPivot_->numberSprintColumns(numberSprintIterations);
+               if (problemStatus_ == 777) {
+                    // problems so do one pass with normal
+                    problemStatus_ = -1;
+                    originalModel(saveModel);
+                    saveModel = NULL;
+                    // Skip factorization
+                    //statusOfProblemInPrimal(lastCleaned,factorType,&progress_,false,saveModel);
+                    statusOfProblemInPrimal(lastCleaned, factorType, &progress_, true, ifValuesPass, saveModel);
+               } else if (problemStatus_ < 0 && !saveModel && numberSprintColumns && firstFree_ < 0) {
+                    int numberSort = 0;
+                    int numberFixed = 0;
+                    int numberBasic = 0;
+                    reasonableSprintIteration = numberIterations_ + 100;
+                    int * whichColumns = new int[numberColumns_];
+                    double * weight = new double[numberColumns_];
+                    int numberNegative = 0;
+                    double sumNegative = 0.0;
+                    // now massage weight so all basic in plus good djs
+                    for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
+                         double dj = dj_[iColumn];
+                         switch(getColumnStatus(iColumn)) {
+
+                         case basic:
+                              dj = -1.0e50;
+                              numberBasic++;
+                              break;
+                         case atUpperBound:
+                              dj = -dj;
+                              break;
+                         case isFixed:
+                              dj = 1.0e50;
+                              numberFixed++;
+                              break;
+                         case atLowerBound:
+                              dj = dj;
+                              break;
+                         case isFree:
+                              dj = -100.0 * fabs(dj);
+                              break;
+                         case superBasic:
+                              dj = -100.0 * fabs(dj);
+                              break;
+                         }
+                         if (dj < -dualTolerance_ && dj > -1.0e50) {
+                              numberNegative++;
+                              sumNegative -= dj;
+                         }
+                         weight[iColumn] = dj;
+                         whichColumns[iColumn] = iColumn;
+                    }
+                    handler_->message(CLP_SPRINT, messages_)
+                              << sprintPass << numberIterations_ - lastSprintIteration << objectiveValue() << sumNegative
+                              << numberNegative
+                              << CoinMessageEol;
+                    sprintPass++;
+                    lastSprintIteration = numberIterations_;
+                    if (objectiveValue()*optimizationDirection_ > lastObjectiveValue - 1.0e-7 && sprintPass > 5) {
+                         // switch off
+		      COIN_DETAIL_PRINT(printf("Switching off sprint\n"));
+                         primalColumnPivot_->switchOffSprint();
+                    } else {
+                         lastObjectiveValue = objectiveValue() * optimizationDirection_;
+                         // sort
+                         CoinSort_2(weight, weight + numberColumns_, whichColumns);
+                         numberSort = CoinMin(numberColumns_ - numberFixed, numberBasic + numberSprintColumns);
+                         // Sort to make consistent ?
+                         std::sort(whichColumns, whichColumns + numberSort);
+                         saveModel = new ClpSimplex(this, numberSort, whichColumns);
+                         delete [] whichColumns;
+                         delete [] weight;
+                         // Skip factorization
+                         //statusOfProblemInPrimal(lastCleaned,factorType,&progress_,false,saveModel);
+                         //statusOfProblemInPrimal(lastCleaned,factorType,&progress_,true,saveModel);
+                         stopSprint = numberIterations_ + numberSprintIterations;
+                         COIN_DETAIL_PRINT(printf("Sprint with %d columns for %d iterations\n",
+						  numberSprintColumns, numberSprintIterations));
+                    }
+               }
+
+               // Say good factorization
+               factorType = 1;
+
+               // Say no pivot has occurred (for steepest edge and updates)
+               pivotRow_ = -2;
+
+               // exit if victory declared
+               if (problemStatus_ >= 0) {
+                    if (originalCost) {
+                         // find number nonbasic with zero reduced costs
+                         int numberDegen = 0;
+                         int numberTotal = numberColumns_; //+numberRows_;
+                         for (int i = 0; i < numberTotal; i++) {
+                              cost_[i] = 0.0;
+                              if (getStatus(i) == atLowerBound) {
+                                   if (dj_[i] <= dualTolerance_) {
+                                        cost_[i] = numberTotal - i + randomNumberGenerator_.randomDouble() * 0.5;
+                                        numberDegen++;
+                                   } else {
+                                        // fix
+                                        cost_[i] = 1.0e10; //upper_[i]=lower_[i];
+                                   }
+                              } else if (getStatus(i) == atUpperBound) {
+                                   if (dj_[i] >= -dualTolerance_) {
+                                        cost_[i] = (numberTotal - i) + randomNumberGenerator_.randomDouble() * 0.5;
+                                        numberDegen++;
+                                   } else {
+                                        // fix
+                                        cost_[i] = -1.0e10; //lower_[i]=upper_[i];
+                                   }
+                              } else if (getStatus(i) == basic) {
+                                   cost_[i] = (numberTotal - i) + randomNumberGenerator_.randomDouble() * 0.5;
+                              }
+                         }
+                         problemStatus_ = -1;
+                         lastObjectiveValue = COIN_DBL_MAX;
+                         // Start check for cycles
+                         progress_.fillFromModel(this);
+                         progress_.startCheck();
+                         COIN_DETAIL_PRINT(printf("%d degenerate after %d iterations\n", numberDegen,
+						  numberIterations_));
+                         if (!numberDegen) {
+                              CoinMemcpyN(originalCost, numberTotal, cost_);
+                              delete [] originalCost;
+                              originalCost = NULL;
+                              CoinMemcpyN(originalLower, numberTotal, lower_);
+                              delete [] originalLower;
+                              CoinMemcpyN(originalUpper, numberTotal, upper_);
+                              delete [] originalUpper;
+                         }
+                         delete nonLinearCost_;
+                         nonLinearCost_ = new ClpNonLinearCost(this);
+                         progress_.endOddState();
+                         continue;
+                    } else {
+		      COIN_DETAIL_PRINT(printf("exiting after %d iterations\n", numberIterations_));
+                         break;
+                    }
+               }
+
+               // test for maximum iterations
+               if (hitMaximumIterations() || (ifValuesPass == 2 && firstFree_ < 0)) {
+                    problemStatus_ = 3;
+                    break;
+               }
+
+               if (firstFree_ < 0) {
+                    if (ifValuesPass) {
+                         // end of values pass
+                         ifValuesPass = 0;
+                         int status = eventHandler_->event(ClpEventHandler::endOfValuesPass);
+                         if (status >= 0) {
+                              problemStatus_ = 5;
+                              secondaryStatus_ = ClpEventHandler::endOfValuesPass;
+                              break;
+                         }
+                    }
+               }
+               // Check event
+               {
+                    int status = eventHandler_->event(ClpEventHandler::endOfFactorization);
+                    if (status >= 0) {
+                         problemStatus_ = 5;
+                         secondaryStatus_ = ClpEventHandler::endOfFactorization;
+                         break;
+                    }
+               }
+               // Iterate
+               whileIterating(ifValuesPass ? 1 : 0);
+          }
+     }
+     assert (!originalCost);
+     // if infeasible get real values
+     //printf("XXXXY final cost %g\n",infeasibilityCost_);
+     progress_.initialWeight_ = 0.0;
+     if (problemStatus_ == 1 && secondaryStatus_ != 6) {
+          infeasibilityCost_ = 0.0;
+          createRim(1 + 4);
+          nonLinearCost_->checkInfeasibilities(0.0);
+          sumPrimalInfeasibilities_ = nonLinearCost_->sumInfeasibilities();
+          numberPrimalInfeasibilities_ = nonLinearCost_->numberInfeasibilities();
+          // and get good feasible duals
+          computeDuals(NULL);
+     }
+     // Stop can skip some things in transposeTimes
+     specialOptions_ &= ~131072;
+     // clean up
+     unflag();
+     finish(0);
+     restoreData(data);
+     return problemStatus_;
+}
diff --git a/cbits/coin/ClpSimplexPrimal.hpp b/cbits/coin/ClpSimplexPrimal.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSimplexPrimal.hpp
@@ -0,0 +1,244 @@
+/* $Id: ClpSimplexPrimal.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef ClpSimplexPrimal_H
+#define ClpSimplexPrimal_H
+
+#include "ClpSimplex.hpp"
+
+/** This solves LPs using the primal simplex method
+
+    It inherits from ClpSimplex.  It has no data of its own and
+    is never created - only cast from a ClpSimplex object at algorithm time.
+
+*/
+
+class ClpSimplexPrimal : public ClpSimplex {
+
+public:
+
+     /**@name Description of algorithm */
+     //@{
+     /** Primal algorithm
+
+         Method
+
+        It tries to be a single phase approach with a weight of 1.0 being
+        given to getting optimal and a weight of infeasibilityCost_ being
+        given to getting primal feasible.  In this version I have tried to
+        be clever in a stupid way.  The idea of fake bounds in dual
+        seems to work so the primal analogue would be that of getting
+        bounds on reduced costs (by a presolve approach) and using
+        these for being above or below feasible region.  I decided to waste
+        memory and keep these explicitly.  This allows for non-linear
+        costs!  I have not tested non-linear costs but will be glad
+        to do something if a reasonable example is provided.
+
+        The code is designed to take advantage of sparsity so arrays are
+        seldom zeroed out from scratch or gone over in their entirety.
+        The only exception is a full scan to find incoming variable for
+        Dantzig row choice.  For steepest edge we keep an updated list
+        of dual infeasibilities (actually squares).
+        On easy problems we don't need full scan - just
+        pick first reasonable.  This method has not been coded.
+
+        One problem is how to tackle degeneracy and accuracy.  At present
+        I am using the modification of costs which I put in OSL and which was
+        extended by Gill et al.  I am still not sure whether we will also
+        need explicit perturbation.
+
+        The flow of primal is three while loops as follows:
+
+        while (not finished) {
+
+          while (not clean solution) {
+
+             Factorize and/or clean up solution by changing bounds so
+         primal feasible.  If looks finished check fake primal bounds.
+         Repeat until status is iterating (-1) or finished (0,1,2)
+
+          }
+
+          while (status==-1) {
+
+            Iterate until no pivot in or out or time to re-factorize.
+
+            Flow is:
+
+            choose pivot column (incoming variable).  if none then
+        we are primal feasible so looks as if done but we need to
+        break and check bounds etc.
+
+        Get pivot column in tableau
+
+            Choose outgoing row.  If we don't find one then we look
+        primal unbounded so break and check bounds etc.  (Also the
+        pivot tolerance is larger after any iterations so that may be
+        reason)
+
+            If we do find outgoing row, we may have to adjust costs to
+        keep going forwards (anti-degeneracy).  Check pivot will be stable
+        and if unstable throw away iteration and break to re-factorize.
+        If minor error re-factorize after iteration.
+
+        Update everything (this may involve changing bounds on
+        variables to stay primal feasible.
+
+          }
+
+        }
+
+        TODO's (or maybe not)
+
+        At present we never check we are going forwards.  I overdid that in
+        OSL so will try and make a last resort.
+
+        Needs partial scan pivot in option.
+
+        May need other anti-degeneracy measures, especially if we try and use
+        loose tolerances as a way to solve in fewer iterations.
+
+        I like idea of dynamic scaling.  This gives opportunity to decouple
+        different implications of scaling for accuracy, iteration count and
+        feasibility tolerance.
+
+        for use of exotic parameter startFinishoptions see Clpsimplex.hpp
+     */
+
+     int primal(int ifValuesPass = 0, int startFinishOptions = 0);
+     //@}
+
+     /**@name For advanced users */
+     //@{
+     /// Do not change infeasibility cost and always say optimal
+     void alwaysOptimal(bool onOff);
+     bool alwaysOptimal() const;
+     /** Normally outgoing variables can go out to slightly negative
+         values (but within tolerance) - this is to help stability and
+         and degeneracy.  This can be switched off
+     */
+     void exactOutgoing(bool onOff);
+     bool exactOutgoing() const;
+     //@}
+
+     /**@name Functions used in primal */
+     //@{
+     /** This has the flow between re-factorizations
+
+         Returns a code to say where decision to exit was made
+         Problem status set to:
+
+         -2 re-factorize
+         -4 Looks optimal/infeasible
+         -5 Looks unbounded
+         +3 max iterations
+
+         valuesOption has original value of valuesPass
+      */
+     int whileIterating(int valuesOption);
+
+     /** Do last half of an iteration.  This is split out so people can
+         force incoming variable.  If solveType_ is 2 then this may
+         re-factorize while normally it would exit to re-factorize.
+         Return codes
+         Reasons to come out (normal mode/user mode):
+         -1 normal
+         -2 factorize now - good iteration/ NA
+         -3 slight inaccuracy - refactorize - iteration done/ same but factor done
+         -4 inaccuracy - refactorize - no iteration/ NA
+         -5 something flagged - go round again/ pivot not possible
+         +2 looks unbounded
+         +3 max iterations (iteration done)
+
+         With solveType_ ==2 this should
+         Pivot in a variable and choose an outgoing one.  Assumes primal
+         feasible - will not go through a bound.  Returns step length in theta
+         Returns ray in ray_
+     */
+     int pivotResult(int ifValuesPass = 0);
+
+
+     /** The primals are updated by the given array.
+         Returns number of infeasibilities.
+         After rowArray will have cost changes for use next iteration
+     */
+     int updatePrimalsInPrimal(CoinIndexedVector * rowArray,
+                               double theta,
+                               double & objectiveChange,
+                               int valuesPass);
+     /**
+         Row array has pivot column
+         This chooses pivot row.
+         Rhs array is used for distance to next bound (for speed)
+         For speed, we may need to go to a bucket approach when many
+         variables go through bounds
+         If valuesPass non-zero then compute dj for direction
+     */
+     void primalRow(CoinIndexedVector * rowArray,
+                    CoinIndexedVector * rhsArray,
+                    CoinIndexedVector * spareArray,
+                    int valuesPass);
+     /**
+         Chooses primal pivot column
+         updateArray has cost updates (also use pivotRow_ from last iteration)
+         Would be faster with separate region to scan
+         and will have this (with square of infeasibility) when steepest
+         For easy problems we can just choose one of the first columns we look at
+     */
+     void primalColumn(CoinIndexedVector * updateArray,
+                       CoinIndexedVector * spareRow1,
+                       CoinIndexedVector * spareRow2,
+                       CoinIndexedVector * spareColumn1,
+                       CoinIndexedVector * spareColumn2);
+
+     /** Checks if tentative optimal actually means unbounded in primal
+         Returns -3 if not, 2 if is unbounded */
+     int checkUnbounded(CoinIndexedVector * ray, CoinIndexedVector * spare,
+                        double changeCost);
+     /**  Refactorizes if necessary
+          Checks if finished.  Updates status.
+          lastCleaned refers to iteration at which some objective/feasibility
+          cleaning too place.
+
+          type - 0 initial so set up save arrays etc
+               - 1 normal -if good update save
+           - 2 restoring from saved
+          saveModel is normally NULL but may not be if doing Sprint
+     */
+     void statusOfProblemInPrimal(int & lastCleaned, int type,
+                                  ClpSimplexProgress * progress,
+                                  bool doFactorization,
+                                  int ifValuesPass,
+                                  ClpSimplex * saveModel = NULL);
+     /// Perturbs problem (method depends on perturbation())
+     void perturb(int type);
+     /// Take off effect of perturbation and say whether to try dual
+     bool unPerturb();
+     /// Unflag all variables and return number unflagged
+     int unflag();
+     /** Get next superbasic -1 if none,
+         Normal type is 1
+         If type is 3 then initializes sorted list
+         if 2 uses list.
+     */
+     int nextSuperBasic(int superBasicType, CoinIndexedVector * columnArray);
+
+     /// Create primal ray
+     void primalRay(CoinIndexedVector * rowArray);
+     /// Clears all bits and clears rowArray[1] etc
+     void clearAll();
+
+     /// Sort of lexicographic resolve
+     int lexSolve();
+
+     //@}
+};
+#endif
+
diff --git a/cbits/coin/ClpSolve.cpp b/cbits/coin/ClpSolve.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSolve.cpp
@@ -0,0 +1,5429 @@
+/* $Id: ClpSolve.cpp 1989 2013-11-11 17:27:32Z forrest $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// This file has higher level solve functions
+
+#include "CoinPragma.hpp"
+#include "ClpConfig.h"
+
+// check already here if COIN_HAS_GLPK is defined, since we do not want to get confused by a COIN_HAS_GLPK in config_coinutils.h
+#if defined(COIN_HAS_AMD) || defined(COIN_HAS_CHOLMOD) || defined(COIN_HAS_GLPK)
+#define UFL_BARRIER
+#endif
+
+#include <math.h>
+
+#include "CoinHelperFunctions.hpp"
+#include "ClpHelperFunctions.hpp"
+#include "CoinSort.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpSimplexOther.hpp"
+#include "ClpSimplexDual.hpp"
+#ifndef SLIM_CLP
+#include "ClpQuadraticObjective.hpp"
+#include "ClpInterior.hpp"
+#include "ClpCholeskyDense.hpp"
+#include "ClpCholeskyBase.hpp"
+#include "ClpPlusMinusOneMatrix.hpp"
+#include "ClpNetworkMatrix.hpp"
+#endif
+#include "ClpEventHandler.hpp"
+#include "ClpLinearObjective.hpp"
+#include "ClpSolve.hpp"
+#include "ClpPackedMatrix.hpp"
+#include "ClpMessage.hpp"
+#include "CoinTime.hpp"
+#if CLP_HAS_ABC
+#include "CoinAbcCommon.hpp"
+#endif
+#ifdef ABC_INHERIT
+#include "AbcSimplex.hpp"
+#include "AbcSimplexFactorization.hpp"
+#endif
+double zz_slack_value=0.0;
+
+#include "ClpPresolve.hpp"
+#ifndef SLIM_CLP
+#include "Idiot.hpp"
+#ifdef COIN_HAS_VOL
+#include "VolVolume.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinMpsIO.hpp"
+//#############################################################################
+
+class lpHook : public VOL_user_hooks {
+private:
+     lpHook(const lpHook&);
+     lpHook& operator=(const lpHook&);
+private:
+     /// Pointer to dense vector of structural variable upper bounds
+     double  *colupper_;
+     /// Pointer to dense vector of structural variable lower bounds
+     double  *collower_;
+     /// Pointer to dense vector of objective coefficients
+     double  *objcoeffs_;
+     /// Pointer to dense vector of right hand sides
+     double  *rhs_;
+     /// Pointer to dense vector of senses
+     char    *sense_;
+
+     /// The problem matrix in a row ordered form
+     CoinPackedMatrix rowMatrix_;
+     /// The problem matrix in a column ordered form
+     CoinPackedMatrix colMatrix_;
+
+public:
+     lpHook(double* clb, double* cub, double* obj,
+            double* rhs, char* sense, const CoinPackedMatrix& mat);
+     virtual ~lpHook();
+
+public:
+     // for all hooks: return value of -1 means that volume should quit
+     /** compute reduced costs
+         @param u (IN) the dual variables
+         @param rc (OUT) the reduced cost with respect to the dual values
+     */
+     virtual int compute_rc(const VOL_dvector& u, VOL_dvector& rc);
+
+     /** Solve the subproblem for the subgradient step.
+         @param dual (IN) the dual variables
+         @param rc (IN) the reduced cost with respect to the dual values
+         @param lcost (OUT) the lagrangean cost with respect to the dual values
+         @param x (OUT) the primal result of solving the subproblem
+         @param v (OUT) b-Ax for the relaxed constraints
+         @param pcost (OUT) the primal objective value of <code>x</code>
+     */
+     virtual int solve_subproblem(const VOL_dvector& dual, const VOL_dvector& rc,
+                                  double& lcost, VOL_dvector& x, VOL_dvector& v,
+                                  double& pcost);
+     /** Starting from the primal vector x, run a heuristic to produce
+         an integer solution
+         @param x (IN) the primal vector
+         @param heur_val (OUT) the value of the integer solution (return
+         <code>DBL_MAX</code> here if no feas sol was found
+     */
+     virtual int heuristics(const VOL_problem& p,
+                            const VOL_dvector& x, double& heur_val) {
+          return 0;
+     }
+};
+
+//#############################################################################
+
+lpHook::lpHook(double* clb, double* cub, double* obj,
+               double* rhs, char* sense,
+               const CoinPackedMatrix& mat)
+{
+     colupper_ = cub;
+     collower_ = clb;
+     objcoeffs_ = obj;
+     rhs_ = rhs;
+     sense_ = sense;
+     assert (mat.isColOrdered());
+     colMatrix_.copyOf(mat);
+     rowMatrix_.reverseOrderedCopyOf(mat);
+}
+
+//-----------------------------------------------------------------------------
+
+lpHook::~lpHook()
+{
+}
+
+//#############################################################################
+
+int
+lpHook::compute_rc(const VOL_dvector& u, VOL_dvector& rc)
+{
+     rowMatrix_.transposeTimes(u.v, rc.v);
+     const int psize = rowMatrix_.getNumCols();
+
+     for (int i = 0; i < psize; ++i)
+          rc[i] = objcoeffs_[i] - rc[i];
+     return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+int
+lpHook::solve_subproblem(const VOL_dvector& dual, const VOL_dvector& rc,
+                         double& lcost, VOL_dvector& x, VOL_dvector& v,
+                         double& pcost)
+{
+     int i;
+     const int psize = x.size();
+     const int dsize = v.size();
+
+     // compute the lagrangean solution corresponding to the reduced costs
+     for (i = 0; i < psize; ++i)
+          x[i] = (rc[i] >= 0.0) ? collower_[i] : colupper_[i];
+
+     // compute the lagrangean value (rhs*dual + primal*rc)
+     lcost = 0;
+     for (i = 0; i < dsize; ++i)
+          lcost += rhs_[i] * dual[i];
+     for (i = 0; i < psize; ++i)
+          lcost += x[i] * rc[i];
+
+     // compute the rhs - lhs
+     colMatrix_.times(x.v, v.v);
+     for (i = 0; i < dsize; ++i)
+          v[i] = rhs_[i] - v[i];
+
+     // compute the lagrangean primal objective
+     pcost = 0;
+     for (i = 0; i < psize; ++i)
+          pcost += x[i] * objcoeffs_[i];
+
+     return 0;
+}
+
+//#############################################################################
+/** A quick inlined function to convert from lb/ub style constraint
+    definition to sense/rhs/range style */
+inline void
+convertBoundToSense(const double lower, const double upper,
+                    char& sense, double& right,
+                    double& range)
+{
+     range = 0.0;
+     if (lower > -1.0e20) {
+          if (upper < 1.0e20) {
+               right = upper;
+               if (upper == lower) {
+                    sense = 'E';
+               } else {
+                    sense = 'R';
+                    range = upper - lower;
+               }
+          } else {
+               sense = 'G';
+               right = lower;
+          }
+     } else {
+          if (upper < 1.0e20) {
+               sense = 'L';
+               right = upper;
+          } else {
+               sense = 'N';
+               right = 0.0;
+          }
+     }
+}
+
+static int
+solveWithVolume(ClpSimplex * model, int numberPasses, int doIdiot)
+{
+     VOL_problem volprob;
+     volprob.parm.gap_rel_precision = 0.00001;
+     volprob.parm.maxsgriters = 3000;
+     if(numberPasses > 3000) {
+          volprob.parm.maxsgriters = numberPasses;
+          volprob.parm.primal_abs_precision = 0.0;
+          volprob.parm.minimum_rel_ascent = 0.00001;
+     } else if (doIdiot > 0) {
+          volprob.parm.maxsgriters = doIdiot;
+     }
+     if (model->logLevel() < 2)
+          volprob.parm.printflag = 0;
+     else
+          volprob.parm.printflag = 3;
+     const CoinPackedMatrix* mat = model->matrix();
+     int psize = model->numberColumns();
+     int dsize = model->numberRows();
+     char * sense = new char[dsize];
+     double * rhs = new double [dsize];
+
+     // Set the lb/ub on the duals
+     volprob.dsize = dsize;
+     volprob.psize = psize;
+     volprob.dual_lb.allocate(dsize);
+     volprob.dual_ub.allocate(dsize);
+     int i;
+     const double * rowLower = model->rowLower();
+     const double * rowUpper = model->rowUpper();
+     for (i = 0; i < dsize; ++i) {
+          double range;
+          convertBoundToSense(rowLower[i], rowUpper[i],
+                              sense[i], rhs[i], range);
+          switch (sense[i]) {
+          case 'E':
+               volprob.dual_lb[i] = -1.0e31;
+               volprob.dual_ub[i] = 1.0e31;
+               break;
+          case 'L':
+               volprob.dual_lb[i] = -1.0e31;
+               volprob.dual_ub[i] = 0.0;
+               break;
+          case 'G':
+               volprob.dual_lb[i] = 0.0;
+               volprob.dual_ub[i] = 1.0e31;
+               break;
+          default:
+               printf("Volume Algorithm can't work if there is a non ELG row\n");
+               return 1;
+          }
+     }
+     // Check bounds
+     double * saveLower = model->columnLower();
+     double * saveUpper = model->columnUpper();
+     bool good = true;
+     for (i = 0; i < psize; i++) {
+          if (saveLower[i] < -1.0e20 || saveUpper[i] > 1.0e20) {
+               good = false;
+               break;
+          }
+     }
+     if (!good) {
+          saveLower = CoinCopyOfArray(model->columnLower(), psize);
+          saveUpper = CoinCopyOfArray(model->columnUpper(), psize);
+          for (i = 0; i < psize; i++) {
+               if (saveLower[i] < -1.0e20)
+                    saveLower[i] = -1.0e20;
+               if(saveUpper[i] > 1.0e20)
+                    saveUpper[i] = 1.0e20;
+          }
+     }
+     lpHook myHook(saveLower, saveUpper,
+                   model->objective(),
+                   rhs, sense, *mat);
+
+     volprob.solve(myHook, false /* no warmstart */);
+
+     if (saveLower != model->columnLower()) {
+          delete [] saveLower;
+          delete [] saveUpper;
+     }
+     //------------- extract the solution ---------------------------
+
+     //printf("Best lagrangean value: %f\n", volprob.value);
+
+     double avg = 0;
+     for (i = 0; i < dsize; ++i) {
+          switch (sense[i]) {
+          case 'E':
+               avg += CoinAbs(volprob.viol[i]);
+               break;
+          case 'L':
+               if (volprob.viol[i] < 0)
+                    avg +=  (-volprob.viol[i]);
+               break;
+          case 'G':
+               if (volprob.viol[i] > 0)
+                    avg +=  volprob.viol[i];
+               break;
+          }
+     }
+
+     //printf("Average primal constraint violation: %f\n", avg/dsize);
+
+     // volprob.dsol contains the dual solution (dual feasible)
+     // volprob.psol contains the primal solution
+     //              (NOT necessarily primal feasible)
+     CoinMemcpyN(volprob.dsol.v, dsize, model->dualRowSolution());
+     CoinMemcpyN(volprob.psol.v, psize, model->primalColumnSolution());
+     return 0;
+}
+#endif
+static ClpInterior * currentModel2 = NULL;
+#endif
+//#############################################################################
+// Allow for interrupts
+// But is this threadsafe ? (so switched off by option)
+
+#include "CoinSignal.hpp"
+static ClpSimplex * currentModel = NULL;
+#ifdef ABC_INHERIT
+static AbcSimplex * currentAbcModel = NULL;
+#endif
+
+extern "C" {
+     static void
+#if defined(_MSC_VER)
+     __cdecl
+#endif // _MSC_VER
+     signal_handler(int /*whichSignal*/)
+     {
+          if (currentModel != NULL)
+               currentModel->setMaximumIterations(0); // stop at next iterations
+#ifdef ABC_INHERIT
+          if (currentAbcModel != NULL)
+               currentAbcModel->setMaximumIterations(0); // stop at next iterations
+#endif
+#ifndef SLIM_CLP
+          if (currentModel2 != NULL)
+               currentModel2->setMaximumBarrierIterations(0); // stop at next iterations
+#endif
+          return;
+     }
+}
+#if ABC_INSTRUMENT>1
+int abcPricing[20];
+int abcPricingDense[20];
+static int trueNumberRows;
+static int numberTypes;
+#define MAX_TYPES 25
+#define MAX_COUNT 20
+#define MAX_FRACTION 101
+static char * types[MAX_TYPES];
+static double counts[MAX_TYPES][MAX_COUNT];
+static double countsFraction[MAX_TYPES][MAX_FRACTION];
+static double * currentCounts;
+static double * currentCountsFraction;
+static int currentType;
+static double workMultiplier[MAX_TYPES];
+static double work[MAX_TYPES];
+static double currentWork;
+static double otherWork[MAX_TYPES];
+static int timesCalled[MAX_TYPES];
+static int timesStarted[MAX_TYPES];
+static int fractionDivider;
+void instrument_initialize(int numberRows)
+{
+  trueNumberRows=numberRows;
+  numberTypes=0;
+  memset(counts,0,sizeof(counts));
+  currentCounts=NULL;
+  memset(countsFraction,0,sizeof(countsFraction));
+  currentCountsFraction=NULL;
+  memset(workMultiplier,0,sizeof(workMultiplier));
+  memset(work,0,sizeof(work));
+  memset(otherWork,0,sizeof(otherWork));
+  memset(timesCalled,0,sizeof(timesCalled));
+  memset(timesStarted,0,sizeof(timesStarted));
+  currentType=-1;
+  fractionDivider=(numberRows+MAX_FRACTION-2)/(MAX_FRACTION-1);
+}
+void instrument_start(const char * type,int numberRowsEtc)
+{
+  if (currentType>=0)
+    instrument_end();
+  currentType=-1;
+  currentWork=0.0;
+  for (int i=0;i<numberTypes;i++) {
+    if (!strcmp(types[i],type)) {
+      currentType=i;
+      break;
+    }
+  }
+  if (currentType==-1) {
+    assert (numberTypes<MAX_TYPES);
+    currentType=numberTypes;
+    types[numberTypes++]=strdup(type);
+  }
+  currentCounts = &counts[currentType][0];
+  currentCountsFraction = &countsFraction[currentType][0];
+  timesStarted[currentType]++;
+  assert (trueNumberRows);
+  workMultiplier[currentType]+=static_cast<double>(numberRowsEtc)/static_cast<double>(trueNumberRows);
+}
+void instrument_add(int count)
+{
+  assert (currentType>=0);
+  currentWork+=count;
+  timesCalled[currentType]++;
+  if (count<MAX_COUNT-1)
+    currentCounts[count]++;
+  else
+    currentCounts[MAX_COUNT-1]++;
+  assert(count/fractionDivider>=0&&count/fractionDivider<MAX_FRACTION);
+  currentCountsFraction[count/fractionDivider]++;
+}
+void instrument_do(const char * type,double count)
+{
+  int iType=-1;
+  for (int i=0;i<numberTypes;i++) {
+    if (!strcmp(types[i],type)) {
+      iType=i;
+      break;
+    }
+  }
+  if (iType==-1) {
+    assert (numberTypes<MAX_TYPES);
+    iType=numberTypes;
+    types[numberTypes++]=strdup(type);
+  }
+  timesStarted[iType]++;
+  otherWork[iType]+=count;
+}
+void instrument_end()
+{
+  work[currentType]+=currentWork;
+  currentType=-1;
+}
+void instrument_end_and_adjust(double factor)
+{
+  work[currentType]+=currentWork*factor;
+  currentType=-1;
+}
+void instrument_print()
+{
+  for (int iType=0;iType<numberTypes;iType++) {
+    currentCounts = &counts[iType][0];
+    currentCountsFraction = &countsFraction[iType][0];
+    if (!otherWork[iType]) {
+      printf("%s started %d times, used %d times, work %g (average length %.1f) multiplier %g\n",
+	     types[iType],timesStarted[iType],timesCalled[iType],
+	     work[iType],work[iType]/(timesCalled[iType]+1.0e-100),workMultiplier[iType]/(timesStarted[iType]+1.0e-100));
+      int n=0;
+      for (int i=0;i<MAX_COUNT-1;i++) {
+	if (currentCounts[i]) {
+	  if (n==5) {
+	    n=0;
+	    printf("\n");
+	  }
+	  n++;
+	  printf("(%d els,%.0f times) ",i,currentCounts[i]);
+	}
+      }
+      if (currentCounts[MAX_COUNT-1]) {
+	if (n==5) {
+	  n=0;
+	  printf("\n");
+	}
+	n++;
+	printf("(>=%d els,%.0f times) ",MAX_COUNT-1,currentCounts[MAX_COUNT-1]);
+      }
+      printf("\n");
+      int largestFraction;
+      int nBig=0;
+      for (largestFraction=MAX_FRACTION-1;largestFraction>=10;largestFraction--) {
+	double count = currentCountsFraction[largestFraction];
+	if (count&&largestFraction>10)
+	  nBig++;
+	if (nBig>4)
+	  break;
+      }
+      int chunk=(largestFraction+5)/10;
+      int lo=0;
+      for (int iChunk=0;iChunk<largestFraction;iChunk+=chunk) {
+	int hi=CoinMin(lo+chunk*fractionDivider,trueNumberRows);
+	double sum=0.0;
+	for (int i=iChunk;i<CoinMin(iChunk+chunk,MAX_FRACTION);i++)
+	  sum += currentCountsFraction[i];
+	if (sum)
+	  printf("(%d-%d %.0f) ",lo,hi,sum);
+	lo=hi;
+      }
+      for (int i=lo/fractionDivider;i<MAX_FRACTION;i++) {
+	if (currentCountsFraction[i])
+	  printf("(%d %.0f) ",i*fractionDivider,currentCountsFraction[i]);
+      }
+      printf("\n");
+    } else {
+      printf("%s started %d times, used %d times, work %g multiplier %g other work %g\n",
+	     types[iType],timesStarted[iType],timesCalled[iType],
+	     work[iType],workMultiplier[iType],otherWork[iType]);
+    }
+    free(types[iType]);
+  }
+}
+#endif
+#if ABC_PARALLEL==2
+#ifndef FAKE_CILK
+int number_cilk_workers=0;
+#include <cilk/cilk_api.h>
+#endif
+#endif
+#ifdef ABC_INHERIT
+void 
+ClpSimplex::dealWithAbc(int solveType, int startUp,
+			bool interrupt)
+{
+  if (!this->abcState()||!numberRows_||!numberColumns_) {
+    if (!solveType)
+      this->dual(0);
+    else
+      this->primal(startUp ? 1 : 0);
+  } else {
+    AbcSimplex * abcModel2=new AbcSimplex(*this);
+    if (interrupt)
+      currentAbcModel = abcModel2;
+    //if (abcSimplex_) {
+    // move factorization stuff
+    abcModel2->factorization()->synchronize(this->factorization(),abcModel2);
+    //}
+    //abcModel2->startPermanentArrays();
+    int crashState=abcModel2->abcState()&(256+512+1024);
+    abcModel2->setAbcState(CLP_ABC_WANTED|crashState);
+    int ifValuesPass=startUp ? 1 : 0;
+    // temp
+    if (fabs(this->primalTolerance()-1.001e-6)<0.999e-9) {
+      int type=1;
+      double diff=this->primalTolerance()-1.001e-6;
+      printf("Diff %g\n",diff);
+      if (fabs(diff-1.0e-10)<1.0e-13)
+	type=2;
+      else if (fabs(diff-1.0e-11)<1.0e-13)
+	type=3;
+#if 0
+      ClpSimplex * thisModel = static_cast<ClpSimplexOther *> (this)->dualOfModel(1.0,1.0);
+      if (thisModel) {
+	printf("Dual of model has %d rows and %d columns\n",
+	       thisModel->numberRows(), thisModel->numberColumns());
+	thisModel->setOptimizationDirection(1.0);
+	Idiot info(*thisModel);
+	info.setStrategy(512 | info.getStrategy());
+	// Allow for scaling
+	info.setStrategy(32 | info.getStrategy());
+	info.setStartingWeight(1.0e3);
+	info.setReduceIterations(6);
+	info.crash(50, this->messageHandler(), this->messagesPointer(),false);
+	// make sure later that primal solution in correct place
+	// and has correct sign
+	abcModel2->setupDualValuesPass(thisModel->primalColumnSolution(),
+				       thisModel->dualRowSolution(),type);
+	//thisModel->dual();
+	delete thisModel;
+      }
+#else
+      if (!solveType) {
+	this->dual(0);
+	abcModel2->setupDualValuesPass(this->dualRowSolution(),
+				       this->primalColumnSolution(),type);
+      } else {
+	ifValuesPass=1;
+	abcModel2->setStateOfProblem(abcModel2->stateOfProblem() | VALUES_PASS);
+	Idiot info(*abcModel2);
+	info.setStrategy(512 | info.getStrategy());
+	// Allow for scaling
+	info.setStrategy(32 | info.getStrategy());
+	info.setStartingWeight(1.0e3);
+	info.setReduceIterations(6);
+	info.crash(200, abcModel2->messageHandler(), abcModel2->messagesPointer(),false);
+	//memcpy(abcModel2->primalColumnSolution(),this->primalColumnSolution(),
+	//     this->numberColumns()*sizeof(double));
+      }
+#endif
+    }
+    char line[200];
+#if ABC_PARALLEL
+#if ABC_PARALLEL==2
+#ifndef FAKE_CILK
+    if (!number_cilk_workers) {
+      number_cilk_workers=__cilkrts_get_nworkers();
+      sprintf(line,"%d cilk workers",number_cilk_workers);
+      handler_->message(CLP_GENERAL, messages_)
+	<< line
+	<< CoinMessageEol;
+    }
+#endif
+#endif
+    int numberCpu=this->abcState()&15;
+    if (numberCpu==9) {
+      numberCpu=1;
+#if ABC_PARALLEL==2
+#ifndef FAKE_CILK
+      if (number_cilk_workers>1)
+      numberCpu=CoinMin(2*number_cilk_workers,8);
+#endif
+#endif
+    } else if (numberCpu==10) {
+      // maximum
+      numberCpu=4;
+    } else if (numberCpu==10) {
+      // decide
+      if (abcModel2->getNumElements()<5000)
+	numberCpu=1;
+#if ABC_PARALLEL==2
+#ifndef FAKE_CILK
+      else if (number_cilk_workers>1)
+	numberCpu=CoinMin(2*number_cilk_workers,8);
+#endif
+#endif
+      else
+	numberCpu=1;
+    } else {
+#if ABC_PARALLEL==2
+#if 0 //ndef FAKE_CILK
+      char temp[3];
+      sprintf(temp,"%d",numberCpu);
+      __cilkrts_set_param("nworkers",temp);
+#endif
+#endif
+    }
+    abcModel2->setParallelMode(numberCpu-1);
+#endif
+    //if (abcState()==3||abcState()==4) {
+    //abcModel2->setMoreSpecialOptions((65536*2)|abcModel2->moreSpecialOptions());
+    //}
+    //if (processTune>0&&processTune<8)
+    //abcModel2->setMoreSpecialOptions(abcModel2->moreSpecialOptions()|65536*processTune);
+#if ABC_INSTRUMENT
+    double startTimeCpu=CoinCpuTime();
+    double startTimeElapsed=CoinGetTimeOfDay();
+#if ABC_INSTRUMENT>1
+    memset(abcPricing,0,sizeof(abcPricing));
+    memset(abcPricingDense,0,sizeof(abcPricing));
+    instrument_initialize(abcModel2->numberRows());
+#endif
+#endif
+    if (!solveType) {
+      abcModel2->ClpSimplex::doAbcDual();
+    } else {
+      int saveOptions=abcModel2->specialOptions();
+      if (startUp==2)
+	abcModel2->setSpecialOptions(8192|saveOptions);
+      abcModel2->ClpSimplex::doAbcPrimal(ifValuesPass);
+      abcModel2->setSpecialOptions(saveOptions);
+    }
+#if ABC_INSTRUMENT
+    double timeCpu=CoinCpuTime()-startTimeCpu;
+    double timeElapsed=CoinGetTimeOfDay()-startTimeElapsed;
+    sprintf(line,"Cpu time for %s (%d rows, %d columns %d elements) %g elapsed %g ratio %g - %d iterations",
+	    this->problemName().c_str(),this->numberRows(),this->numberColumns(),
+	    this->getNumElements(),
+	    timeCpu,timeElapsed,timeElapsed ? timeCpu/timeElapsed : 1.0,abcModel2->numberIterations());
+    handler_->message(CLP_GENERAL, messages_)
+      << line
+      << CoinMessageEol;
+#if ABC_INSTRUMENT>1
+    {
+      int n;
+      n=0;
+      for (int i=0;i<20;i++) 
+	n+= abcPricing[i];
+      printf("CCSparse pricing done %d times",n);
+      int n2=0;
+      for (int i=0;i<20;i++) 
+	n2+= abcPricingDense[i];
+      if (n2) 
+	printf(" and dense pricing done %d times\n",n2);
+      else
+	printf("\n");
+      n=0;
+      printf ("CCS");
+      for (int i=0;i<19;i++) {
+	if (abcPricing[i]) {
+	  if (n==5) {
+	    n=0;
+	    printf("\nCCS");
+	  }
+	  n++;
+	  printf("(%d els,%d times) ",i,abcPricing[i]);
+	}
+      }
+      if (abcPricing[19]) {
+	if (n==5) {
+	  n=0;
+	  printf("\nCCS");
+	}
+	n++;
+	printf("(>=19 els,%d times) ",abcPricing[19]);
+      }
+      if (n2) {
+	printf ("CCD");
+	for (int i=0;i<19;i++) {
+	  if (abcPricingDense[i]) {
+	    if (n==5) {
+	      n=0;
+	      printf("\nCCD");
+	    }
+	    n++;
+	    int k1=(numberRows_/16)*i;;
+	    int k2=CoinMin(numberRows_,k1+(numberRows_/16)-1);
+	    printf("(%d-%d els,%d times) ",k1,k2,abcPricingDense[i]);
+	  }
+	}
+      }
+      printf("\n");
+    }
+    instrument_print();
+#endif
+#endif
+    abcModel2->moveStatusToClp(this);
+    //ClpModel::stopPermanentArrays();
+    this->setSpecialOptions(this->specialOptions()&~65536);
+#if 0
+    this->writeBasis("a.bas",true);
+    for (int i=0;i<this->numberRows();i++)
+      printf("%d %g\n",i,this->dualRowSolution()[i]);
+    this->dual();
+    this->writeBasis("b.bas",true);
+    for (int i=0;i<this->numberRows();i++)
+      printf("%d %g\n",i,this->dualRowSolution()[i]);
+#endif
+    // switch off initialSolve flag
+    moreSpecialOptions_ &= ~16384;
+    //this->setNumberIterations(abcModel2->numberIterations()+this->numberIterations());
+    delete abcModel2;
+  }
+}
+#endif
+/** General solve algorithm which can do presolve
+    special options (bits)
+    1 - do not perturb
+    2 - do not scale
+    4 - use crash (default allslack in dual, idiot in primal)
+    8 - all slack basis in primal
+    16 - switch off interrupt handling
+    32 - do not try and make plus minus one matrix
+    64 - do not use sprint even if problem looks good
+ */
+int
+ClpSimplex::initialSolve(ClpSolve & options)
+{
+     ClpSolve::SolveType method = options.getSolveType();
+     //ClpSolve::SolveType originalMethod=method;
+     ClpSolve::PresolveType presolve = options.getPresolveType();
+     int saveMaxIterations = maximumIterations();
+     int finalStatus = -1;
+     int numberIterations = 0;
+     double time1 = CoinCpuTime();
+     double timeX = time1;
+     double time2;
+     ClpMatrixBase * saveMatrix = NULL;
+     ClpObjective * savedObjective = NULL;
+     if (!objective_ || !matrix_) {
+          // totally empty
+          handler_->message(CLP_EMPTY_PROBLEM, messages_)
+                    << 0
+                    << 0
+                    << 0
+                    << CoinMessageEol;
+          return -1;
+     } else if (!numberRows_ || !numberColumns_ || !getNumElements()) {
+          presolve = ClpSolve::presolveOff;
+     }
+     if (objective_->type() >= 2 && optimizationDirection_ == 0) {
+          // pretend linear
+          savedObjective = objective_;
+          // make up objective
+          double * obj = new double[numberColumns_];
+          for (int i = 0; i < numberColumns_; i++) {
+               double l = fabs(columnLower_[i]);
+               double u = fabs(columnUpper_[i]);
+               obj[i] = 0.0;
+               if (CoinMin(l, u) < 1.0e20) {
+                    if (l < u)
+                         obj[i] = 1.0 + randomNumberGenerator_.randomDouble() * 1.0e-2;
+                    else
+                         obj[i] = -1.0 - randomNumberGenerator_.randomDouble() * 1.0e-2;
+               }
+          }
+          objective_ = new ClpLinearObjective(obj, numberColumns_);
+          delete [] obj;
+     }
+     ClpSimplex * model2 = this;
+     bool interrupt = (options.getSpecialOption(2) == 0);
+     CoinSighandler_t saveSignal = static_cast<CoinSighandler_t> (0);
+     if (interrupt) {
+          currentModel = model2;
+          // register signal handler
+          saveSignal = signal(SIGINT, signal_handler);
+     }
+     // If no status array - set up basis
+     if (!status_)
+          allSlackBasis();
+     ClpPresolve * pinfo = new ClpPresolve();
+     pinfo->setSubstitution(options.substitution());
+     int presolveOptions = options.presolveActions();
+     bool presolveToFile = (presolveOptions & 0x40000000) != 0;
+     presolveOptions &= ~0x40000000;
+     if ((presolveOptions & 0xffff) != 0)
+          pinfo->setPresolveActions(presolveOptions);
+     // switch off singletons to slacks
+     //pinfo->setDoSingletonColumn(false); // done by bits
+     int printOptions = options.getSpecialOption(5);
+     if ((printOptions & 1) != 0)
+          pinfo->statistics();
+     double timePresolve = 0.0;
+     double timeIdiot = 0.0;
+     double timeCore = 0.0;
+     eventHandler()->event(ClpEventHandler::presolveStart);
+     int savePerturbation = perturbation_;
+     int saveScaling = scalingFlag_;
+#ifndef SLIM_CLP
+#ifndef NO_RTTI
+     if (dynamic_cast< ClpNetworkMatrix*>(matrix_)) {
+          // network - switch off stuff
+          presolve = ClpSolve::presolveOff;
+     }
+#else
+     if (matrix_->type() == 11) {
+          // network - switch off stuff
+          presolve = ClpSolve::presolveOff;
+     }
+#endif
+#endif
+     if (presolve != ClpSolve::presolveOff) {
+          bool costedSlacks = false;
+#ifdef ABC_INHERIT
+          int numberPasses = 20;
+#else
+          int numberPasses = 5;
+#endif
+          if (presolve == ClpSolve::presolveNumber) {
+               numberPasses = options.getPresolvePasses();
+               presolve = ClpSolve::presolveOn;
+          } else if (presolve == ClpSolve::presolveNumberCost) {
+               numberPasses = options.getPresolvePasses();
+               presolve = ClpSolve::presolveOn;
+               costedSlacks = true;
+               // switch on singletons to slacks
+               pinfo->setDoSingletonColumn(true);
+               // gub stuff for testing
+               //pinfo->setDoGubrow(true);
+          }
+#ifndef CLP_NO_STD
+          if (presolveToFile) {
+               // PreSolve to file - not fully tested
+               printf("Presolving to file - presolve.save\n");
+               pinfo->presolvedModelToFile(*this, "presolve.save", dblParam_[ClpPresolveTolerance],
+                                          false, numberPasses);
+               model2 = this;
+          } else {
+#endif
+               model2 = pinfo->presolvedModel(*this, dblParam_[ClpPresolveTolerance],
+                                             false, numberPasses, true, costedSlacks);
+#ifndef CLP_NO_STD
+          }
+#endif
+          time2 = CoinCpuTime();
+          timePresolve = time2 - timeX;
+          handler_->message(CLP_INTERVAL_TIMING, messages_)
+                    << "Presolve" << timePresolve << time2 - time1
+                    << CoinMessageEol;
+          timeX = time2;
+          if (!model2) {
+               handler_->message(CLP_INFEASIBLE, messages_)
+                         << CoinMessageEol;
+               model2 = this;
+	       eventHandler()->event(ClpEventHandler::presolveInfeasible);
+               problemStatus_ = pinfo->presolveStatus(); 
+               if (options.infeasibleReturn() || (moreSpecialOptions_ & 1) != 0) {
+		 delete pinfo;
+                    return -1;
+               }
+               presolve = ClpSolve::presolveOff;
+	  } else {
+#if 0 //def ABC_INHERIT
+	    {
+	      AbcSimplex * abcModel2=new AbcSimplex(*model2);
+	      delete model2;
+	      model2=abcModel2;
+	      pinfo->setPresolvedModel(model2);
+	    }
+#else
+	    //ClpModel::stopPermanentArrays();
+	    //setSpecialOptions(specialOptions()&~65536);
+#endif
+	      model2->eventHandler()->setSimplex(model2);
+	      int rcode=model2->eventHandler()->event(ClpEventHandler::presolveSize);
+	      // see if too big or small
+	      if (rcode==2) {
+		  delete model2;
+		 delete pinfo;
+		  return -2;
+	      } else if (rcode==3) {
+		  delete model2;
+		 delete pinfo;
+		  return -3;
+	      }
+          }
+	  model2->setMoreSpecialOptions(model2->moreSpecialOptions()&(~1024));
+	  model2->eventHandler()->setSimplex(model2);
+          // We may be better off using original (but if dual leave because of bounds)
+          if (presolve != ClpSolve::presolveOff &&
+                    numberRows_ < 1.01 * model2->numberRows_ && numberColumns_ < 1.01 * model2->numberColumns_
+                    && model2 != this) {
+               if(method != ClpSolve::useDual ||
+                         (numberRows_ == model2->numberRows_ && numberColumns_ == model2->numberColumns_)) {
+                    delete model2;
+                    model2 = this;
+                    presolve = ClpSolve::presolveOff;
+               }
+          }
+     }
+     if (interrupt)
+          currentModel = model2;
+     // For below >0 overrides
+     // 0 means no, -1 means maybe
+     int doIdiot = 0;
+     int doCrash = 0;
+     int doSprint = 0;
+     int doSlp = 0;
+     int primalStartup = 1;
+     model2->eventHandler()->event(ClpEventHandler::presolveBeforeSolve);
+     bool tryItSave = false;
+     // switch to primal from automatic if just one cost entry
+     if (method == ClpSolve::automatic && model2->numberColumns() > 5000 &&
+               (specialOptions_ & 1024) != 0) {
+          int numberColumns = model2->numberColumns();
+          int numberRows = model2->numberRows();
+          const double * obj = model2->objective();
+          int nNon = 0;
+          for (int i = 0; i < numberColumns; i++) {
+               if (obj[i])
+                    nNon++;
+          }
+          if (nNon == 1) {
+#ifdef COIN_DEVELOP
+               printf("Forcing primal\n");
+#endif
+               method = ClpSolve::usePrimal;
+               tryItSave = numberRows > 200 && numberColumns > 2000 &&
+                           (numberColumns > 2 * numberRows || (specialOptions_ & 1024) != 0);
+          }
+     }
+     if (method != ClpSolve::useDual && method != ClpSolve::useBarrier
+               && method != ClpSolve::useBarrierNoCross) {
+          switch (options.getSpecialOption(1)) {
+          case 0:
+               doIdiot = -1;
+               doCrash = -1;
+               doSprint = -1;
+               break;
+          case 1:
+               doIdiot = 0;
+               doCrash = 1;
+               if (options.getExtraInfo(1) > 0)
+                    doCrash = options.getExtraInfo(1);
+               doSprint = 0;
+               break;
+          case 2:
+               doIdiot = 1;
+               if (options.getExtraInfo(1) > 0)
+                    doIdiot = options.getExtraInfo(1);
+               doCrash = 0;
+               doSprint = 0;
+               break;
+          case 3:
+               doIdiot = 0;
+               doCrash = 0;
+               doSprint = 1;
+               break;
+          case 4:
+               doIdiot = 0;
+               doCrash = 0;
+               doSprint = 0;
+               break;
+          case 5:
+               doIdiot = 0;
+               doCrash = -1;
+               doSprint = -1;
+               break;
+          case 6:
+               doIdiot = -1;
+               doCrash = -1;
+               doSprint = 0;
+               break;
+          case 7:
+               doIdiot = -1;
+               doCrash = 0;
+               doSprint = -1;
+               break;
+          case 8:
+               doIdiot = -1;
+               doCrash = 0;
+               doSprint = 0;
+               break;
+          case 9:
+               doIdiot = 0;
+               doCrash = 0;
+               doSprint = -1;
+               break;
+          case 10:
+               doIdiot = 0;
+               doCrash = 0;
+               doSprint = 0;
+               if (options.getExtraInfo(1) > 0)
+                    doSlp = options.getExtraInfo(1);
+               break;
+          case 11:
+               doIdiot = 0;
+               doCrash = 0;
+               doSprint = 0;
+               primalStartup = 0;
+               break;
+          default:
+               abort();
+          }
+     } else {
+          // Dual
+          switch (options.getSpecialOption(0)) {
+          case 0:
+               doIdiot = 0;
+               doCrash = 0;
+               doSprint = 0;
+               break;
+          case 1:
+               doIdiot = 0;
+               doCrash = 1;
+               if (options.getExtraInfo(0) > 0)
+                    doCrash = options.getExtraInfo(0);
+               doSprint = 0;
+               break;
+          case 2:
+               doIdiot = -1;
+               if (options.getExtraInfo(0) > 0)
+                    doIdiot = options.getExtraInfo(0);
+               doCrash = 0;
+               doSprint = 0;
+               break;
+          default:
+               abort();
+          }
+     }
+#ifndef NO_RTTI
+     ClpQuadraticObjective * quadraticObj = (dynamic_cast< ClpQuadraticObjective*>(objectiveAsObject()));
+#else
+     ClpQuadraticObjective * quadraticObj = NULL;
+     if (objective_->type() == 2)
+          quadraticObj = (static_cast< ClpQuadraticObjective*>(objective_));
+#endif
+     // If quadratic then primal or barrier or slp
+     if (quadraticObj) {
+          doSprint = 0;
+          doIdiot = 0;
+          // off
+          if (method == ClpSolve::useBarrier)
+               method = ClpSolve::useBarrierNoCross;
+          else if (method != ClpSolve::useBarrierNoCross)
+               method = ClpSolve::usePrimal;
+     }
+#ifdef COIN_HAS_VOL
+     // Save number of idiot
+     int saveDoIdiot = doIdiot;
+#endif
+     // Just do this number of passes in Sprint
+     int maxSprintPass = 100;
+     // See if worth trying +- one matrix
+     bool plusMinus = false;
+     int numberElements = model2->getNumElements();
+#ifndef SLIM_CLP
+#ifndef NO_RTTI
+     if (dynamic_cast< ClpNetworkMatrix*>(matrix_)) {
+          // network - switch off stuff
+          doIdiot = 0;
+          if (doSprint < 0)
+               doSprint = 0;
+     }
+#else
+     if (matrix_->type() == 11) {
+          // network - switch off stuff
+          doIdiot = 0;
+          //doSprint=0;
+     }
+#endif
+#endif
+     int numberColumns = model2->numberColumns();
+     int numberRows = model2->numberRows();
+     // If not all slack basis - switch off all except sprint
+     int numberRowsBasic = 0;
+     int iRow;
+     for (iRow = 0; iRow < numberRows; iRow++)
+          if (model2->getRowStatus(iRow) == basic)
+               numberRowsBasic++;
+     if (numberRowsBasic < numberRows) {
+          doIdiot = 0;
+          doCrash = 0;
+          //doSprint=0;
+     }
+     if (options.getSpecialOption(3) == 0) {
+          if(numberElements > 100000)
+               plusMinus = true;
+          if(numberElements > 10000 && (doIdiot || doSprint))
+               plusMinus = true;
+     } else if ((specialOptions_ & 1024) != 0) {
+          plusMinus = true;
+     }
+#ifndef SLIM_CLP
+     // Statistics (+1,-1, other) - used to decide on strategy if not +-1
+     CoinBigIndex statistics[3] = { -1, 0, 0};
+     if (plusMinus) {
+          saveMatrix = model2->clpMatrix();
+#ifndef NO_RTTI
+          ClpPackedMatrix* clpMatrix =
+               dynamic_cast< ClpPackedMatrix*>(saveMatrix);
+#else
+          ClpPackedMatrix* clpMatrix = NULL;
+          if (saveMatrix->type() == 1)
+               clpMatrix =
+                    static_cast< ClpPackedMatrix*>(saveMatrix);
+#endif
+          if (clpMatrix) {
+               ClpPlusMinusOneMatrix * newMatrix = new ClpPlusMinusOneMatrix(*(clpMatrix->matrix()));
+               if (newMatrix->getIndices()) {
+                  // CHECKME This test of specialOptions and the one above
+                  // don't seem compatible.
+#ifndef ABC_INHERIT
+                    if ((specialOptions_ & 1024) == 0) {
+                         model2->replaceMatrix(newMatrix);
+                    } else {
+#endif
+                         // in integer (or abc) - just use for sprint/idiot
+                         saveMatrix = NULL;
+                         delete newMatrix;
+#ifndef ABC_INHERIT
+                    }
+#endif
+               } else {
+                    handler_->message(CLP_MATRIX_CHANGE, messages_)
+                              << "+- 1"
+                              << CoinMessageEol;
+                    CoinMemcpyN(newMatrix->startPositive(), 3, statistics);
+                    saveMatrix = NULL;
+                    plusMinus = false;
+                    delete newMatrix;
+               }
+          } else {
+               saveMatrix = NULL;
+               plusMinus = false;
+          }
+     }
+#endif
+     if (this->factorizationFrequency() == 200) {
+          // User did not touch preset
+          model2->defaultFactorizationFrequency();
+     } else if (model2 != this) {
+          // make sure model2 has correct value
+          model2->setFactorizationFrequency(this->factorizationFrequency());
+     }
+     if (method == ClpSolve::automatic) {
+          if (doSprint == 0 && doIdiot == 0) {
+               // off
+               method = ClpSolve::useDual;
+          } else {
+               // only do primal if sprint or idiot
+               if (doSprint > 0) {
+                    method = ClpSolve::usePrimalorSprint;
+               } else if (doIdiot > 0) {
+                    method = ClpSolve::usePrimal;
+               } else {
+                    if (numberElements < 500000) {
+                         // Small problem
+                         if(numberRows * 10 > numberColumns || numberColumns < 6000
+                                   || (numberRows * 20 > numberColumns && !plusMinus))
+                              doSprint = 0; // switch off sprint
+                    } else {
+                         // larger problem
+                         if(numberRows * 8 > numberColumns)
+                              doSprint = 0; // switch off sprint
+                    }
+                    // switch off idiot or sprint if any free variable
+		    // switch off sprint if very few with costs
+                    int iColumn;
+                    const double * columnLower = model2->columnLower();
+                    const double * columnUpper = model2->columnUpper();
+		    const double * objective = model2->objective();
+		    int nObj=0;
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (columnLower[iColumn] < -1.0e10 && columnUpper[iColumn] > 1.0e10) {
+			      doSprint = 0;
+                              doIdiot = 0;
+                              break;
+			 } else if (objective[iColumn]) {
+			   nObj++;
+                         }
+                    }
+		    if (nObj*10<numberColumns)
+		      doSprint=0;
+                    int nPasses = 0;
+                    // look at rhs
+                    int iRow;
+                    double largest = 0.0;
+                    double smallest = 1.0e30;
+                    double largestGap = 0.0;
+                    int numberNotE = 0;
+                    bool notInteger = false;
+                    for (iRow = 0; iRow < numberRows; iRow++) {
+                         double value1 = model2->rowLower_[iRow];
+                         if (value1 && value1 > -1.0e31) {
+                              largest = CoinMax(largest, fabs(value1));
+                              smallest = CoinMin(smallest, fabs(value1));
+                              if (fabs(value1 - floor(value1 + 0.5)) > 1.0e-8) {
+                                   notInteger = true;
+                                   break;
+                              }
+                         }
+                         double value2 = model2->rowUpper_[iRow];
+                         if (value2 && value2 < 1.0e31) {
+                              largest = CoinMax(largest, fabs(value2));
+                              smallest = CoinMin(smallest, fabs(value2));
+                              if (fabs(value2 - floor(value2 + 0.5)) > 1.0e-8) {
+                                   notInteger = true;
+                                   break;
+                              }
+                         }
+                         // CHECKME This next bit can't be right...
+                         if (value2 > value1) {
+                              numberNotE++;
+                              //if (value2 > 1.0e31 || value1 < -1.0e31)
+			      //   largestGap = COIN_DBL_MAX;
+                              //else
+			      //   largestGap = value2 - value1;
+                         }
+                    }
+                    bool tryIt = numberRows > 200 && numberColumns > 2000 &&
+                                 (numberColumns > 2 * numberRows || (method != ClpSolve::useDual && (specialOptions_ & 1024) != 0));
+                    tryItSave = tryIt;
+                    if (numberRows < 1000 && numberColumns < 3000)
+                         tryIt = false;
+                    if (notInteger)
+                         tryIt = false;
+                    if (largest / smallest > 10 || (largest / smallest > 2.0 && largest > 50))
+                         tryIt = false;
+                    if (tryIt) {
+                         if (largest / smallest > 2.0) {
+                              nPasses = 10 + numberColumns / 100000;
+                              nPasses = CoinMin(nPasses, 50);
+                              nPasses = CoinMax(nPasses, 15);
+                              if (numberRows > 20000 && nPasses > 5) {
+                                   // Might as well go for it
+                                   nPasses = CoinMax(nPasses, 71);
+                              } else if (numberRows > 2000 && nPasses > 5) {
+                                   nPasses = CoinMax(nPasses, 50);
+                              } else if (numberElements < 3 * numberColumns) {
+                                   nPasses = CoinMin(nPasses, 10); // probably not worh it
+                              }
+                         } else if (largest / smallest > 1.01 || numberElements <= 3 * numberColumns) {
+                              nPasses = 10 + numberColumns / 1000;
+                              nPasses = CoinMin(nPasses, 100);
+                              nPasses = CoinMax(nPasses, 30);
+                              if (numberRows > 25000) {
+                                   // Might as well go for it
+                                   nPasses = CoinMax(nPasses, 71);
+                              }
+                              if (!largestGap)
+                                   nPasses *= 2;
+                         } else {
+                              nPasses = 10 + numberColumns / 1000;
+                              nPasses = CoinMin(nPasses, 200);
+                              nPasses = CoinMax(nPasses, 100);
+                              if (!largestGap)
+                                   nPasses *= 2;
+                         }
+                    }
+                    //printf("%d rows %d cols plus %c tryIt %c largest %g smallest %g largestGap %g npasses %d sprint %c\n",
+                    //     numberRows,numberColumns,plusMinus ? 'Y' : 'N',
+                    //     tryIt ? 'Y' :'N',largest,smallest,largestGap,nPasses,doSprint ? 'Y' :'N');
+                    //exit(0);
+                    if (!tryIt || nPasses <= 5)
+                         doIdiot = 0;
+                    if (doSprint) {
+                         method = ClpSolve::usePrimalorSprint;
+                    } else if (doIdiot) {
+                         method = ClpSolve::usePrimal;
+                    } else {
+                         method = ClpSolve::useDual;
+                    }
+               }
+          }
+     }
+     if (method == ClpSolve::usePrimalorSprint) {
+          if (doSprint < 0) {
+               if (numberElements < 500000) {
+                    // Small problem
+                    if(numberRows * 10 > numberColumns || numberColumns < 6000
+                              || (numberRows * 20 > numberColumns && !plusMinus))
+                         method = ClpSolve::usePrimal; // switch off sprint
+               } else {
+                    // larger problem
+                    if(numberRows * 8 > numberColumns)
+                         method = ClpSolve::usePrimal; // switch off sprint
+                    // but make lightweight
+                    if(numberRows * 10 > numberColumns || numberColumns < 6000
+                              || (numberRows * 20 > numberColumns && !plusMinus))
+                         maxSprintPass = 10;
+               }
+          } else if (doSprint == 0) {
+               method = ClpSolve::usePrimal; // switch off sprint
+          }
+     }
+     if (method == ClpSolve::useDual) {
+          double * saveLower = NULL;
+          double * saveUpper = NULL;
+          if (presolve == ClpSolve::presolveOn) {
+               int numberInfeasibilities = model2->tightenPrimalBounds(0.0, 0);
+               if (numberInfeasibilities) {
+                    handler_->message(CLP_INFEASIBLE, messages_)
+                              << CoinMessageEol;
+                    delete model2;
+                    model2 = this;
+                    presolve = ClpSolve::presolveOff;
+               }
+          } else if (numberRows_ + numberColumns_ > 5000) {
+               // do anyway
+               saveLower = new double[numberRows_+numberColumns_];
+               CoinMemcpyN(model2->columnLower(), numberColumns_, saveLower);
+               CoinMemcpyN(model2->rowLower(), numberRows_, saveLower + numberColumns_);
+               saveUpper = new double[numberRows_+numberColumns_];
+               CoinMemcpyN(model2->columnUpper(), numberColumns_, saveUpper);
+               CoinMemcpyN(model2->rowUpper(), numberRows_, saveUpper + numberColumns_);
+               int numberInfeasibilities = model2->tightenPrimalBounds();
+               if (numberInfeasibilities) {
+                    handler_->message(CLP_INFEASIBLE, messages_)
+                              << CoinMessageEol;
+                    CoinMemcpyN(saveLower, numberColumns_, model2->columnLower());
+                    CoinMemcpyN(saveLower + numberColumns_, numberRows_, model2->rowLower());
+                    delete [] saveLower;
+                    saveLower = NULL;
+                    CoinMemcpyN(saveUpper, numberColumns_, model2->columnUpper());
+                    CoinMemcpyN(saveUpper + numberColumns_, numberRows_, model2->rowUpper());
+                    delete [] saveUpper;
+                    saveUpper = NULL;
+               }
+          }
+#ifndef COIN_HAS_VOL
+          // switch off idiot and volume for now
+          doIdiot = 0;
+#endif
+          // pick up number passes
+          int nPasses = 0;
+          int numberNotE = 0;
+#ifndef SLIM_CLP
+          if ((doIdiot < 0 && plusMinus) || doIdiot > 0) {
+               // See if candidate for idiot
+               nPasses = 0;
+               Idiot info(*model2);
+               // Get average number of elements per column
+               double ratio  = static_cast<double> (numberElements) / static_cast<double> (numberColumns);
+               // look at rhs
+               int iRow;
+               double largest = 0.0;
+               double smallest = 1.0e30;
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    double value1 = model2->rowLower_[iRow];
+                    if (value1 && value1 > -1.0e31) {
+                         largest = CoinMax(largest, fabs(value1));
+                         smallest = CoinMin(smallest, fabs(value1));
+                    }
+                    double value2 = model2->rowUpper_[iRow];
+                    if (value2 && value2 < 1.0e31) {
+                         largest = CoinMax(largest, fabs(value2));
+                         smallest = CoinMin(smallest, fabs(value2));
+                    }
+                    if (value2 > value1) {
+                         numberNotE++;
+                    }
+               }
+               if (doIdiot < 0) {
+                    if (numberRows > 200 && numberColumns > 5000 && ratio >= 3.0 &&
+                              largest / smallest < 1.1 && !numberNotE) {
+                         nPasses = 71;
+                    }
+               }
+               if (doIdiot > 0) {
+                    nPasses = CoinMax(nPasses, doIdiot);
+                    if (nPasses > 70) {
+                         info.setStartingWeight(1.0e3);
+                         info.setDropEnoughFeasibility(0.01);
+                    }
+               }
+               if (nPasses > 20) {
+#ifdef COIN_HAS_VOL
+                    int returnCode = solveWithVolume(model2, nPasses, saveDoIdiot);
+                    if (!returnCode) {
+                         time2 = CoinCpuTime();
+                         timeIdiot = time2 - timeX;
+                         handler_->message(CLP_INTERVAL_TIMING, messages_)
+                                   << "Idiot Crash" << timeIdiot << time2 - time1
+                                   << CoinMessageEol;
+                         timeX = time2;
+                    } else {
+                         nPasses = 0;
+                    }
+#else
+                    nPasses = 0;
+#endif
+               } else {
+                    nPasses = 0;
+               }
+          }
+#endif
+          if (doCrash) {
+#ifdef ABC_INHERIT
+	    if (!model2->abcState()) {
+#endif
+               switch(doCrash) {
+                    // standard
+               case 1:
+                    model2->crash(1000, 1);
+                    break;
+                    // As in paper by Solow and Halim (approx)
+               case 2:
+               case 3:
+                    model2->crash(model2->dualBound(), 0);
+                    break;
+                    // Just put free in basis
+               case 4:
+                    model2->crash(0.0, 3);
+                    break;
+               }
+#ifdef ABC_INHERIT
+	    } else if (doCrash>=0) {
+	       model2->setAbcState(model2->abcState()|256*doCrash);
+	    }
+#endif
+          }
+          if (!nPasses) {
+               int saveOptions = model2->specialOptions();
+               if (model2->numberRows() > 100)
+                    model2->setSpecialOptions(saveOptions | 64); // go as far as possible
+               //int numberRows = model2->numberRows();
+               //int numberColumns = model2->numberColumns();
+               if (dynamic_cast< ClpPackedMatrix*>(matrix_)) {
+                    // See if original wanted vector
+                    ClpPackedMatrix * clpMatrixO = dynamic_cast< ClpPackedMatrix*>(matrix_);
+                    ClpMatrixBase * matrix = model2->clpMatrix();
+                    if (dynamic_cast< ClpPackedMatrix*>(matrix) && clpMatrixO->wantsSpecialColumnCopy()) {
+                         ClpPackedMatrix * clpMatrix = dynamic_cast< ClpPackedMatrix*>(matrix);
+                         clpMatrix->makeSpecialColumnCopy();
+                         //model2->setSpecialOptions(model2->specialOptions()|256); // to say no row copy for comparisons
+                         model2->dual(0);
+                         clpMatrix->releaseSpecialColumnCopy();
+                    } else {
+#ifndef ABC_INHERIT
+		      model2->dual(0);
+#else
+		      model2->dealWithAbc(0,0,interrupt);
+#endif
+                    }
+               } else {
+                    model2->dual(0);
+               }
+          } else if (!numberNotE && 0) {
+               // E so we can do in another way
+               double * pi = model2->dualRowSolution();
+               int i;
+               int numberColumns = model2->numberColumns();
+               int numberRows = model2->numberRows();
+               double * saveObj = new double[numberColumns];
+               CoinMemcpyN(model2->objective(), numberColumns, saveObj);
+               CoinMemcpyN(model2->objective(),
+                           numberColumns, model2->dualColumnSolution());
+               model2->clpMatrix()->transposeTimes(-1.0, pi, model2->dualColumnSolution());
+               CoinMemcpyN(model2->dualColumnSolution(),
+                           numberColumns, model2->objective());
+               const double * rowsol = model2->primalRowSolution();
+               double offset = 0.0;
+               for (i = 0; i < numberRows; i++) {
+                    offset += pi[i] * rowsol[i];
+               }
+               double value2;
+               model2->getDblParam(ClpObjOffset, value2);
+               //printf("Offset %g %g\n",offset,value2);
+               model2->setDblParam(ClpObjOffset, value2 - offset);
+               model2->setPerturbation(51);
+               //model2->setRowObjective(pi);
+               // zero out pi
+               //memset(pi,0,numberRows*sizeof(double));
+               // Could put some in basis - only partially tested
+               model2->allSlackBasis();
+               //model2->factorization()->maximumPivots(200);
+               //model2->setLogLevel(63);
+               // solve
+               model2->dual(0);
+               model2->setDblParam(ClpObjOffset, value2);
+               CoinMemcpyN(saveObj, numberColumns, model2->objective());
+               // zero out pi
+               //memset(pi,0,numberRows*sizeof(double));
+               //model2->setRowObjective(pi);
+               delete [] saveObj;
+               //model2->dual(0);
+               model2->setPerturbation(50);
+               model2->primal();
+          } else {
+               // solve
+               model2->setPerturbation(100);
+               model2->dual(2);
+               model2->setPerturbation(50);
+               model2->dual(0);
+          }
+          if (saveLower) {
+               CoinMemcpyN(saveLower, numberColumns_, model2->columnLower());
+               CoinMemcpyN(saveLower + numberColumns_, numberRows_, model2->rowLower());
+               delete [] saveLower;
+               saveLower = NULL;
+               CoinMemcpyN(saveUpper, numberColumns_, model2->columnUpper());
+               CoinMemcpyN(saveUpper + numberColumns_, numberRows_, model2->rowUpper());
+               delete [] saveUpper;
+               saveUpper = NULL;
+          }
+          time2 = CoinCpuTime();
+          timeCore = time2 - timeX;
+          handler_->message(CLP_INTERVAL_TIMING, messages_)
+                    << "Dual" << timeCore << time2 - time1
+                    << CoinMessageEol;
+          timeX = time2;
+     } else if (method == ClpSolve::usePrimal) {
+#ifndef SLIM_CLP
+          if (doIdiot) {
+               int nPasses = 0;
+               Idiot info(*model2);
+               // Get average number of elements per column
+               double ratio  = static_cast<double> (numberElements) / static_cast<double> (numberColumns);
+               // look at rhs
+               int iRow;
+               double largest = 0.0;
+               double smallest = 1.0e30;
+               double largestGap = 0.0;
+               int numberNotE = 0;
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    double value1 = model2->rowLower_[iRow];
+                    if (value1 && value1 > -1.0e31) {
+                         largest = CoinMax(largest, fabs(value1));
+                         smallest = CoinMin(smallest, fabs(value1));
+                    }
+                    double value2 = model2->rowUpper_[iRow];
+                    if (value2 && value2 < 1.0e31) {
+                         largest = CoinMax(largest, fabs(value2));
+                         smallest = CoinMin(smallest, fabs(value2));
+                    }
+                    if (value2 > value1) {
+                         numberNotE++;
+                         if (value2 > 1.0e31 || value1 < -1.0e31)
+                              largestGap = COIN_DBL_MAX;
+                         else
+                              largestGap = value2 - value1;
+                    }
+               }
+               bool increaseSprint = plusMinus;
+               if ((specialOptions_ & 1024) != 0)
+                    increaseSprint = false;
+               if (!plusMinus) {
+                    // If 90% +- 1 then go for sprint
+                    if (statistics[0] >= 0 && 10 * statistics[2] < statistics[0] + statistics[1])
+                         increaseSprint = true;
+               }
+               bool tryIt = tryItSave;
+               if (numberRows < 1000 && numberColumns < 3000)
+                    tryIt = false;
+               if (tryIt) {
+                    if (increaseSprint) {
+                         info.setStartingWeight(1.0e3);
+                         info.setReduceIterations(6);
+                         // also be more lenient on infeasibilities
+                         info.setDropEnoughFeasibility(0.5 * info.getDropEnoughFeasibility());
+                         info.setDropEnoughWeighted(-2.0);
+                         if (largest / smallest > 2.0) {
+                              nPasses = 10 + numberColumns / 100000;
+                              nPasses = CoinMin(nPasses, 50);
+                              nPasses = CoinMax(nPasses, 15);
+                              if (numberRows > 20000 && nPasses > 5) {
+                                   // Might as well go for it
+                                   nPasses = CoinMax(nPasses, 71);
+                              } else if (numberRows > 2000 && nPasses > 5) {
+                                   nPasses = CoinMax(nPasses, 50);
+                              } else if (numberElements < 3 * numberColumns) {
+                                   nPasses = CoinMin(nPasses, 10); // probably not worh it
+                                   if (doIdiot < 0)
+                                        info.setLightweight(1); // say lightweight idiot
+                              } else {
+                                   if (doIdiot < 0)
+                                        info.setLightweight(1); // say lightweight idiot
+                              }
+                         } else if (largest / smallest > 1.01 || numberElements <= 3 * numberColumns) {
+                              nPasses = 10 + numberColumns / 1000;
+                              nPasses = CoinMin(nPasses, 100);
+                              nPasses = CoinMax(nPasses, 30);
+                              if (numberRows > 25000) {
+                                   // Might as well go for it
+                                   nPasses = CoinMax(nPasses, 71);
+                              }
+                              if (!largestGap)
+                                   nPasses *= 2;
+                         } else {
+                              nPasses = 10 + numberColumns / 1000;
+                              nPasses = CoinMin(nPasses, 200);
+                              nPasses = CoinMax(nPasses, 100);
+                              info.setStartingWeight(1.0e-1);
+                              info.setReduceIterations(6);
+                              if (!largestGap)
+                                   nPasses *= 2;
+                              //info.setFeasibilityTolerance(1.0e-7);
+                         }
+                         // If few passes - don't bother
+                         if (nPasses <= 5 && !plusMinus)
+                              nPasses = 0;
+                    } else {
+                         if (doIdiot < 0)
+                              info.setLightweight(1); // say lightweight idiot
+                         if (largest / smallest > 1.01 || numberNotE || statistics[2] > statistics[0] + statistics[1]) {
+                              if (numberRows > 25000 || numberColumns > 5 * numberRows) {
+                                   nPasses = 50;
+                              } else if (numberColumns > 4 * numberRows) {
+                                   nPasses = 20;
+                              } else {
+                                   nPasses = 5;
+                              }
+                         } else {
+                              if (numberRows > 25000 || numberColumns > 5 * numberRows) {
+                                   nPasses = 50;
+                                   info.setLightweight(0); // say not lightweight idiot
+                              } else if (numberColumns > 4 * numberRows) {
+                                   nPasses = 20;
+                              } else {
+                                   nPasses = 15;
+                              }
+                         }
+                         if (ratio < 3.0) {
+                              nPasses = static_cast<int> (ratio * static_cast<double> (nPasses) / 4.0); // probably not worth it
+                         } else {
+                              nPasses = CoinMax(nPasses, 5);
+                         }
+                         if (numberRows > 25000 && nPasses > 5) {
+                              // Might as well go for it
+                              nPasses = CoinMax(nPasses, 71);
+                         } else if (increaseSprint) {
+                              nPasses *= 2;
+                              nPasses = CoinMin(nPasses, 71);
+                         } else if (nPasses == 5 && ratio > 5.0) {
+                              nPasses = static_cast<int> (static_cast<double> (nPasses) * (ratio / 5.0)); // increase if lots of elements per column
+                         }
+                         if (nPasses <= 5 && !plusMinus)
+                              nPasses = 0;
+                         //info.setStartingWeight(1.0e-1);
+                    }
+               }
+               if (doIdiot > 0) {
+                    // pick up number passes
+                    nPasses = options.getExtraInfo(1) % 1000000;
+                    if (nPasses > 70) {
+                         info.setStartingWeight(1.0e3);
+                         info.setReduceIterations(6);
+			 //if (nPasses > 200) 
+			 //info.setFeasibilityTolerance(1.0e-9);
+			 //if (nPasses > 1900) 
+			 //info.setWeightFactor(0.93);
+			 if (nPasses > 900) {
+			   double reductions=nPasses/6.0;
+			   if (nPasses<5000) {
+			     reductions /= 12.0;
+			   } else {
+			     reductions /= 13.0;
+			     info.setStartingWeight(1.0e4);
+			   }
+			   double ratio=1.0/std::pow(10.0,(1.0/reductions));
+			   printf("%d passes reduction factor %g\n",nPasses,ratio);
+			   info.setWeightFactor(ratio);
+			 } else if (nPasses > 500) {
+			   info.setWeightFactor(0.7);
+			 } else if (nPasses > 200) {
+			   info.setWeightFactor(0.5);
+			 }
+			 if (maximumIterations()<nPasses) {
+			   printf("Presuming maximumIterations is just for Idiot\n");
+			   nPasses=maximumIterations();
+			   setMaximumIterations(COIN_INT_MAX);
+			   model2->setMaximumIterations(COIN_INT_MAX);
+			 }
+                         if (nPasses >= 10000&&nPasses<100000) {
+                              int k = nPasses % 100;
+                              nPasses /= 200;
+                              info.setReduceIterations(3);
+                              if (k)
+                                   info.setStartingWeight(1.0e2);
+                         }
+                         // also be more lenient on infeasibilities
+                         info.setDropEnoughFeasibility(0.5 * info.getDropEnoughFeasibility());
+                         info.setDropEnoughWeighted(-2.0);
+                    } else if (nPasses >= 50) {
+                         info.setStartingWeight(1.0e3);
+                         //info.setReduceIterations(6);
+                    }
+                    // For experimenting
+                    if (nPasses < 70 && (nPasses % 10) > 0 && (nPasses % 10) < 4) {
+                         info.setStartingWeight(1.0e3);
+                         info.setLightweight(nPasses % 10); // special testing
+#ifdef COIN_DEVELOP
+                         printf("warning - odd lightweight %d\n", nPasses % 10);
+                         //info.setReduceIterations(6);
+#endif
+                    }
+               }
+               if (options.getExtraInfo(1) > 1000000)
+                    nPasses += 1000000;
+               if (nPasses) {
+                    doCrash = 0;
+#if 0
+                    double * solution = model2->primalColumnSolution();
+                    int iColumn;
+                    double * saveLower = new double[numberColumns];
+                    CoinMemcpyN(model2->columnLower(), numberColumns, saveLower);
+                    double * saveUpper = new double[numberColumns];
+                    CoinMemcpyN(model2->columnUpper(), numberColumns, saveUpper);
+                    printf("doing tighten before idiot\n");
+                    model2->tightenPrimalBounds();
+                    // Move solution
+                    double * columnLower = model2->columnLower();
+                    double * columnUpper = model2->columnUpper();
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         if (columnLower[iColumn] > 0.0)
+                              solution[iColumn] = columnLower[iColumn];
+                         else if (columnUpper[iColumn] < 0.0)
+                              solution[iColumn] = columnUpper[iColumn];
+                         else
+                              solution[iColumn] = 0.0;
+                    }
+                    CoinMemcpyN(saveLower, numberColumns, columnLower);
+                    CoinMemcpyN(saveUpper, numberColumns, columnUpper);
+                    delete [] saveLower;
+                    delete [] saveUpper;
+#else
+                    // Allow for crossover
+                    //#define LACI_TRY
+#ifndef LACI_TRY
+                    //if (doIdiot>0)
+#ifdef ABC_INHERIT
+		    if (!model2->abcState()) 
+#endif
+                    info.setStrategy(512 | info.getStrategy());
+#endif
+                    // Allow for scaling
+                    info.setStrategy(32 | info.getStrategy());
+                    info.crash(nPasses, model2->messageHandler(), model2->messagesPointer());
+#endif
+                    time2 = CoinCpuTime();
+                    timeIdiot = time2 - timeX;
+                    handler_->message(CLP_INTERVAL_TIMING, messages_)
+                              << "Idiot Crash" << timeIdiot << time2 - time1
+                              << CoinMessageEol;
+                    timeX = time2;
+		    if (nPasses>100000&&nPasses<100500) {
+		      // make sure no status left
+		      model2->createStatus();
+		      // solve
+		      if (model2->factorizationFrequency() == 200) {
+			// User did not touch preset
+			model2->defaultFactorizationFrequency();
+		      }
+		      //int numberRows = model2->numberRows();
+		      int numberColumns = model2->numberColumns();
+		      // save duals
+		      //double * saveDuals = CoinCopyOfArray(model2->dualRowSolution(),numberRows);
+		      // for moment this only works on nug etc (i.e. all ==)
+		      // needs row objective
+		      double * saveObj = CoinCopyOfArray(model2->objective(),numberColumns);
+		      double * pi = model2->dualRowSolution();
+		      model2->clpMatrix()->transposeTimes(-1.0, pi, model2->objective());
+		      // just primal values pass
+		      double saveScale = model2->objectiveScale();
+		      model2->setObjectiveScale(1.0e-3);
+		      model2->primal(2);
+		      model2->writeMps("xx.mps");
+		      double * solution = model2->primalColumnSolution();
+		      double * upper = model2->columnUpper();
+		      for (int i=0;i<numberColumns;i++) {
+			if (solution[i]<100.0)
+			  upper[i]=1000.0;
+		      }
+		      model2->setProblemStatus(-1);
+		      model2->setObjectiveScale(saveScale);
+#ifdef ABC_INHERIT
+		      AbcSimplex * abcModel2=new AbcSimplex(*model2);
+		      if (interrupt)
+			currentAbcModel = abcModel2;
+		      if (abcSimplex_) {
+			// move factorization stuff
+			abcModel2->factorization()->synchronize(model2->factorization(),abcModel2);
+		      }
+		      abcModel2->startPermanentArrays();
+		      abcModel2->setAbcState(CLP_ABC_WANTED);
+#if ABC_PARALLEL
+		      int parallelMode=1;
+		      printf("Parallel mode %d\n",parallelMode);
+		      abcModel2->setParallelMode(parallelMode);
+#endif
+		      //if (processTune>0&&processTune<8)
+		      //abcModel2->setMoreSpecialOptions(abcModel2->moreSpecialOptions()|65536*processTune);
+		      abcModel2->doAbcDual();
+		      abcModel2->moveStatusToClp(model2);
+		      //ClpModel::stopPermanentArrays();
+		      model2->setSpecialOptions(model2->specialOptions()&~65536);
+		      //model2->dual();
+		      //model2->setNumberIterations(abcModel2->numberIterations()+model2->numberIterations());
+		      delete abcModel2;
+#endif
+		      memcpy(model2->objective(),saveObj,numberColumns*sizeof(double));
+		      //delete [] saveDuals;
+		      delete [] saveObj;
+		      model2->dual(2);
+		    } // end dubious idiot
+               }
+          }
+#endif
+          // ?
+          if (doCrash) {
+               switch(doCrash) {
+                    // standard
+               case 1:
+                    model2->crash(1000, 1);
+                    break;
+                    // As in paper by Solow and Halim (approx)
+               case 2:
+                    model2->crash(model2->dualBound(), 0);
+                    break;
+                    // My take on it
+               case 3:
+                    model2->crash(model2->dualBound(), -1);
+                    break;
+                    // Just put free in basis
+               case 4:
+                    model2->crash(0.0, 3);
+                    break;
+               }
+          }
+#ifndef SLIM_CLP
+          if (doSlp > 0 && objective_->type() == 2) {
+               model2->nonlinearSLP(doSlp, 1.0e-5);
+          }
+#endif
+#ifndef LACI_TRY
+          if (options.getSpecialOption(1) != 2 ||
+                    options.getExtraInfo(1) < 1000000) {
+               if (dynamic_cast< ClpPackedMatrix*>(matrix_)) {
+                    // See if original wanted vector
+                    ClpPackedMatrix * clpMatrixO = dynamic_cast< ClpPackedMatrix*>(matrix_);
+                    ClpMatrixBase * matrix = model2->clpMatrix();
+                    if (dynamic_cast< ClpPackedMatrix*>(matrix) && clpMatrixO->wantsSpecialColumnCopy()) {
+                         ClpPackedMatrix * clpMatrix = dynamic_cast< ClpPackedMatrix*>(matrix);
+                         clpMatrix->makeSpecialColumnCopy();
+                         //model2->setSpecialOptions(model2->specialOptions()|256); // to say no row copy for comparisons
+                         model2->primal(primalStartup);
+                         clpMatrix->releaseSpecialColumnCopy();
+                    } else {
+#ifndef ABC_INHERIT
+		        model2->primal(primalStartup);
+#else
+			model2->dealWithAbc(1,primalStartup,interrupt);
+#endif
+                    }
+               } else {
+#ifndef ABC_INHERIT
+                    model2->primal(primalStartup);
+#else
+		    model2->dealWithAbc(1,primalStartup,interrupt);
+#endif
+               }
+          }
+#endif
+          time2 = CoinCpuTime();
+          timeCore = time2 - timeX;
+          handler_->message(CLP_INTERVAL_TIMING, messages_)
+                    << "Primal" << timeCore << time2 - time1
+                    << CoinMessageEol;
+          timeX = time2;
+     } else if (method == ClpSolve::usePrimalorSprint) {
+          // Sprint
+          /*
+            This driver implements what I called Sprint when I introduced the idea
+            many years ago.  Cplex calls it "sifting" which I think is just as silly.
+            When I thought of this trivial idea
+            it reminded me of an LP code of the 60's called sprint which after
+            every factorization took a subset of the matrix into memory (all
+            64K words!) and then iterated very fast on that subset.  On the
+            problems of those days it did not work very well, but it worked very
+            well on aircrew scheduling problems where there were very large numbers
+            of columns all with the same flavor.
+          */
+
+          /* The idea works best if you can get feasible easily.  To make it
+             more general we can add in costed slacks */
+
+          int originalNumberColumns = model2->numberColumns();
+          int numberRows = model2->numberRows();
+          ClpSimplex * originalModel2 = model2;
+
+          // We will need arrays to choose variables.  These are too big but ..
+          double * weight = new double [numberRows+originalNumberColumns];
+          int * sort = new int [numberRows+originalNumberColumns];
+          int numberSort = 0;
+          // We are going to add slacks to get feasible.
+          // initial list will just be artificials
+          int iColumn;
+          const double * columnLower = model2->columnLower();
+          const double * columnUpper = model2->columnUpper();
+          double * columnSolution = model2->primalColumnSolution();
+
+          // See if we have costed slacks
+          int * negSlack = new int[numberRows];
+          int * posSlack = new int[numberRows];
+          int iRow;
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               negSlack[iRow] = -1;
+               posSlack[iRow] = -1;
+          }
+          const double * element = model2->matrix()->getElements();
+          const int * row = model2->matrix()->getIndices();
+          const CoinBigIndex * columnStart = model2->matrix()->getVectorStarts();
+          const int * columnLength = model2->matrix()->getVectorLengths();
+          //bool allSlack = (numberRowsBasic==numberRows);
+          for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) {
+               if (!columnSolution[iColumn] || fabs(columnSolution[iColumn]) > 1.0e20) {
+                    double value = 0.0;
+                    if (columnLower[iColumn] > 0.0)
+                         value = columnLower[iColumn];
+                    else if (columnUpper[iColumn] < 0.0)
+                         value = columnUpper[iColumn];
+                    columnSolution[iColumn] = value;
+               }
+               if (columnLength[iColumn] == 1) {
+                    int jRow = row[columnStart[iColumn]];
+                    if (!columnLower[iColumn]) {
+                         if (element[columnStart[iColumn]] > 0.0 && posSlack[jRow] < 0)
+                              posSlack[jRow] = iColumn;
+                         else if (element[columnStart[iColumn]] < 0.0 && negSlack[jRow] < 0)
+                              negSlack[jRow] = iColumn;
+                    } else if (!columnUpper[iColumn]) {
+                         if (element[columnStart[iColumn]] < 0.0 && posSlack[jRow] < 0)
+                              posSlack[jRow] = iColumn;
+                         else if (element[columnStart[iColumn]] > 0.0 && negSlack[jRow] < 0)
+                              negSlack[jRow] = iColumn;
+                    }
+               }
+          }
+          // now see what that does to row solution
+          double * rowSolution = model2->primalRowSolution();
+          CoinZeroN (rowSolution, numberRows);
+          model2->clpMatrix()->times(1.0, columnSolution, rowSolution);
+          // See if we can adjust using costed slacks
+          double penalty = CoinMax(1.0e5, CoinMin(infeasibilityCost_ * 0.01, 1.0e10)) * optimizationDirection_;
+          const double * lower = model2->rowLower();
+          const double * upper = model2->rowUpper();
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               if (lower[iRow] > rowSolution[iRow] + 1.0e-8) {
+                    int jColumn = posSlack[iRow];
+                    if (jColumn >= 0) {
+                         if (columnSolution[jColumn])
+                              continue;
+                         double difference = lower[iRow] - rowSolution[iRow];
+                         double elementValue = element[columnStart[jColumn]];
+                         if (elementValue > 0.0) {
+                              double movement = CoinMin(difference / elementValue, columnUpper[jColumn]);
+                              columnSolution[jColumn] = movement;
+                              rowSolution[iRow] += movement * elementValue;
+                         } else {
+                              double movement = CoinMax(difference / elementValue, columnLower[jColumn]);
+                              columnSolution[jColumn] = movement;
+                              rowSolution[iRow] += movement * elementValue;
+                         }
+                    }
+               } else if (upper[iRow] < rowSolution[iRow] - 1.0e-8) {
+                    int jColumn = negSlack[iRow];
+                    if (jColumn >= 0) {
+                         if (columnSolution[jColumn])
+                              continue;
+                         double difference = upper[iRow] - rowSolution[iRow];
+                         double elementValue = element[columnStart[jColumn]];
+                         if (elementValue < 0.0) {
+                              double movement = CoinMin(difference / elementValue, columnUpper[jColumn]);
+                              columnSolution[jColumn] = movement;
+                              rowSolution[iRow] += movement * elementValue;
+                         } else {
+                              double movement = CoinMax(difference / elementValue, columnLower[jColumn]);
+                              columnSolution[jColumn] = movement;
+                              rowSolution[iRow] += movement * elementValue;
+                         }
+                    }
+               }
+          }
+          delete [] negSlack;
+          delete [] posSlack;
+          int nRow = numberRows;
+          bool network = false;
+          if (dynamic_cast< ClpNetworkMatrix*>(matrix_)) {
+               network = true;
+               nRow *= 2;
+          }
+          int * addStarts = new int [nRow+1];
+          int * addRow = new int[nRow];
+          double * addElement = new double[nRow];
+          addStarts[0] = 0;
+          int numberArtificials = 0;
+          int numberAdd = 0;
+          double * addCost = new double [numberRows];
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               if (lower[iRow] > rowSolution[iRow] + 1.0e-8) {
+                    addRow[numberAdd] = iRow;
+                    addElement[numberAdd++] = 1.0;
+                    if (network) {
+                         addRow[numberAdd] = numberRows;
+                         addElement[numberAdd++] = -1.0;
+                    }
+                    addCost[numberArtificials] = penalty;
+                    numberArtificials++;
+                    addStarts[numberArtificials] = numberAdd;
+               } else if (upper[iRow] < rowSolution[iRow] - 1.0e-8) {
+                    addRow[numberAdd] = iRow;
+                    addElement[numberAdd++] = -1.0;
+                    if (network) {
+                         addRow[numberAdd] = numberRows;
+                         addElement[numberAdd++] = 1.0;
+                    }
+                    addCost[numberArtificials] = penalty;
+                    numberArtificials++;
+                    addStarts[numberArtificials] = numberAdd;
+               }
+          }
+          if (numberArtificials) {
+               // need copy so as not to disturb original
+               model2 = new ClpSimplex(*model2);
+               if (network) {
+                    // network - add a null row
+                    model2->addRow(0, NULL, NULL, -COIN_DBL_MAX, COIN_DBL_MAX);
+                    numberRows++;
+               }
+               model2->addColumns(numberArtificials, NULL, NULL, addCost,
+                                  addStarts, addRow, addElement);
+          }
+          delete [] addStarts;
+          delete [] addRow;
+          delete [] addElement;
+          delete [] addCost;
+          // look at rhs to see if to perturb
+          double largest = 0.0;
+          double smallest = 1.0e30;
+          for (iRow = 0; iRow < numberRows; iRow++) {
+               double value;
+               value = fabs(model2->rowLower_[iRow]);
+               if (value && value < 1.0e30) {
+                    largest = CoinMax(largest, value);
+                    smallest = CoinMin(smallest, value);
+               }
+               value = fabs(model2->rowUpper_[iRow]);
+               if (value && value < 1.0e30) {
+                    largest = CoinMax(largest, value);
+                    smallest = CoinMin(smallest, value);
+               }
+          }
+          double * saveLower = NULL;
+          double * saveUpper = NULL;
+          if (largest < 2.01 * smallest) {
+               // perturb - so switch off standard
+               model2->setPerturbation(100);
+               saveLower = new double[numberRows];
+               CoinMemcpyN(model2->rowLower_, numberRows, saveLower);
+               saveUpper = new double[numberRows];
+               CoinMemcpyN(model2->rowUpper_, numberRows, saveUpper);
+               double * lower = model2->rowLower();
+               double * upper = model2->rowUpper();
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    double lowerValue = lower[iRow], upperValue = upper[iRow];
+                    double value = randomNumberGenerator_.randomDouble();
+                    if (upperValue > lowerValue + primalTolerance_) {
+                         if (lowerValue > -1.0e20 && lowerValue)
+                              lowerValue -= value * 1.0e-4 * fabs(lowerValue);
+                         if (upperValue < 1.0e20 && upperValue)
+                              upperValue += value * 1.0e-4 * fabs(upperValue);
+                    } else if (upperValue > 0.0) {
+                         upperValue -= value * 1.0e-4 * fabs(lowerValue);
+                         lowerValue -= value * 1.0e-4 * fabs(lowerValue);
+                    } else if (upperValue < 0.0) {
+                         upperValue += value * 1.0e-4 * fabs(lowerValue);
+                         lowerValue += value * 1.0e-4 * fabs(lowerValue);
+                    } else {
+                    }
+                    lower[iRow] = lowerValue;
+                    upper[iRow] = upperValue;
+               }
+          }
+          int i;
+          // Just do this number of passes in Sprint
+          if (doSprint > 0)
+               maxSprintPass = options.getExtraInfo(1);
+          // but if big use to get ratio
+          double ratio = 3;
+          if (maxSprintPass > 1000) {
+               ratio = static_cast<double> (maxSprintPass) * 0.0001;
+               ratio = CoinMax(ratio, 1.1);
+               maxSprintPass = maxSprintPass % 1000;
+#ifdef COIN_DEVELOP
+               printf("%d passes wanted with ratio of %g\n", maxSprintPass, ratio);
+#endif
+          }
+          // Just take this number of columns in small problem
+          int smallNumberColumns = static_cast<int> (CoinMin(ratio * numberRows, static_cast<double> (numberColumns)));
+          smallNumberColumns = CoinMax(smallNumberColumns, 3000);
+          smallNumberColumns = CoinMin(smallNumberColumns, numberColumns);
+          //int smallNumberColumns = CoinMin(12*numberRows/10,numberColumns);
+          //smallNumberColumns = CoinMax(smallNumberColumns,3000);
+          //smallNumberColumns = CoinMax(smallNumberColumns,numberRows+1000);
+          // redo as may have changed
+          columnLower = model2->columnLower();
+          columnUpper = model2->columnUpper();
+          columnSolution = model2->primalColumnSolution();
+          // Set up initial list
+          numberSort = 0;
+          if (numberArtificials) {
+               numberSort = numberArtificials;
+               for (i = 0; i < numberSort; i++)
+                    sort[i] = i + originalNumberColumns;
+          }
+          // maybe a solution there already
+          for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) {
+               if (model2->getColumnStatus(iColumn) == basic)
+                    sort[numberSort++] = iColumn;
+          }
+          for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) {
+               if (model2->getColumnStatus(iColumn) != basic) {
+                    if (columnSolution[iColumn] > columnLower[iColumn] &&
+                              columnSolution[iColumn] < columnUpper[iColumn] &&
+                              columnSolution[iColumn])
+                         sort[numberSort++] = iColumn;
+               }
+          }
+          numberSort = CoinMin(numberSort, smallNumberColumns);
+
+          int numberColumns = model2->numberColumns();
+          double * fullSolution = model2->primalColumnSolution();
+
+
+          int iPass;
+          double lastObjective[] = {1.0e31,1.0e31};
+          // It will be safe to allow dense
+          model2->setInitialDenseFactorization(true);
+
+          // We will be using all rows
+          int * whichRows = new int [numberRows];
+          for (iRow = 0; iRow < numberRows; iRow++)
+               whichRows[iRow] = iRow;
+          double originalOffset;
+          model2->getDblParam(ClpObjOffset, originalOffset);
+          int totalIterations = 0;
+          double lastSumArtificials = COIN_DBL_MAX;
+          int originalMaxSprintPass = maxSprintPass;
+          maxSprintPass = 20; // so we do that many if infeasible
+          for (iPass = 0; iPass < maxSprintPass; iPass++) {
+               //printf("Bug until submodel new version\n");
+               //CoinSort_2(sort,sort+numberSort,weight);
+               // Create small problem
+               ClpSimplex small(model2, numberRows, whichRows, numberSort, sort);
+               small.setPerturbation(model2->perturbation());
+               small.setInfeasibilityCost(model2->infeasibilityCost());
+               if (model2->factorizationFrequency() == 200) {
+                    // User did not touch preset
+                    small.defaultFactorizationFrequency();
+               }
+               // now see what variables left out do to row solution
+               double * rowSolution = model2->primalRowSolution();
+               double * sumFixed = new double[numberRows];
+               CoinZeroN (sumFixed, numberRows);
+               int iRow, iColumn;
+               // zero out ones in small problem
+               for (iColumn = 0; iColumn < numberSort; iColumn++) {
+                    int kColumn = sort[iColumn];
+                    fullSolution[kColumn] = 0.0;
+               }
+               // Get objective offset
+               const double * objective = model2->objective();
+               double offset = 0.0;
+               for (iColumn = 0; iColumn < originalNumberColumns; iColumn++)
+                    offset += fullSolution[iColumn] * objective[iColumn];
+#if 0
+	       // Set artificials to zero if first time close to zero
+               for (iColumn = originalNumberColumns; iColumn < numberColumns; iColumn++) {
+		 if (fullSolution[iColumn]<primalTolerance_&&objective[iColumn]==penalty) {
+		   model2->objective()[iColumn]=2.0*penalty;
+		   fullSolution[iColumn]=0.0;
+		 }
+	       }
+#endif
+               small.setDblParam(ClpObjOffset, originalOffset - offset);
+               model2->clpMatrix()->times(1.0, fullSolution, sumFixed);
+
+               double * lower = small.rowLower();
+               double * upper = small.rowUpper();
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    if (lower[iRow] > -1.0e50)
+                         lower[iRow] -= sumFixed[iRow];
+                    if (upper[iRow] < 1.0e50)
+                         upper[iRow] -= sumFixed[iRow];
+                    rowSolution[iRow] -= sumFixed[iRow];
+               }
+               delete [] sumFixed;
+               // Solve
+               if (interrupt)
+                    currentModel = &small;
+               small.defaultFactorizationFrequency();
+               if (dynamic_cast< ClpPackedMatrix*>(matrix_)) {
+                    // See if original wanted vector
+                    ClpPackedMatrix * clpMatrixO = dynamic_cast< ClpPackedMatrix*>(matrix_);
+                    ClpMatrixBase * matrix = small.clpMatrix();
+                    if (dynamic_cast< ClpPackedMatrix*>(matrix) && clpMatrixO->wantsSpecialColumnCopy()) {
+                         ClpPackedMatrix * clpMatrix = dynamic_cast< ClpPackedMatrix*>(matrix);
+                         clpMatrix->makeSpecialColumnCopy();
+                         small.primal(1);
+                         clpMatrix->releaseSpecialColumnCopy();
+                    } else {
+#if 1
+#ifdef ABC_INHERIT
+		      //small.writeMps("try.mps");
+		      if (iPass||!numberArtificials) 
+		         small.dealWithAbc(1,1);
+		       else 
+		         small.dealWithAbc(0,0);
+#else
+		      if (iPass||!numberArtificials) 
+		         small.primal(1);
+		      else
+		         small.dual(0);
+#endif
+		      if (small.problemStatus())
+			small.dual(0);
+#else
+                         int numberColumns = small.numberColumns();
+                         int numberRows = small.numberRows();
+                         // Use dual region
+                         double * rhs = small.dualRowSolution();
+                         int * whichRow = new int[3*numberRows];
+                         int * whichColumn = new int[2*numberColumns];
+                         int nBound;
+                         ClpSimplex * small2 = ((ClpSimplexOther *) (&small))->crunch(rhs, whichRow, whichColumn,
+                                               nBound, false, false);
+                         if (small2) {
+#ifdef ABC_INHERIT
+                              small2->dealWithAbc(1,1);
+#else
+			      small.primal(1);
+#endif
+                              if (small2->problemStatus() == 0) {
+                                   small.setProblemStatus(0);
+                                   ((ClpSimplexOther *) (&small))->afterCrunch(*small2, whichRow, whichColumn, nBound);
+                              } else {
+#ifdef ABC_INHERIT
+                                   small2->dealWithAbc(1,1);
+#else
+				   small.primal(1);
+#endif
+                                   if (small2->problemStatus())
+                                        small.primal(1);
+                              }
+                              delete small2;
+                         } else {
+                              small.primal(1);
+                         }
+                         delete [] whichRow;
+                         delete [] whichColumn;
+#endif
+                    }
+               } else {
+                    small.primal(1);
+               }
+               totalIterations += small.numberIterations();
+               // move solution back
+               const double * solution = small.primalColumnSolution();
+               for (iColumn = 0; iColumn < numberSort; iColumn++) {
+                    int kColumn = sort[iColumn];
+                    model2->setColumnStatus(kColumn, small.getColumnStatus(iColumn));
+                    fullSolution[kColumn] = solution[iColumn];
+               }
+               for (iRow = 0; iRow < numberRows; iRow++)
+                    model2->setRowStatus(iRow, small.getRowStatus(iRow));
+               CoinMemcpyN(small.primalRowSolution(),
+                           numberRows, model2->primalRowSolution());
+               double sumArtificials = 0.0;
+               for (i = 0; i < numberArtificials; i++)
+                    sumArtificials += fullSolution[i + originalNumberColumns];
+               if (sumArtificials && iPass > 5 && sumArtificials >= lastSumArtificials) {
+                    // increase costs
+                    double * cost = model2->objective() + originalNumberColumns;
+                    double newCost = CoinMin(1.0e10, cost[0] * 1.5);
+                    for (i = 0; i < numberArtificials; i++)
+                         cost[i] = newCost;
+               }
+               lastSumArtificials = sumArtificials;
+               // get reduced cost for large problem
+               double * djs = model2->dualColumnSolution();
+               CoinMemcpyN(model2->objective(), numberColumns, djs);
+               model2->clpMatrix()->transposeTimes(-1.0, small.dualRowSolution(), djs);
+               int numberNegative = 0;
+               double sumNegative = 0.0;
+               // now massage weight so all basic in plus good djs
+               // first count and do basic
+               numberSort = 0;
+               for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                    double dj = djs[iColumn] * optimizationDirection_;
+                    double value = fullSolution[iColumn];
+                    if (model2->getColumnStatus(iColumn) == ClpSimplex::basic) {
+                         sort[numberSort++] = iColumn;
+                    } else if (dj < -dualTolerance_ && value < columnUpper[iColumn]) {
+                         numberNegative++;
+                         sumNegative -= dj;
+                    } else if (dj > dualTolerance_ && value > columnLower[iColumn]) {
+                         numberNegative++;
+                         sumNegative += dj;
+                    }
+               }
+               handler_->message(CLP_SPRINT, messages_)
+                         << iPass + 1 << small.numberIterations() << small.objectiveValue() << sumNegative
+                         << numberNegative
+                         << CoinMessageEol;
+               if (sumArtificials < 1.0e-8 && originalMaxSprintPass >= 0) {
+                    maxSprintPass = iPass + originalMaxSprintPass;
+                    originalMaxSprintPass = -1;
+               }
+               if (iPass > 20)
+                    sumArtificials = 0.0;
+               if ((small.objectiveValue()*optimizationDirection_ > lastObjective[1] - 1.0e-7 && iPass > 5 && sumArtificials < 1.0e-8) ||
+                         (!small.numberIterations() && iPass) ||
+                         iPass == maxSprintPass - 1 || small.status() == 3) {
+
+                    break; // finished
+               } else {
+		    lastObjective[1] = lastObjective[0];
+                    lastObjective[0] = small.objectiveValue() * optimizationDirection_;
+                    double tolerance;
+                    double averageNegDj = sumNegative / static_cast<double> (numberNegative + 1);
+                    if (numberNegative + numberSort > smallNumberColumns)
+                         tolerance = -dualTolerance_;
+                    else
+                         tolerance = 10.0 * averageNegDj;
+                    int saveN = numberSort;
+                    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+                         double dj = djs[iColumn] * optimizationDirection_;
+                         double value = fullSolution[iColumn];
+                         if (model2->getColumnStatus(iColumn) != ClpSimplex::basic) {
+                              if (dj < -dualTolerance_ && value < columnUpper[iColumn])
+                                   dj = dj;
+                              else if (dj > dualTolerance_ && value > columnLower[iColumn])
+                                   dj = -dj;
+                              else if (columnUpper[iColumn] > columnLower[iColumn])
+                                   dj = fabs(dj);
+                              else
+                                   dj = 1.0e50;
+                              if (dj < tolerance) {
+                                   weight[numberSort] = dj;
+                                   sort[numberSort++] = iColumn;
+                              }
+                         }
+                    }
+                    // sort
+                    CoinSort_2(weight + saveN, weight + numberSort, sort + saveN);
+                    numberSort = CoinMin(smallNumberColumns, numberSort);
+               }
+          }
+          if (interrupt)
+               currentModel = model2;
+          for (i = 0; i < numberArtificials; i++)
+               sort[i] = i + originalNumberColumns;
+          model2->deleteColumns(numberArtificials, sort);
+          if (network) {
+               int iRow = numberRows - 1;
+               model2->deleteRows(1, &iRow);
+          }
+          delete [] weight;
+          delete [] sort;
+          delete [] whichRows;
+          if (saveLower) {
+               // unperturb and clean
+               for (iRow = 0; iRow < numberRows; iRow++) {
+                    double diffLower = saveLower[iRow] - model2->rowLower_[iRow];
+                    double diffUpper = saveUpper[iRow] - model2->rowUpper_[iRow];
+                    model2->rowLower_[iRow] = saveLower[iRow];
+                    model2->rowUpper_[iRow] = saveUpper[iRow];
+                    if (diffLower)
+                         assert (!diffUpper || fabs(diffLower - diffUpper) < 1.0e-5);
+                    else
+                         diffLower = diffUpper;
+                    model2->rowActivity_[iRow] += diffLower;
+               }
+               delete [] saveLower;
+               delete [] saveUpper;
+          }
+#ifdef ABC_INHERIT
+          model2->dealWithAbc(1,1);
+#else
+          model2->primal(1);
+#endif
+          model2->setPerturbation(savePerturbation);
+          if (model2 != originalModel2) {
+               originalModel2->moveInfo(*model2);
+               delete model2;
+               model2 = originalModel2;
+          }
+          time2 = CoinCpuTime();
+          timeCore = time2 - timeX;
+          handler_->message(CLP_INTERVAL_TIMING, messages_)
+                    << "Sprint" << timeCore << time2 - time1
+                    << CoinMessageEol;
+          timeX = time2;
+          model2->setNumberIterations(model2->numberIterations() + totalIterations);
+     } else if (method == ClpSolve::useBarrier || method == ClpSolve::useBarrierNoCross) {
+#ifndef SLIM_CLP
+          //printf("***** experimental pretty crude barrier\n");
+          //#define SAVEIT 2
+#ifndef SAVEIT
+#define BORROW
+#endif
+#ifdef BORROW
+          ClpInterior barrier;
+          barrier.borrowModel(*model2);
+#else
+          ClpInterior barrier(*model2);
+#endif
+          if (interrupt)
+               currentModel2 = &barrier;
+	  if (barrier.numberRows()+barrier.numberColumns()>10000)
+	    barrier.setMaximumBarrierIterations(1000);
+          int barrierOptions = options.getSpecialOption(4);
+          int aggressiveGamma = 0;
+          bool presolveInCrossover = false;
+          bool scale = false;
+          bool doKKT = false;
+          bool forceFixing = false;
+          int speed = 0;
+          if (barrierOptions & 16) {
+               barrierOptions &= ~16;
+               doKKT = true;
+          }
+          if (barrierOptions&(32 + 64 + 128)) {
+               aggressiveGamma = (barrierOptions & (32 + 64 + 128)) >> 5;
+               barrierOptions &= ~(32 + 64 + 128);
+          }
+          if (barrierOptions & 256) {
+               barrierOptions &= ~256;
+               presolveInCrossover = true;
+          }
+          if (barrierOptions & 512) {
+               barrierOptions &= ~512;
+               forceFixing = true;
+          }
+          if (barrierOptions & 1024) {
+               barrierOptions &= ~1024;
+               barrier.setProjectionTolerance(1.0e-9);
+          }
+          if (barrierOptions&(2048 | 4096)) {
+               speed = (barrierOptions & (2048 | 4096)) >> 11;
+               barrierOptions &= ~(2048 | 4096);
+          }
+          if (barrierOptions & 8) {
+               barrierOptions &= ~8;
+               scale = true;
+          }
+          // If quadratic force KKT
+          if (quadraticObj) {
+               doKKT = true;
+          }
+          switch (barrierOptions) {
+          case 0:
+          default:
+               if (!doKKT) {
+                    ClpCholeskyBase * cholesky = new ClpCholeskyBase(options.getExtraInfo(1));
+                    cholesky->setIntegerParameter(0, speed);
+                    barrier.setCholesky(cholesky);
+               } else {
+                    ClpCholeskyBase * cholesky = new ClpCholeskyBase();
+                    cholesky->setKKT(true);
+                    barrier.setCholesky(cholesky);
+               }
+               break;
+          case 1:
+               if (!doKKT) {
+                    ClpCholeskyDense * cholesky = new ClpCholeskyDense();
+                    barrier.setCholesky(cholesky);
+               } else {
+                    ClpCholeskyDense * cholesky = new ClpCholeskyDense();
+                    cholesky->setKKT(true);
+                    barrier.setCholesky(cholesky);
+               }
+               break;
+#ifdef COIN_HAS_WSMP
+          case 2: {
+               ClpCholeskyWssmp * cholesky = new ClpCholeskyWssmp(CoinMax(100, model2->numberRows() / 10));
+               barrier.setCholesky(cholesky);
+               assert (!doKKT);
+          }
+          break;
+          case 3:
+               if (!doKKT) {
+                    ClpCholeskyWssmp * cholesky = new ClpCholeskyWssmp();
+                    barrier.setCholesky(cholesky);
+               } else {
+                    ClpCholeskyWssmpKKT * cholesky = new ClpCholeskyWssmpKKT(CoinMax(100, model2->numberRows() / 10));
+                    barrier.setCholesky(cholesky);
+               }
+               break;
+#endif
+#ifdef UFL_BARRIER
+          case 4:
+               if (!doKKT) {
+                    ClpCholeskyUfl * cholesky = new ClpCholeskyUfl();
+                    barrier.setCholesky(cholesky);
+               } else {
+                    ClpCholeskyUfl * cholesky = new ClpCholeskyUfl();
+                    cholesky->setKKT(true);
+                    barrier.setCholesky(cholesky);
+               }
+               break;
+#endif
+#ifdef TAUCS_BARRIER
+          case 5: {
+               ClpCholeskyTaucs * cholesky = new ClpCholeskyTaucs();
+               barrier.setCholesky(cholesky);
+               assert (!doKKT);
+          }
+          break;
+#endif
+#ifdef COIN_HAS_MUMPS
+          case 6: {
+               ClpCholeskyMumps * cholesky = new ClpCholeskyMumps();
+               barrier.setCholesky(cholesky);
+               assert (!doKKT);
+          }
+          break;
+#endif
+          }
+          int numberRows = model2->numberRows();
+          int numberColumns = model2->numberColumns();
+          int saveMaxIts = model2->maximumIterations();
+          if (saveMaxIts < 1000) {
+               barrier.setMaximumBarrierIterations(saveMaxIts);
+               model2->setMaximumIterations(10000000);
+          }
+#ifndef SAVEIT
+          //barrier.setDiagonalPerturbation(1.0e-25);
+          if (aggressiveGamma) {
+               switch (aggressiveGamma) {
+               case 1:
+                    barrier.setGamma(1.0e-5);
+                    barrier.setDelta(1.0e-5);
+                    break;
+               case 2:
+                    barrier.setGamma(1.0e-7);
+                    break;
+               case 3:
+                    barrier.setDelta(1.0e-5);
+                    break;
+               case 4:
+                    barrier.setGamma(1.0e-3);
+                    barrier.setDelta(1.0e-3);
+                    break;
+               case 5:
+                    barrier.setGamma(1.0e-3);
+                    break;
+               case 6:
+                    barrier.setDelta(1.0e-3);
+                    break;
+               }
+          }
+          if (scale)
+               barrier.scaling(1);
+          else
+               barrier.scaling(0);
+          barrier.primalDual();
+#elif SAVEIT==1
+          barrier.primalDual();
+#else
+          model2->restoreModel("xx.save");
+          // move solutions
+          CoinMemcpyN(model2->primalRowSolution(),
+                      numberRows, barrier.primalRowSolution());
+          CoinMemcpyN(model2->dualRowSolution(),
+                      numberRows, barrier.dualRowSolution());
+          CoinMemcpyN(model2->primalColumnSolution(),
+                      numberColumns, barrier.primalColumnSolution());
+          CoinMemcpyN(model2->dualColumnSolution(),
+                      numberColumns, barrier.dualColumnSolution());
+#endif
+          time2 = CoinCpuTime();
+          timeCore = time2 - timeX;
+          handler_->message(CLP_INTERVAL_TIMING, messages_)
+                    << "Barrier" << timeCore << time2 - time1
+                    << CoinMessageEol;
+          timeX = time2;
+          int maxIts = barrier.maximumBarrierIterations();
+          int barrierStatus = barrier.status();
+          double gap = barrier.complementarityGap();
+          // get which variables are fixed
+          double * saveLower = NULL;
+          double * saveUpper = NULL;
+          ClpPresolve pinfo2;
+          ClpSimplex * saveModel2 = NULL;
+          bool extraPresolve = false;
+          int numberFixed = barrier.numberFixed();
+          if (numberFixed) {
+               int numberRows = barrier.numberRows();
+               int numberColumns = barrier.numberColumns();
+               int numberTotal = numberRows + numberColumns;
+               saveLower = new double [numberTotal];
+               saveUpper = new double [numberTotal];
+               CoinMemcpyN(barrier.columnLower(), numberColumns, saveLower);
+               CoinMemcpyN(barrier.rowLower(), numberRows, saveLower + numberColumns);
+               CoinMemcpyN(barrier.columnUpper(), numberColumns, saveUpper);
+               CoinMemcpyN(barrier.rowUpper(), numberRows, saveUpper + numberColumns);
+          }
+          if (((numberFixed * 20 > barrier.numberRows() && numberFixed > 5000) || forceFixing) &&
+                    presolveInCrossover) {
+               // may as well do presolve
+               if (!forceFixing) {
+                    barrier.fixFixed();
+               } else {
+                    // Fix
+                    int n = barrier.numberColumns();
+                    double * lower = barrier.columnLower();
+                    double * upper = barrier.columnUpper();
+                    double * solution = barrier.primalColumnSolution();
+                    int nFix = 0;
+                    for (int i = 0; i < n; i++) {
+                         if (barrier.fixedOrFree(i) && lower[i] < upper[i]) {
+                              double value = solution[i];
+                              if (value < lower[i] + 1.0e-6 && value - lower[i] < upper[i] - value) {
+                                   solution[i] = lower[i];
+                                   upper[i] = lower[i];
+                                   nFix++;
+                              } else if (value > upper[i] - 1.0e-6 && value - lower[i] > upper[i] - value) {
+                                   solution[i] = upper[i];
+                                   lower[i] = upper[i];
+                                   nFix++;
+                              }
+                         }
+                    }
+#ifdef CLP_INVESTIGATE
+                    printf("%d columns fixed\n", nFix);
+#endif
+                    int nr = barrier.numberRows();
+                    lower = barrier.rowLower();
+                    upper = barrier.rowUpper();
+                    solution = barrier.primalRowSolution();
+                    nFix = 0;
+                    for (int i = 0; i < nr; i++) {
+                         if (barrier.fixedOrFree(i + n) && lower[i] < upper[i]) {
+                              double value = solution[i];
+                              if (value < lower[i] + 1.0e-6 && value - lower[i] < upper[i] - value) {
+                                   solution[i] = lower[i];
+                                   upper[i] = lower[i];
+                                   nFix++;
+                              } else if (value > upper[i] - 1.0e-6 && value - lower[i] > upper[i] - value) {
+                                   solution[i] = upper[i];
+                                   lower[i] = upper[i];
+                                   nFix++;
+                              }
+                         }
+                    }
+#ifdef CLP_INVESTIGATE
+                    printf("%d row slacks fixed\n", nFix);
+#endif
+               }
+               saveModel2 = model2;
+               extraPresolve = true;
+          } else if (numberFixed) {
+               // Set fixed to bounds (may have restored earlier solution)
+               if (!forceFixing) {
+                    barrier.fixFixed(false);
+               } else {
+                    // Fix
+                    int n = barrier.numberColumns();
+                    double * lower = barrier.columnLower();
+                    double * upper = barrier.columnUpper();
+                    double * solution = barrier.primalColumnSolution();
+                    int nFix = 0;
+                    for (int i = 0; i < n; i++) {
+                         if (barrier.fixedOrFree(i) && lower[i] < upper[i]) {
+                              double value = solution[i];
+                              if (value < lower[i] + 1.0e-8 && value - lower[i] < upper[i] - value) {
+                                   solution[i] = lower[i];
+                                   upper[i] = lower[i];
+                                   nFix++;
+                              } else if (value > upper[i] - 1.0e-8 && value - lower[i] > upper[i] - value) {
+                                   solution[i] = upper[i];
+                                   lower[i] = upper[i];
+                                   nFix++;
+                              } else {
+                                   //printf("fixcol %d %g <= %g <= %g\n",
+                                   //     i,lower[i],solution[i],upper[i]);
+                              }
+                         }
+                    }
+#ifdef CLP_INVESTIGATE
+                    printf("%d columns fixed\n", nFix);
+#endif
+                    int nr = barrier.numberRows();
+                    lower = barrier.rowLower();
+                    upper = barrier.rowUpper();
+                    solution = barrier.primalRowSolution();
+                    nFix = 0;
+                    for (int i = 0; i < nr; i++) {
+                         if (barrier.fixedOrFree(i + n) && lower[i] < upper[i]) {
+                              double value = solution[i];
+                              if (value < lower[i] + 1.0e-5 && value - lower[i] < upper[i] - value) {
+                                   solution[i] = lower[i];
+                                   upper[i] = lower[i];
+                                   nFix++;
+                              } else if (value > upper[i] - 1.0e-5 && value - lower[i] > upper[i] - value) {
+                                   solution[i] = upper[i];
+                                   lower[i] = upper[i];
+                                   nFix++;
+                              } else {
+                                   //printf("fixrow %d %g <= %g <= %g\n",
+                                   //     i,lower[i],solution[i],upper[i]);
+                              }
+                         }
+                    }
+#ifdef CLP_INVESTIGATE
+                    printf("%d row slacks fixed\n", nFix);
+#endif
+               }
+          }
+#ifdef BORROW
+	  int saveNumberIterations = barrier.numberIterations();
+          barrier.returnModel(*model2);
+          double * rowPrimal = new double [numberRows];
+          double * columnPrimal = new double [numberColumns];
+          double * rowDual = new double [numberRows];
+          double * columnDual = new double [numberColumns];
+          // move solutions other way
+          CoinMemcpyN(model2->primalRowSolution(),
+                      numberRows, rowPrimal);
+          CoinMemcpyN(model2->dualRowSolution(),
+                      numberRows, rowDual);
+          CoinMemcpyN(model2->primalColumnSolution(),
+                      numberColumns, columnPrimal);
+          CoinMemcpyN(model2->dualColumnSolution(),
+                      numberColumns, columnDual);
+#else
+          double * rowPrimal = barrier.primalRowSolution();
+          double * columnPrimal = barrier.primalColumnSolution();
+          double * rowDual = barrier.dualRowSolution();
+          double * columnDual = barrier.dualColumnSolution();
+          // move solutions
+          CoinMemcpyN(rowPrimal,
+                      numberRows, model2->primalRowSolution());
+          CoinMemcpyN(rowDual,
+                      numberRows, model2->dualRowSolution());
+          CoinMemcpyN(columnPrimal,
+                      numberColumns, model2->primalColumnSolution());
+          CoinMemcpyN(columnDual,
+                      numberColumns, model2->dualColumnSolution());
+#endif
+          if (saveModel2) {
+               // do presolve
+               model2 = pinfo2.presolvedModel(*model2, dblParam_[ClpPresolveTolerance],
+                                              false, 5, true);
+               if (!model2) {
+                    model2 = saveModel2;
+                    saveModel2 = NULL;
+                    int numberRows = model2->numberRows();
+                    int numberColumns = model2->numberColumns();
+                    CoinMemcpyN(saveLower, numberColumns, model2->columnLower());
+                    CoinMemcpyN(saveLower + numberColumns, numberRows, model2->rowLower());
+                    delete [] saveLower;
+                    CoinMemcpyN(saveUpper, numberColumns, model2->columnUpper());
+                    CoinMemcpyN(saveUpper + numberColumns, numberRows, model2->rowUpper());
+                    delete [] saveUpper;
+                    saveLower = NULL;
+                    saveUpper = NULL;
+               }
+          }
+          if (method == ClpSolve::useBarrier || barrierStatus < 0) {
+               if (maxIts && barrierStatus < 4 && !quadraticObj) {
+                    //printf("***** crossover - needs more thought on difficult models\n");
+#if SAVEIT==1
+                    model2->ClpSimplex::saveModel("xx.save");
+#endif
+                    // make sure no status left
+                    model2->createStatus();
+                    // solve
+                    if (!forceFixing)
+                         model2->setPerturbation(100);
+                    if (model2->factorizationFrequency() == 200) {
+                         // User did not touch preset
+                         model2->defaultFactorizationFrequency();
+                    }
+#if 1 //ndef ABC_INHERIT //#if 1
+                    // throw some into basis
+                    if(!forceFixing) {
+                         int numberRows = model2->numberRows();
+                         int numberColumns = model2->numberColumns();
+                         double * dsort = new double[numberColumns];
+                         int * sort = new int[numberColumns];
+                         int n = 0;
+                         const double * columnLower = model2->columnLower();
+                         const double * columnUpper = model2->columnUpper();
+                         double * primalSolution = model2->primalColumnSolution();
+                         const double * dualSolution = model2->dualColumnSolution();
+                         double tolerance = 10.0 * primalTolerance_;
+                         int i;
+                         for ( i = 0; i < numberRows; i++)
+                              model2->setRowStatus(i, superBasic);
+                         for ( i = 0; i < numberColumns; i++) {
+                              double distance = CoinMin(columnUpper[i] - primalSolution[i],
+                                                        primalSolution[i] - columnLower[i]);
+                              if (distance > tolerance) {
+                                   if (fabs(dualSolution[i]) < 1.0e-5)
+                                        distance *= 100.0;
+                                   dsort[n] = -distance;
+                                   sort[n++] = i;
+                                   model2->setStatus(i, superBasic);
+                              } else if (distance > primalTolerance_) {
+                                   model2->setStatus(i, superBasic);
+                              } else if (primalSolution[i] <= columnLower[i] + primalTolerance_) {
+                                   model2->setStatus(i, atLowerBound);
+                                   primalSolution[i] = columnLower[i];
+                              } else {
+                                   model2->setStatus(i, atUpperBound);
+                                   primalSolution[i] = columnUpper[i];
+                              }
+                         }
+                         CoinSort_2(dsort, dsort + n, sort);
+                         n = CoinMin(numberRows, n);
+                         for ( i = 0; i < n; i++) {
+                              int iColumn = sort[i];
+                              model2->setStatus(iColumn, basic);
+                         }
+                         delete [] sort;
+                         delete [] dsort;
+                         // model2->allSlackBasis();
+                         if (gap < 1.0e-3 * static_cast<double> (numberRows + numberColumns)) {
+                              if (saveUpper) {
+                                   int numberRows = model2->numberRows();
+                                   int numberColumns = model2->numberColumns();
+                                   CoinMemcpyN(saveLower, numberColumns, model2->columnLower());
+                                   CoinMemcpyN(saveLower + numberColumns, numberRows, model2->rowLower());
+                                   CoinMemcpyN(saveUpper, numberColumns, model2->columnUpper());
+                                   CoinMemcpyN(saveUpper + numberColumns, numberRows, model2->rowUpper());
+                                   delete [] saveLower;
+                                   delete [] saveUpper;
+                                   saveLower = NULL;
+                                   saveUpper = NULL;
+                              }
+                              int numberRows = model2->numberRows();
+                              int numberColumns = model2->numberColumns();
+#ifdef ABC_INHERIT
+			      model2->checkSolution(0);
+			      printf("%d primal infeasibilities summing to %g\n",
+				     model2->numberPrimalInfeasibilities(),
+				     model2->sumPrimalInfeasibilities());
+			      model2->dealWithAbc(1,1);
+			 }
+		    }
+#else
+                              // just primal values pass
+                              double saveScale = model2->objectiveScale();
+                              model2->setObjectiveScale(1.0e-3);
+                              model2->primal(2);
+                              model2->setObjectiveScale(saveScale);
+                              // save primal solution and copy back dual
+                              CoinMemcpyN(model2->primalRowSolution(),
+                                          numberRows, rowPrimal);
+                              CoinMemcpyN(rowDual,
+                                          numberRows, model2->dualRowSolution());
+                              CoinMemcpyN(model2->primalColumnSolution(),
+                                          numberColumns, columnPrimal);
+                              CoinMemcpyN(columnDual,
+                                          numberColumns, model2->dualColumnSolution());
+                              //model2->primal(1);
+                              // clean up reduced costs and flag variables
+                              {
+                                   double * dj = model2->dualColumnSolution();
+                                   double * cost = model2->objective();
+                                   double * saveCost = new double[numberColumns];
+                                   CoinMemcpyN(cost, numberColumns, saveCost);
+                                   double * saveLower = new double[numberColumns];
+                                   double * lower = model2->columnLower();
+                                   CoinMemcpyN(lower, numberColumns, saveLower);
+                                   double * saveUpper = new double[numberColumns];
+                                   double * upper = model2->columnUpper();
+                                   CoinMemcpyN(upper, numberColumns, saveUpper);
+                                   int i;
+                                   double tolerance = 10.0 * dualTolerance_;
+                                   for ( i = 0; i < numberColumns; i++) {
+                                        if (model2->getStatus(i) == basic) {
+                                             dj[i] = 0.0;
+                                        } else if (model2->getStatus(i) == atLowerBound) {
+                                             if (optimizationDirection_ * dj[i] < tolerance) {
+                                                  if (optimizationDirection_ * dj[i] < 0.0) {
+                                                       //if (dj[i]<-1.0e-3)
+                                                       //printf("bad dj at lb %d %g\n",i,dj[i]);
+                                                       cost[i] -= dj[i];
+                                                       dj[i] = 0.0;
+                                                  }
+                                             } else {
+                                                  upper[i] = lower[i];
+                                             }
+                                        } else if (model2->getStatus(i) == atUpperBound) {
+                                             if (optimizationDirection_ * dj[i] > tolerance) {
+                                                  if (optimizationDirection_ * dj[i] > 0.0) {
+                                                       //if (dj[i]>1.0e-3)
+                                                       //printf("bad dj at ub %d %g\n",i,dj[i]);
+                                                       cost[i] -= dj[i];
+                                                       dj[i] = 0.0;
+                                                  }
+                                             } else {
+                                                  lower[i] = upper[i];
+                                             }
+                                        }
+                                   }
+                                   // just dual values pass
+                                   //model2->setLogLevel(63);
+                                   //model2->setFactorizationFrequency(1);
+                                   model2->dual(2);
+                                   CoinMemcpyN(saveCost, numberColumns, cost);
+                                   delete [] saveCost;
+                                   CoinMemcpyN(saveLower, numberColumns, lower);
+                                   delete [] saveLower;
+                                   CoinMemcpyN(saveUpper, numberColumns, upper);
+                                   delete [] saveUpper;
+                              }
+                         }
+                         // and finish
+                         // move solutions
+                         CoinMemcpyN(rowPrimal,
+                                     numberRows, model2->primalRowSolution());
+                         CoinMemcpyN(columnPrimal,
+                                     numberColumns, model2->primalColumnSolution());
+                    }
+                    double saveScale = model2->objectiveScale();
+                    model2->setObjectiveScale(1.0e-3);
+                    model2->primal(2);
+                    model2->setObjectiveScale(saveScale);
+                    model2->primal(1);
+#endif
+#else
+                    // just primal
+#ifdef ABC_INHERIT
+		    model2->checkSolution(0);
+		    printf("%d primal infeasibilities summing to %g\n",
+			   model2->numberPrimalInfeasibilities(),
+			   model2->sumPrimalInfeasibilities());
+		    model2->dealWithAbc(1,1);
+#else
+		    model2->primal(1);
+#endif
+		    //model2->primal(1);
+#endif
+               } else if (barrierStatus == 4) {
+                    // memory problems
+                    model2->setPerturbation(savePerturbation);
+                    model2->createStatus();
+                    model2->dual();
+               } else if (maxIts && quadraticObj) {
+                    // make sure no status left
+                    model2->createStatus();
+                    // solve
+                    model2->setPerturbation(100);
+                    model2->reducedGradient(1);
+               }
+          }
+
+          //model2->setMaximumIterations(saveMaxIts);
+#ifdef BORROW
+          model2->setNumberIterations(model2->numberIterations()+saveNumberIterations);
+          delete [] rowPrimal;
+          delete [] columnPrimal;
+          delete [] rowDual;
+          delete [] columnDual;
+#endif
+          if (extraPresolve) {
+               pinfo2.postsolve(true);
+               delete model2;
+               model2 = saveModel2;
+          }
+          if (saveUpper) {
+               if (!forceFixing) {
+                    int numberRows = model2->numberRows();
+                    int numberColumns = model2->numberColumns();
+                    CoinMemcpyN(saveLower, numberColumns, model2->columnLower());
+                    CoinMemcpyN(saveLower + numberColumns, numberRows, model2->rowLower());
+                    CoinMemcpyN(saveUpper, numberColumns, model2->columnUpper());
+                    CoinMemcpyN(saveUpper + numberColumns, numberRows, model2->rowUpper());
+               }
+               delete [] saveLower;
+               delete [] saveUpper;
+               saveLower = NULL;
+               saveUpper = NULL;
+               if (method != ClpSolve::useBarrierNoCross)
+                    model2->primal(1);
+          }
+          model2->setPerturbation(savePerturbation);
+          time2 = CoinCpuTime();
+          timeCore = time2 - timeX;
+          handler_->message(CLP_INTERVAL_TIMING, messages_)
+                    << "Crossover" << timeCore << time2 - time1
+                    << CoinMessageEol;
+          timeX = time2;
+#else
+          abort();
+#endif
+     } else {
+          assert (method != ClpSolve::automatic); // later
+          time2 = 0.0;
+     }
+     if (saveMatrix) {
+          if (model2 == this) {
+               // delete and replace
+               delete model2->clpMatrix();
+               model2->replaceMatrix(saveMatrix);
+          } else {
+               delete saveMatrix;
+          }
+     }
+     numberIterations = model2->numberIterations();
+     finalStatus = model2->status();
+     int finalSecondaryStatus = model2->secondaryStatus();
+     if (presolve == ClpSolve::presolveOn) {
+          int saveLevel = logLevel();
+          if ((specialOptions_ & 1024) == 0)
+               setLogLevel(CoinMin(1, saveLevel));
+          else
+               setLogLevel(CoinMin(0, saveLevel));
+          pinfo->postsolve(true);
+	  numberIterations_ = 0;
+	  delete pinfo;
+	  pinfo = NULL;
+          factorization_->areaFactor(model2->factorization()->adjustedAreaFactor());
+          time2 = CoinCpuTime();
+          timePresolve += time2 - timeX;
+          handler_->message(CLP_INTERVAL_TIMING, messages_)
+                    << "Postsolve" << time2 - timeX << time2 - time1
+                    << CoinMessageEol;
+          timeX = time2;
+          if (!presolveToFile) {
+#if 1 //ndef ABC_INHERIT
+               delete model2;
+#else
+               if (model2->abcSimplex())
+		 delete model2->abcSimplex();
+	       else
+		 delete model2;
+#endif
+	  }
+          if (interrupt)
+               currentModel = this;
+          // checkSolution(); already done by postSolve
+          setLogLevel(saveLevel);
+	  int oldStatus=problemStatus_;
+	  setProblemStatus(finalStatus);
+	  setSecondaryStatus(finalSecondaryStatus);
+	  int rcode=eventHandler()->event(ClpEventHandler::presolveAfterFirstSolve);
+          if (finalStatus != 3 && rcode < 0 && (finalStatus || oldStatus == -1)) {
+               int savePerturbation = perturbation();
+               if (!finalStatus || (moreSpecialOptions_ & 2) == 0 ||
+		   fabs(sumDualInfeasibilities_)+
+		   fabs(sumPrimalInfeasibilities_)<1.0e-3) {
+                    if (finalStatus == 2) {
+                         // unbounded - get feasible first
+                         double save = optimizationDirection_;
+                         optimizationDirection_ = 0.0;
+                         primal(1);
+                         optimizationDirection_ = save;
+                         primal(1);
+                    } else if (finalStatus == 1) {
+                         dual();
+                    } else {
+		        if ((moreSpecialOptions_&65536)==0) {
+			  if (numberRows_<10000) 
+			    setPerturbation(100); // probably better to perturb after n its
+			  else if (savePerturbation<100)
+			    setPerturbation(51); // probably better to perturb after n its
+			}
+#ifndef ABC_INHERIT
+		        primal(1);
+#else
+			dealWithAbc(1,2,interrupt);
+#endif
+                    }
+               } else {
+                    // just set status
+                    problemStatus_ = finalStatus;
+               }
+               setPerturbation(savePerturbation);
+               numberIterations += numberIterations_;
+               numberIterations_ = numberIterations;
+               finalStatus = status();
+               time2 = CoinCpuTime();
+               handler_->message(CLP_INTERVAL_TIMING, messages_)
+                         << "Cleanup" << time2 - timeX << time2 - time1
+                         << CoinMessageEol;
+               timeX = time2;
+          } else if (rcode >= 0) {
+#ifdef ABC_INHERIT
+	    dealWithAbc(1,2,true);
+#else
+	    primal(1);
+#endif
+	  } else {
+               secondaryStatus_ = finalSecondaryStatus;
+          }
+     } else if (model2 != this) {
+          // not presolved - but different model used (sprint probably)
+          CoinMemcpyN(model2->primalRowSolution(),
+                      numberRows_, this->primalRowSolution());
+          CoinMemcpyN(model2->dualRowSolution(),
+                      numberRows_, this->dualRowSolution());
+          CoinMemcpyN(model2->primalColumnSolution(),
+                      numberColumns_, this->primalColumnSolution());
+          CoinMemcpyN(model2->dualColumnSolution(),
+                      numberColumns_, this->dualColumnSolution());
+          CoinMemcpyN(model2->statusArray(),
+                      numberColumns_ + numberRows_, this->statusArray());
+          objectiveValue_ = model2->objectiveValue_;
+          numberIterations_ = model2->numberIterations_;
+          problemStatus_ = model2->problemStatus_;
+          secondaryStatus_ = model2->secondaryStatus_;
+          delete model2;
+     }
+     if (method != ClpSolve::useBarrierNoCross &&
+               method != ClpSolve::useBarrier)
+          setMaximumIterations(saveMaxIterations);
+     std::string statusMessage[] = {"Unknown", "Optimal", "PrimalInfeasible", "DualInfeasible", "Stopped",
+                                    "Errors", "User stopped"
+                                   };
+     assert (finalStatus >= -1 && finalStatus <= 5);
+     numberIterations_ = numberIterations;
+     handler_->message(CLP_TIMING, messages_)
+               << statusMessage[finalStatus+1] << objectiveValue() << numberIterations << time2 - time1;
+     handler_->printing(presolve == ClpSolve::presolveOn)
+               << timePresolve;
+     handler_->printing(timeIdiot != 0.0)
+               << timeIdiot;
+     handler_->message() << CoinMessageEol;
+     if (interrupt)
+          signal(SIGINT, saveSignal);
+     perturbation_ = savePerturbation;
+     scalingFlag_ = saveScaling;
+     // If faking objective - put back correct one
+     if (savedObjective) {
+          delete objective_;
+          objective_ = savedObjective;
+     }
+     if (options.getSpecialOption(1) == 2 &&
+               options.getExtraInfo(1) > 1000000) {
+          ClpObjective * savedObjective = objective_;
+          // make up zero objective
+          double * obj = new double[numberColumns_];
+          for (int i = 0; i < numberColumns_; i++)
+               obj[i] = 0.0;
+          objective_ = new ClpLinearObjective(obj, numberColumns_);
+          delete [] obj;
+          primal(1);
+          delete objective_;
+          objective_ = savedObjective;
+          finalStatus = status();
+     }
+     eventHandler()->event(ClpEventHandler::presolveEnd);
+     delete pinfo;
+     return finalStatus;
+}
+// General solve
+int
+ClpSimplex::initialSolve()
+{
+     // Default so use dual
+     ClpSolve options;
+     return initialSolve(options);
+}
+// General dual solve
+int
+ClpSimplex::initialDualSolve()
+{
+     ClpSolve options;
+     // Use dual
+     options.setSolveType(ClpSolve::useDual);
+     return initialSolve(options);
+}
+// General primal solve
+int
+ClpSimplex::initialPrimalSolve()
+{
+     ClpSolve options;
+     // Use primal
+     options.setSolveType(ClpSolve::usePrimal);
+     return initialSolve(options);
+}
+// barrier solve, not to be followed by crossover
+int
+ClpSimplex::initialBarrierNoCrossSolve()
+{
+     ClpSolve options;
+     // Use primal
+     options.setSolveType(ClpSolve::useBarrierNoCross);
+     return initialSolve(options);
+}
+
+// General barrier solve
+int
+ClpSimplex::initialBarrierSolve()
+{
+     ClpSolve options;
+     // Use primal
+     options.setSolveType(ClpSolve::useBarrier);
+     return initialSolve(options);
+}
+
+// Default constructor
+ClpSolve::ClpSolve (  )
+{
+     method_ = automatic;
+     presolveType_ = presolveOn;
+     numberPasses_ = 5;
+     int i;
+     for (i = 0; i < 7; i++)
+          options_[i] = 0;
+     // say no +-1 matrix
+     options_[3] = 1;
+     for (i = 0; i < 7; i++)
+          extraInfo_[i] = -1;
+     independentOptions_[0] = 0;
+     // But switch off slacks
+     independentOptions_[1] = 512;
+     // Substitute up to 3
+     independentOptions_[2] = 3;
+
+}
+// Constructor when you really know what you are doing
+ClpSolve::ClpSolve ( SolveType method, PresolveType presolveType,
+                     int numberPasses, int options[6],
+                     int extraInfo[6], int independentOptions[3])
+{
+     method_ = method;
+     presolveType_ = presolveType;
+     numberPasses_ = numberPasses;
+     int i;
+     for (i = 0; i < 6; i++)
+          options_[i] = options[i];
+     options_[6] = 0;
+     for (i = 0; i < 6; i++)
+          extraInfo_[i] = extraInfo[i];
+     extraInfo_[6] = 0;
+     for (i = 0; i < 3; i++)
+          independentOptions_[i] = independentOptions[i];
+}
+
+// Copy constructor.
+ClpSolve::ClpSolve(const ClpSolve & rhs)
+{
+     method_ = rhs.method_;
+     presolveType_ = rhs.presolveType_;
+     numberPasses_ = rhs.numberPasses_;
+     int i;
+     for ( i = 0; i < 7; i++)
+          options_[i] = rhs.options_[i];
+     for ( i = 0; i < 7; i++)
+          extraInfo_[i] = rhs.extraInfo_[i];
+     for (i = 0; i < 3; i++)
+          independentOptions_[i] = rhs.independentOptions_[i];
+}
+// Assignment operator. This copies the data
+ClpSolve &
+ClpSolve::operator=(const ClpSolve & rhs)
+{
+     if (this != &rhs) {
+          method_ = rhs.method_;
+          presolveType_ = rhs.presolveType_;
+          numberPasses_ = rhs.numberPasses_;
+          int i;
+          for (i = 0; i < 7; i++)
+               options_[i] = rhs.options_[i];
+          for (i = 0; i < 7; i++)
+               extraInfo_[i] = rhs.extraInfo_[i];
+          for (i = 0; i < 3; i++)
+               independentOptions_[i] = rhs.independentOptions_[i];
+     }
+     return *this;
+
+}
+// Destructor
+ClpSolve::~ClpSolve (  )
+{
+}
+// See header file for details
+void
+ClpSolve::setSpecialOption(int which, int value, int extraInfo)
+{
+     options_[which] = value;
+     extraInfo_[which] = extraInfo;
+}
+int
+ClpSolve::getSpecialOption(int which) const
+{
+     return options_[which];
+}
+
+// Solve types
+void
+ClpSolve::setSolveType(SolveType method, int /*extraInfo*/)
+{
+     method_ = method;
+}
+
+ClpSolve::SolveType
+ClpSolve::getSolveType()
+{
+     return method_;
+}
+
+// Presolve types
+void
+ClpSolve::setPresolveType(PresolveType amount, int extraInfo)
+{
+     presolveType_ = amount;
+     numberPasses_ = extraInfo;
+}
+ClpSolve::PresolveType
+ClpSolve::getPresolveType()
+{
+     return presolveType_;
+}
+// Extra info for idiot (or sprint)
+int
+ClpSolve::getExtraInfo(int which) const
+{
+     return extraInfo_[which];
+}
+int
+ClpSolve::getPresolvePasses() const
+{
+     return numberPasses_;
+}
+/* Say to return at once if infeasible,
+   default is to solve */
+void
+ClpSolve::setInfeasibleReturn(bool trueFalse)
+{
+     independentOptions_[0] = trueFalse ? 1 : 0;
+}
+#include <string>
+// Generates code for above constructor
+void
+ClpSolve::generateCpp(FILE * fp)
+{
+     std::string solveType[] = {
+          "ClpSolve::useDual",
+          "ClpSolve::usePrimal",
+          "ClpSolve::usePrimalorSprint",
+          "ClpSolve::useBarrier",
+          "ClpSolve::useBarrierNoCross",
+          "ClpSolve::automatic",
+          "ClpSolve::notImplemented"
+     };
+     std::string presolveType[] =  {
+          "ClpSolve::presolveOn",
+          "ClpSolve::presolveOff",
+          "ClpSolve::presolveNumber",
+          "ClpSolve::presolveNumberCost"
+     };
+     fprintf(fp, "3  ClpSolve::SolveType method = %s;\n", solveType[method_].c_str());
+     fprintf(fp, "3  ClpSolve::PresolveType presolveType = %s;\n",
+             presolveType[presolveType_].c_str());
+     fprintf(fp, "3  int numberPasses = %d;\n", numberPasses_);
+     fprintf(fp, "3  int options[] = {%d,%d,%d,%d,%d,%d};\n",
+             options_[0], options_[1], options_[2],
+             options_[3], options_[4], options_[5]);
+     fprintf(fp, "3  int extraInfo[] = {%d,%d,%d,%d,%d,%d};\n",
+             extraInfo_[0], extraInfo_[1], extraInfo_[2],
+             extraInfo_[3], extraInfo_[4], extraInfo_[5]);
+     fprintf(fp, "3  int independentOptions[] = {%d,%d,%d};\n",
+             independentOptions_[0], independentOptions_[1], independentOptions_[2]);
+     fprintf(fp, "3  ClpSolve clpSolve(method,presolveType,numberPasses,\n");
+     fprintf(fp, "3                    options,extraInfo,independentOptions);\n");
+}
+//#############################################################################
+#include "ClpNonLinearCost.hpp"
+
+ClpSimplexProgress::ClpSimplexProgress ()
+{
+     int i;
+     for (i = 0; i < CLP_PROGRESS; i++) {
+          objective_[i] = COIN_DBL_MAX;
+          infeasibility_[i] = -1.0; // set to an impossible value
+          realInfeasibility_[i] = COIN_DBL_MAX;
+          numberInfeasibilities_[i] = -1;
+          iterationNumber_[i] = -1;
+     }
+#ifdef CLP_PROGRESS_WEIGHT
+     for (i = 0; i < CLP_PROGRESS_WEIGHT; i++) {
+          objectiveWeight_[i] = COIN_DBL_MAX;
+          infeasibilityWeight_[i] = -1.0; // set to an impossible value
+          realInfeasibilityWeight_[i] = COIN_DBL_MAX;
+          numberInfeasibilitiesWeight_[i] = -1;
+          iterationNumberWeight_[i] = -1;
+     }
+     drop_ = 0.0;
+     best_ = 0.0;
+#endif
+     initialWeight_ = 0.0;
+     for (i = 0; i < CLP_CYCLE; i++) {
+          //obj_[i]=COIN_DBL_MAX;
+          in_[i] = -1;
+          out_[i] = -1;
+          way_[i] = 0;
+     }
+     numberTimes_ = 0;
+     numberBadTimes_ = 0;
+     numberReallyBadTimes_ = 0;
+     numberTimesFlagged_ = 0;
+     model_ = NULL;
+     oddState_ = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+
+ClpSimplexProgress::~ClpSimplexProgress ()
+{
+}
+// Copy constructor.
+ClpSimplexProgress::ClpSimplexProgress(const ClpSimplexProgress &rhs)
+{
+     int i;
+     for (i = 0; i < CLP_PROGRESS; i++) {
+          objective_[i] = rhs.objective_[i];
+          infeasibility_[i] = rhs.infeasibility_[i];
+          realInfeasibility_[i] = rhs.realInfeasibility_[i];
+          numberInfeasibilities_[i] = rhs.numberInfeasibilities_[i];
+          iterationNumber_[i] = rhs.iterationNumber_[i];
+     }
+#ifdef CLP_PROGRESS_WEIGHT
+     for (i = 0; i < CLP_PROGRESS_WEIGHT; i++) {
+          objectiveWeight_[i] = rhs.objectiveWeight_[i];
+          infeasibilityWeight_[i] = rhs.infeasibilityWeight_[i];
+          realInfeasibilityWeight_[i] = rhs.realInfeasibilityWeight_[i];
+          numberInfeasibilitiesWeight_[i] = rhs.numberInfeasibilitiesWeight_[i];
+          iterationNumberWeight_[i] = rhs.iterationNumberWeight_[i];
+     }
+     drop_ = rhs.drop_;
+     best_ = rhs.best_;
+#endif
+     initialWeight_ = rhs.initialWeight_;
+     for (i = 0; i < CLP_CYCLE; i++) {
+          //obj_[i]=rhs.obj_[i];
+          in_[i] = rhs.in_[i];
+          out_[i] = rhs.out_[i];
+          way_[i] = rhs.way_[i];
+     }
+     numberTimes_ = rhs.numberTimes_;
+     numberBadTimes_ = rhs.numberBadTimes_;
+     numberReallyBadTimes_ = rhs.numberReallyBadTimes_;
+     numberTimesFlagged_ = rhs.numberTimesFlagged_;
+     model_ = rhs.model_;
+     oddState_ = rhs.oddState_;
+}
+// Copy constructor.from model
+ClpSimplexProgress::ClpSimplexProgress(ClpSimplex * model)
+{
+     model_ = model;
+     reset();
+     initialWeight_ = 0.0;
+}
+// Fill from model
+void
+ClpSimplexProgress::fillFromModel ( ClpSimplex * model )
+{
+     model_ = model;
+     reset();
+     initialWeight_ = 0.0;
+}
+// Assignment operator. This copies the data
+ClpSimplexProgress &
+ClpSimplexProgress::operator=(const ClpSimplexProgress & rhs)
+{
+     if (this != &rhs) {
+          int i;
+          for (i = 0; i < CLP_PROGRESS; i++) {
+               objective_[i] = rhs.objective_[i];
+               infeasibility_[i] = rhs.infeasibility_[i];
+               realInfeasibility_[i] = rhs.realInfeasibility_[i];
+               numberInfeasibilities_[i] = rhs.numberInfeasibilities_[i];
+               iterationNumber_[i] = rhs.iterationNumber_[i];
+          }
+#ifdef CLP_PROGRESS_WEIGHT
+          for (i = 0; i < CLP_PROGRESS_WEIGHT; i++) {
+               objectiveWeight_[i] = rhs.objectiveWeight_[i];
+               infeasibilityWeight_[i] = rhs.infeasibilityWeight_[i];
+               realInfeasibilityWeight_[i] = rhs.realInfeasibilityWeight_[i];
+               numberInfeasibilitiesWeight_[i] = rhs.numberInfeasibilitiesWeight_[i];
+               iterationNumberWeight_[i] = rhs.iterationNumberWeight_[i];
+          }
+          drop_ = rhs.drop_;
+          best_ = rhs.best_;
+#endif
+          initialWeight_ = rhs.initialWeight_;
+          for (i = 0; i < CLP_CYCLE; i++) {
+               //obj_[i]=rhs.obj_[i];
+               in_[i] = rhs.in_[i];
+               out_[i] = rhs.out_[i];
+               way_[i] = rhs.way_[i];
+          }
+          numberTimes_ = rhs.numberTimes_;
+          numberBadTimes_ = rhs.numberBadTimes_;
+          numberReallyBadTimes_ = rhs.numberReallyBadTimes_;
+          numberTimesFlagged_ = rhs.numberTimesFlagged_;
+          model_ = rhs.model_;
+          oddState_ = rhs.oddState_;
+     }
+     return *this;
+}
+// Seems to be something odd about exact comparison of doubles on linux
+static bool equalDouble(double value1, double value2)
+{
+
+     union {
+          double d;
+          int i[2];
+     } v1, v2;
+     v1.d = value1;
+     v2.d = value2;
+     if (sizeof(int) * 2 == sizeof(double))
+          return (v1.i[0] == v2.i[0] && v1.i[1] == v2.i[1]);
+     else
+          return (v1.i[0] == v2.i[0]);
+}
+int
+ClpSimplexProgress::looping()
+{
+     if (!model_)
+          return -1;
+     double objective;
+     if (model_->algorithm() < 0) {
+       objective = model_->rawObjectiveValue();
+          objective -= model_->bestPossibleImprovement();
+     } else {
+       objective = model_->rawObjectiveValue();
+     }
+     double infeasibility;
+     double realInfeasibility = 0.0;
+     int numberInfeasibilities;
+     int iterationNumber = model_->numberIterations();
+     numberTimesFlagged_ = 0;
+     if (model_->algorithm() < 0) {
+          // dual
+          infeasibility = model_->sumPrimalInfeasibilities();
+          numberInfeasibilities = model_->numberPrimalInfeasibilities();
+     } else {
+          //primal
+          infeasibility = model_->sumDualInfeasibilities();
+          realInfeasibility = model_->nonLinearCost()->sumInfeasibilities();
+          numberInfeasibilities = model_->numberDualInfeasibilities();
+     }
+     int i;
+     int numberMatched = 0;
+     int matched = 0;
+     int nsame = 0;
+     for (i = 0; i < CLP_PROGRESS; i++) {
+          bool matchedOnObjective = equalDouble(objective, objective_[i]);
+          bool matchedOnInfeasibility = equalDouble(infeasibility, infeasibility_[i]);
+          bool matchedOnInfeasibilities =
+               (numberInfeasibilities == numberInfeasibilities_[i]);
+
+          if (matchedOnObjective && matchedOnInfeasibility && matchedOnInfeasibilities) {
+               matched |= (1 << i);
+               // Check not same iteration
+               if (iterationNumber != iterationNumber_[i]) {
+                    numberMatched++;
+                    // here mainly to get over compiler bug?
+                    if (model_->messageHandler()->logLevel() > 10)
+                         printf("%d %d %d %d %d loop check\n", i, numberMatched,
+                                matchedOnObjective, matchedOnInfeasibility,
+                                matchedOnInfeasibilities);
+               } else {
+                    // stuck but code should notice
+                    nsame++;
+               }
+          }
+          if (i) {
+               objective_[i-1] = objective_[i];
+               infeasibility_[i-1] = infeasibility_[i];
+               realInfeasibility_[i-1] = realInfeasibility_[i];
+               numberInfeasibilities_[i-1] = numberInfeasibilities_[i];
+               iterationNumber_[i-1] = iterationNumber_[i];
+          }
+     }
+     objective_[CLP_PROGRESS-1] = objective;
+     infeasibility_[CLP_PROGRESS-1] = infeasibility;
+     realInfeasibility_[CLP_PROGRESS-1] = realInfeasibility;
+     numberInfeasibilities_[CLP_PROGRESS-1] = numberInfeasibilities;
+     iterationNumber_[CLP_PROGRESS-1] = iterationNumber;
+     if (nsame == CLP_PROGRESS)
+          numberMatched = CLP_PROGRESS; // really stuck
+     if (model_->progressFlag())
+          numberMatched = 0;
+     numberTimes_++;
+     if (numberTimes_ < 10)
+          numberMatched = 0;
+     // skip if just last time as may be checking something
+     if (matched == (1 << (CLP_PROGRESS - 1)))
+          numberMatched = 0;
+     if (numberMatched && model_->clpMatrix()->type() < 15) {
+          model_->messageHandler()->message(CLP_POSSIBLELOOP, model_->messages())
+                    << numberMatched
+                    << matched
+                    << numberTimes_
+                    << CoinMessageEol;
+          numberBadTimes_++;
+          if (numberBadTimes_ < 10) {
+               // make factorize every iteration
+               model_->forceFactorization(1);
+               if (numberBadTimes_ < 2) {
+                    startCheck(); // clear other loop check
+                    if (model_->algorithm() < 0) {
+                         // dual - change tolerance
+                         model_->setCurrentDualTolerance(model_->currentDualTolerance() * 1.05);
+                         // if infeasible increase dual bound
+                         if (model_->dualBound() < 1.0e17) {
+                              model_->setDualBound(model_->dualBound() * 1.1);
+                              static_cast<ClpSimplexDual *>(model_)->resetFakeBounds(0);
+                         }
+                    } else {
+                         // primal - change tolerance
+                         if (numberBadTimes_ > 3)
+                              model_->setCurrentPrimalTolerance(model_->currentPrimalTolerance() * 1.05);
+                         // if infeasible increase infeasibility cost
+                         if (model_->nonLinearCost()->numberInfeasibilities() &&
+                                   model_->infeasibilityCost() < 1.0e17) {
+                              model_->setInfeasibilityCost(model_->infeasibilityCost() * 1.1);
+                         }
+                    }
+               } else {
+                    // flag
+                    int iSequence;
+                    if (model_->algorithm() < 0) {
+                         // dual
+                         if (model_->dualBound() > 1.0e14)
+                              model_->setDualBound(1.0e14);
+                         iSequence = in_[CLP_CYCLE-1];
+                    } else {
+                         // primal
+                         if (model_->infeasibilityCost() > 1.0e14)
+                              model_->setInfeasibilityCost(1.0e14);
+                         iSequence = out_[CLP_CYCLE-1];
+                    }
+                    if (iSequence >= 0) {
+                         char x = model_->isColumn(iSequence) ? 'C' : 'R';
+                         if (model_->messageHandler()->logLevel() >= 63)
+                              model_->messageHandler()->message(CLP_SIMPLEX_FLAG, model_->messages())
+                                        << x << model_->sequenceWithin(iSequence)
+                                        << CoinMessageEol;
+                         // if Gub then needs to be sequenceIn_
+                         int save = model_->sequenceIn();
+                         model_->setSequenceIn(iSequence);
+                         model_->setFlagged(iSequence);
+                         model_->setSequenceIn(save);
+                         //printf("flagging %d from loop\n",iSequence);
+                         startCheck();
+                    } else {
+                         // Give up
+                         if (model_->messageHandler()->logLevel() >= 63)
+                              printf("***** All flagged?\n");
+                         return 4;
+                    }
+                    // reset
+                    numberBadTimes_ = 2;
+               }
+               return -2;
+          } else {
+               // look at solution and maybe declare victory
+               if (infeasibility < 1.0e-4) {
+                    return 0;
+               } else {
+                    model_->messageHandler()->message(CLP_LOOP, model_->messages())
+                              << CoinMessageEol;
+#ifndef NDEBUG
+                    printf("debug loop ClpSimplex A\n");
+                    abort();
+#endif
+                    return 3;
+               }
+          }
+     }
+     return -1;
+}
+// Resets as much as possible
+void
+ClpSimplexProgress::reset()
+{
+     int i;
+     for (i = 0; i < CLP_PROGRESS; i++) {
+          if (model_->algorithm() >= 0)
+               objective_[i] = COIN_DBL_MAX;
+          else
+               objective_[i] = -COIN_DBL_MAX;
+          infeasibility_[i] = -1.0; // set to an impossible value
+          realInfeasibility_[i] = COIN_DBL_MAX;
+          numberInfeasibilities_[i] = -1;
+          iterationNumber_[i] = -1;
+     }
+#ifdef CLP_PROGRESS_WEIGHT
+     for (i = 0; i < CLP_PROGRESS_WEIGHT; i++) {
+          objectiveWeight_[i] = COIN_DBL_MAX;
+          infeasibilityWeight_[i] = -1.0; // set to an impossible value
+          realInfeasibilityWeight_[i] = COIN_DBL_MAX;
+          numberInfeasibilitiesWeight_[i] = -1;
+          iterationNumberWeight_[i] = -1;
+     }
+     drop_ = 0.0;
+     best_ = 0.0;
+#endif
+     for (i = 0; i < CLP_CYCLE; i++) {
+          //obj_[i]=COIN_DBL_MAX;
+          in_[i] = -1;
+          out_[i] = -1;
+          way_[i] = 0;
+     }
+     numberTimes_ = 0;
+     numberBadTimes_ = 0;
+     numberReallyBadTimes_ = 0;
+     numberTimesFlagged_ = 0;
+     oddState_ = 0;
+}
+// Returns previous objective (if -1) - current if (0)
+double
+ClpSimplexProgress::lastObjective(int back) const
+{
+     return objective_[CLP_PROGRESS-1-back];
+}
+// Returns previous infeasibility (if -1) - current if (0)
+double
+ClpSimplexProgress::lastInfeasibility(int back) const
+{
+     return realInfeasibility_[CLP_PROGRESS-1-back];
+}
+// Sets real primal infeasibility
+void
+ClpSimplexProgress::setInfeasibility(double value)
+{
+     for (int i = 1; i < CLP_PROGRESS; i++)
+          realInfeasibility_[i-1] = realInfeasibility_[i];
+     realInfeasibility_[CLP_PROGRESS-1] = value;
+}
+// Modify objective e.g. if dual infeasible in dual
+void
+ClpSimplexProgress::modifyObjective(double value)
+{
+     objective_[CLP_PROGRESS-1] = value;
+}
+// Returns previous iteration number (if -1) - current if (0)
+int
+ClpSimplexProgress::lastIterationNumber(int back) const
+{
+     return iterationNumber_[CLP_PROGRESS-1-back];
+}
+// clears iteration numbers (to switch off panic)
+void
+ClpSimplexProgress::clearIterationNumbers()
+{
+     for (int i = 0; i < CLP_PROGRESS; i++)
+          iterationNumber_[i] = -1;
+}
+// Start check at beginning of whileIterating
+void
+ClpSimplexProgress::startCheck()
+{
+     int i;
+     for (i = 0; i < CLP_CYCLE; i++) {
+          //obj_[i]=COIN_DBL_MAX;
+          in_[i] = -1;
+          out_[i] = -1;
+          way_[i] = 0;
+     }
+}
+// Returns cycle length in whileIterating
+int
+ClpSimplexProgress::cycle(int in, int out, int wayIn, int wayOut)
+{
+     int i;
+#if 0
+     if (model_->numberIterations() > 206571) {
+          printf("in %d out %d\n", in, out);
+          for (i = 0; i < CLP_CYCLE; i++)
+               printf("cy %d in %d out %d\n", i, in_[i], out_[i]);
+     }
+#endif
+     int matched = 0;
+     // first see if in matches any out
+     for (i = 1; i < CLP_CYCLE; i++) {
+          if (in == out_[i]) {
+               // even if flip then suspicious
+               matched = -1;
+               break;
+          }
+     }
+#if 0
+     if (!matched || in_[0] < 0) {
+          // can't be cycle
+          for (i = 0; i < CLP_CYCLE - 1; i++) {
+               //obj_[i]=obj_[i+1];
+               in_[i] = in_[i+1];
+               out_[i] = out_[i+1];
+               way_[i] = way_[i+1];
+          }
+     } else {
+          // possible cycle
+          matched = 0;
+          for (i = 0; i < CLP_CYCLE - 1; i++) {
+               int k;
+               char wayThis = way_[i];
+               int inThis = in_[i];
+               int outThis = out_[i];
+               //double objThis = obj_[i];
+               for(k = i + 1; k < CLP_CYCLE; k++) {
+                    if (inThis == in_[k] && outThis == out_[k] && wayThis == way_[k]) {
+                         int distance = k - i;
+                         if (k + distance < CLP_CYCLE) {
+                              // See if repeats
+                              int j = k + distance;
+                              if (inThis == in_[j] && outThis == out_[j] && wayThis == way_[j]) {
+                                   matched = distance;
+                                   break;
+                              }
+                         } else {
+                              matched = distance;
+                              break;
+                         }
+                    }
+               }
+               //obj_[i]=obj_[i+1];
+               in_[i] = in_[i+1];
+               out_[i] = out_[i+1];
+               way_[i] = way_[i+1];
+          }
+     }
+#else
+     if (matched && in_[0] >= 0) {
+          // possible cycle - only check [0] against all
+          matched = 0;
+          int nMatched = 0;
+          char way0 = way_[0];
+          int in0 = in_[0];
+          int out0 = out_[0];
+          //double obj0 = obj_[i];
+          for(int k = 1; k < CLP_CYCLE - 4; k++) {
+               if (in0 == in_[k] && out0 == out_[k] && way0 == way_[k]) {
+                    nMatched++;
+                    // See if repeats
+                    int end = CLP_CYCLE - k;
+                    int j;
+                    for ( j = 1; j < end; j++) {
+                         if (in_[j+k] != in_[j] || out_[j+k] != out_[j] || way_[j+k] != way_[j])
+                              break;
+                    }
+                    if (j == end) {
+                         matched = k;
+                         break;
+                    }
+               }
+          }
+          // If three times then that is too much even if not regular
+          if (matched <= 0 && nMatched > 1)
+               matched = 100;
+     }
+     for (i = 0; i < CLP_CYCLE - 1; i++) {
+          //obj_[i]=obj_[i+1];
+          in_[i] = in_[i+1];
+          out_[i] = out_[i+1];
+          way_[i] = way_[i+1];
+     }
+#endif
+     int way = 1 - wayIn + 4 * (1 - wayOut);
+     //obj_[i]=model_->objectiveValue();
+     in_[CLP_CYCLE-1] = in;
+     out_[CLP_CYCLE-1] = out;
+     way_[CLP_CYCLE-1] = static_cast<char>(way);
+     return matched;
+}
+#include "CoinStructuredModel.hpp"
+// Solve using structure of model and maybe in parallel
+int
+ClpSimplex::solve(CoinStructuredModel * model)
+{
+     // analyze structure
+     int numberRowBlocks = model->numberRowBlocks();
+     int numberColumnBlocks = model->numberColumnBlocks();
+     int numberElementBlocks = model->numberElementBlocks();
+     if (numberElementBlocks == 1) {
+          loadProblem(*model, false);
+          return dual();
+     }
+     // For now just get top level structure
+     CoinModelBlockInfo * blockInfo = new CoinModelBlockInfo [numberElementBlocks];
+     for (int i = 0; i < numberElementBlocks; i++) {
+          CoinStructuredModel * subModel =
+               dynamic_cast<CoinStructuredModel *>(model->block(i));
+          CoinModel * thisBlock;
+          if (subModel) {
+               thisBlock = subModel->coinModelBlock(blockInfo[i]);
+               model->setCoinModel(thisBlock, i);
+          } else {
+               thisBlock = dynamic_cast<CoinModel *>(model->block(i));
+               assert (thisBlock);
+               // just fill in info
+               CoinModelBlockInfo info = CoinModelBlockInfo();
+               int whatsSet = thisBlock->whatIsSet();
+               info.matrix = static_cast<char>(((whatsSet & 1) != 0) ? 1 : 0);
+               info.rhs = static_cast<char>(((whatsSet & 2) != 0) ? 1 : 0);
+               info.rowName = static_cast<char>(((whatsSet & 4) != 0) ? 1 : 0);
+               info.integer = static_cast<char>(((whatsSet & 32) != 0) ? 1 : 0);
+               info.bounds = static_cast<char>(((whatsSet & 8) != 0) ? 1 : 0);
+               info.columnName = static_cast<char>(((whatsSet & 16) != 0) ? 1 : 0);
+               // Which block
+               int iRowBlock = model->rowBlock(thisBlock->getRowBlock());
+               info.rowBlock = iRowBlock;
+               int iColumnBlock = model->columnBlock(thisBlock->getColumnBlock());
+               info.columnBlock = iColumnBlock;
+               blockInfo[i] = info;
+          }
+     }
+     int * rowCounts = new int [numberRowBlocks];
+     CoinZeroN(rowCounts, numberRowBlocks);
+     int * columnCounts = new int [numberColumnBlocks+1];
+     CoinZeroN(columnCounts, numberColumnBlocks);
+     int decomposeType = 0;
+     for (int i = 0; i < numberElementBlocks; i++) {
+          int iRowBlock = blockInfo[i].rowBlock;
+          int iColumnBlock = blockInfo[i].columnBlock;
+          rowCounts[iRowBlock]++;
+          columnCounts[iColumnBlock]++;
+     }
+     if (numberRowBlocks == numberColumnBlocks ||
+               numberRowBlocks == numberColumnBlocks + 1) {
+          // could be Dantzig-Wolfe
+          int numberG1 = 0;
+          for (int i = 0; i < numberRowBlocks; i++) {
+               if (rowCounts[i] > 1)
+                    numberG1++;
+          }
+          bool masterColumns = (numberColumnBlocks == numberRowBlocks);
+          if ((masterColumns && numberElementBlocks == 2 * numberRowBlocks - 1)
+                    || (!masterColumns && numberElementBlocks == 2 * numberRowBlocks)) {
+               if (numberG1 < 2)
+                    decomposeType = 1;
+          }
+     }
+     if (!decomposeType && (numberRowBlocks == numberColumnBlocks ||
+                            numberRowBlocks == numberColumnBlocks - 1)) {
+          // could be Benders
+          int numberG1 = 0;
+          for (int i = 0; i < numberColumnBlocks; i++) {
+               if (columnCounts[i] > 1)
+                    numberG1++;
+          }
+          bool masterRows = (numberColumnBlocks == numberRowBlocks);
+          if ((masterRows && numberElementBlocks == 2 * numberColumnBlocks - 1)
+                    || (!masterRows && numberElementBlocks == 2 * numberColumnBlocks)) {
+               if (numberG1 < 2)
+                    decomposeType = 2;
+          }
+     }
+     delete [] rowCounts;
+     delete [] columnCounts;
+     delete [] blockInfo;
+     // decide what to do
+     switch (decomposeType) {
+          // No good
+     case 0:
+          loadProblem(*model, false);
+          return dual();
+          // DW
+     case 1:
+          return solveDW(model);
+          // Benders
+     case 2:
+          return solveBenders(model);
+     }
+     return 0; // to stop compiler warning
+}
+/* This loads a model from a CoinStructuredModel object - returns number of errors.
+   If originalOrder then keep to order stored in blocks,
+   otherwise first column/rows correspond to first block - etc.
+   If keepSolution true and size is same as current then
+   keeps current status and solution
+*/
+int
+ClpSimplex::loadProblem (  CoinStructuredModel & coinModel,
+                           bool originalOrder,
+                           bool keepSolution)
+{
+     unsigned char * status = NULL;
+     double * psol = NULL;
+     double * dsol = NULL;
+     int numberRows = coinModel.numberRows();
+     int numberColumns = coinModel.numberColumns();
+     int numberRowBlocks = coinModel.numberRowBlocks();
+     int numberColumnBlocks = coinModel.numberColumnBlocks();
+     int numberElementBlocks = coinModel.numberElementBlocks();
+     if (status_ && numberRows_ && numberRows_ == numberRows &&
+               numberColumns_ == numberColumns && keepSolution) {
+          status = new unsigned char [numberRows_+numberColumns_];
+          CoinMemcpyN(status_, numberRows_ + numberColumns_, status);
+          psol = new double [numberRows_+numberColumns_];
+          CoinMemcpyN(columnActivity_, numberColumns_, psol);
+          CoinMemcpyN(rowActivity_, numberRows_, psol + numberColumns_);
+          dsol = new double [numberRows_+numberColumns_];
+          CoinMemcpyN(reducedCost_, numberColumns_, dsol);
+          CoinMemcpyN(dual_, numberRows_, dsol + numberColumns_);
+     }
+     int returnCode = 0;
+     double * rowLower = new double [numberRows];
+     double * rowUpper = new double [numberRows];
+     double * columnLower = new double [numberColumns];
+     double * columnUpper = new double [numberColumns];
+     double * objective = new double [numberColumns];
+     int * integerType = new int [numberColumns];
+     CoinBigIndex numberElements = 0;
+     // Bases for blocks
+     int * rowBase = new int[numberRowBlocks];
+     CoinFillN(rowBase, numberRowBlocks, -1);
+     // And row to put it
+     int * whichRow = new int [numberRows];
+     int * columnBase = new int[numberColumnBlocks];
+     CoinFillN(columnBase, numberColumnBlocks, -1);
+     // And column to put it
+     int * whichColumn = new int [numberColumns];
+     for (int iBlock = 0; iBlock < numberElementBlocks; iBlock++) {
+          CoinModel * block = coinModel.coinBlock(iBlock);
+          numberElements += block->numberElements();
+          //and set up elements etc
+          double * associated = block->associatedArray();
+          // If strings then do copies
+          if (block->stringsExist())
+               returnCode += block->createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                                 objective, integerType, associated);
+          const CoinModelBlockInfo & info = coinModel.blockType(iBlock);
+          int iRowBlock = info.rowBlock;
+          int iColumnBlock = info.columnBlock;
+          if (rowBase[iRowBlock] < 0) {
+               rowBase[iRowBlock] = block->numberRows();
+               // Save block number
+               whichRow[numberRows-numberRowBlocks+iRowBlock] = iBlock;
+          } else {
+               assert(rowBase[iRowBlock] == block->numberRows());
+          }
+          if (columnBase[iColumnBlock] < 0) {
+               columnBase[iColumnBlock] = block->numberColumns();
+               // Save block number
+               whichColumn[numberColumns-numberColumnBlocks+iColumnBlock] = iBlock;
+          } else {
+               assert(columnBase[iColumnBlock] == block->numberColumns());
+          }
+     }
+     // Fill arrays with defaults
+     CoinFillN(rowLower, numberRows, -COIN_DBL_MAX);
+     CoinFillN(rowUpper, numberRows, COIN_DBL_MAX);
+     CoinFillN(columnLower, numberColumns, 0.0);
+     CoinFillN(columnUpper, numberColumns, COIN_DBL_MAX);
+     CoinFillN(objective, numberColumns, 0.0);
+     CoinFillN(integerType, numberColumns, 0);
+     int n = 0;
+     for (int iBlock = 0; iBlock < numberRowBlocks; iBlock++) {
+          int k = rowBase[iBlock];
+          rowBase[iBlock] = n;
+          assert (k >= 0);
+          // block number
+          int jBlock = whichRow[numberRows-numberRowBlocks+iBlock];
+          if (originalOrder) {
+               memcpy(whichRow + n, coinModel.coinBlock(jBlock)->originalRows(), k * sizeof(int));
+          } else {
+               CoinIotaN(whichRow + n, k, n);
+          }
+          n += k;
+     }
+     assert (n == numberRows);
+     n = 0;
+     for (int iBlock = 0; iBlock < numberColumnBlocks; iBlock++) {
+          int k = columnBase[iBlock];
+          columnBase[iBlock] = n;
+          assert (k >= 0);
+          if (k) {
+               // block number
+               int jBlock = whichColumn[numberColumns-numberColumnBlocks+iBlock];
+               if (originalOrder) {
+                    memcpy(whichColumn + n, coinModel.coinBlock(jBlock)->originalColumns(),
+                           k * sizeof(int));
+               } else {
+                    CoinIotaN(whichColumn + n, k, n);
+               }
+               n += k;
+          }
+     }
+     assert (n == numberColumns);
+     bool gotIntegers = false;
+     for (int iBlock = 0; iBlock < numberElementBlocks; iBlock++) {
+          CoinModel * block = coinModel.coinBlock(iBlock);
+          const CoinModelBlockInfo & info = coinModel.blockType(iBlock);
+          int iRowBlock = info.rowBlock;
+          int iRowBase = rowBase[iRowBlock];
+          int iColumnBlock = info.columnBlock;
+          int iColumnBase = columnBase[iColumnBlock];
+          if (info.rhs) {
+               int nRows = block->numberRows();
+               const double * lower = block->rowLowerArray();
+               const double * upper = block->rowUpperArray();
+               for (int i = 0; i < nRows; i++) {
+                    int put = whichRow[i+iRowBase];
+                    rowLower[put] = lower[i];
+                    rowUpper[put] = upper[i];
+               }
+          }
+          if (info.bounds) {
+               int nColumns = block->numberColumns();
+               const double * lower = block->columnLowerArray();
+               const double * upper = block->columnUpperArray();
+               const double * obj = block->objectiveArray();
+               for (int i = 0; i < nColumns; i++) {
+                    int put = whichColumn[i+iColumnBase];
+                    columnLower[put] = lower[i];
+                    columnUpper[put] = upper[i];
+                    objective[put] = obj[i];
+               }
+          }
+          if (info.integer) {
+               gotIntegers = true;
+               int nColumns = block->numberColumns();
+               const int * type = block->integerTypeArray();
+               for (int i = 0; i < nColumns; i++) {
+                    int put = whichColumn[i+iColumnBase];
+                    integerType[put] = type[i];
+               }
+          }
+     }
+     gutsOfLoadModel(numberRows, numberColumns,
+                     columnLower, columnUpper, objective, rowLower, rowUpper, NULL);
+     delete [] rowLower;
+     delete [] rowUpper;
+     delete [] columnLower;
+     delete [] columnUpper;
+     delete [] objective;
+     // Do integers if wanted
+     if (gotIntegers) {
+          for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+               if (integerType[iColumn])
+                    setInteger(iColumn);
+          }
+     }
+     delete [] integerType;
+     setObjectiveOffset(coinModel.objectiveOffset());
+     // Space for elements
+     int * row = new int[numberElements];
+     int * column = new int[numberElements];
+     double * element = new double[numberElements];
+     numberElements = 0;
+     for (int iBlock = 0; iBlock < numberElementBlocks; iBlock++) {
+          CoinModel * block = coinModel.coinBlock(iBlock);
+          const CoinModelBlockInfo & info = coinModel.blockType(iBlock);
+          int iRowBlock = info.rowBlock;
+          int iRowBase = rowBase[iRowBlock];
+          int iColumnBlock = info.columnBlock;
+          int iColumnBase = columnBase[iColumnBlock];
+          if (info.rowName) {
+               int numberItems = block->rowNames()->numberItems();
+               assert( block->numberRows() >= numberItems);
+               if (numberItems) {
+                    const char *const * rowNames = block->rowNames()->names();
+                    for (int i = 0; i < numberItems; i++) {
+                         int put = whichRow[i+iRowBase];
+                         std::string name = rowNames[i];
+                         setRowName(put, name);
+                    }
+               }
+          }
+          if (info.columnName) {
+               int numberItems = block->columnNames()->numberItems();
+               assert( block->numberColumns() >= numberItems);
+               if (numberItems) {
+                    const char *const * columnNames = block->columnNames()->names();
+                    for (int i = 0; i < numberItems; i++) {
+                         int put = whichColumn[i+iColumnBase];
+                         std::string name = columnNames[i];
+                         setColumnName(put, name);
+                    }
+               }
+          }
+          if (info.matrix) {
+               CoinPackedMatrix matrix2;
+               const CoinPackedMatrix * matrix = block->packedMatrix();
+               if (!matrix) {
+                    double * associated = block->associatedArray();
+                    block->createPackedMatrix(matrix2, associated);
+                    matrix = &matrix2;
+               }
+               // get matrix data pointers
+               const int * row2 = matrix->getIndices();
+               const CoinBigIndex * columnStart = matrix->getVectorStarts();
+               const double * elementByColumn = matrix->getElements();
+               const int * columnLength = matrix->getVectorLengths();
+               int n = matrix->getNumCols();
+               assert (matrix->isColOrdered());
+               for (int iColumn = 0; iColumn < n; iColumn++) {
+                    CoinBigIndex j;
+                    int jColumn = whichColumn[iColumn+iColumnBase];
+                    for (j = columnStart[iColumn];
+                              j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+                         row[numberElements] = whichRow[row2[j] + iRowBase];
+                         column[numberElements] = jColumn;
+                         element[numberElements++] = elementByColumn[j];
+                    }
+               }
+          }
+     }
+     delete [] whichRow;
+     delete [] whichColumn;
+     delete [] rowBase;
+     delete [] columnBase;
+     CoinPackedMatrix * matrix =
+          new CoinPackedMatrix (true, row, column, element, numberElements);
+     matrix_ = new ClpPackedMatrix(matrix);
+     matrix_->setDimensions(numberRows, numberColumns);
+     delete [] row;
+     delete [] column;
+     delete [] element;
+     createStatus();
+     if (status) {
+          // copy back
+          CoinMemcpyN(status, numberRows_ + numberColumns_, status_);
+          CoinMemcpyN(psol, numberColumns_, columnActivity_);
+          CoinMemcpyN(psol + numberColumns_, numberRows_, rowActivity_);
+          CoinMemcpyN(dsol, numberColumns_, reducedCost_);
+          CoinMemcpyN(dsol + numberColumns_, numberRows_, dual_);
+          delete [] status;
+          delete [] psol;
+          delete [] dsol;
+     }
+     optimizationDirection_ = coinModel.optimizationDirection();
+     return returnCode;
+}
+/*  If input negative scales objective so maximum <= -value
+    and returns scale factor used.  If positive unscales and also
+    redoes dual stuff
+*/
+double
+ClpSimplex::scaleObjective(double value)
+{
+     double * obj = objective();
+     double largest = 0.0;
+     if (value < 0.0) {
+          value = - value;
+          for (int i = 0; i < numberColumns_; i++) {
+               largest = CoinMax(largest, fabs(obj[i]));
+          }
+          if (largest > value) {
+               double scaleFactor = value / largest;
+               for (int i = 0; i < numberColumns_; i++) {
+                    obj[i] *= scaleFactor;
+                    reducedCost_[i] *= scaleFactor;
+               }
+               for (int i = 0; i < numberRows_; i++) {
+                    dual_[i] *= scaleFactor;
+               }
+               largest /= value;
+          } else {
+               // no need
+               largest = 1.0;
+          }
+     } else {
+          // at end
+          if (value != 1.0) {
+               for (int i = 0; i < numberColumns_; i++) {
+                    obj[i] *= value;
+                    reducedCost_[i] *= value;
+               }
+               for (int i = 0; i < numberRows_; i++) {
+                    dual_[i] *= value;
+               }
+               computeObjectiveValue();
+          }
+     }
+     return largest;
+}
+// Solve using Dantzig-Wolfe decomposition and maybe in parallel
+int
+ClpSimplex::solveDW(CoinStructuredModel * model)
+{
+     double time1 = CoinCpuTime();
+     int numberColumns = model->numberColumns();
+     int numberRowBlocks = model->numberRowBlocks();
+     int numberColumnBlocks = model->numberColumnBlocks();
+     int numberElementBlocks = model->numberElementBlocks();
+     // We already have top level structure
+     CoinModelBlockInfo * blockInfo = new CoinModelBlockInfo [numberElementBlocks];
+     for (int i = 0; i < numberElementBlocks; i++) {
+          CoinModel * thisBlock = model->coinBlock(i);
+          assert (thisBlock);
+          // just fill in info
+          CoinModelBlockInfo info = CoinModelBlockInfo();
+          int whatsSet = thisBlock->whatIsSet();
+          info.matrix = static_cast<char>(((whatsSet & 1) != 0) ? 1 : 0);
+          info.rhs = static_cast<char>(((whatsSet & 2) != 0) ? 1 : 0);
+          info.rowName = static_cast<char>(((whatsSet & 4) != 0) ? 1 : 0);
+          info.integer = static_cast<char>(((whatsSet & 32) != 0) ? 1 : 0);
+          info.bounds = static_cast<char>(((whatsSet & 8) != 0) ? 1 : 0);
+          info.columnName = static_cast<char>(((whatsSet & 16) != 0) ? 1 : 0);
+          // Which block
+          int iRowBlock = model->rowBlock(thisBlock->getRowBlock());
+          info.rowBlock = iRowBlock;
+          int iColumnBlock = model->columnBlock(thisBlock->getColumnBlock());
+          info.columnBlock = iColumnBlock;
+          blockInfo[i] = info;
+     }
+     // make up problems
+     int numberBlocks = numberRowBlocks - 1;
+     // Find master rows and columns
+     int * rowCounts = new int [numberRowBlocks];
+     CoinZeroN(rowCounts, numberRowBlocks);
+     int * columnCounts = new int [numberColumnBlocks+1];
+     CoinZeroN(columnCounts, numberColumnBlocks);
+     int iBlock;
+     for (iBlock = 0; iBlock < numberElementBlocks; iBlock++) {
+          int iRowBlock = blockInfo[iBlock].rowBlock;
+          rowCounts[iRowBlock]++;
+          int iColumnBlock = blockInfo[iBlock].columnBlock;
+          columnCounts[iColumnBlock]++;
+     }
+     int * whichBlock = new int [numberElementBlocks];
+     int masterRowBlock = -1;
+     for (iBlock = 0; iBlock < numberRowBlocks; iBlock++) {
+          if (rowCounts[iBlock] > 1) {
+               if (masterRowBlock == -1) {
+                    masterRowBlock = iBlock;
+               } else {
+                    // Can't decode
+                    masterRowBlock = -2;
+                    break;
+               }
+          }
+     }
+     int masterColumnBlock = -1;
+     int kBlock = 0;
+     for (iBlock = 0; iBlock < numberColumnBlocks; iBlock++) {
+          int count = columnCounts[iBlock];
+          columnCounts[iBlock] = kBlock;
+          kBlock += count;
+     }
+     for (iBlock = 0; iBlock < numberElementBlocks; iBlock++) {
+          int iColumnBlock = blockInfo[iBlock].columnBlock;
+          whichBlock[columnCounts[iColumnBlock]] = iBlock;
+          columnCounts[iColumnBlock]++;
+     }
+     for (iBlock = numberColumnBlocks - 1; iBlock >= 0; iBlock--)
+          columnCounts[iBlock+1] = columnCounts[iBlock];
+     columnCounts[0] = 0;
+     for (iBlock = 0; iBlock < numberColumnBlocks; iBlock++) {
+          int count = columnCounts[iBlock+1] - columnCounts[iBlock];
+          if (count == 1) {
+               int kBlock = whichBlock[columnCounts[iBlock]];
+               int iRowBlock = blockInfo[kBlock].rowBlock;
+               if (iRowBlock == masterRowBlock) {
+                    if (masterColumnBlock == -1) {
+                         masterColumnBlock = iBlock;
+                    } else {
+                         // Can't decode
+                         masterColumnBlock = -2;
+                         break;
+                    }
+               }
+          }
+     }
+     if (masterRowBlock < 0 || masterColumnBlock == -2) {
+          // What now
+          abort();
+     }
+     delete [] rowCounts;
+     // create all data
+     const CoinPackedMatrix ** top = new const CoinPackedMatrix * [numberColumnBlocks];
+     ClpSimplex * sub = new ClpSimplex [numberBlocks];
+     ClpSimplex master;
+     // Set offset
+     master.setObjectiveOffset(model->objectiveOffset());
+     kBlock = 0;
+     int masterBlock = -1;
+     for (iBlock = 0; iBlock < numberColumnBlocks; iBlock++) {
+          top[kBlock] = NULL;
+          int start = columnCounts[iBlock];
+          int end = columnCounts[iBlock+1];
+          assert (end - start <= 2);
+          for (int j = start; j < end; j++) {
+               int jBlock = whichBlock[j];
+               int iRowBlock = blockInfo[jBlock].rowBlock;
+               int iColumnBlock = blockInfo[jBlock].columnBlock;
+               assert (iColumnBlock == iBlock);
+               if (iColumnBlock != masterColumnBlock && iRowBlock == masterRowBlock) {
+                    // top matrix
+                    top[kBlock] = model->coinBlock(jBlock)->packedMatrix();
+               } else {
+                    const CoinPackedMatrix * matrix
+                    = model->coinBlock(jBlock)->packedMatrix();
+                    // Get pointers to arrays
+                    const double * rowLower;
+                    const double * rowUpper;
+                    const double * columnLower;
+                    const double * columnUpper;
+                    const double * objective;
+                    model->block(iRowBlock, iColumnBlock, rowLower, rowUpper,
+                                 columnLower, columnUpper, objective);
+                    if (iColumnBlock != masterColumnBlock) {
+                         // diagonal block
+                         sub[kBlock].loadProblem(*matrix, columnLower, columnUpper,
+                                                 objective, rowLower, rowUpper);
+                         if (true) {
+                              double * lower = sub[kBlock].columnLower();
+                              double * upper = sub[kBlock].columnUpper();
+                              int n = sub[kBlock].numberColumns();
+                              for (int i = 0; i < n; i++) {
+                                   lower[i] = CoinMax(-1.0e8, lower[i]);
+                                   upper[i] = CoinMin(1.0e8, upper[i]);
+                              }
+                         }
+                         if (optimizationDirection_ < 0.0) {
+                              double * obj = sub[kBlock].objective();
+                              int n = sub[kBlock].numberColumns();
+                              for (int i = 0; i < n; i++)
+                                   obj[i] = - obj[i];
+                         }
+                         if (this->factorizationFrequency() == 200) {
+                              // User did not touch preset
+                              sub[kBlock].defaultFactorizationFrequency();
+                         } else {
+                              // make sure model has correct value
+                              sub[kBlock].setFactorizationFrequency(this->factorizationFrequency());
+                         }
+                         sub[kBlock].setPerturbation(50);
+                         // Set columnCounts to be diagonal block index for cleanup
+                         columnCounts[kBlock] = jBlock;
+                    } else {
+                         // master
+                         masterBlock = jBlock;
+                         master.loadProblem(*matrix, columnLower, columnUpper,
+                                            objective, rowLower, rowUpper);
+                         if (optimizationDirection_ < 0.0) {
+                              double * obj = master.objective();
+                              int n = master.numberColumns();
+                              for (int i = 0; i < n; i++)
+                                   obj[i] = - obj[i];
+                         }
+                    }
+               }
+          }
+          if (iBlock != masterColumnBlock)
+               kBlock++;
+     }
+     delete [] whichBlock;
+     delete [] blockInfo;
+     // For now master must have been defined (does not have to have columns)
+     assert (master.numberRows());
+     assert (masterBlock >= 0);
+     int numberMasterRows = master.numberRows();
+     // Overkill in terms of space
+     int spaceNeeded = CoinMax(numberBlocks * (numberMasterRows + 1),
+                               2 * numberMasterRows);
+     int * rowAdd = new int[spaceNeeded];
+     double * elementAdd = new double[spaceNeeded];
+     spaceNeeded = numberBlocks;
+     int * columnAdd = new int[spaceNeeded+1];
+     double * objective = new double[spaceNeeded];
+     // Add in costed slacks
+     int firstArtificial = master.numberColumns();
+     int lastArtificial = firstArtificial;
+     if (true) {
+          const double * lower = master.rowLower();
+          const double * upper = master.rowUpper();
+          int kCol = 0;
+          for (int iRow = 0; iRow < numberMasterRows; iRow++) {
+               if (lower[iRow] > -1.0e10) {
+                    rowAdd[kCol] = iRow;
+                    elementAdd[kCol++] = 1.0;
+               }
+               if (upper[iRow] < 1.0e10) {
+                    rowAdd[kCol] = iRow;
+                    elementAdd[kCol++] = -1.0;
+               }
+          }
+          if (kCol > spaceNeeded) {
+               spaceNeeded = kCol;
+               delete [] columnAdd;
+               delete [] objective;
+               columnAdd = new int[spaceNeeded+1];
+               objective = new double[spaceNeeded];
+          }
+          for (int i = 0; i < kCol; i++) {
+               columnAdd[i] = i;
+               objective[i] = 1.0e13;
+          }
+          columnAdd[kCol] = kCol;
+          master.addColumns(kCol, NULL, NULL, objective,
+                            columnAdd, rowAdd, elementAdd);
+          lastArtificial = master.numberColumns();
+     }
+     int maxPass = 500;
+     int iPass;
+     double lastObjective = 1.0e31;
+     // Create convexity rows for proposals
+     int numberMasterColumns = master.numberColumns();
+     master.resize(numberMasterRows + numberBlocks, numberMasterColumns);
+     if (this->factorizationFrequency() == 200) {
+          // User did not touch preset
+          master.defaultFactorizationFrequency();
+     } else {
+          // make sure model has correct value
+          master.setFactorizationFrequency(this->factorizationFrequency());
+     }
+     master.setPerturbation(50);
+     // Arrays to say which block and when created
+     int maximumColumns = 2 * numberMasterRows + 10 * numberBlocks;
+     whichBlock = new int[maximumColumns];
+     int * when = new int[maximumColumns];
+     int numberColumnsGenerated = numberBlocks;
+     // fill in rhs and add in artificials
+     {
+          double * rowLower = master.rowLower();
+          double * rowUpper = master.rowUpper();
+          int iBlock;
+          columnAdd[0] = 0;
+          for (iBlock = 0; iBlock < numberBlocks; iBlock++) {
+               int iRow = iBlock + numberMasterRows;;
+               rowLower[iRow] = 1.0;
+               rowUpper[iRow] = 1.0;
+               rowAdd[iBlock] = iRow;
+               elementAdd[iBlock] = 1.0;
+               objective[iBlock] = 1.0e13;
+               columnAdd[iBlock+1] = iBlock + 1;
+               when[iBlock] = -1;
+               whichBlock[iBlock] = iBlock;
+          }
+          master.addColumns(numberBlocks, NULL, NULL, objective,
+                            columnAdd, rowAdd, elementAdd);
+     }
+     // and resize matrix to double check clp will be happy
+     //master.matrix()->setDimensions(numberMasterRows+numberBlocks,
+     //			 numberMasterColumns+numberBlocks);
+     std::cout << "Time to decompose " << CoinCpuTime() - time1 << " seconds" << std::endl;
+     for (iPass = 0; iPass < maxPass; iPass++) {
+          printf("Start of pass %d\n", iPass);
+          // Solve master - may be infeasible
+          //master.scaling(0);
+          if (0) {
+               master.writeMps("yy.mps");
+          }
+          // Correct artificials
+          double sumArtificials = 0.0;
+          if (iPass) {
+               double * upper = master.columnUpper();
+               double * solution = master.primalColumnSolution();
+               double * obj = master.objective();
+               sumArtificials = 0.0;
+               for (int i = firstArtificial; i < lastArtificial; i++) {
+                    sumArtificials += solution[i];
+                    //assert (solution[i]>-1.0e-2);
+                    if (solution[i] < 1.0e-6) {
+#if 0
+                         // Could take out
+                         obj[i] = 0.0;
+                         upper[i] = 0.0;
+#else
+                         obj[i] = 1.0e7;
+                         upper[i] = 1.0e-1;
+#endif
+                         solution[i] = 0.0;
+                         master.setColumnStatus(i, isFixed);
+                    } else {
+                         upper[i] = solution[i] + 1.0e-5 * (1.0 + solution[i]);
+                    }
+               }
+               printf("Sum of artificials before solve is %g\n", sumArtificials);
+          }
+          // scale objective to be reasonable
+          double scaleFactor = master.scaleObjective(-1.0e9);
+          {
+               double * dual = master.dualRowSolution();
+               int n = master.numberRows();
+               memset(dual, 0, n * sizeof(double));
+               double * solution = master.primalColumnSolution();
+               master.clpMatrix()->times(1.0, solution, dual);
+               double sum = 0.0;
+               double * lower = master.rowLower();
+               double * upper = master.rowUpper();
+               for (int iRow = 0; iRow < n; iRow++) {
+                    double value = dual[iRow];
+                    if (value > upper[iRow])
+                         sum += value - upper[iRow];
+                    else if (value < lower[iRow])
+                         sum -= value - lower[iRow];
+               }
+               printf("suminf %g\n", sum);
+               lower = master.columnLower();
+               upper = master.columnUpper();
+               n = master.numberColumns();
+               for (int iColumn = 0; iColumn < n; iColumn++) {
+                    double value = solution[iColumn];
+                    if (value > upper[iColumn] + 1.0e-5)
+                         sum += value - upper[iColumn];
+                    else if (value < lower[iColumn] - 1.0e-5)
+                         sum -= value - lower[iColumn];
+               }
+               printf("suminf %g\n", sum);
+          }
+          master.primal(1);
+          // Correct artificials
+          sumArtificials = 0.0;
+          {
+               double * solution = master.primalColumnSolution();
+               for (int i = firstArtificial; i < lastArtificial; i++) {
+                    sumArtificials += solution[i];
+               }
+               printf("Sum of artificials after solve is %g\n", sumArtificials);
+          }
+          master.scaleObjective(scaleFactor);
+          int problemStatus = master.status(); // do here as can change (delcols)
+          if (master.numberIterations() == 0 && iPass)
+               break; // finished
+          if (master.objectiveValue() > lastObjective - 1.0e-7 && iPass > 555)
+               break; // finished
+          lastObjective = master.objectiveValue();
+          // mark basic ones and delete if necessary
+          int iColumn;
+          numberColumnsGenerated = master.numberColumns() - numberMasterColumns;
+          for (iColumn = 0; iColumn < numberColumnsGenerated; iColumn++) {
+               if (master.getStatus(iColumn + numberMasterColumns) == ClpSimplex::basic)
+                    when[iColumn] = iPass;
+          }
+          if (numberColumnsGenerated + numberBlocks > maximumColumns) {
+               // delete
+               int numberKeep = 0;
+               int numberDelete = 0;
+               int * whichDelete = new int[numberColumnsGenerated];
+               for (iColumn = 0; iColumn < numberColumnsGenerated; iColumn++) {
+                    if (when[iColumn] > iPass - 7) {
+                         // keep
+                         when[numberKeep] = when[iColumn];
+                         whichBlock[numberKeep++] = whichBlock[iColumn];
+                    } else {
+                         // delete
+                         whichDelete[numberDelete++] = iColumn + numberMasterColumns;
+                    }
+               }
+               numberColumnsGenerated -= numberDelete;
+               master.deleteColumns(numberDelete, whichDelete);
+               delete [] whichDelete;
+          }
+          const double * dual = NULL;
+          bool deleteDual = false;
+          if (problemStatus == 0) {
+               dual = master.dualRowSolution();
+          } else if (problemStatus == 1) {
+               // could do composite objective
+               dual = master.infeasibilityRay();
+               deleteDual = true;
+               printf("The sum of infeasibilities is %g\n",
+                      master.sumPrimalInfeasibilities());
+          } else if (!master.numberColumns()) {
+               assert(!iPass);
+               dual = master.dualRowSolution();
+               memset(master.dualRowSolution(),
+                      0, (numberMasterRows + numberBlocks)*sizeof(double));
+          } else {
+               abort();
+          }
+          // Scale back on first time
+          if (!iPass) {
+               double * dual2 = master.dualRowSolution();
+               for (int i = 0; i < numberMasterRows + numberBlocks; i++) {
+                    dual2[i] *= 1.0e-7;
+               }
+               dual = master.dualRowSolution();
+          }
+          // Create objective for sub problems and solve
+          columnAdd[0] = 0;
+          int numberProposals = 0;
+          for (iBlock = 0; iBlock < numberBlocks; iBlock++) {
+               int numberColumns2 = sub[iBlock].numberColumns();
+               double * saveObj = new double [numberColumns2];
+               double * objective2 = sub[iBlock].objective();
+               memcpy(saveObj, objective2, numberColumns2 * sizeof(double));
+               // new objective
+               top[iBlock]->transposeTimes(dual, objective2);
+               int i;
+               if (problemStatus == 0) {
+                    for (i = 0; i < numberColumns2; i++)
+                         objective2[i] = saveObj[i] - objective2[i];
+               } else {
+                    for (i = 0; i < numberColumns2; i++)
+                         objective2[i] = -objective2[i];
+               }
+               // scale objective to be reasonable
+               double scaleFactor =
+                    sub[iBlock].scaleObjective((sumArtificials > 1.0e-5) ? -1.0e-4 : -1.0e9);
+               if (iPass) {
+                    sub[iBlock].primal();
+               } else {
+                    sub[iBlock].dual();
+               }
+               sub[iBlock].scaleObjective(scaleFactor);
+               if (!sub[iBlock].isProvenOptimal() &&
+                         !sub[iBlock].isProvenDualInfeasible()) {
+                    memset(objective2, 0, numberColumns2 * sizeof(double));
+                    sub[iBlock].primal();
+                    if (problemStatus == 0) {
+                         for (i = 0; i < numberColumns2; i++)
+                              objective2[i] = saveObj[i] - objective2[i];
+                    } else {
+                         for (i = 0; i < numberColumns2; i++)
+                              objective2[i] = -objective2[i];
+                    }
+                    double scaleFactor = sub[iBlock].scaleObjective(-1.0e9);
+                    sub[iBlock].primal(1);
+                    sub[iBlock].scaleObjective(scaleFactor);
+               }
+               memcpy(objective2, saveObj, numberColumns2 * sizeof(double));
+               // get proposal
+               if (sub[iBlock].numberIterations() || !iPass) {
+                    double objValue = 0.0;
+                    int start = columnAdd[numberProposals];
+                    // proposal
+                    if (sub[iBlock].isProvenOptimal()) {
+                         const double * solution = sub[iBlock].primalColumnSolution();
+                         top[iBlock]->times(solution, elementAdd + start);
+                         for (i = 0; i < numberColumns2; i++)
+                              objValue += solution[i] * saveObj[i];
+                         // See if good dj and pack down
+                         int number = start;
+                         double dj = objValue;
+                         if (problemStatus)
+                              dj = 0.0;
+                         double smallest = 1.0e100;
+                         double largest = 0.0;
+                         for (i = 0; i < numberMasterRows; i++) {
+                              double value = elementAdd[start+i];
+                              if (fabs(value) > 1.0e-15) {
+                                   dj -= dual[i] * value;
+                                   smallest = CoinMin(smallest, fabs(value));
+                                   largest = CoinMax(largest, fabs(value));
+                                   rowAdd[number] = i;
+                                   elementAdd[number++] = value;
+                              }
+                         }
+                         // and convexity
+                         dj -= dual[numberMasterRows+iBlock];
+                         rowAdd[number] = numberMasterRows + iBlock;
+                         elementAdd[number++] = 1.0;
+                         // if elements large then scale?
+                         //if (largest>1.0e8||smallest<1.0e-8)
+                         printf("For subproblem %d smallest - %g, largest %g - dj %g\n",
+                                iBlock, smallest, largest, dj);
+                         if (dj < -1.0e-6 || !iPass) {
+                              // take
+                              objective[numberProposals] = objValue;
+                              columnAdd[++numberProposals] = number;
+                              when[numberColumnsGenerated] = iPass;
+                              whichBlock[numberColumnsGenerated++] = iBlock;
+                         }
+                    } else if (sub[iBlock].isProvenDualInfeasible()) {
+                         // use ray
+                         const double * solution = sub[iBlock].unboundedRay();
+                         top[iBlock]->times(solution, elementAdd + start);
+                         for (i = 0; i < numberColumns2; i++)
+                              objValue += solution[i] * saveObj[i];
+                         // See if good dj and pack down
+                         int number = start;
+                         double dj = objValue;
+                         double smallest = 1.0e100;
+                         double largest = 0.0;
+                         for (i = 0; i < numberMasterRows; i++) {
+                              double value = elementAdd[start+i];
+                              if (fabs(value) > 1.0e-15) {
+                                   dj -= dual[i] * value;
+                                   smallest = CoinMin(smallest, fabs(value));
+                                   largest = CoinMax(largest, fabs(value));
+                                   rowAdd[number] = i;
+                                   elementAdd[number++] = value;
+                              }
+                         }
+                         // if elements large or small then scale?
+                         //if (largest>1.0e8||smallest<1.0e-8)
+                         printf("For subproblem ray %d smallest - %g, largest %g - dj %g\n",
+                                iBlock, smallest, largest, dj);
+                         if (dj < -1.0e-6) {
+                              // take
+                              objective[numberProposals] = objValue;
+                              columnAdd[++numberProposals] = number;
+                              when[numberColumnsGenerated] = iPass;
+                              whichBlock[numberColumnsGenerated++] = iBlock;
+                         }
+                    } else {
+                         abort();
+                    }
+               }
+               delete [] saveObj;
+          }
+          if (deleteDual)
+               delete [] dual;
+          if (numberProposals)
+               master.addColumns(numberProposals, NULL, NULL, objective,
+                                 columnAdd, rowAdd, elementAdd);
+     }
+     std::cout << "Time at end of D-W " << CoinCpuTime() - time1 << " seconds" << std::endl;
+     //master.scaling(0);
+     //master.primal(1);
+     loadProblem(*model);
+     // now put back a good solution
+     double * lower = new double[numberMasterRows+numberBlocks];
+     double * upper = new double[numberMasterRows+numberBlocks];
+     numberColumnsGenerated  += numberMasterColumns;
+     double * sol = new double[numberColumnsGenerated];
+     const double * solution = master.primalColumnSolution();
+     const double * masterLower = master.rowLower();
+     const double * masterUpper = master.rowUpper();
+     double * fullSolution = primalColumnSolution();
+     const double * fullLower = columnLower();
+     const double * fullUpper = columnUpper();
+     const double * rowSolution = master.primalRowSolution();
+     double * fullRowSolution = primalRowSolution();
+     const int * rowBack = model->coinBlock(masterBlock)->originalRows();
+     int numberRows2 = model->coinBlock(masterBlock)->numberRows();
+     const int * columnBack = model->coinBlock(masterBlock)->originalColumns();
+     int numberColumns2 = model->coinBlock(masterBlock)->numberColumns();
+     for (int iRow = 0; iRow < numberRows2; iRow++) {
+          int kRow = rowBack[iRow];
+          setRowStatus(kRow, master.getRowStatus(iRow));
+          fullRowSolution[kRow] = rowSolution[iRow];
+     }
+     for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
+          int kColumn = columnBack[iColumn];
+          setStatus(kColumn, master.getStatus(iColumn));
+          fullSolution[kColumn] = solution[iColumn];
+     }
+     for (iBlock = 0; iBlock < numberBlocks; iBlock++) {
+          // move basis
+          int kBlock = columnCounts[iBlock];
+          const int * rowBack = model->coinBlock(kBlock)->originalRows();
+          int numberRows2 = model->coinBlock(kBlock)->numberRows();
+          const int * columnBack = model->coinBlock(kBlock)->originalColumns();
+          int numberColumns2 = model->coinBlock(kBlock)->numberColumns();
+          for (int iRow = 0; iRow < numberRows2; iRow++) {
+               int kRow = rowBack[iRow];
+               setRowStatus(kRow, sub[iBlock].getRowStatus(iRow));
+          }
+          for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
+               int kColumn = columnBack[iColumn];
+               setStatus(kColumn, sub[iBlock].getStatus(iColumn));
+          }
+          // convert top bit to by rows
+          CoinPackedMatrix topMatrix = *top[iBlock];
+          topMatrix.reverseOrdering();
+          // zero solution
+          memset(sol, 0, numberColumnsGenerated * sizeof(double));
+
+          for (int i = numberMasterColumns; i < numberColumnsGenerated; i++) {
+               if (whichBlock[i-numberMasterColumns] == iBlock)
+                    sol[i] = solution[i];
+          }
+          memset(lower, 0, (numberMasterRows + numberBlocks)*sizeof(double));
+          master.clpMatrix()->times(1.0, sol, lower);
+          for (int iRow = 0; iRow < numberMasterRows; iRow++) {
+               double value = lower[iRow];
+               if (masterUpper[iRow] < 1.0e20)
+                    upper[iRow] = value;
+               else
+                    upper[iRow] = COIN_DBL_MAX;
+               if (masterLower[iRow] > -1.0e20)
+                    lower[iRow] = value;
+               else
+                    lower[iRow] = -COIN_DBL_MAX;
+          }
+          sub[iBlock].addRows(numberMasterRows, lower, upper,
+                              topMatrix.getVectorStarts(),
+                              topMatrix.getVectorLengths(),
+                              topMatrix.getIndices(),
+                              topMatrix.getElements());
+          sub[iBlock].primal(1);
+          const double * subSolution = sub[iBlock].primalColumnSolution();
+          const double * subRowSolution = sub[iBlock].primalRowSolution();
+          // move solution
+          for (int iRow = 0; iRow < numberRows2; iRow++) {
+               int kRow = rowBack[iRow];
+               fullRowSolution[kRow] = subRowSolution[iRow];
+          }
+          for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
+               int kColumn = columnBack[iColumn];
+               fullSolution[kColumn] = subSolution[iColumn];
+          }
+     }
+     for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
+          if (fullSolution[iColumn] < fullUpper[iColumn] - 1.0e-8 &&
+                    fullSolution[iColumn] > fullLower[iColumn] + 1.0e-8) {
+               if (getStatus(iColumn) != ClpSimplex::basic) {
+                    if (columnLower_[iColumn] > -1.0e30 ||
+                              columnUpper_[iColumn] < 1.0e30)
+                         setStatus(iColumn, ClpSimplex::superBasic);
+                    else
+                         setStatus(iColumn, ClpSimplex::isFree);
+               }
+          } else if (fullSolution[iColumn] >= fullUpper[iColumn] - 1.0e-8) {
+               // may help to make rest non basic
+               if (getStatus(iColumn) != ClpSimplex::basic)
+                    setStatus(iColumn, ClpSimplex::atUpperBound);
+          } else if (fullSolution[iColumn] <= fullLower[iColumn] + 1.0e-8) {
+               // may help to make rest non basic
+               if (getStatus(iColumn) != ClpSimplex::basic)
+                    setStatus(iColumn, ClpSimplex::atLowerBound);
+          }
+     }
+     //int numberRows=model->numberRows();
+     //for (int iRow=0;iRow<numberRows;iRow++)
+     //setRowStatus(iRow,ClpSimplex::superBasic);
+     std::cout << "Time before cleanup of full model " << CoinCpuTime() - time1 << " seconds" << std::endl;
+     primal(1);
+     std::cout << "Total time " << CoinCpuTime() - time1 << " seconds" << std::endl;
+     delete [] columnCounts;
+     delete [] sol;
+     delete [] lower;
+     delete [] upper;
+     delete [] whichBlock;
+     delete [] when;
+     delete [] columnAdd;
+     delete [] rowAdd;
+     delete [] elementAdd;
+     delete [] objective;
+     delete [] top;
+     delete [] sub;
+     return 0;
+}
+// Solve using Benders decomposition and maybe in parallel
+int
+ClpSimplex::solveBenders(CoinStructuredModel * model)
+{
+     double time1 = CoinCpuTime();
+     //int numberColumns = model->numberColumns();
+     int numberRowBlocks = model->numberRowBlocks();
+     int numberColumnBlocks = model->numberColumnBlocks();
+     int numberElementBlocks = model->numberElementBlocks();
+     // We already have top level structure
+     CoinModelBlockInfo * blockInfo = new CoinModelBlockInfo [numberElementBlocks];
+     for (int i = 0; i < numberElementBlocks; i++) {
+          CoinModel * thisBlock = model->coinBlock(i);
+          assert (thisBlock);
+          // just fill in info
+          CoinModelBlockInfo info = CoinModelBlockInfo();
+          int whatsSet = thisBlock->whatIsSet();
+          info.matrix = static_cast<char>(((whatsSet & 1) != 0) ? 1 : 0);
+          info.rhs = static_cast<char>(((whatsSet & 2) != 0) ? 1 : 0);
+          info.rowName = static_cast<char>(((whatsSet & 4) != 0) ? 1 : 0);
+          info.integer = static_cast<char>(((whatsSet & 32) != 0) ? 1 : 0);
+          info.bounds = static_cast<char>(((whatsSet & 8) != 0) ? 1 : 0);
+          info.columnName = static_cast<char>(((whatsSet & 16) != 0) ? 1 : 0);
+          // Which block
+          int iRowBlock = model->rowBlock(thisBlock->getRowBlock());
+          info.rowBlock = iRowBlock;
+          int iColumnBlock = model->columnBlock(thisBlock->getColumnBlock());
+          info.columnBlock = iColumnBlock;
+          blockInfo[i] = info;
+     }
+     // make up problems
+     int numberBlocks = numberColumnBlocks - 1;
+     // Find master columns and rows
+     int * columnCounts = new int [numberColumnBlocks];
+     CoinZeroN(columnCounts, numberColumnBlocks);
+     int * rowCounts = new int [numberRowBlocks+1];
+     CoinZeroN(rowCounts, numberRowBlocks);
+     int iBlock;
+     for (iBlock = 0; iBlock < numberElementBlocks; iBlock++) {
+          int iColumnBlock = blockInfo[iBlock].columnBlock;
+          columnCounts[iColumnBlock]++;
+          int iRowBlock = blockInfo[iBlock].rowBlock;
+          rowCounts[iRowBlock]++;
+     }
+     int * whichBlock = new int [numberElementBlocks];
+     int masterColumnBlock = -1;
+     for (iBlock = 0; iBlock < numberColumnBlocks; iBlock++) {
+          if (columnCounts[iBlock] > 1) {
+               if (masterColumnBlock == -1) {
+                    masterColumnBlock = iBlock;
+               } else {
+                    // Can't decode
+                    masterColumnBlock = -2;
+                    break;
+               }
+          }
+     }
+     int masterRowBlock = -1;
+     int kBlock = 0;
+     for (iBlock = 0; iBlock < numberRowBlocks; iBlock++) {
+          int count = rowCounts[iBlock];
+          rowCounts[iBlock] = kBlock;
+          kBlock += count;
+     }
+     for (iBlock = 0; iBlock < numberElementBlocks; iBlock++) {
+          int iRowBlock = blockInfo[iBlock].rowBlock;
+          whichBlock[rowCounts[iRowBlock]] = iBlock;
+          rowCounts[iRowBlock]++;
+     }
+     for (iBlock = numberRowBlocks - 1; iBlock >= 0; iBlock--)
+          rowCounts[iBlock+1] = rowCounts[iBlock];
+     rowCounts[0] = 0;
+     for (iBlock = 0; iBlock < numberRowBlocks; iBlock++) {
+          int count = rowCounts[iBlock+1] - rowCounts[iBlock];
+          if (count == 1) {
+               int kBlock = whichBlock[rowCounts[iBlock]];
+               int iColumnBlock = blockInfo[kBlock].columnBlock;
+               if (iColumnBlock == masterColumnBlock) {
+                    if (masterRowBlock == -1) {
+                         masterRowBlock = iBlock;
+                    } else {
+                         // Can't decode
+                         masterRowBlock = -2;
+                         break;
+                    }
+               }
+          }
+     }
+     if (masterColumnBlock < 0 || masterRowBlock == -2) {
+          // What now
+          abort();
+     }
+     delete [] columnCounts;
+     // create all data
+     const CoinPackedMatrix ** first = new const CoinPackedMatrix * [numberRowBlocks];
+     ClpSimplex * sub = new ClpSimplex [numberBlocks];
+     ClpSimplex master;
+     // Set offset
+     master.setObjectiveOffset(model->objectiveOffset());
+     kBlock = 0;
+     int masterBlock = -1;
+     for (iBlock = 0; iBlock < numberRowBlocks; iBlock++) {
+          first[kBlock] = NULL;
+          int start = rowCounts[iBlock];
+          int end = rowCounts[iBlock+1];
+          assert (end - start <= 2);
+          for (int j = start; j < end; j++) {
+               int jBlock = whichBlock[j];
+               int iColumnBlock = blockInfo[jBlock].columnBlock;
+               int iRowBlock = blockInfo[jBlock].rowBlock;
+               assert (iRowBlock == iBlock);
+               if (iRowBlock != masterRowBlock && iColumnBlock == masterColumnBlock) {
+                    // first matrix
+                    first[kBlock] = model->coinBlock(jBlock)->packedMatrix();
+               } else {
+                    const CoinPackedMatrix * matrix
+                    = model->coinBlock(jBlock)->packedMatrix();
+                    // Get pointers to arrays
+                    const double * columnLower;
+                    const double * columnUpper;
+                    const double * rowLower;
+                    const double * rowUpper;
+                    const double * objective;
+                    model->block(iRowBlock, iColumnBlock, rowLower, rowUpper,
+                                 columnLower, columnUpper, objective);
+                    if (iRowBlock != masterRowBlock) {
+                         // diagonal block
+                         sub[kBlock].loadProblem(*matrix, columnLower, columnUpper,
+                                                 objective, rowLower, rowUpper);
+                         if (optimizationDirection_ < 0.0) {
+                              double * obj = sub[kBlock].objective();
+                              int n = sub[kBlock].numberColumns();
+                              for (int i = 0; i < n; i++)
+                                   obj[i] = - obj[i];
+                         }
+                         if (this->factorizationFrequency() == 200) {
+                              // User did not touch preset
+                              sub[kBlock].defaultFactorizationFrequency();
+                         } else {
+                              // make sure model has correct value
+                              sub[kBlock].setFactorizationFrequency(this->factorizationFrequency());
+                         }
+                         sub[kBlock].setPerturbation(50);
+                         // Set rowCounts to be diagonal block index for cleanup
+                         rowCounts[kBlock] = jBlock;
+                    } else {
+                         // master
+                         masterBlock = jBlock;
+                         master.loadProblem(*matrix, columnLower, columnUpper,
+                                            objective, rowLower, rowUpper);
+                         if (optimizationDirection_ < 0.0) {
+                              double * obj = master.objective();
+                              int n = master.numberColumns();
+                              for (int i = 0; i < n; i++)
+                                   obj[i] = - obj[i];
+                         }
+                    }
+               }
+          }
+          if (iBlock != masterRowBlock)
+               kBlock++;
+     }
+     delete [] whichBlock;
+     delete [] blockInfo;
+     // For now master must have been defined (does not have to have rows)
+     assert (master.numberColumns());
+     assert (masterBlock >= 0);
+     int numberMasterColumns = master.numberColumns();
+     // Overkill in terms of space
+     int spaceNeeded = CoinMax(numberBlocks * (numberMasterColumns + 1),
+                               2 * numberMasterColumns);
+     int * columnAdd = new int[spaceNeeded];
+     double * elementAdd = new double[spaceNeeded];
+     spaceNeeded = numberBlocks;
+     int * rowAdd = new int[spaceNeeded+1];
+     double * objective = new double[spaceNeeded];
+     int maxPass = 500;
+     int iPass;
+     double lastObjective = -1.0e31;
+     // Create columns for proposals
+     int numberMasterRows = master.numberRows();
+     master.resize(numberMasterColumns + numberBlocks, numberMasterRows);
+     if (this->factorizationFrequency() == 200) {
+          // User did not touch preset
+          master.defaultFactorizationFrequency();
+     } else {
+          // make sure model has correct value
+          master.setFactorizationFrequency(this->factorizationFrequency());
+     }
+     master.setPerturbation(50);
+     // Arrays to say which block and when created
+     int maximumRows = 2 * numberMasterColumns + 10 * numberBlocks;
+     whichBlock = new int[maximumRows];
+     int * when = new int[maximumRows];
+     int numberRowsGenerated = numberBlocks;
+     // Add extra variables
+     {
+          int iBlock;
+          columnAdd[0] = 0;
+          for (iBlock = 0; iBlock < numberBlocks; iBlock++) {
+               objective[iBlock] = 1.0;
+               columnAdd[iBlock+1] = 0;
+               when[iBlock] = -1;
+               whichBlock[iBlock] = iBlock;
+          }
+          master.addColumns(numberBlocks, NULL, NULL, objective,
+                            columnAdd, rowAdd, elementAdd);
+     }
+     std::cout << "Time to decompose " << CoinCpuTime() - time1 << " seconds" << std::endl;
+     for (iPass = 0; iPass < maxPass; iPass++) {
+          printf("Start of pass %d\n", iPass);
+          // Solve master - may be unbounded
+          //master.scaling(0);
+          if (1) {
+               master.writeMps("yy.mps");
+          }
+          master.dual();
+          int problemStatus = master.status(); // do here as can change (delcols)
+          if (master.numberIterations() == 0 && iPass)
+               break; // finished
+          if (master.objectiveValue() < lastObjective + 1.0e-7 && iPass > 555)
+               break; // finished
+          lastObjective = master.objectiveValue();
+          // mark non-basic rows and delete if necessary
+          int iRow;
+          numberRowsGenerated = master.numberRows() - numberMasterRows;
+          for (iRow = 0; iRow < numberRowsGenerated; iRow++) {
+               if (master.getStatus(iRow + numberMasterRows) != ClpSimplex::basic)
+                    when[iRow] = iPass;
+          }
+          if (numberRowsGenerated > maximumRows) {
+               // delete
+               int numberKeep = 0;
+               int numberDelete = 0;
+               int * whichDelete = new int[numberRowsGenerated];
+               for (iRow = 0; iRow < numberRowsGenerated; iRow++) {
+                    if (when[iRow] > iPass - 7) {
+                         // keep
+                         when[numberKeep] = when[iRow];
+                         whichBlock[numberKeep++] = whichBlock[iRow];
+                    } else {
+                         // delete
+                         whichDelete[numberDelete++] = iRow + numberMasterRows;
+                    }
+               }
+               numberRowsGenerated -= numberDelete;
+               master.deleteRows(numberDelete, whichDelete);
+               delete [] whichDelete;
+          }
+          const double * primal = NULL;
+          bool deletePrimal = false;
+          if (problemStatus == 0) {
+               primal = master.primalColumnSolution();
+          } else if (problemStatus == 2) {
+               // could do composite objective
+               primal = master.unboundedRay();
+               deletePrimal = true;
+               printf("The sum of infeasibilities is %g\n",
+                      master.sumPrimalInfeasibilities());
+          } else if (!master.numberRows()) {
+               assert(!iPass);
+               primal = master.primalColumnSolution();
+               memset(master.primalColumnSolution(),
+                      0, numberMasterColumns * sizeof(double));
+          } else {
+               abort();
+          }
+          // Create rhs for sub problems and solve
+          rowAdd[0] = 0;
+          int numberProposals = 0;
+          for (iBlock = 0; iBlock < numberBlocks; iBlock++) {
+               int numberRows2 = sub[iBlock].numberRows();
+               double * saveLower = new double [numberRows2];
+               double * lower2 = sub[iBlock].rowLower();
+               double * saveUpper = new double [numberRows2];
+               double * upper2 = sub[iBlock].rowUpper();
+               // new rhs
+               CoinZeroN(saveUpper, numberRows2);
+               first[iBlock]->times(primal, saveUpper);
+               for (int i = 0; i < numberRows2; i++) {
+                    double value = saveUpper[i];
+                    saveLower[i] = lower2[i];
+                    saveUpper[i] = upper2[i];
+                    if (saveLower[i] > -1.0e30)
+                         lower2[i] -= value;
+                    if (saveUpper[i] < 1.0e30)
+                         upper2[i] -= value;
+               }
+               sub[iBlock].dual();
+               memcpy(lower2, saveLower, numberRows2 * sizeof(double));
+               memcpy(upper2, saveUpper, numberRows2 * sizeof(double));
+               // get proposal
+               if (sub[iBlock].numberIterations() || !iPass) {
+                    double objValue = 0.0;
+                    int start = rowAdd[numberProposals];
+                    // proposal
+                    if (sub[iBlock].isProvenOptimal()) {
+                         const double * solution = sub[iBlock].dualRowSolution();
+                         first[iBlock]->transposeTimes(solution, elementAdd + start);
+                         for (int i = 0; i < numberRows2; i++) {
+                              if (solution[i] < -dualTolerance_) {
+                                   // at upper
+                                   assert (saveUpper[i] < 1.0e30);
+                                   objValue += solution[i] * saveUpper[i];
+                              } else if (solution[i] > dualTolerance_) {
+                                   // at lower
+                                   assert (saveLower[i] > -1.0e30);
+                                   objValue += solution[i] * saveLower[i];
+                              }
+                         }
+
+                         // See if cuts off and pack down
+                         int number = start;
+                         double infeas = objValue;
+                         double smallest = 1.0e100;
+                         double largest = 0.0;
+                         for (int i = 0; i < numberMasterColumns; i++) {
+                              double value = elementAdd[start+i];
+                              if (fabs(value) > 1.0e-15) {
+                                   infeas -= primal[i] * value;
+                                   smallest = CoinMin(smallest, fabs(value));
+                                   largest = CoinMax(largest, fabs(value));
+                                   columnAdd[number] = i;
+                                   elementAdd[number++] = -value;
+                              }
+                         }
+                         columnAdd[number] = numberMasterColumns + iBlock;
+                         elementAdd[number++] = -1.0;
+                         // if elements large then scale?
+                         //if (largest>1.0e8||smallest<1.0e-8)
+                         printf("For subproblem %d smallest - %g, largest %g - infeas %g\n",
+                                iBlock, smallest, largest, infeas);
+                         if (infeas < -1.0e-6 || !iPass) {
+                              // take
+                              objective[numberProposals] = objValue;
+                              rowAdd[++numberProposals] = number;
+                              when[numberRowsGenerated] = iPass;
+                              whichBlock[numberRowsGenerated++] = iBlock;
+                         }
+                    } else if (sub[iBlock].isProvenPrimalInfeasible()) {
+                         // use ray
+                         const double * solution = sub[iBlock].infeasibilityRay();
+                         first[iBlock]->transposeTimes(solution, elementAdd + start);
+                         for (int i = 0; i < numberRows2; i++) {
+                              if (solution[i] < -dualTolerance_) {
+                                   // at upper
+                                   assert (saveUpper[i] < 1.0e30);
+                                   objValue += solution[i] * saveUpper[i];
+                              } else if (solution[i] > dualTolerance_) {
+                                   // at lower
+                                   assert (saveLower[i] > -1.0e30);
+                                   objValue += solution[i] * saveLower[i];
+                              }
+                         }
+                         // See if good infeas and pack down
+                         int number = start;
+                         double infeas = objValue;
+                         double smallest = 1.0e100;
+                         double largest = 0.0;
+                         for (int i = 0; i < numberMasterColumns; i++) {
+                              double value = elementAdd[start+i];
+                              if (fabs(value) > 1.0e-15) {
+                                   infeas -= primal[i] * value;
+                                   smallest = CoinMin(smallest, fabs(value));
+                                   largest = CoinMax(largest, fabs(value));
+                                   columnAdd[number] = i;
+                                   elementAdd[number++] = -value;
+                              }
+                         }
+                         // if elements large or small then scale?
+                         //if (largest>1.0e8||smallest<1.0e-8)
+                         printf("For subproblem ray %d smallest - %g, largest %g - infeas %g\n",
+                                iBlock, smallest, largest, infeas);
+                         if (infeas < -1.0e-6) {
+                              // take
+                              objective[numberProposals] = objValue;
+                              rowAdd[++numberProposals] = number;
+                              when[numberRowsGenerated] = iPass;
+                              whichBlock[numberRowsGenerated++] = iBlock;
+                         }
+                    } else {
+                         abort();
+                    }
+               }
+               delete [] saveLower;
+               delete [] saveUpper;
+          }
+          if (deletePrimal)
+               delete [] primal;
+          if (numberProposals) {
+               master.addRows(numberProposals, NULL, objective,
+                              rowAdd, columnAdd, elementAdd);
+          }
+     }
+     std::cout << "Time at end of Benders " << CoinCpuTime() - time1 << " seconds" << std::endl;
+     //master.scaling(0);
+     //master.primal(1);
+     loadProblem(*model);
+     // now put back a good solution
+     const double * columnSolution = master.primalColumnSolution();
+     double * fullColumnSolution = primalColumnSolution();
+     const int * columnBack = model->coinBlock(masterBlock)->originalColumns();
+     int numberColumns2 = model->coinBlock(masterBlock)->numberColumns();
+     const int * rowBack = model->coinBlock(masterBlock)->originalRows();
+     int numberRows2 = model->coinBlock(masterBlock)->numberRows();
+     for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
+          int kColumn = columnBack[iColumn];
+          setColumnStatus(kColumn, master.getColumnStatus(iColumn));
+          fullColumnSolution[kColumn] = columnSolution[iColumn];
+     }
+     for (int iRow = 0; iRow < numberRows2; iRow++) {
+          int kRow = rowBack[iRow];
+          setStatus(kRow, master.getStatus(iRow));
+          //fullSolution[kRow]=solution[iRow];
+     }
+     for (iBlock = 0; iBlock < numberBlocks; iBlock++) {
+          // move basis
+          int kBlock = rowCounts[iBlock];
+          const int * columnBack = model->coinBlock(kBlock)->originalColumns();
+          int numberColumns2 = model->coinBlock(kBlock)->numberColumns();
+          const int * rowBack = model->coinBlock(kBlock)->originalRows();
+          int numberRows2 = model->coinBlock(kBlock)->numberRows();
+          const double * subColumnSolution = sub[iBlock].primalColumnSolution();
+          for (int iColumn = 0; iColumn < numberColumns2; iColumn++) {
+               int kColumn = columnBack[iColumn];
+               setColumnStatus(kColumn, sub[iBlock].getColumnStatus(iColumn));
+               fullColumnSolution[kColumn] = subColumnSolution[iColumn];
+          }
+          for (int iRow = 0; iRow < numberRows2; iRow++) {
+               int kRow = rowBack[iRow];
+               setStatus(kRow, sub[iBlock].getStatus(iRow));
+               setStatus(kRow, atLowerBound);
+          }
+     }
+     double * fullSolution = primalRowSolution();
+     CoinZeroN(fullSolution, numberRows_);
+     times(1.0, fullColumnSolution, fullSolution);
+     //int numberColumns=model->numberColumns();
+     //for (int iColumn=0;iColumn<numberColumns;iColumn++)
+     //setColumnStatus(iColumn,ClpSimplex::superBasic);
+     std::cout << "Time before cleanup of full model " << CoinCpuTime() - time1 << " seconds" << std::endl;
+     this->primal(1);
+     std::cout << "Total time " << CoinCpuTime() - time1 << " seconds" << std::endl;
+     delete [] rowCounts;
+     //delete [] sol;
+     //delete [] lower;
+     //delete [] upper;
+     delete [] whichBlock;
+     delete [] when;
+     delete [] rowAdd;
+     delete [] columnAdd;
+     delete [] elementAdd;
+     delete [] objective;
+     delete [] first;
+     delete [] sub;
+     return 0;
+}
diff --git a/cbits/coin/ClpSolve.hpp b/cbits/coin/ClpSolve.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/ClpSolve.hpp
@@ -0,0 +1,435 @@
+/* $Id: ClpSolve.hpp 1928 2013-04-06 12:54:16Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+/*
+   Authors
+
+   John Forrest
+
+ */
+#ifndef ClpSolve_H
+#define ClpSolve_H
+
+/**
+    This is a very simple class to guide algorithms.  It is used to tidy up
+    passing parameters to initialSolve and maybe for output from that
+
+*/
+
+class ClpSolve  {
+
+public:
+
+     /** enums for solve function */
+     enum SolveType {
+          useDual = 0,
+          usePrimal,
+          usePrimalorSprint,
+          useBarrier,
+          useBarrierNoCross,
+          automatic,
+          notImplemented
+     };
+     enum PresolveType {
+          presolveOn = 0,
+          presolveOff,
+          presolveNumber,
+          presolveNumberCost
+     };
+
+     /**@name Constructors and destructor and copy */
+     //@{
+     /// Default constructor
+     ClpSolve (  );
+     /// Constructor when you really know what you are doing
+     ClpSolve ( SolveType method, PresolveType presolveType,
+                int numberPasses, int options[6],
+                int extraInfo[6], int independentOptions[3]);
+     /// Generates code for above constructor
+     void generateCpp(FILE * fp);
+     /// Copy constructor.
+     ClpSolve(const ClpSolve &);
+     /// Assignment operator. This copies the data
+     ClpSolve & operator=(const ClpSolve & rhs);
+     /// Destructor
+     ~ClpSolve (  );
+     //@}
+
+     /**@name Functions most useful to user */
+     //@{
+     /** Special options - bits
+     0      4 - use crash (default allslack in dual, idiot in primal)
+         8 - all slack basis in primal
+     2      16 - switch off interrupt handling
+     3      32 - do not try and make plus minus one matrix
+         64 - do not use sprint even if problem looks good
+      */
+     /** which translation is:
+         which:
+         0 - startup in Dual  (nothing if basis exists).:
+                      0 - no basis
+       	   1 - crash
+       	   2 - use initiative about idiot! but no crash
+         1 - startup in Primal (nothing if basis exists):
+                      0 - use initiative
+       	   1 - use crash
+       	   2 - use idiot and look at further info
+       	   3 - use sprint and look at further info
+       	   4 - use all slack
+       	   5 - use initiative but no idiot
+       	   6 - use initiative but no sprint
+       	   7 - use initiative but no crash
+                      8 - do allslack or idiot
+                      9 - do allslack or sprint
+       	   10 - slp before
+       	   11 - no nothing and primal(0)
+         2 - interrupt handling - 0 yes, 1 no (for threadsafe)
+         3 - whether to make +- 1matrix - 0 yes, 1 no
+         4 - for barrier
+                      0 - dense cholesky
+       	   1 - Wssmp allowing some long columns
+       	   2 - Wssmp not allowing long columns
+       	   3 - Wssmp using KKT
+                      4 - Using Florida ordering
+       	   8 - bit set to do scaling
+       	   16 - set to be aggressive with gamma/delta?
+                      32 - Use KKT
+         5 - for presolve
+                      1 - switch off dual stuff
+         6 - for detailed printout (initially just presolve)
+                      1 - presolve statistics
+     */
+     void setSpecialOption(int which, int value, int extraInfo = -1);
+     int getSpecialOption(int which) const;
+
+     /// Solve types
+     void setSolveType(SolveType method, int extraInfo = -1);
+     SolveType getSolveType();
+
+     // Presolve types
+     void setPresolveType(PresolveType amount, int extraInfo = -1);
+     PresolveType getPresolveType();
+     int getPresolvePasses() const;
+     /// Extra info for idiot (or sprint)
+     int getExtraInfo(int which) const;
+     /** Say to return at once if infeasible,
+         default is to solve */
+     void setInfeasibleReturn(bool trueFalse);
+     inline bool infeasibleReturn() const {
+          return independentOptions_[0] != 0;
+     }
+     /// Whether we want to do dual part of presolve
+     inline bool doDual() const {
+          return (independentOptions_[1] & 1) == 0;
+     }
+     inline void setDoDual(bool doDual_) {
+          if (doDual_) independentOptions_[1]  &= ~1;
+          else independentOptions_[1] |= 1;
+     }
+     /// Whether we want to do singleton part of presolve
+     inline bool doSingleton() const {
+          return (independentOptions_[1] & 2) == 0;
+     }
+     inline void setDoSingleton(bool doSingleton_) {
+          if (doSingleton_) independentOptions_[1]  &= ~2;
+          else independentOptions_[1] |= 2;
+     }
+     /// Whether we want to do doubleton part of presolve
+     inline bool doDoubleton() const {
+          return (independentOptions_[1] & 4) == 0;
+     }
+     inline void setDoDoubleton(bool doDoubleton_) {
+          if (doDoubleton_) independentOptions_[1]  &= ~4;
+          else independentOptions_[1] |= 4;
+     }
+     /// Whether we want to do tripleton part of presolve
+     inline bool doTripleton() const {
+          return (independentOptions_[1] & 8) == 0;
+     }
+     inline void setDoTripleton(bool doTripleton_) {
+          if (doTripleton_) independentOptions_[1]  &= ~8;
+          else independentOptions_[1] |= 8;
+     }
+     /// Whether we want to do tighten part of presolve
+     inline bool doTighten() const {
+          return (independentOptions_[1] & 16) == 0;
+     }
+     inline void setDoTighten(bool doTighten_) {
+          if (doTighten_) independentOptions_[1]  &= ~16;
+          else independentOptions_[1] |= 16;
+     }
+     /// Whether we want to do forcing part of presolve
+     inline bool doForcing() const {
+          return (independentOptions_[1] & 32) == 0;
+     }
+     inline void setDoForcing(bool doForcing_) {
+          if (doForcing_) independentOptions_[1]  &= ~32;
+          else independentOptions_[1] |= 32;
+     }
+     /// Whether we want to do impliedfree part of presolve
+     inline bool doImpliedFree() const {
+          return (independentOptions_[1] & 64) == 0;
+     }
+     inline void setDoImpliedFree(bool doImpliedfree) {
+          if (doImpliedfree) independentOptions_[1]  &= ~64;
+          else independentOptions_[1] |= 64;
+     }
+     /// Whether we want to do dupcol part of presolve
+     inline bool doDupcol() const {
+          return (independentOptions_[1] & 128) == 0;
+     }
+     inline void setDoDupcol(bool doDupcol_) {
+          if (doDupcol_) independentOptions_[1]  &= ~128;
+          else independentOptions_[1] |= 128;
+     }
+     /// Whether we want to do duprow part of presolve
+     inline bool doDuprow() const {
+          return (independentOptions_[1] & 256) == 0;
+     }
+     inline void setDoDuprow(bool doDuprow_) {
+          if (doDuprow_) independentOptions_[1]  &= ~256;
+          else independentOptions_[1] |= 256;
+     }
+     /// Whether we want to do singleton column part of presolve
+     inline bool doSingletonColumn() const {
+          return (independentOptions_[1] & 512) == 0;
+     }
+     inline void setDoSingletonColumn(bool doSingleton_) {
+          if (doSingleton_) independentOptions_[1]  &= ~512;
+          else independentOptions_[1] |= 512;
+     }
+     /// Whether we want to kill small substitutions
+     inline bool doKillSmall() const {
+          return (independentOptions_[1] & 1024) == 0;
+     }
+     inline void setDoKillSmall(bool doKill) {
+          if (doKill) independentOptions_[1]  &= ~1024;
+          else independentOptions_[1] |= 1024;
+     }
+     /// Set whole group
+     inline int presolveActions() const {
+          return independentOptions_[1] & 0xffff;
+     }
+     inline void setPresolveActions(int action) {
+          independentOptions_[1]  = (independentOptions_[1] & 0xffff0000) | (action & 0xffff);
+     }
+     /// Largest column for substitution (normally 3)
+     inline int substitution() const {
+          return independentOptions_[2];
+     }
+     inline void setSubstitution(int value) {
+          independentOptions_[2] = value;
+     }
+     //@}
+
+////////////////// data //////////////////
+private:
+
+     /**@name data.
+     */
+     //@{
+     /// Solve type
+     SolveType method_;
+     /// Presolve type
+     PresolveType presolveType_;
+     /// Amount of presolve
+     int numberPasses_;
+     /// Options - last is switch for OsiClp
+     int options_[7];
+     /// Extra information
+     int extraInfo_[7];
+     /** Extra algorithm dependent options
+         0 - if set return from clpsolve if infeasible
+         1 - To be copied over to presolve options
+         2 - max substitution level
+     */
+     int independentOptions_[3];
+     //@}
+};
+
+/// For saving extra information to see if looping.
+class ClpSimplexProgress {
+
+public:
+
+
+     /**@name Constructors and destructor and copy */
+     //@{
+     /// Default constructor
+     ClpSimplexProgress (  );
+
+     /// Constructor from model
+     ClpSimplexProgress ( ClpSimplex * model );
+
+     /// Copy constructor.
+     ClpSimplexProgress(const ClpSimplexProgress &);
+
+     /// Assignment operator. This copies the data
+     ClpSimplexProgress & operator=(const ClpSimplexProgress & rhs);
+     /// Destructor
+     ~ClpSimplexProgress (  );
+     /// Resets as much as possible
+     void reset();
+     /// Fill from model
+     void fillFromModel ( ClpSimplex * model );
+
+     //@}
+
+     /**@name Check progress */
+     //@{
+     /** Returns -1 if okay, -n+1 (n number of times bad) if bad but action taken,
+         >=0 if give up and use as problem status
+     */
+     int looping (  );
+     /// Start check at beginning of whileIterating
+     void startCheck();
+     /// Returns cycle length in whileIterating
+     int cycle(int in, int out, int wayIn, int wayOut);
+
+     /// Returns previous objective (if -1) - current if (0)
+     double lastObjective(int back = 1) const;
+     /// Set real primal infeasibility and move back
+     void setInfeasibility(double value);
+     /// Returns real primal infeasibility (if -1) - current if (0)
+     double lastInfeasibility(int back = 1) const;
+     /// Modify objective e.g. if dual infeasible in dual
+     void modifyObjective(double value);
+     /// Returns previous iteration number (if -1) - current if (0)
+     int lastIterationNumber(int back = 1) const;
+     /// clears all iteration numbers (to switch off panic)
+     void clearIterationNumbers();
+     /// Odd state
+     inline void newOddState() {
+          oddState_ = - oddState_ - 1;
+     }
+     inline void endOddState() {
+          oddState_ = abs(oddState_);
+     }
+     inline void clearOddState() {
+          oddState_ = 0;
+     }
+     inline int oddState() const {
+          return oddState_;
+     }
+     /// number of bad times
+     inline int badTimes() const {
+          return numberBadTimes_;
+     }
+     inline void clearBadTimes() {
+          numberBadTimes_ = 0;
+     }
+     /// number of really bad times
+     inline int reallyBadTimes() const {
+          return numberReallyBadTimes_;
+     }
+     inline void incrementReallyBadTimes() {
+          numberReallyBadTimes_++;
+     }
+     /// number of times flagged
+     inline int timesFlagged() const {
+          return numberTimesFlagged_;
+     }
+     inline void clearTimesFlagged() {
+          numberTimesFlagged_ = 0;
+     }
+     inline void incrementTimesFlagged() {
+          numberTimesFlagged_++;
+     }
+
+     //@}
+     /**@name Data  */
+#define CLP_PROGRESS 5
+     //#define CLP_PROGRESS_WEIGHT 10
+     //@{
+     /// Objective values
+     double objective_[CLP_PROGRESS];
+     /// Sum of infeasibilities for algorithm
+     double infeasibility_[CLP_PROGRESS];
+     /// Sum of real primal infeasibilities for primal
+     double realInfeasibility_[CLP_PROGRESS];
+#ifdef CLP_PROGRESS_WEIGHT
+     /// Objective values for weights
+     double objectiveWeight_[CLP_PROGRESS_WEIGHT];
+     /// Sum of infeasibilities for algorithm for weights
+     double infeasibilityWeight_[CLP_PROGRESS_WEIGHT];
+     /// Sum of real primal infeasibilities for primal for weights
+     double realInfeasibilityWeight_[CLP_PROGRESS_WEIGHT];
+     /// Drop  for weights
+     double drop_;
+     /// Best? for weights
+     double best_;
+#endif
+     /// Initial weight for weights
+     double initialWeight_;
+#define CLP_CYCLE 12
+     /// For cycle checking
+     //double obj_[CLP_CYCLE];
+     int in_[CLP_CYCLE];
+     int out_[CLP_CYCLE];
+     char way_[CLP_CYCLE];
+     /// Pointer back to model so we can get information
+     ClpSimplex * model_;
+     /// Number of infeasibilities
+     int numberInfeasibilities_[CLP_PROGRESS];
+     /// Iteration number at which occurred
+     int iterationNumber_[CLP_PROGRESS];
+#ifdef CLP_PROGRESS_WEIGHT
+     /// Number of infeasibilities for weights
+     int numberInfeasibilitiesWeight_[CLP_PROGRESS_WEIGHT];
+     /// Iteration number at which occurred for weights
+     int iterationNumberWeight_[CLP_PROGRESS_WEIGHT];
+#endif
+     /// Number of times checked (so won't stop too early)
+     int numberTimes_;
+     /// Number of times it looked like loop
+     int numberBadTimes_;
+     /// Number really bad times
+     int numberReallyBadTimes_;
+     /// Number of times no iterations as flagged
+     int numberTimesFlagged_;
+     /// If things are in an odd state
+     int oddState_;
+     //@}
+};
+
+#include "ClpConfig.h"
+#if CLP_HAS_ABC
+#include "AbcCommon.hpp"
+/// For saving extra information to see if looping.
+class AbcSimplexProgress : public ClpSimplexProgress {
+
+public:
+
+
+     /**@name Constructors and destructor and copy */
+     //@{
+     /// Default constructor
+     AbcSimplexProgress (  );
+
+     /// Constructor from model
+     AbcSimplexProgress ( ClpSimplex * model );
+
+     /// Copy constructor.
+     AbcSimplexProgress(const AbcSimplexProgress &);
+
+     /// Assignment operator. This copies the data
+     AbcSimplexProgress & operator=(const AbcSimplexProgress & rhs);
+     /// Destructor
+     ~AbcSimplexProgress (  );
+
+     //@}
+
+     /**@name Check progress */
+     //@{
+     /** Returns -1 if okay, -n+1 (n number of times bad) if bad but action taken,
+         >=0 if give up and use as problem status
+     */
+     int looping (  );
+
+     //@}
+     /**@name Data  */
+     //@}
+};
+#endif
+#endif
diff --git a/cbits/coin/Clp_C_Interface.cpp b/cbits/coin/Clp_C_Interface.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Clp_C_Interface.cpp
@@ -0,0 +1,1323 @@
+// $Id: Clp_C_Interface.cpp 1928 2013-04-06 12:54:16Z stefan $
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include "CoinPragma.hpp"
+
+#include <cmath>
+#include <cstring>
+
+#include "CoinHelperFunctions.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpInterior.hpp"
+#ifndef SLIM_CLP
+#include "Idiot.hpp"
+#endif
+#include <cfloat>
+// Get C stuff but with extern C
+#define CLP_EXTERN_C
+#include "Coin_C_defines.h"
+
+/// To allow call backs
+class CMessageHandler : public CoinMessageHandler {
+
+public:
+     /**@name Overrides */
+     //@{
+     virtual int print();
+     //@}
+     /**@name set and get */
+     //@{
+     /// Model
+     const Clp_Simplex * model() const;
+     void setModel(Clp_Simplex * model);
+     /// Call back
+     void setCallBack(clp_callback callback);
+     //@}
+
+     /**@name Constructors, destructor */
+     //@{
+     /** Default constructor. */
+     CMessageHandler();
+     /// Constructor with pointer to model
+     CMessageHandler(Clp_Simplex * model,
+                     FILE * userPointer = NULL);
+     /** Destructor */
+     virtual ~CMessageHandler();
+     //@}
+
+     /**@name Copy method */
+     //@{
+     /** The copy constructor. */
+     CMessageHandler(const CMessageHandler&);
+     /** The copy constructor from an CoinSimplexMessageHandler. */
+     CMessageHandler(const CoinMessageHandler&);
+
+     CMessageHandler& operator=(const CMessageHandler&);
+     /// Clone
+     virtual CoinMessageHandler * clone() const ;
+     //@}
+
+
+protected:
+     /**@name Data members
+        The data members are protected to allow access for derived classes. */
+     //@{
+     /// Pointer back to model
+     Clp_Simplex * model_;
+     /// call back
+     clp_callback callback_;
+     //@}
+};
+
+
+//-------------------------------------------------------------------
+// Default Constructor
+//-------------------------------------------------------------------
+CMessageHandler::CMessageHandler ()
+     : CoinMessageHandler(),
+       model_(NULL),
+       callback_(NULL)
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+CMessageHandler::CMessageHandler (const CMessageHandler & rhs)
+     : CoinMessageHandler(rhs),
+       model_(rhs.model_),
+       callback_(rhs.callback_)
+{
+}
+
+CMessageHandler::CMessageHandler (const CoinMessageHandler & rhs)
+     : CoinMessageHandler(rhs),
+       model_(NULL),
+       callback_(NULL)
+{
+}
+
+// Constructor with pointer to model
+CMessageHandler::CMessageHandler(Clp_Simplex * model,
+                                 FILE * )
+     : CoinMessageHandler(),
+       model_(model),
+       callback_(NULL)
+{
+}
+
+//-------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------
+CMessageHandler::~CMessageHandler ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator
+//-------------------------------------------------------------------
+CMessageHandler &
+CMessageHandler::operator=(const CMessageHandler& rhs)
+{
+     if (this != &rhs) {
+          CoinMessageHandler::operator=(rhs);
+          model_ = rhs.model_;
+          callback_ = rhs.callback_;
+     }
+     return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+CoinMessageHandler * CMessageHandler::clone() const
+{
+     return new CMessageHandler(*this);
+}
+
+int
+CMessageHandler::print()
+{
+     if (callback_) {
+          int messageNumber = currentMessage().externalNumber();
+          if (currentSource() != "Clp")
+               messageNumber += 1000000;
+          int i;
+          int nDouble = numberDoubleFields();
+          assert (nDouble <= 10);
+          double vDouble[10];
+          for (i = 0; i < nDouble; i++)
+               vDouble[i] = doubleValue(i);
+          int nInt = numberIntFields();
+          assert (nInt <= 10);
+          int vInt[10];
+          for (i = 0; i < nInt; i++)
+               vInt[i] = intValue(i);
+          int nString = numberStringFields();
+          assert (nString <= 10);
+          char * vString[10];
+          for (i = 0; i < nString; i++) {
+               std::string value = stringValue(i);
+               vString[i] = CoinStrdup(value.c_str());
+          }
+          callback_(model_, messageNumber,
+                    nDouble, vDouble,
+                    nInt, vInt,
+                    nString, vString);
+          for (i = 0; i < nString; i++)
+               free(vString[i]);
+
+     }
+     return CoinMessageHandler::print();
+}
+const Clp_Simplex *
+CMessageHandler::model() const
+{
+     return model_;
+}
+void
+CMessageHandler::setModel(Clp_Simplex * model)
+{
+     model_ = model;
+}
+// Call back
+void
+CMessageHandler::setCallBack(clp_callback callback)
+{
+     callback_ = callback;
+}
+
+#include "Clp_C_Interface.h"
+#include <string>
+#include <stdio.h>
+#include <iostream>
+
+#if defined(__MWERKS__)
+#pragma export on
+#endif
+/* Default constructor */
+COINLIBAPI Clp_Simplex *  COINLINKAGE
+Clp_newModel()
+{
+     Clp_Simplex * model = new Clp_Simplex;
+     model->model_ = new ClpSimplex();
+     model->handler_ = NULL;
+     return model;
+}
+/* Destructor */
+COINLIBAPI void COINLINKAGE
+Clp_deleteModel(Clp_Simplex * model)
+{
+     delete model->model_;
+     delete model->handler_;
+     delete model;
+}
+
+/* Loads a problem (the constraints on the
+    rows are given by lower and upper bounds). If a pointer is NULL then the
+    following values are the default:
+    <ul>
+    <li> <code>colub</code>: all columns have upper bound infinity
+    <li> <code>collb</code>: all columns have lower bound 0
+    <li> <code>rowub</code>: all rows have upper bound infinity
+    <li> <code>rowlb</code>: all rows have lower bound -infinity
+    <li> <code>obj</code>: all variables have 0 objective coefficient
+    </ul>
+*/
+/* Just like the other loadProblem() method except that the matrix is
+   given in a standard column major ordered format (without gaps). */
+COINLIBAPI void COINLINKAGE
+Clp_loadProblem (Clp_Simplex * model,  const int numcols, const int numrows,
+                 const CoinBigIndex * start, const int* index,
+                 const double* value,
+                 const double* collb, const double* colub,
+                 const double* obj,
+                 const double* rowlb, const double* rowub)
+{
+     const char prefix[] = "Clp_c_Interface::Clp_loadProblem(): ";
+     const int  verbose = 0;
+     if (verbose > 1) {
+          printf("%s numcols = %i, numrows = %i\n",
+                 prefix, numcols, numrows);
+          printf("%s model = %p, start = %p, index = %p, value = %p\n",
+                 prefix, reinterpret_cast<const void *>(model), reinterpret_cast<const void *>(start), reinterpret_cast<const void *>(index), reinterpret_cast<const void *>(value));
+          printf("%s collb = %p, colub = %p, obj = %p, rowlb = %p, rowub = %p\n",
+                 prefix, reinterpret_cast<const void *>(collb), reinterpret_cast<const void *>(colub), reinterpret_cast<const void *>(obj), reinterpret_cast<const void *>(rowlb), reinterpret_cast<const void *>(rowub));
+     }
+     model->model_->loadProblem(numcols, numrows, start, index, value,
+                                collb, colub, obj, rowlb, rowub);
+}
+/* read quadratic part of the objective (the matrix part) */
+COINLIBAPI void COINLINKAGE
+Clp_loadQuadraticObjective(Clp_Simplex * model,
+                           const int numberColumns,
+                           const CoinBigIndex * start,
+                           const int * column,
+                           const double * element)
+{
+
+     model->model_->loadQuadraticObjective(numberColumns,
+                                           start, column, element);
+
+}
+/* Read an mps file from the given filename */
+COINLIBAPI int COINLINKAGE
+Clp_readMps(Clp_Simplex * model, const char *filename,
+            int keepNames,
+            int ignoreErrors)
+{
+     return model->model_->readMps(filename, keepNames != 0, ignoreErrors != 0);
+}
+/* Copy in integer informations */
+COINLIBAPI void COINLINKAGE
+Clp_copyInIntegerInformation(Clp_Simplex * model, const char * information)
+{
+     model->model_->copyInIntegerInformation(information);
+}
+/* Drop integer informations */
+COINLIBAPI void COINLINKAGE
+Clp_deleteIntegerInformation(Clp_Simplex * model)
+{
+     model->model_->deleteIntegerInformation();
+}
+/* Resizes rim part of model  */
+COINLIBAPI void COINLINKAGE
+Clp_resize (Clp_Simplex * model, int newNumberRows, int newNumberColumns)
+{
+     model->model_->resize(newNumberRows, newNumberColumns);
+}
+/* Deletes rows */
+COINLIBAPI void COINLINKAGE
+Clp_deleteRows(Clp_Simplex * model, int number, const int * which)
+{
+     model->model_->deleteRows(number, which);
+}
+/* Add rows */
+COINLIBAPI void COINLINKAGE
+Clp_addRows(Clp_Simplex * model, int number, const double * rowLower,
+            const double * rowUpper,
+            const int * rowStarts, const int * columns,
+            const double * elements)
+{
+     model->model_->addRows(number, rowLower, rowUpper, rowStarts, columns, elements);
+}
+
+/* Deletes columns */
+COINLIBAPI void COINLINKAGE
+Clp_deleteColumns(Clp_Simplex * model, int number, const int * which)
+{
+     model->model_->deleteColumns(number, which);
+}
+/* Add columns */
+COINLIBAPI void COINLINKAGE
+Clp_addColumns(Clp_Simplex * model, int number, const double * columnLower,
+               const double * columnUpper,
+               const double * objective,
+               const int * columnStarts, const int * rows,
+               const double * elements)
+{
+     model->model_->addColumns(number, columnLower, columnUpper, objective,
+                               columnStarts, rows, elements);
+}
+/* Change row lower bounds */
+COINLIBAPI void COINLINKAGE
+Clp_chgRowLower(Clp_Simplex * model, const double * rowLower)
+{
+     model->model_->chgRowLower(rowLower);
+}
+/* Change row upper bounds */
+COINLIBAPI void COINLINKAGE
+Clp_chgRowUpper(Clp_Simplex * model, const double * rowUpper)
+{
+     model->model_->chgRowUpper(rowUpper);
+}
+/* Change column lower bounds */
+COINLIBAPI void COINLINKAGE
+Clp_chgColumnLower(Clp_Simplex * model, const double * columnLower)
+{
+     model->model_->chgColumnLower(columnLower);
+}
+/* Change column upper bounds */
+COINLIBAPI void COINLINKAGE
+Clp_chgColumnUpper(Clp_Simplex * model, const double * columnUpper)
+{
+     model->model_->chgColumnUpper(columnUpper);
+}
+/* Change objective coefficients */
+COINLIBAPI void COINLINKAGE
+Clp_chgObjCoefficients(Clp_Simplex * model, const double * objIn)
+{
+     model->model_->chgObjCoefficients(objIn);
+}
+/* Drops names - makes lengthnames 0 and names empty */
+COINLIBAPI void COINLINKAGE
+Clp_dropNames(Clp_Simplex * model)
+{
+     model->model_->dropNames();
+}
+/* Copies in names */
+COINLIBAPI void COINLINKAGE
+Clp_copyNames(Clp_Simplex * model, const char * const * rowNamesIn,
+              const char * const * columnNamesIn)
+{
+     int iRow;
+     std::vector<std::string> rowNames;
+     int numberRows = model->model_->numberRows();
+     rowNames.reserve(numberRows);
+     for (iRow = 0; iRow < numberRows; iRow++) {
+          rowNames.push_back(rowNamesIn[iRow]);
+     }
+
+     int iColumn;
+     std::vector<std::string> columnNames;
+     int numberColumns = model->model_->numberColumns();
+     columnNames.reserve(numberColumns);
+     for (iColumn = 0; iColumn < numberColumns; iColumn++) {
+          columnNames.push_back(columnNamesIn[iColumn]);
+     }
+     model->model_->copyNames(rowNames, columnNames);
+}
+
+/* Number of rows */
+COINLIBAPI int COINLINKAGE
+Clp_numberRows(Clp_Simplex * model)
+{
+     return model->model_->numberRows();
+}
+/* Number of columns */
+COINLIBAPI int COINLINKAGE
+Clp_numberColumns(Clp_Simplex * model)
+{
+     return model->model_->numberColumns();
+}
+/* Primal tolerance to use */
+COINLIBAPI double COINLINKAGE
+Clp_primalTolerance(Clp_Simplex * model)
+{
+     return model->model_->primalTolerance();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setPrimalTolerance(Clp_Simplex * model,  double value)
+{
+     model->model_->setPrimalTolerance(value);
+}
+/* Dual tolerance to use */
+COINLIBAPI double COINLINKAGE
+Clp_dualTolerance(Clp_Simplex * model)
+{
+     return model->model_->dualTolerance();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setDualTolerance(Clp_Simplex * model,  double value)
+{
+     model->model_->setDualTolerance(value);
+}
+/* Dual objective limit */
+COINLIBAPI double COINLINKAGE
+Clp_dualObjectiveLimit(Clp_Simplex * model)
+{
+     return model->model_->dualObjectiveLimit();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setDualObjectiveLimit(Clp_Simplex * model, double value)
+{
+     model->model_->setDualObjectiveLimit(value);
+}
+/* Objective offset */
+COINLIBAPI double COINLINKAGE
+Clp_objectiveOffset(Clp_Simplex * model)
+{
+     return model->model_->objectiveOffset();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setObjectiveOffset(Clp_Simplex * model, double value)
+{
+     model->model_->setObjectiveOffset(value);
+}
+/* Fills in array with problem name  */
+COINLIBAPI void COINLINKAGE
+Clp_problemName(Clp_Simplex * model, int maxNumberCharacters, char * array)
+{
+     std::string name = model->model_->problemName();
+     maxNumberCharacters = CoinMin(maxNumberCharacters,
+     				   ((int) strlen(name.c_str()))+1) ;
+     strncpy(array, name.c_str(), maxNumberCharacters - 1);
+     array[maxNumberCharacters-1] = '\0';
+}
+/* Sets problem name.  Must have \0 at end.  */
+COINLIBAPI int COINLINKAGE
+Clp_setProblemName(Clp_Simplex * model, int /*maxNumberCharacters*/, char * array)
+{
+     return model->model_->setStrParam(ClpProbName, array);
+}
+/* Number of iterations */
+COINLIBAPI int COINLINKAGE
+Clp_numberIterations(Clp_Simplex * model)
+{
+     return model->model_->numberIterations();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setNumberIterations(Clp_Simplex * model, int numberIterations)
+{
+     model->model_->setNumberIterations(numberIterations);
+}
+/* Maximum number of iterations */
+COINLIBAPI int maximumIterations(Clp_Simplex * model)
+{
+     return model->model_->maximumIterations();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setMaximumIterations(Clp_Simplex * model, int value)
+{
+     model->model_->setMaximumIterations(value);
+}
+/* Maximum time in seconds (from when set called) */
+COINLIBAPI double COINLINKAGE
+Clp_maximumSeconds(Clp_Simplex * model)
+{
+     return model->model_->maximumSeconds();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setMaximumSeconds(Clp_Simplex * model, double value)
+{
+     model->model_->setMaximumSeconds(value);
+}
+/* Returns true if hit maximum iteratio`ns (or time) */
+COINLIBAPI int COINLINKAGE
+Clp_hitMaximumIterations(Clp_Simplex * model)
+{
+     return model->model_->hitMaximumIterations() ? 1 : 0;
+}
+/* Status of problem:
+   0 - optimal
+   1 - primal infeasible
+   2 - dual infeasible
+   3 - stopped on iterations etc
+   4 - stopped due to errors
+*/
+COINLIBAPI int COINLINKAGE
+Clp_status(Clp_Simplex * model)
+{
+     return model->model_->status();
+}
+/* Set problem status */
+COINLIBAPI void COINLINKAGE
+Clp_setProblemStatus(Clp_Simplex * model, int problemStatus)
+{
+     model->model_->setProblemStatus(problemStatus);
+}
+/* Secondary status of problem - may get extended
+   0 - none
+   1 - primal infeasible because dual limit reached
+   2 - scaled problem optimal - unscaled has primal infeasibilities
+   3 - scaled problem optimal - unscaled has dual infeasibilities
+   4 - scaled problem optimal - unscaled has both dual and primal infeasibilities
+*/
+COINLIBAPI int COINLINKAGE
+Clp_secondaryStatus(Clp_Simplex * model)
+{
+     return model->model_->secondaryStatus();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setSecondaryStatus(Clp_Simplex * model, int status)
+{
+     model->model_->setSecondaryStatus(status);
+}
+/* Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+COINLIBAPI double COINLINKAGE
+Clp_optimizationDirection(Clp_Simplex * model)
+{
+     return model->model_->optimizationDirection();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setOptimizationDirection(Clp_Simplex * model, double value)
+{
+     model->model_->setOptimizationDirection(value);
+}
+/* Primal row solution */
+COINLIBAPI double * COINLINKAGE
+Clp_primalRowSolution(Clp_Simplex * model)
+{
+     return model->model_->primalRowSolution();
+}
+/* Primal column solution */
+COINLIBAPI double * COINLINKAGE
+Clp_primalColumnSolution(Clp_Simplex * model)
+{
+     return model->model_->primalColumnSolution();
+}
+/* Dual row solution */
+COINLIBAPI double * COINLINKAGE
+Clp_dualRowSolution(Clp_Simplex * model)
+{
+     return model->model_->dualRowSolution();
+}
+/* Reduced costs */
+COINLIBAPI double * COINLINKAGE
+Clp_dualColumnSolution(Clp_Simplex * model)
+{
+     return model->model_->dualColumnSolution();
+}
+/* Row lower */
+COINLIBAPI double* COINLINKAGE
+Clp_rowLower(Clp_Simplex * model)
+{
+     return model->model_->rowLower();
+}
+/* Row upper  */
+COINLIBAPI double* COINLINKAGE
+Clp_rowUpper(Clp_Simplex * model)
+{
+     return model->model_->rowUpper();
+}
+/* Objective */
+COINLIBAPI double * COINLINKAGE
+Clp_objective(Clp_Simplex * model)
+{
+     return model->model_->objective();
+}
+/* Column Lower */
+COINLIBAPI double * COINLINKAGE
+Clp_columnLower(Clp_Simplex * model)
+{
+     return model->model_->columnLower();
+}
+/* Column Upper */
+COINLIBAPI double * COINLINKAGE
+Clp_columnUpper(Clp_Simplex * model)
+{
+     return model->model_->columnUpper();
+}
+/* Number of elements in matrix */
+COINLIBAPI int COINLINKAGE
+Clp_getNumElements(Clp_Simplex * model)
+{
+     return model->model_->getNumElements();
+}
+// Column starts in matrix
+COINLIBAPI const CoinBigIndex * COINLINKAGE Clp_getVectorStarts(Clp_Simplex * model)
+{
+     CoinPackedMatrix * matrix;
+     matrix = model->model_->matrix();
+     return (matrix == NULL) ? NULL : matrix->getVectorStarts();
+}
+
+// Row indices in matrix
+COINLIBAPI const int * COINLINKAGE Clp_getIndices(Clp_Simplex * model)
+{
+     CoinPackedMatrix * matrix = model->model_->matrix();
+     return (matrix == NULL) ? NULL : matrix->getIndices();
+}
+
+// Column vector lengths in matrix
+COINLIBAPI const int * COINLINKAGE Clp_getVectorLengths(Clp_Simplex * model)
+{
+     CoinPackedMatrix * matrix = model->model_->matrix();
+     return (matrix == NULL) ? NULL : matrix->getVectorLengths();
+}
+
+// Element values in matrix
+COINLIBAPI const double * COINLINKAGE Clp_getElements(Clp_Simplex * model)
+{
+     CoinPackedMatrix * matrix = model->model_->matrix();
+     return (matrix == NULL) ? NULL : matrix->getElements();
+}
+/* Objective value */
+COINLIBAPI double COINLINKAGE
+Clp_objectiveValue(Clp_Simplex * model)
+{
+     return model->model_->objectiveValue();
+}
+/* Integer information */
+COINLIBAPI char * COINLINKAGE
+Clp_integerInformation(Clp_Simplex * model)
+{
+     return model->model_->integerInformation();
+}
+/* Infeasibility/unbounded ray (NULL returned if none/wrong)
+   Up to user to use free() on these arrays.  */
+COINLIBAPI double * COINLINKAGE
+Clp_infeasibilityRay(Clp_Simplex * model)
+{
+     const double * ray = model->model_->internalRay();
+     double * array = NULL;
+     int numberRows = model->model_->numberRows(); 
+     int status = model->model_->status();
+     if (status == 1 && ray) {
+          array = static_cast<double*>(malloc(numberRows*sizeof(double)));
+          memcpy(array,ray,numberRows*sizeof(double));
+#ifdef PRINT_RAY_METHOD
+	  printf("Infeasibility ray obtained by algorithm %s\n",model->model_->algorithm()>0 ?
+	      "primal" : "dual");
+#endif
+     }
+     return array;
+}
+COINLIBAPI double * COINLINKAGE
+Clp_unboundedRay(Clp_Simplex * model)
+{
+     const double * ray = model->model_->internalRay();
+     double * array = NULL;
+     int numberColumns = model->model_->numberColumns(); 
+     int status = model->model_->status();
+     if (status == 2 && ray) {
+          array = static_cast<double*>(malloc(numberColumns*sizeof(double)));
+          memcpy(array,ray,numberColumns*sizeof(double));
+     }
+     return array;
+}
+/* See if status array exists (partly for OsiClp) */
+COINLIBAPI int COINLINKAGE
+Clp_statusExists(Clp_Simplex * model)
+{
+     return model->model_->statusExists() ? 1 : 0;
+}
+/* Return address of status array (char[numberRows+numberColumns]) */
+COINLIBAPI unsigned char *  COINLINKAGE
+Clp_statusArray(Clp_Simplex * model)
+{
+     return model->model_->statusArray();
+}
+/* Copy in status vector */
+COINLIBAPI void COINLINKAGE
+Clp_copyinStatus(Clp_Simplex * model, const unsigned char * statusArray)
+{
+     model->model_->copyinStatus(statusArray);
+}
+
+/* User pointer for whatever reason */
+COINLIBAPI void COINLINKAGE
+Clp_setUserPointer (Clp_Simplex * model, void * pointer)
+{
+     model->model_->setUserPointer(pointer);
+}
+COINLIBAPI void * COINLINKAGE
+Clp_getUserPointer (Clp_Simplex * model)
+{
+     return model->model_->getUserPointer();
+}
+/* Pass in Callback function */
+COINLIBAPI void COINLINKAGE
+Clp_registerCallBack(Clp_Simplex * model,
+                     clp_callback userCallBack)
+{
+     // Will be copy of users one
+     delete model->handler_;
+     model->handler_ = new CMessageHandler(*(model->model_->messageHandler()));
+     model->handler_->setCallBack(userCallBack);
+     model->handler_->setModel(model);
+     model->model_->passInMessageHandler(model->handler_);
+}
+/* Unset Callback function */
+COINLIBAPI void COINLINKAGE
+Clp_clearCallBack(Clp_Simplex * model)
+{
+     delete model->handler_;
+     model->handler_ = NULL;
+}
+/* Amount of print out:
+   0 - none
+   1 - just final
+   2 - just factorizations
+   3 - as 2 plus a bit more
+   4 - verbose
+   above that 8,16,32 etc just for selective debug
+*/
+COINLIBAPI void COINLINKAGE
+Clp_setLogLevel(Clp_Simplex * model, int value)
+{
+     model->model_->setLogLevel(value);
+}
+COINLIBAPI int COINLINKAGE
+Clp_logLevel(Clp_Simplex * model)
+{
+     return model->model_->logLevel();
+}
+/* length of names (0 means no names0 */
+COINLIBAPI int COINLINKAGE
+Clp_lengthNames(Clp_Simplex * model)
+{
+     return model->model_->lengthNames();
+}
+/* Fill in array (at least lengthNames+1 long) with a row name */
+COINLIBAPI void COINLINKAGE
+Clp_rowName(Clp_Simplex * model, int iRow, char * name)
+{
+     std::string rowName = model->model_->rowName(iRow);
+     strcpy(name, rowName.c_str());
+}
+/* Fill in array (at least lengthNames+1 long) with a column name */
+COINLIBAPI void COINLINKAGE
+Clp_columnName(Clp_Simplex * model, int iColumn, char * name)
+{
+     std::string columnName = model->model_->columnName(iColumn);
+     strcpy(name, columnName.c_str());
+}
+
+/* General solve algorithm which can do presolve.
+   See  ClpSolve.hpp for options
+*/
+COINLIBAPI int COINLINKAGE
+Clp_initialSolve(Clp_Simplex * model)
+{
+     return model->model_->initialSolve();
+}
+/* Pass solve options. (Exception to direct analogue rule) */
+COINLIBAPI int COINLINKAGE
+Clp_initialSolveWithOptions(Clp_Simplex * model, Clp_Solve * s)
+{
+     return model->model_->initialSolve(s->options);
+}
+/* Barrier initial solve */
+COINLIBAPI int COINLINKAGE
+Clp_initialBarrierSolve(Clp_Simplex * model0)
+{
+     ClpSimplex *model = model0->model_;
+
+     return model->initialBarrierSolve();
+
+}
+/* Barrier initial solve */
+COINLIBAPI int COINLINKAGE
+Clp_initialBarrierNoCrossSolve(Clp_Simplex * model0)
+{
+     ClpSimplex *model = model0->model_;
+
+     return model->initialBarrierNoCrossSolve();
+
+}
+/* Dual initial solve */
+COINLIBAPI int COINLINKAGE
+Clp_initialDualSolve(Clp_Simplex * model)
+{
+     return model->model_->initialDualSolve();
+}
+/* Primal initial solve */
+COINLIBAPI int COINLINKAGE
+Clp_initialPrimalSolve(Clp_Simplex * model)
+{
+     return model->model_->initialPrimalSolve();
+}
+/* Dual algorithm - see ClpSimplexDual.hpp for method */
+COINLIBAPI int COINLINKAGE
+Clp_dual(Clp_Simplex * model, int ifValuesPass)
+{
+     return model->model_->dual(ifValuesPass);
+}
+/* Primal algorithm - see ClpSimplexPrimal.hpp for method */
+COINLIBAPI int COINLINKAGE
+Clp_primal(Clp_Simplex * model, int ifValuesPass)
+{
+     return model->model_->primal(ifValuesPass);
+}
+/* Sets or unsets scaling, 0 -off, 1 equilibrium, 2 geometric, 3, auto, 4 dynamic(later) */
+COINLIBAPI void COINLINKAGE
+Clp_scaling(Clp_Simplex * model, int mode)
+{
+     model->model_->scaling(mode);
+}
+/* Gets scalingFlag */
+COINLIBAPI int COINLINKAGE
+Clp_scalingFlag(Clp_Simplex * model)
+{
+     return model->model_->scalingFlag();
+}
+/* Crash - at present just aimed at dual, returns
+   -2 if dual preferred and crash basis created
+   -1 if dual preferred and all slack basis preferred
+   0 if basis going in was not all slack
+   1 if primal preferred and all slack basis preferred
+   2 if primal preferred and crash basis created.
+
+   if gap between bounds <="gap" variables can be flipped
+
+   If "pivot" is
+   0 No pivoting (so will just be choice of algorithm)
+   1 Simple pivoting e.g. gub
+   2 Mini iterations
+*/
+COINLIBAPI int COINLINKAGE
+Clp_crash(Clp_Simplex * model, double gap, int pivot)
+{
+     return model->model_->crash(gap, pivot);
+}
+/* If problem is primal feasible */
+COINLIBAPI int COINLINKAGE
+Clp_primalFeasible(Clp_Simplex * model)
+{
+     return model->model_->primalFeasible() ? 1 : 0;
+}
+/* If problem is dual feasible */
+COINLIBAPI int COINLINKAGE
+Clp_dualFeasible(Clp_Simplex * model)
+{
+     return model->model_->dualFeasible() ? 1 : 0;
+}
+/* Dual bound */
+COINLIBAPI double COINLINKAGE
+Clp_dualBound(Clp_Simplex * model)
+{
+     return model->model_->dualBound();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setDualBound(Clp_Simplex * model, double value)
+{
+     model->model_->setDualBound(value);
+}
+/* Infeasibility cost */
+COINLIBAPI double COINLINKAGE
+Clp_infeasibilityCost(Clp_Simplex * model)
+{
+     return model->model_->infeasibilityCost();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setInfeasibilityCost(Clp_Simplex * model, double value)
+{
+     model->model_->setInfeasibilityCost(value);
+}
+/* Perturbation:
+   50  - switch on perturbation
+   100 - auto perturb if takes too long (1.0e-6 largest nonzero)
+   101 - we are perturbed
+   102 - don't try perturbing again
+   default is 100
+   others are for playing
+*/
+COINLIBAPI int COINLINKAGE
+Clp_perturbation(Clp_Simplex * model)
+{
+     return model->model_->perturbation();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setPerturbation(Clp_Simplex * model, int value)
+{
+     model->model_->setPerturbation(value);
+}
+/* Current (or last) algorithm */
+COINLIBAPI int COINLINKAGE
+Clp_algorithm(Clp_Simplex * model)
+{
+     return model->model_->algorithm();
+}
+/* Set algorithm */
+COINLIBAPI void COINLINKAGE
+Clp_setAlgorithm(Clp_Simplex * model, int value)
+{
+     model->model_->setAlgorithm(value);
+}
+/* Sum of dual infeasibilities */
+COINLIBAPI double COINLINKAGE
+Clp_sumDualInfeasibilities(Clp_Simplex * model)
+{
+     return model->model_->sumDualInfeasibilities();
+}
+/* Number of dual infeasibilities */
+COINLIBAPI int COINLINKAGE
+Clp_numberDualInfeasibilities(Clp_Simplex * model)
+{
+     return model->model_->numberDualInfeasibilities();
+}
+/* Sum of primal infeasibilities */
+COINLIBAPI double COINLINKAGE
+Clp_sumPrimalInfeasibilities(Clp_Simplex * model)
+{
+     return model->model_->sumPrimalInfeasibilities();
+}
+/* Number of primal infeasibilities */
+COINLIBAPI int COINLINKAGE
+Clp_numberPrimalInfeasibilities(Clp_Simplex * model)
+{
+     return model->model_->numberPrimalInfeasibilities();
+}
+/* Save model to file, returns 0 if success.  This is designed for
+   use outside algorithms so does not save iterating arrays etc.
+   It does not save any messaging information.
+   Does not save scaling values.
+   It does not know about all types of virtual functions.
+*/
+COINLIBAPI int COINLINKAGE
+Clp_saveModel(Clp_Simplex * model, const char * fileName)
+{
+     return model->model_->saveModel(fileName);
+}
+/* Restore model from file, returns 0 if success,
+   deletes current model */
+COINLIBAPI int COINLINKAGE
+Clp_restoreModel(Clp_Simplex * model, const char * fileName)
+{
+     return model->model_->restoreModel(fileName);
+}
+
+/* Just check solution (for external use) - sets sum of
+   infeasibilities etc */
+COINLIBAPI void COINLINKAGE
+Clp_checkSolution(Clp_Simplex * model)
+{
+     model->model_->checkSolution();
+}
+/* Number of rows */
+COINLIBAPI int COINLINKAGE
+Clp_getNumRows(Clp_Simplex * model)
+{
+     return model->model_->getNumRows();
+}
+/* Number of columns */
+COINLIBAPI int COINLINKAGE
+Clp_getNumCols(Clp_Simplex * model)
+{
+     return model->model_->getNumCols();
+}
+/* Number of iterations */
+COINLIBAPI int COINLINKAGE
+Clp_getIterationCount(Clp_Simplex * model)
+{
+     return model->model_->getIterationCount();
+}
+/* Are there a numerical difficulties? */
+COINLIBAPI int COINLINKAGE
+Clp_isAbandoned(Clp_Simplex * model)
+{
+     return model->model_->isAbandoned() ? 1 : 0;
+}
+/* Is optimality proven? */
+COINLIBAPI int COINLINKAGE
+Clp_isProvenOptimal(Clp_Simplex * model)
+{
+     return model->model_->isProvenOptimal() ? 1 : 0;
+}
+/* Is primal infeasiblity proven? */
+COINLIBAPI int COINLINKAGE
+Clp_isProvenPrimalInfeasible(Clp_Simplex * model)
+{
+     return model->model_->isProvenPrimalInfeasible() ? 1 : 0;
+}
+/* Is dual infeasiblity proven? */
+COINLIBAPI int COINLINKAGE
+Clp_isProvenDualInfeasible(Clp_Simplex * model)
+{
+     return model->model_->isProvenDualInfeasible() ? 1 : 0;
+}
+/* Is the given primal objective limit reached? */
+COINLIBAPI int COINLINKAGE
+Clp_isPrimalObjectiveLimitReached(Clp_Simplex * model)
+{
+     return model->model_->isPrimalObjectiveLimitReached() ? 1 : 0;
+}
+/* Is the given dual objective limit reached? */
+COINLIBAPI int COINLINKAGE
+Clp_isDualObjectiveLimitReached(Clp_Simplex * model)
+{
+     return model->model_->isDualObjectiveLimitReached() ? 1 : 0;
+}
+/* Iteration limit reached? */
+COINLIBAPI int COINLINKAGE
+Clp_isIterationLimitReached(Clp_Simplex * model)
+{
+     return model->model_->isIterationLimitReached() ? 1 : 0;
+}
+/* Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+COINLIBAPI double COINLINKAGE
+Clp_getObjSense(Clp_Simplex * model)
+{
+     return model->model_->getObjSense();
+}
+/* Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+COINLIBAPI void COINLINKAGE
+Clp_setObjSense(Clp_Simplex * model, double objsen)
+{
+     model->model_->setOptimizationDirection(objsen);
+}
+/* Primal row solution */
+COINLIBAPI const double * COINLINKAGE
+Clp_getRowActivity(Clp_Simplex * model)
+{
+     return model->model_->getRowActivity();
+}
+/* Primal column solution */
+COINLIBAPI const double * COINLINKAGE
+Clp_getColSolution(Clp_Simplex * model)
+{
+     return model->model_->getColSolution();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setColSolution(Clp_Simplex * model, const double * input)
+{
+     model->model_->setColSolution(input);
+}
+/* Dual row solution */
+COINLIBAPI const double * COINLINKAGE
+Clp_getRowPrice(Clp_Simplex * model)
+{
+     return model->model_->getRowPrice();
+}
+/* Reduced costs */
+COINLIBAPI const double * COINLINKAGE
+Clp_getReducedCost(Clp_Simplex * model)
+{
+     return model->model_->getReducedCost();
+}
+/* Row lower */
+COINLIBAPI const double* COINLINKAGE
+Clp_getRowLower(Clp_Simplex * model)
+{
+     return model->model_->getRowLower();
+}
+/* Row upper  */
+COINLIBAPI const double* COINLINKAGE
+Clp_getRowUpper(Clp_Simplex * model)
+{
+     return model->model_->getRowUpper();
+}
+/* Objective */
+COINLIBAPI const double * COINLINKAGE
+Clp_getObjCoefficients(Clp_Simplex * model)
+{
+     return model->model_->getObjCoefficients();
+}
+/* Column Lower */
+COINLIBAPI const double * COINLINKAGE
+Clp_getColLower(Clp_Simplex * model)
+{
+     return model->model_->getColLower();
+}
+/* Column Upper */
+COINLIBAPI const double * COINLINKAGE
+Clp_getColUpper(Clp_Simplex * model)
+{
+     return model->model_->getColUpper();
+}
+/* Objective value */
+COINLIBAPI double COINLINKAGE
+Clp_getObjValue(Clp_Simplex * model)
+{
+     return model->model_->getObjValue();
+}
+/* Get variable basis info */
+COINLIBAPI int COINLINKAGE
+Clp_getColumnStatus(Clp_Simplex * model, int sequence)
+{
+     return (int) model->model_->getColumnStatus(sequence);
+}
+/* Get row basis info */
+COINLIBAPI int COINLINKAGE
+Clp_getRowStatus(Clp_Simplex * model, int sequence)
+{
+     return (int) model->model_->getRowStatus(sequence);
+}
+/* Set variable basis info */
+COINLIBAPI void COINLINKAGE
+Clp_setColumnStatus(Clp_Simplex * model, int sequence, int value)
+{
+     if (value >= 0 && value <= 5) {
+          model->model_->setColumnStatus(sequence, (ClpSimplex::Status) value );
+          if (value == 3 || value == 5)
+               model->model_->primalColumnSolution()[sequence] =
+                    model->model_->columnLower()[sequence];
+          else if (value == 2)
+               model->model_->primalColumnSolution()[sequence] =
+                    model->model_->columnUpper()[sequence];
+     }
+}
+/* Set row basis info */
+COINLIBAPI void COINLINKAGE
+Clp_setRowStatus(Clp_Simplex * model, int sequence, int value)
+{
+     if (value >= 0 && value <= 5) {
+          model->model_->setRowStatus(sequence, (ClpSimplex::Status) value );
+          if (value == 3 || value == 5)
+               model->model_->primalRowSolution()[sequence] =
+                    model->model_->rowLower()[sequence];
+          else if (value == 2)
+               model->model_->primalRowSolution()[sequence] =
+                    model->model_->rowUpper()[sequence];
+     }
+}
+/* Small element value - elements less than this set to zero,
+   default is 1.0e-20 */
+COINLIBAPI double COINLINKAGE
+Clp_getSmallElementValue(Clp_Simplex * model)
+{
+     return model->model_->getSmallElementValue();
+}
+COINLIBAPI void COINLINKAGE
+Clp_setSmallElementValue(Clp_Simplex * model, double value)
+{
+     model->model_->setSmallElementValue(value);
+}
+/* Print model */
+COINLIBAPI void COINLINKAGE
+Clp_printModel(Clp_Simplex * model, const char * prefix)
+{
+     ClpSimplex *clp_simplex = model->model_;
+     int numrows    = clp_simplex->numberRows();
+     int numcols    = clp_simplex->numberColumns();
+     int numelem    = clp_simplex->getNumElements();
+     const CoinBigIndex *start = clp_simplex->matrix()->getVectorStarts();
+     const int *index     = clp_simplex->matrix()->getIndices();
+     const double *value  = clp_simplex->matrix()->getElements();
+     const double *collb  = model->model_->columnLower();
+     const double *colub  = model->model_->columnUpper();
+     const double *obj    = model->model_->objective();
+     const double *rowlb  = model->model_->rowLower();
+     const double *rowub  = model->model_->rowUpper();
+     printf("%s numcols = %i, numrows = %i, numelem = %i\n",
+            prefix, numcols, numrows, numelem);
+     printf("%s model = %p, start = %p, index = %p, value = %p\n",
+            prefix, reinterpret_cast<const void *>(model), reinterpret_cast<const void *>(start), reinterpret_cast<const void *>(index), reinterpret_cast<const void *>(value));
+     clp_simplex->matrix()->dumpMatrix(NULL);
+     {
+          int i;
+          for (i = 0; i <= numcols; i++)
+               printf("%s start[%i] = %i\n", prefix, i, start[i]);
+          for (i = 0; i < numelem; i++)
+               printf("%s index[%i] = %i, value[%i] = %g\n",
+                      prefix, i, index[i], i, value[i]);
+     }
+
+     printf("%s collb = %p, colub = %p, obj = %p, rowlb = %p, rowub = %p\n",
+            prefix, reinterpret_cast<const void *>(collb), reinterpret_cast<const void *>(colub), reinterpret_cast<const void *>(obj), reinterpret_cast<const void *>(rowlb), reinterpret_cast<const void *>(rowub));
+     printf("%s optimization direction = %g\n", prefix, Clp_optimizationDirection(model));
+     printf("  (1 - minimize, -1 - maximize, 0 - ignore)\n");
+     {
+          int i;
+          for (i = 0; i < numcols; i++)
+               printf("%s collb[%i] = %g, colub[%i] = %g, obj[%i] = %g\n",
+                      prefix, i, collb[i], i, colub[i], i, obj[i]);
+          for (i = 0; i < numrows; i++)
+               printf("%s rowlb[%i] = %g, rowub[%i] = %g\n",
+                      prefix, i, rowlb[i], i, rowub[i]);
+     }
+}
+
+#ifndef SLIM_CLP
+/** Solve the problem with the idiot code */
+/* tryhard values:
+   tryhard & 7:
+      0: NOT lightweight, 105 iterations within a pass (when mu stays fixed)
+      1: lightweight, but focus more on optimality (mu is high)
+         (23 iters in a pass)
+      2: lightweight, but focus more on feasibility (11 iters in a pass)
+      3: lightweight, but focus more on feasibility (23 iters in a pass, so it
+         goes closer to opt than option 2)
+   tryhard >> 3:
+      number of passes, the larger the number the closer it gets to optimality
+*/
+COINLIBAPI void COINLINKAGE
+Clp_idiot(Clp_Simplex * model, int tryhard)
+{
+     ClpSimplex *clp = model->model_;
+     Idiot info(*clp);
+     int numberpass = tryhard >> 3;
+     int lightweight = tryhard & 7;
+     info.setLightweight(lightweight);
+     info.crash(numberpass, clp->messageHandler(), clp->messagesPointer(), false);
+}
+#endif
+
+COINLIBAPI Clp_Solve * COINLINKAGE 
+ClpSolve_new() 
+{ 
+    return new Clp_Solve(); 
+}
+
+COINLIBAPI void COINLINKAGE 
+ClpSolve_delete(Clp_Solve * solve) 
+{ 
+    delete solve; 
+}
+
+// space- and error-saving macros
+#define ClpSolveGetIntProperty(prop) \
+COINLIBAPI int COINLINKAGE \
+ClpSolve_ ## prop (Clp_Solve *s) \
+{ \
+    return s->options.prop(); \
+}
+
+#define ClpSolveSetIntProperty(prop) \
+COINLIBAPI void COINLINKAGE \
+ClpSolve_ ## prop (Clp_Solve *s, int val) \
+{ \
+    s->options.prop(val); \
+}
+
+COINLIBAPI void COINLINKAGE 
+ClpSolve_setSpecialOption(Clp_Solve * s, int which, int value, int extraInfo) 
+{
+    s->options.setSpecialOption(which,value,extraInfo);
+}
+
+COINLIBAPI int COINLINKAGE 
+ClpSolve_getSpecialOption(Clp_Solve * s, int which)
+{
+    return s->options.getSpecialOption(which);
+}
+
+COINLIBAPI void COINLINKAGE 
+ClpSolve_setSolveType(Clp_Solve * s, int method, int extraInfo)
+{
+    s->options.setSolveType(static_cast<ClpSolve::SolveType>(method), extraInfo);
+}
+
+ClpSolveGetIntProperty(getSolveType)
+
+COINLIBAPI void COINLINKAGE ClpSolve_setPresolveType(Clp_Solve * s, int amount, int extraInfo)
+{
+    s->options.setPresolveType(static_cast<ClpSolve::PresolveType>(amount),extraInfo);
+}
+
+ClpSolveGetIntProperty(getPresolveType)
+
+ClpSolveGetIntProperty(getPresolvePasses)
+
+
+COINLIBAPI int COINLINKAGE 
+ClpSolve_getExtraInfo(Clp_Solve * s, int which) {
+     return s->options.getExtraInfo(which);
+}
+
+ClpSolveSetIntProperty(setInfeasibleReturn)
+ClpSolveGetIntProperty(infeasibleReturn)
+
+ClpSolveGetIntProperty(doDual)
+ClpSolveSetIntProperty(setDoDual)
+
+ClpSolveGetIntProperty(doSingleton)
+ClpSolveSetIntProperty(setDoSingleton)
+
+ClpSolveGetIntProperty(doDoubleton)
+ClpSolveSetIntProperty(setDoDoubleton)
+
+ClpSolveGetIntProperty(doTripleton)
+ClpSolveSetIntProperty(setDoTripleton)
+
+ClpSolveGetIntProperty(doTighten)
+ClpSolveSetIntProperty(setDoTighten)
+
+ClpSolveGetIntProperty(doForcing)
+ClpSolveSetIntProperty(setDoForcing)
+
+ClpSolveGetIntProperty(doImpliedFree)
+ClpSolveSetIntProperty(setDoImpliedFree)
+
+ClpSolveGetIntProperty(doDupcol)
+ClpSolveSetIntProperty(setDoDupcol)
+
+ClpSolveGetIntProperty(doDuprow)
+ClpSolveSetIntProperty(setDoDuprow)
+
+ClpSolveGetIntProperty(doSingletonColumn)
+ClpSolveSetIntProperty(setDoSingletonColumn)
+
+ClpSolveGetIntProperty(presolveActions)
+ClpSolveSetIntProperty(setPresolveActions)
+
+ClpSolveGetIntProperty(substitution)
+ClpSolveSetIntProperty(setSubstitution)
+
+#if defined(__MWERKS__)
+#pragma export off
+#endif
+
diff --git a/cbits/coin/Clp_C_Interface.h b/cbits/coin/Clp_C_Interface.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Clp_C_Interface.h
@@ -0,0 +1,495 @@
+/* $Id: Clp_C_Interface.h 1902 2013-01-03 17:07:26Z stefan $ */
+/*
+  Copyright (C) 2002, 2003 International Business Machines Corporation
+  and others.  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+#ifndef ClpSimplexC_H
+#define ClpSimplexC_H
+
+/* include all defines and ugly stuff */
+#include "Coin_C_defines.h"
+
+#if defined (CLP_EXTERN_C)
+typedef struct {
+  ClpSolve options;
+} Clp_Solve;
+#else
+typedef void Clp_Solve;
+#endif
+
+/** This is a first "C" interface to Clp.
+    It has similarities to the OSL V3 interface
+    and only has most common functions
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+     /**@name Constructors and destructor
+        These do not have an exact analogue in C++.
+        The user does not need to know structure of Clp_Simplex or Clp_Solve.
+
+        For (almost) all Clp_* functions outside this group there is an exact C++
+        analogue created by taking the first parameter out, removing the Clp_
+        from name and applying the method to an object of type ClpSimplex.
+        
+        Similarly, for all ClpSolve_* functions there is an exact C++
+        analogue created by taking the first parameter out, removing the ClpSolve_
+        from name and applying the method to an object of type ClpSolve.
+     */
+     /*@{*/
+
+     /** Default constructor */
+     COINLIBAPI Clp_Simplex * COINLINKAGE Clp_newModel(void);
+     /** Destructor */
+     COINLIBAPI void COINLINKAGE Clp_deleteModel(Clp_Simplex * model);
+     /** Default constructor */
+     COINLIBAPI Clp_Solve * COINLINKAGE ClpSolve_new();
+     /** Destructor */ 
+     COINLIBAPI void COINLINKAGE ClpSolve_delete(Clp_Solve * solve);
+     /*@}*/
+
+     /**@name Load model - loads some stuff and initializes others */
+     /*@{*/
+     /** Loads a problem (the constraints on the
+         rows are given by lower and upper bounds). If a pointer is NULL then the
+         following values are the default:
+         <ul>
+         <li> <code>colub</code>: all columns have upper bound infinity
+         <li> <code>collb</code>: all columns have lower bound 0
+         <li> <code>rowub</code>: all rows have upper bound infinity
+         <li> <code>rowlb</code>: all rows have lower bound -infinity
+         <li> <code>obj</code>: all variables have 0 objective coefficient
+         </ul>
+     */
+     /** Just like the other loadProblem() method except that the matrix is
+     given in a standard column major ordered format (without gaps). */
+     COINLIBAPI void COINLINKAGE Clp_loadProblem (Clp_Simplex * model,  const int numcols, const int numrows,
+               const CoinBigIndex * start, const int* index,
+               const double* value,
+               const double* collb, const double* colub,
+               const double* obj,
+               const double* rowlb, const double* rowub);
+
+     /* read quadratic part of the objective (the matrix part) */
+     COINLIBAPI void COINLINKAGE
+     Clp_loadQuadraticObjective(Clp_Simplex * model,
+                                const int numberColumns,
+                                const CoinBigIndex * start,
+                                const int * column,
+                                const double * element);
+     /** Read an mps file from the given filename */
+     COINLIBAPI int COINLINKAGE Clp_readMps(Clp_Simplex * model, const char *filename,
+                                            int keepNames,
+                                            int ignoreErrors);
+     /** Copy in integer informations */
+     COINLIBAPI void COINLINKAGE Clp_copyInIntegerInformation(Clp_Simplex * model, const char * information);
+     /** Drop integer informations */
+     COINLIBAPI void COINLINKAGE Clp_deleteIntegerInformation(Clp_Simplex * model);
+     /** Resizes rim part of model  */
+     COINLIBAPI void COINLINKAGE Clp_resize (Clp_Simplex * model, int newNumberRows, int newNumberColumns);
+     /** Deletes rows */
+     COINLIBAPI void COINLINKAGE Clp_deleteRows(Clp_Simplex * model, int number, const int * which);
+     /** Add rows */
+     COINLIBAPI void COINLINKAGE Clp_addRows(Clp_Simplex * model, int number, const double * rowLower,
+                                             const double * rowUpper,
+                                             const int * rowStarts, const int * columns,
+                                             const double * elements);
+
+     /** Deletes columns */
+     COINLIBAPI void COINLINKAGE Clp_deleteColumns(Clp_Simplex * model, int number, const int * which);
+     /** Add columns */
+     COINLIBAPI void COINLINKAGE Clp_addColumns(Clp_Simplex * model, int number, const double * columnLower,
+               const double * columnUpper,
+               const double * objective,
+               const int * columnStarts, const int * rows,
+               const double * elements);
+     /** Change row lower bounds */
+     COINLIBAPI void COINLINKAGE Clp_chgRowLower(Clp_Simplex * model, const double * rowLower);
+     /** Change row upper bounds */
+     COINLIBAPI void COINLINKAGE Clp_chgRowUpper(Clp_Simplex * model, const double * rowUpper);
+     /** Change column lower bounds */
+     COINLIBAPI void COINLINKAGE Clp_chgColumnLower(Clp_Simplex * model, const double * columnLower);
+     /** Change column upper bounds */
+     COINLIBAPI void COINLINKAGE Clp_chgColumnUpper(Clp_Simplex * model, const double * columnUpper);
+     /** Change objective coefficients */
+     COINLIBAPI void COINLINKAGE Clp_chgObjCoefficients(Clp_Simplex * model, const double * objIn);
+     /** Drops names - makes lengthnames 0 and names empty */
+     COINLIBAPI void COINLINKAGE Clp_dropNames(Clp_Simplex * model);
+     /** Copies in names */
+     COINLIBAPI void COINLINKAGE Clp_copyNames(Clp_Simplex * model, const char * const * rowNames,
+               const char * const * columnNames);
+
+     /*@}*/
+     /**@name gets and sets - you will find some synonyms at the end of this file */
+     /*@{*/
+     /** Number of rows */
+     COINLIBAPI int COINLINKAGE Clp_numberRows(Clp_Simplex * model);
+     /** Number of columns */
+     COINLIBAPI int COINLINKAGE Clp_numberColumns(Clp_Simplex * model);
+     /** Primal tolerance to use */
+     COINLIBAPI double COINLINKAGE Clp_primalTolerance(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setPrimalTolerance(Clp_Simplex * model,  double value) ;
+     /** Dual tolerance to use */
+     COINLIBAPI double COINLINKAGE Clp_dualTolerance(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setDualTolerance(Clp_Simplex * model,  double value) ;
+     /** Dual objective limit */
+     COINLIBAPI double COINLINKAGE Clp_dualObjectiveLimit(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setDualObjectiveLimit(Clp_Simplex * model, double value);
+     /** Objective offset */
+     COINLIBAPI double COINLINKAGE Clp_objectiveOffset(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setObjectiveOffset(Clp_Simplex * model, double value);
+     /** Fills in array with problem name  */
+     COINLIBAPI void COINLINKAGE Clp_problemName(Clp_Simplex * model, int maxNumberCharacters, char * array);
+     /* Sets problem name.  Must have \0 at end.  */
+     COINLIBAPI int COINLINKAGE
+     Clp_setProblemName(Clp_Simplex * model, int maxNumberCharacters, char * array);
+     /** Number of iterations */
+     COINLIBAPI int COINLINKAGE Clp_numberIterations(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setNumberIterations(Clp_Simplex * model, int numberIterations);
+     /** Maximum number of iterations */
+     COINLIBAPI int maximumIterations(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setMaximumIterations(Clp_Simplex * model, int value);
+     /** Maximum time in seconds (from when set called) */
+     COINLIBAPI double COINLINKAGE Clp_maximumSeconds(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setMaximumSeconds(Clp_Simplex * model, double value);
+     /** Returns true if hit maximum iterations (or time) */
+     COINLIBAPI int COINLINKAGE Clp_hitMaximumIterations(Clp_Simplex * model);
+     /** Status of problem:
+         0 - optimal
+         1 - primal infeasible
+         2 - dual infeasible
+         3 - stopped on iterations etc
+         4 - stopped due to errors
+     */
+     COINLIBAPI int COINLINKAGE Clp_status(Clp_Simplex * model);
+     /** Set problem status */
+     COINLIBAPI void COINLINKAGE Clp_setProblemStatus(Clp_Simplex * model, int problemStatus);
+     /** Secondary status of problem - may get extended
+         0 - none
+         1 - primal infeasible because dual limit reached
+         2 - scaled problem optimal - unscaled has primal infeasibilities
+         3 - scaled problem optimal - unscaled has dual infeasibilities
+         4 - scaled problem optimal - unscaled has both dual and primal infeasibilities
+     */
+     COINLIBAPI int COINLINKAGE Clp_secondaryStatus(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setSecondaryStatus(Clp_Simplex * model, int status);
+     /** Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+     COINLIBAPI double COINLINKAGE Clp_optimizationDirection(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setOptimizationDirection(Clp_Simplex * model, double value);
+     /** Primal row solution */
+     COINLIBAPI double * COINLINKAGE Clp_primalRowSolution(Clp_Simplex * model);
+     /** Primal column solution */
+     COINLIBAPI double * COINLINKAGE Clp_primalColumnSolution(Clp_Simplex * model);
+     /** Dual row solution */
+     COINLIBAPI double * COINLINKAGE Clp_dualRowSolution(Clp_Simplex * model);
+     /** Reduced costs */
+     COINLIBAPI double * COINLINKAGE Clp_dualColumnSolution(Clp_Simplex * model);
+     /** Row lower */
+     COINLIBAPI double* COINLINKAGE Clp_rowLower(Clp_Simplex * model);
+     /** Row upper  */
+     COINLIBAPI double* COINLINKAGE Clp_rowUpper(Clp_Simplex * model);
+     /** Objective */
+     COINLIBAPI double * COINLINKAGE Clp_objective(Clp_Simplex * model);
+     /** Column Lower */
+     COINLIBAPI double * COINLINKAGE Clp_columnLower(Clp_Simplex * model);
+     /** Column Upper */
+     COINLIBAPI double * COINLINKAGE Clp_columnUpper(Clp_Simplex * model);
+     /** Number of elements in matrix */
+     COINLIBAPI int COINLINKAGE Clp_getNumElements(Clp_Simplex * model);
+     /* Column starts in matrix */
+     COINLIBAPI const CoinBigIndex * COINLINKAGE Clp_getVectorStarts(Clp_Simplex * model);
+     /* Row indices in matrix */
+     COINLIBAPI const int * COINLINKAGE Clp_getIndices(Clp_Simplex * model);
+     /* Column vector lengths in matrix */
+     COINLIBAPI const int * COINLINKAGE Clp_getVectorLengths(Clp_Simplex * model);
+     /* Element values in matrix */
+     COINLIBAPI const double * COINLINKAGE Clp_getElements(Clp_Simplex * model);
+     /** Objective value */
+     COINLIBAPI double COINLINKAGE Clp_objectiveValue(Clp_Simplex * model);
+     /** Integer information */
+     COINLIBAPI char * COINLINKAGE Clp_integerInformation(Clp_Simplex * model);
+     /** Infeasibility/unbounded ray (NULL returned if none/wrong)
+         Up to user to use free() on these arrays.  */
+     COINLIBAPI double * COINLINKAGE Clp_infeasibilityRay(Clp_Simplex * model);
+     COINLIBAPI double * COINLINKAGE Clp_unboundedRay(Clp_Simplex * model);
+     /** See if status array exists (partly for OsiClp) */
+     COINLIBAPI int COINLINKAGE Clp_statusExists(Clp_Simplex * model);
+     /** Return address of status array (char[numberRows+numberColumns]) */
+     COINLIBAPI unsigned char *  COINLINKAGE Clp_statusArray(Clp_Simplex * model);
+     /** Copy in status vector */
+     COINLIBAPI void COINLINKAGE Clp_copyinStatus(Clp_Simplex * model, const unsigned char * statusArray);
+     /* status values are as in ClpSimplex.hpp i.e. 0 - free, 1 basic, 2 at upper,
+        3 at lower, 4 superbasic, (5 fixed) */
+     /* Get variable basis info */
+     COINLIBAPI int COINLINKAGE Clp_getColumnStatus(Clp_Simplex * model, int sequence);
+     /* Get row basis info */
+     COINLIBAPI int COINLINKAGE Clp_getRowStatus(Clp_Simplex * model, int sequence);
+     /* Set variable basis info (and value if at bound) */
+     COINLIBAPI void COINLINKAGE Clp_setColumnStatus(Clp_Simplex * model,
+               int sequence, int value);
+     /* Set row basis info (and value if at bound) */
+     COINLIBAPI void COINLINKAGE Clp_setRowStatus(Clp_Simplex * model,
+               int sequence, int value);
+
+     /** User pointer for whatever reason */
+     COINLIBAPI void COINLINKAGE Clp_setUserPointer (Clp_Simplex * model, void * pointer);
+     COINLIBAPI void * COINLINKAGE Clp_getUserPointer (Clp_Simplex * model);
+     /*@}*/
+     /**@name Message handling.  Call backs are handled by ONE function */
+     /*@{*/
+     /** Pass in Callback function.
+      Message numbers up to 1000000 are Clp, Coin ones have 1000000 added */
+     COINLIBAPI void COINLINKAGE Clp_registerCallBack(Clp_Simplex * model,
+               clp_callback userCallBack);
+     /** Unset Callback function */
+     COINLIBAPI void COINLINKAGE Clp_clearCallBack(Clp_Simplex * model);
+     /** Amount of print out:
+         0 - none
+         1 - just final
+         2 - just factorizations
+         3 - as 2 plus a bit more
+         4 - verbose
+         above that 8,16,32 etc just for selective debug
+     */
+     COINLIBAPI void COINLINKAGE Clp_setLogLevel(Clp_Simplex * model, int value);
+     COINLIBAPI int COINLINKAGE Clp_logLevel(Clp_Simplex * model);
+     /** length of names (0 means no names0 */
+     COINLIBAPI int COINLINKAGE Clp_lengthNames(Clp_Simplex * model);
+     /** Fill in array (at least lengthNames+1 long) with a row name */
+     COINLIBAPI void COINLINKAGE Clp_rowName(Clp_Simplex * model, int iRow, char * name);
+     /** Fill in array (at least lengthNames+1 long) with a column name */
+     COINLIBAPI void COINLINKAGE Clp_columnName(Clp_Simplex * model, int iColumn, char * name);
+
+     /*@}*/
+
+
+     /**@name Functions most useful to user */
+     /*@{*/
+     /** General solve algorithm which can do presolve.
+         See  ClpSolve.hpp for options
+      */
+     COINLIBAPI int COINLINKAGE Clp_initialSolve(Clp_Simplex * model);
+     /** Pass solve options. (Exception to direct analogue rule) */ 
+     COINLIBAPI int COINLINKAGE Clp_initialSolveWithOptions(Clp_Simplex * model, Clp_Solve *);
+     /** Dual initial solve */
+     COINLIBAPI int COINLINKAGE Clp_initialDualSolve(Clp_Simplex * model);
+     /** Primal initial solve */
+     COINLIBAPI int COINLINKAGE Clp_initialPrimalSolve(Clp_Simplex * model);
+     /** Barrier initial solve */
+     COINLIBAPI int COINLINKAGE Clp_initialBarrierSolve(Clp_Simplex * model);
+     /** Barrier initial solve, no crossover */
+     COINLIBAPI int COINLINKAGE Clp_initialBarrierNoCrossSolve(Clp_Simplex * model);
+     /** Dual algorithm - see ClpSimplexDual.hpp for method */
+     COINLIBAPI int COINLINKAGE Clp_dual(Clp_Simplex * model, int ifValuesPass);
+     /** Primal algorithm - see ClpSimplexPrimal.hpp for method */
+     COINLIBAPI int COINLINKAGE Clp_primal(Clp_Simplex * model, int ifValuesPass);
+#ifndef SLIM_CLP
+     /** Solve the problem with the idiot code */
+     COINLIBAPI void COINLINKAGE Clp_idiot(Clp_Simplex * model, int tryhard);
+#endif
+     /** Sets or unsets scaling, 0 -off, 1 equilibrium, 2 geometric, 3, auto, 4 dynamic(later) */
+     COINLIBAPI void COINLINKAGE Clp_scaling(Clp_Simplex * model, int mode);
+     /** Gets scalingFlag */
+     COINLIBAPI int COINLINKAGE Clp_scalingFlag(Clp_Simplex * model);
+     /** Crash - at present just aimed at dual, returns
+         -2 if dual preferred and crash basis created
+         -1 if dual preferred and all slack basis preferred
+          0 if basis going in was not all slack
+          1 if primal preferred and all slack basis preferred
+          2 if primal preferred and crash basis created.
+
+          if gap between bounds <="gap" variables can be flipped
+
+          If "pivot" is
+          0 No pivoting (so will just be choice of algorithm)
+          1 Simple pivoting e.g. gub
+          2 Mini iterations
+     */
+     COINLIBAPI int COINLINKAGE Clp_crash(Clp_Simplex * model, double gap, int pivot);
+     /*@}*/
+
+
+     /**@name most useful gets and sets */
+     /*@{*/
+     /** If problem is primal feasible */
+     COINLIBAPI int COINLINKAGE Clp_primalFeasible(Clp_Simplex * model);
+     /** If problem is dual feasible */
+     COINLIBAPI int COINLINKAGE Clp_dualFeasible(Clp_Simplex * model);
+     /** Dual bound */
+     COINLIBAPI double COINLINKAGE Clp_dualBound(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setDualBound(Clp_Simplex * model, double value);
+     /** Infeasibility cost */
+     COINLIBAPI double COINLINKAGE Clp_infeasibilityCost(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setInfeasibilityCost(Clp_Simplex * model, double value);
+     /** Perturbation:
+         50  - switch on perturbation
+         100 - auto perturb if takes too long (1.0e-6 largest nonzero)
+         101 - we are perturbed
+         102 - don't try perturbing again
+         default is 100
+         others are for playing
+     */
+     COINLIBAPI int COINLINKAGE Clp_perturbation(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setPerturbation(Clp_Simplex * model, int value);
+     /** Current (or last) algorithm */
+     COINLIBAPI int COINLINKAGE Clp_algorithm(Clp_Simplex * model);
+     /** Set algorithm */
+     COINLIBAPI void COINLINKAGE Clp_setAlgorithm(Clp_Simplex * model, int value);
+     /** Sum of dual infeasibilities */
+     COINLIBAPI double COINLINKAGE Clp_sumDualInfeasibilities(Clp_Simplex * model);
+     /** Number of dual infeasibilities */
+     COINLIBAPI int COINLINKAGE Clp_numberDualInfeasibilities(Clp_Simplex * model);
+     /** Sum of primal infeasibilities */
+     COINLIBAPI double COINLINKAGE Clp_sumPrimalInfeasibilities(Clp_Simplex * model);
+     /** Number of primal infeasibilities */
+     COINLIBAPI int COINLINKAGE Clp_numberPrimalInfeasibilities(Clp_Simplex * model);
+     /** Save model to file, returns 0 if success.  This is designed for
+         use outside algorithms so does not save iterating arrays etc.
+     It does not save any messaging information.
+     Does not save scaling values.
+     It does not know about all types of virtual functions.
+     */
+     COINLIBAPI int COINLINKAGE Clp_saveModel(Clp_Simplex * model, const char * fileName);
+     /** Restore model from file, returns 0 if success,
+         deletes current model */
+     COINLIBAPI int COINLINKAGE Clp_restoreModel(Clp_Simplex * model, const char * fileName);
+
+     /** Just check solution (for external use) - sets sum of
+         infeasibilities etc */
+     COINLIBAPI void COINLINKAGE Clp_checkSolution(Clp_Simplex * model);
+     /*@}*/
+
+     /******************** End of most useful part **************/
+     /**@name gets and sets - some synonyms */
+     /*@{*/
+     /** Number of rows */
+     COINLIBAPI int COINLINKAGE Clp_getNumRows(Clp_Simplex * model);
+     /** Number of columns */
+     COINLIBAPI int COINLINKAGE Clp_getNumCols(Clp_Simplex * model);
+     /** Number of iterations */
+     COINLIBAPI int COINLINKAGE Clp_getIterationCount(Clp_Simplex * model);
+     /** Are there a numerical difficulties? */
+     COINLIBAPI int COINLINKAGE Clp_isAbandoned(Clp_Simplex * model);
+     /** Is optimality proven? */
+     COINLIBAPI int COINLINKAGE Clp_isProvenOptimal(Clp_Simplex * model);
+     /** Is primal infeasiblity proven? */
+     COINLIBAPI int COINLINKAGE Clp_isProvenPrimalInfeasible(Clp_Simplex * model);
+     /** Is dual infeasiblity proven? */
+     COINLIBAPI int COINLINKAGE Clp_isProvenDualInfeasible(Clp_Simplex * model);
+     /** Is the given primal objective limit reached? */
+     COINLIBAPI int COINLINKAGE Clp_isPrimalObjectiveLimitReached(Clp_Simplex * model) ;
+     /** Is the given dual objective limit reached? */
+     COINLIBAPI int COINLINKAGE Clp_isDualObjectiveLimitReached(Clp_Simplex * model) ;
+     /** Iteration limit reached? */
+     COINLIBAPI int COINLINKAGE Clp_isIterationLimitReached(Clp_Simplex * model);
+     /** Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+     COINLIBAPI double COINLINKAGE Clp_getObjSense(Clp_Simplex * model);
+     /** Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore */
+     COINLIBAPI void COINLINKAGE Clp_setObjSense(Clp_Simplex * model, double objsen);
+     /** Primal row solution */
+     COINLIBAPI const double * COINLINKAGE Clp_getRowActivity(Clp_Simplex * model);
+     /** Primal column solution */
+     COINLIBAPI const double * COINLINKAGE Clp_getColSolution(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setColSolution(Clp_Simplex * model, const double * input);
+     /** Dual row solution */
+     COINLIBAPI const double * COINLINKAGE Clp_getRowPrice(Clp_Simplex * model);
+     /** Reduced costs */
+     COINLIBAPI const double * COINLINKAGE Clp_getReducedCost(Clp_Simplex * model);
+     /** Row lower */
+     COINLIBAPI const double* COINLINKAGE Clp_getRowLower(Clp_Simplex * model);
+     /** Row upper  */
+     COINLIBAPI const double* COINLINKAGE Clp_getRowUpper(Clp_Simplex * model);
+     /** Objective */
+     COINLIBAPI const double * COINLINKAGE Clp_getObjCoefficients(Clp_Simplex * model);
+     /** Column Lower */
+     COINLIBAPI const double * COINLINKAGE Clp_getColLower(Clp_Simplex * model);
+     /** Column Upper */
+     COINLIBAPI const double * COINLINKAGE Clp_getColUpper(Clp_Simplex * model);
+     /** Objective value */
+     COINLIBAPI double COINLINKAGE Clp_getObjValue(Clp_Simplex * model);
+     /** Print model for debugging purposes */
+     COINLIBAPI void COINLINKAGE Clp_printModel(Clp_Simplex * model, const char * prefix);
+     /* Small element value - elements less than this set to zero,
+        default is 1.0e-20 */
+     COINLIBAPI double COINLINKAGE Clp_getSmallElementValue(Clp_Simplex * model);
+     COINLIBAPI void COINLINKAGE Clp_setSmallElementValue(Clp_Simplex * model, double value);
+     /*@}*/
+
+     
+     /**@name Get and set ClpSolve options
+     */
+     /*@{*/
+     COINLIBAPI void COINLINKAGE ClpSolve_setSpecialOption(Clp_Solve *, int which, int value, int extraInfo);
+     COINLIBAPI int COINLINKAGE ClpSolve_getSpecialOption(Clp_Solve *, int which);
+
+     /** method: (see ClpSolve::SolveType)
+         0 - dual simplex
+         1 - primal simplex
+         2 - primal or sprint
+         3 - barrier
+         4 - barrier no crossover
+         5 - automatic
+         6 - not implemented
+       -- pass extraInfo == -1 for default behavior */
+     COINLIBAPI void COINLINKAGE ClpSolve_setSolveType(Clp_Solve *, int method, int extraInfo);
+     COINLIBAPI int COINLINKAGE ClpSolve_getSolveType(Clp_Solve *);
+
+     /** amount: (see ClpSolve::PresolveType)
+         0 - presolve on
+         1 - presolve off
+         2 - presolve number
+         3 - presolve number cost
+       -- pass extraInfo == -1 for default behavior */
+     COINLIBAPI void COINLINKAGE ClpSolve_setPresolveType(Clp_Solve *, int amount, int extraInfo);
+     COINLIBAPI int COINLINKAGE ClpSolve_getPresolveType(Clp_Solve *);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_getPresolvePasses(Clp_Solve *);
+     COINLIBAPI int COINLINKAGE ClpSolve_getExtraInfo(Clp_Solve *, int which);
+     COINLIBAPI void COINLINKAGE ClpSolve_setInfeasibleReturn(Clp_Solve *, int trueFalse);
+     COINLIBAPI int COINLINKAGE ClpSolve_infeasibleReturn(Clp_Solve *);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_doDual(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoDual(Clp_Solve *, int doDual);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_doSingleton(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoSingleton(Clp_Solve *, int doSingleton);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_doDoubleton(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoDoubleton(Clp_Solve *, int doDoubleton);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_doTripleton(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoTripleton(Clp_Solve *, int doTripleton);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_doTighten(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoTighten(Clp_Solve *, int doTighten);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_doForcing(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoForcing(Clp_Solve *, int doForcing);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_doImpliedFree(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoImpliedFree(Clp_Solve *, int doImpliedFree);
+     
+     COINLIBAPI int COINLINKAGE ClpSolve_doDupcol(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoDupcol(Clp_Solve *, int doDupcol);
+     
+     COINLIBAPI int COINLINKAGE ClpSolve_doDuprow(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoDuprow(Clp_Solve *, int doDuprow);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_doSingletonColumn(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setDoSingletonColumn(Clp_Solve *, int doSingleton);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_presolveActions(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setPresolveActions(Clp_Solve *, int action);
+
+     COINLIBAPI int COINLINKAGE ClpSolve_substitution(Clp_Solve *);
+     COINLIBAPI void COINLINKAGE ClpSolve_setSubstitution(Clp_Solve *, int value);
+
+     /*@}*/
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/cbits/coin/CoinAlloc.cpp b/cbits/coin/CoinAlloc.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinAlloc.cpp
@@ -0,0 +1,176 @@
+/* $Id: CoinAlloc.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cassert>
+#include <cstdlib>
+#include <new>
+#include "CoinAlloc.hpp"
+
+#if (COINUTILS_MEMPOOL_MAXPOOLED >= 0)
+
+//=============================================================================
+
+CoinMempool::CoinMempool(size_t entry) :
+#if (COIN_MEMPOOL_SAVE_BLOCKHEADS==1)
+  block_heads_(NULL),
+  block_num_(0),
+  max_block_num_(0),
+#endif
+  last_block_size_(0),
+  first_free_(NULL),
+  entry_size_(entry)
+{
+#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
+  pthread_mutex_init(&mutex_, NULL);
+#endif
+  assert((entry_size_/COINUTILS_MEMPOOL_ALIGNMENT)*COINUTILS_MEMPOOL_ALIGNMENT
+	 == entry_size_);
+}
+
+//=============================================================================
+
+CoinMempool::~CoinMempool()
+{
+#if (COIN_MEMPOOL_SAVE_BLOCKHEADS==1)
+  for (size_t i = 0; i < block_num_; ++i) {
+    free(block_heads_[i]);
+  }
+#endif
+#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
+  pthread_mutex_destroy(&mutex_);
+#endif
+}
+
+//==============================================================================
+
+char* 
+CoinMempool::alloc()
+{
+  lock_mutex();
+  if (first_free_ == NULL) {
+    unlock_mutex();
+    char* block = allocate_new_block();
+    lock_mutex();
+#if (COIN_MEMPOOL_SAVE_BLOCKHEADS==1)
+    // see if we can record another block head. If not, then resize
+    // block_heads
+    if (max_block_num_ == block_num_) {
+      max_block_num_ = 2 * block_num_ + 10;
+      char** old_block_heads = block_heads_;
+      block_heads_ = (char**)malloc(max_block_num_ * sizeof(char*));
+      CoinMemcpyN( old_block_heads,block_num_,block_heads_);
+      free(old_block_heads);
+    }
+    // save the new block
+    block_heads_[block_num_++] = block;
+#endif
+    // link in the new block
+    *(char**)(block+((last_block_size_-1)*entry_size_)) = first_free_;
+    first_free_ = block;
+  }
+  char* p = first_free_;
+  first_free_ = *(char**)p;
+  unlock_mutex();
+  return p;
+}
+
+//=============================================================================
+
+char*
+CoinMempool::allocate_new_block()
+{
+  last_block_size_ = static_cast<int>(1.5 * last_block_size_ + 32);
+  char* block = static_cast<char*>(std::malloc(last_block_size_*entry_size_));
+  // link the entries in the new block together
+  for (int i = last_block_size_-2; i >= 0; --i) {
+    *(char**)(block+(i*entry_size_)) = block+((i+1)*entry_size_);
+  }
+  // terminate the linked list with a null pointer
+  *(char**)(block+((last_block_size_-1)*entry_size_)) = NULL;
+  return block;
+}
+
+//#############################################################################
+
+CoinAlloc CoinAllocator;
+
+CoinAlloc::CoinAlloc() :
+  pool_(NULL),
+  maxpooled_(COINUTILS_MEMPOOL_MAXPOOLED)
+{
+  const char* maxpooled = std::getenv("COINUTILS_MEMPOOL_MAXPOOLED");
+  if (maxpooled) {
+    maxpooled_ = std::atoi(maxpooled);
+  }
+  const size_t poolnum = maxpooled_ / COINUTILS_MEMPOOL_ALIGNMENT;
+  maxpooled_ = poolnum * COINUTILS_MEMPOOL_ALIGNMENT;
+  if (maxpooled_ > 0) {
+    pool_ = (CoinMempool*)malloc(sizeof(CoinMempool)*poolnum);
+    for (int i = poolnum-1; i >= 0; --i) {
+      new (&pool_[i]) CoinMempool(i*COINUTILS_MEMPOOL_ALIGNMENT);
+    }
+  }
+}
+
+//#############################################################################
+
+#if defined(COINUTILS_MEMPOOL_OVERRIDE_NEW) && (COINUTILS_MEMPOOL_OVERRIDE_NEW == 1)
+void* operator new(std::size_t sz) throw (std::bad_alloc)
+{ 
+  return CoinAllocator.alloc(sz); 
+}
+
+void* operator new[](std::size_t sz) throw (std::bad_alloc)
+{ 
+  return CoinAllocator.alloc(sz); 
+}
+
+void operator delete(void* p) throw()
+{ 
+  CoinAllocator.dealloc(p); 
+}
+  
+void operator delete[](void* p) throw()
+{ 
+  CoinAllocator.dealloc(p); 
+}
+  
+void* operator new(std::size_t sz, const std::nothrow_t&) throw()
+{
+  void *p = NULL;
+  try {
+    p = CoinAllocator.alloc(sz);
+  }
+  catch (std::bad_alloc &ba) {
+    return NULL;
+  }
+  return p;
+}
+
+void* operator new[](std::size_t sz, const std::nothrow_t&) throw()
+{
+  void *p = NULL;
+  try {
+    p = CoinAllocator.alloc(sz);
+  }
+  catch (std::bad_alloc &ba) {
+    return NULL;
+  }
+  return p;
+}
+
+void operator delete(void* p, const std::nothrow_t&) throw()
+{
+  CoinAllocator.dealloc(p); 
+}  
+
+void operator delete[](void* p, const std::nothrow_t&) throw()
+{
+  CoinAllocator.dealloc(p); 
+}  
+
+#endif
+
+#endif /*(COINUTILS_MEMPOOL_MAXPOOLED >= 0)*/
diff --git a/cbits/coin/CoinAlloc.hpp b/cbits/coin/CoinAlloc.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinAlloc.hpp
@@ -0,0 +1,176 @@
+/* $Id: CoinAlloc.hpp 1438 2011-06-09 18:14:12Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinAlloc_hpp
+#define CoinAlloc_hpp
+
+#include "CoinUtilsConfig.h"
+#include <cstdlib>
+
+#if !defined(COINUTILS_MEMPOOL_MAXPOOLED)
+#  define COINUTILS_MEMPOOL_MAXPOOLED -1
+#endif
+
+#if (COINUTILS_MEMPOOL_MAXPOOLED >= 0)
+
+#ifndef COINUTILS_MEMPOOL_ALIGNMENT
+#define COINUTILS_MEMPOOL_ALIGNMENT 16
+#endif
+
+/* Note:
+   This memory pool implementation assumes that sizeof(size_t) and
+   sizeof(void*) are both <= COINUTILS_MEMPOOL_ALIGNMENT.
+   Choosing an alignment of 4 will cause segfault on 64-bit platforms and may
+   lead to bad performance on 32-bit platforms. So 8 is a mnimum recommended
+   alignment. Probably 16 does not waste too much space either and may be even
+   better for performance. One must play with it.
+*/
+
+//#############################################################################
+
+#if (COINUTILS_MEMPOOL_ALIGNMENT == 16)
+static const std::size_t CoinAllocPtrShift = 4;
+static const std::size_t CoinAllocRoundMask = ~((std::size_t)15);
+#elif (COINUTILS_MEMPOOL_ALIGNMENT == 8)
+static const std::size_t CoinAllocPtrShift = 3;
+static const std::size_t CoinAllocRoundMask = ~((std::size_t)7);
+#else
+#error "COINUTILS_MEMPOOL_ALIGNMENT must be defined as 8 or 16 (or this code needs to be changed :-)"
+#endif
+
+//#############################################################################
+
+#ifndef COIN_MEMPOOL_SAVE_BLOCKHEADS
+#  define COIN_MEMPOOL_SAVE_BLOCKHEADS 0
+#endif
+
+//#############################################################################
+
+class CoinMempool 
+{
+private:
+#if (COIN_MEMPOOL_SAVE_BLOCKHEADS == 1)
+   char** block_heads;
+   std::size_t block_num;
+   std::size_t max_block_num;
+#endif
+#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
+  pthread_mutex_t mutex_;
+#endif
+  int last_block_size_;
+  char* first_free_;
+  const std::size_t entry_size_;
+
+private:
+  CoinMempool(const CoinMempool&);
+  CoinMempool& operator=(const CoinMempool&);
+
+private:
+  char* allocate_new_block();
+  inline void lock_mutex() {
+#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
+    pthread_mutex_lock(&mutex_);
+#endif
+  }
+  inline void unlock_mutex() {
+#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
+    pthread_mutex_unlock(&mutex_);
+#endif
+  }
+
+public:
+  CoinMempool(std::size_t size = 0);
+  ~CoinMempool();
+
+  char* alloc();
+  inline void dealloc(char *p) 
+  {
+    char** pp = (char**)p;
+    lock_mutex();
+    *pp = first_free_;
+    first_free_ = p;
+    unlock_mutex();
+  }
+};
+
+//#############################################################################
+
+/** A memory pool allocator.
+
+    If a request arrives for allocating \c n bytes then it is first
+    rounded up to the nearest multiple of \c sizeof(void*) (this is \c
+    n_roundup), then one more \c sizeof(void*) is added to this
+    number. If the result is no more than maxpooled_ then
+    the appropriate pool is used to get a chunk of memory, if not,
+    then malloc is used. In either case, the size of the allocated
+    chunk is written into the first \c sizeof(void*) bytes and a
+    pointer pointing afterwards is returned.
+*/
+
+class CoinAlloc
+{
+private:
+  CoinMempool* pool_;
+  int maxpooled_;
+public:
+  CoinAlloc();
+  ~CoinAlloc() {}
+
+  inline void* alloc(const std::size_t n)
+  {
+    if (maxpooled_ <= 0) {
+      return std::malloc(n);
+    }
+    char *p = NULL;
+    const std::size_t to_alloc =
+      ((n+COINUTILS_MEMPOOL_ALIGNMENT-1) & CoinAllocRoundMask) +
+      COINUTILS_MEMPOOL_ALIGNMENT;
+    CoinMempool* pool = NULL;
+    if (maxpooled_ > 0 && to_alloc >= (size_t)maxpooled_) {
+      p = static_cast<char*>(std::malloc(to_alloc));
+      if (p == NULL) throw std::bad_alloc();
+    } else {
+      pool = pool_ + (to_alloc >> CoinAllocPtrShift);
+      p = pool->alloc();
+    }
+    *((CoinMempool**)p) = pool;
+    return static_cast<void*>(p+COINUTILS_MEMPOOL_ALIGNMENT);
+  }
+
+  inline void dealloc(void* p)
+  {
+    if (maxpooled_ <= 0) {
+      std::free(p);
+      return;
+    }
+    if (p) {
+      char* base = static_cast<char*>(p)-COINUTILS_MEMPOOL_ALIGNMENT;
+      CoinMempool* pool = *((CoinMempool**)base);
+      if (!pool) {
+	std::free(base);
+      } else {
+	pool->dealloc(base);
+      }
+    }
+  }
+};
+
+extern CoinAlloc CoinAllocator;
+
+//#############################################################################
+
+#if defined(COINUTILS_MEMPOOL_OVERRIDE_NEW) && (COINUTILS_MEMPOOL_OVERRIDE_NEW == 1)
+void* operator new(std::size_t size) throw (std::bad_alloc);
+void* operator new[](std::size_t) throw (std::bad_alloc);
+void operator delete(void*) throw();
+void operator delete[](void*) throw();
+void* operator new(std::size_t, const std::nothrow_t&) throw();
+void* operator new[](std::size_t, const std::nothrow_t&) throw();
+void operator delete(void*, const std::nothrow_t&) throw();
+void operator delete[](void*, const std::nothrow_t&) throw();
+#endif
+
+#endif /*(COINUTILS_MEMPOOL_MAXPOOLED >= 0)*/
+#endif
diff --git a/cbits/coin/CoinBuild.cpp b/cbits/coin/CoinBuild.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinBuild.cpp
@@ -0,0 +1,390 @@
+/* $Id: CoinBuild.cpp 1550 2012-08-28 14:55:18Z forrest $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include <cstdlib>
+#include <cmath>
+#include <cassert>
+#include <cfloat>
+#include <cstdio>
+#include <iostream>
+
+
+#include "CoinBuild.hpp"
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+
+/*
+  Format of each item is a bit sleazy.
+  First we have pointer to next item
+  Then we have two ints giving item number and number of elements
+  Then we have three double for objective lower and upper
+  Then we have elements
+  Then indices
+*/
+struct buildFormat {
+  buildFormat * next;
+  int itemNumber;
+  int numberElements;
+  double objective;
+  double lower;
+  double upper;
+  double restDouble[1]; 
+  int restInt[1]; // just to make correct size 
+} ;
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinBuild::CoinBuild () 
+  : numberItems_(0),
+    numberOther_(0),
+    numberElements_(0),
+    currentItem_(NULL),
+    firstItem_(NULL),
+    lastItem_(NULL),
+    type_(-1)
+{
+}
+//-------------------------------------------------------------------
+// Constructor with type
+//-------------------------------------------------------------------
+CoinBuild::CoinBuild (int type) 
+  : numberItems_(0),
+    numberOther_(0),
+    numberElements_(0),
+    currentItem_(NULL),
+    firstItem_(NULL),
+    lastItem_(NULL),
+    type_(type)
+{
+  if (type<0||type>1)
+    type_=-1; // unset
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinBuild::CoinBuild (const CoinBuild & rhs) 
+  : numberItems_(rhs.numberItems_),
+    numberOther_(rhs.numberOther_),
+    numberElements_(rhs.numberElements_),
+    type_(rhs.type_)
+{
+  if (numberItems_) {
+    firstItem_=NULL;
+    buildFormat * lastItem = NULL;
+    buildFormat * currentItem = reinterpret_cast<buildFormat *> ( rhs.firstItem_);
+    for (int iItem=0;iItem<numberItems_;iItem++) {
+      buildFormat * item = currentItem;
+      assert (item);
+      int numberElements = item->numberElements;
+      int length = ( CoinSizeofAsInt(buildFormat) + (numberElements-1) *
+                     (CoinSizeofAsInt(double)+CoinSizeofAsInt(int)) );
+      int doubles = (length + CoinSizeofAsInt(double)-1)/CoinSizeofAsInt(double);
+      double * copyOfItem = new double [doubles];
+      memcpy(copyOfItem,item,length);
+      if (!firstItem_) {
+        firstItem_ = copyOfItem;
+      } else {
+        // update pointer
+        lastItem->next = reinterpret_cast<buildFormat *> ( copyOfItem);
+      }
+      currentItem = currentItem->next; // on to next
+      lastItem = reinterpret_cast<buildFormat *> ( copyOfItem);
+    }
+    currentItem_=firstItem_;
+    lastItem_=reinterpret_cast<double *> ( lastItem);
+  } else {
+    currentItem_=NULL;
+    firstItem_=NULL;
+    lastItem_=NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinBuild::~CoinBuild ()
+{
+  buildFormat * item = reinterpret_cast<buildFormat *> ( firstItem_);
+  for (int iItem=0;iItem<numberItems_;iItem++) {
+    double * array = reinterpret_cast<double *> ( item);
+    item = item->next;
+    delete [] array;
+  }
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinBuild &
+CoinBuild::operator=(const CoinBuild& rhs)
+{
+  if (this != &rhs) {
+    buildFormat * item = reinterpret_cast<buildFormat *> ( firstItem_);
+    for (int iItem=0;iItem<numberItems_;iItem++) {
+      double * array = reinterpret_cast<double *> ( item);
+      item = item->next;
+      delete [] array;
+    }
+    numberItems_=rhs.numberItems_;
+    numberOther_=rhs.numberOther_;
+    numberElements_=rhs.numberElements_;
+    type_=rhs.type_;
+    if (numberItems_) {
+      firstItem_=NULL;
+      buildFormat * lastItem = NULL;
+      buildFormat * currentItem = reinterpret_cast<buildFormat *> ( rhs.firstItem_);
+      for (int iItem=0;iItem<numberItems_;iItem++) {
+        buildFormat * item = currentItem;
+        assert (item);
+        int numberElements = item->numberElements;
+        int length = CoinSizeofAsInt(buildFormat)+(numberElements-1)*(CoinSizeofAsInt(double)+CoinSizeofAsInt(int));
+        int doubles = (length + CoinSizeofAsInt(double)-1)/CoinSizeofAsInt(double);
+        double * copyOfItem = new double [doubles];
+        memcpy(copyOfItem,item,length);
+        if (!firstItem_) {
+          firstItem_ = copyOfItem;
+        } else {
+          // update pointer
+          lastItem->next = reinterpret_cast<buildFormat *> ( copyOfItem);
+        }
+        currentItem = currentItem->next; // on to next
+        lastItem = reinterpret_cast<buildFormat *> ( copyOfItem);
+      }
+      currentItem_=firstItem_;
+      lastItem_=reinterpret_cast<double *> ( lastItem);
+    } else {
+      currentItem_=NULL;
+      firstItem_=NULL;
+      lastItem_=NULL;
+    }
+  }
+  return *this;
+}
+// add a row
+void 
+CoinBuild::addRow(int numberInRow, const int * columns,
+                 const double * elements, double rowLower, 
+                 double rowUpper)
+{
+  if (type_<0) {
+    type_=0;
+  } else if (type_==1) {
+    printf("CoinBuild:: unable to add a row in column mode\n");
+    abort();
+  }
+  if (numberInRow<0)
+    printf("bad number %d\n",numberInRow); // to stop compiler error
+  addItem(numberInRow, columns, elements, 
+          rowLower,rowUpper,0.0);
+  if (numberInRow<0)
+    printf("bad number %d\n",numberInRow); // to stop compiler error
+}
+/*  Returns number of elements in a row and information in row
+ */
+int 
+CoinBuild::row(int whichRow, double & rowLower, double & rowUpper,
+              const int * & indices, const double * & elements) const
+{
+  assert (type_==0);
+  setMutableCurrent(whichRow);
+  double dummyObjective;
+  return currentItem(rowLower,rowUpper,dummyObjective,indices,elements);
+}
+/*  Returns number of elements in current row and information in row
+    Used as rows may be stored in a chain
+*/
+int 
+CoinBuild::currentRow(double & rowLower, double & rowUpper,
+                     const int * & indices, const double * & elements) const
+{
+  assert (type_==0);
+  double dummyObjective;
+  return currentItem(rowLower,rowUpper,dummyObjective,indices,elements);
+}
+// Set current row
+void 
+CoinBuild::setCurrentRow(int whichRow)
+{
+  assert (type_==0);
+  setMutableCurrent(whichRow);
+}
+// Returns current row number
+int 
+CoinBuild::currentRow() const
+{
+  assert (type_==0);
+  return currentItem();
+}
+// add a column
+void 
+CoinBuild::addColumn(int numberInColumn, const int * rows,
+                     const double * elements, 
+                     double columnLower, 
+                     double columnUpper, double objectiveValue)
+{
+  if (type_<0) {
+    type_=1;
+  } else if (type_==0) {
+    printf("CoinBuild:: unable to add a column in row mode\n");
+    abort();
+  }
+  addItem(numberInColumn, rows, elements,
+          columnLower,columnUpper, objectiveValue);
+}
+/*  Returns number of elements in a column and information in column
+ */
+int 
+CoinBuild::column(int whichColumn,
+                  double & columnLower, double & columnUpper, double & objectiveValue, 
+                  const int * & indices, const double * & elements) const
+{
+  assert (type_==1);
+  setMutableCurrent(whichColumn);
+  return currentItem(columnLower,columnUpper,objectiveValue,indices,elements);
+}
+/*  Returns number of elements in current column and information in column
+    Used as columns may be stored in a chain
+*/
+int 
+CoinBuild::currentColumn( double & columnLower, double & columnUpper, double & objectiveValue, 
+                         const int * & indices, const double * & elements) const
+{
+  assert (type_==1);
+  return currentItem(columnLower,columnUpper,objectiveValue,indices,elements);
+}
+// Set current column
+void 
+CoinBuild::setCurrentColumn(int whichColumn)
+{
+  assert (type_==1);
+  setMutableCurrent(whichColumn);
+}
+// Returns current column number
+int 
+CoinBuild::currentColumn() const
+{
+  assert (type_==1);
+  return currentItem();
+}
+// add a item
+void 
+CoinBuild::addItem(int numberInItem, const int * indices,
+                  const double * elements, 
+                  double itemLower, 
+                  double itemUpper, double objectiveValue)
+{
+  buildFormat * lastItem = reinterpret_cast<buildFormat *> ( lastItem_);
+  int length = CoinSizeofAsInt(buildFormat)+(numberInItem-1)*(CoinSizeofAsInt(double)+CoinSizeofAsInt(int));
+  int doubles = (length + CoinSizeofAsInt(double)-1)/CoinSizeofAsInt(double);
+  double * newItem = new double [doubles];
+  if (!firstItem_) {
+    firstItem_ = newItem;
+  } else {
+    // update pointer
+    lastItem->next = reinterpret_cast<buildFormat *> ( newItem);
+  }
+  lastItem_=newItem;
+  currentItem_=newItem;
+  // now fill in
+  buildFormat * item = reinterpret_cast<buildFormat *> ( newItem);
+  double * els = &item->restDouble[0];
+  int * cols = reinterpret_cast<int *> (els+numberInItem);
+  item->next=NULL;
+  item->itemNumber=numberItems_;
+  numberItems_++;
+  item->numberElements=numberInItem;
+  numberElements_ += numberInItem;
+  item->objective=objectiveValue;
+  item->lower=itemLower;
+  item->upper=itemUpper;
+  for (int k=0;k<numberInItem;k++) {
+    int iColumn = indices[k];
+    assert (iColumn>=0);
+    if (iColumn<0) {
+      printf("bad col %d\n",iColumn); // to stop compiler error
+      abort();
+    }
+    if (iColumn>=numberOther_)
+      numberOther_ = iColumn+1;
+    els[k]=elements[k];
+    cols[k]=iColumn;
+  }
+  return;
+}
+/*  Returns number of elements in a item and information in item
+ */
+int 
+CoinBuild::item(int whichItem, 
+                double & itemLower, double & itemUpper, double & objectiveValue, 
+                const int * & indices, const double * & elements) const
+{
+  setMutableCurrent(whichItem);
+  return currentItem(itemLower,itemUpper,objectiveValue,indices,elements);
+}
+/*  Returns number of elements in current item and information in item
+    Used as items may be stored in a chain
+*/
+int 
+CoinBuild::currentItem(double & itemLower, double & itemUpper,
+                       double & objectiveValue, 
+                       const int * & indices, const double * & elements) const
+{
+  buildFormat * item = reinterpret_cast<buildFormat *> ( currentItem_);
+  if (item) {
+    int numberElements = item->numberElements;
+    elements = &item->restDouble[0];
+    indices = reinterpret_cast<const int *> (elements+numberElements);
+    objectiveValue=item->objective;
+    itemLower = item->lower;
+    itemUpper=item->upper;
+    return numberElements;
+  } else {
+    return -1;
+  }
+}
+// Set current item
+void 
+CoinBuild::setCurrentItem(int whichItem)
+{
+  setMutableCurrent(whichItem);
+}
+// Set current item
+void 
+CoinBuild::setMutableCurrent(int whichItem) const
+{
+  if (whichItem>=0&&whichItem<numberItems_) {
+    int nSkip = whichItem-1;
+    buildFormat * item = reinterpret_cast<buildFormat *> ( firstItem_);
+    // if further on then we can start from where we are
+    buildFormat * current = reinterpret_cast<buildFormat *> ( currentItem_);
+    if (current->itemNumber<=whichItem) {
+      item=current;
+      nSkip = whichItem-current->itemNumber;
+    }
+    for (int iItem=0;iItem<nSkip;iItem++) {
+      item = item->next;
+    }
+    assert (whichItem==item->itemNumber);
+    currentItem_ = reinterpret_cast<double *> ( item);
+  }
+}
+// Returns current item number
+int 
+CoinBuild::currentItem() const
+{
+  buildFormat * item = reinterpret_cast<buildFormat *> ( currentItem_);
+  if (item)
+    return item->itemNumber;
+  else
+    return -1;
+}
diff --git a/cbits/coin/CoinBuild.hpp b/cbits/coin/CoinBuild.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinBuild.hpp
@@ -0,0 +1,149 @@
+/* $Id: CoinBuild.hpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinBuild_H
+#define CoinBuild_H
+
+
+#include "CoinPragma.hpp"
+#include "CoinTypes.hpp"
+#include "CoinFinite.hpp"
+
+
+/** 
+    In many cases it is natural to build a model by adding one row at a time.  In Coin this
+    is inefficient so this class gives some help.  An instance of CoinBuild can be built up
+    more efficiently and then added to the Clp/OsiModel in one go.
+
+    It may be more efficient to have fewer arrays and re-allocate them but this should
+    give a large gain over addRow.
+
+    I have now extended it to columns.
+
+*/
+
+class CoinBuild {
+  
+public:
+  /**@name Useful methods */
+   //@{
+   /// add a row
+   void addRow(int numberInRow, const int * columns,
+	       const double * elements, double rowLower=-COIN_DBL_MAX, 
+              double rowUpper=COIN_DBL_MAX);
+   /// add a column
+   void addColumn(int numberInColumn, const int * rows,
+                  const double * elements, 
+                  double columnLower=0.0, 
+                  double columnUpper=COIN_DBL_MAX, double objectiveValue=0.0);
+   /// add a column
+   inline void addCol(int numberInColumn, const int * rows,
+                  const double * elements, 
+                  double columnLower=0.0, 
+                  double columnUpper=COIN_DBL_MAX, double objectiveValue=0.0)
+  { addColumn(numberInColumn, rows, elements, columnLower, columnUpper, objectiveValue);}
+   /// Return number of rows or maximum found so far
+  inline int numberRows() const
+  { return (type_==0) ? numberItems_ : numberOther_;}
+   /// Return number of columns or maximum found so far
+  inline int numberColumns() const
+  { return (type_==1) ? numberItems_ : numberOther_;}
+   /// Return number of elements
+  inline CoinBigIndex numberElements() const
+  { return numberElements_;}
+  /**  Returns number of elements in a row and information in row
+   */
+  int row(int whichRow, double & rowLower, double & rowUpper,
+          const int * & indices, const double * & elements) const;
+  /**  Returns number of elements in current row and information in row
+       Used as rows may be stored in a chain
+   */
+  int currentRow(double & rowLower, double & rowUpper,
+          const int * & indices, const double * & elements) const;
+  /// Set current row
+  void setCurrentRow(int whichRow);
+  /// Returns current row number
+  int currentRow() const;
+  /**  Returns number of elements in a column and information in column
+   */
+  int column(int whichColumn, 
+             double & columnLower, double & columnUpper,double & objectiveValue,
+             const int * & indices, const double * & elements) const;
+  /**  Returns number of elements in current column and information in column
+       Used as columns may be stored in a chain
+   */
+  int currentColumn( double & columnLower, double & columnUpper,double & objectiveValue,
+          const int * & indices, const double * & elements) const;
+  /// Set current column
+  void setCurrentColumn(int whichColumn);
+  /// Returns current column number
+  int currentColumn() const;
+  /// Returns type
+  inline int type() const
+  { return type_;}
+   //@}
+
+
+  /**@name Constructors, destructor */
+   //@{
+   /** Default constructor. */
+   CoinBuild();
+   /** Constructor with type 0==for addRow, 1== for addColumn. */
+   CoinBuild(int type);
+   /** Destructor */
+   ~CoinBuild();
+   //@}
+
+   /**@name Copy method */
+   //@{
+   /** The copy constructor. */
+   CoinBuild(const CoinBuild&);
+  /// =
+   CoinBuild& operator=(const CoinBuild&);
+   //@}
+private:
+  /// Set current 
+  void setMutableCurrent(int which) const;
+   /// add a item
+   void addItem(int numberInItem, const int * indices,
+                  const double * elements, 
+                  double itemLower, 
+                  double itemUpper, double objectiveValue);
+  /**  Returns number of elements in a item and information in item
+   */
+  int item(int whichItem, 
+             double & itemLower, double & itemUpper,double & objectiveValue,
+             const int * & indices, const double * & elements) const;
+  /**  Returns number of elements in current item and information in item
+       Used as items may be stored in a chain
+   */
+  int currentItem( double & itemLower, double & itemUpper,double & objectiveValue,
+          const int * & indices, const double * & elements) const;
+  /// Set current item
+  void setCurrentItem(int whichItem);
+  /// Returns current item number
+  int currentItem() const;
+   
+private:
+  /**@name Data members */
+   //@{
+  /// Current number of items
+  int numberItems_;
+  /// Current number of other dimension i.e. Columns if addRow (i.e. max)
+  int numberOther_;
+  /// Current number of elements
+  CoinBigIndex numberElements_;
+  /// Current item pointer
+  mutable double * currentItem_;
+  /// First item pointer
+  double * firstItem_;
+  /// Last item pointer
+  double * lastItem_;
+  /// Type of build - 0 for row, 1 for column, -1 unset
+  int type_;
+   //@}
+};
+
+#endif
diff --git a/cbits/coin/CoinDenseFactorization.cpp b/cbits/coin/CoinDenseFactorization.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinDenseFactorization.cpp
@@ -0,0 +1,1052 @@
+/* $Id: CoinDenseFactorization.cpp 1417 2011-04-17 15:05:57Z forrest $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinUtilsConfig.h"
+#include "CoinPragma.hpp"
+
+#include <cassert>
+#include <cstdio>
+
+#include "CoinDenseFactorization.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinFinite.hpp"
+#if COIN_BIG_DOUBLE==1
+#undef DENSE_CODE
+#endif
+#ifdef DENSE_CODE
+// using simple lapack interface
+extern "C" 
+{
+  /** LAPACK Fortran subroutine DGETRF. */
+  void F77_FUNC(dgetrf,DGETRF)(ipfint * m, ipfint *n,
+                               double *A, ipfint *ldA,
+                               ipfint * ipiv, ipfint *info);
+  /** LAPACK Fortran subroutine DGETRS. */
+  void F77_FUNC(dgetrs,DGETRS)(char *trans, cipfint *n,
+                               cipfint *nrhs, const double *A, cipfint *ldA,
+                               cipfint * ipiv, double *B, cipfint *ldB, ipfint *info,
+			       int trans_len);
+}
+#endif
+//:class CoinDenseFactorization.  Deals with Factorization and Updates
+//  CoinDenseFactorization.  Constructor
+CoinDenseFactorization::CoinDenseFactorization (  )
+  : CoinOtherFactorization()
+{
+  gutsOfInitialize();
+}
+
+/// Copy constructor 
+CoinDenseFactorization::CoinDenseFactorization ( const CoinDenseFactorization &other)
+  : CoinOtherFactorization(other)
+{
+  gutsOfInitialize();
+  gutsOfCopy(other);
+}
+// Clone
+CoinOtherFactorization * 
+CoinDenseFactorization::clone() const 
+{
+  return new CoinDenseFactorization(*this);
+}
+/// The real work of constructors etc
+void CoinDenseFactorization::gutsOfDestructor()
+{
+  delete [] elements_;
+  delete [] pivotRow_;
+  delete [] workArea_;
+  elements_ = NULL;
+  pivotRow_ = NULL;
+  workArea_ = NULL;
+  numberRows_ = 0;
+  numberColumns_ = 0;
+  numberGoodU_ = 0;
+  status_ = -1;
+  maximumRows_=0;
+  maximumSpace_=0;
+  solveMode_=0;
+}
+void CoinDenseFactorization::gutsOfInitialize()
+{
+  pivotTolerance_ = 1.0e-1;
+  zeroTolerance_ = 1.0e-13;
+#ifndef COIN_FAST_CODE
+  slackValue_ = -1.0;
+#endif
+  maximumPivots_=200;
+  relaxCheck_=1.0;
+  numberRows_ = 0;
+  numberColumns_ = 0;
+  numberGoodU_ = 0;
+  status_ = -1;
+  numberPivots_ = 0;
+  maximumRows_=0;
+  maximumSpace_=0;
+  elements_ = NULL;
+  pivotRow_ = NULL;
+  workArea_ = NULL;
+  solveMode_=0;
+}
+//  ~CoinDenseFactorization.  Destructor
+CoinDenseFactorization::~CoinDenseFactorization (  )
+{
+  gutsOfDestructor();
+}
+//  =
+CoinDenseFactorization & CoinDenseFactorization::operator = ( const CoinDenseFactorization & other ) {
+  if (this != &other) {    
+    gutsOfDestructor();
+    gutsOfInitialize();
+    gutsOfCopy(other);
+  }
+  return *this;
+}
+#ifdef DENSE_CODE
+#define WORK_MULT 2
+#else
+#define WORK_MULT 2
+#endif
+void CoinDenseFactorization::gutsOfCopy(const CoinDenseFactorization &other)
+{
+  pivotTolerance_ = other.pivotTolerance_;
+  zeroTolerance_ = other.zeroTolerance_;
+#ifndef COIN_FAST_CODE
+  slackValue_ = other.slackValue_;
+#endif
+  relaxCheck_ = other.relaxCheck_;
+  numberRows_ = other.numberRows_;
+  numberColumns_ = other.numberColumns_;
+  maximumRows_ = other.maximumRows_;
+  maximumSpace_ = other.maximumSpace_;
+  solveMode_ = other.solveMode_;
+  numberGoodU_ = other.numberGoodU_;
+  maximumPivots_ = other.maximumPivots_;
+  numberPivots_ = other.numberPivots_;
+  factorElements_ = other.factorElements_;
+  status_ = other.status_;
+  if (other.pivotRow_) {
+    pivotRow_ = new int [2*maximumRows_+maximumPivots_];
+    CoinMemcpyN(other.pivotRow_,(2*maximumRows_+numberPivots_),pivotRow_);
+    elements_ = new CoinFactorizationDouble [maximumSpace_];
+    CoinMemcpyN(other.elements_,(maximumRows_+numberPivots_)*maximumRows_,elements_);
+    workArea_ = new CoinFactorizationDouble [maximumRows_*WORK_MULT];
+    CoinZeroN(workArea_,maximumRows_*WORK_MULT);
+  } else {
+    elements_ = NULL;
+    pivotRow_ = NULL;
+    workArea_ = NULL;
+  }
+}
+
+//  getAreas.  Gets space for a factorization
+//called by constructors
+void
+CoinDenseFactorization::getAreas ( int numberOfRows,
+			 int numberOfColumns,
+			 CoinBigIndex ,
+			 CoinBigIndex  )
+{
+
+  numberRows_ = numberOfRows;
+  numberColumns_ = numberOfColumns;
+  CoinBigIndex size = numberRows_*(numberRows_+CoinMax(maximumPivots_,(numberRows_+1)>>1));
+  if (size>maximumSpace_) {
+    delete [] elements_;
+    elements_ = new CoinFactorizationDouble [size];
+    maximumSpace_ = size;
+  }
+  if (numberRows_>maximumRows_) {
+    maximumRows_ = numberRows_;
+    delete [] pivotRow_;
+    delete [] workArea_;
+    pivotRow_ = new int [2*maximumRows_+maximumPivots_];
+    workArea_ = new CoinFactorizationDouble [maximumRows_*WORK_MULT];
+  }
+}
+
+//  preProcess.  
+void
+CoinDenseFactorization::preProcess ()
+{
+  // could do better than this but this only a demo
+  CoinBigIndex put = numberRows_*numberRows_;
+  int *indexRow = reinterpret_cast<int *> (elements_+put);
+  CoinBigIndex * starts = reinterpret_cast<CoinBigIndex *> (pivotRow_); 
+  put = numberRows_*numberColumns_;
+  for (int i=numberColumns_-1;i>=0;i--) {
+    put -= numberRows_;
+    memset(workArea_,0,numberRows_*sizeof(CoinFactorizationDouble));
+    assert (starts[i]<=put);
+    for (CoinBigIndex j=starts[i];j<starts[i+1];j++) {
+      int iRow = indexRow[j];
+      workArea_[iRow] = elements_[j];
+    }
+    // move to correct position
+    CoinMemcpyN(workArea_,numberRows_,elements_+put);
+  }
+}
+
+//Does factorization
+int
+CoinDenseFactorization::factor ( )
+{
+  numberPivots_=0;
+  status_= 0;
+#ifdef DENSE_CODE
+  if (numberRows_==numberColumns_&&(solveMode_%10)!=0) {
+    int info;
+    F77_FUNC(dgetrf,DGETRF)(&numberRows_,&numberRows_,
+			    elements_,&numberRows_,pivotRow_,
+			    &info);
+    // need to check size of pivots
+    if(!info) {
+      // OK
+      solveMode_=1+10*(solveMode_/10);
+      numberGoodU_=numberRows_;
+      CoinZeroN(workArea_,2*numberRows_);
+#if 0 //ndef NDEBUG
+      const CoinFactorizationDouble * column = elements_;
+      double smallest=COIN_DBL_MAX;
+      for (int i=0;i<numberRows_;i++) {
+	if (fabs(column[i])<smallest)
+	  smallest = fabs(column[i]);
+	column += numberRows_;
+      }
+      if (smallest<1.0e-8)
+	printf("small el %g\n",smallest);
+#endif
+      return 0;
+    } else {
+      solveMode_=10*(solveMode_/10);
+    }
+  }
+#endif
+  for (int j=0;j<numberRows_;j++) {
+    pivotRow_[j+numberRows_]=j;
+  }
+  CoinFactorizationDouble * elements = elements_;
+  numberGoodU_=0;
+  for (int i=0;i<numberColumns_;i++) {
+    int iRow = -1;
+    // Find largest
+    double largest=zeroTolerance_;
+    for (int j=i;j<numberRows_;j++) {
+      double value = fabs(elements[j]);
+      if (value>largest) {
+	largest=value;
+	iRow=j;
+      }
+    }
+    if (iRow>=0) {
+      if (iRow!=i) {
+	// swap
+	assert (iRow>i);
+	CoinFactorizationDouble * elementsA = elements_;
+	for (int k=0;k<=i;k++) {
+	  // swap
+	  CoinFactorizationDouble value = elementsA[i];
+	  elementsA[i]=elementsA[iRow];
+	  elementsA[iRow]=value;
+	  elementsA += numberRows_;
+	}
+	int iPivot = pivotRow_[i+numberRows_];
+	pivotRow_[i+numberRows_]=pivotRow_[iRow+numberRows_];
+	pivotRow_[iRow+numberRows_]=iPivot;
+      }
+      CoinFactorizationDouble pivotValue = 1.0/elements[i];
+      elements[i]=pivotValue;
+      for (int j=i+1;j<numberRows_;j++) {
+	elements[j] *= pivotValue;
+      }
+      // Update rest
+      CoinFactorizationDouble * elementsA = elements;
+      for (int k=i+1;k<numberColumns_;k++) {
+	elementsA += numberRows_;
+	// swap
+	if (iRow!=i) {
+	  CoinFactorizationDouble value = elementsA[i];
+	  elementsA[i]=elementsA[iRow];
+	  elementsA[iRow]=value;
+	}
+	CoinFactorizationDouble value = elementsA[i];
+	for (int j=i+1;j<numberRows_;j++) {
+	  elementsA[j] -= value * elements[j];
+	}
+      }
+    } else {
+      status_=-1;
+      break;
+    }
+    numberGoodU_++;
+    elements += numberRows_;
+  }
+  for (int j=0;j<numberRows_;j++) {
+    int k = pivotRow_[j+numberRows_];
+    pivotRow_[k]=j;
+  }
+  return status_;
+}
+// Makes a non-singular basis by replacing variables
+void 
+CoinDenseFactorization::makeNonSingular(int * sequence, int numberColumns)
+{
+  // Replace bad ones by correct slack
+  int * workArea = reinterpret_cast<int *> (workArea_);
+  int i;
+  for ( i=0;i<numberRows_;i++) 
+    workArea[i]=-1;
+  for ( i=0;i<numberGoodU_;i++) {
+    int iOriginal = pivotRow_[i+numberRows_];
+    workArea[iOriginal]=i;
+    //workArea[i]=iOriginal;
+  }
+  int lastRow=-1;
+  for ( i=0;i<numberRows_;i++) {
+    if (workArea[i]==-1) {
+      lastRow=i;
+      break;
+    }
+  }
+  assert (lastRow>=0);
+  for ( i=numberGoodU_;i<numberRows_;i++) {
+    assert (lastRow<numberRows_);
+    // Put slack in basis
+    sequence[i]=lastRow+numberColumns;
+    lastRow++;
+    for (;lastRow<numberRows_;lastRow++) {
+      if (workArea[lastRow]==-1)
+	break;
+    }
+  }
+}
+#define DENSE_PERMUTE
+// Does post processing on valid factorization - putting variables on correct rows
+void 
+CoinDenseFactorization::postProcess(const int * sequence, int * pivotVariable)
+{
+#ifdef DENSE_CODE
+  if ((solveMode_%10)==0) {
+#endif
+    for (int i=0;i<numberRows_;i++) {
+      int k = sequence[i];
+#ifdef DENSE_PERMUTE
+      pivotVariable[pivotRow_[i+numberRows_]]=k;
+#else
+      //pivotVariable[pivotRow_[i]]=k;
+      //pivotVariable[pivotRow_[i]]=k;
+      pivotVariable[i]=k;
+      k=pivotRow_[i];
+      pivotRow_[i] = pivotRow_[i+numberRows_];
+      pivotRow_[i+numberRows_]=k;
+#endif
+    }
+#ifdef DENSE_CODE
+  } else {
+    // lapack
+    for (int i=0;i<numberRows_;i++) {
+      int k = sequence[i];
+      pivotVariable[i]=k;
+    }
+  }
+#endif
+}
+/* Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+   If checkBeforeModifying is true will do all accuracy checks
+   before modifying factorization.  Whether to set this depends on
+   speed considerations.  You could just do this on first iteration
+   after factorization and thereafter re-factorize
+   partial update already in U */
+int 
+CoinDenseFactorization::replaceColumn ( CoinIndexedVector * regionSparse,
+					int pivotRow,
+					double pivotCheck ,
+					bool /*checkBeforeModifying*/,
+				       double /*acceptablePivot*/)
+{
+  if (numberPivots_==maximumPivots_)
+    return 3;
+  CoinFactorizationDouble * elements = elements_ + numberRows_*(numberColumns_+numberPivots_);
+  double *region = regionSparse->denseVector (  );
+  int *regionIndex = regionSparse->getIndices (  );
+  int numberNonZero = regionSparse->getNumElements (  );
+  int i;
+  memset(elements,0,numberRows_*sizeof(CoinFactorizationDouble));
+  CoinFactorizationDouble pivotValue = pivotCheck;
+  if (fabs(pivotValue)<zeroTolerance_)
+    return 2;
+  pivotValue = 1.0/pivotValue;
+#ifdef DENSE_CODE
+  if ((solveMode_%10)==0) {
+#endif
+    if (regionSparse->packedMode()) {
+      for (i=0;i<numberNonZero;i++) {
+	int iRow = regionIndex[i];
+	double value = region[i];
+#ifdef DENSE_PERMUTE
+	iRow = pivotRow_[iRow]; // permute
+#endif
+	elements[iRow] = value;;
+      }
+    } else {
+      // not packed! - from user pivot?
+      for (i=0;i<numberNonZero;i++) {
+	int iRow = regionIndex[i];
+	double value = region[iRow];
+#ifdef DENSE_PERMUTE
+	iRow = pivotRow_[iRow]; // permute
+#endif
+	elements[iRow] = value;;
+      }
+    }
+    int realPivotRow = pivotRow_[pivotRow];
+    elements[realPivotRow]=pivotValue;
+    pivotRow_[2*numberRows_+numberPivots_]=realPivotRow;
+#ifdef DENSE_CODE
+  } else {
+    // lapack
+    if (regionSparse->packedMode()) {
+      for (i=0;i<numberNonZero;i++) {
+	int iRow = regionIndex[i];
+	double value = region[i];
+	elements[iRow] = value;;
+      }
+    } else {
+      // not packed! - from user pivot?
+      for (i=0;i<numberNonZero;i++) {
+	int iRow = regionIndex[i];
+	double value = region[iRow];
+	elements[iRow] = value;;
+      }
+    }
+    elements[pivotRow]=pivotValue;
+    pivotRow_[2*numberRows_+numberPivots_]=pivotRow;
+  }
+#endif
+  numberPivots_++;
+  return 0;
+}
+/* This version has same effect as above with FTUpdate==false
+   so number returned is always >=0 */
+int 
+CoinDenseFactorization::updateColumn ( CoinIndexedVector * regionSparse,
+				       CoinIndexedVector * regionSparse2,
+				       bool noPermute) const
+{
+  assert (numberRows_==numberColumns_);
+  double *region2 = regionSparse2->denseVector (  );
+  int *regionIndex = regionSparse2->getIndices (  );
+  int numberNonZero = regionSparse2->getNumElements (  );
+  double *region = regionSparse->denseVector (  );
+#ifdef DENSE_CODE
+  if ((solveMode_%10)==0) {
+#endif
+    if (!regionSparse2->packedMode()) {
+      if (!noPermute) {
+	for (int j=0;j<numberRows_;j++) {
+	  int iRow = pivotRow_[j+numberRows_];
+	  region[j]=region2[iRow];
+	  region2[iRow]=0.0;
+	}
+      } else {
+	// can't due to check mode assert (regionSparse==regionSparse2);
+	region = regionSparse2->denseVector (  );
+      }
+    } else {
+      // packed mode
+      assert (!noPermute);
+      for (int j=0;j<numberNonZero;j++) {
+	int jRow = regionIndex[j];
+	int iRow = pivotRow_[jRow];
+	region[iRow]=region2[j];
+	region2[j]=0.0;
+      }
+    }
+#ifdef DENSE_CODE
+  } else {
+    // lapack
+    if (!regionSparse2->packedMode()) {
+      if (!noPermute) {
+	for (int j=0;j<numberRows_;j++) {
+	  region[j]=region2[j];
+	  region2[j]=0.0;
+	}
+      } else {
+	// can't due to check mode assert (regionSparse==regionSparse2);
+	region = regionSparse2->denseVector (  );
+      }
+    } else {
+      // packed mode
+      assert (!noPermute);
+      for (int j=0;j<numberNonZero;j++) {
+	int jRow = regionIndex[j];
+	region[jRow]=region2[j];
+	region2[j]=0.0;
+      }
+    }
+  }
+#endif
+  int i;
+  CoinFactorizationDouble * elements = elements_;
+#ifdef DENSE_CODE
+  if ((solveMode_%10)==0) {
+#endif
+    // base factorization L
+    for (i=0;i<numberColumns_;i++) {
+      double value = region[i];
+      for (int j=i+1;j<numberRows_;j++) {
+	region[j] -= value*elements[j];
+      }
+      elements += numberRows_;
+    }
+    elements = elements_+numberRows_*numberRows_;
+    // base factorization U
+    for (i=numberColumns_-1;i>=0;i--) {
+      elements -= numberRows_;
+      CoinFactorizationDouble value = region[i]*elements[i];
+      region[i] = value;
+      for (int j=0;j<i;j++) {
+	region[j] -= value*elements[j];
+      }
+    }
+#ifdef DENSE_CODE
+  } else {
+    char trans = 'N';
+    int ione=1;
+    int info;
+    F77_FUNC(dgetrs,DGETRS)(&trans,&numberRows_,&ione,elements_,&numberRows_,
+			      pivotRow_,region,&numberRows_,&info,1);
+  }
+#endif
+  // now updates
+  elements = elements_+numberRows_*numberRows_;
+  for (i=0;i<numberPivots_;i++) {
+    int iPivot = pivotRow_[i+2*numberRows_];
+    CoinFactorizationDouble value = region[iPivot]*elements[iPivot];
+    for (int j=0;j<numberRows_;j++) {
+      region[j] -= value*elements[j];
+    }
+    region[iPivot] = value;
+    elements += numberRows_;
+  }
+  // permute back and get nonzeros
+  numberNonZero=0;
+#ifdef DENSE_CODE
+  if ((solveMode_%10)==0) {
+#endif
+    if (!noPermute) {
+      if (!regionSparse2->packedMode()) {
+	for (int j=0;j<numberRows_;j++) {
+#ifdef DENSE_PERMUTE
+	  int iRow = pivotRow_[j];
+#else
+	  int iRow=j;
+#endif
+	  double value = region[iRow];
+	  region[iRow]=0.0;
+	  if (fabs(value)>zeroTolerance_) {
+	    region2[j] = value;
+	    regionIndex[numberNonZero++]=j;
+	  }
+	}
+      } else {
+	// packed mode
+	for (int j=0;j<numberRows_;j++) {
+#ifdef DENSE_PERMUTE
+	  int iRow = pivotRow_[j];
+#else
+	  int iRow=j;
+#endif
+	  double value = region[iRow];
+	  region[iRow]=0.0;
+	  if (fabs(value)>zeroTolerance_) {
+	    region2[numberNonZero] = value;
+	    regionIndex[numberNonZero++]=j;
+	  }
+	}
+      }
+    } else {
+      for (int j=0;j<numberRows_;j++) {
+	double value = region[j];
+	if (fabs(value)>zeroTolerance_) {
+	  regionIndex[numberNonZero++]=j;
+	} else {
+	  region[j]=0.0;
+	}
+      }
+    }
+#ifdef DENSE_CODE
+  } else {
+    // lapack
+    if (!noPermute) {
+      if (!regionSparse2->packedMode()) {
+	for (int j=0;j<numberRows_;j++) {
+	  double value = region[j];
+	  region[j]=0.0;
+	  if (fabs(value)>zeroTolerance_) {
+	    region2[j] = value;
+	    regionIndex[numberNonZero++]=j;
+	  }
+	}
+      } else {
+	// packed mode
+	for (int j=0;j<numberRows_;j++) {
+	  double value = region[j];
+	  region[j]=0.0;
+	  if (fabs(value)>zeroTolerance_) {
+	    region2[numberNonZero] = value;
+	    regionIndex[numberNonZero++]=j;
+	  }
+	}
+      }
+    } else {
+      for (int j=0;j<numberRows_;j++) {
+	double value = region[j];
+	if (fabs(value)>zeroTolerance_) {
+	  regionIndex[numberNonZero++]=j;
+	} else {
+	  region[j]=0.0;
+	}
+      }
+    }
+  }
+#endif
+  regionSparse2->setNumElements(numberNonZero);
+  return 0;
+}
+
+
+int 
+CoinDenseFactorization::updateTwoColumnsFT(CoinIndexedVector * regionSparse1,
+					  CoinIndexedVector * regionSparse2,
+					  CoinIndexedVector * regionSparse3,
+					   bool /*noPermute*/)
+{
+#ifdef DENSE_CODE
+#if 0
+  CoinIndexedVector s2(*regionSparse2);
+  CoinIndexedVector s3(*regionSparse3);
+  updateColumn(regionSparse1,&s2);
+  updateColumn(regionSparse1,&s3);
+#endif
+  if ((solveMode_%10)==0) {
+#endif
+    updateColumn(regionSparse1,regionSparse2);
+    updateColumn(regionSparse1,regionSparse3);
+#ifdef DENSE_CODE
+  } else {
+    // lapack
+    assert (numberRows_==numberColumns_);
+    double *region2 = regionSparse2->denseVector (  );
+    int *regionIndex2 = regionSparse2->getIndices (  );
+    int numberNonZero2 = regionSparse2->getNumElements (  );
+    CoinFactorizationDouble * regionW2 = workArea_;
+    if (!regionSparse2->packedMode()) {
+      for (int j=0;j<numberRows_;j++) {
+	regionW2[j]=region2[j];
+	region2[j]=0.0;
+      }
+    } else {
+      // packed mode
+      for (int j=0;j<numberNonZero2;j++) {
+	int jRow = regionIndex2[j];
+	regionW2[jRow]=region2[j];
+	region2[j]=0.0;
+      }
+    }
+    double *region3 = regionSparse3->denseVector (  );
+    int *regionIndex3 = regionSparse3->getIndices (  );
+    int numberNonZero3 = regionSparse3->getNumElements (  );
+    CoinFactorizationDouble *regionW3 = workArea_+numberRows_;
+    if (!regionSparse3->packedMode()) {
+      for (int j=0;j<numberRows_;j++) {
+	regionW3[j]=region3[j];
+	region3[j]=0.0;
+      }
+    } else {
+      // packed mode
+      for (int j=0;j<numberNonZero3;j++) {
+	int jRow = regionIndex3[j];
+	regionW3[jRow]=region3[j];
+	region3[j]=0.0;
+      }
+    }
+    int i;
+    CoinFactorizationDouble * elements = elements_;
+    char trans = 'N';
+    int itwo=2;
+    int info;
+    F77_FUNC(dgetrs,DGETRS)(&trans,&numberRows_,&itwo,elements_,&numberRows_,
+			    pivotRow_,workArea_,&numberRows_,&info,1);
+    // now updates
+    elements = elements_+numberRows_*numberRows_;
+    for (i=0;i<numberPivots_;i++) {
+      int iPivot = pivotRow_[i+2*numberRows_];
+      CoinFactorizationDouble value2 = regionW2[iPivot]*elements[iPivot];
+      CoinFactorizationDouble value3 = regionW3[iPivot]*elements[iPivot];
+      for (int j=0;j<numberRows_;j++) {
+	regionW2[j] -= value2*elements[j];
+	regionW3[j] -= value3*elements[j];
+      }
+      regionW2[iPivot] = value2;
+      regionW3[iPivot] = value3;
+      elements += numberRows_;
+    }
+    // permute back and get nonzeros
+    numberNonZero2=0;
+    if (!regionSparse2->packedMode()) {
+      for (int j=0;j<numberRows_;j++) {
+	double value = regionW2[j];
+	regionW2[j]=0.0;
+	if (fabs(value)>zeroTolerance_) {
+	  region2[j] = value;
+	  regionIndex2[numberNonZero2++]=j;
+	}
+      }
+    } else {
+      // packed mode
+      for (int j=0;j<numberRows_;j++) {
+	double value = regionW2[j];
+	regionW2[j]=0.0;
+	if (fabs(value)>zeroTolerance_) {
+	  region2[numberNonZero2] = value;
+	  regionIndex2[numberNonZero2++]=j;
+	}
+      }
+    }
+    regionSparse2->setNumElements(numberNonZero2);
+    numberNonZero3=0;
+    if (!regionSparse3->packedMode()) {
+      for (int j=0;j<numberRows_;j++) {
+	double value = regionW3[j];
+	regionW3[j]=0.0;
+	if (fabs(value)>zeroTolerance_) {
+	  region3[j] = value;
+	  regionIndex3[numberNonZero3++]=j;
+	}
+      }
+    } else {
+      // packed mode
+      for (int j=0;j<numberRows_;j++) {
+	double value = regionW3[j];
+	regionW3[j]=0.0;
+	if (fabs(value)>zeroTolerance_) {
+	  region3[numberNonZero3] = value;
+	  regionIndex3[numberNonZero3++]=j;
+	}
+      }
+    }
+    regionSparse3->setNumElements(numberNonZero3);
+#if 0
+    printf("Good2==\n");
+    s2.print();
+    printf("Bad2==\n");
+    regionSparse2->print();
+    printf("======\n");
+    printf("Good3==\n");
+    s3.print();
+    printf("Bad3==\n");
+    regionSparse3->print();
+    printf("======\n");
+#endif
+  }
+#endif
+  return 0;
+}
+
+/* Updates one column (BTRAN) from regionSparse2
+   regionSparse starts as zero and is zero at end 
+   Note - if regionSparse2 packed on input - will be packed on output
+*/
+int 
+CoinDenseFactorization::updateColumnTranspose ( CoinIndexedVector * regionSparse,
+						CoinIndexedVector * regionSparse2) const
+{
+  assert (numberRows_==numberColumns_);
+  double *region2 = regionSparse2->denseVector (  );
+  int *regionIndex = regionSparse2->getIndices (  );
+  int numberNonZero = regionSparse2->getNumElements (  );
+  double *region = regionSparse->denseVector (  );
+#ifdef DENSE_CODE
+  if ((solveMode_%10)==0) {
+#endif
+    if (!regionSparse2->packedMode()) {
+      for (int j=0;j<numberRows_;j++) {
+#ifdef DENSE_PERMUTE
+	int iRow = pivotRow_[j];
+#else
+	int iRow=j;
+#endif
+	region[iRow]=region2[j];
+	region2[j]=0.0;
+      }
+    } else {
+      for (int j=0;j<numberNonZero;j++) {
+	int jRow = regionIndex[j];
+#ifdef DENSE_PERMUTE
+	int iRow = pivotRow_[jRow];
+#else
+	int iRow=jRow;
+#endif
+	region[iRow]=region2[j];
+	region2[j]=0.0;
+      }
+    }
+#ifdef DENSE_CODE
+  } else {
+    // lapack
+    if (!regionSparse2->packedMode()) {
+      for (int j=0;j<numberRows_;j++) {
+	region[j]=region2[j];
+	region2[j]=0.0;
+      }
+    } else {
+      for (int j=0;j<numberNonZero;j++) {
+	int jRow = regionIndex[j];
+	region[jRow]=region2[j];
+	region2[j]=0.0;
+      }
+    }
+  }
+#endif
+  int i;
+  CoinFactorizationDouble * elements = elements_+numberRows_*(numberRows_+numberPivots_);
+  // updates
+  for (i=numberPivots_-1;i>=0;i--) {
+    elements -= numberRows_;
+    int iPivot = pivotRow_[i+2*numberRows_];
+    CoinFactorizationDouble value = region[iPivot]; //*elements[iPivot];
+    for (int j=0;j<iPivot;j++) {
+      value -= region[j]*elements[j];
+    }
+    for (int j=iPivot+1;j<numberRows_;j++) {
+      value -= region[j]*elements[j];
+    }
+    region[iPivot] = value*elements[iPivot];
+  }
+#ifdef DENSE_CODE
+  if ((solveMode_%10)==0) {
+#endif
+    // base factorization U
+    elements = elements_;
+    for (i=0;i<numberColumns_;i++) {
+      //CoinFactorizationDouble value = region[i]*elements[i];
+      CoinFactorizationDouble value = region[i];
+      for (int j=0;j<i;j++) {
+	value -= region[j]*elements[j];
+      }
+      //region[i] = value;
+      region[i] = value*elements[i];
+      elements += numberRows_;
+    }
+    // base factorization L
+    elements = elements_+numberRows_*numberRows_;
+    for (i=numberColumns_-1;i>=0;i--) {
+      elements -= numberRows_;
+      CoinFactorizationDouble value = region[i];
+      for (int j=i+1;j<numberRows_;j++) {
+	value -= region[j]*elements[j];
+      }
+      region[i] = value;
+    }
+#ifdef DENSE_CODE
+  } else {
+    char trans = 'T';
+    int ione=1;
+    int info;
+    F77_FUNC(dgetrs,DGETRS)(&trans,&numberRows_,&ione,elements_,&numberRows_,
+			      pivotRow_,region,&numberRows_,&info,1);
+  }
+#endif
+  // permute back and get nonzeros
+  numberNonZero=0;
+#ifdef DENSE_CODE
+  if ((solveMode_%10)==0) {
+#endif
+    if (!regionSparse2->packedMode()) {
+      for (int j=0;j<numberRows_;j++) {
+	int iRow = pivotRow_[j+numberRows_];
+	double value = region[j];
+	region[j]=0.0;
+	if (fabs(value)>zeroTolerance_) {
+	  region2[iRow] = value;
+	  regionIndex[numberNonZero++]=iRow;
+	}
+      }
+    } else {
+      for (int j=0;j<numberRows_;j++) {
+	int iRow = pivotRow_[j+numberRows_];
+	double value = region[j];
+	region[j]=0.0;
+	if (fabs(value)>zeroTolerance_) {
+	  region2[numberNonZero] = value;
+	  regionIndex[numberNonZero++]=iRow;
+	}
+      }
+    }
+#ifdef DENSE_CODE
+  } else {
+    // lapack
+    if (!regionSparse2->packedMode()) {
+      for (int j=0;j<numberRows_;j++) {
+	double value = region[j];
+	region[j]=0.0;
+	if (fabs(value)>zeroTolerance_) {
+	  region2[j] = value;
+	  regionIndex[numberNonZero++]=j;
+	}
+      }
+    } else {
+      for (int j=0;j<numberRows_;j++) {
+	double value = region[j];
+	region[j]=0.0;
+	if (fabs(value)>zeroTolerance_) {
+	  region2[numberNonZero] = value;
+	  regionIndex[numberNonZero++]=j;
+	}
+      }
+    }
+  }
+#endif
+  regionSparse2->setNumElements(numberNonZero);
+  return 0;
+}
+// Default constructor
+CoinOtherFactorization::CoinOtherFactorization (  )
+   :  pivotTolerance_(1.0e-1),
+      zeroTolerance_(1.0e-13),
+#ifndef COIN_FAST_CODE
+      slackValue_(-1.0),
+#endif
+      relaxCheck_(1.0),
+      factorElements_(0),
+      numberRows_(0),
+      numberColumns_(0),
+      numberGoodU_(0),
+      maximumPivots_(200),
+      numberPivots_(0),
+      status_(-1),
+      solveMode_(0)
+{
+}
+// Copy constructor 
+CoinOtherFactorization::CoinOtherFactorization ( const CoinOtherFactorization &other)
+   :  pivotTolerance_(other.pivotTolerance_),
+  zeroTolerance_(other.zeroTolerance_),
+#ifndef COIN_FAST_CODE
+  slackValue_(other.slackValue_),
+#endif
+  relaxCheck_(other.relaxCheck_),
+  factorElements_(other.factorElements_),
+  numberRows_(other.numberRows_),
+  numberColumns_(other.numberColumns_),
+  numberGoodU_(other.numberGoodU_),
+  maximumPivots_(other.maximumPivots_),
+  numberPivots_(other.numberPivots_),
+      status_(other.status_),
+      solveMode_(other.solveMode_)
+{
+}
+// Destructor
+CoinOtherFactorization::~CoinOtherFactorization (  )
+{
+}
+// = copy
+CoinOtherFactorization & CoinOtherFactorization::operator = ( const CoinOtherFactorization & other )
+{
+  if (this != &other) {    
+    pivotTolerance_ = other.pivotTolerance_;
+    zeroTolerance_ = other.zeroTolerance_;
+#ifndef COIN_FAST_CODE
+    slackValue_ = other.slackValue_;
+#endif
+    relaxCheck_ = other.relaxCheck_;
+    factorElements_ = other.factorElements_;
+    numberRows_ = other.numberRows_;
+    numberColumns_ = other.numberColumns_;
+    numberGoodU_ = other.numberGoodU_;
+    maximumPivots_ = other.maximumPivots_;
+    numberPivots_ = other.numberPivots_;
+    status_ = other.status_;
+    solveMode_ = other.solveMode_;
+  }
+  return *this;
+}
+void CoinOtherFactorization::pivotTolerance (  double value )
+{
+  if (value>0.0&&value<=1.0) {
+    pivotTolerance_=value;
+  }
+}
+void CoinOtherFactorization::zeroTolerance (  double value )
+{
+  if (value>0.0&&value<1.0) {
+    zeroTolerance_=value;
+  }
+}
+#ifndef COIN_FAST_CODE
+void CoinOtherFactorization::slackValue (  double value )
+{
+  if (value>=0.0) {
+    slackValue_=1.0;
+  } else {
+    slackValue_=-1.0;
+  }
+}
+#endif
+void 
+CoinOtherFactorization::maximumPivots (  int value )
+{
+  if (value>maximumPivots_) {
+    delete [] pivotRow_;
+    pivotRow_ = new int[2*maximumRows_+value];
+  }
+  maximumPivots_ = value;
+}
+// Number of entries in each row
+int * 
+CoinOtherFactorization::numberInRow() const
+{ return reinterpret_cast<int *> (workArea_);}
+// Number of entries in each column
+int * 
+CoinOtherFactorization::numberInColumn() const
+{ return (reinterpret_cast<int *> (workArea_))+numberRows_;}
+// Returns array to put basis starts in
+CoinBigIndex * 
+CoinOtherFactorization::starts() const
+{ return reinterpret_cast<CoinBigIndex *> (pivotRow_);}
+// Returns array to put basis elements in
+CoinFactorizationDouble * 
+CoinOtherFactorization::elements() const
+{ return elements_;}
+// Returns pivot row 
+int * 
+CoinOtherFactorization::pivotRow() const
+{ return pivotRow_;}
+// Returns work area
+CoinFactorizationDouble * 
+CoinOtherFactorization::workArea() const
+{ return workArea_;}
+// Returns int work area
+int * 
+CoinOtherFactorization::intWorkArea() const
+{ return reinterpret_cast<int *> (workArea_);}
+// Returns permute back
+int * 
+CoinOtherFactorization::permuteBack() const
+{ return pivotRow_+numberRows_;}
+// Returns true if wants tableauColumn in replaceColumn
+bool
+CoinOtherFactorization::wantsTableauColumn() const
+{ return true;}
+/* Useful information for factorization
+   0 - iteration number
+   whereFrom is 0 for factorize and 1 for replaceColumn
+*/
+void 
+CoinOtherFactorization::setUsefulInformation(const int * ,int )
+{ }
diff --git a/cbits/coin/CoinDenseFactorization.hpp b/cbits/coin/CoinDenseFactorization.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinDenseFactorization.hpp
@@ -0,0 +1,416 @@
+/* $Id: CoinDenseFactorization.hpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+/* 
+   Authors
+   
+   John Forrest
+
+ */
+#ifndef CoinDenseFactorization_H
+#define CoinDenseFactorization_H
+
+#include <iostream>
+#include <string>
+#include <cassert>
+#include "CoinTypes.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinFactorization.hpp"
+class CoinPackedMatrix;
+/// Abstract base class which also has some scalars so can be used from Dense or Simp
+class CoinOtherFactorization {
+
+public:
+
+  /**@name Constructors and destructor and copy */
+  //@{
+  /// Default constructor
+  CoinOtherFactorization (  );
+  /// Copy constructor 
+  CoinOtherFactorization ( const CoinOtherFactorization &other);
+  
+  /// Destructor
+  virtual ~CoinOtherFactorization (  );
+  /// = copy
+  CoinOtherFactorization & operator = ( const CoinOtherFactorization & other );
+ 
+  /// Clone
+  virtual CoinOtherFactorization * clone() const = 0;
+  //@}
+
+  /**@name general stuff such as status */
+  //@{ 
+  /// Returns status
+  inline int status (  ) const {
+    return status_;
+  }
+  /// Sets status
+  inline void setStatus (  int value)
+  {  status_=value;  }
+  /// Returns number of pivots since factorization
+  inline int pivots (  ) const {
+    return numberPivots_;
+  }
+  /// Sets number of pivots since factorization
+  inline void setPivots (  int value ) 
+  { numberPivots_=value; }
+  /// Set number of Rows after factorization
+  inline void setNumberRows(int value)
+  { numberRows_ = value; }
+  /// Number of Rows after factorization
+  inline int numberRows (  ) const {
+    return numberRows_;
+  }
+  /// Total number of columns in factorization
+  inline int numberColumns (  ) const {
+    return numberColumns_;
+  }
+  /// Number of good columns in factorization
+  inline int numberGoodColumns (  ) const {
+    return numberGoodU_;
+  }
+  /// Allows change of pivot accuracy check 1.0 == none >1.0 relaxed
+  inline void relaxAccuracyCheck(double value)
+  { relaxCheck_ = value;}
+  inline double getAccuracyCheck() const
+  { return relaxCheck_;}
+  /// Maximum number of pivots between factorizations
+  inline int maximumPivots (  ) const {
+    return maximumPivots_ ;
+  }
+  /// Set maximum pivots
+  virtual void maximumPivots (  int value );
+
+  /// Pivot tolerance
+  inline double pivotTolerance (  ) const {
+    return pivotTolerance_ ;
+  }
+  void pivotTolerance (  double value );
+  /// Zero tolerance
+  inline double zeroTolerance (  ) const {
+    return zeroTolerance_ ;
+  }
+  void zeroTolerance (  double value );
+#ifndef COIN_FAST_CODE
+  /// Whether slack value is +1 or -1
+  inline double slackValue (  ) const {
+    return slackValue_ ;
+  }
+  void slackValue (  double value );
+#endif
+  /// Returns array to put basis elements in
+  virtual CoinFactorizationDouble * elements() const;
+  /// Returns pivot row 
+  virtual int * pivotRow() const;
+  /// Returns work area
+  virtual CoinFactorizationDouble * workArea() const;
+  /// Returns int work area
+  virtual int * intWorkArea() const;
+  /// Number of entries in each row
+  virtual int * numberInRow() const;
+  /// Number of entries in each column
+  virtual int * numberInColumn() const;
+  /// Returns array to put basis starts in
+  virtual CoinBigIndex * starts() const;
+  /// Returns permute back
+  virtual int * permuteBack() const;
+  /** Get solve mode e.g. 0 C++ code, 1 Lapack, 2 choose
+      If 4 set then values pass
+      if 8 set then has iterated
+  */
+  inline int solveMode() const
+  { return solveMode_ ;}
+  /** Set solve mode e.g. 0 C++ code, 1 Lapack, 2 choose
+      If 4 set then values pass
+      if 8 set then has iterated
+  */
+  inline void setSolveMode(int value)
+  { solveMode_ = value;}
+  /// Returns true if wants tableauColumn in replaceColumn
+  virtual bool wantsTableauColumn() const;
+  /** Useful information for factorization
+      0 - iteration number
+      whereFrom is 0 for factorize and 1 for replaceColumn
+  */
+  virtual void setUsefulInformation(const int * info,int whereFrom);
+  /// Get rid of all memory
+  virtual void clearArrays() {}
+  //@}
+  /**@name virtual general stuff such as permutation */
+  //@{ 
+  /// Returns array to put basis indices in
+  virtual int * indices() const  = 0;
+  /// Returns permute in
+  virtual int * permute() const = 0;
+  /// Total number of elements in factorization
+  virtual int numberElements (  ) const = 0;
+  //@}
+  /**@name Do factorization - public */
+  //@{
+  /// Gets space for a factorization
+  virtual void getAreas ( int numberRows,
+		  int numberColumns,
+		  CoinBigIndex maximumL,
+		  CoinBigIndex maximumU ) = 0;
+  
+  /// PreProcesses column ordered copy of basis
+  virtual void preProcess ( ) = 0;
+  /** Does most of factorization returning status
+      0 - OK
+      -99 - needs more memory
+      -1 - singular - use numberGoodColumns and redo
+  */
+  virtual int factor ( ) = 0;
+  /// Does post processing on valid factorization - putting variables on correct rows
+  virtual void postProcess(const int * sequence, int * pivotVariable) = 0;
+  /// Makes a non-singular basis by replacing variables
+  virtual void makeNonSingular(int * sequence, int numberColumns) = 0;
+  //@}
+
+  /**@name rank one updates which do exist */
+  //@{
+
+  /** Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+      If checkBeforeModifying is true will do all accuracy checks
+      before modifying factorization.  Whether to set this depends on
+      speed considerations.  You could just do this on first iteration
+      after factorization and thereafter re-factorize
+   partial update already in U */
+  virtual int replaceColumn ( CoinIndexedVector * regionSparse,
+		      int pivotRow,
+		      double pivotCheck ,
+			      bool checkBeforeModifying=false,
+			      double acceptablePivot=1.0e-8)=0;
+  //@}
+
+  /**@name various uses of factorization (return code number elements) 
+   which user may want to know about */
+  //@{
+  /** Updates one column (FTRAN) from regionSparse2
+      Tries to do FT update
+      number returned is negative if no room
+      regionSparse starts as zero and is zero at end.
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+  virtual int updateColumnFT ( CoinIndexedVector * regionSparse,
+			       CoinIndexedVector * regionSparse2,
+			       bool noPermute=false) = 0;
+  /** This version has same effect as above with FTUpdate==false
+      so number returned is always >=0 */
+  virtual int updateColumn ( CoinIndexedVector * regionSparse,
+		     CoinIndexedVector * regionSparse2,
+		     bool noPermute=false) const = 0;
+    /// does FTRAN on two columns
+    virtual int updateTwoColumnsFT(CoinIndexedVector * regionSparse1,
+			   CoinIndexedVector * regionSparse2,
+			   CoinIndexedVector * regionSparse3,
+			   bool noPermute=false) = 0;
+  /** Updates one column (BTRAN) from regionSparse2
+      regionSparse starts as zero and is zero at end 
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+  virtual int updateColumnTranspose ( CoinIndexedVector * regionSparse,
+			      CoinIndexedVector * regionSparse2) const = 0;
+  //@}
+
+////////////////// data //////////////////
+protected:
+
+  /**@name data */
+  //@{
+  /// Pivot tolerance
+  double pivotTolerance_;
+  /// Zero tolerance
+  double zeroTolerance_;
+#ifndef COIN_FAST_CODE
+  /// Whether slack value is  +1 or -1
+  double slackValue_;
+#else
+#ifndef slackValue_
+#define slackValue_ -1.0
+#endif
+#endif
+  /// Relax check on accuracy in replaceColumn
+  double relaxCheck_;
+  /// Number of elements after factorization
+  CoinBigIndex factorElements_;
+  /// Number of Rows in factorization
+  int numberRows_;
+  /// Number of Columns in factorization
+  int numberColumns_;
+  /// Number factorized in U (not row singletons)
+  int numberGoodU_;
+  /// Maximum number of pivots before factorization
+  int maximumPivots_;
+  /// Number pivots since last factorization
+  int numberPivots_;
+  /// Status of factorization
+  int status_;
+  /// Maximum rows ever (i.e. use to copy arrays etc)
+  int maximumRows_;
+  /// Maximum length of iterating area
+  CoinBigIndex maximumSpace_;
+  /// Pivot row 
+  int * pivotRow_;
+  /** Elements of factorization and updates
+      length is maxR*maxR+maxSpace
+      will always be long enough so can have nR*nR ints in maxSpace 
+  */
+  CoinFactorizationDouble * elements_;
+  /// Work area of numberRows_ 
+  CoinFactorizationDouble * workArea_;
+  /** Solve mode e.g. 0 C++ code, 1 Lapack, 2 choose
+      If 4 set then values pass
+      if 8 set then has iterated
+  */
+  int solveMode_;
+  //@}
+};
+/** This deals with Factorization and Updates
+    This is a simple dense version so other people can write a better one
+
+    I am assuming that 32 bits is enough for number of rows or columns, but CoinBigIndex
+    may be redefined to get 64 bits.
+ */
+
+
+
+class CoinDenseFactorization : public CoinOtherFactorization {
+   friend void CoinDenseFactorizationUnitTest( const std::string & mpsDir );
+
+public:
+
+  /**@name Constructors and destructor and copy */
+  //@{
+  /// Default constructor
+  CoinDenseFactorization (  );
+  /// Copy constructor 
+  CoinDenseFactorization ( const CoinDenseFactorization &other);
+  
+  /// Destructor
+  virtual ~CoinDenseFactorization (  );
+  /// = copy
+  CoinDenseFactorization & operator = ( const CoinDenseFactorization & other );
+  /// Clone
+  virtual CoinOtherFactorization * clone() const ;
+  //@}
+
+  /**@name Do factorization - public */
+  //@{
+  /// Gets space for a factorization
+  virtual void getAreas ( int numberRows,
+		  int numberColumns,
+		  CoinBigIndex maximumL,
+		  CoinBigIndex maximumU );
+  
+  /// PreProcesses column ordered copy of basis
+  virtual void preProcess ( );
+  /** Does most of factorization returning status
+      0 - OK
+      -99 - needs more memory
+      -1 - singular - use numberGoodColumns and redo
+  */
+  virtual int factor ( );
+  /// Does post processing on valid factorization - putting variables on correct rows
+  virtual void postProcess(const int * sequence, int * pivotVariable);
+  /// Makes a non-singular basis by replacing variables
+  virtual void makeNonSingular(int * sequence, int numberColumns);
+  //@}
+
+  /**@name general stuff such as number of elements */
+  //@{ 
+  /// Total number of elements in factorization
+  virtual inline int numberElements (  ) const {
+    return numberRows_*(numberColumns_+numberPivots_);
+  }
+  /// Returns maximum absolute value in factorization
+  double maximumCoefficient() const;
+  //@}
+
+  /**@name rank one updates which do exist */
+  //@{
+
+  /** Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+      If checkBeforeModifying is true will do all accuracy checks
+      before modifying factorization.  Whether to set this depends on
+      speed considerations.  You could just do this on first iteration
+      after factorization and thereafter re-factorize
+   partial update already in U */
+  virtual int replaceColumn ( CoinIndexedVector * regionSparse,
+		      int pivotRow,
+		      double pivotCheck ,
+			      bool checkBeforeModifying=false,
+			      double acceptablePivot=1.0e-8);
+  //@}
+
+  /**@name various uses of factorization (return code number elements) 
+   which user may want to know about */
+  //@{
+  /** Updates one column (FTRAN) from regionSparse2
+      Tries to do FT update
+      number returned is negative if no room
+      regionSparse starts as zero and is zero at end.
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+  virtual inline int updateColumnFT ( CoinIndexedVector * regionSparse,
+				      CoinIndexedVector * regionSparse2,
+				      bool = false)
+  { return updateColumn(regionSparse,regionSparse2);}
+  /** This version has same effect as above with FTUpdate==false
+      so number returned is always >=0 */
+  virtual int updateColumn ( CoinIndexedVector * regionSparse,
+		     CoinIndexedVector * regionSparse2,
+		     bool noPermute=false) const;
+    /// does FTRAN on two columns
+    virtual int updateTwoColumnsFT(CoinIndexedVector * regionSparse1,
+			   CoinIndexedVector * regionSparse2,
+			   CoinIndexedVector * regionSparse3,
+			   bool noPermute=false);
+  /** Updates one column (BTRAN) from regionSparse2
+      regionSparse starts as zero and is zero at end 
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+  virtual int updateColumnTranspose ( CoinIndexedVector * regionSparse,
+			      CoinIndexedVector * regionSparse2) const;
+  //@}
+  /// *** Below this user may not want to know about
+
+  /**@name various uses of factorization
+   which user may not want to know about (left over from my LP code) */
+  //@{
+  /// Get rid of all memory
+  inline void clearArrays()
+  { gutsOfDestructor();}
+  /// Returns array to put basis indices in
+  virtual inline int * indices() const
+  { return reinterpret_cast<int *> (elements_+numberRows_*numberRows_);}
+  /// Returns permute in
+  virtual inline int * permute() const
+  { return NULL;/*pivotRow_*/;}
+  //@}
+
+  /// The real work of desstructor 
+  void gutsOfDestructor();
+  /// The real work of constructor
+  void gutsOfInitialize();
+  /// The real work of copy
+  void gutsOfCopy(const CoinDenseFactorization &other);
+
+  //@}
+protected:
+  /** Returns accuracy status of replaceColumn
+      returns 0=OK, 1=Probably OK, 2=singular */
+  int checkPivot(double saveFromU, double oldPivot) const;
+////////////////// data //////////////////
+protected:
+
+  /**@name data */
+  //@{
+  //@}
+};
+#endif
diff --git a/cbits/coin/CoinDenseVector.cpp b/cbits/coin/CoinDenseVector.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinDenseVector.cpp
@@ -0,0 +1,209 @@
+/* $Id: CoinDenseVector.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Resized.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+#include "CoinDenseVector.hpp"
+#include "CoinHelperFunctions.hpp"
+
+//#############################################################################
+
+template <typename T> void
+CoinDenseVector<T>::clear()
+{
+   memset(elements_, 0, nElements_*sizeof(T));
+}
+
+//#############################################################################
+
+template <typename T> CoinDenseVector<T> &
+CoinDenseVector<T>::operator=(const CoinDenseVector<T> & rhs)
+{
+   if (this != &rhs) {
+     setVector(rhs.getNumElements(), rhs.getElements());
+   }
+   return *this;
+}
+
+//#############################################################################
+
+template <typename T> void
+CoinDenseVector<T>::setVector(int size, const T * elems)
+{
+   resize(size);
+   CoinMemcpyN( elems,size,elements_);
+}
+
+//#############################################################################
+
+template <typename T> void
+CoinDenseVector<T>::setConstant(int size, T value)
+{
+   resize(size);
+   for(int i=0; i<size; i++)
+     elements_[i] = value;
+}
+
+//#############################################################################
+
+template <typename T> void
+CoinDenseVector<T>::resize(int newsize, T value)
+{
+  if (newsize != nElements_){
+    assert(newsize > 0);
+    T *newarray = new T[newsize];
+    int cpysize = CoinMin(newsize, nElements_);
+    CoinMemcpyN( elements_,cpysize,newarray);
+    delete[] elements_;
+    elements_ = newarray;
+    nElements_ = newsize;
+    for(int i=cpysize; i<newsize; i++)
+      elements_[i] = value;
+  }
+}
+
+//#############################################################################
+
+template <typename T> void
+CoinDenseVector<T>::setElement(int index, T element)
+{
+  assert(index >= 0 && index < nElements_);
+   elements_[index] = element;
+}
+
+//#############################################################################
+
+template <typename T> void
+CoinDenseVector<T>::append(const CoinDenseVector<T> & caboose)
+{
+   const int s = nElements_;
+   const int cs = caboose.getNumElements();
+   int newsize = s + cs;
+   resize(newsize);
+   const T * celem = caboose.getElements();
+   CoinDisjointCopyN(celem, cs, elements_ + s);
+}
+
+//#############################################################################
+
+template <typename T> void
+CoinDenseVector<T>::operator+=(T value) 
+{
+  for(int i=0; i<nElements_; i++)
+    elements_[i] += value;
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T> void
+CoinDenseVector<T>::operator-=(T value) 
+{
+  for(int i=0; i<nElements_; i++)
+    elements_[i] -= value;
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T> void
+CoinDenseVector<T>::operator*=(T value) 
+{
+  for(int i=0; i<nElements_; i++)
+    elements_[i] *= value;
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T> void
+CoinDenseVector<T>::operator/=(T value) 
+{
+  for(int i=0; i<nElements_; i++)
+    elements_[i] /= value;
+}
+
+//#############################################################################
+
+template <typename T> CoinDenseVector<T>::CoinDenseVector():
+   nElements_(0),
+   elements_(NULL)
+{}
+  
+//#############################################################################
+
+template <typename T> 
+CoinDenseVector<T>::CoinDenseVector(int size, const T * elems):
+   nElements_(0),
+   elements_(NULL)
+{
+  gutsOfSetVector(size, elems);
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T> CoinDenseVector<T>::CoinDenseVector(int size, T value):
+   nElements_(0),
+   elements_(NULL)
+{
+  gutsOfSetConstant(size, value);
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T> 
+CoinDenseVector<T>::CoinDenseVector(const CoinDenseVector<T> & rhs):
+   nElements_(0),
+   elements_(NULL)
+{
+     setVector(rhs.getNumElements(), rhs.getElements());
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T> CoinDenseVector<T>::~CoinDenseVector ()
+{
+   delete [] elements_;
+}
+
+//#############################################################################
+
+template <typename T> void
+CoinDenseVector<T>::gutsOfSetVector(int size, const T * elems)
+{
+   if ( size != 0 ) {
+      resize(size);
+      nElements_ = size;
+      CoinDisjointCopyN(elems, size, elements_);
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+template <typename T> void
+CoinDenseVector<T>::gutsOfSetConstant(int size, T value)
+{
+   if ( size != 0 ) {
+      resize(size);
+      nElements_ = size;
+      CoinFillN(elements_, size, value);
+   }
+}
+
+//#############################################################################
+/** Access the i'th element of the dense vector.  */
+template <typename T> T &
+CoinDenseVector<T>::operator[](int index) const
+{
+  assert(index >= 0 && index < nElements_);
+  T *where = elements_ + index;
+  return *where;
+}
+//#############################################################################
+
+// template class CoinDenseVector<int>; This works but causes warning messages
+template class CoinDenseVector<float>;
+template class CoinDenseVector<double>;
diff --git a/cbits/coin/CoinDenseVector.hpp b/cbits/coin/CoinDenseVector.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinDenseVector.hpp
@@ -0,0 +1,383 @@
+/* $Id: CoinDenseVector.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinDenseVector_H
+#define CoinDenseVector_H
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include "CoinHelperFunctions.hpp"
+
+//#############################################################################
+/** A function that tests the methods in the CoinDenseVector class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+    template <typename T> void
+    CoinDenseVectorUnitTest(T dummy);
+
+//#############################################################################
+/** Dense Vector
+
+Stores a dense (or expanded) vector of floating point values.
+Type of vector elements is controlled by templating.
+(Some working quantities such as accumulated sums
+are explicitly declared of type double). This allows the 
+components of the vector integer, single or double precision.
+
+Here is a sample usage:
+@verbatim
+    const int ne = 4;
+    double el[ne] = { 10., 40., 1., 50. }
+
+    // Create vector and set its value
+    CoinDenseVector<double> r(ne,el);
+
+    // access each element
+    assert( r.getElements()[0]==10. );
+    assert( r.getElements()[1]==40. );
+    assert( r.getElements()[2]== 1. );
+    assert( r.getElements()[3]==50. );
+
+    // Test for equality
+    CoinDenseVector<double> r1;
+    r1=r;
+
+    // Add dense vectors.
+    // Similarly for subtraction, multiplication,
+    // and division.
+    CoinDenseVector<double> add = r + r1;
+    assert( add[0] == 10.+10. );
+    assert( add[1] == 40.+40. );
+    assert( add[2] ==  1.+ 1. );
+    assert( add[3] == 50.+50. );
+
+    assert( r.sum() == 10.+40.+1.+50. );
+@endverbatim
+*/
+template <typename T> class CoinDenseVector {
+private:
+   /**@name Private member data */
+   //@{
+   /// Size of element vector
+   int nElements_;
+   ///Vector elements
+   T * elements_;
+   //@}
+  
+public:
+   /**@name Get methods. */
+   //@{
+   /// Get the size
+   inline int getNumElements() const { return nElements_; }
+   inline int size() const { return nElements_; }
+   /// Get element values
+   inline const T * getElements() const { return elements_; }
+   /// Get element values
+   inline T * getElements() { return elements_; }
+   //@}
+ 
+   //-------------------------------------------------------------------
+   // Set indices and elements
+   //------------------------------------------------------------------- 
+   /**@name Set methods */
+   //@{
+   /// Reset the vector (i.e. set all elemenets to zero)
+   void clear();
+   /** Assignment operator */
+   CoinDenseVector & operator=(const CoinDenseVector &);
+   /** Member of array operator */
+   T & operator[](int index) const;
+
+   /** Set vector size, and elements.
+       Size is the length of the elements vector.
+       The element vector is copied into this class instance's
+       member data. */ 
+   void setVector(int size, const T * elems);
+
+  
+   /** Elements set to have the same scalar value */
+   void setConstant(int size, T elems);
+  
+
+   /** Set an existing element in the dense vector
+       The first argument is the "index" into the elements() array
+   */
+   void setElement(int index, T element);
+   /** Resize the dense vector to be the first newSize elements.
+       If length is decreased, vector is truncated. If increased
+       new entries, set to new default element */
+   void resize(int newSize, T fill=T()); 
+
+   /** Append a dense vector to this dense vector */
+   void append(const CoinDenseVector &);
+   //@}
+
+   /**@name norms, sum and scale */
+   //@{
+   /// 1-norm of vector
+   inline T oneNorm() const {
+     T norm = 0;
+     for (int i=0; i<nElements_; i++)
+       norm += CoinAbs(elements_[i]);
+     return norm;
+   }
+   /// 2-norm of vector
+   inline double twoNorm() const {
+     double norm = 0.;
+     for (int i=0; i<nElements_; i++)
+       norm += elements_[i] * elements_[i];
+     // std namespace removed because it was causing a compile
+     // problem with Microsoft Visual C++
+     return /*std::*/sqrt(norm);
+   }
+   /// infinity-norm of vector
+   inline T infNorm() const {
+     T norm = 0;
+     for (int i=0; i<nElements_; i++)
+       norm = CoinMax(norm, CoinAbs(elements_[i]));
+     return norm;
+   }
+   /// sum of vector elements
+   inline T sum() const {
+     T sume = 0;
+     for (int i=0; i<nElements_; i++)
+       sume += elements_[i];
+     return sume;
+   }
+   /// scale vector elements
+   inline void scale(T factor) {
+     for (int i=0; i<nElements_; i++)
+       elements_[i] *= factor;
+     return;
+   }
+   //@}
+
+   /**@name Arithmetic operators. */
+   //@{
+   /// add <code>value</code> to every entry
+   void operator+=(T value);
+   /// subtract <code>value</code> from every entry
+   void operator-=(T value);
+   /// multiply every entry by <code>value</code>
+   void operator*=(T value);
+   /// divide every entry by <code>value</code>
+   void operator/=(T value);
+   //@}
+
+   /**@name Constructors and destructors */
+   //@{
+   /** Default constructor */
+   CoinDenseVector();
+   /** Alternate Constructors - set elements to vector of Ts */
+   CoinDenseVector(int size, const T * elems);
+   /** Alternate Constructors - set elements to same scalar value */
+   CoinDenseVector(int size, T element=T());
+   /** Copy constructors */
+   CoinDenseVector(const CoinDenseVector &);
+
+    /** Destructor */
+   ~CoinDenseVector ();
+   //@}
+    
+private:
+   /**@name Private methods */
+   //@{  
+   /// Copy internal data
+   void gutsOfSetVector(int size, const T * elems);
+   /// Set all elements to a given value
+   void gutsOfSetConstant(int size, T value);
+   //@}
+};
+
+//#############################################################################
+
+/**@name Arithmetic operators on dense vectors.
+
+   <strong>NOTE</strong>: Because these methods return an object (they can't
+   return a reference, though they could return a pointer...) they are
+   <em>very</em> inefficient...
+ */
+//@{
+/// Return the sum of two dense vectors
+template <typename T> inline
+CoinDenseVector<T> operator+(const CoinDenseVector<T>& op1,
+			     const CoinDenseVector<T>& op2){
+  assert(op1.size() == op2.size());
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  const T *elements2 = op2.getElements();
+  T *elements3 = op3.getElements();
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] + elements2[i];
+  return op3;
+}
+
+/// Return the difference of two dense vectors
+template <typename T> inline
+CoinDenseVector<T> operator-(const CoinDenseVector<T>& op1,
+			     const CoinDenseVector<T>& op2){
+  assert(op1.size() == op2.size());
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  const T *elements2 = op2.getElements();
+  T *elements3 = op3.getElements();
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] - elements2[i];
+  return op3;
+}
+
+
+/// Return the element-wise product of two dense vectors
+template <typename T> inline
+CoinDenseVector<T> operator*(const CoinDenseVector<T>& op1,
+			  const CoinDenseVector<T>& op2){
+  assert(op1.size() == op2.size());
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  const T *elements2 = op2.getElements();
+  T *elements3 = op3.getElements();
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] * elements2[i];
+  return op3;
+}
+
+/// Return the element-wise ratio of two dense vectors
+template <typename T> inline
+CoinDenseVector<T> operator/(const CoinDenseVector<T>& op1,
+			  const CoinDenseVector<T>& op2){
+  assert(op1.size() == op2.size());
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  const T *elements2 = op2.getElements();
+  T *elements3 = op3.getElements();
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] / elements2[i];
+  return op3;
+}
+//@}
+
+/**@name Arithmetic operators on dense vector and a constant. 
+   These functions create a dense vector as a result. That dense vector will
+   have the same indices as <code>op1</code> and the specified operation is
+   done entry-wise with the given value. */
+//@{
+/// Return the sum of a dense vector and a constant
+template <typename T> inline
+CoinDenseVector<T> operator+(const CoinDenseVector<T>& op1, T value){
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  T *elements3 = op3.getElements();
+  double dvalue = value;
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] + dvalue;
+  return op3;
+}
+
+/// Return the difference of a dense vector and a constant
+template <typename T> inline
+CoinDenseVector<T> operator-(const CoinDenseVector<T>& op1, T value){
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  T *elements3 = op3.getElements();
+  double dvalue = value;
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] - dvalue;
+  return op3;
+}
+
+/// Return the element-wise product of a dense vector and a constant
+template <typename T> inline
+CoinDenseVector<T> operator*(const CoinDenseVector<T>& op1, T value){
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  T *elements3 = op3.getElements();
+  double dvalue = value;
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] * dvalue;
+  return op3;
+}
+
+/// Return the element-wise ratio of a dense vector and a constant
+template <typename T> inline
+CoinDenseVector<T> operator/(const CoinDenseVector<T>& op1, T value){
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  T *elements3 = op3.getElements();
+  double dvalue = value;
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] / dvalue;
+  return op3;
+}
+
+/// Return the sum of a constant and a dense vector
+template <typename T> inline
+CoinDenseVector<T> operator+(T value, const CoinDenseVector<T>& op1){
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  T *elements3 = op3.getElements();
+  double dvalue = value;
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] + dvalue;
+  return op3;
+}
+
+/// Return the difference of a constant and a dense vector
+template <typename T> inline
+CoinDenseVector<T> operator-(T value, const CoinDenseVector<T>& op1){
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  T *elements3 = op3.getElements();
+  double dvalue = value;
+  for(int i=0; i<size; i++)
+    elements3[i] = dvalue - elements1[i];
+  return op3;
+}
+
+/// Return the element-wise product of a constant and a dense vector
+template <typename T> inline
+CoinDenseVector<T> operator*(T value, const CoinDenseVector<T>& op1){
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  T *elements3 = op3.getElements();
+  double dvalue = value;
+  for(int i=0; i<size; i++)
+    elements3[i] = elements1[i] * dvalue;
+  return op3;
+}
+
+/// Return the element-wise ratio of a a constant and dense vector
+template <typename T> inline
+CoinDenseVector<T> operator/(T value, const CoinDenseVector<T>& op1){
+  int size = op1.size();
+  CoinDenseVector<T> op3(size);
+  const T *elements1 = op1.getElements();
+  T *elements3 = op3.getElements();
+  double dvalue = value;
+  for(int i=0; i<size; i++)
+    elements3[i] = dvalue / elements1[i];
+  return op3;
+}
+//@}
+
+#endif
diff --git a/cbits/coin/CoinDistance.hpp b/cbits/coin/CoinDistance.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinDistance.hpp
@@ -0,0 +1,48 @@
+/* $Id: CoinDistance.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinDistance_H
+#define CoinDistance_H
+
+#include <iterator>
+
+//-------------------------------------------------------------------
+//
+// Attempt to provide an std::distance function
+// that will work on multiple platforms
+//
+//-------------------------------------------------------------------
+
+/** CoinDistance
+
+This is the Coin implementation of the std::function that is 
+designed to work on multiple platforms.
+*/
+template <class ForwardIterator, class Distance>
+void coinDistance(ForwardIterator first, ForwardIterator last,
+		  Distance& n)
+{
+#if defined(__SUNPRO_CC)
+   n = 0;
+   std::distance(first,last,n);
+#else
+   n = std::distance(first,last);
+#endif
+}
+
+template <class ForwardIterator>
+size_t coinDistance(ForwardIterator first, ForwardIterator last)
+{
+   size_t retVal;
+#if defined(__SUNPRO_CC)
+   retVal = 0;
+   std::distance(first,last,retVal);
+#else
+   retVal = std::distance(first,last);
+#endif
+  return retVal;
+}
+
+#endif
diff --git a/cbits/coin/CoinError.cpp b/cbits/coin/CoinError.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinError.cpp
@@ -0,0 +1,20 @@
+/* $Id: CoinError.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinError.hpp"
+
+bool CoinError::printErrors_ = false;
+
+/** A function to block the popup windows that windows creates when the code
+    crashes */
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+void WindowsErrorPopupBlocker()
+{
+  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+}
+#else
+void WindowsErrorPopupBlocker() {}
+#endif
diff --git a/cbits/coin/CoinError.hpp b/cbits/coin/CoinError.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinError.hpp
@@ -0,0 +1,257 @@
+/* $Id: CoinError.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinError_H
+#define CoinError_H
+
+#include <string>
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+#include "CoinUtilsConfig.h"
+#include "CoinPragma.hpp"
+
+/** A function to block the popup windows that windows creates when the code
+    crashes */
+void WindowsErrorPopupBlocker();
+
+//-------------------------------------------------------------------
+//
+// Error class used to throw exceptions
+//
+// Errors contain:
+//
+//-------------------------------------------------------------------
+
+/** Error Class thrown by an exception
+
+This class is used when exceptions are thrown.
+It contains:
+  <ul>
+  <li>message text
+  <li>name of method throwing exception
+  <li>name of class throwing exception or hint
+  <li>name of file if assert
+  <li>line number
+  </ul>
+  For asserts class=> optional hint
+*/
+class CoinError  {
+    friend void CoinErrorUnitTest();
+
+private:
+    CoinError()
+      :
+      message_(),
+      method_(),
+      class_(),
+      file_(),
+      lineNumber_()
+    {
+      // nothing to do here
+    }
+
+public:
+    
+  //-------------------------------------------------------------------
+  // Get methods
+  //-------------------------------------------------------------------   
+  /**@name Get error attributes */
+  //@{
+    /// get message text
+    inline const std::string & message() const 
+    { return message_; }
+    /// get name of method instantiating error
+    inline const std::string & methodName() const 
+    { return method_;  }
+    /// get name of class instantiating error (or hint for assert)
+    inline const std::string & className() const 
+    { return class_;   }
+    /// get name of file for assert
+    inline const std::string & fileName() const 
+    { return file_;  }
+    /// get line number of assert (-1 if not assert)
+    inline int lineNumber() const 
+    { return lineNumber_;   }
+    /// Just print (for asserts)
+    inline void print(bool doPrint = true) const
+    {
+      if (! doPrint)
+        return;
+      if (lineNumber_<0) {
+        std::cout<<message_<<" in "<<class_<<"::"<<method_<<std::endl;
+      } else {
+        std::cout<<file_<<":"<<lineNumber_<<" method "<<method_
+                 <<" : assertion \'"<<message_<<"\' failed."<<std::endl;
+        if(class_!="")
+          std::cout<<"Possible reason: "<<class_<<std::endl;
+      }
+    }
+  //@}
+  
+    
+  /**@name Constructors and destructors */
+  //@{
+    /// Alternate Constructor 
+    CoinError ( 
+      std::string message__, 
+      std::string methodName__, 
+      std::string className__,
+      std::string fileName_ = std::string(),
+      int line = -1)
+      :
+      message_(message__),
+      method_(methodName__),
+      class_(className__),
+      file_(fileName_),
+      lineNumber_(line)
+    {
+      print(printErrors_);
+    }
+
+    /// Copy constructor 
+    CoinError (const CoinError & source)
+      :
+      message_(source.message_),
+      method_(source.method_),
+      class_(source.class_),
+      file_(source.file_),
+      lineNumber_(source.lineNumber_)
+    {
+      // nothing to do here
+    }
+
+    /// Assignment operator 
+    CoinError & operator=(const CoinError& rhs)
+    {
+      if (this != &rhs) {
+	message_=rhs.message_;
+	method_=rhs.method_;
+	class_=rhs.class_;
+	file_=rhs.file_;
+	lineNumber_ = rhs.lineNumber_;
+      }
+      return *this;
+    }
+
+    /// Destructor 
+    virtual ~CoinError ()
+    {
+      // nothing to do here
+    }
+  //@}
+    
+private:
+    
+  /**@name Private member data */
+  //@{
+    /// message test
+    std::string message_;
+    /// method name
+    std::string method_;
+    /// class name or hint
+    std::string class_;
+    /// file name
+    std::string file_;
+    /// Line number
+    int lineNumber_;
+  //@}
+
+public:
+  /// Whether to print every error
+  static bool printErrors_;
+};
+
+#ifndef __STRING
+#define __STRING(x)	#x
+#endif
+
+#ifndef __GNUC_PREREQ
+# define __GNUC_PREREQ(maj, min) (0)
+#endif 
+
+#ifndef COIN_ASSERT
+#   define CoinAssertDebug(expression) assert(expression)
+#   define CoinAssertDebugHint(expression,hint) assert(expression)
+#   define CoinAssert(expression) assert(expression)
+#   define CoinAssertHint(expression,hint) assert(expression)
+#else
+#   ifdef NDEBUG
+#      define CoinAssertDebug(expression)		{}
+#      define CoinAssertDebugHint(expression,hint)	{}
+#   else
+#      if defined(__GNUC__) && __GNUC_PREREQ(2, 6)
+#         define CoinAssertDebug(expression) { 				   \
+             if (!(expression)) {					   \
+                throw CoinError(__STRING(expression), __PRETTY_FUNCTION__, \
+                                "", __FILE__, __LINE__);		   \
+             }								   \
+          }
+#         define CoinAssertDebugHint(expression,hint) {			   \
+             if (!(expression)) {					   \
+                throw CoinError(__STRING(expression), __PRETTY_FUNCTION__, \
+                                hint, __FILE__,__LINE__);		   \
+             }								   \
+          }
+#      else
+#         define CoinAssertDebug(expression) {				   \
+             if (!(expression)) {					   \
+                throw CoinError(__STRING(expression), "",		   \
+                                "", __FILE__,__LINE__);			   \
+             }								   \
+          }
+#         define CoinAssertDebugHint(expression,hint) {			   \
+             if (!(expression)) {					   \
+                throw CoinError(__STRING(expression), "",		   \
+                                hint, __FILE__,__LINE__);		   \
+             }								   \
+          }
+#      endif
+#   endif
+#   if defined(__GNUC__) && __GNUC_PREREQ(2, 6)
+#      define CoinAssert(expression) { 					\
+          if (!(expression)) {						\
+             throw CoinError(__STRING(expression), __PRETTY_FUNCTION__, \
+                             "", __FILE__, __LINE__);			\
+          }								\
+       }
+#      define CoinAssertHint(expression,hint) {				\
+          if (!(expression)) {						\
+             throw CoinError(__STRING(expression), __PRETTY_FUNCTION__, \
+                             hint, __FILE__,__LINE__);			\
+          }								\
+       }
+#   else
+#      define CoinAssert(expression) {					\
+          if (!(expression)) {						\
+             throw CoinError(__STRING(expression), "",			\
+                             "", __FILE__,__LINE__);			\
+          }								\
+       }
+#      define CoinAssertHint(expression,hint) {				\
+          if (!(expression)) {						\
+             throw CoinError(__STRING(expression), "",			\
+                             hint, __FILE__,__LINE__);			\
+          }								\
+       }
+#   endif
+#endif
+
+
+//#############################################################################
+/** A function that tests the methods in the CoinError class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void
+CoinErrorUnitTest();
+
+#ifdef __LINE__
+#define CoinErrorFL(x, y, z) CoinError((x), (y), (z), __FILE__, __LINE__)
+#endif
+
+#endif
diff --git a/cbits/coin/CoinFactorization.hpp b/cbits/coin/CoinFactorization.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFactorization.hpp
@@ -0,0 +1,1918 @@
+/* $Id: CoinFactorization.hpp 1590 2013-04-10 16:48:33Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/* 
+   Authors
+   
+   John Forrest
+
+ */
+#ifndef CoinFactorization_H
+#define CoinFactorization_H
+//#define COIN_ONE_ETA_COPY 100
+
+#include <iostream>
+#include <string>
+#include <cassert>
+#include <cstdio>
+#include <cmath>
+#include "CoinTypes.hpp"
+#include "CoinIndexedVector.hpp"
+
+class CoinPackedMatrix;
+/** This deals with Factorization and Updates
+
+    This class started with a parallel simplex code I was writing in the
+    mid 90's.  The need for parallelism led to many complications and
+    I have simplified as much as I could to get back to this.
+
+    I was aiming at problems where I might get speed-up so I was looking at dense
+    problems or ones with structure.  This led to permuting input and output
+    vectors and to increasing the number of rows each rank-one update.  This is 
+    still in as a minor overhead.
+
+    I have also put in handling for hyper-sparsity.  I have taken out
+    all outer loop unrolling, dense matrix handling and most of the
+    book-keeping for slacks.  Also I always use FTRAN approach to updating
+    even if factorization fairly dense.  All these could improve performance.
+
+    I blame some of the coding peculiarities on the history of the code
+    but mostly it is just because I can't do elegant code (or useful
+    comments).
+
+    I am assuming that 32 bits is enough for number of rows or columns, but CoinBigIndex
+    may be redefined to get 64 bits.
+ */
+
+
+class CoinFactorization {
+   friend void CoinFactorizationUnitTest( const std::string & mpsDir );
+
+public:
+
+  /**@name Constructors and destructor and copy */
+  //@{
+  /// Default constructor
+    CoinFactorization (  );
+  /// Copy constructor 
+  CoinFactorization ( const CoinFactorization &other);
+
+  /// Destructor
+   ~CoinFactorization (  );
+  /// Delete all stuff (leaves as after CoinFactorization())
+  void almostDestructor();
+  /// Debug show object (shows one representation)
+  void show_self (  ) const;
+  /// Debug - save on file - 0 if no error
+  int saveFactorization (const char * file  ) const;
+  /** Debug - restore from file - 0 if no error on file.
+      If factor true then factorizes as if called from ClpFactorization
+  */
+  int restoreFactorization (const char * file  , bool factor=false) ;
+  /// Debug - sort so can compare
+  void sort (  ) const;
+  /// = copy
+    CoinFactorization & operator = ( const CoinFactorization & other );
+  //@}
+
+  /**@name Do factorization */
+  //@{
+  /** When part of LP - given by basic variables.
+  Actually does factorization.
+  Arrays passed in have non negative value to say basic.
+  If status is okay, basic variables have pivot row - this is only needed
+  If status is singular, then basic variables have pivot row
+  and ones thrown out have -1
+  returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
+  int factorize ( const CoinPackedMatrix & matrix, 
+		  int rowIsBasic[], int columnIsBasic[] , 
+		  double areaFactor = 0.0 );
+  /** When given as triplets.
+  Actually does factorization.  maximumL is guessed maximum size of L part of
+  final factorization, maximumU of U part.  These are multiplied by
+  areaFactor which can be computed by user or internally.  
+  Arrays are copied in.  I could add flag to delete arrays to save a 
+  bit of memory.
+  If status okay, permutation has pivot rows - this is only needed
+  If status is singular, then basic variables have pivot row
+  and ones thrown out have -1
+  returns 0 -okay, -1 singular, -99 memory */
+  int factorize ( int numberRows,
+		  int numberColumns,
+		  CoinBigIndex numberElements,
+		  CoinBigIndex maximumL,
+		  CoinBigIndex maximumU,
+		  const int indicesRow[],
+		  const int indicesColumn[], const double elements[] ,
+		  int permutation[],
+		  double areaFactor = 0.0);
+  /** Two part version for maximum flexibility
+      This part creates arrays for user to fill.
+      estimateNumberElements is safe estimate of number
+      returns 0 -okay, -99 memory */
+  int factorizePart1 ( int numberRows,
+		       int numberColumns,
+		       CoinBigIndex estimateNumberElements,
+		       int * indicesRow[],
+		       int * indicesColumn[],
+		       CoinFactorizationDouble * elements[],
+		  double areaFactor = 0.0);
+  /** This is part two of factorization
+      Arrays belong to factorization and were returned by part 1
+      If status okay, permutation has pivot rows - this is only needed
+      If status is singular, then basic variables have pivot row
+      and ones thrown out have -1
+      returns 0 -okay, -1 singular, -99 memory */
+  int factorizePart2 (int permutation[],int exactNumberElements);
+  /// Condition number - product of pivots after factorization
+  double conditionNumber() const;
+  
+  //@}
+
+  /**@name general stuff such as permutation or status */
+  //@{ 
+  /// Returns status
+  inline int status (  ) const {
+    return status_;
+  }
+  /// Sets status
+  inline void setStatus (  int value)
+  {  status_=value;  }
+  /// Returns number of pivots since factorization
+  inline int pivots (  ) const {
+    return numberPivots_;
+  }
+  /// Sets number of pivots since factorization
+  inline void setPivots (  int value ) 
+  { numberPivots_=value; }
+  /// Returns address of permute region
+  inline int *permute (  ) const {
+    return permute_.array();
+  }
+  /// Returns address of pivotColumn region (also used for permuting)
+  inline int *pivotColumn (  ) const {
+    return pivotColumn_.array();
+  }
+  /// Returns address of pivot region
+  inline CoinFactorizationDouble *pivotRegion (  ) const {
+    return pivotRegion_.array();
+  }
+  /// Returns address of permuteBack region
+  inline int *permuteBack (  ) const {
+    return permuteBack_.array();
+  }
+  /** Returns address of pivotColumnBack region (also used for permuting)
+      Now uses firstCount to save memory allocation */
+  inline int *pivotColumnBack (  ) const {
+    //return firstCount_.array();
+    return pivotColumnBack_.array();
+  }
+  /// Start of each row in L
+  inline CoinBigIndex * startRowL() const
+  { return startRowL_.array();}
+
+  /// Start of each column in L
+  inline CoinBigIndex * startColumnL() const
+  { return startColumnL_.array();}
+
+  /// Index of column in row for L
+  inline int * indexColumnL() const
+  { return indexColumnL_.array();}
+
+  /// Row indices of L
+  inline int * indexRowL() const
+  { return indexRowL_.array();}
+
+  /// Elements in L (row copy)
+  inline CoinFactorizationDouble * elementByRowL() const
+  { return elementByRowL_.array();}
+
+  /// Number of Rows after iterating
+  inline int numberRowsExtra (  ) const {
+    return numberRowsExtra_;
+  }
+  /// Set number of Rows after factorization
+  inline void setNumberRows(int value)
+  { numberRows_ = value; }
+  /// Number of Rows after factorization
+  inline int numberRows (  ) const {
+    return numberRows_;
+  }
+  /// Number in L
+  inline CoinBigIndex numberL() const
+  { return numberL_;}
+
+  /// Base of L
+  inline CoinBigIndex baseL() const
+  { return baseL_;}
+  /// Maximum of Rows after iterating
+  inline int maximumRowsExtra (  ) const {
+    return maximumRowsExtra_;
+  }
+  /// Total number of columns in factorization
+  inline int numberColumns (  ) const {
+    return numberColumns_;
+  }
+  /// Total number of elements in factorization
+  inline int numberElements (  ) const {
+    return totalElements_;
+  }
+  /// Length of FT vector
+  inline int numberForrestTomlin (  ) const {
+    return numberInColumn_.array()[numberColumnsExtra_];
+  }
+  /// Number of good columns in factorization
+  inline int numberGoodColumns (  ) const {
+    return numberGoodU_;
+  }
+  /// Whether larger areas needed
+  inline double areaFactor (  ) const {
+    return areaFactor_;
+  }
+  inline void areaFactor ( double value ) {
+    areaFactor_=value;
+  }
+  /// Returns areaFactor but adjusted for dense
+  double adjustedAreaFactor() const;
+  /// Allows change of pivot accuracy check 1.0 == none >1.0 relaxed
+  inline void relaxAccuracyCheck(double value)
+  { relaxCheck_ = value;}
+  inline double getAccuracyCheck() const
+  { return relaxCheck_;}
+  /// Level of detail of messages
+  inline int messageLevel (  ) const {
+    return messageLevel_ ;
+  }
+  void messageLevel (  int value );
+  /// Maximum number of pivots between factorizations
+  inline int maximumPivots (  ) const {
+    return maximumPivots_ ;
+  }
+  void maximumPivots (  int value );
+
+  /// Gets dense threshold
+  inline int denseThreshold() const 
+    { return denseThreshold_;}
+  /// Sets dense threshold
+  inline void setDenseThreshold(int value)
+    { denseThreshold_ = value;}
+  /// Pivot tolerance
+  inline double pivotTolerance (  ) const {
+    return pivotTolerance_ ;
+  }
+  void pivotTolerance (  double value );
+  /// Zero tolerance
+  inline double zeroTolerance (  ) const {
+    return zeroTolerance_ ;
+  }
+  void zeroTolerance (  double value );
+#ifndef COIN_FAST_CODE
+  /// Whether slack value is +1 or -1
+  inline double slackValue (  ) const {
+    return slackValue_ ;
+  }
+  void slackValue (  double value );
+#endif
+  /// Returns maximum absolute value in factorization
+  double maximumCoefficient() const;
+  /// true if Forrest Tomlin update, false if PFI 
+  inline bool forrestTomlin() const
+  { return doForrestTomlin_;}
+  inline void setForrestTomlin(bool value)
+  { doForrestTomlin_=value;}
+  /// True if FT update and space
+  inline bool spaceForForrestTomlin() const
+  {
+    CoinBigIndex start = startColumnU_.array()[maximumColumnsExtra_];
+    CoinBigIndex space = lengthAreaU_ - ( start + numberRowsExtra_ );
+    return (space>=0)&&doForrestTomlin_;
+  }
+  //@}
+
+  /**@name some simple stuff */
+  //@{
+
+  /// Returns number of dense rows
+  inline int numberDense() const
+  { return numberDense_;}
+
+  /// Returns number in U area
+  inline CoinBigIndex numberElementsU (  ) const {
+    return lengthU_;
+  }
+  /// Setss number in U area
+  inline void setNumberElementsU(CoinBigIndex value)
+  { lengthU_ = value; }
+  /// Returns length of U area
+  inline CoinBigIndex lengthAreaU (  ) const {
+    return lengthAreaU_;
+  }
+  /// Returns number in L area
+  inline CoinBigIndex numberElementsL (  ) const {
+    return lengthL_;
+  }
+  /// Returns length of L area
+  inline CoinBigIndex lengthAreaL (  ) const {
+    return lengthAreaL_;
+  }
+  /// Returns number in R area
+  inline CoinBigIndex numberElementsR (  ) const {
+    return lengthR_;
+  }
+  /// Number of compressions done
+  inline CoinBigIndex numberCompressions() const
+  { return numberCompressions_;}
+  /// Number of entries in each row
+  inline int * numberInRow() const
+  { return numberInRow_.array();}
+  /// Number of entries in each column
+  inline int * numberInColumn() const
+  { return numberInColumn_.array();}
+  /// Elements of U
+  inline CoinFactorizationDouble * elementU() const
+  { return elementU_.array();}
+  /// Row indices of U
+  inline int * indexRowU() const
+  { return indexRowU_.array();}
+  /// Start of each column in U
+  inline CoinBigIndex * startColumnU() const
+  { return startColumnU_.array();}
+  /// Maximum number of Columns after iterating
+  inline int maximumColumnsExtra()
+  { return maximumColumnsExtra_;}
+  /** L to U bias
+      0 - U bias, 1 - some U bias, 2 some L bias, 3 L bias
+  */
+  inline int biasLU() const
+  { return biasLU_;}
+  inline void setBiasLU(int value)
+  { biasLU_=value;}
+  /** Array persistence flag
+      If 0 then as now (delete/new)
+      1 then only do arrays if bigger needed
+      2 as 1 but give a bit extra if bigger needed
+  */
+  inline int persistenceFlag() const
+  { return persistenceFlag_;}
+  void setPersistenceFlag(int value);
+  //@}
+
+  /**@name rank one updates which do exist */
+  //@{
+
+  /** Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+      If checkBeforeModifying is true will do all accuracy checks
+      before modifying factorization.  Whether to set this depends on
+      speed considerations.  You could just do this on first iteration
+      after factorization and thereafter re-factorize
+   partial update already in U */
+  int replaceColumn ( CoinIndexedVector * regionSparse,
+		      int pivotRow,
+		      double pivotCheck ,
+		      bool checkBeforeModifying=false,
+		      double acceptablePivot=1.0e-8);
+  /** Combines BtranU and delete elements
+      If deleted is NULL then delete elements
+      otherwise store where elements are
+  */
+  void replaceColumnU ( CoinIndexedVector * regionSparse,
+			CoinBigIndex * deleted,
+			int internalPivotRow);
+  //@}
+
+  /**@name various uses of factorization (return code number elements) 
+   which user may want to know about */
+  //@{
+  /** Updates one column (FTRAN) from regionSparse2
+      Tries to do FT update
+      number returned is negative if no room
+      regionSparse starts as zero and is zero at end.
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+  int updateColumnFT ( CoinIndexedVector * regionSparse,
+		       CoinIndexedVector * regionSparse2);
+  /** This version has same effect as above with FTUpdate==false
+      so number returned is always >=0 */
+  int updateColumn ( CoinIndexedVector * regionSparse,
+		     CoinIndexedVector * regionSparse2,
+		     bool noPermute=false) const;
+  /** Updates one column (FTRAN) from region2
+      Tries to do FT update
+      number returned is negative if no room.
+      Also updates region3
+      region1 starts as zero and is zero at end */
+  int updateTwoColumnsFT ( CoinIndexedVector * regionSparse1,
+			   CoinIndexedVector * regionSparse2,
+			   CoinIndexedVector * regionSparse3,
+			   bool noPermuteRegion3=false) ;
+  /** Updates one column (BTRAN) from regionSparse2
+      regionSparse starts as zero and is zero at end 
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+  int updateColumnTranspose ( CoinIndexedVector * regionSparse,
+			      CoinIndexedVector * regionSparse2) const;
+  /** makes a row copy of L for speed and to allow very sparse problems */
+  void goSparse();
+  /**  get sparse threshold */
+  inline int sparseThreshold ( ) const
+  { return sparseThreshold_;}
+  /**  set sparse threshold */
+  void sparseThreshold ( int value );
+  //@}
+  /// *** Below this user may not want to know about
+
+  /**@name various uses of factorization (return code number elements) 
+   which user may not want to know about (left over from my LP code) */
+  //@{
+  /// Get rid of all memory
+  inline void clearArrays()
+  { gutsOfDestructor();}
+  //@}
+
+  /**@name various updates - none of which have been written! */
+  //@{
+
+  /** Adds given elements to Basis and updates factorization,
+      can increase size of basis. Returns rank */
+  int add ( CoinBigIndex numberElements,
+	       int indicesRow[],
+	       int indicesColumn[], double elements[] );
+
+  /** Adds one Column to basis,
+      can increase size of basis. Returns rank */
+  int addColumn ( CoinBigIndex numberElements,
+		     int indicesRow[], double elements[] );
+
+  /** Adds one Row to basis,
+      can increase size of basis. Returns rank */
+  int addRow ( CoinBigIndex numberElements,
+		  int indicesColumn[], double elements[] );
+
+  /// Deletes one Column from basis, returns rank
+  int deleteColumn ( int Row );
+  /// Deletes one Row from basis, returns rank
+  int deleteRow ( int Row );
+
+  /** Replaces one Row in basis,
+      At present assumes just a singleton on row is in basis
+      returns 0=OK, 1=Probably OK, 2=singular, 3 no space */
+  int replaceRow ( int whichRow, int numberElements,
+		      const int indicesColumn[], const double elements[] );
+  /// Takes out all entries for given rows
+  void emptyRows(int numberToEmpty, const int which[]);
+  //@}
+  /**@name used by ClpFactorization */
+  /// See if worth going sparse
+  void checkSparse();
+  /// For statistics 
+  inline bool collectStatistics() const
+  { return collectStatistics_;}
+  /// For statistics 
+  inline void setCollectStatistics(bool onOff) const
+  { collectStatistics_ = onOff;}
+  /// The real work of constructors etc 0 just scalars, 1 bit normal 
+  void gutsOfDestructor(int type=1);
+  /// 1 bit - tolerances etc, 2 more, 4 dummy arrays
+  void gutsOfInitialize(int type);
+  void gutsOfCopy(const CoinFactorization &other);
+
+  /// Reset all sparsity etc statistics
+  void resetStatistics();
+
+
+  //@}
+
+  /**@name used by factorization */
+  /// Gets space for a factorization, called by constructors
+  void getAreas ( int numberRows,
+		  int numberColumns,
+		  CoinBigIndex maximumL,
+		  CoinBigIndex maximumU );
+
+  /** PreProcesses raw triplet data.
+      state is 0 - triplets, 1 - some counts etc , 2 - .. */
+  void preProcess ( int state,
+		    int possibleDuplicates = -1 );
+  /// Does most of factorization
+  int factor (  );
+protected:
+  /** Does sparse phase of factorization
+      return code is <0 error, 0= finished */
+  int factorSparse (  );
+  /** Does sparse phase of factorization (for smaller problems)
+      return code is <0 error, 0= finished */
+  int factorSparseSmall (  );
+  /** Does sparse phase of factorization (for larger problems)
+      return code is <0 error, 0= finished */
+  int factorSparseLarge (  );
+  /** Does dense phase of factorization
+      return code is <0 error, 0= finished */
+  int factorDense (  );
+
+  /// Pivots when just one other row so faster?
+  bool pivotOneOtherRow ( int pivotRow,
+			  int pivotColumn );
+  /// Does one pivot on Row Singleton in factorization
+  bool pivotRowSingleton ( int pivotRow,
+			   int pivotColumn );
+  /// Does one pivot on Column Singleton in factorization
+  bool pivotColumnSingleton ( int pivotRow,
+			      int pivotColumn );
+
+  /** Gets space for one Column with given length,
+   may have to do compression  (returns True if successful),
+   also moves existing vector,
+   extraNeeded is over and above present */
+  bool getColumnSpace ( int iColumn,
+			int extraNeeded );
+
+  /** Reorders U so contiguous and in order (if there is space)
+      Returns true if it could */
+  bool reorderU();
+  /**  getColumnSpaceIterateR.  Gets space for one extra R element in Column
+       may have to do compression  (returns true)
+       also moves existing vector */
+  bool getColumnSpaceIterateR ( int iColumn, double value,
+			       int iRow);
+  /**  getColumnSpaceIterate.  Gets space for one extra U element in Column
+       may have to do compression  (returns true)
+       also moves existing vector.
+       Returns -1 if no memory or where element was put
+       Used by replaceRow (turns off R version) */
+  CoinBigIndex getColumnSpaceIterate ( int iColumn, double value,
+			       int iRow);
+  /** Gets space for one Row with given length,
+  may have to do compression  (returns True if successful),
+  also moves existing vector */
+  bool getRowSpace ( int iRow, int extraNeeded );
+
+  /** Gets space for one Row with given length while iterating,
+  may have to do compression  (returns True if successful),
+  also moves existing vector */
+  bool getRowSpaceIterate ( int iRow,
+			    int extraNeeded );
+  /// Checks that row and column copies look OK
+  void checkConsistency (  );
+  /// Adds a link in chain of equal counts
+  inline void addLink ( int index, int count ) {
+    int *nextCount = nextCount_.array();
+    int *firstCount = firstCount_.array();
+    int *lastCount = lastCount_.array();
+    int next = firstCount[count];
+      lastCount[index] = -2 - count;
+    if ( next < 0 ) {
+      //first with that count
+      firstCount[count] = index;
+      nextCount[index] = -1;
+    } else {
+      firstCount[count] = index;
+      nextCount[index] = next;
+      lastCount[next] = index;
+  }}
+  /// Deletes a link in chain of equal counts
+  inline void deleteLink ( int index ) {
+    int *nextCount = nextCount_.array();
+    int *firstCount = firstCount_.array();
+    int *lastCount = lastCount_.array();
+    int next = nextCount[index];
+    int last = lastCount[index];
+    if ( last >= 0 ) {
+      nextCount[last] = next;
+    } else {
+      int count = -last - 2;
+
+      firstCount[count] = next;
+    }
+    if ( next >= 0 ) {
+      lastCount[next] = last;
+    }
+    nextCount[index] = -2;
+    lastCount[index] = -2;
+    return;
+  }
+  /// Separate out links with same row/column count
+  void separateLinks(int count,bool rowsFirst);
+  /// Cleans up at end of factorization
+  void cleanup (  );
+
+  /// Updates part of column (FTRANL)
+  void updateColumnL ( CoinIndexedVector * region, int * indexIn ) const;
+  /// Updates part of column (FTRANL) when densish
+  void updateColumnLDensish ( CoinIndexedVector * region, int * indexIn ) const;
+  /// Updates part of column (FTRANL) when sparse
+  void updateColumnLSparse ( CoinIndexedVector * region, int * indexIn ) const;
+  /// Updates part of column (FTRANL) when sparsish
+  void updateColumnLSparsish ( CoinIndexedVector * region, int * indexIn ) const;
+
+  /// Updates part of column (FTRANR) without FT update
+  void updateColumnR ( CoinIndexedVector * region ) const;
+  /** Updates part of column (FTRANR) with FT update.
+      Also stores update after L and R */
+  void updateColumnRFT ( CoinIndexedVector * region, int * indexIn );
+
+  /// Updates part of column (FTRANU)
+  void updateColumnU ( CoinIndexedVector * region, int * indexIn) const;
+
+  /// Updates part of column (FTRANU) when sparse
+  void updateColumnUSparse ( CoinIndexedVector * regionSparse, 
+			     int * indexIn) const;
+  /// Updates part of column (FTRANU) when sparsish
+  void updateColumnUSparsish ( CoinIndexedVector * regionSparse, 
+			       int * indexIn) const;
+  /// Updates part of column (FTRANU)
+  int updateColumnUDensish ( double * COIN_RESTRICT region, 
+			     int * COIN_RESTRICT regionIndex) const;
+  /// Updates part of 2 columns (FTRANU) real work
+  void updateTwoColumnsUDensish (
+				 int & numberNonZero1,
+				 double * COIN_RESTRICT region1, 
+				 int * COIN_RESTRICT index1,
+				 int & numberNonZero2,
+				 double * COIN_RESTRICT region2, 
+				 int * COIN_RESTRICT index2) const;
+  /// Updates part of column PFI (FTRAN) (after rest)
+  void updateColumnPFI ( CoinIndexedVector * regionSparse) const; 
+  /// Permutes back at end of updateColumn
+  void permuteBack ( CoinIndexedVector * regionSparse, 
+		     CoinIndexedVector * outVector) const;
+
+  /// Updates part of column transpose PFI (BTRAN) (before rest)
+  void updateColumnTransposePFI ( CoinIndexedVector * region) const;
+  /** Updates part of column transpose (BTRANU),
+      assumes index is sorted i.e. region is correct */
+  void updateColumnTransposeU ( CoinIndexedVector * region,
+				int smallestIndex) const;
+  /** Updates part of column transpose (BTRANU) when sparsish,
+      assumes index is sorted i.e. region is correct */
+  void updateColumnTransposeUSparsish ( CoinIndexedVector * region,
+					int smallestIndex) const;
+  /** Updates part of column transpose (BTRANU) when densish,
+      assumes index is sorted i.e. region is correct */
+  void updateColumnTransposeUDensish ( CoinIndexedVector * region,
+				       int smallestIndex) const;
+  /** Updates part of column transpose (BTRANU) when sparse,
+      assumes index is sorted i.e. region is correct */
+  void updateColumnTransposeUSparse ( CoinIndexedVector * region) const;
+  /** Updates part of column transpose (BTRANU) by column
+      assumes index is sorted i.e. region is correct */
+  void updateColumnTransposeUByColumn ( CoinIndexedVector * region,
+					int smallestIndex) const;
+
+  /// Updates part of column transpose (BTRANR)
+  void updateColumnTransposeR ( CoinIndexedVector * region ) const;
+  /// Updates part of column transpose (BTRANR) when dense
+  void updateColumnTransposeRDensish ( CoinIndexedVector * region ) const;
+  /// Updates part of column transpose (BTRANR) when sparse
+  void updateColumnTransposeRSparse ( CoinIndexedVector * region ) const;
+
+  /// Updates part of column transpose (BTRANL)
+  void updateColumnTransposeL ( CoinIndexedVector * region ) const;
+  /// Updates part of column transpose (BTRANL) when densish by column
+  void updateColumnTransposeLDensish ( CoinIndexedVector * region ) const;
+  /// Updates part of column transpose (BTRANL) when densish by row
+  void updateColumnTransposeLByRow ( CoinIndexedVector * region ) const;
+  /// Updates part of column transpose (BTRANL) when sparsish by row
+  void updateColumnTransposeLSparsish ( CoinIndexedVector * region ) const;
+  /// Updates part of column transpose (BTRANL) when sparse (by Row)
+  void updateColumnTransposeLSparse ( CoinIndexedVector * region ) const;
+public:
+  /** Replaces one Column to basis for PFI
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room.
+   In this case region is not empty - it is incoming variable (updated)
+  */
+  int replaceColumnPFI ( CoinIndexedVector * regionSparse,
+			 int pivotRow, double alpha);
+protected:
+  /** Returns accuracy status of replaceColumn
+      returns 0=OK, 1=Probably OK, 2=singular */
+  int checkPivot(double saveFromU, double oldPivot) const;
+  /********************************* START LARGE TEMPLATE ********/
+#ifdef INT_IS_8
+#define COINFACTORIZATION_BITS_PER_INT 64
+#define COINFACTORIZATION_SHIFT_PER_INT 6
+#define COINFACTORIZATION_MASK_PER_INT 0x3f
+#else
+#define COINFACTORIZATION_BITS_PER_INT 32
+#define COINFACTORIZATION_SHIFT_PER_INT 5
+#define COINFACTORIZATION_MASK_PER_INT 0x1f
+#endif
+  template <class T>  inline bool
+  pivot ( int pivotRow,
+	  int pivotColumn,
+	  CoinBigIndex pivotRowPosition,
+	  CoinBigIndex pivotColumnPosition,
+	  CoinFactorizationDouble work[],
+	  unsigned int workArea2[],
+	  int increment2,
+	  T markRow[] ,
+	  int largeInteger)
+{
+  int *indexColumnU = indexColumnU_.array();
+  CoinBigIndex *startColumnU = startColumnU_.array();
+  int *numberInColumn = numberInColumn_.array();
+  CoinFactorizationDouble *elementU = elementU_.array();
+  int *indexRowU = indexRowU_.array();
+  CoinBigIndex *startRowU = startRowU_.array();
+  int *numberInRow = numberInRow_.array();
+  CoinFactorizationDouble *elementL = elementL_.array();
+  int *indexRowL = indexRowL_.array();
+  int *saveColumn = saveColumn_.array();
+  int *nextRow = nextRow_.array();
+  int *lastRow = lastRow_.array() ;
+
+  //store pivot columns (so can easily compress)
+  int numberInPivotRow = numberInRow[pivotRow] - 1;
+  CoinBigIndex startColumn = startColumnU[pivotColumn];
+  int numberInPivotColumn = numberInColumn[pivotColumn] - 1;
+  CoinBigIndex endColumn = startColumn + numberInPivotColumn + 1;
+  int put = 0;
+  CoinBigIndex startRow = startRowU[pivotRow];
+  CoinBigIndex endRow = startRow + numberInPivotRow + 1;
+
+  if ( pivotColumnPosition < 0 ) {
+    for ( pivotColumnPosition = startRow; pivotColumnPosition < endRow; pivotColumnPosition++ ) {
+      int iColumn = indexColumnU[pivotColumnPosition];
+      if ( iColumn != pivotColumn ) {
+	saveColumn[put++] = iColumn;
+      } else {
+        break;
+      }
+    }
+  } else {
+    for (CoinBigIndex i = startRow ; i < pivotColumnPosition ; i++ ) {
+      saveColumn[put++] = indexColumnU[i];
+    }
+  }
+  assert (pivotColumnPosition<endRow);
+  assert (indexColumnU[pivotColumnPosition]==pivotColumn);
+  pivotColumnPosition++;
+  for ( ; pivotColumnPosition < endRow; pivotColumnPosition++ ) {
+    saveColumn[put++] = indexColumnU[pivotColumnPosition];
+  }
+  //take out this bit of indexColumnU
+  int next = nextRow[pivotRow];
+  int last = lastRow[pivotRow];
+
+  nextRow[last] = next;
+  lastRow[next] = last;
+  nextRow[pivotRow] = numberGoodU_;	//use for permute
+  lastRow[pivotRow] = -2;
+  numberInRow[pivotRow] = 0;
+  //store column in L, compress in U and take column out
+  CoinBigIndex l = lengthL_;
+
+  if ( l + numberInPivotColumn > lengthAreaL_ ) {
+    //need more memory
+    if ((messageLevel_&4)!=0) 
+      printf("more memory needed in middle of invert\n");
+    return false;
+  }
+  //l+=currentAreaL_->elementByColumn-elementL;
+  CoinBigIndex lSave = l;
+
+  CoinBigIndex * startColumnL = startColumnL_.array();
+  startColumnL[numberGoodL_] = l;	//for luck and first time
+  numberGoodL_++;
+  startColumnL[numberGoodL_] = l + numberInPivotColumn;
+  lengthL_ += numberInPivotColumn;
+  if ( pivotRowPosition < 0 ) {
+    for ( pivotRowPosition = startColumn; pivotRowPosition < endColumn; pivotRowPosition++ ) {
+      int iRow = indexRowU[pivotRowPosition];
+      if ( iRow != pivotRow ) {
+	indexRowL[l] = iRow;
+	elementL[l] = elementU[pivotRowPosition];
+	markRow[iRow] = static_cast<T>(l - lSave);
+	l++;
+	//take out of row list
+	CoinBigIndex start = startRowU[iRow];
+	CoinBigIndex end = start + numberInRow[iRow];
+	CoinBigIndex where = start;
+
+	while ( indexColumnU[where] != pivotColumn ) {
+	  where++;
+	}			/* endwhile */
+#if DEBUG_COIN
+	if ( where >= end ) {
+	  abort (  );
+	}
+#endif
+	indexColumnU[where] = indexColumnU[end - 1];
+	numberInRow[iRow]--;
+      } else {
+	break;
+      }
+    }
+  } else {
+    CoinBigIndex i;
+
+    for ( i = startColumn; i < pivotRowPosition; i++ ) {
+      int iRow = indexRowU[i];
+
+      markRow[iRow] = static_cast<T>(l - lSave);
+      indexRowL[l] = iRow;
+      elementL[l] = elementU[i];
+      l++;
+      //take out of row list
+      CoinBigIndex start = startRowU[iRow];
+      CoinBigIndex end = start + numberInRow[iRow];
+      CoinBigIndex where = start;
+
+      while ( indexColumnU[where] != pivotColumn ) {
+	where++;
+      }				/* endwhile */
+#if DEBUG_COIN
+      if ( where >= end ) {
+	abort (  );
+      }
+#endif
+      indexColumnU[where] = indexColumnU[end - 1];
+      numberInRow[iRow]--;
+      assert (numberInRow[iRow]>=0);
+    }
+  }
+  assert (pivotRowPosition<endColumn);
+  assert (indexRowU[pivotRowPosition]==pivotRow);
+  CoinFactorizationDouble pivotElement = elementU[pivotRowPosition];
+  CoinFactorizationDouble pivotMultiplier = 1.0 / pivotElement;
+
+  pivotRegion_.array()[numberGoodU_] = pivotMultiplier;
+  pivotRowPosition++;
+  for ( ; pivotRowPosition < endColumn; pivotRowPosition++ ) {
+    int iRow = indexRowU[pivotRowPosition];
+    
+    markRow[iRow] = static_cast<T>(l - lSave);
+    indexRowL[l] = iRow;
+    elementL[l] = elementU[pivotRowPosition];
+    l++;
+    //take out of row list
+    CoinBigIndex start = startRowU[iRow];
+    CoinBigIndex end = start + numberInRow[iRow];
+    CoinBigIndex where = start;
+    
+    while ( indexColumnU[where] != pivotColumn ) {
+      where++;
+    }				/* endwhile */
+#if DEBUG_COIN
+    if ( where >= end ) {
+      abort (  );
+    }
+#endif
+    indexColumnU[where] = indexColumnU[end - 1];
+    numberInRow[iRow]--;
+    assert (numberInRow[iRow]>=0);
+  }
+  markRow[pivotRow] = static_cast<T>(largeInteger);
+  //compress pivot column (move pivot to front including saved)
+  numberInColumn[pivotColumn] = 0;
+  //use end of L for temporary space
+  int *indexL = &indexRowL[lSave];
+  CoinFactorizationDouble *multipliersL = &elementL[lSave];
+
+  //adjust
+  int j;
+
+  for ( j = 0; j < numberInPivotColumn; j++ ) {
+    multipliersL[j] *= pivotMultiplier;
+  }
+  //zero out fill
+  CoinBigIndex iErase;
+  for ( iErase = 0; iErase < increment2 * numberInPivotRow;
+	iErase++ ) {
+    workArea2[iErase] = 0;
+  }
+  CoinBigIndex added = numberInPivotRow * numberInPivotColumn;
+  unsigned int *temp2 = workArea2;
+  int * nextColumn = nextColumn_.array();
+
+  //pack down and move to work
+  int jColumn;
+  for ( jColumn = 0; jColumn < numberInPivotRow; jColumn++ ) {
+    int iColumn = saveColumn[jColumn];
+    CoinBigIndex startColumn = startColumnU[iColumn];
+    CoinBigIndex endColumn = startColumn + numberInColumn[iColumn];
+    int iRow = indexRowU[startColumn];
+    CoinFactorizationDouble value = elementU[startColumn];
+    double largest;
+    CoinBigIndex put = startColumn;
+    CoinBigIndex positionLargest = -1;
+    CoinFactorizationDouble thisPivotValue = 0.0;
+
+    //compress column and find largest not updated
+    bool checkLargest;
+    int mark = markRow[iRow];
+
+    if ( mark == largeInteger+1 ) {
+      largest = fabs ( value );
+      positionLargest = put;
+      put++;
+      checkLargest = false;
+    } else {
+      //need to find largest
+      largest = 0.0;
+      checkLargest = true;
+      if ( mark != largeInteger ) {
+	//will be updated
+	work[mark] = value;
+	int word = mark >> COINFACTORIZATION_SHIFT_PER_INT;
+	int bit = mark & COINFACTORIZATION_MASK_PER_INT;
+
+	temp2[word] = temp2[word] | ( 1 << bit );	//say already in counts
+	added--;
+      } else {
+	thisPivotValue = value;
+      }
+    }
+    CoinBigIndex i;
+    for ( i = startColumn + 1; i < endColumn; i++ ) {
+      iRow = indexRowU[i];
+      value = elementU[i];
+      int mark = markRow[iRow];
+
+      if ( mark == largeInteger+1 ) {
+	//keep
+	indexRowU[put] = iRow;
+	elementU[put] = value;
+	if ( checkLargest ) {
+	  double absValue = fabs ( value );
+
+	  if ( absValue > largest ) {
+	    largest = absValue;
+	    positionLargest = put;
+	  }
+	}
+	put++;
+      } else if ( mark != largeInteger ) {
+	//will be updated
+	work[mark] = value;
+	int word = mark >> COINFACTORIZATION_SHIFT_PER_INT;
+	int bit = mark & COINFACTORIZATION_MASK_PER_INT;
+
+	temp2[word] = temp2[word] | ( 1 << bit );	//say already in counts
+	added--;
+      } else {
+	thisPivotValue = value;
+      }
+    }
+    //slot in pivot
+    elementU[put] = elementU[startColumn];
+    indexRowU[put] = indexRowU[startColumn];
+    if ( positionLargest == startColumn ) {
+      positionLargest = put;	//follow if was largest
+    }
+    put++;
+    elementU[startColumn] = thisPivotValue;
+    indexRowU[startColumn] = pivotRow;
+    //clean up counts
+    startColumn++;
+    numberInColumn[iColumn] = put - startColumn;
+    int * numberInColumnPlus = numberInColumnPlus_.array();
+    numberInColumnPlus[iColumn]++;
+    startColumnU[iColumn]++;
+    //how much space have we got
+    int next = nextColumn[iColumn];
+    CoinBigIndex space;
+
+    space = startColumnU[next] - put - numberInColumnPlus[next];
+    //assume no zero elements
+    if ( numberInPivotColumn > space ) {
+      //getColumnSpace also moves fixed part
+      if ( !getColumnSpace ( iColumn, numberInPivotColumn ) ) {
+	return false;
+      }
+      //redo starts
+      if (positionLargest >= 0)
+         positionLargest = positionLargest + startColumnU[iColumn] - startColumn;
+      startColumn = startColumnU[iColumn];
+      put = startColumn + numberInColumn[iColumn];
+    }
+    double tolerance = zeroTolerance_;
+
+    int *nextCount = nextCount_.array();
+    for ( j = 0; j < numberInPivotColumn; j++ ) {
+      value = work[j] - thisPivotValue * multipliersL[j];
+      double absValue = fabs ( value );
+
+      if ( absValue > tolerance ) {
+	work[j] = 0.0;
+	assert (put<lengthAreaU_); 
+	elementU[put] = value;
+	indexRowU[put] = indexL[j];
+	if ( absValue > largest ) {
+	  largest = absValue;
+	  positionLargest = put;
+	}
+	put++;
+      } else {
+	work[j] = 0.0;
+	added--;
+	int word = j >> COINFACTORIZATION_SHIFT_PER_INT;
+	int bit = j & COINFACTORIZATION_MASK_PER_INT;
+
+	if ( temp2[word] & ( 1 << bit ) ) {
+	  //take out of row list
+	  iRow = indexL[j];
+	  CoinBigIndex start = startRowU[iRow];
+	  CoinBigIndex end = start + numberInRow[iRow];
+	  CoinBigIndex where = start;
+
+	  while ( indexColumnU[where] != iColumn ) {
+	    where++;
+	  }			/* endwhile */
+#if DEBUG_COIN
+	  if ( where >= end ) {
+	    abort (  );
+	  }
+#endif
+	  indexColumnU[where] = indexColumnU[end - 1];
+	  numberInRow[iRow]--;
+	} else {
+	  //make sure won't be added
+	  int word = j >> COINFACTORIZATION_SHIFT_PER_INT;
+	  int bit = j & COINFACTORIZATION_MASK_PER_INT;
+
+	  temp2[word] = temp2[word] | ( 1 << bit );	//say already in counts
+	}
+      }
+    }
+    numberInColumn[iColumn] = put - startColumn;
+    //move largest
+    if ( positionLargest >= 0 ) {
+      value = elementU[positionLargest];
+      iRow = indexRowU[positionLargest];
+      elementU[positionLargest] = elementU[startColumn];
+      indexRowU[positionLargest] = indexRowU[startColumn];
+      elementU[startColumn] = value;
+      indexRowU[startColumn] = iRow;
+    }
+    //linked list for column
+    if ( nextCount[iColumn + numberRows_] != -2 ) {
+      //modify linked list
+      deleteLink ( iColumn + numberRows_ );
+      addLink ( iColumn + numberRows_, numberInColumn[iColumn] );
+    }
+    temp2 += increment2;
+  }
+  //get space for row list
+  unsigned int *putBase = workArea2;
+  int bigLoops = numberInPivotColumn >> COINFACTORIZATION_SHIFT_PER_INT;
+  int i = 0;
+
+  // do linked lists and update counts
+  while ( bigLoops ) {
+    bigLoops--;
+    int bit;
+    for ( bit = 0; bit < COINFACTORIZATION_BITS_PER_INT; i++, bit++ ) {
+      unsigned int *putThis = putBase;
+      int iRow = indexL[i];
+
+      //get space
+      int number = 0;
+      int jColumn;
+
+      for ( jColumn = 0; jColumn < numberInPivotRow; jColumn++ ) {
+	unsigned int test = *putThis;
+
+	putThis += increment2;
+	test = 1 - ( ( test >> bit ) & 1 );
+	number += test;
+      }
+      int next = nextRow[iRow];
+      CoinBigIndex space;
+
+      space = startRowU[next] - startRowU[iRow];
+      number += numberInRow[iRow];
+      if ( space < number ) {
+	if ( !getRowSpace ( iRow, number ) ) {
+	  return false;
+	}
+      }
+      // now do
+      putThis = putBase;
+      next = nextRow[iRow];
+      number = numberInRow[iRow];
+      CoinBigIndex end = startRowU[iRow] + number;
+      int saveIndex = indexColumnU[startRowU[next]];
+
+      //add in
+      for ( jColumn = 0; jColumn < numberInPivotRow; jColumn++ ) {
+	unsigned int test = *putThis;
+
+	putThis += increment2;
+	test = 1 - ( ( test >> bit ) & 1 );
+	indexColumnU[end] = saveColumn[jColumn];
+	end += test;
+      }
+      //put back next one in case zapped
+      indexColumnU[startRowU[next]] = saveIndex;
+      markRow[iRow] = static_cast<T>(largeInteger+1);
+      number = end - startRowU[iRow];
+      numberInRow[iRow] = number;
+      deleteLink ( iRow );
+      addLink ( iRow, number );
+    }
+    putBase++;
+  }				/* endwhile */
+  int bit;
+
+  for ( bit = 0; i < numberInPivotColumn; i++, bit++ ) {
+    unsigned int *putThis = putBase;
+    int iRow = indexL[i];
+
+    //get space
+    int number = 0;
+    int jColumn;
+
+    for ( jColumn = 0; jColumn < numberInPivotRow; jColumn++ ) {
+      unsigned int test = *putThis;
+
+      putThis += increment2;
+      test = 1 - ( ( test >> bit ) & 1 );
+      number += test;
+    }
+    int next = nextRow[iRow];
+    CoinBigIndex space;
+
+    space = startRowU[next] - startRowU[iRow];
+    number += numberInRow[iRow];
+    if ( space < number ) {
+      if ( !getRowSpace ( iRow, number ) ) {
+	return false;
+      }
+    }
+    // now do
+    putThis = putBase;
+    next = nextRow[iRow];
+    number = numberInRow[iRow];
+    CoinBigIndex end = startRowU[iRow] + number;
+    int saveIndex;
+
+    saveIndex = indexColumnU[startRowU[next]];
+
+    //add in
+    for ( jColumn = 0; jColumn < numberInPivotRow; jColumn++ ) {
+      unsigned int test = *putThis;
+
+      putThis += increment2;
+      test = 1 - ( ( test >> bit ) & 1 );
+
+      indexColumnU[end] = saveColumn[jColumn];
+      end += test;
+    }
+    indexColumnU[startRowU[next]] = saveIndex;
+    markRow[iRow] = static_cast<T>(largeInteger+1);
+    number = end - startRowU[iRow];
+    numberInRow[iRow] = number;
+    deleteLink ( iRow );
+    addLink ( iRow, number );
+  }
+  markRow[pivotRow] = static_cast<T>(largeInteger+1);
+  //modify linked list for pivots
+  deleteLink ( pivotRow );
+  deleteLink ( pivotColumn + numberRows_ );
+  totalElements_ += added;
+  return true;
+}
+
+  /********************************* END LARGE TEMPLATE ********/
+  //@}
+////////////////// data //////////////////
+protected:
+
+  /**@name data */
+  //@{
+  /// Pivot tolerance
+  double pivotTolerance_;
+  /// Zero tolerance
+  double zeroTolerance_;
+#ifndef COIN_FAST_CODE
+  /// Whether slack value is  +1 or -1
+  double slackValue_;
+#else
+#ifndef slackValue_
+#define slackValue_ -1.0
+#endif
+#endif
+  /// How much to multiply areas by
+  double areaFactor_;
+  /// Relax check on accuracy in replaceColumn
+  double relaxCheck_;
+  /// Number of Rows in factorization
+  int numberRows_;
+  /// Number of Rows after iterating
+  int numberRowsExtra_;
+  /// Maximum number of Rows after iterating
+  int maximumRowsExtra_;
+  /// Number of Columns in factorization
+  int numberColumns_;
+  /// Number of Columns after iterating
+  int numberColumnsExtra_;
+  /// Maximum number of Columns after iterating
+  int maximumColumnsExtra_;
+  /// Number factorized in U (not row singletons)
+  int numberGoodU_;
+  /// Number factorized in L
+  int numberGoodL_;
+  /// Maximum number of pivots before factorization
+  int maximumPivots_;
+  /// Number pivots since last factorization
+  int numberPivots_;
+  /// Number of elements in U (to go)
+  ///       or while iterating total overall
+  CoinBigIndex totalElements_;
+  /// Number of elements after factorization
+  CoinBigIndex factorElements_;
+  /// Pivot order for each Column
+  CoinIntArrayWithLength pivotColumn_;
+  /// Permutation vector for pivot row order
+  CoinIntArrayWithLength permute_;
+  /// DePermutation vector for pivot row order
+  CoinIntArrayWithLength permuteBack_;
+  /// Inverse Pivot order for each Column
+  CoinIntArrayWithLength pivotColumnBack_;
+  /// Status of factorization
+  int status_;
+
+  /** 0 - no increasing rows - no permutations,
+   1 - no increasing rows but permutations 
+   2 - increasing rows 
+     - taken out as always 2 */
+  //int increasingRows_;
+
+  /// Number of trials before rejection
+  int numberTrials_;
+  /// Start of each Row as pointer
+  CoinBigIndexArrayWithLength startRowU_;
+
+  /// Number in each Row
+  CoinIntArrayWithLength numberInRow_;
+
+  /// Number in each Column
+  CoinIntArrayWithLength numberInColumn_;
+
+  /// Number in each Column including pivoted
+  CoinIntArrayWithLength numberInColumnPlus_;
+
+  /** First Row/Column with count of k,
+      can tell which by offset - Rows then Columns */
+  CoinIntArrayWithLength firstCount_;
+
+  /// Next Row/Column with count
+  CoinIntArrayWithLength nextCount_;
+
+  /// Previous Row/Column with count
+  CoinIntArrayWithLength lastCount_;
+
+  /// Next Column in memory order
+  CoinIntArrayWithLength nextColumn_;
+
+  /// Previous Column in memory order
+  CoinIntArrayWithLength lastColumn_;
+
+  /// Next Row in memory order
+  CoinIntArrayWithLength nextRow_;
+
+  /// Previous Row in memory order
+  CoinIntArrayWithLength lastRow_;
+
+  /// Columns left to do in a single pivot
+  CoinIntArrayWithLength saveColumn_;
+
+  /// Marks rows to be updated
+  CoinIntArrayWithLength markRow_;
+
+  /// Detail in messages
+  int messageLevel_;
+
+  /// Larger of row and column size
+  int biggerDimension_;
+
+  /// Base address for U (may change)
+  CoinIntArrayWithLength indexColumnU_;
+
+  /// Pivots for L
+  CoinIntArrayWithLength pivotRowL_;
+
+  /// Inverses of pivot values
+  CoinFactorizationDoubleArrayWithLength pivotRegion_;
+
+  /// Number of slacks at beginning of U
+  int numberSlacks_;
+
+  /// Number in U
+  int numberU_;
+
+  /// Maximum space used in U
+  CoinBigIndex maximumU_;
+
+  /// Base of U is always 0
+  //int baseU_;
+
+  /// Length of U
+  CoinBigIndex lengthU_;
+
+  /// Length of area reserved for U
+  CoinBigIndex lengthAreaU_;
+
+/// Elements of U
+  CoinFactorizationDoubleArrayWithLength elementU_;
+
+/// Row indices of U
+  CoinIntArrayWithLength indexRowU_;
+
+/// Start of each column in U
+  CoinBigIndexArrayWithLength startColumnU_;
+
+/// Converts rows to columns in U 
+  CoinBigIndexArrayWithLength convertRowToColumnU_;
+
+  /// Number in L
+  CoinBigIndex numberL_;
+
+/// Base of L
+  CoinBigIndex baseL_;
+
+  /// Length of L
+  CoinBigIndex lengthL_;
+
+  /// Length of area reserved for L
+  CoinBigIndex lengthAreaL_;
+
+  /// Elements of L
+  CoinFactorizationDoubleArrayWithLength elementL_;
+
+  /// Row indices of L
+  CoinIntArrayWithLength indexRowL_;
+
+  /// Start of each column in L
+  CoinBigIndexArrayWithLength startColumnL_;
+
+  /// true if Forrest Tomlin update, false if PFI 
+  bool doForrestTomlin_;
+
+  /// Number in R
+  int numberR_;
+
+  /// Length of R stuff
+  CoinBigIndex lengthR_;
+
+  /// length of area reserved for R
+  CoinBigIndex lengthAreaR_;
+
+  /// Elements of R
+  CoinFactorizationDouble *elementR_;
+
+  /// Row indices for R
+  int *indexRowR_;
+
+  /// Start of columns for R
+  CoinBigIndexArrayWithLength startColumnR_;
+
+  /// Dense area
+  double  * denseArea_;
+
+  /// Dense permutation
+  int * densePermute_;
+
+  /// Number of dense rows
+  int numberDense_;
+
+  /// Dense threshold
+  int denseThreshold_;
+
+  /// First work area
+  CoinFactorizationDoubleArrayWithLength workArea_;
+
+  /// Second work area
+  CoinUnsignedIntArrayWithLength workArea2_;
+
+  /// Number of compressions done
+  CoinBigIndex numberCompressions_;
+
+  /// Below are all to collect
+  mutable double ftranCountInput_;
+  mutable double ftranCountAfterL_;
+  mutable double ftranCountAfterR_;
+  mutable double ftranCountAfterU_;
+  mutable double btranCountInput_;
+  mutable double btranCountAfterU_;
+  mutable double btranCountAfterR_;
+  mutable double btranCountAfterL_;
+
+  /// We can roll over factorizations
+  mutable int numberFtranCounts_;
+  mutable int numberBtranCounts_;
+
+  /// While these are average ratios collected over last period
+  double ftranAverageAfterL_;
+  double ftranAverageAfterR_;
+  double ftranAverageAfterU_;
+  double btranAverageAfterU_;
+  double btranAverageAfterR_;
+  double btranAverageAfterL_;
+
+  /// For statistics 
+  mutable bool collectStatistics_;
+
+  /// Below this use sparse technology - if 0 then no L row copy
+  int sparseThreshold_;
+
+  /// And one for "sparsish"
+  int sparseThreshold2_;
+
+  /// Start of each row in L
+  CoinBigIndexArrayWithLength startRowL_;
+
+  /// Index of column in row for L
+  CoinIntArrayWithLength indexColumnL_;
+
+  /// Elements in L (row copy)
+  CoinFactorizationDoubleArrayWithLength elementByRowL_;
+
+  /// Sparse regions
+  mutable CoinIntArrayWithLength sparse_;
+  /** L to U bias
+      0 - U bias, 1 - some U bias, 2 some L bias, 3 L bias
+  */
+  int biasLU_;
+  /** Array persistence flag
+      If 0 then as now (delete/new)
+      1 then only do arrays if bigger needed
+      2 as 1 but give a bit extra if bigger needed
+  */
+  int persistenceFlag_;
+  //@}
+};
+// Dense coding
+#ifdef COIN_HAS_LAPACK
+#define DENSE_CODE 1
+/* Type of Fortran integer translated into C */
+#ifndef ipfint
+//typedef ipfint FORTRAN_INTEGER_TYPE ;
+typedef int ipfint;
+typedef const int cipfint;
+#endif
+#endif
+#endif
+// Extra for ugly include
+#ifdef UGLY_COIN_FACTOR_CODING
+#define FAC_UNSET (FAC_SET+1)
+{
+  goodPivot=false;
+  //store pivot columns (so can easily compress)
+  CoinBigIndex startColumnThis = startColumn[iPivotColumn];
+  CoinBigIndex endColumn = startColumnThis + numberDoColumn + 1;
+  int put = 0;
+  CoinBigIndex startRowThis = startRow[iPivotRow];
+  CoinBigIndex endRow = startRowThis + numberDoRow + 1;
+  if ( pivotColumnPosition < 0 ) {
+    for ( pivotColumnPosition = startRowThis; pivotColumnPosition < endRow; pivotColumnPosition++ ) {
+      int iColumn = indexColumn[pivotColumnPosition];
+      if ( iColumn != iPivotColumn ) {
+	saveColumn[put++] = iColumn;
+      } else {
+        break;
+      }
+    }
+  } else {
+    for (CoinBigIndex i = startRowThis ; i < pivotColumnPosition ; i++ ) {
+      saveColumn[put++] = indexColumn[i];
+    }
+  }
+  assert (pivotColumnPosition<endRow);
+  assert (indexColumn[pivotColumnPosition]==iPivotColumn);
+  pivotColumnPosition++;
+  for ( ; pivotColumnPosition < endRow; pivotColumnPosition++ ) {
+    saveColumn[put++] = indexColumn[pivotColumnPosition];
+  }
+  //take out this bit of indexColumn
+  int next = nextRow[iPivotRow];
+  int last = lastRow[iPivotRow];
+  
+  nextRow[last] = next;
+  lastRow[next] = last;
+  nextRow[iPivotRow] = numberGoodU_;	//use for permute
+  lastRow[iPivotRow] = -2;
+  numberInRow[iPivotRow] = 0;
+  //store column in L, compress in U and take column out
+  CoinBigIndex l = lengthL_;
+  // **** HORRID coding coming up but a goto seems best!
+  {
+    if ( l + numberDoColumn > lengthAreaL_ ) {
+      //need more memory
+      if ((messageLevel_&4)!=0) 
+	printf("more memory needed in middle of invert\n");
+      goto BAD_PIVOT;
+    }
+    //l+=currentAreaL_->elementByColumn-elementL;
+    CoinBigIndex lSave = l;
+    
+    CoinBigIndex * startColumnL = startColumnL_.array();
+    startColumnL[numberGoodL_] = l;	//for luck and first time
+    numberGoodL_++;
+    startColumnL[numberGoodL_] = l + numberDoColumn;
+    lengthL_ += numberDoColumn;
+    if ( pivotRowPosition < 0 ) {
+      for ( pivotRowPosition = startColumnThis; pivotRowPosition < endColumn; pivotRowPosition++ ) {
+	int iRow = indexRow[pivotRowPosition];
+	if ( iRow != iPivotRow ) {
+	  indexRowL[l] = iRow;
+	  elementL[l] = element[pivotRowPosition];
+	  markRow[iRow] = l - lSave;
+	  l++;
+	  //take out of row list
+	  CoinBigIndex start = startRow[iRow];
+	  CoinBigIndex end = start + numberInRow[iRow];
+	  CoinBigIndex where = start;
+	  
+	  while ( indexColumn[where] != iPivotColumn ) {
+	    where++;
+	  }			/* endwhile */
+#if DEBUG_COIN
+	  if ( where >= end ) {
+	    abort (  );
+	  }
+#endif
+	  indexColumn[where] = indexColumn[end - 1];
+	  numberInRow[iRow]--;
+	} else {
+	  break;
+	}
+      }
+    } else {
+      CoinBigIndex i;
+      
+      for ( i = startColumnThis; i < pivotRowPosition; i++ ) {
+	int iRow = indexRow[i];
+	
+	markRow[iRow] = l - lSave;
+	indexRowL[l] = iRow;
+	elementL[l] = element[i];
+	l++;
+	//take out of row list
+	CoinBigIndex start = startRow[iRow];
+	CoinBigIndex end = start + numberInRow[iRow];
+	CoinBigIndex where = start;
+	
+	while ( indexColumn[where] != iPivotColumn ) {
+	  where++;
+	}				/* endwhile */
+#if DEBUG_COIN
+	if ( where >= end ) {
+	  abort (  );
+	}
+#endif
+	indexColumn[where] = indexColumn[end - 1];
+	numberInRow[iRow]--;
+	assert (numberInRow[iRow]>=0);
+      }
+    }
+    assert (pivotRowPosition<endColumn);
+    assert (indexRow[pivotRowPosition]==iPivotRow);
+    CoinFactorizationDouble pivotElement = element[pivotRowPosition];
+    CoinFactorizationDouble pivotMultiplier = 1.0 / pivotElement;
+    
+    pivotRegion_.array()[numberGoodU_] = pivotMultiplier;
+    pivotRowPosition++;
+    for ( ; pivotRowPosition < endColumn; pivotRowPosition++ ) {
+      int iRow = indexRow[pivotRowPosition];
+      
+      markRow[iRow] = l - lSave;
+      indexRowL[l] = iRow;
+      elementL[l] = element[pivotRowPosition];
+      l++;
+      //take out of row list
+      CoinBigIndex start = startRow[iRow];
+      CoinBigIndex end = start + numberInRow[iRow];
+      CoinBigIndex where = start;
+      
+      while ( indexColumn[where] != iPivotColumn ) {
+	where++;
+      }				/* endwhile */
+#if DEBUG_COIN
+      if ( where >= end ) {
+	abort (  );
+      }
+#endif
+      indexColumn[where] = indexColumn[end - 1];
+      numberInRow[iRow]--;
+      assert (numberInRow[iRow]>=0);
+    }
+    markRow[iPivotRow] = FAC_SET;
+    //compress pivot column (move pivot to front including saved)
+    numberInColumn[iPivotColumn] = 0;
+    //use end of L for temporary space
+    int *indexL = &indexRowL[lSave];
+    CoinFactorizationDouble *multipliersL = &elementL[lSave];
+    
+    //adjust
+    int j;
+    
+    for ( j = 0; j < numberDoColumn; j++ ) {
+      multipliersL[j] *= pivotMultiplier;
+    }
+    //zero out fill
+    CoinBigIndex iErase;
+    for ( iErase = 0; iErase < increment2 * numberDoRow;
+	  iErase++ ) {
+      workArea2[iErase] = 0;
+    }
+    CoinBigIndex added = numberDoRow * numberDoColumn;
+    unsigned int *temp2 = workArea2;
+    int * nextColumn = nextColumn_.array();
+    
+    //pack down and move to work
+    int jColumn;
+    for ( jColumn = 0; jColumn < numberDoRow; jColumn++ ) {
+      int iColumn = saveColumn[jColumn];
+      CoinBigIndex startColumnThis = startColumn[iColumn];
+      CoinBigIndex endColumn = startColumnThis + numberInColumn[iColumn];
+      int iRow = indexRow[startColumnThis];
+      CoinFactorizationDouble value = element[startColumnThis];
+      double largest;
+      CoinBigIndex put = startColumnThis;
+      CoinBigIndex positionLargest = -1;
+      CoinFactorizationDouble thisPivotValue = 0.0;
+      
+      //compress column and find largest not updated
+      bool checkLargest;
+      int mark = markRow[iRow];
+      
+      if ( mark == FAC_UNSET ) {
+	largest = fabs ( value );
+	positionLargest = put;
+	put++;
+	checkLargest = false;
+      } else {
+	//need to find largest
+	largest = 0.0;
+	checkLargest = true;
+	if ( mark != FAC_SET ) {
+	  //will be updated
+	  workArea[mark] = value;
+	  int word = mark >> COINFACTORIZATION_SHIFT_PER_INT;
+	  int bit = mark & COINFACTORIZATION_MASK_PER_INT;
+	  
+	  temp2[word] = temp2[word] | ( 1 << bit );	//say already in counts
+	  added--;
+	} else {
+	  thisPivotValue = value;
+	}
+      }
+      CoinBigIndex i;
+      for ( i = startColumnThis + 1; i < endColumn; i++ ) {
+	iRow = indexRow[i];
+	value = element[i];
+	int mark = markRow[iRow];
+	
+	if ( mark == FAC_UNSET ) {
+	  //keep
+	  indexRow[put] = iRow;
+	  element[put] = value;
+	  if ( checkLargest ) {
+	    double absValue = fabs ( value );
+	    
+	    if ( absValue > largest ) {
+	      largest = absValue;
+	      positionLargest = put;
+	    }
+	  }
+	  put++;
+	} else if ( mark != FAC_SET ) {
+	  //will be updated
+	  workArea[mark] = value;
+	  int word = mark >> COINFACTORIZATION_SHIFT_PER_INT;
+	  int bit = mark & COINFACTORIZATION_MASK_PER_INT;
+	  
+	  temp2[word] = temp2[word] | ( 1 << bit );	//say already in counts
+	  added--;
+	} else {
+	  thisPivotValue = value;
+	}
+      }
+      //slot in pivot
+      element[put] = element[startColumnThis];
+      indexRow[put] = indexRow[startColumnThis];
+      if ( positionLargest == startColumnThis ) {
+	positionLargest = put;	//follow if was largest
+      }
+      put++;
+      element[startColumnThis] = thisPivotValue;
+      indexRow[startColumnThis] = iPivotRow;
+      //clean up counts
+      startColumnThis++;
+      numberInColumn[iColumn] = put - startColumnThis;
+      int * numberInColumnPlus = numberInColumnPlus_.array();
+      numberInColumnPlus[iColumn]++;
+      startColumn[iColumn]++;
+      //how much space have we got
+      int next = nextColumn[iColumn];
+      CoinBigIndex space;
+      
+      space = startColumn[next] - put - numberInColumnPlus[next];
+      //assume no zero elements
+      if ( numberDoColumn > space ) {
+	//getColumnSpace also moves fixed part
+	if ( !getColumnSpace ( iColumn, numberDoColumn ) ) {
+	  goto BAD_PIVOT;
+	}
+	//redo starts
+	positionLargest = positionLargest + startColumn[iColumn] - startColumnThis;
+	startColumnThis = startColumn[iColumn];
+	put = startColumnThis + numberInColumn[iColumn];
+      }
+      double tolerance = zeroTolerance_;
+      
+      int *nextCount = nextCount_.array();
+      for ( j = 0; j < numberDoColumn; j++ ) {
+	value = workArea[j] - thisPivotValue * multipliersL[j];
+	double absValue = fabs ( value );
+	
+	if ( absValue > tolerance ) {
+	  workArea[j] = 0.0;
+	  element[put] = value;
+	  indexRow[put] = indexL[j];
+	  if ( absValue > largest ) {
+	    largest = absValue;
+	    positionLargest = put;
+	  }
+	  put++;
+	} else {
+	  workArea[j] = 0.0;
+	  added--;
+	  int word = j >> COINFACTORIZATION_SHIFT_PER_INT;
+	  int bit = j & COINFACTORIZATION_MASK_PER_INT;
+	  
+	  if ( temp2[word] & ( 1 << bit ) ) {
+	    //take out of row list
+	    iRow = indexL[j];
+	    CoinBigIndex start = startRow[iRow];
+	    CoinBigIndex end = start + numberInRow[iRow];
+	    CoinBigIndex where = start;
+	    
+	    while ( indexColumn[where] != iColumn ) {
+	      where++;
+	    }			/* endwhile */
+#if DEBUG_COIN
+	    if ( where >= end ) {
+	      abort (  );
+	    }
+#endif
+	    indexColumn[where] = indexColumn[end - 1];
+	    numberInRow[iRow]--;
+	  } else {
+	    //make sure won't be added
+	    int word = j >> COINFACTORIZATION_SHIFT_PER_INT;
+	    int bit = j & COINFACTORIZATION_MASK_PER_INT;
+	    
+	    temp2[word] = temp2[word] | ( 1 << bit );	//say already in counts
+	  }
+	}
+      }
+      numberInColumn[iColumn] = put - startColumnThis;
+      //move largest
+      if ( positionLargest >= 0 ) {
+	value = element[positionLargest];
+	iRow = indexRow[positionLargest];
+	element[positionLargest] = element[startColumnThis];
+	indexRow[positionLargest] = indexRow[startColumnThis];
+	element[startColumnThis] = value;
+	indexRow[startColumnThis] = iRow;
+      }
+      //linked list for column
+      if ( nextCount[iColumn + numberRows_] != -2 ) {
+	//modify linked list
+	deleteLink ( iColumn + numberRows_ );
+	addLink ( iColumn + numberRows_, numberInColumn[iColumn] );
+      }
+      temp2 += increment2;
+    }
+    //get space for row list
+    unsigned int *putBase = workArea2;
+    int bigLoops = numberDoColumn >> COINFACTORIZATION_SHIFT_PER_INT;
+    int i = 0;
+    
+    // do linked lists and update counts
+    while ( bigLoops ) {
+      bigLoops--;
+      int bit;
+      for ( bit = 0; bit < COINFACTORIZATION_BITS_PER_INT; i++, bit++ ) {
+	unsigned int *putThis = putBase;
+	int iRow = indexL[i];
+	
+	//get space
+	int number = 0;
+	int jColumn;
+	
+	for ( jColumn = 0; jColumn < numberDoRow; jColumn++ ) {
+	  unsigned int test = *putThis;
+	  
+	  putThis += increment2;
+	  test = 1 - ( ( test >> bit ) & 1 );
+	  number += test;
+	}
+	int next = nextRow[iRow];
+	CoinBigIndex space;
+	
+	space = startRow[next] - startRow[iRow];
+	number += numberInRow[iRow];
+	if ( space < number ) {
+	  if ( !getRowSpace ( iRow, number ) ) {
+	    goto BAD_PIVOT;
+	  }
+	}
+	// now do
+	putThis = putBase;
+	next = nextRow[iRow];
+	number = numberInRow[iRow];
+	CoinBigIndex end = startRow[iRow] + number;
+	int saveIndex = indexColumn[startRow[next]];
+	
+	//add in
+	for ( jColumn = 0; jColumn < numberDoRow; jColumn++ ) {
+	  unsigned int test = *putThis;
+	  
+	  putThis += increment2;
+	  test = 1 - ( ( test >> bit ) & 1 );
+	  indexColumn[end] = saveColumn[jColumn];
+	  end += test;
+	}
+	//put back next one in case zapped
+	indexColumn[startRow[next]] = saveIndex;
+	markRow[iRow] = FAC_UNSET;
+	number = end - startRow[iRow];
+	numberInRow[iRow] = number;
+	deleteLink ( iRow );
+	addLink ( iRow, number );
+      }
+      putBase++;
+    }				/* endwhile */
+    int bit;
+    
+    for ( bit = 0; i < numberDoColumn; i++, bit++ ) {
+      unsigned int *putThis = putBase;
+      int iRow = indexL[i];
+      
+      //get space
+      int number = 0;
+      int jColumn;
+      
+      for ( jColumn = 0; jColumn < numberDoRow; jColumn++ ) {
+	unsigned int test = *putThis;
+	
+	putThis += increment2;
+	test = 1 - ( ( test >> bit ) & 1 );
+	number += test;
+      }
+      int next = nextRow[iRow];
+      CoinBigIndex space;
+      
+      space = startRow[next] - startRow[iRow];
+      number += numberInRow[iRow];
+      if ( space < number ) {
+	if ( !getRowSpace ( iRow, number ) ) {
+	  goto BAD_PIVOT;
+	}
+      }
+      // now do
+      putThis = putBase;
+      next = nextRow[iRow];
+      number = numberInRow[iRow];
+      CoinBigIndex end = startRow[iRow] + number;
+      int saveIndex;
+      
+      saveIndex = indexColumn[startRow[next]];
+      
+      //add in
+      for ( jColumn = 0; jColumn < numberDoRow; jColumn++ ) {
+	unsigned int test = *putThis;
+	
+	putThis += increment2;
+	test = 1 - ( ( test >> bit ) & 1 );
+	
+	indexColumn[end] = saveColumn[jColumn];
+	end += test;
+      }
+      indexColumn[startRow[next]] = saveIndex;
+      markRow[iRow] = FAC_UNSET;
+      number = end - startRow[iRow];
+      numberInRow[iRow] = number;
+      deleteLink ( iRow );
+      addLink ( iRow, number );
+    }
+    markRow[iPivotRow] = FAC_UNSET;
+    //modify linked list for pivots
+    deleteLink ( iPivotRow );
+    deleteLink ( iPivotColumn + numberRows_ );
+    totalElements_ += added;
+    goodPivot= true;
+    // **** UGLY UGLY UGLY
+  }
+ BAD_PIVOT:
+
+  ;
+}
+#undef FAC_UNSET
+#endif
diff --git a/cbits/coin/CoinFactorization1.cpp b/cbits/coin/CoinFactorization1.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFactorization1.cpp
@@ -0,0 +1,2425 @@
+/* $Id: CoinFactorization1.cpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinUtilsConfig.h"
+
+#include <cassert>
+#include "CoinFactorization.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinFinite.hpp"
+#include <stdio.h>
+//:class CoinFactorization.  Deals with Factorization and Updates
+//  CoinFactorization.  Constructor
+CoinFactorization::CoinFactorization (  )
+{
+  persistenceFlag_=0;
+  gutsOfInitialize(7);
+}
+
+/// Copy constructor 
+CoinFactorization::CoinFactorization ( const CoinFactorization &other)
+{
+  persistenceFlag_=0;
+  gutsOfInitialize(3);
+  persistenceFlag_=other.persistenceFlag_;
+  gutsOfCopy(other);
+}
+/// The real work of constructors etc
+/// Really really delete if type 2
+void CoinFactorization::gutsOfDestructor(int type)
+{
+  delete [] denseArea_;
+  delete [] densePermute_;
+  if (type==2) {
+    elementU_.switchOff();
+    startRowU_.switchOff();
+    convertRowToColumnU_.switchOff();
+    indexRowU_.switchOff();
+    indexColumnU_.switchOff();
+    startColumnU_.switchOff();
+    elementL_.switchOff();
+    indexRowL_.switchOff();
+    startColumnL_.switchOff();
+    startColumnR_.switchOff();
+    numberInRow_.switchOff();
+    numberInColumn_.switchOff();
+    numberInColumnPlus_.switchOff();
+    pivotColumn_.switchOff();
+    pivotColumnBack_.switchOff();
+    firstCount_.switchOff();
+    nextCount_.switchOff();
+    lastCount_.switchOff();
+    permute_.switchOff();
+    permuteBack_.switchOff();
+    nextColumn_.switchOff();
+    lastColumn_.switchOff();
+    nextRow_.switchOff();
+    lastRow_.switchOff();
+    saveColumn_.switchOff();
+    markRow_.switchOff();
+    pivotRowL_.switchOff();
+    pivotRegion_.switchOff();
+    elementByRowL_.switchOff();
+    startRowL_.switchOff();
+    indexColumnL_.switchOff();
+    sparse_.switchOff();
+    workArea_.switchOff();
+    workArea2_.switchOff();
+  }
+  elementU_.conditionalDelete();
+  startRowU_.conditionalDelete();
+  convertRowToColumnU_.conditionalDelete();
+  indexRowU_.conditionalDelete();
+  indexColumnU_.conditionalDelete();
+  startColumnU_.conditionalDelete();
+  elementL_.conditionalDelete();
+  indexRowL_.conditionalDelete();
+  startColumnL_.conditionalDelete();
+  startColumnR_.conditionalDelete();
+  numberInRow_.conditionalDelete();
+  numberInColumn_.conditionalDelete();
+  numberInColumnPlus_.conditionalDelete();
+  pivotColumn_.conditionalDelete();
+  pivotColumnBack_.conditionalDelete();
+  firstCount_.conditionalDelete();
+  nextCount_.conditionalDelete();
+  lastCount_.conditionalDelete();
+  permute_.conditionalDelete();
+  permuteBack_.conditionalDelete();
+  nextColumn_.conditionalDelete();
+  lastColumn_.conditionalDelete();
+  nextRow_.conditionalDelete();
+  lastRow_.conditionalDelete();
+  saveColumn_.conditionalDelete();
+  markRow_.conditionalDelete();
+  pivotRowL_.conditionalDelete();
+  pivotRegion_.conditionalDelete();
+  elementByRowL_.conditionalDelete();
+  startRowL_.conditionalDelete();
+  indexColumnL_.conditionalDelete();
+  sparse_.conditionalDelete();
+  workArea_.conditionalDelete();
+  workArea2_.conditionalDelete();
+  numberCompressions_ = 0;
+  biggerDimension_ = 0;
+  numberRows_ = 0;
+  numberRowsExtra_ = 0;
+  maximumRowsExtra_ = 0;
+  numberColumns_ = 0;
+  numberColumnsExtra_ = 0;
+  maximumColumnsExtra_ = 0;
+  numberGoodU_ = 0;
+  numberGoodL_ = 0;
+  totalElements_ = 0;
+  factorElements_ = 0;
+  status_ = -1;
+  numberSlacks_ = 0;
+  numberU_ = 0;
+  maximumU_=0;
+  lengthU_ = 0;
+  lengthAreaU_ = 0;
+  numberL_ = 0;
+  baseL_ = 0;
+  lengthL_ = 0;
+  lengthAreaL_ = 0;
+  numberR_ = 0;
+  lengthR_ = 0;
+  lengthAreaR_ = 0;
+  denseArea_=NULL;
+  densePermute_=NULL;
+  // next two offsets but this makes cleaner
+  elementR_=NULL;
+  indexRowR_=NULL;
+  numberDense_=0;
+  //persistenceFlag_=0;
+  ////denseThreshold_=0;
+  
+}
+// type - 1 bit tolerances etc, 2 rest
+void CoinFactorization::gutsOfInitialize(int type)
+{
+  if ((type&2)!=0) {
+    numberCompressions_ = 0;
+    biggerDimension_ = 0;
+    numberRows_ = 0;
+    numberRowsExtra_ = 0;
+    maximumRowsExtra_ = 0;
+    numberColumns_ = 0;
+    numberColumnsExtra_ = 0;
+    maximumColumnsExtra_ = 0;
+    numberGoodU_ = 0;
+    numberGoodL_ = 0;
+    totalElements_ = 0;
+    factorElements_ = 0;
+    status_ = -1;
+    numberPivots_ = 0;
+    numberSlacks_ = 0;
+    numberU_ = 0;
+    maximumU_=0;
+    lengthU_ = 0;
+    lengthAreaU_ = 0;
+    numberL_ = 0;
+    baseL_ = 0;
+    lengthL_ = 0;
+    lengthAreaL_ = 0;
+    numberR_ = 0;
+    lengthR_ = 0;
+    lengthAreaR_ = 0;
+    elementR_ = NULL;
+    indexRowR_ = NULL;
+    // always switch off sparse
+    sparseThreshold_=0;
+    sparseThreshold2_= 0;
+    denseArea_ = NULL;
+    densePermute_=NULL;
+    numberDense_=0;
+    if (!persistenceFlag_) {
+      workArea_=CoinFactorizationDoubleArrayWithLength();
+      workArea2_=CoinUnsignedIntArrayWithLength();
+      pivotColumn_=CoinIntArrayWithLength();
+    }
+  }
+  // after 2 because of persistenceFlag_
+  if ((type&1)!=0) {
+    areaFactor_ = 0.0;
+    pivotTolerance_ = 1.0e-1;
+    zeroTolerance_ = 1.0e-13;
+#ifndef COIN_FAST_CODE
+    slackValue_ = -1.0;
+#endif
+    messageLevel_=0;
+    maximumPivots_=200;
+    numberTrials_ = 4;
+    relaxCheck_=1.0;
+#if DENSE_CODE==1
+    denseThreshold_=31;
+    denseThreshold_=71;
+#else
+    denseThreshold_=0;
+#endif
+    biasLU_=2;
+    doForrestTomlin_=true;
+    persistenceFlag_=0;
+  }
+  if ((type&4)!=0) {
+    // we need to get 1 element arrays for any with length n+1 !!
+    startColumnL_.conditionalNew (1);
+    startColumnR_.conditionalNew( 1 );
+    startRowU_.conditionalNew(1);
+    numberInRow_.conditionalNew(1);
+    nextRow_.conditionalNew(1);
+    lastRow_.conditionalNew( 1 );
+    pivotRegion_.conditionalNew(1);
+    permuteBack_.conditionalNew(1);
+    permute_.conditionalNew(1);
+    pivotColumnBack_.conditionalNew(1);
+    startColumnU_.conditionalNew( 1 );
+    numberInColumn_.conditionalNew(1);
+    numberInColumnPlus_.conditionalNew(1);
+    pivotColumn_.conditionalNew(1);
+    nextColumn_.conditionalNew(1);
+    lastColumn_.conditionalNew(1);
+    collectStatistics_=false;
+    
+    // Below are all to collect
+    ftranCountInput_=0.0;
+    ftranCountAfterL_=0.0;
+    ftranCountAfterR_=0.0;
+    ftranCountAfterU_=0.0;
+    btranCountInput_=0.0;
+    btranCountAfterU_=0.0;
+    btranCountAfterR_=0.0;
+    btranCountAfterL_=0.0;
+    
+    // We can roll over factorizations
+    numberFtranCounts_=0;
+    numberBtranCounts_=0;
+    
+    // While these are averages collected over last 
+    ftranAverageAfterL_=0;
+    ftranAverageAfterR_=0;
+    ftranAverageAfterU_=0;
+    btranAverageAfterU_=0;
+    btranAverageAfterR_=0;
+    btranAverageAfterL_=0; 
+#ifdef ZEROFAULT
+    startColumnL_.array()[0] = 0;
+    startColumnR_.array()[0] = 0;
+    startRowU_.array()[0] = 0;
+    numberInRow_.array()[0] = 0;
+    nextRow_.array()[0] = 0;
+    lastRow_.array()[0] = 0;
+    pivotRegion_.array()[0] = 0.0;
+    permuteBack_.array()[0] = 0;
+    permute_.array()[0] = 0;
+    pivotColumnBack_.array()[0] = 0;
+    startColumnU_.array()[0] = 0;
+    numberInColumn_.array()[0] = 0;
+    numberInColumnPlus_.array()[0] = 0;
+    pivotColumn_.array()[0] = 0;
+    nextColumn_.array()[0] = 0;
+    lastColumn_.array()[0] = 0;
+#endif
+  }
+}
+//Part of LP
+int CoinFactorization::factorize (
+				 const CoinPackedMatrix & matrix,
+				 int rowIsBasic[],
+				 int columnIsBasic[],
+				 double areaFactor )
+{
+  // maybe for speed will be better to leave as many regions as possible
+  gutsOfDestructor();
+  gutsOfInitialize(2);
+  // ? is this correct
+  //if (biasLU_==2)
+  //biasLU_=3;
+  if (areaFactor)
+    areaFactor_ = areaFactor;
+  const int * row = matrix.getIndices();
+  const CoinBigIndex * columnStart = matrix.getVectorStarts();
+  const int * columnLength = matrix.getVectorLengths(); 
+  const double * element = matrix.getElements();
+  int numberRows=matrix.getNumRows();
+  int numberColumns=matrix.getNumCols();
+  int numberBasic = 0;
+  CoinBigIndex numberElements=0;
+  int numberRowBasic=0;
+
+  // compute how much in basis
+
+  int i;
+
+  for (i=0;i<numberRows;i++) {
+    if (rowIsBasic[i]>=0)
+      numberRowBasic++;
+  }
+
+  numberBasic = numberRowBasic;
+
+  for (i=0;i<numberColumns;i++) {
+    if (columnIsBasic[i]>=0) {
+      numberBasic++;
+      numberElements += columnLength[i];
+    }
+  }
+  if ( numberBasic > numberRows ) {
+    return -2; // say too many in basis
+  }
+  numberElements = 3 * numberBasic + 3 * numberElements + 20000;
+  getAreas ( numberRows, numberBasic, numberElements,
+	     2 * numberElements );
+  //fill
+  //copy
+  numberBasic=0;
+  numberElements=0;
+  int * indexColumnU = indexColumnU_.array();
+  int * indexRowU = indexRowU_.array();
+  CoinFactorizationDouble * elementU = elementU_.array();
+  for (i=0;i<numberRows;i++) {
+    if (rowIsBasic[i]>=0) {
+      indexRowU[numberElements]=i;
+      indexColumnU[numberElements]=numberBasic;
+      elementU[numberElements++]=slackValue_;
+      numberBasic++;
+    }
+  }
+  for (i=0;i<numberColumns;i++) {
+    if (columnIsBasic[i]>=0) {
+      CoinBigIndex j;
+      for (j=columnStart[i];j<columnStart[i]+columnLength[i];j++) {
+	indexRowU[numberElements]=row[j];
+	indexColumnU[numberElements]=numberBasic;
+	elementU[numberElements++]=element[j];
+      }
+      numberBasic++;
+    }
+  }
+  lengthU_ = numberElements;
+  maximumU_ = numberElements;
+
+  preProcess ( 0 );
+  factor (  );
+  numberBasic=0;
+  if (status_ == 0) {
+    int * permuteBack = permuteBack_.array();
+    int * back = pivotColumnBack();
+    for (i=0;i<numberRows;i++) {
+      if (rowIsBasic[i]>=0) {
+	rowIsBasic[i]=permuteBack[back[numberBasic++]];
+      }
+    }
+    for (i=0;i<numberColumns;i++) {
+      if (columnIsBasic[i]>=0) {
+	columnIsBasic[i]=permuteBack[back[numberBasic++]];
+      }
+    }
+    // Set up permutation vector
+    // these arrays start off as copies of permute
+    // (and we could use permute_ instead of pivotColumn (not back though))
+    CoinMemcpyN ( permute_.array(), numberRows_ , pivotColumn_.array()  );
+    CoinMemcpyN ( permuteBack_.array(), numberRows_ , pivotColumnBack()  );
+  } else if (status_ == -1) {
+    const int * pivotColumn = pivotColumn_.array();
+    // mark as basic or non basic
+    for (i=0;i<numberRows_;i++) {
+      if (rowIsBasic[i]>=0) {
+	if (pivotColumn[numberBasic]>=0) 
+	  rowIsBasic[i]=pivotColumn[numberBasic];
+	else 
+	  rowIsBasic[i]=-1;
+	numberBasic++;
+      }
+    }
+    for (i=0;i<numberColumns;i++) {
+      if (columnIsBasic[i]>=0) {
+	if (pivotColumn[numberBasic]>=0) 
+	  columnIsBasic[i]=pivotColumn[numberBasic];
+	 else 
+	  columnIsBasic[i]=-1;
+	numberBasic++;
+      }
+    }
+  }
+
+  return status_;
+}
+//Given as triplets
+int CoinFactorization::factorize (
+			     int numberOfRows,
+			     int numberOfColumns,
+			     CoinBigIndex numberOfElements,
+			     CoinBigIndex maximumL,
+			     CoinBigIndex maximumU,
+			     const int indicesRow[],
+			     const int indicesColumn[],
+			     const double elements[] ,
+			     int permutation[],
+			     double areaFactor)
+{
+  gutsOfDestructor();
+  gutsOfInitialize(2);
+  if (areaFactor)
+    areaFactor_ = areaFactor;
+  getAreas ( numberOfRows, numberOfColumns, maximumL, maximumU );
+  //copy
+  CoinMemcpyN ( indicesRow, numberOfElements, indexRowU_.array() );
+  CoinMemcpyN ( indicesColumn, numberOfElements, indexColumnU_.array() );
+  int i;
+  CoinFactorizationDouble * elementU = elementU_.array();
+  for (i=0;i<numberOfElements;i++)
+    elementU[i] = elements[i];
+  lengthU_ = numberOfElements;
+  maximumU_ = numberOfElements;
+  preProcess ( 0 );
+  factor (  );
+  //say which column is pivoting on which row
+  if (status_ == 0) {
+    int * permuteBack = permuteBack_.array();
+    int * back = pivotColumnBack();
+    // permute so slacks on own rows etc
+    for (i=0;i<numberOfColumns;i++) {
+      permutation[i]=permuteBack[back[i]];
+    }
+    // Set up permutation vector
+    // these arrays start off as copies of permute
+    // (and we could use permute_ instead of pivotColumn (not back though))
+    CoinMemcpyN ( permute_.array(), numberRows_ , pivotColumn_.array()  );
+    CoinMemcpyN ( permuteBack_.array(), numberRows_ , pivotColumnBack()  );
+  } else if (status_ == -1) {
+    const int * pivotColumn = pivotColumn_.array();
+    // mark as basic or non basic
+    for (i=0;i<numberOfColumns;i++) {
+      if (pivotColumn[i]>=0) {
+	permutation[i]=pivotColumn[i];
+      } else {
+	permutation[i]=-1;
+      }
+    }
+  }
+
+  return status_;
+}
+/* Two part version for flexibility
+   This part creates arrays for user to fill.
+   maximumL is guessed maximum size of L part of
+   final factorization, maximumU of U part.  These are multiplied by
+   areaFactor which can be computed by user or internally.  
+   returns 0 -okay, -99 memory */
+int 
+CoinFactorization::factorizePart1 ( int numberOfRows,
+				   int ,
+				   CoinBigIndex numberOfElements,
+				   int * indicesRow[],
+				   int * indicesColumn[],
+				   CoinFactorizationDouble * elements[],
+				   double areaFactor)
+{
+  // maybe for speed will be better to leave as many regions as possible
+  gutsOfDestructor();
+  gutsOfInitialize(2);
+  if (areaFactor)
+    areaFactor_ = areaFactor;
+  CoinBigIndex numberElements = 3 * numberOfRows + 3 * numberOfElements + 20000;
+  getAreas ( numberOfRows, numberOfRows, numberElements,
+	     2 * numberElements );
+  // need to trap memory for -99 code
+  *indicesRow = indexRowU_.array() ;
+  *indicesColumn = indexColumnU_.array() ;
+  *elements = elementU_.array() ;
+  lengthU_ = numberOfElements;
+  maximumU_ = numberElements;
+  return 0;
+}
+/* This is part two of factorization
+   Arrays belong to factorization and were returned by part 1
+   If status okay, permutation has pivot rows.
+   If status is singular, then basic variables have +1 and ones thrown out have -COIN_INT_MAX
+   to say thrown out.
+   returns 0 -okay, -1 singular, -99 memory */
+int 
+CoinFactorization::factorizePart2 (int permutation[],int exactNumberElements)
+{
+  lengthU_ = exactNumberElements;
+  preProcess ( 0 );
+  factor (  );
+  //say which column is pivoting on which row
+  int i;
+  int * permuteBack = permuteBack_.array();
+  int * back = pivotColumnBack();
+  // permute so slacks on own rows etc
+  for (i=0;i<numberColumns_;i++) {
+    permutation[i]=permuteBack[back[i]];
+  }
+  if (status_ == 0) {
+    // Set up permutation vector
+    // these arrays start off as copies of permute
+    // (and we could use permute_ instead of pivotColumn (not back though))
+    CoinMemcpyN ( permute_.array(), numberRows_ , pivotColumn_.array()  );
+    CoinMemcpyN ( permuteBack_.array(), numberRows_ , pivotColumnBack()  );
+  } else if (status_ == -1) {
+    const int * pivotColumn = pivotColumn_.array();
+    // mark as basic or non basic
+    for (i=0;i<numberColumns_;i++) {
+      if (pivotColumn[i]>=0) {
+	permutation[i]=pivotColumn[i];
+      } else {
+	permutation[i]=-1;
+      }
+    }
+  }
+
+  return status_;
+}
+
+//  ~CoinFactorization.  Destructor
+CoinFactorization::~CoinFactorization (  )
+{
+  gutsOfDestructor(2);
+}
+
+//  show_self.  Debug show object
+void
+CoinFactorization::show_self (  ) const
+{
+  int i;
+
+  const int * pivotColumn = pivotColumn_.array();
+  for ( i = 0; i < numberRows_; i++ ) {
+    std::cout << "r " << i << " " << pivotColumn[i];
+    if (pivotColumnBack()) std::cout<< " " << pivotColumnBack()[i];
+    std::cout<< " " << permute_.array()[i];
+    if (permuteBack_.array()) std::cout<< " " << permuteBack_.array()[i];
+    std::cout<< " " << pivotRegion_.array()[i];
+    std::cout << std::endl;
+  }
+  for ( i = 0; i < numberRows_; i++ ) {
+    std::cout << "u " << i << " " << numberInColumn_.array()[i] << std::endl;
+    int j;
+    CoinSort_2(indexRowU_.array()+startColumnU_.array()[i],
+	       indexRowU_.array()+startColumnU_.array()[i]+numberInColumn_.array()[i],
+	       elementU_.array()+startColumnU_.array()[i]);
+    for ( j = startColumnU_.array()[i]; j < startColumnU_.array()[i] + numberInColumn_.array()[i];
+	  j++ ) {
+      assert (indexRowU_.array()[j]>=0&&indexRowU_.array()[j]<numberRows_);
+      assert (elementU_.array()[j]>-1.0e50&&elementU_.array()[j]<1.0e50);
+      std::cout << indexRowU_.array()[j] << " " << elementU_.array()[j] << std::endl;
+    }
+  }
+  for ( i = 0; i < numberRows_; i++ ) {
+    std::cout << "l " << i << " " << startColumnL_.array()[i + 1] -
+      startColumnL_.array()[i] << std::endl;
+    CoinSort_2(indexRowL_.array()+startColumnL_.array()[i],
+	       indexRowL_.array()+startColumnL_.array()[i+1],
+	       elementL_.array()+startColumnL_.array()[i]);
+    int j;
+    for ( j = startColumnL_.array()[i]; j < startColumnL_.array()[i + 1]; j++ ) {
+      std::cout << indexRowL_.array()[j] << " " << elementL_.array()[j] << std::endl;
+    }
+  }
+
+}
+//  sort so can compare
+void
+CoinFactorization::sort (  ) const
+{
+  int i;
+
+  for ( i = 0; i < numberRows_; i++ ) {
+    CoinSort_2(indexRowU_.array()+startColumnU_.array()[i],
+	       indexRowU_.array()+startColumnU_.array()[i]+numberInColumn_.array()[i],
+	       elementU_.array()+startColumnU_.array()[i]);
+  }
+  for ( i = 0; i < numberRows_; i++ ) {
+    CoinSort_2(indexRowL_.array()+startColumnL_.array()[i],
+	       indexRowL_.array()+startColumnL_.array()[i+1],
+	       elementL_.array()+startColumnL_.array()[i]);
+  }
+
+}
+
+//  getAreas.  Gets space for a factorization
+//called by constructors
+void
+CoinFactorization::getAreas ( int numberOfRows,
+			 int numberOfColumns,
+			 CoinBigIndex maximumL,
+			 CoinBigIndex maximumU )
+{
+  
+  numberRows_ = numberOfRows;
+  numberColumns_ = numberOfColumns;
+  maximumRowsExtra_ = numberRows_ + maximumPivots_;
+  numberRowsExtra_ = numberRows_;
+  maximumColumnsExtra_ = numberColumns_ + maximumPivots_;
+  numberColumnsExtra_ = numberColumns_;
+  lengthAreaU_ = maximumU;
+  lengthAreaL_ = maximumL;
+  if ( !areaFactor_ ) {
+    areaFactor_ = 1.0;
+  }
+  if ( areaFactor_ != 1.0 ) {
+    if ((messageLevel_&16)!=0) 
+      printf("Increasing factorization areas by %g\n",areaFactor_);
+    lengthAreaU_ =  static_cast<CoinBigIndex> (areaFactor_*lengthAreaU_);
+    lengthAreaL_ =  static_cast<CoinBigIndex> (areaFactor_*lengthAreaL_);
+  }
+  elementU_.conditionalNew( lengthAreaU_ );
+  indexRowU_.conditionalNew( lengthAreaU_ );
+  indexColumnU_.conditionalNew( lengthAreaU_ );
+  elementL_.conditionalNew( lengthAreaL_ );
+  indexRowL_.conditionalNew( lengthAreaL_ );
+  if (persistenceFlag_) {
+    // But we can use all we have if bigger
+    int length;
+    length = CoinMin(elementU_.getSize(),indexRowU_.getSize());
+    if (length>lengthAreaU_) {
+      lengthAreaU_=length;
+      assert (indexColumnU_.getSize()==indexRowU_.getSize());
+    }
+    length = CoinMin(elementL_.getSize(),indexRowL_.getSize());
+    if (length>lengthAreaL_) {
+      lengthAreaL_=length;
+    }
+  }
+  startColumnL_.conditionalNew( numberRows_ + 1 );
+  startColumnL_.array()[0] = 0;
+  startRowU_.conditionalNew( maximumRowsExtra_ + 1);
+  // make sure this is valid
+  startRowU_.array()[maximumRowsExtra_]=0;
+  numberInRow_.conditionalNew( maximumRowsExtra_ + 1 );
+  markRow_.conditionalNew( numberRows_ );
+  pivotRowL_.conditionalNew( numberRows_ + 1 );
+  nextRow_.conditionalNew( maximumRowsExtra_ + 1 );
+  lastRow_.conditionalNew( maximumRowsExtra_ + 1 );
+  permute_.conditionalNew( maximumRowsExtra_ + 1 );
+  pivotRegion_.conditionalNew( maximumRowsExtra_ + 1 );
+#ifdef ZEROFAULT
+  memset(elementU_.array(),'a',lengthAreaU_*sizeof(CoinFactorizationDouble));
+  memset(indexRowU_.array(),'b',lengthAreaU_*sizeof(int));
+  memset(indexColumnU_.array(),'c',lengthAreaU_*sizeof(int));
+  memset(elementL_.array(),'d',lengthAreaL_*sizeof(CoinFactorizationDouble));
+  memset(indexRowL_.array(),'e',lengthAreaL_*sizeof(int));
+  memset(startColumnL_.array()+1,'f',numberRows_*sizeof(CoinBigIndex));
+  memset(startRowU_.array(),'g',maximumRowsExtra_*sizeof(CoinBigIndex));
+  memset(numberInRow_.array(),'h',(maximumRowsExtra_+1)*sizeof(int));
+  memset(markRow_.array(),'i',numberRows_*sizeof(int));
+  memset(pivotRowL_.array(),'j',(numberRows_+1)*sizeof(int));
+  memset(nextRow_.array(),'k',(maximumRowsExtra_+1)*sizeof(int));
+  memset(lastRow_.array(),'l',(maximumRowsExtra_+1)*sizeof(int));
+  memset(permute_.array(),'l',(maximumRowsExtra_+1)*sizeof(int));
+  memset(pivotRegion_.array(),'m',(maximumRowsExtra_+1)*sizeof(CoinFactorizationDouble));
+#endif
+  startColumnU_.conditionalNew( maximumColumnsExtra_ + 1 );
+  numberInColumn_.conditionalNew( maximumColumnsExtra_ + 1 );
+  numberInColumnPlus_.conditionalNew( maximumColumnsExtra_ + 1 );
+  pivotColumn_.conditionalNew( maximumColumnsExtra_ + 1 );
+  nextColumn_.conditionalNew( maximumColumnsExtra_ + 1 );
+  lastColumn_.conditionalNew( maximumColumnsExtra_ + 1 );
+  saveColumn_.conditionalNew( numberColumns_);
+#ifdef ZEROFAULT
+  memset(startColumnU_.array(),'a',(maximumColumnsExtra_+1)*sizeof(CoinBigIndex));
+  memset(numberInColumn_.array(),'b',(maximumColumnsExtra_+1)*sizeof(int));
+  memset(numberInColumnPlus_.array(),'c',(maximumColumnsExtra_+1)*sizeof(int));
+  memset(pivotColumn_.array(),'d',(maximumColumnsExtra_+1)*sizeof(int));
+  memset(nextColumn_.array(),'e',(maximumColumnsExtra_+1)*sizeof(int));
+  memset(lastColumn_.array(),'f',(maximumColumnsExtra_+1)*sizeof(int));
+#endif
+  if ( numberRows_ + numberColumns_ ) {
+    if ( numberRows_ > numberColumns_ ) {
+      biggerDimension_ = numberRows_;
+    } else {
+      biggerDimension_ = numberColumns_;
+    }
+    firstCount_.conditionalNew( CoinMax(biggerDimension_ + 2, maximumRowsExtra_+1) );
+    nextCount_.conditionalNew( numberRows_ + numberColumns_ );
+    lastCount_.conditionalNew( numberRows_ + numberColumns_ );
+#ifdef ZEROFAULT
+    memset(firstCount_.array(),'g',(biggerDimension_ + 2 )*sizeof(int));
+    memset(nextCount_.array(),'h',(numberRows_+numberColumns_)*sizeof(int));
+    memset(lastCount_.array(),'i',(numberRows_+numberColumns_)*sizeof(int));
+#endif
+  } else {
+    firstCount_.conditionalNew( 2 );
+    nextCount_.conditionalNew( 0 );
+    lastCount_.conditionalNew( 0 );
+#ifdef ZEROFAULT
+    memset(firstCount_.array(),'g', 2 *sizeof(int));
+#endif
+    biggerDimension_ = 0;
+  }
+}
+
+//  preProcess.  PreProcesses raw triplet data
+//state is 0 - triplets, 1 - some counts etc , 2 - ..
+void
+CoinFactorization::preProcess ( int state,
+			   int )
+{
+  int *indexRow = indexRowU_.array();
+  int *indexColumn = indexColumnU_.array();
+  CoinFactorizationDouble *element = elementU_.array();
+  CoinBigIndex numberElements = lengthU_;
+  int *numberInRow = numberInRow_.array();
+  int *numberInColumn = numberInColumn_.array();
+  int *numberInColumnPlus = numberInColumnPlus_.array();
+  CoinBigIndex *startRow = startRowU_.array();
+  CoinBigIndex *startColumn = startColumnU_.array();
+  int numberRows = numberRows_;
+  int numberColumns = numberColumns_;
+
+  if (state<4)
+    totalElements_ = numberElements;
+  //state falls through to next state
+  switch ( state ) {
+  case 0:			//counts
+    {
+      CoinZeroN ( numberInRow, numberRows + 1 );
+      CoinZeroN ( numberInColumn, maximumColumnsExtra_ + 1 );
+      CoinBigIndex i;
+      for ( i = 0; i < numberElements; i++ ) {
+	int iRow = indexRow[i];
+	int iColumn = indexColumn[i];
+
+	numberInRow[iRow]++;
+	numberInColumn[iColumn]++;
+      }
+    }
+  case -1:			//sort
+  case 1:			//sort
+    {
+      CoinBigIndex i, k;
+
+      i = 0;
+      int iColumn;
+      for ( iColumn = 0; iColumn < numberColumns; iColumn++ ) {
+	//position after end of Column
+	i += numberInColumn[iColumn];
+	startColumn[iColumn] = i;
+      }
+      for ( k = numberElements - 1; k >= 0; k-- ) {
+	int iColumn = indexColumn[k];
+
+	if ( iColumn >= 0 ) {
+	  CoinFactorizationDouble value = element[k];
+	  int iRow = indexRow[k];
+
+	  indexColumn[k] = -1;
+	  while ( true ) {
+	    CoinBigIndex iLook = startColumn[iColumn] - 1;
+
+	    startColumn[iColumn] = iLook;
+	    CoinFactorizationDouble valueSave = element[iLook];
+	    int iColumnSave = indexColumn[iLook];
+	    int iRowSave = indexRow[iLook];
+
+	    element[iLook] = value;
+	    indexRow[iLook] = iRow;
+	    indexColumn[iLook] = -1;
+	    if ( iColumnSave >= 0 ) {
+	      iColumn = iColumnSave;
+	      value = valueSave;
+	      iRow = iRowSave;
+	    } else {
+	      break;
+	    }
+	  }			/* endwhile */
+	}
+      }
+    }
+  case 2:			//move largest in column to beginning
+    //and do row part
+    {
+      CoinBigIndex i, k;
+
+      i = 0;
+      int iRow;
+      for ( iRow = 0; iRow < numberRows; iRow++ ) {
+	startRow[iRow] = i;
+	i += numberInRow[iRow];
+      }
+      CoinZeroN ( numberInRow, numberRows );
+      int iColumn;
+      for ( iColumn = 0; iColumn < numberColumns; iColumn++ ) {
+	int number = numberInColumn[iColumn];
+
+	if ( number ) {
+	  CoinBigIndex first = startColumn[iColumn];
+	  CoinBigIndex largest = first;
+	  int iRowSave = indexRow[first];
+	  CoinFactorizationDouble valueSave = element[first];
+	  double valueLargest = fabs ( valueSave );
+	  int iLook = numberInRow[iRowSave];
+
+	  numberInRow[iRowSave] = iLook + 1;
+	  indexColumn[startRow[iRowSave] + iLook] = iColumn;
+	  for ( k = first + 1; k < first + number; k++ ) {
+	    int iRow = indexRow[k];
+	    int iLook = numberInRow[iRow];
+
+	    numberInRow[iRow] = iLook + 1;
+	    indexColumn[startRow[iRow] + iLook] = iColumn;
+	    CoinFactorizationDouble value = element[k];
+	    double valueAbs = fabs ( value );
+
+	    if ( valueAbs > valueLargest ) {
+	      valueLargest = valueAbs;
+	      largest = k;
+	    }
+	  }
+	  indexRow[first] = indexRow[largest];
+	  element[first] = element[largest];
+	  indexRow[largest] = iRowSave;
+	  element[largest] = valueSave;
+	}
+      }
+    }
+  case 3:			//links and initialize pivots
+    {
+      int *lastRow = lastRow_.array();
+      int *nextRow = nextRow_.array();
+      int *lastColumn = lastColumn_.array();
+      int *nextColumn = nextColumn_.array();
+
+      CoinFillN ( firstCount_.array(), biggerDimension_ + 2, -1 );
+      CoinFillN ( pivotColumn_.array(), numberColumns_, -1 );
+      CoinZeroN ( numberInColumnPlus, maximumColumnsExtra_ + 1 );
+      int iRow;
+      for ( iRow = 0; iRow < numberRows; iRow++ ) {
+	lastRow[iRow] = iRow - 1;
+	nextRow[iRow] = iRow + 1;
+	int number = numberInRow[iRow];
+
+	addLink ( iRow, number );
+      }
+      lastRow[maximumRowsExtra_] = numberRows - 1;
+      nextRow[maximumRowsExtra_] = 0;
+      lastRow[0] = maximumRowsExtra_;
+      nextRow[numberRows - 1] = maximumRowsExtra_;
+      startRow[maximumRowsExtra_] = numberElements;
+      int iColumn;
+      for ( iColumn = 0; iColumn < numberColumns; iColumn++ ) {
+	lastColumn[iColumn] = iColumn - 1;
+	nextColumn[iColumn] = iColumn + 1;
+	int number = numberInColumn[iColumn];
+
+	addLink ( iColumn + numberRows, number );
+      }
+      lastColumn[maximumColumnsExtra_] = numberColumns - 1;
+      nextColumn[maximumColumnsExtra_] = 0;
+      lastColumn[0] = maximumColumnsExtra_;
+      if (numberColumns)
+	nextColumn[numberColumns - 1] = maximumColumnsExtra_;
+      startColumn[maximumColumnsExtra_] = numberElements;
+    }
+    break;
+  case 4:			//move largest in column to beginning
+    {
+      CoinBigIndex i, k;
+      CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+      int iColumn;
+      int iRow;
+      for ( iRow = 0; iRow < numberRows; iRow++ ) {
+	if( numberInRow[iRow]>=0) {
+	  // zero count
+	  numberInRow[iRow]=0;
+	} else {
+	  // empty
+	  //numberInRow[iRow]=-1; already that
+	}
+      }
+      //CoinZeroN ( numberInColumnPlus, maximumColumnsExtra_ + 1 );
+      for ( iColumn = 0; iColumn < numberColumns; iColumn++ ) {
+	int number = numberInColumn[iColumn];
+
+	if ( number ) {
+	  // use pivotRegion and startRow for remaining elements
+	  CoinBigIndex first = startColumn[iColumn];
+	  CoinBigIndex largest = -1;
+	  
+	  double valueLargest = -1.0;
+	  int nOther=0;
+	  k = first;
+	  CoinBigIndex end = first+number;
+	  for (  ; k < end; k++ ) {
+	    int iRow = indexRow[k];
+	    assert (iRow<numberRows_);
+	    CoinFactorizationDouble value = element[k];
+	    if (numberInRow[iRow]>=0) {
+	      numberInRow[iRow]++;
+	      double valueAbs = fabs ( value );
+	      if ( valueAbs > valueLargest ) {
+		valueLargest = valueAbs;
+		largest = nOther;
+	      }
+	      startRow[nOther]=iRow;
+	      pivotRegion[nOther++]=value;
+	    } else {
+	      indexRow[first] = iRow;
+	      element[first++] = value;
+	    }
+	  }
+	  numberInColumnPlus[iColumn]=first-startColumn[iColumn];
+	  startColumn[iColumn]=first;
+	  //largest
+	  if (largest>=0) {
+	    indexRow[first] = startRow[largest];
+	    element[first++] = pivotRegion[largest];
+	  }
+	  for (k=0;k<nOther;k++) {
+	    if (k!=largest) {
+	      indexRow[first] = startRow[k];
+	      element[first++] = pivotRegion[k];
+	    }
+	  }
+	  numberInColumn[iColumn]=first-startColumn[iColumn];
+	}
+      }
+      //and do row part
+      i = 0;
+      for ( iRow = 0; iRow < numberRows; iRow++ ) {
+	startRow[iRow] = i;
+	int n=numberInRow[iRow];
+	if (n>0) {
+	  numberInRow[iRow]=0;
+	  i += n;
+	}
+      }
+      for ( iColumn = 0; iColumn < numberColumns; iColumn++ ) {
+	int number = numberInColumn[iColumn];
+
+	if ( number ) {
+	  CoinBigIndex first = startColumn[iColumn];
+	  for ( k = first; k < first + number; k++ ) {
+	    int iRow = indexRow[k];
+	    int iLook = numberInRow[iRow];
+
+	    numberInRow[iRow] = iLook + 1;
+	    indexColumn[startRow[iRow] + iLook] = iColumn;
+	  }
+	}
+      }
+    }
+    // modified 3
+    {
+      //set markRow so no rows updated
+      //CoinFillN ( markRow_.array(), numberRows_, -1 );
+      int *lastColumn = lastColumn_.array();
+      int *nextColumn = nextColumn_.array();
+      CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+
+      int iRow;
+      int numberGood=0;
+      startColumnL_.array()[0] = 0;	//for luck
+      for ( iRow = 0; iRow < numberRows; iRow++ ) {
+	int number = numberInRow[iRow];
+	if (number<0) {
+	  numberInRow[iRow]=0;
+	  pivotRegion[numberGood++]=slackValue_;
+	}
+      }
+      int iColumn;
+      for ( iColumn = 0 ; iColumn < numberColumns_; iColumn++ ) {
+	lastColumn[iColumn] = iColumn - 1;
+	nextColumn[iColumn] = iColumn + 1;
+	int number = numberInColumn[iColumn];
+	deleteLink(iColumn+numberRows);
+	addLink ( iColumn + numberRows, number );
+      }
+      lastColumn[maximumColumnsExtra_] = numberColumns - 1;
+      nextColumn[maximumColumnsExtra_] = 0;
+      lastColumn[0] = maximumColumnsExtra_;
+      if (numberColumns)
+	nextColumn[numberColumns - 1] = maximumColumnsExtra_;
+      startColumn[maximumColumnsExtra_] = numberElements;
+    }
+  }				/* endswitch */
+}
+
+//Does most of factorization
+int
+CoinFactorization::factor (  )
+{
+  int * lastColumn = lastColumn_.array();
+  int * lastRow = lastRow_.array();
+  //sparse
+  status_ = factorSparse (  );
+  switch ( status_ ) {
+  case 0:			//finished
+    totalElements_ = 0;
+    {
+      int * pivotColumn = pivotColumn_.array();
+      if ( numberGoodU_ < numberRows_ ) {
+	int i, k;
+	// Clean out unset nextRow
+	int * nextRow = nextRow_.array();
+	//int nSing =0;
+	k=nextRow[maximumRowsExtra_];
+	while (k!=maximumRowsExtra_ && k>=0) {
+	  int iRow = k;
+	  k=nextRow[k];
+	  //nSing++;
+	  nextRow[iRow]=-1;
+	}
+	//assert (nSing);
+	//printf("%d singularities - good %d rows %d\n",nSing,
+	//     numberGoodU_,numberRows_);
+	// Now nextRow has -1 or sequence into numberGoodU_;
+	int * permuteA = permute_.array();
+	for ( i = 0; i < numberRows_; i++ ) {
+	  int iGood= nextRow[i];
+	  if (iGood>=0)
+	    permuteA[iGood]=i;
+	}
+
+	// swap arrays
+	permute_.swap(nextRow_);
+	int * permute = permute_.array();
+	for ( i = 0; i < numberRows_; i++ ) {
+	  lastRow[i] = -1;
+	}
+	for ( i = 0; i < numberColumns_; i++ ) {
+	  lastColumn[i] = -1;
+	}
+	for ( i = 0; i < numberGoodU_; i++ ) {
+	  int goodRow = permuteA[i];	//valid pivot row
+	  int goodColumn = pivotColumn[i];
+
+	  lastRow[goodRow] = goodColumn;	//will now have -1 or column sequence
+	  lastColumn[goodColumn] = goodRow;	//will now have -1 or row sequence
+	}
+	nextRow_.conditionalDelete();
+	k = 0;
+	//copy back and count
+	for ( i = 0; i < numberRows_; i++ ) {
+	  permute[i] = lastRow[i];
+	  if ( permute[i] < 0 ) {
+	    //std::cout << i << " " <<permute[i] << std::endl;
+	  } else {
+	    k++;
+	  }
+	}
+	for ( i = 0; i < numberColumns_; i++ ) {
+	  pivotColumn[i] = lastColumn[i];
+	}
+	if ((messageLevel_&4)!=0) 
+	  std::cout <<"Factorization has "<<numberRows_-k
+		    <<" singularities"<<std::endl;
+	status_ = -1;
+      }
+    }
+    break;
+    // dense
+  case 2:
+    status_=factorDense();
+    if(!status_) 
+      break;
+  default:
+    //singular ? or some error
+    if ((messageLevel_&4)!=0) 
+      std::cout << "Error " << status_ << std::endl;
+    break;
+  }				/* endswitch */
+  //clean up
+  if ( !status_ ) {
+    if ( (messageLevel_ & 16)&&numberCompressions_)
+      std::cout<<"        Factorization did "<<numberCompressions_
+	       <<" compressions"<<std::endl;
+    if ( numberCompressions_ > 10 ) {
+      areaFactor_ *= 1.1;
+    }
+    numberCompressions_=0;
+    cleanup (  );
+  }
+  return status_;
+}
+
+
+//  pivotRowSingleton.  Does one pivot on Row Singleton in factorization
+bool
+CoinFactorization::pivotRowSingleton ( int pivotRow,
+				  int pivotColumn )
+{
+  //store pivot columns (so can easily compress)
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  CoinBigIndex startColumn = startColumnU[pivotColumn];
+  int * numberInRow = numberInRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int numberDoColumn = numberInColumn[pivotColumn] - 1;
+  CoinBigIndex endColumn = startColumn + numberDoColumn + 1;
+  CoinBigIndex pivotRowPosition = startColumn;
+  int * indexRowU = indexRowU_.array();
+  int iRow = indexRowU[pivotRowPosition];
+  CoinBigIndex * startRowU = startRowU_.array();
+  int * nextRow = nextRow_.array();
+  int * lastRow = lastRow_.array();
+
+  while ( iRow != pivotRow ) {
+    pivotRowPosition++;
+    iRow = indexRowU[pivotRowPosition];
+  }				/* endwhile */
+  assert ( pivotRowPosition < endColumn );
+  //store column in L, compress in U and take column out
+  CoinBigIndex l = lengthL_;
+
+  if ( l + numberDoColumn > lengthAreaL_ ) {
+    //need more memory
+    if ((messageLevel_&4)!=0) 
+      std::cout << "more memory needed in middle of invert" << std::endl;
+    return false;
+  }
+  CoinBigIndex * startColumnL = startColumnL_.array();
+  CoinFactorizationDouble * elementL = elementL_.array();
+  int * indexRowL = indexRowL_.array();
+  startColumnL[numberGoodL_] = l;	//for luck and first time
+  numberGoodL_++;
+  startColumnL[numberGoodL_] = l + numberDoColumn;
+  lengthL_ += numberDoColumn;
+  CoinFactorizationDouble *elementU = elementU_.array();
+  CoinFactorizationDouble pivotElement = elementU[pivotRowPosition];
+  CoinFactorizationDouble pivotMultiplier = 1.0 / pivotElement;
+
+  pivotRegion_.array()[numberGoodU_] = pivotMultiplier;
+  CoinBigIndex i;
+
+  int * indexColumnU = indexColumnU_.array();
+  for ( i = startColumn; i < pivotRowPosition; i++ ) {
+    int iRow = indexRowU[i];
+
+    indexRowL[l] = iRow;
+    elementL[l] = elementU[i] * pivotMultiplier;
+    l++;
+    //take out of row list
+    CoinBigIndex start = startRowU[iRow];
+    int iNumberInRow = numberInRow[iRow];
+    CoinBigIndex end = start + iNumberInRow;
+    CoinBigIndex where = start;
+
+    while ( indexColumnU[where] != pivotColumn ) {
+      where++;
+    }				/* endwhile */
+    assert ( where < end );
+    indexColumnU[where] = indexColumnU[end - 1];
+    iNumberInRow--;
+    numberInRow[iRow] = iNumberInRow;
+    deleteLink ( iRow );
+    addLink ( iRow, iNumberInRow );
+  }
+  for ( i = pivotRowPosition + 1; i < endColumn; i++ ) {
+    int iRow = indexRowU[i];
+
+    indexRowL[l] = iRow;
+    elementL[l] = elementU[i] * pivotMultiplier;
+    l++;
+    //take out of row list
+    CoinBigIndex start = startRowU[iRow];
+    int iNumberInRow = numberInRow[iRow];
+    CoinBigIndex end = start + iNumberInRow;
+    CoinBigIndex where = start;
+
+    while ( indexColumnU[where] != pivotColumn ) {
+      where++;
+    }				/* endwhile */
+    assert ( where < end );
+    indexColumnU[where] = indexColumnU[end - 1];
+    iNumberInRow--;
+    numberInRow[iRow] = iNumberInRow;
+    deleteLink ( iRow );
+    addLink ( iRow, iNumberInRow );
+  }
+  numberInColumn[pivotColumn] = 0;
+  //modify linked list for pivots
+  numberInRow[pivotRow] = 0;
+  deleteLink ( pivotRow );
+  deleteLink ( pivotColumn + numberRows_ );
+  //take out this bit of indexColumnU
+  int next = nextRow[pivotRow];
+  int last = lastRow[pivotRow];
+
+  nextRow[last] = next;
+  lastRow[next] = last;
+  lastRow[pivotRow] =-2;
+  nextRow[pivotRow] = numberGoodU_;	//use for permute
+  return true;
+}
+
+//  pivotColumnSingleton.  Does one pivot on Column Singleton in factorization
+bool
+CoinFactorization::pivotColumnSingleton ( int pivotRow,
+				     int pivotColumn )
+{
+  int * numberInRow = numberInRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int * numberInColumnPlus = numberInColumnPlus_.array();
+  //store pivot columns (so can easily compress)
+  int numberDoRow = numberInRow[pivotRow] - 1;
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  CoinBigIndex startColumn = startColumnU[pivotColumn];
+  int put = 0;
+  CoinBigIndex * startRowU = startRowU_.array();
+  CoinBigIndex startRow = startRowU[pivotRow];
+  CoinBigIndex endRow = startRow + numberDoRow + 1;
+  int * indexColumnU = indexColumnU_.array();
+  int * indexRowU = indexRowU_.array();
+  int * saveColumn = saveColumn_.array();
+  CoinBigIndex i;
+
+  for ( i = startRow; i < endRow; i++ ) {
+    int iColumn = indexColumnU[i];
+
+    if ( iColumn != pivotColumn ) {
+      saveColumn[put++] = iColumn;
+    }
+  }
+  int * nextRow = nextRow_.array();
+  int * lastRow = lastRow_.array();
+  //take out this bit of indexColumnU
+  int next = nextRow[pivotRow];
+  int last = lastRow[pivotRow];
+
+  nextRow[last] = next;
+  lastRow[next] = last;
+  nextRow[pivotRow] = numberGoodU_;	//use for permute
+  lastRow[pivotRow] =-2; //mark
+  //clean up counts
+  CoinFactorizationDouble *elementU = elementU_.array();
+  CoinFactorizationDouble pivotElement = elementU[startColumn];
+
+  pivotRegion_.array()[numberGoodU_] = 1.0 / pivotElement;
+  numberInColumn[pivotColumn] = 0;
+  //totalElements_ --;
+  //numberInColumnPlus[pivotColumn]++;
+  //move pivot row in other columns to safe zone
+  for ( i = 0; i < numberDoRow; i++ ) {
+    int iColumn = saveColumn[i];
+
+    if ( numberInColumn[iColumn] ) {
+      int number = numberInColumn[iColumn] - 1;
+
+      //modify linked list
+      deleteLink ( iColumn + numberRows_ );
+      addLink ( iColumn + numberRows_, number );
+      //move pivot row element
+      if ( number ) {
+	CoinBigIndex start = startColumnU[iColumn];
+	CoinBigIndex pivot = start;
+	int iRow = indexRowU[pivot];
+	while ( iRow != pivotRow ) {
+	  pivot++;
+	  iRow = indexRowU[pivot];
+	}
+        assert (pivot < startColumnU[iColumn] +
+                numberInColumn[iColumn]);
+	if ( pivot != start ) {
+	  //move largest one up
+	  CoinFactorizationDouble value = elementU[start];
+
+	  iRow = indexRowU[start];
+	  elementU[start] = elementU[pivot];
+	  indexRowU[start] = indexRowU[pivot];
+	  elementU[pivot] = elementU[start + 1];
+	  indexRowU[pivot] = indexRowU[start + 1];
+	  elementU[start + 1] = value;
+	  indexRowU[start + 1] = iRow;
+	} else {
+	  //find new largest element
+	  int iRowSave = indexRowU[start + 1];
+	  CoinFactorizationDouble valueSave = elementU[start + 1];
+	  double valueLargest = fabs ( valueSave );
+	  CoinBigIndex end = start + numberInColumn[iColumn];
+	  CoinBigIndex largest = start + 1;
+
+	  CoinBigIndex k;
+	  for ( k = start + 2; k < end; k++ ) {
+	    CoinFactorizationDouble value = elementU[k];
+	    double valueAbs = fabs ( value );
+
+	    if ( valueAbs > valueLargest ) {
+	      valueLargest = valueAbs;
+	      largest = k;
+	    }
+	  }
+	  indexRowU[start + 1] = indexRowU[largest];
+	  elementU[start + 1] = elementU[largest];
+	  indexRowU[largest] = iRowSave;
+	  elementU[largest] = valueSave;
+	}
+      }
+      //clean up counts
+      numberInColumn[iColumn]--;
+      numberInColumnPlus[iColumn]++;
+      startColumnU[iColumn]++;
+      //totalElements_--;
+    }
+  }
+  //modify linked list for pivots
+  deleteLink ( pivotRow );
+  deleteLink ( pivotColumn + numberRows_ );
+  numberInRow[pivotRow] = 0;
+  //put in dummy pivot in L
+  CoinBigIndex l = lengthL_;
+
+  CoinBigIndex * startColumnL = startColumnL_.array();
+  startColumnL[numberGoodL_] = l;	//for luck and first time
+  numberGoodL_++;
+  startColumnL[numberGoodL_] = l;
+  return true;
+}
+
+
+//  getColumnSpace.  Gets space for one Column with given length
+//may have to do compression  (returns true)
+//also moves existing vector
+bool
+CoinFactorization::getColumnSpace ( int iColumn,
+			       int extraNeeded )
+{
+  int * numberInColumn = numberInColumn_.array();
+  int * numberInColumnPlus = numberInColumnPlus_.array();
+  int * nextColumn = nextColumn_.array();
+  int * lastColumn = lastColumn_.array();
+  int number = numberInColumnPlus[iColumn] +
+    numberInColumn[iColumn];
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  CoinBigIndex space = lengthAreaU_ - startColumnU[maximumColumnsExtra_];
+  CoinFactorizationDouble *elementU = elementU_.array();
+  int * indexRowU = indexRowU_.array();
+
+  if ( space < extraNeeded + number + 4 ) {
+    //compression
+    int iColumn = nextColumn[maximumColumnsExtra_];
+    CoinBigIndex put = 0;
+
+    while ( iColumn != maximumColumnsExtra_ ) {
+      //move
+      CoinBigIndex get;
+      CoinBigIndex getEnd;
+
+      if ( startColumnU[iColumn] >= 0 ) {
+	get = startColumnU[iColumn]
+	  - numberInColumnPlus[iColumn];
+	getEnd = startColumnU[iColumn] + numberInColumn[iColumn];
+	startColumnU[iColumn] = put + numberInColumnPlus[iColumn];
+      } else {
+	get = -startColumnU[iColumn];
+	getEnd = get + numberInColumn[iColumn];
+	startColumnU[iColumn] = -put;
+      }
+      CoinBigIndex i;
+      for ( i = get; i < getEnd; i++ ) {
+	indexRowU[put] = indexRowU[i];
+	elementU[put] = elementU[i];
+	put++;
+      }
+      iColumn = nextColumn[iColumn];
+    }				/* endwhile */
+    numberCompressions_++;
+    startColumnU[maximumColumnsExtra_] = put;
+    space = lengthAreaU_ - put;
+    if ( extraNeeded == COIN_INT_MAX >> 1 ) {
+      return true;
+    }
+    if ( space < extraNeeded + number + 2 ) {
+      //need more space
+      //if we can allocate bigger then do so and copy
+      //if not then return so code can start again
+      status_ = -99;
+      return false;
+    }
+  }
+  CoinBigIndex put = startColumnU[maximumColumnsExtra_];
+  int next = nextColumn[iColumn];
+  int last = lastColumn[iColumn];
+
+  if ( extraNeeded || next != maximumColumnsExtra_ ) {
+    //out
+    nextColumn[last] = next;
+    lastColumn[next] = last;
+    //in at end
+    last = lastColumn[maximumColumnsExtra_];
+    nextColumn[last] = iColumn;
+    lastColumn[maximumColumnsExtra_] = iColumn;
+    lastColumn[iColumn] = last;
+    nextColumn[iColumn] = maximumColumnsExtra_;
+    //move
+    CoinBigIndex get = startColumnU[iColumn]
+      - numberInColumnPlus[iColumn];
+
+    startColumnU[iColumn] = put + numberInColumnPlus[iColumn];
+    if ( number < 50 ) {
+      int *indexRow = indexRowU;
+      CoinFactorizationDouble *element = elementU;
+      int i = 0;
+
+      if ( ( number & 1 ) != 0 ) {
+	element[put] = element[get];
+	indexRow[put] = indexRow[get];
+	i = 1;
+      }
+      for ( ; i < number; i += 2 ) {
+	CoinFactorizationDouble value0 = element[get + i];
+	CoinFactorizationDouble value1 = element[get + i + 1];
+	int index0 = indexRow[get + i];
+	int index1 = indexRow[get + i + 1];
+
+	element[put + i] = value0;
+	element[put + i + 1] = value1;
+	indexRow[put + i] = index0;
+	indexRow[put + i + 1] = index1;
+      }
+    } else {
+      CoinMemcpyN ( &indexRowU[get], number, &indexRowU[put] );
+      CoinMemcpyN ( &elementU[get], number, &elementU[put] );
+    }
+    put += number;
+    get += number;
+    //add 2 for luck
+    startColumnU[maximumColumnsExtra_] = put + extraNeeded + 2;
+    if (startColumnU[maximumColumnsExtra_]>lengthAreaU_) {
+      // get more memory
+#ifdef CLP_DEVELOP
+      printf("put %d, needed %d, start %d, length %d\n",
+	     put,extraNeeded,startColumnU[maximumColumnsExtra_],
+	     lengthAreaU_);
+#endif
+      return false;
+    }
+  } else {
+    //take off space
+    startColumnU[maximumColumnsExtra_] = startColumnU[last] +
+      numberInColumn[last];
+  }
+  return true;
+}
+
+//  getRowSpace.  Gets space for one Row with given length
+//may have to do compression  (returns true)
+//also moves existing vector
+bool
+CoinFactorization::getRowSpace ( int iRow,
+			    int extraNeeded )
+{
+  int * numberInRow = numberInRow_.array();
+  int number = numberInRow[iRow];
+  CoinBigIndex * startRowU = startRowU_.array();
+  CoinBigIndex space = lengthAreaU_ - startRowU[maximumRowsExtra_];
+  int * nextRow = nextRow_.array();
+  int * lastRow = lastRow_.array();
+  int * indexColumnU = indexColumnU_.array();
+
+  if ( space < extraNeeded + number + 2 ) {
+    //compression
+    int iRow = nextRow[maximumRowsExtra_];
+    CoinBigIndex put = 0;
+
+    while ( iRow != maximumRowsExtra_ ) {
+      //move
+      CoinBigIndex get = startRowU[iRow];
+      CoinBigIndex getEnd = startRowU[iRow] + numberInRow[iRow];
+
+      startRowU[iRow] = put;
+      CoinBigIndex i;
+      for ( i = get; i < getEnd; i++ ) {
+	indexColumnU[put] = indexColumnU[i];
+	put++;
+      }
+      iRow = nextRow[iRow];
+    }				/* endwhile */
+    numberCompressions_++;
+    startRowU[maximumRowsExtra_] = put;
+    space = lengthAreaU_ - put;
+    if ( space < extraNeeded + number + 2 ) {
+      //need more space
+      //if we can allocate bigger then do so and copy
+      //if not then return so code can start again
+      status_ = -99;
+      return false;;
+    }
+  }
+  CoinBigIndex put = startRowU[maximumRowsExtra_];
+  int next = nextRow[iRow];
+  int last = lastRow[iRow];
+
+  //out
+  nextRow[last] = next;
+  lastRow[next] = last;
+  //in at end
+  last = lastRow[maximumRowsExtra_];
+  nextRow[last] = iRow;
+  lastRow[maximumRowsExtra_] = iRow;
+  lastRow[iRow] = last;
+  nextRow[iRow] = maximumRowsExtra_;
+  //move
+  CoinBigIndex get = startRowU[iRow];
+
+  startRowU[iRow] = put;
+  while ( number ) {
+    number--;
+    indexColumnU[put] = indexColumnU[get];
+    put++;
+    get++;
+  }				/* endwhile */
+  //add 4 for luck
+  startRowU[maximumRowsExtra_] = put + extraNeeded + 4;
+  return true;
+}
+
+#if COIN_ONE_ETA_COPY
+/* Reorders U so contiguous and in order (if there is space)
+   Returns true if it could */
+bool 
+CoinFactorization::reorderU()
+{
+#if 1
+  return false;
+#else
+  if (numberRows_!=numberColumns_)
+    return false;
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int * numberInColumnPlus = numberInColumnPlus_.array();
+  int iColumn;
+  CoinBigIndex put = 0;
+  for (iColumn =0;iColumn<numberRows_;iColumn++) 
+    put += numberInColumnPlus[iColumn];
+  CoinBigIndex space = lengthAreaU_ - startColumnU[maximumColumnsExtra_];
+  if (space<put) {
+    //printf("Space %d out of %d - needed %d\n",
+    //   space,lengthAreaU_,put);
+    return false;
+  }
+  int *indexRowU = indexRowU_.array();
+  CoinFactorizationDouble *elementU = elementU_.array();
+  int * pivotColumn = pivotColumn_.array();
+  put = startColumnU[maximumColumnsExtra_];
+  for (int jColumn =0;jColumn<numberRows_;jColumn++) {
+    iColumn = pivotColumn[jColumn];
+    int n = numberInColumnPlus[iColumn];
+    CoinBigIndex getEnd = startColumnU[iColumn];
+    CoinBigIndex get = getEnd - n;
+    startColumnU[iColumn] = put;
+    numberInColumn[jColumn]=n;
+    CoinBigIndex i;
+    for ( i = get; i < getEnd; i++ ) {
+      indexRowU[put] = indexRowU[i];
+      elementU[put] = elementU[i];
+      put++;
+    }
+  }
+  // and pack down
+  put = 0;
+  for (int jColumn =0;jColumn<numberRows_;jColumn++) {
+    iColumn = pivotColumn[jColumn];
+    int n = numberInColumn[jColumn];
+    CoinBigIndex get = startColumnU[iColumn];
+    CoinBigIndex getEnd = get+n;
+    CoinBigIndex i;
+    for ( i = get; i < getEnd; i++ ) {
+      indexRowU[put] = indexRowU[i];
+      elementU[put] = elementU[i];
+      put++;
+    }
+  }
+  put=0;
+  for (iColumn =0;iColumn<numberRows_;iColumn++) { 
+    int n = numberInColumn[iColumn];
+    startColumnU[iColumn]=put;
+    put += n;
+    //numberInColumnPlus[iColumn]=n;
+    //numberInColumn[iColumn]=0; // necessary?
+    //pivotColumn[iColumn]=iColumn;
+  }
+#if 0
+  // reset nextColumn - probably not necessary
+  int * nextColumn = nextColumn_.array();
+  nextColumn[maximumColumnsExtra_]=0;
+  nextColumn[numberRows_-1] = maximumColumnsExtra_;
+  for (iColumn=0;iColumn<numberRows_-1;iColumn++)
+    nextColumn[iColumn]=iColumn+1;
+  // swap arrays
+  numberInColumn_.swap(numberInColumnPlus_);
+#endif
+  //return false;
+  return true;
+#endif
+}
+#endif
+//  cleanup.  End of factorization
+void
+CoinFactorization::cleanup (  )
+{
+#if COIN_ONE_ETA_COPY
+  bool compressDone = reorderU();
+  if (!compressDone) {
+    getColumnSpace ( 0, COIN_INT_MAX >> 1 );	//compress
+    // swap arrays
+    numberInColumn_.swap(numberInColumnPlus_);
+  }
+#else
+  getColumnSpace ( 0, COIN_INT_MAX >> 1 );	//compress
+  // swap arrays
+    numberInColumn_.swap(numberInColumnPlus_);
+#endif
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  CoinBigIndex lastU = startColumnU[maximumColumnsExtra_];
+
+  //free some memory here
+  saveColumn_.conditionalDelete();
+  markRow_.conditionalDelete() ;
+  //firstCount_.conditionalDelete() ;
+  nextCount_.conditionalDelete() ;
+  lastCount_.conditionalDelete() ;
+  int * numberInRow = numberInRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int * numberInColumnPlus = numberInColumnPlus_.array();
+  //make column starts OK
+  //for best cache behavior get in order (last pivot at bottom of space)
+  //that will need thinking about
+  //use nextRow for permutation  (as that is what it is)
+  int i;
+
+#ifndef NDEBUG
+  {
+    if (numberGoodU_<numberRows_)
+      abort();
+    char * mark = new char[numberRows_];
+    memset(mark,0,numberRows_);
+    int * array;
+    array = nextRow_.array();
+    for ( i = 0; i < numberRows_; i++ ) {
+      int k = array[i];
+      if(k<0||k>=numberRows_)
+	printf("Bad a %d %d\n",i,k);
+      assert(k>=0&&k<numberRows_);
+      if(mark[k]==1)
+	printf("Bad a %d %d\n",i,k);
+      mark[k]=1;
+    }
+    for ( i = 0; i < numberRows_; i++ ) {
+      assert(mark[i]==1);
+      if(mark[i]!=1)
+	printf("Bad b %d\n",i);
+    }
+    delete [] mark;
+  }
+#endif
+  // swap arrays
+  permute_.swap(nextRow_);
+  //safety feature
+  int * permute = permute_.array();
+  permute[numberRows_] = 0;
+  permuteBack_.conditionalNew( maximumRowsExtra_ + 1);
+  int * permuteBack = permuteBack_.array();
+#ifdef ZEROFAULT
+  memset(permuteBack_.array(),'w',(maximumRowsExtra_+1)*sizeof(int));
+#endif
+  for ( i = 0; i < numberRows_; i++ ) {
+    int iRow = permute[i];
+
+    permuteBack[iRow] = i;
+  }
+  //redo nextRow_
+
+#ifndef NDEBUG
+  for ( i = 0; i < numberRows_; i++ ) {
+    assert (permute[i]>=0&&permute[i]<numberRows_);
+    assert (permuteBack[i]>=0&&permuteBack[i]<numberRows_);
+  }
+#endif
+#if COIN_ONE_ETA_COPY
+  if (!compressDone) {
+#endif
+    // Redo total elements
+    totalElements_=0;
+    for ( i = 0; i < numberColumns_; i++ ) {
+      int number = numberInColumn[i];
+      totalElements_ += number;
+      startColumnU[i] -= number;
+    }
+#if COIN_ONE_ETA_COPY
+  }
+#endif
+  int numberU = 0;
+
+  pivotColumnBack_.conditionalNew( maximumRowsExtra_ + 1);
+#ifdef ZEROFAULT
+  memset(pivotColumnBack(),'q',(maximumRowsExtra_+1)*sizeof(int));
+#endif
+  const int * pivotColumn = pivotColumn_.array();
+  int * pivotColumnB = pivotColumnBack();
+  int *indexColumnU = indexColumnU_.array();
+  CoinBigIndex *startColumn = startColumnU;
+  int *indexRowU = indexRowU_.array();
+  CoinFactorizationDouble *elementU = elementU_.array();
+#if COIN_ONE_ETA_COPY
+  if (!compressDone) {
+#endif
+    for ( i = 0; i < numberColumns_; i++ ) {
+      int iColumn = pivotColumn[i];
+      
+      pivotColumnB[iColumn] = i;
+      if ( iColumn >= 0 ) {
+	//wanted
+	if ( numberU != iColumn ) {
+	  numberInColumnPlus[iColumn] = numberU;
+	} else {
+	  numberInColumnPlus[iColumn] = -1;	//already in correct place
+	}
+	numberU++;
+      }
+    }
+    for ( i = 0; i < numberColumns_; i++ ) {
+      int number = numberInColumn[i];	//always 0?
+      int where = numberInColumnPlus[i];
+      
+      numberInColumnPlus[i] = -1;
+      CoinBigIndex start = startColumnU[i];
+      
+      while ( where >= 0 ) {
+	//put where it should be
+	int numberNext = numberInColumn[where];	//always 0?
+	int whereNext = numberInColumnPlus[where];
+	CoinBigIndex startNext = startColumnU[where];
+	
+	numberInColumn[where] = number;
+	numberInColumnPlus[where] = -1;
+	startColumnU[where] = start;
+	number = numberNext;
+	where = whereNext;
+	start = startNext;
+      }				/* endwhile */
+    }
+    //sort - using indexColumn
+    CoinFillN ( indexColumnU_.array(), lastU, -1 );
+    CoinBigIndex k = 0;
+    
+    for ( i = numberSlacks_; i < numberRows_; i++ ) {
+      CoinBigIndex start = startColumn[i];
+      CoinBigIndex end = start + numberInColumn[i];
+      
+      CoinBigIndex j;
+      for ( j = start; j < end; j++ ) {
+	indexColumnU[j] = k++;
+      }
+    }
+    for ( i = numberSlacks_; i < numberRows_; i++ ) {
+      CoinBigIndex start = startColumn[i];
+      CoinBigIndex end = start + numberInColumn[i];
+      
+      CoinBigIndex j;
+      for ( j = start; j < end; j++ ) {
+	CoinBigIndex k = indexColumnU[j];
+	int iRow = indexRowU[j];
+	CoinFactorizationDouble element = elementU[j];
+	
+	while ( k != -1 ) {
+	  CoinBigIndex kNext = indexColumnU[k];
+	  int iRowNext = indexRowU[k];
+	  CoinFactorizationDouble elementNext = elementU[k];
+	  
+	  indexColumnU[k] = -1;
+	  indexRowU[k] = iRow;
+	  elementU[k] = element;
+	  k = kNext;
+	  iRow = iRowNext;
+	  element = elementNext;
+	}				/* endwhile */
+      }
+    }
+    CoinZeroN ( startColumnU, numberSlacks_ );
+    k = 0;
+    for ( i = numberSlacks_; i < numberRows_; i++ ) {
+      startColumnU[i] = k;
+      k += numberInColumn[i];
+    }
+    maximumU_=k;
+#if COIN_ONE_ETA_COPY
+  } else {
+    // U already OK
+    for ( i = 0; i < numberColumns_; i++ ) {
+      int iColumn = pivotColumn[i];
+      pivotColumnB[iColumn] = i;
+    }
+    maximumU_=startColumnU[numberRows_-1]+
+      numberInColumn[numberRows_-1];
+    numberU=numberRows_;
+  }
+#endif
+  if ( (messageLevel_ & 8)) {
+    std::cout<<"        length of U "<<totalElements_<<", length of L "<<lengthL_;
+    if (numberDense_)
+      std::cout<<" plus "<<numberDense_*numberDense_<<" from "<<numberDense_<<" dense rows";
+    std::cout<<std::endl;
+  }
+  // and add L and dense
+  totalElements_ += numberDense_*numberDense_+lengthL_;
+  int * nextColumn = nextColumn_.array();
+  int * lastColumn = lastColumn_.array();
+  // See whether to have extra copy of R
+  if (maximumU_>10*numberRows_||numberRows_<200) {
+    // NO
+    numberInColumnPlus_.conditionalDelete() ;
+  } else {
+    for ( i = 0; i < numberColumns_; i++ ) {
+      lastColumn[i] = i - 1;
+      nextColumn[i] = i + 1;
+      numberInColumnPlus[i]=0;
+    }
+    nextColumn[numberColumns_ - 1] = maximumColumnsExtra_;
+    lastColumn[maximumColumnsExtra_] = numberColumns_ - 1;
+    nextColumn[maximumColumnsExtra_] = 0;
+    lastColumn[0] = maximumColumnsExtra_;
+  }
+  numberU_ = numberU;
+  numberGoodU_ = numberU;
+  numberL_ = numberGoodL_;
+#if COIN_DEBUG
+  for ( i = 0; i < numberRows_; i++ ) {
+    if ( permute[i] < 0 ) {
+      std::cout << i << std::endl;
+      abort (  );
+    }
+  }
+#endif
+  CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+  for ( i = numberSlacks_; i < numberU; i++ ) {
+    CoinBigIndex start = startColumnU[i];
+    CoinBigIndex end = start + numberInColumn[i];
+
+    totalElements_ += numberInColumn[i];
+    CoinBigIndex j;
+
+    for ( j = start; j < end; j++ ) {
+      int iRow = indexRowU[j];
+      iRow = permute[iRow];
+      indexRowU[j] = iRow;
+      numberInRow[iRow]++;
+    }
+  }
+#if COIN_ONE_ETA_COPY
+  if (numberRows_>=COIN_ONE_ETA_COPY) {
+#endif
+    //space for cross reference
+    convertRowToColumnU_.conditionalNew( lengthAreaU_ );
+    CoinBigIndex *convertRowToColumn = convertRowToColumnU_.array();
+    CoinBigIndex j = 0;
+    CoinBigIndex *startRow = startRowU_.array();
+    
+    int iRow;
+    for ( iRow = 0; iRow < numberRows_; iRow++ ) {
+      startRow[iRow] = j;
+      j += numberInRow[iRow];
+    }
+    CoinBigIndex numberInU = j;
+    
+    CoinZeroN ( numberInRow_.array(), numberRows_ );
+    
+    for ( i = numberSlacks_; i < numberRows_; i++ ) {
+      CoinBigIndex start = startColumnU[i];
+      CoinBigIndex end = start + numberInColumn[i];
+      
+      CoinFactorizationDouble pivotValue = pivotRegion[i];
+
+      CoinBigIndex j;
+      for ( j = start; j < end; j++ ) {
+	int iRow = indexRowU[j];
+	int iLook = numberInRow[iRow];
+	
+	numberInRow[iRow] = iLook + 1;
+	CoinBigIndex k = startRow[iRow] + iLook;
+	
+	indexColumnU[k] = i;
+	convertRowToColumn[k] = j;
+	//multiply by pivot
+	elementU[j] *= pivotValue;
+      }
+    }
+    int * nextRow = nextRow_.array();
+    int * lastRow = lastRow_.array();
+    for ( j = 0; j < numberRows_; j++ ) {
+      lastRow[j] = j - 1;
+      nextRow[j] = j + 1;
+    }
+    nextRow[numberRows_ - 1] = maximumRowsExtra_;
+    lastRow[maximumRowsExtra_] = numberRows_ - 1;
+    nextRow[maximumRowsExtra_] = 0;
+    lastRow[0] = maximumRowsExtra_;
+    startRow[maximumRowsExtra_] = numberInU;
+#if COIN_ONE_ETA_COPY
+  } else {
+    // no row copy
+    for ( i = numberSlacks_; i < numberU; i++ ) {
+      CoinBigIndex start = startColumnU[i];
+      CoinBigIndex end = start + numberInColumn[i];
+      
+      CoinBigIndex j;
+      CoinFactorizationDouble pivotValue = pivotRegion[i];
+      
+      for ( j = start; j < end; j++ ) {
+	//multiply by pivot
+	elementU[j] *= pivotValue;
+      }
+    }
+  }
+#endif
+
+  int firstReal = numberRows_;
+
+  CoinBigIndex * startColumnL = startColumnL_.array();
+  int * indexRowL = indexRowL_.array();
+  for ( i = numberRows_ - 1; i >= 0; i-- ) {
+    CoinBigIndex start = startColumnL[i];
+    CoinBigIndex end = startColumnL[i + 1];
+
+    totalElements_ += end - start;
+    if ( end > start ) {
+      firstReal = i;
+      CoinBigIndex j;
+      for ( j = start; j < end; j++ ) {
+	int iRow = indexRowL[j];
+	iRow = permute[iRow];
+	assert (iRow>firstReal);
+	indexRowL[j] = iRow;
+      }
+    }
+  }
+  baseL_ = firstReal;
+  numberL_ -= firstReal;
+  factorElements_ = totalElements_;
+  //can delete pivotRowL_ as not used
+  pivotRowL_.conditionalDelete() ;
+  //use L for R if room
+  CoinBigIndex space = lengthAreaL_ - lengthL_;
+  CoinBigIndex spaceUsed = lengthL_ + lengthU_;
+
+  int needed = ( spaceUsed + numberRows_ - 1 ) / numberRows_;
+
+  needed = needed * 2 * maximumPivots_;
+  if ( needed < 2 * numberRows_ ) {
+    needed = 2 * numberRows_;
+  }
+  if (numberInColumnPlus_.array()) {
+    // Need double the space for R
+    space = space/2;
+    startColumnR_.conditionalNew( maximumPivots_ + 1 + maximumColumnsExtra_ + 1 );
+    CoinBigIndex * startR = startColumnR_.array() + maximumPivots_+1;
+    CoinZeroN (startR,(maximumColumnsExtra_+1));
+  } else {
+    startColumnR_.conditionalNew(maximumPivots_ + 1 );
+  }
+#ifdef ZEROFAULT
+  memset(startColumnR_.array(),'z',(maximumPivots_ + 1)*sizeof(CoinBigIndex));
+#endif
+  if ( space >= needed ) {
+    lengthR_ = 0;
+    lengthAreaR_ = space;
+    elementR_ = elementL_.array() + lengthL_;
+    indexRowR_ = indexRowL_.array() + lengthL_;
+  } else {
+    lengthR_ = 0;
+    lengthAreaR_ = space;
+    elementR_ = elementL_.array() + lengthL_;
+    indexRowR_ = indexRowL_.array() + lengthL_;
+    if ((messageLevel_&4))
+      std::cout<<"Factorization may need some increasing area space"
+	       <<std::endl;
+    if ( areaFactor_ ) {
+      areaFactor_ *= 1.1;
+    } else {
+      areaFactor_ = 1.1;
+    }
+  }
+  numberR_ = 0;
+}
+// Returns areaFactor but adjusted for dense
+double 
+CoinFactorization::adjustedAreaFactor() const
+{
+  double factor = areaFactor_;
+  if (numberDense_&&areaFactor_>1.0) {
+    double dense = numberDense_;
+    dense *= dense;
+    double withoutDense = totalElements_ - dense +1.0;
+    factor *= 1.0 +dense/withoutDense;
+  }
+  return factor;
+}
+
+//  checkConsistency.  Checks that row and column copies look OK
+void
+CoinFactorization::checkConsistency (  )
+{
+  bool bad = false;
+
+  int iRow;
+  CoinBigIndex * startRowU = startRowU_.array();
+  int * numberInRow = numberInRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int * indexColumnU = indexColumnU_.array();
+  int * indexRowU = indexRowU_.array();
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  for ( iRow = 0; iRow < numberRows_; iRow++ ) {
+    if ( numberInRow[iRow] ) {
+      CoinBigIndex startRow = startRowU[iRow];
+      CoinBigIndex endRow = startRow + numberInRow[iRow];
+
+      CoinBigIndex j;
+      for ( j = startRow; j < endRow; j++ ) {
+	int iColumn = indexColumnU[j];
+	CoinBigIndex startColumn = startColumnU[iColumn];
+	CoinBigIndex endColumn = startColumn + numberInColumn[iColumn];
+	bool found = false;
+
+	CoinBigIndex k;
+	for ( k = startColumn; k < endColumn; k++ ) {
+	  if ( indexRowU[k] == iRow ) {
+	    found = true;
+	    break;
+	  }
+	}
+	if ( !found ) {
+	  bad = true;
+	  std::cout << "row " << iRow << " column " << iColumn << " Rows" << std::endl;
+	}
+      }
+    }
+  }
+  int iColumn;
+  for ( iColumn = 0; iColumn < numberColumns_; iColumn++ ) {
+    if ( numberInColumn[iColumn] ) {
+      CoinBigIndex startColumn = startColumnU[iColumn];
+      CoinBigIndex endColumn = startColumn + numberInColumn[iColumn];
+
+      CoinBigIndex j;
+      for ( j = startColumn; j < endColumn; j++ ) {
+	int iRow = indexRowU[j];
+	CoinBigIndex startRow = startRowU[iRow];
+	CoinBigIndex endRow = startRow + numberInRow[iRow];
+	bool found = false;
+
+	CoinBigIndex k;
+	for (  k = startRow; k < endRow; k++ ) {
+	  if ( indexColumnU[k] == iColumn ) {
+	    found = true;
+	    break;
+	  }
+	}
+	if ( !found ) {
+	  bad = true;
+	  std::cout << "row " << iRow << " column " << iColumn << " Columns" <<
+	    std::endl;
+	}
+      }
+    }
+  }
+  if ( bad ) {
+    abort (  );
+  }
+}
+  //  pivotOneOtherRow.  When just one other row so faster
+bool 
+CoinFactorization::pivotOneOtherRow ( int pivotRow,
+					   int pivotColumn )
+{
+  int * numberInRow = numberInRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int * numberInColumnPlus = numberInColumnPlus_.array();
+  int numberInPivotRow = numberInRow[pivotRow] - 1;
+  CoinBigIndex * startRowU = startRowU_.array();
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  CoinBigIndex startColumn = startColumnU[pivotColumn];
+  CoinBigIndex startRow = startRowU[pivotRow];
+  CoinBigIndex endRow = startRow + numberInPivotRow + 1;
+
+  //take out this bit of indexColumnU
+  int * nextRow = nextRow_.array();
+  int * lastRow = lastRow_.array();
+  int next = nextRow[pivotRow];
+  int last = lastRow[pivotRow];
+
+  nextRow[last] = next;
+  lastRow[next] = last;
+  nextRow[pivotRow] = numberGoodU_;	//use for permute
+  lastRow[pivotRow] = -2;
+  numberInRow[pivotRow] = 0;
+  //store column in L, compress in U and take column out
+  CoinBigIndex l = lengthL_;
+
+  if ( l + 1 > lengthAreaL_ ) {
+    //need more memory
+    if ((messageLevel_&4)!=0) 
+      std::cout << "more memory needed in middle of invert" << std::endl;
+    return false;
+  }
+  //l+=currentAreaL_->elementByColumn-elementL_;
+  //CoinBigIndex lSave=l;
+  CoinBigIndex * startColumnL = startColumnL_.array();
+  CoinFactorizationDouble * elementL = elementL_.array();
+  int * indexRowL = indexRowL_.array();
+  startColumnL[numberGoodL_] = l;	//for luck and first time
+  numberGoodL_++;
+  startColumnL[numberGoodL_] = l + 1;
+  lengthL_++;
+  CoinFactorizationDouble pivotElement;
+  CoinFactorizationDouble otherMultiplier;
+  int otherRow;
+  int * saveColumn = saveColumn_.array();
+  CoinFactorizationDouble *elementU = elementU_.array();
+  int * indexRowU = indexRowU_.array();
+
+  if ( indexRowU[startColumn] == pivotRow ) {
+    pivotElement = elementU[startColumn];
+    otherMultiplier = elementU[startColumn + 1];
+    otherRow = indexRowU[startColumn + 1];
+  } else {
+    pivotElement = elementU[startColumn + 1];
+    otherMultiplier = elementU[startColumn];
+    otherRow = indexRowU[startColumn];
+  }
+  int numberSave = numberInRow[otherRow];
+  CoinFactorizationDouble pivotMultiplier = 1.0 / pivotElement;
+
+  CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+  pivotRegion[numberGoodU_] = pivotMultiplier;
+  numberInColumn[pivotColumn] = 0;
+  otherMultiplier = otherMultiplier * pivotMultiplier;
+  indexRowL[l] = otherRow;
+  elementL[l] = otherMultiplier;
+  //take out of row list
+  CoinBigIndex start = startRowU[otherRow];
+  CoinBigIndex end = start + numberSave;
+  CoinBigIndex where = start;
+  int * indexColumnU = indexColumnU_.array();
+
+  while ( indexColumnU[where] != pivotColumn ) {
+    where++;
+  }				/* endwhile */
+  assert ( where < end );
+  end--;
+  indexColumnU[where] = indexColumnU[end];
+  int numberAdded = 0;
+  int numberDeleted = 0;
+
+  //pack down and move to work
+  int j;
+  const int * nextCount = nextCount_.array();
+  int * nextColumn = nextColumn_.array();
+
+  for ( j = startRow; j < endRow; j++ ) {
+    int iColumn = indexColumnU[j];
+
+    if ( iColumn != pivotColumn ) {
+      CoinBigIndex startColumn = startColumnU[iColumn];
+      CoinBigIndex endColumn = startColumn + numberInColumn[iColumn];
+      int iRow = indexRowU[startColumn];
+      CoinFactorizationDouble value = elementU[startColumn];
+      double largest;
+      bool foundOther = false;
+
+      //leave room for pivot
+      CoinBigIndex put = startColumn + 1;
+      CoinBigIndex positionLargest = -1;
+      CoinFactorizationDouble thisPivotValue = 0.0;
+      CoinFactorizationDouble otherElement = 0.0;
+      CoinFactorizationDouble nextValue = elementU[put];;
+      int nextIRow = indexRowU[put];
+
+      //compress column and find largest not updated
+      if ( iRow != pivotRow ) {
+	if ( iRow != otherRow ) {
+	  largest = fabs ( value );
+	  elementU[put] = value;
+	  indexRowU[put] = iRow;
+	  positionLargest = put;
+	  put++;
+	  CoinBigIndex i;
+	  for ( i = startColumn + 1; i < endColumn; i++ ) {
+	    iRow = nextIRow;
+	    value = nextValue;
+#ifdef ZEROFAULT
+	    // doesn't matter reading uninitialized but annoys checking
+	    if ( i + 1 < endColumn ) {
+#endif
+	      nextIRow = indexRowU[i + 1];
+	      nextValue = elementU[i + 1];
+#ifdef ZEROFAULT
+	    }
+#endif
+	    if ( iRow != pivotRow ) {
+	      if ( iRow != otherRow ) {
+		//keep
+		indexRowU[put] = iRow;
+		elementU[put] = value;;
+		put++;
+	      } else {
+		otherElement = value;
+		foundOther = true;
+	      }
+	    } else {
+	      thisPivotValue = value;
+	    }
+	  }
+	} else {
+	  otherElement = value;
+	  foundOther = true;
+	  //need to find largest
+	  largest = 0.0;
+	  CoinBigIndex i;
+	  for ( i = startColumn + 1; i < endColumn; i++ ) {
+	    iRow = nextIRow;
+	    value = nextValue;
+#ifdef ZEROFAULT
+	    // doesn't matter reading uninitialized but annoys checking
+	    if ( i + 1 < endColumn ) {
+#endif
+	      nextIRow = indexRowU[i + 1];
+	      nextValue = elementU[i + 1];
+#ifdef ZEROFAULT
+	    }
+#endif
+	    if ( iRow != pivotRow ) {
+	      //keep
+	      indexRowU[put] = iRow;
+	      elementU[put] = value;;
+	      double absValue = fabs ( value );
+
+	      if ( absValue > largest ) {
+		largest = absValue;
+		positionLargest = put;
+	      }
+	      put++;
+	    } else {
+	      thisPivotValue = value;
+	    }
+	  }
+	}
+      } else {
+	//need to find largest
+	largest = 0.0;
+	thisPivotValue = value;
+	CoinBigIndex i;
+	for ( i = startColumn + 1; i < endColumn; i++ ) {
+	  iRow = nextIRow;
+	  value = nextValue;
+#ifdef ZEROFAULT
+	  // doesn't matter reading uninitialized but annoys checking
+	  if ( i + 1 < endColumn ) {
+#endif
+	    nextIRow = indexRowU[i + 1];
+	    nextValue = elementU[i + 1];
+#ifdef ZEROFAULT
+	  }
+#endif
+	  if ( iRow != otherRow ) {
+	    //keep
+	    indexRowU[put] = iRow;
+	    elementU[put] = value;;
+	    double absValue = fabs ( value );
+
+	    if ( absValue > largest ) {
+	      largest = absValue;
+	      positionLargest = put;
+	    }
+	    put++;
+	  } else {
+	    otherElement = value;
+	    foundOther = true;
+	  }
+	}
+      }
+      //slot in pivot
+      elementU[startColumn] = thisPivotValue;
+      indexRowU[startColumn] = pivotRow;
+      //clean up counts
+      startColumn++;
+      numberInColumn[iColumn] = put - startColumn;
+      numberInColumnPlus[iColumn]++;
+      startColumnU[iColumn]++;
+      otherElement = otherElement - thisPivotValue * otherMultiplier;
+      double absValue = fabs ( otherElement );
+
+      if ( absValue > zeroTolerance_ ) {
+	if ( !foundOther ) {
+	  //have we space
+	  saveColumn[numberAdded++] = iColumn;
+	  int next = nextColumn[iColumn];
+	  CoinBigIndex space;
+
+	  space = startColumnU[next] - put - numberInColumnPlus[next];
+	  if ( space <= 0 ) {
+	    //getColumnSpace also moves fixed part
+	    int number = numberInColumn[iColumn];
+
+	    if ( !getColumnSpace ( iColumn, number + 1 ) ) {
+	      return false;
+	    }
+	    //redo starts
+	    positionLargest =
+	      positionLargest + startColumnU[iColumn] - startColumn;
+	    startColumn = startColumnU[iColumn];
+	    put = startColumn + number;
+	  }
+	}
+	elementU[put] = otherElement;
+	indexRowU[put] = otherRow;
+	if ( absValue > largest ) {
+	  largest = absValue;
+	  positionLargest = put;
+	}
+	put++;
+      } else {
+	if ( foundOther ) {
+	  numberDeleted++;
+	  //take out of row list
+	  CoinBigIndex where = start;
+
+	  while ( indexColumnU[where] != iColumn ) {
+	    where++;
+	  }			/* endwhile */
+	  assert ( where < end );
+	  end--;
+	  indexColumnU[where] = indexColumnU[end];
+	}
+      }
+      numberInColumn[iColumn] = put - startColumn;
+      //move largest
+      if ( positionLargest >= 0 ) {
+	value = elementU[positionLargest];
+	iRow = indexRowU[positionLargest];
+	elementU[positionLargest] = elementU[startColumn];
+	indexRowU[positionLargest] = indexRowU[startColumn];
+	elementU[startColumn] = value;
+	indexRowU[startColumn] = iRow;
+      }
+      //linked list for column
+      if ( nextCount[iColumn + numberRows_] != -2 ) {
+	//modify linked list
+	deleteLink ( iColumn + numberRows_ );
+	addLink ( iColumn + numberRows_, numberInColumn[iColumn] );
+      }
+    }
+  }
+  //get space for row list
+  next = nextRow[otherRow];
+  CoinBigIndex space;
+
+  space = startRowU[next] - end;
+  totalElements_ += numberAdded - numberDeleted;
+  int number = numberAdded + ( end - start );
+
+  if ( space < numberAdded ) {
+    numberInRow[otherRow] = end - start;
+    if ( !getRowSpace ( otherRow, number ) ) {
+      return false;
+    }
+    end = startRowU[otherRow] + end - start;
+  }
+  // do linked lists and update counts
+  numberInRow[otherRow] = number;
+  if ( number != numberSave ) {
+    deleteLink ( otherRow );
+    addLink ( otherRow, number );
+  }
+  for ( j = 0; j < numberAdded; j++ ) {
+    indexColumnU[end++] = saveColumn[j];
+  }
+  //modify linked list for pivots
+  deleteLink ( pivotRow );
+  deleteLink ( pivotColumn + numberRows_ );
+  return true;
+}
+void 
+CoinFactorization::setPersistenceFlag(int flag)
+{ 
+  persistenceFlag_=flag;
+  workArea_.setPersistence(flag,maximumRowsExtra_+1);
+  workArea2_.setPersistence(flag,maximumRowsExtra_+1);
+  pivotColumn_.setPersistence(flag,maximumColumnsExtra_+1);
+  permute_.setPersistence(flag,maximumRowsExtra_+1);
+  pivotColumnBack_.setPersistence(flag,maximumRowsExtra_+1);
+  permuteBack_.setPersistence(flag,maximumRowsExtra_+1);
+  nextRow_.setPersistence(flag,maximumRowsExtra_+1);
+  startRowU_.setPersistence(flag,maximumRowsExtra_+1);
+  numberInRow_.setPersistence(flag,maximumRowsExtra_+1);
+  numberInColumn_.setPersistence(flag,maximumColumnsExtra_+1);
+  numberInColumnPlus_.setPersistence(flag,maximumColumnsExtra_+1);
+  firstCount_.setPersistence(flag,CoinMax(biggerDimension_+2,maximumRowsExtra_+1));
+  nextCount_.setPersistence(flag,numberRows_+numberColumns_);
+  lastCount_.setPersistence(flag,numberRows_+numberColumns_);
+  nextColumn_.setPersistence(flag,maximumColumnsExtra_+1);
+  lastColumn_.setPersistence(flag,maximumColumnsExtra_+1);
+  lastRow_.setPersistence(flag,maximumRowsExtra_+1);
+  markRow_.setPersistence(flag,numberRows_);
+  saveColumn_.setPersistence(flag,numberColumns_);
+  indexColumnU_.setPersistence(flag,lengthAreaU_);
+  pivotRowL_.setPersistence(flag,numberRows_+1);
+  pivotRegion_.setPersistence(flag,maximumRowsExtra_+1);
+  elementU_.setPersistence(flag,lengthAreaU_);
+  indexRowU_.setPersistence(flag,lengthAreaU_);
+  startColumnU_.setPersistence(flag,maximumColumnsExtra_+1);
+  convertRowToColumnU_.setPersistence( flag, lengthAreaU_ );
+  elementL_.setPersistence( flag, lengthAreaL_ );
+  indexRowL_.setPersistence( flag, lengthAreaL_ );
+  startColumnL_.setPersistence( flag, numberRows_ + 1 );
+  startColumnR_.setPersistence( flag,  maximumPivots_ + 1 + maximumColumnsExtra_ + 1 );
+  startRowL_.setPersistence( flag,0 );
+  indexColumnL_.setPersistence( flag, 0 );
+  elementByRowL_.setPersistence( flag, 0 );
+  sparse_.setPersistence( flag, 0 );
+}
+// Delete all stuff
+void 
+CoinFactorization::almostDestructor()
+{
+  gutsOfDestructor(2);
+}
diff --git a/cbits/coin/CoinFactorization2.cpp b/cbits/coin/CoinFactorization2.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFactorization2.cpp
@@ -0,0 +1,1414 @@
+/* $Id: CoinFactorization2.cpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinUtilsConfig.h"
+
+#include <cassert>
+#include <cfloat>
+#include <stdio.h>
+#include "CoinFactorization.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinFinite.hpp"
+#if DENSE_CODE==1
+// using simple lapack interface
+extern "C" 
+{
+  /** LAPACK Fortran subroutine DGETRF. */
+  void F77_FUNC(dgetrf,DGETRF)(ipfint * m, ipfint *n,
+                               double *A, ipfint *ldA,
+                               ipfint * ipiv, ipfint *info);
+}
+#endif
+#ifndef NDEBUG
+static int counter1=0;
+#endif
+//  factorSparse.  Does sparse phase of factorization
+//return code is <0 error, 0= finished
+int
+CoinFactorization::factorSparse (  )
+{
+  int larger;
+
+  if ( numberRows_ < numberColumns_ ) {
+    larger = numberColumns_;
+  } else {
+    larger = numberRows_;
+  }
+  int returnCode;
+#define LARGELIMIT 65530
+#define SMALL_SET 65531
+#define SMALL_UNSET (SMALL_SET+1)
+#define LARGE_SET COIN_INT_MAX-10
+#define LARGE_UNSET (LARGE_SET+1)
+  if ( larger < LARGELIMIT )
+    returnCode = factorSparseSmall();
+  else
+    returnCode = factorSparseLarge();
+  return returnCode;
+}
+//  factorSparse.  Does sparse phase of factorization
+//return code is <0 error, 0= finished
+int
+CoinFactorization::factorSparseSmall (  )
+{
+  int *indexRow = indexRowU_.array();
+  int *indexColumn = indexColumnU_.array();
+  CoinFactorizationDouble *element = elementU_.array();
+  int count = 1;
+  workArea_.conditionalNew(numberRows_);
+  CoinFactorizationDouble * workArea = workArea_.array();
+#ifndef NDEBUG
+  counter1++;
+#endif
+  // when to go dense
+  int denseThreshold=denseThreshold_;
+
+  CoinZeroN ( workArea, numberRows_ );
+  //get space for bit work area
+  CoinBigIndex workSize = 1000;
+  workArea2_.conditionalNew(workSize);
+  unsigned int * workArea2 = workArea2_.array();
+
+  //set markRow so no rows updated
+  unsigned short * markRow = reinterpret_cast<unsigned short *> (markRow_.array());
+  CoinFillN (  markRow, numberRows_, static_cast<unsigned short> (SMALL_UNSET));
+  int status = 0;
+  //do slacks first
+  int * numberInRow = numberInRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int * numberInColumnPlus = numberInColumnPlus_.array();
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  CoinBigIndex * startColumnL = startColumnL_.array();
+  if (biasLU_<3&&numberColumns_==numberRows_) {
+    int iPivotColumn;
+    int * pivotColumn = pivotColumn_.array();
+    int * nextRow = nextRow_.array();
+    int * lastRow = lastRow_.array();
+    for ( iPivotColumn = 0; iPivotColumn < numberColumns_;
+	  iPivotColumn++ ) {
+      if ( numberInColumn[iPivotColumn] == 1 ) {
+	CoinBigIndex start = startColumnU[iPivotColumn];
+	CoinFactorizationDouble value = element[start];
+	if ( value == slackValue_ && numberInColumnPlus[iPivotColumn] == 0 ) {
+	  // treat as slack
+	  int iRow = indexRow[start];
+	  // but only if row not marked
+	  if (numberInRow[iRow]>0) {
+	    totalElements_ -= numberInRow[iRow];
+	    //take out this bit of indexColumnU
+	    int next = nextRow[iRow];
+	    int last = lastRow[iRow];
+	    
+	    nextRow[last] = next;
+	    lastRow[next] = last;
+	    nextRow[iRow] = numberGoodU_;	//use for permute
+	    lastRow[iRow] = -2; //mark
+	    //modify linked list for pivots
+	    deleteLink ( iRow );
+	    numberInRow[iRow]=-1;
+	    numberInColumn[iPivotColumn]=0;
+	    numberGoodL_++;
+	    startColumnL[numberGoodL_] = 0;
+	    pivotColumn[numberGoodU_] = iPivotColumn;
+	    numberGoodU_++;
+	  }
+	}
+      }
+    }
+    // redo
+    preProcess(4);
+    CoinFillN (  markRow, numberRows_, static_cast<unsigned short> (SMALL_UNSET));
+  }
+  numberSlacks_ = numberGoodU_;
+  int *nextCount = nextCount_.array();
+  int *firstCount = firstCount_.array();
+  CoinBigIndex *startRow = startRowU_.array();
+  CoinBigIndex *startColumn = startColumnU;
+  //#define UGLY_COIN_FACTOR_CODING
+#ifdef UGLY_COIN_FACTOR_CODING
+  CoinFactorizationDouble *elementL = elementL_.array();
+  int *indexRowL = indexRowL_.array();
+  int *saveColumn = saveColumn_.array();
+  int *nextRow = nextRow_.array();
+  int *lastRow = lastRow_.array() ;
+#endif
+  double pivotTolerance = pivotTolerance_;
+  int numberTrials = numberTrials_;
+  int numberRows = numberRows_;
+  // Put column singletons first - (if false)
+  separateLinks(1,(biasLU_>1));
+#ifndef NDEBUG
+  int counter2=0;
+#endif
+  while ( count <= biggerDimension_ ) {
+#ifndef NDEBUG
+    counter2++;
+    int badRow=-1;
+    if (counter1==-1&&counter2>=0) {
+      // check counts consistent
+      for (int iCount=1;iCount<numberRows_;iCount++) {
+        int look = firstCount[iCount];
+        while ( look >= 0 ) {
+          if ( look < numberRows_ ) {
+            int iRow = look;
+            if (iRow==badRow)
+              printf("row count for row %d is %d\n",iCount,iRow);
+            if ( numberInRow[iRow] != iCount ) {
+              printf("failed debug on %d entry to factorSparse and %d try\n",
+                     counter1,counter2);
+              printf("row %d - count %d number %d\n",iRow,iCount,numberInRow[iRow]);
+              abort();
+            }
+            look = nextCount[look];
+          } else {
+            int iColumn = look - numberRows;
+            if ( numberInColumn[iColumn] != iCount ) {
+              printf("failed debug on %d entry to factorSparse and %d try\n",
+                     counter1,counter2);
+              printf("column %d - count %d number %d\n",iColumn,iCount,numberInColumn[iColumn]);
+              abort();
+            }
+            look = nextCount[look];
+          }
+        }
+      }
+    }
+#endif
+    CoinBigIndex minimumCount = COIN_INT_MAX;
+    double minimumCost = COIN_DBL_MAX;
+
+    int iPivotRow = -1;
+    int iPivotColumn = -1;
+    int pivotRowPosition = -1;
+    int pivotColumnPosition = -1;
+    int look = firstCount[count];
+    int trials = 0;
+    int * pivotColumn = pivotColumn_.array();
+
+    if ( count == 1 && firstCount[1] >= 0 &&!biasLU_) {
+      //do column singletons first to put more in U
+      while ( look >= 0 ) {
+        if ( look < numberRows_ ) {
+          look = nextCount[look];
+        } else {
+          int iColumn = look - numberRows_;
+          
+          assert ( numberInColumn[iColumn] == count );
+          CoinBigIndex start = startColumnU[iColumn];
+          int iRow = indexRow[start];
+          
+          iPivotRow = iRow;
+          pivotRowPosition = start;
+          iPivotColumn = iColumn;
+          assert (iPivotRow>=0&&iPivotColumn>=0);
+          pivotColumnPosition = -1;
+          look = -1;
+          break;
+        }
+      }			/* endwhile */
+      if ( iPivotRow < 0 ) {
+        //back to singletons
+        look = firstCount[1];
+      }
+    }
+    while ( look >= 0 ) {
+      if ( look < numberRows_ ) {
+        int iRow = look;
+#ifndef NDEBUG        
+        if ( numberInRow[iRow] != count ) {
+          printf("failed on %d entry to factorSparse and %d try\n",
+                 counter1,counter2);
+          printf("row %d - count %d number %d\n",iRow,count,numberInRow[iRow]);
+          abort();
+        }
+#endif
+        look = nextCount[look];
+        bool rejected = false;
+        CoinBigIndex start = startRow[iRow];
+        CoinBigIndex end = start + count;
+        
+        CoinBigIndex i;
+        for ( i = start; i < end; i++ ) {
+          int iColumn = indexColumn[i];
+          assert (numberInColumn[iColumn]>0);
+          double cost = ( count - 1 ) * numberInColumn[iColumn];
+          
+          if ( cost < minimumCost ) {
+            CoinBigIndex where = startColumn[iColumn];
+            double minimumValue = element[where];
+            
+            minimumValue = fabs ( minimumValue ) * pivotTolerance;
+            while ( indexRow[where] != iRow ) {
+              where++;
+            }			/* endwhile */
+            assert ( where < startColumn[iColumn] +
+                     numberInColumn[iColumn]);
+            CoinFactorizationDouble value = element[where];
+            
+            value = fabs ( value );
+            if ( value >= minimumValue ) {
+              minimumCost = cost;
+              minimumCount = numberInColumn[iColumn];
+              iPivotRow = iRow;
+              pivotRowPosition = -1;
+              iPivotColumn = iColumn;
+              assert (iPivotRow>=0&&iPivotColumn>=0);
+              pivotColumnPosition = i;
+              rejected=false;
+              if ( minimumCount < count ) {
+                look = -1;
+                break;
+              }
+            } else if ( iPivotRow == -1 ) {
+              rejected = true;
+            }
+          }
+        }
+        trials++;
+        if ( trials >= numberTrials && iPivotRow >= 0 ) {
+          look = -1;
+          break;
+        }
+        if ( rejected ) {
+          //take out for moment
+          //eligible when row changes
+          deleteLink ( iRow );
+          addLink ( iRow, biggerDimension_ + 1 );
+        }
+      } else {
+        int iColumn = look - numberRows;
+        
+        assert ( numberInColumn[iColumn] == count );
+        look = nextCount[look];
+        CoinBigIndex start = startColumn[iColumn];
+        CoinBigIndex end = start + numberInColumn[iColumn];
+        CoinFactorizationDouble minimumValue = element[start];
+        
+        minimumValue = fabs ( minimumValue ) * pivotTolerance;
+        CoinBigIndex i;
+        for ( i = start; i < end; i++ ) {
+          CoinFactorizationDouble value = element[i];
+          
+          value = fabs ( value );
+          if ( value >= minimumValue ) {
+            int iRow = indexRow[i];
+            int nInRow = numberInRow[iRow];
+            assert (nInRow>0);
+            double cost = ( count - 1 ) * nInRow;
+            
+            if ( cost < minimumCost ) {
+              minimumCost = cost;
+              minimumCount = nInRow;
+              iPivotRow = iRow;
+              pivotRowPosition = i;
+              iPivotColumn = iColumn;
+              assert (iPivotRow>=0&&iPivotColumn>=0);
+              pivotColumnPosition = -1;
+              if ( minimumCount <= count + 1 ) {
+                look = -1;
+                break;
+              }
+            }
+          }
+        }
+        trials++;
+        if ( trials >= numberTrials && iPivotRow >= 0 ) {
+          look = -1;
+          break;
+        }
+      }
+    }				/* endwhile */
+    if (iPivotRow>=0) {
+      assert (iPivotRow<numberRows_);
+      int numberDoRow = numberInRow[iPivotRow] - 1;
+      int numberDoColumn = numberInColumn[iPivotColumn] - 1;
+      
+      totalElements_ -= ( numberDoRow + numberDoColumn + 1 );
+      if ( numberDoColumn > 0 ) {
+	if ( numberDoRow > 0 ) {
+	  if ( numberDoColumn > 1 ) {
+	    //  if (1) {
+	    //need to adjust more for cache and SMP
+	    //allow at least 4 extra
+	    int increment = numberDoColumn + 1 + 4;
+            
+	    if ( increment & 15 ) {
+	      increment = increment & ( ~15 );
+	      increment += 16;
+	    }
+	    int increment2 =
+	      
+	      ( increment + COINFACTORIZATION_BITS_PER_INT - 1 ) >> COINFACTORIZATION_SHIFT_PER_INT;
+	    CoinBigIndex size = increment2 * numberDoRow;
+            
+	    if ( size > workSize ) {
+	      workSize = size;
+	      workArea2_.conditionalNew(workSize);
+	      workArea2 = workArea2_.array();
+	    }
+	    bool goodPivot;
+#ifndef UGLY_COIN_FACTOR_CODING
+	    //branch out to best pivot routine 
+	    goodPivot = pivot ( iPivotRow, iPivotColumn,
+				pivotRowPosition, pivotColumnPosition,
+				workArea, workArea2, 
+				increment2,  markRow ,
+				SMALL_SET);
+#else
+#define FAC_SET SMALL_SET
+#include "CoinFactorization.hpp"
+#undef FAC_SET
+#undef UGLY_COIN_FACTOR_CODING
+#endif
+	    if ( !goodPivot ) {
+	      status = -99;
+	      count=biggerDimension_+1;
+	      break;
+	    }
+	  } else {
+	    if ( !pivotOneOtherRow ( iPivotRow, iPivotColumn ) ) {
+	      status = -99;
+	      count=biggerDimension_+1;
+	      break;
+	    }
+	  }
+	} else {
+	  assert (!numberDoRow);
+	  if ( !pivotRowSingleton ( iPivotRow, iPivotColumn ) ) {
+	    status = -99;
+	    count=biggerDimension_+1;
+	    break;
+	  }
+	}
+      } else {
+	assert (!numberDoColumn);
+	if ( !pivotColumnSingleton ( iPivotRow, iPivotColumn ) ) {
+	  status = -99;
+	  count=biggerDimension_+1;
+	  break;
+	}
+      }
+      assert (nextRow_.array()[iPivotRow]==numberGoodU_);
+      pivotColumn[numberGoodU_] = iPivotColumn;
+      numberGoodU_++;
+      // This should not need to be trapped here - but be safe
+      if (numberGoodU_==numberRows_) 
+	count=biggerDimension_+1;
+#if COIN_DEBUG==2
+      checkConsistency (  );
+#endif
+#if 0
+      // Even if no dense code may be better to use naive dense
+      if (!denseThreshold_&&totalElements_>1000) {
+        int leftRows=numberRows_-numberGoodU_;
+        double full = leftRows;
+        full *= full;
+        assert (full>=0.0);
+        double leftElements = totalElements_;
+        double ratio;
+        if (leftRows>2000)
+          ratio=4.0;
+        else 
+          ratio=3.0;
+        if (ratio*leftElements>full) 
+          denseThreshold=1;
+      }
+#endif
+      if (denseThreshold) {
+        // see whether to go dense 
+        int leftRows=numberRows_-numberGoodU_;
+        double full = leftRows;
+        full *= full;
+        assert (full>=0.0);
+        double leftElements = totalElements_;
+        //if (leftRows==100)
+        //printf("at 100 %d elements\n",totalElements_);
+        double ratio;
+        if (leftRows>2000)
+          ratio=4.0;
+        else if (leftRows>800)
+          ratio=3.0;
+        else if (leftRows>256)
+          ratio=2.0;
+        else
+          ratio=1.5;
+        if ((ratio*leftElements>full&&leftRows>denseThreshold_)) {
+          //return to do dense
+          if (status!=0)
+            break;
+          int check=0;
+          for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+            if (numberInColumn[iColumn]) 
+              check++;
+          }
+          if (check!=leftRows&&denseThreshold_) {
+            //printf("** mismatch %d columns left, %d rows\n",check,leftRows);
+            denseThreshold=0;
+          } else {
+            status=2;
+            if ((messageLevel_&4)!=0) 
+              std::cout<<"      Went dense at "<<leftRows<<" rows "<<
+                totalElements_<<" "<<full<<" "<<leftElements<<std::endl;
+            if (!denseThreshold_)
+              denseThreshold_=-check; // say how many
+            break;
+          }
+        }
+      }
+      // start at 1 again
+      count = 1;
+    } else {
+      //end of this - onto next
+      count++;
+    } 
+  }				/* endwhile */
+  workArea_.conditionalDelete() ;
+  workArea2_.conditionalDelete() ;
+  return status;
+}
+
+//:method factorDense.  Does dense phase of factorization
+//return code is <0 error, 0= finished
+int CoinFactorization::factorDense()
+{
+  int status=0;
+  numberDense_=numberRows_-numberGoodU_;
+  if (sizeof(CoinBigIndex)==4&&numberDense_>=2<<15) {
+    abort();
+  } 
+  CoinBigIndex full;
+  if (denseThreshold_>0) 
+    full = numberDense_*numberDense_;
+  else
+    full = - denseThreshold_*numberDense_;
+  totalElements_=full;
+  denseArea_= new double [full];
+  CoinZeroN(denseArea_,full);
+  densePermute_= new int [numberDense_];
+  int * indexRowU = indexRowU_.array();
+  //mark row lookup using lastRow
+  int i;
+  int * nextRow = nextRow_.array();
+  int * lastRow = lastRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int * numberInColumnPlus = numberInColumnPlus_.array();
+  for (i=0;i<numberRows_;i++) {
+    if (lastRow[i]>=0)
+      lastRow[i]=0;
+  }
+  int * indexRow = indexRowU_.array();
+  CoinFactorizationDouble * element = elementU_.array();
+  int which=0;
+  for (i=0;i<numberRows_;i++) {
+    if (!lastRow[i]) {
+      lastRow[i]=which;
+      nextRow[i]=numberGoodU_+which;
+      densePermute_[which]=i;
+      which++;
+    }
+  } 
+  //for L part
+  CoinBigIndex * startColumnL = startColumnL_.array();
+  CoinFactorizationDouble * elementL = elementL_.array();
+  int * indexRowL = indexRowL_.array();
+  CoinBigIndex endL=startColumnL[numberGoodL_];
+  //take out of U
+  double * column = denseArea_;
+  int rowsDone=0;
+  int iColumn=0;
+  int * pivotColumn = pivotColumn_.array();
+  CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+    if (numberInColumn[iColumn]) {
+      //move
+      CoinBigIndex start = startColumnU[iColumn];
+      int number = numberInColumn[iColumn];
+      CoinBigIndex end = start+number;
+      for (CoinBigIndex i=start;i<end;i++) {
+        int iRow=indexRow[i];
+        iRow=lastRow[iRow];
+	assert (iRow>=0&&iRow<numberDense_);
+        column[iRow]=element[i];
+      } /* endfor */
+      column+=numberDense_;
+      while (lastRow[rowsDone]<0) {
+        rowsDone++;
+      } /* endwhile */
+      nextRow[rowsDone]=numberGoodU_;
+      rowsDone++;
+      startColumnL[numberGoodU_+1]=endL;
+      numberInColumn[iColumn]=0;
+      pivotColumn[numberGoodU_]=iColumn;
+      pivotRegion[numberGoodU_]=1.0;
+      numberGoodU_++;
+    } 
+  } 
+#ifdef DENSE_CODE
+  if (denseThreshold_>0) {
+    assert(numberGoodU_==numberRows_);
+    numberGoodL_=numberRows_;
+    //now factorize
+    //dgef(denseArea_,&numberDense_,&numberDense_,densePermute_);
+    int info;
+    F77_FUNC(dgetrf,DGETRF)(&numberDense_,&numberDense_,denseArea_,&numberDense_,densePermute_,
+			    &info);
+    // need to check size of pivots
+    if(info)
+      status = -1;
+    return status;
+  } 
+#endif
+  numberGoodU_ = numberRows_-numberDense_;
+  int base = numberGoodU_;
+  int iDense;
+  int numberToDo=-denseThreshold_;
+  denseThreshold_=0;
+  double tolerance = zeroTolerance_;
+  tolerance = 1.0e-30;
+  int * nextColumn = nextColumn_.array();
+  const int * pivotColumnConst = pivotColumn_.array();
+  // make sure we have enough space in L and U
+  for (iDense=0;iDense<numberToDo;iDense++) {
+    //how much space have we got
+    iColumn = pivotColumnConst[base+iDense];
+    int next = nextColumn[iColumn];
+    int numberInPivotColumn = iDense;
+    CoinBigIndex space = startColumnU[next] 
+      - startColumnU[iColumn]
+      - numberInColumnPlus[next];
+    //assume no zero elements
+    if ( numberInPivotColumn > space ) {
+      //getColumnSpace also moves fixed part
+      if ( !getColumnSpace ( iColumn, numberInPivotColumn ) ) {
+	return -99;
+      }
+    }
+    // set so further moves will work
+    numberInColumn[iColumn]=numberInPivotColumn;
+  }
+  // Fill in ?
+  for (iColumn=numberGoodU_+numberToDo;iColumn<numberRows_;iColumn++) {
+    nextRow[iColumn]=iColumn;
+    startColumnL[iColumn+1]=endL;
+    pivotRegion[iColumn]=1.0;
+  } 
+  if ( lengthL_ + full*0.5 > lengthAreaL_ ) {
+    //need more memory
+    if ((messageLevel_&4)!=0) 
+      std::cout << "more memory needed in middle of invert" << std::endl;
+    return -99;
+  }
+  CoinFactorizationDouble *elementU = elementU_.array();
+  for (iDense=0;iDense<numberToDo;iDense++) {
+    int iRow;
+    int jDense;
+    int pivotRow=-1;
+    double * element = denseArea_+iDense*numberDense_;
+    CoinFactorizationDouble largest = 1.0e-12;
+    for (iRow=iDense;iRow<numberDense_;iRow++) {
+      if (fabs(element[iRow])>largest) {
+	largest = fabs(element[iRow]);
+	pivotRow = iRow;
+      }
+    }
+    if ( pivotRow >= 0 ) {
+      iColumn = pivotColumnConst[base+iDense];
+      CoinFactorizationDouble pivotElement=element[pivotRow];
+      // get original row
+      int originalRow = densePermute_[pivotRow];
+      // do nextRow
+      nextRow[originalRow] = numberGoodU_;
+      lastRow[originalRow] = -2; //mark
+      // swap
+      densePermute_[pivotRow]=densePermute_[iDense];
+      densePermute_[iDense] = originalRow;
+      for (jDense=iDense;jDense<numberDense_;jDense++) {
+	CoinFactorizationDouble value = element[iDense];
+	element[iDense] = element[pivotRow];
+	element[pivotRow] = value;
+	element += numberDense_;
+      }
+      CoinFactorizationDouble pivotMultiplier = 1.0 / pivotElement;
+      //printf("pivotMultiplier %g\n",pivotMultiplier);
+      pivotRegion[numberGoodU_] = pivotMultiplier;
+      // Do L
+      element = denseArea_+iDense*numberDense_;
+      CoinBigIndex l = lengthL_;
+      startColumnL[numberGoodL_] = l;	//for luck and first time
+      for (iRow=iDense+1;iRow<numberDense_;iRow++) {
+	CoinFactorizationDouble value = element[iRow]*pivotMultiplier;
+	element[iRow] = value;
+	if (fabs(value)>tolerance) {
+	  indexRowL[l] = densePermute_[iRow];
+	  elementL[l++] = value;
+	}
+      }
+      numberGoodL_++;
+      lengthL_ = l;
+      startColumnL[numberGoodL_] = l;
+      // update U column
+      CoinBigIndex start = startColumnU[iColumn];
+      for (iRow=0;iRow<iDense;iRow++) {
+	if (fabs(element[iRow])>tolerance) {
+	  indexRowU[start] = densePermute_[iRow];
+	  elementU[start++] = element[iRow];
+	}
+      }
+      numberInColumn[iColumn]=0;
+      numberInColumnPlus[iColumn] += start-startColumnU[iColumn];
+      startColumnU[iColumn]=start;
+      // update other columns
+      double * element2 = element+numberDense_;
+      for (jDense=iDense+1;jDense<numberToDo;jDense++) {
+	CoinFactorizationDouble value = element2[iDense];
+	for (iRow=iDense+1;iRow<numberDense_;iRow++) {
+	  //double oldValue=element2[iRow];
+	  element2[iRow] -= value*element[iRow];
+	  //if (oldValue&&!element2[iRow]) {
+          //printf("Updated element for column %d, row %d old %g",
+          //   pivotColumnConst[base+jDense],densePermute_[iRow],oldValue);
+          //printf(" new %g\n",element2[iRow]);
+	  //}
+	}
+	element2 += numberDense_;
+      }
+      numberGoodU_++;
+    } else {
+      return -1;
+    }
+  }
+  // free area (could use L?)
+  delete [] denseArea_;
+  denseArea_ = NULL;
+  // check if can use another array for densePermute_
+  delete [] densePermute_;
+  densePermute_ = NULL;
+  numberDense_=0;
+  return status;
+}
+// Separate out links with same row/column count
+void 
+CoinFactorization::separateLinks(int count,bool rowsFirst)
+{
+  int *nextCount = nextCount_.array();
+  int *firstCount = firstCount_.array();
+  int *lastCount = lastCount_.array();
+  int next = firstCount[count];
+  int firstRow=-1;
+  int firstColumn=-1;
+  int lastRow=-1;
+  int lastColumn=-1;
+  while(next>=0) {
+    int next2=nextCount[next];
+    if (next>=numberRows_) {
+      nextCount[next]=-1;
+      // Column
+      if (firstColumn>=0) {
+	lastCount[next]=lastColumn;
+	nextCount[lastColumn]=next;
+      } else {
+	lastCount[next]= -2 - count;
+	firstColumn=next;
+      }
+      lastColumn=next;
+    } else {
+      // Row
+      if (firstRow>=0) {
+	lastCount[next]=lastRow;
+	nextCount[lastRow]=next;
+      } else {
+	lastCount[next]= -2 - count;
+	firstRow=next;
+      }
+      lastRow=next;
+    }
+    next=next2;
+  }
+  if (rowsFirst&&firstRow>=0) {
+    firstCount[count]=firstRow;
+    nextCount[lastRow]=firstColumn;
+    if (firstColumn>=0)
+      lastCount[firstColumn]=lastRow;
+  } else if (firstRow<0) {
+    firstCount[count]=firstColumn;
+  } else if (firstColumn>=0) {
+    firstCount[count]=firstColumn;
+    nextCount[lastColumn]=firstRow;
+    if (firstRow>=0)
+      lastCount[firstRow]=lastColumn;
+  } 
+}
+// Debug - save on file
+int
+CoinFactorization::saveFactorization (const char * file  ) const
+{
+  FILE * fp = fopen(file,"wb");
+  if (fp) {
+    // Save so we can pick up scalars
+    const char * first = reinterpret_cast<const char *> ( &pivotTolerance_);
+    const char * last = reinterpret_cast<const char *> ( &biasLU_);
+    // increment
+    last += sizeof(int);
+    if (fwrite(first,last-first,1,fp)!=1)
+      return 1;
+    // Now arrays
+    if (CoinToFile(elementU_.array(),lengthAreaU_ , fp ))
+      return 1;
+    if (CoinToFile(indexRowU_.array(),lengthAreaU_ , fp ))
+      return 1;
+    if (CoinToFile(indexColumnU_.array(),lengthAreaU_ , fp ))
+      return 1;
+    if (CoinToFile(convertRowToColumnU_.array(),lengthAreaU_ , fp ))
+      return 1;
+    if (CoinToFile(elementByRowL_.array(),lengthAreaL_ , fp ))
+      return 1;
+    if (CoinToFile(indexColumnL_.array(),lengthAreaL_ , fp ))
+      return 1;
+    if (CoinToFile(startRowL_.array() , numberRows_+1, fp ))
+      return 1;
+    if (CoinToFile(elementL_.array(),lengthAreaL_ , fp ))
+      return 1;
+    if (CoinToFile(indexRowL_.array(),lengthAreaL_ , fp ))
+      return 1;
+    if (CoinToFile(startColumnL_.array(),numberRows_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(markRow_.array(),numberRows_  , fp))
+      return 1;
+    if (CoinToFile(saveColumn_.array(),numberColumns_  , fp))
+      return 1;
+    if (CoinToFile(startColumnR_.array() , maximumPivots_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(startRowU_.array(),maximumRowsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(numberInRow_.array(),maximumRowsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(nextRow_.array(),maximumRowsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(lastRow_.array(),maximumRowsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(pivotRegion_.array(),maximumRowsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(permuteBack_.array(),maximumRowsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(permute_.array(),maximumRowsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(pivotColumnBack_.array(),maximumRowsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(startColumnU_.array(),maximumColumnsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(numberInColumn_.array(),maximumColumnsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(numberInColumnPlus_.array(),maximumColumnsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(firstCount_.array(),biggerDimension_ + 2 , fp ))
+      return 1;
+    if (CoinToFile(nextCount_.array(),numberRows_ + numberColumns_ , fp ))
+      return 1;
+    if (CoinToFile(lastCount_.array(),numberRows_ + numberColumns_ , fp ))
+      return 1;
+    if (CoinToFile(pivotRowL_.array(),numberRows_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(pivotColumn_.array(),maximumColumnsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(nextColumn_.array(),maximumColumnsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(lastColumn_.array(),maximumColumnsExtra_ + 1 , fp ))
+      return 1;
+    if (CoinToFile(denseArea_ , numberDense_*numberDense_, fp ))
+      return 1;
+    if (CoinToFile(densePermute_ , numberDense_, fp ))
+      return 1;
+    fclose(fp);
+  }
+  return 0;
+}
+// Debug - restore from file
+int 
+CoinFactorization::restoreFactorization (const char * file , bool factorIt ) 
+{
+  FILE * fp = fopen(file,"rb");
+  if (fp) {
+    // Get rid of current
+    gutsOfDestructor();
+    CoinBigIndex newSize=0; // for checking - should be same
+    // Restore so we can pick up scalars
+    char * first = reinterpret_cast<char *> ( &pivotTolerance_);
+    char * last = reinterpret_cast<char *> ( &biasLU_);
+    // increment
+    last += sizeof(int);
+    if (fread(first,last-first,1,fp)!=1)
+      return 1;
+    CoinBigIndex space = lengthAreaL_ - lengthL_;
+    // Now arrays
+    CoinFactorizationDouble *elementU = elementU_.array();
+    if (CoinFromFile(elementU,lengthAreaU_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==lengthAreaU_);
+    int * indexRowU = indexRowU_.array();
+    if (CoinFromFile(indexRowU,lengthAreaU_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==lengthAreaU_);
+    int * indexColumnU = indexColumnU_.array();
+    if (CoinFromFile(indexColumnU,lengthAreaU_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==lengthAreaU_);
+    CoinBigIndex *convertRowToColumnU = convertRowToColumnU_.array();
+    if (CoinFromFile(convertRowToColumnU,lengthAreaU_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==lengthAreaU_||(newSize==0&&!convertRowToColumnU_.array()));
+    CoinFactorizationDouble * elementByRowL = elementByRowL_.array();
+    if (CoinFromFile(elementByRowL,lengthAreaL_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==lengthAreaL_||(newSize==0&&!elementByRowL_.array()));
+    int * indexColumnL = indexColumnL_.array();
+    if (CoinFromFile(indexColumnL,lengthAreaL_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==lengthAreaL_||(newSize==0&&!indexColumnL_.array()));
+    CoinBigIndex * startRowL = startRowL_.array();
+    if (CoinFromFile(startRowL , numberRows_+1, fp, newSize )==1)
+      return 1;
+    assert (newSize==numberRows_+1||(newSize==0&&!startRowL_.array()));
+    CoinFactorizationDouble * elementL = elementL_.array();
+    if (CoinFromFile(elementL,lengthAreaL_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==lengthAreaL_);
+    int * indexRowL = indexRowL_.array();
+    if (CoinFromFile(indexRowL,lengthAreaL_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==lengthAreaL_);
+    CoinBigIndex * startColumnL = startColumnL_.array();
+    if (CoinFromFile(startColumnL,numberRows_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==numberRows_+1);
+    int * markRow = markRow_.array();
+    if (CoinFromFile(markRow,numberRows_  , fp, newSize )==1)
+      return 1;
+    assert (newSize==numberRows_);
+    int * saveColumn = saveColumn_.array();
+    if (CoinFromFile(saveColumn,numberColumns_  , fp, newSize )==1)
+      return 1;
+    assert (newSize==numberColumns_);
+    CoinBigIndex * startColumnR = startColumnR_.array();
+    if (CoinFromFile(startColumnR , maximumPivots_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumPivots_+1||(newSize==0&&!startColumnR_.array()));
+    CoinBigIndex * startRowU = startRowU_.array();
+    if (CoinFromFile(startRowU,maximumRowsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumRowsExtra_+1||(newSize==0&&!startRowU_.array()));
+    int * numberInRow = numberInRow_.array();
+    if (CoinFromFile(numberInRow,maximumRowsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumRowsExtra_+1);
+    int * nextRow = nextRow_.array();
+    if (CoinFromFile(nextRow,maximumRowsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumRowsExtra_+1);
+    int * lastRow = lastRow_.array();
+    if (CoinFromFile(lastRow,maximumRowsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumRowsExtra_+1);
+    CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+    if (CoinFromFile(pivotRegion,maximumRowsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumRowsExtra_+1);
+    int * permuteBack = permuteBack_.array();
+    if (CoinFromFile(permuteBack,maximumRowsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumRowsExtra_+1||(newSize==0&&!permuteBack_.array()));
+    int * permute = permute_.array();
+    if (CoinFromFile(permute,maximumRowsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumRowsExtra_+1||(newSize==0&&!permute_.array()));
+    int * pivotColumnBack = pivotColumnBack_.array();
+    if (CoinFromFile(pivotColumnBack,maximumRowsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumRowsExtra_+1||(newSize==0&&!pivotColumnBack_.array()));
+    CoinBigIndex * startColumnU = startColumnU_.array();
+    if (CoinFromFile(startColumnU,maximumColumnsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumColumnsExtra_+1);
+    int * numberInColumn = numberInColumn_.array();
+    if (CoinFromFile(numberInColumn,maximumColumnsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumColumnsExtra_+1);
+    int * numberInColumnPlus = numberInColumnPlus_.array();
+    if (CoinFromFile(numberInColumnPlus,maximumColumnsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumColumnsExtra_+1);
+    int *firstCount = firstCount_.array();
+    if (CoinFromFile(firstCount,biggerDimension_ + 2 , fp, newSize )==1)
+      return 1;
+    assert (newSize==biggerDimension_+2);
+    int *nextCount = nextCount_.array();
+    if (CoinFromFile(nextCount,numberRows_ + numberColumns_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==numberRows_+numberColumns_);
+    int *lastCount = lastCount_.array();
+    if (CoinFromFile(lastCount,numberRows_ + numberColumns_ , fp, newSize )==1)
+      return 1;
+    assert (newSize==numberRows_+numberColumns_);
+    int * pivotRowL = pivotRowL_.array();
+    if (CoinFromFile(pivotRowL,numberRows_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==numberRows_+1);
+    int * pivotColumn = pivotColumn_.array(); 
+    if (CoinFromFile(pivotColumn,maximumColumnsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumColumnsExtra_+1);
+    int * nextColumn = nextColumn_.array();
+    if (CoinFromFile(nextColumn,maximumColumnsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumColumnsExtra_+1);
+    int * lastColumn = lastColumn_.array();
+    if (CoinFromFile(lastColumn,maximumColumnsExtra_ + 1 , fp, newSize )==1)
+      return 1;
+    assert (newSize==maximumColumnsExtra_+1);
+    if (CoinFromFile(denseArea_ , numberDense_*numberDense_, fp, newSize )==1)
+      return 1;
+    assert (newSize==numberDense_*numberDense_);
+    if (CoinFromFile(densePermute_ , numberDense_, fp, newSize )==1)
+      return 1;
+    assert (newSize==numberDense_);
+    lengthAreaR_ = space;
+    elementR_ = elementL_.array() + lengthL_;
+    indexRowR_ = indexRowL_.array() + lengthL_;
+    fclose(fp);
+    if (factorIt) {
+      if (biasLU_>=3||numberRows_!=numberColumns_)
+        preProcess ( 2 );
+      else
+        preProcess ( 3 ); // no row copy
+      factor (  );
+    }
+  }
+  return 0;
+}
+//  factorSparse.  Does sparse phase of factorization
+//return code is <0 error, 0= finished
+int
+CoinFactorization::factorSparseLarge (  )
+{
+  int *indexRow = indexRowU_.array();
+  int *indexColumn = indexColumnU_.array();
+  CoinFactorizationDouble *element = elementU_.array();
+  int count = 1;
+  workArea_.conditionalNew(numberRows_);
+  CoinFactorizationDouble * workArea = workArea_.array();
+#ifndef NDEBUG
+  counter1++;
+#endif
+  // when to go dense
+  int denseThreshold=denseThreshold_;
+
+  CoinZeroN ( workArea, numberRows_ );
+  //get space for bit work area
+  CoinBigIndex workSize = 1000;
+  workArea2_.conditionalNew(workSize);
+  unsigned int * workArea2 = workArea2_.array();
+
+  //set markRow so no rows updated
+  int * markRow = markRow_.array();
+  CoinFillN ( markRow, numberRows_, COIN_INT_MAX-10+1);
+  int status = 0;
+  //do slacks first
+  int * numberInRow = numberInRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  int * numberInColumnPlus = numberInColumnPlus_.array();
+  CoinBigIndex * startColumnU = startColumnU_.array();
+  CoinBigIndex * startColumnL = startColumnL_.array();
+  if (biasLU_<3&&numberColumns_==numberRows_) {
+    int iPivotColumn;
+    int * pivotColumn = pivotColumn_.array();
+    int * nextRow = nextRow_.array();
+    int * lastRow = lastRow_.array();
+    for ( iPivotColumn = 0; iPivotColumn < numberColumns_;
+	  iPivotColumn++ ) {
+      if ( numberInColumn[iPivotColumn] == 1 ) {
+	CoinBigIndex start = startColumnU[iPivotColumn];
+	CoinFactorizationDouble value = element[start];
+	if ( value == slackValue_ && numberInColumnPlus[iPivotColumn] == 0 ) {
+	  // treat as slack
+	  int iRow = indexRow[start];
+	  // but only if row not marked
+	  if (numberInRow[iRow]>0) {
+	    totalElements_ -= numberInRow[iRow];
+	    //take out this bit of indexColumnU
+	    int next = nextRow[iRow];
+	    int last = lastRow[iRow];
+	    
+	    nextRow[last] = next;
+	    lastRow[next] = last;
+	    nextRow[iRow] = numberGoodU_;	//use for permute
+	    lastRow[iRow] = -2; //mark
+	    //modify linked list for pivots
+	    deleteLink ( iRow );
+	    numberInRow[iRow]=-1;
+	    numberInColumn[iPivotColumn]=0;
+	    numberGoodL_++;
+	    startColumnL[numberGoodL_] = 0;
+	    pivotColumn[numberGoodU_] = iPivotColumn;
+	    numberGoodU_++;
+	  }
+	}
+      }
+    }
+    // redo
+    preProcess(4);
+    CoinFillN ( markRow, numberRows_, COIN_INT_MAX-10+1);
+  }
+  numberSlacks_ = numberGoodU_;
+  int *nextCount = nextCount_.array();
+  int *firstCount = firstCount_.array();
+  CoinBigIndex *startRow = startRowU_.array();
+  CoinBigIndex *startColumn = startColumnU;
+  //double *elementL = elementL_.array();
+  //int *indexRowL = indexRowL_.array();
+  //int *saveColumn = saveColumn_.array();
+  //int *nextRow = nextRow_.array();
+  //int *lastRow = lastRow_.array() ;
+  double pivotTolerance = pivotTolerance_;
+  int numberTrials = numberTrials_;
+  int numberRows = numberRows_;
+  // Put column singletons first - (if false)
+  separateLinks(1,(biasLU_>1));
+#ifndef NDEBUG
+  int counter2=0;
+#endif
+  while ( count <= biggerDimension_ ) {
+#ifndef NDEBUG
+    counter2++;
+    int badRow=-1;
+    if (counter1==-1&&counter2>=0) {
+      // check counts consistent
+      for (int iCount=1;iCount<numberRows_;iCount++) {
+        int look = firstCount[iCount];
+        while ( look >= 0 ) {
+          if ( look < numberRows_ ) {
+            int iRow = look;
+            if (iRow==badRow)
+              printf("row count for row %d is %d\n",iCount,iRow);
+            if ( numberInRow[iRow] != iCount ) {
+              printf("failed debug on %d entry to factorSparse and %d try\n",
+                     counter1,counter2);
+              printf("row %d - count %d number %d\n",iRow,iCount,numberInRow[iRow]);
+              abort();
+            }
+            look = nextCount[look];
+          } else {
+            int iColumn = look - numberRows;
+            if ( numberInColumn[iColumn] != iCount ) {
+              printf("failed debug on %d entry to factorSparse and %d try\n",
+                     counter1,counter2);
+              printf("column %d - count %d number %d\n",iColumn,iCount,numberInColumn[iColumn]);
+              abort();
+            }
+            look = nextCount[look];
+          }
+        }
+      }
+    }
+#endif
+    CoinBigIndex minimumCount = COIN_INT_MAX;
+    double minimumCost = COIN_DBL_MAX;
+
+    int iPivotRow = -1;
+    int iPivotColumn = -1;
+    int pivotRowPosition = -1;
+    int pivotColumnPosition = -1;
+    int look = firstCount[count];
+    int trials = 0;
+    int * pivotColumn = pivotColumn_.array();
+
+    if ( count == 1 && firstCount[1] >= 0 &&!biasLU_) {
+      //do column singletons first to put more in U
+      while ( look >= 0 ) {
+        if ( look < numberRows_ ) {
+          look = nextCount[look];
+        } else {
+          int iColumn = look - numberRows_;
+          
+          assert ( numberInColumn[iColumn] == count );
+          CoinBigIndex start = startColumnU[iColumn];
+          int iRow = indexRow[start];
+          
+          iPivotRow = iRow;
+          pivotRowPosition = start;
+          iPivotColumn = iColumn;
+          assert (iPivotRow>=0&&iPivotColumn>=0);
+          pivotColumnPosition = -1;
+          look = -1;
+          break;
+        }
+      }			/* endwhile */
+      if ( iPivotRow < 0 ) {
+        //back to singletons
+        look = firstCount[1];
+      }
+    }
+    while ( look >= 0 ) {
+      if ( look < numberRows_ ) {
+        int iRow = look;
+#ifndef NDEBUG        
+        if ( numberInRow[iRow] != count ) {
+          printf("failed on %d entry to factorSparse and %d try\n",
+                 counter1,counter2);
+          printf("row %d - count %d number %d\n",iRow,count,numberInRow[iRow]);
+          abort();
+        }
+#endif
+        look = nextCount[look];
+        bool rejected = false;
+        CoinBigIndex start = startRow[iRow];
+        CoinBigIndex end = start + count;
+        
+        CoinBigIndex i;
+        for ( i = start; i < end; i++ ) {
+          int iColumn = indexColumn[i];
+          assert (numberInColumn[iColumn]>0);
+          double cost = ( count - 1 ) * numberInColumn[iColumn];
+          
+          if ( cost < minimumCost ) {
+            CoinBigIndex where = startColumn[iColumn];
+            CoinFactorizationDouble minimumValue = element[where];
+            
+            minimumValue = fabs ( minimumValue ) * pivotTolerance;
+            while ( indexRow[where] != iRow ) {
+              where++;
+            }			/* endwhile */
+            assert ( where < startColumn[iColumn] +
+                     numberInColumn[iColumn]);
+            CoinFactorizationDouble value = element[where];
+            
+            value = fabs ( value );
+            if ( value >= minimumValue ) {
+              minimumCost = cost;
+              minimumCount = numberInColumn[iColumn];
+              iPivotRow = iRow;
+              pivotRowPosition = -1;
+              iPivotColumn = iColumn;
+              assert (iPivotRow>=0&&iPivotColumn>=0);
+              pivotColumnPosition = i;
+              rejected=false;
+              if ( minimumCount < count ) {
+                look = -1;
+                break;
+              }
+            } else if ( iPivotRow == -1 ) {
+              rejected = true;
+            }
+          }
+        }
+        trials++;
+        if ( trials >= numberTrials && iPivotRow >= 0 ) {
+          look = -1;
+          break;
+        }
+        if ( rejected ) {
+          //take out for moment
+          //eligible when row changes
+          deleteLink ( iRow );
+          addLink ( iRow, biggerDimension_ + 1 );
+        }
+      } else {
+        int iColumn = look - numberRows;
+        
+        assert ( numberInColumn[iColumn] == count );
+        look = nextCount[look];
+        CoinBigIndex start = startColumn[iColumn];
+        CoinBigIndex end = start + numberInColumn[iColumn];
+        CoinFactorizationDouble minimumValue = element[start];
+        
+        minimumValue = fabs ( minimumValue ) * pivotTolerance;
+        CoinBigIndex i;
+        for ( i = start; i < end; i++ ) {
+          CoinFactorizationDouble value = element[i];
+          
+          value = fabs ( value );
+          if ( value >= minimumValue ) {
+            int iRow = indexRow[i];
+            int nInRow = numberInRow[iRow];
+            assert (nInRow>0);
+            double cost = ( count - 1 ) * nInRow;
+            
+            if ( cost < minimumCost ) {
+              minimumCost = cost;
+              minimumCount = nInRow;
+              iPivotRow = iRow;
+              pivotRowPosition = i;
+              iPivotColumn = iColumn;
+              assert (iPivotRow>=0&&iPivotColumn>=0);
+              pivotColumnPosition = -1;
+              if ( minimumCount <= count + 1 ) {
+                look = -1;
+                break;
+              }
+            }
+          }
+        }
+        trials++;
+        if ( trials >= numberTrials && iPivotRow >= 0 ) {
+          look = -1;
+          break;
+        }
+      }
+    }				/* endwhile */
+    if (iPivotRow>=0) {
+      if ( iPivotRow >= 0 ) {
+        int numberDoRow = numberInRow[iPivotRow] - 1;
+        int numberDoColumn = numberInColumn[iPivotColumn] - 1;
+        
+        totalElements_ -= ( numberDoRow + numberDoColumn + 1 );
+        if ( numberDoColumn > 0 ) {
+          if ( numberDoRow > 0 ) {
+            if ( numberDoColumn > 1 ) {
+              //  if (1) {
+              //need to adjust more for cache and SMP
+              //allow at least 4 extra
+              int increment = numberDoColumn + 1 + 4;
+              
+              if ( increment & 15 ) {
+                increment = increment & ( ~15 );
+                increment += 16;
+              }
+              int increment2 =
+                
+                ( increment + COINFACTORIZATION_BITS_PER_INT - 1 ) >> COINFACTORIZATION_SHIFT_PER_INT;
+              CoinBigIndex size = increment2 * numberDoRow;
+              
+              if ( size > workSize ) {
+                workSize = size;
+		workArea2_.conditionalNew(workSize);
+		workArea2 = workArea2_.array();
+              }
+              bool goodPivot;
+              
+	      //might be able to do better by permuting
+#ifndef UGLY_COIN_FACTOR_CODING
+	      //branch out to best pivot routine 
+	      goodPivot = pivot ( iPivotRow, iPivotColumn,
+				  pivotRowPosition, pivotColumnPosition,
+				  workArea, workArea2, 
+				  increment2, markRow ,
+				  LARGE_SET);
+#else
+#define FAC_SET LARGE_SET
+#include "CoinFactorization.hpp"
+#undef FAC_SET
+#endif
+              if ( !goodPivot ) {
+                status = -99;
+                count=biggerDimension_+1;
+                break;
+              }
+            } else {
+              if ( !pivotOneOtherRow ( iPivotRow, iPivotColumn ) ) {
+                status = -99;
+                count=biggerDimension_+1;
+                break;
+              }
+            }
+          } else {
+            assert (!numberDoRow);
+            if ( !pivotRowSingleton ( iPivotRow, iPivotColumn ) ) {
+              status = -99;
+              count=biggerDimension_+1;
+              break;
+            }
+          }
+        } else {
+          assert (!numberDoColumn);
+          if ( !pivotColumnSingleton ( iPivotRow, iPivotColumn ) ) {
+            status = -99;
+            count=biggerDimension_+1;
+            break;
+          }
+        }
+	assert (nextRow_.array()[iPivotRow]==numberGoodU_);
+        pivotColumn[numberGoodU_] = iPivotColumn;
+        numberGoodU_++;
+        // This should not need to be trapped here - but be safe
+        if (numberGoodU_==numberRows_) 
+          count=biggerDimension_+1;
+      }
+#if COIN_DEBUG==2
+      checkConsistency (  );
+#endif
+#if 0
+      // Even if no dense code may be better to use naive dense
+      if (!denseThreshold_&&totalElements_>1000) {
+        int leftRows=numberRows_-numberGoodU_;
+        double full = leftRows;
+        full *= full;
+        assert (full>=0.0);
+        double leftElements = totalElements_;
+        double ratio;
+        if (leftRows>2000)
+          ratio=4.0;
+        else 
+          ratio=3.0;
+        if (ratio*leftElements>full) 
+          denseThreshold=1;
+      }
+#endif
+      if (denseThreshold) {
+        // see whether to go dense 
+        int leftRows=numberRows_-numberGoodU_;
+        double full = leftRows;
+        full *= full;
+        assert (full>=0.0);
+        double leftElements = totalElements_;
+        //if (leftRows==100)
+        //printf("at 100 %d elements\n",totalElements_);
+        double ratio;
+        if (leftRows>2000)
+          ratio=4.0;
+        else if (leftRows>800)
+          ratio=3.0;
+        else if (leftRows>256)
+          ratio=2.0;
+        else
+          ratio=1.5;
+        if ((ratio*leftElements>full&&leftRows>denseThreshold_)) {
+          //return to do dense
+          if (status!=0)
+            break;
+          int check=0;
+          for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+            if (numberInColumn[iColumn]) 
+              check++;
+          }
+          if (check!=leftRows&&denseThreshold_) {
+            //printf("** mismatch %d columns left, %d rows\n",check,leftRows);
+            denseThreshold=0;
+          } else {
+            status=2;
+            if ((messageLevel_&4)!=0) 
+              std::cout<<"      Went dense at "<<leftRows<<" rows "<<
+                totalElements_<<" "<<full<<" "<<leftElements<<std::endl;
+            if (!denseThreshold_)
+              denseThreshold_=-check; // say how many
+            break;
+          }
+        }
+      }
+      // start at 1 again
+      count = 1;
+    } else {
+      //end of this - onto next
+      count++;
+    } 
+  }				/* endwhile */
+  workArea_.conditionalDelete() ;
+  workArea2_.conditionalDelete() ;
+  return status;
+}
diff --git a/cbits/coin/CoinFactorization3.cpp b/cbits/coin/CoinFactorization3.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFactorization3.cpp
@@ -0,0 +1,2126 @@
+/* $Id: CoinFactorization3.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinUtilsConfig.h"
+
+#include <cassert>
+#include <cstdio>
+
+#include "CoinFactorization.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include <stdio.h>
+#include <iostream>
+#if DENSE_CODE==1 
+// using simple lapack interface
+extern "C" 
+{
+  /** LAPACK Fortran subroutine DGETRS. */
+  void F77_FUNC(dgetrs,DGETRS)(char *trans, cipfint *n,
+                               cipfint *nrhs, const double *A, cipfint *ldA,
+                               cipfint * ipiv, double *B, cipfint *ldB, ipfint *info,
+			       int trans_len);
+}
+#endif
+// For semi-sparse
+#define BITS_PER_CHECK 8
+#define CHECK_SHIFT 3
+typedef unsigned char CoinCheckZero;
+
+//:class CoinFactorization.  Deals with Factorization and Updates
+
+/* Updates one column (FTRAN) from region2 and permutes.
+   region1 starts as zero
+   Note - if regionSparse2 packed on input - will be packed on output
+   - returns un-permuted result in region2 and region1 is zero */
+int CoinFactorization::updateColumn ( CoinIndexedVector * regionSparse,
+				      CoinIndexedVector * regionSparse2,
+				      bool noPermute) 
+  const
+{
+  //permute and move indices into index array
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  int numberNonZero;
+  const int *permute = permute_.array();
+  double * COIN_RESTRICT region = regionSparse->denseVector();
+
+#ifndef CLP_FACTORIZATION
+  if (!noPermute) {
+#endif
+    numberNonZero = regionSparse2->getNumElements();
+    int * COIN_RESTRICT index = regionSparse2->getIndices();
+    double * COIN_RESTRICT array = regionSparse2->denseVector();
+#ifndef CLP_FACTORIZATION
+    bool packed = regionSparse2->packedMode();
+    if (packed) {
+      for (int j = 0; j < numberNonZero; j ++ ) {
+	int iRow = index[j];
+	double value = array[j];
+	array[j]=0.0;
+	iRow = permute[iRow];
+	region[iRow] = value;
+	regionIndex[j] = iRow;
+      }
+    } else {
+#else
+      assert (!regionSparse2->packedMode());
+#endif
+      for (int j = 0; j < numberNonZero; j ++ ) {
+	int iRow = index[j];
+	double value = array[iRow];
+	array[iRow]=0.0;
+	iRow = permute[iRow];
+	region[iRow] = value;
+	regionIndex[j] = iRow;
+      }
+#ifndef CLP_FACTORIZATION
+    }
+#endif
+    regionSparse->setNumElements ( numberNonZero );
+#ifndef CLP_FACTORIZATION
+  } else {
+    numberNonZero = regionSparse->getNumElements();
+  }
+#endif
+  if (collectStatistics_) {
+    numberFtranCounts_++;
+    ftranCountInput_ += numberNonZero;
+  }
+    
+  //  ******* L
+  updateColumnL ( regionSparse, regionIndex );
+  if (collectStatistics_) 
+    ftranCountAfterL_ += regionSparse->getNumElements();
+  //permute extra
+  //row bits here
+  updateColumnR ( regionSparse );
+  if (collectStatistics_) 
+    ftranCountAfterR_ += regionSparse->getNumElements();
+  
+  //update counts
+  //  ******* U
+  updateColumnU ( regionSparse, regionIndex);
+  if (!doForrestTomlin_) {
+    // Do PFI after everything else
+    updateColumnPFI(regionSparse);
+  }
+  if (!noPermute) {
+    permuteBack(regionSparse,regionSparse2);
+    return regionSparse2->getNumElements (  );
+  } else {
+    return regionSparse->getNumElements (  );
+  }
+}
+// Permutes back at end of updateColumn
+void 
+CoinFactorization::permuteBack ( CoinIndexedVector * regionSparse, 
+				 CoinIndexedVector * outVector) const
+{
+  // permute back
+  int oldNumber = regionSparse->getNumElements();
+  const int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  double * COIN_RESTRICT region = regionSparse->denseVector();
+  int * COIN_RESTRICT outIndex = outVector->getIndices (  );
+  double * COIN_RESTRICT out = outVector->denseVector();
+  const int * COIN_RESTRICT permuteBack = pivotColumnBack();
+  int number=0;
+  if (outVector->packedMode()) {
+    for (int j = 0; j < oldNumber; j ++ ) {
+      int iRow = regionIndex[j];
+      double value = region[iRow];
+      region[iRow]=0.0;
+      if (fabs(value)>zeroTolerance_) {
+	iRow = permuteBack[iRow];
+	outIndex[number]=iRow;
+	out[number++] = value;
+      }
+    }
+  } else {
+    for (int j = 0; j < oldNumber; j ++ ) {
+      int iRow = regionIndex[j];
+      double value = region[iRow];
+      region[iRow]=0.0;
+      if (fabs(value)>zeroTolerance_) {
+	iRow = permuteBack[iRow];
+	outIndex[number++]=iRow;
+	out[iRow] = value;
+      }
+    }
+  }
+  outVector->setNumElements(number);
+  regionSparse->setNumElements(0);
+}
+//  updateColumnL.  Updates part of column (FTRANL)
+void
+CoinFactorization::updateColumnL ( CoinIndexedVector * regionSparse,
+					   int * COIN_RESTRICT regionIndex) const
+{
+  if (numberL_) {
+    int number = regionSparse->getNumElements (  );
+    int goSparse;
+    // Guess at number at end
+    if (sparseThreshold_>0) {
+      if (ftranAverageAfterL_) {
+	int newNumber = static_cast<int> (number*ftranAverageAfterL_);
+	if (newNumber< sparseThreshold_&&(numberL_<<2)>newNumber)
+	  goSparse = 2;
+	else if (newNumber< sparseThreshold2_&&(numberL_<<1)>newNumber)
+	  goSparse = 1;
+	else
+	  goSparse = 0;
+      } else {
+	if (number<sparseThreshold_&&(numberL_<<2)>number) 
+	  goSparse = 2;
+	else
+	  goSparse = 0;
+      }
+    } else {
+      goSparse=0;
+    }
+    switch (goSparse) {
+    case 0: // densish
+      updateColumnLDensish(regionSparse,regionIndex);
+      break;
+    case 1: // middling
+      updateColumnLSparsish(regionSparse,regionIndex);
+      break;
+    case 2: // sparse
+      updateColumnLSparse(regionSparse,regionIndex);
+      break;
+    }
+  }
+#ifdef DENSE_CODE
+  if (numberDense_) {
+    //take off list
+    int lastSparse = numberRows_-numberDense_;
+    int number = regionSparse->getNumElements();
+    double * COIN_RESTRICT region = regionSparse->denseVector (  );
+    int i=0;
+    bool doDense=false;
+    while (i<number) {
+      int iRow = regionIndex[i];
+      if (iRow>=lastSparse) {
+	doDense=true;
+	regionIndex[i] = regionIndex[--number];
+      } else {
+	i++;
+      }
+    }
+    if (doDense) {
+      char trans = 'N';
+      int ione=1;
+      int info;
+      F77_FUNC(dgetrs,DGETRS)(&trans,&numberDense_,&ione,denseArea_,&numberDense_,
+			      densePermute_,region+lastSparse,&numberDense_,&info,1);
+      for (int i=lastSparse;i<numberRows_;i++) {
+	double value = region[i];
+	if (value) {
+	  if (fabs(value)>=1.0e-15) 
+	    regionIndex[number++] = i;
+	  else
+	    region[i]=0.0;
+	}
+      }
+      regionSparse->setNumElements(number);
+    }
+  }
+#endif
+}
+// Updates part of column (FTRANL) when densish
+void 
+CoinFactorization::updateColumnLDensish ( CoinIndexedVector * regionSparse ,
+					  int * COIN_RESTRICT regionIndex)
+  const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int number = regionSparse->getNumElements (  );
+  int numberNonZero;
+  double tolerance = zeroTolerance_;
+  
+  numberNonZero = 0;
+  
+  const CoinBigIndex * COIN_RESTRICT startColumn = startColumnL_.array();
+  const int * COIN_RESTRICT indexRow = indexRowL_.array();
+  const CoinFactorizationDouble * COIN_RESTRICT element = elementL_.array();
+  int last = numberRows_;
+  assert ( last == baseL_ + numberL_);
+#if DENSE_CODE==1
+  //can take out last bit of sparse L as empty
+  last -= numberDense_;
+#endif
+  int smallestIndex = numberRowsExtra_;
+  // do easy ones
+  for (int k=0;k<number;k++) {
+    int iPivot=regionIndex[k];
+    if (iPivot>=baseL_) 
+      smallestIndex = CoinMin(iPivot,smallestIndex);
+    else
+      regionIndex[numberNonZero++]=iPivot;
+  }
+  // now others
+  for (int i = smallestIndex; i < last; i++ ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    
+    if ( fabs(pivotValue) > tolerance ) {
+      CoinBigIndex start = startColumn[i];
+      CoinBigIndex end = startColumn[i + 1];
+      for (CoinBigIndex j = start; j < end; j ++ ) {
+	int iRow = indexRow[j];
+	CoinFactorizationDouble result = region[iRow];
+	CoinFactorizationDouble value = element[j];
+
+	region[iRow] = result - value * pivotValue;
+      }     
+      regionIndex[numberNonZero++] = i;
+    } else {
+      region[i] = 0.0;
+    }       
+  }     
+  // and dense
+  for (int i=last ; i < numberRows_; i++ ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    if ( fabs(pivotValue) > tolerance ) {
+      regionIndex[numberNonZero++] = i;
+    } else {
+      region[i] = 0.0;
+    }       
+  }     
+  regionSparse->setNumElements ( numberNonZero );
+} 
+// Updates part of column (FTRANL) when sparsish
+void 
+CoinFactorization::updateColumnLSparsish ( CoinIndexedVector * regionSparse,
+					   int * COIN_RESTRICT regionIndex)
+  const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int number = regionSparse->getNumElements (  );
+  int numberNonZero;
+  double tolerance = zeroTolerance_;
+  
+  numberNonZero = 0;
+  
+  const CoinBigIndex *startColumn = startColumnL_.array();
+  const int *indexRow = indexRowL_.array();
+  const CoinFactorizationDouble *element = elementL_.array();
+  int last = numberRows_;
+  assert ( last == baseL_ + numberL_);
+#if DENSE_CODE==1
+  //can take out last bit of sparse L as empty
+  last -= numberDense_;
+#endif
+  // mark known to be zero
+  int nInBig = sizeof(CoinBigIndex)/sizeof(int);
+  CoinCheckZero * COIN_RESTRICT mark = reinterpret_cast<CoinCheckZero *> (sparse_.array()+(2+nInBig)*maximumRowsExtra_);
+  int smallestIndex = numberRowsExtra_;
+  // do easy ones
+  for (int k=0;k<number;k++) {
+    int iPivot=regionIndex[k];
+    if (iPivot<baseL_) { 
+      regionIndex[numberNonZero++]=iPivot;
+    } else {
+      smallestIndex = CoinMin(iPivot,smallestIndex);
+      int iWord = iPivot>>CHECK_SHIFT;
+      int iBit = iPivot-(iWord<<CHECK_SHIFT);
+      if (mark[iWord]) {
+	mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+      } else {
+	mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+      }
+    }
+  }
+  // now others
+  // First do up to convenient power of 2
+  int jLast = (smallestIndex+BITS_PER_CHECK-1)>>CHECK_SHIFT;
+  jLast = CoinMin((jLast<<CHECK_SHIFT),last);
+  int i;
+  for ( i = smallestIndex; i < jLast; i++ ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    CoinBigIndex start = startColumn[i];
+    CoinBigIndex end = startColumn[i + 1];
+    
+    if ( fabs(pivotValue) > tolerance ) {
+      for (CoinBigIndex j = start; j < end; j ++ ) {
+	int iRow = indexRow[j];
+	CoinFactorizationDouble result = region[iRow];
+	CoinFactorizationDouble value = element[j];
+	region[iRow] = result - value * pivotValue;
+	int iWord = iRow>>CHECK_SHIFT;
+	int iBit = iRow-(iWord<<CHECK_SHIFT);
+	if (mark[iWord]) {
+	  mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+	} else {
+	  mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+	}
+      }     
+      regionIndex[numberNonZero++] = i;
+    } else {
+      region[i] = 0.0;
+    }       
+  }
+  
+  int kLast = last>>CHECK_SHIFT;
+  if (jLast<last) {
+    // now do in chunks
+    for (int k=(jLast>>CHECK_SHIFT);k<kLast;k++) {
+      unsigned int iMark = mark[k];
+      if (iMark) {
+	// something in chunk - do all (as imark may change)
+	i = k<<CHECK_SHIFT;
+	int iLast = i+BITS_PER_CHECK;
+	for ( ; i < iLast; i++ ) {
+	  CoinFactorizationDouble pivotValue = region[i];
+	  CoinBigIndex start = startColumn[i];
+	  CoinBigIndex end = startColumn[i + 1];
+	  
+	  if ( fabs(pivotValue) > tolerance ) {
+	    CoinBigIndex j;
+	    for ( j = start; j < end; j ++ ) {
+	      int iRow = indexRow[j];
+	      CoinFactorizationDouble result = region[iRow];
+	      CoinFactorizationDouble value = element[j];
+	      region[iRow] = result - value * pivotValue;
+	      int iWord = iRow>>CHECK_SHIFT;
+	      int iBit = iRow-(iWord<<CHECK_SHIFT);
+	      if (mark[iWord]) {
+		mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+	      } else {
+		mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+	      }
+	    }     
+	    regionIndex[numberNonZero++] = i;
+	  } else {
+	    region[i] = 0.0;
+	  }       
+	}
+	mark[k]=0; // zero out marked
+      }
+    }
+    i = kLast<<CHECK_SHIFT;
+  }
+  for ( ; i < last; i++ ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    CoinBigIndex start = startColumn[i];
+    CoinBigIndex end = startColumn[i + 1];
+    
+    if ( fabs(pivotValue) > tolerance ) {
+      for (CoinBigIndex j = start; j < end; j ++ ) {
+	int iRow = indexRow[j];
+	CoinFactorizationDouble result = region[iRow];
+	CoinFactorizationDouble value = element[j];
+	region[iRow] = result - value * pivotValue;
+      }     
+      regionIndex[numberNonZero++] = i;
+    } else {
+      region[i] = 0.0;
+    }       
+  }
+  // Now dense part
+  for ( ; i < numberRows_; i++ ) {
+    double pivotValue = region[i];
+    if ( fabs(pivotValue) > tolerance ) {
+      regionIndex[numberNonZero++] = i;
+    } else {
+      region[i] = 0.0;
+    }       
+  }
+  // zero out ones that might have been skipped
+  mark[smallestIndex>>CHECK_SHIFT]=0;
+  int kkLast = (numberRows_+BITS_PER_CHECK-1)>>CHECK_SHIFT;
+  CoinZeroN(mark+kLast,kkLast-kLast);
+  regionSparse->setNumElements ( numberNonZero );
+}
+// Updates part of column (FTRANL) when sparse
+void 
+CoinFactorization::updateColumnLSparse ( CoinIndexedVector * regionSparse ,
+					   int * COIN_RESTRICT regionIndex)
+  const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int number = regionSparse->getNumElements (  );
+  int numberNonZero;
+  double tolerance = zeroTolerance_;
+  
+  numberNonZero = 0;
+  
+  const CoinBigIndex *startColumn = startColumnL_.array();
+  const int *indexRow = indexRowL_.array();
+  const CoinFactorizationDouble *element = elementL_.array();
+  // use sparse_ as temporary area
+  // mark known to be zero
+  int * COIN_RESTRICT stack = sparse_.array();  /* pivot */
+  int * COIN_RESTRICT list = stack + maximumRowsExtra_;  /* final list */
+  CoinBigIndex * COIN_RESTRICT next = reinterpret_cast<CoinBigIndex *> (list + maximumRowsExtra_);  /* jnext */
+  char * COIN_RESTRICT mark = reinterpret_cast<char *> (next + maximumRowsExtra_);
+  int nList;
+#ifdef COIN_DEBUG
+  for (int i=0;i<maximumRowsExtra_;i++) {
+    assert (!mark[i]);
+  }
+#endif
+  nList=0;
+  for (int k=0;k<number;k++) {
+    int kPivot=regionIndex[k];
+    if (kPivot>=baseL_) {
+      assert (kPivot<numberRowsExtra_);
+      //if (kPivot>=numberRowsExtra_) abort();
+      if(!mark[kPivot]) {
+	stack[0]=kPivot;
+	CoinBigIndex j=startColumn[kPivot+1]-1;
+        int nStack=0;
+	while (nStack>=0) {
+	  /* take off stack */
+	  if (j>=startColumn[kPivot]) {
+	    int jPivot=indexRow[j--];
+	    assert (jPivot>=baseL_&&jPivot<numberRowsExtra_);
+	    //if (jPivot<baseL_||jPivot>=numberRowsExtra_) abort();
+	    /* put back on stack */
+	    next[nStack] =j;
+	    if (!mark[jPivot]) {
+	      /* and new one */
+	      kPivot=jPivot;
+	      j = startColumn[kPivot+1]-1;
+	      stack[++nStack]=kPivot;
+	      assert (kPivot<numberRowsExtra_);
+	      //if (kPivot>=numberRowsExtra_) abort();
+	      mark[kPivot]=1;
+	      next[nStack]=j;
+	    }
+	  } else {
+	    /* finished so mark */
+	    list[nList++]=kPivot;
+	    mark[kPivot]=1;
+	    --nStack;
+	    if (nStack>=0) {
+	      kPivot=stack[nStack];
+	      assert (kPivot<numberRowsExtra_);
+	      j=next[nStack];
+	    }
+	  }
+	}
+      }
+    } else {
+      // just put on list
+      regionIndex[numberNonZero++]=kPivot;
+    }
+  }
+  for (int i=nList-1;i>=0;i--) {
+    int iPivot = list[i];
+    mark[iPivot]=0;
+    CoinFactorizationDouble pivotValue = region[iPivot];
+    if ( fabs ( pivotValue ) > tolerance ) {
+      regionIndex[numberNonZero++]=iPivot;
+      for (CoinBigIndex j = startColumn[iPivot]; 
+	   j < startColumn[iPivot+1]; j ++ ) {
+	int iRow = indexRow[j];
+	CoinFactorizationDouble value = element[j];
+	region[iRow] -= value * pivotValue;
+      }
+    } else {
+      region[iPivot]=0.0;
+    }
+  }
+  regionSparse->setNumElements ( numberNonZero );
+}
+/* Updates one column (FTRAN) from region2
+   Tries to do FT update
+   number returned is negative if no room.
+   Also updates region3
+   region1 starts as zero and is zero at end */
+int 
+CoinFactorization::updateTwoColumnsFT ( CoinIndexedVector * regionSparse1,
+					CoinIndexedVector * regionSparse2,
+					CoinIndexedVector * regionSparse3,
+					bool noPermuteRegion3)
+{
+#if 1
+  //#ifdef NDEBUG
+  //#undef NDEBUG
+  //#endif
+  //#define COIN_DEBUG
+#ifdef COIN_DEBUG
+  regionSparse1->checkClean();
+  CoinIndexedVector save2(*regionSparse2);
+  CoinIndexedVector save3(*regionSparse3);
+#endif
+  CoinIndexedVector * regionFT ;
+  CoinIndexedVector * regionUpdate ;
+  int * COIN_RESTRICT regionIndex ;
+  int numberNonZero ;
+  const int *permute = permute_.array();
+  int * COIN_RESTRICT index ;
+  double * COIN_RESTRICT region ;
+  if (!noPermuteRegion3) {
+    regionFT = regionSparse3;
+    regionUpdate = regionSparse1;
+    //permute and move indices into index array
+    regionIndex = regionUpdate->getIndices (  );
+    //int numberNonZero;
+    region = regionUpdate->denseVector();
+    
+    numberNonZero = regionSparse3->getNumElements();
+    int * COIN_RESTRICT index = regionSparse3->getIndices();
+    double * COIN_RESTRICT array = regionSparse3->denseVector();
+    assert (!regionSparse3->packedMode());
+    for (int j = 0; j < numberNonZero; j ++ ) {
+      int iRow = index[j];
+      double value = array[iRow];
+      array[iRow]=0.0;
+      iRow = permute[iRow];
+      region[iRow] = value;
+      regionIndex[j] = iRow;
+    }
+    regionUpdate->setNumElements ( numberNonZero );
+  } else {
+    regionFT = regionSparse1;
+    regionUpdate = regionSparse3;
+  }
+  //permute and move indices into index array (in U)
+  regionIndex = regionFT->getIndices (  );
+  numberNonZero = regionSparse2->getNumElements();
+  index = regionSparse2->getIndices();
+  region = regionFT->denseVector();
+  double * COIN_RESTRICT array = regionSparse2->denseVector();
+  CoinBigIndex * COIN_RESTRICT startColumnU = startColumnU_.array();
+  CoinBigIndex start = startColumnU[maximumColumnsExtra_];
+  startColumnU[numberColumnsExtra_] = start;
+  regionIndex = indexRowU_.array() + start;
+
+  assert(regionSparse2->packedMode());
+  for (int j = 0; j < numberNonZero; j ++ ) {
+    int iRow = index[j];
+    double value = array[j];
+    array[j]=0.0;
+    iRow = permute[iRow];
+    region[iRow] = value;
+    regionIndex[j] = iRow;
+  }
+  regionFT->setNumElements ( numberNonZero );
+  if (collectStatistics_) {
+    numberFtranCounts_+=2;
+    ftranCountInput_ += regionFT->getNumElements()+
+      regionUpdate->getNumElements();
+  }
+    
+  //  ******* L
+  updateColumnL ( regionFT, regionIndex );
+  updateColumnL ( regionUpdate, regionUpdate->getIndices() );
+  if (collectStatistics_) 
+    ftranCountAfterL_ += regionFT->getNumElements()+
+      regionUpdate->getNumElements();
+  //permute extra
+  //row bits here
+  updateColumnRFT ( regionFT, regionIndex );
+  updateColumnR ( regionUpdate );
+  if (collectStatistics_) 
+    ftranCountAfterR_ += regionFT->getNumElements()+
+    regionUpdate->getNumElements();
+  //  ******* U - see if densish
+  // Guess at number at end
+  int goSparse=0;
+  if (sparseThreshold_>0) {
+    int numberNonZero = (regionUpdate->getNumElements (  )+
+			 regionFT->getNumElements())>>1;
+    if (ftranAverageAfterR_) {
+      int newNumber = static_cast<int> (numberNonZero*ftranAverageAfterU_);
+      if (newNumber< sparseThreshold_)
+	goSparse = 2;
+      else if (newNumber< sparseThreshold2_)
+	goSparse = 1;
+    } else {
+      if (numberNonZero<sparseThreshold_) 
+	goSparse = 2;
+    }
+  }
+#ifndef COIN_FAST_CODE
+  assert (slackValue_==-1.0);
+#endif
+  if (!goSparse&&numberRows_<1000) {
+    double * COIN_RESTRICT arrayFT = regionFT->denseVector (  );
+    int * COIN_RESTRICT indexFT = regionFT->getIndices();
+    int numberNonZeroFT;
+    double * COIN_RESTRICT arrayUpdate = regionUpdate->denseVector (  );
+    int * COIN_RESTRICT indexUpdate = regionUpdate->getIndices();
+    int numberNonZeroUpdate;
+    updateTwoColumnsUDensish(numberNonZeroFT,arrayFT,indexFT,
+			     numberNonZeroUpdate,arrayUpdate,indexUpdate);
+    regionFT->setNumElements ( numberNonZeroFT );
+    regionUpdate->setNumElements ( numberNonZeroUpdate );
+  } else {
+    // sparse 
+    updateColumnU ( regionFT, regionIndex);
+    updateColumnU ( regionUpdate, regionUpdate->getIndices());
+  }
+  permuteBack(regionFT,regionSparse2);
+  if (!noPermuteRegion3) {
+    permuteBack(regionUpdate,regionSparse3);
+  }
+#ifdef COIN_DEBUG
+  int n2=regionSparse2->getNumElements();
+  regionSparse1->checkClean();
+  int n2a= updateColumnFT(regionSparse1,&save2);
+  assert(n2==n2a);
+  {
+    int j;
+    double * regionA = save2.denseVector();
+    int * indexA = save2.getIndices();
+    double * regionB = regionSparse2->denseVector();
+    int * indexB = regionSparse2->getIndices();
+    for (j=0;j<n2;j++) {
+      int k = indexA[j];
+      assert (k==indexB[j]);
+      CoinFactorizationDouble value = regionA[j];
+      assert (value==regionB[j]);
+    }
+  }
+  updateColumn(&save3,
+	       &save3,
+	       noPermuteRegion3);
+  int n3=regionSparse3->getNumElements();
+  assert (n3==save3.getNumElements());
+  {
+    int j;
+    double * regionA = save3.denseVector();
+    int * indexA = save3.getIndices();
+    double * regionB = regionSparse3->denseVector();
+    int * indexB = regionSparse3->getIndices();
+    for (j=0;j<n3;j++) {
+      int k = indexA[j];
+      assert (k==indexB[j]);
+      CoinFactorizationDouble value = regionA[k];
+      assert (value==regionB[k]);
+    }
+  }
+  //*regionSparse2=save2;
+  //*regionSparse3=save3;
+  printf("REGION2 %d els\n",regionSparse2->getNumElements());
+  regionSparse2->print();
+  printf("REGION3 %d els\n",regionSparse3->getNumElements());
+  regionSparse3->print();
+#endif
+  return regionSparse2->getNumElements();
+#else
+  int returnCode= updateColumnFT(regionSparse1,
+				 regionSparse2);
+  assert (noPermuteRegion3);
+  updateColumn(regionSparse3,
+	       regionSparse3,
+	       noPermuteRegion3);
+  //printf("REGION2 %d els\n",regionSparse2->getNumElements());
+  //regionSparse2->print();
+  //printf("REGION3 %d els\n",regionSparse3->getNumElements());
+  //regionSparse3->print();
+  return returnCode;
+#endif
+}
+// Updates part of 2 columns (FTRANU) real work
+void
+CoinFactorization::updateTwoColumnsUDensish (
+					     int & numberNonZero1,
+					     double * COIN_RESTRICT region1, 
+					     int * COIN_RESTRICT index1,
+					     int & numberNonZero2,
+					     double * COIN_RESTRICT region2, 
+					     int * COIN_RESTRICT index2) const
+{
+  double tolerance = zeroTolerance_;
+  const CoinBigIndex * COIN_RESTRICT startColumn = startColumnU_.array();
+  const int * COIN_RESTRICT indexRow = indexRowU_.array();
+  const CoinFactorizationDouble * COIN_RESTRICT element = elementU_.array();
+  int numberNonZeroA = 0;
+  int numberNonZeroB = 0;
+  const int *numberInColumn = numberInColumn_.array();
+  const CoinFactorizationDouble *pivotRegion = pivotRegion_.array();
+  
+  for (int i = numberU_-1 ; i >= numberSlacks_; i-- ) {
+    CoinFactorizationDouble pivotValue2 = region2[i];
+    region2[i] = 0.0;
+    CoinFactorizationDouble pivotValue1 = region1[i];
+    region1[i] = 0.0;
+    if ( fabs ( pivotValue2 ) > tolerance ) {
+      CoinBigIndex start = startColumn[i];
+      const CoinFactorizationDouble * COIN_RESTRICT thisElement = element+start;
+      const int * COIN_RESTRICT thisIndex = indexRow+start;
+      if ( fabs ( pivotValue1 ) <= tolerance ) {
+	// just region 2
+	for (CoinBigIndex j=numberInColumn[i]-1 ; j >=0; j-- ) {
+	  int iRow = thisIndex[j];
+	  CoinFactorizationDouble value = thisElement[j];
+#ifdef NO_LOAD
+	  region2[iRow] -= value * pivotValue2;
+#else
+	  CoinFactorizationDouble regionValue2 = region2[iRow];
+	  region2[iRow] = regionValue2 - value * pivotValue2;
+#endif
+	}
+	pivotValue2 *= pivotRegion[i];
+	region2[i]=pivotValue2;
+	index2[numberNonZeroB++]=i;
+      } else {
+	// both
+	for (CoinBigIndex j=numberInColumn[i]-1 ; j >=0; j-- ) {
+	  int iRow = thisIndex[j];
+	  CoinFactorizationDouble value = thisElement[j];
+#ifdef NO_LOAD
+	  region1[iRow] -= value * pivotValue1;
+	  region2[iRow] -= value * pivotValue2;
+#else
+	  CoinFactorizationDouble regionValue1 = region1[iRow];
+	  CoinFactorizationDouble regionValue2 = region2[iRow];
+	  region1[iRow] = regionValue1 - value * pivotValue1;
+	  region2[iRow] = regionValue2 - value * pivotValue2;
+#endif
+	}
+	pivotValue1 *= pivotRegion[i];
+	pivotValue2 *= pivotRegion[i];
+	region1[i]=pivotValue1;
+	index1[numberNonZeroA++]=i;
+	region2[i]=pivotValue2;
+	index2[numberNonZeroB++]=i;
+      }
+    } else if ( fabs ( pivotValue1 ) > tolerance ) {
+      CoinBigIndex start = startColumn[i];
+      const CoinFactorizationDouble * COIN_RESTRICT thisElement = element+start;
+      const int * COIN_RESTRICT thisIndex = indexRow+start;
+      // just region 1
+      for (CoinBigIndex j=numberInColumn[i]-1 ; j >=0; j-- ) {
+	int iRow = thisIndex[j];
+	CoinFactorizationDouble value = thisElement[j];
+#ifdef NO_LOAD
+	region1[iRow] -= value * pivotValue1;
+#else
+	CoinFactorizationDouble regionValue1 = region1[iRow];
+	region1[iRow] = regionValue1 - value * pivotValue1;
+#endif
+      }
+      pivotValue1 *= pivotRegion[i];
+      region1[i]=pivotValue1;
+      index1[numberNonZeroA++]=i;
+    }
+  }
+  // Slacks 
+    
+  for (int i = numberSlacks_-1; i>=0;i--) {
+    double value2 = region2[i];
+    double value1 = region1[i];
+    bool value1NonZero = (value1!=0.0);
+    if ( fabs(value2) > tolerance ) {
+      region2[i]=-value2;
+      index2[numberNonZeroB++]=i;
+    } else {
+      region2[i]=0.0;
+    }
+    if ( value1NonZero ) {
+      index1[numberNonZeroA]=i;
+      if ( fabs(value1) > tolerance ) {
+	region1[i]=-value1;
+	numberNonZeroA++;
+      } else {
+	region1[i]=0.0;
+      }
+    }
+  }
+  numberNonZero1=numberNonZeroA;
+  numberNonZero2=numberNonZeroB;
+}
+//  updateColumnU.  Updates part of column (FTRANU)
+void
+CoinFactorization::updateColumnU ( CoinIndexedVector * regionSparse,
+				   int * indexIn) const
+{
+  int numberNonZero = regionSparse->getNumElements (  );
+
+  int goSparse;
+  // Guess at number at end
+  if (sparseThreshold_>0) {
+    if (ftranAverageAfterR_) {
+      int newNumber = static_cast<int> (numberNonZero*ftranAverageAfterU_);
+      if (newNumber< sparseThreshold_)
+	goSparse = 2;
+      else if (newNumber< sparseThreshold2_)
+	goSparse = 1;
+      else
+	goSparse = 0;
+    } else {
+      if (numberNonZero<sparseThreshold_) 
+	goSparse = 2;
+      else
+	goSparse = 0;
+    }
+  } else {
+    goSparse=0;
+  }
+  switch (goSparse) {
+  case 0: // densish
+    {
+      double *region = regionSparse->denseVector (  );
+      int * regionIndex = regionSparse->getIndices();
+      int numberNonZero=updateColumnUDensish(region,regionIndex);
+      regionSparse->setNumElements ( numberNonZero );
+    }
+    break;
+  case 1: // middling
+    updateColumnUSparsish(regionSparse,indexIn);
+    break;
+  case 2: // sparse
+    updateColumnUSparse(regionSparse,indexIn);
+    break;
+  }
+  if (collectStatistics_) 
+    ftranCountAfterU_ += regionSparse->getNumElements (  );
+}
+#ifdef COIN_DEVELOP
+double ncall_DZ=0.0;
+double nrow_DZ=0.0;
+double nslack_DZ=0.0;
+double nU_DZ=0.0;
+double nnz_DZ=0.0;
+double nDone_DZ=0.0;
+#endif
+// Updates part of column (FTRANU) real work
+int 
+CoinFactorization::updateColumnUDensish ( double * COIN_RESTRICT region, 
+					  int * COIN_RESTRICT regionIndex) const
+{
+  double tolerance = zeroTolerance_;
+  const CoinBigIndex *startColumn = startColumnU_.array();
+  const int *indexRow = indexRowU_.array();
+  const CoinFactorizationDouble *element = elementU_.array();
+  int numberNonZero = 0;
+  const int *numberInColumn = numberInColumn_.array();
+  const CoinFactorizationDouble *pivotRegion = pivotRegion_.array();
+#ifdef COIN_DEVELOP
+  ncall_DZ++;
+  nrow_DZ += numberRows_;
+  nslack_DZ += numberSlacks_;
+  nU_DZ += numberU_;
+#endif
+  
+  for (int i = numberU_-1 ; i >= numberSlacks_; i-- ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    if (pivotValue) {
+#ifdef COIN_DEVELOP
+      nnz_DZ++;
+#endif
+      region[i] = 0.0;
+      if ( fabs ( pivotValue ) > tolerance ) {
+	CoinBigIndex start = startColumn[i];
+	const CoinFactorizationDouble * thisElement = element+start;
+	const int * thisIndex = indexRow+start;
+#ifdef COIN_DEVELOP
+	nDone_DZ += numberInColumn[i];
+#endif
+	for (CoinBigIndex j=numberInColumn[i]-1 ; j >=0; j-- ) {
+	  int iRow = thisIndex[j];
+	  CoinFactorizationDouble regionValue = region[iRow];
+	  CoinFactorizationDouble value = thisElement[j];
+	  region[iRow] = regionValue - value * pivotValue;
+	}
+	pivotValue *= pivotRegion[i];
+	region[i]=pivotValue;
+	regionIndex[numberNonZero++]=i;
+      }
+    }
+  }
+    
+  // now do slacks
+#ifndef COIN_FAST_CODE
+  if (slackValue_==-1.0) {
+#endif
+#if 0
+    // Could skew loop to pick up next one earlier
+    // might improve pipelining
+    for (int i = numberSlacks_-1; i>2;i-=2) {
+      double value0 = region[i];
+      double absValue0 = fabs ( value0 );
+      double value1 = region[i-1];
+      double absValue1 = fabs ( value1 );
+      if ( value0 ) {
+	if ( absValue0 > tolerance ) {
+	  region[i]=-value0;
+	  regionIndex[numberNonZero++]=i;
+	} else {
+	  region[i]=0.0;
+	}
+      }
+      if ( value1 ) {
+	if ( absValue1 > tolerance ) {
+	  region[i-1]=-value1;
+	  regionIndex[numberNonZero++]=i-1;
+	} else {
+	  region[i-1]=0.0;
+	}
+      }
+    }
+    for ( ; i>=0;i--) {
+      double value = region[i];
+      double absValue = fabs ( value );
+      if ( value ) {
+	if ( absValue > tolerance ) {
+	  region[i]=-value;
+	  regionIndex[numberNonZero++]=i;
+	} else {
+	  region[i]=0.0;
+	}
+      }
+    }
+#else
+    for (int i = numberSlacks_-1; i>=0;i--) {
+      double value = region[i];
+      if ( value ) {
+	region[i]=-value;
+	regionIndex[numberNonZero]=i;
+	if ( fabs(value) > tolerance ) 
+	  numberNonZero++;
+	else 
+	  region[i]=0.0;
+      }
+    }
+#endif
+#ifndef COIN_FAST_CODE
+  } else {
+    assert (slackValue_==1.0);
+    for (int i = numberSlacks_-1; i>=0;i--) {
+      double value = region[i];
+      double absValue = fabs ( value );
+      if ( value ) {
+	region[i]=0.0;
+	if ( absValue > tolerance ) {
+	  region[i]=value;
+	  regionIndex[numberNonZero++]=i;
+	}
+      }
+    }
+  }
+#endif
+  return numberNonZero;
+}
+//  updateColumnU.  Updates part of column (FTRANU)
+/*
+  Since everything is in order I should be able to do a better job of
+  marking stuff - think.  Also as L is static maybe I can do something
+  better there (I know I could if I marked the depth of every element
+  but that would lead to other inefficiencies.
+*/
+void
+CoinFactorization::updateColumnUSparse ( CoinIndexedVector * regionSparse,
+					 int * COIN_RESTRICT indexIn) const
+{
+  int numberNonZero = regionSparse->getNumElements (  );
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  double tolerance = zeroTolerance_;
+  const CoinBigIndex *startColumn = startColumnU_.array();
+  const int *indexRow = indexRowU_.array();
+  const CoinFactorizationDouble *element = elementU_.array();
+  const CoinFactorizationDouble *pivotRegion = pivotRegion_.array();
+  // use sparse_ as temporary area
+  // mark known to be zero
+  int * COIN_RESTRICT stack = sparse_.array();  /* pivot */
+  int * COIN_RESTRICT list = stack + maximumRowsExtra_;  /* final list */
+  CoinBigIndex * COIN_RESTRICT next = reinterpret_cast<CoinBigIndex *> (list + maximumRowsExtra_);  /* jnext */
+  char * COIN_RESTRICT mark = reinterpret_cast<char *> (next + maximumRowsExtra_);
+#ifdef COIN_DEBUG
+  for (int i=0;i<maximumRowsExtra_;i++) {
+    assert (!mark[i]);
+  }
+#endif
+
+  // move slacks to end of stack list
+  int * COIN_RESTRICT putLast = stack+maximumRowsExtra_;
+  int * COIN_RESTRICT put = putLast;
+
+  const int *numberInColumn = numberInColumn_.array();
+  int nList = 0;
+  for (int i=0;i<numberNonZero;i++) {
+    int kPivot=indexIn[i];
+    stack[0]=kPivot;
+    CoinBigIndex j=startColumn[kPivot]+numberInColumn[kPivot]-1;
+    int nStack=1;
+    next[0]=j;
+    while (nStack) {
+      /* take off stack */
+      int kPivot=stack[--nStack];
+      if (mark[kPivot]!=1) {
+	j=next[nStack];
+	if (j>=startColumn[kPivot]) {
+	  kPivot=indexRow[j--];
+	  /* put back on stack */
+	  next[nStack++] =j;
+	  if (!mark[kPivot]) {
+	    /* and new one */
+	    int numberIn = numberInColumn[kPivot];
+	    if (numberIn) {
+	      j = startColumn[kPivot]+numberIn-1;
+	      stack[nStack]=kPivot;
+	      mark[kPivot]=2;
+	      next[nStack++]=j;
+	    } else {
+	      // can do immediately
+	      /* finished so mark */
+	      mark[kPivot]=1;
+	      if (kPivot>=numberSlacks_) {
+		list[nList++]=kPivot;
+	      } else {
+		// slack - put at end
+		--put;
+		*put=kPivot;
+	      }
+	    }
+	  }
+	} else {
+	  /* finished so mark */
+	  mark[kPivot]=1;
+	  if (kPivot>=numberSlacks_) {
+	    list[nList++]=kPivot;
+	  } else {
+	    // slack - put at end
+	    assert (!numberInColumn[kPivot]);
+	    --put;
+	    *put=kPivot;
+	  }
+	}
+      }
+    }
+  }
+#if 0
+  {
+    std::sort(list,list+nList);
+    int i;
+    int last;
+    last =-1;
+    for (i=0;i<nList;i++) {
+      int k = list[i];
+      assert (k>last);
+      last=k;
+    }
+    std::sort(put,putLast);
+    int n = putLast-put;
+    last =-1;
+    for (i=0;i<n;i++) {
+      int k = put[i];
+      assert (k>last);
+      last=k;
+    }
+  }
+#endif
+  numberNonZero=0;
+  for (int i=nList-1;i>=0;i--) {
+    int iPivot = list[i];
+    mark[iPivot]=0;
+    CoinFactorizationDouble pivotValue = region[iPivot];
+    region[iPivot]=0.0;
+    if ( fabs ( pivotValue ) > tolerance ) {
+      CoinBigIndex start = startColumn[iPivot];
+      int number = numberInColumn[iPivot];
+      
+      CoinBigIndex j;
+      for ( j = start; j < start+number; j++ ) {
+	CoinFactorizationDouble value = element[j];
+	int iRow = indexRow[j];
+	region[iRow] -=  value * pivotValue;
+      }
+      pivotValue *= pivotRegion[iPivot];
+      region[iPivot]=pivotValue;
+      regionIndex[numberNonZero++]=iPivot;
+    }
+  }
+  // slacks
+#ifndef COIN_FAST_CODE
+  if (slackValue_==1.0) {
+    for (;put<putLast;put++) {
+      int iPivot = *put;
+      mark[iPivot]=0;
+      CoinFactorizationDouble pivotValue = region[iPivot];
+      region[iPivot]=0.0;
+      if ( fabs ( pivotValue ) > tolerance ) {
+	region[iPivot]=pivotValue;
+	regionIndex[numberNonZero++]=iPivot;
+      }
+    }
+  } else {
+#endif
+    for (;put<putLast;put++) {
+      int iPivot = *put;
+      mark[iPivot]=0;
+      CoinFactorizationDouble pivotValue = region[iPivot];
+      region[iPivot]=0.0;
+      if ( fabs ( pivotValue ) > tolerance ) {
+	region[iPivot]=-pivotValue;
+	regionIndex[numberNonZero++]=iPivot;
+      }
+    }
+#ifndef COIN_FAST_CODE
+  }
+#endif
+  regionSparse->setNumElements ( numberNonZero );
+}
+//  updateColumnU.  Updates part of column (FTRANU)
+/*
+  Since everything is in order I should be able to do a better job of
+  marking stuff - think.  Also as L is static maybe I can do something
+  better there (I know I could if I marked the depth of every element
+  but that would lead to other inefficiencies.
+*/
+#ifdef COIN_DEVELOP
+double ncall_SZ=0.0;
+double nrow_SZ=0.0;
+double nslack_SZ=0.0;
+double nU_SZ=0.0;
+double nnz_SZ=0.0;
+double nDone_SZ=0.0;
+#endif
+void
+CoinFactorization::updateColumnUSparsish ( CoinIndexedVector * regionSparse,
+					   int * COIN_RESTRICT indexIn) const
+{
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  // mark known to be zero
+  int * COIN_RESTRICT stack = sparse_.array();  /* pivot */
+  int * COIN_RESTRICT list = stack + maximumRowsExtra_;  /* final list */
+  CoinBigIndex * COIN_RESTRICT next = reinterpret_cast<CoinBigIndex *> (list + maximumRowsExtra_);  /* jnext */
+  CoinCheckZero * COIN_RESTRICT mark = reinterpret_cast<CoinCheckZero *> (next + maximumRowsExtra_);
+  const int *numberInColumn = numberInColumn_.array();
+#ifdef COIN_DEBUG
+  for (int i=0;i<maximumRowsExtra_;i++) {
+    assert (!mark[i]);
+  }
+#endif
+
+  int nMarked=0;
+  int numberNonZero = regionSparse->getNumElements (  );
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  double tolerance = zeroTolerance_;
+  const CoinBigIndex *startColumn = startColumnU_.array();
+  const int *indexRow = indexRowU_.array();
+  const CoinFactorizationDouble *element = elementU_.array();
+  const CoinFactorizationDouble *pivotRegion = pivotRegion_.array();
+#ifdef COIN_DEVELOP
+  ncall_SZ++;
+  nrow_SZ += numberRows_;
+  nslack_SZ += numberSlacks_;
+  nU_SZ += numberU_;
+#endif
+
+  for (int ii=0;ii<numberNonZero;ii++) {
+    int iPivot=indexIn[ii];
+    int iWord = iPivot>>CHECK_SHIFT;
+    int iBit = iPivot-(iWord<<CHECK_SHIFT);
+    if (mark[iWord]) {
+      mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+    } else {
+      mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+      stack[nMarked++]=iWord;
+    }
+  }
+  numberNonZero = 0;
+  // First do down to convenient power of 2
+  CoinBigIndex jLast = (numberU_-1)>>CHECK_SHIFT;
+  jLast = CoinMax((jLast<<CHECK_SHIFT),static_cast<CoinBigIndex> (numberSlacks_));
+  int i;
+  for ( i = numberU_-1 ; i >= jLast; i-- ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    region[i] = 0.0;
+    if ( fabs ( pivotValue ) > tolerance ) {
+#ifdef COIN_DEVELOP
+      nnz_SZ ++;
+#endif
+      CoinBigIndex start = startColumn[i];
+      const CoinFactorizationDouble * thisElement = element+start;
+      const int * thisIndex = indexRow+start;
+      
+#ifdef COIN_DEVELOP
+      nDone_SZ += numberInColumn[i];
+#endif
+      for (int j=numberInColumn[i]-1 ; j >=0; j-- ) {
+	int iRow0 = thisIndex[j];
+	CoinFactorizationDouble regionValue0 = region[iRow0];
+	CoinFactorizationDouble value0 = thisElement[j];
+	int iWord = iRow0>>CHECK_SHIFT;
+	int iBit = iRow0-(iWord<<CHECK_SHIFT);
+	if (mark[iWord]) {
+	  mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+	} else {
+	  mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+	  stack[nMarked++]=iWord;
+	}
+	region[iRow0] = regionValue0 - value0 * pivotValue;
+      }
+      pivotValue *= pivotRegion[i];
+      region[i]=pivotValue;
+      regionIndex[numberNonZero++]=i;
+    }
+  }
+  int kLast = (numberSlacks_+BITS_PER_CHECK-1)>>CHECK_SHIFT;
+  if (jLast>numberSlacks_) {
+    // now do in chunks
+    for (int k=(jLast>>CHECK_SHIFT)-1;k>=kLast;k--) {
+      unsigned int iMark = mark[k];
+      if (iMark) {
+	// something in chunk - do all (as imark may change)
+	int iLast = k<<CHECK_SHIFT;
+	for ( i = iLast+BITS_PER_CHECK-1 ; i >= iLast; i-- ) {
+	  CoinFactorizationDouble pivotValue = region[i];
+	  if (pivotValue) {
+#ifdef COIN_DEVELOP
+	    nnz_SZ ++;
+#endif
+	    region[i] = 0.0;
+	    if ( fabs ( pivotValue ) > tolerance ) {
+	      CoinBigIndex start = startColumn[i];
+	      const CoinFactorizationDouble * thisElement = element+start;
+	      const int * thisIndex = indexRow+start;
+#ifdef COIN_DEVELOP
+	      nDone_SZ += numberInColumn[i];
+#endif
+	      for (int j=numberInColumn[i]-1 ; j >=0; j-- ) {
+		int iRow0 = thisIndex[j];
+		CoinFactorizationDouble regionValue0 = region[iRow0];
+		CoinFactorizationDouble value0 = thisElement[j];
+		int iWord = iRow0>>CHECK_SHIFT;
+		int iBit = iRow0-(iWord<<CHECK_SHIFT);
+		if (mark[iWord]) {
+		  mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+		} else {
+		  mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+		  stack[nMarked++]=iWord;
+		}
+		region[iRow0] = regionValue0 - value0 * pivotValue;
+	      }
+	      pivotValue *= pivotRegion[i];
+	      region[i]=pivotValue;
+	      regionIndex[numberNonZero++]=i;
+	    }
+	  }
+	}
+	mark[k]=0;
+      }
+    }
+    i = (kLast<<CHECK_SHIFT)-1;
+  }
+  for ( ; i >= numberSlacks_; i-- ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    region[i] = 0.0;
+    if ( fabs ( pivotValue ) > tolerance ) {
+#ifdef COIN_DEVELOP
+      nnz_SZ ++;
+#endif
+      CoinBigIndex start = startColumn[i];
+      const CoinFactorizationDouble * thisElement = element+start;
+      const int * thisIndex = indexRow+start;
+#ifdef COIN_DEVELOP
+      nDone_SZ += numberInColumn[i];
+#endif
+      for (int j=numberInColumn[i]-1 ; j >=0; j-- ) {
+	int iRow0 = thisIndex[j];
+	CoinFactorizationDouble regionValue0 = region[iRow0];
+	CoinFactorizationDouble value0 = thisElement[j];
+	int iWord = iRow0>>CHECK_SHIFT;
+	int iBit = iRow0-(iWord<<CHECK_SHIFT);
+	if (mark[iWord]) {
+	  mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+	} else {
+	  mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+	  stack[nMarked++]=iWord;
+	}
+	region[iRow0] = regionValue0 - value0 * pivotValue;
+      }
+      pivotValue *= pivotRegion[i];
+      region[i]=pivotValue;
+      regionIndex[numberNonZero++]=i;
+    }
+  }
+  
+  if (numberSlacks_) {
+    // now do slacks
+#ifndef COIN_FAST_CODE
+    double factor = slackValue_;
+    if (factor==1.0) {
+      // First do down to convenient power of 2
+      CoinBigIndex jLast = (numberSlacks_-1)>>CHECK_SHIFT;
+      jLast = jLast<<CHECK_SHIFT;
+      for ( i = numberSlacks_-1; i>=jLast;i--) {
+	double value = region[i];
+	double absValue = fabs ( value );
+	if ( value ) {
+	  region[i]=0.0;
+	  if ( absValue > tolerance ) {
+	  region[i]=value;
+	  regionIndex[numberNonZero++]=i;
+	  }
+	}
+      }
+      mark[jLast]=0;
+      // now do in chunks
+      for (int k=(jLast>>CHECK_SHIFT)-1;k>=0;k--) {
+	unsigned int iMark = mark[k];
+	if (iMark) {
+	  // something in chunk - do all (as imark may change)
+	  int iLast = k<<CHECK_SHIFT;
+	  i = iLast+BITS_PER_CHECK-1;
+	  for ( ; i >= iLast; i-- ) {
+	    double value = region[i];
+	    double absValue = fabs ( value );
+	    if ( value ) {
+	      region[i]=0.0;
+	      if ( absValue > tolerance ) {
+		region[i]=value;
+		regionIndex[numberNonZero++]=i;
+	      }
+	    }
+	  }
+	  mark[k]=0;
+	}
+      }
+    } else {
+      assert (factor==-1.0);
+#endif
+      // First do down to convenient power of 2
+      CoinBigIndex jLast = (numberSlacks_-1)>>CHECK_SHIFT;
+      jLast = jLast<<CHECK_SHIFT;
+      for ( i = numberSlacks_-1; i>=jLast;i--) {
+	double value = region[i];
+	double absValue = fabs ( value );
+	if ( value ) {
+	  region[i]=0.0;
+	  if ( absValue > tolerance ) {
+	    region[i]=-value;
+	    regionIndex[numberNonZero++]=i;
+	  }
+	}
+      }
+      mark[jLast]=0;
+      // now do in chunks
+      for (int k=(jLast>>CHECK_SHIFT)-1;k>=0;k--) {
+	unsigned int iMark = mark[k];
+	if (iMark) {
+	  // something in chunk - do all (as imark may change)
+	  int iLast = k<<CHECK_SHIFT;
+	  i = iLast+BITS_PER_CHECK-1;
+	  for ( ; i >= iLast; i-- ) {
+	    double value = region[i];
+	    double absValue = fabs ( value );
+	    if ( value ) {
+	      region[i]=0.0;
+	      if ( absValue > tolerance ) {
+		region[i]=-value;
+		regionIndex[numberNonZero++]=i;
+	      }
+	    }
+	  }
+	  mark[k]=0;
+	}
+      }
+#ifndef COIN_FAST_CODE
+    }
+#endif
+  }
+  regionSparse->setNumElements ( numberNonZero );
+  mark[(numberU_-1)>>CHECK_SHIFT]=0;
+  mark[numberSlacks_>>CHECK_SHIFT]=0;
+  if (numberSlacks_)
+    mark[(numberSlacks_-1)>>CHECK_SHIFT]=0;
+#ifdef COIN_DEBUG
+  for (i=0;i<maximumRowsExtra_;i++) {
+    assert (!mark[i]);
+  }
+#endif
+}
+//  updateColumnR.  Updates part of column (FTRANR)
+void
+CoinFactorization::updateColumnR ( CoinIndexedVector * regionSparse ) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  int numberNonZero = regionSparse->getNumElements (  );
+
+  if ( !numberR_ )
+    return;	//return if nothing to do
+  double tolerance = zeroTolerance_;
+
+  const CoinBigIndex * startColumn = startColumnR_.array()-numberRows_;
+  const int * indexRow = indexRowR_;
+  const CoinFactorizationDouble * element = elementR_;
+  const int * permute = permute_.array();
+
+  // Work out very dubious idea of what would be fastest
+  int method=-1;
+  // Size of R
+  double sizeR=startColumnR_.array()[numberR_];
+  // Average
+  double averageR = sizeR/(static_cast<double> (numberRowsExtra_));
+  // weights (relative to actual work)
+  double setMark = 0.1; // setting mark
+  double test1= 1.0; // starting ftran (without testPivot)
+  double testPivot = 2.0; // Seeing if zero etc
+  double startDot=2.0; // For starting dot product version
+  // For final scan
+  double final = numberNonZero*1.0;
+  double methodTime[3];
+  // For second type
+  methodTime[1] = numberPivots_ * (testPivot + ((static_cast<double> (numberNonZero))/(static_cast<double> (numberRows_))
+						* averageR));
+  methodTime[1] += numberNonZero *(test1 + averageR);
+  // For first type
+  methodTime[0] = methodTime[1] + (numberNonZero+numberPivots_)*setMark;
+  methodTime[1] += numberNonZero*final;
+  // third
+  methodTime[2] = sizeR + numberPivots_*startDot + numberNonZero*final;
+  // switch off if necessary
+  if (!numberInColumnPlus_.array()) {
+    methodTime[0]=1.0e100;
+    methodTime[1]=1.0e100;
+  } else if (!sparse_.array()) {
+    methodTime[0]=1.0e100;
+  }
+  double best=1.0e100;
+  for (int i=0;i<3;i++) {
+    if (methodTime[i]<best) {
+      best=methodTime[i];
+      method=i;
+    }
+  }
+  assert (method>=0);
+  const int * numberInColumnPlus = numberInColumnPlus_.array();
+  //if (method==1)
+  //printf(" methods %g %g %g - chosen %d\n",methodTime[0],methodTime[1],methodTime[2],method);
+
+  switch (method) {
+  case 0:
+#ifdef STACK
+    {
+      // use sparse_ as temporary area
+      // mark known to be zero
+      int * COIN_RESTRICT stack = sparse_.array();  /* pivot */
+      int * COIN_RESTRICT list = stack + maximumRowsExtra_;  /* final list */
+      CoinBigIndex * COIN_RESTRICT next = (CoinBigIndex *) (list + maximumRowsExtra_);  /* jnext */
+      char * COIN_RESTRICT mark = (char *) (next + maximumRowsExtra_);
+      // we have another copy of R in R
+      const CoinFactorizationDouble * elementR = elementR_ + lengthAreaR_;
+      const int * indexRowR = indexRowR_ + lengthAreaR_;
+      const CoinBigIndex * startR = startColumnR_.array()+maximumPivots_+1;
+      int nList=0;
+      const int * permuteBack = permuteBack_.array();
+      for (int k=0;k<numberNonZero;k++) {
+	int kPivot=regionIndex[k];
+	if(!mark[kPivot]) {
+	  stack[0]=kPivot;
+	  CoinBigIndex j=-10;
+	  next[0]=j;
+	  int nStack=0;
+	  while (nStack>=0) {
+	    /* take off stack */
+	    if (j>=startR[kPivot]) {
+	      int jPivot=indexRowR[j--];
+	      /* put back on stack */
+	      next[nStack] =j;
+	      if (!mark[jPivot]) {
+		/* and new one */
+		kPivot=jPivot;
+		j=-10;
+		stack[++nStack]=kPivot;
+		mark[kPivot]=1;
+		next[nStack]=j;
+	      }
+	    } else if (j==-10) {
+	      // before first - see if followon
+	      int jPivot = permuteBack[kPivot];
+	      if (jPivot<numberRows_) {
+		// no
+		j=startR[kPivot]+numberInColumnPlus[kPivot]-1;
+		next[nStack]=j;
+	      } else {
+		// add to list
+		if (!mark[jPivot]) {
+		  /* and new one */
+		  kPivot=jPivot;
+		  j=-10;
+		  stack[++nStack]=kPivot;
+		  mark[kPivot]=1;
+		  next[nStack]=j;
+		} else {
+		  j=startR[kPivot]+numberInColumnPlus[kPivot]-1;
+		  next[nStack]=j;
+		}
+	      }
+	    } else {
+	      // finished
+	      list[nList++]=kPivot;
+	      mark[kPivot]=1;
+	      --nStack;
+	      if (nStack>=0) {
+		kPivot=stack[nStack];
+		j=next[nStack];
+	      }
+	    }
+	  }
+	}
+      }
+      numberNonZero=0;
+      for (int i=nList-1;i>=0;i--) {
+	int iPivot = list[i];
+	mark[iPivot]=0;
+	CoinFactorizationDouble pivotValue;
+	if (iPivot<numberRows_) {
+	  pivotValue = region[iPivot];
+	} else {
+	  int before = permute[iPivot];
+	  pivotValue = region[iPivot] + region[before];
+	  region[before]=0.0;
+	}
+	if ( fabs ( pivotValue ) > tolerance ) {
+	  region[iPivot] = pivotValue;
+	  CoinBigIndex start = startR[iPivot];
+	  int number = numberInColumnPlus[iPivot];
+	  CoinBigIndex end = start + number;
+	  CoinBigIndex j;
+	  for (j=start ; j < end; j ++ ) {
+	    int iRow = indexRowR[j];
+	    CoinFactorizationDouble value = elementR[j];
+	    region[iRow] -= value * pivotValue;
+	  }     
+	  regionIndex[numberNonZero++] = iPivot;
+	} else {
+	  region[iPivot] = 0.0;
+	}       
+      }
+    }
+#else
+    {
+      
+      // use sparse_ as temporary area
+      // mark known to be zero
+      int * COIN_RESTRICT stack = sparse_.array();  /* pivot */
+      int * COIN_RESTRICT list = stack + maximumRowsExtra_;  /* final list */
+      CoinBigIndex * COIN_RESTRICT next = reinterpret_cast<CoinBigIndex *> (list + maximumRowsExtra_);  /* jnext */
+      char * COIN_RESTRICT mark = reinterpret_cast<char *> (next + maximumRowsExtra_);
+      // mark all rows which will be permuted
+      for (int i = numberRows_; i < numberRowsExtra_; i++ ) {
+	int iRow = permute[i];
+	mark[iRow]=1;
+      }
+      // we have another copy of R in R
+      const CoinFactorizationDouble * elementR = elementR_ + lengthAreaR_;
+      const int * indexRowR = indexRowR_ + lengthAreaR_;
+      const CoinBigIndex * startR = startColumnR_.array()+maximumPivots_+1;
+      // For current list order does not matter as
+      // only affects end
+      int newNumber=0;
+      for (int i = 0; i < numberNonZero; i++ ) {
+	int iRow = regionIndex[i];
+	assert (region[iRow]);
+	if (!mark[iRow])
+	  regionIndex[newNumber++]=iRow;
+	int number = numberInColumnPlus[iRow];
+	if (number) {
+	  CoinFactorizationDouble pivotValue = region[iRow];
+	  CoinBigIndex start=startR[iRow];
+	  CoinBigIndex end = start+number;
+	  for (CoinBigIndex j = start; j < end; j ++ ) {
+	    CoinFactorizationDouble value = elementR[j];
+	    int jRow = indexRowR[j];
+	    region[jRow] -= pivotValue*value;
+	  }
+	}
+      }
+      numberNonZero = newNumber;
+      for (int i = numberRows_; i < numberRowsExtra_; i++ ) {
+	//move using permute_ (stored in inverse fashion)
+	int iRow = permute[i];
+	CoinFactorizationDouble pivotValue = region[iRow]+region[i];
+	//zero out pre-permuted
+	region[iRow] = 0.0;
+	if ( fabs ( pivotValue ) > tolerance ) {
+	  region[i] = pivotValue;
+	  if (!mark[i])
+	    regionIndex[numberNonZero++] = i;
+	  int number = numberInColumnPlus[i];
+	  CoinBigIndex start=startR[i];
+	  CoinBigIndex end = start+number;
+	  for (CoinBigIndex j = start; j < end; j ++ ) {
+	    CoinFactorizationDouble value = elementR[j];
+	    int jRow = indexRowR[j];
+	    region[jRow] -= pivotValue*value;
+	  }
+	} else {
+	  region[i] = 0.0;
+	}
+	mark[iRow]=0;
+      }
+    }
+#endif
+    break;
+  case 1:
+    {
+      // no sparse region
+      // we have another copy of R in R
+      const CoinFactorizationDouble * elementR = elementR_ + lengthAreaR_;
+      const int * indexRowR = indexRowR_ + lengthAreaR_;
+      const CoinBigIndex * startR = startColumnR_.array()+maximumPivots_+1;
+      // For current list order does not matter as
+      // only affects end
+      for (int i = 0; i < numberNonZero; i++ ) {
+	int iRow = regionIndex[i];
+	assert (region[iRow]);
+	int number = numberInColumnPlus[iRow];
+	if (number) {
+	  CoinFactorizationDouble pivotValue = region[iRow];
+	  CoinBigIndex start=startR[iRow];
+	  CoinBigIndex end = start+number;
+	  for (CoinBigIndex j = start; j < end; j ++ ) {
+	    CoinFactorizationDouble value = elementR[j];
+	    int jRow = indexRowR[j];
+	    region[jRow] -= pivotValue*value;
+	  }
+	}
+      }
+      for (int i = numberRows_; i < numberRowsExtra_; i++ ) {
+	//move using permute_ (stored in inverse fashion)
+	int iRow = permute[i];
+	CoinFactorizationDouble pivotValue = region[iRow]+region[i];
+	//zero out pre-permuted
+	region[iRow] = 0.0;
+	if ( fabs ( pivotValue ) > tolerance ) {
+	  region[i] = pivotValue;
+	  regionIndex[numberNonZero++] = i;
+	  int number = numberInColumnPlus[i];
+	  CoinBigIndex start=startR[i];
+	  CoinBigIndex end = start+number;
+	  for (CoinBigIndex j = start; j < end; j ++ ) {
+	    CoinFactorizationDouble value = elementR[j];
+	    int jRow = indexRowR[j];
+	    region[jRow] -= pivotValue*value;
+	  }
+	} else {
+	  region[i] = 0.0;
+	}
+      }
+    }
+    break;
+  case 2:
+    {
+      CoinBigIndex start = startColumn[numberRows_];
+      for (int i = numberRows_; i < numberRowsExtra_; i++ ) {
+	//move using permute_ (stored in inverse fashion)
+	CoinBigIndex end = startColumn[i+1];
+	int iRow = permute[i];
+	CoinFactorizationDouble pivotValue = region[iRow];
+	//zero out pre-permuted
+	region[iRow] = 0.0;
+
+	for (CoinBigIndex j = start; j < end; j ++ ) {
+	  CoinFactorizationDouble value = element[j];
+	  int jRow = indexRow[j];
+	  value *= region[jRow];
+	  pivotValue -= value;
+	}
+	start=end;
+	if ( fabs ( pivotValue ) > tolerance ) {
+	  region[i] = pivotValue;
+	  regionIndex[numberNonZero++] = i;
+	} else {
+	region[i] = 0.0;
+	}
+      }
+    }
+    break;
+  }
+  if (method) {
+    // pack down
+    int n=numberNonZero;
+    numberNonZero=0;
+    for (int i=0;i<n;i++) {
+      int indexValue = regionIndex[i];
+      double value = region[indexValue];
+      if (value) 
+	regionIndex[numberNonZero++]=indexValue;
+    }
+  }
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+//  updateColumnR.  Updates part of column (FTRANR)
+void
+CoinFactorization::updateColumnRFT ( CoinIndexedVector * regionSparse,
+				     int * COIN_RESTRICT regionIndex) 
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  //int *regionIndex = regionSparse->getIndices (  );
+  CoinBigIndex * COIN_RESTRICT startColumnU = startColumnU_.array();
+  int numberNonZero = regionSparse->getNumElements (  );
+
+  if ( numberR_ ) {
+    double tolerance = zeroTolerance_;
+    
+    const CoinBigIndex * startColumn = startColumnR_.array()-numberRows_;
+    const int * indexRow = indexRowR_;
+    const CoinFactorizationDouble * element = elementR_;
+    const int * permute = permute_.array();
+    
+
+    // Work out very dubious idea of what would be fastest
+    int method=-1;
+    // Size of R
+    double sizeR=startColumnR_.array()[numberR_];
+    // Average
+    double averageR = sizeR/(static_cast<double> (numberRowsExtra_));
+    // weights (relative to actual work)
+    double setMark = 0.1; // setting mark
+    double test1= 1.0; // starting ftran (without testPivot)
+    double testPivot = 2.0; // Seeing if zero etc
+    double startDot=2.0; // For starting dot product version
+    // For final scan
+    double final = numberNonZero*1.0;
+    double methodTime[3];
+    // For second type
+    methodTime[1] = numberPivots_ * (testPivot + ((static_cast<double> (numberNonZero))/(static_cast<double> (numberRows_))
+						  * averageR));
+    methodTime[1] += numberNonZero *(test1 + averageR);
+    // For first type
+    methodTime[0] = methodTime[1] + (numberNonZero+numberPivots_)*setMark;
+    methodTime[1] += numberNonZero*final;
+    // third
+    methodTime[2] = sizeR + numberPivots_*startDot + numberNonZero*final;
+    // switch off if necessary
+    if (!numberInColumnPlus_.array()) {
+      methodTime[0]=1.0e100;
+      methodTime[1]=1.0e100;
+    } else if (!sparse_.array()) {
+      methodTime[0]=1.0e100;
+    }
+    const int * numberInColumnPlus = numberInColumnPlus_.array();
+    int * numberInColumn = numberInColumn_.array();
+    // adjust for final scan
+    methodTime[1] += final;
+    double best=1.0e100;
+    for (int i=0;i<3;i++) {
+      if (methodTime[i]<best) {
+	best=methodTime[i];
+	method=i;
+      }
+    }
+    assert (method>=0);
+    
+    switch (method) {
+    case 0:
+      {
+	// use sparse_ as temporary area
+	// mark known to be zero
+	int * COIN_RESTRICT stack = sparse_.array();  /* pivot */
+	int * COIN_RESTRICT list = stack + maximumRowsExtra_;  /* final list */
+	CoinBigIndex * COIN_RESTRICT next = reinterpret_cast<CoinBigIndex *> (list + maximumRowsExtra_);  /* jnext */
+	char * COIN_RESTRICT mark = reinterpret_cast<char *> (next + maximumRowsExtra_);
+	// mark all rows which will be permuted
+	for (int i = numberRows_; i < numberRowsExtra_; i++ ) {
+	  int iRow = permute[i];
+	  mark[iRow]=1;
+	}
+	// we have another copy of R in R
+	const CoinFactorizationDouble * elementR = elementR_ + lengthAreaR_;
+	const int * indexRowR = indexRowR_ + lengthAreaR_;
+	const CoinBigIndex * startR = startColumnR_.array()+maximumPivots_+1;
+	//save in U
+	//in at end
+	int iColumn = numberColumnsExtra_;
+
+	startColumnU[iColumn] = startColumnU[maximumColumnsExtra_];
+	CoinBigIndex start = startColumnU[iColumn];
+  
+	//int * putIndex = indexRowU_ + start;
+	CoinFactorizationDouble * COIN_RESTRICT putElement = elementU_.array() + start;
+	// For current list order does not matter as
+	// only affects end
+	int newNumber=0;
+	for (int i = 0; i < numberNonZero; i++ ) {
+	  int iRow = regionIndex[i];
+	  CoinFactorizationDouble pivotValue = region[iRow];
+	  assert (region[iRow]);
+	  if (!mark[iRow]) {
+	    //putIndex[newNumber]=iRow;
+	    putElement[newNumber]=pivotValue;;
+	    regionIndex[newNumber++]=iRow;
+	  }
+	  int number = numberInColumnPlus[iRow];
+	  if (number) {
+	    CoinBigIndex start=startR[iRow];
+	    CoinBigIndex end = start+number;
+	    for (CoinBigIndex j = start; j < end; j ++ ) {
+	      CoinFactorizationDouble value = elementR[j];
+	      int jRow = indexRowR[j];
+	      region[jRow] -= pivotValue*value;
+	    }
+	  }
+	}
+	numberNonZero = newNumber;
+	for (int i = numberRows_; i < numberRowsExtra_; i++ ) {
+	  //move using permute_ (stored in inverse fashion)
+	  int iRow = permute[i];
+	  CoinFactorizationDouble pivotValue = region[iRow]+region[i];
+	  //zero out pre-permuted
+	  region[iRow] = 0.0;
+	  if ( fabs ( pivotValue ) > tolerance ) {
+	    region[i] = pivotValue;
+	    if (!mark[i]) {
+	      //putIndex[numberNonZero]=i;
+	      putElement[numberNonZero]=pivotValue;;
+	      regionIndex[numberNonZero++]=i;
+	    }
+	    int number = numberInColumnPlus[i];
+	    CoinBigIndex start=startR[i];
+	    CoinBigIndex end = start+number;
+	    for (CoinBigIndex j = start; j < end; j ++ ) {
+	      CoinFactorizationDouble value = elementR[j];
+	      int jRow = indexRowR[j];
+	      region[jRow] -= pivotValue*value;
+	    }
+	  } else {
+	    region[i] = 0.0;
+	  }
+	  mark[iRow]=0;
+	}
+	numberInColumn[iColumn] = numberNonZero;
+	startColumnU[maximumColumnsExtra_] = start + numberNonZero;
+      }
+      break;
+    case 1:
+      {
+	// no sparse region
+	// we have another copy of R in R
+	const CoinFactorizationDouble * elementR = elementR_ + lengthAreaR_;
+	const int * indexRowR = indexRowR_ + lengthAreaR_;
+	const CoinBigIndex * startR = startColumnR_.array()+maximumPivots_+1;
+	// For current list order does not matter as
+	// only affects end
+	for (int i = 0; i < numberNonZero; i++ ) {
+	  int iRow = regionIndex[i];
+	  assert (region[iRow]);
+	  int number = numberInColumnPlus[iRow];
+	  if (number) {
+	    CoinFactorizationDouble pivotValue = region[iRow];
+	    CoinBigIndex start=startR[iRow];
+	    CoinBigIndex end = start+number;
+	    for (CoinBigIndex j = start; j < end; j ++ ) {
+	      CoinFactorizationDouble value = elementR[j];
+	      int jRow = indexRowR[j];
+	      region[jRow] -= pivotValue*value;
+	    }
+	  }
+	}
+	for (int i = numberRows_; i < numberRowsExtra_; i++ ) {
+	  //move using permute_ (stored in inverse fashion)
+	  int iRow = permute[i];
+	  CoinFactorizationDouble pivotValue = region[iRow]+region[i];
+	  //zero out pre-permuted
+	  region[iRow] = 0.0;
+	  if ( fabs ( pivotValue ) > tolerance ) {
+	    region[i] = pivotValue;
+	    regionIndex[numberNonZero++] = i;
+	    int number = numberInColumnPlus[i];
+	    CoinBigIndex start=startR[i];
+	    CoinBigIndex end = start+number;
+	    for (CoinBigIndex j = start; j < end; j ++ ) {
+	      CoinFactorizationDouble value = elementR[j];
+	      int jRow = indexRowR[j];
+	      region[jRow] -= pivotValue*value;
+	    }
+	  } else {
+	    region[i] = 0.0;
+	  }
+	}
+      }
+      break;
+    case 2:
+      {
+	CoinBigIndex start = startColumn[numberRows_];
+	for (int i = numberRows_; i < numberRowsExtra_; i++ ) {
+	  //move using permute_ (stored in inverse fashion)
+	  CoinBigIndex end = startColumn[i+1];
+	  int iRow = permute[i];
+	  CoinFactorizationDouble pivotValue = region[iRow];
+	  //zero out pre-permuted
+	  region[iRow] = 0.0;
+	  
+	  for (CoinBigIndex j = start; j < end; j ++ ) {
+	    CoinFactorizationDouble value = element[j];
+	    int jRow = indexRow[j];
+	    value *= region[jRow];
+	    pivotValue -= value;
+	  }
+	  start=end;
+	  if ( fabs ( pivotValue ) > tolerance ) {
+	    region[i] = pivotValue;
+	    regionIndex[numberNonZero++] = i;
+	  } else {
+	    region[i] = 0.0;
+	  }
+	}
+      }
+      break;
+    }
+    if (method) {
+      // pack down
+      int n=numberNonZero;
+      numberNonZero=0;
+      //save in U
+      //in at end
+      int iColumn = numberColumnsExtra_;
+      
+      assert(startColumnU[iColumn] == startColumnU[maximumColumnsExtra_]);
+      CoinBigIndex start = startColumnU[iColumn];
+      
+      int * COIN_RESTRICT putIndex = indexRowU_.array() + start;
+      CoinFactorizationDouble * COIN_RESTRICT putElement = elementU_.array() + start;
+      for (int i=0;i<n;i++) {
+	int indexValue = regionIndex[i];
+	double value = region[indexValue];
+	if (value) {
+	  putIndex[numberNonZero]=indexValue;
+	  putElement[numberNonZero]=value;
+	  regionIndex[numberNonZero++]=indexValue;
+	}
+      }
+      numberInColumn[iColumn] = numberNonZero;
+      startColumnU[maximumColumnsExtra_] = start + numberNonZero;
+    }
+    //set counts
+    regionSparse->setNumElements ( numberNonZero );
+  } else {
+    // No R but we still need to save column
+    //save in U
+    //in at end
+    int * COIN_RESTRICT numberInColumn = numberInColumn_.array();
+    numberNonZero = regionSparse->getNumElements (  );
+    int iColumn = numberColumnsExtra_;
+    
+    assert(startColumnU[iColumn] == startColumnU[maximumColumnsExtra_]);
+    CoinBigIndex start = startColumnU[iColumn];
+    numberInColumn[iColumn] = numberNonZero;
+    startColumnU[maximumColumnsExtra_] = start + numberNonZero;
+    
+    int * COIN_RESTRICT putIndex = indexRowU_.array() + start;
+    CoinFactorizationDouble * COIN_RESTRICT putElement = elementU_.array() + start;
+    for (int i=0;i<numberNonZero;i++) {
+      int indexValue = regionIndex[i];
+      double value = region[indexValue];
+      putIndex[i]=indexValue;
+      putElement[i]=value;
+    }
+  }
+}
+/* Updates one column (FTRAN) from region2 and permutes.
+   region1 starts as zero
+   Note - if regionSparse2 packed on input - will be packed on output
+   - returns un-permuted result in region2 and region1 is zero */
+int CoinFactorization::updateColumnFT ( CoinIndexedVector * regionSparse,
+					CoinIndexedVector * regionSparse2)
+{
+  //permute and move indices into index array
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  int numberNonZero = regionSparse2->getNumElements();
+  const int *permute = permute_.array();
+  int * COIN_RESTRICT index = regionSparse2->getIndices();
+  double * COIN_RESTRICT region = regionSparse->denseVector();
+  double * COIN_RESTRICT array = regionSparse2->denseVector();
+  CoinBigIndex * COIN_RESTRICT startColumnU = startColumnU_.array();
+  bool doFT=doForrestTomlin_;
+  // see if room
+  if (doFT) {
+    int iColumn = numberColumnsExtra_;
+    
+    startColumnU[iColumn] = startColumnU[maximumColumnsExtra_];
+    CoinBigIndex start = startColumnU[iColumn];
+    CoinBigIndex space = lengthAreaU_ - ( start + numberRowsExtra_ );
+    doFT = space>=0;
+    if (doFT) {
+      regionIndex = indexRowU_.array() + start;
+    } else {
+      startColumnU[maximumColumnsExtra_] = lengthAreaU_+1;
+    }
+  }
+
+#ifndef CLP_FACTORIZATION
+  bool packed = regionSparse2->packedMode();
+  if (packed) {
+#else
+    assert (regionSparse2->packedMode());
+#endif
+    for (int j = 0; j < numberNonZero; j ++ ) {
+      int iRow = index[j];
+      double value = array[j];
+      array[j]=0.0;
+      iRow = permute[iRow];
+      region[iRow] = value;
+      regionIndex[j] = iRow;
+    }
+#ifndef CLP_FACTORIZATION
+  } else {
+    for (int j = 0; j < numberNonZero; j ++ ) {
+      int iRow = index[j];
+      double value = array[iRow];
+      array[iRow]=0.0;
+      iRow = permute[iRow];
+      region[iRow] = value;
+      regionIndex[j] = iRow;
+    }
+  }
+#endif
+  regionSparse->setNumElements ( numberNonZero );
+  if (collectStatistics_) {
+    numberFtranCounts_++;
+    ftranCountInput_ += numberNonZero;
+  }
+    
+  //  ******* L
+#if 0
+  {
+    double *region = regionSparse->denseVector (  );
+    //int *regionIndex = regionSparse->getIndices (  );
+    int numberNonZero = regionSparse->getNumElements (  );
+    for (int i=0;i<numberNonZero;i++) {
+      int iRow = regionIndex[i];
+      assert (region[iRow]);
+    }
+  }
+#endif
+  updateColumnL ( regionSparse, regionIndex );
+#if 0
+  {
+    double *region = regionSparse->denseVector (  );
+    //int *regionIndex = regionSparse->getIndices (  );
+    int numberNonZero = regionSparse->getNumElements (  );
+    for (int i=0;i<numberNonZero;i++) {
+      int iRow = regionIndex[i];
+      assert (region[iRow]);
+    }
+  }
+#endif
+  if (collectStatistics_) 
+    ftranCountAfterL_ += regionSparse->getNumElements();
+  //permute extra
+  //row bits here
+  if ( doFT ) 
+    updateColumnRFT ( regionSparse, regionIndex );
+  else
+    updateColumnR ( regionSparse );
+  if (collectStatistics_) 
+    ftranCountAfterR_ += regionSparse->getNumElements();
+  //  ******* U
+  updateColumnU ( regionSparse, regionIndex);
+  if (!doForrestTomlin_) {
+    // Do PFI after everything else
+    updateColumnPFI(regionSparse);
+  }
+  permuteBack(regionSparse,regionSparse2);
+  // will be negative if no room
+  if ( doFT ) 
+    return regionSparse2->getNumElements();
+  else 
+    return -regionSparse2->getNumElements();
+}
diff --git a/cbits/coin/CoinFactorization4.cpp b/cbits/coin/CoinFactorization4.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFactorization4.cpp
@@ -0,0 +1,2685 @@
+/* $Id: CoinFactorization4.cpp 1553 2012-10-30 17:13:11Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinUtilsConfig.h"
+
+#include <cassert>
+#include <cstdio>
+
+#include "CoinFactorization.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include <stdio.h>
+#include <iostream>
+#if DENSE_CODE==1 
+// using simple lapack interface
+extern "C" 
+{
+  /** LAPACK Fortran subroutine DGETRS. */
+  void F77_FUNC(dgetrs,DGETRS)(char *trans, cipfint *n,
+                               cipfint *nrhs, const double *A, cipfint *ldA,
+                               cipfint * ipiv, double *B, cipfint *ldB, ipfint *info,
+			       int trans_len);
+}
+#endif
+// For semi-sparse
+#define BITS_PER_CHECK 8
+#define CHECK_SHIFT 3
+typedef unsigned char CoinCheckZero;
+
+//:class CoinFactorization.  Deals with Factorization and Updates
+
+
+//  getRowSpaceIterate.  Gets space for one Row with given length
+//may have to do compression  (returns true)
+//also moves existing vector
+bool
+CoinFactorization::getRowSpaceIterate ( int iRow,
+                                      int extraNeeded )
+{
+  const int * numberInRow = numberInRow_.array();
+  int number = numberInRow[iRow];
+  CoinBigIndex * COIN_RESTRICT startRow = startRowU_.array();
+  int * COIN_RESTRICT indexColumn = indexColumnU_.array();
+  CoinBigIndex * COIN_RESTRICT convertRowToColumn = convertRowToColumnU_.array();
+  CoinBigIndex space = lengthAreaU_ - startRow[maximumRowsExtra_];
+  int * COIN_RESTRICT nextRow = nextRow_.array();
+  int * COIN_RESTRICT lastRow = lastRow_.array();
+  if ( space < extraNeeded + number + 2 ) {
+    //compression
+    int iRow = nextRow[maximumRowsExtra_];
+    CoinBigIndex put = 0;
+    while ( iRow != maximumRowsExtra_ ) {
+      //move
+      CoinBigIndex get = startRow[iRow];
+      CoinBigIndex getEnd = startRow[iRow] + numberInRow[iRow];
+      
+      startRow[iRow] = put;
+      CoinBigIndex i;
+      for ( i = get; i < getEnd; i++ ) {
+	indexColumn[put] = indexColumn[i];
+	convertRowToColumn[put] = convertRowToColumn[i];
+	put++;
+      }       
+      iRow = nextRow[iRow];
+    }       /* endwhile */
+    numberCompressions_++;
+    startRow[maximumRowsExtra_] = put;
+    space = lengthAreaU_ - put;
+    if ( space < extraNeeded + number + 2 ) {
+      //need more space
+      //if we can allocate bigger then do so and copy
+      //if not then return so code can start again
+      status_ = -99;
+      return false;    }       
+  }       
+  CoinBigIndex put = startRow[maximumRowsExtra_];
+  int next = nextRow[iRow];
+  int last = lastRow[iRow];
+  
+  //out
+  nextRow[last] = next;
+  lastRow[next] = last;
+  //in at end
+  last = lastRow[maximumRowsExtra_];
+  nextRow[last] = iRow;
+  lastRow[maximumRowsExtra_] = iRow;
+  lastRow[iRow] = last;
+  nextRow[iRow] = maximumRowsExtra_;
+  //move
+  CoinBigIndex get = startRow[iRow];
+  
+  int * indexColumnU = indexColumnU_.array();
+  startRow[iRow] = put;
+  while ( number ) {
+    number--;
+    indexColumnU[put] = indexColumnU[get];
+    convertRowToColumn[put] = convertRowToColumn[get];
+    put++;
+    get++;
+  }       /* endwhile */
+  //add four for luck
+  startRow[maximumRowsExtra_] = put + extraNeeded + 4;
+  return true;
+}
+
+//  getColumnSpaceIterateR.  Gets space for one extra R element in Column
+//may have to do compression  (returns true)
+//also moves existing vector
+bool
+CoinFactorization::getColumnSpaceIterateR ( int iColumn, double value,
+					   int iRow)
+{
+  CoinFactorizationDouble * COIN_RESTRICT elementR = elementR_ + lengthAreaR_;
+  int * COIN_RESTRICT indexRowR = indexRowR_ + lengthAreaR_;
+  CoinBigIndex * COIN_RESTRICT startR = startColumnR_.array()+maximumPivots_+1;
+  int * COIN_RESTRICT numberInColumnPlus = numberInColumnPlus_.array();
+  int number = numberInColumnPlus[iColumn];
+  //*** modify so sees if can go in
+  //see if it can go in at end
+  int * COIN_RESTRICT nextColumn = nextColumn_.array();
+  int * COIN_RESTRICT lastColumn = lastColumn_.array();
+  if (lengthAreaR_-startR[maximumColumnsExtra_]<number+1) {
+    //compression
+    int jColumn = nextColumn[maximumColumnsExtra_];
+    CoinBigIndex put = 0;
+    while ( jColumn != maximumColumnsExtra_ ) {
+      //move
+      CoinBigIndex get;
+      CoinBigIndex getEnd;
+
+      get = startR[jColumn];
+      getEnd = get + numberInColumnPlus[jColumn];
+      startR[jColumn] = put;
+      CoinBigIndex i;
+      for ( i = get; i < getEnd; i++ ) {
+	indexRowR[put] = indexRowR[i];
+	elementR[put] = elementR[i];
+	put++;
+      }
+      jColumn = nextColumn[jColumn];
+    }
+    numberCompressions_++;
+    startR[maximumColumnsExtra_]=put;
+  }
+  // Still may not be room (as iColumn was still in)
+  if (lengthAreaR_-startR[maximumColumnsExtra_]<number+1) 
+    return false;
+
+  int next = nextColumn[iColumn];
+  int last = lastColumn[iColumn];
+
+  //out
+  nextColumn[last] = next;
+  lastColumn[next] = last;
+
+  CoinBigIndex put = startR[maximumColumnsExtra_];
+  //in at end
+  last = lastColumn[maximumColumnsExtra_];
+  nextColumn[last] = iColumn;
+  lastColumn[maximumColumnsExtra_] = iColumn;
+  lastColumn[iColumn] = last;
+  nextColumn[iColumn] = maximumColumnsExtra_;
+  
+  //move
+  CoinBigIndex get = startR[iColumn];
+  startR[iColumn] = put;
+  int i = 0;
+  for (i=0 ; i < number; i ++ ) {
+    elementR[put]= elementR[get];
+    indexRowR[put++] = indexRowR[get++];
+  }
+  //insert
+  elementR[put]=value;
+  indexRowR[put++]=iRow;
+  numberInColumnPlus[iColumn]++;
+  //add 4 for luck
+  startR[maximumColumnsExtra_] = CoinMin(static_cast<CoinBigIndex> (put + 4) ,lengthAreaR_);
+  return true;
+}
+int CoinFactorization::checkPivot(double saveFromU,
+				 double oldPivot) const
+{
+  int status;
+  if ( fabs ( saveFromU ) > 1.0e-8 ) {
+    double checkTolerance;
+    
+    if ( numberRowsExtra_ < numberRows_ + 2 ) {
+      checkTolerance = 1.0e-5;
+    } else if ( numberRowsExtra_ < numberRows_ + 10 ) {
+      checkTolerance = 1.0e-6;
+    } else if ( numberRowsExtra_ < numberRows_ + 50 ) {
+      checkTolerance = 1.0e-8;
+    } else {
+      checkTolerance = 1.0e-10;
+    }       
+    checkTolerance *= relaxCheck_;
+    if ( fabs ( 1.0 - fabs ( saveFromU / oldPivot ) ) < checkTolerance ) {
+      status = 0;
+    } else {
+#if COIN_DEBUG
+      std::cout <<"inaccurate pivot "<< oldPivot << " " 
+		<< saveFromU << std::endl;
+#endif
+      if ( fabs ( fabs ( oldPivot ) - fabs ( saveFromU ) ) < 1.0e-12 ||
+        fabs ( 1.0 - fabs ( saveFromU / oldPivot ) ) < 1.0e-8 ) {
+        status = 1;
+      } else {
+        status = 2;
+      }       
+    }       
+  } else {
+    //error
+    status = 2;
+#if COIN_DEBUG
+    std::cout <<"inaccurate pivot "<< saveFromU / oldPivot 
+	      << " " << saveFromU << std::endl;
+#endif
+  } 
+  return status;
+}
+//  replaceColumn.  Replaces one Column to basis
+//      returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+//partial update already in U
+int
+CoinFactorization::replaceColumn ( CoinIndexedVector * regionSparse,
+                                 int pivotRow,
+				  double pivotCheck ,
+				   bool checkBeforeModifying,
+				   double )
+{
+  assert (numberU_<=numberRowsExtra_);
+  CoinBigIndex * COIN_RESTRICT startColumnU = startColumnU_.array();
+  CoinBigIndex * COIN_RESTRICT startColumn;
+  int * COIN_RESTRICT indexRow;
+  CoinFactorizationDouble * COIN_RESTRICT element;
+  
+  //return at once if too many iterations
+  if ( numberColumnsExtra_ >= maximumColumnsExtra_ ) {
+    return 5;
+  }       
+  if ( lengthAreaU_ < startColumnU[maximumColumnsExtra_] ) {
+    return 3;
+  }   
+  
+  int * COIN_RESTRICT numberInRow = numberInRow_.array();
+  int * COIN_RESTRICT numberInColumn = numberInColumn_.array();
+  int * COIN_RESTRICT numberInColumnPlus = numberInColumnPlus_.array();
+  int realPivotRow;
+  realPivotRow = pivotColumn_.array()[pivotRow];
+  //zeroed out region
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  
+  element = elementU_.array();
+  //take out old pivot column
+
+  // If we have done no pivots then always check before modification
+  if (!numberPivots_)
+    checkBeforeModifying=true;
+  
+  totalElements_ -= numberInColumn[realPivotRow];
+  CoinFactorizationDouble * COIN_RESTRICT pivotRegion = pivotRegion_.array();
+  CoinFactorizationDouble oldPivot = pivotRegion[realPivotRow];
+  // for accuracy check
+  pivotCheck = pivotCheck / oldPivot;
+#if COIN_DEBUG>1
+  int checkNumber=1000000;
+  //if (numberL_) checkNumber=-1;
+  if (numberR_>=checkNumber) {
+    printf("pivot row %d, check %g - alpha region:\n",
+      realPivotRow,pivotCheck);
+      /*int i;
+      for (i=0;i<numberRows_;i++) {
+      if (pivotRegion[i])
+      printf("%d %g\n",i,pivotRegion[i]);
+  }*/
+  }   
+#endif
+  pivotRegion[realPivotRow] = 0.0;
+
+  CoinBigIndex saveEnd = startColumnU[realPivotRow]
+                         + numberInColumn[realPivotRow];
+  // not necessary at present - but take no chances for future
+  numberInColumn[realPivotRow] = 0;
+  //get entries in row (pivot not stored)
+  int numberNonZero = 0;
+  int * COIN_RESTRICT indexColumn = indexColumnU_.array();
+  CoinBigIndex * COIN_RESTRICT convertRowToColumn = convertRowToColumnU_.array();
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  CoinBigIndex * COIN_RESTRICT startRow = startRowU_.array();
+  CoinBigIndex start=0;
+  CoinBigIndex end=0;
+#if COIN_DEBUG>1
+  if (numberR_>=checkNumber) 
+    printf("Before btranu\n");
+#endif
+
+#if COIN_ONE_ETA_COPY
+  if (convertRowToColumn) {
+#endif
+    start = startRow[realPivotRow];
+    end = start + numberInRow[realPivotRow];
+    
+    int smallestIndex=numberRowsExtra_;
+    if (!checkBeforeModifying) {
+      for (CoinBigIndex i = start; i < end ; i ++ ) {
+	int iColumn = indexColumn[i];
+	assert (iColumn<numberRowsExtra_);
+	smallestIndex = CoinMin(smallestIndex,iColumn);
+	CoinBigIndex j = convertRowToColumn[i];
+	
+	region[iColumn] = element[j];
+#if COIN_DEBUG>1
+	if (numberR_>=checkNumber) 
+	  printf("%d %g\n",iColumn,region[iColumn]);
+#endif
+	element[j] = 0.0;
+	regionIndex[numberNonZero++] = iColumn;
+      }
+    } else {
+      for (CoinBigIndex i = start; i < end ; i ++ ) {
+	int iColumn = indexColumn[i];
+	smallestIndex = CoinMin(smallestIndex,iColumn);
+	CoinBigIndex j = convertRowToColumn[i];
+	
+	region[iColumn] = element[j];
+#if COIN_DEBUG>1
+	if (numberR_>=checkNumber) 
+	  printf("%d %g\n",iColumn,region[iColumn]);
+#endif
+	regionIndex[numberNonZero++] = iColumn;
+      }
+    }       
+    //do BTRAN - finding first one to use
+    regionSparse->setNumElements ( numberNonZero );
+    updateColumnTransposeU ( regionSparse, smallestIndex );
+#if COIN_ONE_ETA_COPY
+  } else {
+    // use R to save where elements are
+    CoinBigIndex * saveWhere = NULL;
+    if (checkBeforeModifying) {
+      if ( lengthR_ + maximumRowsExtra_ +1>= lengthAreaR_ ) {
+	//not enough room
+	return 3;
+      }       
+      saveWhere = indexRowR_+lengthR_;
+    }
+    replaceColumnU(regionSparse,saveWhere,
+		   realPivotRow);
+  }
+#endif
+  numberNonZero = regionSparse->getNumElements (  );
+  CoinFactorizationDouble saveFromU = 0.0;
+
+  CoinBigIndex startU = startColumnU[numberColumnsExtra_];
+  int * COIN_RESTRICT indexU = &indexRowU_.array()[startU];
+  CoinFactorizationDouble * COIN_RESTRICT elementU = &elementU_.array()[startU];
+  
+
+  // Do accuracy test here if caller is paranoid
+  if (checkBeforeModifying) {
+    double tolerance = zeroTolerance_;
+    int number = numberInColumn[numberColumnsExtra_];
+  
+    for (CoinBigIndex i = 0; i < number; i++ ) {
+      int iRow = indexU[i];
+      //if (numberCompressions_==99&&lengthU_==278)
+      //printf("row %d saveFromU %g element %g region %g\n",
+      //       iRow,saveFromU,elementU[i],region[iRow]);
+      if ( fabs ( elementU[i] ) > tolerance ) {
+	if ( iRow != realPivotRow ) {
+	  saveFromU -= elementU[i] * region[iRow];
+	} else {
+	  saveFromU += elementU[i];
+	}       
+      }       
+    }       
+    //check accuracy
+    int status = checkPivot(saveFromU,pivotCheck);
+    if (status) {
+      // restore some things
+      pivotRegion[realPivotRow] = oldPivot;
+      number = saveEnd-startColumnU[realPivotRow];
+      totalElements_ += number;
+      numberInColumn[realPivotRow]=number;
+      regionSparse->clear();
+      return status;
+#if COIN_ONE_ETA_COPY
+    } else if (convertRowToColumn) {
+#else
+    } else {
+#endif
+      // do what we would have done by now
+      for (CoinBigIndex i = start; i < end ; i ++ ) {
+	CoinBigIndex j = convertRowToColumn[i];
+	element[j] = 0.0;
+      }
+#if COIN_ONE_ETA_COPY
+    } else {
+      // delete elements
+      // used R to save where elements are
+      CoinBigIndex * saveWhere = indexRowR_+lengthR_;
+      CoinFactorizationDouble *element = elementU_.array();
+      int n = saveWhere[0];
+      for (int i=0;i<n;i++) {
+	CoinBigIndex where = saveWhere[i+1];
+	element[where]=0.0;
+      }
+      //printf("deleting els\n");
+#endif
+    }
+  }
+  // Now zero out column of U
+  //take out old pivot column
+  for (CoinBigIndex i = startColumnU[realPivotRow]; i < saveEnd ; i ++ ) {
+    element[i] = 0.0;
+  }       
+  //zero out pivot Row (before or after?)
+  //add to R
+  startColumn = startColumnR_.array();
+  indexRow = indexRowR_;
+  element = elementR_;
+  CoinBigIndex l = lengthR_;
+  int number = numberR_;
+  
+  startColumn[number] = l;  //for luck and first time
+  number++;
+  startColumn[number] = l + numberNonZero;
+  numberR_ = number;
+  lengthR_ = l + numberNonZero;
+  totalElements_ += numberNonZero;
+  if ( lengthR_ >= lengthAreaR_ ) {
+    //not enough room
+    regionSparse->clear();
+    return 3;
+  }       
+#if COIN_DEBUG>1
+  if (numberR_>=checkNumber) 
+    printf("After btranu\n");
+#endif
+  for (CoinBigIndex i = 0; i < numberNonZero; i++ ) {
+    int iRow = regionIndex[i];
+#if COIN_DEBUG>1
+    if (numberR_>=checkNumber) 
+      printf("%d %g\n",iRow,region[iRow]);
+#endif
+    
+    indexRow[l] = iRow;
+    element[l] = region[iRow];
+    l++;
+  }       
+  int * nextRow;
+  int * lastRow;
+  int next;
+  int last;
+#if COIN_ONE_ETA_COPY
+  if (convertRowToColumn) {
+#endif
+    //take out row
+    nextRow = nextRow_.array();
+    lastRow = lastRow_.array();
+    next = nextRow[realPivotRow];
+    last = lastRow[realPivotRow];
+    
+    nextRow[last] = next;
+    lastRow[next] = last;
+    numberInRow[realPivotRow]=0;
+#if COIN_DEBUG
+    nextRow[realPivotRow] = 777777;
+    lastRow[realPivotRow] = 777777;
+#endif
+#if COIN_ONE_ETA_COPY
+  }
+#endif
+  //do permute
+  permute_.array()[numberRowsExtra_] = realPivotRow;
+  // and other way
+  permuteBack_.array()[realPivotRow] = numberRowsExtra_;
+  permuteBack_.array()[numberRowsExtra_] = -1;;
+  //and for safety
+  permute_.array()[numberRowsExtra_ + 1] = 0;
+
+  pivotColumn_.array()[pivotRow] = numberRowsExtra_;
+  pivotColumnBack()[numberRowsExtra_] = pivotRow;
+  startColumn = startColumnU;
+  indexRow = indexRowU_.array();
+  element = elementU_.array();
+
+  numberU_++;
+  number = numberInColumn[numberColumnsExtra_];
+
+  totalElements_ += number;
+  lengthU_ += number;
+  if ( lengthU_ >= lengthAreaU_ ) {
+    //not enough room
+    regionSparse->clear();
+    return 3;
+  }
+       
+  saveFromU = 0.0;
+  
+  //put in pivot
+  //add row counts
+
+#if COIN_DEBUG>1
+  if (numberR_>=checkNumber) 
+    printf("On U\n");
+#endif
+#if COIN_ONE_ETA_COPY
+  if (convertRowToColumn) {
+#endif
+    for (CoinBigIndex i = 0; i < number; i++ ) {
+      int iRow = indexU[i];
+#if COIN_DEBUG>1
+      if (numberR_>=checkNumber) 
+	printf("%d %g\n",iRow,elementU[i]);
+#endif
+      
+      //assert ( fabs ( elementU[i] ) > zeroTolerance_ );
+      if ( iRow != realPivotRow ) {
+	int next = nextRow[iRow];
+	int iNumberInRow = numberInRow[iRow];
+	CoinBigIndex space;
+	CoinBigIndex put = startRow[iRow] + iNumberInRow;
+	
+	space = startRow[next] - put;
+	if ( space <= 0 ) {
+	  getRowSpaceIterate ( iRow, iNumberInRow + 4 );
+	  put = startRow[iRow] + iNumberInRow;
+	}     
+	indexColumn[put] = numberColumnsExtra_;
+	convertRowToColumn[put] = i + startU;
+	numberInRow[iRow] = iNumberInRow + 1;
+	saveFromU = saveFromU - elementU[i] * region[iRow];
+      } else {
+	//zero out and save
+	saveFromU += elementU[i];
+	elementU[i] = 0.0;
+      }       
+    }       
+    //in at end
+    last = lastRow[maximumRowsExtra_];
+    nextRow[last] = numberRowsExtra_;
+    lastRow[maximumRowsExtra_] = numberRowsExtra_;
+    lastRow[numberRowsExtra_] = last;
+    nextRow[numberRowsExtra_] = maximumRowsExtra_;
+    startRow[numberRowsExtra_] = startRow[maximumRowsExtra_];
+    numberInRow[numberRowsExtra_] = 0;
+#if COIN_ONE_ETA_COPY
+  } else {
+    //abort();
+    for (CoinBigIndex i = 0; i < number; i++ ) {
+      int iRow = indexU[i];
+#if COIN_DEBUG>1
+      if (numberR_>=checkNumber) 
+	printf("%d %g\n",iRow,elementU[i]);
+#endif
+      
+      if ( fabs ( elementU[i] ) > tolerance ) {
+	if ( iRow != realPivotRow ) {
+	  saveFromU = saveFromU - elementU[i] * region[iRow];
+	} else {
+	  //zero out and save
+	  saveFromU += elementU[i];
+	  elementU[i] = 0.0;
+	}       
+      } else {
+	elementU[i] = 0.0;
+      }       
+    }       
+  }
+#endif
+  //column in at beginning (as empty)
+  int * COIN_RESTRICT nextColumn = nextColumn_.array();
+  int * COIN_RESTRICT lastColumn = lastColumn_.array();
+  next = nextColumn[maximumColumnsExtra_];
+  lastColumn[next] = numberColumnsExtra_;
+  nextColumn[maximumColumnsExtra_] = numberColumnsExtra_;
+  nextColumn[numberColumnsExtra_] = next;
+  lastColumn[numberColumnsExtra_] = maximumColumnsExtra_;
+  //check accuracy - but not if already checked (optimization problem)
+  int status =  (checkBeforeModifying) ? 0 : checkPivot(saveFromU,pivotCheck);
+
+  if (status!=2) {
+  
+    CoinFactorizationDouble pivotValue = 1.0 / saveFromU;
+    
+    pivotRegion[numberRowsExtra_] = pivotValue;
+    //modify by pivot
+    for (CoinBigIndex i = 0; i < number; i++ ) {
+      elementU[i] *= pivotValue;
+    }       
+    maximumU_ = CoinMax(maximumU_,startU+number);
+    numberRowsExtra_++;
+    numberColumnsExtra_++;
+    numberGoodU_++;
+    numberPivots_++;
+  }       
+  if ( numberRowsExtra_ > numberRows_ + 50 ) {
+    CoinBigIndex extra = factorElements_ >> 1;
+    
+    if ( numberRowsExtra_ > numberRows_ + 100 + numberRows_ / 500 ) {
+      if ( extra < 2 * numberRows_ ) {
+        extra = 2 * numberRows_;
+      }       
+    } else {
+      if ( extra < 5 * numberRows_ ) {
+        extra = 5 * numberRows_;
+      }       
+    }       
+    CoinBigIndex added = totalElements_ - factorElements_;
+    
+    if ( added > extra && added > ( factorElements_ ) << 1 && !status 
+	 && 3*totalElements_ > 2*(lengthAreaU_+lengthAreaL_)) {
+      status = 3;
+      if ( messageLevel_ & 4 ) {
+        std::cout << "Factorization has "<< totalElements_
+          << ", basis had " << factorElements_ <<std::endl;
+      }
+    }       
+  }
+  if (numberInColumnPlus&&status<2) {
+    // we are going to put another copy of R in R
+    CoinFactorizationDouble * COIN_RESTRICT elementR = elementR_ + lengthAreaR_;
+    int * COIN_RESTRICT indexRowR = indexRowR_ + lengthAreaR_;
+    CoinBigIndex * COIN_RESTRICT startR = startColumnR_.array()+maximumPivots_+1;
+    int pivotRow = numberRowsExtra_-1;
+    for (CoinBigIndex i = 0; i < numberNonZero; i++ ) {
+      int iRow = regionIndex[i];
+      assert (pivotRow>iRow);
+      next = nextColumn[iRow];
+      CoinBigIndex space;
+      if (next!=maximumColumnsExtra_)
+	space = startR[next]-startR[iRow];
+      else
+	space = lengthAreaR_-startR[iRow];
+      int numberInR = numberInColumnPlus[iRow];
+      if (space>numberInR) {
+	// there is space
+	CoinBigIndex  put=startR[iRow]+numberInR;
+	numberInColumnPlus[iRow]=numberInR+1;
+	indexRowR[put]=pivotRow;
+	elementR[put]=region[iRow];
+	//add 4 for luck
+	if (next==maximumColumnsExtra_)
+	  startR[maximumColumnsExtra_] = CoinMin(static_cast<CoinBigIndex> (put + 4) ,lengthAreaR_);
+      } else {
+	// no space - do we shuffle?
+	if (!getColumnSpaceIterateR(iRow,region[iRow],pivotRow)) {
+	  // printf("Need more space for R\n");
+	  numberInColumnPlus_.conditionalDelete();
+	  regionSparse->clear();
+	  break;
+	}
+      }
+      region[iRow]=0.0;
+    }       
+    regionSparse->setNumElements(0);
+  } else {
+    regionSparse->clear();
+  }
+  return status;
+}
+
+//  updateColumnTranspose.  Updates one column transpose (BTRAN)
+int
+CoinFactorization::updateColumnTranspose ( CoinIndexedVector * regionSparse,
+                                          CoinIndexedVector * regionSparse2 ) 
+  const
+{
+  //zero region
+  regionSparse->clear (  );
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  double * COIN_RESTRICT vector = regionSparse2->denseVector();
+  int * COIN_RESTRICT index = regionSparse2->getIndices();
+  int numberNonZero = regionSparse2->getNumElements();
+  const int * pivotColumn = pivotColumn_.array();
+  
+  //move indices into index array
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  bool packed = regionSparse2->packedMode();
+  if (packed) {
+    for (int i = 0; i < numberNonZero; i ++ ) {
+      int iRow = index[i];
+      double value = vector[i];
+      iRow=pivotColumn[iRow];
+      vector[i]=0.0;
+      region[iRow] = value;
+      regionIndex[i] = iRow;
+    }
+  } else {
+    for (int i = 0; i < numberNonZero; i ++ ) {
+      int iRow = index[i];
+      double value = vector[iRow];
+      vector[iRow]=0.0;
+      iRow=pivotColumn[iRow];
+      region[iRow] = value;
+      regionIndex[i] = iRow;
+    }
+  }
+  regionSparse->setNumElements ( numberNonZero );
+  if (collectStatistics_) {
+    numberBtranCounts_++;
+    btranCountInput_ += static_cast<double> (numberNonZero);
+  }
+  if (!doForrestTomlin_) {
+    // Do PFI before everything else
+    updateColumnTransposePFI(regionSparse);
+    numberNonZero = regionSparse->getNumElements();
+  }
+  //  ******* U
+  // Apply pivot region - could be combined for speed
+  CoinFactorizationDouble * COIN_RESTRICT pivotRegion = pivotRegion_.array();
+  
+  int smallestIndex=numberRowsExtra_;
+  for (int j = 0; j < numberNonZero; j++ ) {
+    int iRow = regionIndex[j];
+    smallestIndex = CoinMin(smallestIndex,iRow);
+    region[iRow] *= pivotRegion[iRow];
+  }
+  updateColumnTransposeU ( regionSparse,smallestIndex );
+  if (collectStatistics_) 
+    btranCountAfterU_ += static_cast<double> (regionSparse->getNumElements());
+  //permute extra
+  //row bits here
+  updateColumnTransposeR ( regionSparse );
+  //  ******* L
+  updateColumnTransposeL ( regionSparse );
+  numberNonZero = regionSparse->getNumElements (  );
+  if (collectStatistics_) 
+    btranCountAfterL_ += static_cast<double> (numberNonZero);
+  const int * permuteBack = pivotColumnBack();
+  int number=0;
+  if (packed) {
+    for (int i=0;i<numberNonZero;i++) {
+      int iRow=regionIndex[i];
+      double value = region[iRow];
+      region[iRow]=0.0;
+      //if (fabs(value)>zeroTolerance_) {
+	iRow=permuteBack[iRow];
+	vector[number]=value;
+	index[number++]=iRow;
+	//}
+    }
+  } else {
+    for (int i=0;i<numberNonZero;i++) {
+      int iRow=regionIndex[i];
+      double value = region[iRow];
+      region[iRow]=0.0;
+      //if (fabs(value)>zeroTolerance_) {
+	iRow=permuteBack[iRow];
+	vector[iRow]=value;
+	index[number++]=iRow;
+	//}
+    }
+  }
+  regionSparse->setNumElements(0);
+  regionSparse2->setNumElements(number);
+#ifdef COIN_DEBUG
+  for (i=0;i<numberRowsExtra_;i++) {
+    assert (!region[i]);
+  }
+#endif
+  return number;
+}
+
+/* Updates part of column transpose (BTRANU) when densish,
+   assumes index is sorted i.e. region is correct */
+void 
+CoinFactorization::updateColumnTransposeUDensish 
+                        ( CoinIndexedVector * regionSparse,
+			  int smallestIndex) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int numberNonZero = regionSparse->getNumElements (  );
+  double tolerance = zeroTolerance_;
+  
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  
+  const CoinBigIndex *startRow = startRowU_.array();
+  
+  const CoinBigIndex *convertRowToColumn = convertRowToColumnU_.array();
+  const int *indexColumn = indexColumnU_.array();
+  
+  const CoinFactorizationDouble * element = elementU_.array();
+  int last = numberU_;
+  
+  const int *numberInRow = numberInRow_.array();
+  numberNonZero = 0;
+  for (int i=smallestIndex ; i < last; i++ ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    if ( fabs ( pivotValue ) > tolerance ) {
+      CoinBigIndex start = startRow[i];
+      int numberIn = numberInRow[i];
+      CoinBigIndex end = start + numberIn;
+      for (CoinBigIndex j = start ; j < end; j ++ ) {
+	int iRow = indexColumn[j];
+	CoinBigIndex getElement = convertRowToColumn[j];
+	CoinFactorizationDouble value = element[getElement];
+	region[iRow] -=  value * pivotValue;
+      }     
+      regionIndex[numberNonZero++] = i;
+    } else {
+      region[i] = 0.0;
+    }       
+  }
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+/* Updates part of column transpose (BTRANU) when sparsish,
+      assumes index is sorted i.e. region is correct */
+void 
+CoinFactorization::updateColumnTransposeUSparsish 
+                        ( CoinIndexedVector * regionSparse,
+			  int smallestIndex) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int numberNonZero = regionSparse->getNumElements (  );
+  double tolerance = zeroTolerance_;
+  
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  
+  const CoinBigIndex *startRow = startRowU_.array();
+  
+  const CoinBigIndex *convertRowToColumn = convertRowToColumnU_.array();
+  const int *indexColumn = indexColumnU_.array();
+  
+  const CoinFactorizationDouble * element = elementU_.array();
+  int last = numberU_;
+  
+  const int *numberInRow = numberInRow_.array();
+  
+  // mark known to be zero
+  int nInBig = sizeof(CoinBigIndex)/sizeof(int);
+  CoinCheckZero * COIN_RESTRICT mark = reinterpret_cast<CoinCheckZero *> (sparse_.array()+(2+nInBig)*maximumRowsExtra_);
+
+  for (int i=0;i<numberNonZero;i++) {
+    int iPivot=regionIndex[i];
+    int iWord = iPivot>>CHECK_SHIFT;
+    int iBit = iPivot-(iWord<<CHECK_SHIFT);
+    if (mark[iWord]) {
+      mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+    } else {
+      mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+    }
+  }
+
+  numberNonZero = 0;
+  // Find convenient power of 2
+  smallestIndex = smallestIndex >> CHECK_SHIFT;
+  int kLast = last>>CHECK_SHIFT;
+  // do in chunks
+
+  for (int k=smallestIndex;k<kLast;k++) {
+    unsigned int iMark = mark[k];
+    if (iMark) {
+      // something in chunk - do all (as imark may change)
+      int i = k<<CHECK_SHIFT;
+      int iLast = i+BITS_PER_CHECK;
+      for ( ; i < iLast; i++ ) {
+	CoinFactorizationDouble pivotValue = region[i];
+	if ( fabs ( pivotValue ) > tolerance ) {
+	  CoinBigIndex start = startRow[i];
+	  int numberIn = numberInRow[i];
+	  CoinBigIndex end = start + numberIn;
+	  for (CoinBigIndex j = start ; j < end; j ++ ) {
+	    int iRow = indexColumn[j];
+	    CoinBigIndex getElement = convertRowToColumn[j];
+	    CoinFactorizationDouble value = element[getElement];
+	    int iWord = iRow>>CHECK_SHIFT;
+	    int iBit = iRow-(iWord<<CHECK_SHIFT);
+	    if (mark[iWord]) {
+	      mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+	    } else {
+	      mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+	    }
+	    region[iRow] -=  value * pivotValue;
+	  }     
+	  regionIndex[numberNonZero++] = i;
+	} else {
+	  region[i] = 0.0;
+	}       
+      }
+      mark[k]=0;
+    }
+  }
+  mark[kLast]=0;
+  for (int i = kLast<<CHECK_SHIFT; i < last; i++ ) {
+    CoinFactorizationDouble pivotValue = region[i];
+    if ( fabs ( pivotValue ) > tolerance ) {
+      CoinBigIndex start = startRow[i];
+      int numberIn = numberInRow[i];
+      CoinBigIndex end = start + numberIn;
+      for (CoinBigIndex j = start ; j < end; j ++ ) {
+	int iRow = indexColumn[j];
+	CoinBigIndex getElement = convertRowToColumn[j];
+	CoinFactorizationDouble value = element[getElement];
+
+	region[iRow] -=  value * pivotValue;
+      }     
+      regionIndex[numberNonZero++] = i;
+    } else {
+      region[i] = 0.0;
+    }       
+  }
+#ifdef COIN_DEBUG
+  for (int i=0;i<maximumRowsExtra_;i++) {
+    assert (!mark[i]);
+  }
+#endif
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+/* Updates part of column transpose (BTRANU) when sparse,
+   assumes index is sorted i.e. region is correct */
+void 
+CoinFactorization::updateColumnTransposeUSparse ( 
+		   CoinIndexedVector * regionSparse) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int numberNonZero = regionSparse->getNumElements (  );
+  double tolerance = zeroTolerance_;
+  
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  const CoinBigIndex *startRow = startRowU_.array();
+  
+  const CoinBigIndex *convertRowToColumn = convertRowToColumnU_.array();
+  const int *indexColumn = indexColumnU_.array();
+  
+  const CoinFactorizationDouble * element = elementU_.array();
+  
+  const int *numberInRow = numberInRow_.array();
+  
+  // use sparse_ as temporary area
+  // mark known to be zero
+  int * COIN_RESTRICT stack = sparse_.array();  /* pivot */
+  int * COIN_RESTRICT list = stack + maximumRowsExtra_;  /* final list */
+  CoinBigIndex * COIN_RESTRICT next = reinterpret_cast<CoinBigIndex *> (list + maximumRowsExtra_);  /* jnext */
+  char * COIN_RESTRICT mark = reinterpret_cast<char *> (next + maximumRowsExtra_);
+  int nList;
+#ifdef COIN_DEBUG
+  for (int i=0;i<maximumRowsExtra_;i++) {
+    assert (!mark[i]);
+  }
+#endif
+#if 0
+  {
+    int i;
+    for (i=0;i<numberRowsExtra_;i++) {
+      CoinBigIndex krs = startRow[i];
+      CoinBigIndex kre = krs + numberInRow[i];
+      CoinBigIndex k;
+      for (k=krs;k<kre;k++)
+	assert (indexColumn[k]>i);
+    }
+  }
+#endif
+  nList=0;
+  for (int k=0;k<numberNonZero;k++) {
+    int kPivot=regionIndex[k];
+    stack[0]=kPivot;
+    CoinBigIndex j=startRow[kPivot]+numberInRow[kPivot]-1;
+    next[0]=j;
+    int nStack=1;
+    while (nStack) {
+      /* take off stack */
+      kPivot=stack[--nStack];
+      if (mark[kPivot]!=1) {
+	j=next[nStack];
+	if (j>=startRow[kPivot]) {
+	  kPivot=indexColumn[j--];
+	  /* put back on stack */
+	  next[nStack++] =j;
+	  if (!mark[kPivot]) {
+	    /* and new one */
+	    j=startRow[kPivot]+numberInRow[kPivot]-1;
+	    stack[nStack]=kPivot;
+	    mark[kPivot]=2;
+	    next[nStack++]=j;
+	  }
+	} else {
+	  // finished
+	  list[nList++]=kPivot;
+	  mark[kPivot]=1;
+	}
+      }
+    }
+  }
+  numberNonZero=0;
+  for (int i=nList-1;i>=0;i--) {
+    int iPivot = list[i];
+    mark[iPivot]=0;
+    CoinFactorizationDouble pivotValue = region[iPivot];
+    if ( fabs ( pivotValue ) > tolerance ) {
+      CoinBigIndex start = startRow[iPivot];
+      int numberIn = numberInRow[iPivot];
+      CoinBigIndex end = start + numberIn;
+      for (CoinBigIndex j=start ; j < end; j ++ ) {
+	int iRow = indexColumn[j];
+	CoinBigIndex getElement = convertRowToColumn[j];
+	CoinFactorizationDouble value = element[getElement];
+	region[iRow] -= value * pivotValue;
+      }     
+      regionIndex[numberNonZero++] = iPivot;
+    } else {
+      region[iPivot] = 0.0;
+    }       
+  }       
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+//  updateColumnTransposeU.  Updates part of column transpose (BTRANU)
+//assumes index is sorted i.e. region is correct
+//does not sort by sign
+void
+CoinFactorization::updateColumnTransposeU ( CoinIndexedVector * regionSparse,
+					    int smallestIndex) const
+{
+#if COIN_ONE_ETA_COPY
+  CoinBigIndex *convertRowToColumn = convertRowToColumnU_.array();
+  if (!convertRowToColumn) {
+    //abort();
+    updateColumnTransposeUByColumn(regionSparse,smallestIndex);
+    return;
+  }
+#endif
+  int number = regionSparse->getNumElements (  );
+  int goSparse;
+  // Guess at number at end
+  if (sparseThreshold_>0) {
+    if (btranAverageAfterU_) {
+      int newNumber = static_cast<int> (number*btranAverageAfterU_);
+      if (newNumber< sparseThreshold_)
+	goSparse = 2;
+      else if (newNumber< sparseThreshold2_)
+	goSparse = 1;
+      else
+	goSparse = 0;
+    } else {
+      if (number<sparseThreshold_) 
+	goSparse = 2;
+      else
+	goSparse = 0;
+    }
+  } else {
+    goSparse=0;
+  }
+  switch (goSparse) {
+  case 0: // densish
+    updateColumnTransposeUDensish(regionSparse,smallestIndex);
+    break;
+  case 1: // middling
+    updateColumnTransposeUSparsish(regionSparse,smallestIndex);
+    break;
+  case 2: // sparse
+    updateColumnTransposeUSparse(regionSparse);
+    break;
+  }
+}
+
+/*  updateColumnTransposeLDensish.  
+    Updates part of column transpose (BTRANL) dense by column */
+void
+CoinFactorization::updateColumnTransposeLDensish 
+     ( CoinIndexedVector * regionSparse ) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  int numberNonZero;
+  double tolerance = zeroTolerance_;
+  int base;
+  int first = -1;
+  
+  numberNonZero=0;
+  //scan
+  for (first=numberRows_-1;first>=0;first--) {
+    if (region[first]) 
+      break;
+  }
+  if ( first >= 0 ) {
+    base = baseL_;
+    const CoinBigIndex * COIN_RESTRICT startColumn = startColumnL_.array();
+    const int * COIN_RESTRICT indexRow = indexRowL_.array();
+    const CoinFactorizationDouble * COIN_RESTRICT element = elementL_.array();
+    int last = baseL_ + numberL_;
+    
+    if ( first >= last ) {
+      first = last - 1;
+    }       
+    for (int i = first ; i >= base; i-- ) {
+      CoinBigIndex j;
+      CoinFactorizationDouble pivotValue = region[i];
+      for ( j= startColumn[i] ; j < startColumn[i+1]; j++ ) {
+	int iRow = indexRow[j];
+	CoinFactorizationDouble value = element[j];
+	pivotValue -= value * region[iRow];
+      }       
+      if ( fabs ( pivotValue ) > tolerance ) {
+	region[i] = pivotValue;
+	regionIndex[numberNonZero++] = i;
+      } else { 
+	region[i] = 0.0;
+      }       
+    }       
+    //may have stopped early
+    if ( first < base ) {
+      base = first + 1;
+    }
+    if (base > 5) {
+      int i=base-1;
+      CoinFactorizationDouble pivotValue=region[i];
+      bool store = fabs(pivotValue) > tolerance;
+      for (; i > 0; i-- ) {
+	bool oldStore = store;
+	CoinFactorizationDouble oldValue = pivotValue;
+	pivotValue = region[i-1];
+	store = fabs ( pivotValue ) > tolerance ;
+	if (!oldStore) {
+	  region[i] = 0.0;
+	} else {
+	  region[i] = oldValue;
+	  regionIndex[numberNonZero++] = i;
+	}       
+      }     
+      if (store) {
+	region[0] = pivotValue;
+	regionIndex[numberNonZero++] = 0;
+      } else {
+	region[0] = 0.0;
+      }       
+    } else {
+      for (int i = base -1 ; i >= 0; i-- ) {
+	CoinFactorizationDouble pivotValue = region[i];
+	if ( fabs ( pivotValue ) > tolerance ) {
+	  region[i] = pivotValue;
+	  regionIndex[numberNonZero++] = i;
+	} else {
+	  region[i] = 0.0;
+	}       
+      }     
+    }
+  } 
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+/*  updateColumnTransposeLByRow. 
+    Updates part of column transpose (BTRANL) densish but by row */
+void
+CoinFactorization::updateColumnTransposeLByRow 
+    ( CoinIndexedVector * regionSparse ) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  int numberNonZero;
+  double tolerance = zeroTolerance_;
+  int first = -1;
+  
+  // use row copy of L
+  const CoinFactorizationDouble * element = elementByRowL_.array();
+  const CoinBigIndex * startRow = startRowL_.array();
+  const int * column = indexColumnL_.array();
+  for (first=numberRows_-1;first>=0;first--) {
+    if (region[first]) 
+      break;
+  }
+  numberNonZero=0;
+  for (int i=first;i>=0;i--) {
+    CoinFactorizationDouble pivotValue = region[i];
+    if ( fabs ( pivotValue ) > tolerance ) {
+      regionIndex[numberNonZero++] = i;
+      CoinBigIndex j;
+      for (j = startRow[i + 1]-1;j >= startRow[i]; j--) {
+	int iRow = column[j];
+	CoinFactorizationDouble value = element[j];
+	region[iRow] -= pivotValue*value;
+      }
+    } else {
+      region[i] = 0.0;
+    }     
+  }
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+// Updates part of column transpose (BTRANL) when sparsish by row
+void
+CoinFactorization::updateColumnTransposeLSparsish 
+    ( CoinIndexedVector * regionSparse ) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  int numberNonZero = regionSparse->getNumElements();
+  double tolerance = zeroTolerance_;
+  
+  // use row copy of L
+  const CoinFactorizationDouble * element = elementByRowL_.array();
+  const CoinBigIndex * startRow = startRowL_.array();
+  const int * column = indexColumnL_.array();
+  // mark known to be zero
+  int nInBig = sizeof(CoinBigIndex)/sizeof(int);
+  CoinCheckZero * COIN_RESTRICT mark = reinterpret_cast<CoinCheckZero *> (sparse_.array()+(2+nInBig)*maximumRowsExtra_);
+  for (int i=0;i<numberNonZero;i++) {
+    int iPivot=regionIndex[i];
+    int iWord = iPivot>>CHECK_SHIFT;
+    int iBit = iPivot-(iWord<<CHECK_SHIFT);
+    if (mark[iWord]) {
+      mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+    } else {
+      mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+    }
+  }
+  numberNonZero = 0;
+  // First do down to convenient power of 2
+  int jLast = (numberRows_-1)>>CHECK_SHIFT;
+  jLast = (jLast<<CHECK_SHIFT);
+  for (int i=numberRows_-1;i>=jLast;i--) {
+    CoinFactorizationDouble pivotValue = region[i];
+    if ( fabs ( pivotValue ) > tolerance ) {
+      regionIndex[numberNonZero++] = i;
+      CoinBigIndex j;
+      for (j = startRow[i + 1]-1;j >= startRow[i]; j--) {
+	int iRow = column[j];
+	CoinFactorizationDouble value = element[j];
+	int iWord = iRow>>CHECK_SHIFT;
+	int iBit = iRow-(iWord<<CHECK_SHIFT);
+	if (mark[iWord]) {
+	  mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+	} else {
+	  mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+	}
+	region[iRow] -= pivotValue*value;
+      }
+    } else {
+      region[i] = 0.0;
+    }     
+  }
+  // and in chunks
+  jLast = jLast>>CHECK_SHIFT;
+  mark[jLast]=0;
+  for (int k=jLast-1;k>=0;k--) {
+    unsigned int iMark = mark[k];
+    if (iMark) {
+      // something in chunk - do all (as imark may change)
+      int iLast = k<<CHECK_SHIFT;
+      for (int i = iLast+BITS_PER_CHECK-1; i >= iLast; i-- ) {
+	CoinFactorizationDouble pivotValue = region[i];
+	if ( fabs ( pivotValue ) > tolerance ) {
+	  regionIndex[numberNonZero++] = i;
+	  CoinBigIndex j;
+	  for (j = startRow[i + 1]-1;j >= startRow[i]; j--) {
+	    int iRow = column[j];
+	    CoinFactorizationDouble value = element[j];
+	    int iWord = iRow>>CHECK_SHIFT;
+	    int iBit = iRow-(iWord<<CHECK_SHIFT);
+	    if (mark[iWord]) {
+	      mark[iWord] = static_cast<CoinCheckZero>(mark[iWord] | (1<<iBit));
+	    } else {
+	      mark[iWord] = static_cast<CoinCheckZero>(1<<iBit);
+	    }
+	    region[iRow] -= pivotValue*value;
+	  }
+	} else {
+	  region[i] = 0.0;
+	}     
+      }
+      mark[k]=0;
+    }
+  }
+#ifdef COIN_DEBUG
+  for (int i=0;i<maximumRowsExtra_;i++) {
+    assert (!mark[i]);
+  }
+#endif
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+/*  updateColumnTransposeLSparse. 
+    Updates part of column transpose (BTRANL) sparse */
+void
+CoinFactorization::updateColumnTransposeLSparse 
+    ( CoinIndexedVector * regionSparse ) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  int numberNonZero = regionSparse->getNumElements (  );
+  double tolerance = zeroTolerance_;
+  
+  // use row copy of L
+  const CoinFactorizationDouble * element = elementByRowL_.array();
+  const CoinBigIndex * startRow = startRowL_.array();
+  const int * column = indexColumnL_.array();
+  // use sparse_ as temporary area
+  // mark known to be zero
+  int * COIN_RESTRICT stack = sparse_.array();  /* pivot */
+  int * COIN_RESTRICT list = stack + maximumRowsExtra_;  /* final list */
+  CoinBigIndex * COIN_RESTRICT next = reinterpret_cast<CoinBigIndex *> (list + maximumRowsExtra_);  /* jnext */
+  char * COIN_RESTRICT mark = reinterpret_cast<char *> (next + maximumRowsExtra_);
+  int nList;
+  int number = numberNonZero;
+#ifdef COIN_DEBUG
+  for (i=0;i<maximumRowsExtra_;i++) {
+    assert (!mark[i]);
+  }
+#endif
+  nList=0;
+  for (int k=0;k<number;k++) {
+    int kPivot=regionIndex[k];
+    if(!mark[kPivot]&&region[kPivot]) {
+      stack[0]=kPivot;
+      CoinBigIndex j=startRow[kPivot+1]-1;
+      int nStack=0;
+      while (nStack>=0) {
+	/* take off stack */
+	if (j>=startRow[kPivot]) {
+	  int jPivot=column[j--];
+	  /* put back on stack */
+	  next[nStack] =j;
+	  if (!mark[jPivot]) {
+	    /* and new one */
+	    kPivot=jPivot;
+	    j = startRow[kPivot+1]-1;
+	    stack[++nStack]=kPivot;
+	    mark[kPivot]=1;
+	    next[nStack]=j;
+	  }
+	} else {
+	  /* finished so mark */
+	  list[nList++]=kPivot;
+	  mark[kPivot]=1;
+	  --nStack;
+	  if (nStack>=0) {
+	    kPivot=stack[nStack];
+	    j=next[nStack];
+	  }
+	}
+      }
+    }
+  }
+  numberNonZero=0;
+  for (int i=nList-1;i>=0;i--) {
+    int iPivot = list[i];
+    mark[iPivot]=0;
+    CoinFactorizationDouble pivotValue = region[iPivot];
+    if ( fabs ( pivotValue ) > tolerance ) {
+      regionIndex[numberNonZero++] = iPivot;
+      CoinBigIndex j;
+      for ( j = startRow[iPivot]; j < startRow[iPivot+1]; j ++ ) {
+	int iRow = column[j];
+	CoinFactorizationDouble value = element[j];
+	region[iRow] -= value * pivotValue;
+      }
+    } else {
+      region[iPivot]=0.0;
+    }
+  }
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+//  updateColumnTransposeL.  Updates part of column transpose (BTRANL)
+void
+CoinFactorization::updateColumnTransposeL ( CoinIndexedVector * regionSparse ) const
+{
+  int number = regionSparse->getNumElements (  );
+  if (!numberL_&&!numberDense_) {
+    if (sparse_.array()||number<numberRows_)
+      return;
+  }
+  int goSparse;
+  // Guess at number at end
+  // we may need to rethink on dense
+  if (sparseThreshold_>0) {
+    if (btranAverageAfterL_) {
+      int newNumber = static_cast<int> (number*btranAverageAfterL_);
+      if (newNumber< sparseThreshold_)
+	goSparse = 2;
+      else if (newNumber< sparseThreshold2_)
+	goSparse = 1;
+      else
+	goSparse = 0;
+    } else {
+      if (number<sparseThreshold_) 
+	goSparse = 2;
+      else
+	goSparse = 0;
+    }
+  } else {
+    goSparse=-1;
+  }
+#ifdef DENSE_CODE
+  if (numberDense_) {
+    //take off list
+    int lastSparse = numberRows_-numberDense_;
+    int number = regionSparse->getNumElements();
+    double * COIN_RESTRICT region = regionSparse->denseVector (  );
+    int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+    int i=0;
+    bool doDense=false;
+    if (number<=numberRows_) {
+      while (i<number) {
+	int iRow = regionIndex[i];
+	if (iRow>=lastSparse) {
+	  doDense=true;
+	  regionIndex[i] = regionIndex[--number];
+	} else {
+	  i++;
+	}
+      }
+    } else {
+      for (i=numberRows_-1;i>=lastSparse;i--) {
+	if (region[i]) {
+	  doDense=true;
+          // numbers are all wrong - do a scan
+          regionSparse->setNumElements(0);
+          regionSparse->scan(0,lastSparse,zeroTolerance_);
+          number=regionSparse->getNumElements();
+	  break;
+	}
+      }
+      if (sparseThreshold_)
+	goSparse=0;
+      else
+	goSparse=-1;
+    }
+    if (doDense) {
+      regionSparse->setNumElements(number);
+      char trans = 'T';
+      int ione=1;
+      int info;
+      F77_FUNC(dgetrs,DGETRS)(&trans,&numberDense_,&ione,denseArea_,&numberDense_,
+			      densePermute_,region+lastSparse,&numberDense_,&info,1);
+      //and scan again
+      if (goSparse>0||!numberL_)
+	regionSparse->scan(lastSparse,numberRows_,zeroTolerance_);
+    } 
+    if (!numberL_) {
+      // could be odd combination of sparse/dense
+      if (number>numberRows_) {
+	regionSparse->setNumElements(0);
+	regionSparse->scan(0,numberRows_,zeroTolerance_);
+      }
+      return;
+    }
+  } 
+#endif
+  if (goSparse>0&&regionSparse->getNumElements()>numberRows_)
+    goSparse=0;
+  switch (goSparse) {
+  case -1: // No row copy
+    updateColumnTransposeLDensish(regionSparse);
+    break;
+  case 0: // densish but by row
+    updateColumnTransposeLByRow(regionSparse);
+    break;
+  case 1: // middling(and by row)
+    updateColumnTransposeLSparsish(regionSparse);
+    break;
+  case 2: // sparse
+    updateColumnTransposeLSparse(regionSparse);
+    break;
+  }
+}
+#if COIN_ONE_ETA_COPY
+/* Combines BtranU and delete elements
+   If deleted is NULL then delete elements
+   otherwise store where elements are
+*/
+void 
+CoinFactorization::replaceColumnU ( CoinIndexedVector * regionSparse,
+				    CoinBigIndex * deleted,
+				    int internalPivotRow)
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector();
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices();
+  double tolerance = zeroTolerance_;
+  const CoinBigIndex *startColumn = startColumnU_.array();
+  const int *indexRow = indexRowU_.array();
+  CoinFactorizationDouble *element = elementU_.array();
+  int numberNonZero = 0;
+  const int *numberInColumn = numberInColumn_.array();
+  //const CoinFactorizationDouble *pivotRegion = pivotRegion_.array();
+  bool deleteNow=true;
+  if (deleted) {
+    deleteNow = false;
+    deleted ++;
+  }
+  int nPut=0;
+  for (int i = CoinMax(numberSlacks_,internalPivotRow) ;
+       i < numberU_; i++ ) {
+    assert (!region[i]);
+    CoinFactorizationDouble pivotValue = 0.0; //region[i]*pivotRegion[i];
+    //printf("Epv %g reg %g pr %g\n",
+    //   pivotValue,region[i],pivotRegion[i]);
+    //pivotValue = region[i];
+    for (CoinBigIndex  j= startColumn[i] ; 
+	 j < startColumn[i]+numberInColumn[i]; j++ ) {
+      int iRow = indexRow[j];
+      CoinFactorizationDouble value = element[j];
+      if (iRow!=internalPivotRow) {
+	pivotValue -= value * region[iRow];
+      } else {
+	assert (!region[iRow]);
+	pivotValue += value;
+	if (deleteNow)
+	  element[j]=0.0;
+	else
+	  deleted[nPut++]=j;
+      }
+    }       
+    if ( fabs ( pivotValue ) > tolerance ) {
+      regionIndex[numberNonZero++] = i;
+      region[i] = pivotValue;
+    } else {
+      region[i] = 0;
+    }       
+  }
+  if (!deleteNow) {
+    deleted--;
+    deleted[0]=nPut;
+  }
+  regionSparse->setNumElements(numberNonZero);
+}
+/* Updates part of column transpose (BTRANU) by column
+   assumes index is sorted i.e. region is correct */
+void 
+CoinFactorization::updateColumnTransposeUByColumn ( CoinIndexedVector * regionSparse,
+						    int smallestIndex) const
+{
+  //CoinIndexedVector temp = *regionSparse;
+  //updateColumnTransposeUDensish(&temp,smallestIndex);
+  double * COIN_RESTRICT region = regionSparse->denseVector();
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices();
+  double tolerance = zeroTolerance_;
+  const CoinBigIndex *startColumn = startColumnU_.array();
+  const int *indexRow = indexRowU_.array();
+  const CoinFactorizationDouble *element = elementU_.array();
+  int numberNonZero = 0;
+  const int *numberInColumn = numberInColumn_.array();
+  const CoinFactorizationDouble *pivotRegion = pivotRegion_.array();
+  
+  for (int i = smallestIndex;i<numberSlacks_; i++) {
+    double value = region[i];
+    if ( value ) {
+      //region[i]=-value;
+      regionIndex[numberNonZero]=i;
+      if ( fabs(value) > tolerance ) 
+	numberNonZero++;
+      else 
+	region[i]=0.0;
+    }
+  }
+  for (int i = CoinMax(numberSlacks_,smallestIndex) ;
+       i < numberU_; i++ ) {
+    CoinFactorizationDouble pivotValue = region[i]*pivotRegion[i];
+    //printf("pv %g reg %g pr %g\n",
+    //   pivotValue,region[i],pivotRegion[i]);
+    pivotValue = region[i];
+    for (CoinBigIndex  j= startColumn[i] ; 
+	 j < startColumn[i]+numberInColumn[i]; j++ ) {
+      int iRow = indexRow[j];
+      CoinFactorizationDouble value = element[j];
+      pivotValue -= value * region[iRow];
+    }       
+    if ( fabs ( pivotValue ) > tolerance ) {
+      regionIndex[numberNonZero++] = i;
+      region[i] = pivotValue;
+    } else {
+      region[i] = 0;
+    }       
+  }
+  regionSparse->setNumElements(numberNonZero);
+  //double * region2 = temp.denseVector();
+  //for (i=0;i<maximumRowsExtra_;i++) {
+  //assert(fabs(region[i]-region2[i])<1.0e-4);
+  //}
+}
+#endif
+// Updates part of column transpose (BTRANR) when dense
+void 
+CoinFactorization::updateColumnTransposeRDensish 
+( CoinIndexedVector * regionSparse ) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+
+#ifdef COIN_DEBUG
+  regionSparse->checkClean();
+#endif
+  int last = numberRowsExtra_-1;
+  
+  
+  const int *indexRow = indexRowR_;
+  const CoinFactorizationDouble *element = elementR_;
+  const CoinBigIndex * startColumn = startColumnR_.array()-numberRows_;
+  //move using permute_ (stored in inverse fashion)
+  const int * permute = permute_.array();
+  
+  for (int i = last ; i >= numberRows_; i-- ) {
+    int putRow = permute[i];
+    CoinFactorizationDouble pivotValue = region[i];
+    //zero out  old permuted
+    region[i] = 0.0;
+    if ( pivotValue ) {
+      for (CoinBigIndex j = startColumn[i]; j < startColumn[i+1]; j++ ) {
+	CoinFactorizationDouble value = element[j];
+	int iRow = indexRow[j];
+	region[iRow] -= value * pivotValue;
+      }
+      region[putRow] = pivotValue;
+      //putRow must have been zero before so put on list ??
+      //but can't catch up so will have to do L from end
+      //unless we update lookBtran in replaceColumn - yes
+    }
+  }
+}
+// Updates part of column transpose (BTRANR) when sparse
+void 
+CoinFactorization::updateColumnTransposeRSparse 
+( CoinIndexedVector * regionSparse ) const
+{
+  double * COIN_RESTRICT region = regionSparse->denseVector (  );
+  int * COIN_RESTRICT regionIndex = regionSparse->getIndices (  );
+  int numberNonZero = regionSparse->getNumElements (  );
+  double tolerance = zeroTolerance_;
+
+#ifdef COIN_DEBUG
+  regionSparse->checkClean();
+#endif
+  int last = numberRowsExtra_-1;
+  
+  
+  const int *indexRow = indexRowR_;
+  const CoinFactorizationDouble *element = elementR_;
+  const CoinBigIndex * startColumn = startColumnR_.array()-numberRows_;
+  //move using permute_ (stored in inverse fashion)
+  const int * permute = permute_.array();
+    
+  // we can use sparse_ as temporary array
+  int * COIN_RESTRICT spare = sparse_.array();
+  for (int i=0;i<numberNonZero;i++) {
+    spare[regionIndex[i]]=i;
+  }
+  // still need to do in correct order (for now)
+  for (int i = last ; i >= numberRows_; i-- ) {
+    int putRow = permute[i];
+    assert (putRow<=i);
+    CoinFactorizationDouble pivotValue = region[i];
+    //zero out  old permuted
+    region[i] = 0.0;
+    if ( pivotValue ) {
+      for (CoinBigIndex j = startColumn[i]; j < startColumn[i+1]; j++ ) {
+	CoinFactorizationDouble value = element[j];
+	int iRow = indexRow[j];
+	CoinFactorizationDouble oldValue = region[iRow];
+	CoinFactorizationDouble newValue = oldValue - value * pivotValue;
+	if (oldValue) {
+	  if (newValue) 
+	    region[iRow]=newValue;
+	  else
+	    region[iRow]=COIN_INDEXED_REALLY_TINY_ELEMENT;
+	} else if (fabs(newValue)>tolerance) {
+	  region[iRow] = newValue;
+	  spare[iRow]=numberNonZero;
+	  regionIndex[numberNonZero++]=iRow;
+	}
+      }
+      region[putRow] = pivotValue;
+      // modify list
+      int position=spare[i];
+      regionIndex[position]=putRow;
+      spare[putRow]=position;
+    }
+  }
+  regionSparse->setNumElements(numberNonZero);
+}
+
+//  updateColumnTransposeR.  Updates part of column (FTRANR)
+void
+CoinFactorization::updateColumnTransposeR ( CoinIndexedVector * regionSparse ) const
+{
+  if (numberRowsExtra_==numberRows_)
+    return;
+  int numberNonZero = regionSparse->getNumElements (  );
+
+  if (numberNonZero) {
+    if (numberNonZero < (sparseThreshold_<<2)||(!numberL_&&sparse_.array())) {
+      updateColumnTransposeRSparse ( regionSparse );
+      if (collectStatistics_) 
+	btranCountAfterR_ += regionSparse->getNumElements();
+    } else {
+      updateColumnTransposeRDensish ( regionSparse );
+      // we have lost indices
+      // make sure won't try and go sparse again
+      if (collectStatistics_) 
+	btranCountAfterR_ += CoinMin((numberNonZero<<1),numberRows_);
+      regionSparse->setNumElements (numberRows_+1);
+    }
+  }
+}
+//  makes a row copy of L
+void
+CoinFactorization::goSparse ( )
+{
+  if (!sparseThreshold_) {
+    if (numberRows_>300) {
+      if (numberRows_<10000) {
+	sparseThreshold_=CoinMin(numberRows_/6,500);
+	//sparseThreshold2_=sparseThreshold_;
+      } else {
+	sparseThreshold_=1000;
+	//sparseThreshold2_=sparseThreshold_;
+      }
+      sparseThreshold2_=numberRows_>>2;
+    } else {
+      sparseThreshold_=0;
+      sparseThreshold2_=0;
+    }
+  } else {
+    if (!sparseThreshold_&&numberRows_>400) {
+      sparseThreshold_=CoinMin((numberRows_-300)/9,1000);
+    }
+    sparseThreshold2_=sparseThreshold_;
+  }
+  if (!sparseThreshold_)
+    return;
+  // allow for stack, list, next and char map of mark
+  int nRowIndex = (maximumRowsExtra_+CoinSizeofAsInt(int)-1)/
+    CoinSizeofAsInt(char);
+  int nInBig = static_cast<int>(sizeof(CoinBigIndex)/sizeof(int));
+  assert (nInBig>=1);
+  sparse_.conditionalNew( (2+nInBig)*maximumRowsExtra_ + nRowIndex );
+  // zero out mark
+  memset(sparse_.array()+(2+nInBig)*maximumRowsExtra_,
+         0,maximumRowsExtra_*sizeof(char));
+  elementByRowL_.conditionalDelete();
+  indexColumnL_.conditionalDelete();
+  startRowL_.conditionalNew(numberRows_+1);
+  if (lengthAreaL_) {
+    elementByRowL_.conditionalNew(lengthAreaL_);
+    indexColumnL_.conditionalNew(lengthAreaL_);
+  }
+  // counts
+  CoinBigIndex * COIN_RESTRICT startRowL = startRowL_.array();
+  CoinZeroN(startRowL,numberRows_);
+  const CoinBigIndex * startColumnL = startColumnL_.array();
+  CoinFactorizationDouble * COIN_RESTRICT elementL = elementL_.array();
+  const int * indexRowL = indexRowL_.array();
+  for (int i=baseL_;i<baseL_+numberL_;i++) {
+    for (CoinBigIndex j=startColumnL[i];j<startColumnL[i+1];j++) {
+      int iRow = indexRowL[j];
+      startRowL[iRow]++;
+    }
+  }
+  // convert count to lasts
+  CoinBigIndex count=0;
+  for (int i=0;i<numberRows_;i++) {
+    int numberInRow=startRowL[i];
+    count += numberInRow;
+    startRowL[i]=count;
+  }
+  startRowL[numberRows_]=count;
+  // now insert
+  CoinFactorizationDouble * COIN_RESTRICT elementByRowL = elementByRowL_.array();
+  int * COIN_RESTRICT indexColumnL = indexColumnL_.array();
+  for (int i=baseL_+numberL_-1;i>=baseL_;i--) {
+    for (CoinBigIndex j=startColumnL[i];j<startColumnL[i+1];j++) {
+      int iRow = indexRowL[j];
+      CoinBigIndex start = startRowL[iRow]-1;
+      startRowL[iRow]=start;
+      elementByRowL[start]=elementL[j];
+      indexColumnL[start]=i;
+    }
+  }
+}
+
+//  set sparse threshold
+void
+CoinFactorization::sparseThreshold ( int value ) 
+{
+  if (value>0&&sparseThreshold_) {
+    sparseThreshold_=value;
+    sparseThreshold2_= sparseThreshold_;
+  } else if (!value&&sparseThreshold_) {
+    // delete copy
+    sparseThreshold_=0;
+    sparseThreshold2_= 0;
+    elementByRowL_.conditionalDelete();
+    startRowL_.conditionalDelete();
+    indexColumnL_.conditionalDelete();
+    sparse_.conditionalDelete();
+  } else if (value>0&&!sparseThreshold_) {
+    if (value>1)
+      sparseThreshold_=value;
+    else
+      sparseThreshold_=0;
+    sparseThreshold2_= sparseThreshold_;
+    goSparse();
+  }
+}
+void CoinFactorization::maximumPivots (  int value )
+{
+  if (value>0) {
+    maximumPivots_=value;
+  }
+}
+void CoinFactorization::messageLevel (  int value )
+{
+  if (value>0&&value<16) {
+    messageLevel_=value;
+  }
+}
+void CoinFactorization::pivotTolerance (  double value )
+{
+  if (value>0.0&&value<=1.0) {
+    pivotTolerance_=value;
+  }
+}
+void CoinFactorization::zeroTolerance (  double value )
+{
+  if (value>0.0&&value<1.0) {
+    zeroTolerance_=value;
+  }
+}
+#ifndef COIN_FAST_CODE
+void CoinFactorization::slackValue (  double value )
+{
+  if (value>=0.0) {
+    slackValue_=1.0;
+  } else {
+    slackValue_=-1.0;
+  }
+}
+#endif
+// Reset all sparsity etc statistics
+void CoinFactorization::resetStatistics()
+{
+  collectStatistics_=false;
+
+  /// Below are all to collect
+  ftranCountInput_=0.0;
+  ftranCountAfterL_=0.0;
+  ftranCountAfterR_=0.0;
+  ftranCountAfterU_=0.0;
+  btranCountInput_=0.0;
+  btranCountAfterU_=0.0;
+  btranCountAfterR_=0.0;
+  btranCountAfterL_=0.0;
+
+  /// We can roll over factorizations
+  numberFtranCounts_=0;
+  numberBtranCounts_=0;
+
+  /// While these are averages collected over last 
+  ftranAverageAfterL_=0.0;
+  ftranAverageAfterR_=0.0;
+  ftranAverageAfterU_=0.0;
+  btranAverageAfterU_=0.0;
+  btranAverageAfterR_=0.0;
+  btranAverageAfterL_=0.0; 
+}
+/*  getColumnSpaceIterate.  Gets space for one extra U element in Column
+    may have to do compression  (returns true)
+    also moves existing vector.
+    Returns -1 if no memory or where element was put
+    Used by replaceRow (turns off R version) */
+CoinBigIndex 
+CoinFactorization::getColumnSpaceIterate ( int iColumn, double value,
+					   int iRow)
+{
+  if (numberInColumnPlus_.array()) {
+    numberInColumnPlus_.conditionalDelete();
+  }
+  int * COIN_RESTRICT numberInRow = numberInRow_.array();
+  int * COIN_RESTRICT numberInColumn = numberInColumn_.array();
+  int * COIN_RESTRICT nextColumn = nextColumn_.array();
+  int * COIN_RESTRICT lastColumn = lastColumn_.array();
+  int number = numberInColumn[iColumn];
+  int iNext=nextColumn[iColumn];
+  CoinBigIndex * COIN_RESTRICT startColumnU = startColumnU_.array();
+  CoinBigIndex * COIN_RESTRICT startRowU = startRowU_.array();
+  CoinBigIndex space = startColumnU[iNext]-startColumnU[iColumn];
+  CoinBigIndex put;
+  CoinBigIndex * COIN_RESTRICT convertRowToColumnU = convertRowToColumnU_.array();
+  int * COIN_RESTRICT indexColumnU = indexColumnU_.array();
+  CoinFactorizationDouble * COIN_RESTRICT elementU = elementU_.array();
+  int * COIN_RESTRICT indexRowU = indexRowU_.array();
+  if ( space < number + 1 ) {
+    //see if it can go in at end
+    if (lengthAreaU_-startColumnU[maximumColumnsExtra_]<number+1) {
+      //compression
+      int jColumn = nextColumn[maximumColumnsExtra_];
+      CoinBigIndex put = 0;
+      while ( jColumn != maximumColumnsExtra_ ) {
+	//move
+	CoinBigIndex get;
+	CoinBigIndex getEnd;
+
+	get = startColumnU[jColumn];
+	getEnd = get + numberInColumn[jColumn];
+	startColumnU[jColumn] = put;
+	CoinBigIndex i;
+	for ( i = get; i < getEnd; i++ ) {
+	  CoinFactorizationDouble value = elementU[i];
+	  if (value) {
+	    indexRowU[put] = indexRowU[i];
+	    elementU[put] = value;
+	    put++;
+	  } else {
+	    numberInColumn[jColumn]--;
+	  }
+	}
+	jColumn = nextColumn[jColumn];
+      }
+      numberCompressions_++;
+      startColumnU[maximumColumnsExtra_]=put;
+      //space for cross reference
+      CoinBigIndex *convertRowToColumn = convertRowToColumnU_.array();
+      CoinBigIndex j = 0;
+      CoinBigIndex *startRow = startRowU_.array();
+      
+      int iRow;
+      for ( iRow = 0; iRow < numberRowsExtra_; iRow++ ) {
+	startRow[iRow] = j;
+	j += numberInRow[iRow];
+      }
+      factorElements_=j;
+      
+      CoinZeroN ( numberInRow, numberRowsExtra_ );
+      int i;
+      for ( i = 0; i < numberRowsExtra_; i++ ) {
+	CoinBigIndex start = startColumnU[i];
+	CoinBigIndex end = start + numberInColumn[i];
+
+	CoinBigIndex j;
+	for ( j = start; j < end; j++ ) {
+	  int iRow = indexRowU[j];
+	  int iLook = numberInRow[iRow];
+	  
+	  numberInRow[iRow] = iLook + 1;
+	  CoinBigIndex k = startRow[iRow] + iLook;
+	  
+	  indexColumnU[k] = i;
+	  convertRowToColumn[k] = j;
+	}
+      }
+    }
+    // Still may not be room (as iColumn was still in)
+    if (lengthAreaU_-startColumnU[maximumColumnsExtra_]>=number+1) {
+      int next = nextColumn[iColumn];
+      int last = lastColumn[iColumn];
+      
+      //out
+      nextColumn[last] = next;
+      lastColumn[next] = last;
+      
+      put = startColumnU[maximumColumnsExtra_];
+      //in at end
+      last = lastColumn[maximumColumnsExtra_];
+      nextColumn[last] = iColumn;
+      lastColumn[maximumColumnsExtra_] = iColumn;
+      lastColumn[iColumn] = last;
+      nextColumn[iColumn] = maximumColumnsExtra_;
+      
+      //move
+      CoinBigIndex get = startColumnU[iColumn];
+      startColumnU[iColumn] = put;
+      int i = 0;
+      for (i=0 ; i < number; i ++ ) {
+	CoinFactorizationDouble value = elementU[get];
+	int iRow=indexRowU[get++];
+	if (value) {
+	  elementU[put]= value;
+	  int n=numberInRow[iRow];
+	  CoinBigIndex start = startRowU[iRow];
+	  CoinBigIndex j;
+	  for (j=start;j<start+n;j++) {
+	    if (indexColumnU[j]==iColumn) {
+	      convertRowToColumnU[j]=put;
+	      break;
+	    }
+	  }
+	  assert (j<start+n);
+	  indexRowU[put++] = iRow;
+	} else {
+	  assert (!numberInRow[iRow]);
+	  numberInColumn[iColumn]--;
+	}
+      }
+      //insert
+      int n=numberInRow[iRow];
+      CoinBigIndex start = startRowU[iRow];
+      CoinBigIndex j;
+      for (j=start;j<start+n;j++) {
+	if (indexColumnU[j]==iColumn) {
+	  convertRowToColumnU[j]=put;
+	  break;
+	}
+      }
+      assert (j<start+n);
+      elementU[put]=value;
+      indexRowU[put]=iRow;
+      numberInColumn[iColumn]++;
+      //add 4 for luck
+      startColumnU[maximumColumnsExtra_] = CoinMin(static_cast<CoinBigIndex> (put + 4) ,lengthAreaU_);
+    } else {
+      // no room
+      put=-1;
+    }
+  } else {
+    // just slot in
+    put=startColumnU[iColumn]+numberInColumn[iColumn];
+    int n=numberInRow[iRow];
+    CoinBigIndex start = startRowU[iRow];
+    CoinBigIndex j;
+    for (j=start;j<start+n;j++) {
+      if (indexColumnU[j]==iColumn) {
+	convertRowToColumnU[j]=put;
+	break;
+      }
+    }
+    assert (j<start+n);
+    elementU[put]=value;
+    indexRowU[put]=iRow;
+    numberInColumn[iColumn]++;
+  }
+  return put;
+}
+/* Replaces one Row in basis,
+   At present assumes just a singleton on row is in basis
+   returns 0=OK, 1=Probably OK, 2=singular, 3 no space */
+int 
+CoinFactorization::replaceRow ( int whichRow, int iNumberInRow,
+				const int indicesColumn[], const double elements[] )
+{
+  if (!iNumberInRow)
+    return 0;
+  int next = nextRow_.array()[whichRow];
+  int * numberInRow = numberInRow_.array();
+#ifndef NDEBUG
+  const int * numberInColumn = numberInColumn_.array();
+#endif
+  int numberNow = numberInRow[whichRow];
+  const CoinBigIndex * startRowU = startRowU_.array();
+  CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+  CoinBigIndex start = startRowU[whichRow];
+  CoinFactorizationDouble * elementU = elementU_.array();
+  CoinBigIndex *convertRowToColumnU = convertRowToColumnU_.array();
+  if (numberNow&&numberNow<100) {
+    int ind[100];
+    CoinMemcpyN(indexColumnU_.array()+start,numberNow,ind);
+    int i;
+    for (i=0;i<iNumberInRow;i++) {
+      int jColumn=indicesColumn[i];
+      int k;
+      for (k=0;k<numberNow;k++) {
+	if (ind[k]==jColumn) {
+	  ind[k]=-1;
+	  break;
+	}
+      }
+      if (k==numberNow) {
+	printf("new column %d not in current\n",jColumn);
+      } else {
+	k=convertRowToColumnU[start+k];
+	CoinFactorizationDouble oldValue = elementU[k];
+	CoinFactorizationDouble newValue = elements[i]*pivotRegion[jColumn];
+	if (fabs(oldValue-newValue)>1.0e-3)
+	  printf("column %d, old value %g new %g (el %g, piv %g)\n",jColumn,oldValue,
+		 newValue,elements[i],pivotRegion[jColumn]);
+      }
+    }
+    for (i=0;i<numberNow;i++) {
+      if (ind[i]>=0)
+	printf("current column %d not in new\n",ind[i]);
+    }
+    assert (numberNow==iNumberInRow);
+  }
+  assert (numberInColumn[whichRow]==0);
+  assert (pivotRegion[whichRow]==1.0);
+  CoinBigIndex space;
+  int returnCode=0;
+      
+  space = startRowU[next] - (start+iNumberInRow);
+  if ( space < 0 ) {
+    if (!getRowSpaceIterate ( whichRow, iNumberInRow)) 
+      returnCode=3;
+  }
+  //return 0;
+  if (!returnCode) {
+    int * indexColumnU = indexColumnU_.array();
+    numberInRow[whichRow]=iNumberInRow;
+    start = startRowU[whichRow];
+    int i;
+    for (i=0;i<iNumberInRow;i++) {
+      int iColumn = indicesColumn[i];
+      indexColumnU[start+i]=iColumn;
+      assert (iColumn>whichRow);
+      CoinFactorizationDouble value  = elements[i]*pivotRegion[iColumn];
+#if 0
+      int k;
+      bool found=false;
+      for (k=startColumnU[iColumn];k<startColumnU[iColumn]+numberInColumn[iColumn];k++) {
+	if (indexRowU[k]==whichRow) {
+	  assert (fabs(elementU[k]-value)<1.0e-3);
+	  found=true;
+	  break;
+	}
+      }
+#if 0
+      assert (found);
+#else
+      if (found) {
+	int number = numberInColumn[iColumn]-1;
+	numberInColumn[iColumn]=number;
+	CoinBigIndex j=startColumnU[iColumn]+number;
+	if (k<j) {
+	  int iRow=indexRowU[j];
+	  indexRowU[k]=iRow;
+	  elementU[k]=elementU[j];
+	  int n=numberInRow[iRow];
+	  CoinBigIndex start = startRowU[iRow];
+	  for (j=start;j<start+n;j++) {
+	    if (indexColumnU[j]==iColumn) {
+	      convertRowToColumnU[j]=k;
+	      break;
+	    }
+	  }
+	  assert (j<start+n);
+	}
+      }
+      found=false;
+#endif
+      if (!found) {
+#endif
+	CoinBigIndex iWhere = getColumnSpaceIterate(iColumn,value,whichRow);
+	if (iWhere>=0) {
+	  convertRowToColumnU[start+i] = iWhere;
+	} else {
+	  returnCode=3;
+	  break;
+	}
+#if 0
+      } else {
+	convertRowToColumnU[start+i] = k;
+      }
+#endif
+    }
+  }       
+  return returnCode;
+}
+// Takes out all entries for given rows
+void 
+CoinFactorization::emptyRows(int numberToEmpty, const int which[])
+{
+  int i;
+  int * delRow = new int [maximumRowsExtra_];
+  int * indexRowU = indexRowU_.array();
+#ifndef NDEBUG
+  CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+#endif
+  for (i=0;i<maximumRowsExtra_;i++)
+    delRow[i]=0;
+  int * numberInRow = numberInRow_.array();
+  int * numberInColumn = numberInColumn_.array();
+  CoinFactorizationDouble * elementU = elementU_.array();
+  const CoinBigIndex * startColumnU = startColumnU_.array();
+  for (i=0;i<numberToEmpty;i++) {
+    int iRow = which[i];
+    delRow[iRow]=1;
+    assert (numberInColumn[iRow]==0);
+    assert (pivotRegion[iRow]==1.0);
+    numberInRow[iRow]=0;
+  }
+  for (i=0;i<numberU_;i++) {
+    CoinBigIndex k;
+    CoinBigIndex j=startColumnU[i];
+    for (k=startColumnU[i];k<startColumnU[i]+numberInColumn[i];k++) {
+      int iRow=indexRowU[k];
+      if (!delRow[iRow]) {
+	indexRowU[j]=indexRowU[k];
+	elementU[j++]=elementU[k];
+      }
+    }
+    numberInColumn[i] = j-startColumnU[i];
+  }
+  delete [] delRow;
+  //space for cross reference
+  CoinBigIndex *convertRowToColumn = convertRowToColumnU_.array();
+  CoinBigIndex j = 0;
+  CoinBigIndex *startRow = startRowU_.array();
+
+  int iRow;
+  for ( iRow = 0; iRow < numberRows_; iRow++ ) {
+    startRow[iRow] = j;
+    j += numberInRow[iRow];
+  }
+  factorElements_=j;
+
+  CoinZeroN ( numberInRow, numberRows_ );
+
+  int * indexColumnU = indexColumnU_.array();
+  for ( i = 0; i < numberRows_; i++ ) {
+    CoinBigIndex start = startColumnU[i];
+    CoinBigIndex end = start + numberInColumn[i];
+
+    CoinBigIndex j;
+    for ( j = start; j < end; j++ ) {
+      int iRow = indexRowU[j];
+      int iLook = numberInRow[iRow];
+
+      numberInRow[iRow] = iLook + 1;
+      CoinBigIndex k = startRow[iRow] + iLook;
+
+      indexColumnU[k] = i;
+      convertRowToColumn[k] = j;
+    }
+  }
+}
+// Updates part of column PFI (FTRAN)
+void 
+CoinFactorization::updateColumnPFI ( CoinIndexedVector * regionSparse) const
+{
+  double *region = regionSparse->denseVector (  );
+  int * regionIndex = regionSparse->getIndices();
+  double tolerance = zeroTolerance_;
+  const CoinBigIndex *startColumn = startColumnU_.array()+numberRows_;
+  const int *indexRow = indexRowU_.array();
+  const CoinFactorizationDouble *element = elementU_.array();
+  int numberNonZero = regionSparse->getNumElements();
+  int i;
+#ifdef COIN_DEBUG
+  for (i=0;i<numberNonZero;i++) {
+    int iRow=regionIndex[i];
+    assert (iRow>=0&&iRow<numberRows_);
+    assert (region[iRow]);
+  }
+#endif
+  const CoinFactorizationDouble *pivotRegion = pivotRegion_.array()+numberRows_;
+  const int *pivotColumn = pivotColumn_.array()+numberRows_;
+
+  for (i = 0 ; i <numberPivots_; i++ ) {
+    int pivotRow=pivotColumn[i];
+    CoinFactorizationDouble pivotValue = region[pivotRow];
+    if (pivotValue) {
+      if ( fabs ( pivotValue ) > tolerance ) {
+	for (CoinBigIndex  j= startColumn[i] ; j < startColumn[i+1]; j++ ) {
+	  int iRow = indexRow[j];
+	  CoinFactorizationDouble oldValue = region[iRow];
+	  CoinFactorizationDouble value = oldValue - pivotValue*element[j];
+	  if (!oldValue) {
+	    if (fabs(value)>tolerance) {
+	      region[iRow]=value;
+	      regionIndex[numberNonZero++]=iRow;
+	    }
+	  } else {
+	    if (fabs(value)>tolerance) {
+	      region[iRow]=value;
+	    } else {
+	      region[iRow]=COIN_INDEXED_REALLY_TINY_ELEMENT;
+	    }
+	  }
+	}       
+	pivotValue *= pivotRegion[i];
+	region[pivotRow]=pivotValue;
+      } else if (pivotValue) {
+	region[pivotRow]=COIN_INDEXED_REALLY_TINY_ELEMENT;
+      }
+    }
+  }
+  regionSparse->setNumElements ( numberNonZero );
+}
+// Updates part of column transpose PFI (BTRAN),
+    
+void 
+CoinFactorization::updateColumnTransposePFI ( CoinIndexedVector * regionSparse) const
+{
+  double *region = regionSparse->denseVector (  );
+  int numberNonZero = regionSparse->getNumElements();
+  int *index = regionSparse->getIndices (  );
+  int i;
+#ifdef COIN_DEBUG
+  for (i=0;i<numberNonZero;i++) {
+    int iRow=index[i];
+    assert (iRow>=0&&iRow<numberRows_);
+    assert (region[iRow]);
+  }
+#endif
+  const int * pivotColumn = pivotColumn_.array()+numberRows_;
+  const CoinFactorizationDouble *pivotRegion = pivotRegion_.array()+numberRows_;
+  double tolerance = zeroTolerance_;
+  
+  const CoinBigIndex *startColumn = startColumnU_.array()+numberRows_;
+  const int *indexRow = indexRowU_.array();
+  const CoinFactorizationDouble *element = elementU_.array();
+
+  for (i=numberPivots_-1 ; i>=0; i-- ) {
+    int pivotRow = pivotColumn[i];
+    CoinFactorizationDouble pivotValue = region[pivotRow]*pivotRegion[i];
+    for (CoinBigIndex  j= startColumn[i] ; j < startColumn[i+1]; j++ ) {
+      int iRow = indexRow[j];
+      CoinFactorizationDouble value = element[j];
+      pivotValue -= value * region[iRow];
+    }       
+    //pivotValue *= pivotRegion[i];
+    if ( fabs ( pivotValue ) > tolerance ) {
+      if (!region[pivotRow])
+	index[numberNonZero++] = pivotRow;
+      region[pivotRow] = pivotValue;
+    } else {
+      if (region[pivotRow])
+	region[pivotRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+    }       
+  }       
+  //set counts
+  regionSparse->setNumElements ( numberNonZero );
+}
+/* Replaces one Column to basis for PFI
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+   Not sure what checkBeforeModifying means for PFI.
+*/
+int 
+CoinFactorization::replaceColumnPFI ( CoinIndexedVector * regionSparse,
+				      int pivotRow,
+				      double alpha)
+{
+  CoinBigIndex *startColumn=startColumnU_.array()+numberRows_;
+  int *indexRow=indexRowU_.array();
+  CoinFactorizationDouble *element=elementU_.array();
+  CoinFactorizationDouble * pivotRegion = pivotRegion_.array()+numberRows_;
+  // This has incoming column
+  const double *region = regionSparse->denseVector (  );
+  const int * index = regionSparse->getIndices();
+  int numberNonZero = regionSparse->getNumElements();
+
+  int iColumn = numberPivots_;
+
+  if (!iColumn) 
+    startColumn[0]=startColumn[maximumColumnsExtra_];
+  CoinBigIndex start = startColumn[iColumn];
+  
+  //return at once if too many iterations
+  if ( numberPivots_ >= maximumPivots_ ) {
+    return 5;
+  }       
+  if ( lengthAreaU_ - ( start + numberNonZero ) < 0) {
+    return 3;
+  }   
+  
+  int i;
+  if (numberPivots_) {
+    if (fabs(alpha)<1.0e-5) {
+      if (fabs(alpha)<1.0e-7)
+	return 2;
+      else
+	return 1;
+    }
+  } else {
+    if (fabs(alpha)<1.0e-8)
+      return 2;
+  }
+  CoinFactorizationDouble pivotValue = 1.0/alpha;
+  pivotRegion[iColumn]=pivotValue;
+  double tolerance = zeroTolerance_;
+  const int * pivotColumn = pivotColumn_.array();
+  // Operations done before permute back
+  if (regionSparse->packedMode()) {
+    for ( i = 0; i < numberNonZero; i++ ) {
+      int iRow = index[i];
+      if (iRow!=pivotRow) {
+	if ( fabs ( region[i] ) > tolerance ) {
+	  indexRow[start]=pivotColumn[iRow];
+	  element[start++]=region[i]*pivotValue;
+	}
+      }
+    }    
+  } else {
+    for ( i = 0; i < numberNonZero; i++ ) {
+      int iRow = index[i];
+      if (iRow!=pivotRow) {
+	if ( fabs ( region[iRow] ) > tolerance ) {
+	  indexRow[start]=pivotColumn[iRow];
+	  element[start++]=region[iRow]*pivotValue;
+	}
+      }
+    }    
+  }   
+  numberPivots_++;
+  numberNonZero=start-startColumn[iColumn];
+  startColumn[numberPivots_]=start;
+  totalElements_ += numberNonZero;
+  int * pivotColumn2 = pivotColumn_.array()+numberRows_;
+  pivotColumn2[iColumn]=pivotColumn[pivotRow];
+  return 0;
+}
+//  =
+CoinFactorization & CoinFactorization::operator = ( const CoinFactorization & other ) {
+  if (this != &other) {    
+    gutsOfDestructor(2);
+    gutsOfInitialize(3);
+    persistenceFlag_=other.persistenceFlag_;
+    gutsOfCopy(other);
+  }
+  return *this;
+}
+void CoinFactorization::gutsOfCopy(const CoinFactorization &other)
+{
+  elementU_.allocate(other.elementU_, other.lengthAreaU_ *CoinSizeofAsInt(CoinFactorizationDouble));
+  indexRowU_.allocate(other.indexRowU_, other.lengthAreaU_*CoinSizeofAsInt(int) );
+  elementL_.allocate(other.elementL_, other.lengthAreaL_*CoinSizeofAsInt(CoinFactorizationDouble) );
+  indexRowL_.allocate(other.indexRowL_, other.lengthAreaL_*CoinSizeofAsInt(int) );
+  startColumnL_.allocate(other.startColumnL_,(other.numberRows_ + 1)*CoinSizeofAsInt(CoinBigIndex) );
+  int extraSpace;
+  if (other.numberInColumnPlus_.array()) {
+    extraSpace = other.maximumPivots_ + 1 + other.maximumColumnsExtra_ + 1;
+  } else {
+    extraSpace = other.maximumPivots_ + 1 ;
+  }
+  startColumnR_.allocate(other.startColumnR_,extraSpace*CoinSizeofAsInt(CoinBigIndex));
+  pivotRegion_.allocate(other.pivotRegion_, (other.maximumRowsExtra_ + 1 )*CoinSizeofAsInt(CoinFactorizationDouble));
+  permuteBack_.allocate(other.permuteBack_,(other.maximumRowsExtra_ + 1)*CoinSizeofAsInt(int));
+  permute_.allocate(other.permute_,(other.maximumRowsExtra_ + 1)*CoinSizeofAsInt(int));
+  pivotColumnBack_.allocate(other.pivotColumnBack_,(other.maximumRowsExtra_ + 1)*CoinSizeofAsInt(int));
+  firstCount_.allocate(other.firstCount_,(other.maximumRowsExtra_ + 1)*CoinSizeofAsInt(int));
+  startColumnU_.allocate(other.startColumnU_, (other.maximumColumnsExtra_ + 1 )*CoinSizeofAsInt(CoinBigIndex));
+  numberInColumn_.allocate(other.numberInColumn_, (other.maximumColumnsExtra_ + 1 )*CoinSizeofAsInt(int));
+  pivotColumn_.allocate(other.pivotColumn_,(other.maximumColumnsExtra_ + 1)*CoinSizeofAsInt(int));
+  nextColumn_.allocate(other.nextColumn_, (other.maximumColumnsExtra_ + 1 )*CoinSizeofAsInt(int));
+  lastColumn_.allocate(other.lastColumn_, (other.maximumColumnsExtra_ + 1 )*CoinSizeofAsInt(int));
+  indexColumnU_.allocate(other.indexColumnU_, other.lengthAreaU_*CoinSizeofAsInt(int) );
+  nextRow_.allocate(other.nextRow_,(other.maximumRowsExtra_ + 1)*CoinSizeofAsInt(int));
+  lastRow_.allocate( other.lastRow_,(other.maximumRowsExtra_ + 1 )*CoinSizeofAsInt(int));
+  const CoinBigIndex * convertUOther = other.convertRowToColumnU_.array();
+#if COIN_ONE_ETA_COPY
+  if (convertUOther) {
+#endif
+    convertRowToColumnU_.allocate(other.convertRowToColumnU_, other.lengthAreaU_*CoinSizeofAsInt(CoinBigIndex) );
+    startRowU_.allocate(other.startRowU_,(other.maximumRowsExtra_ + 1)*CoinSizeofAsInt(CoinBigIndex));
+    numberInRow_.allocate(other.numberInRow_, (other.maximumRowsExtra_ + 1 )*CoinSizeofAsInt(int));
+#if COIN_ONE_ETA_COPY
+  }
+#endif
+  if (other.sparseThreshold_) {
+    elementByRowL_.allocate(other.elementByRowL_, other.lengthAreaL_ );
+    indexColumnL_.allocate(other.indexColumnL_, other.lengthAreaL_ );
+    startRowL_.allocate(other.startRowL_,other.numberRows_+1);
+  }
+  numberTrials_ = other.numberTrials_;
+  biggerDimension_ = other.biggerDimension_;
+  relaxCheck_ = other.relaxCheck_;
+  numberSlacks_ = other.numberSlacks_;
+  numberU_ = other.numberU_;
+  maximumU_=other.maximumU_;
+  lengthU_ = other.lengthU_;
+  lengthAreaU_ = other.lengthAreaU_;
+  numberL_ = other.numberL_;
+  baseL_ = other.baseL_;
+  lengthL_ = other.lengthL_;
+  lengthAreaL_ = other.lengthAreaL_;
+  numberR_ = other.numberR_;
+  lengthR_ = other.lengthR_;
+  lengthAreaR_ = other.lengthAreaR_;
+  pivotTolerance_ = other.pivotTolerance_;
+  zeroTolerance_ = other.zeroTolerance_;
+#ifndef COIN_FAST_CODE
+  slackValue_ = other.slackValue_;
+#endif
+  areaFactor_ = other.areaFactor_;
+  numberRows_ = other.numberRows_;
+  numberRowsExtra_ = other.numberRowsExtra_;
+  maximumRowsExtra_ = other.maximumRowsExtra_;
+  numberColumns_ = other.numberColumns_;
+  numberColumnsExtra_ = other.numberColumnsExtra_;
+  maximumColumnsExtra_ = other.maximumColumnsExtra_;
+  maximumPivots_=other.maximumPivots_;
+  numberGoodU_ = other.numberGoodU_;
+  numberGoodL_ = other.numberGoodL_;
+  numberPivots_ = other.numberPivots_;
+  messageLevel_ = other.messageLevel_;
+  totalElements_ = other.totalElements_;
+  factorElements_ = other.factorElements_;
+  status_ = other.status_;
+  doForrestTomlin_ = other.doForrestTomlin_;
+  collectStatistics_=other.collectStatistics_;
+  ftranCountInput_=other.ftranCountInput_;
+  ftranCountAfterL_=other.ftranCountAfterL_;
+  ftranCountAfterR_=other.ftranCountAfterR_;
+  ftranCountAfterU_=other.ftranCountAfterU_;
+  btranCountInput_=other.btranCountInput_;
+  btranCountAfterU_=other.btranCountAfterU_;
+  btranCountAfterR_=other.btranCountAfterR_;
+  btranCountAfterL_=other.btranCountAfterL_;
+  numberFtranCounts_=other.numberFtranCounts_;
+  numberBtranCounts_=other.numberBtranCounts_;
+  ftranAverageAfterL_=other.ftranAverageAfterL_;
+  ftranAverageAfterR_=other.ftranAverageAfterR_;
+  ftranAverageAfterU_=other.ftranAverageAfterU_;
+  btranAverageAfterU_=other.btranAverageAfterU_;
+  btranAverageAfterR_=other.btranAverageAfterR_;
+  btranAverageAfterL_=other.btranAverageAfterL_; 
+  biasLU_=other.biasLU_;
+  sparseThreshold_=other.sparseThreshold_;
+  sparseThreshold2_=other.sparseThreshold2_;
+  CoinBigIndex space = lengthAreaL_ - lengthL_;
+
+  numberDense_ = other.numberDense_;
+  denseThreshold_=other.denseThreshold_;
+  if (numberDense_) {
+    denseArea_ = new double [numberDense_*numberDense_];
+    CoinMemcpyN(other.denseArea_,
+	   numberDense_*numberDense_,denseArea_);
+    densePermute_ = new int [numberDense_];
+    CoinMemcpyN(other.densePermute_,
+	   numberDense_,densePermute_);
+  }
+
+  lengthAreaR_ = space;
+  elementR_ = elementL_.array() + lengthL_;
+  indexRowR_ = indexRowL_.array() + lengthL_;
+  workArea_ = other.workArea_;
+  workArea2_ = other.workArea2_;
+  //now copy everything
+  //assuming numberRowsExtra==numberColumnsExtra
+  if (numberRowsExtra_) {
+    if (convertUOther) {
+      CoinMemcpyN ( other.startRowU_.array(), numberRowsExtra_ + 1, startRowU_.array() );
+      CoinMemcpyN ( other.numberInRow_.array(), numberRowsExtra_ + 1, numberInRow_.array() );
+      startRowU_.array()[maximumRowsExtra_] = other.startRowU_.array()[maximumRowsExtra_];
+    }
+    CoinMemcpyN ( other.pivotRegion_.array(), numberRowsExtra_ , pivotRegion_.array() );
+    CoinMemcpyN ( other.permuteBack_.array(), numberRowsExtra_ + 1, permuteBack_.array() );
+    CoinMemcpyN ( other.permute_.array(), numberRowsExtra_ + 1, permute_.array() );
+    CoinMemcpyN ( other.pivotColumnBack_.array(), numberRowsExtra_ + 1, pivotColumnBack_.array() );
+    CoinMemcpyN ( other.firstCount_.array(), numberRowsExtra_ + 1, firstCount_.array() );
+    CoinMemcpyN ( other.startColumnU_.array(), numberRowsExtra_ + 1, startColumnU_.array() );
+    CoinMemcpyN ( other.numberInColumn_.array(), numberRowsExtra_ + 1, numberInColumn_.array() );
+    CoinMemcpyN ( other.pivotColumn_.array(), numberRowsExtra_ + 1, pivotColumn_.array() );
+    CoinMemcpyN ( other.nextColumn_.array(), numberRowsExtra_ + 1, nextColumn_.array() );
+    CoinMemcpyN ( other.lastColumn_.array(), numberRowsExtra_ + 1, lastColumn_.array() );
+    CoinMemcpyN ( other.startColumnR_.array() , numberRowsExtra_ - numberColumns_ + 1,
+			startColumnR_.array() );  
+    //extra one at end
+    startColumnU_.array()[maximumColumnsExtra_] =
+      other.startColumnU_.array()[maximumColumnsExtra_];
+    nextColumn_.array()[maximumColumnsExtra_] = other.nextColumn_.array()[maximumColumnsExtra_];
+    lastColumn_.array()[maximumColumnsExtra_] = other.lastColumn_.array()[maximumColumnsExtra_];
+    CoinMemcpyN ( other.nextRow_.array(), numberRowsExtra_ + 1, nextRow_.array() );
+    CoinMemcpyN ( other.lastRow_.array(), numberRowsExtra_ + 1, lastRow_.array() );
+    nextRow_.array()[maximumRowsExtra_] = other.nextRow_.array()[maximumRowsExtra_];
+    lastRow_.array()[maximumRowsExtra_] = other.lastRow_.array()[maximumRowsExtra_];
+  }
+  CoinMemcpyN ( other.elementR_, lengthR_, elementR_ );
+  CoinMemcpyN ( other.indexRowR_, lengthR_, indexRowR_ );
+  //row and column copies of U
+  /* as elements of U may have been zeroed but column counts zero
+     copy all elements */
+  const CoinBigIndex * startColumnU = startColumnU_.array();
+  const int * numberInColumn = numberInColumn_.array();
+#ifndef NDEBUG
+  int maxU=0;
+  for (int iRow = 0; iRow < numberRowsExtra_; iRow++ ) {
+    CoinBigIndex start = startColumnU[iRow];
+    int numberIn = numberInColumn[iRow];
+    maxU = CoinMax(maxU,start+numberIn);
+  }
+  assert (maximumU_>=maxU);
+#endif
+  CoinMemcpyN ( other.elementU_.array() , maximumU_, elementU_.array() );
+#if COIN_ONE_ETA_COPY
+  if (convertUOther) {
+#endif
+    const int * indexColumnUOther = other.indexColumnU_.array();
+    CoinBigIndex * convertU = convertRowToColumnU_.array();
+    int * indexColumnU = indexColumnU_.array();
+    const CoinBigIndex * startRowU = startRowU_.array();
+    const int * numberInRow = numberInRow_.array();
+    for (int iRow = 0; iRow < numberRowsExtra_; iRow++ ) {
+      //row
+      CoinBigIndex start = startRowU[iRow];
+      int numberIn = numberInRow[iRow];
+      
+      CoinMemcpyN ( indexColumnUOther + start, numberIn, indexColumnU + start );
+      CoinMemcpyN (convertUOther + start , numberIn,   convertU + start );
+    }
+#if COIN_ONE_ETA_COPY
+  }
+#endif
+  const int * indexRowUOther = other.indexRowU_.array();
+  int * indexRowU = indexRowU_.array();
+  for (int iRow = 0; iRow < numberRowsExtra_; iRow++ ) {
+    //column
+    CoinBigIndex start = startColumnU[iRow];
+    int numberIn = numberInColumn[iRow];
+    CoinMemcpyN ( indexRowUOther + start, numberIn, indexRowU + start );
+  }
+  // L is contiguous
+  if (numberRows_)
+    CoinMemcpyN ( other.startColumnL_.array(), numberRows_ + 1, startColumnL_.array() );
+  CoinMemcpyN ( other.elementL_.array(), lengthL_, elementL_.array() );
+  CoinMemcpyN ( other.indexRowL_.array(), lengthL_, indexRowL_.array() );
+  if (other.sparseThreshold_) {
+    goSparse();
+  }
+}
+// See if worth going sparse
+void 
+CoinFactorization::checkSparse()
+{
+  // See if worth going sparse and when
+  if (numberFtranCounts_>100) {
+    ftranCountInput_= CoinMax(ftranCountInput_,1.0);
+    ftranAverageAfterL_ = CoinMax(ftranCountAfterL_/ftranCountInput_,1.0);
+    ftranAverageAfterR_ = CoinMax(ftranCountAfterR_/ftranCountAfterL_,1.0);
+    ftranAverageAfterU_ = CoinMax(ftranCountAfterU_/ftranCountAfterR_,1.0);
+    if (btranCountInput_&&btranCountAfterU_&&btranCountAfterR_) {
+      btranAverageAfterU_ = CoinMax(btranCountAfterU_/btranCountInput_,1.0);
+      btranAverageAfterR_ = CoinMax(btranCountAfterR_/btranCountAfterU_,1.0);
+      btranAverageAfterL_ = CoinMax(btranCountAfterL_/btranCountAfterR_,1.0);
+    } else {
+      // we have not done any useful btrans (values pass?)
+      btranAverageAfterU_ = 1.0;
+      btranAverageAfterR_ = 1.0;
+      btranAverageAfterL_ = 1.0;
+    }
+  }
+  // scale back
+  
+  ftranCountInput_ *= 0.8;
+  ftranCountAfterL_ *= 0.8;
+  ftranCountAfterR_ *= 0.8;
+  ftranCountAfterU_ *= 0.8;
+  btranCountInput_ *= 0.8;
+  btranCountAfterU_ *= 0.8;
+  btranCountAfterR_ *= 0.8;
+  btranCountAfterL_ *= 0.8;
+}
+// Condition number - product of pivots after factorization
+double 
+CoinFactorization::conditionNumber() const
+{
+  double condition = 1.0;
+  const CoinFactorizationDouble * pivotRegion = pivotRegion_.array();
+  for (int i=0;i<numberRows_;i++) {
+    condition *= pivotRegion[i];
+  }
+  condition = CoinMax(fabs(condition),1.0e-50);
+  return 1.0/condition;
+}
+#ifdef COIN_DEVELOP
+extern double ncall_DZ;
+extern double nrow_DZ;
+extern double nslack_DZ;
+extern double nU_DZ;
+extern double nnz_DZ;
+extern double nDone_DZ;
+extern double ncall_SZ;
+extern double nrow_SZ;
+extern double nslack_SZ;
+extern double nU_SZ;
+extern double nnz_SZ;
+extern double nDone_SZ;
+void print_fac_stats()
+{
+  double mult = ncall_DZ ? 1.0/ncall_DZ : 1.0;
+  printf("UDen called %g times, average rows %g, average slacks %g, average (U-S) %g average nnz in %g average ops %g\n",
+	 ncall_DZ,mult*nrow_DZ,mult*nslack_DZ,mult*(nU_DZ-nslack_DZ),mult*nnz_DZ,mult*nDone_DZ);
+  ncall_DZ=0.0;
+  nrow_DZ=0.0;
+  nslack_DZ=0.0;
+  nU_DZ=0.0;
+  nnz_DZ=0.0;
+  nDone_DZ=0.0;
+  mult = ncall_SZ ? 1.0/ncall_SZ : 1.0;
+  printf("USpars called %g times, average rows %g, average slacks %g, average (U-S) %g average nnz in %g average ops %g\n",
+	 ncall_SZ,mult*nrow_SZ,mult*nslack_SZ,mult*(nU_SZ-nslack_SZ),mult*nnz_SZ,mult*nDone_SZ);
+  ncall_SZ=0.0;
+  nrow_SZ=0.0;
+  nslack_SZ=0.0;
+  nU_SZ=0.0;
+  nnz_SZ=0.0;
+  nDone_SZ=0.0;
+}
+#endif
diff --git a/cbits/coin/CoinFileIO.cpp b/cbits/coin/CoinFileIO.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFileIO.cpp
@@ -0,0 +1,694 @@
+/* $Id: CoinFileIO.cpp 1439 2011-06-13 16:31:21Z stefan $ */
+// Copyright (C) 2005, COIN-OR.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinUtilsConfig.h"
+#include "CoinFileIO.hpp"
+
+#include "CoinError.hpp"
+#include "CoinHelperFunctions.hpp"
+
+#include <vector>
+#include <cstring>
+
+// ------ CoinFileIOBase -------
+
+CoinFileIOBase::CoinFileIOBase (const std::string &fileName):
+  fileName_ (fileName)
+{}
+
+CoinFileIOBase::~CoinFileIOBase ()
+{}
+
+const char *CoinFileIOBase::getFileName () const
+{
+  return fileName_.c_str ();
+}
+
+
+// ------------------------------------------------------
+//   next we implement some subclasses of CoinFileInput 
+//   for plain text and compressed files
+// ------------------------------------------------------
+
+// ------ Input for plain text ------
+
+#include <stdio.h>
+
+// This reads plain text files
+class CoinPlainFileInput: public CoinFileInput
+{
+public:
+  CoinPlainFileInput (const std::string &fileName):
+    CoinFileInput (fileName), f_ (0)
+  {
+    readType_="plain";
+    if (fileName!="stdin") {
+      f_ = fopen (fileName.c_str (), "r");
+      if (f_ == 0)
+        throw CoinError ("Could not open file for reading!", 
+                         "CoinPlainFileInput", 
+                         "CoinPlainFileInput");
+    } else {
+      f_ = stdin;
+    }
+  }
+
+  virtual ~CoinPlainFileInput ()
+  {
+    if (f_ != 0)
+      fclose (f_);
+  }
+
+  virtual int read (void *buffer, int size)
+  {
+    return static_cast<int>(fread (buffer, 1, size, f_));
+  }
+
+  virtual char *gets (char *buffer, int size)
+  {
+    return fgets (buffer, size, f_);
+  }
+
+private:
+  FILE *f_;
+};
+
+// ------ helper class supporting buffered gets -------
+
+// This is a CoinFileInput class to handle cases, where the gets method
+// is not easy to implement (i.e. bzlib has no equivalent to gets, and
+// zlib's gzgets is extremely slow). It's subclasses only have to implement
+// the readRaw method, while the read and gets methods are handled by this
+// class using an internal buffer.
+class CoinGetslessFileInput: public CoinFileInput
+{
+public:
+  CoinGetslessFileInput (const std::string &fileName): 
+    CoinFileInput (fileName), 
+    dataBuffer_ (8*1024), 
+    dataStart_ (&dataBuffer_[0]), 
+    dataEnd_ (&dataBuffer_[0])
+  {}
+
+  virtual ~CoinGetslessFileInput () {}
+
+  virtual int read (void *buffer, int size)
+  {
+    if (size <= 0)
+      return 0;
+
+    // return value
+    int r = 0;
+
+    // treat destination as char *
+    char *dest = static_cast<char *>(buffer);
+
+    // First consume data from buffer if available.
+    if (dataStart_ < dataEnd_)
+      {
+	int amount = static_cast<int>(dataEnd_ - dataStart_);
+	if (amount > size)
+	  amount = size;
+
+ CoinMemcpyN( dataStart_, amount, dest);
+
+	dest += amount;
+	size -= amount;
+
+	dataStart_ += amount;
+
+	r = amount;
+      }
+
+    // If we require more data, use readRaw.
+    // We don't use the buffer here, as readRaw is ecpected to be efficient.
+    if (size > 0)
+      r += readRaw (dest, size);
+
+    return r;
+  }
+
+  virtual char *gets (char *buffer, int size)
+  {
+    if (size <= 1)
+      return 0;
+
+    char *dest = buffer;
+    char *destLast = dest + size - 2; // last position allowed to be written
+
+    bool initiallyEmpty = (dataStart_ == dataEnd_);
+    
+    for (;;)
+      {
+	// refill dataBuffer if needed
+	if (dataStart_ == dataEnd_)
+	  {
+	    dataStart_ = dataEnd_ = &dataBuffer_[0];
+	    int count = readRaw (dataStart_, static_cast<int>(dataBuffer_.size ()));
+
+	    // at EOF?
+	    if (count <= 0) 
+	      {
+		*dest = 0;
+		// if it was initially empty we had nothing written and should 
+		// return 0, otherwise at least the buffer contents were
+		// transfered and buffer has to be returned.
+		return initiallyEmpty ? 0 : buffer;
+	      }
+
+	    dataEnd_ = dataStart_ + count;
+	  }
+
+	// copy character from buffer
+	*dest = *dataStart_++;
+
+	// terminate, if character was \n or bufferEnd was reached
+	if (*dest == '\n' || dest == destLast)
+	  {
+	    *++dest = 0;
+	    return buffer;
+	  }
+
+	++dest;
+      } 
+
+    // we should never reach this place
+    throw CoinError ("Reached unreachable code!", 
+		     "gets", 
+		     "CoinGetslessFileInput");
+  }
+
+protected:
+  // This should be implemented by the subclasses. It essentially behaves
+  // like fread: the location pointed to by buffer should be filled with
+  // size bytes. Return value is the number of bytes written (0 indicates EOF).
+  virtual int readRaw (void *buffer, int size) = 0;
+
+private:
+  std::vector<char> dataBuffer_; // memory used for buffering 
+  char *dataStart_; // pointer to currently buffered data
+  char *dataEnd_; // pointer to "one behind last data element"
+};
+
+
+// -------- input for gzip compressed files -------
+
+
+#ifdef COIN_HAS_ZLIB
+
+#include <zlib.h>
+
+// This class handles gzip'ed files using libz.
+// While zlib offers the gzread and gzgets functions which do all we want, 
+// the gzgets is _very_ slow as it gets single bytes via the complex gzread.
+// So we use the CoinGetslessFileInput as base.
+class CoinGzipFileInput: public CoinGetslessFileInput
+{
+public:
+  CoinGzipFileInput (const std::string &fileName):
+    CoinGetslessFileInput (fileName), gzf_ (0)
+  {
+    readType_="zlib";
+    gzf_ = gzopen (fileName.c_str (), "r");
+    if (gzf_ == 0)
+      throw CoinError ("Could not open file for reading!", 
+		       "CoinGzipFileInput", 
+		       "CoinGzipFileInput");
+  }
+
+  virtual ~CoinGzipFileInput ()
+  {
+    if (gzf_ != 0)
+      gzclose (gzf_);
+  }
+
+protected:
+  virtual int readRaw (void *buffer, int size)
+  {
+    return gzread (gzf_, buffer, size);
+  }
+
+private:
+  gzFile gzf_;
+};
+
+#endif // COIN_HAS_ZLIB
+
+
+// ------- input for bzip2 compressed files ------
+
+#ifdef COIN_HAS_BZLIB
+
+#include <bzlib.h>
+
+// This class handles files compressed by bzip2 using libbz.
+// As bzlib has no builtin gets, we use the CoinGetslessFileInput.
+class CoinBzip2FileInput: public CoinGetslessFileInput
+{
+public:
+  CoinBzip2FileInput (const std::string &fileName):
+    CoinGetslessFileInput (fileName), f_ (0), bzf_ (0)
+  {
+    int bzError = BZ_OK;
+    readType_="bzlib";
+
+    f_ = fopen (fileName.c_str (), "r");
+    
+    if (f_ != 0)
+      bzf_ = BZ2_bzReadOpen (&bzError, f_, 0, 0, 0, 0);
+
+    if (f_ == 0 || bzError != BZ_OK || bzf_ == 0)
+      throw CoinError ("Could not open file for reading!", 
+		       "CoinBzip2FileInput", 
+		       "CoinBzip2FileInput");
+  }
+
+  virtual ~CoinBzip2FileInput ()
+  {
+    int bzError = BZ_OK;
+    if (bzf_ != 0)
+      BZ2_bzReadClose (&bzError, bzf_);
+
+    if (f_ != 0)
+      fclose (f_);
+  }
+
+protected:
+  virtual int readRaw (void *buffer, int size)
+  {
+    int bzError = BZ_OK;
+    int count = BZ2_bzRead (&bzError, bzf_, buffer, size);
+
+    if (bzError == BZ_OK || bzError == BZ_STREAM_END)
+      return count;
+    
+    // Error?
+    return 0;
+  }
+
+private:
+  FILE *f_;
+  BZFILE *bzf_;
+};
+
+#endif // COIN_HAS_BZLIB
+
+
+// ----- implementation of CoinFileInput's methods
+
+/// indicates whether CoinFileInput supports gzip'ed files
+bool CoinFileInput::haveGzipSupport() {
+#ifdef COIN_HAS_ZLIB
+  return true;
+#else
+  return false;
+#endif
+}
+
+/// indicates whether CoinFileInput supports bzip2'ed files
+bool CoinFileInput::haveBzip2Support() {
+#ifdef COIN_HAS_BZLIB
+  return true;
+#else
+  return false;
+#endif
+}
+
+CoinFileInput *CoinFileInput::create (const std::string &fileName)
+{
+  // first try to open file, and read first bytes 
+  unsigned char header[4];
+  size_t count ; // So stdin will be plain file
+  if (fileName!="stdin") {
+    FILE *f = fopen (fileName.c_str (), "r");
+
+    if (f == 0)
+      throw CoinError ("Could not open file for reading!",
+                       "create",
+                       "CoinFileInput");
+    count = fread (header, 1, 4, f);
+    fclose (f);
+  } else {
+    // Reading from stdin - for moment not compressed
+    count=0 ; // So stdin will be plain file
+  }
+  // gzip files start with the magic numbers 0x1f 0x8b
+  if (count >= 2 && header[0] == 0x1f && header[1] == 0x8b)
+    {
+#ifdef COIN_HAS_ZLIB
+      return new CoinGzipFileInput (fileName);
+#else
+      throw CoinError ("Cannot read gzip'ed file because zlib was "
+		       "not compiled into COIN!",
+		       "create",
+		       "CoinFileInput");
+#endif
+    }
+
+  // bzip2 files start with the string "BZh"
+  if (count >= 3 && header[0] == 'B' && header[1] == 'Z' && header[2] == 'h')
+    {
+#ifdef COIN_HAS_BZLIB
+      return new CoinBzip2FileInput (fileName);
+#else
+      throw CoinError ("Cannot read bzip2'ed file because bzlib was "
+		       "not compiled into COIN!",
+		       "create",
+		       "CoinFileInput");
+#endif
+    }
+
+  // fallback: probably plain text file
+  return new CoinPlainFileInput (fileName);
+}
+
+CoinFileInput::CoinFileInput (const std::string &fileName): 
+  CoinFileIOBase (fileName)
+{}
+
+CoinFileInput::~CoinFileInput () 
+{}
+
+
+// ------------------------------------------------------
+//   Some subclasses of CoinFileOutput 
+//   for plain text and compressed files
+// ------------------------------------------------------
+
+
+// -------- CoinPlainFileOutput ---------
+
+// Class to handle output to text files without compression.
+class CoinPlainFileOutput: public CoinFileOutput
+{
+public:
+  CoinPlainFileOutput (const std::string &fileName): 
+    CoinFileOutput (fileName), f_ (0)
+  {
+    if (fileName == "-" || fileName == "stdout") {
+      f_ = stdout;
+    } else {
+      f_ = fopen (fileName.c_str (), "w");
+      if (f_ == 0)
+	throw CoinError ("Could not open file for writing!",
+			 "CoinPlainFileOutput",
+			 "CoinPlainFileOutput");
+    }
+  }
+
+  virtual ~CoinPlainFileOutput () 
+  {
+    if (f_ != 0 && f_ != stdout)
+      fclose (f_);
+  }
+
+  virtual int write (const void *buffer, int size)
+  {
+    return static_cast<int>(fwrite (buffer, 1, size, f_));
+  }
+
+  // we have something better than the default implementation
+  virtual bool puts (const char *s)
+  {
+    return fputs (s, f_) >= 0;
+  }
+
+private:
+  FILE *f_;
+};
+
+
+// ------- CoinGzipFileOutput ---------
+
+#ifdef COIN_HAS_ZLIB
+
+// no need to include the header, as this was done for the input class
+
+// Handle output with gzip compression
+class CoinGzipFileOutput: public CoinFileOutput
+{
+public:
+  CoinGzipFileOutput (const std::string &fileName): 
+    CoinFileOutput (fileName), gzf_ (0)
+  {
+    gzf_ = gzopen (fileName.c_str (), "w");
+    if (gzf_ == 0)
+      throw CoinError ("Could not open file for writing!",
+		       "CoinGzipFileOutput",
+		       "CoinGzipFileOutput");
+  }
+
+  virtual ~CoinGzipFileOutput () 
+  {
+    if (gzf_ != 0)
+      gzclose (gzf_);
+  }
+
+  virtual int write (const void * buffer, int size)
+  {
+    return gzwrite (gzf_, const_cast<void *> (buffer), size);
+  }
+  
+  // as zlib's gzputs is no more clever than our own, there's
+  // no need to replace the default.
+  
+private:
+  gzFile gzf_;
+};
+
+#endif  // COIN_HAS_ZLIB
+
+
+// ------- CoinBzip2FileOutput -------
+
+#ifdef COIN_HAS_BZLIB
+
+// no need to include the header, as this was done for the input class
+
+// Output to bzip2 compressed file
+class CoinBzip2FileOutput: public CoinFileOutput
+{
+public:
+  CoinBzip2FileOutput (const std::string &fileName): 
+    CoinFileOutput (fileName), f_ (0), bzf_ (0)
+  {
+    int bzError = BZ_OK;
+
+    f_ = fopen (fileName.c_str (), "w");
+    
+    if (f_ != 0)
+      bzf_ = BZ2_bzWriteOpen (&bzError, f_, 
+			      9, /* Number of 100k blocks used for compression.
+				    Must be between 1 and 9 inclusive. As 9
+				    gives best compression and I guess we can
+				    spend some memory, we use it. */
+			      0, /* verbosity */
+			      30 /* suggested by bzlib manual */ );
+
+    if (f_ == 0 || bzError != BZ_OK || bzf_ == 0)
+      throw CoinError ("Could not open file for writing!",
+		       "CoinBzip2FileOutput",
+		       "CoinBzip2FileOutput");
+  }
+
+  virtual ~CoinBzip2FileOutput () 
+  {
+    int bzError = BZ_OK;
+    if (bzf_ != 0)
+      BZ2_bzWriteClose (&bzError, bzf_, 0, 0, 0);
+
+    if (f_ != 0)
+      fclose (f_);
+  }
+
+  virtual int write (const void *buffer, int size)
+  {
+    int bzError = BZ_OK;
+    BZ2_bzWrite (&bzError, bzf_, const_cast<void *> (buffer), size);
+    return (bzError == BZ_OK) ? size : 0;
+  }
+  
+private:
+  FILE *f_;
+  BZFILE *bzf_;
+};
+
+#endif // COIN_HAS_BZLIB
+
+
+// ------- implementation of CoinFileOutput's methods
+
+bool CoinFileOutput::compressionSupported (Compression compression)
+{
+  switch (compression)
+    {
+    case COMPRESS_NONE: 
+      return true;
+
+    case COMPRESS_GZIP:
+#ifdef COIN_HAS_ZLIB
+      return true;
+#else
+      return false;
+#endif
+
+    case COMPRESS_BZIP2:
+#ifdef COIN_HAS_BZLIB
+      return true;
+#else
+      return false;
+#endif
+
+    default:
+      return false;
+    }
+}
+
+CoinFileOutput *CoinFileOutput::create (const std::string &fileName, 
+					Compression compression)
+{
+  switch (compression)
+    {
+    case COMPRESS_NONE: 
+      return new CoinPlainFileOutput (fileName);
+
+    case COMPRESS_GZIP:
+#ifdef COIN_HAS_ZLIB
+      return new CoinGzipFileOutput (fileName);
+#endif
+      break;
+      
+    case COMPRESS_BZIP2:
+#ifdef COIN_HAS_BZLIB
+      return new CoinBzip2FileOutput (fileName);
+#endif
+      break;
+
+    default:
+      break;
+    }
+
+  throw CoinError ("Unsupported compression selected!",
+		   "create",
+		   "CoinFileOutput");
+}
+
+CoinFileOutput::CoinFileOutput (const std::string &fileName):
+  CoinFileIOBase (fileName)
+{}
+
+CoinFileOutput::~CoinFileOutput ()
+{}
+
+bool CoinFileOutput::puts (const char *s)
+{
+  int len = static_cast<int>(strlen (s));
+  if (len == 0)
+    return true;
+
+  return write (s, len) == len;
+}
+
+/*
+  Tests if the given string looks like an absolute path to a file.
+    - unix:	string begins with `/'
+    - windows:	string begins with `\' or `drv:', where drv is a drive
+		designator.
+*/
+bool fileAbsPath (const std::string &path)
+{
+  const char dirsep =  CoinFindDirSeparator() ;
+
+  // If the first two chars are drive designators then treat it as absolute
+  // path (noone in their right mind would create a file named 'Z:' on unix,
+  // right?...)
+  const size_t len = path.length();
+  if (len >= 2 && path[1] == ':') {
+    const char ch = path[0];
+    if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) {
+      return true;
+    }
+  }
+
+  return path[0] == dirsep;
+}
+
+
+/*
+   Tests if file readable and may change name to add 
+   compression extension.  Here to get ZLIB etc in one place
+
+   stdin goes by unmolested by all the fussing with file names. We shouldn't
+   close it, either.
+*/
+bool fileCoinReadable(std::string & fileName, const std::string &dfltPrefix)
+{
+  if (fileName != "stdin")
+  { const char dirsep =  CoinFindDirSeparator();
+    std::string directory ;
+    if (dfltPrefix == "")
+    { directory = (dirsep == '/' ? "./" : ".\\") ; }
+    else
+    { directory = dfltPrefix ;
+      if (directory[directory.length()-1] != dirsep)
+      { directory += dirsep ; } }
+
+    bool absolutePath = fileAbsPath(fileName) ;
+    std::string field = fileName;
+
+    if (absolutePath) {
+      // nothing to do
+    } else if (field[0]=='~') {
+      char * home_dir = getenv("HOME");
+      if (home_dir) {
+	std::string home(home_dir);
+	field=field.erase(0,1);
+	fileName = home+field;
+      } else {
+	fileName=field;
+      }
+    } else {
+      fileName = directory+field;
+    }
+  }
+  // I am opening it to make sure not odd
+  FILE *fp;
+  if (strcmp(fileName.c_str(),"stdin")) {
+    fp = fopen ( fileName.c_str(), "r" );
+  } else {
+    fp = stdin;
+  }
+#ifdef COIN_HAS_ZLIB
+  if (!fp) {
+    std::string fname = fileName;
+    fname += ".gz";
+    fp = fopen ( fname.c_str(), "r" );
+    if (fp)
+      fileName=fname;
+  }
+#endif
+#ifdef COIN_HAS_BZLIB
+  if (!fp) {
+    std::string fname = fileName;
+    fname += ".bz2";
+    fp = fopen ( fname.c_str(), "r" );
+    if (fp)
+      fileName=fname;
+  }
+#endif
+  if (!fp) {
+    return false;
+  } else {
+    if (fp != stdin) {
+      fclose(fp);
+    }
+    return true;
+  }
+}
+
diff --git a/cbits/coin/CoinFileIO.hpp b/cbits/coin/CoinFileIO.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFileIO.hpp
@@ -0,0 +1,166 @@
+/* $Id: CoinFileIO.hpp 1439 2011-06-13 16:31:21Z stefan $ */
+// Copyright (C) 2005, COIN-OR.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinFileIO_H
+#define CoinFileIO_H
+
+#include <string>
+
+/// Base class for FileIO classes.
+class CoinFileIOBase
+{
+public:
+  /// Constructor.
+  /// @param fileName The name of the file used by this object.
+  CoinFileIOBase (const std::string &fileName);
+
+  /// Destructor.
+  ~CoinFileIOBase ();
+
+  /// Return the name of the file used by this object.
+  const char *getFileName () const;
+
+  /// Return the method of reading being used
+  inline std::string getReadType () const
+  { return readType_.c_str();}
+protected:
+  std::string readType_;
+private:
+  CoinFileIOBase ();
+  CoinFileIOBase (const CoinFileIOBase &);
+
+  std::string fileName_;
+};
+
+/// Abstract base class for file input classes.
+class CoinFileInput: public CoinFileIOBase
+{
+public:
+  /// indicates whether CoinFileInput supports gzip'ed files
+  static bool haveGzipSupport();
+  /// indicates whether CoinFileInput supports bzip2'ed files
+  static bool haveBzip2Support();
+
+  /// Factory method, that creates a CoinFileInput (more precisely
+  /// a subclass of it) for the file specified. This method reads the 
+  /// first few bytes of the file and determines if this is a compressed
+  /// or a plain file and returns the correct subclass to handle it.
+  /// If the file does not exist or uses a compression not compiled in
+  /// an exception is thrown.
+  /// @param fileName The file that should be read.
+  static CoinFileInput *create (const std::string &fileName);
+
+  /// Constructor (don't use this, use the create method instead).
+  /// @param fileName The name of the file used by this object.
+  CoinFileInput (const std::string &fileName);
+
+  /// Destructor.
+  virtual ~CoinFileInput ();
+
+  /// Read a block of data from the file, similar to fread.
+  /// @param buffer Address of a buffer to store the data into.
+  /// @param size Number of bytes to read (buffer should be large enough).
+  /// @return Number of bytes read.
+  virtual int read (void *buffer, int size) = 0;
+
+  /// Reads up to (size-1) characters an stores them into the buffer, 
+  /// similar to fgets.
+  /// Reading ends, when EOF or a newline occurs or (size-1) characters have
+  /// been read. The resulting string is terminated with '\0'. If reading
+  /// ends due to an encoutered newline, the '\n' is put into the buffer, 
+  /// before the '\0' is appended.
+  /// @param buffer The buffer to put the string into.
+  /// @param size The size of the buffer in characters.
+  /// @return buffer on success, or 0 if no characters have been read.
+  virtual char *gets (char *buffer, int size) = 0;
+};
+
+/// Abstract base class for file output classes.
+class CoinFileOutput: public CoinFileIOBase
+{
+public:
+
+  /// The compression method.
+  enum Compression { 
+    COMPRESS_NONE = 0, ///< No compression.
+    COMPRESS_GZIP = 1, ///< gzip compression.
+    COMPRESS_BZIP2 = 2 ///< bzip2 compression.
+  };
+
+  /// Returns whether the specified compression method is supported 
+  /// (i.e. was compiled into COIN).
+  static bool compressionSupported (Compression compression);
+
+  /// Factory method, that creates a CoinFileOutput (more precisely
+  /// a subclass of it) for the file specified. If the compression method
+  /// is not supported an exception is thrown (so use compressionSupported
+  /// first, if this is a problem). The reason for not providing direct 
+  /// access to the subclasses (and using such a method instead) is that
+  /// depending on the build configuration some of the classes are not 
+  /// available (or functional). This way we can handle all required ifdefs
+  /// here instead of polluting other files.
+  /// @param fileName The file that should be read.
+  /// @param compression Compression method used.
+  static CoinFileOutput *create (const std::string &fileName, 
+				 Compression compression);
+
+  /// Constructor (don't use this, use the create method instead).
+  /// @param fileName The name of the file used by this object.
+  CoinFileOutput (const std::string &fileName);
+
+  /// Destructor.
+  virtual ~CoinFileOutput ();
+
+  /// Write a block of data to the file, similar to fwrite.
+  /// @param buffer Address of a buffer containing the data to be written.
+  /// @param size Number of bytes to write.
+  /// @return Number of bytes written.
+  virtual int write (const void * buffer, int size) = 0;
+
+  /// Write a string to the file (like fputs).
+  /// Just as with fputs no trailing newline is inserted!
+  /// The terminating '\0' is not written to the file.
+  /// The default implementation determines the length of the string
+  /// and calls write on it.
+  /// @param s The zero terminated string to be written.
+  /// @return true on success, false on error.
+  virtual bool puts (const char *s);
+
+  /// Convenience method: just a 'puts(s.c_str())'.
+  inline bool puts (const std::string &s)
+  {
+    return puts (s.c_str ());
+  } 
+};
+
+/*! \relates CoinFileInput
+    \brief Test if the given string looks like an absolute file path
+
+    The criteria are:
+    - unix: string begins with `/'
+    - windows: string begins with `\' or with `drv:' (drive specifier)
+*/
+bool fileAbsPath (const std::string &path) ;
+
+/*! \relates CoinFileInput
+    \brief Test if the file is readable, using likely versions of the file
+	   name, and return the name that worked.
+
+   The file name is constructed from \p name using the following rules:
+   <ul>
+     <li> An absolute path is not modified.
+     <li> If the name begins with `~', an attempt is made to replace `~'
+	  with the value of the environment variable HOME.
+     <li> If a default prefix (\p dfltPrefix) is provided, it is
+	  prepended to the name.
+   </ul>
+   If the constructed file name cannot be opened, and CoinUtils was built
+   with support for compressed files, fileCoinReadable will try any
+   standard extensions for supported compressed files.
+
+   The value returned in \p name is the file name that actually worked.
+*/
+bool fileCoinReadable(std::string &name,
+		      const std::string &dfltPrefix = std::string(""));
+#endif
diff --git a/cbits/coin/CoinFinite.cpp b/cbits/coin/CoinFinite.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFinite.cpp
@@ -0,0 +1,49 @@
+/* $Id: CoinFinite.cpp 1420 2011-04-29 18:09:32Z stefan $ */
+// Copyright (C) 2011, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinFinite.hpp"
+#include "CoinUtilsConfig.h"
+
+#ifdef HAVE_CFLOAT
+# include <cfloat>
+#else
+# ifdef HAVE_FLOAT_H
+#  include <float.h>
+# endif
+#endif
+
+#ifdef HAVE_CMATH
+# include <cmath>
+#else
+# ifdef HAVE_MATH_H
+#  include <math.h>
+# endif
+#endif
+
+#ifdef HAVE_CIEEEFP
+# include <cieeefp>
+#else
+# ifdef HAVE_IEEEFP_H
+#  include <ieeefp.h>
+# endif
+#endif
+
+bool CoinFinite(double val)
+{
+#ifdef COIN_C_FINITE
+    return COIN_C_FINITE(val)!=0;
+#else
+    return val != DBL_MAX && val != -DBL_MAX;
+#endif
+}
+
+bool CoinIsnan(double val)
+{
+#ifdef COIN_C_ISNAN
+    return COIN_C_ISNAN(val)!=0;
+#else
+    return false;
+#endif
+}
diff --git a/cbits/coin/CoinFinite.hpp b/cbits/coin/CoinFinite.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFinite.hpp
@@ -0,0 +1,34 @@
+/* $Id: CoinFinite.hpp 1423 2011-04-30 10:17:48Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/* Defines COIN_DBL_MAX and relatives and provides CoinFinite and CoinIsnan. */
+
+#ifndef CoinFinite_H
+#define CoinFinite_H
+
+#include <limits>
+
+//=============================================================================
+// Smallest positive double value and Plus infinity (double and int)
+
+#if 1
+const double COIN_DBL_MIN = std::numeric_limits<double>::min();
+const double COIN_DBL_MAX = std::numeric_limits<double>::max();
+const int    COIN_INT_MAX = std::numeric_limits<int>::max();
+const double COIN_INT_MAX_AS_DOUBLE = std::numeric_limits<int>::max();
+#else
+#define COIN_DBL_MIN (std::numeric_limits<double>::min())
+#define COIN_DBL_MAX (std::numeric_limits<double>::max())
+#define COIN_INT_MAX (std::numeric_limits<int>::max())
+#define COIN_INT_MAX_AS_DOUBLE (std::numeric_limits<int>::max())
+#endif
+
+/** checks if a double value is finite (not infinity and not NaN) */
+extern bool CoinFinite(double val);
+
+/** checks if a double value is not a number */
+extern bool CoinIsnan(double val);
+
+#endif
diff --git a/cbits/coin/CoinFloatEqual.hpp b/cbits/coin/CoinFloatEqual.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinFloatEqual.hpp
@@ -0,0 +1,177 @@
+/* $Id: CoinFloatEqual.hpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinFloatEqual_H
+#define CoinFloatEqual_H
+
+#include <algorithm>
+#include <cmath>
+
+#include "CoinFinite.hpp"
+
+/*! \file CoinFloatEqual.hpp
+    \brief Function objects for testing equality of real numbers.
+
+  Two objects are provided; one tests for equality to an absolute tolerance,
+  one to a scaled tolerance. The tests will handle IEEE floating point, but
+  note that infinity == infinity. Mathematicians are rolling in their graves,
+  but this matches the behaviour for the common practice of using
+  <code>DBL_MAX</code> (<code>numeric_limits<double>::max()</code>, or similar
+  large finite number) as infinity.
+
+  <p>
+  Example usage:
+  @verbatim
+    double d1 = 3.14159 ;
+    double d2 = d1 ;
+    double d3 = d1+.0001 ;
+
+    CoinAbsFltEq eq1 ;
+    CoinAbsFltEq eq2(.001) ;
+
+    assert(  eq1(d1,d2) ) ;
+    assert( !eq1(d1,d3) ) ;
+    assert(  eq2(d1,d3) ) ;
+  @endverbatim
+  CoinRelFltEq follows the same pattern.  */
+
+/*! \brief Equality to an absolute tolerance
+
+  Operands are considered equal if their difference is within an epsilon ;
+  the test does not consider the relative magnitude of the operands.
+*/
+
+class CoinAbsFltEq
+{
+  public:
+
+  //! Compare function
+
+  inline bool operator() (const double f1, const double f2) const
+
+  { if (CoinIsnan(f1) || CoinIsnan(f2)) return false ;
+    if (f1 == f2) return true ;
+    return (fabs(f1-f2) < epsilon_) ; } 
+
+  /*! \name Constructors and destructors */
+  //@{
+
+  /*! \brief Default constructor
+
+    Default tolerance is 1.0e-10.
+  */
+
+  CoinAbsFltEq () : epsilon_(1.e-10) {} 
+
+  //! Alternate constructor with epsilon as a parameter
+
+  CoinAbsFltEq (const double epsilon) : epsilon_(epsilon) {} 
+
+  //! Destructor
+
+  virtual ~CoinAbsFltEq () {} 
+
+  //! Copy constructor
+
+  CoinAbsFltEq (const CoinAbsFltEq& src) : epsilon_(src.epsilon_) {} 
+
+  //! Assignment
+
+  CoinAbsFltEq& operator= (const CoinAbsFltEq& rhs)
+
+  { if (this != &rhs) epsilon_ = rhs.epsilon_ ;
+    return (*this) ; } 
+
+  //@}
+
+  private:  
+
+  /*! \name Private member data */
+  //@{
+
+  //! Equality tolerance.
+
+  double epsilon_ ;
+
+  //@}
+
+} ;
+
+
+
+/*! \brief Equality to a scaled tolerance
+
+  Operands are considered equal if their difference is within a scaled
+  epsilon calculated as epsilon_*(1+CoinMax(|f1|,|f2|)).
+*/
+
+class CoinRelFltEq
+{
+  public:
+
+  //! Compare function
+
+  inline bool operator() (const double f1, const double f2) const
+
+  { if (CoinIsnan(f1) || CoinIsnan(f2)) return false ;
+    if (f1 == f2) return true ;
+    if (!CoinFinite(f1) || !CoinFinite(f2)) return false ;
+
+    double tol = (fabs(f1)>fabs(f2))?fabs(f1):fabs(f2) ;
+
+    return (fabs(f1-f2) <= epsilon_*(1+tol)) ; }
+
+  /*! \name Constructors and destructors */
+  //@{
+
+#ifndef COIN_FLOAT
+  /*! Default constructor
+
+    Default tolerance is 1.0e-10.
+  */
+  CoinRelFltEq () : epsilon_(1.e-10) {} 
+#else
+  /*! Default constructor
+
+    Default tolerance is 1.0e-6.
+  */
+  CoinRelFltEq () : epsilon_(1.e-6) {} ; // as float
+#endif
+
+  //! Alternate constructor with epsilon as a parameter
+
+  CoinRelFltEq (const double epsilon) : epsilon_(epsilon) {} 
+
+  //! Destructor
+
+  virtual ~CoinRelFltEq () {} 
+
+  //! Copy constructor
+
+  CoinRelFltEq (const CoinRelFltEq & src) : epsilon_(src.epsilon_) {} 
+
+  //! Assignment
+
+  CoinRelFltEq& operator= (const CoinRelFltEq& rhs)
+
+  { if (this != &rhs) epsilon_ = rhs.epsilon_ ;
+    return (*this) ; } 
+
+  //@}
+
+private: 
+
+  /*! \name Private member data */
+  //@{
+
+  //! Base equality tolerance
+
+  double epsilon_ ;
+
+  //@}
+
+} ;
+
+#endif
diff --git a/cbits/coin/CoinHelperFunctions.hpp b/cbits/coin/CoinHelperFunctions.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinHelperFunctions.hpp
@@ -0,0 +1,1109 @@
+/* $Id: CoinHelperFunctions.hpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinHelperFunctions_H
+#define CoinHelperFunctions_H
+
+#include "CoinUtilsConfig.h"
+
+#if defined(_MSC_VER)
+#  include <direct.h>
+#  define getcwd _getcwd
+#else
+#  include <unistd.h>
+#endif
+//#define USE_MEMCPY
+
+#include <cstdlib>
+#include <cstdio>
+#include <algorithm>
+#include "CoinTypes.hpp"
+#include "CoinError.hpp"
+
+// Compilers can produce better code if they know about __restrict
+#ifndef COIN_RESTRICT
+#ifdef COIN_USE_RESTRICT
+#define COIN_RESTRICT __restrict
+#else
+#define COIN_RESTRICT
+#endif
+#endif
+
+//#############################################################################
+
+/** This helper function copies an array to another location using Duff's
+    device (for a speedup of ~2). The arrays are given by pointers to their
+    first entries and by the size of the source array. Overlapping arrays are
+    handled correctly. */
+
+template <class T> inline void
+CoinCopyN(register const T* from, const int size, register T* to)
+{
+    if (size == 0 || from == to)
+	return;
+
+#ifndef NDEBUG
+    if (size < 0)
+	throw CoinError("trying to copy negative number of entries",
+			"CoinCopyN", "");
+#endif
+
+    register int n = (size + 7) / 8;
+    if (to > from) {
+	register const T* downfrom = from + size;
+	register T* downto = to + size;
+	// Use Duff's device to copy
+	switch (size % 8) {
+	case 0: do{     *--downto = *--downfrom;
+	case 7:         *--downto = *--downfrom;
+	case 6:         *--downto = *--downfrom;
+	case 5:         *--downto = *--downfrom;
+	case 4:         *--downto = *--downfrom;
+	case 3:         *--downto = *--downfrom;
+	case 2:         *--downto = *--downfrom;
+	case 1:         *--downto = *--downfrom;
+	}while(--n>0);
+	}
+    } else {
+	// Use Duff's device to copy
+	--from;
+	--to;
+	switch (size % 8) {
+	case 0: do{     *++to = *++from;
+	case 7:         *++to = *++from;
+	case 6:         *++to = *++from;
+	case 5:         *++to = *++from;
+	case 4:         *++to = *++from;
+	case 3:         *++to = *++from;
+	case 2:         *++to = *++from;
+	case 1:         *++to = *++from;
+	}while(--n>0);
+	}
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+/** This helper function copies an array to another location using Duff's
+    device (for a speedup of ~2). The source array is given by its first and
+    "after last" entry; the target array is given by its first entry.
+    Overlapping arrays are handled correctly.
+
+    All of the various CoinCopyN variants use an int for size. On 64-bit
+    architectures, the address diff last-first will be a 64-bit quantity.
+    Given that everything else uses an int, I'm going to choose to kick
+    the difference down to int.  -- lh, 100823 --
+*/
+template <class T> inline void
+CoinCopy(register const T* first, register const T* last, register T* to)
+{
+    CoinCopyN(first, static_cast<int>(last-first), to);
+}
+
+//-----------------------------------------------------------------------------
+
+/** This helper function copies an array to another location. The two arrays
+    must not overlap (otherwise an exception is thrown). For speed 8 entries
+    are copied at a time. The arrays are given by pointers to their first
+    entries and by the size of the source array. 
+
+    Note JJF - the speed claim seems to be false on IA32 so I have added 
+    CoinMemcpyN which can be used for atomic data */
+template <class T> inline void
+CoinDisjointCopyN(register const T* from, const int size, register T* to)
+{
+#ifndef _MSC_VER
+    if (size == 0 || from == to)
+	return;
+
+#ifndef NDEBUG
+    if (size < 0)
+	throw CoinError("trying to copy negative number of entries",
+			"CoinDisjointCopyN", "");
+#endif
+
+#if 0
+    /* There is no point to do this test. If to and from are from different
+       blocks then dist is undefined, so this can crash correct code. It's
+       better to trust the user that the arrays are really disjoint. */
+    const long dist = to - from;
+    if (-size < dist && dist < size)
+	throw CoinError("overlapping arrays", "CoinDisjointCopyN", "");
+#endif
+
+    for (register int n = size / 8; n > 0; --n, from += 8, to += 8) {
+	to[0] = from[0];
+	to[1] = from[1];
+	to[2] = from[2];
+	to[3] = from[3];
+	to[4] = from[4];
+	to[5] = from[5];
+	to[6] = from[6];
+	to[7] = from[7];
+    }
+    switch (size % 8) {
+    case 7: to[6] = from[6];
+    case 6: to[5] = from[5];
+    case 5: to[4] = from[4];
+    case 4: to[3] = from[3];
+    case 3: to[2] = from[2];
+    case 2: to[1] = from[1];
+    case 1: to[0] = from[0];
+    case 0: break;
+    }
+#else
+    CoinCopyN(from, size, to);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+
+/** This helper function copies an array to another location. The two arrays
+    must not overlap (otherwise an exception is thrown). For speed 8 entries
+    are copied at a time. The source array is given by its first and "after
+    last" entry; the target array is given by its first entry. */
+template <class T> inline void
+CoinDisjointCopy(register const T* first, register const T* last,
+		 register T* to)
+{
+    CoinDisjointCopyN(first, static_cast<int>(last - first), to);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! \brief Return an array of length \p size filled with input from \p array,
+  or null if \p array is null.
+*/
+
+template <class T> inline T*
+CoinCopyOfArray( const T * array, const int size)
+{
+    if (array) {
+	T * arrayNew = new T[size];
+	std::memcpy(arrayNew,array,size*sizeof(T));
+	return arrayNew;
+    } else {
+	return NULL;
+    }
+}
+
+
+/*! \brief Return an array of length \p size filled with first copySize from \p array,
+  or null if \p array is null.
+*/
+
+template <class T> inline T*
+CoinCopyOfArrayPartial( const T * array, const int size,const int copySize)
+{
+    if (array||size) {
+	T * arrayNew = new T[size];
+	assert (copySize<=size);
+	std::memcpy(arrayNew,array,copySize*sizeof(T));
+	return arrayNew;
+    } else {
+	return NULL;
+    }
+}
+
+/*! \brief Return an array of length \p size filled with input from \p array,
+  or filled with (scalar) \p value if \p array is null
+*/
+
+template <class T> inline T*
+CoinCopyOfArray( const T * array, const int size, T value)
+{
+    T * arrayNew = new T[size];
+    if (array) {
+        std::memcpy(arrayNew,array,size*sizeof(T));
+    } else {
+	int i;
+	for (i=0;i<size;i++) 
+	    arrayNew[i] = value;
+    }
+    return arrayNew;
+}
+
+
+/*! \brief Return an array of length \p size filled with input from \p array,
+  or filled with zero if \p array is null
+*/
+
+template <class T> inline T*
+CoinCopyOfArrayOrZero( const T * array , const int size)
+{
+    T * arrayNew = new T[size];
+    if (array) {
+      std::memcpy(arrayNew,array,size*sizeof(T));
+    } else {
+      std::memset(arrayNew,0,size*sizeof(T));
+    }
+    return arrayNew;
+}
+
+
+//-----------------------------------------------------------------------------
+
+/** This helper function copies an array to another location. The two arrays
+    must not overlap (otherwise an exception is thrown). For speed 8 entries
+    are copied at a time. The arrays are given by pointers to their first
+    entries and by the size of the source array. 
+
+    Note JJF - the speed claim seems to be false on IA32 so I have added 
+    alternative coding if USE_MEMCPY defined*/
+#ifndef COIN_USE_RESTRICT
+template <class T> inline void
+CoinMemcpyN(register const T* from, const int size, register T* to)
+{
+#ifndef _MSC_VER
+#ifdef USE_MEMCPY
+    // Use memcpy - seems a lot faster on Intel with gcc
+#ifndef NDEBUG
+    // Some debug so check
+    if (size < 0)
+	throw CoinError("trying to copy negative number of entries",
+			"CoinMemcpyN", "");
+  
+#if 0
+    /* There is no point to do this test. If to and from are from different
+       blocks then dist is undefined, so this can crash correct code. It's
+       better to trust the user that the arrays are really disjoint. */
+    const long dist = to - from;
+    if (-size < dist && dist < size)
+	throw CoinError("overlapping arrays", "CoinMemcpyN", "");
+#endif
+#endif
+    std::memcpy(to,from,size*sizeof(T));
+#else
+    if (size == 0 || from == to)
+	return;
+
+#ifndef NDEBUG
+    if (size < 0)
+	throw CoinError("trying to copy negative number of entries",
+			"CoinMemcpyN", "");
+#endif
+
+#if 0
+    /* There is no point to do this test. If to and from are from different
+       blocks then dist is undefined, so this can crash correct code. It's
+       better to trust the user that the arrays are really disjoint. */
+    const long dist = to - from;
+    if (-size < dist && dist < size)
+	throw CoinError("overlapping arrays", "CoinMemcpyN", "");
+#endif
+
+    for (register int n = size / 8; n > 0; --n, from += 8, to += 8) {
+	to[0] = from[0];
+	to[1] = from[1];
+	to[2] = from[2];
+	to[3] = from[3];
+	to[4] = from[4];
+	to[5] = from[5];
+	to[6] = from[6];
+	to[7] = from[7];
+    }
+    switch (size % 8) {
+    case 7: to[6] = from[6];
+    case 6: to[5] = from[5];
+    case 5: to[4] = from[4];
+    case 4: to[3] = from[3];
+    case 3: to[2] = from[2];
+    case 2: to[1] = from[1];
+    case 1: to[0] = from[0];
+    case 0: break;
+    }
+#endif
+#else
+    CoinCopyN(from, size, to);
+#endif
+}
+#else
+template <class T> inline void
+CoinMemcpyN(const T * COIN_RESTRICT from, int size, T* COIN_RESTRICT to)
+{
+#ifdef USE_MEMCPY
+  std::memcpy(to,from,size*sizeof(T));
+#else
+  T * COIN_RESTRICT put =  to;
+  const T * COIN_RESTRICT get = from;
+  for ( ; 0<size ; --size)
+    *put++ = *get++;
+#endif
+}
+#endif
+
+//-----------------------------------------------------------------------------
+
+/** This helper function copies an array to another location. The two arrays
+    must not overlap (otherwise an exception is thrown). For speed 8 entries
+    are copied at a time. The source array is given by its first and "after
+    last" entry; the target array is given by its first entry. */
+template <class T> inline void
+CoinMemcpy(register const T* first, register const T* last,
+	   register T* to)
+{
+    CoinMemcpyN(first, static_cast<int>(last - first), to);
+}
+
+//#############################################################################
+
+/** This helper function fills an array with a given value. For speed 8 entries
+    are filled at a time. The array is given by a pointer to its first entry
+    and its size. 
+
+    Note JJF - the speed claim seems to be false on IA32 so I have added 
+    CoinZero to allow for memset. */
+template <class T> inline void
+CoinFillN(register T* to, const int size, register const T value)
+{
+    if (size == 0)
+	return;
+
+#ifndef NDEBUG
+    if (size < 0)
+	throw CoinError("trying to fill negative number of entries",
+			"CoinFillN", "");
+#endif
+#if 1
+    for (register int n = size / 8; n > 0; --n, to += 8) {
+	to[0] = value;
+	to[1] = value;
+	to[2] = value;
+	to[3] = value;
+	to[4] = value;
+	to[5] = value;
+	to[6] = value;
+	to[7] = value;
+    }
+    switch (size % 8) {
+    case 7: to[6] = value;
+    case 6: to[5] = value;
+    case 5: to[4] = value;
+    case 4: to[3] = value;
+    case 3: to[2] = value;
+    case 2: to[1] = value;
+    case 1: to[0] = value;
+    case 0: break;
+    }
+#else
+    // Use Duff's device to fill
+    register int n = (size + 7) / 8;
+    --to;
+    switch (size % 8) {
+    case 0: do{     *++to = value;
+    case 7:         *++to = value;
+    case 6:         *++to = value;
+    case 5:         *++to = value;
+    case 4:         *++to = value;
+    case 3:         *++to = value;
+    case 2:         *++to = value;
+    case 1:         *++to = value;
+    }while(--n>0);
+    }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+
+/** This helper function fills an array with a given value. For speed 8
+    entries are filled at a time. The array is given by its first and "after
+    last" entry. */
+template <class T> inline void
+CoinFill(register T* first, register T* last, const T value)
+{
+    CoinFillN(first, last - first, value);
+}
+
+//#############################################################################
+
+/** This helper function fills an array with zero. For speed 8 entries
+    are filled at a time. The array is given by a pointer to its first entry
+    and its size.
+
+    Note JJF - the speed claim seems to be false on IA32 so I have allowed 
+    for memset as an alternative */
+template <class T> inline void
+CoinZeroN(register T* to, const int size)
+{
+#ifdef USE_MEMCPY
+    // Use memset - seems faster on Intel with gcc
+#ifndef NDEBUG
+    // Some debug so check
+    if (size < 0)
+	throw CoinError("trying to fill negative number of entries",
+			"CoinZeroN", "");
+#endif
+    memset(to,0,size*sizeof(T));
+#else
+    if (size == 0)
+	return;
+
+#ifndef NDEBUG
+    if (size < 0)
+	throw CoinError("trying to fill negative number of entries",
+			"CoinZeroN", "");
+#endif
+#if 1
+    for (register int n = size / 8; n > 0; --n, to += 8) {
+	to[0] = 0;
+	to[1] = 0;
+	to[2] = 0;
+	to[3] = 0;
+	to[4] = 0;
+	to[5] = 0;
+	to[6] = 0;
+	to[7] = 0;
+    }
+    switch (size % 8) {
+    case 7: to[6] = 0;
+    case 6: to[5] = 0;
+    case 5: to[4] = 0;
+    case 4: to[3] = 0;
+    case 3: to[2] = 0;
+    case 2: to[1] = 0;
+    case 1: to[0] = 0;
+    case 0: break;
+    }
+#else
+    // Use Duff's device to fill
+    register int n = (size + 7) / 8;
+    --to;
+    switch (size % 8) {
+    case 0: do{     *++to = 0;
+    case 7:         *++to = 0;
+    case 6:         *++to = 0;
+    case 5:         *++to = 0;
+    case 4:         *++to = 0;
+    case 3:         *++to = 0;
+    case 2:         *++to = 0;
+    case 1:         *++to = 0;
+    }while(--n>0);
+    }
+#endif
+#endif
+}
+/// This Debug helper function checks an array is all zero
+inline void
+CoinCheckDoubleZero(double * to, const int size)
+{
+    int n=0;
+    for (int j=0;j<size;j++) {
+	if (to[j]) 
+	    n++;
+    }
+    if (n) {
+	printf("array of length %d should be zero has %d nonzero\n",size,n);
+    }
+}
+/// This Debug helper function checks an array is all zero
+inline void
+CoinCheckIntZero(int * to, const int size)
+{
+    int n=0;
+    for (int j=0;j<size;j++) {
+	if (to[j]) 
+	    n++;
+    }
+    if (n) {
+	printf("array of length %d should be zero has %d nonzero\n",size,n);
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+/** This helper function fills an array with a given value. For speed 8
+    entries are filled at a time. The array is given by its first and "after
+    last" entry. */
+template <class T> inline void
+CoinZero(register T* first, register T* last)
+{
+    CoinZeroN(first, last - first);
+}
+
+//#############################################################################
+
+/** Returns strdup or NULL if original NULL */
+inline char * CoinStrdup(const char * name)
+{
+  char* dup = NULL;
+  if (name) {
+    const int len = static_cast<int>(strlen(name));
+    dup = static_cast<char*>(malloc(len+1));
+    CoinMemcpyN(name, len, dup);
+    dup[len] = 0;
+  }
+  return dup;
+}
+
+//#############################################################################
+
+/** Return the larger (according to <code>operator<()</code> of the arguments.
+    This function was introduced because for some reason compiler tend to
+    handle the <code>max()</code> function differently. */
+template <class T> inline T
+CoinMax(register const T x1, register const T x2)
+{
+    return (x1 > x2) ? x1 : x2;
+}
+
+//-----------------------------------------------------------------------------
+
+/** Return the smaller (according to <code>operator<()</code> of the arguments.
+    This function was introduced because for some reason compiler tend to
+    handle the min() function differently. */
+template <class T> inline T
+CoinMin(register const T x1, register const T x2)
+{
+    return (x1 < x2) ? x1 : x2;
+}
+
+//-----------------------------------------------------------------------------
+
+/** Return the absolute value of the argument. This function was introduced
+    because for some reason compiler tend to handle the abs() function
+    differently. */
+template <class T> inline T
+CoinAbs(const T value)
+{
+    return value<0 ? -value : value;
+}
+
+//#############################################################################
+
+/** This helper function tests whether the entries of an array are sorted
+    according to operator<. The array is given by a pointer to its first entry
+    and by its size. */
+template <class T> inline bool
+CoinIsSorted(register const T* first, const int size)
+{
+    if (size == 0)
+	return true;
+
+#ifndef NDEBUG
+    if (size < 0)
+	throw CoinError("negative number of entries", "CoinIsSorted", "");
+#endif
+#if 1
+    // size1 is the number of comparisons to be made
+    const int size1 = size  - 1;
+    for (register int n = size1 / 8; n > 0; --n, first += 8) {
+	if (first[8] < first[7]) return false;
+	if (first[7] < first[6]) return false;
+	if (first[6] < first[5]) return false;
+	if (first[5] < first[4]) return false;
+	if (first[4] < first[3]) return false;
+	if (first[3] < first[2]) return false;
+	if (first[2] < first[1]) return false;
+	if (first[1] < first[0]) return false;
+    }
+
+    switch (size1 % 8) {
+    case 7: if (first[7] < first[6]) return false;
+    case 6: if (first[6] < first[5]) return false;
+    case 5: if (first[5] < first[4]) return false;
+    case 4: if (first[4] < first[3]) return false;
+    case 3: if (first[3] < first[2]) return false;
+    case 2: if (first[2] < first[1]) return false;
+    case 1: if (first[1] < first[0]) return false;
+    case 0: break;
+    }
+#else
+    register const T* next = first;
+    register const T* last = first + size;
+    for (++next; next != last; first = next, ++next)
+	if (*next < *first)
+	    return false;
+#endif   
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+/** This helper function tests whether the entries of an array are sorted
+    according to operator<. The array is given by its first and "after
+    last" entry. */
+template <class T> inline bool
+CoinIsSorted(register const T* first, register const T* last)
+{
+    return CoinIsSorted(first, static_cast<int>(last - first));
+}
+
+//#############################################################################
+
+/** This helper function fills an array with the values init, init+1, init+2,
+    etc. For speed 8 entries are filled at a time. The array is given by a
+    pointer to its first entry and its size. */
+template <class T> inline void
+CoinIotaN(register T* first, const int size, register T init)
+{
+    if (size == 0)
+	return;
+
+#ifndef NDEBUG
+    if (size < 0)
+	throw CoinError("negative number of entries", "CoinIotaN", "");
+#endif
+#if 1
+    for (register int n = size / 8; n > 0; --n, first += 8, init += 8) {
+	first[0] = init;
+	first[1] = init + 1;
+	first[2] = init + 2;
+	first[3] = init + 3;
+	first[4] = init + 4;
+	first[5] = init + 5;
+	first[6] = init + 6;
+	first[7] = init + 7;
+    }
+    switch (size % 8) {
+    case 7: first[6] = init + 6;
+    case 6: first[5] = init + 5;
+    case 5: first[4] = init + 4;
+    case 4: first[3] = init + 3;
+    case 3: first[2] = init + 2;
+    case 2: first[1] = init + 1;
+    case 1: first[0] = init;
+    case 0: break;
+    }
+#else
+    // Use Duff's device to fill
+    register int n = (size + 7) / 8;
+    --first;
+    --init;
+    switch (size % 8) {
+    case 0: do{     *++first = ++init;
+    case 7:         *++first = ++init;
+    case 6:         *++first = ++init;
+    case 5:         *++first = ++init;
+    case 4:         *++first = ++init;
+    case 3:         *++first = ++init;
+    case 2:         *++first = ++init;
+    case 1:         *++first = ++init;
+    }while(--n>0);
+    }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+
+/** This helper function fills an array with the values init, init+1, init+2,
+    etc. For speed 8 entries are filled at a time. The array is given by its
+    first and "after last" entry. */
+template <class T> inline void
+CoinIota(T* first, const T* last, T init)
+{
+    CoinIotaN(first, last-first, init);
+}
+
+//#############################################################################
+
+/** This helper function deletes certain entries from an array. The array is
+    given by pointers to its first and "after last" entry (first two
+    arguments). The positions of the entries to be deleted are given in the
+    integer array specified by the last two arguments (again, first and "after
+    last" entry). */
+template <class T> inline T *
+CoinDeleteEntriesFromArray(register T * arrayFirst, register T * arrayLast,
+			   const int * firstDelPos, const int * lastDelPos)
+{
+    int delNum = static_cast<int>(lastDelPos - firstDelPos);
+    if (delNum == 0)
+	return arrayLast;
+
+    if (delNum < 0)
+	throw CoinError("trying to delete negative number of entries",
+			"CoinDeleteEntriesFromArray", "");
+
+    int * delSortedPos = NULL;
+    if (! (CoinIsSorted(firstDelPos, lastDelPos) &&
+	   std::adjacent_find(firstDelPos, lastDelPos) == lastDelPos)) {
+	// the positions of the to be deleted is either not sorted or not unique
+	delSortedPos = new int[delNum];
+	CoinDisjointCopy(firstDelPos, lastDelPos, delSortedPos);
+	std::sort(delSortedPos, delSortedPos + delNum);
+	delNum = static_cast<int>(std::unique(delSortedPos,
+				  delSortedPos+delNum) - delSortedPos);
+    }
+    const int * delSorted = delSortedPos ? delSortedPos : firstDelPos;
+
+    const int last = delNum - 1;
+    int size = delSorted[0];
+    for (int i = 0; i < last; ++i) {
+	const int copyFirst = delSorted[i] + 1;
+	const int copyLast = delSorted[i+1];
+	CoinCopy(arrayFirst + copyFirst, arrayFirst + copyLast,
+		 arrayFirst + size);
+	size += copyLast - copyFirst;
+    }
+    const int copyFirst = delSorted[last] + 1;
+    const int copyLast = static_cast<int>(arrayLast - arrayFirst);
+    CoinCopy(arrayFirst + copyFirst, arrayFirst + copyLast,
+	     arrayFirst + size);
+    size += copyLast - copyFirst;
+
+    if (delSortedPos)
+	delete[] delSortedPos;
+
+    return arrayFirst + size;
+}
+
+//#############################################################################
+
+#define COIN_OWN_RANDOM_32
+
+#if defined COIN_OWN_RANDOM_32
+/* Thanks to Stefano Gliozzi for providing an operating system
+   independent random number generator.  */
+
+/*! \brief Return a random number between 0 and 1
+
+  A platform-independent linear congruential generator. For a given seed, the
+  generated sequence is always the same regardless of the (32-bit)
+  architecture. This allows to build & test in different environments, getting
+  in most cases the same optimization path.
+
+  Set \p isSeed to true and supply an integer seed to set the seed
+  (vid. #CoinSeedRandom)
+
+  \todo Anyone want to volunteer an upgrade for 64-bit architectures?
+*/
+inline double CoinDrand48 (bool isSeed = false, unsigned int seed = 1)
+{
+  static unsigned int last = 123456;
+  if (isSeed) { 
+    last = seed;
+  } else {
+    last = 1664525*last+1013904223;
+    return ((static_cast<double> (last))/4294967296.0);
+  }
+  return (0.0);
+}
+
+/// Set the seed for the random number generator
+inline void CoinSeedRandom(int iseed)
+{
+  CoinDrand48(true, iseed);
+}
+
+#else // COIN_OWN_RANDOM_32
+
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN32__)
+
+/// Return a random number between 0 and 1
+inline double CoinDrand48() { return rand() / (double) RAND_MAX; }
+/// Set the seed for the random number generator
+inline void CoinSeedRandom(int iseed) { srand(iseed + 69822); }
+
+#else
+
+/// Return a random number between 0 and 1
+inline double CoinDrand48() { return drand48(); }
+/// Set the seed for the random number generator
+inline void CoinSeedRandom(int iseed) { srand48(iseed + 69822); }
+
+#endif
+
+#endif // COIN_OWN_RANDOM_32
+
+//#############################################################################
+
+/** This function figures out whether file names should contain slashes or 
+    backslashes as directory separator */
+inline char CoinFindDirSeparator()
+{
+    int size = 1000;
+    char* buf = 0;
+    while (true) {
+	buf = new char[size];
+	if (getcwd(buf, size))
+	    break;
+	delete[] buf;
+	buf = 0;
+	size = 2*size;
+    }
+    // if first char is '/' then it's unix and the dirsep is '/'. otherwise we 
+    // assume it's dos and the dirsep is '\'
+    char dirsep = buf[0] == '/' ? '/' : '\\';
+    delete[] buf;
+    return dirsep;
+}
+//#############################################################################
+
+inline int CoinStrNCaseCmp(const char* s0, const char* s1,
+			   const size_t len)
+{
+    for (size_t i = 0; i < len; ++i) {
+	if (s0[i] == 0) {
+	    return s1[i] == 0 ? 0 : -1;
+	}
+	if (s1[i] == 0) {
+	    return 1;
+	}
+	const int c0 = tolower(s0[i]);
+	const int c1 = tolower(s1[i]);
+	if (c0 < c1)
+	    return -1;
+	if (c0 > c1)
+	    return 1;
+    }
+    return 0;
+}
+
+//#############################################################################
+
+/// Swap the arguments.
+template <class T> inline void CoinSwap (T &x, T &y)
+{
+    T t = x;
+    x = y;
+    y = t;
+}
+
+//#############################################################################
+
+/** This helper function copies an array to file 
+    Returns 0 if OK, 1 if bad write.
+*/
+
+template <class T> inline int
+CoinToFile( const T* array, CoinBigIndex size, FILE * fp)
+{
+    CoinBigIndex numberWritten;
+    if (array&&size) {
+	numberWritten =
+	    static_cast<CoinBigIndex>(fwrite(&size,sizeof(int),1,fp));
+	if (numberWritten!=1)
+	    return 1;
+	numberWritten =
+	    static_cast<CoinBigIndex>(fwrite(array,sizeof(T),size_t(size),fp));
+	if (numberWritten!=size)
+	    return 1;
+    } else {
+	size = 0;
+	numberWritten = 
+	    static_cast<CoinBigIndex>(fwrite(&size,sizeof(int),1,fp));
+	if (numberWritten!=1)
+	    return 1;
+    }
+    return 0;
+}
+
+//#############################################################################
+
+/** This helper function copies an array from file and creates with new.
+    Passed in array is ignored i.e. not deleted.
+    But if NULL and size does not match and newSize 0 then leaves as NULL and 0
+    Returns 0 if OK, 1 if bad read, 2 if size did not match.
+*/
+
+template <class T> inline int
+CoinFromFile( T* &array, CoinBigIndex size, FILE * fp, CoinBigIndex & newSize)
+{
+    CoinBigIndex numberRead;
+    numberRead =
+        static_cast<CoinBigIndex>(fread(&newSize,sizeof(int),1,fp));
+    if (numberRead!=1)
+	return 1;
+    int returnCode=0;
+    if (size!=newSize&&(newSize||array))
+	returnCode=2;
+    if (newSize) {
+	array = new T [newSize];
+	numberRead =
+	    static_cast<CoinBigIndex>(fread(array,sizeof(T),newSize,fp));
+	if (numberRead!=newSize)
+	    returnCode=1;
+    } else {
+	array = NULL;
+    }
+    return returnCode;
+}
+
+//#############################################################################
+
+/// Cube Root
+#if 0
+inline double CoinCbrt(double x)
+{
+#if defined(_MSC_VER) 
+    return pow(x,(1./3.));
+#else
+    return cbrt(x);
+#endif
+}
+#endif
+
+//-----------------------------------------------------------------------------
+
+/// This helper returns "sizeof" as an int 
+#define CoinSizeofAsInt(type) (static_cast<int>(sizeof(type)))
+/// This helper returns "strlen" as an int 
+inline int
+CoinStrlenAsInt(const char * string)
+{
+    return static_cast<int>(strlen(string));
+}
+
+/** Class for thread specific random numbers
+*/
+#if defined COIN_OWN_RANDOM_32
+class CoinThreadRandom  {
+public:
+  /**@name Constructors, destructor */
+
+  //@{
+  /** Default constructor. */
+  CoinThreadRandom()
+  { seed_=12345678;}
+  /** Constructor wih seed. */
+  CoinThreadRandom(int seed)
+  { 
+    seed_ = seed;
+  }
+  /** Destructor */
+  ~CoinThreadRandom() {}
+  // Copy
+  CoinThreadRandom(const CoinThreadRandom & rhs)
+  { seed_ = rhs.seed_;}
+  // Assignment
+  CoinThreadRandom& operator=(const CoinThreadRandom & rhs)
+  {
+    if (this != &rhs) {
+      seed_ = rhs.seed_;
+    }
+    return *this;
+  }
+
+  //@}
+  
+  /**@name Sets/gets */
+
+  //@{
+  /** Set seed. */
+  inline void setSeed(int seed)
+  { 
+    seed_ = seed;
+  }
+  /** Get seed. */
+  inline unsigned int getSeed() const
+  { 
+    return seed_;
+  }
+  /// return a random number
+  inline double randomDouble() const
+  {
+    double retVal;
+    seed_ = 1664525*(seed_)+1013904223;
+    retVal = ((static_cast<double> (seed_))/4294967296.0);
+    return retVal;
+  }
+  /// make more random (i.e. for startup)
+  inline void randomize(int n=0)
+  {
+    if (!n) 
+      n=seed_ & 255;
+    for (int i=0;i<n;i++)
+      randomDouble();
+  }
+  //@}
+  
+  
+protected:
+  /**@name Data members
+     The data members are protected to allow access for derived classes. */
+  //@{
+  /// Current seed
+  mutable unsigned int seed_;
+  //@}
+};
+#else
+class CoinThreadRandom  {
+public:
+  /**@name Constructors, destructor */
+
+  //@{
+  /** Default constructor. */
+  CoinThreadRandom()
+  { seed_[0]=50000;seed_[1]=40000;seed_[2]=30000;}
+  /** Constructor wih seed. */
+  CoinThreadRandom(const unsigned short seed[3])
+  { memcpy(seed_,seed,3*sizeof(unsigned short));}
+  /** Constructor wih seed. */
+  CoinThreadRandom(int seed)
+  { 
+    union { int i[2]; unsigned short int s[4];} put;
+    put.i[0]=seed;
+    put.i[1]=seed;
+    memcpy(seed_,put.s,3*sizeof(unsigned short));
+  }
+  /** Destructor */
+  ~CoinThreadRandom() {}
+  // Copy
+  CoinThreadRandom(const CoinThreadRandom & rhs)
+  { memcpy(seed_,rhs.seed_,3*sizeof(unsigned short));}
+  // Assignment
+  CoinThreadRandom& operator=(const CoinThreadRandom & rhs)
+  {
+    if (this != &rhs) {
+      memcpy(seed_,rhs.seed_,3*sizeof(unsigned short));
+    }
+    return *this;
+  }
+
+  //@}
+  
+  /**@name Sets/gets */
+
+  //@{
+  /** Set seed. */
+  inline void setSeed(const unsigned short seed[3])
+  { memcpy(seed_,seed,3*sizeof(unsigned short));}
+  /** Set seed. */
+  inline void setSeed(int seed)
+  { 
+    union { int i[2]; unsigned short int s[4];} put;
+    put.i[0]=seed;
+    put.i[1]=seed;
+    memcpy(seed_,put.s,3*sizeof(unsigned short));
+  }
+  /// return a random number
+  inline double randomDouble() const
+  {
+    double retVal;
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN32__)
+    retVal=rand();
+    retVal=retVal/(double) RAND_MAX;
+#else
+    retVal = erand48(seed_);
+#endif
+    return retVal;
+  }
+  /// make more random (i.e. for startup)
+  inline void randomize(int n=0)
+  {
+    if (!n) {
+      n=seed_[0]+seed_[1]+seed_[2];
+      n &= 255;
+    }
+    for (int i=0;i<n;i++)
+      randomDouble();
+  }
+  //@}
+  
+  
+protected:
+  /**@name Data members
+     The data members are protected to allow access for derived classes. */
+  //@{
+  /// Current seed
+  mutable unsigned short seed_[3];
+  //@}
+};
+#endif
+#ifndef COIN_DETAIL
+#define COIN_DETAIL_PRINT(s) {}
+#else
+#define COIN_DETAIL_PRINT(s) s
+#endif
+#endif
diff --git a/cbits/coin/CoinIndexedVector.cpp b/cbits/coin/CoinIndexedVector.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinIndexedVector.cpp
@@ -0,0 +1,2312 @@
+/* $Id: CoinIndexedVector.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+  
+#include <cassert>
+#include <cstdio>
+
+#include "CoinTypes.hpp"
+#include "CoinFloatEqual.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinTypes.hpp"
+//#############################################################################
+#define WARN_USELESS 0
+void
+CoinIndexedVector::clear()
+{
+#if WARN_USELESS
+  int nNonZero=0;
+  for (int i=0;i<capacity_;i++) {
+    if(elements_[i])
+      nNonZero++;
+  }
+  assert (nNonZero<=nElements_);
+#if WARN_USELESS>1
+  if (nNonZero!=nElements_)
+    printf("Vector said it had %d nonzeros - only had %d\n",
+	   nElements_,nNonZero);
+#endif
+  if (!nNonZero&&nElements_)
+    printf("Vector said it had %d nonzeros - but is already empty\n",
+	   nElements_);
+#endif
+  if (!packedMode_) {
+    if (3*nElements_<capacity_) {
+      int i=0;
+      if ((nElements_&1)!=0) {
+	elements_[indices_[0]]=0.0;
+	i=1;
+      }
+      for (;i<nElements_;i+=2) {
+	int i0 = indices_[i];
+	int i1 = indices_[i+1];
+	elements_[i0]=0.0;
+	elements_[i1]=0.0;
+      }
+    } else {
+      CoinZeroN(elements_,capacity_);
+    }
+  } else {
+    CoinZeroN(elements_,nElements_);
+  }
+  nElements_ = 0;
+  packedMode_=false;
+  //checkClear();
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::empty()
+{
+  delete [] indices_;
+  indices_=NULL;
+  if (elements_)
+    delete [] (elements_-offset_);
+  elements_=NULL;
+  nElements_ = 0;
+  capacity_=0;
+  packedMode_=false;
+}
+
+//#############################################################################
+
+CoinIndexedVector &
+CoinIndexedVector::operator=(const CoinIndexedVector & rhs)
+{
+  if (this != &rhs) {
+    clear();
+    packedMode_=rhs.packedMode_;
+    if (!packedMode_)
+      gutsOfSetVector(rhs.capacity_,rhs.nElements_, 
+		      rhs.indices_, rhs.elements_);
+    else
+      gutsOfSetPackedVector(rhs.capacity_,rhs.nElements_, 
+		      rhs.indices_, rhs.elements_);
+  }
+  return *this;
+}
+/* Copy the contents of one vector into another.  If multiplier is 1
+   It is the equivalent of = but if vectors are same size does
+   not re-allocate memory just clears and copies */
+void 
+CoinIndexedVector::copy(const CoinIndexedVector & rhs, double multiplier)
+{
+  if (capacity_==rhs.capacity_) {
+    // can do fast
+    clear();
+    packedMode_=rhs.packedMode_;
+    nElements_=0;
+    if (!packedMode_) {
+      for (int i=0;i<rhs.nElements_;i++) {
+        int index = rhs.indices_[i];
+        double value = rhs.elements_[index]*multiplier;
+        if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) 
+          value = COIN_INDEXED_REALLY_TINY_ELEMENT;
+        elements_[index]=value;
+        indices_[nElements_++]=index;
+      }
+    } else {
+      for (int i=0;i<rhs.nElements_;i++) {
+        int index = rhs.indices_[i];
+        double value = rhs.elements_[i]*multiplier;
+        if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) 
+          value = COIN_INDEXED_REALLY_TINY_ELEMENT;
+        elements_[nElements_]=value;
+        indices_[nElements_++]=index;
+      }
+    }
+  } else {
+    // do as two operations
+    *this = rhs;
+    (*this) *= multiplier;
+  }
+}
+
+//#############################################################################
+#ifndef CLP_NO_VECTOR
+CoinIndexedVector &
+CoinIndexedVector::operator=(const CoinPackedVectorBase & rhs)
+{
+  clear();
+  packedMode_=false;
+  gutsOfSetVector(rhs.getNumElements(), 
+			    rhs.getIndices(), rhs.getElements());
+  return *this;
+}
+#endif
+//#############################################################################
+
+void
+CoinIndexedVector::borrowVector(int size, int numberIndices, int* inds, double* elems)
+{
+  empty();
+  capacity_=size;
+  nElements_ = numberIndices;
+  indices_ = inds;  
+  elements_ = elems;
+  
+  // whole point about borrowvector is that it is lightweight so no testing is done
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::returnVector()
+{
+  indices_=NULL;
+  elements_=NULL;
+  nElements_ = 0;
+  capacity_=0;
+  packedMode_=false;
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::setVector(int size, const int * inds, const double * elems)
+{
+  clear();
+  gutsOfSetVector(size, inds, elems);
+}
+//#############################################################################
+
+
+void 
+CoinIndexedVector::setVector(int size, int numberIndices, const int * inds, const double * elems)
+{
+  clear();
+  gutsOfSetVector(size, numberIndices, inds, elems);
+}
+//#############################################################################
+
+void
+CoinIndexedVector::setConstant(int size, const int * inds, double value)
+{
+  clear();
+  gutsOfSetConstant(size, inds, value);
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::setFull(int size, const double * elems)
+{
+  // Clear out any values presently stored
+  clear();
+  
+#ifndef COIN_FAST_CODE
+  if (size<0)
+    throw CoinError("negative number of indices", "setFull", "CoinIndexedVector");
+#endif
+  reserve(size);
+  nElements_ = 0;
+  // elements_ array is all zero
+  int i;
+  for (i=0;i<size;i++) {
+    int indexValue=i;
+    if (fabs(elems[i])>=COIN_INDEXED_TINY_ELEMENT) {
+      elements_[indexValue]=elems[i];
+      indices_[nElements_++]=indexValue;
+    }
+  }
+}
+//#############################################################################
+
+/** Access the i'th element of the full storage vector.  */
+double &
+CoinIndexedVector::operator[](int index) const
+{
+  assert (!packedMode_);
+#ifndef COIN_FAST_CODE
+  if ( index >= capacity_ ) 
+    throw CoinError("index >= capacity()", "[]", "CoinIndexedVector");
+  if ( index < 0 ) 
+    throw CoinError("index < 0" , "[]", "CoinIndexedVector");
+#endif
+  double * where = elements_ + index;
+  return *where;
+  
+}
+//#############################################################################
+
+void
+CoinIndexedVector::setElement(int index, double element)
+{
+#ifndef COIN_FAST_CODE
+  if ( index >= nElements_ ) 
+    throw CoinError("index >= size()", "setElement", "CoinIndexedVector");
+  if ( index < 0 ) 
+    throw CoinError("index < 0" , "setElement", "CoinIndexedVector");
+#endif
+  elements_[indices_[index]] = element;
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::insert( int index, double element )
+{
+#ifndef COIN_FAST_CODE
+  if ( index < 0 ) 
+    throw CoinError("index < 0" , "setElement", "CoinIndexedVector");
+#endif
+  if (index >= capacity_)
+    reserve(index+1);
+#ifndef COIN_FAST_CODE
+  if (elements_[index])
+    throw CoinError("Index already exists", "insert", "CoinIndexedVector");
+#endif
+  indices_[nElements_++] = index;
+  elements_[index] = element;
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::add( int index, double element )
+{
+#ifndef COIN_FAST_CODE
+  if ( index < 0 ) 
+    throw CoinError("index < 0" , "setElement", "CoinIndexedVector");
+#endif
+  if (index >= capacity_)
+    reserve(index+1);
+  if (elements_[index]) {
+    element += elements_[index];
+    if (fabs(element)>= COIN_INDEXED_TINY_ELEMENT) {
+      elements_[index] = element;
+    } else {
+      elements_[index] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+    }
+  } else if (fabs(element)>= COIN_INDEXED_TINY_ELEMENT) {
+    indices_[nElements_++] = index;
+    assert (nElements_<=capacity_);
+    elements_[index] = element;
+   }
+}
+
+//#############################################################################
+
+int
+CoinIndexedVector::clean( double tolerance )
+{
+  int number = nElements_;
+  int i;
+  nElements_=0;
+  assert(!packedMode_);
+  for (i=0;i<number;i++) {
+    int indexValue = indices_[i];
+    if (fabs(elements_[indexValue])>=tolerance) {
+      indices_[nElements_++]=indexValue;
+    } else {
+      elements_[indexValue]=0.0;
+    }
+  }
+  return nElements_;
+}
+#ifndef NDEBUG
+//#############################################################################
+// For debug check vector is clear i.e. no elements
+void CoinIndexedVector::checkClear()
+{
+#ifndef NDEBUG
+  //printf("checkClear %p\n",this);
+  assert(!nElements_);
+  //assert(!packedMode_);
+  int i;
+  for (i=0;i<capacity_;i++) {
+    assert(!elements_[i]);
+  }
+  // check mark array zeroed
+  char * mark = reinterpret_cast<char *> (indices_+capacity_);
+  for (i=0;i<capacity_;i++) {
+    assert(!mark[i]);
+  }
+#else
+  if(nElements_) {
+    printf("%d nElements_ - checkClear\n",nElements_);
+    abort();
+  }
+  if(packedMode_) {
+    printf("packed mode when empty - checkClear\n");
+    abort();
+  }
+  int i;
+  int n=0;
+  int k=-1;
+  for (i=0;i<capacity_;i++) {
+    if(elements_[i]) {
+      n++;
+      if (k<0)
+	k=i;
+    }
+  }
+  if(n) {
+    printf("%d elements, first %d - checkClear\n",n,k);
+    abort();
+  }
+#endif
+}
+// For debug check vector is clean i.e. elements match indices
+void CoinIndexedVector::checkClean()
+{
+  //printf("checkClean %p\n",this);
+  int i;
+  if (packedMode_) {
+    for (i=0;i<nElements_;i++) 
+      assert(elements_[i]);
+    for (;i<capacity_;i++) 
+      assert(!elements_[i]);
+  } else {
+    double * copy = new double[capacity_];
+    CoinMemcpyN(elements_,capacity_,copy);
+    for (i=0;i<nElements_;i++) {
+      int indexValue = indices_[i];
+      assert (copy[indexValue]);
+      copy[indexValue]=0.0;
+    }
+    for (i=0;i<capacity_;i++) 
+      assert(!copy[i]);
+    delete [] copy;
+  }
+#ifndef NDEBUG
+  // check mark array zeroed
+  char * mark = reinterpret_cast<char *> (indices_+capacity_);
+  for (i=0;i<capacity_;i++) {
+    assert(!mark[i]);
+  }
+#endif
+}
+#endif
+//#############################################################################
+#ifndef CLP_NO_VECTOR
+void
+CoinIndexedVector::append(const CoinPackedVectorBase & caboose) 
+{
+  const int cs = caboose.getNumElements();
+  
+  const int * cind = caboose.getIndices();
+  const double * celem = caboose.getElements();
+  int maxIndex=-1;
+  int i;
+  for (i=0;i<cs;i++) {
+    int indexValue = cind[i];
+    if (indexValue<0)
+      throw CoinError("negative index", "append", "CoinIndexedVector");
+    if (maxIndex<indexValue)
+      maxIndex = indexValue;
+  }
+  reserve(maxIndex+1);
+  bool needClean=false;
+  int numberDuplicates=0;
+  for (i=0;i<cs;i++) {
+    int indexValue=cind[i];
+    if (elements_[indexValue]) {
+      numberDuplicates++;
+      elements_[indexValue] += celem[i] ;
+      if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) 
+	needClean=true; // need to go through again
+    } else {
+      if (fabs(celem[i])>=COIN_INDEXED_TINY_ELEMENT) {
+	elements_[indexValue]=celem[i];
+	indices_[nElements_++]=indexValue;
+      }
+    }
+  }
+  if (needClean) {
+    // go through again
+    int size=nElements_;
+    nElements_=0;
+    for (i=0;i<size;i++) {
+      int indexValue=indices_[i];
+      double value=elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	indices_[nElements_++]=indexValue;
+      } else {
+        elements_[indexValue]=0.0;
+      }
+    }
+  }
+  if (numberDuplicates)
+    throw CoinError("duplicate index", "append", "CoinIndexedVector");
+}
+#endif
+//#############################################################################
+
+void
+CoinIndexedVector::swap(int i, int j) 
+{
+  if ( i >= nElements_ ) 
+    throw CoinError("index i >= size()","swap","CoinIndexedVector");
+  if ( i < 0 ) 
+    throw CoinError("index i < 0" ,"swap","CoinIndexedVector");
+  if ( j >= nElements_ ) 
+    throw CoinError("index j >= size()","swap","CoinIndexedVector");
+  if ( j < 0 ) 
+    throw CoinError("index j < 0" ,"swap","CoinIndexedVector");
+  
+  // Swap positions i and j of the
+  // indices array
+  
+  int isave = indices_[i];
+  indices_[i] = indices_[j];
+  indices_[j] = isave;
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::truncate( int n ) 
+{
+  reserve(n);
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::operator+=(double value) 
+{
+  assert (!packedMode_);
+  int i,indexValue;
+  for (i=0;i<nElements_;i++) {
+    indexValue = indices_[i];
+    double newValue = elements_[indexValue] + value;
+    if (fabs(newValue)>=COIN_INDEXED_TINY_ELEMENT)
+      elements_[indexValue] = newValue;
+    else
+      elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinIndexedVector::operator-=(double value) 
+{
+  assert (!packedMode_);
+  int i,indexValue;
+  for (i=0;i<nElements_;i++) {
+    indexValue = indices_[i];
+    double newValue = elements_[indexValue] - value;
+    if (fabs(newValue)>=COIN_INDEXED_TINY_ELEMENT)
+      elements_[indexValue] = newValue;
+    else
+      elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinIndexedVector::operator*=(double value) 
+{
+  assert (!packedMode_);
+  int i,indexValue;
+  for (i=0;i<nElements_;i++) {
+    indexValue = indices_[i];
+    double newValue = elements_[indexValue] * value;
+    if (fabs(newValue)>=COIN_INDEXED_TINY_ELEMENT)
+      elements_[indexValue] = newValue;
+    else
+      elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinIndexedVector::operator/=(double value) 
+{
+  assert (!packedMode_);
+  int i,indexValue;
+  for (i=0;i<nElements_;i++) {
+    indexValue = indices_[i];
+    double newValue = elements_[indexValue] / value;
+    if (fabs(newValue)>=COIN_INDEXED_TINY_ELEMENT)
+      elements_[indexValue] = newValue;
+    else
+      elements_[indexValue] = COIN_INDEXED_REALLY_TINY_ELEMENT;
+  }
+}
+//#############################################################################
+
+void
+CoinIndexedVector::reserve(int n) 
+{
+  int i;
+  // don't make allocated space smaller but do take off values
+  if ( n < capacity_ ) {
+#ifndef COIN_FAST_CODE
+    if (n<0) 
+      throw CoinError("negative capacity", "reserve", "CoinIndexedVector");
+#endif
+    int nNew=0;
+    for (i=0;i<nElements_;i++) {
+      int indexValue=indices_[i];
+      if (indexValue<n) {
+        indices_[nNew++]=indexValue;
+      } else {
+        elements_[indexValue]=0.0;
+      }
+    }
+    nElements_=nNew;
+  } else if (n>capacity_) {
+    
+    // save pointers to existing data
+    int * tempIndices = indices_;
+    double * tempElements = elements_;
+    double * delTemp = elements_-offset_;
+    
+    // allocate new space
+    int nPlus;
+    if (sizeof(int)==4*sizeof(char))
+      nPlus=(n+3)>>2;
+    else
+      nPlus=(n+7)>>4;
+    indices_ = new int [n+nPlus];
+    CoinZeroN(indices_+n,nPlus);
+    // align on 64 byte boundary
+    double * temp = new double [n+9];
+    offset_ = 0;
+    CoinInt64 xx = reinterpret_cast<CoinInt64>(temp);
+    int iBottom = static_cast<int>(xx & 63);
+    //if (iBottom)
+      offset_ = (64-iBottom)>>3;
+    elements_ = temp + offset_;;
+    
+    // copy data to new space
+    // and zero out part of array
+    if (nElements_ > 0) {
+      CoinMemcpyN(tempIndices, nElements_, indices_);
+      CoinMemcpyN(tempElements, capacity_, elements_);
+      CoinZeroN(elements_+capacity_,n-capacity_);
+    } else {
+      CoinZeroN(elements_,n);
+    }
+    capacity_ = n;
+    
+    // free old data
+    if (tempElements)
+      delete [] delTemp;
+    delete [] tempIndices;
+  }
+}
+
+//#############################################################################
+
+CoinIndexedVector::CoinIndexedVector () :
+indices_(NULL),
+elements_(NULL),
+nElements_(0),
+capacity_(0),
+offset_(0),
+packedMode_(false)
+{
+}
+
+
+CoinIndexedVector::CoinIndexedVector (int size) :
+indices_(NULL),
+elements_(NULL),
+nElements_(0),
+capacity_(0),
+offset_(0),
+packedMode_(false)
+{
+  // Get space
+  reserve(size);
+}
+
+//-----------------------------------------------------------------------------
+
+CoinIndexedVector::CoinIndexedVector(int size,
+				     const int * inds, const double * elems)  :
+  indices_(NULL),
+  elements_(NULL),
+  nElements_(0),
+  capacity_(0),
+  offset_(0),
+  packedMode_(false)
+{
+  gutsOfSetVector(size, inds, elems);
+}
+
+//-----------------------------------------------------------------------------
+
+CoinIndexedVector::CoinIndexedVector(int size,
+  const int * inds, double value) :
+indices_(NULL),
+elements_(NULL),
+nElements_(0),
+capacity_(0),
+offset_(0),
+packedMode_(false)
+{
+gutsOfSetConstant(size, inds, value);
+}
+
+//-----------------------------------------------------------------------------
+
+CoinIndexedVector::CoinIndexedVector(int size, const double * element) :
+indices_(NULL),
+elements_(NULL),
+nElements_(0),
+capacity_(0),
+offset_(0),
+packedMode_(false)
+{
+  setFull(size, element);
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+CoinIndexedVector::CoinIndexedVector(const CoinPackedVectorBase & rhs) :
+indices_(NULL),
+elements_(NULL),
+nElements_(0),
+capacity_(0),
+offset_(0),
+packedMode_(false)
+{  
+  gutsOfSetVector(rhs.getNumElements(), 
+			    rhs.getIndices(), rhs.getElements());
+}
+#endif
+//-----------------------------------------------------------------------------
+
+CoinIndexedVector::CoinIndexedVector(const CoinIndexedVector & rhs) :
+indices_(NULL),
+elements_(NULL),
+nElements_(0),
+capacity_(0),
+offset_(0),
+packedMode_(false)
+{
+  if (!rhs.packedMode_)
+    gutsOfSetVector(rhs.capacity_,rhs.nElements_, rhs.indices_, rhs.elements_);
+  else
+    gutsOfSetPackedVector(rhs.capacity_,rhs.nElements_, rhs.indices_, rhs.elements_);
+}
+
+//-----------------------------------------------------------------------------
+
+CoinIndexedVector::CoinIndexedVector(const CoinIndexedVector * rhs) :
+indices_(NULL),
+elements_(NULL),
+nElements_(0),
+capacity_(0),
+offset_(0),
+packedMode_(false)
+{  
+  if (!rhs->packedMode_)
+    gutsOfSetVector(rhs->capacity_,rhs->nElements_, rhs->indices_, rhs->elements_);
+  else
+    gutsOfSetPackedVector(rhs->capacity_,rhs->nElements_, rhs->indices_, rhs->elements_);
+}
+
+//-----------------------------------------------------------------------------
+
+CoinIndexedVector::~CoinIndexedVector ()
+{
+  delete [] indices_;
+  if (elements_)
+    delete [] (elements_-offset_);
+}
+//#############################################################################
+//#############################################################################
+
+/// Return the sum of two indexed vectors
+CoinIndexedVector 
+CoinIndexedVector::operator+(
+                            const CoinIndexedVector& op2)
+{
+  assert (!packedMode_);
+  int i;
+  int nElements=nElements_;
+  int capacity = CoinMax(capacity_,op2.capacity_);
+  CoinIndexedVector newOne(*this);
+  newOne.reserve(capacity);
+  bool needClean=false;
+  // new one now can hold everything so just modify old and add new
+  for (i=0;i<op2.nElements_;i++) {
+    int indexValue=op2.indices_[i];
+    double value=op2.elements_[indexValue];
+    double oldValue=elements_[indexValue];
+    if (!oldValue) {
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	newOne.elements_[indexValue]=value;
+	newOne.indices_[nElements++]=indexValue;
+      }
+    } else {
+      value += oldValue;
+      newOne.elements_[indexValue]=value;
+      if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) {
+	needClean=true;
+      }
+    }
+  }
+  newOne.nElements_=nElements;
+  if (needClean) {
+    // go through again
+    newOne.nElements_=0;
+    for (i=0;i<nElements;i++) {
+      int indexValue=newOne.indices_[i];
+      double value=newOne.elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	newOne.indices_[newOne.nElements_++]=indexValue;
+      } else {
+        newOne.elements_[indexValue]=0.0;
+      }
+    }
+  }
+  return newOne;
+}
+
+/// Return the difference of two indexed vectors
+CoinIndexedVector 
+CoinIndexedVector::operator-(
+                            const CoinIndexedVector& op2)
+{
+  assert (!packedMode_);
+  int i;
+  int nElements=nElements_;
+  int capacity = CoinMax(capacity_,op2.capacity_);
+  CoinIndexedVector newOne(*this);
+  newOne.reserve(capacity);
+  bool needClean=false;
+  // new one now can hold everything so just modify old and add new
+  for (i=0;i<op2.nElements_;i++) {
+    int indexValue=op2.indices_[i];
+    double value=op2.elements_[indexValue];
+    double oldValue=elements_[indexValue];
+    if (!oldValue) {
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	newOne.elements_[indexValue]=-value;
+	newOne.indices_[nElements++]=indexValue;
+      }
+    } else {
+      value = oldValue-value;
+      newOne.elements_[indexValue]=value;
+      if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) {
+	needClean=true;
+      }
+    }
+  }
+  newOne.nElements_=nElements;
+  if (needClean) {
+    // go through again
+    newOne.nElements_=0;
+    for (i=0;i<nElements;i++) {
+      int indexValue=newOne.indices_[i];
+      double value=newOne.elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	newOne.indices_[newOne.nElements_++]=indexValue;
+      } else {
+        newOne.elements_[indexValue]=0.0;
+      }
+    }
+  }
+  return newOne;
+}
+
+/// Return the element-wise product of two indexed vectors
+CoinIndexedVector 
+CoinIndexedVector::operator*(
+                            const CoinIndexedVector& op2)
+{
+  assert (!packedMode_);
+  int i;
+  int nElements=nElements_;
+  int capacity = CoinMax(capacity_,op2.capacity_);
+  CoinIndexedVector newOne(*this);
+  newOne.reserve(capacity);
+  bool needClean=false;
+  // new one now can hold everything so just modify old and add new
+  for (i=0;i<op2.nElements_;i++) {
+    int indexValue=op2.indices_[i];
+    double value=op2.elements_[indexValue];
+    double oldValue=elements_[indexValue];
+    if (oldValue) {
+      value *= oldValue;
+      newOne.elements_[indexValue]=value;
+      if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) {
+	needClean=true;
+      }
+    }
+  }
+
+  newOne.nElements_=nElements;
+
+  if (needClean) {
+    // go through again
+    newOne.nElements_=0;
+    for (i=0;i<nElements;i++) {
+      int indexValue=newOne.indices_[i];
+      double value=newOne.elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	newOne.indices_[newOne.nElements_++]=indexValue;
+      } else {
+        newOne.elements_[indexValue]=0.0;
+      }
+    }
+  }
+  return newOne;
+}
+
+/// Return the element-wise ratio of two indexed vectors
+CoinIndexedVector 
+CoinIndexedVector::operator/ (const CoinIndexedVector& op2) 
+{
+  assert (!packedMode_);
+  // I am treating 0.0/0.0 as 0.0
+  int i;
+  int nElements=nElements_;
+  int capacity = CoinMax(capacity_,op2.capacity_);
+  CoinIndexedVector newOne(*this);
+  newOne.reserve(capacity);
+  bool needClean=false;
+  // new one now can hold everything so just modify old and add new
+  for (i=0;i<op2.nElements_;i++) {
+    int indexValue=op2.indices_[i];
+    double value=op2.elements_[indexValue];
+    double oldValue=elements_[indexValue];
+    if (oldValue) {
+      if (!value)
+        throw CoinError("zero divisor", "/", "CoinIndexedVector");
+      value = oldValue/value;
+      newOne.elements_[indexValue]=value;
+      if (fabs(value)<COIN_INDEXED_TINY_ELEMENT) {
+	needClean=true;
+      }
+    }
+  }
+
+  newOne.nElements_=nElements;
+
+  if (needClean) {
+    // go through again
+    newOne.nElements_=0;
+    for (i=0;i<nElements;i++) {
+      int indexValue=newOne.indices_[i];
+      double value=newOne.elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	newOne.indices_[newOne.nElements_++]=indexValue;
+      } else {
+        newOne.elements_[indexValue]=0.0;
+      }
+    }
+  }
+  return newOne;
+}
+// The sum of two indexed vectors
+void 
+CoinIndexedVector::operator+=(const CoinIndexedVector& op2)
+{
+  // do slowly at first
+  *this = *this + op2;
+}
+
+// The difference of two indexed vectors
+void 
+CoinIndexedVector::operator-=( const CoinIndexedVector& op2)
+{
+  // do slowly at first
+  *this = *this - op2;
+}
+
+// The element-wise product of two indexed vectors
+void 
+CoinIndexedVector::operator*=(const CoinIndexedVector& op2)
+{
+  // do slowly at first
+  *this = *this * op2;
+}
+
+// The element-wise ratio of two indexed vectors (0.0/0.0 => 0.0) (0 vanishes)
+void 
+CoinIndexedVector::operator/=(const CoinIndexedVector& op2)
+{
+  // do slowly at first
+  *this = *this / op2;
+}
+//#############################################################################
+void 
+CoinIndexedVector::sortDecrIndex()
+{ 
+  // Should replace with std sort
+  double * elements = new double [nElements_];
+  CoinZeroN (elements,nElements_);
+  CoinSort_2(indices_, indices_ + nElements_, elements,
+	     CoinFirstGreater_2<int, double>());
+  delete [] elements;
+}
+
+void 
+CoinIndexedVector::sortPacked()
+{ 
+  assert(packedMode_);  
+  CoinSort_2(indices_, indices_ + nElements_, elements_);
+}
+
+void 
+CoinIndexedVector::sortIncrElement()
+{ 
+  double * elements = new double [nElements_];
+  int i;
+  for (i=0;i<nElements_;i++) 
+    elements[i] = elements_[indices_[i]];
+  CoinSort_2(elements, elements + nElements_, indices_,
+    CoinFirstLess_2<double, int>());
+  delete [] elements;
+}
+
+void 
+CoinIndexedVector::sortDecrElement()
+{ 
+  double * elements = new double [nElements_];
+  int i;
+  for (i=0;i<nElements_;i++) 
+    elements[i] = elements_[indices_[i]];
+  CoinSort_2(elements, elements + nElements_, indices_,
+    CoinFirstGreater_2<double, int>());
+  delete [] elements;
+}
+//#############################################################################
+
+void
+CoinIndexedVector::gutsOfSetVector(int size,
+				   const int * inds, const double * elems)
+{
+#ifndef COIN_FAST_CODE
+  if (size<0)
+    throw CoinError("negative number of indices", "setVector", "CoinIndexedVector");
+#endif    
+  assert(!packedMode_);  
+  // find largest
+  int i;
+  int maxIndex=-1;
+  for (i=0;i<size;i++) {
+    int indexValue = inds[i];
+#ifndef COIN_FAST_CODE
+    if (indexValue<0)
+      throw CoinError("negative index", "setVector", "CoinIndexedVector");
+#endif    
+    if (maxIndex<indexValue)
+      maxIndex = indexValue;
+  }
+  reserve(maxIndex+1);
+  nElements_ = 0;
+  // elements_ array is all zero
+  bool needClean=false;
+  int numberDuplicates=0;
+  for (i=0;i<size;i++) {
+    int indexValue=inds[i];
+    if (elements_[indexValue] == 0)
+    {
+      if (fabs(elems[i])>=COIN_INDEXED_TINY_ELEMENT) {
+	indices_[nElements_++]=indexValue;
+	elements_[indexValue]=elems[i];
+      }
+    }
+    else
+    {
+      numberDuplicates++;
+      elements_[indexValue] += elems[i] ;
+      if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) 
+	needClean=true; // need to go through again
+    }
+  }
+  if (needClean) {
+    // go through again
+    size=nElements_;
+    nElements_=0;
+    for (i=0;i<size;i++) {
+      int indexValue=indices_[i];
+      double value=elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	indices_[nElements_++]=indexValue;
+      } else {
+        elements_[indexValue]=0.0;
+      }
+    }
+  }
+  if (numberDuplicates)
+    throw CoinError("duplicate index", "setVector", "CoinIndexedVector");
+}
+
+//#############################################################################
+
+void
+CoinIndexedVector::gutsOfSetVector(int size, int numberIndices, 
+				   const int * inds, const double * elems)
+{
+  assert(!packedMode_);  
+  
+  int i;
+  reserve(size);
+#ifndef COIN_FAST_CODE
+  if (numberIndices<0)
+    throw CoinError("negative number of indices", "setVector", "CoinIndexedVector");
+#endif    
+  nElements_ = 0;
+  // elements_ array is all zero
+  bool needClean=false;
+  int numberDuplicates=0;
+  for (i=0;i<numberIndices;i++) {
+    int indexValue=inds[i];
+#ifndef COIN_FAST_CODE
+    if (indexValue<0) 
+      throw CoinError("negative index", "setVector", "CoinIndexedVector");
+    else if (indexValue>=size) 
+      throw CoinError("too large an index", "setVector", "CoinIndexedVector");
+#endif    
+    if (elements_[indexValue]) {
+      numberDuplicates++;
+      elements_[indexValue] += elems[indexValue] ;
+      if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) 
+	needClean=true; // need to go through again
+    } else {
+#ifndef COIN_FAC_NEW
+      if (fabs(elems[indexValue])>=COIN_INDEXED_TINY_ELEMENT) {
+#endif
+	elements_[indexValue]=elems[indexValue];
+	indices_[nElements_++]=indexValue;
+#ifndef COIN_FAC_NEW
+      }
+#endif
+    }
+  }
+  if (needClean) {
+    // go through again
+    size=nElements_;
+    nElements_=0;
+    for (i=0;i<size;i++) {
+      int indexValue=indices_[i];
+      double value=elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	indices_[nElements_++]=indexValue;
+      } else {
+        elements_[indexValue]=0.0;
+      }
+    }
+  }
+  if (numberDuplicates)
+    throw CoinError("duplicate index", "setVector", "CoinIndexedVector");
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinIndexedVector::gutsOfSetPackedVector(int size, int numberIndices, 
+				   const int * inds, const double * elems)
+{
+  packedMode_=true;  
+  
+  int i;
+  reserve(size);
+#ifndef COIN_FAST_CODE
+  if (numberIndices<0)
+    throw CoinError("negative number of indices", "setVector", "CoinIndexedVector");
+#endif    
+  nElements_ = 0;
+  // elements_ array is all zero
+  // Does not check for duplicates
+  for (i=0;i<numberIndices;i++) {
+    int indexValue=inds[i];
+#ifndef COIN_FAST_CODE
+    if (indexValue<0) 
+      throw CoinError("negative index", "setVector", "CoinIndexedVector");
+    else if (indexValue>=size) 
+      throw CoinError("too large an index", "setVector", "CoinIndexedVector");
+#endif    
+    if (fabs(elems[i])>=COIN_INDEXED_TINY_ELEMENT) {
+      elements_[nElements_]=elems[i];
+      indices_[nElements_++]=indexValue;
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinIndexedVector::gutsOfSetConstant(int size,
+				     const int * inds, double value)
+{
+
+  assert(!packedMode_);  
+#ifndef COIN_FAST_CODE
+  if (size<0)
+    throw CoinError("negative number of indices", "setConstant", "CoinIndexedVector");
+#endif    
+  // find largest
+  int i;
+  int maxIndex=-1;
+  for (i=0;i<size;i++) {
+    int indexValue = inds[i];
+#ifndef COIN_FAST_CODE
+    if (indexValue<0)
+      throw CoinError("negative index", "setConstant", "CoinIndexedVector");
+#endif    
+    if (maxIndex<indexValue)
+      maxIndex = indexValue;
+  }
+  
+  reserve(maxIndex+1);
+  nElements_ = 0;
+  int numberDuplicates=0;
+  // elements_ array is all zero
+  bool needClean=false;
+  for (i=0;i<size;i++) {
+    int indexValue=inds[i];
+    if (elements_[indexValue] == 0)
+    {
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	elements_[indexValue] += value;
+	indices_[nElements_++]=indexValue;
+      }
+    }
+    else
+    {
+      numberDuplicates++;
+      elements_[indexValue] += value ;
+      if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) 
+	needClean=true; // need to go through again
+    }
+  }
+  if (needClean) {
+    // go through again
+    size=nElements_;
+    nElements_=0;
+    for (i=0;i<size;i++) {
+      int indexValue=indices_[i];
+      double value=elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	indices_[nElements_++]=indexValue;
+      } else {
+        elements_[indexValue]=0.0;
+      }
+    }
+  }
+  if (numberDuplicates)
+    throw CoinError("duplicate index", "setConstant", "CoinIndexedVector");
+}
+
+//#############################################################################
+// Append a CoinIndexedVector to the end
+void 
+CoinIndexedVector::append(const CoinIndexedVector & caboose)
+{
+  const int cs = caboose.getNumElements();
+  
+  const int * cind = caboose.getIndices();
+  const double * celem = caboose.denseVector();
+  int maxIndex=-1;
+  int i;
+  for (i=0;i<cs;i++) {
+    int indexValue = cind[i];
+#ifndef COIN_FAST_CODE
+    if (indexValue<0)
+      throw CoinError("negative index", "append", "CoinIndexedVector");
+#endif    
+    if (maxIndex<indexValue)
+      maxIndex = indexValue;
+  }
+  reserve(maxIndex+1);
+  bool needClean=false;
+  int numberDuplicates=0;
+  for (i=0;i<cs;i++) {
+    int indexValue=cind[i];
+    if (elements_[indexValue]) {
+      numberDuplicates++;
+      elements_[indexValue] += celem[indexValue] ;
+      if (fabs(elements_[indexValue])<COIN_INDEXED_TINY_ELEMENT) 
+	needClean=true; // need to go through again
+    } else {
+      if (fabs(celem[indexValue])>=COIN_INDEXED_TINY_ELEMENT) {
+	elements_[indexValue]=celem[indexValue];
+	indices_[nElements_++]=indexValue;
+      }
+    }
+  }
+  if (needClean) {
+    // go through again
+    int size=nElements_;
+    nElements_=0;
+    for (i=0;i<size;i++) {
+      int indexValue=indices_[i];
+      double value=elements_[indexValue];
+      if (fabs(value)>=COIN_INDEXED_TINY_ELEMENT) {
+	indices_[nElements_++]=indexValue;
+      } else {
+        elements_[indexValue]=0.0;
+      }
+    }
+  }
+  if (numberDuplicates)
+    throw CoinError("duplicate index", "append", "CoinIndexedVector");
+}
+// Append a CoinIndexedVector to the end and modify indices
+void 
+CoinIndexedVector::append(CoinIndexedVector & other,int adjustIndex, bool zapElements/*,double multiplier*/)
+{
+  const int cs = other.nElements_;
+  const int * cind = other.indices_;
+  double * celem = other.elements_;
+  int * newInd = indices_+nElements_;
+  if (packedMode_) {
+    double * newEls = elements_+nElements_;
+    if (zapElements) {
+      if (other.packedMode_) {
+	for (int i=0;i<cs;i++) {
+	  newInd[i]=cind[i]+adjustIndex;
+	  newEls[i]=celem[i]/* *multiplier*/;
+	  celem[i]=0.0;
+	}
+      } else {
+	for (int i=0;i<cs;i++) {
+	  int k=cind[i];
+	  newInd[i]=k+adjustIndex;
+	  newEls[i]=celem[k]/* *multiplier*/;
+	  celem[k]=0.0;
+	}
+      }
+    } else {
+      if (other.packedMode_) {
+	for (int i=0;i<cs;i++) {
+	  newEls[i]=celem[i]/* *multiplier*/;
+	  newInd[i]=cind[i]+adjustIndex;
+	}
+      } else {
+	for (int i=0;i<cs;i++) {
+	  int k=cind[i];
+	  newInd[i]=k+adjustIndex;
+	  newEls[i]=celem[k]/* *multiplier*/;
+	}
+      }
+    }
+  } else {
+    double * newEls = elements_+adjustIndex;
+    if (zapElements) {
+      if (other.packedMode_) {
+	for (int i=0;i<cs;i++) {
+	  int k=cind[i];
+	  newInd[i]=k+adjustIndex;
+	  newEls[k]=celem[i]/* *multiplier*/;
+	  celem[i]=0.0;
+	}
+      } else {
+	for (int i=0;i<cs;i++) {
+	  int k=cind[i];
+	  newInd[i]=k+adjustIndex;
+	  newEls[k]=celem[k]/* *multiplier*/;
+	  celem[k]=0.0;
+	}
+      }
+    } else {
+      if (other.packedMode_) {
+	for (int i=0;i<cs;i++) {
+	  int k=cind[i];
+	  newInd[i]=k+adjustIndex;
+	  newEls[k]=celem[i]/* *multiplier*/;
+	}
+      } else {
+	for (int i=0;i<cs;i++) {
+	  int k=cind[i];
+	  newInd[i]=k+adjustIndex;
+	  newEls[k]=celem[k]/* *multiplier*/;
+	}
+      }
+    }
+  }
+  nElements_ += cs;
+  if (zapElements)
+    other.nElements_=0;
+}
+#ifndef CLP_NO_VECTOR
+/* Equal. Returns true if vectors have same length and corresponding
+   element of each vector is equal. */
+bool 
+CoinIndexedVector::operator==(const CoinPackedVectorBase & rhs) const
+{
+  const int cs = rhs.getNumElements();
+  
+  const int * cind = rhs.getIndices();
+  const double * celem = rhs.getElements();
+  if (nElements_!=cs)
+    return false;
+  int i;
+  bool okay=true;
+  for (i=0;i<cs;i++) {
+    int iRow = cind[i];
+    if (celem[i]!=elements_[iRow]) {
+      okay=false;
+      break;
+    }
+  }
+  return okay;
+}
+// Not equal
+bool 
+CoinIndexedVector::operator!=(const CoinPackedVectorBase & rhs) const
+{
+  const int cs = rhs.getNumElements();
+  
+  const int * cind = rhs.getIndices();
+  const double * celem = rhs.getElements();
+  if (nElements_!=cs)
+    return true;
+  int i;
+  bool okay=false;
+  for (i=0;i<cs;i++) {
+    int iRow = cind[i];
+    if (celem[i]!=elements_[iRow]) {
+      okay=true;
+      break;
+    }
+  }
+  return okay;
+}
+#endif
+// Equal with a tolerance (returns -1 or position of inequality). 
+int
+CoinIndexedVector::isApproximatelyEqual(const CoinIndexedVector & rhs, double tolerance) const
+{
+  CoinIndexedVector tempA(*this);
+  CoinIndexedVector tempB(rhs);
+  int * cind = tempB.indices_;
+  double * celem = tempB.elements_;
+  double * elem = tempA.elements_;
+  int cs = tempB.nElements_;
+  int bad=-1;
+  CoinRelFltEq eq(tolerance);
+  if (!packedMode_&&!tempB.packedMode_) {
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      if (!eq(celem[iRow],elem[iRow])) {
+	bad=iRow;
+	break;
+      } else {
+	celem[iRow]=elem[iRow]=0.0;
+      }
+    }
+    cs=tempA.nElements_;
+    cind=tempA.indices_;
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      if (!eq(celem[iRow],elem[iRow])) {
+	bad=iRow;
+	break;
+      } else {
+	celem[iRow]=elem[iRow]=0.0;
+      }
+    }
+  } else if (packedMode_&&tempB.packedMode_) {
+    double * celem2 = rhs.elements_;
+    memset(celem,0,CoinMin(capacity_,tempB.capacity_)*sizeof(double));
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      celem[iRow]=celem2[i];
+    }
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      if (!eq(celem[iRow],elem[i])) {
+	bad=iRow;
+	break;
+      } else {
+	celem[iRow]=elem[i]=0.0;
+      }
+    }
+  } else {
+    double * celem2=elem;
+    double * celem3=celem;
+    if (packedMode_) {
+      celem2=celem;
+      celem3=elem;
+    }
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      if (!eq(celem2[iRow],celem3[i])) {
+	bad=iRow;
+	break;
+      } else {
+	celem2[iRow]=celem3[i]=0.0;
+      }
+    }
+  }
+  if (bad<0) {
+    for (int i=0;i<tempA.capacity_;i++) {
+      if (elem[i]) {
+	if (fabs(elem[i])>tolerance) {
+	  bad=i;
+	  break;
+	}
+      }
+    }
+    for (int i=0;i<tempB.capacity_;i++) {
+      if (celem[i]) {
+	if (fabs(celem[i])>tolerance) {
+	  bad=i;
+	  break;
+	}
+      }
+    }
+  }
+  return bad;
+}
+/* Equal. Returns true if vectors have same length and corresponding
+   element of each vector is equal. */
+bool 
+CoinIndexedVector::operator==(const CoinIndexedVector & rhs) const
+{
+  const int cs = rhs.nElements_;
+  
+  const int * cind = rhs.indices_;
+  const double * celem = rhs.elements_;
+  if (nElements_!=cs)
+    return false;
+  bool okay=true;
+  CoinRelFltEq eq(1.0e-8);
+  if (!packedMode_&&!rhs.packedMode_) {
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      if (!eq(celem[iRow],elements_[iRow])) {
+	okay=false;
+	break;
+      }
+    }
+  } else if (packedMode_&&rhs.packedMode_) {
+    double * temp = new double[CoinMax(capacity_,rhs.capacity_)];
+    memset(temp,0,CoinMax(capacity_,rhs.capacity_)*sizeof(double));
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      temp[iRow]=celem[i];
+    }
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      if (!eq(temp[iRow],elements_[i])) {
+	okay=false;
+	break;
+      }
+    }
+  } else {
+    const double * celem2=elements_;
+    if (packedMode_) {
+      celem2=celem;
+      celem=elements_;
+    }
+    for (int i=0;i<cs;i++) {
+      int iRow = cind[i];
+      if (!eq(celem2[iRow],celem[i])) {
+	okay=false;
+	break;
+      }
+    }
+  }
+  return okay;
+}
+/// Not equal
+bool 
+CoinIndexedVector::operator!=(const CoinIndexedVector & rhs) const
+{
+  const int cs = rhs.nElements_;
+  
+  const int * cind = rhs.indices_;
+  const double * celem = rhs.elements_;
+  if (nElements_!=cs)
+    return true;
+  int i;
+  bool okay=false;
+  for (i=0;i<cs;i++) {
+    int iRow = cind[i];
+    if (celem[iRow]!=elements_[iRow]) {
+      okay=true;
+      break;
+    }
+  }
+  return okay;
+}
+// Get value of maximum index
+int 
+CoinIndexedVector::getMaxIndex() const
+{
+  int maxIndex = -COIN_INT_MAX;
+  int i;
+  for (i=0;i<nElements_;i++)
+    maxIndex = CoinMax(maxIndex,indices_[i]);
+  return maxIndex;
+}
+// Get value of minimum index
+int 
+CoinIndexedVector::getMinIndex() const
+{
+  int minIndex = COIN_INT_MAX;
+  int i;
+  for (i=0;i<nElements_;i++)
+    minIndex = CoinMin(minIndex,indices_[i]);
+  return minIndex;
+}
+// Scan dense region and set up indices
+int
+CoinIndexedVector::scan()
+{
+  nElements_=0;
+  return scan(0,capacity_);
+}
+// Scan dense region from start to < end and set up indices
+int
+CoinIndexedVector::scan(int start, int end)
+{
+  assert(!packedMode_);
+  end = CoinMin(end,capacity_);
+  start = CoinMax(start,0);
+  int i;
+  int number = 0;
+  int * indices = indices_+nElements_;
+  for (i=start;i<end;i++) 
+    if (elements_[i])
+      indices[number++] = i;
+  nElements_ += number;
+  return number;
+}
+// Scan dense region and set up indices with tolerance
+int
+CoinIndexedVector::scan(double tolerance)
+{
+  nElements_=0;
+  return scan(0,capacity_,tolerance);
+}
+// Scan dense region from start to < end and set up indices with tolerance
+int
+CoinIndexedVector::scan(int start, int end, double tolerance)
+{
+  assert(!packedMode_);
+  end = CoinMin(end,capacity_);
+  start = CoinMax(start,0);
+  int i;
+  int number = 0;
+  int * indices = indices_+nElements_;
+  for (i=start;i<end;i++) {
+    double value = elements_[i];
+    if (value) {
+      if (fabs(value)>=tolerance) 
+	indices[number++] = i;
+      else
+	elements_[i]=0.0;
+    }
+  }
+  nElements_ += number;
+  return number;
+}
+// These pack down
+int
+CoinIndexedVector::cleanAndPack( double tolerance )
+{
+  if (!packedMode_) {
+    int number = nElements_;
+    int i;
+    nElements_=0;
+    for (i=0;i<number;i++) {
+      int indexValue = indices_[i];
+      double value = elements_[indexValue];
+      elements_[indexValue]=0.0;
+      if (fabs(value)>=tolerance) {
+	elements_[nElements_]=value;
+	indices_[nElements_++]=indexValue;
+      }
+    }
+    packedMode_=true;
+  }
+  return nElements_;
+}
+// These pack down
+int
+CoinIndexedVector::cleanAndPackSafe( double tolerance )
+{
+  int number = nElements_;
+  if (number) {
+    int i;
+    nElements_=0;
+    assert(!packedMode_);
+    double * temp=NULL;
+    bool gotMemory;
+    if (number*3<capacity_-3-9999999) {
+      // can find room without new
+      gotMemory=false;
+      // But may need to align on 8 byte boundary
+      char * tempC = reinterpret_cast<char *> (indices_+number);
+      CoinInt64 xx = reinterpret_cast<CoinInt64>(tempC);
+      CoinInt64 iBottom = xx & 7;
+      if (iBottom)
+	tempC += 8-iBottom;
+      temp = reinterpret_cast<double *> (tempC);
+      xx = reinterpret_cast<CoinInt64>(temp);
+      iBottom = xx & 7;
+      assert(!iBottom);
+    } else {
+      // might be better to do complete scan
+      gotMemory=true;
+      temp = new double[number];
+    }
+    for (i=0;i<number;i++) {
+      int indexValue = indices_[i];
+      double value = elements_[indexValue];
+      elements_[indexValue]=0.0;
+      if (fabs(value)>=tolerance) {
+	temp[nElements_]=value;
+	indices_[nElements_++]=indexValue;
+      }
+    }
+    CoinMemcpyN(temp,nElements_,elements_);
+    if (gotMemory)
+      delete [] temp;
+    packedMode_=true;
+  }
+  return nElements_;
+}
+// Scan dense region and set up indices
+int
+CoinIndexedVector::scanAndPack()
+{
+  nElements_=0;
+  return scanAndPack(0,capacity_);
+}
+// Scan dense region from start to < end and set up indices
+int
+CoinIndexedVector::scanAndPack(int start, int end)
+{
+  assert(!packedMode_);
+  end = CoinMin(end,capacity_);
+  start = CoinMax(start,0);
+  int i;
+  int number = 0;
+  int * indices = indices_+nElements_;
+  for (i=start;i<end;i++) {
+    double value = elements_[i];
+    elements_[i]=0.0;
+    if (value) {
+      elements_[number]=value;
+      indices[number++] = i;
+    }
+  }
+  nElements_ += number;
+  packedMode_=true;
+  return number;
+}
+// Scan dense region and set up indices with tolerance
+int
+CoinIndexedVector::scanAndPack(double tolerance)
+{
+  nElements_=0;
+  return scanAndPack(0,capacity_,tolerance);
+}
+// Scan dense region from start to < end and set up indices with tolerance
+int
+CoinIndexedVector::scanAndPack(int start, int end, double tolerance)
+{
+  assert(!packedMode_);
+  end = CoinMin(end,capacity_);
+  start = CoinMax(start,0);
+  int i;
+  int number = 0;
+  int * indices = indices_+nElements_;
+  for (i=start;i<end;i++) {
+    double value = elements_[i];
+    elements_[i]=0.0;
+    if (fabs(value)>=tolerance) {
+      elements_[number]=value;
+	indices[number++] = i;
+    }
+  }
+  nElements_ += number;
+  packedMode_=true;
+  return number;
+}
+// This is mainly for testing - goes from packed to indexed
+void 
+CoinIndexedVector::expand()
+{
+  if (nElements_&&packedMode_) {
+    double * temp = new double[capacity_];
+    int i;
+    for (i=0;i<nElements_;i++) 
+      temp[indices_[i]]=elements_[i];
+    CoinZeroN(elements_,nElements_);
+    for (i=0;i<nElements_;i++) {
+      int iRow = indices_[i];
+      elements_[iRow]=temp[iRow];
+    }
+    delete [] temp;
+  }
+  packedMode_=false;
+}
+// Create packed array
+void 
+CoinIndexedVector::createPacked(int number, const int * indices, 
+		    const double * elements)
+{
+  nElements_=number;
+  packedMode_=true;
+  CoinMemcpyN(indices,number,indices_);
+  CoinMemcpyN(elements,number,elements_);
+}
+// Create packed array
+void 
+CoinIndexedVector::createUnpacked(int number, const int * indices, 
+		    const double * elements)
+{
+  nElements_=number;
+  packedMode_=false;
+  for (int i=0;i<nElements_;i++) {
+    int iRow=indices[i];
+    indices_[i]=iRow;
+    elements_[iRow]=elements[i];
+  }
+}
+// Create unpacked singleton
+void 
+CoinIndexedVector::createOneUnpackedElement(int index, double element)
+{
+  nElements_=1;
+  packedMode_=false;
+  indices_[0]=index;
+  elements_[index]=element;
+}
+//  Print out
+void 
+CoinIndexedVector::print() const
+{
+  printf("Vector has %d elements (%spacked mode)\n",nElements_,packedMode_ ? "" : "un");
+  for (int i=0;i<nElements_;i++) {
+    if (i&&(i%5==0))
+      printf("\n");
+    int index = indices_[i];
+    double value = packedMode_ ? elements_[i] : elements_[index];
+    printf(" (%d,%g)",index,value);
+  }
+  printf("\n");
+}
+
+// Zero out array
+void 
+CoinArrayWithLength::clear()
+{
+  assert ((size_>0&&array_)||!array_);
+  memset (array_,0,size_);
+}
+// Get array with alignment
+void 
+CoinArrayWithLength::getArray(int size)
+{
+  if (size>0) {
+    if(alignment_>2) {
+      offset_ = 1<<alignment_;
+    } else {
+      offset_=0;
+    }
+    assert (size>0);
+    char * array = new char [size+offset_];
+    if (offset_) {
+      // need offset
+      CoinInt64 xx = reinterpret_cast<CoinInt64>(array);
+      int iBottom = static_cast<int>(xx & ((offset_-1)));
+      if (iBottom)
+	offset_ = offset_-iBottom;
+      else
+	offset_ = 0;
+      array_ = array + offset_;;
+    } else {
+      array_=array;
+    }
+    if (size_!=-1)
+      size_=size;
+  } else {
+    array_= NULL;
+  }
+}
+// Get rid of array with alignment
+void 
+CoinArrayWithLength::conditionalDelete()
+{
+  if (size_==-1) {
+    char * charArray = reinterpret_cast<char *> (array_);
+    if (charArray)
+      delete [] (charArray-offset_);
+    array_=NULL;
+  } else if (size_>=0) {
+    size_ = -size_-2;
+  }
+}
+// Really get rid of array with alignment
+void 
+CoinArrayWithLength::reallyFreeArray()
+{
+  char * charArray = reinterpret_cast<char *> (array_);
+  if (charArray)
+    delete [] (charArray-offset_);
+  array_=NULL;
+  size_=-1;
+}
+// Get enough space
+void 
+CoinArrayWithLength::getCapacity(int numberBytes,int numberNeeded)
+{
+  int k=capacity();
+  if (k<numberBytes) {
+    int saveSize=size_;
+    reallyFreeArray();
+    size_=saveSize;
+    getArray(CoinMax(numberBytes,numberNeeded));
+  } else if (size_<0) {
+    size_=-size_-2;
+  }
+}
+/* Alternate Constructor - length in bytes 
+   mode -  0 size_ set to size
+   >0 size_ set to size and zeroed
+   if size<=0 just does alignment
+   If abs(mode) >2 then align on that as power of 2
+*/
+CoinArrayWithLength::CoinArrayWithLength(int size, int mode)
+{
+  alignment_=abs(mode);
+  getArray(size);
+  if (mode>0&&array_) 
+    memset(array_,0,size);
+  size_=size;
+}
+CoinArrayWithLength::~CoinArrayWithLength ()
+{ 
+  if (array_)
+    delete [] (array_-offset_); 
+}
+// Conditionally gets new array
+char * 
+CoinArrayWithLength::conditionalNew(long sizeWanted)
+{
+  if (size_==-1) {
+    getCapacity(static_cast<int>(sizeWanted));
+  } else {
+    int newSize = static_cast<int> (sizeWanted*101/100)+64;
+    // round to multiple of 16
+    newSize -= newSize&15;
+    getCapacity(static_cast<int>(sizeWanted),newSize);
+  }
+  return array_;
+}
+/* Copy constructor. */
+CoinArrayWithLength::CoinArrayWithLength(const CoinArrayWithLength & rhs)
+{
+  assert (capacity()>=0);
+  getArray(rhs.capacity());
+  if (size_>0)
+    CoinMemcpyN(rhs.array_,size_,array_);
+}
+
+/* Copy constructor.2 */
+CoinArrayWithLength::CoinArrayWithLength(const CoinArrayWithLength * rhs)
+{
+  assert (rhs->capacity()>=0);
+  size_=rhs->size_;
+  getArray(rhs->capacity());
+  if (size_>0)
+    CoinMemcpyN(rhs->array_,size_,array_);
+}
+/* Assignment operator. */
+CoinArrayWithLength & 
+CoinArrayWithLength::operator=(const CoinArrayWithLength & rhs)
+{
+  if (this != &rhs) {
+    assert (rhs.size_!=-1||!rhs.array_);
+    if (rhs.size_==-1) {
+      reallyFreeArray();
+    } else {
+      getCapacity(rhs.size_);
+      if (size_>0)
+	CoinMemcpyN(rhs.array_,size_,array_);
+    }
+  }
+  return *this;
+}
+/* Assignment with length (if -1 use internal length) */
+void 
+CoinArrayWithLength::copy(const CoinArrayWithLength & rhs, int numberBytes)
+{
+  if (numberBytes==-1||numberBytes<=rhs.capacity()) {
+    CoinArrayWithLength::operator=(rhs);
+  } else {
+    assert (numberBytes>=0);
+    getCapacity(numberBytes);
+    if (rhs.array_)
+      CoinMemcpyN(rhs.array_,numberBytes,array_);
+  }
+}
+/* Assignment with length - does not copy */
+void 
+CoinArrayWithLength::allocate(const CoinArrayWithLength & rhs, int numberBytes)
+{
+  if (numberBytes==-1||numberBytes<=rhs.capacity()) {
+    assert (rhs.size_!=-1||!rhs.array_);
+    if (rhs.size_==-1) {
+      reallyFreeArray();
+    } else {
+      getCapacity(rhs.size_);
+    }
+  } else {
+    assert (numberBytes>=0);
+    if (size_==-1) {
+      delete [] array_;
+      array_=NULL;
+    } else {
+      size_=-1;
+    } 
+    if (rhs.size_>=0) 
+      size_ = numberBytes;
+    assert (numberBytes>=0);
+    assert (!array_);
+    if (numberBytes)
+      array_ = new char[numberBytes];
+  }
+}
+// Does what is needed to set persistence
+void 
+CoinArrayWithLength::setPersistence(int flag,int currentLength)
+{
+  if (flag) {
+    if (size_==-1) {
+      if (currentLength&&array_) {
+	size_=currentLength;
+      } else {
+	size_=0;
+	conditionalDelete();
+	array_=NULL;
+      }
+    }
+  } else {
+    size_=-1;
+  }
+}
+// Swaps memory between two members
+void 
+CoinArrayWithLength::swap(CoinArrayWithLength & other)
+{
+#ifdef COIN_DEVELOP
+  if (!(size_==other.size_||size_==-1||other.size_==-1))
+    printf("Two arrays have sizes - %d and %d\n",size_,other.size_);
+#endif
+  assert (alignment_==other.alignment_);
+  char * swapArray = other.array_;
+  other.array_=array_;
+  array_=swapArray;
+  int swapSize = other.size_;
+  other.size_=size_;
+  size_=swapSize;
+  int swapOffset = other.offset_;
+  other.offset_=offset_;
+  offset_=swapOffset;
+}
+// Extend a persistent array keeping data (size in bytes)
+void 
+CoinArrayWithLength::extend(int newSize)
+{
+  //assert (newSize>=capacity()&&capacity()>=0);
+  assert (size_>=0); // not much point otherwise
+  if (newSize>size_) {
+    char * temp = array_;
+    getArray(newSize);
+    if (temp) {
+      CoinMemcpyN(array_,size_,temp);
+      delete [] (temp-offset_);
+    }
+    size_=newSize;
+  }
+}
+
+/* Default constructor */
+CoinPartitionedVector::CoinPartitionedVector()
+  : CoinIndexedVector()
+{
+  memset(startPartition_,0,((&numberPartitions_-startPartition_)+1)*sizeof(int));
+}
+/* Copy constructor. */
+CoinPartitionedVector::CoinPartitionedVector(const CoinPartitionedVector & rhs)
+  : CoinIndexedVector(rhs)
+{
+  memcpy(startPartition_,rhs.startPartition_,((&numberPartitions_-startPartition_)+1)*sizeof(int));
+}
+/* Copy constructor.2 */
+CoinPartitionedVector::CoinPartitionedVector(const CoinPartitionedVector * rhs)
+  : CoinIndexedVector(rhs)
+{
+  memcpy(startPartition_,rhs->startPartition_,((&numberPartitions_-startPartition_)+1)*sizeof(int));
+}
+/* Assignment operator. */
+CoinPartitionedVector & CoinPartitionedVector::operator=(const CoinPartitionedVector & rhs)
+{
+  if (this != &rhs) {
+    CoinIndexedVector::operator=(rhs);
+    memcpy(startPartition_,rhs.startPartition_,((&numberPartitions_-startPartition_)+1)*sizeof(int));
+  }
+  return *this;
+}
+/* Destructor */
+CoinPartitionedVector::~CoinPartitionedVector ()
+{
+}
+// Add up number of elements in partitions
+void 
+CoinPartitionedVector::computeNumberElements()
+{
+  if (numberPartitions_) {
+    assert (packedMode_);
+    int n=0;
+    for (int i=0;i<numberPartitions_;i++)
+      n += numberElementsPartition_[i];
+    nElements_=n;
+  }
+}
+// Add up number of elements in partitions and pack and get rid of partitions
+void 
+CoinPartitionedVector::compact()
+{
+  if (numberPartitions_) {
+    int n=numberElementsPartition_[0];
+    numberElementsPartition_[0]=0;
+    for (int i=1;i<numberPartitions_;i++) {
+      int nThis=numberElementsPartition_[i];
+      int start=startPartition_[i];
+      memmove(indices_+n,indices_+start,nThis*sizeof(int));
+      memmove(elements_+n,elements_+start,nThis*sizeof(double));
+      n += nThis;
+    }
+    nElements_=n;
+    // clean up
+    for (int i=1;i<numberPartitions_;i++) {
+      int nThis=numberElementsPartition_[i];
+      int start=startPartition_[i];
+      numberElementsPartition_[i]=0;
+      int end=nThis+start;
+      if (nElements_<end) {
+	int offset=CoinMax(nElements_-start,0);
+	start+=offset;
+	nThis-=offset;
+	memset(elements_+start,0,nThis*sizeof(double));
+      }
+    }
+    packedMode_=true;
+    numberPartitions_=0;
+  }
+}
+/* Reserve space.
+ */
+void 
+CoinPartitionedVector::reserve(int n)
+{
+  CoinIndexedVector::reserve(n);
+  memset(startPartition_,0,((&numberPartitions_-startPartition_)+1)*sizeof(int));
+  startPartition_[1]=capacity_; // for safety
+}
+// Setup partitions (needs end as well)
+void 
+CoinPartitionedVector::setPartitions(int number,const int * starts)
+{
+  if (number) {
+    packedMode_=true;
+    assert (number<=COIN_PARTITIONS);
+    memcpy(startPartition_,starts,(number+1)*sizeof(int));
+    numberPartitions_=number;
+#ifndef NDEBUG
+    assert (startPartition_[0]==0);
+    int last=-1;
+    for (int i=0;i<numberPartitions_;i++) {
+      assert (startPartition_[i]>=last);
+      assert (numberElementsPartition_[i]==0);
+      last=startPartition_[i];
+    }
+    assert (startPartition_[numberPartitions_]>=last&&
+	    startPartition_[numberPartitions_]<=capacity_);
+#endif
+  } else {
+    clearAndReset();
+  }
+}
+// Reset the vector (as if were just created an empty vector). Gets rid of partitions
+void 
+CoinPartitionedVector::clearAndReset()
+{
+  if (numberPartitions_) {
+    assert (packedMode_||!nElements_);
+    for (int i=0;i<numberPartitions_;i++) {
+      int n=numberElementsPartition_[i];
+      memset(elements_+startPartition_[i],0,n*sizeof(double));
+      numberElementsPartition_[i]=0;
+    }
+  } else {
+    memset(elements_,0,nElements_*sizeof(double));
+  }
+  nElements_=0;
+  numberPartitions_=0;
+  startPartition_[1]=capacity_;
+  packedMode_=false;
+}
+// Reset the vector (as if were just created an empty vector). Keeps partitions
+void 
+CoinPartitionedVector::clearAndKeep()
+{
+  assert (packedMode_);
+  for (int i=0;i<numberPartitions_;i++) {
+    int n=numberElementsPartition_[i];
+    memset(elements_+startPartition_[i],0,n*sizeof(double));
+    numberElementsPartition_[i]=0;
+  }
+  nElements_=0;
+}
+// Clear a partition.
+void 
+CoinPartitionedVector::clearPartition(int partition)
+{
+  assert (packedMode_);
+  assert (partition<COIN_PARTITIONS);
+  int n=numberElementsPartition_[partition];
+  memset(elements_+startPartition_[partition],0,n*sizeof(double));
+  numberElementsPartition_[partition]=0;
+}
+#ifndef NDEBUG
+// For debug check vector is clear i.e. no elements
+void 
+CoinPartitionedVector::checkClear()
+{
+#ifndef NDEBUG
+  //printf("checkClear %p\n",this);
+  assert(!nElements_);
+  //assert(!packedMode_);
+  int i;
+  for (i=0;i<capacity_;i++) {
+    assert(!elements_[i]);
+  }
+#else
+  if(nElements_) {
+    printf("%d nElements_ - checkClear\n",nElements_);
+    abort();
+  }
+  int i;
+  int n=0;
+  int k=-1;
+  for (i=0;i<capacity_;i++) {
+    if(elements_[i]) {
+      n++;
+      if (k<0)
+	k=i;
+    }
+  }
+  if(n) {
+    printf("%d elements, first %d - checkClear\n",n,k);
+    abort();
+  }
+#endif
+}
+// For debug check vector is clean i.e. elements match indices
+void 
+CoinPartitionedVector::checkClean()
+{
+  //printf("checkClean %p\n",this);
+  if (!nElements_) {
+    checkClear();
+  } else {
+    assert (packedMode_);
+    int i;
+    for (i=0;i<nElements_;i++) 
+      assert(elements_[i]);
+    for (;i<capacity_;i++) 
+      assert(!elements_[i]);
+#ifndef NDEBUG
+    // check mark array zeroed
+    char * mark = reinterpret_cast<char *> (indices_+capacity_);
+    for (i=0;i<capacity_;i++) {
+      assert(!mark[i]);
+    }
+#endif
+  }
+}
+#endif
+// Scan dense region and set up indices (returns number found)
+int 
+CoinPartitionedVector::scan(int partition, double tolerance)
+{
+  assert (packedMode_);
+  assert (partition<COIN_PARTITIONS);
+  int n=0;
+  int start=startPartition_[partition];
+  double * COIN_RESTRICT elements=elements_+start;
+  int * COIN_RESTRICT indices=indices_+start;
+  int sizePartition=startPartition_[partition+1]-start;
+  if (!tolerance) {
+    for (int i=0;i<sizePartition;i++) {
+      double value = elements[i];
+      if (value) {
+	elements[i]=0.0;
+	elements[n]=value;
+	indices[n++]=i+start;
+      }
+    }
+  } else {
+    for (int i=0;i<sizePartition;i++) {
+      double value = elements[i];
+      if (value) {
+	elements[i]=0.0;
+	if (fabs(value)>tolerance) {
+	  elements[n]=value;
+	  indices[n++]=i+start;
+	}
+      }
+    }
+  }
+  numberElementsPartition_[partition]=n;
+  return n;
+}
+//  Print out
+void 
+CoinPartitionedVector::print() const
+{
+  printf("Vector has %d elements (%d partitions)\n",nElements_,numberPartitions_);
+  if (!numberPartitions_) {
+    CoinIndexedVector::print();
+    return;
+  }
+  double * tempElements=CoinCopyOfArray(elements_,capacity_);
+  int * tempIndices=CoinCopyOfArray(indices_,capacity_);
+  for (int partition=0;partition<numberPartitions_;partition++) {
+    printf("Partition %d has %d elements\n",partition,numberElementsPartition_[partition]);
+    int start=startPartition_[partition];
+    double * COIN_RESTRICT elements=tempElements+start;
+    int * COIN_RESTRICT indices=tempIndices+start;
+    CoinSort_2(indices,indices+numberElementsPartition_[partition],elements);
+    for (int i=0;i<numberElementsPartition_[partition];i++) {
+      if (i&&(i%5==0))
+	printf("\n");
+      int index = indices[i];
+      double value =  elements[i];
+      printf(" (%d,%g)",index,value);
+    }
+    printf("\n");
+  }
+}
+/* Sort the indexed storage vector (increasing indices). */
+void 
+CoinPartitionedVector::sort()
+{
+  assert (packedMode_);
+  for (int partition=0;partition<numberPartitions_;partition++) {
+    int start=startPartition_[partition];
+    double * COIN_RESTRICT elements=elements_+start;
+    int * COIN_RESTRICT indices=indices_+start;
+    CoinSort_2(indices,indices+numberElementsPartition_[partition],elements);
+  }
+}
diff --git a/cbits/coin/CoinIndexedVector.hpp b/cbits/coin/CoinIndexedVector.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinIndexedVector.hpp
@@ -0,0 +1,1162 @@
+/* $Id: CoinIndexedVector.hpp 1554 2012-10-31 16:52:28Z forrest $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinIndexedVector_H
+#define CoinIndexedVector_H
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <map>
+#include "CoinFinite.hpp"
+#ifndef CLP_NO_VECTOR
+#include "CoinPackedVectorBase.hpp"
+#endif
+#include "CoinSort.hpp"
+#include "CoinHelperFunctions.hpp"
+#include <cassert>
+
+#ifndef COIN_FLOAT
+#define COIN_INDEXED_TINY_ELEMENT 1.0e-50
+#define COIN_INDEXED_REALLY_TINY_ELEMENT 1.0e-100
+#else
+#define COIN_INDEXED_TINY_ELEMENT 1.0e-35
+#define COIN_INDEXED_REALLY_TINY_ELEMENT 1.0e-39
+#endif
+
+/** Indexed Vector
+
+This stores values unpacked but apart from that is a bit like CoinPackedVector.
+It is designed to be lightweight in normal use.
+
+It now has a "packed" mode when it is even more like CoinPackedVector
+
+Indices array has capacity_ extra chars which are zeroed and can
+be used for any purpose - but must be re-zeroed
+
+Stores vector of indices and associated element values.
+Supports sorting of indices.  
+
+Does not support negative indices.
+
+Does NOT support testing for duplicates
+
+*** getElements is no longer supported
+
+Here is a sample usage:
+@verbatim
+    const int ne = 4;
+    int inx[ne] =   {  1,   4,  0,   2 }
+    double el[ne] = { 10., 40., 1., 50. }
+
+    // Create vector and set its valuex1
+    CoinIndexedVector r(ne,inx,el);
+
+    // access as a full storage vector
+    assert( r[ 0]==1. );
+    assert( r[ 1]==10.);
+    assert( r[ 2]==50.);
+    assert( r[ 3]==0. );
+    assert( r[ 4]==40.);
+
+    // sort Elements in increasing order
+    r.sortIncrElement();
+
+    // access each index and element
+    assert( r.getIndices ()[0]== 0  );
+    assert( r.getIndices ()[1]== 1  );
+    assert( r.getIndices ()[2]== 4  );
+    assert( r.getIndices ()[3]== 2  );
+
+    // access as a full storage vector
+    assert( r[ 0]==1. );
+    assert( r[ 1]==10.);
+    assert( r[ 2]==50.);
+    assert( r[ 3]==0. );
+    assert( r[ 4]==40.);
+
+    // Tests for equality and equivalence
+    CoinIndexedVector r1;
+    r1=r;
+    assert( r==r1 );
+    assert( r.equivalent(r1) );
+    r.sortIncrElement();
+    assert( r!=r1 );
+    assert( r.equivalent(r1) );
+
+    // Add indexed vectors.
+    // Similarly for subtraction, multiplication,
+    // and division.
+    CoinIndexedVector add = r + r1;
+    assert( add[0] ==  1.+ 1. );
+    assert( add[1] == 10.+10. );
+    assert( add[2] == 50.+50. );
+    assert( add[3] ==  0.+ 0. );
+    assert( add[4] == 40.+40. );
+
+    assert( r.sum() == 10.+40.+1.+50. );
+@endverbatim
+*/
+class CoinIndexedVector {
+   friend void CoinIndexedVectorUnitTest();
+  
+public:
+   /**@name Get methods. */
+   //@{
+   /// Get the size
+   inline int getNumElements() const { return nElements_; }
+   /// Get indices of elements
+   inline const int * getIndices() const { return indices_; }
+   /// Get element values
+   // ** No longer supported virtual const double * getElements() const ;
+   /// Get indices of elements
+   inline int * getIndices() { return indices_; }
+   /** Get the vector as a dense vector. This is normal storage method.
+       The user should not not delete [] this.
+   */
+   inline double * denseVector() const { return elements_; }
+   /// For very temporary use when user needs to borrow a dense vector
+  inline void setDenseVector(double * array)
+  { elements_ = array;}
+   /// For very temporary use when user needs to borrow an index vector
+  inline void setIndexVector(int * array)
+  { indices_ = array;}
+   /** Access the i'th element of the full storage vector.
+   */
+   double & operator[](int i) const; 
+
+   //@}
+ 
+   //-------------------------------------------------------------------
+   // Set indices and elements
+   //------------------------------------------------------------------- 
+   /**@name Set methods */
+   //@{
+   /// Set the size
+   inline void setNumElements(int value) { nElements_ = value;
+   if (!nElements_) packedMode_=false;}
+   /// Reset the vector (as if were just created an empty vector).  This leaves arrays!
+   void clear();
+   /// Reset the vector (as if were just created an empty vector)
+   void empty();
+   /** Assignment operator. */
+   CoinIndexedVector & operator=(const CoinIndexedVector &);
+#ifndef CLP_NO_VECTOR
+   /** Assignment operator from a CoinPackedVectorBase. <br>
+   <strong>NOTE</strong>: This assumes no duplicates */
+   CoinIndexedVector & operator=(const CoinPackedVectorBase & rhs);
+#endif
+   /** Copy the contents of one vector into another.  If multiplier is 1
+       It is the equivalent of = but if vectors are same size does
+       not re-allocate memory just clears and copies */
+   void copy(const CoinIndexedVector & rhs, double multiplier=1.0);
+
+   /** Borrow ownership of the arguments to this vector.
+       Size is the length of the unpacked elements vector. */
+  void borrowVector(int size, int numberIndices, int* inds, double* elems);
+
+   /** Return ownership of the arguments to this vector.
+       State after is empty .
+   */
+   void returnVector();
+
+   /** Set vector numberIndices, indices, and elements.
+       NumberIndices is the length of both the indices and elements vectors.
+       The indices and elements vectors are copied into this class instance's
+       member data. Assumed to have no duplicates */
+  void setVector(int numberIndices, const int * inds, const double * elems);
+  
+   /** Set vector size, indices, and elements.
+       Size is the length of the unpacked elements vector.
+       The indices and elements vectors are copied into this class instance's
+       member data. We do not check for duplicate indices */
+   void setVector(int size, int numberIndices, const int * inds, const double * elems);
+  
+   /** Elements set to have the same scalar value */
+  void setConstant(int size, const int * inds, double elems);
+  
+   /** Indices are not specified and are taken to be 0,1,...,size-1 */
+  void setFull(int size, const double * elems);
+
+   /** Set an existing element in the indexed vector
+       The first argument is the "index" into the elements() array
+   */
+   void setElement(int index, double element);
+
+   /// Insert an element into the vector
+   void insert(int index, double element);
+   /// Insert a nonzero element into the vector
+   inline void quickInsert(int index, double element)
+               {
+		 assert (!elements_[index]);
+		 indices_[nElements_++] = index;
+		 assert (nElements_<=capacity_);
+		 elements_[index] = element;
+	       }
+   /** Insert or if exists add an element into the vector
+       Any resulting zero elements will be made tiny */
+   void add(int index, double element);
+   /** Insert or if exists add an element into the vector
+       Any resulting zero elements will be made tiny.
+       This version does no checking */
+   inline void quickAdd(int index, double element)
+               {
+		 if (elements_[index]) {
+		   element += elements_[index];
+		   if ((element > 0 ? element : -element) >= COIN_INDEXED_TINY_ELEMENT) {
+		     elements_[index] = element;
+		   } else {
+		     elements_[index] = 1.0e-100;
+		   }
+		 } else if ((element > 0 ? element : -element) >= COIN_INDEXED_TINY_ELEMENT) {
+		   indices_[nElements_++] = index;
+		   assert (nElements_<=capacity_);
+		   elements_[index] = element;
+		 }
+	       }
+   /** Insert or if exists add an element into the vector
+       Any resulting zero elements will be made tiny.
+       This knows element is nonzero
+       This version does no checking */
+   inline void quickAddNonZero(int index, double element)
+               {
+		 assert (element);
+		 if (elements_[index]) {
+		   element += elements_[index];
+		   if ((element > 0 ? element : -element) >= COIN_INDEXED_TINY_ELEMENT) {
+		     elements_[index] = element;
+		   } else {
+		     elements_[index] = COIN_DBL_MIN;
+		   }
+		 } else {
+		   indices_[nElements_++] = index;
+		   assert (nElements_<=capacity_);
+		   elements_[index] = element;
+		 }
+	       }
+   /** Makes nonzero tiny.
+       This version does no checking */
+   inline void zero(int index)
+               {
+		 if (elements_[index]) 
+		   elements_[index] = COIN_DBL_MIN;
+	       }
+   /** set all small values to zero and return number remaining
+      - < tolerance => 0.0 */
+   int clean(double tolerance);
+   /// Same but packs down
+   int cleanAndPack(double tolerance);
+   /// Same but packs down and is safe (i.e. if order is odd)
+   int cleanAndPackSafe(double tolerance);
+  /// Mark as packed
+  inline void setPacked()
+  { packedMode_ = true;}
+#ifndef NDEBUG
+   /// For debug check vector is clear i.e. no elements
+   void checkClear();
+   /// For debug check vector is clean i.e. elements match indices
+   void checkClean();
+#else
+  inline void checkClear() {};
+  inline void checkClean() {};
+#endif
+   /// Scan dense region and set up indices (returns number found)
+   int scan();
+   /** Scan dense region from start to < end and set up indices
+       returns number found
+   */
+   int scan(int start, int end);
+  /** Scan dense region and set up indices (returns number found).
+      Only ones >= tolerance */
+   int scan(double tolerance);
+   /** Scan dense region from start to < end and set up indices
+       returns number found.  Only >= tolerance
+   */
+   int scan(int start, int end, double tolerance);
+   /// These are same but pack down
+   int scanAndPack();
+   int scanAndPack(int start, int end);
+   int scanAndPack(double tolerance);
+   int scanAndPack(int start, int end, double tolerance);
+   /// Create packed array
+   void createPacked(int number, const int * indices, 
+		    const double * elements);
+   /// Create unpacked array
+   void createUnpacked(int number, const int * indices, 
+		    const double * elements);
+   /// Create unpacked singleton
+   void createOneUnpackedElement(int index, double element);
+   /// This is mainly for testing - goes from packed to indexed
+   void expand();
+#ifndef CLP_NO_VECTOR
+   /// Append a CoinPackedVector to the end
+   void append(const CoinPackedVectorBase & caboose);
+#endif
+   /// Append a CoinIndexedVector to the end (with extra space)
+   void append(const CoinIndexedVector & caboose);
+   /// Append a CoinIndexedVector to the end and modify indices
+  void append(CoinIndexedVector & other,int adjustIndex,bool zapElements=false);
+
+   /// Swap values in positions i and j of indices and elements
+   void swap(int i, int j); 
+
+   /// Throw away all entries in rows >= newSize
+   void truncate(int newSize); 
+   ///  Print out
+   void print() const;
+   //@}
+   /**@name Arithmetic operators. */
+   //@{
+   /// add <code>value</code> to every entry
+   void operator+=(double value);
+   /// subtract <code>value</code> from every entry
+   void operator-=(double value);
+   /// multiply every entry by <code>value</code>
+   void operator*=(double value);
+   /// divide every entry by <code>value</code> (** 0 vanishes)
+   void operator/=(double value);
+   //@}
+
+   /**@name Comparison operators on two indexed vectors */
+   //@{
+#ifndef CLP_NO_VECTOR
+   /** Equal. Returns true if vectors have same length and corresponding
+       element of each vector is equal. */
+   bool operator==(const CoinPackedVectorBase & rhs) const;
+   /// Not equal
+   bool operator!=(const CoinPackedVectorBase & rhs) const;
+#endif
+   /** Equal. Returns true if vectors have same length and corresponding
+       element of each vector is equal. */
+   bool operator==(const CoinIndexedVector & rhs) const;
+   /// Not equal
+   bool operator!=(const CoinIndexedVector & rhs) const;
+   /// Equal with a tolerance (returns -1 or position of inequality). 
+   int isApproximatelyEqual(const CoinIndexedVector & rhs, double tolerance=1.0e-8) const;
+   //@}
+
+   /**@name Index methods */
+   //@{
+   /// Get value of maximum index
+   int getMaxIndex() const;
+   /// Get value of minimum index
+   int getMinIndex() const;
+   //@}
+
+
+   /**@name Sorting */
+   //@{ 
+   /** Sort the indexed storage vector (increasing indices). */
+   void sort()
+   { std::sort(indices_,indices_+nElements_); }
+
+   void sortIncrIndex()
+   { std::sort(indices_,indices_+nElements_); }
+
+   void sortDecrIndex();
+  
+   void sortIncrElement();
+
+   void sortDecrElement();
+   void sortPacked();
+
+   //@}
+
+  //#############################################################################
+
+  /**@name Arithmetic operators on packed vectors.
+
+   <strong>NOTE</strong>: These methods operate on those positions where at
+   least one of the arguments has a value listed. At those positions the
+   appropriate operation is executed, Otherwise the result of the operation is
+   considered 0.<br>
+   <strong>NOTE 2</strong>: Because these methods return an object (they can't
+   return a reference, though they could return a pointer...) they are
+   <em>very</em> inefficient...
+ */
+//@{
+/// Return the sum of two indexed vectors
+CoinIndexedVector operator+(
+			   const CoinIndexedVector& op2);
+
+/// Return the difference of two indexed vectors
+CoinIndexedVector operator-(
+			   const CoinIndexedVector& op2);
+
+/// Return the element-wise product of two indexed vectors
+CoinIndexedVector operator*(
+			   const CoinIndexedVector& op2);
+
+/// Return the element-wise ratio of two indexed vectors (0.0/0.0 => 0.0) (0 vanishes)
+CoinIndexedVector operator/(
+			   const CoinIndexedVector& op2);
+/// The sum of two indexed vectors
+void operator+=(const CoinIndexedVector& op2);
+
+/// The difference of two indexed vectors
+void operator-=( const CoinIndexedVector& op2);
+
+/// The element-wise product of two indexed vectors
+void operator*=(const CoinIndexedVector& op2);
+
+/// The element-wise ratio of two indexed vectors (0.0/0.0 => 0.0) (0 vanishes)
+void operator/=(const CoinIndexedVector& op2);
+//@}
+
+   /**@name Memory usage */
+   //@{
+   /** Reserve space.
+       If one knows the eventual size of the indexed vector,
+       then it may be more efficient to reserve the space.
+   */
+   void reserve(int n);
+   /** capacity returns the size which could be accomodated without
+       having to reallocate storage.
+   */
+   int capacity() const { return capacity_; }
+   /// Sets packed mode
+   inline void setPackedMode(bool yesNo)
+   { packedMode_=yesNo;}
+   /// Gets packed mode
+   inline bool packedMode() const
+   { return packedMode_;}
+   //@}
+
+   /**@name Constructors and destructors */
+   //@{
+   /** Default constructor */
+   CoinIndexedVector();
+   /** Alternate Constructors - set elements to vector of doubles */
+  CoinIndexedVector(int size, const int * inds, const double * elems);
+   /** Alternate Constructors - set elements to same scalar value */
+  CoinIndexedVector(int size, const int * inds, double element);
+   /** Alternate Constructors - construct full storage with indices 0 through
+       size-1. */
+  CoinIndexedVector(int size, const double * elements);
+   /** Alternate Constructors - just size */
+  CoinIndexedVector(int size);
+   /** Copy constructor. */
+   CoinIndexedVector(const CoinIndexedVector &);
+   /** Copy constructor.2 */
+   CoinIndexedVector(const CoinIndexedVector *);
+#ifndef CLP_NO_VECTOR
+   /** Copy constructor <em>from a PackedVectorBase</em>. */
+   CoinIndexedVector(const CoinPackedVectorBase & rhs);
+#endif
+   /** Destructor */
+   ~CoinIndexedVector ();
+   //@}
+    
+private:
+   /**@name Private methods */
+   //@{  
+   /// Copy internal data
+   void gutsOfSetVector(int size,
+			const int * inds, const double * elems);
+   void gutsOfSetVector(int size, int numberIndices,
+			const int * inds, const double * elems);
+   void gutsOfSetPackedVector(int size, int numberIndices,
+			const int * inds, const double * elems);
+   ///
+   void gutsOfSetConstant(int size,
+			  const int * inds, double value);
+   //@}
+
+protected:
+   /**@name Private member data */
+   //@{
+   /// Vector indices
+   int * indices_;
+   ///Vector elements
+   double * elements_;
+   /// Size of indices and packed elements vectors
+   int nElements_;
+   /// Amount of memory allocated for indices_, and elements_.
+   int capacity_;
+   ///  Offset to get where new allocated array
+   int offset_;
+   /// If true then is operating in packed mode
+   bool packedMode_;
+   //@}
+};
+
+//#############################################################################
+/** A function that tests the methods in the CoinIndexedVector class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void
+CoinIndexedVectorUnitTest();
+/** Pointer with length in bytes
+    
+    This has a pointer to an array and the number of bytes in array.
+    If number of bytes==-1 then
+    CoinConditionalNew deletes existing pointer and returns new pointer
+    of correct size (and number bytes still -1).
+    CoinConditionalDelete deletes existing pointer and NULLs it.
+    So behavior is as normal (apart from New deleting pointer which will have
+    no effect with good coding practices.
+    If number of bytes >=0 then
+    CoinConditionalNew just returns existing pointer if array big enough
+    otherwise deletes existing pointer, allocates array with spare 1%+64 bytes
+    and updates number of bytes
+    CoinConditionalDelete sets number of bytes = -size-2 and then array 
+    returns NULL
+*/
+class CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_; }
+  /// Get the size
+  inline int rawSize() const 
+  { return size_; }
+  /// See if persistence already on
+  inline bool switchedOn() const 
+  { return size_!=-1; }
+  /// Get the capacity (just read it)
+  inline int capacity() const 
+  { return (size_>-2) ? size_ : (-size_)-2; }
+  /// Set the capacity to >=0 if <=-2
+  inline void setCapacity() 
+  { if (size_<=-2) size_ = (-size_)-2; }
+  /// Get Array
+  inline const char * array() const 
+  { return (size_>-2) ? array_ : NULL; }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value; }
+  /// Set the size to -1
+  inline void switchOff() 
+  { size_ = -1; }
+  /// Set the size to -2 and alignment
+  inline void switchOn(int alignment=3) 
+  { size_ = -2; alignment_=alignment;}
+  /// Does what is needed to set persistence
+  void setPersistence(int flag,int currentLength);
+  /// Zero out array
+  void clear();
+  /// Swaps memory between two members
+  void swap(CoinArrayWithLength & other);
+  /// Extend a persistent array keeping data (size in bytes)
+  void extend(int newSize);
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  char * conditionalNew(long sizeWanted); 
+  /// Conditionally deletes
+  void conditionalDelete();
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinArrayWithLength()
+    : array_(NULL),size_(-1),offset_(0),alignment_(0)
+  { }
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinArrayWithLength(int size)
+    : size_(-1),offset_(0),alignment_(0)
+  { array_=new char [size];}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      mode>0 size_ set to size and zeroed
+      if size<=0 just does alignment
+      If abs(mode) >2 then align on that as power of 2
+  */
+  CoinArrayWithLength(int size, int mode);
+  /** Copy constructor. */
+  CoinArrayWithLength(const CoinArrayWithLength & rhs);
+  /** Copy constructor.2 */
+  CoinArrayWithLength(const CoinArrayWithLength * rhs);
+  /** Assignment operator. */
+  CoinArrayWithLength& operator=(const CoinArrayWithLength & rhs);
+  /** Assignment with length (if -1 use internal length) */
+  void copy(const CoinArrayWithLength & rhs, int numberBytes=-1);
+  /** Assignment with length - does not copy */
+  void allocate(const CoinArrayWithLength & rhs, int numberBytes);
+  /** Destructor */
+  ~CoinArrayWithLength ();
+  /// Get array with alignment
+  void getArray(int size);
+  /// Really get rid of array with alignment
+  void reallyFreeArray();
+  /// Get enough space (if more needed then do at least needed)
+  void getCapacity(int numberBytes,int numberIfNeeded=-1);
+  //@}
+  
+protected:
+  /**@name Private member data */
+  //@{
+  /// Array
+  char * array_;
+  /// Size of array in bytes
+  CoinBigIndex size_;
+  /// Offset of array
+  int offset_;
+  /// Alignment wanted (power of 2)
+  int alignment_;
+  //@}
+};
+/// double * version
+
+class CoinDoubleArrayWithLength : public CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_/CoinSizeofAsInt(double); }
+  /// Get Array
+  inline double * array() const 
+  { return reinterpret_cast<double *> ((size_>-2) ? array_ : NULL); }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value*CoinSizeofAsInt(double); }
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  inline double * conditionalNew(int sizeWanted)
+  { return reinterpret_cast<double *> ( CoinArrayWithLength::conditionalNew(sizeWanted>=0 ? static_cast<long> ((sizeWanted)*CoinSizeofAsInt(double)) : -1)); }
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinDoubleArrayWithLength()
+  { array_=NULL; size_=-1;}
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinDoubleArrayWithLength(int size)
+  { array_=new char [size*CoinSizeofAsInt(double)]; size_=-1;}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      1 size_ set to size and zeroed
+  */
+  inline CoinDoubleArrayWithLength(int size, int mode)
+    : CoinArrayWithLength(size*CoinSizeofAsInt(double),mode) {}
+  /** Copy constructor. */
+  inline CoinDoubleArrayWithLength(const CoinDoubleArrayWithLength & rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Copy constructor.2 */
+  inline CoinDoubleArrayWithLength(const CoinDoubleArrayWithLength * rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Assignment operator. */
+  inline CoinDoubleArrayWithLength& operator=(const CoinDoubleArrayWithLength & rhs)
+  { CoinArrayWithLength::operator=(rhs);  return *this;}
+  //@}
+};
+/// CoinFactorizationDouble * version
+
+class CoinFactorizationDoubleArrayWithLength : public CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_/CoinSizeofAsInt(CoinFactorizationDouble); }
+  /// Get Array
+  inline CoinFactorizationDouble * array() const 
+  { return reinterpret_cast<CoinFactorizationDouble *> ((size_>-2) ? array_ : NULL); }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value*CoinSizeofAsInt(CoinFactorizationDouble); }
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  inline CoinFactorizationDouble * conditionalNew(int sizeWanted)
+  { return reinterpret_cast<CoinFactorizationDouble *> (CoinArrayWithLength::conditionalNew(sizeWanted>=0 ? static_cast<long> (( sizeWanted)*CoinSizeofAsInt(CoinFactorizationDouble)) : -1)); }
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinFactorizationDoubleArrayWithLength()
+  { array_=NULL; size_=-1;}
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinFactorizationDoubleArrayWithLength(int size)
+  { array_=new char [size*CoinSizeofAsInt(CoinFactorizationDouble)]; size_=-1;}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      1 size_ set to size and zeroed
+  */
+  inline CoinFactorizationDoubleArrayWithLength(int size, int mode)
+    : CoinArrayWithLength(size*CoinSizeofAsInt(CoinFactorizationDouble),mode) {}
+  /** Copy constructor. */
+  inline CoinFactorizationDoubleArrayWithLength(const CoinFactorizationDoubleArrayWithLength & rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Copy constructor.2 */
+  inline CoinFactorizationDoubleArrayWithLength(const CoinFactorizationDoubleArrayWithLength * rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Assignment operator. */
+  inline CoinFactorizationDoubleArrayWithLength& operator=(const CoinFactorizationDoubleArrayWithLength & rhs)
+  { CoinArrayWithLength::operator=(rhs);  return *this;}
+  //@}
+};
+/// CoinFactorizationLongDouble * version
+
+class CoinFactorizationLongDoubleArrayWithLength : public CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_/CoinSizeofAsInt(long double); }
+  /// Get Array
+  inline long double * array() const 
+  { return reinterpret_cast<long double *> ((size_>-2) ? array_ : NULL); }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value*CoinSizeofAsInt(long double); }
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  inline long double * conditionalNew(int sizeWanted)
+  { return reinterpret_cast<long double *> (CoinArrayWithLength::conditionalNew(sizeWanted>=0 ? static_cast<long> (( sizeWanted)*CoinSizeofAsInt(long double)) : -1)); }
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinFactorizationLongDoubleArrayWithLength()
+  { array_=NULL; size_=-1;}
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinFactorizationLongDoubleArrayWithLength(int size)
+  { array_=new char [size*CoinSizeofAsInt(long double)]; size_=-1;}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      1 size_ set to size and zeroed
+  */
+  inline CoinFactorizationLongDoubleArrayWithLength(int size, int mode)
+    : CoinArrayWithLength(size*CoinSizeofAsInt(long double),mode) {}
+  /** Copy constructor. */
+  inline CoinFactorizationLongDoubleArrayWithLength(const CoinFactorizationLongDoubleArrayWithLength & rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Copy constructor.2 */
+  inline CoinFactorizationLongDoubleArrayWithLength(const CoinFactorizationLongDoubleArrayWithLength * rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Assignment operator. */
+  inline CoinFactorizationLongDoubleArrayWithLength& operator=(const CoinFactorizationLongDoubleArrayWithLength & rhs)
+  { CoinArrayWithLength::operator=(rhs);  return *this;}
+  //@}
+};
+/// int * version
+
+class CoinIntArrayWithLength : public CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_/CoinSizeofAsInt(int); }
+  /// Get Array
+  inline int * array() const 
+  { return reinterpret_cast<int *> ((size_>-2) ? array_ : NULL); }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value*CoinSizeofAsInt(int); }
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  inline int * conditionalNew(int sizeWanted)
+  { return reinterpret_cast<int *> (CoinArrayWithLength::conditionalNew(sizeWanted>=0 ? static_cast<long> (( sizeWanted)*CoinSizeofAsInt(int)) : -1)); }
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinIntArrayWithLength()
+  { array_=NULL; size_=-1;}
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinIntArrayWithLength(int size)
+  { array_=new char [size*CoinSizeofAsInt(int)]; size_=-1;}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      1 size_ set to size and zeroed
+  */
+  inline CoinIntArrayWithLength(int size, int mode)
+    : CoinArrayWithLength(size*CoinSizeofAsInt(int),mode) {}
+  /** Copy constructor. */
+  inline CoinIntArrayWithLength(const CoinIntArrayWithLength & rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Copy constructor.2 */
+  inline CoinIntArrayWithLength(const CoinIntArrayWithLength * rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Assignment operator. */
+  inline CoinIntArrayWithLength& operator=(const CoinIntArrayWithLength & rhs)
+  { CoinArrayWithLength::operator=(rhs);  return *this;}
+  //@}
+};
+/// CoinBigIndex * version
+
+class CoinBigIndexArrayWithLength : public CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_/CoinSizeofAsInt(CoinBigIndex); }
+  /// Get Array
+  inline CoinBigIndex * array() const 
+  { return reinterpret_cast<CoinBigIndex *> ((size_>-2) ? array_ : NULL); }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value*CoinSizeofAsInt(CoinBigIndex); }
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  inline CoinBigIndex * conditionalNew(int sizeWanted)
+  { return reinterpret_cast<CoinBigIndex *> (CoinArrayWithLength::conditionalNew(sizeWanted>=0 ? static_cast<long> (( sizeWanted)*CoinSizeofAsInt(CoinBigIndex)) : -1)); }
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinBigIndexArrayWithLength()
+  { array_=NULL; size_=-1;}
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinBigIndexArrayWithLength(int size)
+  { array_=new char [size*CoinSizeofAsInt(CoinBigIndex)]; size_=-1;}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      1 size_ set to size and zeroed
+  */
+  inline CoinBigIndexArrayWithLength(int size, int mode)
+    : CoinArrayWithLength(size*CoinSizeofAsInt(CoinBigIndex),mode) {}
+  /** Copy constructor. */
+  inline CoinBigIndexArrayWithLength(const CoinBigIndexArrayWithLength & rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Copy constructor.2 */
+  inline CoinBigIndexArrayWithLength(const CoinBigIndexArrayWithLength * rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Assignment operator. */
+  inline CoinBigIndexArrayWithLength& operator=(const CoinBigIndexArrayWithLength & rhs)
+  { CoinArrayWithLength::operator=(rhs);  return *this;}
+  //@}
+};
+/// unsigned int * version
+
+class CoinUnsignedIntArrayWithLength : public CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_/CoinSizeofAsInt(unsigned int); }
+  /// Get Array
+  inline unsigned int * array() const 
+  { return reinterpret_cast<unsigned int *> ((size_>-2) ? array_ : NULL); }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value*CoinSizeofAsInt(unsigned int); }
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  inline unsigned int * conditionalNew(int sizeWanted)
+  { return reinterpret_cast<unsigned int *> (CoinArrayWithLength::conditionalNew(sizeWanted>=0 ? static_cast<long> (( sizeWanted)*CoinSizeofAsInt(unsigned int)) : -1)); }
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinUnsignedIntArrayWithLength()
+  { array_=NULL; size_=-1;}
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinUnsignedIntArrayWithLength(int size)
+  { array_=new char [size*CoinSizeofAsInt(unsigned int)]; size_=-1;}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      1 size_ set to size and zeroed
+  */
+  inline CoinUnsignedIntArrayWithLength(int size, int mode)
+    : CoinArrayWithLength(size*CoinSizeofAsInt(unsigned int),mode) {}
+  /** Copy constructor. */
+  inline CoinUnsignedIntArrayWithLength(const CoinUnsignedIntArrayWithLength & rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Copy constructor.2 */
+  inline CoinUnsignedIntArrayWithLength(const CoinUnsignedIntArrayWithLength * rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Assignment operator. */
+  inline CoinUnsignedIntArrayWithLength& operator=(const CoinUnsignedIntArrayWithLength & rhs)
+  { CoinArrayWithLength::operator=(rhs);  return *this;}
+  //@}
+};
+/// void * version
+
+class CoinVoidStarArrayWithLength : public CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_/CoinSizeofAsInt(void *); }
+  /// Get Array
+  inline void ** array() const 
+  { return reinterpret_cast<void **> ((size_>-2) ? array_ : NULL); }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value*CoinSizeofAsInt(void *); }
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  inline void ** conditionalNew(int sizeWanted)
+  { return reinterpret_cast<void **> ( CoinArrayWithLength::conditionalNew(sizeWanted>=0 ? static_cast<long> ((sizeWanted)*CoinSizeofAsInt(void *)) : -1)); }
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinVoidStarArrayWithLength()
+  { array_=NULL; size_=-1;}
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinVoidStarArrayWithLength(int size)
+  { array_=new char [size*CoinSizeofAsInt(void *)]; size_=-1;}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      1 size_ set to size and zeroed
+  */
+  inline CoinVoidStarArrayWithLength(int size, int mode)
+    : CoinArrayWithLength(size*CoinSizeofAsInt(void *),mode) {}
+  /** Copy constructor. */
+  inline CoinVoidStarArrayWithLength(const CoinVoidStarArrayWithLength & rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Copy constructor.2 */
+  inline CoinVoidStarArrayWithLength(const CoinVoidStarArrayWithLength * rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Assignment operator. */
+  inline CoinVoidStarArrayWithLength& operator=(const CoinVoidStarArrayWithLength & rhs)
+  { CoinArrayWithLength::operator=(rhs);  return *this;}
+  //@}
+};
+/// arbitrary version
+
+class CoinArbitraryArrayWithLength : public CoinArrayWithLength {
+  
+public:
+  /**@name Get methods. */
+  //@{
+  /// Get the size
+  inline int getSize() const 
+  { return size_/lengthInBytes_; }
+  /// Get Array
+  inline void ** array() const 
+  { return reinterpret_cast<void **> ((size_>-2) ? array_ : NULL); }
+  //@}
+  
+  /**@name Set methods */
+  //@{
+  /// Set the size
+  inline void setSize(int value) 
+  { size_ = value*lengthInBytes_; }
+  //@}
+  
+  /**@name Condition methods */
+  //@{
+  /// Conditionally gets new array
+  inline char * conditionalNew(int length, int sizeWanted)
+  { lengthInBytes_=length;return reinterpret_cast<char *> ( CoinArrayWithLength::conditionalNew(sizeWanted>=0 ? static_cast<long> 
+									  ((sizeWanted)*lengthInBytes_) : -1)); }
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /** Default constructor - NULL*/
+  inline CoinArbitraryArrayWithLength(int length=1)
+  { array_=NULL; size_=-1;lengthInBytes_=length;}
+  /** Alternate Constructor - length in bytes - size_ -1 */
+  inline CoinArbitraryArrayWithLength(int length, int size)
+  { array_=new char [size*length]; size_=-1; lengthInBytes_=length;}
+  /** Alternate Constructor - length in bytes 
+      mode -  0 size_ set to size
+      1 size_ set to size and zeroed
+  */
+  inline CoinArbitraryArrayWithLength(int length, int size, int mode)
+    : CoinArrayWithLength(size*length,mode) {lengthInBytes_=length;}
+  /** Copy constructor. */
+  inline CoinArbitraryArrayWithLength(const CoinArbitraryArrayWithLength & rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Copy constructor.2 */
+  inline CoinArbitraryArrayWithLength(const CoinArbitraryArrayWithLength * rhs)
+    : CoinArrayWithLength(rhs) {}
+  /** Assignment operator. */
+  inline CoinArbitraryArrayWithLength& operator=(const CoinArbitraryArrayWithLength & rhs)
+  { CoinArrayWithLength::operator=(rhs);  return *this;}
+  //@}
+
+protected:
+  /**@name Private member data */
+  //@{
+  /// Length in bytes
+  int lengthInBytes_;
+   //@}
+};
+class CoinPartitionedVector : public CoinIndexedVector {
+  
+public:
+#ifndef COIN_PARTITIONS
+#define COIN_PARTITIONS 8
+#endif
+   /**@name Get methods. */
+   //@{
+   /// Get the size of a partition
+   inline int getNumElements(int partition) const { assert (partition<COIN_PARTITIONS);
+     return numberElementsPartition_[partition]; }
+   /// Get number of partitions
+   inline int getNumPartitions() const
+  { return numberPartitions_; }
+   /// Get the size
+   inline int getNumElements() const { return nElements_; }
+   /// Get starts
+  inline int startPartition(int partition) const  { assert (partition<=COIN_PARTITIONS);
+    return startPartition_[partition]; }
+   /// Get starts
+  inline const int * startPartitions() const
+  { return startPartition_; }
+   //@}
+ 
+   //-------------------------------------------------------------------
+   // Set indices and elements
+   //------------------------------------------------------------------- 
+   /**@name Set methods */
+   //@{
+   /// Set the size of a partition
+  inline void setNumElementsPartition(int partition, int value) { assert (partition<COIN_PARTITIONS);
+    if (numberPartitions_) numberElementsPartition_[partition]=value; }
+   /// Set the size of a partition (just for a tiny while)
+  inline void setTempNumElementsPartition(int partition, int value) { assert (partition<COIN_PARTITIONS);
+    numberElementsPartition_[partition]=value; }
+  /// Add up number of elements in partitions
+  void computeNumberElements();
+  /// Add up number of elements in partitions and pack and get rid of partitions
+  void compact();
+   /** Reserve space.
+   */
+   void reserve(int n);
+  /// Setup partitions (needs end as well)
+  void setPartitions(int number,const int * starts);
+   /// Reset the vector (as if were just created an empty vector). Gets rid of partitions
+   void clearAndReset();
+   /// Reset the vector (as if were just created an empty vector). Keeps partitions
+   void clearAndKeep();
+   /// Clear a partition.
+   void clearPartition(int partition);
+#ifndef NDEBUG
+   /// For debug check vector is clear i.e. no elements
+   void checkClear();
+   /// For debug check vector is clean i.e. elements match indices
+   void checkClean();
+#else
+  inline void checkClear() {};
+  inline void checkClean() {};
+#endif
+   /// Scan dense region and set up indices (returns number found)
+  int scan(int partition, double tolerance=0.0);
+   /** Scan dense region from start to < end and set up indices
+       returns number found
+   */
+   ///  Print out
+   void print() const;
+   //@}
+ 
+   /**@name Sorting */
+   //@{ 
+   /** Sort the indexed storage vector (increasing indices). */
+  void sort();
+   //@}
+
+   /**@name Constructors and destructors (not all wriiten) */
+   //@{
+   /** Default constructor */
+   CoinPartitionedVector();
+   /** Alternate Constructors - set elements to vector of doubles */
+  CoinPartitionedVector(int size, const int * inds, const double * elems);
+   /** Alternate Constructors - set elements to same scalar value */
+  CoinPartitionedVector(int size, const int * inds, double element);
+   /** Alternate Constructors - construct full storage with indices 0 through
+       size-1. */
+  CoinPartitionedVector(int size, const double * elements);
+   /** Alternate Constructors - just size */
+  CoinPartitionedVector(int size);
+   /** Copy constructor. */
+   CoinPartitionedVector(const CoinPartitionedVector &);
+   /** Copy constructor.2 */
+   CoinPartitionedVector(const CoinPartitionedVector *);
+   /** Assignment operator. */
+   CoinPartitionedVector & operator=(const CoinPartitionedVector &);
+   /** Destructor */
+   ~CoinPartitionedVector ();
+   //@}
+protected:
+   /**@name Private member data */
+   //@{
+   /// Starts
+   int startPartition_[COIN_PARTITIONS+1];
+   /// Size of indices in a partition
+   int numberElementsPartition_[COIN_PARTITIONS];
+  /// Number of partitions (0 means off)
+  int numberPartitions_;
+   //@}
+};
+#endif
diff --git a/cbits/coin/CoinLpIO.cpp b/cbits/coin/CoinLpIO.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinLpIO.cpp
@@ -0,0 +1,2527 @@
+/* $Id: CoinLpIO.cpp 1652 2013-10-18 10:35:37Z stefan $ */
+// Last edit: 11/5/08
+//
+// Name:     CoinLpIO.cpp; Support for Lp files
+// Author:   Francois Margot
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+// Date:     12/28/03
+//-----------------------------------------------------------------------------
+// Copyright (C) 2003, Francois Margot, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinUtilsConfig.h"
+
+#include <cmath>
+#include <cfloat>
+#include <cctype>
+#include <cassert>
+#include <string>
+#include <cstdarg>
+
+#include "CoinError.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinLpIO.hpp"
+#include "CoinFinite.hpp"
+
+using namespace std;
+
+//#define LPIO_DEBUG
+
+/************************************************************************/
+
+CoinLpIO::CoinLpIO() :
+  problemName_(CoinStrdup("")),
+  defaultHandler_(true),
+  numberRows_(0),
+  numberColumns_(0),
+  numberElements_(0),
+  rowsense_(NULL),
+  rhs_(NULL),
+  rowrange_(NULL),
+  matrixByRow_(NULL),
+  matrixByColumn_(NULL),
+  rowlower_(NULL),
+  rowupper_(NULL),
+  collower_(NULL),
+  colupper_(NULL),
+  objective_(NULL),
+  objectiveOffset_(0),
+  integerType_(NULL),
+  fileName_(NULL),
+  infinity_(COIN_DBL_MAX),
+  numberAcross_(10),
+  epsilon_(1e-5),
+  decimals_(5),
+  objName_(NULL)
+{
+  card_previous_names_[0] = 0;
+  card_previous_names_[1] = 0;
+  previous_names_[0] = NULL;
+  previous_names_[1] = NULL;
+
+  maxHash_[0]=0;
+  numberHash_[0]=0;
+  hash_[0] = NULL;
+  names_[0] = NULL;
+  maxHash_[1] = 0;
+  numberHash_[1] = 0;
+  hash_[1] = NULL;
+  names_[1] = NULL;
+  handler_ = new CoinMessageHandler();
+  messages_ = CoinMessage();
+}
+
+//-------------------------------------------------------------------
+// Copy constructor
+//-------------------------------------------------------------------
+CoinLpIO::CoinLpIO(const CoinLpIO& rhs)
+    :
+    problemName_(CoinStrdup("")),
+    defaultHandler_(true),
+    numberRows_(0),
+    numberColumns_(0),
+    numberElements_(0),
+    rowsense_(NULL),
+    rhs_(NULL),
+    rowrange_(NULL),
+    matrixByRow_(NULL),
+    matrixByColumn_(NULL),
+    rowlower_(NULL),
+    rowupper_(NULL),
+    collower_(NULL),
+    colupper_(NULL),
+    objective_(NULL),
+    objectiveOffset_(0.0),
+    integerType_(NULL),
+    fileName_(CoinStrdup("")),
+    infinity_(COIN_DBL_MAX),
+    numberAcross_(10),
+    epsilon_(1e-5),
+    objName_(NULL)
+{
+    card_previous_names_[0] = 0;
+    card_previous_names_[1] = 0;
+    previous_names_[0] = NULL;
+    previous_names_[1] = NULL;
+    maxHash_[0] = 0;
+    numberHash_[0] = 0;
+    hash_[0] = NULL;
+    names_[0] = NULL;
+    maxHash_[1] = 0;
+    numberHash_[1] = 0;
+    hash_[1] = NULL;
+    names_[1] = NULL;
+ 
+    if ( rhs.rowlower_ != NULL || rhs.collower_ != NULL) {
+       gutsOfCopy(rhs);
+    }
+ 
+    defaultHandler_ = rhs.defaultHandler_;
+ 
+    if (defaultHandler_) {
+       handler_ = new CoinMessageHandler(*rhs.handler_);
+    } else {
+       handler_ = rhs.handler_;
+    }
+ 
+    messages_ = CoinMessage();
+}
+
+
+void CoinLpIO::gutsOfCopy(const CoinLpIO& rhs)
+{
+    defaultHandler_ = rhs.defaultHandler_;
+ 
+    if (rhs.matrixByRow_) {
+       matrixByRow_ = new CoinPackedMatrix(*(rhs.matrixByRow_));
+    }
+ 
+    numberElements_ = rhs.numberElements_;
+    numberRows_ = rhs.numberRows_;
+    numberColumns_ = rhs.numberColumns_;
+    decimals_ = rhs.decimals_;
+ 
+    if (rhs.rowlower_) {
+       rowlower_ = reinterpret_cast<double*> (malloc(numberRows_ * sizeof(double)));
+       rowupper_ = reinterpret_cast<double*> (malloc(numberRows_ * sizeof(double)));
+       memcpy(rowlower_, rhs.rowlower_, numberRows_ * sizeof(double));
+       memcpy(rowupper_, rhs.rowupper_, numberRows_ * sizeof(double));
+       rowrange_ = reinterpret_cast<double *> (malloc(numberRows_*sizeof(double)));
+       rowsense_ = reinterpret_cast<char *> (malloc(numberRows_*sizeof(char)));
+       rhs_ = reinterpret_cast<double *> (malloc(numberRows_*sizeof(double)));
+       memcpy(rowrange_,rhs.getRowRange(),numberRows_*sizeof(double));
+       memcpy(rowsense_,rhs.getRowSense(),numberRows_*sizeof(char));
+       memcpy(rhs_,rhs.getRightHandSide(),numberRows_*sizeof(double));
+    }
+ 
+    if (rhs.collower_) {
+       collower_ = reinterpret_cast<double*> (malloc(numberColumns_ * sizeof(double)));
+       colupper_ = reinterpret_cast<double*> (malloc(numberColumns_ * sizeof(double)));
+       objective_ = reinterpret_cast<double*> (malloc(numberColumns_ * sizeof(double)));
+       memcpy(collower_, rhs.collower_, numberColumns_ * sizeof(double));
+       memcpy(colupper_, rhs.colupper_, numberColumns_ * sizeof(double));
+       memcpy(objective_, rhs.objective_, numberColumns_ * sizeof(double));
+    }
+ 
+    if (rhs.integerType_) {
+       integerType_ = reinterpret_cast<char*> (malloc (numberColumns_ * sizeof(char)));
+       memcpy(integerType_, rhs.integerType_, numberColumns_ * sizeof(char));
+    }
+ 
+    free(fileName_);
+    free(problemName_);
+    fileName_ = CoinStrdup(rhs.fileName_);
+    problemName_ = CoinStrdup(rhs.problemName_);
+    numberHash_[0] = rhs.numberHash_[0];
+    numberHash_[1] = rhs.numberHash_[1];
+    maxHash_[0] = rhs.maxHash_[0];
+    maxHash_[1] = rhs.maxHash_[1];
+    infinity_ = rhs.infinity_;
+    numberAcross_ = rhs.numberAcross_;
+    objectiveOffset_ = rhs.objectiveOffset_;
+    int section;
+ 
+    for (section = 0; section < 2; section++) {
+       if (numberHash_[section]) {
+          char** names2 = rhs.names_[section];
+          names_[section] = reinterpret_cast<char**> (malloc(maxHash_[section] *
+                            sizeof(char*)));
+          char** names = names_[section];
+          int i;
+ 
+          for (i = 0; i < numberHash_[section]; i++) {
+             names[i] = CoinStrdup(names2[i]);
+          }
+ 
+          hash_[section] = new CoinHashLink[maxHash_[section]];
+          std::memcpy(hash_[section], rhs.hash_[section], maxHash_[section]*sizeof(CoinHashLink));
+       }
+    }
+ }
+
+CoinLpIO &
+CoinLpIO::operator=(const CoinLpIO& rhs)
+{
+    if (this != &rhs) {
+       gutsOfDestructor();
+ 
+       if ( rhs.rowlower_ != NULL || rhs.collower_ != NULL) {
+          gutsOfCopy(rhs);
+       }
+ 
+       defaultHandler_ = rhs.defaultHandler_;
+ 
+       if (defaultHandler_) {
+          handler_ = new CoinMessageHandler(*rhs.handler_);
+       } else {
+          handler_ = rhs.handler_;
+       }
+ 
+       messages_ = CoinMessage();
+    }
+ 
+    return *this;
+}
+
+
+void CoinLpIO::gutsOfDestructor()
+ {
+    freeAll();
+ 
+    if (defaultHandler_) {
+       delete handler_;
+       handler_ = NULL;
+    }
+}
+
+
+
+/************************************************************************/
+CoinLpIO::~CoinLpIO() {
+  stopHash(0);
+  stopHash(1);
+  freeAll();
+  if (defaultHandler_) {
+    delete handler_;
+    handler_ = NULL; 
+  }
+}
+
+/************************************************************************/
+void
+CoinLpIO::freePreviousNames(const int section) {
+
+  int j;
+
+  if(previous_names_[section] != NULL) {
+    for(j=0; j<card_previous_names_[section]; j++) {
+      free(previous_names_[section][j]);
+    }
+    free(previous_names_[section]);
+  }
+  previous_names_[section] = NULL;
+  card_previous_names_[section] = 0;
+} /* freePreviousNames */
+
+/************************************************************************/
+void
+CoinLpIO::freeAll() {
+
+  delete matrixByColumn_;
+  matrixByColumn_ = NULL; 
+  delete matrixByRow_;
+  matrixByRow_ = NULL; 
+  free(rowupper_);
+  rowupper_ = NULL;
+  free(rowlower_);
+  rowlower_ = NULL;
+  free(colupper_);
+  colupper_ = NULL;
+  free(collower_);
+  collower_ = NULL;
+  free(rhs_);
+  rhs_ = NULL;
+  free(rowrange_);
+  rowrange_ = NULL;
+  free(rowsense_);
+  rowsense_ = NULL;
+  free(objective_);
+  objective_ = NULL;
+  free(integerType_);
+  integerType_ = NULL;
+  free(problemName_);
+  problemName_ = NULL;
+  free(fileName_);
+  fileName_ = NULL;
+
+  freePreviousNames(0);
+  freePreviousNames(1);
+}
+
+/*************************************************************************/
+const char * CoinLpIO::getProblemName() const
+{
+  return problemName_;
+}
+
+void
+CoinLpIO::setProblemName (const char *name)
+{
+  free(problemName_) ;
+  problemName_ = CoinStrdup(name);
+}
+
+/*************************************************************************/
+int CoinLpIO::getNumCols() const
+{
+  return numberColumns_;
+}
+
+/*************************************************************************/
+int CoinLpIO::getNumRows() const
+{
+  return numberRows_;
+}
+
+/*************************************************************************/
+int CoinLpIO::getNumElements() const
+{
+  return numberElements_;
+}
+
+/*************************************************************************/
+const double * CoinLpIO::getColLower() const
+{
+  return collower_;
+}
+
+/*************************************************************************/
+const double * CoinLpIO::getColUpper() const
+{
+  return colupper_;
+}
+
+/*************************************************************************/
+const double * CoinLpIO::getRowLower() const
+{
+  return rowlower_;
+}
+
+/*************************************************************************/
+const double * CoinLpIO::getRowUpper() const
+{
+  return rowupper_;
+}
+
+/*************************************************************************/
+/** A quick inlined function to convert from lb/ub style constraint
+    definition to sense/rhs/range style */
+inline void
+CoinLpIO::convertBoundToSense(const double lower, const double upper,
+			      char& sense, double& right,
+			      double& range) const
+{
+  range = 0.0;
+  if (lower > -infinity_) {
+    if (upper < infinity_) {
+      right = upper;
+      if (upper==lower) {
+        sense = 'E';
+      } else {
+        sense = 'R';
+        range = upper - lower;
+      }
+    } else {
+      sense = 'G';
+      right = lower;
+    }
+  } else {
+    if (upper < infinity_) {
+      sense = 'L';
+      right = upper;
+    } else {
+      sense = 'N';
+      right = 0.0;
+    }
+  }
+}
+
+/*************************************************************************/
+ const char * CoinLpIO::getRowSense() const
+{
+  if(rowsense_  == NULL) {
+    int nr=numberRows_;
+    rowsense_ = reinterpret_cast<char *> (malloc(nr*sizeof(char)));
+    
+    double dum1,dum2;
+    int i;
+    for(i=0; i<nr; i++) {
+      convertBoundToSense(rowlower_[i],rowupper_[i],rowsense_[i],dum1,dum2);
+    }
+  }
+  return rowsense_;
+}
+
+/*************************************************************************/
+const double * CoinLpIO::getRightHandSide() const
+{
+  if(rhs_==NULL) {
+    int nr=numberRows_;
+    rhs_ = reinterpret_cast<double *> (malloc(nr*sizeof(double)));
+
+    char dum1;
+    double dum2;
+    int i;
+    for (i=0; i<nr; i++) {
+      convertBoundToSense(rowlower_[i],rowupper_[i],dum1,rhs_[i],dum2);
+    }
+  }
+  return rhs_;
+}
+
+/*************************************************************************/
+const double * CoinLpIO::getRowRange() const
+{
+  if (rowrange_ == NULL) {
+    int nr=numberRows_;
+    rowrange_ = reinterpret_cast<double *> (malloc(nr*sizeof(double)));
+    std::fill(rowrange_,rowrange_+nr,0.0);
+
+    char dum1;
+    double dum2;
+    int i;
+    for (i=0; i<nr; i++) {
+      convertBoundToSense(rowlower_[i],rowupper_[i],dum1,dum2,rowrange_[i]);
+    }
+  }
+  return rowrange_;
+}
+
+/*************************************************************************/
+const double * CoinLpIO::getObjCoefficients() const
+{
+  return objective_;
+}
+ 
+/*************************************************************************/
+const CoinPackedMatrix * CoinLpIO::getMatrixByRow() const
+{
+  return matrixByRow_;
+}
+
+/*************************************************************************/
+const CoinPackedMatrix * CoinLpIO::getMatrixByCol() const
+{
+  if (matrixByColumn_ == NULL && matrixByRow_) {
+    matrixByColumn_ = new CoinPackedMatrix(*matrixByRow_);
+    matrixByColumn_->reverseOrdering();
+  }
+  return matrixByColumn_;
+}
+
+/*************************************************************************/
+const char * CoinLpIO::getObjName() const
+{
+  return objName_;
+}
+ 
+/*************************************************************************/
+void CoinLpIO::checkRowNames() {
+
+  int i, nrow = getNumRows();
+
+  if(numberHash_[0] != nrow+1) {
+    setDefaultRowNames();
+    handler_->message(COIN_GENERAL_WARNING,messages_)<<
+      "### CoinLpIO::checkRowNames(): non distinct or missing row names or objective function name.\nNow using default row names."
+						     <<CoinMessageEol;
+  }
+
+  char const * const * rowNames = getRowNames();
+  const char *rSense = getRowSense();
+  char rName[256];
+
+  // Check that row names and objective function name are all distinct, 
+  /// even after adding "_low" to ranged constraint names
+
+  for(i=0; i<nrow; i++) {
+    if(rSense[i] == 'R') {
+      sprintf(rName, "%s_low", rowNames[i]);
+      if(findHash(rName, 0) != -1) {
+	setDefaultRowNames();
+	char printBuffer[512];
+	sprintf(printBuffer,"### CoinLpIO::checkRowNames(): ranged constraint %d has a name %s identical to another constraint name or objective function name.\nUse getPreviousNames() to get the old row names.\nNow using default row names.", i, rName);
+	handler_->message(COIN_GENERAL_WARNING,messages_)<<printBuffer
+						  <<CoinMessageEol;
+	break;
+      }
+    }
+  }
+} /* checkRowNames */
+
+/*************************************************************************/
+void CoinLpIO::checkColNames() {
+
+  int ncol = getNumCols();
+
+  if(numberHash_[1] != ncol) {
+    setDefaultColNames();
+    handler_->message(COIN_GENERAL_WARNING,messages_)<<
+      "### CoinLpIO::checkColNames(): non distinct or missing column names.\nNow using default column names."
+					      <<CoinMessageEol;
+  }
+} /* checkColNames */
+
+/*************************************************************************/
+void CoinLpIO::getPreviousRowNames(char const * const * prev, 
+				   int *card_prev) const
+{
+  *card_prev = card_previous_names_[0];
+  prev = previous_names_[0];
+}
+ 
+/*************************************************************************/
+void CoinLpIO::getPreviousColNames(char const * const * prev, 
+				   int *card_prev) const
+{
+  *card_prev = card_previous_names_[1];
+  prev = previous_names_[1];
+}
+ 
+/*************************************************************************/
+char const * const * CoinLpIO::getRowNames() const
+{
+  return names_[0];
+}
+ 
+/*************************************************************************/
+char const * const * CoinLpIO::getColNames() const
+{
+  return names_[1];
+}
+ 
+/*************************************************************************/
+const char * CoinLpIO::rowName(int index) const {
+
+  if((names_[0] != NULL) && (index >= 0) && (index < numberRows_+1)) {
+    return names_[0][index];
+  } 
+  else {
+    return NULL;
+  }
+}
+
+/*************************************************************************/
+const char * CoinLpIO::columnName(int index) const {
+
+  if((names_[1] != NULL) && (index >= 0) && (index < numberColumns_)) {
+    return names_[1][index];
+  } 
+  else {
+    return NULL;
+  }
+}
+
+/*************************************************************************/
+int CoinLpIO::rowIndex(const char * name) const {
+
+  if (!hash_[0]) {
+    return -1;
+  }
+  return findHash(name , 0);
+}
+
+/*************************************************************************/
+int CoinLpIO::columnIndex(const char * name) const {
+
+  if (!hash_[1]) {
+    return -1;
+  }
+  return findHash(name , 1);
+}
+
+/************************************************************************/
+double CoinLpIO::getInfinity() const
+{
+  return infinity_;
+}
+
+/************************************************************************/
+void CoinLpIO::setInfinity(const double value) 
+{
+  if (value >= 1.0e20) {
+    infinity_ = value;
+  } 
+  else {
+    char str[8192];
+    sprintf(str,"### ERROR: value: %f\n", value);
+    throw CoinError(str, "setInfinity", "CoinLpIO", __FILE__, __LINE__);
+  }
+}
+
+/************************************************************************/
+double CoinLpIO::getEpsilon() const
+{
+  return epsilon_;
+}
+
+/************************************************************************/
+void CoinLpIO::setEpsilon(const double value) 
+{
+  if (value < 0.1) {
+    epsilon_ = value;
+  } 
+  else {
+    char str[8192];
+    sprintf(str,"### ERROR: value: %f\n", value);
+    throw CoinError(str, "setEpsilon", "CoinLpIO", __FILE__, __LINE__);
+  }
+}
+
+/************************************************************************/
+int CoinLpIO::getNumberAcross() const
+{
+  return numberAcross_;
+}
+
+/************************************************************************/
+void CoinLpIO::setNumberAcross(const int value) 
+{
+  if (value > 0) {
+    numberAcross_ = value;
+  } 
+  else {
+    char str[8192];
+    sprintf(str,"### ERROR: value: %d\n", value);
+    throw CoinError(str, "setNumberAcross", "CoinLpIO", __FILE__, __LINE__);
+  }
+}
+
+/************************************************************************/
+int CoinLpIO::getDecimals() const
+{
+  return decimals_;
+}
+
+/************************************************************************/
+void CoinLpIO::setDecimals(const int value) 
+{
+  if (value > 0) {
+    decimals_ = value;
+  } 
+  else {
+    char str[8192];
+    sprintf(str,"### ERROR: value: %d\n", value);
+    throw CoinError(str, "setDecimals", "CoinLpIO", __FILE__, __LINE__);
+  }
+}
+
+/************************************************************************/
+double CoinLpIO::objectiveOffset() const
+{
+  return objectiveOffset_;
+}
+
+/************************************************************************/
+bool CoinLpIO::isInteger(int columnNumber) const
+{
+  const char * intType = integerType_;
+  if (intType == NULL) return false;
+  assert (columnNumber >= 0 && columnNumber < numberColumns_);
+  if (intType[columnNumber] != 0) return true;
+  return false;
+}
+
+/************************************************************************/
+const char * CoinLpIO::integerColumns() const
+{
+  return integerType_;
+}
+
+/************************************************************************/
+void
+CoinLpIO::setLpDataWithoutRowAndColNames(
+			      const CoinPackedMatrix& m,
+			      const double *collb, const double *colub,
+			      const double *obj_coeff,
+			      const char *is_integer,
+			      const double *rowlb, const double *rowub) {
+
+  freeAll();
+  problemName_ = CoinStrdup("");
+
+  if (m.isColOrdered()) {
+    matrixByRow_ = new CoinPackedMatrix();
+    matrixByRow_->reverseOrderedCopyOf(m);
+  } 
+  else {
+    matrixByRow_ = new CoinPackedMatrix(m);
+  }
+  numberColumns_ = matrixByRow_->getNumCols();
+  numberRows_ = matrixByRow_->getNumRows();
+  
+  rowlower_ = reinterpret_cast<double *> (malloc (numberRows_ * sizeof(double)));
+  rowupper_ = reinterpret_cast<double *> (malloc (numberRows_ * sizeof(double)));
+  collower_ = reinterpret_cast<double *> (malloc (numberColumns_ * sizeof(double)));
+  colupper_ = reinterpret_cast<double *> (malloc (numberColumns_ * sizeof(double)));
+  objective_ = reinterpret_cast<double *> (malloc (numberColumns_ * sizeof(double)));
+  std::copy(rowlb, rowlb + numberRows_, rowlower_);
+  std::copy(rowub, rowub + numberRows_, rowupper_);
+  std::copy(collb, collb + numberColumns_, collower_);
+  std::copy(colub, colub + numberColumns_, colupper_);
+  std::copy(obj_coeff, obj_coeff + numberColumns_, objective_);
+
+  if (is_integer) {
+    integerType_ = reinterpret_cast<char *> (malloc (numberColumns_ * sizeof(char)));
+    std::copy(is_integer, is_integer + numberColumns_, integerType_);
+  } 
+  else {
+    integerType_ = 0;
+  }
+
+  if((numberHash_[0] > 0) && (numberHash_[0] != numberRows_+1)) {
+    stopHash(0);
+  }
+  if((numberHash_[1] > 0) && (numberHash_[1] != numberColumns_)) {
+    stopHash(1);
+  }
+} /* SetLpDataWithoutRowAndColNames */
+
+/*************************************************************************/
+void CoinLpIO::setDefaultRowNames() {
+
+  int i, nrow = getNumRows();
+  char **defaultRowNames = reinterpret_cast<char **> (malloc ((nrow+1) * sizeof(char *)));
+  char buff[1024];
+
+  for(i=0; i<nrow; i++) {
+    sprintf(buff, "cons%d", i);
+    defaultRowNames[i] = CoinStrdup(buff);
+  }
+  sprintf(buff, "obj");
+  defaultRowNames[nrow] = CoinStrdup(buff);
+
+  stopHash(0);
+  startHash(defaultRowNames, nrow+1, 0);
+  objName_ = CoinStrdup("obj");
+
+  for(i=0; i<nrow+1; i++) {
+    free(defaultRowNames[i]);
+  }
+  free(defaultRowNames);
+
+} /* setDefaultRowNames */
+
+/*************************************************************************/
+void CoinLpIO::setDefaultColNames() {
+
+  int j, ncol = getNumCols();
+  char **defaultColNames = reinterpret_cast<char **> (malloc (ncol * sizeof(char *)));
+  char buff[256];
+
+  for(j=0; j<ncol; j++) {
+    sprintf(buff, "x%d", j);
+    defaultColNames[j] = CoinStrdup(buff);
+  }
+  stopHash(1);
+  startHash(defaultColNames, ncol, 1);
+
+  for(j=0; j<ncol; j++) {
+    free(defaultColNames[j]);
+  }
+  free(defaultColNames);
+
+} /* setDefaultColNames */
+
+/*************************************************************************/
+void CoinLpIO::setLpDataRowAndColNames(char const * const * const rownames,
+				       char const * const * const colnames) {
+
+  int nrow = getNumRows();
+  int ncol = getNumCols();
+
+  if(rownames != NULL) {
+    if(are_invalid_names(rownames, nrow+1, true)) {
+      setDefaultRowNames();
+      handler_->message(COIN_GENERAL_WARNING,messages_)<<
+      "### CoinLpIO::setLpDataRowAndColNames(): Invalid row names\nUse getPreviousNames() to get the old row names.\nNow using default row names."
+						<<CoinMessageEol;
+    } 
+    else {
+      stopHash(0);
+      startHash(rownames, nrow+1, 0);
+      objName_ = CoinStrdup(rownames[nrow]);
+      checkRowNames();
+    }
+  }
+  else {
+    if(objName_ == NULL) {
+      objName_ = CoinStrdup("obj");      
+    }
+  }
+
+  if(colnames != NULL) {
+    if(are_invalid_names(colnames, ncol, false)) {
+      setDefaultColNames();
+      handler_->message(COIN_GENERAL_WARNING,messages_)<<
+      "### CoinLpIO::setLpDataRowAndColNames(): Invalid column names\nNow using default row names."
+						<<CoinMessageEol;
+    } 
+    else {
+      stopHash(1);
+      startHash(colnames, ncol, 1);
+      checkColNames();
+    }
+  }
+} /* setLpDataColAndRowNames */
+
+/************************************************************************/
+void
+CoinLpIO::out_coeff(FILE *fp, const double v, const int print_1) const {
+
+  double lp_eps = getEpsilon();
+
+  if(!print_1) {
+    if(fabs(v-1) < lp_eps) {
+      return;
+    }
+    if(fabs(v+1) < lp_eps) {
+      fprintf(fp, " -");
+      return;
+    }
+  }
+
+  double frac = v - floor(v);
+
+  if(frac < lp_eps) {
+    fprintf(fp, " %.0f", floor(v));
+  }
+  else {
+    if(frac > 1 - lp_eps) {
+      fprintf(fp, " %.0f", floor(v+0.5));
+    }
+    else {
+      int decimals = getDecimals();
+      char form[15];
+      sprintf(form, " %%.%df", decimals);
+      fprintf(fp, form, v);
+    }
+  }
+} /* out_coeff */
+
+/************************************************************************/
+int
+CoinLpIO::writeLp(const char *filename, const double epsilon,
+		  const int numberAcross, const int decimals,
+		  const bool useRowNames) {
+
+  FILE *fp = NULL;
+  fp = fopen(filename,"w");
+  if (!fp) {
+    char str[8192];
+    sprintf(str,"### ERROR: unable to open file %s\n", filename);
+    throw CoinError(str, "writeLP", "CoinLpIO", __FILE__, __LINE__);
+  }
+  int nerr = writeLp(fp, epsilon, numberAcross, decimals, useRowNames);
+  fclose(fp);
+  return(nerr);
+}
+
+/************************************************************************/
+int
+CoinLpIO::writeLp(FILE *fp, const double epsilon,
+		  const int numberAcross, const int decimals,
+		  const bool useRowNames) {
+
+  setEpsilon(epsilon);
+  setNumberAcross(numberAcross);
+  setDecimals(decimals);
+  return writeLp(fp, useRowNames);
+}
+
+/************************************************************************/
+int
+CoinLpIO::writeLp(const char *filename, const bool useRowNames)
+{
+  FILE *fp = NULL;
+  fp = fopen(filename,"w");
+  if (!fp) {
+    char str[8192];
+    sprintf(str,"### ERROR: unable to open file %s\n", filename);
+    throw CoinError(str, "writeLP", "CoinLpIO", __FILE__, __LINE__);
+  }
+  int nerr = writeLp(fp, useRowNames);
+  fclose(fp);
+  return(nerr);
+}
+
+/************************************************************************/
+int
+CoinLpIO::writeLp(FILE *fp, const bool useRowNames)
+{
+   double lp_eps = getEpsilon();
+   double lp_inf = getInfinity();
+   int numberAcross = getNumberAcross();
+
+   int i, j, cnt_print, loc_row_names = 0, loc_col_names = 0;
+   char **prowNames = NULL, **pcolNames = NULL;
+
+   const int *indices = matrixByRow_->getIndices();
+   const double *elements  = matrixByRow_->getElements();
+   int ncol = getNumCols();
+   int nrow = getNumRows();
+   const double *collow = getColLower();
+   const double *colup = getColUpper();
+   const double *rowlow = getRowLower();
+   const double *rowup = getRowUpper();
+   const double *obj = getObjCoefficients();
+   const char *integerType = integerColumns();
+   char const * const * rowNames = getRowNames();
+   char const * const * colNames = getColNames();
+   
+   char buff[256];
+
+   if(rowNames == NULL) {
+     loc_row_names = 1;
+     prowNames = reinterpret_cast<char **> (malloc ((nrow+1) * sizeof(char *)));
+
+     for (j=0; j<nrow; j++) {
+       sprintf(buff, "cons%d", j);
+       prowNames[j] = CoinStrdup(buff);
+     }
+     prowNames[nrow] = CoinStrdup("obj");
+     rowNames = prowNames;
+   }
+
+   if(colNames == NULL) {
+     loc_col_names = 1;
+     pcolNames = reinterpret_cast<char **> (malloc (ncol * sizeof(char *)));
+
+     for (j=0; j<ncol; j++) {
+       sprintf(buff, "x%d", j);
+       pcolNames[j] = CoinStrdup(buff);
+     }
+     colNames = pcolNames;
+   }
+
+#ifdef LPIO_DEBUG
+   printf("CoinLpIO::writeLp(): numberRows: %d numberColumns: %d\n", 
+	  nrow, ncol);
+#endif
+ 
+   fprintf(fp, "\\Problem name: %s\n\n", getProblemName());
+   fprintf(fp, "Minimize\n");
+
+   if(useRowNames) {
+     fprintf(fp, "%s:", objName_);
+   }
+
+   cnt_print = 0;
+   for(j=0; j<ncol; j++) {
+     if((cnt_print > 0) && (objective_[j] > lp_eps)) {
+       fprintf(fp, " +");
+     }
+     if(fabs(obj[j]) > lp_eps) {
+       out_coeff(fp, obj[j], 0);
+       fprintf(fp, " %s", colNames[j]);
+       cnt_print++;
+       if(cnt_print % numberAcross == 0) {
+	 fprintf(fp, "\n");
+       }
+     }
+   }
+ 
+   if((cnt_print > 0) && (objectiveOffset_ > lp_eps)) {
+     fprintf(fp, " +");
+   }
+   if(fabs(objectiveOffset_) > lp_eps) {
+     out_coeff(fp, objectiveOffset_, 1);
+     cnt_print++;
+   }
+
+   if((cnt_print == 0) || (cnt_print % numberAcross != 0)) {
+     fprintf(fp, "\n");
+   }
+   
+   fprintf(fp, "Subject To\n");
+   
+   int cnt_out_rows = 0;
+
+   for(i=0; i<nrow; i++) {
+     cnt_print = 0;
+     
+     if(useRowNames) {
+       fprintf(fp, "%s: ", rowNames[i]);
+     }
+     cnt_out_rows++;
+
+     for(j=matrixByRow_->getVectorFirst(i); 
+	 j<matrixByRow_->getVectorLast(i); j++) {
+       if((cnt_print > 0) && (elements[j] > lp_eps)) {
+	 fprintf(fp, " +");
+       }
+       if(fabs(elements[j]) > lp_eps) {
+	 out_coeff(fp, elements[j], 0);
+	 fprintf(fp, " %s", colNames[indices[j]]);
+	 cnt_print++;
+	 if(cnt_print % numberAcross == 0) {
+	   fprintf(fp, "\n");
+	 }
+       }
+     }
+
+     if(rowup[i] - rowlow[i] < lp_eps) {
+          fprintf(fp, " =");
+	  out_coeff(fp, rowlow[i], 1);
+	  fprintf(fp, "\n");
+     }
+     else {
+       if(rowup[i] < lp_inf) {
+	 fprintf(fp, " <=");
+	 out_coeff(fp, rowup[i], 1);	 
+	 fprintf(fp, "\n");
+
+	 if(rowlower_[i] > -lp_inf) {
+
+	   cnt_print = 0;
+
+	   if(useRowNames) {
+	     fprintf(fp, "%s_low:", rowNames[i]);
+	   }
+	   cnt_out_rows++;
+	   
+	   for(j=matrixByRow_->getVectorFirst(i); 
+	       j<matrixByRow_->getVectorLast(i); j++) {
+	     if((cnt_print>0) && (elements[j] > lp_eps)) {
+	       fprintf(fp, " +");
+	     }
+	     if(fabs(elements[j]) > lp_eps) {
+	       out_coeff(fp, elements[j], 0);
+	       fprintf(fp, " %s", colNames[indices[j]]);
+	       cnt_print++;
+	       if(cnt_print % numberAcross == 0) {
+		 fprintf(fp, "\n");
+	       }
+	     }
+	   }
+	   fprintf(fp, " >=");
+	   out_coeff(fp, rowlow[i], 1);
+	   fprintf(fp, "\n");
+	 }
+
+       }
+       else {
+	 fprintf(fp, " >=");
+	 out_coeff(fp, rowlow[i], 1);	 
+	 fprintf(fp, "\n");
+       }
+     }
+   }
+
+#ifdef LPIO_DEBUG
+   printf("CoinLpIO::writeLp(): Done with constraints\n");
+#endif
+
+   fprintf(fp, "Bounds\n");
+   
+   for(j=0; j<ncol; j++) {
+     if((collow[j] > -lp_inf) && (colup[j] < lp_inf)) {
+       out_coeff(fp, collow[j], 1);
+       fprintf(fp, " <= %s <=", colNames[j]); 
+       out_coeff(fp, colup[j], 1);
+       fprintf(fp, "\n");
+     }
+     if((collow[j] == -lp_inf) && (colup[j] < lp_inf)) {
+       fprintf(fp, "%s <=", colNames[j]);
+       out_coeff(fp, colup[j], 1);
+       fprintf(fp, "\n");
+     }
+     if((collow[j] > -lp_inf) && (colup[j] == lp_inf)) {
+       if(fabs(collow[j]) > lp_eps) { 
+	 out_coeff(fp, collow[j], 1);
+	 fprintf(fp, " <= %s\n", colNames[j]);
+       }
+     }
+     if(collow[j] == -lp_inf) {
+       fprintf(fp, " %s Free\n", colNames[j]); 
+     }
+   }
+
+#ifdef LPIO_DEBUG
+   printf("CoinLpIO::writeLp(): Done with bounds\n");
+#endif
+
+   if(integerType != NULL) {
+     int first_int = 1;
+     cnt_print = 0;
+     for(j=0; j<ncol; j++) {
+       if(integerType[j] == 1) {
+
+	 if(first_int) {
+	   fprintf(fp, "Integers\n");
+	   first_int = 0;
+	 }
+
+	 fprintf(fp, "%s ", colNames[j]);
+	 cnt_print++;
+	 if(cnt_print % numberAcross == 0) {
+	   fprintf(fp, "\n");
+	 }
+       }
+     }
+
+     if(cnt_print % numberAcross != 0) {
+       fprintf(fp, "\n");
+     }
+   }
+
+#ifdef LPIO_DEBUG
+   printf("CoinLpIO::writeLp(): Done with integers\n");
+#endif
+
+   fprintf(fp, "End\n");
+
+   if(loc_row_names) {
+     for(j=0; j<nrow+1; j++) {
+       free(prowNames[j]);
+     }
+     free(prowNames);
+   }
+
+   if(loc_col_names) {
+     for(j=0; j<ncol; j++) {
+       free(pcolNames[j]);
+     }
+     free(pcolNames);
+   }
+   return 0;
+} /* writeLp */
+
+/*************************************************************************/
+int 
+CoinLpIO::find_obj(FILE *fp) const {
+
+  char buff[1024];
+
+  sprintf(buff, "aa");
+  size_t lbuff = strlen(buff);
+
+  while(((lbuff != 8) || (CoinStrNCaseCmp(buff, "minimize", 8) != 0)) &&
+	((lbuff != 3) || (CoinStrNCaseCmp(buff, "min", 3) != 0)) &&
+	((lbuff != 8) || (CoinStrNCaseCmp(buff, "maximize", 8) != 0)) &&
+	((lbuff != 3) || (CoinStrNCaseCmp(buff, "max", 3) != 0))) {
+
+    scan_next(buff, fp);
+    lbuff = strlen(buff);
+    
+    if(feof(fp)) {
+      char str[8192];
+      sprintf(str,"### ERROR: Unable to locate objective function\n");
+      throw CoinError(str, "find_obj", "CoinLpIO", __FILE__, __LINE__);
+    }
+  }
+
+  if(((lbuff == 8) && (CoinStrNCaseCmp(buff, "minimize", 8) == 0)) ||
+     ((lbuff == 3) && (CoinStrNCaseCmp(buff, "min", 3) == 0))) {
+    return(1);
+  }
+  return(-1);
+} /* find_obj */
+
+/*************************************************************************/
+int
+CoinLpIO::is_subject_to(const char *buff) const {
+
+  size_t lbuff = strlen(buff);
+
+  if(((lbuff == 4) && (CoinStrNCaseCmp(buff, "s.t.", 4) == 0)) ||
+     ((lbuff == 3) && (CoinStrNCaseCmp(buff, "st.", 3) == 0)) ||
+     ((lbuff == 2) && (CoinStrNCaseCmp(buff, "st", 2) == 0))) {
+    return(1);
+  }
+  if((lbuff == 7) && (CoinStrNCaseCmp(buff, "subject", 7) == 0)) {
+    return(2);
+  }
+  return(0);
+} /* is_subject_to */
+
+/*************************************************************************/
+int 
+CoinLpIO::first_is_number(const char *buff) const {
+
+  size_t pos;
+  char str_num[] = "1234567890";
+
+  pos = strcspn (buff, str_num);
+  if (pos == 0) {
+    return(1);
+  }
+  return(0);
+} /* first_is_number */
+
+/*************************************************************************/
+int 
+CoinLpIO::is_sense(const char *buff) const {
+
+  size_t pos;
+  char str_sense[] = "<>=";
+
+  pos = strcspn(buff, str_sense);
+  if(pos == 0) {
+    if(strcmp(buff, "<=") == 0) {
+      return(0);
+    }
+    if(strcmp(buff, "=") == 0) {
+      return(1);
+    }
+    if(strcmp(buff, ">=") == 0) {
+      return(2);
+    }
+    
+    printf("### ERROR: CoinLpIO: is_sense(): string: %s \n", buff);
+  }
+  return(-1);
+} /* is_sense */
+
+/*************************************************************************/
+int 
+CoinLpIO::is_free(const char *buff) const {
+
+  size_t lbuff = strlen(buff);
+
+  if((lbuff == 4) && (CoinStrNCaseCmp(buff, "free", 4) == 0)) {
+    return(1);
+  }
+  return(0);
+} /* is_free */
+
+/*************************************************************************/
+int 
+CoinLpIO::is_inf(const char *buff) const {
+
+  size_t lbuff = strlen(buff);
+
+  if((lbuff == 3) && (CoinStrNCaseCmp(buff, "inf", 3) == 0)) {
+    return(1);
+  }
+  return(0);
+} /* is_inf */
+
+/*************************************************************************/
+int 
+CoinLpIO::is_comment(const char *buff) const {
+
+  if((buff[0] == '/') || (buff[0] == '\\')) {
+    return(1);
+  }
+  return(0);
+} /* is_comment */
+
+/*************************************************************************/
+void
+CoinLpIO::skip_comment(char *buff, FILE *fp) const {
+
+  while(strcspn(buff, "\n") == strlen(buff)) { // end of line not read yet
+    if(feof(fp)) {
+      char str[8192];
+      sprintf(str,"### ERROR: end of file reached while skipping comment\n");
+      throw CoinError(str, "skip_comment", "CoinLpIO", __FILE__, __LINE__);
+    }
+    if(ferror(fp)) {
+      char str[8192];
+      sprintf(str,"### ERROR: error while skipping comment\n");
+      throw CoinError(str, "skip_comment", "CoinLpIO", __FILE__, __LINE__);
+    }
+    char * x=fgets(buff, sizeof(buff), fp);    
+    if (!x)
+      throw("bad fgets");
+  } 
+} /* skip_comment */
+
+/*************************************************************************/
+void
+CoinLpIO::scan_next(char *buff, FILE *fp) const {
+
+  int x=fscanf(fp, "%s", buff);
+  if (x<=0)
+    throw("bad fscanf");
+  while(is_comment(buff)) {
+    skip_comment(buff, fp);
+    x=fscanf(fp, "%s", buff);
+    if (x<=0)
+      throw("bad fscanf");
+  }
+
+#ifdef LPIO_DEBUG
+  printf("CoinLpIO::scan_next: (%s)\n", buff);
+#endif
+
+} /* scan_next */
+
+/*************************************************************************/
+int 
+CoinLpIO::is_invalid_name(const char *name, 
+			  const bool ranged) const {
+
+  size_t pos, lname, valid_lname = 100;
+  char str_valid[] = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"!#$%&(),.;?@_'`{}~";
+
+  if(ranged) {
+    valid_lname -= 4; // will add "_low" when writing the Lp file
+  }
+
+  if(name == NULL) {
+    lname = 0;
+  }
+  else {
+    lname = strlen(name);
+  }
+  if(lname < 1) {
+    handler_->message(COIN_GENERAL_WARNING,messages_)<<
+    "### CoinLpIO::is_invalid_name(): Name is empty"
+					      <<CoinMessageEol;
+    return(5);
+  }
+  if(lname > valid_lname) {
+	char printBuffer[512];
+	sprintf(printBuffer,"### CoinLpIO::is_invalid_name(): Name %s is too long", 
+	   name);
+	handler_->message(COIN_GENERAL_WARNING,messages_)<<printBuffer
+							 <<CoinMessageEol;
+    return(1);
+  }
+  if(first_is_number(name)) {
+    char printBuffer[512];
+    sprintf(printBuffer,"### CoinLpIO::is_invalid_name(): Name %s should not start with a number", name);
+    handler_->message(COIN_GENERAL_WARNING,messages_)<<printBuffer
+						     <<CoinMessageEol;
+    return(2);
+  }
+  pos = strspn(name, str_valid);
+  if(pos != lname) {
+    char printBuffer[512];
+    sprintf(printBuffer,"### CoinLpIO::is_invalid_name(): Name %s contains illegal character '%c'", name, name[pos]);
+    handler_->message(COIN_GENERAL_WARNING,messages_)<<printBuffer
+						     <<CoinMessageEol;
+    return(3);
+  }
+
+  if((is_keyword(name)) || (is_free(name) || (is_inf(name)))) {
+    return(4);
+  }
+
+  return(0);
+} /* is_invalid_name */
+
+/*************************************************************************/
+int 
+CoinLpIO::are_invalid_names(char const * const * const vnames, 
+			    const int card_vnames, 
+			    const bool check_ranged) const {
+
+  int i, invalid = 0, flag, nrows = getNumRows();
+  bool is_ranged = 0;
+  const char * rSense = getRowSense();
+
+  if((check_ranged) && (card_vnames != nrows+1)) {
+    char str[8192];
+    sprintf(str,"### ERROR: card_vnames: %d   number of rows: %d\n",
+	    card_vnames, getNumRows());
+    throw CoinError(str, "are_invalid_names", "CoinLpIO", __FILE__, __LINE__);
+  }
+
+  for(i=0; i<card_vnames; i++) {
+
+    if((check_ranged) && (i < nrows) && (rSense[i] == 'R')) {
+      is_ranged = true;
+    }
+    else {
+      is_ranged = false;
+    }
+    flag = is_invalid_name(vnames[i], is_ranged);
+    if(flag) {
+      char printBuffer[512];
+      sprintf(printBuffer,"### CoinLpIO::are_invalid_names(): Invalid name: vnames[%d]: %s",
+	      i, vnames[i]);
+      handler_->message(COIN_GENERAL_WARNING,messages_)<<printBuffer
+						       <<CoinMessageEol;
+      invalid = flag;
+    }
+  }
+  return(invalid);
+} /* are_invalid_names */
+
+/*************************************************************************/
+int 
+CoinLpIO::read_monom_obj(FILE *fp, double *coeff, char **name, int *cnt, 
+						 char **obj_name) {
+
+  double mult;
+  char buff[1024] = "aa", loc_name[1024], *start;
+  int read_st = 0;
+
+  scan_next(buff, fp);
+
+  if(feof(fp)) {
+    char str[8192];
+    sprintf(str,"### ERROR: Unable to read objective function\n");
+    throw CoinError(str, "read_monom_obj", "CoinLpIO", __FILE__, __LINE__);
+  }
+
+  if(buff[strlen(buff)-1] == ':') {
+    buff[strlen(buff)-1] = '\0';
+
+#ifdef LPIO_DEBUG
+    printf("CoinLpIO: read_monom_obj(): obj_name: %s\n", buff);
+#endif
+
+    *obj_name = CoinStrdup(buff);
+    return(0);
+  }
+
+
+  read_st = is_subject_to(buff);
+
+#ifdef LPIO_DEBUG
+  printf("read_monom_obj: first buff: (%s)\n", buff);
+#endif
+
+  if(read_st > 0) {
+    return(read_st);
+  }
+
+  start = buff;
+  mult = 1;
+  if(buff[0] == '+') {
+    mult = 1;
+    if(strlen(buff) == 1) {
+      scan_next(buff, fp);
+      start = buff;
+    }
+    else {
+      start = &(buff[1]);
+    }
+  }
+  
+  if(buff[0] == '-') {
+    mult = -1;
+    if(strlen(buff) == 1) {
+      scan_next(buff, fp);
+      start = buff;
+    }
+    else {
+      start = &(buff[1]);
+    }
+  }
+  
+  if(first_is_number(start)) {
+    coeff[*cnt] = atof(start);       
+    sprintf(loc_name, "aa");
+    scan_next(loc_name, fp);
+  }
+  else {
+    coeff[*cnt] = 1;
+    strcpy(loc_name, start);
+  }
+
+  read_st = is_subject_to(loc_name);
+
+#ifdef LPIO_DEBUG
+  printf("read_monom_obj: second buff: (%s)\n", buff);
+#endif
+
+  if(read_st > 0) {
+    setObjectiveOffset(mult * coeff[*cnt]);
+
+#ifdef LPIO_DEBUG
+  printf("read_monom_obj: objectiveOffset: %f\n", objectiveOffset_);
+#endif
+
+    return(read_st);
+  }
+
+  coeff[*cnt] *= mult;
+  name[*cnt] = CoinStrdup(loc_name);
+
+#ifdef LPIO_DEBUG
+  printf("read_monom_obj: (%f)  (%s)\n", coeff[*cnt], name[*cnt]);
+#endif
+
+  (*cnt)++;
+
+  return(read_st);
+} /* read_monom_obj */
+
+/*************************************************************************/
+int 
+CoinLpIO::read_monom_row(FILE *fp, char *start_str, 
+			 double *coeff, char **name, 
+			 int cnt_coeff) const {
+
+  double mult;
+  char buff[1024], loc_name[1024], *start;
+  int read_sense = -1;
+
+  sprintf(buff, "%s", start_str);
+  read_sense = is_sense(buff);
+  if(read_sense > -1) {
+    return(read_sense);
+  }
+
+  start = buff;
+  mult = 1;
+  if(buff[0] == '+') {
+    mult = 1;
+    if(strlen(buff) == 1) {
+      scan_next(buff, fp);
+      start = buff;
+    }
+    else {
+      start = &(buff[1]);
+    }
+  }
+  
+  if(buff[0] == '-') {
+    mult = -1;
+    if(strlen(buff) == 1) {
+      scan_next(buff, fp);
+      start = buff;
+    }
+    else {
+      start = &(buff[1]);
+    }
+  }
+  
+  if(first_is_number(start)) {
+    coeff[cnt_coeff] = atof(start);       
+    scan_next(loc_name, fp);
+  }
+  else {
+    coeff[cnt_coeff] = 1;
+    strcpy(loc_name, start);
+  }
+
+  coeff[cnt_coeff] *= mult;
+#ifdef KILL_ZERO_READLP
+  if (fabs(coeff[cnt_coeff])>epsilon_)
+    name[cnt_coeff] = CoinStrdup(loc_name);
+  else
+    read_sense=-2; // effectively zero
+#else
+  name[cnt_coeff] = CoinStrdup(loc_name);
+#endif
+
+#ifdef LPIO_DEBUG
+  printf("CoinLpIO: read_monom_row: (%f)  (%s)\n", 
+	 coeff[cnt_coeff], name[cnt_coeff]);
+#endif  
+  return(read_sense);
+} /* read_monom_row */
+
+/*************************************************************************/
+void
+CoinLpIO::realloc_coeff(double **coeff, char ***colNames, 
+			int *maxcoeff) const {
+  
+  *maxcoeff *= 5;
+
+  *colNames = reinterpret_cast<char **> (realloc ((*colNames), (*maxcoeff+1) * sizeof(char *)));
+  *coeff = reinterpret_cast<double *> (realloc ((*coeff), (*maxcoeff+1) * sizeof(double)));
+
+} /* realloc_coeff */
+
+/*************************************************************************/
+void
+CoinLpIO::realloc_row(char ***rowNames, int **start, double **rhs, 
+		      double **rowlow, double **rowup, int *maxrow) const {
+
+  *maxrow *= 5;
+  *rowNames = reinterpret_cast<char **> (realloc ((*rowNames), (*maxrow+1) * sizeof(char *)));
+  *start = reinterpret_cast<int *> (realloc ((*start), (*maxrow+1) * sizeof(int)));
+  *rhs = reinterpret_cast<double *> (realloc ((*rhs), (*maxrow+1) * sizeof(double)));
+  *rowlow = reinterpret_cast<double *> (realloc ((*rowlow), (*maxrow+1) * sizeof(double)));
+  *rowup = reinterpret_cast<double *> (realloc ((*rowup), (*maxrow+1) * sizeof(double)));
+
+} /* realloc_row */
+
+/*************************************************************************/
+void
+CoinLpIO::realloc_col(double **collow, double **colup, char **is_int,
+		      int *maxcol) const {
+  
+  *maxcol += 100;
+  *collow = reinterpret_cast<double *> (realloc ((*collow), (*maxcol+1) * sizeof(double)));
+  *colup = reinterpret_cast<double *> (realloc ((*colup), (*maxcol+1) * sizeof(double)));
+  *is_int = reinterpret_cast<char *> (realloc ((*is_int), (*maxcol+1) * sizeof(char)));
+
+} /* realloc_col */
+
+/*************************************************************************/
+void 
+CoinLpIO::read_row(FILE *fp, char *buff,
+		   double **pcoeff, char ***pcolNames, 
+		   int *cnt_coeff,
+		   int *maxcoeff,
+		   double *rhs, double *rowlow, double *rowup, 
+		   int *cnt_row, double inf) const {
+
+  int read_sense = -1;
+  char start_str[1024];
+  
+  sprintf(start_str, "%s", buff);
+
+  while(read_sense < 0) {
+
+    if((*cnt_coeff) == (*maxcoeff)) {
+      realloc_coeff(pcoeff, pcolNames, maxcoeff);
+    }
+    read_sense = read_monom_row(fp, start_str, 
+				*pcoeff, *pcolNames, *cnt_coeff);
+#ifdef KILL_ZERO_READLP
+    if (read_sense!=-2) // see if zero
+#endif
+      (*cnt_coeff)++;
+
+    scan_next(start_str, fp);
+
+    if(feof(fp)) {
+      char str[8192];
+      sprintf(str,"### ERROR: Unable to read row monomial\n");
+      throw CoinError(str, "read_monom_row", "CoinLpIO", __FILE__, __LINE__);
+    }
+  }
+  (*cnt_coeff)--;
+
+  rhs[*cnt_row] = atof(start_str);
+
+  switch(read_sense) {
+  case 0: rowlow[*cnt_row] = -inf; rowup[*cnt_row] = rhs[*cnt_row];
+    break;
+  case 1: rowlow[*cnt_row] = rhs[*cnt_row]; rowup[*cnt_row] = rhs[*cnt_row];
+    break;
+  case 2: rowlow[*cnt_row] = rhs[*cnt_row]; rowup[*cnt_row] = inf; 
+    break;
+  default: break;
+  }
+  (*cnt_row)++;
+
+} /* read_row */
+
+/*************************************************************************/
+int 
+CoinLpIO::is_keyword(const char *buff) const {
+
+  size_t lbuff = strlen(buff);
+
+  if(((lbuff == 5) && (CoinStrNCaseCmp(buff, "bound", 5) == 0)) ||
+     ((lbuff == 6) && (CoinStrNCaseCmp(buff, "bounds", 6) == 0))) {
+    return(1);
+  }
+
+  if(((lbuff == 7) && (CoinStrNCaseCmp(buff, "integer", 7) == 0)) ||
+     ((lbuff == 8) && (CoinStrNCaseCmp(buff, "integers", 8) == 0))) {
+    return(2);
+  }
+  
+  if(((lbuff == 7) && (CoinStrNCaseCmp(buff, "general", 7) == 0)) ||
+     ((lbuff == 8) && (CoinStrNCaseCmp(buff, "generals", 8) == 0))) {
+    return(2);
+  }
+
+  if(((lbuff == 6) && (CoinStrNCaseCmp(buff, "binary", 6) == 0)) ||
+     ((lbuff == 8) && (CoinStrNCaseCmp(buff, "binaries", 8) == 0))) {
+    return(3);
+  }
+  
+  if((lbuff == 3) && (CoinStrNCaseCmp(buff, "end", 3) == 0)) {
+    return(4);
+  }
+
+  return(0);
+
+} /* is_keyword */
+
+/*************************************************************************/
+void
+CoinLpIO::readLp(const char *filename, const double epsilon)
+{
+  setEpsilon(epsilon);
+  readLp(filename);
+}
+
+/*************************************************************************/
+void
+CoinLpIO::readLp(const char *filename)
+{
+  FILE *fp = fopen(filename, "r");
+  if(!fp) {
+    char str[8192];
+    sprintf(str,"### ERROR: Unable to open file %s for reading\n", filename);
+    throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+  }
+  readLp(fp);
+  fclose(fp);
+}
+
+/*************************************************************************/
+void
+CoinLpIO::readLp(FILE* fp, const double epsilon)
+{
+  setEpsilon(epsilon);
+  readLp(fp);
+}
+
+/*************************************************************************/
+void
+CoinLpIO::readLp(FILE* fp)
+{
+
+  int maxrow = 1000;
+  int maxcoeff = 40000;
+  double lp_eps = getEpsilon();
+  double lp_inf = getInfinity();
+
+  char buff[1024];
+
+  int objsense, cnt_coeff = 0, cnt_row = 0, cnt_obj = 0;
+  char *objName = NULL;
+
+  char **colNames = reinterpret_cast<char **> (malloc ((maxcoeff+1) * sizeof(char *)));
+  double *coeff = reinterpret_cast<double *> (malloc ((maxcoeff+1) * sizeof(double)));
+
+  char **rowNames = reinterpret_cast<char **> (malloc ((maxrow+1) * sizeof(char *)));
+  int *start = reinterpret_cast<int *> (malloc ((maxrow+1) * sizeof(int)));
+  double *rhs = reinterpret_cast<double *> (malloc ((maxrow+1) * sizeof(double)));
+  double *rowlow = reinterpret_cast<double *> (malloc ((maxrow+1) * sizeof(double)));
+  double *rowup = reinterpret_cast<double *> (malloc ((maxrow+1) * sizeof(double)));
+
+  int i;
+
+  objsense = find_obj(fp);
+
+  int read_st = 0;
+  while(!read_st) {
+    read_st = read_monom_obj(fp, coeff, colNames, &cnt_obj, &objName);
+
+    if(cnt_obj == maxcoeff) {
+      realloc_coeff(&coeff, &colNames, &maxcoeff);
+    }
+  }
+  
+  start[0] = cnt_obj;
+  cnt_coeff = cnt_obj;
+
+  if(read_st == 2) {
+    int x=fscanf(fp, "%s", buff);
+    if (x<=0)
+      throw("bad fscanf");
+    size_t lbuff = strlen(buff);
+
+    if((lbuff != 2) || (CoinStrNCaseCmp(buff, "to", 2) != 0)) {
+      char str[8192];
+      sprintf(str,"### ERROR: Can not locate keyword 'Subject To'\n");
+      throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+    }
+  }
+  
+  scan_next(buff, fp);
+
+  while(!is_keyword(buff)) {
+    if(buff[strlen(buff)-1] == ':') {
+      buff[strlen(buff)-1] = '\0';
+
+#ifdef LPIO_DEBUG
+      printf("CoinLpIO::readLp(): rowName[%d]: %s\n", cnt_row, buff);
+#endif
+
+      rowNames[cnt_row] = CoinStrdup(buff);
+      scan_next(buff, fp);
+    }
+    else {
+      char rname[15];
+      sprintf(rname, "cons%d", cnt_row); 
+      rowNames[cnt_row] = CoinStrdup(rname);
+    }
+    read_row(fp, buff, 
+	     &coeff, &colNames, &cnt_coeff, &maxcoeff, rhs, rowlow, rowup, 
+	     &cnt_row, lp_inf);
+    scan_next(buff, fp);
+    start[cnt_row] = cnt_coeff;
+
+    if(cnt_row == maxrow) {
+      realloc_row(&rowNames, &start, &rhs, &rowlow, &rowup, &maxrow);
+    }
+
+  }
+
+  numberRows_ = cnt_row;
+
+  stopHash(1);
+  startHash(colNames, cnt_coeff, 1);
+  
+  COINColumnIndex icol;
+  int read_sense1,  read_sense2;
+  double bnd1 = 0, bnd2 = 0;
+
+  int maxcol = numberHash_[1] + 100;
+
+  double *collow = reinterpret_cast<double *> (malloc ((maxcol+1) * sizeof(double)));
+  double *colup = reinterpret_cast<double *> (malloc ((maxcol+1) * sizeof(double)));
+  char *is_int = reinterpret_cast<char *> (malloc ((maxcol+1) * sizeof(char)));
+  int has_int = 0;
+
+  for (i=0; i<maxcol; i++) {
+    collow[i] = 0;
+    colup[i] = lp_inf;
+    is_int[i] = 0;
+  }
+
+  int done = 0;
+
+  while(!done) {
+    switch(is_keyword(buff)) {
+
+    case 1: /* Bounds section */ 
+      scan_next(buff, fp);
+
+      while(is_keyword(buff) == 0) {
+
+	read_sense1 = -1;
+	read_sense2 = -1;
+	int mult = 1;
+	char *start_str = buff;
+
+	if(buff[0] == '-' || buff[0] == '+') {
+	  mult = (buff[0] == '-') ? -1 : +1;
+	  if(strlen(buff) == 1) {
+	    scan_next(buff, fp);
+	    start_str = buff;
+	  }
+	  else {
+	    start_str = &(buff[1]);
+	  }
+	}
+
+	int scan_sense = 0;
+	if(first_is_number(start_str)) {
+	  bnd1 = mult * atof(start_str);
+	  scan_sense = 1;
+	}
+	else {
+	  if(is_inf(start_str)) {
+	    bnd1 = mult * lp_inf;
+	    scan_sense = 1;
+	  }
+	}
+	if(scan_sense) {
+	  scan_next(buff, fp);
+	  read_sense1 = is_sense(buff);
+	  if(read_sense1 < 0) {
+	    char str[8192];
+	    sprintf(str,"### ERROR: Bounds; expect a sense, get: %s\n", buff);
+	    throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+	  }
+	  scan_next(buff, fp);
+	}
+
+	icol = findHash(buff, 1);
+	if(icol < 0) {
+	  char printBuffer[512];
+	  sprintf(printBuffer,"### CoinLpIO::readLp(): Variable %s does not appear in objective function or constraints", buff);
+	  handler_->message(COIN_GENERAL_WARNING,messages_)<<printBuffer
+							   <<CoinMessageEol;
+	  insertHash(buff, 1);
+	  icol = findHash(buff, 1);
+	  if(icol == maxcol) {
+	    realloc_col(&collow, &colup, &is_int, &maxcol);
+	  }
+	}
+
+	scan_next(buff, fp);
+	if(is_free(buff)) {
+	  collow[icol] = -lp_inf;
+	  scan_next(buff, fp);
+	}
+       	else {
+	  read_sense2 = is_sense(buff);
+	  if(read_sense2 > -1) {
+	    scan_next(buff, fp);
+	    mult = 1;
+	    start_str = buff;
+
+	    if(buff[0] == '-'||buff[0] == '+') {
+	      mult = (buff[0] == '-') ? -1 : +1;
+	      if(strlen(buff) == 1) {
+		scan_next(buff, fp);
+		start_str = buff;
+	      }
+	      else {
+		start_str = &(buff[1]);
+	      }
+	    }
+	    if(first_is_number(start_str)) {
+	      bnd2 = mult * atof(start_str);
+	      scan_next(buff, fp);
+	    }
+	    else {
+	      if(is_inf(start_str)) {
+		bnd2 = mult * lp_inf;
+		scan_next(buff, fp);
+	      }
+	      else {
+		char str[8192];
+		sprintf(str,"### ERROR: Bounds; expect a number, get: %s\n",
+			buff);
+		throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+	      }
+	    }
+	  }
+
+	  if((read_sense1 > -1) && (read_sense2 > -1)) {
+	    if(read_sense1 != read_sense2) {
+	      char str[8192];
+	      sprintf(str,"### ERROR: Bounds; variable: %s read_sense1: %d  read_sense2: %d\n",
+		      buff, read_sense1, read_sense2);
+	      throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+	    }
+	    else {
+	      if(read_sense1 == 1) {
+		if(fabs(bnd1 - bnd2) > lp_eps) {
+		  char str[8192];
+		  sprintf(str,"### ERROR: Bounds; variable: %s read_sense1: %d  read_sense2: %d  bnd1: %f  bnd2: %f\n", 
+			  buff, read_sense1, read_sense2, bnd1, bnd2);
+		  throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+		}
+		collow[icol] = bnd1;
+		colup[icol] = bnd1;
+	      }
+	      if(read_sense1 == 0) {
+		collow[icol] = bnd1;
+		colup[icol] = bnd2;	    
+	      }
+	      if(read_sense1 == 2) {
+		colup[icol] = bnd1;
+		collow[icol] = bnd2;	    
+	      }
+	    }
+	  }
+	  else {
+	    if(read_sense1 > -1) {
+	      switch(read_sense1) {
+	      case 0: collow[icol] = bnd1; break;
+	      case 1: collow[icol] = bnd1; colup[icol] = bnd1; break;
+	      case 2: colup[icol] = bnd1; break;
+	      }
+	    }
+	    if(read_sense2 > -1) {
+	      switch(read_sense2) {
+	      case 0: colup[icol] = bnd2; break;
+	      case 1: collow[icol] = bnd2; colup[icol] = bnd2; break;
+	      case 2: collow[icol] = bnd2; break;
+	      }
+	    }
+	  }
+	}
+      }
+      break;
+
+    case 2: /* Integers/Generals section */
+
+      scan_next(buff, fp);
+    
+      while(is_keyword(buff) == 0) {
+      
+	icol = findHash(buff, 1);
+
+#ifdef LPIO_DEBUG
+	printf("CoinLpIO::readLp(): Integer: colname: (%s)  icol: %d\n", 
+	       buff, icol);
+#endif
+
+	if(icol < 0) {
+	  char printBuffer[512];
+	  sprintf(printBuffer,"### CoinLpIO::readLp(): Integer variable %s does not appear in objective function or constraints", buff);
+	  handler_->message(COIN_GENERAL_WARNING,messages_)<<printBuffer
+							   <<CoinMessageEol;
+	  insertHash(buff, 1);
+	  icol = findHash(buff, 1);
+	  if(icol == maxcol) {
+	    realloc_col(&collow, &colup, &is_int, &maxcol);
+	  }
+	  
+#ifdef LPIO_DEBUG
+	  printf("CoinLpIO::readLp(): Integer: colname: (%s)  icol: %d\n", 
+		 buff, icol);
+#endif
+	  
+	}
+	is_int[icol] = 1;
+	has_int = 1;
+	scan_next(buff, fp);
+      };
+      break;
+
+    case 3: /* Binaries section */
+  
+      scan_next(buff, fp);
+      
+      while(is_keyword(buff) == 0) {
+
+	icol = findHash(buff, 1);
+
+#ifdef LPIO_DEBUG
+	printf("CoinLpIO::readLp(): binary: colname: (%s)  icol: %d\n", 
+	       buff, icol);
+#endif
+
+	if(icol < 0) {
+	  char printBuffer[512];
+	  sprintf(printBuffer,"### CoinLpIO::readLp(): Binary variable %s does not appear in objective function or constraints", buff);
+	  handler_->message(COIN_GENERAL_WARNING,messages_)<<printBuffer
+							   <<CoinMessageEol;
+	  insertHash(buff, 1);
+	  icol = findHash(buff, 1);
+	  if(icol == maxcol) {
+	    realloc_col(&collow, &colup, &is_int, &maxcol);
+	  }
+#ifdef LPIO_DEBUG
+	  printf("CoinLpIO::readLp(): binary: colname: (%s)  icol: %d\n", 
+		 buff, icol);
+#endif
+	  
+	}
+
+	is_int[icol] = 1;
+	has_int = 1;
+	if(collow[icol] < 0) {
+	  collow[icol] = 0;
+	}
+	if(colup[icol] > 1) {
+	  colup[icol] = 1;
+	}
+	scan_next(buff, fp);
+      }
+      break;
+      
+    case 4: done = 1; break;
+      
+    default: 
+      char str[8192];
+      sprintf(str,"### ERROR: Lost while reading: (%s)\n", buff);
+      throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+      break;
+    }
+  }
+
+#ifdef LPIO_DEBUG
+  printf("CoinLpIO::readLp(): Done with reading the Lp file\n");
+#endif
+
+  int *ind = reinterpret_cast<int *> (malloc ((maxcoeff+1) * sizeof(int)));
+
+  for(i=0; i<cnt_coeff; i++) {
+    ind[i] = findHash(colNames[i], 1);
+
+#ifdef LPIO_DEBUG
+    printf("CoinLpIO::readLp(): name[%d]: (%s)   ind: %d\n", 
+	   i, colNames[i], ind[i]);
+#endif
+
+    if(ind[i] < 0) {
+      char str[8192];
+      sprintf(str,"### ERROR: Hash table: %s not found\n", colNames[i]);
+      throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+    }
+  }
+  
+  numberColumns_ = numberHash_[1];
+  numberElements_ = cnt_coeff - start[0];
+
+  double *obj = reinterpret_cast<double *> (malloc (numberColumns_ * sizeof(double)));
+  memset(obj, 0, numberColumns_ * sizeof(double));
+
+  for(i=0; i<cnt_obj; i++) {
+    icol = findHash(colNames[i], 1);
+    if(icol < 0) {
+      char str[8192];
+      sprintf(str,"### ERROR: Hash table: %s (obj) not found\n", colNames[i]);
+      throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
+    }
+    obj[icol] = objsense * coeff[i];
+  }
+
+  if (objsense == -1) {
+    handler_->message(COIN_GENERAL_INFO,messages_)<<
+      " CoinLpIO::readLp(): Maximization problem reformulated as minimization"
+						  <<CoinMessageEol;
+    objectiveOffset_ = -objectiveOffset_;
+  }
+
+
+  for(i=0; i<cnt_row+1; i++) {
+    start[i] -= cnt_obj;
+  }
+
+  CoinPackedMatrix *matrix = 
+    new CoinPackedMatrix(false,
+			 numberColumns_, numberRows_, numberElements_,
+			 &(coeff[cnt_obj]), &(ind[cnt_obj]), start, NULL);
+
+#ifdef LPIO_DEBUG
+  matrix->dumpMatrix();  
+#endif
+
+  setLpDataWithoutRowAndColNames(*matrix, collow, colup,
+				 obj, has_int ? is_int : 0, rowlow, rowup);
+
+
+  if(objName == NULL) {
+    rowNames[cnt_row] = CoinStrdup("obj");
+  }
+  else {
+    rowNames[cnt_row] = CoinStrdup(objName);
+  }
+
+  // Hash tables for column names are already set up
+  setLpDataRowAndColNames(rowNames, NULL);
+
+  if(are_invalid_names(names_[1], numberHash_[1], false)) {
+    setDefaultColNames();
+    handler_->message(COIN_GENERAL_WARNING,messages_)<<
+      "### CoinLpIO::readLp(): Invalid column names\nNow using default column names."
+						     <<CoinMessageEol;
+  } 
+  
+  for(i=0; i<cnt_coeff; i++) {
+    free(colNames[i]);
+  }
+  free(colNames);
+
+  for(i=0; i<cnt_row+1; i++) {
+    free(rowNames[i]);
+  }
+  free(rowNames);
+
+  free(objName);
+
+#ifdef LPIO_DEBUG
+  writeLp("readlp.xxx");
+  printf("CoinLpIO::readLp(): read Lp file written in file readlp.xxx\n");
+#endif
+
+  free(coeff);
+  free(start);
+  free(ind);
+  free(colup);
+  free(collow);
+  free(rhs);
+  free(rowlow);
+  free(rowup);
+  free(is_int);
+  free(obj);
+  delete matrix;
+
+} /* readLp */
+
+/*************************************************************************/
+void
+CoinLpIO::print() const {
+
+  printf("problemName_: %s\n", problemName_);
+  printf("numberRows_: %d\n", numberRows_);
+  printf("numberColumns_: %d\n", numberColumns_);
+
+  printf("matrixByRows_:\n");
+  matrixByRow_->dumpMatrix();  
+
+  int i;
+  printf("rowlower_:\n");
+  for(i=0; i<numberRows_; i++) {
+    printf("%.5f ", rowlower_[i]);
+  }
+  printf("\n");
+
+  printf("rowupper_:\n");
+  for(i=0; i<numberRows_; i++) {
+    printf("%.5f ", rowupper_[i]);
+  }
+  printf("\n");
+  
+  printf("collower_:\n");
+  for(i=0; i<numberColumns_; i++) {
+    printf("%.5f ", collower_[i]);
+  }
+  printf("\n");
+
+  printf("colupper_:\n");
+  for(i=0; i<numberColumns_; i++) {
+    printf("%.5f ", colupper_[i]);
+  }
+  printf("\n");
+  
+  printf("objective_:\n");
+  for(i=0; i<numberColumns_; i++) {
+    printf("%.5f ", objective_[i]);
+  }
+  printf("\n");
+  
+  if(integerType_ != NULL) {
+    printf("integerType_:\n");
+    for(i=0; i<numberColumns_; i++) {
+      printf("%c ", integerType_[i]);
+    }
+  }
+  else {
+    printf("integerType_: NULL\n");
+  }
+
+  printf("\n");
+  if(fileName_ != NULL) {
+    printf("fileName_: %s\n", fileName_);
+  }
+  printf("infinity_: %.5f\n", infinity_);
+} /* print */
+
+
+/*************************************************************************/
+// Hash functions slightly modified from CoinMpsIO.cpp
+
+namespace {
+  const int mmult[] = {
+    262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
+    241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829,
+    221281, 218849, 216319, 213721, 211093, 208673, 206263, 203773,
+    201233, 198637, 196159, 193603, 191161, 188701, 186149, 183761,
+    181303, 178873, 176389, 173897, 171469, 169049, 166471, 163871,
+    161387, 158941, 156437, 153949, 151531, 149159, 146749, 144299,
+    141709, 139369, 136889, 134591, 132169, 129641, 127343, 124853,
+    122477, 120163, 117757, 115361, 112979, 110567, 108179, 105727,
+    103387, 101021, 98639, 96179, 93911, 91583, 89317, 86939, 84521,
+    82183, 79939, 77587, 75307, 72959, 70793, 68447, 66103
+  };
+ int compute_hash(const char *name, int maxsiz, int length)
+{
+  
+  int n = 0;
+  int j;
+
+  for ( j = 0; j < length; ++j ) {
+    int iname = name[j];
+
+    n += mmult[j] * iname;
+  }
+  return ( abs ( n ) % maxsiz );	/* integer abs */
+}
+} // end file-local namespace
+
+/************************************************************************/
+//  startHash.  Creates hash list for names
+//  setup names_[section] with names in the same order as in the parameter, 
+//  but removes duplicates
+
+void
+CoinLpIO::startHash(char const * const * const names, 
+		    const COINColumnIndex number, int section)
+{
+  maxHash_[section] = 4 * number;
+  int maxhash = maxHash_[section];
+  COINColumnIndex i, ipos, iput;
+
+  names_[section] = reinterpret_cast<char **> (malloc(maxhash * sizeof(char *)));
+  hash_[section] = new CoinHashLink[maxhash];
+  
+  CoinHashLink * hashThis = hash_[section];
+  char **hashNames = names_[section];
+  
+  for ( i = 0; i < maxhash; i++ ) {
+    hashThis[i].index = -1;
+    hashThis[i].next = -1;
+  }
+  
+  /*
+   * Initialize the hash table.  Only the index of the first name that
+   * hashes to a value is entered in the table; subsequent names that
+   * collide with it are not entered.
+   */
+  
+  for (i=0; i<number; i++) {
+    const char *thisName = names[i];
+    int length = CoinStrlenAsInt(thisName);
+    
+    ipos = compute_hash(thisName, maxhash, length);
+    if (hashThis[ipos].index == -1) {
+      hashThis[ipos].index = i; // will be changed below
+    }
+  }
+  
+  /*
+   * Now take care of the names that collided in the preceding loop,
+   * by finding some other entry in the table for them.
+   * Since there are as many entries in the table as there are names,
+   * there must be room for them.
+   * Also setting up hashNames.
+   */
+
+  int cnt_distinct = 0;
+  
+  iput = -1;
+  for (i=0; i<number; i++) {
+    const char *thisName = names[i];
+    int length = CoinStrlenAsInt(thisName);
+    
+    ipos = compute_hash(thisName, maxhash, length);
+    
+    while (1) {
+      COINColumnIndex j1 = hashThis[ipos].index;
+      
+      if(j1 == i) {
+
+	// first occurence of thisName in the parameter "names"
+
+	hashThis[ipos].index = cnt_distinct;
+	hashNames[cnt_distinct] = CoinStrdup(thisName);
+	cnt_distinct++;
+	break;
+      }
+      else {
+
+#ifdef LPIO_DEBUG
+	if(j1 > i) {
+	  char str[8192];
+	  sprintf(str,"### ERROR: Hash table: j1: %d  i: %d\n", j1, i);
+	  throw CoinError(str, "startHash", "CoinLpIO", __FILE__, __LINE__);
+	}
+#endif
+
+	if (strcmp(thisName, hashNames[j1]) == 0) {
+
+	  // thisName already entered
+
+	  break;
+	}
+	else {
+	  // Collision; check if thisName already entered
+
+	  COINColumnIndex k = hashThis[ipos].next;
+
+	  if (k == -1) {
+
+	    // thisName not found; enter it
+
+	    while (1) {
+	      ++iput;
+	      if (iput > maxhash) {
+		char str[8192];
+		sprintf(str,"### ERROR: Hash table: too many names\n");
+		throw CoinError(str, "startHash", "CoinLpIO", __FILE__, __LINE__);
+		break;
+	      }
+	      if (hashThis[iput].index == -1) {
+		break;
+	      }
+	    }
+	    hashThis[ipos].next = iput;
+	    hashThis[iput].index = cnt_distinct;
+	    hashNames[cnt_distinct] = CoinStrdup(thisName);
+	    cnt_distinct++;
+	    break;
+	  } 
+	  else {
+	    ipos = k;
+
+	    // continue the check with names in collision 
+
+	  }
+	}
+      }
+    }
+  }
+
+  numberHash_[section] = cnt_distinct;
+
+} /* startHash */
+
+/**************************************************************************/
+//  stopHash.  Deletes hash storage
+void
+CoinLpIO::stopHash(int section)
+{
+  freePreviousNames(section);
+  previous_names_[section] = names_[section];
+  card_previous_names_[section] = numberHash_[section];
+
+  delete[] hash_[section];
+  hash_[section] = NULL;
+
+  maxHash_[section] = 0;
+  numberHash_[section] = 0;
+
+  if(section == 0) {
+    free(objName_);
+    objName_ = NULL;
+  }
+} /* stopHash */
+
+/**********************************************************************/
+//  findHash.  -1 not found
+COINColumnIndex
+CoinLpIO::findHash(const char *name, int section) const
+{
+  COINColumnIndex found = -1;
+
+  char ** names = names_[section];
+  CoinHashLink * hashThis = hash_[section];
+  COINColumnIndex maxhash = maxHash_[section];
+  COINColumnIndex ipos;
+
+  /* default if we don't find anything */
+  if (!maxhash)
+    return -1;
+
+  int length = CoinStrlenAsInt(name);
+
+  ipos = compute_hash(name, maxhash, length);
+  while (1) {
+    COINColumnIndex j1 = hashThis[ipos].index;
+
+    if (j1 >= 0) {
+      char *thisName2 = names[j1];
+
+      if (strcmp (name, thisName2) != 0) {
+	COINColumnIndex k = hashThis[ipos].next;
+
+	if (k != -1)
+	  ipos = k;
+	else
+	  break;
+      } 
+      else {
+	found = j1;
+	break;
+      }
+    } 
+    else {
+      found = -1;
+      break;
+    }
+  }
+  return found;
+} /* findHash */
+
+/*********************************************************************/
+void
+CoinLpIO::insertHash(const char *thisName, int section)
+{
+
+  int number = numberHash_[section];
+  int maxhash = maxHash_[section];
+
+  CoinHashLink * hashThis = hash_[section];
+  char **hashNames = names_[section];
+
+  int iput = -1;
+  int length = CoinStrlenAsInt(thisName);
+
+  int ipos = compute_hash(thisName, maxhash, length);
+
+  while (1) {
+    COINColumnIndex j1 = hashThis[ipos].index;
+    
+    if (j1 == -1) {
+      hashThis[ipos].index = number;
+      break;
+    }
+    else {
+      char *thisName2 = hashNames[j1];
+      
+      if ( strcmp (thisName, thisName2) != 0 ) {
+	COINColumnIndex k = hashThis[ipos].next;
+
+	if (k == -1) {
+	  while (1) {
+	    ++iput;
+	    if (iput == maxhash) {
+	      char str[8192];
+	      sprintf(str,"### ERROR: Hash table: too many names\n");
+	      throw CoinError(str, "insertHash", "CoinLpIO", __FILE__, __LINE__);
+	      break;
+	    }
+	    if (hashThis[iput].index == -1) {
+	      break;
+	    }
+	  }
+	  hashThis[ipos].next = iput;
+	  hashThis[iput].index = number;
+	  break;
+	} 
+	else {
+	  ipos = k;
+	  /* nothing worked - try it again */
+	}
+      }
+    }
+  }
+
+  hashNames[number] = CoinStrdup(thisName);
+  (numberHash_[section])++;
+
+}
+// Pass in Message handler (not deleted at end)
+void 
+CoinLpIO::passInMessageHandler(CoinMessageHandler * handler)
+{
+  if (defaultHandler_)
+    delete handler_;
+  defaultHandler_=false;
+  handler_=handler;
+}
+// Set language
+void 
+CoinLpIO::newLanguage(CoinMessages::Language language)
+{
+  messages_ = CoinMessage(language);
+}
+
diff --git a/cbits/coin/CoinLpIO.hpp b/cbits/coin/CoinLpIO.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinLpIO.hpp
@@ -0,0 +1,750 @@
+/* $Id: CoinLpIO.hpp 1652 2013-10-18 10:35:37Z stefan $ */
+// Last edit: 11/5/08
+//
+// Name:     CoinLpIO.hpp; Support for Lp files
+// Author:   Francois Margot
+//           Tepper School of Business
+//           Carnegie Mellon University, Pittsburgh, PA 15213
+//           email: fmargot@andrew.cmu.edu
+// Date:     12/28/03
+//-----------------------------------------------------------------------------
+// Copyright (C) 2003, Francois Margot, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinLpIO_H
+#define CoinLpIO_H
+
+#include <cstdio>
+
+#include "CoinPackedMatrix.hpp"
+#include "CoinMessage.hpp"
+
+typedef int COINColumnIndex;
+
+  /** Class to read and write Lp files 
+
+ Lp file format: 
+
+/ this is a comment <BR>
+\ this too <BR>
+ Min<BR>
+  obj: x0 + x1 + 3 x2 - 4.5 xyr + 1 <BR>
+ s.t. <BR>
+ cons1: x0 - x2 - 2.3 x4 <= 4.2   / this is another comment <BR>
+ c2: x1 + x2 >= 1 <BR>
+ cc: x1 + x2 + xyr = 2 <BR>
+ Bounds <BR>
+ 0 <= x1 <= 3 <BR>
+ 1 >= x2 <BR>
+ x3 = 1 <BR>
+ -2 <= x4 <= Inf <BR>
+ xyr free <BR>
+ Integers <BR>
+ x0 <BR>
+ Generals <BR>
+ x1 xyr <BR>
+ Binaries <BR>
+ x2 <BR>
+ End
+
+Notes: <UL>
+ <LI> Keywords are: Min, Max, Minimize, Maximize, s.t., Subject To, 
+      Bounds, Integers, Generals, Binaries, End, Free, Inf. 
+ <LI> Keywords are not case sensitive and may be in plural or singular form.
+      They should not be used as objective, row or column names.
+ <LI> Bounds, Integers, Generals, Binaries sections are optional.
+ <LI> Generals and Integers are synonymous.
+ <LI> Bounds section (if any) must come before Integers, Generals, and 
+      Binaries sections.
+ <LI> Row names must be followed by ':' without blank space.
+      Row names are optional. If row names are present, 
+      they must be distinct (if the k-th constraint has no given name, its name
+      is set automatically to "consk" for k=0,...,).
+      For valid row names, see the method is_invalid_name(). 
+ <LI> Column names must be followed by a blank space. They must be distinct. 
+      For valid column names, see the method is_invalid_name(). 
+ <LI> The objective function name must be followed by ':' without blank space.
+      Objective function name is optional (if no objective function name
+      is given, it is set to "obj" by default).
+      For valid objective function names, see the method is_invalid_name(). 
+ <LI> Ranged constraints are written as two constraints.
+      If a name is given for a ranged constraint, the upper bound constraint 
+      has that name and the lower bound constraint has that name with "_low" 
+      as suffix. This should be kept in mind when assigning names to ranged
+      constraint, as the resulting name must be distinct from all the other
+      names and be considered valid by the method is_invalid_name().
+ <LI> At most one term related to any single variable may appear in the
+      objective function; if more than one term are present, only the last
+      one is taken into account.
+      At most one constant term may appear in the objective function; 
+      if present, it must appear last. 
+ <LI> Default bounds are 0 for lower bound and +infinity for upper bound.
+ <LI> Free variables get default lower bound -infinity and 
+      default upper bound +infinity. Writing "x0 Free" in an
+      LP file means "set lower bound on x0 to -infinity".
+ <LI> If more than one upper (resp. lower) bound on a variable appears in 
+      the Bounds section, the last one is the one taken into 
+      account. The bounds for a binary variable are set to 0/1 only if this 
+      bound is stronger than the bound obtained from the Bounds section. 
+ <LI> Numbers larger than DBL_MAX (or larger than 1e+400) in the input file
+      might crash the code.
+ <LI> A comment must start with '\' or '/'. That symbol must either be
+      the first character of a line or be preceded by a blank space. The 
+      comment ends at the end of the 
+      line. Comments are skipped while reading an Lp file and they may be
+      inserted anywhere.
+</UL>
+*/
+class CoinLpIO {
+      friend void CoinLpIOUnitTest(const std::string & lpDir); 
+public:
+
+  /**@name Constructor and Destructor */
+  //@{
+  /// Default Constructor
+  CoinLpIO(); 
+  
+  /// Does the heavy lifting for destruct and assignment.
+  void gutsOfDestructor(); 
+ 
+  /// Does the heavy lifting for copy and assignment
+  void gutsOfCopy(const CoinLpIO &); 
+ 
+  /// assignment operator
+  CoinLpIO & operator = (const CoinLpIO& rhs) ; 
+ 
+  /// Copy constructor 
+  CoinLpIO (const CoinLpIO &); 
+
+  /// Destructor 
+  ~CoinLpIO();
+
+  /** Free the vector previous_names_[section] and set 
+      card_previous_names_[section] to 0.
+      section = 0 for row names, 
+      section = 1 for column names.  
+  */
+  void freePreviousNames(const int section);
+
+  /// Free all memory (except memory related to hash tables and objName_).
+  void freeAll();
+  //@}
+
+    /** A quick inlined function to convert from lb/ub style constraint
+	definition to sense/rhs/range style */
+    inline void
+    convertBoundToSense(const double lower, const double upper,
+			char& sense, double& right, double& range) const;
+
+  /**@name Queries */
+  //@{
+
+  /// Get the problem name
+  const char * getProblemName() const;
+
+  /// Set problem name
+  void setProblemName(const char *name);
+
+  /// Get number of columns
+  int getNumCols() const;
+
+  /// Get number of rows
+  int getNumRows() const;
+
+  /// Get number of nonzero elements
+  int getNumElements() const;
+  
+  /// Get pointer to array[getNumCols()] of column lower bounds
+  const double * getColLower() const;
+
+  /// Get pointer to array[getNumCols()] of column upper bounds
+  const double * getColUpper() const;
+
+  /// Get pointer to array[getNumRows()] of row lower bounds
+  const double * getRowLower() const;
+  
+  /// Get pointer to array[getNumRows()] of row upper bounds
+  const double * getRowUpper() const;
+      /** Get pointer to array[getNumRows()] of constraint senses.
+	<ul>
+	<li>'L': <= constraint
+	<li>'E': =  constraint
+	<li>'G': >= constraint
+	<li>'R': ranged constraint
+	<li>'N': free constraint
+	</ul>
+      */
+  const char * getRowSense() const;
+  
+  /** Get pointer to array[getNumRows()] of constraint right-hand sides.
+      
+  Given constraints with upper (rowupper) and/or lower (rowlower) bounds,
+  the constraint right-hand side (rhs) is set as
+  <ul>
+  <li> if rowsense()[i] == 'L' then rhs()[i] == rowupper()[i]
+  <li> if rowsense()[i] == 'G' then rhs()[i] == rowlower()[i]
+  <li> if rowsense()[i] == 'R' then rhs()[i] == rowupper()[i]
+  <li> if rowsense()[i] == 'N' then rhs()[i] == 0.0
+	</ul>
+  */
+  const double * getRightHandSide() const;
+  
+  /** Get pointer to array[getNumRows()] of row ranges.
+      
+  Given constraints with upper (rowupper) and/or lower (rowlower) bounds, 
+  the constraint range (rowrange) is set as
+  <ul>
+  <li> if rowsense()[i] == 'R' then
+  rowrange()[i] == rowupper()[i] - rowlower()[i]
+  <li> if rowsense()[i] != 'R' then
+  rowrange()[i] is 0.0
+  </ul>
+  Put another way, only ranged constraints have a nontrivial value for
+  rowrange.
+  */
+  const double * getRowRange() const;
+
+  /// Get pointer to array[getNumCols()] of objective function coefficients
+  const double * getObjCoefficients() const;
+  
+  /// Get pointer to row-wise copy of the coefficient matrix
+  const CoinPackedMatrix * getMatrixByRow() const;
+
+  /// Get pointer to column-wise copy of the coefficient matrix
+  const CoinPackedMatrix * getMatrixByCol() const;
+
+  /// Get objective function name
+  const char * getObjName() const;
+  
+  /// Get pointer to array[*card_prev] of previous row names.
+  /// The value of *card_prev might be different than getNumRows()+1 if 
+  /// non distinct
+  /// row names were present or if no previous names were saved or if
+  /// the object was holding a different problem before.
+  void getPreviousRowNames(char const * const * prev, 
+			   int *card_prev) const;
+
+  /// Get pointer to array[*card_prev] of previous column names.
+  /// The value of *card_prev might be different than getNumCols() if non
+  /// distinct column names were present of if no previous names were saved, 
+  /// or if the object was holding a different problem before. 
+  void getPreviousColNames(char const * const * prev, 
+			   int *card_prev) const;
+
+  /// Get pointer to array[getNumRows()+1] of row names, including
+  /// objective function name as last entry.
+  char const * const * getRowNames() const;
+  
+  /// Get pointer to array[getNumCols()] of column names
+  char const * const *getColNames() const;
+  
+  /// Return the row name for the specified index.
+  /// Return the objective function name if index = getNumRows().
+  /// Return 0 if the index is out of range or if row names are not defined.
+  const char * rowName(int index) const;
+
+  /// Return the column name for the specified index.
+  /// Return 0 if the index is out of range or if column names are not 
+  /// defined.
+  const char * columnName(int index) const;
+
+  /// Return the index for the specified row name.
+  /// Return getNumRows() for the objective function name.
+  /// Return -1 if the name is not found.
+  int rowIndex(const char * name) const;
+
+  /// Return the index for the specified column name.
+  /// Return -1 if the name is not found.
+  int columnIndex(const char * name) const;
+
+  ///Returns the (constant) objective offset
+  double objectiveOffset() const;
+  
+  /// Set objective offset
+  inline void setObjectiveOffset(double value)
+  { objectiveOffset_ = value;}
+  
+  /// Return true if a column is an integer (binary or general 
+  /// integer) variable
+  bool isInteger(int columnNumber) const;
+  
+  /// Get characteristic vector of integer variables
+  const char * integerColumns() const;
+  //@}
+  
+  /**@name Parameters */
+  //@{
+  /// Get infinity
+  double getInfinity() const;
+
+  /// Set infinity. Any number larger is considered infinity.
+  /// Default: DBL_MAX
+  void setInfinity(const double);
+
+  /// Get epsilon
+  double getEpsilon() const;
+
+  /// Set epsilon.
+  /// Default: 1e-5.
+  void setEpsilon(const double);
+
+  /// Get numberAcross, the number of monomials to be printed per line
+  int getNumberAcross() const;
+
+  /// Set numberAcross.
+  /// Default: 10.
+  void setNumberAcross(const int);
+
+  /// Get decimals, the number of digits to write after the decimal point
+  int getDecimals() const;
+
+  /// Set decimals.
+  /// Default: 5
+  void setDecimals(const int);
+  //@}
+
+  /**@name Public methods */
+  //@{
+  /** Set the data of the object.
+      Set it from the coefficient matrix m, the lower bounds
+      collb,  the upper bounds colub, objective function obj_coeff, 
+      integrality vector integrality, lower/upper bounds on the constraints.
+      The sense of optimization of the objective function is assumed to be 
+      a minimization. 
+      Numbers larger than DBL_MAX (or larger than 1e+400) 
+      might crash the code.
+  */
+  void setLpDataWithoutRowAndColNames(
+			      const CoinPackedMatrix& m,
+			      const double* collb, const double* colub,
+			      const double* obj_coeff, 
+			      const char* integrality,
+			      const double* rowlb, const double* rowub);
+
+  /** Return 0 if buff is a valid name for a row, a column or objective
+      function, return a positive number otherwise.
+      If parameter ranged = true, the name is intended for a ranged 
+      constraint. <BR>
+      Return 1 if the name has more than 100 characters (96 characters
+      for a ranged constraint name, as "_low" will be added to the name).<BR>
+      Return 2 if the name starts with a number.<BR>
+      Return 3 if the name is not built with 
+      the letters a to z, A to Z, the numbers 0 to 9 or the characters
+      " ! # $ % & ( ) . ; ? @ _ ' ` { } ~ <BR>
+      Return 4 if the name is a keyword.<BR>
+      Return 5 if the name is empty or NULL. */
+  int is_invalid_name(const char *buff, const bool ranged) const;
+  
+  /** Return 0 if each of the card_vnames entries of vnames is a valid name, 
+      return a positive number otherwise. The return value, if not 0, is the 
+      return value of is_invalid_name() for the last invalid name
+      in vnames. If check_ranged = true, the names are row names and 
+      names for ranged constaints must be checked for additional restrictions
+      since "_low" will be added to the name if an Lp file is written.
+      When check_ranged = true, card_vnames must have getNumRows()+1 entries, 
+      with entry vnames[getNumRows()] being the
+      name of the objective function.
+      For a description of valid names and return values, see the method 
+      is_invalid_name(). 
+
+      This method must not be called with check_ranged = true before 
+      setLpDataWithoutRowAndColNames() has been called, since access
+      to the indices of all the ranged constraints is required.
+  */
+  int are_invalid_names(char const * const *vnames, 
+				  const int card_vnames,
+				  const bool check_ranged) const;
+  
+  /// Set objective function name to the default "obj" and row 
+  /// names to the default "cons0", "cons1", ...
+  void setDefaultRowNames();
+
+  /// Set column names to the default "x0", "x1", ...
+  void setDefaultColNames();
+
+  /** Set the row and column names.
+      The array rownames must either be NULL or have exactly getNumRows()+1 
+      distinct entries,
+      each of them being a valid name (see is_invalid_name()) and the
+      last entry being the intended name for the objective function.
+      If rownames is NULL, existing row names and objective function
+      name are not changed.
+      If rownames is deemed invalid, default row names and objective function
+      name are used (see setDefaultRowNames()). The memory location of 
+      array rownames (or its entries) should not be related
+      to the memory location of the array (or entries) obtained from 
+      getRowNames() or getPreviousRowNames(), as the call to 
+      setLpDataRowAndColNames() modifies the corresponding arrays. 
+      Unpredictable results
+      are obtained if this requirement is ignored.
+
+      Similar remarks apply to the array colnames, which must either be
+      NULL or have exactly getNumCols() entries.
+  */
+  void setLpDataRowAndColNames(char const * const * const rownames,
+			       char const * const * const colnames);
+
+  /** Write the data in Lp format in the file with name filename.
+      Coefficients with value less than epsilon away from an integer value
+      are written as integers.
+      Write at most numberAcross monomials on a line.
+      Write non integer numbers with decimals digits after the decimal point.
+      Write objective function name and row names if useRowNames = true.
+
+      Ranged constraints are written as two constraints.
+      If row names are used, the upper bound constraint has the
+      name of the original ranged constraint and the
+      lower bound constraint has for name the original name with 
+      "_low" as suffix. If doing so creates two identical row names,
+      default row names are used (see setDefaultRowNames()).
+  */
+  int writeLp(const char *filename, 
+	      const double epsilon, 
+	      const int numberAcross,
+	      const int decimals,
+	      const bool useRowNames = true);
+
+  /** Write the data in Lp format in the file pointed to by the paramater fp.
+      Coefficients with value less than epsilon away from an integer value
+      are written as integers.
+      Write at most numberAcross monomials on a line.
+      Write non integer numbers with decimals digits after the decimal point.
+      Write objective function name and row names if useRowNames = true.
+
+      Ranged constraints are written as two constraints.
+      If row names are used, the upper bound constraint has the
+      name of the original ranged constraint and the
+      lower bound constraint has for name the original name with 
+      "_low" as suffix. If doing so creates two identical row names,
+      default row names are used (see setDefaultRowNames()).
+  */
+  int writeLp(FILE *fp, 
+	      const double epsilon, 
+	      const int numberAcross,
+	      const int decimals,
+	      const bool useRowNames = true);
+
+  /// Write the data in Lp format in the file with name filename.
+  /// Write objective function name and row names if useRowNames = true.
+  int writeLp(const char *filename, const bool useRowNames = true);
+
+  /// Write the data in Lp format in the file pointed to by the parameter fp.
+  /// Write objective function name and row names if useRowNames = true.
+  int writeLp(FILE *fp, const bool useRowNames = true);
+
+  /// Read the data in Lp format from the file with name filename, using
+  /// the given value for epsilon. If the original problem is
+  /// a maximization problem, the objective function is immediadtly 
+  /// flipped to get a minimization problem.
+  void readLp(const char *filename, const double epsilon);
+
+  /// Read the data in Lp format from the file with name filename.
+  /// If the original problem is
+  /// a maximization problem, the objective function is immediadtly 
+  /// flipped to get a minimization problem.  
+  void readLp(const char *filename);
+
+  /// Read the data in Lp format from the file stream, using
+  /// the given value for epsilon.
+  /// If the original problem is
+  /// a maximization problem, the objective function is immediadtly 
+  /// flipped to get a minimization problem.  
+  void readLp(FILE *fp, const double epsilon);
+
+  /// Read the data in Lp format from the file stream.
+  /// If the original problem is
+  /// a maximization problem, the objective function is immediadtly 
+  /// flipped to get a minimization problem.  
+  void readLp(FILE *fp);
+
+  /// Dump the data. Low level method for debugging.
+  void print() const;
+  //@}
+/**@name Message handling */
+//@{
+  /** Pass in Message handler
+  
+      Supply a custom message handler. It will not be destroyed when the
+      CoinMpsIO object is destroyed.
+  */
+  void passInMessageHandler(CoinMessageHandler * handler);
+
+  /// Set the language for messages.
+  void newLanguage(CoinMessages::Language language);
+
+  /// Set the language for messages.
+  inline void setLanguage(CoinMessages::Language language) {newLanguage(language);}
+
+  /// Return the message handler
+  inline CoinMessageHandler * messageHandler() const {return handler_;}
+
+  /// Return the messages
+  inline CoinMessages messages() {return messages_;}
+  /// Return the messages pointer
+  inline CoinMessages * messagesPointer() {return & messages_;}
+//@}
+
+protected:
+  /// Problem name
+  char * problemName_;
+
+  /// Message handler
+  CoinMessageHandler * handler_;
+  /** Flag to say if the message handler is the default handler.
+      
+      If true, the handler will be destroyed when the CoinMpsIO
+      object is destroyed; if false, it will not be destroyed.
+  */
+  bool defaultHandler_;
+  /// Messages
+  CoinMessages messages_;
+
+  /// Number of rows
+  int numberRows_;
+  
+  /// Number of columns
+  int numberColumns_;
+  
+  /// Number of elements
+  int numberElements_;
+  
+  /// Pointer to column-wise copy of problem matrix coefficients.
+  mutable CoinPackedMatrix *matrixByColumn_;  
+  
+  /// Pointer to row-wise copy of problem matrix coefficients.
+  CoinPackedMatrix *matrixByRow_;  
+  
+  /// Pointer to dense vector of row lower bounds
+  double * rowlower_;
+  
+  /// Pointer to dense vector of row upper bounds
+  double * rowupper_;
+  
+  /// Pointer to dense vector of column lower bounds
+  double * collower_;
+  
+  /// Pointer to dense vector of column upper bounds
+  double * colupper_;
+  
+  /// Pointer to dense vector of row rhs
+  mutable double * rhs_;
+  
+  /** Pointer to dense vector of slack variable upper bounds for ranged 
+      constraints (undefined for non-ranged constraints)
+  */
+  mutable double  *rowrange_;
+
+  /// Pointer to dense vector of row senses
+  mutable char * rowsense_;
+  
+  /// Pointer to dense vector of objective coefficients
+  double * objective_;
+  
+  /// Constant offset for objective value
+  double objectiveOffset_;
+  
+  /// Pointer to dense vector specifying if a variable is continuous
+  /// (0) or integer (1).
+  char * integerType_;
+  
+  /// Current file name
+  char * fileName_;
+  
+  /// Value to use for infinity
+  double infinity_;
+
+  /// Value to use for epsilon
+  double epsilon_;
+
+  /// Number of monomials printed in a row
+  int numberAcross_;
+
+  /// Number of decimals printed for coefficients
+  int decimals_;
+
+  /// Objective function name
+  char *objName_;
+
+  /** Row names (including objective function name) 
+      and column names when stopHash() for the corresponding 
+      section was last called or for initial names (deemed invalid) 
+      read from a file.<BR>
+      section = 0 for row names, 
+      section = 1 for column names.  */
+  char **previous_names_[2];
+
+  /// card_previous_names_[section] holds the number of entries in the vector 
+  /// previous_names_[section].
+  /// section = 0 for row names, 
+  /// section = 1 for column names. 
+  int card_previous_names_[2];
+
+  /// Row names (including objective function name) 
+  /// and column names (linked to Hash tables).
+  /// section = 0 for row names, 
+  /// section = 1 for column names. 
+  char **names_[2];
+
+  typedef struct {
+    int index, next;
+  } CoinHashLink;
+
+  /// Maximum number of entries in a hash table section.
+  /// section = 0 for row names, 
+  /// section = 1 for column names. 
+  int maxHash_[2];
+
+  /// Number of entries in a hash table section.
+  /// section = 0 for row names, 
+  /// section = 1 for column names. 
+  int numberHash_[2];
+
+  /// Hash tables with two sections.
+  /// section = 0 for row names (including objective function name), 
+  /// section = 1 for column names. 
+  mutable CoinHashLink *hash_[2];
+
+  /// Build the hash table for the given names. The parameter number is
+  /// the cardinality of parameter names. Remove duplicate names. 
+  ///
+  /// section = 0 for row names, 
+  /// section = 1 for column names. 
+  void startHash(char const * const * const names, 
+		 const COINColumnIndex number, 
+		 int section);
+
+  /// Delete hash storage. If section = 0, it also frees objName_.
+  /// section = 0 for row names, 
+  /// section = 1 for column names. 
+  void stopHash(int section);
+
+  /// Return the index of the given name, return -1 if the name is not found.
+  /// Return getNumRows() for the objective function name.
+  /// section = 0 for row names (including objective function name), 
+  /// section = 1 for column names. 
+  COINColumnIndex findHash(const char *name, int section) const;
+
+  /// Insert thisName in the hash table if not present yet; does nothing
+  /// if the name is already in.
+  /// section = 0 for row names, 
+  /// section = 1 for column names. 
+  void insertHash(const char *thisName, int section);
+
+  /// Write a coefficient.
+  /// print_1 = 0 : do not print the value 1.
+  void out_coeff(FILE *fp, double v, int print_1) const;
+
+  /// Locate the objective function. 
+  /// Return 1 if found the keyword "Minimize" or one of its variants, 
+  /// -1 if found keyword "Maximize" or one of its variants.
+  int find_obj(FILE *fp) const;
+
+  /// Return an integer indicating if the keyword "subject to" or one
+  /// of its variants has been read.
+  /// Return 1 if buff is the keyword "s.t" or one of its variants.
+  /// Return 2 if buff is the keyword "subject" or one of its variants.
+  /// Return 0 otherwise.
+  int is_subject_to(const char *buff) const;
+
+  /// Return 1 if the first character of buff is a number.
+  /// Return 0 otherwise.
+  int first_is_number(const char *buff) const;
+
+  /// Return 1 if the first character of buff is '/' or '\'.
+  /// Return 0 otherwise.
+  int is_comment(const char *buff) const;
+
+  /// Read the file fp until buff contains an end of line
+  void skip_comment(char *buff, FILE *fp) const;
+
+  /// Put in buff the next string that is not part of a comment
+  void scan_next(char *buff, FILE *fp) const;
+
+  /// Return 1 if buff is the keyword "free" or one of its variants.
+  /// Return 0 otherwise.
+  int is_free(const char *buff) const;
+  
+  /// Return 1 if buff is the keyword "inf" or one of its variants.
+  /// Return 0 otherwise.
+  int is_inf(const char *buff) const;
+  
+  /// Return an integer indicating the inequality sense read.
+  /// Return 0 if buff is '<='.
+  /// Return 1 if buff is '='.
+  /// Return 2 if buff is '>='.
+  /// Return -1 otherwise.
+  int is_sense(const char *buff) const;
+
+  /// Return an integer indicating if one of the keywords "Bounds", "Integers",
+  /// "Generals", "Binaries", "End", or one
+  /// of their variants has been read.
+  /// Return 1 if buff is the keyword "Bounds" or one of its variants.
+  /// Return 2 if buff is the keyword "Integers" or "Generals" or one of their 
+  /// variants.
+  /// Return 3 if buff is the keyword "Binaries" or one of its variants.
+  /// Return 4 if buff is the keyword "End" or one of its variants.
+  /// Return 0 otherwise.
+  int is_keyword(const char *buff) const;
+
+  /// Read a monomial of the objective function.
+  /// Return 1 if "subject to" or one of its variants has been read.
+  int read_monom_obj(FILE *fp, double *coeff, char **name, int *cnt, 
+		     char **obj_name);
+
+  /// Read a monomial of a constraint.
+  /// Return a positive number if the sense of the inequality has been 
+  /// read (see method is_sense() for the return code).
+  /// Return -1 otherwise.
+  int read_monom_row(FILE *fp, char *start_str, double *coeff, char **name, 
+		     int cnt_coeff) const;
+
+  /// Reallocate vectors related to number of coefficients.
+  void realloc_coeff(double **coeff, char ***colNames, int *maxcoeff) const;
+
+  /// Reallocate vectors related to rows.
+  void realloc_row(char ***rowNames, int **start, double **rhs, 
+		   double **rowlow, double **rowup, int *maxrow) const;
+    
+  /// Reallocate vectors related to columns.
+  void realloc_col(double **collow, double **colup, char **is_int,
+		   int *maxcol) const;
+
+  /// Read a constraint.
+  void read_row(FILE *fp, char *buff, double **pcoeff, char ***pcolNames, 
+		int *cnt_coeff, int *maxcoeff,
+		     double *rhs, double *rowlow, double *rowup, 
+		     int *cnt_row, double inf) const;
+
+  /** Check that current objective name and all row names are distinct
+      including row names obtained by adding "_low" for ranged constraints.
+      If there is a conflict in the names, they are replaced by default 
+      row names (see setDefaultRowNames()).
+
+      This method must not be called before 
+      setLpDataWithoutRowAndColNames() has been called, since access
+      to the indices of all the ranged constraints is required.
+
+      This method must not be called before 
+      setLpDataRowAndColNames() has been called, since access
+      to all the row names is required.
+  */
+  void checkRowNames();
+
+  /** Check that current column names are distinct.
+      If not, they are replaced by default 
+      column names (see setDefaultColNames()).
+
+      This method must not be called before 
+      setLpDataRowAndColNames() has been called, since access
+      to all the column names is required.
+  */
+  void checkColNames();
+
+};
+
+void
+CoinLpIOUnitTest(const std::string& lpDir);
+
+
+#endif 
diff --git a/cbits/coin/CoinMessage.cpp b/cbits/coin/CoinMessage.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinMessage.cpp
@@ -0,0 +1,110 @@
+/* $Id: CoinMessage.cpp 1540 2012-06-28 10:31:24Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinPragma.hpp"
+#include "CoinMessage.hpp"
+#include "CoinError.hpp"
+
+typedef struct {
+  COIN_Message internalNumber;
+  int externalNumber; // or continuation
+  char detail;
+  const char * message;
+} Coin_message;
+static Coin_message us_english[]=
+{
+  {COIN_MPS_LINE,1,1,"At line %d %s"},
+  {COIN_MPS_STATS,2,1,"Problem %s has %d rows, %d columns and %d elements"},
+  {COIN_MPS_ILLEGAL,3001,0,"Illegal value for %s of %g"},
+  {COIN_MPS_BADIMAGE,3002,0,"Bad image at line %d < %s >"},
+  {COIN_MPS_DUPOBJ,3003,0,"Duplicate objective at line %d < %s >"},
+  {COIN_MPS_DUPROW,3004,0,"Duplicate row %s at line %d < %s >"},
+  {COIN_MPS_NOMATCHROW,3005,0,"No match for row %s at line %d < %s >"},
+  {COIN_MPS_NOMATCHCOL,3006,0,"No match for column %s at line %d < %s >"},
+  {COIN_MPS_FILE,6001,0,"Unable to open mps input file %s"},
+  {COIN_MPS_BADFILE1,6002,0,"Unknown image %s at line %d of file %s"},
+  {COIN_MPS_BADFILE2,6003,0,"Consider the possibility of a compressed file\
+ which %s is unable to read"},
+  {COIN_MPS_EOF,6004,0,"EOF on file %s"},
+  {COIN_MPS_RETURNING,6005,0,"Returning as too many errors"},
+  {COIN_MPS_CHANGED,3007,1,"Generated %s names had duplicates - %d changed"},
+  {COIN_SOLVER_MPS,8,1,"%s read with %d errors"},
+  {COIN_PRESOLVE_COLINFEAS,501,2,"Problem is infeasible due to column %d, %.16g %.16g"},
+  {COIN_PRESOLVE_ROWINFEAS,502,2,"Problem is infeasible due to row %d, %.16g %.16g"},
+  {COIN_PRESOLVE_COLUMNBOUNDA,503,2,"Problem looks unbounded above due to column %d, %g %g"},
+  {COIN_PRESOLVE_COLUMNBOUNDB,504,2,"Problem looks unbounded below due to column %d, %g %g"},
+  {COIN_PRESOLVE_NONOPTIMAL,505,1,"Presolved problem not optimal, resolve after postsolve"},
+  {COIN_PRESOLVE_STATS,506,1,"Presolve %d (%d) rows, %d (%d) columns and %d (%d) elements"},
+  {COIN_PRESOLVE_INFEAS,507,1,"Presolve determined that the problem was infeasible with tolerance of %g"},
+  {COIN_PRESOLVE_UNBOUND,508,1,"Presolve thinks problem is unbounded"},
+  {COIN_PRESOLVE_INFEASUNBOUND,509,1,"Presolve thinks problem is infeasible AND unbounded???"},
+  {COIN_PRESOLVE_INTEGERMODS,510,1,"Presolve is modifying %d integer bounds and re-presolving"},
+  {COIN_PRESOLVE_POSTSOLVE,511,1,"After Postsolve, objective %g, infeasibilities - dual %g (%d), primal %g (%d)"},
+  {COIN_PRESOLVE_NEEDS_CLEANING,512,1,"Presolved model was optimal, full model needs cleaning up"},
+  {COIN_PRESOLVE_PASS,513,3,"%d rows dropped after presolve pass %d"},
+# if PRESOLVE_DEBUG
+  { COIN_PRESOLDBG_FIRSTCHECK,514,3,"First occurrence of %s checks." },
+  { COIN_PRESOLDBG_RCOSTACC,515,3,
+    "rcost[%d] = %g should be %g |diff| = %g." },
+  { COIN_PRESOLDBG_RCOSTSTAT,516,3,
+    "rcost[%d] = %g inconsistent with status %s (%s)." },
+  { COIN_PRESOLDBG_STATSB,517,3,
+    "status[%d] = %s rcost = %g lb = %g val = %g ub = %g." },
+  { COIN_PRESOLDBG_DUALSTAT,518,3,
+    "dual[%d] = %g inconsistent with status %s (%s)." },
+# endif
+  {COIN_GENERAL_INFO,9,1,"%s"},
+  {COIN_GENERAL_WARNING,3007,1,"%s"},
+  {COIN_DUMMY_END,999999,0,""}
+};
+// **** aiutami!
+static Coin_message italian[]=
+{
+  {COIN_MPS_LINE,1,1,"al numero %d %s"},
+  {COIN_MPS_STATS,2,1,"matrice %s ha %d file, %d colonne and %d elementi (diverso da zero)"},
+  {COIN_DUMMY_END,999999,0,""}
+};
+/* Constructor */
+CoinMessage::CoinMessage(Language language) :
+  CoinMessages(sizeof(us_english)/sizeof(Coin_message))
+{
+  language_=language;
+  strcpy(source_,"Coin");
+  class_= 2; // Coin
+  Coin_message * message = us_english;
+
+  while (message->internalNumber!=COIN_DUMMY_END) {
+    CoinOneMessage oneMessage(message->externalNumber,message->detail,
+		message->message);
+    addMessage(message->internalNumber,oneMessage);
+    message ++;
+  }
+  // Put into compact form
+  toCompact();
+  // now override any language ones
+
+  switch (language) {
+  case it:
+    message = italian;
+    break;
+
+  default:
+    message=NULL;
+    break;
+  }
+
+  // replace if any found
+  if (message) {
+    while (message->internalNumber!=COIN_DUMMY_END) {
+      replaceMessage(message->internalNumber,message->message);
+      message ++;
+    }
+  }
+}
diff --git a/cbits/coin/CoinMessage.hpp b/cbits/coin/CoinMessage.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinMessage.hpp
@@ -0,0 +1,95 @@
+/* $Id: CoinMessage.hpp 1411 2011-03-30 11:40:33Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinMessage_H
+#define CoinMessage_H
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+/*! \file
+
+    This file contains the enum for the standard set of Coin messages and a
+    class definition whose sole purpose is to supply a constructor. The text
+    ot the messages is defined in CoinMessage.cpp,
+
+    CoinMessageHandler.hpp contains the generic facilities for message
+    handling.
+*/
+
+#include "CoinMessageHandler.hpp"
+
+/*! \brief Symbolic names for the standard set of COIN messages */
+
+enum COIN_Message
+{
+  COIN_MPS_LINE=0,
+  COIN_MPS_STATS,
+  COIN_MPS_ILLEGAL,
+  COIN_MPS_BADIMAGE,
+  COIN_MPS_DUPOBJ,
+  COIN_MPS_DUPROW,
+  COIN_MPS_NOMATCHROW,
+  COIN_MPS_NOMATCHCOL,
+  COIN_MPS_FILE,
+  COIN_MPS_BADFILE1,
+  COIN_MPS_BADFILE2,
+  COIN_MPS_EOF,
+  COIN_MPS_RETURNING,
+  COIN_MPS_CHANGED,
+  COIN_SOLVER_MPS,
+  COIN_PRESOLVE_COLINFEAS,
+  COIN_PRESOLVE_ROWINFEAS,
+  COIN_PRESOLVE_COLUMNBOUNDA,
+  COIN_PRESOLVE_COLUMNBOUNDB,
+  COIN_PRESOLVE_NONOPTIMAL,
+  COIN_PRESOLVE_STATS,
+  COIN_PRESOLVE_INFEAS,
+  COIN_PRESOLVE_UNBOUND,
+  COIN_PRESOLVE_INFEASUNBOUND,
+  COIN_PRESOLVE_INTEGERMODS,
+  COIN_PRESOLVE_POSTSOLVE,
+  COIN_PRESOLVE_NEEDS_CLEANING,
+  COIN_PRESOLVE_PASS,
+# if PRESOLVE_DEBUG
+  COIN_PRESOLDBG_FIRSTCHECK,
+  COIN_PRESOLDBG_RCOSTACC,
+  COIN_PRESOLDBG_RCOSTSTAT,
+  COIN_PRESOLDBG_STATSB,
+  COIN_PRESOLDBG_DUALSTAT,
+# endif
+  COIN_GENERAL_INFO,
+  COIN_GENERAL_WARNING,
+  COIN_DUMMY_END
+};
+
+
+/*! \class CoinMessage
+    \brief The standard set of Coin messages
+
+    This class provides convenient access to the standard set of Coin messages.
+    In a nutshell, it's a CoinMessages object with a constructor that
+    preloads the standard Coin messages.
+*/
+
+class CoinMessage : public CoinMessages {
+
+public:
+
+  /**@name Constructors etc */
+  //@{
+  /*! \brief Constructor
+  
+    Build a CoinMessages object and load it with the standard set of
+    Coin messages.
+  */
+  CoinMessage(Language language=us_en);
+  //@}
+
+};
+
+#endif
diff --git a/cbits/coin/CoinMessageHandler.cpp b/cbits/coin/CoinMessageHandler.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinMessageHandler.cpp
@@ -0,0 +1,984 @@
+/* $Id: CoinMessageHandler.cpp 1513 2011-12-10 23:34:13Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinMessageHandler.hpp"
+#include "CoinHelperFunctions.hpp"
+#include <cassert>
+#include <cstdlib>
+#include <cstddef>
+#include <map>
+
+
+/* Default constructor. */
+CoinOneMessage::CoinOneMessage()
+{
+  externalNumber_=-1;
+  message_[0]='\0';
+  severity_='I';
+  detail_=0;
+}
+/* Destructor */
+CoinOneMessage::~CoinOneMessage()
+{
+}
+/* The copy constructor */
+CoinOneMessage::CoinOneMessage(const CoinOneMessage & rhs)
+{
+  externalNumber_=rhs.externalNumber_;
+  strcpy(message_,rhs.message_);
+  severity_=rhs.severity_;
+  detail_=rhs.detail_;
+}
+/* assignment operator. */
+CoinOneMessage& 
+CoinOneMessage::operator=(const CoinOneMessage & rhs)
+{
+  if (this != &rhs) {
+    externalNumber_=rhs.externalNumber_;
+    strcpy(message_,rhs.message_);
+    severity_=rhs.severity_;
+    detail_=rhs.detail_;
+  }
+  return *this;
+}
+/* Normal constructor */
+CoinOneMessage::CoinOneMessage(int externalNumber, char detail,
+		const char * message)
+{
+  externalNumber_=externalNumber;
+  strcpy(message_,message);
+  if (externalNumber<3000)
+    severity_='I';
+  else if (externalNumber<6000)
+    severity_='W';
+  else if (externalNumber<9000)
+    severity_='E';
+  else
+    severity_='S';
+  detail_=detail;
+}
+// Replaces messages (i.e. a different language)
+void 
+CoinOneMessage::replaceMessage( const char * message)
+{
+  strcpy(message_,message);
+}
+
+
+/* Constructor with number of messages. */
+CoinMessages::CoinMessages(int numberMessages)
+{
+  numberMessages_=numberMessages;
+  language_=us_en;
+  strcpy(source_,"Unk");
+  class_=1;
+  lengthMessages_=-1;
+  if (numberMessages_) {
+    message_ = new CoinOneMessage * [numberMessages_];
+    int i;
+    for (i=0;i<numberMessages_;i++) 
+      message_[i]=NULL;
+  } else {
+    message_=NULL;
+  }
+}
+/* Destructor */
+CoinMessages::~CoinMessages()
+{
+  int i;
+  if (lengthMessages_<0) {
+    for (i=0;i<numberMessages_;i++) 
+      delete message_[i];
+  }
+  delete [] message_;
+}
+/* The copy constructor */
+CoinMessages::CoinMessages(const CoinMessages & rhs)
+{
+  numberMessages_=rhs.numberMessages_;
+  language_=rhs.language_;
+  strcpy(source_,rhs.source_);
+  class_=rhs.class_;
+  lengthMessages_=rhs.lengthMessages_;
+  if (lengthMessages_<0) {
+    if (numberMessages_) {
+      message_ = new CoinOneMessage * [numberMessages_];
+      int i;
+      for (i=0;i<numberMessages_;i++) 
+	if (rhs.message_[i])
+	  message_[i]=new CoinOneMessage(*(rhs.message_[i]));
+	else
+	  message_[i] = NULL;
+    } else {
+      message_=NULL;
+    }
+  } else {
+    char * temp = CoinCopyOfArray(reinterpret_cast<char *> (rhs.message_),lengthMessages_);
+    message_ = reinterpret_cast<CoinOneMessage **> (temp);
+    std::ptrdiff_t offset = temp - reinterpret_cast<char *> (rhs.message_);
+    int i;
+    //printf("new address %x(%x), rhs %x - length %d\n",message_,temp,rhs.message_,lengthMessages_);
+    for (i=0;i<numberMessages_;i++) {
+      if (message_[i]) {
+	char * newAddress = (reinterpret_cast<char *> (message_[i])) + offset;
+	assert (newAddress-temp<lengthMessages_);
+	message_[i] = reinterpret_cast<CoinOneMessage *> (newAddress);
+	//printf("message %d at %x is %s\n",i,message_[i],message_[i]->message());
+	//printf("message %d at %x wass %s\n",i,rhs.message_[i],rhs.message_[i]->message());
+      }
+    }
+  }
+}
+/* assignment operator. */
+CoinMessages& 
+CoinMessages::operator=(const CoinMessages & rhs)
+{
+  if (this != &rhs) {
+    language_=rhs.language_;
+    strcpy(source_,rhs.source_);
+    class_=rhs.class_;
+    if (lengthMessages_<0) {
+      int i;
+      for (i=0;i<numberMessages_;i++)
+	delete message_[i];
+    }
+    delete [] message_;
+    numberMessages_=rhs.numberMessages_;
+    lengthMessages_=rhs.lengthMessages_;
+    if (lengthMessages_<0) {
+      if (numberMessages_) {
+	message_ = new CoinOneMessage * [numberMessages_];
+	int i;
+	for (i=0;i<numberMessages_;i++) 
+	  if (rhs.message_[i])
+	    message_[i]=new CoinOneMessage(*(rhs.message_[i]));
+	  else
+	    message_[i] = NULL;
+      } else {
+	message_=NULL;
+      }
+    } else {
+      char * temp = CoinCopyOfArray(reinterpret_cast<char *> (rhs.message_),lengthMessages_);
+      message_ = reinterpret_cast<CoinOneMessage **> (temp);
+      std::ptrdiff_t offset = temp - reinterpret_cast<char *> (rhs.message_);
+      int i;
+      //printf("new address %x(%x), rhs %x - length %d\n",message_,temp,rhs.message_,lengthMessages_);
+      for (i=0;i<numberMessages_;i++) {
+	if (message_[i]) {
+	  char * newAddress = (reinterpret_cast<char *> (message_[i])) + offset;
+	  assert (newAddress-temp<lengthMessages_);
+	  message_[i] = reinterpret_cast<CoinOneMessage *> (newAddress);
+	  //printf("message %d at %x is %s\n",i,message_[i],message_[i]->message());
+	  //printf("message %d at %x wass %s\n",i,rhs.message_[i],rhs.message_[i]->message());
+	}
+      }
+    }
+  }
+  return *this;
+}
+// Puts message in correct place
+void 
+CoinMessages::addMessage(int messageNumber, const CoinOneMessage & message)
+{
+  if (messageNumber>=numberMessages_) {
+    // should not happen but allow for it
+    CoinOneMessage ** temp = new CoinOneMessage * [messageNumber+1];
+    int i;
+    for (i=0;i<numberMessages_;i++) 
+      temp[i] = message_[i];
+    for (;i<=messageNumber;i++) 
+      temp[i] = NULL;
+    delete [] message_;
+    message_ = temp;
+  }
+  if (lengthMessages_>=0)
+    fromCompact();
+  delete message_[messageNumber];
+  message_[messageNumber]=new CoinOneMessage(message);
+}
+// Replaces messages (i.e. a different language)
+void 
+CoinMessages::replaceMessage(int messageNumber, 
+			     const char * message)
+{
+  if (lengthMessages_>=0)
+    fromCompact();
+  assert(messageNumber<numberMessages_);
+  message_[messageNumber]->replaceMessage(message);
+}
+// Changes detail level for one message
+void 
+CoinMessages::setDetailMessage(int newLevel, int messageNumber)
+{
+  int i;
+  // Last message is null (corresponds to DUMMY)
+  for (i=0;i<numberMessages_-1;i++) {
+    if (message_[i]->externalNumber()==messageNumber) {
+      message_[i]->setDetail(newLevel);
+      break;
+    }
+  }
+}
+// Changes detail level for several messages
+void 
+CoinMessages::setDetailMessages(int newLevel, int numberMessages,
+			       int * messageNumbers)
+{
+  int i;
+  if (numberMessages<3&&messageNumbers) {
+    // do one by one
+    int j;
+    for (j=0;j<numberMessages;j++) {
+      int messageNumber = messageNumbers[j];
+      for (i=0;i<numberMessages_;i++) {
+	if (message_[i]->externalNumber()==messageNumber) {
+	  message_[i]->setDetail(newLevel);
+	  break;
+	}
+      }
+    }
+  } else if (numberMessages<10000&&messageNumbers) {
+    // do backward mapping
+    int backward[10000];
+    for (i=0;i<10000;i++) 
+      backward[i]=-1;
+    for (i=0;i<numberMessages_;i++) 
+      backward[message_[i]->externalNumber()]=i;
+    for (i=0;i<numberMessages;i++) {
+      int iback = backward[messageNumbers[i]];
+      if (iback>=0)
+	message_[iback]->setDetail(newLevel);
+    }
+  } else {
+    // do all (except for dummy end)
+    for (i=0;i<numberMessages_-1;i++) {
+      message_[i]->setDetail(newLevel);
+    }
+  }
+}
+
+// Changes detail level for all messages >= low and < high
+void 
+CoinMessages::setDetailMessages(int newLevel, int low, int high)
+{
+  // do all (except for dummy end) if in range
+  for (int i=0;i<numberMessages_-1;i++) {
+    int iNumber = message_[i]->externalNumber();
+    if (iNumber>=low&&iNumber<high)
+      message_[i]->setDetail(newLevel);
+  }
+}
+/*
+  Moves to compact format
+
+  Compact format is an initial array of CoinOneMessage pointers, followed by a
+  bulk store that holds compressed CoinOneMessage objects, where the
+  message_ array is truncated to be just as large as necessary.
+*/
+void 
+CoinMessages::toCompact()
+{
+  if (numberMessages_&&lengthMessages_<0) {
+    lengthMessages_=numberMessages_*CoinSizeofAsInt(CoinOneMessage *);
+    int i;
+    for (i=0;i<numberMessages_;i++) {
+      if (message_[i]) {
+	int length = static_cast<int>(strlen(message_[i]->message()));
+	length = static_cast<int>((message_[i]->message()+length+1)-
+				      reinterpret_cast<char *> (message_[i]));
+	assert (length<COIN_MESSAGE_HANDLER_MAX_BUFFER_SIZE);
+	int leftOver = length %8;
+	if (leftOver)
+	  length += 8-leftOver;
+	lengthMessages_+=length;
+      }
+    }
+    // space
+    char * temp = new char [lengthMessages_];
+    CoinOneMessage ** newMessage = reinterpret_cast<CoinOneMessage **> (temp);
+    temp += numberMessages_*CoinSizeofAsInt(CoinOneMessage *);
+    CoinOneMessage message;
+    //printf("new address %x(%x) - length %d\n",newMessage,temp,lengthMessages_);
+    lengthMessages_=numberMessages_*CoinSizeofAsInt(CoinOneMessage *);
+    for (i=0;i<numberMessages_;i++) {
+      if (message_[i]) {
+	message = *message_[i];
+	int length = static_cast<int>(strlen(message.message()));
+	length = static_cast<int>((message.message()+length+1)-
+				  reinterpret_cast<char *> (&message));
+	assert (length<COIN_MESSAGE_HANDLER_MAX_BUFFER_SIZE);
+	int leftOver = length %8;
+	memcpy(temp,&message,length);
+	newMessage[i]=reinterpret_cast<CoinOneMessage *> (temp);
+	//printf("message %d at %x is %s\n",i,newMessage[i],newMessage[i]->message());
+	if (leftOver)
+	  length += 8-leftOver;
+	temp += length;
+	lengthMessages_+=length;
+      } else {
+	// null message
+	newMessage[i]=NULL;
+      }
+    }
+    for (i=0;i<numberMessages_;i++)
+      delete message_[i];
+    delete [] message_;
+    message_ = newMessage;
+  }
+}
+// Moves from compact format
+void 
+CoinMessages::fromCompact()
+{
+  if (numberMessages_&&lengthMessages_>=0) {
+    CoinOneMessage ** temp = new CoinOneMessage * [numberMessages_];
+    int i;
+    for (i=0;i<numberMessages_;i++) {
+      if (message_[i])
+	temp[i]=new CoinOneMessage(*(message_[i]));
+      else
+	temp[i]=NULL;
+    }
+    delete [] message_;
+    message_ = temp;
+  }
+  lengthMessages_=-1;
+}
+
+// Clean, print message and check severity, return 0 normally
+int 
+CoinMessageHandler::internalPrint() 
+{
+  int returnCode=0;
+  if (messageOut_>messageBuffer_) {
+    *messageOut_=0;
+    //take off trailing spaces and commas
+    messageOut_--;
+    while (messageOut_>=messageBuffer_) {
+      if (*messageOut_==' '||*messageOut_==',') {
+	*messageOut_=0;
+	messageOut_--;
+      } else {
+	break;
+      } 
+    }
+    // Now do print which can be overridden
+    returnCode=print();
+    // See what to do on error
+    checkSeverity();
+  }
+  return returnCode;
+}
+// Print message, return 0 normally
+int 
+CoinMessageHandler::print() 
+{
+  fprintf(fp_,"%s\n",messageBuffer_);
+  return 0;
+}
+// Check severity
+void 
+CoinMessageHandler::checkSeverity() 
+{
+  if (currentMessage_.severity_=='S') {
+    fprintf(fp_,"Stopping due to previous errors.\n");
+    //Should do walkback
+    abort();
+  } 
+}
+/* Amount of print out:
+   0 - none
+   1 - minimal
+   2 - normal low
+   3 - normal high
+   4 - verbose
+   above that 8,16,32 etc just for selective debug and are for
+   printf messages in code
+*/
+void 
+CoinMessageHandler::setLogLevel (int value)
+{
+  if (value >= -1) logLevel_ = value ;
+}
+void 
+CoinMessageHandler::setLogLevel (int which, int value)
+{
+  if (which >= 0 && which < COIN_NUM_LOG) {
+    if (value >= -1)
+      logLevels_[which] = value ;
+  }
+}
+void 
+CoinMessageHandler::setPrecision(unsigned int new_precision) {
+
+  char new_string[8] = {'%','.','8','f','\0','\0','\0','\0'};
+  
+  //we assume that the precision is smaller than one thousand
+  new_precision = std::min<unsigned int>(999,new_precision);
+  if (new_precision == 0)
+    new_precision = 1;
+  g_precision_ = new_precision ;
+  int idx = 2;
+  int base = 100;
+  bool print = false;
+  while (base > 0) {
+
+    char c = static_cast<char>(new_precision / base);
+    new_precision = new_precision % base;
+    if (c != 0)
+      print = true;
+    if (print) {
+      new_string[idx] = static_cast<char>(c +  '0');
+      idx++;
+    }
+    base /= 10;
+  }
+  new_string[idx] = 'g';
+  strcpy(g_format_,new_string);
+}
+void 
+CoinMessageHandler::setPrefix(bool value)
+{
+  if (value)
+    prefix_ = 255;
+  else
+    prefix_ =0;
+}
+bool  
+CoinMessageHandler::prefix() const
+{
+  return (prefix_!=0);
+}
+// Constructor
+CoinMessageHandler::CoinMessageHandler() :
+  logLevel_(1),
+  prefix_(255),
+  currentMessage_(),
+  internalNumber_(0),
+  format_(NULL),
+  printStatus_(0),
+  highestNumber_(-1),
+  fp_(stdout)
+{
+  const char* g_default = "%.8g";
+
+  strcpy(g_format_,g_default);
+  g_precision_ = 8 ;
+  
+  for (int i=0;i<COIN_NUM_LOG;i++)
+    logLevels_[i]=-1000;
+  messageBuffer_[0]='\0';
+  messageOut_ = messageBuffer_;
+  source_="Unk";
+}
+// Constructor
+CoinMessageHandler::CoinMessageHandler(FILE * fp) :
+  logLevel_(1),
+  prefix_(255),
+  currentMessage_(),
+  internalNumber_(0),
+  format_(NULL),
+  printStatus_(0),
+  highestNumber_(-1),
+  fp_(fp)
+{
+  const char* g_default = "%.8g";
+  
+  strcpy(g_format_,g_default);
+  g_precision_ = 8 ;
+
+  for (int i=0;i<COIN_NUM_LOG;i++)
+    logLevels_[i]=-1000;
+  messageBuffer_[0]='\0';
+  messageOut_ = messageBuffer_;
+  source_="Unk";
+}
+/* Destructor */
+CoinMessageHandler::~CoinMessageHandler()
+{
+}
+
+void
+CoinMessageHandler::gutsOfCopy(const CoinMessageHandler& rhs)
+{
+  logLevel_=rhs.logLevel_;
+  prefix_ = rhs.prefix_;
+  if (rhs.format_ && *rhs.format_ == '\0')
+  { *rhs.format_ = '%' ;
+    currentMessage_=rhs.currentMessage_;
+    *rhs.format_ = '\0' ; }
+  else
+  { currentMessage_=rhs.currentMessage_; }
+  internalNumber_=rhs.internalNumber_;
+  int i;
+  for ( i=0;i<COIN_NUM_LOG;i++)
+    logLevels_[i]=rhs.logLevels_[i];
+  doubleValue_=rhs.doubleValue_;
+  longValue_=rhs.longValue_;
+  charValue_=rhs.charValue_;
+  stringValue_=rhs.stringValue_;
+  std::ptrdiff_t offset ;
+  if (rhs.format_)
+  { offset = rhs.format_ - rhs.currentMessage_.message();
+    format_ = currentMessage_.message()+offset; }
+  else
+  { format_ = NULL ; }
+  std::memcpy(messageBuffer_,rhs.messageBuffer_,
+	      COIN_MESSAGE_HANDLER_MAX_BUFFER_SIZE);
+  offset = rhs.messageOut_-rhs.messageBuffer_;
+  messageOut_= messageBuffer_+offset;
+  printStatus_= rhs.printStatus_;
+  highestNumber_= rhs.highestNumber_;
+  fp_ = rhs.fp_;
+  source_ = rhs.source_;
+  strcpy(g_format_,rhs.g_format_);
+  g_precision_ = rhs.g_precision_ ;
+}
+/* The copy constructor */
+CoinMessageHandler::CoinMessageHandler(const CoinMessageHandler& rhs)
+{
+  gutsOfCopy(rhs);
+}
+/* assignment operator. */
+CoinMessageHandler & 
+CoinMessageHandler::operator=(const CoinMessageHandler& rhs)
+{
+  if (this != &rhs) {
+    gutsOfCopy(rhs);
+  }
+  return *this;
+}
+// Clone
+CoinMessageHandler * 
+CoinMessageHandler::clone() const
+{
+  return new CoinMessageHandler(*this);
+}
+
+/*
+  Decide if we're printing or not. Split out because it's nontrivial and
+  used in two places.
+
+  Recall that setLogLevel(lvl) sets logLevel_. To set logLevels_[i], use
+  setLogLevel(i,lvl). The two are not connected. By default, all entries
+  of logLevels_ are initialised to -1000.
+
+  Unless the client changes logLevels_[0], when the log level (lvl)
+  of the message is 8 or more, it's ANDed with the handler's log level
+  (logLevel_). Printing is enabled only if the result is nonzero. Commonly
+  this is used in a scheme where individual bits enable particular debug
+  output.
+*/
+void CoinMessageHandler::calcPrintStatus (int msglvl, int msgclass)
+{
+  printStatus_ = 0 ;
+  if (logLevels_[0] == -1000) {
+    if (msglvl >= 8 && logLevel_ >= 0) {
+      if ((msglvl&logLevel_) == 0)
+	printStatus_ = 3 ;
+    } else if (logLevel_ < msglvl) {
+      printStatus_ = 3 ;
+    }
+  } else if (logLevels_[msgclass] < msglvl) {
+    printStatus_ = 3;
+  }
+}
+
+/*
+  Start a message using a standard CoinOneMessage.
+*/
+CoinMessageHandler & 
+CoinMessageHandler::message (int messageNumber,
+			     const CoinMessages &normalMessages)
+{
+  // Deal with the previous message, if there is one.
+  if (messageOut_ != messageBuffer_) {
+    internalPrint() ;
+  }
+  // Acquire the new message
+  internalNumber_ = messageNumber ;
+  currentMessage_ = *(normalMessages.message_[messageNumber]) ;
+  source_ = normalMessages.source_ ;
+  format_ = currentMessage_.message_ ;
+  highestNumber_ = CoinMax(highestNumber_,currentMessage_.externalNumber_);
+
+  // Initialise the message construction buffer
+  messageBuffer_[0] = '\0' ;
+  messageOut_ = messageBuffer_ ;
+
+  // Decide whether or not to print (sets printStatus_)
+  calcPrintStatus(currentMessage_.detail_,normalMessages.class_) ;
+
+  // If we're printing, initialise the message
+  if (!printStatus_) {
+    if (prefix_) {
+      sprintf(messageOut_,"%s%4.4d%c ",source_.c_str(),
+	      currentMessage_.externalNumber_,
+	      currentMessage_.severity_) ;
+      messageOut_ += strlen(messageOut_) ;
+    }
+    format_ = nextPerCent(format_,true) ;
+  }
+  return (*this) ;
+}
+/*
+  Start a message, providing the full message, information to generate
+  a prefix, a severity code, and an optional log level.
+  Intended as an aid to help existing codes interface.
+*/
+CoinMessageHandler & 
+CoinMessageHandler::message (int externalNumber, const char *source,
+			     const char *msg, char severity, int loglvl)
+{
+  // Deal with the previous message, if there is one.
+  if (messageOut_ != messageBuffer_) {
+    internalPrint() ;
+  }
+  // Set up a dummy message.
+  internalNumber_ = externalNumber ;
+  char detail = ((loglvl >= 0)?(static_cast<char>(loglvl)):'\000') ;
+  currentMessage_= CoinOneMessage(externalNumber,detail,msg) ;
+  source_ = source ;
+  highestNumber_ = CoinMax(highestNumber_,externalNumber);
+
+  // Initialise the message construction buffer
+  messageBuffer_[0] = '\0' ;
+  messageOut_ = messageBuffer_ ;
+
+  /*
+    Decide whether or not to print. The normal value of printStatus_ here
+    is 2 (complete message provided). loglvl defaults to -1 for backwards
+    compatibility (previously there was no provision for a log level).
+  */
+  if (loglvl >= 0) calcPrintStatus(loglvl,0) ;
+  if (!printStatus_) {
+    printStatus_ = 2 ;
+    if (prefix_) {
+      sprintf(messageOut_,"%s%4.4d%c ",source_.c_str(),
+	      externalNumber,severity) ;
+    }
+    strcat(messageBuffer_,msg) ;
+    messageOut_ = messageBuffer_+strlen(messageBuffer_) ;
+  }
+  return (*this) ;
+}
+
+/*
+  Decides whether or not to print and returns a reference to the handler.
+*/
+CoinMessageHandler & 
+CoinMessageHandler::message(int loglvl)
+{
+  // Adjust print status?
+  if (loglvl >= 0) calcPrintStatus(loglvl,0) ;
+
+  return (*this) ;
+}
+
+/*
+  Allows for skipping printing of part of message, but putting in data
+*/
+CoinMessageHandler & 
+CoinMessageHandler::printing(bool onOff)
+{
+  // has no effect if skipping or whole message in
+  if (printStatus_ < 2) {
+    assert(format_[1]=='?');
+    *format_ = '%' ;
+    if (onOff)
+      printStatus_=0;
+    else
+      printStatus_=1;
+    format_ = nextPerCent(format_+2,true);
+  }
+  return *this;
+}
+/*
+  Stop (and print)
+
+  Unless printing is currently suppressed. We need to do the finishing actions
+  in any event.
+*/
+int 
+CoinMessageHandler::finish()
+{
+  // Deal with the collected message
+  if (printStatus_ < 3 && messageOut_ != messageBuffer_) {
+    internalPrint();
+  }
+  // Clean up for the next message.
+  internalNumber_ = -1 ;
+  format_ = NULL ;
+  messageBuffer_[0] = '\0' ;
+  messageOut_ = messageBuffer_ ;
+  printStatus_ = 0 ;
+  doubleValue_.clear() ;
+  longValue_.clear() ;
+  charValue_.clear() ;
+  stringValue_.clear() ;
+  return (0) ;
+}
+
+/* Gets position of next field in format
+   If we're scanning the initial portion of the string (prior to the first
+   `%' code) the prefix will be copied to the output buffer. Normally, the
+   text from the current position up to and including a % code is is processed
+   by the relevant operator<< method.
+*/
+char * 
+CoinMessageHandler::nextPerCent(char * start , const bool initial)
+{
+  if (start) {
+    bool foundNext=false;
+    while (!foundNext) {
+      char * nextPerCent = strchr(start,'%');
+      if (nextPerCent) {
+	if (initial&&!printStatus_) {
+	  int numberToCopy=static_cast<int>(nextPerCent-start);
+	  strncpy(messageOut_,start,numberToCopy);
+	  messageOut_+=numberToCopy;
+	} 
+	// %? is skipped over as it is just a separator
+	if (nextPerCent[1]!='?') {
+	  start=nextPerCent;
+	  if (start[1]!='%') {
+	    foundNext=true;
+	    if (!initial) 
+	      *start='\0'; //zap
+	  } else {
+	    start+=2;
+	    if (initial) {
+	      *messageOut_='%';
+	      messageOut_++;
+	    } 
+	  }
+	} else {
+	  foundNext=true;
+	  // skip to % and zap
+	  start=nextPerCent;
+	  *start='\0'; 
+	}
+      } else {
+        if (initial&&!printStatus_) {
+          strcpy(messageOut_,start);
+          messageOut_+=strlen(messageOut_);
+        } 
+        start=0;
+        foundNext=true;
+      } 
+    } 
+  } 
+  return start;
+}
+// Adds into message
+CoinMessageHandler & 
+CoinMessageHandler::operator<< (int intvalue)
+{
+  if (printStatus_==3)
+    return *this; // not doing this message
+  longValue_.push_back(intvalue);
+  if (printStatus_<2) {
+    if (format_) {
+      //format is at % (but may be changed to null)
+      *format_='%';
+      char * next = nextPerCent(format_+1);
+      // could check
+      if (!printStatus_) {
+	sprintf(messageOut_,format_,intvalue);
+	messageOut_+=strlen(messageOut_);
+      }
+      format_=next;
+    } else {
+      sprintf(messageOut_," %d",intvalue);
+      messageOut_+=strlen(messageOut_);
+    } 
+  }
+  return *this;
+}
+CoinMessageHandler & 
+CoinMessageHandler::operator<< (double doublevalue)
+{
+  if (printStatus_==3)
+    return *this; // not doing this message
+  doubleValue_.push_back(doublevalue);
+
+  if (printStatus_<2) {
+    if (format_) {
+      //format is at \0 (but changed to %)
+      *format_='%';
+      char * next = nextPerCent(format_+1);
+      // could check
+      if (!printStatus_) {
+	if (format_[1] == '.' && format_[2] >= '0' && format_[2] <= '9') {
+	  // an explicitly specified precision currently overrides the
+	  // precision of the message handler
+	  sprintf(messageOut_,format_,doublevalue);
+	}
+	else {
+	  sprintf(messageOut_,g_format_,doublevalue);
+	  if (next != format_+2) {
+	    messageOut_+=strlen(messageOut_);
+	    sprintf(messageOut_,format_+2);
+	  }
+	}
+	messageOut_+=strlen(messageOut_);
+      }
+      format_=next;
+    } else {
+      sprintf(messageOut_," ");
+      messageOut_ += 1;
+      sprintf(messageOut_,g_format_,doublevalue);
+      messageOut_+=strlen(messageOut_);
+    } 
+  }
+  return *this;
+}
+#if COIN_BIG_INDEX==1
+CoinMessageHandler & 
+CoinMessageHandler::operator<< (long longvalue)
+{
+  if (printStatus_==3)
+    return *this; // not doing this message
+  longValue_.push_back(longvalue);
+  if (printStatus_<2) {
+    if (format_) {
+      //format is at % (but may be changed to null)
+      *format_='%';
+      char * next = nextPerCent(format_+1);
+      // could check
+      if (!printStatus_) {
+	sprintf(messageOut_,format_,longvalue);
+	messageOut_+=strlen(messageOut_);
+      }
+      format_=next;
+    } else {
+      sprintf(messageOut_," %ld",longvalue);
+      messageOut_+=strlen(messageOut_);
+    } 
+  }
+  return *this;
+}
+#endif
+#if COIN_BIG_INDEX==2
+CoinMessageHandler & 
+CoinMessageHandler::operator<< (long long longvalue)
+{
+  if (printStatus_==3)
+    return *this; // not doing this message
+  longValue_.push_back(longvalue);
+  if (printStatus_<2) {
+    if (format_) {
+      //format is at % (but may be changed to null)
+      *format_='%';
+      char * next = nextPerCent(format_+1);
+      // could check
+      if (!printStatus_) {
+	sprintf(messageOut_,format_,longvalue);
+	messageOut_+=strlen(messageOut_);
+      }
+      format_=next;
+    } else {
+      sprintf(messageOut_," %ld",longvalue);
+      messageOut_+=strlen(messageOut_);
+    } 
+  }
+  return *this;
+}
+#endif
+CoinMessageHandler & 
+CoinMessageHandler::operator<< (const std::string& stringvalue)
+{
+  if (printStatus_==3)
+    return *this; // not doing this message
+  stringValue_.push_back(stringvalue);
+  if (printStatus_<2) {
+    if (format_) {
+      //format is at % (but changed to 0)
+      *format_='%';
+      char * next = nextPerCent(format_+1);
+      // could check
+      if (!printStatus_) {
+	sprintf(messageOut_,format_,stringvalue.c_str());
+	messageOut_+=strlen(messageOut_);
+      }
+      format_=next;
+    } else {
+      sprintf(messageOut_," %s",stringvalue.c_str());
+      messageOut_+=strlen(messageOut_);
+    } 
+  }
+  return *this;
+}
+CoinMessageHandler & 
+CoinMessageHandler::operator<< (char charvalue)
+{
+  if (printStatus_==3)
+    return *this; // not doing this message
+  charValue_.push_back(charvalue);
+  if (printStatus_<2) {
+    if (format_) {
+      //format is at % (but changed to 0)
+      *format_='%';
+      char * next = nextPerCent(format_+1);
+      // could check
+      if (!printStatus_) {
+	sprintf(messageOut_,format_,charvalue);
+	messageOut_+=strlen(messageOut_);
+      }
+      format_=next;
+    } else {
+      sprintf(messageOut_," %c",charvalue);
+      messageOut_+=strlen(messageOut_);
+    } 
+  }
+  return *this;
+}
+CoinMessageHandler & 
+CoinMessageHandler::operator<< (const char *stringvalue)
+{
+  if (printStatus_==3)
+    return *this; // not doing this message
+  stringValue_.push_back(stringvalue);
+  if (printStatus_<2) {
+    if (format_) {
+      //format is at % (but changed to 0)
+      *format_='%';
+      char * next = nextPerCent(format_+1);
+      // could check
+      if (!printStatus_) {
+	sprintf(messageOut_,format_,stringvalue);
+	messageOut_+=strlen(messageOut_);
+      }
+      format_=next;
+    } else {
+      sprintf(messageOut_," %s",stringvalue);
+      messageOut_+=strlen(messageOut_);
+    } 
+  }
+  return *this;
+}
+
+/*
+  Handle markers. Even when printing is suppressed (printStatus_ == 3) we need
+  to execute finish() to reset for the next message.
+*/
+CoinMessageHandler & 
+CoinMessageHandler::operator<< (CoinMessageMarker marker)
+{
+  switch (marker) {
+    case CoinMessageEol: {
+      finish() ;
+      break ;
+    }
+    case CoinMessageNewline: {
+      if (printStatus_ != 3) {
+	strcat(messageOut_,"\n") ;
+	messageOut_++ ;
+      }
+      break ;
+    }
+  }
+  return (*this) ;
+}
diff --git a/cbits/coin/CoinMessageHandler.hpp b/cbits/coin/CoinMessageHandler.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinMessageHandler.hpp
@@ -0,0 +1,666 @@
+/* $Id: CoinMessageHandler.hpp 1514 2011-12-10 23:35:23Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinMessageHandler_H
+#define CoinMessageHandler_H
+
+#include "CoinUtilsConfig.h"
+#include "CoinPragma.hpp"
+
+#include <iostream>
+#include <cstdio>
+#include <string>
+#include <vector>
+
+/** \file CoinMessageHandler.hpp
+    \brief This is a first attempt at a message handler.
+
+ The COIN Project is in favo(u)r of multi-language support. This implementation
+ of a message handler tries to make it as lightweight as possible in the sense
+ that only a subset of messages need to be defined --- the rest default to US
+ English.
+
+ The default handler at present just prints to stdout or to a FILE pointer
+
+ \todo
+ This needs to be worked over for correct operation with ISO character codes.
+*/
+
+/*
+ I (jjf) am strongly in favo(u)r of language support for an open
+ source project, but I have tried to make it as lightweight as
+ possible in the sense that only a subset of messages need to be
+ defined - the rest default to US English.  There will be different
+ sets of messages for each component - so at present there is a
+ Clp component and a Coin component.
+
+ Because messages are only used in a controlled environment and have no
+ impact on code and are tested by other tests I have included tests such
+ as language and derivation in other unit tests.
+*/
+/*
+  Where there are derived classes I (jjf) have started message numbers at 1001.
+*/
+
+
+/** \brief Class for one massaged message.
+
+  A message consists of a text string with formatting codes (#message_),
+  an integer identifier (#externalNumber_) which also determines the severity
+  level (#severity_) of the message, and a detail (logging) level (#detail_).
+
+  CoinOneMessage is just a container to hold this information. The
+  interpretation is set by CoinMessageHandler, which see.
+ */
+
+class CoinOneMessage {
+
+public:
+  /**@name Constructors etc */
+  //@{
+  /** Default constructor. */
+  CoinOneMessage();
+  /** Normal constructor */
+  CoinOneMessage(int externalNumber, char detail,
+		const char * message);
+  /** Destructor */
+  ~CoinOneMessage();
+  /** The copy constructor */
+  CoinOneMessage(const CoinOneMessage&);
+  /** assignment operator. */
+  CoinOneMessage& operator=(const CoinOneMessage&);
+  //@}
+
+  /**@name Useful stuff */
+  //@{
+  /// Replace message text (<i>e.g.</i>, text in a different language)
+  void replaceMessage(const char * message);
+  //@}
+
+  /**@name Get and set methods */
+  //@{
+  /** Get message ID number */
+  inline int externalNumber() const
+  {return externalNumber_;}
+  /** \brief Set message ID number
+  
+    In the default CoinMessageHandler, this number is printed in the message
+    prefix and is used to determine the message severity level.
+  */
+  inline void setExternalNumber(int number) 
+  {externalNumber_=number;}
+  /// Severity
+  inline char severity() const
+  {return severity_;}
+  /// Set detail level
+  inline void setDetail(int level)
+  {detail_=static_cast<char> (level);}
+  /// Get detail level
+  inline int detail() const
+  {return detail_;}
+  /// Return the message text
+  inline char * message() const 
+  {return message_;}
+  //@}
+
+  /**@name member data */
+  //@{
+  /// number to print out (also determines severity)
+    int externalNumber_;
+  /// Will only print if detail matches
+    char detail_;
+  /// Severity
+    char severity_;
+  /// Messages (in correct language) (not all 400 may exist)
+  mutable char message_[400];
+  //@}
+};
+
+/** \brief Class to hold and manipulate an array of massaged messages.
+
+  Note that the message index used to reference a message in the array of
+  messages is completely distinct from the external ID number stored with the
+  message.
+*/
+
+class CoinMessages {
+
+public:
+  /** \brief Supported languages
+  
+    These are the languages that are supported.  At present only
+    us_en is serious and the rest are for testing.
+  */
+  enum Language {
+    us_en = 0,
+    uk_en,
+    it
+  };
+
+  /**@name Constructors etc */
+  //@{
+  /** Constructor with number of messages. */
+  CoinMessages(int numberMessages=0);
+  /** Destructor */
+  ~CoinMessages();
+  /** The copy constructor */
+  CoinMessages(const CoinMessages&);
+  /** assignment operator. */
+  CoinMessages& operator=(const CoinMessages&);
+  //@}
+
+  /**@name Useful stuff */
+  //@{
+  /*! \brief Installs a new message in the specified index position
+
+    Any existing message is replaced, and a copy of the specified message is
+    installed.
+  */
+  void addMessage(int messageNumber, const CoinOneMessage & message);
+  /*! \brief Replaces the text of the specified message
+
+    Any existing text is deleted and the specified text is copied into the
+    specified message.
+  */
+  void replaceMessage(int messageNumber, const char * message);
+  /** Language.  Need to think about iso codes */
+  inline Language language() const
+  {return language_;}
+  /** Set language */
+  void setLanguage(Language newlanguage)
+  {language_ = newlanguage;}
+  /// Change detail level for one message
+  void setDetailMessage(int newLevel, int messageNumber);
+  /** \brief Change detail level for several messages
+
+    messageNumbers is expected to contain the indices of the messages to be
+    changed.
+    If numberMessages >= 10000 or messageNumbers is NULL, the detail level
+    is changed on all messages.
+  */
+  void setDetailMessages(int newLevel, int numberMessages,
+			 int * messageNumbers);
+  /** Change detail level for all messages with low <= ID number < high */
+  void setDetailMessages(int newLevel, int low, int high);
+
+  /// Returns class
+  inline int getClass() const
+  { return class_;}
+  /// Moves to compact format
+  void toCompact();
+  /// Moves from compact format
+  void fromCompact();
+  //@}
+
+  /**@name member data */
+  //@{
+  /// Number of messages
+  int numberMessages_;
+  /// Language 
+  Language language_;
+  /// Source (null-terminated string, maximum 4 characters).
+  char source_[5];
+  /// Class - see later on before CoinMessageHandler
+  int class_;
+  /** Length of fake CoinOneMessage array.
+      First you get numberMessages_ pointers which point to stuff
+  */
+  int lengthMessages_;
+  /// Messages
+  CoinOneMessage ** message_;
+  //@}
+};
+
+// for convenience eol
+enum CoinMessageMarker {
+  CoinMessageEol = 0,
+  CoinMessageNewline = 1
+};
+
+/** Base class for message handling
+
+    The default behavior is described here: messages are printed, and (if the
+    severity is sufficiently high) execution will be aborted. Inherit and
+    redefine the methods #print and #checkSeverity to augment the behaviour.
+
+    Messages can be printed with or without a prefix; the prefix will consist
+    of a source string, the external ID number, and a letter code,
+    <i>e.g.</i>, Clp6024W.
+    A prefix makes the messages look less nimble but is very useful
+    for "grep" <i>etc</i>.
+
+    <h3> Usage </h3>
+
+    The general approach to using the COIN messaging facility is as follows:
+    <ul>
+      <li> Define your messages. For each message, you must supply an external
+	 ID number, a log (detail) level, and a format string. Typically, you
+	 define a convenience structure for this, something that's easy to
+	 use to create an array of initialised message definitions at compile
+	 time.
+      <li> Create a CoinMessages object, sized to accommodate the number of
+        messages you've defined. (Incremental growth will happen if
+	necessary as messages are loaded, but it's inefficient.)
+      <li> Load the messages into the CoinMessages object. Typically this
+	entails creating a CoinOneMessage object for each message and
+	passing it as a parameter to CoinMessages::addMessage(). You specify
+	the message's internal ID as the other parameter to addMessage.
+      <li> Create and use a CoinMessageHandler object to print messages.
+    </ul>
+    See, for example, CoinMessage.hpp and CoinMessage.cpp for an example of
+    the first three steps. `Format codes' below has a simple example of
+    printing a message.
+
+    <h3> External ID numbers and severity </h3>
+
+    CoinMessageHandler assumes the following relationship between the
+    external ID number of a message and the severity of the message:
+    \li <3000 are informational ('I')
+    \li <6000 warnings ('W')
+    \li <9000 non-fatal errors ('E')
+    \li >=9000 aborts the program (after printing the message) ('S')
+
+    <h3> Log (detail) levels </h3>
+
+    The default behaviour is that a message will print if its detail level
+    is less than or equal to the handler's log level.  If all you want to
+    do is set a single log level for the handler, use #setLogLevel(int).
+
+    If you want to get fancy, here's how it really works: There's an array,
+    #logLevels_, which you can manipulate with #setLogLevel(int,int). Each
+    entry logLevels_[i] specifies the log level for messages of class i (see
+    CoinMessages::class_). If logLevels_[0] is set to the magic number -1000
+    you get the simple behaviour described above, whatever the class of the
+    messages. If logLevels_[0] is set to a valid log level (>= 0), then
+    logLevels_[i] really is the log level for messages of class i.
+
+    <h3> Format codes </h3>
+
+    CoinMessageHandler can print integers (normal, long, and long long),
+    doubles, characters, and strings. See the descriptions of the
+    various << operators.
+    
+    When processing a standard message with a format string, the formatting
+    codes specified in the format string will be passed to the sprintf
+    function, along with the argument. When generating a message with no
+    format string, each << operator uses a simple format code appropriate for
+    its argument.  Consult the documentation for the standard printf facility
+    for further information on format codes.
+
+    The special format code `%?' provides a hook to enable or disable
+    printing.  For each `%?' code, there must be a corresponding call to
+    printing(bool).  This provides a way to define optional parts in
+    messages, delineated by the code `%?' in the format string.  Printing can
+    be suppressed for these optional parts, but any operands must still be
+    supplied. For example, given the message string
+    \verbatim
+    "A message with%? an optional integer %d and%? a double %g."
+    \endverbatim
+    installed in CoinMessages \c exampleMsgs with index 5, and
+    \c CoinMessageHandler \c hdl, the code
+    \code
+    hdl.message(5,exampleMsgs) ;
+    hdl.printing(true) << 42 ;
+    hdl.printing(true) << 53.5 << CoinMessageEol ;
+    \endcode
+    will print
+    \verbatim
+    A message with an optional integer 42 and a double 53.5.
+    \endverbatim
+    while
+    \code
+    hdl.message(5,exampleMsgs) ;
+    hdl.printing(false) << 42 ;
+    hdl.printing(true) << 53.5 << CoinMessageEol ;
+    \endcode
+    will print
+    \verbatim
+    A message with a double 53.5.
+    \endverbatim
+
+    For additional examples of usage, see CoinMessageHandlerUnitTest in
+    CoinMessageHandlerTest.cpp.
+*/
+
+class CoinMessageHandler  {
+
+friend bool CoinMessageHandlerUnitTest () ;
+
+public:
+   /**@name Virtual methods that the derived classes may provide */
+   //@{
+  /** Print message, return 0 normally.
+  */
+  virtual int print() ;
+  /** Check message severity - if too bad then abort
+  */
+  virtual void checkSeverity() ;
+   //@}
+
+  /**@name Constructors etc */
+  //@{
+  /// Constructor
+  CoinMessageHandler();
+  /// Constructor to put to file pointer (won't be closed)
+  CoinMessageHandler(FILE *fp);
+  /** Destructor */
+  virtual ~CoinMessageHandler();
+  /** The copy constructor */
+  CoinMessageHandler(const CoinMessageHandler&);
+  /** Assignment operator. */
+  CoinMessageHandler& operator=(const CoinMessageHandler&);
+  /// Clone
+  virtual CoinMessageHandler * clone() const;
+  //@}
+   /**@name Get and set methods */
+   //@{
+  /// Get detail level of a message.
+  inline int detail(int messageNumber, const CoinMessages &normalMessage) const
+  { return normalMessage.message_[messageNumber]->detail();}
+  /** Get current log (detail) level. */
+  inline int logLevel() const
+          { return logLevel_;}
+  /** \brief Set current log (detail) level.
+
+    If the log level is equal or greater than the detail level of a message,
+    the message will be printed. A rough convention for the amount of output
+    expected is
+    - 0 - none
+    - 1 - minimal
+    - 2 - normal low
+    - 3 - normal high
+    - 4 - verbose
+
+    Please assign log levels to messages accordingly. Log levels of 8 and
+    above (8,16,32, <i>etc</i>.) are intended for selective debugging.
+    The logical AND of the log level specified in the message and the current
+    log level is used to determine if the message is printed. (In other words,
+    you're using individual bits to determine which messages are printed.)
+  */
+  void setLogLevel(int value);
+  /** Get alternative log level. */
+  inline int logLevel(int which) const
+  { return logLevels_[which];}
+  /*! \brief Set alternative log level value.
+
+    Can be used to store alternative log level information within the handler.
+  */
+  void setLogLevel(int which, int value);
+
+  /// Set the number of significant digits for printing floating point numbers
+  void setPrecision(unsigned int new_precision);
+  /// Current number of significant digits for printing floating point numbers
+  inline int precision() { return (g_precision_) ; }
+
+  /// Switch message prefix on or off.
+  void setPrefix(bool yesNo);
+  /// Current setting for printing message prefix.
+  bool  prefix() const;
+  /*! \brief Values of double fields already processed.
+
+    As the parameter for a double field is processed, the value is saved
+    and can be retrieved using this function.
+  */
+  inline double doubleValue(int position) const
+  { return doubleValue_[position];}
+  /*! \brief Number of double fields already processed.
+
+    Incremented each time a field of type double is processed.
+  */
+  inline int numberDoubleFields() const
+  {return static_cast<int>(doubleValue_.size());}
+  /*! \brief Values of integer fields already processed.
+
+    As the parameter for a integer field is processed, the value is saved
+    and can be retrieved using this function.
+  */
+  inline int intValue(int position) const
+  { return longValue_[position];}
+  /*! \brief Number of integer fields already processed.
+
+    Incremented each time a field of type integer is processed.
+  */
+  inline int numberIntFields() const
+  {return static_cast<int>(longValue_.size());}
+  /*! \brief Values of char fields already processed.
+
+    As the parameter for a char field is processed, the value is saved
+    and can be retrieved using this function.
+  */
+  inline char charValue(int position) const
+  { return charValue_[position];}
+  /*! \brief Number of char fields already processed.
+
+    Incremented each time a field of type char is processed.
+  */
+  inline int numberCharFields() const
+  {return static_cast<int>(charValue_.size());}
+  /*! \brief Values of string fields already processed.
+
+    As the parameter for a string field is processed, the value is saved
+    and can be retrieved using this function.
+  */
+  inline std::string stringValue(int position) const
+  { return stringValue_[position];}
+  /*! \brief Number of string fields already processed.
+
+    Incremented each time a field of type string is processed.
+  */
+  inline int numberStringFields() const
+  {return static_cast<int>(stringValue_.size());}
+
+  /// Current message
+  inline CoinOneMessage  currentMessage() const
+  {return currentMessage_;}
+  /// Source of current message
+  inline std::string currentSource() const
+  {return source_;}
+  /// Output buffer
+  inline const char * messageBuffer() const
+  {return messageBuffer_;}
+  /// Highest message number (indicates any errors)
+  inline int highestNumber() const
+  {return highestNumber_;}
+  /// Get current file pointer
+  inline FILE * filePointer() const
+  { return fp_;}
+  /// Set new file pointer
+  inline void setFilePointer(FILE * fp)
+  { fp_ = fp;}
+  //@}
+  
+  /**@name Actions to create a message  */
+  //@{
+  /*! \brief Start a message
+
+    Look up the specified message. A prefix will be generated if enabled.
+    The message will be printed if the current log level is equal or greater
+    than the log level of the message.
+  */
+  CoinMessageHandler &message(int messageNumber,
+			      const CoinMessages &messages) ;
+
+  /*! \brief Start or continue a message
+
+    With detail = -1 (default), does nothing except return a reference to the
+    handler. (I.e., msghandler.message() << "foo" is precisely equivalent
+    to msghandler << "foo".) If \p msgDetail is >= 0, is will be used
+    as the detail level to determine whether the message should print
+    (assuming class 0).
+
+    This can be used with any of the << operators. One use is to start
+    a message which will be constructed entirely from scratch. Another
+    use is continuation of a message after code that interrupts the usual
+    sequence of << operators.
+  */
+  CoinMessageHandler & message(int detail = -1) ;
+
+  /*! \brief Print a complete message
+  
+    Generate a standard prefix and append \c msg `as is'. This is intended as
+    a transition mechanism.  The standard prefix is generated (if enabled),
+    and \c msg is appended. The message must be ended with a CoinMessageEol
+    marker. Attempts to add content with << will have no effect.
+
+    The default value of \p detail will not change printing status. If
+    \p detail is >= 0, it will be used as the detail level to determine
+    whether the message should print (assuming class 0).
+
+  */
+  CoinMessageHandler &message(int externalNumber, const char *source,
+			      const char *msg,
+			      char severity, int detail = -1) ;
+
+  /*! \brief Process an integer parameter value.
+
+    The default format code is `%d'.
+  */
+  CoinMessageHandler & operator<< (int intvalue);
+#if COIN_BIG_INDEX==1
+  /*! \brief Process a long integer parameter value.
+
+    The default format code is `%ld'.
+  */
+  CoinMessageHandler & operator<< (long longvalue);
+#endif
+#if COIN_BIG_INDEX==2
+  /*! \brief Process a long long integer parameter value.
+
+    The default format code is `%ld'.
+  */
+  CoinMessageHandler & operator<< (long long longvalue);
+#endif
+  /*! \brief Process a double parameter value.
+
+    The default format code is `%d'.
+  */
+  CoinMessageHandler & operator<< (double doublevalue);
+  /*! \brief Process a STL string parameter value.
+
+    The default format code is `%g'.
+  */
+  CoinMessageHandler & operator<< (const std::string& stringvalue);
+  /*! \brief Process a char parameter value.
+
+    The default format code is `%s'.
+  */
+  CoinMessageHandler & operator<< (char charvalue);
+  /*! \brief Process a C-style string parameter value.
+
+    The default format code is `%c'.
+  */
+  CoinMessageHandler & operator<< (const char *stringvalue);
+  /*! \brief Process a marker.
+
+    The default format code is `%s'.
+  */
+  CoinMessageHandler & operator<< (CoinMessageMarker);
+  /** Finish (and print) the message.
+  
+    Equivalent to using the CoinMessageEol marker.
+  */
+  int finish();
+  /*! \brief Enable or disable printing of an optional portion of a message.
+
+    Optional portions of a message are delimited by `%?' markers, and
+    printing processes one %? marker. If \c onOff is true, the subsequent
+    portion of the message (to the next %? marker or the end of the format
+    string) will be printed. If \c onOff is false, printing is suppressed.
+    Parameters must still be supplied, whether printing is suppressed or not.
+    See the class documentation for an example.
+  */
+  CoinMessageHandler & printing(bool onOff);
+
+  //@}
+
+  /** Log levels will be by type and will then use type
+      given in CoinMessage::class_
+
+    - 0 - Branch and bound code or similar
+    - 1 - Solver
+    - 2 - Stuff in Coin directory
+    - 3 - Cut generators
+  */
+#define COIN_NUM_LOG 4
+/// Maximum length of constructed message (characters)
+#define COIN_MESSAGE_HANDLER_MAX_BUFFER_SIZE 1000
+protected:
+  /**@name Protected member data */
+  //@{
+  /// values in message
+  std::vector<double> doubleValue_;
+  std::vector<int> longValue_;
+  std::vector<char> charValue_;
+  std::vector<std::string> stringValue_;
+  /// Log level
+  int logLevel_;
+  /// Log levels
+  int logLevels_[COIN_NUM_LOG];
+  /// Whether we want prefix (may get more subtle so is int)
+  int prefix_;
+  /// Current message
+  CoinOneMessage  currentMessage_;
+  /// Internal number for use with enums
+  int internalNumber_;
+  /// Format string for message (remainder)
+  char * format_;
+  /// Output buffer
+  char messageBuffer_[COIN_MESSAGE_HANDLER_MAX_BUFFER_SIZE];
+  /// Position in output buffer
+  char * messageOut_;
+  /// Current source of message
+  std::string source_;
+  /** 0 - Normal.
+      1 - Put in values, move along format, but don't print.
+      2 - A complete message was provided; nothing more to do but print
+          when CoinMessageEol is processed. Any << operators are treated
+	  as noops.
+      3 - do nothing except look for CoinMessageEol (i.e., the message
+          detail level was not sufficient to cause it to print).
+  */
+  int printStatus_;
+  /// Highest message number (indicates any errors)
+  int highestNumber_;
+  /// File pointer
+  FILE * fp_;
+  /// Current format for floating point numbers
+  char g_format_[8];
+  /// Current number of significant digits for floating point numbers
+  int g_precision_ ;
+   //@}
+
+private:
+
+  /** The body of the copy constructor and the assignment operator */
+  void gutsOfCopy(const CoinMessageHandler &rhs) ;
+
+  /*! \brief Internal function to locate next format code.
+
+    Intended for internal use. Side effects modify the format string.
+  */
+  char *nextPerCent(char *start, const bool initial = false) ;
+
+  /*! \brief Internal printing function.
+  
+    Makes it easier to split up print into clean, print and check severity
+  */
+  int internalPrint() ;
+
+  /// Decide if this message should print.
+  void calcPrintStatus(int msglvl, int msgclass) ;
+    
+
+};
+
+//#############################################################################
+/** A function that tests the methods in the CoinMessageHandler class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+bool
+CoinMessageHandlerUnitTest();
+
+#endif
diff --git a/cbits/coin/CoinModel.cpp b/cbits/coin/CoinModel.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinModel.cpp
@@ -0,0 +1,4084 @@
+/* $Id: CoinModel.cpp 1509 2011-12-05 13:50:48Z forrest $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinUtilsConfig.h"
+#include "CoinHelperFunctions.hpp"
+#include "CoinModel.hpp"
+#include "CoinSort.hpp"
+#include "CoinMpsIO.hpp"
+#include "CoinFloatEqual.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinBaseModel::CoinBaseModel () 
+  :  numberRows_(0),
+     numberColumns_(0),
+     optimizationDirection_(1.0),
+     objectiveOffset_(0.0),
+     logLevel_(0)
+{
+  problemName_ = "";
+  rowBlockName_ = "row_master";
+  columnBlockName_ = "column_master";
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinBaseModel::CoinBaseModel (const CoinBaseModel & rhs) 
+  : numberRows_(rhs.numberRows_),
+    numberColumns_(rhs.numberColumns_),
+    optimizationDirection_(rhs.optimizationDirection_),
+    objectiveOffset_(rhs.objectiveOffset_),
+    logLevel_(rhs.logLevel_)
+{
+  problemName_ = rhs.problemName_;
+  rowBlockName_ = rhs.rowBlockName_;
+  columnBlockName_ = rhs.columnBlockName_;
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinBaseModel::~CoinBaseModel ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinBaseModel &
+CoinBaseModel::operator=(const CoinBaseModel& rhs)
+{
+  if (this != &rhs) {
+    problemName_ = rhs.problemName_;
+    rowBlockName_ = rhs.rowBlockName_;
+    columnBlockName_ = rhs.columnBlockName_;
+    numberRows_ = rhs.numberRows_;
+    numberColumns_ = rhs.numberColumns_;
+    optimizationDirection_ = rhs.optimizationDirection_;
+    objectiveOffset_ = rhs.objectiveOffset_;
+    logLevel_ = rhs.logLevel_;
+  }
+  return *this;
+}
+void 
+CoinBaseModel::setLogLevel(int value)
+{
+  if (value>=0&&value<3)
+    logLevel_=value;
+}
+void
+CoinBaseModel::setProblemName (const char *name)
+{ 
+  if (name)
+    problemName_ = name ;
+  else
+    problemName_ = "";
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinModel::CoinModel () 
+  :  CoinBaseModel(),
+     maximumRows_(0),
+     maximumColumns_(0),
+     numberElements_(0),
+     maximumElements_(0),
+     numberQuadraticElements_(0),
+     maximumQuadraticElements_(0),
+     rowLower_(NULL),
+     rowUpper_(NULL),
+     rowType_(NULL),
+     objective_(NULL),
+     columnLower_(NULL),
+     columnUpper_(NULL),
+     integerType_(NULL),
+     columnType_(NULL),
+     start_(NULL),
+     elements_(NULL),
+     packedMatrix_(NULL),
+     quadraticElements_(NULL),
+     sortIndices_(NULL),
+     sortElements_(NULL),
+     sortSize_(0),
+     sizeAssociated_(0),
+     associated_(NULL),
+     numberSOS_(0),
+     startSOS_(NULL),
+     memberSOS_(NULL),
+     typeSOS_(NULL),
+     prioritySOS_(NULL),
+     referenceSOS_(NULL),
+     priority_(NULL),
+     cut_(NULL),
+     moreInfo_(NULL),
+     type_(-1),
+     noNames_(false),
+     links_(0)
+{
+}
+/* Constructor with sizes. */
+CoinModel::CoinModel(int firstRows, int firstColumns, int firstElements,bool noNames)
+  :  CoinBaseModel(),
+     maximumRows_(0),
+     maximumColumns_(0),
+     numberElements_(0),
+     maximumElements_(0),
+     numberQuadraticElements_(0),
+     maximumQuadraticElements_(0),
+     rowLower_(NULL),
+     rowUpper_(NULL),
+     rowType_(NULL),
+     objective_(NULL),
+     columnLower_(NULL),
+     columnUpper_(NULL),
+     integerType_(NULL),
+     columnType_(NULL),
+     start_(NULL),
+     elements_(NULL),
+     packedMatrix_(NULL),
+     quadraticElements_(NULL),
+     sortIndices_(NULL),
+     sortElements_(NULL),
+     sortSize_(0),
+     sizeAssociated_(0),
+     associated_(NULL),
+     numberSOS_(0),
+     startSOS_(NULL),
+     memberSOS_(NULL),
+     typeSOS_(NULL),
+     prioritySOS_(NULL),
+     referenceSOS_(NULL),
+     priority_(NULL),
+     cut_(NULL),
+     moreInfo_(NULL),
+     type_(-1),
+     noNames_(noNames),
+     links_(0)
+{
+  if (!firstRows) {
+    if (firstColumns) {
+      type_=1;
+      resize(0,firstColumns,firstElements);
+    }
+  } else {
+    type_=0;
+    resize(firstRows,0,firstElements);
+    if (firstColumns) {
+      // mixed - do linked lists for columns
+      //createList(2);
+    }
+  }
+}
+/* Read a problem in MPS or GAMS format from the given filename.
+ */
+CoinModel::CoinModel(const char *fileName, int allowStrings)
+  : CoinBaseModel(),
+    maximumRows_(0),
+    maximumColumns_(0),
+    numberElements_(0),
+    maximumElements_(0),
+    numberQuadraticElements_(0),
+    maximumQuadraticElements_(0),
+    rowLower_(NULL),
+    rowUpper_(NULL),
+    rowType_(NULL),
+    objective_(NULL),
+    columnLower_(NULL),
+    columnUpper_(NULL),
+    integerType_(NULL),
+    columnType_(NULL),
+    start_(NULL),
+    elements_(NULL),
+    packedMatrix_(NULL),
+    quadraticElements_(NULL),
+    sortIndices_(NULL),
+    sortElements_(NULL),
+    sortSize_(0),
+    sizeAssociated_(0),
+    associated_(NULL),
+    numberSOS_(0),
+    startSOS_(NULL),
+    memberSOS_(NULL),
+    typeSOS_(NULL),
+    prioritySOS_(NULL),
+    referenceSOS_(NULL),
+    priority_(NULL),
+    cut_(NULL),
+    moreInfo_(NULL),
+    type_(-1),
+    noNames_(false),
+    links_(0)
+{
+  rowBlockName_ = "row_master";
+  columnBlockName_ = "column_master";
+  int status=0;
+  if (!strcmp(fileName,"-")||!strcmp(fileName,"stdin")) {
+    // stdin
+  } else {
+    std::string name=fileName;
+    bool readable = fileCoinReadable(name);
+    if (!readable) {
+      std::cerr<<"Unable to open file "
+	       <<fileName<<std::endl;
+      status = -1;
+    }
+  }
+  CoinMpsIO m;
+  m.setAllowStringElements(allowStrings);
+  m.setConvertObjective(true);
+  if (!status) {
+    try {
+      status=m.readMps(fileName,"");
+    }
+    catch (CoinError& e) {
+      e.print();
+      status=-1;
+    }
+  }
+  if (!status) {
+    // set problem name
+    problemName_=m.getProblemName();
+    objectiveOffset_ = m.objectiveOffset();
+    // build model
+    int numberRows = m.getNumRows();
+    int numberColumns = m.getNumCols();
+    
+    // Build by row from scratch
+    CoinPackedMatrix matrixByRow = * m.getMatrixByRow();
+    const double * element = matrixByRow.getElements();
+    const int * column = matrixByRow.getIndices();
+    const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+    const int * rowLength = matrixByRow.getVectorLengths();
+    const double * rowLower = m.getRowLower();
+    const double * rowUpper = m.getRowUpper();
+    const double * columnLower = m.getColLower();
+    const double * columnUpper = m.getColUpper();
+    const double * objective = m.getObjCoefficients();
+    int i;
+    for (i=0;i<numberRows;i++) {
+      addRow(rowLength[i],column+rowStart[i],
+	     element+rowStart[i],rowLower[i],rowUpper[i],m.rowName(i));
+    }
+    int numberIntegers = 0;
+    // Now do column part
+    for (i=0;i<numberColumns;i++) {
+      setColumnBounds(i,columnLower[i],columnUpper[i]);
+      setColumnObjective(i,objective[i]);
+      if (m.isInteger(i)) {
+	setColumnIsInteger(i,true);;
+	numberIntegers++;
+      }
+    }
+    bool quadraticInteger = (numberIntegers!=0)&&m.reader()->whichSection (  ) == COIN_QUAD_SECTION ;
+    // do names
+    int iRow;
+    for (iRow=0;iRow<numberRows_;iRow++) {
+      const char * name = m.rowName(iRow);
+      setRowName(iRow,name);
+    }
+    bool ifStrings = ( m.numberStringElements() != 0 );
+    int nChanged=0;
+    int iColumn;
+    for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+      // Replace - + or * if strings
+      if (!ifStrings&&!quadraticInteger) {
+	const char * name = m.columnName(iColumn);
+	setColumnName(iColumn,name);
+      } else {
+	assert (strlen(m.columnName(iColumn))<100);
+	char temp[100];
+	strcpy(temp,m.columnName(iColumn));
+	int n=CoinStrlenAsInt(temp);
+	bool changed=false;
+	for (int i=0;i<n;i++) {
+	  if (temp[i]=='-') {
+	    temp[i]='_';
+	    changed=true;
+	  } else
+	  if (temp[i]=='+') {
+	    temp[i]='$';
+	    changed=true;
+	  } else
+	  if (temp[i]=='*') {
+	    temp[i]='&';
+	    changed=true;
+	  }
+	}
+	if (changed)
+	  nChanged++;
+	setColumnName(iColumn,temp);
+      }
+    }
+    if (nChanged) 
+      printf("%d column names changed to eliminate - + or *\n",nChanged);
+    if (ifStrings) {
+      // add in 
+      int numberElements = m.numberStringElements();
+      for (int i=0;i<numberElements;i++) {
+	const char * line = m.stringElement(i);
+	int iRow;
+	int iColumn;
+	sscanf(line,"%d,%d,",&iRow,&iColumn);
+	assert (iRow>=0&&iRow<=numberRows_+2);
+	assert (iColumn>=0&&iColumn<=numberColumns_);
+	const char * pos = strchr(line,',');
+	assert (pos);
+	pos = strchr(pos+1,',');
+	assert (pos);
+	pos++;
+	if (iRow<numberRows_&&iColumn<numberColumns_) {
+	  // element
+	  setElement(iRow,iColumn,pos);
+	} else {
+	  fprintf(stderr,"code CoinModel strings for rim\n");
+	  abort();
+	}
+      }
+    }
+    // get quadratic part
+    if (m.reader()->whichSection (  ) == COIN_QUAD_SECTION ) {
+      int * start=NULL;
+      int * column = NULL;
+      double * element = NULL;
+      status=m.readQuadraticMps(NULL,start,column,element,2);
+      if (!status) {
+	// If strings allowed 13 then just for Hans convert to constraint
+	int objRow=-1;
+	if (allowStrings==13) {
+	  int objColumn=numberColumns_;
+	  objRow=numberRows_;
+	  // leave linear part in objective
+	  addColumn(0,NULL,NULL,-COIN_DBL_MAX,COIN_DBL_MAX,1.0,"obj");
+	  double minusOne=-1.0;
+	  addRow(1,&objColumn,&minusOne,-COIN_DBL_MAX,0.0,"objrow");
+	}
+	if (!ifStrings&&!numberIntegers) {
+	  // no strings - add to quadratic (not done yet)
+	  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+	    for (CoinBigIndex j = start[iColumn];j<start[iColumn+1];j++) {
+	      int jColumn = column[j];
+	      double value = element[j];
+	      // what about diagonal etc
+	      if (jColumn==iColumn) {
+		printf("diag %d %d %g\n",iColumn,jColumn,value);
+		setQuadraticElement(iColumn,jColumn,0.5*value);
+	      } else if (jColumn>iColumn) {
+		printf("above diag %d %d %g\n",iColumn,jColumn,value);
+	      } else if (jColumn<iColumn) {
+		printf("below diag %d %d %g\n",iColumn,jColumn,value);
+		setQuadraticElement(iColumn,jColumn,value);
+	      }
+	    }
+	  }
+	} else {
+	  // add in as strings
+	  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+	    char temp[20000];
+	    temp[0]='\0';
+	    int put=0;
+	    int n=0;
+	    bool ifFirst=true;
+	    double value = getColumnObjective(iColumn);
+	    if (value&&objRow<0) {
+	      sprintf(temp,"%g",value);
+	      ifFirst=false;
+              /* static cast is safe, temp is at most 20000 chars */
+	      put = CoinStrlenAsInt(temp);
+	    }
+	    for (CoinBigIndex j = start[iColumn];j<start[iColumn+1];j++) {
+	      int jColumn = column[j];
+	      double value = element[j];
+	      // what about diagonal etc
+	      if (jColumn==iColumn) {
+		//printf("diag %d %d %g\n",iColumn,jColumn,value);
+		value *= 0.5;
+	      } else if (jColumn>iColumn) {
+		//printf("above diag %d %d %g\n",iColumn,jColumn,value);
+	      } else if (jColumn<iColumn) {
+		//printf("below diag %d %d %g\n",iColumn,jColumn,value);
+		value=0.0;
+	      }
+	      if (value) {
+		n++;
+		const char * name = columnName(jColumn);
+		if (value==1.0) {
+		  sprintf(temp+put,"%s%s",ifFirst ? "" : "+",name);
+		} else {
+		  if (ifFirst||value<0.0)
+		    sprintf(temp+put,"%g*%s",value,name);
+		  else
+		    sprintf(temp+put,"+%g*%s",value,name);
+		}
+		put += CoinStrlenAsInt(temp+put);
+		assert (put<20000);
+		ifFirst=false;
+	      }
+	    }
+	    if (n) {
+	      if (objRow<0)
+		setObjective(iColumn,temp);
+	      else
+		setElement(objRow,iColumn,temp);
+	      //printf("el for objective column c%7.7d is %s\n",iColumn,temp);
+	    }
+	  }
+	}
+      } 
+      delete [] start;
+      delete [] column;
+      delete [] element;
+    }
+  }
+}
+// From arrays
+CoinModel::CoinModel(int numberRows, int numberColumns,
+	    const CoinPackedMatrix * matrix,
+	    const double * rowLower, const double * rowUpper,
+	    const double * columnLower, const double * columnUpper,
+	    const double * objective)
+  :  CoinBaseModel(),
+     maximumRows_(numberRows),
+     maximumColumns_(numberColumns),
+     numberElements_(matrix->getNumElements()),
+     maximumElements_(matrix->getNumElements()),
+     numberQuadraticElements_(0),
+     maximumQuadraticElements_(0),
+     rowType_(NULL),
+     integerType_(NULL),
+     columnType_(NULL),
+     start_(NULL),
+     elements_(NULL),
+     packedMatrix_(NULL),
+     quadraticElements_(NULL),
+     sortIndices_(NULL),
+     sortElements_(NULL),
+     sortSize_(0),
+     sizeAssociated_(0),
+     associated_(NULL),
+     numberSOS_(0),
+     startSOS_(NULL),
+     memberSOS_(NULL),
+     typeSOS_(NULL),
+     prioritySOS_(NULL),
+     referenceSOS_(NULL),
+     priority_(NULL),
+     cut_(NULL),
+     moreInfo_(NULL),
+     type_(-1),
+     noNames_(false),
+     links_(0)
+{
+  numberRows_ = numberRows;
+  numberColumns_ = numberColumns;
+  assert (numberRows_>=matrix->getNumRows());
+  assert (numberColumns_>=matrix->getNumCols());
+  type_ = 3;
+  packedMatrix_ = new CoinPackedMatrix(*matrix);
+  rowLower_ = CoinCopyOfArray(rowLower,numberRows_);
+  rowUpper_ = CoinCopyOfArray(rowUpper,numberRows_);
+  objective_ = CoinCopyOfArray(objective,numberColumns_);
+  columnLower_ = CoinCopyOfArray(columnLower,numberColumns_);
+  columnUpper_ = CoinCopyOfArray(columnUpper,numberColumns_);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinModel::CoinModel (const CoinModel & rhs) 
+  : CoinBaseModel(rhs),
+    maximumRows_(rhs.maximumRows_),
+    maximumColumns_(rhs.maximumColumns_),
+    numberElements_(rhs.numberElements_),
+    maximumElements_(rhs.maximumElements_),
+    numberQuadraticElements_(rhs.numberQuadraticElements_),
+    maximumQuadraticElements_(rhs.maximumQuadraticElements_),
+    rowName_(rhs.rowName_),
+    columnName_(rhs.columnName_),
+    string_(rhs.string_),
+    hashElements_(rhs.hashElements_),
+    rowList_(rhs.rowList_),
+    columnList_(rhs.columnList_),
+    hashQuadraticElements_(rhs.hashQuadraticElements_),
+    sortSize_(rhs.sortSize_),
+    quadraticRowList_(rhs.quadraticRowList_),
+    quadraticColumnList_(rhs.quadraticColumnList_),
+    sizeAssociated_(rhs.sizeAssociated_),
+    numberSOS_(rhs.numberSOS_),
+    type_(rhs.type_),
+    noNames_(rhs.noNames_),
+    links_(rhs.links_)
+{
+  rowLower_ = CoinCopyOfArray(rhs.rowLower_,maximumRows_);
+  rowUpper_ = CoinCopyOfArray(rhs.rowUpper_,maximumRows_);
+  rowType_ = CoinCopyOfArray(rhs.rowType_,maximumRows_);
+  objective_ = CoinCopyOfArray(rhs.objective_,maximumColumns_);
+  columnLower_ = CoinCopyOfArray(rhs.columnLower_,maximumColumns_);
+  columnUpper_ = CoinCopyOfArray(rhs.columnUpper_,maximumColumns_);
+  integerType_ = CoinCopyOfArray(rhs.integerType_,maximumColumns_);
+  columnType_ = CoinCopyOfArray(rhs.columnType_,maximumColumns_);
+  sortIndices_ = CoinCopyOfArray(rhs.sortIndices_,sortSize_);
+  sortElements_ = CoinCopyOfArray(rhs.sortElements_,sortSize_);
+  associated_ = CoinCopyOfArray(rhs.associated_,sizeAssociated_);
+  priority_ = CoinCopyOfArray(rhs.priority_,maximumColumns_);
+  cut_ = CoinCopyOfArray(rhs.cut_,maximumRows_);
+  moreInfo_ = rhs.moreInfo_;
+  if (rhs.packedMatrix_)
+    packedMatrix_ = new CoinPackedMatrix(*rhs.packedMatrix_);
+  else
+    packedMatrix_ = NULL;
+  if (numberSOS_) {
+    startSOS_ = CoinCopyOfArray(rhs.startSOS_,numberSOS_+1);
+    int numberMembers = startSOS_[numberSOS_];
+    memberSOS_ = CoinCopyOfArray(rhs.memberSOS_,numberMembers);
+    typeSOS_ = CoinCopyOfArray(rhs.typeSOS_,numberSOS_);
+    prioritySOS_ = CoinCopyOfArray(rhs.prioritySOS_,numberSOS_);
+    referenceSOS_ = CoinCopyOfArray(rhs.referenceSOS_,numberMembers);
+  } else {
+    startSOS_ = NULL;
+    memberSOS_ = NULL;
+    typeSOS_ = NULL;
+    prioritySOS_ = NULL;
+    referenceSOS_ = NULL;
+  }
+  if (type_==0) {
+    start_ = CoinCopyOfArray(rhs.start_,maximumRows_+1);
+  } else if (type_==1) {
+    start_ = CoinCopyOfArray(rhs.start_,maximumColumns_+1);
+  } else {
+    start_=NULL;
+  }
+  elements_ = CoinCopyOfArray(rhs.elements_,maximumElements_);
+  quadraticElements_ = CoinCopyOfArray(rhs.quadraticElements_,maximumQuadraticElements_);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinModel::~CoinModel ()
+{
+  delete [] rowLower_;
+  delete [] rowUpper_;
+  delete [] rowType_;
+  delete [] objective_;
+  delete [] columnLower_;
+  delete [] columnUpper_;
+  delete [] integerType_;
+  delete [] columnType_;
+  delete [] start_;
+  delete [] elements_;
+  delete [] quadraticElements_;
+  delete [] sortIndices_;
+  delete [] sortElements_;
+  delete [] associated_;
+  delete [] startSOS_;
+  delete [] memberSOS_;
+  delete [] typeSOS_;
+  delete [] prioritySOS_;
+  delete [] referenceSOS_;
+  delete [] priority_;
+  delete [] cut_;
+  delete packedMatrix_;
+}
+// Clone
+CoinBaseModel *
+CoinModel::clone() const
+{
+  return new CoinModel(*this);
+}
+
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinModel &
+CoinModel::operator=(const CoinModel& rhs)
+{
+  if (this != &rhs) {
+    CoinBaseModel::operator=(rhs);
+    delete [] rowLower_;
+    delete [] rowUpper_;
+    delete [] rowType_;
+    delete [] objective_;
+    delete [] columnLower_;
+    delete [] columnUpper_;
+    delete [] integerType_;
+    delete [] columnType_;
+    delete [] start_;
+    delete [] elements_;
+    delete [] quadraticElements_;
+    delete [] sortIndices_;
+    delete [] sortElements_;
+    delete [] associated_;
+    delete [] startSOS_;
+    delete [] memberSOS_;
+    delete [] typeSOS_;
+    delete [] prioritySOS_;
+    delete [] referenceSOS_;
+    delete [] priority_;
+    delete [] cut_;
+    delete packedMatrix_;
+    maximumRows_ = rhs.maximumRows_;
+    maximumColumns_ = rhs.maximumColumns_;
+    numberElements_ = rhs.numberElements_;
+    maximumElements_ = rhs.maximumElements_;
+    numberQuadraticElements_ = rhs.numberQuadraticElements_;
+    maximumQuadraticElements_ = rhs.maximumQuadraticElements_;
+    sortSize_ = rhs.sortSize_;
+    rowName_ = rhs.rowName_;
+    columnName_ = rhs.columnName_;
+    string_ = rhs.string_;
+    hashElements_=rhs.hashElements_;
+    hashQuadraticElements_=rhs.hashQuadraticElements_;
+    rowList_ = rhs.rowList_;
+    quadraticColumnList_ = rhs.quadraticColumnList_;
+    quadraticRowList_ = rhs.quadraticRowList_;
+    columnList_ = rhs.columnList_;
+    sizeAssociated_= rhs.sizeAssociated_;
+    numberSOS_ = rhs.numberSOS_;
+    type_ = rhs.type_;
+    noNames_ = rhs.noNames_;
+    links_ = rhs.links_;
+    rowLower_ = CoinCopyOfArray(rhs.rowLower_,maximumRows_);
+    rowUpper_ = CoinCopyOfArray(rhs.rowUpper_,maximumRows_);
+    rowType_ = CoinCopyOfArray(rhs.rowType_,maximumRows_);
+    objective_ = CoinCopyOfArray(rhs.objective_,maximumColumns_);
+    columnLower_ = CoinCopyOfArray(rhs.columnLower_,maximumColumns_);
+    columnUpper_ = CoinCopyOfArray(rhs.columnUpper_,maximumColumns_);
+    integerType_ = CoinCopyOfArray(rhs.integerType_,maximumColumns_);
+    columnType_ = CoinCopyOfArray(rhs.columnType_,maximumColumns_);
+    priority_ = CoinCopyOfArray(rhs.priority_,maximumColumns_);
+    cut_ = CoinCopyOfArray(rhs.cut_,maximumRows_);
+    moreInfo_ = rhs.moreInfo_;
+    if (rhs.packedMatrix_)
+      packedMatrix_ = new CoinPackedMatrix(*rhs.packedMatrix_);
+    else
+      packedMatrix_ = NULL;
+    if (numberSOS_) {
+      startSOS_ = CoinCopyOfArray(rhs.startSOS_,numberSOS_+1);
+      int numberMembers = startSOS_[numberSOS_];
+      memberSOS_ = CoinCopyOfArray(rhs.memberSOS_,numberMembers);
+      typeSOS_ = CoinCopyOfArray(rhs.typeSOS_,numberSOS_);
+      prioritySOS_ = CoinCopyOfArray(rhs.prioritySOS_,numberSOS_);
+      referenceSOS_ = CoinCopyOfArray(rhs.referenceSOS_,numberMembers);
+    } else {
+      startSOS_ = NULL;
+      memberSOS_ = NULL;
+      typeSOS_ = NULL;
+      prioritySOS_ = NULL;
+      referenceSOS_ = NULL;
+    }
+    if (type_==0) {
+      start_ = CoinCopyOfArray(rhs.start_,maximumRows_+1);
+    } else if (type_==1) {
+      start_ = CoinCopyOfArray(rhs.start_,maximumColumns_+1);
+    } else {
+      start_=NULL;
+    }
+    elements_ = CoinCopyOfArray(rhs.elements_,maximumElements_);
+    quadraticElements_ = CoinCopyOfArray(rhs.quadraticElements_,maximumQuadraticElements_);
+    sortIndices_ = CoinCopyOfArray(rhs.sortIndices_,sortSize_);
+    sortElements_ = CoinCopyOfArray(rhs.sortElements_,sortSize_);
+    associated_ = CoinCopyOfArray(rhs.associated_,sizeAssociated_);
+  }
+  return *this;
+}
+/* add a row -  numberInRow may be zero */
+void 
+CoinModel::addRow(int numberInRow, const int * columns,
+                  const double * elements, double rowLower, 
+                  double rowUpper, const char * name)
+{
+  if (type_==-1) {
+    // initial
+    type_=0;
+    resize(100,0,1000);
+  } else if (type_==1) {
+    // mixed - do linked lists for rows
+    createList(1);
+  } else if (type_==3) {
+    badType();
+  }
+  int newColumn=-1;
+  if (numberInRow>0) {
+    // Move and sort
+    if (numberInRow>sortSize_) {
+      delete [] sortIndices_;
+      delete [] sortElements_;
+      sortSize_ = numberInRow+100; 
+      sortIndices_ = new int [sortSize_];
+      sortElements_ = new double [sortSize_];
+    }
+    bool sorted = true;
+    int last=-1;
+    int i;
+    for (i=0;i<numberInRow;i++) {
+      int k=columns[i];
+      if (k<=last)
+        sorted=false;
+      last=k;
+      sortIndices_[i]=k;
+      sortElements_[i]=elements[i];
+    }
+    if (!sorted) {
+      CoinSort_2(sortIndices_,sortIndices_+numberInRow,sortElements_);
+    }
+    // check for duplicates etc
+    if (sortIndices_[0]<0) {
+      printf("bad index %d\n",sortIndices_[0]);
+      // clean up
+      abort();
+    }
+    last=-1;
+    bool duplicate=false;
+    for (i=0;i<numberInRow;i++) {
+      int k=sortIndices_[i];
+      if (k==last)
+        duplicate=true;
+      last=k;
+    }
+    if (duplicate) {
+      printf("duplicates - what do we want\n");
+      abort();
+    }
+    newColumn = CoinMax(newColumn,last);
+  }
+  int newRow=0;
+  int newElement=0;
+  if (numberElements_+numberInRow>maximumElements_) {
+    newElement = (3*(numberElements_+numberInRow)/2) + 1000;
+    if (numberRows_*10>maximumRows_*9)
+      newRow = (maximumRows_*3)/2+100;
+  }
+  if (numberRows_==maximumRows_)
+    newRow = (maximumRows_*3)/2+100;
+  if (newRow||newColumn>=maximumColumns_||newElement) {
+    if (newColumn<maximumColumns_) {
+      // columns okay
+      resize(newRow,0,newElement);
+    } else {
+      // newColumn will be new numberColumns_
+      resize(newRow,(3*newColumn)/2+100,newElement);
+    }
+  }
+  // If rows extended - take care of that
+  fillRows(numberRows_,false,true);
+  // Do name
+  if (name) {
+    rowName_.addHash(numberRows_,name);
+  } else if (!noNames_) {
+    char name[9];
+    sprintf(name,"r%7.7d",numberRows_);
+    rowName_.addHash(numberRows_,name);
+  }
+  rowLower_[numberRows_]=rowLower;
+  rowUpper_[numberRows_]=rowUpper;
+  // If columns extended - take care of that
+  fillColumns(newColumn,false);
+  if (type_==0) {
+    // can do simply
+    int put = start_[numberRows_];
+    assert (put==numberElements_);
+    bool doHash = hashElements_.numberItems()!=0;
+    for (int i=0;i<numberInRow;i++) {
+      setRowAndStringInTriple(elements_[put],numberRows_,false);
+      //elements_[put].row=static_cast<unsigned int>(numberRows_);
+      //elements_[put].string=0;
+      elements_[put].column=sortIndices_[i];
+      elements_[put].value=sortElements_[i];
+      if (doHash)
+        hashElements_.addHash(put,numberRows_,sortIndices_[i],elements_);
+      put++;
+    }
+    start_[numberRows_+1]=put;
+    numberElements_+=numberInRow;
+  } else {
+    if (numberInRow) {
+      // must update at least one link
+      assert (links_);
+      if (links_==1||links_==3) {
+        int first = rowList_.addEasy(numberRows_,numberInRow,sortIndices_,sortElements_,elements_,
+                                     hashElements_);
+        if (links_==3)
+          columnList_.addHard(first,elements_,rowList_.firstFree(),rowList_.lastFree(),
+                              rowList_.next());
+        numberElements_=CoinMax(numberElements_,rowList_.numberElements());
+        if (links_==3)
+          assert (columnList_.numberElements()==rowList_.numberElements());
+      } else if (links_==2) {
+        columnList_.addHard(numberRows_,numberInRow,sortIndices_,sortElements_,elements_,
+                            hashElements_);
+        numberElements_=CoinMax(numberElements_,columnList_.numberElements());
+      }
+    }
+    numberElements_=CoinMax(numberElements_,hashElements_.numberItems());
+  }
+  numberRows_++;
+}
+// add a column - numberInColumn may be zero */
+void 
+CoinModel::addColumn(int numberInColumn, const int * rows,
+                     const double * elements, 
+                     double columnLower, 
+                     double columnUpper, double objectiveValue,
+                     const char * name, bool isInteger)
+{
+  if (type_==-1) {
+    // initial
+    type_=1;
+    resize(0,100,1000);
+  } else if (type_==0) {
+    // mixed - do linked lists for columns
+    createList(2);
+  } else if (type_==3) {
+    badType();
+  }
+  int newRow=-1;
+  if (numberInColumn>0) {
+    // Move and sort
+    if (numberInColumn>sortSize_) {
+      delete [] sortIndices_;
+      delete [] sortElements_;
+      sortSize_ = numberInColumn+100; 
+      sortIndices_ = new int [sortSize_];
+      sortElements_ = new double [sortSize_];
+    }
+    bool sorted = true;
+    int last=-1;
+    int i;
+    for (i=0;i<numberInColumn;i++) {
+      int k=rows[i];
+      if (k<=last)
+        sorted=false;
+      last=k;
+      sortIndices_[i]=k;
+      sortElements_[i]=elements[i];
+    }
+    if (!sorted) {
+      CoinSort_2(sortIndices_,sortIndices_+numberInColumn,sortElements_);
+    }
+    // check for duplicates etc
+    if (sortIndices_[0]<0) {
+      printf("bad index %d\n",sortIndices_[0]);
+      // clean up
+      abort();
+    }
+    last=-1;
+    bool duplicate=false;
+    for (i=0;i<numberInColumn;i++) {
+      int k=sortIndices_[i];
+      if (k==last)
+        duplicate=true;
+      last=k;
+    }
+    if (duplicate) {
+      printf("duplicates - what do we want\n");
+      abort();
+    }
+    newRow = CoinMax(newRow,last);
+  }
+  int newColumn=0;
+  int newElement=0;
+  if (numberElements_+numberInColumn>maximumElements_) {
+    newElement = (3*(numberElements_+numberInColumn)/2) + 1000;
+    if (numberColumns_*10>maximumColumns_*9)
+      newColumn = (maximumColumns_*3)/2+100;
+  }
+  if (numberColumns_==maximumColumns_)
+    newColumn = (maximumColumns_*3)/2+100;
+  if (newColumn||newRow>=maximumRows_||newElement) {
+    if (newRow<maximumRows_) {
+      // rows okay
+      resize(0,newColumn,newElement);
+    } else {
+      // newRow will be new numberRows_
+      resize((3*newRow)/2+100,newColumn,newElement);
+    }
+  }
+  // If columns extended - take care of that
+  fillColumns(numberColumns_,false,true);
+  // Do name
+  if (name) {
+    columnName_.addHash(numberColumns_,name);
+  } else if (!noNames_) {
+    char name[9];
+    sprintf(name,"c%7.7d",numberColumns_);
+    columnName_.addHash(numberColumns_,name);
+  }
+  columnLower_[numberColumns_]=columnLower;
+  columnUpper_[numberColumns_]=columnUpper;
+  objective_[numberColumns_]=objectiveValue;
+  if (isInteger)
+    integerType_[numberColumns_]=1;
+  else
+    integerType_[numberColumns_]=0;
+  // If rows extended - take care of that
+  fillRows(newRow,false);
+  if (type_==1) {
+    // can do simply
+    int put = start_[numberColumns_];
+    assert (put==numberElements_);
+    bool doHash = hashElements_.numberItems()!=0;
+    for (int i=0;i<numberInColumn;i++) {
+      elements_[put].column=numberColumns_;
+      setRowAndStringInTriple(elements_[put],sortIndices_[i],false);
+      //elements_[put].string=0;
+      //elements_[put].row=static_cast<unsigned int>(sortIndices_[i]);
+      elements_[put].value=sortElements_[i];
+      if (doHash)
+        hashElements_.addHash(put,sortIndices_[i],numberColumns_,elements_);
+      put++;
+    }
+    start_[numberColumns_+1]=put;
+    numberElements_+=numberInColumn;
+  } else {
+    if (numberInColumn) {
+      // must update at least one link
+      assert (links_);
+      if (links_==2||links_==3) {
+        int first = columnList_.addEasy(numberColumns_,numberInColumn,sortIndices_,sortElements_,elements_,
+                                        hashElements_);
+        if (links_==3)
+          rowList_.addHard(first,elements_,columnList_.firstFree(),columnList_.lastFree(),
+                              columnList_.next());
+        numberElements_=CoinMax(numberElements_,columnList_.numberElements());
+        if (links_==3)
+          assert (columnList_.numberElements()==rowList_.numberElements());
+      } else if (links_==1) {
+        rowList_.addHard(numberColumns_,numberInColumn,sortIndices_,sortElements_,elements_,
+                         hashElements_);
+        numberElements_=CoinMax(numberElements_,rowList_.numberElements());
+      }
+    }
+  }
+  numberColumns_++;
+}
+// Sets value for row i and column j 
+void 
+CoinModel::setElement(int i,int j,double value) 
+{
+  if (type_==-1) {
+    // initial
+    type_=0;
+    resize(100,100,1000);
+    createList(2);
+  } else if (type_==3) {
+    badType();
+  } else if (!links_) {
+    if (type_==0||type_==2) {
+      createList(1);
+    } else if(type_==1) {
+      createList(2);
+    }
+  }
+  if (!hashElements_.maximumItems()) {
+    hashElements_.resize(maximumElements_,elements_);
+  }
+  int position = hashElements_.hash(i,j,elements_);
+  if (position>=0) {
+    elements_[position].value=value;
+    setStringInTriple(elements_[position],false);
+  } else {
+    int newColumn=0;
+    if (j>=maximumColumns_) {
+      newColumn = j+1;
+    }
+    int newRow=0;
+    if (i>=maximumRows_) {
+      newRow = i+1;
+    }
+    int newElement=0;
+    if (numberElements_==maximumElements_) {
+      newElement = (3*numberElements_/2) + 1000;
+    }
+    if (newRow||newColumn||newElement) {
+      if (newColumn) 
+        newColumn = (3*newColumn)/2+100;
+      if (newRow) 
+        newRow = (3*newRow)/2+100;
+      resize(newRow,newColumn,newElement);
+    }
+    // If columns extended - take care of that
+    fillColumns(j,false);
+    // If rows extended - take care of that
+    fillRows(i,false);
+    // treat as addRow unless only columnList_ exists
+    if ((links_&1)!=0) {
+      int first = rowList_.addEasy(i,1,&j,&value,elements_,hashElements_);
+      if (links_==3)
+        columnList_.addHard(first,elements_,rowList_.firstFree(),rowList_.lastFree(),
+                            rowList_.next());
+      numberElements_=CoinMax(numberElements_,rowList_.numberElements());
+      if (links_==3)
+        assert (columnList_.numberElements()==rowList_.numberElements());
+    } else if (links_==2) {
+      columnList_.addHard(i,1,&j,&value,elements_,hashElements_);
+      numberElements_=CoinMax(numberElements_,columnList_.numberElements());
+    }
+    numberRows_=CoinMax(numberRows_,i+1);;
+    numberColumns_=CoinMax(numberColumns_,j+1);;
+  }
+}
+// Sets quadratic value for column i and j 
+void 
+CoinModel::setQuadraticElement(int ,int ,double ) 
+{
+  printf("not written yet\n");
+  abort();
+  return;
+}
+// Sets value for row i and column j as string
+void 
+CoinModel::setElement(int i,int j,const char * value) 
+{
+  double dummyValue=1.0;
+  if (type_==-1) {
+    // initial
+    type_=0;
+    resize(100,100,1000);
+    createList(2);
+  } else if (type_==3) {
+    badType();
+  } else if (!links_) {
+    if (type_==0||type_==2) {
+      createList(1);
+    } else if(type_==1) {
+      createList(2);
+    }
+  }
+  if (!hashElements_.maximumItems()) {
+    // set up number of items
+    hashElements_.setNumberItems(numberElements_);
+    hashElements_.resize(maximumElements_,elements_);
+  }
+  int position = hashElements_.hash(i,j,elements_);
+  if (position>=0) {
+    int iValue = addString(value);
+    elements_[position].value=iValue;
+    setStringInTriple(elements_[position],true);
+  } else {
+    int newColumn=0;
+    if (j>=maximumColumns_) {
+      newColumn = j+1;
+    }
+    int newRow=0;
+    if (i>=maximumRows_) {
+      newRow = i+1;
+    }
+    int newElement=0;
+    if (numberElements_==maximumElements_) {
+      newElement = (3*numberElements_/2) + 1000;
+    }
+    if (newRow||newColumn||newElement) {
+      if (newColumn) 
+        newColumn = (3*newColumn)/2+100;
+      if (newRow) 
+        newRow = (3*newRow)/2+100;
+      resize(newRow,newColumn,newElement);
+    }
+    // If columns extended - take care of that
+    fillColumns(j,false);
+    // If rows extended - take care of that
+    fillRows(i,false);
+    // treat as addRow unless only columnList_ exists
+    if ((links_&1)!=0) {
+      int first = rowList_.addEasy(i,1,&j,&dummyValue,elements_,hashElements_);
+      if (links_==3)
+        columnList_.addHard(first,elements_,rowList_.firstFree(),rowList_.lastFree(),
+                            rowList_.next());
+      numberElements_=CoinMax(numberElements_,rowList_.numberElements());
+      if (links_==3)
+        assert (columnList_.numberElements()==rowList_.numberElements());
+    } else if (links_==2) {
+      columnList_.addHard(i,1,&j,&dummyValue,elements_,hashElements_);
+      numberElements_=CoinMax(numberElements_,columnList_.numberElements());
+    }
+    numberRows_=CoinMax(numberRows_,i+1);;
+    numberColumns_=CoinMax(numberColumns_,j+1);;
+    int position = hashElements_.hash(i,j,elements_);
+    assert (position>=0);
+    int iValue = addString(value);
+    elements_[position].value=iValue;
+    setStringInTriple(elements_[position],true);
+  }
+}
+// Associates a string with a value.  Returns string id (or -1 if does not exist)
+int 
+CoinModel::associateElement(const char * stringValue, double value)
+{
+  int position = string_.hash(stringValue);
+  if (position<0) {
+    // not there -add
+    position = addString(stringValue);
+    assert (position==string_.numberItems()-1);
+  }
+  if (sizeAssociated_<=position) {
+    int newSize = (3*position)/2+100;
+    double * temp = new double[newSize];
+    CoinMemcpyN(associated_,sizeAssociated_,temp);
+    CoinFillN(temp+sizeAssociated_,newSize-sizeAssociated_,unsetValue());
+    delete [] associated_;
+    associated_ = temp;
+    sizeAssociated_=newSize;
+  }
+  associated_[position]=value;
+  return position;
+}
+/* Sets rowLower (if row does not exist then
+   all rows up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setRowLower(int whichRow,double rowLower)
+{
+  assert (whichRow>=0);
+  // make sure enough room and fill
+  fillRows(whichRow,true);
+  rowLower_[whichRow]=rowLower;
+  rowType_[whichRow] &= ~1;
+}
+/* Sets rowUpper (if row does not exist then
+   all rows up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setRowUpper(int whichRow,double rowUpper)
+{
+  assert (whichRow>=0);
+  // make sure enough room and fill
+  fillRows(whichRow,true);
+  rowUpper_[whichRow]=rowUpper;
+  rowType_[whichRow] &= ~2;
+}
+/* Sets rowLower and rowUpper (if row does not exist then
+   all rows up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setRowBounds(int whichRow,double rowLower,double rowUpper)
+{
+  assert (whichRow>=0);
+  // make sure enough room and fill
+  fillRows(whichRow,true);
+  rowLower_[whichRow]=rowLower;
+  rowUpper_[whichRow]=rowUpper;
+  rowType_[whichRow] &= ~3;
+}
+/* Sets name (if row does not exist then
+   all rows up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setRowName(int whichRow,const char * rowName)
+{
+  assert (whichRow>=0);
+  // make sure enough room and fill
+  fillRows(whichRow,true);
+  assert (!noNames_) ;
+  const char * oldName = rowName_.name(whichRow);
+  if (oldName)
+    rowName_.deleteHash(whichRow);
+  if (rowName)
+    rowName_.addHash(whichRow,rowName);
+}
+/* Sets columnLower (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnLower(int whichColumn,double columnLower)
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  columnLower_[whichColumn]=columnLower;
+  columnType_[whichColumn] &= ~1;
+}
+/* Sets columnUpper (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnUpper(int whichColumn,double columnUpper)
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  columnUpper_[whichColumn]=columnUpper;
+  columnType_[whichColumn] &= ~2;
+}
+/* Sets columnLower and columnUpper (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnBounds(int whichColumn,double columnLower,double columnUpper)
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  columnLower_[whichColumn]=columnLower;
+  columnUpper_[whichColumn]=columnUpper;
+  columnType_[whichColumn] &= ~3;
+}
+/* Sets columnObjective (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnObjective(int whichColumn,double columnObjective)
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  objective_[whichColumn]=columnObjective;
+  columnType_[whichColumn] &= ~4;
+}
+/* Sets name (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnName(int whichColumn,const char * columnName)
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  const char * oldName = columnName_.name(whichColumn);
+  assert (!noNames_) ;
+  if (oldName)
+    columnName_.deleteHash(whichColumn);
+  if (columnName)
+    columnName_.addHash(whichColumn,columnName);
+}
+/* Sets integer (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnIsInteger(int whichColumn,bool columnIsInteger)
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  integerType_[whichColumn]=(columnIsInteger) ? 1 : 0;
+  columnType_[whichColumn] &= ~8;
+}
+// Adds one string, returns index
+int 
+CoinModel::addString(const char * string)
+{
+  int position = string_.hash(string);
+  if (position<0) {
+    position = string_.numberItems();
+    string_.addHash(position,string);
+  }
+  return position;
+}
+/* Sets rowLower (if row does not exist then
+   all rows up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setRowLower(int whichRow,const char * rowLower) 
+{
+  assert (whichRow>=0);
+  // make sure enough room and fill
+  fillRows(whichRow,true);
+  if (rowLower) {
+    int value = addString(rowLower);
+    rowLower_[whichRow]=value;
+    rowType_[whichRow] |= 1; 
+  } else {
+    rowLower_[whichRow]=-COIN_DBL_MAX;
+  }
+}
+/* Sets rowUpper (if row does not exist then
+   all rows up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setRowUpper(int whichRow,const char * rowUpper) 
+{
+  assert (whichRow>=0);
+  // make sure enough room and fill
+  fillRows(whichRow,true);
+  if (rowUpper) {
+    int value = addString(rowUpper);
+    rowUpper_[whichRow]=value;
+    rowType_[whichRow] |= 2; 
+  } else {
+    rowUpper_[whichRow]=COIN_DBL_MAX;
+  }
+}
+/* Sets columnLower (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnLower(int whichColumn,const char * columnLower) 
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  if (columnLower) {
+    int value = addString(columnLower);
+    columnLower_[whichColumn]=value;
+    columnType_[whichColumn] |= 1; 
+  } else {
+    columnLower_[whichColumn]=0.0;
+  }
+}
+/* Sets columnUpper (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnUpper(int whichColumn,const char * columnUpper) 
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  if (columnUpper) {
+    int value = addString(columnUpper);
+    columnUpper_[whichColumn]=value;
+    columnType_[whichColumn] |= 2; 
+  } else {
+    columnUpper_[whichColumn]=COIN_DBL_MAX;
+  }
+}
+/* Sets columnObjective (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnObjective(int whichColumn,const char * columnObjective) 
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  if (columnObjective) {
+    int value = addString(columnObjective);
+    objective_[whichColumn]=value;
+    columnType_[whichColumn] |= 4; 
+  } else {
+    objective_[whichColumn]=0.0;
+  }
+}
+/* Sets integer (if column does not exist then
+   all columns up to this are defined with default values and no elements)
+*/
+void 
+CoinModel::setColumnIsInteger(int whichColumn,const char * columnIsInteger) 
+{
+  assert (whichColumn>=0);
+  // make sure enough room and fill
+  fillColumns(whichColumn,true);
+  if (columnIsInteger) {
+    int value = addString(columnIsInteger);
+    integerType_[whichColumn]=value;
+    columnType_[whichColumn] |= 8; 
+  } else {
+    integerType_[whichColumn]=0;
+  }
+}
+//static const char * minusInfinity="-infinity";
+//static const char * plusInfinity="+infinity";
+//static const char * zero="0.0";
+static const char * numeric="Numeric";
+/* Gets rowLower (if row does not exist then -COIN_DBL_MAX)
+ */
+const char *  
+CoinModel::getRowLowerAsString(int whichRow) const  
+{
+  assert (whichRow>=0);
+  if (whichRow<numberRows_&&rowLower_) {
+    if ((rowType_[whichRow]&1)!=0) {
+      int position = static_cast<int> (rowLower_[whichRow]);
+      return string_.name(position);
+    } else {
+      return numeric;
+    }
+  } else {
+    return numeric;
+  }
+}
+/* Gets rowUpper (if row does not exist then +COIN_DBL_MAX)
+ */
+const char *  
+CoinModel::getRowUpperAsString(int whichRow) const  
+{
+  assert (whichRow>=0);
+  if (whichRow<numberRows_&&rowUpper_) {
+    if ((rowType_[whichRow]&2)!=0) {
+      int position = static_cast<int> (rowUpper_[whichRow]);
+      return string_.name(position);
+    } else {
+      return numeric;
+    }
+  } else {
+    return numeric;
+  }
+}
+/* Gets columnLower (if column does not exist then 0.0)
+ */
+const char *  
+CoinModel::getColumnLowerAsString(int whichColumn) const  
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_&&columnLower_) {
+    if ((columnType_[whichColumn]&1)!=0) {
+      int position = static_cast<int> (columnLower_[whichColumn]);
+      return string_.name(position);
+    } else {
+      return numeric;
+    }
+  } else {
+    return numeric;
+  }
+}
+/* Gets columnUpper (if column does not exist then COIN_DBL_MAX)
+ */
+const char *  
+CoinModel::getColumnUpperAsString(int whichColumn) const  
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_&&columnUpper_) {
+    if ((columnType_[whichColumn]&2)!=0) {
+      int position = static_cast<int> (columnUpper_[whichColumn]);
+      return string_.name(position);
+    } else {
+      return numeric;
+    }
+  } else {
+    return numeric;
+  }
+}
+/* Gets columnObjective (if column does not exist then 0.0)
+ */
+const char *  
+CoinModel::getColumnObjectiveAsString(int whichColumn) const  
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_&&objective_) {
+    if ((columnType_[whichColumn]&4)!=0) {
+      int position = static_cast<int> (objective_[whichColumn]);
+      return string_.name(position);
+    } else {
+      return numeric;
+    }
+  } else {
+    return numeric;
+  }
+}
+/* Gets if integer (if column does not exist then false)
+ */
+const char * 
+CoinModel::getColumnIsIntegerAsString(int whichColumn) const  
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_&&integerType_) {
+    if ((columnType_[whichColumn]&8)!=0) {
+      int position = integerType_[whichColumn];
+      return string_.name(position);
+    } else {
+      return numeric;
+    }
+  } else {
+    return numeric;
+  }
+}
+/* Deletes all entries in row and bounds.*/
+void
+CoinModel::deleteRow(int whichRow)
+{
+  assert (whichRow>=0);
+  if (whichRow<numberRows_) {
+    if (rowLower_) {
+      rowLower_[whichRow]=-COIN_DBL_MAX;
+      rowUpper_[whichRow]=COIN_DBL_MAX;
+      rowType_[whichRow]=0;
+      if (!noNames_) 
+	rowName_.deleteHash(whichRow);
+    }
+    // need lists
+    if (type_==0) {
+      assert (start_);
+      assert (!hashElements_.numberItems());
+      delete [] start_;
+      start_=NULL;
+    }
+    if ((links_&1)==0) {
+      createList(1);
+    } 
+    assert (links_);
+    // row links guaranteed to exist
+    rowList_.deleteSame(whichRow,elements_,hashElements_,(links_!=3));
+    // Just need to set first and last and take out
+    if (links_==3)
+      columnList_.updateDeleted(whichRow,elements_,rowList_);
+  }
+}
+/* Deletes all entries in column and bounds.*/
+void
+CoinModel::deleteColumn(int whichColumn)
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_) {
+    if (columnLower_) {
+      columnLower_[whichColumn]=0.0;
+      columnUpper_[whichColumn]=COIN_DBL_MAX;
+      objective_[whichColumn]=0.0;
+      integerType_[whichColumn]=0;
+      columnType_[whichColumn]=0;
+      if (!noNames_) 
+	columnName_.deleteHash(whichColumn);
+    }
+    // need lists
+    if (type_==0) {
+      assert (start_);
+      assert (!hashElements_.numberItems());
+      delete [] start_;
+      start_=NULL;
+    } else if (type_==3) {
+      badType();
+    }
+    if ((links_&2)==0) {
+      createList(2);
+    } 
+    assert (links_);
+    // column links guaranteed to exist
+    columnList_.deleteSame(whichColumn,elements_,hashElements_,(links_!=3));
+    // Just need to set first and last and take out
+    if (links_==3)
+      rowList_.updateDeleted(whichColumn,elements_,columnList_);
+  }
+}
+// Takes element out of matrix
+int
+CoinModel::deleteElement(int row, int column)
+{
+  int iPos = position(row,column);
+  if (iPos>=0)
+    deleteThisElement(row,column,iPos);
+  return iPos;
+}
+// Takes element out of matrix when position known
+void
+#ifndef NDEBUG
+CoinModel::deleteThisElement(int row, int column,int position)
+#else
+CoinModel::deleteThisElement(int , int ,int position)
+#endif
+{
+  assert (row<numberRows_&&column<numberColumns_);
+  assert (row==rowInTriple(elements_[position])&&
+	  column==static_cast<int>(elements_[position].column));
+  if ((links_&1)==0) {
+    createList(1);
+  } 
+  assert (links_);
+  // row links guaranteed to exist
+  rowList_.deleteRowOne(position,elements_,hashElements_);
+  // Just need to set first and last and take out
+  if (links_==3)
+    columnList_.updateDeletedOne(position,elements_);
+  elements_[position].column=-1;
+  elements_[position].value=0.0;
+}
+/* Packs down all rows i.e. removes empty rows permanently.  Empty rows
+   have no elements and feasible bounds. returns number of rows deleted. */
+int 
+CoinModel::packRows()
+{
+  if (type_==3) 
+    badType();
+  int * newRow = new int[numberRows_];
+  memset(newRow,0,numberRows_*sizeof(int));
+  int iRow;
+  int n=0;
+  for (iRow=0;iRow<numberRows_;iRow++) {
+    if (rowLower_[iRow]!=-COIN_DBL_MAX)
+      newRow[iRow]++;
+    if (rowUpper_[iRow]!=COIN_DBL_MAX)
+      newRow[iRow]++;
+    if (!noNames_&&rowName_.name(iRow))
+	newRow[iRow]++;
+  }
+  int i;
+  for ( i=0;i<numberElements_;i++) {
+    if (elements_[i].column>=0) {
+      iRow = rowInTriple(elements_[i]);
+      assert (iRow>=0&&iRow<numberRows_);
+      newRow[iRow]++;
+    }
+  }
+  bool doRowNames = ( rowName_.numberItems() != 0 );
+  for (iRow=0;iRow<numberRows_;iRow++) {
+    if (newRow[iRow]) {
+      rowLower_[n]=rowLower_[iRow];
+      rowUpper_[n]=rowUpper_[iRow];
+      rowType_[n]=rowType_[iRow];
+      if (doRowNames)
+        rowName_.setName(n,rowName_.getName(iRow));
+      newRow[iRow]=n++;
+    } else {
+      newRow[iRow]=-1;
+    }
+  }
+  int numberDeleted = numberRows_-n;
+  if (numberDeleted) {
+    numberRows_=n;
+    n=0;
+    for ( i=0;i<numberElements_;i++) {
+      if (elements_[i].column>=0) {
+        elements_[n]=elements_[i];
+        setRowInTriple(elements_[n],newRow[rowInTriple(elements_[i])]);
+        n++;
+      }
+    }
+    numberElements_=n;
+    // now redo
+    if (doRowNames) {
+      rowName_.setNumberItems(numberRows_);
+      rowName_.resize(rowName_.maximumItems(),true);
+    }
+    if (hashElements_.numberItems()) {
+      hashElements_.setNumberItems(numberElements_);
+      hashElements_.resize(hashElements_.maximumItems(),elements_,true);
+    }
+    if (start_) {
+      int last=-1;
+      if (type_==0) {
+        for (i=0;i<numberElements_;i++) {
+          int now = rowInTriple(elements_[i]);
+          assert (now>=last);
+          if (now>last) {
+            start_[last+1]=numberElements_;
+            for (int j=last+1;j<now;j++)
+              start_[j+1]=numberElements_;
+            last=now;
+          }
+        }
+        for (int j=last+1;j<numberRows_;j++)
+          start_[j+1]=numberElements_;
+      } else {
+        assert (type_==1);
+        for (i=0;i<numberElements_;i++) {
+          int now = elements_[i].column;
+          assert (now>=last);
+          if (now>last) {
+            start_[last+1]=numberElements_;
+            for (int j=last+1;j<now;j++)
+              start_[j+1]=numberElements_;
+            last=now;
+          }
+        }
+        for (int j=last+1;j<numberColumns_;j++)
+          start_[j+1]=numberElements_;
+      }
+    }
+    if ((links_&1)!=0) {
+      rowList_ = CoinModelLinkedList();
+      links_ &= ~1;
+      createList(1);
+    }
+    if ((links_&2)!=0) {
+      columnList_ = CoinModelLinkedList();
+      links_ &= ~2;
+      createList(2);
+    }
+  }
+  delete [] newRow;
+  return numberDeleted;
+}
+/* Packs down all columns i.e. removes empty columns permanently.  Empty columns
+   have no elements and no objective. returns number of columns deleted. */
+int 
+CoinModel::packColumns()
+{
+  if (type_==3) 
+    badType();
+  int * newColumn = new int[numberColumns_];
+  memset(newColumn,0,numberColumns_*sizeof(int));
+  int iColumn;
+  int n=0;
+  for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+    if (columnLower_[iColumn]!=0.0)
+      newColumn[iColumn]++;
+    if (columnUpper_[iColumn]!=COIN_DBL_MAX)
+      newColumn[iColumn]++;
+    if (objective_[iColumn]!=0.0)
+      newColumn[iColumn]++;
+    if (!noNames_&&columnName_.name(iColumn))
+      newColumn[iColumn]++;
+  }
+  int i;
+  for ( i=0;i<numberElements_;i++) {
+    if (elements_[i].column>=0) {
+      iColumn = static_cast<int> (elements_[i].column);
+      assert (iColumn>=0&&iColumn<numberColumns_);
+      newColumn[iColumn]++;
+    }
+  }
+  bool doColumnNames = ( columnName_.numberItems() != 0 );
+  for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+    if (newColumn[iColumn]) {
+      columnLower_[n]=columnLower_[iColumn];
+      columnUpper_[n]=columnUpper_[iColumn];
+      objective_[n]=objective_[iColumn];
+      integerType_[n]=integerType_[iColumn];
+      columnType_[n]=columnType_[iColumn];
+      if (doColumnNames)
+        columnName_.setName(n,columnName_.getName(iColumn));
+      newColumn[iColumn]=n++;
+    } else {
+      newColumn[iColumn]=-1;
+    }
+  }
+  int numberDeleted = numberColumns_-n;
+  if (numberDeleted) {
+    numberColumns_=n;
+    n=0;
+    for ( i=0;i<numberElements_;i++) {
+      if (elements_[i].column>=0) {
+        elements_[n]=elements_[i];
+        elements_[n].column = newColumn[elements_[i].column];
+        n++;
+      }
+    }
+    numberElements_=n;
+    // now redo
+    if (doColumnNames) {
+      columnName_.setNumberItems(numberColumns_);
+      columnName_.resize(columnName_.maximumItems(),true);
+    }
+    if (hashElements_.numberItems()) {
+      hashElements_.setNumberItems(numberElements_);
+      hashElements_.resize(hashElements_.maximumItems(),elements_,true);
+    }
+    if (start_) {
+      int last=-1;
+      if (type_==0) {
+        for (i=0;i<numberElements_;i++) {
+          int now = rowInTriple(elements_[i]);
+          assert (now>=last);
+          if (now>last) {
+            start_[last+1]=numberElements_;
+            for (int j=last+1;j<now;j++)
+              start_[j+1]=numberElements_;
+            last=now;
+          }
+        }
+        for (int j=last+1;j<numberRows_;j++)
+          start_[j+1]=numberElements_;
+      } else {
+        assert (type_==1);
+        for (i=0;i<numberElements_;i++) {
+          int now = elements_[i].column;
+          assert (now>=last);
+          if (now>last) {
+            start_[last+1]=numberElements_;
+            for (int j=last+1;j<now;j++)
+              start_[j+1]=numberElements_;
+            last=now;
+          }
+        }
+        for (int j=last+1;j<numberColumns_;j++)
+          start_[j+1]=numberElements_;
+      }
+    }
+    if ((links_&1)!=0) {
+      rowList_ = CoinModelLinkedList();
+      links_ &= ~1;
+      createList(1);
+    }
+    if ((links_&2)!=0) {
+      columnList_ = CoinModelLinkedList();
+      links_ &= ~2;
+      createList(2);
+    }
+  }
+  delete [] newColumn;
+  return numberDeleted;
+}
+/* Packs down all rows and columns.  i.e. removes empty rows and columns permanently.
+   Empty rows have no elements and feasible bounds.
+   Empty columns have no elements and no objective.
+   returns number of rows+columns deleted. */
+int 
+CoinModel::pack()
+{
+  // For now do slowly (obvious overheads)
+  return packRows()+packColumns();
+}
+// Creates a packed matrix - return sumber of errors
+int 
+CoinModel::createPackedMatrix(CoinPackedMatrix & matrix, 
+			      const double * associated)
+{
+  if (type_==3) 
+    return 0; // badType();
+  // Set to say all parts
+  type_=2;
+  resize(numberRows_,numberColumns_,numberElements_);
+  // Do counts for CoinPackedMatrix
+  int * length = new int[numberColumns_];
+  CoinZeroN(length,numberColumns_);
+  int i;
+  int numberElements=0;
+  for (i=0;i<numberElements_;i++) {
+    int column = elements_[i].column;
+    if (column>=0) {
+      length[column]++;
+      numberElements++;
+    }
+  }
+  int numberErrors=0;
+  CoinBigIndex * start = new int[numberColumns_+1];
+  int * row = new int[numberElements];
+  double * element = new double[numberElements];
+  start[0]=0;
+  for (i=0;i<numberColumns_;i++) {
+    start[i+1]=start[i]+length[i];
+    length[i]=0;
+  }
+  numberElements=0;
+  for (i=0;i<numberElements_;i++) {
+    int column = elements_[i].column;
+    if (column>=0) {
+      double value = elements_[i].value;
+      if (stringInTriple(elements_[i])) {
+        int position = static_cast<int> (value);
+        assert (position<sizeAssociated_);
+        value = associated[position];
+        if (value==unsetValue()) {
+          numberErrors++;
+          value=0.0;
+        }
+      }
+      if (value) {
+        numberElements++;
+        int put=start[column]+length[column];
+        row[put]=rowInTriple(elements_[i]);
+        element[put]=value;
+        length[column]++;
+      }
+    }
+  }
+  for (i=0;i<numberColumns_;i++) {
+    int put = start[i];
+    CoinSort_2(row+put,row+put+length[i],element+put);
+  }
+  matrix=CoinPackedMatrix(true,numberRows_,numberColumns_,numberElements,
+                          element,row,start,length,0.0,0.0);
+  delete [] start;
+  delete [] length;
+  delete [] row;
+  delete [] element;
+  return numberErrors;
+}
+/* Fills in startPositive and startNegative with counts for +-1 matrix.
+   If not +-1 then startPositive[0]==-1 otherwise counts and
+   startPositive[numberColumns]== size
+      - return number of errors
+*/
+int 
+CoinModel::countPlusMinusOne(CoinBigIndex * startPositive, CoinBigIndex * startNegative,
+                             const double * associated)
+{
+  if (type_==3) 
+    badType();
+  memset(startPositive,0,numberColumns_*sizeof(int));
+  memset(startNegative,0,numberColumns_*sizeof(int));
+  // Set to say all parts
+  type_=2;
+  resize(numberRows_,numberColumns_,numberElements_);
+  int numberErrors=0;
+  CoinBigIndex numberElements=0;
+  for (CoinBigIndex i=0;i<numberElements_;i++) {
+    int column = elements_[i].column;
+    if (column>=0) {
+      double value = elements_[i].value;
+      if (stringInTriple(elements_[i])) {
+        int position = static_cast<int> (value);
+        assert (position<sizeAssociated_);
+        value = associated[position];
+        if (value==unsetValue()) {
+          numberErrors++;
+          value=0.0;
+          startPositive[0]=-1;
+          break;
+        }
+      }
+      if (value) {
+        numberElements++;
+        if (value==1.0) {
+          startPositive[column]++;
+        } else if (value==-1.0) {
+          startNegative[column]++;
+        } else {
+          startPositive[0]=-1;
+          break;
+        }
+      }
+    }
+  }
+  if (startPositive[0]>=0) 
+    startPositive[numberColumns_]=numberElements;
+  return numberErrors;
+}
+/* Creates +-1 matrix given startPositive and startNegative counts for +-1 matrix.
+ */
+void 
+CoinModel::createPlusMinusOne(CoinBigIndex * startPositive, CoinBigIndex * startNegative,
+                              int * indices,
+                              const double * associated)
+{
+  if (type_==3) 
+    badType();
+  CoinBigIndex size=0;
+  int iColumn;
+  for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+    CoinBigIndex n=startPositive[iColumn];
+    startPositive[iColumn]=size;
+    size+= n;
+    n=startNegative[iColumn];
+    startNegative[iColumn]=size;
+    size+= n;
+  }
+  startPositive[numberColumns_]=size;
+  for (CoinBigIndex i=0;i<numberElements_;i++) {
+    int column = elements_[i].column;
+    if (column>=0) {
+      double value = elements_[i].value;
+      if (stringInTriple(elements_[i])) {
+        int position = static_cast<int> (value);
+        assert (position<sizeAssociated_);
+        value = associated[position];
+      }
+      int iRow=rowInTriple(elements_[i]);
+      if (value==1.0) {
+        CoinBigIndex position = startPositive[column];
+        indices[position]=iRow;
+        startPositive[column]++;
+      } else if (value==-1.0) {
+        CoinBigIndex position = startNegative[column];
+        indices[position]=iRow;
+        startNegative[column]++;
+      }
+    }
+  }
+  // and now redo starts
+  for (iColumn=numberColumns_-1;iColumn>=0;iColumn--) {
+    startPositive[iColumn+1]=startNegative[iColumn];
+    startNegative[iColumn]=startPositive[iColumn];
+  }
+  startPositive[0]=0;
+  for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+    CoinBigIndex start = startPositive[iColumn];
+    CoinBigIndex end = startNegative[iColumn];
+    std::sort(indices+start,indices+end);
+    start = startNegative[iColumn];
+    end = startPositive[iColumn+1];
+    std::sort(indices+start,indices+end);
+  }
+}
+// Fills in all associated - returning number of errors
+int CoinModel::computeAssociated(double * associated)
+{
+  CoinYacc info;
+  info.length=0;
+  int numberErrors=0;
+  for (int i=0;i<string_.numberItems();i++) {
+    if (string_.name(i)&&associated[i]==unsetValue()) {
+      associated[i] = getDoubleFromString(info,string_.name(i));
+      if (associated[i]==unsetValue())
+        numberErrors++;
+    }
+  }
+  return numberErrors;
+}
+// Creates copies of various arrays - return number of errors
+int 
+CoinModel::createArrays(double * & rowLower, double * &  rowUpper,
+                        double * & columnLower, double * & columnUpper,
+                        double * & objective, int * & integerType,
+                        double * & associated)
+{
+  if (sizeAssociated_<string_.numberItems()) {
+    int newSize = string_.numberItems();
+    double * temp = new double[newSize];
+    CoinMemcpyN(associated_,sizeAssociated_,temp);
+    CoinFillN(temp+sizeAssociated_,newSize-sizeAssociated_,unsetValue());
+    delete [] associated_;
+    associated_ = temp;
+    sizeAssociated_=newSize;
+  }
+  associated = CoinCopyOfArray(associated_,sizeAssociated_);
+  int numberErrors = computeAssociated(associated);
+  // Fill in as much as possible
+  rowLower = CoinCopyOfArray( rowLower_,numberRows_);
+  rowUpper = CoinCopyOfArray( rowUpper_,numberRows_);
+  for (int iRow=0;iRow<numberRows_;iRow++) {
+    if ((rowType_[iRow]&1)!=0) {
+      int position = static_cast<int> (rowLower[iRow]);
+      assert (position<sizeAssociated_);
+      double value = associated[position];
+      if (value!=unsetValue()) {
+        rowLower[iRow]=value;
+      }
+    }
+    if ((rowType_[iRow]&2)!=0) {
+      int position = static_cast<int> (rowUpper[iRow]);
+      assert (position<sizeAssociated_);
+      double value = associated[position];
+      if (value!=unsetValue()) {
+        rowUpper[iRow]=value;
+      }
+    }
+  }
+  columnLower = CoinCopyOfArray( columnLower_,numberColumns_);
+  columnUpper = CoinCopyOfArray( columnUpper_,numberColumns_);
+  objective = CoinCopyOfArray( objective_,numberColumns_);
+  integerType = CoinCopyOfArray( integerType_,numberColumns_);
+  for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+    if ((columnType_[iColumn]&1)!=0) {
+      int position = static_cast<int> (columnLower[iColumn]);
+      assert (position<sizeAssociated_);
+      double value = associated[position];
+      if (value!=unsetValue()) {
+        columnLower[iColumn]=value;
+      }
+    }
+    if ((columnType_[iColumn]&2)!=0) {
+      int position = static_cast<int> (columnUpper[iColumn]);
+      assert (position<sizeAssociated_);
+      double value = associated[position];
+      if (value!=unsetValue()) {
+        columnUpper[iColumn]=value;
+      }
+    }
+    if ((columnType_[iColumn]&4)!=0) {
+      int position = static_cast<int> (objective[iColumn]);
+      assert (position<sizeAssociated_);
+      double value = associated[position];
+      if (value!=unsetValue()) {
+        objective[iColumn]=value;
+      }
+    }
+    if ((columnType_[iColumn]&8)!=0) {
+      int position = integerType[iColumn];
+      assert (position<sizeAssociated_);
+      double value = associated[position];
+      if (value!=unsetValue()) {
+        integerType[iColumn]=static_cast<int> (value);
+      }
+    }
+  }
+  return numberErrors;
+}
+
+/* Write the problem in MPS format to a file with the given filename.
+ */
+int 
+CoinModel::writeMps(const char *filename, int compression,
+                    int formatType , int numberAcross , bool keepStrings) 
+{
+  int numberErrors = 0;
+  // Set arrays for normal use
+  double * rowLower = rowLower_;
+  double * rowUpper = rowUpper_;
+  double * columnLower = columnLower_;
+  double * columnUpper = columnUpper_;
+  double * objective = objective_;
+  int * integerType = integerType_;
+  double * associated = associated_;
+  // If strings then do copies
+  if (string_.numberItems()) {
+    numberErrors = createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                 objective, integerType,associated);
+  }
+  CoinPackedMatrix matrix;
+  if (type_!=3) {
+    createPackedMatrix(matrix,associated);
+  } else {
+    matrix = *packedMatrix_;
+  }
+  char* integrality = new char[numberColumns_];
+  bool hasInteger = false;
+  for (int i = 0; i < numberColumns_; i++) {
+    if (integerType[i]) {
+      integrality[i] = 1;
+      hasInteger = true;
+    } else {
+      integrality[i] = 0;
+    }
+  }
+
+  CoinMpsIO writer;
+  writer.setInfinity(COIN_DBL_MAX);
+  const char *const * rowNames=NULL;
+  if (rowName_.numberItems())
+    rowNames=rowName_.names();
+  const char * const * columnNames=NULL;
+  if (columnName_.numberItems())
+    columnNames=columnName_.names();
+  writer.setMpsData(matrix, COIN_DBL_MAX,
+                    columnLower, columnUpper,
+                    objective, hasInteger ? integrality : 0,
+		     rowLower, rowUpper,
+		     columnNames,rowNames);
+  delete[] integrality;
+  if (rowLower!=rowLower_) {
+    delete [] rowLower;
+    delete [] rowUpper;
+    delete [] columnLower;
+    delete [] columnUpper;
+    delete [] objective;
+    delete [] integerType;
+    delete [] associated;
+    if (numberErrors&&logLevel_>0&&!keepStrings)
+      printf("%d string elements had no values associated with them\n",numberErrors);
+  }
+  writer.setObjectiveOffset(objectiveOffset_);
+  writer.setProblemName(problemName_.c_str());
+  if (keepStrings&&string_.numberItems()) {
+    // load up strings - sorted by column and row
+    writer.copyStringElements(this);
+  }
+  return writer.writeMps(filename, compression, formatType, numberAcross);
+}
+/* Check two models against each other.  Return nonzero if different.
+   Ignore names if that set.
+   May modify both models by cleaning up
+*/
+int 
+CoinModel::differentModel(CoinModel & other, bool ignoreNames)
+{
+  int numberErrors = 0;
+  int numberErrors2 = 0;
+  int returnCode=0;
+  if (numberRows_!=other.numberRows_||numberColumns_!=other.numberColumns_) {
+    if (logLevel_>0)
+      printf("** Mismatch on size, this has %d rows, %d columns - other has %d rows, %d columns\n",
+             numberRows_,numberColumns_,other.numberRows_,other.numberColumns_);
+    returnCode=1000;
+  }
+  // Set arrays for normal use
+  double * rowLower = rowLower_;
+  double * rowUpper = rowUpper_;
+  double * columnLower = columnLower_;
+  double * columnUpper = columnUpper_;
+  double * objective = objective_;
+  int * integerType = integerType_;
+  double * associated = associated_;
+  // If strings then do copies
+  if (string_.numberItems()) {
+    numberErrors += createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                 objective, integerType,associated);
+  }
+  // Set arrays for normal use
+  double * rowLower2 = other.rowLower_;
+  double * rowUpper2 = other.rowUpper_;
+  double * columnLower2 = other.columnLower_;
+  double * columnUpper2 = other.columnUpper_;
+  double * objective2 = other.objective_;
+  int * integerType2 = other.integerType_;
+  double * associated2 = other.associated_;
+  // If strings then do copies
+  if (other.string_.numberItems()) {
+    numberErrors2 += other.createArrays(rowLower2, rowUpper2, columnLower2, columnUpper2,
+                                 objective2, integerType2,associated2);
+  }
+  CoinPackedMatrix matrix;
+  createPackedMatrix(matrix,associated);
+  CoinPackedMatrix matrix2;
+  other.createPackedMatrix(matrix2,associated2);
+  if (numberErrors||numberErrors2)
+    if (logLevel_>0)
+      printf("** Errors when converting strings, %d on this, %d on other\n",
+             numberErrors,numberErrors2);
+  CoinRelFltEq tolerance;
+  if (numberRows_==other.numberRows_) {
+    bool checkNames = !ignoreNames;
+    if (!rowName_.numberItems()||
+        !other.rowName_.numberItems())
+      checkNames=false;
+    int numberDifferentL = 0;
+    int numberDifferentU = 0;
+    int numberDifferentN = 0;
+    for (int i=0;i<numberRows_;i++) {
+      if (!tolerance(rowLower[i],rowLower2[i]))
+        numberDifferentL++;
+      if (!tolerance(rowUpper[i],rowUpper2[i]))
+        numberDifferentU++;
+      if (checkNames&&rowName_.name(i)&&other.rowName_.name(i)) {
+        if (strcmp(rowName_.name(i),other.rowName_.name(i)))
+          numberDifferentN++;
+      }
+    }
+    int n = numberDifferentL+numberDifferentU+numberDifferentN;
+    returnCode+=n;
+    if (n&&logLevel_>0)
+      printf("Row differences , %d lower, %d upper and %d names\n",
+             numberDifferentL,numberDifferentU,numberDifferentN);
+  }
+  if (numberColumns_==other.numberColumns_) {
+    int numberDifferentL = 0;
+    int numberDifferentU = 0;
+    int numberDifferentN = 0;
+    int numberDifferentO = 0;
+    int numberDifferentI = 0;
+    bool checkNames = !ignoreNames;
+    if (!columnName_.numberItems()||
+        !other.columnName_.numberItems())
+      checkNames=false;
+    for (int i=0;i<numberColumns_;i++) {
+      if (!tolerance(columnLower[i],columnLower2[i]))
+        numberDifferentL++;
+      if (!tolerance(columnUpper[i],columnUpper2[i]))
+        numberDifferentU++;
+      if (!tolerance(objective[i],objective2[i]))
+        numberDifferentO++;
+      int i1 = (integerType) ? integerType[i] : 0;
+      int i2 = (integerType2) ? integerType2[i] : 0;
+      if (i1!=i2)
+        numberDifferentI++;
+      if (checkNames&&columnName_.name(i)&&other.columnName_.name(i)) {
+        if (strcmp(columnName_.name(i),other.columnName_.name(i)))
+          numberDifferentN++;
+      }
+    }
+    int n = numberDifferentL+numberDifferentU+numberDifferentN;
+    n+= numberDifferentO+numberDifferentI;
+    returnCode+=n;
+    if (n&&logLevel_>0)
+      printf("Column differences , %d lower, %d upper, %d objective, %d integer and %d names\n",
+             numberDifferentL,numberDifferentU,numberDifferentO,
+             numberDifferentI,numberDifferentN);
+  }
+  if (numberRows_==other.numberRows_&&
+      numberColumns_==other.numberColumns_&&
+      numberElements_==other.numberElements_) {
+    if (!matrix.isEquivalent(matrix2,tolerance)) {
+      returnCode+=100;
+    if (returnCode&&logLevel_>0)
+      printf("Two matrices are not same\n");
+    }
+  }
+
+  if (rowLower!=rowLower_) {
+    delete [] rowLower;
+    delete [] rowUpper;
+    delete [] columnLower;
+    delete [] columnUpper;
+    delete [] objective;
+    delete [] integerType;
+    delete [] associated;
+  }
+  if (rowLower2!=other.rowLower_) {
+    delete [] rowLower2;
+    delete [] rowUpper2;
+    delete [] columnLower2;
+    delete [] columnUpper2;
+    delete [] objective2;
+    delete [] integerType2;
+    delete [] associated2;
+  }
+  return returnCode;
+}
+// Returns value for row i and column j
+double 
+CoinModel::getElement(int i,int j) const
+{
+  if (!hashElements_.numberItems()) {
+    hashElements_.setNumberItems(numberElements_);
+    hashElements_.resize(maximumElements_,elements_);
+  }
+  int position = hashElements_.hash(i,j,elements_);
+  if (position>=0) {
+    return elements_[position].value;
+  } else {
+    return 0.0;
+  }
+}
+// Returns value for row rowName and column columnName
+double 
+CoinModel::getElement(const char * rowName,const char * columnName) const
+{
+  if (!hashElements_.numberItems()) {
+    hashElements_.setNumberItems(numberElements_);
+    hashElements_.resize(maximumElements_,elements_);
+  }
+  assert (!noNames_); 
+  int i=rowName_.hash(rowName);
+  int j=columnName_.hash(columnName);
+  int position;
+  if (i>=0&&j>=0)
+    position = hashElements_.hash(i,j,elements_);
+  else
+    position=-1;
+  if (position>=0) {
+    return elements_[position].value;
+  } else {
+    return 0.0;
+  }
+}
+// Returns quadratic value for columns i and j
+double 
+CoinModel::getQuadraticElement(int ,int ) const
+{
+  printf("not written yet\n");
+  abort();
+  return 0.0;
+}
+// Returns value for row i and column j as string
+const char * 
+CoinModel::getElementAsString(int i,int j) const
+{
+  if (!hashElements_.numberItems()) {
+    hashElements_.setNumberItems(numberElements_);
+    hashElements_.resize(maximumElements_,elements_);
+  }
+  int position = hashElements_.hash(i,j,elements_);
+  if (position>=0) {
+    if (stringInTriple(elements_[position])) {
+      int iString =  static_cast<int> (elements_[position].value);
+      assert (iString>=0&&iString<string_.numberItems());
+      return string_.name(iString);
+    } else {
+      return numeric;
+    }
+  } else {
+    return NULL;
+  }
+}
+/* Returns position of element for row i column j.
+   Only valid until next modification. 
+   -1 if element does not exist */
+int
+CoinModel::position (int i,int j) const
+{
+  if (!hashElements_.numberItems()) {
+    hashElements_.setNumberItems(numberElements_);
+    hashElements_.resize(maximumElements_,elements_,true);
+  }
+  return hashElements_.hash(i,j,elements_);
+}
+
+/* Returns pointer to element for row i column j.
+   Only valid until next modification. 
+   NULL if element does not exist */
+double * 
+CoinModel::pointer (int i,int j) const
+{
+  if (!hashElements_.numberItems()) {
+    hashElements_.setNumberItems(numberElements_);
+    hashElements_.resize(maximumElements_,elements_);
+  }
+  int position = hashElements_.hash(i,j,elements_);
+  if (position>=0) {
+    return &(elements_[position].value);
+  } else {
+    return NULL;
+  }
+}
+
+  
+/* Returns first element in given row - index is -1 if none.
+   Index is given by .index and value by .value
+*/
+CoinModelLink 
+CoinModel::firstInRow(int whichRow) const
+{
+  CoinModelLink link;
+  if (whichRow>=0&&whichRow<numberRows_) {
+    link.setOnRow(true);
+    if (type_==0) {
+      assert (start_);
+      int position = start_[whichRow];
+      if (position<start_[whichRow+1]) {
+        link.setRow(whichRow);
+        link.setPosition(position);
+        link.setColumn(elements_[position].column);
+        assert (whichRow==rowInTriple(elements_[position]));
+        link.setValue(elements_[position].value);
+      }
+    } else {
+      fillList(whichRow,rowList_,1);
+      int position = rowList_.first(whichRow);
+      if (position>=0) {
+        link.setRow(whichRow);
+        link.setPosition(position);
+        link.setColumn(elements_[position].column);
+        assert (whichRow==rowInTriple(elements_[position]));
+        link.setValue(elements_[position].value);
+      }
+    }
+  }
+  return link;
+}
+/* Returns last element in given row - index is -1 if none.
+   Index is given by .index and value by .value
+  */
+CoinModelLink 
+CoinModel::lastInRow(int whichRow) const
+{
+  CoinModelLink link;
+  if (whichRow>=0&&whichRow<numberRows_) {
+    link.setOnRow(true);
+    if (type_==0) {
+      assert (start_);
+      int position = start_[whichRow+1]-1;
+      if (position>=start_[whichRow]) {
+        link.setRow(whichRow);
+        link.setPosition(position);
+        link.setColumn(elements_[position].column);
+        assert (whichRow==rowInTriple(elements_[position]));
+        link.setValue(elements_[position].value);
+      }
+    } else {
+      fillList(whichRow,rowList_,1);
+      int position = rowList_.last(whichRow);
+      if (position>=0) {
+        link.setRow(whichRow);
+        link.setPosition(position);
+        link.setColumn(elements_[position].column);
+        assert (whichRow==rowInTriple(elements_[position]));
+        link.setValue(elements_[position].value);
+      }
+    }
+  }
+  return link;
+}
+/* Returns first element in given column - index is -1 if none.
+   Index is given by .index and value by .value
+*/
+CoinModelLink 
+CoinModel::firstInColumn(int whichColumn) const
+{
+  CoinModelLink link;
+  if (whichColumn>=0&&whichColumn<numberColumns_) {
+    link.setOnRow(false);
+    if (type_==1) {
+      assert (start_);
+      int position = start_[whichColumn];
+      if (position<start_[whichColumn+1]) {
+        link.setColumn(whichColumn);
+        link.setPosition(position);
+        link.setRow(rowInTriple(elements_[position]));
+        assert (whichColumn==static_cast<int> (elements_[position].column));
+        link.setValue(elements_[position].value);
+      }
+    } else {
+      fillList(whichColumn,columnList_,2);
+      if ((links_&2)==0) {
+        // Create list
+        assert (!columnList_.numberMajor());
+        createList(2);
+      }
+      int position = columnList_.first(whichColumn);
+      if (position>=0) {
+        link.setColumn(whichColumn);
+        link.setPosition(position);
+        link.setRow(rowInTriple(elements_[position]));
+        assert (whichColumn==static_cast<int> (elements_[position].column));
+        link.setValue(elements_[position].value);
+      }
+    }
+  }
+  return link;
+}
+/* Returns last element in given column - index is -1 if none.
+   Index is given by .index and value by .value
+*/
+CoinModelLink 
+CoinModel::lastInColumn(int whichColumn) const
+{
+  CoinModelLink link;
+  if (whichColumn>=0&&whichColumn<numberColumns_) {
+    link.setOnRow(false);
+    if (type_==1) {
+      assert (start_);
+      int position = start_[whichColumn+1]-1;
+      if (position>=start_[whichColumn]) {
+        link.setColumn(whichColumn);
+        link.setPosition(position);
+        link.setRow(rowInTriple(elements_[position]));
+        assert (whichColumn==static_cast<int> (elements_[position].column));
+        link.setValue(elements_[position].value);
+      }
+    } else {
+      fillList(whichColumn,columnList_,2);
+      int position = columnList_.last(whichColumn);
+      if (position>=0) {
+        link.setColumn(whichColumn);
+        link.setPosition(position);
+        link.setRow(rowInTriple(elements_[position]));
+        assert (whichColumn==static_cast<int> (elements_[position].column));
+        link.setValue(elements_[position].value);
+      }
+    }
+  }
+  return link;
+}
+/* Returns next element in current row or column - index is -1 if none.
+   Index is given by .index and value by .value.
+   User could also tell because input.next would be NULL
+*/
+CoinModelLink 
+CoinModel::next(CoinModelLink & current) const
+{
+  CoinModelLink link=current;
+  int position = current.position();
+  if (position>=0) {
+    if (current.onRow()) {
+      // Doing by row
+      int whichRow = current.row();
+      if (type_==0) {
+        assert (start_);
+        position++;
+        if (position<start_[whichRow+1]) {
+          link.setPosition(position);
+          link.setColumn(elements_[position].column);
+          assert (whichRow==rowInTriple(elements_[position]));
+          link.setValue(elements_[position].value);
+        } else {
+          // signal end
+          link.setPosition(-1);
+          link.setColumn(-1);
+          link.setRow(-1);
+          link.setValue(0.0);
+        }
+      } else {
+        assert ((links_&1)!=0);
+        position = rowList_.next()[position];
+        if (position>=0) {
+          link.setPosition(position);
+          link.setColumn(elements_[position].column);
+          assert (whichRow==rowInTriple(elements_[position]));
+          link.setValue(elements_[position].value);
+        } else {
+          // signal end
+          link.setPosition(-1);
+          link.setColumn(-1);
+          link.setRow(-1);
+          link.setValue(0.0);
+        }
+      }
+    } else {
+      // Doing by column
+      int whichColumn = current.column();
+      if (type_==1) {
+        assert (start_);
+        position++;
+        if (position<start_[whichColumn+1]) {
+          link.setPosition(position);
+          link.setRow(rowInTriple(elements_[position]));
+          assert (whichColumn==static_cast<int> (elements_[position].column));
+          link.setValue(elements_[position].value);
+        } else {
+          // signal end
+          link.setPosition(-1);
+          link.setColumn(-1);
+          link.setRow(-1);
+          link.setValue(0.0);
+        }
+      } else {
+        assert ((links_&2)!=0);
+        position = columnList_.next()[position];
+        if (position>=0) {
+          link.setPosition(position);
+          link.setRow(rowInTriple(elements_[position]));
+          assert (whichColumn==static_cast<int> (elements_[position].column));
+          link.setValue(elements_[position].value);
+        } else {
+          // signal end
+          link.setPosition(-1);
+          link.setColumn(-1);
+          link.setRow(-1);
+          link.setValue(0.0);
+        }
+      }
+    }
+  }
+  return link;
+}
+/* Returns previous element in current row or column - index is -1 if none.
+   Index is given by .index and value by .value.
+   User could also tell because input.previous would be NULL
+*/
+CoinModelLink 
+CoinModel::previous(CoinModelLink & current) const
+{
+  CoinModelLink link=current;
+  int position = current.position();
+  if (position>=0) {
+    if (current.onRow()) {
+      // Doing by row
+      int whichRow = current.row();
+      if (type_==0) {
+        assert (start_);
+        position--;
+        if (position>=start_[whichRow]) {
+          link.setPosition(position);
+          link.setColumn(elements_[position].column);
+          assert (whichRow==rowInTriple(elements_[position]));
+          link.setValue(elements_[position].value);
+        } else {
+          // signal end
+          link.setPosition(-1);
+          link.setColumn(-1);
+          link.setRow(-1);
+          link.setValue(0.0);
+        }
+      } else {
+        assert ((links_&1)!=0);
+        position = rowList_.previous()[position];
+        if (position>=0) {
+          link.setPosition(position);
+          link.setColumn(elements_[position].column);
+          assert (whichRow==rowInTriple(elements_[position]));
+          link.setValue(elements_[position].value);
+        } else {
+          // signal end
+          link.setPosition(-1);
+          link.setColumn(-1);
+          link.setRow(-1);
+          link.setValue(0.0);
+        }
+      }
+    } else {
+      // Doing by column
+      int whichColumn = current.column();
+      if (type_==1) {
+        assert (start_);
+        position--;
+        if (position>=start_[whichColumn]) {
+          link.setPosition(position);
+          link.setRow(rowInTriple(elements_[position]));
+          assert (whichColumn==static_cast<int> (elements_[position].column));
+          link.setValue(elements_[position].value);
+        } else {
+          // signal end
+          link.setPosition(-1);
+          link.setColumn(-1);
+          link.setRow(-1);
+          link.setValue(0.0);
+        }
+      } else {
+        assert ((links_&2)!=0);
+        position = columnList_.previous()[position];
+        if (position>=0) {
+          link.setPosition(position);
+          link.setRow(rowInTriple(elements_[position]));
+          assert (whichColumn==static_cast<int> (elements_[position].column));
+          link.setValue(elements_[position].value);
+        } else {
+          // signal end
+          link.setPosition(-1);
+          link.setColumn(-1);
+          link.setRow(-1);
+          link.setValue(0.0);
+        }
+      }
+    }
+  }
+  return link;
+}
+/* Returns first element in given quadratic column - index is -1 if none.
+   Index is given by .index and value by .value
+*/
+CoinModelLink 
+CoinModel::firstInQuadraticColumn(int ) const
+{
+  printf("not written yet\n");
+  abort();
+  CoinModelLink x;
+  return x;
+}
+/* Returns last element in given quadratic column - index is -1 if none.
+   Index is given by .index and value by .value
+*/
+CoinModelLink 
+CoinModel::lastInQuadraticColumn(int) const
+{
+  printf("not written yet\n");
+  abort();
+  CoinModelLink x;
+  return x;
+}
+/* Gets rowLower (if row does not exist then -COIN_DBL_MAX)
+ */
+double  
+CoinModel::getRowLower(int whichRow) const
+{
+  assert (whichRow>=0);
+  if (whichRow<numberRows_&&rowLower_)
+    return rowLower_[whichRow];
+  else
+    return -COIN_DBL_MAX;
+}
+/* Gets rowUpper (if row does not exist then +COIN_DBL_MAX)
+ */
+double  
+CoinModel::getRowUpper(int whichRow) const
+{
+  assert (whichRow>=0);
+  if (whichRow<numberRows_&&rowUpper_)
+    return rowUpper_[whichRow];
+  else
+    return COIN_DBL_MAX;
+}
+/* Gets name (if row does not exist then NULL)
+ */
+const char * 
+CoinModel::getRowName(int whichRow) const
+{
+  assert (whichRow>=0);
+  if (whichRow<rowName_.numberItems())
+    return rowName_.name(whichRow);
+  else
+    return NULL;
+}
+/* Gets columnLower (if column does not exist then 0.0)
+ */
+double  
+CoinModel::getColumnLower(int whichColumn) const
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_&&columnLower_)
+    return columnLower_[whichColumn];
+  else
+    return 0.0;
+}
+/* Gets columnUpper (if column does not exist then COIN_DBL_MAX)
+ */
+double  
+CoinModel::getColumnUpper(int whichColumn) const
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_&&columnUpper_)
+    return columnUpper_[whichColumn];
+  else
+    return COIN_DBL_MAX;
+}
+/* Gets columnObjective (if column does not exist then 0.0)
+ */
+double  
+CoinModel::getColumnObjective(int whichColumn) const
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_&&objective_)
+    return objective_[whichColumn];
+  else
+    return 0.0;
+}
+/* Gets name (if column does not exist then NULL)
+ */
+const char * 
+CoinModel::getColumnName(int whichColumn) const
+{
+  assert (whichColumn>=0);
+  if (whichColumn<columnName_.numberItems())
+    return columnName_.name(whichColumn);
+  else
+    return NULL;
+}
+/* Gets if integer (if column does not exist then false)
+ */
+bool 
+CoinModel::getColumnIsInteger(int whichColumn) const
+{
+  assert (whichColumn>=0);
+  if (whichColumn<numberColumns_&&integerType_)
+    return integerType_[whichColumn]!=0;
+  else
+    return false;
+}
+// Row index from row name (-1 if no names or no match)
+int 
+CoinModel::row(const char * rowName) const
+{
+  assert (!noNames_) ;
+  return rowName_.hash(rowName);
+}
+// Column index from column name (-1 if no names or no match)
+int 
+CoinModel::column(const char * columnName) const
+{
+  assert (!noNames_) ;
+  return columnName_.hash(columnName);
+}
+// Resize
+void 
+CoinModel::resize(int maximumRows, int maximumColumns, int maximumElements)
+{
+  maximumElements = CoinMax(maximumElements,maximumElements_);
+  if (type_==0||type_==2) {
+    // need to redo row stuff
+    maximumRows = CoinMax(maximumRows,numberRows_);
+    if (maximumRows>maximumRows_) {
+      bool needFill = rowLower_==NULL;
+      double * tempArray;
+      tempArray = new double[maximumRows];
+      CoinMemcpyN(rowLower_,numberRows_,tempArray);
+#     ifdef ZEROFAULT
+      memset(tempArray+numberRows_,0,(maximumRows-numberRows_)*sizeof(double)) ;
+#     endif
+      delete [] rowLower_;
+      rowLower_=tempArray;
+      tempArray = new double[maximumRows];
+      CoinMemcpyN(rowUpper_,numberRows_,tempArray);
+#     ifdef ZEROFAULT
+      memset(tempArray+numberRows_,0,(maximumRows-numberRows_)*sizeof(double)) ;
+#     endif
+      delete [] rowUpper_;
+      rowUpper_=tempArray;
+      int * tempArray2;
+      tempArray2 = new int[maximumRows];
+      CoinMemcpyN(rowType_,numberRows_,tempArray2);
+#     ifdef ZEROFAULT
+      memset(tempArray2+numberRows_,0,(maximumRows-numberRows_)*sizeof(int)) ;
+#     endif
+      delete [] rowType_;
+      rowType_=tempArray2;
+      // resize hash
+      if (!noNames_) 
+	rowName_.resize(maximumRows);
+      // If we have links we need to resize
+      if ((links_&1)!=0) {
+        rowList_.resize(maximumRows,maximumElements);
+      }
+      // If we have start then we need to resize that
+      if (type_==0) {
+        int * tempArray2;
+        tempArray2 = new int[maximumRows+1];
+#	ifdef ZEROFAULT
+	memset(tempArray2,0,(maximumRows+1)*sizeof(int)) ;
+#	endif
+        if (start_) {
+          CoinMemcpyN(start_,(numberRows_+1),tempArray2);
+          delete [] start_;
+        } else {
+          tempArray2[0]=0;
+        }
+        start_=tempArray2;
+      }
+      maximumRows_=maximumRows;
+      // Fill
+      if (needFill) {
+        int save=numberRows_-1;
+        numberRows_=0;
+        fillRows(save,true);
+      }
+    }
+  } else if (type_==3) {
+    badType();
+  }
+  if (type_==1||type_==2) {
+    // need to redo column stuff
+    maximumColumns = CoinMax(maximumColumns,numberColumns_);
+    if (maximumColumns>maximumColumns_) {
+      bool needFill = columnLower_==NULL;
+      double * tempArray;
+      tempArray = new double[maximumColumns];
+      CoinMemcpyN(columnLower_,numberColumns_,tempArray);
+#     ifdef ZEROFAULT
+      memset(tempArray+numberColumns_,0,
+	     (maximumColumns-numberColumns_)*sizeof(double)) ;
+#     endif
+      delete [] columnLower_;
+      columnLower_=tempArray;
+      tempArray = new double[maximumColumns];
+      CoinMemcpyN(columnUpper_,numberColumns_,tempArray);
+#     ifdef ZEROFAULT
+      memset(tempArray+numberColumns_,0,
+	     (maximumColumns-numberColumns_)*sizeof(double)) ;
+#     endif
+      delete [] columnUpper_;
+      columnUpper_=tempArray;
+      tempArray = new double[maximumColumns];
+      CoinMemcpyN(objective_,numberColumns_,tempArray);
+#     ifdef ZEROFAULT
+      memset(tempArray+numberColumns_,0,
+	     (maximumColumns-numberColumns_)*sizeof(double)) ;
+#     endif
+      delete [] objective_;
+      objective_=tempArray;
+      int * tempArray2;
+      tempArray2 = new int[maximumColumns];
+      CoinMemcpyN(columnType_,numberColumns_,tempArray2);
+#     ifdef ZEROFAULT
+      memset(tempArray2+numberColumns_,0,
+	     (maximumColumns-numberColumns_)*sizeof(int)) ;
+#     endif
+      delete [] columnType_;
+      columnType_=tempArray2;
+      tempArray2 = new int[maximumColumns];
+      CoinMemcpyN(integerType_,numberColumns_,tempArray2);
+#     ifdef ZEROFAULT
+      memset(tempArray2+numberColumns_,0,
+	     (maximumColumns-numberColumns_)*sizeof(int)) ;
+#     endif
+      delete [] integerType_;
+      integerType_=tempArray2;
+      // resize hash
+      if (!noNames_) 
+	columnName_.resize(maximumColumns);
+      // If we have links we need to resize
+      if ((links_&2)!=0) {
+        columnList_.resize(maximumColumns,maximumElements);
+      }
+      // If we have start then we need to resize that
+      if (type_==1) {
+        int * tempArray2;
+        tempArray2 = new int[maximumColumns+1];
+#       ifdef ZEROFAULT
+        memset(tempArray2,0,(maximumColumns+1)*sizeof(int)) ;
+#       endif
+        if (start_) {
+          CoinMemcpyN(start_,(numberColumns_+1),tempArray2);
+          delete [] start_;
+        } else {
+          tempArray2[0]=0;
+        }
+        start_=tempArray2;
+      }
+      maximumColumns_=maximumColumns;
+      // Fill
+      if (needFill) {
+        int save=numberColumns_-1;
+        numberColumns_=0;
+        fillColumns(save,true);
+      }
+    }
+  }
+  if (type_==3) 
+    badType();
+  if (maximumElements>maximumElements_) {
+    CoinModelTriple * tempArray = new CoinModelTriple[maximumElements];
+    CoinMemcpyN(elements_,numberElements_,tempArray);
+#   ifdef ZEROFAULT
+    memset(tempArray+numberElements_,0,
+	     (maximumElements-numberElements_)*sizeof(CoinModelTriple)) ;
+#   endif
+    delete [] elements_;
+    elements_=tempArray;
+    if (hashElements_.numberItems())
+      hashElements_.resize(maximumElements,elements_);
+    maximumElements_=maximumElements;
+    // If we have links we need to resize
+    if ((links_&1)!=0) {
+      rowList_.resize(maximumRows_,maximumElements_);
+    }
+    if ((links_&2)!=0) {
+      columnList_.resize(maximumColumns_,maximumElements_);
+    }
+  }
+}
+void
+CoinModel::fillRows(int whichRow, bool forceCreation,bool fromAddRow)
+{
+  if (forceCreation||fromAddRow) {
+    if (type_==-1) {
+      // initial
+      type_=0;
+      resize(CoinMax(100,whichRow+1),0,1000);
+    } else if (type_==1) {
+      type_=2;
+    }
+    if (!rowLower_) {
+      // need to set all
+      whichRow = numberRows_-1;
+      numberRows_=0;
+      if (type_!=3)
+	resize(CoinMax(100,whichRow+1),0,0);
+      else
+	resize(CoinMax(1,whichRow+1),0,0);
+    }
+    if (whichRow>=maximumRows_) {
+      if (type_!=3)
+      resize(CoinMax((3*maximumRows_)/2,whichRow+1),0,0);
+      else
+	resize(CoinMax(1,whichRow+1),0,0);
+    }
+  }
+  if (whichRow>=numberRows_&&rowLower_) {
+    // Need to fill
+    int i;
+    for ( i=numberRows_;i<=whichRow;i++) {
+      rowLower_[i]=-COIN_DBL_MAX;
+      rowUpper_[i]=COIN_DBL_MAX;
+      rowType_[i]=0;
+    }
+  }
+  if ( !fromAddRow) {
+    numberRows_=CoinMax(whichRow+1,numberRows_);
+    // If simple minded then delete start
+    if (start_) {
+      delete [] start_;
+      start_ = NULL;
+      assert (!links_);
+      // mixed - do linked lists for rows
+      createList(1);
+    }
+  }
+}
+void
+CoinModel::fillColumns(int whichColumn,bool forceCreation,bool fromAddColumn)
+{
+  if (forceCreation||fromAddColumn) {
+    if (type_==-1) {
+      // initial
+      type_=1;
+      resize(0,CoinMax(100,whichColumn+1),1000);
+    } else if (type_==0) {
+      type_=2;
+    }
+    if (!objective_) {
+      // need to set all
+      whichColumn = numberColumns_-1;
+      numberColumns_=0;
+      if (type_!=3)
+	resize(0,CoinMax(100,whichColumn+1),0);
+      else
+	resize(0,CoinMax(1,whichColumn+1),0);
+    }
+    if (whichColumn>=maximumColumns_) {
+      if (type_!=3)
+	resize(0,CoinMax((3*maximumColumns_)/2,whichColumn+1),0);
+      else
+	resize(0,CoinMax(1,whichColumn+1),0);
+    }
+  }
+  if (whichColumn>=numberColumns_&&objective_) {
+    // Need to fill
+    int i;
+    for ( i=numberColumns_;i<=whichColumn;i++) {
+      columnLower_[i]=0.0;
+      columnUpper_[i]=COIN_DBL_MAX;
+      objective_[i]=0.0;
+      integerType_[i]=0;
+      columnType_[i]=0;
+    }
+  }
+  if ( !fromAddColumn) {
+    numberColumns_=CoinMax(whichColumn+1,numberColumns_);
+    // If simple minded then delete start
+    if (start_) {
+      delete [] start_;
+      start_ = NULL;
+      assert (!links_);
+      // mixed - do linked lists for columns
+      createList(2);
+    }
+  }
+}
+// Fill in default linked list information
+void 
+CoinModel::fillList(int which, CoinModelLinkedList & list, int type) const
+{
+  if ((links_&type)==0) {
+    // Create list
+    assert (!list.numberMajor());
+    if (type==1) {
+      list.create(maximumRows_,maximumElements_,numberRows_,numberColumns_,0,
+                  numberElements_,elements_);
+    } else {
+      list.create(maximumColumns_,maximumElements_,numberColumns_,numberRows_,1,
+                  numberElements_,elements_);
+    }
+    if (links_==1 && type== 2) {
+      columnList_.synchronize(rowList_);
+    } else if (links_==2 && type==1) {
+      rowList_.synchronize(columnList_);
+    }
+    links_ |= type;
+  }
+  int number = list.numberMajor();
+  if (which>=number) {
+    // may still need to extend list or fill it in
+    if (which>=list.maximumMajor()) {
+      list.resize((which*3)/2+100,list.maximumElements());
+    }
+    list.fill(number,which+1);
+  }
+}
+/* Gets sorted row - user must provide enough space 
+   (easiest is allocate number of columns).
+   Returns number of elements
+*/
+int CoinModel::getRow(int whichRow, int * column, double * element)
+{
+  if (!hashElements_.maximumItems()) {
+    // set up number of items
+    hashElements_.setNumberItems(numberElements_);
+    hashElements_.resize(maximumElements_,elements_);
+  }
+  assert (whichRow>=0);
+  int n=0;
+  if (whichRow<numberRows_) {
+    CoinModelLink triple=firstInRow(whichRow);
+    bool sorted=true;
+    int last=-1;
+    while (triple.column()>=0) {
+      int iColumn = triple.column();
+      assert (whichRow==triple.row());
+      if (iColumn<last)
+        sorted=false;
+      last=iColumn;
+      if (column)
+	column[n]=iColumn;
+      if (element)
+	element[n]=triple.value();
+      n++;
+      triple=next(triple);
+    }
+    if (!sorted) {
+      CoinSort_2(column,column+n,element);
+    }
+  }
+  return n;
+}
+/* Gets sorted column - user must provide enough space 
+   (easiest is allocate number of rows).
+   Returns number of elements
+*/
+int CoinModel::getColumn(int whichColumn, int * row, double * element)
+{
+  if (!hashElements_.maximumItems()) {
+    // set up number of items
+    hashElements_.setNumberItems(numberElements_);
+    hashElements_.resize(maximumElements_,elements_);
+  }
+  assert (whichColumn>=0);
+  int n=0;
+  if (whichColumn<numberColumns_) {
+    CoinModelLink triple=firstInColumn(whichColumn);
+    bool sorted=true;
+    int last=-1;
+    while (triple.column()>=0) {
+      int iRow = triple.row();
+      assert (whichColumn==triple.column());
+      if (iRow<last)
+        sorted=false;
+      last=iRow;
+      if (row)
+	row[n]=iRow;
+      if (element)
+	element[n]=triple.value();
+      n++;
+      triple=next(triple);
+    }
+    if (!sorted) {
+      CoinSort_2(row,row+n,element);
+    }
+  }
+  return n;
+}
+/* Create a linked list and synchronize free 
+   type 1 for row 2 for column
+   Marked as const as list is mutable */
+void 
+CoinModel::createList(int type) const
+{
+  type_=2;
+  if (type==1) {
+    assert ((links_&1)==0);
+    rowList_.create(maximumRows_,maximumElements_,
+                    numberRows_,numberColumns_,0,
+                    numberElements_,elements_);
+    if (links_==2) {
+      // synchronize free list
+      rowList_.synchronize(columnList_);
+    }
+    links_ |= 1;
+  } else {
+    assert ((links_&2)==0);
+    columnList_.create(maximumColumns_,maximumElements_,
+                       numberColumns_,numberRows_,1,
+                       numberElements_,elements_);
+    if (links_==1) {
+      // synchronize free list
+      columnList_.synchronize(rowList_);
+    }
+    links_ |= 2;
+  }
+}
+// Checks that links are consistent
+void 
+CoinModel::validateLinks() const
+{
+  if ((links_&1)) {
+    // validate row links
+    rowList_.validateLinks(elements_);
+  }
+  if ((links_&2)) {
+    // validate column links
+    columnList_.validateLinks(elements_);
+  }
+}
+// returns jColumn (-2 if linear term, -1 if unknown) and coefficient
+int 
+CoinModel::decodeBit(char * phrase, char * & nextPhrase, double & coefficient, bool ifFirst) const
+{
+  char * pos = phrase;
+  // may be leading - (or +)
+  char * pos2 = pos;
+  double value=1.0;
+  if (*pos2=='-'||*pos2=='+')
+    pos2++;
+  // next terminator * or + or -
+  while (*pos2) {
+    if (*pos2=='*') {
+      break;
+    } else if (*pos2=='-'||*pos2=='+') {
+      if (pos2==pos||*(pos2-1)!='e')
+	break;
+    }
+    pos2++;
+  }
+  // if * must be number otherwise must be name
+  if (*pos2=='*') {
+    char * pos3 = pos;
+    while (pos3!=pos2) {
+#ifndef NDEBUG
+      char x = *pos3;
+#endif
+      pos3++;
+      assert ((x>='0'&&x<='9')||x=='.'||x=='+'||x=='-'||x=='e');
+    }
+    char saved = *pos2;
+    *pos2='\0';
+    value = atof(pos);
+    *pos2=saved;
+    // and down to next
+    pos2++;
+    pos=pos2;
+    while (*pos2) {
+      if (*pos2=='-'||*pos2=='+')
+	break;
+      pos2++;
+    }
+  }
+  char saved = *pos2;
+  *pos2='\0';
+  // now name
+  // might have + or -
+  if (*pos=='+') {
+    pos++;
+  } else if (*pos=='-') {
+    pos++;
+    assert (value==1.0);
+    value = - value;
+  }
+  int jColumn = column(pos);
+  // must be column unless first when may be linear term
+  if (jColumn<0) {
+    if (ifFirst) {
+      char * pos3 = pos;
+      while (pos3!=pos2) {
+#ifndef NDEBUG
+	char x = *pos3;
+#endif
+	pos3++;
+	assert ((x>='0'&&x<='9')||x=='.'||x=='+'||x=='-'||x=='e');
+      }
+      assert(*pos2=='\0');
+      // keep possible -
+      value = value * atof(pos);
+      jColumn=-2;
+    } else {
+      // bad
+      *pos2=saved;
+      printf("bad nonlinear term %s\n",phrase);
+      // maybe return -1 
+      abort();
+    }
+  }
+  *pos2=saved;
+  pos=pos2;
+  coefficient=value;
+  nextPhrase = pos;
+  return jColumn;
+}
+/* Gets correct form for a quadratic row - user to delete
+   If row is not quadratic then returns which other variables are involved
+   with tiny elements and count of total number of variables which could not
+   be put in quadratic form
+*/
+CoinPackedMatrix * 
+CoinModel::quadraticRow(int rowNumber,double * linearRow,
+			int & numberBad) const
+{
+  numberBad=0;
+  CoinZeroN(linearRow,numberColumns_);
+  int numberElements=0;
+  assert (rowNumber>=-1&&rowNumber<numberRows_);
+  if (rowNumber!=-1) {
+    // not objective 
+    CoinModelLink triple=firstInRow(rowNumber);
+    while (triple.column()>=0) {
+      int iColumn = triple.column();
+      const char * expr = getElementAsString(rowNumber,iColumn);
+      if (strcmp(expr,"Numeric")) {
+	// try and see which columns
+	assert (strlen(expr)<20000);
+	char temp[20000];
+	strcpy(temp,expr);
+	char * pos = temp;
+	bool ifFirst=true;
+	while (*pos) {
+	  double value;
+	  int jColumn = decodeBit(pos, pos, value, ifFirst);
+	  // must be column unless first when may be linear term
+	  if (jColumn>=0) {
+	    numberElements++;
+	  } else if (jColumn==-2) {
+	    linearRow[iColumn]=value;
+	  } else if (jColumn==-1) {
+	    // nonlinear term - we will just be marking
+	    numberElements++;
+	  } else {
+	    printf("bad nonlinear term %s\n",temp);
+	    abort();
+	  }
+	  ifFirst=false;
+	}
+      } else {
+	linearRow[iColumn]=getElement(rowNumber,iColumn);
+      }
+      triple=next(triple);
+    }
+    if (!numberElements) {
+      return NULL;
+    } else {
+      int * column = new int[numberElements];
+      int * column2 = new int[numberElements];
+      double * element = new double[numberElements];
+      numberElements=0;
+      CoinModelLink triple=firstInRow(rowNumber);
+      while (triple.column()>=0) {
+	int iColumn = triple.column();
+	const char * expr = getElementAsString(rowNumber,iColumn);
+	if (strcmp(expr,"Numeric")) {
+	  // try and see which columns
+	  assert (strlen(expr)<20000);
+	  char temp[20000];
+	  strcpy(temp,expr);
+	  char * pos = temp;
+	  bool ifFirst=true;
+	  while (*pos) {
+	    double value;
+	    int jColumn = decodeBit(pos, pos, value, ifFirst);
+	    // must be column unless first when may be linear term
+	    if (jColumn>=0) {
+	      column[numberElements]=iColumn;
+	      column2[numberElements]=jColumn;
+	      element[numberElements++]=value;
+	    } else if (jColumn==-1) {
+	      // nonlinear term - we will just be marking
+	      assert (jColumn>=0);
+	      column[numberElements]=iColumn;
+	      column2[numberElements]=jColumn;
+	      element[numberElements++]=1.0e-100;
+	      numberBad++;
+	    } else if (jColumn!=-2) {
+	      printf("bad nonlinear term %s\n",temp);
+	      abort();
+	    }
+	    ifFirst=false;
+	  }
+	}
+	triple=next(triple);
+      }
+      CoinPackedMatrix * newMatrix = new CoinPackedMatrix(true,column2,column,element,numberElements);
+      delete [] column;
+      delete [] column2;
+      delete [] element;
+      return newMatrix;
+    }
+  } else {
+    // objective
+    int iColumn;
+    for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+      const char * expr = getColumnObjectiveAsString(iColumn);
+      if (strcmp(expr,"Numeric")) {
+	// try and see which columns
+	assert (strlen(expr)<20000);
+	char temp[20000];
+	strcpy(temp,expr);
+	char * pos = temp;
+	bool ifFirst=true;
+	while (*pos) {
+	  double value;
+	  int jColumn = decodeBit(pos, pos, value, ifFirst);
+	  // must be column unless first when may be linear term
+	  if (jColumn>=0) {
+	    numberElements++;
+	  } else if (jColumn==-2) {
+	    linearRow[iColumn]=value;
+	  } else if (jColumn==-1) {
+	    // nonlinear term - we will just be marking
+	    numberElements++;
+	  } else {
+	    printf("bad nonlinear term %s\n",temp);
+	    abort();
+	  }
+	  ifFirst=false;
+	}
+      } else {
+	linearRow[iColumn]=getElement(rowNumber,iColumn);
+      }
+    }
+    if (!numberElements) {
+      return NULL;
+    } else {
+      int * column = new int[numberElements];
+      int * column2 = new int[numberElements];
+      double * element = new double[numberElements];
+      numberElements=0;
+      for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+	const char * expr = getColumnObjectiveAsString(iColumn);
+	if (strcmp(expr,"Numeric")) {
+	  // try and see which columns
+	  assert (strlen(expr)<20000);
+	  char temp[20000];
+	  strcpy(temp,expr);
+	  char * pos = temp;
+	  bool ifFirst=true;
+	  while (*pos) {
+	    double value;
+	    int jColumn = decodeBit(pos, pos, value, ifFirst);
+	    // must be column unless first when may be linear term
+	    if (jColumn>=0) {
+	      column[numberElements]=iColumn;
+	      column2[numberElements]=jColumn;
+	      element[numberElements++]=value;
+	    } else if (jColumn==-1) {
+	      // nonlinear term - we will just be marking
+	      assert (jColumn>=0);
+	      column[numberElements]=iColumn;
+	      column2[numberElements]=jColumn;
+	      element[numberElements++]=1.0e-100;
+	      numberBad++;
+	    } else if (jColumn!=-2) {
+	      printf("bad nonlinear term %s\n",temp);
+	      abort();
+	    }
+	    ifFirst=false;
+	  }
+	}
+      }
+      return new CoinPackedMatrix(true,column2,column,element,numberElements);
+    }
+  }
+}
+// Replaces a quadratic row
+void 
+CoinModel::replaceQuadraticRow(int rowNumber,const double * linearRow, const CoinPackedMatrix * quadraticPart)
+{
+  assert (rowNumber>=-1&&rowNumber<numberRows_);
+  if (rowNumber>=0) {
+    CoinModelLink triple=firstInRow(rowNumber);
+    while (triple.column()>=0) {
+      int iColumn = triple.column();
+      deleteElement(rowNumber,iColumn);
+      // triple stale - so start over
+      triple=firstInRow(rowNumber);
+    }
+    const double * element = quadraticPart->getElements();
+    const int * column = quadraticPart->getIndices();
+    const CoinBigIndex * columnStart = quadraticPart->getVectorStarts();
+    const int * columnLength = quadraticPart->getVectorLengths();
+    int numberLook = quadraticPart->getNumCols();
+    int i;
+    for (i=0;i<numberLook;i++) {
+      if (!columnLength[i]) {
+	// just linear part
+	if (linearRow[i])
+	  setElement(rowNumber,i,linearRow[i]);
+      } else {
+	char temp[10000];
+	int put=0;
+	char temp2[30];
+	bool first=true;
+	if (linearRow[i]) {
+	  sprintf(temp,"%g",linearRow[i]);
+	  first=false;
+          /* temp is at most 10000 long, so static_cast is safe */
+	  put = static_cast<int>(strlen(temp));
+	}
+	for (int j=columnStart[i];j<columnStart[i]+columnLength[i];j++) {
+	  int jColumn = column[j];
+	  double value = element[j];
+	  if (value<0.0||first) 
+	    sprintf(temp2,"%g*c%7.7d",value,jColumn);
+	  else
+	    sprintf(temp2,"+%g*c%7.7d",value,jColumn);
+	  int nextPut = put + static_cast<int>(strlen(temp2));
+	  assert (nextPut<10000);
+	  strcpy(temp+put,temp2);
+	  put = nextPut;
+	}
+	setElement(rowNumber,i,temp);
+      }
+    }
+    // rest of linear
+    for (;i<numberColumns_;i++) {
+      if (linearRow[i])
+	setElement(rowNumber,i,linearRow[i]);
+    }
+  } else {
+    // objective
+    int iColumn;
+    for (iColumn=0;iColumn<numberColumns_;iColumn++) {
+      setColumnObjective(iColumn,0.0);
+    }
+    const double * element = quadraticPart->getElements();
+    const int * column = quadraticPart->getIndices();
+    const CoinBigIndex * columnStart = quadraticPart->getVectorStarts();
+    const int * columnLength = quadraticPart->getVectorLengths();
+    int numberLook = quadraticPart->getNumCols();
+    int i;
+    for (i=0;i<numberLook;i++) {
+      if (!columnLength[i]) {
+	// just linear part
+	if (linearRow[i])
+	  setColumnObjective(i,linearRow[i]);
+      } else {
+	char temp[10000];
+	int put=0;
+	char temp2[30];
+	bool first=true;
+	if (linearRow[i]) {
+	  sprintf(temp,"%g",linearRow[i]);
+	  first=false;
+          /* temp is at most 10000 long, so static_cast is safe */
+	  put = static_cast<int>(strlen(temp));
+	}
+	for (int j=columnStart[i];j<columnStart[i]+columnLength[i];j++) {
+	  int jColumn = column[j];
+	  double value = element[j];
+	  if (value<0.0||first) 
+	    sprintf(temp2,"%g*c%7.7d",value,jColumn);
+	  else
+	    sprintf(temp2,"+%g*c%7.7d",value,jColumn);
+	  int nextPut = put + static_cast<int>(strlen(temp2));
+	  assert (nextPut<10000);
+	  strcpy(temp+put,temp2);
+	  put = nextPut;
+	}
+	setColumnObjective(i,temp);
+      }
+    }
+    // rest of linear
+    for (;i<numberColumns_;i++) {
+      if (linearRow[i])
+	setColumnObjective(i,linearRow[i]);
+    }
+  }
+}
+/* If possible return a model where if all variables marked nonzero are fixed
+      the problem will be linear.  At present may only work if quadratic.
+      Returns NULL if not possible
+*/
+CoinModel * 
+CoinModel::reorder(const char * mark) const
+{
+  // redo array so 2 high priority nonlinear, 1 nonlinear, 0 linear
+  char * highPriority = new char [numberColumns_];
+  double * linear = new double[numberColumns_];
+  CoinModel * newModel = new CoinModel(*this);
+  int iRow;
+  for (iRow=-1;iRow<numberRows_;iRow++) {
+    int numberBad;
+    CoinPackedMatrix * row = quadraticRow(iRow,linear,numberBad);
+    assert (!numberBad); // fix later
+    if (row) {
+      // see if valid
+      //const double * element = row->getElements();
+      const int * column = row->getIndices();
+      const CoinBigIndex * columnStart = row->getVectorStarts();
+      const int * columnLength = row->getVectorLengths();
+      int numberLook = row->getNumCols();
+      for (int i=0;i<numberLook;i++) {
+	if (mark[i])
+	  highPriority[i]=2;
+	else
+	  highPriority[i]=1;
+	for (int j=columnStart[i];j<columnStart[i]+columnLength[i];j++) {
+	  int iColumn = column[j];
+	  if (mark[iColumn])
+	    highPriority[iColumn]=2;
+	  else
+	    highPriority[iColumn]=1;
+	}
+      }
+      delete row;
+    }
+  }
+  for (iRow=-1;iRow<numberRows_;iRow++) {
+    int numberBad;
+    CoinPackedMatrix * row = quadraticRow(iRow,linear,numberBad);
+    if (row) {
+      // see if valid
+      const double * element = row->getElements();
+      const int * columnLow = row->getIndices();
+      const CoinBigIndex * columnHigh = row->getVectorStarts();
+      const int * columnLength = row->getVectorLengths();
+      int numberLook = row->getNumCols();
+      int canSwap=0;
+      for (int i=0;i<numberLook;i++) {
+	// this one needs to be available
+	int iPriority = highPriority[i];
+	for (int j=columnHigh[i];j<columnHigh[i]+columnLength[i];j++) {
+	  int iColumn = columnLow[j];
+	  if (highPriority[iColumn]<=1) {
+	    assert (highPriority[iColumn]==1);
+	    if (iPriority==1) {
+	      canSwap=-1; // no good
+	      break;
+	    } else {
+	      canSwap=1;
+	    }
+	  }
+	}
+      }
+      if (canSwap) {
+	if (canSwap>0) {
+	  // rewrite row
+	  /* get triples
+	     then swap ones needed
+	     then create packedmatrix
+	     then replace row
+	  */
+	  int numberElements=columnHigh[numberLook];
+	  int * columnHigh2 = new int [numberElements];
+	  int * columnLow2 = new int [numberElements];
+	  double * element2 = new double [numberElements];
+	  for (int i=0;i<numberLook;i++) {
+	    // this one needs to be available
+	    int iPriority = highPriority[i];
+	    if (iPriority==2) {
+	      for (int j=columnHigh[i];j<columnHigh[i]+columnLength[i];j++) {
+		columnHigh2[j]=i;
+		columnLow2[j]=columnLow[j];
+		element2[j]=element[j];
+	      }
+	    } else {
+	      for (int j=columnHigh[i];j<columnHigh[i]+columnLength[i];j++) {
+		columnLow2[j]=i;
+		columnHigh2[j]=columnLow[j];
+		element2[j]=element[j];
+	      }
+	    }
+	  }
+	  delete row;
+	  row = new CoinPackedMatrix(true,columnHigh2,columnLow2,element2,numberElements);
+	  delete [] columnHigh2;
+	  delete [] columnLow2;
+	  delete [] element2;
+	  // Now replace row
+	  newModel->replaceQuadraticRow(iRow,linear,row);
+	  delete row;
+	} else {
+	  delete row;
+	  delete newModel;
+	  newModel=NULL;
+	  printf("Unable to use priority - row %d\n",iRow);
+	  break;
+	}
+      }
+    }
+  }
+  delete [] highPriority;
+  delete [] linear;
+  return newModel;
+}
+// Sets cut marker array
+void 
+CoinModel::setCutMarker(int size,const int * marker)
+{
+  delete [] cut_;
+  cut_ = new int [maximumRows_];
+  CoinZeroN(cut_,maximumRows_);
+  CoinMemcpyN(marker,size,cut_);
+}
+// Sets priority array
+void 
+CoinModel::setPriorities(int size,const int * priorities)
+{
+  delete [] priority_;
+  priority_ = new int [maximumColumns_];
+  CoinZeroN(priority_,maximumColumns_);
+  CoinMemcpyN(priorities,size,priority_);
+}
+/* Sets columnObjective array
+ */
+void 
+CoinModel::setObjective(int numberColumns,const double * objective) 
+{
+  fillColumns(numberColumns,true,true);
+  for (int i=0;i<numberColumns;i++) {
+    objective_[i]=objective[i];
+    columnType_[i] &= ~4;
+  }
+}
+/* Sets columnLower array
+ */
+void 
+CoinModel::setColumnLower(int numberColumns,const double * columnLower)
+{
+  fillColumns(numberColumns,true,true);
+  for (int i=0;i<numberColumns;i++) {
+    columnLower_[i]=columnLower[i];
+    columnType_[i] &= ~1;
+  }
+}
+/* Sets columnUpper array
+ */
+void 
+CoinModel::setColumnUpper(int numberColumns,const double * columnUpper)
+{
+  fillColumns(numberColumns,true,true);
+  for (int i=0;i<numberColumns;i++) {
+    columnUpper_[i]=columnUpper[i];
+    columnType_[i] &= ~2;
+  }
+}
+/* Sets rowLower array
+ */
+void 
+CoinModel::setRowLower(int numberRows,const double * rowLower)
+{
+  fillColumns(numberRows,true,true);
+  for (int i=0;i<numberRows;i++) {
+    rowLower_[i]=rowLower[i];
+    rowType_[i] &= ~1;
+  }
+}
+/* Sets rowUpper array
+ */
+void 
+CoinModel::setRowUpper(int numberRows,const double * rowUpper)
+{
+  fillColumns(numberRows,true,true);
+  for (int i=0;i<numberRows;i++) {
+    rowUpper_[i]=rowUpper[i];
+    rowType_[i] &= ~2;
+  }
+}
+// Pass in CoinPackedMatrix (and switch off element updates)
+void 
+CoinModel::passInMatrix(const CoinPackedMatrix & matrix)
+{
+  type_=3;
+  packedMatrix_ = new CoinPackedMatrix(matrix);
+}
+// Convert elements to CoinPackedMatrix (and switch off element updates)
+int 
+CoinModel::convertMatrix()
+{
+  int numberErrors=0;
+  if (type_!=3) {
+    // If strings then do copies
+    if (string_.numberItems()) {
+      numberErrors = createArrays(rowLower_, rowUpper_, 
+				  columnLower_, columnUpper_,
+				  objective_, integerType_,associated_);
+    }
+    CoinPackedMatrix matrix;
+    createPackedMatrix(matrix,associated_);
+    packedMatrix_ = new CoinPackedMatrix(matrix);
+    type_=3;
+  }
+  return numberErrors;
+}
+// Aborts with message about packedMatrix
+void 
+CoinModel::badType() const
+{
+  fprintf(stderr,"******** operation not allowed when in block mode ****\n");
+  abort();
+}
+
+//#############################################################################
+// Methods to input a problem
+//#############################################################################
+/** A function to convert from the lb/ub style of constraint
+    definition to the sense/rhs/range style */
+void
+convertBoundToSense(const double lower, const double upper,
+					char& sense, double& right,
+					double& range) 
+{
+  double inf = 1.0e-30;
+  range = 0.0;
+  if (lower > -inf) {
+    if (upper < inf) {
+      right = upper;
+      if (upper==lower) {
+        sense = 'E';
+      } else {
+        sense = 'R';
+        range = upper - lower;
+      }
+    } else {
+      sense = 'G';
+      right = lower;
+    }
+  } else {
+    if (upper < inf) {
+      sense = 'L';
+      right = upper;
+    } else {
+      sense = 'N';
+      right = 0.0;
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+/** A function to convert from the sense/rhs/range style of
+    constraint definition to the lb/ub style */
+void
+convertSenseToBound(const char sense, const double right,
+					const double range,
+					double& lower, double& upper) 
+{
+  double inf=COIN_DBL_MAX;
+  switch (sense) {
+  case 'E':
+    lower = upper = right;
+    break;
+  case 'L':
+    lower = -inf;
+    upper = right;
+    break;
+  case 'G':
+    lower = right;
+    upper = inf;
+    break;
+  case 'R':
+    lower = right - range;
+    upper = right;
+    break;
+  case 'N':
+    lower = -inf;
+    upper = inf;
+    break;
+  }
+}
+
+void
+CoinModel::loadBlock(const CoinPackedMatrix& matrix,
+				   const double* collb, const double* colub,   
+				   const double* obj,
+				   const double* rowlb, const double* rowub)
+{
+  passInMatrix(matrix);
+  int numberRows=matrix.getNumRows();
+  int numberColumns=matrix.getNumCols();
+  setObjective(numberColumns,obj);
+  setRowLower(numberRows,rowlb);
+  setRowUpper(numberRows,rowub);
+  setColumnLower(numberColumns,collb);
+  setColumnUpper(numberColumns,colub);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinModel::loadBlock(const CoinPackedMatrix& matrix,
+				   const double* collb, const double* colub,
+				   const double* obj,
+				   const char* rowsen, const double* rowrhs,   
+				   const double* rowrng)
+{
+  // If any of Rhs NULLs then create arrays
+  int numrows = matrix.getNumRows();
+  const char * rowsenUse = rowsen;
+  if (!rowsen) {
+    char * rowsen = new char [numrows];
+    for (int i=0;i<numrows;i++)
+      rowsen[i]='G';
+    rowsenUse = rowsen;
+  } 
+  const double * rowrhsUse = rowrhs;
+  if (!rowrhs) {
+    double * rowrhs = new double [numrows];
+    for (int i=0;i<numrows;i++)
+      rowrhs[i]=0.0;
+    rowrhsUse = rowrhs;
+  }
+  const double * rowrngUse = rowrng;
+  if (!rowrng) {
+    double * rowrng = new double [numrows];
+    for (int i=0;i<numrows;i++)
+      rowrng[i]=0.0;
+    rowrngUse = rowrng;
+  }
+  double * rowlb = new double[numrows];
+  double * rowub = new double[numrows];
+  for (int i = numrows-1; i >= 0; --i) {   
+    convertSenseToBound(rowsenUse[i],rowrhsUse[i],rowrngUse[i],rowlb[i],rowub[i]);
+  }
+  if (rowsen!=rowsenUse)
+    delete [] rowsenUse;
+  if (rowrhs!=rowrhsUse)
+    delete [] rowrhsUse;
+  if (rowrng!=rowrngUse)
+    delete [] rowrngUse;
+  loadBlock(matrix, collb, colub, obj, rowlb, rowub);
+  delete [] rowlb;
+  delete [] rowub;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinModel::loadBlock(const int numcols, const int numrows,
+		     const CoinBigIndex * start, const int* index,
+		     const double* value,
+		     const double* collb, const double* colub,
+		     const double* obj,
+		     const double* rowlb, const double* rowub)
+{
+  int numberElements = start[numcols];
+  int * length = new int [numcols];
+  for (int i=0;i<numcols;i++) 
+    length[i]=start[i+1]-start[i];
+  CoinPackedMatrix matrix(true,numrows,numcols,numberElements,value,
+			  index,start,length,0.0,0.0);
+  loadBlock(matrix, collb, colub, obj, rowlb, rowub);
+  delete [] length;
+}
+//-----------------------------------------------------------------------------
+
+void
+CoinModel::loadBlock(const int numcols, const int numrows,
+		     const CoinBigIndex * start, const int* index,
+		     const double* value,
+		     const double* collb, const double* colub,
+		     const double* obj,
+		     const char* rowsen, const double* rowrhs,   
+		     const double* rowrng)
+{
+  // If any of Rhs NULLs then create arrays
+  const char * rowsenUse = rowsen;
+  if (!rowsen) {
+    char * rowsen = new char [numrows];
+    for (int i=0;i<numrows;i++)
+      rowsen[i]='G';
+    rowsenUse = rowsen;
+  } 
+  const double * rowrhsUse = rowrhs;
+  if (!rowrhs) {
+    double * rowrhs = new double [numrows];
+    for (int i=0;i<numrows;i++)
+      rowrhs[i]=0.0;
+    rowrhsUse = rowrhs;
+  }
+  const double * rowrngUse = rowrng;
+  if (!rowrng) {
+    double * rowrng = new double [numrows];
+    for (int i=0;i<numrows;i++)
+      rowrng[i]=0.0;
+    rowrngUse = rowrng;
+  }
+  double * rowlb = new double[numrows];
+  double * rowub = new double[numrows];
+  for (int i = numrows-1; i >= 0; --i) {   
+    convertSenseToBound(rowsenUse[i],rowrhsUse[i],rowrngUse[i],rowlb[i],rowub[i]);
+  }
+  if (rowsen!=rowsenUse)
+    delete [] rowsenUse;
+  if (rowrhs!=rowrhsUse)
+    delete [] rowrhsUse;
+  if (rowrng!=rowrngUse)
+    delete [] rowrngUse;
+  int numberElements = start[numcols];
+  int * length = new int [numcols];
+  for (int i=0;i<numcols;i++) 
+    length[i]=start[i+1]-start[i];
+  CoinPackedMatrix matrix(true,numrows,numcols,numberElements,value,
+			  index,start,length,0.0,0.0);
+  loadBlock(matrix, collb, colub, obj, rowlb, rowub);
+  delete [] length;
+  delete[] rowlb;
+  delete[] rowub;
+}
+/* Returns which parts of model are set
+   1 - matrix
+   2 - rhs
+   4 - row names
+   8 - column bounds and/or objective
+   16 - column names
+   32 - integer types
+*/
+int 
+CoinModel::whatIsSet() const
+{
+  int type = (numberElements_) ? 1 : 0;
+  bool defaultValues=true;
+  if (rowLower_) {
+    for (int i=0;i<numberRows_;i++) {
+      if (rowLower_[i]!=-COIN_DBL_MAX) {
+	defaultValues=false;
+	break;
+      }
+      if (rowUpper_[i]!=COIN_DBL_MAX) {
+	defaultValues=false;
+	break;
+      }
+    }
+  }
+  if (!defaultValues)
+    type |= 2;
+  if (rowName_.numberItems())
+    type |= 4;
+  defaultValues=true;
+  if (columnLower_) {
+    for (int i=0;i<numberColumns_;i++) {
+      if (objective_[i]!=0.0) {
+	defaultValues=false;
+	break;
+      }
+      if (columnLower_[i]!=0.0) {
+	defaultValues=false;
+	break;
+      }
+      if (columnUpper_[i]!=COIN_DBL_MAX) {
+	defaultValues=false;
+	break;
+      }
+    }
+  }
+  if (!defaultValues)
+    type |= 8;
+  if (columnName_.numberItems())
+    type |= 16;
+  defaultValues=true;
+  if (integerType_) {
+    for (int i=0;i<numberColumns_;i++) {
+      if (integerType_[i]) {
+	defaultValues=false;
+	break;
+      }
+    }
+  }
+  if (!defaultValues)
+    type |= 32;
+  return type;
+}
+// For decomposition set original row and column indices
+void 
+CoinModel::setOriginalIndices(const int * row, const int * column)
+{
+  if (!rowType_)
+    rowType_ = new int [numberRows_];
+  memcpy(rowType_,row,numberRows_*sizeof(int));
+  if (!columnType_)
+    columnType_ = new int [numberColumns_];
+  memcpy(columnType_,column,numberColumns_*sizeof(int));
+}
diff --git a/cbits/coin/CoinModel.hpp b/cbits/coin/CoinModel.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinModel.hpp
@@ -0,0 +1,1045 @@
+/* $Id: CoinModel.hpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinModel_H
+#define CoinModel_H
+
+#include "CoinModelUseful.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinFinite.hpp"
+class CoinBaseModel {
+
+public:
+
+
+  /**@name Constructors, destructor */
+   //@{
+  /// Default Constructor 
+  CoinBaseModel ();
+
+  /// Copy constructor 
+  CoinBaseModel ( const CoinBaseModel &rhs);
+   
+  /// Assignment operator 
+  CoinBaseModel & operator=( const CoinBaseModel& rhs);
+
+  /// Clone
+  virtual CoinBaseModel * clone() const=0;
+
+  /// Destructor 
+  virtual ~CoinBaseModel () ;
+   //@}
+
+  /**@name For getting information */
+   //@{
+   /// Return number of rows
+  inline int numberRows() const
+  { return numberRows_;}
+   /// Return number of columns
+  inline int numberColumns() const
+  { return numberColumns_;}
+   /// Return number of elements
+  virtual CoinBigIndex numberElements() const = 0;
+  /** Returns the (constant) objective offset
+      This is the RHS entry for the objective row
+  */
+  inline double objectiveOffset() const
+  { return objectiveOffset_;}
+  /// Set objective offset
+  inline void setObjectiveOffset(double value)
+  { objectiveOffset_=value;}
+  /// Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+  inline double optimizationDirection() const {
+    return  optimizationDirection_;
+  }
+  /// Set direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+  inline void setOptimizationDirection(double value)
+  { optimizationDirection_=value;}
+  /// Get print level 0 - off, 1 - errors, 2 - more
+  inline int logLevel() const
+  { return logLevel_;}
+  /// Set print level 0 - off, 1 - errors, 2 - more
+  void setLogLevel(int value);
+  /// Return the problem name
+  inline const char * getProblemName() const
+  { return problemName_.c_str();}
+  /// Set problem name
+  void setProblemName(const char *name) ;
+  /// Set problem name
+  void setProblemName(const std::string &name) ;
+  /// Return the row block name
+  inline const std::string & getRowBlock() const
+  { return rowBlockName_;}
+  /// Set row block name
+  inline void setRowBlock(const std::string &name) 
+  { rowBlockName_ = name;}
+  /// Return the column block name
+  inline const std::string & getColumnBlock() const
+  { return columnBlockName_;}
+  /// Set column block name
+  inline void setColumnBlock(const std::string &name) 
+  { columnBlockName_ = name;}
+   //@}
+  
+protected:
+  /**@name Data members */
+   //@{
+  /// Current number of rows
+  int numberRows_;
+  /// Current number of columns
+  int numberColumns_;
+  /// Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+  double optimizationDirection_;
+  /// Objective offset to be passed on
+  double objectiveOffset_;
+  /// Problem name
+  std::string problemName_;
+  /// Rowblock name
+  std::string rowBlockName_;
+  /// Columnblock name
+  std::string columnBlockName_;
+  /** Print level.
+      I could have gone for full message handling but this should normally
+      be silent and lightweight.  I can always change.
+      0 - no output
+      1 - on errors
+      2 - more detailed
+  */
+  int logLevel_;
+   //@}
+  /// data
+
+};
+
+/** 
+    This is a simple minded model which is stored in a format which makes
+    it easier to construct and modify but not efficient for algorithms.  It has
+    to be passed across to ClpModel or OsiSolverInterface by addRows, addCol(umn)s
+    or loadProblem.
+
+    It may have up to four parts -
+    1) A matrix of doubles (or strings - see note A)
+    2) Column information including integer information and names
+    3) Row information including names
+    4) Quadratic objective (not implemented - but see A)
+
+    This class is meant to make it more efficient to build a model.  It is at
+    its most efficient when all additions are done as addRow or as addCol but
+    not mixed.  If only 1 and 2 exist then solver.addColumns may be used to pass to solver,
+    if only 1 and 3 exist then solver.addRows may be used.  Otherwise solver.loadProblem
+    must be used.
+
+    If addRows and addColumns are mixed or if individual elements are set then the
+    speed will drop to some extent and more memory will be used.
+
+    It is also possible to iterate over existing elements and to access columns and rows
+    by name.  Again each of these use memory and cpu time.  However memory is unlikely
+    to be critical as most algorithms will use much more.
+
+    Notes:
+    A)  Although this could be used to pass nonlinear information around the
+        only use at present is to have named values e.g. value1 which can then be
+        set to a value after model is created.  I have no idea whether that could
+        be useful but I thought it might be fun.
+	Quadratic terms are allowed in strings!  A solver could try and use this
+	if so - the convention is that 0.5* quadratic is stored
+	
+    B)  This class could be useful for modeling.
+*/
+
+class CoinModel : public CoinBaseModel {
+  
+public:
+  /**@name Useful methods for building model */
+   //@{
+   /** add a row -  numberInRow may be zero */
+   void addRow(int numberInRow, const int * columns,
+	       const double * elements, double rowLower=-COIN_DBL_MAX, 
+              double rowUpper=COIN_DBL_MAX, const char * name=NULL);
+  /// add a column - numberInColumn may be zero */
+   void addColumn(int numberInColumn, const int * rows,
+                  const double * elements, 
+                  double columnLower=0.0, 
+                  double columnUpper=COIN_DBL_MAX, double objectiveValue=0.0,
+                  const char * name=NULL, bool isInteger=false);
+  /// add a column - numberInColumn may be zero */
+  inline void addCol(int numberInColumn, const int * rows,
+                     const double * elements, 
+                     double columnLower=0.0, 
+                     double columnUpper=COIN_DBL_MAX, double objectiveValue=0.0,
+                     const char * name=NULL, bool isInteger=false)
+  { addColumn(numberInColumn, rows, elements, columnLower, columnUpper, objectiveValue,
+              name,isInteger);}
+  /// Sets value for row i and column j 
+  inline void operator() (int i,int j,double value) 
+  { setElement(i,j,value);}
+  /// Sets value for row i and column j 
+  void setElement(int i,int j,double value) ;
+  /** Gets sorted row - user must provide enough space 
+      (easiest is allocate number of columns).
+      If column or element NULL then just returns number
+      Returns number of elements
+  */
+  int getRow(int whichRow, int * column, double * element);
+  /** Gets sorted column - user must provide enough space 
+      (easiest is allocate number of rows).
+      If row or element NULL then just returns number
+      Returns number of elements
+  */
+  int getColumn(int whichColumn, int * column, double * element);
+  /// Sets quadratic value for column i and j 
+  void setQuadraticElement(int i,int j,double value) ;
+  /// Sets value for row i and column j as string
+  inline void operator() (int i,int j,const char * value) 
+  { setElement(i,j,value);}
+  /// Sets value for row i and column j as string
+  void setElement(int i,int j,const char * value) ;
+  /// Associates a string with a value.  Returns string id (or -1 if does not exist)
+  int associateElement(const char * stringValue, double value);
+  /** Sets rowLower (if row does not exist then
+      all rows up to this are defined with default values and no elements)
+  */
+  void setRowLower(int whichRow,double rowLower); 
+  /** Sets rowUpper (if row does not exist then
+      all rows up to this are defined with default values and no elements)
+  */
+  void setRowUpper(int whichRow,double rowUpper); 
+  /** Sets rowLower and rowUpper (if row does not exist then
+      all rows up to this are defined with default values and no elements)
+  */
+  void setRowBounds(int whichRow,double rowLower,double rowUpper); 
+  /** Sets name (if row does not exist then
+      all rows up to this are defined with default values and no elements)
+  */
+  void setRowName(int whichRow,const char * rowName); 
+  /** Sets columnLower (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnLower(int whichColumn,double columnLower); 
+  /** Sets columnUpper (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnUpper(int whichColumn,double columnUpper); 
+  /** Sets columnLower and columnUpper (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnBounds(int whichColumn,double columnLower,double columnUpper); 
+  /** Sets columnObjective (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnObjective(int whichColumn,double columnObjective); 
+  /** Sets name (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnName(int whichColumn,const char * columnName); 
+  /** Sets integer state (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnIsInteger(int whichColumn,bool columnIsInteger); 
+  /** Sets columnObjective (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setObjective(int whichColumn,double columnObjective) 
+  { setColumnObjective( whichColumn, columnObjective);} 
+  /** Sets integer state (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setIsInteger(int whichColumn,bool columnIsInteger) 
+  { setColumnIsInteger( whichColumn, columnIsInteger);} 
+  /** Sets integer (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setInteger(int whichColumn) 
+  { setColumnIsInteger( whichColumn, true);} 
+  /** Sets continuous (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setContinuous(int whichColumn) 
+  { setColumnIsInteger( whichColumn, false);} 
+  /** Sets columnLower (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setColLower(int whichColumn,double columnLower) 
+  { setColumnLower( whichColumn, columnLower);} 
+  /** Sets columnUpper (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setColUpper(int whichColumn,double columnUpper) 
+  { setColumnUpper( whichColumn, columnUpper);} 
+  /** Sets columnLower and columnUpper (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setColBounds(int whichColumn,double columnLower,double columnUpper) 
+  { setColumnBounds( whichColumn, columnLower, columnUpper);} 
+  /** Sets columnObjective (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setColObjective(int whichColumn,double columnObjective) 
+  { setColumnObjective( whichColumn, columnObjective);} 
+  /** Sets name (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setColName(int whichColumn,const char * columnName) 
+  { setColumnName( whichColumn, columnName);} 
+  /** Sets integer (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setColIsInteger(int whichColumn,bool columnIsInteger) 
+  { setColumnIsInteger( whichColumn, columnIsInteger);} 
+  /** Sets rowLower (if row does not exist then
+      all rows up to this are defined with default values and no elements)
+  */
+  void setRowLower(int whichRow,const char * rowLower); 
+  /** Sets rowUpper (if row does not exist then
+      all rows up to this are defined with default values and no elements)
+  */
+  void setRowUpper(int whichRow,const char * rowUpper); 
+  /** Sets columnLower (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnLower(int whichColumn,const char * columnLower); 
+  /** Sets columnUpper (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnUpper(int whichColumn,const char * columnUpper); 
+  /** Sets columnObjective (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnObjective(int whichColumn,const char * columnObjective); 
+  /** Sets integer (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  void setColumnIsInteger(int whichColumn,const char * columnIsInteger); 
+  /** Sets columnObjective (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setObjective(int whichColumn,const char * columnObjective) 
+  { setColumnObjective( whichColumn, columnObjective);} 
+  /** Sets integer (if column does not exist then
+      all columns up to this are defined with default values and no elements)
+  */
+  inline void setIsInteger(int whichColumn,const char * columnIsInteger) 
+  { setColumnIsInteger( whichColumn, columnIsInteger);} 
+  /** Deletes all entries in row and bounds.  Will be ignored by
+      writeMps etc and will be packed down if asked for. */
+  void deleteRow(int whichRow);
+  /** Deletes all entries in column and bounds and objective.  Will be ignored by
+      writeMps etc and will be packed down if asked for. */
+  void deleteColumn(int whichColumn);
+  /** Deletes all entries in column and bounds.  If last column the number of columns
+      will be decremented and true returned.  */
+  inline void deleteCol(int whichColumn)
+  { deleteColumn(whichColumn);}
+  /// Takes element out of matrix - returning position (<0 if not there);
+  int deleteElement(int row, int column);
+  /// Takes element out of matrix when position known
+  void deleteThisElement(int row, int column,int position);
+  /** Packs down all rows i.e. removes empty rows permanently.  Empty rows
+      have no elements and feasible bounds. returns number of rows deleted. */
+  int packRows();
+  /** Packs down all columns i.e. removes empty columns permanently.  Empty columns
+      have no elements and no objective. returns number of columns deleted. */
+  int packColumns();
+  /** Packs down all columns i.e. removes empty columns permanently.  Empty columns
+      have no elements and no objective. returns number of columns deleted. */
+  inline int packCols()
+  { return packColumns();}
+  /** Packs down all rows and columns.  i.e. removes empty rows and columns permanently.
+      Empty rows have no elements and feasible bounds.
+      Empty columns have no elements and no objective.
+      returns number of rows+columns deleted. */
+  int pack();
+
+  /** Sets columnObjective array
+  */
+  void setObjective(int numberColumns,const double * objective) ;
+  /** Sets columnLower array
+  */
+  void setColumnLower(int numberColumns,const double * columnLower);
+  /** Sets columnLower array
+  */
+  inline void setColLower(int numberColumns,const double * columnLower)
+  { setColumnLower( numberColumns, columnLower);} 
+  /** Sets columnUpper array
+  */
+  void setColumnUpper(int numberColumns,const double * columnUpper);
+  /** Sets columnUpper array
+  */
+  inline void setColUpper(int numberColumns,const double * columnUpper)
+  { setColumnUpper( numberColumns, columnUpper);} 
+  /** Sets rowLower array
+  */
+  void setRowLower(int numberRows,const double * rowLower);
+  /** Sets rowUpper array
+  */
+  void setRowUpper(int numberRows,const double * rowUpper);
+
+  /** Write the problem in MPS format to a file with the given filename.
+      
+  \param compression can be set to three values to indicate what kind
+  of file should be written
+  <ul>
+  <li> 0: plain text (default)
+  <li> 1: gzip compressed (.gz is appended to \c filename)
+  <li> 2: bzip2 compressed (.bz2 is appended to \c filename) (TODO)
+  </ul>
+  If the library was not compiled with the requested compression then
+  writeMps falls back to writing a plain text file.
+  
+  \param formatType specifies the precision to used for values in the
+  MPS file
+  <ul>
+  <li> 0: normal precision (default)
+  <li> 1: extra accuracy
+  <li> 2: IEEE hex
+  </ul>
+  
+  \param numberAcross specifies whether 1 or 2 (default) values should be
+  specified on every data line in the MPS file.
+  
+  not const as may change model e.g. fill in default bounds
+  */
+  int writeMps(const char *filename, int compression = 0,
+               int formatType = 0, int numberAcross = 2, bool keepStrings=false) ;
+  
+  /** Check two models against each other.  Return nonzero if different.
+      Ignore names if that set.
+      May modify both models by cleaning up
+  */
+  int differentModel(CoinModel & other, bool ignoreNames);
+   //@}
+
+
+  /**@name For structured models */
+   //@{
+  /// Pass in CoinPackedMatrix (and switch off element updates)
+  void passInMatrix(const CoinPackedMatrix & matrix);
+  /** Convert elements to CoinPackedMatrix (and switch off element updates).
+      Returns number of errors */
+  int convertMatrix();
+  /// Return a pointer to CoinPackedMatrix (or NULL)
+  inline const CoinPackedMatrix * packedMatrix() const
+  { return packedMatrix_;}
+  /// Return pointers to original rows (for decomposition)
+  inline const int * originalRows() const
+  { return rowType_;}
+  /// Return pointers to original columns (for decomposition)
+  inline const int * originalColumns() const
+  { return columnType_;}
+   //@}
+
+
+  /**@name For getting information */
+   //@{
+   /// Return number of elements
+  inline CoinBigIndex numberElements() const
+  { return numberElements_;}
+   /// Return  elements as triples
+  inline const CoinModelTriple * elements() const
+  { return elements_;}
+  /// Returns value for row i and column j
+  inline double operator() (int i,int j) const
+  { return getElement(i,j);}
+  /// Returns value for row i and column j
+  double getElement(int i,int j) const;
+  /// Returns value for row rowName and column columnName
+  inline double operator() (const char * rowName,const char * columnName) const
+  { return getElement(rowName,columnName);}
+  /// Returns value for row rowName and column columnName
+  double getElement(const char * rowName,const char * columnName) const;
+  /// Returns quadratic value for columns i and j
+  double getQuadraticElement(int i,int j) const;
+  /** Returns value for row i and column j as string.
+      Returns NULL if does not exist.
+      Returns "Numeric" if not a string
+  */
+  const char * getElementAsString(int i,int j) const;
+  /** Returns pointer to element for row i column j.
+      Only valid until next modification. 
+      NULL if element does not exist */
+  double * pointer (int i,int j) const;
+  /** Returns position in elements for row i column j.
+      Only valid until next modification. 
+      -1 if element does not exist */
+  int position (int i,int j) const;
+  
+  
+  /** Returns first element in given row - index is -1 if none.
+      Index is given by .index and value by .value
+  */
+  CoinModelLink firstInRow(int whichRow) const ;
+  /** Returns last element in given row - index is -1 if none.
+      Index is given by .index and value by .value
+  */
+  CoinModelLink lastInRow(int whichRow) const ;
+  /** Returns first element in given column - index is -1 if none.
+      Index is given by .index and value by .value
+  */
+  CoinModelLink firstInColumn(int whichColumn) const ;
+  /** Returns last element in given column - index is -1 if none.
+      Index is given by .index and value by .value
+  */
+  CoinModelLink lastInColumn(int whichColumn) const ;
+  /** Returns next element in current row or column - index is -1 if none.
+      Index is given by .index and value by .value.
+      User could also tell because input.next would be NULL
+  */
+  CoinModelLink next(CoinModelLink & current) const ;
+  /** Returns previous element in current row or column - index is -1 if none.
+      Index is given by .index and value by .value.
+      User could also tell because input.previous would be NULL
+      May not be correct if matrix updated.
+  */
+  CoinModelLink previous(CoinModelLink & current) const ;
+  /** Returns first element in given quadratic column - index is -1 if none.
+      Index is given by .index and value by .value
+      May not be correct if matrix updated.
+  */
+  CoinModelLink firstInQuadraticColumn(int whichColumn) const ;
+  /** Returns last element in given quadratic column - index is -1 if none.
+      Index is given by .index and value by .value
+  */
+  CoinModelLink lastInQuadraticColumn(int whichColumn) const ;
+  /** Gets rowLower (if row does not exist then -COIN_DBL_MAX)
+  */
+  double  getRowLower(int whichRow) const ; 
+  /** Gets rowUpper (if row does not exist then +COIN_DBL_MAX)
+  */
+  double  getRowUpper(int whichRow) const ; 
+  /** Gets name (if row does not exist then NULL)
+  */
+  const char * getRowName(int whichRow) const ; 
+  inline double  rowLower(int whichRow) const
+  { return getRowLower(whichRow);}
+  /** Gets rowUpper (if row does not exist then COIN_DBL_MAX)
+  */
+  inline double  rowUpper(int whichRow) const
+  { return getRowUpper(whichRow) ;}
+  /** Gets name (if row does not exist then NULL)
+  */
+  inline const char * rowName(int whichRow) const
+  { return getRowName(whichRow);}
+  /** Gets columnLower (if column does not exist then 0.0)
+  */
+  double  getColumnLower(int whichColumn) const ; 
+  /** Gets columnUpper (if column does not exist then COIN_DBL_MAX)
+  */
+  double  getColumnUpper(int whichColumn) const ; 
+  /** Gets columnObjective (if column does not exist then 0.0)
+  */
+  double  getColumnObjective(int whichColumn) const ; 
+  /** Gets name (if column does not exist then NULL)
+  */
+  const char * getColumnName(int whichColumn) const ; 
+  /** Gets if integer (if column does not exist then false)
+  */
+  bool getColumnIsInteger(int whichColumn) const ; 
+  /** Gets columnLower (if column does not exist then 0.0)
+  */
+  inline double  columnLower(int whichColumn) const
+  { return getColumnLower(whichColumn);}
+  /** Gets columnUpper (if column does not exist then COIN_DBL_MAX)
+  */
+  inline double  columnUpper(int whichColumn) const
+  { return getColumnUpper(whichColumn) ;}
+  /** Gets columnObjective (if column does not exist then 0.0)
+  */
+  inline double  columnObjective(int whichColumn) const
+  { return getColumnObjective(whichColumn);}
+  /** Gets columnObjective (if column does not exist then 0.0)
+  */
+  inline double  objective(int whichColumn) const
+  { return getColumnObjective(whichColumn);}
+  /** Gets name (if column does not exist then NULL)
+  */
+  inline const char * columnName(int whichColumn) const
+  { return getColumnName(whichColumn);}
+  /** Gets if integer (if column does not exist then false)
+  */
+  inline bool columnIsInteger(int whichColumn) const
+  { return getColumnIsInteger(whichColumn);}
+  /** Gets if integer (if column does not exist then false)
+  */
+  inline bool isInteger(int whichColumn) const
+  { return getColumnIsInteger(whichColumn);}
+  /** Gets columnLower (if column does not exist then 0.0)
+  */
+  inline double  getColLower(int whichColumn) const
+  { return getColumnLower(whichColumn);}
+  /** Gets columnUpper (if column does not exist then COIN_DBL_MAX)
+  */
+  inline double  getColUpper(int whichColumn) const
+  { return getColumnUpper(whichColumn) ;}
+  /** Gets columnObjective (if column does not exist then 0.0)
+  */
+  inline double  getColObjective(int whichColumn) const
+  { return getColumnObjective(whichColumn);}
+  /** Gets name (if column does not exist then NULL)
+  */
+  inline const char * getColName(int whichColumn) const
+  { return getColumnName(whichColumn);}
+  /** Gets if integer (if column does not exist then false)
+  */
+  inline bool getColIsInteger(int whichColumn) const
+  { return getColumnIsInteger(whichColumn);}
+  /** Gets rowLower (if row does not exist then -COIN_DBL_MAX)
+  */
+  const char *  getRowLowerAsString(int whichRow) const ; 
+  /** Gets rowUpper (if row does not exist then +COIN_DBL_MAX)
+  */
+  const char *  getRowUpperAsString(int whichRow) const ; 
+  inline const char *  rowLowerAsString(int whichRow) const
+  { return getRowLowerAsString(whichRow);}
+  /** Gets rowUpper (if row does not exist then COIN_DBL_MAX)
+  */
+  inline const char *  rowUpperAsString(int whichRow) const
+  { return getRowUpperAsString(whichRow) ;}
+  /** Gets columnLower (if column does not exist then 0.0)
+  */
+  const char *  getColumnLowerAsString(int whichColumn) const ; 
+  /** Gets columnUpper (if column does not exist then COIN_DBL_MAX)
+  */
+  const char *  getColumnUpperAsString(int whichColumn) const ; 
+  /** Gets columnObjective (if column does not exist then 0.0)
+  */
+  const char *  getColumnObjectiveAsString(int whichColumn) const ; 
+  /** Gets if integer (if column does not exist then false)
+  */
+  const char * getColumnIsIntegerAsString(int whichColumn) const ; 
+  /** Gets columnLower (if column does not exist then 0.0)
+  */
+  inline const char *  columnLowerAsString(int whichColumn) const
+  { return getColumnLowerAsString(whichColumn);}
+  /** Gets columnUpper (if column does not exist then COIN_DBL_MAX)
+  */
+  inline const char *  columnUpperAsString(int whichColumn) const
+  { return getColumnUpperAsString(whichColumn) ;}
+  /** Gets columnObjective (if column does not exist then 0.0)
+  */
+  inline const char *  columnObjectiveAsString(int whichColumn) const
+  { return getColumnObjectiveAsString(whichColumn);}
+  /** Gets columnObjective (if column does not exist then 0.0)
+  */
+  inline const char *  objectiveAsString(int whichColumn) const
+  { return getColumnObjectiveAsString(whichColumn);}
+  /** Gets if integer (if column does not exist then false)
+  */
+  inline const char * columnIsIntegerAsString(int whichColumn) const
+  { return getColumnIsIntegerAsString(whichColumn);}
+  /** Gets if integer (if column does not exist then false)
+  */
+  inline const char * isIntegerAsString(int whichColumn) const
+  { return getColumnIsIntegerAsString(whichColumn);}
+  /// Row index from row name (-1 if no names or no match)
+  int row(const char * rowName) const;
+  /// Column index from column name (-1 if no names or no match)
+  int column(const char * columnName) const;
+  /// Returns type
+  inline int type() const
+  { return type_;}
+  /// returns unset value
+  inline double unsetValue() const
+  { return -1.23456787654321e-97;}
+  /// Creates a packed matrix - return number of errors
+  int createPackedMatrix(CoinPackedMatrix & matrix, 
+			 const double * associated);
+  /** Fills in startPositive and startNegative with counts for +-1 matrix.
+      If not +-1 then startPositive[0]==-1 otherwise counts and
+      startPositive[numberColumns]== size
+      - return number of errors
+  */
+  int countPlusMinusOne(CoinBigIndex * startPositive, CoinBigIndex * startNegative,
+                        const double * associated);
+  /** Creates +-1 matrix given startPositive and startNegative counts for +-1 matrix.
+  */
+  void createPlusMinusOne(CoinBigIndex * startPositive, CoinBigIndex * startNegative,
+                         int * indices,
+                         const double * associated);
+  /// Creates copies of various arrays - return number of errors
+  int createArrays(double * & rowLower, double * &  rowUpper,
+                   double * & columnLower, double * & columnUpper,
+                   double * & objective, int * & integerType,
+                   double * & associated);
+  /// Says if strings exist
+  inline bool stringsExist() const
+  { return string_.numberItems()!=0;}
+  /// Return string array
+  inline const CoinModelHash * stringArray() const
+  { return &string_;}
+  /// Returns associated array
+  inline double * associatedArray() const
+  { return associated_;}
+  /// Return rowLower array
+  inline double * rowLowerArray() const
+  { return rowLower_;}
+  /// Return rowUpper array
+  inline double * rowUpperArray() const
+  { return rowUpper_;}
+  /// Return columnLower array
+  inline double * columnLowerArray() const
+  { return columnLower_;}
+  /// Return columnUpper array
+  inline double * columnUpperArray() const
+  { return columnUpper_;}
+  /// Return objective array
+  inline double * objectiveArray() const
+  { return objective_;}
+  /// Return integerType array
+  inline int * integerTypeArray() const
+  { return integerType_;}
+  /// Return row names array
+  inline const CoinModelHash * rowNames() const
+  { return &rowName_;}
+  /// Return column names array
+  inline const CoinModelHash * columnNames() const
+  { return &columnName_;}
+  /// Reset row names
+  inline void zapRowNames()
+  { rowName_=CoinModelHash();}
+  /// Reset column names
+  inline void zapColumnNames()
+  { columnName_=CoinModelHash();}
+  /// Returns array of 0 or nonzero if can be a cut (or returns NULL)
+  inline const int * cutMarker() const
+  { return cut_;}
+  /// Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+  inline double optimizationDirection() const {
+    return  optimizationDirection_;
+  }
+  /// Set direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+  inline void setOptimizationDirection(double value)
+  { optimizationDirection_=value;}
+  /// Return pointer to more information
+  inline void * moreInfo() const
+  { return moreInfo_;}
+  /// Set pointer to more information
+  inline void setMoreInfo(void * info)
+  { moreInfo_ = info;}
+  /** Returns which parts of model are set
+      1 - matrix
+      2 - rhs
+      4 - row names
+      8 - column bounds and/or objective
+      16 - column names
+      32 - integer types
+  */
+  int whatIsSet() const;
+   //@}
+
+  /**@name for block models - matrix will be CoinPackedMatrix */
+   //@{
+  /*! \brief Load in a problem by copying the arguments. The constraints on
+    the rows are given by lower and upper bounds.
+    
+    If a pointer is 0 then the following values are the default:
+    <ul>
+    <li> <code>colub</code>: all columns have upper bound infinity
+    <li> <code>collb</code>: all columns have lower bound 0 
+    <li> <code>rowub</code>: all rows have upper bound infinity
+    <li> <code>rowlb</code>: all rows have lower bound -infinity
+    <li> <code>obj</code>: all variables have 0 objective coefficient
+    </ul>
+    
+    Note that the default values for rowub and rowlb produce the
+    constraint -infty <= ax <= infty. This is probably not what you want.
+  */
+  void loadBlock (const CoinPackedMatrix& matrix,
+		  const double* collb, const double* colub,   
+		  const double* obj,
+		  const double* rowlb, const double* rowub) ;
+  /*! \brief Load in a problem by copying the arguments.
+    The constraints on the rows are given by sense/rhs/range triplets.
+    
+    If a pointer is 0 then the following values are the default:
+    <ul>
+    <li> <code>colub</code>: all columns have upper bound infinity
+    <li> <code>collb</code>: all columns have lower bound 0 
+    <li> <code>obj</code>: all variables have 0 objective coefficient
+    <li> <code>rowsen</code>: all rows are >=
+    <li> <code>rowrhs</code>: all right hand sides are 0
+    <li> <code>rowrng</code>: 0 for the ranged rows
+    </ul>
+    
+    Note that the default values for rowsen, rowrhs, and rowrng produce the
+    constraint ax >= 0.
+  */
+  void loadBlock (const CoinPackedMatrix& matrix,
+		  const double* collb, const double* colub,
+		  const double* obj,
+		  const char* rowsen, const double* rowrhs,   
+		  const double* rowrng) ;
+  
+  /*! \brief Load in a problem by copying the arguments. The constraint
+    matrix is is specified with standard column-major
+    column starts / row indices / coefficients vectors. 
+    The constraints on the rows are given by lower and upper bounds.
+    
+    The matrix vectors must be gap-free. Note that <code>start</code> must
+    have <code>numcols+1</code> entries so that the length of the last column
+    can be calculated as <code>start[numcols]-start[numcols-1]</code>.
+    
+    See the previous loadBlock method using rowlb and rowub for default
+    argument values.
+  */
+  void loadBlock (const int numcols, const int numrows,
+		  const CoinBigIndex * start, const int* index,
+		  const double* value,
+		  const double* collb, const double* colub,   
+		  const double* obj,
+		  const double* rowlb, const double* rowub) ;
+  
+  /*! \brief Load in a problem by copying the arguments. The constraint
+    matrix is is specified with standard column-major
+    column starts / row indices / coefficients vectors. 
+    The constraints on the rows are given by sense/rhs/range triplets.
+    
+    The matrix vectors must be gap-free. Note that <code>start</code> must
+    have <code>numcols+1</code> entries so that the length of the last column
+    can be calculated as <code>start[numcols]-start[numcols-1]</code>.
+    
+    See the previous loadBlock method using sense/rhs/range for default
+    argument values.
+  */
+  void loadBlock (const int numcols, const int numrows,
+		  const CoinBigIndex * start, const int* index,
+		  const double* value,
+		  const double* collb, const double* colub,   
+		  const double* obj,
+		  const char* rowsen, const double* rowrhs,   
+		  const double* rowrng) ;
+
+   //@}
+
+  /**@name Constructors, destructor */
+   //@{
+   /** Default constructor. */
+   CoinModel();
+   /** Constructor with sizes. */
+   CoinModel(int firstRows, int firstColumns, int firstElements,bool noNames=false);
+   /** Read a problem in MPS or GAMS format from the given filename.
+   */
+   CoinModel(const char *fileName, int allowStrings=0);
+   /** Read a problem from AMPL nl file
+       NOTE - as I can't work out configure etc the source code is in Cbc_ampl.cpp!
+   */
+   CoinModel( int nonLinear, const char * fileName,const void * info);
+  /// From arrays
+  CoinModel(int numberRows, int numberColumns,
+	    const CoinPackedMatrix * matrix,
+	    const double * rowLower, const double * rowUpper,
+	    const double * columnLower, const double * columnUpper,
+	    const double * objective);
+  /// Clone
+  virtual CoinBaseModel * clone() const;
+
+   /** Destructor */
+   virtual ~CoinModel();
+   //@}
+
+   /**@name Copy method */
+   //@{
+   /** The copy constructor. */
+   CoinModel(const CoinModel&);
+  /// =
+   CoinModel& operator=(const CoinModel&);
+   //@}
+
+   /**@name For debug */
+   //@{
+  /// Checks that links are consistent
+  void validateLinks() const;
+   //@}
+private:
+  /// Resize
+  void resize(int maximumRows, int maximumColumns, int maximumElements);
+  /// Fill in default row information
+  void fillRows(int which,bool forceCreation,bool fromAddRow=false);
+  /// Fill in default column information
+  void fillColumns(int which,bool forceCreation,bool fromAddColumn=false);
+  /** Fill in default linked list information (1= row, 2 = column)
+      Marked as const as list is mutable */
+  void fillList(int which, CoinModelLinkedList & list,int type) const ;
+  /** Create a linked list and synchronize free 
+      type 1 for row 2 for column
+      Marked as const as list is mutable */
+  void createList(int type) const;
+  /// Adds one string, returns index
+  int addString(const char * string);
+  /** Gets a double from a string possibly containing named strings,
+      returns unset if not found
+  */
+  double getDoubleFromString(CoinYacc & info, const char * string);
+  /// Frees value memory
+  void freeStringMemory(CoinYacc & info);
+public:
+  /// Fills in all associated - returning number of errors
+  int computeAssociated(double * associated);
+  /** Gets correct form for a quadratic row - user to delete
+      If row is not quadratic then returns which other variables are involved
+      with tiny (1.0e-100) elements and count of total number of variables which could not
+      be put in quadratic form
+  */
+  CoinPackedMatrix * quadraticRow(int rowNumber,double * linear,
+				  int & numberBad) const;
+  /// Replaces a quadratic row
+  void replaceQuadraticRow(int rowNumber,const double * linear, const CoinPackedMatrix * quadraticPart);
+  /** If possible return a model where if all variables marked nonzero are fixed
+      the problem will be linear.  At present may only work if quadratic.
+      Returns NULL if not possible
+  */
+  CoinModel * reorder(const char * mark) const;
+  /** Expands out all possible combinations for a knapsack
+      If buildObj NULL then just computes space needed - returns number elements
+      On entry numberOutput is maximum allowed, on exit it is number needed or
+      -1 (as will be number elements) if maximum exceeded.  numberOutput will have at
+      least space to return values which reconstruct input.
+      Rows returned will be original rows but no entries will be returned for
+      any rows all of whose entries are in knapsack.  So up to user to allow for this.
+      If reConstruct >=0 then returns number of entrie which make up item "reConstruct"
+      in expanded knapsack.  Values in buildRow and buildElement;
+  */
+  int expandKnapsack(int knapsackRow, int & numberOutput,double * buildObj, CoinBigIndex * buildStart,
+		     int * buildRow, double * buildElement,int reConstruct=-1) const;
+  /// Sets cut marker array
+  void setCutMarker(int size,const int * marker);
+  /// Sets priority array
+  void setPriorities(int size,const int * priorities);
+  /// priorities (given for all columns (-1 if not integer)
+  inline const int * priorities() const
+  { return priority_;}
+  /// For decomposition set original row and column indices
+  void setOriginalIndices(const int * row, const int * column);
+  
+private:
+  /** Read a problem from AMPL nl file
+      so not constructor so gdb will work
+   */
+  void gdb( int nonLinear, const char * fileName, const void * info);
+  /// returns jColumn (-2 if linear term, -1 if unknown) and coefficient
+  int decodeBit(char * phrase, char * & nextPhrase, double & coefficient, bool ifFirst) const;
+  /// Aborts with message about packedMatrix
+  void badType() const;
+  /**@name Data members */
+   //@{
+  /// Maximum number of rows
+  int maximumRows_;
+  /// Maximum number of columns
+  int maximumColumns_;
+  /// Current number of elements
+  int numberElements_;
+  /// Maximum number of elements
+  int maximumElements_;
+  /// Current number of quadratic elements
+  int numberQuadraticElements_;
+  /// Maximum number of quadratic elements
+  int maximumQuadraticElements_;
+  /// Row lower 
+  double * rowLower_;
+  /// Row upper 
+  double * rowUpper_;
+  /// Row names
+  CoinModelHash rowName_;
+  /** Row types.
+      Has information - at present
+      bit 0 - rowLower is a string
+      bit 1 - rowUpper is a string
+      NOTE - if converted to CoinPackedMatrix - may be indices of 
+      original rows (i.e. when decomposed)
+  */
+  int * rowType_;
+  /// Objective
+  double * objective_;
+  /// Column Lower
+  double * columnLower_;
+  /// Column Upper
+  double * columnUpper_;
+  /// Column names
+  CoinModelHash columnName_;
+  /// Integer information
+  int * integerType_;
+  /// Strings
+  CoinModelHash string_;
+  /** Column types.
+      Has information - at present
+      bit 0 - columnLower is a string
+      bit 1 - columnUpper is a string
+      bit 2 - objective is a string
+      bit 3 - integer setting is a string
+      NOTE - if converted to CoinPackedMatrix - may be indices of 
+      original columns (i.e. when decomposed)
+  */
+  int * columnType_;
+  /// If simple then start of each row/column
+  int * start_;
+  /// Actual elements
+  CoinModelTriple * elements_;
+  /// Actual elements as CoinPackedMatrix
+  CoinPackedMatrix * packedMatrix_;
+  /// Hash for elements
+  mutable CoinModelHash2 hashElements_;
+  /// Linked list for rows
+  mutable CoinModelLinkedList rowList_;
+  /// Linked list for columns
+  mutable CoinModelLinkedList columnList_;
+  /// Actual quadratic elements (always linked lists)
+  CoinModelTriple * quadraticElements_;
+  /// Hash for quadratic elements
+  mutable CoinModelHash2 hashQuadraticElements_;
+  /// Array for sorting indices
+  int * sortIndices_;
+  /// Array for sorting elements
+  double * sortElements_;
+  /// Size of sort arrays
+  int sortSize_;
+  /// Linked list for quadratic rows
+  mutable CoinModelLinkedList quadraticRowList_;
+  /// Linked list for quadratic columns
+  mutable CoinModelLinkedList quadraticColumnList_;
+  /// Size of associated values
+  int sizeAssociated_;
+  /// Associated values
+  double * associated_;
+  /// Number of SOS - all these are done in one go e.g. from ampl
+  int numberSOS_;
+  /// SOS starts
+  int * startSOS_;
+  /// SOS members
+  int * memberSOS_;
+  /// SOS type
+  int * typeSOS_;
+  /// SOS priority
+  int * prioritySOS_;
+  /// SOS reference
+  double * referenceSOS_;
+  /// priorities (given for all columns (-1 if not integer)
+  int * priority_;
+  /// Nonzero if row is cut - done in one go e.g. from ampl
+  int * cut_;
+  /// Pointer to more information
+  void * moreInfo_;
+  /** Type of build -
+      -1 unset,
+      0 for row, 
+      1 for column,
+      2 linked.
+      3 matrix is CoinPackedMatrix (and at present can't be modified);
+  */
+  mutable int type_;
+  /// True if no names EVER being used (for users who know what they are doing)
+  bool noNames_;
+  /** Links present (could be tested by sizes of objects)
+      0 - none,
+      1 - row links,
+      2 - column links,
+      3 - both
+  */
+  mutable int links_;
+   //@}
+};
+/// Just function of single variable x
+double getFunctionValueFromString(const char * string, const char * x, double xValue);
+/// faster version
+double getDoubleFromString(CoinYacc & info, const char * string, const char * x, double xValue);
+#endif
diff --git a/cbits/coin/CoinModelUseful.cpp b/cbits/coin/CoinModelUseful.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinModelUseful.cpp
@@ -0,0 +1,1455 @@
+/* $Id: CoinModelUseful.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+
+#include <cstdlib>
+#include <cmath>
+#include <cassert>
+#include <cfloat>
+#include <string>
+#include <cstdio>
+#include <iostream>
+
+#include "CoinHelperFunctions.hpp"
+
+#include "CoinModelUseful.hpp"
+
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinModelLink::CoinModelLink () 
+ : row_(-1),
+   column_(-1),
+   value_(0.0),
+   position_(-1),
+   onRow_(true)
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinModelLink::CoinModelLink (const CoinModelLink & rhs) 
+  : row_(rhs.row_),
+    column_(rhs.column_),
+    value_(rhs.value_),
+    position_(rhs.position_),
+    onRow_(rhs.onRow_)
+{
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinModelLink::~CoinModelLink ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinModelLink &
+CoinModelLink::operator=(const CoinModelLink& rhs)
+{
+  if (this != &rhs) {
+    row_ = rhs.row_;
+    column_ = rhs.column_;
+    value_ = rhs.value_;
+    position_ = rhs.position_;
+    onRow_ = rhs.onRow_;
+  }
+  return *this;
+}
+
+namespace {
+ const int mmult[] = {
+    262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
+    241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829,
+    221281, 218849, 216319, 213721, 211093, 208673, 206263, 203773,
+    201233, 198637, 196159, 193603, 191161, 188701, 186149, 183761,
+    181303, 178873, 176389, 173897, 171469, 169049, 166471, 163871,
+    161387, 158941, 156437, 153949, 151531, 149159, 146749, 144299,
+    141709, 139369, 136889, 134591, 132169, 129641, 127343, 124853,
+    122477, 120163, 117757, 115361, 112979, 110567, 108179, 105727,
+    103387, 101021, 98639, 96179, 93911, 91583, 89317, 86939, 84521,
+    82183, 79939, 77587, 75307, 72959, 70793, 68447, 66103
+  };
+  const int lengthMult = static_cast<int> (sizeof(mmult) / sizeof(int));
+}
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinModelHash::CoinModelHash () 
+  : names_(NULL),
+    hash_(NULL),
+    numberItems_(0),
+    maximumItems_(0),
+    lastSlot_(-1)
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinModelHash::CoinModelHash (const CoinModelHash & rhs) 
+  : names_(NULL),
+    hash_(NULL),
+    numberItems_(rhs.numberItems_),
+    maximumItems_(rhs.maximumItems_),
+    lastSlot_(rhs.lastSlot_)
+{
+  if (maximumItems_) {
+    names_ = new char * [maximumItems_];
+    for (int i=0;i<maximumItems_;i++) {
+      names_[i]=CoinStrdup(rhs.names_[i]);
+    }
+    hash_ = CoinCopyOfArray(rhs.hash_,4*maximumItems_);
+  }
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinModelHash::~CoinModelHash ()
+{
+  for (int i=0;i<maximumItems_;i++) 
+    free(names_[i]);
+  delete [] names_;
+  delete [] hash_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinModelHash &
+CoinModelHash::operator=(const CoinModelHash& rhs)
+{
+  if (this != &rhs) {
+    for (int i=0;i<maximumItems_;i++) 
+      free(names_[i]);
+    delete [] names_;
+    delete [] hash_;
+    numberItems_ = rhs.numberItems_;
+    maximumItems_ = rhs.maximumItems_;
+    lastSlot_ = rhs.lastSlot_;
+    if (maximumItems_) {
+      names_ = new char * [maximumItems_];
+      for (int i=0;i<maximumItems_;i++) {
+        names_[i]=CoinStrdup(rhs.names_[i]);
+      }
+      hash_ = CoinCopyOfArray(rhs.hash_,4*maximumItems_);
+    } else {
+      names_ = NULL;
+      hash_ = NULL;
+    }
+  }
+  return *this;
+}
+// Set number of items
+void 
+CoinModelHash::setNumberItems(int number)
+{
+  assert (number>=0&&number<=numberItems_);
+  numberItems_=number;
+}
+// Resize hash (also re-hashs)
+void 
+CoinModelHash::resize(int maxItems,bool forceReHash)
+{
+  assert (numberItems_<=maximumItems_);
+  if (maxItems<=maximumItems_&&!forceReHash)
+    return;
+  int n=maximumItems_;
+  maximumItems_=maxItems;
+  char ** names = new char * [maximumItems_];
+  int i;
+  for ( i=0;i<n;i++) 
+    names[i]=names_[i];
+  for ( ;i<maximumItems_;i++) 
+    names[i]=NULL;
+  delete [] names_;
+  names_ = names;
+  delete [] hash_;
+  int maxHash = 4 * maximumItems_;
+  hash_ = new CoinModelHashLink [maxHash];
+  int ipos;
+
+  for ( i = 0; i < maxHash; i++ ) {
+    hash_[i].index = -1;
+    hash_[i].next = -1;
+  }
+
+  /*
+   * Initialize the hash table.  Only the index of the first name that
+   * hashes to a value is entered in the table; subsequent names that
+   * collide with it are not entered.
+   */
+  for ( i = 0; i < numberItems_; ++i ) {
+    if (names_[i]) {
+      ipos = hashValue ( names_[i]);
+      if ( hash_[ipos].index == -1 ) {
+        hash_[ipos].index = i;
+      }
+    }
+  }
+
+  /*
+   * Now take care of the names that collided in the preceding loop,
+   * by finding some other entry in the table for them.
+   * Since there are as many entries in the table as there are names,
+   * there must be room for them.
+   */
+  lastSlot_ = -1;
+  for ( i = 0; i < numberItems_; ++i ) {
+    if (!names_[i]) 
+      continue;
+    char *thisName = names[i];
+    ipos = hashValue ( thisName);
+
+    while ( true ) {
+      int j1 = hash_[ipos].index;
+
+      if ( j1 == i )
+	break;
+      else {
+	char *thisName2 = names[j1];
+
+	if ( strcmp ( thisName, thisName2 ) == 0 ) {
+	  printf ( "** duplicate name %s\n", names[i] );
+          abort();
+	  break;
+	} else {
+	  int k = hash_[ipos].next;
+
+	  if ( k == -1 ) {
+	    while ( true ) {
+	      ++lastSlot_;
+	      if ( lastSlot_ > numberItems_ ) {
+		printf ( "** too many names\n" );
+                abort();
+		break;
+	      }
+	      if ( hash_[lastSlot_].index == -1 ) {
+		break;
+	      }
+	    }
+	    hash_[ipos].next = lastSlot_;
+	    hash_[lastSlot_].index = i;
+	    break;
+	  } else {
+	    ipos = k;
+	    /* nothing worked - try it again */
+	  }
+	}
+      }
+    }
+  }
+  
+}
+// validate
+void 
+CoinModelHash::validateHash() const
+{
+  for (int i = 0; i < numberItems_; ++i ) {
+    if (names_[i]) {
+      assert (hash( names_[i])>=0);
+    }
+  }
+}
+// Returns index or -1
+int 
+CoinModelHash::hash(const char * name) const
+{
+  int found = -1;
+
+  int ipos;
+
+  /* default if we don't find anything */
+  if ( !numberItems_ )
+    return -1;
+
+  ipos = hashValue ( name );
+  while ( true ) {
+    int j1 = hash_[ipos].index;
+
+    if ( j1 >= 0 ) {
+      char *thisName2 = names_[j1];
+
+      if ( strcmp ( name, thisName2 ) != 0 ) {
+	int k = hash_[ipos].next;
+
+	if ( k != -1 )
+	  ipos = k;
+	else
+	  break;
+      } else {
+	found = j1;
+	break;
+      }
+    } else {
+      int k = hash_[ipos].next;
+      
+      if ( k != -1 )
+        ipos = k;
+      else
+        break;
+    }
+  }
+  return found;
+}
+// Adds to hash
+void 
+CoinModelHash::addHash(int index, const char * name)
+{
+  // resize if necessary
+  if (numberItems_>=maximumItems_) 
+    resize(1000+3*numberItems_/2);
+  assert (!names_[index]);
+  names_[index]=CoinStrdup(name);
+  int ipos = hashValue ( name);
+  numberItems_ = CoinMax(numberItems_,index+1);
+  if ( hash_[ipos].index <0 ) {
+    hash_[ipos].index = index;
+  } else {
+    while ( true ) {
+      int j1 = hash_[ipos].index;
+      
+      if ( j1 == index )
+	break; // duplicate?
+      else {
+        if (j1>=0) {
+          char *thisName2 = names_[j1];
+          if ( strcmp ( name, thisName2 ) == 0 ) {
+            printf ( "** duplicate name %s\n", names_[index] );
+            abort();
+            break;
+          } else {
+            int k = hash_[ipos].next;
+            
+            if ( k == -1 ) {
+              while ( true ) {
+                ++lastSlot_;
+                if ( lastSlot_ > numberItems_ ) {
+                  printf ( "** too many names\n" );
+                  abort();
+                  break;
+                }
+                if ( hash_[lastSlot_].index <0 && hash_[lastSlot_].next<0) {
+                  break;
+                }
+              }
+              hash_[ipos].next = lastSlot_;
+              hash_[lastSlot_].index = index;
+              hash_[lastSlot_].next=-1;
+              break;
+            } else {
+              ipos = k;
+            }
+          }
+        } else {
+          //slot available
+          hash_[ipos].index = index;
+        }
+      }
+    }
+  }
+}
+// Deletes from hash
+void 
+CoinModelHash::deleteHash(int index)
+{
+  if (index<numberItems_&&names_[index]) {
+    
+    int ipos = hashValue ( names_[index] );
+
+    while ( ipos>=0 ) {
+      int j1 = hash_[ipos].index;
+      if ( j1!=index) {
+        ipos = hash_[ipos].next;
+      } else {
+        hash_[ipos].index=-1; // available
+        break;
+      }
+    }
+    assert (ipos>=0);
+    free(names_[index]);
+    names_[index]=NULL;
+  }
+}
+// Returns name at position (or NULL)
+const char * 
+CoinModelHash::name(int which) const
+{
+  if (which<numberItems_)
+    return names_[which];
+  else
+    return NULL;
+}
+// Returns non const name at position (or NULL)
+char * 
+CoinModelHash::getName(int which) const
+{
+  if (which<numberItems_)
+    return names_[which];
+  else
+    return NULL;
+}
+// Sets name at position (does not create)
+void 
+CoinModelHash::setName(int which,char * name ) 
+{
+  if (which<numberItems_)
+    names_[which]=name;
+}
+// Returns a hash value
+int 
+CoinModelHash::hashValue(const char * name) const
+{
+  
+  int n = 0;
+  int j;
+  int length =  static_cast<int> (strlen(name));
+  // may get better spread with unsigned
+  const unsigned char * name2 = reinterpret_cast<const unsigned char *> (name);
+  while (length) {
+    int length2 = CoinMin( length,lengthMult);
+    for ( j = 0; j < length2; ++j ) {
+      n += mmult[j] * name2[j];
+    }
+    name+=length2;
+    length-=length2;
+  }
+  int maxHash = 4 * maximumItems_;
+  return ( abs ( n ) % maxHash );	/* integer abs */
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinModelHash2::CoinModelHash2 () 
+ :   hash_(NULL),
+    numberItems_(0),
+    maximumItems_(0),
+    lastSlot_(-1)
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinModelHash2::CoinModelHash2 (const CoinModelHash2 & rhs) 
+  : hash_(NULL),
+    numberItems_(rhs.numberItems_),
+    maximumItems_(rhs.maximumItems_),
+    lastSlot_(rhs.lastSlot_)
+{
+  if (maximumItems_) {
+    hash_ = CoinCopyOfArray(rhs.hash_,4*maximumItems_);
+  }
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinModelHash2::~CoinModelHash2 ()
+{
+  delete [] hash_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinModelHash2 &
+CoinModelHash2::operator=(const CoinModelHash2& rhs)
+{
+  if (this != &rhs) {
+    delete [] hash_;
+    numberItems_ = rhs.numberItems_;
+    maximumItems_ = rhs.maximumItems_;
+    lastSlot_ = rhs.lastSlot_;
+    if (maximumItems_) {
+      hash_ = CoinCopyOfArray(rhs.hash_,4*maximumItems_);
+    } else {
+      hash_ = NULL;
+    }
+  }
+  return *this;
+}
+// Set number of items
+void 
+CoinModelHash2::setNumberItems(int number)
+{
+  assert (number>=0&&(number<=numberItems_||!numberItems_));
+  numberItems_=number;
+}
+// Resize hash (also re-hashs)
+void 
+CoinModelHash2::resize(int maxItems, const CoinModelTriple * triples,bool forceReHash)
+{
+  assert (numberItems_<=maximumItems_||!maximumItems_);
+  if (maxItems<=maximumItems_&&!forceReHash)
+    return;
+  if (maxItems>maximumItems_) {
+    maximumItems_=maxItems;
+    delete [] hash_;
+    hash_ = new CoinModelHashLink [4*maximumItems_];
+  }
+  int maxHash = 4 * maximumItems_;
+  int ipos;
+  int i;
+  for ( i = 0; i < maxHash; i++ ) {
+    hash_[i].index = -1;
+    hash_[i].next = -1;
+  }
+
+  /*
+   * Initialize the hash table.  Only the index of the first name that
+   * hashes to a value is entered in the table; subsequent names that
+   * collide with it are not entered.
+   */
+  for ( i = 0; i < numberItems_; ++i ) {
+    int row = static_cast<int> (rowInTriple(triples[i]));
+    int column = triples[i].column;
+    if (column>=0) {
+      ipos = hashValue ( row, column);
+      if ( hash_[ipos].index == -1 ) {
+        hash_[ipos].index = i;
+      }
+    }
+  }
+
+  /*
+   * Now take care of the entries that collided in the preceding loop,
+   * by finding some other entry in the table for them.
+   * Since there are as many entries in the table as there are entries,
+   * there must be room for them.
+   */
+  lastSlot_ = -1;
+  for ( i = 0; i < numberItems_; ++i ) {
+    int row = static_cast<int> (rowInTriple(triples[i]));
+    int column = triples[i].column;
+    if (column>=0) {
+      ipos = hashValue ( row, column);
+
+      while ( true ) {
+        int j1 = hash_[ipos].index;
+        
+        if ( j1 == i )
+          break;
+        else {
+          int row2 = static_cast<int> (rowInTriple(triples[j1]));
+          int column2 = triples[j1].column;
+          if ( row==row2&&column==column2 ) {
+            printf ( "** duplicate entry %d %d\n", row,column );
+            abort();
+            break;
+          } else {
+            int k = hash_[ipos].next;
+            
+            if ( k == -1 ) {
+              while ( true ) {
+                ++lastSlot_;
+                if ( lastSlot_ > numberItems_ ) {
+                  printf ( "** too many entries\n" );
+                  abort();
+                  break;
+                }
+                if ( hash_[lastSlot_].index == -1 ) {
+                  break;
+                }
+              }
+              hash_[ipos].next = lastSlot_;
+              hash_[lastSlot_].index = i;
+              break;
+            } else {
+              ipos = k;
+            }
+          }
+	}
+      }
+    }
+  }
+  
+}
+// Returns index or -1
+int 
+CoinModelHash2::hash(int row, int column, const CoinModelTriple * triples) const
+{
+  int found = -1;
+
+  int ipos;
+
+  /* default if we don't find anything */
+  if ( !numberItems_ )
+    return -1;
+
+  ipos = hashValue ( row, column );
+  while ( true ) {
+    int j1 = hash_[ipos].index;
+
+    if ( j1 >= 0 ) {
+      int row2 = static_cast<int> (rowInTriple(triples[j1]));
+      int column2 = triples[j1].column;
+      if ( row!=row2||column!=column2 ) {
+	int k = hash_[ipos].next;
+        
+	if ( k != -1 )
+	  ipos = k;
+	else
+	  break;
+      } else {
+	found = j1;
+	break;
+      }
+    } else {
+      int k = hash_[ipos].next;
+      
+      if ( k != -1 )
+        ipos = k;
+      else
+        break;
+    }
+  }
+  return found;
+}
+// Adds to hash
+void 
+CoinModelHash2::addHash(int index, int row, int column, const CoinModelTriple * triples)
+{
+  // resize if necessary
+  if (numberItems_>=maximumItems_||index+1>=maximumItems_) 
+    resize(CoinMax(1000+3*numberItems_/2,index+1), triples);
+  int ipos = hashValue ( row, column);
+  numberItems_ = CoinMax(numberItems_,index+1);
+  assert (numberItems_<=maximumItems_);
+  if ( hash_[ipos].index <0 ) {
+    hash_[ipos].index = index;
+  } else {
+    while ( true ) {
+      int j1 = hash_[ipos].index;
+      
+      if ( j1 == index ) {
+	break; // duplicate??
+      } else {
+        if (j1 >=0 ) {
+          int row2 = static_cast<int> (rowInTriple(triples[j1]));
+          int column2 = triples[j1].column;
+          if ( row==row2&&column==column2 ) {
+            printf ( "** duplicate entry %d %d\n", row, column );
+            abort();
+            break;
+          } else {
+            int k = hash_[ipos].next;
+            
+            if ( k ==-1 ) {
+              while ( true ) {
+                ++lastSlot_;
+                if ( lastSlot_ > numberItems_ ) {
+                  printf ( "** too many entrys\n" );
+                  abort();
+                  break;
+                }
+                if ( hash_[lastSlot_].index <0 ) {
+                  break;
+                }
+              }
+              hash_[ipos].next = lastSlot_;
+              hash_[lastSlot_].index = index;
+              hash_[lastSlot_].next=-1;
+              break;
+            } else {
+              ipos = k;
+            }
+          }
+        } else {
+          // slot available
+          hash_[ipos].index = index;
+        }
+      }
+    }
+  }
+}
+// Deletes from hash
+void 
+CoinModelHash2::deleteHash(int index,int row, int column)
+{
+  if (index<numberItems_) {
+    
+    int ipos = hashValue ( row, column );
+
+    while ( ipos>=0 ) {
+      int j1 = hash_[ipos].index;
+      if ( j1!=index) {
+        ipos = hash_[ipos].next;
+      } else {
+        hash_[ipos].index=-1; // available
+        break;
+      }
+    }
+  }
+}
+namespace {
+  const int mmult2[] = {
+    262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
+    241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829
+  };
+}
+// Returns a hash value
+int 
+CoinModelHash2::hashValue(int row, int column) const
+{
+  
+  // Optimizer should take out one side of if
+  if (sizeof(int)==4*sizeof(char)) {
+    unsigned char tempChar[4];
+    
+    unsigned int n = 0;
+    int * temp = reinterpret_cast<int *> (tempChar);
+    *temp=row;
+    n += mmult2[0] * tempChar[0];
+    n += mmult2[1] * tempChar[1];
+    n += mmult2[2] * tempChar[2];
+    n += mmult[3] * tempChar[3];
+    *temp=column;
+    n += mmult2[0+8] * tempChar[0];
+    n += mmult2[1+8] * tempChar[1];
+    n += mmult2[2+8] * tempChar[2];
+    n += mmult2[3+8] * tempChar[3];
+    return n % (maximumItems_<<1);
+  } else {
+    // ints are 8
+    unsigned char tempChar[8];
+    
+    int n = 0;
+    unsigned int j;
+    int * temp = reinterpret_cast<int *> (tempChar);
+    *temp=row;
+    for ( j = 0; j < sizeof(int); ++j ) {
+      int itemp = tempChar[j];
+      n += mmult2[j] * itemp;
+    }
+    *temp=column;
+    for ( j = 0; j < sizeof(int); ++j ) {
+      int itemp = tempChar[j];
+      n += mmult2[j+8] * itemp;
+    }
+    int maxHash = 4 * maximumItems_;
+    int absN = abs(n);
+    int returnValue = absN % maxHash;
+    return returnValue;
+  }
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinModelLinkedList::CoinModelLinkedList () 
+  : previous_(NULL),
+    next_(NULL),
+    first_(NULL),
+    last_(NULL),
+    numberMajor_(0),
+    maximumMajor_(0),
+    numberElements_(0),
+    maximumElements_(0),
+    type_(-1)
+{
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinModelLinkedList::CoinModelLinkedList (const CoinModelLinkedList & rhs) 
+  : numberMajor_(rhs.numberMajor_),
+    maximumMajor_(rhs.maximumMajor_),
+    numberElements_(rhs.numberElements_),
+    maximumElements_(rhs.maximumElements_),
+    type_(rhs.type_)
+{
+  if (maximumMajor_) {
+    previous_ = CoinCopyOfArray(rhs.previous_,maximumElements_);
+    next_ = CoinCopyOfArray(rhs.next_,maximumElements_);
+    first_ = CoinCopyOfArray(rhs.first_,maximumMajor_+1);
+    last_ = CoinCopyOfArray(rhs.last_,maximumMajor_+1);
+  } else {
+    previous_ = NULL;
+    next_ = NULL;
+    first_ = NULL;
+    last_ = NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinModelLinkedList::~CoinModelLinkedList ()
+{
+  delete [] previous_;
+  delete [] next_;
+  delete [] first_;
+  delete [] last_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinModelLinkedList &
+CoinModelLinkedList::operator=(const CoinModelLinkedList& rhs)
+{
+  if (this != &rhs) {
+    delete [] previous_;
+    delete [] next_;
+    delete [] first_;
+    delete [] last_;
+    numberMajor_ = rhs.numberMajor_;
+    maximumMajor_ = rhs.maximumMajor_;
+    numberElements_ = rhs.numberElements_;
+    maximumElements_ = rhs.maximumElements_;
+    type_ = rhs.type_;
+    if (maximumMajor_) {
+      previous_ = CoinCopyOfArray(rhs.previous_,maximumElements_);
+      next_ = CoinCopyOfArray(rhs.next_,maximumElements_);
+      first_ = CoinCopyOfArray(rhs.first_,maximumMajor_+1);
+      last_ = CoinCopyOfArray(rhs.last_,maximumMajor_+1);
+    } else {
+      previous_ = NULL;
+      next_ = NULL;
+      first_ = NULL;
+      last_ = NULL;
+    }
+  }
+  return *this;
+}
+// Resize list - for row list maxMajor is maximum rows
+void 
+CoinModelLinkedList::resize(int maxMajor,int maxElements)
+{
+  maxMajor=CoinMax(maxMajor,maximumMajor_);
+  maxElements=CoinMax(maxElements,maximumElements_);
+  if (maxMajor>maximumMajor_) {
+    int * first = new int [maxMajor+1];
+    int free;
+    if (maximumMajor_) {
+      CoinMemcpyN(first_,maximumMajor_,first);
+#     ifdef ZEROFAULT
+      memset(first+maximumMajor_,0,(maxMajor-maximumMajor_)*sizeof(int)) ;
+#     endif
+      free = first_[maximumMajor_];
+      first[maximumMajor_]=-1;
+    } else {
+      free=-1;
+    }
+    first[maxMajor]=free;
+    delete [] first_;
+    first_=first;
+    int * last = new int [maxMajor+1];
+    if (maximumMajor_) {
+      CoinMemcpyN(last_,maximumMajor_,last);
+#     ifdef ZEROFAULT
+      memset(last+maximumMajor_,0,(maxMajor-maximumMajor_)*sizeof(int)) ;
+#     endif
+      free = last_[maximumMajor_];
+      last[maximumMajor_]=-1;
+    } else {
+      free=-1;
+    }
+    last[maxMajor]=free;
+    delete [] last_;
+    last_=last;
+    maximumMajor_ = maxMajor;
+  }
+  if ( maxElements>maximumElements_) {
+    int * previous = new int [maxElements];
+    CoinMemcpyN(previous_,numberElements_,previous);
+#   ifdef ZEROFAULT
+    memset(previous+numberElements_,0,
+	   (maxElements-numberElements_)*sizeof(int)) ;
+#   endif
+    delete [] previous_;
+    previous_=previous;
+    int * next = new int [maxElements];
+    CoinMemcpyN(next_,numberElements_,next);
+#   ifdef ZEROFAULT
+    memset(next+numberElements_,0,(maxElements-numberElements_)*sizeof(int)) ;
+#   endif
+    delete [] next_;
+    next_=next;
+    maximumElements_=maxElements;
+  }
+}
+// Create list - for row list maxMajor is maximum rows
+void 
+CoinModelLinkedList::create(int maxMajor,int maxElements,
+                            int numberMajor,int /*numberMinor*/, int type,
+                            int numberElements, const CoinModelTriple * triples)
+{
+  maxMajor=CoinMax(maxMajor,maximumMajor_);
+  maxMajor=CoinMax(maxMajor,numberMajor);
+  maxElements=CoinMax(maxElements,maximumElements_);
+  maxElements=CoinMax(maxElements,numberElements);
+  type_=type;
+  assert (!previous_);
+  previous_ = new int [maxElements];
+  next_ = new int [maxElements];
+  maximumElements_=maxElements;
+  assert (maxElements>=numberElements);
+  assert (maxMajor>0&&!maximumMajor_);
+  first_ = new int[maxMajor+1];
+  last_ = new int[maxMajor+1];
+# ifdef ZEROFAULT
+  memset(previous_,0,maxElements*sizeof(int)) ;
+  memset(next_,0,maxElements*sizeof(int)) ;
+  memset(first_,0,(maxMajor+1)*sizeof(int)) ;
+  memset(last_,0,(maxMajor+1)*sizeof(int)) ;
+# endif
+  assert (numberElements>=0);
+  numberElements_=numberElements;
+  maximumMajor_ = maxMajor;
+  // do lists
+  int i;
+  for (i=0;i<numberMajor;i++) {
+    first_[i]=-1;
+    last_[i]=-1;
+  }
+  first_[maximumMajor_]=-1;
+  last_[maximumMajor_]=-1;
+  int freeChain=-1;
+  for (i=0;i<numberElements;i++) {
+    if (triples[i].column>=0) {
+      int iMajor;
+      if (!type_) {
+        // for rows
+        iMajor=static_cast<int> (rowInTriple(triples[i]));
+      } else {
+        iMajor=triples[i].column;
+      }
+      assert (iMajor<numberMajor);
+      if (first_[iMajor]>=0) {
+        // not first
+        int j=last_[iMajor];
+        next_[j]=i;
+        previous_[i]=j;
+      } else {
+        // first
+        first_[iMajor]=i;
+        previous_[i]=-1;
+      }
+      last_[iMajor]=i;
+    } else {
+      // on deleted list
+      if (freeChain>=0) {
+        next_[freeChain]=i;
+        previous_[i]=freeChain;
+      } else {
+        first_[maximumMajor_]=i;
+        previous_[i]=-1;
+      }
+      freeChain=i;
+    }
+  }
+  // Now clean up
+  if (freeChain>=0) {
+    next_[freeChain]=-1;
+    last_[maximumMajor_]=freeChain;
+  }
+  for (i=0;i<numberMajor;i++) {
+    int k=last_[i];
+    if (k>=0) {
+      next_[k]=-1;
+      last_[i]=k;
+    }
+  }
+  numberMajor_=numberMajor;
+}
+/* Adds to list - easy case i.e. add row to row list
+   Returns where chain starts
+*/
+int 
+CoinModelLinkedList::addEasy(int majorIndex, int numberOfElements, const int * indices,
+                             const double * elements, CoinModelTriple * triples,
+                             CoinModelHash2 & hash)
+{
+  assert (majorIndex<maximumMajor_);
+  if (numberOfElements+numberElements_>maximumElements_) {
+    resize(maximumMajor_,(3*(numberElements_+numberOfElements))/2+1000);
+  }
+  int first=-1;
+  if (majorIndex>=numberMajor_) {
+    for (int i=numberMajor_;i<=majorIndex;i++) {
+      first_[i]=-1;
+      last_[i]=-1;
+    }
+  }
+  if (numberOfElements) {
+    bool doHash = hash.maximumItems()!=0;
+    int lastFree=last_[maximumMajor_];
+    int last=last_[majorIndex];
+    for (int i=0;i<numberOfElements;i++) {
+      int put;
+      if (lastFree>=0) {
+        put=lastFree;
+        lastFree=previous_[lastFree];
+      } else {
+        put=numberElements_;
+        assert (put<maximumElements_);
+        numberElements_++;
+      }
+      if (type_==0) {
+        // row
+	setRowAndStringInTriple(triples[put],majorIndex,false);
+        triples[put].column=indices[i];
+      } else {
+        // column
+	setRowAndStringInTriple(triples[put],indices[i],false);
+        triples[put].column=majorIndex;
+      }
+      triples[put].value=elements[i];
+      if (doHash)
+        hash.addHash(put,static_cast<int> (rowInTriple(triples[put])),triples[put].column,triples);
+      if (last>=0) {
+        next_[last]=put;
+      } else {
+        first_[majorIndex]=put;
+      }
+      previous_[put]=last;
+      last=put;
+    }
+    next_[last]=-1;
+    if (last_[majorIndex]<0) {
+      // first in row
+      first = first_[majorIndex];
+    } else {
+      first = next_[last_[majorIndex]];
+    }
+    last_[majorIndex]=last;
+    if (lastFree>=0) {
+      next_[lastFree]=-1;
+      last_[maximumMajor_]=lastFree;
+    } else {
+      first_[maximumMajor_]=-1;
+      last_[maximumMajor_]=-1;
+    }
+  }
+  numberMajor_=CoinMax(numberMajor_,majorIndex+1);
+  return first;
+}
+/* Adds to list - hard case i.e. add row to column list
+ */
+void 
+CoinModelLinkedList::addHard(int minorIndex, int numberOfElements, const int * indices,
+                             const double * elements, CoinModelTriple * triples,
+                             CoinModelHash2 & hash)
+{
+  int lastFree=last_[maximumMajor_];
+  bool doHash = hash.maximumItems()!=0;
+  for (int i=0;i<numberOfElements;i++) {
+    int put;
+    if (lastFree>=0) {
+      put=lastFree;
+      lastFree=previous_[lastFree];
+    } else {
+      put=numberElements_;
+      assert (put<maximumElements_);
+      numberElements_++;
+    }
+    int other=indices[i];
+    if (type_==0) {
+      // row
+      setRowAndStringInTriple(triples[put],other,false);
+      triples[put].column=minorIndex;
+    } else {
+      // column
+      setRowAndStringInTriple(triples[put],minorIndex,false);
+      triples[put].column=other;
+    }
+    triples[put].value=elements[i];
+    if (doHash)
+      hash.addHash(put,static_cast<int> (rowInTriple(triples[put])),triples[put].column,triples);
+    if (other>=numberMajor_) {
+      // Need to fill in null values
+      fill(numberMajor_,other+1);
+      numberMajor_=other+1;
+    }
+    int last=last_[other];
+    if (last>=0) {
+      next_[last]=put;
+    } else {
+      first_[other]=put;
+    }
+    previous_[put]=last;
+    next_[put]=-1;
+    last_[other]=put;
+  }
+  if (lastFree>=0) {
+    next_[lastFree]=-1;
+    last_[maximumMajor_]=lastFree;
+  } else {
+    first_[maximumMajor_]=-1;
+    last_[maximumMajor_]=-1;
+  }
+}
+/* Adds to list - hard case i.e. add row to column list
+   This is when elements have been added to other copy
+*/
+void 
+CoinModelLinkedList::addHard(int first, const CoinModelTriple * triples,
+                             int firstFree, int lastFree,const int * next)
+{
+  first_[maximumMajor_]=firstFree;
+  last_[maximumMajor_]=lastFree;
+  int put=first;
+  int minorIndex=-1;
+  while (put>=0) {
+    assert (put<maximumElements_);
+    numberElements_=CoinMax(numberElements_,put+1);
+    int other;
+    if (type_==0) {
+      // row
+      other=rowInTriple(triples[put]);
+      if (minorIndex>=0)
+        assert(triples[put].column==minorIndex);
+      else
+        minorIndex=triples[put].column;
+    } else {
+      // column
+      other=triples[put].column;
+      if (minorIndex>=0)
+        assert(static_cast<int> (rowInTriple(triples[put]))==minorIndex);
+      else
+        minorIndex=rowInTriple(triples[put]);
+    }
+    assert (other<maximumMajor_);
+    if (other>=numberMajor_) {
+      // Need to fill in null values
+      fill (numberMajor_,other+1);
+      numberMajor_=other+1;
+    }
+    int last=last_[other];
+    if (last>=0) {
+      next_[last]=put;
+    } else {
+      first_[other]=put;
+    }
+    previous_[put]=last;
+    next_[put]=-1;
+    last_[other]=put;
+    put = next[put];
+  }
+}
+/* Deletes from list - same case i.e. delete row from row list
+*/
+void 
+CoinModelLinkedList::deleteSame(int which, CoinModelTriple * triples,
+                                CoinModelHash2 & hash, bool zapTriples)
+{
+  assert (which>=0);
+  if (which<numberMajor_) {
+    int lastFree=last_[maximumMajor_];
+    int put=first_[which];
+    first_[which]=-1;
+    while (put>=0) {
+      if (hash.numberItems()) {
+        // take out of hash
+        hash.deleteHash(put, static_cast<int> (rowInTriple(triples[put])),triples[put].column);
+      }
+      if (zapTriples) {
+        triples[put].column=-1;
+        triples[put].value=0.0;
+      }
+      if (lastFree>=0) {
+        next_[lastFree]=put;
+      } else {
+        first_[maximumMajor_]=put;
+      }
+      previous_[put]=lastFree;
+      lastFree=put;
+      put=next_[put];
+    }
+    if (lastFree>=0) {
+      next_[lastFree]=-1;
+      last_[maximumMajor_]=lastFree;
+    } else {
+      assert (last_[maximumMajor_]==-1);
+    }
+    last_[which]=-1;
+  }
+}
+/* Deletes from list - other case i.e. delete row from column list
+   This is when elements have been deleted from other copy
+*/
+void 
+CoinModelLinkedList::updateDeleted(int /*which*/, CoinModelTriple * triples,
+                                   CoinModelLinkedList & otherList)
+{
+  int firstFree = otherList.firstFree();
+  int lastFree = otherList.lastFree();
+  const int * previousOther = otherList.previous();
+  assert (maximumMajor_);
+  if (lastFree>=0) {
+    // First free should be same
+    if (first_[maximumMajor_]>=0)
+      assert (firstFree==first_[maximumMajor_]);
+    int last = last_[maximumMajor_];
+    first_[maximumMajor_]=firstFree;
+    // Maybe nothing to do
+    if (last_[maximumMajor_]==lastFree)
+      return;
+    last_[maximumMajor_]=lastFree;
+    int iMajor;
+    if (!type_) {
+      // for rows
+      iMajor=static_cast<int> (rowInTriple(triples[lastFree]));
+    } else {
+      iMajor=triples[lastFree].column;
+    }
+    if (first_[iMajor]>=0) {
+      // take out
+      int previousThis = previous_[lastFree];
+      int nextThis = next_[lastFree];
+      if (previousThis>=0&&previousThis!=last) {
+        next_[previousThis]=nextThis;
+#ifndef NDEBUG
+        int iTest;
+        if (!type_) {
+          // for rows
+          iTest=static_cast<int> (rowInTriple(triples[previousThis]));
+        } else {
+          iTest=triples[previousThis].column;
+        }
+        assert (triples[previousThis].column>=0);
+        assert (iTest==iMajor);
+#endif
+      } else {
+        first_[iMajor]=nextThis;
+      }
+      if (nextThis>=0) {
+        previous_[nextThis]=previousThis;
+#ifndef NDEBUG
+        int iTest;
+        if (!type_) {
+          // for rows
+          iTest=static_cast<int> (rowInTriple(triples[nextThis]));
+        } else {
+          iTest=triples[nextThis].column;
+        }
+        assert (triples[nextThis].column>=0);
+        assert (iTest==iMajor);
+#endif
+      } else {
+        last_[iMajor]=previousThis;
+      }
+    }
+    triples[lastFree].column=-1;
+    triples[lastFree].value=0.0;
+    // Do first (by which I mean last)
+    next_[lastFree]=-1;
+    int previous = previousOther[lastFree];
+    while (previous!=last) {
+      if (previous>=0) {
+        if (!type_) {
+          // for rows
+          iMajor=static_cast<int> (rowInTriple(triples[previous]));
+        } else {
+          iMajor=triples[previous].column;
+        }
+        if (first_[iMajor]>=0) {
+          // take out
+          int previousThis = previous_[previous];
+          int nextThis = next_[previous];
+          if (previousThis>=0&&previousThis!=last) {
+            next_[previousThis]=nextThis;
+#ifndef NDEBUG
+            int iTest;
+            if (!type_) {
+              // for rows
+              iTest=static_cast<int> (rowInTriple(triples[previousThis]));
+            } else {
+              iTest=triples[previousThis].column;
+            }
+            assert (triples[previousThis].column>=0);
+            assert (iTest==iMajor);
+#endif
+          } else {
+            first_[iMajor]=nextThis;
+          }
+          if (nextThis>=0) {
+            previous_[nextThis]=previousThis;
+#ifndef NDEBUG
+            int iTest;
+            if (!type_) {
+              // for rows
+              iTest=static_cast<int> (rowInTriple(triples[nextThis]));
+            } else {
+              iTest=triples[nextThis].column;
+            }
+            assert (triples[nextThis].column>=0);
+            assert (iTest==iMajor);
+#endif
+          } else {
+            last_[iMajor]=previousThis;
+          }
+        }
+        triples[previous].column=-1;
+        triples[previous].value=0.0;
+        next_[previous]=lastFree;
+      } else {
+        assert (lastFree==firstFree);
+      }
+      previous_[lastFree]=previous;
+      lastFree=previous;
+      previous = previousOther[lastFree];
+    }
+    if (last>=0) {
+      next_[previous]=lastFree;
+    } else {
+      assert (firstFree==lastFree);
+    }
+    previous_[lastFree]=previous;
+  }
+}
+/* Deletes one element from Row list
+ */
+void 
+CoinModelLinkedList::deleteRowOne(int position, CoinModelTriple * triples,
+                                  CoinModelHash2 & hash)
+{
+  int row=rowInTriple(triples[position]);
+  assert (row<numberMajor_);
+  if (hash.numberItems()) {
+    // take out of hash
+    hash.deleteHash(position, static_cast<int> (rowInTriple(triples[position])),triples[position].column);
+  }
+  int previous = previous_[position];
+  int next = next_[position];
+  // put on free list
+  int lastFree=last_[maximumMajor_];
+  if (lastFree>=0) {
+    next_[lastFree]=position;
+  } else {
+    first_[maximumMajor_]=position;
+    assert (last_[maximumMajor_]==-1);
+  }
+  last_[maximumMajor_]=position;
+  previous_[position]=lastFree;
+  next_[position]=-1;
+  // Now take out of row
+  if (previous>=0) {
+    next_[previous]=next;
+  } else {
+    first_[row]=next;
+  }
+  if (next>=0) {
+    previous_[next]=previous;
+  } else {
+    last_[row]=previous;
+  }
+}
+/* Update column list for one element when
+   one element deleted from row copy
+*/
+void 
+CoinModelLinkedList::updateDeletedOne(int position, const CoinModelTriple * triples)
+{
+  assert (maximumMajor_);
+  int column=triples[position].column;
+  assert (column>=0&&column<numberMajor_);
+  int previous = previous_[position];
+  int next = next_[position];
+  // put on free list
+  int lastFree=last_[maximumMajor_];
+  if (lastFree>=0) {
+    next_[lastFree]=position;
+  } else {
+    first_[maximumMajor_]=position;
+    assert (last_[maximumMajor_]==-1);
+  }
+  last_[maximumMajor_]=position;
+  previous_[position]=lastFree;
+  next_[position]=-1;
+  // Now take out of column
+  if (previous>=0) {
+    next_[previous]=next;
+  } else {
+    first_[column]=next;
+  }
+  if (next>=0) {
+    previous_[next]=previous;
+  } else {
+    last_[column]=previous;
+  }
+}
+// Fills first,last with -1
+void 
+CoinModelLinkedList::fill(int first,int last)
+{
+  for (int i=first;i<last;i++) {
+    first_[i]=-1;
+    last_[i]=-1;
+  }
+}
+/* Puts in free list from other list */
+void 
+CoinModelLinkedList::synchronize(CoinModelLinkedList & other)
+{
+  int first = other.first_[other.maximumMajor_];
+  first_[maximumMajor_]=first;
+  int last = other.last_[other.maximumMajor_];
+  last_[maximumMajor_]=last;
+  int put=first;
+  while (put>=0) {
+    previous_[put]=other.previous_[put];
+    next_[put]=other.next_[put];
+    put = next_[put];
+  }
+}
+// Checks that links are consistent
+void 
+CoinModelLinkedList::validateLinks(const CoinModelTriple * triples) const
+{
+  char * mark = new char[maximumElements_];
+  memset(mark,0,maximumElements_);
+  int lastElement=-1;
+  int i;
+  for ( i=0;i<numberMajor_;i++) {
+    int position = first_[i];
+#ifndef NDEBUG
+    int lastPosition=-1;
+#endif
+    while (position>=0) {
+      assert (position==first_[i] || next_[previous_[position]]==position);
+      assert (type_ || i == static_cast<int> (rowInTriple(triples[position])));  // i == iMajor for rows
+      assert (!type_ || i == triples[position].column);  // i == iMajor
+      assert (triples[position].column>=0);
+      mark[position]=1;
+      lastElement = CoinMax(lastElement,position);
+#ifndef NDEBUG
+      lastPosition=position;
+#endif
+      position = next_[position];
+    }
+    assert (lastPosition==last_[i]);
+  }
+  for (i=0;i<=lastElement;i++) {
+    if (!mark[i])
+      assert(triples[i].column==-1);
+  }
+  delete [] mark;
+}
diff --git a/cbits/coin/CoinModelUseful.hpp b/cbits/coin/CoinModelUseful.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinModelUseful.hpp
@@ -0,0 +1,441 @@
+/* $Id: CoinModelUseful.hpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinModelUseful_H
+#define CoinModelUseful_H
+
+
+#include <cstdlib>
+#include <cmath>
+#include <cassert>
+#include <cfloat>
+#include <cstring>
+#include <cstdio>
+#include <iostream>
+
+
+#include "CoinPragma.hpp"
+
+/**
+   This is for various structures/classes needed by CoinModel.
+
+   CoinModelLink
+   CoinModelLinkedList
+   CoinModelHash
+*/
+/// for going through row or column
+
+class CoinModelLink {
+  
+public:
+  /**@name Constructors, destructor */
+   //@{
+   /** Default constructor. */
+   CoinModelLink();
+   /** Destructor */
+   ~CoinModelLink();
+   //@}
+
+   /**@name Copy method */
+   //@{
+   /** The copy constructor. */
+   CoinModelLink(const CoinModelLink&);
+  /// =
+   CoinModelLink& operator=(const CoinModelLink&);
+   //@}
+
+   /**@name Sets and gets method */
+   //@{
+  /// Get row
+  inline int row() const
+  { return row_;}
+  /// Get column
+  inline int column() const
+  { return column_;}
+  /// Get value
+  inline double value() const
+  { return value_;}
+  /// Get value
+  inline double element() const
+  { return value_;}
+  /// Get position
+  inline int position() const
+  { return position_;}
+  /// Get onRow
+  inline bool onRow() const
+  { return onRow_;}
+  /// Set row
+  inline void setRow(int row)
+  { row_=row;}
+  /// Set column
+  inline void setColumn(int column)
+  { column_=column;}
+  /// Set value
+  inline void setValue(double value)
+  { value_=value;}
+  /// Set value
+  inline void setElement(double value)
+  { value_=value;}
+  /// Set position
+  inline void setPosition(int position)
+  { position_=position;}
+  /// Set onRow
+  inline void setOnRow(bool onRow)
+  { onRow_=onRow;}
+   //@}
+
+private:
+  /**@name Data members */
+  //@{
+  /// Row
+  int row_;
+  /// Column
+  int column_;
+  /// Value as double
+  double value_;
+  /// Position in data
+  int position_;
+  /// If on row chain
+  bool onRow_;
+  //@}
+};
+
+/// for linked lists
+// for specifying triple
+typedef struct {
+  // top bit is nonzero if string
+  // rest is row
+  unsigned int row;
+  //CoinModelRowIndex row;
+  int column;
+  double value; // If string then index into strings
+} CoinModelTriple;
+inline int rowInTriple(const CoinModelTriple & triple)
+{ return triple.row&0x7fffffff;}
+inline void setRowInTriple(CoinModelTriple & triple,int iRow)
+{ triple.row = iRow|(triple.row&0x80000000);}
+inline bool stringInTriple(const CoinModelTriple & triple)
+{ return (triple.row&0x80000000)!=0;}
+inline void setStringInTriple(CoinModelTriple & triple,bool string)
+{ triple.row = (string ? 0x80000000 : 0)|(triple.row&0x7fffffff);}
+inline void setRowAndStringInTriple(CoinModelTriple & triple,
+				    int iRow,bool string)
+{ triple.row = (string ? 0x80000000 : 0)|iRow;}
+/// for names and hashing
+// for hashing
+typedef struct {
+  int index, next;
+} CoinModelHashLink;
+
+/* Function type.  */
+typedef double (*func_t) (double);
+
+/// For string evaluation
+/* Data type for links in the chain of symbols.  */
+struct symrec
+{
+  char *name;  /* name of symbol */
+  int type;    /* type of symbol: either VAR or FNCT */
+  union
+  {
+    double var;      /* value of a VAR */
+    func_t fnctptr;  /* value of a FNCT */
+  } value;
+  struct symrec *next;  /* link field */
+};
+     
+typedef struct symrec symrec;
+
+class CoinYacc {
+private:
+  CoinYacc(const CoinYacc& rhs);
+  CoinYacc& operator=(const CoinYacc& rhs);
+
+public:
+  CoinYacc() : symtable(NULL), symbuf(NULL), length(0), unsetValue(0) {}
+  ~CoinYacc()
+  {
+    if (length) {
+      free(symbuf);
+      symbuf = NULL;
+    }
+    symrec* s = symtable;
+    while (s) {
+      free(s->name);
+      symtable = s;
+      s = s->next;
+      free(symtable);
+    }
+  }
+    
+public:
+  symrec * symtable;
+  char * symbuf;
+  int length;
+  double unsetValue;
+};
+
+class CoinModelHash {
+  
+public:
+  /**@name Constructors, destructor */
+  //@{
+  /** Default constructor. */
+  CoinModelHash();
+  /** Destructor */
+  ~CoinModelHash();
+  //@}
+  
+  /**@name Copy method */
+  //@{
+  /** The copy constructor. */
+  CoinModelHash(const CoinModelHash&);
+  /// =
+  CoinModelHash& operator=(const CoinModelHash&);
+  //@}
+
+  /**@name sizing (just increases) */
+  //@{
+  /// Resize hash (also re-hashs)
+  void resize(int maxItems,bool forceReHash=false);
+  /// Number of items i.e. rows if just row names
+  inline int numberItems() const
+  { return numberItems_;}
+  /// Set number of items
+  void setNumberItems(int number);
+  /// Maximum number of items
+  inline int maximumItems() const
+  { return maximumItems_;}
+  /// Names
+  inline const char *const * names() const
+  { return names_;}
+  //@}
+
+  /**@name hashing */
+  //@{
+  /// Returns index or -1
+  int hash(const char * name) const;
+  /// Adds to hash
+  void addHash(int index, const char * name);
+  /// Deletes from hash
+  void deleteHash(int index);
+  /// Returns name at position (or NULL)
+  const char * name(int which) const;
+  /// Returns non const name at position (or NULL)
+  char * getName(int which) const;
+  /// Sets name at position (does not create)
+  void setName(int which,char * name ) ;
+  /// Validates
+  void validateHash() const;
+private:
+  /// Returns a hash value
+  int hashValue(const char * name) const;
+public:
+  //@}
+private:
+  /**@name Data members */
+  //@{
+  /// Names
+  char ** names_;
+  /// hash
+  CoinModelHashLink * hash_;
+  /// Number of items 
+  int numberItems_;
+  /// Maximum number of items
+  int maximumItems_;
+  /// Last slot looked at
+  int lastSlot_;
+  //@}
+};
+/// For int,int hashing
+class CoinModelHash2 {
+  
+public:
+  /**@name Constructors, destructor */
+  //@{
+  /** Default constructor. */
+  CoinModelHash2();
+  /** Destructor */
+  ~CoinModelHash2();
+  //@}
+  
+  /**@name Copy method */
+  //@{
+  /** The copy constructor. */
+  CoinModelHash2(const CoinModelHash2&);
+  /// =
+  CoinModelHash2& operator=(const CoinModelHash2&);
+  //@}
+
+  /**@name sizing (just increases) */
+  //@{
+  /// Resize hash (also re-hashs)
+  void resize(int maxItems, const CoinModelTriple * triples,bool forceReHash=false);
+  /// Number of items
+  inline int numberItems() const
+  { return numberItems_;}
+  /// Set number of items
+  void setNumberItems(int number);
+  /// Maximum number of items
+  inline int maximumItems() const
+  { return maximumItems_;}
+  //@}
+
+  /**@name hashing */
+  //@{
+  /// Returns index or -1
+  int hash(int row, int column, const CoinModelTriple * triples) const;
+  /// Adds to hash
+  void addHash(int index, int row, int column, const CoinModelTriple * triples);
+  /// Deletes from hash
+  void deleteHash(int index, int row, int column);
+private:
+  /// Returns a hash value
+  int hashValue(int row, int column) const;
+public:
+  //@}
+private:
+  /**@name Data members */
+  //@{
+  /// hash
+  CoinModelHashLink * hash_;
+  /// Number of items 
+  int numberItems_;
+  /// Maximum number of items
+  int maximumItems_;
+  /// Last slot looked at
+  int lastSlot_;
+  //@}
+};
+class CoinModelLinkedList {
+  
+public:
+  /**@name Constructors, destructor */
+  //@{
+  /** Default constructor. */
+  CoinModelLinkedList();
+  /** Destructor */
+  ~CoinModelLinkedList();
+  //@}
+  
+  /**@name Copy method */
+  //@{
+  /** The copy constructor. */
+  CoinModelLinkedList(const CoinModelLinkedList&);
+  /// =
+  CoinModelLinkedList& operator=(const CoinModelLinkedList&);
+  //@}
+
+  /**@name sizing (just increases) */
+  //@{
+  /** Resize list - for row list maxMajor is maximum rows.
+  */
+  void resize(int maxMajor,int maxElements);
+  /** Create list - for row list maxMajor is maximum rows.
+      type 0 row list, 1 column list
+  */
+  void create(int maxMajor,int maxElements,
+              int numberMajor, int numberMinor,
+              int type,
+              int numberElements, const CoinModelTriple * triples);
+  /// Number of major items i.e. rows if just row links
+  inline int numberMajor() const
+  { return numberMajor_;}
+  /// Maximum number of major items i.e. rows if just row links
+  inline int maximumMajor() const
+  { return maximumMajor_;}
+  /// Number of elements
+  inline int numberElements() const
+  { return numberElements_;}
+  /// Maximum number of elements
+  inline int maximumElements() const
+  { return maximumElements_;}
+  /// First on free chain
+  inline int firstFree() const
+  { return first_[maximumMajor_];}
+  /// Last on free chain
+  inline int lastFree() const
+  { return last_[maximumMajor_];}
+  /// First on  chain
+  inline int first(int which) const
+  { return first_[which];}
+  /// Last on  chain
+  inline int last(int which) const
+  { return last_[which];}
+  /// Next array
+  inline const int * next() const
+  { return next_;}
+  /// Previous array
+  inline const int * previous() const
+  { return previous_;}
+  //@}
+
+  /**@name does work */
+  //@{
+  /** Adds to list - easy case i.e. add row to row list
+      Returns where chain starts
+  */
+  int addEasy(int majorIndex, int numberOfElements, const int * indices,
+              const double * elements, CoinModelTriple * triples,
+              CoinModelHash2 & hash);
+  /** Adds to list - hard case i.e. add row to column list
+  */
+  void addHard(int minorIndex, int numberOfElements, const int * indices,
+               const double * elements, CoinModelTriple * triples,
+               CoinModelHash2 & hash);
+  /** Adds to list - hard case i.e. add row to column list
+      This is when elements have been added to other copy
+  */
+  void addHard(int first, const CoinModelTriple * triples,
+               int firstFree, int lastFree,const int * nextOther);
+  /** Deletes from list - same case i.e. delete row from row list
+  */
+  void deleteSame(int which, CoinModelTriple * triples,
+                 CoinModelHash2 & hash, bool zapTriples);
+  /** Deletes from list - other case i.e. delete row from column list
+      This is when elements have been deleted from other copy
+  */
+  void updateDeleted(int which, CoinModelTriple * triples,
+                     CoinModelLinkedList & otherList);
+  /** Deletes one element from Row list
+  */
+  void deleteRowOne(int position, CoinModelTriple * triples,
+                 CoinModelHash2 & hash);
+  /** Update column list for one element when
+      one element deleted from row copy
+  */
+  void updateDeletedOne(int position, const CoinModelTriple * triples);
+  /// Fills first,last with -1
+  void fill(int first,int last);
+  /** Puts in free list from other list */
+  void synchronize(CoinModelLinkedList & other);
+  /// Checks that links are consistent
+  void validateLinks(const CoinModelTriple * triples) const;
+  //@}
+private:
+  /**@name Data members */
+  //@{
+  /// Previous - maximumElements long
+  int * previous_;
+  /// Next - maximumElements long
+  int * next_;
+  /// First - maximumMajor+1 long (last free element chain)
+  int * first_;
+  /// Last - maximumMajor+1 long (last free element chain)
+  int * last_;
+  /// Number of major items i.e. rows if just row links
+  int numberMajor_;
+  /// Maximum number of major items i.e. rows if just row links
+  int maximumMajor_;
+  /// Number of elements
+  int numberElements_;
+  /// Maximum number of elements
+  int maximumElements_;
+  /// 0 row list, 1 column list
+  int type_;
+  //@}
+};
+
+#endif
diff --git a/cbits/coin/CoinModelUseful2.cpp b/cbits/coin/CoinModelUseful2.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinModelUseful2.cpp
@@ -0,0 +1,1557 @@
+/* $Id: CoinModelUseful2.cpp 1395 2011-03-01 10:33:12Z forrest $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+/* A Bison parser, made by GNU Bison 1.875c.  */
+
+// License sounds scary but see special exception so has no problems
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Written by Richard Stallman by simplifying the original so called
+   ``semantic'' parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     NUM = 258,
+     VAR = 259,
+     FNCT = 260,
+     NEG = 261
+   };
+#endif
+#define NUM 258
+#define VAR 259
+#define FNCT 260
+#define NEG 261
+
+#include <cstdlib>
+
+#include "CoinModel.hpp"
+#include "CoinHelperFunctions.hpp"
+
+
+/* Copy the first part of user declarations.  */
+
+#include <cmath>  /* For math functions, cos(), sin(), etc.  */
+
+#include <cstdio>
+#include <ctype.h>
+#include <cstring>
+#include <cassert>
+static void yyerror (char const *);
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+typedef union YYSTYPE {
+  double    val;   /* For returning numbers.  */
+  symrec  *tptr;   /* For returning symbol-table pointers.  */
+} YYSTYPE;
+/* Line 191 of yacc.c.  */
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 214 of yacc.c.  */
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   define YYSTACK_ALLOC alloca
+#  endif
+# else
+#  if defined (alloca) || defined (_ALLOCA_H)
+#   define YYSTACK_ALLOC alloca
+#  else
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning. */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+#  if defined (__STDC__) || defined (__cplusplus)
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   define YYSIZE_T size_t
+#  endif
+#  define YYSTACK_ALLOC malloc
+#  define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+	 || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short yyss;
+  YYSTYPE yyvs;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short) + sizeof (YYSTYPE))				\
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined (__GNUC__) && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  register YYSIZE_T yyi;		\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+typedef signed char yysigned_char;
+#else
+typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL  2
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   64
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS  16
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS  4
+/* YYNRULES -- Number of rules. */
+#define YYNRULES  17
+/* YYNRULES -- Number of states. */
+#define YYNSTATES  32
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   261
+
+#define YYTRANSLATE(YYX) 						\
+  (static_cast<unsigned int> ((YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK))
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const unsigned char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+      13,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+      14,    15,     9,     8,     2,     7,     2,    10,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     6,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    12,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,    11
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const unsigned char yyprhs[] =
+{
+       0,     0,     3,     4,     7,     9,    12,    15,    17,    19,
+      23,    28,    32,    36,    40,    44,    47,    51
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+      17,     0,    -1,    -1,    17,    18,    -1,    13,    -1,    19,
+      13,    -1,     1,    13,    -1,     3,    -1,     4,    -1,     4,
+       6,    19,    -1,     5,    14,    19,    15,    -1,    19,     8,
+      19,    -1,    19,     7,    19,    -1,    19,     9,    19,    -1,
+      19,    10,    19,    -1,     7,    19,    -1,    19,    12,    19,
+      -1,    14,    19,    15,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const unsigned char yyrline[] =
+{
+       0,    23,    23,    24,    28,    29,    30,    33,    34,    35,
+      36,    37,    38,    39,    40,    41,    42,    43
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "NUM", "VAR", "FNCT", "'='", "'-'",
+  "'+'", "'*'", "'/'", "NEG", "'^'", "'\\n'", "'('", "')'", "$accept",
+  "input", "line", "exp", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const unsigned short yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,    61,    45,    43,    42,
+      47,   261,    94,    10,    40,    41
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const unsigned char yyr1[] =
+{
+       0,    16,    17,    17,    18,    18,    18,    19,    19,    19,
+      19,    19,    19,    19,    19,    19,    19,    19
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const unsigned char yyr2[] =
+{
+       0,     2,     0,     2,     1,     2,     2,     1,     1,     3,
+       4,     3,     3,     3,     3,     2,     3,     3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const unsigned char yydefact[] =
+{
+       2,     0,     1,     0,     7,     8,     0,     0,     4,     0,
+       3,     0,     6,     0,     0,    15,     0,     0,     0,     0,
+       0,     0,     5,     9,     0,    17,    12,    11,    13,    14,
+      16,    10
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+      -1,     1,    10,    11
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -13
+static const yysigned_char yypact[] =
+{
+     -13,    15,   -13,   -12,   -13,    -3,   -10,    20,   -13,    20,
+     -13,    41,   -13,    20,    20,    -4,    23,    20,    20,    20,
+      20,    20,   -13,    48,    32,   -13,    52,    52,    -4,    -4,
+      -4,   -13
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yysigned_char yypgoto[] =
+{
+     -13,   -13,   -13,    -7
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+      15,    12,    16,    13,    14,     0,    23,    24,    21,     0,
+      26,    27,    28,    29,    30,     2,     3,     0,     4,     5,
+       6,     0,     7,     4,     5,     6,     0,     7,     8,     9,
+      17,    18,    19,    20,     9,    21,     0,     0,    25,    17,
+      18,    19,    20,     0,    21,     0,     0,    31,    17,    18,
+      19,    20,     0,    21,    22,    17,    18,    19,    20,     0,
+      21,    19,    20,     0,    21
+};
+
+static const yysigned_char yycheck[] =
+{
+       7,    13,     9,     6,    14,    -1,    13,    14,    12,    -1,
+      17,    18,    19,    20,    21,     0,     1,    -1,     3,     4,
+       5,    -1,     7,     3,     4,     5,    -1,     7,    13,    14,
+       7,     8,     9,    10,    14,    12,    -1,    -1,    15,     7,
+       8,     9,    10,    -1,    12,    -1,    -1,    15,     7,     8,
+       9,    10,    -1,    12,    13,     7,     8,     9,    10,    -1,
+      12,     9,    10,    -1,    12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const unsigned char yystos[] =
+{
+       0,    17,     0,     1,     3,     4,     5,     7,    13,    14,
+      18,    19,    13,     6,    14,    19,    19,     7,     8,     9,
+      10,    12,    13,    19,    19,    15,    19,    19,    19,    19,
+      19,    15
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { 								\
+      yyerror ("syntax error: cannot back up",error);\
+      YYERROR;							\
+    }								\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+   are run).  */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)		\
+   ((Current).first_line   = (Rhs)[1].first_line,	\
+    (Current).first_column = (Rhs)[1].first_column,	\
+    (Current).last_line    = (Rhs)[N].last_line,	\
+    (Current).last_column  = (Rhs)[N].last_column)
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (0)
+
+# define YYDSYMPRINT(Args)			\
+do {						\
+  if (yydebug)					\
+    yysymprint Args;				\
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location)		\
+do {								\
+  if (yydebug)							\
+    {								\
+      YYFPRINTF (stderr, "%s ", Title);				\
+      yysymprint (stderr, 					\
+                  Token, Value);	\
+      YYFPRINTF (stderr, "\n");					\
+    }								\
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    short *bottom;
+    short *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (/* Nothing. */; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+    int yyrule;
+#endif
+{
+  int yyi;
+  unsigned int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+             yyrule - 1, yylno);
+  /* Print the symbols being reduced, and their result.  */
+  for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+    YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+  YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (Rule);		\
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+static int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  register const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  register char *yyd = yydest;
+  register const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (yytype < YYNTOKENS)
+    {
+      YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+      YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+    }
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+  YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  switch (yytype)
+    {
+
+      default:
+        break;
+    }
+}
+
+
+
+
+static     symrec *
+     putsym ( symrec * & symtable, char const *sym_name, int sym_type)
+     {
+       symrec *ptr;
+       ptr = reinterpret_cast<symrec *> (malloc (sizeof (symrec)));
+       ptr->name = reinterpret_cast<char *> (malloc (strlen (sym_name) + 1));
+       strcpy (ptr->name,sym_name);
+       ptr->type = sym_type;
+       ptr->value.var = 0; /* Set value to 0 even if fctn.  */
+       ptr->next = reinterpret_cast<struct symrec *>(symtable);
+       symtable = ptr;
+       return ptr;
+     }
+     
+static     symrec *
+     getsym ( symrec *symtable,char const *sym_name)
+     {
+       symrec *ptr;
+       for (ptr = symtable; ptr != NULL;
+            ptr = reinterpret_cast<symrec *>(ptr->next))
+         if (strcmp (ptr->name,sym_name) == 0)
+           return ptr;
+       return 0;
+     }
+     
+static     void
+     freesym ( symrec *symtable)
+     {
+       symrec *ptr;
+       for (ptr = symtable; ptr != NULL;) {
+         free (ptr->name);
+         symrec * ptrNext = reinterpret_cast<symrec *> (ptr->next) ;
+         free (ptr);
+         ptr=ptrNext;
+       }
+     }
+     
+     /* Called by yyparse on error.  */
+static     void
+yyerror (char const * /*s*/)
+     {
+       // Put back if needed
+       //printf ("%s\n", s);
+     }
+     
+     struct init
+     {
+       char const *fname;
+       double (*fnct) (double);
+     };
+
+     inline double sin_wrapper (double x) { return sin(x) ; }
+     inline double cos_wrapper (double x) { return cos(x) ; }
+     inline double atan_wrapper (double x) { return atan(x) ; }
+     inline double log_wrapper (double x) { return log(x) ; }
+     inline double exp_wrapper (double x) { return exp(x) ; }
+     inline double sqrt_wrapper (double x) { return sqrt(x) ; }
+     inline double fabs_wrapper (double x) { return fabs(x) ; }
+
+     struct init const arith_fncts[] =
+     {
+       {"sin",  sin_wrapper},
+       {"cos",  cos_wrapper},
+       {"atan", atan_wrapper},
+       {"ln",   log_wrapper},
+       {"exp",  exp_wrapper},
+       {"sqrt", sqrt_wrapper},
+       {"fabs", fabs_wrapper},
+       {"abs", fabs_wrapper},
+       {NULL, 0}
+     };
+     
+     /* The symbol table: a chain of `struct symrec'.  */
+     
+     /* Put arithmetic functions in table.  */
+static     void
+     init_table ( symrec * &symtable)
+     {
+       int i;
+       symrec *ptr;
+       for (i = 0; arith_fncts[i].fname != NULL; i++)
+         {
+           ptr = putsym ( symtable,arith_fncts[i].fname, FNCT);
+           ptr->value.fnctptr = arith_fncts[i].fnct;
+         }
+     }
+     
+
+     
+static     int
+     yylex ( symrec *&symtable, const char * line, int * position, char * & symbuf, int & length,
+             const double * associated, const CoinModelHash & string,
+             int & error, double unsetValue,
+                        YYSTYPE &yylval)
+     {
+       int c;
+       int ipos=*position;
+       /* Ignore white space, get first nonwhite character.  */
+       while ((c = line[ipos]) == ' ' || c == '\t')
+         ipos++;
+     
+       if (c == EOF) 
+         return 0;
+     
+       /* Char starts a number => parse the number.         */
+       if (c == '.' || isdigit (c))
+         {
+           sscanf (line+ipos,"%lf", &yylval.val);
+           /* Get first white or other character.  */
+           int nE=0;
+           int nDot=0;
+           if (c=='.')
+             nDot=1;
+           ipos++; // skip possible sign
+           while (true) {
+             c=line[ipos];
+             if (isdigit(c)) {
+             } else if (!nDot&&c=='.') {
+               nDot=1;
+             } else if (c=='e'&&!nE) {
+               nE=1;
+               if (line[ipos+1]=='+'||line[ipos+1]=='-')
+                 ipos++;
+             } else {
+               break;
+             }
+             ipos++;
+           }
+           *position = ipos;
+           return NUM;
+         }
+     
+       /* Char starts an identifier => read the name.       */
+       if (isalpha (c))
+         {
+           symrec *s;
+           int i;
+     
+           /* Initially make the buffer long enough
+              for a 40-character symbol name.  */
+           if (length == 0)
+             length = 40, symbuf = reinterpret_cast<char *>(malloc (length + 1));
+     
+           i = 0;
+           do
+             {
+               /* If buffer is full, make it bigger.        */
+               if (i == length)
+                 {
+                   length *= 2;
+                   symbuf = reinterpret_cast<char *> (realloc (symbuf, length + 1));
+                 }
+               /* Add this character to the buffer.         */
+               symbuf[i++] = static_cast<char>(c);
+               /* Get another character.                    */
+               ipos++;
+               c = line[ipos];
+             }
+           while (isalnum (c));
+     
+           symbuf[i] = '\0';
+     
+           s = getsym ( symtable, symbuf);
+           if (s == 0) {
+             // Find in strings
+             int find = string.hash(symbuf);
+             double value;
+             if (find>=0) {
+               value = associated[find];
+               //printf("symbol %s found with value of %g\n",symbuf,value);
+               if (value==unsetValue)
+                 error=CoinMax(error,1);
+             } else {
+               //printf("unknown symbol %s\n",symbuf);
+               value=unsetValue;
+               error=3;
+             }
+             s = putsym (symtable, symbuf, VAR);
+             s->value.var=value;
+           }
+           yylval.tptr = s;
+           *position = ipos;
+           return s->type;
+         }
+     
+       /* Any other character is a token by itself.        */
+       if (c) {
+         *position = ipos+1;
+         return c;
+       } else {
+         *position = ipos;
+         return 10;
+       }
+     }
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+static double yyparse ( symrec *& symtable, const char * line, char * & symbuf, int & length,
+                        const double * associated, const CoinModelHash & string, int & error,
+                        double unsetValue,
+                        int & yychar, YYSTYPE &yylval, int & yynerrs)
+{
+  
+  int position=0;
+  int nEof=0; // Number of time send of string
+  register int yystate;
+  register int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  short	yyssa[YYINITDEPTH];
+  short *yyss = yyssa;
+  register short *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule.  */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = static_cast<short>(yystate);
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack. Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	short *yyss1 = yyss;
+
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow ("parser stack overflow",
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyoverflowlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyoverflowlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	short *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  reinterpret_cast<union yyalloc *> (YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)));
+	if (! yyptr)
+	  goto yyoverflowlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = yylex( symtable, line,&position,symbuf,length,
+                      associated,string,error,unsetValue,yylval);
+      if (yychar==10) {
+        if (nEof)
+          yychar=0;
+        nEof++;
+      }
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = static_cast<int>(YYTRANSLATE (yychar));
+      YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+  YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 5:
+          { //printf ("\t%.10g\n", yyvsp[-1].val);
+    return yyvsp[-1].val;}
+    break;
+
+  case 6:
+    { yyerrok;                  ;}
+    break;
+
+  case 7:
+    { yyval.val = yyvsp[0].val;                         ;}
+    break;
+
+  case 8:
+    { yyval.val = yyvsp[0].tptr->value.var;              ;}
+    break;
+
+  case 9:
+    { yyval.val = yyvsp[0].val; yyvsp[-2].tptr->value.var = yyvsp[0].val;     ;}
+    break;
+
+  case 10:
+    { yyval.val = (*(yyvsp[-3].tptr->value.fnctptr))(yyvsp[-1].val); ;}
+    break;
+
+  case 11:
+    { yyval.val = yyvsp[-2].val + yyvsp[0].val;                    ;}
+    break;
+
+  case 12:
+    { yyval.val = yyvsp[-2].val - yyvsp[0].val;                    ;}
+    break;
+
+  case 13:
+    { yyval.val = yyvsp[-2].val * yyvsp[0].val;                    ;}
+    break;
+
+  case 14:
+    { yyval.val = yyvsp[-2].val / yyvsp[0].val;                    ;}
+    break;
+
+  case 15:
+    { yyval.val = -yyvsp[0].val;                        ;}
+    break;
+
+  case 16:
+    { yyval.val = pow (yyvsp[-2].val, yyvsp[0].val);               ;}
+    break;
+
+  case 17:
+    { yyval.val = yyvsp[-1].val;                         ;}
+    break;
+
+
+    }
+
+/* Line 993 of yacc.c.  */
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+
+
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      error = CoinMax(error,2);
+      ++yynerrs;
+#if YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (YYPACT_NINF < yyn && yyn < YYLAST)
+	{
+	  YYSIZE_T yysize = 0;
+	  int yytype = YYTRANSLATE (yychar);
+	  const char* yyprefix;
+	  char *yymsg;
+	  int yyx;
+
+	  /* Start YYX at -YYN if negative to avoid negative indexes in
+	     YYCHECK.  */
+	  int yyxbegin = yyn < 0 ? -yyn : 0;
+
+	  /* Stay within bounds of both yycheck and yytname.  */
+	  int yychecklim = YYLAST - yyn;
+	  int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+	  int yycount = 0;
+
+	  yyprefix = ", expecting ";
+	  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	      {
+		yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+		yycount += 1;
+		if (yycount == 5)
+		  {
+		    yysize = 0;
+		    break;
+		  }
+	      }
+	  yysize += (sizeof ("syntax error, unexpected ")
+		     + yystrlen (yytname[yytype]));
+	  yymsg = (char *) YYSTACK_ALLOC (yysize);
+	  if (yymsg != 0)
+	    {
+	      char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+	      yyp = yystpcpy (yyp, yytname[yytype]);
+
+	      if (yycount < 5)
+		{
+		  yyprefix = ", expecting ";
+		  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+		    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+		      {
+			yyp = yystpcpy (yyp, yyprefix);
+			yyp = yystpcpy (yyp, yytname[yyx]);
+			yyprefix = " or ";
+		      }
+		}
+	      yyerror (yymsg);
+	      YYSTACK_FREE (yymsg);
+	    }
+	  else
+	    yyerror ("syntax error; also virtual memory exhausted");
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror ("syntax error");
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+          /* If at end of input, pop the error token,
+	     then the rest of the stack, then return failure.  */
+	  if (yychar == YYEOF)
+	     for (;;)
+	       {
+		 YYPOPSTACK;
+		 if (yyssp == yyss)
+		   YYABORT;
+		 YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+		 yydestruct (yystos[*yyssp], yyvsp);
+	       }
+        }
+      else
+	{
+	  YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+	  yydestruct (yytoken, &yylval);
+	  yychar = YYEMPTY;
+
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+  /* Pacify GCC when the user code never invokes YYERROR and the label
+     yyerrorlab therefore never appears in user code.  */
+  if (0)
+     goto yyerrorlab;
+#endif
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+      yydestruct (yystos[yystate], yyvsp);
+      YYPOPSTACK;
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  YYDPRINTF ((stderr, "Shifting error token, "));
+
+  *++yyvsp = yylval;
+
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here.  |
+`----------------------------------------------*/
+yyoverflowlab:
+  yyerror ("parser stack overflow");
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+
+double
+CoinModel::getDoubleFromString(CoinYacc & info,const char * string)
+{
+  if (!info.length) {
+    info.symtable=NULL;
+    info.symbuf=NULL;
+    init_table ( info.symtable);
+    info.unsetValue=unsetValue();
+  }
+  int error=0;
+
+  // Here to make thread safe
+  /* The lookahead symbol.  */
+  int yychar;
+  
+  /* The semantic value of the lookahead symbol.  */
+  YYSTYPE yylval;
+  
+  /* Number of syntax errors so far.  */
+  int yynerrs;
+
+  double value = yyparse ( info.symtable, string,info.symbuf,info.length,
+                           associated_,string_,error,info.unsetValue,
+                           yychar, yylval,  yynerrs);
+
+  if (error){
+    // 1 means strings found but unset value
+    // 2 syntax error
+    // 3 string not found
+    if (logLevel_>=1)
+      printf("string %s returns value %g and error-code %d\n",
+             string,value,error);
+    value = info.unsetValue;
+  } else if (logLevel_>=2) {
+    printf("%s computes as %g\n",string,value);
+  }
+  return value;
+}
+// Frees value memory
+void 
+CoinModel::freeStringMemory(CoinYacc & info)
+{
+  freesym( info.symtable);
+  free(info.symbuf);
+  info.length=0;
+}
+// Adds one string, returns index
+static int 
+addString(CoinModelHash & stringX, const char * string)
+{
+  int position = stringX.hash(string);
+  if (position<0) {
+    position = stringX.numberItems();
+    stringX.addHash(position,string);
+  }
+  return position;
+}
+double
+getFunctionValueFromString(const char * string, const char * x, double xValue)
+{
+  CoinYacc info;
+  double unset = -1.23456787654321e-97;
+  info.length=0;
+  info.symtable=NULL;
+  info.symbuf=NULL;
+  init_table ( info.symtable);
+  info.unsetValue=unset;
+  int error=0;
+
+  double associated[2];
+  associated[0]=xValue;
+  associated[1]=unset;
+
+  CoinModelHash stringX;
+  addString(stringX,x);
+  addString(stringX,string);
+  
+
+  // Here to make thread safe
+  /* The lookahead symbol.  */
+  int yychar;
+  
+  /* The semantic value of the lookahead symbol.  */
+  YYSTYPE yylval;
+  
+  /* Number of syntax errors so far.  */
+  int yynerrs;
+
+  double value = yyparse ( info.symtable, string,info.symbuf,info.length,
+                           associated,stringX,error,info.unsetValue,
+                           yychar, yylval,  yynerrs);
+
+  int logLevel_=2;
+  if (error){
+    // 1 means strings found but unset value
+    // 2 syntax error
+    // 3 string not found
+    if (logLevel_>=1)
+    printf("string %s returns value %g and error-code %d\n",
+	   string,value,error);
+    value = unset;
+  } else if (logLevel_>=2) {
+    printf("%s computes as %g\n",string,value);
+  }
+  freesym( info.symtable);
+  free(info.symbuf);
+  return value;
+}
+
+
diff --git a/cbits/coin/CoinMpsIO.cpp b/cbits/coin/CoinMpsIO.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinMpsIO.cpp
@@ -0,0 +1,6132 @@
+/* $Id: CoinMpsIO.cpp 1646 2013-10-16 15:06:38Z tkr $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinUtilsConfig.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+#include <string>
+#include <cstdio>
+#include <iostream>
+
+#include "CoinMpsIO.hpp"
+#include "CoinMessage.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinModel.hpp"
+#include "CoinSort.hpp"
+
+//#############################################################################
+// type - 0 normal, 1 INTEL IEEE, 2 other IEEE
+
+namespace {
+
+  const double fraction[]=
+  {1.0,1.0e-1,1.0e-2,1.0e-3,1.0e-4,1.0e-5,1.0e-6,1.0e-7,1.0e-8,
+   1.0e-9,1.0e-10,1.0e-11,1.0e-12,1.0e-13,1.0e-14,1.0e-15,1.0e-16,
+   1.0e-17,1.0e-18,1.0e-19,1.0e-20,1.0e-21,1.0e-22,1.0e-23};
+
+  const double exponent[]=
+  {1.0e-9,1.0e-8,1.0e-7,1.0e-6,1.0e-5,1.0e-4,1.0e-3,1.0e-2,1.0e-1,
+   1.0,1.0e1,1.0e2,1.0e3,1.0e4,1.0e5,1.0e6,1.0e7,1.0e8,1.0e9};
+
+} // end file-local namespace
+double CoinMpsCardReader::osi_strtod(char * ptr, char ** output, int type) 
+{
+
+  double value = 0.0;
+  char * save = ptr;
+
+  // take off leading white space
+  while (*ptr==' '||*ptr=='\t')
+    ptr++;
+  if (!type) {
+    double sign1=1.0;
+    // do + or -
+    if (*ptr=='-') {
+      sign1=-1.0;
+      ptr++;
+    } else if (*ptr=='+') {
+      ptr++;
+    }
+    // more white space
+    while (*ptr==' '||*ptr=='\t')
+      ptr++;
+    char thisChar=0;
+    while (value<1.0e30) {
+      thisChar = *ptr;
+      ptr++;
+      if (thisChar>='0'&&thisChar<='9') 
+	value = value*10.0+thisChar-'0';
+      else
+	break;
+    }
+    if (value<1.0e30) {
+      if (thisChar=='.') {
+	// do fraction
+	double value2 = 0.0;
+	int nfrac=0;
+	while (nfrac<24) {
+	  thisChar = *ptr;
+	  ptr++;
+	  if (thisChar>='0'&&thisChar<='9') {
+	    value2 = value2*10.0+thisChar-'0';
+	    nfrac++;
+	  } else {
+	    break;
+	  }
+	}
+	if (nfrac<24) {
+	  value += value2*fraction[nfrac];
+	} else {
+	  thisChar='x'; // force error
+	}
+      }
+      if (thisChar=='e'||thisChar=='E') {
+	// exponent
+	int sign2=1;
+	// do + or -
+	if (*ptr=='-') {
+	  sign2=-1;
+	  ptr++;
+	} else if (*ptr=='+') {
+	  ptr++;
+	}
+	int value3 = 0;
+	while (value3<1000) {
+	  thisChar = *ptr;
+	  ptr++;
+	  if (thisChar>='0'&&thisChar<='9') {
+	    value3 = value3*10+thisChar-'0';
+	  } else {
+	    break;
+	  }
+	}
+	if (value3<300) {
+	  value3 *= sign2; // power of 10
+	  if (abs(value3)<10) {
+	    // do most common by lookup (for accuracy?)
+	    value *= exponent[value3+9];
+	  } else {
+	    value *= pow(10.0,value3);
+	  }
+	} else if (sign2<0.0) {
+	  value = 0.0; // force zero
+	} else {
+	  value = COIN_DBL_MAX;
+	}
+      } 
+      if (thisChar==0||thisChar=='\t'||thisChar==' ') {
+	// okay
+	*output=ptr;
+      } else {
+	value = osi_strtod(save,output);
+	sign1=1.0;
+      }
+    } else {
+      // bad value
+      value = osi_strtod(save,output);
+      sign1=1.0;
+    }
+    value *= sign1;
+  } else {
+    // ieee - 3 bytes go to 2
+    assert (sizeof(double)==8*sizeof(char));
+    assert (sizeof(unsigned short) == 2*sizeof(char));
+    unsigned short shortValue[4];
+    *output = ptr+12; // say okay
+    if (type==1) {
+      // INTEL
+      for (int i=3;i>=0;i--) {
+	int integerValue=0;
+	char * three = reinterpret_cast<char *> (&integerValue);
+	three[1]=ptr[0];
+	three[2]=ptr[1];
+	three[3]=ptr[2];
+	unsigned short thisValue=0;
+	// decode 6 bits at a time
+	for (int j=2;j>=0;j--) {
+	  thisValue = static_cast<unsigned short>(thisValue<<6);
+	  char thisChar = ptr[j];
+	  if (thisChar >= '0' && thisChar <= '0' + 9) {
+	    thisValue = static_cast<unsigned short>(thisValue | (thisChar - '0'));
+	  } else if (thisChar >= 'a' && thisChar <= 'a' + 25) {
+	    thisValue = static_cast<unsigned short>(thisValue | (thisChar - 'a' + 10));
+	  } else if (thisChar >= 'A' && thisChar <= 'A' + 25) {
+	    thisValue = static_cast<unsigned short>(thisValue | (thisChar - 'A' + 36));
+	  } else if (thisChar >= '*' && thisChar <= '*' + 1) {
+	    thisValue = static_cast<unsigned short>(thisValue | (thisChar - '*' + 62));
+	  } else {
+	    // error 
+	    *output=save;
+	  }
+	}
+	ptr+=3;
+	shortValue[i]=thisValue;
+      }
+    } else {
+      // not INTEL
+      for (int i=0;i<4;i++) {
+	int integerValue=0;
+	char * three = reinterpret_cast<char *> (&integerValue);
+	three[1]=ptr[0];
+	three[2]=ptr[1];
+	three[3]=ptr[2];
+	unsigned short thisValue=0;
+	// decode 6 bits at a time
+	for (int j=2;j>=0;j--) {
+	  thisValue = static_cast<unsigned short>(thisValue<<6);
+	  char thisChar = ptr[j];
+	  if (thisChar >= '0' && thisChar <= '0' + 9) {
+	    thisValue = static_cast<unsigned short>(thisValue | (thisChar - '0'));
+	  } else if (thisChar >= 'a' && thisChar <= 'a' + 25) {
+	    thisValue = static_cast<unsigned short>(thisValue | (thisChar - 'a' + 10));
+	  } else if (thisChar >= 'A' && thisChar <= 'A' + 25) {
+	    thisValue = static_cast<unsigned short>(thisValue | (thisChar - 'A' + 36));
+	  } else if (thisChar >= '*' && thisChar <= '*' + 1) {
+	    thisValue = static_cast<unsigned short>(thisValue | (thisChar - '*' + 62));
+	  } else {
+	    // error 
+	    *output=save;
+	  }
+	}
+	ptr+=3;
+	shortValue[i]=thisValue;
+      }
+    }
+    memcpy(&value,shortValue,sizeof(double));
+  }
+  return value;
+}
+// for strings 
+double CoinMpsCardReader::osi_strtod(char * ptr, char ** output) 
+{
+  char * save = ptr;
+  double value=-1.0e100;
+  if (!stringsAllowed_) {
+    *output=save;
+  } else {
+    // take off leading white space
+    while (*ptr==' '||*ptr=='\t')
+      ptr++;
+    if (*ptr=='=') {
+      strcpy(valueString_,ptr);
+#define STRING_VALUE  -1.234567e-101
+      value = STRING_VALUE;
+      *output=ptr+strlen(ptr);
+    } else {
+      *output=save;
+    }
+  }
+  return value;
+}
+//#############################################################################
+// sections
+const static char *section[] = {
+  "", "NAME", "ROW", "COLUMN", "RHS", "RANGES", "BOUNDS", "ENDATA", " ","QSECTION", "CSECTION", 
+  "QUADOBJ" , "SOS", "BASIS",
+  " "
+};
+
+// what is allowed in each section - must line up with COINSectionType
+const static COINMpsType startType[] = {
+  COIN_UNKNOWN_MPS_TYPE, COIN_UNKNOWN_MPS_TYPE,
+  COIN_N_ROW, COIN_BLANK_COLUMN,
+  COIN_BLANK_COLUMN, COIN_BLANK_COLUMN,
+  COIN_UP_BOUND, COIN_UNKNOWN_MPS_TYPE,
+  COIN_UNKNOWN_MPS_TYPE,
+  COIN_BLANK_COLUMN, COIN_BLANK_COLUMN, COIN_BLANK_COLUMN, COIN_S1_BOUND, 
+  COIN_BS_BASIS, COIN_UNKNOWN_MPS_TYPE
+};
+const static COINMpsType endType[] = {
+  COIN_UNKNOWN_MPS_TYPE, COIN_UNKNOWN_MPS_TYPE,
+  COIN_BLANK_COLUMN, COIN_UNSET_BOUND,
+  COIN_S1_COLUMN, COIN_S1_COLUMN,
+  COIN_UNKNOWN_MPS_TYPE, COIN_UNKNOWN_MPS_TYPE,
+  COIN_UNKNOWN_MPS_TYPE,
+  COIN_BLANK_COLUMN, COIN_BLANK_COLUMN, COIN_BLANK_COLUMN, COIN_BS_BASIS,
+  COIN_UNKNOWN_MPS_TYPE, COIN_UNKNOWN_MPS_TYPE
+};
+const static int allowedLength[] = {
+  0, 0,
+  1, 2,
+  0, 0,
+  2, 0,
+  0, 0,
+  0, 0,
+  0, 2,
+  0
+};
+
+// names of types
+const static char *mpsTypes[] = {
+  "N", "E", "L", "G",
+  "  ", "S1", "S2", "S3", "  ", "  ", "  ",
+  "  ", "UP", "FX", "LO", "FR", "MI", "PL", "BV", "UI", "LI", "SC",
+  "X1", "X2", "BS", "XL", "XU", "LL", "UL", "  "
+};
+
+int CoinMpsCardReader::cleanCard()
+{
+  char * getit;
+  getit = input_->gets ( card_, MAX_CARD_LENGTH);
+
+  if ( getit ) {
+    cardNumber_++;
+    unsigned char * lastNonBlank = reinterpret_cast<unsigned char *> (card_-1);
+    unsigned char * image = reinterpret_cast<unsigned char *> (card_);
+    bool tabs=false;
+    while ( *image != '\0' ) {
+      if ( *image != '\t' && *image < ' ' ) {
+	break;
+      } else if ( *image != '\t' && *image != ' ') {
+	lastNonBlank = image;
+      } else if (*image == '\t') {
+        tabs=true;
+      }
+      image++;
+    }
+    *(lastNonBlank+1)='\0';
+    if (tabs&&section_ == COIN_BOUNDS_SECTION&&!freeFormat_&&eightChar_) {
+      int length = static_cast<int>(lastNonBlank+1-
+      				    reinterpret_cast<unsigned char *>(card_));
+      assert (length<81);
+      memcpy(card_+82,card_,length);
+      int pos[]={1,4,14,24,1000};
+      int put=0;
+      int tab=0;
+      for (int i=0;i<length;i++) {
+        char look = card_[i+82];
+        if (look!='\t') {
+          card_[put++]=look;
+        } else {
+          // count on to next
+          for (;tab<5;tab++) {
+            if (put<pos[tab]) {
+              while (put<pos[tab])
+                card_[put++]= ' ';
+              break;
+            }
+          }
+        }
+      }
+      card_[put++]='\0';
+    }
+    return 0;
+  } else {
+    return 1;
+  }
+}
+
+char *
+CoinMpsCardReader::nextBlankOr ( char *image )
+{
+  char * saveImage=image;
+  while ( 1 ) {
+    if ( *image == ' ' || *image == '\t' ) {
+      break;
+    }
+    if ( *image == '\0' )
+      return NULL;
+    image++;
+  }
+  // Allow for floating - or +.  Will fail if user has that as row name!!
+  if (image-saveImage==1&&(*saveImage=='+'||*saveImage=='-')) {
+    while ( *image == ' ' || *image == '\t' ) {
+      image++;
+    }
+    image=nextBlankOr(image);
+  }
+  return image;
+}
+
+// Read to NAME card - return nonzero if bad
+COINSectionType
+CoinMpsCardReader::readToNextSection (  )
+{
+  bool found = false;
+
+  while ( !found ) {
+    // need new image
+
+    if ( cleanCard() ) {
+      section_ = COIN_EOF_SECTION;
+      break;
+    }
+    if ( !strncmp ( card_, "NAME", 4 ) ||
+		!strncmp( card_, "TIME", 4 ) ||
+		!strncmp( card_, "BASIS", 5 ) ||
+		!strncmp( card_, "STOCH", 5 ) ) {
+      section_ = COIN_NAME_SECTION;
+      char *next = card_ + 5;
+      position_ = eol_ = card_+strlen(card_);
+
+      handler_->message(COIN_MPS_LINE,messages_)<<cardNumber_
+					       <<card_<<CoinMessageEol;
+      while ( next < eol_ ) {
+	if ( *next == ' ' || *next == '\t' ) {
+	  next++;
+	} else {
+	  break;
+	}
+      }
+      if ( next < eol_ ) {
+	char *nextBlank = nextBlankOr ( next );
+	char save;
+
+	if ( nextBlank ) {
+	  save = *nextBlank;
+	  *nextBlank = '\0';
+	  strcpy ( columnName_, next );
+	  *nextBlank = save;
+	  if ( strstr ( nextBlank, "FREEIEEE" ) ) {
+	    freeFormat_ = true;
+	    // see if intel
+	    ieeeFormat_=1;
+	    double value=1.0;
+	    char x[8];
+	    memcpy(x,&value,8);
+	    if (x[0]==63) {
+	      ieeeFormat_=2; // not intel
+	    } else {
+	      assert (x[0]==0);
+	    }
+	  } else if ( strstr ( nextBlank, "FREE" ) ) {
+	    freeFormat_ = true;
+	  } else if ( strstr ( nextBlank, "VALUES" ) ) {
+	    // basis is always free - just use this to communicate back
+	    freeFormat_ = true;
+	  } else if ( strstr ( nextBlank, "IEEE" ) ) {
+	    // see if intel
+	    ieeeFormat_=1;
+	    double value=1.0;
+	    char x[8];
+	    memcpy(x,&value,8);
+	    if (x[0]==63) {
+	      ieeeFormat_=2; // not intel
+	    } else {
+	      assert (x[0]==0);
+	    }
+	  }
+	} else {
+	  strcpy ( columnName_, next );
+	}
+      } else {
+	strcpy ( columnName_, "no_name" );
+      }
+      break;
+    } else if ( card_[0] != '*' && card_[0] != '#' ) {
+      // not a comment
+      int i;
+
+      handler_->message(COIN_MPS_LINE,messages_)<<cardNumber_
+					       <<card_<<CoinMessageEol;
+      for ( i = COIN_ROW_SECTION; i < COIN_UNKNOWN_SECTION; i++ ) {
+	if ( !strncmp ( card_, section[i], strlen ( section[i] ) ) ) {
+	  break;
+	}
+      }
+      position_ = card_;
+      eol_ = card_;
+      section_ = static_cast< COINSectionType > (i);
+      break;
+    }
+  }
+  return section_;
+}
+
+CoinMpsCardReader::CoinMpsCardReader (  CoinFileInput *input, 
+					CoinMpsIO * reader)
+{
+  memset ( card_, 0, MAX_CARD_LENGTH );
+  position_ = card_;
+  eol_ = card_;
+  mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+  memset ( rowName_, 0, COIN_MAX_FIELD_LENGTH );
+  memset ( columnName_, 0, COIN_MAX_FIELD_LENGTH );
+  value_ = 0.0;
+  input_ = input;
+  section_ = COIN_EOF_SECTION;
+  cardNumber_ = 0;
+  freeFormat_ = false;
+  ieeeFormat_ = 0;
+  eightChar_ = true;
+  reader_ = reader;
+  handler_ = reader_->messageHandler();
+  messages_ = reader_->messages();
+  memset ( valueString_, 0, COIN_MAX_FIELD_LENGTH );
+  stringsAllowed_=false;
+}
+//  ~CoinMpsCardReader.  Destructor
+CoinMpsCardReader::~CoinMpsCardReader (  )
+{
+  delete input_;
+}
+
+void
+CoinMpsCardReader::strcpyAndCompress ( char *to, const char *from )
+{
+  int n = static_cast<int>(strlen(from));
+  int i;
+  int nto = 0;
+
+  for ( i = 0; i < n; i++ ) {
+    if ( from[i] != ' ' ) {
+      to[nto++] = from[i];
+    }
+  }
+  if ( !nto )
+    to[nto++] = ' ';
+  to[nto] = '\0';
+}
+
+//  nextField
+COINSectionType
+CoinMpsCardReader::nextField (  )
+{
+  mpsType_ = COIN_BLANK_COLUMN;
+  // find next non blank character
+  char *next = position_;
+
+  while ( next != eol_ ) {
+    if ( *next == ' ' || *next == '\t' ) {
+      next++;
+    } else {
+      break;
+    }
+  }
+  bool gotCard;
+
+  if ( next == eol_ ) {
+    gotCard = false;
+  } else {
+    gotCard = true;
+  }
+  while ( !gotCard ) {
+    // need new image
+
+    if ( cleanCard() ) {
+      return COIN_EOF_SECTION;
+    }
+    if ( card_[0] == ' ' || card_[0] == '\0') {
+      // not a section or comment
+      position_ = card_;
+      eol_ = card_ + strlen ( card_ );
+      // get mps type and column name
+      // scan to first non blank
+      next = card_;
+      while ( next != eol_ ) {
+	if ( *next == ' ' || *next == '\t' ) {
+	  next++;
+	} else {
+	  break;
+	}
+      }
+      if ( next != eol_ ) {
+	char *nextBlank = nextBlankOr ( next );
+	int nchar;
+
+	if ( nextBlank ) {
+	  nchar = static_cast<int>(nextBlank - next);
+	} else {
+	  nchar = -1;
+	}
+	mpsType_ = COIN_BLANK_COLUMN;
+	// special coding if RHS or RANGES, not free format and blanks
+	if ( ( section_ != COIN_RHS_SECTION 
+	       && section_ != COIN_RANGES_SECTION )
+	     || freeFormat_ || strncmp ( card_ + 4, "        ", 8 ) ) {
+	  // if columns section only look for first field if MARKER
+	  if ( section_ == COIN_COLUMN_SECTION
+	       && !strstr ( next, "'MARKER'" ) ) nchar = -1;
+	  if (section_ == COIN_SOS_SECTION) {
+	    if (!strncmp(card_," S1",3)) {
+	      mpsType_ = COIN_S1_BOUND;
+	      break;
+	    } else if (!strncmp(card_," S2",3)) {
+	      mpsType_ = COIN_S2_BOUND;
+	      break;
+	    }
+	  }
+	  if ( nchar == allowedLength[section_] ) {
+	    //could be a type
+	    int i;
+
+	    for ( i = startType[section_]; i < endType[section_]; i++ ) {
+	      if ( !strncmp ( next, mpsTypes[i], nchar ) ) {
+		mpsType_ = static_cast<COINMpsType> (i);
+		break;
+	      }
+	    }
+	    if ( mpsType_ != COIN_BLANK_COLUMN ) {
+	      //we know all we need so we can skip over
+	      next = nextBlank;
+	      while ( next != eol_ ) {
+		if ( *next == ' ' || *next == '\t' ) {
+		  next++;
+		} else {
+		  break;
+		}
+	      }
+	      if ( next == eol_ ) {
+		// error
+		position_ = eol_;
+		mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+	      } else {
+		nextBlank = nextBlankOr ( next );
+	      }
+	    } else if (section_ == COIN_BOUNDS_SECTION) {
+              // should have been something - but just fix LI problem
+              // set to something illegal
+              if (card_[0]==' '&&card_[3]==' '&&(card_[1]!=' '||card_[2]!=' ')) {
+                mpsType_ = COIN_S3_COLUMN;
+                //we know all we need so we can skip over
+                next = nextBlank;
+                while ( next != eol_ ) {
+                  if ( *next == ' ' || *next == '\t' ) {
+                    next++;
+                  } else {
+                    break;
+                  }
+                }
+                if ( next == eol_ ) {
+                  // error
+                  position_ = eol_;
+                  mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+                } else {
+                  nextBlank = nextBlankOr ( next );
+                }
+              }
+            }
+	  }
+	  if ( mpsType_ != COIN_UNKNOWN_MPS_TYPE ) {
+	    // special coding if BOUND, not free format and blanks
+	    if ( section_ != COIN_BOUNDS_SECTION ||
+		 freeFormat_ || strncmp ( card_ + 4, "        ", 8 ) ) {
+	      char save = '?';
+
+	      if ( !freeFormat_ && eightChar_ && next == card_ + 4 ) {
+		if ( eol_ - next >= 8 ) {
+		  if ( *( next + 8 ) != ' ' && *( next + 8 ) != '\0' ) {
+		    eightChar_ = false;
+		  } else {
+		    nextBlank = next + 8;
+		  }
+		  if (nextBlank) {
+		    save = *nextBlank;
+		    *nextBlank = '\0';
+		  }
+		} else {
+		  nextBlank = NULL;
+		}
+	      } else {
+		if ( nextBlank ) {
+		  save = *nextBlank;
+		  *nextBlank = '\0';
+		}
+	      }
+	      strcpyAndCompress ( columnName_, next );
+	      if ( nextBlank ) {
+		*nextBlank = save;
+		// on to next
+		next = nextBlank;
+	      } else {
+		next = eol_;
+	      }
+	    } else {
+	      // blank bounds name
+	      strcpy ( columnName_, "        " );
+	    }
+	    while ( next != eol_ ) {
+	      if ( *next == ' ' || *next == '\t' ) {
+		next++;
+	      } else {
+		break;
+	      }
+	    }
+	    if ( next == eol_ ) {
+	      // error unless row section or conic section
+	      position_ = eol_;
+	      value_ = -1.0e100;
+	      if ( section_ != COIN_ROW_SECTION && 
+		   section_!= COIN_CONIC_SECTION)
+		mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+	      else
+		return section_;
+	    } else {
+	      nextBlank = nextBlankOr ( next );
+	      //if (section_==COIN_CONIC_SECTION)
+	    }
+	    if ( section_ != COIN_ROW_SECTION ) {
+	      char save = '?';
+
+	      if ( !freeFormat_ && eightChar_ && next == card_ + 14 ) {
+		if ( eol_ - next >= 8 ) {
+		  if ( *( next + 8 ) != ' ' && *( next + 8 ) != '\0' ) {
+		    eightChar_ = false;
+		  } else {
+		    nextBlank = next + 8;
+		  }
+		  save = *nextBlank;
+		  *nextBlank = '\0';
+		} else {
+		  nextBlank = NULL;
+		}
+	      } else {
+		if ( nextBlank ) {
+		  save = *nextBlank;
+		  *nextBlank = '\0';
+		}
+	      }
+	      strcpyAndCompress ( rowName_, next );
+	      if ( nextBlank ) {
+		*nextBlank = save;
+		// on to next
+		next = nextBlank;
+	      } else {
+		next = eol_;
+	      }
+	      while ( next != eol_ ) {
+		if ( *next == ' ' || *next == '\t' ) {
+		  next++;
+		} else {
+		  break;
+		}
+	      }
+	      // special coding for markers
+	      if ( section_ == COIN_COLUMN_SECTION &&
+		   !strncmp ( rowName_, "'MARKER'", 8 ) && next != eol_ ) {
+		if ( !strncmp ( next, "'INTORG'", 8 ) ) {
+		  mpsType_ = COIN_INTORG;
+		} else if ( !strncmp ( next, "'INTEND'", 8 ) ) {
+		  mpsType_ = COIN_INTEND;
+		} else if ( !strncmp ( next, "'SOSORG'", 8 ) ) {
+		  if ( mpsType_ == COIN_BLANK_COLUMN )
+		    mpsType_ = COIN_S1_COLUMN;
+		} else if ( !strncmp ( next, "'SOSEND'", 8 ) ) {
+		  mpsType_ = COIN_SOSEND;
+		} else {
+		  mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+		}
+		position_ = eol_;
+		return section_;
+	      }
+	      if ( next == eol_ ) {
+		// error unless bounds or basis
+		position_ = eol_;
+		if ( section_ != COIN_BOUNDS_SECTION ) {
+		  if ( section_ != COIN_BASIS_SECTION ) 
+		    mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+		  value_ = -1.0e100;
+		} else {
+		  value_ = 0.0;
+		}
+	      } else {
+		nextBlank = nextBlankOr ( next );
+		if ( nextBlank ) {
+		  save = *nextBlank;
+		  *nextBlank = '\0';
+		}
+		char * after;
+		value_ = osi_strtod(next,&after,ieeeFormat_);
+		// see if error
+		if (after>next) {
+                  if ( nextBlank ) {
+                    *nextBlank = save;
+                    position_ = nextBlank;
+                  } else {
+                    position_ = eol_;
+                  }
+                } else {
+                  // error
+                  position_ = eol_;
+                  mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+		  value_ = -1.0e100;
+                }
+	      }
+	    }
+	  }
+	} else {
+	  //blank name in RHS or RANGES
+	  strcpy ( columnName_, "        " );
+	  char save = '?';
+
+	  if ( !freeFormat_ && eightChar_ && next == card_ + 14 ) {
+	    if ( eol_ - next >= 8 ) {
+	      if ( *( next + 8 ) != ' ' && *( next + 8 ) != '\0' ) {
+		eightChar_ = false;
+	      } else {
+		nextBlank = next + 8;
+	      }
+	      save = *nextBlank;
+	      *nextBlank = '\0';
+	    } else {
+	      nextBlank = NULL;
+	    }
+	  } else {
+	    if ( nextBlank ) {
+	      save = *nextBlank;
+	      *nextBlank = '\0';
+	    }
+	  }
+	  strcpyAndCompress ( rowName_, next );
+	  if ( nextBlank ) {
+	    *nextBlank = save;
+	    // on to next
+	    next = nextBlank;
+	  } else {
+	    next = eol_;
+	  }
+	  while ( next != eol_ ) {
+	    if ( *next == ' ' || *next == '\t' ) {
+	      next++;
+	    } else {
+	      break;
+	    }
+	  }
+	  if ( next == eol_ ) {
+	    // error 
+	    position_ = eol_;
+	    value_ = -1.0e100;
+	    mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+	  } else {
+	    nextBlank = nextBlankOr ( next );
+	    value_ = -1.0e100;
+	    if ( nextBlank ) {
+	      save = *nextBlank;
+	      *nextBlank = '\0';
+	    }
+	    char * after;
+	    value_ = osi_strtod(next,&after,ieeeFormat_);
+	    // see if error
+	    if (after>next) {
+              if ( nextBlank ) {
+                *nextBlank = save;
+                position_ = nextBlank;
+              } else {
+                position_ = eol_;
+              }
+            } else {
+              // error
+              position_ = eol_;
+              mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+              value_ = -1.0e100;
+            }
+	  }
+	}
+      } else {
+	// blank
+	continue;
+      }
+      return section_;
+    } else if ( card_[0] != '*' ) {
+      // not a comment
+      int i;
+
+      handler_->message(COIN_MPS_LINE,messages_)<<cardNumber_
+					       <<card_<<CoinMessageEol;
+      for ( i = COIN_ROW_SECTION; i < COIN_UNKNOWN_SECTION; i++ ) {
+	if ( !strncmp ( card_, section[i], strlen ( section[i] ) ) ) {
+	  break;
+	}
+      }
+      position_ = card_;
+      eol_ = card_;
+      section_ = static_cast<COINSectionType> (i);
+      return section_;
+    } else {
+      // comment
+    }
+  }
+  // we only get here for second field (we could even allow more???)
+  {
+    char save = '?';
+    char *nextBlank = nextBlankOr ( next );
+
+    if ( !freeFormat_ && eightChar_ && next == card_ + 39 ) {
+      if ( eol_ - next >= 8 ) {
+	if ( *( next + 8 ) != ' ' && *( next + 8 ) != '\0' ) {
+	  eightChar_ = false;
+	} else {
+	  nextBlank = next + 8;
+	}
+	save = *nextBlank;
+	*nextBlank = '\0';
+      } else {
+	nextBlank = NULL;
+      }
+    } else {
+      if ( nextBlank ) {
+	save = *nextBlank;
+	*nextBlank = '\0';
+      }
+    }
+    strcpyAndCompress ( rowName_, next );
+    // on to next
+    if ( nextBlank ) {
+      *nextBlank = save;
+      next = nextBlank;
+    } else {
+      next = eol_;
+    }
+    while ( next != eol_ ) {
+      if ( *next == ' ' || *next == '\t' ) {
+	next++;
+      } else {
+	break;
+      }
+    }
+    if ( next == eol_ && section_ != COIN_SOS_SECTION) {
+      // error
+      position_ = eol_;
+      mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+    } else {
+      nextBlank = nextBlankOr ( next );
+    }
+    if ( nextBlank ) {
+      save = *nextBlank;
+      *nextBlank = '\0';
+    }
+    //value_ = -1.0e100;
+    char * after;
+    value_ = osi_strtod(next,&after,ieeeFormat_);
+    // see if error
+    if (after>next) {
+      if ( nextBlank ) {
+        *nextBlank = save;
+        position_ = nextBlank;
+      } else {
+        position_ = eol_;
+      }
+    } else {
+      // error
+      position_ = eol_;
+      if (mpsType_!=COIN_S1_BOUND&&mpsType_!=COIN_S2_BOUND)
+	mpsType_ = COIN_UNKNOWN_MPS_TYPE;
+      value_ = -1.0e100;
+    }
+  }
+  return section_;
+}
+static char *
+nextNonBlank ( char *image )
+{
+  while ( 1 ) {
+    if ( *image != ' ' && *image != '\t' ) 
+      break;
+    else
+      image++;
+  }
+  if ( *image == '\0' )
+    image=NULL;
+  return image;
+}
+/** Gets next field for .gms file and returns type.
+    -1 - EOF
+    0 - what we expected (and processed so pointer moves past)
+    1 - not what we expected
+    2 - equation type when expecting value name pair
+    leading blanks always ignored
+    input types 
+    0 - anything - stops on non blank card
+    1 - name (in columnname)
+    2 - value
+    3 - value name pair
+    4 - equation type
+    5 - ;
+*/
+int 
+CoinMpsCardReader::nextGmsField ( int expectedType )
+{
+  int returnCode=-1;
+  bool good=false;
+  switch(expectedType) {
+  case 0:
+    // 0 - May get * in first column or anything
+    if ( cleanCard())
+      return -1;
+    while(!strlen(card_)) {
+      if ( cleanCard())
+	return -1;
+    }
+    eol_ = card_+strlen(card_);
+    position_=card_;
+    returnCode=0;
+    break;
+  case 1:
+    // 1 - expect name
+    while (!good) {
+      position_ = nextNonBlank(position_);
+      if (position_==NULL) {
+	if ( cleanCard())
+	  return -1;
+	eol_ = card_+strlen(card_);
+	position_=card_;
+      } else {
+	good=true;
+	char nextChar =*position_;
+	if ((nextChar>='a'&&nextChar<='z')||
+	    (nextChar>='A'&&nextChar<='Z')) {
+          returnCode=0;
+          char * next=position_;
+          while (*next!=','&&*next!=';'&&*next!='='&&*next!=' '
+                 &&*next!='\t'&&*next!='-'&&*next!='+'&&*next>=32)
+            next++;
+          if (next) {
+            int length = static_cast<int>(next-position_);
+            strncpy(columnName_,position_,length);
+            columnName_[length]='\0';
+          } else {
+            strcpy(columnName_,position_);
+            next=eol_;
+          }
+          position_=next;
+        } else {
+          returnCode=1;
+        }
+      }
+    }
+    break;
+  case 2:
+    // 2 - expect value
+    while (!good) {
+      position_ = nextNonBlank(position_);
+      if (position_==NULL) {
+	if ( cleanCard())
+	  return -1;
+	eol_ = card_+strlen(card_);
+	position_=card_;
+      } else {
+	good=true;
+	char nextChar =*position_;
+	if ((nextChar>='0'&&nextChar<='9')||nextChar=='+'||nextChar=='-') {
+          returnCode=0;
+          char * next=position_;
+          while (*next!=','&&*next!=';'&&*next!='='&&*next!=' '
+                 &&*next!='\t'&&*next>=32)
+            next++;
+          if (next) {
+            int length = static_cast<int>(next-position_);
+            strncpy(rowName_,position_,length);
+            rowName_[length]='\0';
+          } else {
+            strcpy(rowName_,position_);
+            next=eol_;
+          }
+          value_=-1.0e100;
+          sscanf(rowName_,"%lg",&value_);
+          position_=next;
+        } else {
+          returnCode=1;
+        }
+      }
+    }
+    break;
+  case 3:
+    // 3 - expect value name pair
+    while (!good) {
+      position_ = nextNonBlank(position_);
+      char * savePosition = position_;
+      if (position_==NULL) {
+	if ( cleanCard())
+	  return -1;
+	eol_ = card_+strlen(card_);
+	position_=card_;
+        savePosition = position_;
+      } else {
+	good=true;
+        value_=1.0;
+	char nextChar =*position_;
+        returnCode=0;
+	if ((nextChar>='0'&&nextChar<='9')||nextChar=='+'||nextChar=='-') {
+          char * next;
+          int put=0;
+          if (nextChar=='+'||nextChar=='-') {
+            rowName_[0]=nextChar;
+            put=1;
+            next=position_+1;
+            while (*next==' '||*next=='\t')
+              next++;
+            if ((*next>='a'&&*next<='z')||
+                (*next>='A'&&*next<='Z')) {
+              // name - set value
+              if (nextChar=='+')
+                value_=1.0;
+              else
+                value_=-1.0;
+              position_=next;
+            } else if ((*next>='0'&&*next<='9')||*next=='+'||*next=='-') {
+              rowName_[put++]=*next;
+              next++;
+              while (*next!=' '&&*next!='\t'&&*next!='*') {
+                rowName_[put++]=*next;
+                next++;
+              }
+              assert (*next=='*');
+              next ++;
+              rowName_[put]='\0';
+              value_=-1.0e100;
+              sscanf(rowName_,"%lg",&value_);
+              position_=next;
+            } else {
+              returnCode=1;
+            }
+          } else {
+            // number
+            char * next = nextBlankOr(position_);
+            // but could be *
+            char * next2 = strchr(position_,'*');
+            if (next2&&next2-position_<next-position_) {
+              next=next2;
+            }
+            int length = static_cast<int>(next-position_);
+            strncpy(rowName_,position_,length);
+            rowName_[length]='\0';
+            value_=-1.0e100;
+            sscanf(rowName_,"%lg",&value_);
+            position_=next;
+          }
+	} else if ((nextChar>='a'&&nextChar<='z')||
+                   (nextChar>='A'&&nextChar<='Z')) {
+          // name so take value as 1.0
+        } else if (nextChar=='=') {
+          returnCode=2;
+          position_=savePosition;
+        } else {
+          returnCode=1;
+          position_=savePosition;
+        }
+        if ((*position_)=='*')
+          position_++;
+        position_= nextNonBlank(position_);
+        if (!returnCode) {
+          char nextChar =*position_;
+          if ((nextChar>='a'&&nextChar<='z')||
+              (nextChar>='A'&&nextChar<='Z')) {
+            char * next = nextBlankOr(position_);
+            if (next) {
+              int length = static_cast<int>(next-position_);
+              strncpy(columnName_,position_,length);
+              columnName_[length]='\0';
+            } else {
+              strcpy(columnName_,position_);
+              next=eol_;
+            }
+            position_=next;
+          } else {
+            returnCode=1;
+            position_=savePosition;
+          }
+        }
+      }
+    }
+    break;
+  case 4:
+    // 4 - expect equation type
+    while (!good) {
+      position_ = nextNonBlank(position_);
+      if (position_==NULL) {
+	if ( cleanCard())
+	  return -1;
+	eol_ = card_+strlen(card_);
+	position_=card_;
+      } else {
+	good=true;
+	char nextChar =*position_;
+	if (nextChar=='=') {
+          returnCode=0;
+          char * next = nextBlankOr(position_);
+          int length = static_cast<int>(next-position_);
+          strncpy(rowName_,position_,length);
+          rowName_[length]='\0';
+          position_=next;
+        } else {
+          returnCode=1;
+        }
+      }
+    }
+    break;
+  case 5:
+    // 5 - ; expected
+    while (!good) {
+      position_ = nextNonBlank(position_);
+      if (position_==NULL) {
+	if ( cleanCard())
+	  return -1;
+	eol_ = card_+strlen(card_);
+	position_=card_;
+      } else {
+	good=true;
+	char nextChar =*position_;
+	if (nextChar==';') {
+          returnCode=0;
+          char * next = nextBlankOr(position_);
+          if (!next)
+            next=eol_;
+          position_=next;
+        } else {
+          returnCode=1;
+        }
+      }
+    }
+    break;
+  }
+  return returnCode;
+}
+
+//#############################################################################
+
+namespace {
+const int mmult[] = {
+    262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
+    241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829,
+    221281, 218849, 216319, 213721, 211093, 208673, 206263, 203773,
+    201233, 198637, 196159, 193603, 191161, 188701, 186149, 183761,
+    181303, 178873, 176389, 173897, 171469, 169049, 166471, 163871,
+    161387, 158941, 156437, 153949, 151531, 149159, 146749, 144299,
+    141709, 139369, 136889, 134591, 132169, 129641, 127343, 124853,
+    122477, 120163, 117757, 115361, 112979, 110567, 108179, 105727,
+    103387, 101021, 98639, 96179, 93911, 91583, 89317, 86939, 84521,
+    82183, 79939, 77587, 75307, 72959, 70793, 68447, 66103
+  };
+
+int hash ( const char *name, int maxsiz, int length )
+{
+  
+  int n = 0;
+  int j;
+
+  for ( j = 0; j < length; ++j ) {
+    int iname = name[j];
+
+    n += mmult[j] * iname;
+  }
+  return ( abs ( n ) % maxsiz );	/* integer abs */
+}
+} // end file-local namespace
+
+// Define below if you are reading a Cnnnnnn file 
+// Will not do row names (for electricfence)
+//#define NONAMES
+#ifndef NONAMES
+//  startHash.  Creates hash list for names
+void
+CoinMpsIO::startHash ( char **names, const COINColumnIndex number , int section )
+{
+  names_[section] = names;
+  numberHash_[section] = number;
+  startHash(section);
+}
+void
+CoinMpsIO::startHash ( int section ) const
+{
+  char ** names = names_[section];
+  COINColumnIndex number = numberHash_[section];
+  COINColumnIndex i;
+  COINColumnIndex maxhash = 4 * number;
+  COINColumnIndex ipos, iput;
+
+  //hash_=(CoinHashLink *) malloc(maxhash*sizeof(CoinHashLink));
+  hash_[section] = new CoinHashLink[maxhash];
+  
+  CoinHashLink * hashThis = hash_[section];
+
+  for ( i = 0; i < maxhash; i++ ) {
+    hashThis[i].index = -1;
+    hashThis[i].next = -1;
+  }
+
+  /*
+   * Initialize the hash table.  Only the index of the first name that
+   * hashes to a value is entered in the table; subsequent names that
+   * collide with it are not entered.
+   */
+  for ( i = 0; i < number; ++i ) {
+    char *thisName = names[i];
+    int length = static_cast<int>(strlen(thisName));
+
+    ipos = hash ( thisName, maxhash, length );
+    if ( hashThis[ipos].index == -1 ) {
+      hashThis[ipos].index = i;
+    }
+  }
+
+  /*
+   * Now take care of the names that collided in the preceding loop,
+   * by finding some other entry in the table for them.
+   * Since there are as many entries in the table as there are names,
+   * there must be room for them.
+   */
+  iput = -1;
+  for ( i = 0; i < number; ++i ) {
+    char *thisName = names[i];
+    int length = static_cast<int>(strlen(thisName));
+
+    ipos = hash ( thisName, maxhash, length );
+
+    while ( 1 ) {
+      COINColumnIndex j1 = hashThis[ipos].index;
+
+      if ( j1 == i )
+	break;
+      else {
+	char *thisName2 = names[j1];
+
+	if ( strcmp ( thisName, thisName2 ) == 0 ) {
+	  printf ( "** duplicate name %s\n", names[i] );
+	  break;
+	} else {
+	  COINColumnIndex k = hashThis[ipos].next;
+
+	  if ( k == -1 ) {
+	    while ( 1 ) {
+	      ++iput;
+	      if ( iput > number ) {
+		printf ( "** too many names\n" );
+		break;
+	      }
+	      if ( hashThis[iput].index == -1 ) {
+		break;
+	      }
+	    }
+	    hashThis[ipos].next = iput;
+	    hashThis[iput].index = i;
+	    break;
+	  } else {
+	    ipos = k;
+	    /* nothing worked - try it again */
+	  }
+	}
+      }
+    }
+  }
+}
+
+//  stopHash.  Deletes hash storage
+void
+CoinMpsIO::stopHash ( int section )
+{
+  delete [] hash_[section];
+  hash_[section] = NULL;
+}
+
+//  findHash.  -1 not found
+COINColumnIndex
+CoinMpsIO::findHash ( const char *name , int section ) const
+{
+  COINColumnIndex found = -1;
+
+  char ** names = names_[section];
+  CoinHashLink * hashThis = hash_[section];
+  COINColumnIndex maxhash = 4 * numberHash_[section];
+  COINColumnIndex ipos;
+
+  /* default if we don't find anything */
+  if ( !maxhash )
+    return -1;
+  int length = static_cast<int>(strlen(name));
+
+  ipos = hash ( name, maxhash, length );
+  while ( 1 ) {
+    COINColumnIndex j1 = hashThis[ipos].index;
+
+    if ( j1 >= 0 ) {
+      char *thisName2 = names[j1];
+
+      if ( strcmp ( name, thisName2 ) != 0 ) {
+	COINColumnIndex k = hashThis[ipos].next;
+
+	if ( k != -1 )
+	  ipos = k;
+	else
+	  break;
+      } else {
+	found = j1;
+	break;
+      }
+    } else {
+      found = -1;
+      break;
+    }
+  }
+  return found;
+}
+#else
+// Version when we know images are C/Rnnnnnn
+//  startHash.  Creates hash list for names
+void
+CoinMpsIO::startHash ( char **names, const COINColumnIndex number , int section )
+{
+  numberHash_[section] = number;
+  names_[section] = names;
+}
+void
+CoinMpsIO::startHash ( int section ) const
+{
+}
+
+//  stopHash.  Deletes hash storage
+void
+CoinMpsIO::stopHash ( int section )
+{
+}
+
+//  findHash.  -1 not found
+COINColumnIndex
+CoinMpsIO::findHash ( const char *name , int section ) const
+{
+  COINColumnIndex found = atoi(name+1);
+  if (!strcmp(name,"OBJROW"))
+    found = numberHash_[section]-1;
+  return found;
+}
+#endif
+//------------------------------------------------------------------
+// Get value for infinity
+//------------------------------------------------------------------
+double CoinMpsIO::getInfinity() const
+{
+  return infinity_;
+}
+//------------------------------------------------------------------
+// Set value for infinity
+//------------------------------------------------------------------
+void CoinMpsIO::setInfinity(double value) 
+{
+  if ( value >= 1.020 ) {
+    infinity_ = value;
+  } else {
+    handler_->message(COIN_MPS_ILLEGAL,messages_)<<"infinity"
+						<<value
+						<<CoinMessageEol;
+  }
+
+}
+// Set file name
+void CoinMpsIO::setFileName(const char * name)
+{
+  free(fileName_);
+  fileName_=CoinStrdup(name);
+}
+// Get file name
+const char * CoinMpsIO::getFileName() const
+{
+  return fileName_;
+}
+// Deal with filename - +1 if new, 0 if same as before, -1 if error
+int
+CoinMpsIO::dealWithFileName(const char * filename,  const char * extension,
+		       CoinFileInput * & input)
+{
+  if (input != 0) {
+    delete input;
+    input = 0;
+  }
+
+  int goodFile=0;
+
+  if (!fileName_||(filename!=NULL&&strcmp(filename,fileName_))) {
+    if (filename==NULL) {
+      handler_->message(COIN_MPS_FILE,messages_)<<"NULL"
+						<<CoinMessageEol;
+      return -1;
+    }
+    goodFile=-1;
+    // looks new name
+    char newName[400];
+    if (strcmp(filename,"stdin")&&strcmp(filename,"-")) {
+      if (extension&&strlen(extension)) {
+	// There was an extension - but see if user gave .xxx
+	int i = static_cast<int>(strlen(filename))-1;
+	strcpy(newName,filename);
+	bool foundDot=false; 
+	for (;i>=0;i--) {
+	  char character = filename[i];
+	  if (character=='/'||character=='\\') {
+	    break;
+	  } else if (character=='.') {
+	    foundDot=true;
+	    break;
+	  }
+	}
+	if (!foundDot) {
+	  strcat(newName,".");
+	  strcat(newName,extension);
+	}
+      } else {
+	// no extension
+	strcpy(newName,filename);
+      }
+    } else {
+      strcpy(newName,"stdin");    
+    }
+    // See if new name
+    if (fileName_&&!strcmp(newName,fileName_)) {
+      // old name
+      return 0;
+    } else {
+      // new file
+      free(fileName_);
+      fileName_=CoinStrdup(newName);    
+      if (strcmp(fileName_,"stdin")) {
+
+	// be clever with extensions here
+	std::string fname = fileName_;
+	bool readable = fileCoinReadable(fname);
+	if (!readable)
+	  goodFile = -1;
+	else
+	  {
+	    input = CoinFileInput::create (fname);
+	    goodFile = 1;
+	  }
+      } else {
+        // only plain file at present
+        input = CoinFileInput::create ("stdin");
+        goodFile = 1;
+      }
+    }
+  } else {
+    // same as before
+    // reset section ?
+    goodFile=0;
+  }
+  if (goodFile<0) 
+    handler_->message(COIN_MPS_FILE,messages_)<<fileName_
+					      <<CoinMessageEol;
+  return goodFile;
+}
+/* objective offset - this is RHS entry for objective row */
+double CoinMpsIO::objectiveOffset() const
+{
+  return objectiveOffset_;
+}
+/*
+  Prior to June 2007, this was set to 1e30. But that causes problems in
+  some of the cut generators --- they need to see finite infinity in order
+  to work properly.
+*/
+#define MAX_INTEGER COIN_DBL_MAX
+// Sets default upper bound for integer variables
+void CoinMpsIO::setDefaultBound(int value)
+{
+  if ( value >= 1 && value <=MAX_INTEGER ) {
+    defaultBound_ = value;
+  } else {
+    handler_->message(COIN_MPS_ILLEGAL,messages_)<<"default integer bound"
+						<<value
+						<<CoinMessageEol;
+  }
+}
+// gets default upper bound for integer variables
+int CoinMpsIO::getDefaultBound() const
+{
+  return defaultBound_;
+}
+//------------------------------------------------------------------
+// Read mps files
+//------------------------------------------------------------------
+int CoinMpsIO::readMps(const char * filename,  const char * extension)
+{
+  // Deal with filename - +1 if new, 0 if same as before, -1 if error
+
+  CoinFileInput *input = 0;
+  int returnCode = dealWithFileName(filename,extension,input);
+  if (returnCode<0) {
+    return -1;
+  } else if (returnCode>0) {
+    delete cardReader_;
+    cardReader_ = new CoinMpsCardReader ( input, this);
+  }
+  if (!extension||(strcmp(extension,"gms")&&!strstr(filename,".gms"))) {
+    return readMps();
+  } else {
+    int numberSets=0;
+    CoinSet ** sets=NULL;
+    int returnCode = readGms(numberSets,sets);
+    for (int i=0;i<numberSets;i++)
+      delete sets[i];
+    delete [] sets;
+    return returnCode;
+  }
+}
+int CoinMpsIO::readMps(const char * filename,  const char * extension,
+		       int & numberSets,CoinSet ** &sets)
+{
+  // Deal with filename - +1 if new, 0 if same as before, -1 if error
+  CoinFileInput *input = 0;
+  int returnCode = dealWithFileName(filename,extension,input);
+  if (returnCode<0) {
+    return -1;
+  } else if (returnCode>0) {
+    delete cardReader_;
+    cardReader_ = new CoinMpsCardReader ( input, this);
+  }
+  return readMps(numberSets,sets);
+}
+int CoinMpsIO::readMps()
+{
+  int numberSets=0;
+  CoinSet ** sets=NULL;
+  int returnCode = readMps(numberSets,sets);
+  for (int i=0;i<numberSets;i++)
+    delete sets[i];
+  delete [] sets;
+  return returnCode;
+}
+int CoinMpsIO::readMps(int & numberSets,CoinSet ** &sets)
+{
+  bool ifmps;
+
+  cardReader_->readToNextSection();
+
+  if ( cardReader_->whichSection (  ) == COIN_NAME_SECTION ) {
+    ifmps = true;
+    // save name of section
+    free(problemName_);
+    problemName_=CoinStrdup(cardReader_->columnName());
+  } else if ( cardReader_->whichSection (  ) == COIN_UNKNOWN_SECTION ) {
+    handler_->message(COIN_MPS_BADFILE1,messages_)<<cardReader_->card()
+						  <<1
+						 <<fileName_
+						  <<CoinMessageEol;
+
+    if (cardReader_->fileInput()->getReadType()!="plain") 
+      handler_->message(COIN_MPS_BADFILE2,messages_)
+        <<cardReader_->fileInput()->getReadType()
+        <<CoinMessageEol;
+
+    return -2;
+  } else if ( cardReader_->whichSection (  ) != COIN_EOF_SECTION ) {
+    // save name of section
+    free(problemName_);
+    problemName_=CoinStrdup(cardReader_->card());
+    ifmps = false;
+  } else {
+    handler_->message(COIN_MPS_EOF,messages_)<<fileName_
+					    <<CoinMessageEol;
+    return -3;
+  }
+  CoinBigIndex *start;
+  COINRowIndex *row;
+  double *element;
+  objectiveOffset_ = 0.0;
+
+  int numberErrors = 0;
+  int i;
+  if ( ifmps ) {
+    // mps file - always read in free format
+    bool gotNrow = false;
+    // allow strings ?
+    if (allowStringElements_)
+      cardReader_->setStringsAllowed();
+
+    //get ROWS
+    cardReader_->nextField (  ) ;
+    // Fudge for what ever code has OBJSENSE
+    if (!strncmp(cardReader_->card(),"OBJSENSE",8)) {
+      cardReader_->nextField();
+      int i;
+      const char * thisCard = cardReader_->card();
+      int direction = 0;
+      for (i=0;i<20;i++) {
+	if (thisCard[i]!=' ') {
+	  if (!strncmp(thisCard+i,"MAX",3))
+	    direction=-1;
+	  else if (!strncmp(thisCard+i,"MIN",3))
+	    direction=1;
+	  break;
+	}
+      }
+      if (!direction)
+	printf("No MAX/MIN found after OBJSENSE\n");
+      else 
+	printf("%s found after OBJSENSE - Coin ignores\n",
+	       (direction>0 ? "MIN" : "MAX"));
+      cardReader_->nextField();
+    }
+    if ( cardReader_->whichSection (  ) != COIN_ROW_SECTION ) {
+      handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						    <<cardReader_->card()
+						    <<CoinMessageEol;
+      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+      return numberErrors+100000;
+    }
+    //use malloc etc as I don't know how to do realloc in C++
+    numberRows_ = 0;
+    numberColumns_ = 0;
+    numberElements_ = 0;
+    COINRowIndex maxRows = 1000;
+    COINMpsType *rowType =
+
+      reinterpret_cast< COINMpsType *> (malloc ( maxRows * sizeof ( COINMpsType )));
+    char **rowName = reinterpret_cast<char **> (malloc ( maxRows * sizeof ( char * )));
+
+    // for discarded free rows
+    COINRowIndex maxFreeRows = 100;
+    COINRowIndex numberOtherFreeRows = 0;
+    char **freeRowName =
+
+      reinterpret_cast<char **> (malloc ( maxFreeRows * sizeof ( char * )));
+    while ( cardReader_->nextField (  ) == COIN_ROW_SECTION ) {
+      switch ( cardReader_->mpsType (  ) ) {
+      case COIN_N_ROW:
+	if ( !gotNrow ) {
+	  gotNrow = true;
+	  // save name of section
+	  free(objectiveName_);
+	  objectiveName_=CoinStrdup(cardReader_->columnName());
+	} else {
+	  // add to discard list
+	  if ( numberOtherFreeRows == maxFreeRows ) {
+	    maxFreeRows = ( 3 * maxFreeRows ) / 2 + 100;
+	    freeRowName =
+	      reinterpret_cast<char **> (realloc ( freeRowName,
+					      maxFreeRows * sizeof ( char * )));
+	  }
+	  freeRowName[numberOtherFreeRows] =
+	    CoinStrdup ( cardReader_->columnName (  ) );
+	  numberOtherFreeRows++;
+	}
+	break;
+      case COIN_E_ROW:
+      case COIN_L_ROW:
+      case COIN_G_ROW:
+	if ( numberRows_ == maxRows ) {
+	  maxRows = ( 3 * maxRows ) / 2 + 1000;
+	  rowType =
+	    reinterpret_cast<COINMpsType *> (realloc ( rowType,
+						       maxRows * sizeof ( COINMpsType )));
+	  rowName =
+
+	    reinterpret_cast<char **> (realloc ( rowName, maxRows * sizeof ( char * )));
+	}
+	rowType[numberRows_] = cardReader_->mpsType (  );
+#ifndef NONAMES
+	rowName[numberRows_] = CoinStrdup ( cardReader_->columnName (  ) );
+#endif
+	numberRows_++;
+	break;
+      default:
+	numberErrors++;
+	if ( numberErrors < 100 ) {
+	  handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						       <<cardReader_->card()
+						       <<CoinMessageEol;
+	} else if (numberErrors > 100000) {
+	  handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	  return numberErrors;
+	}
+      }
+    }
+    if ( cardReader_->whichSection (  ) != COIN_COLUMN_SECTION ) {
+      handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						    <<cardReader_->card()
+						    <<CoinMessageEol;
+      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+      return numberErrors+100000;
+    }
+    //assert ( gotNrow );
+    if (numberRows_)
+      rowType =
+	reinterpret_cast<COINMpsType *> (realloc ( rowType,
+						   numberRows_ * sizeof ( COINMpsType )));
+    else
+      rowType =
+	reinterpret_cast<COINMpsType *> (realloc ( rowType,sizeof ( COINMpsType )));
+    // put objective and other free rows at end
+    rowName =
+      reinterpret_cast<char **> (realloc ( rowName,
+			    ( numberRows_ + 1 +
+
+			      numberOtherFreeRows ) * sizeof ( char * )));
+#ifndef NONAMES
+    rowName[numberRows_] = CoinStrdup(objectiveName_);
+    memcpy ( rowName + numberRows_ + 1, freeRowName,
+	     numberOtherFreeRows * sizeof ( char * ) );
+    // now we can get rid of this array
+    free(freeRowName);
+#else
+    memset(rowName,0,(numberRows_+1)*sizeof(char **));
+#endif
+
+    startHash ( rowName, numberRows_ + 1 + numberOtherFreeRows , 0 );
+    COINColumnIndex maxColumns = 1000 + numberRows_ / 5;
+    CoinBigIndex maxElements = 5000 + numberRows_ / 2;
+    COINMpsType *columnType = reinterpret_cast<COINMpsType *>
+      (malloc ( maxColumns * sizeof ( COINMpsType )));
+    char **columnName = reinterpret_cast<char **> (malloc ( maxColumns * sizeof ( char * )));
+
+    objective_ = reinterpret_cast<double *> (malloc ( maxColumns * sizeof ( double )));
+    start = reinterpret_cast<CoinBigIndex *>
+      (malloc ( ( maxColumns + 1 ) * sizeof ( CoinBigIndex )));
+    row = reinterpret_cast<COINRowIndex *>
+      (malloc ( maxElements * sizeof ( COINRowIndex )));
+    element =
+      reinterpret_cast<double *> (malloc ( maxElements * sizeof ( double )));
+    // for duplicates
+    CoinBigIndex *rowUsed = new CoinBigIndex[numberRows_];
+
+    for (i=0;i<numberRows_;i++) {
+      rowUsed[i]=-1;
+    }
+    bool objUsed = false;
+
+    numberElements_ = 0;
+    char lastColumn[200];
+
+    memset ( lastColumn, '\0', 200 );
+    COINColumnIndex column = -1;
+    bool inIntegerSet = false;
+    COINColumnIndex numberIntegers = 0;
+
+    while ( cardReader_->nextField (  ) == COIN_COLUMN_SECTION ) {
+      switch ( cardReader_->mpsType (  ) ) {
+      case COIN_BLANK_COLUMN:
+	if ( strcmp ( lastColumn, cardReader_->columnName (  ) ) ) {
+	  // new column
+
+	  // reset old column and take out tiny
+	  if ( numberColumns_ ) {
+	    objUsed = false;
+	    CoinBigIndex i;
+	    CoinBigIndex k = start[column];
+
+	    for ( i = k; i < numberElements_; i++ ) {
+	      COINRowIndex irow = row[i];
+#if 0
+	      if ( fabs ( element[i] ) > smallElement_ ) {
+		element[k++] = element[i];
+	      }
+#endif
+	      rowUsed[irow] = -1;
+	    }
+	    //numberElements_ = k;
+	  }
+	  column = numberColumns_;
+	  if ( numberColumns_ == maxColumns ) {
+	    maxColumns = ( 3 * maxColumns ) / 2 + 1000;
+	    columnType = reinterpret_cast<COINMpsType *>
+	      (realloc ( columnType, maxColumns * sizeof ( COINMpsType )));
+	    columnName = reinterpret_cast<char **>
+	      (realloc ( columnName, maxColumns * sizeof ( char * )));
+
+	    objective_ = reinterpret_cast<double *>
+	      (realloc ( objective_, maxColumns * sizeof ( double )));
+	    start = reinterpret_cast<CoinBigIndex *>
+	      (realloc ( start,
+			 ( maxColumns + 1 ) * sizeof ( CoinBigIndex )));
+	  }
+	  if ( !inIntegerSet ) {
+	    columnType[column] = COIN_UNSET_BOUND;
+	  } else {
+	    columnType[column] = COIN_INTORG;
+	    numberIntegers++;
+	  }
+#ifndef NONAMES
+	  columnName[column] = CoinStrdup ( cardReader_->columnName (  ) );
+#else
+          columnName[column]=NULL;
+#endif
+	  strcpy ( lastColumn, cardReader_->columnName (  ) );
+	  objective_[column] = 0.0;
+	  start[column] = numberElements_;
+	  numberColumns_++;
+	}
+	if ( fabs ( cardReader_->value (  ) ) > smallElement_ ) {
+	  if ( numberElements_ == maxElements ) {
+	    maxElements = ( 3 * maxElements ) / 2 + 1000;
+	    row = reinterpret_cast<COINRowIndex *>
+	      (realloc ( row, maxElements * sizeof ( COINRowIndex )));
+	    element = reinterpret_cast<double *>
+	      (realloc ( element, maxElements * sizeof ( double )));
+	  }
+	  // get row number
+	  COINRowIndex irow = findHash ( cardReader_->rowName (  ) , 0 );
+
+	  if ( irow >= 0 ) {
+	    double value = cardReader_->value (  );
+
+	    // check for duplicates
+	    if ( irow == numberRows_ ) {
+	      // objective
+	      if ( objUsed ) {
+		numberErrors++;
+		if ( numberErrors < 100 ) {
+		  handler_->message(COIN_MPS_DUPOBJ,messages_)
+		    <<cardReader_->cardNumber()<<cardReader_->card()
+		    <<CoinMessageEol;
+		} else if (numberErrors > 100000) {
+		  handler_->message(COIN_MPS_RETURNING,messages_)
+		    <<CoinMessageEol;
+		  return numberErrors;
+		}
+	      } else {
+		objUsed = true;
+	      }
+	      value += objective_[column];
+	      if ( fabs ( value ) <= smallElement_ )
+		value = 0.0;
+	      objective_[column] = value;
+	    } else if ( irow < numberRows_ ) {
+	      // other free rows will just be discarded so won't get here
+	      if ( rowUsed[irow] >= 0 ) {
+		element[rowUsed[irow]] += value;
+		numberErrors++;
+		if ( numberErrors < 100 ) {
+		  handler_->message(COIN_MPS_DUPROW,messages_)
+		    <<cardReader_->rowName()<<cardReader_->cardNumber()
+		    <<cardReader_->card()
+		    <<CoinMessageEol;
+		} else if (numberErrors > 100000) {
+		  handler_->message(COIN_MPS_RETURNING,messages_)
+		    <<CoinMessageEol;
+		  return numberErrors;
+		}
+	      } else {
+		row[numberElements_] = irow;
+		element[numberElements_] = value;
+		rowUsed[irow] = numberElements_;
+		numberElements_++;
+	      }
+	    }
+	  } else {
+	    numberErrors++;
+	    if ( numberErrors < 100 ) {
+		  handler_->message(COIN_MPS_NOMATCHROW,messages_)
+		    <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card()
+		    <<CoinMessageEol;
+	    } else if (numberErrors > 100000) {
+	      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	      return numberErrors;
+	    }
+	  }
+	} else if (cardReader_->value () == STRING_VALUE ) {
+	  // tiny element - string
+	  const char * s = cardReader_->valueString();
+	  assert (*s=='=');
+	  // get row number
+	  COINRowIndex irow = findHash ( cardReader_->rowName (  ) , 0 );
+
+	  if ( irow >= 0 ) {
+	    addString(irow,column,s+1);
+	  } else {
+	    numberErrors++;
+	    if ( numberErrors < 100 ) {
+		  handler_->message(COIN_MPS_NOMATCHROW,messages_)
+		    <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card()
+		    <<CoinMessageEol;
+	    } else if (numberErrors > 100000) {
+	      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	      return numberErrors;
+	    }
+	  }
+	}
+	break;
+      case COIN_INTORG:
+	inIntegerSet = true;
+	break;
+      case COIN_INTEND:
+	inIntegerSet = false;
+	break;
+      case COIN_S1_COLUMN:
+      case COIN_S2_COLUMN:
+      case COIN_S3_COLUMN:
+      case COIN_SOSEND:
+	std::cout << "** code sos etc later" << std::endl;
+	abort (  );
+	break;
+      default:
+	numberErrors++;
+	if ( numberErrors < 100 ) {
+	  handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						       <<cardReader_->card()
+						       <<CoinMessageEol;
+	} else if (numberErrors > 100000) {
+	  handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	  return numberErrors;
+	}
+      }
+    }
+    start[numberColumns_] = numberElements_;
+    delete[]rowUsed;
+    if ( cardReader_->whichSection (  ) != COIN_RHS_SECTION ) {
+      handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						    <<cardReader_->card()
+						    <<CoinMessageEol;
+      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+      return numberErrors+100000;
+    }
+    if (numberColumns_) {
+      columnType =
+	reinterpret_cast<COINMpsType *> (realloc ( columnType,
+						   numberColumns_ * sizeof ( COINMpsType )));
+      columnName =
+	
+	reinterpret_cast<char **> (realloc ( columnName, numberColumns_ * sizeof ( char * )));
+      objective_ = reinterpret_cast<double *>
+	(realloc ( objective_, numberColumns_ * sizeof ( double )));
+    } else {
+      columnType =
+	reinterpret_cast<COINMpsType *> (realloc ( columnType,
+				     sizeof ( COINMpsType )));
+      columnName =
+	
+	reinterpret_cast<char **> (realloc ( columnName, sizeof ( char * )));
+      objective_ = reinterpret_cast<double *>
+	(realloc ( objective_, sizeof ( double )));
+    }
+    start = reinterpret_cast<CoinBigIndex *>
+      (realloc ( start, ( numberColumns_ + 1 ) * sizeof ( CoinBigIndex )));
+    if (numberElements_) {
+      row = reinterpret_cast<COINRowIndex *>
+	(realloc ( row, numberElements_ * sizeof ( COINRowIndex )));
+      element = reinterpret_cast<double *>
+	(realloc ( element, numberElements_ * sizeof ( double )));
+    } else {
+      row = reinterpret_cast<COINRowIndex *>
+	(realloc ( row,  sizeof ( COINRowIndex )));
+      element = reinterpret_cast<double *>
+	(realloc ( element, sizeof ( double )));
+    }
+    if (numberRows_) {
+      rowlower_ = reinterpret_cast<double *> (malloc ( numberRows_ * sizeof ( double )));
+      rowupper_ = reinterpret_cast<double *> (malloc ( numberRows_ * sizeof ( double )));
+    } else {
+      rowlower_ = reinterpret_cast<double *> (malloc ( sizeof ( double )));
+      rowupper_ = reinterpret_cast<double *> (malloc ( sizeof ( double )));
+    }
+    for (i=0;i<numberRows_;i++) {
+      rowlower_[i]=-infinity_;
+      rowupper_[i]=infinity_;
+    }
+    objUsed = false;
+    memset ( lastColumn, '\0', 200 );
+    bool gotRhs = false;
+
+    // need coding for blank rhs
+    while ( cardReader_->nextField (  ) == COIN_RHS_SECTION ) {
+      COINRowIndex irow;
+
+      switch ( cardReader_->mpsType (  ) ) {
+      case COIN_BLANK_COLUMN:
+	if ( strcmp ( lastColumn, cardReader_->columnName (  ) ) ) {
+
+	  // skip rest if got a rhs
+	  if ( gotRhs ) {
+	    while ( cardReader_->nextField (  ) == COIN_RHS_SECTION ) {
+	    }
+	    break;
+	  } else {
+	    gotRhs = true;
+	    strcpy ( lastColumn, cardReader_->columnName (  ) );
+	    // save name of section
+	    free(rhsName_);
+	    rhsName_=CoinStrdup(cardReader_->columnName());
+	  }
+	}
+	// get row number
+	irow = findHash ( cardReader_->rowName (  ) , 0 );
+	if ( irow >= 0 ) {
+	  double value = cardReader_->value (  );
+
+	  // check for duplicates
+	  if ( irow == numberRows_ ) {
+	    // objective
+	    if ( objUsed ) {
+	      numberErrors++;
+	      if ( numberErrors < 100 ) {
+		  handler_->message(COIN_MPS_DUPOBJ,messages_)
+		    <<cardReader_->cardNumber()<<cardReader_->card()
+		    <<CoinMessageEol;
+	      } else if (numberErrors > 100000) {
+		handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+		return numberErrors;
+	      }
+	    } else {
+	      objUsed = true;
+	    }
+	    if (value==STRING_VALUE) {
+	      value=0.0;
+	      // tiny element - string
+	      const char * s = cardReader_->valueString();
+	      assert (*s=='=');
+	      addString(irow,numberColumns_,s+1);
+	    }
+	    objectiveOffset_ += value;
+	  } else if ( irow < numberRows_ ) {
+	    if ( rowlower_[irow] != -infinity_ ) {
+	      numberErrors++;
+	      if ( numberErrors < 100 ) {
+		handler_->message(COIN_MPS_DUPROW,messages_)
+		  <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card()
+		  <<CoinMessageEol;
+	      } else if (numberErrors > 100000) {
+		handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+		return numberErrors;
+	      }
+	    } else {
+	      if (value==STRING_VALUE) {
+		value=0.0;
+		// tiny element - string
+		const char * s = cardReader_->valueString();
+		assert (*s=='=');
+		addString(irow,numberColumns_,s+1);
+	      }
+	      rowlower_[irow] = value;
+	    }
+	  }
+	} else {
+	  numberErrors++;
+	  if ( numberErrors < 100 ) {
+	    handler_->message(COIN_MPS_NOMATCHROW,messages_)
+	      <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card()
+	      <<CoinMessageEol;
+	  } else if (numberErrors > 100000) {
+	    handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	    return numberErrors;
+	  }
+	}
+	break;
+      default:
+	numberErrors++;
+	if ( numberErrors < 100 ) {
+	  handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						       <<cardReader_->card()
+						       <<CoinMessageEol;
+	} else if (numberErrors > 100000) {
+	  handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	  return numberErrors;
+	}
+      }
+    }
+    if ( cardReader_->whichSection (  ) == COIN_RANGES_SECTION ) {
+      memset ( lastColumn, '\0', 200 );
+      bool gotRange = false;
+      COINRowIndex irow;
+
+      // need coding for blank range
+      while ( cardReader_->nextField (  ) == COIN_RANGES_SECTION ) {
+	switch ( cardReader_->mpsType (  ) ) {
+	case COIN_BLANK_COLUMN:
+	  if ( strcmp ( lastColumn, cardReader_->columnName (  ) ) ) {
+
+	    // skip rest if got a range
+	    if ( gotRange ) {
+	      while ( cardReader_->nextField (  ) == COIN_RANGES_SECTION ) {
+	      }
+	      break;
+	    } else {
+	      gotRange = true;
+	      strcpy ( lastColumn, cardReader_->columnName (  ) );
+	      // save name of section
+	      free(rangeName_);
+	      rangeName_=CoinStrdup(cardReader_->columnName());
+	    }
+	  }
+	  // get row number
+	  irow = findHash ( cardReader_->rowName (  ) , 0 );
+	  if ( irow >= 0 ) {
+	    double value = cardReader_->value (  );
+
+	    // check for duplicates
+	    if ( irow == numberRows_ ) {
+	      // objective
+	      numberErrors++;
+	      if ( numberErrors < 100 ) {
+		  handler_->message(COIN_MPS_DUPOBJ,messages_)
+		    <<cardReader_->cardNumber()<<cardReader_->card()
+		    <<CoinMessageEol;
+	      } else if (numberErrors > 100000) {
+		handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+		return numberErrors;
+	      }
+	    } else {
+	      if ( rowupper_[irow] != infinity_ ) {
+		numberErrors++;
+		if ( numberErrors < 100 ) {
+		  handler_->message(COIN_MPS_DUPROW,messages_)
+		    <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card()
+		    <<CoinMessageEol;
+		} else if (numberErrors > 100000) {
+		  handler_->message(COIN_MPS_RETURNING,messages_)
+		    <<CoinMessageEol;
+		  return numberErrors;
+		}
+	      } else {
+		rowupper_[irow] = value;
+	      }
+	    }
+	  } else {
+	    numberErrors++;
+	    if ( numberErrors < 100 ) {
+	      handler_->message(COIN_MPS_NOMATCHROW,messages_)
+		<<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card()
+		<<CoinMessageEol;
+	    } else if (numberErrors > 100000) {
+	      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	      return numberErrors;
+	    }
+	  }
+	  break;
+	default:
+	  numberErrors++;
+	  if ( numberErrors < 100 ) {
+	  handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						       <<cardReader_->card()
+						       <<CoinMessageEol;
+	  } else if (numberErrors > 100000) {
+	    handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	    return numberErrors;
+	  }
+	}
+      }
+    }
+    stopHash ( 0 );
+    // massage ranges
+    {
+      COINRowIndex irow;
+
+      for ( irow = 0; irow < numberRows_; irow++ ) {
+	double lo = rowlower_[irow];
+	double up = rowupper_[irow];
+	double up2 = rowupper_[irow];	//range
+
+	switch ( rowType[irow] ) {
+	case COIN_E_ROW:
+	  if ( lo == -infinity_ )
+	    lo = 0.0;
+	  if ( up == infinity_ ) {
+	    up = lo;
+	  } else if ( up > 0.0 ) {
+	    up += lo;
+	  } else {
+	    up = lo;
+	    lo += up2;
+	  }
+	  break;
+	case COIN_L_ROW:
+	  if ( lo == -infinity_ ) {
+	    up = 0.0;
+	  } else {
+	    up = lo;
+	    lo = -infinity_;
+	  }
+	  if ( up2 != infinity_ ) {
+	    lo = up - fabs ( up2 );
+	  }
+	  break;
+	case COIN_G_ROW:
+	  if ( lo == -infinity_ ) {
+	    lo = 0.0;
+	    up = infinity_;
+	  } else {
+	    up = infinity_;
+	  }
+	  if ( up2 != infinity_ ) {
+	    up = lo + fabs ( up2 );
+	  }
+	  break;
+	default:
+	  abort();
+	}
+	rowlower_[irow] = lo;
+	rowupper_[irow] = up;
+      }
+    }
+    free ( rowType );
+    // default bounds
+    if (numberColumns_) {
+      collower_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+      colupper_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+    } else {
+      collower_ = reinterpret_cast<double *> (malloc ( sizeof ( double )));
+      colupper_ = reinterpret_cast<double *> (malloc ( sizeof ( double )));
+    }
+    for (i=0;i<numberColumns_;i++) {
+      collower_[i]=0.0;
+      colupper_[i]=infinity_;
+    }
+    // set up integer region just in case
+    if (numberColumns_) 
+      integerType_ = reinterpret_cast<char *> (malloc (numberColumns_*sizeof(char)));
+    else
+      integerType_ = reinterpret_cast<char *> (malloc (sizeof(char)));
+    for ( column = 0; column < numberColumns_; column++ ) {
+      if ( columnType[column] == COIN_INTORG ) {
+	columnType[column] = COIN_UNSET_BOUND;
+	integerType_[column] = 1;
+      } else {
+	integerType_[column] = 0;
+      }
+    }
+    // start hash even if no bound section - to make sure names survive
+    startHash ( columnName, numberColumns_ , 1 );
+    if ( cardReader_->whichSection (  ) == COIN_BOUNDS_SECTION ) {
+      memset ( lastColumn, '\0', 200 );
+      bool gotBound = false;
+
+      while ( cardReader_->nextField (  ) == COIN_BOUNDS_SECTION ) {
+	if ( strcmp ( lastColumn, cardReader_->columnName (  ) ) ) {
+
+	  // skip rest if got a bound
+	  if ( gotBound ) {
+	    while ( cardReader_->nextField (  ) == COIN_BOUNDS_SECTION ) {
+	    }
+	    break;
+	  } else {
+	    gotBound = true;;
+	    strcpy ( lastColumn, cardReader_->columnName (  ) );
+	    // save name of section
+	    free(boundName_);
+	    boundName_=CoinStrdup(cardReader_->columnName());
+	  }
+	}
+	// get column number
+	COINColumnIndex icolumn = findHash ( cardReader_->rowName (  ) , 1 );
+
+	if ( icolumn >= 0 ) {
+	  double value = cardReader_->value (  );
+	  bool ifError = false;
+
+	  switch ( cardReader_->mpsType (  ) ) {
+	  case COIN_UP_BOUND:
+	    if ( value == -1.0e100 )
+	      ifError = true;
+	    if (value==STRING_VALUE) {
+	      value=1.0e10;
+	      // tiny element - string
+	      const char * s = cardReader_->valueString();
+	      assert (*s=='=');
+	      addString(numberRows_+2,icolumn,s+1);
+	    }
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	      if ( value < 0.0 ) {
+		collower_[icolumn] = -infinity_;
+	      }
+	    } else if ( columnType[icolumn] == COIN_LO_BOUND ||
+                        columnType[icolumn] == COIN_LI_BOUND) {
+	      if ( value < collower_[icolumn] ) {
+		ifError = true;
+	      } else if ( value < collower_[icolumn] + smallElement_ ) {
+		value = collower_[icolumn];
+	      }
+	    } else if ( columnType[icolumn] == COIN_MI_BOUND ) {
+	    } else {
+	      ifError = true;
+	    }
+            if (value>1.0e25)
+              value=infinity_;
+	    colupper_[icolumn] = value;
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+ 	        columnType[icolumn] = COIN_UP_BOUND;
+            } else {
+ 	        columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
+            }
+	    break;
+	  case COIN_LO_BOUND:
+	    if ( value == -1.0e100 )
+	      ifError = true;
+	    if (value==STRING_VALUE) {
+	      value=-1.0e10;
+	      // tiny element - string
+	      const char * s = cardReader_->valueString();
+	      assert (*s=='=');
+	      addString(numberRows_+1,icolumn,s+1);
+	    }
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	    } else if ( columnType[icolumn] == COIN_UP_BOUND ||
+			columnType[icolumn] == COIN_UI_BOUND ) {
+	      if ( value > colupper_[icolumn] ) {
+		ifError = true;
+	      } else if ( value > colupper_[icolumn] - smallElement_ ) {
+		value = colupper_[icolumn];
+	      }
+	    } else if ( columnType[icolumn] == COIN_PL_BOUND ) {
+	    } else {
+	      ifError = true;
+	    }
+            if (value<-1.0e25)
+              value=-infinity_;
+	    collower_[icolumn] = value;
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+ 	        columnType[icolumn] = COIN_LO_BOUND;
+            } else {
+ 	        columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
+            }
+	    break;
+	  case COIN_FX_BOUND:
+	    if ( value == -1.0e100 )
+	      ifError = true;
+	    if (value==STRING_VALUE) {
+	      value=0.0;
+	      // tiny element - string
+	      const char * s = cardReader_->valueString();
+	      assert (*s=='=');
+	      addString(numberRows_+1,icolumn,s+1);
+	      addString(numberRows_+2,icolumn,s+1);
+	    }
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {    
+	    } else if (columnType[icolumn] == COIN_FX_BOUND ) {
+		ifError=true;
+            } else if (integerType_[icolumn] ) {
+	      // Allow so people can easily put FX's at end
+	      double value2 = floor(value);
+	      if (fabs(value2-value)>1.0e-12||
+		  value2<collower_[icolumn]||
+		  value2>colupper_[icolumn]) {
+		ifError=true;
+	      } else {
+		// take off integer list
+		    numberIntegers--;
+		    integerType_[icolumn] = 0;
+	      }
+	    } else {
+	      ifError = true;
+	    }
+	    collower_[icolumn] = value;
+	    colupper_[icolumn] = value;
+	    columnType[icolumn] = COIN_FX_BOUND;
+	    break;
+	  case COIN_FR_BOUND:
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	    } else {
+	      ifError = true;
+	    }
+	    collower_[icolumn] = -infinity_;
+	    colupper_[icolumn] = infinity_;
+	    columnType[icolumn] = COIN_FR_BOUND;
+	    break;
+	  case COIN_MI_BOUND:
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	      colupper_[icolumn] = COIN_DBL_MAX;
+	    } else if ( columnType[icolumn] == COIN_UP_BOUND ||
+			columnType[icolumn] == COIN_UI_BOUND ) {
+	    } else {
+	      ifError = true;
+	    }
+	    collower_[icolumn] = -infinity_;
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+ 	        columnType[icolumn] = COIN_MI_BOUND;
+            } else {
+ 	        columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
+            }
+	    break;
+	  case COIN_PL_BOUND:
+	    // change to allow if no upper bound set
+	    //if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	    if (colupper_[icolumn]==infinity_) {
+	    } else {
+	      ifError = true;
+	    }
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+ 	        columnType[icolumn] = COIN_PL_BOUND;
+            } else {
+ 	        columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
+            }
+	    break;
+	  case COIN_UI_BOUND:
+	    if (value==STRING_VALUE) {
+	      value=1.0e20;
+	      // tiny element - string
+	      const char * s = cardReader_->valueString();
+	      assert (*s=='=');
+	      addString(numberRows_+2,icolumn,s+1);
+	    }
+#if 0
+	    if ( value == -1.0e100 ) 
+	      ifError = true;
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	    } else if ( columnType[icolumn] == COIN_LO_BOUND ||
+                        columnType[icolumn] == COIN_LI_BOUND) {
+	      if ( value < collower_[icolumn] ) {
+		ifError = true;
+	      } else if ( value < collower_[icolumn] + smallElement_ ) {
+		value = collower_[icolumn];
+	      }
+	    } else if ( columnType[icolumn] == COIN_MI_BOUND ) {
+	    } else {
+	      ifError = true;
+	    }
+#else
+	    if ( value == -1.0e100 ) {
+	       value = infinity_;
+	       if (columnType[icolumn] != COIN_UNSET_BOUND &&
+		       columnType[icolumn] != COIN_LO_BOUND &&
+		       columnType[icolumn] != COIN_LI_BOUND &&
+		       columnType[icolumn] != COIN_MI_BOUND) {
+		     ifError = true;
+	       }
+	    } else {
+	       if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	       } else if ( columnType[icolumn] == COIN_LO_BOUND ||
+			   columnType[icolumn] == COIN_LI_BOUND ||
+                           columnType[icolumn] == COIN_MI_BOUND ) {
+		  if ( value < collower_[icolumn] ) {
+		     ifError = true;
+		  } else if ( value < collower_[icolumn] + smallElement_ ) {
+		     value = collower_[icolumn];
+		  }
+	       } else {
+		  ifError = true;
+	       }
+	    }
+#endif
+            if (value>1.0e25)
+              value=infinity_;
+	    colupper_[icolumn] = value;
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+ 	        columnType[icolumn] = COIN_UI_BOUND;
+            } else {
+ 	        columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
+            }
+	    if ( !integerType_[icolumn] ) {
+	      numberIntegers++;
+	      integerType_[icolumn] = 1;
+	    }
+	    break;
+	  case COIN_LI_BOUND:
+	    if ( value == -1.0e100 )
+	      ifError = true;
+	    if (value==STRING_VALUE) {
+	      value=-1.0e20;
+	      // tiny element - string
+	      const char * s = cardReader_->valueString();
+	      assert (*s=='=');
+	      addString(numberRows_+1,icolumn,s+1);
+	    }
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	    } else if ( columnType[icolumn] == COIN_UP_BOUND ||
+			columnType[icolumn] == COIN_UI_BOUND ) {
+	      if ( value > colupper_[icolumn] ) {
+		ifError = true;
+	      } else if ( value > colupper_[icolumn] - smallElement_ ) {
+		value = colupper_[icolumn];
+	      }
+	    } else if ( columnType[icolumn] == COIN_PL_BOUND ) {
+	    } else {
+	      ifError = true;
+	    }
+            if (value<-1.0e25)
+              value=-infinity_;
+	    collower_[icolumn] = value;
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+ 	        columnType[icolumn] = COIN_LI_BOUND;
+            } else {
+ 	        columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
+            }
+	    if ( !integerType_[icolumn] ) {
+	      numberIntegers++;
+	      integerType_[icolumn] = 1;
+	    }
+	    break;
+	  case COIN_BV_BOUND:
+	    if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
+	    } else {
+	      ifError = true;
+	    }
+	    collower_[icolumn] = 0.0;
+	    colupper_[icolumn] = 1.0;
+	    columnType[icolumn] = COIN_BV_BOUND;
+	    if ( !integerType_[icolumn] ) {
+	      numberIntegers++;
+	      integerType_[icolumn] = 1;
+	    }
+	    break;
+	  default:
+	    ifError = true;
+	    break;
+	  }
+	  if ( ifError ) {
+	    numberErrors++;
+	    if ( numberErrors < 100 ) {
+	      handler_->message(COIN_MPS_BADIMAGE,messages_)
+		<<cardReader_->cardNumber()
+		<<cardReader_->card()
+		<<CoinMessageEol;
+	    } else if (numberErrors > 100000) {
+	      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	      return numberErrors;
+	    }
+	  }
+	} else {
+	  numberErrors++;
+	  if ( numberErrors < 100 ) {
+	    handler_->message(COIN_MPS_NOMATCHCOL,messages_)
+	      <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card()
+	      <<CoinMessageEol;
+	  } else if (numberErrors > 100000) {
+	    handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	    return numberErrors;
+	  }
+	}
+      }
+    }
+    //for (i=0;i<numberSets;i++)
+    //delete sets[i];
+    numberSets=0;
+    //delete [] sets;
+    sets=NULL;
+    
+    // Do SOS if found
+    if ( cardReader_->whichSection (  ) == COIN_SOS_SECTION ) {
+      // Go to free format
+      cardReader_->setFreeFormat(true);
+      int numberInSet=0;
+      int iType=-1;
+      int * which = new int[numberColumns_];
+      double * weights = new double[numberColumns_];
+      CoinSet ** setsA = new CoinSet * [numberColumns_];
+      while ( cardReader_->nextField (  ) == COIN_SOS_SECTION ) {
+	if (cardReader_->mpsType()==COIN_S1_BOUND||
+	    cardReader_->mpsType()==COIN_S2_BOUND) {
+	  if (numberInSet) {
+	    CoinSosSet * newSet = new CoinSosSet(numberInSet,which,weights,iType);
+	    setsA[numberSets++]=newSet;
+	  }
+	  numberInSet=0;
+	  iType = cardReader_->mpsType()== COIN_S1_BOUND ? 1 : 2;
+	  // skip
+	  continue;
+	}
+	// get column number
+	COINColumnIndex icolumn = findHash ( cardReader_->columnName (  ) , 1 );
+	if ( icolumn >= 0 ) {
+	  //integerType_[icolumn]=2;
+	  double value = cardReader_->value (  );
+	  if (value==-1.0e100)
+	    value = atof(cardReader_->rowName()); // try from row name
+	  which[numberInSet]=icolumn;
+	  weights[numberInSet++]=value;
+	} else {
+	  numberErrors++;
+	  if ( numberErrors < 100 ) {
+	    handler_->message(COIN_MPS_NOMATCHCOL,messages_)
+	      <<cardReader_->columnName()<<cardReader_->cardNumber()<<cardReader_->card()
+	      <<CoinMessageEol;
+	  } else if (numberErrors > 100000) {
+	    handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	    return numberErrors;
+	  }
+	}
+      }
+      if (numberInSet) {
+	CoinSosSet * newSet = new CoinSosSet(numberInSet,which,weights,iType);
+	setsA[numberSets++]=newSet;
+      }
+      if (numberSets) {
+	sets = new CoinSet * [numberSets];
+	memcpy(sets,setsA,numberSets*sizeof(CoinSet **));
+      }
+      delete [] setsA;
+      delete [] which;
+      delete [] weights;
+    }
+    stopHash ( 1 );
+    // clean up integers
+    if ( !numberIntegers ) {
+      free(integerType_);
+      integerType_ = NULL;
+    } else {
+      COINColumnIndex icolumn;
+
+      for ( icolumn = 0; icolumn < numberColumns_; icolumn++ ) {
+	if ( integerType_[icolumn] ) {
+	  collower_[icolumn] = CoinMax( collower_[icolumn] , -MAX_INTEGER );
+	  // if 0 infinity make 0-1 ???
+	  if ( columnType[icolumn] == COIN_UNSET_BOUND ) 
+	    colupper_[icolumn] = defaultBound_;
+	  if ( colupper_[icolumn] > MAX_INTEGER ) 
+	    colupper_[icolumn] = MAX_INTEGER;
+	  // clean up to allow for bad reads on 1.0e2 etc
+	  if (colupper_[icolumn]<1.0e10) {
+	    double value = colupper_[icolumn];
+	    double value2 = floor(value+0.5);
+	    if (value!=value2) {
+	      if (fabs(value-value2)<1.0e-5)
+		colupper_[icolumn]=value2;
+	    }
+	  }
+	  if (collower_[icolumn]>-1.0e10) {
+	    double value = collower_[icolumn];
+	    double value2 = floor(value+0.5);
+	    if (value!=value2) {
+	      if (fabs(value-value2)<1.0e-5)
+		collower_[icolumn]=value2;
+	    }
+	  }
+	}
+      }
+    }
+    free ( columnType );
+    if ( cardReader_->whichSection (  ) != COIN_ENDATA_SECTION &&
+	 cardReader_->whichSection (  ) != COIN_QUAD_SECTION &&
+	 cardReader_->whichSection (  ) != COIN_CONIC_SECTION ) {
+      handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						    <<cardReader_->card()
+						    <<CoinMessageEol;
+      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+      return numberErrors+100000;
+    }
+  } else {
+    // This is very simple format - what should we use?
+    COINColumnIndex i;
+    
+    /* old: 
+       FILE * fp = cardReader_->filePointer();
+       fscanf ( fp, "%d %d %d\n", &numberRows_, &numberColumns_, &i);
+    */
+    // new:
+    char buffer[1000];
+    cardReader_->fileInput ()->gets (buffer, 1000);
+    sscanf (buffer, "%d %d %d\n", &numberRows_, &numberColumns_, &i);
+
+    numberElements_  = i; // done this way in case numberElements_ long
+
+    rowlower_ = reinterpret_cast<double *> (malloc ( numberRows_ * sizeof ( double )));
+    rowupper_ = reinterpret_cast<double *> (malloc ( numberRows_ * sizeof ( double )));
+    for ( i = 0; i < numberRows_; i++ ) {
+      int j;
+
+      // old: fscanf ( fp, "%d %lg %lg\n", &j, &rowlower_[i], &rowupper_[i] );
+      // new:
+      cardReader_->fileInput ()->gets (buffer, 1000);
+      sscanf (buffer, "%d %lg %lg\n", &j, &rowlower_[i], &rowupper_[i] );
+
+      assert ( i == j );
+    }
+    collower_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+    colupper_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+    objective_= reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+    start = reinterpret_cast<CoinBigIndex *> (malloc ((numberColumns_ + 1) *
+				       sizeof (CoinBigIndex)));
+    row = reinterpret_cast<COINRowIndex *> (malloc (numberElements_ * sizeof (COINRowIndex)));
+    element = reinterpret_cast<double *> (malloc (numberElements_ * sizeof (double)));
+
+    start[0] = 0;
+    numberElements_ = 0;
+    for ( i = 0; i < numberColumns_; i++ ) {
+      int j;
+      int n;
+
+      /* old:
+	 fscanf ( fp, "%d %d %lg %lg %lg\n", &j, &n, 
+	          &collower_[i], &colupper_[i],
+	          &objective_[i] );
+      */
+      // new: 
+      cardReader_->fileInput ()->gets (buffer, 1000);
+      sscanf (buffer, "%d %d %lg %lg %lg\n", &j, &n, 
+	      &collower_[i], &colupper_[i], &objective_[i] );
+
+      assert ( i == j );
+      for ( j = 0; j < n; j++ ) {
+	/* old:
+	   fscanf ( fp, "       %d %lg\n", &row[numberElements_],
+		 &element[numberElements_] );
+	*/
+	// new: 
+	cardReader_->fileInput ()->gets (buffer, 1000);
+	sscanf (buffer, "       %d %lg\n", &row[numberElements_],
+		 &element[numberElements_] );
+
+	numberElements_++;
+      }
+      start[i + 1] = numberElements_;
+    }
+  }
+  // construct packed matrix
+  matrixByColumn_ = 
+    new CoinPackedMatrix(true,
+			numberRows_,numberColumns_,numberElements_,
+			element,row,start,NULL);
+  free ( row );
+  free ( start );
+  free ( element );
+
+  handler_->message(COIN_MPS_STATS,messages_)<<problemName_
+					    <<numberRows_
+					    <<numberColumns_
+					    <<numberElements_
+					    <<CoinMessageEol;
+  return numberErrors;
+}
+#ifdef COIN_HAS_GLPK
+#include "glpk.h"
+glp_tran* cbc_glp_tran = NULL;
+glp_prob* cbc_glp_prob = NULL;
+#endif
+/* Read a problem in GMPL (subset of AMPL)  format from the given filenames.
+   Thanks to Ted Ralphs - I just looked at his coding rather than look at the GMPL documentation.
+ */
+int 
+CoinMpsIO::readGMPL(const char * modelName, const char * dataName,
+                    bool keepNames)
+{
+#ifdef COIN_HAS_GLPK
+  int returnCode;
+  gutsOfDestructor();
+  // initialize
+  cbc_glp_tran = glp_mpl_alloc_wksp();
+  // read model
+  char name[2000]; // should be long enough
+  assert (strlen(modelName)<2000&&(!dataName||strlen(dataName)<2000));
+  strcpy(name,modelName);
+  returnCode = glp_mpl_read_model(cbc_glp_tran,name,false);
+  if (returnCode != 0) {
+    // errors
+    glp_mpl_free_wksp(cbc_glp_tran);
+    cbc_glp_tran = NULL;
+    return 1;
+  }
+  if (dataName) {
+    // read data
+    strcpy(name,dataName);
+    returnCode = glp_mpl_read_data(cbc_glp_tran,name);
+    if (returnCode != 0) {
+      // errors
+      glp_mpl_free_wksp(cbc_glp_tran);
+      cbc_glp_tran = NULL;
+      return 1;
+    }
+  }
+  // generate model
+  returnCode = glp_mpl_generate(cbc_glp_tran,NULL);
+  if (returnCode!=0) {
+    // errors
+    glp_mpl_free_wksp(cbc_glp_tran);
+    cbc_glp_tran = NULL;
+    return 2;
+  }
+  cbc_glp_prob = glp_create_prob();
+  glp_mpl_build_prob(cbc_glp_tran, cbc_glp_prob);
+  // Get number of rows, columns, and elements
+  numberRows_=glp_get_num_rows(cbc_glp_prob);
+  numberColumns_ = glp_get_num_cols(cbc_glp_prob);
+  numberElements_=glp_get_num_nz(cbc_glp_prob);
+  int iRow, iColumn;
+  CoinBigIndex * start = new CoinBigIndex [numberRows_+1];
+  int * index = new int [numberElements_];
+  double * element = new double[numberElements_];
+  // Row stuff
+  rowlower_ = reinterpret_cast<double *> (malloc ( numberRows_ * sizeof ( double )));
+  rowupper_ = reinterpret_cast<double *> (malloc ( numberRows_ * sizeof ( double )));
+  // and objective
+  objective_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+  problemName_= CoinStrdup(glp_get_prob_name(cbc_glp_prob));
+  int kRow=0;
+  start[0]=0;
+  numberElements_=0;
+  // spare space for checking
+  double * el = new double[numberColumns_];
+  int * ind = new int[numberColumns_];
+  char ** names = NULL;
+  if (keepNames) {
+    names = reinterpret_cast<char **> (malloc(numberRows_*sizeof(char *)));
+    names_[0] = names;
+    numberHash_[0] = numberRows_;
+  }
+  for (iRow=0; iRow<numberRows_;iRow++) {
+    int number = glp_get_mat_row(cbc_glp_prob,iRow+1,ind-1,el-1);
+    double rowLower,rowUpper;
+    int rowType;
+    rowLower = glp_get_row_lb(cbc_glp_prob, iRow+1);
+    rowUpper = glp_get_row_ub(cbc_glp_prob, iRow+1);
+    rowType  = glp_get_row_type(cbc_glp_prob, iRow+1); 
+    switch(rowType) {                                           
+    case GLP_LO: 
+      rowUpper =  COIN_DBL_MAX;
+      break;	 
+    case GLP_UP:
+      rowLower = -COIN_DBL_MAX;
+      break;
+    case GLP_FR:
+      rowLower = -COIN_DBL_MAX;
+       rowUpper =  COIN_DBL_MAX;
+     break;
+    default:
+      break;
+    }
+    rowlower_[kRow]=rowLower;
+    rowupper_[kRow]=rowUpper;
+    for (int i=0;i<number;i++) {
+      iColumn = ind[i]-1;
+      index[numberElements_]=iColumn;
+      element[numberElements_++]=el[i];
+    }
+    if (keepNames) {
+      strcpy(name,glp_get_row_name(cbc_glp_prob,iRow+1));
+      // could look at name?
+      names[kRow]=CoinStrdup(name);
+    }
+    kRow++;
+    start[kRow]=numberElements_;
+  }
+  delete [] el;
+  delete [] ind;
+
+   // FIXME why this variable is not used?
+  bool minimize=(glp_get_obj_dir(cbc_glp_prob)==GLP_MAX ? false : true);
+   // sign correct?
+  objectiveOffset_ = glp_get_obj_coef(cbc_glp_prob, 0);
+  for (int i=0;i<numberColumns_;i++)
+    objective_[i]=glp_get_obj_coef(cbc_glp_prob, i+1);
+  if (!minimize) {
+  for (int i=0;i<numberColumns_;i++)
+    objective_[i]=-objective_[i];
+    handler_->message(COIN_GENERAL_INFO,messages_)<<
+      " CoinMpsIO::readGMPL(): Maximization problem reformulated as minimization"
+						  <<CoinMessageEol;
+    objectiveOffset_ = -objectiveOffset_;
+  }
+
+  // Matrix
+  matrixByColumn_ = new CoinPackedMatrix(false,numberColumns_,numberRows_,numberElements_,
+                                  element,index,start,NULL);
+  matrixByColumn_->reverseOrdering();
+  delete [] element;
+  delete [] start;
+  delete [] index;
+  // Now do columns
+  collower_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+  colupper_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+  integerType_ = reinterpret_cast<char *> (malloc (numberColumns_*sizeof(char)));
+  if (keepNames) {
+    names = reinterpret_cast<char **> (malloc(numberColumns_*sizeof(char *)));
+    names_[1] = names;
+    numberHash_[1] = numberColumns_;
+  }
+  int numberIntegers=0;
+  for (iColumn=0; iColumn<numberColumns_;iColumn++) {
+    double columnLower = glp_get_col_lb(cbc_glp_prob, iColumn+1);
+    double columnUpper = glp_get_col_ub(cbc_glp_prob, iColumn+1);
+    int columnType = glp_get_col_type(cbc_glp_prob, iColumn+1);
+    switch(columnType) {                                           
+    case GLP_LO: 
+      columnUpper =  COIN_DBL_MAX;
+      break;	 
+    case GLP_UP:
+      columnLower = -COIN_DBL_MAX;
+      break;
+    case GLP_FR:
+      columnLower = -COIN_DBL_MAX;
+      columnUpper =  COIN_DBL_MAX;
+      break;
+    default:
+      break;
+    }
+    collower_[iColumn]=columnLower;
+    colupper_[iColumn]=columnUpper;
+    columnType = glp_get_col_kind(cbc_glp_prob,iColumn+1);
+    if (columnType==GLP_IV) {
+      integerType_[iColumn]=1;
+      numberIntegers++;
+      //assert ( collower_[iColumn] >= -MAX_INTEGER );
+      if ( collower_[iColumn] < -MAX_INTEGER ) 
+        collower_[iColumn] = -MAX_INTEGER;
+      if ( colupper_[iColumn] > MAX_INTEGER ) 
+        colupper_[iColumn] = MAX_INTEGER;
+    } else if (columnType==GLP_BV) {
+      numberIntegers++;
+      integerType_[iColumn]=1;
+      collower_[iColumn]=0.0;
+      colupper_[iColumn]=1.0;
+    } else {
+      integerType_[iColumn]=0;
+    }
+    if (keepNames) {
+      strcpy(name,glp_get_col_name(cbc_glp_prob,iColumn+1));
+      // could look at name?
+      names[iColumn]=CoinStrdup(name);
+    }
+  }
+  // leave in case report needed
+  //glp_free(cbc_glp_prob);
+  //glp_mpl_free_wksp(cbc_glp_tran);
+  //glp_free_env();
+  if ( !numberIntegers ) {
+    free(integerType_);
+    integerType_ = NULL;
+  }
+  if(handler_)
+    handler_->message(COIN_MPS_STATS,messages_)<<problemName_
+					    <<numberRows_
+					    <<numberColumns_
+					    <<numberElements_
+					    <<CoinMessageEol;
+  return 0;
+#else
+  printf("GLPK is not available\n");
+  abort();
+  return 1;
+#endif
+}
+//------------------------------------------------------------------
+// Read gams files
+//------------------------------------------------------------------
+int CoinMpsIO::readGms(const char * filename,  const char * extension,bool convertObjective)
+{
+  convertObjective_=convertObjective;
+  // Deal with filename - +1 if new, 0 if same as before, -1 if error
+  CoinFileInput *input = 0;
+  int returnCode = dealWithFileName(filename,extension,input);
+  if (returnCode<0) {
+    return -1;
+  } else if (returnCode>0) {
+    delete cardReader_;
+    cardReader_ = new CoinMpsCardReader ( input, this);
+  }
+  int numberSets=0;
+  CoinSet ** sets=NULL;
+  returnCode = readGms(numberSets,sets);
+  for (int i=0;i<numberSets;i++)
+    delete sets[i];
+  delete [] sets;
+  return returnCode;
+}
+int CoinMpsIO::readGms(const char * filename,  const char * extension,
+		       int & numberSets,CoinSet ** &sets)
+{
+  // Deal with filename - +1 if new, 0 if same as before, -1 if error
+  CoinFileInput *input = 0;
+  int returnCode = dealWithFileName(filename,extension,input);
+  if (returnCode<0) {
+    return -1;
+  } else if (returnCode>0) {
+    delete cardReader_;
+    cardReader_ = new CoinMpsCardReader ( input, this);
+  }
+  return readGms(numberSets,sets);
+}
+int CoinMpsIO::readGms(int & /*numberSets*/,CoinSet ** &/*sets*/)
+{
+  // First version expects comments giving size
+  numberRows_ = 0;
+  numberColumns_ = 0;
+  numberElements_ = 0;
+  bool gotName=false;
+  bool minimize=false;
+  char objName[COIN_MAX_FIELD_LENGTH];
+  int decodeType=-1;
+  while(!gotName) {
+    if (cardReader_->nextGmsField(0)<0) {
+      handler_->message(COIN_MPS_EOF,messages_)<<fileName_
+                                               <<CoinMessageEol;
+      return -3;
+    } else {
+      char * card = cardReader_->mutableCard();
+      if (card[0]!='*') {
+        // finished preamble without finding name
+        printf("bad gms file\n");
+        return -1;
+      } else {
+        // skip * and find next
+        char * next = nextNonBlank(card+1);
+        if (!next)
+          continue;
+        if (decodeType>=0) {
+          // in middle of getting a total
+          if (!strncmp(next,"Total",5)) {
+            // next line wanted
+            decodeType+=100;
+          } else if (decodeType>=100) {
+            decodeType -= 100;
+            int number = atoi(next);
+            assert (number>0);
+            if (decodeType==0)
+              numberRows_=number;
+            else if (decodeType==1)
+              numberColumns_=number;
+            else
+              numberElements_=number;
+            decodeType=-1;
+          }
+        } else if (!strncmp(next,"Equation",8)) {
+          decodeType=0;
+        } else if (!strncmp(next,"Variable",8)) {
+          decodeType=1;
+        } else if (!strncmp(next,"Nonzero",7)) {
+          decodeType=2;
+        } else if (!strncmp(next,"Solve",5)) {
+          decodeType=-1;
+          gotName=true;
+          assert (numberRows_>0&&numberColumns_>0&&numberElements_>0);
+          next = cardReader_->nextBlankOr(next+5);
+          char name[100];
+          char * put=name;
+          next= nextNonBlank(next);
+          while(*next!=' '&&*next!='\t') {
+            *put = *next;
+            put++;
+            next++;
+          }
+          *put='\0';
+          assert (put-name<100);
+          free(problemName_);
+          problemName_=CoinStrdup(name);
+          next = strchr(next,';');
+          assert (next);
+          // backup
+          while(*next!=' '&&*next!='\t') {
+            next--;
+          }
+          cardReader_->setPosition(next);
+#ifdef NDEBUG
+          cardReader_->nextGmsField(1);
+#else
+          int returnCode = cardReader_->nextGmsField(1);
+          assert (!returnCode);
+#endif
+          next = strchr(next,';');
+          cardReader_->setPosition(next+1);
+          strcpy(objName,cardReader_->columnName());
+          char * semi = strchr(objName,';');
+          if (semi)
+            *semi='\0';
+	  if (strstr(card,"minim")) {
+	    minimize=true;
+	  } else {
+	    assert (strstr(card,"maxim"));
+	    minimize=false;
+	  }
+        } else {
+          decodeType=-1;
+        }
+      }
+    }
+  }
+
+  objectiveOffset_ = 0.0;
+  rowlower_ = reinterpret_cast<double *> (malloc ( numberRows_ * sizeof ( double )));
+  rowupper_ = reinterpret_cast<double *> (malloc ( numberRows_ * sizeof ( double )));
+  collower_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+  colupper_ = reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+  objective_= reinterpret_cast<double *> (malloc ( numberColumns_ * sizeof ( double )));
+  CoinBigIndex *start = reinterpret_cast<CoinBigIndex *> (malloc ((numberRows_ + 1) *
+						   sizeof (CoinBigIndex)));
+  COINColumnIndex * column = reinterpret_cast<COINRowIndex *> (malloc (numberElements_ * sizeof (COINRowIndex)));
+  double *element = reinterpret_cast<double *> (malloc (numberElements_ * sizeof (double)));
+  COINMpsType *rowType =
+    reinterpret_cast<COINMpsType *> (malloc ( numberRows_ * sizeof ( COINMpsType )));
+  char **rowName = reinterpret_cast<char **> (malloc ( numberRows_ * sizeof ( char * )));
+  COINMpsType *columnType = reinterpret_cast<COINMpsType *>
+    (malloc ( numberColumns_ * sizeof ( COINMpsType )));
+  char **columnName = reinterpret_cast<char **> (malloc ( numberColumns_ * sizeof ( char * )));
+
+  start[0] = 0;
+  numberElements_ = 0;
+
+  int numberErrors = 0;
+  int i;
+  COINColumnIndex numberIntegers = 0;
+
+  // expect Variables
+  int returnCode;
+  returnCode = cardReader_->nextGmsField(1);
+  assert (!returnCode&&!strcmp(cardReader_->columnName(),"Variables"));
+  for (i=0;i<numberColumns_;i++) {
+    returnCode = cardReader_->nextGmsField(1);
+    assert (!returnCode);
+    char * next = cardReader_->getPosition();
+    if (*next=='\0') {
+      // eol - expect , at beginning of next line
+      returnCode = cardReader_->nextGmsField(0);
+      assert (!returnCode);
+      next = strchr(cardReader_->mutableCard(),',');
+      assert (next);
+    }
+    assert (*next==','||*next==';');
+    cardReader_->setPosition(next+1);
+    columnName[i]=CoinStrdup(cardReader_->columnName());
+    // Default is free? 
+    collower_[i]=-COIN_DBL_MAX;
+    // Surely not - check
+    collower_[i]=0.0;
+    colupper_[i]=COIN_DBL_MAX;
+    objective_[i]=0.0;
+    columnType[i]=COIN_UNSET_BOUND;
+  }
+  startHash ( columnName, numberColumns_ , 1 );
+  integerType_ = reinterpret_cast<char *> (malloc (numberColumns_*sizeof(char)));
+  memset(integerType_,0,numberColumns_);
+  // Lists come in various flavors - I don't know many now
+  // 0 - Positive
+  // 1 - Binary
+  // -1 end
+  int listType=10;
+  while (listType>=0) {
+    returnCode=cardReader_->nextGmsField(1);
+    assert (!returnCode);
+    listType=-1;
+    if (!strcmp(cardReader_->columnName(),"Positive")) {
+      listType=0;
+    } else if (!strcmp(cardReader_->columnName(),"Binary")) {
+      listType=1;
+    } else if (!strcmp(cardReader_->columnName(),"Integer")) {
+      listType=2;
+    } else {
+      break;
+    }
+    // skip Variables
+    returnCode=cardReader_->nextGmsField(1);
+    assert (!returnCode);
+    assert (!strcmp(cardReader_->columnName(),"Variables"));
+
+    // Go through lists
+    bool inList=true;
+    while (inList) {
+      returnCode=cardReader_->nextGmsField(1);
+      assert (!returnCode);
+      char * next = cardReader_->getPosition();
+      if (*next=='\0') {
+        // eol - expect , at beginning of next line
+        returnCode = cardReader_->nextGmsField(0);
+        assert (!returnCode);
+        next = strchr(cardReader_->mutableCard(),',');
+        assert (next);
+      }
+      assert (*next==','||*next==';');
+      cardReader_->setPosition(next+1);
+      inList=(*next==',');
+      int iColumn = findHash(cardReader_->columnName(),1);
+      assert (iColumn>=0);
+      if (listType==0) {
+        collower_[iColumn]=0.0;
+      } else if (listType==1) {
+        collower_[iColumn]=0.0;
+        colupper_[iColumn]=1.0;
+        columnType[iColumn]=COIN_BV_BOUND;
+	integerType_[iColumn] = 1;
+        numberIntegers++;
+      } else if (listType==2) {
+        collower_[iColumn]=0.0;
+        columnType[iColumn]=COIN_UI_BOUND;
+	integerType_[iColumn] = 1;
+        numberIntegers++;
+      }
+    }
+  }
+  // should be equations
+  assert (!strcmp(cardReader_->columnName(),"Equations"));
+  for (i=0;i<numberRows_;i++) {
+    returnCode = cardReader_->nextGmsField(1);
+    assert (!returnCode);
+    char * next = cardReader_->getPosition();
+    if (*next=='\0') {
+      // eol - expect , at beginning of next line
+      returnCode = cardReader_->nextGmsField(0);
+      assert (!returnCode);
+      next = strchr(cardReader_->mutableCard(),',');
+      assert (next);
+    }
+    assert (*next==','||*next==';');
+    cardReader_->setPosition(next+1);
+    rowName[i]=CoinStrdup(cardReader_->columnName());
+    // Default is free?
+    rowlower_[i]=-COIN_DBL_MAX;
+    rowupper_[i]=COIN_DBL_MAX;
+    rowType[i]=COIN_N_ROW;
+  }
+  startHash ( rowName, numberRows_ , 0 );
+  const double largeElement = 1.0e14;
+  int numberTiny=0;
+  int numberLarge=0;
+  // For now expect just equations so do loop
+  for (i=0;i<numberRows_;i++) {
+    returnCode = cardReader_->nextGmsField(1);
+    assert (!returnCode);
+    char * next = cardReader_->getPosition();
+    assert (*next==' ');
+    char rowName[COIN_MAX_FIELD_LENGTH];
+    strcpy(rowName,cardReader_->columnName());
+    char * dot = strchr(rowName,'.');
+    assert (dot); 
+    *dot='\0';
+    assert (*(dot+1)=='.');
+#ifndef NDEBUG
+    int iRow = findHash(rowName,0);
+    assert (i==iRow);
+#endif
+    returnCode=0;
+    while(!returnCode) {
+      returnCode = cardReader_->nextGmsField(3);
+      assert (returnCode==0||returnCode==2);
+      if (returnCode==2)
+        break;
+      int iColumn = findHash(cardReader_->columnName(),1);
+      if (iColumn>=0) {
+	column[numberElements_]=iColumn;
+	double value = cardReader_->value();
+	if (fabs(value)<smallElement_)
+	  numberTiny++;
+	else if (fabs(value)>largeElement)
+	  numberLarge++;
+	element[numberElements_++]=value;
+      } else {
+	// may be string
+	char temp[100];
+	strcpy(temp,cardReader_->columnName());
+	char * ast = strchr(temp,'*');
+	if (!ast) {
+	  assert (iColumn>=0);
+	} else {
+	  assert (allowStringElements_);
+	  *ast='\0';
+	  if (allowStringElements_==1)
+	    iColumn = findHash(temp,1);
+	  else
+	    iColumn = findHash(ast+1,1);
+	  assert (iColumn>=0);
+	  char temp2[100];
+	  temp2[0]='\0';
+	  double value = cardReader_->value();
+	  if (value&&value!=1.0) 
+	    sprintf(temp2,"%g*",value);
+	  if (allowStringElements_==1)
+	    strcat(temp2,ast+1);
+	  else
+	    strcat(temp2,temp);
+	  addString(i,iColumn,temp2);
+	}
+      }
+    }
+    start[i+1]=numberElements_;
+    next=cardReader_->getPosition();
+    // what about ranges?
+    COINMpsType type=COIN_N_ROW;
+    if (!strncmp(next,"=E=",3))
+      type=COIN_E_ROW;
+    else if (!strncmp(next,"=G=",3))
+      type=COIN_G_ROW;
+    else if (!strncmp(next,"=L=",3))
+      type=COIN_L_ROW;
+    assert (type!=COIN_N_ROW);
+    cardReader_->setPosition(next+3);
+    returnCode = cardReader_->nextGmsField(2);
+    assert (!returnCode);
+    if (type==COIN_E_ROW) {
+      rowlower_[i]=cardReader_->value();
+      rowupper_[i]=cardReader_->value();
+    } else if (type==COIN_G_ROW) {
+      rowlower_[i]=cardReader_->value();
+    } else if (type==COIN_L_ROW) {
+      rowupper_[i]=cardReader_->value();
+    }
+    rowType[i]=type;
+    // and skip ;
+#ifdef NDEBUG
+    cardReader_->nextGmsField(5);
+#else
+    returnCode = cardReader_->nextGmsField(5);
+    assert (!returnCode);
+#endif
+  }
+  // Now non default bounds
+  while (true) {
+    returnCode=cardReader_->nextGmsField(0);
+    if (returnCode<0)
+      break;
+    // if there is a . see if valid name
+    char * card = cardReader_->mutableCard();
+    char * dot = strchr(card,'.');
+    if (dot) {
+      *dot='\0';
+      int iColumn = findHash(card,1);
+      if (iColumn>=0) {
+        // bound
+        char * next = strchr(dot+1,'=');
+        assert (next);
+        double value =atof(next+1);
+        if (!strncmp(dot+1,"fx",2)) {
+          collower_[iColumn]=value;
+          colupper_[iColumn]=value;
+        } else if (!strncmp(dot+1,"up",2)) {
+          colupper_[iColumn]=value;
+        } else if (!strncmp(dot+1,"lo",2)) {
+          collower_[iColumn]=value;
+        }
+      }
+      // may be two per card
+      char * semi = strchr(dot+1,';');
+      dot = NULL;
+      if (semi)
+	dot = strchr(semi+1,'.');
+      if (dot) {
+	char * next= nextNonBlank(semi+1);
+	dot = strchr(next,'.');
+	assert (dot);
+	*dot='\0';
+	assert (iColumn==findHash(next,1));
+        // bound
+        next = strchr(dot+1,'=');
+        assert (next);
+        double value =atof(next+1);
+        if (!strncmp(dot+1,"fx",2)) {
+          collower_[iColumn]=value;
+	  abort();
+          colupper_[iColumn]=value;
+        } else if (!strncmp(dot+1,"up",2)) {
+          colupper_[iColumn]=value;
+        } else if (!strncmp(dot+1,"lo",2)) {
+          collower_[iColumn]=value;
+        }
+	// may be two per card
+	semi = strchr(dot+1,';');
+	assert (semi);
+      }
+    }
+  }
+  // Objective
+  int iObjCol = findHash(objName,1);
+  int iObjRow=-1;
+  assert (iObjCol>=0);
+  if (!convertObjective_) {
+    objective_[iObjCol]=minimize ? 1.0 : -1.0;
+  } else {
+    // move column stuff
+    COINColumnIndex iColumn;
+    free(names_[1][iObjCol]);
+    for ( iColumn = iObjCol+1; iColumn < numberColumns_; iColumn++ ) {
+      integerType_[iColumn-1]=integerType_[iColumn];
+      collower_[iColumn-1]=collower_[iColumn];
+      colupper_[iColumn-1]=colupper_[iColumn];
+      names_[1][iColumn-1]=names_[1][iColumn];
+    }
+    numberHash_[1]--;
+    numberColumns_--;
+    double multiplier = minimize ? 1.0 : -1.0;
+    // but swap
+    multiplier *= -1.0;
+    int iRow;
+    CoinBigIndex nel=0;
+    CoinBigIndex last=0;
+    int kRow=0;
+    for (iRow=0;iRow<numberRows_;iRow++) {
+      CoinBigIndex j;
+      bool found=false;
+      for (j=last;j<start[iRow+1];j++) {
+	int iColumn = column[j];
+	if (iColumn!=iObjCol) {
+	  column[nel]=(iColumn<iObjCol) ? iColumn : iColumn-1;
+	  element[nel++]=element[j];
+	} else {
+	  found=true;
+	  assert (element[j]==1.0);
+	  break;
+	}
+      }
+      if (!found) {
+	last=start[iRow+1];
+	rowlower_[kRow]=rowlower_[iRow];
+	rowupper_[kRow]=rowupper_[iRow];
+	names_[0][kRow]=names_[0][iRow];
+	start[kRow+1]=nel;
+	kRow++;
+      } else {
+	free(names_[0][iRow]);
+	iObjRow = iRow;
+	for (j=last;j<start[iRow+1];j++) {
+	  int iColumn = column[j];
+	  if (iColumn!=iObjCol) {
+	    if (iColumn>iObjCol)
+	      iColumn --;
+	    objective_[iColumn]=multiplier * element[j];
+	  }
+	}
+	nel=start[kRow];
+	last=start[iRow+1];
+      }
+    }
+    numberRows_=kRow;
+    assert (iObjRow>=0);
+    numberHash_[0]--;
+  }
+  stopHash(0);
+  stopHash(1);
+  // clean up integers
+  if ( !numberIntegers ) {
+    free(integerType_);
+    integerType_ = NULL;
+  } else {
+    COINColumnIndex iColumn;
+    for ( iColumn = 0; iColumn < numberColumns_; iColumn++ ) {
+      if ( integerType_[iColumn] ) {
+        //assert ( collower_[iColumn] >= -MAX_INTEGER );
+        if ( collower_[iColumn] < -MAX_INTEGER ) 
+          collower_[iColumn] = -MAX_INTEGER;
+        if ( colupper_[iColumn] > MAX_INTEGER ) 
+          colupper_[iColumn] = MAX_INTEGER;
+      }
+    }
+  }
+  free ( columnType );
+  free ( rowType );
+  if (numberStringElements()&&convertObjective_) {
+    int numberElements = numberStringElements();
+    for (int i=0;i<numberElements;i++) {
+      char * line = stringElements_[i];
+      int iRow;
+      int iColumn;
+      sscanf(line,"%d,%d,",&iRow,&iColumn);
+      bool modify=false;
+      if (iRow>iObjRow) {
+	modify=true;
+	iRow--;
+      }
+      if (iColumn>iObjCol) {
+	modify=true;
+	iColumn--;
+      }
+      if (modify) {
+	char temp[500];
+	const char * pos = strchr(line,',');
+	assert (pos);
+	pos = strchr(pos+1,',');
+	assert (pos);
+	pos++;
+	sprintf(temp,"%d,%d,%s",iRow,iColumn,pos);
+	free(line);
+	stringElements_[i]=CoinStrdup(temp);
+      }
+    }
+  }
+// construct packed matrix and convert to column format
+  CoinPackedMatrix matrixByRow(false,
+                               numberColumns_,numberRows_,numberElements_,
+                               element,column,start,NULL);
+  free ( column );
+  free ( start );
+  free ( element );
+  matrixByColumn_= new CoinPackedMatrix();
+  matrixByColumn_->setExtraGap(0.0);
+  matrixByColumn_->setExtraMajor(0.0);
+  matrixByColumn_->reverseOrderedCopyOf(matrixByRow);
+  if (!convertObjective_)
+    assert (matrixByColumn_->getVectorLengths()[iObjCol]==1);
+  
+  handler_->message(COIN_MPS_STATS,messages_)<<problemName_
+					    <<numberRows_
+					    <<numberColumns_
+					    <<numberElements_
+					    <<CoinMessageEol;
+  if ((numberTiny||numberLarge)&&handler_->logLevel()>3)
+    printf("There were %d coefficients < %g and %d > %g\n",
+           numberTiny,smallElement_,numberLarge,largeElement);
+  return numberErrors;
+}
+/* Read a basis in MPS format from the given filename.
+   If VALUES on NAME card and solution not NULL fills in solution
+   status values as for CoinWarmStartBasis (but one per char)
+   
+   Use "stdin" or "-" to read from stdin.
+*/
+int 
+CoinMpsIO::readBasis(const char *filename, const char *extension ,
+		     double * solution, unsigned char * rowStatus, unsigned char * columnStatus,
+		     const std::vector<std::string> & colnames,int numberColumns,
+		     const std::vector<std::string> & rownames, int numberRows)
+{
+  // Deal with filename - +1 if new, 0 if same as before, -1 if error
+  CoinFileInput *input = 0;
+  int returnCode = dealWithFileName(filename,extension,input);
+  if (returnCode<0) {
+    return -1;
+  } else if (returnCode>0) {
+    delete cardReader_;
+    cardReader_ = new CoinMpsCardReader ( input, this);
+  }
+
+  cardReader_->readToNextSection();
+
+  if ( cardReader_->whichSection (  ) == COIN_NAME_SECTION ) {
+    // Get whether to use values (passed back by freeFormat)
+    if (!cardReader_->freeFormat())
+      solution = NULL;
+    
+  } else if ( cardReader_->whichSection (  ) == COIN_UNKNOWN_SECTION ) {
+    handler_->message(COIN_MPS_BADFILE1,messages_)<<cardReader_->card()
+						  <<1
+						 <<fileName_
+						 <<CoinMessageEol;
+    if (cardReader_->fileInput()->getReadType()!="plain") 
+      handler_->message(COIN_MPS_BADFILE2,messages_)
+        <<cardReader_->fileInput()->getReadType()
+        <<CoinMessageEol;
+
+    return -2;
+  } else if ( cardReader_->whichSection (  ) != COIN_EOF_SECTION ) {
+    return -4;
+  } else {
+    handler_->message(COIN_MPS_EOF,messages_)<<fileName_
+					    <<CoinMessageEol;
+    return -3;
+  }
+  numberRows_=numberRows;
+  numberColumns_=numberColumns;
+  // bas file - always read in free format
+  bool gotNames;
+  if (rownames.size()!=static_cast<unsigned int> (numberRows_)||
+      colnames.size()!=static_cast<unsigned int> (numberColumns_)) {
+    gotNames = false;
+  } else {
+    gotNames=true;
+    numberHash_[0]=numberRows_;
+    numberHash_[1]=numberColumns_;
+    names_[0] = reinterpret_cast<char **> (malloc(numberRows_ * sizeof(char *)));
+    names_[1] = reinterpret_cast<char **> (malloc (numberColumns_ * sizeof(char *)));
+    const char** rowNames = const_cast<const char **>(names_[0]);
+    const char** columnNames = const_cast<const char **>(names_[1]);
+    int i;
+    for (i = 0; i < numberRows_; ++i) {
+      rowNames[i] = rownames[i].c_str();
+    }
+    for (i = 0; i < numberColumns_; ++i) {
+      columnNames[i] = colnames[i].c_str();
+    }
+    startHash ( const_cast<char **>(rowNames), numberRows , 0 );
+    startHash ( const_cast<char **>(columnNames), numberColumns , 1 );
+  }
+  cardReader_->setWhichSection(COIN_BASIS_SECTION);
+  cardReader_->setFreeFormat(true);
+  // below matches CoinWarmStartBasis,
+  const unsigned char basic = 0x01;
+  const unsigned char atLowerBound = 0x03;
+  const unsigned char atUpperBound = 0x02;
+  while ( cardReader_->nextField (  ) == COIN_BASIS_SECTION ) {
+    // Get type and column number
+    int iColumn;
+    if (gotNames) {
+      iColumn = findHash (cardReader_->columnName(),1);
+    } else {
+      // few checks 
+      char check;
+      sscanf(cardReader_->columnName(),"%c%d",&check,&iColumn);
+      assert (check=='C'&&iColumn>=0);
+      if (iColumn>=numberColumns_)
+	iColumn=-1;
+    }
+    if (iColumn>=0) {
+      double value = cardReader_->value (  );
+      if (solution && value>-1.0e50)
+	solution[iColumn]=value;
+      int iRow=-1;
+      switch ( cardReader_->mpsType (  ) ) {
+      case COIN_BS_BASIS:
+	columnStatus[iColumn]=  basic;
+	break;
+      case COIN_XL_BASIS:
+	columnStatus[iColumn]= basic;
+	// get row number
+	if (gotNames) {
+	  iRow = findHash (cardReader_->rowName(),0);
+	} else {
+	  // few checks 
+	  char check;
+	  sscanf(cardReader_->rowName(),"%c%d",&check,&iRow);
+	  assert (check=='R'&&iRow>=0);
+	  if (iRow>=numberRows_)
+	    iRow=-1;
+	}
+	if ( iRow >= 0 ) {
+	  rowStatus[iRow] = atLowerBound;
+	}
+	break;
+      case COIN_XU_BASIS:
+	columnStatus[iColumn]= basic;
+	// get row number
+	if (gotNames) {
+	  iRow = findHash (cardReader_->rowName(),0);
+	} else {
+	  // few checks 
+	  char check;
+	  sscanf(cardReader_->rowName(),"%c%d",&check,&iRow);
+	  assert (check=='R'&&iRow>=0);
+	  if (iRow>=numberRows_)
+	    iRow=-1;
+	}
+	if ( iRow >= 0 ) {
+	  rowStatus[iRow] = atUpperBound;
+	}
+	break;
+      case COIN_LL_BASIS:
+	columnStatus[iColumn]= atLowerBound;
+	break;
+      case COIN_UL_BASIS:
+	columnStatus[iColumn]= atUpperBound;
+	break;
+      default:
+	break;
+      }
+    }
+  }
+  if (gotNames) {
+    stopHash ( 0 );
+    stopHash ( 1 );
+    free(names_[0]);
+    names_[0]=NULL;
+    numberHash_[0]=0;
+    free(names_[1]);
+    names_[1]=NULL;
+    numberHash_[1]=0;
+    delete[] hash_[0];
+    delete[] hash_[1];
+    hash_[0]=0;
+    hash_[1]=0;
+  }
+  if ( cardReader_->whichSection (  ) != COIN_ENDATA_SECTION) {
+    handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						  <<cardReader_->card()
+						  <<CoinMessageEol;
+    handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+    return -1;
+  } else {
+    return solution ? 1 : 0;
+  }
+}
+
+//------------------------------------------------------------------
+
+// Function to create row name field
+static void
+convertRowName(int formatType, const char * name, char outputRow[100])
+{
+  strcpy(outputRow,name);
+  if (!formatType) {
+    int i;
+    // pad out to 8
+    for (i=0;i<8;i++) {
+      if (outputRow[i]=='\0')
+	break;
+    }
+    for (;i<8;i++) 
+      outputRow[i]=' ';
+    outputRow[8]='\0';
+  } else if (formatType>1&&formatType<8) {
+    int i;
+    // pad out to 8
+    for (i=0;i<8;i++) {
+      if (outputRow[i]=='\0')
+	break;
+    }
+    for (;i<8;i++) 
+      outputRow[i]=' ';
+    outputRow[8]='\0';
+  }
+}
+// Function to return number in most efficient way
+// Also creates row name field
+/* formatType is
+   0 - normal and 8 character names
+   1 - extra accuracy
+   2 - IEEE hex - INTEL
+   3 - IEEE hex - not INTEL
+*/
+static void
+convertDouble(int section,int formatType, double value, char outputValue[24],
+	      const char * name, char outputRow[100])
+{
+  convertRowName(formatType,name,outputRow);
+  CoinConvertDouble(section,formatType&3,value,outputValue);
+}
+// Function to return number in most efficient way
+/* formatType is
+   0 - normal and 8 character names
+   1 - extra accuracy
+   2 - IEEE hex - INTEL
+   3 - IEEE hex - not INTEL
+*/
+void
+CoinConvertDouble(int section, int formatType, double value, char outputValue[24])
+{
+  if (formatType==0) {
+    bool stripZeros=true;
+    if (fabs(value)<1.0e40) {
+      int power10, decimal;
+      if (value>=0.0) {
+	power10 =static_cast<int> (log10(value));
+	if (power10<9&&power10>-4) {
+	  decimal = CoinMin(10,10-power10);
+	  char format[8];
+	  sprintf(format,"%%12.%df",decimal);
+	  sprintf(outputValue,format,value);
+	} else {
+	  sprintf(outputValue,"%13.7g",value);
+	  stripZeros=false;
+	}
+      } else {
+	power10 =static_cast<int> (log10(-value))+1;
+	if (power10<8&&power10>-3) {
+	  decimal = CoinMin(9,9-power10);
+	  char format[8];
+	  sprintf(format,"%%12.%df",decimal);
+	  sprintf(outputValue,format,value);
+	} else {
+	  sprintf(outputValue,"%13.6g",value);
+	  stripZeros=false;
+	}
+      }
+      if (stripZeros) {
+	// take off trailing 0
+	int j;
+	for (j=11;j>=0;j--) {
+	  if (outputValue[j]=='0')
+	    outputValue[j]=' ';
+	  else
+	    break;
+	}
+      } else {
+	// still need to make sure fits in 12 characters
+	char * e = strchr(outputValue,'e');
+	if (!e) {
+	  // no e but better make sure fits in 12
+          if (outputValue[12]!=' '&&outputValue[12]!='\0') {
+            assert (outputValue[0]==' ');
+            int j;
+            for (j=0;j<12;j++) 
+              outputValue[j]=outputValue[j+1];
+          }
+	  outputValue[12]='\0';
+	} else {
+	  // e take out 0s
+	  int j = static_cast<int>((e-outputValue))+1;
+	  int put = j+1;
+	  assert(outputValue[j]=='-'||outputValue[j]=='+');
+	  for ( j = put ; j < 14 ; j++) {
+	    if (outputValue[j]!='0')
+	      break;
+	  }
+	  if (j == put) {
+	    // we need to lose something
+	    // try taking out blanks
+	    if (outputValue[0]==' ') {
+	      // skip blank
+	      j=1;
+	      put=0;
+	    } else {
+	      // rounding will be wrong but ....
+	      put -= 3; // points to one before e
+	      j -= 2; // points to e
+	    }
+	  }
+	  // copy rest
+	  for (  ; j < 14 ; j++) {
+	    outputValue[put++] = outputValue[j];
+	  }
+	}
+      }
+      // overwrite if very very small
+      if (fabs(value)<1.0e-20) 
+	strcpy(outputValue,"0.0");
+    } else {
+      if (section==2) {
+        outputValue[0]= '\0'; // needs no value
+      } else {
+        // probably error ... but ....
+        sprintf(outputValue,"%12.6g",value);
+      }
+    }
+    int i;
+    // pad out to 12
+    for (i=0;i<12;i++) {
+      if (outputValue[i]=='\0')
+	break;
+    }
+    for (;i<12;i++) 
+      outputValue[i]=' ';
+    outputValue[12]='\0';
+  } else if (formatType==1) {
+    if (fabs(value)<1.0e40) {
+      memset(outputValue,' ',24);
+      sprintf(outputValue,"%.16g",value);
+      // take out blanks
+      int i=0;
+      int j;
+      for (j=0;j<23;j++) {
+	if (outputValue[j]!=' ')
+	  outputValue[i++]=outputValue[j];
+      }
+      outputValue[i]='\0';
+    } else {
+      if (section==2) {
+        outputValue[0]= '\0'; // needs no value
+      } else {
+        // probably error ... but ....
+        sprintf(outputValue,"%12.6g",value);
+      }
+    }
+  } else {
+    // IEEE
+    // ieee - 3 bytes go to 2
+    assert (sizeof(double)==8*sizeof(char));
+    assert (sizeof(unsigned short) == 2*sizeof(char));
+    unsigned short shortValue[4];
+    memcpy(shortValue,&value,sizeof(double));
+    outputValue[12]='\0';
+    if (formatType==2) {
+      // INTEL
+      char * thisChar = outputValue;
+      for (int i=3;i>=0;i--) {
+	unsigned short thisValue=shortValue[i];
+	// encode 6 bits at a time
+	for (int j=0;j<3;j++) {
+	  unsigned short thisPart = static_cast<unsigned short>(thisValue & 63);
+	  thisValue = static_cast<unsigned short>(thisValue>>6);
+	  if (thisPart < 10) {
+	    *thisChar = static_cast<char>(thisPart+'0');
+	  } else if (thisPart < 36) {
+	    *thisChar = static_cast<char>(thisPart-10+'a');
+	  } else if (thisPart < 62) {
+	    *thisChar = static_cast<char>(thisPart-36+'A');
+	  } else {
+	    *thisChar = static_cast<char>(thisPart-62+'*');
+	  }
+	  thisChar++;
+	}
+      }
+    } else {
+      // not INTEL
+      char * thisChar = outputValue;
+      for (int i=0;i<4;i++) {
+	unsigned short thisValue=shortValue[i];
+	// encode 6 bits at a time
+	for (int j=0;j<3;j++) {
+	  unsigned short thisPart = static_cast<unsigned short>(thisValue & 63);
+	  thisValue = static_cast<unsigned short>(thisValue>>6);
+	  if (thisPart < 10) {
+	    *thisChar = static_cast<char>(thisPart+'0');
+	  } else if (thisPart < 36) {
+	    *thisChar = static_cast<char>(thisPart-10+'a');
+	  } else if (thisPart < 62) {
+	    *thisChar = static_cast<char>(thisPart-36+'A');
+	  } else {
+	    *thisChar = static_cast<char>(thisPart-62+'*');
+	  }
+	  thisChar++;
+	}
+      }
+    }
+  }
+}
+static void
+writeString(CoinFileOutput *output, const char* str)
+{
+   if (output != 0) {
+      output->puts (str);
+   }
+}
+
+// Put out card image
+static void outputCard(int formatType,int numberFields,
+		       CoinFileOutput *output,
+		       std::string head, const char * name,
+		       const char outputValue[2][24],
+		       const char outputRow[2][100])
+{
+   // fprintf(fp,"%s",head.c_str());
+   std::string line = head;
+   int i;
+   if (formatType==0||(formatType>=2&&formatType<8)) {
+      char outputColumn[9];
+      strcpy(outputColumn,name);
+      for (i=0;i<8;i++) {
+	 if (outputColumn[i]=='\0')
+	    break;
+      }
+      for (;i<8;i++) 
+	 outputColumn[i]=' ';
+      outputColumn[8]='\0';
+      // fprintf(fp,"%s  ",outputColumn);
+      line += outputColumn;
+      line += "  ";
+      for (i=0;i<numberFields;i++) {
+	 // fprintf(fp,"%s  %s",outputRow[i],outputValue[i]);
+	 line += outputRow[i];
+	 line += "  ";
+	 line += outputValue[i];
+	 if (i<numberFields-1) {
+	    // fprintf(fp,"   ");
+	    line += "   ";
+	 }
+      }
+   } else {
+      // fprintf(fp,"%s",name);
+      line += name;
+      for (i=0;i<numberFields;i++) {
+	 // fprintf(fp," %s %s",outputRow[i],outputValue[i]);
+	 line += " ";
+	 line += outputRow[i];
+	 line += " ";
+	 line += outputValue[i];
+      }
+   }
+   
+   // fprintf(fp,"\n");
+   line += "\n";
+   writeString(output, line.c_str());
+}
+static int
+makeUniqueNames(char ** names,int number,char first)
+{
+  int largest=-1;
+  int i;
+  for (i=0;i<number;i++) {
+    char * name = names[i];
+    if (name[0]==first&&strlen(name)==8) {
+      // check number
+      int n=0;
+      for (int j=1;j<8;j++) {
+        char num = name[j];
+        if (num>='0'&&num<='9') {
+          n *= 10;
+          n += num-'0';
+        } else {
+          n=-1;
+          break;
+        }
+      }
+      if (n>=0)
+        largest = CoinMax(largest,n);
+    }
+  }
+  largest ++;
+  if (largest>0) {
+    // check
+    char * used = new char[largest];
+    memset(used,0,largest);
+    int nDup=0;
+    for (i=0;i<number;i++) {
+      char * name = names[i];
+      if (name[0]==first&&strlen(name)==8) {
+        // check number
+        int n=0;
+        for (int j=1;j<8;j++) {
+          char num = name[j];
+          if (num>='0'&&num<='9') {
+            n *= 10;
+            n += num-'0';
+          } else {
+            n=-1;
+            break;
+          }
+        }
+        if (n>=0) {
+          if (!used[n]) {
+            used[n]=1;
+          } else {
+            // duplicate
+            nDup++;
+            free(names[i]);
+            char newName[9];
+            sprintf(newName,"%c%7.7d",first,largest);
+            names[i] = CoinStrdup(newName);
+            largest++;
+          }
+        }
+      }
+    }
+    delete []used;
+    return nDup;
+  } else {
+    return 0;
+  }
+}
+static void
+strcpyeq(char * output, const char * input)
+{
+  output[0]='=';
+  strcpy(output+1,input);
+}
+
+int
+CoinMpsIO::writeMps(const char *filename, int compression,
+		   int formatType, int numberAcross,
+		    CoinPackedMatrix * quadratic,
+		    int numberSOS, const CoinSet * setInfo) const
+{
+  // Clean up format and numberacross
+  numberAcross=CoinMax(1,numberAcross);
+  numberAcross=CoinMin(2,numberAcross);
+  formatType=CoinMax(0,formatType);
+  formatType=CoinMin(2,formatType);
+  int possibleCompression=0;
+#ifdef COIN_HAS_ZLIB
+  possibleCompression =1;
+#endif
+#ifdef COIN_HAS_BZLIB
+  possibleCompression += 2;
+#endif
+  if ((compression&possibleCompression)==0) {
+    // switch to other if possible
+    if (compression&&possibleCompression)
+      compression = 3-compression;
+    else
+      compression=0;
+  }
+  std::string line = filename;
+   CoinFileOutput *output = 0;
+   switch (compression) {
+   case 1:
+     if (strcmp(line.c_str() +(line.size()-3), ".gz") != 0) {
+       line += ".gz";
+     }
+     output = CoinFileOutput::create (line, CoinFileOutput::COMPRESS_GZIP);
+     break;
+
+   case 2:
+     if (strcmp(line.c_str() +(line.size()-4), ".bz2") != 0) {
+       line += ".bz2";
+     }
+     output = CoinFileOutput::create (line, CoinFileOutput::COMPRESS_BZIP2);
+     break;
+
+   case 0:
+   default:
+     output = CoinFileOutput::create (line, CoinFileOutput::COMPRESS_NONE);
+     break;
+   }
+
+   const char * const * const rowNames = names_[0];
+   const char * const * const columnNames = names_[1];
+   int i;
+   unsigned int length = 8;
+   bool freeFormat = (formatType==1);
+   // Check names for uniqueness if default
+   int nChanged;
+   nChanged=makeUniqueNames(names_[0],numberRows_,'R');
+   if (nChanged)
+     handler_->message(COIN_MPS_CHANGED,messages_)<<"row"<<nChanged
+                                                  <<CoinMessageEol;
+   nChanged=makeUniqueNames(names_[1],numberColumns_,'C');
+   if (nChanged)
+     handler_->message(COIN_MPS_CHANGED,messages_)<<"column"<<nChanged
+                                                  <<CoinMessageEol;
+   for (i = 0 ; i < numberRows_; ++i) {
+      if (strlen(rowNames[i]) > length) {
+	 length = static_cast<int>(strlen(rowNames[i]));
+	 break;
+      }
+   }
+   if (length <= 8) {
+      for (i = 0 ; i < numberColumns_; ++i) {
+	 if (strlen(columnNames[i]) > length) {
+	    length = static_cast<int>(strlen(columnNames[i]));
+	    break;
+	 }
+      }
+   }
+   if (length > 8 && freeFormat!=1) {
+      freeFormat = true;
+      formatType += 8;
+   }
+   if (numberStringElements_) {
+     freeFormat=true;
+     numberAcross=1;
+   }
+   
+   // NAME card
+
+   line = "NAME          ";
+   if (strcmp(problemName_,"")==0) {
+      line.append("BLANK   ");
+   } else {
+      if (strlen(problemName_) >= 8) {
+	 line.append(problemName_, 8);
+      } else {
+	 line.append(problemName_);
+	 line.append(8-strlen(problemName_), ' ');
+      }
+   }
+   if (freeFormat&&(formatType&7)!=2)
+     line.append("  FREE");
+   else if (freeFormat)
+     line.append("  FREEIEEE");
+   else if ((formatType&7)==2)
+     line.append("  IEEE");
+   // See if INTEL if IEEE
+   if ((formatType&7)==2) {
+     // test intel here and add 1 if not intel
+     double value=1.0;
+     char x[8];
+     memcpy(x,&value,8);
+     if (x[0]==63) {
+       formatType ++; // not intel
+     } else {
+       assert (x[0]==0);
+     }
+   }
+   // finish off name and do ROWS card and objective
+   char* objrow =
+     CoinStrdup(strcmp(objectiveName_,"")==0 ? "OBJROW" : objectiveName_);
+   line.append("\nROWS\n N  ");
+   line.append(objrow);
+   line.append("\n");
+   writeString(output, line.c_str());
+
+   // Rows section
+   // Sense array
+   // But massage if looks odd
+   char * sense = new char [numberRows_];
+   memcpy( sense , getRowSense(), numberRows_);
+   const double * rowLower = getRowLower();
+   const double * rowUpper = getRowUpper();
+  
+   for (i=0;i<numberRows_;i++) {
+      line = " ";
+      if (sense[i]!='R') {
+	 line.append(1,sense[i]);
+      } else {
+	if (rowLower[i]>-1.0e30) {
+	  if(rowUpper[i]<1.0e30) {
+	 line.append("L");
+	  } else {
+	    sense[i]='G';
+	    line.append(1,sense[i]);
+      }
+	} else {
+	  sense[i]='L';
+	  line.append(1,sense[i]);
+	}
+      }
+      line.append("  ");
+      line.append(rowNames[i]);
+      line.append("\n");
+      writeString(output, line.c_str());
+   }
+
+   // COLUMNS card
+   writeString(output, "COLUMNS\n");
+
+   bool ifBounds=false;
+   double largeValue = infinity_;
+   largeValue = 1.0e30; // safer
+
+   const double * columnLower = getColLower();
+   const double * columnUpper = getColUpper();
+   const double * objective = getObjCoefficients();
+   const CoinPackedMatrix * matrix = getMatrixByCol();
+   const double * elements = matrix->getElements();
+   const int * rows = matrix->getIndices();
+   const CoinBigIndex * starts = matrix->getVectorStarts();
+   const int * lengths = matrix->getVectorLengths();
+
+   char outputValue[2][24];
+   char outputRow[2][100];
+   // strings
+   int nextRowString=numberRows_+10;
+   int nextColumnString=numberColumns_+10;
+   int whichString=0;
+   const char * nextString=NULL;
+   // mark string rows
+   char * stringRow = new char[numberRows_+1];
+   memset(stringRow,0,numberRows_+1);
+   if (numberStringElements_) {
+     decodeString(whichString,nextRowString,nextColumnString,nextString);
+   }
+   // Arrays so we can put out rows in order
+   int * tempRow = new int [numberRows_];
+   double * tempValue = new double [numberRows_];
+
+   // Through columns (only put out if elements or objective value)
+   for (i=0;i<numberColumns_;i++) {
+     if (i==nextColumnString) {
+       // set up
+       int k=whichString;
+       int iColumn=nextColumnString;
+       int iRow=nextRowString;
+       const char * dummy;
+       while (iColumn==nextColumnString) {
+	 stringRow[iRow]=1;
+	 k++;
+	 decodeString(k,iRow,iColumn,dummy);
+       }
+     }
+     if (objective[i]||lengths[i]||i==nextColumnString) {
+       // see if bound will be needed
+       if (columnLower[i]||columnUpper[i]<largeValue||isInteger(i))
+	 ifBounds=true;
+       int numberFields=0;
+       if (objective[i]) {
+	 convertDouble(0,formatType,objective[i],outputValue[0],
+		       objrow,outputRow[0]);
+	 numberFields=1;
+	 if (stringRow[numberRows_]) {
+	   assert (objective[i]==STRING_VALUE);
+	   assert (nextColumnString==i&&nextRowString==numberRows_);
+	   strcpyeq(outputValue[0],nextString);
+	   stringRow[numberRows_]=0;
+	   decodeString(++whichString,nextRowString,nextColumnString,nextString);
+	 }
+       }
+       if (numberFields==numberAcross) {
+	 // put out card
+	 outputCard(formatType, numberFields,
+		    output, "    ",
+		    columnNames[i],
+		    outputValue,
+		    outputRow);
+	 numberFields=0;
+       }
+       int j;
+       int numberEntries = lengths[i];
+       int start = starts[i];
+       for (j=0;j<numberEntries;j++) {
+	 tempRow[j] = rows[start+j];
+	 tempValue[j] = elements[start+j];
+       }
+       CoinSort_2(tempRow,tempRow+numberEntries,tempValue);
+       for (j=0;j<numberEntries;j++) {
+	 int jRow = tempRow[j];
+	 double value = tempValue[j];
+	 if (value&&!stringRow[jRow]) {
+	   convertDouble(0,formatType,value,
+			 outputValue[numberFields],
+			 rowNames[jRow],
+			 outputRow[numberFields]);
+	   numberFields++;
+	   if (numberFields==numberAcross) {
+	     // put out card
+	     outputCard(formatType, numberFields,
+			output, "    ",
+			columnNames[i],
+			outputValue,
+			outputRow);
+	     numberFields=0;
+	   }
+	 }
+       }
+       if (numberFields) {
+	 // put out card
+	 outputCard(formatType, numberFields,
+		    output, "    ",
+		    columnNames[i],
+		    outputValue,
+		    outputRow);
+       }
+     }
+     // end see if any strings
+     if (i==nextColumnString) {
+       int iColumn=nextColumnString;
+       int iRow=nextRowString;
+       while (iColumn==nextColumnString) {
+	 double value = 1.0;
+	 convertDouble(0,formatType,value,
+		       outputValue[0],
+		       rowNames[nextRowString],
+		       outputRow[0]);
+	 strcpyeq(outputValue[0],nextString);
+	 // put out card
+	 outputCard(formatType, 1,
+		    output, "    ",
+		    columnNames[i],
+		    outputValue,
+		    outputRow);
+	 stringRow[iRow]=0;
+	 decodeString(++whichString,nextRowString,nextColumnString,nextString);
+       }
+     }
+   }
+   delete [] tempRow;
+   delete [] tempValue;
+   delete [] stringRow;
+
+   bool ifRange=false;
+   // RHS
+   writeString(output, "RHS\n");
+
+   int numberFields = 0;
+   // If there is any offset - then do that
+   if (objectiveOffset_ ) {
+     convertDouble(1,formatType,objectiveOffset_,
+		   outputValue[0],
+		   objrow,
+		   outputRow[0]);
+     numberFields++;
+     if (numberFields==numberAcross) {
+       // put out card
+       outputCard(formatType, numberFields,
+		  output, "    ",
+		  "RHS",
+		  outputValue,
+		  outputRow);
+       numberFields=0;
+     }
+   }
+   for (i=0;i<numberRows_;i++) {
+      double value;
+      switch (sense[i]) {
+      case 'E':
+	 value=rowLower[i];
+	 break;
+      case 'R':
+	 value=rowUpper[i];
+	   ifRange=true;
+	 break;
+      case 'L':
+	 value=rowUpper[i];
+	 break;
+      case 'G':
+	 value=rowLower[i];
+	 break;
+      default:
+	 value=0.0;
+	 break;
+      }
+      if (value != 0.0) {
+	 convertDouble(1,formatType,value,
+		       outputValue[numberFields],
+		       rowNames[i],
+		       outputRow[numberFields]);
+	 if (i==nextRowString&&nextColumnString>=numberColumns_) {
+	   strcpyeq(outputValue[0],nextString);
+	   decodeString(++whichString,nextRowString,nextColumnString,nextString);
+	 }
+	 numberFields++;
+	 if (numberFields==numberAcross) {
+	    // put out card
+	    outputCard(formatType, numberFields,
+		       output, "    ",
+		       "RHS",
+		       outputValue,
+		       outputRow);
+	    numberFields=0;
+	 }
+      }
+   }
+   if (numberFields) {
+      // put out card
+      outputCard(formatType, numberFields,
+		 output, "    ",
+		 "RHS",
+		 outputValue,
+		 outputRow);
+   }
+
+   if (ifRange) {
+      // RANGES
+      writeString(output, "RANGES\n");
+
+      numberFields = 0;
+      for (i=0;i<numberRows_;i++) {
+	 if (sense[i]=='R') {
+	    double value =rowUpper[i]-rowLower[i];
+	    if (value<1.0e30) {
+	      convertDouble(1,formatType,value,
+			    outputValue[numberFields],
+			    rowNames[i],
+			    outputRow[numberFields]);
+	      numberFields++;
+	      if (numberFields==numberAcross) {
+		// put out card
+		outputCard(formatType, numberFields,
+			   output, "    ",
+			   "RANGE",
+			   outputValue,
+			   outputRow);
+		numberFields=0;
+	      }
+	    }
+	 }
+      }
+      if (numberFields) {
+	 // put out card
+	 outputCard(formatType, numberFields,
+		    output, "    ",
+		    "RANGE",
+		    outputValue,
+		    outputRow);
+      }
+   }
+   delete [] sense;
+   if (ifBounds) {
+      // BOUNDS
+      writeString(output, "BOUNDS\n");
+
+      for (i=0;i<numberColumns_;i++) {
+	if (i==nextColumnString) {
+	  // just lo and up
+	  if (columnLower[i]==STRING_VALUE) {
+	    assert (nextRowString==numberRows_+1);
+	    convertDouble(2,formatType,1.0,
+			  outputValue[0],
+			  columnNames[i],
+			  outputRow[0]);
+	    strcpyeq(outputValue[0],nextString);
+	    decodeString(++whichString,nextRowString,nextColumnString,nextString);
+	    if (i==nextColumnString) {
+	      assert (columnUpper[i]==STRING_VALUE);
+	      assert (nextRowString==numberRows_+2);
+	      if (!strcmp(nextString,outputValue[0])) {
+		// put out card FX
+		outputCard(formatType, 1,
+			   output, " FX ",
+			   "BOUND",
+			   outputValue,
+			   outputRow);
+	      } else {
+		// put out card LO
+		outputCard(formatType, 1,
+			   output, " LO ",
+			   "BOUND",
+			   outputValue,
+			   outputRow);
+		// put out card UP
+		strcpyeq(outputValue[0],nextString);
+		outputCard(formatType, 1,
+			   output, " UP ",
+			   "BOUND",
+			   outputValue,
+			   outputRow);
+	      }
+	      decodeString(++whichString,nextRowString,nextColumnString,nextString);
+	    } else {
+	      // just LO
+	      // put out card LO
+	      outputCard(formatType, 1,
+			 output, " LO ",
+			 "BOUND",
+			 outputValue,
+			 outputRow);
+	    }
+	  } else if (columnUpper[i]==STRING_VALUE) {
+	    assert (nextRowString==numberRows_+2);
+	    convertDouble(2,formatType,1.0,
+			  outputValue[0],
+			  columnNames[i],
+			  outputRow[0]);
+	    strcpyeq(outputValue[0],nextString);
+	    outputCard(formatType, 1,
+		       output, " UP ",
+		       "BOUND",
+		       outputValue,
+		       outputRow);
+	    decodeString(++whichString,nextRowString,nextColumnString,nextString);
+	  }
+	  continue;
+	}
+	 if (objective[i]||lengths[i]) {
+	    // see if bound will be needed
+	    if (columnLower[i]||columnUpper[i]<largeValue||isInteger(i)) {
+	      double lowerValue = columnLower[i];
+	      double upperValue = columnUpper[i];
+	      if (isInteger(i)) {
+		// Old argument - what are correct ranges for integer variables
+		lowerValue = CoinMax(lowerValue, -MAX_INTEGER);
+		upperValue = CoinMin(upperValue, MAX_INTEGER);
+	      }
+	       int numberFields=1;
+	       std::string header[2];
+	       double value[2];
+	       if (lowerValue<=-largeValue) {
+		  // FR or MI
+		  if (upperValue>=largeValue&&!isInteger(i)) {
+		     header[0]=" FR ";
+		     value[0] = largeValue;
+		  } else {
+		     header[0]=" MI ";
+		     value[0] = -largeValue;
+                     if (!isInteger(i))
+                       header[1]=" UP ";
+                     else
+                       header[1]=" UI ";
+                     if (upperValue<largeValue) 
+                       value[1] = upperValue;
+                     else
+                       value[1] = largeValue;
+		     numberFields=2;
+		  }
+	       } else if (fabs(upperValue-lowerValue)<1.0e-8) {
+		  header[0]=" FX ";
+		  value[0] = lowerValue;
+	       } else {
+		  // do LO if needed
+		  if (lowerValue) {
+		     // LO
+		     header[0]=" LO ";
+		     value[0] = lowerValue;
+		     if (isInteger(i)) {
+			// Integer variable so UI
+			header[1]=" UI ";
+                        if (upperValue<largeValue) 
+                          value[1] = upperValue;
+                        else
+                          value[1] = largeValue;
+			numberFields=2;
+		     } else if (upperValue<largeValue) {
+			// UP
+			header[1]=" UP ";
+			value[1] = upperValue;
+			numberFields=2;
+		     }
+		  } else {
+		     if (isInteger(i)) {
+			// Integer variable so BV or UI
+			if (fabs(upperValue-1.0)<1.0e-8) {
+			   // BV
+			   header[0]=" BV ";
+			   value[0] = 1.0;
+			} else {
+			   // UI
+			   header[0]=" UI ";
+                           if (upperValue<largeValue) 
+                             value[0] = upperValue;
+                           else
+                             value[0] = largeValue;
+			}
+		     } else {
+			// UP
+			header[0]=" UP ";
+			value[0] = upperValue;
+		     }
+		  }
+	       }
+	       // put out fields
+	       int j;
+	       for (j=0;j<numberFields;j++) {
+		  convertDouble(2,formatType,value[j],
+				outputValue[0],
+				columnNames[i],
+				outputRow[0]);
+		  // put out card
+		  outputCard(formatType, 1,
+			     output, header[j],
+			     "BOUND",
+			     outputValue,
+			     outputRow);
+	       }
+	    }
+	 }
+      }
+   }
+   
+   // do any quadratic part
+   if (quadratic) {
+
+     writeString(output, "QUADOBJ\n");
+
+     const int * columnQuadratic = quadratic->getIndices();
+     const CoinBigIndex * columnQuadraticStart = quadratic->getVectorStarts();
+     const int * columnQuadraticLength = quadratic->getVectorLengths();
+     const double * quadraticElement = quadratic->getElements();
+     for (int iColumn=0;iColumn<numberColumns_;iColumn++) {
+       int numberFields=0;
+       for (int j=columnQuadraticStart[iColumn];
+	    j<columnQuadraticStart[iColumn]+columnQuadraticLength[iColumn];j++) {
+	 int jColumn = columnQuadratic[j];
+	 double elementValue = quadraticElement[j];
+	 convertDouble(0,formatType,elementValue,
+		       outputValue[numberFields],
+		       columnNames[jColumn],
+		       outputRow[numberFields]);
+	 numberFields++;
+	 if (numberFields==numberAcross) {
+	   // put out card
+	   outputCard(formatType, numberFields,
+		      output, "    ",
+		      columnNames[iColumn],
+		      outputValue,
+		      outputRow);
+	   numberFields=0;
+	 }
+       }
+       if (numberFields) {
+	 // put out card
+	 outputCard(formatType, numberFields,
+		    output, "    ",
+		    columnNames[iColumn],
+		    outputValue,
+		    outputRow);
+       }
+     }
+   }
+   // SOS
+   if (numberSOS) {
+     writeString(output, "SOS\n");
+     for (int i=0;i<numberSOS;i++) {
+       int type = setInfo[i].setType();
+       writeString(output, (type==1) ? " S1\n" : " S2\n");
+       int n=setInfo[i].numberEntries();
+       const int * which = setInfo[i].which();
+       const double * weights = setInfo[i].weights();
+       
+       for (int j=0;j<n;j++) {
+	 int k=which[j];
+	 convertDouble(2,formatType,
+		       weights ? weights[j] : COIN_DBL_MAX,outputValue[0],
+		       "",outputRow[0]);
+	 // put out card
+	 outputCard(formatType, 1,
+		    output, "   ",
+		    columnNames[k],
+		    outputValue,outputRow);
+       }
+     }
+   }
+
+   // and finish
+
+   writeString(output, "ENDATA\n");
+
+   free(objrow);
+
+   delete output;
+   return 0;
+}
+   
+//------------------------------------------------------------------
+// Problem name
+const char * CoinMpsIO::getProblemName() const
+{
+  return problemName_;
+}
+// Objective name
+const char * CoinMpsIO::getObjectiveName() const
+{
+  return objectiveName_;
+}
+// Rhs name
+const char * CoinMpsIO::getRhsName() const
+{
+  return rhsName_;
+}
+// Range name
+const char * CoinMpsIO::getRangeName() const
+{
+  return rangeName_;
+}
+// Bound name
+const char * CoinMpsIO::getBoundName() const
+{
+  return boundName_;
+}
+
+//------------------------------------------------------------------
+// Get number of rows, columns and elements
+//------------------------------------------------------------------
+int CoinMpsIO::getNumCols() const
+{
+  return numberColumns_;
+}
+int CoinMpsIO::getNumRows() const
+{
+  return numberRows_;
+}
+int CoinMpsIO::getNumElements() const
+{
+  return numberElements_;
+}
+
+//------------------------------------------------------------------
+// Get pointer to column lower and upper bounds.
+//------------------------------------------------------------------  
+const double * CoinMpsIO::getColLower() const
+{
+  return collower_;
+}
+const double * CoinMpsIO::getColUpper() const
+{
+  return colupper_;
+}
+
+//------------------------------------------------------------------
+// Get pointer to row lower and upper bounds.
+//------------------------------------------------------------------  
+const double * CoinMpsIO::getRowLower() const
+{
+  return rowlower_;
+}
+const double * CoinMpsIO::getRowUpper() const
+{
+  return rowupper_;
+}
+ 
+/** A quick inlined function to convert from lb/ub style constraint
+    definition to sense/rhs/range style */
+inline void
+CoinMpsIO::convertBoundToSense(const double lower, const double upper,
+					char& sense, double& right,
+					double& range) const
+{
+  range = 0.0;
+  if (lower > -infinity_) {
+    if (upper < infinity_) {
+      right = upper;
+      if (upper==lower) {
+        sense = 'E';
+      } else {
+        sense = 'R';
+        range = upper - lower;
+      }
+    } else {
+      sense = 'G';
+      right = lower;
+    }
+  } else {
+    if (upper < infinity_) {
+      sense = 'L';
+      right = upper;
+    } else {
+      sense = 'N';
+      right = 0.0;
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+/** A quick inlined function to convert from sense/rhs/range stryle constraint
+    definition to lb/ub style */
+inline void
+CoinMpsIO::convertSenseToBound(const char sense, const double right,
+					const double range,
+					double& lower, double& upper) const
+{
+  switch (sense) {
+  case 'E':
+    lower = upper = right;
+    break;
+  case 'L':
+    lower = -infinity_;
+    upper = right;
+    break;
+  case 'G':
+    lower = right;
+    upper = infinity_;
+    break;
+  case 'R':
+    lower = right - range;
+    upper = right;
+    break;
+  case 'N':
+    lower = -infinity_;
+    upper = infinity_;
+    break;
+  }
+}
+//------------------------------------------------------------------
+// Get sense of row constraints.
+//------------------------------------------------------------------ 
+const char * CoinMpsIO::getRowSense() const
+{
+  if ( rowsense_==NULL ) {
+
+    int nr=numberRows_;
+    rowsense_ = reinterpret_cast<char *> (malloc(nr*sizeof(char)));
+
+
+    double dum1,dum2;
+    int i;
+    for ( i=0; i<nr; i++ ) {
+      convertBoundToSense(rowlower_[i],rowupper_[i],rowsense_[i],dum1,dum2);
+    }
+  }
+  return rowsense_;
+}
+
+//------------------------------------------------------------------
+// Get the rhs of rows.
+//------------------------------------------------------------------ 
+const double * CoinMpsIO::getRightHandSide() const
+{
+  if ( rhs_==NULL ) {
+
+    int nr=numberRows_;
+    rhs_ = reinterpret_cast<double *> (malloc(nr*sizeof(double)));
+
+
+    char dum1;
+    double dum2;
+    int i;
+    for ( i=0; i<nr; i++ ) {
+      convertBoundToSense(rowlower_[i],rowupper_[i],dum1,rhs_[i],dum2);
+    }
+  }
+  return rhs_;
+}
+
+//------------------------------------------------------------------
+// Get the range of rows.
+// Length of returned vector is getNumRows();
+//------------------------------------------------------------------ 
+const double * CoinMpsIO::getRowRange() const
+{
+  if ( rowrange_==NULL ) {
+
+    int nr=numberRows_;
+    rowrange_ = reinterpret_cast<double *> (malloc(nr*sizeof(double)));
+    std::fill(rowrange_,rowrange_+nr,0.0);
+
+    char dum1;
+    double dum2;
+    int i;
+    for ( i=0; i<nr; i++ ) {
+      convertBoundToSense(rowlower_[i],rowupper_[i],dum1,dum2,rowrange_[i]);
+    }
+  }
+  return rowrange_;
+}
+
+const double * CoinMpsIO::getObjCoefficients() const
+{
+  return objective_;
+}
+ 
+//------------------------------------------------------------------
+// Create a row copy of the matrix ...
+//------------------------------------------------------------------
+const CoinPackedMatrix * CoinMpsIO::getMatrixByRow() const
+{
+  if ( matrixByRow_ == NULL && matrixByColumn_) {
+    matrixByRow_ = new CoinPackedMatrix(*matrixByColumn_);
+    matrixByRow_->reverseOrdering();
+  }
+  return matrixByRow_;
+}
+
+//------------------------------------------------------------------
+// Create a column copy of the matrix ...
+//------------------------------------------------------------------
+const CoinPackedMatrix * CoinMpsIO::getMatrixByCol() const
+{
+  return matrixByColumn_;
+}
+
+//------------------------------------------------------------------
+// Save the data ...
+//------------------------------------------------------------------
+void
+CoinMpsIO::setMpsDataWithoutRowAndColNames(
+                                  const CoinPackedMatrix& m, const double infinity,
+                                  const double* collb, const double* colub,
+                                  const double* obj, const char* integrality,
+                                  const double* rowlb, const double* rowub)
+{
+  freeAll();
+  if (m.isColOrdered()) {
+    matrixByColumn_ = new CoinPackedMatrix(m);
+  } else {
+    matrixByColumn_ = new CoinPackedMatrix;
+    matrixByColumn_->reverseOrderedCopyOf(m);
+  }
+  numberColumns_ = matrixByColumn_->getNumCols();
+  numberRows_ = matrixByColumn_->getNumRows();
+  numberElements_ = matrixByColumn_->getNumElements();
+  defaultBound_ = 1;
+  infinity_ = infinity;
+  objectiveOffset_ = 0;
+  
+  rowlower_ = reinterpret_cast<double *> (malloc (numberRows_ * sizeof(double)));
+  rowupper_ = reinterpret_cast<double *> (malloc (numberRows_ * sizeof(double)));
+  collower_ = reinterpret_cast<double *> (malloc (numberColumns_ * sizeof(double)));
+  colupper_ = reinterpret_cast<double *> (malloc (numberColumns_ * sizeof(double)));
+  objective_ = reinterpret_cast<double *> (malloc (numberColumns_ * sizeof(double)));
+  std::copy(rowlb, rowlb + numberRows_, rowlower_);
+  std::copy(rowub, rowub + numberRows_, rowupper_);
+  std::copy(collb, collb + numberColumns_, collower_);
+  std::copy(colub, colub + numberColumns_, colupper_);
+  std::copy(obj, obj + numberColumns_, objective_);
+  if (integrality) {
+    integerType_ = reinterpret_cast<char *> (malloc (numberColumns_ * sizeof(char)));
+    std::copy(integrality, integrality + numberColumns_, integerType_);
+  } else {
+    integerType_ = NULL;
+  }
+    
+  problemName_ = CoinStrdup("");
+  objectiveName_ = CoinStrdup("");
+  rhsName_ = CoinStrdup("");
+  rangeName_ = CoinStrdup("");
+  boundName_ = CoinStrdup("");
+}
+
+
+void
+CoinMpsIO::setMpsDataColAndRowNames(
+		      char const * const * const colnames,
+		      char const * const * const rownames)
+{
+  releaseRowNames();
+  releaseColumnNames();
+   // If long names free format
+  names_[0] = reinterpret_cast<char **> (malloc(numberRows_ * sizeof(char *)));
+  names_[1] = reinterpret_cast<char **> (malloc (numberColumns_ * sizeof(char *)));
+   numberHash_[0]=numberRows_;
+   numberHash_[1]=numberColumns_;
+   char** rowNames = names_[0];
+   char** columnNames = names_[1];
+   int i;
+   if (rownames) {
+     for (i = 0 ; i < numberRows_; ++i) {
+       if (rownames[i]) {
+         rowNames[i] = CoinStrdup(rownames[i]);
+       } else {
+         rowNames[i] = reinterpret_cast<char *> (malloc (9 * sizeof(char)));
+         sprintf(rowNames[i],"R%7.7d",i);
+       }
+     }
+   } else {
+     for (i = 0; i < numberRows_; ++i) {
+       rowNames[i] = reinterpret_cast<char *> (malloc (9 * sizeof(char)));
+       sprintf(rowNames[i],"R%7.7d",i);
+     }
+   }
+#ifndef NONAMES
+   if (colnames) {
+     for (i = 0 ; i < numberColumns_; ++i) {
+       if (colnames[i]) {
+         columnNames[i] = CoinStrdup(colnames[i]);
+       } else {
+         columnNames[i] = reinterpret_cast<char *> (malloc (9 * sizeof(char)));
+         sprintf(columnNames[i],"C%7.7d",i);
+       }
+     }
+   } else {
+     for (i = 0; i < numberColumns_; ++i) {
+       columnNames[i] = reinterpret_cast<char *> (malloc (9 * sizeof(char)));
+       sprintf(columnNames[i],"C%7.7d",i);
+     }
+   }
+#else
+   const double * objective = getObjCoefficients();
+   const CoinPackedMatrix * matrix = getMatrixByCol();
+   const int * lengths = matrix->getVectorLengths();
+   int k=0;
+   for (i = 0 ; i < numberColumns_; ++i) {
+     columnNames[i] = reinterpret_cast<char *> (malloc (9 * sizeof(char)));
+     sprintf(columnNames[i],"C%7.7d",k);
+     if (objective[i]||lengths[i])
+       k++;
+     }
+#endif
+}
+
+void
+CoinMpsIO::setMpsDataColAndRowNames(
+		      const std::vector<std::string> & colnames,
+		      const std::vector<std::string> & rownames)
+{  
+   // If long names free format
+  names_[0] = reinterpret_cast<char **> (malloc(numberRows_ * sizeof(char *)));
+  names_[1] = reinterpret_cast<char **> (malloc (numberColumns_ * sizeof(char *)));
+   char** rowNames = names_[0];
+   char** columnNames = names_[1];
+   int i;
+   if (rownames.size()!=0) {
+     for (i = 0 ; i < numberRows_; ++i) {
+       rowNames[i] = CoinStrdup(rownames[i].c_str());
+     }
+   } else {
+     for (i = 0; i < numberRows_; ++i) {
+       rowNames[i] = reinterpret_cast<char *> (malloc (9 * sizeof(char)));
+       sprintf(rowNames[i],"R%7.7d",i);
+     }
+   }
+   if (colnames.size()!=0) {
+     for (i = 0 ; i < numberColumns_; ++i) {
+       columnNames[i] = CoinStrdup(colnames[i].c_str());
+     }
+   } else {
+     for (i = 0; i < numberColumns_; ++i) {
+       columnNames[i] = reinterpret_cast<char *> (malloc (9 * sizeof(char)));
+       sprintf(columnNames[i],"C%7.7d",i);
+     }
+   }
+}
+
+void
+CoinMpsIO::setMpsData(const CoinPackedMatrix& m, const double infinity,
+                      const double* collb, const double* colub,
+                      const double* obj, const char* integrality,
+                      const double* rowlb, const double* rowub,
+                      char const * const * const colnames,
+                      char const * const * const rownames)
+{
+  setMpsDataWithoutRowAndColNames(m,infinity,collb,colub,obj,integrality,rowlb,rowub);
+  setMpsDataColAndRowNames(colnames,rownames);
+}
+
+void
+CoinMpsIO::setMpsData(const CoinPackedMatrix& m, const double infinity,
+                      const double* collb, const double* colub,
+                      const double* obj, const char* integrality,
+                      const double* rowlb, const double* rowub,
+                      const std::vector<std::string> & colnames,
+                      const std::vector<std::string> & rownames)
+{
+  setMpsDataWithoutRowAndColNames(m,infinity,collb,colub,obj,integrality,rowlb,rowub);
+  setMpsDataColAndRowNames(colnames,rownames);
+}
+
+void
+CoinMpsIO::setMpsData(const CoinPackedMatrix& m, const double infinity,
+		      const double* collb, const double* colub,
+		      const double* obj, const char* integrality,
+		      const char* rowsen, const double* rowrhs,
+		      const double* rowrng,
+		      char const * const * const colnames,
+		      char const * const * const rownames)
+{
+   const int numrows = m.getNumRows();
+
+   double * rlb = numrows ? new double[numrows] : 0;
+   double * rub = numrows ? new double[numrows] : 0;
+
+   for (int i = 0; i < numrows; ++i) {
+      convertSenseToBound(rowsen[i], rowrhs[i], rowrng[i], rlb[i], rub[i]);
+   }
+   setMpsData(m, infinity, collb, colub, obj, integrality, rlb, rub,
+	      colnames, rownames);
+   delete [] rlb;
+   delete [] rub;
+}
+
+void
+CoinMpsIO::setMpsData(const CoinPackedMatrix& m, const double infinity,
+		      const double* collb, const double* colub,
+		      const double* obj, const char* integrality,
+		      const char* rowsen, const double* rowrhs,
+		      const double* rowrng,
+		      const std::vector<std::string> & colnames,
+		      const std::vector<std::string> & rownames)
+{
+   const int numrows = m.getNumRows();
+
+   double * rlb = numrows ? new double[numrows] : 0;
+   double * rub = numrows ? new double[numrows] : 0;
+
+   for (int i = 0; i < numrows; ++i) {
+      convertSenseToBound(rowsen[i], rowrhs[i], rowrng[i], rlb[i], rub[i]);
+   }
+   setMpsData(m, infinity, collb, colub, obj, integrality, rlb, rub,
+	      colnames, rownames);
+   delete [] rlb;
+   delete [] rub;
+}
+
+void
+CoinMpsIO::setProblemName (const char *name)
+{ free(problemName_) ;
+  problemName_ = CoinStrdup(name) ; }
+
+void
+CoinMpsIO::setObjectiveName (const char *name)
+{ free(objectiveName_) ;
+  objectiveName_ = CoinStrdup(name) ; }
+
+//------------------------------------------------------------------
+// Return true if column is a continuous, binary, ...
+//------------------------------------------------------------------
+bool CoinMpsIO::isContinuous(int columnNumber) const
+{
+  const char * intType = integerType_;
+  if ( intType==NULL ) return true;
+  assert (columnNumber>=0 && columnNumber < numberColumns_);
+  if ( intType[columnNumber]==0 ) return true;
+  return false;
+}
+
+/* Return true if column is integer.
+   Note: This function returns true if the the column
+   is binary or a general integer.
+*/
+bool CoinMpsIO::isInteger(int columnNumber) const
+{
+  const char * intType = integerType_;
+  if ( intType==NULL ) return false;
+  assert (columnNumber>=0 && columnNumber < numberColumns_);
+  if ( intType[columnNumber]!=0 ) return true;
+  return false;
+}
+// if integer
+const char * CoinMpsIO::integerColumns() const
+{
+  return integerType_;
+}
+// Pass in array saying if each variable integer
+void 
+CoinMpsIO::copyInIntegerInformation(const char * integerType)
+{
+  if (integerType) {
+    if (!integerType_)
+      integerType_ = reinterpret_cast<char *> (malloc (numberColumns_ * sizeof(char)));
+    memcpy(integerType_,integerType,numberColumns_);
+  } else {
+    free(integerType_);
+    integerType_=NULL;
+  }
+}
+// names - returns NULL if out of range
+const char * CoinMpsIO::rowName(int index) const
+{
+  if (index>=0&&index<numberRows_) {
+    return names_[0][index];
+  } else {
+    return NULL;
+  }
+}
+const char * CoinMpsIO::columnName(int index) const
+{
+  if (index>=0&&index<numberColumns_) {
+    return names_[1][index];
+  } else {
+    return NULL;
+  }
+}
+// names - returns -1 if name not found
+int CoinMpsIO::rowIndex(const char * name) const
+{
+  if (!hash_[0]) {
+    if (numberRows_) {
+      startHash(0);
+    } else {
+      return -1;
+    }
+  }
+  return findHash ( name , 0 );
+}
+    int CoinMpsIO::columnIndex(const char * name) const
+{
+  if (!hash_[1]) {
+    if (numberColumns_) {
+      startHash(1);
+    } else {
+      return -1;
+    }
+  }
+  return findHash ( name , 1 );
+}
+
+// Release all row information (lower, upper)
+void CoinMpsIO::releaseRowInformation()
+{
+  free(rowlower_);
+  free(rowupper_);
+  rowlower_=NULL;
+  rowupper_=NULL;
+}
+// Release all column information (lower, upper, objective)
+void CoinMpsIO::releaseColumnInformation()
+{
+  free(collower_);
+  free(colupper_);
+  free(objective_);
+  collower_=NULL;
+  colupper_=NULL;
+  objective_=NULL;
+}
+// Release integer information
+void CoinMpsIO::releaseIntegerInformation()
+{
+  free(integerType_);
+  integerType_=NULL;
+}
+// Release row names
+void CoinMpsIO::releaseRowNames()
+{
+  releaseRedundantInformation();
+  int i;
+  for (i=0;i<numberHash_[0];i++) {
+    free(names_[0][i]);
+  }
+  free(names_[0]);
+  names_[0]=NULL;
+  numberHash_[0]=0;
+}
+// Release column names
+void CoinMpsIO::releaseColumnNames()
+{
+  releaseRedundantInformation();
+  int i;
+  for (i=0;i<numberHash_[1];i++) {
+    free(names_[1][i]);
+  }
+  free(names_[1]);
+  names_[1]=NULL;
+  numberHash_[1]=0;
+}
+// Release matrix information
+void CoinMpsIO::releaseMatrixInformation()
+{
+  releaseRedundantInformation();
+  delete matrixByColumn_;
+  matrixByColumn_=NULL;
+}
+  
+
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinMpsIO::CoinMpsIO ()
+:
+problemName_(CoinStrdup("")),
+objectiveName_(CoinStrdup("")),
+rhsName_(CoinStrdup("")),
+rangeName_(CoinStrdup("")),
+boundName_(CoinStrdup("")),
+numberRows_(0),
+numberColumns_(0),
+numberElements_(0),
+rowsense_(NULL),
+rhs_(NULL),
+rowrange_(NULL),
+matrixByRow_(NULL),
+matrixByColumn_(NULL),
+rowlower_(NULL),
+rowupper_(NULL),
+collower_(NULL),
+colupper_(NULL),
+objective_(NULL),
+objectiveOffset_(0.0),
+integerType_(NULL),
+fileName_(CoinStrdup("????")),
+defaultBound_(1),
+infinity_(COIN_DBL_MAX),
+smallElement_(1.0e-14),
+defaultHandler_(true),
+cardReader_(NULL),
+convertObjective_(false),
+allowStringElements_(0),
+maximumStringElements_(0),
+numberStringElements_(0),
+stringElements_(NULL)
+{
+  numberHash_[0]=0;
+  hash_[0]=NULL;
+  names_[0]=NULL;
+  numberHash_[1]=0;
+  hash_[1]=NULL;
+  names_[1]=NULL;
+  handler_ = new CoinMessageHandler();
+  messages_ = CoinMessage();
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinMpsIO::CoinMpsIO(const CoinMpsIO & rhs)
+:
+problemName_(CoinStrdup("")),
+objectiveName_(CoinStrdup("")),
+rhsName_(CoinStrdup("")),
+rangeName_(CoinStrdup("")),
+boundName_(CoinStrdup("")),
+numberRows_(0),
+numberColumns_(0),
+numberElements_(0),
+rowsense_(NULL),
+rhs_(NULL),
+rowrange_(NULL),
+matrixByRow_(NULL),
+matrixByColumn_(NULL),
+rowlower_(NULL),
+rowupper_(NULL),
+collower_(NULL),
+colupper_(NULL),
+objective_(NULL),
+objectiveOffset_(0.0),
+integerType_(NULL),
+fileName_(CoinStrdup("????")),
+defaultBound_(1),
+infinity_(COIN_DBL_MAX),
+smallElement_(1.0e-14),
+defaultHandler_(true),
+cardReader_(NULL),
+allowStringElements_(rhs.allowStringElements_),
+maximumStringElements_(rhs.maximumStringElements_),
+numberStringElements_(rhs.numberStringElements_),
+stringElements_(NULL)
+{
+  numberHash_[0]=0;
+  hash_[0]=NULL;
+  names_[0]=NULL;
+  numberHash_[1]=0;
+  hash_[1]=NULL;
+  names_[1]=NULL;
+  if ( rhs.rowlower_ !=NULL || rhs.collower_ != NULL) {
+    gutsOfCopy(rhs);
+    // OK and proper to leave rowsense_, rhs_, and
+    // rowrange_ (also row copy and hash) to NULL.  They will be constructed
+    // if they are required.
+  }
+  defaultHandler_ = rhs.defaultHandler_;
+  if (defaultHandler_)
+    handler_ = new CoinMessageHandler(*rhs.handler_);
+  else
+    handler_ = rhs.handler_;
+  messages_ = CoinMessage();
+}
+
+void CoinMpsIO::gutsOfCopy(const CoinMpsIO & rhs)
+{
+  defaultHandler_ = rhs.defaultHandler_;
+  if (rhs.matrixByColumn_)
+    matrixByColumn_=new CoinPackedMatrix(*(rhs.matrixByColumn_));
+  numberElements_=rhs.numberElements_;
+  numberRows_=rhs.numberRows_;
+  numberColumns_=rhs.numberColumns_;
+  convertObjective_=rhs.convertObjective_;
+  if (rhs.rowlower_) {
+    rowlower_ = reinterpret_cast<double *> (malloc(numberRows_*sizeof(double)));
+    rowupper_ = reinterpret_cast<double *> (malloc(numberRows_*sizeof(double)));
+    memcpy(rowlower_,rhs.rowlower_,numberRows_*sizeof(double));
+    memcpy(rowupper_,rhs.rowupper_,numberRows_*sizeof(double));
+  }
+  if (rhs.collower_) {
+    collower_ = reinterpret_cast<double *> (malloc(numberColumns_*sizeof(double)));
+    colupper_ = reinterpret_cast<double *> (malloc(numberColumns_*sizeof(double)));
+    objective_ = reinterpret_cast<double *> (malloc(numberColumns_*sizeof(double)));
+    memcpy(collower_,rhs.collower_,numberColumns_*sizeof(double));
+    memcpy(colupper_,rhs.colupper_,numberColumns_*sizeof(double));
+    memcpy(objective_,rhs.objective_,numberColumns_*sizeof(double));
+  }
+  if (rhs.integerType_) {
+    integerType_ = reinterpret_cast<char *> (malloc (numberColumns_*sizeof(char)));
+    memcpy(integerType_,rhs.integerType_,numberColumns_*sizeof(char));
+  }
+  free(fileName_);
+  free(problemName_);
+  free(objectiveName_);
+  free(rhsName_);
+  free(rangeName_);
+  free(boundName_);
+  fileName_ = CoinStrdup(rhs.fileName_);
+  problemName_ = CoinStrdup(rhs.problemName_);
+  objectiveName_ = CoinStrdup(rhs.objectiveName_);
+  rhsName_ = CoinStrdup(rhs.rhsName_);
+  rangeName_ = CoinStrdup(rhs.rangeName_);
+  boundName_ = CoinStrdup(rhs.boundName_);
+  numberHash_[0]=rhs.numberHash_[0];
+  numberHash_[1]=rhs.numberHash_[1];
+  defaultBound_=rhs.defaultBound_;
+  infinity_=rhs.infinity_;
+  smallElement_ = rhs.smallElement_;
+  objectiveOffset_=rhs.objectiveOffset_;
+  int section;
+  for (section=0;section<2;section++) {
+    if (numberHash_[section]) {
+      char ** names2 = rhs.names_[section];
+      names_[section] = reinterpret_cast<char **> (malloc(numberHash_[section]*
+						     sizeof(char *)));
+      char ** names = names_[section];
+      int i;
+      for (i=0;i<numberHash_[section];i++) {
+	names[i]=CoinStrdup(names2[i]);
+      }
+    }
+  }
+  allowStringElements_ = rhs.allowStringElements_;
+  maximumStringElements_ = rhs.maximumStringElements_;
+  numberStringElements_ = rhs.numberStringElements_;
+  if (numberStringElements_) {
+    stringElements_ = new char * [maximumStringElements_];
+    for (int i=0;i<numberStringElements_;i++)
+      stringElements_[i]=CoinStrdup(rhs.stringElements_[i]);
+  } else {
+    stringElements_ = NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinMpsIO::~CoinMpsIO ()
+{
+  gutsOfDestructor();
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinMpsIO &
+CoinMpsIO::operator=(const CoinMpsIO& rhs)
+{
+  if (this != &rhs) {    
+    gutsOfDestructor();
+    if ( rhs.rowlower_ !=NULL || rhs.collower_ != NULL) {
+      gutsOfCopy(rhs);
+    }
+    defaultHandler_ = rhs.defaultHandler_;
+    if (defaultHandler_)
+      handler_ = new CoinMessageHandler(*rhs.handler_);
+    else
+      handler_ = rhs.handler_;
+    messages_ = CoinMessage();
+  }
+  return *this;
+}
+
+//-------------------------------------------------------------------
+void CoinMpsIO::gutsOfDestructor()
+{  
+  freeAll();
+  if (defaultHandler_) {
+    delete handler_;
+    handler_ = NULL;
+  }
+  delete cardReader_;
+  cardReader_ = NULL;
+}
+
+
+void CoinMpsIO::freeAll()
+{  
+  releaseRedundantInformation();
+  releaseRowNames();
+  releaseColumnNames();
+  delete matrixByRow_;
+  delete matrixByColumn_;
+  matrixByRow_=NULL;
+  matrixByColumn_=NULL;
+  free(rowlower_);
+  free(rowupper_);
+  free(collower_);
+  free(colupper_);
+  free(objective_);
+  free(integerType_);
+  free(fileName_);
+  rowlower_=NULL;
+  rowupper_=NULL;
+  collower_=NULL;
+  colupper_=NULL;
+  objective_=NULL;
+  integerType_=NULL;
+  fileName_=NULL;
+  free(problemName_);
+  free(objectiveName_);
+  free(rhsName_);
+  free(rangeName_);
+  free(boundName_);
+  problemName_=NULL;
+  objectiveName_=NULL;
+  rhsName_=NULL;
+  rangeName_=NULL;
+  boundName_=NULL;
+  for (int i=0;i<numberStringElements_;i++)
+    free(stringElements_[i]);
+  delete [] stringElements_;
+}
+
+/* Release all information which can be re-calculated e.g. rowsense
+    also any row copies OR hash tables for names */
+void CoinMpsIO::releaseRedundantInformation()
+{  
+  free( rowsense_);
+  free( rhs_);
+  free( rowrange_);
+  rowsense_=NULL;
+  rhs_=NULL;
+  rowrange_=NULL;
+  delete [] hash_[0];
+  delete [] hash_[1];
+  hash_[0]=0;
+  hash_[1]=0;
+  delete matrixByRow_;
+  matrixByRow_=NULL;
+}
+// Pass in Message handler (not deleted at end)
+void 
+CoinMpsIO::passInMessageHandler(CoinMessageHandler * handler)
+{
+  if (defaultHandler_) 
+    delete handler_;
+  defaultHandler_=false;
+  handler_=handler;
+}
+// Set language
+void 
+CoinMpsIO::newLanguage(CoinMessages::Language language)
+{
+  messages_ = CoinMessage(language);
+}
+
+/* Read in a quadratic objective from the given filename.  
+   If filename is NULL then continues reading from previous file.  If
+   not then the previous file is closed.
+   
+   No assumption is made on symmetry, positive definite etc.
+   No check is made for duplicates or non-triangular
+   
+   Returns number of errors
+*/
+int 
+CoinMpsIO::readQuadraticMps(const char * filename,
+			    int * &columnStart, int * &column2, double * &elements,
+			    int checkSymmetry)
+{
+  // Deal with filename - +1 if new, 0 if same as before, -1 if error
+  CoinFileInput *input = 0;
+  int returnCode = dealWithFileName(filename,"",input);
+  if (returnCode<0) {
+    return -1;
+  } else if (returnCode>0) {
+    delete cardReader_;
+    cardReader_ = new CoinMpsCardReader ( input, this);
+  }
+  // See if QUADOBJ just found
+  if (!filename&&cardReader_->whichSection (  ) == COIN_QUAD_SECTION ) {
+    cardReader_->setWhichSection(COIN_QUAD_SECTION);
+  } else if (cardReader_->whichSection (  ) == COIN_CONIC_SECTION ) {
+      return -3;
+  } else {
+    cardReader_->readToNextSection();
+    
+    // Skip NAME
+    if ( cardReader_->whichSection (  ) == COIN_NAME_SECTION ) 
+      cardReader_->readToNextSection();
+    if ( cardReader_->whichSection (  ) == COIN_QUAD_SECTION ) {
+      // save name of section
+      free(problemName_);
+      problemName_=CoinStrdup(cardReader_->columnName());
+    } else if ( cardReader_->whichSection (  ) == COIN_EOF_SECTION ) {
+      handler_->message(COIN_MPS_EOF,messages_)<<fileName_
+					       <<CoinMessageEol;
+      return -3;
+    } else {
+    handler_->message(COIN_MPS_BADFILE1,messages_)<<cardReader_->card()
+						  <<cardReader_->cardNumber()
+						  <<fileName_
+						  <<CoinMessageEol;
+    return -2;
+    }
+  }    
+
+  int numberErrors = 0;
+
+  // Guess at size of data
+  int maximumNonZeros = 5 *numberColumns_;
+  // Use malloc so can use realloc
+  int * column = reinterpret_cast<int *> (malloc(maximumNonZeros*sizeof(int)));
+  int * column2Temp = reinterpret_cast<int *> (malloc(maximumNonZeros*sizeof(int)));
+  double * elementTemp = reinterpret_cast<double *> (malloc(maximumNonZeros*sizeof(double)));
+
+  startHash(1);
+  int numberElements=0;
+
+  while ( cardReader_->nextField (  ) == COIN_QUAD_SECTION ) {
+    switch ( cardReader_->mpsType (  ) ) {
+    case COIN_BLANK_COLUMN:
+      if ( fabs ( cardReader_->value (  ) ) > smallElement_ ) {
+	if ( numberElements == maximumNonZeros ) {
+	  maximumNonZeros = ( 3 * maximumNonZeros ) / 2 + 1000;
+	  column = reinterpret_cast<COINColumnIndex * >
+	    (realloc ( column, maximumNonZeros * sizeof ( COINColumnIndex )));
+	  column2Temp = reinterpret_cast<COINColumnIndex *>
+	    (realloc ( column2Temp, maximumNonZeros * sizeof ( COINColumnIndex )));
+	  elementTemp = reinterpret_cast<double *>
+	    (realloc ( elementTemp, maximumNonZeros * sizeof ( double )));
+	}
+	// get indices
+	COINColumnIndex iColumn1 = findHash ( cardReader_->columnName (  ) , 1 );
+	COINColumnIndex iColumn2 = findHash ( cardReader_->rowName (  ) , 1 );
+
+	if ( iColumn1 >= 0 ) {
+	  if (iColumn2 >=0) {
+	    double value = cardReader_->value (  );
+	    column[numberElements]=iColumn1;
+	    column2Temp[numberElements]=iColumn2;
+	    elementTemp[numberElements++]=value;
+	  } else {
+	    numberErrors++;
+	    if ( numberErrors < 100 ) {
+		  handler_->message(COIN_MPS_NOMATCHROW,messages_)
+		    <<cardReader_->rowName()<<cardReader_->cardNumber()<<cardReader_->card()
+		    <<CoinMessageEol;
+	    } else if (numberErrors > 100000) {
+	      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	      return numberErrors;
+	    }
+	  }
+	} else {
+	  numberErrors++;
+	  if ( numberErrors < 100 ) {
+	    handler_->message(COIN_MPS_NOMATCHCOL,messages_)
+	      <<cardReader_->columnName()<<cardReader_->cardNumber()<<cardReader_->card()
+	      <<CoinMessageEol;
+	  } else if (numberErrors > 100000) {
+	    handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	    return numberErrors;
+	  }
+	}
+      }
+      break;
+    default:
+      numberErrors++;
+      if ( numberErrors < 100 ) {
+	handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						      <<cardReader_->card()
+						      <<CoinMessageEol;
+      } else if (numberErrors > 100000) {
+	handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	return numberErrors;
+      }
+    }
+  }
+  if ( cardReader_->whichSection (  ) != COIN_ENDATA_SECTION &&
+	 cardReader_->whichSection (  ) != COIN_CONIC_SECTION ) {
+      handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						    <<cardReader_->card()
+						    <<CoinMessageEol;
+      handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+      return numberErrors+100000;
+    }
+
+  stopHash(1);
+  // Do arrays as new [] and make column ordered
+  columnStart = new int [numberColumns_+1];
+  // for counts
+  int * count = new int[numberColumns_];
+  memset(count,0,numberColumns_*sizeof(int));
+  CoinBigIndex i;
+  // See about lower triangular
+  if (checkSymmetry&&numberErrors) 
+    checkSymmetry=2; // force corrections
+  if (checkSymmetry) {
+    if (checkSymmetry==1) {
+      // just check lower triangular
+      for ( i = 0; i < numberElements; i++ ) {
+	int iColumn = column[i];
+	int iColumn2 = column2Temp[i];
+	if (iColumn2<iColumn) {
+	  numberErrors=-4;
+	  column[i]=iColumn2;
+	  column2Temp[i]=iColumn;
+	}
+      }
+    } else {
+      // make lower triangular
+      for ( i = 0; i < numberElements; i++ ) {
+	int iColumn = column[i];
+	int iColumn2 = column2Temp[i];
+	if (iColumn2<iColumn) {
+	  column[i]=iColumn2;
+	  column2Temp[i]=iColumn;
+	}
+      }
+    }
+  }
+  for ( i = 0; i < numberElements; i++ ) {
+    int iColumn = column[i];
+    count[iColumn]++;
+  }
+  // Do starts
+  int number = 0;
+  columnStart[0]=0;
+  for (i=0;i<numberColumns_;i++) {
+    number += count[i];
+    count[i]= columnStart[i];
+    columnStart[i+1]=number;
+  }
+  column2 = new int[numberElements];
+  elements = new double[numberElements];
+
+  // Get column ordering
+  for ( i = 0; i < numberElements; i++ ) {
+    int iColumn = column[i];
+    int iColumn2 = column2Temp[i];
+    int put = count[iColumn];
+    elements[put]=elementTemp[i];
+    column2[put++]=iColumn2;
+    count[iColumn]=put;
+  }
+  free(column);
+  free(column2Temp);
+  free(elementTemp);
+
+  // Now in column order - deal with duplicates
+  for (i=0;i<numberColumns_;i++) 
+    count[i] = -1;
+
+  int start = 0;
+  number=0;
+  for (i=0;i<numberColumns_;i++) {
+    int j;
+    for (j=start;j<columnStart[i+1];j++) {
+      int iColumn2 = column2[j];
+      if (count[iColumn2]<0) {
+	count[iColumn2]=j;
+      } else {
+	// duplicate
+	int iOther = count[iColumn2];
+	double value = elements[iOther]+elements[j];
+	elements[iOther]=value;
+	elements[j]=0.0;
+      }
+    }
+    for (j=start;j<columnStart[i+1];j++) {
+      int iColumn2 = column2[j];
+      count[iColumn2]=-1;
+      double value = elements[j];
+      if (value) {
+	column2[number]=iColumn2;
+	elements[number++]=value;
+      }
+    }
+    start = columnStart[i+1];
+    columnStart[i+1]=number;
+  }
+
+  delete [] count;
+  return numberErrors;
+}
+/* Read in a list of cones from the given filename.  
+   If filename is NULL (or same) then continues reading from previous file.
+   If not then the previous file is closed.  Code should be added to
+   general MPS reader to read this if CSECTION
+   
+   No checking is done that in unique cone
+   
+   Arrays should be deleted by delete []
+   
+   Returns number of errors, -1 bad file, -2 no conic section, -3 empty section
+   
+   columnStart is numberCones+1 long, other number of columns in matrix
+
+   coneType is 1 for QUAD, 2 for RQUAD (numberCones long)
+*/
+int 
+CoinMpsIO::readConicMps(const char * filename,
+			int * &columnStart, int * &column, int * &coneType, int & numberCones)
+{
+  // Deal with filename - +1 if new, 0 if same as before, -1 if error
+  CoinFileInput *input = 0;
+  int returnCode = dealWithFileName(filename,"",input);
+  if (returnCode<0) {
+    return -1;
+  } else if (returnCode>0) {
+    delete cardReader_;
+    cardReader_ = new CoinMpsCardReader ( input, this);
+  }
+
+  // See if CSECTION just found
+  if (!filename&&cardReader_->whichSection (  ) == COIN_CONIC_SECTION ) {
+    cardReader_->setWhichSection(COIN_CONIC_SECTION);
+  } else {
+    cardReader_->readToNextSection();
+
+  // Skip NAME
+  if ( cardReader_->whichSection (  ) == COIN_NAME_SECTION ) 
+    cardReader_->readToNextSection();
+    if ( cardReader_->whichSection (  ) == COIN_CONIC_SECTION ) {
+      // looks good
+    } else if ( cardReader_->whichSection (  ) == COIN_EOF_SECTION ) {
+      handler_->message(COIN_MPS_EOF,messages_)<<fileName_
+					       <<CoinMessageEol;
+      return -3;
+    } else {
+    handler_->message(COIN_MPS_BADFILE1,messages_)<<cardReader_->card()
+						  <<cardReader_->cardNumber()
+						  <<fileName_
+						  <<CoinMessageEol;
+    return -2;
+    }
+  }    
+
+  numberCones=0;
+
+  // Get arrays (some too big, but ...)
+  columnStart = new int [numberColumns_+1];
+  column = new int [numberColumns_];
+  coneType = new int [numberColumns_];
+  // check QUAD or RQUAD (by hand) - card has had end stripped 
+  const char * quad = cardReader_->card()+strlen(cardReader_->card())-4; 
+  // Should be QUAD but if not don't complain
+  int type=1;
+  if (!strcmp(quad,"QUAD")) {
+    if (*(quad-1)=='R')
+      type=2;
+  }
+  coneType[0] = type;
+  int numberErrors = 0;
+  columnStart[0]=0;
+  int numberElements=0;
+  startHash(1);
+  
+  while ( cardReader_->nextField (  ) == COIN_CONIC_SECTION ) {
+    const char * card = cardReader_->card();
+    if (!strncmp(card,"CSECTION",8)) {
+      // check QUAD or RQUAD (by hand) - card has had end stripped 
+      const char * quad = card+strlen(card)-4; 
+      // Should be QUAD but if not don't complain
+      int type=1;
+      if (!strcmp(quad,"QUAD")) {
+	if (*(quad-1)=='R')
+	  type=2;
+      }
+      if (numberElements==columnStart[numberCones]) {
+	printf("Cone must have at least one column\n");
+	abort();
+      }
+      columnStart[++numberCones]=numberElements;
+      coneType[numberCones] = type;
+      continue;
+    }
+    COINColumnIndex iColumn1;
+    switch ( cardReader_->mpsType (  ) ) {
+    case COIN_BLANK_COLUMN:
+      // get index
+      iColumn1 = findHash ( cardReader_->columnName (  ) , 1 );
+      
+      if ( iColumn1 >= 0 ) {
+	column[numberElements++]=iColumn1;
+      } else {
+	numberErrors++;
+	if ( numberErrors < 100 ) {
+	  handler_->message(COIN_MPS_NOMATCHCOL,messages_)
+	    <<cardReader_->columnName()<<cardReader_->cardNumber()<<cardReader_->card()
+	    <<CoinMessageEol;
+	} else if (numberErrors > 100000) {
+	  handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	  return numberErrors;
+	}
+      }
+      break;
+    default:
+      numberErrors++;
+      if ( numberErrors < 100 ) {
+	handler_->message(COIN_MPS_BADIMAGE,messages_)<<cardReader_->cardNumber()
+						      <<cardReader_->card()
+						      <<CoinMessageEol;
+      } else if (numberErrors > 100000) {
+	handler_->message(COIN_MPS_RETURNING,messages_)<<CoinMessageEol;
+	return numberErrors;
+      }
+    }
+  }
+  if ( cardReader_->whichSection (  ) == COIN_ENDATA_SECTION ) {
+    // Error if no cones
+    if (!numberElements) {
+      handler_->message(COIN_MPS_EOF,messages_)<<fileName_
+					       <<CoinMessageEol;
+      delete [] columnStart;
+      delete [] column;
+      delete [] coneType;
+      columnStart = NULL;
+      column = NULL;
+      coneType = NULL;
+      return -3;
+    } else {
+      columnStart[++numberCones]=numberElements;
+    }
+  } else {
+    handler_->message(COIN_MPS_BADFILE1,messages_)<<cardReader_->card()
+						  <<cardReader_->cardNumber()
+						 <<fileName_
+						  <<CoinMessageEol;
+      delete [] columnStart;
+      delete [] column;
+      delete [] coneType;
+      columnStart = NULL;
+      column = NULL;
+      coneType = NULL;
+    return -2;
+  }
+
+  stopHash(1);
+  return numberErrors;
+}
+// Add string to list
+void 
+CoinMpsIO::addString(int iRow,int iColumn, const char * value)
+{
+  char id [20];
+  sprintf(id,"%d,%d,",iRow,iColumn);
+  int n = static_cast<int>(strlen(id)+strlen(value));
+  if (numberStringElements_==maximumStringElements_) {
+    maximumStringElements_ = 2*maximumStringElements_+100;
+    char ** temp = new char * [maximumStringElements_];
+    for (int i=0;i<numberStringElements_;i++)
+      temp[i]=stringElements_[i];
+    delete [] stringElements_;
+    stringElements_ = temp;
+  }
+  char * line = reinterpret_cast<char *> (malloc(n+1));
+  stringElements_[numberStringElements_++]=line;
+  strcpy(line,id);
+  strcat(line,value);
+}
+// Decode string
+void 
+CoinMpsIO::decodeString(int iString, int & iRow, int & iColumn, const char * & value) const
+{
+  iRow=-1;
+  iColumn=-1;
+  value=NULL;
+  if (iString>=0&&iString<numberStringElements_) {
+    value = stringElements_[iString];
+    sscanf(value,"%d,%d,",&iRow,&iColumn);
+    value = strchr(value,',');
+    assert(value);
+    value++;
+    value = strchr(value,',');
+    assert(value);
+    value++;
+  }
+}
+// copies in strings from a CoinModel - returns number
+int 
+CoinMpsIO::copyStringElements(const CoinModel * model)
+{
+  if (!model->stringsExist())
+    return 0; // no strings
+  assert (!numberStringElements_);
+  /*
+    First columns (including objective==numberRows)
+    then RHS(==numberColumns (+1)) (with rowLower and rowUpper marked)
+    then bounds LO==numberRows+1, UP==numberRows+2
+  */
+  int numberColumns = model->numberColumns();
+  int numberRows = model->numberRows();
+  int iColumn;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    const char * expr = model->getColumnObjectiveAsString(iColumn);
+    if (strcmp(expr,"Numeric")) {
+      addString(numberRows,iColumn,expr);
+    }
+    CoinModelLink triple=model->firstInColumn(iColumn);
+    while (triple.row()>=0) {
+      int iRow = triple.row();
+      const char * expr = model->getElementAsString(iRow,iColumn);
+      if (strcmp(expr,"Numeric")) {
+	addString(iRow,iColumn,expr);
+      }
+      triple=model->next(triple);
+    }
+  }
+  int iRow;
+  for (iRow=0;iRow<numberRows;iRow++) {
+    // for now no ranges
+    const char * expr1 = model->getRowLowerAsString(iRow);
+    const char * expr2 = model->getRowUpperAsString(iRow);
+    if (strcmp(expr1,"Numeric")) {
+      if (rowupper_[iRow]>1.0e20&&!strcmp(expr2,"Numeric")) {
+	// G row
+	addString(iRow,numberColumns,expr1);
+	rowlower_[iRow]=STRING_VALUE;
+      } else if (!strcmp(expr1,expr2)) {
+	// E row
+	addString(iRow,numberColumns,expr1);
+	rowlower_[iRow]=STRING_VALUE;
+	addString(iRow,numberColumns+1,expr1);
+	rowupper_[iRow]=STRING_VALUE;
+      } else if (rowlower_[iRow]<-1.0e20&&!strcmp(expr1,"Numeric")) {
+	// L row
+	addString(iRow,numberColumns+1,expr2);
+	rowupper_[iRow]=STRING_VALUE;
+      } else {
+	// Range
+	printf("Unaable to handle string ranges row %d %s %s\n",
+	       iRow,expr1,expr2);
+	abort();
+      }
+    }
+  }
+  // Bounds
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    const char * expr = model->getColumnLowerAsString(iColumn);
+    if (strcmp(expr,"Numeric")) {
+      addString(numberRows+1,iColumn,expr);
+      collower_[iColumn]=STRING_VALUE;
+    }
+    expr = model->getColumnUpperAsString(iColumn);
+    if (strcmp(expr,"Numeric")) {
+      addString(numberRows+2,iColumn,expr);
+      colupper_[iColumn]=STRING_VALUE;
+    }
+  }
+  return numberStringElements_;
+}
+// Constructor 
+CoinSet::CoinSet ( int numberEntries, const int * which)
+{
+  numberEntries_ = numberEntries;
+  which_ = new int [numberEntries_];
+  weights_ = NULL;
+  memcpy(which_,which,numberEntries_*sizeof(int));
+  setType_=1;
+}
+// Default constructor 
+CoinSet::CoinSet ()
+{
+  numberEntries_ = 0;
+  which_ = NULL;
+  weights_ = NULL;
+  setType_=1;
+}
+
+// Copy constructor 
+CoinSet::CoinSet (const CoinSet & rhs)
+{
+  numberEntries_ = rhs.numberEntries_;
+  setType_=rhs.setType_;
+  which_ = CoinCopyOfArray(rhs.which_,numberEntries_);
+  weights_ = CoinCopyOfArray(rhs.weights_,numberEntries_);
+}
+  
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinSet &
+CoinSet::operator=(const CoinSet& rhs)
+{
+  if (this != &rhs) {    
+    delete [] which_;
+    delete [] weights_;
+    numberEntries_ = rhs.numberEntries_;
+    setType_=rhs.setType_;
+    which_ = CoinCopyOfArray(rhs.which_,numberEntries_);
+    weights_ = CoinCopyOfArray(rhs.weights_,numberEntries_);
+  }
+  return *this;
+}
+
+// Destructor
+CoinSet::~CoinSet (  )
+{
+  delete [] which_;
+  delete [] weights_;
+}
+// Constructor 
+CoinSosSet::CoinSosSet ( int numberEntries, const int * which, const double * weights, int type)
+  : CoinSet(numberEntries,which)
+{
+  weights_= new double [numberEntries_];
+  memcpy(weights_,weights,numberEntries_*sizeof(double));
+  setType_ = type;
+  double last = weights_[0];
+  int i;
+  bool allSame=true;
+  for (i=1;i<numberEntries_;i++) {
+    if(weights_[i]!=last) {
+      allSame=false;
+      break;
+    }
+  }
+  if (allSame) {
+    for (i=0;i<numberEntries_;i++) 
+      weights_[i] = i;
+  }
+}
+
+// Destructor
+CoinSosSet::~CoinSosSet (  )
+{
+}
+#ifdef USE_SBB
+#include "SbbModel.hpp"
+#include "SbbBranchActual.hpp"
+// returns an object of type SbbObject
+SbbObject * 
+CoinSosSet::sbbObject(SbbModel * model) const 
+{
+  // which are matrix here - need to put as integer index
+  abort();
+  return new SbbSOS(model,numberEntries_,which_,weights_,0,setType_);
+}
+#endif
diff --git a/cbits/coin/CoinMpsIO.hpp b/cbits/coin/CoinMpsIO.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinMpsIO.hpp
@@ -0,0 +1,1056 @@
+/* $Id: CoinMpsIO.hpp 1643 2013-10-16 03:43:21Z tkr $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinMpsIO_H
+#define CoinMpsIO_H
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <vector>
+#include <string>
+
+#include "CoinUtilsConfig.h"
+#include "CoinPackedMatrix.hpp"
+#include "CoinMessageHandler.hpp"
+#include "CoinFileIO.hpp"
+class CoinModel;
+
+/// The following lengths are in decreasing order (for 64 bit etc)
+/// Large enough to contain element index
+/// This is already defined as CoinBigIndex
+/// Large enough to contain column index
+typedef int COINColumnIndex;
+
+/// Large enough to contain row index (or basis)
+typedef int COINRowIndex;
+
+// We are allowing free format - but there is a limit!
+// User can override by using CXXFLAGS += -DCOIN_MAX_FIELD_LENGTH=nnn
+#ifndef COIN_MAX_FIELD_LENGTH
+#define COIN_MAX_FIELD_LENGTH 160
+#endif
+#define MAX_CARD_LENGTH 5*COIN_MAX_FIELD_LENGTH+80
+
+enum COINSectionType { COIN_NO_SECTION, COIN_NAME_SECTION, COIN_ROW_SECTION,
+		       COIN_COLUMN_SECTION,
+		       COIN_RHS_SECTION, COIN_RANGES_SECTION, COIN_BOUNDS_SECTION,
+		       COIN_ENDATA_SECTION, COIN_EOF_SECTION, COIN_QUADRATIC_SECTION, 
+		       COIN_CONIC_SECTION,COIN_QUAD_SECTION,COIN_SOS_SECTION, 
+		       COIN_BASIS_SECTION,COIN_UNKNOWN_SECTION
+};
+
+enum COINMpsType { COIN_N_ROW, COIN_E_ROW, COIN_L_ROW, COIN_G_ROW,
+  COIN_BLANK_COLUMN, COIN_S1_COLUMN, COIN_S2_COLUMN, COIN_S3_COLUMN,
+  COIN_INTORG, COIN_INTEND, COIN_SOSEND, COIN_UNSET_BOUND,
+  COIN_UP_BOUND, COIN_FX_BOUND, COIN_LO_BOUND, COIN_FR_BOUND,
+                   COIN_MI_BOUND, COIN_PL_BOUND, COIN_BV_BOUND, 
+				   COIN_UI_BOUND, COIN_LI_BOUND, COIN_BOTH_BOUNDS_SET,
+		   COIN_SC_BOUND, COIN_S1_BOUND, COIN_S2_BOUND,
+		   COIN_BS_BASIS, COIN_XL_BASIS, COIN_XU_BASIS,
+		   COIN_LL_BASIS, COIN_UL_BASIS, COIN_UNKNOWN_MPS_TYPE
+};
+class CoinMpsIO;
+/// Very simple code for reading MPS data
+class CoinMpsCardReader {
+
+public:
+
+  /**@name Constructor and destructor */
+  //@{
+  /// Constructor expects file to be open 
+  /// This one takes gzFile if fp null
+  CoinMpsCardReader ( CoinFileInput *input, CoinMpsIO * reader );
+
+  /// Destructor
+  ~CoinMpsCardReader (  );
+  //@}
+
+
+  /**@name card stuff */
+  //@{
+  /// Read to next section
+  COINSectionType readToNextSection (  );
+  /// Gets next field and returns section type e.g. COIN_COLUMN_SECTION
+  COINSectionType nextField (  );
+  /** Gets next field for .gms file and returns type.
+      -1 - EOF
+      0 - what we expected (and processed so pointer moves past)
+      1 - not what we expected
+      leading blanks always ignored
+      input types 
+      0 - anything - stops on non blank card
+      1 - name (in columnname)
+      2 - value
+      3 - value name pair
+      4 - equation type
+      5 - ;
+  */
+  int nextGmsField ( int expectedType );
+  /// Returns current section type
+  inline COINSectionType whichSection (  ) const {
+    return section_;
+  }
+  /// Sets current section type
+  inline void setWhichSection(COINSectionType section  ) {
+    section_=section;
+  }
+  /// Sees if free format. 
+  inline bool freeFormat() const
+  { return freeFormat_;}
+  /// Sets whether free format.  Mainly for blank RHS etc
+  inline void setFreeFormat(bool yesNo) 
+  { freeFormat_=yesNo;}
+  /// Only for first field on card otherwise BLANK_COLUMN
+  /// e.g. COIN_E_ROW
+  inline COINMpsType mpsType (  ) const {
+    return mpsType_;
+  }
+  /// Reads and cleans card - taking out trailing blanks - return 1 if EOF
+  int cleanCard();
+  /// Returns row name of current field
+  inline const char *rowName (  ) const {
+    return rowName_;
+  }
+  /// Returns column name of current field
+  inline const char *columnName (  ) const {
+    return columnName_;
+  }
+  /// Returns value in current field
+  inline double value (  ) const {
+    return value_;
+  }
+  /// Returns value as string in current field
+  inline const char *valueString (  ) const {
+    return valueString_;
+  }
+  /// Whole card (for printing)
+  inline const char *card (  ) const {
+    return card_;
+  }
+  /// Whole card - so we look at it (not const so nextBlankOr will work for gms reader)
+  inline char *mutableCard (  ) {
+    return card_;
+  }
+  /// set position (again so gms reader will work)
+  inline void setPosition(char * position)
+  { position_=position;}
+  /// get position (again so gms reader will work)
+  inline char * getPosition() const
+  { return position_;}
+  /// Returns card number
+  inline CoinBigIndex cardNumber (  ) const {
+    return cardNumber_;
+  }
+  /// Returns file input
+  inline CoinFileInput * fileInput (  ) const {
+    return input_;
+  }
+  /// Sets whether strings allowed
+  inline void setStringsAllowed()
+  { stringsAllowed_=true;}
+  //@}
+
+////////////////// data //////////////////
+protected:
+
+  /**@name data */
+  //@{
+  /// Current value
+  double value_;
+  /// Current card image
+  char card_[MAX_CARD_LENGTH];
+  /// Current position within card image
+  char *position_;
+  /// End of card
+  char *eol_;
+  /// Current COINMpsType
+  COINMpsType mpsType_;
+  /// Current row name
+  char rowName_[COIN_MAX_FIELD_LENGTH];
+  /// Current column name
+  char columnName_[COIN_MAX_FIELD_LENGTH];
+  /// File input
+  CoinFileInput *input_;
+  /// Which section we think we are in
+  COINSectionType section_;
+  /// Card number
+  CoinBigIndex cardNumber_;
+  /// Whether free format.  Just for blank RHS etc
+  bool freeFormat_;
+  /// Whether IEEE - 0 no, 1 INTEL, 2 not INTEL
+  int ieeeFormat_;
+  /// If all names <= 8 characters then allow embedded blanks
+  bool eightChar_;
+  /// MpsIO
+  CoinMpsIO * reader_;
+  /// Message handler
+  CoinMessageHandler * handler_;
+  /// Messages
+  CoinMessages messages_;
+  /// Current element as characters (only if strings allowed) 
+  char valueString_[COIN_MAX_FIELD_LENGTH];
+  /// Whether strings allowed
+  bool stringsAllowed_;
+  //@}
+public:
+  /**@name methods */
+  //@{
+  /// type - 0 normal, 1 INTEL IEEE, 2 other IEEE
+  double osi_strtod(char * ptr, char ** output, int type);
+  /// remove blanks 
+  static void strcpyAndCompress ( char *to, const char *from );
+  ///
+  static char * nextBlankOr ( char *image );
+  /// For strings
+  double osi_strtod(char * ptr, char ** output);
+  //@}
+
+};
+
+//#############################################################################
+#ifdef USE_SBB
+class SbbObject;
+class SbbModel;
+#endif
+/// Very simple class for containing data on set
+class CoinSet {
+
+public:
+
+  /**@name Constructor and destructor */
+  //@{
+  /// Default constructor 
+  CoinSet ( );
+  /// Constructor 
+  CoinSet ( int numberEntries, const int * which);
+
+  /// Copy constructor 
+  CoinSet (const CoinSet &);
+  
+  /// Assignment operator 
+  CoinSet & operator=(const CoinSet& rhs);  
+  
+  /// Destructor
+  virtual ~CoinSet (  );
+  //@}
+
+
+  /**@name gets */
+  //@{
+  /// Returns number of entries
+  inline int numberEntries (  ) const 
+  { return numberEntries_;  }
+  /// Returns type of set - 1 =SOS1, 2 =SOS2
+  inline int setType (  ) const 
+  { return setType_;  }
+  /// Returns list of variables
+  inline const int * which (  ) const 
+  { return which_;  }
+  /// Returns weights
+  inline const double * weights (  ) const 
+  { return weights_;  }
+  //@}
+
+#ifdef USE_SBB
+  /**@name Use in sbb */
+  //@{
+  /// returns an object of type SbbObject
+  virtual SbbObject * sbbObject(SbbModel * model) const 
+  { return NULL;}
+  //@}
+#endif
+
+////////////////// data //////////////////
+protected:
+
+  /**@name data */
+  //@{
+  /// Number of entries
+  int numberEntries_;
+  /// type of set
+  int setType_;
+  /// Which variables are in set
+  int * which_;
+  /// Weights
+  double * weights_;
+  //@}
+};
+
+//#############################################################################
+/// Very simple class for containing SOS set
+class CoinSosSet : public CoinSet{
+
+public:
+
+  /**@name Constructor and destructor */
+  //@{
+  /// Constructor 
+  CoinSosSet ( int numberEntries, const int * which, const double * weights, int type);
+
+  /// Destructor
+  virtual ~CoinSosSet (  );
+  //@}
+
+
+#ifdef USE_SBB
+  /**@name Use in sbb */
+  //@{
+  /// returns an object of type SbbObject
+  virtual SbbObject * sbbObject(SbbModel * model) const ;
+  //@}
+#endif
+
+////////////////// data //////////////////
+protected:
+
+  /**@name data */
+  //@{
+  //@}
+};
+
+//#############################################################################
+
+/** MPS IO Interface
+
+    This class can be used to read in mps files without a solver.  After
+    reading the file, the CoinMpsIO object contains all relevant data, which
+    may be more than a particular OsiSolverInterface allows for.  Items may
+    be deleted to allow for flexibility of data storage.
+
+    The implementation makes the CoinMpsIO object look very like a dummy solver,
+    as the same conventions are used.
+*/
+
+class CoinMpsIO {
+   friend void CoinMpsIOUnitTest(const std::string & mpsDir);
+
+public:
+
+/** @name Methods to retrieve problem information
+
+   These methods return information about the problem held by the CoinMpsIO
+   object.
+   
+   Querying an object that has no data associated with it result in zeros for
+   the number of rows and columns, and NULL pointers from the methods that
+   return vectors.  Const pointers returned from any data-query method are
+   always valid
+*/
+//@{
+    /// Get number of columns
+    int getNumCols() const;
+
+    /// Get number of rows
+    int getNumRows() const;
+
+    /// Get number of nonzero elements
+    int getNumElements() const;
+
+    /// Get pointer to array[getNumCols()] of column lower bounds
+    const double * getColLower() const;
+
+    /// Get pointer to array[getNumCols()] of column upper bounds
+    const double * getColUpper() const;
+
+    /** Get pointer to array[getNumRows()] of constraint senses.
+	<ul>
+	<li>'L': <= constraint
+	<li>'E': =  constraint
+	<li>'G': >= constraint
+	<li>'R': ranged constraint
+	<li>'N': free constraint
+	</ul>
+    */
+    const char * getRowSense() const;
+
+    /** Get pointer to array[getNumRows()] of constraint right-hand sides.
+
+	Given constraints with upper (rowupper) and/or lower (rowlower) bounds,
+	the constraint right-hand side (rhs) is set as
+	<ul>
+	  <li> if rowsense()[i] == 'L' then rhs()[i] == rowupper()[i]
+	  <li> if rowsense()[i] == 'G' then rhs()[i] == rowlower()[i]
+	  <li> if rowsense()[i] == 'R' then rhs()[i] == rowupper()[i]
+	  <li> if rowsense()[i] == 'N' then rhs()[i] == 0.0
+	</ul>
+    */
+    const double * getRightHandSide() const;
+
+    /** Get pointer to array[getNumRows()] of row ranges.
+
+	Given constraints with upper (rowupper) and/or lower (rowlower) bounds, 
+	the constraint range (rowrange) is set as
+	<ul>
+          <li> if rowsense()[i] == 'R' then
+                  rowrange()[i] == rowupper()[i] - rowlower()[i]
+          <li> if rowsense()[i] != 'R' then
+                  rowrange()[i] is 0.0
+        </ul>
+	Put another way, only range constraints have a nontrivial value for
+	rowrange.
+    */
+    const double * getRowRange() const;
+
+    /// Get pointer to array[getNumRows()] of row lower bounds
+    const double * getRowLower() const;
+
+    /// Get pointer to array[getNumRows()] of row upper bounds
+    const double * getRowUpper() const;
+
+    /// Get pointer to array[getNumCols()] of objective function coefficients
+    const double * getObjCoefficients() const;
+
+    /// Get pointer to row-wise copy of the coefficient matrix
+    const CoinPackedMatrix * getMatrixByRow() const;
+
+    /// Get pointer to column-wise copy of the coefficient matrix
+    const CoinPackedMatrix * getMatrixByCol() const;
+
+    /// Return true if column is a continuous variable
+    bool isContinuous(int colNumber) const;
+
+    /** Return true if a column is an integer variable
+
+        Note: This function returns true if the the column
+        is a binary or general integer variable.
+    */
+    bool isInteger(int columnNumber) const;
+  
+    /** Returns array[getNumCols()] specifying if a variable is integer.
+
+	At present, simply coded as zero (continuous) and non-zero (integer)
+	May be extended at a later date.
+    */
+    const char * integerColumns() const;
+
+    /** Returns the row name for the specified index.
+
+	Returns 0 if the index is out of range.
+    */
+    const char * rowName(int index) const;
+
+    /** Returns the column name for the specified index.
+
+	Returns 0 if the index is out of range.
+    */
+    const char * columnName(int index) const;
+
+    /** Returns the index for the specified row name
+  
+	Returns -1 if the name is not found.
+        Returns numberRows for the objective row and > numberRows for
+	dropped free rows.
+    */
+    int rowIndex(const char * name) const;
+
+    /** Returns the index for the specified column name
+  
+	Returns -1 if the name is not found.
+    */
+    int columnIndex(const char * name) const;
+
+    /** Returns the (constant) objective offset
+    
+	This is the RHS entry for the objective row
+    */
+    double objectiveOffset() const;
+    /// Set objective offset
+    inline void setObjectiveOffset(double value)
+    { objectiveOffset_=value;}
+
+    /// Return the problem name
+    const char * getProblemName() const;
+
+    /// Return the objective name
+    const char * getObjectiveName() const;
+
+    /// Return the RHS vector name
+    const char * getRhsName() const;
+
+    /// Return the range vector name
+    const char * getRangeName() const;
+
+    /// Return the bound vector name
+    const char * getBoundName() const;
+    /// Number of string elements
+    inline int numberStringElements() const
+    { return numberStringElements_;}
+    /// String element
+    inline const char * stringElement(int i) const
+    { return stringElements_[i];}
+//@}
+
+
+/** @name Methods to set problem information
+
+    Methods to load a problem into the CoinMpsIO object.
+*/
+//@{
+  
+    /// Set the problem data
+    void setMpsData(const CoinPackedMatrix& m, const double infinity,
+		     const double* collb, const double* colub,
+		     const double* obj, const char* integrality,
+		     const double* rowlb, const double* rowub,
+		     char const * const * const colnames,
+		     char const * const * const rownames);
+    void setMpsData(const CoinPackedMatrix& m, const double infinity,
+		     const double* collb, const double* colub,
+		     const double* obj, const char* integrality,
+		     const double* rowlb, const double* rowub,
+		     const std::vector<std::string> & colnames,
+		     const std::vector<std::string> & rownames);
+    void setMpsData(const CoinPackedMatrix& m, const double infinity,
+		     const double* collb, const double* colub,
+		     const double* obj, const char* integrality,
+		     const char* rowsen, const double* rowrhs,
+		     const double* rowrng,
+		     char const * const * const colnames,
+		     char const * const * const rownames);
+    void setMpsData(const CoinPackedMatrix& m, const double infinity,
+		     const double* collb, const double* colub,
+		     const double* obj, const char* integrality,
+		     const char* rowsen, const double* rowrhs,
+		     const double* rowrng,
+		     const std::vector<std::string> & colnames,
+		     const std::vector<std::string> & rownames);
+
+    /** Pass in an array[getNumCols()] specifying if a variable is integer.
+
+	At present, simply coded as zero (continuous) and non-zero (integer)
+	May be extended at a later date.
+    */
+    void copyInIntegerInformation(const char * integerInformation);
+
+    /// Set problem name
+    void setProblemName(const char *name) ;
+
+    /// Set objective name
+    void setObjectiveName(const char *name) ;
+
+//@}
+
+/** @name Parameter set/get methods
+
+  Methods to set and retrieve MPS IO parameters.
+*/
+
+//@{
+    /// Set infinity
+    void setInfinity(double value);
+
+    /// Get infinity
+    double getInfinity() const;
+
+    /// Set default upper bound for integer variables
+    void setDefaultBound(int value);
+
+    /// Get default upper bound for integer variables
+    int getDefaultBound() const;
+    /// Whether to allow string elements
+    inline int allowStringElements() const
+    { return allowStringElements_;}
+    /// Whether to allow string elements (0 no, 1 yes, 2 yes and try flip)
+    inline void setAllowStringElements(int yesNo)
+    { allowStringElements_ = yesNo;}
+    /** Small element value - elements less than this set to zero on input
+        default is 1.0e-14 */
+    inline double getSmallElementValue() const
+    { return smallElement_;}
+    inline void setSmallElementValue(double value)
+    { smallElement_=value;} 
+//@}
+
+
+/** @name Methods for problem input and output
+
+  Methods to read and write MPS format problem files.
+   
+  The read and write methods return the number of errors that occurred during
+  the IO operation, or -1 if no file is opened.
+
+  \note
+  If the CoinMpsIO class was compiled with support for libz then
+  readMps will automatically try to append .gz to the file name and open it as
+  a compressed file if the specified file name cannot be opened.
+  (Automatic append of the .bz2 suffix when libbz is used is on the TODO list.)
+
+  \todo
+  Allow for file pointers and positioning
+*/
+
+//@{
+    /// Set the current file name for the CoinMpsIO object
+    void setFileName(const char * name);
+
+    /// Get the current file name for the CoinMpsIO object
+    const char * getFileName() const;
+
+    /** Read a problem in MPS format from the given filename.
+
+      Use "stdin" or "-" to read from stdin.
+    */
+    int readMps(const char *filename, const char *extension = "mps");
+
+    /** Read a problem in MPS format from the given filename.
+
+      Use "stdin" or "-" to read from stdin.
+      But do sets as well
+    */
+     int readMps(const char *filename, const char *extension ,
+        int & numberSets, CoinSet **& sets);
+
+    /** Read a problem in MPS format from a previously opened file
+
+      More precisely, read a problem using a CoinMpsCardReader object already
+      associated with this CoinMpsIO object.
+
+      \todo
+      Provide an interface that will allow a client to associate a
+      CoinMpsCardReader object with a CoinMpsIO object by setting the
+      cardReader_ field.
+    */
+    int readMps();
+    /// and
+    int readMps(int & numberSets, CoinSet **& sets);
+    /** Read a basis in MPS format from the given filename.
+	If VALUES on NAME card and solution not NULL fills in solution
+	status values as for CoinWarmStartBasis (but one per char)
+	-1 file error, 0 normal, 1 has solution values
+
+      Use "stdin" or "-" to read from stdin.
+
+      If sizes of names incorrect - read without names
+    */
+    int readBasis(const char *filename, const char *extension ,
+		  double * solution, unsigned char *rowStatus, unsigned char *columnStatus,
+		  const std::vector<std::string> & colnames,int numberColumns,
+		  const std::vector<std::string> & rownames, int numberRows);
+
+    /** Read a problem in GAMS format from the given filename.
+
+      Use "stdin" or "-" to read from stdin.
+      if convertObjective then massages objective column
+    */
+    int readGms(const char *filename, const char *extension = "gms",bool convertObjective=false);
+
+    /** Read a problem in GAMS format from the given filename.
+
+      Use "stdin" or "-" to read from stdin.
+      But do sets as well
+    */
+     int readGms(const char *filename, const char *extension ,
+        int & numberSets, CoinSet **& sets);
+
+    /** Read a problem in GAMS format from a previously opened file
+
+      More precisely, read a problem using a CoinMpsCardReader object already
+      associated with this CoinMpsIO object.
+
+    */
+    // Not for now int readGms();
+    /// and
+    int readGms(int & numberSets, CoinSet **& sets);
+    /** Read a problem in GMPL (subset of AMPL)  format from the given filenames.
+    */
+    int readGMPL(const char *modelName, const char * dataName=NULL, bool keepNames=false);
+
+    /** Write the problem in MPS format to a file with the given filename.
+
+	\param compression can be set to three values to indicate what kind
+	of file should be written
+	<ul>
+	  <li> 0: plain text (default)
+	  <li> 1: gzip compressed (.gz is appended to \c filename)
+	  <li> 2: bzip2 compressed (.bz2 is appended to \c filename) (TODO)
+	</ul>
+	If the library was not compiled with the requested compression then
+	writeMps falls back to writing a plain text file.
+
+	\param formatType specifies the precision to used for values in the
+	MPS file
+	<ul>
+	  <li> 0: normal precision (default)
+	  <li> 1: extra accuracy
+	  <li> 2: IEEE hex
+	</ul>
+
+	\param numberAcross specifies whether 1 or 2 (default) values should be
+	specified on every data line in the MPS file.
+
+	\param quadratic specifies quadratic objective to be output
+    */
+    int writeMps(const char *filename, int compression = 0,
+		 int formatType = 0, int numberAcross = 2,
+		 CoinPackedMatrix * quadratic = NULL,
+		 int numberSOS=0,const CoinSet * setInfo=NULL) const;
+
+    /// Return card reader object so can see what last card was e.g. QUADOBJ
+    inline const CoinMpsCardReader * reader() const
+    { return cardReader_;}
+  
+    /** Read in a quadratic objective from the given filename.
+
+      If filename is NULL (or the same as the currently open file) then
+      reading continues from the current file.
+      If not, the file is closed and the specified file is opened.
+      
+      Code should be added to
+      general MPS reader to read this if QSECTION
+      Data is assumed to be Q and objective is c + 1/2 xT Q x
+      No assumption is made for symmetry, positive definite, etc.
+      No check is made for duplicates or non-triangular if checkSymmetry==0.
+      If 1 checks lower triangular (so off diagonal should be 2*Q)
+      if 2 makes lower triangular and assumes full Q (but adds off diagonals)
+      
+      Arrays should be deleted by delete []
+
+      Returns number of errors:
+      <ul>
+	<li> -1: bad file
+	<li> -2: no Quadratic section
+	<li> -3: an empty section
+        <li> +n: then matching errors etc (symmetry forced)
+        <li> -4: no matching errors but fails triangular test
+		 (triangularity forced)
+      </ul>
+      columnStart is numberColumns+1 long, others numberNonZeros
+    */
+    int readQuadraticMps(const char * filename,
+			 int * &columnStart, int * &column, double * &elements,
+			 int checkSymmetry);
+
+    /** Read in a list of cones from the given filename.  
+
+      If filename is NULL (or the same as the currently open file) then
+      reading continues from the current file.
+      If not, the file is closed and the specified file is opened.
+
+      Code should be added to
+      general MPS reader to read this if CSECTION
+      No checking is done that in unique cone
+
+      Arrays should be deleted by delete []
+
+      Returns number of errors, -1 bad file, -2 no conic section,
+      -3 empty section
+
+      columnStart is numberCones+1 long, other number of columns in matrix
+
+	  coneType is 1 for QUAD, 2 for RQUAD (numberCones long)
+*/	
+	int readConicMps(const char * filename,
+			int * &columnStart, int * &column, int * &coneType, int & numberCones);
+    /// Set whether to move objective from matrix
+    inline void setConvertObjective(bool trueFalse)
+    { convertObjective_=trueFalse;}
+  /// copies in strings from a CoinModel - returns number
+  int copyStringElements(const CoinModel * model);
+  //@}
+
+/** @name Constructors and destructors */
+//@{
+    /// Default Constructor
+    CoinMpsIO(); 
+      
+    /// Copy constructor 
+    CoinMpsIO (const CoinMpsIO &);
+  
+    /// Assignment operator 
+    CoinMpsIO & operator=(const CoinMpsIO& rhs);
+  
+    /// Destructor 
+    ~CoinMpsIO ();
+//@}
+
+
+/**@name Message handling */
+//@{
+  /** Pass in Message handler
+  
+      Supply a custom message handler. It will not be destroyed when the
+      CoinMpsIO object is destroyed.
+  */
+  void passInMessageHandler(CoinMessageHandler * handler);
+
+  /// Set the language for messages.
+  void newLanguage(CoinMessages::Language language);
+
+  /// Set the language for messages.
+  inline void setLanguage(CoinMessages::Language language) {newLanguage(language);}
+
+  /// Return the message handler
+  inline CoinMessageHandler * messageHandler() const {return handler_;}
+
+  /// Return the messages
+  inline CoinMessages messages() {return messages_;}
+  /// Return the messages pointer
+  inline CoinMessages * messagesPointer() {return & messages_;}
+//@}
+
+
+/**@name Methods to release storage
+
+  These methods allow the client to reduce the storage used by the CoinMpsIO
+  object be selectively releasing unneeded problem information.
+*/
+//@{
+    /** Release all information which can be re-calculated.
+    
+	E.g., row sense, copies of rows, hash tables for names.
+    */
+    void releaseRedundantInformation();
+
+    /// Release all row information (lower, upper)
+    void releaseRowInformation();
+
+    /// Release all column information (lower, upper, objective)
+    void releaseColumnInformation();
+
+    /// Release integer information
+    void releaseIntegerInformation();
+
+    /// Release row names
+    void releaseRowNames();
+
+    /// Release column names
+    void releaseColumnNames();
+
+    /// Release matrix information
+    void releaseMatrixInformation();
+  //@}
+
+protected:
+  
+/**@name Miscellaneous helper functions */
+  //@{
+
+    /// Utility method used several times to implement public methods
+    void
+    setMpsDataWithoutRowAndColNames(
+		      const CoinPackedMatrix& m, const double infinity,
+		      const double* collb, const double* colub,
+		      const double* obj, const char* integrality,
+		      const double* rowlb, const double* rowub);
+    void
+    setMpsDataColAndRowNames(
+		      const std::vector<std::string> & colnames,
+		      const std::vector<std::string> & rownames);
+    void
+    setMpsDataColAndRowNames(
+		      char const * const * const colnames,
+		      char const * const * const rownames);
+
+  
+    /// Does the heavy lifting for destruct and assignment.
+    void gutsOfDestructor();
+
+    /// Does the heavy lifting for copy and assignment.
+    void gutsOfCopy(const CoinMpsIO &);
+  
+    /// Clears problem data from the CoinMpsIO object.
+    void freeAll();
+
+
+    /** A quick inlined function to convert from lb/ub style constraint
+	definition to sense/rhs/range style */
+    inline void
+    convertBoundToSense(const double lower, const double upper,
+			char& sense, double& right, double& range) const;
+    /** A quick inlined function to convert from sense/rhs/range stryle
+	constraint definition to lb/ub style */
+    inline void
+    convertSenseToBound(const char sense, const double right,
+			const double range,
+			double& lower, double& upper) const;
+
+  /** Deal with a filename
+  
+    As the name says.
+    Returns +1 if the file name is new, 0 if it's the same as before
+    (i.e., matches fileName_), and -1 if there's an error and the file
+    can't be opened.
+    Handles automatic append of .gz suffix when compiled with libz.
+
+    \todo
+    Add automatic append of .bz2 suffix when compiled with libbz.
+  */
+
+  int dealWithFileName(const char * filename,  const char * extension,
+		       CoinFileInput * &input); 
+  /** Add string to list
+      iRow==numberRows is objective, nr+1 is lo, nr+2 is up
+      iColumn==nc is rhs (can't cope with ranges at present)
+  */
+  void addString(int iRow,int iColumn, const char * value);
+  /// Decode string
+  void decodeString(int iString, int & iRow, int & iColumn, const char * & value) const;
+  //@}
+
+  
+  // for hashing
+  typedef struct {
+    int index, next;
+  } CoinHashLink;
+
+  /**@name Hash table methods */
+  //@{
+  /// Creates hash list for names (section = 0 for rows, 1 columns)
+  void startHash ( char **names, const int number , int section );
+  /// This one does it when names are already in
+  void startHash ( int section ) const;
+  /// Deletes hash storage
+  void stopHash ( int section );
+  /// Finds match using hash,  -1 not found
+  int findHash ( const char *name , int section ) const;
+  //@}
+
+    /**@name Cached problem information */
+    //@{
+      /// Problem name
+      char * problemName_;
+
+      /// Objective row name
+      char * objectiveName_;
+
+      /// Right-hand side vector name
+      char * rhsName_;
+
+      /// Range vector name
+      char * rangeName_;
+
+      /// Bounds vector name
+      char * boundName_;
+
+      /// Number of rows
+      int numberRows_;
+
+      /// Number of columns
+      int numberColumns_;
+
+      /// Number of coefficients
+      CoinBigIndex numberElements_;
+
+      /// Pointer to dense vector of row sense indicators
+      mutable char    *rowsense_;
+  
+      /// Pointer to dense vector of row right-hand side values
+      mutable double  *rhs_;
+  
+      /** Pointer to dense vector of slack variable upper bounds for range 
+          constraints (undefined for non-range rows)
+      */
+      mutable double  *rowrange_;
+   
+      /// Pointer to row-wise copy of problem matrix coefficients.
+      mutable CoinPackedMatrix *matrixByRow_;  
+
+      /// Pointer to column-wise copy of problem matrix coefficients.
+      CoinPackedMatrix *matrixByColumn_;  
+
+      /// Pointer to dense vector of row lower bounds
+      double * rowlower_;
+
+      /// Pointer to dense vector of row upper bounds
+      double * rowupper_;
+
+      /// Pointer to dense vector of column lower bounds
+      double * collower_;
+
+      /// Pointer to dense vector of column upper bounds
+      double * colupper_;
+
+      /// Pointer to dense vector of objective coefficients
+      double * objective_;
+
+      /// Constant offset for objective value (i.e., RHS value for OBJ row)
+      double objectiveOffset_;
+
+
+      /** Pointer to dense vector specifying if a variable is continuous
+	  (0) or integer (1).
+      */
+      char * integerType_;
+
+      /** Row and column names
+	  Linked to hash table sections (0 - row names, 1 column names)
+      */
+      char **names_[2];
+    //@}
+
+    /** @name Hash tables */
+    //@{
+      /// Current file name
+      char * fileName_;
+
+      /// Number of entries in a hash table section
+      int numberHash_[2];
+
+      /// Hash tables (two sections, 0 - row names, 1 - column names)
+      mutable CoinHashLink *hash_[2];
+    //@}
+
+    /** @name CoinMpsIO object parameters */
+    //@{
+      /// Upper bound when no bounds for integers
+      int defaultBound_; 
+
+      /// Value to use for infinity
+      double infinity_;
+      /// Small element value
+      double smallElement_;
+
+      /// Message handler
+      CoinMessageHandler * handler_;
+      /** Flag to say if the message handler is the default handler.
+
+          If true, the handler will be destroyed when the CoinMpsIO
+	  object is destroyed; if false, it will not be destroyed.
+      */
+      bool defaultHandler_;
+      /// Messages
+      CoinMessages messages_;
+      /// Card reader
+      CoinMpsCardReader * cardReader_;
+      /// If .gms file should it be massaged to move objective
+      bool convertObjective_;
+      /// Whether to allow string elements
+      int allowStringElements_;
+      /// Maximum number of string elements
+      int maximumStringElements_;
+      /// Number of string elements
+      int numberStringElements_;
+      /// String elements
+      char ** stringElements_;
+    //@}
+
+};
+
+//#############################################################################
+/** A function that tests the methods in the CoinMpsIO class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. Also, if this method is compiled with
+    optimization, the compilation takes 10-15 minutes and the machine pages
+    (has 256M core memory!)... */
+void
+CoinMpsIOUnitTest(const std::string & mpsDir);
+// Function to return number in most efficient way
+// section is 0 for columns, 1 for rhs,ranges and 2 for bounds
+/* formatType is
+   0 - normal and 8 character names
+   1 - extra accuracy
+   2 - IEEE hex - INTEL
+   3 - IEEE hex - not INTEL
+*/
+void
+CoinConvertDouble(int section, int formatType, double value, char outputValue[24]);
+
+#endif
+
diff --git a/cbits/coin/CoinOslC.h b/cbits/coin/CoinOslC.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinOslC.h
@@ -0,0 +1,873 @@
+/* $Id: CoinOslC.h 1585 2013-04-06 20:42:02Z stefan $ */
+#ifndef COIN_OSL_C_INCLUDE
+/*
+  Copyright (C) 1987, 2009, International Business Machines Corporation
+  and others.  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+#define COIN_OSL_C_INCLUDE
+
+#ifndef CLP_OSL
+#define CLP_OSL 0
+#endif
+#define C_EKK_GO_SPARSE 200
+
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define INTEL
+#endif
+#endif
+
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define SPARSE_UPDATE
+#define NO_SHIFT
+#include "CoinHelperFunctions.hpp"
+
+#include <stddef.h>
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+int c_ekkbtrn( register const EKKfactinfo *fact,
+	    double *dwork1,
+	    int * mpt,int first_nonzero);
+int c_ekkbtrn_ipivrw( register const EKKfactinfo *fact,
+		   double *dwork1,
+		   int * mpt, int ipivrw,int * spare);
+
+int c_ekketsj( register /*const*/ EKKfactinfo *fact,
+	    double *dwork1,
+	    int *mpt2, double dalpha, int orig_nincol,
+	    int npivot, int *nuspikp,
+	    const int ipivrw, int * spare);
+int c_ekkftrn( register const EKKfactinfo *fact, 
+	    double *dwork1,
+	    double * dpermu,int * mpt, int numberNonZero);
+
+int c_ekkftrn_ft( register EKKfactinfo *fact, 
+	       double *dwork1, int *mpt, int *nincolp);
+void c_ekkftrn2( register EKKfactinfo *fact, double *dwork1,
+	      double * dpermu1,int * mpt1, int *nincolp,
+	     double *dwork1_ft, int *mpt_ft, int *nincolp_ft);
+
+int c_ekklfct( register EKKfactinfo *fact);
+int c_ekkslcf( register const EKKfactinfo *fact);
+inline void c_ekkscpy(int n, const int *marr1,int *marr2)
+{ CoinMemcpyN(marr1,n,marr2);} 
+inline void c_ekkdcpy(int n, const double *marr1,double *marr2)
+{ CoinMemcpyN(marr1,n,marr2);} 
+int c_ekk_IsSet(const int * array,int bit);
+void c_ekk_Set(int * array,int bit);
+void c_ekk_Unset(int * array,int bit);
+
+void c_ekkzero(int length, int n, void * array);
+inline void c_ekkdzero(int n, double *marray)
+{CoinZeroN(marray,n);}
+inline void c_ekkizero(int n, int *marray)
+{CoinZeroN(marray,n);}
+inline void c_ekkczero(int n, char *marray)
+{CoinZeroN(marray,n);}
+#ifdef __cplusplus
+          }
+#endif
+ 
+#define c_ekkscpy_0_1(s,ival,array) CoinFillN(array,s,ival)
+#define c_ekks1cpy( n,marr1,marr2)  CoinMemcpyN(marr1,n, marr2)
+void clp_setup_pointers(EKKfactinfo * fact);
+void clp_memory(int type);
+double * clp_double(int number_entries);
+int * clp_int(int number_entries);
+void * clp_malloc(int number_entries);
+void clp_free(void * oldArray);
+
+#define SLACK_VALUE -1.0
+#define	C_EKK_REMOVE_LINK(hpiv,hin,link,ipivot)	\
+  {						\
+    int ipre = link[ipivot].pre;		\
+    int isuc = link[ipivot].suc;		\
+    if (ipre > 0) {				\
+      link[ipre].suc = isuc;			\
+    }						\
+    if (ipre <= 0) {				\
+      hpiv[hin[ipivot]] = isuc;			\
+    }						\
+    if (isuc > 0) {				\
+      link[isuc].pre = ipre;			\
+    }						\
+  }
+
+#define	C_EKK_ADD_LINK(hpiv,nzi,link, npr)	\
+  {						\
+    int ifiri = hpiv[nzi];			\
+    hpiv[nzi] = npr;				\
+    link[npr].suc = ifiri;			\
+    link[npr].pre = 0;				\
+    if (ifiri != 0) {				\
+      link[ifiri].pre = npr;			\
+    }						\
+  }
+#include <assert.h>
+#ifdef	NO_SHIFT
+
+#define	SHIFT_INDEX(limit)	(limit)
+#define	UNSHIFT_INDEX(limit)	(limit)
+#define	SHIFT_REF(arr,ind)	(arr)[ind]
+
+#else
+
+#define	SHIFT_INDEX(limit)	((limit)<<3)
+#define	UNSHIFT_INDEX(limit)	((unsigned int)(limit)>>3)
+#define	SHIFT_REF(arr,ind)	(*(double*)((char*)(arr) + (ind)))
+
+#endif
+
+#ifdef INTEL
+#define	NOT_ZERO(x)	(((*((reinterpret_cast<unsigned char *>(&x))+7)) & 0x7F) != 0)
+#else
+#define	NOT_ZERO(x)	((x) != 0.0)
+#endif
+
+#define	SWAP(type,_x,_y)	{ type _tmp = (_x); (_x) = (_y); (_y) = _tmp;}
+
+#define	UNROLL_LOOP_BODY1(code)			\
+  {{code}}
+#define	UNROLL_LOOP_BODY2(code)			\
+  {{code} {code}}
+#define	UNROLL_LOOP_BODY4(code)			\
+  {{code} {code} {code} {code}}
+#endif
+#ifdef COIN_OSL_CMFC
+/*     Return codes in IRTCOD/IRTCOD are */
+/*     4: numerical problems */
+/*     5: not enough space in row file */
+/*     6: not enough space in column file */
+/*    23: system error at label 320 */
+{
+#if 1
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  int nnentl	= fact->nnentl;
+  int nnentu	= fact->nnentu;
+  int kmxeta	= fact->kmxeta;
+  int xnewro	= *xnewrop;
+  int ncompactions	= *ncompactionsp;
+
+  MACTION_T *maction = reinterpret_cast<MACTION_T*>(maction_void);
+
+  int i, j, k;
+  double d1;
+  int j1, j2;
+  int jj, kk, kr, nz, jj1, jj2, kce, kcs, kqq, npr;
+  int fill, naft;
+  int enpr;
+  int nres, npre;
+  int knpr, irow, iadd32, ibase;
+  double pivot;
+  int count, nznpr;
+  int nlast, epivr1;
+  int kipis;
+  double dpivx;
+  int kipie, kcpiv, knprs, knpre;
+  bool cancel;
+  double multip, elemnt;
+  int ipivot, jpivot, epivro, epivco, lstart, nfirst;
+  int nzpivj, kfill, kstart;
+  int nmove, ileft;
+#ifndef C_EKKCMFY
+  int iput, nspare;
+  int noRoomForDense=0;
+  int if_sparse_update=fact->if_sparse_update;
+  int ifdens = 0;
+#endif
+  int irtcod	= 0;
+  const int nrow	= fact->nrow;
+
+  /* Parameter adjustments */
+  --maction;
+
+  /* Function Body */
+  lstart = nnetas - nnentl + 1;
+  for (i = lstart; i <= nnetas; ++i) {
+      hrowi[i] = SHIFT_INDEX(hcoli[i]);
+  }
+
+  for (i = 1; i <= nrow; ++i) {
+    maction[i] = 0;
+    mwork[i].pre = i - 1;
+    mwork[i].suc = i + 1;
+  }
+
+  iadd32 = 0;
+  nlast = nrow;
+  nfirst = 1;
+  mwork[1].pre = nrow;
+  mwork[nrow].suc = 1;
+
+  for (count = 1; count <= nrow; ++count) {
+
+    /* Pick column singletons */
+    if (! (hpivco[1] <= 0)) {
+      int small_pivot = c_ekkcsin(fact,
+				 rlink, clink,
+				    nsingp);
+
+      if (small_pivot) {
+	irtcod = 7; /* pivot too small */
+	if (fact->invok >= 0) {
+	  goto L1050;
+	}
+      }
+      if (fact->npivots >= nrow) {
+	goto L1050;
+      }
+    }
+
+    /* Pick row singletons */
+    if (! (hpivro[1] <= 0)) {
+      irtcod = c_ekkrsin(fact,
+			 rlink, clink,
+			 mwork,nfirst,
+			 nsingp,
+			 
+		     &xnewco, &xnewro,
+		     &nnentu,
+		     &kmxeta, &ncompactions,
+			 &nnentl);
+	if (irtcod != 0) {
+	  if (irtcod < 0 || fact->invok >= 0) {
+	    /* -5 */
+	    goto L1050;
+	  }
+	  /* ASSERT:  irtcod == 7 - pivot too small */
+	  /* why don't we return with an error? */	    
+	}
+	if (fact->npivots >= nrow) {
+	    goto L1050;
+	}
+	lstart = nnetas - nnentl + 1;
+    }
+
+    /* Find a pivot element */
+    irtcod = c_ekkfpvt(fact,
+		      rlink, clink,
+		     nsingp, xrejctp, &ipivot, &jpivot);
+    if (irtcod != 0) {
+      /* irtcod == 10 */
+	goto L1050;
+    }
+    /*        Update list structures and prepare for numerical phase */
+    c_ekkprpv(fact, rlink, clink,
+		     *xrejctp, ipivot, jpivot);
+
+    epivco = hincol[jpivot];
+    ++fact->xnetal;
+    mcstrt[fact->xnetal] = lstart - 1;
+    hpivco[fact->xnetal] = ipivot;
+    epivro = hinrow[ipivot];
+    epivr1 = epivro - 1;
+    kipis = mrstrt[ipivot];
+    pivot = dluval[kipis];
+    dpivx = 1. / pivot;
+    kipie = kipis + epivr1;
+    ++kipis;
+#ifndef	C_EKKCMFY
+    {
+      double size = nrow - fact->npivots;
+      if (size > GO_DENSE && (nnentu - fact->nuspike) * GO_DENSE_RATIO > size * size) {
+	/* say going to dense coding */
+	if (*nsingp == 0) {
+	  ifdens = 1;
+	}
+      }
+    }
+#endif
+    /* copy the pivot row entries into dvalpv */
+    /* the maction array tells us the index into dvalpv for a given row */
+    /* the alternative would be using a large array of doubles */
+    for (k = kipis; k <= kipie; ++k) {
+      irow = hcoli[k];
+      dvalpv[k - kipis + 1] = dluval[k];
+      maction[irow] = static_cast<MACTION_T>(k - kipis + 1);
+    }
+
+    /* Loop over nonzeros in pivot column */
+    kcpiv = mcstrt[jpivot] - 1;
+    for (nzpivj = 1; nzpivj <= epivco; ++nzpivj) {
+      ++kcpiv;
+      npr = hrowi[kcpiv];
+      hrowi[kcpiv] = 0;	/* zero out for possible compaction later on */
+
+      --hincol[jpivot];
+
+      ++mcstrt[jpivot];
+      /* loop invariant:  kcpiv == mcstrt[jpivot] - 1 */
+
+      --hinrow[npr];
+      enpr = hinrow[npr];
+      knprs = mrstrt[npr];
+      knpre = knprs + enpr;
+
+      /* Search for element to be eliminated */
+      knpr = knprs;
+      while (1) {
+	  UNROLL_LOOP_BODY4({
+	    if (jpivot == hcoli[knpr]) {
+	      break;
+	    }
+	    knpr++;
+	  });
+      }
+
+      multip = -dluval[knpr] * dpivx;
+
+      /* swap last entry with pivot */
+      dluval[knpr] = dluval[knpre];
+      hcoli[knpr] = hcoli[knpre];
+      --knpre;
+
+#if	1
+      /* MONSTER_UNROLLED_CODE - see below */
+      kfill = epivr1 - (knpre - knprs + 1);
+      nres = ((knpre - knprs + 1) & 1) + knprs;
+      cancel = false;
+      d1 = 1e33;
+      j1 = hcoli[nres];
+
+      if (nres != knprs) {
+	j = hcoli[knprs];
+	if (maction[j] == 0) {
+	  ++kfill;
+	} else {
+	  jj = maction[j];
+	  maction[j] = static_cast<MACTION_T>(-maction[j]);
+	  dluval[knprs] += multip * dvalpv[jj];
+	  d1 = fabs(dluval[knprs]);
+	}
+      }
+      j2 = hcoli[nres + 1];
+      jj1 = maction[j1];
+      for (kr = nres; kr < knpre; kr += 2) {
+	jj2 = maction[j2];
+	if ( (jj1 == 0)) {
+	  ++kfill;
+	} else {
+	  maction[j1] = static_cast<MACTION_T>(-maction[j1]);
+	  dluval[kr] += multip * dvalpv[jj1];
+	  cancel = cancel || ! (fact->zeroTolerance < d1);
+	  d1 = fabs(dluval[kr]);
+	}
+	j1 = hcoli[kr + 2];
+	if ( (jj2 == 0)) {
+	  ++kfill;
+	} else {
+	  maction[j2] = static_cast<MACTION_T>(-maction[j2]);
+	  dluval[kr + 1] += multip * dvalpv[jj2];
+	  cancel = cancel || ! (fact->zeroTolerance < d1);
+	  d1 = fabs(dluval[kr + 1]);
+	}
+	jj1 = maction[j1];
+	j2 = hcoli[kr + 3];
+      }
+      cancel = cancel || ! (fact->zeroTolerance < d1);
+#else
+      /*
+       * This is apparently what the above code does.
+       * In addition to being unrolled, the assignments to j[12] and jj[12]
+       * are shifted so that the result of dereferencing maction doesn't
+       * have to be used immediately afterwards for the branch test.
+       * This would would cause a pipeline delay.  (The apparent dereference
+       * of hcoli will be removed by the compiler using strength reduction).
+       *
+       * loop through the entries in the row being processed,
+       * flipping the sign of the maction entries as we go along.
+       * Afterwards, we look for positive entries to see what pivot
+       * row entries will cause fill-in.  We count the number of fill-ins, too.
+       * "cancel" says if the result of combining the pivot row with this one
+       * causes an entry to get too small; if so, we discard those entries.
+       */
+      kfill = epivr1 - (knpre - knprs + 1);
+      cancel = false;
+
+      for (kr = knprs; kr <= knpre; kr++) {
+	j1 = hcoli[kr];
+	jj1 = maction[j1];
+	if ( (jj1 == 0)) {
+	  /* no entry - this pivot column entry will have to be added */
+	  ++kfill;
+	} else {
+	  /* there is an entry for this column in the pivot row */
+	  maction[j1] = -maction[j1];
+	  dluval[kr] += multip * dvalpv[jj1];
+	  d1 = fabs(dluval[kr]);
+	  cancel = cancel || ! (fact->zeroTolerance < d1);
+	}
+      }
+#endif
+      kstart = knpre;
+      fill = kfill;
+      
+      if (cancel) {
+	/* KSTART is used as a stack pointer for nonzeros in factored row */
+	kstart = knprs - 1;
+	for (kr = knprs; kr <= knpre; ++kr) {
+	  j = hcoli[kr];
+	  if (fabs(dluval[kr]) > fact->zeroTolerance) {
+	    ++kstart;
+	    dluval[kstart] = dluval[kr];
+	    hcoli[kstart] = j;
+	  } else {
+	    /* Remove element from column file */
+	    --nnentu;
+	    --hincol[j];
+	    --enpr;
+	    kcs = mcstrt[j];
+	    kce = kcs + hincol[j];
+	    for (kk = kcs; kk <= kce; ++kk) {
+	      if (hrowi[kk] == npr) {
+		hrowi[kk] = hrowi[kce];
+		hrowi[kce] = 0;
+		break;
+	      }
+	    }
+	    /* ASSERT !(kk>kce) */
+	  }
+	}
+	knpre = kstart;
+      }
+      /* Fill contains an upper bound on the amount of fill-in */
+      if (fill == 0) {
+	for (k = kipis; k <= kipie; ++k) {
+	  maction[hcoli[k]] = static_cast<MACTION_T>(-maction[hcoli[k]]);
+	}
+      }
+      else {
+	naft = mwork[npr].suc;
+	kqq = mrstrt[naft] - knpre - 1;
+	
+	if (fill > kqq) {
+	  /* Fill-in exceeds space left. Check if there is enough */
+	  /* space in row file for the new row. */
+	  nznpr = enpr + fill;
+	  if (! (xnewro + nznpr + 1 < lstart)) {
+	    if (! (nnentu + nznpr + 1 < lstart)) {
+	      irtcod = -5;
+	      goto L1050;
+	    }
+	    /* idea 1 is to compress every time xnewro increases by x thousand */
+	    /* idea 2 is to copy nucleus rows with a reasonable gap */
+	    /* then copy each row down when used */
+	    /* compressions would just be 1 remainder which eventually will */
+	    /* fit in cache */
+	    {
+	      int iput = c_ekkrwcs(fact,dluval, hcoli, mrstrt, hinrow, mwork, nfirst);
+	      kmxeta += xnewro - iput ;
+	      xnewro = iput - 1;
+	      ++ncompactions;
+	    }
+	    
+	    kipis = mrstrt[ipivot] + 1;
+	    kipie = kipis + epivr1 - 1;
+	    knprs = mrstrt[npr];
+	  }
+	  
+	  /* I think this assignment should be inside the previous if-stmt */
+	  /* otherwise, it does nothing */
+	  /*assert(knpre == knprs + enpr - 1);*/
+	  knpre = knprs + enpr - 1; 
+	  
+	  /*
+	   * copy this row to the end of the row file and adjust its links.
+	   * The links keep track of the order of rows in memory.
+	   * Rows are only moved from the middle all the way to the end.
+	   */
+	  if (npr != nlast) {
+	    npre = mwork[npr].pre;
+	    if (npr == nfirst) {
+	      nfirst = naft;
+	    }
+	    /*             take out of chain */
+	    mwork[naft].pre = npre;
+	    mwork[npre].suc = naft;
+	    /*             and put in at end */
+	    mwork[nfirst].pre = npr;
+	    mwork[nlast].suc = npr;
+	    mwork[npr].pre = nlast;
+	    mwork[npr].suc = nfirst;
+	    nlast = npr;
+	    kstart = xnewro;
+	    mrstrt[npr] = kstart + 1;
+	    nmove = knpre - knprs + 1;
+	    ibase = kstart + 1 - knprs;
+	    for (kr = knprs; kr <= knpre; ++kr) {
+	      dluval[ibase + kr] = dluval[kr];
+	      hcoli[ibase + kr] = hcoli[kr];
+	    }
+	    kstart += nmove;
+	  } else {
+	    kstart = knpre;
+	  }
+	  
+	  /* extra space ? */
+	  /*
+	   * The mystery of iadd32.
+	   * This code assigns to xnewro, possibly using iadd32.
+	   * However, in that case xnewro is assigned to just after
+	   * the for-loop below, and there is no intervening reference.
+	   * Therefore, I believe that this code can be entirely eliminated;
+	   * it is the leftover of an interrupted or dropped experiment.
+	   * Presumably, this was trying to implement the ideas about
+	   * padding expressed above.
+	   */
+	  if (iadd32 != 0) {
+	    xnewro += iadd32;
+	  } else {
+	    if (kstart + (nrow << 1) + 100 < lstart) {
+	      ileft = ((nrow - fact->npivots + 32) & -32);
+	      if (kstart + ileft * ileft + 32 < lstart) {
+		iadd32 = ileft;
+		xnewro = CoinMax(kstart,xnewro);
+		xnewro = (xnewro & -32) + ileft;
+	      } else {
+		xnewro = ((kstart + 31) & -32);
+	      }
+	    } else {
+	      xnewro = kstart;
+	    }
+	  }
+	  
+	  hinrow[npr] = enpr;
+	} else if (! (nnentu + kqq + 2 < lstart)) {
+	  irtcod = -5;
+	  goto L1050;
+	}
+	/* Scan pivot row again to generate fill in. */
+	for (kr = kipis; kr <= kipie; ++kr) {
+	  j = hcoli[kr];
+	  jj = maction[j];
+	  if (jj >0) {
+	    elemnt = multip * dvalpv[jj];
+	    if (fabs(elemnt) > fact->zeroTolerance) {
+	      ++kstart;
+	      dluval[kstart] = elemnt;
+	      //printf("pivot %d at %d col %d el %g\n",
+	      // npr,kstart,j,elemnt);
+	      hcoli[kstart] = j;
+	      ++nnentu;
+	      nz = hincol[j];
+	      kcs = mcstrt[j];
+	      kce = kcs + nz - 1;
+	      if (kce == xnewco) {
+		if (xnewco + 1 >= lstart) {
+		  if (xnewco + nz + 1 >= lstart) {
+		    /*                  Compress column file */
+		    if (nnentu + nz + 1 < lstart) {
+		      xnewco = c_ekkclco(fact,hrowi, mcstrt, hincol, xnewco);
+		      ++ncompactions;
+		      
+		      kcpiv = mcstrt[jpivot] - 1;
+		      kcs = mcstrt[j];
+		      /*                  HINCOL MAY HAVE CHANGED? (JJHF) ??? */
+		      nz = hincol[j];
+		      kce = kcs + nz - 1;
+		    } else {
+		      irtcod = -5;
+		      goto L1050;
+		    }
+		  }
+		  /*              Copy column */
+		  mcstrt[j] = xnewco + 1;
+		  ibase = mcstrt[j] - kcs;
+		  for (kk = kcs; kk <= kce; ++kk) {
+		    hrowi[ibase + kk] = hrowi[kk];
+		    hrowi[kk] = 0;
+		  }
+		  kce = xnewco + kce - kcs + 1;
+		  xnewco = kce + 1;
+		} else {
+		  ++xnewco;
+		}
+	      } else if (hrowi[kce + 1] != 0) {
+		/* here we use the fact that hrowi entries not "in use" are zeroed */
+		if (xnewco + nz + 1 >= lstart) {
+		  /* Compress column file */
+		  if (nnentu + nz + 1 < lstart) {
+		    xnewco = c_ekkclco(fact,hrowi, mcstrt, hincol, xnewco);
+		    ++ncompactions;
+		    
+		    kcpiv = mcstrt[jpivot] - 1;
+		    kcs = mcstrt[j];
+		    /*                  HINCOL MAY HAVE CHANGED? (JJHF) ??? */
+		    nz = hincol[j];
+		    kce = kcs + nz - 1;
+		  } else {
+		    irtcod = -5;
+		    goto L1050;
+		  }
+		}
+		/* move the column to the end of the column file */
+		mcstrt[j] = xnewco + 1;
+		ibase = mcstrt[j] - kcs;
+		for (kk = kcs; kk <= kce; ++kk) {
+		  hrowi[ibase + kk] = hrowi[kk];
+		  hrowi[kk] = 0;
+		}
+		kce = xnewco + kce - kcs + 1;
+		xnewco = kce + 1;
+	      }
+	      /* store element */
+	      hrowi[kce + 1] = npr;
+	      hincol[j] = nz + 1;
+	    }
+	  } else {
+	    maction[j] = static_cast<MACTION_T>(-maction[j]);
+	  }
+	}
+	if (fill > kqq) {
+	  xnewro = kstart;
+	}
+      }
+      hinrow[npr] = kstart - mrstrt[npr] + 1;
+      /* Check if row or column file needs compression */
+      if (! (xnewco + 1 < lstart)) {
+	xnewco = c_ekkclco(fact,hrowi, mcstrt, hincol, xnewco);
+	++ncompactions;
+	
+	kcpiv = mcstrt[jpivot] - 1;
+      }
+      if (! (xnewro + 1 < lstart)) {
+	int iput = c_ekkrwcs(fact,dluval, hcoli, mrstrt, hinrow, mwork, nfirst);
+	kmxeta += xnewro - iput ;
+	xnewro = iput - 1;
+	++ncompactions;
+	
+	kipis = mrstrt[ipivot] + 1;
+	kipie = kipis + epivr1 - 1;
+      }
+      /* Store elementary row transformation */
+      ++nnentl;
+      --nnentu;
+      --lstart;
+      dluval[lstart] = multip;
+      
+      hrowi[lstart] = SHIFT_INDEX(npr);
+#define INLINE_AFPV 3
+      /* We could do this while computing values but
+	 it makes it much more complex.  At least we should get
+	 reasonable cache behavior by doing it each row */
+#if INLINE_AFPV
+      {
+	int j;
+	int nel, krs;
+	int koff;
+	int * index;
+	double * els;
+	nel = hinrow[npr];
+	krs = mrstrt[npr];
+	index=&hcoli[krs];
+	els=&dluval[krs];
+#if INLINE_AFPV<3
+#if INLINE_AFPV==1
+	double maxaij = 0.0;
+	koff = 0;
+	j=0;
+	while (j<nel) {
+	  double d = fabs(els[j]);
+	  if (maxaij < d) {
+	    maxaij = d;
+	    koff=j;
+	  }
+	  j++;
+	}
+#else
+	assert (nel);
+	koff=0;
+	double maxaij=fabs(els[0]);
+	for (j=1;j<nel;j++) {
+	  double d = fabs(els[j]);
+	  if (maxaij < d) {
+	    maxaij = d;
+	    koff=j;
+	  }
+	}
+#endif
+#else
+	double maxaij = 0.0;
+	koff = 0;
+	j=0;
+	if ((nel&1)!=0) {
+	  maxaij=fabs(els[0]);
+	  j=1;
+	}
+	
+	while (j<nel) {
+	  UNROLL_LOOP_BODY2({
+	      double d = fabs(els[j]);
+	      if (maxaij < d) {
+		maxaij = d;
+		koff=j;
+	      }
+	      j++;
+	    });
+	}
+#endif
+	SWAP(int, index[koff], index[0]);
+	SWAP(double, els[koff], els[0]);
+      }
+#endif
+
+      {
+	int nzi = hinrow[npr];
+	if (nzi > 0) {
+	  C_EKK_ADD_LINK(hpivro, nzi, rlink, npr);
+	}
+      }
+    }
+
+    /* after pivot move biggest to first in each row */
+#if INLINE_AFPV==0
+    int nn = mcstrt[fact->xnetal] - lstart + 1;
+    c_ekkafpv(hrowi+lstart, hcoli, dluval, mrstrt, hinrow, nn);
+#endif
+
+    /* Restore work array */
+    for (k = kipis; k <= kipie; ++k) {
+      maction[hcoli[k]] = 0;
+    }
+
+    if (*xrejctp > 0) {
+      for (k = kipis; k <= kipie; ++k) {
+	int j = hcoli[k];
+	int nzj = hincol[j];
+	if (! (nzj <= 0) &&
+	    ! ((clink[j].pre > nrow && nzj != 1))) {
+	  C_EKK_ADD_LINK(hpivco, nzj, clink, j);
+	}
+      }
+    } else {
+      for (k = kipis; k <= kipie; ++k) {
+	int j = hcoli[k];
+	int nzj = hincol[j];
+	if (! (nzj <= 0)) {
+	  C_EKK_ADD_LINK(hpivco, nzj, clink, j);
+	}
+      }
+    }
+    fact->nuspike += hinrow[ipivot];
+
+    /* Go to dense coding if appropriate */
+#ifndef	C_EKKCMFY
+    if (ifdens != 0) {
+      int ndense = nrow - fact->npivots;
+      if (! (xnewro + ndense * ndense >= lstart)) {
+
+	/* set up sort order in MACTION */
+	c_ekkizero( nrow, reinterpret_cast<int *> (maction+1));
+	iput = 0;
+	for (i = 1; i <= nrow; ++i) {
+	  if (clink[i].pre >= 0) {
+	    ++iput;
+	    maction[i] = static_cast<short int>(iput);
+	  }
+	}
+	/* and get number spare needed */
+	nspare = 0;
+	for (i = 1; i <= nrow; ++i) {
+	  if (rlink[i].pre >= 0) {
+	    nspare = nspare + ndense - hinrow[i];
+	  }
+	}
+	if (iput != nrow - fact->npivots) {
+	  /* must be singular */
+	  c_ekkizero( nrow, reinterpret_cast<int *> (maction+1));
+	} else {
+	  /* pack down then back up */
+	  int iput = c_ekkrwcs(fact,dluval, hcoli, mrstrt, hinrow, mwork, nfirst);
+	  kmxeta += xnewro - iput ;
+	  xnewro = iput - 1;
+	  ++ncompactions;
+	  
+	  --ncompactions;
+	  if (xnewro + nspare + ndense * ndense >= lstart) {
+	    c_ekkizero( nrow, reinterpret_cast<int *> (maction+1));
+	  }
+	  else {
+	    xnewro += nspare;
+	    c_ekkrwct(fact,dluval, hcoli, mrstrt, hinrow, mwork,
+		    rlink, maction, dvalpv,
+		    nlast,  xnewro);
+	    kmxeta += xnewro ;
+	    if (nnentu + nnentl > nrow * 5 &&
+		(ndense*ndense)>(nnentu+nnentl)>>2 &&
+		!if_sparse_update) {
+	      fact->ndenuc = ndense;
+	    }
+	    irtcod = c_ekkcmfd(fact,
+			     (reinterpret_cast<int*>(dvalpv)+1),
+			     rlink, clink,
+			     (reinterpret_cast<int*>(maction+1))+1,
+			     nnetas,
+			     &nnentl, &nnentu,
+			     nsingp);
+	    /* irtcod == 0 || irtcod == 10 */
+	    /* 10 == found 0.0 pivot */
+	    goto L1050;
+	  }
+	}
+      } else {
+	/* say not enough room */
+	/*printf("no room %d\n",ndense);*/
+	if (1) {
+	  /* return and increase size of etas if possible */
+	  if (!noRoomForDense) {
+	    int etasize =CoinMax(4*fact->nnentu+(nnetas-fact->nnentl)+1000,fact->eta_size);
+	    noRoomForDense=ndense;
+	    fact->eta_size=CoinMin(static_cast<int>(1.2*fact->eta_size),etasize);
+	    if (fact->maxNNetas>0&&fact->eta_size>
+		fact->maxNNetas) {
+	      fact->eta_size=fact->maxNNetas;
+	    }
+	  }
+	}
+      }
+    }
+#endif	/* C_EKKCMFY */
+  }
+
+ L1050:
+  {
+    int iput = c_ekkrwcs(fact,dluval, hcoli, mrstrt, hinrow, mwork, nfirst);
+    kmxeta += xnewro - iput;
+    xnewro = iput - 1;
+    ++ncompactions;
+  }
+
+  nnentu = xnewro;
+  /* save order of row copy for c_ekkshfv */
+  mwork[nrow+1].pre = nfirst;
+  mwork[nrow+1].suc = nlast;
+
+  fact->nnentl = nnentl;
+  fact->nnentu = nnentu;
+  fact->kmxeta = kmxeta;
+  *xnewrop = xnewro;
+  *ncompactionsp = ncompactions;
+
+  return (irtcod);
+} /* c_ekkcmfc */
+#endif
+
diff --git a/cbits/coin/CoinOslFactorization.cpp b/cbits/coin/CoinOslFactorization.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinOslFactorization.cpp
@@ -0,0 +1,1501 @@
+/* $Id: CoinOslFactorization.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+// Copyright (C) 1987, 2009, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinUtilsConfig.h"
+
+#include <cassert>
+#include "CoinPragma.hpp"
+#include "CoinOslFactorization.hpp"
+#include "CoinOslC.h"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinTypes.hpp"
+#include "CoinFinite.hpp"
+#include <stdio.h>
+static void c_ekksmem(EKKfactinfo *fact,int numberRows,int maximumPivots);
+static void c_ekksmem_copy(EKKfactinfo *fact,const EKKfactinfo * rhsFact);
+static void c_ekksmem_delete(EKKfactinfo *fact);
+//:class CoinOslFactorization.  Deals with Factorization and Updates
+//  CoinOslFactorization.  Constructor
+CoinOslFactorization::CoinOslFactorization (  )
+  : CoinOtherFactorization()
+{
+  gutsOfInitialize();
+}
+
+/// Copy constructor 
+CoinOslFactorization::CoinOslFactorization ( const CoinOslFactorization &other)
+  : CoinOtherFactorization(other)
+{
+  gutsOfInitialize();
+  gutsOfCopy(other);
+}
+// Clone
+CoinOtherFactorization * 
+CoinOslFactorization::clone() const 
+{
+  return new CoinOslFactorization(*this);
+}
+/// The real work of constructors etc
+void CoinOslFactorization::gutsOfDestructor(bool clearFact)
+{
+  delete [] elements_;
+  delete [] pivotRow_;
+  delete [] workArea_;
+  elements_ = NULL;
+  pivotRow_ = NULL;
+  workArea_ = NULL;
+  numberRows_ = 0;
+  numberColumns_ = 0;
+  numberGoodU_ = 0;
+  status_ = -1;
+  maximumRows_=0;
+  maximumSpace_=0;
+  solveMode_=0;
+  if (clearFact)
+    c_ekksmem_delete(&factInfo_);
+}
+void CoinOslFactorization::gutsOfInitialize(bool zapFact)
+{
+  pivotTolerance_ = 1.0e-1;
+  zeroTolerance_ = 1.0e-13;
+#ifndef COIN_FAST_CODE
+  slackValue_ = -1.0;
+#endif
+  maximumPivots_=200;
+  relaxCheck_=1.0;
+  numberRows_ = 0;
+  numberColumns_ = 0;
+  numberGoodU_ = 0;
+  status_ = -1;
+  numberPivots_ = 0;
+  maximumRows_=0;
+  maximumSpace_=0;
+  elements_ = NULL;
+  pivotRow_ = NULL;
+  workArea_ = NULL;
+  solveMode_=0;
+  if (zapFact) {
+    memset(&factInfo_,0,sizeof(factInfo_));
+    factInfo_.maxinv=100;
+    factInfo_.drtpiv=1.0e-10;
+    factInfo_.zeroTolerance=1.0e-12;
+    factInfo_.zpivlu=0.1;
+    factInfo_.areaFactor=1.0;
+    factInfo_.nbfinv=100;
+  }
+}
+//  ~CoinOslFactorization.  Destructor
+CoinOslFactorization::~CoinOslFactorization (  )
+{
+  gutsOfDestructor();
+}
+//  =
+CoinOslFactorization & CoinOslFactorization::operator = ( const CoinOslFactorization & other ) {
+  if (this != &other) {    
+    bool noGood = factInfo_.nrowmx!=other.factInfo_.nrowmx&&
+      factInfo_.eta_size!=other.factInfo_.eta_size;
+    gutsOfDestructor(noGood);
+    gutsOfInitialize(noGood);
+    gutsOfCopy(other);
+  }
+  return *this;
+}
+#define WORK_MULT 2
+void CoinOslFactorization::gutsOfCopy(const CoinOslFactorization &other)
+{
+  pivotTolerance_ = other.pivotTolerance_;
+  zeroTolerance_ = other.zeroTolerance_;
+#ifndef COIN_FAST_CODE
+  slackValue_ = other.slackValue_;
+#endif
+  relaxCheck_ = other.relaxCheck_;
+  numberRows_ = other.numberRows_;
+  numberColumns_ = other.numberColumns_;
+  maximumRows_ = other.maximumRows_;
+  maximumSpace_ = other.maximumSpace_;
+  solveMode_ = other.solveMode_;
+  numberGoodU_ = other.numberGoodU_;
+  maximumPivots_ = other.maximumPivots_;
+  numberPivots_ = other.numberPivots_;
+  factorElements_ = other.factorElements_;
+  status_ = other.status_;
+  elements_ = NULL;
+  pivotRow_ = NULL;
+  workArea_ = NULL;
+  c_ekksmem_copy(&factInfo_,&other.factInfo_);
+}
+
+//  getAreas.  Gets space for a factorization
+//called by constructors
+void
+CoinOslFactorization::getAreas ( int numberOfRows,
+			 int numberOfColumns,
+			 CoinBigIndex maximumL,
+			 CoinBigIndex maximumU )
+{
+
+  numberRows_ = numberOfRows;
+  numberColumns_ = numberOfColumns;
+  CoinBigIndex size = static_cast<CoinBigIndex>(factInfo_.areaFactor*
+						(maximumL+maximumU));
+  factInfo_.zeroTolerance=zeroTolerance_;
+  // If wildly out redo
+  if (maximumRows_>numberRows_+1000) {
+    maximumRows_=0;
+    maximumSpace_=0;
+    factInfo_.last_eta_size=0;
+  }
+  if (size>maximumSpace_) {
+    //delete [] elements_;
+    //elements_ = new CoinFactorizationDouble [size];
+    maximumSpace_ = size;
+  }
+  factInfo_.lastEtaCount = factInfo_.nnentu+factInfo_.nnentl;
+  int oldnnetas=factInfo_.last_eta_size;
+  // If we are going to increase then be on safe side
+  if (size>oldnnetas) 
+    size = static_cast<int>(1.1*size);
+  factInfo_.eta_size=CoinMax(size,oldnnetas);
+  //printf("clp size %d, old %d now %d - iteration %d - last count %d - rows %d,%d,%d\n",
+  // size,oldnnetas,factInfo_.eta_size,factInfo_.iterno,factInfo_.lastEtaCount,
+  //numberRows_,factInfo_.nrowmx,factInfo_.nrow);
+  //if (!factInfo_.iterno) {
+  //printf("here\n");
+  //}
+  /** Get solve mode e.g. 0 C++ code, 1 Lapack, 2 choose
+      If 4 set then values pass
+      if 8 set then has iterated
+  */
+  solveMode_ &= 4+8; // clear bottom bits
+  factInfo_.ifvsol= ((solveMode_&4)!=0) ? 1 : 0;
+  if ((solveMode_&8)!=0) {
+    factInfo_.ifvsol=0;
+    factInfo_.invok=1; 
+  } else {
+    factInfo_.iter0=factInfo_.iterno;
+    factInfo_.invok=-1;
+    factInfo_.if_sparse_update=0;
+  }
+#if 0
+  if (!factInfo_.if_sparse_update &&
+      factInfo_.iterno>factInfo_.iter0 &&
+      numberRows_>=C_EKK_GO_SPARSE) {
+    printf("count %d rows %d etasize %d\n",
+	   factInfo_.lastEtaCount,factInfo_.nrow,factInfo_.eta_size);
+    
+  }
+#endif 
+  if (!factInfo_.if_sparse_update &&
+      factInfo_.iterno>factInfo_.iter0 &&
+      numberRows_>=C_EKK_GO_SPARSE &&
+      (factInfo_.lastEtaCount>>2)<factInfo_.nrow&&
+      !factInfo_.switch_off_sparse_update) {
+#if PRINT_DEBUG
+    printf("**** Switching on sparse update - etacount\n");
+#endif
+    /* I suspect this can go into c_ekksslvf;
+     * if c_ekkshff decides to switch sparse_update off,
+     * then it problably always switches it off (?)
+     */
+    factInfo_.if_sparse_update=2;
+  }
+  c_ekksmem(&factInfo_,numberRows_,maximumPivots_);
+  if (numberRows_>maximumRows_) { 
+    maximumRows_ = numberRows_;
+    //delete [] pivotRow_;
+    //delete [] workArea_; 
+    //pivotRow_ = new int [2*maximumRows_+maximumPivots_];
+    //workArea_ = new CoinFactorizationDouble [maximumRows_*WORK_MULT];
+  }
+}  
+
+//  preProcess.  
+void
+CoinOslFactorization::preProcess ()
+{
+  factInfo_.zpivlu=pivotTolerance_;
+  // Go to Fortran  
+  int * hcoli=factInfo_.xecadr+1;
+  int * indexRowU = factInfo_.xeradr+1;
+  CoinBigIndex * startColumnU=factInfo_.xcsadr+1;
+  for (int i=0;i<numberRows_;i++) {
+    int start = startColumnU[i];
+    startColumnU[i]++; // to Fortran
+    for (int j=start;j<startColumnU[i+1];j++) {
+      indexRowU[j]++; // to Fortran
+      hcoli[j]=i+1; // to Fortran     
+    }
+  }
+  startColumnU[numberRows_]++; // to Fortran
+
+  /* can do in column order - no zeros or duplicates */
+#ifndef NDEBUG
+  int ninbas =
+#endif 
+    c_ekkslcf(&factInfo_);
+  assert (ninbas>0);
+}
+
+//Does factorization
+int
+CoinOslFactorization::factor ( )
+{
+  /*     Uwe's factorization (sort of) */
+  int irtcod = c_ekklfct(&factInfo_);
+  
+  /*       Check return code */
+  /*       0 - Fine , 1 - Backtrack, 2 - Singularities on initial, 3-Fatal */
+  /*       now 5-Need more memory */
+  
+  status_= 0;
+  if (factInfo_.eta_size>factInfo_.last_eta_size) {
+    factInfo_.areaFactor *= factInfo_.eta_size;
+    factInfo_.areaFactor /= factInfo_.last_eta_size;
+#ifdef CLP_INVESTIGATE
+    printf("areaFactor increased to %g\n",factInfo_.areaFactor);
+#endif
+  }
+  if (irtcod==5) {
+    status_=-99;
+    assert (factInfo_.eta_size>factInfo_.last_eta_size) ;
+#ifdef CLP_INVESTIGATE
+    printf("need more memory\n");
+#endif
+  } else if (irtcod) {
+    status_=-1;
+    //printf("singular %d\n",irtcod);
+  }
+  return status_;
+}
+// Makes a non-singular basis by replacing variables
+void 
+CoinOslFactorization::makeNonSingular(int * sequence, int numberColumns)
+{
+  const EKKHlink *rlink	= factInfo_.kp1adr;
+  const EKKHlink *clink	= factInfo_.kp2adr;
+  int nextRow=0;
+  //int * mark = reinterpret_cast<int *>(factInfo_.kw1adr);
+  //int nr=0;
+  //int nc=0;
+#if 0  
+  for (int i=0;i<numberRows_;i++) {
+    //mark[i]=-1;
+    if (rlink[i].pre>=0||rlink[i].pre==-(numberRows_+1)) {
+      nr++;
+      printf("%d rl %d cl %d\n",i,rlink[i].pre,clink[i].pre);
+    }
+    if (clink[i].pre>=0||clink[i].pre==-(numberRows_+1)) {
+      nc++;
+      printf("%d rl %d cl %d\n",i,rlink[i].pre,clink[i].pre);
+    }
+  }
+#endif
+  //printf("nr %d nc %d\n",nr,nc);
+#ifndef NDEBUG
+  bool goodPass=true;
+#endif
+  int numberDone=0;
+  for (int i=0;i<numberRows_;i++) {
+    int cRow =(-clink[i].pre)-1;
+    if (cRow==numberRows_||cRow<0) {
+      // throw out
+      for (;nextRow<numberRows_;nextRow++) {
+	int rRow =(-rlink[nextRow].pre)-1;
+	if (rRow==numberRows_||rRow<0)
+	  break;  
+      }
+      if (nextRow<numberRows_) {
+	sequence[i]=nextRow+numberColumns;
+	nextRow++;
+	numberDone++;
+      } else {
+#ifndef NDEBUG
+	goodPass=false;
+#endif
+	assert(numberDone);
+	//printf("BAD singular at row %d\n",i);
+	break;
+      }
+    }
+  }
+#ifndef NDEBUG
+  if (goodPass) { 
+    for (;nextRow<numberRows_;nextRow++) {
+      int rRow =(-rlink[nextRow].pre)-1;
+      assert (!(rRow==numberRows_||rRow<0)); 
+    }
+  }
+#endif
+}
+// Does post processing on valid factorization - putting variables on correct rows  
+void 
+CoinOslFactorization::postProcess(const int * sequence, int * pivotVariable)
+{
+  factInfo_.iterin=factInfo_.iterno;
+  factInfo_.npivots=0;
+  numberPivots_=0;
+  const int * permute3 = factInfo_.mpermu+1;
+  assert (permute3==reinterpret_cast<const int *> 
+	  (factInfo_.kadrpm+numberRows_+1));
+  // this is ridiculous - must be better way
+  int * permute2 = reinterpret_cast<int *>(factInfo_.kw1adr);
+  const int * permute = reinterpret_cast<const int *>(factInfo_.kp2adr);
+  for (int i=0;i<numberRows_;i++) {
+    permute2[permute[i]-1]=i;
+  }
+  for (int i=0;i<numberRows_;i++) {
+    // the row is i
+    // the column is whatever matches k3[i] in k1
+    int look=permute3[i]-1;
+    int j=permute2[look];
+    int k = sequence[j];
+    pivotVariable[i]=k;
+  }
+#ifdef CLP_REUSE_ETAS
+  int * start = factInfo_.xcsadr+1;
+  int * putSeq = factInfo_.xrsadr+2*factInfo_.nrowmx+2;
+  int * position = putSeq+factInfo_.maxinv;
+  int * putStart = position+factInfo_.maxinv;
+  memcpy(putStart,start,numberRows_*sizeof(int));
+  int iLast=start[numberRows_-1];
+  putStart[numberRows_]=iLast+factInfo_.xeradr[iLast]+1;
+  factInfo_.save_nnentu=factInfo_.nnentu;
+#endif
+#ifndef NDEBUG
+  {
+    int lstart=numberRows_+factInfo_.maxinv+5;
+    int ndo = factInfo_.xnetal-lstart;
+    double * dluval=factInfo_.xeeadr;
+    int * mcstrt = factInfo_.xcsadr+lstart;
+    if (ndo)
+      assert (dluval[mcstrt[ndo]+1]<1.0e50);
+  }
+#endif
+}
+/* Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+   If checkBeforeModifying is true will do all accuracy checks
+   before modifying factorization.  Whether to set this depends on
+   speed considerations.  You could just do this on first iteration
+   after factorization and thereafter re-factorize
+   partial update already in U */
+int 
+CoinOslFactorization::replaceColumn ( CoinIndexedVector * regionSparse,
+					int pivotRow,
+					double pivotCheck ,
+				      bool /*checkBeforeModifying*/,
+				       double acceptablePivot)
+{
+  if (numberPivots_+1==maximumPivots_)
+    return 3;
+  int *regionIndex = regionSparse->getIndices (  );
+  double *region = regionSparse->denseVector (  );
+  int orig_nincol=0;
+  double saveTolerance = factInfo_.drtpiv;
+  factInfo_.drtpiv=acceptablePivot;
+  int returnCode=c_ekketsj(&factInfo_,region-1,
+			 regionIndex,
+			 pivotCheck,orig_nincol,
+			 numberPivots_,&factInfo_.nuspike,
+			 pivotRow+1,
+			 reinterpret_cast<int *>(factInfo_.kw1adr));
+  factInfo_.drtpiv=saveTolerance;
+  if (returnCode!=2)
+    numberPivots_++;
+#ifndef NDEBUG
+  {
+    int lstart=numberRows_+factInfo_.maxinv+5;
+    int ndo = factInfo_.xnetal-lstart;
+    double * dluval=factInfo_.xeeadr;
+    int * mcstrt = factInfo_.xcsadr+lstart;
+    if (ndo)
+      assert (dluval[mcstrt[ndo]+1]<1.0e50);
+  }
+#endif
+  return returnCode;
+}
+/* This version has same effect as above with FTUpdate==false
+   so number returned is always >=0 */
+int 
+CoinOslFactorization::updateColumn ( CoinIndexedVector * regionSparse,
+				       CoinIndexedVector * regionSparse2,
+				     bool /*noPermute*/) const
+{
+#ifndef NDEBUG
+  {
+    int lstart=numberRows_+factInfo_.maxinv+5;
+    int ndo = factInfo_.xnetal-lstart;
+    double * dluval=factInfo_.xeeadr;
+    int * mcstrt = factInfo_.xcsadr+lstart;
+    if (ndo)
+      assert (dluval[mcstrt[ndo]+1]<1.0e50);
+  }
+#endif
+  assert (numberRows_==numberColumns_);
+  double *region2 = regionSparse2->denseVector (  );
+  int *regionIndex2 = regionSparse2->getIndices (  );
+  int numberNonZero = regionSparse2->getNumElements (  );
+  double *region = regionSparse->denseVector (  );
+  //const int * permuteIn = factInfo_.mpermu+1;
+  // Stuff is put one up so won't get illegal read
+  assert (!region[numberRows_]);
+  assert (!regionSparse2->packedMode());
+#if 0
+  int first=numberRows_;
+  for (int j=0;j<numberNonZero;j++) {
+    int jRow = regionIndex2[j];
+    int iRow = permuteIn[jRow];
+    region[iRow]=region2[jRow];
+    first=CoinMin(first,iRow);
+    region2[jRow]=0.0;
+  }
+#endif
+  numberNonZero=c_ekkftrn(&factInfo_,
+			region2-1,region,regionIndex2,numberNonZero);
+  regionSparse2->setNumElements(numberNonZero);
+  return 0;
+}
+/* Updates one column (FTRAN) from regionSparse2
+   Tries to do FT update
+   number returned is negative if no room
+   regionSparse starts as zero and is zero at end.
+   Note - if regionSparse2 packed on input - will be packed on output
+*/
+int 
+CoinOslFactorization::updateColumnFT ( CoinIndexedVector * regionSparse,
+				      CoinIndexedVector * regionSparse2,
+				       bool /*noPermute*/)
+{
+  assert (numberRows_==numberColumns_);
+  double *region2 = regionSparse2->denseVector (  );
+  int *regionIndex2 = regionSparse2->getIndices (  );
+  int numberNonZero = regionSparse2->getNumElements (  );
+  assert (regionSparse2->packedMode());
+  // packed mode
+  //int numberNonInOriginal=numberNonZero;
+  //double *dpermu = factInfo_.kadrpm;
+  // Use region instead of dpermu
+  double * save =factInfo_.kadrpm;
+  factInfo_.kadrpm=regionSparse->denseVector()-1;
+  int nuspike=c_ekkftrn_ft(&factInfo_, region2,regionIndex2,
+			 &numberNonZero);
+  factInfo_.kadrpm=save;
+  regionSparse2->setNumElements(numberNonZero);
+  //regionSparse2->print();
+  factInfo_.nuspike=nuspike;
+  return nuspike;
+}
+
+
+int 
+CoinOslFactorization::updateTwoColumnsFT(CoinIndexedVector * regionSparse1,
+					  CoinIndexedVector * regionSparse2,
+					  CoinIndexedVector * regionSparse3,
+					 bool /*noPermute*/)
+{
+#if 1
+  // probably best to merge on a LU part by part
+  // but can try full merge
+  double *region2 = regionSparse2->denseVector (  );
+  int *regionIndex2 = regionSparse2->getIndices (  );
+  int numberNonZero2 = regionSparse2->getNumElements (  );
+  assert (regionSparse2->packedMode());
+
+  assert (numberRows_==numberColumns_);
+  double *region3 = regionSparse3->denseVector (  );
+  int *regionIndex3 = regionSparse3->getIndices (  );
+  int numberNonZero3 = regionSparse3->getNumElements (  );
+  double *region = regionSparse1->denseVector (  );
+  // Stuff is put one up so won't get illegal read
+  assert (!region[numberRows_]);
+  assert (!regionSparse3->packedMode());
+  // packed mode
+  //double *dpermu = factInfo_.kadrpm;
+#if 0
+  factInfo_.nuspike=c_ekkftrn_ft(&factInfo_, region2,regionIndex2,
+			       &numberNonZero2);
+  numberNonZero3=c_ekkftrn(&factInfo_,
+			region3-1,region,regionIndex3,numberNonZero3);
+#else
+  c_ekkftrn2(&factInfo_,region3-1,region,regionIndex3,&numberNonZero3,
+  region2,regionIndex2,&numberNonZero2);
+#endif
+  regionSparse2->setNumElements(numberNonZero2);
+  regionSparse3->setNumElements(numberNonZero3);
+  return factInfo_.nuspike;
+#else
+  // probably best to merge on a LU part by part
+  // but can try full merge
+  int returnCode= updateColumnFT(regionSparse1,
+				 regionSparse2);
+  updateColumn(regionSparse1,
+	       regionSparse3,
+	       noPermute);
+  return returnCode;
+#endif
+}
+
+/* Updates one column (BTRAN) from regionSparse2
+   regionSparse starts as zero and is zero at end 
+   Note - if regionSparse2 packed on input - will be packed on output
+*/
+int  
+CoinOslFactorization::updateColumnTranspose ( CoinIndexedVector * regionSparse,
+						CoinIndexedVector * regionSparse2) const
+{
+  assert (numberRows_==numberColumns_);
+  double *region2 = regionSparse2->denseVector (  );
+  int *regionIndex2 = regionSparse2->getIndices (  );
+  int numberNonZero = regionSparse2->getNumElements (  );
+  //double *region = regionSparse->denseVector (  );
+  /*int *regionIndex = regionSparse->getIndices (  );*/
+  const int * permuteIn = factInfo_.mpermu+1;
+  factInfo_.packedMode = regionSparse2->packedMode() ? 1 : 0;
+  // Use region instead of dpermu
+  double * save =factInfo_.kadrpm;
+  factInfo_.kadrpm=regionSparse->denseVector()-1;
+  // use internal one for now (address is one off)
+  double * region = factInfo_.kadrpm;
+  if (numberNonZero<2) {
+    if (numberNonZero) {
+      int ipivrw=regionIndex2[0];
+      if (factInfo_.packedMode) {
+	double value=region2[0];
+	region2[0]=0.0;
+	region2[ipivrw]=value;
+      }
+      numberNonZero=c_ekkbtrn_ipivrw(&factInfo_, region2-1,
+				   regionIndex2-1,ipivrw+1,
+				   reinterpret_cast<int *>(factInfo_.kp1adr));
+    }
+  } else {
+#ifndef NDEBUG    
+    {
+      int *mcstrt	= factInfo_.xcsadr;
+      int * hpivco_new=factInfo_.kcpadr+1;
+      int nrow=factInfo_.nrow;
+      int i;
+      int ipiv = hpivco_new[0];
+      int last = mcstrt[ipiv];
+      for (i=0;i<nrow-1;i++) {
+	ipiv=hpivco_new[ipiv];
+	assert (mcstrt[ipiv]>last);
+	last=mcstrt[ipiv];
+      }
+    }
+#endif
+    int iSmallest = COIN_INT_MAX;
+    int iPiv=0;
+    const int *mcstrt	= factInfo_.xcsadr;
+    // permute and save where nonzeros are
+    if (!factInfo_.packedMode) {
+      if ((numberRows_<200||(numberNonZero<<4)>numberRows_)) {
+	for (int j=0;j<numberNonZero;j++) {
+	  int jRow = regionIndex2[j];
+	  int iRow = permuteIn[jRow];
+	  regionIndex2[j]=iRow; 
+	  region[iRow]=region2[jRow];
+	  region2[jRow]=0.0;
+	}
+      } else {
+	for (int j=0;j<numberNonZero;j++) {
+	  int jRow = regionIndex2[j];
+	  int iRow = permuteIn[jRow];
+	  regionIndex2[j]=iRow; 
+	  region[iRow]=region2[jRow];
+	  if (mcstrt[iRow]<iSmallest) {
+	    iPiv=iRow;
+	    iSmallest=mcstrt[iRow];
+	  }
+	  region2[jRow]=0.0;
+	}
+      }
+    } else {
+      for (int j=0;j<numberNonZero;j++) {
+	int jRow = regionIndex2[j];
+	int iRow = permuteIn[jRow];
+	regionIndex2[j]=iRow;
+	region[iRow]=region2[j];
+	region2[j]=0.0;
+      }
+    }
+    assert (iPiv>=0);
+    numberNonZero=c_ekkbtrn(&factInfo_, region2-1,regionIndex2-1,iPiv);
+  }
+  factInfo_.kadrpm=save;
+  factInfo_.packedMode=0;
+  regionSparse2->setNumElements(numberNonZero);
+  return 0;
+}
+// Number of entries in each row
+int * 
+CoinOslFactorization::numberInRow() const
+{ return reinterpret_cast<int *> (factInfo_.xrnadr+1);}
+// Number of entries in each column
+int * 
+CoinOslFactorization::numberInColumn() const
+{ return reinterpret_cast<int *> (factInfo_.xcnadr+1);}
+// Returns array to put basis starts in
+CoinBigIndex * 
+CoinOslFactorization::starts() const
+{ return reinterpret_cast<CoinBigIndex *> (factInfo_.xcsadr+1);}
+// Returns array to put basis elements in
+CoinFactorizationDouble * 
+CoinOslFactorization::elements() const
+{ return factInfo_.xeeadr+1;}
+// Returns pivot row 
+int * 
+CoinOslFactorization::pivotRow() const
+{ return factInfo_.krpadr+1;}
+// Returns work area
+CoinFactorizationDouble * 
+CoinOslFactorization::workArea() const
+{ return factInfo_.kw1adr;}
+// Returns int work area
+int * 
+CoinOslFactorization::intWorkArea() const
+{ return reinterpret_cast<int *> (factInfo_.kw1adr);}
+// Returns permute back
+int * 
+CoinOslFactorization::permuteBack() const
+{ return factInfo_.kcpadr+1;}
+// Returns array to put basis indices in
+int * 
+CoinOslFactorization::indices() const
+{ return factInfo_.xeradr+1;}
+// Returns true if wants tableauColumn in replaceColumn
+bool
+CoinOslFactorization::wantsTableauColumn() const
+{ return false;}
+/* Useful information for factorization
+   0 - iteration number
+   whereFrom is 0 for factorize and 1 for replaceColumn
+*/
+#ifdef CLP_REUSE_ETAS
+void 
+CoinOslFactorization::setUsefulInformation(const int * info,int whereFrom)
+{ 
+  factInfo_.iterno=info[0]; 
+  if (whereFrom) {
+    factInfo_.reintro=-1;
+    if( factInfo_.first_dense>=factInfo_.last_dense) {
+      int * putSeq = factInfo_.xrsadr+2*factInfo_.nrowmx+2;
+      int * position = putSeq+factInfo_.maxinv;
+      //int * putStart = position+factInfo_.maxinv;
+      int iSequence=info[1];
+      if (whereFrom==1) {
+	putSeq[factInfo_.npivots]=iSequence;
+      } else {
+	int i;
+	for (i=factInfo_.npivots-1;i>=0;i--) {
+	  if (putSeq[i]==iSequence)
+	    break;
+	}
+	if (i>=0) {
+	  factInfo_.reintro=position[i];
+	} else {
+	  factInfo_.reintro=-1;
+	}
+	factInfo_.nnentu=factInfo_.save_nnentu;
+      }
+    }
+  }
+}
+#else
+void
+CoinOslFactorization::setUsefulInformation(const int * info,int /*whereFrom*/)
+{ factInfo_.iterno=info[0]; }
+#endif
+
+// Get rid of all memory
+void 
+CoinOslFactorization::clearArrays()
+{
+  factInfo_.nR_etas=0;
+  factInfo_.nnentu=0;
+  factInfo_.nnentl=0;
+  maximumRows_=0;
+  maximumSpace_=0;
+  factInfo_.last_eta_size=0;
+  gutsOfDestructor(false);
+}
+void 
+CoinOslFactorization::maximumPivots (  int value )
+{
+  maximumPivots_ = value;
+}
+#define CLP_FILL 15
+/*#undef NDEBUG*/
+//#define CLP_DEBUG_MALLOC 1000000
+#if CLP_DEBUG_MALLOC
+static int malloc_number=0;
+static int malloc_check=-1;
+static int malloc_counts_on=0;
+struct malloc_struct {
+  void * previous;
+  void * next;
+  int size;
+  int when;
+  int type;
+};
+static double malloc_times=0.0;
+static double malloc_total=0.0;
+static double malloc_current=0.0;
+static double malloc_max=0.0;
+static int malloc_amount[]={0,32,128,256,1024,4096,16384,65536,262144,
+			    2000000000};
+static int malloc_n=10;
+double malloc_counts[10]={0,0,0,0,0,0,0,0,0,0};
+typedef struct malloc_struct malloc_struct;
+static malloc_struct startM = {0,0,0,0};
+static malloc_struct endM = {0,0,0,0};
+static int extra=4;
+void clp_memory(int type)
+{
+  if (type==0) {
+    /* switch on */
+    malloc_counts_on=1;
+    startM.next=&endM;
+    endM.previous=&startM;
+  } else {
+    /* summary */
+    double average = malloc_total/malloc_times;
+    int i;
+    malloc_struct * previous = (malloc_struct *) endM.previous;
+    printf("count %g bytes %g - average %g\n",malloc_times,malloc_total,average);
+    printf("current bytes %g - maximum %g\n",malloc_current,malloc_max);
+    
+    for ( i=0;i<malloc_n;i++) 
+      printf("%g ",malloc_counts[i]);
+    printf("\n");
+    malloc_counts_on=0;
+    if (previous->previous!=&startM) {
+      int n=0;
+      printf("Allocated blocks\n");
+      while (previous->previous!=&startM) {
+	printf("(%d at %d) ",previous->size,previous->when);
+	n++;
+	if ((n%5)==0)
+	  printf("\n");
+	previous = (malloc_struct *) previous->previous;
+      }
+      printf("\n - total %d\n",n);
+    }
+  }
+  malloc_number=0;
+  malloc_times=0.0;
+  malloc_total=0.0;
+  malloc_current=0.0;
+  malloc_max=0.0;
+  memset(malloc_counts,0,sizeof(malloc_counts));
+}
+static void clp_adjust(void * temp,int size,int type)
+{
+  malloc_struct * itemp = (malloc_struct *) temp;
+  malloc_struct * first = (malloc_struct *) startM.next;
+  int i;
+  startM.next=temp;
+  first->previous=temp;
+  itemp->previous=&startM;
+  itemp->next=first;
+  malloc_number++;
+  if (malloc_number==malloc_check) {
+    printf("Allocation of %d bytes at %d (type %d) not freed\n",
+	   size,malloc_number,type);
+  }
+  itemp->when=malloc_number;
+  itemp->size=size;
+  itemp->type=type;
+  malloc_times ++;
+  malloc_total += size;
+  malloc_current += size;
+  malloc_max=CoinMax(malloc_max,malloc_current);
+  for (i=0;i<malloc_n;i++) {
+    if ((int) size<=malloc_amount[i]) {
+      malloc_counts[i]++;
+      break;
+    }
+  }
+}
+#endif
+/* covers */
+double * clp_double(int number_entries)
+{
+#if CLP_DEBUG_MALLOC==0
+  return reinterpret_cast<double *>( malloc(number_entries*sizeof(double)));
+#else
+  double * temp = reinterpret_cast<double *>( malloc((number_entries+extra)*sizeof(double)));
+  clp_adjust(temp,number_entries*sizeof(double),1);
+#if CLP_DEBUG_MALLOC>1
+  if (number_entries*sizeof(double)>=CLP_DEBUG_MALLOC)
+    printf("WWW %x malloced by double %d - size %d\n",
+	   temp+extra,malloc_number,number_entries);
+#endif
+  return temp+extra;
+#endif
+}
+int * clp_int(int number_entries)
+{
+#if CLP_DEBUG_MALLOC==0
+  return reinterpret_cast<int *>( malloc(number_entries*sizeof(int)));
+#else
+  double * temp = reinterpret_cast<double *>( malloc(((number_entries+1)/2+extra)*sizeof(double)));
+  clp_adjust(temp,number_entries*sizeof(int),2);
+#if CLP_DEBUG_MALLOC>1
+  if (number_entries*sizeof(int)>=CLP_DEBUG_MALLOC)
+    printf("WWW %x malloced by int %d - size %d\n",
+	   temp+extra,malloc_number,number_entries);
+#endif
+  return reinterpret_cast<int *>( (temp+extra));
+#endif
+}
+void * clp_malloc(int number_entries)
+{
+#if CLP_DEBUG_MALLOC==0
+  return malloc(number_entries);
+#else
+  double * temp = reinterpret_cast<double *>( malloc(number_entries+extra*sizeof(double)));
+  clp_adjust(temp,number_entries,0);
+#if CLP_DEBUG_MALLOC>1
+  if (number_entries>=CLP_DEBUG_MALLOC)
+    printf("WWW %x malloced by void %d - size %d\n",
+	   temp+extra,malloc_number,number_entries);
+#endif
+  return (void *) (temp+extra);
+#endif
+}
+void clp_free(void * oldArray)
+{
+#if CLP_DEBUG_MALLOC==0
+  free(oldArray);
+#else
+  if (oldArray) {
+    double * temp = (reinterpret_cast<double *>( oldArray)-extra);
+    malloc_struct * itemp = (malloc_struct *) temp;
+    malloc_struct * next = (malloc_struct *) itemp->next;
+    malloc_struct * previous = (malloc_struct *) itemp->previous;
+    previous->next=next;
+    next->previous=previous;
+    malloc_current -= itemp->size;
+#if CLP_DEBUG_MALLOC>1
+    if (itemp->size>=CLP_DEBUG_MALLOC)
+    printf("WWW %x freed by free %d - old length %d - type %d\n",
+	   oldArray,itemp->when,itemp->size,itemp->type);
+#endif
+    free(temp);
+  }
+#endif
+}
+/*#define FIX_ADD 4*nrowmx+5
+  #define FIX_ADD2 4*nrowmx+5*/
+#define FIX_ADD 1*nrowmx+5
+#define FIX_ADD2 1*nrowmx+5
+#define ALIGNMENT 32
+static void * clp_align (void * memory)
+{
+  if (sizeof(int)==sizeof(void *)&&ALIGNMENT) {
+    CoinInt64 k = reinterpret_cast<CoinInt64> (memory);
+    if ((k&(ALIGNMENT-1))!=0) {
+      k &= ~(ALIGNMENT-1);
+      k += ALIGNMENT;
+      memory = reinterpret_cast<void *> (k);
+    }
+    return memory;
+  } else {
+    return memory;
+  }
+}
+void clp_setup_pointers(EKKfactinfo * fact)
+{
+  /* do extra stuff */
+  int nrow=fact->nrow;
+  int nrowmx=fact->nrowmx;
+  int maxinv=fact->maxinv;
+  fact->lstart	= nrow + maxinv + 5;
+  /* this is the number of L transforms */
+  fact->xnetalval = fact->xnetal - fact->lstart;
+  fact->mpermu	= (reinterpret_cast<int*> (fact->kadrpm+nrow))+1;
+  fact->bitArray = fact->krpadr + ( nrowmx+2);
+  fact->back	= fact->kcpadr+2*nrow + maxinv + 4;
+  fact->hpivcoR = fact->kcpadr+nrow+3;
+  fact->nonzero = (reinterpret_cast<char *>( &fact->mpermu[nrow+1]))-1;
+}
+#ifndef NDEBUG
+int ets_count=0;
+int ets_check=-1;
+//static int adjust_count=0;
+//static int adjust_check=-1;
+#endif
+static void clp_adjust_pointers(EKKfactinfo * fact, int adjust)
+{
+#if 0 //ndef NDEBUG
+  adjust_count++;
+  if (adjust_check>=0&&adjust_count>=adjust_check) {
+    printf("trouble\n");
+  }
+#endif
+  if (fact->trueStart) {
+    fact->kadrpm += adjust;
+    fact->krpadr += adjust;
+    fact->kcpadr += adjust;
+    fact->xrsadr += adjust;
+    fact->xcsadr += adjust;
+    fact->xrnadr += adjust;
+    fact->xcnadr += adjust;
+  }
+  if (fact->xeradr) {
+    fact->xeradr += adjust;
+    fact->xecadr += adjust;
+    fact->xeeadr += adjust;
+  }
+}
+/* deals with memory for complicated array 
+   0 just do addresses 
+   1 just get memory */
+static double *
+clp_alloc_memory(EKKfactinfo * fact,int type, int * length)
+{
+  int nDouble=0;
+  int nInt=0;
+  int nrowmxp;
+  int ntot1;
+  int ntot2;
+  int ntot3;
+  int nrowmx;
+  int * tempI;
+  double * tempD;
+  nrowmx=fact->nrowmx;
+  nrowmxp = nrowmx + 2;
+  ntot1 = nrowmxp;
+  ntot2 = 3*nrowmx+5; /* space for three lists */
+  ntot3 = 2*nrowmx;
+  if ((ntot1<<1)<ntot2) {
+    ntot1=ntot2>>1;
+  }
+  ntot3=CoinMax(ntot3,ntot1);
+  /*   Row work regions */
+  /* must be contiguous so allocate as one chunk */
+  /* may only need 2.5 */
+  /* now doing all at once - far too much - reduce later */
+  tempD=fact->kw1adr;
+  tempD+=nrowmxp;
+  tempD = reinterpret_cast<double *>( clp_align(tempD));
+  fact->kw2adr=tempD;
+  tempD+=nrowmxp;
+  tempD = reinterpret_cast<double *>( clp_align(tempD));
+  fact->kw3adr=tempD-1;
+  tempD+=nrowmxp;
+  tempD = reinterpret_cast<double *>( clp_align(tempD));
+  fact->kp1adr=reinterpret_cast<EKKHlink *>(tempD);
+  tempD+=nrowmxp;
+  tempD = reinterpret_cast<double *>( clp_align(tempD));
+  fact->kp2adr=reinterpret_cast<EKKHlink *>(tempD);
+  //tempD+=ntot3;
+  tempD+=nrowmxp;
+  tempD = reinterpret_cast<double *>( clp_align(tempD));
+  /*printf("zz %x %x\n",tempD,fact->kadrpm);*/
+  fact->kadrpm = tempD;
+  /* seems a lot */
+  tempD += ((6*nrowmx +8)*(sizeof(int))/sizeof(double));
+  /* integer arrays */
+  tempI = reinterpret_cast<int *>( tempD);
+  tempI = reinterpret_cast<int *>( clp_align(tempI));
+  fact->xrsadr = tempI;
+#ifdef CLP_REUSE_ETAS
+  tempI +=( 3*(nrowmx+fact->maxinv+1));
+#else
+  tempI +=( (nrowmx<<1)+fact->maxinv+1);
+#endif
+  tempI = reinterpret_cast<int *>( clp_align(tempI));
+  fact->xcsadr = tempI;
+#if 1 //def CLP_REUSE_ETAS
+  tempI += ( 2*nrowmx+8+2*fact->maxinv);
+#else
+  tempI += ( 2*nrowmx+8+fact->maxinv);
+#endif
+  tempI += FIX_ADD+FIX_ADD2;
+  tempI = reinterpret_cast<int *>( clp_align(tempI));
+  fact->xrnadr = tempI;
+  tempI += nrowmx;
+  tempI = reinterpret_cast<int *>( clp_align(tempI));
+  fact->xcnadr = tempI;
+  tempI += nrowmx;
+  tempI = reinterpret_cast<int *>( clp_align(tempI));
+  fact->krpadr = tempI;
+  tempI += ( nrowmx+1) +((nrowmx+33)>>5);
+  /*printf("zzz %x %x\n",tempI,fact->kcpadr);*/
+  tempI = reinterpret_cast<int *>( clp_align(tempI));
+  fact->kcpadr = tempI;
+  tempI += 3*nrowmx+8+fact->maxinv;
+  fact->R_etas_start = fact->xcsadr+nrowmx+fact->maxinv+4;
+  fact->R_etas_start += FIX_ADD;
+  nInt = static_cast<int>(tempI-(reinterpret_cast<int *>( fact->trueStart)));
+  nDouble = static_cast<int>(sizeof(int)*(nInt+1)/sizeof(double));
+  *length = nDouble;
+  /*printf("nDouble %d - type %d\n",nDouble,type);*/
+  nDouble += static_cast<int>((2*ALIGNMENT)/sizeof(double));
+  if (type) {
+    /*printf("%d allocated\n",nDouble);*/
+    tempD = reinterpret_cast<double *>( clp_double(nDouble));
+#ifndef NDEBUG
+    memset(tempD,CLP_FILL,nDouble*sizeof(double));
+#endif
+  }
+  return tempD;
+}
+static void c_ekksmem(EKKfactinfo *fact,int nrow,int maximumPivots)
+{
+  /* space for invert */
+  int nnetas=fact->eta_size;
+  fact->nrow=nrow;
+  if (!(nnetas>fact->last_eta_size||(!fact->xe2adr&&fact->if_sparse_update)||
+	nrow>fact->nrowmx||maximumPivots>fact->maxinv))
+    return;
+  clp_adjust_pointers(fact, +1);
+  if (nrow>fact->nrowmx||maximumPivots>fact->maxinv) {
+    int length;
+    fact->nrowmx=CoinMax(nrow,fact->nrowmx);
+    fact->maxinv=CoinMax(maximumPivots,fact->maxinv);
+    clp_free(fact->trueStart);
+    fact->trueStart=0;
+    fact->kw1adr=0;
+    fact->trueStart=clp_alloc_memory(fact,1,&length);
+    fact->kw1adr=reinterpret_cast<double *>( clp_align(fact->trueStart));
+    clp_alloc_memory(fact,0,&length);
+  }
+  /*if (!fact->iterno) fact->eta_size+=1000000;*//* TEMP*/
+  if (nnetas>fact->last_eta_size||(!fact->xe2adr&&fact->if_sparse_update)) {
+    fact->last_eta_size = nnetas;
+    clp_free(reinterpret_cast<char *>(fact->xe2adr));
+    /* if malloc fails - we have lost memory - start again */
+    if (!fact->ndenuc &&fact->if_sparse_update) {
+      /* allow second copy of elements */
+      fact->xe2adr = clp_double(nnetas);
+#ifndef NDEBUG
+      memset(fact->xe2adr,CLP_FILL,nnetas*sizeof(double));
+#endif
+      if (!fact->xe2adr) {
+	fact->maxNNetas=fact->last_eta_size; /* dont allow any increase */
+	nnetas=fact->last_eta_size;
+	fact->eta_size=nnetas;
+#ifdef PRINT_DEBUG
+	if (fact->if_sparse_update) {
+	  printf("*** Sparse update off due to memory\n");
+	}
+#endif
+	fact->if_sparse_update=0;
+	fact->switch_off_sparse_update=1;
+      }
+    } else {
+      fact->xe2adr = 0;
+      fact->if_sparse_update=0;
+    }
+    clp_free(fact->xeradr);
+    fact->xeradr= clp_int( nnetas);
+#ifndef NDEBUG
+      memset(fact->xeradr,CLP_FILL,nnetas*sizeof(int));
+#endif
+    if (!fact->xeradr) {
+      nnetas=0;
+    }
+    if (nnetas) {
+      clp_free(fact->xecadr);
+      fact->xecadr= clp_int( nnetas);
+#ifndef NDEBUG
+      memset(fact->xecadr,CLP_FILL,nnetas*sizeof(int));
+#endif
+      if (!fact->xecadr) {
+	nnetas=0;
+      }
+    }
+    if (nnetas) {
+      clp_free(fact->xeeadr);
+      fact->xeeadr= clp_double(nnetas);
+#ifndef NDEBUG
+      memset(fact->xeeadr,CLP_FILL,nnetas*sizeof(double));
+#endif
+      if (!fact->xeeadr) {
+	nnetas=0;
+      }
+    }
+  }
+  if (!nnetas) {
+    char msg[100];
+    sprintf(msg,"Unable to allocate factorization memory for %d elements",
+	   nnetas);
+    throw(msg);
+  }
+  /*c_ekklplp->nnetas=nnetas;*/
+  fact->nnetas=nnetas;
+  clp_adjust_pointers(fact, -1);
+}
+static void c_ekksmem_copy(EKKfactinfo *fact,const EKKfactinfo * rhsFact)
+{
+  /* space for invert */
+  int nrowmx=rhsFact->nrowmx,nnetas=rhsFact->nnetas;
+  int canReuseEtas= (fact->eta_size==rhsFact->eta_size) ? 1 : 0;
+  int canReuseArrays = (fact->nrowmx==rhsFact->nrowmx) ? 1 : 0;
+  clp_adjust_pointers(fact, +1);
+  clp_adjust_pointers(const_cast<EKKfactinfo *>(rhsFact), +1);
+  /*memset(fact,0,sizeof(EKKfactinfo));*/
+  /* copy scalars */
+  memcpy(&fact->drtpiv,&rhsFact->drtpiv,5*sizeof(double));
+  memcpy(&fact->nrow,&rhsFact->nrow,((&fact->maxNNetas-&fact->nrow)+1)*
+	 sizeof(int));
+  if (nrowmx) {
+    int length;
+    int kCopyEnd,nCopyEnd,nCopyStart;
+    if (!canReuseEtas) {
+      clp_free(fact->xeradr);
+      clp_free(fact->xecadr);
+      clp_free(fact->xeeadr);
+      clp_free(fact->xe2adr);
+      fact->xeradr = 0;
+      fact->xecadr = 0;
+      fact->xeeadr = 0;
+      fact->xe2adr = 0;
+    }
+    if (!canReuseArrays) {
+      clp_free(fact->trueStart);
+      fact->trueStart=0;
+      fact->kw1adr=0;
+      fact->trueStart=clp_alloc_memory(fact,1,&length);
+      fact->kw1adr=reinterpret_cast<double *>( clp_align(fact->trueStart));
+    }
+    clp_alloc_memory(fact,0,&length);
+    nnetas=fact->eta_size;
+    assert (nnetas);
+    {
+      int n2 = rhsFact->nR_etas;
+      int n3 = n2 ? rhsFact->R_etas_start[1+n2]: 0;
+      int * startR = rhsFact->R_etas_index+n3; 
+      nCopyEnd=static_cast<int>((rhsFact->xeradr+nnetas)-startR);
+      nCopyStart=rhsFact->nnentu;
+      nCopyEnd = CoinMin(nCopyEnd+20,nnetas);
+      kCopyEnd = nnetas-nCopyEnd;
+      nCopyStart = CoinMin(nCopyStart+20,nnetas);
+      if (!n2&&!rhsFact->nnentu&&!rhsFact->nnentl) {
+	nCopyStart=nCopyEnd=0;
+      }
+    }
+    /* copy */
+    if(nCopyStart||nCopyEnd||true) {
+#if 1
+      memcpy(fact->kw1adr,rhsFact->kw1adr,length*sizeof(double));
+#else
+      c_ekkscpy((length*sizeof(double))/sizeof(int),
+	      reinterpret_cast<int *>( rhsFact->kw1adr,reinterpret_cast<int *>( fact->kw1adr));
+#endif
+    }
+    /* if malloc fails - we have lost memory - start again */
+    if (!fact->ndenuc &&fact->if_sparse_update) {
+      /* allow second copy of elements */
+      if (!canReuseEtas) 
+	fact->xe2adr = clp_double(nnetas);
+      if (!fact->xe2adr) {
+	fact->maxNNetas=nnetas; /* dont allow any increase */
+#ifdef PRINT_DEBUG
+	if (fact->if_sparse_update) {
+	  printf("*** Sparse update off due to memory\n");
+	}
+#endif
+	fact->if_sparse_update=0;
+      } else {
+#ifndef NDEBUG
+	memset(fact->xe2adr,CLP_FILL,nnetas*sizeof(double));
+#endif
+      }
+    } else {
+      clp_free(fact->xe2adr);
+      fact->xe2adr = 0;
+      fact->if_sparse_update=0;
+    }
+    
+    if (!canReuseEtas) 
+      fact->xeradr= clp_int(nnetas);
+    if (!fact->xeradr) {
+      nnetas=0;
+    } else {
+#ifndef NDEBUG
+      memset(fact->xeradr,CLP_FILL,nnetas*sizeof(int));
+#endif
+      
+      /* copy */
+      if(nCopyStart||nCopyEnd) {
+#if 0
+	memcpy(fact->xeradr,rhsFact->xeradr,nCopyStart*sizeof(int));
+	memcpy(fact->xeradr+kCopyEnd,rhsFact->xeradr+kCopyEnd,nCopyEnd*sizeof(int));
+#else
+	c_ekkscpy(nCopyStart,rhsFact->xeradr,fact->xeradr);
+	c_ekkscpy(nCopyEnd,rhsFact->xeradr+kCopyEnd,fact->xeradr+kCopyEnd);
+#endif
+      }
+    }
+    if (nnetas) {
+      if (!canReuseEtas) 
+	fact->xecadr= clp_int(nnetas);
+      if (!fact->xecadr) {
+	nnetas=0;
+      } else {
+#ifndef NDEBUG
+	memset(fact->xecadr,CLP_FILL,nnetas*sizeof(int));
+#endif
+	/* copy */
+	if (fact->rows_ok&&(nCopyStart||nCopyEnd)) {
+	  int i;
+	  int * hcoliR=rhsFact->xecadr-1;
+	  int * hcoli=fact->xecadr-1;
+	  int * mrstrt=fact->xrsadr;
+	  int * hinrow=fact->xrnadr;
+#if 0
+	  memcpy(fact->xecadr+kCopyEnd,rhsFact->xecadr+kCopyEnd,
+		 nCopyEnd*sizeof(int));
+#else
+	  c_ekkscpy(nCopyEnd,rhsFact->xecadr+kCopyEnd,fact->xecadr+kCopyEnd);
+#endif
+	  if (!fact->xe2adr) {
+	    for (i=0;i<fact->nrow;i++) {
+	      int istart = mrstrt[i];
+	      assert (istart>0&&istart<=nnetas);
+	      assert (hinrow[i]>=0&&hinrow[i]<=fact->nrow);
+	      memcpy(hcoli+istart,hcoliR+istart,hinrow[i]*sizeof(int));
+	    }
+	  } else {
+	    double * de2valR=rhsFact->xe2adr-1;
+	    double * de2val=fact->xe2adr-1;
+#if 0
+	    memcpy(fact->xe2adr+kCopyEnd,rhsFact->xe2adr+kCopyEnd,
+		   nCopyEnd*sizeof(double));
+#else
+	    c_ekkdcpy(nCopyEnd,rhsFact->xe2adr+kCopyEnd
+		     ,fact->xe2adr+kCopyEnd);
+#endif
+	    for (i=0;i<fact->nrow;i++) {
+	      int istart = mrstrt[i];
+	      assert (istart>0&&istart<=nnetas);
+	      assert (hinrow[i]>=0&&hinrow[i]<=fact->nrow);
+	      memcpy(hcoli+istart,hcoliR+istart,hinrow[i]*sizeof(int));
+	      memcpy(de2val+istart,de2valR+istart,hinrow[i]*sizeof(double));
+#ifndef NDEBUG
+	      {
+		int j;
+		for (j=istart;j<istart+hinrow[i];j++)
+		  assert (fabs(de2val[j])<1.0e50);
+	      }
+#endif
+	    }
+	  }
+	}
+      }
+    }
+    if (nnetas) {
+      if (!canReuseEtas) 
+	fact->xeeadr= clp_double(nnetas);
+      if (!fact->xeeadr) {
+	nnetas=0;
+      } else {
+#ifndef NDEBUG
+	memset(fact->xeeadr,CLP_FILL,nnetas*sizeof(double));
+#endif
+	/* copy */
+	if(nCopyStart||nCopyEnd) {
+#if 0
+	  memcpy(fact->xeeadr,rhsFact->xeeadr,nCopyStart*sizeof(double));
+	  memcpy(fact->xeeadr+kCopyEnd,rhsFact->xeeadr+kCopyEnd,nCopyEnd*sizeof(double));
+#else
+	  c_ekkdcpy(nCopyStart,
+		  rhsFact->xeeadr,fact->xeeadr);
+	  c_ekkdcpy(nCopyEnd,
+		   rhsFact->xeeadr+kCopyEnd,
+		   fact->xeeadr+kCopyEnd);
+#endif
+	}
+	/*fact->R_etas_index = &XERADR1()[kdnspt - 1];
+	  fact->R_etas_element = &XEEADR1()[kdnspt - 1];*/
+	fact->R_etas_start = fact->xcsadr+
+	  (rhsFact->R_etas_start-rhsFact->xcsadr);
+	fact->R_etas_index = fact->xeradr+
+	  (rhsFact->R_etas_index-rhsFact->xeradr);
+	fact->R_etas_element = fact->xeeadr+
+	  (rhsFact->R_etas_element-rhsFact->xeeadr);
+      }
+    }
+  }
+  assert (nnetas||!nrowmx);
+  fact->nnetas=nnetas;
+  clp_adjust_pointers(fact, -1);
+  clp_setup_pointers(fact);
+  clp_adjust_pointers(const_cast<EKKfactinfo *>(rhsFact), -1);
+}
+static void c_ekksmem_delete(EKKfactinfo *fact)
+{
+  clp_adjust_pointers(fact, +1);
+  clp_free(fact->trueStart);
+  clp_free(fact->xe2adr);
+  clp_free(fact->xecadr);
+  clp_free(fact->xeradr);
+  clp_free(fact->xeeadr);
+  fact->eta_size=0;
+  fact->xrsadr = 0;
+  fact->xcsadr = 0;
+  fact->xrnadr = 0;
+  fact->xcnadr = 0;
+  fact->krpadr = 0;
+  fact->kcpadr = 0;
+  fact->xeradr = 0;
+  fact->xecadr = 0;
+  fact->xeeadr = 0;
+  fact->xe2adr = 0;
+  fact->trueStart = 0;
+  fact->kw2adr = 0;
+  fact->kw3adr = 0;
+  fact->kp1adr = 0;
+  fact->kp2adr = 0;
+  fact->kadrpm = 0;
+  fact->kw1adr = 0;
+}
+int c_ekk_IsSet(const int * array,int bit);
+void c_ekk_Set(int * array,int bit);
+void c_ekk_Unset(int * array,int bit);
+int c_ekk_IsSet(const int * array,int bit)
+{
+  int iWord = bit>>5;
+  int iBit = bit&31;
+  int word = array[iWord];
+  return (word&(1<<iBit))!=0;
+}
+void c_ekk_Set(int * array,int bit)
+{
+  int iWord = bit>>5;
+  int iBit = bit&31;
+  array[iWord] |= (1<<iBit);
+}
+void c_ekk_Unset(int * array,int bit)
+{
+  int iWord = bit>>5;
+  int iBit = bit&31;
+  array[iWord] &= ~(1<<iBit);
+}
+int CoinOslFactorization::factorize (
+				 const CoinPackedMatrix & matrix,
+				 int rowIsBasic[],
+				 int columnIsBasic[],
+				 double areaFactor )
+{
+  setSolveMode(10);
+  if (areaFactor)
+    factInfo_.areaFactor = areaFactor;
+  const int * row = matrix.getIndices();
+  const CoinBigIndex * columnStart = matrix.getVectorStarts();
+  const int * columnLength = matrix.getVectorLengths(); 
+  const double * element = matrix.getElements();
+  int numberRows=matrix.getNumRows();
+  int numberColumns=matrix.getNumCols();
+  int numberBasic = 0;
+  CoinBigIndex numberElements=0;
+  int numberRowBasic=0;
+  
+  // compute how much in basis
+  
+  int i;
+  // Move pivot variables across if they look good
+  int * pivotTemp = new int [numberRows];
+  
+  for (i=0;i<numberRows;i++) {
+    if (rowIsBasic[i]>=0) 
+      pivotTemp[numberRowBasic++]=i;
+  }
+  
+  numberBasic = numberRowBasic;
+  
+  for (i=0;i<numberColumns;i++) {
+    if (columnIsBasic[i]>=0) {
+      pivotTemp[numberBasic++]=i;
+      numberElements += columnLength[i];
+    }
+  }
+  if ( numberBasic > numberRows ) {
+    return -2; // say too many in basis
+  }
+  numberElements = 3 * numberRows + 3 * numberElements + 20000;
+  setUsefulInformation(&numberRows,0);
+  getAreas ( numberRows, numberRows, numberElements,
+	     2 * numberElements );
+  //fill
+  numberBasic=0;
+  numberElements=0;
+  // Fill in counts so we can skip part of preProcess
+  double * elementU=elements();
+  int * indexRowU=indices();
+  int * startColumnU=starts();
+  int * numberInRow=this->numberInRow();
+  int * numberInColumn=this->numberInColumn();
+  CoinZeroN ( numberInRow, numberRows  );
+  CoinZeroN ( numberInColumn, numberRows );
+  for (i=0;i<numberRowBasic;i++) {
+    int iRow = pivotTemp[i];
+    // Change pivotTemp to correct sequence
+    pivotTemp[i]=iRow+numberColumns;
+    indexRowU[i]=iRow;
+    startColumnU[i]=i;
+    elementU[i]=-1.0;
+    numberInRow[iRow]=1;
+    numberInColumn[i]=1;
+  }
+  startColumnU[numberRowBasic]=numberRowBasic;
+  numberElements=numberRowBasic;
+  numberBasic=numberRowBasic;
+  for (i=0;i<numberColumns;i++) {
+    if (columnIsBasic[i]>=0) {
+      CoinBigIndex j;
+      for (j=columnStart[i];j<columnStart[i]+columnLength[i];j++) {
+	int iRow=row[j];
+	numberInRow[iRow]++;
+	indexRowU[numberElements]=iRow;
+	elementU[numberElements++]=element[j];
+      }
+      numberInColumn[numberBasic]=columnLength[i];
+      numberBasic++;
+      startColumnU[numberBasic]=numberElements;
+    }
+  }
+  preProcess ( );
+  factor (  );
+  if (status() == 0) {
+    int * pivotVariable = new int [numberRows];
+    postProcess(pivotTemp,pivotVariable);
+    for (i=0;i<numberRows;i++) {
+      int iPivot=pivotVariable[i];
+      if (iPivot<numberColumns) {
+	assert (columnIsBasic[iPivot]>=0);
+	columnIsBasic[iPivot]=i;
+      } else {
+	iPivot-=numberColumns;
+	assert (rowIsBasic[iPivot]>=0);
+	rowIsBasic[iPivot]=i;
+      }
+    }
+    delete [] pivotVariable;
+  }
+  delete [] pivotTemp;
+  return status_;
+}
+// Condition number - product of pivots after factorization
+double 
+CoinOslFactorization::conditionNumber() const
+{
+  double condition = 1.0;
+  const double *dluval	= factInfo_.xeeadr+1-1; // stored before
+  const int *mcstrt	= factInfo_.xcsadr+1;
+  for (int i=0;i<numberRows_;i++) {
+    const int kx = mcstrt[i];
+    const double dpiv = dluval[kx];
+    condition *= dpiv;
+  }
+  condition = CoinMax(fabs(condition),1.0e-50);
+  return 1.0/condition;
+}
diff --git a/cbits/coin/CoinOslFactorization.hpp b/cbits/coin/CoinOslFactorization.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinOslFactorization.hpp
@@ -0,0 +1,280 @@
+/* $Id: CoinOslFactorization.hpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 1987, 2009, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/* 
+   Authors
+   
+   John Forrest
+
+ */
+#ifndef CoinOslFactorization_H
+#define CoinOslFactorization_H
+#include <iostream>
+#include <string>
+#include <cassert>
+#include "CoinTypes.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinDenseFactorization.hpp"
+class CoinPackedMatrix;
+/** This deals with Factorization and Updates
+    This is ripped off from OSL!!!!!!!!!
+
+    I am assuming that 32 bits is enough for number of rows or columns, but CoinBigIndex
+    may be redefined to get 64 bits.
+ */
+
+typedef struct {int suc, pre;} EKKHlink;
+typedef struct _EKKfactinfo {
+  double drtpiv;
+  double demark;
+  double zpivlu;
+  double zeroTolerance;
+  double areaFactor;
+  int *xrsadr;
+  int *xcsadr;
+  int *xrnadr;
+  int *xcnadr;
+  int *krpadr;
+  int *kcpadr;
+  int *mpermu;
+  int *bitArray;
+  int * back;
+  char * nonzero;
+  double * trueStart;
+  mutable double *kadrpm;
+  int *R_etas_index;
+  int *R_etas_start;
+  double *R_etas_element;
+
+  int *xecadr;
+  int *xeradr;
+  double *xeeadr;
+  double *xe2adr;
+  EKKHlink * kp1adr;
+  EKKHlink * kp2adr;
+  double * kw1adr;
+  double * kw2adr;
+  double * kw3adr;
+  int * hpivcoR;
+  int nrow;
+  int nrowmx;
+  int firstDoRow;
+  int firstLRow;
+  int maxinv;
+  int nnetas;
+  int iterin;
+  int iter0;
+  int invok;
+  int nbfinv;
+  int num_resets;
+  int nnentl;
+  int nnentu;
+#ifdef CLP_REUSE_ETAS
+  int save_nnentu;
+#endif
+  int ndenuc;
+  int npivots; /* use as xpivsq in factorization */
+  int kmxeta;
+  int xnetal;
+  int first_dense;
+  int last_dense;
+  int iterno;
+  int numberSlacks;
+  int lastSlack;
+  int firstNonSlack;
+  int xnetalval;
+  int lstart;
+  int if_sparse_update;
+  mutable int packedMode;
+  int switch_off_sparse_update;
+  int nuspike;
+  bool rows_ok;	/* replaces test using mrstrt[1] */
+#ifdef CLP_REUSE_ETAS
+  mutable int reintro;
+#endif
+  int nR_etas;
+  int sortedEta; /* if vector for F-T is sorted */
+  int lastEtaCount;
+  int ifvsol;
+  int eta_size;
+  int last_eta_size;
+  int maxNNetas;
+} EKKfactinfo;
+
+class CoinOslFactorization : public CoinOtherFactorization {
+   friend void CoinOslFactorizationUnitTest( const std::string & mpsDir );
+
+public:
+
+  /**@name Constructors and destructor and copy */
+  //@{
+  /// Default constructor
+  CoinOslFactorization (  );
+  /// Copy constructor 
+  CoinOslFactorization ( const CoinOslFactorization &other);
+  
+  /// Destructor
+  virtual ~CoinOslFactorization (  );
+  /// = copy
+  CoinOslFactorization & operator = ( const CoinOslFactorization & other );
+  /// Clone
+  virtual CoinOtherFactorization * clone() const ;
+  //@}
+
+  /**@name Do factorization - public */
+  //@{
+  /// Gets space for a factorization
+  virtual void getAreas ( int numberRows,
+		  int numberColumns,
+		  CoinBigIndex maximumL,
+		  CoinBigIndex maximumU );
+  
+  /// PreProcesses column ordered copy of basis
+  virtual void preProcess ( );
+  /** Does most of factorization returning status
+      0 - OK
+      -99 - needs more memory
+      -1 - singular - use numberGoodColumns and redo
+  */
+  virtual int factor ( );
+  /// Does post processing on valid factorization - putting variables on correct rows
+  virtual void postProcess(const int * sequence, int * pivotVariable);
+  /// Makes a non-singular basis by replacing variables
+  virtual void makeNonSingular(int * sequence, int numberColumns);
+  /** When part of LP - given by basic variables.
+  Actually does factorization.
+  Arrays passed in have non negative value to say basic.
+  If status is okay, basic variables have pivot row - this is only needed
+  If status is singular, then basic variables have pivot row
+  and ones thrown out have -1
+  returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
+  int factorize ( const CoinPackedMatrix & matrix, 
+		  int rowIsBasic[], int columnIsBasic[] , 
+		  double areaFactor = 0.0 );
+  //@}
+
+  /**@name general stuff such as number of elements */
+  //@{ 
+  /// Total number of elements in factorization
+  virtual inline int numberElements (  ) const {
+    return numberRows_*(numberColumns_+numberPivots_);
+  }
+  /// Returns array to put basis elements in
+  virtual CoinFactorizationDouble * elements() const;
+  /// Returns pivot row 
+  virtual int * pivotRow() const;
+  /// Returns work area
+  virtual CoinFactorizationDouble * workArea() const;
+  /// Returns int work area
+  virtual int * intWorkArea() const;
+  /// Number of entries in each row
+  virtual int * numberInRow() const;
+  /// Number of entries in each column
+  virtual int * numberInColumn() const;
+  /// Returns array to put basis starts in
+  virtual CoinBigIndex * starts() const;
+  /// Returns permute back
+  virtual int * permuteBack() const;
+  /// Returns true if wants tableauColumn in replaceColumn
+  virtual bool wantsTableauColumn() const;
+  /** Useful information for factorization
+      0 - iteration number
+      whereFrom is 0 for factorize and 1 for replaceColumn
+  */
+  virtual void setUsefulInformation(const int * info,int whereFrom);
+  /// Set maximum pivots
+  virtual void maximumPivots (  int value );
+
+  /// Returns maximum absolute value in factorization
+  double maximumCoefficient() const;
+  /// Condition number - product of pivots after factorization
+  double conditionNumber() const;
+  /// Get rid of all memory
+  virtual void clearArrays();
+  //@}
+
+  /**@name rank one updates which do exist */
+  //@{
+
+  /** Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+      If checkBeforeModifying is true will do all accuracy checks
+      before modifying factorization.  Whether to set this depends on
+      speed considerations.  You could just do this on first iteration
+      after factorization and thereafter re-factorize
+   partial update already in U */
+  virtual int replaceColumn ( CoinIndexedVector * regionSparse,
+		      int pivotRow,
+		      double pivotCheck ,
+			      bool checkBeforeModifying=false,
+			      double acceptablePivot=1.0e-8);
+  //@}
+
+  /**@name various uses of factorization (return code number elements) 
+   which user may want to know about */
+  //@{
+  /** Updates one column (FTRAN) from regionSparse2
+      Tries to do FT update
+      number returned is negative if no room
+      regionSparse starts as zero and is zero at end.
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+  virtual int updateColumnFT ( CoinIndexedVector * regionSparse,
+				      CoinIndexedVector * regionSparse2,
+				      bool noPermute=false);
+  /** This version has same effect as above with FTUpdate==false
+      so number returned is always >=0 */
+  virtual int updateColumn ( CoinIndexedVector * regionSparse,
+		     CoinIndexedVector * regionSparse2,
+		     bool noPermute=false) const;
+    /// does FTRAN on two columns
+    virtual int updateTwoColumnsFT(CoinIndexedVector * regionSparse1,
+			   CoinIndexedVector * regionSparse2,
+			   CoinIndexedVector * regionSparse3,
+			   bool noPermute=false);
+  /** Updates one column (BTRAN) from regionSparse2
+      regionSparse starts as zero and is zero at end 
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+  virtual int updateColumnTranspose ( CoinIndexedVector * regionSparse,
+			      CoinIndexedVector * regionSparse2) const;
+  //@}
+  /// *** Below this user may not want to know about
+
+  /**@name various uses of factorization
+   which user may not want to know about (left over from my LP code) */
+  //@{
+  /// Get rid of all memory
+  //inline void clearArrays()
+  //{ gutsOfDestructor();}
+  /// Returns array to put basis indices in
+  virtual int * indices() const;
+  /// Returns permute in
+  virtual inline int * permute() const
+  { return NULL;/*pivotRow_*/;}
+  //@}
+
+  /// The real work of desstructor 
+  void gutsOfDestructor(bool clearFact=true);
+  /// The real work of constructor
+  void gutsOfInitialize(bool zapFact=true);
+  /// The real work of copy
+  void gutsOfCopy(const CoinOslFactorization &other);
+
+  //@}
+protected:
+  /** Returns accuracy status of replaceColumn
+      returns 0=OK, 1=Probably OK, 2=singular */
+  int checkPivot(double saveFromU, double oldPivot) const;
+////////////////// data //////////////////
+protected:
+
+  /**@name data */
+  //@{
+  /// Osl factorization data
+  EKKfactinfo factInfo_;
+  //@}
+};
+#endif
diff --git a/cbits/coin/CoinOslFactorization2.cpp b/cbits/coin/CoinOslFactorization2.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinOslFactorization2.cpp
@@ -0,0 +1,4207 @@
+/* $Id: CoinOslFactorization2.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+/*
+  Copyright (C) 1987, 2009, International Business Machines
+  Corporation and others.  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+/*
+  CLP_OSL - if defined use osl
+  0 - don't unroll 2 and 3 - don't use in Gomory
+  1 - don't unroll - do use in Gomory
+  2 - unroll - don't use in Gomory
+  3 - unroll and use in Gomory
+*/
+#include "CoinOslFactorization.hpp"
+#include "CoinOslC.h"
+#include "CoinFinite.hpp"
+
+#ifndef NDEBUG
+extern int ets_count;
+extern int ets_check;
+#endif
+#define COIN_REGISTER register
+#define COIN_REGISTER2
+#define COIN_REGISTER3 register
+#ifdef COIN_USE_RESTRICT
+# define COIN_RESTRICT2 __restrict
+#else
+# define COIN_RESTRICT2
+#endif
+static int c_ekkshfpo_scan2zero(COIN_REGISTER const EKKfactinfo * COIN_RESTRICT2 fact,const int * COIN_RESTRICT mpermu,
+		       double *COIN_RESTRICT worki, double *COIN_RESTRICT worko, int * COIN_RESTRICT mptr)
+{
+  
+  /* Local variables */
+  int irow;
+  double tolerance = fact->zeroTolerance;
+  int nin=fact->nrow;
+  int * COIN_RESTRICT mptrX=mptr;
+  if ((nin&1)!=0) {
+    irow=1;
+    if (fact->packedMode) {
+      int irow0= *mpermu;
+      double dval;
+      assert (irow0>=1&&irow0<=nin);
+      mpermu++;
+      dval=worki[irow0];
+      if (NOT_ZERO(dval)) {
+	worki[irow0]=0.0;
+	if (fabs(dval) >= tolerance) {
+	  *(worko++)=dval;
+	  *(mptrX++) = 0;
+	}
+      }
+    } else {
+      int irow0= *mpermu;
+      double dval;
+      assert (irow0>=1&&irow0<=nin);
+      mpermu++;
+      dval=worki[irow0];
+      if (NOT_ZERO(dval)) {
+	worki[irow0]=0.0;
+	if (fabs(dval) >= tolerance) {
+	  *worko=dval;
+	  *(mptrX++) = 0;
+	}
+      }
+      worko++;
+    }
+  } else {
+    irow=0;
+  }
+  if (fact->packedMode) {
+    for (; irow < nin; irow+=2) {
+      int irow0,irow1;
+      double dval0,dval1;
+      irow0=mpermu[0];
+      irow1=mpermu[1];
+      assert (irow0>=1&&irow0<=nin);
+      assert (irow1>=1&&irow1<=nin);
+      dval0=worki[irow0];
+      dval1=worki[irow1];
+      if (NOT_ZERO(dval0)) {
+	worki[irow0]=0.0;
+	if (fabs(dval0) >= tolerance) {
+	  *(worko++)=dval0;
+	  *(mptrX++) = irow+0;
+	}
+      }
+      if (NOT_ZERO(dval1)) {
+	worki[irow1]=0.0;
+	if (fabs(dval1) >= tolerance) {
+	  *(worko++)=dval1;
+	  *(mptrX++) = irow+1;
+	}
+      }
+      mpermu+=2;
+    }
+  } else {
+    for (; irow < nin; irow+=2) {
+      int irow0,irow1;
+      double dval0,dval1;
+      irow0=mpermu[0];
+      irow1=mpermu[1];
+      assert (irow0>=1&&irow0<=nin);
+      assert (irow1>=1&&irow1<=nin);
+      dval0=worki[irow0];
+      dval1=worki[irow1];
+      if (NOT_ZERO(dval0)) {
+	worki[irow0]=0.0;
+	if (fabs(dval0) >= tolerance) {
+	  worko[0]=dval0;
+	  *(mptrX++) = irow+0;
+	}
+      }
+      if (NOT_ZERO(dval1)) {
+	worki[irow1]=0.0;
+	if (fabs(dval1) >= tolerance) {
+	  worko[1]=dval1;
+	  *(mptrX++) = irow+1;
+	}
+      }
+      mpermu+=2;
+      worko+=2;
+    }
+  }
+  return static_cast<int>(mptrX-mptr);
+}
+/*
+ * c_ekkshfpi_list executes the following loop:
+ *
+ * for (k=nincol, i=1; k; k--, i++) {
+ *   int ipt = mptr[i];
+ *   int irow = mpermu[ipt]; 
+ *   worko[mpermu[irow]] = worki[i];
+ *   worki[i] = 0.0;
+ * }
+ */
+static int c_ekkshfpi_list(const int *COIN_RESTRICT mpermu, 
+			   double *COIN_RESTRICT worki, 
+			   double *COIN_RESTRICT worko,
+			   const int * COIN_RESTRICT mptr, int nincol,
+			   int * lastNonZero)
+{
+  int i,k,irow0,irow1;
+  int first=COIN_INT_MAX;
+  int last=0;
+  /* worko was zeroed out outside */
+  k = nincol;
+  i = 0;
+  if ((k&1)!=0) {
+    int ipt=mptr[i];
+    irow0=mpermu[ipt];
+    first = CoinMin(irow0,first);
+    last = CoinMax(irow0,last);
+    i++;
+    worko[irow0]=*worki;
+    *worki++=0.0;
+  }
+  k=k>>1;
+  for (; k; k--) {
+    int ipt0 = mptr[i];
+    int ipt1 = mptr[i+1];
+    irow0 = mpermu[ipt0];
+    irow1 = mpermu[ipt1];
+    i+=2;
+    first = CoinMin(irow0,first);
+    last = CoinMax(irow0,last);
+    first = CoinMin(irow1,first);
+    last = CoinMax(irow1,last);
+    worko[irow0] = worki[0];
+    worko[irow1] = worki[1];
+    worki[0]=0.0;
+    worki[1]=0.0;
+    worki+=2;
+  }
+  *lastNonZero=last;
+  return first;
+}
+/*
+ * c_ekkshfpi_list2 executes the following loop:
+ *
+ * for (k=nincol, i=1; k; k--, i++) {
+ *   int ipt = mptr[i];
+ *   int irow = mpermu[ipt]; 
+ *   worko[mpermu[irow]] = worki[ipt];
+ *   worki[ipt] = 0.0;
+ * }
+ */
+static int c_ekkshfpi_list2(const int *COIN_RESTRICT mpermu, double *COIN_RESTRICT worki, double *COIN_RESTRICT worko,
+			    const int * COIN_RESTRICT mptr, int nincol,
+			   int * lastNonZero)
+{
+#if 1
+  int i,k,irow0,irow1;
+  int first=COIN_INT_MAX;
+  int last=0;
+  /* worko was zeroed out outside */
+  k = nincol;
+  i = 0;
+  if ((k&1)!=0) {
+    int ipt=mptr[i];
+    irow0=mpermu[ipt];
+    first = CoinMin(irow0,first);
+    last = CoinMax(irow0,last);
+    i++;
+    worko[irow0]=worki[ipt];
+    worki[ipt]=0.0;
+  }
+  k=k>>1;
+  for (; k; k--) {
+    int ipt0 = mptr[i];
+    int ipt1 = mptr[i+1];
+    irow0 = mpermu[ipt0];
+    irow1 = mpermu[ipt1];
+    i+=2;
+    first = CoinMin(irow0,first);
+    last = CoinMax(irow0,last);
+    first = CoinMin(irow1,first);
+    last = CoinMax(irow1,last);
+    worko[irow0] = worki[ipt0];
+    worko[irow1] = worki[ipt1];
+    worki[ipt0]=0.0;
+    worki[ipt1]=0.0;
+  }
+#else
+  int first=COIN_INT_MAX;
+  int last=0;
+  /* worko was zeroed out outside */
+  for (int i=0; i<nincol; i++) {
+    int ipt = mptr[i];
+    int irow = mpermu[ipt];
+    first = CoinMin(irow,first);
+    last = CoinMax(irow,last);
+    worko[irow] = worki[ipt];
+    worki[ipt]=0.0;
+  }
+#endif
+  *lastNonZero=last;
+  return first;
+}
+/*
+ * c_ekkshfpi_list3 executes the following loop:
+ *
+ * for (k=nincol, i=1; k; k--, i++) {
+ *   int ipt  = mptr[i];
+ *   int irow = mpermu[ipt];
+ *   worko[irow] = worki[i];
+ *   worki[i] = 0.0;
+ *   mptr[i] = mpermu[ipt];
+ * }
+ */
+static void c_ekkshfpi_list3(const int *COIN_RESTRICT mpermu,
+		    double *COIN_RESTRICT worki, double *COIN_RESTRICT worko,
+		    int * COIN_RESTRICT mptr, int nincol)
+{
+  int i,k,irow0,irow1;
+  /* worko was zeroed out outside */
+  k = nincol;
+  i = 0;
+  if ((k&1)!=0) {
+    int ipt=mptr[i];
+    irow0=mpermu[ipt];
+    mptr[i] = irow0;
+    i++;
+    worko[irow0]=*worki;
+    *worki++=0.0;
+  }
+  k=k>>1;
+  for (; k; k--) {
+    int ipt0 = mptr[i];
+    int ipt1 = mptr[i+1];
+    irow0 = mpermu[ipt0];
+    irow1 = mpermu[ipt1];
+    mptr[i] = irow0;
+    mptr[i+1] = irow1;
+    i+=2;
+    worko[irow0] = worki[0];
+    worko[irow1] = worki[1];
+    worki[0]=0.0;
+    worki[1]=0.0;
+    worki+=2;
+  }
+}
+static int c_ekkscmv(COIN_REGISTER const EKKfactinfo * COIN_RESTRICT2 fact,int n, double *COIN_RESTRICT dwork, int *COIN_RESTRICT mptr, 
+		   double *COIN_RESTRICT dwork2)
+{
+  double tolerance = fact->zeroTolerance;
+  int irow;
+  const int * COIN_RESTRICT mptrsave = mptr;
+  double * COIN_RESTRICT dwhere = dwork+1;
+  if ((n&1)!=0) {
+    if (NOT_ZERO(*dwhere)) {
+      if (fabs(*dwhere) >= tolerance) {
+	*++dwork2 = *dwhere;
+	*++mptr = SHIFT_INDEX(1);
+      } else {
+	*dwhere = 0.0;
+      }
+    }
+    dwhere++;
+    irow=2;
+  } else {
+    irow=1;
+  }
+  for (n=n>>1;n;n--) {
+    int second = NOT_ZERO(*(dwhere+1));
+    if (NOT_ZERO(*dwhere)) {
+      if (fabs(*dwhere) >= tolerance) {
+	*++dwork2 = *dwhere;
+	*++mptr = SHIFT_INDEX(irow);
+      } else {
+	*dwhere = 0.0;
+      }
+    }
+    if (second) {
+      if (fabs(*(dwhere+1)) >= tolerance) {
+	*++dwork2 = *(dwhere+1);
+	*++mptr = SHIFT_INDEX(irow+1);
+      } else {
+	*(dwhere+1) = 0.0;
+      }
+    }
+    dwhere+=2;
+    irow+=2;
+  }
+  
+  return static_cast<int>(mptr-mptrsave);
+} /* c_ekkscmv */
+double c_ekkputl(const EKKfactinfo * COIN_RESTRICT2 fact,
+	     const int *COIN_RESTRICT mpt2,
+	     double *COIN_RESTRICT dwork1,
+	     double del3, 
+	     int nincol, int nuspik)
+{
+  double * COIN_RESTRICT dwork3	= fact->xeeadr+fact->nnentu;
+  int * COIN_RESTRICT hrowi	= fact->xeradr+fact->nnentu;
+  int offset = fact->R_etas_start[fact->nR_etas+1];
+  int *COIN_RESTRICT hrowiR = fact->R_etas_index+offset;
+  double *COIN_RESTRICT dluval = fact->R_etas_element+offset;
+  int i, j;
+  
+  /* dwork1 is r', the new R transform
+   * dwork3 is the updated incoming column, alpha_p
+   * del3 apparently has the pivot of the incoming column (???).
+   * Here, we compute the p'th element of R^-1 alpha_p
+   * (as described on p. 273), which is just a dot product.
+   * I don't know why we subtract.
+   */
+  for (i = 1; i <= nuspik; ++i) {
+    j = UNSHIFT_INDEX(hrowi[ i]);
+    del3 -= dwork3[i] * dwork1[j];
+  }
+  
+  /* here we finally copy the r' to where we want it, the end */
+  /* also take into account that the p'th row of R^-1 is -(p'th row of R). */
+  /* also zero out dwork1 as we go */
+  for (i = 0; i < nincol; ++i) {
+    j = mpt2[i];
+    hrowiR[ - i ] = SHIFT_INDEX(j);
+    dluval[ - i ] = -dwork1[j];
+    dwork1[j] = 0.;
+  }
+  
+  return del3;
+} /* c_ekkputl */
+/* making this static seems to slow code down!
+   may be being inlined
+*/
+int c_ekkputl2( const EKKfactinfo * COIN_RESTRICT2 fact,
+	     double *COIN_RESTRICT dwork1,
+	     double *del3p, 
+	     int nuspik)
+{
+  double * COIN_RESTRICT dwork3	= fact->xeeadr+fact->nnentu;
+  int * COIN_RESTRICT hrowi	= fact->xeradr+fact->nnentu;
+  int offset = fact->R_etas_start[fact->nR_etas+1];
+  int *COIN_RESTRICT hrowiR = fact->R_etas_index+offset;
+  double *COIN_RESTRICT dluval = fact->R_etas_element+offset;
+  int i, j;
+#if 0
+  int nincol=c_ekksczr(fact,fact->nrow,dwork1,hrowiR);
+#else
+  int nrow=fact->nrow;
+  const double tolerance = fact->zeroTolerance;
+  int * COIN_RESTRICT mptrX=hrowiR;
+  for (i = 1; i <= nrow; ++i) {
+    if (dwork1[i] != 0.) {
+      if (fabs(dwork1[i]) >= tolerance) {
+	*(mptrX--) = SHIFT_INDEX(i);
+      } else {
+	dwork1[i] = 0.0;
+      }
+    }
+  }
+  int nincol=static_cast<int>(hrowiR-mptrX);
+#endif
+  double del3 = *del3p;
+  /* dwork1 is r', the new R transform
+   * dwork3 is the updated incoming column, alpha_p
+   * del3 apparently has the pivot of the incoming column (???).
+   * Here, we compute the p'th element of R^-1 alpha_p
+   * (as described on p. 273), which is just a dot product.
+   * I don't know why we subtract.
+   */
+  for (i = 1; i <= nuspik; ++i) {
+    j = UNSHIFT_INDEX(hrowi[ i]);
+    del3 -= dwork3[i] * dwork1[j];
+  }
+  
+  /* here we finally copy the r' to where we want it, the end */
+  /* also take into account that the p'th row of R^-1 is -(p'th row of R). */
+  /* also zero out dwork1 as we go */
+  for (i = 0; i < nincol; ++i) {
+    j = UNSHIFT_INDEX(hrowiR[-i]);
+    dluval[ - i ] = -dwork1[j];
+    dwork1[j] = 0.;
+  }
+  
+  *del3p = del3;
+  return nincol;
+} /* c_ekkputl */
+static void c_ekkbtj4p_no_dense(const int nrow,const double * COIN_RESTRICT dluval, 
+				const int * COIN_RESTRICT hrowi,
+				const int * COIN_RESTRICT mcstrt,  
+				double * COIN_RESTRICT dwork1, int ndo,int jpiv)
+{
+  int i;
+  double dv1;
+  int iel;
+  int irow;
+  int i1,i2;
+  
+  /* count down to first nonzero */
+  for (i=nrow;i >=1;i--) {
+    if (dwork1[i]) {
+      break;
+    }
+  }
+  i--; /* as pivot is just 1.0 */
+  if (i>ndo+jpiv) {
+    i=ndo+jpiv;
+  }
+  mcstrt -= jpiv;
+  i2=mcstrt[i+1];
+  for (; i > jpiv; --i) {
+    double dv1b=0.0;
+    int nel;
+    i1 = mcstrt[i];
+    nel= i1-i2;
+    dv1 = dwork1[i];
+    iel=i2;
+    if ((nel&1)!=0) {
+      irow = hrowi[iel];
+      dv1b = SHIFT_REF(dwork1, irow) * dluval[iel];
+      iel++;
+    }
+    for ( ; iel < i1; iel+=2) {
+      int irow = hrowi[iel];
+      int irowb = hrowi[iel+1];
+      dv1 += SHIFT_REF(dwork1, irow) * dluval[iel];
+      dv1b += SHIFT_REF(dwork1, irowb) * dluval[iel+1];
+    }
+    i2=i1;
+    dwork1[i] = dv1+dv1b;
+  }
+} /* c_ekkbtj4 */
+
+static int c_ekkbtj4p_dense(const int nrow,const double * COIN_RESTRICT dluval,
+			    const int * COIN_RESTRICT hrowi,
+			    const int * COIN_RESTRICT mcstrt,  double * COIN_RESTRICT dwork1,
+		   int ndenuc,
+		   int ndo,int jpiv)
+{
+  int i;
+  int i2;
+  
+  int last=ndo-ndenuc+1;
+  double * COIN_RESTRICT densew = &dwork1[nrow-1];
+  int nincol=0;
+  const double * COIN_RESTRICT dlu1;
+  dluval--;
+  hrowi--;
+  /* count down to first nonzero */
+  for (i=nrow;i >=1;i--) {
+    if (dwork1[i]) {
+      break;
+    }
+  }
+  if (i<ndo+jpiv) {
+    int diff = ndo+jpiv-i;
+    ndo -= diff;
+    densew-=diff;
+    nincol=diff;
+  }
+  i2=mcstrt[ndo+1];
+  dlu1=&dluval[i2+1];
+  for (i = ndo; i >last; i-=2) {
+    int k;
+    double dv1,dv2;
+    const double * COIN_RESTRICT dlu2;
+    dv1=densew[1];
+    dlu2=dlu1+nincol;
+    dv2=densew[0];
+    for (k=0;k<nincol;k++) {
+#ifdef DEBUG
+      int kk=dlu1-dluval;
+      int jj = (densew+(nincol-k+1))-dwork1;
+      int ll=hrowi[k+kk];
+      if (ll!=jj) abort();
+#endif
+      dv1 += densew[nincol-k+1]*dlu1[k];
+      dv2 += densew[nincol-k+1]*dlu2[k];
+    }
+    densew[1]=dv1;
+    dlu1=dlu2+nincol;
+    dv2 += dv1*dlu1[0];
+    dlu1++;
+    nincol+=2;
+    densew[0]=dv2;
+    densew-=2;
+  }
+  return i;
+} /* c_ekkbtj4 */
+
+static void c_ekkbtj4p_after_dense(const double * COIN_RESTRICT dluval, 
+				   const int * COIN_RESTRICT hrowi,
+				   const int * COIN_RESTRICT mcstrt,  
+				   double * COIN_RESTRICT dwork1, int i,int jpiv)
+{
+  int iel;
+  mcstrt -= jpiv;
+  i += jpiv;
+  iel=mcstrt[i+1];
+  for (; i > jpiv+1; i-=2) {
+    int i1 = mcstrt[i];
+    double dv1 = dwork1[i];
+    double dv2;
+    for (; iel < i1; iel++) {
+      int irow = hrowi[iel];
+      dv1 += SHIFT_REF(dwork1, irow) * dluval[iel];
+    }
+    i1 = mcstrt[i-1];
+    dv2 = dwork1[i-1];
+    dwork1[i] = dv1;
+    for (; iel < i1; iel++) {
+      int irow = hrowi[iel];
+      dv2 += SHIFT_REF(dwork1, irow) * dluval[iel];
+    }
+    dwork1[i-1] = dv2;
+  }
+  if (i>jpiv) {
+    int i1 = mcstrt[i];
+    double dv1 = dwork1[i];
+    for (; iel < i1; iel++) {
+      int irow = hrowi[iel];
+      dv1 += SHIFT_REF(dwork1, irow) * dluval[iel];
+    }
+    dwork1[i] = dv1;
+  }
+}
+
+static void c_ekkbtj4p(COIN_REGISTER const EKKfactinfo * COIN_RESTRICT2 fact,
+	      double * COIN_RESTRICT dwork1)
+{
+  int lstart=fact->lstart;
+  const int * COIN_RESTRICT hpivco	= fact->kcpadr;
+  const double * COIN_RESTRICT dluval	= fact->xeeadr+1;
+  const int * COIN_RESTRICT hrowi	= fact->xeradr+1;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr+lstart-1;
+  int jpiv=hpivco[lstart]-1;
+  int ndo=fact->xnetalval;
+  /*     see if dense enough to unroll */
+  if (fact->ndenuc<5) {
+    c_ekkbtj4p_no_dense(fact->nrow,dluval,hrowi,mcstrt,dwork1,ndo,jpiv);
+  } else {
+    int i = c_ekkbtj4p_dense(fact->nrow,dluval,hrowi,mcstrt,dwork1,
+			   fact->ndenuc, ndo,jpiv);
+    c_ekkbtj4p_after_dense(dluval,hrowi,mcstrt,dwork1,i,jpiv);
+  }
+} /* c_ekkbtj4p */
+
+static int c_ekkbtj4_sparse(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+			  double * COIN_RESTRICT dwork1, 
+			  int * COIN_RESTRICT mpt,	/* C style */
+			  double * COIN_RESTRICT dworko,
+			  int nincol, int * COIN_RESTRICT spare)
+{
+  const int nrow		= fact->nrow;
+  const int * COIN_RESTRICT hcoli	= fact->xecadr;
+  const int * COIN_RESTRICT mrstrt	= fact->xrsadr+nrow;
+  char * COIN_RESTRICT nonzero = fact->nonzero;
+  const int * COIN_RESTRICT hpivro	= fact->krpadr;
+  const double * COIN_RESTRICT de2val	= fact->xe2adr-1;
+  double tolerance = fact->zeroTolerance;
+  double dv;
+  int iel;
+  
+  int k,nStack,kx;
+  int nList=0;
+  int * COIN_RESTRICT list = spare;
+  int * COIN_RESTRICT stack = spare+nrow;
+  int * COIN_RESTRICT next = stack+nrow;
+  int iPivot,kPivot;
+  int iput,nput=0,kput=nrow;
+  int j;
+  int firstDoRow=fact->firstDoRow;
+  
+  for (k=0;k<nincol;k++) {
+    nStack=1;
+    iPivot=mpt[k];
+    if (nonzero[iPivot]!=1&&iPivot>=firstDoRow) {
+      stack[0]=iPivot;
+      next[0]=mrstrt[iPivot];
+      while (nStack) {
+	/* take off stack */
+	kPivot=stack[--nStack];
+	if (nonzero[kPivot]!=1&&kPivot>=firstDoRow) {
+	  j=next[nStack];
+	  if (j==mrstrt[kPivot+1]) {
+	    /* finished so mark */
+	    list[nList++]=kPivot;
+	    nonzero[kPivot]=1;
+	  } else {
+	    kPivot=hcoli[j];
+	    /* put back on stack */
+	    next[nStack++] ++;
+	    if (!nonzero[kPivot]) {
+	      /* and new one */
+	      stack[nStack]=kPivot;
+	      nonzero[kPivot]=2;
+	      next[nStack++]=mrstrt[kPivot];
+	    }
+	  }
+	} else if (kPivot<firstDoRow) {
+	  list[--kput]=kPivot;
+	  nonzero[kPivot]=1;
+	}
+      }
+    } else if (nonzero[iPivot]!=1) {
+      /* nothing to do (except check size at end) */
+      list[--kput]=iPivot;
+      nonzero[iPivot]=1;
+    }
+  }
+  if (fact->packedMode) {
+    dworko++;
+    for (k=nList-1;k>=0;k--) {
+      double dv;
+      iPivot = list[k];
+      dv = dwork1[iPivot];
+      dwork1[iPivot]=0.0;
+      nonzero[iPivot]=0;
+      if (fabs(dv) > tolerance) {
+	iput=hpivro[iPivot];
+	kx=mrstrt[iPivot];
+	dworko[nput]=dv;
+	for (iel = kx; iel < mrstrt[iPivot+1]; iel++) {
+	  double dval;
+	  int irow = hcoli[iel];
+	  dval=de2val[iel];
+	  dwork1[irow] += dv*dval;
+	}
+	mpt[nput++]=iput-1;
+      } else {
+	dwork1[iPivot]=0.0;	/* force to zero, not just near zero */
+      }
+    }
+    /* check remainder */
+    for (k=kput;k<nrow;k++) {
+      iPivot = list[k];
+      nonzero[iPivot]=0;
+      dv = dwork1[iPivot];
+      dwork1[iPivot]=0.0;
+      iput=hpivro[iPivot];
+      if (fabs(dv) > tolerance) {
+	dworko[nput]=dv;
+	mpt[nput++]=iput-1;
+      }
+    }
+  } else {
+    /* not packed */
+    for (k=nList-1;k>=0;k--) {
+      double dv;
+      iPivot = list[k];
+      dv = dwork1[iPivot];
+      dwork1[iPivot]=0.0;
+      nonzero[iPivot]=0;
+      if (fabs(dv) > tolerance) {
+	iput=hpivro[iPivot];
+	kx=mrstrt[iPivot];
+	dworko[iput]=dv;
+	for (iel = kx; iel < mrstrt[iPivot+1]; iel++) {
+	  double dval;
+	  int irow = hcoli[iel];
+	  dval=de2val[iel];
+	  dwork1[irow] += dv*dval;
+	}
+	mpt[nput++]=iput-1;
+      } else {
+	dwork1[iPivot]=0.0;	/* force to zero, not just near zero */
+      }
+    }
+    /* check remainder */
+    for (k=kput;k<nrow;k++) {
+      iPivot = list[k];
+      nonzero[iPivot]=0;
+      dv = dwork1[iPivot];
+      dwork1[iPivot]=0.0;
+      iput=hpivro[iPivot];
+      if (fabs(dv) > tolerance) {
+	dworko[iput]=dv;
+	mpt[nput++]=iput-1;
+      }
+    }
+  }
+  
+  return (nput);
+} /* c_ekkbtj4 */
+
+static void c_ekkbtjl(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+		    double * COIN_RESTRICT dwork1)
+{
+  int i, j, k, k1;
+  int l1;
+  const double * COIN_RESTRICT dluval = fact->R_etas_element;
+  const int * COIN_RESTRICT hrowi = fact->R_etas_index;
+  const int * COIN_RESTRICT mcstrt = fact->R_etas_start;
+  const int * COIN_RESTRICT hpivco = fact->hpivcoR;
+  int ndo=fact->nR_etas;
+#ifndef UNROLL1
+#define UNROLL1 4
+#endif
+#if UNROLL1>2
+  int l2;
+#endif
+  int kn;
+  double dv;
+  int iel;
+  int ipiv;
+  int knext;
+  
+  knext = mcstrt[ndo + 1];
+#if UNROLL1>2
+  for (i = ndo; i > 0; --i) {
+    k1 = knext;
+    knext = mcstrt[i];
+    ipiv = hpivco[i];
+    dv = dwork1[ipiv];
+    /*       fast floating */
+    k = knext - k1;
+    kn = k >> 2;
+    iel = k1 + 1;
+    if (dv != 0.) {
+      l1 = (k & 1) != 0;
+      l2 = (k & 2) != 0;
+      for (j = 1; j <= kn; j++) {
+	int irow0 = hrowi[iel + 0];
+	int irow1 = hrowi[iel + 1];
+	int irow2 = hrowi[iel + 2];
+	int irow3 = hrowi[iel + 3];
+	double dval0 = dv * dluval[iel + 0] + SHIFT_REF(dwork1, irow0);
+	double dval1 = dv * dluval[iel + 1] + SHIFT_REF(dwork1, irow1);
+	double dval2 = dv * dluval[iel + 2] + SHIFT_REF(dwork1, irow2);
+	double dval3 = dv * dluval[iel + 3] + SHIFT_REF(dwork1, irow3);
+	SHIFT_REF(dwork1, irow0) = dval0;
+	SHIFT_REF(dwork1, irow1) = dval1;
+	SHIFT_REF(dwork1, irow2) = dval2;
+	SHIFT_REF(dwork1, irow3) = dval3;
+	iel+=4;
+      }
+      if (l1) {
+	int irow0 = hrowi[iel];
+	SHIFT_REF(dwork1, irow0) += dv* dluval[iel];
+	++iel;
+      }
+      if (l2) {
+	int irow0 = hrowi[iel + 0];
+	int irow1 = hrowi[iel + 1];
+	SHIFT_REF(dwork1, irow0) += dv* dluval[iel];
+	SHIFT_REF(dwork1, irow1) += dv* dluval[iel+1];
+      }
+    }
+  }
+#else
+  for (i = ndo; i > 0; --i) {
+    k1 = knext;
+    knext = mcstrt[i];
+    ipiv = hpivco[i];
+    dv = dwork1[ipiv];
+    k = knext - k1;
+    kn = k >> 1;
+    iel = k1 + 1;
+    if (dv != 0.) {
+      l1 = (k & 1) != 0;
+      for (j = 1; j <= kn; j++) {
+	int irow0 = hrowi[iel + 0];
+	int irow1 = hrowi[iel + 1];
+	double dval0 = dv * dluval[iel + 0] + SHIFT_REF(dwork1, irow0);
+	double dval1 = dv * dluval[iel + 1] + SHIFT_REF(dwork1, irow1);
+	SHIFT_REF(dwork1, irow0) = dval0;
+	SHIFT_REF(dwork1, irow1) = dval1;
+	iel+=2;
+      }
+      if (l1) {
+	int irow0 = hrowi[iel];
+	SHIFT_REF(dwork1, irow0) += dv* dluval[iel];
+	++iel;
+      }
+    }
+  }
+#endif
+} /* c_ekkbtjl */
+
+static int c_ekkbtjl_sparse(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+		   double * COIN_RESTRICT dwork1, 
+		   int * COIN_RESTRICT mpt , int nincol)
+{
+  const double * COIN_RESTRICT dluval = fact->R_etas_element;
+  const int * COIN_RESTRICT hrowi = fact->R_etas_index;
+  const int * COIN_RESTRICT mcstrt = fact->R_etas_start;
+  const int * COIN_RESTRICT hpivco = fact->hpivcoR;
+  char * COIN_RESTRICT nonzero = fact->nonzero;
+  int ndo=fact->nR_etas;
+  int i, j, k1;
+  double dv;
+  int ipiv;
+  int irow0, irow1;
+  int knext;
+  int number=nincol;
+  
+  /*     ------------------------------------------- */
+  /* adjust back */
+  hrowi++;
+  dluval++;
+  
+  /*         DO ANY ROW TRANSFORMATIONS */
+  
+  /* Function Body */
+  knext = mcstrt[ndo + 1];
+  for (i = ndo; i > 0; --i) {
+    k1 = knext;
+    knext = mcstrt[i];
+    ipiv = hpivco[i];
+    dv = dwork1[ipiv];
+    if (dv) {
+      for (j = k1; j <knext-1; j+=2) {
+	irow0 = hrowi[j];
+	irow1 = hrowi[j+1];
+	SHIFT_REF(dwork1, irow0) += dv * dluval[j];
+	SHIFT_REF(dwork1, irow1) += dv * dluval[j+1];
+	if (!nonzero[irow0]) {
+	  nonzero[irow0]=1;
+	  mpt[++number]=UNSHIFT_INDEX(irow0);
+	}
+	if (!nonzero[irow1]) {
+	  nonzero[irow1]=1;
+	  mpt[++number]=UNSHIFT_INDEX(irow1);
+	}
+      }
+      if (j<knext) {
+	irow0 = hrowi[j];
+	SHIFT_REF(dwork1, irow0) += dv * dluval[j];
+	if (!nonzero[irow0]) {
+	  nonzero[irow0]=1;
+	  mpt[++number]=UNSHIFT_INDEX(irow0);
+	}
+      }
+    }
+  }
+  return (number);
+} /* c_ekkbtjl */
+
+
+
+static void c_ekkbtju_dense(const int nrow,
+			    const double * COIN_RESTRICT dluval,
+			    const int * COIN_RESTRICT hrowi,
+			    const int * COIN_RESTRICT mcstrt, 
+			    int * COIN_RESTRICT hpivco, 
+			    double * COIN_RESTRICT dwork1,
+			    int * COIN_RESTRICT start,int last,int offset,
+			    double * COIN_RESTRICT densew)
+{
+  /* Local variables */
+  int ipiv1,ipiv2;
+  int save=hpivco[last];
+  
+  hpivco[last]=nrow+1;
+  
+  ipiv1=*start;
+  ipiv2=hpivco[ipiv1];
+  while(ipiv2<last) {
+    int iel,k;
+    const int   kx1	= mcstrt[ipiv1];
+    const int   kx2  = mcstrt[ipiv2];
+    const int   nel1 = hrowi[kx1-1];
+    const int   nel2 = hrowi[kx2-1];
+    const double dpiv1 = dluval[kx1-1];
+    const double dpiv2 = dluval[kx2-1];
+    const int   n1	= offset+ipiv1; /* number in dense part */
+    const int   nsparse1=nel1-n1;
+    const int   nsparse2=nel2-n1-(ipiv2-ipiv1);
+    const int   k1 = kx1+nsparse1;
+    const int   k2 = kx2+nsparse2;
+    const double *dlu1 = &dluval[k1];
+    const double *dlu2 = &dluval[k2];
+    
+    double dv1 = dwork1[ipiv1];
+    double dv2 = dwork1[ipiv2];
+    
+    for (iel = kx1; iel < k1; ++iel) {
+      dv1 -= SHIFT_REF(dwork1, hrowi[iel]) * dluval[iel];
+    }
+    for (iel = kx2; iel < k2; ++iel) {
+      dv2 -= SHIFT_REF(dwork1, hrowi[iel]) * dluval[iel];
+    }
+    for (k=0;k<n1;k++) {
+      dv1 -= dlu1[k] * densew[k];
+      dv2 -= dlu2[k] * densew[k];
+    }
+    dv1 *= dpiv1;
+    dv2 -= dlu2[n1] * dv1;
+    dwork1[ipiv1] = dv1;
+    dwork1[ipiv2] = dv2*dpiv2;
+    ipiv1 = hpivco[ipiv2];
+    ipiv2 = hpivco[ipiv1];
+  }
+  hpivco[last]=save;
+  
+  *start=ipiv1;
+  return;
+}
+/* about 8-10% of execution time is spent in this routine */
+static int c_ekkbtju_aux(const double * COIN_RESTRICT dluval, 
+			 const int * COIN_RESTRICT hrowi,
+			 const int * COIN_RESTRICT mcstrt, 
+			 const int * COIN_RESTRICT hpivco,
+			 double * COIN_RESTRICT dwork1,
+			 int ipiv, int loop_end)
+{
+#define UNROLL2 2
+#ifndef UNROLL2
+#if CLP_OSL==2||CLP_OSL==3
+#define UNROLL2 2
+#else
+#define UNROLL2 1
+#endif
+#endif
+  while (ipiv<=loop_end) {
+    int kx = mcstrt[ipiv];
+    const int nel = hrowi[kx-1];
+#if UNROLL2<2
+    const int kxe = kx + nel;
+#endif
+    
+    double dv = dwork1[ipiv];	/* rhs */
+#if UNROLL2>1
+    const int * hrowi2=hrowi+kx;
+    const int * hrowi2end=hrowi2+nel;
+    const double * dluval2=dluval+kx;
+#else
+    int iel;
+#endif
+    const double dpiv = dluval[kx-1];	/* inverse of pivot */
+    
+    
+    /* subtract terms whose unknowns have been solved for */
+    
+    /* a significant proportion of these loops may not modify dv at all.
+     * However, it seems to be just as expensive to check if the loop
+     * would modify dv as it is to just do it.
+     * The only difference would be that dluval wouldn't be referenced
+     * for those loops, would might save some cache paging,
+     * but unfortunately the code generated to search for zeros (on AIX)
+     * is *worse* than code that just multiplies by dval.
+     */
+#if UNROLL2<2
+    for (iel = kx; iel < kxe; ++iel) {
+      const int irow = hrowi[iel];
+      const double dval=dluval[iel];
+      dv -= SHIFT_REF(dwork1, irow) * dval;
+    }
+    
+    dwork1[ipiv] = dv * dpiv;	/* divide by the pivot */
+#else
+    if ((nel&1)!=0) {
+      int irow = *hrowi2;
+      double dval=*dluval2;
+      dv -= SHIFT_REF(dwork1, irow) * dval;
+      hrowi2++;
+      dluval2++;
+    }
+    for (; hrowi2 < hrowi2end; hrowi2 +=2,dluval2 +=2) {
+      int irow0 = hrowi2[0];
+      int irow1 = hrowi2[1];
+      double dval0=dluval2[0];
+      double dval1=dluval2[1];
+      double d0=SHIFT_REF(dwork1, irow0);
+      double d1=SHIFT_REF(dwork1, irow1);
+      dv -= d0 * dval0;
+      dv -= d1 * dval1;
+    }
+    dwork1[ipiv] = dv * dpiv;	/* divide by the pivot */
+#endif
+    
+    ipiv=hpivco[ipiv];
+  }
+  
+  return (ipiv);
+}
+
+/*
+ * We are given the upper diagonal matrix U from the LU factorization
+ * and a rhs dwork1.
+ * This solves the system U x = dwork1
+ * by back substitution, overwriting dwork1 with the solution x.
+ *
+ * It does this in textbook style by solving the equations "bottom" up,
+ * so for each equation one new unknown is solved for by subtracting
+ * from the rhs the sum of the terms whose unknowns have been solved for,
+ * then dividing by the coefficient of the new unknown.
+ *
+ * Since we update the U matrix using F-T, the order of the columns
+ * changes slightly each iteration.  Initially, hpivco[i] == i+1,
+ * and each iteration (generally) introduces one element where this
+ * is no longer true.  However, because we periodically refactorize,
+ * it is much more common for hpivco[i] == i+1 than not.
+ *
+ * The one quirk is that value referred to as the pivot is actually
+ * the reciprocal of the pivot, to avoid a division.
+ *
+ * Solving in this fashion is inappropriate if there are frequently
+ * cases where all unknowns in an equation have value zero.
+ * This seems to happen frequently if the sparsity of the rhs is, say, 10%.
+ */
+static void c_ekkbtju(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,	     
+	     double * COIN_RESTRICT dwork1,
+	     int ipiv)
+{
+  const int nrow	= fact->nrow;
+  double * COIN_RESTRICT dluval	= fact->xeeadr;
+  int * COIN_RESTRICT hrowi	= fact->xeradr;
+  int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  int * COIN_RESTRICT hpivco_new = fact->kcpadr+1;
+  int ndenuc=fact->ndenuc;
+  int first_dense = fact->first_dense;
+  int last_dense = fact->last_dense;
+  
+  const int has_dense = (first_dense<last_dense &&
+			 mcstrt[ipiv]<=mcstrt[last_dense]);
+  
+  /* Parameter adjustments */
+  /* dluval and hrowi were NOT decremented here.
+     I believe that they are used as C-style arrays below.
+     At this point, I am going to convert them from Fortran- to C-style
+     here by incrementing them; at some later time, I will convert their
+     uses in this file to Fortran-style.
+  */
+  dluval++;
+  hrowi++;
+  
+  if (has_dense) 
+    ipiv = c_ekkbtju_aux(dluval, hrowi, mcstrt, hpivco_new, dwork1, ipiv,
+		       first_dense - 1);
+  
+  if (has_dense) {
+    int n=0;
+    int firstDense = nrow-ndenuc+1;
+    double *densew = &dwork1[firstDense];
+    
+    /* check first dense to see where in triangle it is */
+    int last=first_dense;
+    int j=mcstrt[last]-1;
+    int k1=j;
+    int k2=j+hrowi[j];
+    
+    for (j=k2;j>k1;j--) {
+      int irow=UNSHIFT_INDEX(hrowi[j]);
+      if (irow<firstDense) {
+	break;
+      } else {
+#ifdef DEBUG
+	if (irow!=last-1) {
+	  abort();
+	}
+#endif
+	last=irow;
+	n++;
+      }
+    }
+    c_ekkbtju_dense(nrow,dluval,hrowi,mcstrt,const_cast<int *> (hpivco_new),
+		  dwork1,&ipiv,last_dense, n - first_dense, densew);
+  }
+  
+  (void) c_ekkbtju_aux(dluval, hrowi, mcstrt, hpivco_new, dwork1, ipiv, nrow);
+} /* c_ekkbtju */
+
+
+/*
+ * mpt / *nincolp contain the indices of nonzeros in dwork1.
+ * nonzero contains the same information as a byte-mask.
+ *
+ * currently, erase_nonzero is true iff this is called from c_ekketsj.
+ */
+static int c_ekkbtju_sparse(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+		   double * COIN_RESTRICT dwork1,
+		   int * COIN_RESTRICT mpt, int nincol,
+		   int * COIN_RESTRICT spare)
+{
+  const double * COIN_RESTRICT dluval	= fact->xeeadr+1;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  char * COIN_RESTRICT nonzero = fact->nonzero;
+  const int * COIN_RESTRICT hcoli	= fact->xecadr;
+  const int * COIN_RESTRICT mrstrt	= fact->xrsadr;
+  const int * COIN_RESTRICT hinrow	= fact->xrnadr;
+  const double * COIN_RESTRICT de2val	= fact->xe2adr-1;
+  int i;
+  int iPivot;
+  int nList=0;
+  int nStack,k,kx;
+  const int nrow=fact->nrow;
+  const double tolerance = fact->zeroTolerance;
+  int * COIN_RESTRICT list = spare;
+  int * COIN_RESTRICT stack = spare+nrow;
+  int * COIN_RESTRICT next = stack+nrow;
+  /*
+   * Examine all nonzero elements and determine which elements may be
+   * nonzero in the result.
+   * Any row in U that contains terms that may have nonzero variable values
+   * may produce a nonzero value.
+   */
+  for (k=0;k<nincol;k++) {
+    nStack=1;
+    iPivot=mpt[k];
+    stack[0]=iPivot;
+    next[0]=0;
+    while (nStack) {
+      int kPivot,ninrow,j;
+      /* take off stack */
+      kPivot=stack[--nStack];
+      /*printf("nStack %d kPivot %d, ninrow %d, j %d, nList %d\n",
+	nStack,kPivot,hinrow[kPivot],
+	next[nStack],nList);*/
+      if (nonzero[kPivot]!=1) {
+	ninrow = hinrow[kPivot];
+	j=next[nStack];
+	if (j!=ninrow) {
+	  kx = mrstrt[kPivot];
+	  kPivot=hcoli[kx+j];
+	  /* put back on stack */
+	  next[nStack++] ++;
+	  if (!nonzero[kPivot]) {
+	    /* and new one */
+	    stack[nStack]=kPivot;
+	    nonzero[kPivot]=2;
+	    next[nStack++]=0;
+	  }
+	} else {
+	  /* finished so mark */
+	  list[nList++]=kPivot;
+	  nonzero[kPivot]=1;
+	}
+      }
+    }
+  }
+  
+  i=nList-1;
+  nList=0;
+  for (;i>=0;i--) {
+    double dpiv;
+    double dv;
+    iPivot = list[i];
+    kx	= mcstrt[iPivot];
+    dpiv = dluval[kx-1];
+    dv	= dpiv * dwork1[iPivot];
+    nonzero[iPivot] = 0;
+    if (fabs(dv)>=tolerance) {
+      int iel;
+      int krx	= mrstrt[iPivot];
+      int krxe	= krx+hinrow[iPivot];
+      dwork1[iPivot]=dv;
+      mpt[nList++]=iPivot;
+      for (iel = krx; iel < krxe; iel++) {
+	int irow0 = hcoli[iel];
+	double dval=de2val[iel];
+	dwork1[irow0] -= dv*dval;
+      }
+    } else {
+      dwork1[iPivot]=0.0;
+    }
+  }
+  
+  return (nList);
+} /* c_ekkbtjuRow */
+
+/*
+ * dpermu is supposed to be zeroed on entry to this routine.
+ * It is used as a working buffer.
+ * The input vector dwork1 is permuted into dpermu, operated on,
+ * and the answer is permuted back into dwork1, zeroing dpermu in
+ * the process.
+ */
+/*
+ * nincol > 0 ==> mpt contains indices of non-zeros in dpermu
+ *
+ * first_nonzero contains index of first (last??)nonzero;
+ * only used if nincol==0.
+ *
+ * dpermu contains permuted input; dwork1 is now zero
+ */
+int c_ekkbtrn(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact,
+	    double * COIN_RESTRICT dwork1,
+	    int * COIN_RESTRICT mpt, int first_nonzero)
+{
+  double * COIN_RESTRICT dpermu = fact->kadrpm;
+  const int * COIN_RESTRICT mpermu=fact->mpermu;
+  const int * COIN_RESTRICT hpivco_new= fact->kcpadr+1;
+  
+  const int nrow	= fact->nrow;
+  int i;
+  int nincol;
+  /* find the first non-zero input */
+  int ipiv;
+  if (first_nonzero) {
+    ipiv = first_nonzero;
+#if 1
+    if (c_ekk_IsSet(fact->bitArray,ipiv)) {
+      /* slack */
+      int lastSlack = fact->lastSlack;
+      int firstDo=hpivco_new[lastSlack];
+      assert (dpermu[ipiv]);
+      while (ipiv!=firstDo) {
+	assert (c_ekk_IsSet(fact->bitArray,ipiv));
+	if (dpermu[ipiv])
+	  dpermu[ipiv]=-dpermu[ipiv];
+	ipiv=hpivco_new[ipiv];
+      }
+    }
+#endif
+  } else {
+    int lastSlack = fact->numberSlacks;
+    ipiv=hpivco_new[0];
+    for (i=0;i<lastSlack;i++) {
+      int next_piv = hpivco_new[ipiv];
+      assert (c_ekk_IsSet(fact->bitArray,ipiv));
+      if (dpermu[ipiv]) {
+	break;
+      } else {
+	ipiv=next_piv;
+      }
+    }
+    
+    /* usually, there is a non-zero slack entry... */
+    if (i==lastSlack) {
+      /* but if there isn't... */
+      for (;i<nrow;i++) {
+	if (!dpermu[ipiv]) {
+	  ipiv=hpivco_new[ipiv];
+	} else {
+	  break;
+	}
+      }
+    } else {
+      /* reverse signs for slacks */
+      for (;i<lastSlack;i++) {
+	assert (c_ekk_IsSet(fact->bitArray,ipiv));
+	if (dpermu[ipiv])
+	  dpermu[ipiv]=-dpermu[ipiv];
+	ipiv=hpivco_new[ipiv];
+      }
+      assert (!c_ekk_IsSet(fact->bitArray,ipiv)||ipiv>fact->nrow);
+      
+      /* this is presumably the first non-zero non slack */
+      /*ipiv=firstDo;*/
+    }
+  }
+  if (ipiv<=fact->nrow) {
+    /* skipBtju is always (?) 0 first the first call,
+     * ipiv tends to be >nrow for the second */
+    
+    /*       DO U */
+    c_ekkbtju(fact,dpermu,
+	    ipiv); 
+  }
+  
+  
+  /*       DO ROW ETAS IN L */
+  c_ekkbtjl(fact, dpermu); 
+  c_ekkbtj4p(fact,dpermu);
+  
+  /* dwork1[mpermu] = dpermu; dpermu = 0; mpt = indices of non-zeros */
+  nincol = 
+    c_ekkshfpo_scan2zero(fact,&mpermu[1],dpermu,&dwork1[1],&mpt[1]);
+  
+  /* dpermu should be zero now */
+#ifdef DEBUG
+  for (i=1;i<=nrow ;i++ ) {
+    if (dpermu[i]) {
+      abort();
+    } /* endif */
+  } /* endfor */
+#endif
+  return (nincol);
+} /* c_ekkbtrn */
+
+static int c_ekkbtrn0_new(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact,
+			double * COIN_RESTRICT dwork1,
+			int * COIN_RESTRICT mpt, int nincol, 
+			   int * COIN_RESTRICT spare)
+{
+  double * COIN_RESTRICT dpermu = fact->kadrpm;
+  const int * COIN_RESTRICT mpermu=fact->mpermu;
+  const int * COIN_RESTRICT hpivro	= fact->krpadr;
+  
+  const int nrow	= fact->nrow;
+  
+  int i;
+  char * nonzero=fact->nonzero;
+  int doSparse=1;
+  
+  /* so:  dpermu must contain room for:
+   * nrow doubles, followed by
+   * nrow ints (mpermu), followed by
+   * nrow ints (the inverse permutation), followed by
+   * an unused area (?) of nrow ints, followed by
+   * nrow chars (this non-zero array).
+   *
+   * and apparently the first nrow elements of nonzero are expected
+   * to already be zero.
+   */    
+#ifdef DEBUG
+  for (i=1;i<=nrow ;i++ ) {
+    if (nonzero[i]) {
+      abort();
+    } /* endif */
+  } /* endfor */
+#endif
+  /* now nonzero[i]==1 iff there is an entry for i in mpt */
+  
+  nincol=c_ekkbtju_sparse(fact, dpermu,
+			&mpt[1], nincol,
+			spare);
+  
+  /* the vector may have more nonzero elements now */
+  /*       DO ROW ETAS IN L */
+#define DENSE_THRESHOLD (nincol*10+100)
+  if (DENSE_THRESHOLD>nrow) {
+    doSparse=0;
+    c_ekkbtjl(fact, dpermu); 
+  } else {
+    /* set nonzero */
+    for(i=0;i<nincol;i++) {
+      int j=mpt[i+1];
+      nonzero[j]=1;
+    }
+    nincol =
+      c_ekkbtjl_sparse(fact,
+		     dpermu,
+		     mpt, 
+		     nincol);
+    for(i=0;i<nincol;i++) {
+      int j=mpt[i+1];
+      nonzero[j]=0;
+    }
+    if (DENSE_THRESHOLD>nrow) {
+      doSparse=0;
+#ifdef DEBUG
+      for (i=1;i<=nrow;i++) {
+	if (nonzero[i]) {
+	  abort();
+	}
+      }
+#endif
+    }
+  }
+  if (!doSparse) {
+    c_ekkbtj4p(fact,dpermu);
+    /* dwork1[mpermu] = dpermu; dpermu = 0; mpt = indices of non-zeros */
+    nincol = 
+      c_ekkshfpo_scan2zero(fact,&mpermu[1],dpermu,&dwork1[1],&mpt[1]);
+    
+    /* dpermu should be zero now */
+#ifdef DEBUG
+    for (i=1;i<=nrow ;i++ ) {
+      if (dpermu[i]) {
+	abort();
+      } /* endif */
+    } /* endfor */
+#endif
+  } else {
+    /* still sparse */
+    if (fact->nnentl) {
+      nincol =
+	c_ekkbtj4_sparse(fact,
+		       dpermu,
+		       &mpt[1],
+		       dwork1,
+		       nincol,spare);
+    } else {
+      double tolerance=fact->zeroTolerance;
+      int irow;
+      int nput=0;
+      if (fact->packedMode) {
+	for (i = 0; i <nincol; i++) {
+	  int irow0;
+	  double dval;
+	  irow=mpt[i+1];
+	  dval=dpermu[irow];
+	  if (NOT_ZERO(dval)) {
+	    if (fabs(dval) >= tolerance) {
+	      irow0= hpivro[irow];
+	      dwork1[1+nput]=dval;
+	      mpt[1 + nput++]=irow0-1;
+	    }
+	    dpermu[irow]=0.0;
+	  }
+	}
+      } else {
+	for (i = 0; i <nincol; i++) {
+	  int irow0;
+	  double dval;
+	  irow=mpt[i+1];
+	  dval=dpermu[irow];
+	  if (NOT_ZERO(dval)) {
+	    if (fabs(dval) >= tolerance) {
+	      irow0= hpivro[irow];
+	      dwork1[irow0]=dval;
+	      mpt[1 + nput++]=irow0-1;
+	    }
+	    dpermu[irow]=0.0;
+	  }
+	}
+      }
+      nincol=nput;
+    }
+  }
+  
+  
+  return (nincol);
+} /* c_ekkbtrn */
+
+
+/* returns c_ekkbtrn(fact, dwork1, mpt)
+ *
+ * but since mpt[1..nincol] contains the indices of non-zeros in dwork1,
+ * we can do faster.
+ */
+static int c_ekkbtrn_mpt(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact,
+		double * COIN_RESTRICT dwork1,
+		int * COIN_RESTRICT mpt, int nincol,int * COIN_RESTRICT spare)
+{
+  double * COIN_RESTRICT dpermu = fact->kadrpm;
+  const int nrow	= fact->nrow;
+  
+  const int * COIN_RESTRICT mpermu=fact->mpermu;
+  /*const int *mrstrt	= fact->xrsadr;*/
+  
+#ifdef DEBUG
+  int i;
+  memset(spare,'A',3*nrow*sizeof(int));
+  {
+    
+    for (i=1;i<=nrow;i++) {
+      if (dpermu[i]) {
+	abort();
+      }
+    }
+  } 
+#endif
+  
+  
+  int i;
+#ifdef DEBUG
+  for (i=1;i<=nrow;i++) {
+    if (fact->nonzero[i]||dpermu[i]) {
+      abort();
+    }
+  }
+#endif
+  assert (fact->if_sparse_update>0&&mpt&&fact->rows_ok) ;
+  
+  /* read the input vector from mpt/dwork1;
+   * permute it into dpermu;
+   * construct a nonzero mask in nonzero;
+   * overwrite mpt with the permuted indices;
+   * clear the dwork1 vector.
+   */
+  for (i=0;i<nincol;i++) {
+    int irow=mpt[i+1];
+    int jrow=mpermu[irow];
+    dpermu[jrow]=dwork1[irow];
+    /*nonzero[jrow-1]=1; this is done in btrn0 */
+    mpt[i+1]=jrow;
+    dwork1[irow]=0.0;
+  }
+  
+  if (DENSE_THRESHOLD<nrow) {
+    nincol = c_ekkbtrn0_new(fact, dwork1, mpt, nincol,spare);
+  } else {
+    nincol = c_ekkbtrn(fact, dwork1, mpt, 0);
+  }
+#ifdef DEBUG
+  {
+    
+    for (i=1;i<=nrow;i++) {
+      if (dpermu[i]) {
+	abort();
+      }
+    }
+    if (fact->if_sparse_update>0) {
+      for (i=1;i<=nrow;i++) {
+	if (fact->nonzero[i]) {
+	  abort();
+	}
+      }
+    }
+  } 
+#endif
+  return nincol;
+}
+
+/* returns c_ekkbtrn(fact, dwork1, mpt)
+ *
+ * but since (dwork1[i]!=0) == (i==ipivrw),
+ * we can do faster.
+ */
+int c_ekkbtrn_ipivrw(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact,
+		   double * COIN_RESTRICT dwork1,
+		   int * COIN_RESTRICT mpt, int ipivrw,int * COIN_RESTRICT spare)
+{
+  double * COIN_RESTRICT dpermu = fact->kadrpm;
+  const int nrow	= fact->nrow;
+  
+  const int * COIN_RESTRICT mpermu=fact->mpermu;
+  const double * COIN_RESTRICT dluval	= fact->xeeadr;
+  const int * COIN_RESTRICT mrstrt	= fact->xrsadr;
+  const int * COIN_RESTRICT hinrow	= fact->xrnadr;
+  const int * COIN_RESTRICT hcoli	= fact->xecadr;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  
+  int nincol;
+  
+#ifdef DEBUG
+  int i;
+  for (i=1;i<=nrow ;i++ ) {
+    if (dpermu[i]) {
+      abort();
+    } /* endif */
+  } /* endfor */
+#endif
+  
+  if (fact->if_sparse_update>0&&mpt&& fact->rows_ok) {
+    mpt[1] = ipivrw;
+    nincol = c_ekkbtrn_mpt(fact, dwork1, mpt, 1,spare);
+  } else {
+    int ipiv;
+    int kpivrw = mpermu[ipivrw];
+    dpermu[kpivrw]=dwork1[ipivrw];
+    dwork1[ipivrw]=0.0;
+    
+    if (fact->rows_ok) {
+      /* !fact->if_sparse_update
+       * but we still have rowwise info,
+       * so we may as well use it to do the slack row
+       */
+      int iipivrw=nrow+1;
+      int itest = fact->nnentu+1;
+      int k=mrstrt[kpivrw];
+      int lastInRow= k+hinrow[kpivrw];
+      double dpiv,dv;
+      for (;k<lastInRow;k++) {
+	int icol=hcoli[k];
+	int start=mcstrt[icol];
+	if (start<itest) {
+	  iipivrw=icol;
+	  itest=start;
+	}
+      }
+      /* do missed pivot */
+      itest=mcstrt[kpivrw];
+      dpiv=dluval[itest];
+      dv=dpermu[kpivrw];
+      dv*=dpiv;
+      dpermu[kpivrw]=dv;
+      ipiv=iipivrw;
+    } else {
+      /* no luck - c_ekkbtju will slog through slacks (?) */
+      ipiv=kpivrw;
+    }
+    /* nincol not read */
+    /* not sparse */
+    /* do slacks */
+    if (ipiv<=fact->nrow) {
+      if (c_ekk_IsSet(fact->bitArray,ipiv)) {
+	const int * hpivco_new= fact->kcpadr+1;
+	int lastSlack = fact->lastSlack;
+	int firstDo=hpivco_new[lastSlack];
+	/* slack */
+	/* need pivot row of first nonslack */
+	dpermu[ipiv]=-dpermu[ipiv];
+#ifndef NDEBUG
+	while (1) {
+	  assert (c_ekk_IsSet(fact->bitArray,ipiv));
+	  ipiv=hpivco_new[ipiv];
+	  if (ipiv>fact->nrow||ipiv==firstDo)
+	    break;
+	}
+	assert (!c_ekk_IsSet(fact->bitArray,ipiv)||ipiv>fact->nrow);
+	assert (ipiv==firstDo);
+#endif
+	ipiv=firstDo;
+      }
+    }
+    nincol = c_ekkbtrn(fact, dwork1, mpt, ipiv);
+  }
+  
+  return nincol;
+}
+/*
+ * Does work associated with eq. 3.7:
+ *	r' = u' U^-1
+ *
+ * where u' (can't write the overbar) is the p'th row of U, without
+ * the entry for column p.  (here, jpivrw is p).
+ * We solve this as for btju.  We know
+ *	r' U = u'
+ *
+ * so we solve from low index to hi, determining the next value u_i'
+ * by doing the dot-product of r' and the i'th column of U (excluding
+ * element i itself), subtracting that from u'_i, and dividing by
+ * U_ii (we store the reciprocal, so here we multiply).
+ *
+ * Now, in principle dwork1 should be initialized to the p'th row of U.
+ * Instead, it is initially zeroed and filled in as we go along.
+ * Of the entries in u' that we reference during a dot product with
+ * a column of U, either
+ *	the entry is 0 by definition, since it is < p, or
+ *	it has already been set by a previous iteration, or
+ *	it is p.
+ *
+ * Because of this, we know that all elements < p will be zero;
+ * that's why we start with p (kpivrw).
+ 
+ * While we do this product, we also zero out the p'th row.
+ */
+static void c_ekketju_aux(COIN_REGISTER2 EKKfactinfo * COIN_RESTRICT2 fact,int sparse,
+			double * COIN_RESTRICT dluval, int * COIN_RESTRICT hrowi,
+			const int * COIN_RESTRICT mcstrt, const int * COIN_RESTRICT hpivco,
+			double * COIN_RESTRICT dwork1,
+			int *ipivp, int jpivrw, int stop_col)
+{
+  int ipiv = *ipivp;
+  if (1&&ipiv<stop_col&&c_ekk_IsSet(fact->bitArray,ipiv)) {
+    /* slack */
+    int lastSlack = fact->lastSlack;
+    int firstDo=hpivco[lastSlack];
+    while (1) {
+      assert (c_ekk_IsSet(fact->bitArray,ipiv));
+      dwork1[ipiv] = -dwork1[ipiv];
+      ipiv=hpivco[ipiv];	/* next column - generally ipiv+1 */
+      if (ipiv==firstDo||ipiv>=stop_col)
+	break;
+    }
+  }
+  
+  while(ipiv<stop_col) {
+    double dv = dwork1[ipiv];
+    int kx = mcstrt[ipiv];
+    int nel = hrowi[kx];
+    double dpiv = dluval[kx];
+    int kcs = kx + 1;
+    int kce = kx + nel;
+    int iel;
+    
+    for (iel = kcs; iel <= kce; ++iel) {
+      int irow = hrowi[iel];
+      irow = UNSHIFT_INDEX(irow);
+      dv -= dwork1[irow] * dluval[iel];
+      if (irow == jpivrw) {
+	break;
+      }
+    }
+    
+    /* assuming the p'th row is sparse,
+     * this branch will be infrequently taken */
+    if (iel <= kce) {
+      int irow = hrowi[iel];
+      /* irow == jpivrw */
+      dv += dluval[iel];
+      
+      if (sparse) {
+	/* delete this entry by overwriting it with the last */
+	--nel;
+	hrowi[kx] = nel;
+	hrowi[iel] = hrowi[kce];
+#ifdef CLP_REUSE_ETAS
+	double temp=dluval[iel];
+	dluval[iel] = dluval[kce];
+	hrowi[kce]=jpivrw;
+	dluval[kce]=temp;
+#else
+	dluval[iel] = dluval[kce];
+#endif
+	kce--;
+      } else {
+	/* we can't delete an entry from a dense column,
+	 * so we just zero it out */
+	dluval[iel]=0.0;
+	iel++;
+      }
+      
+      /* finish up the remaining entries; same as above loop, but no check */
+      for (; iel <= kce; ++iel) {
+	irow = UNSHIFT_INDEX(hrowi[iel]);
+	dv -= dwork1[irow] * dluval[iel];
+      }
+    }
+    dwork1[ipiv] = dv * dpiv;	/* divide by pivot */
+    ipiv=hpivco[ipiv];	/* next column - generally ipiv+1 */
+  }
+  
+  /* ? is it guaranteed that ipiv==stop_col at this point?? */
+  *ipivp = ipiv;
+}
+
+/* dwork1 is assumed to be zeroed on entry */
+static void c_ekketju(COIN_REGISTER EKKfactinfo * COIN_RESTRICT2 fact,double *dluval, int *hrowi,
+		    const int * COIN_RESTRICT mcstrt, const int * COIN_RESTRICT hpivco,
+		    double * COIN_RESTRICT dwork1,
+		    int kpivrw, int first_dense , int last_dense)
+{
+  int ipiv = hpivco[kpivrw];
+  int jpivrw = SHIFT_INDEX(kpivrw);
+  
+  const int nrow	= fact->nrow;
+  
+  if (first_dense < last_dense &&
+      mcstrt[ipiv] <= mcstrt[last_dense]) {
+    /* There are dense columns, and
+     * some dense columns precede the pivot column */
+    
+    /* first do any sparse columns "on the left" */
+    c_ekketju_aux(fact, true, dluval, hrowi, mcstrt, hpivco, dwork1,
+		&ipiv, jpivrw, first_dense);
+    
+    /* then do dense columns */
+    c_ekketju_aux(fact, false, dluval, hrowi, mcstrt, hpivco, dwork1,
+		&ipiv, jpivrw, last_dense+1);
+    
+    /* final sparse columns "on the right" ...*/
+  } 
+  /* ...are the same as sparse columns if there are no dense */
+  c_ekketju_aux(fact, true, dluval, hrowi, mcstrt, hpivco, dwork1,
+	      &ipiv, jpivrw, nrow+1);
+} /* c_ekketju */
+
+
+
+
+
+
+
+
+
+
+
+
+/*#define PRINT_DEBUG*/
+/* dwork1 is assumed to be zeroed on entry */
+int c_ekketsj(COIN_REGISTER2 /*const*/ EKKfactinfo * COIN_RESTRICT2 fact,
+	    double * COIN_RESTRICT dwork1,
+	    int * COIN_RESTRICT mpt2, double dalpha, int orig_nincol,
+	    int npivot, int *nuspikp,
+	    const int ipivrw,int * spare)
+{
+  int nuspik	= *nuspikp;
+  
+  int * COIN_RESTRICT mpermu=fact->mpermu;
+  
+  int * COIN_RESTRICT hcoli	= fact->xecadr;
+  double * COIN_RESTRICT dluval	= fact->xeeadr;
+  int * COIN_RESTRICT mrstrt	= fact->xrsadr;
+  int * COIN_RESTRICT hrowi	= fact->xeradr;
+  int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  int * COIN_RESTRICT hinrow	= fact->xrnadr;
+  /*int *hincol	= fact->xcnadr;
+    int *hpivro	= fact->krpadr;*/
+  int * COIN_RESTRICT hpivco	= fact->kcpadr;
+  double * COIN_RESTRICT de2val	= fact->xe2adr;
+  
+  const int nrow	= fact->nrow;
+  const int ifRowCopy	= fact->rows_ok;
+  
+  int i, j=-1, k, i1, i2, k1;
+  int kc, iel;
+  double del3;
+  int nroom;
+  bool ifrows= (mrstrt[1] != 0);
+  int kpivrw, jpivrw;
+  int first_dense_mcstrt,last_dense_mcstrt;
+  int nnentl;			/* includes row stuff */
+  int doSparse=(fact->if_sparse_update>0);
+#ifdef MORE_DEBUG
+  {
+    const int * COIN_RESTRICT hrowi = fact->R_etas_index;
+    const int * COIN_RESTRICT mcstrt = fact->R_etas_start;
+    int ndo=fact->nR_etas;
+    int knext;
+  
+    knext = mcstrt[ndo + 1];
+    for (int i = ndo; i > 0; --i) {
+      int k1 = knext;
+      knext = mcstrt[i];
+      for (int j = k1+1; j < knext; j++) {
+	assert (hrowi[j]>0&&hrowi[j]<100000);
+      }
+    }
+  }
+#endif
+  
+  int mcstrt_piv;
+  int nincol=0;
+  int * COIN_RESTRICT hpivco_new=fact->kcpadr+1;
+  int * COIN_RESTRICT back=fact->back;
+  int irtcod = 0;
+  
+  /* Parameter adjustments */
+  de2val--;
+  
+  /* Function Body */
+  if (!ifRowCopy) {
+    doSparse=0;
+    fact->if_sparse_update=-abs(fact->if_sparse_update);
+  }
+  if (npivot==1) {
+    fact->num_resets=0;
+  }
+  kpivrw = mpermu[ipivrw];
+#if 0 //ndef NDEBUG
+  ets_count++;
+  if (ets_check>=0&&ets_count>=ets_check) {
+    printf("trouble\n");
+  }
+#endif
+  mcstrt_piv=mcstrt[kpivrw];
+  /* ndenuc - top has number deleted */
+  if (fact->ndenuc) {
+    first_dense_mcstrt = mcstrt[fact->first_dense];
+    last_dense_mcstrt  = mcstrt[fact->last_dense];
+  } else {
+    first_dense_mcstrt=0;
+    last_dense_mcstrt=0;
+  }
+  {
+    int kdnspt = fact->nnetas - fact->nnentl;
+    
+    i1 = ((kdnspt - 1) + fact->R_etas_start[fact->nR_etas + 1]);
+    /*i1 = -99999999;*/
+    
+    /* fact->R_etas_start[fact->nR_etas + 1] is -(the number of els in R) */
+    nnentl = fact->nnetas - ((kdnspt - 1) + fact->R_etas_start[fact->nR_etas + 1]);
+  }
+  fact->demark=fact->nnentu+nnentl;
+  jpivrw = SHIFT_INDEX(kpivrw);
+  
+#ifdef CLP_REUSE_ETAS
+  double del3Orig=0.0;
+#endif
+  if (nuspik < 0) {
+    goto L7000;
+  } else if (nuspik == 0) {
+    del3 = 0.;
+  } else {
+    del3 = 0.;
+    i1 = fact->nnentu + 1;
+    i2 = fact->nnentu + nuspik;
+    if (fact->sortedEta) {
+      /* binary search */
+      if (hrowi[i2] == jpivrw) {
+	/* sitting right on the end - easy */
+	del3 = dluval[i2];
+	--nuspik;
+      } else {
+	bool foundit = true;
+	
+	/* binary search - sort of implies hrowi is sorted */
+	i = i1;
+	if (hrowi[i] != jpivrw) {
+	  while (1) {
+	    i = (i1 + i2) >>1;
+	    if (i == i1) {
+	      foundit = false;
+	      break;
+	    }
+	    if (hrowi[i] < jpivrw) {
+	      i1 = i;
+	    } else if (hrowi[i] > jpivrw) {
+	      i2 = i;
+	    }
+	    else
+	      break;
+	  }
+	}
+	/* ??? what if we didn't find it? */
+	
+	if (foundit) {
+	  del3 = dluval[i];
+	  --nuspik;
+	  /* remove it and move the last element into its place */
+	  hrowi[i] = hrowi[nuspik + fact->nnentu+1];
+	  dluval[i] = dluval[nuspik + fact->nnentu+1];
+	}
+      }
+    } else {
+      /* search */
+      for (i=i1;i<=i2;i++) {
+	if (hrowi[i] == jpivrw) {
+	  del3 = dluval[i];
+	  --nuspik;
+	  /* remove it and move the last element into its place */
+	  hrowi[i] = hrowi[i2];
+	  dluval[i] = dluval[i2];
+	  break;
+	}
+      }
+    }
+  }
+#ifdef CLP_REUSE_ETAS
+  del3Orig=del3;
+#endif
+  
+  /*      OLD COLUMN POINTERS */
+  /* **************************************************************** */
+  if (!ifRowCopy) {
+    /*       old method */
+    /*       DO U */
+    c_ekketju(fact,dluval, hrowi, mcstrt, hpivco_new,
+	    dwork1, kpivrw,fact->first_dense,
+	    fact->last_dense);
+  } else {
+    
+    /*       could take out of old column but lets try being crude */
+    /*       try taking out */
+    if (fact->xe2adr != 0&&doSparse) {
+      
+      /*
+       * There is both a column and row representation of U.
+       * For each row in the kpivrw'th column of the col U rep,
+       * find its position in the U row rep and remove it
+       * by overwriting it with the last element.
+       */
+      int k1x = mcstrt[kpivrw];
+      int nel = hrowi[k1x];	/* yes, this is the nel, for the pivot */
+      int k2x = k1x + nel;
+      
+      for (k = k1x + 1; k <= k2x; ++k) {
+	int irow = UNSHIFT_INDEX(hrowi[k]);
+	int kx = mrstrt[irow];
+	int nel = hinrow[irow]-1;
+	hinrow[irow]=nel;
+	
+	int jlast = kx + nel;
+	for (int iel=kx;iel<jlast;iel++) {
+	  if (kpivrw==hcoli[iel]) {
+	    hcoli[iel] = hcoli[jlast];
+	    de2val[iel] = de2val[jlast];
+	    break;
+	  }
+	}
+      }
+    } else if (ifRowCopy) {
+      /* still take out */
+      int k1x = mcstrt[kpivrw];
+      int nel = hrowi[k1x];	/* yes, this is the nel, for the pivot */
+      int k2x = k1x + nel;
+      
+      for (k = k1x + 1; k <= k2x; ++k) {
+	int irow = UNSHIFT_INDEX(hrowi[k]);
+	int kx = mrstrt[irow];
+	int nel = hinrow[irow]-1;
+	hinrow[irow]=nel;
+	int jlast = kx + nel ;
+	for (;kx<jlast;kx++) {
+	  if (kpivrw==hcoli[kx]) {
+	    hcoli[kx] = hcoli[jlast];
+	    break;
+	  }
+	}
+      }
+    }
+    
+    /*       add to row version */
+    /* the updated column (alpha_p) was written to entries
+     * nnentu+1..nnentu+nuspik by routine c_ekkftrn_ft.
+     * That was just an intermediate value of the usual ftrn.
+     */
+    i1 = fact->nnentu + 1;
+    i2 = fact->nnentu + nuspik;
+    int * COIN_RESTRICT eta_last=mpermu+nrow*2+3;
+    int * COIN_RESTRICT eta_next=eta_last+nrow+2;
+    if (fact->xe2adr == 0||!doSparse) {
+      /* we have column indices by row, but not the actual values */
+      for (iel = i1; iel <= i2; ++iel) {
+	int irow = UNSHIFT_INDEX(hrowi[iel]);
+	int iput = hinrow[irow];
+	int kput = mrstrt[irow];
+	int nextRow=eta_next[irow];
+	assert (kput>0);
+	kput += iput;
+	if (kput < mrstrt[nextRow]) {
+	  /* there is room - append the pivot column;
+	   * this corresponds making alpha_p the rightmost column of U (p. 268)*/
+	  hinrow[irow] = iput + 1;
+	  hcoli[kput] = kpivrw;
+	} else {
+	  /* no room - switch off */
+	  doSparse=0;
+	  /* possible kpivrw 1 */
+	  k1 = mrstrt[kpivrw];
+	  mrstrt[1]=-1;
+	  fact->rows_ok = false;
+	  goto L1226;
+	}
+      }
+    } else {
+      if (! doSparse) {
+	/* we have both column indices and values by row */
+	/* just like loop above, but with extra assign to de2val */
+	for (iel = i1; iel <= i2; ++iel) {
+	  int irow = UNSHIFT_INDEX(hrowi[iel]);
+	  int iput = hinrow[irow];
+	  int kput = mrstrt[irow];
+	  int nextRow=eta_next[irow];
+	  assert (kput>0);
+	  kput += iput;
+	  if (kput < mrstrt[nextRow]) {
+	    hinrow[irow] = iput + 1;
+	    hcoli[kput] = kpivrw;
+	    de2val[kput] = dluval[iel];
+	  } else {
+	    /* no room - switch off */
+	    doSparse=0;
+	    /* possible kpivrw 1 */
+	    k1 = mrstrt[kpivrw];
+	    mrstrt[1]=-1;
+	    fact->rows_ok = false;
+	    goto L1226;
+	  }
+	}
+      } else {
+	for (iel = i1; iel <= i2; ++iel) {
+	  int j,k;
+	  int irow = UNSHIFT_INDEX(hrowi[iel]);
+	  int iput = hinrow[irow];
+	  k=mrstrt[irow]+iput;
+	  j=eta_next[irow];
+	  if (k >= mrstrt[j]) {
+	    /* no room - can we make some? */
+	    int klast=eta_last[nrow+1];
+	    int jput=mrstrt[klast]+hinrow[klast]+2;
+	    int distance=mrstrt[nrow+1]-jput;
+	    if (iput+1<distance) {
+	      /* this presumably copies the row to the end */
+	      int jn,jl;
+	      int kstart=mrstrt[irow];
+	      int nin=hinrow[irow];
+	      /* out */
+	      jn=eta_next[irow];
+	      jl=eta_last[irow];
+	      eta_next[jl]=jn;
+	      eta_last[jn]=jl;
+	      /* in */
+	      eta_next[klast]=irow;
+	      eta_last[nrow+1]=irow;
+	      eta_last[irow]=klast;
+	      eta_next[irow]=nrow+1;
+	      mrstrt[irow]=jput;
+#if 0
+	      memcpy(&hcoli[jput],&hcoli[kstart],nin*sizeof(int));
+	      memcpy(&de2val[jput],&de2val[kstart],nin*sizeof(double));
+#else
+	      c_ekkscpy(nin,hcoli+kstart,hcoli+jput);
+	      c_ekkdcpy(nin,
+		      (de2val+kstart),(de2val+jput));
+#endif
+	      k=jput+iput;
+	    } else {
+	      /* shuffle down */
+	      int spare=(fact->nnetas-fact->nnentu-fact->nnentl-3);
+	      if (spare>nrow<<1) {
+		/* presumbly, this compacts the rows */
+		int jrow,jput;
+		if (1) {
+		  if (fact->num_resets<1000000) {
+		    int etasize =CoinMax(4*fact->nnentu+
+					 (fact->nnetas-fact->nnentl)+1000,fact->eta_size);
+		    if (ifrows) {
+		      fact->num_resets++;
+		      if (npivot>40&&fact->num_resets<<4>npivot) {
+			fact->eta_size=static_cast<int>(1.05*fact->eta_size);
+			fact->num_resets=1000000;
+		      }
+		    } else {
+		      fact->eta_size=static_cast<int>(1.1*fact->eta_size);
+		      fact->num_resets=1000000;
+		    }
+		    fact->eta_size=CoinMin(fact->eta_size,etasize);
+		    if (fact->maxNNetas>0&&fact->eta_size>
+			fact->maxNNetas) {
+		      fact->eta_size=fact->maxNNetas;
+		    }
+		  }
+		}
+		jrow=eta_next[0];
+		jput=1;
+		for (j=0;j<nrow;j++) {
+		  int k,nin=hinrow[jrow];
+		  k=mrstrt[jrow];
+		  mrstrt[jrow]=jput;
+		  for (;nin;nin--) {
+		    hcoli[jput]=hcoli[k];
+		    de2val[jput++]=de2val[k++];
+		  }
+		  jrow=eta_next[jrow];
+		}
+		if (spare>nrow<<3) {
+		  spare=3;
+		} else if (spare>nrow<<2) {
+		  spare=1;
+		} else {
+		  spare=0;
+		} 
+		jput+=nrow*spare;;
+		jrow=eta_last[nrow+1];
+		for (j=0;j<nrow;j++) {
+		  int k,nin=hinrow[jrow];
+		  k=mrstrt[jrow]+nin;
+		  jput-=spare;
+		  for (;nin;nin--) {
+		    hcoli[--jput]=hcoli[--k];
+		    de2val[jput]=de2val[k];
+		  }
+		  mrstrt[jrow]=jput;
+		  jrow=eta_last[jrow];
+		}
+		/* set up for copy below */
+		k=mrstrt[irow]+iput;
+	      } else {
+		/* no room - switch off */
+		doSparse=0;
+		/* possible kpivrw 1 */
+		k1 = mrstrt[kpivrw];
+		mrstrt[1]=-1;
+		fact->rows_ok = false;
+		goto L1226;
+	      }
+	    }
+	  }
+	  /* now we have room - append the new value */
+	  hinrow[irow] = iput + 1;
+	  hcoli[k] = kpivrw;
+	  de2val[k] = dluval[iel];
+	}
+      }
+    }
+    
+    /*       TAKE OUT ALL ELEMENTS IN PIVOT ROW */
+    k1 = mrstrt[kpivrw];
+    
+  L1226:
+    {
+      int k2 = k1 + hinrow[kpivrw] - 1;
+      
+      /* "delete" the row */
+      hinrow[kpivrw] = 0;
+      j = 0;
+      if (doSparse) {
+	/* remove pivot row entries from the corresponding columns */
+	for (k = k1; k <= k2; ++k) {
+	  int icol = hcoli[k];
+	  int kx = mcstrt[icol];
+	  int nel = hrowi[kx];
+	  for (iel = kx + 1; iel <= kx+nel; iel ++) {
+	    if (hrowi[iel] == jpivrw) {
+	      break;
+	    }
+	  }
+	  if (iel <= kx+nel) {
+	    /* this has to happen, right?? */
+	    
+	    /* copy the element into a temporary */
+	    dwork1[icol] = dluval[iel];
+	    mpt2[nincol++]=icol;
+	    /*nonzero[icol-1]=1;*/
+	    
+	    hrowi[kx]=nel-1;	/* column is shorter by one */
+	    j=1;
+	    hrowi[iel]=hrowi[kx+nel];
+	    dluval[iel]=dluval[kx+nel];
+#ifdef CLP_REUSE_ETAS
+	    hrowi[kx+nel]=jpivrw;
+	    dluval[kx+nel]=dwork1[icol];
+#endif
+	  }
+	}
+	if (j != 0) {
+	  /* now compute r', the new R transform */
+	  orig_nincol=c_ekkbtju_sparse(fact, dwork1,
+				     mpt2, nincol,
+				     spare);
+	  dwork1[kpivrw]=0.0;
+	}
+      } else {
+	/* row version isn't ok (?) */
+	for (k = k1; k <= k2; ++k) {
+	  int icol = hcoli[k];
+	  int kx = mcstrt[icol];
+	  int nel = hrowi[kx];
+	  j = kx+nel;
+	  int iel;
+	  for (iel=kx+1;iel<=j;iel++) {
+	    if (hrowi[iel]==jpivrw)
+	      break;
+	  }
+	  dwork1[icol] = dluval[iel];
+	  if (kx<first_dense_mcstrt || kx>last_dense_mcstrt) {
+	    hrowi[kx] = nel - 1;	/* shorten column */
+	    /* not packing - presumably column isn't sorted */
+	    hrowi[iel] = hrowi[j];
+	    dluval[iel] = dluval[j];
+#ifdef CLP_REUSE_ETAS
+	    hrowi[j]=jpivrw;
+	    dluval[j]=dwork1[icol];
+#endif
+	  } else {
+	    /* dense element - just zero it */
+	    dluval[iel]=0.0;
+	  }
+	}
+	if (j != 0) {
+	  /* Find first nonzero */
+	  int ipiv = hpivco_new[kpivrw];
+	  while(ipiv<=nrow) {
+	    if (!dwork1[ipiv]) {
+	      ipiv=hpivco_new[ipiv];
+	    } else {
+	      break;
+	    }
+	  }
+	  if (ipiv<=nrow) {
+	    /*       DO U */
+	    /* now compute r', the new R transform */
+	    c_ekkbtju(fact, dwork1,
+		      ipiv);
+	  }
+	}
+      }
+    }
+  }
+  
+  if (kpivrw==fact->first_dense) {
+    /* increase until valid pivot */
+    fact->first_dense=hpivco_new[fact->first_dense];
+  } else if (kpivrw==fact->last_dense) {
+    fact->last_dense=back[fact->last_dense];
+  }
+  if (fact->first_dense==fact->last_dense) {
+    fact->ndenuc=0;
+    fact->first_dense=0;
+    fact->last_dense=-1;
+  }
+  if (! (ifRowCopy && j==0)) {
+    
+    /*     increase amount of work on Etas */
+    
+    /* **************************************************************** */
+    /*       DO ROW ETAS IN L */
+    {
+      if (!doSparse) {
+	dwork1[kpivrw] = 0.;
+#if 0	
+	orig_nincol=c_ekksczr(fact,nrow, dwork1, mpt2);
+	del3=c_ekkputl(fact, mpt2, dwork1, del3, 
+		     orig_nincol, nuspik);
+#else
+	orig_nincol=c_ekkputl2(fact,
+		      dwork1, &del3, 
+		     nuspik);
+#endif
+      } else {
+	del3=c_ekkputl(fact, mpt2,
+		      dwork1, del3, 
+		     orig_nincol, nuspik);
+      }
+    }
+    if (orig_nincol != 0) {
+      /* STORE AS A ROW VECTOR */
+      int n = fact->nR_etas+1;
+      int i1 = fact->R_etas_start[n];
+      fact->nR_etas=n;
+      fact->R_etas_start[n + 1] = i1 - orig_nincol;
+      hpivco[fact->nR_etas + nrow+3] = kpivrw;
+    }
+  }
+  
+  /*       CHECK DEL3 AGAINST DALPHA/DOUT */
+  {
+    int kx = mcstrt[kpivrw];
+    double dout = dluval[kx];
+    double dcheck = fabs(dalpha / dout);
+    double difference=0.0;
+    if (fabs(del3) > CoinMin(1.0e-8,fact->drtpiv*0.99999)) {
+      double checkTolerance;
+      if ( fact->npivots < 2 ) {
+	checkTolerance = 1.0e-5;
+      } else if ( fact->npivots < 10 ) {
+	checkTolerance = 1.0e-6;
+      } else if ( fact->npivots < 50 ) {
+	checkTolerance = 1.0e-8;
+      } else {
+	checkTolerance = 1.0e-9;
+      }
+      difference = fabs(1.0-fabs(del3)/dcheck);
+      if (difference > 0.1*checkTolerance) {
+	if (difference < checkTolerance||
+	    (difference<1.0e-7&&fact->npivots>=50)) {
+	  irtcod=1;
+#ifdef PRINT_DEBUG
+	  printf("mildly bad %g after %d pivots, etsj %g ftncheck %g ftnalpha %g\n",
+		 difference,fact->npivots,del3,dcheck,dalpha);
+#endif    
+	} else {
+	  irtcod=2;
+#ifdef PRINT_DEBUG
+	  printf("bad %g after %d pivots, etsj %g ftncheck %g ftnalpha %g\n",
+		 difference,fact->npivots,del3,dcheck,dalpha);
+#endif    
+	}
+      }
+    } else {
+      irtcod=2;
+#ifdef PRINT_DEBUG
+      printf("bad small %g after %d pivots, etsj %g ftncheck %g ftnalpha %g\n",
+	     difference,fact->npivots,del3,dcheck,dalpha);
+#endif    
+    }
+    if (irtcod>1)
+      goto L8000;
+    fact->npivots++;
+  }
+  
+  mcstrt[kpivrw] = fact->nnentu;
+#ifdef CLP_REUSE_ETAS
+  {
+    int * putSeq = fact->xrsadr+2*fact->nrowmx+2;
+    int * position = putSeq+fact->maxinv;
+    int * putStart = position+fact->maxinv;
+    putStart[fact->nrow+fact->npivots-1]=fact->nnentu;
+  }
+#endif
+  dluval[fact->nnentu] = 1. / del3;	/* new pivot */
+  hrowi[fact->nnentu] = nuspik;	/* new nelems */
+#ifndef NDEBUG
+  {
+    int lastSlack = fact->lastSlack;
+    int firstDo=hpivco_new[lastSlack];
+    int ipiv=hpivco_new[0];
+    int now = fact->numberSlacks;
+    if (now) {
+      while (1) {
+	if (ipiv>fact->nrow||ipiv==firstDo)
+	  break;
+	assert (c_ekk_IsSet(fact->bitArray,ipiv));
+	ipiv=hpivco_new[ipiv];
+      }
+      if (ipiv<=fact->nrow) {
+	while (1) {
+	  if (ipiv>fact->nrow)
+	    break;
+	  assert (!c_ekk_IsSet(fact->bitArray,ipiv));
+	  ipiv=hpivco_new[ipiv];
+	}
+      }
+    }
+  }
+#endif
+  {
+    /* do new hpivco */
+    int inext=hpivco_new[kpivrw];
+    int iback=back[kpivrw];
+    if (inext!=nrow+1) {
+      int ilast=back[nrow+1];
+      hpivco_new[iback]=inext;
+      back[inext]=iback;
+      assert (hpivco_new[ilast]==nrow+1);
+      hpivco_new[ilast]=kpivrw;
+      back[kpivrw]=ilast;
+      hpivco_new[kpivrw]=nrow+1;
+      back[nrow+1]=kpivrw;
+    }
+  }
+  {
+    int lastSlack = fact->lastSlack;
+    int now = fact->numberSlacks;
+    if (now&&mcstrt_piv<=mcstrt[lastSlack]) {
+      if (c_ekk_IsSet(fact->bitArray,kpivrw)) {
+	/*printf("piv %d lastSlack %d\n",mcstrt_piv,lastSlack);*/
+	fact->numberSlacks--;	
+	now--;
+	/* one less slack */
+	c_ekk_Unset(fact->bitArray,kpivrw);
+	if (now&&kpivrw==lastSlack) {
+	  int i;
+	  int ipiv;
+	  ipiv=hpivco_new[0];
+	  for (i=0;i<now-1;i++)
+	    ipiv=hpivco_new[ipiv];
+	  lastSlack=ipiv;
+	  assert (c_ekk_IsSet(fact->bitArray,ipiv));
+	  assert (!c_ekk_IsSet(fact->bitArray,hpivco_new[ipiv])||hpivco_new[ipiv]>fact->nrow);
+	  fact->lastSlack = lastSlack;
+	} else if (!now) {
+	  fact->lastSlack=0;
+	}
+      }
+    }
+    fact->firstNonSlack=hpivco_new[lastSlack];
+#ifndef NDEBUG
+    {
+      int lastSlack = fact->lastSlack;
+      int firstDo=hpivco_new[lastSlack];
+      int ipiv=hpivco_new[0];
+      int now = fact->numberSlacks;
+      if (now) {
+	while (1) {
+	  if (ipiv>fact->nrow||ipiv==firstDo)
+	    break;
+	  assert (c_ekk_IsSet(fact->bitArray,ipiv));
+	  ipiv=hpivco_new[ipiv];
+	}
+	if (ipiv<=fact->nrow) {
+	  while (1) {
+	    if (ipiv>fact->nrow)
+	      break;
+	    assert (!c_ekk_IsSet(fact->bitArray,ipiv));
+	    ipiv=hpivco_new[ipiv];
+	  }
+	}
+      }
+    }
+#endif
+  }
+  fact->nnentu += nuspik;
+#ifdef CLP_REUSE_ETAS
+  if (fact->first_dense>=fact->last_dense) {
+    // save
+    fact->nnentu++;
+    dluval[fact->nnentu]=del3Orig;
+    hrowi[fact->nnentu]=kpivrw;
+    int * putSeq = fact->xrsadr+2*fact->nrowmx+2;
+    int * position = putSeq+fact->maxinv;
+    int * putStart = position+fact->maxinv;
+    int nnentu_at_factor=putStart[fact->nrow]&0x7fffffff;
+    //putStart[fact->nrow+fact->npivots]=fact->nnentu+1;
+    int where;
+    if (mcstrt_piv<nnentu_at_factor) {
+      // original LU
+      where=kpivrw-1;
+    } else {
+      // could do binary search
+      int * look = putStart+fact->nrow;
+      for (where=fact->npivots-1;where>=0;where--) {
+	if (mcstrt_piv==(look[where]&0x7fffffff))
+	  break;
+      }
+      assert (where>=0);
+      where += fact->nrow;
+    }
+    position[fact->npivots-1]=where;
+    if (orig_nincol == 0) {
+      // flag
+      putStart[fact->nrow+fact->npivots-1] |= 0x80000000;
+    }
+  }
+#endif
+  {
+    int kdnspt = fact->nnetas - fact->nnentl;
+    
+    /* fact->R_etas_start[fact->nR_etas + 1] is -(the number of els in R) */
+    nnentl = fact->nnetas - ((kdnspt - 1) + fact->R_etas_start[fact->nR_etas + 1]);
+  }
+  fact->demark = (fact->nnentu + nnentl) - fact->demark;
+  
+  /*     if need to redo row version */
+  if (! fact->rows_ok&&fact->first_dense>=fact->last_dense) {
+    int extraSpace=10000;
+    int spareSpace;
+    if (fact->if_sparse_update>0) {
+      spareSpace=(fact->nnetas-fact->nnentu-fact->nnentl);
+    } else {
+      /* missing out nnentl stuff */
+      spareSpace=fact->nnetas-fact->nnentu;
+    }
+    /*       save clean row copy if enough room */
+    nroom = spareSpace / nrow;
+    
+    if ((fact->nnentu<<3)>150*fact->maxinv) {
+      extraSpace=150*fact->maxinv;
+    } else {
+      extraSpace=fact->nnentu<<3;
+    }
+    
+    ifrows = false;
+    if (fact->nnetas>fact->nnentu+fact->nnentl+extraSpace) {
+      ifrows = true;
+    }
+    if (nroom < 5) {
+      ifrows = false;
+    }
+    
+    if (nroom > CoinMin(50, fact->maxinv - (fact->iterno - fact->iterin))) {
+      ifrows = true;
+    }
+    
+#ifdef PRINT_DEBUGx
+    printf(" redoing row copy %d %d %d\n",ifrows,nroom,spareSpace);
+#endif
+    if (1) {
+      if (fact->num_resets<1000000) {
+	if (ifrows) {
+	  fact->num_resets++;
+	  if (npivot>40&&fact->num_resets<<4>npivot) {
+	    fact->eta_size=static_cast<int>(1.05*fact->eta_size);
+	    fact->num_resets=1000000;
+	  }
+	} else {
+	  fact->eta_size=static_cast<int>(1.1*fact->eta_size);
+	  fact->num_resets=1000000;
+	}
+	if (fact->maxNNetas>0&&fact->eta_size>
+	    fact->maxNNetas) {
+	  fact->eta_size=fact->maxNNetas;
+	}
+      }
+    }
+    fact->rows_ok = ifrows;
+    if (ifrows) {
+      int ibase = 1;
+      c_ekkizero(nrow,&hinrow[1]);
+      for (i = 1; i <= nrow; ++i) {
+	int kx = mcstrt[i];
+	int nel = hrowi[kx];
+	int kcs = kx + 1;
+	int kce = kx + nel;
+	for (kc = kcs; kc <= kce; ++kc) {
+	  int irow = UNSHIFT_INDEX(hrowi[kc]);
+	  if (dluval[kc]) {
+	    hinrow[irow]++;
+	  }
+	}
+      }
+      int * eta_last=mpermu+nrow*2+3;
+      int * eta_next=eta_last+nrow+2;
+      eta_next[0]=1;
+      for (i = 1; i <= nrow; ++i) {
+	eta_next[i]=i+1;
+	eta_last[i]=i-1;
+	mrstrt[i] = ibase;
+	ibase = ibase + hinrow[i] + nroom;
+	hinrow[i] = 0;
+      }
+      eta_last[nrow+1]=nrow;
+      //eta_next[nrow+1]=nrow+2;
+      mrstrt[nrow+1]=ibase;
+      if (fact->xe2adr == 0) {
+	for (i = 1; i <= nrow; ++i) {
+	  int kx = mcstrt[i];
+	  int nel = hrowi[kx];
+	  int kcs = kx + 1;
+	  int kce = kx + nel;
+	  for (kc = kcs; kc <= kce; ++kc) {
+	    if (dluval[kc]) {
+	      int irow = UNSHIFT_INDEX(hrowi[kc]);
+	      int iput = hinrow[irow];
+	      assert (irow);
+	      hcoli[mrstrt[irow] + iput] = i;
+	      hinrow[irow] = iput + 1;
+	    }
+	  }
+	}
+      } else {
+	for (i = 1; i <= nrow; ++i) {
+	  int kx = mcstrt[i];
+	  int nel = hrowi[kx];
+	  int kcs = kx + 1;
+	  int kce = kx + nel;
+	  for (kc = kcs; kc <= kce; ++kc) {
+	    int irow = UNSHIFT_INDEX(hrowi[kc]);
+	    int iput = hinrow[irow];
+	    hcoli[mrstrt[irow] + iput] = i;
+	    de2val[mrstrt[irow] + iput] = dluval[kc];
+	    hinrow[irow] = iput + 1;
+	  }
+	}
+      }
+    } else {
+      mrstrt[1] = 0;
+      if (fact->if_sparse_update>0&&fact->iterno-fact->iterin>100) {
+	goto L7000;
+      }
+    }
+  }
+  goto L8000;
+  
+  /*       OUT OF SPACE - COULD PACK DOWN */
+ L7000:
+  irtcod = 1;
+#ifdef PRINT_DEBUG
+  printf(" out of space\n");
+#endif    
+  if (1) {
+    if ((npivot<<3)<fact->nbfinv) {
+      /* low on space */
+      if (npivot<10) {
+	fact->eta_size=fact->eta_size<<1;
+      } else {
+	double ratio=fact->nbfinv;
+	double ratio2=npivot<<3;
+	ratio=ratio/ratio2;
+	if (ratio>2.0) {
+	  ratio=2.0;
+	} /* endif */
+	fact->eta_size=static_cast<int>(ratio*fact->eta_size);
+      } /* endif */
+    } else {
+      fact->eta_size=static_cast<int>(1.05*fact->eta_size);
+    } /* endif */
+    if (fact->maxNNetas>0&&fact->eta_size>
+	fact->maxNNetas) {
+      fact->eta_size=fact->maxNNetas;
+    }
+  }
+  
+  /* ================= IF ERROR SHOULD WE GET RID OF LAST ITERATION??? */
+ L8000:
+  
+  *nuspikp = nuspik;
+#ifdef MORE_DEBUG
+  for (int i=1;i<=fact->nrow;i++) {
+    int kx=mcstrt[i];
+    int nel=hrowi[kx];
+    for (int j=0;j<nel;j++) {
+      assert (i!=hrowi[j+kx+1]);
+    }
+  }
+#endif
+#ifdef CLP_REUSE_ETAS
+  fact->save_nnentu=fact->nnentu;
+#endif
+  return (irtcod);
+} /* c_ekketsj */
+static void c_ekkftj4p(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, 
+		     double * COIN_RESTRICT dwork1, int firstNonZero)
+{
+  /* this is where the L factors start, because this is the place
+   * where c_ekktria starts laying them down (see initialization of xnetal).
+   */
+  int lstart=fact->lstart;
+  const int * COIN_RESTRICT hpivco	= fact->kcpadr;
+  int firstLRow = hpivco[lstart];
+  if (firstNonZero>firstLRow) {
+    lstart += firstNonZero-firstLRow;
+  }
+  assert (firstLRow==fact->firstLRow);
+  int jpiv=hpivco[lstart];
+  const double * COIN_RESTRICT dluval	= fact->xeeadr;
+  const int * COIN_RESTRICT hrowi	= fact->xeradr;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr+lstart;
+  int ndo=fact->xnetal-lstart;
+  int i, iel;
+  
+  /* find first non-zero */
+  for (i=0;i<ndo;i++) {
+    if (dwork1[i+jpiv]!=0.0)
+      break;
+  }
+  for (; i < ndo; ++i) {
+    double dv = dwork1[i+jpiv];
+    
+    if (dv != 0.) {
+      int kce1 = mcstrt[i + 1] ;
+      
+      for (iel = mcstrt[i]; iel > kce1; --iel) {
+	int irow0 = hrowi[iel];
+	SHIFT_REF(dwork1, irow0) += dv * dluval[iel];
+      }
+    }
+  }
+  
+} /* c_ekkftj4p */
+
+/*
+ * This version is more efficient for input columns that are sparse.
+ * It is instructive to consider the case of an especially sparse column,
+ * which is a slack.  The slack for row r has exactly one non-zero element,
+ * in row r, which is +-1.0.  Let pr = mpermu[r].
+ * In this case, nincol==1 and mpt[0] == pr on entry.
+ * if mpt[0] == pr <= jpiv
+ * then this slack is completely unaffected by L;
+ *	this is reflected by the fact that save_where = last
+ *	after the first loop, so none of the remaining loops
+ *	ever execute,
+ * else if mpt[0] == pr > jpiv, but pr-jpiv > ndo
+ * then the slack is also unaffected by L, this time because
+ *	its row is "after" L.  During factorization, it may
+ *	be the case that the first part of the basis is upper
+ *	triangular (c_ekktria), but it may also be the case that the
+ *	last part of the basis is upper triangular (in which case the
+ *	L triangle gets "chopped off" on the right).  In both cases,
+ *	no L entries are required.  Since in this case the tests
+ *	(i<=ndo) will fail (and dwork1[ipiv]==1.0), the code will
+ *	do nothing.
+ * else if mpt[0] == pr > jpiv and pr-jpiv <= ndo
+ * then the slack *is* affected by L.
+ *	the for-loop inside the second while-loop will discover
+ *	that none of the factors for the corresponding column of L
+ *	are non-zero in the slack column, so last will not be incremented.
+ *	We multiply the eta-vector, and the last loop does nothing.
+ */
+static int c_ekkftj4_sparse(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+		   double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt,
+		   int nincol,int * COIN_RESTRICT spare)
+{
+  const int nrow	= fact->nrow;
+  /* this is where the L factors start, because this is the place
+   * where c_ekktria starts laying them down (see initialization of xnetal).
+   */
+  int lstart=fact->lstart;
+  const int * COIN_RESTRICT hpivco	= fact->kcpadr;
+  const double * COIN_RESTRICT dluval	= fact->xeeadr;
+  const int * COIN_RESTRICT hrowi	= fact->xeradr;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr+lstart-1;
+  double tolerance = fact->zeroTolerance;
+  int jpiv=hpivco[lstart]-1;
+  char * COIN_RESTRICT nonzero=fact->nonzero;
+  int ndo=fact->xnetalval;
+  int k,nStack;
+  int nList=0;
+  int iPivot;
+  int * COIN_RESTRICT list = spare;
+  int * COIN_RESTRICT stack = spare+nrow;
+  int * COIN_RESTRICT next = stack+nrow;
+  double dv;
+  int iel;
+  int nput=0,kput=nrow;
+  int check=jpiv+ndo+1;
+  const int * COIN_RESTRICT mcstrt2 = mcstrt-jpiv;
+  
+  for (k=0;k<nincol;k++) {
+    nStack=1;
+    iPivot=mpt[k];
+    if (nonzero[iPivot]!=1&&iPivot>jpiv&&iPivot<check) {
+      stack[0]=iPivot;
+      next[0]=mcstrt2[iPivot+1]+1;
+      while (nStack) {
+	int kPivot,j;
+	/* take off stack */
+	kPivot=stack[--nStack];
+	if (nonzero[kPivot]!=1&&kPivot>jpiv&&kPivot<check) {
+	  j=next[nStack];
+	  if (j>mcstrt2[kPivot]) {
+	    /* finished so mark */
+	    list[nList++]=kPivot;
+	    nonzero[kPivot]=1;
+	  } else {
+	    kPivot=UNSHIFT_INDEX(hrowi[j]);
+	    /* put back on stack */
+	    next[nStack++] ++;
+	    if (!nonzero[kPivot]) {
+	      /* and new one */
+	      stack[nStack]=kPivot;
+	      nonzero[kPivot]=2;
+	      next[nStack++]=mcstrt2[kPivot+1]+1;
+	    }
+	  }
+	} else if (kPivot>=check) {
+	  list[--kput]=kPivot;
+	  nonzero[kPivot]=1;
+	}
+      }
+    } else if (nonzero[iPivot]!=1) {
+      /* nothing to do (except check size at end) */
+      list[--kput]=iPivot;
+      nonzero[iPivot]=1;
+    }
+  }
+  for (k=nList-1;k>=0;k--) {
+    double dv;
+    iPivot = list[k];
+    dv = dwork1[iPivot];
+    nonzero[iPivot]=0;
+    if (fabs(dv) > tolerance) {
+      /* the same code as in c_ekkftj4p */
+      int kce1 = mcstrt2[iPivot + 1];
+      for (iel = mcstrt2[iPivot]; iel > kce1; --iel) {
+	int irow0 = hrowi[iel];
+	SHIFT_REF(dwork1, irow0) += dv * dluval[iel];
+      }
+      mpt[nput++]=iPivot;
+    } else {
+      dwork1[iPivot]=0.0;	/* force to zero, not just near zero */
+    }
+  }
+  /* check remainder */
+  for (k=kput;k<nrow;k++) {
+    iPivot = list[k];
+    nonzero[iPivot]=0;
+    dv = dwork1[iPivot];
+    if (fabs(dv) > tolerance) {
+      mpt[nput++]=iPivot;
+    } else {
+      dwork1[iPivot]=0.0;	/* force to zero, not just near zero */
+    }
+  }
+  
+  return (nput);
+} /* c_ekkftj4 */
+/*
+ * This applies the R transformations of the F-T LU update procedure,
+ * equation 3.11 on p. 270 in the 1972 Math Programming paper.
+ * Note that since the non-zero off-diagonal elements are in a row,
+ * multiplying an R by a column is a reduction, not like applying
+ * L or U.
+ *
+ * Note that this may introduce new non-zeros in dwork1,
+ * since an hpivco entry may correspond to a zero element,
+ * and that some non-zeros in dwork1 may be cancelled.
+ */
+static int c_ekkftjl_sparse3(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+		    double * COIN_RESTRICT dwork1, 
+		    int * COIN_RESTRICT mpt,
+		    int * COIN_RESTRICT hput, double * COIN_RESTRICT dluput ,
+		    int nincol)
+{
+  int i;
+  int knext;
+  int ipiv;
+  double dv;
+  const double * COIN_RESTRICT dluval = fact->R_etas_element+1;
+  const int * COIN_RESTRICT hrowi = fact->R_etas_index+1;
+  const int * COIN_RESTRICT mcstrt = fact->R_etas_start;
+  int ndo=fact->nR_etas;
+  double tolerance = fact->zeroTolerance;
+  const int * COIN_RESTRICT hpivco = fact->hpivcoR;
+  /* and make cleaner */
+  hput++;
+  dluput++;
+  
+  /* DO ANY ROW TRANSFORMATIONS */
+  
+  /* Function Body */
+  /* mpt has correct list of nonzeros */
+  if (ndo != 0) {
+    knext = mcstrt[1];
+    for (i = 1; i <= ndo; ++i) {
+      int k1 = knext;	/* == mcstrt[i] */
+      int iel;
+      ipiv = hpivco[i];
+      dv = dwork1[ipiv];
+      bool onList = (dv!=0.0);
+      knext = mcstrt[i + 1];
+      
+      for (iel = knext ; iel < k1; ++iel) {
+	int irow = hrowi[iel];
+	dv += SHIFT_REF(dwork1, irow) * dluval[iel];
+      }
+      /* (1) if dwork[ipiv] == 0.0, then this may add a non-zero.
+       * (2) if dwork[ipiv] != 0.0, then this may cancel out a non-zero.
+       */
+      if (onList) {
+	if (fabs(dv) > tolerance) {
+	  dwork1[ipiv]=dv;
+	} else {
+	  dwork1[ipiv] = 1.0e-128;
+	}
+      } else {
+	if (fabs(dv) > tolerance) {
+	  /* put on list if not there */
+	  mpt[nincol++]=ipiv;
+	  dwork1[ipiv]=dv;
+	} 
+      }
+    }
+  }
+  knext=0;
+  for (i=0; i<nincol; i++) {
+    ipiv=mpt[i];
+    dv=dwork1[ipiv];
+    if (fabs(dv) > tolerance) {
+      hput[knext]=SHIFT_INDEX(ipiv);
+      dluput[knext]=dv;
+      mpt[knext++]=ipiv;
+    } else {
+      dwork1[ipiv]=0.0;
+    }
+  }
+  return knext;
+} /* c_ekkftjl */
+
+static int c_ekkftjl_sparse2(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+		    double * COIN_RESTRICT dwork1, 
+		    int * COIN_RESTRICT mpt,
+		    int nincol)
+{
+  double tolerance = fact->zeroTolerance;
+  const double * COIN_RESTRICT dluval = fact->R_etas_element+1;
+  const int * COIN_RESTRICT hrowi = fact->R_etas_index+1;
+  const int * COIN_RESTRICT mcstrt = fact->R_etas_start;
+  int ndo=fact->nR_etas;
+  const int * COIN_RESTRICT hpivco = fact->hpivcoR;
+  int i;
+  int knext;
+  int ipiv;
+  double dv;
+  
+  /* DO ANY ROW TRANSFORMATIONS */
+  
+  /* Function Body */
+  /* mpt has correct list of nonzeros */
+  if (ndo != 0) {
+    knext = mcstrt[1];
+    for (i = 1; i <= ndo; ++i) {
+      int k1 = knext;	/* == mcstrt[i] */
+      int iel;
+      ipiv = hpivco[i];
+      dv = dwork1[ipiv];
+      bool onList = (dv!=0.0);
+      knext = mcstrt[i + 1];
+      
+      for (iel = knext ; iel < k1; ++iel) {
+	int irow = hrowi[iel];
+	dv += SHIFT_REF(dwork1, irow) * dluval[iel];
+      }
+      /* (1) if dwork[ipiv] == 0.0, then this may add a non-zero.
+       * (2) if dwork[ipiv] != 0.0, then this may cancel out a non-zero.
+       */
+      if (onList) {
+	if (fabs(dv) > tolerance) {
+	  dwork1[ipiv]=dv;
+	} else {
+	  dwork1[ipiv] = 1.0e-128;
+	}
+      } else {
+	if (fabs(dv) > tolerance) {
+	  /* put on list if not there */
+	  mpt[nincol++]=ipiv;
+	  dwork1[ipiv]=dv;
+	} 
+      }
+    }
+  }
+  knext=0;
+  for (i=0; i<nincol; i++) {
+    ipiv=mpt[i];
+    dv=dwork1[ipiv];
+    if (fabs(dv) > tolerance) {
+      mpt[knext++]=ipiv;
+    } else {
+      dwork1[ipiv]=0.0;
+    }
+  }
+  return knext;
+} /* c_ekkftjl */
+
+static void c_ekkftjl(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+	     double * COIN_RESTRICT dwork1)
+{
+  double tolerance = fact->zeroTolerance;
+  const double * COIN_RESTRICT dluval = fact->R_etas_element+1;
+  const int * COIN_RESTRICT hrowi = fact->R_etas_index+1;
+  const int * COIN_RESTRICT mcstrt = fact->R_etas_start;
+  int ndo=fact->nR_etas;
+  const int * COIN_RESTRICT hpivco = fact->hpivcoR;
+  int i;
+  int knext;
+  
+  /* DO ANY ROW TRANSFORMATIONS */
+  
+  /* Function Body */
+  if (ndo != 0) {
+    /*
+     * The following three lines are here just to ensure that this
+     * new formulation of the loop has exactly the same effect
+     * as the original.
+     */
+    {
+      int ipiv = hpivco[1];
+      double dv = dwork1[ipiv];
+      dwork1[ipiv] = (fabs(dv) > tolerance) ? dv : 0.0;
+    }
+    
+    knext = mcstrt[1];
+    for (i = 1; i <= ndo; ++i) {
+      int k1 = knext;	/* == mcstrt[i] */
+      int ipiv = hpivco[i];
+      double dv = dwork1[ipiv];
+      int iel;
+      //#define UNROLL3 2
+#ifndef UNROLL3
+#if CLP_OSL==2||CLP_OSL==3
+#define UNROLL3 2
+#else
+#define UNROLL3 1
+#endif
+#endif
+      knext = mcstrt[i + 1];
+      
+#if UNROLL3<2
+      for (iel = knext ; iel < k1; ++iel) {
+	int irow = hrowi[iel];
+	dv += SHIFT_REF(dwork1, irow) * dluval[iel];
+      }
+#else
+      iel = knext;
+      if (((k1-knext)&1)!=0) {
+	int irow = hrowi[iel];
+	dv += SHIFT_REF(dwork1, irow) * dluval[iel];
+	iel++;
+      }
+      for ( ; iel < k1; iel+=2) {
+	int irow0 = hrowi[iel];
+	double dval0 = dluval[iel];
+	int irow1 = hrowi[iel+1];
+	double dval1 = dluval[iel+1];
+	dv += SHIFT_REF(dwork1, irow0) * dval0;
+	dv += SHIFT_REF(dwork1, irow1) * dval1; 
+      }
+#endif
+      /* (1) if dwork[ipiv] == 0.0, then this may add a non-zero.
+       * (2) if dwork[ipiv] != 0.0, then this may cancel out a non-zero.
+       */
+      dwork1[ipiv] = (fabs(dv) > tolerance) ? dv : 0.0;
+    }
+  }
+} /* c_ekkftjl */
+/* this assumes it is ok to reference back[loop_limit] */
+/* another 3 seconds from a ~570 second run can be trimmed
+ * by using two routines, one with scan==true and the other false,
+ * since that eliminates the branch instructions involving them
+ * entirely.  This was how the code was originally written.
+ * However, I'm still hoping that eventually we can use
+ * C++ templates to do that for us automatically.
+ */
+static void
+c_ekkftjup_scan_aux(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+		  double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dworko ,
+		  int loop_limit, int *ip, int ** mptp)
+{
+  const double * COIN_RESTRICT dluval	= fact->xeeadr+1;
+  const int * COIN_RESTRICT hrowi	= fact->xeradr+1;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  const int * COIN_RESTRICT hpivro	= fact->krpadr;
+  const int * COIN_RESTRICT back=fact->back;
+  double tolerance = fact->zeroTolerance;
+  int ipiv = *ip;
+  double dv = dwork1[ipiv];
+  
+  int * mptX = *mptp;
+  assert (mptX);
+  while (ipiv != loop_limit) {
+    int next_ipiv = back[ipiv];
+    
+    dwork1[ipiv] = 0.0;
+#ifndef UNROLL4
+#define UNROLL4 2
+#endif
+    /* invariant:  dv == dwork1[ipiv] */
+    
+    /* in the case of world.mps with dual, this condition is true
+     * only 20-60% of the time. */
+    if (fabs(dv) > tolerance) {
+      const int kx = mcstrt[ipiv];
+      const int nel = hrowi[kx-1];
+      const double dpiv = dluval[kx-1];
+#if UNROLL4>1
+      const int * hrowi2=hrowi+kx;
+      const int * hrowi2end=hrowi2+nel;
+      const double * dluval2=dluval+kx;
+#else
+      int iel;
+#endif
+      
+      dv*=dpiv;
+      
+      /*
+       * The following loop is the unrolled version of this:
+       *
+       * for (iel = kx+1; iel <= kx + nel; iel++) {
+       *   SHIFT_REF(dwork1, hrowi[iel]) -= dv * dluval[iel];
+       * }
+       */
+#if UNROLL4<2
+      iel = kx;
+      if (nel&1) {
+	int irow = hrowi[iel];
+	double dval=dluval[iel];
+	SHIFT_REF(dwork1, irow) -= dv*dval;
+	iel++;
+      }
+      for (; iel < kx + nel; iel+=2) {
+	int irow0 = hrowi[iel];
+	int irow1 = hrowi[iel+1];
+	double dval0=dluval[iel];
+	double dval1=dluval[iel+1];
+	double d0=SHIFT_REF(dwork1, irow0);
+	double d1=SHIFT_REF(dwork1, irow1);
+	
+	d0-=dv*dval0;
+	d1-=dv*dval1;
+	SHIFT_REF(dwork1, irow0)=d0;
+	SHIFT_REF(dwork1, irow1)=d1;
+      } /* end loop */
+#else
+      if ((nel&1)!=0) {
+	int irow = *hrowi2;
+	double dval=*dluval2;
+	SHIFT_REF(dwork1, irow) -= dv*dval;
+	hrowi2++;
+	dluval2++;
+      }
+      for (; hrowi2 < hrowi2end; hrowi2 +=2,dluval2 +=2) {
+	int irow0 = hrowi2[0];
+	int irow1 = hrowi2[1];
+	double dval0=dluval2[0];
+	double dval1=dluval2[1];
+	double d0=SHIFT_REF(dwork1, irow0);
+	double d1=SHIFT_REF(dwork1, irow1);
+	
+	d0-=dv*dval0;
+	d1-=dv*dval1;
+	SHIFT_REF(dwork1, irow0)=d0;
+	SHIFT_REF(dwork1, irow1)=d1;
+      }
+#endif
+      /* put this down here so that dv is less likely to cause a stall */
+      if (fabs(dv) >= tolerance) {
+	int iput=hpivro[ipiv];
+	dworko[iput]=dv;
+	*mptX++=iput-1;
+      }
+    }
+    
+    dv = dwork1[next_ipiv];
+    ipiv=next_ipiv;
+  } /* endwhile */
+  
+  *mptp = mptX;
+  *ip = ipiv;
+}
+static void c_ekkftjup_aux3(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+			     double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dworko,
+			  const int * COIN_RESTRICT back,
+			  const int * COIN_RESTRICT hpivro,
+			  int *ipivp, int loop_limit,
+			  int **mptXp)
+  
+{
+  double tolerance = fact->zeroTolerance;
+  int ipiv = *ipivp;
+  if (ipiv!=loop_limit) {
+    int *mptX = *mptXp;
+    
+    double dv = dwork1[ipiv];
+    
+    do {
+      int next_ipiv = back[ipiv];
+      double next_dv=dwork1[next_ipiv];
+      
+      dwork1[ipiv]=0.0;
+      
+      if (fabs(dv)>=tolerance) {
+	int iput=hpivro[ipiv];
+	dworko[iput]=dv;
+	*mptX++=iput-1;
+      }
+      
+      ipiv = next_ipiv;
+      dv = next_dv;
+    } while (ipiv!=loop_limit);
+    
+    *mptXp = mptX;
+    *ipivp = ipiv;
+  }
+}
+static void c_ekkftju_dense(const double *dluval, 
+			    const int * COIN_RESTRICT hrowi, 
+			    const int * COIN_RESTRICT mcstrt,
+			    const int * COIN_RESTRICT back,
+			    double * COIN_RESTRICT dwork1, 
+			    int * start, int last,
+		   int offset , double *densew)
+{
+  int ipiv=*start;
+  
+  while (ipiv>last ) {
+    const int ipiv1=ipiv;
+    double dv1=dwork1[ipiv1];
+    ipiv=back[ipiv];
+    if (fabs(dv1) > 1.0e-14) {
+      const int kx1 = mcstrt[ipiv1];
+      const int nel1 = hrowi[kx1-1];
+      const double dpiv1 = dluval[kx1-1];
+      
+      int iel,k;
+      const int n1=offset+ipiv1;	/* number in dense part */
+      
+      const int nsparse1=nel1-n1;
+      const int k1=kx1+nsparse1;
+      const double *dlu1=&dluval[k1];
+      
+      int ipiv2=back[ipiv1];
+      const int nskip=ipiv1-ipiv2;
+      
+      dv1*=dpiv1;
+      
+      dwork1[ipiv1]=dv1;
+      
+      for (k = n1 - (nskip-1) -1; k >=0 ; k--) {
+        const double dval = dv1*dlu1[k];
+	double dv2=densew[k]-dval;
+        ipiv=back[ipiv];
+        if (fabs(dv2) > 1.0e-14) {
+          const int kx2 = mcstrt[ipiv2];
+          const int nel2 = hrowi[kx2-1];
+          const double dpiv2 = dluval[kx2-1];
+	  
+          /* number in dense part is k */
+          const int nsparse2=nel2-k;
+	  
+          const int k2=kx2+nsparse2;
+          const double *dlu2=&dluval[k2];
+	  
+          dv2*=dpiv2;
+          densew[k]=dv2;	/* was dwork1[ipiv2]=dv2; */
+	  
+          k--;
+	  
+	  /*
+	   * The following loop is the unrolled version of:
+	   *
+	   * for (; k >= 0; k--) {
+	   *   densew[k]-=dv1*dlu1[k]+dv2*dlu2[k];
+	   * }
+	   */
+          if ((k&1)==0) {
+            densew[k]-=dv1*dlu1[k]+dv2*dlu2[k];
+            k--;
+          }
+          for (; k >=0 ; k-=2) {
+            double da,db;
+            da=densew[k];
+            db=densew[k-1];
+            da-=dv1*dlu1[k];
+            db-=dv1*dlu1[k-1];
+            da-=dv2*dlu2[k];
+            db-=dv2*dlu2[k-1];
+            densew[k]=da;
+            densew[k-1]=db;
+          }
+	  /* end loop */
+	  
+	  /*
+	   * The following loop is the unrolled version of:
+	   *
+	   * for (iel=kx2+nsparse2-1; iel >= kx2; iel--) {
+	   *   SHIFT_REF(dwork1, hrowi[iel]) -= dv2*dluval[iel];
+	   * }
+	   */
+	  iel=kx2+nsparse2-1;
+          if ((nsparse2&1)!=0) {
+            int irow0 = hrowi[iel];
+            double dval=dluval[iel];
+            SHIFT_REF(dwork1,irow0) -= dv2*dval;
+            iel--;
+          }
+          for (; iel >=kx2 ; iel-=2) {
+            double dval0 = dluval[iel];
+	    double dval1 = dluval[iel-1];
+            int irow0 = hrowi[iel];
+            int irow1 = hrowi[iel-1];
+            double d0 = SHIFT_REF(dwork1, irow0);
+            double d1 = SHIFT_REF(dwork1, irow1);
+	    
+            d0-=dv2*dval0;
+            d1-=dv2*dval1;
+	    SHIFT_REF(dwork1, irow0) = d0;
+	    SHIFT_REF(dwork1, irow1) = d1;
+          }
+	  /* end loop */
+	  
+        } else {
+          densew[k]=0.0;
+          /* skip if next deleted */
+          k-=ipiv2-ipiv-1;
+          ipiv2=ipiv;
+          if (ipiv<last) {
+	    k--;
+	    for (; k >=0 ; k--) {
+	      double dval;
+	      dval=dv1*dlu1[k];
+	      densew[k]=densew[k]-dval;
+	    }
+	  }
+        }
+      }
+      
+      /*
+       * The following loop is the unrolled version of:
+       *
+       * for (iel=kx1+nsparse1-1; iel >= kx1; iel--) {
+       *   SHIFT_REF(dwork1, hrowi[iel]) -= dv1*dluval[iel];
+       * }
+       */
+      iel=kx1+nsparse1-1;
+      if ((nsparse1&1)!=0) {
+        int irow0 = hrowi[iel];
+        double dval=dluval[iel];
+        SHIFT_REF(dwork1, irow0) -= dv1*dval;
+        iel--;
+      }
+      for (; iel >=kx1 ; iel-=2) {
+        double dval0=dluval[iel];
+        double dval1=dluval[iel-1];
+        int irow0 = hrowi[iel];
+        int irow1 = hrowi[iel-1];
+        double d0=SHIFT_REF(dwork1, irow0);
+        double d1=SHIFT_REF(dwork1, irow1);
+	
+        d0-=dv1*dval0;
+        d1-=dv1*dval1;
+        SHIFT_REF(dwork1, irow0) = d0;
+        SHIFT_REF(dwork1, irow1) = d1;
+      }
+      /* end loop */
+    } else {
+      dwork1[ipiv1]=0.0;
+    } /* endif */
+  } /* endwhile */
+  *start=ipiv;
+}
+
+/* do not use return value if mpt==0 */
+/* using dual, this is usually called via c_ekkftrn_ft, from c_ekksdul
+ * (so mpt is non-null).
+ * it is generally called every iteration, but sometimes several iterations
+ * are skipped (null moves?).
+ *
+ * generally, back[i] == i-1 (initialized in c_ekkshfv towards the end).
+ */
+static int c_ekkftjup(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact,
+	     double * COIN_RESTRICT dwork1, int last,
+	     double * COIN_RESTRICT dworko , int * COIN_RESTRICT mpt)
+{
+  const double * COIN_RESTRICT dluval	= fact->xeeadr;
+  const int * COIN_RESTRICT hrowi	= fact->xeradr;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  const int * COIN_RESTRICT hpivro	= fact->krpadr;
+  double tolerance = fact->zeroTolerance;
+  int ndenuc=fact->ndenuc;
+  const int first_dense=fact->first_dense;
+  const int last_dense=fact->last_dense;
+  int i;
+  int * mptX = mpt;
+  
+  const int nrow		= fact->nrow;
+  const int * COIN_RESTRICT back=fact->back;
+  int ipiv=back[nrow+1];
+  
+  if (last_dense>first_dense&&mcstrt[ipiv]>=mcstrt[last_dense]) {
+    c_ekkftjup_scan_aux(fact,
+		      dwork1, dworko, last_dense, &ipiv,
+		      &mptX);
+    
+    {
+      int j;
+      int n=0;
+      const int firstDense	= nrow- ndenuc+1;
+      double *densew = &dwork1[firstDense];
+      int offset;
+      
+      /* check first dense to see where in triangle it is */
+      int last=first_dense;
+      const int k1=mcstrt[last];
+      const int k2=k1+hrowi[k1];
+      
+      for (j=k2; j>k1; j--) {
+        int irow = UNSHIFT_INDEX(hrowi[j]);
+        if (irow<firstDense) {
+          break;
+        } else {
+#ifdef DEBUG
+          if (irow!=last-1) {
+            abort();
+          }
+#endif
+          last=irow;
+          n++;
+        }
+      }
+      offset=n-first_dense;
+      i=ipiv;
+      /* loop counter i may be modified by this call */
+      c_ekkftju_dense(&dluval[1],&hrowi[1],mcstrt,back,
+		    dwork1, &i, first_dense,offset,densew);
+      
+      c_ekkftjup_aux3(fact,dwork1, dworko, back, hpivro, &ipiv, i, &mptX);
+    }
+  }
+  
+  c_ekkftjup_scan_aux(fact,
+		    dwork1, dworko, last, &ipiv,
+		    &mptX);
+  
+  if (ipiv!=0) {
+    double dv = dwork1[ipiv];
+    
+    do {
+      int next_ipiv = back[ipiv];
+      double next_dv=dwork1[next_ipiv];
+      
+      dwork1[ipiv]=0.0;
+      
+      if (fabs(dv)>=tolerance) {
+	int iput=hpivro[ipiv];
+	dworko[iput]=-dv;
+	*mptX++=iput-1;
+      }
+      
+      ipiv = next_ipiv;
+      dv = next_dv;
+    } while (ipiv!=0);
+    
+  }
+  return static_cast<int>(mptX-mpt);
+}
+/* this assumes it is ok to reference back[loop_limit] */
+/* another 3 seconds from a ~570 second run can be trimmed
+ * by using two routines, one with scan==true and the other false,
+ * since that eliminates the branch instructions involving them
+ * entirely.  This was how the code was originally written.
+ * However, I'm still hoping that eventually we can use
+ * C++ templates to do that for us automatically.
+ */
+static void
+c_ekkftjup_scan_aux_pack(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+		       double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dworko ,
+		       int loop_limit, int *ip, int ** mptp)
+{
+  double tolerance = fact->zeroTolerance;
+  const double *dluval	= fact->xeeadr+1;
+  const int *hrowi	= fact->xeradr+1;
+  const int *mcstrt	= fact->xcsadr;
+  const int *hpivro	= fact->krpadr;
+  const int * back=fact->back;
+  int ipiv = *ip;
+  double dv = dwork1[ipiv];
+  
+  int * mptX = *mptp;
+#if 0
+  int inSlacks=0;
+  int lastSlack;
+  if (fact->numberSlacks!=0)
+    lastSlack=fact->lastSlack;
+  else
+    lastSlack=0;
+  if (c_ekk_IsSet(fact->bitArray,ipiv)) {
+    printf("already in slacks - ipiv %d\n",ipiv);
+    inSlacks=1;
+    return;
+  }
+#endif
+  assert (mptX);
+  while (ipiv != loop_limit) {
+    int next_ipiv = back[ipiv];
+#if 0
+    if (ipiv==lastSlack) {
+      printf("now in slacks - ipiv %d\n",ipiv);
+      inSlacks=1;
+      break;
+    }
+    if (inSlacks) {
+      assert (c_ekk_IsSet(fact->bitArray,ipiv));
+      assert (dluval[mcstrt[ipiv]-1]==-1.0);
+      assert (hrowi[mcstrt[ipiv]-1]==0);
+    }
+#endif
+    dwork1[ipiv] = 0.0;
+    /* invariant:  dv == dwork1[ipiv] */
+    
+    /* in the case of world.mps with dual, this condition is true
+     * only 20-60% of the time. */
+    if (fabs(dv) > tolerance) {
+      const int kx = mcstrt[ipiv];
+      const int nel = hrowi[kx-1];
+      const double dpiv = dluval[kx-1];
+#ifndef UNROLL5
+#define UNROLL5 2
+#endif
+#if UNROLL5>1
+      const int * hrowi2=hrowi+kx;
+      const int * hrowi2end=hrowi2+nel;
+      const double * dluval2=dluval+kx;
+#else
+      int iel;
+#endif
+      
+      dv*=dpiv;
+      
+      /*
+       * The following loop is the unrolled version of this:
+       *
+       * for (iel = kx+1; iel <= kx + nel; iel++) {
+       *   SHIFT_REF(dwork1, hrowi[iel]) -= dv * dluval[iel];
+       * }
+       */
+#if UNROLL5<2
+      iel = kx;
+      if (nel&1) {
+	int irow = hrowi[iel];
+	double dval=dluval[iel];
+	SHIFT_REF(dwork1, irow) -= dv*dval;
+	iel++;
+      }
+      for (; iel < kx + nel; iel+=2) {
+	int irow0 = hrowi[iel];
+	int irow1 = hrowi[iel+1];
+	double dval0=dluval[iel];
+	double dval1=dluval[iel+1];
+	double d0=SHIFT_REF(dwork1, irow0);
+	double d1=SHIFT_REF(dwork1, irow1);
+	
+	d0-=dv*dval0;
+	d1-=dv*dval1;
+	SHIFT_REF(dwork1, irow0)=d0;
+	SHIFT_REF(dwork1, irow1)=d1;
+      } /* end loop */
+#else
+      if ((nel&1)!=0) {
+	int irow = *hrowi2;
+	double dval=*dluval2;
+	SHIFT_REF(dwork1, irow) -= dv*dval;
+	hrowi2++;
+	dluval2++;
+      }
+      for (; hrowi2 < hrowi2end; hrowi2 +=2,dluval2 +=2) {
+	int irow0 = hrowi2[0];
+	int irow1 = hrowi2[1];
+	double dval0=dluval2[0];
+	double dval1=dluval2[1];
+	double d0=SHIFT_REF(dwork1, irow0);
+	double d1=SHIFT_REF(dwork1, irow1);
+	
+	d0-=dv*dval0;
+	d1-=dv*dval1;
+	SHIFT_REF(dwork1, irow0)=d0;
+	SHIFT_REF(dwork1, irow1)=d1;
+      }
+#endif
+      /* put this down here so that dv is less likely to cause a stall */
+      if (fabs(dv) >= tolerance) {
+	int iput=hpivro[ipiv];
+	*dworko++=dv;
+	*mptX++=iput-1;
+      }
+    }
+    
+    dv = dwork1[next_ipiv];
+    ipiv=next_ipiv;
+  } /* endwhile */
+  
+  *mptp = mptX;
+  *ip = ipiv;
+}
+static void c_ekkftjup_aux3_pack(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+				  double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dworko,
+			       const int * COIN_RESTRICT back,
+			       const int * COIN_RESTRICT hpivro,
+			       int *ipivp, int loop_limit,
+			       int **mptXp)
+  
+{
+  double tolerance = fact->zeroTolerance;
+  int ipiv = *ipivp;
+  if (ipiv!=loop_limit) {
+    int *mptX = *mptXp;
+    
+    double dv = dwork1[ipiv];
+    do {
+      int next_ipiv = back[ipiv];
+      double next_dv=dwork1[next_ipiv];
+      
+      dwork1[ipiv]=0.0;
+      
+      if (fabs(dv)>=tolerance) {
+	int iput=hpivro[ipiv];
+	*dworko++=dv;
+	*mptX++=iput-1;
+      }
+      
+      ipiv = next_ipiv;
+      dv = next_dv;
+    } while (ipiv!=loop_limit);
+    
+    *mptXp = mptX;
+    
+    *ipivp = ipiv;
+  }
+}
+
+/* do not use return value if mpt==0 */
+/* using dual, this is usually called via c_ekkftrn_ft, from c_ekksdul
+ * (so mpt is non-null).
+ * it is generally called every iteration, but sometimes several iterations
+ * are skipped (null moves?).
+ *
+ * generally, back[i] == i-1 (initialized in c_ekkshfv towards the end).
+ */
+static int c_ekkftjup_pack(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact,
+		  double * COIN_RESTRICT dwork1, int last,
+		  double * COIN_RESTRICT dworko , int * COIN_RESTRICT mpt)
+{
+  const double * COIN_RESTRICT dluval	= fact->xeeadr;
+  const int * COIN_RESTRICT hrowi	= fact->xeradr;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  const int * COIN_RESTRICT hpivro	= fact->krpadr;
+  double tolerance = fact->zeroTolerance;
+  int ndenuc=fact->ndenuc;
+  const int first_dense=fact->first_dense;
+  const int last_dense=fact->last_dense;
+  int * mptX = mpt; int * mptY = mpt;
+  
+  const int nrow		= fact->nrow;
+  const int * COIN_RESTRICT back=fact->back;
+  int ipiv=back[nrow+1];
+  assert (mpt);
+  
+  if (last_dense>first_dense&&mcstrt[ipiv]>=mcstrt[last_dense]) {
+    c_ekkftjup_scan_aux_pack(fact,
+			   dwork1, dworko, last_dense, &ipiv,
+			   &mptX );
+    /* adjust */
+    dworko+= (mptX-mpt);
+    mpt=mptX;
+    {
+      int j;
+      int n=0;
+      const int firstDense	= nrow- ndenuc+1;
+      double *densew = &dwork1[firstDense];
+      int offset;
+      
+      /* check first dense to see where in triangle it is */
+      int last=first_dense;
+      const int k1=mcstrt[last];
+      const int k2=k1+hrowi[k1];
+      
+      for (j=k2; j>k1; j--) {
+        int irow = UNSHIFT_INDEX(hrowi[j]);
+        if (irow<firstDense) {
+          break;
+        } else {
+#ifdef DEBUG
+          if (irow!=last-1) {
+            abort();
+          }
+#endif
+          last=irow;
+          n++;
+        }
+      }
+      offset=n-first_dense;
+      int ipiv2=ipiv;
+      /* loop counter i may be modified by this call */
+      c_ekkftju_dense(&dluval[1],&hrowi[1],mcstrt,back,
+		    dwork1, &ipiv2, first_dense,offset,densew);
+      
+      c_ekkftjup_aux3_pack(fact,dwork1, dworko, back, hpivro, &ipiv, ipiv2,&mptX);
+      /* adjust dworko */
+      dworko += (mptX-mpt);
+      mpt=mptX;
+    }
+  }
+  
+  c_ekkftjup_scan_aux_pack(fact,
+			 dwork1, dworko, last, &ipiv,
+			 &mptX );
+  /* adjust dworko */
+  dworko += (mptX-mpt);
+  while (ipiv!=0) {
+    double dv = dwork1[ipiv];
+    int next_ipiv = back[ipiv];
+    
+    dwork1[ipiv]=0.0;
+    
+    if (fabs(dv)>=tolerance) {
+      int iput=hpivro[ipiv];
+      *dworko++=-dv;
+      *mptX++=iput-1;
+    }
+    
+    ipiv = next_ipiv;
+  }
+  
+  return static_cast<int>(mptX-mptY);
+}
+static int c_ekkftju_sparse_a(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+			    int * COIN_RESTRICT mpt,
+			    int nincol,int * COIN_RESTRICT spare)
+{
+  const int * COIN_RESTRICT hrowi	= fact->xeradr+1;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  const int nrow		= fact->nrow;
+  char * COIN_RESTRICT nonzero=fact->nonzero;
+  
+  int k,nStack,kx,nel;
+  int nList=0;
+  int iPivot;
+  /*int kkk=nincol;*/
+  int * COIN_RESTRICT list = spare;
+  int * COIN_RESTRICT stack = spare+nrow;
+  int * COIN_RESTRICT next = stack+nrow;
+  for (k=0;k<nincol;k++) {
+    nStack=1;
+    iPivot=mpt[k];
+    stack[0]=iPivot;
+    next[0]=0;
+    while (nStack) {
+      int kPivot,j;
+      /* take off stack */
+      kPivot=stack[--nStack];
+      if (nonzero[kPivot]!=1) {
+	kx = mcstrt[kPivot];
+	nel = hrowi[kx-1];
+	j=next[nStack];
+	if (j==nel) {
+	  /* finished so mark */
+	  list[nList++]=kPivot;
+	  nonzero[kPivot]=1;
+	} else {
+	  kPivot=hrowi[kx+j];
+	  /* put back on stack */
+	  next[nStack++] ++;
+	  if (!nonzero[kPivot]) {
+	    /* and new one */
+	    stack[nStack]=kPivot;
+	    nonzero[kPivot]=2;
+	    next[nStack++]=0;
+	    /*kkk++;*/
+	  }
+	}
+      }
+    }
+  }
+  return (nList);
+}
+static int c_ekkftju_sparse_b(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact,
+			    double * COIN_RESTRICT dwork1, 
+			    double * COIN_RESTRICT dworko , int * COIN_RESTRICT mpt,
+			    int nList,int * COIN_RESTRICT spare)
+{
+  
+  const double * COIN_RESTRICT dluval	= fact->xeeadr+1;
+  const int * COIN_RESTRICT hrowi	= fact->xeradr+1;
+  const int * COIN_RESTRICT mcstrt	= fact->xcsadr;
+  const int * COIN_RESTRICT hpivro	= fact->krpadr;
+  double tolerance = fact->zeroTolerance;
+  char * COIN_RESTRICT nonzero=fact->nonzero;
+  int i,k,kx,nel;
+  int iPivot;
+  /*int kkk=nincol;*/
+  int * COIN_RESTRICT list = spare;
+  i=nList-1;
+  nList=0;
+  for (;i>=0;i--) {
+    double dpiv;
+    double dv;
+    iPivot = list[i];
+    /*printf("pivot %d %d\n",i,iPivot);*/
+    dv=dwork1[iPivot];
+    kx = mcstrt[iPivot];
+    nel = hrowi[kx-1];
+    dwork1[iPivot]=0.0;
+    dpiv = dluval[kx-1];
+    dv*=dpiv;
+    nonzero[iPivot]=0;
+    iPivot=hpivro[iPivot];
+    if (fabs(dv)>=tolerance) {
+      *dworko++=dv;
+      mpt[nList++]=iPivot-1;
+      for (k = kx; k < kx+nel; k++) {
+        double dval;
+        double dd;
+        int irow = hrowi[k];
+        dval=dluval[k];
+        dd=dwork1[irow];
+        dd-=dv*dval;
+        dwork1[irow]=dd;
+      }
+    }
+  }
+  return (nList);
+}
+/* dwork1 = (B^-1)dwork1;
+ * I think dpermu[1..nrow+1] is zeroed on exit (?)
+ * I don't think it is expected to have any particular value on entry (?)
+ */
+int c_ekkftrn(COIN_REGISTER const EKKfactinfo * COIN_RESTRICT2 fact, 
+	    double * COIN_RESTRICT dwork1, 
+	    double * COIN_RESTRICT dpermu, int * COIN_RESTRICT mpt,int numberNonZero)
+{
+  const int * COIN_RESTRICT mpermu = fact->mpermu;
+  int lastNonZero;
+  int firstNonZero = c_ekkshfpi_list2(mpermu+1, dwork1+1, dpermu, mpt,
+				      numberNonZero,&lastNonZero);
+  if (fact->nnentl&&lastNonZero>=fact->firstLRow) {
+    /* dpermu = (L^-1)dpermu */
+    c_ekkftj4p(fact, dpermu, firstNonZero);
+  }
+  
+  
+  int lastSlack;
+  
+  /* dpermu = (R^-1) dpermu */
+  c_ekkftjl(fact, dpermu);
+  
+  assert (fact->numberSlacks!=0||!fact->lastSlack);
+  lastSlack=fact->lastSlack;
+  
+  /* dwork1 = (U^-1)dpermu; dpermu zeroed (?) */
+  return c_ekkftjup(fact, 
+		  dpermu, lastSlack, dwork1, mpt);
+  
+} /* c_ekkftrn */
+
+int c_ekkftrn_ft(COIN_REGISTER EKKfactinfo * COIN_RESTRICT2 fact,
+	       double * COIN_RESTRICT dwork1_ft, int * COIN_RESTRICT mpt_ft, int *nincolp_ft)
+{
+  double * COIN_RESTRICT dpermu_ft = fact->kadrpm;
+  int * COIN_RESTRICT spare = reinterpret_cast<int *>(fact->kp1adr);
+  int nincol	= *nincolp_ft;
+  
+  int nuspik;
+  double * COIN_RESTRICT dluvalPut = fact->xeeadr+fact->nnentu+1;
+  int * COIN_RESTRICT hrowiPut	= fact->xeradr+fact->nnentu+1;
+  
+  const int nrow	= fact->nrow;
+  /* mpermu contains the permutation */
+  const int * COIN_RESTRICT mpermu=fact->mpermu;
+  
+  int lastSlack;
+  
+  int kdnspt = fact->nnetas - fact->nnentl;
+  bool isRoom = (fact->nnentu + (nrow << 1) < (kdnspt - 2) 
+		 + fact->R_etas_start[fact->nR_etas + 1]);
+  
+  /* say F-T will be sorted */
+  fact->sortedEta=1;
+  
+  assert (fact->numberSlacks!=0||!fact->lastSlack);
+  lastSlack=fact->lastSlack;
+#ifdef CLP_REUSE_ETAS
+  bool skipStuff = (fact->reintro>=0);
+  
+  int save_nR_etas=fact->nR_etas;
+  int * save_hpivcoR=fact->hpivcoR;
+  int * save_R_etas_start=fact->R_etas_start;
+  if (skipStuff) {
+    // just move
+    int * putSeq = fact->xrsadr+2*fact->nrowmx+2;
+    int * position = putSeq+fact->maxinv;
+    int * putStart = position+fact->maxinv;
+    memset(dwork1_ft,0,nincol*sizeof(double));
+    int iPiv=fact->reintro;
+    int start=putStart[iPiv]&0x7fffffff;
+    int end=putStart[iPiv+1]&0x7fffffff;
+    double * COIN_RESTRICT dluval	= fact->xeeadr;
+    int * COIN_RESTRICT hrowi	= fact->xeradr;
+    double dValue;
+    if (fact->reintro<fact->nrow) {
+      iPiv++;
+      dValue=1.0/dluval[start++];
+    } else {
+      iPiv=hrowi[--end];
+      dValue=dluval[end];
+      start++;
+      int ndoSkip=0;
+      for (int i=fact->nrow;i<fact->reintro;i++) {
+	if ((putStart[i]&0x80000000)==0)
+	ndoSkip++;
+      }
+      fact->nR_etas-=ndoSkip;
+      fact->hpivcoR+=ndoSkip;
+      fact->R_etas_start+=ndoSkip;
+    }
+    dpermu_ft[iPiv]=dValue;
+    if (fact->if_sparse_update>0 &&  DENSE_THRESHOLD<nrow) {
+      nincol=0;
+      if (dValue)
+	mpt_ft[nincol++]=iPiv;
+      for (int i=start;i<end;i++) {
+	int iRow=hrowi[i];
+	dpermu_ft[iRow]=dluval[i];
+	mpt_ft[nincol++]=iRow;
+      }
+    } else {
+      for (int i=start;i<end;i++) {
+	int iRow=hrowi[i];
+	dpermu_ft[iRow]=dluval[i];
+      }
+    }
+  }
+#else
+  bool skipStuff = false;
+#endif
+  if (fact->if_sparse_update>0 &&  DENSE_THRESHOLD<nrow) {
+    if (!skipStuff) {
+      /* iterating so c_ekkgtcl will have list */
+      /* in order for this to make sense, nonzero[1..nrow] must already be zeroed */
+      c_ekkshfpi_list3(mpermu+1, dwork1_ft, dpermu_ft, mpt_ft, nincol);
+      
+      /* it may be the case that the basis was entirely upper-triangular */
+      if (fact->nnentl) {
+	nincol = 
+	  c_ekkftj4_sparse(fact,
+			 dpermu_ft,  mpt_ft,
+			 nincol,spare);
+      }
+    }
+    /*       DO ROW ETAS IN L */
+    if (isRoom) {
+      ++fact->nnentu;
+      nincol=
+	c_ekkftjl_sparse3(fact,
+			  dpermu_ft, 
+			  mpt_ft, hrowiPut,
+			  dluvalPut,nincol);
+      nuspik = nincol;
+      /* temporary */
+      /* say not sorted */
+      fact->sortedEta=0;
+    } else {
+      /* no room */
+      nuspik=-3;
+      nincol=
+	c_ekkftjl_sparse2(fact,
+			  dpermu_ft, 
+			  mpt_ft,  nincol);
+    }
+    /*         DO U */
+    if (DENSE_THRESHOLD>nrow-fact->numberSlacks) {
+      nincol = c_ekkftjup_pack(fact, 
+			       dpermu_ft,lastSlack, dwork1_ft, 
+			       mpt_ft);
+    } else {
+      nincol= c_ekkftju_sparse_a(fact,
+				 mpt_ft,
+				 nincol, spare);
+      nincol = c_ekkftju_sparse_b(fact,
+				  dpermu_ft, 
+				  dwork1_ft , mpt_ft,
+				  nincol, spare);
+    }
+  } else {
+    if (!skipStuff) {
+      int lastNonZero;
+      int firstNonZero = c_ekkshfpi_list(mpermu+1, dwork1_ft, dpermu_ft, 
+				       mpt_ft, nincol,&lastNonZero);
+      if (fact->nnentl&&lastNonZero>=fact->firstLRow) {
+	/* dpermu_ft = (L^-1)dpermu_ft */
+	c_ekkftj4p(fact, dpermu_ft, firstNonZero);
+      }
+    }
+    
+    /* dpermu_ft = (R^-1) dpermu_ft */
+    c_ekkftjl(fact, dpermu_ft);
+    
+    if (isRoom) {
+      
+      /*        fake start to allow room for pivot */
+      /* dluval[fact->nnentu...] = non-zeros of dpermu_ft;
+       * hrowi[fact->nnentu..] = indices of these non-zeros;
+       * near-zeros in dluval flattened
+       */
+      ++fact->nnentu;
+      nincol= c_ekkscmv(fact,fact->nrow, dpermu_ft, hrowiPut,
+		      dluvalPut);
+      
+      /*
+       * note that this is not the value of nincol determined by c_ekkftjup. 
+       * For Forrest-Tomlin update we want vector before U
+       * this vector will replace one in U
+       */
+      nuspik = nincol;
+    } else {
+      /* no room */
+      nuspik = -3;
+    }
+    
+    /* dwork1_ft = (U^-1)dpermu_ft; dpermu_ft zeroed (?) */
+    nincol = c_ekkftjup_pack(fact, 
+			   dpermu_ft, lastSlack, dwork1_ft, mpt_ft);
+  }
+#ifdef CLP_REUSE_ETAS
+  fact->nR_etas=save_nR_etas;
+  fact->hpivcoR=save_hpivcoR;
+  fact->R_etas_start=save_R_etas_start;
+#endif
+  
+  *nincolp_ft = nincol;
+  return (nuspik);
+} /* c_ekkftrn */
+void c_ekkftrn2(COIN_REGISTER EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1,
+	     double * COIN_RESTRICT dpermu1,int * COIN_RESTRICT mpt1, int *nincolp,
+	     double * COIN_RESTRICT dwork1_ft, int * COIN_RESTRICT mpt_ft, int *nincolp_ft)
+{
+  double * COIN_RESTRICT dluvalPut = fact->xeeadr+fact->nnentu+1;
+  int * COIN_RESTRICT hrowiPut	= fact->xeradr+fact->nnentu+1;
+  
+  const int nrow	= fact->nrow;
+  /* mpermu contains the permutation */
+  const int * COIN_RESTRICT mpermu=fact->mpermu;
+  
+  int lastSlack;
+  assert (fact->numberSlacks!=0||!fact->lastSlack);
+  lastSlack=fact->lastSlack;
+  
+  int nincol	= *nincolp_ft;
+
+  /* using dwork1 instead double *dpermu_ft = fact->kadrpm; */
+  int * spare = reinterpret_cast<int *>(fact->kp1adr);
+  
+  int kdnspt = fact->nnetas - fact->nnentl;
+  bool isRoom = (fact->nnentu + (nrow << 1) < (kdnspt - 2) 
+		 + fact->R_etas_start[fact->nR_etas + 1]);
+  /* say F-T will be sorted */
+  fact->sortedEta=1;
+  int lastNonZero;
+  int firstNonZero = c_ekkshfpi_list2(mpermu+1, dwork1+1, dpermu1, 
+				      mpt1, *nincolp,&lastNonZero);
+  if (fact->nnentl&&lastNonZero>=fact->firstLRow) {
+    /* dpermu1 = (L^-1)dpermu1 */
+    c_ekkftj4p(fact, dpermu1, firstNonZero);
+  }
+
+#ifdef CLP_REUSE_ETAS
+  bool skipStuff = (fact->reintro>=0);
+  int save_nR_etas=fact->nR_etas;
+  int * save_hpivcoR=fact->hpivcoR;
+  int * save_R_etas_start=fact->R_etas_start;
+  if (skipStuff) {
+    // just move
+    int * putSeq = fact->xrsadr+2*fact->nrowmx+2;
+    int * position = putSeq+fact->maxinv;
+    int * putStart = position+fact->maxinv;
+    memset(dwork1_ft,0,nincol*sizeof(double));
+    int iPiv=fact->reintro;
+    int start=putStart[iPiv]&0x7fffffff;
+    int end=putStart[iPiv+1]&0x7fffffff;
+    double * COIN_RESTRICT dluval	= fact->xeeadr;
+    int * COIN_RESTRICT hrowi	= fact->xeradr;
+    double dValue;
+    if (fact->reintro<fact->nrow) {
+      iPiv++;
+      dValue=1.0/dluval[start++];
+    } else {
+      iPiv=hrowi[--end];
+      dValue=dluval[end];
+      start++;
+      int ndoSkip=0;
+      for (int i=fact->nrow;i<fact->reintro;i++) {
+	if ((putStart[i]&0x80000000)==0)
+	ndoSkip++;
+      }
+      fact->nR_etas-=ndoSkip;
+      fact->hpivcoR+=ndoSkip;
+      fact->R_etas_start+=ndoSkip;
+    }
+    dwork1[iPiv]=dValue;
+    if (fact->if_sparse_update>0 &&  DENSE_THRESHOLD<nrow) {
+      nincol=0;
+      if (dValue)
+	mpt_ft[nincol++]=iPiv;
+      for (int i=start;i<end;i++) {
+	int iRow=hrowi[i];
+	dwork1[iRow]=dluval[i];
+	mpt_ft[nincol++]=iRow;
+      }
+    } else {
+      for (int i=start;i<end;i++) {
+	int iRow=hrowi[i];
+	dwork1[iRow]=dluval[i];
+      }
+    }
+  }
+#else
+  bool skipStuff = false;
+#endif
+  if (fact->if_sparse_update>0 &&  DENSE_THRESHOLD<nrow) {
+    if (!skipStuff) {
+      /* iterating so c_ekkgtcl will have list */
+      /* in order for this to make sense, nonzero[1..nrow] must already be zeroed */
+      c_ekkshfpi_list3(mpermu+1, dwork1_ft, dwork1, mpt_ft, nincol);
+      
+      /* it may be the case that the basis was entirely upper-triangular */
+      if (fact->nnentl) {
+	nincol = 
+	  c_ekkftj4_sparse(fact,
+			   dwork1, mpt_ft,
+			   nincol,spare);
+      }
+    }
+    /*       DO ROW ETAS IN L */
+    if (isRoom) {
+      ++fact->nnentu;
+      nincol=
+	c_ekkftjl_sparse3(fact,
+			  dwork1, 
+			  mpt_ft, hrowiPut,
+			  dluvalPut,
+			  nincol);
+      fact->nuspike = nincol;
+      /* say not sorted */
+      fact->sortedEta=0;
+    } else {
+      /* no room */
+      fact->nuspike=-3;
+      nincol=
+	c_ekkftjl_sparse2(fact,
+			  dwork1, 
+			  mpt_ft, nincol);
+    }
+  } else {
+    if (!skipStuff) {
+      int lastNonZero;
+      int firstNonZero = c_ekkshfpi_list(mpermu+1, dwork1_ft, dwork1, 
+				       mpt_ft, nincol,&lastNonZero);
+      if (fact->nnentl&&lastNonZero>=fact->firstLRow) {
+	/* dpermu_ft = (L^-1)dpermu_ft */
+	c_ekkftj4p(fact, dwork1, firstNonZero);
+      }
+    }
+    c_ekkftjl(fact, dwork1);
+    
+    if (isRoom) {
+      
+      /*        fake start to allow room for pivot */
+      /* dluval[fact->nnentu...] = non-zeros of dpermu_ft;
+       * hrowi[fact->nnentu..] = indices of these non-zeros;
+       * near-zeros in dluval flattened
+       */
+      ++fact->nnentu;
+      nincol= c_ekkscmv(fact,fact->nrow, dwork1, 
+		      hrowiPut,
+		      dluvalPut);
+      
+      /*
+       * note that this is not the value of nincol determined by c_ekkftjup. 
+       * For Forrest-Tomlin update we want vector before U
+       * this vector will replace one in U
+       */
+      fact->nuspike = nincol;
+    } else {
+      /* no room */
+      fact->nuspike = -3;
+    }
+  }
+#ifdef CLP_REUSE_ETAS
+  fact->nR_etas=save_nR_etas;
+  fact->hpivcoR=save_hpivcoR;
+  fact->R_etas_start=save_R_etas_start;
+#endif
+  
+  
+  /* dpermu1 = (R^-1) dpermu1 */
+  c_ekkftjl(fact, dpermu1);
+  
+  /*         DO U */
+  if (fact->if_sparse_update<=0 ||  DENSE_THRESHOLD>nrow-fact->numberSlacks) {
+    nincol = c_ekkftjup_pack(fact,
+			   dwork1,lastSlack, dwork1_ft, mpt_ft);
+  } else {
+    nincol= c_ekkftju_sparse_a(fact,
+			     mpt_ft,
+			     nincol, spare);
+    nincol = c_ekkftju_sparse_b(fact,
+			      dwork1, 
+			      dwork1_ft , mpt_ft,
+			      nincol, spare);
+  }
+  *nincolp_ft = nincol;
+  /* dwork1 = (U^-1)dpermu1; dpermu1 zeroed (?) */
+  *nincolp = c_ekkftjup(fact,
+		      dpermu1,lastSlack, dwork1, mpt1);
+
+}
+
+
diff --git a/cbits/coin/CoinOslFactorization3.cpp b/cbits/coin/CoinOslFactorization3.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinOslFactorization3.cpp
@@ -0,0 +1,3121 @@
+/* $Id: CoinOslFactorization3.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+/*
+  Copyright (C) 1987, 2009, International Business Machines
+  Corporation and others.  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+#include "CoinOslFactorization.hpp"
+#include "CoinOslC.h"
+#include "CoinFinite.hpp"
+#define GO_DENSE 70
+#define GO_DENSE_RATIO 1.8
+int c_ekkclco(const EKKfactinfo *fact,int *hcoli,
+	    int *mrstrt, int *hinrow, int xnewro);
+
+void c_ekkclcp(const int *hcol, const double *dels, const int * mrstrt,
+	     int *hrow, double *dels2, int *mcstrt,
+	     int *hincol, int itype, int nnrow, int nncol,
+	     int ninbas);
+
+int c_ekkcmfc(EKKfactinfo *fact,
+	    EKKHlink *rlink, EKKHlink *clink,
+	    EKKHlink *mwork, void *maction_void,
+	    int nnetas,
+	    int *nsingp, int *xrejctp,
+	    int *xnewrop, int xnewco, 
+	    int *ncompactionsp);
+
+int c_ekkcmfy(EKKfactinfo *fact,
+	    EKKHlink *rlink, EKKHlink *clink,
+	    EKKHlink *mwork, void *maction_void,
+	    int nnetas,
+	    int *nsingp, int *xrejctp,
+	    int *xnewrop, int xnewco, 
+	    int *ncompactionsp);
+
+int c_ekkcmfd(EKKfactinfo *fact,
+	    int *mcol, 
+	    EKKHlink *rlink, EKKHlink *clink,
+	    int *maction,
+	    int nnetas,
+	    int *nnentlp, int *nnentup,
+	    int *nsingp);
+int c_ekkford(const EKKfactinfo *fact,const int *hinrow, const int *hincol,
+	    int *hpivro, int *hpivco,
+	    EKKHlink *rlink, EKKHlink *clink);
+void c_ekkrowq(int *hrow, int *hcol, double *dels, 
+	     int *mrstrt,
+	     const int *hinrow, int nnrow, int ninbas);
+int c_ekkrwco(const EKKfactinfo *fact,double *dluval, int *hcoli, int *
+	    mrstrt, int *hinrow, int xnewro);
+
+int c_ekkrwcs(const EKKfactinfo *fact,double *dluval, int *hcoli, int *mrstrt,
+	    const int *hinrow, const EKKHlink *mwork,
+	    int nfirst);
+
+void c_ekkrwct(const EKKfactinfo *fact,double *dluval, int *hcoli, int *mrstrt,
+	     const int *hinrow, const EKKHlink *mwork,
+	     const EKKHlink *rlink,
+	     const short *msort, double *dsort,
+	     int nlast, int xnewro);
+
+int c_ekkshff(EKKfactinfo *fact,
+	    EKKHlink *clink, EKKHlink *rlink, 
+	    int xnewro);
+
+void c_ekkshfv(EKKfactinfo *fact, EKKHlink *rlink, EKKHlink *clink,
+	     int xnewro);
+int c_ekktria(EKKfactinfo *fact,
+	      EKKHlink * rlink,
+	      EKKHlink * clink,
+	    int *nsingp, 
+	    int *xnewcop, int *xnewrop,
+	    int *nlrowtp,
+	    const int ninbas);
+#if 0
+static void c_ekkafpv(int *hentry, int *hcoli,
+	     double *dluval, int *mrstrt,
+	     int *hinrow, int nentry)
+{
+  int j;
+  int nel, krs;
+  int koff;
+  int irow;
+  int ientry;
+  int * index;
+  
+  for (ientry = 0; ientry < nentry; ++ientry) {
+#ifdef INTEL
+    int * els_long,maxaij_long;
+#endif
+    double * els;
+    irow = UNSHIFT_INDEX(hentry[ientry]);
+    nel = hinrow[irow];
+    krs = mrstrt[irow];
+    index=&hcoli[krs];
+    els=&dluval[krs];
+#ifdef INTEL
+    els_long=reinterpret_cast<int *> (els);
+    maxaij_long=0;
+#else
+    double maxaij = 0.f;
+#endif
+    koff = 0;
+    j=0;
+    if ((nel&1)!=0) {
+#ifdef INTEL
+      maxaij_long = els_long[1] & 0x7fffffff;
+#else
+      maxaij=fabs(els[0]);
+#endif
+      j=1;
+    }
+    
+    while (j<nel) {
+#ifdef INTEL
+      UNROLL_LOOP_BODY2({
+	  int d_long = els_long[1+(j<<1)] & 0x7fffffff;
+	  if (maxaij_long < d_long) {
+	    maxaij_long = d_long;
+	    koff=j;
+	  }
+	  j++;
+	});
+#else
+      UNROLL_LOOP_BODY2({
+	  double d = fabs(els[j]);
+	  if (maxaij < d) {
+	    maxaij = d;
+	    koff=j;
+	  }
+	  j++;
+	});
+#endif
+    }
+    
+    SWAP(int, index[koff], index[0]);
+    SWAP(double, els[koff], els[0]);
+  }
+} /* c_ekkafpv */
+#endif
+
+/*     Uwe H. Suhl, March 1987 */
+/*     This routine processes col singletons during the LU-factorization. */
+/*     Return codes (checked version 1.11): */
+/*	0: ok */
+/*      6: pivot element too small */
+/*     -43: system error at label 420 (ipivot not found) */
+/*
+ * This routine processes singleton columns during factorization of the
+ * nucleus.  It is very similar to the first part of c_ekktria,
+ * but is more complex, because we now have to maintain the length
+ * lists.
+ * The differences are:
+ * (1) here we use the length list for length 1 rather than a queue.
+ * This routine is only called if it is known that there is a singleton
+ * column.
+ *
+ * (2) here we maintain hrowi by moving the last entry into the pivot
+ * column entry; that means we don't have to search for the pivot row
+ * entry like we do in c_ekktria.
+ *
+ * (3) here the hlink data structure is in use for the length lists,
+ * so we maintain it as we shorten rows and removing columns altogether.
+ *
+ */
+int c_ekkcsin(EKKfactinfo *fact,
+	      EKKHlink *rlink, EKKHlink *clink,
+	      
+	      int *nsingp)
+{
+#if 1
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  //double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  const int nrow	= fact->nrow;
+  const double drtpiv	= fact->drtpiv;
+  
+  
+  int j, k, kc, kce, kcs, nzj;
+  double pivot;
+  int kipis, kipie;
+  int jpivot;
+#ifndef NDEBUG
+  int kpivot=-1;
+#else
+  int kpivot=-1;
+#endif
+  
+  bool small_pivot = false;
+  
+  
+  /* next singleton column.
+   * Note that when the pivot column itself was removed from the
+   * list, the column in the list after it (if any) moves to the
+   * head of the list.
+   * Also, if any column from the pivot row was reduced to length 1,
+   * then it will have been added to the list and now be in front.
+   */
+  for (jpivot = hpivco[1]; jpivot > 0; jpivot = hpivco[1]) {
+    const int ipivot = hrowi[mcstrt[jpivot]]; /* (2) */
+    assert(ipivot);
+    /* The pivot row is being eliminated (3) */
+    C_EKK_REMOVE_LINK(hpivro, hinrow, rlink, ipivot);
+    
+    /* Loop over nonzeros in pivot row: */
+    kipis = mrstrt[ipivot];
+    kipie = kipis + hinrow[ipivot] - 1;
+    for (k = kipis; k <= kipie; ++k) {
+      j = hcoli[k];
+      
+      /*
+       * We're eliminating column jpivot,
+       * so we're eliminating the row it occurs in,
+       * so every column in this row is becoming one shorter.
+       *
+       * I don't know why we don't do the same for rejected columns.
+       *
+       * if xrejct is false, then no column has ever been rejected
+       * and this test wouldn't have to be made.
+       * However, that means this whole loop would have to be copied.
+       */
+      if (! (clink[j].pre > nrow)) {
+	C_EKK_REMOVE_LINK(hpivco, hincol, clink, j); /* (3) */
+      }
+      --hincol[j];
+      
+      kcs = mcstrt[j];
+      kce = kcs + hincol[j];
+      for (kc = kcs; kc <= kce; ++kc) {
+	if (ipivot == hrowi[kc]) {
+	  break;
+	}
+      }
+      /* ASSERT !(kc>kce) */
+      
+      /* (2) */
+      hrowi[kc] = hrowi[kce];
+      hrowi[kce] = 0;
+      
+      if (j == jpivot) {
+	/* remember the slot corresponding to the pivot column */
+	kpivot = k;
+      }
+      else {
+	/*
+	 * We just reduced the length of the column.
+	 * If we haven't eliminated all of its elements completely,
+	 * then we have to put it back in its new length list.
+	 *
+	 * If the column was rejected, we only put it back in a length
+	 * list when it has been reduced to a singleton column,
+	 * because it would just be rejected again.
+	 */
+	nzj = hincol[j];
+	if (! (nzj <= 0) &&
+	    ! (clink[j].pre > nrow && nzj != 1)) {
+	  C_EKK_ADD_LINK(hpivco, nzj, clink, j); /* (3) */
+	}
+      }
+    }
+    assert (kpivot>0);
+    
+    /* store pivot sequence number */
+    ++fact->npivots;
+    rlink[ipivot].pre = -fact->npivots;
+    clink[jpivot].pre = -fact->npivots;
+    
+    /* compute how much room we'll need later */
+    fact->nuspike += hinrow[ipivot];
+    
+    /* check the pivot */
+    pivot = dluval[kpivot];
+    if (fabs(pivot) < drtpiv) {
+      /* pivot element too small */
+      small_pivot = true;
+      rlink[ipivot].pre = -nrow - 1;
+      clink[jpivot].pre = -nrow - 1;
+      ++(*nsingp);
+    }
+    
+    /* swap the pivoted column entry with the first entry in the row */
+    dluval[kpivot] = dluval[kipis];
+    dluval[kipis] = pivot;
+    hcoli[kpivot] = hcoli[kipis];
+    hcoli[kipis] = jpivot;
+  }
+  
+  return (small_pivot);
+} /* c_ekkcsin */
+
+
+/*     Uwe H. Suhl, March 1987 */
+/*     This routine processes row singletons during the computation of */
+/*     an LU-decomposition for the nucleus. */
+/*     Return codes (checked version 1.16): */
+/*      -5: not enough space in row file */
+/*      -6: not enough space in column file */
+/*      7: pivot element too small */
+/*     -52: system error at label 220 (ipivot not found) */
+/*     -53: system error at label 400 (jpivot not found) */
+int c_ekkrsin(EKKfactinfo *fact,
+	    EKKHlink *rlink, EKKHlink *clink,
+	    EKKHlink *mwork, int nfirst,
+	    int *nsingp, 
+	    int *xnewcop, int *xnewrop,
+	    int *nnentup, 
+	    int *kmxetap, int *ncompactionsp,
+	    int *nnentlp)
+  
+{
+#if 1
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  //double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  const int nrow	= fact->nrow;
+  const double drtpiv	= fact->drtpiv;
+  
+  int xnewro	= *xnewrop;
+  int xnewco	= *xnewcop;
+  int kmxeta	= *kmxetap;
+  int nnentu	= *nnentup;
+  int ncompactions	= *ncompactionsp;
+  int nnentl	= *nnentlp;
+  
+  int i, j, k, kc, kr, npr, nzi;
+  double pivot;
+  int kjpis, kjpie, knprs, knpre;
+  double elemnt, maxaij;
+  int ipivot, epivco, lstart;
+#ifndef NDEBUG
+  int kpivot=-1;
+#else
+  int kpivot=-1;
+#endif
+  int irtcod = 0;
+  const int nnetas	= fact->nnetas;
+  
+  lstart = nnetas - nnentl + 1;
+  
+  
+  for (ipivot = hpivro[1]; ipivot > 0; ipivot = hpivro[1]) {
+    const int jpivot = hcoli[mrstrt[ipivot]];
+    
+    kjpis = mcstrt[jpivot];
+    kjpie = kjpis + hincol[jpivot] ;
+    for (k = kjpis; k < kjpie; ++k) {
+      i = hrowi[k];
+      
+      /*
+       * We're eliminating row ipivot,
+       * so we're eliminating the column it occurs in,
+       * so every row in this column is becoming one shorter.
+       *
+       * No exception is made for rejected rows.
+       */
+      C_EKK_REMOVE_LINK(hpivro, hinrow, rlink, i);
+    }
+    
+    /* The pivot column is being eliminated */
+    /* I don't know why there is an exception for rejected columns */
+    if (! (clink[jpivot].pre > nrow)) {
+      C_EKK_REMOVE_LINK(hpivco, hincol, clink, jpivot);
+    }
+    
+    epivco = hincol[jpivot] - 1;
+    kjpie = kjpis + epivco;
+    for (kc = kjpis; kc <= kjpie; ++kc) {
+      if (ipivot == hrowi[kc]) {
+	break;
+      }
+    }
+    /* ASSERT !(kc>kjpie) */
+    
+    /* move the last column entry into this deleted one to keep */
+    /* the entries compact */
+    hrowi[kc] = hrowi[kjpie];
+    
+    hrowi[kjpie] = 0;
+    
+    /* store pivot sequence number */
+    ++fact->npivots;
+    rlink[ipivot].pre = -fact->npivots;
+    clink[jpivot].pre = -fact->npivots;
+    
+    /* Check if row or column files have to be compressed */
+    if (! (xnewro + epivco < lstart)) {
+      if (! (nnentu + epivco < lstart)) {
+	return (-5);
+      }
+      {
+	int iput = c_ekkrwcs(fact,dluval, hcoli, mrstrt, hinrow, mwork, nfirst);
+	kmxeta += xnewro - iput ;
+	xnewro = iput - 1;
+	++ncompactions;
+      }
+    }
+    if (! (xnewco + epivco < lstart)) {
+      if (! (nnentu + epivco < lstart)) {
+	return (-5);
+      }
+      xnewco = c_ekkclco(fact,hrowi, mcstrt, hincol, xnewco);
+      ++ncompactions;
+    }
+    
+    /* This column has no more entries in it */
+    hincol[jpivot] = 0;
+    
+    /* Perform numerical part of elimination. */
+    pivot = dluval[mrstrt[ipivot]];
+    if (fabs(pivot) < drtpiv) {
+      irtcod = 7;
+      rlink[ipivot].pre = -nrow - 1;
+      clink[jpivot].pre = -nrow - 1;
+      ++(*nsingp);
+    }
+    
+    /* If epivco is 0, then we can treat this like a singleton column (?)*/
+    if (! (epivco <= 0)) {
+      ++fact->xnetal;
+      mcstrt[fact->xnetal] = lstart - 1;
+      hpivco[fact->xnetal] = ipivot;
+      
+      /* Loop over nonzeros in pivot column. */
+      kjpis = mcstrt[jpivot];
+      kjpie = kjpis + epivco ;
+      nnentl+=epivco;
+      nnentu-=epivco;
+      for (kc = kjpis; kc < kjpie; ++kc) {
+	npr = hrowi[kc];
+	/* zero out the row entries as we go along */
+	hrowi[kc] = 0;
+	
+	/* each row in the column is getting shorter */
+	--hinrow[npr];
+	
+	/* find the entry in this row for the pivot column */
+	knprs = mrstrt[npr];
+	knpre = knprs + hinrow[npr];
+	for (kr = knprs; kr <= knpre; ++kr) {
+	  if (jpivot == hcoli[kr])
+	    break;
+	}
+	/* ASSERT !(kr>knpre) */
+	
+	elemnt = dluval[kr];
+	/* move the last pivot column entry into this one */
+	/* to keep entries compact */
+	dluval[kr] = dluval[knpre];
+	hcoli[kr] = hcoli[knpre];
+	
+	/*
+	 * c_ekkmltf put the largest entries in front, and 
+	 * we want to maintain that property.
+	 * There is only a problem if we just pivoted out the first
+	 * entry, and there is more than one entry in the list.
+	 */
+	if (! (kr != knprs || hinrow[npr] <= 1)) {
+	  maxaij = 0.f;
+	  for (k = knprs; k <= knpre; ++k) {
+	    if (! (fabs(dluval[k]) <= maxaij)) {
+	      maxaij = fabs(dluval[k]);
+	      kpivot = k;
+	    }
+	  }
+	  assert (kpivot>0);
+	  maxaij = dluval[kpivot];
+	  dluval[kpivot] = dluval[knprs];
+	  dluval[knprs] = maxaij;
+	  
+	  j = hcoli[kpivot];
+	  hcoli[kpivot] = hcoli[knprs];
+	  hcoli[knprs] = j;
+	}
+	
+	/* store elementary row transformation */
+	--lstart;
+	dluval[lstart] = -elemnt / pivot;
+	hrowi[lstart] = SHIFT_INDEX(npr);
+	
+	/* Only add the row back in a length list if it isn't empty */
+	nzi = hinrow[npr];
+	if (! (nzi <= 0)) {
+	  C_EKK_ADD_LINK(hpivro, nzi, rlink, npr);
+	}
+      }
+      ++fact->nuspike;
+    }
+  }
+  
+  *xnewrop = xnewro;
+  *xnewcop = xnewco;
+  *kmxetap = kmxeta;
+  *nnentup = nnentu;
+  *ncompactionsp = ncompactions;
+  *nnentlp = nnentl;
+  
+  return (irtcod);
+} /* c_ekkrsin */
+
+
+int c_ekkfpvt(const EKKfactinfo *fact,
+	    EKKHlink *rlink, EKKHlink *clink,
+	    int *nsingp, int *xrejctp,
+	    int *xipivtp, int *xjpivtp)
+{
+  double zpivlu = fact->zpivlu;
+#if 1
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  //double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  int i, j, k, ke, kk, ks, nz, nz1, kce, kcs, kre, krs;
+  double minsze;
+  int marcst, mincst, mincnt, trials, nentri;
+  int jpivot=-1;
+  bool rjectd;
+  int ipivot;
+  const int nrow	= fact->nrow;
+  int irtcod = 0;
+  
+  /* this used to be initialized in c_ekklfct */
+  const int xtrial = 1;
+  
+  trials = 0;
+  ipivot = 0;
+  mincst = COIN_INT_MAX;
+  mincnt = COIN_INT_MAX;
+  for (nz = 2; nz <= nrow; ++nz) {
+    nz1 = nz - 1;
+    if (mincnt <= nz) {
+      goto L900;
+    }
+    
+    /* Search rows for a pivot */
+    for (i = hpivro[nz]; ! (i <= 0); i = rlink[i].suc) {
+      
+      ks = mrstrt[i];
+      ke = ks + nz - 1;
+      /* Determine magnitude of minimal acceptable element */
+      minsze = fabs(dluval[ks]) * zpivlu;
+      for (k = ks; k <= ke; ++k) {
+	/* Consider a column only if it passes the stability test */
+	if (! (fabs(dluval[k]) < minsze)) {
+	  j = hcoli[k];
+	  marcst = nz1 * hincol[j];
+	  if (! (marcst >= mincst)) {
+	    mincst = marcst;
+	    mincnt = hincol[j];
+	    ipivot = i;
+	    jpivot = j;
+	    if (mincnt <= nz + 1) {
+	      goto L900;
+	    }
+	  }
+	}
+      }
+      ++trials;
+      
+      if (trials >= xtrial) {
+	goto L900;
+      }
+    }
+    
+    /* Search columns for a pivot */
+    j = hpivco[nz];
+    while (! (j <= 0)) {
+      /* XSEARD = XSEARD + 1 */
+      rjectd = false;
+      kcs = mcstrt[j];
+      kce = kcs + nz - 1;
+      for (k = kcs; k <= kce; ++k) {
+	i = hrowi[k];
+	nentri = hinrow[i];
+	marcst = nz1 * nentri;
+	if (! (marcst >= mincst)) {
+	  /* Determine magnitude of minimal acceptable element */
+	  minsze = fabs(dluval[mrstrt[i]]) * zpivlu;
+	  krs = mrstrt[i];
+	  kre = krs + nentri - 1;
+	  for (kk = krs; kk <= kre; ++kk) {
+	    if (hcoli[kk] == j)
+	      break;
+	  }
+	  /* ASSERT (kk <= kre) */
+	  
+	  /* perform stability test */
+	  if (! (fabs(dluval[kk]) < minsze)) {
+	    mincst = marcst;
+	    mincnt = nentri;
+	    ipivot = i;
+	    jpivot = j;
+	    rjectd = false;
+	    if (mincnt <= nz) {
+	      goto L900;
+	    }
+	  }
+	  else {
+	    if (ipivot == 0) {
+	      rjectd = true;
+	    }
+	  }
+	}
+      }
+      ++trials;
+      if (trials >= xtrial && ipivot > 0) {
+	goto L900;
+      }
+      if (rjectd) {
+	int jsuc = clink[j].suc;
+	++(*xrejctp);
+	C_EKK_REMOVE_LINK(hpivco, hincol, clink, j);
+	clink[j].pre = nrow + 1;
+	j = jsuc;
+      }
+      else {
+	j = clink[j].suc;
+      }
+    }
+  }
+  
+  /* FLAG REJECTED ROWS (should this be columns ?) */
+  for (j = 1; j <= nrow; ++j) {
+    if (hinrow[j] == 0) {
+      rlink[j].pre = -nrow - 1;
+      ++(*nsingp);
+    }
+  }
+  irtcod = 10;
+  
+ L900:
+  *xipivtp = ipivot;
+  *xjpivtp = jpivot;
+  return (irtcod);
+} /* c_ekkfpvt */
+void c_ekkprpv(EKKfactinfo *fact,
+	     EKKHlink *rlink, EKKHlink *clink,
+	     
+	     int xrejct,
+	     int ipivot, int jpivot)
+{
+#if 1
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  //double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  int i, k;
+  int kc;
+  double pivot;
+  int kipis = mrstrt[ipivot];
+  int kipie = kipis + hinrow[ipivot] - 1;
+  
+#ifndef NDEBUG
+  int kpivot=-1;
+#else
+  int kpivot=-1;
+#endif
+  const int nrow	= fact->nrow;
+  
+  /*     Update data structures */
+  {
+    int kjpis = mcstrt[jpivot];
+    int kjpie = kjpis + hincol[jpivot] ;
+    for (k = kjpis; k < kjpie; ++k) {
+      i = hrowi[k];
+      C_EKK_REMOVE_LINK(hpivro, hinrow, rlink, i);
+    }
+  }
+  
+  for (k = kipis; k <= kipie; ++k) {
+    int j = hcoli[k];
+    
+    if ((xrejct == 0) ||
+	! (clink[j].pre > nrow)) {
+      C_EKK_REMOVE_LINK(hpivco, hincol, clink, j);
+    }
+    
+    --hincol[j];
+    int kcs = mcstrt[j];
+    int kce = kcs + hincol[j];
+    
+    for (kc = kcs; kc < kce ; kc ++) {
+      if (hrowi[kc] == ipivot) 
+	break;
+    }
+    assert (kc<kce||hrowi[kce]==ipivot);
+    hrowi[kc] = hrowi[kce];
+    hrowi[kce] = 0;
+    if (j == jpivot) {
+      kpivot = k;
+    }
+  }
+  assert (kpivot>0);
+  
+  /* Store the pivot sequence number */
+  ++fact->npivots;
+  rlink[ipivot].pre = -fact->npivots;
+  clink[jpivot].pre = -fact->npivots;
+  
+  pivot = dluval[kpivot];
+  dluval[kpivot] = dluval[kipis];
+  dluval[kipis] = pivot;
+  hcoli[kpivot] = hcoli[kipis];
+  hcoli[kipis] = jpivot;
+  
+} /* c_ekkprpv */
+
+/*
+ * c_ekkclco is almost exactly like c_ekkrwco.
+ */
+int c_ekkclco(const EKKfactinfo *fact,int *hcoli, int *mrstrt, int *hinrow, int xnewro)
+{
+#if 0
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  int i, k, nz, kold;
+  int kstart;
+  const int nrow	= fact->nrow;
+  
+  for (i = 1; i <= nrow; ++i) {
+    nz = hinrow[i];
+    if (0 < nz) {
+      /* save the last column entry of row i in hinrow */
+      /* and replace that entry with -i */
+      k = mrstrt[i] + nz - 1;
+      hinrow[i] = hcoli[k];
+      hcoli[k] = -i;
+    }
+  }
+  
+  kstart = 0;
+  kold = 0;
+  for (k = 1; k <= xnewro; ++k) {
+    if (hcoli[k] != 0) {
+      ++kstart;
+      
+      /* if this is the last entry for the row... */
+      if (hcoli[k] < 0) {
+	/* restore the entry */
+	i = -hcoli[k];
+	hcoli[k] = hinrow[i];
+	
+	/* update mrstart and hinrow */
+	mrstrt[i] = kold + 1;
+	hinrow[i] = kstart - kold;
+	kold = kstart;
+      }
+      
+      hcoli[kstart] = hcoli[k];
+    }
+  }
+  
+  /* INSERTED INCASE CALLED FROM YTRIAN JJHF */
+  mrstrt[nrow + 1] = kstart + 1;
+  
+  return (kstart);
+} /* c_ekkclco */
+
+
+
+#undef MACTION_T
+#define COIN_OSL_CMFC
+#define MACTION_T short int
+int c_ekkcmfc(EKKfactinfo *fact,
+	    EKKHlink *rlink, EKKHlink *clink,
+	    EKKHlink *mwork, void *maction_void,
+	    int nnetas,
+	    int *nsingp, int *xrejctp,
+	    int *xnewrop, int xnewco, 
+	    int *ncompactionsp)
+  
+#include "CoinOslC.h"
+#undef COIN_OSL_CMFC
+#undef MACTION_T
+  static int c_ekkidmx(int n, const double *dx)
+{
+  int ret_val;
+  int i;
+  double dmax;
+  --dx;
+  
+  /* Function Body */
+  
+  if (n < 1) {
+    return (0);
+  }
+  
+  if (n == 1) {
+    return (1);
+  }
+  
+  ret_val = 1;
+  dmax = fabs(dx[1]);
+  for (i = 2; i <= n; ++i) {
+    if (fabs(dx[i]) > dmax) {
+      ret_val = i;
+      dmax = fabs(dx[i]);
+    }
+  }
+  
+  return ret_val;
+} /* c_ekkidmx */
+/*     Return codes in IRTCOD/IRTCOD are */
+/*     4: numerical problems */
+/*     5: not enough space in row file */
+/*     6: not enough space in column file */
+int c_ekkcmfd(EKKfactinfo *fact,
+	    int *mcol, 
+	    EKKHlink *rlink, EKKHlink *clink,
+	    int *maction,
+	    int nnetas,
+	    int *nnentlp, int *nnentup,
+	    int *nsingp)
+{
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+  int nnentl	= *nnentlp;
+  int nnentu	= *nnentup;
+  int storeZero = fact->ndenuc;
+  
+  int mkrs[8];
+  double dpivyy[8];
+  
+  /* Local variables */
+  int i, j;
+  double d0, dx;
+  int nz, ndo, krs;
+  int kend, jcol;
+  int irow, iput, jrow, krxs;
+  int mjcol[8];
+  double pivot;
+  int count;
+  int ilast, isort;
+  double dpivx, dsave;
+  double dpivxx[8];
+  double multip;
+  int lstart, ndense, krlast, kcount, idense, ipivot,
+    jdense, kchunk, jpivot;
+  
+  const int nrow	= fact->nrow;
+  
+  int irtcod = 0;
+  
+  lstart = nnetas - nnentl + 1;
+  
+  /* put list of columns in last HROWI */
+  /* fix row order once for all */
+  ndense = nrow - fact->npivots;
+  iput = ndense + 1;
+  for (i = 1; i <= nrow; ++i) {
+    if (hpivro[i] > 0) {
+      irow = hpivro[i];
+      for (j = 1; j <= nrow; ++j) {
+	--iput;
+	maction[iput] = irow;
+	irow = rlink[irow].suc;
+	if (irow == 0) {
+	  break;
+	}
+      }
+    }
+  }
+  if (iput != 1) {
+    ++(*nsingp);
+  }
+  else {
+    /*     Use HCOLI just for last row */
+    ilast = maction[1];
+    krlast = mrstrt[ilast];
+    /*     put list of columns in last HCOLI */
+    iput = 0;
+    for (i = 1; i <= nrow; ++i) {
+      if (clink[i].pre >= 0) {
+	hcoli[krlast + iput] = i;
+	++iput;
+      }
+    }
+    if (iput != ndense) {
+      ++(*nsingp);
+    }
+    else {
+      ndo = ndense / 8;
+      /*     do most */
+      for (kcount = 1; kcount <= ndo; ++kcount) {
+        idense = ndense;
+        isort = 8;
+        for (count = ndense; count >= ndense - 7; --count) {
+	  ipivot = maction[count];
+	  krs = mrstrt[ipivot];
+	  --isort;
+	  mkrs[isort] = krs;
+        }
+        isort = 8;
+        for (count = ndense; count >= ndense - 7; --count) {
+	  /* Find a pivot element */
+	  --isort;
+	  ipivot = maction[count];
+	  krs = mkrs[isort];
+	  jcol = c_ekkidmx(idense, &dluval[krs]) - 1;
+	  pivot = dluval[krs + jcol];
+	  --idense;
+	  mcol[count] = jcol;
+	  mjcol[isort] = mcol[count];
+	  dluval[krs + jcol] = dluval[krs + idense];
+	  if (fabs(pivot) < fact->zeroTolerance) {
+	    pivot = 0.;
+	    dpivx = 0.;
+	  } else {
+	    dpivx = 1. / pivot;
+	  }
+	  dluval[krs + idense] = pivot;
+	  dpivxx[isort] = dpivx;
+	  for (j = isort - 1; j >= 0; --j) {
+	    krxs = mkrs[j];
+	    multip = -dluval[krxs + jcol] * dpivx;
+	    dluval[krxs + jcol] = dluval[krxs + idense];
+	    /*           for moment skip if zero */
+	    if (fabs(multip) > fact->zeroTolerance) {
+	      for (i = 0; i < idense; ++i) {
+		dluval[krxs + i] += multip * dluval[krs + i];
+	      }
+	    } else {
+	      multip = 0.;
+	    }
+	    dluval[krxs + idense] = multip;
+	  }
+        }
+	/*       sort all U in rows already done */
+        for (i = 7; i >= 0; --i) {
+	  /* ****     this is important bit */
+	  krs = mkrs[i];
+	  for (j = i - 1; j >= 0; --j) {
+	    jcol = mjcol[j];
+	    dsave = dluval[krs + jcol];
+	    dluval[krs + jcol] = dluval[krs + idense + j];
+	    dluval[krs + idense + j] = dsave;
+	  }
+        }
+	/*       leave IDENSE as it is */
+        if (ndense <= 400) {
+	  for (jrow = ndense - 8; jrow >= 1; --jrow) {
+	    irow = maction[jrow];
+	    krxs = mrstrt[irow];
+	    for (j = 7; j >= 0; --j) {
+	      jcol = mjcol[j];
+	      dsave = dluval[krxs + jcol];
+	      dluval[krxs + jcol] = dluval[krxs + idense + j];
+	      dluval[krxs + idense + j] = dsave;
+	    }
+	    for (j = 7; j >= 0; --j) {
+	      krs = mkrs[j];
+	      jdense = idense + j;
+	      dpivx = dpivxx[j];
+	      multip = -dluval[krxs + jdense] * dpivx;
+	      if (fabs(multip) <= fact->zeroTolerance) {
+		multip = 0.;
+	      }
+	      dpivyy[j] = multip;
+	      dluval[krxs + jdense] = multip;
+	      for (i = idense; i < jdense; ++i) {
+		dluval[krxs + i] += multip * dluval[krs + i];
+	      }
+	    }
+	    for (i = 0; i < idense; ++i) {
+	      dx = dluval[krxs + i];
+	      d0 = dpivyy[0] * dluval[mkrs[0] + i];
+	      dx += dpivyy[1] * dluval[mkrs[1] + i];
+	      d0 += dpivyy[2] * dluval[mkrs[2] + i];
+	      dx += dpivyy[3] * dluval[mkrs[3] + i];
+	      d0 += dpivyy[4] * dluval[mkrs[4] + i];
+	      dx += dpivyy[5] * dluval[mkrs[5] + i];
+	      d0 += dpivyy[6] * dluval[mkrs[6] + i];
+	      dx += dpivyy[7] * dluval[mkrs[7] + i];
+	      dluval[krxs + i] = d0 + dx;
+	    }
+	  }
+        } else {
+	  for (jrow = ndense - 8; jrow >= 1; --jrow) {
+	    irow = maction[jrow];
+	    krxs = mrstrt[irow];
+	    for (j = 7; j >= 0; --j) {
+	      jcol = mjcol[j];
+	      dsave = dluval[krxs + jcol];
+	      dluval[krxs + jcol] = dluval[krxs + idense + j];
+	      dluval[krxs + idense + j] = dsave;
+	    }
+	    for (j = 7; j >= 0; --j) {
+	      krs = mkrs[j];
+	      jdense = idense + j;
+	      dpivx = dpivxx[j];
+	      multip = -dluval[krxs + jdense] * dpivx;
+	      if (fabs(multip) <= fact->zeroTolerance) {
+		multip = 0.;
+	      }
+	      dluval[krxs + jdense] = multip;
+	      for (i = idense; i < jdense; ++i) {
+		dluval[krxs + i] += multip * dluval[krs + i];
+	      }
+	    }
+	  }
+	  for (kchunk = 0; kchunk < idense; kchunk += 400) {
+	    kend = CoinMin(idense - 1, kchunk + 399);
+	    for (jrow = ndense - 8; jrow >= 1; --jrow) {
+	      irow = maction[jrow];
+	      krxs = mrstrt[irow];
+	      for (j = 7; j >= 0; --j) {
+		dpivyy[j] = dluval[krxs + idense + j];
+	      }
+	      for (i = kchunk; i <= kend; ++i) {
+		dx = dluval[krxs + i];
+		d0 = dpivyy[0] * dluval[mkrs[0] + i];
+		dx += dpivyy[1] * dluval[mkrs[1] + i];
+		d0 += dpivyy[2] * dluval[mkrs[2] + i];
+		dx += dpivyy[3] * dluval[mkrs[3] + i];
+		d0 += dpivyy[4] * dluval[mkrs[4] + i];
+		dx += dpivyy[5] * dluval[mkrs[5] + i];
+		d0 += dpivyy[6] * dluval[mkrs[6] + i];
+		dx += dpivyy[7] * dluval[mkrs[7] + i];
+		dluval[krxs + i] = d0 + dx;
+	      }
+	    }
+	  }
+        }
+	/*       resort all U in rows already done */
+        for (i = 7; i >= 0; --i) {
+	  krs = mkrs[i];
+	  for (j = 0; j < i; ++j) {
+	    jcol = mjcol[j];
+	    dsave = dluval[krs + jcol];
+	    dluval[krs + jcol] = dluval[krs + idense + j];
+	    dluval[krs + idense + j] = dsave;
+	  }
+        }
+        ndense += -8;
+      }
+      idense = ndense;
+      /*     do remainder */
+      for (count = ndense; count >= 1; --count) {
+	/*        Find a pivot element */
+        ipivot = maction[count];
+        krs = mrstrt[ipivot];
+        jcol = c_ekkidmx(idense, &dluval[krs]) - 1;
+        pivot = dluval[krs + jcol];
+        --idense;
+        mcol[count] = jcol;
+        dluval[krs + jcol] = dluval[krs + idense];
+        if (fabs(pivot) < fact->zeroTolerance) {
+	  dluval[krs + idense] = 0.;
+        } else {
+	  dpivx = 1. / pivot;
+	  dluval[krs + idense] = pivot;
+	  for (jrow = idense; jrow >= 1; --jrow) {
+	    irow = maction[jrow];
+	    krxs = mrstrt[irow];
+	    multip = -dluval[krxs + jcol] * dpivx;
+	    dluval[krxs + jcol] = dluval[krxs + idense];
+	    /*           for moment skip if zero */
+	    if (fabs(multip) > fact->zeroTolerance) {
+	      dluval[krxs + idense] = multip;
+	      for (i = 0; i < idense; ++i) {
+		dluval[krxs + i] += multip * dluval[krs + i];
+	      }
+	    } else {
+	      dluval[krxs + idense] = 0.;
+	    }
+	  }
+        }
+      }
+      /*     now create in form for OSL */
+      ndense = nrow - fact->npivots;
+      idense = ndense;
+      for (count = ndense; count >= 1; --count) {
+	/*        Find a pivot element */
+        ipivot = maction[count];
+        krs = mrstrt[ipivot];
+        --idense;
+        jcol = mcol[count];
+        jpivot = hcoli[krlast + jcol];
+        ++fact->npivots;
+        pivot = dluval[krs + idense];
+        if (pivot == 0.) {
+	  hinrow[ipivot] = 0;
+	  rlink[ipivot].pre = -nrow - 1;
+	  ++(*nsingp);
+	  irtcod = 10;
+        } else {
+	  rlink[ipivot].pre = -fact->npivots;
+	  clink[jpivot].pre = -fact->npivots;
+	  hincol[jpivot] = 0;
+	  ++fact->xnetal;
+	  mcstrt[fact->xnetal] = lstart - 1;
+	  hpivco[fact->xnetal] = ipivot;
+	  for (jrow = idense; jrow >= 1; --jrow) {
+	    irow = maction[jrow];
+	    krxs = mrstrt[irow];
+	    multip = dluval[krxs + idense];
+	    /*           for moment skip if zero */
+	    if (multip != 0.||storeZero) {
+	      /* Store elementary row transformation */
+	      ++nnentl;
+	      --nnentu;
+	      --lstart;
+	      dluval[lstart] = multip;
+	      hrowi[lstart] = SHIFT_INDEX(irow);
+	    }
+	  }
+	  hcoli[krlast + jcol] = hcoli[krlast + idense];
+	  /*         update pivot row and last row HCOLI */
+	  dluval[krs + idense] = dluval[krs];
+	  hcoli[krlast + idense] = hcoli[krlast];
+	  nz = 1;
+	  dluval[krs] = pivot;
+	  hcoli[krs] = jpivot;
+	  if (!storeZero) {
+	    for (i = 1; i <= idense; ++i) {
+	      if (fabs(dluval[krs + i]) > fact->zeroTolerance) {
+		++nz;
+		hcoli[krs + nz - 1] = hcoli[krlast + i];
+		dluval[krs + nz - 1] = dluval[krs + i];
+	      }
+	    }
+	    hinrow[ipivot] = nz;
+	  } else {
+	    for (i = 1; i <= idense; ++i) {
+	      ++nz;
+	      hcoli[krs + nz - 1] = hcoli[krlast + i];
+	      dluval[krs + nz - 1] = dluval[krs + i];
+	    }
+	    hinrow[ipivot] = nz;
+	  }
+        }
+      }
+    }
+  }
+  
+  *nnentlp = nnentl;
+  *nnentup = nnentu;
+  
+  return (irtcod);
+} /* c_ekkcmfd */
+/* ***C_EKKCMFC */
+
+/*
+ * Generate a variant of c_ekkcmfc that uses an maction array of type
+ * int rather than short.
+ */
+#undef MACTION_T
+#define C_EKKCMFY
+#define COIN_OSL_CMFC
+#define MACTION_T int
+int c_ekkcmfy(EKKfactinfo *fact,
+	    EKKHlink *rlink, EKKHlink *clink,
+	    EKKHlink *mwork, void *maction_void,
+	    int nnetas,
+	    int *nsingp, int *xrejctp,
+	    int *xnewrop, int xnewco, 
+	    int *ncompactionsp)
+  
+#include "CoinOslC.h"
+#undef COIN_OSL_CMFC
+#undef C_EKKCMFY
+#undef MACTION_T
+int c_ekkford(const EKKfactinfo *fact,const int *hinrow, const int *hincol,
+	    int *hpivro, int *hpivco,
+	    EKKHlink *rlink, EKKHlink *clink)
+{
+  int i, iri, nzi;
+  const int nrow	= fact->nrow;
+  int nsing = 0;
+  
+  /*     Uwe H. Suhl, August 1986 */
+  /*     Builds linked lists of rows and cols of nucleus for efficient */
+  /*     pivot searching. */
+
+  memset(hpivro+1,0,nrow*sizeof(int));
+  memset(hpivco+1,0,nrow*sizeof(int));
+  for (i = 1; i <= nrow; ++i) {
+    //hpivro[i] = 0;
+    //hpivco[i] = 0;
+    assert(rlink[i].suc == 0);
+    assert(clink[i].suc == 0);
+  }
+  
+  /*     Generate double linked list of rows having equal numbers of */
+  /*     nonzeros in each row. Skip pivotal rows. */
+  for (i = 1; i <= nrow; ++i) {
+    if (! (rlink[i].pre < 0)) {
+      nzi = hinrow[i];
+      if (nzi <= 0) {
+	++nsing;
+	rlink[i].pre = -nrow - 1;
+      }
+      else {
+	iri = hpivro[nzi];
+	hpivro[nzi] = i;
+	rlink[i].suc = iri;
+	rlink[i].pre = 0;
+	if (iri != 0) {
+	  rlink[iri].pre = i;
+	}
+      }
+    }
+  }
+  
+  /*     Generate double linked list of cols having equal numbers of */
+  /*     nonzeros in each col. Skip pivotal cols. */
+  for (i = 1; i <= nrow; ++i) {
+    if (! (clink[i].pre < 0)) {
+      nzi = hincol[i];
+      if (nzi <= 0) {
+	++nsing;
+	clink[i].pre = -nrow - 1;
+      }
+      else {
+	iri = hpivco[nzi];
+	hpivco[nzi] = i;
+	clink[i].suc = iri;
+	clink[i].pre = 0;
+	if (iri != 0) {
+	  clink[iri].pre = i;
+	}
+      }
+    }
+  }
+  
+  return (nsing);
+} /* c_ekkford */
+
+/*    c version of OSL from 36100 */
+
+/*     Assumes that a basis exists in correct form */
+/*     Calls Uwe's routines (approximately) */
+/*     Then if OK shuffles U into column order */
+/*     Return codes: */
+
+/*     0: everything ok */
+/*     1: everything ok but performance would be better if more space */
+/*        would be make available */
+/*     4: growth rate of element in U too big */
+/*     5: not enough space in row file */
+/*     6: not enough space in column file */
+/*     7: pivot too small - col sing */
+/*     8: pivot too small - row sing */
+/*    10: matrix is singular */
+
+/* I suspect c_ekklfct never returns 1 */
+/*
+ * layout of data
+ *
+ * dluval/hcoli:	(L^-1)B	- hole - L factors
+ *
+ * The L factors are written from high to low, starting from nnetas.
+ * There are nnentl factors in L.  lstart the next entry to use for the
+ * L factors.  Eventually, (L^-1)B turns into U.
+ 
+ * The ninbas coefficients of matrix B are originally in the start of
+ * dluval/hcoli.  As L transforms it, rows may have to be expanded.
+ * If there is room, they are copied to the start of the hole,
+ * otherwise the first part of this area is compacted, and hopefully
+ * there is then room.
+ * There are nnentu coefficients in (L^-1)B.
+ * nnentu + nnentl >= ninbas.
+ * nnentu + nnentl == ninbas if there has been no fill-in.
+ * nnentu is decreased when the pivot eliminates elements
+ * (in which case there is a corresponding increase in nnentl),
+ * and if pivoting happens to cancel out factors (in which case
+ * there is no corresponding increase in L).
+ * nnentu is increased if there is fill-in (no decrease in L).
+ * If nnentu + nnentl >= nnetas, then we've run out of room.
+ * It is not the case that the elements of (L^-1)B are all in the
+ * first nnentu positions of dluval/hcoli, but that is of course
+ * the lower bound on the number of positions needed to store it.
+ * nuspik is roughly the sum of the row lengths of the rows that were pivoted
+ * out.  singleton rows in c_ekktria do not change nuspik, but
+ * c_ekkrsin does increment it for each singleton row.
+ * That is, there are nuspik elements that in the upper part of (L^-1)B,
+ * and (nnentu - nuspik) elements left in B.
+ */
+/*
+ * As part of factorization, we test candidate pivots for numerical
+ * stability; if the largest element in a row/col is much larger than
+ * the smallest, this generally causes problems.  To easily determine
+ * what the largest element is, we ensure that it is always in front.
+ * This establishes this property; later on we take steps to preserve it.
+ */
+static void c_ekkmltf(const EKKfactinfo *fact,double *dluval, int *hcoli,
+		    const int *mrstrt, const int *hinrow,
+		    const EKKHlink *rlink)
+{
+#if 0
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  int i, j, k;
+  int koff=-1;
+  const int nrow	= fact->nrow;
+  
+  
+  for (i = 1; i <= nrow; ++i) {
+    /* ignore rows that have already been pivoted */
+    /* if it is a singleton row, the property trivially holds */
+    if (! (rlink[i].pre < 0 || hinrow[i] <= 1)) {
+      const int krs = mrstrt[i];
+      const int kre = krs + hinrow[i] - 1;
+      
+      double maxaij = 0.f;
+      
+      /* this assumes that at least one of the dluvals is non-zero. */
+      for (k = krs; k <= kre; ++k) {
+	if (! (fabs(dluval[k]) <= maxaij)) {
+	  maxaij = fabs(dluval[k]);
+	  koff = k;
+	}
+      }
+      assert (koff>0);
+      maxaij = dluval[koff];
+      j = hcoli[koff];
+      
+      dluval[koff] = dluval[krs];
+      hcoli[koff] = hcoli[krs];
+      
+      dluval[krs] = maxaij;
+      hcoli[krs] = j;
+    }
+  }
+} /* c_ekkmltf */
+int c_ekklfct( register EKKfactinfo *fact)
+{
+  const int nrow	= fact->nrow;
+  int ninbas = fact->xcsadr[nrow+1]-1;
+  int ifvsol = fact->ifvsol;
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr;
+  int *hpivco	= fact->kcpadr;
+  
+  
+  EKKHlink *rlink	= fact->kp1adr;
+  EKKHlink *clink	= fact->kp2adr;
+  EKKHlink *mwork	= (reinterpret_cast<EKKHlink*>(fact->kw1adr))-1;
+  
+  int nsing, kdnspt, xnewro, xnewco;
+  int i;
+  int xrejct;
+  int irtcod;
+  const int nnetas	= fact->nnetas;
+  
+  int ncompactions;
+  double save_drtpiv = fact->drtpiv;
+  double save_zpivlu = fact->zpivlu;
+  if (ifvsol > 0 && fact->invok < 0) {
+    fact->zpivlu =  CoinMin(0.9, fact->zpivlu * 10.);
+    fact->drtpiv=1.0e-8;
+  }
+  
+  rlink --;
+  clink --;
+  
+  /* Function Body */
+  hcoli[nnetas] = 1;
+  hrowi[nnetas] = 1;
+  dluval[nnetas] = 0.0;
+  /*     set amount of work */
+  xrejct = 0;
+  nsing = 0;
+  kdnspt = nnetas + 1;
+  fact->ndenuc = 0;
+  /*     Triangularize */
+  irtcod = c_ekktria(fact,rlink,clink,
+		   &nsing, 
+		   &xnewco, &xnewro,
+		   &ncompactions, ninbas);
+  fact->nnentl = ninbas - fact->nnentu;
+  
+  if (irtcod < 0) {
+    /* no space or system error */
+    goto L8000;
+  }
+  
+  if (irtcod != 0 && fact->invok >= 0) {
+    goto L8500;	/* 7 or 8 - pivot too small */
+  }
+#if 0
+  /* is this necessary ? */
+  lstart = nnetas - fact->nnentl + 1;
+  for (i = lstart; i <= nnetas; ++i) {
+    hrowi[i] = (hcoli[i] << 3);
+  }
+#endif
+  
+  /* See if finished */
+  if (! (fact->npivots >= nrow)) {
+    int nsing1;
+    
+    /*     No - do nucleus */
+    
+    nsing1 = c_ekkford(fact,hinrow, hincol, hpivro, hpivco, rlink, clink);
+    nsing+= nsing1;
+    if (nsing1 != 0 && fact->invok >= 0) {
+      irtcod=7;
+      goto L8500;
+    }
+    c_ekkmltf(fact,dluval, hcoli, mrstrt, hinrow, rlink);
+    
+    {
+      bool callcmfy = false;
+      
+      if (nrow > 32767) {
+	int count = 0;
+	for (i = 1; i <= nrow; ++i) {
+	  count = CoinMax(count,hinrow[i]);
+	}
+	if (count + nrow - fact->npivots > 32767) {
+	  /* will have to use I*4 version of CMFC */
+	  /* no changes to pointer params */
+	  callcmfy = true;
+	}
+      }
+      
+      irtcod = (callcmfy ? c_ekkcmfy : c_ekkcmfc)
+	(fact, 
+	 rlink, clink,
+	 mwork, &mwork[nrow + 1],
+	 nnetas,
+	 &nsing, &xrejct,
+	 &xnewro, xnewco,
+	 &ncompactions);
+      
+      /* irtcod one of 0,-5,7,10 */
+    }
+    
+    if (irtcod < 0) {
+      goto L8000;
+    }
+    kdnspt = nnetas - fact->nnentl;
+  }
+  
+  /*     return if error */
+  if (nsing > 0 || irtcod == 10) {
+    irtcod = 99;
+  }
+  /* irtcod one of 0,7,99 */
+  
+  if (irtcod != 0) {
+    goto L8500;
+  }
+  ++fact->xnetal;
+  mcstrt[fact->xnetal] = nnetas - fact->nnentl;
+  
+  /* give message if tight on memory */
+  if (ncompactions > 2 ) {
+    if (1) {
+      int etasize =CoinMax(4*fact->nnentu+(nnetas-fact->nnentl)+1000,fact->eta_size);
+      fact->eta_size=CoinMin(static_cast<int>(1.2*fact->eta_size),etasize);
+      if (fact->maxNNetas>0&&fact->eta_size>
+	  fact->maxNNetas) {
+	fact->eta_size=fact->maxNNetas;
+      }
+    } /* endif */
+  }
+  /*       Shuffle U and multiply L by 8 (if assembler) */
+  {
+    int jrtcod = c_ekkshff(fact, clink, rlink,
+			   xnewro);
+    
+    /* nR_etas is the number of R transforms;
+     * it is incremented only in c_ekketsj.
+     */
+    fact->nR_etas = 0;
+    /*fact->R_etas_start = mcstrt+nrow+fact->nnentl+3;*/
+    fact->R_etas_start[1] = /*kdnspt - 1*/0;	/* magic */
+    fact->R_etas_index = &fact->xeradr[kdnspt - 1];
+    fact->R_etas_element = &fact->xeeadr[kdnspt - 1];
+    
+    
+    
+    if (jrtcod != 0) {
+      irtcod = jrtcod;
+      /* irtcod == 2 */
+    }
+  }
+  goto L8500;
+  
+  /* Fatal error */
+ L8000:
+  
+  if (1) {
+    if (fact->maxNNetas != fact->eta_size &&
+	nnetas) {
+      /* return and get more space */
+      
+      /* double eta_size, unless that exceeds max (if there is one) */
+      fact->eta_size = fact->eta_size<<1;
+      if (fact->maxNNetas > 0 &&
+	  fact->eta_size > fact->maxNNetas) {
+	fact->eta_size = fact->maxNNetas;
+      }
+      return (5);
+    }
+  }
+  /*c_ekkmesg_no_i1(121, -irtcod);*/
+  irtcod = 3;
+  
+ L8500:
+  /* restore pivot tolerance */
+  fact->drtpiv=save_drtpiv;
+  fact->zpivlu=save_zpivlu;
+#ifndef NDEBUG
+  if (fact->rows_ok) {
+    int * hinrow=fact->xrnadr;
+    if (!fact->xe2adr) {
+      for (int i=1;i<=fact->nrow;i++) {
+	assert (hinrow[i]>=0&&hinrow[i]<=fact->nrow);
+      }
+    }
+  }
+#endif
+  return (irtcod);
+} /* c_ekklfct */
+
+
+/*
+  summary of return codes
+  
+  c_ekktria:
+  7 small pivot
+  -5 no memory
+  
+  c_ekkcsin:
+  returns true if small pivot
+  
+  c_ekkrsin:
+  -5 no memory
+  7 small pivot
+  
+  c_ekkfpvt:
+  10: no pivots found (singular)
+  
+  c_ekkcmfd:
+  10: zero pivot (not just small)
+  
+  c_ekkcmfc:
+  -5:  no memory
+  any non-zero code from c_ekkcsin, c_ekkrsin, c_ekkfpvt, c_ekkprpv, c_ekkcmfd
+  
+  c_ekkshff:
+  2:  singular
+  
+  c_ekklfct:
+  any positive code from c_ekktria, c_ekkcmfc, c_ekkshff (2,7,10)
+  *except* 10, which is changed to 99.
+  all negative return codes are changed to 5 or 3
+  (5 == ran out of memory but could get more,
+  3 == ran out of memory, no luck)
+  so:  2,3,5,7,99
+  
+  c_ekklfct1:
+  1: c_ekksmem_invert failed
+  2: c_ekkslcf/c_ekkslct ran out of room
+  any return code from c_ekklfct, except 2 and 5
+*/
+
+void c_ekkrowq(int *hrow, int *hcol, double *dels, 
+	     int *mrstrt,
+	     const int *hinrow, int nnrow, int ninbas)
+{
+  int i, k, iak, jak;
+  double daik;
+  int iloc;
+  double dsave;
+  int isave, jsave;
+  
+  /* Order matrix rowwise using MRSTRT, DELS, HCOL */
+  
+  k = 1;
+  /* POSITION AFTER END OF ROW */
+  for (i = 1; i <= nnrow; ++i) {
+    k += hinrow[i];
+    mrstrt[i] = k;
+  }
+  
+  for (k = ninbas; k >= 1; --k) {
+    iak = hrow[k];
+    if (iak != 0) {
+      daik = dels[k];
+      jak = hcol[k];
+      hrow[k] = 0;
+      while (1) {
+	--mrstrt[iak];
+	
+	iloc = mrstrt[iak];
+	
+	dsave = dels[iloc];
+	isave = hrow[iloc];
+	jsave = hcol[iloc];
+	dels[iloc] = daik;
+	hrow[iloc] = 0;
+	hcol[iloc] = jak;
+	
+	if (isave == 0)
+	  break;
+	daik = dsave;
+	iak = isave;
+	jak = jsave;
+      }
+      
+    }
+  }
+} /* c_ekkrowq */
+
+
+
+int c_ekkrwco(const EKKfactinfo *fact,double *dluval, 
+	    int *hcoli, int *mrstrt, int *hinrow, int xnewro)
+{
+  int i, k, nz, kold;
+  int kstart;
+  const int nrow	= fact->nrow;
+  
+  for (i = 1; i <= nrow; ++i) {
+    nz = hinrow[i];
+    if (0 < nz) {
+      /* save the last column entry of row i in hinrow */
+      /* and replace that entry with -i */
+      k = mrstrt[i] + nz - 1;
+      hinrow[i] = hcoli[k];
+      hcoli[k] = -i;
+    }
+  }
+  
+  kstart = 0;
+  kold = 0;
+  for (k = 1; k <= xnewro; ++k) {
+    if (hcoli[k] != 0) {
+      ++kstart;
+      
+      /* if this is the last entry for the row... */
+      if (hcoli[k] < 0) {
+	/* restore the entry */
+	i = -hcoli[k];
+	hcoli[k] = hinrow[i];
+	
+	/* update mrstart and hinrow */
+	/* ACTUALLY, hinrow should already be accurate */
+	mrstrt[i] = kold + 1;
+	hinrow[i] = kstart - kold;
+	kold = kstart;
+      }
+      
+      /* move the entry */
+      dluval[kstart] = dluval[k];
+      hcoli[kstart] = hcoli[k];
+    }
+  }
+  
+  return (kstart);
+} /* c_ekkrwco */
+
+
+
+int c_ekkrwcs(const EKKfactinfo *fact,double *dluval, int *hcoli, int *mrstrt,
+	    const int *hinrow, const EKKHlink *mwork,
+	    int nfirst)
+{
+#if 0
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  int i, k, k1, k2, nz;
+  int irow, iput;
+  const int nrow	= fact->nrow;
+  
+  /*     Compress row file */
+  
+  iput = 1;
+  irow = nfirst;
+  for (i = 1; i <= nrow; ++i) {
+    nz = hinrow[irow];
+    k1 = mrstrt[irow];
+    if (k1 != iput) {
+      mrstrt[irow] = iput;
+      k2 = k1 + nz - 1;
+      for (k = k1; k <= k2; ++k) {
+	dluval[iput] = dluval[k];
+	hcoli[iput] = hcoli[k];
+	++iput;
+      }
+    } else {
+      iput += nz;
+    }
+    irow = mwork[irow].suc;
+  }
+  
+  return (iput);
+} /* c_ekkrwcs */
+void c_ekkrwct(const EKKfactinfo *fact,double *dluval, int *hcoli, int *mrstrt,
+	     const int *hinrow, const EKKHlink *mwork,
+	     const EKKHlink *rlink,
+	     const short *msort, double *dsort,
+	     int nlast, int xnewro)
+{
+#if 0
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+#endif
+  int i, k, k1, nz, icol;
+  int kmax;
+  int irow, iput;
+  int ilook;
+  const int nrow	= fact->nrow;
+  
+  iput = xnewro;
+  irow = nlast;
+  kmax = nrow - fact->npivots;
+  for (i = 1; i <= nrow; ++i) {
+    nz = hinrow[irow];
+    k1 = mrstrt[irow] - 1;
+    if (rlink[irow].pre < 0) {
+      /* pivoted on already */
+      iput -= nz;
+      if (k1 != iput) {
+	mrstrt[irow] = iput + 1;
+	for (k = nz; k >= 1; --k) {
+	  dluval[iput + k] = dluval[k1 + k];
+	  hcoli[iput + k] = hcoli[k1 + k];
+	}
+      }
+    } else {
+      /* not pivoted - going dense */
+      iput -= kmax;
+      mrstrt[irow] = iput + 1;
+      c_ekkdzero( kmax, &dsort[1]);
+      for (k = 1; k <= nz; ++k) {
+	icol = hcoli[k1 + k];
+	ilook = msort[icol];
+	dsort[ilook] = dluval[k1 + k];
+      }
+      c_ekkdcpy(kmax,
+	      (dsort+1), (dluval+iput + 1));
+    }
+    irow = mwork[irow].pre;
+  }
+} /* c_ekkrwct */
+/*     takes Uwe's modern structures and puts them back 20 years */
+int c_ekkshff(EKKfactinfo *fact,
+	    EKKHlink *clink, EKKHlink *rlink, 
+	    int xnewro)
+{
+  int *hpivro	= fact->krpadr; 
+  
+  int i, j;
+  int nbas, icol;
+  int ipiv;
+  const int nrow	= fact->nrow;
+  int nsing;
+  
+  for (i = 1; i <= nrow; ++i) {
+    j = -rlink[i].pre;
+    rlink[i].pre = j;
+    if (j > 0 && j <= nrow) {
+      hpivro[j] = i;
+    }
+    j = -clink[i].pre;
+    clink[i].pre = j;
+  }
+  /* hpivro[j] is now (hopefully) the row that was pivoted on step j */
+  /* rlink[i].pre is the step in which row i was pivoted */
+  
+  nbas = 0;
+  nsing = 0;
+  /* Decide if permutation wanted */
+  fact->first_dense=nrow-fact->ndenuc+1+1;
+  fact->last_dense=nrow;
+  
+  /* rlink[].suc is dead at this point */
+  
+  /*
+   * replace the the basis index 
+   * with the pivot (or permuted) index generated by factorization.
+   * This eventually goes into mpermu.
+   */
+  for (icol = 1; icol <= nrow; ++icol) {
+    int ibasis = icol;
+    ipiv = clink[ibasis].pre;
+    
+    if (0 < ipiv && ipiv <= nrow) {
+      rlink[ibasis].suc = ipiv;
+      ++nbas;
+    }
+  }
+  
+  nsing = nrow - nbas;
+  if (nsing > 0) {
+    abort();
+  }
+  
+  /* if we reach here, then rlink[1..nrow].suc == clink[1..nrow].pre */
+  
+  /* switch off sparse update if any dense section */
+  {
+    const int notMuchRoom = (fact->nnentu + xnewro + 10 > fact->nnetas - fact->nnentl);
+    
+    /* must be same as in c_ekkshfv */
+    if (fact->ndenuc || notMuchRoom||nrow<C_EKK_GO_SPARSE) {
+#if PRINT_DEBUG
+      if (fact->if_sparse_update) {
+	printf("**** Switching off sparse update - dense - c_ekkshff\n");
+      }
+#endif
+      fact->if_sparse_update=0;
+    }
+  }
+  
+  /* hpivro[1..nrow] is not read by c_ekkshfv */
+  c_ekkshfv(fact,
+	    rlink, clink, 
+	  xnewro);
+  
+  return (0);
+} /* c_ekkshff */
+/* sorts on indices dragging elements with */
+static void c_ekk_sort2(int * key , double * array2,int number)
+{
+  int minsize=10;
+  int n = number;
+  int sp;
+  int *v = key;
+  int *m, t;
+  int * ls[32] , * rs[32];
+  int *l , *r , c;
+  double it;
+  int j;
+  /*check already sorted  */
+#ifndef LONG_MAX
+#define LONG_MAX 0x7fffffff;
+#endif
+  int last=-LONG_MAX;
+  for (j=0;j<number;j++) {
+    if (key[j]>=last) {
+      last=key[j];
+    } else {
+      break;
+    } /* endif */
+  } /* endfor */
+  if (j==number) {
+    return;
+  } /* endif */
+  sp = 0 ; ls[sp] = v ; rs[sp] = v + (n-1) ;
+  while( sp >= 0 )
+    {
+      if ( rs[sp] - ls[sp] > minsize )
+	{
+	  l = ls[sp] ; r = rs[sp] ; m = l + (r-l)/2 ;
+	  if ( *l > *m )
+	    {
+	      t = *l ; *l = *m ; *m = t ;
+	      it = array2[l-v] ; array2[l-v] = array2[m-v] ; array2[m-v] = it ;
+	    }
+	  if ( *m > *r )
+	    {
+	      t = *m ; *m = *r ; *r = t ;
+	      it = array2[m-v] ; array2[m-v] = array2[r-v] ; array2[r-v] = it ;
+	      if ( *l > *m )
+		{
+		  t = *l ; *l = *m ; *m = t ;
+		  it = array2[l-v] ; array2[l-v] = array2[m-v] ; array2[m-v] = it ;
+		}
+	    }
+	  c = *m ;
+	  while ( r - l > 1 )
+	    {
+	      while ( *(++l) < c ) ;
+	      while ( *(--r) > c ) ;
+	      t = *l ; *l = *r ; *r = t ;
+	      it = array2[l-v] ; array2[l-v] = array2[r-v] ; array2[r-v] = it ;
+	    }
+	  l = r - 1 ;
+	  if ( l < m )
+	    {  ls[sp+1] = ls[sp] ;
+	      rs[sp+1] = l      ;
+	      ls[sp  ] = r      ;
+	    }
+	  else
+	    {  ls[sp+1] = r      ;
+	      rs[sp+1] = rs[sp] ;
+	      rs[sp  ] = l      ;
+	    }
+	  sp++ ;
+	}
+      else sp-- ;
+    }
+  for ( l = v , m = v + (n-1) ; l < m ; l++ )
+    {  if ( *l > *(l+1) )
+	{
+	  c = *(l+1) ;
+	  it = array2[(l-v)+1] ;
+	  for ( r = l ; r >= v && *r > c ; r-- )
+	    {
+	      *(r+1) = *r ;
+	      array2[(r-v)+1] = array2[(r-v)] ;
+	    }
+	  *(r+1) = c ;
+	  array2[(r-v)+1] = it ;
+	}
+    }
+}
+/*     For each row compute reciprocal of pivot element and  take out of */
+/*     Also use HLINK(1 to permute column numbers */
+/*     and HPIVRO to permute row numbers */
+/*     Sort into column order as was stored by row */
+/*     If Assembler then shift row numbers in L by 3 */
+/*     Put column numbers in U for L-U update */
+/*     and multiply U elements by - reciprocal of pivot element */
+/*     and set up backward pointers for pivot rows */
+void c_ekkshfv(EKKfactinfo *fact,
+	       EKKHlink *rlink, EKKHlink *clink,
+	     int xnewro)
+{
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  double *dvalpv = fact->kw3adr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *hpivro	= fact->krpadr; 
+  int *hpivco	= fact->kcpadr;
+  double *dpermu = fact->kadrpm;
+  double * de2val = fact->xe2adr ? fact->xe2adr-1: 0;
+  int nnentu	= fact->nnentu;
+  int xnetal	= fact->xnetal;
+  
+  int numberSlacks; /* numberSlacks not read */
+  
+  int i, j, k, kk, nel;
+  int nroom;
+  bool need_more_space;
+  int ndenuc=fact->ndenuc;
+  int if_sparse_update=fact->if_sparse_update; 
+  int nnentl = fact->nnentl;
+  int nnetas = fact->nnetas;
+  
+  int *ihlink	= (reinterpret_cast<int*> (clink))+1;	/* can't use rlink for simple loop below */
+  
+  const int nrow		= fact->nrow;
+  const int maxinv	= fact->maxinv;
+  
+  /* this is not just a temporary - c_ekkbtrn etc use this */
+  int *mpermu	= (reinterpret_cast<int*> (dpermu+nrow))+1;
+  
+  int * temp = ihlink+nrow;
+  int * temp2 = temp+nrow;
+  const int notMuchRoom = (nnentu + xnewro + 10 > nnetas - nnentl);
+  
+  /* compress hlink and make simpler */
+  for (i = 1; i <= nrow; ++i) {
+    mpermu[i] = rlink[i].pre;
+    ihlink[i] = rlink[i].suc;
+  }
+  /* mpermu[i] == the step in which row i was pivoted */
+  /* ihlink[i] == the step in which col i was pivoted */
+  
+  /* must be same as in c_ekkshff */
+  if (fact->ndenuc||notMuchRoom||nrow<C_EKK_GO_SPARSE) {
+    int ninbas;
+    
+    /* CHANGE COLUMN NUMBERS AND FILL IN RECIPROCALS */
+    /* ALSO RECOMPUTE NUMBER IN COLUMN */
+    /* initialize with a fake pivot in each column */
+    c_ekkscpy_0_1(nrow, 1, &hincol[1]);
+    
+    if (notMuchRoom) {
+      fact->eta_size=static_cast<int>(1.05*fact->eta_size);
+      
+      /* eta_size can be no larger than maxNNetas */
+      if (fact->maxNNetas > 0 &&
+	  fact->eta_size > fact->maxNNetas) {
+	fact->eta_size=fact->maxNNetas;
+      }
+    } /* endif */
+    
+    /* For each row compute reciprocal of pivot element and take out of U */
+    /* Also use ihlink to permute column numbers */
+    /* the rows are not stored compactly or in order,
+     * so we have to find out where the last one is stored */
+    ninbas=0;
+    for (i = 1; i <= nrow; ++i) {
+      int jpiv=mpermu[i];
+      int nin=hinrow[i];
+      int krs = mrstrt[i];
+      int kre = krs + nin;
+      
+      temp[jpiv]=krs;
+      temp2[jpiv]=nin;
+      
+      ninbas = CoinMax(kre, ninbas);
+      
+      /* c_ekktria etc ensure that the first row entry is the pivot */
+      dvalpv[jpiv] = 1. / dluval[krs];
+      hcoli[krs] = 0;	/* probably needed for c_ekkrowq */
+      /* room for the pivot has already been allocated, so hincol ok */
+      
+      for (kk = krs + 1; kk < kre; ++kk) {
+	int j = ihlink[hcoli[kk]];
+	hcoli[kk] = j;		/* permute the col index */
+	hrowi[kk] = jpiv;	/* permute the row index */
+	++hincol[j];
+      }
+    }
+    /* temp [mpermu[i]] == mrstrt[i] */
+    /* temp2[mpermu[i]] == hinrow[i] */
+    
+    ninbas--;	/* ???? */
+    c_ekkscpy(nrow, &temp[1], &mrstrt[1]);
+    c_ekkscpy(nrow, &temp2[1], &hinrow[1]);
+    
+    /* now mrstrt, hinrow, hcoli and hrowi have been permuted */
+    
+    /* Sort into column order as was stored by row */
+    /* There will be an empty entry in front of each each column,
+     * because we initialized hincol to 1s, and c_ekkrowq fills in
+     * entries from the back */
+    c_ekkrowq(hcoli, hrowi, dluval, mcstrt, hincol, nrow, ninbas);
+    
+    
+    /* The shuffle zeroed out column pointers */
+    /* Put them back for L-U update */
+    /* Also multiply U elements by - reciprocal of pivot element */
+    /* Also decrement mcstrt/hincol to give "real" sizes */
+    for (i = 1; i <= nrow; ++i) {
+      int kx = --mcstrt[i];
+      nel = --hincol[i];
+      hrowi[kx] = nel;
+      dluval[kx] = dvalpv[i];
+#ifndef NO_SHIFT
+      for (int j=kx+1;j<=kx+nel;j++)
+	hrowi[j] = SHIFT_INDEX(hrowi[j]);
+#endif
+    }
+    
+    /* sort dense part */
+    for (i=nrow-ndenuc+1; i<=nrow; i++) {
+      int kx = mcstrt[i]+1;	/* "real" entries start after pivot */
+      int nel = hincol[i];
+      c_ekk_sort2(&hrowi[kx],&dluval[kx],nel);
+    }
+    
+    /* Recompute number in U */
+    nnentu = mcstrt[nrow] + hincol[nrow];
+    mcstrt[nrow + 4] = nnentu + 1;	/* magic - AND DEAD */
+    
+    /* as not much room switch off fast etas */
+    mrstrt[1] = 0;			/* magic */
+    fact->rows_ok = false;
+    i = nrow + maxinv + 5;	/* DEAD */
+  } else {
+    /* *************************************** */
+    /*       enough memory to do a bit faster */
+    /*       For each row compute reciprocal of pivot element and */
+    /*       take out of U */
+    /*       Also use HLINK(1 to permute column numbers */
+    int ninbas=0;
+    int ilast; /* last available entry */
+    int spareSpace;
+    double * dluval2;
+    /*int * hlink2 = ihlink+nrow;
+      int * mrstrt2 = hlink2+nrow;*/
+    /* mwork has order of row copy */
+    EKKHlink *mwork	= (reinterpret_cast<EKKHlink*>(fact->kw1adr))-1;
+    fact->rows_ok = true;
+    
+    if (if_sparse_update) {
+      ilast=nnetas-nnentl;
+    } else {
+      /* missing out nnentl stuff */
+      ilast=nnetas;
+    }
+    spareSpace=ilast-nnentu;
+    need_more_space=false;
+    /*     save clean row copy if enough room */
+    nroom = (spareSpace) / nrow;
+    if (nrow<10000) {
+      if (nroom < 10) {
+	need_more_space=true;
+      }
+    } else {
+      if (nroom < 5&&!if_sparse_update) {
+	need_more_space=true;
+      }
+    }
+    if (nroom > CoinMin(50,maxinv)) {
+      need_more_space=false;
+    }
+    if (need_more_space) {
+      if (if_sparse_update) {
+	int i1=fact->eta_size+10*nrow;
+	fact->eta_size=static_cast<int>(1.2*fact->eta_size);
+	if (i1>fact->eta_size) {
+	  fact->eta_size=i1;
+	}
+      } else {
+	fact->eta_size=static_cast<int>(1.05*fact->eta_size);
+      }
+    } else {
+      if (nroom<11) {
+	if (if_sparse_update) {
+	  int i1=fact->eta_size+(11-nroom)*nrow;
+	  fact->eta_size=static_cast<int>(1.2*fact->eta_size);
+	  if (i1>fact->eta_size) {
+	    fact->eta_size=i1;
+	  }
+	}
+      }
+    }
+    if (fact->maxNNetas>0&&fact->eta_size>
+	fact->maxNNetas) {
+      fact->eta_size=fact->maxNNetas;
+    }
+    {
+      /* we can swap de2val and dluval to save copying */
+      int * eta_last=mpermu+nrow*2+3;
+      int * eta_next=eta_last+nrow+2;
+      int last=0;
+      eta_last[0]=-1;
+      if (nnentl) {
+	/* went into c_ekkcmfc - if not then in order */
+	int next;
+	/*next=mwork[((nrow+1)<<1)+1];*/
+	next=mwork[nrow+1].pre;
+#ifdef DEBUG
+	j=mrstrt[next];
+#endif
+	for (i = 1; i <= nrow; ++i) {
+	  int iperm=mpermu[next];
+	  eta_next[last]=iperm;
+	  eta_last[iperm]=last;
+	  temp[iperm] = mrstrt[next];
+	  temp2[iperm] = hinrow[next];
+#ifdef DEBUG
+	  if (mrstrt[next]!=j) abort();
+	  j=mrstrt[next]+hinrow[next];
+#endif
+	  /*next= mwork[(next<<1)+2];*/
+	  next= mwork[next].suc;
+	  last=iperm;
+	}
+      } else {
+#ifdef DEBUG
+	j=0;
+#endif
+	for (i = 1; i <= nrow; ++i) {
+	  int iperm=mpermu[i];
+	  eta_next[last]=iperm;
+	  eta_last[iperm]=last;
+	  temp[iperm] = mrstrt[i];
+	  temp2[iperm] = hinrow[i];
+	  last=iperm;
+#ifdef DEBUG
+	  if (mrstrt[i]<=j) abort();
+	  if (i>1&&mrstrt[i]!=j+hinrow[i-1]) abort();
+	  j=mrstrt[i];
+#endif
+	}
+      }
+      eta_next[last]=nrow+1;
+      eta_last[nrow+1]=last;
+      eta_next[nrow+1]=nrow+2;
+      c_ekkscpy(nrow, &temp[1], &mrstrt[1]);
+      c_ekkscpy(nrow, &temp2[1], &hinrow[1]);
+      i=eta_last[nrow+1];
+      ninbas=mrstrt[i]+hinrow[i]-1;
+#ifdef DEBUG
+      if (spareSpace<ninbas) {
+        abort();
+      }
+#endif
+      c_ekkizero( nrow, &hincol[1]);
+#ifdef DEBUG
+      for (i=nrow; i>0; i--) {
+	int krs = mrstrt[i];
+	int jpiv = hcoli[krs];
+	if (ihlink[jpiv]!=i) abort();
+      }
+#endif
+      for (i = 1; i <= ninbas; ++i) {
+	k = hcoli[i];
+	k = ihlink[k];
+#ifdef DEBUG
+        if (k<=0||k>nrow) abort();
+#endif
+	hcoli[i]=k;
+	hincol[k]++;
+      }
+#ifdef DEBUG
+      for (i=nrow; i>0; i--) {
+	int krs = mrstrt[i];
+	int jpiv = hcoli[krs];
+	if (jpiv!=i) abort();
+	if (krs>ninbas) abort();
+      }
+#endif
+      /*       Sort into column order as was stored by row */
+      k = 1;
+      /*        Position */
+      for (kk = 1; kk <= nrow; ++kk) {
+	nel=hincol[kk];
+        mcstrt[kk] = k;
+	hrowi[k]=nel-1;
+        k += hincol[kk];
+	hincol[kk]=0;
+      }
+      if (de2val) {
+	dluval2=de2val;
+      } else {
+	dluval2=dluval+ninbas;
+      }
+      nnentu = k-1;
+      mcstrt[nrow + 4] = nnentu + 1;
+      /* create column copy */
+      for (i=nrow; i>0; i--) {
+	int krs = mrstrt[i];
+	int kre = krs + hinrow[i];
+	hinrow[i]--;
+	mrstrt[i]++;
+        {
+	  int kx = mcstrt[i];
+	  /*nel = hincol[i];
+	    if (hrowi[kx]!=nel) abort();
+	    hrowi[kx] = nel-1;*/
+	  dluval2[kx] = 1.0 /dluval[krs];
+	  /*hincol[i]=0;*/
+	  for (kk = krs + 1; kk < kre; ++kk) {
+	    int j = hcoli[kk];
+	    int iput = hincol[j]+1;
+	    hincol[j]=iput;
+	    iput+= mcstrt[j];
+	    hrowi[iput] = SHIFT_INDEX(i);
+	    dluval2[iput] = dluval[kk];
+	  }
+	}
+      }
+      if (de2val) {
+	double * a=dluval;
+	double * address;
+	/* move first down */
+	i=eta_next[0];
+	{
+	  int krs=mrstrt[i];
+	  nel=hinrow[i];
+	  for (j=1;j<=nel;j++) {
+	    hcoli[j]=hcoli[j+krs-1];
+	    dluval[j]=dluval[j+krs-1];
+	  }
+	}
+	mrstrt[i]=1;
+	/****** swap dluval and de2val !!!! ******/
+	/* should work even for dspace */
+	/* move L part across */
+	address=fact->xeeadr+1;
+	fact->xeeadr=fact->xe2adr-1;
+	fact->xe2adr=address;
+	if (nnentl) {
+	  int n=xnetal-nrow-maxinv-5;
+	  int j1,j2;
+	  int * mcstrt2=mcstrt+nrow+maxinv+4;
+	  j2 = mcstrt2[1];
+	  j1 = mcstrt2[n+1]+1;
+#if 0
+	  memcpy(de2val+j1,dluval+j1,(j2-j1+1)*sizeof(double));
+#else
+	  c_ekkdcpy(j2-j1+1,
+		  (dluval+j1),(de2val+j1));
+#endif
+	}
+	dluval = de2val; 
+	de2val = a;
+      } else {
+	/* copy down dluval */
+#if 0
+	memcpy(&dluval[1],&dluval2[1],ninbas*sizeof(double));
+#else
+	c_ekkdcpy(ninbas,
+		(dluval2+1),(dluval+1));
+#endif
+      }
+      /* sort dense part */
+      for (i=nrow-ndenuc+1;i<=nrow;i++) {
+	int kx = mcstrt[i]+1;
+	int nel = hincol[i];
+	c_ekk_sort2(&hrowi[kx],&dluval[kx],nel);
+      }
+    }
+    mrstrt[nrow + 1] = ilast + 1;
+  }
+  /* Find first non slack */
+  for (i = 1; i <= nrow; ++i) {
+    int kcs = mcstrt[i];
+    if (hincol[i] != 0 || dluval[kcs] != SLACK_VALUE) {
+      break;
+    }
+  }
+  numberSlacks = i - 1;
+  {
+    /* set slacks to 1 */
+    int * array = fact->krpadr + ( fact->nrowmx+2);
+    int nSet = (numberSlacks)>>5;
+    int n2 = (fact->nrowmx+32)>>5;
+    int i;
+    memset(array,0xff,nSet*sizeof(int));
+    memset(array+nSet,0,(n2-nSet)*sizeof(int));
+    for (i=nSet<<5;i<=numberSlacks;i++)
+      c_ekk_Set(array,i);
+    c_ekk_Unset(array,fact->nrow+1); /* make sure off end not slack */
+#ifndef NDEBUG
+    for (i=1;i<=numberSlacks;i++)
+      assert (c_ekk_IsSet(array,i));
+    for (;i<=fact->nrow;i++)
+      assert (!c_ekk_IsSet(array,i));
+#endif
+  }
+  
+  /* and set up backward pointers */
+  /* clean up HPIVCO for fancy assembler stuff */
+  /* xnetal was initialized to nrow + maxinv + 4 in c_ekktria, and grows */
+  c_ekkscpy_0_1(maxinv + 1, 1, &hpivco[nrow+4]);	/* magic */
+  
+  hpivco[xnetal] = 1;
+  /* shuffle down for gaps so can get rid of hpivco for L */
+  {
+    const int lstart	= nrow + maxinv + 5;
+    int n=xnetal-lstart ;	/* number of L entries */
+    int add,iel;
+    int * hpivco_L = &hpivco[lstart];
+    int * mcstrt_L = &mcstrt[lstart];
+    if (nnentl) {
+      /* elements of L were stored in descending order in dluval/hcoli */
+      int kle = mcstrt_L[0];
+      int kls = mcstrt_L[n]+1;
+      
+      if(if_sparse_update) {
+	int i2,iel;
+	int * mrstrt2 = &mrstrt[nrow];
+	
+	/* need row copy of L */
+	/* hpivro is spare for counts; just used as a temp buffer */
+	c_ekkizero( nrow, &hpivro[1]);
+	
+	/* permute L indices; count L row lengths */
+	for (iel = kls; iel <= kle; ++iel) {
+	  int jrow = mpermu[UNSHIFT_INDEX(hrowi[iel])];
+	  hpivro[jrow]++;
+	  hrowi[iel] = SHIFT_INDEX(jrow);
+	}
+	{
+	  int ibase=nnetas-nnentl+1;
+	  int firstDoRow=0;
+	  for (i=1;i<=nrow;i++) {
+	    mrstrt2[i]=ibase;
+	    if (hpivro[i]&&!firstDoRow) {
+	      firstDoRow=i;
+	    }
+	    ibase+=hpivro[i];
+	    hpivro[i]=mrstrt2[i];
+	  }
+	  if (!firstDoRow) {
+	    firstDoRow=nrow+1;
+	  }
+	  mrstrt2[i]=ibase;
+	  fact->firstDoRow = firstDoRow;
+	}
+	i2=mcstrt_L[n];
+	for (i = n-1; i >= 0; --i) {
+	  int i1 = mcstrt_L[i];
+	  int ipiv=hpivco_L[i];
+	  ipiv=mpermu[ipiv];
+	  hpivco_L[i]=ipiv;
+	  for (iel=i2 ; iel < i1; iel++) {
+	    int irow = UNSHIFT_INDEX(hrowi[iel+1]);
+	    int iput=hpivro[irow];
+	    hpivro[irow]=iput+1;
+	    hcoli[iput]=ipiv;
+	    de2val[iput]=dluval[iel+1];
+	  }
+	  i2=i1;
+	}
+      } else {
+	/* just permute row numbers */
+	
+	for (j = 0; j < n; ++j) {
+	  hpivco_L[j] = mpermu[hpivco_L[j]];
+	}
+	for (iel = kls; iel <= kle; ++iel) {
+	  int jrow = mpermu[UNSHIFT_INDEX(hrowi[iel])];
+	  hrowi[iel] = SHIFT_INDEX(jrow);
+	}
+      }
+      
+      add=hpivco_L[n-1]-hpivco_L[0]-n+1;
+      if (add) {
+	int i;
+	int last = hpivco_L[n-1];
+	int laststart = mcstrt_L[n];
+	int base=hpivco_L[0]-1;
+	/* adjust so numbers match */
+	mcstrt_L-=base;
+	hpivco_L-=base;
+	mcstrt_L[last]=laststart;
+	for (i=n-1;i>=0;i--) {
+	  int ipiv=hpivco_L[i+base];
+	  while (ipiv<last) {
+	    mcstrt_L[last-1]=laststart;
+	    hpivco_L[last-1]=last;
+	    last--;
+	  }
+	  laststart=mcstrt_L[i+base];
+	  mcstrt_L[last-1]=laststart;
+	  hpivco_L[last-1]=last;
+	  last--;
+	}
+	xnetal+=add;
+      }
+    }
+    //int lstart=fact->lstart;
+    //const int * COIN_RESTRICT hpivco	= fact->kcpadr;
+    fact->firstLRow = hpivco[lstart];
+  }
+  fact->nnentu = nnentu;
+  fact->xnetal = xnetal;
+  /* now we have xnetal * we can set up pointers */
+  clp_setup_pointers(fact);
+  
+  /* this is the array used in c_ekkbtrn; it is passed to c_ekkbtju as hpivco.
+   * this gets modified by F-T as we pivot columns in and out.
+   */
+  {
+    /* do new hpivco */
+    int * hpivco_new = fact->kcpadr+1;
+    int * back = &fact->kcpadr[2*nrow+maxinv+4];
+    /* set zeroth to stop illegal read */
+    back[0]=1;
+    
+    hpivco_new[nrow+1]=nrow+1; /* deliberate loop for dense tests */
+    hpivco_new[0]=1;
+    
+    for (i=1;i<=nrow;i++) {
+      hpivco_new[i]=i+1;
+      back[i+1]=i;
+    }
+    back[1]=0;
+    
+    fact->first_dense = CoinMax(fact->first_dense,4);
+    fact->numberSlacks=numberSlacks;
+    fact->lastSlack=numberSlacks;
+    fact->firstNonSlack=hpivco_new[numberSlacks];
+  }
+  
+  /* also zero out permute region and nonzero */
+  c_ekkdzero( nrow, (dpermu+1));
+  
+  if (if_sparse_update) {
+    char * nonzero = reinterpret_cast<char *> (&mpermu[nrow+1]);	/* used in c_ekkbtrn */
+    /*c_ekkizero(nrow,(int *)nonzero);*/
+    c_ekkczero(nrow,nonzero);
+    /*memset(nonzero,0,nrow*sizeof(int));*/ /* for faster method */
+  }
+  for (i = 1; i <= nrow; ++i) {
+    hpivro[mpermu[i]] = i;
+  }
+  
+} /* c_ekkshfv */
+
+
+static void c_ekkclcp1(const int *hcol, const int * mrstrt,
+		     int *hrow, int *mcstrt,
+		     int *hincol, int nnrow, int nncol,
+		     int ninbas)
+{
+  int i, j, kc, kr, kre, krs, icol; 
+  int iput;
+  
+  /* Create columnwise storage of row indices */
+  
+  kc = 1;
+  for (j = 1; j <= nncol; ++j) {
+    mcstrt[j] = kc;
+    kc += hincol[j];
+    hincol[j] = 0;
+  }
+  mcstrt[nncol + 1] = ninbas + 1;
+  
+  for (i = 1; i <= nnrow; ++i) {
+    krs = mrstrt[i];
+    kre = mrstrt[i + 1] - 1;
+    for (kr = krs; kr <= kre; ++kr) {
+      icol = hcol[kr];
+      iput = hincol[icol];
+      hincol[icol] = iput + 1;
+      iput += mcstrt[icol];
+      hrow[iput] = i;
+    }
+  }
+} /* c_ekkclcp */
+inline void c_ekkclcp2(const int *hcol, const double *dels, const int * mrstrt,
+		     int *hrow, double *dels2, int *mcstrt,
+		     int *hincol, int nnrow, int nncol,
+		     int ninbas)
+{
+  int i, j, kc, kr, kre, krs, icol; 
+  int iput;
+  
+  /* Create columnwise storage of row indices */
+  
+  kc = 1;
+  for (j = 1; j <= nncol; ++j) {
+    mcstrt[j] = kc;
+    kc += hincol[j];
+    hincol[j] = 0;
+  }
+  mcstrt[nncol + 1] = ninbas + 1;
+  
+  for (i = 1; i <= nnrow; ++i) {
+    krs = mrstrt[i];
+    kre = mrstrt[i + 1] - 1;
+    for (kr = krs; kr <= kre; ++kr) {
+      icol = hcol[kr];
+      iput = hincol[icol];
+      hincol[icol] = iput + 1;
+      iput += mcstrt[icol];
+      hrow[iput] = i;
+      dels2[iput] = dels[kr];
+    }
+  }
+} /* c_ekkclcp */
+int c_ekkslcf( register const EKKfactinfo *fact)
+{
+  int * hrow = fact->xeradr;
+  int * hcol = fact->xecadr;
+  double * dels = fact->xeeadr;
+  int * hinrow = fact->xrnadr;
+  int * hincol = fact->xcnadr;
+  int * mrstrt = fact->xrsadr;
+  int * mcstrt = fact->xcsadr;
+  const int nrow = fact->nrow;
+  int ninbas;
+  /* space for etas */
+  const int nnetas	= fact->nnetas;
+  ninbas=mcstrt[nrow+1]-1;
+  
+  /* Now sort */
+  if (ninbas << 1 > nnetas) {
+    /* Put it in row order */
+    int i,k;
+    c_ekkrowq(hrow, hcol, dels, mrstrt, hinrow, nrow, ninbas);
+    k = 1;
+    for (i = 1; i <= nrow; ++i) {
+      mrstrt[i] = k;
+      k += hinrow[i];
+    }
+    mrstrt[nrow + 1] = k;
+    
+    /* make a column copy without the extra values */
+    c_ekkclcp1(hcol, mrstrt, hrow, mcstrt, hincol, nrow, nrow, ninbas); 
+  } else {
+    /* Move elements up memory */
+    c_ekkdcpy(ninbas,
+	    (dels+1), (dels+ninbas + 1));
+    
+    /* make a row copy with the extra values */
+    c_ekkclcp2(hrow, &dels[ninbas], mcstrt, hcol, dels, mrstrt, hinrow, nrow, nrow, ninbas); 
+  }
+  return (ninbas);
+} /* c_ekkslcf */
+/*     Uwe H. Suhl, September 1986 */
+/*     Removes lower and upper triangular factors from the matrix. */
+/*     Code for routine: 102 */
+/*     Return codes: */
+/*	0: ok */
+/*      -5: not enough space in row file */
+/*      7: pivot too small - col sing */
+/*
+ * This selects singleton columns and rows for the LU factorization.
+ * Singleton columns require no 
+ *
+ * (1) Note that columns are processed using a queue, not a stack;
+ * this produces better pivots.
+ *
+ * (2) At most nrows elements are ever entered into the queue.
+ *
+ * (3) When pivoting singleton columns, every column that is part of
+ * the pivot row is shortened by one, including the singleton column
+ * itself; the hincol entries are updated appropriately.
+ * Thus, pivoting on a singleton column may create other singleton columns
+ * (but not singleton rows).
+ * The dual property is true for rows.
+ *
+ * (4) Row entries (hrowi) are not changed when pivoting singleton columns.
+ * Singleton columns that are created as a result of pivoting the
+ * rows of other singleton columns will therefore have row entries
+ * corresponding to those pivoted rows.  Since we need to find the
+ * row entry for the row being pivoted, we have to
+ * search its row entries for the one whose hlink entry indicates
+ * that it has not yet been pivoted.
+ *
+ * (9) As a result of pivoting columns, sections in hrowi corresponding to
+ * pivoted columns are no longer needed, and entries in sections
+ * for non-pivoted columns may have entries corresponding to pivoted rows.
+ * This is why hrowi needs to be compacted.
+ *
+ * (5) When the row_pre and col_pre fields of the hlink struct contain
+ * negative values, they indicate that the row has been pivoted, and
+ * the negative of that value is the pivot order.
+ * That is the only use for these fields in this routine.
+ *
+ * (6) This routine assumes that hlink is initialized to zeroes.
+ * Under this assumption, the following is an invariant in this routine:
+ *
+ *	(clink[i].pre < 0) ==> (hincol[i]==0)
+ *
+ * The converse is not true; see (15).
+ *
+ * The dual is also true, but only while pivoting singletong rows,
+ * since we don't update hinrow while pivoting columns;
+ * THESE VALUES ARE USED LATER, BUT I DON'T UNDERSTAND HOW YET.
+ *
+ * (7) hpivco is used for two purposes.  The low end is used to implement the
+ * queue when pivoting columns; the high end is used to hold eta-matrix
+ * entries. 
+ *
+ * (8) As a result of pivoting columns, for all i:1<=i<=nrow, either
+ *	hinrow[i] has not changed
+ * or
+ *	hinrow[i] = 0
+ * This is another way of saying that pivoting singleton columns cannot
+ * create singleton rows.
+ * The dual holds for hincol after pivoting rows.
+ *
+ * (10) In constrast to (4), while pivoting rows we
+ * do not let the hcoli get out-of-date.  That is because as part of
+ * the process of numerical pivoting we have to find the row entries
+ * for all the rows in the pivot column, so we may as well keep the
+ * entries up to date.  This is done by moving the last column entry
+ * for each row into the entry that was used for the pivot column.
+ *
+ * (11) When pivoting a column, we must find the pivot row entry in
+ * its row table.  Sometimes we search for other things at the same time.
+ * The same is true for pivoting columns.  This search should never
+ * fail.
+ *
+ * (12) Information concerning the eta matrices is stored in the high
+ * ends of arrays that are also used to store information concerning
+ * the basis; these arrays are: hpivco, mcstrt, dluval and hcoli.
+ * Information is only stored in these arrays as a part of pivoting
+ * singleton rows, since the only thing that needs to be saved as
+ * a part of pivoting singleton columns is which rows and columns were chosen,
+ * and this is stored in hlink.
+ * Since they have to share the same array, the eta information grows
+ * downward instead of upward. Eventually, eta information may grow
+ * down to the top of the basis information.  As pivoting proceeds,
+ * more and more of this information is no longer needed, so when this
+ * happens we can try compacting the arrays to see if we can recover
+ * enough space.  lstart points at the bottom entry in the arrays,
+ * xnewro/xnewco at the top of the basis information, and each time we
+ * pivot a singleton row we know that we will need exactly as many new
+ * entries as there are rows in the pivot column, so we can easily
+ * determine if we need more room.  The variable maxinv may be used
+ * to reserve extra room when inversion starts.
+ *
+ * (13) Eta information is stored in a fashion that is similar to how
+ * matrices are stored.  There is one entry in hpivco and mcstrt for
+ * each eta (other than the initial ones for singleton columns and
+ * for singleton rows that turn out to be singleton columns),
+ * in the order they were chosen.  hpivco records the pivot row,
+ * and mcstrt points at the first entry in the other two arrays
+ * for this row.  dluval contains the actual eta values for the column,
+ * and hcoli the rows these values were in.
+ * These entries in mcstrt and hpivco grow upward; they start above
+ * the entries used to store basis information.
+ * (Actually, I don't see why they need to start maxinv+4 entries past the top).
+ *
+ * (14) c_ekkrwco assumes that invalidated hrowi/hcoli entries contain 0.
+ *
+ * (15) When pivoting singleton columns, it may possibly happen
+ * that a row with all singleton column entries is created.
+ * In this case, all of the columns will be enqueued, and pivoting
+ * on any of them eliminates the rest, without their being chosen
+ * as pivots.  The dual holds for singleton rows.
+ * DOES THIS INDICATE A SINGULARITY?
+ *
+ * (15) There are some aspects of the implementation that I find odd.
+ * hrowi is not set to 0 for pivot rows while pivoting singleton columns,
+ * which would make sense to me.  Things don't work if this isn't done,
+ * so the information is used somehow later on.  Also, the information
+ * for the pivot column is shifted to the front of the pivot row
+ * when pivoting singleton columns; this is also necessary for reasons
+ * I don't understand.
+ */
+int c_ekktria(EKKfactinfo *fact,
+	      EKKHlink * rlink,
+	      EKKHlink * clink,
+	    int *nsingp, 
+	    int *xnewcop, int *xnewrop,
+	    int *ncompactionsp,
+	    const int ninbas)
+{
+  const int nrow	= fact->nrow;
+  const int maxinv	= fact->maxinv;
+  int *hcoli	= fact->xecadr;
+  double *dluval	= fact->xeeadr;
+  int *mrstrt	= fact->xrsadr;
+  int *hrowi	= fact->xeradr;
+  int *mcstrt	= fact->xcsadr;
+  int *hinrow	= fact->xrnadr;
+  int *hincol	= fact->xcnadr;
+  int *stack	= fact->krpadr; /* normally hpivro */
+  int *hpivco	= fact->kcpadr;
+  const double drtpiv	= fact->drtpiv;
+  CoinZeroN(reinterpret_cast<int *>(rlink+1),static_cast<int>(nrow*(sizeof(EKKHlink)/sizeof(int))));
+  CoinZeroN(reinterpret_cast<int *>(clink+1),static_cast<int>(nrow*(sizeof(EKKHlink)/sizeof(int))));
+  
+  fact->npivots	= 0;
+  /*      Use NUSPIK to keep sum of deactivated row counts */
+  fact->nuspike	= 0;
+  int xnetal	= nrow + maxinv + 4;
+  int xnewro	= mrstrt[nrow] + hinrow[nrow] - 1;
+  int xnewco	= xnewro;
+  int kmxeta	= ninbas;
+  int ncompactions	= 0;
+  
+  int i, j, k, kc, kce, kcs, npr;
+  double pivot;
+  int kipis, kipie, kjpis, kjpie, knprs, knpre;
+  int ipivot, jpivot, stackc, stackr;
+#ifndef NDEBUG
+  int kpivot=-1;
+#else
+  int kpivot=-1;
+#endif
+  int epivco, kstart, maxstk;
+  int irtcod = 0;
+  int lastSlack=0;
+  
+  int lstart = fact->nnetas + 1;
+  /*int nnentu	= ninbas; */
+  int lstart_minus_nnentu=lstart-ninbas;
+  /* do initial column singletons - as can do faster */
+  for (jpivot = 1; jpivot <= nrow; ++jpivot) {
+    if (hincol[jpivot] == 1) {
+      ipivot = hrowi[mcstrt[jpivot]];
+      if (ipivot>lastSlack) {
+	lastSlack=ipivot;
+      } else {
+        /* so we can't put a structural over a slack */
+	break;
+      }
+      kipis = mrstrt[ipivot];
+#if 1
+      assert (hcoli[kipis]==jpivot);
+#else
+      if (hcoli[kipis]!=jpivot) {
+	kpivot=kipis+1;
+	while(hcoli[kpivot]!=jpivot) kpivot++;
+#ifdef DEBUG
+	kipie = kipis + hinrow[ipivot] ;
+	if (kpivot>=kipie) {
+	  abort();
+	}
+#endif
+        pivot=dluval[kpivot];
+	dluval[kpivot] = dluval[kipis];
+	dluval[kipis] = pivot;
+	hcoli[kpivot] = hcoli[kipis];
+	hcoli[kipis] = jpivot;
+      }
+#endif
+      if (dluval[kipis]==SLACK_VALUE) {
+	/* record the new pivot row and column */
+	++fact->npivots;
+	rlink[ipivot].pre = -fact->npivots;
+	clink[jpivot].pre = -fact->npivots;
+	hincol[jpivot]=0;
+	fact->nuspike += hinrow[ipivot];
+      } else {
+	break;
+      }
+    } else {
+      break;
+    }
+  }
+  /* Fill queue with other column singletons and clean up */
+  maxstk = 0;
+  for (j = 1; j <= nrow; ++j) {
+    if (hincol[j]) {
+      int n=0;
+      kcs = mcstrt[j];
+      kce = mcstrt[j + 1];
+      for (k = kcs; k < kce; ++k) {
+	if (! (rlink[hrowi[k]].pre < 0)) {
+	  n++;
+	}
+      }
+      hincol[j] = n;
+      if (n == 1) {
+	/* we just created a new singleton column - enqueue it */
+	++maxstk;
+	stack[maxstk] = j;
+      }
+    }
+  }
+  stackc = 0; /* (1) */
+  
+  while (! (stackc >= maxstk)) {	/* (1) */
+    /* dequeue the next entry */
+    ++stackc;
+    jpivot = stack[stackc];
+    
+    /* (15) */
+    if (hincol[jpivot] != 0) {
+      
+      for (k = mcstrt[jpivot]; rlink[hrowi[k]].pre < 0; k++) {
+	/* (4) */
+      }
+      ipivot = hrowi[k];
+      
+      /* All the columns in this row are being shortened. */
+      kipis = mrstrt[ipivot];
+      kipie = kipis + hinrow[ipivot] ;
+      for (k = kipis; k < kipie; ++k) {
+	j = hcoli[k];
+	--hincol[j];	/* (3) (6) */
+	
+	if (j == jpivot) {
+	  kpivot = k;		/* (11) */
+	} else if (hincol[j] == 1) {
+	  /* we just created a new singleton column - enqueue it */
+	  ++maxstk;
+	  stack[maxstk] = j;
+	}
+      }
+      
+      /* record the new pivot row and column */
+      ++fact->npivots;
+      rlink[ipivot].pre = -fact->npivots;
+      clink[jpivot].pre = -fact->npivots;
+      
+      fact->nuspike += hinrow[ipivot];
+      
+      /* check the pivot */
+      assert (kpivot>0);
+      pivot = dluval[kpivot];
+      if (fabs(pivot) < drtpiv) {
+	irtcod = 7;
+	++(*nsingp);
+	rlink[ipivot].pre = -nrow - 1;
+	clink[jpivot].pre = -nrow - 1;
+      }
+      
+      /* swap the pivot column entry with the first one. */
+      /* I don't know why. */
+      dluval[kpivot] = dluval[kipis];
+      dluval[kipis] = pivot;
+      hcoli[kpivot] = hcoli[kipis];
+      hcoli[kipis] = jpivot;
+    }
+  }
+  /* (8) */
+  
+  /* The entire basis may already be triangular */
+  if (fact->npivots < nrow) {
+    
+    /* (9) */
+    kstart = 0;
+    for (j = 1; j <= nrow; ++j) {
+      if (! (clink[j].pre < 0)) {
+	kcs = mcstrt[j];
+	kce = mcstrt[j + 1];
+	
+	mcstrt[j] = kstart + 1;
+	
+	for (k = kcs; k < kce; ++k) {
+	  if (! (rlink[hrowi[k]].pre < 0)) {
+	    ++kstart;
+	    hrowi[kstart] = hrowi[k];
+	  }
+	}
+	hincol[j] = kstart - mcstrt[j] + 1;
+      }
+    }
+    xnewco = kstart;
+    
+    
+    /* Fill stack with initial row singletons that haven't been pivoted away */
+    stackr = 0;
+    for (i = 1; i <= nrow; ++i) {
+      if (! (rlink[i].pre < 0) &&
+	  (hinrow[i] == 1)) {
+	++stackr;
+	stack[stackr] = i;
+      }
+    }
+    
+    while (! (stackr <= 0)) {
+      ipivot = stack[stackr];
+      assert (ipivot);
+      --stackr;
+      
+#if 1
+      assert (rlink[ipivot].pre>=0);
+#else
+      /* This test is probably unnecessary:  rlink[i].pre < 0 ==> hinrow[i]==0 */
+      if (rlink[ipivot].pre < 0) {
+	continue;
+      }
+#endif
+      
+      /* (15) */
+      if (hinrow[ipivot] != 0) {
+	
+	/* This is a singleton row, which means it has exactly one column */
+	jpivot = hcoli[mrstrt[ipivot]];
+	
+	kjpis = mcstrt[jpivot];
+	epivco = hincol[jpivot] - 1;
+	hincol[jpivot] = 0;	/* this column is being pivoted away */
+	
+	/* (11) */
+	kjpie = kjpis + epivco;
+	for (k = kjpis; k <= kjpie; ++k) {
+	  if (ipivot == hrowi[k])
+	    break;
+	}
+	/* ASSERT (k <= kjpie) */
+	
+	/* move the last row entry for the pivot column into the pivot row's entry */
+	/* I don't know why */
+	hrowi[k] = hrowi[kjpie];
+	
+	/* invalidate the (old) last row entry of the pivot column */
+	/* I don't know why */
+	hrowi[kjpie] = 0;
+	
+	/* (12) */
+	if (! (xnewro + epivco < lstart)) {
+	  int kstart;
+	  
+	  if (! (epivco < lstart_minus_nnentu)) {
+	    irtcod = -5;
+	    break;
+	  }
+	  kstart = c_ekkrwco(fact,dluval, hcoli, mrstrt, hinrow, xnewro);
+	  ++ncompactions;
+	  kmxeta += (xnewro - kstart) << 1;
+	  xnewro = kstart;
+	}
+	if (! (xnewco + epivco < lstart)) {
+	  if (! (epivco < lstart_minus_nnentu)) {
+	    irtcod = -5;
+	    break;
+	  }
+	  xnewco = c_ekkclco(fact,hrowi, mcstrt, hincol, xnewco);
+	  ++ncompactions;
+	  
+	  /*     HINCOL MAY HAVE CHANGED ??? (JJHF) */
+	  epivco = hincol[jpivot];
+	}
+	
+	/* record the new pivot row and column */
+	++fact->npivots;
+	rlink[ipivot].pre = -fact->npivots;
+	clink[jpivot].pre = -fact->npivots;
+	
+	/* no update for nuspik */
+	
+	/* check the pivot */
+	pivot = dluval[mrstrt[ipivot]];
+	if (fabs(pivot) < drtpiv) {
+	  /* If the pivot is too small, reject it, but keep going */
+	  irtcod = 7;
+	  rlink[ipivot].pre = -nrow - 1;
+	  clink[jpivot].pre = -nrow - 1;
+	}
+	
+	/* Perform numerical part of elimination. */
+	if (! (epivco <= 0)) {
+	  ++xnetal;
+	  mcstrt[xnetal] = lstart - 1;
+	  hpivco[xnetal] = ipivot;
+	  pivot = -1.f / pivot;
+	  
+	  kcs = mcstrt[jpivot];
+	  kce = kcs + epivco - 1;
+	  hincol[jpivot] = 0;
+	  
+	  for (kc = kcs; kc <= kce; ++kc) {
+	    npr = hrowi[kc];
+	    
+	    /* why bother? */
+	    hrowi[kc] = 0;
+	    
+	    --hinrow[npr];	/* (3) */
+	    if (hinrow[npr] == 1) {
+	      /* this may create new singleton rows */
+	      ++stackr;
+	      stack[stackr] = npr;
+	    }
+	    
+	    /* (11) */
+	    knprs = mrstrt[npr];
+	    knpre = knprs + hinrow[npr];
+	    for (k = knprs; k <= knpre; ++k) {
+	      if (jpivot == hcoli[k]) {
+		kpivot = k;
+		break;
+	      }
+	    }
+	    /* ASSERT (kpivot <= knpre) */
+	    
+	    {
+	      /* (10) */
+	      double elemnt = dluval[kpivot];
+	      dluval[kpivot] = dluval[knpre];
+	      hcoli[kpivot] = hcoli[knpre];
+	      
+	      hcoli[knpre] = 0;	/* (14) */
+	      
+	      /* store elementary row transformation */
+	      --lstart;
+	      dluval[lstart] = elemnt * pivot;
+	      hcoli[lstart] = npr;
+	    }
+	  }
+	}
+      }
+    }
+  }
+  /* (8) */
+  
+  *xnewcop = xnewco;
+  *xnewrop = xnewro;
+  fact->xnetal = xnetal;
+  fact->nnentu = lstart - lstart_minus_nnentu;
+  fact->kmxeta = kmxeta;
+  *ncompactionsp = ncompactions;
+  
+  return (irtcod);
+} /* c_ekktria */
diff --git a/cbits/coin/CoinPackedMatrix.cpp b/cbits/coin/CoinPackedMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPackedMatrix.cpp
@@ -0,0 +1,3800 @@
+/* $Id: CoinPackedMatrix.cpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinUtilsConfig.h"
+
+#include <algorithm>
+#include <numeric>
+#include <cassert>
+#include <cstdio>
+#include <cmath>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinSort.hpp"
+#include "CoinHelperFunctions.hpp"
+#ifndef CLP_NO_VECTOR
+#include "CoinPackedVectorBase.hpp"
+#endif
+#include "CoinFloatEqual.hpp"
+#include "CoinPackedMatrix.hpp"
+
+#if !defined(COIN_COINUTILS_CHECKLEVEL)
+#define COIN_COINUTILS_CHECKLEVEL 0
+#endif
+
+//#############################################################################
+// T must be an integral type (int, CoinBigIndex, etc.)
+template <typename T>
+static inline T
+CoinLengthWithExtra(T len, double extraGap)
+{
+  return static_cast<T>(ceil(len * (1 + extraGap)));
+}
+
+//#############################################################################
+
+static inline void
+CoinTestSortedIndexSet(const int num, const int * sorted, const int maxEntry,
+		      const char * testingMethod)
+{
+   if (sorted[0] < 0 || sorted[num-1] >= maxEntry)
+      throw CoinError("bad index", testingMethod, "CoinPackedMatrix");
+   if (std::adjacent_find(sorted, sorted + num) != sorted + num)
+      throw CoinError("duplicate index", testingMethod, "CoinPackedMatrix");
+}
+
+//-----------------------------------------------------------------------------
+
+static inline int *
+CoinTestIndexSet(const int numDel, const int * indDel, const int maxEntry,
+		const char * testingMethod)
+{
+   if (! CoinIsSorted(indDel, indDel + numDel)) {
+      // if not sorted then sort it, test for consistency and return a pointer
+      // to the sorted array
+      int * sorted = new int[numDel];
+      CoinMemcpyN(indDel, numDel, sorted);
+      std::sort(sorted, sorted + numDel);
+      CoinTestSortedIndexSet(numDel, sorted, maxEntry, testingMethod);
+      return sorted;
+   }
+
+   // Otherwise it's already sorted, so just test for consistency and return a
+   // 0 pointer.
+   CoinTestSortedIndexSet(numDel, indDel, maxEntry, testingMethod);
+   return 0;
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::reserve(const int newMaxMajorDim, const CoinBigIndex newMaxSize,
+			  bool create)
+{
+   if (newMaxMajorDim > maxMajorDim_) {
+      maxMajorDim_ = newMaxMajorDim;
+      int * oldlength = length_;
+      CoinBigIndex * oldstart = start_;
+      length_ = new int[newMaxMajorDim];
+      start_ = new CoinBigIndex[newMaxMajorDim+1];
+      start_[0]=0;
+      if (majorDim_ > 0) {
+	 CoinMemcpyN(oldlength, majorDim_, length_);
+	 CoinMemcpyN(oldstart, majorDim_ + 1, start_);
+      }
+      if (create) {
+	// create empty vectors
+	CoinFillN(length_+majorDim_,maxMajorDim_-majorDim_,0);
+	CoinFillN(start_+majorDim_+1,maxMajorDim_-majorDim_,0);
+	majorDim_=maxMajorDim_;
+      }
+      delete[] oldlength;
+      delete[] oldstart;
+   }
+   if (newMaxSize > maxSize_) {
+      maxSize_ = newMaxSize;
+      int * oldind = index_;
+      double * oldelem = element_;
+      index_ = new int[newMaxSize];
+      element_ = new double[newMaxSize];
+      for (int i = majorDim_ - 1; i >= 0; --i) {
+	 CoinMemcpyN(oldind+start_[i], length_[i], index_+start_[i]);
+	 CoinMemcpyN(oldelem+start_[i], length_[i], element_+start_[i]);
+      }
+      delete[] oldind;
+      delete[] oldelem;
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::clear()
+{
+   majorDim_ = 0;
+   minorDim_ = 0;
+   size_ = 0;
+}
+
+//#############################################################################
+//#############################################################################
+
+void
+CoinPackedMatrix::setDimensions(int newnumrows, int newnumcols)
+{
+  const int numrows = getNumRows();
+  if (newnumrows < 0)
+    newnumrows = numrows;
+  if (newnumrows < numrows)
+    throw CoinError("Bad new rownum (less than current)",
+		    "setDimensions", "CoinPackedMatrix");
+
+  const int numcols = getNumCols();
+  if (newnumcols < 0)
+    newnumcols = numcols;
+  if (newnumcols < numcols)
+    throw CoinError("Bad new colnum (less than current)",
+		    "setDimensions", "CoinPackedMatrix");
+
+  int numplus = 0;
+  if (isColOrdered()) {
+    minorDim_ = newnumrows;
+    numplus = newnumcols - numcols;
+  } else {
+    minorDim_ = newnumcols;
+    numplus = newnumrows - numrows;
+  }
+  if (numplus > 0) {
+    int* lengths = new int[numplus];
+    CoinZeroN(lengths, numplus);
+    resizeForAddingMajorVectors(numplus, lengths);
+    delete[] lengths;
+    majorDim_ += numplus; //forgot to change majorDim_
+  }
+
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::setExtraGap(const double newGap)
+{
+   if (newGap < 0)
+      throw CoinError("negative new extra gap",
+		     "setExtraGap", "CoinPackedMatrix");
+   extraGap_ = newGap;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::setExtraMajor(const double newMajor)
+{
+   if (newMajor < 0)
+      throw CoinError("negative new extra major",
+		     "setExtraMajor", "CoinPackedMatrix");
+   extraMajor_ = newMajor;
+}
+
+//#############################################################################
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::appendCol(const CoinPackedVectorBase& vec)
+{
+   if (colOrdered_)
+      appendMajorVector(vec);
+   else
+      appendMinorVector(vec);
+}
+#endif
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::appendCol(const int vecsize,
+			   const int *vecind,
+			   const double *vecelem)
+{
+   if (colOrdered_)
+      appendMajorVector(vecsize, vecind, vecelem);
+   else
+      appendMinorVector(vecsize, vecind, vecelem);
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::appendCols(const int numcols,
+			    const CoinPackedVectorBase * const * cols)
+{
+   if (colOrdered_)
+      appendMajorVectors(numcols, cols);
+   else
+      appendMinorVectors(numcols, cols);
+}
+#endif
+//-----------------------------------------------------------------------------
+
+int 
+CoinPackedMatrix::appendCols(const int numcols,
+                             const CoinBigIndex * columnStarts, const int * row,
+                             const double * element, int numberRows)
+{
+  int numberErrors;
+  if (colOrdered_) {
+    numberErrors=appendMajor(numcols, columnStarts, row, element, numberRows);
+  } else {
+    numberErrors=appendMinor(numcols, columnStarts, row, element, numberRows);
+  }
+  return numberErrors;
+}
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::appendRow(const CoinPackedVectorBase& vec)
+{
+   if (colOrdered_)
+      appendMinorVector(vec);
+   else
+      appendMajorVector(vec);
+}
+#endif
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::appendRow(const int vecsize,
+			   const int *vecind,
+			   const double *vecelem)
+{
+   if (colOrdered_)
+      appendMinorVector(vecsize, vecind, vecelem);
+   else
+      appendMajorVector(vecsize, vecind, vecelem);
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::appendRows(const int numrows,
+			    const CoinPackedVectorBase * const * rows)
+{
+  if (colOrdered_) {
+    // make sure enough columns
+    if (numrows == 0)
+      return;
+
+    int i;
+    int maxDim=-1;
+    for (i = numrows - 1; i >= 0; --i) {
+      const int vecsize = rows[i]->getNumElements();
+      const int* vecind = rows[i]->getIndices();
+      for (int j = vecsize - 1; j >= 0; --j) 
+	maxDim = CoinMax(maxDim,vecind[j]);
+    }
+    maxDim++;
+    if (maxDim>majorDim_) {
+      setDimensions(minorDim_,maxDim);
+      //int nAdd=maxDim-majorDim_;
+      //int * length = new int[nAdd];
+      //memset(length,0,nAdd*sizeof(int));
+      //resizeForAddingMajorVectors(nAdd,length);
+      //delete [] length;
+    }
+    appendMinorVectors(numrows, rows);
+  } else {
+    appendMajorVectors(numrows, rows);
+  }
+}
+#endif
+//-----------------------------------------------------------------------------
+
+int 
+CoinPackedMatrix::appendRows(const int numrows,
+                             const CoinBigIndex * rowStarts, const int * column,
+                             const double * element, int numberColumns)
+{
+  int numberErrors;
+  if (colOrdered_) {
+    numberErrors=appendMinor(numrows, rowStarts, column, element, numberColumns);
+  } else {
+    numberErrors=appendMajor(numrows, rowStarts, column, element, numberColumns);
+  }
+  return numberErrors;
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::rightAppendPackedMatrix(const CoinPackedMatrix& matrix)
+{
+   if (colOrdered_) {
+      if (matrix.colOrdered_) {
+	 majorAppendSameOrdered(matrix);
+      } else {
+	 majorAppendOrthoOrdered(matrix);
+      }
+   } else {
+      if (matrix.colOrdered_) {
+	 minorAppendOrthoOrdered(matrix);
+      } else {
+	 minorAppendSameOrdered(matrix);
+      }
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::bottomAppendPackedMatrix(const CoinPackedMatrix& matrix)
+{
+   if (colOrdered_) {
+      if (matrix.colOrdered_) {
+	 minorAppendSameOrdered(matrix);
+      } else {
+	 minorAppendOrthoOrdered(matrix);
+      }
+   } else {
+      if (matrix.colOrdered_) {
+	 majorAppendOrthoOrdered(matrix);
+      } else {
+	 majorAppendSameOrdered(matrix);
+      }
+   }
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::deleteCols(const int numDel, const int * indDel)
+{
+  if (numDel) {
+    if (colOrdered_)
+      deleteMajorVectors(numDel, indDel);
+    else
+      deleteMinorVectors(numDel, indDel);
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::deleteRows(const int numDel, const int * indDel)
+{
+  if (numDel) {
+    if (colOrdered_)
+      deleteMinorVectors(numDel, indDel);
+    else
+      deleteMajorVectors(numDel, indDel);
+  }
+}
+
+//#############################################################################
+/* Replace the elements of a vector.  The indices remain the same.
+   At most the number specified will be replaced.
+   The index is between 0 and major dimension of matrix */
+void 
+CoinPackedMatrix::replaceVector(const int index,
+			       const int numReplace, 
+			       const double * newElements)
+{
+  if (index >= 0 && index < majorDim_) {
+    int length = (length_[index] < numReplace) ? length_[index] : numReplace;
+    CoinMemcpyN(newElements, length, element_ + start_[index]);
+  } else {
+#ifdef COIN_DEBUG
+    throw CoinError("bad index", "replaceVector", "CoinPackedMatrix");
+#endif
+  }
+}
+/* Modify one element of packed matrix.  An element may be added.
+   If the new element is zero it will be deleted unless
+   keepZero true */
+void 
+CoinPackedMatrix::modifyCoefficient(int row, int column, double newElement,
+				    bool keepZero)
+{
+  int minorIndex,majorIndex;
+  if (colOrdered_) {
+    majorIndex=column;
+    minorIndex=row;
+  } else {
+    minorIndex=column;
+    majorIndex=row;
+  }
+  if (majorIndex >= 0 && majorIndex < majorDim_) {
+    if (minorIndex >= 0 && minorIndex < minorDim_) {
+      CoinBigIndex j;
+      CoinBigIndex end=start_[majorIndex]+length_[majorIndex];;
+      for (j=start_[majorIndex];j<end;j++) {
+	if (minorIndex==index_[j]) {
+	  // replacement
+	  if (newElement||keepZero) {
+	    element_[j]=newElement;
+	  } else {
+	    // pack down and return
+	    length_[majorIndex]--;
+	    end--;
+	    size_--;
+	    for (;j<end;j++) {
+	      element_[j]=element_[j+1];
+	      index_[j]=index_[j+1];
+	    }
+	  }
+	  return;
+	}
+      }
+      if (j==end&&(newElement||keepZero)) {
+	// we need to insert - keep in minor order if possible
+	if (end>=start_[majorIndex+1]) {
+	   int * addedEntries = new int[majorDim_];
+	   memset(addedEntries, 0, majorDim_ * sizeof(int));
+	   addedEntries[majorIndex] = 1;
+	   resizeForAddingMinorVectors(addedEntries);
+	   delete[] addedEntries;
+        }
+        // So where to insert? We're just going to assume that the entries
+        // in the major vector are in increasing order, so we'll insert the
+        // new entry to the last place we can
+        const CoinBigIndex start = start_[majorIndex];
+        end = start_[majorIndex]+length_[majorIndex]; // recalculate end
+        for (j = end - 1; j >= start; --j) {
+          if (index_[j] < minorIndex)
+            break;
+          index_[j+1] = index_[j];
+          element_[j+1] = element_[j];
+        }
+        ++j;
+        index_[j] = minorIndex;
+        element_[j] = newElement;
+        size_++;
+        length_[majorIndex]++;
+      }
+    } else {
+#ifdef COIN_DEBUG
+      throw CoinError("bad minor index", "modifyCoefficient",
+		      "CoinPackedMatrix");
+#endif
+    }
+  } else {
+#ifdef COIN_DEBUG
+    throw CoinError("bad major index", "modifyCoefficient",
+		    "CoinPackedMatrix");
+#endif
+  }
+}
+/* Return one element of packed matrix.
+   This works for either ordering
+   If it is not present will return 0.0 */
+double 
+CoinPackedMatrix::getCoefficient(int row, int column) const
+{
+  int minorIndex,majorIndex;
+  if (colOrdered_) {
+    majorIndex=column;
+    minorIndex=row;
+  } else {
+    minorIndex=column;
+    majorIndex=row;
+  }
+  double value=0.0;
+  if (majorIndex >= 0 && majorIndex < majorDim_) {
+    if (minorIndex >= 0 && minorIndex < minorDim_) {
+      CoinBigIndex j;
+      CoinBigIndex end=start_[majorIndex]+length_[majorIndex];;
+      for (j=start_[majorIndex];j<end;j++) {
+	if (minorIndex==index_[j]) {
+          value = element_[j];
+          break;
+	}
+      }
+    } else {
+#ifdef COIN_DEBUG
+      throw CoinError("bad minor index", "modifyCoefficient",
+		      "CoinPackedMatrix");
+#endif
+    }
+  } else {
+#ifdef COIN_DEBUG
+    throw CoinError("bad major index", "modifyCoefficient",
+		    "CoinPackedMatrix");
+#endif
+  }
+  return value;
+}
+
+//#############################################################################
+/* Eliminate all elements in matrix whose 
+   absolute value is less than threshold.
+   The column starts are not affected.  Returns number of elements
+   eliminated.  Elements eliminated are at end of each vector
+*/
+int 
+CoinPackedMatrix::compress(double threshold)
+{
+  CoinBigIndex numberEliminated =0;
+  // space for eliminated
+  int * eliminatedIndex = new int[minorDim_];
+  double * eliminatedElement = new double[minorDim_];
+  int i;
+  for (i=0;i<majorDim_;i++) {
+    int length = length_[i];
+    CoinBigIndex k=start_[i];
+    int kbad=0;
+    CoinBigIndex j;
+    for (j=start_[i];j<start_[i]+length;j++) {
+      if (fabs(element_[j])>=threshold) {
+	element_[k]=element_[j];
+	index_[k++]=index_[j];
+      } else {
+	eliminatedElement[kbad]=element_[j];
+	eliminatedIndex[kbad++]=index_[j];
+      }
+    }
+    if (kbad) {
+      numberEliminated += kbad;
+      length_[i] = k-start_[i];
+      memcpy(index_+k,eliminatedIndex,kbad*sizeof(int));
+      memcpy(element_+k,eliminatedElement,kbad*sizeof(double));
+    }
+  }
+  size_ -= numberEliminated;
+  delete [] eliminatedIndex;
+  delete [] eliminatedElement;
+  return numberEliminated;
+}
+//#############################################################################
+/* Eliminate all elements in matrix whose 
+   absolute value is less than threshold.ALSO removes duplicates
+   The column starts are not affected.  Returns number of elements
+   eliminated. 
+*/
+int 
+CoinPackedMatrix::eliminateDuplicates(double threshold)
+{
+  CoinBigIndex numberEliminated =0;
+  // space for eliminated
+  int * mark = new int [minorDim_];
+  int i;
+  for (i=0;i<minorDim_;i++)
+    mark[i]=-1;
+  for (i=0;i<majorDim_;i++) {
+    CoinBigIndex k=start_[i];
+    CoinBigIndex end = k+length_[i];
+    CoinBigIndex j;
+    for (j=k;j<end;j++) {
+      int index = index_[j];
+      if (mark[index]==-1) {
+	mark[index]=j;
+      } else {
+	// duplicate
+	int jj = mark[index];
+	element_[jj] += element_[j];
+	element_[j]=0.0;
+      }
+    }
+    for (j=k;j<end;j++) {
+      int index = index_[j];
+      mark[index]=-1;
+      if (fabs(element_[j])>=threshold) {
+	element_[k]=element_[j];
+	index_[k++]=index_[j];
+      }
+    }
+    numberEliminated += end-k;
+    length_[i] = k-start_[i];
+  }
+  size_ -= numberEliminated;
+  delete [] mark;
+  return numberEliminated;
+}
+//#############################################################################
+
+void
+CoinPackedMatrix::removeGaps(double removeValue)
+{
+  if (removeValue<0.0) {
+    if (size_<start_[majorDim_]) {
+#if 1
+      // Small copies so faster to do simply
+      int i;
+      CoinBigIndex size=0;
+      for (i = 1; i < majorDim_+1; ++i) {
+	const CoinBigIndex si = start_[i];
+	size += length_[i-1];
+	if (si>size)
+	  break;
+      }
+      for (; i < majorDim_; ++i) {
+	const CoinBigIndex si = start_[i];
+	const int li = length_[i];
+	start_[i] = size;
+	for (CoinBigIndex j=si;j<si+li;j++) {
+	  assert (size<size_);
+	  index_[size]=index_[j];
+	  element_[size++]=element_[j];
+	}
+      }
+      assert (size==size_);
+      start_[majorDim_] = size;
+      for (i=0; i < majorDim_; ++i) {
+	assert (start_[i+1]==start_[i]+length_[i]);
+      }
+#else
+      for (int i = 1; i < majorDim_; ++i) {
+	const CoinBigIndex si = start_[i];
+	const int li = length_[i];
+	start_[i] = start_[i-1] + length_[i-1];
+	CoinCopy(index_ + si, index_ + (si + li), index_ + start_[i]);
+	CoinCopy(element_ + si, element_ + (si + li), element_ + start_[i]);
+
+      }
+      start_[majorDim_] = size_;
+#endif
+    } else {
+#ifndef NDEBUG
+      for (int i = 1; i < majorDim_; ++i) {
+	assert (start_[i] == start_[i-1] + length_[i-1]);
+      }
+      assert(start_[majorDim_] == size_);
+#endif
+    }
+  } else {
+    CoinBigIndex put=0;
+    assert (!start_[0]);
+    CoinBigIndex start = 0;
+    for (int i = 0; i < majorDim_; ++i) {
+      const CoinBigIndex si = start;
+      start = start_[i+1];
+      const int li = length_[i];
+      for (CoinBigIndex j = si;j<si+li;j++) {
+	double value = element_[j];
+	if (fabs(value)>removeValue) {
+	  index_[put]=index_[j];
+	  element_[put++]=value;
+	}
+      }
+      length_[i]=put-start_[i];
+      start_[i+1] = put;
+    }
+    size_ = put;
+  }
+}
+
+//#############################################################################
+
+/* Really clean up matrix.
+   a) eliminate all duplicate AND small elements in matrix 
+   b) remove all gaps and set extraGap_ and extraMajor_ to 0.0
+   c) reallocate arrays and make max lengths equal to lengths
+   d) orders elements
+   returns number of elements eliminated
+*/
+int 
+CoinPackedMatrix::cleanMatrix(double threshold)
+{
+  if (!majorDim_) {
+    extraGap_=0.0;
+    extraMajor_=0.0;
+    return 0;
+  }
+  CoinBigIndex numberEliminated =0;
+  // space for eliminated
+  int * mark = new int [minorDim_];
+  int i;
+  for (i=0;i<minorDim_;i++)
+    mark[i]=-1;
+  CoinBigIndex n = 0;
+  for (i=0;i<majorDim_;i++) {
+    CoinBigIndex k=start_[i];
+    start_[i]=n;
+    CoinBigIndex end = k+length_[i];
+    CoinBigIndex j;
+    for (j=k;j<end;j++) {
+      int index = index_[j];
+      if (mark[index]==-1) {
+	mark[index]=j;
+      } else {
+	// duplicate
+	int jj = mark[index];
+	element_[jj] += element_[j];
+	element_[j]=0.0;
+      }
+    }
+    for (j=k;j<end;j++) {
+      int index = index_[j];
+      mark[index]=-1;
+      if (fabs(element_[j])>=threshold) {
+	element_[n]=element_[j];
+	index_[n++]=index_[j];
+	k++;
+      }
+    }
+    numberEliminated += end-k;
+    length_[i] = n-start_[i];
+    // sort
+    CoinSort_2(index_+start_[i],index_+n,element_+start_[i]);
+  }
+  start_[majorDim_]=n;
+  size_ -= numberEliminated;
+  assert (n==size_);
+  delete [] mark;
+  extraGap_=0.0;
+  extraMajor_=0.0;
+  maxMajorDim_=majorDim_;
+  maxSize_=size_;
+  // Now reallocate - do smallest ones first
+  int * temp = CoinCopyOfArray(length_,majorDim_);
+  delete [] length_;
+  length_ = temp;
+  CoinBigIndex * temp2 = CoinCopyOfArray(start_,majorDim_+1);
+  delete [] start_;
+  start_ = temp2;
+  temp = CoinCopyOfArray(index_,size_);
+  delete [] index_;
+  index_ = temp;
+  double * temp3 = CoinCopyOfArray(element_,size_);
+  delete [] element_;
+  element_ = temp3;
+  return numberEliminated;
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::submatrixOf(const CoinPackedMatrix& matrix,
+			     const int numMajor, const int * indMajor)
+{
+   int i;
+   int* sortedIndPtr = CoinTestIndexSet(numMajor, indMajor, matrix.majorDim_,
+				       "submatrixOf");
+   const int * sortedInd = sortedIndPtr == 0 ? indMajor : sortedIndPtr;
+
+   gutsOfDestructor();
+
+   // Count how many nonzeros there'll be
+   CoinBigIndex nzcnt = 0;
+   const int* length = matrix.getVectorLengths();
+   for (i = 0; i < numMajor; ++i) {
+      nzcnt += length[sortedInd[i]];
+   }
+
+   colOrdered_ = matrix.colOrdered_;
+   maxMajorDim_ = int(numMajor * (1+extraMajor_) + 1);
+   maxSize_ = static_cast<CoinBigIndex> (nzcnt * (1+extraMajor_) * (1+extraGap_) + 100);
+   length_ = new int[maxMajorDim_];
+   start_ = new CoinBigIndex[maxMajorDim_+1];
+   start_[0]=0;
+   index_ = new int[maxSize_];
+   element_ = new double[maxSize_];
+   majorDim_ = 0;
+   minorDim_ = matrix.minorDim_;
+   size_ = 0;
+#ifdef CLP_NO_VECTOR
+   for (i = 0; i < numMajor; ++i) {
+     int j = sortedInd[i];
+     CoinBigIndex start = matrix.start_[j];
+     appendMajorVector(matrix.length_[j],matrix.index_+start,matrix.element_+start);
+   }
+#else
+   for (i = 0; i < numMajor; ++i) {
+      const CoinShallowPackedVector reqdBySunCC = matrix.getVector(sortedInd[i]) ;
+      appendMajorVector(reqdBySunCC);
+   }
+#endif
+
+   delete[] sortedIndPtr;
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::submatrixOfWithDuplicates(const CoinPackedMatrix& matrix,
+			     const int numMajor, const int * indMajor)
+{
+  int i;
+  // we allow duplicates - can be useful
+#ifndef NDEBUG
+  for (i=0; i<numMajor;i++) {
+    if (indMajor[i]<0||indMajor[i]>=matrix.majorDim_)
+      throw CoinError("bad index", "submatrixOfWithDuplicates", "CoinPackedMatrix");
+  }
+#endif
+  gutsOfDestructor();
+  // Get rid of gaps
+  extraMajor_ = 0;
+  extraGap_ = 0;
+  colOrdered_ = matrix.colOrdered_;
+  maxMajorDim_ = numMajor ;
+  
+  const int* length = matrix.getVectorLengths();
+  length_ = new int[maxMajorDim_];
+  start_ = new CoinBigIndex[maxMajorDim_+1];
+  // Count how many nonzeros there'll be
+  CoinBigIndex nzcnt = 0;
+  for (i = 0; i < maxMajorDim_; ++i) {
+    start_[i]=nzcnt;
+    int thisLength = length[indMajor[i]];
+    nzcnt += thisLength;
+    length_[i]=thisLength;
+  }
+  start_[maxMajorDim_]=nzcnt;
+  maxSize_ = nzcnt ;
+  index_ = new int[maxSize_];
+  element_ = new double[maxSize_];
+  majorDim_ = maxMajorDim_;
+  minorDim_ = matrix.minorDim_;
+  size_ = 0;
+  const CoinBigIndex * startOld = matrix.start_;
+  const double * elementOld = matrix.element_;
+  const int * indexOld = matrix.index_;
+  for (i = 0; i < maxMajorDim_; ++i) {
+    int j = indMajor[i];
+    CoinBigIndex start = startOld[j];
+    int thisLength = length_[i];
+    const double * element = elementOld+start;
+    const int * index = indexOld+start;
+    for (int j=0;j<thisLength;j++) {
+      element_[size_] = element[j];
+       index_[size_++] = index[j];
+    }
+  }
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::copyOf(const CoinPackedMatrix& rhs)
+{
+   if (this != &rhs) {
+      gutsOfDestructor();
+      gutsOfCopyOf(rhs.colOrdered_,
+		   rhs.minorDim_, rhs.majorDim_, rhs.size_,
+		   rhs.element_, rhs.index_, rhs.start_, rhs.length_,
+		   rhs.extraMajor_, rhs.extraGap_);
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::copyOf(const bool colordered,
+			const int minor, const int major,
+			const CoinBigIndex numels,
+			const double * elem, const int * ind,
+			const CoinBigIndex * start, const int * len,
+			const double extraMajor, const double extraGap)
+{
+   gutsOfDestructor();
+   gutsOfCopyOf(colordered, minor, major, numels, elem, ind, start, len,
+		extraMajor, extraGap);
+}
+//#############################################################################
+/* Copy method. This method makes an exact replica of the argument,
+   including the extra space parameters. 
+   If there is room it will re-use arrays */
+void 
+CoinPackedMatrix::copyReuseArrays(const CoinPackedMatrix& rhs)
+{
+  assert (colOrdered_==rhs.colOrdered_);
+  if (maxMajorDim_>=rhs.majorDim_&&maxSize_>=rhs.size_) {
+    majorDim_ = rhs.majorDim_;
+    minorDim_ = rhs.minorDim_;
+    size_ = rhs.size_;
+    extraGap_ = rhs.extraGap_;
+    extraMajor_ = rhs.extraMajor_;
+    CoinMemcpyN(rhs.length_, majorDim_,length_);
+    CoinMemcpyN(rhs.start_, majorDim_+1,start_);
+    if (size_==start_[majorDim_]) {
+      CoinMemcpyN(rhs.index_ , size_, index_);
+      CoinMemcpyN(rhs.element_ , size_, element_);
+    } else {
+     // we can't just simply memcpy these content over, because that can
+     // upset memory debuggers like purify if there were gaps and those gaps
+     // were uninitialized memory blocks
+     for (int i = majorDim_ - 1; i >= 0; --i) {
+       CoinMemcpyN(rhs.index_ + start_[i], length_[i], index_ + start_[i]);
+       CoinMemcpyN(rhs.element_ + start_[i], length_[i], element_ + start_[i]);
+     }
+    }
+  } else {
+    copyOf(rhs);
+  }
+}
+
+//#############################################################################
+
+// This method is essentially the same as minorAppendOrthoOrdered(). However,
+// since we start from an empty matrix, lots of fluff can be avoided.
+
+void
+CoinPackedMatrix::reverseOrderedCopyOf(const CoinPackedMatrix& rhs)
+{
+   if (this == &rhs) {
+      reverseOrdering();
+      return;
+   }
+
+   int i;
+   colOrdered_ = !rhs.colOrdered_;
+   majorDim_ = rhs.minorDim_;
+   minorDim_ = rhs.majorDim_;
+   size_ = rhs.size_;
+
+   if (size_ == 0) {
+     // we still need to allocate starts and lengths
+     maxMajorDim_=majorDim_;
+     delete[] start_;
+     delete[] length_;
+     delete[] index_;
+     delete[] element_;
+     start_ = new CoinBigIndex[maxMajorDim_ + 1];
+     length_ = new int[maxMajorDim_];
+     for (i = 0; i < majorDim_; ++i) {
+       start_[i] = 0;
+       length_[i]=0;
+     }
+     start_[majorDim_]=0;
+     index_ = new int[maxSize_];
+     element_ = new double[maxSize_];
+     return;
+   }
+
+
+   // Allocate sufficient space (resizeForAddingMinorVectors())
+   
+   const int newMaxMajorDim_ =
+     CoinMax(maxMajorDim_, CoinLengthWithExtra(majorDim_, extraMajor_));
+
+   if (newMaxMajorDim_ > maxMajorDim_) {
+      maxMajorDim_ = newMaxMajorDim_;
+      delete[] start_;
+      delete[] length_;
+      start_ = new CoinBigIndex[maxMajorDim_ + 1];
+      length_ = new int[maxMajorDim_];
+   }
+   // first compute how long each major-dimension vector will be
+   int * COIN_RESTRICT orthoLength = length_;
+   rhs.countOrthoLength(orthoLength);
+
+   start_[0] = 0;
+   if (extraGap_ == 0) {
+      for (i = 0; i < majorDim_; ++i)
+	 start_[i+1] = start_[i] + orthoLength[i];
+   } else {
+      const double eg = extraGap_;
+      for (i = 0; i < majorDim_; ++i)
+	start_[i+1] = start_[i] + CoinLengthWithExtra(orthoLength[i], eg);
+   }
+
+   const CoinBigIndex newMaxSize =
+      CoinMax(maxSize_, CoinLengthWithExtra(getLastStart(), extraMajor_));
+
+   if (newMaxSize > maxSize_) {
+      maxSize_ = newMaxSize;
+      delete[] index_;
+      delete[] element_;
+      index_ = new int[maxSize_];
+      element_ = new double[maxSize_];
+#     ifdef ZEROFAULT
+      memset(index_,0,(maxSize_*sizeof(int))) ;
+      memset(element_,0,(maxSize_*sizeof(double))) ;
+#     endif
+   }
+
+   // now insert the entries of matrix
+   
+   minorDim_ = rhs.majorDim_;
+   const CoinBigIndex * COIN_RESTRICT start = rhs.start_;
+   const int * COIN_RESTRICT index = rhs.index_;
+   const int * COIN_RESTRICT length = rhs.length_;
+   const double * COIN_RESTRICT element = rhs.element_;
+   assert (start[0]==0);
+   CoinBigIndex first = 0;
+   for (i = 0; i < minorDim_; ++i) {
+     CoinBigIndex last = first + length[i]; 
+     CoinBigIndex j = first;
+     first = start[i+1];
+#if 0
+     if (((last-j)&1)!=0) {
+       const int ind = index[j];
+       CoinBigIndex put = start_[ind];
+       start_[ind] = put +1;
+       element_[put] = element[j];
+       index_[put] = i;
+       j++;
+     }
+     for (; j != last; j+=2) {
+       const int ind0 = index[j];
+       CoinBigIndex put0 = start_[ind0];
+       double value0=element[j];
+       const int ind1 = index[j+1];
+       CoinBigIndex put1 = start_[ind1];
+       double value1=element[j+1];
+       start_[ind0] = put0 +1;
+       start_[ind1] = put1 +1;
+       element_[put0] = value0;
+       index_[put0] = i;
+       element_[put1] = value1;
+       index_[put1] = i;
+     }
+#else
+     for (; j != last; ++j) {
+       const int ind = index[j];
+       CoinBigIndex put = start_[ind];
+       start_[ind] = put +1;
+       element_[put] = element[j];
+       index_[put] = i;
+     }
+#endif
+   }
+   // and re-adjust start_
+   for (i = 0; i < majorDim_; ++i) {
+     start_[i] -= length_[i];
+   }
+}
+   
+//#############################################################################
+
+void
+CoinPackedMatrix::assignMatrix(const bool colordered,
+			      const int minor, const int major,
+			      const CoinBigIndex numels,
+			      double *& elem, int *& ind,
+			      CoinBigIndex *& start, int *& len,
+			      const int maxmajor, const CoinBigIndex maxsize)
+{
+   gutsOfDestructor();
+   colOrdered_ = colordered;
+   element_ = elem;
+   index_ = ind;
+   start_ = start;
+   majorDim_ = major;
+   minorDim_ = minor;
+   size_ = numels;
+   maxMajorDim_ = maxmajor != -1 ? maxmajor : major;
+   maxSize_ = maxsize != -1 ? maxsize : numels;
+   if (len == NULL) {
+     delete [] length_;
+     length_ = new int[maxMajorDim_];
+     std::adjacent_difference(start + 1, start + (major + 1), length_);
+     length_[0] -= start[0];
+   } else {
+     length_ = len;
+   }
+   elem = NULL;
+   ind = NULL;
+   start = NULL;
+   len = NULL;
+}
+
+//#############################################################################
+
+CoinPackedMatrix &
+CoinPackedMatrix::operator=(const CoinPackedMatrix& rhs)
+{
+   if (this != &rhs) {
+      gutsOfDestructor();
+      extraGap_=rhs.extraGap_;
+      extraMajor_=rhs.extraMajor_;
+      gutsOfOpEqual(rhs.colOrdered_,
+		    rhs.minorDim_,  rhs.majorDim_, rhs.size_,
+		    rhs.element_, rhs.index_, rhs.start_, rhs.length_);
+   }
+   return *this;
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::reverseOrdering()
+{
+   CoinPackedMatrix m;
+   m.extraGap_ = extraMajor_;
+   m.extraMajor_ = extraGap_;
+   m.reverseOrderedCopyOf(*this);
+   swap(m);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::transpose()
+{
+   colOrdered_ = ! colOrdered_;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::swap(CoinPackedMatrix& m)
+{
+   std::swap(colOrdered_,  m.colOrdered_);
+   std::swap(extraGap_,	   m.extraGap_);
+   std::swap(extraMajor_,  m.extraMajor_);
+   std::swap(element_, 	   m.element_);
+   std::swap(index_,	   m.index_);
+   std::swap(start_,	   m.start_);
+   std::swap(length_,	   m.length_);
+   std::swap(majorDim_,	   m.majorDim_);
+   std::swap(minorDim_,	   m.minorDim_);
+   std::swap(size_,	   m.size_);
+   std::swap(maxMajorDim_, m.maxMajorDim_);
+   std::swap(maxSize_,     m.maxSize_);
+}
+
+//#############################################################################
+//#############################################################################
+
+void
+CoinPackedMatrix::times(const double * x, double * y) const 
+{
+   if (colOrdered_)
+      timesMajor(x, y);
+   else
+      timesMinor(x, y);
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::times(const CoinPackedVectorBase& x, double * y) const 
+{
+   if (colOrdered_)
+      timesMajor(x, y);
+   else
+      timesMinor(x, y);
+}
+#endif
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::transposeTimes(const double * x, double * y) const 
+{
+   if (colOrdered_)
+      timesMinor(x, y);
+   else
+      timesMajor(x, y);
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::transposeTimes(const CoinPackedVectorBase& x, double * y) const
+{
+   if (colOrdered_)
+      timesMinor(x, y);
+   else
+      timesMajor(x, y);
+}
+#endif
+//#############################################################################
+//#############################################################################
+/* Count the number of entries in every minor-dimension vector and
+   fill in an array containing these lengths.  */
+void
+CoinPackedMatrix::countOrthoLength(int * orthoLength) const
+{
+  CoinZeroN(orthoLength, minorDim_);
+  if (size_!=start_[majorDim_]) {
+    // has gaps
+    for (int i = 0; i <majorDim_ ; ++i) {
+      const CoinBigIndex first = start_[i];
+      const CoinBigIndex last = first + length_[i];
+      for (CoinBigIndex j = first; j < last; ++j) {
+	assert( index_[j] < minorDim_ && index_[j]>=0);
+	++orthoLength[index_[j]];
+      }
+    }
+  } else {
+    // no gaps 
+    const CoinBigIndex last = start_[majorDim_];
+    for (CoinBigIndex j = 0; j < last; ++j) {
+      assert( index_[j] < minorDim_ && index_[j]>=0);
+      ++orthoLength[index_[j]];
+    }
+  }
+}
+
+int *
+CoinPackedMatrix::countOrthoLength() const
+{
+   int * orthoLength = new int[minorDim_];
+   countOrthoLength(orthoLength);
+   return orthoLength;
+}
+
+//#############################################################################
+/* Returns an array containing major indices.  The array is
+    getNumElements long and if getVectorStarts() is 0,2,5 then
+    the array would start 0,0,1,1,1,2...
+    This method is provided to go back from a packed format
+    to a triple format.
+    The returned array is allocated with <code>new int[]</code>,
+    free it with  <code>delete[]</code>. */
+int * 
+CoinPackedMatrix::getMajorIndices() const
+{
+  // Check valid
+  if (!majorDim_||start_[majorDim_]!=size_)
+    return NULL;
+  int * array = new int [size_];
+  for (int i=0;i<majorDim_;i++) {
+    for (CoinBigIndex k=start_[i];k<start_[i+1];k++)
+      array[k]=i;
+  }
+  return array;
+}
+//#############################################################################
+
+void
+CoinPackedMatrix::appendMajorVector(const int vecsize,
+				   const int *vecind,
+				   const double *vecelem)
+{
+#ifdef COIN_DEBUG
+  for (int i = 0; i < vecsize; ++i) {
+    if (vecind[i] < 0 )
+      throw CoinError("out of range index",
+		     "appendMajorVector", "CoinPackedMatrix");
+  }
+#if 0   
+  if (std::find_if(vecind, vecind + vecsize,
+		   compose2(logical_or<bool>(),
+			    bind2nd(less<int>(), 0),
+			    bind2nd(greater_equal<int>(), minorDim_))) !=
+      vecind + vecsize)
+    throw CoinError("out of range index",
+		   "appendMajorVector", "CoinPackedMatrix");
+#endif
+#endif
+  
+  if (majorDim_ == maxMajorDim_ || vecsize > maxSize_ - getLastStart()) {
+    resizeForAddingMajorVectors(1, &vecsize);
+  }
+
+  // got to get this again since it might change!
+  const CoinBigIndex last = getLastStart();
+
+  // OK, now just append the major-dimension vector to the end
+
+  length_[majorDim_] = vecsize;
+  CoinMemcpyN(vecind, vecsize, index_ + last);
+  CoinMemcpyN(vecelem, vecsize, element_ + last);
+  if (majorDim_ == 0)
+    start_[0] = 0;
+  start_[majorDim_ + 1] =
+    CoinMin(last + CoinLengthWithExtra(vecsize, extraGap_), maxSize_ );
+
+   // LL: Do we want to allow appending a vector that has more entries than
+   // the current size?
+   if (vecsize > 0) {
+     minorDim_ = CoinMax(minorDim_,
+			(*std::max_element(vecind, vecind+vecsize)) + 1);
+   }
+
+   ++majorDim_;
+   size_ += vecsize;
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::appendMajorVector(const CoinPackedVectorBase& vec)
+{
+   appendMajorVector(vec.getNumElements(),
+		     vec.getIndices(), vec.getElements());
+}
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::appendMajorVectors(const int numvecs,
+				    const CoinPackedVectorBase * const * vecs)
+{
+  int i;
+  CoinBigIndex nz = 0;
+  for (i = 0; i < numvecs; ++i)
+    nz += CoinLengthWithExtra(vecs[i]->getNumElements(), extraGap_);
+  reserve(majorDim_ + numvecs, getLastStart() + nz);
+  for (i = 0; i < numvecs; ++i)
+    appendMajorVector(*vecs[i]);
+}
+#endif
+
+//#############################################################################
+
+void
+CoinPackedMatrix::appendMinorVector(const int vecsize,
+				   const int *vecind,
+				   const double *vecelem)
+{
+  if (vecsize == 0) {
+    ++minorDim_; // empty row/column - still need to increase
+    return;
+  }
+
+  int i;
+#if COIN_COINUTILS_CHECKLEVEL > 3
+  // Test if any of the indices are out of range
+  for (i = 0; i < vecsize; ++i) {
+    if (vecind[i] < 0 || vecind[i] >= majorDim_)
+      throw CoinError("out of range index",
+		     "appendMinorVector", "CoinPackedMatrix");
+  }
+  // Test if there are duplicate indices
+  int* sortedind = CoinCopyOfArray(vecind, vecsize);
+  std::sort(sortedind, sortedind+vecsize);
+  if (std::adjacent_find(sortedind, sortedind+vecsize) != sortedind+vecsize) {
+    throw CoinError("identical indices",
+		     "appendMinorVector", "CoinPackedMatrix");
+  }
+#endif
+
+  // test that there's a gap at the end of every major-dimension vector where
+  // we want to add a new entry
+   
+  for (i = vecsize - 1; i >= 0; --i) {
+    const int j = vecind[i];
+    if (start_[j] + length_[j] == start_[j+1])
+      break;
+  }
+
+  if (i >= 0) {
+    int * addedEntries = new int[majorDim_];
+    memset(addedEntries, 0, majorDim_ * sizeof(int));
+    for (i = vecsize - 1; i >= 0; --i)
+      addedEntries[vecind[i]] = 1;
+    resizeForAddingMinorVectors(addedEntries);
+    delete[] addedEntries;
+  }
+
+  // OK, now insert the entries of the minor-dimension vector
+  for (i = vecsize - 1; i >= 0; --i) {
+    const int j = vecind[i];
+    const CoinBigIndex posj = start_[j] + (length_[j]++);
+    index_[posj] = minorDim_;
+    element_[posj] = vecelem[i];
+  }
+
+  ++minorDim_;
+  size_ += vecsize;
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::appendMinorVector(const CoinPackedVectorBase& vec)
+{
+   appendMinorVector(vec.getNumElements(),
+		     vec.getIndices(), vec.getElements());
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::appendMinorVectors(const int numvecs,
+				    const CoinPackedVectorBase * const * vecs)
+{
+  if (numvecs == 0)
+    return;
+
+  int i;
+
+  int * addedEntries = new int[majorDim_];
+  CoinZeroN(addedEntries, majorDim_);
+  for (i = numvecs - 1; i >= 0; --i) {
+    const int vecsize = vecs[i]->getNumElements();
+    const int* vecind = vecs[i]->getIndices();
+    for (int j = vecsize - 1; j >= 0; --j) {
+#ifdef COIN_DEBUG
+      if (vecind[j] < 0 || vecind[j] >= majorDim_)
+	throw CoinError("out of range index", "appendMinorVectors",
+		       "CoinPackedMatrix");
+#endif
+      ++addedEntries[vecind[j]];
+    }
+  }
+ 
+  for (i = majorDim_ - 1; i >= 0; --i) {
+    if (start_[i] + length_[i] + addedEntries[i] > start_[i+1])
+      break;
+  }
+  if (i >= 0)
+    resizeForAddingMinorVectors(addedEntries);
+  delete[] addedEntries;
+
+  // now insert the entries of the vectors
+  for (i = 0; i < numvecs; ++i) {
+    const int vecsize = vecs[i]->getNumElements();
+    const int* vecind = vecs[i]->getIndices();
+    const double* vecelem = vecs[i]->getElements();
+    for (int j = vecsize - 1; j >= 0; --j) {
+      const int ind = vecind[j];
+      element_[start_[ind] + length_[ind]] = vecelem[j];
+      index_[start_[ind] + (length_[ind]++)] = minorDim_;
+    }
+    ++minorDim_;
+    size_ += vecsize;
+  }
+}
+#endif
+
+//#############################################################################
+//#############################################################################
+
+void
+CoinPackedMatrix::majorAppendSameOrdered(const CoinPackedMatrix& matrix)
+{
+   if (minorDim_ != matrix.minorDim_) {
+      throw CoinError("dimension mismatch", "rightAppendSameOrdered",
+		     "CoinPackedMatrix");
+   }
+   if (matrix.majorDim_ == 0)
+      return;
+
+   int i;
+   if (majorDim_ + matrix.majorDim_ > maxMajorDim_ ||
+       getLastStart() + matrix.getLastStart() > maxSize_) {
+      // we got to resize before we add. note that the resizing method
+      // properly fills out start_ and length_ for the major-dimension
+      // vectors to be added!
+      resizeForAddingMajorVectors(matrix.majorDim_, matrix.length_);
+      start_ += majorDim_;
+      for (i = 0; i < matrix.majorDim_; ++i) {
+	 const int l = matrix.length_[i];
+	 CoinMemcpyN(matrix.index_ + matrix.start_[i], l,
+			   index_ + start_[i]);
+	 CoinMemcpyN(matrix.element_ + matrix.start_[i], l,
+			   element_ + start_[i]);
+      }
+      start_ -= majorDim_;
+   } else {
+      start_ += majorDim_;
+      length_ += majorDim_;
+      for (i = 0; i < matrix.majorDim_; ++i) {
+	 const int l = matrix.length_[i];
+	 CoinMemcpyN(matrix.index_ + matrix.start_[i], l,
+			   index_ + start_[i]);
+	 CoinMemcpyN(matrix.element_ + matrix.start_[i], l,
+			   element_ + start_[i]);
+	 start_[i+1] = start_[i] + matrix.start_[i+1] - matrix.start_[i];
+	 length_[i] = l;
+      }
+      start_ -= majorDim_;
+      length_ -= majorDim_;
+   }
+   majorDim_ += matrix.majorDim_;
+   size_ += matrix.size_;
+}
+
+//-----------------------------------------------------------------------------
+   
+void
+CoinPackedMatrix::minorAppendSameOrdered(const CoinPackedMatrix& matrix)
+{
+   if (majorDim_ != matrix.majorDim_) {
+      throw CoinError("dimension mismatch", "bottomAppendSameOrdered",
+		      "CoinPackedMatrix");
+   }
+   if (matrix.minorDim_ == 0)
+      return;
+
+   int i;
+   for (i = majorDim_ - 1; i >= 0; --i) {
+      if (start_[i] + length_[i] + matrix.length_[i] > start_[i+1])
+	 break;
+   }
+   if (i >= 0)
+      resizeForAddingMinorVectors(matrix.length_);
+
+   // now insert the entries of matrix
+   for (i = majorDim_ - 1; i >= 0; --i) {
+      const int l = matrix.length_[i];
+      std::transform(matrix.index_ + matrix.start_[i],
+		matrix.index_ + (matrix.start_[i] + l),
+		index_ + (start_[i] + length_[i]),
+		std::bind2nd(std::plus<int>(), minorDim_));
+      CoinMemcpyN(matrix.element_ + matrix.start_[i], l,
+		       element_ + (start_[i] + length_[i]));
+      length_[i] += l;
+   }
+   minorDim_ += matrix.minorDim_;
+   size_ += matrix.size_;
+}
+   
+//-----------------------------------------------------------------------------
+   
+void
+CoinPackedMatrix::majorAppendOrthoOrdered(const CoinPackedMatrix& matrix)
+{
+   if (minorDim_ != matrix.majorDim_) {
+      throw CoinError("dimension mismatch", "majorAppendOrthoOrdered",
+		     "CoinPackedMatrix");
+      }
+   if (matrix.majorDim_ == 0)
+      return;
+
+   int i;
+   CoinBigIndex j;
+   // this trickery is needed because MSVC++ is not willing to delete[] a
+   // 'const int *'
+   int * orthoLengthPtr = matrix.countOrthoLength();
+   const int * orthoLength = orthoLengthPtr;
+
+   if (majorDim_ + matrix.minorDim_ > maxMajorDim_) {
+      resizeForAddingMajorVectors(matrix.minorDim_, orthoLength);
+   } else {
+     const double extra_gap = extraGap_;
+     start_ += majorDim_;
+     for (i = 0; i < matrix.minorDim_ ; ++i) {
+       start_[i+1] = start_[i] + CoinLengthWithExtra(orthoLength[i], extra_gap);
+     }
+     start_ -= majorDim_;
+     if (start_[majorDim_ + matrix.minorDim_] > maxSize_) {
+       resizeForAddingMajorVectors(matrix.minorDim_, orthoLength);
+     }
+   }
+   // At this point everything is big enough to accommodate the new entries.
+   // Also, start_ is set to the correct starting points for all the new
+   // major-dimension vectors. The length of the new major-dimension vectors
+   // may or may not be correctly set. Hence we just zero them out and they'll
+   // be set when the entries are actually added below.
+
+   start_ += majorDim_;
+   length_ += majorDim_;
+
+   CoinZeroN(length_, matrix.minorDim_);
+
+   for (i = 0; i < matrix.majorDim_; ++i) {
+      const CoinBigIndex last = matrix.getVectorLast(i);
+      for (j = matrix.getVectorFirst(i); j < last; ++j) {
+	 const int ind = matrix.index_[j];
+	 element_[start_[ind] + length_[ind]] = matrix.element_[j];
+	 index_[start_[ind] + (length_[ind]++)] = i;
+      }
+   }
+   
+   length_ -= majorDim_;
+   start_ -= majorDim_;
+
+   // We need to update majorDim_ and size_.  We can just add in from matrix
+   majorDim_ += matrix.minorDim_;
+   size_ += matrix.size_;
+
+   delete[] orthoLengthPtr;
+}
+
+//-----------------------------------------------------------------------------
+   
+void
+CoinPackedMatrix::minorAppendOrthoOrdered(const CoinPackedMatrix& matrix)
+{
+   if (majorDim_ != matrix.minorDim_) {
+      throw CoinError("dimension mismatch", "bottomAppendOrthoOrdered",
+		     "CoinPackedMatrix");
+      }
+   if (matrix.majorDim_ == 0)
+      return;
+
+   int i;
+   // first compute how many entries will be added to each major-dimension
+   // vector, and if needed, resize the matrix to accommodate all
+   // this trickery is needed because MSVC++ is not willing to delete[] a
+   // 'const int *'
+   int * addedEntriesPtr = matrix.countOrthoLength();
+   const int * addedEntries = addedEntriesPtr;
+   for (i = majorDim_ - 1; i >= 0; --i) {
+      if (start_[i] + length_[i] + addedEntries[i] > start_[i+1])
+	 break;
+   }
+   if (i >= 0)
+      resizeForAddingMinorVectors(addedEntries);
+   delete[] addedEntriesPtr;
+
+   // now insert the entries of matrix
+   for (i = 0; i < matrix.majorDim_; ++i) {
+      const CoinBigIndex last = matrix.getVectorLast(i);
+      for (CoinBigIndex j = matrix.getVectorFirst(i); j != last; ++j) {
+	 const int ind = matrix.index_[j];
+	 element_[start_[ind] + length_[ind]] = matrix.element_[j];
+	 index_[start_[ind] + (length_[ind]++)] = minorDim_;
+      }
+      ++minorDim_;
+   }
+   size_ += matrix.size_;
+}
+
+//#############################################################################
+//#############################################################################
+
+void
+CoinPackedMatrix::deleteMajorVectors(const int numDel,
+				    const int * indDel)
+{
+   if (numDel == majorDim_) {
+      // everything is deleted
+      majorDim_ = 0;
+      minorDim_ = 0;
+      size_ = 0;
+      // Get rid of memory as well
+      maxMajorDim_ = 0;
+      delete [] length_;
+      length_ = NULL;
+      delete [] start_;
+      start_ = new CoinBigIndex[1];
+      start_[0]=0;;
+      delete [] element_;
+      element_=NULL;
+      delete [] index_;
+      index_=NULL;
+      maxSize_ = 0;
+      return;
+   }
+
+   if (!extraGap_&&!extraMajor_) {
+     // See if this is faster
+     char * keep = new char[majorDim_];
+     memset(keep,1,majorDim_);
+     for (int i=0;i<numDel;i++) {
+       int k=indDel[i];
+       assert (k>=0&&k<majorDim_&&keep[k]);
+       keep[k]=0;
+     }
+     int n;
+     // find first
+     for (n=0;n<majorDim_;n++) {
+       if (!keep[n])
+	 break;
+     }
+     size_=start_[n];
+     for (int i=n;i<majorDim_;i++) {
+       if (keep[i]) {
+	 int length = length_[i];
+	 length_[n]=length;
+	 for (CoinBigIndex j=start_[i];j<start_[i+1];j++) {
+	   element_[size_]=element_[j];
+	   index_[size_++]=index_[j];
+	 }
+	 start_[++n]=size_;
+       }
+     }
+     majorDim_=n;
+     delete [] keep;
+   } else {
+     int *sortedDelPtr = CoinTestIndexSet(numDel, indDel, majorDim_,
+					  "deleteMajorVectors");
+     const int * sortedDel = sortedDelPtr == 0 ? indDel : sortedDelPtr;
+     
+     CoinBigIndex deleted = 0;
+     const int last = numDel - 1;
+     for (int i = 0; i < last; ++i) {
+       const int ind = sortedDel[i];
+       const int ind1 = sortedDel[i+1];
+       deleted += length_[ind];
+       if (ind1 - ind > 1) {
+	 CoinCopy(start_ + (ind + 1), start_ + ind1, start_ + (ind - i));
+	 CoinCopy(length_ + (ind + 1), length_ + ind1, length_ + (ind - i));
+       }
+     }
+     
+     // copy the last block of length_ and start_
+     const int ind = sortedDel[last];
+     deleted += length_[ind];
+     if (sortedDel[last] != majorDim_ - 1) {
+       const int ind1 = majorDim_;
+       CoinCopy(start_ + (ind + 1), start_ + ind1, start_ + (ind - last));
+       CoinCopy(length_ + (ind + 1), length_ + ind1, length_ + (ind - last));
+     }
+     majorDim_ -= numDel;
+     const int lastlength = CoinLengthWithExtra(length_[majorDim_-1], extraGap_);
+     start_[majorDim_] = CoinMin(start_[majorDim_-1] + lastlength, maxSize_);
+     size_ -= deleted;
+     
+     // if the very first major vector was deleted then copy the new first major
+     // vector to the beginning to make certain that start_[0] is 0. This may
+     // not be necessary, but better safe than sorry...
+     if (sortedDel[0] == 0) {
+       CoinCopyN(index_ + start_[0], length_[0], index_);
+       CoinCopyN(element_ + start_[0], length_[0], element_);
+       start_[0] = 0;
+     }
+     
+     delete[] sortedDelPtr;
+   }
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::deleteMinorVectors(const int numDel,
+				    const int * indDel)
+{
+   if (numDel == minorDim_) {
+     // everything is deleted
+     minorDim_ = 0;
+     size_ = 0;
+     // Get rid of as much memory as possible
+     memset(length_,0,majorDim_*sizeof(int));
+     memset(start_,0,(majorDim_+1)*sizeof(CoinBigIndex ));
+     delete [] element_;
+     element_=NULL;
+     delete [] index_;
+     index_=NULL;
+     maxSize_ = 0;
+     return;
+   }
+  int i, j, k;
+
+  // first compute the new index of every row
+  int* newindexPtr = new int[minorDim_];
+  CoinZeroN(newindexPtr, minorDim_);
+  for (j = 0; j < numDel; ++j) {
+    const int ind = indDel[j];
+#ifdef COIN_DEBUG
+    if (ind < 0 || ind >= minorDim_)
+      throw CoinError("out of range index",
+		     "deleteMinorVectors", "CoinPackedMatrix");
+    if (newindexPtr[ind] == -1)
+      throw CoinError("duplicate index",
+		     "deleteMinorVectors", "CoinPackedMatrix");
+#endif
+    newindexPtr[ind] = -1;
+  }
+  for (i = 0, k = 0; i < minorDim_; ++i) {
+    if (newindexPtr[i] != -1) {
+      newindexPtr[i] = k++;
+    }
+  }
+  // Now crawl through the matrix
+  const int * newindex = newindexPtr;
+#ifdef TAKEOUT
+  int mcount[400];
+  memset(mcount,0,400*sizeof(int));
+  for (i = 0; i < majorDim_; ++i) {
+    int * index = index_ + start_[i];
+    double * elem = element_ + start_[i];
+    const int length_i = length_[i];
+    for (j = 0, k = 0; j < length_i; ++j) {
+      mcount[index[j]]++;
+    }
+  }
+  for (i=0;i<minorDim_;i++) {
+    if (mcount[i]==10||mcount[i]==15) {
+      if (newindex[i]>=0)
+	printf("Keeping original row %d (new %d) with count of %d\n",
+	       i,newindex[i],mcount[i]);
+      else
+	printf("deleting row %d with count of %d\n",
+	       i,mcount[i]);
+    }
+  }
+#endif
+  if (!extraGap_) {
+    // pack down
+    size_=0;
+    for (i = 0; i < majorDim_; ++i) {
+      int * index = index_ + start_[i];
+      double * elem = element_ + start_[i];
+      start_[i]=size_;
+      const int length_i = length_[i];
+      for (j = 0; j < length_i; ++j) {
+	const int ind = newindex[index[j]];
+	if (ind >= 0) {
+	  index_[size_] = ind;
+	  element_[size_++] = elem[j];
+	}
+      }
+      length_[i] = size_-start_[i];
+    }
+    start_[majorDim_]=size_;
+  } else {
+    int deleted = 0;
+    for (i = 0; i < majorDim_; ++i) {
+      int * index = index_ + start_[i];
+      double * elem = element_ + start_[i];
+      const int length_i = length_[i];
+      for (j = 0, k = 0; j < length_i; ++j) {
+	const int ind = newindex[index[j]];
+	if (ind != -1) {
+	  index[k] = ind;
+	  elem[k++] = elem[j];
+	}
+      }
+      deleted += length_i - k;
+      length_[i] = k;
+    }
+    size_ -= deleted;
+  }
+
+  delete[] newindexPtr;
+
+  minorDim_ -= numDel;
+}
+
+//#############################################################################
+//#############################################################################
+
+void
+CoinPackedMatrix::timesMajor(const double * x, double * y) const 
+{
+   memset(y, 0, minorDim_ * sizeof(double));
+   for (int i = majorDim_ - 1; i >= 0; --i) {
+      const double x_i = x[i];
+      if (x_i != 0.0) {
+	 const CoinBigIndex last = getVectorLast(i);
+	 for (CoinBigIndex j = getVectorFirst(i); j < last; ++j)
+	    y[index_[j]] += x_i * element_[j];
+      }
+   }
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::timesMajor(const CoinPackedVectorBase& x, double * y) const 
+{
+   memset(y, 0, minorDim_ * sizeof(double));
+   for (CoinBigIndex i = x.getNumElements() - 1; i >= 0; --i) {
+      const double x_i = x.getElements()[i];
+      if (x_i != 0.0) {
+	 const int ind = x.getIndices()[i];
+	 const CoinBigIndex last = getVectorLast(ind);
+	 for (CoinBigIndex j = getVectorFirst(ind); j < last; ++j)
+	    y[index_[j]] += x_i * element_[j];
+      }
+   }
+}
+#endif
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedMatrix::timesMinor(const double * x, double * y) const 
+{
+   memset(y, 0, majorDim_ * sizeof(double));
+   for (int i = majorDim_ - 1; i >= 0; --i) {
+      double y_i = 0;
+      const CoinBigIndex last = getVectorLast(i);
+      for (CoinBigIndex j = getVectorFirst(i); j < last; ++j)
+	 y_i += x[index_[j]] * element_[j];
+      y[i] = y_i;
+   }
+}
+
+//-----------------------------------------------------------------------------
+#ifndef CLP_NO_VECTOR
+void
+CoinPackedMatrix::timesMinor(const CoinPackedVectorBase& x, double * y) const 
+{
+   memset(y, 0, majorDim_ * sizeof(double));
+   for (int i = majorDim_ - 1; i >= 0; --i) {
+      double y_i = 0;
+      const CoinBigIndex last = getVectorLast(i);
+      for (CoinBigIndex j = getVectorFirst(i); j < last; ++j)
+	 y_i += x[index_[j]] * element_[j];
+      y[i] = y_i;
+   }
+}
+#endif
+//#############################################################################
+//#############################################################################
+
+CoinPackedMatrix::CoinPackedMatrix() :
+   colOrdered_(true),
+   extraGap_(0.0),
+   extraMajor_(0.0),
+   element_(0), 
+   index_(0),
+   length_(0),
+   majorDim_(0),
+   minorDim_(0),
+   size_(0),
+   maxMajorDim_(0),
+   maxSize_(0) 
+{
+  start_ = new CoinBigIndex[1];
+  start_[0] = 0;
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedMatrix::CoinPackedMatrix(const bool colordered,
+				 const double extraMajor,
+				 const double extraGap) :
+   colOrdered_(colordered),
+   extraGap_(extraGap),
+   extraMajor_(extraMajor),
+   element_(0), 
+   index_(0),
+   length_(0),
+   majorDim_(0),
+   minorDim_(0),
+   size_(0),
+   maxMajorDim_(0),
+   maxSize_(0)
+{
+  start_ = new CoinBigIndex[1];
+  start_[0] = 0;
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedMatrix::CoinPackedMatrix(const bool colordered,
+				 const int minor, const int major,
+				 const CoinBigIndex numels,
+				 const double * elem, const int * ind,
+				 const CoinBigIndex * start, const int * len,
+				 const double extraMajor,
+				 const double extraGap) :
+   colOrdered_(colordered),
+   extraGap_(extraGap),
+   extraMajor_(extraMajor),
+   element_(NULL),
+   index_(NULL),
+   start_(NULL),
+   length_(NULL),
+   majorDim_(0),
+   minorDim_(0),
+   size_(0),
+   maxMajorDim_(0),
+   maxSize_(0)
+{
+   gutsOfOpEqual(colordered, minor, major, numels, elem, ind, start, len);
+}
+
+//-----------------------------------------------------------------------------
+   
+CoinPackedMatrix::CoinPackedMatrix(const bool colordered,
+				 const int minor, const int major,
+         const CoinBigIndex numels,
+         const double * elem, const int * ind,
+         const CoinBigIndex * start, const int * len) :
+   colOrdered_(colordered),
+   extraGap_(0.0),
+   extraMajor_(0.0),
+   element_(NULL),
+   index_(NULL),
+   start_(NULL),
+   length_(NULL),
+   majorDim_(0),
+   minorDim_(0),
+   size_(0),
+   maxMajorDim_(0),
+   maxSize_(0)
+{
+     gutsOfOpEqual(colordered, minor, major, numels, elem, ind, start, len);
+}
+  
+//-----------------------------------------------------------------------------
+// makes column ordered from triplets and takes out duplicates 
+// will be sorted 
+//
+// This is an interesting in-place sorting algorithm; 
+// We have triples, and want to sort them so that triples with the same column
+// are adjacent.
+// We begin by computing how many entries there are for each column (columnCount)
+// and using that to compute where each set of column entries will *end* (startColumn).
+// As we drop entries into place, startColumn is decremented until it contains
+// the position where the column entries *start*.
+// The invalid column index -2 means there's a "hole" in that position;
+// the invalid column index -1 means the entry in that spot is "where it wants to go".
+// Initially, no one is where they want to go.
+// Going back to front,
+//    if that entry is where it wants to go
+//    then leave it there
+//    otherwise pick it up (which leaves a hole), and 
+//	      for as long as you have an entry in your right hand,
+//	- pick up the entry (with your left hand) in the position where the one in 
+//		your right hand wants to go;
+//	- pass the entry in your left hand to your right hand;
+//	- was that entry really just the "hole"?  If so, stop.
+// It could be that all the entries get shuffled in the first loop iteration
+// and all the rest just confirm that everyone is happy where they are.
+// We never move an entry that is where it wants to go, so entries are moved at
+// most once.  They may not change position if they happen to initially be
+// where they want to go when the for loop gets to them.
+// It depends on how many subpermutations the triples initially defined.
+// Each while loop takes care of one permutation.
+// The while loop has to stop, because each time around we mark one entry as happy.
+// We can't run into a happy entry, because we are decrementing the startColumn
+// all the time, so we must be running into new entries.
+// Once we've processed all the slots for a column, it cannot be the case that
+// there are any others that want to go there.
+// This all means that we eventually must run into the hole.
+CoinPackedMatrix::CoinPackedMatrix(
+     const bool colordered,
+     const int * indexRow ,
+     const int * indexColumn,
+     const double * element, 
+     CoinBigIndex numberElements ) 
+     :
+   colOrdered_(colordered),
+     extraGap_(0.0),
+     extraMajor_(0.0),
+     element_(NULL),
+     index_(NULL),
+     start_(NULL),
+     length_(NULL),
+     majorDim_(0),
+     minorDim_(0),
+     size_(0),
+     maxMajorDim_(0),
+     maxSize_(0)
+{
+     CoinAbsFltEq eq;
+       int * colIndices = new int[numberElements];
+       int * rowIndices = new int[numberElements];
+       double * elements = new double[numberElements];
+       CoinCopyN(element,numberElements,elements);
+     if ( colordered ) {
+       CoinCopyN(indexColumn,numberElements,colIndices);
+       CoinCopyN(indexRow,numberElements,rowIndices);
+     }
+     else {
+       CoinCopyN(indexColumn,numberElements,rowIndices);
+       CoinCopyN(indexRow,numberElements,colIndices);
+     }
+
+  int numberRows;
+  int numberColumns;
+  if (numberElements ) {
+    numberRows = *std::max_element(rowIndices,rowIndices+numberElements)+1;
+    numberColumns = *std::max_element(colIndices,colIndices+numberElements)+1;
+  } else {
+    numberRows = 0;
+    numberColumns = 0;
+  }
+  int * rowCount = new int[numberRows];
+  int * columnCount = new int[numberColumns];
+  CoinBigIndex * startColumn = new CoinBigIndex[numberColumns+1];
+  int * lengths = new int[numberColumns+1];
+
+  int iColumn,i;
+  CoinBigIndex k;
+  for (i=0;i<numberRows;i++) {
+    rowCount[i]=0;
+  }
+  for (i=0;i<numberColumns;i++) {
+    columnCount[i]=0;
+  }
+  for (i=0;i<numberElements;i++) {
+    int iRow=rowIndices[i];
+    int iColumn=colIndices[i];
+    rowCount[iRow]++;
+    columnCount[iColumn]++;
+  }
+  CoinBigIndex iCount=0;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    /* position after end of Column */
+    iCount+=columnCount[iColumn];
+    startColumn[iColumn]=iCount;
+  } /* endfor */
+  startColumn[iColumn]=iCount;
+  for (k=numberElements-1;k>=0;k--) {
+    iColumn=colIndices[k];
+    if (iColumn>=0) {
+      /* pick up the entry with your right hand */
+      double value = elements[k];
+      int iRow=rowIndices[k];
+      colIndices[k]=-2;	/* the hole */
+
+      while (1) {
+	/* pick this up with your left */
+        CoinBigIndex iLook=startColumn[iColumn]-1;
+        double valueSave=elements[iLook];
+        int iColumnSave=colIndices[iLook];
+        int iRowSave=rowIndices[iLook];
+
+	/* put the right-hand entry where it wanted to go */
+        startColumn[iColumn]=iLook;
+        elements[iLook]=value;
+        rowIndices[iLook]=iRow;
+        colIndices[iLook]=-1;	/* mark it as being where it wants to be */
+
+	/* there was something there */
+        if (iColumnSave>=0) {
+          iColumn=iColumnSave;
+          value=valueSave;
+          iRow=iRowSave;
+	} else if (iColumnSave == -2) {	/* that was the hole */
+          break;
+	} else {
+	  assert(1==0);	/* should never happen */
+	}
+	/* endif */
+      } /* endwhile */
+    } /* endif */
+  } /* endfor */
+
+  /* now pack the elements and combine entries with the same row and column */
+  /* also, drop entries with "small" coefficients */
+  numberElements=0;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    CoinBigIndex start=startColumn[iColumn];
+    CoinBigIndex end =startColumn[iColumn+1];
+    lengths[iColumn]=0;
+    startColumn[iColumn]=numberElements;
+    if (end>start) {
+      int lastRow;
+      double lastValue;
+      // sorts on indices dragging elements with
+      CoinSort_2(rowIndices+start,rowIndices+end,elements+start,CoinFirstLess_2<int, double>());
+      lastRow=rowIndices[start];
+      lastValue=elements[start];
+      for (i=start+1;i<end;i++) {
+        int iRow=rowIndices[i];
+        double value=elements[i];
+        if (iRow>lastRow) {
+          //if(fabs(lastValue)>tolerance) {
+          if(!eq(lastValue,0.0)) {
+            rowIndices[numberElements]=lastRow;
+            elements[numberElements]=lastValue;
+            numberElements++;
+            lengths[iColumn]++;
+          }
+          lastRow=iRow;
+          lastValue=value;
+        } else {
+          lastValue+=value;
+        } /* endif */
+      } /* endfor */
+      //if(fabs(lastValue)>tolerance) {
+      if(!eq(lastValue,0.0)) {
+        rowIndices[numberElements]=lastRow;
+        elements[numberElements]=lastValue;
+        numberElements++;
+        lengths[iColumn]++;
+      }
+    }
+  } /* endfor */
+  startColumn[numberColumns]=numberElements;
+#if 0
+  gutsOfOpEqual(colordered,numberRows,numberColumns,numberElements,elements,rowIndices,startColumn,lengths);
+  
+  delete [] rowCount;
+  delete [] columnCount;
+  delete [] startColumn;
+  delete [] lengths;
+
+  delete [] colIndices;
+  delete [] rowIndices;
+  delete [] elements;
+#else
+  assignMatrix(colordered,numberRows,numberColumns,numberElements,
+    elements,rowIndices,startColumn,lengths); 
+  delete [] rowCount;
+  delete [] columnCount;
+  delete [] lengths;
+  delete [] colIndices;
+#endif
+
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedMatrix::CoinPackedMatrix (const CoinPackedMatrix & rhs) :
+   colOrdered_(true),
+   extraGap_(0.0),
+   extraMajor_(0.0),
+   element_(0), 
+   index_(0),
+   start_(0),
+   length_(0),
+   majorDim_(0),
+   minorDim_(0),
+   size_(0),
+   maxMajorDim_(0),
+   maxSize_(0)
+{
+  bool hasGaps = rhs.size_<rhs.start_[rhs.majorDim_];
+  if (!hasGaps&&!rhs.extraMajor_) {
+   gutsOfCopyOfNoGaps(rhs.colOrdered_,
+		rhs.minorDim_, rhs.majorDim_,
+                      rhs.element_, rhs.index_, rhs.start_);
+  } else {
+   gutsOfCopyOf(rhs.colOrdered_,
+		rhs.minorDim_, rhs.majorDim_, rhs.size_,
+		rhs.element_, rhs.index_, rhs.start_, rhs.length_,
+		rhs.extraMajor_, rhs.extraGap_);
+  }
+}
+/* Copy constructor - fine tuning - allowing extra space and/or reverse
+   ordering.
+
+   extraForMajor is exact extra after any possible reverse ordering. If
+    < 0 then gaps and small values are removed as the copy is created.
+   extraMajor_ and extraGap_ set to zero.
+*/
+CoinPackedMatrix::CoinPackedMatrix (const CoinPackedMatrix& rhs,
+				    int extraForMajor, 
+				    int extraElements, bool reverseOrdering)
+  :  colOrdered_(rhs.colOrdered_),
+   extraGap_(0),
+   extraMajor_(0),
+   element_(0), 
+   index_(0),
+   start_(0),
+   length_(0),
+   majorDim_(rhs.majorDim_),
+   minorDim_(rhs.minorDim_),
+   size_(rhs.size_),
+   maxMajorDim_(0),
+   maxSize_(0)
+{
+  if (!reverseOrdering) {
+    if (extraForMajor>=0) {
+      maxMajorDim_ = majorDim_+ extraForMajor;
+      maxSize_ = size_ + extraElements;
+      assert (maxMajorDim_>0);
+      assert (maxSize_>0);
+      length_ = new int[maxMajorDim_];
+      CoinMemcpyN(rhs.length_, majorDim_, length_);
+      start_ = new CoinBigIndex[maxMajorDim_+1];
+      element_ = new double[maxSize_];
+      index_ = new int[maxSize_];
+      bool hasGaps = rhs.size_<rhs.start_[rhs.majorDim_];
+      if (hasGaps) {
+	// we can't just simply memcpy these content over, because that can
+	// upset memory debuggers like purify if there were gaps and those gaps
+	// were uninitialized memory blocks
+	CoinBigIndex size=0;
+	for (int i = 0 ; i < majorDim_ ; i++) {
+	  start_[i]=size;
+	  CoinMemcpyN(rhs.index_ + rhs.start_[i], length_[i], index_ + size);
+	  CoinMemcpyN(rhs.element_ + rhs.start_[i], length_[i], element_ + size);
+	  size += length_[i];
+	}
+	start_[majorDim_]=size;
+	assert (size_==size);
+      } else {
+	CoinMemcpyN(rhs.start_, majorDim_+1, start_);
+	CoinMemcpyN(rhs.index_, size_, index_);
+	CoinMemcpyN(rhs.element_, size_, element_ );
+      }
+    } else {
+      // take out small and gaps
+      maxMajorDim_ = majorDim_;
+      maxSize_ = size_;
+      if (maxMajorDim_>0) {
+	length_ = new int[maxMajorDim_];
+	start_ = new CoinBigIndex[maxMajorDim_+1];
+	if (maxSize_>0) {
+	  element_ = new double[maxSize_];
+	  index_ = new int[maxSize_];
+	}
+	CoinBigIndex size=0;
+	const double * oldElement = rhs.element_;
+	const CoinBigIndex * oldStart = rhs.start_;
+	const int * oldIndex = rhs.index_;
+	const int * oldLength = rhs.length_;
+	CoinBigIndex tooSmallCount=0;
+	for (int i = 0 ; i < majorDim_ ; i++) {
+	  start_[i]=size;
+	  for (CoinBigIndex j=oldStart[i];
+	       j<oldStart[i]+oldLength[i];j++) {
+	    double value = oldElement[j];
+	    if (fabs(value)>1.0e-21) {
+	      element_[size]=value;
+	      index_[size++]=oldIndex[j];
+	    } else {
+	      tooSmallCount++;
+	    }
+	  }
+	  length_[i]=size-start_[i];
+	}
+	start_[majorDim_]=size;
+	assert (size_==size+tooSmallCount);
+	size_ = size;
+      } else {
+	start_ = new CoinBigIndex[1];
+	start_[0]=0;
+      }
+    }
+  } else {
+    // more complicated
+    colOrdered_ =  ! colOrdered_;
+    minorDim_ = rhs.majorDim_;
+    majorDim_ = rhs.minorDim_;
+    maxMajorDim_ = majorDim_ + extraForMajor;
+    maxSize_ = CoinMax(size_ + extraElements,1);
+    assert (maxMajorDim_>0);
+    length_ = new int[maxMajorDim_];
+    start_ = new CoinBigIndex[maxMajorDim_+1];
+    element_ = new double[maxSize_];
+    index_ = new int[maxSize_];
+    bool hasGaps = rhs.size_<rhs.start_[rhs.majorDim_];
+    CoinZeroN(length_, majorDim_);
+    int i;
+    if (hasGaps) {
+      // has gaps
+      for (i = 0; i <rhs.majorDim_ ; ++i) {
+	const CoinBigIndex first = rhs.start_[i];
+	const CoinBigIndex last = first + rhs.length_[i];
+	for (CoinBigIndex j = first; j < last; ++j) {
+	  assert( rhs.index_[j] < rhs.minorDim_ && rhs.index_[j]>=0);
+	  ++length_[rhs.index_[j]];
+	}
+      }
+    } else {
+      // no gaps 
+      const CoinBigIndex last = rhs.start_[rhs.majorDim_];
+      for (CoinBigIndex j = 0; j < last; ++j) {
+       assert( rhs.index_[j] < rhs.minorDim_ && rhs.index_[j]>=0);
+       ++length_[rhs.index_[j]];
+      }
+    }
+    // Now do starts
+    CoinBigIndex size=0;
+    for (i = 0; i <majorDim_ ; ++i) {
+      start_[i]=size;
+      size += length_[i];
+    }
+    start_[majorDim_]=size;
+    assert (size==size_);
+    for (i = 0; i <rhs.majorDim_ ; ++i) {
+      const CoinBigIndex first = rhs.start_[i];
+      const CoinBigIndex last = first + rhs.length_[i];
+      for (CoinBigIndex j = first; j < last; ++j) {
+	const int ind = rhs.index_[j];
+	CoinBigIndex put = start_[ind];
+	start_[ind] = put +1;
+	element_[put] = rhs.element_[j];
+	index_[put] = i;
+      }
+    }
+    // and re-adjust start_
+    for (i = 0; i < majorDim_; ++i) {
+      start_[i] -= length_[i];
+    }
+  }
+}
+// Subset constructor (without gaps)
+CoinPackedMatrix::CoinPackedMatrix (const CoinPackedMatrix & rhs,
+				    int numberRows, const int * whichRow,
+				    int numberColumns, 
+				    const int * whichColumn) :
+   colOrdered_(true),
+   extraGap_(0.0),
+   extraMajor_(0.0),
+   element_(NULL), 
+   index_(NULL),
+   start_(NULL),
+   length_(NULL),
+   majorDim_(0),
+   minorDim_(0),
+   size_(0),
+   maxMajorDim_(0),
+   maxSize_(0)
+{
+  if (numberRows<=0||numberColumns<=0) {
+    start_ = new CoinBigIndex[1];
+    start_[0] = 0;
+  } else {
+    if (!rhs.colOrdered_) {
+      // just swap lists
+      colOrdered_=false;
+      const int * temp = whichRow;
+      whichRow = whichColumn;
+      whichColumn = temp;
+      int n = numberRows;
+      numberRows = numberColumns;
+      numberColumns = n;
+    }
+    const double * element1 = rhs.element_;
+    const int * index1 = rhs.index_;
+    const CoinBigIndex * start1 = rhs.start_;
+    const int * length1 = rhs.length_;
+
+    majorDim_ = numberColumns;
+    maxMajorDim_ = numberColumns;
+    minorDim_ = numberRows;
+    // Throw exception if rhs empty
+    if (rhs.majorDim_ <= 0 || rhs.minorDim_ <= 0)
+      throw CoinError("empty rhs", "subset constructor", "CoinPackedMatrix");
+    // Array to say if an old row is in new copy
+    int * newRow = new int [rhs.minorDim_];
+    int iRow;
+    for (iRow=0;iRow<rhs.minorDim_;iRow++) 
+      newRow[iRow] = -1;
+    // and array for duplicating rows
+    int * duplicateRow = new int [numberRows];
+    int numberBad=0;
+    int numberDuplicate=0;
+    for (iRow=0;iRow<numberRows;iRow++) {
+      duplicateRow[iRow] = -1;
+      int kRow = whichRow[iRow];
+      if (kRow>=0  && kRow < rhs.minorDim_) {
+	if (newRow[kRow]<0) {
+	  // first time
+	  newRow[kRow]=iRow;
+	} else {
+	  // duplicate
+	  numberDuplicate++;
+	  int lastRow = newRow[kRow];
+	  newRow[kRow]=iRow;
+	  duplicateRow[iRow] = lastRow;
+	}
+      } else {
+	// bad row
+	numberBad++;
+      }
+    }
+
+    if (numberBad)
+      throw CoinError("bad minor entries", 
+		      "subset constructor", "CoinPackedMatrix");
+    // now get size and check columns
+    size_ = 0;
+    int iColumn;
+    numberBad=0;
+    if (!numberDuplicate) {
+      // No duplicates so can do faster
+      // If not much smaller then use original size
+      if (3*majorDim_>2*rhs.majorDim_&&
+	  3*minorDim_>2*rhs.minorDim_) {
+	// now create arrays
+	maxSize_=CoinMax(static_cast<CoinBigIndex> (1),rhs.size_);
+	start_ = new CoinBigIndex [numberColumns+1];
+	length_ = new int [numberColumns];
+	index_ = new int[maxSize_];
+	element_ = new double [maxSize_];
+	// and fill them
+	size_ = 0;
+	start_[0]=0;
+	for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	  int kColumn = whichColumn[iColumn];
+	  if (kColumn>=0  && kColumn <rhs.majorDim_) {
+	    CoinBigIndex i;
+	    for (i=start1[kColumn];i<start1[kColumn]+length1[kColumn];i++) {
+	      int kRow = index1[i];
+	      double value = element1[i];
+	      kRow = newRow[kRow];
+	      if (kRow>=0) {
+		index_[size_] = kRow;
+		element_[size_++] = value;
+	      }
+	    }
+	  } else {
+	    // bad column
+	    numberBad++;
+	  }
+	  start_[iColumn+1] = size_;
+	  length_[iColumn] = size_ - start_[iColumn];
+	}
+	if (numberBad)
+	  throw CoinError("bad major entries", 
+			  "subset constructor", "CoinPackedMatrix");
+      } else {
+	for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	  int kColumn = whichColumn[iColumn];
+	  if (kColumn>=0  && kColumn <rhs.majorDim_) {
+	    CoinBigIndex i;
+	    for (i=start1[kColumn];i<start1[kColumn]+length1[kColumn];i++) {
+	      int kRow = index1[i];
+	      kRow = newRow[kRow];
+	      if (kRow>=0)
+		size_++;
+	    }
+	  } else {
+	    // bad column
+	    numberBad++;
+	  }
+	}
+	if (numberBad)
+	  throw CoinError("bad major entries", 
+			  "subset constructor", "CoinPackedMatrix");
+	// now create arrays
+	maxSize_=CoinMax(static_cast<CoinBigIndex> (1),size_);
+	start_ = new CoinBigIndex [numberColumns+1];
+	length_ = new int [numberColumns];
+	index_ = new int[maxSize_];
+	element_ = new double [maxSize_];
+	// and fill them
+	size_ = 0;
+	start_[0]=0;
+	for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	  int kColumn = whichColumn[iColumn];
+	  CoinBigIndex i;
+	  for (i=start1[kColumn];i<start1[kColumn]+length1[kColumn];i++) {
+	    int kRow = index1[i];
+	    double value = element1[i];
+	    kRow = newRow[kRow];
+	    if (kRow>=0) {
+	      index_[size_] = kRow;
+	      element_[size_++] = value;
+	    }
+	  }
+	  start_[iColumn+1] = size_;
+	  length_[iColumn] = size_ - start_[iColumn];
+	}
+      }
+    } else {
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	int kColumn = whichColumn[iColumn];
+	if (kColumn>=0  && kColumn <rhs.majorDim_) {
+	  CoinBigIndex i;
+	  for (i=start1[kColumn];i<start1[kColumn]+length1[kColumn];i++) {
+	    int kRow = index1[i];
+	    kRow = newRow[kRow];
+	    while (kRow>=0) {
+	      size_++;
+	      kRow = duplicateRow[kRow];
+	    }
+	  }
+	} else {
+	  // bad column
+	  numberBad++;
+	}
+      }
+      if (numberBad)
+	throw CoinError("bad major entries", 
+			"subset constructor", "CoinPackedMatrix");
+      // now create arrays
+      maxSize_=CoinMax(static_cast<CoinBigIndex> (1),size_);
+      start_ = new CoinBigIndex [numberColumns+1];
+      length_ = new int [numberColumns];
+      index_ = new int[maxSize_];
+      element_ = new double [maxSize_];
+      // and fill them
+      size_ = 0;
+      start_[0]=0;
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	int kColumn = whichColumn[iColumn];
+	CoinBigIndex i;
+	for (i=start1[kColumn];i<start1[kColumn]+length1[kColumn];i++) {
+	  int kRow = index1[i];
+	  double value = element1[i];
+	  kRow = newRow[kRow];
+	  while (kRow>=0) {
+	    index_[size_] = kRow;
+	    element_[size_++] = value;
+	    kRow = duplicateRow[kRow];
+	  }
+	}
+	start_[iColumn+1] = size_;
+	length_[iColumn] = size_ - start_[iColumn];
+      }
+    }
+    delete [] newRow;
+    delete [] duplicateRow;
+  }
+}
+
+
+//-----------------------------------------------------------------------------
+
+CoinPackedMatrix::~CoinPackedMatrix ()
+{
+   gutsOfDestructor();
+}
+
+//#############################################################################
+//#############################################################################
+//#############################################################################
+
+void
+CoinPackedMatrix::gutsOfDestructor()
+{
+   delete[] length_;
+   delete[] start_;
+   delete[] index_;
+   delete[] element_;
+   length_ = 0;
+   start_ = 0;
+   index_ = 0;
+   element_ = 0;
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::gutsOfCopyOf(const bool colordered,
+			      const int minor, const int major,
+			      const CoinBigIndex numels,
+			      const double * elem, const int * ind,
+			      const CoinBigIndex * start, const int * len,
+			      const double extraMajor, const double extraGap)
+{
+   colOrdered_ = colordered;
+   majorDim_ = major;
+   minorDim_ = minor;
+   size_ = numels;
+
+   extraGap_ = extraGap;
+   extraMajor_ = extraMajor;
+
+   maxMajorDim_ = CoinLengthWithExtra(majorDim_, extraMajor_);
+
+   if (maxMajorDim_ > 0) {
+     delete [] length_;
+     length_ = new int[maxMajorDim_];
+     if (len == 0) {
+       std::adjacent_difference(start + 1, start + (major + 1), length_);
+       length_[0] -= start[0];
+     } else {
+       CoinMemcpyN(len, major, length_);
+     }
+     delete [] start_;
+     start_ = new CoinBigIndex[maxMajorDim_+1];
+     start_[0]=0;
+     CoinMemcpyN(start, major+1, start_);
+   } else {
+     // empty but be safe
+     delete [] length_;
+     length_ = NULL;
+     delete [] start_;
+     start_ = new CoinBigIndex[1];
+     start_[0]=0;
+   }
+
+   maxSize_ = maxMajorDim_ > 0 ? start_[major] : 0;
+   maxSize_ = CoinLengthWithExtra(maxSize_, extraMajor_);
+
+   if (maxSize_ > 0) {
+     delete [] element_;
+     delete []index_;
+     element_ = new double[maxSize_];
+     index_ = new int[maxSize_];
+     // we can't just simply memcpy these content over, because that can
+     // upset memory debuggers like purify if there were gaps and those gaps
+     // were uninitialized memory blocks
+     for (int i = majorDim_ - 1; i >= 0; --i) {
+       CoinMemcpyN(ind + start[i], length_[i], index_ + start_[i]);
+       CoinMemcpyN(elem + start[i], length_[i], element_ + start_[i]);
+     }
+   }
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::gutsOfCopyOfNoGaps(const bool colordered,
+			      const int minor, const int major,
+			      const double * elem, const int * ind,
+                                     const CoinBigIndex * start)
+{
+   colOrdered_ = colordered;
+   majorDim_ = major;
+   minorDim_ = minor;
+   size_ = start[majorDim_];
+
+   extraGap_ = 0;
+   extraMajor_ = 0;
+
+   maxMajorDim_ = majorDim_;
+
+   // delete all arrays
+   delete [] length_;
+   delete [] start_;
+   delete [] element_;
+   delete [] index_;
+   
+   if (maxMajorDim_ > 0) {
+     length_ = new int[maxMajorDim_];
+     assert (!start[0]);
+     start_ = new CoinBigIndex[maxMajorDim_+1];
+     start_[0]=0;
+     CoinBigIndex last = 0;
+     for (int i=0;i<majorDim_;i++) {
+       CoinBigIndex first = last;
+       last = start[i+1];
+       length_[i] = last-first;
+       start_[i+1]=last;
+     }
+   } else {
+     // empty but be safe
+     length_ = NULL;
+     start_ = new CoinBigIndex[1];
+     start_[0]=0;
+   }
+
+   maxSize_ = start_[majorDim_];
+
+   if (maxSize_ > 0) {
+     element_ = new double[maxSize_];
+     index_ = new int[maxSize_];
+     CoinMemcpyN(ind , maxSize_, index_);
+     CoinMemcpyN(elem , maxSize_, element_);
+   } else {
+     element_ = NULL;
+     index_ = NULL;
+   }
+}
+
+//#############################################################################
+
+void
+CoinPackedMatrix::gutsOfOpEqual(const bool colordered,
+			       const int minor, const int major,
+			       const CoinBigIndex numels,
+			       const double * elem, const int * ind,
+			       const CoinBigIndex * start, const int * len)
+{
+   colOrdered_ = colordered;
+   majorDim_ = major;
+   minorDim_ = minor;
+   size_ = numels;
+   if (!len && numels > 0 && numels==start[major] && start[0]==0) {
+     // No gaps - do faster
+     if (major>maxMajorDim_||!start_) {
+       maxMajorDim_ = major;
+       delete [] length_;
+       length_ = new int[maxMajorDim_];
+       delete [] start_;
+       start_ = new CoinBigIndex[maxMajorDim_+1];
+     }
+     CoinMemcpyN(start,major+1,start_);
+     std::adjacent_difference(start + 1, start + (major + 1), length_);
+     if (numels>maxSize_||!element_) {
+       maxSize_=numels;
+       delete [] element_;
+       delete [] index_;
+       element_ = new double[maxSize_];
+       index_ = new int[maxSize_];
+     }
+     CoinMemcpyN(ind,numels,index_);
+     CoinMemcpyN(elem,numels,element_);
+   } else {
+     
+     maxMajorDim_ = CoinLengthWithExtra(majorDim_, extraMajor_);
+     
+     int i;
+     if (maxMajorDim_ > 0) {
+       delete [] length_;
+       length_ = new int[maxMajorDim_];
+       if (len == 0) {
+	 std::adjacent_difference(start + 1, start + (major + 1), length_);
+	 length_[0] -= start[0];
+       } else {
+	 CoinMemcpyN(len, major, length_);
+       }
+       delete [] start_;
+       start_ = new CoinBigIndex[maxMajorDim_+1];
+       start_[0] = 0;
+       if (extraGap_ == 0) {
+	 for (i = 0; i < major; ++i)
+	   start_[i+1] = start_[i] + length_[i];
+       } else {
+	 const double extra_gap = extraGap_;
+	 for (i = 0; i < major; ++i)
+	   start_[i+1] = start_[i] + CoinLengthWithExtra(length_[i], extra_gap);
+       }
+     } else {
+       // empty matrix
+       delete [] start_;
+       start_ = new CoinBigIndex[1];
+       start_[0] = 0;
+     }
+     
+     maxSize_ = maxMajorDim_ > 0 ? start_[major] : 0;
+     maxSize_ = CoinLengthWithExtra(maxSize_, extraMajor_);
+     
+     if (maxSize_ > 0) {
+       delete [] element_;
+       delete [] index_;
+       element_ = new double[maxSize_];
+       index_ = new int[maxSize_];
+       assert (maxSize_>=start_[majorDim_-1]+length_[majorDim_-1]);
+       // we can't just simply memcpy these content over, because that can
+       // upset memory debuggers like purify if there were gaps and those gaps
+       // were uninitialized memory blocks
+       for (i = majorDim_ - 1; i >= 0; --i) {
+	 CoinMemcpyN(ind + start[i], length_[i], index_ + start_[i]);
+	 CoinMemcpyN(elem + start[i], length_[i], element_ + start_[i]);
+       }
+     }
+   }
+#ifndef NDEBUG
+   for (int i = majorDim_ - 1; i >= 0; --i) {
+     const CoinBigIndex last = getVectorLast(i);
+     for (CoinBigIndex j = getVectorFirst(i); j < last; ++j) {
+       int index = index_[j];
+       assert (index>=0&&index<minorDim_);
+     }
+   }
+#endif
+}
+
+//#############################################################################
+
+// This routine is called only if we MUST resize!
+void
+CoinPackedMatrix::resizeForAddingMajorVectors(const int numVec,
+					     const int * lengthVec)
+{
+  const double extra_gap = extraGap_;
+  int i;
+
+  maxMajorDim_ =
+    CoinMax(maxMajorDim_, CoinLengthWithExtra(majorDim_ + numVec, extraMajor_));
+
+  CoinBigIndex * newStart = new CoinBigIndex[maxMajorDim_ + 1];
+  int * newLength = new int[maxMajorDim_];
+
+  CoinMemcpyN(length_, majorDim_, newLength);
+  // fake that the new vectors are there
+  CoinMemcpyN(lengthVec, numVec, newLength + majorDim_);
+  majorDim_ += numVec;
+
+  newStart[0] = 0;
+  if (extra_gap == 0) {
+    for (i = 0; i < majorDim_; ++i)
+      newStart[i+1] = newStart[i] + newLength[i];
+  } else {
+    for (i = 0; i < majorDim_; ++i)
+      newStart[i+1] = newStart[i] + CoinLengthWithExtra(newLength[i],extra_gap);
+  }
+
+  maxSize_ =
+    CoinMax(maxSize_, CoinLengthWithExtra(newStart[majorDim_], extraMajor_));
+  majorDim_ -= numVec;
+
+  int * newIndex = new int[maxSize_];
+  double * newElem = new double[maxSize_];
+  for (i = majorDim_ - 1; i >= 0; --i) {
+    CoinMemcpyN(index_ + start_[i], length_[i], newIndex + newStart[i]);
+    CoinMemcpyN(element_ + start_[i], length_[i], newElem + newStart[i]);
+  }
+
+  gutsOfDestructor();
+  start_   = newStart;
+  length_  = newLength;
+  index_   = newIndex;
+  element_ = newElem;
+}
+
+
+//#############################################################################
+
+void
+CoinPackedMatrix::resizeForAddingMinorVectors(const int * addedEntries)
+{
+   int i;
+   maxMajorDim_ =
+     CoinMax(CoinLengthWithExtra(majorDim_, extraMajor_), maxMajorDim_);
+   CoinBigIndex * newStart = new CoinBigIndex[maxMajorDim_ + 1];
+   int * newLength = new int[maxMajorDim_];
+   // increase the lengths temporarily so that the correct new start positions
+   // can be easily computed (it's faster to modify the lengths and reset them
+   // than do a test for every entry when the start positions are computed.
+   for (i = majorDim_ - 1; i >= 0; --i)
+      newLength[i] = length_[i] + addedEntries[i];
+
+   newStart[0] = 0;
+   if (extraGap_ == 0) {
+      for (i = 0; i < majorDim_; ++i)
+	 newStart[i+1] = newStart[i] + newLength[i];
+   } else {
+      const double eg = extraGap_;
+      for (i = 0; i < majorDim_; ++i)
+	 newStart[i+1] = newStart[i] + CoinLengthWithExtra(newLength[i], eg);
+   }
+
+   // reset the lengths
+   for (i = majorDim_ - 1; i >= 0; --i)
+      newLength[i] -= addedEntries[i];
+
+   maxSize_ =
+     CoinMax(maxSize_, CoinLengthWithExtra(newStart[majorDim_], extraMajor_));
+   int * newIndex = new int[maxSize_];
+   double * newElem = new double[maxSize_];
+   for (i = majorDim_ - 1; i >= 0; --i) {
+      CoinMemcpyN(index_ + start_[i], length_[i],
+			newIndex + newStart[i]);
+      CoinMemcpyN(element_ + start_[i], length_[i],
+			newElem + newStart[i]);
+   }
+
+   gutsOfDestructor();
+   start_   = newStart;
+   length_  = newLength;
+   index_   = newIndex;
+   element_ = newElem;
+}
+
+//#############################################################################
+//#############################################################################
+
+void
+CoinPackedMatrix::dumpMatrix(const char* fname) const
+{
+  if (! fname) {
+    printf("Dumping matrix...\n\n");
+    printf("colordered: %i\n", isColOrdered() ? 1 : 0);
+    const int major = getMajorDim();
+    const int minor = getMinorDim();
+    printf("major: %i   minor: %i\n", major, minor);
+    for (int i = 0; i < major; ++i) {
+      printf("vec %i has length %i with entries:\n", i, length_[i]);
+      for (CoinBigIndex j = start_[i]; j < start_[i] + length_[i]; ++j) {
+	printf("        %15i  %40.25f\n", index_[j], element_[j]);
+      }
+    }
+    printf("\nFinished dumping matrix\n");
+  } else {
+    FILE* out = fopen(fname, "w");
+    fprintf(out, "Dumping matrix...\n\n");
+    fprintf(out, "colordered: %i\n", isColOrdered() ? 1 : 0);
+    const int major = getMajorDim();
+    const int minor = getMinorDim();
+    fprintf(out, "major: %i   minor: %i\n", major, minor);
+    for (int i = 0; i < major; ++i) {
+      fprintf(out, "vec %i has length %i with entries:\n", i, length_[i]);
+      for (CoinBigIndex j = start_[i]; j < start_[i] + length_[i]; ++j) {
+	fprintf(out, "        %15i  %40.25f\n", index_[j], element_[j]);
+      }
+    }
+    fprintf(out, "\nFinished dumping matrix\n");
+    fclose(out);
+  }
+}
+void
+CoinPackedMatrix::printMatrixElement (const int row_val,
+				      const int col_val) const
+{
+  int major_index, minor_index;
+  if (isColOrdered()) {
+    major_index = col_val;
+    minor_index = row_val;
+  } else {
+    major_index = row_val;
+    minor_index = col_val;
+  }
+  if (major_index < 0 || major_index > getMajorDim()-1) {
+    std::cout
+      << "Major index " << major_index << " not in range 0.."
+      << getMajorDim()-1 << std::endl ;
+  } else if (minor_index < 0 || minor_index > getMinorDim()-1) {
+    std::cout
+      << "Minor index " << minor_index << " not in range 0.."
+      << getMinorDim()-1 << std::endl ;
+  } else {
+    CoinBigIndex curr_point = start_[major_index];
+    const CoinBigIndex stop_point = curr_point+length_[major_index];
+    double aij = 0.0 ;
+    for ( ; curr_point < stop_point ; curr_point++) {
+      if (index_[curr_point] == minor_index) {
+	aij = element_[curr_point];
+	break;
+      }
+    }
+    std::cout << aij ;
+  }
+}
+#ifndef CLP_NO_VECTOR
+bool 
+CoinPackedMatrix::isEquivalent2(const CoinPackedMatrix& rhs) const
+{
+  CoinRelFltEq eq;
+  // Both must be column order or both row ordered and must be of same size
+  if (isColOrdered() ^ rhs.isColOrdered()) {
+    std::cerr<<"Ordering "<<isColOrdered()<<
+      " rhs - "<<rhs.isColOrdered()<<std::endl;
+    return false;
+  }
+  if (getNumCols() != rhs.getNumCols()) {
+    std::cerr<<"NumCols "<<getNumCols()<<
+      " rhs - "<<rhs.getNumCols()<<std::endl;
+    return false;
+  }
+  if  (getNumRows() != rhs.getNumRows()) {
+    std::cerr<<"NumRows "<<getNumRows()<<
+      " rhs - "<<rhs.getNumRows()<<std::endl;
+    return false;
+  }
+  if  (getNumElements() != rhs.getNumElements()) {
+    std::cerr<<"NumElements "<<getNumElements()<<
+      " rhs - "<<rhs.getNumElements()<<std::endl;
+    return false;
+  }
+  
+  for (int i=getMajorDim()-1; i >= 0; --i) {
+    CoinShallowPackedVector pv = getVector(i);
+    CoinShallowPackedVector rhsPv = rhs.getVector(i);
+    if ( !pv.isEquivalent(rhsPv,eq) ) {
+      std::cerr<<"vector # "<<i<<" nel "<<pv.getNumElements()<<
+      " rhs - "<<rhsPv.getNumElements()<<std::endl;
+      int j;
+      const int * inds = pv.getIndices();
+      const double * elems = pv.getElements();
+      const int * inds2 = rhsPv.getIndices();
+      const double * elems2 = rhsPv.getElements();
+      for ( j = 0 ;j < pv.getNumElements() ;  ++j) {
+	double diff = elems[j]-elems2[j];
+	if (diff) {
+	  std::cerr<<j<<"( "<<inds[j]<<", "<<elems[j]<<"), rhs ( "<<
+	    inds2[j]<<", "<<elems2[j]<<") diff "<<
+	    diff<<std::endl;
+	  const int * xx = reinterpret_cast<const int *> (elems+j);
+	  printf("%x %x",xx[0],xx[1]);
+	  xx = reinterpret_cast<const int *> (elems2+j);
+	  printf(" %x %x\n",xx[0],xx[1]);
+	}
+      }
+      //return false;
+    }
+  }
+  return true;
+}
+#else
+/* Equivalence.
+   Two matrices are equivalent if they are both by rows or both by columns,
+   they have the same dimensions, and each vector is equivalent. 
+   In this method the FloatEqual function operator can be specified. 
+*/
+bool 
+CoinPackedMatrix::isEquivalent(const CoinPackedMatrix& rhs, const CoinRelFltEq& eq) const
+{
+  // Both must be column order or both row ordered and must be of same size
+  if ((isColOrdered() ^ rhs.isColOrdered()) ||
+      (getNumCols() != rhs.getNumCols()) ||
+      (getNumRows() != rhs.getNumRows()) ||
+      (getNumElements() != rhs.getNumElements()))
+    return false;
+  
+  const int major = getMajorDim();
+  const int minor = getMinorDim();
+  double * values = new double[minor];
+  memset(values,0,minor*sizeof(double));
+  bool same=true;
+  for (int i = 0; i < major; ++i) {
+    int length = length_[i];
+    if (length!=rhs.length_[i]) {
+      same=false;
+      break;
+    } else {
+      CoinBigIndex j;
+      for ( j = start_[i]; j < start_[i] + length; ++j) {
+        int index = index_[j];
+        values[index]=element_[j];
+      }
+      for ( j = rhs.start_[i]; j < rhs.start_[i] + length; ++j) {
+        int index = index_[j];
+        double oldValue = values[index];
+        values[index]=0.0;
+        if (!eq(oldValue,rhs.element_[j])) {
+          same=false;
+          break;
+        }
+      }
+      if (!same)
+        break;
+    }
+  }
+  delete [] values;
+  return same;
+}
+#endif
+bool CoinPackedMatrix::isEquivalent(const CoinPackedMatrix& rhs) const
+{
+   return isEquivalent(rhs,CoinRelFltEq());
+}
+/* Sort all columns so indices are increasing.in each column */
+void 
+CoinPackedMatrix::orderMatrix()
+{
+  for (int i=0;i<majorDim_;i++) {
+    CoinBigIndex start = start_[i];
+    CoinBigIndex end = start + length_[i];
+    CoinSort_2(index_+start,index_+end,element_+start);
+  }
+}
+/* Append a set of rows/columns to the end of the matrix. Returns number of errors
+   i.e. if any of the new rows/columns contain an index that's larger than the
+   number of columns-1/rows-1 (if numberOther>0) or duplicates 
+   This version is easy one i.e. adding columns to column ordered */
+int 
+CoinPackedMatrix::appendMajor(const int number,
+                              const CoinBigIndex * starts, const int * index,
+                              const double * element, int numberOther)
+{
+  int i;
+  int numberErrors=0;
+  CoinBigIndex numberElements = starts[number];
+  if (majorDim_ + number > maxMajorDim_ ||
+      getLastStart() + numberElements > maxSize_) {
+    // we got to resize before we add. note that the resizing method
+    // properly fills out start_ and length_ for the major-dimension
+    // vectors to be added!
+    if (!extraGap_&&!extraMajor_&&numberOther<=0&&!hasGaps()) {
+      // can do faster
+      if (majorDim_+number>maxMajorDim_) {
+	maxMajorDim_ = majorDim_+number;
+	int * newLength = new int[maxMajorDim_];
+	CoinMemcpyN(length_, majorDim_, newLength);
+	delete [] length_;
+	length_  = newLength;
+	CoinBigIndex * newStart = new CoinBigIndex[maxMajorDim_ + 1];
+	CoinMemcpyN(start_, majorDim_+1, newStart);
+	delete [] start_;
+	start_   = newStart;
+      }
+      if (size_+numberElements>maxSize_) {
+	maxSize_ = size_+numberElements;
+	double * newElem = new double[maxSize_];
+	CoinMemcpyN(element_,size_,newElem);
+	delete [] element_;
+	element_ = newElem;
+	int * newIndex = new int[maxSize_];
+	CoinMemcpyN(index_,size_,newIndex);
+	delete [] index_;
+	index_ = newIndex;
+      }
+      CoinMemcpyN(index,numberElements,index_+size_);
+      // Do minor dimension
+      int lastMinor=-1;
+      for (CoinBigIndex j=0;j<numberElements;j++) {
+	int iIndex = index[j];
+	lastMinor = CoinMax(lastMinor,iIndex);
+      }
+      // update minorDim if necessary
+      minorDim_ = CoinMax(minorDim_,lastMinor+1);
+      CoinMemcpyN(element,numberElements,element_+size_);
+      i=majorDim_;
+      starts -= majorDim_;
+      majorDim_ += number;
+      int iStart=0;
+      for (;i<majorDim_;i++) {
+	int next = starts[i+1];
+	int length = next-iStart;
+	length_[i]=length;
+	iStart=next;
+	size_ += length;
+	start_[i+1]=size_;
+      }
+      return 0;
+    } else {
+      int * length = new int[number];
+      for (i=0;i<number;i++)
+	length[i]=starts[i+1]-starts[i];
+      resizeForAddingMajorVectors(number, length);
+      delete [] length;
+    }
+    if (numberOther>0) {
+      char * which = new char[numberOther];
+      memset(which,0,numberOther);
+      for (i = 0; i < number; i++) {
+        CoinBigIndex put = start_[majorDim_+i];
+        CoinBigIndex j;
+        for ( j=starts[i];j<starts[i+1];j++) {
+          int iIndex = index[j];
+          element_[put]=element[j];
+          if (iIndex>=0&&iIndex<numberOther) {
+            if (!which[iIndex])
+              which[iIndex]=1;
+            else
+              numberErrors++;
+          } else {
+            numberErrors++;
+          }
+          index_[put++]=iIndex;
+        }
+        for ( j=starts[i];j<starts[i+1];j++) {
+          int iIndex = index[j];
+          if (iIndex>=0&&iIndex<numberOther) 
+            which[iIndex]=0;
+        }
+      }
+      delete [] which;
+    } else {
+      // easy
+      int lastMinor=-1;
+      if (!extraGap_) {
+        // just one copy
+        int * index2 = index_+start_[majorDim_];
+        for (CoinBigIndex j=0;j<numberElements;j++) {
+          int iIndex = index[j];
+          index2[j] = iIndex;
+          lastMinor = CoinMax(lastMinor,iIndex);
+        }
+        CoinMemcpyN(element,numberElements,element_+start_[majorDim_]);
+      } else {
+        start_ += majorDim_;
+        for (i = 0; i < number; i++) {
+          int length = starts[i+1]-starts[i];
+          int * index2 = index_+start_[i];
+          const int * index1 = index+starts[i];
+          for (CoinBigIndex j=0;j<length;j++) {
+            int iIndex = index1[j];
+            index2[j] = iIndex;
+            lastMinor = CoinMax(lastMinor,iIndex);
+          }
+          CoinMemcpyN(element + starts[i], length,
+                      element_ + start_[i]);
+        }
+        start_ -= majorDim_;
+      }
+      // update minorDim if necessary
+      minorDim_ = CoinMax(minorDim_,lastMinor+1);
+    }
+  } else {
+    if (numberOther>0) {
+      char * which = new char[numberOther];
+      memset(which,0,numberOther);
+      for (i = 0; i < number; i++) {
+        CoinBigIndex put = start_[majorDim_+i];
+        CoinBigIndex j;
+        for ( j=starts[i];j<starts[i+1];j++) {
+          int iIndex = index[j];
+          element_[put]=element[j];
+          if (iIndex>=0&&iIndex<numberOther) {
+            if (!which[iIndex])
+              which[iIndex]=1;
+            else
+              numberErrors++;
+          } else {
+            numberErrors++;
+          }
+          index_[put++]=iIndex;
+        }
+        start_[majorDim_+i+1] = put;
+        length_[majorDim_+i] = put-start_[majorDim_+i];;
+        for ( j=starts[i];j<starts[i+1];j++) {
+          int iIndex = index[j];
+          if (iIndex>=0&&iIndex<numberOther) 
+            which[iIndex]=0;
+        }
+      }
+      delete [] which;
+    } else {
+      // easy
+      int lastMinor=-1;
+      if (!extraGap_) {
+        // just one copy
+        // just one copy
+        int * index2 = index_+start_[majorDim_];
+        for (CoinBigIndex j=0;j<numberElements;j++) {
+          int iIndex = index[j];
+          index2[j] = iIndex;
+          lastMinor = CoinMax(lastMinor,iIndex);
+        }
+        CoinMemcpyN(element,numberElements,element_+start_[majorDim_]);
+        start_ += majorDim_;
+        for (i = 0; i < number; i++) {
+          int length = starts[i+1]-starts[i];
+          start_[i+1] = start_[i] + length;
+          length_[majorDim_+i] = length;
+        }
+        start_ -= majorDim_;
+      } else {
+        start_ += majorDim_;
+        for (i = 0; i < number; i++) {
+          int length = starts[i+1]-starts[i];
+          int * index2 = index_+start_[i];
+          const int * index1 = index+starts[i];
+          for (CoinBigIndex j=0;j<length;j++) {
+            int iIndex = index1[j];
+            index2[j] = iIndex;
+            lastMinor = CoinMax(lastMinor,iIndex);
+          }
+          CoinMemcpyN(element + starts[i], length,
+                      element_ + start_[i]);
+          start_[i+1] = start_[i] + length;
+          length_[majorDim_+i] = length;
+        }
+        start_ -= majorDim_;
+      }
+      // update minorDim if necessary
+      minorDim_ = CoinMax(minorDim_,lastMinor+1);
+    }
+  }
+  majorDim_ += number;
+  size_ += numberElements;
+#ifndef NDEBUG
+  int checkSize=0;
+  for (int i=0;i<majorDim_;i++) {
+    checkSize += length_[i];
+  }
+  assert (checkSize==size_);
+#endif
+  return numberErrors;
+}
+/* Append a set of rows/columns to the end of the matrix. Returns number of errors
+   i.e. if any of the new rows/columns contain an index that's larger than the
+   number of columns-1/rows-1 (if numberOther>0) or duplicates
+   This version is harder one i.e. adding columns to row ordered */
+int 
+CoinPackedMatrix::appendMinor(const int number,
+                              const CoinBigIndex * starts, const int * index,
+                              const double * element, int numberOther)
+{
+  int i;
+  int numberErrors=0;
+  // first compute how many entries will be added to each major-dimension
+  // vector, and if needed, resize the matrix to accommodate all
+  int * addedEntries = NULL;
+  if (numberOther>0) {
+    addedEntries = new int[majorDim_];
+    CoinZeroN(addedEntries,majorDim_);
+    numberOther=majorDim_;
+    char * which = new char[numberOther];
+    memset(which,0,numberOther);
+    for (i = 0; i < number; i++) {
+      CoinBigIndex j;
+      for ( j=starts[i];j<starts[i+1];j++) {
+        int iIndex = index[j];
+        if (iIndex>=0&&iIndex<numberOther) {
+          addedEntries[iIndex]++;
+          if (!which[iIndex])
+            which[iIndex]=1;
+          else
+            numberErrors++;
+        } else {
+          numberErrors++;
+        }
+      }
+      for ( j=starts[i];j<starts[i+1];j++) {
+        int iIndex = index[j];
+        if (iIndex>=0&&iIndex<numberOther) 
+          which[iIndex]=0;
+      }
+    }
+    delete [] which;
+  } else {
+    int largest = majorDim_-1;
+    for (i = 0; i < number; i++) {
+      CoinBigIndex j;
+      for ( j=starts[i];j<starts[i+1];j++) {
+        int iIndex = index[j];
+        largest = CoinMax(largest,iIndex);
+      }
+    }
+    if (largest+1>majorDim_) {
+      if (isColOrdered())
+        setDimensions(-1,largest+1);
+      else 
+        setDimensions(largest+1,-1);
+    }
+    addedEntries = new int[majorDim_];
+    CoinZeroN(addedEntries,majorDim_);
+    // no checking
+    for (i = 0; i < number; i++) {
+      CoinBigIndex j;
+      for ( j=starts[i];j<starts[i+1];j++) {
+        int iIndex = index[j];
+        addedEntries[iIndex]++;
+      }
+    }
+  }
+  for (i = majorDim_ - 1; i >= 0; i--) {
+    if (start_[i] + length_[i] + addedEntries[i] > start_[i+1])
+      break;
+  }
+  if (i >= 0)
+    resizeForAddingMinorVectors(addedEntries);
+  delete[] addedEntries;
+
+  // now insert the entries of matrix
+  for (i = 0; i < number; i++) {
+    CoinBigIndex j;
+    for ( j=starts[i];j<starts[i+1];j++) {
+      int iIndex = index[j];
+      element_[start_[iIndex] + length_[iIndex]] = element[j];
+      index_[start_[iIndex] + (length_[iIndex]++)] = minorDim_;
+    }
+    ++minorDim_;
+  }
+  size_ += starts[number];
+#ifndef NDEBUG
+  int checkSize=0;
+  for (int i=0;i<majorDim_;i++) {
+    checkSize += length_[i];
+  }
+  assert (checkSize==size_);
+#endif
+  return numberErrors;
+}
+//#define ADD_ROW_ANALYZE
+#ifdef ADD_ROW_ANALYZE
+static int xxxxxx[10]={0,0,0,0,0,0,0,0,0,0};
+#endif
+/* Append a set of rows/columns to the end of the matrix. This case is
+   when we know there are no gaps and majorDim_ will not change
+   This version is harder one i.e. adding columns to row ordered */
+void
+CoinPackedMatrix::appendMinorFast(const int number,
+				  const CoinBigIndex * starts, const int * index,
+				  const double * element)
+{
+#ifdef ADD_ROW_ANALYZE
+  xxxxxx[0]++;
+#endif
+  // first compute how many entries will be added to each major-dimension
+  // vector, and if needed, resize the matrix to accommodate all
+  // Will be used as new start array
+  CoinBigIndex * newStart = new CoinBigIndex [maxMajorDim_+1];
+  CoinZeroN(newStart,maxMajorDim_);
+  // no checking
+  int numberAdded = starts[number];
+  for (CoinBigIndex j = 0; j < numberAdded; j++) {
+    int iIndex = index[j];
+    newStart[iIndex]++;
+  }
+  int packType=0;
+#ifdef ADD_ROW_ANALYZE
+  int nBad=0;
+#endif
+  if (size_+numberAdded<=maxSize_) {
+    CoinBigIndex nextStart=start_[majorDim_];
+    // could do other way and then stop moving
+    for (int i = majorDim_ - 1; i >= 0; i--) {
+      CoinBigIndex start = start_[i];
+      if (start + length_[i] + newStart[i] <= nextStart) {
+	nextStart=start;
+      } else {
+	packType=-1;
+#ifdef ADD_ROW_ANALYZE
+	nBad++;
+#else
+	break;
+#endif
+      }
+    }
+  } else {
+    // Need more space
+    packType=1;
+  }
+#ifdef ADD_ROW_ANALYZE
+  if (!hasGaps())
+    xxxxxx[9]++;
+  if (packType==-1&&nBad<6)
+    packType=nBad+1;
+  xxxxxx[packType+2]++;
+  if ((xxxxxx[0]%100)==0) {
+    printf("Append ");
+    for (int i=0;i<10;i++)
+      printf("%d ",xxxxxx[i]);
+    printf("\n");
+  }
+#endif
+  if (hasGaps()&&packType)
+    packType=1;
+  CoinBigIndex n = 0;
+  if (packType) {
+    double slack = (static_cast<double> (maxSize_-size_-numberAdded))/
+      static_cast<double> (majorDim_);
+    slack  = CoinMax(0.0,slack-0.01);
+    if (!slack) {
+      for (int i = 0; i < majorDim_; ++i) {
+	int thisCount = newStart[i];
+	newStart[i]=n;
+	n += length_[i] + thisCount;
+      }
+    } else {
+      double added=0.0;
+      for (int i = 0; i < majorDim_; ++i) {
+	int thisCount = newStart[i];
+	newStart[i]=n;
+	added += slack;
+	double extra=0;
+	if (added>=1.0) {
+	  extra = floor(added);
+	  added -= extra;
+	}
+	n += length_[i] + thisCount+ static_cast<int> (extra);
+      }
+    }
+    newStart[majorDim_]=n;
+  }
+  if (packType) {
+    maxSize_ = CoinMax(maxSize_, n);
+    int * newIndex = new int[maxSize_];
+    double * newElem = new double[maxSize_];
+    for (int i = majorDim_ - 1; i >= 0; --i) {
+      CoinBigIndex start = start_[i];
+#ifdef USE_MEMCPY
+      int length = length_[i];
+      CoinBigIndex put = newStart[i];
+      CoinMemcpyN(index_+start,length,newIndex+put);
+      CoinMemcpyN(element_+start,length,newElem+put);
+#else
+      CoinBigIndex end = start+length_[i];
+      CoinBigIndex put = newStart[i];
+      for (CoinBigIndex j=start;j<end;j++) {
+	newIndex[put]=index_[j];
+	newElem[put++]=element_[j];
+      }
+#endif
+    }
+    
+    delete [] start_;
+    delete [] index_;
+    delete [] element_;
+    start_   = newStart;
+    index_   = newIndex;
+    element_ = newElem;
+  } else if (packType<0) {
+    assert (maxSize_ >= n);
+    for (int i = majorDim_ - 1; i >= 0; --i) {
+      CoinBigIndex start = start_[i];
+      int length = length_[i];
+      CoinBigIndex end = start+length;
+      CoinBigIndex put = newStart[i];
+      //if (put==start)
+      //break;
+      put += length;
+      for (CoinBigIndex j=end-1;j>=start;j--) {
+	index_[--put]=index_[j];
+	element_[put]=element_[j];
+      }
+    }
+    delete [] start_;
+    start_   = newStart;
+  } else {
+    delete[] newStart;
+  }
+
+  // now insert the entries of matrix
+  for (int i = 0; i < number; i++) {
+    CoinBigIndex j;
+    for ( j=starts[i];j<starts[i+1];j++) {
+      int iIndex = index[j];
+      element_[start_[iIndex] + length_[iIndex]] = element[j];
+      index_[start_[iIndex] + (length_[iIndex]++)] = minorDim_;
+    }
+    ++minorDim_;
+  }
+  size_ += starts[number];
+#ifndef NDEBUG
+  int checkSize=0;
+  for (int i=0;i<majorDim_;i++) {
+    checkSize += length_[i];
+  }
+  assert (checkSize==size_);
+#endif
+}
+
+/*
+  Utility to scan a packed matrix for corruption and inconsistencies. Not
+  exhaustive, but useful. By default, the method counts coefficients of zero
+  and reports them, but does not consider them an error. Set zeroesAreError to
+  true if you want an error.
+*/
+
+int CoinPackedMatrix::verifyMtx (int verbosity, bool zeroesAreError) const
+
+{
+  const double smallCoeff = 1.0e-50 ;
+  const double largeCoeff = 1.0e50 ;
+
+  int majDim = majorDim_ ;
+  int minDim = minorDim_ ;
+
+  std::string majName, minName ;
+
+  int m, n ;
+  if (colOrdered_) {
+    n = majDim ;
+    majName = "col" ;
+    m = minDim ;
+    minName = "row" ;
+  } else {
+    m = majDim ;
+    majName = "row" ;
+    n = minDim ;
+    minName = "col" ;
+  }
+
+/*
+  size_ is the number of coefficients, maxSize_ the size of the bulk store.
+  start_[majDim] should be one past the last valid coefficient in the bulk
+  store. The actual relation is (#coeffs + #gaps) = start_[majDim].
+*/
+  bool gaps = (size_ < start_[majDim]) ;
+  CoinBigIndex maxIndex = CoinMin(maxSize_,start_[majDim])-1 ;
+
+  if (verbosity >= 3) {
+    std::cout
+      << " Matrix is " << ((colOrdered_)?"column":"row") << "-major, "
+      << m << " rows X " << n << " cols; " << size_ << " coeffs."
+      << std::endl ;
+    std::cout
+      << "  Bulk store " << maxSize_ << " coeffs, last coeff at "
+      << start_[majDim]-1 << ", ex maj " << extraMajor_
+      << ", ex gap " << extraGap_  ;
+    if (gaps) std::cout << ";  matrix has gaps" ;
+    std::cout << "." << std::endl ;
+  }
+
+  const CoinBigIndex *const majStarts = start_ ;
+  const int *const majLens = length_ ;
+  const int *const minInds = index_ ;
+  const double *const coeffs = element_ ;
+/*
+  Set up arrays to track use of bulk store entries.
+*/
+  int errs = 0 ;
+  int zeroes = 0 ;
+  int *refCnt = new int[maxSize_] ;
+  CoinZeroN(refCnt,maxSize_) ;
+  bool *inGap = new bool[maxSize_] ;
+  CoinZeroN(inGap,maxSize_) ;
+
+  for (int majndx = 0 ; majndx < majDim ; majndx++) {
+/*
+  Check that the range of indices for the major vector falls within the bulk
+  store. If any of these checks fail, it's pointless (and possibly unsafe)
+  to do more with this vector.
+
+  Subtle point: Normally, majStarts[majDim] = maxIndex+1 (one past the
+  end of the bulk store), and majStarts[k], k < majDim, should be a valid
+  index. But ... if the last major vector (k = majDim-1) has length 0,
+  then majStarts[k] = maxIndex. This will propagate back through multiple
+  major vectors of length 0. Hence the check for length = 0.
+*/
+    CoinBigIndex majStart = majStarts[majndx] ;
+    int majLen = majLens[majndx] ;
+
+    if (majStart < 0 || (majStart == (maxIndex+1) && majLen != 0) ||
+        majStart > maxIndex+1) {
+      if (verbosity >= 1) {
+        std::cout
+	  << "  " << majName << " " << majndx
+	  << ": start " << majStart << " should be between 0 and "
+	  << maxIndex << "." << std::endl ;
+      }
+      errs++ ;
+      if (majStart >= maxSize_) {
+        std::cout
+	  << "  " << "index exceeds bulk store limit " << maxSize_
+	  << "!" << std::endl ;
+      }
+      continue ;
+    }
+    if (majLen < 0 || majLen > minDim) {
+      if (verbosity >= 1) {
+        std::cout
+	  << "  " << majName << " " << majndx << ": vector length "
+	  << majLen << " should be between 0 and " << minDim
+	  << std::endl ;
+      }
+      errs++ ;
+      continue ;
+    }
+    CoinBigIndex majEnd = majStart+majLen ;
+    if (majEnd < 0 || majEnd > maxIndex+1) {
+      if (verbosity >= 1) {
+        std::cout
+	  << "  " << majName << " " << majndx
+	  << ": end " << majEnd << " should be between 0 and "
+	  << maxIndex << "." << std::endl ;
+      }
+      errs++ ;
+      if (majEnd >= maxSize_) {
+        std::cout
+	  << "  " << "index exceeds bulk store limit " << maxSize_
+	  << "!" << std::endl ;
+      }
+      continue ;
+    }
+/*
+  Check that the major vector length is consistent with the distance between
+  majStart[majndx] and majStart[majndx+1]. If the matrix is gap-free, they
+  should be equal. We've already confirmed that majStart+majLen is within the
+  bulk store, so we can continue even if these checks fail.
+
+  Recall that the final entry in the major vector start array is one past the
+  end of the bulk store. The previous tests will check more carefully if
+  majndx+1 is not the final entry.
+*/
+    CoinBigIndex majStartp1 = majStarts[majndx+1] ;
+    CoinBigIndex startDist = majStartp1-majStart ;
+    if (majStartp1 < 0 || majStartp1 > maxIndex+1) {
+      if (verbosity >= 1) {
+        std::cout
+	  << "  " << majName << " " << majndx
+	  << ": start of next " << majName << " " << majStartp1
+	  << " should be between 0 and " << maxIndex+1 << "." << std::endl ;
+      }
+      errs++ ;
+      if (majStartp1 >= maxSize_) {
+        std::cout
+	  << "  " << "index exceeds bulk store limit " << maxSize_
+	  << "!" << std::endl ;
+      }
+    } else if ((startDist < 0) || ((startDist > minDim) && !gaps)) {
+      if (verbosity >= 1) {
+	std::cout
+	  << "  " << majName << " " << majndx << ": distance between "
+	  << majName << " starts " << startDist
+	  << " should be between 0 and " << minDim << "." << std::endl ;
+      }
+      errs++ ;
+    } else if (majLen > startDist) {
+      if (verbosity >= 1) {
+	std::cout
+	  << "  " << majName << " " << majndx << ": vector length "
+	  << majLen << " should not be greater than distance between "
+	  << majName << " starts " << startDist << std::endl ;
+      }
+      errs++ ;
+    } else if (majLen != startDist && !gaps) {
+      if (verbosity >= 1) {
+	std::cout
+	  << "  " << majName << " " << majndx
+	  << ": " << majName << " length " << majLen
+	  << " should equal distance " << startDist << " between "
+	  << majName << " starts in gap-free matrix." << std::endl ;
+      }
+      errs++ ;
+    }
+/*
+  Scan the major dimension vector, checking for obviously bogus minor indices
+  and coefficients. Generate reference counts for each bulk store entry.
+*/
+    for (CoinBigIndex ii = majStart ;  ii < majEnd ; ii++) {
+      refCnt[ii]++ ;
+      int minndx = minInds[ii] ;
+      if (minndx < 0 || minndx >= minDim) {
+        if (verbosity >= 1) {
+	  std::cout
+	    << "  " << majName << " " << majndx << ": "
+	    << minName << " index " << ii << " is " << minndx
+	    << ", should be between 0 and " << minDim-1 << "." << std::endl ;
+	}
+	errs++ ;
+      }
+      double aij = coeffs[ii] ;
+      if (CoinIsnan(aij) || CoinAbs(aij) > largeCoeff) {
+	if (verbosity >= 1) {
+	  std::cout
+	    << "  (" << ii << ") a<" << majndx << "," << minndx << "> = "
+	    << aij << " appears bogus." << std::endl ;
+	}
+	errs++ ;
+      }
+      if (CoinAbs(aij) < smallCoeff) {
+	if (verbosity >= 4 || zeroesAreError) {
+	  std::cout
+	    << "  (" << ii << ") a<" << majndx << "," << minndx << "> = "
+	    << aij << " appears bogus." << std::endl ;
+	}
+	zeroes++ ;
+      }
+    }
+/*
+  And mark the gaps, if any.
+*/
+    if (gaps) {
+      for (CoinBigIndex ii = majEnd ; ii < majStartp1 ; ii++)
+	inGap[ii] = true ;
+    }
+  }
+/*
+  Check the reference counts. They should all be 1 unless the entry is in a
+  gap, in which case it should be zero. Anything else is a problem. Allow that
+  the matrix may not use the full size of the bulk store.
+*/
+  for (CoinBigIndex ii = 0 ; ii <= maxIndex  ; ii++) {
+    if (!((refCnt[ii] == 1 && inGap[ii] == false) ||
+          (refCnt[ii] == 0 && inGap[ii] == true))) {
+      if (verbosity >= 1) {
+        std::cout
+	  << "  Bulk store entry " << ii << " has reference count "
+	  << refCnt[ii] << "; should be " << ((inGap[ii])?0:1) << "."
+	  << std::endl ;
+      }
+      errs++ ;
+    }
+  }
+  delete[] refCnt ;
+/*
+  Report the result.
+*/
+  if (zeroesAreError) errs += zeroes ;
+  if (errs > 0) {
+    if (verbosity >= 1) {
+      std::cout << "  Detected " << errs << " errors in matrix" ;
+      if (zeroes) std::cout << " (includes " << zeroes << " zeroes)" ;
+      std::cout << "." << std::endl ;
+    }
+  } else {
+    if (verbosity >= 2) {
+      std::cout << "  Matrix verified" ;
+      if (zeroes) std::cout << " (" << zeroes << " zeroes)" ;
+      std::cout << "." << std::endl ;
+    }
+  }
+
+  return (errs) ;
+}
diff --git a/cbits/coin/CoinPackedMatrix.hpp b/cbits/coin/CoinPackedMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPackedMatrix.hpp
@@ -0,0 +1,947 @@
+/* $Id: CoinPackedMatrix.hpp 1560 2012-11-24 00:29:01Z lou $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPackedMatrix_H
+#define CoinPackedMatrix_H
+
+#include "CoinError.hpp"
+#include "CoinTypes.hpp"
+#ifndef CLP_NO_VECTOR
+#include "CoinPackedVectorBase.hpp"
+#include "CoinShallowPackedVector.hpp"
+#else
+class CoinRelFltEq;
+#endif
+
+/** Sparse Matrix Base Class
+
+  This class is intended to represent sparse matrices using row-major
+  or column-major ordering. The representation is very efficient for
+  adding, deleting, or retrieving major-dimension vectors. Adding
+  a minor-dimension vector is less efficient, but can be helped by
+  providing "extra" space as described in the next paragraph. Deleting
+  a minor-dimension vector requires inspecting all coefficients in the
+  matrix. Retrieving a minor-dimension vector would incur the same cost
+  and is not supported (except in the sense that you can write a loop to
+  retrieve all coefficients one at a time). Consider physically transposing
+  the matrix, or keeping a second copy with the other major-vector ordering.
+
+  The sparse represention can be completely compact or it can have "extra"
+  space available at the end of each major vector.  Incorporating extra
+  space into the sparse matrix representation can improve performance in
+  cases where new data needs to be inserted into the packed matrix against
+  the major-vector orientation (e.g, inserting a row into a matrix stored
+  in column-major order).
+
+  For example if the matrix:
+  @verbatim
+     3  1  0   -2   -1  0  0   -1                 
+     0  2  1.1  0    0  0  0    0                       
+     0  0  1    0    0  1  0    0         
+     0  0  0    2.8  0  0 -1.2  0   
+   5.6  0  0    0    1  0  0    1.9
+
+  was stored by rows (with no extra space) in 
+  CoinPackedMatrix r then: 
+    r.getElements() returns a vector containing: 
+      3 1 -2 -1 -1 2 1.1 1 1 2.8 -1.2 5.6 1 1.9 
+    r.getIndices() returns a vector containing: 
+      0 1  3  4  7 1 2   2 5 3    6   0   4 7 
+    r.getVectorStarts() returns a vector containing: 
+      0 5 7 9 11 14 
+    r.getNumElements() returns 14. 
+    r.getMajorDim() returns 5. 
+    r.getVectorSize(0) returns 5. 
+    r.getVectorSize(1) returns 2. 
+    r.getVectorSize(2) returns 2. 
+    r.getVectorSize(3) returns 2. 
+    r.getVectorSize(4) returns 3. 
+ 
+  If stored by columns (with no extra space) then: 
+    c.getElements() returns a vector containing: 
+      3 5.6 1 2 1.1 1 -2 2.8 -1 1 1 -1.2 -1 1.9 
+    c.getIndices() returns a vector containing: 
+      0  4  0 1 1   2  0 3    0 4 2  3    0 4 
+    c.getVectorStarts() returns a vector containing: 
+      0 2 4 6 8 10 11 12 14 
+    c.getNumElements() returns 14. 
+    c.getMajorDim() returns 8. 
+  @endverbatim
+
+  Compiling this class with CLP_NO_VECTOR defined will excise all methods
+  which use CoinPackedVectorBase, CoinPackedVector, or CoinShallowPackedVector
+  as parameters or return types.
+
+  Compiling this class with COIN_FAST_CODE defined removes index range checks.
+*/
+class CoinPackedMatrix  {
+   friend void CoinPackedMatrixUnitTest();
+
+public:
+
+
+  //---------------------------------------------------------------------------
+  /**@name Query members */
+  //@{
+    /** Return the current setting of the extra gap. */
+    inline double getExtraGap() const { return extraGap_; }
+    /** Return the current setting of the extra major. */
+    inline double getExtraMajor() const { return extraMajor_; }
+
+    /** Reserve sufficient space for appending major-ordered vectors. 
+	If create is true, empty columns are created (for column generation) */
+    void reserve(const int newMaxMajorDim, const CoinBigIndex newMaxSize,
+		 bool create=false);
+    /** Clear the data, but do not free any arrays */
+    void clear();
+
+    /** Whether the packed matrix is column major ordered or not. */
+    inline bool isColOrdered() const { return colOrdered_; }
+
+    /** Whether the packed matrix has gaps or not. */
+    inline bool hasGaps() const { return (size_<start_[majorDim_]) ; } 
+
+    /** Number of entries in the packed matrix. */
+    inline CoinBigIndex getNumElements() const { return size_; }
+
+    /** Number of columns. */
+    inline int getNumCols() const
+    { return colOrdered_ ? majorDim_ : minorDim_; }
+
+    /** Number of rows. */
+    inline int getNumRows() const
+    { return colOrdered_ ? minorDim_ : majorDim_; }
+
+    /*! \brief A vector containing the elements in the packed matrix.
+    
+	Returns #elements_. Note that there might be gaps in this vector,
+	entries that do not belong to any major-dimension vector. To get
+	the actual elements one should look at this vector together with
+	vectorStarts (#start_) and vectorLengths (#length_).
+    */
+    inline const double * getElements() const { return element_; }
+
+    /*! \brief A vector containing the minor indices of the elements in
+    	       the packed matrix.
+
+	Returns #index_. Note that there might be gaps in this list,
+	entries that do not belong to any major-dimension vector. To get
+	the actual elements one should look at this vector together with
+	vectorStarts (#start_) and vectorLengths (#length_).
+    */
+    inline const int * getIndices() const { return index_; }
+
+    /*! \brief The size of the <code>vectorStarts</code> array
+
+	See #start_.
+    */
+    inline int getSizeVectorStarts() const
+    { return ((majorDim_ > 0)?(majorDim_+1):(0)) ; }
+
+    /*! \brief The size of the <code>vectorLengths</code> array
+    
+        See #length_.
+    */
+    inline int getSizeVectorLengths() const { return majorDim_; }
+
+    /*! \brief The positions where the major-dimension vectors start in
+    	       elements and indices.
+
+	See #start_.
+    */
+    inline const CoinBigIndex * getVectorStarts() const { return start_; }
+
+    /*! \brief The lengths of the major-dimension vectors.
+    
+        See #length_.
+    */
+    inline const int * getVectorLengths() const { return length_; }
+
+    /** The position of the first element in the i'th major-dimension vector.
+     */
+    CoinBigIndex getVectorFirst(const int i) const {
+#ifndef COIN_FAST_CODE
+      if (i < 0 || i >= majorDim_)
+	throw CoinError("bad index", "vectorFirst", "CoinPackedMatrix");
+#endif
+      return start_[i];
+    }
+    /** The position of the last element (well, one entry <em>past</em> the
+        last) in the i'th major-dimension vector. */
+    CoinBigIndex getVectorLast(const int i) const {
+#ifndef COIN_FAST_CODE
+      if (i < 0 || i >= majorDim_)
+	throw CoinError("bad index", "vectorLast", "CoinPackedMatrix");
+#endif
+      return start_[i] + length_[i];
+    }
+    /** The length of i'th vector. */
+    inline int getVectorSize(const int i) const {
+#ifndef COIN_FAST_CODE
+      if (i < 0 || i >= majorDim_)
+	throw CoinError("bad index", "vectorSize", "CoinPackedMatrix");
+#endif
+      return length_[i];
+    }
+#ifndef CLP_NO_VECTOR  
+    /** Return the i'th vector in matrix. */
+    const CoinShallowPackedVector getVector(int i) const {
+#ifndef COIN_FAST_CODE
+      if (i < 0 || i >= majorDim_)
+	throw CoinError("bad index", "vector", "CoinPackedMatrix");
+#endif
+      return CoinShallowPackedVector(length_[i],
+  				    index_ + start_[i],
+  				    element_ + start_[i],
+  				    false);
+    }
+#endif
+    /** Returns an array containing major indices.  The array is
+	  getNumElements long and if getVectorStarts() is 0,2,5 then
+	  the array would start 0,0,1,1,1,2...
+	  This method is provided to go back from a packed format
+	  to a triple format.  It returns NULL if there are gaps in
+	  matrix so user should use removeGaps() if there are any gaps.
+	  It does this as this array has to match getElements() and 
+	  getIndices() and because it makes no sense otherwise.
+	  The returned array is allocated with <code>new int[]</code>,
+	  free it with  <code>delete[]</code>. */
+    int * getMajorIndices() const;
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Modifying members */
+  //@{
+    /*! \brief Set the dimensions of the matrix.
+    
+      The method name is deceptive; the effect is to append empty columns
+      and/or rows to the matrix to reach the specified dimensions.
+      A negative number for either dimension means that that dimension
+      doesn't change. An exception will be thrown if the specified dimensions
+      are smaller than the current dimensions.
+    */
+    void setDimensions(int numrows, int numcols);
+   
+    /** Set the extra gap to be allocated to the specified value. */
+    void setExtraGap(const double newGap);
+    /** Set the extra major to be allocated to the specified value. */
+    void setExtraMajor(const double newMajor);
+#ifndef CLP_NO_VECTOR
+    /*! Append a column to the end of the matrix.
+    
+       When compiled with COIN_DEBUG defined this method throws an exception
+       if the column vector specifies a nonexistent row index.  Otherwise the
+       method assumes that every index fits into the matrix.
+    */
+    void appendCol(const CoinPackedVectorBase& vec);
+#endif
+    /*! Append a column to the end of the matrix.
+    
+       When compiled with COIN_DEBUG defined this method throws an exception
+       if the column vector specifies a nonexistent row index.  Otherwise the
+       method assumes that every index fits into the matrix.
+    */
+    void appendCol(const int vecsize,
+  		   const int *vecind, const double *vecelem);
+#ifndef CLP_NO_VECTOR
+    /*! Append a set of columns to the end of the matrix.
+
+       When compiled with COIN_DEBUG defined this method throws an exception
+       if any of the column vectors specify a nonexistent row index. Otherwise
+       the method assumes that every index fits into the matrix.
+    */
+    void appendCols(const int numcols,
+		    const CoinPackedVectorBase * const * cols);
+#endif
+    /*! Append a set of columns to the end of the matrix.
+    
+      Returns the number of errors (nonexistent or duplicate row index).
+      No error checking is performed if \p numberRows < 0.
+    */
+    int appendCols(const int numcols,
+		    const CoinBigIndex * columnStarts, const int * row,
+                   const double * element, int numberRows=-1);
+#ifndef CLP_NO_VECTOR
+    /*! Append a row to the end of the matrix.
+  
+       When compiled with COIN_DEBUG defined this method throws an exception
+       if the row vector specifies a nonexistent column index.  Otherwise the
+       method assumes that every index fits into the matrix.
+    */
+    void appendRow(const CoinPackedVectorBase& vec);
+#endif
+    /*! Append a row to the end of the matrix.
+
+       When compiled with COIN_DEBUG defined this method throws an exception
+       if the row vector specifies a nonexistent column index.  Otherwise the
+       method assumes that every index fits into the matrix.
+    */
+    void appendRow(const int vecsize,
+  		  const int *vecind, const double *vecelem);
+#ifndef CLP_NO_VECTOR
+    /*! Append a set of rows to the end of the matrix.
+    
+       When compiled with COIN_DEBUG defined this method throws an exception
+       if any of the row vectors specify a nonexistent column index. Otherwise
+       the method assumes that every index fits into the matrix.
+    */
+    void appendRows(const int numrows,
+		    const CoinPackedVectorBase * const * rows);
+#endif
+    /*! Append a set of rows to the end of the matrix.
+    
+      Returns the number of errors (nonexistent or duplicate column index).
+      No error checking is performed if \p numberColumns < 0.
+    */
+    int appendRows(const int numrows,
+		    const CoinBigIndex * rowStarts, const int * column,
+                   const double * element, int numberColumns=-1);
+  
+    /** Append the argument to the "right" of the current matrix. Imagine this
+        as adding new columns (don't worry about how the matrices are ordered,
+        that is taken care of). An exception is thrown if the number of rows
+        is different in the matrices. */
+    void rightAppendPackedMatrix(const CoinPackedMatrix& matrix);
+    /** Append the argument to the "bottom" of the current matrix. Imagine this
+        as adding new rows (don't worry about how the matrices are ordered,
+        that is taken care of). An exception is thrown if the number of columns
+        is different in the matrices. */
+    void bottomAppendPackedMatrix(const CoinPackedMatrix& matrix);
+  
+    /** Delete the columns whose indices are listed in <code>indDel</code>. */
+    void deleteCols(const int numDel, const int * indDel);
+    /** Delete the rows whose indices are listed in <code>indDel</code>. */
+    void deleteRows(const int numDel, const int * indDel);
+
+    /** Replace the elements of a vector.  The indices remain the same.
+	At most the number specified will be replaced.
+        The index is between 0 and major dimension of matrix */
+    void replaceVector(const int index,
+		       const int numReplace, const double * newElements);
+    /** Modify one element of packed matrix.  An element may be added.
+        This works for either ordering
+	If the new element is zero it will be deleted unless
+	keepZero true */
+    void modifyCoefficient(int row, int column, double newElement,
+			   bool keepZero=false);
+    /** Return one element of packed matrix.
+        This works for either ordering
+	If it is not present will return 0.0 */
+    double getCoefficient(int row, int column) const;
+
+    /** Eliminate all elements in matrix whose 
+	absolute value is less than threshold.
+	The column starts are not affected.  Returns number of elements
+	eliminated.  Elements eliminated are at end of each vector
+    */
+    int compress(double threshold);
+    /** Eliminate all duplicate AND small elements in matrix 
+	The column starts are not affected.  Returns number of elements
+	eliminated.  
+    */
+    int eliminateDuplicates(double threshold);
+    /** Sort all columns so indices are increasing.in each column */
+    void orderMatrix();
+    /** Really clean up matrix.
+	a) eliminate all duplicate AND small elements in matrix 
+	b) remove all gaps and set extraGap_ and extraMajor_ to 0.0
+	c) reallocate arrays and make max lengths equal to lengths
+	d) orders elements
+	returns number of elements eliminated
+    */
+    int cleanMatrix(double threshold=1.0e-20);
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Methods that reorganize the whole matrix */
+  //@{
+    /** Remove the gaps from the matrix if there were any
+	Can also remove small elements fabs() <= removeValue*/
+    void removeGaps(double removeValue=-1.0);
+ 
+    /** Extract a submatrix from matrix. Those major-dimension vectors of
+	the matrix comprise the submatrix whose indices are given in the
+	arguments. Does not allow duplicates. */
+    void submatrixOf(const CoinPackedMatrix& matrix,
+		     const int numMajor, const int * indMajor);
+    /** Extract a submatrix from matrix. Those major-dimension vectors of
+	the matrix comprise the submatrix whose indices are given in the
+	arguments. Allows duplicates and keeps order. */
+    void submatrixOfWithDuplicates(const CoinPackedMatrix& matrix,
+		     const int numMajor, const int * indMajor);
+#if 0
+    /** Extract a submatrix from matrix. Those major/minor-dimension vectors of
+	the matrix comprise the submatrix whose indices are given in the
+	arguments. */
+    void submatrixOf(const CoinPackedMatrix& matrix,
+		     const int numMajor, const int * indMajor,
+		     const int numMinor, const int * indMinor);
+#endif
+
+    /** Copy method. This method makes an exact replica of the argument,
+        including the extra space parameters. */
+    void copyOf(const CoinPackedMatrix& rhs);
+    /** Copy the arguments to the matrix. If <code>len</code> is a NULL pointer
+        then the matrix is assumed to have no gaps in it and <code>len</code>
+        will be created accordingly. */
+    void copyOf(const bool colordered,
+ 	       const int minor, const int major, const CoinBigIndex numels,
+ 	       const double * elem, const int * ind,
+ 	       const CoinBigIndex * start, const int * len,
+ 	       const double extraMajor=0.0, const double extraGap=0.0);
+    /** Copy method. This method makes an exact replica of the argument,
+        including the extra space parameters. 
+	If there is room it will re-use arrays */
+    void copyReuseArrays(const CoinPackedMatrix& rhs);
+
+    /*! \brief Make a reverse-ordered copy.
+    
+      This method makes an exact replica of the argument with the major
+      vector orientation changed from row (column) to column (row).
+      The extra space parameters are also copied and reversed.
+      (Cf. #reverseOrdering, which does the same thing in place.)
+    */
+    void reverseOrderedCopyOf(const CoinPackedMatrix& rhs);
+
+    /** Assign the arguments to the matrix. If <code>len</code> is a NULL
+	pointer then the matrix is assumed to have no gaps in it and
+	<code>len</code> will be created accordingly. <br>
+        <strong>NOTE 1</strong>: After this method returns the pointers
+        passed to the method will be NULL pointers! <br>
+        <strong>NOTE 2</strong>: When the matrix is eventually destructed the
+        arrays will be deleted by <code>delete[]</code>. Hence one should use
+        this method ONLY if all array swere allocated by <code>new[]</code>! */
+    void assignMatrix(const bool colordered,
+ 		     const int minor, const int major, 
+		      const CoinBigIndex numels,
+ 		     double *& elem, int *& ind,
+ 		     CoinBigIndex *& start, int *& len,
+ 		     const int maxmajor = -1, const CoinBigIndex maxsize = -1);
+ 
+ 
+ 
+    /** Assignment operator. This copies out the data, but uses the current
+        matrix's extra space parameters. */
+    CoinPackedMatrix & operator=(const CoinPackedMatrix& rhs);
+ 
+    /*! \brief Reverse the ordering of the packed matrix.
+
+      Change the major vector orientation of the matrix data structures from
+      row (column) to column (row). (Cf. #reverseOrderedCopyOf, which does
+      the same thing but produces a new matrix.)
+    */
+    void reverseOrdering();
+
+    /*! \brief Transpose the matrix.
+
+        \note
+	If you start with a column-ordered matrix and invoke transpose, you
+	will have a row-ordered transposed matrix. To change the major vector
+	orientation (e.g., to transform a column-ordered matrix to a
+	column-ordered transposed matrix), invoke transpose() followed by
+	#reverseOrdering().
+    */
+    void transpose();
+ 
+    /*! \brief Swap the content of two packed matrices. */
+    void swap(CoinPackedMatrix& matrix);
+   
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Matrix times vector methods */
+  //@{
+    /** Return <code>A * x</code> in <code>y</code>.
+        @pre <code>x</code> must be of size <code>numColumns()</code>
+        @pre <code>y</code> must be of size <code>numRows()</code> */
+    void times(const double * x, double * y) const;
+#ifndef CLP_NO_VECTOR
+    /** Return <code>A * x</code> in <code>y</code>. Same as the previous
+        method, just <code>x</code> is given in the form of a packed vector. */
+    void times(const CoinPackedVectorBase& x, double * y) const;
+#endif
+    /** Return <code>x * A</code> in <code>y</code>.
+        @pre <code>x</code> must be of size <code>numRows()</code>
+        @pre <code>y</code> must be of size <code>numColumns()</code> */
+    void transposeTimes(const double * x, double * y) const;
+#ifndef CLP_NO_VECTOR
+    /** Return <code>x * A</code> in <code>y</code>. Same as the previous
+        method, just <code>x</code> is given in the form of a packed vector. */
+    void transposeTimes(const CoinPackedVectorBase& x, double * y) const;
+#endif
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Helper functions used internally, but maybe useful externally.
+
+     These methods do not worry about testing whether the packed matrix is
+     row or column major ordered; they operate under the assumption that the
+     correct version is invoked. In fact, a number of other methods simply
+     just call one of these after testing the ordering of the matrix. */
+  //@{
+
+    //-------------------------------------------------------------------------
+    /**@name Queries */
+    //@{
+      /** Count the number of entries in every minor-dimension vector and
+	  return an array containing these lengths. The returned array is
+	  allocated with <code>new int[]</code>, free it with
+	  <code>delete[]</code>. */
+      int * countOrthoLength() const;
+      /** Count the number of entries in every minor-dimension vector and
+	  fill in an array containing these lengths.  */
+      void countOrthoLength(int * counts) const;
+      /** Major dimension. For row ordered matrix this would be the number of
+          rows. */
+      inline int getMajorDim() const { return majorDim_; }
+      /** Set major dimension. For row ordered matrix this would be the number of
+          rows. Use with great care.*/
+      inline void setMajorDim(int value) { majorDim_ = value; }
+      /** Minor dimension. For row ordered matrix this would be the number of
+	  columns. */
+      inline int getMinorDim() const { return minorDim_; }
+      /** Set minor dimension. For row ordered matrix this would be the number of
+          columns. Use with great care.*/
+      inline void setMinorDim(int value) { minorDim_ = value; }
+      /** Current maximum for major dimension. For row ordered matrix this many
+          rows can be added without reallocating the vector related to the
+	  major dimension (<code>start_</code> and <code>length_</code>). */
+      inline int getMaxMajorDim() const { return maxMajorDim_; }
+
+      /** Dump the matrix on stdout. When in dire straits this method can
+	  help. */
+      void dumpMatrix(const char* fname = NULL) const;
+
+      /// Print a single matrix element.
+      void printMatrixElement(const int row_val, const int col_val) const;
+    //@}
+
+    //-------------------------------------------------------------------------
+    /*! @name Append vectors
+
+       \details
+       When compiled with COIN_DEBUG defined these methods throw an exception
+       if the major (minor) vector contains an index that's invalid for the
+       minor (major) dimension. Otherwise the methods assume that every index
+       fits into the matrix.
+    */
+    //@{
+#ifndef CLP_NO_VECTOR
+      /** Append a major-dimension vector to the end of the matrix. */
+      void appendMajorVector(const CoinPackedVectorBase& vec);
+#endif
+      /** Append a major-dimension vector to the end of the matrix. */
+      void appendMajorVector(const int vecsize, const int *vecind,
+			     const double *vecelem);
+#ifndef CLP_NO_VECTOR
+      /** Append several major-dimensonvectors to the end of the matrix */
+      void appendMajorVectors(const int numvecs,
+			      const CoinPackedVectorBase * const * vecs);
+
+      /** Append a minor-dimension vector to the end of the matrix. */
+      void appendMinorVector(const CoinPackedVectorBase& vec);
+#endif
+      /** Append a minor-dimension vector to the end of the matrix. */
+      void appendMinorVector(const int vecsize, const int *vecind,
+			     const double *vecelem);
+#ifndef CLP_NO_VECTOR
+      /** Append several minor-dimension vectors to the end of the matrix */
+      void appendMinorVectors(const int numvecs,
+			      const CoinPackedVectorBase * const * vecs);
+#endif
+    /*! \brief Append a set of rows (columns) to the end of a column (row)
+    	       ordered matrix.
+    
+      This case is when we know there are no gaps and majorDim_ will not
+      change.
+
+      \todo
+      This method really belongs in the group of protected methods with
+      #appendMinor; there are no safeties here even with COIN_DEBUG.
+      Apparently this method was needed in ClpPackedMatrix and giving it
+      proper visibility was too much trouble. Should be moved.
+    */
+    void appendMinorFast(const int number,
+		    const CoinBigIndex * starts, const int * index,
+                    const double * element);
+    //@}
+
+    //-------------------------------------------------------------------------
+    /*! \name Append matrices
+
+      \details
+      We'll document these methods assuming that the current matrix is
+      column major ordered (Hence in the <code>...SameOrdered()</code>
+      methods the argument is column ordered, in the
+      <code>OrthoOrdered()</code> methods the argument is row ordered.)
+    */
+    //@{
+      /** Append the columns of the argument to the right end of this matrix.
+	  @pre <code>minorDim_ == matrix.minorDim_</code> <br>
+	  This method throws an exception if the minor dimensions are not the
+	  same. */
+      void majorAppendSameOrdered(const CoinPackedMatrix& matrix);
+      /** Append the columns of the argument to the bottom end of this matrix.
+	  @pre <code>majorDim_ == matrix.majorDim_</code> <br>
+	  This method throws an exception if the major dimensions are not the
+	  same. */
+      void minorAppendSameOrdered(const CoinPackedMatrix& matrix);
+      /** Append the rows of the argument to the right end of this matrix.
+	  @pre <code>minorDim_ == matrix.majorDim_</code> <br>
+	  This method throws an exception if the minor dimension of the
+	  current matrix is not the same as the major dimension of the
+	  argument matrix. */
+      void majorAppendOrthoOrdered(const CoinPackedMatrix& matrix);
+      /** Append the rows of the argument to the bottom end of this matrix.
+	  @pre <code>majorDim_ == matrix.minorDim_</code> <br>
+	  This method throws an exception if the major dimension of the
+	  current matrix is not the same as the minor dimension of the
+	  argument matrix. */
+      void minorAppendOrthoOrdered(const CoinPackedMatrix& matrix);
+      //@}
+
+      //-----------------------------------------------------------------------
+      /**@name Delete vectors */
+      //@{
+      /** Delete the major-dimension vectors whose indices are listed in
+	  <code>indDel</code>. */
+      void deleteMajorVectors(const int numDel, const int * indDel);
+      /** Delete the minor-dimension vectors whose indices are listed in
+	  <code>indDel</code>. */
+      void deleteMinorVectors(const int numDel, const int * indDel);
+      //@}
+
+      //-----------------------------------------------------------------------
+      /**@name Various dot products. */
+      //@{
+      /** Return <code>A * x</code> (multiplied from the "right" direction) in
+	  <code>y</code>.
+	  @pre <code>x</code> must be of size <code>majorDim()</code>
+	  @pre <code>y</code> must be of size <code>minorDim()</code> */
+      void timesMajor(const double * x, double * y) const;
+#ifndef CLP_NO_VECTOR
+      /** Return <code>A * x</code> (multiplied from the "right" direction) in
+	  <code>y</code>. Same as the previous method, just <code>x</code> is
+	  given in the form of a packed vector. */
+      void timesMajor(const CoinPackedVectorBase& x, double * y) const;
+#endif
+      /** Return <code>A * x</code> (multiplied from the "right" direction) in
+	  <code>y</code>.
+	  @pre <code>x</code> must be of size <code>minorDim()</code>
+	  @pre <code>y</code> must be of size <code>majorDim()</code> */
+      void timesMinor(const double * x, double * y) const;
+#ifndef CLP_NO_VECTOR
+      /** Return <code>A * x</code> (multiplied from the "right" direction) in
+	  <code>y</code>. Same as the previous method, just <code>x</code> is
+	  given in the form of a packed vector. */
+      void timesMinor(const CoinPackedVectorBase& x, double * y) const;
+#endif
+      //@}
+   //@}
+
+   //--------------------------------------------------------------------------
+   /**@name Logical Operations. */
+   //@{
+#ifndef CLP_NO_VECTOR
+   /*! \brief Test for equivalence.
+
+       Two matrices are equivalent if they are both row- or column-ordered,
+       they have the same dimensions, and each (major) vector is equivalent.
+       The operator used to test for equality can be specified using the
+       \p FloatEqual template parameter.
+   */
+   template <class FloatEqual> bool 
+   isEquivalent(const CoinPackedMatrix& rhs, const FloatEqual& eq) const
+   {
+      // Both must be column order or both row ordered and must be of same size
+      if ((isColOrdered() ^ rhs.isColOrdered()) ||
+	  (getNumCols() != rhs.getNumCols()) ||
+	  (getNumRows() != rhs.getNumRows()) ||
+	  (getNumElements() != rhs.getNumElements()))
+	 return false;
+     
+      for (int i=getMajorDim()-1; i >= 0; --i) {
+        CoinShallowPackedVector pv = getVector(i);
+        CoinShallowPackedVector rhsPv = rhs.getVector(i);
+        if ( !pv.isEquivalent(rhsPv,eq) )
+          return false;
+      }
+      return true;
+   }
+
+  /*! \brief Test for equivalence and report differences
+
+    Equivalence is defined as for #isEquivalent. In addition, this method will
+    print differences to std::cerr. Intended for use in unit tests and
+    for debugging.
+  */
+  bool isEquivalent2(const CoinPackedMatrix& rhs) const;
+#else
+   /*! \brief Test for equivalence.
+
+       Two matrices are equivalent if they are both row- or column-ordered,
+       they have the same dimensions, and each (major) vector is equivalent.
+       This method is optimised for speed. CoinPackedVector#isEquivalent is
+       replaced with more efficient code for repeated comparison of
+       equal-length vectors. The CoinRelFltEq operator is used. 
+   */
+  bool isEquivalent(const CoinPackedMatrix& rhs, const CoinRelFltEq & eq) const;
+#endif
+   /*! \brief Test for equivalence.
+   
+     The test for element equality is the default CoinRelFltEq operator.
+   */
+   bool isEquivalent(const CoinPackedMatrix& rhs) const;
+   //@}
+
+   //--------------------------------------------------------------------------
+   /*! \name Non-const methods
+
+     These are to be used with great care when doing column generation, etc.
+   */
+   //@{
+    /** A vector containing the elements in the packed matrix. Note that there
+	might be gaps in this list, entries that do not belong to any
+	major-dimension vector. To get the actual elements one should look at
+	this vector together with #start_ and #length_. */
+    inline double * getMutableElements() const { return element_; }
+    /** A vector containing the minor indices of the elements in the packed
+        matrix. Note that there might be gaps in this list, entries that do not
+        belong to any major-dimension vector. To get the actual elements one
+        should look at this vector together with #start_ and
+        #length_. */
+    inline int * getMutableIndices() const { return index_; }
+
+    /** The positions where the major-dimension vectors start in #element_ and
+        #index_. */
+    inline CoinBigIndex * getMutableVectorStarts() const { return start_; }
+    /** The lengths of the major-dimension vectors. */
+    inline int * getMutableVectorLengths() const { return length_; }
+    /// Change the size of the bulk store after modifying - be careful
+    inline void setNumElements(CoinBigIndex value)
+    { size_ = value;}
+    /*! NULLify element array
+    
+      Used when space is very tight. Does not free the space!
+    */
+    inline void nullElementArray() {element_=NULL;}
+
+    /*! NULLify start array
+    
+      Used when space is very tight. Does not free the space!
+    */
+    inline void nullStartArray() {start_=NULL;}
+
+    /*! NULLify length array
+    
+      Used when space is very tight. Does not free the space!
+    */
+    inline void nullLengthArray() {length_=NULL;}
+
+    /*! NULLify index array
+    
+      Used when space is very tight. Does not free the space!
+    */
+    inline void nullIndexArray() {index_=NULL;}
+   //@}
+
+   //--------------------------------------------------------------------------
+   /*! \name Constructors and destructors */
+   //@{
+   /// Default Constructor creates an empty column ordered packed matrix
+   CoinPackedMatrix();
+
+   /// A constructor where the ordering and the gaps are specified
+   CoinPackedMatrix(const bool colordered,
+		   const double extraMajor, const double extraGap);
+
+   CoinPackedMatrix(const bool colordered,
+		   const int minor, const int major, const CoinBigIndex numels,
+		   const double * elem, const int * ind,
+		   const CoinBigIndex * start, const int * len,
+		   const double extraMajor, const double extraGap);
+
+   CoinPackedMatrix(const bool colordered,
+		   const int minor, const int major, const CoinBigIndex numels,
+		   const double * elem, const int * ind,
+		   const CoinBigIndex * start, const int * len);
+
+   /** Create packed matrix from triples.
+       If colordered is true then the created matrix will be column ordered.
+       Duplicate matrix elements are allowed. The created matrix will have 
+       the sum of the duplicates. <br>
+       For example if: <br>
+         rowIndices[0]=2; colIndices[0]=5; elements[0]=2.0 <br>
+         rowIndices[1]=2; colIndices[1]=5; elements[1]=0.5 <br>
+       then the created matrix will contain a value of 2.5 in row 2 and column 5.<br>
+       The matrix is created without gaps.
+   */
+   CoinPackedMatrix(const bool colordered,
+     const int * rowIndices, 
+     const int * colIndices, 
+     const double * elements, 
+     CoinBigIndex numels ); 
+
+   /// Copy constructor 
+   CoinPackedMatrix(const CoinPackedMatrix& m);
+
+  /*! \brief Copy constructor with fine tuning
+  
+    This constructor allows for the specification of an exact amount of extra
+    space and/or reverse ordering.
+
+    \p extraForMajor is the exact number of spare major vector slots after
+    any possible reverse ordering. If \p extraForMajor < 0, all gaps and small
+    elements will be removed from the copy, otherwise gaps and small elements
+    are preserved.
+
+    \p extraElements is the exact number of spare element entries.
+
+    The usual multipliers, #extraMajor_ and #extraGap_, are set to zero.
+  */
+  CoinPackedMatrix(const CoinPackedMatrix &m,
+  		   int extraForMajor, int extraElements,
+		   bool reverseOrdering = false) ;
+
+  /** Subset constructor (without gaps).  Duplicates are allowed
+      and order is as given */
+  CoinPackedMatrix (const CoinPackedMatrix & wholeModel,
+		    int numberRows, const int * whichRows,
+		    int numberColumns, const int * whichColumns);
+
+   /// Destructor 
+   virtual ~CoinPackedMatrix();    
+   //@}
+
+  /*! \name Debug Utilities */
+  //@{
+    /*! \brief Scan the matrix for anomalies.
+
+	Returns the number of anomalies. Scans the structure for gaps,
+	obviously bogus indices and coefficients, and inconsistencies. Gaps
+	are not an error unless #hasGaps() says the matrix should be
+	gap-free. Zeroes are not an error unless \p zeroesAreError is set to
+	true.
+	
+	Values for verbosity are:
+	- 0: No messages, just the return value
+	- 1: Messages about errors
+	- 2: If there are no errors, a message indicating the matrix was
+	     checked is printed (positive confirmation).
+	- 3: Adds a bit more information about the matrix.
+	- 4: Prints warnings about zeroes even if they're not considered
+	     errors.
+
+	Obviously bogus coefficients are coefficients that are NaN or have
+	absolute value greater than 1e50. Zeros have absolute value less
+	than 1e-50.
+      */
+    int verifyMtx(int verbosity = 1, bool zeroesAreError = false) const ;
+  //@}
+
+  //--------------------------------------------------------------------------
+protected:
+   void gutsOfDestructor();
+   void gutsOfCopyOf(const bool colordered,
+		     const int minor, const int major, const CoinBigIndex numels,
+		     const double * elem, const int * ind,
+		     const CoinBigIndex * start, const int * len,
+		     const double extraMajor=0.0, const double extraGap=0.0);
+   /// When no gaps we can do faster
+   void gutsOfCopyOfNoGaps(const bool colordered,
+		     const int minor, const int major,
+		     const double * elem, const int * ind,
+                           const CoinBigIndex * start);
+   void gutsOfOpEqual(const bool colordered,
+		      const int minor, const int major, const CoinBigIndex numels,
+		      const double * elem, const int * ind,
+		      const CoinBigIndex * start, const int * len);
+   void resizeForAddingMajorVectors(const int numVec, const int * lengthVec);
+   void resizeForAddingMinorVectors(const int * addedEntries);
+
+    /*! \brief Append a set of rows (columns) to the end of a row (colum)
+    	       ordered matrix.
+	
+      If \p numberOther > 0 the method will check if any of the new rows
+      (columns) contain duplicate indices or invalid indices and return the
+      number of errors. A valid minor index must satisfy
+      \code 0 <= k < numberOther \endcode
+      If \p numberOther < 0 no checking is performed.
+    */
+    int appendMajor(const int number,
+		    const CoinBigIndex * starts, const int * index,
+                    const double * element, int numberOther=-1);
+    /*! \brief Append a set of rows (columns) to the end of a column (row)
+    	       ordered matrix.
+    
+      If \p numberOther > 0 the method will check if any of the new rows
+      (columns) contain duplicate indices or indices outside the current
+      range for the major dimension and return the number of violations.
+      If \p numberOther <= 0 the major dimension will be expanded as
+      necessary and there are no checks for duplicate indices.
+    */
+    int appendMinor(const int number,
+		    const CoinBigIndex * starts, const int * index,
+                    const double * element, int numberOther=-1);
+
+private:
+   inline CoinBigIndex getLastStart() const {
+      return majorDim_ == 0 ? 0 : start_[majorDim_];
+   }
+
+   //--------------------------------------------------------------------------
+protected:
+   /**@name Data members
+      The data members are protected to allow access for derived classes. */
+   //@{
+   /** A flag indicating whether the matrix is column or row major ordered. */
+   bool     colOrdered_;
+   /** This much times more space should be allocated for each major-dimension
+       vector (with respect to the number of entries in the vector) when the
+       matrix is resized. The purpose of these gaps is to allow fast insertion
+       of new minor-dimension vectors. */
+   double   extraGap_;
+   /** his much times more space should be allocated for major-dimension
+       vectors when the matrix is resized. The purpose of these gaps is to
+       allow fast addition of new major-dimension vectors. */
+   double   extraMajor_;
+
+   /** List of nonzero element values. The entries in the gaps between
+       major-dimension vectors are undefined. */
+   double  *element_;
+   /** List of nonzero element minor-dimension indices. The entries in the gaps
+       between major-dimension vectors are undefined. */
+   int     *index_;
+   /** Starting positions of major-dimension vectors. */
+   CoinBigIndex     *start_;
+   /** Lengths of major-dimension vectors. */
+   int     *length_;
+
+   /// number of vectors in matrix
+   int majorDim_;
+   /// size of other dimension
+   int minorDim_;
+   /// the number of nonzero entries
+   CoinBigIndex size_;
+
+   /// max space allocated for major-dimension
+   int maxMajorDim_;
+   /// max space allocated for entries
+   CoinBigIndex maxSize_;
+   //@}
+};
+
+//#############################################################################
+/*! \brief Test the methods in the CoinPackedMatrix class.
+
+    The only reason for it not to be a member method is that this way
+    it doesn't have to be compiled into the library. And that's a gain,
+    because the library should be compiled with optimization on, but this
+    method should be compiled with debugging.
+*/
+void
+CoinPackedMatrixUnitTest();
+
+#endif
diff --git a/cbits/coin/CoinPackedVector.cpp b/cbits/coin/CoinPackedVector.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPackedVector.cpp
@@ -0,0 +1,525 @@
+/* $Id: CoinPackedVector.cpp 1509 2011-12-05 13:50:48Z forrest $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+
+//#############################################################################
+
+void
+CoinPackedVector::clear()
+{
+   nElements_ = 0;
+   clearBase();
+}
+
+//#############################################################################
+
+CoinPackedVector &
+CoinPackedVector::operator=(const CoinPackedVector & rhs)
+{
+   if (this != &rhs) {
+      clear();
+      gutsOfSetVector(rhs.getVectorNumElements(), rhs.getVectorIndices(), rhs.getVectorElements(),
+		      CoinPackedVectorBase::testForDuplicateIndex(),
+		      "operator=");
+   }
+   return *this;
+}
+
+//#############################################################################
+
+CoinPackedVector &
+CoinPackedVector::operator=(const CoinPackedVectorBase & rhs)
+{
+   if (this != &rhs) {
+      clear();
+      gutsOfSetVector(rhs.getNumElements(), rhs.getIndices(), rhs.getElements(),
+		      CoinPackedVectorBase::testForDuplicateIndex(),
+		      "operator= from base");
+   }
+   return *this;
+}
+
+//#############################################################################
+#if 0
+void
+CoinPackedVector::assignVector(int size, int*& inds, double*& elems,
+			      bool testForDuplicateIndex)
+{
+   clear();
+   // Allocate storage
+   if ( size != 0 ) {
+      reserve(size);
+      nElements_ = size;
+      indices_ = inds;    inds = NULL;
+      elements_ = elems;  elems = NULL;
+      CoinIotaN(origIndices_, size, 0);
+   }
+   try {
+      CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex);
+   }
+   catch (CoinError& e) {
+      throw CoinError("duplicate index", "assignVector", "CoinPackedVector");
+   }
+}
+#else
+void
+CoinPackedVector::assignVector(int size, int*& inds, double*& elems,
+                              bool testForDuplicateIndex)
+{
+  clear();
+  // Allocate storage
+  if ( size != 0 ) {
+		  //reserve(size); //This is a BUG!!!
+    nElements_ = size;
+    if (indices_ != NULL) delete[] indices_;
+    indices_ = inds;    inds = NULL;
+    if (elements_ != NULL) delete[] elements_;
+    elements_ = elems;  elems = NULL;
+    if (origIndices_ != NULL) delete[] origIndices_;
+    origIndices_ = new int[size];
+    CoinIotaN(origIndices_, size, 0);
+    capacity_ = size;
+  }
+  if (testForDuplicateIndex) {
+    try {    
+      CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex);
+    }
+    catch (CoinError& e) {
+    throw CoinError("duplicate index", "assignVector",
+		    "CoinPackedVector");
+    }
+  } else {
+    setTestsOff();
+  }
+}
+#endif
+
+//#############################################################################
+
+void
+CoinPackedVector::setVector(int size, const int * inds, const double * elems,
+			   bool testForDuplicateIndex)
+{
+   clear();
+   gutsOfSetVector(size, inds, elems, testForDuplicateIndex, "setVector");
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::setConstant(int size, const int * inds, double value,
+			     bool testForDuplicateIndex)
+{
+   clear();
+   gutsOfSetConstant(size, inds, value, testForDuplicateIndex, "setConstant");
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::setFull(int size, const double * elems,
+			 bool testForDuplicateIndex) 
+{
+  // Clear out any values presently stored
+  clear();
+  
+  // Allocate storage
+  if ( size!=0 ) {
+    reserve(size);  
+    nElements_ = size;
+
+    CoinIotaN(origIndices_, size, 0);
+    CoinIotaN(indices_, size, 0);
+    CoinDisjointCopyN(elems, size, elements_);
+  }
+  // Full array can not have duplicates
+  CoinPackedVectorBase::setTestForDuplicateIndexWhenTrue(testForDuplicateIndex);
+}
+
+//#############################################################################
+/* Indices are not specified and are taken to be 0,1,...,size-1,
+    but only where non zero*/
+
+void
+CoinPackedVector::setFullNonZero(int size, const double * elems,
+			 bool testForDuplicateIndex) 
+{
+  // Clear out any values presently stored
+  clear();
+
+  // For now waste space
+  // Allocate storage
+  if ( size!=0 ) {
+    reserve(size);  
+    nElements_ = 0;
+    int i;
+    for (i=0;i<size;i++) {
+      if (elems[i]) {
+	origIndices_[nElements_]= i;
+	indices_[nElements_]= i;
+	elements_[nElements_++] = elems[i];
+      }
+    }
+  }
+  // Full array can not have duplicates
+  CoinPackedVectorBase::setTestForDuplicateIndexWhenTrue(testForDuplicateIndex);
+}
+
+
+//#############################################################################
+
+void
+CoinPackedVector::setElement(int index, double element)
+{
+#ifndef COIN_FAST_CODE
+   if ( index >= nElements_ ) 
+      throw CoinError("index >= size()", "setElement", "CoinPackedVector");
+   if ( index < 0 ) 
+      throw CoinError("index < 0" , "setElement", "CoinPackedVector");
+#endif
+   elements_[index] = element;
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::insert( int index, double element )
+{
+   const int s = nElements_;
+   if (testForDuplicateIndex()) {
+      std::set<int>& is = *indexSet("insert", "CoinPackedVector");
+      if (! is.insert(index).second)
+	 throw CoinError("Index already exists", "insert", "CoinPackedVector");
+   }
+
+   if( capacity_ <= s ) {
+      reserve( CoinMax(5, 2*capacity_) );
+      assert( capacity_ > s );
+   }
+   indices_[s] = index;
+   elements_[s] = element;
+   origIndices_[s] = s;
+   ++nElements_;
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::append(const CoinPackedVectorBase & caboose)
+{
+   const int cs = caboose.getNumElements();
+   if (cs == 0) {
+       return;
+   }
+   if (testForDuplicateIndex()) {
+       // Just to initialize the index heap
+       indexSet("append (1st call)", "CoinPackedVector");
+   }
+   const int s = nElements_;
+   // Make sure there is enough room for the caboose
+   if ( capacity_ < s + cs)
+      reserve(CoinMax(s + cs, 2 * capacity_));
+
+   const int * cind = caboose.getIndices();
+   const double * celem = caboose.getElements();
+   CoinDisjointCopyN(cind, cs, indices_ + s);
+   CoinDisjointCopyN(celem, cs, elements_ + s);
+   CoinIotaN(origIndices_ + s, cs, s);
+   nElements_ += cs;
+   if (testForDuplicateIndex()) {
+      std::set<int>& is = *indexSet("append (2nd call)", "CoinPackedVector");
+      for (int i = 0; i < cs; ++i) {
+	 if (!is.insert(cind[i]).second)
+	    throw CoinError("duplicate index", "append", "CoinPackedVector");
+      }
+   }
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::swap(int i, int j)
+{
+   if ( i >= nElements_ ) 
+      throw CoinError("index i >= size()","swap","CoinPackedVector");
+   if ( i < 0 ) 
+      throw CoinError("index i < 0" ,"swap","CoinPackedVector");
+   if ( i >= nElements_ ) 
+      throw CoinError("index j >= size()","swap","CoinPackedVector");
+   if ( i < 0 ) 
+      throw CoinError("index j < 0" ,"swap","CoinPackedVector");
+
+   // Swap positions i and j of the
+   // indices and elements arrays
+   std::swap(indices_[i], indices_[j]);
+   std::swap(elements_[i], elements_[j]);
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::truncate( int n )
+{
+   if ( n > nElements_ ) 
+      throw CoinError("n > size()","truncate","CoinPackedVector");
+   if ( n < 0 ) 
+      throw CoinError("n < 0","truncate","CoinPackedVector");
+   nElements_ = n;
+   clearBase();
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::operator+=(double value) 
+{
+   std::transform(elements_, elements_ + nElements_, elements_,
+		  std::bind2nd(std::plus<double>(), value) );
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedVector::operator-=(double value) 
+{
+   std::transform(elements_, elements_ + nElements_, elements_,
+		  std::bind2nd(std::minus<double>(), value) );
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedVector::operator*=(double value) 
+{
+   std::transform(elements_, elements_ + nElements_, elements_,
+		  std::bind2nd(std::multiplies<double>(), value) );
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedVector::operator/=(double value) 
+{
+   std::transform(elements_, elements_ + nElements_, elements_,
+		  std::bind2nd(std::divides<double>(), value) );
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::sortOriginalOrder() {
+  CoinSort_3(origIndices_, origIndices_ + nElements_, indices_, elements_);
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::reserve(int n)
+{
+   // don't make allocated space smaller
+   if ( n <= capacity_ )
+      return;
+   capacity_ = n;
+
+   // save pointers to existing data
+   int * tempIndices = indices_;
+   int * tempOrigIndices = origIndices_;
+   double * tempElements = elements_;
+
+   // allocate new space
+   indices_ = new int [capacity_];
+   origIndices_ = new int [capacity_];
+   elements_ = new double [capacity_];
+
+   // copy data to new space
+   if (nElements_ > 0) {
+      CoinDisjointCopyN(tempIndices, nElements_, indices_);
+      CoinDisjointCopyN(tempOrigIndices, nElements_, origIndices_);
+      CoinDisjointCopyN(tempElements, nElements_, elements_);
+   }
+
+   // free old data
+   delete [] tempElements;
+   delete [] tempOrigIndices;
+   delete [] tempIndices;
+}
+
+//#############################################################################
+
+CoinPackedVector::CoinPackedVector (bool testForDuplicateIndex) :
+   CoinPackedVectorBase(),
+   indices_(NULL),
+   elements_(NULL),
+   nElements_(0),
+   origIndices_(NULL),
+   capacity_(0)
+{
+   // This won't fail, the packed vector is empty. There can't be duplicate
+   // indices.
+   CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex);
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedVector::CoinPackedVector(int size,
+				 const int * inds, const double * elems,
+				 bool testForDuplicateIndex) :
+   CoinPackedVectorBase(),
+   indices_(NULL),
+   elements_(NULL),
+   nElements_(0),
+   origIndices_(NULL),
+   capacity_(0)
+{
+   gutsOfSetVector(size, inds, elems, testForDuplicateIndex,
+		   "constructor for array value");
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedVector::CoinPackedVector(int size,
+				 const int * inds, double value,
+				 bool testForDuplicateIndex) :
+   CoinPackedVectorBase(),
+   indices_(NULL),
+   elements_(NULL),
+   nElements_(0),
+   origIndices_(NULL),
+   capacity_(0)
+{
+   gutsOfSetConstant(size, inds, value, testForDuplicateIndex,
+		     "constructor for constant value");
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedVector::CoinPackedVector(int capacity, int size,
+ 				   int *&inds, double *&elems,
+				   bool /*testForDuplicateIndex*/) :
+    CoinPackedVectorBase(),
+    indices_(inds),
+    elements_(elems),
+    nElements_(size),
+    origIndices_(NULL),
+    capacity_(capacity)
+{
+   assert( size <= capacity );
+   inds = NULL;
+   elems = NULL;
+   origIndices_ = new int[capacity_];
+   CoinIotaN(origIndices_, size, 0);
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedVector::CoinPackedVector(int size, const double * element,
+				 bool testForDuplicateIndex) :
+   CoinPackedVectorBase(),
+   indices_(NULL),
+   elements_(NULL),
+   nElements_(0),
+   origIndices_(NULL),
+   capacity_(0)
+{
+   setFull(size, element, testForDuplicateIndex);
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedVector::CoinPackedVector(const CoinPackedVectorBase & rhs) :
+   CoinPackedVectorBase(),
+   indices_(NULL),
+   elements_(NULL),
+   nElements_(0),
+   origIndices_(NULL),
+   capacity_(0)
+{  
+   gutsOfSetVector(rhs.getNumElements(), rhs.getIndices(), rhs.getElements(),
+		   rhs.testForDuplicateIndex(), "copy constructor from base");
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedVector::CoinPackedVector(const CoinPackedVector & rhs) :
+   CoinPackedVectorBase(),
+   indices_(NULL),
+   elements_(NULL),
+   nElements_(0),
+   origIndices_(NULL),
+   capacity_(0)
+{  
+   gutsOfSetVector(rhs.getVectorNumElements(), rhs.getVectorIndices(), rhs.getVectorElements(),
+		   rhs.testForDuplicateIndex(), "copy constructor");
+}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedVector::~CoinPackedVector ()
+{
+   delete [] indices_;
+   delete [] origIndices_;
+   delete [] elements_;
+}
+
+//#############################################################################
+
+void
+CoinPackedVector::gutsOfSetVector(int size,
+				 const int * inds, const double * elems,
+				 bool testForDuplicateIndex,
+				 const char * method)
+{
+   if ( size != 0 ) {
+      reserve(size);
+      nElements_ = size;
+      CoinDisjointCopyN(inds, size, indices_);
+      CoinDisjointCopyN(elems, size, elements_);
+      CoinIotaN(origIndices_, size, 0);
+   }
+   if (testForDuplicateIndex) {
+     try {
+       CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex);
+     }
+     catch (CoinError& e) {
+       throw CoinError("duplicate index", method, "CoinPackedVector");
+     }
+   } else {
+     setTestsOff();
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedVector::gutsOfSetConstant(int size,
+				   const int * inds, double value,
+				   bool testForDuplicateIndex,
+				   const char * method)
+{
+   if ( size != 0 ) {
+      reserve(size);
+      nElements_ = size;
+      CoinDisjointCopyN(inds, size, indices_);
+      CoinFillN(elements_, size, value);
+      CoinIotaN(origIndices_, size, 0);
+   }
+   try {
+      CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex);
+   }
+   catch (CoinError& e) {
+      throw CoinError("duplicate index", method, "CoinPackedVector");
+   }
+}
+
+//#############################################################################
diff --git a/cbits/coin/CoinPackedVector.hpp b/cbits/coin/CoinPackedVector.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPackedVector.hpp
@@ -0,0 +1,657 @@
+/* $Id: CoinPackedVector.hpp 1509 2011-12-05 13:50:48Z forrest $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPackedVector_H
+#define CoinPackedVector_H
+
+#include <map>
+
+#include "CoinPragma.hpp"
+#include "CoinPackedVectorBase.hpp"
+#include "CoinSort.hpp"
+
+#ifdef COIN_FAST_CODE
+#ifndef COIN_NOTEST_DUPLICATE
+#define COIN_NOTEST_DUPLICATE
+#endif
+#endif
+
+#ifndef COIN_NOTEST_DUPLICATE
+#define COIN_DEFAULT_VALUE_FOR_DUPLICATE true
+#else
+#define COIN_DEFAULT_VALUE_FOR_DUPLICATE false
+#endif
+/** Sparse Vector
+
+Stores vector of indices and associated element values.
+Supports sorting of vector while maintaining the original indices.
+
+Here is a sample usage:
+@verbatim
+    const int ne = 4;
+    int inx[ne] =   {  1,   4,  0,   2 }
+    double el[ne] = { 10., 40., 1., 50. }
+
+    // Create vector and set its value
+    CoinPackedVector r(ne,inx,el);
+
+    // access each index and element
+    assert( r.indices ()[0]== 1  );
+    assert( r.elements()[0]==10. );
+    assert( r.indices ()[1]== 4  );
+    assert( r.elements()[1]==40. );
+    assert( r.indices ()[2]== 0  );
+    assert( r.elements()[2]== 1. );
+    assert( r.indices ()[3]== 2  );
+    assert( r.elements()[3]==50. );
+
+    // access original position of index
+    assert( r.originalPosition()[0]==0 );
+    assert( r.originalPosition()[1]==1 );
+    assert( r.originalPosition()[2]==2 );
+    assert( r.originalPosition()[3]==3 );
+
+    // access as a full storage vector
+    assert( r[ 0]==1. );
+    assert( r[ 1]==10.);
+    assert( r[ 2]==50.);
+    assert( r[ 3]==0. );
+    assert( r[ 4]==40.);
+
+    // sort Elements in increasing order
+    r.sortIncrElement();
+
+    // access each index and element
+    assert( r.indices ()[0]== 0  );
+    assert( r.elements()[0]== 1. );
+    assert( r.indices ()[1]== 1  );
+    assert( r.elements()[1]==10. );
+    assert( r.indices ()[2]== 4  );
+    assert( r.elements()[2]==40. );
+    assert( r.indices ()[3]== 2  );
+    assert( r.elements()[3]==50. );    
+
+    // access original position of index    
+    assert( r.originalPosition()[0]==2 );
+    assert( r.originalPosition()[1]==0 );
+    assert( r.originalPosition()[2]==1 );
+    assert( r.originalPosition()[3]==3 );
+
+    // access as a full storage vector
+    assert( r[ 0]==1. );
+    assert( r[ 1]==10.);
+    assert( r[ 2]==50.);
+    assert( r[ 3]==0. );
+    assert( r[ 4]==40.);
+
+    // Restore orignal sort order
+    r.sortOriginalOrder();
+    
+    assert( r.indices ()[0]== 1  );
+    assert( r.elements()[0]==10. );
+    assert( r.indices ()[1]== 4  );
+    assert( r.elements()[1]==40. );
+    assert( r.indices ()[2]== 0  );
+    assert( r.elements()[2]== 1. );
+    assert( r.indices ()[3]== 2  );
+    assert( r.elements()[3]==50. );
+
+    // Tests for equality and equivalence
+    CoinPackedVector r1;
+    r1=r;
+    assert( r==r1 );
+    assert( r.equivalent(r1) );
+    r.sortIncrElement();
+    assert( r!=r1 );
+    assert( r.equivalent(r1) );
+
+    // Add packed vectors.
+    // Similarly for subtraction, multiplication,
+    // and division.
+    CoinPackedVector add = r + r1;
+    assert( add[0] ==  1.+ 1. );
+    assert( add[1] == 10.+10. );
+    assert( add[2] == 50.+50. );
+    assert( add[3] ==  0.+ 0. );
+    assert( add[4] == 40.+40. );
+
+    assert( r.sum() == 10.+40.+1.+50. );
+@endverbatim
+*/
+class CoinPackedVector : public CoinPackedVectorBase {
+   friend void CoinPackedVectorUnitTest();
+  
+public:
+   /**@name Get methods. */
+   //@{
+   /// Get the size
+   virtual int getNumElements() const { return nElements_; }
+   /// Get indices of elements
+   virtual const int * getIndices() const { return indices_; }
+   /// Get element values
+   virtual const double * getElements() const { return elements_; }
+   /// Get indices of elements
+   int * getIndices() { return indices_; }
+   /// Get the size
+   inline int getVectorNumElements() const { return nElements_; }
+   /// Get indices of elements
+   inline const int * getVectorIndices() const { return indices_; }
+   /// Get element values
+   inline const double * getVectorElements() const { return elements_; }
+   /// Get element values
+   double * getElements() { return elements_; }
+   /** Get pointer to int * vector of original postions.
+       If the packed vector has not been sorted then this
+       function returns the vector: 0, 1, 2, ..., size()-1. */
+   const int * getOriginalPosition() const { return origIndices_; }
+   //@}
+ 
+   //-------------------------------------------------------------------
+   // Set indices and elements
+   //------------------------------------------------------------------- 
+   /**@name Set methods */
+   //@{
+   /// Reset the vector (as if were just created an empty vector)
+   void clear();
+   /** Assignment operator. <br>
+       <strong>NOTE</strong>: This operator keeps the current
+       <code>testForDuplicateIndex</code> setting, and affter copying the data
+       it acts accordingly. */
+   CoinPackedVector & operator=(const CoinPackedVector &);
+   /** Assignment operator from a CoinPackedVectorBase. <br>
+       <strong>NOTE</strong>: This operator keeps the current
+       <code>testForDuplicateIndex</code> setting, and affter copying the data
+       it acts accordingly. */
+   CoinPackedVector & operator=(const CoinPackedVectorBase & rhs);
+
+   /** Assign the ownership of the arguments to this vector.
+       Size is the length of both the indices and elements vectors.
+       The indices and elements vectors are copied into this class instance's
+       member data. The last argument indicates whether this vector will have
+       to be tested for duplicate indices.
+   */
+   void assignVector(int size, int*& inds, double*& elems,
+		     bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+
+   /** Set vector size, indices, and elements.
+       Size is the length of both the indices and elements vectors.
+       The indices and elements vectors are copied into this class instance's
+       member data. The last argument specifies whether this vector will have
+       to be checked for duplicate indices whenever that can happen. */
+   void setVector(int size, const int * inds, const double * elems,
+		  bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+  
+   /** Elements set to have the same scalar value */
+   void setConstant(int size, const int * inds, double elems,
+		    bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+  
+   /** Indices are not specified and are taken to be 0,1,...,size-1 */
+   void setFull(int size, const double * elems,
+		bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+
+   /** Indices are not specified and are taken to be 0,1,...,size-1,
+    but only where non zero*/
+   void setFullNonZero(int size, const double * elems,
+		bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+
+   /** Set an existing element in the packed vector
+       The first argument is the "index" into the elements() array
+   */
+   void setElement(int index, double element);
+
+   /// Insert an element into the vector
+   void insert(int index, double element);
+   /// Append a CoinPackedVector to the end
+   void append(const CoinPackedVectorBase & caboose);
+
+   /// Swap values in positions i and j of indices and elements
+   void swap(int i, int j); 
+
+   /** Resize the packed vector to be the first newSize elements.
+       Problem with truncate: what happens with origIndices_ ??? */
+   void truncate(int newSize); 
+   //@}
+
+   /**@name Arithmetic operators. */
+   //@{
+   /// add <code>value</code> to every entry
+   void operator+=(double value);
+   /// subtract <code>value</code> from every entry
+   void operator-=(double value);
+   /// multiply every entry by <code>value</code>
+   void operator*=(double value);
+   /// divide every entry by <code>value</code>
+   void operator/=(double value);
+   //@}
+
+   /**@name Sorting */
+   //@{ 
+   /** Sort the packed storage vector.
+       Typcical usages:
+       <pre> 
+       packedVector.sort(CoinIncrIndexOrdered());   //increasing indices
+       packedVector.sort(CoinIncrElementOrdered()); // increasing elements
+       </pre>
+   */ 
+   template <class CoinCompare3>
+   void sort(const CoinCompare3 & tc)
+   { CoinSort_3(indices_, indices_ + nElements_, origIndices_, elements_,
+		tc); }
+
+   void sortIncrIndex()
+   { CoinSort_3(indices_, indices_ + nElements_, origIndices_, elements_,
+		CoinFirstLess_3<int, int, double>()); }
+
+   void sortDecrIndex()
+   { CoinSort_3(indices_, indices_ + nElements_, origIndices_, elements_,
+		CoinFirstGreater_3<int, int, double>()); }
+  
+   void sortIncrElement()
+   { CoinSort_3(elements_, elements_ + nElements_, origIndices_, indices_,
+		CoinFirstLess_3<double, int, int>()); }
+
+   void sortDecrElement()
+   { CoinSort_3(elements_, elements_ + nElements_, origIndices_, indices_,
+		CoinFirstGreater_3<double, int, int>()); }
+  
+
+   /** Sort in original order.
+       If the vector has been sorted, then this method restores
+       to its orignal sort order.
+   */
+   void sortOriginalOrder();
+   //@}
+
+   /**@name Memory usage */
+   //@{
+   /** Reserve space.
+       If one knows the eventual size of the packed vector,
+       then it may be more efficient to reserve the space.
+   */
+   void reserve(int n);
+   /** capacity returns the size which could be accomodated without
+       having to reallocate storage.
+   */
+   int capacity() const { return capacity_; }
+   //@}
+   /**@name Constructors and destructors */
+   //@{
+   /** Default constructor */
+   CoinPackedVector(bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+   /** \brief Alternate Constructors - set elements to vector of doubles
+   
+     This constructor copies the vectors provided as parameters.
+   */
+   CoinPackedVector(int size, const int * inds, const double * elems,
+		   bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+   /** \brief Alternate Constructors - set elements to vector of doubles
+
+     This constructor takes ownership of the vectors passed as parameters.
+     \p inds and \p elems will be NULL on return.
+   */
+   CoinPackedVector(int capacity, int size, int *&inds, double *&elems,
+		    bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+   /** Alternate Constructors - set elements to same scalar value */
+   CoinPackedVector(int size, const int * inds, double element,
+		   bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+   /** Alternate Constructors - construct full storage with indices 0 through
+       size-1. */
+   CoinPackedVector(int size, const double * elements,
+		   bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+   /** Copy constructor. */
+   CoinPackedVector(const CoinPackedVector &);
+   /** Copy constructor <em>from a PackedVectorBase</em>. */
+   CoinPackedVector(const CoinPackedVectorBase & rhs);
+   /** Destructor */
+   virtual ~CoinPackedVector ();
+   //@}
+    
+private:
+   /**@name Private methods */
+   //@{  
+   /// Copy internal date
+   void gutsOfSetVector(int size,
+			const int * inds, const double * elems,
+			bool testForDuplicateIndex,
+			const char * method);
+   ///
+   void gutsOfSetConstant(int size,
+			  const int * inds, double value,
+			  bool testForDuplicateIndex,
+			  const char * method);
+   //@}
+
+private:
+   /**@name Private member data */
+   //@{
+   /// Vector indices
+   int * indices_;
+   ///Vector elements
+   double * elements_;
+   /// Size of indices and elements vectors
+   int nElements_;
+   /// original unsorted indices
+   int * origIndices_;
+   /// Amount of memory allocated for indices_, origIndices_, and elements_.
+   int capacity_;
+   //@}
+};
+
+//#############################################################################
+
+/**@name Arithmetic operators on packed vectors.
+
+   <strong>NOTE</strong>: These methods operate on those positions where at
+   least one of the arguments has a value listed. At those positions the
+   appropriate operation is executed, Otherwise the result of the operation is
+   considered 0.<br>
+   <strong>NOTE 2</strong>: There are two kind of operators here. One is used
+   like "c = binaryOp(a, b)", the other is used like "binaryOp(c, a, b)", but
+   they are really the same. The first is much more natural to use, but it
+   involves the creation of a temporary object (the function *must* return an
+   object), while the second form puts the result directly into the argument
+   "c". Therefore, depending on the circumstances, the second form can be
+   significantly faster.
+ */
+//@{
+template <class BinaryFunction> void
+binaryOp(CoinPackedVector& retVal,
+	 const CoinPackedVectorBase& op1, double value,
+	 BinaryFunction bf)
+{
+   retVal.clear();
+   const int s = op1.getNumElements();
+   if (s > 0) {
+      retVal.reserve(s);
+      const int * inds = op1.getIndices();
+      const double * elems = op1.getElements();
+      for (int i=0; i<s; ++i ) {
+	 retVal.insert(inds[i], bf(value, elems[i]));
+      }
+   }
+}
+
+template <class BinaryFunction> inline void
+binaryOp(CoinPackedVector& retVal,
+	 double value, const CoinPackedVectorBase& op2,
+	 BinaryFunction bf)
+{
+   binaryOp(retVal, op2, value, bf);
+}
+
+template <class BinaryFunction> void
+binaryOp(CoinPackedVector& retVal,
+	 const CoinPackedVectorBase& op1, const CoinPackedVectorBase& op2,
+	 BinaryFunction bf)
+{
+   retVal.clear();
+   const int s1 = op1.getNumElements();
+   const int s2 = op2.getNumElements();
+/*
+  Replaced || with &&, in response to complaint from Sven deVries, who
+  rightly points out || is not appropriate for additive operations. &&
+  should be ok as long as binaryOp is understood not to create something
+  from nothing.		-- lh, 04.06.11
+*/
+   if (s1 == 0 && s2 == 0)
+      return;
+
+   retVal.reserve(s1+s2);
+
+   const int * inds1 = op1.getIndices();
+   const double * elems1 = op1.getElements();
+   const int * inds2 = op2.getIndices();
+   const double * elems2 = op2.getElements();
+
+   int i;
+   // loop once for each element in op1
+   for ( i=0; i<s1; ++i ) {
+      const int index = inds1[i];
+      const int pos2 = op2.findIndex(index);
+      const double val = bf(elems1[i], pos2 == -1 ? 0.0 : elems2[pos2]);
+      // if (val != 0.0) // *THINK* : should we put in only nonzeros?
+      retVal.insert(index, val);
+   }
+   // loop once for each element in operand2  
+   for ( i=0; i<s2; ++i ) {
+      const int index = inds2[i];
+      // if index exists in op1, then element was processed in prior loop
+      if ( op1.isExistingIndex(index) )
+	 continue;
+      // Index does not exist in op1, so the element value must be zero
+      const double val = bf(0.0, elems2[i]);
+      // if (val != 0.0) // *THINK* : should we put in only nonzeros?
+      retVal.insert(index, val);
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+template <class BinaryFunction> CoinPackedVector
+binaryOp(const CoinPackedVectorBase& op1, double value,
+	 BinaryFunction bf)
+{
+   CoinPackedVector retVal;
+   retVal.setTestForDuplicateIndex(true);
+   binaryOp(retVal, op1, value, bf);
+   return retVal;
+}
+
+template <class BinaryFunction> CoinPackedVector
+binaryOp(double value, const CoinPackedVectorBase& op2,
+	 BinaryFunction bf)
+{
+   CoinPackedVector retVal;
+   retVal.setTestForDuplicateIndex(true);
+   binaryOp(retVal, op2, value, bf);
+   return retVal;
+}
+
+template <class BinaryFunction> CoinPackedVector
+binaryOp(const CoinPackedVectorBase& op1, const CoinPackedVectorBase& op2,
+	 BinaryFunction bf)
+{
+   CoinPackedVector retVal;
+   retVal.setTestForDuplicateIndex(true);
+   binaryOp(retVal, op1, op2, bf);
+   return retVal;
+}
+
+//-----------------------------------------------------------------------------
+/// Return the sum of two packed vectors
+inline CoinPackedVector operator+(const CoinPackedVectorBase& op1,
+				  const CoinPackedVectorBase& op2)
+{
+   CoinPackedVector retVal;
+   retVal.setTestForDuplicateIndex(true);
+   binaryOp(retVal, op1, op2, std::plus<double>());
+   return retVal;
+}
+
+/// Return the difference of two packed vectors
+inline CoinPackedVector operator-(const CoinPackedVectorBase& op1,
+				 const CoinPackedVectorBase& op2)
+{
+   CoinPackedVector retVal;
+   retVal.setTestForDuplicateIndex(true);
+   binaryOp(retVal, op1, op2, std::minus<double>());
+   return retVal;
+}
+
+/// Return the element-wise product of two packed vectors
+inline CoinPackedVector operator*(const CoinPackedVectorBase& op1,
+				  const CoinPackedVectorBase& op2)
+{
+   CoinPackedVector retVal;
+   retVal.setTestForDuplicateIndex(true);
+   binaryOp(retVal, op1, op2, std::multiplies<double>());
+   return retVal;
+}
+
+/// Return the element-wise ratio of two packed vectors
+inline CoinPackedVector operator/(const CoinPackedVectorBase& op1,
+				  const CoinPackedVectorBase& op2)
+{
+   CoinPackedVector retVal;
+   retVal.setTestForDuplicateIndex(true);
+   binaryOp(retVal, op1, op2, std::divides<double>());
+   return retVal;
+}
+//@}
+
+/// Returns the dot product of two CoinPackedVector objects whose elements are
+/// doubles.  Use this version if the vectors are *not* guaranteed to be sorted.
+inline double sparseDotProduct(const CoinPackedVectorBase& op1,
+                        const CoinPackedVectorBase& op2){
+  int len, i;
+  double acc = 0.0;
+  CoinPackedVector retVal;
+
+  CoinPackedVector retval = op1*op2;
+  len = retval.getNumElements();
+  double * CParray = retval.getElements();
+
+  for(i = 0; i < len; i++){
+    acc += CParray[i];
+  }
+return acc;
+}
+
+
+/// Returns the dot product of two sorted CoinPackedVector objects.
+///  The vectors should be sorted in ascending order of indices.
+inline double sortedSparseDotProduct(const CoinPackedVectorBase& op1,
+                        const CoinPackedVectorBase& op2){
+  int i, j, len1, len2;
+  double acc = 0.0;
+
+  const double* v1val = op1.getElements();
+  const double* v2val = op2.getElements();
+  const int* v1ind = op1.getIndices();
+  const int* v2ind = op2.getIndices();
+
+  len1 = op1.getNumElements();
+  len2 = op2.getNumElements();
+
+  i = 0;
+  j = 0;
+
+  while(i < len1 && j < len2){
+    if(v1ind[i] == v2ind[j]){
+      acc += v1val[i] * v2val[j];
+      i++;
+      j++;
+   }
+    else if(v2ind[j] < v1ind[i]){
+      j++;
+    }
+    else{
+      i++;
+    } // end if-else-elseif
+  } // end while
+  return acc;
+ }
+
+
+//-----------------------------------------------------------------------------
+
+/**@name Arithmetic operators on packed vector and a constant. <br>
+   These functions create a packed vector as a result. That packed vector will
+   have the same indices as <code>op1</code> and the specified operation is
+   done entry-wise with the given value. */
+//@{
+/// Return the sum of a packed vector and a constant
+inline CoinPackedVector
+operator+(const CoinPackedVectorBase& op1, double value)
+{
+   CoinPackedVector retVal(op1);
+   retVal += value;
+   return retVal;
+}
+
+/// Return the difference of a packed vector and a constant
+inline CoinPackedVector
+operator-(const CoinPackedVectorBase& op1, double value)
+{
+   CoinPackedVector retVal(op1);
+   retVal -= value;
+   return retVal;
+}
+
+/// Return the element-wise product of a packed vector and a constant
+inline CoinPackedVector
+operator*(const CoinPackedVectorBase& op1, double value)
+{
+   CoinPackedVector retVal(op1);
+   retVal *= value;
+   return retVal;
+}
+
+/// Return the element-wise ratio of a packed vector and a constant
+inline CoinPackedVector
+operator/(const CoinPackedVectorBase& op1, double value)
+{
+   CoinPackedVector retVal(op1);
+   retVal /= value;
+   return retVal;
+}
+
+//-----------------------------------------------------------------------------
+
+/// Return the sum of a constant and a packed vector
+inline CoinPackedVector
+operator+(double value, const CoinPackedVectorBase& op1)
+{
+   CoinPackedVector retVal(op1);
+   retVal += value;
+   return retVal;
+}
+
+/// Return the difference of a constant and a packed vector
+inline CoinPackedVector
+operator-(double value, const CoinPackedVectorBase& op1)
+{
+   CoinPackedVector retVal(op1);
+   const int size = retVal.getNumElements();
+   double* elems = retVal.getElements();
+   for (int i = 0; i < size; ++i) {
+      elems[i] = value - elems[i];
+   }
+   return retVal;
+}
+
+/// Return the element-wise product of a constant and a packed vector
+inline CoinPackedVector
+operator*(double value, const CoinPackedVectorBase& op1)
+{
+   CoinPackedVector retVal(op1);
+   retVal *= value;
+   return retVal;
+}
+
+/// Return the element-wise ratio of a a constant and packed vector
+inline CoinPackedVector
+operator/(double value, const CoinPackedVectorBase& op1)
+{
+   CoinPackedVector retVal(op1);
+   const int size = retVal.getNumElements();
+   double* elems = retVal.getElements();
+   for (int i = 0; i < size; ++i) {
+      elems[i] = value / elems[i];
+   }
+   return retVal;
+}
+//@}
+
+//#############################################################################
+/** A function that tests the methods in the CoinPackedVector class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void
+CoinPackedVectorUnitTest();
+
+#endif
diff --git a/cbits/coin/CoinPackedVectorBase.cpp b/cbits/coin/CoinPackedVectorBase.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPackedVectorBase.cpp
@@ -0,0 +1,329 @@
+/* $Id: CoinPackedVectorBase.cpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <numeric>
+
+#include "CoinPackedVectorBase.hpp"
+#include "CoinTypes.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinFloatEqual.hpp"
+
+//#############################################################################
+
+double *
+CoinPackedVectorBase::denseVector(int denseSize) const
+{
+   if (getMaxIndex() >= denseSize)
+      throw CoinError("Dense vector size is less than max index",
+		     "denseVector", "CoinPackedVectorBase");
+
+   double * dv = new double[denseSize];
+   CoinFillN(dv, denseSize, 0.0);
+   const int s = getNumElements();
+   const int * inds = getIndices();
+   const double * elems = getElements();
+   for (int i = 0; i < s; ++i)
+      dv[inds[i]] = elems[i];
+   return dv;
+}
+
+//-----------------------------------------------------------------------------
+
+double
+CoinPackedVectorBase::operator[](int i) const
+{
+   if (! testedDuplicateIndex_)
+      duplicateIndex("operator[]", "CoinPackedVectorBase");
+
+   // Get a reference to a map of full storage indices to 
+   // packed storage location.
+   const std::set<int> & sv = *indexSet("operator[]", "CoinPackedVectorBase");
+#if 1
+   if (sv.find(i) == sv.end())
+      return 0.0;
+   return getElements()[findIndex(i)];
+#else
+   // LL: suggested change, somthing is wrong with this
+   const size_t ind = std::distance(sv.begin(), sv.find(i));
+   return (ind == sv.size()) ? 0.0 : getElements()[ind];
+#endif
+      
+}
+
+//#############################################################################
+
+void
+CoinPackedVectorBase::setTestForDuplicateIndex(bool test) const
+{
+   if (test == true) {
+      testForDuplicateIndex_ = true;
+      duplicateIndex("setTestForDuplicateIndex", "CoinPackedVectorBase");
+   } else {
+      testForDuplicateIndex_ = false;
+      testedDuplicateIndex_ = false;
+   }
+}
+
+//#############################################################################
+
+void
+CoinPackedVectorBase::setTestForDuplicateIndexWhenTrue(bool test) const
+{
+  // We know everything is okay so let's not test (e.g. full array)
+  testForDuplicateIndex_ = test;
+  testedDuplicateIndex_ = test;
+}
+
+//#############################################################################
+
+int
+CoinPackedVectorBase::getMaxIndex() const
+{
+   findMaxMinIndices();
+   return maxIndex_;
+}
+
+//-----------------------------------------------------------------------------
+
+int
+CoinPackedVectorBase::getMinIndex() const
+{
+   findMaxMinIndices();
+   return minIndex_;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedVectorBase::duplicateIndex(const char* methodName,
+				    const char * className) const
+{
+   if (testForDuplicateIndex())
+      indexSet(methodName, className);
+   testedDuplicateIndex_ = true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+CoinPackedVectorBase::isExistingIndex(int i) const
+{
+   if (! testedDuplicateIndex_)
+      duplicateIndex("indexExists", "CoinPackedVectorBase");
+
+   const std::set<int> & sv = *indexSet("indexExists", "CoinPackedVectorBase");
+   return sv.find(i) != sv.end();
+}
+
+
+int
+CoinPackedVectorBase::findIndex(int i) const
+{   
+   const int * inds = getIndices();
+   int retVal = static_cast<int>(std::find(inds, inds + getNumElements(), i) - inds);
+   if (retVal == getNumElements() ) retVal = -1;
+   return retVal;
+}
+
+//#############################################################################
+
+bool
+CoinPackedVectorBase::operator==(const CoinPackedVectorBase& rhs) const
+{  if (getNumElements() == 0 || rhs.getNumElements() == 0) {
+     if (getNumElements() == 0 && rhs.getNumElements() == 0)
+       return (true) ;
+     else
+       return (false) ;
+   } else {
+     return (getNumElements()==rhs.getNumElements() &&
+	     std::equal(getIndices(),getIndices()+getNumElements(),
+		        rhs.getIndices()) &&
+	     std::equal(getElements(),getElements()+getNumElements(),
+		        rhs.getElements())) ;
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+CoinPackedVectorBase::operator!=(const CoinPackedVectorBase& rhs) const
+{
+   return !( (*this)==rhs );
+}
+
+//-----------------------------------------------------------------------------
+
+int
+CoinPackedVectorBase::compare(const CoinPackedVectorBase& rhs) const
+{
+  const int size = getNumElements();
+  int itmp = size - rhs.getNumElements();
+  if (itmp != 0) {
+    return itmp;
+  }
+  itmp = memcmp(getIndices(), rhs.getIndices(), size * sizeof(int));
+  if (itmp != 0) {
+    return itmp;
+  }
+  return memcmp(getElements(), rhs.getElements(), size * sizeof(double));
+}
+
+bool
+CoinPackedVectorBase::isEquivalent(const CoinPackedVectorBase& rhs) const
+{
+   return isEquivalent(rhs,  CoinRelFltEq());
+}
+
+//#############################################################################
+
+double
+CoinPackedVectorBase::dotProduct(const double* dense) const
+{
+   const double * elems = getElements();
+   const int * inds = getIndices();
+   double dp = 0.0;
+   for (int i = getNumElements() - 1; i >= 0; --i)
+      dp += elems[i] * dense[inds[i]];
+   return dp;
+}
+
+//-----------------------------------------------------------------------------
+
+double
+CoinPackedVectorBase::oneNorm() const
+{
+   register double norm = 0.0;
+   register const double* elements = getElements();
+   for (int i = getNumElements() - 1; i >= 0; --i) {
+      norm += fabs(elements[i]);
+   }
+   return norm;
+}
+
+//-----------------------------------------------------------------------------
+
+double
+CoinPackedVectorBase::normSquare() const
+{
+   return std::inner_product(getElements(), getElements() + getNumElements(),
+			     getElements(), 0.0);
+}
+
+//-----------------------------------------------------------------------------
+
+double
+CoinPackedVectorBase::twoNorm() const
+{
+   return sqrt(normSquare());
+}
+
+//-----------------------------------------------------------------------------
+
+double
+CoinPackedVectorBase::infNorm() const
+{
+   register double norm = 0.0;
+   register const double* elements = getElements();
+   for (int i = getNumElements() - 1; i >= 0; --i) {
+      norm = CoinMax(norm, fabs(elements[i]));
+   }
+   return norm;
+}
+   
+//-----------------------------------------------------------------------------
+
+double
+CoinPackedVectorBase::sum() const
+{
+   return std::accumulate(getElements(), getElements() + getNumElements(), 0.0);
+}
+
+//#############################################################################
+
+CoinPackedVectorBase::CoinPackedVectorBase() :
+   maxIndex_(-COIN_INT_MAX/*0*/),
+   minIndex_(COIN_INT_MAX/*0*/),
+   indexSetPtr_(NULL),
+   testForDuplicateIndex_(true),
+   testedDuplicateIndex_(false) {}
+
+//-----------------------------------------------------------------------------
+
+CoinPackedVectorBase::~CoinPackedVectorBase()
+{
+   delete indexSetPtr_;
+}
+
+//#############################################################################
+//#############################################################################
+
+void
+CoinPackedVectorBase::findMaxMinIndices() const
+{
+   if ( getNumElements()==0 ) 
+      return;
+   // if indexSet exists then grab begin and rend to get min & max indices
+   else if ( indexSetPtr_ != NULL ) {
+      maxIndex_ = *indexSetPtr_->rbegin();
+      minIndex_ = *indexSetPtr_-> begin();
+   } else {
+      // Have to scan through vector to find min and max.
+      maxIndex_ = *(std::max_element(getIndices(),
+				     getIndices() + getNumElements()));
+      minIndex_ = *(std::min_element(getIndices(),
+				     getIndices() + getNumElements()));
+   }
+}
+
+//-------------------------------------------------------------------
+
+std::set<int> *
+CoinPackedVectorBase::indexSet(const char* methodName,
+			      const char * className) const
+{
+   testedDuplicateIndex_ = true;
+   if ( indexSetPtr_ == NULL ) {
+      // create a set of the indices
+      indexSetPtr_ = new std::set<int>;
+      const int s = getNumElements();
+      const int * inds = getIndices();
+      for (int j=0; j < s; ++j) {
+	 if (!indexSetPtr_->insert(inds[j]).second) {
+	    testedDuplicateIndex_ = false;
+	    delete indexSetPtr_;
+	    indexSetPtr_ = NULL;
+	    if (methodName != NULL) {
+	       throw CoinError("Duplicate index found", methodName, className);
+	    } else {
+	       throw CoinError("Duplicate index found",
+			      "indexSet", "CoinPackedVectorBase");
+	    }
+	 }
+      }
+   }
+   return indexSetPtr_;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedVectorBase::clearIndexSet() const
+{
+   delete indexSetPtr_;
+   indexSetPtr_ = NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+CoinPackedVectorBase::clearBase() const
+{
+   clearIndexSet();
+   maxIndex_ = -COIN_INT_MAX/*0*/;
+   minIndex_ = COIN_INT_MAX/*0*/;
+   testedDuplicateIndex_ = false;
+}
+
+//#############################################################################
diff --git a/cbits/coin/CoinPackedVectorBase.hpp b/cbits/coin/CoinPackedVectorBase.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPackedVectorBase.hpp
@@ -0,0 +1,269 @@
+/* $Id: CoinPackedVectorBase.hpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPackedVectorBase_H
+#define CoinPackedVectorBase_H
+
+#include <set>
+#include <map>
+#include "CoinPragma.hpp"
+#include "CoinError.hpp"
+
+class CoinPackedVector;
+
+/** Abstract base class for various sparse vectors.
+
+    Since this class is abstract, no object of this type can be created. The
+    sole purpose of this class is to provide access to a <em>constant</em>
+    packed vector. All members of this class are const methods, they can't
+    change the object. */
+
+class CoinPackedVectorBase  {
+  
+public:
+   /**@name Virtual methods that the derived classes must provide */
+   //@{
+   /// Get length of indices and elements vectors
+   virtual int getNumElements() const = 0;
+   /// Get indices of elements
+   virtual const int * getIndices() const = 0;
+   /// Get element values
+   virtual const double * getElements() const = 0;
+   //@}
+
+   /**@name Methods related to whether duplicate-index checking is performed.
+
+       If the checking for duplicate indices is turned off, then
+       some CoinPackedVector methods may not work correctly if there
+       are duplicate indices.
+       Turning off the checking for duplicate indices may result in
+       better run time performance.
+      */
+   //@{
+   /** \brief Set to the argument value whether to test for duplicate indices
+	      in the vector whenever they can occur.
+       
+       Calling this method with \p test set to true will trigger an immediate
+       check for duplicate indices.
+   */
+   void setTestForDuplicateIndex(bool test) const;
+   /** \brief Set to the argument value whether to test for duplicate indices
+	      in the vector whenever they can occur BUT we know that right
+	      now the vector has no duplicate indices.
+
+       Calling this method with \p test set to true will <em>not</em> trigger
+       an immediate check for duplicate indices; instead, it's assumed that
+       the result of the test will be true.
+   */
+   void setTestForDuplicateIndexWhenTrue(bool test) const;
+   /** Returns true if the vector should be tested for duplicate indices when
+       they can occur. */
+   bool testForDuplicateIndex() const { return testForDuplicateIndex_; }
+   /// Just sets test stuff false without a try etc
+   inline void setTestsOff() const
+   { testForDuplicateIndex_=false; testedDuplicateIndex_=false;}
+   //@}
+
+   /**@name Methods for getting info on the packed vector as a full vector */
+   //@{
+   /** Get the vector as a dense vector. The argument specifies how long this
+       dense vector is. <br>
+       <strong>NOTE</strong>: The user needs to <code>delete[]</code> this
+       pointer after it's not needed anymore.
+   */
+   double * denseVector(int denseSize) const;
+   /** Access the i'th element of the full storage vector.
+       If the i'th is not stored, then zero is returned. The initial use of
+       this method has some computational and storage overhead associated with
+       it.<br>
+       <strong>NOTE</strong>: This is <em>very</em> expensive. It is probably
+       much better to use <code>denseVector()</code>.
+   */
+   double operator[](int i) const; 
+   //@}
+
+   /**@name Index methods */
+   //@{
+   /// Get value of maximum index
+   int getMaxIndex() const;
+   /// Get value of minimum index
+   int getMinIndex() const;
+
+   /// Throw an exception if there are duplicate indices
+   void duplicateIndex(const char* methodName = NULL,
+		       const char * className = NULL) const;
+
+   /** Return true if the i'th element of the full storage vector exists in
+       the packed storage vector.*/
+   bool isExistingIndex(int i) const;
+   
+   /** Return the position of the i'th element of the full storage vector.
+       If index does not exist then -1 is returned  */
+   int findIndex(int i) const;
+ 
+   //@}
+  
+   /**@name Comparison operators on two packed vectors */
+   //@{
+   /** Equal. Returns true if vectors have same length and corresponding
+       element of each vector is equal. */
+   bool operator==(const CoinPackedVectorBase & rhs) const;
+   /// Not equal
+   bool operator!=(const CoinPackedVectorBase & rhs) const;
+
+#if 0
+   // LL: This should be implemented eventually. It is useful to have.
+   /** Lexicographic comparisons of two packed vectors. Returns
+       negative/0/positive depending on whether \c this is
+       smaller/equal.greater than \c rhs */
+   int lexCompare(const CoinPackedVectorBase& rhs);
+#endif
+  
+   /** This method establishes an ordering on packed vectors. It is complete
+       ordering, but not the same as lexicographic ordering. However, it is
+       quick and dirty to compute and thus it is useful to keep packed vectors
+       in a heap when all we care is to quickly check whether a particular
+       vector is already in the heap or not. Returns negative/0/positive
+       depending on whether \c this is smaller/equal.greater than \c rhs. */
+   int compare(const CoinPackedVectorBase& rhs) const;
+
+   /** equivalent - If shallow packed vector A & B are equivalent, then they
+       are still equivalent no matter how they are sorted.
+       In this method the FloatEqual function operator can be specified. The
+       default equivalence test is that the entries are relatively equal.<br> 
+       <strong>NOTE</strong>: This is a relatively expensive method as it
+       sorts the two shallow packed vectors.
+   */
+   template <class FloatEqual> bool
+   isEquivalent(const CoinPackedVectorBase& rhs, const FloatEqual& eq) const
+   {
+      if (getNumElements() != rhs.getNumElements())
+	 return false;
+
+      duplicateIndex("equivalent", "CoinPackedVector");
+      rhs.duplicateIndex("equivalent", "CoinPackedVector");
+
+      std::map<int,double> mv;
+      const int * inds = getIndices();
+      const double * elems = getElements();
+      int i;
+      for ( i = getNumElements() - 1; i >= 0; --i) {
+	 mv.insert(std::make_pair(inds[i], elems[i]));
+      }
+
+      std::map<int,double> mvRhs;
+      inds = rhs.getIndices();
+      elems = rhs.getElements();
+      for ( i = getNumElements() - 1; i >= 0; --i) {
+	 mvRhs.insert(std::make_pair(inds[i], elems[i]));
+      }
+
+      std::map<int,double>::const_iterator mvI = mv.begin();
+      std::map<int,double>::const_iterator mvIlast = mv.end();
+      std::map<int,double>::const_iterator mvIrhs = mvRhs.begin();
+      while (mvI != mvIlast) {
+	 if (mvI->first != mvIrhs->first || ! eq(mvI->second, mvIrhs->second))
+	    return false;
+	 ++mvI;
+	 ++mvIrhs;
+      }
+      return true;
+   }
+
+   bool isEquivalent(const CoinPackedVectorBase& rhs) const;
+   //@}
+
+
+   /**@name Arithmetic operators. */
+   //@{
+   /// Create the dot product with a full vector
+   double dotProduct(const double* dense) const;
+
+   /// Return the 1-norm of the vector
+   double oneNorm() const;
+
+   /// Return the square of the 2-norm of the vector
+   double normSquare() const;
+
+   /// Return the 2-norm of the vector
+   double twoNorm() const;
+
+   /// Return the infinity-norm of the vector
+   double infNorm() const;
+
+   /// Sum elements of vector.
+   double sum() const;
+   //@}
+
+protected:
+
+   /**@name Constructors, destructor
+      <strong>NOTE</strong>: All constructors are protected. There's no need
+      to expose them, after all, this is an abstract class. */
+   //@{
+   /** Default constructor. */
+   CoinPackedVectorBase();
+
+public:
+   /** Destructor */
+   virtual ~CoinPackedVectorBase();
+   //@}
+
+private:
+   /**@name Disabled methods */
+   //@{
+   /** The copy constructor. <br>
+       This must be at least protected, but we make it private. The reason is
+       that when, say, a shallow packed vector is created, first the
+       underlying class, it this one is constructed. However, at that point we
+       don't know how much of the data members of this class we need to copy
+       over. Therefore the copy constructor is not used. */
+   CoinPackedVectorBase(const CoinPackedVectorBase&);
+   /** This class provides <em>const</em> access to packed vectors, so there's
+       no need to provide an assignment operator. */
+   CoinPackedVectorBase& operator=(const CoinPackedVectorBase&);
+   //@}
+   
+protected:
+    
+   /**@name Protected methods */
+   //@{      
+   /// Find Maximum and Minimum Indices
+   void findMaxMinIndices() const;
+
+   /// Return indexSetPtr_ (create it if necessary).
+   std::set<int> * indexSet(const char* methodName = NULL,
+			    const char * className = NULL) const;
+
+   /// Delete the indexSet
+   void clearIndexSet() const;
+   void clearBase() const;
+   void copyMaxMinIndex(const CoinPackedVectorBase & x) const {
+      maxIndex_ = x.maxIndex_;
+      minIndex_ = x.minIndex_;
+   }
+   //@}
+    
+private:
+   /**@name Protected member data */
+   //@{
+   /// Contains max index value or -infinity
+   mutable int maxIndex_;
+   /// Contains minimum index value or infinity
+   mutable int minIndex_;
+   /** Store the indices in a set. This set is only created if it is needed.
+       Its primary use is testing for duplicate indices.
+    */
+   mutable std::set<int> * indexSetPtr_;
+   /** True if the vector should be tested for duplicate indices when they can
+       occur. */
+   mutable bool testForDuplicateIndex_;
+   /** True if the vector has already been tested for duplicate indices. Most
+       of the operations in CoinPackedVector preserves this flag. */
+   mutable bool testedDuplicateIndex_;
+   //@}
+};
+
+#endif
diff --git a/cbits/coin/CoinParam.cpp b/cbits/coin/CoinParam.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinParam.cpp
@@ -0,0 +1,566 @@
+/* $Id: CoinParam.cpp 1424 2011-05-02 08:02:28Z stefan $ */
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <string>
+#include <cassert>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinParam.hpp"
+
+/*
+  Constructors and destructors
+
+  There's a generic constructor and one for integer, double, keyword, string,
+  and action parameters.
+*/
+
+/*
+  Default constructor.
+*/
+CoinParam::CoinParam () 
+  : type_(coinParamInvalid),
+    name_(),
+    lengthName_(0),
+    lengthMatch_(0),
+    lowerDblValue_(0.0),
+    upperDblValue_(0.0),
+    dblValue_(0.0),
+    lowerIntValue_(0),
+    upperIntValue_(0),
+    intValue_(0),
+    strValue_(),
+    definedKwds_(),
+    currentKwd_(-1),
+    pushFunc_(0),
+    pullFunc_(0),
+    shortHelp_(),
+    longHelp_(),
+    display_(false)
+{
+  /* Nothing to be done here */
+}
+
+
+/*
+  Constructor for double parameter
+*/
+CoinParam::CoinParam (std::string name, std::string help,
+		      double lower, double upper, double dflt, bool display)
+  : type_(coinParamDbl),
+    name_(name),
+    lengthName_(0),
+    lengthMatch_(0),
+    lowerDblValue_(lower),
+    upperDblValue_(upper),
+    dblValue_(dflt),
+    lowerIntValue_(0),
+    upperIntValue_(0),
+    intValue_(0),
+    strValue_(),
+    definedKwds_(),
+    currentKwd_(-1),
+    pushFunc_(0),
+    pullFunc_(0),
+    shortHelp_(help),
+    longHelp_(),
+    display_(display)
+{
+  processName() ;
+}
+
+/*
+  Constructor for integer parameter
+*/
+CoinParam::CoinParam (std::string name, std::string help,
+		      int lower, int upper, int dflt, bool display)
+  : type_(coinParamInt),
+    name_(name),
+    lengthName_(0),
+    lengthMatch_(0),
+    lowerDblValue_(0.0),
+    upperDblValue_(0.0),
+    dblValue_(0.0),
+    lowerIntValue_(lower),
+    upperIntValue_(upper),
+    intValue_(dflt),
+    strValue_(),
+    definedKwds_(),
+    currentKwd_(-1),
+    pushFunc_(0),
+    pullFunc_(0),
+    shortHelp_(help),
+    longHelp_(),
+    display_(display)
+{
+  processName() ;
+}
+
+/*
+  Constructor for keyword parameter.
+*/
+CoinParam::CoinParam (std::string name, std::string help,
+		      std::string firstValue, int dflt, bool display)
+  : type_(coinParamKwd),
+    name_(name),
+    lengthName_(0),
+    lengthMatch_(0),
+    lowerDblValue_(0.0),
+    upperDblValue_(0.0),
+    dblValue_(0.0),
+    lowerIntValue_(0),
+    upperIntValue_(0),
+    intValue_(0),
+    strValue_(),
+    definedKwds_(),
+    currentKwd_(dflt),
+    pushFunc_(0),
+    pullFunc_(0),
+    shortHelp_(help),
+    longHelp_(),
+    display_(display)
+{
+  processName() ;
+  definedKwds_.push_back(firstValue) ;
+}
+
+/*
+  Constructor for string parameter.
+*/
+CoinParam::CoinParam (std::string name, std::string help,
+	 	      std::string dflt, bool display)
+  : type_(coinParamStr),
+    name_(name),
+    lengthName_(0),
+    lengthMatch_(0),
+    lowerDblValue_(0.0),
+    upperDblValue_(0.0),
+    dblValue_(0.0),
+    lowerIntValue_(0),
+    upperIntValue_(0),
+    intValue_(0),
+    strValue_(dflt),
+    definedKwds_(),
+    currentKwd_(0),
+    pushFunc_(0),
+    pullFunc_(0),
+    shortHelp_(help),
+    longHelp_(),
+    display_(display)
+{
+  processName() ;
+}
+
+/*
+  Constructor for action parameter.
+*/
+CoinParam::CoinParam (std::string name, std::string help, bool display)
+  : type_(coinParamAct),
+    name_(name),
+    lengthName_(0),
+    lengthMatch_(0),
+    lowerDblValue_(0.0),
+    upperDblValue_(0.0),
+    dblValue_(0.0),
+    lowerIntValue_(0),
+    upperIntValue_(0),
+    intValue_(0),
+    strValue_(),
+    definedKwds_(),
+    currentKwd_(0),
+    pushFunc_(0),
+    pullFunc_(0),
+    shortHelp_(help),
+    longHelp_(),
+    display_(display)
+{
+  processName() ;
+}
+
+/*
+  Copy constructor.
+*/
+CoinParam::CoinParam (const CoinParam &orig)
+  : type_(orig.type_),
+    lengthName_(orig.lengthName_),
+    lengthMatch_(orig.lengthMatch_),
+    lowerDblValue_(orig.lowerDblValue_),
+    upperDblValue_(orig.upperDblValue_),
+    dblValue_(orig.dblValue_),
+    lowerIntValue_(orig.lowerIntValue_),
+    upperIntValue_(orig.upperIntValue_),
+    intValue_(orig.intValue_),
+    currentKwd_(orig.currentKwd_),
+    pushFunc_(orig.pushFunc_),
+    pullFunc_(orig.pullFunc_),
+    display_(orig.display_)
+{
+  name_ = orig.name_ ;
+  strValue_ = orig.strValue_ ;
+  definedKwds_ = orig.definedKwds_ ;
+  shortHelp_ = orig.shortHelp_ ;
+  longHelp_ = orig.longHelp_ ;
+}
+
+/*
+  Clone
+*/
+
+CoinParam *CoinParam::clone ()
+{
+  return (new CoinParam(*this)) ;
+}
+
+CoinParam &CoinParam::operator= (const CoinParam &rhs)
+{
+  if (this != &rhs)
+  { type_ = rhs.type_ ;
+    name_ = rhs.name_ ;
+    lengthName_ = rhs.lengthName_ ;
+    lengthMatch_ = rhs.lengthMatch_ ;
+    lowerDblValue_ = rhs.lowerDblValue_ ;
+    upperDblValue_ = rhs.upperDblValue_ ;
+    dblValue_ = rhs.dblValue_ ;
+    lowerIntValue_ = rhs.lowerIntValue_ ;
+    upperIntValue_ = rhs.upperIntValue_ ;
+    intValue_ = rhs.intValue_ ;
+    strValue_ = rhs.strValue_ ;
+    definedKwds_ = rhs.definedKwds_ ;
+    currentKwd_ = rhs.currentKwd_ ;
+    pushFunc_ = rhs.pushFunc_ ;
+    pullFunc_ = rhs.pullFunc_ ;
+    shortHelp_ = rhs.shortHelp_ ;
+    longHelp_ = rhs.longHelp_ ;
+    display_ = rhs.display_ ; }
+
+  return *this ; }
+
+/*
+  Destructor
+*/
+CoinParam::~CoinParam ()
+{ /* Nothing more to do */ }
+
+
+/*
+  Methods to manipulate a CoinParam object.
+*/
+
+/*
+  Process the parameter name.
+  
+  Process the name for efficient matching: determine if an `!' is present. If
+  so, locate and record the position and remove the `!'.
+*/
+
+void CoinParam::processName()
+
+{ std::string::size_type shriekPos = name_.find('!') ;
+  lengthName_ = name_.length() ;
+  if (shriekPos == std::string::npos)
+  { lengthMatch_ = lengthName_ ; }
+  else
+  { lengthMatch_ = shriekPos ;
+    name_ = name_.substr(0,shriekPos)+name_.substr(shriekPos+1) ;
+    lengthName_-- ; }
+
+  return ; }
+
+/*
+  Check an input string to see if it matches the parameter name. The whole
+  input string must match, and the length of the match must exceed the
+  minimum match length. A match is impossible if the string is longer than
+  the name.
+
+  Returns: 0 for no match, 1 for a successful match, 2 if the match is short
+*/
+int CoinParam::matches (std::string input) const
+{
+  size_t inputLen = input.length() ;
+  if (inputLen <= lengthName_)
+  { size_t i ;
+    for (i = 0 ; i < inputLen ; i++)
+    { if (tolower(name_[i]) != tolower(input[i])) 
+	break ; }
+    if (i < inputLen)
+    { return (0) ; }
+    else
+    if (i >= lengthMatch_)
+    { return (1) ; }
+    else
+    { return (2) ; } }
+  
+  return (0) ;
+}
+
+
+/*
+  Return the parameter name, formatted to indicate how it'll be matched.
+  E.g., some!Name will come back as some(Name).
+*/
+std::string CoinParam::matchName () const
+{ 
+  if (lengthMatch_ == lengthName_) 
+  { return name_ ; }
+  else
+  { return name_.substr(0,lengthMatch_)+"("+name_.substr(lengthMatch_)+")" ; }
+}
+
+
+/*
+  Print the long help message and a message about appropriate values.
+*/
+void CoinParam::printLongHelp() const
+{
+  if (longHelp_ != "")
+  { CoinParamUtils::printIt(longHelp_.c_str()) ; }
+  else
+  if (shortHelp_ != "")
+  { CoinParamUtils::printIt(shortHelp_.c_str()) ; }
+  else
+  { CoinParamUtils::printIt("No help provided.") ; }
+
+  switch (type_)
+  { case coinParamDbl:
+    { std::cout << "<Range of values is " << lowerDblValue_ << " to "
+		<< upperDblValue_ << ";\n\tcurrent " << dblValue_ << ">"
+		<< std::endl ;
+      assert (upperDblValue_>lowerDblValue_) ;
+      break ; }
+    case coinParamInt:
+    { std::cout << "<Range of values is " << lowerIntValue_ << " to "
+		<< upperIntValue_ << ";\n\tcurrent " << intValue_ << ">"
+		<< std::endl ;
+      assert (upperIntValue_>lowerIntValue_) ;
+      break ; }
+    case coinParamKwd:
+    { printKwds() ;
+      break ; }
+    case coinParamStr:
+    { std::cout << "<Current value is " ;
+      if (strValue_ == "")
+      { std::cout << "(unset)>" ; }
+      else
+      { std::cout << "`" << strValue_ << "'>" ; }
+      std::cout << std::endl ;
+      break ; }
+    case coinParamAct:
+    { break ; }
+    default:
+    { std::cout << "!! invalid parameter type !!" << std::endl ;
+      assert (false) ; } }
+}
+
+
+/*
+  Methods to manipulate the value of a parameter.
+*/
+
+/*
+  Methods to manipulate the values associated with a keyword parameter.
+*/
+
+/*
+  Add a keyword to the list for a keyword parameter.
+*/
+void CoinParam::appendKwd (std::string kwd)
+{ 
+  assert (type_ == coinParamKwd) ;
+
+  definedKwds_.push_back(kwd) ;
+}
+
+/*
+  Scan the keywords of a keyword parameter and return the integer index of
+  the keyword matching the input, or -1 for no match.
+*/
+int CoinParam::kwdIndex (std::string input) const
+{
+  assert (type_ == coinParamKwd) ;
+
+  int whichItem = -1 ;
+  size_t numberItems = definedKwds_.size() ;
+  if (numberItems > 0)
+  { size_t inputLen = input.length() ;
+    size_t it ;
+/*
+  Open a loop to check each keyword against the input string. We don't record
+  the match length for keywords, so we need to check each one for an `!' and
+  do the necessary preprocessing (record position and elide `!') before
+  checking for a match of the required length.
+*/
+    for (it = 0 ; it < numberItems ; it++)
+    { std::string kwd = definedKwds_[it] ;
+      std::string::size_type shriekPos = kwd.find('!') ;
+      size_t kwdLen = kwd.length() ;
+      size_t matchLen = kwdLen ;
+      if (shriekPos != std::string::npos)
+      { matchLen = shriekPos ;
+	kwd = kwd.substr(0,shriekPos)+kwd.substr(shriekPos+1) ;
+	kwdLen = kwd.length() ; }
+/*
+  Match is possible only if input is shorter than the keyword. The entire input
+  must match and the match must exceed the minimum length.
+*/
+      if (inputLen <= kwdLen)
+      { unsigned int i ;
+	for (i = 0 ; i < inputLen ; i++)
+	{ if (tolower(kwd[i]) != tolower(input[i])) 
+	    break ; }
+	if (i >= inputLen && i >= matchLen)
+	{ whichItem = static_cast<int>(it) ;
+	  break ; } } } }
+
+  return (whichItem) ;
+}
+
+/*
+  Set current value for a keyword parameter using a string.
+*/
+void CoinParam::setKwdVal (const std::string value)
+{
+  assert (type_ == coinParamKwd) ;
+
+  int action = kwdIndex(value) ;
+  if (action >= 0)
+  { currentKwd_ = action ; }
+}
+
+/*
+  Set current value for keyword parameter using an integer. Echo the new value
+  to cout if requested.
+*/
+void CoinParam::setKwdVal (int value, bool printIt)
+{
+  assert (type_ == coinParamKwd) ;
+  assert (value >= 0 && unsigned(value) < definedKwds_.size()) ;
+
+  if (printIt && value != currentKwd_)
+  { std::cout << "Option for " << name_ << " changed from "
+              << definedKwds_[currentKwd_] << " to "
+              << definedKwds_[value] << std::endl ; }
+
+  currentKwd_ = value ;
+}
+
+/*
+  Return the string corresponding to the current value.
+*/
+std::string CoinParam::kwdVal() const
+{
+  assert (type_ == coinParamKwd) ;
+  
+  return (definedKwds_[currentKwd_]) ;
+}
+
+/*
+  Print the keywords for a keyword parameter, formatted to indicate how they'll
+  be matched. (E.g., some!Name prints as some(Name).). Follow with current
+  value.
+*/
+void CoinParam::printKwds () const
+{
+  assert (type_ == coinParamKwd) ;
+
+  std::cout << "Possible options for " << name_ << " are:" ;
+  unsigned int it ;
+  int maxAcross = 5 ;
+  for (it = 0 ; it < definedKwds_.size() ; it++)
+  { std::string kwd = definedKwds_[it] ;
+    std::string::size_type shriekPos = kwd.find('!') ;
+    if (shriekPos != std::string::npos)
+    { kwd = kwd.substr(0,shriekPos)+"("+kwd.substr(shriekPos+1)+")" ; }
+    if (it%maxAcross == 0)
+    { std::cout << std::endl ; }
+    std::cout << "  " << kwd ; }
+  std::cout << std::endl ;
+
+  assert (currentKwd_ >= 0 && unsigned(currentKwd_) < definedKwds_.size()) ;
+
+  std::string current = definedKwds_[currentKwd_] ;
+  std::string::size_type  shriekPos = current.find('!') ;
+  if (shriekPos != std::string::npos)
+  { current = current.substr(0,shriekPos)+
+			"("+current.substr(shriekPos+1)+")" ; }
+  std::cout << "  <current: " << current << ">" << std::endl ;
+}
+
+
+/*
+  Methods to manipulate the value of a string parameter.
+*/
+
+void CoinParam::setStrVal (std::string value)
+{ 
+  assert (type_ == coinParamStr) ;
+
+  strValue_ = value ;
+}
+
+std::string CoinParam::strVal () const
+{
+  assert (type_ == coinParamStr) ;
+
+  return (strValue_) ;
+}
+
+
+/*
+  Methods to manipulate the value of a double parameter.
+*/
+
+void CoinParam::setDblVal (double value)
+{ 
+  assert (type_ == coinParamDbl) ;
+
+  dblValue_ = value ;
+}
+
+double CoinParam::dblVal () const
+{
+  assert (type_ == coinParamDbl) ;
+
+  return (dblValue_) ;
+}
+
+
+/*
+  Methods to manipulate the value of an integer parameter.
+*/
+
+void CoinParam::setIntVal (int value)
+{ 
+  assert (type_ == coinParamInt) ;
+
+  intValue_ = value ;
+}
+
+int CoinParam::intVal () const
+{
+  assert (type_ == coinParamInt) ;
+
+  return (intValue_) ;
+}
+
+/*
+  A print function (friend of the class)
+*/
+
+std::ostream &operator<< (std::ostream &s, const CoinParam &param)
+{
+  switch (param.type())
+  { case CoinParam::coinParamDbl:
+    { return (s << param.dblVal()) ; }
+    case CoinParam::coinParamInt:
+    { return (s << param.intVal()) ; }
+    case CoinParam::coinParamKwd:
+    { return (s << param.kwdVal()) ; }
+    case CoinParam::coinParamStr:
+    { return (s << param.strVal()) ; }
+    case CoinParam::coinParamAct:
+    { return (s << "<evokes action>") ; }
+    default:
+    { return (s << "!! invalid parameter type !!") ; } }
+}
diff --git a/cbits/coin/CoinParam.hpp b/cbits/coin/CoinParam.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinParam.hpp
@@ -0,0 +1,644 @@
+/* $Id: CoinParam.hpp 1493 2011-11-01 16:56:07Z tkr $ */
+#ifndef CoinParam_H
+#define CoinParam_H
+
+/*
+  Copyright (C) 2002, International Business Machines
+  Corporation and others.  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+
+/*! \file CoinParam.hpp
+    \brief Declaration of a class for command line parameters.
+*/
+
+#include <vector>
+#include <string>
+#include <cstdio>
+
+/*! \class CoinParam
+    \brief A base class for `keyword value' command line parameters.
+
+  The underlying paradigm is that a parameter specifies an action to be
+  performed on a target object. The base class provides two function
+  pointers, a `push' function and a `pull' function.  By convention, a push
+  function will set some value in the target object or perform some action
+  using the target object.  A `pull' function will retrieve some value from
+  the target object.  This is only a convention, however; CoinParam and
+  associated utilities make no use of these functions and have no hardcoded
+  notion of how they should be used.
+
+  The action to be performed, and the target object, will be specific to a
+  particular application. It is expected that users will derive
+  application-specific parameter classes from this base class. A derived
+  class will typically add fields and methods to set/get a code for the
+  action to be performed (often, an enum class) and the target object (often,
+  a pointer or reference).
+
+  Facilities provided by the base class and associated utility routines
+  include:
+  <ul>
+    <li> Support for common parameter types with numeric, string, or
+	 keyword values.
+    <li> Support for short and long help messages.
+    <li> Pointers to `push' and `pull' functions as described above.
+    <li> Command line parsing and keyword matching.
+  </ul>
+  All utility routines are declared in the #CoinParamUtils namespace.
+
+  The base class recognises five types of parameters: actions (which require
+  no value); numeric parameters with integer or real (double) values; keyword
+  parameters, where the value is one of a defined set of value-keywords;
+  and string parameters (where the value is a string).
+  The base class supports the definition of a valid range, a default value,
+  and short and long help messages for a parameter.
+
+  As defined by the #CoinParamFunc typedef, push and pull functions
+  should take a single parameter, a pointer to a CoinParam. Typically this
+  object will actually be a derived class as described above, and the
+  implementation function will have access to all capabilities of CoinParam and
+  of the derived class.
+
+  When specified as command line parameters, the expected syntax is `-keyword
+  value' or `-keyword=value'. You can also use the Gnu double-dash style,
+  `--keyword'. Spaces around the `=' will \e not work.
+
+  The keyword (name) for a parameter can be defined with an `!' to mark the
+  minimal match point. For example, allow!ableGap will be considered matched
+  by the strings `allow', `allowa', `allowab', \e etc. Similarly, the
+  value-keyword strings for keyword parameters can be defined with `!' to
+  mark the minimal match point.  Matching of keywords and value-keywords is
+  \e not case sensitive.
+*/
+
+class CoinParam
+{
+ 
+public:
+
+/*! \name Subtypes */
+//@{
+
+  /*! \brief Enumeration for the types of parameters supported by CoinParam
+
+    CoinParam provides support for several types of parameters:
+    <ul>
+      <li> Action parameters, which require no value.
+      <li> Integer and double numeric parameters, with upper and lower bounds.
+      <li> String parameters that take an arbitrary string value.
+      <li> Keyword parameters that take a defined set of string (value-keyword)
+	   values. Value-keywords are associated with integers in the order in
+	   which they are added, starting from zero.
+    </ul>
+  */
+  typedef enum { coinParamInvalid = 0,
+		 coinParamAct, coinParamInt, coinParamDbl,
+		 coinParamStr, coinParamKwd } CoinParamType ;
+
+  /*! \brief Type declaration for push and pull functions.
+
+    By convention, a return code of  0 indicates execution without error, >0
+    indicates nonfatal error, and <0 indicates fatal error. This is only
+    convention, however; the base class makes no use of the push and pull
+    functions and has no hardcoded interpretation of the return code.
+  */
+  typedef int (*CoinParamFunc)(CoinParam *param) ;
+
+//@}
+
+/*! \name Constructors and Destructors
+
+  Be careful how you specify parameters for the constructors! Some compilers
+  are entirely too willing to convert almost anything to bool.
+*/
+//@{
+
+  /*! \brief Default constructor */
+
+  CoinParam() ;
+
+  /*! \brief Constructor for a parameter with a double value
+  
+    The default value is 0.0. Be careful to clearly indicate that \p lower and
+    \p upper are real (double) values to distinguish this constructor from the
+    constructor for an integer parameter.
+  */
+  CoinParam(std::string name, std::string help,
+	    double lower, double upper, double dflt = 0.0,
+	    bool display = true) ;
+
+  /*! \brief Constructor for a parameter with an integer value
+  
+    The default value is 0.
+  */
+  CoinParam(std::string name, std::string help,
+	    int lower, int upper, int dflt = 0,
+	    bool display = true) ;
+
+  /*! \brief Constructor for a parameter with keyword values
+
+    The string supplied as \p firstValue becomes the first value-keyword.
+    Additional value-keywords can be added using appendKwd().  It's necessary
+    to specify both the first value-keyword (\p firstValue) and the default
+    value-keyword index (\p dflt) in order to distinguish this constructor
+    from the constructors for string and action parameters.
+
+    Value-keywords are associated with an integer, starting with zero and
+    increasing as each keyword is added.  The value-keyword given as \p
+    firstValue will be associated with the integer zero. The integer supplied
+    for \p dflt can be any value, as long as it will be valid once all
+    value-keywords have been added.
+  */
+  CoinParam(std::string name, std::string help,
+	    std::string firstValue, int dflt, bool display = true) ;
+
+  /*! \brief Constructor for a string parameter
+
+    For some compilers, the default value (\p dflt) must be specified
+    explicitly with type std::string to distinguish the constructor for a
+    string parameter from the constructor for an action parameter. For
+    example, use std::string("default") instead of simply "default", or use a
+    variable of type std::string.
+  */
+  CoinParam(std::string name, std::string help,
+	    std::string dflt, bool display = true) ;
+
+  /*! \brief Constructor for an action parameter */
+
+  CoinParam(std::string name, std::string help,
+	    bool display = true) ;
+
+  /*! \brief Copy constructor */
+
+  CoinParam(const CoinParam &orig) ;
+
+  /*! \brief Clone */
+
+  virtual CoinParam *clone() ;
+
+  /*! \brief Assignment */
+  
+    CoinParam &operator=(const CoinParam &rhs) ;
+
+  /*! \brief  Destructor */
+
+  virtual ~CoinParam() ;
+
+//@}
+
+/*! \name Methods to query and manipulate the value(s) of a parameter */
+//@{
+
+  /*! \brief Add an additional value-keyword to a keyword parameter */
+
+  void appendKwd(std::string kwd) ;
+
+  /*! \brief Return the integer associated with the specified value-keyword
+  
+    Returns -1 if no value-keywords match the specified string.
+  */
+  int kwdIndex(std::string kwd) const ;
+
+  /*! \brief Return the value-keyword that is the current value of the
+	     keyword parameter
+  */
+  std::string kwdVal() const ;
+
+  /*! \brief Set the value of the keyword parameter using the integer
+	     associated with a value-keyword.
+  
+    If \p printIt is true, the corresponding value-keyword string will be
+    echoed to std::cout.
+  */
+  void setKwdVal(int value, bool printIt = false) ;
+
+  /*! \brief Set the value of the keyword parameter using a value-keyword
+	     string.
+  
+    The given string will be tested against the set of value-keywords for
+    the parameter using the shortest match rules.
+  */
+  void setKwdVal(const std::string value ) ;
+
+  /*! \brief Prints the set of value-keywords defined for this keyword
+	     parameter
+  */
+  void printKwds() const ;
+
+
+  /*! \brief Set the value of a string parameter */
+
+  void setStrVal(std::string value) ;
+
+  /*! \brief Get the value of a string parameter */
+
+  std::string strVal() const ;
+
+
+  /*! \brief Set the value of a double parameter */
+
+  void setDblVal(double value) ;
+
+  /*! \brief Get the value of a double parameter */
+
+  double dblVal() const ;
+
+
+  /*! \brief Set the value of a integer parameter */
+
+  void setIntVal(int value) ;
+
+  /*! \brief Get the value of a integer parameter */
+
+  int intVal() const ;
+
+
+  /*! \brief Add a short help string to a parameter */
+
+  inline void setShortHelp(const std::string help) { shortHelp_ = help ; } 
+
+  /*! \brief Retrieve the short help string */
+
+  inline std::string shortHelp() const { return (shortHelp_) ; } 
+
+  /*! \brief Add a long help message to a parameter
+  
+    See printLongHelp() for a description of how messages are broken into
+    lines.
+  */
+  inline void setLongHelp(const std::string help) { longHelp_ = help ; } 
+
+  /*! \brief Retrieve the long help message */
+
+  inline std::string longHelp() const { return (longHelp_) ; } 
+
+  /*! \brief  Print long help
+
+    Prints the long help string, plus the valid range and/or keywords if
+    appropriate. The routine makes a best effort to break the message into
+    lines appropriate for an 80-character line. Explicit line breaks in the
+    message will be observed. The short help string will be used if
+    long help is not available.
+  */
+  void printLongHelp() const ;
+
+//@}
+
+/*! \name Methods to query and manipulate a parameter object */
+//@{
+
+  /*! \brief Return the type of the parameter */
+
+  inline CoinParamType type() const { return (type_) ; } 
+
+  /*! \brief Set the type of the parameter */
+
+  inline void setType(CoinParamType type) { type_ = type ; } 
+
+  /*! \brief Return the parameter keyword (name) string */
+
+  inline std::string  name() const { return (name_) ; } 
+
+  /*! \brief Set the parameter keyword (name) string */
+
+  inline void setName(std::string name) { name_ = name ; processName() ; } 
+
+  /*! \brief Check if the specified string matches the parameter keyword (name)
+	     string
+  
+    Returns 1 if the string matches and meets the minimum match length,
+    2 if the string matches but doesn't meet the minimum match length,
+    and 0 if the string doesn't match. Matches are \e not case-sensitive.
+  */
+  int matches (std::string input) const ;
+
+  /*! \brief Return the parameter keyword (name) string formatted to show
+	     the minimum match length
+  
+    For example, if the parameter name was defined as allow!ableGap, the
+    string returned by matchName would be allow(ableGap).
+  */
+  std::string matchName() const ;
+
+  /*! \brief Set visibility of parameter
+
+    Intended to control whether the parameter is shown when a list of
+    parameters is processed. Used by CoinParamUtils::printHelp when printing
+    help messages for a list of parameters.
+  */
+  inline void setDisplay(bool display) { display_ = display ; } 
+
+  /*! \brief Get visibility of parameter */
+
+  inline bool display() const { return (display_) ; } 
+
+  /*! \brief Get push function */
+
+  inline CoinParamFunc pushFunc() { return (pushFunc_) ; } 
+
+  /*! \brief Set push function */
+
+  inline void setPushFunc(CoinParamFunc func) { pushFunc_ = func ; }  
+
+  /*! \brief Get pull function */
+
+  inline CoinParamFunc pullFunc() { return (pullFunc_) ; } 
+
+  /*! \brief Set pull function */
+
+  inline void setPullFunc(CoinParamFunc func) { pullFunc_ = func ; } 
+
+//@}
+
+private:
+
+/*! \name Private methods */
+//@{
+
+  /*! Process a name for efficient matching */
+  void processName() ;
+
+//@}
+
+/*! \name Private parameter data */
+//@{
+  /// Parameter type (see #CoinParamType)
+  CoinParamType type_ ;
+
+  /// Parameter name
+  std::string name_ ;
+
+  /// Length of parameter name
+  size_t lengthName_ ;
+
+  /*! \brief  Minimum length required to declare a match for the parameter
+	      name.
+  */
+  size_t lengthMatch_ ;
+
+  /// Lower bound on value for a double parameter
+  double lowerDblValue_ ;
+
+  /// Upper bound on value for a double parameter
+  double upperDblValue_ ;
+
+  /// Double parameter - current value
+  double dblValue_ ;
+
+  /// Lower bound on value for an integer parameter
+  int lowerIntValue_ ;
+
+  /// Upper bound on value for an integer parameter
+  int upperIntValue_ ;
+
+  /// Integer parameter - current value
+  int intValue_ ;
+
+  /// String parameter - current value
+  std::string strValue_ ;
+
+  /// Set of valid value-keywords for a keyword parameter
+  std::vector<std::string> definedKwds_ ;
+
+  /*! \brief Current value for a keyword parameter (index into #definedKwds_)
+  */
+  int currentKwd_ ;
+
+  /// Push function
+  CoinParamFunc pushFunc_ ;
+
+  /// Pull function
+  CoinParamFunc pullFunc_ ;
+
+  /// Short help
+  std::string shortHelp_ ;
+
+  /// Long help
+  std::string longHelp_ ;
+
+  /// Display when processing lists of parameters?
+  bool display_ ;
+//@}
+
+} ;
+
+/*! \relatesalso CoinParam
+    \brief A type for a parameter vector.
+*/
+typedef std::vector<CoinParam*> CoinParamVec ;
+
+/*! \relatesalso CoinParam
+    \brief A stream output function for a CoinParam object.
+*/
+std::ostream &operator<< (std::ostream &s, const CoinParam &param) ;
+
+/*
+  Bring in the utility functions for parameter handling (CbcParamUtils).
+*/
+
+/*! \brief Utility functions for processing CoinParam parameters.
+
+  The functions in CoinParamUtils support command line or interactive
+  parameter processing and a help facility. Consult the `Related Functions'
+  section of the CoinParam class documentation for individual function
+  documentation.
+*/
+namespace CoinParamUtils {
+  /*! \relatesalso CoinParam
+      \brief Take command input from the file specified by src.
+
+      Use stdin for \p src to specify interactive prompting for commands.
+  */
+  void setInputSrc(FILE *src) ;
+
+  /*! \relatesalso CoinParam
+      \brief Returns true if command line parameters are being processed.
+  */
+  bool isCommandLine() ;
+
+  /*! \relatesalso CoinParam
+      \brief Returns true if parameters are being obtained from stdin.
+  */
+  bool isInteractive() ;
+
+  /*! \relatesalso CoinParam
+      \brief Attempt to read a string from the input.
+      
+      \p argc and \p argv are used only if isCommandLine() would return true.
+      If \p valid is supplied, it will be set to 0 if a string is parsed
+      without error, 2 if no field is present.
+  */
+  std::string getStringField(int argc, const char *argv[], int *valid) ;
+
+  /*! \relatesalso CoinParam
+      \brief Attempt to read an integer from the input.
+      
+      \p argc and \p argv are used only if isCommandLine() would return true.
+      If \p valid is supplied, it will be set to 0 if an integer is parsed
+      without error, 1 if there's a parse error, and 2 if no field is present.
+  */
+  int getIntField(int argc, const char *argv[], int *valid) ;
+
+  /*! \relatesalso CoinParam
+      \brief Attempt to read a real (double) from the input.
+      
+      \p argc and \p argv are used only if isCommandLine() would return true.
+      If \p valid is supplied, it will be set to 0 if a real number is parsed
+      without error, 1 if there's a parse error, and 2 if no field is present.
+  */
+  double getDoubleField(int argc, const char *argv[], int *valid) ;
+
+  /*! \relatesalso CoinParam
+      \brief Scan a parameter vector for parameters whose keyword (name) string
+	     matches \p name using minimal match rules.
+      
+       \p matchNdx is set to the index of the last parameter that meets the
+       minimal match criteria (but note there should be at most one matching
+       parameter if the parameter vector is properly configured). \p shortCnt
+       is set to the number of short matches (should be zero for a properly
+       configured parameter vector if a minimal match is found). The return
+       value is the number of matches satisfying the minimal match requirement
+       (should be 0 or 1 in a properly configured vector).
+  */
+  int matchParam(const CoinParamVec &paramVec, std::string name,
+		 int &matchNdx, int &shortCnt) ;
+
+  /*! \relatesalso CoinParam
+      \brief Get the next command keyword (name)
+
+    To be precise, return the next field from the current command input
+    source, after a bit of processing. In command line mode (isCommandLine()
+    returns true) the next field will normally be of the form `-keyword' or
+    `--keyword' (\e i.e., a parameter keyword), and the string returned would
+    be `keyword'. In interactive mode (isInteractive() returns true), the
+    user will be prompted if necessary.  It is assumed that the user knows
+    not to use the `-' or `--' prefixes unless specifying parameters on the
+    command line.
+
+    There are a number of special cases if we're in command line mode. The
+    order of processing of the raw string goes like this:
+    <ul>
+      <li> A stand-alone `-' is forced to `stdin'.
+      <li> A stand-alone '--' is returned as a word; interpretation is up to
+	   the client.
+      <li> A prefix of '-' or '--' is stripped from the string.
+    </ul>
+    If the result is the string `stdin', command processing shifts to
+    interactive mode and the user is immediately prompted for a new command.
+
+    Whatever results from the above sequence is returned to the user as the
+    return value of the function. An empty string indicates end of input.
+
+    \p prompt will be used only if it's necessary to prompt the user in
+    interactive mode.
+  */
+
+  std::string getCommand(int argc, const char *argv[],
+			 const std::string prompt, std::string *pfx = 0) ;
+
+  /*! \relatesalso CoinParam
+      \brief Look up the command keyword (name) in the parameter vector.
+      	     Print help if requested.
+
+    In the most straightforward use, \p name is a string without `?', and the
+    value returned is the index in \p paramVec of the single parameter that
+    matched \p name. One or more '?' characters at the end of \p name is a
+    query for information. The routine prints short (one '?') or long (more
+    than one '?') help messages for a query.  Help is also printed in the case
+    where the name is ambiguous (some of the matches did not meet the minimal
+    match length requirement).
+
+    Note that multiple matches meeting the minimal match requirement is a
+    configuration error. The mimimal match length for the parameters
+    involved is too short.
+
+    If provided as parameters, on return
+    <ul>
+      <li> \p matchCnt will be set to the number of matches meeting the
+	   minimal match requirement
+      <li> \p shortCnt will be set to the number of matches that did not
+	   meet the miminal match requirement
+      <li> \p queryCnt will be set to the number of '?' characters at the
+	   end of the name
+    </ul>
+
+    The return values are:
+    <ul>
+      <li> >0: index in \p paramVec of the single unique match for \p name
+      <li> -1: a query was detected (one or more '?' characters at the end
+	       of \p name
+      <li> -2: one or more short matches, not a query
+      <li> -3: no matches, not a query
+      <li> -4: multiple matches meeting the minimal match requirement
+	       (configuration error)
+    </ul>
+  */
+  int lookupParam(std::string name, CoinParamVec &paramVec, 
+		  int *matchCnt = 0, int *shortCnt = 0, int *queryCnt = 0) ;
+
+  /*! \relatesalso CoinParam
+      \brief Utility to print a long message as filled lines of text
+
+      The routine makes a best effort to break lines without exceeding the
+      standard 80 character line length. Explicit newlines in \p msg will
+      be obeyed.
+  */
+  void printIt(const char *msg) ;
+
+  /*! \relatesalso CoinParam
+      \brief Utility routine to print help given a short match or explicit
+	     request for help.
+
+      The two really are related, in that a query (a string that ends with
+      one or more `?' characters) will often result in a short match. The
+      routine expects that \p name matches a single parameter, and does not
+      look for multiple matches.
+      
+      If called with \p matchNdx < 0, the routine will look up \p name in \p
+      paramVec and print the full name from the parameter. If called with \p
+      matchNdx > 0, it just prints the name from the specified parameter.  If
+      the name is a query, short (one '?') or long (more than one '?') help
+      is printed.
+
+  */ void shortOrHelpOne(CoinParamVec &paramVec,int matchNdx, std::string
+  name, int numQuery) ;
+
+  /*! \relatesalso CoinParam
+      \brief Utility routine to print help given multiple matches.
+
+      If the name is not a query, or asks for short help (\e i.e., contains
+      zero or one '?' characters), the list of matching names is printed. If
+      the name asks for long help (contains two or more '?' characters),
+      short help is printed for each matching name.
+  */
+  void shortOrHelpMany(CoinParamVec &paramVec,
+		       std::string name, int numQuery) ;
+
+  /*! \relatesalso CoinParam
+      \brief Print a generic `how to use the command interface' help message.
+
+    The message is hard coded to match the behaviour of the parsing utilities.
+  */
+  void printGenericHelp() ;
+
+  /*! \relatesalso CoinParam
+      \brief Utility routine to print help messages for one or more
+	     parameters.
+    
+    Intended as a utility to implement explicit `help' commands. Help will be
+    printed for all parameters in \p paramVec from \p firstParam to \p
+    lastParam, inclusive. If \p shortHelp is true, short help messages will
+    be printed. If \p longHelp is true, long help messages are printed. \p
+    shortHelp overrules \p longHelp. If neither is true, only command
+    keywords are printed. \p prefix is printed before each line; it's an
+    imperfect attempt at indentation.
+  */
+  void printHelp(CoinParamVec &paramVec, int firstParam, int lastParam,
+		 std::string prefix,
+		 bool shortHelp, bool longHelp, bool hidden) ;
+}
+
+
+#endif	/* CoinParam_H */
+
diff --git a/cbits/coin/CoinParamUtils.cpp b/cbits/coin/CoinParamUtils.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinParamUtils.cpp
@@ -0,0 +1,800 @@
+/* $Id: CoinParamUtils.cpp 1468 2011-09-03 17:19:13Z stefan $ */
+// Copyright (C) 2007, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cassert>
+#include <cerrno>
+#include <iostream>
+
+#include "CoinUtilsConfig.h"
+#include "CoinParam.hpp"
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+
+#ifdef COIN_HAS_READLINE     
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+/* Unnamed local namespace */
+namespace
+{
+
+/*
+  cmdField: The index of the current command line field. Forced to -1 when
+	    accepting commands from stdin (interactive) or a command file.
+  readSrc:  Current input source.
+
+  pendingVal: When the form param=value is encountered, both keyword and value
+	    form one command line field. We need to return `param' as the
+	    field and somehow keep the value around for the upcoming call
+	    that'll request it. That's the purpose of pendingVal.
+*/
+
+int cmdField = 1 ;
+FILE *readSrc = stdin ;
+std::string pendingVal = "" ;
+
+
+/*
+  Get next command or field in command. When in interactive mode, prompt the
+  user and read the resulting line of input.
+*/
+std::string nextField (const char *prompt)
+{
+  static char line[1000] ;
+  static char *where = NULL ;
+  std::string field ;
+  const char *dflt_prompt = "Eh? " ;
+
+  if (prompt == 0)
+  { prompt = dflt_prompt ; }
+/*
+  Do we have a line at the moment? If not, acquire one. When we're done,
+  line holds the input line and where points to the start of the line. If we're
+  using the readline library, add non-empty lines to the history list.
+*/
+  if (!where) {
+#ifdef COIN_HAS_READLINE
+    if (readSrc == stdin)
+    { where = readline(prompt) ;
+      if (where)
+      { if (*where)
+	  add_history (where) ;
+	strcpy(line,where) ;
+	free(where) ;
+	where = line ; } }
+    else
+    { where = fgets(line,1000,readSrc) ; }
+#else
+    if (readSrc == stdin)
+      { fprintf(stdout,"%s",prompt) ;
+      fflush(stdout) ; }
+    where = fgets(line,1000,readSrc) ;
+#endif
+/*
+  If where is NULL, we have EOF. Return a null string.
+*/
+    if (!where)
+      return field ;
+/*
+  Clean the image. Trailing junk first. The line will be cut off at the last
+  non-whitespace character, but we need to scan until we find the end of the
+  string or some other non-printing character to make sure we don't miss a
+  printing character after whitespace.
+*/
+    char *lastNonBlank = line-1 ;
+    for (where = line ; *where != '\0' ; where++)
+    { if (*where != '\t' && *where < ' ')
+      { break ; }
+      if (*where != '\t' && *where != ' ')
+      { lastNonBlank = where ; } }
+    *(lastNonBlank+1) = '\0' ;
+    where = line ; }
+/*
+  Munch through leading white space.
+*/
+  while (*where == ' ' || *where == '\t')
+    where++ ;
+/*
+  See if we can separate a field; if so, copy it over into field for return.
+  If we're out of line, return the string "EOL".
+*/
+  char *saveWhere = where ;
+  while (*where != ' ' && *where != '\t' && *where!='\0')
+    where++ ;
+  if (where != saveWhere)
+  { char save = *where ;
+    *where = '\0' ;
+    field = saveWhere ;
+    *where = save ; }
+  else
+  { where = NULL ;
+    field = "EOL" ; }
+
+  return (field) ; }
+
+}
+
+
+/* Visible functions */
+
+namespace CoinParamUtils
+{
+
+/*
+  As mentioned above, cmdField set to -1 is the indication that we're reading
+  from stdin or a file.
+*/
+void setInputSrc (FILE *src)
+
+{ if (src != 0)
+  { cmdField = -1 ;
+    readSrc = src ; } }
+
+/*
+  A utility to allow clients to determine if we're processing parameters from
+  the comand line or otherwise.
+*/
+bool isCommandLine ()
+
+{ assert(cmdField != 0) ;
+  
+  if (cmdField > 0)
+  { return (true) ; }
+  else
+  { return (false) ; } }
+
+/*
+  A utility to allow clients to determine if we're accepting parameters
+  interactively.
+*/
+bool isInteractive ()
+
+{ assert(cmdField != 0) ;
+  
+  if (cmdField < 0 && readSrc == stdin)
+  { return (true) ; }
+  else
+  { return (false) ; } }
+
+/*
+  Utility functions for acquiring input.
+*/
+
+
+/*
+  Return the next field (word) from the current command line. Generally, this
+  is expected to be of the form `-param' or `--param', with special cases as
+  set out below.
+
+  If we're in interactive mode (cmdField == -1), nextField does all the work
+  to prompt the user and return the next field from the resulting input. It is
+  assumed that the user knows not to use `-' or `--' prefixes in interactive
+  mode.
+
+  If we're in command line mode (cmdField > 0), cmdField indicates the
+  current command line word. The order of processing goes like this:
+    * A stand-alone `-' is converted to `stdin'
+    * A stand-alone '--' is returned as a word; interpretation is up to the
+      client.
+    * A prefix of '-' or '--' is stripped from the field.
+  If the result is `stdin', it's assumed we're switching to interactive mode
+  and the user is prompted for another command.
+
+  Whatever results from the above sequence is returned to the client as the
+  next field. An empty string indicates end of input.
+
+  Prompt will be used by nextField if it's necessary to prompt the user for
+  a command (only when reading from stdin).
+
+  If provided, pfx is set to the prefix ("-", "--", or "") stripped from the
+  field. Lack of prefix is not necessarily an error because of the following
+  scenario:  To read a file, the verbose command might be "foo -import
+  myfile". But we might want to allow a short form, "foo myfile". And we'd
+  like "foo import" to be interpreted as "foo -import import" (i.e., import the
+  file named `import').
+*/
+
+std::string getCommand (int argc, const char *argv[],
+			const std::string prompt, std::string *pfx)
+
+{ std::string field = "EOL" ;
+  pendingVal = "" ;
+  int pfxlen ;
+
+  if (pfx != 0)
+  { (*pfx) = "" ; }
+/*
+  Acquire the next field, and convert as outlined above if we're processing
+  command line parameters.
+*/
+  while (field == "EOL")
+  { pfxlen = 0 ;
+    if (cmdField > 0)
+    { if (cmdField < argc)
+      { field = argv[cmdField++] ;
+	if (field == "-")
+	{ field = "stdin" ; }
+	else
+	if (field == "--")
+	{ /* Prevent `--' from being eaten by next case. */ }
+	else
+	{ if (field[0] == '-')
+	  { pfxlen = 1 ;
+	    if (field[1] == '-')
+	      pfxlen = 2 ;
+	    if (pfx != 0)
+	      (*pfx) = field.substr(0,pfxlen) ;
+	    field = field.substr(pfxlen) ; } } }
+      else
+      { field = "" ; } }
+    else
+    { field = nextField(prompt.c_str()) ; }
+    if (field == "stdin")
+    { std::cout << "Switching to line mode" << std::endl ;
+      cmdField = -1 ;
+      field = nextField(prompt.c_str()) ; } }
+/*
+  Are we left with something of the form param=value? If so, separate the
+  pieces, returning `param' and saving `value' for later use as per comments
+  at the head of the file.
+*/
+  std::string::size_type found = field.find('=');
+  if (found != std::string::npos)
+  { pendingVal = field.substr(found+1) ;
+    field = field.substr(0,found) ; }
+
+  return (field) ; }
+
+
+/*
+  Function to look up a parameter keyword (name) in the parameter vector and
+  deal with the result. The keyword may end in one or more `?' characters;
+  this is a query for information about matching parameters.
+
+  If we have a single match satisfying the minimal match requirements, and
+  there's no query, we simply return the index of the matching parameter in
+  the parameter vector. If there are no matches, and no query, the return
+  value will be -3. No matches on a query returns -1.
+
+  A single short match, or a single match of any length with a query, will
+  result in a short help message
+
+  If present, these values are set as follows:
+    * matchCntp is set to the number of parameters that matched.
+    * shortCntp is set to the number of matches that failed to meet the minimum
+      match requirement.
+    * queryCntp is set to the number of trailing `?' characters at the end
+      of name.
+
+  Return values:
+    >0:	index of the single unique match for the name
+    -1: query present
+    -2: no query, one or more short matches
+    -3: no query, no match
+    -4: multiple full matches (indicates configuration error)
+
+  The final three parameters (matchCnt, shortCnt, queryCnt) are optional and
+  default to null. Use them if you want more detail on the match.
+*/
+
+int lookupParam (std::string name, CoinParamVec &paramVec,
+		 int *matchCntp, int *shortCntp, int *queryCntp)
+
+{
+  int retval = -3 ;
+
+  if (matchCntp != 0)
+  { *matchCntp = 0 ; }
+  if (shortCntp != 0)
+  { *shortCntp = 0 ; }
+  if (queryCntp != 0)
+  { *queryCntp = 0 ; }
+/*
+  Is there anything here at all? 
+*/
+  if (name.length() == 0)
+  { return (retval) ; }
+/*
+  Scan the parameter name to see if it ends in one or more `?' characters. If
+  so, take it as a request to return a list of parameters that match name up
+  to the first `?'.  The strings '?' and '???' are considered to be valid
+  parameter names (short and long help, respectively) and are handled as
+  special cases: If the whole string is `?'s, one and three are commands as
+  is, while 2 and 4 or more are queries about `?' or `???'.
+*/
+  int numQuery = 0 ;
+  { int length = static_cast<int>(name.length()) ;
+    int i ;
+    for (i = length-1 ; i >= 0 && name[i] == '?' ; i--)
+    { numQuery++ ; }
+    if (numQuery == length)
+    { switch (length)
+      { case 1:
+	case 3:
+	{ numQuery = 0 ;
+	  break ; }
+	case 2:
+	{ numQuery -= 1 ;
+	  break ; }
+        default:
+	{ numQuery -= 3 ;
+	  break ; } } }
+    name = name.substr(0,length-numQuery) ;
+    if (queryCntp != 0)
+    { *queryCntp = numQuery ; } }
+/*
+  See if we can match the parameter name. On return, matchNdx is set to the
+  last match satisfying the minimal match criteria, or -1 if there's no
+  match.  matchCnt is the number of matches satisfying the minimum match
+  length, and shortCnt is possible matches that were short of the minimum
+  match length,
+*/
+  int matchNdx = -1 ;
+  int shortCnt = 0 ;
+  int matchCnt = CoinParamUtils::matchParam(paramVec,name,matchNdx,shortCnt) ;
+/*
+  Set up return values before we get into further processing.
+*/
+  if (matchCntp != 0)
+  { *matchCntp = matchCnt ; }
+  if (shortCntp != 0)
+  { *shortCntp = shortCnt ; }
+  if (numQuery > 0)
+  { retval = -1 ; }
+  else
+  { if (matchCnt+shortCnt == 0)
+    { retval = -3 ; }
+    else
+    if (matchCnt > 1)
+    { retval = -4 ; }
+    else
+    { retval = -2 ; } }
+/*
+  No matches? Nothing more to be done here.
+*/
+  if (matchCnt+shortCnt == 0)
+  { return (retval) ; }
+/*
+  A unique match and no `?' in the name says we have our parameter. Return
+  the result.
+*/
+  if (matchCnt == 1 && shortCnt == 0 && numQuery == 0)
+  { assert (matchNdx >= 0 && matchNdx < static_cast<int>(paramVec.size())) ;
+    return (matchNdx) ; }
+/*
+  A single match? There are two possibilities:
+    * The string specified is shorter than the match length requested by the
+      parameter. (Useful for avoiding inadvertent execution of commands that
+      the client might regret.)
+    * The string specified contained a `?', in which case we print the help.
+      The match may or may not be short.
+*/
+  if (matchCnt+shortCnt == 1)
+  { CoinParamUtils::shortOrHelpOne(paramVec,matchNdx,name,numQuery) ;
+    return (retval) ; }
+/*
+  The final case: multiple matches. Most commonly this will be multiple short
+  matches. If we have multiple matches satisfying the minimal length
+  criteria, we have a configuration problem.  The other question is whether
+  the user wanted help information. Two question marks gets short help.
+*/
+  if (matchCnt > 1)
+  { std::cout
+    << "Configuration error! `" << name
+    <<"' was fully matched " << matchCnt << " times!"
+    << std::endl ; }
+  std::cout
+    << "Multiple matches for `" << name << "'; possible completions:"
+    << std::endl ;
+  CoinParamUtils::shortOrHelpMany(paramVec,name,numQuery) ;
+
+  return (retval) ; }
+
+
+/*
+  Utility functions to acquire parameter values from the command line. For
+  all of these, a pendingVal is consumed if it exists.
+*/
+
+
+/*
+  Read a string and return a pointer to the string. Set valid to indicate the
+  result of parsing: 0: okay, 1: <unused>, 2: not present.
+*/
+
+std::string getStringField (int argc, const char *argv[], int *valid)
+
+{ std::string field ;
+
+  if (pendingVal != "")
+  { field = pendingVal ;
+    pendingVal = "" ; }
+  else
+  { field = "EOL" ;
+    if (cmdField > 0)
+    { if (cmdField < argc)
+      { field = argv[cmdField++] ; } }
+    else
+    { field = nextField(0) ; } }
+
+  if (valid != 0)
+  { if (field != "EOL")
+    { *valid = 0 ; }
+    else
+    { *valid = 2 ; } }
+
+  return (field) ; }
+
+/*
+  Read an int and return the value. Set valid to indicate the result of
+  parsing: 0: okay, 1: parse error, 2: not present.
+*/
+
+int getIntField (int argc, const char *argv[], int *valid)
+
+{ std::string field ;
+
+  if (pendingVal != "")
+  { field = pendingVal ;
+    pendingVal = "" ; }
+  else
+  { field = "EOL" ;
+    if (cmdField > 0)
+    { if (cmdField < argc)
+      { field = argv[cmdField++] ; } }
+    else
+    { field = nextField(0) ; } }
+/*
+  The only way to check for parse error here is to set the system variable
+  errno to 0 and then see if it's nonzero after we try to convert the string
+  to integer.
+*/
+  int value = 0 ;
+  errno = 0 ;
+  if (field != "EOL")
+  { value =  atoi(field.c_str()) ; }
+
+  if (valid != 0)
+  { if (field != "EOL")
+    { if (errno == 0)
+      { *valid = 0 ; }
+      else
+      { *valid = 1 ; } }
+    else
+    { *valid = 2 ; } }
+
+  return (value) ; }
+
+
+/*
+  Read a double and return the value. Set valid to indicate the result of
+  parsing: 0: okay, 1: bad parse, 2: not present. But we'll never return
+  valid == 1 because atof gives us no way to tell.)
+*/
+
+double getDoubleField (int argc, const char *argv[], int *valid)
+
+{ std::string field ;
+
+  if (pendingVal != "")
+  { field = pendingVal ;
+    pendingVal = "" ; }
+  else
+  { field = "EOL" ;
+    if (cmdField > 0)
+    { if (cmdField < argc)
+      { field = argv[cmdField++] ; } }
+    else
+    { field = nextField(0) ; } }
+/*
+  The only way to check for parse error here is to set the system variable
+  errno to 0 and then see if it's nonzero after we try to convert the string
+  to integer.
+*/
+  double value = 0.0 ;
+  errno = 0 ;
+  if (field != "EOL")
+  { value = atof(field.c_str()) ; }
+
+  if (valid != 0)
+  { if (field != "EOL")
+    { if (errno == 0)
+      { *valid = 0 ; }
+      else
+      { *valid = 1 ; } }
+    else
+    { *valid = 2 ; } }
+
+  return (value) ; }
+
+
+/*
+  Utility function to scan a parameter vector for matches. Sets matchNdx to
+  the index of the last parameter that meets the minimal match criteria (but
+  note there should be at most one such parameter if the parameter vector is
+  properly configured). Sets shortCnt to the number of short matches (should
+  be zero in a properly configured vector if a minimal match is found).
+  Returns the number of matches satisfying the minimal match requirement
+  (should be 0 or 1 in a properly configured vector).
+
+  The routine allows for the possibility of null entries in the parameter
+  vector.
+
+  In order to handle `?' and `???', there's nothing to it but to force a
+  unique match if we match `?' exactly. (This is another quirk of clp/cbc
+  parameter parsing, which we need to match for historical reasons.)
+*/
+
+int matchParam (const CoinParamVec &paramVec, std::string name,
+		int &matchNdx, int &shortCnt)
+
+{ 
+  int vecLen = static_cast<int>(paramVec.size()) ;
+  int matchCnt = 0 ;
+
+  matchNdx = -1 ;
+  shortCnt = 0 ;
+
+  for (int i = 0 ; i < vecLen  ; i++)
+  { CoinParam *param =  paramVec[i] ;
+    if (param == 0) continue ;
+    int match = paramVec[i]->matches(name) ;
+    if (match == 1)
+    { matchNdx = i ;
+      matchCnt++ ;
+      if (name == "?")
+      { matchCnt = 1 ;
+	break ; } }
+    else
+    { shortCnt += match>>1 ; } }
+
+  return (matchCnt) ;
+}
+
+/*
+  Now a bunch of routines that are useful in the context of generating help
+  messages.
+*/
+
+/*
+  Simple formatting routine for long messages. Used to print long help for
+  parameters. Lines are broken at the first white space after 65 characters,
+  or when an explicit return (`\n') character is scanned. Leading spaces are
+  suppressed.
+*/
+
+void printIt (const char *msg)
+
+{ int length = static_cast<int>(strlen(msg)) ;
+  char temp[101] ;
+  int i ;
+  int n = 0 ;
+  for (i = 0 ; i < length ; i++)
+  { if (msg[i] == '\n' ||
+	(n >= 65 && (msg[i] == ' ' || msg[i] == '\t')))
+    { temp[n] = '\0' ;
+      std::cout << temp << std::endl ;
+      n = 0 ; }
+    else
+    if (n || msg[i] != ' ')
+    { temp[n++] = msg[i] ; } }
+  if (n > 0)
+  { temp[n] = '\0' ;
+    std::cout << temp << std::endl ; }
+
+  return ; }
+
+
+/*
+  Utility function for the case where a name matches a single parameter, but
+  either it's short, or the user wanted help, or both.
+
+  The routine allows for the possibility that there are null entries in the
+  parameter vector, but matchNdx should point to a valid entry if it's >= 0.
+*/
+
+void shortOrHelpOne (CoinParamVec &paramVec,
+		     int matchNdx, std::string name, int numQuery)
+
+{ int i ;
+  int numParams = static_cast<int>(paramVec.size()) ;
+  int lclNdx = -1 ;
+/*
+  For a short match, we need to look up the parameter again. This should find
+  a short match, given the conditions where this routine is called. But be
+  prepared to find a full match.
+  
+  If matchNdx >= 0, just use the index we're handed.
+*/
+  if (matchNdx < 0) 
+  { int match = 0 ;
+    for (i = 0 ; i < numParams ; i++)
+    { CoinParam *param =  paramVec[i] ;
+      if (param == 0) continue ;
+      int match = param->matches(name) ;
+      if (match != 0)
+      { lclNdx = i ;
+	break ; } }
+
+    assert (lclNdx >= 0) ;
+
+    if (match == 1)
+    { std::cout
+	<< "Match for '" << name << "': "
+	<< paramVec[matchNdx]->matchName() << "." ; }
+    else
+    { std::cout
+      << "Short match for '" << name << "'; possible completion: "
+      << paramVec[lclNdx]->matchName() << "." ; } }
+  else
+  { assert(matchNdx >= 0 && matchNdx < static_cast<int>(paramVec.size())) ;
+    std::cout << "Match for `" << name << "': "
+	      << paramVec[matchNdx]->matchName() ;
+    lclNdx = matchNdx ; }
+/*
+  Print some help, if there was a `?' in the name. `??' gets the long help.
+*/
+  if (numQuery > 0)
+  { std::cout << std::endl ;
+    if (numQuery == 1)
+    { std::cout << paramVec[lclNdx]->shortHelp() ; }
+    else
+    { paramVec[lclNdx]->printLongHelp() ; } }
+  std::cout << std::endl ;
+
+  return ; }
+
+/*
+  Utility function for the case where a name matches multiple parameters.
+  Zero or one `?' gets just the matching names, while `??' gets short help
+  with each match.
+
+  The routine allows for the possibility that there are null entries in the
+  parameter vector.
+*/
+
+void shortOrHelpMany (CoinParamVec &paramVec, std::string name, int numQuery)
+
+{ int numParams = static_cast<int>(paramVec.size()) ;
+/*
+  Scan the parameter list. For each match, print just the name, or the name
+  and short help.
+*/
+  int lineLen = 0 ;
+  bool printed = false ;
+  for (int i = 0 ; i < numParams ; i++)
+  { CoinParam *param = paramVec[i] ;
+    if (param == 0) continue ;
+    int match = param->matches(name) ;
+    if (match > 0)
+    { std::string nme = param->matchName() ;
+      int len = static_cast<int>(nme.length()) ;
+      if (numQuery >= 2) 
+      { std::cout << nme << " : " << param->shortHelp() ;
+	std::cout << std::endl ; }
+      else
+      { lineLen += 2+len ;
+	if (lineLen > 80)
+	{ std::cout << std::endl ;
+	  lineLen = 2+len ; }
+	std::cout << "  " << nme ;
+	printed = true ; } } }
+
+  if (printed)
+  { std::cout << std::endl ; }
+
+  return ; }
+
+
+/*
+  A generic help message that explains the basic operation of parameter
+  parsing.
+*/
+
+void printGenericHelp ()
+
+{ std::cout << std::endl ;
+  std::cout
+    << "For command line arguments, keywords have a leading `-' or '--'; "
+    << std::endl ;
+  std::cout
+    << "-stdin or just - switches to stdin with a prompt."
+    << std::endl ;
+  std::cout
+    << "When prompted, one command per line, without the leading `-'."
+    << std::endl ;
+  std::cout
+    << "abcd value sets abcd to value."
+    << std::endl ;
+  std::cout
+    << "abcd without a value (where one is expected) gives the current value."
+    << std::endl ;
+  std::cout
+    << "abcd? gives a list of possible matches; if there's only one, a short"
+    << std::endl ;
+  std::cout
+    << "help message is printed."
+    << std::endl ;
+  std::cout
+    << "abcd?? prints the short help for all matches; if there's only one"
+    << std::endl ;
+  std::cout
+    << "match, a longer help message and current value are printed."
+    << std::endl ;
+  
+  return ; }
+
+
+/*
+  Utility function for various levels of `help' command. The entries between
+  paramVec[firstParam] and paramVec[lastParam], inclusive, will be printed.
+  If shortHelp is true, the short help message will be printed for each
+  parameter. If longHelp is true, the long help message will be printed for
+  each parameter.  If hidden is true, even parameters with display = false
+  will be printed. Each line is prefaced with the specified prefix.
+
+  The routine allows for the possibility that there are null entries in the
+  parameter vector.
+*/
+
+void printHelp (CoinParamVec &paramVec, int firstParam, int lastParam,
+		std::string prefix,
+		bool shortHelp, bool longHelp, bool hidden)
+
+{ bool noHelp = !(shortHelp || longHelp) ;
+  int i ;
+  int pfxLen = static_cast<int>(prefix.length()) ;
+  bool printed = false ;
+
+  if (noHelp)
+  { int lineLen = 0 ;
+    for (i = firstParam ; i <= lastParam ; i++)
+    { CoinParam *param = paramVec[i] ;
+      if (param == 0) continue ;
+      if (param->display() || hidden)
+      { std::string nme = param->matchName() ;
+	int len = static_cast<int>(nme.length()) ;
+	if (!printed)
+	{ std::cout << std::endl << prefix ;
+	  lineLen += pfxLen ;
+	  printed = true ; }
+	lineLen += 2+len ;
+	if (lineLen > 80)
+	{ std::cout << std::endl << prefix ;
+	  lineLen = pfxLen+2+len ; }
+        std::cout << "  " << nme ; } }
+    if (printed)
+    { std::cout << std::endl ; } }
+  else
+  if (shortHelp)
+  { for (i = firstParam ; i <= lastParam ; i++)
+    { CoinParam *param = paramVec[i] ;
+      if (param == 0) continue ;
+      if (param->display() || hidden)
+      { std::cout << std::endl << prefix ;
+	std::cout << param->matchName() ;
+	std::cout << ": " ;
+	std::cout << param->shortHelp() ; } }
+      std::cout << std::endl ; }
+  else
+  if (longHelp)
+  { for (i = firstParam ; i <= lastParam ; i++)
+    { CoinParam *param = paramVec[i] ;
+      if (param == 0) continue ;
+      if (param->display() || hidden)
+      { std::cout << std::endl << prefix ;
+	std::cout << "Command: " << param->matchName() ;
+        std::cout << std::endl << prefix ;
+	std::cout << "---- description" << std::endl ;
+	printIt(param->longHelp().c_str()) ;
+	std::cout << prefix << "----" << std::endl ; } } }
+
+  std::cout << std::endl ;
+
+  return ; }   
+
+} // end namespace CoinParamUtils
diff --git a/cbits/coin/CoinPostsolveMatrix.cpp b/cbits/coin/CoinPostsolveMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPostsolveMatrix.cpp
@@ -0,0 +1,217 @@
+/* $Id: CoinPostsolveMatrix.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+
+#include <cassert>
+#include <iostream>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+
+#if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+/*! \file
+
+  This file contains methods for CoinPostsolveMatrix, the object used during
+  postsolve transformations.
+*/
+
+/*
+  Constructor and destructor for CoinPostsolveMatrix.
+*/
+
+/*
+  Default constructor
+
+  Postpone allocation of space until we actually load the object.
+*/
+
+CoinPostsolveMatrix::CoinPostsolveMatrix
+  (int ncols_alloc, int nrows_alloc, CoinBigIndex nelems_alloc)
+
+  : CoinPrePostsolveMatrix(ncols_alloc,nrows_alloc,nelems_alloc),
+    free_list_(0),
+    maxlink_(nelems_alloc),
+    link_(0),
+    cdone_(0),
+    rdone_(0)
+
+{ /* nothing to do here */ 
+
+  return ; }
+
+/*
+  Destructor
+*/
+
+CoinPostsolveMatrix::~CoinPostsolveMatrix()
+
+{ delete[] link_ ;
+
+  delete[] cdone_ ;
+  delete[] rdone_ ;
+
+  return ; }
+
+/*
+  This routine loads a CoinPostsolveMatrix object from a CoinPresolveMatrix
+  object. The CoinPresolveMatrix object will be stripped, its components
+  transferred to the CoinPostsolveMatrix object, and the empty shell of the
+  CoinPresolveObject will be destroyed.
+
+  The routine expects an empty CoinPostsolveMatrix object, and will leak
+  any memory already allocated.
+*/
+
+void
+CoinPostsolveMatrix::assignPresolveToPostsolve (CoinPresolveMatrix *&preObj)
+
+{
+/*
+  Start with simple data --- allocated and current size.
+*/
+  ncols0_ = preObj->ncols0_ ;
+  nrows0_ = preObj->nrows0_ ;
+  nelems0_ = preObj->nelems0_ ;
+  bulk0_ = preObj->bulk0_ ;
+
+  ncols_ = preObj->ncols_ ;
+  nrows_ = preObj->nrows_ ;
+  nelems_ = preObj->nelems_ ;
+/*
+  Now bring over the column-major matrix and other problem data.
+*/
+  mcstrt_ = preObj->mcstrt_ ;
+  preObj->mcstrt_ = 0 ;
+  hincol_ = preObj->hincol_ ;
+  preObj->hincol_ = 0 ;
+  hrow_ = preObj->hrow_ ;
+  preObj->hrow_ = 0 ;
+  colels_ = preObj->colels_ ;
+  preObj->colels_ = 0 ;
+
+  cost_ = preObj->cost_ ;
+  preObj->cost_ = 0 ;
+  originalOffset_ = preObj->originalOffset_ ;
+  clo_ = preObj->clo_ ;
+  preObj->clo_ = 0 ;
+  cup_ = preObj->cup_ ;
+  preObj->cup_ = 0 ;
+  rlo_ = preObj->rlo_ ;
+  preObj->rlo_ = 0 ;
+  rup_ = preObj->rup_ ;
+  preObj->rup_ = 0 ;
+
+  originalColumn_ = preObj->originalColumn_ ;
+  preObj->originalColumn_ = 0 ;
+  originalRow_ = preObj->originalRow_ ;
+  preObj->originalRow_ = 0 ;
+
+  ztolzb_ = preObj->ztolzb_ ;
+  ztoldj_ = preObj->ztoldj_ ;
+  maxmin_ = preObj->maxmin_ ;
+/*
+  Now the problem solution. Often this will be empty, but that's not a problem.
+*/
+  sol_ = preObj->sol_ ;
+  preObj->sol_ = 0 ;
+  rowduals_ = preObj->rowduals_ ;
+  preObj->rowduals_ = 0 ;
+  acts_ = preObj->acts_ ;
+  preObj->acts_ = 0 ;
+  rcosts_ = preObj->rcosts_ ;
+  preObj->rcosts_ = 0 ;
+  colstat_ = preObj->colstat_ ;
+  preObj->colstat_ = 0 ;
+  rowstat_ = preObj->rowstat_ ;
+  preObj->rowstat_ = 0 ;
+/*
+  The CoinPostsolveMatrix comes with messages and a handler, but replace them
+  with the versions from the CoinPresolveObject, in case they've been
+  customized. Let preObj believe it's no longer responsible for the handler.
+*/
+  if (defaultHandler_ == true)
+    delete handler_ ;
+  handler_ = preObj->handler_ ;
+  preObj->defaultHandler_ = false ;
+  messages_ = preObj->messages_ ;
+/*
+  Initialise the postsolve portions of this object. Which amounts to setting
+  up the thread links to match the column-major matrix representation. This
+  would be trivial except that the presolve matrix is loosely packed. We can
+  either compress the matrix, or record the existing free space pattern. Bet
+  that the latter is more efficient. Remember that mcstrt_[ncols_] actually
+  points to the end of the bulk storage area, so when we process the last
+  column in the bulk storage area, we'll add the free space block at the end
+  of bulk storage to the free list.
+
+  We need to allow for a 0x0 matrix here --- a pathological case, but it slips
+  in when (for example) confirming a solution in an ILP code.
+*/
+  free_list_ = NO_LINK ;
+  maxlink_ = bulk0_ ;
+  link_ = new CoinBigIndex [maxlink_] ;
+
+  if (ncols_ > 0)
+  { CoinBigIndex minkcs = -1 ;
+    for (int j = 0 ; j < ncols_ ; j++)
+    { CoinBigIndex kcs = mcstrt_[j] ;
+      int lenj = hincol_[j] ;
+      assert(lenj > 0) ;
+      CoinBigIndex kce = kcs+lenj-1 ;
+      CoinBigIndex k ;
+
+      for (k = kcs ; k < kce ; k++)
+      { link_[k] = k+1 ; }
+      link_[k++] = NO_LINK ;
+
+      if (preObj->clink_[j].pre == NO_LINK)
+      { minkcs = kcs ; }
+      int nxtj = preObj->clink_[j].suc ;
+      assert(nxtj >= 0 && nxtj <= ncols_) ;
+      CoinBigIndex nxtcs = mcstrt_[nxtj] ;
+      for ( ; k < nxtcs ; k++)
+      { link_[k] = free_list_ ;
+	free_list_ = k ; } }
+
+    assert(minkcs >= 0) ;
+    if (minkcs > 0)
+    { for (CoinBigIndex k = 0 ; k < minkcs ; k++)
+      { link_[k] = free_list_ ;
+	free_list_ = k ; } } }
+  else
+  { for (CoinBigIndex k = 0 ; k < maxlink_ ; k++)
+    { link_[k] = free_list_ ;
+      free_list_ = k ; } }
+/*
+  That's it, preObj can die now.
+*/
+  delete preObj ;
+  preObj = 0 ;
+
+# if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
+/*
+  These are used to track the action of postsolve transforms during debugging.
+*/
+  cdone_ = new char [ncols0_] ;
+  CoinFillN(cdone_,ncols_,PRESENT_IN_REDUCED) ;
+  CoinZeroN(cdone_+ncols_,ncols0_-ncols_) ;
+  rdone_ = new char [nrows0_] ;
+  CoinFillN(rdone_,nrows_,PRESENT_IN_REDUCED) ;
+  CoinZeroN(rdone_+nrows_,nrows0_-nrows_) ;
+# else
+  cdone_ = 0 ;
+  rdone_ = 0 ;
+# endif
+
+# if PRESOLVE_CONSISTENCY
+  presolve_check_free_list(this,true) ;
+  presolve_check_threads(this) ;
+# endif
+
+  return ; }
diff --git a/cbits/coin/CoinPragma.hpp b/cbits/coin/CoinPragma.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPragma.hpp
@@ -0,0 +1,26 @@
+/* $Id: CoinPragma.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPragma_H
+#define CoinPragma_H
+
+//-------------------------------------------------------------------
+//
+// This is a file which can contain Pragma's that are
+// generally applicable to any source file.
+//
+//-------------------------------------------------------------------
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+// Turn off compiler warning: 
+// "empty controlled statement found; is this the intent?"
+#  pragma warning(disable:4390)
+// Turn off compiler warning about deprecated functions
+#  pragma warning(disable:4996)
+#endif
+
+#endif
diff --git a/cbits/coin/CoinPrePostsolveMatrix.cpp b/cbits/coin/CoinPrePostsolveMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPrePostsolveMatrix.cpp
@@ -0,0 +1,528 @@
+/* $Id: CoinPrePostsolveMatrix.cpp 1516 2011-12-10 23:40:39Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+#ifndef SLIM_CLP
+#include "CoinWarmStartBasis.hpp"
+#endif
+
+/*! \file
+  This file contains methods for CoinPrePostsolveMatrix, the foundation class
+  for CoinPresolveMatrix and CoinPostsolveMatrix.
+*/
+
+/*
+  Constructor and destructor for CoinPrePostsolveMatrix.
+*/
+
+/*
+  CoinPrePostsolveMatrix constructor
+
+  This constructor does next to nothing, because there's no sensible middle
+  ground between next to nothing and a constructor with twenty parameters
+  that all need to be extracted from the constraint system held by an OSI.
+  The alternative, creating a constructor which takes some flavour of OSI as
+  a parameter, seems to me (lh) to be wrong. That knowledge does not belong
+  in the generic COIN support library.
+
+  The philosophy here is to create an empty CoinPrePostsolveMatrix object and
+  then load in the constraint matrix, vectors, and miscellaneous parameters.
+  Some of this will be done from CoinPresolveMatrix or CoinPostsolveMatrix
+  constructors, but in the end most of it should be pushed back to an
+  OSI-specific method. Then the knowledge of how to access the required data
+  in an OSI is pushed back to the individual OSI classes where it belongs.
+
+  Thus, all vector allocation is postponed until load time.
+*/
+
+CoinPrePostsolveMatrix::CoinPrePostsolveMatrix
+  (int ncols_alloc, int nrows_alloc, CoinBigIndex nelems_alloc)
+
+  : ncols_(0),
+    nrows_(0),
+    nelems_(0),
+    ncols0_(ncols_alloc),
+    nrows0_(nrows_alloc),
+    nelems0_(nelems_alloc),
+    bulkRatio_(2.0),
+
+    mcstrt_(0),
+    hincol_(0),
+    hrow_(0),
+    colels_(0),
+
+    cost_(0),
+    originalOffset_(0),
+    clo_(0),
+    cup_(0),
+    rlo_(0),
+    rup_(0),
+
+    originalColumn_(0),
+    originalRow_(0),
+
+    ztolzb_(0.0),
+    ztoldj_(0.0),
+
+    maxmin_(0),
+
+    sol_(0),
+    rowduals_(0),
+    acts_(0),
+    rcosts_(0),
+    colstat_(0),
+    rowstat_(0),
+
+    handler_(0),
+    defaultHandler_(false),
+    messages_()
+
+{ handler_ = new CoinMessageHandler() ;
+  defaultHandler_ = true ;
+  bulk0_ = static_cast<CoinBigIndex> (bulkRatio_*nelems_alloc);
+
+  return ; }
+
+/*
+  CoinPrePostsolveMatrix destructor
+*/
+
+CoinPrePostsolveMatrix::~CoinPrePostsolveMatrix()
+{
+  delete[] sol_ ;
+  delete[] rowduals_ ;
+  delete[] acts_ ;
+  delete[] rcosts_ ;
+
+/*
+  Note that we do NOT delete rowstat_. This is to maintain compatibility with
+  ClpPresolve and OsiPresolve, which allocate a single vector and split it
+  between column and row status.
+*/
+  delete[] colstat_ ;
+
+  delete[] cost_ ;
+  delete[] clo_ ;
+  delete[] cup_ ;
+  delete[] rlo_ ;
+  delete[] rup_ ;
+
+  delete[] mcstrt_ ;
+  delete[] hrow_ ;
+  delete[] colels_ ;
+  delete[] hincol_ ;
+
+  delete[] originalColumn_ ;
+  delete[] originalRow_ ;
+
+  if (defaultHandler_ == true)
+    delete handler_ ;
+}
+
+
+#ifndef SLIM_CLP
+/*
+  Methods to set the miscellaneous parameters: max/min, objective offset, and
+  tolerances.
+*/
+
+void CoinPrePostsolveMatrix::setObjOffset (double offset)
+
+{ originalOffset_ = offset ; }
+
+void CoinPrePostsolveMatrix::setObjSense (double objSense)
+
+{ maxmin_ = objSense ; }
+
+void CoinPrePostsolveMatrix::setPrimalTolerance (double primTol)
+
+{ ztolzb_ = primTol ; }
+
+void CoinPrePostsolveMatrix::setDualTolerance (double dualTol)
+
+{ ztoldj_ = dualTol ; }
+
+
+
+/*
+  Methods to set the various vectors. For all methods, lenParam can be
+  omitted and will default to -1. In that case, the default action is to copy
+  ncols_ or nrows_ entries, as appropriate.
+
+  It is *not* considered an error to specify lenParam = 0! This allows for
+  allocation of vectors in an intially empty system.  Note that ncols_ and
+  nrows_ will be 0 before a constraint system is loaded. Be careful what you
+  ask for.
+
+  The vector allocated in the CoinPrePostsolveMatrix will be of size ncols0_
+  or nrows0_, as appropriate.
+*/
+
+void CoinPrePostsolveMatrix::setColLower (const double *colLower, int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = ncols_ ; }
+  else
+  if (lenParam > ncols0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setColLower","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (clo_ == 0) clo_ = new double[ncols0_] ;
+  CoinMemcpyN(colLower,len,clo_) ;
+
+  return ; }
+  
+void CoinPrePostsolveMatrix::setColUpper (const double *colUpper, int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = ncols_ ; }
+  else
+  if (lenParam > ncols0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setColUpper","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (cup_ == 0) cup_ = new double[ncols0_] ;
+  CoinMemcpyN(colUpper,len,cup_) ;
+
+  return ; }
+  
+void CoinPrePostsolveMatrix::setColSolution (const double *colSol,
+					     int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = ncols_ ; }
+  else
+  if (lenParam > ncols0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setColSolution","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (sol_ == 0) sol_ = new double[ncols0_] ;
+  CoinMemcpyN(colSol,len,sol_) ;
+
+  return ; }
+  
+void CoinPrePostsolveMatrix::setCost (const double *cost, int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = ncols_ ; }
+  else
+  if (lenParam > ncols0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setCost","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (cost_ == 0) cost_ = new double[ncols0_] ;
+  CoinMemcpyN(cost,len,cost_) ;
+
+  return ; }
+
+void CoinPrePostsolveMatrix::setReducedCost (const double *redCost,
+					     int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = ncols_ ; }
+  else
+  if (lenParam > ncols0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setReducedCost","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (rcosts_ == 0) rcosts_ = new double[ncols0_] ;
+  CoinMemcpyN(redCost,len,rcosts_) ;
+
+  return ; }
+
+
+void CoinPrePostsolveMatrix::setRowLower (const double *rowLower, int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = nrows_ ; }
+  else
+  if (lenParam > nrows0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setRowLower","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (rlo_ == 0) rlo_ = new double[nrows0_] ;
+  CoinMemcpyN(rowLower,len,rlo_) ;
+
+  return ; }
+  
+void CoinPrePostsolveMatrix::setRowUpper (const double *rowUpper, int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = nrows_ ; }
+  else
+  if (lenParam > nrows0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setRowUpper","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (rup_ == 0) rup_ = new double[nrows0_] ;
+  CoinMemcpyN(rowUpper,len,rup_) ;
+
+  return ; }
+  
+void CoinPrePostsolveMatrix::setRowPrice (const double *rowSol, int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = nrows_ ; }
+  else
+  if (lenParam > nrows0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setRowPrice","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (rowduals_ == 0) rowduals_ = new double[nrows0_] ;
+  CoinMemcpyN(rowSol,len,rowduals_) ;
+
+  return ; }
+  
+void CoinPrePostsolveMatrix::setRowActivity (const double *rowAct, int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = nrows_ ; }
+  else
+  if (lenParam > nrows0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setRowActivity","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (acts_ == 0) acts_ = new double[nrows0_] ;
+  CoinMemcpyN(rowAct,len,acts_) ;
+
+  return ; }
+
+
+
+/*
+  Methods to set the status vectors for a basis. Note that we need to allocate
+  colstat_ and rowstat_ as a single vector, to maintain compatibility with
+  OsiPresolve and ClpPresolve.
+
+  The `using ::getStatus' declaration is required to get the compiler to
+  consider the getStatus helper function defined in CoinWarmStartBasis.hpp.
+*/
+
+void CoinPrePostsolveMatrix::setStructuralStatus (const char *strucStatus,
+						  int lenParam)
+
+{ int len ;
+  using ::getStatus ;
+
+  if (lenParam < 0)
+  { len = ncols_ ; }
+  else
+  if (lenParam > ncols0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setStructuralStatus","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (colstat_ == 0)
+  { colstat_ = new unsigned char[ncols0_+nrows0_] ;
+#   ifdef ZEROFAULT
+    CoinZeroN(colstat_,ncols0_+nrows0_) ;
+#   endif
+    rowstat_ = colstat_+ncols0_ ; }
+  for (int j = 0 ; j < len ; j++)
+  { Status statj = Status(getStatus(strucStatus,j)) ;
+    setColumnStatus(j,statj) ; }
+
+  return ; }
+
+
+void CoinPrePostsolveMatrix::setArtificialStatus (const char *artifStatus,
+						  int lenParam)
+
+{ int len ;
+  using ::getStatus ;
+
+  if (lenParam < 0)
+  { len = nrows_ ; }
+  else
+  if (lenParam > nrows0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setArtificialStatus","CoinPrePostsolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (colstat_ == 0)
+  { colstat_ = new unsigned char[ncols0_+nrows0_] ;
+#   ifdef ZEROFAULT
+    CoinZeroN(colstat_,ncols0_+nrows0_) ;
+#   endif
+    rowstat_ = colstat_+ncols0_ ; }
+  for (int i = 0 ; i < len ; i++)
+  { Status stati = Status(getStatus(artifStatus,i)) ;
+    setRowStatus(i,stati) ; }
+
+  return ; }
+
+/*
+  This routine initialises structural and artificial status given a
+  CoinWarmStartBasis as the parameter.
+*/
+
+void CoinPrePostsolveMatrix::setStatus (const CoinWarmStartBasis *basis)
+
+{ setStructuralStatus(basis->getStructuralStatus(),
+		      basis->getNumStructural()) ;
+  setArtificialStatus(basis->getArtificialStatus(),
+		      basis->getNumArtificial()) ;
+
+  return ; }
+
+/*
+  This routine returns structural and artificial status in the form of a
+  CoinWarmStartBasis object.
+
+  What to do when CoinPrePostsolveMatrix::Status == superBasic? There's
+  no analog in CoinWarmStartBasis::Status.
+*/
+
+CoinWarmStartBasis *CoinPrePostsolveMatrix::getStatus ()
+
+{ int n = ncols_ ;
+  int m = nrows_ ;
+  CoinWarmStartBasis *wsb = new CoinWarmStartBasis() ;
+  wsb->setSize(n,m) ;
+  for (int j = 0 ; j < n ; j++)
+  { CoinWarmStartBasis::Status statj = 
+	CoinWarmStartBasis::Status(getColumnStatus(j)) ;
+    wsb->setStructStatus(j,statj) ; }
+  for (int i = 0 ; i < m ; i++)
+  { CoinWarmStartBasis::Status stati =
+	CoinWarmStartBasis::Status(getRowStatus(i)) ;
+    wsb->setArtifStatus(i,stati) ; }
+  
+  return (wsb) ; }
+#endif
+/*
+  Set the status of a non-basic artificial variable based on the
+  variable's value and bounds.
+*/
+
+void CoinPrePostsolveMatrix::setRowStatusUsingValue (int iRow)
+
+{ double value = acts_[iRow] ;
+  double lower = rlo_[iRow] ;
+  double upper = rup_[iRow] ;
+  if (lower < -1.0e20 && upper > 1.0e20) {
+    setRowStatus(iRow,isFree) ;
+  } else if (fabs(lower-value) <= ztolzb_) {
+    setRowStatus(iRow,atUpperBound) ;
+  } else if (fabs(upper-value) <= ztolzb_) {
+    setRowStatus(iRow,atLowerBound) ;
+  } else {
+    setRowStatus(iRow,superBasic) ;
+  }
+}
+
+/*
+  Set the status of a non-basic structural variable based on the
+  variable's value and bounds.
+*/
+
+void CoinPrePostsolveMatrix::setColumnStatusUsingValue(int iColumn)
+{
+  double value = sol_[iColumn];
+  double lower = clo_[iColumn];
+  double upper = cup_[iColumn];
+  if (lower<-1.0e20&&upper>1.0e20) {
+    setColumnStatus(iColumn,isFree);
+  } else if (fabs(lower-value)<=ztolzb_) {
+    setColumnStatus(iColumn,atLowerBound);
+  } else if (fabs(upper-value)<=ztolzb_) {
+    setColumnStatus(iColumn,atUpperBound);
+  } else {
+    setColumnStatus(iColumn,superBasic);
+  }
+}
+#ifndef SLIM_CLP
+
+
+/*
+  Simple routines to return a constant character string for the status value.
+  Separate row and column routines for convenience, and one that just takes
+  the status code.
+*/
+
+const char *CoinPrePostsolveMatrix::columnStatusString (int j) const
+
+{ Status statj = getColumnStatus(j) ;
+
+  switch (statj)
+  { case isFree: { return ("NBFR") ; }
+    case basic: { return ("B") ; }
+    case atUpperBound: { return ("NBUB") ; }
+    case atLowerBound: { return ("NBLB") ; }
+    case superBasic: { return ("SB") ; }
+    default: { return ("INVALID!") ; }
+  }
+}
+
+const char *CoinPrePostsolveMatrix::rowStatusString (int j) const
+
+{ Status statj = getRowStatus(j) ;
+
+  switch (statj)
+  { case isFree: { return ("NBFR") ; }
+    case basic: { return ("B") ; }
+    case atUpperBound: { return ("NBUB") ; }
+    case atLowerBound: { return ("NBLB") ; }
+    case superBasic: { return ("SB") ; }
+    default: { return ("INVALID!") ; }
+  }
+}
+
+const char *statusName (CoinPrePostsolveMatrix::Status status)
+{
+  switch (status) {
+    case CoinPrePostsolveMatrix::isFree: { return ("NBFR") ; }
+    case CoinPrePostsolveMatrix::basic: { return ("B") ; }
+    case CoinPrePostsolveMatrix::atUpperBound: { return ("NBUB") ; }
+    case CoinPrePostsolveMatrix::atLowerBound: { return ("NBLB") ; }
+    case CoinPrePostsolveMatrix::superBasic: { return ("SB") ; }
+    default: { return ("INVALID!") ; }
+  }
+}
+
+#endif
diff --git a/cbits/coin/CoinPresolveDoubleton.cpp b/cbits/coin/CoinPresolveDoubleton.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveDoubleton.cpp
@@ -0,0 +1,1481 @@
+/* $Id: CoinPresolveDoubleton.cpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinFinite.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+
+#include "CoinPresolveEmpty.hpp"	// for DROP_COL/DROP_ROW
+#include "CoinPresolveZeros.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveDoubleton.hpp"
+
+#include "CoinPresolvePsdebug.hpp"
+#include "CoinMessage.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+namespace {	/* begin unnamed local namespace */
+
+#if PRESOLVE_DEBUG > 0
+#define DBGPARAM(zz_param_zz) zz_param_zz
+#else
+#define DBGPARAM(zz_param_zz)
+#endif
+
+/*
+   This routine does the grunt work needed to substitute x for y in all rows i
+   where coeff[i,y] != 0. Given ax + by = c, we have
+  
+  	 y = (c - a*x)/b = c/b + (-a/b)*x
+
+   Suppose we're fixing row i. We need to adjust the row bounds by
+   -coeff[i,y]*(c/b) and coeff[i,x] by coeff[i,y]*(-a/b). The value
+   c/b is passed as the bounds_factor, and -a/b as the coeff_factor.
+
+   row0 is the doubleton row.  It is assumed that coeff[row0,y] has been
+   removed from the column major representation before this routine is
+   called. (Otherwise, we'd have to check for it to avoid a useless row
+   update.)
+
+   Both the row and col representations are updated. There are two cases:
+
+   * coeff[i,x] != 0:
+	in the column rep, modify coeff[i,x] ;
+	in the row rep, modify coeff[i,x] and drop coeff[i,y].
+
+   * coeff[i,x] == 0 (i.e., non-existent):
+        in the column rep, add coeff[i,x]; mcstrt is modified if the column
+	must be moved ;
+	in the row rep, convert coeff[i,y] to coeff[i,x].
+  
+   The row and column reps are inconsistent during the routine and at
+   completion.  In the row rep, column x and y are updated except for
+   the doubleton row, and in the column rep only column x is updated
+   except for coeff[row0,x]. On return, column y and row row0 will be deleted
+   and consistency will be restored.
+*/
+
+bool elim_doubleton (const char *DBGPARAM(msg),
+		     CoinBigIndex *mcstrt, 
+		     double *rlo, double *rup,
+		     double *colels,
+		     int *hrow, int *hcol,
+		     int *hinrow, int *hincol,
+		     presolvehlink *clink, int ncols,
+		     CoinBigIndex *mrstrt, double *rowels,
+		     double coeff_factor,
+		     double bounds_factor,
+		     int DBGPARAM(row0),
+		     int icolx, int icoly)
+
+{
+  CoinBigIndex kcsx = mcstrt[icolx] ;
+  CoinBigIndex kcex = kcsx + hincol[icolx] ;
+
+# if PRESOLVE_DEBUG > 1
+  printf("%s %d x=%d y=%d cf=%g bf=%g nx=%d yrows=(", msg,
+	 row0, icolx, icoly, coeff_factor, bounds_factor, hincol[icolx]) ;
+# endif
+/*
+  Open a loop to scan column y. For each nonzero coefficient (row,y),
+  update column x and the row bounds for the row.
+
+  The initial assert checks that we're properly updating column x.
+*/
+  CoinBigIndex base = mcstrt[icoly] ;
+  int numberInY = hincol[icoly] ;
+  for (int kwhere = 0 ; kwhere < numberInY ; kwhere++) {
+    PRESOLVEASSERT(kcex == kcsx+hincol[icolx]) ;
+    const CoinBigIndex kcoly = base+kwhere ;
+    const int row = hrow[kcoly] ;
+    const double coeffy = colels[kcoly] ;
+    double delta = coeffy*coeff_factor ;
+/*
+  Look for coeff[row,x], then update accordingly.
+*/
+    CoinBigIndex kcolx = presolve_find_row1(row,kcsx,kcex,hrow) ;
+#   if PRESOLVE_DEBUG > 1
+    printf("%d%s ",row,(kcolx < kcex)?"+":"") ;
+#   endif
+/*
+  Case 1: coeff[i,x] != 0: update it in column and row reps; drop coeff[i,y]
+  from row rep.
+*/
+    if (kcolx < kcex) {
+      colels[kcolx] += delta ;
+
+      const CoinBigIndex kmi =
+        presolve_find_col(icolx,mrstrt[row],mrstrt[row]+hinrow[row],hcol) ;
+      rowels[kmi] = colels[kcolx] ;
+      presolve_delete_from_row(row,icoly,mrstrt,hinrow,hcol,rowels) ;
+/*
+  Case 2: coeff[i,x] == 0: add it in the column rep; convert coeff[i,y] in
+  the row rep. presolve_expand_col ensures an empty entry exists at the
+  end of the column. The location of column x may change with expansion.
+*/
+    } else {
+      const bool no_mem = presolve_expand_col(mcstrt,colels,hrow,hincol,
+					      clink,ncols,icolx) ;
+      if (no_mem) return (true) ;
+	  
+      kcsx = mcstrt[icolx] ;
+      kcex = kcsx+hincol[icolx] ;
+      // recompute y as well
+      base = mcstrt[icoly] ;
+
+      hrow[kcex] = row ;
+      colels[kcex] = delta ;
+      hincol[icolx]++ ;
+      kcex++ ;
+
+      CoinBigIndex k2 =
+        presolve_find_col(icoly,mrstrt[row],mrstrt[row]+hinrow[row],hcol) ;
+      hcol[k2] = icolx ;
+      rowels[k2] = delta ;
+    }
+/*
+  Update the row bounds, if necessary. Avoid updating finite infinity.
+*/
+    if (bounds_factor != 0.0) {
+      delta = coeffy*bounds_factor ;
+      if (-PRESOLVE_INF < rlo[row])
+	rlo[row] -= delta ;
+      if (rup[row] < PRESOLVE_INF)
+	rup[row] -= delta ;
+    }
+  }
+
+# if PRESOLVE_DEBUG > 1
+  printf(")\n") ;
+# endif
+
+  return (false) ;
+}
+
+#if PRESOLVE_DEBUG > 0
+/*
+  Debug helpers
+*/
+
+double *doubleton_mult ;
+int *doubleton_id ;
+
+void check_doubletons (const CoinPresolveAction *paction)
+{
+  const CoinPresolveAction * paction0 = paction ;
+  
+  if (paction) {
+    check_doubletons(paction->next) ;
+    
+    if (strcmp(paction0->name(),"doubleton_action") == 0) {
+      const doubleton_action *daction = 
+	dynamic_cast<const doubleton_action *>(paction0) ;
+      for (int i = daction->nactions_-1 ; i >= 0 ; --i) {
+	int icolx = daction->actions_[i].icolx ;
+	int icoly = daction->actions_[i].icoly ;
+	double coeffx = daction->actions_[i].coeffx ;
+	double coeffy = daction->actions_[i].coeffy ;
+
+	doubleton_mult[icoly] = -coeffx/coeffy ;
+	doubleton_id[icoly] = icolx ;
+      }
+    }
+  }
+}
+
+void check_doubletons1(const CoinPresolveAction * paction,
+		       int ncols)
+{
+  doubleton_mult = new double[ncols] ;
+  doubleton_id = new int[ncols] ;
+  int i ;
+  for ( i=0; i<ncols; ++i)
+    doubleton_id[i] = i ;
+  check_doubletons(paction) ;
+  double minmult = 1.0 ;
+  int minid = -1 ;
+  for ( i=0; i<ncols; ++i) {
+    double mult = 1.0 ;
+    int j = i ;
+    if (doubleton_id[j] != j) {
+      printf("MULTS (%d):  ", j) ;
+      while (doubleton_id[j] != j) {
+	printf("%d %g, ", doubleton_id[j], doubleton_mult[j]) ;
+	mult *= doubleton_mult[j] ;
+	j = doubleton_id[j] ;
+      }
+      printf(" == %g\n", mult) ;
+      if (minmult > fabs(mult)) {
+	minmult = fabs(mult) ;
+	minid = i ;
+      }
+    }
+  }
+  if (minid != -1)
+    printf("MIN MULT:  %d %g\n", minid, minmult) ;
+}
+#endif  // PRESOLVE_DEBUG
+
+
+} /* end unnamed local namespace */
+
+
+
+/*
+  It is always the case that one of the variables of a doubleton is, or
+  can be made, implied free, but neither will necessarily be a singleton.
+  Since in the case of a doubleton the number of non-zero entries will never
+  increase if one is eliminated, it makes sense to always eliminate them.
+
+  The col rep and row rep must be consistent.
+ */
+const CoinPresolveAction
+  *doubleton_action::presolve (CoinPresolveMatrix *prob,
+			      const CoinPresolveAction *next)
+
+{
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering doubleton_action::presolve; considering "
+    << prob->numberRowsToDo_ << " rows." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int startEmptyRows = 0 ;
+  int startEmptyColumns = 0 ;
+  startEmptyRows = prob->countEmptyRows() ;
+  startEmptyColumns = prob->countEmptyCols() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0 ;
+  if (prob->tuning_) startTime = CoinCpuTime() ;
+# endif
+# endif
+
+  const int n = prob->ncols_ ;
+  const int m = prob->nrows_ ;
+
+/*
+  Unpack column-major and row-major representations, along with rim vectors.
+*/
+  CoinBigIndex *colStarts = prob->mcstrt_ ;
+  int *colLengths = prob->hincol_ ;
+  double *colCoeffs = prob->colels_ ;
+  int *rowIndices = prob->hrow_ ;
+  presolvehlink *clink = prob->clink_ ;
+
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+
+  CoinBigIndex *rowStarts = prob->mrstrt_ ;
+  int *rowLengths = prob->hinrow_ ;
+  double *rowCoeffs = prob->rowels_ ;
+  int *colIndices = prob->hcol_ ;
+  presolvehlink *rlink = prob->rlink_ ;
+
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+
+  const unsigned char *integerType = prob->integerType_ ;
+
+  double *cost = prob->cost_ ;
+
+  int numberLook = prob->numberRowsToDo_ ;
+  int *look = prob->rowsToDo_ ;
+  const double ztolzb	= prob->ztolzb_ ;
+  const double ztolzero = 1.0e-12 ;
+
+  action *actions = new action [m] ;
+  int nactions = 0 ;
+
+/*
+  zeros will hold columns that should be groomed to remove explicit zeros when
+  we're finished.
+
+  fixed will hold columns that have ended up as fixed variables.
+*/
+  int *zeros = prob->usefulColumnInt_ ;
+  int nzeros = 0 ;
+
+  int *fixed = zeros+n ;
+  int nfixed = 0 ;
+
+  unsigned char *rowstat = prob->rowstat_ ;
+  double *acts	= prob->acts_ ;
+  double *sol = prob->sol_ ;
+/*
+  More like `ignore infeasibility'.
+*/
+  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+
+/*
+  Open the main loop to scan for doubleton candidates.
+*/
+  for (int iLook = 0 ; iLook < numberLook ; iLook++) {
+    const int tgtrow = look[iLook] ;
+/*
+  We need an equality with two coefficients. Avoid isolated constraints, lest
+  both variables vanish.
+
+  Failure of the assert indicates that the row- and column-major
+  representations are out of sync.
+*/
+    if ((rowLengths[tgtrow] != 2) ||
+        (fabs(rup[tgtrow]-rlo[tgtrow]) > ZTOLDP)) continue ;
+
+    const CoinBigIndex krs = rowStarts[tgtrow] ;
+    int tgtcolx = colIndices[krs] ;
+    int tgtcoly = colIndices[krs+1] ;
+
+    PRESOLVEASSERT(colLengths[tgtcolx] > 0 || colLengths[tgtcoly] > 0) ;
+    if (colLengths[tgtcolx] == 1 && colLengths[tgtcoly] == 1) continue ;
+/*
+  Avoid prohibited columns and fixed columns. Make sure the coefficients are
+  nonzero.
+  JJF - test should allow one to be prohibited as long as you leave that
+  one.  I modified earlier code but hope I have got this right.
+*/
+    if (prob->colProhibited(tgtcolx) && prob->colProhibited(tgtcoly))
+      continue ;
+    if (fabs(rowCoeffs[krs]) < ZTOLDP2 || fabs(rowCoeffs[krs+1]) < ZTOLDP2)
+      continue ;
+    if ((fabs(cup[tgtcolx]-clo[tgtcolx]) < ZTOLDP) ||
+	(fabs(cup[tgtcoly]-clo[tgtcoly]) < ZTOLDP)) continue ;
+
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  row " << tgtrow << " colx " << tgtcolx << " coly " << tgtcoly
+      << " passes preliminary eval." << std::endl ;
+#   endif
+
+/*
+  Find this row in each column. The indices are not const because we may flip
+  them below, once we decide which column will be eliminated.
+*/
+    CoinBigIndex krowx =
+        presolve_find_row(tgtrow,colStarts[tgtcolx],
+			  colStarts[tgtcolx]+colLengths[tgtcolx],rowIndices) ;
+    double coeffx = colCoeffs[krowx] ;
+    CoinBigIndex krowy =
+        presolve_find_row(tgtrow,colStarts[tgtcoly],
+			  colStarts[tgtcoly]+colLengths[tgtcoly],rowIndices) ;
+    double coeffy = colCoeffs[krowy] ;
+    const double rhs = rlo[tgtrow] ;
+/*
+  Avoid obscuring a requirement for integrality.
+
+  If only one variable is integer, keep it and substitute for the continuous
+  variable.
+
+  If both are integer, substitute only for the forms x = k*y (k integral
+  and non-empty intersection on bounds on x) or x = 1-y, where both x and
+  y are binary.
+
+  flag bits for integerStatus: 0x01: x integer;  0x02: y integer
+
+  This bit of code works because 0 is continuous, 1 is integer. Make sure
+  that's true.
+*/
+    assert((integerType[tgtcolx] == 0) || (integerType[tgtcolx] == 1)) ;
+    assert((integerType[tgtcoly] == 0) || (integerType[tgtcoly] == 1)) ;
+
+    int integerX = integerType[tgtcolx];
+    int integerY = integerType[tgtcoly];
+    /* if one prohibited then treat that as integer. This
+       may be pessimistic - but will catch SOS etc */
+    if (prob->colProhibited2(tgtcolx))
+      integerX=1;
+    if (prob->colProhibited2(tgtcoly))
+      integerY=1;
+    int integerStatus = (integerY<<1)|integerX ;
+
+    if (integerStatus == 3) {
+      int good = 0 ;
+      double rhs2 = rhs ;
+      if (coeffx < 0.0) {
+	coeffx = -coeffx ;
+	rhs2 += 1 ;
+      }
+      if ((cup[tgtcolx] == 1.0) && (clo[tgtcolx] == 0.0) &&
+	  (fabs(coeffx-1.0) < 1.0e-7) && !prob->colProhibited2(tgtcoly))
+	good = 1 ;
+      if (coeffy < 0.0) {
+	coeffy = -coeffy ;
+	rhs2 += 1 ;
+      }
+      if ((cup[tgtcoly] == 1.0) && (clo[tgtcoly] == 0.0) &&
+	  (fabs(coeffy-1.0) < 1.0e-7) && !prob->colProhibited2(tgtcolx))
+	good |= 2 ;
+      if (!(good == 3 && fabs(rhs2-1.0) < 1.0e-7))
+	integerStatus = -1 ;
+/*
+  Not x+y = 1. Try for ax+by = 0
+*/
+      if (integerStatus < 0 && rhs == 0.0) {
+	coeffx = colCoeffs[krowx] ;
+	coeffy = colCoeffs[krowy] ;
+	double ratio ;
+	bool swap = false ;
+	if (fabs(coeffx) > fabs(coeffy)) {
+	  ratio = coeffx/coeffy ;
+	} else {
+	  ratio = coeffy/coeffx ;
+	  swap = true ;
+	}
+	ratio = fabs(ratio) ;
+	if (fabs(ratio-floor(ratio+0.5)) < ztolzero) {
+	  integerStatus = swap ? 2 : 1 ;
+	}
+      }
+/*
+  One last try --- just require an integral substitution formula.
+
+  But ax+by = 0 above is a subset of ax+by = c below and should pass the
+  test below. For that matter, so will x+y = 1. Why separate special cases
+  above?  -- lh, 121106 --
+*/
+      if (integerStatus < 0) {
+	bool canDo = false ;
+	coeffx = colCoeffs[krowx] ;
+	coeffy = colCoeffs[krowy] ;
+	double ratio ;
+	bool swap = false ;
+	double rhsRatio ;
+	if (fabs(coeffx) > fabs(coeffy)) {
+	  ratio = coeffx/coeffy ;
+	  rhsRatio = rhs/coeffx ;
+	} else {
+	  ratio = coeffy/coeffx ;
+	  rhsRatio = rhs/coeffy ;
+	  swap = true ;
+	}
+	ratio = fabs(ratio) ;
+	if (fabs(ratio-floor(ratio+0.5)) < ztolzero) {
+	  // possible
+	  integerStatus = swap ? 2 : 1 ;
+	  // but check rhs
+	  if (rhsRatio==floor(rhsRatio+0.5))
+	    canDo=true ;
+	}
+#       ifdef COIN_DEVELOP2
+	if (canDo)
+	  printf("Good CoinPresolveDoubleton tgtcolx %d (%g and bounds %g %g) tgtcoly %d (%g and bound %g %g) - rhs %g\n",
+		 tgtcolx,colCoeffs[krowx],clo[tgtcolx],cup[tgtcolx],
+		 tgtcoly,colCoeffs[krowy],clo[tgtcoly],cup[tgtcoly],rhs) ;
+	else
+	printf("Bad CoinPresolveDoubleton tgtcolx %d (%g) tgtcoly %d (%g) - rhs %g\n",
+	       tgtcolx,colCoeffs[krowx],tgtcoly,colCoeffs[krowy],rhs) ;
+#       endif
+	if (!canDo)
+	  continue ;
+      }
+    }
+/*
+  We've resolved integrality concerns. If we concluded that we need to
+  switch the roles of x and y because of integrality, do that now. If both
+  variables are continuous, we may still want to swap for numeric stability.
+  Eliminate the variable with the larger coefficient.
+*/
+    if (integerStatus == 2) {
+      CoinSwap(tgtcoly,tgtcolx) ;
+      CoinSwap(krowy,krowx) ;
+    } else if (integerStatus == 0) {
+      if (fabs(colCoeffs[krowy]) < fabs(colCoeffs[krowx])) {
+	CoinSwap(tgtcoly,tgtcolx) ;
+	CoinSwap(krowy,krowx) ;
+      }
+    }
+/*
+  Don't eliminate y just yet if it's entangled in a singleton row (we want to
+  capture that explicit bound in a column bound).
+*/
+    const CoinBigIndex kcsy = colStarts[tgtcoly] ;
+    const CoinBigIndex kcey = kcsy+colLengths[tgtcoly] ;
+    bool singletonRow = false ;
+    for (CoinBigIndex kcol = kcsy ; kcol < kcey ; kcol++) {
+      if (rowLengths[rowIndices[kcol]] == 1) {
+        singletonRow = true ;
+	break ;
+      }
+    }
+    // skip if y prohibited
+    if (singletonRow || prob->colProhibited2(tgtcoly)) continue ;
+
+    coeffx = colCoeffs[krowx] ;
+    coeffy = colCoeffs[krowy] ;
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  doubleton row " << tgtrow << ", keep x(" << tgtcolx
+      << ") elim x(" << tgtcoly << ")." << std::endl ;
+#   endif
+    PRESOLVE_DETAIL_PRINT(printf("pre_doubleton %dC %dC %dR E\n",
+				 tgtcoly,tgtcolx,tgtrow)) ;
+/*
+  Capture the existing columns and other information before we start to modify
+  the constraint system. Save the shorter column.
+*/
+    action *s = &actions[nactions] ;
+    nactions++ ;
+    s->row = tgtrow ;
+    s->icolx = tgtcolx ;
+    s->clox = clo[tgtcolx] ;
+    s->cupx = cup[tgtcolx] ;
+    s->costx = cost[tgtcolx] ;
+    s->icoly = tgtcoly ;
+    s->costy = cost[tgtcoly] ;
+    s->rlo = rlo[tgtrow] ;
+    s->coeffx = coeffx ;
+    s->coeffy = coeffy ;
+    s->ncolx = colLengths[tgtcolx] ;
+    s->ncoly = colLengths[tgtcoly] ;
+    if (s->ncoly < s->ncolx) {
+      s->colel	= presolve_dupmajor(colCoeffs,rowIndices,colLengths[tgtcoly],
+				    colStarts[tgtcoly],tgtrow) ;
+      s->ncolx = 0 ;
+    } else {
+      s->colel = presolve_dupmajor(colCoeffs,rowIndices,colLengths[tgtcolx],
+				   colStarts[tgtcolx],tgtrow) ;
+      s->ncoly = 0 ;
+    }
+/*
+  Move finite bound information from y to x, so that y is implied free.
+    a x + b y = c
+    l1 <= x <= u1
+    l2 <= y <= u2
+   
+    l2 <= (c - a x) / b <= u2
+    b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a
+    b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a
+*/
+    {
+      double lo1 = -PRESOLVE_INF ;
+      double up1 = PRESOLVE_INF ;
+      
+      if (-PRESOLVE_INF < clo[tgtcoly]) {
+	if (coeffx*coeffy < 0)
+	  lo1 = (coeffy*clo[tgtcoly]-rhs)/-coeffx ;
+	else 
+	  up1 = (coeffy*clo[tgtcoly]-rhs)/-coeffx ;
+      }
+      
+      if (cup[tgtcoly] < PRESOLVE_INF) {
+	if (coeffx*coeffy < 0)
+	  up1 = (coeffy*cup[tgtcoly]-rhs)/-coeffx ;
+	else 
+	  lo1 = (coeffy*cup[tgtcoly]-rhs)/-coeffx ;
+      }
+/*
+  Don't forget the objective coefficient.
+    costy y = costy ((c - a x) / b) = (costy c)/b + x (costy -a)/b
+*/
+      cost[tgtcolx] += (cost[tgtcoly]*-coeffx)/coeffy ;
+      prob->change_bias((cost[tgtcoly]*rhs)/coeffy) ;
+/*
+  The transfer of bounds could make x infeasible. Patch it up if the problem
+  is minor or if the user was so incautious as to instruct us to ignore it.
+  Prefer an integer value if there's one nearby. If there's nothing to be
+  done, break out of the main loop.
+*/
+      {
+	double lo2 = CoinMax(clo[tgtcolx],lo1) ;
+	double up2 = CoinMin(cup[tgtcolx],up1) ;
+	if (lo2 > up2) {
+	  if (lo2 <= up2+prob->feasibilityTolerance_ || fixInfeasibility) {
+	    double nearest = floor(lo2+0.5) ;
+	    if (fabs(nearest-lo2) < 2.0*prob->feasibilityTolerance_) {
+	      lo2 = nearest ;
+	      up2 = nearest ;
+	    } else {
+	      lo2 = up2 ;
+	    }
+	  } else {
+	    prob->status_ |= 1 ;
+	    prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS,
+	    				    prob->messages())
+		 << tgtcolx << lo2 << up2 << CoinMessageEol ;
+	    break ;
+	  }
+	}
+#       if PRESOLVE_DEBUG > 2
+	std::cout
+	  << "  x(" << tgtcolx << ") lb " << clo[tgtcolx] << " --> " << lo2
+	  << ", ub " << cup[tgtcolx] << " --> " << up2 << std::endl ;
+#       endif
+	clo[tgtcolx] = lo2 ;
+	cup[tgtcolx] = up2 ;
+/*
+  Do we have a solution to maintain? If so, take a stab at it. If x ends up at
+  bound, prefer to set it nonbasic, but if we're short of basic variables
+  after eliminating y and the logical for the row, make it basic.
+
+  This code will snap the value of x to bound if it's within the primal
+  feasibility tolerance.
+*/
+	if (rowstat && sol) {
+	  int numberBasic = 0 ;
+	  double movement = 0 ;
+	  if (prob->columnIsBasic(tgtcolx))
+	    numberBasic++ ;
+	  if (prob->columnIsBasic(tgtcoly))
+	    numberBasic++ ;
+	  if (prob->rowIsBasic(tgtrow))
+	    numberBasic++ ;
+	  if (sol[tgtcolx] <= lo2+ztolzb) {
+	    movement = lo2-sol[tgtcolx] ;
+	    sol[tgtcolx] = lo2 ;
+	    prob->setColumnStatus(tgtcolx,
+	    			  CoinPrePostsolveMatrix::atLowerBound) ;
+	  } else if (sol[tgtcolx] >= up2-ztolzb) {
+	    movement = up2-sol[tgtcolx] ;
+	    sol[tgtcolx] = up2 ;
+	    prob->setColumnStatus(tgtcolx,
+	    			  CoinPrePostsolveMatrix::atUpperBound) ;
+	  }
+	  if (numberBasic > 1)
+	    prob->setColumnStatus(tgtcolx,CoinPrePostsolveMatrix::basic) ;
+/*
+  We need to compensate if x was forced to move. Beyond that, even if x
+  didn't move, we've forced y = (c-ax)/b, and that might not have been
+  true before. So even if x didn't move, y may have moved. Note that the
+  constant term c/b is subtracted out as the constraints are modified,
+  so we don't include it when calculating movement for y.
+*/
+	  if (movement) { 
+	    const CoinBigIndex kkcsx = colStarts[tgtcolx] ;
+	    const CoinBigIndex kkcex = kkcsx+colLengths[tgtcolx] ;
+	    for (CoinBigIndex kcol = kkcsx ; kcol < kkcex ; kcol++) {
+	      int row = rowIndices[kcol] ;
+	      if (rowLengths[row])
+		acts[row] += movement*colCoeffs[kcol] ;
+	    }
+	  }
+	  movement = ((-coeffx*sol[tgtcolx])/coeffy)-sol[tgtcoly] ;
+	  if (movement) {
+	    const CoinBigIndex kkcsy = colStarts[tgtcoly] ;
+	    const CoinBigIndex kkcey = kkcsy+colLengths[tgtcoly] ;
+	    for (CoinBigIndex kcol = kkcsy ; kcol < kkcey ; kcol++) {
+	      int row = rowIndices[kcol] ;
+	      if (rowLengths[row])
+		acts[row] += movement*colCoeffs[kcol] ;
+	    }
+	  }
+	}
+	if (lo2 == up2)
+	  fixed[nfixed++] = tgtcolx ;
+      }
+    }
+/*
+  We're done transferring bounds from y to x, and we've patched up the
+  solution if one existed to patch. One last thing to do before we eliminate
+  column y and the doubleton row: put column x and the entangled rows on
+  the lists of columns and rows to look at in the next round of transforms.
+*/
+    {
+      prob->addCol(tgtcolx) ;
+      const CoinBigIndex kkcsy = colStarts[tgtcoly] ;
+      const CoinBigIndex kkcey = kkcsy+colLengths[tgtcoly] ;
+      for (CoinBigIndex kcol = kkcsy ; kcol < kkcey ; kcol++) {
+	int row = rowIndices[kcol] ;
+	prob->addRow(row) ;
+      }
+      const CoinBigIndex kkcsx = colStarts[tgtcolx] ;
+      const CoinBigIndex kkcex = kkcsx+colLengths[tgtcolx] ;
+      for (CoinBigIndex kcol = kkcsx ; kcol < kkcex ; kcol++) {
+	int row = rowIndices[kcol] ;
+	prob->addRow(row) ;
+      }
+    }
+
+/*
+  Empty tgtrow in the column-major matrix.  Deleting the coefficient for
+  (tgtrow,tgtcoly) is a bit costly (given that we're about to drop the whole
+  column), but saves the trouble of checking for it in elim_doubleton.
+*/
+    presolve_delete_from_col(tgtrow,tgtcolx,
+    			     colStarts,colLengths,rowIndices,colCoeffs) ;
+    presolve_delete_from_col(tgtrow,tgtcoly,
+    			     colStarts,colLengths,rowIndices,colCoeffs) ;
+/*
+  Drop tgtrow in the row-major representation: set the length to 0
+  and reclaim the major vector space in bulk storage.
+*/
+    rowLengths[tgtrow] = 0 ;
+    PRESOLVE_REMOVE_LINK(rlink,tgtrow) ;
+
+/*
+  Transfer the colx factors to coly. This modifies coefficients in column x
+  as it removes coefficients in column y.
+*/
+    bool no_mem = elim_doubleton("ELIMD",
+				 colStarts,rlo,rup,colCoeffs,
+				 rowIndices,colIndices,rowLengths,colLengths,
+				 clink,n, 
+				 rowStarts,rowCoeffs,
+				 -coeffx/coeffy,
+				 rhs/coeffy,
+				 tgtrow,tgtcolx,tgtcoly) ;
+    if (no_mem) 
+      throwCoinError("out of memory","doubleton_action::presolve") ;
+
+/*
+  Eliminate coly entirely from the col rep. We'll want to groom colx to remove
+  explicit zeros.
+*/
+    colLengths[tgtcoly] = 0 ;
+    PRESOLVE_REMOVE_LINK(clink, tgtcoly) ;
+    cost[tgtcoly] = 0.0 ;
+
+    rlo[tgtrow] = 0.0 ;
+    rup[tgtrow] = 0.0 ;
+
+    zeros[nzeros++] = tgtcolx ;
+
+#   if PRESOLVE_CONSISTENCY > 0
+    presolve_consistent(prob) ;
+    presolve_links_ok(prob) ;
+#   endif
+  }
+/*
+  Tidy up the collected actions and clean up explicit zeros and fixed
+  variables. Don't bother unless we're feasible (status of 0).
+*/
+  if (nactions && !prob->status_) {
+#   if PRESOLVE_SUMMARY > 0
+    printf("NDOUBLETONS:  %d\n", nactions) ;
+#   endif
+    action *actions1 = new action[nactions] ;
+    CoinMemcpyN(actions, nactions, actions1) ;
+
+    next = new doubleton_action(nactions, actions1, next) ;
+
+    if (nzeros)
+      next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next) ;
+    if (nfixed)
+      next = remove_fixed_action::presolve(prob, fixed, nfixed, next) ;
+  }
+
+  deleteAction(actions,action*) ;
+
+# if COIN_PRESOLVE_TUNING > 0
+  if (prob->tuning_) double thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_sol(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving doubleton_action::presolve, " << droppedRows << " rows, "
+    << droppedColumns << " columns dropped" ;
+# if COIN_PRESOLVE_TUNING > 0
+  std::cout << " in " << thisTime-startTime << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+
+
+/*
+  Reintroduce the column (y) and doubleton row (irow) removed in presolve.
+  Correct the other column (x) involved in the doubleton, update the solution,
+  etc.
+
+  A fair amount of complication arises because the presolve transform saves the
+  shorter of x or y. Postsolve thus includes portions to restore either.
+*/
+void doubleton_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_ ;
+  const int nactions = nactions_ ;
+
+  double *colels	= prob->colels_ ;
+  int *hrow		= prob->hrow_ ;
+  CoinBigIndex *mcstrt	= prob->mcstrt_ ;
+  int *hincol		= prob->hincol_ ;
+  int *link		= prob->link_ ;
+
+  double *clo	= prob->clo_ ;
+  double *cup	= prob->cup_ ;
+
+  double *rlo	= prob->rlo_ ;
+  double *rup	= prob->rup_ ;
+
+  double *dcost	= prob->cost_ ;
+
+  double *sol	= prob->sol_ ;
+  double *acts	= prob->acts_ ;
+  double *rowduals = prob->rowduals_ ;
+  double *rcosts = prob->rcosts_ ;
+
+  unsigned char *colstat = prob->colstat_ ;
+  unsigned char *rowstat = prob->rowstat_ ;
+
+  const double maxmin	= prob->maxmin_ ;
+
+  CoinBigIndex &free_list = prob->free_list_ ;
+
+  const double ztolzb	= prob->ztolzb_ ;
+  const double ztoldj	= prob->ztoldj_ ;
+  const double ztolzero = 1.0e-12 ;
+
+  int nrows = prob->nrows_ ;
+
+  // Arrays to rebuild the unsaved column.
+  int *index1 = new int[nrows] ;
+  double *element1 = new double[nrows] ;
+  CoinZeroN(element1,nrows) ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  char *cdone	= prob->cdone_ ;
+  char *rdone	= prob->rdone_ ;
+
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+  presolve_check_reduced_costs(prob) ;
+
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering doubleton_action::postsolve, " << nactions
+    << " transforms to undo." << std::endl ;
+# endif
+# endif
+/*
+  The outer loop: step through the doubletons in this array of actions.
+  The first activity is to unpack the doubleton.
+*/
+  for (const action *f = &actions[nactions-1] ; actions <= f ; f--) {
+
+    const int irow = f->row ;
+    const double lo0 = f->clox ;
+    const double up0 = f->cupx ;
+
+
+    const double coeffx = f->coeffx ;
+    const double coeffy = f->coeffy ;
+    const int jcolx = f->icolx ;
+    const int jcoly = f->icoly ;
+
+    const double rhs = f->rlo ;
+
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << std::endl
+      << "  restoring doubleton " << irow << ", elim x(" << jcoly
+      << "), kept x(" << jcolx << "); stored col " ;
+    if (f->ncoly)
+      std::cout << jcoly ;
+    else 
+      std::cout << jcolx ;
+    std::cout << "." << std::endl ;
+    std::cout
+      << "  x(" << jcolx << ") " << prob->columnStatusString(jcolx) << " "
+      << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
+      << "; cj " << f->costx << " dj " << rcosts[jcolx] << "." << std::endl ;
+#   endif
+/*
+  jcolx is in the problem (for whatever reason), and the doubleton row (irow)
+  and column (jcoly) have only been processed by empty row/column postsolve
+  (i.e., reintroduced with length 0).
+*/
+    PRESOLVEASSERT(cdone[jcolx] && rdone[irow] == DROP_ROW) ;
+    PRESOLVEASSERT(cdone[jcoly] == DROP_COL) ;
+
+/*
+  Restore bounds for doubleton row, bounds and objective coefficient for x,
+  objective for y.
+
+  Original comment: restoration of rlo and rup likely isn't necessary.
+*/
+    rlo[irow] = f->rlo ;
+    rup[irow] = f->rlo ;
+
+    clo[jcolx] = lo0 ;
+    cup[jcolx] = up0 ;
+
+    dcost[jcolx] = f->costx ;
+    dcost[jcoly] = f->costy ;
+
+/*
+  Set primal solution for y (including status) and row activity for the
+  doubleton row. The motivation (up in presolve) for wanting coeffx < coeffy
+  is to avoid inflation into sol[y]. Since this is a (satisfied) equality,
+  activity is the rhs value and the logical is nonbasic.
+*/
+    const double diffy = rhs-coeffx*sol[jcolx] ;
+    if (fabs(diffy) < ztolzero)
+      sol[jcoly] = 0 ;
+    else
+      sol[jcoly] = diffy/coeffy ;
+    acts[irow] = rhs ;
+    if (rowstat)
+      prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound) ;
+
+#   if PRESOLVE_DEBUG > 2
+/*
+  Original comment: I've forgotten what this is about
+
+  We have sol[y] = (rhs - coeffx*sol[x])/coeffy. As best I can figure,
+  the original check here tested for the possibility of loss of significant
+  digits through cancellation, followed by inflation if coeffy is small.
+  The hazard is clear enough, but the test was puzzling. Overly complicated
+  and it generated false warnings for the common case of sol[y] a clean zero.
+  Replaced with something that I hope is more useful. The tolerances are, sad
+  to say, completely arbitrary.    -- lh, 121106 --
+*/
+    if ((fabs(diffy) < 1.0e-6) && (fabs(diffy) >= ztolzero) &&
+        (fabs(coeffy) < 1.0e-3))
+      std::cout
+        << "  loss of significance? rhs " << rhs
+	<< " (coeffx*sol[jcolx])" << (coeffx*sol[jcolx])
+	<< " diff " << diffy << "." << std::endl ;
+#   endif
+
+/*
+  Time to get into the correction/restoration of coefficients for columns x
+  and y, with attendant correction of row bounds and activities. Accumulate
+  partial reduced costs (missing the contribution from the doubleton row) so
+  that we can eventually calculate a dual for the doubleton row.
+*/
+    double djy = maxmin*dcost[jcoly] ;
+    double djx = maxmin*dcost[jcolx] ;
+/*
+  We saved column y in the action, so we'll use it to reconstruct column x.
+  There are two aspects: correction of existing x coefficients, and fill in.
+  Given
+    coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor
+  we have
+    coeffx[k] = coeffx'[k]-coeffy[k]*coeff_factor
+  where
+    coeff_factor = -coeffx[dblton]/coeffy[dblton].
+
+  Keep in mind that the major vector stored in the action does not include
+  the coefficient from the doubleton row --- the doubleton coefficients are
+  held in coeffx and coeffy.
+*/
+    if (f->ncoly) {
+      int ncoly = f->ncoly-1 ;
+      int *indy = reinterpret_cast<int *>(f->colel+ncoly) ;
+/*
+  Rebuild a threaded column y, starting with the end of the thread and working
+  back to the beginning. In the process, accumulate corrections to column x
+  in element1 and index1. Fix row bounds and activity as we go (add back the
+  constant correction removed in presolve), and accumulate contributions to
+  the reduced cost for y. Don't tweak finite infinity.
+
+  The PRESOLVEASSERT says this row should already be present. 
+*/
+      int ystart = NO_LINK ;
+      int nX = 0 ;
+      for (int kcol = 0 ; kcol < ncoly ; ++kcol) {
+	const int i = indy[kcol] ;
+	PRESOLVEASSERT(rdone[i]) ;
+
+	double yValue = f->colel[kcol] ;
+
+	if (-PRESOLVE_INF < rlo[i])
+	  rlo[i] += (yValue*rhs)/coeffy ;
+	if (rup[i] < PRESOLVE_INF)
+	  rup[i] += (yValue*rhs)/coeffy ;
+
+	acts[i] += (yValue*rhs)/coeffy ;
+
+	djy -= rowduals[i]*yValue ;
+/*
+  Link the coefficient into column y: Acquire the first free slot in the
+  bulk arrays and store the row index and coefficient. Then link the slot
+  in front of coefficients we've already processed.
+*/
+	const CoinBigIndex kfree = free_list ;
+	assert(kfree >= 0 && kfree < prob->bulk0_) ;
+	free_list = link[free_list] ;
+	hrow[kfree] = i ;
+	colels[kfree] = yValue ;
+	link[kfree] = ystart ;
+	ystart = kfree ;
+
+#       if PRESOLVE_DEBUG > 4
+	std::cout
+	  << "  link y " << kfree << " row " << i << " coeff " << yValue
+	  << " dual " << rowduals[i] << std::endl ;
+#       endif
+/*
+  Calculate and store the correction to the x coefficient.
+*/
+	yValue = (yValue*coeffx)/coeffy ;
+	element1[i] = yValue ;
+	index1[nX++] = i ;
+      }
+#     if PRESOLVE_CONSISTENCY > 0
+      presolve_check_free_list(prob) ;
+#     endif
+/*
+  Handle the coefficients of the doubleton row. Insert coeffy, coeffx.
+*/
+      const CoinBigIndex kfree = free_list ;
+      assert(kfree >= 0 && kfree < prob->bulk0_) ;
+      free_list = link[free_list] ;
+      hrow[kfree] = irow ;
+      colels[kfree] = coeffy ;
+      link[kfree] = ystart ;
+      ystart = kfree ;
+
+#     if PRESOLVE_DEBUG > 4
+      std::cout
+	<< "  link y " << kfree << " row " << irow << " coeff " << coeffy
+	<< " dual n/a" << std::endl ;
+#     endif
+
+      element1[irow] = coeffx ;
+      index1[nX++] = irow ;
+/*
+  Attach the threaded column y to mcstrt and record the length.
+*/
+      mcstrt[jcoly] = ystart ;
+      hincol[jcoly] = f->ncoly ;
+/*
+  Now integrate the corrections to column x. Scan the column and correct the
+  existing entries.  The correction could cancel the existing coefficient and
+  we don't want to leave an explicit zero. In this case, relink the column
+  around it.  The freed slot is linked at the beginning of the free list.
+*/
+      CoinBigIndex kcs = mcstrt[jcolx] ;
+      CoinBigIndex last_nonzero = NO_LINK ;
+      int numberInColumn = hincol[jcolx] ;
+      const int numberToDo = numberInColumn ;
+      for (int kcol = 0 ; kcol < numberToDo ; ++kcol) {
+	const int i = hrow[kcs] ;
+	assert(i >= 0 && i < nrows && i != irow) ;
+	double value = colels[kcs]+element1[i] ;
+	element1[i] = 0.0 ;
+	if (fabs(value) >= 1.0e-15) {
+	  colels[kcs] = value ;
+	  last_nonzero = kcs ;
+	  kcs = link[kcs] ;
+	  djx -= rowduals[i]*value ;
+
+#         if PRESOLVE_DEBUG > 4
+	  std::cout
+	    << "  link x " << last_nonzero << " row " << i << " coeff "
+	    << value << " dual " << rowduals[i] << std::endl ;
+#         endif
+
+	} else {
+
+#         if PRESOLVE_DEBUG > 4
+	  std::cout
+	    << "  link x skipped row  " << i << " dual "
+	    << rowduals[i] << std::endl ;
+#         endif
+
+	  numberInColumn-- ;
+	  // add to free list
+	  int nextk = link[kcs] ;
+	  assert(free_list >= 0) ;
+	  link[kcs] = free_list ;
+	  free_list = kcs ;
+	  assert(kcs >= 0) ;
+	  kcs = nextk ;
+	  if (last_nonzero != NO_LINK)
+	    link[last_nonzero] = kcs ;
+	  else
+	    mcstrt[jcolx] = kcs ;
+	}
+      }
+      if (last_nonzero != NO_LINK)
+	link[last_nonzero] = NO_LINK ;
+/*
+  We've dealt with the existing nonzeros in column x. Any remaining
+  nonzeros in element1 will be fill in, which we insert at the beginning of
+  the column.
+*/
+      for (int kcol = 0 ; kcol < nX ; kcol++) {
+	const int i = index1[kcol] ;
+	double xValue = element1[i] ;
+	element1[i] = 0.0 ;
+	if (fabs(xValue) >= 1.0e-15) {
+	  if (i != irow)
+	    djx -= rowduals[i]*xValue ;
+	  numberInColumn++ ;
+	  CoinBigIndex kfree = free_list ;
+	  assert(kfree >= 0 && kfree < prob->bulk0_) ;
+	  free_list = link[free_list] ;
+	  hrow[kfree] = i ;
+	  PRESOLVEASSERT(rdone[hrow[kfree]] || (hrow[kfree] == irow)) ;
+	  colels[kfree] = xValue ;
+	  link[kfree] = mcstrt[jcolx] ;
+	  mcstrt[jcolx] = kfree ;
+#         if PRESOLVE_DEBUG > 4
+	  std::cout
+	    << "  link x " << kfree << " row " << i << " coeff " << xValue
+	    << " dual " ;
+	  if (i != irow)
+	    std::cout << rowduals[i] ;
+	  else
+	    std::cout << "n/a" ;
+	  std::cout << std::endl ;
+#         endif
+	}
+      }
+	  
+#     if PRESOLVE_CONSISTENCY > 0
+      presolve_check_free_list(prob) ;
+#     endif
+	  
+/*
+  Whew! Set the column length and we're done.
+*/
+      assert(numberInColumn) ;
+      hincol[jcolx] = numberInColumn ;
+    } else {
+/*
+  Of course, we could have saved column x in the action. Now we need to
+  regenerate coefficients of column y.
+  Given
+    coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor
+  we have
+    coeffy[k] = (coeffx'[k]-coeffx[k])*(1/coeff_factor)
+  where
+    coeff_factor = -coeffx[dblton]/coeffy[dblton].
+*/
+      const int ncolx = f->ncolx-1 ;
+      int *indx = reinterpret_cast<int *> (f->colel+ncolx) ;
+/*
+  Scan existing column x to find the end. While we're at it, accumulate part
+  of the new y coefficients in index1 and element1.
+*/
+      CoinBigIndex kcs = mcstrt[jcolx] ;
+      int nX = 0 ;
+      for (int kcol = 0 ; kcol < hincol[jcolx]-1 ; ++kcol) {
+	if (colels[kcs]) {
+	  const int i = hrow[kcs] ;
+	  index1[nX++] = i ;
+	  element1[i] = -(colels[kcs]*coeffy)/coeffx ;
+	}
+	kcs = link[kcs] ;
+      }
+      if (colels[kcs]) {
+        const int i = hrow[kcs] ;
+        index1[nX++] = i ;
+        element1[i] = -(colels[kcs]*coeffy)/coeffx ;
+      }
+/*
+  Replace column x with the the original column x held in the doubleton action
+  (recall that this column does not include coeffx). We first move column
+  x to the free list, then thread a column with the original coefficients,
+  back to front.  While we're at it, add the second part of the y coefficients
+  to index1 and element1.
+*/
+      link[kcs] = free_list ;
+      free_list = mcstrt[jcolx] ;
+      int xstart = NO_LINK ;
+      for (int kcol = 0 ; kcol < ncolx ; ++kcol) {
+	const int i = indx[kcol] ;
+	PRESOLVEASSERT(rdone[i] && i != irow) ;
+
+	double xValue = f->colel[kcol] ;
+	CoinBigIndex k = free_list ;
+	assert(k >= 0 && k < prob->bulk0_) ;
+	free_list = link[free_list] ;
+	hrow[k] = i ;
+	colels[k] = xValue ;
+	link[k] = xstart ;
+	xstart = k ;
+
+	djx -= rowduals[i]*xValue ;
+
+	xValue = (xValue*coeffy)/coeffx ;
+	if (!element1[i]) {
+	  element1[i] = xValue ;
+	  index1[nX++] = i ;
+	} else {
+	  element1[i] += xValue ;
+	}
+      }
+#     if PRESOLVE_CONSISTENCY > 0
+      presolve_check_free_list(prob) ;
+#     endif
+/*
+  The same, for the doubleton row.
+*/
+      {
+	double xValue = coeffx ;
+	CoinBigIndex k = free_list ;
+	assert(k >= 0 && k < prob->bulk0_) ;
+	free_list = link[free_list] ;
+	hrow[k] = irow ;
+	colels[k] = xValue ;
+	link[k] = xstart ;
+	xstart = k ;
+	element1[irow] = coeffy ;
+	index1[nX++] = irow ;
+      }
+/*
+  Link the new column x to mcstrt and set the length.
+*/
+      mcstrt[jcolx] = xstart ;
+      hincol[jcolx] = f->ncolx ;
+/*
+  Now get to work building a threaded column y from the nonzeros in element1.
+  As before, build the thread in reverse.
+*/
+      int ystart = NO_LINK ;
+      int leny = 0 ;
+      for (int kcol = 0 ; kcol < nX ; kcol++) {
+	const int i = index1[kcol] ;
+	PRESOLVEASSERT(rdone[i] || i == irow) ;
+	double yValue = element1[i] ;
+	element1[i] = 0.0 ;
+	if (fabs(yValue) >= ztolzero) {
+	  leny++ ;
+	  CoinBigIndex k = free_list ;
+	  assert(k >= 0 && k < prob->bulk0_) ;
+	  free_list = link[free_list] ;
+	  hrow[k] = i ;
+	  colels[k] = yValue ;
+	  link[k] = ystart ;
+	  ystart = k ;
+	}
+      }
+#     if PRESOLVE_CONSISTENCY > 0
+      presolve_check_free_list(prob) ;
+#     endif
+/*
+  Tidy up --- link the new column into mcstrt and set the length.
+*/
+      mcstrt[jcoly] = ystart ;
+      assert(leny) ;
+      hincol[jcoly] = leny ;
+/*
+  Now that we have the original y, we can scan it and do the corrections to
+  the row bounds and activity, and get a start on a reduced cost for y.
+*/
+      kcs = mcstrt[jcoly] ;
+      const int ny = hincol[jcoly] ;
+      for (int kcol = 0 ; kcol < ny ; ++kcol) {
+	const int row = hrow[kcs] ;
+	const double coeff = colels[kcs] ;
+	kcs = link[kcs] ;
+
+	if (row != irow) {
+	  
+	  // undo elim_doubleton(1)
+	  if (-PRESOLVE_INF < rlo[row])
+	    rlo[row] += (coeff*rhs)/coeffy ;
+	  
+	  // undo elim_doubleton(2)
+	  if (rup[row] < PRESOLVE_INF)
+	    rup[row] += (coeff*rhs)/coeffy ;
+	  
+	  acts[row] += (coeff*rhs)/coeffy ;
+	  
+	  djy -= rowduals[row]*coeff ;
+	}
+      }
+    }
+#   if PRESOLVE_DEBUG > 2
+/*
+  Sanity checks. The doubleton coefficients should be linked in the first
+  position of the each column (for no good reason except that it makes it much
+  easier to write these checks).
+*/
+#   if PRESOLVE_DEBUG > 4
+    std::cout
+      << "  kept: saved " << jcolx << " " << coeffx << ", reconstructed "
+      << hrow[mcstrt[jcolx]] << " " << colels[mcstrt[jcolx]]
+      << "." << std::endl ;
+    std::cout
+      << "  elim: saved " << jcoly << " " << coeffy << ", reconstructed "
+      << hrow[mcstrt[jcoly]] << " " << colels[mcstrt[jcoly]]
+      << "." << std::endl ;
+#   endif
+    assert((coeffx == colels[mcstrt[jcolx]]) &&
+	   (coeffy == colels[mcstrt[jcoly]])) ;
+#   endif
+/*
+  Time to calculate a dual for the doubleton row, and settle the status of x
+  and y. Ideally, we'll leave x at whatever nonbasic status it currently has
+  and make y basic. There's a potential problem, however: Remember that we
+  transferred bounds from y to x when we eliminated y. If those bounds were
+  tighter than x's original bounds, we may not be able to maintain x at its
+  present status, or even as nonbasic.
+
+  We'll make two claims here:
+
+    * If the dual value for the doubleton row is chosen to keep the reduced
+      cost djx of col x at its prior value, then the reduced cost djy of col
+      y will be 0. (Crank through the linear algebra to convince yourself.)
+
+    * If the bounds on x have loosened, then it must be possible to make y
+      nonbasic, because we've transferred the tight bound back to y. (Yeah,
+      I'm waving my hands. But it sounds good.  -- lh, 040907 --)
+
+  So ... if we can maintain x nonbasic, then we need to set y basic, which
+  means we should calculate rowduals[dblton] so that rcost[jcoly] == 0. We
+  may need to change the status of x (an artifact of loosening a bound when
+  x was previously a fixed variable).
+  
+  If we need to push x into the basis, then we calculate rowduals[dblton] so
+  that rcost[jcolx] == 0 and make y nonbasic.
+*/
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  pre status: x(" << jcolx << ") " << prob->columnStatusString(jcolx)
+      << " " << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
+      << ", cj " << dcost[jcolx]
+      << ", dj " << djx << "." << std::endl ;
+    std::cout
+      << "  pre status: x(" << jcoly << ") "
+      << clo[jcoly] << " <= " << sol[jcoly] << " <= " << cup[jcoly]
+      << ", cj " << dcost[jcoly]
+      << ", dj " << djy << "." << std::endl ;
+#   endif
+    if (colstat) {
+      bool basicx = prob->columnIsBasic(jcolx) ;
+      bool nblbxok = (fabs(lo0 - sol[jcolx]) < ztolzb) &&
+		     (rcosts[jcolx] >= -ztoldj) ;
+      bool nbubxok = (fabs(up0 - sol[jcolx]) < ztolzb) &&
+		     (rcosts[jcolx] <= ztoldj) ;
+      if (basicx || nblbxok || nbubxok) {
+        if (!basicx) {
+	  if (nblbxok) {
+	    prob->setColumnStatus(jcolx,
+				  CoinPrePostsolveMatrix::atLowerBound) ;
+	  } else if (nbubxok) {
+	    prob->setColumnStatus(jcolx,
+				  CoinPrePostsolveMatrix::atUpperBound) ;
+	  }
+	}
+	prob->setColumnStatus(jcoly,CoinPrePostsolveMatrix::basic) ;
+	rowduals[irow] = djy/coeffy ;
+	rcosts[jcolx] = djx-rowduals[irow]*coeffx ;
+	rcosts[jcoly] = 0.0 ;
+      } else {
+	prob->setColumnStatus(jcolx,CoinPrePostsolveMatrix::basic) ;
+	prob->setColumnStatusUsingValue(jcoly) ;
+	rowduals[irow] = djx/coeffx ;
+	rcosts[jcoly] = djy-rowduals[irow]*coeffy ;
+	rcosts[jcolx] = 0.0 ;
+      }
+#     if PRESOLVE_DEBUG > 2
+      std::cout
+        << "  post status: " << irow << " dual " << rowduals[irow]
+	<< " rhs " << rlo[irow]
+	<< std::endl ;
+      std::cout
+	<< "  post status: x(" << jcolx << ") "
+	<< prob->columnStatusString(jcolx) << " "
+	<< clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
+	<< ", cj " << dcost[jcolx]
+	<< ", dj = " << rcosts[jcolx] << "." << std::endl ;
+      std::cout
+	<< "  post status: x(" << jcoly << ") "
+	<< prob->columnStatusString(jcoly) << " "
+	<< clo[jcoly] << " <= " << sol[jcoly] << " <= " << cup[jcoly]
+	<< ", cj " << dcost[jcoly]
+	<< ", dj " << rcosts[jcoly] << "." << std::endl ;
+/*
+  These asserts are valid but need a scaled tolerance to work well over
+  a range of problems. Occasionally useful for a hard stop while debugging.
+
+      assert(!prob->columnIsBasic(jcolx) || (fabs(rcosts[jcolx]) < 1.0e-5)) ;
+      assert(!prob->columnIsBasic(jcoly) || (fabs(rcosts[jcoly]) < 1.0e-5)) ;
+*/
+#     endif
+    } else {
+      // No status array
+      // this is the coefficient we need to force col y's reduced cost to 0.0 ;
+      // for example, this is obviously true if y is a singleton column
+      rowduals[irow] = djy/coeffy ;
+      rcosts[jcoly] = 0.0 ;
+    }
+    
+#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+/*
+  Mark the column and row as processed by doubleton action. Then check
+  integrity of the threaded matrix.
+*/
+    cdone[jcoly] = DOUBLETON ;
+    rdone[irow] = DOUBLETON ;
+    presolve_check_threads(prob) ;
+#   endif
+#   if PRESOLVE_DEBUG > 0
+/*
+  Confirm accuracy of reduced cost for columns x and y.
+*/
+    {
+      CoinBigIndex k = mcstrt[jcolx] ;
+      const int nx = hincol[jcolx] ;
+      double dj = maxmin*dcost[jcolx] ;
+      
+      for (int kcol = 0 ; kcol < nx ; ++kcol) {
+	const int row = hrow[k] ;
+	const double coeff = colels[k] ;
+	k = link[k] ;
+	dj -= rowduals[row]*coeff ;
+      }
+      if (!(fabs(rcosts[jcolx]-dj) < 100*ZTOLDP))
+	printf("BAD DOUBLE X DJ:  %d %d %g %g\n",
+	       irow,jcolx,rcosts[jcolx],dj) ;
+      rcosts[jcolx] = dj ;
+    }
+    {
+      CoinBigIndex k = mcstrt[jcoly] ;
+      const int ny = hincol[jcoly] ;
+      double dj = maxmin*dcost[jcoly] ;
+      
+      for (int kcol = 0 ; kcol < ny ; ++kcol) {
+	const int row = hrow[k] ;
+	const double coeff = colels[k] ;
+	k = link[k] ;
+	dj -= rowduals[row]*coeff ;
+      }
+      if (!(fabs(rcosts[jcoly]-dj) < 100*ZTOLDP))
+	printf("BAD DOUBLE Y DJ:  %d %d %g %g\n",
+	       irow,jcoly,rcosts[jcoly],dj) ;
+      rcosts[jcoly] = dj ;
+    }
+#   endif
+  }
+/*
+  Done at last. Delete the scratch arrays.
+*/
+  delete [] index1 ;
+  delete [] element1 ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+  presolve_check_reduced_costs(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving doubleton_action::postsolve." << std::endl ;
+# endif
+# endif
+}
+
+
+doubleton_action::~doubleton_action()
+{
+  for (int i=nactions_-1; i>=0; i--) {
+    delete[]actions_[i].colel ;
+  }
+  deleteAction(actions_,action*) ;
+}
+
+
diff --git a/cbits/coin/CoinPresolveDoubleton.hpp b/cbits/coin/CoinPresolveDoubleton.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveDoubleton.hpp
@@ -0,0 +1,73 @@
+/* $Id: CoinPresolveDoubleton.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveDoubleton_H
+#define CoinPresolveDoubleton_H
+
+#define	DOUBLETON	5
+
+/*! \class doubleton_action
+    \brief Solve ax+by=c for y and substitute y out of the problem.
+
+  This moves the bounds information for y onto x, making y free and allowing
+  us to substitute it away.
+  \verbatim
+	   a x + b y = c
+	   l1 <= x <= u1
+	   l2 <= y <= u2	==>
+	  
+	   l2 <= (c - a x) / b <= u2
+	   b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a
+	   b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a
+  \endverbatim
+*/
+class doubleton_action : public CoinPresolveAction {
+ public:
+  struct action {
+
+    double clox;
+    double cupx;
+    double costx;
+    
+    double costy;
+
+    double rlo;
+
+    double coeffx;
+    double coeffy;
+
+    double *colel;
+
+    int icolx;
+    int icoly;
+    int row;
+    int ncolx;
+    int ncoly;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+ private:
+  doubleton_action(int nactions,
+		      const action *actions,
+		      const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions)
+{}
+
+ public:
+  const char *name() const { return ("doubleton_action"); }
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *,
+					 const CoinPresolveAction *next);
+  
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~doubleton_action();
+};
+#endif
+
+
diff --git a/cbits/coin/CoinPresolveDual.cpp b/cbits/coin/CoinPresolveDual.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveDual.cpp
@@ -0,0 +1,1158 @@
+/* $Id: CoinPresolveDual.cpp 1607 2013-07-16 09:01:29Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveDual.hpp"
+#include "CoinMessage.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinFloatEqual.hpp"
+
+/*
+  Define PRESOLVE_DEBUG and PRESOLVE_CONSISTENCY as compile flags! If not
+  uniformly on across all uses of presolve code you'll get something between
+  garbage and a core dump. See comments in CoinPresolvePsdebug.hpp
+*/
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+/*
+  Set to > 0 to enable bound propagation on dual variables? This has been
+  disabled for a good while. See notes in code.
+
+  #define PRESOLVE_TIGHTEN_DUALS 1
+*/
+/*
+  Guards incorrect code that attempts to adjust a column solution. See
+  comments with the code. Could possibly be fixed, which is why it hasn't
+  been chopped out.
+
+  #define REMOVE_DUAL_ACTION_REPAIR_SOLN 1
+*/
+
+/*
+  In this transform we're looking to prove bounds on the duals y<i> and
+  reduced costs cbar<j>. We can use this in two ways.
+  
+  First, if we can prove a bound on the reduced cost cbar<j> with strict
+  inequality,
+    * cbar<j> > 0 ==> x<j> NBLB at optimality
+    * cbar<j> < 0 ==> x<j> NBUB at optimality
+  If the required bound is not finite, the problem is unbounded.  Andersen &
+  Andersen call this a dominated column.
+
+  Second, suppose we can show that cbar<i> = -y<i> is strictly nonzero
+  for the logical s<i> associated with some inequality i. (There must be
+  exactly one finite row bound, so that the logical has exactly one finite
+  bound which is 0).  If cbar<i> demands the logical be nonbasic at bound,
+  it's zero, and we can convert the inequality to an equality.
+
+  Not based on duals and reduced costs, but in the same vein, if we can
+  identify an architectural x<j> that'll accomplish the same goal (bring
+  one constraint tight when moved in a favourable direction), we can make
+  that constraint an equality. The conditions are different, however:
+    * Moving x<j> in the favourable direction tightens exactly one
+      constraint.
+    * The bound (l<j> or u<j>) in the favourable direction is infinite.
+    * If x<j> is entangled in any other constraints, moving x<j> in the
+      favourable direction loosens those constraints.
+  A bit of thought and linear algebra is required to convince yourself that in
+  the circumstances, cbar<j> = c<j>, hence we need only look at c<j> to
+  determine the favourable direction.
+
+  
+  To get from bounds on the duals to bounds on the reduced costs, note that
+    cbar<j> = c<j> - (SUM{P}a<ij>y<i> + SUM{M}a<ij>y<i>)
+  for P = {a<ij> > 0} and M = {a<ij> < 0}. Then
+    cbarmin<j> = c<j> - (SUM{P}a<ij>ymax<i> + SUM{M}a<ij>ymin<i>)
+    cbarmax<j> = c<j> - (SUM{P}a<ij>ymin<i> + SUM{M}a<ij>ymax<i>)
+
+  As A&A note, the reverse implication also holds:
+    * if l<j> = -infty, cbar<j> <= 0 at optimality
+    * if u<j> =  infty, cbar<j> >= 0 at optimality
+
+  We can use this to run bound propagation on the duals in an attempt to
+  tighten bounds and force more reduced costs to strict inequality. Suppose
+  u<j> = infty. Then cbar<j> >= 0. It must be possible to achieve this, so
+  cbarmax<j> >= 0:
+    0 <= c<j> - (SUM{P}a<ij>ymin<i> + SUM{M}a<ij>ymax<i>)
+  Solve for y<t>, a<tj> > 0:
+    y<t> <= 1/a<tj>[c<j> - (SUM{P\t}a<ij>ymin<i> + SUM{M}a<ij>ymax<i>)]
+  If a<tj> < 0,
+    y<t> >= 1/a<tj>[c<j> - (SUM{P}a<ij>ymin<i> + SUM{M\t}a<ij>ymax<i>)]
+  For l<j> = -infty, cbar<j> <= 0, hence cbarmin <= 0: 
+    0 >= c<j> - (SUM{P}a<ij>ymax<i> + SUM{M}a<ij>ymin<i>) 
+  Solve for y<t>, a<tj> > 0:
+    y<t> >= 1/a<tj>[c<j> - (SUM{P\t}a<ij>ymax<i> + SUM{M}a<ij>ymin<i>)]
+  If a<tj> < 0,
+    y<t> <= 1/a<tj>[c<j> - (SUM{P}a<ij>ymax<i> + SUM{M\t}a<ij>ymin<i>)]
+
+  We can get initial bounds on ymin<i> and ymax<i> from column singletons
+  x<j>, where
+    cbar<j> = c<j> - a<ij>y<i>
+  If u<j> = infty, then at optimality
+    0 <= cbar<j> = c<j> - a<ij>y<i>
+  For a<ij> > 0 we have
+    y<i> <= c<j>/a<ij>
+  and for a<ij> < 0 we have
+    y<i> >= c<j>/a<ij>
+  We can do a similar calculation for l<j> = -infty, so that
+    0 >= cbar<j> = c<j> - a<ij>y<i>
+  For a<ij> > 0 we have
+    y<i> >= c<j>/a<ij>
+  and for a<ij> < 0 we have
+    y<i> <= c<j>/a<ij>
+  A logical is a column singleton with c<j> = 0.0 and |a<ij>| = 1.0. One or
+  both bounds can be finite, depending on constraint representation.
+
+  This code is hardwired for minimisation.
+
+  Extensive rework of the second part of the routine Fall 2011 to add a
+  postsolve transform to fix bug #67, incorrect status for logicals.
+  -- lh, 111208 --
+*/
+/*
+  Original comments from 040916:
+
+  This routine looks to be something of a work in progress.  Down in the
+  bound propagation loop, why do we only work with variables with u_j =
+  infty? The corresponding section of code for l_j = -infty is ifdef'd away.
+  l<j> = -infty is uncommon; perhaps it's not worth the effort?
+
+  Why exclude the code protected by PRESOLVE_TIGHTEN_DUALS? Why are we
+  using ekkinf instead of PRESOLVE_INF?
+*/
+const CoinPresolveAction
+  *remove_dual_action::presolve (CoinPresolveMatrix *prob,
+				 const CoinPresolveAction *next)
+{
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering remove_dual_action::presolve, " << prob->nrows_ 
+    << "x" << prob->ncols_ << "." << std::endl ;
+# endif
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_sol(prob,2,1,1) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int startEmptyRows = 0 ;
+  int startEmptyColumns = 0 ;
+  startEmptyRows = prob->countEmptyRows() ;
+  startEmptyColumns = prob->countEmptyCols() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0 ;
+  if (prob->tuning_) startTime = CoinCpuTime() ;
+# endif
+# endif
+
+  // column-major representation
+  const int ncols = prob->ncols_ ;
+  const CoinBigIndex *const mcstrt = prob->mcstrt_ ;
+  const int *const hincol = prob->hincol_ ;
+  const int *const hrow = prob->hrow_ ;
+  const double *const colels = prob->colels_ ;
+  const double *const cost = prob->cost_ ;
+
+  // column type, bounds, solution, and status
+  const unsigned char *const integerType = prob->integerType_ ;
+  const double *const clo = prob->clo_ ;
+  const double *const cup = prob->cup_ ;
+  double *const csol = prob->sol_ ;
+  unsigned char *&colstat = prob->colstat_ ;
+
+  // row-major representation
+  const int nrows = prob->nrows_ ;
+  const CoinBigIndex *const mrstrt = prob->mrstrt_ ;
+  const int *const hinrow = prob->hinrow_ ;
+  const int *const hcol = prob->hcol_ ;
+# if REMOVE_DUAL_ACTION_REPAIR_SOLN > 0
+  const double *const rowels = prob->rowels_ ;
+# endif
+
+  // row bounds
+  double *const rlo = prob->rlo_ ;
+  double *const rup = prob->rup_ ;
+
+  // tolerances
+  const double ekkinf2 = PRESOLVE_SMALL_INF ;
+  const double ekkinf = ekkinf2*1.0e8 ;
+  const double ztolcbarj = prob->ztoldj_ ;
+  const CoinRelFltEq relEq(prob->ztolzb_) ;
+
+/*
+  Grab one of the preallocated scratch arrays to hold min and max values of
+  row duals.
+*/
+  double *ymin	= prob->usefulRowDouble_ ;
+  double *ymax	= ymin+nrows ;
+/*
+  Initialise row dual min/max. The defaults are +/- infty, but if we know
+  that the logical has no upper (lower) bound, it can only be nonbasic at
+  the other bound. Given minimisation, we can conclude:
+    * <= constraint ==> [0,infty] ==> NBLB ==> cbar<i> > 0 ==> y<i> < 0
+    * >= constraint ==> [-infty,0] ==> NBUB ==> cbar<i> < 0 ==> y<i> > 0
+  Range constraints are not helpful here, the dual can be either sign. There's
+  no calculation because we assume the objective coefficient c<i> = 0  and the
+  coefficient a<ii> = 1.0, hence cbar<i> = -y<i>.
+*/
+  for (int i = 0; i < nrows; i++) {
+    const bool no_lb = (rup[i] >= ekkinf) ;
+    const bool no_ub = (rlo[i] <= -ekkinf) ;
+
+    ymin[i] = ((no_lb && !no_ub)?0.0:(-PRESOLVE_INF)) ;
+    ymax[i] = ((no_ub && !no_lb)?0.0:PRESOLVE_INF) ;
+  }
+/*
+  We can do a similar calculation with singleton columns where the variable
+  has only one finite bound, but we have to work a bit harder, as the cost
+  coefficient c<j> is not necessarily 0.0 and a<ij> is not necessarily 1.0.
+
+  cbar<j> = c<j> - y<i>a<ij>, hence y<i> = c<j>/a<ij> at cbar<j> = 0. The
+  question is whether this is an upper or lower bound on y<i>.
+    * x<j> NBLB ==> cbar<j> >= 0
+      a<ij> > 0 ==> increasing y<i> decreases cbar<j> ==> upper bound 
+      a<ij> < 0 ==> increasing y<i> increases cbar<j> ==> lower bound 
+    * x<j> NBUB ==> cbar<j> <= 0
+      a<ij> > 0 ==> increasing y<i> decreases cbar<j> ==> lower bound 
+      a<ij> < 0 ==> increasing y<i> increases cbar<j> ==> upper bound 
+  The condition below (simple test for equality to choose the bound) looks
+  a bit odd, but a bit of boolean algebra should convince you it's correct.
+  We have a bound; the only question is whether it's upper or lower.
+
+  Skip integer variables; it's far too likely that we'll tighten infinite
+  bounds elsewhere in presolve.
+
+  NOTE: If bound propagation is applied to continuous variables, the same
+  	hazard will apply.  -- lh, 110611 --
+*/
+  for (int j = 0 ; j < ncols ; j++) {
+    if (integerType[j]) continue ;
+    if (hincol[j] != 1) continue ;
+    const bool no_ub = (cup[j] >= ekkinf) ;
+    const bool no_lb = (clo[j] <= -ekkinf) ;
+    if (no_ub != no_lb) {
+      const int &i = hrow[mcstrt[j]] ;
+      double aij = colels[mcstrt[j]] ;
+      PRESOLVEASSERT(fabs(aij) > ZTOLDP) ;
+      const double yzero = cost[j]/aij ;
+      if ((aij > 0.0) == no_ub) {
+	if (ymax[i] > yzero)
+	  ymax[i] = yzero ;
+      } else {
+	if (ymin[i] < yzero)
+	  ymin[i] = yzero ;
+      }
+    }
+  }
+  int nfixup_cols = 0 ;
+  int nfixdown_cols = ncols ;
+  // Grab another work array, sized to ncols_
+  int *fix_cols	= prob->usefulColumnInt_ ;
+# if PRESOLVE_TIGHTEN_DUALS > 0
+  double *cbarmin = new double[ncols] ;
+  double *cbarmax = new double[ncols] ;
+# endif
+/*
+  Now we have (admittedly weak) bounds on the dual for each row. We can use
+  these to calculate upper and lower bounds on cbar<j>. Open loops to
+  take multiple passes over all columns.
+*/
+  int nPass = 0 ;
+  while (nPass++ < 100) {
+    int tightened = 0 ;
+    for (int j = 0 ; j < ncols ; j++) {
+      if (hincol[j] <= 0) continue ;
+/*
+  Calculate min cbar<j> and max cbar<j> for the column by calculating the
+  contribution to c<j>-ya<j> using ymin<i> and ymax<i> from above.
+*/
+      const CoinBigIndex &kcs = mcstrt[j] ;
+      const CoinBigIndex kce = kcs + hincol[j] ;
+      // Number of infinite rows
+      int nflagu = 0 ;
+      int nflagl = 0 ;
+      // Number of ordinary rows
+      int nordu = 0 ;
+      int nordl = 0 ;
+      double cbarjmin = cost[j] ;
+      double cbarjmax = cbarjmin ;
+      for (CoinBigIndex k = kcs ; k < kce ; k++) {
+	const int &i = hrow[k] ;
+	const double &aij = colels[k] ;
+	const double mindelta = aij*ymin[i] ;
+	const double maxdelta = aij*ymax[i] ;
+	
+	if (aij > 0.0) {
+	  if (ymin[i] >= -ekkinf2) {
+	    cbarjmax -= mindelta ;
+	    nordu++ ;
+	  } else {
+	    nflagu++ ;
+	  }
+	  if (ymax[i] <= ekkinf2) {
+	    cbarjmin -= maxdelta ;
+	    nordl++ ;
+	  } else {
+	    nflagl++ ;
+	  }
+	} else {
+	  if (ymax[i] <= ekkinf2) {
+	    cbarjmax -= maxdelta ;
+	    nordu++ ;
+	  } else {
+	    nflagu++ ;
+	  }
+	  if (ymin[i] >= -ekkinf2) {
+	    cbarjmin -= mindelta ;
+	    nordl++ ;
+	  } else {
+	    nflagl++ ;
+	  }
+	}
+      }
+/*
+  See if we can tighten bounds on a dual y<t>. See the comments at the head of
+  the file for the linear algebra.
+
+  At this point, I don't understand the restrictions on propagation. Neither
+  are necessary. The net effect is to severely restrict the circumstances
+  where we'll propagate. Requiring nflagu == 1 excludes the case where all
+  duals have finite bounds (unlikely?). And why cbarjmax < -ztolcbarj?
+
+  In any event, we're looking for the row that's contributing the infinity. If
+  a<tj> > 0, the contribution is due to ymin<t> and we tighten ymax<t>;
+  a<tj> < 0, ymax<t> and ymin<t>, respectively.
+
+  The requirement cbarjmax < (ymax[i]*aij-ztolcbarj) ensures we don't propagate
+  tiny changes. If we make a change, it will affect cbarjmin. Make the
+  adjustment immediately.
+
+  Continuous variables only.
+*/
+      if (!integerType[j]) {
+	if (cup[j] > ekkinf) {
+	  if (nflagu == 1 && cbarjmax < -ztolcbarj) {
+	    for (CoinBigIndex k = kcs ; k < kce; k++) {
+	      const int i = hrow[k] ;
+	      const double aij = colels[k] ;
+	      if (aij > 0.0 && ymin[i] < -ekkinf2) {
+		if (cbarjmax < (ymax[i]*aij-ztolcbarj)) {
+		  const double newValue = cbarjmax/aij ;
+		  if (ymax[i] > ekkinf2 && newValue <= ekkinf2) {
+		    nflagl-- ;
+		    cbarjmin -= aij*newValue ;
+		  } else if (ymax[i] <= ekkinf2) {
+		    cbarjmin -= aij*(newValue-ymax[i]) ;
+		  }
+#		  if PRESOLVE_DEBUG > 1
+		  std::cout
+		    << "NDUAL(infu/inf): u(" << j << ") = " << cup[j]
+		    << ": max y(" << i << ") was " << ymax[i]
+		    << " now " << newValue << "." << std::endl ;
+#		  endif
+		  ymax[i] = newValue ;
+		  tightened++ ;
+		}
+	      } else if (aij < 0.0 && ymax[i] > ekkinf2) {
+		if (cbarjmax < (ymin[i]*aij-ztolcbarj)) {
+		  const double newValue = cbarjmax/aij ;
+		  if (ymin[i] < -ekkinf2 && newValue >= -ekkinf2) {
+		    nflagl-- ;
+		    cbarjmin -= aij*newValue ;
+		  } else if (ymin[i] >= -ekkinf2) {
+		    cbarjmin -= aij*(newValue-ymin[i]) ;
+		  }
+#		  if PRESOLVE_DEBUG > 1
+		  std::cout
+		    << "NDUAL(infu/inf): u(" << j << ") = " << cup[j]
+		    << ": min y(" << i << ") was " << ymin[i]
+		    << " now " << newValue << "." << std::endl ;
+#		  endif
+		  ymin[i] = newValue ;
+		  tightened++ ;
+		  // Huh? asymmetric 
+		  // cbarjmin = 0.0 ;
+		}
+	      }
+	    }
+	  } else if (nflagl == 0 && nordl == 1 && cbarjmin < -ztolcbarj) {
+/*
+  This is a column singleton. Why are we doing this? It's not like changes
+  to other y will affect this.
+*/
+	    for (CoinBigIndex k = kcs; k < kce; k++) {
+	      const int i = hrow[k] ;
+	      const double aij = colels[k] ;
+	      if (aij > 0.0) {
+#		if PRESOLVE_DEBUG > 1
+		std::cout
+		  << "NDUAL(infu/sing): u(" << j << ") = " << cup[j]
+		  << ": max y(" << i << ") was " << ymax[i]
+		  << " now " << ymax[i]+cbarjmin/aij << "." << std::endl ;
+#		endif
+		ymax[i] += cbarjmin/aij ;
+		cbarjmin = 0.0 ;
+		tightened++ ;
+	      } else if (aij < 0.0 ) {
+#		if PRESOLVE_DEBUG > 1
+		std::cout
+		  << "NDUAL(infu/sing): u(" << j << ") = " << cup[j]
+		  << ": min y(" << i << ") was " << ymin[i]
+		  << " now " << ymin[i]+cbarjmin/aij << "." << std::endl ;
+#		endif
+		ymin[i] += cbarjmin/aij ;
+		cbarjmin = 0.0 ;
+		tightened++ ;
+	      }
+	    }
+	  }
+	}   // end u<j> = infty
+#       if PROCESS_INFINITE_LB
+/*
+  Unclear why this section is commented out, except for the possibility that
+  bounds of -infty < x < something are rare and it likely suffered fromm the
+  same errors. Consider the likelihood that this whole block needs to be
+  edited to sway min/max, & similar.
+*/
+	if (clo[j]<-ekkinf) {
+	  // cbarj can not be positive
+	  if (cbarjmin > ztolcbarj&&nflagl == 1) {
+	    // We can make bound finite one way
+	    for (CoinBigIndex k = kcs; k < kce; k++) {
+	      const int i = hrow[k] ;
+	      const double coeff = colels[k] ;
+	      
+	      if (coeff < 0.0&&ymin[i] < -ekkinf2) {
+		// ymax[i] has upper bound
+		if (cbarjmin>ymax[i]*coeff+ztolcbarj) {
+		  const double newValue = cbarjmin/coeff ;
+		  // re-compute hi
+		  if (ymax[i] > ekkinf2 && newValue <= ekkinf2) {
+		    nflagu-- ;
+		    cbarjmax -= coeff * newValue ;
+		  } else if (ymax[i] <= ekkinf2) {
+		    cbarjmax -= coeff * (newValue-ymax[i]) ;
+		  }
+		  ymax[i] = newValue ;
+		  tightened++ ;
+#		  if PRESOLVE_DEBUG > 1
+		  printf("Col %d, row %d max pi now %g\n",j,i,ymax[i]) ;
+#		  endif
+		}
+	      } else if (coeff > 0.0 && ymax[i] > ekkinf2) {
+		// ymin[i] has lower bound
+		if (cbarjmin>ymin[i]*coeff+ztolcbarj) {
+		  const double newValue = cbarjmin/coeff ;
+		  // re-compute lo
+		  if (ymin[i] < -ekkinf2 && newValue >= -ekkinf2) {
+		    nflagu-- ;
+		    cbarjmax -= coeff * newValue ;
+		  } else if (ymin[i] >= -ekkinf2) {
+		    cbarjmax -= coeff*(newValue-ymin[i]) ;
+		  }
+		  ymin[i] = newValue ;
+		  tightened++ ;
+#		  if PRESOLVE_DEBUG > 1
+		  printf("Col %d, row %d min pi now %g\n",j,i,ymin[i]) ;
+#		  endif
+		}
+	      }
+	    }
+	  } else if (nflagu == 0 && nordu == 1 && cbarjmax > ztolcbarj) {
+	    // We may be able to tighten
+	    for (CoinBigIndex k = kcs; k < kce; k++) {
+	      const int i = hrow[k] ;
+	      const double coeff = colels[k] ;
+	      
+	      if (coeff < 0.0) {
+		ymax[i] += cbarjmax/coeff ;
+		cbarjmax =0.0 ;
+		tightened++ ;
+#		if PRESOLVE_DEBUG > 1
+		printf("Col %d, row %d max pi now %g\n",j,i,ymax[i]) ;
+#		endif
+	      } else if (coeff > 0.0 ) {
+		ymin[i] += cbarjmax/coeff ;
+		cbarjmax =0.0 ;
+		tightened++ ;
+#		if PRESOLVE_DEBUG > 1
+		printf("Col %d, row %d min pi now %g\n",j,i,ymin[i]) ;
+#		endif
+	      }
+	    }
+	  }
+	}    // end l<j> < -infty
+#       endif	// PROCESS_INFINITE_LB
+      }
+/*
+  That's the end of propagation of bounds for dual variables.
+*/
+#     if PRESOLVE_TIGHTEN_DUALS > 0
+      cbarmin[j] = (nflagl?(-PRESOLVE_INF):cbarjmin) ;
+      cbarmax[j] = (nflagu?PRESOLVE_INF:cbarjmax) ;
+#     endif
+/*
+  If cbarmin<j> > 0 (strict inequality) then x<j> NBLB at optimality. If l<j>
+  is -infinity, notify the user and set the status to unbounded.
+*/
+      if (cbarjmin > ztolcbarj && nflagl == 0 && !prob->colProhibited2(j)) {
+	if (clo[j] <= -ekkinf) {
+	  CoinMessageHandler *msghdlr = prob->messageHandler() ;
+	  msghdlr->message(COIN_PRESOLVE_COLUMNBOUNDB,prob->messages())
+	    << j << CoinMessageEol ;
+	  prob->status_ |= 2 ;
+	  break ;
+	} else {
+	  fix_cols[--nfixdown_cols] = j ;
+#	  if PRESOLVE_DEBUG > 1
+	  std::cout << "NDUAL(fix l): fix x(" << j << ")" ;
+	  if (csol) std::cout << " = " << csol[j] ;
+	  std::cout
+	    << " at l(" << j << ") = " << clo[j] << "; cbar("
+	    << j << ") > " << cbarjmin << "." << std::endl ;
+#	  endif
+	  if (csol) {
+#           if REMOVE_DUAL_ACTION_REPAIR_SOLN > 0
+/*
+  Original comment: User may have given us feasible solution - move if simple
+
+  Except it's not simple. The net result is that we end up with an excess of
+  basic variables. Mark x<j> NBLB and let the client recalculate the solution
+  after establishing the basis.
+*/
+	    if (csol[j]-clo[j] > 1.0e-7 && hincol[j] == 1) {
+	      double value_j = colels[mcstrt[j]] ;
+	      double distance_j = csol[j]-clo[j] ;
+	      int row = hrow[mcstrt[j]] ;
+	      // See if another column can take value
+	      for (CoinBigIndex kk = mrstrt[row] ; kk < mrstrt[row]+hinrow[row] ; kk++) {
+		const int k = hcol[kk] ;
+		if (colstat[k] == CoinPrePostsolveMatrix::superBasic)
+		  continue ;
+
+		if (hincol[k] == 1 && k != j) {
+		  const double value_k = rowels[kk] ;
+		  double movement ;
+		  if (value_k*value_j>0.0) {
+		    // k needs to increase
+		    double distance_k = cup[k]-csol[k] ;
+		    movement = CoinMin((distance_j*value_j)/value_k,distance_k) ;
+		  } else {
+		    // k needs to decrease
+		    double distance_k = clo[k]-csol[k] ;
+		    movement = CoinMax((distance_j*value_j)/value_k,distance_k) ;
+		  }
+		  if (relEq(movement,0)) continue ;
+
+		  csol[k] += movement ;
+		  if (relEq(csol[k],clo[k]))
+		  { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; }
+		  else
+		  if (relEq(csol[k],cup[k]))
+		  { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; }
+		  else
+		  if (colstat[k] != CoinPrePostsolveMatrix::isFree)
+		  { colstat[k] = CoinPrePostsolveMatrix::basic ; }
+		  printf("NDUAL: x<%d> moved %g to %g; ",
+			 k,movement,csol[k]) ;
+		  printf("lb = %g, ub = %g, status now %s.\n",
+			 clo[k],cup[k],columnStatusString(k)) ;
+		  distance_j -= (movement*value_k)/value_j ;
+		  csol[j] -= (movement*value_k)/value_j ;
+		  if (distance_j<1.0e-7)
+		    break ;
+		}
+	      }
+	    }
+#	    endif    // repair solution.
+
+	    csol[j] = clo[j] ;
+	    colstat[j] = CoinPrePostsolveMatrix::atLowerBound ;
+	  }
+	}
+      } else if (cbarjmax < -ztolcbarj && nflagu == 0 &&
+      		 !prob->colProhibited2(j)) {
+/*
+  If cbarmax<j> < 0 (strict inequality) then x<j> NBUB at optimality. If u<j>
+  is infinity, notify the user and set the status to unbounded.
+*/
+	if (cup[j] >= ekkinf) {
+	  CoinMessageHandler *msghdlr = prob->messageHandler() ;
+	  msghdlr->message(COIN_PRESOLVE_COLUMNBOUNDA,prob->messages())
+	    << j << CoinMessageEol ;
+	  prob->status_ |= 2 ;
+	  break ;
+	} else {
+	  fix_cols[nfixup_cols++] = j ;
+#	  if PRESOLVE_DEBUG > 1
+	  std::cout << "NDUAL(fix u): fix x(" << j << ")" ;
+	  if (csol) std::cout << " = " << csol[j] ;
+	  std::cout
+	    << " at u(" << j << ") = " << cup[j] << "; cbar("
+	    << j << ") < " << cbarjmax << "." << std::endl ;
+#	  endif
+	  if (csol) {
+#	    if 0
+	    // See comments above for 'fix at lb'.
+	    if (cup[j]-csol[j] > 1.0e-7 && hincol[j] == 1) {
+	      double value_j = colels[mcstrt[j]] ;
+	      double distance_j = csol[j]-cup[j] ;
+	      int row = hrow[mcstrt[j]] ;
+	      // See if another column can take value
+	      for (CoinBigIndex kk = mrstrt[row] ; kk < mrstrt[row]+hinrow[row] ; kk++) {
+		const int k = hcol[kk] ;
+		if (colstat[k] == CoinPrePostsolveMatrix::superBasic)
+		  continue ;
+
+		if (hincol[k] == 1 && k != j) {
+		  const double value_k = rowels[kk] ;
+		  double movement ;
+		  if (value_k*value_j<0.0) {
+		    // k needs to increase
+		    double distance_k = cup[k]-csol[k] ;
+		    movement = CoinMin((distance_j*value_j)/value_k,distance_k) ;
+		  } else {
+		    // k needs to decrease
+		    double distance_k = clo[k]-csol[k] ;
+		    movement = CoinMax((distance_j*value_j)/value_k,distance_k) ;
+		  }
+		  if (relEq(movement,0)) continue ;
+
+		  csol[k] += movement ;
+		  if (relEq(csol[k],clo[k]))
+		  { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; }
+		  else
+		  if (relEq(csol[k],cup[k]))
+		  { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; }
+		  else
+		  if (colstat[k] != CoinPrePostsolveMatrix::isFree)
+		  { colstat[k] = CoinPrePostsolveMatrix::basic ; }
+		  printf("NDUAL: x<%d> moved %g to %g; ",
+			 k,movement,csol[k]) ;
+		  printf("lb = %g, ub = %g, status now %s.\n",
+			 clo[k],cup[k],columnStatusString(k)) ;
+		  distance_j -= (movement*value_k)/value_j ;
+		  csol[j] -= (movement*value_k)/value_j ;
+		  if (distance_j>-1.0e-7)
+		    break ;
+		}
+	      }
+	    }
+#	    endif
+	    csol[j] = cup[j] ;
+	    colstat[j] = CoinPrePostsolveMatrix::atUpperBound ;
+	  }
+	}
+      }    // end cbar<j> < 0
+    }
+/*
+  That's the end of this walk through the columns.
+*/
+    // I don't know why I stopped doing this.
+#   if PRESOLVE_TIGHTEN_DUALS > 0
+    const double *rowels	= prob->rowels_ ;
+    const int *hcol	= prob->hcol_ ;
+    const CoinBigIndex *mrstrt	= prob->mrstrt_ ;
+    int *hinrow	= prob->hinrow_ ;
+    // tighten row dual bounds, as described on p. 229
+    for (int i = 0; i < nrows; i++) {
+      const bool no_ub = (rup[i] >= ekkinf) ;
+      const bool no_lb = (rlo[i] <= -ekkinf) ;
+
+      if ((no_ub ^ no_lb) == true) {
+	const CoinBigIndex krs = mrstrt[i] ;
+	const CoinBigIndex kre = krs + hinrow[i] ;
+	const double rmax  = ymax[i] ;
+	const double rmin  = ymin[i] ;
+
+	// all row columns are non-empty
+	for (CoinBigIndex k = krs ; k < kre ; k++) {
+	  const double coeff = rowels[k] ;
+	  const int icol = hcol[k] ;
+	  const double cbarmax0 = cbarmax[icol] ;
+	  const double cbarmin0 = cbarmin[icol] ;
+
+	  if (no_ub) {
+	    // cbarj must not be negative
+	    if (coeff > ZTOLDP2 &&
+	    	cbarjmax0 < PRESOLVE_INF && cup[icol] >= ekkinf) {
+	      const double bnd = cbarjmax0 / coeff ;
+	      if (rmax > bnd) {
+#		if PRESOLVE_DEBUG > 1
+		printf("MAX TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymax[i],bnd) ;
+#		endif
+		ymax[i] = rmax = bnd ;
+		tightened ++; ;
+	      }
+	    } else if (coeff < -ZTOLDP2 &&
+	    	       cbarjmax0 <PRESOLVE_INF && cup[icol] >= ekkinf) {
+	      const double bnd = cbarjmax0 / coeff ;
+	      if (rmin < bnd) {
+#		if PRESOLVE_DEBUG > 1
+		printf("MIN TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymin[i],bnd) ;
+#		endif
+		ymin[i] = rmin = bnd ;
+		tightened ++; ;
+	      }
+	    }
+	  } else {	// no_lb
+	    // cbarj must not be positive
+	    if (coeff > ZTOLDP2 &&
+	    	cbarmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) {
+	      const double bnd = cbarmin0 / coeff ;
+	      if (rmin < bnd) {
+#		if PRESOLVE_DEBUG > 1
+		printf("MIN1 TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymin[i],bnd) ;
+#		endif
+		ymin[i] = rmin = bnd ;
+		tightened ++; ;
+	      }
+	    } else if (coeff < -ZTOLDP2 &&
+	    	       cbarmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) {
+	      const double bnd = cbarmin0 / coeff ;
+	      if (rmax > bnd) {
+#		if PRESOLVE_DEBUG > 1
+		printf("MAX TIGHT1[%d,%d]: %g --> %g\n",i,hrow[k],ymax[i],bnd) ;
+#		endif
+		ymax[i] = rmax = bnd ;
+		tightened ++; ;
+	      }
+	    }
+	  }
+	}
+      }
+    }
+#   endif    // PRESOLVE_TIGHTEN_DUALS
+/*
+  Is it productive to continue with another pass? Essentially, we need lots of
+  tightening but no fixing. If we fixed any variables, break and process them.
+*/
+#   if PRESOLVE_DEBUG > 1
+    std::cout
+      << "NDUAL: pass " << nPass << ": fixed " << (ncols-nfixdown_cols)
+      << " down, " << nfixup_cols << " up, tightened " << tightened
+      << " duals." << std::endl ;
+#   endif
+    if (tightened < 100 || nfixdown_cols < ncols || nfixup_cols)
+      break ;
+  }
+  assert (nfixup_cols <= nfixdown_cols) ;
+/*
+  Process columns fixed at upper bound.
+*/
+  if (nfixup_cols) {
+#   if PRESOLVE_DEBUG > 1
+    std::cout << "NDUAL(upper):" ;
+    for (int k = 0 ; k < nfixup_cols ; k++)
+      std::cout << " " << fix_cols[k] ;
+    std::cout << "." << std::endl ;
+#   endif
+    next = make_fixed_action::presolve(prob,fix_cols,nfixup_cols,false,next) ;
+  }
+/*
+  Process columns fixed at lower bound.
+*/
+  if (nfixdown_cols < ncols) {
+    int *fixdown_cols = fix_cols+nfixdown_cols ; 
+    nfixdown_cols = ncols-nfixdown_cols ;
+#   if PRESOLVE_DEBUG > 1
+    std::cout << "NDUAL(lower):" ;
+    for (int k = 0 ; k < nfixdown_cols ; k++)
+      std::cout << " " << fixdown_cols[k] ;
+    std::cout << "." << std::endl ;
+#   endif
+    next = make_fixed_action::presolve(prob,fixdown_cols,
+    				       nfixdown_cols,true,next) ;
+  }
+/*
+  Now look for variables that, when moved in the favourable direction
+  according to reduced cost, will naturally tighten an inequality to an
+  equality. We can convert that inequality to an equality. See the comments
+  at the head of the routine.
+
+  Start with logicals. Open a loop and look for suitable rows. At the
+  end of this loop, rows marked with +/-1 will be forced to equality by
+  their logical. Rows marked with +/-2 are inequalities that (perhaps)
+  can be forced to equality using architecturals. Rows marked with 0 are
+  not suitable (range or nonbinding).
+
+  Note that usefulRowInt_ is 3*nrows_; we'll use the second partition below.
+*/
+  int *canFix = prob->usefulRowInt_ ;
+  for (int i = 0 ; i < nrows ; i++) {
+    const bool no_rlb = (rlo[i] <= -ekkinf) ;
+    const bool no_rub = (rup[i] >= ekkinf) ;
+    canFix[i] = 0 ;
+    if (no_rub && !no_rlb ) {
+      if (ymin[i] > 0.0) 
+	canFix[i] = -1 ;
+      else
+	canFix[i] = -2 ;
+    } else if (no_rlb && !no_rub ) {
+      if (ymax[i] < 0.0)
+	canFix[i] = 1 ;
+      else
+	canFix[i] = 2 ;
+    }
+#   if PRESOLVE_DEBUG > 1
+    if (abs(canFix[i]) == 1) {
+      std::cout
+        << "NDUAL(eq): candidate row (" << i << ") (" << rlo[i]
+	<< "," << rup[i] << "), logical must be "
+	<< ((canFix[i] == -1)?"NBUB":"NBLB") << "." << std::endl ;
+    }
+#   endif
+  }
+/*
+  Can we do a similar trick with architectural variables? Here, we're looking
+  for x<j> such that
+  (1) Exactly one of l<j> or u<j> is infinite.
+  (2) Moving x<j> towards the infinite bound can tighten exactly one
+      constraint i to equality.  If x<j> is entangled with other constraints,
+      moving x<j> towards the infinite bound will loosen those constraints.
+  (3) Moving x<j> towards the infinite bound is a good idea according to the
+      cost c<j> (note we don't have to consider reduced cost here).
+  If we can find a suitable x<j>, constraint i can become an equality.
+
+  This is yet another instance of bound propagation, but we're looking for
+  a very specific pattern: A variable that can be increased arbitrarily
+  in all rows it's entangled with, except for one, which bounds it. And
+  we're going to push the variable so as to make that row an equality.
+  But note what we're *not* doing: No actual comparison of finite bound
+  values to the amount necessary to force an equality. So no worries about
+  accuracy, the bane of bound propagation.
+
+  Open a loop to scan columns. bindingUp and bindingDown indicate the result
+  of the analysis; -1 says `possible', -2 is ruled out. Test first for
+  condition (1). Column singletons are presumably handled elsewhere. Integer
+  variables need not apply. If both bounds are finite, no need to look
+  further.
+*/
+  for (int j = 0 ; j < ncols ; j++) {
+    if (hincol[j] <= 1) continue ;
+    if (integerType[j]) continue ;
+    int bindingUp = -1 ;
+    int bindingDown = -1 ;
+    if (cup[j] < ekkinf)
+      bindingUp = -2 ;
+    if (clo[j] > -ekkinf)
+      bindingDown = -2 ;
+    if (bindingUp == -2 && bindingDown == -2) continue ;
+/*
+  Open a loop to walk the column and check for condition (2).
+
+  The test for |canFix[i]| != 2 is a non-interference check. We don't want to
+  mess with constraints where we've already decided to use the logical to
+  force equality. Nor do we want to deal with range or nonbinding constraints.
+*/
+    const CoinBigIndex &kcs = mcstrt[j] ;
+    const CoinBigIndex kce = kcs+hincol[j] ;
+    for (CoinBigIndex k = kcs; k < kce; k++) {
+      const int &i = hrow[k] ;
+      if (abs(canFix[i]) != 2) {
+	bindingUp = -2 ;
+	bindingDown = -2 ;
+	break ;
+      }
+      double aij = colels[k] ;
+/*
+  For a<ij> > 0 in a <= constraint (canFix = 2), the up direction is
+  binding. For a >= constraint, it'll be the down direction. If the relevant
+  binding code is still -1, set it to the index of the row. Similarly for
+  a<ij> < 0.
+
+  If this is the second or subsequent binding constraint in that direction,
+  set binding[Up,Down] to -2 (we don't want to get into the business of
+  calculating which constraint is actually binding).
+*/
+      if (aij > 0.0) {
+	if (canFix[i] == 2) {
+	  if (bindingUp == -1)
+	    bindingUp = i ;
+	  else
+	    bindingUp = -2 ;
+	} else {
+	  if (bindingDown == -1)
+	    bindingDown = i ;
+	  else
+	    bindingDown = -2 ;
+	}
+      } else {
+	if (canFix[i] == 2) {
+	  if (bindingDown == -1)
+	    bindingDown = i ;
+	  else
+	    bindingDown = -2 ;
+	} else {
+	  if (bindingUp == -1)
+	    bindingUp = i ;
+	  else
+	    bindingUp = -2 ;
+	}
+      }
+    }
+    if (bindingUp == -2 && bindingDown == -2) continue ;
+/*
+  If bindingUp > -2, then either no constraint provided a bound (-1) or
+  there's a single constraint (0 <= i < m) that bounds x<j>.  If we have
+  just one binding constraint, check that the reduced cost is favourable
+  (c<j> <= 0 for x<j> NBUB at optimum for minimisation). If so, declare
+  that we will force the row to equality (canFix[i] = +/-1). Note that we
+  don't adjust the primal solution value for x<j>.
+
+  If no constraint provided a bound, we might be headed for unboundedness,
+  but leave that for some other code to determine.
+*/
+    double cj = cost[j] ;
+    if (bindingUp > -2 && cj <= 0.0) {
+      if (bindingUp >= 0) {
+	canFix[bindingUp] /= 2 ;
+#       if PRESOLVE_DEBUG > 1
+	std::cout
+	  << "NDUAL(eq): candidate row (" << bindingUp << ") ("
+	  << rlo[bindingUp] << "," << rup[bindingUp] << "), "
+	  << " increasing x(" << j << "), cbar = " << cj << "."
+	  << std::endl ;
+      } else {
+          std::cout
+	    << "NDUAL(eq): no binding upper bound for x(" << j
+	    << "), cbar = " << cj << "." << std::endl ;
+#        endif
+      }
+    } else if (bindingDown > -2 && cj >= 0.0) {
+      if (bindingDown >= 0) {
+	canFix[bindingDown] /= 2 ;
+#       if PRESOLVE_DEBUG > 1
+	std::cout
+	  << "NDUAL(eq): candidate row (" << bindingDown << ") ("
+	  << rlo[bindingDown] << "," << rup[bindingDown] << "), "
+	  << " decreasing x(" << j << "), cbar = " << cj << "."
+	  << std::endl ;
+      } else {
+          std::cout
+	    << "NDUAL(eq): no binding lower bound for x(" << j
+	    << "), cbar = " << cj << "." << std::endl ;
+#        endif
+      }
+    }
+  }
+/*
+  We have candidate rows. We've avoided scanning full rows until now,
+  but there's one remaining hazard: if the row contains unfixed integer
+  variables then we don't want to just pin the row to a fixed rhs; that
+  might prevent us from achieving integrality. Scan canFix, count and
+  record suitable rows (use the second partition of usefulRowInt_).
+*/
+# if PRESOLVE_DEBUG > 0
+  int makeEqCandCnt = 0 ;
+  for (int i = 0 ; i < nrows ; i++) {
+    if (abs(canFix[i]) == 1) makeEqCandCnt++ ;
+  }
+# endif
+  int makeEqCnt = nrows ;
+  for (int i = 0 ; i < nrows ; i++) {
+    if (abs(canFix[i]) == 1) {
+      const CoinBigIndex &krs = mrstrt[i] ;
+      const CoinBigIndex kre = krs+hinrow[i] ;
+      for (CoinBigIndex k = krs ; k < kre ; k++) {
+	const int j = hcol[k] ;
+	if (cup[j] > clo[j] && (integerType[j]||prob->colProhibited2(j))) {
+	  canFix[i] = 0 ;
+#	  if PRESOLVE_DEBUG > 1
+	  std::cout
+	    << "NDUAL(eq): cannot convert row " << i << " to equality; "
+	    << "unfixed integer variable x(" << j << ")." << std::endl ;
+#         endif
+          break ;
+	}
+      }
+      if (canFix[i] != 0) canFix[makeEqCnt++] = i ;
+    }
+  }
+  makeEqCnt -= nrows ;
+# if PRESOLVE_DEBUG > 0
+  if ((makeEqCandCnt-makeEqCnt) > 0) {
+    std::cout
+      << "NDUAL(eq): rejected " << (makeEqCandCnt-makeEqCnt)
+      << " rows due to unfixed integer variables." << std::endl ;
+  }
+# endif
+/*
+  If we've identified inequalities to convert, do the conversion, record
+  the information needed to restore bounds in postsolve, and finally create
+  the postsolve object.
+*/
+  if (makeEqCnt > 0) {
+    action *bndRecords = new action[makeEqCnt] ;
+    for (int k = 0 ; k < makeEqCnt ; k++) {
+      const int &i = canFix[k+nrows] ;
+#     if PRESOLVE_DEBUG > 1
+      std::cout << "NDUAL(eq): forcing row " << i << " to equality;" ;
+      if (canFix[i] == -1)
+	std::cout << " dropping b = " << rup[i] << " to " << rlo[i] ;
+      else
+	std::cout << " raising blow = " << rlo[i] << " to " << rup[i] ;
+      std::cout << "." << std::endl ;
+#     endif
+      action &bndRec = bndRecords[(k)] ;
+      bndRec.rlo_ = rlo[i] ;
+      bndRec.rup_ = rup[i] ;
+      bndRec.ndx_ = i ;
+      if (canFix[i] == 1) {
+	rlo[i] = rup[i] ;
+	prob->addRow(i) ;
+      } else if (canFix[i] == -1) {
+	rup[i] = rlo[i] ;
+	prob->addRow(i) ;
+      }
+    }
+    next = new remove_dual_action(makeEqCnt,bndRecords,next) ;
+  }
+
+# if PRESOLVE_TIGHTEN_DUALS > 0
+  delete[] cbarmin ;
+  delete[] cbarmax ;
+# endif
+
+# if COIN_PRESOLVE_TUNING > 0
+  double thisTime = 0.0 ;
+  if (prob->tuning_) thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_sol(prob,2,1,1) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving remove_dual_action::presolve, dropped " << droppedRows
+    << " rows, " << droppedColumns << " columns, forced "
+    << makeEqCnt << " equalities" ;
+# if COIN_PRESOLVE_TUNING > 0
+  if (prob->tuning_)
+    std::cout << " in " << (thisTime-prob->startTime_) << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+/*
+  Postsolve: replace the original row bounds.
+
+  The catch here is that each constraint was an equality in the presolved
+  problem, with a logical s<i> that had l<i> = u<i> = 0. We're about to
+  convert the equality back to an inequality. One row bound will go to
+  infinity, as will one of the bounds of the logical. We may need to patch the
+  basis. The logical for a <= constraint cannot be NBUB, and the logical for a
+  >= constraint cannot be NBLB.
+*/
+void remove_dual_action::postsolve (CoinPostsolveMatrix *prob) const
+{
+  const action *const &bndRecords = actions_ ;
+  const int &numRecs = nactions_ ;
+
+  double *&rlo = prob->rlo_ ;
+  double *&rup = prob->rup_ ;
+  unsigned char *&rowstat = prob->rowstat_ ;
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering remove_dual_action::postsolve, " << numRecs
+    << " bounds to restore." << std::endl ;
+# endif
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+/*
+  For each record, restore the row bounds. If we have status arrays, check
+  the status of the logical and adjust if necessary.
+
+  In spite of the fact that the status array is an unsigned char array,
+  we still need to use getRowStatus to make sure we're only looking at the
+  bottom three bits. Why is this an issue? Because the status array isn't
+  necessarily cleared to zeros, and setRowStatus carefully changes only
+  the bottom three bits!
+*/
+  for (int k = 0 ; k < numRecs ; k++) {
+    const action &bndRec = bndRecords[k] ;
+    const int &i = bndRec.ndx_ ;
+    const double &rloi = bndRec.rlo_ ;
+    const double &rupi = bndRec.rup_ ;
+
+#   if PRESOLVE_DEBUG > 1
+    std::cout << "NDUAL(eq): row(" << i << ")" ;
+    if (rlo[i] != rloi) std::cout << " LB " << rlo[i] << " -> " << rloi ;
+    if (rup[i] != rupi) std::cout << " UB " << rup[i] << " -> " << rupi ;
+#   endif
+
+    rlo[i] = rloi ;
+    rup[i] = rupi ;
+    if (rowstat) {
+      unsigned char stati = prob->getRowStatus(i) ;
+      if (stati == CoinPresolveMatrix::atUpperBound) {
+        if (rloi <= -PRESOLVE_INF) {
+	  rowstat[i] = CoinPresolveMatrix::atLowerBound ;
+#         if PRESOLVE_DEBUG > 1
+	  std::cout
+	    << ", status forced to "
+	    << statusName(static_cast<CoinPresolveMatrix::Status>(rowstat[i])) ;
+#         endif
+	}
+      } else if (stati == CoinPresolveMatrix::atLowerBound) {
+        if (rupi >= PRESOLVE_INF) {
+	  rowstat[i] = CoinPresolveMatrix::atUpperBound ;
+#         if PRESOLVE_DEBUG > 1
+	  std::cout
+	    << ", status forced to "
+	    << statusName(static_cast<CoinPresolveMatrix::Status>(rowstat[i])) ;
+#         endif
+	}
+      }
+#     if PRESOLVE_DEBUG > 2
+        else if (stati == CoinPresolveMatrix::basic) {
+        std::cout << ", status is basic." ;
+      } else if (stati == CoinPresolveMatrix::isFree) {
+        std::cout << ", status is free?!" ;
+      } else {
+        unsigned int tmp = static_cast<unsigned int>(stati) ;
+        std::cout << ", status is invalid (" << tmp << ")!" ;
+      }
+#     endif
+    }
+#   if PRESOLVE_DEBUG > 1
+    std::cout << "." << std::endl ;
+#   endif
+  }
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving remove_dual_action::postsolve." << std::endl ;
+# endif
+# endif
+
+  return ;
+}
+
+/*
+  Destructor
+*/
+remove_dual_action::~remove_dual_action ()
+{
+  deleteAction(actions_,action*) ;
+}
diff --git a/cbits/coin/CoinPresolveDual.hpp b/cbits/coin/CoinPresolveDual.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveDual.hpp
@@ -0,0 +1,85 @@
+/* $Id: CoinPresolveDual.hpp 1510 2011-12-08 23:56:01Z lou $ */
+
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveDual_H
+#define CoinPresolveDual_H
+
+/*! \class remove_dual_action
+    \brief Attempt to fix variables by bounding reduced costs
+
+  The reduced cost of x_j is d_j = c_j - y*a_j (1). Assume minimization,
+  so that at optimality d_j >= 0 for x_j nonbasic at lower bound, and
+  d_j <= 0 for x_j nonbasic at upper bound.
+ 
+  For a slack variable s_i, c_(n+i) = 0 and a_(n+i) is a unit vector, hence
+  d_(n+i) = -y_i. If s_i has a finite lower bound and no upper bound, we
+  must have y_i <= 0 at optimality. Similarly, if s_i has no lower bound and a
+  finite upper bound, we must have y_i >= 0.
+
+  For a singleton variable x_j, d_j = c_j - y_i*a_ij. Given x_j with a
+  single finite bound, we can bound d_j greater or less than 0 at
+  optimality, and that allows us to calculate an upper or lower bound on y_i
+  (depending on the bound on d_j and the sign of a_ij).
+
+  Now we have bounds on some subset of the y_i, and we can use these to
+  calculate upper and lower bounds on the d_j, using bound propagation on
+  (1). If we can manage to bound some d_j as strictly positive or strictly
+  negative, then at optimality the corresponding variable must be nonbasic
+  at its lower or upper bound, respectively. If the required bound is lacking,
+  the problem is unbounded.
+*/
+
+class remove_dual_action : public CoinPresolveAction {
+
+  public:
+
+  /// Destructor
+  ~remove_dual_action () ;
+
+  /// Name
+  inline const char *name () const { return ("remove_dual_action") ; }
+
+  /*! \brief Attempt to fix variables by bounding reduced costs
+
+    Always scans all variables. Propagates bounds on reduced costs until there's
+    no change or until some set of variables can be fixed.
+  */
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					    const CoinPresolveAction *next) ;
+
+  /*! \brief Postsolve
+
+    In addition to fixing variables (handled by make_fixed_action), we may
+    need use our own postsolve to restore constraint bounds.
+  */
+  void postsolve (CoinPostsolveMatrix *prob) const ;
+
+  private:
+
+  /// Postsolve (bound restore) instruction
+  struct action {
+    double rlo_ ;  ///< restored row lower bound
+    double rup_ ;  ///< restored row upper bound
+    int ndx_ ;     ///< row index
+  } ;
+
+  /// Constructor with postsolve actions.
+  remove_dual_action(int nactions, const action *actions,
+		     const CoinPresolveAction *next)
+    : CoinPresolveAction(next),
+      nactions_(nactions),
+      actions_(actions)
+  {}
+
+  /// Count of bound restore entries
+  const int nactions_ ;
+  /// Bound restore entries
+  const action *actions_ ;
+
+} ;
+#endif
+
+
diff --git a/cbits/coin/CoinPresolveDupcol.cpp b/cbits/coin/CoinPresolveDupcol.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveDupcol.cpp
@@ -0,0 +1,1836 @@
+/* $Id: CoinPresolveDupcol.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+//#define PRESOLVE_DEBUG 1
+// Debugging macros/functions
+//#define PRESOLVE_DETAIL 1
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveDupcol.hpp"
+#include "CoinSort.hpp"
+#include "CoinFinite.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveUseless.hpp"
+#include "CoinMessage.hpp"
+#if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+#define DSEED2 2147483647.0
+// Can be used from anywhere
+void coin_init_random_vec(double *work, int n)
+{
+  double deseed = 12345678.0;
+
+  for (int i = 0; i < n; ++i) {
+    deseed *= 16807.;
+    int jseed = static_cast<int> (deseed /    DSEED2);
+    deseed -= static_cast<double> (jseed) * DSEED2;
+    double random = deseed /  DSEED2;
+
+    work[i]=random;
+  }
+}
+
+namespace {	// begin unnamed file-local namespace
+
+/*
+  For each candidate major-dimension vector in majcands, calculate the sum
+  over the vector, with each minor dimension weighted by a random amount.
+  (E.g., calculate column sums with each row weighted by a random amount.)
+  The sums are returned in the corresponding entries of majsums.
+*/
+
+  void compute_sums (int /*n*/, const int *majlens, const CoinBigIndex *majstrts,
+		   int *minndxs, double *elems, const double *minmuls,
+		   int *majcands, double *majsums, int nlook)
+
+{ for (int cndx = 0 ; cndx < nlook ; ++cndx)
+  { int i = majcands[cndx] ;
+    PRESOLVEASSERT(majlens[i] > 0) ;
+
+    CoinBigIndex kcs = majstrts[i] ;
+    CoinBigIndex kce = kcs + majlens[i] ;
+
+    double value = 0.0 ;
+
+    for (CoinBigIndex k = kcs ; k < kce ; k++)
+    { int irow = minndxs[k] ;
+      value += minmuls[irow]*elems[k] ; }
+
+    majsums[cndx] = value ; }
+
+  return ; }
+
+
+void create_col (int col, int n, double *els,
+		 CoinBigIndex *mcstrt, double *colels, int *hrow, int *link,
+		 CoinBigIndex *free_listp)
+{
+  int *rows = reinterpret_cast<int *>(els+n) ;
+  CoinBigIndex free_list = *free_listp;
+  int xstart = NO_LINK;
+  for (int i=0; i<n; ++i) {
+    CoinBigIndex k = free_list;
+    assert(k >= 0) ;
+    free_list = link[free_list];
+    hrow[k]   = rows[i];
+    colels[k] = els[i];
+    link[k] = xstart;
+    xstart = k;
+  }
+  mcstrt[col] = xstart;
+  *free_listp = free_list;
+}
+
+
+} // end unnamed file-local namespace
+
+
+
+const char *dupcol_action::name () const
+{
+  return ("dupcol_action");
+}
+
+
+/*
+  Original comment: This is just ekkredc5, adapted into the new framework.
+	The datasets scorpion.mps and allgrade.mps have duplicate columns.
+
+  In case you don't have your OSL manual handy, a somewhat more informative
+  explanation: We're looking for an easy-to-detect special case of linearly
+  dependent columns, where the coefficients of the duplicate columns are
+  exactly equal. The idea for locating such columns is to generate pseudo-
+  random weights for each row and then calculate the weighted sum of
+  coefficients of each column. Columns with equal sums are checked more
+  thoroughly.
+
+  Analysis of the situation says there are two major cases:
+    * If the columns have equal objective coefficients, we can combine
+      them.
+    * If the columns have unequal objective coefficients, we may be able to
+      fix one at bound. If the required bound doesn't exist, we have dual
+      infeasibility (hence one of primal infeasibility or unboundedness).
+
+  In the comments below are a few fragments of code from the original
+  routine. I don't think they make sense, but I've left them for the nonce in
+  case someone else recognises the purpose.   -- lh, 040909 --
+*/
+
+const CoinPresolveAction
+    *dupcol_action::presolve (CoinPresolveMatrix *prob,
+			      const CoinPresolveAction *next)
+{
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering dupcol_action::presolve." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int startEmptyRows = 0 ;
+  int startEmptyColumns = 0 ;
+  startEmptyRows = prob->countEmptyRows() ;
+  startEmptyColumns = prob->countEmptyCols() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0;
+  if (prob->tuning_) startTime = CoinCpuTime() ;
+# endif
+# endif
+
+  double maxmin	= prob->maxmin_ ;
+
+  double *colels	= prob->colels_ ;
+  int *hrow		= prob->hrow_ ;
+  CoinBigIndex *mcstrt	= prob->mcstrt_ ;
+  int *hincol		= prob->hincol_ ;
+  int ncols		= prob->ncols_ ;
+  int nrows		= prob->nrows_ ;
+
+  double *clo	= prob->clo_ ;
+  double *cup	= prob->cup_ ;
+  double *sol	= prob->sol_ ;
+  double *rlo	= prob->rlo_ ;
+  double *rup	= prob->rup_ ;
+
+  // If all coefficients positive do more simply
+  bool allPositive=true;
+  double * rhs = prob->usefulRowDouble_; //new double[nrows];
+  CoinMemcpyN(rup,nrows,rhs);  
+/*
+  Scan the columns for candidates, and write the indices into sort. We're not
+  interested in columns that are empty, prohibited, or integral.
+
+  Question: Should we exclude singletons, which are useful in other transforms?
+  Question: Why are we excluding integral columns?
+*/
+  // allow integral columns if asked for
+  bool allowIntegers = ((prob->presolveOptions_&0x01) != 0) ;
+  int *sort = prob->usefulColumnInt_; //new int[ncols] ;
+  int nlook = 0 ;
+  for (int j = 0 ; j < ncols ; j++) {
+    if (hincol[j] == 0) continue ;
+    // sort
+    CoinSort_2(hrow+mcstrt[j],hrow+mcstrt[j]+hincol[j],
+	       colels+mcstrt[j]);
+    // check all positive and adjust rhs
+    if (allPositive) {
+      double lower = clo[j];
+      if (lower<cup[j]) {
+        for (int k=mcstrt[j];k<mcstrt[j]+hincol[j];k++) {
+          double value=colels[k];
+          if (value<0.0)
+            allPositive=false;
+          else
+            rhs[hrow[k]] -= lower*value;
+        }
+      } else {
+        for (int k=mcstrt[j];k<mcstrt[j]+hincol[j];k++) {
+          double value=colels[k];
+          rhs[hrow[k]] -= lower*value;
+        }
+      }
+    }
+    if (prob->colProhibited2(j)) continue ;
+    //#define PRESOLVE_INTEGER_DUPCOL
+#ifndef PRESOLVE_INTEGER_DUPCOL
+    if (prob->isInteger(j)&&!allowIntegers) continue ;
+#endif
+    sort[nlook++] = j ; }
+  if (nlook == 0)
+    { //delete[] sort ;
+      //delete [] rhs;
+    return (next) ; }
+/*
+  Prep: add the coefficients of each candidate column. To reduce false
+  positives, multiply each row by a `random' multiplier when forming the
+  sums.  On return from compute_sums, sort and colsum are loaded with the
+  indices and column sums, respectively, of candidate columns.  The pair of
+  arrays are then sorted by sum so that equal sums are adjacent.
+*/
+  double *colsum = prob->usefulColumnDouble_; //new double[ncols] ;
+  double *rowmul;
+  if (!prob->randomNumber_) {
+    rowmul = new double[nrows] ;
+    coin_init_random_vec(rowmul,nrows) ;
+  } else {
+    rowmul = prob->randomNumber_;
+  }
+  compute_sums(ncols,hincol,mcstrt,hrow,colels,rowmul,sort,colsum,nlook) ;
+  CoinSort_2(colsum,colsum+nlook,sort) ;
+/*
+  General prep --- unpack the various vectors we'll need, and allocate arrays
+  to record the results.
+*/
+  presolvehlink *clink	= prob->clink_ ;
+
+  double *rowels	= prob->rowels_ ;
+  int *hcol		= prob->hcol_ ;
+  const CoinBigIndex *mrstrt = prob->mrstrt_ ;
+  int *hinrow		= prob->hinrow_ ;
+
+  double *dcost	= prob->cost_ ;
+
+  action *actions	= new action [nlook] ;
+  int nactions = 0 ;
+# ifdef ZEROFAULT
+  memset(actions,0,nlook*sizeof(action)) ;
+# endif
+
+  int *fixed_down	= new int[nlook] ;
+  int nfixed_down	= 0 ;
+  int *fixed_up		= new int[nlook] ;
+  int nfixed_up		= 0 ;
+
+#if 0
+  // Excluded in the original routine. I'm guessing it's excluded because
+  // it's just not cost effective to worry about this. -- lh, 040908 --
+
+  // It may be the case that several columns are duplicate.
+  // If not all have the same cost, then we have to make sure
+  // that we set the most expensive one to its minimum
+  // now sort in each class by cost
+  {
+    double dval = colsum[0] ;
+    int first = 0 ;
+    for (int jj = 1; jj < nlook; jj++) {
+      while (colsum[jj]==dval) 
+	jj++ ;
+
+      if (first + 1 < jj) {
+	double buf[jj - first] ;
+	for (int i=first; i<jj; ++i)
+	  buf[i-first] = dcost[sort[i]]*maxmin ;
+
+	CoinSort_2(buf,buf+jj-first,sort+first) ;
+	//ekk_sortonDouble(buf,&sort[first],jj-first) ;
+      }
+    }
+  }
+#endif
+  // We will get all min/max but only if needed
+  bool gotStuff=false;
+/*
+  Original comment: It appears to be the case that this loop is finished,
+	there may still be duplicate cols left. I haven't done anything
+	about that yet.
+
+  Open the main loop to compare column pairs. We'll compare sort[jj] to
+  sort[tgt]. This allows us to accumulate multiple columns into one. But
+  we don't manage all-pairs comparison when we can't combine columns.
+
+  We can quickly dismiss pairs which have unequal sums or lengths.
+*/
+  int isorted = -1 ;
+  int tgt = 0 ;
+  for (int jj = 1 ;  jj < nlook ; jj++)
+    { if (colsum[jj] != colsum[jj-1]) {
+      tgt = jj; // Must update before continuing
+      continue ;
+    }
+
+    int j2 = sort[jj] ;
+    int j1 = sort[tgt] ;
+    int len2 = hincol[j2] ;
+    int len1 =  hincol[j1] ;
+
+    if (len2 != len1)
+    { tgt = jj ;
+      continue ; }
+/*
+  The final test: sort the columns by row index and compare each index and
+  coefficient.
+*/
+    CoinBigIndex kcs = mcstrt[j2] ;
+    CoinBigIndex kce = kcs+hincol[j2] ;
+    int ishift = mcstrt[j1]-kcs ;
+
+    if (len1 > 1 && isorted < j1)
+    { CoinSort_2(hrow+mcstrt[j1],hrow+mcstrt[j1]+len1,
+		 colels+mcstrt[j1]) ;
+      isorted = j1 ; }
+    if (len2 > 1 && isorted < j2)
+    { CoinSort_2(hrow+kcs,hrow+kcs+len2,colels+kcs) ;
+      isorted = j2 ; }
+
+    CoinBigIndex k ;
+    for (k = kcs ; k < kce ; k++)
+    { if (hrow[k] != hrow[k+ishift] || colels[k] != colels[k+ishift])
+      { break ; } }
+    if (k != kce)
+    { tgt = jj ;
+      continue ; }
+/*
+  These really are duplicate columns. Grab values for convenient reference.
+  Convert the objective coefficients for minimization.
+*/
+    double clo1 = clo[j1] ;
+    double cup1 = cup[j1] ;
+    double clo2 = clo[j2] ;
+    double cup2 = cup[j2] ;
+    double c1 = dcost[j1]*maxmin ;
+    double c2 = dcost[j2]*maxmin ;
+    PRESOLVEASSERT(!(clo1 == cup1 || clo2 == cup2)) ;
+    // Get reasonable bounds on sum of two variables
+    double lowerBound=-COIN_DBL_MAX;
+    double upperBound=COIN_DBL_MAX;
+    // For now only if lower bounds are zero
+    if (!clo1&&!clo2) {
+      // Only need bounds if c1 != c2
+      if (c1!=c2) {
+	if (!allPositive) {
+#if 0
+
+	  for (k=kcs;k<kce;k++) {
+	    int iRow = hrow[k];
+	    bool posinf = false;
+	    bool neginf = false;
+	    double maxup = 0.0;
+	    double maxdown = 0.0;
+	    
+	    // compute sum of all bounds except for j1,j2
+	    CoinBigIndex kk;
+	    CoinBigIndex kre = mrstrt[iRow]+hinrow[iRow];
+	    double value1=0.0;
+	    for (kk=mrstrt[iRow]; kk<kre; kk++) {
+	      int col = hcol[kk];
+	      if (col == j1||col==j2) {
+		value1=rowels[kk];
+		continue;
+	      }
+	      double coeff = rowels[kk];
+	      double lb = clo[col];
+	      double ub = cup[col];
+	      
+	      if (coeff > 0.0) {
+		if (PRESOLVE_INF <= ub) {
+		  posinf = true;
+		  if (neginf)
+		    break;	// pointless
+		} else {
+		  maxup += ub * coeff;
+		}
+		if (lb <= -PRESOLVE_INF) {
+		  neginf = true;
+		  if (posinf)
+		    break;	// pointless
+		} else {
+		  maxdown += lb * coeff;
+		}
+	      } else {
+		if (PRESOLVE_INF <= ub) {
+		  neginf = true;
+		  if (posinf)
+		    break;	// pointless
+		} else {
+		  maxdown += ub * coeff;
+		}
+		if (lb <= -PRESOLVE_INF) {
+		  posinf = true;
+		  if (neginf)
+		    break;	// pointless
+		} else {
+		  maxup += lb * coeff;
+		}
+	      }
+	    }
+	    
+	    if (kk==kre) {
+	      assert (value1);
+	      if (value1>1.0e-5) {
+		if (!neginf&&rup[iRow]<1.0e10)
+		  if (upperBound*value1>rup[iRow]-maxdown)
+		    upperBound = (rup[iRow]-maxdown)/value1;
+		if (!posinf&&rlo[iRow]>-1.0e10)
+		  if (lowerBound*value1<rlo[iRow]-maxup)
+		    lowerBound = (rlo[iRow]-maxup)/value1;
+	      } else if (value1<-1.0e-5) {
+		if (!neginf&&rup[iRow]<1.0e10)
+		  if (lowerBound*value1>rup[iRow]-maxdown) {
+#ifndef NDEBUG
+		    double x=lowerBound;
+#endif
+		    lowerBound = (rup[iRow]-maxdown)/value1;
+		    assert (lowerBound == CoinMax(x,(rup[iRow]-maxdown)/value1));
+		  }
+		if (!posinf&&rlo[iRow]>-1.0e10)
+		  if (upperBound*value1<rlo[iRow]-maxup) {
+#ifndef NDEBUG
+		    double x=upperBound;
+#endif
+		    upperBound = (rlo[iRow]-maxup)/value1;
+		    assert(upperBound == CoinMin(x,(rlo[iRow]-maxup)/value1));
+		  }
+	      }
+	    }
+	  }
+	  double l=lowerBound;
+	  double u=upperBound;
+#endif
+	  if (!gotStuff) {
+	    prob->recomputeSums(-1); // get min max
+	    gotStuff=true;
+	  }
+	  int positiveInf=0;
+	  int negativeInf=0;
+	  double lo=0;
+	  double up=0.0;
+	  if (clo1<-PRESOLVE_INF)
+	    negativeInf++;
+	  else
+	    lo+=clo1;
+	  if (clo2<-PRESOLVE_INF)
+	    negativeInf++;
+	  else
+	    lo+=clo2;
+	  if (cup1>PRESOLVE_INF)
+	    positiveInf++;
+	  else
+	    up+=cup1;
+	  if (cup2>PRESOLVE_INF)
+	    positiveInf++;
+	  else
+	    up+=cup2;
+	  for (k=kcs;k<kce;k++) {
+	    int iRow = hrow[k];
+	    double value = colels[k];
+	    int pInf = (value>0.0) ? positiveInf : negativeInf; 
+	    int nInf = (value>0.0) ? negativeInf : positiveInf; 
+	    int posinf = prob->infiniteUp_[iRow]-pInf;
+	    int neginf = prob->infiniteDown_[iRow]-nInf;
+	    if (posinf>0&&neginf>0)
+	      continue; // this row can't bound
+	    double maxup = prob->sumUp_[iRow];
+	    double maxdown = prob->sumDown_[iRow];
+	    
+	    if (value>0.0) {
+	      maxdown -= value*lo;
+	      maxup -= value*up;
+	    } else {
+	      maxdown -= value*up;
+	      maxup -= value*lo;
+	    }
+	    if (value>1.0e-5) {
+	      if (!neginf&&rup[iRow]<1.0e10)
+		if (upperBound*value>rup[iRow]-maxdown)
+		  upperBound = (rup[iRow]-maxdown)/value;
+	      if (!posinf&&rlo[iRow]>-1.0e10)
+		if (lowerBound*value<rlo[iRow]-maxup)
+		  lowerBound = (rlo[iRow]-maxup)/value;
+	    } else if (value<-1.0e-5) {
+	      if (!neginf&&rup[iRow]<1.0e10)
+		if (lowerBound*value>rup[iRow]-maxdown) {
+		  lowerBound = (rup[iRow]-maxdown)/value;
+		}
+	      if (!posinf&&rlo[iRow]>-1.0e10)
+		if (upperBound*value<rlo[iRow]-maxup) {
+		  upperBound = (rlo[iRow]-maxup)/value;
+		}
+	    }
+	  }
+	  //assert (fabs(l-lowerBound)<1.0e-5&&fabs(u-upperBound)<1.0e-5);
+	} else {
+	  // can do faster
+	  lowerBound=0.0;
+	  for (k=kcs;k<kce;k++) {
+	    int iRow = hrow[k];
+	    double value=colels[k];
+	    if (upperBound*value>rhs[iRow])
+		upperBound = rhs[iRow]/value;
+	  }
+	}
+      }
+      // relax a bit
+      upperBound -= 1.0e-9;
+    } else {
+      // Not sure what to do so give up
+      continue;
+    }
+/*
+  There are two main cases: The objective coefficients are equal or unequal.
+
+  For equal objective coefficients c1 == c2, we can combine the columns by
+  making the substitution x<j1> = x'<j1> - x<j2>. This will eliminate column
+  sort[jj] = j2 and leave the new variable x' in column sort[tgt] = j1. tgt
+  doesn't move.
+*/
+    if (c1 == c2)
+    { 
+#ifdef PRESOLVE_INTEGER_DUPCOL
+      if (!allowIntegers) {
+	if (prob->isInteger(j1)) {
+	  if (!prob->isInteger(j2)) {
+	    if (cup2 < upperBound) //if (!prob->colInfinite(j2))
+	      continue;
+	    else
+	      cup2 = COIN_DBL_MAX;
+	  }
+	} else if (prob->isInteger(j2)) {
+	  if (cup1 < upperBound) //if (!prob->colInfinite(j1))
+	    continue;
+	  else
+	    cup1 = COIN_DBL_MAX;
+	}
+	//printf("TakingINTeq\n");
+      }
+#endif
+/*
+  As far as the presolved lp, there's no difference between columns. But we
+  need this relation to hold in order to guarantee that we can split the
+  value of the combined column during postsolve without damaging the basis.
+  (The relevant case is when the combined column is basic --- we need to be
+  able to retain column j1 in the basis and make column j2 nonbasic.)
+*/
+      if (!(clo2+cup1 <= clo1+cup2))
+      { CoinSwap(j1,j2) ;
+	CoinSwap(clo1,clo2) ;
+	CoinSwap(cup1,cup2) ;
+	tgt = jj ; }
+/*
+  Create the postsolve action before we start to modify the columns.
+*/
+#     if PRESOLVE_DEBUG > 1
+      PRESOLVE_STMT(printf("DUPCOL: (%d,%d) %d += %d\n",j1,j2,j1,j2)) ;
+      PRESOLVE_DETAIL_PRINT(printf("pre_dupcol %dC %dC E\n",j2,j1));
+#     endif
+
+      action *s = &actions[nactions++] ;	  
+      s->thislo = clo[j2] ;
+      s->thisup = cup[j2] ;
+      s->lastlo = clo[j1] ;
+      s->lastup = cup[j1] ;
+      s->ithis  = j2 ;
+      s->ilast  = j1 ;
+      s->nincol = hincol[j2] ;
+      s->colels = presolve_dupmajor(colels,hrow,hincol[j2],mcstrt[j2]) ;
+/*
+  Combine the columns into column j1. Upper and lower bounds and solution
+  simply add, and the coefficients are unchanged.
+
+  I'm skeptical of pushing a bound to infinity like this, but leave it for now.
+  -- lh, 040908 --
+*/
+      clo1 += clo2 ;
+      if (clo1 < -1.0e20)
+      { clo1 = -PRESOLVE_INF ; }
+      clo[j1] = clo1 ;
+      cup1 += cup2 ;
+      if (cup1 > 1.0e20)
+      { cup1 = PRESOLVE_INF ; }
+      cup[j1] = cup1 ;
+      if (sol)
+      { sol[j1] += sol[j2] ; }
+      if (prob->colstat_)
+      { if (prob->getColumnStatus(j1) == CoinPrePostsolveMatrix::basic ||
+	    prob->getColumnStatus(j2) == CoinPrePostsolveMatrix::basic)
+	{ prob->setColumnStatus(j1,CoinPrePostsolveMatrix::basic); } }
+/*
+  Empty column j2.
+*/
+      dcost[j2] = 0.0 ;
+      if (sol)
+      { sol[j2] = clo2 ; }
+      CoinBigIndex k2cs = mcstrt[j2] ;
+      CoinBigIndex k2ce = k2cs + hincol[j2] ;
+      for (CoinBigIndex k = k2cs ; k < k2ce ; ++k)
+      { presolve_delete_from_row(hrow[k],j2,mrstrt,hinrow,hcol,rowels) ; }
+      hincol[j2] = 0 ;
+      PRESOLVE_REMOVE_LINK(clink,j2) ;
+      continue ; }
+/*
+  Unequal reduced costs. In this case, we may be able to fix one of the columns
+  or prove dual infeasibility. Given column a_k, duals y, objective
+  coefficient c_k, the reduced cost cbar_k = c_k - dot(y,a_k). Given
+  a_1 = a_2, substitute for dot(y,a_1) in the relation for cbar_2 to get
+    cbar_2 = (c_2 - c_1) + cbar_1
+  Independent elements here are variable bounds l_k, u_k, and difference
+  (c_2 - c_1). Infinite bounds for l_k, u_k will constrain the sign of cbar_k.
+  Assume minimization. If you do the case analysis, you find these cases of
+  interest:
+
+        l_1	u_1	l_2	u_2	cbar_1	c_2-c_1	cbar_2	result
+
+    A    any	finite	-inf	any	<= 0	  > 0	  <= 0	x_1 -> NBUB
+    B   -inf	 any	 any	finite	<= 0	  < 0	  < 0	x_2 -> NBUB
+
+    C   finite	 any	 any	+inf	>= 0	  < 0	  >= 0	x_1 -> NBLB
+    D    any	+inf	finite	 any	>= 0	  > 0	  >= 0	x_2 -> NBLB
+
+    E   -inf	any	 any	+inf	<= 0	  < 0	  >= 0	dual infeas
+    F    any	inf	-inf	 any	>= 0	  > 0	  <= 0  dual infeas
+
+    G    any	finite	finite	 any		  > 0		no inference
+    H   finite	 any	 any	finite		  < 0		no inference
+
+  The cases labelled dual infeasible are primal unbounded.
+
+  To keep the code compact, we'll always aim to take x_2 to bound. In the cases
+  where x_1 should go to bound, we'll swap. The implementation is boolean
+  algebra. Define bits for infinite bounds and (c_2 > c_1), then look for the
+  correct patterns.
+*/
+    else
+    { int minterm = 0 ;
+#ifdef PRESOLVE_INTEGER_DUPCOL
+      if (!allowIntegers) {
+	if (c2 > c1) {
+	  if (cup1 < upperBound/*!prob->colInfinite(j1)*/ && (prob->isInteger(j1)||prob->isInteger(j2)))
+	    continue ;
+	} else {
+	  if (cup2 < upperBound/*!prob->colInfinite(j2)*/ && (prob->isInteger(j1)||prob->isInteger(j2)))
+	    continue ;
+	}
+	//printf("TakingINTne\n");
+      }
+#endif
+      bool swapped = false ;
+#if PRESOLVE_DEBUG > 1
+      printf("bounds %g %g\n",lowerBound,upperBound);
+#endif
+      if (c2 > c1) minterm |= 1<<0 ;
+      if (cup2 >= PRESOLVE_INF/*prob->colInfinite(j2)*/) minterm |= 1<<1 ;
+      if (clo2 <= -PRESOLVE_INF) minterm |= 1<<2 ;
+      if (cup1 >= PRESOLVE_INF/*prob->colInfinite(j1)*/) minterm |= 1<<3 ;
+      if (clo1 <= -PRESOLVE_INF) minterm |= 1<<4 ;
+      // for now be careful - just one special case
+      if (!clo1&&!clo2) {
+        if (c2 > c1 && cup1 >= upperBound)
+          minterm |= 1<<3;
+        else if (c2 < c1 && cup2 >= upperBound)
+          minterm |= 1<<1;
+      }
+/*
+  The most common case in a well-formed system should be no inference. We're
+  looking for x00x1 (case G) and 0xx00 (case H). This is where we have the
+  potential to miss inferences: If there are three or more columns with the
+  same sum, sort[tgt] == j1 will only be compared to the second in the
+  group.
+*/
+      if ((minterm&0x0d) == 0x1 || (minterm&0x13) == 0)
+      { tgt = jj ;
+	continue ; }
+/*
+  Next remove the unbounded cases, 1xx10 and x11x1.
+*/
+      if ((minterm&0x13) == 0x12 || (minterm&0x0d) == 0x0d)
+      { prob->setStatus(2) ;
+#       if PRESOLVE_DEBUG > 1
+	PRESOLVE_STMT(printf("DUPCOL: (%d,%d) Unbounded\n",j1,j2)) ;
+#       endif
+	break ; }
+/*
+  With the no inference and unbounded cases removed, all that's left are the
+  cases where we can push a variable to bound. Swap if necessary (x01x1 or
+  0xx10) so that we're always fixing index j2.  This means that column
+  sort[tgt] = j1 will be fixed. Unswapped, we fix column sort[jj] = j2.
+*/
+      if ((minterm&0x0d) == 0x05 || (minterm&0x13) == 0x02)
+      { CoinSwap(j1, j2) ;
+	CoinSwap(clo1, clo2) ;
+	CoinSwap(cup1, cup2) ;
+	CoinSwap(c1, c2) ;
+	int tmp1 = minterm&0x18 ;
+	int tmp2 = minterm&0x06 ;
+	int tmp3 = minterm&0x01 ;
+	minterm = (tmp1>>2)|(tmp2<<2)|(tmp3^0x01) ;
+	swapped = true ; }
+/*
+  Force x_2 to upper bound? (Case B, boolean 1X100, where X == don't care.)
+*/
+      if ((minterm&0x13) == 0x10)
+      { fixed_up[nfixed_up++] = j2 ;
+#       if PRESOLVE_DEBUG > 1
+	PRESOLVE_STMT(printf("DUPCOL: (%d,%d) %d -> NBUB\n",j1,j2,j2)) ;
+#       endif
+	if (prob->colstat_)
+	{ if (prob->getColumnStatus(j1) == CoinPrePostsolveMatrix::basic ||
+	      prob->getColumnStatus(j2) == CoinPrePostsolveMatrix::basic)
+	  { prob->setColumnStatus(j1,CoinPrePostsolveMatrix::basic) ; }
+	  prob->setColumnStatus(j2,CoinPrePostsolveMatrix::atUpperBound) ; }
+	if (sol)
+	{ double delta2 = cup2-sol[j2] ;
+	  sol[j2] = cup2 ;
+	  sol[j1] -= delta2 ; }
+	if (swapped)
+	{ tgt = jj ; }
+	continue ; }
+/*
+  Force x_2 to lower bound? (Case C, boolean X1011.)
+*/
+      if ((minterm&0x0d) == 0x09)
+      { fixed_down[nfixed_down++] = j2 ;
+#       if PRESOLVE_DEBUG > 1
+	PRESOLVE_STMT(printf("DUPCOL: (%d,%d) %d -> NBLB\n",j1,j2,j2)) ;
+#       endif
+	if (prob->colstat_)
+	{ if (prob->getColumnStatus(j1) == CoinPrePostsolveMatrix::basic ||
+	      prob->getColumnStatus(j2) == CoinPrePostsolveMatrix::basic)
+	  { prob->setColumnStatus(j1,CoinPrePostsolveMatrix::basic) ; }
+	  prob->setColumnStatus(j2,CoinPrePostsolveMatrix::atLowerBound) ; }
+	if (sol)
+	{ double delta2 = clo2-sol[j2] ;
+	  sol[j2] = clo2 ;
+	  sol[j1] -= delta2 ; }
+	if (swapped)
+	{ tgt = jj ; }
+	continue ; } }
+/*
+  We should never reach this point in the loop --- all cases force a new
+  iteration or loop termination. If we get here, something happened that we
+  didn't anticipate.
+*/
+    PRESOLVE_STMT(printf("DUPCOL: (%d,%d) UNEXPECTED!\n",j1,j2)) ; }
+/*
+  What's left? Deallocate vectors, and call make_fixed_action to handle any
+  variables that were fixed to bound.
+*/
+  if (rowmul != prob->randomNumber_)
+    delete[] rowmul ;
+  //delete[] colsum ;
+  //delete[] sort ;
+  //delete [] rhs;
+
+# if PRESOLVE_SUMMARY || PRESOLVE_DEBUG
+  if (nactions+nfixed_down+nfixed_up > 0)
+  { printf("DUPLICATE COLS: %d combined, %d lb, %d ub\n",
+	   nactions,nfixed_down,nfixed_up) ; }
+# endif
+  if (nactions)
+  { next = new dupcol_action(nactions,CoinCopyOfArray(actions,nactions),next) ;
+    // we can't go round again in integer
+    prob->presolveOptions_ |= 0x80000000;
+}
+  deleteAction(actions,action*) ;
+
+  if (nfixed_down)
+  { next =
+      make_fixed_action::presolve(prob,fixed_down,nfixed_down,true,next) ; }
+  delete[]fixed_down ;
+
+  if (nfixed_up)
+  { next =
+      make_fixed_action::presolve(prob,fixed_up,nfixed_up,false,next) ; }
+  delete[]fixed_up ;
+
+# if COIN_PRESOLVE_TUNING > 0
+  if (prob->tuning_) double thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_sol(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving dupcol_action::presolve, "
+    << droppedRows << " rows, " << droppedColumns << " columns dropped" ;
+# if COIN_PRESOLVE_TUNING > 0
+  std::cout << " in " << thisTime-startTime << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+
+void dupcol_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_;
+  const int nactions = nactions_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+
+  double *sol	= prob->sol_;
+  double *dcost	= prob->cost_;
+  
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt		= prob->mcstrt_;
+  int *hincol		= prob->hincol_;
+  int *link		= prob->link_;
+
+  double *rcosts	= prob->rcosts_;
+  double tolerance = prob->ztolzb_;
+
+  for (const action *f = &actions[nactions-1]; actions<=f; f--) {
+    int icol  = f->ithis;	// was fixed
+    int icol2 = f->ilast;	// was kept
+
+    dcost[icol] = dcost[icol2];
+    clo[icol] = f->thislo;
+    cup[icol] = f->thisup;
+    clo[icol2] = f->lastlo;
+    cup[icol2] = f->lastup;
+
+    create_col(icol,f->nincol,f->colels,mcstrt,colels,hrow,link,
+	       &prob->free_list_) ;
+#   if PRESOLVE_CONSISTENCY
+    presolve_check_free_list(prob) ;
+#   endif
+    // hincol[icol] = hincol[icol2]; // right? - no - has to match number in create_col
+    hincol[icol] = f->nincol; 
+
+    double l_j = f->thislo;
+    double u_j = f->thisup;
+    double l_k = f->lastlo;
+    double u_k = f->lastup;
+    double x_k_sol = sol[icol2];
+    PRESOLVE_DETAIL_PRINT(printf("post icol %d %g %g %g icol2 %d %g %g %g\n",
+	   icol,clo[icol],sol[icol],cup[icol],
+				 icol2,clo[icol2],sol[icol2],cup[icol2]));
+    if (l_j>-PRESOLVE_INF&& x_k_sol-l_j>=l_k-tolerance&&x_k_sol-l_j<=u_k+tolerance) {
+      // j at lb, leave k
+      prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atLowerBound);
+      sol[icol] = l_j;
+      sol[icol2] = x_k_sol - sol[icol];
+    } else if (u_j<PRESOLVE_INF&& x_k_sol-u_j>=l_k-tolerance&&x_k_sol-u_j<=u_k+tolerance) {
+      // j at ub, leave k
+      prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atUpperBound);
+      sol[icol] = u_j;
+      sol[icol2] = x_k_sol - sol[icol];
+    } else if (l_k>-PRESOLVE_INF&& x_k_sol-l_k>=l_j-tolerance&&x_k_sol-l_k<=u_j+tolerance) {
+      // k at lb make j basic
+      prob->setColumnStatus(icol,prob->getColumnStatus(icol2));
+      sol[icol2] = l_k;
+      sol[icol] = x_k_sol - l_k;
+      prob->setColumnStatus(icol2,CoinPrePostsolveMatrix::atLowerBound);
+    } else if (u_k<PRESOLVE_INF&& x_k_sol-u_k>=l_j-tolerance&&x_k_sol-u_k<=u_j+tolerance) {
+      // k at ub make j basic
+      prob->setColumnStatus(icol,prob->getColumnStatus(icol2));
+      sol[icol2] = u_k;
+      sol[icol] = x_k_sol - u_k;
+      prob->setColumnStatus(icol2,CoinPrePostsolveMatrix::atUpperBound);
+    } else {
+      // both free!  superbasic time
+      sol[icol] = 0.0;	// doesn't matter
+      prob->setColumnStatus(icol,CoinPrePostsolveMatrix::isFree);
+    }
+    PRESOLVE_DETAIL_PRINT(printf("post2 icol %d %g icol2 %d %g\n",
+	   icol,sol[icol],
+				 icol2,sol[icol2]));
+    // row activity doesn't change
+    // dj of both variables is the same
+    rcosts[icol] = rcosts[icol2];
+    // leave until destructor
+    //    deleteAction(f->colels,double *);
+
+#   if PRESOLVE_DEBUG > 0
+    const double ztolzb = prob->ztolzb_;
+    if (! (clo[icol] - ztolzb <= sol[icol] && sol[icol] <= cup[icol] + ztolzb))
+	     printf("BAD DUPCOL BOUNDS:  %g %g %g\n", clo[icol], sol[icol], cup[icol]);
+    if (! (clo[icol2] - ztolzb <= sol[icol2] && sol[icol2] <= cup[icol2] + ztolzb))
+	     printf("BAD DUPCOL BOUNDS:  %g %g %g\n", clo[icol2], sol[icol2], cup[icol2]);
+#   endif
+  }
+  // leave until desctructor
+  //  deleteAction(actions_,action *);
+}
+
+dupcol_action::~dupcol_action()
+{
+    for (int i = nactions_-1; i >= 0; --i) {
+	deleteAction(actions_[i].colels, double *);
+    }
+    deleteAction(actions_, action*);
+}
+
+
+
+/*
+  Routines for duplicate rows. This is definitely unfinished --- there's no
+  postsolve action.
+*/
+
+const char *duprow_action::name () const
+{
+  return ("duprow_action");
+}
+
+// This is just ekkredc4, adapted into the new framework.
+/*
+  I've made minimal changes for compatibility with dupcol: An initial scan to
+  accumulate rows of interest in sort.
+  -- lh, 040909 --
+*/
+const CoinPresolveAction
+    *duprow_action::presolve (CoinPresolveMatrix *prob,
+			      const CoinPresolveAction *next)
+{
+  double startTime = 0.0;
+  int startEmptyRows=0;
+  int startEmptyColumns = 0;
+  if (prob->tuning_) {
+    startTime = CoinCpuTime();
+    startEmptyRows = prob->countEmptyRows();
+    startEmptyColumns = prob->countEmptyCols();
+  }
+  double *rowels	= prob->rowels_;
+  int *hcol		= prob->hcol_;
+  CoinBigIndex *mrstrt	= prob->mrstrt_;
+  int *hinrow		= prob->hinrow_;
+  int ncols		= prob->ncols_;
+  int nrows		= prob->nrows_;
+
+/*
+  Scan the rows for candidates, and write the indices into sort. We're not
+  interested in rows that are empty or prohibited.
+
+  Question: Should we exclude singletons, which are useful in other transforms?
+  Question: Why are we excluding integral columns?
+*/
+  int *sort = new int[nrows] ;
+  int nlook = 0 ;
+  for (int i = 0 ; i < nrows ; i++)
+  { if (hinrow[i] == 0) continue ;
+    if (prob->rowProhibited2(i)) continue ;
+    // sort
+    CoinSort_2(hcol+mrstrt[i],hcol+mrstrt[i]+hinrow[i],
+	       rowels+mrstrt[i]);
+    sort[nlook++] = i ; }
+  if (nlook == 0)
+  { delete[] sort ;
+    return (next) ; }
+
+  double * workrow = new double[nrows+1];
+
+  double * workcol;
+  if (!prob->randomNumber_) {
+    workcol = new double[ncols+1];
+    coin_init_random_vec(workcol, ncols);
+  } else {
+    workcol = prob->randomNumber_;
+  }
+  compute_sums(nrows,hinrow,mrstrt,hcol,rowels,workcol,sort,workrow,nlook);
+  CoinSort_2(workrow,workrow+nlook,sort);
+
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  int nuseless_rows = 0;
+  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+  bool allowIntersection = ((prob->presolveOptions_&0x10) != 0) ;
+  double tolerance = prob->feasibilityTolerance_;
+
+  double dval = workrow[0];
+  for (int jj = 1; jj < nlook; jj++) {
+    if (workrow[jj]==dval) {
+      int ithis=sort[jj];
+      int ilast=sort[jj-1];
+      CoinBigIndex krs = mrstrt[ithis];
+      CoinBigIndex kre = krs + hinrow[ithis];
+      if (hinrow[ithis] == hinrow[ilast]) {
+	int ishift = mrstrt[ilast] - krs;
+	CoinBigIndex k;
+	for (k=krs;k<kre;k++) {
+	  if (hcol[k] != hcol[k+ishift] ||
+	      rowels[k] != rowels[k+ishift]) {
+	    break;
+	  }
+	}
+	if (k == kre) {
+	  /* now check rhs to see what is what */
+	  double rlo1=rlo[ilast];
+	  double rup1=rup[ilast];
+	  double rlo2=rlo[ithis];
+	  double rup2=rup[ithis];
+
+	  int idelete=-1;
+	  if (rlo1<=rlo2) {
+	    if (rup2<=rup1) {
+	      /* this is strictly tighter than last */
+	      idelete=ilast;
+	      PRESOLVE_DETAIL_PRINT(printf("pre_duprow %dR %dR E\n",ilast,ithis));
+	    } else if (fabs(rlo1-rlo2)<1.0e-12) {
+	      /* last is strictly tighter than this */
+	      idelete=ithis;
+	      PRESOLVE_DETAIL_PRINT(printf("pre_duprow %dR %dR E\n",ithis,ilast));
+	      // swap so can carry on deleting
+	      sort[jj-1]=ithis;
+	      sort[jj]=ilast;
+	    } else {
+	      if (rup1<rlo2-tolerance&&!fixInfeasibility) {
+		// infeasible
+		prob->status_|= 1;
+		// wrong message - correct if works
+		prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
+						prob->messages())
+						  <<ithis
+						  <<rlo[ithis]
+						  <<rup[ithis]
+						  <<CoinMessageEol;
+		break;
+	      } else if (allowIntersection/*||fabs(rup1-rlo2)<tolerance*/) {
+		/* overlapping - could merge */
+#ifdef CLP_INVESTIGATE7
+		printf("overlapping duplicate row %g %g, %g %g\n",
+		       rlo1,rup1,rlo2,rup2);
+#	      endif
+		// pretend this is stricter than last
+		idelete=ilast;
+		PRESOLVE_DETAIL_PRINT(printf("pre_duprow %dR %dR E\n",ilast,ithis));
+		rup[ithis]=rup1;
+	      }
+	    }
+	  } else {
+	    // rlo1>rlo2
+	    if (rup1<=rup2) {
+	      /* last is strictly tighter than this */
+	      idelete=ithis;
+	      PRESOLVE_DETAIL_PRINT(printf("pre_duprow %dR %dR E\n",ithis,ilast));
+	      // swap so can carry on deleting
+	      sort[jj-1]=ithis;
+	      sort[jj]=ilast;
+	    } else {
+	      /* overlapping - could merge */
+	      // rlo1>rlo2
+	      // rup1>rup2 
+	      if (rup2<rlo1-tolerance&&!fixInfeasibility) {
+		// infeasible
+		prob->status_|= 1;
+		// wrong message - correct if works
+		prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
+						prob->messages())
+						  <<ithis
+						  <<rlo[ithis]
+						  <<rup[ithis]
+						  <<CoinMessageEol;
+		break;
+	      } else if (allowIntersection/*||fabs(rup2-rlo1)<tolerance*/) {
+#ifdef CLP_INVESTIGATE7
+		printf("overlapping duplicate row %g %g, %g %g\n",
+		       rlo1,rup1,rlo2,rup2);
+#	      endif
+		// pretend this is stricter than last
+		idelete=ilast;
+		PRESOLVE_DETAIL_PRINT(printf("pre_duprow %dR %dR E\n",ilast,ithis));
+		rlo[ithis]=rlo1;
+	      }
+	    }
+	  }
+	  if (idelete>=0) 
+	    sort[nuseless_rows++]=idelete;
+	}
+      }
+    }
+    dval=workrow[jj];
+  }
+
+  delete[]workrow;
+  if(workcol != prob->randomNumber_)
+    delete[]workcol;
+
+
+  if (nuseless_rows) {
+#   if PRESOLVE_SUMMARY
+    printf("DUPLICATE ROWS:  %d\n", nuseless_rows);
+#   endif
+    next = useless_constraint_action::presolve(prob,
+					       sort, nuseless_rows,
+					       next);
+  }
+  delete[]sort;
+
+  if (prob->tuning_) {
+    double thisTime=CoinCpuTime();
+    int droppedRows = prob->countEmptyRows() - startEmptyRows ;
+    int droppedColumns =  prob->countEmptyCols() - startEmptyColumns;
+    printf("CoinPresolveDuprow(256) - %d rows, %d columns dropped in time %g, total %g\n",
+	   droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_);
+  }
+  return (next);
+}
+
+void duprow_action::postsolve(CoinPostsolveMatrix *) const
+{
+  printf("STILL NO POSTSOLVE FOR DUPROW!\n");
+  abort();
+}
+
+
+
+/*
+  Routines for gub rows. This is definitely unfinished --- there's no
+  postsolve action.
+
+  This is potentially called from ClpPresolve and OsiPresolve. Unclear that
+  it can be backed out --- there's no postsolve.
+*/
+
+const char *gubrow_action::name () const
+{
+  return ("gubrow_action");
+}
+
+
+const CoinPresolveAction
+    *gubrow_action::presolve (CoinPresolveMatrix *prob,
+			      const CoinPresolveAction *next)
+{
+  double startTime = 0.0;
+  int droppedElements=0;
+  int affectedRows=0;
+  if (prob->tuning_) {
+    startTime = CoinCpuTime();
+  }
+  double *rowels	= prob->rowels_;
+  int *hcol		= prob->hcol_;
+  CoinBigIndex *mrstrt	= prob->mrstrt_;
+  int *hinrow		= prob->hinrow_;
+  double *colels	= prob->colels_ ;
+  int *hrow		= prob->hrow_ ;
+  CoinBigIndex *mcstrt	= prob->mcstrt_ ;
+  int *hincol		= prob->hincol_ ;
+  int ncols		= prob->ncols_;
+  int nrows		= prob->nrows_;
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+/*
+  Scan the rows.  We're not
+  interested in rows that are empty or prohibited.
+
+*/
+  int *which = prob->usefulRowInt_;
+  int * number = which + nrows;
+  double * els = prob->usefulRowDouble_;
+  char * markCol = reinterpret_cast<char *> (prob->usefulColumnInt_);
+  memset(markCol,0,ncols);
+  CoinZeroN(els,nrows);
+  for (int i = 0 ; i < nrows ; i++) {
+    int nInRow = hinrow[i];
+    if (nInRow>1 &&!prob->rowProhibited2(i)&&rlo[i]==rup[i]) {
+      CoinBigIndex rStart = mrstrt[i];
+      CoinBigIndex k = rStart;
+      CoinBigIndex rEnd = rStart+nInRow;
+      double value1=rowels[k];
+      k++;
+      for (;k<rEnd;k++) {
+	if (rowels[k]!=value1)
+	  break;
+      }
+      if (k==rEnd) {
+	// Gub row
+	int nLook = 0 ;
+	for (k=rStart;k<rEnd;k++) {
+	  int iColumn = hcol[k];
+	  markCol[iColumn]=1;
+	  CoinBigIndex kk = mcstrt[iColumn];
+	  CoinBigIndex cEnd = kk+hincol[iColumn];
+	  for (;kk<cEnd;kk++) {
+	    int iRow = hrow[kk];
+	    double value = colels[kk];
+	    if (iRow!=i) {
+	      double value2 = els[iRow];
+	      if (value2) {
+		if (value==value2)
+		  number[iRow]++;
+	      } else {
+		// first
+		els[iRow]=value;
+		number[iRow]=1;
+		which[nLook++]=iRow;
+	      }
+	    }
+	  }
+	}
+	// Now see if any promising
+	for (int j=0;j<nLook;j++) {
+	  int iRow = which[j];
+	  if (number[iRow]==nInRow) {
+	    // can delete elements and adjust rhs
+	    affectedRows++;
+	    droppedElements += nInRow;
+	    for (CoinBigIndex kk=rStart; kk<rEnd; kk++) 
+	      presolve_delete_from_col(iRow,hcol[kk],mcstrt,hincol,hrow,colels) ;
+	    int nInRow2 = hinrow[iRow];
+	    CoinBigIndex rStart2 = mrstrt[iRow];
+	    CoinBigIndex rEnd2 = rStart2+nInRow2;
+	    for (CoinBigIndex kk=rStart2; kk<rEnd2; kk++) {
+	      int iColumn = hcol[kk];
+	      if (markCol[iColumn]==0) {
+		hcol[rStart2]=iColumn;
+		rowels[rStart2++]=rowels[kk];
+	      }
+	    }
+	    hinrow[iRow] = nInRow2-nInRow;
+	    if (!hinrow[iRow])
+	      PRESOLVE_REMOVE_LINK(prob->rlink_,iRow) ;
+	    double value =(rlo[i]/value1)*els[iRow];
+	    // correct rhs
+	    if (rlo[iRow]>-1.0e20)
+	      rlo[iRow] -= value;
+	    if (rup[iRow]<1.0e20)
+	      rup[iRow] -= value;
+	  }
+	  els[iRow]=0.0;
+	}
+	for (k=rStart;k<rEnd;k++) {
+	  int iColumn = hcol[k];
+	  markCol[iColumn]=0;
+	}
+      }
+    }
+  }
+  if (prob->tuning_) {
+    double thisTime=CoinCpuTime();
+    printf("CoinPresolveGubrow(1024) - %d elements dropped (%d rows) in time %g, total %g\n",
+	   droppedElements,affectedRows,thisTime-startTime,thisTime-prob->startTime_);
+  } else if (droppedElements) {
+#ifdef CLP_INVESTIGATE
+    printf("CoinPresolveGubrow(1024) - %d elements dropped (%d rows)\n",
+	   droppedElements,affectedRows);
+#endif
+  }
+  return (next);
+}
+
+void gubrow_action::postsolve(CoinPostsolveMatrix *) const
+{
+  printf("STILL NO POSTSOLVE FOR GUBROW!\n");
+  abort();
+}
+
+
+
+/*
+  Routines for two by two blocks. This is definitely unfinished --- there's no
+  postsolve action.
+*/
+
+const char *twoxtwo_action::name () const
+{
+  return ("twoxtwo_action");
+}
+
+const CoinPresolveAction
+    *twoxtwo_action::presolve (CoinPresolveMatrix *prob,
+			      const CoinPresolveAction *next)
+{
+  double startTime = 0.0;
+  int startEmptyRows=0;
+  int startEmptyColumns = 0;
+  if (prob->tuning_) {
+    startTime = CoinCpuTime();
+    startEmptyRows = prob->countEmptyRows();
+    startEmptyColumns = prob->countEmptyCols();
+  }
+  // maximum number of records
+  action * boundRecords = new action[(prob->nrows_+1)>>1];
+  int nactions=0;
+  // column-major representation
+  const int ncols = prob->ncols_ ;
+  const CoinBigIndex *const mcstrt = prob->mcstrt_ ;
+  const int *const hincol = prob->hincol_ ;
+  const int *const hrow = prob->hrow_ ;
+  const double * colels = prob->colels_ ;
+  double * cost = prob->cost_ ;
+
+  // column type, bounds, solution, and status
+  const unsigned char *const integerType = prob->integerType_ ;
+  double * clo = prob->clo_ ;
+  double * cup = prob->cup_ ;
+  // row-major representation
+  //const int nrows = prob->nrows_ ;
+  const CoinBigIndex *const mrstrt = prob->mrstrt_ ;
+  const int *const hinrow = prob->hinrow_ ;
+  const int *const hcol = prob->hcol_ ;
+  const double * rowels = prob->rowels_ ;
+
+  // row bounds
+  double * rlo = prob->rlo_ ;
+  double * rup = prob->rup_ ;
+
+  // tolerances
+  //const double ekkinf2 = PRESOLVE_SMALL_INF ;
+  //const double ekkinf = ekkinf2*1.0e8 ;
+  //const double ztolcbarj = prob->ztoldj_ ;
+  //const CoinRelFltEq relEq(prob->ztolzb_) ;
+  double bound[2];
+  double alpha[2]={0.0,0.0};
+  double offset=0.0;
+
+  for (int icol=0;icol<ncols;icol++) {
+    if (hincol[icol]==2) {
+      CoinBigIndex start=mcstrt[icol];
+      int row0 = hrow[start];
+      if (hinrow[row0]!=2)
+	continue;
+      int row1 = hrow[start+1];
+      if (hinrow[row1]!=2)
+	continue;
+      double element0 = colels[start];
+      double rowUpper0=rup[row0];
+      bool swapSigns0=false;
+      if (rlo[row0]>-1.0e30) {
+	if (rup[row0]>1.0e30) {
+	  swapSigns0=true;
+	  rowUpper0=-rlo[row0];
+	  element0=-element0;
+	} else {
+	  // range or equality
+	  continue;
+	}
+      } else if (rup[row0]>1.0e30) {
+	// free
+	continue;
+      }
+#if 0
+      // skip here for speed
+      // skip if no cost (should be able to get rid of)
+      if (!cost[icol]) {
+	PRESOLVE_DETAIL_PRINT(printf("should be able to get rid of %d with no cost\n",icol));
+	continue;
+      }
+      // skip if negative cost for now
+      if (cost[icol]<0.0) {
+	PRESOLVE_DETAIL_PRINT(printf("code for negative cost\n"));
+	continue;
+      }
+#endif
+      double element1 = colels[start+1];
+      double rowUpper1=rup[row1];
+      bool swapSigns1=false;
+      if (rlo[row1]>-1.0e30) {
+	if (rup[row1]>1.0e30) {
+	  swapSigns1=true;
+	  rowUpper1=-rlo[row1];
+	  element1=-element1;
+	} else {
+	  // range or equality
+	  continue;
+	}
+      } else if (rup[row1]>1.0e30) {
+	// free
+	continue;
+      }
+      double lowerX=clo[icol];
+      double upperX=cup[icol];
+      int otherCol=-1;
+      CoinBigIndex startRow=mrstrt[row0];
+      for (CoinBigIndex j=startRow;j<startRow+2;j++) {
+	int jcol=hcol[j];
+	if (jcol!=icol) {
+	  alpha[0]=swapSigns0 ? -rowels[j] :rowels[j];
+	  otherCol=jcol;
+	}
+      }
+      startRow=mrstrt[row1];
+      bool possible=true;
+      for (CoinBigIndex j=startRow;j<startRow+2;j++) {
+	int jcol=hcol[j];
+	if (jcol!=icol) {
+	  if (jcol==otherCol) {
+	    alpha[1]=swapSigns1 ? -rowels[j] :rowels[j];
+	  } else {
+	    possible=false;
+	  }
+	}
+      }
+      if (possible) {
+	// skip if no cost (should be able to get rid of)
+	if (!cost[icol]) {
+	  PRESOLVE_DETAIL_PRINT(printf("should be able to get rid of %d with no cost\n",icol));
+	  continue;
+	}
+	// skip if negative cost for now
+	if (cost[icol]<0.0) {
+	  PRESOLVE_DETAIL_PRINT(printf("code for negative cost\n"));
+	  continue;
+	}
+	bound[0]=clo[otherCol];
+	bound[1]=cup[otherCol];
+	double lowestLowest=COIN_DBL_MAX;
+	double highestLowest=-COIN_DBL_MAX;
+	double lowestHighest=COIN_DBL_MAX;
+	double highestHighest=-COIN_DBL_MAX;
+	int binding0=0;
+	int binding1=0;
+	for (int k=0;k<2;k++) {
+	  bool infLow0=false;
+	  bool infLow1=false;
+	  double sum0=0.0;
+	  double sum1=0.0;
+	  double value=bound[k];
+	  if (fabs(value)<1.0e30) {
+	    sum0+=alpha[0]*value;
+	    sum1+=alpha[1]*value;
+	  } else {
+	    if (alpha[0]>0.0) {
+	      if (value<0.0)
+		infLow0 =true;
+	    } else if (alpha[0]<0.0) {
+	      if (value>0.0)
+		infLow0 =true;
+	    }
+	    if (alpha[1]>0.0) {
+	      if (value<0.0)
+		infLow1 =true;
+	    } else if (alpha[1]<0.0) {
+	      if (value>0.0)
+		infLow1 =true;
+	    }
+	  }
+	  /* Got sums
+	   */
+	  double thisLowest0=-COIN_DBL_MAX;
+	  double thisHighest0=COIN_DBL_MAX;
+	  if (element0>0.0) {
+	    // upper bound unless inf&2 !=0
+	    if (!infLow0)
+	      thisHighest0 = (rowUpper0-sum0)/element0;
+	  } else {
+	    // lower bound unless inf&2 !=0
+	    if (!infLow0)
+	      thisLowest0 = (rowUpper0-sum0)/element0;
+	  }
+	  double thisLowest1=-COIN_DBL_MAX;
+	  double thisHighest1=COIN_DBL_MAX;
+	  if (element1>0.0) {
+	    // upper bound unless inf&2 !=0
+	    if (!infLow1)
+	      thisHighest1 = (rowUpper1-sum1)/element1;
+	  } else {
+	    // lower bound unless inf&2 !=0
+	    if (!infLow1)
+	      thisLowest1 = (rowUpper1-sum1)/element1;
+	  }
+	  if (thisLowest0>thisLowest1+1.0e-12) {
+	    if (thisLowest0>lowerX+1.0e-12)
+	      binding0|= 1<<k;
+	  } else if (thisLowest1>thisLowest0+1.0e-12) {
+	    if (thisLowest1>lowerX+1.0e-12)
+	      binding1|= 1<<k;
+	    thisLowest0=thisLowest1;
+	  }
+	  if (thisHighest0<thisHighest1-1.0e-12) {
+	    if (thisHighest0<upperX-1.0e-12)
+	      binding0|= 1<<k;
+	  } else if (thisHighest1<thisHighest0-1.0e-12) {
+	    if (thisHighest1<upperX-1.0e-12)
+	      binding1|= 1<<k;
+	    thisHighest0=thisHighest1;
+	  }
+	  lowestLowest=CoinMin(lowestLowest,thisLowest0);
+	  highestHighest=CoinMax(highestHighest,thisHighest0);
+	  lowestHighest=CoinMin(lowestHighest,thisHighest0);
+	  highestLowest=CoinMax(highestLowest,thisLowest0);
+	}
+	// see if any good
+	//#define PRINT_VALUES
+	if (!binding0||!binding1) {
+	  PRESOLVE_DETAIL_PRINT(printf("Row redundant for column %d\n",icol));
+	} else {
+	  PRESOLVE_DETAIL_PRINT(printf("Column %d bounds %g,%g lowest %g,%g highest %g,%g\n",
+		 icol,lowerX,upperX,lowestLowest,lowestHighest,
+				       highestLowest,highestHighest));
+	  // if integer adjust
+	  if (integerType[icol]) {
+	    lowestLowest=ceil(lowestLowest-1.0e-5);
+	    highestLowest=ceil(highestLowest-1.0e-5);
+	    lowestHighest=floor(lowestHighest+1.0e-5);
+	    highestHighest=floor(highestHighest+1.0e-5);
+	  }
+	  // if costed may be able to adjust
+	  if (cost[icol]>=0.0) {
+	    if (highestLowest<upperX&&highestLowest>=lowerX&&highestHighest<1.0e30) {
+	      highestHighest=CoinMin(highestHighest,highestLowest);
+	    }
+	  }
+	  if (cost[icol]<=0.0) {
+	    if (lowestHighest>lowerX&&lowestHighest<=upperX&&lowestHighest>-1.0e30) {
+	      lowestLowest=CoinMax(lowestLowest,lowestHighest);
+	    }
+	  }
+#if 1
+	  if (lowestLowest>lowerX+1.0e-8) {
+	    PRESOLVE_DETAIL_PRINT(printf("Can increase lower bound on %d from %g to %g\n",
+					 icol,lowerX,lowestLowest));
+	    lowerX=lowestLowest;
+	  }
+	  if (highestHighest<upperX-1.0e-8) {
+	    PRESOLVE_DETAIL_PRINT(printf("Can decrease upper bound on %d from %g to %g\n",
+					 icol,upperX,highestHighest));
+	    upperX=highestHighest;
+	    
+	  }
+#endif
+	  // see if we can move costs
+	  double xValue;
+	  double yValue0;
+	  double yValue1;
+	  double newLower=COIN_DBL_MAX;
+	  double newUpper=-COIN_DBL_MAX;
+	  double costEqual;
+	  double slope[2];
+	  assert (binding0+binding1==3);
+	  // get where equal
+	  xValue=(rowUpper0*element1-rowUpper1*element0)/(alpha[0]*element1-alpha[1]*element0);
+	  yValue0=(rowUpper0-xValue*alpha[0])/element0;
+	  yValue1=(rowUpper1-xValue*alpha[1])/element1;
+	  newLower=CoinMin(newLower,CoinMax(yValue0,yValue1));
+	  newUpper=CoinMax(newUpper,CoinMax(yValue0,yValue1));
+	  double xValueEqual=xValue;
+	  double yValueEqual=yValue0;
+	  costEqual = xValue*cost[otherCol]+yValueEqual*cost[icol];
+	  if (binding0==1) {
+	    // take x 1.0 down
+	    double x=xValue-1.0;
+	    double y=(rowUpper0-x*alpha[0])/element0;
+	    double costTotal = x*cost[otherCol]+y*cost[icol];
+	    slope[0] = costEqual-costTotal;
+	    // take x 1.0 up
+	    x=xValue+1.0;
+	    y=(rowUpper1-x*alpha[1])/element0;
+	    costTotal = x*cost[otherCol]+y*cost[icol];
+	    slope[1] = costTotal-costEqual;
+	  } else {
+	    // take x 1.0 down
+	    double x=xValue-1.0;
+	    double y=(rowUpper1-x*alpha[1])/element0;
+	    double costTotal = x*cost[otherCol]+y*cost[icol];
+	    slope[1] = costEqual-costTotal;
+	    // take x 1.0 up
+	    x=xValue+1.0;
+	    y=(rowUpper0-x*alpha[0])/element0;
+	    costTotal = x*cost[otherCol]+y*cost[icol];
+	    slope[0] = costTotal-costEqual;
+	  }
+	  PRESOLVE_DETAIL_PRINT(printf("equal value of %d is %g, value of %d is max(%g,%g) - %g\n",
+				       otherCol,xValue,icol,yValue0,yValue1,CoinMax(yValue0,yValue1)));
+	  PRESOLVE_DETAIL_PRINT(printf("Cost at equality %g for constraint 0 slope %g for constraint 1 slope %g\n",
+				       costEqual,slope[0],slope[1]));
+	  xValue=bound[0];
+	  yValue0=(rowUpper0-xValue*alpha[0])/element0;
+	  yValue1=(rowUpper1-xValue*alpha[1])/element1;
+	  PRESOLVE_DETAIL_PRINT(printf("value of %d is %g, value of %d is max(%g,%g) - %g\n",
+				       otherCol,xValue,icol,yValue0,yValue1,CoinMax(yValue0,yValue1)));
+	  newLower=CoinMin(newLower,CoinMax(yValue0,yValue1));
+	  // cost>0 so will be at lower
+	  //double yValueAtBound0=newLower;
+	  newUpper=CoinMax(newUpper,CoinMax(yValue0,yValue1));
+	  xValue=bound[1];
+	  yValue0=(rowUpper0-xValue*alpha[0])/element0;
+	  yValue1=(rowUpper1-xValue*alpha[1])/element1;
+	  PRESOLVE_DETAIL_PRINT(printf("value of %d is %g, value of %d is max(%g,%g) - %g\n",
+				       otherCol,xValue,icol,yValue0,yValue1,CoinMax(yValue0,yValue1)));
+	  newLower=CoinMin(newLower,CoinMax(yValue0,yValue1));
+	  // cost>0 so will be at lower
+	  //double yValueAtBound1=newLower;
+	  newUpper=CoinMax(newUpper,CoinMax(yValue0,yValue1));
+	  lowerX=CoinMax(lowerX,newLower-1.0e-12*fabs(newLower));
+	  upperX=CoinMin(upperX,newUpper+1.0e-12*fabs(newUpper));
+	  // Now make duplicate row
+	  // keep row 0 so need to adjust costs so same
+	  PRESOLVE_DETAIL_PRINT(printf("Costs for x %g,%g,%g are %g,%g,%g\n",
+		 xValueEqual-1.0,xValueEqual,xValueEqual+1.0,
+				       costEqual-slope[0],costEqual,costEqual+slope[1]));
+	  double costOther=cost[otherCol]+slope[1];
+	  double costThis=cost[icol]+slope[1]*(element0/alpha[0]);
+	  xValue=xValueEqual;
+	  yValue0=CoinMax((rowUpper0-xValue*alpha[0])/element0,lowerX);
+	  double thisOffset=costEqual-(costOther*xValue+costThis*yValue0);
+	  offset += thisOffset;
+	  PRESOLVE_DETAIL_PRINT(printf("new cost at equal %g\n",costOther*xValue+costThis*yValue0+thisOffset));
+	  xValue=xValueEqual-1.0;
+	  yValue0=CoinMax((rowUpper0-xValue*alpha[0])/element0,lowerX);
+	  PRESOLVE_DETAIL_PRINT(printf("new cost at -1 %g\n",costOther*xValue+costThis*yValue0+thisOffset));
+	  assert(fabs((costOther*xValue+costThis*yValue0+thisOffset)-(costEqual-slope[0]))<1.0e-5);
+	  xValue=xValueEqual+1.0;
+	  yValue0=CoinMax((rowUpper0-xValue*alpha[0])/element0,lowerX);
+	  PRESOLVE_DETAIL_PRINT(printf("new cost at +1 %g\n",costOther*xValue+costThis*yValue0+thisOffset));
+	  assert(fabs((costOther*xValue+costThis*yValue0+thisOffset)-(costEqual+slope[1]))<1.0e-5);
+	  action & boundRecord = boundRecords[nactions++] ;
+	  boundRecord.row=row1;
+	  boundRecord.col=icol;
+	  boundRecord.othercol=otherCol;
+	  boundRecord.lbound_row=rlo[row1];
+	  boundRecord.ubound_row=rup[row1];
+	  boundRecord.lbound_col=clo[icol];
+	  boundRecord.ubound_col=cup[icol];
+	  boundRecord.cost_col=cost[icol];
+	  boundRecord.cost_othercol=cost[otherCol];
+	  cost[otherCol] = costOther;
+	  cost[icol] = costThis;
+	  clo[icol]=lowerX;
+	  cup[icol]=upperX;
+	  // make row useless
+	  rlo[row1]=-COIN_DBL_MAX;
+	  rup[row1]=COIN_DBL_MAX;
+	}
+      }
+    }
+  }
+  if (nactions) {
+#   if PRESOLVE_SUMMARY
+    printf("Cost offset %g - from %d blocks\n",offset,nactions);
+    printf("TWO by TWO blocks:  %d - offset %g\n", nactions,offset);
+#   endif
+    action * actions = new action[nactions];
+    memcpy(actions,boundRecords,nactions*sizeof(action));
+    next = new twoxtwo_action(nactions,actions,next);
+    int *sort = prob->usefulColumnInt_; 
+    for (int i=0;i<nactions;i++)
+      sort[i]=boundRecords[i].row;
+    next = useless_constraint_action::presolve(prob,
+					       sort, nactions,
+					       next);
+    // adjust offset
+    prob->change_bias(offset);
+  }
+  delete [] boundRecords;
+  if (prob->tuning_) {
+    double thisTime=CoinCpuTime();
+    int droppedRows = prob->countEmptyRows() - startEmptyRows ;
+    int droppedColumns =  prob->countEmptyCols() - startEmptyColumns;
+    printf("CoinPresolveTwoxtwo(2048) - %d rows, %d columns dropped in time %g, total %g\n",
+	   droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_);
+  }
+  return (next);
+}
+void twoxtwo_action::postsolve(CoinPostsolveMatrix * prob) const
+{
+  const CoinBigIndex *const mcstrt = prob->mcstrt_ ;
+  const int *const hincol = prob->hincol_ ;
+  const int *const hrow = prob->hrow_ ;
+  const double * colels = prob->colels_ ;
+  int *link		= prob->link_;
+  double * cost = prob->cost_ ;
+
+  // column type, bounds, solution, and status
+  //const unsigned char *const integerType = prob->integerType_ ;
+  double * clo = prob->clo_ ;
+  double * cup = prob->cup_ ;
+
+  // row bounds
+  double * rlo = prob->rlo_ ;
+  double * rup = prob->rup_ ;
+  double *sol	= prob->sol_;
+  double *rcosts	= prob->rcosts_;
+  double * rowacts = prob->acts_;
+  double * dual = prob->rowduals_;
+  double tolerance = prob->ztolzb_;
+  const double maxmin	= prob->maxmin_;
+  for (int iAction=0;iAction<nactions_;iAction++) {
+    const action & boundRecord = actions_[iAction];
+    int row1=boundRecord.row;
+    int icol=boundRecord.col;
+    int otherCol=boundRecord.othercol;
+    CoinBigIndex start=mcstrt[icol];
+    CoinBigIndex nextEl = link[start];
+    int row0;
+    // first is otherCol
+    double els0[2]={0.0,0.0};
+    double els1[2]={0.0,0.0};
+    if (hrow[start]==row1) {
+      row0=hrow[nextEl];
+      els0[1]=colels[nextEl];
+      els1[1]=colels[start];
+    } else {
+      row0=hrow[start];
+      els0[1]=colels[start];
+      els1[1]=colels[nextEl];
+    }
+    nextEl=mcstrt[otherCol];
+    for (CoinBigIndex j=0;j<hincol[otherCol];j++) {
+      if (hrow[nextEl]==row0)
+	els0[0]=colels[nextEl];
+      else if (hrow[nextEl]==row1)
+	els1[0]=colels[nextEl];
+      nextEl=link[nextEl];
+    }
+    prob->setRowStatus(row1,CoinPrePostsolveMatrix::basic);
+    // put stuff back
+    rlo[row1]=boundRecord.lbound_row;
+    rup[row1]=boundRecord.ubound_row;
+    clo[icol]=boundRecord.lbound_col;
+    cup[icol]=boundRecord.ubound_col;
+    double oldCost=cost[icol];
+    //double oldOtherCost=cost[otherCol];
+    cost[icol]=boundRecord.cost_col;
+    cost[otherCol]=boundRecord.cost_othercol;
+    double els0real[2];
+    double els1real[2];
+    els0real[0]=els0[0];
+    els0real[1]=els0[1];
+    els1real[0]=els1[0];
+    els1real[1]=els1[1];
+    // make <= rows
+    double rowUpper0=rup[row0];
+    if (rlo[row0]>-1.0e30) {
+      rowUpper0=-rlo[row0];
+      els0[0]=-els0[0];
+      els0[1]=-els0[1];
+    }
+    double rowUpper1=rup[row1];
+    bool swapSigns1=false;
+    if (rlo[row1]>-1.0e30) {
+      swapSigns1=true;
+      rowUpper1=-rlo[row1];
+      els1[0]=-els1[0];
+      els1[1]=-els1[1];
+    }
+    // compute feasible value for icol
+    double valueOther=sol[otherCol];
+    double value;
+    // first see if at bound is OK
+    bool lowerBoundPossible = clo[icol]>-1.0e30;
+    value=clo[icol];
+    if (lowerBoundPossible) {
+      double value0 = els0[0]*valueOther + els0[1]*value;
+      if (value0>rowUpper0+tolerance)
+	lowerBoundPossible=false;
+      double value1 = els1[0]*valueOther + els1[1]*value;
+      if (value1>rowUpper1+tolerance)
+	lowerBoundPossible=false;
+    }
+    bool upperBoundPossible = cup[icol]<1.0e30;
+    value=cup[icol];
+    if (upperBoundPossible) {
+      double value0 = els0[0]*valueOther + els0[1]*value;
+      if (value0>rowUpper0+tolerance)
+	upperBoundPossible=false;
+      double value1 = els1[0]*valueOther + els1[1]*value;
+      if (value1>rowUpper1+tolerance)
+	upperBoundPossible=false;
+    }
+    if (lowerBoundPossible&&cost[icol]>=0.0) {
+      // set to lower bound
+      prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atLowerBound);
+      sol[icol]=clo[icol];
+      rcosts[icol]=maxmin*cost[icol]-dual[row0]*els0real[1];
+    } else if (upperBoundPossible&&cost[icol]<=0.0) {
+      // set to upper bound
+      prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atUpperBound);
+      sol[icol]=cup[icol];
+      rcosts[icol]=maxmin*cost[icol]-dual[row0]*els0real[1];
+    } else {
+      // need to make basic
+      // we shouldn't get here (at present) if zero cost
+      assert (cost[icol]);
+      double value0 = (rowUpper0-els0[0]*valueOther)/els0[1];
+      double value1 = (rowUpper1-els1[0]*valueOther)/els1[1];
+      //bool binding0=true;
+      double value;
+      if (cost[icol]>0) {
+	if (value0>value1) {
+	  value=value0;
+	} else {
+	  value=value1;
+	  //binding0=false;
+	}
+      } else {
+	if (value0<value1) {
+	  value=value0;
+	} else {
+	  value=value1;
+	  //binding0=false;
+	}
+      }
+      sol[icol]=value;
+#if 0
+      printf("row %d status %d, row %d status %d, col %d status %d, col %d status %d - binding0 %c\n",
+	     row0,prob->getRowStatus(row0),
+	     row1,prob->getRowStatus(row1),
+	     otherCol,prob->getColumnStatus(otherCol),
+	     icol,prob->getColumnStatus(icol),binding0 ? 'T' : 'F');
+#endif
+      if (prob->getColumnStatus(icol)==CoinPrePostsolveMatrix::basic) {
+	//printf("col %d above was basic\n",icol);
+	if (prob->getRowStatus(row0)!=CoinPrePostsolveMatrix::basic) {
+	  // adjust dual
+	  dual[row0]=maxmin*((cost[icol]-oldCost)/els0real[1]);
+	}
+	continue;
+      }
+      //if (binding0)
+      //printf("Says row0 %d binding?\n",row0);
+      prob->setColumnStatus(icol,CoinPrePostsolveMatrix::basic);
+      rcosts[icol]=0.0;
+      //printf("row1 %d taken out of basis\n",row1);
+      if (!swapSigns1) {
+	prob->setRowStatus(row1,CoinPrePostsolveMatrix::atUpperBound);
+	rowacts[row1]=rup[row1];
+      } else {
+	prob->setRowStatus(row1,CoinPrePostsolveMatrix::atLowerBound);
+	rowacts[row1]=rlo[row1];
+      }
+      dual[row1]=maxmin*((cost[icol]-oldCost)/els1real[1]);
+      if (iAction==-1)
+	abort();
+    }
+  }
+}
+
diff --git a/cbits/coin/CoinPresolveDupcol.hpp b/cbits/coin/CoinPresolveDupcol.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveDupcol.hpp
@@ -0,0 +1,198 @@
+/* $Id: CoinPresolveDupcol.hpp 1550 2012-08-28 14:55:18Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveDupcol_H
+#define CoinPresolveDupcol_H
+
+#include "CoinPresolveMatrix.hpp"
+
+/*!
+  \file
+*/
+
+#define	DUPCOL	10
+
+/*! \class dupcol_action
+    \brief Detect and remove duplicate columns
+
+    The general technique is to sum the coefficients a_(*,j) of each column.
+    Columns with identical sums are duplicates. The obvious problem is that,
+    <i>e.g.</i>, [1 0 1 0] and [0 1 0 1] both add to 2. To minimize the
+    chances of false positives, the coefficients of each row are multipled by
+    a random number r_i, so that we sum r_i*a_ij.
+
+   Candidate columns are checked to confirm they are identical. Where the
+   columns have the same objective coefficient, the two are combined. If the
+   columns have different objective coefficients, complications ensue. In order
+   to remove the duplicate, it must be possible to fix the variable at a bound.
+*/
+
+class dupcol_action : public CoinPresolveAction {
+  dupcol_action();
+  dupcol_action(const dupcol_action& rhs);
+  dupcol_action& operator=(const dupcol_action& rhs);
+
+  struct action {
+    double thislo;
+    double thisup;
+    double lastlo;
+    double lastup;
+    int ithis;
+    int ilast;
+
+    double *colels;
+    int nincol;
+  };
+
+  const int nactions_;
+  // actions_ is owned by the class and must be deleted at destruction
+  const action *const actions_;
+
+  dupcol_action(int nactions, const action *actions,
+		const CoinPresolveAction *next) :
+      CoinPresolveAction(next),
+      nactions_(nactions),
+      actions_(actions) {}
+
+ public:
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~dupcol_action();
+
+};
+
+
+/*! \class duprow_action
+    \brief Detect and remove duplicate rows
+
+    The algorithm to detect duplicate rows is as outlined for dupcol_action.
+
+    If the feasible interval for one constraint is strictly contained in the
+    other, the tighter (contained) constraint is kept. If the feasible
+    intervals are disjoint, the problem is infeasible. If the feasible
+    intervals overlap, both constraints are kept.
+
+    duprow_action is definitely a work in progress; #postsolve is
+    unimplemented.
+    This doesn't matter as it uses useless_constraint.
+*/
+
+class duprow_action : public CoinPresolveAction {
+  struct action {
+    int row;
+    double lbound;
+    double ubound;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  duprow_action():CoinPresolveAction(NULL),nactions_(0),actions_(NULL) {}
+  duprow_action(int nactions,
+		      const action *actions,
+		      const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions) {}
+
+ public:
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  //~duprow_action() { delete[]actions_; }
+};
+
+/*! \class gubrow_action
+    \brief Detect and remove entries whose sum is known
+
+    If we have an equality row where all entries same then
+    For other rows where all entries for that equality row are same
+    then we can delete entries and modify rhs
+    gubrow_action is definitely a work in progress; #postsolve is
+    unimplemented.
+*/
+
+class gubrow_action : public CoinPresolveAction {
+  struct action {
+    int row;
+    double lbound;
+    double ubound;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  gubrow_action():CoinPresolveAction(NULL),nactions_(0),actions_(NULL) {}
+  gubrow_action(int nactions,
+		      const action *actions,
+		      const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions) {}
+
+ public:
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  //~gubrow_action() { delete[]actions_; }
+};
+
+/*! \class twoxtwo_action
+    \brief Detect interesting 2 by 2 blocks
+
+    If a variable has two entries and for each row there are only
+    two entries with same other variable then we can get rid of 
+    one constraint and modify costs.
+
+    This is a work in progress - I need more examples
+*/
+
+class twoxtwo_action : public CoinPresolveAction {
+  struct action {
+    double lbound_row;
+    double ubound_row;
+    double lbound_col;
+    double ubound_col;
+    double cost_col;
+    double cost_othercol;
+    int row;
+    int col;
+    int othercol;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  twoxtwo_action():CoinPresolveAction(NULL),nactions_(0),actions_(NULL) {}
+  twoxtwo_action(int nactions,
+		      const action *actions,
+		      const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions) {}
+
+ public:
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  ~twoxtwo_action() { delete [] actions_; }
+};
+
+#endif
+
diff --git a/cbits/coin/CoinPresolveEmpty.cpp b/cbits/coin/CoinPresolveEmpty.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveEmpty.cpp
@@ -0,0 +1,659 @@
+/* $Id: CoinPresolveEmpty.cpp 1607 2013-07-16 09:01:29Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinFinite.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+
+#include "CoinPresolveEmpty.hpp"
+#include "CoinMessage.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+/* \file
+
+  Routines to remove/reinsert empty columns and rows.
+*/
+
+
+/*
+  Physically remove empty columns, compressing mcstrt and hincol. The major
+  side effect is that columns are renumbered, thus clink_ is no longer valid
+  and must be rebuilt. And we're totally inconsistent with the row-major
+  representation.
+
+  It's necessary to rebuild clink_ in order to do direct conversion of a
+  CoinPresolveMatrix to a CoinPostsolveMatrix by transferring the data arrays.
+  Without clink_, it's impractical to build link_ to match the transferred bulk
+  storage.
+*/
+const CoinPresolveAction
+  *drop_empty_cols_action::presolve (CoinPresolveMatrix *prob,
+				     const int *ecols,
+				     int necols,
+				     const CoinPresolveAction *next)
+{
+
+# if PRESOLVE_CONSISTENCY > 0
+  presolve_links_ok(prob) ;
+  presolve_consistent(prob) ;
+# endif
+
+  const int n_orig = prob->ncols_ ;
+
+  CoinBigIndex *mcstrt = prob->mcstrt_ ;
+  int *hincol = prob->hincol_ ;
+  presolvehlink *clink = prob->clink_ ;
+
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+  double *cost = prob->cost_ ;
+
+  const double ztoldj = prob->ztoldj_ ;
+
+  unsigned char *integerType = prob->integerType_ ;
+  int *originalColumn = prob->originalColumn_ ;
+
+  const double maxmin = prob->maxmin_ ;
+
+  double *sol = prob->sol_ ;
+  unsigned char *colstat = prob->colstat_ ;
+
+  action *actions = new action[necols] ;
+  int *colmapping = new int [n_orig+1] ;
+  CoinZeroN(colmapping,n_orig) ;
+
+  // More like `ignore infeasibility'
+  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+
+/*
+  Open a loop to walk the list of empty columns. Mark them as empty in
+  colmapping.
+*/
+  for (int ndx = necols-1 ; ndx >= 0 ; ndx--) {
+    const int j = ecols[ndx] ;
+    colmapping[j] = -1 ;
+/*
+  Groom bounds on integral variables. Check for previously undetected
+  infeasibility unless the user wants to ignore it. If we find it, quit.
+*/
+    double &lj = clo[j] ;
+    double &uj = cup[j] ;
+
+    if (integerType[j]) {
+      lj = ceil(lj-1.0e-9) ;
+      uj = floor(uj+1.0e-9) ;
+      if (lj > uj && !fixInfeasibility) {
+	prob->status_ |= 1 ;
+	prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS,
+				        prob->messages())
+	    << j << lj << uj << CoinMessageEol ;
+	break ;
+      }
+    }
+/*
+  Load up the postsolve action with the index and rim vector components.
+*/
+    action &e = actions[ndx] ;
+    e.jcol = j ;
+    e.clo = lj ;
+    e.cup = uj ;
+    e.cost = cost[j] ;
+/*
+  There are no more constraints on this variable so we had better be able to
+  compute the answer now. Try to make it nonbasic at bound. If we're
+  unbounded, say so and quit.
+*/
+    if (fabs(cost[j]) < ztoldj) cost[j] = 0.0 ;
+    if (cost[j] == 0.0) {
+      if (-PRESOLVE_INF < lj)
+        e.sol = lj ;
+      else if (uj < PRESOLVE_INF)
+        e.sol = uj ;
+      else
+        e.sol = 0.0 ;
+    } else if (cost[j]*maxmin > 0.0) {
+      if (-PRESOLVE_INF < lj)
+	e.sol = lj ;
+      else {
+	prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDB,
+					prob->messages())
+	    << j << CoinMessageEol ;
+	prob->status_ |= 2 ;
+	break ;
+      }
+    } else {
+      if (uj < PRESOLVE_INF)
+	e.sol = uj ;
+      else {
+	prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDA,
+					prob->messages())
+	    << j << CoinMessageEol ;
+	prob->status_ |= 2 ;
+	break ;
+      }
+    }
+
+#   if PRESOLVE_DEBUG > 2
+    if (e.sol*cost[j]) {
+      std::cout
+        << "  non-zero cost " << cost[j] << " for empty col " << j << "."
+	<< std::endl ;
+    }
+#   endif
+    prob->change_bias(e.sol*cost[j]) ;
+  }
+/*
+  No sense doing the actual work of compression unless we're still feasible
+  and bounded. If we are, start out by compressing out the entries associated
+  with empty columns. Empty columns are nonzero in colmapping.
+*/
+  if (prob->status_ == 0) {
+    int n_compressed = 0 ;
+    for (int ndx = 0 ; ndx < n_orig ; ndx++) {
+      if (!colmapping[ndx]) {
+	mcstrt[n_compressed] = mcstrt[ndx] ;
+	hincol[n_compressed] = hincol[ndx] ;
+      
+	clo[n_compressed]   = clo[ndx] ;
+	cup[n_compressed]   = cup[ndx] ;
+
+	cost[n_compressed] = cost[ndx] ;
+	if (sol) {
+	  sol[n_compressed] = sol[ndx] ;
+	  colstat[n_compressed] = colstat[ndx] ;
+	}
+
+	integerType[n_compressed] = integerType[ndx] ;
+	originalColumn[n_compressed] = originalColumn[ndx] ;
+	colmapping[ndx] = n_compressed++ ;
+      }
+    }
+    mcstrt[n_compressed] = mcstrt[n_orig] ;
+    colmapping[n_orig] = n_compressed ;
+/*
+  Rebuild clink_. At this point, all empty columns are linked out, so the
+  only columns left are columns that are to be saved, hence available in
+  colmapping.  All we need to do is walk clink_ and write the new entries
+  into a new array.
+*/
+
+    presolvehlink *newclink = new presolvehlink [n_compressed+1] ;
+    for (int oldj = n_orig ; oldj >= 0 ; oldj = clink[oldj].pre) {
+      presolvehlink &oldlnk = clink[oldj] ;
+      int newj = colmapping[oldj] ;
+      assert(newj >= 0 && newj <= n_compressed) ;
+      presolvehlink &newlnk = newclink[newj] ;
+      if (oldlnk.suc >= 0) {
+        newlnk.suc = colmapping[oldlnk.suc] ;
+      } else {
+        newlnk.suc = NO_LINK ;
+      }
+      if (oldlnk.pre >= 0) {
+        newlnk.pre = colmapping[oldlnk.pre] ;
+      } else {
+        newlnk.pre = NO_LINK ;
+      }
+    }
+    delete [] clink ;
+    prob->clink_ = newclink ;
+
+    prob->ncols_ = n_compressed ;
+  }
+
+  delete [] colmapping ;
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_links_ok(prob,true,false) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  return (new drop_empty_cols_action(necols,actions,next)) ;
+}
+
+/*
+  The top-level method scans the matrix for empty columns and calls a worker
+  routine to do the heavy lifting.
+
+  NOTE: At the end of this routine, the column- and row-major representations
+	are not consistent. Empty columns have been compressed out,
+	effectively renumbering the columns.
+*/
+const CoinPresolveAction
+  *drop_empty_cols_action::presolve (CoinPresolveMatrix *prob,
+  				     const CoinPresolveAction *next)
+{
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Entering drop_empty_cols_action::presolve." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  const int *hincol = prob->hincol_ ;
+  int ncols = prob->ncols_ ;
+  int nempty = 0 ;
+  int *empty = new int [ncols] ;
+  CoinBigIndex nelems2 = 0 ;
+
+  // count empty cols
+  for (int i = 0 ; i < ncols ; i++) {
+    nelems2 += hincol[i] ;
+    if (hincol[i] == 0&&!prob->colProhibited2(i)) {
+#     if PRESOLVE_DEBUG > 1
+      if (nempty == 0)
+	std::cout << "UNUSED COLS:" ;
+      else
+      if (i < 100 && nempty%25 == 0)
+	std::cout << std::endl ;
+      else
+      if (i >= 100 && i < 1000 && nempty%19 == 0)
+	std::cout << std::endl ;
+      else
+      if (i >= 1000 && nempty%15 == 0)
+	std::cout << std::endl ;
+      std::cout << " " << i ;
+#     endif
+      empty[nempty++] = i;
+    }
+  }
+  prob->nelems_ = nelems2 ;
+
+  if (nempty)
+    next = drop_empty_cols_action::presolve(prob,empty,nempty,next) ;
+
+  delete [] empty ;
+
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  std::cout << "Leaving drop_empty_cols_action::presolve" ;
+  if (nempty) std::cout << ", dropped " << nempty << " columns" ;
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next);
+}
+
+
+/*
+  Reintroduce empty columns dropped at the end of presolve.
+*/
+void drop_empty_cols_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const int nactions = nactions_ ;
+  const action *const actions = actions_ ;
+
+  int ncols = prob->ncols_ ;
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering drop_empty_cols_action::postsolve, initial system "
+    << prob->nrows_ << "x" << ncols << ", " << nactions
+    << " columns to restore." << std::endl ;
+# endif
+  char *cdone	= prob->cdone_ ;
+
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  CoinBigIndex *colStarts = prob->mcstrt_ ;
+  int *colLengths = prob->hincol_ ;
+
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+
+  double *sol = prob->sol_ ;
+  double *cost = prob->cost_ ;
+  double *rcosts = prob->rcosts_ ;
+  unsigned char *colstat = prob->colstat_ ;
+  const double maxmin = prob->maxmin_ ;
+
+/*
+  Set up a mapping vector, coded 0 for existing columns, -1 for columns we're
+  about to reintroduce.
+*/
+  int ncols2 = ncols+nactions ;
+  int *colmapping = new int [ncols2] ;
+  CoinZeroN(colmapping,ncols2) ;
+  for (int ndx = 0 ; ndx < nactions ; ndx++) {
+    const action *e = &actions[ndx] ;
+    int j = e->jcol ;
+    colmapping[j] = -1 ;
+  }
+/*
+  Working back from the highest index, expand the existing ncols columns over
+  the full range ncols2, leaving holes for the columns we want to reintroduce.
+*/
+  for (int j = ncols2-1 ; j >= 0 ; j--) {
+    if (!colmapping[j]) {
+      ncols-- ;
+      colStarts[j] = colStarts[ncols] ;
+      colLengths[j] = colLengths[ncols] ;
+
+      clo[j]   = clo[ncols] ;
+      cup[j]   = cup[ncols] ;
+      cost[j] = cost[ncols] ;
+
+      if (sol) sol[j] = sol[ncols] ;
+      if (rcosts) rcosts[j] = rcosts[ncols] ;
+      if (colstat) colstat[j] = colstat[ncols] ;
+
+#     if PRESOLVE_DEBUG > 0
+      cdone[j] = cdone[ncols] ;
+#     endif
+    }
+  }
+  assert (!ncols) ;
+  
+  delete [] colmapping ;
+/*
+  Reintroduce the dropped columns.
+*/
+  for (int ndx = 0 ; ndx < nactions ; ndx++) {
+    const action *e = &actions[ndx] ;
+    int j = e->jcol ;
+    colLengths[j] = 0 ;
+    colStarts[j] = NO_LINK ;
+    clo[j] = e->clo ;
+    cup[j] = e->cup ;
+    cost[j] = e->cost ;
+
+    if (sol) sol[j] = e->sol ;
+    if (rcosts) rcosts[j] = maxmin*cost[j] ;
+    if (colstat) prob->setColumnStatusUsingValue(j) ;
+
+#   if PRESOLVE_DEBUG > 0
+    cdone[j] = DROP_COL ;
+#   if PRESOLVE_DEBUG > 1
+    std::cout
+      << "  restoring col " << j << ", lb = " << clo[j] << ", ub = " << cup[j]
+      << std::endl ;
+#   endif
+#   endif
+  }
+
+  prob->ncols_ += nactions ;
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving drop_empty_cols_action::postsolve, system "
+    << prob->nrows_ << "x" << prob->ncols_ << "." << std::endl ;
+# endif
+# endif
+
+}
+
+
+const CoinPresolveAction
+  *drop_empty_rows_action::presolve (CoinPresolveMatrix *prob,
+				     const CoinPresolveAction *next)
+{
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Entering drop_empty_rows_action::presolve." << std::endl ;
+# endif
+
+  int ncols	= prob->ncols_;
+  CoinBigIndex *mcstrt	= prob->mcstrt_;
+  int *hincol	= prob->hincol_;
+  int *hrow	= prob->hrow_;
+
+  int nrows	= prob->nrows_;
+  // This is done after row copy needed
+  //int *mrstrt	= prob->mrstrt_;
+  int *hinrow	= prob->hinrow_;
+  //int *hcol	= prob->hcol_;
+  
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  unsigned char *rowstat	= prob->rowstat_;
+  double *acts	= prob->acts_;
+  int * originalRow  = prob->originalRow_;
+
+  //presolvehlink *rlink = prob->rlink_;
+  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+  // Relax tolerance
+  double tolerance = 10.0*prob->feasibilityTolerance_;
+  
+
+  int i;
+  int nactions = 0;
+  for (i=0; i<nrows; i++)
+    if (hinrow[i] == 0)
+      nactions++;
+/*
+  Bail out if there's nothing to be done.
+*/
+  if (nactions == 0) {
+#   if PRESOLVE_DEBUG > 0
+    std::cout << "Leaving drop_empty_rows_action::presolve." << std::endl ;
+#   endif
+    return (next) ;
+  }
+/*
+  Work to do.
+*/
+  action *actions 	= new action[nactions];
+  int * rowmapping = new int [nrows];
+
+  nactions = 0;
+  int nrows2=0;
+  for (i=0; i<nrows; i++) {
+    if (hinrow[i] == 0) {
+      action &e = actions[nactions];
+
+#     if PRESOLVE_DEBUG > 1
+      if (nactions == 0)
+        std::cout << "UNUSED ROWS:" ;
+      else
+      if (i < 100 && nactions%25 == 0)
+        std::cout << std::endl ;
+      else
+      if (i >= 100 && i < 1000 && nactions%19 == 0)
+        std::cout << std::endl ;
+      else
+      if (i >= 1000 && nactions%15 == 0)
+        std::cout << std::endl ;
+      std::cout << " " << i ;
+#     endif
+
+      nactions++;
+      if (rlo[i] > 0.0 || rup[i] < 0.0) {
+	if ((rlo[i]<=tolerance &&
+	     rup[i]>=-tolerance)||fixInfeasibility) {
+	  rlo[i]=0.0;
+	  rup[i]=0.0;
+	} else {
+	  prob->status_|= 1;
+	prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
+					   prob->messages())
+					     <<i
+					     <<rlo[i]
+					     <<rup[i]
+					     <<CoinMessageEol;
+	  break;
+	}
+      }
+      e.row	= i;
+      e.rlo	= rlo[i];
+      e.rup	= rup[i];
+      rowmapping[i]=-1;
+
+    } else {
+      // move down - we want to preserve order
+      rlo[nrows2]=rlo[i];
+      rup[nrows2]=rup[i];
+      originalRow[nrows2]=i;
+      if (acts) {
+	acts[nrows2]=acts[i];
+	rowstat[nrows2]=rowstat[i];
+      }
+      rowmapping[i]=nrows2++;
+    }
+  }
+# if PRESOLVE_DEBUG > 1
+  std::cout << std::endl ;
+# endif
+
+  // remap matrix
+  for (i=0;i<ncols;i++) {
+    int j;
+    for (j=mcstrt[i];j<mcstrt[i]+hincol[i];j++) 
+      hrow[j] = rowmapping[hrow[j]];
+  }
+  delete [] rowmapping;
+
+  prob->nrows_ = nrows2;
+
+  next = new drop_empty_rows_action(nactions,actions,next) ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving drop_empty_rows_action::presolve" ;
+  if (nactions) std::cout << ", dropped " << nactions << " rows" ;
+  std::cout << "." << std::endl ;
+# endif
+# endif
+
+  return (next) ;
+}
+
+void drop_empty_rows_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const int nactions = nactions_ ;
+  const action *const actions = actions_ ;
+
+  int ncols = prob->ncols_ ;
+  int nrows0 = prob->nrows0_ ;
+  int nrows = prob->nrows_ ;
+
+  CoinBigIndex *mcstrt	= prob->mcstrt_ ;
+  int *hincol = prob->hincol_ ;
+
+  int *hrow = prob->hrow_ ;
+
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+  unsigned char *rowstat = prob->rowstat_ ;
+  double *rowduals = prob->rowduals_ ;
+  double *acts = prob->acts_ ;
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering drop_empty_rows_action::postsolve, initial system "
+    << nrows << "x" << ncols << ", " << nactions
+    << " rows to restore." << std::endl ;
+# endif
+  char *rdone = prob->rdone_ ;
+
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+/*
+  Process the array of actions and mark rowmapping[i] if constraint i was
+  eliminated in presolve.
+*/
+  int *rowmapping = new int [nrows0] ;
+  CoinZeroN(rowmapping,nrows0) ;
+  for (int k = 0 ; k < nactions ; k++) {
+    const action *e = &actions[k] ;
+    int i = e->row ;
+    rowmapping[i] = -1 ;
+  }
+/*
+  Now walk the vectors for row bounds, activity, duals, and status. Expand
+  the existing entries in 0..(nrows-1) to occupy 0..(nrows0-1), leaving
+  holes for the rows we're about to reintroduce.
+*/
+  for (int i = nrows0-1 ; i >= 0 ; i--) {
+    if (!rowmapping[i]) {
+      nrows-- ;
+      rlo[i] = rlo[nrows] ;
+      rup[i] = rup[nrows] ;
+      acts[i] = acts[nrows] ;
+      rowduals[i] = rowduals[nrows] ;
+      if (rowstat)
+	rowstat[i] = rowstat[nrows] ;
+#     if PRESOLVE_DEBUG > 0
+      rdone[i] = rdone[nrows] ;
+#     endif
+    }
+  }
+  assert (!nrows) ;
+/*
+  Rewrite rowmapping so that it maps presolved row indices to row indices in
+  the restored matrix.
+*/
+  for (int i = 0 ; i < nrows0 ; i++) {
+    if (!rowmapping[i])
+      rowmapping[nrows++] = i ;
+  }
+/*
+  Now walk the row index array for each column, rewriting the row indices so
+  they are correct for the restored matrix.
+*/
+  for (int j = 0 ; j < ncols ; j++) {
+    const CoinBigIndex &start = mcstrt[j] ;
+    const CoinBigIndex &end = start+hincol[j] ;
+    for (CoinBigIndex k = start ; k < end ; k++) {
+      hrow[k] = rowmapping[hrow[k]] ;
+    }
+  }
+  delete [] rowmapping;
+/*
+  And reintroduce the (still empty) rows that were removed in presolve. The
+  assumption is that an empty row cannot be tight, hence the logical is basic
+  and the dual is zero.
+*/
+  for (int k = 0 ; k < nactions ; k++) {
+    const action *e = &actions[k] ;
+    int i = e->row ;
+    rlo[i] = e->rlo ;
+    rup[i] = e->rup ;
+    acts[i] = 0.0 ;
+    if (rowstat)
+      prob->setRowStatus(i,CoinPrePostsolveMatrix::basic) ;
+    rowduals[i] = 0.0 ;
+#   if PRESOLVE_DEBUG > 0
+    rdone[i] = DROP_ROW;
+#   if PRESOLVE_DEBUG > 1
+    std::cout
+      << "  restoring row " << i << ", LB = " << rlo[i] << ", UB = " << rup[i]
+      << std::endl ;
+#   endif
+#   endif
+  }
+  prob->nrows_ += nactions ;
+  assert(prob->nrows_ == prob->nrows0_) ;
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving drop_empty_rows_action::postsolve, system "
+    << prob->nrows_ << "x" << prob->ncols_ << "." << std::endl ;
+# endif
+# endif
+
+}
+
diff --git a/cbits/coin/CoinPresolveEmpty.hpp b/cbits/coin/CoinPresolveEmpty.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveEmpty.hpp
@@ -0,0 +1,116 @@
+/* $Id: CoinPresolveEmpty.hpp 1561 2012-11-24 00:32:16Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveEmpty_H
+#define CoinPresolveEmpty_H
+
+/*! \file
+
+  Drop/reinsert empty rows/columns.
+*/
+
+const int DROP_ROW = 3;
+const int DROP_COL = 4;
+
+/*! \class drop_empty_cols_action
+    \brief Physically removes empty columns in presolve, and reinserts
+	   empty columns in postsolve.
+
+  Physical removal of rows and columns should be the last activities
+  performed during presolve. Do them exactly once. The row-major matrix
+  is <b>not</b> maintained by this transform.
+
+  To physically drop the columns, CoinPrePostsolveMatrix::mcstrt_ and
+  CoinPrePostsolveMatrix::hincol_ are compressed, along with column bounds,
+  objective, and (if present) the column portions of the solution. This
+  renumbers the columns. drop_empty_cols_action::presolve will reconstruct
+  CoinPresolveMatrix::clink_.
+
+  \todo Confirm correct behaviour with solution in presolve.
+*/
+
+class drop_empty_cols_action : public CoinPresolveAction {
+private:
+  const int nactions_;
+
+  struct action {
+    double clo;
+    double cup;
+    double cost;
+    double sol;
+    int jcol;
+  };
+  const action *const actions_;
+
+  drop_empty_cols_action(int nactions,
+			 const action *const actions,
+			 const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), 
+    actions_(actions)
+  {}
+
+ public:
+  const char *name() const { return ("drop_empty_cols_action"); }
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *,
+					 const int *ecols,
+					 int necols,
+					 const CoinPresolveAction*);
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~drop_empty_cols_action() { deleteAction(actions_,action*); }
+};
+
+
+/*! \class drop_empty_rows_action
+    \brief Physically removes empty rows in presolve, and reinserts
+	   empty rows in postsolve.
+
+  Physical removal of rows and columns should be the last activities
+  performed during presolve. Do them exactly once. The row-major matrix
+  is <b>not</b> maintained by this transform.
+
+  To physically drop the rows, the rows are renumbered, excluding empty
+  rows. This involves rewriting CoinPrePostsolveMatrix::hrow_ and compressing
+  the row bounds and (if present) the row portions of the solution.
+
+  \todo Confirm behaviour when a solution is present in presolve.
+*/
+class drop_empty_rows_action : public CoinPresolveAction {
+private:
+  struct action {
+    double rlo;
+    double rup;
+    int row;
+    int fill_row;	// which row was moved into position row to fill it
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  drop_empty_rows_action(int nactions,
+			 const action *actions,
+			 const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions)
+{}
+
+ public:
+  const char *name() const { return ("drop_empty_rows_action"); }
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					    const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~drop_empty_rows_action() { deleteAction(actions_,action*); }
+};
+#endif
+
diff --git a/cbits/coin/CoinPresolveFixed.cpp b/cbits/coin/CoinPresolveFixed.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveFixed.cpp
@@ -0,0 +1,869 @@
+/* $Id: CoinPresolveFixed.cpp 1565 2012-11-29 19:32:14Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinFinite.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+/* Begin routines associated with remove_fixed_action */
+
+const char *remove_fixed_action::name() const
+{
+  return ("remove_fixed_action");
+}
+
+/*
+ * Original comment:
+ *
+ * invariant:  both reps are loosely packed.
+ * coefficients of both reps remain consistent.
+ *
+ * Note that this concerns variables whose column bounds determine that
+ * they are slack; this does NOT concern singleton row constraints that
+ * determine that the relevant variable is slack.
+ *
+ * Invariant:  col and row rep are consistent
+ */
+
+/*
+  This routine empties the columns for the list of fixed variables passed in
+  (fcols, nfcols). As each coefficient a<ij> is set to 0, rlo<i> and rup<i>
+  are adjusted accordingly. Note, however, that c<j> is not considered to be
+  removed from the objective until column j is physically removed from the
+  matrix (drop_empty_cols_action), so the correction to the objective is
+  adjusted there.
+
+  If a column solution is available, row activity (acts_) is adjusted.
+  remove_fixed_action implicitly assumes that the value of the variable has
+  already been forced within bounds. If this isn't true, the correction to
+  acts_ will be wrong. See make_fixed_action if you need to force the value
+  within bounds first.
+*/
+const remove_fixed_action*
+  remove_fixed_action::presolve (CoinPresolveMatrix *prob,
+				 int *fcols, int nfcols,
+				 const CoinPresolveAction *next)
+{
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt	= prob->mcstrt_;
+  int *hincol		= prob->hincol_;
+
+  double *rowels	= prob->rowels_;
+  int *hcol		= prob->hcol_;
+  CoinBigIndex *mrstrt	= prob->mrstrt_;
+  int *hinrow		= prob->hinrow_;
+
+  double *clo	= prob->clo_;
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+  double *sol	= prob->sol_;
+  double *acts	= prob->acts_;
+
+  presolvehlink *clink = prob->clink_;
+  presolvehlink *rlink = prob->rlink_;
+
+  action *actions 	= new  action[nfcols+1];
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering remove_fixed_action::presolve; processing " << nfcols
+    << " fixed columns." << std::endl ;
+# endif
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+/*
+  Scan columns to be removed and total up the number of coefficients.
+*/
+  int estsize=0;
+  int ckc;
+  for (ckc = 0 ; ckc < nfcols ; ckc++) {
+    int j = fcols[ckc];
+    estsize += hincol[j];
+  }
+// Allocate arrays to hold coefficients and associated row indices
+  double * els_action = new double[estsize];
+  int * rows_action = new int[estsize];
+  int actsize=0;
+  // faster to do all deletes in row copy at once
+  int nrows		= prob->nrows_;
+  CoinBigIndex * rstrt = new int[nrows+1];
+  CoinZeroN(rstrt,nrows);
+
+/*
+  Open a loop to excise each column a<j>. The first thing to do is load the
+  action entry with the index j, the value of x<j>, and the number of
+  entries in a<j>. After we walk the column and tweak the row-major
+  representation, we'll simply claim this column is empty by setting
+  hincol[j] = 0.
+*/
+  for (ckc = 0 ; ckc < nfcols ; ckc++) {
+    int j = fcols[ckc];
+    double solj = clo[j];
+    CoinBigIndex kcs = mcstrt[j];
+    CoinBigIndex kce = kcs + hincol[j];
+    CoinBigIndex k;
+
+    { action &f = actions[ckc];
+      f.col = j;
+      f.sol = solj;
+      f.start = actsize;
+    }
+/*
+  Now walk a<j>. For each row i with a coefficient a<ij> != 0:
+    * save the coefficient and row index,
+    * substitute the value of x<j>, adjusting the row bounds and lhs value
+      accordingly, then
+    * delete a<ij> from the row-major representation.
+    * Finally: mark the row as changed and add it to the list of rows to be
+	processed next. Then, for each remaining column in the row, put it on
+	the list of columns to be processed.
+*/
+    for (k = kcs ; k < kce ; k++) {
+      int row = hrow[k];
+      double coeff = colels[k];
+     
+      els_action[actsize]=coeff;
+      rstrt[row]++; // increase counts
+      rows_action[actsize++]=row;
+
+      // Avoid reducing finite infinity.
+      if (-PRESOLVE_INF < rlo[row])
+	rlo[row] -= solj*coeff;
+      if (rup[row] < PRESOLVE_INF)
+	rup[row] -= solj*coeff;
+      if (sol) {
+	acts[row] -= solj*coeff;
+      }
+#define TRY2
+#ifndef TRY2
+      presolve_delete_from_row(row,j,mrstrt,hinrow,hcol,rowels);
+      if (hinrow[row] == 0)
+      { PRESOLVE_REMOVE_LINK(rlink,row) ; }
+
+      // mark unless already marked
+      if (!prob->rowChanged(row)) {
+	prob->addRow(row);
+	CoinBigIndex krs = mrstrt[row];
+	CoinBigIndex kre = krs + hinrow[row];
+	for (CoinBigIndex k=krs; k<kre; k++) {
+	  int jcol = hcol[k];
+	  prob->addCol(jcol);
+	}
+      }
+#endif
+    }
+/*
+  Remove the column's link from the linked list of columns, and declare
+  it empty in the column-major representation. Link removal must execute
+  even if the column is already of length 0 when it arrives.
+*/
+    PRESOLVE_REMOVE_LINK(clink, j);
+    hincol[j] = 0;
+  }
+/*
+  Set the actual end of the coefficient and row index arrays.
+*/
+  actions[nfcols].start=actsize;
+# if PRESOLVE_SUMMARY
+  printf("NFIXED:  %d", nfcols);
+  if (estsize-actsize > 0)
+  { printf(", overalloc %d",estsize-actsize) ; }
+  printf("\n") ;
+# endif
+  // Now get columns by row
+  int * column = new int[actsize];
+  int nel=0;
+  int iRow;
+  for (iRow=0;iRow<nrows;iRow++) {
+    int n=rstrt[iRow];
+    rstrt[iRow]=nel;
+    nel += n;
+  }
+  rstrt[nrows]=nel;
+  for (ckc = 0 ; ckc < nfcols ; ckc++) {
+    int kcs = actions[ckc].start;
+    int j=actions[ckc].col;
+    int kce;
+    if (ckc<nfcols-1)
+      kce = actions[ckc+1].start;
+    else
+      kce = actsize;
+    for (int k=kcs;k<kce;k++) {
+      int iRow = rows_action[k];
+      CoinBigIndex put = rstrt[iRow];
+      rstrt[iRow]++;
+      column[put]=j;
+    }
+  }
+  // Now do rows
+  int ncols		= prob->ncols_;
+  char * mark = new char[ncols];
+  memset(mark,0,ncols);
+  // rstrts are now one out i.e. rstrt[0] is end of row 0
+  nel=0;
+#ifdef TRY2
+  for (iRow=0;iRow<nrows;iRow++) {
+    int k;
+    for (k=nel;k<rstrt[iRow];k++) {
+      mark[column[k]]=1;
+    }
+    presolve_delete_many_from_major(iRow,mark,mrstrt,hinrow,hcol,rowels);
+#if PRESOLVE_DEBUG > 0
+    for (k = nel ; k < rstrt[iRow] ; k++) {
+      assert(mark[column[k]] == 0) ;
+    }
+#endif
+    if (hinrow[iRow] == 0)
+      {
+        PRESOLVE_REMOVE_LINK(rlink,iRow) ;
+      }
+    // mark unless already marked
+    if (!prob->rowChanged(iRow)) {
+      prob->addRow(iRow);
+      CoinBigIndex krs = mrstrt[iRow];
+      CoinBigIndex kre = krs + hinrow[iRow];
+      for (CoinBigIndex k=krs; k<kre; k++) {
+        int jcol = hcol[k];
+        prob->addCol(jcol);
+      }
+    }
+    nel=rstrt[iRow];
+  }
+#endif
+  delete [] mark;
+  delete [] column;
+  delete [] rstrt;
+
+/*
+  Create the postsolve object, link it at the head of the list of postsolve
+  objects, and return a pointer.
+*/
+  const remove_fixed_action *fixedActions =
+      new remove_fixed_action(nfcols,actions,els_action,rows_action,next) ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_sol(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving remove_fixed_action::presolve." << std::endl ;
+# endif
+# endif
+
+  return (fixedActions) ;
+}
+
+
+remove_fixed_action::remove_fixed_action(int nactions,
+					 action *actions,
+					 double * els_action,
+					 int * rows_action,
+					 const CoinPresolveAction *next) :
+  CoinPresolveAction(next),
+  colrows_(rows_action),
+  colels_(els_action),
+  nactions_(nactions),
+  actions_(actions)
+{
+}
+
+remove_fixed_action::~remove_fixed_action()
+{
+  deleteAction(actions_,action*);
+  delete [] colels_;
+  delete [] colrows_;
+}
+
+/*
+ * Say we determined that cup - clo <= ztolzb, so we fixed sol at clo.
+ * This involved subtracting clo*coeff from ub/lb for each row the
+ * variable occurred in.
+ * Now when we put the variable back in, by construction the variable
+ * is within tolerance, the non-slacks are unchanged, and the 
+ * distances of the affected slacks from their bounds should remain
+ * unchanged (ignoring roundoff errors).
+ * It may be that by adding the term back in, the affected constraints
+ * now aren't as accurate due to round-off errors; this could happen
+ * if only one summand and the slack in the original formulation were large
+ * (and naturally had opposite signs), and the new term in the constraint
+ * is about the size of the old slack, so the new slack becomes about 0.
+ * It may be that there is catastrophic cancellation in the summation,
+ * so it might not compute to 0.
+ */
+void remove_fixed_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  action * actions	= actions_;
+  const int nactions	= nactions_;
+
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt	= prob->mcstrt_;
+  int *hincol		= prob->hincol_;
+  int *link		= prob->link_;
+  CoinBigIndex &free_list = prob->free_list_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  double *sol	= prob->sol_;
+  double *dcost	= prob->cost_;
+  double *rcosts	= prob->rcosts_;
+
+  double *acts	= prob->acts_;
+  double *rowduals = prob->rowduals_;
+
+  unsigned char *colstat	= prob->colstat_;
+
+  const double maxmin	= prob->maxmin_;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  char *cdone	= prob->cdone_;
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering remove_fixed_action::postsolve, repopulating " << nactions
+    << " columns." << std::endl ;
+# endif
+  presolve_check_threads(prob) ;
+  presolve_check_free_list(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  double * els_action = colels_;
+  int * rows_action = colrows_;
+  int end = actions[nactions].start;
+
+/*
+  At one point, it turned out that forcing_constraint_action was putting
+  duplicates in the column list it passed to remove_fixed_action. This is now
+  fixed, but ... it looks to me like we could be in trouble here if we
+  reinstate a column multiple times. Hence the assert.
+*/
+  for (const action *f = &actions[nactions-1]; actions<=f; f--) {
+    int icol = f->col;
+    const double thesol = f->sol;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+    if (cdone[icol] == FIXED_VARIABLE) {
+      std::cout
+        << "RFA::postsolve: column " << icol << " already unfixed!"
+	<< std::endl ;
+      assert(cdone[icol] != FIXED_VARIABLE) ;
+    }
+    cdone[icol] = FIXED_VARIABLE ;
+# endif
+
+    sol[icol] = thesol;
+    clo[icol] = thesol;
+    cup[icol] = thesol;
+
+    int cs = NO_LINK ;
+    int start = f->start;
+    double dj = maxmin * dcost[icol];
+    
+    for (int i=start; i<end; ++i) {
+      int row = rows_action[i];
+      double coeff =els_action[i];
+      
+      // pop free_list
+      CoinBigIndex k = free_list;
+      assert(k >= 0 && k < prob->bulk0_) ;
+      free_list = link[free_list];
+      // restore
+      hrow[k] = row;
+      colels[k] = coeff;
+      link[k] = cs;
+      cs = k;
+
+      if (-PRESOLVE_INF < rlo[row])
+	rlo[row] += coeff * thesol;
+      if (rup[row] < PRESOLVE_INF)
+	rup[row] += coeff * thesol;
+      acts[row] += coeff * thesol;
+      
+      dj -= rowduals[row] * coeff;
+    }
+
+#   if PRESOLVE_CONSISTENCY > 0
+    presolve_check_free_list(prob) ;
+#   endif
+      
+    mcstrt[icol] = cs;
+    
+    rcosts[icol] = dj;
+    hincol[icol] = end-start;
+    end=start;
+
+    /* Original comment:
+     * the bounds in the reduced problem were tightened.
+     * that means that this variable may not have been basic
+     * because it didn't have to be,
+     * but now it may have to.
+     * no - the bounds aren't changed by this operation
+     */
+/*
+  We've reintroduced the variable, but it's still fixed (equal bounds).
+  Pick the nonbasic status that agrees with the reduced cost. Later, if
+  postsolve unfixes the variable, we'll need to confirm that this status is
+  still viable. We live in a minimisation world here.
+*/
+    if (colstat)
+    { if (dj < 0)
+	prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atUpperBound);
+      else
+	prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atLowerBound); }
+
+  }
+
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving remove_fixed_action::postsolve." << std::endl ;
+# endif
+# endif
+
+  return ;
+}
+
+/*
+  Scan the problem for variables that are already fixed, and remove them.
+  There's an implicit assumption that the value of the variable is already
+  within bounds. If you want to protect against this possibility, you want to
+  use make_fixed.
+*/
+const CoinPresolveAction *remove_fixed (CoinPresolveMatrix *prob,
+					const CoinPresolveAction *next)
+{
+  int ncols	= prob->ncols_;
+  int *fcols	= new int[ncols];
+  int nfcols	= 0;
+
+  int *hincol		= prob->hincol_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+
+  for (int i = 0 ; i < ncols ; i++)
+    if (hincol[i] > 0 && clo[i] == cup[i]&&!prob->colProhibited2(i))
+      fcols[nfcols++] = i;
+
+  if (nfcols > 0)
+  { next = remove_fixed_action::presolve(prob, fcols, nfcols, next) ; }
+  delete[]fcols;
+  return (next);
+}
+
+/* End routines associated with remove_fixed_action */
+
+/* Begin routines associated with make_fixed_action */
+
+const char *make_fixed_action::name() const
+{
+  return ("make_fixed_action");
+}
+
+
+/*
+  This routine does the actual job of fixing one or more variables. The set
+  of indices to be fixed is specified by nfcols and fcols. fix_to_lower
+  specifies the bound where the variable(s) should be fixed. The other bound
+  is preserved as part of the action and the bounds are set equal. Note that
+  you don't get to specify the bound on a per-variable basis.
+
+  If a primal solution is available, make_fixed_action will adjust the the
+  row activity to compensate for forcing the variable within bounds. If the
+  bounds are already equal, and the variable is within bounds, you should
+  consider remove_fixed_action.
+*/
+const CoinPresolveAction*
+make_fixed_action::presolve (CoinPresolveMatrix *prob,
+			     int *fcols, int nfcols,
+			     bool fix_to_lower,
+			     const CoinPresolveAction *next)
+
+{ double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+  double *csol	= prob->sol_;
+
+  double *colels = prob->colels_;
+  int *hrow	= prob->hrow_;
+  CoinBigIndex *mcstrt	= prob->mcstrt_;
+  int *hincol	= prob->hincol_;
+
+  double *acts	= prob->acts_;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering make_fixed_action::presolve, fixed = " << nfcols << "."
+    << std::endl ;
+# endif
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+/*
+  Shouldn't happen, but ...
+*/
+  if (nfcols <= 0) {
+#   if PRESOLVE_DEBUG > 0
+    std::cout
+      << "make_fixed_action::presolve: useless call, " << nfcols
+      << " to fix." << std::endl ;
+#   endif
+    return (next) ;
+  }
+
+  action *actions = new action[nfcols] ;
+
+/*
+  Scan the set of indices specifying variables to be fixed. For each variable,
+  stash the unused bound in the action and set the bounds equal. If the client
+  has passed in a primal solution, update it if the value of the variable
+  changes.
+*/
+  for (int ckc = 0 ; ckc < nfcols ; ckc++)
+  { int j = fcols[ckc] ;
+    double movement = 0 ;
+
+    action &f = actions[ckc] ;
+
+    f.col = j ;
+    if (fix_to_lower) {
+      f.bound = cup[j];
+      cup[j] = clo[j];
+      if (csol) {
+	movement = clo[j]-csol[j] ;
+	csol[j] = clo[j] ;
+      }
+    } else {
+      f.bound = clo[j];
+      clo[j] = cup[j];
+      if (csol) {
+	movement = cup[j]-csol[j];
+	csol[j] = cup[j];
+      }
+    }
+    if (movement) {
+      CoinBigIndex k;
+      for (k = mcstrt[j] ; k < mcstrt[j]+hincol[j] ; k++) {
+	int row = hrow[k];
+	acts[row] += movement*colels[k];
+      }
+    }
+  }
+/*
+  Original comment:
+  This is unusual in that the make_fixed_action transform contains within it
+  a remove_fixed_action transform. Bad idea?
+
+  Explanatory comment:
+  Now that we've adjusted the bounds, time to create the postsolve action
+  that will restore the original bounds. But wait! We're not done. By calling
+  remove_fixed_action::presolve, we will (virtually) remove these variables
+  from the model by substituting for the variable where it occurs and emptying
+  the column. Cache the postsolve transform that will repopulate the column
+  inside the postsolve transform for fixing the bounds.
+*/
+  if (nfcols > 0) {
+    next = new make_fixed_action(nfcols,actions,fix_to_lower,
+			   remove_fixed_action::presolve(prob,fcols,nfcols,0),
+				 next) ;
+  }
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving make_fixed_action::presolve." << std::endl ;
+# endif
+# endif
+
+  return (next) ;
+}
+
+/*
+  Recall that in presolve, make_fixed_action forced a bound to fix a variable,
+  then called remove_fixed_action to empty the column. removed_fixed_action
+  left a postsolve object hanging off faction_, and our first act here is to
+  call r_f_a::postsolve to repopulate the columns. The m_f_a postsolve activity
+  consists of relaxing one of the bounds and making sure that the status is
+  still viable (we can potentially eliminate the bound here).
+*/
+void make_fixed_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_;
+  const int nactions = nactions_;
+  const bool fix_to_lower = fix_to_lower_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+  double *sol	= prob->sol_ ;
+  unsigned char *colstat = prob->colstat_;
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Entering make_fixed_action::postsolve." << std::endl ;
+# endif
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+/*
+  Repopulate the columns.
+*/
+  assert(nactions == faction_->nactions_) ;
+  faction_->postsolve(prob);
+/*
+  Walk the actions: restore each bound and check that the status is still
+  appropriate. Given that we're unfixing a fixed variable, it's safe to assume
+  that the unaffected bound is finite.
+*/
+  for (int cnt = nactions-1 ; cnt >= 0 ; cnt--)
+  { const action *f = &actions[cnt];
+    int icol = f->col;
+    double xj = sol[icol] ;
+
+    assert(faction_->actions_[cnt].col == icol) ;
+
+    if (fix_to_lower)
+    { double ub = f->bound ;
+      cup[icol] = ub ;
+      if (colstat)
+      { if (ub >= PRESOLVE_INF || xj != ub)
+	{ prob->setColumnStatus(icol,
+				CoinPrePostsolveMatrix::atLowerBound) ; } } }
+    else
+    { double lb = f->bound ;
+      clo[icol] = lb ;
+      if (colstat)
+      { if (lb <= -PRESOLVE_INF || xj != lb)
+	{ prob->setColumnStatus(icol,
+				CoinPrePostsolveMatrix::atUpperBound) ; } } } }
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+  std::cout << "Leaving make_fixed_action::postsolve." << std::endl ;
+# endif
+  return ; }
+
+/*
+  Scan the columns and collect indices of columns that have upper and lower
+  bounds within the zero tolerance of one another. Hand this list to
+  make_fixed_action::presolve() to do the heavy lifting.
+
+  make_fixed_action will compensate for variables which are infeasible, forcing
+  them to feasibility and correcting the row activity, before invoking
+  remove_fixed_action to remove the variable from the problem. If you're
+  confident of feasibility, consider remove_fixed.
+*/
+const CoinPresolveAction *make_fixed (CoinPresolveMatrix *prob,
+				      const CoinPresolveAction *next)
+{
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering make_fixed, checking " << prob->ncols_ << " columns."
+    << std::endl ;
+# endif
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  int ncols = prob->ncols_ ;
+  int *fcols = prob->usefulColumnInt_ ;
+  int nfcols = 0 ;
+
+  int *hincol = prob->hincol_ ;
+
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+
+  for (int i = 0 ; i < ncols ; i++)
+  { if (hincol[i] > 0 &&
+	fabs(cup[i]-clo[i]) < ZTOLDP && !prob->colProhibited2(i)) 
+    { fcols[nfcols++] = i ; } }
+
+/*
+  Call m_f_a::presolve to do the heavy lifting. This will create a new
+  CoinPresolveAction, which will become the head of the list of
+  CoinPresolveAction's currently pointed to by next.
+
+  No point in going through the effort of a call if there are no fixed
+  variables.
+*/
+  if (nfcols > 0)
+    next = make_fixed_action::presolve(prob,fcols,nfcols,true,next) ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Leaving make_fixed, fixed " << nfcols << " columns." << std::endl ;
+# endif
+# endif
+
+  return (next) ; }
+
+/*
+  Transfer the cost coefficient of a column singleton in an equality to the
+  cost coefficients of the remaining variables. Suppose x<s> is the singleton
+  and x<t> is some other variable. For movement delta<t>, there must be
+  compensating change delta<s> = -(a<it>/a<is>)delta<t>. Substituting in the
+  objective, c<s>delta<s> + c<t>delta<t> becomes
+    c<s>(-a<it>/a<is>)delta<t> + c<t>delta<t>
+    (c<t> - c<s>(a<it>/a<is>))delta<t>
+  This is transform (A) below.
+*/
+void transferCosts (CoinPresolveMatrix *prob)
+{
+  double *colels = prob->colels_ ;
+  int *hrow = prob->hrow_ ;
+  CoinBigIndex *mcstrt = prob->mcstrt_ ;
+  int *hincol = prob->hincol_ ;
+
+  double *rowels = prob->rowels_ ;
+  int *hcol = prob->hcol_ ;
+  CoinBigIndex *mrstrt = prob->mrstrt_ ;
+  int *hinrow = prob->hinrow_ ;
+
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+  int ncols = prob->ncols_ ;
+  double *cost	= prob->cost_ ; 
+  unsigned char *integerType = prob->integerType_ ;
+  double bias = prob->dobias_ ;
+
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Entering transferCosts." << std::endl ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  int numberIntegers = 0 ;
+  for (int icol = 0 ; icol < ncols ; icol++) {
+    if (integerType[icol]) numberIntegers++ ;
+  }
+/*
+  For unfixed column singletons in equalities, calculate and install transform
+  (A) described in the comments at the head of the method.
+*/
+  int nchanged = 0 ;
+  for (int js = 0 ; js < ncols ; js++) {
+    if (cost[js] && hincol[js] == 1 && cup[js] > clo[js]) {
+      const CoinBigIndex &jsstrt = mcstrt[js] ;
+      const int &i = hrow[jsstrt];
+      if (rlo[i] == rup[i]) {
+        const double ratio = cost[js]/colels[jsstrt];
+        bias += rlo[i]*ratio ;
+	const CoinBigIndex &istrt = mrstrt[i] ;
+	const CoinBigIndex iend = istrt+hinrow[i] ;
+        for (CoinBigIndex jj = istrt ; jj < iend ; jj++) {
+          int j = hcol[jj] ;
+          double aij = rowels[jj] ;
+          cost[j] -= ratio*aij ;
+        }
+        cost[js] = 0.0 ;
+        nchanged++ ;
+      }
+    }
+  }
+# if PRESOLVE_DEBUG > 0
+  if (nchanged)
+    std::cout
+      << "  transferred costs for " << nchanged << " singleton columns."
+      << std::endl ;
+
+  int nPasses = 0 ;
+# endif
+/*
+  We don't really need a singleton column to do this trick, just an equality.
+  But if the column's not a singleton, it's only worth doing if we can move
+  costs onto integer variables that start with costs of zero. Try and find some
+  unfixed variable with a nonzero cost, that's involved in an equality where
+  there are integer variables with costs of zero. If there's a net gain in the
+  number of integer variables with costs (nThen > nNow), do the transform.
+  One per column, please.
+*/
+  if (numberIntegers) {
+    int changed = -1 ;
+    while (changed) {
+      changed = 0 ;
+      for (int js = 0 ; js < ncols ; js++) {
+        if (cost[js] && cup[js] > clo[js]) {
+	  const CoinBigIndex &jsstrt = mcstrt[js] ;
+	  const CoinBigIndex jsend = jsstrt+hincol[js] ;
+          for (CoinBigIndex ii = jsstrt ; ii < jsend ; ii++) {
+            const int &i = hrow[ii] ;
+            if (rlo[i] == rup[i]) {
+              int nNow = ((integerType[js])?1:0) ;
+              int nThen = 0 ;
+	      const CoinBigIndex &istrt = mrstrt[i] ;
+	      const CoinBigIndex iend = istrt+hinrow[i] ;
+              for (CoinBigIndex jj = istrt ; jj < iend ; jj++) {
+                int j = hcol[jj] ;
+                if (!cost[j] && integerType[j]) nThen++ ;
+              }
+              if (nThen > nNow) {
+                const double ratio = cost[js]/colels[jsstrt] ;
+                bias += rlo[i]*ratio ;
+                for (CoinBigIndex jj = istrt ; jj < iend ; jj++) {
+                  int j = hcol[jj] ;
+                  double aij = rowels[jj] ;
+                  cost[j] -= ratio*aij ;
+                }
+                cost[js] = 0.0 ;
+                changed++ ;
+                break ;
+              }
+            }
+          }
+        }
+      }
+      if (changed) {
+        nchanged += changed ;
+#	if PRESOLVE_DEBUG > 0
+	std::cout
+	  << "    pass " << nPasses++ << " transferred costs to "
+	  << changed << " integer variables." << std::endl ;
+#       endif
+      }
+    }
+  }
+# if PRESOLVE_DEBUG > 0
+  if (bias != prob->dobias_)
+    std::cout << "  new bias " << bias << "." << std::endl ;
+# endif
+  prob->dobias_ = bias;
+
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving transferCosts." << std::endl ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+}
+
+
diff --git a/cbits/coin/CoinPresolveFixed.hpp b/cbits/coin/CoinPresolveFixed.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveFixed.hpp
@@ -0,0 +1,181 @@
+/* $Id: CoinPresolveFixed.hpp 1510 2011-12-08 23:56:01Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveFixed_H
+#define CoinPresolveFixed_H
+#define	FIXED_VARIABLE	1
+
+/*! \class remove_fixed_action
+    \brief Excise fixed variables from the model.
+
+  Implements the action of virtually removing one or more fixed variables
+  x_j from the model by substituting the value sol_j in each constraint.
+  Specifically, for each constraint i where a_ij != 0, rlo_i and rup_i
+  are adjusted by -a_ij*sol_j and a_ij is set to 0.
+
+  There is an implicit assumption that the variable already has the correct
+  value. If this isn't true, corrections to row activity may be incorrect.
+  If you want to guard against this possibility, consider make_fixed_action.
+
+  Actual removal of the empty column from the matrix is handled by
+  drop_empty_cols_action. Correction of the objective function is done there.
+*/
+class remove_fixed_action : public CoinPresolveAction {
+ public:
+  /*! \brief Structure to hold information necessary to reintroduce a
+	     column into the problem representation.
+  */
+  struct action {
+    int col;		///< column index of variable
+    int start;		///< start of coefficients in #colels_ and #colrows_
+    double sol;		///< value of variable
+  };
+  /// Array of row indices for coefficients of excised columns
+  int *colrows_;
+  /// Array of coefficients of excised columns
+  double *colels_;
+  /// Number of entries in #actions_
+  int nactions_;
+  /// Vector specifying variable(s) affected by this object
+  action *actions_;
+
+ private:
+  /*! \brief Constructor */
+  remove_fixed_action(int nactions,
+		      action *actions,
+		      double * colels,
+		      int * colrows,
+		      const CoinPresolveAction *next);
+
+ public:
+  /// Returns string "remove_fixed_action".
+  const char *name() const;
+
+  /*! \brief Excise the specified columns.
+
+    Remove the specified columns (\p nfcols, \p fcols) from the problem
+    representation (\p prob), leaving the appropriate postsolve object
+    linked as the head of the list of postsolve objects (currently headed
+    by \p next).
+  */
+  static const remove_fixed_action *presolve(CoinPresolveMatrix *prob,
+					 int *fcols,
+					 int nfcols,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  /// Destructor
+  virtual ~remove_fixed_action();
+};
+
+
+/*! \relates remove_fixed_action
+    \brief Scan the problem for fixed columns and remove them.
+
+  A front end to collect a list of columns with equal bounds and hand them to
+  remove_fixed_action::presolve() for processing.
+*/
+
+const CoinPresolveAction *remove_fixed(CoinPresolveMatrix *prob,
+				    const CoinPresolveAction *next);
+
+
+/*! \class make_fixed_action
+    \brief Fix a variable at a specified bound.
+
+  Implements the action of fixing a variable by forcing both bounds to the same
+  value and forcing the value of the variable to match.
+
+  If the bounds are already equal, and the value of the variable is already
+  correct, consider remove_fixed_action.
+*/
+class make_fixed_action : public CoinPresolveAction {
+
+  /// Structure to preserve the bound overwritten when fixing a variable
+  struct action {
+    double bound;	///< Value of bound overwritten to fix variable.
+    int col ;		///< column index of variable
+  };
+
+  /// Number of preserved bounds
+  int nactions_;
+  /// Vector of preserved bounds, one for each variable fixed in this object
+  const action *actions_;
+
+  /*! \brief True to fix at lower bound, false to fix at upper bound.
+
+    Note that this applies to all variables fixed in this object.
+  */
+  const bool fix_to_lower_;
+
+  /*! \brief The postsolve object with the information required to repopulate
+  	     the fixed columns.
+  */
+  const remove_fixed_action *faction_;
+
+  /*! \brief Constructor */
+  make_fixed_action(int nactions, const action *actions, bool fix_to_lower,
+		    const remove_fixed_action *faction,
+		    const CoinPresolveAction *next)
+    : CoinPresolveAction(next),
+      nactions_(nactions), actions_(actions),
+      fix_to_lower_(fix_to_lower),
+      faction_(faction)
+  {}
+
+ public:
+  /// Returns string "make_fixed_action".
+  const char *name() const;
+
+  /*! \brief Perform actions to fix variables and return postsolve object
+
+    For each specified variable (\p nfcols, \p fcols), fix the variable to
+    the specified bound (\p fix_to_lower) by setting the variable's bounds
+    to be equal in \p prob. Create a postsolve object, link it at the head of
+    the list of postsolve objects (\p next), and return the object.
+  */
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					 int *fcols,
+					 int nfcols,
+					 bool fix_to_lower,
+					 const CoinPresolveAction *next);
+
+  /*! \brief Postsolve (unfix variables)
+
+    Back out the variables fixed by the presolve side of this object.
+  */
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  /// Destructor
+  virtual ~make_fixed_action() {
+    deleteAction(actions_,action*); 
+    delete faction_;
+  }
+};
+
+/*! \relates make_fixed_action
+    \brief Scan variables and fix any with equal bounds
+
+  A front end to collect a list of columns with equal bounds and hand them to
+  make_fixed_action::presolve() for processing.
+*/
+
+const CoinPresolveAction *make_fixed(CoinPresolveMatrix *prob,
+				    const CoinPresolveAction *next) ;
+
+/*! \brief Transfer costs from singleton variables
+    \relates make_fixed_action
+
+  Transfers costs from singleton variables in equalities onto the other
+  variables. Will also transfer costs from one integer variable to other
+  integer variables with zero cost if there's a net gain in integer variables
+  with non-zero cost.
+
+  The relation to make_fixed_action is tenuous, but this transform should be
+  attempted before the initial round of variable fixing.
+*/
+void transferCosts(CoinPresolveMatrix * prob);
+#endif
diff --git a/cbits/coin/CoinPresolveForcing.cpp b/cbits/coin/CoinPresolveForcing.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveForcing.cpp
@@ -0,0 +1,719 @@
+/* $Id: CoinPresolveForcing.cpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveEmpty.hpp"	// for DROP_COL/DROP_ROW
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveSubst.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveUseless.hpp"
+#include "CoinPresolveForcing.hpp"
+#include "CoinMessage.hpp"
+#include "CoinFinite.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+
+namespace {
+
+/*
+  Calculate the minimum and maximum row activity (also referred to as lhs
+  bounds, from the common form ax <= b) for the row specified by the range
+  krs, kre in els and hcol. Return the result in maxupp, maxdnp.
+*/
+void implied_row_bounds (const double *els,
+			 const double *clo, const double *cup,
+			 const int *hcol, CoinBigIndex krs, CoinBigIndex kre,
+			 double &maxupp, double &maxdnp)
+{
+  bool posinf = false ;
+  bool neginf = false ;
+  double maxup = 0.0 ;
+  double maxdown = 0.0 ;
+
+/*
+  Walk the row and add up the upper and lower bounds on the variables. Once
+  both maxup and maxdown have an infinity contribution the row cannot be shown
+  to be useless or forcing, so break as soon as that's detected.
+*/
+  for (CoinBigIndex kk = krs ; kk < kre ; kk++) {
+
+    const int col = hcol[kk] ;
+    const double coeff = els[kk] ;
+    const double lb = clo[col] ;
+    const double ub = cup[col] ;
+
+    if (coeff > 0.0) {
+      if (PRESOLVE_INF <= ub) {
+	posinf = true ;
+	if (neginf) break ;
+      } else {
+	maxup += ub*coeff ;
+      }
+      if (lb <= -PRESOLVE_INF) {
+	neginf = true ;
+	if (posinf) break ;
+      } else {
+	maxdown += lb*coeff ;
+      }
+    } else {
+      if (PRESOLVE_INF <= ub) {
+	neginf = true ;
+	if (posinf) break ;
+      } else {
+	maxdown += ub*coeff ;
+      }
+      if (lb <= -PRESOLVE_INF) {
+	posinf = true ;
+	if (neginf) break ;
+      } else {
+	maxup += lb*coeff ;
+      }
+    }
+  }
+
+  maxupp   = (posinf)?PRESOLVE_INF:maxup ;
+  maxdnp = (neginf)?-PRESOLVE_INF:maxdown ;
+}
+
+}	// end file-local namespace
+
+
+
+const char *forcing_constraint_action::name() const
+{
+  return ("forcing_constraint_action") ;
+}
+
+/*
+  It may be the case that the bounds on the variables in a constraint are
+  such that no matter what feasible value the variables take, the constraint
+  cannot be violated. In this case we can drop the constraint as useless.
+
+  On the other hand, it may be that the only way to satisfy a constraint
+  is to jam all the variables in the constraint to one of their bounds, fixing
+  the variables. This is a forcing constraint, the primary target of this
+  transform.
+
+  Detection of both useless and forcing constraints requires calculation of
+  bounds on the row activity (often referred to as lhs bounds, from the common
+  form ax <= b). This routine will remember useless constraints as it finds
+  them and invoke useless_constraint_action to deal with them.
+  
+  The transform applied here simply tightens the bounds on the variables.
+  Other transforms will remove the fixed variables, leaving an empty row which
+  is ultimately dropped.
+
+  A reasonable question to ask is ``If a variable is already fixed, why do
+  we need a record in the postsolve object?'' The answer is that in postsolve
+  we'll be dealing with a column-major representation and we may need to scan
+  the row (see postsolve comments). So it's useful to record all variables in
+  the constraint.
+  
+  On the other hand, it's definitely harmful to ask remove_fixed_action
+  to process a variable more than once (causes problems in
+  remove_fixed_action::postsolve).
+
+  Original comments:
+
+  It looks like these checks could be performed in parallel, that is,
+  the tests could be carried out for all rows in parallel, and then the
+  rows deleted and columns tightened afterward.  Obviously, this is true
+  for useless rows.  By doing it in parallel rather than sequentially,
+  we may miss transformations due to variables that were fixed by forcing
+  constraints, though.
+
+  Note that both of these operations will cause problems if the variables
+  in question really need to exceed their bounds in order to make the
+  problem feasible.
+*/
+const CoinPresolveAction*
+  forcing_constraint_action::presolve (CoinPresolveMatrix *prob,
+  				       const CoinPresolveAction *next)
+{
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING
+  int startEmptyRows = 0 ;
+  int startEmptyColumns = 0 ;
+  startEmptyRows = prob->countEmptyRows() ;
+  startEmptyColumns = prob->countEmptyCols() ;
+# endif
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering forcing_constraint_action::presolve, considering "
+    << prob->numberRowsToDo_ << " rows." << std::endl ;
+# endif
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if COIN_PRESOLVE_TUNING
+  double startTime = 0.0 ;
+  if (prob->tuning_) {
+    startTime = CoinCpuTime() ;
+  }
+# endif
+
+  // Column solution and bounds
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+  double *csol = prob->sol_ ;
+
+  // Row-major representation
+  const CoinBigIndex *mrstrt = prob->mrstrt_ ;
+  const double *rowels = prob->rowels_ ;
+  const int *hcol = prob->hcol_ ;
+  const int *hinrow = prob->hinrow_ ;
+  const int nrows = prob->nrows_ ;
+
+  const double *rlo = prob->rlo_ ;
+  const double *rup = prob->rup_ ;
+
+  const double tol = ZTOLDP ;
+  const double inftol = prob->feasibilityTolerance_ ;
+  const int ncols = prob->ncols_ ;
+
+  int *fixed_cols = new int[ncols] ;
+  int nfixed_cols = 0 ;
+
+  action *actions = new action [nrows] ;
+  int nactions = 0 ;
+
+  int *useless_rows = new int[nrows] ;
+  int nuseless_rows = 0 ;
+
+  const int numberLook = prob->numberRowsToDo_ ;
+  int *look = prob->rowsToDo_ ;
+
+  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+/*
+  Open a loop to scan the constraints of interest. There must be variables
+  left in the row.
+*/
+  for (int iLook = 0 ; iLook < numberLook ; iLook++) {
+    int irow = look[iLook] ;
+    if (hinrow[irow] <= 0) continue ;
+
+    const CoinBigIndex krs = mrstrt[irow] ;
+    const CoinBigIndex kre = krs+hinrow[irow] ;
+/*
+  Calculate upper and lower bounds on the row activity based on upper and lower
+  bounds on the variables. If these are finite and incompatible with the given
+  row bounds, we have infeasibility.
+*/
+    double maxup, maxdown ;
+    implied_row_bounds(rowels,clo,cup,hcol,krs,kre,maxup,maxdown) ;
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  considering row " << irow << ", rlo " << rlo[irow]
+      << " LB " << maxdown << " UB " << maxup << " rup " << rup[irow] ;
+#   endif
+/*
+  If the maximum lhs value is less than L(i) or the minimum lhs value is
+  greater than U(i), we're infeasible.
+*/
+    if (maxup < PRESOLVE_INF &&
+        maxup+inftol < rlo[irow] && !fixInfeasibility) {
+      CoinMessageHandler *hdlr = prob->messageHandler() ;
+      prob->status_|= 1 ;
+      hdlr->message(COIN_PRESOLVE_ROWINFEAS,prob->messages())
+	 << irow << rlo[irow] << rup[irow] << CoinMessageEol ;
+#     if PRESOLVE_DEBUG > 2
+      std::cout << "; infeasible." << std::endl ;
+#     endif
+      break ;
+    }
+    if (-PRESOLVE_INF < maxdown &&
+        rup[irow] < maxdown-inftol && !fixInfeasibility) {
+      CoinMessageHandler *hdlr = prob->messageHandler() ;
+      prob->status_|= 1 ;
+      hdlr->message(COIN_PRESOLVE_ROWINFEAS,prob->messages())
+	 << irow << rlo[irow] << rup[irow] << CoinMessageEol ;
+#     if PRESOLVE_DEBUG > 2
+      std::cout << "; infeasible." << std::endl ;
+#     endif
+      break ;
+    }
+/*
+  We've dealt with prima facie infeasibility. Now check if the constraint
+  is trivially satisfied. If so, add it to the list of useless rows and move
+  on.
+
+  The reason we require maxdown and maxup to be finite if the row bound is
+  finite is to guard against some subsequent transform changing a column
+  bound from infinite to finite. Once finite, bounds continue to tighten,
+  so we're safe.
+*/
+    if (((rlo[irow] <= -PRESOLVE_INF) ||
+	 (-PRESOLVE_INF < maxdown && rlo[irow] <= maxdown-inftol)) &&
+	((rup[irow] >= PRESOLVE_INF) ||
+	 (maxup < PRESOLVE_INF && rup[irow] >= maxup+inftol))) {
+      // check none prohibited
+      if (prob->anyProhibited_) {
+	bool anyProhibited=false;
+	for (int k=krs; k<kre; k++) {
+	  int jcol = hcol[k];
+	  if (prob->colProhibited(jcol)) {
+	    anyProhibited=true;
+	    break;
+	  }
+	}
+	if (anyProhibited)
+	  continue; // skip row
+      }
+      useless_rows[nuseless_rows++] = irow ;
+#     if PRESOLVE_DEBUG > 2
+      std::cout << "; useless." << std::endl ;
+#     endif
+      continue ;
+    }
+/*
+  Is it the case that we can just barely attain L(i) or U(i)? If so, we have a
+  forcing constraint. As explained above, we need maxup and maxdown to be
+  finite in order for the test to be valid.
+*/
+    const bool tightAtLower = ((maxup < PRESOLVE_INF) &&
+    			       (fabs(rlo[irow]-maxup) < tol)) ;
+    const bool tightAtUpper = ((-PRESOLVE_INF < maxdown) &&
+			       (fabs(rup[irow]-maxdown) < tol)) ;
+#   if PRESOLVE_DEBUG > 2
+    if (tightAtLower || tightAtUpper) std::cout << "; forcing." ;
+    std::cout << std::endl ;
+#   endif
+    if (!(tightAtLower || tightAtUpper)) continue ;
+    // check none prohibited
+    if (prob->anyProhibited_) {
+      bool anyProhibited=false;
+      for (int k=krs; k<kre; k++) {
+	int jcol = hcol[k];
+	if (prob->colProhibited(jcol)) {
+	  anyProhibited=true;
+	  break;
+	}
+      }
+      if (anyProhibited)
+	continue; // skip row
+    }
+/*
+  We have a forcing constraint.
+  Get down to the business of fixing the variables at the appropriate bound.
+  We need to remember the original value of the bound we're tightening.
+  Allocate a pair of arrays the size of the row. Load variables fixed at l<j>
+  from the start, variables fixed at u<j> from the end. Add the column to
+  the list of columns to be processed further.
+*/
+    double *bounds = new double[hinrow[irow]] ;
+    int *rowcols = new int[hinrow[irow]] ;
+    CoinBigIndex lk = krs ;
+    CoinBigIndex uk = kre ;
+    for (CoinBigIndex k = krs ; k < kre ; k++) {
+      const int j = hcol[k] ;
+      const double lj = clo[j] ;
+      const double uj = cup[j] ;
+      const double coeff = rowels[k] ;
+      PRESOLVEASSERT(fabs(coeff) > ZTOLDP) ;
+/*
+  If maxup is tight at L(i), then we want to force variables x<j> to the bound
+  that produced maxup: u<j> if a<ij> > 0, l<j> if a<ij> < 0. If maxdown is
+  tight at U(i), it'll be just the opposite.
+*/
+      if (tightAtLower == (coeff > 0.0)) {
+	--uk ;
+	bounds[uk-krs] = lj ;
+	rowcols[uk-krs] = j ;
+	if (csol != 0) {
+	  csol[j] = uj ;
+	}
+	clo[j] = uj ;
+      } else {
+	bounds[lk-krs] = uj ;
+	rowcols[lk-krs] = j ;
+	++lk ;
+	if (csol != 0) {
+	  csol[j] = lj ;
+	}
+	cup[j] = lj ;
+      }
+/*
+  Only add a column to the list of fixed columns the first time it's fixed.
+*/
+      if (lj != uj) {
+	fixed_cols[nfixed_cols++] = j ;
+	prob->addCol(j) ;
+      }
+    }
+    PRESOLVEASSERT(uk == lk) ;
+    PRESOLVE_DETAIL_PRINT(printf("pre_forcing %dR E\n",irow)) ;
+#   if PRESOLVE_DEBUG > 1
+    std::cout
+      << "FORCING: row(" << irow << "), " << (kre-krs) << " variables."
+      << std::endl ;
+#   endif
+/*
+  Done with this row. Remember the changes in a postsolve action.
+*/
+    action *f = &actions[nactions] ;
+    nactions++ ;
+    f->row = irow ;
+    f->nlo = lk-krs ;
+    f->nup = kre-uk ;
+    f->rowcols = rowcols ;
+    f->bounds = bounds ;
+  }
+
+/*
+  Done processing the rows of interest.  No sense doing any additional work
+  unless we're feasible.
+*/
+  if (prob->status_ == 0) {
+#   if PRESOLVE_DEBUG > 0
+    std::cout
+      << "FORCING: " << nactions << " forcing, " << nuseless_rows << " useless."
+      << std::endl ;
+#   endif
+/*
+  Trim the actions array to size and create a postsolve object.
+*/
+    if (nactions) {
+      next = new forcing_constraint_action(nactions, 
+				 CoinCopyOfArray(actions,nactions),next) ;
+    }
+/*
+  Hand off the job of dealing with the useless rows to a specialist.
+*/
+    if (nuseless_rows) {
+      next = useless_constraint_action::presolve(prob,
+      					useless_rows,nuseless_rows,next) ;
+    }
+/*
+  Hand off the job of dealing with the fixed columns to a specialist.
+
+  Note that there *cannot* be duplicates in this list or we'll get in trouble
+  `unfixing' a column multiple times. The code above now adds a variable
+  to fixed_cols only if it's not already fixed. If that ever changes,
+  the disabled code (sort, unique) will need to be reenabled.
+*/
+    if (nfixed_cols) {
+      if (false && nfixed_cols > 1) {
+	std::sort(fixed_cols,fixed_cols+nfixed_cols) ;
+	int *end = std::unique(fixed_cols,fixed_cols+nfixed_cols) ;
+	nfixed_cols = static_cast<int>(end-fixed_cols) ;
+      }
+      next = remove_fixed_action::presolve(prob,fixed_cols,nfixed_cols,next) ;
+    }
+  }
+
+  deleteAction(actions,action*) ;
+  delete [] useless_rows ;
+  delete [] fixed_cols ;
+
+# if COIN_PRESOLVE_TUNING
+  if (prob->tuning_) double thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns =  prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving forcing_constraint_action::presolve: removed " << droppedRows
+    << " rows, " << droppedColumns << " columns" ;
+# if COIN_PRESOLVE_TUNING > 0
+  if (prob->tuning_)
+    std::cout << " in " << (thisTime-prob->startTime_) << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+/*
+  We're here to undo the bound changes that were put in place for forcing
+  constraints.  This is a bit trickier than it appears.
+
+  Assume we are working with constraint r.  The situation on arrival is
+  that constraint r exists and is fully populated with fixed variables, all
+  of which are nonbasic. Even though the constraint is tight, the logical
+  s(r) is basic and the dual y(r) is zero.
+  
+  We may need to change that if a bound is relaxed to infinity on some
+  variable x(t), making x(t)'s current nonbasic status untenable. We'll need
+  to make s(r) nonbasic so that y(r) can be nonzero. Then we can make x(t)
+  basic and use y(r) to force cbar(t) to zero. The code below will choose
+  the variable x(t) whose reduced cost cbar(t) is most wrong and adjust y(r)
+  to drive cbar(t) to zero using
+     cbar(t) = c(t) - SUM{i\r} y(i) a(it) - y(r)a(rt)
+     cbar(t) = cbar(t\r) - y(r)a(rt)
+  Setting cbar(t) to zero,
+     y(r) = cbar(t\r)/a(rt)
+
+  We will need to scan row r, correcting cbar(j) for all x(j) entangled
+  with the row. We may need to change the nonbasic status of x(j) if the
+  adjustment causes cbar(j) to change sign.
+*/
+void forcing_constraint_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_ ;
+  const int nactions = nactions_ ;
+
+  const double *colels = prob->colels_ ;
+  const int *hrow = prob->hrow_ ;
+  const CoinBigIndex *mcstrt = prob->mcstrt_ ;
+  const int *hincol = prob->hincol_ ;
+  const int *link = prob->link_ ;
+
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+
+  double *rcosts = prob->rcosts_ ;
+
+  double *acts = prob->acts_ ;
+  double *rowduals = prob->rowduals_ ;
+
+  const double ztoldj = prob->ztoldj_ ;
+  const double ztolzb = prob->ztolzb_ ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  const double *sol = prob->sol_ ;
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering forcing_constraint_action::postsolve, "
+    << nactions << " constraints to process." << std::endl ;
+# endif
+  presolve_check_threads(prob) ;
+  presolve_check_free_list(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+/*
+  Open a loop to process the actions. One action per constraint.
+*/
+  for (const action *f = &actions[nactions-1] ; actions <= f ; f--) {
+    const int irow = f->row ;
+    const int nlo = f->nlo ;
+    const int nup = f->nup ;
+    const int ninrow = nlo+nup ;
+    const int *rowcols = f->rowcols ;
+    const double *bounds = f->bounds ;
+
+#   if PRESOLVE_DEBUG > 1
+    std::cout
+      << "  Restoring constraint " << irow << ", " << ninrow
+      << " variables." << std::endl ;
+#   endif
+
+    PRESOLVEASSERT(prob->getRowStatus(irow) == CoinPrePostsolveMatrix::basic) ;
+    PRESOLVEASSERT(rowduals[irow] == 0.0) ;
+/*
+  Process variables where the upper bound is relaxed.
+    * If the variable is basic, we should leave the status unchanged. Relaxing
+      the bound cannot make nonbasic status feasible.
+    * The bound change may be a noop, in which nothing needs to be done.
+    * Otherwise, the status should be set to NBLB.
+*/
+    bool dualfeas = true ;
+    for (int k = 0 ; k < nlo ; k++) {
+      const int jcol = rowcols[k] ;
+      PRESOLVEASSERT(fabs(sol[jcol]-clo[jcol]) <= ztolzb) ;
+      const double cbarj = rcosts[jcol] ;
+      const double olduj = cup[jcol] ;
+      const double newuj = bounds[k] ;
+      const bool change = (fabs(newuj-olduj) > ztolzb) ;
+
+#     if PRESOLVE_DEBUG > 2
+      std::cout
+        << "    x(" << jcol << ") " << prob->columnStatusString(jcol)
+	<< " cbar = " << cbarj << ", lb = " << clo[jcol]
+	<< ", ub = " << olduj << " -> " << newuj ;
+#     endif
+
+      if (change &&
+          prob->getColumnStatus(jcol) != CoinPrePostsolveMatrix::basic) {
+	prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound) ;
+	if (cbarj < -ztoldj || clo[jcol] <= -COIN_DBL_MAX) dualfeas = false ;
+      }
+      cup[jcol] = bounds[k] ;
+
+#     if PRESOLVE_DEBUG > 2
+      std::cout
+        << " -> " << prob->columnStatusString(jcol) << "." << std::endl ;
+#     endif
+    }
+/*
+  Process variables where the lower bound is relaxed. The comments above
+  apply.
+*/
+    for (int k = nlo ; k < ninrow ; k++) {
+      const int jcol = rowcols[k] ;
+      PRESOLVEASSERT(fabs(sol[jcol]-cup[jcol]) <= ztolzb) ;
+      const double cbarj = rcosts[jcol] ;
+      const double oldlj = clo[jcol] ;
+      const double newlj = bounds[k] ;
+      const bool change = (fabs(newlj-oldlj) > ztolzb) ;
+
+#     if PRESOLVE_DEBUG > 2
+      std::cout
+        << "    x(" << jcol << ") " << prob->columnStatusString(jcol)
+	<< " cbar = " << cbarj << ", ub = " << cup[jcol]
+	<< ", lb = " << oldlj << " -> " << newlj ;
+#     endif
+
+      if (change &&
+          prob->getColumnStatus(jcol) != CoinPrePostsolveMatrix::basic) {
+	prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound) ;
+	if (cbarj > ztoldj || cup[jcol] >= COIN_DBL_MAX) dualfeas = false ;
+      }
+      clo[jcol] = bounds[k] ;
+
+#     if PRESOLVE_DEBUG > 2
+      std::cout
+        << " -> " << prob->columnStatusString(jcol) << "." << std::endl ;
+#     endif
+    }
+/*
+  The reduced costs and status for the columns may or may not be ok for
+  the relaxed column bounds.  If not, find the variable x<joow> most
+  out-of-whack with respect to reduced cost and calculate the value of
+  y<irow> required to reduce cbar<joow> to zero.
+*/
+
+    if (dualfeas == false) {
+      int joow = -1 ;
+      double yi = 0.0 ;
+      for (int k = 0 ; k < ninrow ; k++) {
+	int jcol = rowcols[k] ;
+	CoinBigIndex kk = presolve_find_row2(irow,mcstrt[jcol],
+					     hincol[jcol],hrow,link) ;
+	const double &cbarj = rcosts[jcol] ;
+	const CoinPrePostsolveMatrix::Status statj =
+					prob->getColumnStatus(jcol) ;
+	if ((cbarj < -ztoldj &&
+	     statj != CoinPrePostsolveMatrix::atUpperBound) ||
+	    (cbarj > ztoldj &&
+	     statj != CoinPrePostsolveMatrix::atLowerBound)) {
+	  double yi_j = cbarj/colels[kk] ;
+	  if (fabs(yi_j) > fabs(yi)) {
+	    joow = jcol ;
+	    yi = yi_j ;
+	  }
+#         if PRESOLVE_DEBUG > 3
+	  std::cout
+	    << "      oow: x(" << jcol << ") "
+	    << prob->columnStatusString(jcol) << " cbar " << cbarj << " aij "
+	    << colels[kk] << " corr " << yi_j << "." << std::endl ;
+#         endif
+	}
+      }
+      assert(joow != -1) ;
+/*
+  Make x<joow> basic and set the row status according to whether we're
+  tight at the lower or upper bound. Keep in mind the convention that a
+  <= constraint has a slack 0 <= s <= infty, while a >= constraint has a
+  surplus -infty <= s <= 0.
+*/
+
+#     if PRESOLVE_DEBUG > 1
+      std::cout
+	<< "    Adjusting row dual; x(" << joow
+	<< ") " << prob->columnStatusString(joow) << " -> "
+	<< statusName(CoinPrePostsolveMatrix::basic)
+	<< ", y = 0.0 -> " << yi << "." << std::endl ;
+#     endif
+
+      prob->setColumnStatus(joow,CoinPrePostsolveMatrix::basic) ;
+      if (acts[irow]-rlo[irow] < rup[irow]-acts[irow])
+	prob->setRowStatus(irow,CoinPrePostsolveMatrix::atUpperBound) ;
+      else
+	prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound) ;
+      rowduals[irow] = yi ;
+
+#     if PRESOLVE_DEBUG > 1
+      std::cout
+	<< "    Row status " << prob->rowStatusString(irow)
+	<< ", lb = " << rlo[irow] << ", ax = " << acts[irow]
+	<< ", ub = " << rup[irow] << "." << std::endl ;
+#     endif
+/*
+  Now correct the reduced costs for other variables in the row. This may
+  cause a reduced cost to change sign, in which case we need to change status.
+
+  The code implicitly assumes that if it's necessary to change the status
+  of a variable because the reduced cost has changed sign, then it will be
+  possible to do it. I'm not sure I could prove that, however.
+  -- lh, 121108 --
+*/
+      for (int k = 0 ; k < ninrow ; k++) {
+	int jcol = rowcols[k] ;
+	CoinBigIndex kk = presolve_find_row2(irow,mcstrt[jcol],
+					     hincol[jcol],hrow,link) ;
+	const double old_cbarj = rcosts[jcol] ;
+	rcosts[jcol] -= yi*colels[kk] ;
+	const double new_cbarj = rcosts[jcol] ;
+
+	if ((old_cbarj < 0) != (new_cbarj < 0)) {
+	  if (new_cbarj < -ztoldj && cup[jcol] < COIN_DBL_MAX)
+	    prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound) ;
+	  else if (new_cbarj > ztoldj && clo[jcol] > -COIN_DBL_MAX)
+	    prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound) ;
+	}
+
+#       if PRESOLVE_DEBUG > 3
+	const CoinPrePostsolveMatrix::Status statj =
+						prob->getColumnStatus(jcol) ;
+	std::cout
+	  << "      corr: x(" << jcol << ") "
+	  << prob->columnStatusString(jcol) << " cbar " << new_cbarj ;
+	if ((new_cbarj < -ztoldj &&
+	     statj != CoinPrePostsolveMatrix::atUpperBound) ||
+	    (new_cbarj > ztoldj &&
+	     statj != CoinPrePostsolveMatrix::atLowerBound) ||
+	    (statj == CoinPrePostsolveMatrix::basic &&
+	     fabs(new_cbarj) > ztoldj))
+	  std::cout << " error!" << std::endl ;
+	else
+	  std::cout << "." << std::endl ;
+#       endif
+
+      }
+    }
+# if PRESOLVE_DEBUG > 0
+  presolve_check_nbasic(prob) ;
+# endif
+  }
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving forcing_constraint_action::postsolve." << std::endl ;
+# endif
+# endif
+
+}
+
+
+forcing_constraint_action::~forcing_constraint_action() 
+{ 
+  int i ;
+  for (i=0;i<nactions_;i++) {
+    //delete [] actions_[i].rowcols; MS Visual C++ V6 can not compile
+    //delete [] actions_[i].bounds; MS Visual C++ V6 can not compile
+    deleteAction(actions_[i].rowcols,int *) ;
+    deleteAction(actions_[i].bounds,double *) ;
+  }
+  // delete [] actions_; MS Visual C++ V6 can not compile
+  deleteAction(actions_,action *) ;
+}
+
diff --git a/cbits/coin/CoinPresolveForcing.hpp b/cbits/coin/CoinPresolveForcing.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveForcing.hpp
@@ -0,0 +1,61 @@
+/* $Id: CoinPresolveForcing.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveForcing_H
+#define CoinPresolveForcing_H
+
+#include "CoinPresolveMatrix.hpp"
+
+/*!
+  \file
+*/
+
+#define	IMPLIED_BOUND	7
+
+/*! \class forcing_constraint_action
+    \brief Detect and process forcing constraints and useless constraints
+
+  A constraint is useless if the bounds on the variables prevent the constraint
+  from ever being violated.
+
+  A constraint is a forcing constraint if the bounds on the constraint force
+  the value of an involved variable to one of its bounds. A constraint can
+  force more than one variable.
+*/
+class forcing_constraint_action : public CoinPresolveAction {
+  forcing_constraint_action();
+  forcing_constraint_action(const forcing_constraint_action& rhs);
+  forcing_constraint_action& operator=(const forcing_constraint_action& rhs);
+public:
+  struct action {
+    const int *rowcols;
+    const double *bounds;
+    int row;
+    int nlo;
+    int nup;
+  };
+private:
+  const int nactions_;
+  // actions_ is owned by the class and must be deleted at destruction
+  const action *const actions_;
+
+public:
+  forcing_constraint_action(int nactions,
+		      const action *actions,
+		      const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions) {}
+
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix * prob,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~forcing_constraint_action();
+};
+
+#endif
diff --git a/cbits/coin/CoinPresolveHelperFunctions.cpp b/cbits/coin/CoinPresolveHelperFunctions.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveHelperFunctions.cpp
@@ -0,0 +1,450 @@
+/* $Id: CoinPresolveHelperFunctions.cpp 1560 2012-11-24 00:29:01Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*! \file
+
+  This file contains helper functions for CoinPresolve. The declarations needed
+  for use are included in CoinPresolveMatrix.hpp.
+*/
+
+#include <stdio.h>
+
+#include <cassert>
+#include <iostream>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+
+
+/*! \defgroup PMMDVX Packed Matrix Major Dimension Vector Expansion
+    \brief Functions to help with major-dimension vector expansion in a
+	   packed matrix structure.
+
+  This next block of functions handles the problems associated with expanding
+  a column in a column-major representation or a row in a row-major
+  representation.
+  
+  We need to be able to answer the questions:
+    * Is there room to expand a major vector in place?
+    * Is there sufficient free space at the end of the element and minor
+      index storage areas (bulk storage) to hold the major vector?
+
+  When the answer to the first question is `no', we need to be able to move
+  the major vector to the free space at the end of bulk storage.
+  
+  When the answer to the second question is `no', we need to be able to
+  compact the major vectors in the bulk storage area in order to regain a
+  block of useable space at the end.
+
+  presolve_make_memlists initialises a linked list that tracks the position of
+  major vectors in the bulk storage area. It's used to locate physically
+  adjacent vectors.
+
+  presolve_expand deals with adding a coefficient to a major vector, either
+  in-place or by moving it to free space at the end of the storage areas.
+  There are two inline wrappers, presolve_expand_col and presolve_expand_row,
+  defined in CoinPresolveMatrix.hpp.
+
+  compact_rep compacts the major vectors in the storage areas to
+  leave a single block of free space at the end.
+*/
+//@{
+
+/*
+  This first function doesn't need to be known outside of this file.
+*/
+namespace {
+
+/*
+  compact_rep
+
+  This routine compacts the major vectors in the bulk storage area,
+  leaving a single block of free space at the end. The vectors are not
+  reordered, just shifted down to remove gaps.
+*/
+
+void compact_rep (double *elems, int *indices,
+		  CoinBigIndex *starts, const int *lengths, int n,
+		  const presolvehlink *link)
+{
+# if PRESOLVE_SUMMARY
+  printf("****COMPACTING****\n") ;
+# endif
+
+  // for now, just look for the first element of the list
+  int i = n ;
+  while (link[i].pre != NO_LINK)
+    i = link[i].pre ;
+
+  CoinBigIndex j = 0 ;
+  for (; i != n; i = link[i].suc) {
+    CoinBigIndex s = starts[i] ;
+    CoinBigIndex e = starts[i] + lengths[i] ;
+
+    // because of the way link is organized, j <= s
+    starts[i] = j ;
+    for (CoinBigIndex k = s; k < e; k++) {
+      elems[j] = elems[k] ;
+      indices[j] = indices[k] ;
+      j++ ;
+   }
+  }
+}
+
+
+} /* end unnamed namespace */
+
+/*
+  \brief Initialise linked list for major vector order in bulk storage
+
+  Initialise the linked list that will track the order of major vectors in
+  the element and row index bulk storage arrays.  When finished, link[j].pre
+  contains the index of the previous non-empty vector in the storage arrays
+  and link[j].suc contains the index of the next non-empty vector.
+
+  For an empty vector j, link[j].pre = link[j].suc = NO_LINK.
+
+  If n is the number of major-dimension vectors, link[n] is valid;
+  link[n].pre is the index of the last non-empty vector, and
+  link[n].suc = NO_LINK.
+
+  This routine makes the implicit assumption that the order of vectors in the
+  storage areas matches the order in starts. (I.e., there's no check that
+  starts[j] > starts[i] for j < i.)
+*/
+
+void presolve_make_memlists (/*CoinBigIndex *starts,*/ int *lengths,
+			     presolvehlink *link, int n)
+{
+  int i ;
+  int pre = NO_LINK ;
+  
+  for (i=0; i<n; i++) {
+    if (lengths[i]) {
+      link[i].pre = pre ;
+      if (pre != NO_LINK)
+	link[pre].suc = i ;
+      pre = i ;
+    }
+    else {
+      link[i].pre = NO_LINK ;
+      link[i].suc = NO_LINK ;
+    }
+  }
+  if (pre != NO_LINK)
+    link[pre].suc = n ;
+
+  // (1) Arbitrarily place the last non-empty entry in link[n].pre
+  link[n].pre = pre ;
+
+  link[n].suc = NO_LINK ;
+}
+
+
+
+/*
+  presolve_expand_major
+
+  The routine looks at the space currently occupied by major-dimension vector
+  k and makes sure that there's room to add one coefficient.
+
+  This may require moving the vector to the vacant area at the end of the
+  bulk storage array. If there's no room left at the end of the array, an
+  attempt is made to compact the existing vectors to make space.
+
+  Returns true for failure, false for success.
+*/
+
+bool presolve_expand_major (CoinBigIndex *majstrts, double *els,
+			    int *minndxs, int *majlens,
+			    presolvehlink *majlinks, int nmaj, int k)
+
+{ const CoinBigIndex bulkCap = majstrts[nmaj] ;
+
+/*
+  Get the start and end of column k, and the index of the column which
+  follows in the bulk storage.
+*/
+  CoinBigIndex kcsx = majstrts[k] ;
+  CoinBigIndex kcex = kcsx + majlens[k] ;
+  int nextcol = majlinks[k].suc ;
+/*
+  Do we have room to add one coefficient in place?
+*/
+  if (kcex+1 < majstrts[nextcol])
+  { /* no action required */ }
+/*
+  Is k the last non-empty column? In that case, attempt to compact the
+  bulk storage. This will move k, so update the column start and end.
+  If we still have no space, it's a fatal error.
+*/
+  else
+  if (nextcol == nmaj)
+  { compact_rep(els,minndxs,majstrts,majlens,nmaj,majlinks) ;
+    kcsx = majstrts[k] ;
+    kcex = kcsx + majlens[k] ;
+    if (kcex+1 >= bulkCap)
+    { return (true) ; } }
+/*
+  The most complicated case --- we need to move k from its current location
+  to empty space at the end of the bulk storage. And we may need to make that!
+  Compaction is identical to the above case.
+*/
+  else
+  { int lastcol = majlinks[nmaj].pre ;
+    int newkcsx = majstrts[lastcol]+majlens[lastcol] ;
+    int newkcex = newkcsx+majlens[k] ;
+
+    if (newkcex+1 >= bulkCap)
+    { compact_rep(els,minndxs,majstrts,majlens,nmaj,majlinks) ;
+      kcsx = majstrts[k] ;
+      kcex = kcsx + majlens[k] ;
+      newkcsx = majstrts[lastcol]+majlens[lastcol] ;
+      newkcex = newkcsx+majlens[k] ;
+      if (newkcex+1 >= bulkCap)
+      { return (true) ; } }
+/*
+  Moving the vector requires three actions. First we move the data, then
+  update the packed matrix vector start, then relink the storage order list,
+*/
+    memcpy(reinterpret_cast<void *>(&minndxs[newkcsx]),
+	   reinterpret_cast<void *>(&minndxs[kcsx]),majlens[k]*sizeof(int)) ;
+    memcpy(reinterpret_cast<void *>(&els[newkcsx]),
+	   reinterpret_cast<void *>(&els[kcsx]),majlens[k]*sizeof(double)) ;
+    majstrts[k] = newkcsx ;
+    PRESOLVE_REMOVE_LINK(majlinks,k) ;
+    PRESOLVE_INSERT_LINK(majlinks,k,lastcol) ; }
+/*
+  Success --- the vector has room for one more coefficient.
+*/
+  return (false) ; }
+
+//@}
+
+
+
+/*
+  Helper function to duplicate a major-dimension vector.
+*/
+
+/*
+  A major-dimension vector is composed of paired element and minor index
+  arrays.  We want to duplicate length entries from both arrays, starting at
+  offset.
+
+  If tgt > 0, we'll run a more complicated copy loop which will elide the
+  entry with minor index == tgt. In this case, we want to reduce the size of
+  the allocated array by 1.
+
+  Pigs will fly before sizeof(int) > sizeof(double), but if it ever
+  happens this code will fail.
+*/
+
+double *presolve_dupmajor (const double *elems, const int *indices,
+			   int length, CoinBigIndex offset, int tgt)
+
+{ int n ;
+
+  if (tgt >= 0) length-- ;
+
+  if (2*sizeof(int) <= sizeof(double))
+    n = (3*length+1)>>1 ;
+  else
+    n = 2*length ;
+
+  double *dArray = new double [n] ;
+  int *iArray = reinterpret_cast<int *>(dArray+length) ;
+
+  if (tgt < 0)
+  { memcpy(dArray,elems+offset,length*sizeof(double)) ;
+    memcpy(iArray,indices+offset,length*sizeof(int)) ; }
+  else
+  { int korig ;
+    int kcopy = 0 ;
+    indices += offset ;
+    elems += offset ;
+    for (korig = 0 ; korig <= length ; korig++)
+    { int i = indices[korig] ;
+      if (i != tgt)
+      { dArray[kcopy] = elems[korig] ;
+	iArray[kcopy++] = indices[korig] ; } } }
+
+  return (dArray) ; }
+
+
+
+/*
+  Routines to find the position of the entry for a given minor index in a
+  major vector. Inline wrappers with column-major and row-major parameter
+  names are defined in CoinPresolveMatrix.hpp. The threaded matrix used in
+  postsolve exists only as a column-major form, so only one wrapper is
+  defined.
+*/
+
+/*
+  presolve_find_minor
+
+  Find the position (k) of the entry for a given minor index (tgt) within
+  the range of entries for a major vector (ks, ke).
+
+  Print a tag and abort (DIE) if there's no entry for tgt.
+*/
+#if 0
+CoinBigIndex presolve_find_minor (int tgt, CoinBigIndex ks,
+				  CoinBigIndex ke, const int *minndxs)
+
+{ CoinBigIndex k ;
+  for (k = ks ; k < ke ; k++)
+  { if (minndxs[k] == tgt)
+      return (k) ; }
+  DIE("FIND_MINOR") ;
+
+  abort () ; return -1; }
+#endif
+/*
+  As presolve_find_minor, but return a position one past the end of
+  the major vector when the entry is not already present.
+*/
+CoinBigIndex presolve_find_minor1 (int tgt, CoinBigIndex ks,
+				   CoinBigIndex ke, const int *minndxs)
+{ CoinBigIndex k ;
+  for (k = ks ; k < ke ; k++)
+  { if (minndxs[k] == tgt)
+      return (k) ; }
+
+  return (k) ; }
+
+/*
+  In a threaded matrix, the major vector does not occupy a contiguous block
+  in the bulk storage area. For example, in a threaded column-major matrix,
+  if a<i,p> is in pos'n kp of hrow, the next coefficient a<i,q> will be
+  in pos'n kq = link[kp]. Abort if we don't find it.
+*/
+CoinBigIndex presolve_find_minor2 (int tgt, CoinBigIndex ks,
+				   int majlen, const int *minndxs,
+				   const CoinBigIndex *majlinks)
+
+{ for (int i = 0 ; i < majlen ; ++i)
+  { if (minndxs[ks] == tgt)
+      return (ks) ;
+    ks = majlinks[ks] ; }
+  DIE("FIND_MINOR2") ;
+
+  abort () ; return -1; }
+
+/*
+  As presolve_find_minor2, but return -1 if the entry is missing
+*/
+CoinBigIndex presolve_find_minor3 (int tgt, CoinBigIndex ks,
+				   int majlen, const int *minndxs,
+				   const CoinBigIndex *majlinks)
+
+{ for (int i = 0 ; i < majlen ; ++i)
+  { if (minndxs[ks] == tgt)
+      return (ks) ;
+    ks = majlinks[ks] ; }
+
+  return (-1) ; }
+
+/*
+  Delete the entry for a minor index from a major vector.  The last entry in
+  the major vector is moved into the hole left by the deleted entry. This
+  leaves some space between the end of this major vector and the start of the
+  next in the bulk storage areas (this is termed loosely packed). Inline
+  wrappers with column-major and row-major parameter names are defined in
+  CoinPresolveMatrix.hpp.  The threaded matrix used in postsolve exists only
+  as a column-major form, so only one wrapper is defined.
+*/
+
+#if 0
+void presolve_delete_from_major (int majndx, int minndx,
+				 const CoinBigIndex *majstrts,
+				 int *majlens, int *minndxs, double *els)
+
+{ CoinBigIndex ks = majstrts[majndx] ;
+  CoinBigIndex ke = ks + majlens[majndx] ;
+
+  CoinBigIndex kmi = presolve_find_minor(minndx,ks,ke,minndxs) ;
+
+  minndxs[kmi] = minndxs[ke-1] ;
+  els[kmi] = els[ke-1] ;
+  majlens[majndx]-- ;
+  
+  return ; }
+// Delete all marked and zero marked
+void presolve_delete_many_from_major (int majndx, char * marked,
+				 const CoinBigIndex *majstrts,
+				 int *majlens, int *minndxs, double *els)
+
+{ 
+  CoinBigIndex ks = majstrts[majndx] ;
+  CoinBigIndex ke = ks + majlens[majndx] ;
+  CoinBigIndex put=ks;
+  for (CoinBigIndex k=ks;k<ke;k++) {
+    int iMinor = minndxs[k];
+    if (!marked[iMinor]) {
+      minndxs[put]=iMinor;
+      els[put++]=els[k];
+    } else {
+      marked[iMinor]=0;
+    }
+  } 
+  majlens[majndx] = put-ks ;
+  return ;
+}
+#endif
+
+/*
+  Delete the entry for a minor index from a major vector in a threaded matrix.
+
+  This involves properly relinking the free list.
+*/
+void presolve_delete_from_major2 (int majndx, int minndx,
+				  CoinBigIndex *majstrts, int *majlens,
+				  int *minndxs, int *majlinks, 
+				  CoinBigIndex *free_listp)
+
+{
+  CoinBigIndex k = majstrts[majndx] ;
+
+/*
+  Desired entry is the first in its major vector. We need to touch up majstrts
+  to point to the next entry and link the deleted entry to the front of the
+  free list.
+*/
+  if (minndxs[k] == minndx) {
+    majstrts[majndx] = majlinks[k] ;
+    majlinks[k] = *free_listp ;
+    *free_listp = k ;
+    majlens[majndx]-- ;
+  } else {
+/*
+  Desired entry is somewhere in the major vector. We need to relink around
+  it and then link it on the front of the free list.
+
+  The loop runs over elements 1 .. len-1; we've already ruled out element 0.
+*/
+    int len = majlens[majndx] ;
+    CoinBigIndex kpre = k ;
+    k = majlinks[k] ;
+    for (int i = 1 ; i < len ; ++i) {
+      if (minndxs[k] == minndx) {
+        majlinks[kpre] = majlinks[k] ;
+	majlinks[k] = *free_listp ;
+	*free_listp = k ;
+	majlens[majndx]-- ;
+	return ;
+      }
+      kpre = k ;
+      k = majlinks[k] ;
+    }
+    DIE("DELETE_FROM_MAJOR2") ;
+  }
+
+  assert(*free_listp >= 0) ;
+
+  return ;
+}
+
diff --git a/cbits/coin/CoinPresolveImpliedFree.cpp b/cbits/coin/CoinPresolveImpliedFree.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveImpliedFree.cpp
@@ -0,0 +1,1148 @@
+/* $Id: CoinPresolveImpliedFree.cpp 1595 2013-04-19 14:39:06Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveSubst.hpp"
+#include "CoinPresolveIsolated.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveImpliedFree.hpp"
+#include "CoinPresolveUseless.hpp"
+#include "CoinPresolveForcing.hpp"
+#include "CoinMessage.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinSort.hpp"
+#include "CoinFinite.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+/*
+  Implied Free and Subst Transforms
+
+  If there is a constraint i entangled with a singleton column x(t) such
+  that for any feasible (with respect to column bounds) values of the other
+  variables in the constraint we can calculate a feasible value for x(t),
+  then we can drop x(t) and constraint i, since we can compute the value
+  of x(t) from the values of the other variables during postsolve.
+
+  To put this into practice, calculate bounds L(i\t) and U(i\t) on row
+  activity and use those bounds to calculate implied lower and upper
+  bounds l'(t) and u'(t) on x(t). If the implied bounds are tighter than
+  the original column bounds l(t) and u(t) (the implied free condition),
+  we can drop constraint i and x(t).
+
+  If x(t) is not a natural singleton, we can still do something similar. Let
+  constraint i be an equality constraint that satisfies the implied free
+  condition.  In that case, we use constraint i to generate a substitution
+  formula and substitute away x(t) in any other constraints where it appears.
+  This introduces new coefficients, but the total number of coefficients
+  never increases if x(t) is entangled with only two constraints
+  (coefficients added during substitution are cancelled by dropping
+  constraint i). The total may not increase much even if there are more.
+
+  Both situations are detected in implied_free_action::presolve. Natural
+  singletons are processed by implied_free_action::presolve. The rest are
+  passed to subst_constraint_action (which see).
+
+  It is possible for two singleton columns to be in the same row.  In that
+  case, the other one will become empty.  If its bounds and costs aren't
+  just right, this signals an unbounded problem.  We don't need to check
+  that specially here.
+
+  There is a superficial (and misleading) similarity to a useless constraint.
+  A useless constraint cannot be made tight for *any* feasible values of
+  its variables.  Here, it's possible we could pick some feasible value
+  of x(t) that *would* violate the constraint.
+*/
+
+
+/*
+  Scan for candidates for the implied free and subst transforms (see
+  comments at head of file and in CoinPresolveSubst.cpp). Process natural
+  singletons. Pass more complicated cases to subst_constraint_action.
+
+  fill_level limits the allowable number of coefficients in a column under
+  consideration as the implied free variable. There's a feedback loop between
+  implied_free_action and the presolve driver.  The feedback loop operates
+  as follows: If we're not finding enough transforms and fill_level <
+  maxSubstLevel_, increase it by one and pass it back out negated. The
+  presolve driver can act on this, if it chooses, or simply pass it back
+  in on the next call to implied_free_action.  If implied_free_action sees
+  a negative value, it will look at all columns, instead of just those
+  in colsToDo_.
+*/
+
+const CoinPresolveAction *implied_free_action::presolve (
+    CoinPresolveMatrix *prob, const CoinPresolveAction *next, int &fill_level)
+{
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering implied_free_action::presolve, fill level " << fill_level
+    << "." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  const int startEmptyRows = prob->countEmptyRows() ;
+  const int startEmptyColumns = prob->countEmptyCols() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0 ;
+  if (prob->tuning_) startTime = CoinCpuTime() ;
+# endif
+# endif
+
+/*
+  Unpack the row- and column-major representations.
+*/
+  const int m = prob->nrows_ ;
+  const int n = prob->ncols_ ;
+
+  const CoinBigIndex *rowStarts = prob->mrstrt_ ;
+  int *rowLengths = prob->hinrow_ ;
+  const int *colIndices = prob->hcol_ ;
+  const double *rowCoeffs = prob->rowels_ ;
+  presolvehlink *rlink = prob->rlink_ ;
+
+  CoinBigIndex *colStarts = prob->mcstrt_ ;
+  int *colLengths = prob->hincol_ ;
+  int *rowIndices = prob->hrow_ ;
+  double *colCoeffs = prob->colels_ ;
+  presolvehlink *clink = prob->clink_ ;
+
+/*
+  Column bounds, row bounds, cost, integrality.
+*/
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+  double *cost = prob->cost_ ;
+  const unsigned char *integerType = prob->integerType_ ;
+
+/*
+  Documented as `inhibit x+y+z = 1 mods'.  From the code below, it's clear
+  that this is intended to avoid removing SOS equalities with length >= 5
+  (hardcoded). 
+*/
+  const bool stopSomeStuff = ((prob->presolveOptions()&0x04) != 0) ;
+/*
+  Ignore infeasibility. `Fix' is overly optimistic.
+*/
+  const bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+/*
+  Defaults to 0.0.
+*/
+  const double feasTol = prob->feasibilityTolerance_ ;
+
+# if 0  
+/*
+  Tentatively moved to be a front-end function for useless_constraint_action,
+  much as make_fixed is a front-end for make_fixed_action. This bit of code
+  left for possible tuning.
+  -- lh, 121127 --
+
+  Original comment: This needs to be made faster.
+*/
+# ifdef COIN_LIGHTWEIGHT_PRESOLVE
+  if (prob->pass_ == 1) {
+# endif
+    next = testRedundant(prob,next) ;
+    if (prob->status_&0x01 != 0) {
+      if ((prob->presolveOptions_&0x4000) != 0)
+        prob->status &= !0x01 ;
+      else
+	return (next) ;
+    }
+# ifdef COIN_LIGHTWEIGHT_PRESOLVE
+  }
+# endif
+# endif
+
+/*
+  implied_free and subst take a fair bit of effort to scan for candidates.
+  This is a hook to allow a presolve driver to avoid that work.
+*/
+  if (prob->pass_ > 15 && (prob->presolveOptions_&0x10000) != 0) { 
+    fill_level = 2 ;
+    return (next) ;
+  }
+
+/*
+  Set up to collect implied_free actions.
+*/
+  action *actions = new action [n] ;
+# ifdef ZEROFAULT
+  CoinZeroN(reinterpret_cast<char *>(actions),n*sizeof(action)) ;
+# endif
+  int nactions = 0 ;
+
+  int *implied_free = prob->usefulColumnInt_ ;
+  int *whichFree = implied_free+n ;
+  int numberFree = 0 ;
+/*
+  Arrays to hold row activity (row lhs) min and max values. Each row lhs bound
+  is held as two components: a sum of finite column bounds and a count of
+  infinite column bounds.
+*/
+  int *infiniteDown = new int[m] ;
+  int *infiniteUp = new int[m] ;
+  double *maxDown = new double[m] ;
+  double *maxUp = new double[m] ;
+/*
+  Overload infiniteUp with row status codes:
+  -1: L(i)/U(i) not yet computed,
+  -2: do not use (empty or useless row),
+  -3: give up (infeasible)
+  -4: chosen as implied free row
+*/
+  for (int i = 0 ; i < m ; i++) {
+    if (rowLengths[i] > 1)
+      infiniteUp[i] = -1 ;
+    else
+      infiniteUp[i] = -2 ;
+  }
+  // Get rid of rows with prohibited columns
+  if (prob->anyProhibited_) {
+    for (int i = 0 ; i < m ; i++) {
+      CoinBigIndex rStart = rowStarts[i];
+      CoinBigIndex rEnd = rStart+rowLengths[i];
+      bool badRow=false;
+      for (CoinBigIndex j = rStart; j < rEnd; ++j) {
+	if (prob->colProhibited(colIndices[j])) {
+	  badRow=true;
+	  break;
+	}
+      }
+      if (badRow)
+	infiniteUp[i] = -2 ;
+    }
+  }
+
+// Can't go on without a suitable finite infinity, can we?
+#ifdef USE_SMALL_LARGE
+  const double large = 1.0e10 ;
+#else
+  const double large = 1.0e20 ;
+#endif
+
+/*
+  Decide which columns we're going to look at. There are columns already queued
+  in colsToDo_, but sometimes we want to look at all of them. Don't suck in
+  prohibited columns. See comments at the head of the routine for fill_level.
+
+  NOTE the overload on usefulColumnInt_. It was assigned above to whichFree
+       (indices of interesting columns). We'll be ok because columns are
+       consumed out of look at one per main loop iteration, but not all
+       columns are interesting.
+
+  Original comment: if gone from 2 to 3 look at all
+*/
+  int numberLook = prob->numberColsToDo_ ;
+  int iLook ;
+  int *look = prob->colsToDo_ ;
+  if (fill_level < 0) {
+    look = prob->usefulColumnInt_+n ;
+    if (!prob->anyProhibited()) {
+      CoinIotaN(look,n,0) ;
+      numberLook = n ;
+    } else {
+      numberLook = 0 ;
+      for (iLook = 0 ; iLook < n ; iLook++) 
+	if (!prob->colProhibited(iLook))
+	  look[numberLook++] = iLook ;
+    }
+  }
+/*
+  Step through the columns of interest looking for suitable x(tgt).
+
+  Interesting columns are limited by number of nonzeros to minimise fill-in
+  during substitution.
+*/
+  bool infeas = false ;
+  const int maxLook = abs(fill_level) ;
+  for (iLook = 0 ; iLook < numberLook ; iLook++) {
+    const int tgtcol = look[iLook] ;
+    const int tgtcol_len = colLengths[tgtcol] ;
+
+    if (tgtcol_len <= 0 || tgtcol_len > maxLook) continue ;
+/*
+  Set up to reconnoiter the column.
+
+  The initial value for ait_max is chosen to make sure that anything that
+  satisfies the stability check is big enough to use (though we'd clearly like
+  something better).
+*/
+    const CoinBigIndex kcs = colStarts[tgtcol] ;
+    const CoinBigIndex kce = kcs+tgtcol_len ;
+    const bool singletonCol = (tgtcol_len == 1) ;
+    bool possibleRow = false ;
+    bool singletonRow = false ;
+    double ait_max = 20*ZTOLDP2 ;
+/*
+  If this is a singleton column, the only concern is that the row is not a
+  singleton row (that has its own, simpler, transform: slack_doubleton). But
+  make sure we're not dealing with some tiny a(it).
+
+  Note that there's no point in marking a singleton row. By definition, we
+  won't encounter it again.
+*/
+    if (singletonCol) {
+      const int i = rowIndices[kcs] ;
+      singletonRow = (rowLengths[i] == 1) ;
+      possibleRow = (fabs(colCoeffs[kcs]) > ZTOLDP2) ;
+    } else {
+      
+/*
+  If the column is not a singleton, we'll need a numerically stable
+  substitution formula. Check that this is possible.  One of the entangled
+  rows must be an equality with a numerically stable coefficient, at least
+  .1*MAX{i}a(it).
+*/
+      for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
+	const int i = rowIndices[kcol] ;
+	if (rowLengths[i] == 1) {
+	  singletonRow = true ;
+	  break ;
+	}
+	const double abs_ait = fabs(colCoeffs[kcol]) ;
+	ait_max = CoinMax(ait_max,abs_ait) ;
+	if (fabs(rlo[i]-rup[i]) < feasTol && abs_ait > .1*ait_max) {
+	  possibleRow = true ;
+	}
+      }
+    }
+    if (singletonRow || !possibleRow) continue ;
+/*
+  The column has possibilities. Walk the column, calculate row activity
+  bounds L(i) and U(i) for suitable entangled rows, then calculate the
+  improvement (if any) on the column bounds for l(j) and u(j). The goal is to
+  satisfy the implied free condition over all entangled rows and find at least
+  one row suitable for a substitution formula (if the column is not a natural
+  singleton).
+
+  Suitable: If this is a natural singleton, we need to look at the single
+  entangled constraint.  If we're attempting to create a singleton by
+  substitution, only look at equalities with stable coefficients. If x(t) is
+  integral, make sure the scaled rhs will be integral.
+*/
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  Checking x(" << tgtcol << "), " << tgtcol_len << " nonzeros"
+      << ", l(" << tgtcol << ") " << clo[tgtcol] << ", u(" << tgtcol
+      << ") " << cup[tgtcol] << ", c(" << tgtcol << ") " << cost[tgtcol]
+      << "." << std::endl ;
+#   endif
+    const double lt = clo[tgtcol] ;
+    const double ut = cup[tgtcol] ;
+    double impliedLow = -COIN_DBL_MAX ;
+    double impliedHigh = COIN_DBL_MAX ;
+    int subst_ndx = -1 ;
+    int subst_len = n ;
+    for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
+      const int i = rowIndices[kcol] ;
+
+      assert(infiniteUp[i] != -3) ;
+      if (infiniteUp[i] <= -2) continue ;
+
+      const double ait = colCoeffs[kcol] ;
+      const int leni = rowLengths[i] ;
+      const double rloi = rlo[i] ;
+      const double rupi = rup[i] ;
+/*
+  A suitable row for substitution must
+    * be an equality;
+    * the entangled coefficient must be large enough to be numerically stable;
+    * if x(t) is integer, the constant term in the substitution formula must be
+      integer.
+*/
+      bool rowiOK = (fabs(rloi-rupi) < feasTol) && (fabs(ait) > .1*ait_max) ;
+      rowiOK = rowiOK && ((integerType[tgtcol] == 0) ||
+                          (fabs((rloi/ait)-floor((rloi/ait)+0.5)) < feasTol)) ;
+/*
+  If we don't already have L(i) and U(i), calculate now. Check for useless and
+  infeasible constraints when that's done.
+*/
+      int infUi = 0 ;
+      int infLi = 0 ;
+      double maxUi = 0.0 ;
+      double maxLi = 0.0 ;
+      const CoinBigIndex krs = rowStarts[i] ;
+      const CoinBigIndex kre = krs+leni ;
+
+      if (infiniteUp[i] == -1) {
+	for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
+	  const double aik = rowCoeffs[krow] ;
+	  const int k = colIndices[krow] ;
+	  const double lk = clo[k] ;
+	  const double uk = cup[k] ;
+	  if (aik > 0.0) {
+	    if (uk < large) 
+	      maxUi += uk*aik ;
+	    else
+	      ++infUi ;
+	    if (lk > -large) 
+	      maxLi += lk*aik ;
+	    else
+	      ++infLi ;
+	  } else if (aik < 0.0) {
+	    if (uk < large) 
+	      maxLi += uk*aik ;
+	    else
+	      ++infLi ;
+	    if (lk > -large) 
+	      maxUi += lk*aik ;
+	    else
+	      ++infUi ;
+	  }
+	}
+	const double maxUinf = maxUi+infUi*1.0e31 ;
+	const double maxLinf = maxLi-infLi*1.0e31 ;
+	if (maxUinf <= rupi+feasTol && maxLinf >= rloi-feasTol) {
+	  infiniteUp[i] = -2 ;
+	} else if (maxUinf < rloi-feasTol && !fixInfeasibility) {
+	  prob->status_|= 1 ;
+	  infeas = true ;
+	  prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
+					  prob->messages())
+	    << i << rloi << rupi << CoinMessageEol ;
+	  infiniteUp[i] = -3 ;
+	} else if (maxLinf > rupi+feasTol && !fixInfeasibility) {
+	  prob->status_|= 1 ;
+	  infeas = true ;
+	  prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
+					  prob->messages())
+	    << i << rloi << rupi << CoinMessageEol ;
+	  infiniteUp[i] = -3 ;
+	} else {
+	  infiniteUp[i] = infUi ;
+	  infiniteDown[i] = infLi ;
+	  maxUp[i] = maxUi ;
+	  maxDown[i] = maxLi ;
+	}
+      } else {
+        infUi = infiniteUp[i] ;
+	infLi = infiniteDown[i] ;
+	maxUi = maxUp[i] ;
+	maxLi = maxDown[i] ;
+      }
+#     if PRESOLVE_DEBUG > 2
+      std::cout
+        << "    row(" << i << ") " << leni << " nonzeros, blow " << rloi
+	<< ", L (" << infLi << "," << maxLi
+	<< "), U (" << infUi << "," << maxUi
+	<< "), b " << rupi ;
+      if (infeas) std::cout << " infeas" ;
+      if (infiniteUp[i] == -2) std::cout << " useless" ;
+      std::cout << "." << std::endl ;
+#     endif
+/*
+  If we're infeasible, no sense checking further; escape the implied bound
+  loop. The other possibility is that we've just discovered the constraint
+  is useless, in which case we just move on to the next one in the column.
+*/
+      if (infeas) break ;
+      if (infiniteUp[i] == -2) continue ;
+      assert(infiniteUp[i] >= 0 && infiniteUp[i] <= leni) ;
+/*
+  At this point we have L(i) and U(i), expressed as finite and infinite
+  components, and constraint i is neither useless or infeasible. Calculate
+  the implied bounds l'(t) and u'(t) on x(t). The calculation (for a(it) > 0)
+  is
+    u'(t) <= (b(i) - (L(i)-a(it)l(t)))/a(it) = l(t)+(b(i)-L(i))/a(it)
+    l'(t) >= (blow(i) - (U(i)-a(it)u(t)))/a(it) = u(t)+(blow(i)-U(i))/a(it)
+  Insert the appropriate flips for a(it) < 0. Notice that if there's exactly
+  one infinite contribution to L(i) or U(i) and x(t) is responsible, then the
+  finite portion of L(i) or U(i) is already correct.
+
+  Cut some slack for possible numerical inaccuracy if the finite portion of
+  L(i) or U(i) is very large. If the new bound is very large, force it to
+  infinity.
+*/
+      double ltprime = -COIN_DBL_MAX ;
+      double utprime = COIN_DBL_MAX ;
+      if (ait > 0.0) {
+	if (rloi > -large) {
+	  if (!infUi) {
+	    assert(ut < large) ;
+	    ltprime = ut+(rloi-maxUi)/ait ;
+	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
+	      ltprime -= 1.0e-12*fabs(maxUi) ;
+	  } else if (infUi == 1 && ut > large) {
+	    ltprime = (rloi-maxUi)/ait ;
+	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
+	      ltprime -= 1.0e-12*fabs(maxUi) ;
+	  } else {
+	    ltprime = -COIN_DBL_MAX ;
+	  }
+	  impliedLow = CoinMax(impliedLow,ltprime) ;
+	}
+	if (rupi < large) {
+	  if (!infLi) {
+	    assert(lt > -large) ;
+	    utprime = lt+(rupi-maxLi)/ait ;
+	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
+	      utprime += 1.0e-12*fabs(maxLi) ;
+	  } else if (infLi == 1 && lt < -large) {
+	    utprime = (rupi-maxLi)/ait ;
+	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
+	      utprime += 1.0e-12*fabs(maxLi) ;
+	  } else {
+	    utprime = COIN_DBL_MAX ;
+	  }
+	  impliedHigh = CoinMin(impliedHigh,utprime) ;
+	}
+      } else {
+	if (rloi > -large) {
+	  if (!infUi) {
+	    assert(lt > -large) ;
+	    utprime = lt+(rloi-maxUi)/ait ;
+	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
+	      utprime += 1.0e-12*fabs(maxUi) ;
+	  } else if (infUi == 1 && lt < -large) {
+	    utprime = (rloi-maxUi)/ait ;
+	    if (fabs(maxUi) > 1.0e8 && !singletonCol)
+	      utprime += 1.0e-12*fabs(maxUi) ;
+	  } else {
+	    utprime = COIN_DBL_MAX ;
+	  }
+	  impliedHigh = CoinMin(impliedHigh,utprime) ;
+	}
+	if (rupi < large) {
+	  if (!infLi) {
+	    assert(ut < large) ;
+	    ltprime = ut+(rupi-maxLi)/ait ;
+	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
+	      ltprime -= 1.0e-12*fabs(maxLi) ;
+	  } else if (infLi == 1 && ut > large) {
+	    ltprime = (rupi-maxLi)/ait ;
+	    if (fabs(maxLi) > 1.0e8 && !singletonCol)
+	      ltprime -= 1.0e-12*fabs(maxLi) ;
+	  } else {
+	    ltprime = -COIN_DBL_MAX ;
+	  }
+	  impliedLow = CoinMax(impliedLow,ltprime) ;
+	}
+      }
+#     if PRESOLVE_DEBUG > 2
+      std::cout
+        << "    row(" << i << ") l'(" << tgtcol << ") " << ltprime
+	<< ", u'(" << tgtcol << ") " << utprime ;
+      if (lt <= impliedLow && impliedHigh <= ut)
+	std::cout << "; implied free satisfied" ;
+      std::cout << "." << std::endl ;
+#     endif
+/*
+  For x(t) integral, see if a substitution formula based on row i will
+  preserve integrality.  The final check in this clause aims to preserve
+  SOS equalities (i.e., don't eliminate a non-trivial SOS equality from
+  the system using this transform).
+
+  Note that this can't be folded into the L(i)/U(i) loop because the answer
+  changes with x(t).
+
+  Original comment: can only accept if good looking row
+*/
+      if (integerType[tgtcol]) {
+	possibleRow = true ;
+	bool allOnes = true ;
+	for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
+	  const int j = colIndices[krow] ;
+	  const double scaled_aij = rowCoeffs[krow]/ait ;
+	  if (fabs(scaled_aij) != 1.0)
+	    allOnes = false ;
+	  if (!integerType[j] ||
+	      fabs(scaled_aij-floor(scaled_aij+0.5)) > feasTol) {
+	    possibleRow = false ;
+	    break ;
+	  }
+	}
+	if (rloi == 1.0 && leni >= 5 && stopSomeStuff && allOnes)
+	  possibleRow = false ;
+	rowiOK = rowiOK && possibleRow ;
+      }
+/*
+  Do we have a winner? If we have an incumbent, prefer the one with fewer
+  coefficients.
+*/
+      if (rowiOK) {
+	if (subst_ndx < 0 || (leni < subst_len)) {
+#         if PRESOLVE_DEBUG > 2
+          std::cout
+	    << "    row(" << i << ") now candidate for x(" << tgtcol << ")."
+	    << std::endl ;
+#         endif
+	  subst_ndx = i ;
+	  subst_len = leni ;
+	}
+      }
+    }
+
+    if (infeas) break ;
+/*
+  Can we do the transform? If so, subst_ndx will have a valid row.
+  Record the implied free variable and the equality we'll use to substitute
+  it out. Take the row out of the running --- we can't use the same row
+  for two substitutions.
+*/
+    if (lt <= impliedLow && impliedHigh <= ut &&
+        (subst_ndx >= 0 || singletonRow)) {
+      implied_free[numberFree] = subst_ndx ;
+      infiniteUp[subst_ndx] = -4 ;
+      whichFree[numberFree++] = tgtcol ;
+#     if PRESOLVE_DEBUG > 1
+      std::cout
+        << "  x(" << tgtcol << ") implied free by row " << subst_ndx
+	<< std::endl ;
+#     endif
+    }
+  }
+
+  delete[] infiniteDown ;
+  delete[] infiniteUp ;
+  delete[] maxDown ;
+  delete[] maxUp ;
+
+/*
+  If we're infeasible, there's nothing more to be done.
+*/
+  if (infeas) {
+#   if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0
+    std::cout << "  IMPLIED_FREE: infeasible." << std::endl ;
+#   endif
+    return (next) ;
+  }
+
+/*
+  We have a list of implied free variables, each with a row that can be used
+  to substitute the variable to singleton status if the variable is not a
+  natural singleton. The loop here will only process natural singletons.
+  We'll hand the remainder to subst_constraint_action below, if there is
+  a remainder.
+
+  The natural singletons processed here are compressed out of whichFree and
+  implied_free.
+*/
+  int unprocessed = 0 ;
+  for (iLook = 0 ; iLook < numberFree ; iLook++) {
+    const int tgtcol = whichFree[iLook] ;
+
+    if (colLengths[tgtcol] != 1) {
+      whichFree[unprocessed] = whichFree[iLook] ;
+      implied_free[unprocessed] = implied_free[iLook] ;
+      unprocessed++ ;
+      continue ;
+    }
+
+    const int tgtrow = implied_free[iLook] ;
+    const int tgtrow_len = rowLengths[tgtrow] ;
+
+    const CoinBigIndex kcs = colStarts[tgtcol] ;
+    const double tgtcol_coeff = colCoeffs[kcs] ;
+    const double tgtcol_cost = cost[tgtcol] ;
+
+    const CoinBigIndex krs = rowStarts[tgtrow] ;
+    const CoinBigIndex kre = krs+tgtrow_len ;
+    if (tgtcol_cost != 0.0) {
+      // Check costs don't make unstable
+      //double minOldCost=COIN_DBL_MAX;
+      double maxOldCost=0.0;
+      //double minNewCost=COIN_DBL_MAX;
+      double maxNewCost=0.0;
+      for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
+	const int j = colIndices[krow] ;
+	if (j != tgtcol) {
+	  double oldCost = cost[j] ;
+	  double newCost = oldCost - (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ;
+	  oldCost = fabs(oldCost);
+	  newCost = fabs(newCost);
+	  //minOldCost=CoinMin(minOldCost,oldCost);
+	  maxOldCost=CoinMax(maxOldCost,oldCost);
+	  //minNewCost=CoinMin(minNewCost,newCost);
+	  maxNewCost=CoinMax(maxNewCost,newCost);
+	}
+      }
+      if (maxNewCost>1000.0*(maxOldCost+1.0) /*&& maxOldCost*/) {
+	//printf("too big %d tgtcost %g maxOld %g maxNew %g\n",
+	//     tgtcol,tgtcol_cost,maxOldCost,maxNewCost);
+	continue;
+      }
+    }
+/*
+  Initialise the postsolve action. We need to remember the row and column.
+*/
+    action *s = &actions[nactions++] ;
+    s->row = tgtrow ;
+    s->col = tgtcol ;
+    s->clo = clo[tgtcol] ;
+    s->cup = cup[tgtcol] ;
+    s->rlo = rlo[tgtrow] ;
+    s->rup = rup[tgtrow] ;
+    s->ninrow = tgtrow_len ;
+    s->rowels = presolve_dupmajor(rowCoeffs,colIndices,tgtrow_len,krs) ;
+    s->costs = NULL ;
+/*
+  We're processing a singleton, hence no substitutions in the matrix, but we
+  do need to fix up the cost vector. The substitution formula is
+    x(t) = (rhs(i) - SUM{j\t}a(ik)x(k))/a(it)
+  hence
+    c'(k) = c(k)-c(t)a(ik)/a(it)
+  and there's a constant offset
+    c(t)rhs(i)/a(it).
+  where rhs(i) is one of blow(i) or b(i).
+
+  For general constraints where blow(i) != b(i), we need to take a bit
+  of care. If only one of blow(i) or b(i) is finite, that's the one to
+  use. Where we have two finite but unequal bounds, choose the bound that
+  will result in the most favourable value for x(t). For minimisation, if
+  c(t) < 0 we want to maximise x(t), so choose b(i) if a(it) > 0, blow(i)
+  if a(it) < 0.  A bit of case analysis says choose b(i) when c(t)a(it) <
+  0, blow(i) when c(t)a(it) > 0. We shouldn't be here if both row bounds
+  are infinite.
+
+  Fortunately, the objective coefficients are not affected by this.
+*/
+    if (tgtcol_cost != 0.0) {
+      double tgtrow_rhs = rup[tgtrow] ;
+      if (fabs(rlo[tgtrow]-rup[tgtrow]) > feasTol) {
+	const double rlot = rlo[tgtrow] ;
+	const double rupt = rup[tgtrow] ;
+        if (rlot > -COIN_DBL_MAX && rupt < COIN_DBL_MAX) {
+	  if ((tgtcol_cost*tgtcol_coeff) > 0)
+	    tgtrow_rhs = rlot ;
+	  else
+	    tgtrow_rhs = rupt ;
+	} else if (rupt >= COIN_DBL_MAX) {
+	  tgtrow_rhs = rlot ;
+	}
+      }
+      assert(fabs(tgtrow_rhs) <= large) ;
+      double *save_costs = new double[tgtrow_len] ;
+
+      for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
+	const int j = colIndices[krow] ;
+	save_costs[krow-krs] = cost[j] ;
+	cost[j] -= (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ;
+      }
+      prob->change_bias((tgtcol_cost*tgtrow_rhs)/tgtcol_coeff) ;
+      cost[tgtcol] = 0.0 ;
+      s->costs = save_costs ;
+    }
+/*
+  Remove the row from the column-major representation, queuing up each column
+  for reconsideration. Then remove the row from the row-major representation.
+*/
+    for (CoinBigIndex krow = krs ; krow < kre ; krow++) {
+      const int j = colIndices[krow] ;
+      presolve_delete_from_col(tgtrow,j,colStarts,colLengths,rowIndices,
+      			       colCoeffs) ;
+      if (colLengths[j] == 0) {
+        PRESOLVE_REMOVE_LINK(prob->clink_,j) ;
+      } else {
+	prob->addCol(j) ;
+      }
+    }
+    PRESOLVE_REMOVE_LINK(clink,tgtcol) ;
+    colLengths[tgtcol] = 0 ;
+
+    PRESOLVE_REMOVE_LINK(rlink,tgtrow) ;
+    rowLengths[tgtrow] = 0 ;
+    rlo[tgtrow] = 0.0 ;
+    rup[tgtrow] = 0.0 ;
+  }
+/*
+  We're done with the natural singletons. Trim actions to length and create
+  the postsolve object.
+*/
+  if (nactions) {
+#   if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0
+    printf("NIMPLIED FREE:  %d\n", nactions) ;
+#   endif
+    action *actions1 = new action[nactions] ;
+    CoinMemcpyN(actions, nactions, actions1) ;
+    next = new implied_free_action(nactions,actions1,next) ;
+  } 
+  delete [] actions ;
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "  IMPLIED_FREE: identified " << numberFree
+    << " implied free transforms, processed " << numberFree-unprocessed
+    << " natural singletons." << std::endl ;
+# endif
+
+/*
+  Now take a stab at the columns that aren't natural singletons, if there are
+  any left.
+*/
+  if (unprocessed != 0) {
+    next = subst_constraint_action::presolve(prob,implied_free,whichFree,
+    					     unprocessed,next,maxLook) ;
+  }
+/*
+  Give some feedback to the presolve driver. If we aren't finding enough
+  candidates and haven't reached the limit, bump fill_level and return a
+  negated value. The presolve driver can tweak this value or simply return
+  it on the next call. See the top of the routine for a full explanation.
+*/
+  if (numberFree < 30 && maxLook < prob->maxSubstLevel_) {
+    fill_level = -(maxLook+1) ;
+  } else {
+    fill_level = maxLook ;
+  }
+
+# if COIN_PRESOLVE_TUNING > 0
+  double thisTime ;
+  if (prob->tuning_) thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving implied_free_action::presolve, fill level " << fill_level
+    << ", " << droppedRows << " rows, "
+    << droppedColumns << " columns dropped" ;
+# if COIN_PRESOLVE_TUNING > 0
+  std::cout << " in " << thisTime-startTime << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+
+const char *implied_free_action::name() const
+{
+  return ("implied_free_action") ;
+}
+
+
+/*
+  Restore the target constraint and target column x(t) eliminated by the
+  implied free presolve action. We'll solve the target constraint to get a
+  value for x(t), so by construction the constraint is tight.
+
+  For range constraints, we need to consider both the upper and lower row
+  bounds when calculating a value for x(t). x(t) can end up at one of its
+  column bounds or strictly between bounds.
+
+  Then there's the matter of patching up the basis and solution. The
+  natural thing to do is to make the logical nonbasic and x(t) basic.
+  No corrections to duals or reduced costs are required because we built
+  that correction into the problem when we modified the objective. Work the
+  linear algebra; it's very neat.
+  
+  It will frequently happen that the implied bounds on x(t) are simply equal
+  to the existing column bounds and the value we calculate here will be at
+  one of the original column bounds. This leaves x(t) degenerate basic. The
+  original version of this routine looked for this and attempted to make
+  x(t) nonbasic and use the logical as the basic variable. The linear
+  algebra for this is ugly. To calculate the proper correction for the dual
+  variables requires the basis inverse (terms do not conveniently cancel).
+  The original code made no attempt to fix the duals and applied a correction
+  to the reduced costs that was valid only for the nonbasic partition. It
+  accepted the result if it was dual feasible. In general this would leave
+  slack dual constraints. It's really not possible to predict the effect
+  going forward on subsequent postsolve transforms. Nor is it clear to
+  me that a degenerate basic architectural is inherently worse than a
+  degenerate basic logical. This version of the code always makes x(t) basic.
+*/
+
+  
+
+void implied_free_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_ ;
+  const int nactions = nactions_ ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  char *cdone	= prob->cdone_ ;
+  char *rdone	= prob->rdone_ ;
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering implied_free_action::postsolve, " << nactions
+    << " transforms to undo." << std::endl ;
+# endif
+  presolve_check_threads(prob) ;
+  presolve_check_free_list(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+/*
+  Unpack the column-major representation.
+*/
+  CoinBigIndex *colStarts = prob->mcstrt_ ;
+  int *colLengths = prob->hincol_ ;
+  int *rowIndices = prob->hrow_ ;
+  double *colCoeffs = prob->colels_ ;
+  CoinBigIndex *link = prob->link_ ;
+  CoinBigIndex &free_list = prob->free_list_ ;
+/*
+  Column bounds, row bounds, and cost.
+*/
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+  double *cost = prob->cost_ ;
+/*
+  Solution, reduced costs, duals, row activity.
+*/
+  double *sol = prob->sol_ ;
+  double *rcosts = prob->rcosts_ ;
+  double *acts = prob->acts_ ;
+  double *rowduals = prob->rowduals_ ;
+/*
+  In your dreams ... hardwired to minimisation.
+*/
+  const double maxmin = 1.0 ;
+/*
+  And a suitably small infinity.
+*/
+  const double large = 1.0e20 ;
+/*
+  Open a loop to restore the row and column for each action. Start by
+  unpacking the action. There won't be saved costs if the original cost c(t)
+  was zero.
+*/
+  for (const action *f = &actions[nactions-1] ; actions <= f ; f--) {
+
+    const int tgtrow = f->row ;
+    const int tgtcol = f->col ;
+    const int tgtrow_len = f->ninrow ;
+    const double *tgtrow_coeffs = f->rowels ;
+    const int *tgtrow_cols =
+        reinterpret_cast<const int *>(tgtrow_coeffs+tgtrow_len) ;
+    const double *saved_costs = f->costs ;
+
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  restoring col " << tgtcol << " row " << tgtrow ;
+    if (saved_costs != 0) std::cout << ", modified costs" ;
+    std::cout << "." << std::endl ;
+#   endif
+
+/*
+  Restore the target row and column and the original cost coefficients.
+  We need to initialise the target column; for others, just bump the
+  coefficient count. While we're restoring the row, pick off the coefficient
+  for x(t) and calculate the row activity.
+*/
+    double tgt_coeff = 0.0 ;
+    double tgtrow_act = 0.0 ;
+    for (int krow = 0 ; krow < tgtrow_len ; krow++) {
+      const int j = tgtrow_cols[krow] ;
+      const double atj = tgtrow_coeffs[krow] ;
+
+      assert(free_list >= 0 && free_list < prob->bulk0_) ;
+      CoinBigIndex kk = free_list ;
+      free_list = link[free_list] ;
+      link[kk] = colStarts[j] ;
+      colStarts[j] = kk ;
+      colCoeffs[kk] = atj ;
+      rowIndices[kk] = tgtrow ;
+
+      if (saved_costs) cost[j] = saved_costs[krow] ;
+
+      if (j == tgtcol) {
+	colLengths[j] = 1 ;
+	clo[tgtcol] = f->clo ;
+	cup[tgtcol] = f->cup ;
+	rcosts[j] = -cost[tgtcol]/atj ;
+	tgt_coeff = atj ;
+      } else {
+	colLengths[j]++ ;
+	tgtrow_act += atj*sol[j] ;
+      }
+    }
+    rlo[tgtrow] = f->rlo ;
+    rup[tgtrow] = f->rup ;
+
+    PRESOLVEASSERT(fabs(tgt_coeff) > ZTOLDP) ;
+#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+    cdone[tgtcol] = IMPLIED_FREE ;
+    rdone[tgtrow] = IMPLIED_FREE ;
+#   endif
+#   if PRESOLVE_CONSISTENCY > 0
+    presolve_check_free_list(prob) ;
+#   endif
+/*
+  Calculate a value for x(t).  We have two possible values for x(t),
+  calculated against the upper and lower bound of the constraint. x(t)
+  could end up at one of its original bounds or it could end up strictly
+  within bounds. In either event, the constraint will be tight.
+
+  The code simply forces the calculated value for x(t) to be within
+  bounds. Arguably it should complain more loudly as this likely indicates
+  algorithmic error or numerical inaccuracy. You'll get a warning if
+  debugging is enabled.
+*/
+    double xt_lo,xt_up ;
+    if (tgt_coeff > 0) {
+      xt_lo = (rlo[tgtrow]-tgtrow_act)/tgt_coeff ;
+      xt_up = (rup[tgtrow]-tgtrow_act)/tgt_coeff ;
+    } else {
+      xt_lo = (rup[tgtrow]-tgtrow_act)/tgt_coeff ;
+      xt_up = (rlo[tgtrow]-tgtrow_act)/tgt_coeff ;
+    }
+    const double lt = clo[tgtcol] ;
+    const double ut = cup[tgtcol] ;
+
+#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+    bool chklo = true ;
+    bool chkup = true ;
+    if (tgt_coeff > 0) {
+      if (rlo[tgtrow] < -large) chklo = false ;
+      if (rup[tgtrow] > large) chkup = false ;
+    } else {
+      if (rup[tgtrow] > large) chklo = false ;
+      if (rlo[tgtrow] < -large) chkup = false ;
+    }
+    if (chklo && (xt_lo < lt-prob->ztolzb_)) {
+      std::cout
+        << "  LOW CSOL (implied_free): x(" << tgtcol << ") lb " << lt
+	<< ", sol = " << xt_lo << ", err " << (lt-xt_lo)
+	<< "." << std::endl ;
+    }
+    if (chkup && (xt_up > ut+prob->ztolzb_)) {
+      std::cout
+        << "  HIGH CSOL (implied_free): x(" << tgtcol << ") ub " << ut
+	<< ", sol = " << xt_up << ", err " << (xt_up-ut)
+	<< "." << std::endl ;
+    }
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  x(" << tgtcol << ") lb " << lt << " lo " << xt_lo
+      << ", up " << xt_up << " ub " << ut << "." << std::endl ;
+#   endif
+#   endif
+
+    xt_lo = CoinMax(xt_lo,lt) ;
+    xt_up = CoinMin(xt_up,ut) ;
+
+/*
+  Time to make x(t) basic and the logical nonbasic.  The sign of the
+  dual determines the tight row bound, which in turn determines the value
+  of x(t). Because the row is tight, activity is by definition equal to
+  the bound.
+
+  Coin convention is that a <= constraint puts a lower bound on the slack and
+  a >= constraint puts an upper bound on the slack. Case analysis
+  (minimisation) says:
+
+  dual >= 0 ==> reduced cost <= 0 ==> NBUB ==> finite rlo
+  dual <= 0 ==> reduced cost >= 0 ==> NBLB ==> finite rup
+*/
+    const double ct = maxmin*cost[tgtcol] ;
+    double possibleDual = ct/tgt_coeff ;
+    rowduals[tgtrow] = possibleDual ;
+    if (possibleDual >= 0 && rlo[tgtrow] > -large) {
+      sol[tgtcol] = (rlo[tgtrow]-tgtrow_act)/tgt_coeff ;
+      acts[tgtrow] = rlo[tgtrow] ;
+      prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atUpperBound) ;
+    } else
+    if (possibleDual <= 0 && rup[tgtrow] < large) {
+      sol[tgtcol] = (rup[tgtrow]-tgtrow_act)/tgt_coeff ;
+      acts[tgtrow] = rup[tgtrow] ;
+      prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atLowerBound) ;
+    } else {
+      assert(rup[tgtrow] < large || rlo[tgtrow] > -large) ;
+      if (rup[tgtrow] < large) {
+	sol[tgtcol] = (rup[tgtrow]-tgtrow_act)/tgt_coeff ;
+	acts[tgtrow] = rup[tgtrow] ;
+	prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atLowerBound) ;
+      } else {
+	sol[tgtcol] = (rlo[tgtrow]-tgtrow_act)/tgt_coeff ;
+	acts[tgtrow] = rlo[tgtrow] ;
+	prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atUpperBound) ;
+      }
+#     if PRESOLVE_DEBUG > 0
+      std::cout
+        << "BAD ROW STATUS row " << tgtrow << ": dual "
+	<< rowduals[tgtrow] << " but row "
+	<< ((rowduals[tgtrow] > 0)?"upper":"lower")
+	<< " bound is not finite; forcing status "
+	<< prob->rowStatusString(tgtrow)
+	<< "." << std::endl ;
+#     endif
+    }
+    prob->setColumnStatus(tgtcol,CoinPrePostsolveMatrix::basic) ;
+    rcosts[tgtcol] = 0.0 ;
+
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  x(" << tgtcol << ") B dj " << rcosts[tgtcol] << "." << std::endl ;
+    std::cout
+      << "  row " << tgtrow << " dual " << rowduals[tgtrow] << "."
+      << std::endl ;
+#   endif
+    PRESOLVEASSERT(acts[tgtrow] >= rlo[tgtrow]-1.0e-5 &&
+		   acts[tgtrow] <= rup[tgtrow]+1.0e-5) ;
+
+#   if PRESOLVE_DEBUG > 2
+/*
+   Debug code to compare the reduced costs against a calculation from
+   scratch as c(j)-ya(j).
+*/
+    for (int krow = 0 ; krow < tgtrow_len ; krow++) {
+      const int j = tgtrow_cols[krow] ;
+      const int lenj = colLengths[j] ;
+      double dj = cost[j] ;
+      CoinBigIndex kcol = colStarts[j] ;
+      for (int cntj = 0 ; cntj < lenj ; ++cntj) {
+	const int i = rowIndices[kcol] ;
+	const double aij = colCoeffs[kcol] ;
+	dj -= rowduals[i]*aij ;
+	kcol = link[kcol] ;
+      }
+      if (fabs(dj-rcosts[j]) > 1.0e-3) {
+        std::cout
+	  << "  cbar(" << j << ") update " << rcosts[j]
+	  << " expected " << dj << " err " << fabs(dj-rcosts[j])
+	  << "." << std::endl ;
+      }
+    }
+#   endif
+  }
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving implied_free_action::postsolve." << std::endl ;
+# endif
+# endif
+
+  return ;
+}
+
+
+
+implied_free_action::~implied_free_action() 
+{ 
+  int i ;
+  for (i=0;i<nactions_;i++) {
+    deleteAction(actions_[i].rowels,double *) ;
+    deleteAction( actions_[i].costs,double *) ;
+  }
+  deleteAction(actions_,action *) ;
+}
+
diff --git a/cbits/coin/CoinPresolveImpliedFree.hpp b/cbits/coin/CoinPresolveImpliedFree.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveImpliedFree.hpp
@@ -0,0 +1,60 @@
+/* $Id: CoinPresolveImpliedFree.hpp 1562 2012-11-24 00:36:15Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveImpliedFree_H
+#define CoinPresolveInpliedFree_H
+
+/*!
+  \file
+*/
+
+#define	IMPLIED_FREE	9
+
+/*! \class implied_free_action
+    \brief Detect and process implied free variables
+
+  Consider a singleton variable x (<i>i.e.</i>, a variable involved in only
+  one constraint).  Suppose that the bounds on that constraint, combined with
+  the bounds on the other variables involved in the constraint, are such that
+  even the worst case values of the other variables still imply bounds for x
+  which are tighter than the variable's original bounds. Since x can never
+  reach its upper or lower bounds, it is an implied free variable. Both x and
+  the constraint can be deleted from the problem.
+
+  A similar transform for the case where the variable is not a natural column
+  singleton is handled by #subst_constraint_action.
+*/
+class implied_free_action : public CoinPresolveAction {
+  struct action {
+    int row, col;
+    double clo, cup;
+    double rlo, rup;
+    const double *rowels;
+    const double *costs;
+    int ninrow;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  implied_free_action(int nactions,
+		      const action *actions,
+		      const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions) {}
+
+ public:
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix * prob,
+					 const CoinPresolveAction *next,
+					int & fillLevel);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~implied_free_action();
+};
+
+#endif
diff --git a/cbits/coin/CoinPresolveIsolated.cpp b/cbits/coin/CoinPresolveIsolated.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveIsolated.cpp
@@ -0,0 +1,205 @@
+/* $Id: CoinPresolveIsolated.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveIsolated.hpp"
+#include "CoinHelperFunctions.hpp"
+
+#if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+// Rarely, there may a constraint whose variables only
+// occur in that constraint.
+// In this case it is a completely independent problem.
+// We should be able to solve it right now.
+// Since that is actually not trivial, I'm just going to ignore
+// them and stick them back in at postsolve.
+const CoinPresolveAction *isolated_constraint_action::presolve(CoinPresolveMatrix *prob,
+							    int irow,
+							    const CoinPresolveAction *next)
+{
+  int *hincol	= prob->hincol_;
+  const CoinBigIndex *mcstrt	= prob->mcstrt_;
+  int *hrow	= prob->hrow_;
+  double *colels	= prob->colels_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+
+  const double *rowels	= prob->rowels_;
+  const int *hcol	= prob->hcol_;
+  const CoinBigIndex *mrstrt	= prob->mrstrt_;
+
+  // may be written by useless constraint
+  int *hinrow	= prob->hinrow_;
+
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  CoinBigIndex krs = mrstrt[irow];
+  CoinBigIndex kre = krs + hinrow[irow];
+  
+  double *dcost	= prob->cost_;
+  const double maxmin	= prob->maxmin_;
+
+# if PRESOLVE_DEBUG
+  {
+    printf("ISOLATED:  %d - ", irow);
+    CoinBigIndex k;
+    for ( k = krs; k<kre; ++k)
+      printf("%d ", hcol[k]);
+    printf("\n");
+  }
+# endif
+
+  if (rlo[irow] != 0.0 || rup[irow] != 0.0) {
+#   if PRESOLVE_DEBUG
+    printf("can't handle non-trivial isolated constraints for now\n");
+#   endif
+    return NULL;
+  }
+  CoinBigIndex k;
+  for ( k = krs; k<kre; ++k) {
+    int jcol = hcol[k];
+    if ((clo[jcol] != 0.0 && cup[jcol] != 0.0)||
+        (maxmin*dcost[jcol] > 0.0 && clo[jcol] != 0.0) ||
+        (maxmin*dcost[jcol] < 0.0 && cup[jcol] != 0.0) ){
+#     if PRESOLVE_DEBUG
+      printf("can't handle non-trivial isolated constraints for now\n");
+#     endif
+      return NULL;
+    }
+  }
+
+  int nc = hinrow[irow];
+
+#if 0
+  double tableau = new double[nc];
+  double sol = new double[nc];
+  double clo = new double[nc];
+  double cup = new double[nc];
+
+
+  for (int i=0; i<nc; ++i) {
+    int col = hcol[krs+1];
+    tableau[i] = rowels[krs+i];
+    clo[i] = prob->clo[krs+i];
+    cup[i] = prob->cup[krs+i];
+
+    sol[i] = clo[i];
+  }
+#endif
+
+  // HACK - set costs to 0.0 so empty.cpp doesn't complain
+  double *costs = new double[nc];
+  for (k = krs; k<kre; ++k) {
+    costs[k-krs] = dcost[hcol[k]];
+    dcost[hcol[k]] = 0.0;
+  }
+
+  next = new isolated_constraint_action(rlo[irow], rup[irow],
+					irow, nc,
+					CoinCopyOfArray(&hcol[krs], nc),
+					CoinCopyOfArray(&rowels[krs], nc),
+					costs,
+					next);
+
+  for ( k=krs; k<kre; k++)
+  { presolve_delete_from_col(irow,hcol[k],mcstrt,hincol,hrow,colels) ;
+    if (hincol[hcol[k]] == 0)
+    { PRESOLVE_REMOVE_LINK(prob->clink_,hcol[k]) ; } }
+  hinrow[irow] = 0 ;
+  PRESOLVE_REMOVE_LINK(prob->rlink_,irow) ;
+
+  // just to make things squeeky
+  rlo[irow] = 0.0;
+  rup[irow] = 0.0;
+
+# if CHECK_CONSISTENCY
+  presolve_links_ok(prob) ;
+  presolve_consistent(prob);
+# endif
+
+  return (next);
+}
+
+const char *isolated_constraint_action::name() const
+{
+  return ("isolated_constraint_action");
+}
+
+void isolated_constraint_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt		= prob->mcstrt_;
+  int *link		= prob->link_;
+  int *hincol		= prob->hincol_;
+  
+  double *rowduals	= prob->rowduals_;
+  double *rowacts	= prob->acts_;
+  double *sol		= prob->sol_;
+
+  CoinBigIndex &free_list		= prob->free_list_;
+
+
+  // hides fields
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  double rowact = 0.0;
+
+  int irow  = this->row_;
+
+  rup[irow] = this->rup_;
+  rlo[irow] = this->rlo_;
+  int k;
+
+  for (k=0; k<this->ninrow_; k++) {
+    int jcol = this->rowcols_[k];
+
+    sol[jcol] = 0.0;	// ONLY ACCEPTED SUCH CONSTRAINTS
+
+    CoinBigIndex kk = free_list;
+    assert(kk >= 0 && kk < prob->bulk0_) ;
+    free_list = link[free_list];
+
+    mcstrt[jcol] = kk;
+
+    //rowact += rowels[k] * sol[jcol];
+
+    colels[kk] = this->rowels_[k];
+    hrow[kk]   = irow;
+    link[kk] = NO_LINK ;
+
+    hincol[jcol] = 1;
+  }
+
+# if PRESOLVE_CONSISTENCY
+  presolve_check_free_list(prob) ;
+# endif
+
+  // ???
+  prob->setRowStatus(irow,CoinPrePostsolveMatrix::basic);
+    rowduals[irow] = 0.0;
+
+  rowacts[irow] = rowact;
+
+  // leave until desctructor
+  //  deleteAction(rowcols_,int *);
+  //  deleteAction(rowels_,double *);
+  //  deleteAction(costs_,double *);
+}
+
+isolated_constraint_action::~isolated_constraint_action()
+{
+    deleteAction(rowcols_,int *);
+    deleteAction(rowels_,double *);
+    deleteAction(costs_,double *);
+}
diff --git a/cbits/coin/CoinPresolveIsolated.hpp b/cbits/coin/CoinPresolveIsolated.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveIsolated.hpp
@@ -0,0 +1,51 @@
+/* $Id: CoinPresolveIsolated.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveIsolated_H
+#define CoinPresolveIsolated_H
+
+#include "CoinPresolveMatrix.hpp"
+
+class isolated_constraint_action : public CoinPresolveAction {
+  isolated_constraint_action();
+  isolated_constraint_action(const isolated_constraint_action& rhs);
+  isolated_constraint_action& operator=(const isolated_constraint_action& rhs);
+
+  double rlo_;
+  double rup_;
+  int row_;
+  int ninrow_;
+  // the arrays are owned by the class and must be deleted at destruction
+  const int *rowcols_;
+  const double *rowels_;
+  const double *costs_;
+
+  isolated_constraint_action(double rlo,
+			     double rup,
+			     int row,
+			     int ninrow,
+			     const int *rowcols,
+			     const double *rowels,
+			     const double *costs,
+			     const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    rlo_(rlo), rup_(rup), row_(row), ninrow_(ninrow),
+    rowcols_(rowcols), rowels_(rowels), costs_(costs) {}
+      
+ public:
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix * prob,
+					 int row,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~isolated_constraint_action();
+};
+
+
+
+#endif
diff --git a/cbits/coin/CoinPresolveMatrix.cpp b/cbits/coin/CoinPresolveMatrix.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveMatrix.cpp
@@ -0,0 +1,593 @@
+/* $Id: CoinPresolveMatrix.cpp 1510 2011-12-08 23:56:01Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+
+#include <cassert>
+#include <iostream>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+#include "CoinTime.hpp"
+
+/*! \file
+
+  This file contains methods for CoinPresolveMatrix, the object used during
+  presolve transformations.
+*/
+
+/*
+  Constructor and destructor for CoinPresolveMatrix.
+*/
+
+/*
+  CoinPresolveMatrix constructor
+
+  The constructor does very little, for much the same reasons that the
+  CoinPrePostsolveMatrix constructor does little. Might as well wait until we
+  load a matrix.
+
+  In general, for presolve the allocated size can be equal to the size of the
+  constraint matrix before presolve transforms are applied. (Presolve
+  transforms are assumed to reduce the size of the constraint system.) But we
+  need to keep the *_alloc parameters for compatibility with
+  CoinPrePostsolveMatrix.
+*/
+
+CoinPresolveMatrix::CoinPresolveMatrix
+  (int ncols_alloc, int nrows_alloc, CoinBigIndex nelems_alloc)
+
+  : CoinPrePostsolveMatrix(ncols_alloc,nrows_alloc,nelems_alloc),
+
+    clink_(0),
+    rlink_(0),
+
+    dobias_(0.0),
+    mrstrt_(0),
+    hinrow_(0),
+    rowels_(0),
+    hcol_(0),
+
+    integerType_(0),
+    anyInteger_(false),
+    tuning_(false),
+    startTime_(0.0),
+    feasibilityTolerance_(0.0),
+    status_(-1),
+    pass_(0),
+    maxSubstLevel_(3),
+    colChanged_(0),
+    colsToDo_(0),
+    numberColsToDo_(0),
+    nextColsToDo_(0),
+    numberNextColsToDo_(0),
+
+    rowChanged_(0),
+    rowsToDo_(0),
+    numberRowsToDo_(0),
+    nextRowsToDo_(0),
+    numberNextRowsToDo_(0),
+    presolveOptions_(0),
+    anyProhibited_(false),
+    usefulRowInt_(NULL),
+    usefulRowDouble_(NULL),
+    usefulColumnInt_(NULL),
+    usefulColumnDouble_(NULL),
+    randomNumber_(NULL),
+    infiniteUp_(NULL),
+    sumUp_(NULL),
+    infiniteDown_(NULL),
+    sumDown_(NULL)
+
+{ /* nothing to do here */ 
+
+  return ; }
+
+/*
+  CoinPresolveMatrix destructor.
+*/
+
+CoinPresolveMatrix::~CoinPresolveMatrix()
+
+{ delete[] clink_ ;
+  delete[] rlink_ ;
+  
+  delete[] mrstrt_ ;
+  delete[] hinrow_ ;
+  delete[] rowels_ ;
+  delete[] hcol_ ;
+
+  delete[] integerType_ ;
+  delete[] rowChanged_ ;
+  delete[] rowsToDo_ ;
+  delete[] nextRowsToDo_ ;
+  delete[] colChanged_ ;
+  delete[] colsToDo_ ;
+  delete[] nextColsToDo_ ;
+  delete[] usefulRowInt_;
+  delete[] usefulRowDouble_;
+  delete[] usefulColumnInt_;
+  delete[] usefulColumnDouble_;
+  delete[] randomNumber_;
+  delete[] infiniteUp_;
+  delete[] sumUp_;
+  delete[] infiniteDown_;
+  delete[] sumDown_;
+
+  return ; }
+
+
+
+/*
+  This routine loads a CoinPackedMatrix and proceeds to do the bulk of the
+  initialisation for the PrePostsolve and Presolve objects.
+
+  In the CoinPrePostsolveMatrix portion of the object, it initialises the
+  column-major packed matrix representation and the arrays that track the
+  motion of original columns and rows.
+
+  In the CoinPresolveMatrix portion of the object, it initialises the
+  row-major packed matrix representation, the arrays that assist in matrix
+  storage management, and the arrays that track the rows and columns to be
+  processed.
+
+  Arrays are allocated to the requested size (ncols0_, nrow0_, nelems0_).
+
+  The source matrix must be column ordered; it does not need to be gap-free.
+  Bulk storage in the column-major (hrow_, colels_) and row-major (hcol_,
+  rowels_) matrices is allocated at twice the required size so that we can
+  expand columns and rows as needed. This is almost certainly grossly
+  oversize, but (1) it's efficient, and (2) the utility routines which
+  compact the bulk storage areas have no provision to reallocate.
+*/
+
+void CoinPresolveMatrix::setMatrix (const CoinPackedMatrix *mtx)
+
+{
+/*
+  Check to make sure the matrix will fit and is column ordered.
+*/
+  if (mtx->isColOrdered() == false)
+  { throw CoinError("source matrix must be column ordered",
+		    "setMatrix","CoinPrePostsolveMatrix") ; }
+
+  int numCols = mtx->getNumCols() ;
+  if (numCols > ncols0_)
+  { throw CoinError("source matrix exceeds allocated capacity",
+		    "setMatrix","CoinPrePostsolveMatrix") ; }
+/*
+  Acquire the actual size, but allocate the matrix storage to the
+  requested capacity. The column-major rep is part of the PrePostsolve
+  object, the row-major rep belongs to the Presolve object.
+*/
+  ncols_ = numCols ;
+  nrows_ = mtx->getNumRows() ;
+  nelems_ = mtx->getNumElements() ;
+  bulk0_ = static_cast<CoinBigIndex> (bulkRatio_*nelems0_) ;
+
+  if (mcstrt_ == 0) mcstrt_ = new CoinBigIndex [ncols0_+1] ;
+  if (hincol_ == 0) hincol_ = new int [ncols0_+1] ;
+  if (hrow_ == 0) hrow_ = new int [bulk0_] ;
+  if (colels_ == 0) colels_ = new double [bulk0_] ;
+
+  if (mrstrt_ == 0) mrstrt_ = new CoinBigIndex [nrows0_+1] ;
+  if (hinrow_ == 0) hinrow_ = new int [nrows0_+1] ;
+  if (hcol_ == 0) hcol_ = new int [bulk0_] ;
+  if (rowels_ == 0) rowels_ = new double [bulk0_] ;
+/*
+  Grab the corresponding vectors from the source matrix.
+*/
+  const CoinBigIndex *src_mcstrt = mtx->getVectorStarts() ;
+  const int *src_hincol = mtx->getVectorLengths() ;
+  const double *src_colels = mtx->getElements() ;
+  const int *src_hrow = mtx->getIndices() ;
+/*
+  Bulk copy the column starts and lengths.
+*/
+  CoinMemcpyN(src_mcstrt,mtx->getSizeVectorStarts(),mcstrt_) ;
+  CoinMemcpyN(src_hincol,mtx->getSizeVectorLengths(),hincol_) ;
+/*
+  Copy the coefficients column by column in case there are gaps between
+  the columns in the bulk storage area. The assert is just in case the
+  gaps are *really* big.
+*/
+  assert(src_mcstrt[ncols_] <= bulk0_) ;
+  int j;
+  for ( j = 0 ; j < numCols ; j++)
+  { int lenj = src_hincol[j] ;
+    CoinBigIndex offset = mcstrt_[j] ;
+    CoinMemcpyN(src_colels+offset,lenj,colels_+offset) ;
+    CoinMemcpyN(src_hrow+offset,lenj,hrow_+offset) ; }
+/*
+  Now make a row-major copy. Start by counting the number of coefficients in
+  each row; we can do this directly in hinrow. Given the number of
+  coefficients in a row, we know how to lay out the bulk storage area.
+*/
+  CoinZeroN(hinrow_,nrows0_+1) ;
+  for ( j = 0 ; j < ncols_ ; j++)
+  { int *rowIndices = hrow_+mcstrt_[j] ;
+    int lenj = hincol_[j] ;
+    for (int k = 0 ; k < lenj ; k++)
+    { int i = rowIndices[k] ;
+      hinrow_[i]++ ; } }
+/*
+  Initialize mrstrt[i] to the start of row i+1. As we drop each coefficient
+  and column index into the bulk storage arrays, we'll decrement and store.
+  When we're done, mrstrt[i] will point to the start of row i, as it should.
+*/
+  int totalCoeffs = 0 ;
+  int i;
+  for ( i = 0 ; i < nrows_ ; i++)
+  { totalCoeffs += hinrow_[i] ;
+    mrstrt_[i] = totalCoeffs ; }
+  mrstrt_[nrows_] = totalCoeffs ;
+  for ( j = ncols_-1 ; j >= 0 ; j--)
+  { int lenj = hincol_[j] ;
+    double *colCoeffs = colels_+mcstrt_[j] ;
+    int *rowIndices = hrow_+mcstrt_[j] ;
+    for (int k = 0 ; k < lenj ; k++)
+    { int ri;
+      ri = rowIndices[k] ;
+      double aij = colCoeffs[k] ;
+      CoinBigIndex l = --mrstrt_[ri] ;
+      rowels_[l] = aij ;
+      hcol_[l] = j ; } }
+/*
+  Now the support structures. The entry for original column j should start
+  out as j; similarly for row i. originalColumn_ and originalRow_ belong to
+  the PrePostsolve object.
+*/
+  if (originalColumn_ == 0) originalColumn_ = new int [ncols0_] ;
+  if (originalRow_ == 0) originalRow_ = new int [nrows0_] ;
+
+  for ( j = 0 ; j < ncols0_ ; j++) 
+    originalColumn_[j] = j ;
+  for ( i = 0 ; i < nrows0_ ; i++) 
+    originalRow_[i] = i ;
+/*
+  We have help to set up the clink_ and rlink_ vectors (aids for matrix bulk
+  storage management). clink_ and rlink_ belong to the Presolve object.  Once
+  this is done, it's safe to set mrstrt_[nrows_] and mcstrt_[ncols_] to the
+  full size of the bulk storage area.
+*/
+  if (clink_ == 0) clink_ = new presolvehlink [ncols0_+1] ;
+  if (rlink_ == 0) rlink_ = new presolvehlink [nrows0_+1] ;
+  presolve_make_memlists(/*mcstrt_,*/hincol_,clink_,ncols_) ;
+  presolve_make_memlists(/*mrstrt_,*/hinrow_,rlink_,nrows_) ;
+  mcstrt_[ncols_] = bulk0_ ;
+  mrstrt_[nrows_] = bulk0_ ;
+/*
+  No rows or columns have been changed just yet. colChanged_ and rowChanged_
+  belong to the Presolve object.
+*/
+  if (colChanged_ == 0) colChanged_ = new unsigned char [ncols0_] ;
+  CoinZeroN(colChanged_,ncols0_) ;
+  if (rowChanged_ == 0) rowChanged_ = new unsigned char [nrows0_] ;
+  CoinZeroN(rowChanged_,nrows0_) ;
+/*
+  Finally, allocate the various *ToDo arrays. These are used to track the rows
+  and columns which should be processed in a given round of presolve
+  transforms. These belong to the Presolve object. Setting number*ToDo to 0
+  is all the initialization that's required here.
+*/
+  rowsToDo_ = new int [nrows0_] ;
+  numberRowsToDo_ = 0 ;
+  nextRowsToDo_ = new int [nrows0_] ;
+  numberNextRowsToDo_ = 0 ;
+  colsToDo_ = new int [ncols0_] ;
+  numberColsToDo_ = 0 ;
+  nextColsToDo_ = new int [ncols0_] ;
+  numberNextColsToDo_ = 0 ;
+  initializeStuff();
+  return ; }
+
+/*
+  Recompute ups and downs for a row (nonzero if infeasible).
+
+  If oneRow == -1 then do all rows.
+*/
+int CoinPresolveMatrix::recomputeSums (int oneRow)
+{
+  const int &numberRows = nrows_ ;
+  const int &numberColumns = ncols_ ;
+  
+  const double *const columnLower = clo_ ;
+  const double *const columnUpper = cup_ ;
+
+  double *const rowLower = rlo_ ;
+  double *const rowUpper = rup_ ;
+
+  const double *element = rowels_ ;
+  const int *column = hcol_ ;
+  const CoinBigIndex *rowStart = mrstrt_ ;
+  const int *rowLength = hinrow_ ;
+
+  const double large = PRESOLVE_SMALL_INF ;
+  const double &tolerance = feasibilityTolerance_ ;
+
+  const int iFirst = ((oneRow >= 0)?oneRow:0) ;
+  const int iLast = ((oneRow >= 0)?oneRow:numberRows) ;
+/*
+  Open a loop to process rows of interest.
+*/
+  int infeasible = 0 ;
+  for (int iRow = iFirst ; iRow < iLast ; iRow++) {
+    infiniteUp_[iRow] = 0 ;
+    sumUp_[iRow] = 0.0 ;
+    infiniteDown_[iRow] = 0 ;
+    sumDown_[iRow] = 0.0 ;
+/*
+  Compute finite and infinite contributions to row lhs upper and lower bounds
+  for nonempty rows with at least one reasonable bound.
+*/
+    if ((rowLower[iRow] > -large || rowUpper[iRow] < large) &&
+        rowLength[iRow] > 0) {
+      int infiniteUpper = 0 ;
+      int infiniteLower = 0 ;
+      double maximumUp = 0.0 ;
+      double maximumDown = 0.0 ; 
+      const CoinBigIndex &rStart = rowStart[iRow] ;
+      const CoinBigIndex rEnd = rStart+rowLength[iRow] ;
+      for (CoinBigIndex j = rStart ; j < rEnd ; ++j) {
+	const double &value = element[j] ;
+	const int &iColumn = column[j] ;
+	const double &lj = columnLower[iColumn] ;
+	const double &uj = columnUpper[iColumn] ;
+	if (value > 0.0) {
+	  if (uj < large) 
+	    maximumUp += uj*value ;
+	  else
+	    ++infiniteUpper ;
+	  if (lj > -large) 
+	    maximumDown += lj*value ;
+	  else
+	    ++infiniteLower ;
+	} else if (value < 0.0) {
+	  if (uj < large) 
+	    maximumDown += uj*value ;
+	  else
+	    ++infiniteLower ;
+	  if (lj > -large) 
+	    maximumUp += lj*value ;
+	  else
+	    ++infiniteUpper ;
+	}
+      }
+      infiniteUp_[iRow] = infiniteUpper ;
+      sumUp_[iRow] = maximumUp ;
+      infiniteDown_[iRow] = infiniteLower ;
+      sumDown_[iRow] = maximumDown ;
+      double maxUp = maximumUp+infiniteUpper*large ;
+      double maxDown = maximumDown-infiniteLower*large ;
+/*
+  Check for redundant or infeasible row.
+*/
+      if (maxUp <= rowUpper[iRow]+tolerance && 
+	  maxDown >= rowLower[iRow]-tolerance) {
+	infiniteUp_[iRow] = numberColumns+1 ;
+	infiniteDown_[iRow] = numberColumns+1 ;
+      } else if (maxUp < rowLower[iRow]-tolerance) {
+	infeasible++ ;
+      } else if (maxDown > rowUpper[iRow]+tolerance) {
+	infeasible++ ;
+      }
+    } else if (rowLength[iRow] > 0) {
+/*
+  A row where both rhs bounds are very large. Mark as redundant.
+*/
+      assert(rowLower[iRow] <= -large && rowUpper[iRow] >= large) ;
+      infiniteUp_[iRow] = numberColumns+1 ;
+      infiniteDown_[iRow] = numberColumns+1 ;
+    } else {
+/*
+  Row with length zero. Check the the rhs bounds include zero and force
+  `near-to-zero' to exactly zero.
+*/
+      assert(rowLength[iRow] == 0) ;
+      if (rowLower[iRow] > 0.0 || rowUpper[iRow] < 0.0) {
+	double tolerance2 = 10.0*tolerance ;
+	if (rowLower[iRow] > 0.0 && rowLower[iRow] < tolerance2)
+	  rowLower[iRow] = 0.0 ;
+	else
+	  infeasible++ ;
+	if (rowUpper[iRow] < 0.0 && rowUpper[iRow] > -tolerance2)
+	  rowUpper[iRow] = 0.0 ;
+	else
+	  infeasible++ ;
+      }
+    }
+  }
+  return (infeasible) ;
+}
+/*
+  Preallocate scratch work arrays, arrays to hold row lhs bound information,
+  and an array of random numbers.
+*/
+void CoinPresolveMatrix::initializeStuff ()
+{
+  usefulRowInt_ = new int [3*nrows_] ;
+  usefulRowDouble_ = new double [2*nrows_] ;
+  usefulColumnInt_ = new int [2*ncols_] ;
+  usefulColumnDouble_ = new double[ncols_] ;
+  int k = CoinMax(ncols_+1,nrows_+1) ;
+  randomNumber_ = new double [k] ;
+  coin_init_random_vec(randomNumber_,k) ;
+  infiniteUp_ = new int [nrows_] ;
+  sumUp_ = new double [nrows_] ;
+  infiniteDown_ = new int [nrows_] ;
+  sumDown_ = new double [nrows_] ;
+  return ;
+}
+
+/*
+  Free arrays allocated in initializeStuff.
+*/
+void CoinPresolveMatrix::deleteStuff()
+{
+  delete[] usefulRowInt_;
+  delete[] usefulRowDouble_;
+  delete[] usefulColumnInt_;
+  delete[] usefulColumnDouble_;
+  delete[] randomNumber_;
+  delete[] infiniteUp_;
+  delete[] sumUp_;
+  delete[] infiniteDown_;
+  delete[] sumDown_;
+  usefulRowInt_ = NULL;
+  usefulRowDouble_ = NULL;
+  usefulColumnInt_ = NULL;
+  usefulColumnDouble_ = NULL;
+  randomNumber_ = NULL;
+  infiniteUp_ = NULL;
+  sumUp_ = NULL;
+  infiniteDown_ = NULL;
+  sumDown_ = NULL;
+}
+
+
+/*
+  These functions set integer type information. The first expects an array with
+  an entry for each variable. The second sets all variables to integer or
+  continuous type.
+*/
+
+void CoinPresolveMatrix::setVariableType (const unsigned char *variableType,
+					 int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = ncols_ ; }
+  else
+  if (lenParam > ncols0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setIntegerType","CoinPresolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (integerType_ == 0) integerType_ = new unsigned char [ncols0_] ;
+  CoinCopyN(variableType,len,integerType_) ;
+
+  return ; }
+
+void CoinPresolveMatrix::setVariableType (bool allIntegers, int lenParam)
+
+{ int len ;
+
+  if (lenParam < 0)
+  { len = ncols_ ; }
+  else
+  if (lenParam > ncols0_)
+  { throw CoinError("length exceeds allocated size",
+		    "setIntegerType","CoinPresolveMatrix") ; }
+  else
+  { len = lenParam ; }
+
+  if (integerType_ == 0) integerType_ = new unsigned char [ncols0_] ;
+
+  const unsigned char value = 1 ;
+
+  if (allIntegers == true)
+  { CoinFillN(integerType_,len,value) ; }
+  else
+  { CoinZeroN(integerType_,len) ; }
+
+  return ; }
+
+/*
+  The next pair of routines initialises the [row,col]ToDo lists in preparation
+  for a major pass. All except rows/columns marked as prohibited are added to
+  the lists.
+*/
+
+void CoinPresolveMatrix::initColsToDo ()
+/*
+  Initialize the ToDo lists in preparation for a major iteration of
+  preprocessing. First, cut back the ToDo and NextToDo lists to zero entries.
+  Then place all columns not marked prohibited on the ToDo list.
+*/
+
+{ int j ;
+
+  numberNextColsToDo_ = 0 ;
+
+  if (anyProhibited_ == false)
+  { for (j = 0 ; j < ncols_ ; j++) 
+    { colsToDo_[j] = j ; }
+      numberColsToDo_ = ncols_ ; }
+  else
+  { numberColsToDo_ = 0 ;
+    for (j = 0 ; j < ncols_ ; j++) 
+    if (colProhibited(j) == false)
+    { colsToDo_[numberColsToDo_++] = j ; } }
+
+  return ; }
+
+void CoinPresolveMatrix::initRowsToDo ()
+/*
+  Initialize the ToDo lists in preparation for a major iteration of
+  preprocessing. First, cut back the ToDo and NextToDo lists to zero entries.
+  Then place all rows not marked prohibited on the ToDo list.
+*/
+
+{ int i ;
+
+  numberNextRowsToDo_ = 0 ;
+
+  if (anyProhibited_ == false)
+  { for (i = 0 ; i < nrows_ ; i++) 
+    { rowsToDo_[i] = i ; }
+      numberRowsToDo_ = nrows_ ; }
+  else
+  { numberRowsToDo_ = 0 ;
+    for (i = 0 ; i < nrows_ ; i++) 
+    if (rowProhibited(i) == false)
+    { rowsToDo_[numberRowsToDo_++] = i ; } }
+
+  return ; }
+
+int CoinPresolveMatrix::stepColsToDo ()
+/*
+  This routine transfers the contents of NextToDo to ToDo, simultaneously
+  resetting the Changed indicator. It returns the number of columns
+  transfered.
+*/
+{ int k ;
+
+  for (k = 0 ; k < numberNextColsToDo_ ; k++)
+  { int j = nextColsToDo_[k] ;
+    unsetColChanged(j) ;
+    colsToDo_[k] = j ; }
+  numberColsToDo_ = numberNextColsToDo_ ;
+  numberNextColsToDo_ = 0 ;
+
+  return (numberColsToDo_) ; }
+
+int CoinPresolveMatrix::stepRowsToDo ()
+/*
+  This routine transfers the contents of NextToDo to ToDo, simultaneously
+  resetting the Changed indicator. It returns the number of columns
+  transfered.
+*/
+{ int k ;
+
+  for (k = 0 ; k < numberNextRowsToDo_ ; k++)
+  { int i = nextRowsToDo_[k] ;
+    unsetRowChanged(i) ;
+    rowsToDo_[k] = i ; }
+  numberRowsToDo_ = numberNextRowsToDo_ ;
+  numberNextRowsToDo_ = 0 ;
+
+  return (numberRowsToDo_) ; }
+// Say we want statistics - also set time
+void 
+CoinPresolveMatrix::statistics()
+{
+  tuning_=true;
+  startTime_ = CoinCpuTime();
+}
+#ifdef PRESOLVE_DEBUG
+#include "CoinPresolvePsdebug.cpp"
+#endif
diff --git a/cbits/coin/CoinPresolveMatrix.hpp b/cbits/coin/CoinPresolveMatrix.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveMatrix.hpp
@@ -0,0 +1,1842 @@
+/* $Id: CoinPresolveMatrix.hpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveMatrix_H
+#define CoinPresolveMatrix_H
+
+#include "CoinPragma.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinMessage.hpp"
+#include "CoinTime.hpp"
+
+#include <cmath>
+#include <cassert>
+#include <cfloat>
+#include <cassert>
+#include <cstdlib>
+
+#if PRESOLVE_DEBUG > 0
+#include "CoinFinite.hpp"
+#endif
+
+/*! \file
+
+  Declarations for CoinPresolveMatrix and CoinPostsolveMatrix and their
+  common base class CoinPrePostsolveMatrix. Also declarations for
+  CoinPresolveAction and a number of non-member utility functions.
+*/
+
+
+#if defined(_MSC_VER)
+// Avoid MS Compiler problem in recognizing type to delete
+// by casting to type.
+// Is this still necessary? -- lh, 111202 --
+#define deleteAction(array,type) delete [] ((type) array)
+#else
+#define deleteAction(array,type) delete [] array
+#endif
+
+/*
+  Define PRESOLVE_DEBUG and PRESOLVE_CONSISTENCY on the configure command
+  line or in a Makefile!  See comments in CoinPresolvePsdebug.hpp.
+*/
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+
+#define PRESOLVE_STMT(s) s
+
+#define PRESOLVEASSERT(x) \
+  ((x) ? 1 : ((std::cerr << "FAILED ASSERTION at line " \
+			 << __LINE__ << ": " #x "\n"), abort(), 0))
+
+inline void DIE(const char *s) { std::cout << s ; abort() ; }
+
+/*! \brief Indicate column or row present at start of postsolve
+
+  This code is used during postsolve in [cr]done to indicate columns and rows
+  that are present in the presolved system (i.e., present at the start of
+  postsolve processing).
+
+  \todo
+  There are a bunch of these code definitions, scattered through presolve
+  files. They should be collected in one place.
+*/
+#define PRESENT_IN_REDUCED	'\377'
+
+#else
+
+#define PRESOLVEASSERT(x) {} 
+#define	PRESOLVE_STMT(s) {}
+
+inline void DIE(const char *) {}
+
+#endif
+
+/*
+  Unclear why these are separate from standard debug.
+*/
+#ifndef PRESOLVE_DETAIL
+#define PRESOLVE_DETAIL_PRINT(s) {}
+#else
+#define PRESOLVE_DETAIL_PRINT(s) s
+#endif
+
+/*! \brief Zero tolerance
+
+  OSL had a fixed zero tolerance; we still use that here.
+*/
+const double ZTOLDP = 1e-12 ;
+/*! \brief Alternate zero tolerance
+
+  Use a different one if we are doing doubletons, etc.
+*/
+const double ZTOLDP2 = 1e-10 ;
+
+/// The usual finite infinity
+#define PRESOLVE_INF COIN_DBL_MAX
+/// And a small infinity
+#define PRESOLVE_SMALL_INF 1.0e20
+/// Check for infinity using finite infinity
+#define	PRESOLVEFINITE(n) (-PRESOLVE_INF < (n) && (n) < PRESOLVE_INF)
+
+
+class CoinPostsolveMatrix ;
+
+/*! \class CoinPresolveAction
+    \brief Abstract base class of all presolve routines.
+
+  The details will make more sense after a quick overview of the grand plan:
+  A presolve object is handed a problem object, which it is expected to
+  modify in some useful way.  Assuming that it succeeds, the presolve object
+  should create a postsolve object, <i>i.e.</i>, an object that contains
+  instructions for backing out the presolve transform to recover the original
+  problem. These postsolve objects are accumulated in a linked list, with each
+  successive presolve action adding its postsolve action to the head of the
+  list. The end result of all this is a presolved problem object, and a list
+  of postsolve objects. The presolved problem object is then handed to a
+  solver for optimization, and the problem object augmented with the
+  results.  The list of postsolve objects is then traversed. Each of them
+  (un)modifies the problem object, with the end result being the original
+  problem, augmented with solution information.
+
+  The problem object representation is CoinPrePostsolveMatrix and subclasses.
+  Check there for details. The \c CoinPresolveAction class and subclasses
+  represent the presolve and postsolve objects.
+
+  In spite of the name, the only information held in a \c CoinPresolveAction
+  object is the information needed to postsolve (<i>i.e.</i>, the information
+  needed to back out the presolve transformation). This information is not
+  expected to change, so the fields are all \c const.
+
+  A subclass of \c CoinPresolveAction, implementing a specific pre/postsolve
+  action, is expected to declare a static function that attempts to perform a
+  presolve transformation. This function will be handed a CoinPresolveMatrix
+  to transform, and a pointer to the head of the list of postsolve objects.
+  If the transform is successful, the function will create a new
+  \c CoinPresolveAction object, link it at the head of the list of postsolve
+  objects, and return a pointer to the postsolve object it has just created.
+  Otherwise, it should return 0. It is expected that these static functions
+  will be the only things that can create new \c CoinPresolveAction objects;
+  this is expressed by making each subclass' constructor(s) private.
+
+  Every subclass must also define a \c postsolve method.
+  This function will be handed a CoinPostsolveMatrix to transform.
+
+  It is the client's responsibility to implement presolve and postsolve driver
+  routines. See OsiPresolve for examples.
+
+  \note Since the only fields in a \c CoinPresolveAction are \c const, anything
+	one can do with a variable declared \c CoinPresolveAction* can also be
+	done with a variable declared \c const \c CoinPresolveAction* It is
+	expected that all derived subclasses of \c CoinPresolveAction also have
+	this property.
+*/
+class CoinPresolveAction
+{
+ public:
+  /*! \brief Stub routine to throw exceptions.
+  
+   Exceptions are inefficient, particularly with g++.  Even with xlC, the
+   use of exceptions adds a long prologue to a routine.  Therefore, rather
+   than use throw directly in the routine, I use it in a stub routine.
+  */
+  static void throwCoinError(const char *error, const char *ps_routine)
+  { throw CoinError(error, ps_routine, "CoinPresolve"); } 
+
+  /*! \brief The next presolve transformation
+  
+    Set at object construction.
+  */
+  const CoinPresolveAction *next;
+  
+  /*! \brief Construct a postsolve object and add it to the transformation list.
+  
+    This is an `add to head' operation. This object will point to the
+    one passed as the parameter.
+  */
+  CoinPresolveAction(const CoinPresolveAction *next) : next(next) {}
+  /// modify next (when building rather than passing)
+  inline void setNext(const CoinPresolveAction *nextAction)
+  { next = nextAction;}
+
+  /*! \brief A name for debug printing.
+
+    It is expected that the name is not stored in the transform itself.
+  */
+  virtual const char *name() const = 0;
+
+  /*! \brief Apply the postsolve transformation for this particular
+	     presolve action.
+  */
+  virtual void postsolve(CoinPostsolveMatrix *prob) const = 0;
+
+  /*! \brief Virtual destructor. */
+  virtual ~CoinPresolveAction() {}
+};
+
+/*
+  These are needed for OSI-aware constructors associated with
+  CoinPrePostsolveMatrix, CoinPresolveMatrix, and CoinPostsolveMatrix.
+*/
+class ClpSimplex;
+class OsiSolverInterface;
+
+/*
+  CoinWarmStartBasis is required for methods in CoinPrePostsolveMatrix
+  that accept/return a CoinWarmStartBasis object.
+*/
+class CoinWarmStartBasis ;
+
+/*! \class CoinPrePostsolveMatrix
+    \brief Collects all the information about the problem that is needed
+	   in both presolve and postsolve.
+    
+    In a bit more detail, a column-major representation of the constraint
+    matrix and upper and lower bounds on variables and constraints, plus row
+    and column solutions, reduced costs, and status. There's also a set of
+    arrays holding the original row and column numbers.
+
+    As presolve and postsolve transform the matrix, it will occasionally be
+    necessary to expand the number of entries in a column. There are two
+    aspects:
+    <ul>
+      <li> During postsolve, the constraint system is expected to grow as
+	   the smaller presolved system is transformed back to the original
+	   system.
+      <li> During both pre- and postsolve, transforms can increase the number
+	   of coefficients in a row or column. (See the 
+	   variable substitution, doubleton, and tripleton transforms.)
+    </ul>
+
+    The first is addressed by the members #ncols0_, #nrows0_, and #nelems0_.
+    These should be set (via constructor parameters) to values large enough
+    for the largest size taken on by the constraint system. Typically, this
+    will be the size of the original constraint system.
+
+    The second is addressed by a generous allocation of extra (empty) space
+    for the arrays used to hold coefficients and row indices. When columns
+    must be expanded, they are moved into the empty space. When it is used up,
+    the arrays are compacted. When compaction fails to produce sufficient
+    space, presolve/postsolve will fail.
+
+    CoinPrePostsolveMatrix isn't really intended to be used `bare' --- the
+    expectation is that it'll be used through CoinPresolveMatrix or
+    CoinPostsolveMatrix. Some of the functions needed to load a problem are
+    defined in the derived classes.
+
+  When CoinPresolve is applied when reoptimising, we need to be prepared to
+  accept a basis and modify it in step with the presolve actions (otherwise
+  we throw away all the advantages of warm start for reoptimization). But
+  other solution components (#acts_, #rowduals_, #sol_, and #rcosts_) are
+  needed only for postsolve, where they're used in places to determine the
+  proper action(s) when restoring rows or columns.  If presolve is provided
+  with a solution, it will modify it in step with the presolve actions.
+  Moving the solution components from CoinPrePostsolveMatrix to
+  CoinPostsolveMatrix would break a lot of code.  It's not clear that it's
+  worth it, and it would preclude upgrades to the presolve side that might
+  make use of any of these.  -- lh, 080501 --
+
+  The constructors that take an OSI or ClpSimplex as a parameter really should
+  not be here, but for historical reasons they will likely remain for the
+  forseeable future.  -- lh, 111202 --
+*/
+
+class CoinPrePostsolveMatrix
+{
+ public:
+
+  /*! \name Constructors & Destructors */
+
+  //@{
+  /*! \brief `Native' constructor
+
+    This constructor creates an empty object which must then be loaded. On
+    the other hand, it doesn't assume that the client is an
+    OsiSolverInterface.
+  */
+  CoinPrePostsolveMatrix(int ncols_alloc, int nrows_alloc,
+			 CoinBigIndex nelems_alloc) ;
+
+  /*! \brief Generic OSI constructor
+
+    See OSI code for the definition.
+  */
+  CoinPrePostsolveMatrix(const OsiSolverInterface * si,
+			int ncols_,
+			int nrows_,
+			CoinBigIndex nelems_);
+
+  /*! ClpOsi constructor
+
+    See Clp code for the definition.
+  */
+  CoinPrePostsolveMatrix(const ClpSimplex * si,
+			int ncols_,
+			int nrows_,
+			CoinBigIndex nelems_,
+                         double bulkRatio);
+
+  /// Destructor
+  ~CoinPrePostsolveMatrix();
+  //@}
+
+  /*! \brief Enum for status of various sorts
+  
+    Matches CoinWarmStartBasis::Status and adds superBasic. Most code that
+    converts between CoinPrePostsolveMatrix::Status and
+    CoinWarmStartBasis::Status will break if this correspondence is broken.
+
+    superBasic is an unresolved problem: there's no analogue in
+    CoinWarmStartBasis::Status.
+  */
+  enum Status {
+    isFree = 0x00,
+    basic = 0x01,
+    atUpperBound = 0x02,
+    atLowerBound = 0x03,
+    superBasic = 0x04
+  };
+
+  /*! \name Functions to work with variable status
+
+    Functions to work with the CoinPrePostsolveMatrix::Status enum and
+    related vectors.
+
+    \todo
+    Why are we futzing around with three bit status? A holdover from the
+    packed arrays of CoinWarmStartBasis? Big swaths of the presolve code
+    manipulates colstat_ and rowstat_ as unsigned char arrays using simple
+    assignment to set values.
+  */
+  //@{
+  
+  /// Set row status (<i>i.e.</i>, status of artificial for this row)
+  inline void setRowStatus(int sequence, Status status)
+  {
+    unsigned char & st_byte = rowstat_[sequence];
+    st_byte = static_cast<unsigned char>(st_byte & (~7)) ;
+    st_byte = static_cast<unsigned char>(st_byte | status) ;
+  }
+  /// Get row status
+  inline Status getRowStatus(int sequence) const
+  {return static_cast<Status> (rowstat_[sequence]&7);}
+  /// Check if artificial for this row is basic
+  inline bool rowIsBasic(int sequence) const
+  {return (static_cast<Status> (rowstat_[sequence]&7)==basic);}
+  /// Set column status (<i>i.e.</i>, status of primal variable)
+  inline void setColumnStatus(int sequence, Status status)
+  {
+    unsigned char & st_byte = colstat_[sequence];
+    st_byte = static_cast<unsigned char>(st_byte & (~7)) ;
+    st_byte = static_cast<unsigned char>(st_byte | status) ;
+
+#   ifdef PRESOLVE_DEBUG
+    switch (status)
+    { case isFree:
+      { if (clo_[sequence] > -PRESOLVE_INF || cup_[sequence] < PRESOLVE_INF)
+	{ std::cout << "Bad status: Var " << sequence
+		    << " isFree, lb = " << clo_[sequence]
+		    << ", ub = " << cup_[sequence] << std::endl ; }
+	break ; }
+      case basic:
+      { break ; }
+      case atUpperBound:
+      { if (cup_[sequence] >= PRESOLVE_INF)
+	{ std::cout << "Bad status: Var " << sequence
+	            << " atUpperBound, lb = " << clo_[sequence]
+	            << ", ub = " << cup_[sequence] << std::endl ; }
+	break ; }
+      case atLowerBound:
+      { if (clo_[sequence] <= -PRESOLVE_INF)
+	{ std::cout << "Bad status: Var " << sequence
+	            << " atLowerBound, lb = " << clo_[sequence]
+	            << ", ub = " << cup_[sequence] << std::endl ; }
+	break ; }
+      case superBasic:
+      { if (clo_[sequence] <= -PRESOLVE_INF && cup_[sequence] >= PRESOLVE_INF)
+	{ std::cout << "Bad status: Var " << sequence
+	            << " superBasic, lb = " << clo_[sequence]
+	            << ", ub = " << cup_[sequence] << std::endl ; }
+	break ; }
+      default:
+      { assert(false) ;
+	break ; } }
+#   endif
+  }
+  /// Get column (structural variable) status
+  inline Status getColumnStatus(int sequence) const
+  {return static_cast<Status> (colstat_[sequence]&7);}
+  /// Check if column (structural variable) is basic
+  inline bool columnIsBasic(int sequence) const
+  {return (static_cast<Status> (colstat_[sequence]&7)==basic);}
+  /*! \brief Set status of row (artificial variable) to the correct nonbasic
+	     status given bounds and current value
+  */
+  void setRowStatusUsingValue(int iRow);
+  /*! \brief Set status of column (structural variable) to the correct
+	     nonbasic status given bounds and current value
+  */
+  void setColumnStatusUsingValue(int iColumn);
+  /*! \brief Set column (structural variable) status vector */
+  void setStructuralStatus(const char *strucStatus, int lenParam) ;
+  /*! \brief Set row (artificial variable) status vector */
+  void setArtificialStatus(const char *artifStatus, int lenParam) ;
+  /*! \brief Set the status of all variables from a basis */
+  void setStatus(const CoinWarmStartBasis *basis) ;
+  /*! \brief Get status in the form of a CoinWarmStartBasis */
+  CoinWarmStartBasis *getStatus() ;
+  /*! \brief Return a print string for status of a column (structural
+	     variable)
+  */
+  const char *columnStatusString(int j) const ;
+  /*! \brief Return a print string for status of a row (artificial
+	     variable)
+  */
+  const char *rowStatusString(int i) const ;
+  //@}
+
+  /*! \name Functions to load problem and solution information
+
+    These functions can be used to load portions of the problem definition
+    and solution. See also the CoinPresolveMatrix and CoinPostsolveMatrix
+    classes.
+  */
+  //@{
+  /// Set the objective function offset for the original system.
+  void setObjOffset(double offset) ;
+  /*! \brief Set the objective sense (max/min)
+
+    Coded as 1.0 for min, -1.0 for max.
+    Yes, there's a method, and a matching attribute. No, you really
+    don't want to set this to maximise.
+  */
+  void setObjSense(double objSense) ;
+  /// Set the primal feasibility tolerance
+  void setPrimalTolerance(double primTol) ;
+  /// Set the dual feasibility tolerance
+  void setDualTolerance(double dualTol) ;
+  /// Set column lower bounds
+  void setColLower(const double *colLower, int lenParam) ;
+  /// Set column upper bounds
+  void setColUpper(const double *colUpper, int lenParam) ;
+  /// Set column solution
+  void setColSolution(const double *colSol, int lenParam) ;
+  /// Set objective coefficients
+  void setCost(const double *cost, int lenParam) ;
+  /// Set reduced costs
+  void setReducedCost(const double *redCost, int lenParam) ;
+  /// Set row lower bounds
+  void setRowLower(const double *rowLower, int lenParam) ;
+  /// Set row upper bounds
+  void setRowUpper(const double *rowUpper, int lenParam) ;
+  /// Set row solution
+  void setRowPrice(const double *rowSol, int lenParam) ;
+  /// Set row activity
+  void setRowActivity(const double *rowAct, int lenParam) ;
+  //@}
+
+  /*! \name Functions to retrieve problem and solution information */
+  //@{
+  /// Get current number of columns
+  inline int getNumCols() const
+  { return (ncols_) ; } 
+  /// Get current number of rows
+  inline int getNumRows() const
+  { return (nrows_) ; }
+  /// Get current number of non-zero coefficients
+  inline int getNumElems() const
+  { return (nelems_) ; }
+  /// Get column start vector for column-major packed matrix
+  inline const CoinBigIndex *getColStarts() const
+  { return (mcstrt_) ; } 
+  /// Get column length vector for column-major packed matrix
+  inline const int *getColLengths() const
+  { return (hincol_) ; } 
+  /// Get vector of row indices for column-major packed matrix
+  inline const int *getRowIndicesByCol() const
+  { return (hrow_) ; } 
+  /// Get vector of elements for column-major packed matrix
+  inline const double *getElementsByCol() const
+  { return (colels_) ; } 
+  /// Get column lower bounds
+  inline const double *getColLower() const
+  { return (clo_) ; } 
+  /// Get column upper bounds
+  inline const double *getColUpper() const
+  { return (cup_) ; } 
+  /// Get objective coefficients
+  inline const double *getCost() const
+  { return (cost_) ; } 
+  /// Get row lower bounds
+  inline const double *getRowLower() const
+  { return (rlo_) ; } 
+  /// Get row upper bounds
+  inline const double *getRowUpper() const
+  { return (rup_) ; } 
+  /// Get column solution (primal variable values)
+  inline const double *getColSolution() const
+  { return (sol_) ; }
+  /// Get row activity (constraint lhs values)
+  inline const double *getRowActivity() const
+  { return (acts_) ; }
+  /// Get row solution (dual variables)
+  inline const double *getRowPrice() const
+  { return (rowduals_) ; }
+  /// Get reduced costs
+  inline const double *getReducedCost() const
+  { return (rcosts_) ; }
+  /// Count empty columns
+  inline int countEmptyCols()
+  { int empty = 0 ;
+    for (int i = 0 ; i < ncols_ ; i++) if (hincol_[i] == 0) empty++ ;
+    return (empty) ; }
+  //@}
+
+
+  /*! \name Message handling */
+  //@{
+  /// Return message handler
+  inline CoinMessageHandler *messageHandler() const 
+  { return handler_; }
+  /*! \brief Set message handler
+
+    The client retains responsibility for the handler --- it will not be
+    destroyed with the \c CoinPrePostsolveMatrix object.
+  */
+  inline void setMessageHandler(CoinMessageHandler *handler)
+  { if (defaultHandler_ == true)
+    { delete handler_ ;
+      defaultHandler_ = false ; }
+    handler_ = handler ; }
+  /// Return messages
+  inline CoinMessages messages() const 
+  { return messages_; }
+  //@}
+
+  /*! \name Current and Allocated Size
+
+    During pre- and postsolve, the matrix will change in size. During presolve
+    it will shrink; during postsolve it will grow. Hence there are two sets of
+    size variables, one for the current size and one for the allocated size.
+    (See the general comments for the CoinPrePostsolveMatrix class for more
+    information.)
+  */
+  //@{
+
+  /// current number of columns
+  int ncols_;
+  /// current number of rows
+  int nrows_;
+  /// current number of coefficients
+  CoinBigIndex nelems_;
+
+  /// Allocated number of columns
+  int ncols0_;
+  /// Allocated number of rows
+  int nrows0_ ;
+  /// Allocated number of coefficients
+  CoinBigIndex nelems0_ ;
+  /*! \brief Allocated size of bulk storage for row indices and coefficients
+
+    This is the space allocated for hrow_ and colels_.  This must be large
+    enough to allow columns to be copied into empty space when they need to
+    be expanded.  For efficiency (to minimize the number of times the
+    representation must be compressed) it's recommended that this be at least
+    2*nelems0_.
+  */
+  CoinBigIndex bulk0_ ;
+  /// Ratio of bulk0_ to nelems0_; default is 2.
+  double bulkRatio_;
+  //@}
+
+  /*! \name Problem representation
+
+    The matrix is the common column-major format: A pair of vectors with
+    positional correspondence to hold coefficients and row indices, and a
+    second pair of vectors giving the starting position and length of each
+    column in the first pair.
+  */
+  //@{
+  /// Vector of column start positions in #hrow_, #colels_
+  CoinBigIndex *mcstrt_;
+  /// Vector of column lengths
+  int *hincol_;
+  /// Row indices (positional correspondence with #colels_)
+  int *hrow_;
+  /// Coefficients (positional correspondence with #hrow_)
+  double *colels_;
+
+  /// Objective coefficients
+  double *cost_;
+  /// Original objective offset
+  double originalOffset_;
+
+  /// Column (primal variable) lower bounds
+  double *clo_;
+  /// Column (primal variable) upper bounds
+  double *cup_;
+
+  /// Row (constraint) lower bounds
+  double *rlo_;
+  /// Row (constraint) upper bounds
+  double *rup_;
+
+  /*! \brief Original column numbers
+
+    Over the current range of column numbers in the presolved problem,
+    the entry for column j will contain the index of the corresponding
+    column in the original problem.
+  */
+  int * originalColumn_;
+  /*! \brief Original row numbers
+
+    Over the current range of row numbers in the presolved problem, the
+    entry for row i will contain the index of the corresponding row in
+    the original problem.
+  */
+  int * originalRow_;
+
+  /// Primal feasibility tolerance
+  double ztolzb_;
+  /// Dual feasibility tolerance
+  double ztoldj_;
+
+  /*! \brief Maximization/minimization
+
+    Yes, there's a variable here. No, you really don't want to set this to
+    maximise. See the main notes for CoinPresolveMatrix.
+  */
+  double maxmin_;
+  //@}
+
+  /*! \name Problem solution information
+   
+    The presolve phase will work without any solution information
+    (appropriate for initial optimisation) or with solution information
+    (appropriate for reoptimisation).  When solution information is supplied,
+    presolve will maintain it to the best of its ability.  #colstat_ is
+    checked to determine the presence/absence of status information. #sol_ is
+    checked for primal solution information, and #rowduals_ for dual solution
+    information.
+
+    The postsolve phase requires the complete solution information from the
+    presolved problem (status, primal and dual solutions). It will be
+    transformed into a correct solution for the original problem.
+  */
+  //@{
+  /*! \brief Vector of primal variable values
+
+    If #sol_ exists, it is assumed that primal solution information should be
+    updated and that #acts_ also exists.
+  */
+  double *sol_;
+  /*! \brief Vector of dual variable values
+
+    If #rowduals_ exists, it is assumed that dual solution information should
+    be updated and that #rcosts_ also exists.
+  */
+  double *rowduals_;
+  /*! \brief Vector of constraint left-hand-side values (row activity)
+  
+    Produced by evaluating constraints according to #sol_. Updated iff
+    #sol_ exists.
+  */
+  double *acts_;
+  /*! \brief Vector of reduced costs
+  
+    Produced by evaluating dual constraints according to #rowduals_. Updated
+    iff #rowduals_ exists.
+  */
+  double *rcosts_;
+
+  /*! \brief Status of primal variables
+
+    Coded with CoinPrePostSolveMatrix::Status, one code per char. colstat_ and
+    #rowstat_ <b>MUST</b> be allocated as a single vector. This is to maintain
+    compatibility with ClpPresolve and OsiPresolve, which do it this way.
+  */
+  unsigned char *colstat_;
+
+  /*! \brief Status of constraints
+
+    More accurately, the status of the logical variable associated with the
+    constraint. Coded with CoinPrePostSolveMatrix::Status, one code per char.
+    Note that this must be allocated as a single vector with #colstat_.
+  */
+  unsigned char *rowstat_;
+  //@}
+
+  /*! \name Message handling
+
+    Uses the standard COIN approach: a default handler is installed, and the
+    CoinPrePostsolveMatrix object takes responsibility for it. If the client
+    replaces the handler with one of their own, it becomes their
+    responsibility.
+  */
+  //@{
+  /// Message handler
+  CoinMessageHandler *handler_; 
+  /// Indicates if the current #handler_ is default (true) or not (false).
+  bool defaultHandler_;
+  /// Standard COIN messages
+  CoinMessage messages_; 
+  //@}
+
+};
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Generate a print string for a status code.
+*/
+const char *statusName (CoinPrePostsolveMatrix::Status status) ;
+
+
+/*! \class presolvehlink
+    \brief Links to aid in packed matrix modification
+
+   Currently, the matrices held by the CoinPrePostsolveMatrix and
+   CoinPresolveMatrix objects are represented in the same way as a
+   CoinPackedMatrix. In the course of presolve and postsolve transforms, it
+   will happen that a major-dimension vector needs to increase in size. In
+   order to check whether there is enough room to add another coefficient in
+   place, it helps to know the next vector (in memory order) in the bulk
+   storage area. To do that, a linked list of major-dimension vectors is
+   maintained; the "pre" and "suc" fields give the previous and next vector,
+   in memory order (that is, the vector whose mcstrt_ or mrstrt_ entry is
+   next smaller or larger).
+
+   Consider a column-major matrix with ncols columns. By definition,
+   presolvehlink[ncols].pre points to the column in the last occupied
+   position of the bulk storage arrays. There is no easy way to find the
+   column which occupies the first position (there is no presolvehlink[-1] to
+   consult). If the column that initially occupies the first position is
+   moved for expansion, there is no way to reclaim the space until the bulk
+   storage is compacted.  The same holds for the last and first rows of a
+   row-major matrix, of course.
+*/
+
+class presolvehlink
+{ public:
+  int pre, suc;
+} ;
+
+#define NO_LINK -66666666
+
+/*! \relates presolvehlink
+    \brief unlink vector i
+
+  Remove vector i from the ordering.
+*/
+inline void PRESOLVE_REMOVE_LINK(presolvehlink *link, int i)
+{ 
+  int ipre = link[i].pre;
+  int isuc = link[i].suc;
+  if (ipre >= 0) {
+    link[ipre].suc = isuc;
+  }
+  if (isuc >= 0) {
+    link[isuc].pre = ipre;
+  }
+  link[i].pre = NO_LINK, link[i].suc = NO_LINK;
+}
+
+/*! \relates presolvehlink
+    \brief insert vector i after vector j
+
+  Insert vector i between j and j.suc.
+*/
+inline void PRESOLVE_INSERT_LINK(presolvehlink *link, int i, int j)
+{
+  int isuc = link[j].suc;
+  link[j].suc = i;
+  link[i].pre = j;
+  if (isuc >= 0) {
+    link[isuc].pre = i;
+  }
+  link[i].suc = isuc;
+}
+
+/*! \relates presolvehlink
+    \brief relink vector j in place of vector i
+
+   Replace vector i in the ordering with vector j. This is equivalent to
+   <pre>
+     int pre = link[i].pre;
+     PRESOLVE_REMOVE_LINK(link,i);
+     PRESOLVE_INSERT_LINK(link,j,pre);
+   </pre>
+   But, this routine will work even if i happens to be first in the order.
+*/
+inline void PRESOLVE_MOVE_LINK(presolvehlink *link, int i, int j)
+{ 
+  int ipre = link[i].pre;
+  int isuc = link[i].suc;
+  if (ipre >= 0) {
+    link[ipre].suc = j;
+  }
+  if (isuc >= 0) {
+    link[isuc].pre = j;
+  }
+  link[i].pre = NO_LINK, link[i].suc = NO_LINK;
+}
+
+
+/*! \class CoinPresolveMatrix
+    \brief Augments CoinPrePostsolveMatrix with information about the problem
+	   that is only needed during presolve.
+
+  For problem manipulation, this class adds a row-major matrix
+  representation, linked lists that allow for easy manipulation of the matrix
+  when applying presolve transforms, and vectors to track row and column
+  processing status (changed, needs further processing, change prohibited)
+
+  For problem representation, this class adds information about variable type
+  (integer or continuous), an objective offset, and a feasibility tolerance.
+
+  <b>NOTE</b> that the #anyInteger_ and #anyProhibited_ flags are independent
+  of the vectors used to track this information for individual variables
+  (#integerType_ and #rowChanged_ and #colChanged_, respectively).
+
+  <b>NOTE</b> also that at the end of presolve the column-major and row-major
+  matrix representations are loosely packed (<i>i.e.</i>, there may be gaps
+  between columns in the bulk storage arrays).
+
+  <b>NOTE</b> that while you might think that CoinPresolve is prepared to
+  handle minimisation or maximisation, it's unlikely that this still works.
+  This is a good thing: better to convert objective coefficients and duals
+  once, before starting presolve, rather than doing it over and over in
+  each transform that considers dual variables.
+
+  The constructors that take an OSI or ClpSimplex as a parameter really should
+  not be here, but for historical reasons they will likely remain for the
+  forseeable future.  -- lh, 111202 --
+*/
+
+class CoinPresolveMatrix : public CoinPrePostsolveMatrix
+{
+ public:
+
+  /*! \brief `Native' constructor
+
+    This constructor creates an empty object which must then be loaded.
+    On the other hand, it doesn't assume that the client is an
+    OsiSolverInterface.
+  */
+  CoinPresolveMatrix(int ncols_alloc, int nrows_alloc,
+		     CoinBigIndex nelems_alloc) ;
+
+  /*! \brief Clp OSI constructor
+
+    See Clp code for the definition.
+  */
+  CoinPresolveMatrix(int ncols0,
+		    double maxmin,
+		    // end prepost members
+
+		    ClpSimplex * si,
+
+		    // rowrep
+		    int nrows,
+		    CoinBigIndex nelems,
+		 bool doStatus,
+		 double nonLinearVariable,
+                     double bulkRatio);
+
+  /*! \brief Update the model held by a Clp OSI */
+  void update_model(ClpSimplex * si,
+			    int nrows0,
+			    int ncols0,
+			    CoinBigIndex nelems0);
+  /*! \brief Generic OSI constructor
+
+    See OSI code for the definition.
+  */
+  CoinPresolveMatrix(int ncols0,
+		     double maxmin,
+		     // end prepost members
+		     OsiSolverInterface * si,
+		     // rowrep
+		     int nrows,
+		     CoinBigIndex nelems,
+		     bool doStatus,
+		     double nonLinearVariable,
+                     const char * prohibited,
+		     const char * rowProhibited=NULL);
+
+  /*! \brief Update the model held by a generic OSI */
+  void update_model(OsiSolverInterface * si,
+			    int nrows0,
+			    int ncols0,
+			    CoinBigIndex nelems0);
+
+  /// Destructor
+  ~CoinPresolveMatrix();
+
+  /*! \brief Initialize a CoinPostsolveMatrix object, destroying the
+	     CoinPresolveMatrix object.
+
+    See CoinPostsolveMatrix::assignPresolveToPostsolve.
+  */
+  friend void assignPresolveToPostsolve (CoinPresolveMatrix *&preObj) ;
+
+  /*! \name Functions to load the problem representation
+  */
+  //@{
+  /*! \brief Load the cofficient matrix.
+
+    Load the coefficient matrix before loading the other vectors (bounds,
+    objective, variable type) required to define the problem.
+  */
+  void setMatrix(const CoinPackedMatrix *mtx) ;
+
+  /// Count number of empty rows
+  inline int countEmptyRows()
+  { int empty = 0 ;
+    for (int i = 0 ; i < nrows_ ; i++) if (hinrow_[i] == 0) empty++ ;
+    return (empty) ; }
+
+  /*! \brief Set variable type information for a single variable
+
+    Set \p variableType to 0 for continous, 1 for integer.
+    Does not manipulate the #anyInteger_ flag.
+  */
+  inline void setVariableType(int i, int variableType)
+  { if (integerType_ == 0) integerType_ = new unsigned char [ncols0_] ;
+    integerType_[i] = static_cast<unsigned char>(variableType) ; }
+
+  /*! \brief Set variable type information for all variables
+  
+    Set \p variableType[i] to 0 for continuous, 1 for integer.
+    Does not manipulate the #anyInteger_ flag.
+  */
+  void setVariableType(const unsigned char *variableType, int lenParam) ;
+
+  /*! \brief Set the type of all variables
+
+    allIntegers should be true to set the type to integer, false to set the
+    type to continuous.
+  */
+  void setVariableType (bool allIntegers, int lenParam) ;
+
+  /// Set a flag for presence (true) or absence (false) of integer variables
+  inline void setAnyInteger (bool anyInteger = true)
+  { anyInteger_ = anyInteger ; }
+  //@}
+
+  /*! \name Functions to retrieve problem information
+  */
+  //@{
+
+  /// Get row start vector for row-major packed matrix
+  inline const CoinBigIndex *getRowStarts() const
+  { return (mrstrt_) ; }
+  /// Get vector of column indices for row-major packed matrix
+  inline const int *getColIndicesByRow() const
+  { return (hcol_) ; }
+  /// Get vector of elements for row-major packed matrix
+  inline const double *getElementsByRow() const
+  { return (rowels_) ; }
+
+  /*! \brief Check for integrality of the specified variable.
+
+    Consults the #integerType_ vector if present; fallback is the
+    #anyInteger_ flag.
+  */
+  inline bool isInteger (int i) const
+  { if (integerType_ == 0)
+    { return (anyInteger_) ; }
+    else
+    if (integerType_[i] == 1)
+    { return (true) ; }
+    else
+    { return (false) ; } }
+
+  /*! \brief Check if there are any integer variables
+
+    Consults the #anyInteger_ flag
+  */
+  inline bool anyInteger () const
+  { return (anyInteger_) ; }
+  /// Picks up any special options
+  inline int presolveOptions() const
+  { return presolveOptions_;}
+  /// Sets any special options (see #presolveOptions_)
+  inline void setPresolveOptions(int value)
+  { presolveOptions_=value;}
+  //@}
+
+  /*! \name Matrix storage management links
+  
+    Linked lists, modelled after the linked lists used in OSL
+    factorization. They are used for management of the bulk coefficient
+    and minor index storage areas.
+  */
+  //@{
+  /// Linked list for the column-major representation.
+  presolvehlink *clink_;
+  /// Linked list for the row-major representation.
+  presolvehlink *rlink_;
+  //@}
+
+  /// Objective function offset introduced during presolve
+  double dobias_ ;
+
+  /// Adjust objective function constant offset
+  inline void change_bias(double change_amount)
+  {
+    dobias_ += change_amount ;
+  # if PRESOLVE_DEBUG > 2
+    assert(fabs(change_amount)<1.0e50) ;
+    if (change_amount)
+      PRESOLVE_STMT(printf("changing bias by %g to %g\n",
+			    change_amount, dobias_)) ;
+  # endif
+  }
+
+  /*! \name Row-major representation
+
+    Common row-major format: A pair of vectors with positional
+    correspondence to hold coefficients and column indices, and a second pair
+    of vectors giving the starting position and length of each row in
+    the first pair.
+  */
+  //@{
+  /// Vector of row start positions in #hcol, #rowels_
+  CoinBigIndex *mrstrt_;
+  /// Vector of row lengths
+  int *hinrow_;
+  /// Coefficients (positional correspondence with #hcol_)
+  double *rowels_;
+  /// Column indices (positional correspondence with #rowels_)
+  int *hcol_;
+  //@}
+
+  /// Tracks integrality of columns (1 for integer, 0 for continuous)
+  unsigned char *integerType_;
+  /*! \brief Flag to say if any variables are integer
+
+    Note that this flag is <i>not</i> manipulated by the various
+    \c setVariableType routines.
+  */
+  bool anyInteger_ ;
+  /// Print statistics for tuning
+  bool tuning_;
+  /// Say we want statistics - also set time
+  void statistics();
+  /// Start time of presolve
+  double startTime_;
+
+  /// Bounds can be moved by this to retain feasibility
+  double feasibilityTolerance_;
+  /// Return feasibility tolerance
+  inline double feasibilityTolerance()
+  { return (feasibilityTolerance_) ; }
+  /// Set feasibility tolerance
+  inline void setFeasibilityTolerance (double val)
+  { feasibilityTolerance_ = val ; }
+
+  /*! \brief Output status: 0 = feasible, 1 = infeasible, 2 = unbounded
+
+    Actually implemented as single bit flags: 1^0 = infeasible, 1^1 =
+    unbounded.
+  */
+  int status_;
+  /// Returns problem status (0 = feasible, 1 = infeasible, 2 = unbounded)
+  inline int status()
+  { return (status_) ; }
+  /// Set problem status
+  inline void setStatus(int status)
+  { status_ = (status&0x3) ; }
+
+  /*! \brief Presolve pass number
+
+    Should be incremented externally by the method controlling application of
+    presolve transforms.
+    Used to control the execution of testRedundant (evoked by the
+    implied_free transform).
+  */
+  int pass_;
+  /// Set pass number
+  inline void setPass (int pass = 0)
+  { pass_ = pass ; }
+
+  /*! \brief Maximum substitution level
+
+    Used to control the execution of subst from implied_free
+  */
+  int maxSubstLevel_;
+  /// Set Maximum substitution level (normally 3)
+  inline void setMaximumSubstitutionLevel (int level)
+  { maxSubstLevel_ = level ; }
+
+
+  /*! \name Row and column processing status
+
+    Information used to determine if rows or columns can be changed and
+    if they require further processing due to changes.
+
+    There are four major lists: the [row,col]ToDo list, and the
+    [row,col]NextToDo list.  In general, a transform processes entries from
+    the ToDo list and adds entries to the NextToDo list.
+
+    There are two vectors, [row,col]Changed, which track the status of
+    individual rows and columns.
+  */
+  //@{
+  /*! \brief Column change status information
+
+    Coded using the following bits:
+    <ul>
+      <li> 0x01: Column has changed
+      <li> 0x02: preprocessing prohibited
+      <li> 0x04: Column has been used
+      <li> 0x08: Column originally had infinite ub
+    </ul>
+  */
+  unsigned char * colChanged_;
+  /// Input list of columns to process
+  int * colsToDo_;
+  /// Length of #colsToDo_
+  int numberColsToDo_;
+  /// Output list of columns to process next
+  int * nextColsToDo_;
+  /// Length of #nextColsToDo_
+  int numberNextColsToDo_;
+
+  /*! \brief Row change status information
+
+    Coded using the following bits:
+    <ul>
+      <li> 0x01: Row has changed
+      <li> 0x02: preprocessing prohibited
+      <li> 0x04: Row has been used
+    </ul>
+  */
+  unsigned char * rowChanged_;
+  /// Input list of rows to process
+  int * rowsToDo_;
+  /// Length of #rowsToDo_
+  int numberRowsToDo_;
+  /// Output list of rows to process next
+  int * nextRowsToDo_;
+  /// Length of #nextRowsToDo_
+  int numberNextRowsToDo_;
+  /*! \brief Fine control over presolve actions
+
+    Set/clear the following bits to allow or suppress actions:
+      - 0x01 allow duplicate column tests for integer variables
+      - 0x02 not used
+      - 0x04 set to inhibit x+y+z=1 mods
+      - 0x08 not used
+      - 0x10 set to allow stuff which won't unroll easily (overlapping
+          duplicate rows; opportunistic fixing of variables from bound
+	  propagation).
+      - 0x04000 allow presolve transforms to arbitrarily ignore infeasibility
+          and set arbitrary feasible bounds.
+      - 0x10000 instructs implied_free_action to be `more lightweight'; will
+          return without doing anything after 15 presolve passes.
+      - 0x20000 instructs implied_free_action to remove small created elements
+      - 0x80000000 set by presolve to say dupcol_action compressed columns
+  */
+  int presolveOptions_;
+  /*! Flag to say if any rows or columns are marked as prohibited
+
+    Note that this flag is <i>not</i> manipulated by any of the
+    various \c set*Prohibited routines.
+  */
+  bool anyProhibited_;
+  //@}
+
+  /*! \name Scratch work arrays
+
+    Preallocated work arrays are useful to avoid having to allocate and free
+    work arrays in individual presolve methods.
+
+    All are allocated from #setMatrix by #initializeStuff, freed from
+    #~CoinPresolveMatrix.  You can use #deleteStuff followed by
+    #initializeStuff to remove and recreate them.
+  */
+  //@{
+  /// Preallocated scratch work array, 3*nrows_
+  int *usefulRowInt_ ;
+  /// Preallocated scratch work array, 2*nrows_
+  double *usefulRowDouble_ ;
+  /// Preallocated scratch work array, 2*ncols_
+  int *usefulColumnInt_ ;
+  /// Preallocated scratch work array, ncols_
+  double *usefulColumnDouble_ ;
+  /// Array of random numbers (max row,column)
+  double *randomNumber_ ;
+
+  /// Work array for count of infinite contributions to row lhs upper bound
+  int *infiniteUp_ ;
+  /// Work array for sum of finite contributions to row lhs upper bound
+  double *sumUp_ ;
+  /// Work array for count of infinite contributions to row lhs lower bound
+  int *infiniteDown_ ;
+  /// Work array for sum of finite contributions to row lhs lower bound
+  double *sumDown_ ;
+  //@}
+
+  /*! \brief Recompute row lhs bounds
+
+    Calculate finite contributions to row lhs upper and lower bounds
+    and count infinite contributions. Returns the number of rows found
+    to be infeasible.
+
+    If \p whichRow < 0, bounds are recomputed for all rows.
+
+    As of 110611, this seems to be a work in progress in the sense that it's
+    barely used by the existing presolve code.
+  */
+  int recomputeSums(int whichRow) ;
+
+  /// Allocate scratch arrays
+  void initializeStuff() ;
+  /// Free scratch arrays
+  void deleteStuff() ;
+
+  /*! \name Functions to manipulate row and column processing status */
+  //@{
+
+  /*! \brief Initialise the column ToDo lists
+
+    Places all columns in the #colsToDo_ list except for columns marked
+    as prohibited (<i>viz.</i> #colChanged_).
+  */
+  void initColsToDo () ;
+
+  /*! \brief Step column ToDo lists
+
+    Moves columns on the #nextColsToDo_ list to the #colsToDo_ list, emptying
+    #nextColsToDo_. Returns the number of columns transferred.
+  */
+  int stepColsToDo () ;
+
+  /// Return the number of columns on the #colsToDo_ list
+  inline int numberColsToDo()
+  { return (numberColsToDo_) ; }
+
+  /// Has column been changed?
+  inline bool colChanged(int i) const {
+    return (colChanged_[i]&1)!=0;
+  }
+  /// Mark column as not changed
+  inline void unsetColChanged(int i) {
+    colChanged_[i] = static_cast<unsigned char>(colChanged_[i] & (~1)) ;
+  }
+  /// Mark column as changed.
+  inline void setColChanged(int i) {
+    colChanged_[i] = static_cast<unsigned char>(colChanged_[i] | (1)) ;
+  }
+  /// Mark column as changed and add to list of columns to process next
+  inline void addCol(int i) {
+    if ((colChanged_[i]&1)==0) {
+      colChanged_[i] = static_cast<unsigned char>(colChanged_[i] | (1)) ;
+      nextColsToDo_[numberNextColsToDo_++] = i;
+    }
+  }
+  /// Test if column is eligible for preprocessing
+  inline bool colProhibited(int i) const {
+    return (colChanged_[i]&2)!=0;
+  }
+  /*! \brief Test if column is eligible for preprocessing
+
+    The difference between this method and #colProhibited() is that this
+    method first tests #anyProhibited_ before examining the specific entry
+    for the specified column.
+  */
+  inline bool colProhibited2(int i) const {
+    if (!anyProhibited_)
+      return false;
+    else
+      return (colChanged_[i]&2)!=0;
+  }
+  /// Mark column as ineligible for preprocessing
+  inline void setColProhibited(int i) {
+    colChanged_[i] = static_cast<unsigned char>(colChanged_[i] | (2)) ;
+  }
+  /*! \brief Test if column is marked as used
+  
+    This is for doing faster lookups to see where two columns have entries
+    in common.
+  */
+  inline bool colUsed(int i) const {
+    return (colChanged_[i]&4)!=0;
+  }
+  /// Mark column as used
+  inline void setColUsed(int i) {
+    colChanged_[i] = static_cast<unsigned char>(colChanged_[i] | (4)) ;
+  }
+  /// Mark column as unused
+  inline void unsetColUsed(int i) {
+    colChanged_[i] = static_cast<unsigned char>(colChanged_[i] & (~4)) ;
+  }
+  /// Has column infinite ub (originally)
+  inline bool colInfinite(int i) const {
+    return (colChanged_[i]&8)!=0;
+  }
+  /// Mark column as not infinite ub (originally)
+  inline void unsetColInfinite(int i) {
+    colChanged_[i] = static_cast<unsigned char>(colChanged_[i] & (~8)) ;
+  }
+  /// Mark column as infinite ub (originally)
+  inline void setColInfinite(int i) {
+    colChanged_[i] = static_cast<unsigned char>(colChanged_[i] | (8)) ;
+  }
+
+  /*! \brief Initialise the row ToDo lists
+
+    Places all rows in the #rowsToDo_ list except for rows marked
+    as prohibited (<i>viz.</i> #rowChanged_).
+  */
+  void initRowsToDo () ;
+
+  /*! \brief Step row ToDo lists
+
+    Moves rows on the #nextRowsToDo_ list to the #rowsToDo_ list, emptying
+    #nextRowsToDo_. Returns the number of rows transferred.
+  */
+  int stepRowsToDo () ;
+
+  /// Return the number of rows on the #rowsToDo_ list
+  inline int numberRowsToDo()
+  { return (numberRowsToDo_) ; }
+
+  /// Has row been changed?
+  inline bool rowChanged(int i) const {
+    return (rowChanged_[i]&1)!=0;
+  }
+  /// Mark row as not changed
+  inline void unsetRowChanged(int i) {
+    rowChanged_[i] = static_cast<unsigned char>(rowChanged_[i] & (~1)) ;
+  }
+  /// Mark row as changed
+  inline void setRowChanged(int i) {
+    rowChanged_[i] = static_cast<unsigned char>(rowChanged_[i] | (1)) ;
+  }
+  /// Mark row as changed and add to list of rows to process next
+  inline void addRow(int i) {
+    if ((rowChanged_[i]&1)==0) {
+      rowChanged_[i] = static_cast<unsigned char>(rowChanged_[i] | (1)) ;
+      nextRowsToDo_[numberNextRowsToDo_++] = i;
+    }
+  }
+  /// Test if row is eligible for preprocessing
+  inline bool rowProhibited(int i) const {
+    return (rowChanged_[i]&2)!=0;
+  }
+  /*! \brief Test if row is eligible for preprocessing
+
+    The difference between this method and #rowProhibited() is that this
+    method first tests #anyProhibited_ before examining the specific entry
+    for the specified row.
+  */
+  inline bool rowProhibited2(int i) const {
+    if (!anyProhibited_)
+      return false;
+    else
+      return (rowChanged_[i]&2)!=0;
+  }
+  /// Mark row as ineligible for preprocessing
+  inline void setRowProhibited(int i) {
+    rowChanged_[i] = static_cast<unsigned char>(rowChanged_[i] | (2)) ;
+  }
+  /*! \brief Test if row is marked as used
+
+     This is for doing faster lookups to see where two rows have entries
+     in common.  It can be used anywhere as long as it ends up zeroed out.
+  */
+  inline bool rowUsed(int i) const {
+    return (rowChanged_[i]&4)!=0;
+  }
+  /// Mark row as used
+  inline void setRowUsed(int i) {
+    rowChanged_[i] = static_cast<unsigned char>(rowChanged_[i] | (4)) ;
+  }
+  /// Mark row as unused
+  inline void unsetRowUsed(int i) {
+    rowChanged_[i] = static_cast<unsigned char>(rowChanged_[i] & (~4)) ;
+  }
+
+
+  /// Check if there are any prohibited rows or columns 
+  inline bool anyProhibited() const
+  { return anyProhibited_;}
+  /// Set a flag for presence of prohibited rows or columns
+  inline void setAnyProhibited(bool val = true)
+  { anyProhibited_ = val ; }
+  //@}
+
+};
+
+/*! \class CoinPostsolveMatrix
+    \brief Augments CoinPrePostsolveMatrix with information about the problem
+	   that is only needed during postsolve.
+
+  The notable point is that the matrix representation is threaded. The
+  representation is column-major and starts with the standard two pairs of
+  arrays: one pair to hold the row indices and coefficients, the second pair
+  to hold the column starting positions and lengths. But the row indices and
+  coefficients for a column do not necessarily occupy a contiguous block in
+  their respective arrays. Instead, a link array gives the position of the
+  next (row index,coefficient) pair. If the row index and value of a
+  coefficient a<p,j> occupy position kp in their arrays, then the position of
+  the next coefficient a<q,j> is found as kq = link[kp].
+
+  This threaded representation allows for efficient expansion of columns as
+  rows are reintroduced during postsolve transformations. The basic packed
+  structures are allocated to the expected size of the postsolved matrix,
+  and as new coefficients are added, their location is simply added to the
+  thread for the column.
+
+  There is no provision to convert the threaded representation to a packed
+  representation. In the context of postsolve, it's not required. (You did
+  keep a copy of the original matrix, eh?)
+
+  The constructors that take an OSI or ClpSimplex as a parameter really should
+  not be here, but for historical reasons they will likely remain for the
+  forseeable future.  -- lh, 111202 --
+*/
+class CoinPostsolveMatrix : public CoinPrePostsolveMatrix
+{
+ public:
+
+  /*! \brief `Native' constructor
+
+    This constructor creates an empty object which must then be loaded.
+    On the other hand, it doesn't assume that the client is an
+    OsiSolverInterface.
+  */
+  CoinPostsolveMatrix(int ncols_alloc, int nrows_alloc,
+		      CoinBigIndex nelems_alloc) ;
+
+
+  /*! \brief Clp OSI constructor
+
+    See Clp code for the definition.
+  */
+  CoinPostsolveMatrix(ClpSimplex * si,
+
+		   int ncols0,
+		   int nrows0,
+		   CoinBigIndex nelems0,
+		     
+		   double maxmin_,
+		   // end prepost members
+
+		   double *sol,
+		   double *acts,
+
+		   unsigned char *colstat,
+		   unsigned char *rowstat);
+
+  /*! \brief Generic OSI constructor
+
+    See OSI code for the definition.
+  */
+  CoinPostsolveMatrix(OsiSolverInterface * si,
+
+		   int ncols0,
+		   int nrows0,
+		   CoinBigIndex nelems0,
+		     
+		   double maxmin_,
+		   // end prepost members
+
+		   double *sol,
+		   double *acts,
+
+		   unsigned char *colstat,
+		   unsigned char *rowstat);
+
+  /*! \brief Load an empty CoinPostsolveMatrix from a CoinPresolveMatrix
+
+    This routine transfers the contents of the CoinPrePostsolveMatrix
+    object from the CoinPresolveMatrix object to the CoinPostsolveMatrix
+    object and completes initialisation of the CoinPostsolveMatrix object.
+    The empty shell of the CoinPresolveMatrix object is destroyed.
+
+    The routine expects an empty CoinPostsolveMatrix object. If handed a loaded
+    object, a lot of memory will leak.
+  */
+  void assignPresolveToPostsolve (CoinPresolveMatrix *&preObj) ;
+
+  /// Destructor
+  ~CoinPostsolveMatrix();
+
+  /*! \name Column thread structures
+
+    As mentioned in the class documentation, the entries for a given column
+    do not necessarily occupy a contiguous block of space. The #link_ array
+    is used to maintain the threading. There is one thread for each column,
+    and a single thread for all free entries in #hrow_ and #colels_.
+
+    The allocated size of #link_ must be at least as large as the allocated
+    size of #hrow_ and #colels_.
+  */
+  //@{
+
+  /*! \brief First entry in free entries thread */
+  CoinBigIndex free_list_;
+  /// Allocated size of #link_
+  int maxlink_;
+  /*! \brief Thread array
+
+    Within a thread, link_[k] points to the next entry in the thread.
+  */
+  CoinBigIndex *link_;
+
+  //@}
+
+  /*! \name Debugging aids
+
+     These arrays are allocated only when CoinPresolve is compiled with
+     PRESOLVE_DEBUG defined. They hold codes which track the reason that
+     a column or row is added to the problem during postsolve.
+  */
+  //@{
+  char *cdone_;
+  char *rdone_;
+  //@}
+
+  /// debug
+  void check_nbasic();
+
+};
+
+
+/*! \defgroup MtxManip Presolve Matrix Manipulation Functions
+
+  Functions to work with the loosely packed and threaded packed matrix
+  structures used during presolve and postsolve.
+*/
+//@{
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Initialise linked list for major vector order in bulk storage
+*/
+
+void presolve_make_memlists(/*CoinBigIndex *starts,*/ int *lengths,
+			    presolvehlink *link, int n);
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Make sure a major-dimension vector k has room for one more
+	   coefficient.
+
+    You can use this directly, or use the inline wrappers presolve_expand_col
+    and presolve_expand_row
+*/
+bool presolve_expand_major(CoinBigIndex *majstrts, double *majels,
+			   int *minndxs, int *majlens,
+			   presolvehlink *majlinks, int nmaj, int k) ;
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Make sure a column (colx) in a column-major matrix has room for
+	   one more coefficient
+*/
+
+inline bool presolve_expand_col(CoinBigIndex *mcstrt, double *colels,
+				int *hrow, int *hincol,
+				presolvehlink *clink, int ncols, int colx)
+{ return presolve_expand_major(mcstrt,colels,
+			       hrow,hincol,clink,ncols,colx) ; }
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Make sure a row (rowx) in a row-major matrix has room for one
+	   more coefficient
+*/
+
+inline bool presolve_expand_row(CoinBigIndex *mrstrt, double *rowels,
+				int *hcol, int *hinrow,
+				presolvehlink *rlink, int nrows, int rowx)
+{ return presolve_expand_major(mrstrt,rowels,
+			       hcol,hinrow,rlink,nrows,rowx) ; }
+
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Find position of a minor index in a major vector.
+
+    The routine returns the position \c k in \p minndxs for the specified
+    minor index \p tgt. It will abort if the entry does not exist. Can be
+    used directly or via the inline wrappers presolve_find_row and
+    presolve_find_col.
+*/
+inline CoinBigIndex presolve_find_minor(int tgt,
+					CoinBigIndex ks, CoinBigIndex ke,
+				        const int *minndxs)
+{ CoinBigIndex k ;
+  for (k = ks ; k < ke ; k++)
+#ifndef NDEBUG
+  { if (minndxs[k] == tgt)
+      return (k) ; }
+  DIE("FIND_MINOR") ;
+
+  abort () ; return -1;
+#else
+  { if (minndxs[k] == tgt)
+      break ; }
+  return (k) ;
+#endif
+}
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Find position of a row in a column in a column-major matrix.
+
+    The routine returns the position \c k in \p hrow for the specified \p row.
+    It will abort if the entry does not exist.
+*/
+inline CoinBigIndex presolve_find_row(int row, CoinBigIndex kcs,
+				      CoinBigIndex kce, const int *hrow)
+{ return presolve_find_minor(row,kcs,kce,hrow) ; }
+
+/*! \relates CoinPostsolveMatrix
+    \brief Find position of a column in a row in a row-major matrix.
+
+    The routine returns the position \c k in \p hcol for the specified \p col.
+    It will abort if the entry does not exist.
+*/
+inline CoinBigIndex presolve_find_col(int col, CoinBigIndex krs,
+				      CoinBigIndex kre, const int *hcol)
+{ return presolve_find_minor(col,krs,kre,hcol) ; }
+
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Find position of a minor index in a major vector.
+
+    The routine returns the position \c k in \p minndxs for the specified
+    minor index \p tgt.  A return value of \p ke means the entry does not
+    exist.  Can be used directly or via the inline wrappers
+    presolve_find_row1 and presolve_find_col1.
+*/
+CoinBigIndex presolve_find_minor1(int tgt, CoinBigIndex ks, CoinBigIndex ke,
+				  const int *minndxs);
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Find position of a row in a column in a column-major matrix.
+
+    The routine returns the position \c k in \p hrow for the specified \p row.
+    A return value of \p kce means the entry does not exist.
+*/
+inline CoinBigIndex presolve_find_row1(int row, CoinBigIndex kcs,
+				       CoinBigIndex kce, const int *hrow)
+{ return presolve_find_minor1(row,kcs,kce,hrow) ; } 
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Find position of a column in a row in a row-major matrix.
+
+    The routine returns the position \c k in \p hcol for the specified \p col.
+    A return value of \p kre means the entry does not exist.
+*/
+inline CoinBigIndex presolve_find_col1(int col, CoinBigIndex krs,
+				       CoinBigIndex kre, const int *hcol)
+{ return presolve_find_minor1(col,krs,kre,hcol) ; } 
+
+/*! \relates CoinPostsolveMatrix
+    \brief Find position of a minor index in a major vector in a threaded
+	   matrix.
+
+    The routine returns the position \c k in \p minndxs for the specified
+    minor index \p tgt. It will abort if the entry does not exist. Can be
+    used directly or via the inline wrapper presolve_find_row2.
+*/
+CoinBigIndex presolve_find_minor2(int tgt, CoinBigIndex ks, int majlen,
+				  const int *minndxs,
+				  const CoinBigIndex *majlinks) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Find position of a row in a column in a column-major threaded
+	   matrix.
+
+    The routine returns the position \c k in \p hrow for the specified \p row.
+    It will abort if the entry does not exist.
+*/
+inline CoinBigIndex presolve_find_row2(int row, CoinBigIndex kcs, int collen,
+				       const int *hrow,
+				       const CoinBigIndex *clinks)
+{ return presolve_find_minor2(row,kcs,collen,hrow,clinks) ; }
+
+/*! \relates CoinPostsolveMatrix
+    \brief Find position of a minor index in a major vector in a threaded
+	   matrix.
+
+    The routine returns the position \c k in \p minndxs for the specified
+    minor index \p tgt. It will return -1 if the entry does not exist.
+    Can be used directly or via the inline wrappers presolve_find_row3.
+*/
+CoinBigIndex presolve_find_minor3(int tgt, CoinBigIndex ks, int majlen,
+				  const int *minndxs,
+				  const CoinBigIndex *majlinks) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Find position of a row in a column in a column-major threaded
+	   matrix.
+
+    The routine returns the position \c k in \p hrow for the specified \p row.
+    It will return -1 if the entry does not exist.
+*/
+inline CoinBigIndex presolve_find_row3(int row, CoinBigIndex kcs, int collen,
+				       const int *hrow,
+				       const CoinBigIndex *clinks)
+{ return presolve_find_minor3(row,kcs,collen,hrow,clinks) ; }
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Delete the entry for a minor index from a major vector.
+
+   Deletes the entry for \p minndx from the major vector \p majndx.
+   Specifically, the relevant entries are removed from the minor index
+   (\p minndxs) and coefficient (\p els) arrays and the vector length (\p
+   majlens) is decremented.  Loose packing is maintained by swapping the last
+   entry in the row into the position occupied by the deleted entry.
+*/
+inline void presolve_delete_from_major(int majndx, int minndx,
+				const CoinBigIndex *majstrts,
+				int *majlens, int *minndxs, double *els) 
+{
+  const CoinBigIndex ks = majstrts[majndx] ;
+  const CoinBigIndex ke = ks+majlens[majndx] ;
+
+  const CoinBigIndex kmi = presolve_find_minor(minndx,ks,ke,minndxs) ;
+
+  minndxs[kmi] = minndxs[ke-1] ;
+  els[kmi] = els[ke-1] ;
+  majlens[majndx]-- ;
+  
+  return ;
+}
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Delete marked entries
+
+    Removes the entries specified in \p marked, compressing the major vector
+    to maintain loose packing. \p marked is cleared in the process.
+*/
+inline void presolve_delete_many_from_major(int majndx, char *marked,
+				const CoinBigIndex *majstrts,
+				int *majlens, int *minndxs, double *els) 
+{ 
+  const CoinBigIndex ks = majstrts[majndx] ;
+  const CoinBigIndex ke = ks+majlens[majndx] ;
+  CoinBigIndex put = ks ;
+  for (CoinBigIndex k = ks ; k < ke ; k++) {
+    int iMinor = minndxs[k] ;
+    if (!marked[iMinor]) {
+      minndxs[put] = iMinor ;
+      els[put++] = els[k] ;
+    } else {
+      marked[iMinor] = 0 ;
+    }
+  } 
+  majlens[majndx] = put-ks ;
+  return ;
+}
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Delete the entry for row \p row from column \p col in a
+	   column-major matrix
+
+   Deletes the entry for \p row from the major vector for \p col.
+   Specifically, the relevant entries are removed from the row index (\p
+   hrow) and coefficient (\p colels) arrays and the vector length (\p
+   hincol) is decremented.  Loose packing is maintained by swapping the last
+   entry in the row into the position occupied by the deleted entry.
+*/
+inline void presolve_delete_from_col(int row, int col,
+				     const CoinBigIndex *mcstrt,
+				     int *hincol, int *hrow, double *colels)
+{ presolve_delete_from_major(col,row,mcstrt,hincol,hrow,colels) ; }
+
+/*! \relates CoinPrePostsolveMatrix
+    \brief Delete the entry for column \p col from row \p row in a
+	   row-major matrix
+
+   Deletes the entry for \p col from the major vector for \p row.
+   Specifically, the relevant entries are removed from the column index (\p
+   hcol) and coefficient (\p rowels) arrays and the vector length (\p
+   hinrow) is decremented.  Loose packing is maintained by swapping the last
+   entry in the column into the position occupied by the deleted entry.
+*/
+inline void presolve_delete_from_row(int row, int col,
+				     const CoinBigIndex *mrstrt,
+				     int *hinrow, int *hcol, double *rowels)
+{ presolve_delete_from_major(row,col,mrstrt,hinrow,hcol,rowels) ; }
+
+/*! \relates CoinPostsolveMatrix
+    \brief Delete the entry for a minor index from a major vector in a
+    threaded matrix.
+
+   Deletes the entry for \p minndx from the major vector \p majndx.
+   Specifically, the relevant entries are removed from the minor index (\p
+   minndxs) and coefficient (\p els) arrays and the vector length (\p
+   majlens) is decremented. The thread for the major vector is relinked
+   around the deleted entry and the space is returned to the free list.
+*/
+void presolve_delete_from_major2 (int majndx, int minndx,
+				  CoinBigIndex *majstrts, int *majlens,
+				  int *minndxs, int *majlinks,
+				   CoinBigIndex *free_listp) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Delete the entry for row \p row from column \p col in a
+	   column-major threaded matrix
+
+   Deletes the entry for \p row from the major vector for \p col.
+   Specifically, the relevant entries are removed from the row index (\p
+   hrow) and coefficient (\p colels) arrays and the vector length (\p
+   hincol) is decremented. The thread for the major vector is relinked
+   around the deleted entry and the space is returned to the free list.
+*/
+inline void presolve_delete_from_col2(int row, int col, CoinBigIndex *mcstrt,
+				      int *hincol, int *hrow,
+				      int *clinks, CoinBigIndex *free_listp)
+{ presolve_delete_from_major2(col,row,mcstrt,hincol,hrow,clinks,free_listp) ; }
+
+//@}
+
+/*! \defgroup PresolveUtilities Presolve Utility Functions
+
+  Utilities used by multiple presolve transform objects.
+*/
+//@{
+
+/*! \brief Duplicate a major-dimension vector; optionally omit the entry
+	   with minor index \p tgt.
+
+    Designed to copy a major-dimension vector from the paired coefficient
+    (\p elems) and minor index (\p indices) arrays used in the standard
+    packed matrix representation. Copies \p length entries starting at
+    \p offset.
+    
+    If \p tgt is specified, the entry with minor index == \p tgt is
+    omitted from the copy.
+*/
+double *presolve_dupmajor(const double *elems, const int *indices,
+			  int length, CoinBigIndex offset, int tgt = -1);
+
+/// Initialize a vector with random numbers
+void coin_init_random_vec(double *work, int n);
+
+//@}
+
+
+#endif
diff --git a/cbits/coin/CoinPresolveMonitor.cpp b/cbits/coin/CoinPresolveMonitor.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveMonitor.cpp
@@ -0,0 +1,301 @@
+/* $Id: CoinPresolveMonitor.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+// Copyright (C) 2011 Lou Hafer
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cassert>
+#include <iostream>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveMonitor.hpp"
+
+/*! \file
+
+  This file contains methods for CoinPresolveMonitor, used to monitor changes
+  to a row or column during presolve and postsolve
+*/
+
+/*
+  Constructors
+*/
+
+/*
+  Default constructor
+*/
+CoinPresolveMonitor::CoinPresolveMonitor ()
+{ }
+
+/*
+  Constructor to initialise from a CoinPresolveMatrix (not threaded)
+*/
+CoinPresolveMonitor::CoinPresolveMonitor (const CoinPresolveMatrix *mtx,
+					  bool isRow,
+					  int k)
+{
+  ndx_ = k ;
+  isRow_ = isRow ;
+
+  if (isRow) {
+    origVec_ = extractRow(k,mtx) ;
+    const double *blow = mtx->getRowLower() ;
+    lb_ = blow[k] ;
+    const double *b = mtx->getRowUpper() ;
+    ub_ = b[k] ;
+  } else {
+    origVec_ = extractCol(k,mtx) ;
+    const double *lb = mtx->getColLower() ;
+    lb_ = lb[k] ;
+    const double *ub = mtx->getColUpper() ;
+    ub_ = ub[k] ;
+  }
+  origVec_->sortIncrIndex() ;
+}
+/*
+  Constructor to initialise from a CoinPostsolveMatrix
+*/
+CoinPresolveMonitor::CoinPresolveMonitor (const CoinPostsolveMatrix *mtx,
+					  bool isRow,
+					  int k)
+{
+  ndx_ = k ;
+  isRow_ = isRow ;
+
+  if (isRow) {
+    origVec_ = extractRow(k,mtx) ;
+    const double *blow = mtx->getRowLower() ;
+    lb_ = blow[k] ;
+    const double *b = mtx->getRowUpper() ;
+    ub_ = b[k] ;
+  } else {
+    origVec_ = extractCol(k,mtx) ;
+    const double *lb = mtx->getColLower() ;
+    lb_ = lb[k] ;
+    const double *ub = mtx->getColUpper() ;
+    ub_ = ub[k] ;
+  }
+  origVec_->sortIncrIndex() ;
+}
+
+/*
+  Extract a row from a CoinPresolveMatrix. Since a CoinPresolveMatrix contains
+  both row-ordered and column-ordered copies, this is relatively efficient.
+*/
+CoinPackedVector *CoinPresolveMonitor::extractRow (int i,
+					const CoinPresolveMatrix *mtx) const
+{
+  const CoinBigIndex *rowStarts = mtx->getRowStarts() ;
+  const int *colIndices = mtx->getColIndicesByRow() ;
+  const double *coeffs = mtx->getElementsByRow() ;
+  const int rowLen = mtx->hinrow_[i] ;
+  const CoinBigIndex &ii = rowStarts[i] ;
+  return (new CoinPackedVector(rowLen,&colIndices[ii],&coeffs[ii])) ;
+}
+
+/*
+  Extract a column from a CoinPresolveMatrix. Since a CoinPresolveMatrix
+  contains both row-ordered and column-ordered copies, this is relatively
+  efficient.
+*/
+CoinPackedVector *CoinPresolveMonitor::extractCol (int j,
+					const CoinPresolveMatrix *mtx) const
+{
+  const CoinBigIndex *colStarts = mtx->getColStarts() ;
+  const int *colLens = mtx->getColLengths() ;
+  const int *rowIndices = mtx->getRowIndicesByCol() ;
+  const double *coeffs = mtx->getElementsByCol() ;
+  const CoinBigIndex &jj = colStarts[j] ;
+  return (new CoinPackedVector(colLens[j],&rowIndices[jj],&coeffs[jj])) ;
+}
+
+/*
+  Extract a row from a CoinPostsolveMatrix. This is very painful, because
+  the matrix is threaded column-ordered only. We have to scan every entry
+  in the matrix, looking for entries that match the requested row index.
+*/
+CoinPackedVector *CoinPresolveMonitor::extractRow (int i,
+					const CoinPostsolveMatrix *mtx) const
+{
+  const CoinBigIndex *colStarts = mtx->getColStarts() ;
+  const int *colLens = mtx->getColLengths() ;
+  const double *coeffs = mtx->getElementsByCol() ;
+  const int *rowIndices = mtx->getRowIndicesByCol() ;
+  const CoinBigIndex *colLinks = mtx->link_ ;
+
+  int n = mtx->getNumCols() ;
+
+  CoinPackedVector *pkvec = new CoinPackedVector() ;
+
+  for (int j = 0 ; j < n ; j++) {
+    const CoinBigIndex ii =
+	presolve_find_row3(i,colStarts[j],colLens[j],rowIndices,colLinks) ;
+    if (ii >= 0) pkvec->insert(j,coeffs[ii]) ;
+  }
+
+  return (pkvec) ;
+}
+
+/*
+  Extract a column from a CoinPostsolveMatrix. At least here we only need to
+  walk one threaded column.
+*/
+CoinPackedVector *CoinPresolveMonitor::extractCol (int j,
+					const CoinPostsolveMatrix *mtx) const
+{
+  const CoinBigIndex *colStarts = mtx->getColStarts() ;
+  const int *colLens = mtx->getColLengths() ;
+  const double *coeffs = mtx->getElementsByCol() ;
+  const int *rowIndices = mtx->getRowIndicesByCol() ;
+  const CoinBigIndex *colLinks = mtx->link_ ;
+
+  CoinPackedVector *pkvec = new CoinPackedVector() ;
+
+  CoinBigIndex jj = colStarts[j] ;
+  const int &lenj = colLens[j] ;
+  for (int k = 0 ; k < lenj ; k++) {
+    pkvec->insert(rowIndices[jj],coeffs[jj]) ;
+    jj = colLinks[jj] ;
+  }
+  
+  return (pkvec) ;
+}
+
+/*
+  Extract the current version of the row or column from the CoinPresolveMatrix
+  into a CoinPackedVector, sort it, and compare it to the stored
+  CoinPackedVector. Differences are reported to std::cout.
+*/
+void CoinPresolveMonitor::checkAndTell (const CoinPresolveMatrix *mtx)
+{
+  CoinPackedVector *curVec = 0 ;
+  const double *lbs = 0 ;
+  const double *ubs = 0 ;
+  if (isRow_) {
+    lbs = mtx->getRowLower() ;
+    ubs = mtx->getRowUpper() ;
+    curVec = extractRow(ndx_,mtx) ;
+  } else {
+    curVec = extractCol(ndx_,mtx) ;
+    lbs = mtx->getColLower() ;
+    ubs = mtx->getColUpper() ;
+  }
+  checkAndTell(curVec,lbs[ndx_],ubs[ndx_]) ;
+}
+
+/*
+  Extract the current version of the row or column from the CoinPostsolveMatrix
+  into a CoinPackedVector, sort it, and compare it to the stored
+  CoinPackedVector. Differences are reported to std::cout.
+*/
+void CoinPresolveMonitor::checkAndTell (const CoinPostsolveMatrix *mtx)
+{
+  CoinPackedVector *curVec = 0 ;
+  const double *lbs = 0 ;
+  const double *ubs = 0 ;
+  if (isRow_) {
+    lbs = mtx->getRowLower() ;
+    ubs = mtx->getRowUpper() ;
+    curVec = extractRow(ndx_,mtx) ;
+  } else {
+    curVec = extractCol(ndx_,mtx) ;
+    lbs = mtx->getColLower() ;
+    ubs = mtx->getColUpper() ;
+  }
+  checkAndTell(curVec,lbs[ndx_],ubs[ndx_]) ;
+}
+
+/*
+  And the worker method, which does the actual diff of the vectors and also
+  checks the bounds.
+
+  If the vector fails a quick check with ==, extract the indices, merge them,
+  and then walk the indices checking for presence in each vector. Where both
+  elements are present, check the coefficient. Report any differences.
+
+  Not the most efficient implementation, but it leverages existing
+  capabilities.
+*/
+void CoinPresolveMonitor::checkAndTell (CoinPackedVector *curVec,
+					double lb, double ub)
+{
+  curVec->sortIncrIndex() ;
+
+  std::cout
+    << "checking " << ((isRow_)?"row ":"column ") << ndx_ << " ..." ;
+
+  int diffcnt = 0 ;
+  if (lb_ != lb) {
+    diffcnt++ ;
+    std::cout
+      << std::endl << "    "
+      << ((isRow_)?"blow":"lb") << " = " << lb_ << " in original, "
+      << lb << " in current." ;
+  }
+  if (ub_ != ub) {
+    diffcnt++ ;
+    std::cout
+      << std::endl << "    "
+      << ((isRow_)?"b":"ub") << " = " << ub_ << " in original, "
+      << ub << " in current." ;
+  }
+  bool vecDiff = ((*origVec_) == (*curVec)) ;
+/*
+  Dispense with the easy outcomes.
+*/
+  if (diffcnt == 0 && !vecDiff) {
+    std::cout << " equal." << std::endl ;
+    return ;
+  } else if (!vecDiff) {
+    std::cout << std::endl << " coefficients equal." << std::endl ;
+    return ;
+  }
+/*
+  We have to compare the coefficients. Merge the index sets.
+*/
+  int origLen = origVec_->getNumElements() ;
+  int curLen = curVec->getNumElements() ;
+  int mergedLen = origLen+curLen ;
+  int *mergedIndices = new int [mergedLen] ;
+  CoinCopyN(origVec_->getIndices(),origLen,mergedIndices) ;
+  CoinCopyN(curVec->getIndices(),curLen,mergedIndices+origLen) ;
+  std::inplace_merge(mergedIndices,mergedIndices+origLen,
+  		     mergedIndices+mergedLen) ;
+  int *uniqEnd = std::unique(mergedIndices,mergedIndices+mergedLen) ;
+  int uniqLen = static_cast<int>(uniqEnd-mergedIndices) ;
+
+  for (int k = 0 ; k < uniqLen ; k++) {
+    int j = mergedIndices[k] ;
+    double aij_orig = 0.0 ;
+    double aij_cur = 0.0 ;
+    bool inOrig = false ;
+    bool inCur = false ;
+    if (origVec_->findIndex(j) >= 0) {
+      inOrig = true ;
+      aij_orig = (*origVec_)[j] ;
+    }
+    if (curVec->findIndex(j) >= 0) {
+      inCur = true ;
+      aij_cur = (*curVec)[j] ;
+    }
+    if (inOrig == false || inCur == false ||
+        aij_orig != aij_cur) {
+      diffcnt++ ;
+      std::cout << std::endl << "    " ;
+      if (isRow_)
+        std::cout << "coeff a(" << ndx_ << "," << j << ") " ;
+      else
+        std::cout << "coeff a(" << j << "," << ndx_ << ") " ;
+      if (inOrig == false)
+        std::cout << "= " << aij_cur << " not present in original." ;
+      else if (inCur == false)
+        std::cout << "= " << aij_orig << " not present in current." ;
+      else
+        std::cout
+	  << " = " << aij_orig << " in original, "
+	  << aij_cur << " in current." ;
+    }
+  }
+  std::cout << std::endl << "  " << diffcnt << " changes." << std::endl ;
+  delete[] mergedIndices ;
+}
+
diff --git a/cbits/coin/CoinPresolveMonitor.hpp b/cbits/coin/CoinPresolveMonitor.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveMonitor.hpp
@@ -0,0 +1,105 @@
+
+#ifndef CoinPresolveMonitor_H
+#define CoinPresolveMonitor_H
+
+/*!
+  \brief Monitor a row or column for modification
+
+  The purpose of this class is to monitor a row or column for modifications
+  during presolve and postsolve. Each object can monitor one row or
+  column. The initial copy of the row or column is loaded by the constructor.
+  Each subsequent call to checkAndTell() compares the current state of the row
+  or column with the stored state and reports any modifications.
+
+  Internally the row or column is held as a CoinPackedVector so that it's
+  possible to follow a row or column through presolve (CoinPresolveMatrix)
+  and postsolve (CoinPostsolveMatrix).
+
+  Do not underestimate the amount of work required here. Extracting a row from
+  the CoinPostsolve matrix requires a scan of every element in the matrix.
+  That's one scan by the constructor and one scan with every call to modify.
+  But that's precisely why it's virtually impossible to debug presolve without
+  aids.
+
+  Parameter overloads for CoinPresolveMatrix and CoinPostsolveMatrix are a
+  little clumsy, but not a problem in use. The alternative is to add methods
+  to the CoinPresolveMatrix and CoinPostsolveMatrix classes that will only be
+  used for debugging. That's not too attractive either.
+*/
+class CoinPresolveMonitor
+{
+  public:
+
+  /*! \brief Default constructor
+
+    Creates an empty monitor.
+  */
+  CoinPresolveMonitor() ;
+
+  /*! \brief Initialise from a CoinPresolveMatrix
+
+    Load the initial row or column from a CoinPresolveMatrix. Set \p isRow
+    true for a row, false for a column.
+  */
+  CoinPresolveMonitor(const CoinPresolveMatrix *mtx, bool isRow, int k) ;
+
+  /*! \brief Initialise from a CoinPostsolveMatrix
+
+    Load the initial row or column from a CoinPostsolveMatrix. Set \p isRow
+    true for a row, false for a column.
+  */
+  CoinPresolveMonitor(const CoinPostsolveMatrix *mtx, bool isRow, int k) ;
+
+  /*! \brief Compare the present row or column against the stored copy and
+  	     report differences.
+
+    Load the current row or column from a CoinPresolveMatrix and compare.
+    Differences are printed to std::cout.
+  */
+  void checkAndTell(const CoinPresolveMatrix *mtx) ;
+
+  /*! \brief Compare the present row or column against the stored copy and
+  	     report differences.
+
+    Load the current row or column from a CoinPostsolveMatrix and compare.
+    Differences are printed to std::cout.
+  */
+  void checkAndTell(const CoinPostsolveMatrix *mtx) ;
+
+  private:
+
+  /// Extract a row from a CoinPresolveMatrix
+  CoinPackedVector *extractRow(int i, const CoinPresolveMatrix *mtx) const ;
+
+  /// Extract a column from a CoinPresolveMatrix
+  CoinPackedVector *extractCol(int j, const CoinPresolveMatrix *mtx) const ;
+
+  /// Extract a row from a CoinPostsolveMatrix
+  CoinPackedVector *extractRow(int i, const CoinPostsolveMatrix *mtx) const ;
+
+  /// Extract a column from a CoinPostsolveMatrix
+  CoinPackedVector *extractCol(int j, const CoinPostsolveMatrix *mtx) const ;
+
+  /// Worker method underlying the public checkAndTell methods.
+  void checkAndTell(CoinPackedVector *curVec, double lb, double ub) ;
+
+  /// True to monitor a row, false to monitor a column
+  bool isRow_ ;
+
+  /// Row or column index
+  int ndx_ ;
+
+  /*! The original row or column
+
+    Sorted in increasing order of indices.
+  */
+  CoinPackedVector *origVec_ ;
+
+  /// Original row or column lower bound
+  double lb_ ;
+
+  /// Original row or column upper bound
+  double ub_ ;
+} ;
+
+#endif
diff --git a/cbits/coin/CoinPresolvePsdebug.cpp b/cbits/coin/CoinPresolvePsdebug.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolvePsdebug.cpp
@@ -0,0 +1,1162 @@
+/* $Id: CoinPresolvePsdebug.cpp 1560 2012-11-24 00:29:01Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <new>
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinPresolveMatrix.hpp"
+#include "CoinHelperFunctions.hpp"
+
+/*
+  \file
+
+  This file contains a number of routines that are useful when doing
+  serious debugging but unneeded otherwise. It also contains the methods
+  that implement the CoinPresolveMonitor class.
+
+  Presumably if you're deep enough into presolve to need these, you're
+  willing to scan the file to see what can be done. See also the Presolve
+  Debug Functions module in the doxygen doc'n and CoinPresolvePsdebug.hpp.
+
+  The general approach for the matrix consistency routines is that the
+  routines return void and abort when they find a problem. The routines
+  that check the basis and solution complain loudly but do not abort.
+
+  NOTE: The definitions for PRESOLVE_CONSISTENCY and PRESOLVE_DEBUG MUST
+	BE CONSISTENT across all CoinPresolve source files AND OsiPresolve
+	AND ClpPresolve AND OsiDylpPresolve (assuming any of the latter
+	are relevant to your code).  Otherwise, at best you'll get garbage
+	output. More likely, you'll get a core dump. Resist the temptation
+	to define these constants in individual files. In particular,
+	cdone and rdone will NOT be consistently maintained during postsolve.
+
+  Hack away as your needs dictate.
+*/
+
+
+/*
+  Integrity checking routines for the (loosely) packed matrices of a
+  CoinPresolveMatrix object. Some routines work on column-major and row-major
+  reps separately, others do cross-checking.
+*/
+
+namespace { // begin unnamed file-local namespace
+
+#if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
+/*
+  Check for duplicate entries in a major vector by walking the vector. For
+  each coefficient, use presolve_find_minor1 to search the remainder of the
+  major vector for an entry with the same minor index. We don't want to find
+  anything.
+*/
+  
+void no_majvec_dups (const char *majdones, const CoinBigIndex *majstrts,
+		     const int *minndxs, const int *majlens, int nmaj)
+
+{ for (int maj = 0 ; maj < nmaj ; maj++) 
+  { if ((!majdones || majdones[maj]) && majlens[maj] > 0)
+    { CoinBigIndex ks = majstrts[maj] ;
+      CoinBigIndex ke = ks+majlens[maj] ;
+      for (CoinBigIndex k = ks ; k < ke ; k++)
+      { 
+/*
+  Assert we fell off the end of the major vector without finding the entry. 
+*/
+	PRESOLVEASSERT(presolve_find_minor1(minndxs[k],k+1,
+					    ke,minndxs) == ke) ; } } }
+  return ; }
+
+/*
+  As the name implies: scan for explicit zeros.
+*/
+void check_majvec_nozeros (const CoinBigIndex *majstrts, const double *majels,
+			   const int *majlens, int nmaj)
+
+{ for (int maj = 0 ; maj < nmaj ; maj++) 
+  { if (majlens[maj] > 0)
+    { CoinBigIndex ks = majstrts[maj] ;
+      CoinBigIndex ke = ks+majlens[maj] ;
+      for (CoinBigIndex k = ks ; k < ke ; k++)
+      { PRESOLVEASSERT(fabs(majels[k]) > ZTOLDP) ; } } }
+
+  return ; }
+
+/*
+  Integrity checks for the linked lists that indicate major vector ordering
+  in the bulk storage area (minor index and coefficient arrays).
+ */
+void links_ok (presolvehlink *majlink, int *majstrts, int *majlens, int nmaj)
+
+{ int maj ;
+
+/*
+  Confirm link integrity. Vectors of length 0 should not be part of the chain.
+*/
+  for (maj = 0 ; maj < nmaj ; maj++)
+  { int pre = majlink[maj].pre ;
+    int suc = majlink[maj].suc ;
+
+    if (majlens[maj] == 0)
+    { PRESOLVEASSERT(pre == NO_LINK && suc == NO_LINK) ; }
+    if (pre != NO_LINK)
+    { PRESOLVEASSERT(0 <= pre && pre <= nmaj) ;
+      PRESOLVEASSERT(majlink[pre].suc == maj) ; }
+    if (suc != NO_LINK)
+    { PRESOLVEASSERT(0 <= suc && suc <= nmaj) ;
+      PRESOLVEASSERT(majlink[suc].pre == maj) ; } }
+/*
+  There must be a first vector.
+*/
+  for (maj = 0 ; maj < nmaj ; maj++) 
+  { if (majlink[maj].pre == NO_LINK)
+      break ; }
+  PRESOLVEASSERT(nmaj == 0 || maj < nmaj) ;
+/*
+  The order of the linked list should match the ordering indicated by the
+  major vector start & length arrays.
+*/
+  while (maj != NO_LINK)
+  { if (majlink[maj].suc != NO_LINK) 
+    { PRESOLVEASSERT(majstrts[maj]+majlens[maj] <=
+				majstrts[majlink[maj].suc]) ; }
+    maj = majlink[maj].suc ; }
+
+  return ; }
+
+
+/*
+ matrix_consistent checks that an entry is in the column-major representation
+ if it is in the row-major representation.  If testvals is non-zero, it also
+ checks that their values are the same.
+
+ By doing the appropriate swaps of column- and row-major data structures in
+ the parameter list, we can check that an entry is in the row-major
+ representation if it's in the column-major representation.
+
+ I can't see any nice way to rename the parameters (majmajstrt? minmajstrt?).
+
+ Original comment:  ``Note that there may be entries in a row that correspond
+ to empty columns and vice-versa.'' To which a previous browser had commented
+ ``HUH???''. And I agree. -- lh, 040907 --
+*/
+
+void matrix_consistent (const CoinBigIndex *mrstrt, const int *hinrow,
+			const int *hcol, const double *rowels,
+			const CoinBigIndex *mcstrt, const int *hincol,
+			const int *hrow, const double *colels,
+			int nrows, int testvals,
+			const char *ROW, const char *COL)
+{
+  for (int irow = 0 ; irow < nrows ; irow++) {
+    if (hinrow[irow] > 0) {
+      const CoinBigIndex krs = mrstrt[irow] ;
+      const CoinBigIndex kre = krs+hinrow[irow] ;
+
+      for (CoinBigIndex k = krs ; k < kre ; k++) {
+	int jcol = hcol[k] ;
+	const CoinBigIndex kcs = mcstrt[jcol] ;
+	const CoinBigIndex kce = kcs+hincol[jcol] ;
+
+	CoinBigIndex kk = presolve_find_row1(irow,kcs,kce,hrow) ;
+	if (kk == kce) {
+	  std::cout
+	    << "MATRIX INCONSISTENT:  can't find " << ROW << " " << irow
+	    << " in " << COL << " " << jcol << std::endl ;
+	  fflush(stdout) ;
+	  abort() ;
+	}
+	if (testvals && colels[kk] != rowels[k]) {
+	  std::cout
+	    << "MATRIX INCONSISTENT: values differ for " << ROW << " " << irow
+	    << " and " << COL << " " << jcol << std::endl ;
+	  fflush(stdout) ;
+	  abort() ;
+	}
+      }
+    }
+  }
+}
+#endif
+} // end unnamed file-local namespace
+
+/*
+  Utilizes matrix_consistent to check for equivalence of the column- and
+  row-major representations. Checks for presence of coefficients in the
+  column-major matrix, given presence in the row-major matrix, then checks
+  for presence in the row-major matrix given presence in the column-major
+  matrix. If testvals == true (default), the check also tests that the
+  coefficients have equal value.
+  
+  See further comments with matrix_consistent.
+*/
+
+# if PRESOLVE_CONSISTENCY
+void presolve_consistent(const CoinPresolveMatrix *preObj, bool testvals)
+{
+  matrix_consistent(preObj->mrstrt_,preObj->hinrow_,preObj->hcol_,
+		    preObj->rowels_,
+		    preObj->mcstrt_,preObj->hincol_,preObj->hrow_,
+		    preObj->colels_,
+		    preObj->nrows_,testvals,"row","col") ;
+  matrix_consistent(preObj->mcstrt_,preObj->hincol_,preObj->hrow_,
+		    preObj->colels_,
+		    preObj->mrstrt_,preObj->hinrow_,preObj->hcol_,
+		    preObj->rowels_, 
+		    preObj->ncols_,testvals,"col","row") ;
+}
+
+/*
+  Check the column- and/or row-major matrices for duplicates. By default, both
+  will be checked.
+*/
+  
+void presolve_no_dups (const CoinPresolveMatrix *preObj,
+		       bool doCol, bool doRow)
+
+{
+  if (doCol)
+  { no_majvec_dups(0,preObj->mcstrt_,preObj->hrow_,
+		   preObj->hincol_,preObj->ncols_) ; }
+  if (doRow)
+  { no_majvec_dups(0,preObj->mrstrt_,preObj->hcol_,
+		   preObj->hinrow_,preObj->nrows_) ; }
+
+  return ; }
+
+
+/*
+  As the name implies: scan for explicit zeros. By default, both matrices are
+  scanned.
+*/
+void presolve_no_zeros (const CoinPresolveMatrix *preObj,
+			bool doCol, bool doRow)
+{
+  if (doCol)
+  { check_majvec_nozeros(preObj->mcstrt_,preObj->colels_,preObj->hincol_,
+			 preObj->ncols_) ; }
+  if (doRow)
+  { check_majvec_nozeros(preObj->mrstrt_,preObj->rowels_,preObj->hinrow_,
+			 preObj->nrows_) ; }
+
+  return ; }
+
+/*
+  Lazy check on column lengths. Scan the row index array for the column.
+  If the relevant row length in the row-major rep is non-zero, assume we're ok.
+
+  Not advertised in CoinPresolvePsdebug.hpp.
+*/
+void presolve_hincol_ok(const int *mcstrt, const int *hincol,
+	       const int *hinrow,
+	       const int *hrow, int ncols)
+{
+  int jcol;
+
+  for (jcol=0; jcol<ncols; jcol++) 
+    if (hincol[jcol] > 0) {
+      int kcs = mcstrt[jcol];
+      int kce = kcs + hincol[jcol];
+      int n=0;
+      
+      int k;
+      for (k=kcs; k<kce; k++) {
+	int row = hrow[k];
+	if (hinrow[row] > 0)
+	  n++;
+      }
+      if (n != hincol[jcol])
+	abort();
+    }
+}
+
+/*
+  Integrity checks for the linked lists that indicate major vector ordering
+  in the bulk storage area (minor index and coefficient arrays).
+ */
+void presolve_links_ok (const CoinPresolveMatrix *preObj,
+			bool doCol, bool doRow)
+{
+  if (doCol)
+  { links_ok(preObj->clink_,preObj->mcstrt_,
+	     preObj->hincol_,preObj->ncols_) ; }
+  if (doRow)
+  { links_ok(preObj->rlink_,preObj->mrstrt_,
+	     preObj->hinrow_,preObj->nrows_) ; }
+
+  return ; }
+
+
+
+/*
+  Routines to check a threaded matrix from a CoinPostsolve object.
+*/
+
+/*
+  Check that the column length agrees with the column thread. There must be
+  the correct number of coefficients, and the thread must end with the NO_LINK
+  marker.
+*/
+void presolve_check_threads (const CoinPostsolveMatrix *obj)
+
+{ 
+
+  CoinBigIndex *mcstrt = obj->mcstrt_ ;
+  int *hincol = obj->hincol_ ;
+  CoinBigIndex *link = obj->link_ ;
+  char *cdone = obj->cdone_ ;
+
+  int n = obj->ncols0_ ;
+
+/*
+  Scan the columns, checking only the ones that have been processed into the
+  constraint matrix.
+*/
+  for (int j = 0 ; j < n ; j++)
+  { if (!cdone[j]) continue ;
+
+    int lenj = hincol[j] ;
+    int k ;
+    for (k = mcstrt[j] ; k != NO_LINK && lenj > 0 ; k = link[k])
+    { assert(k >= 0 && k < obj->maxlink_) ;
+      lenj-- ; }
+
+    assert(k == NO_LINK && lenj == 0) ; }
+
+  return ; }
+
+/*
+  Check the free list. We're looking for gross corruption here. The notion is
+  that the free list plus elements in the matrix should add up to the capacity
+  of the bulk store.
+*/
+
+void presolve_check_free_list (const CoinPostsolveMatrix *obj, bool chkElemCnt)
+
+{ 
+
+  CoinBigIndex k = obj->free_list_ ;
+  CoinBigIndex freeCnt = 0 ;
+  CoinBigIndex maxlink = obj->maxlink_ ;
+  CoinBigIndex *link = obj->link_ ;
+/*
+  Redundancy in the data structure. These should always be equal.
+*/
+  assert(maxlink == obj->bulk0_) ;
+/*
+  Walk the free list portion of link. We should never point outside the bulk
+  store. If we ever come across an entry that's less than 0, it had better be
+  NO_LINK, the end marker.
+*/
+  while (k >= 0)
+  { assert(k < maxlink) ;
+    freeCnt++ ;
+    k = link[k] ; }
+  assert(k == NO_LINK) ;
+/*
+  And a final test: elements in the matrix plus free space should equal the
+  size of the bulk area. A good thought, but less than practical. Currently
+  postsolve doesn't track the number of elements in the matrix. But you might
+  find it useful if you're checking a newly constructed postsolve matrix. Even
+  then, you need to make sure nelems_ is correct. In the normal scheme of
+  things, this requires that somewhere there's a count of elements. Right now,
+  drop_empty_cols_action::presolve does this count, and you can get an accurate
+  value from the presolve object. assignPresolveToPostsolve will transfer this
+  value. Otherwise you're on your own --- your constructor must somehow find
+  this count. Using a standard CoinPackedMatrix is another way to get a count.
+*/
+  if (chkElemCnt)
+  { assert(obj->nelems_+freeCnt == maxlink) ; }
+
+
+  return ; }
+#endif
+
+
+/*
+  Routines to check solution and basis composition.
+*/
+
+/*
+  CoinPostsolveMatrix
+
+  This routine performs two checks on reduced costs held in rcosts_:
+    * The value held in rcosts_ is checked against the status of the
+      variable. Errors reported as "Bad rcost"
+    * The reduced cost is calculated from scratch and compared to the
+      value held in rcosts_. Errors reported as "Inacc rcost"
+
+  Remember that postsolve has a schizophrenic attitude about maximisation. All
+  transforms assume minimisation, and that's reflected in the reduced costs we
+  see here. And you must load duals and reduced costs with the correct sign for
+  minimisation. But, as a small courtesy (and a big inconsistency), postsolve
+  will negate objective coefficients for you. Hence the rather odd use of
+  maxmin.
+
+  The routine is specific to CoinPostsolveMatrix because the reduced cost
+  calculation requires traversal of (threaded) matrix columns.
+
+  NOTE: This routine holds static variables. It will detect when the problem
+	size changes and reinitialise. If you use presolve debugging over
+	multiple problems and you want to be dead sure of reinitialisation,
+	use the call presolve_check_reduced_costs(0), which will reinitialise
+	and return.
+*/
+# if PRESOLVE_DEBUG
+
+void presolve_check_reduced_costs (const CoinPostsolveMatrix *postObj)
+{
+
+  static bool warned = false ;
+  static double *warned_rcosts = 0 ;
+  static int allocSize = 0 ;
+  static const CoinPostsolveMatrix *lastObj = 0 ;
+
+/*
+  Is the client asking for reinitialisation only?
+*/
+  if (postObj == 0)
+  { warned = false ;
+    if (warned_rcosts != 0)
+    { delete[] warned_rcosts ;
+      warned_rcosts = 0 ; }
+    allocSize = 0 ;
+    lastObj = 0 ;
+    return ; }
+/*
+  *Should* the client have asked for reinitialisation?
+*/
+  int ncols0 = postObj->ncols0_ ;
+  if (allocSize < ncols0 || postObj != lastObj)
+  { warned = false ;
+    delete[] warned_rcosts ;
+    warned_rcosts = 0 ;
+    allocSize = 0 ;
+    lastObj = postObj ; }
+
+  double *rcosts = postObj->rcosts_ ;
+
+/*
+  By tracking values in warned_rcosts, we can produce a single message the
+  first time a value is determined to be incorrect.
+*/
+  if (!warned)
+  { warned = true ;
+    std::cout
+      << "reduced cost" << std::endl ;
+    warned_rcosts = new double[ncols0] ;
+    CoinZeroN(warned_rcosts,ncols0) ; }
+
+  double *colels = postObj->colels_ ;
+  int *hrow = postObj->hrow_ ;
+  int *mcstrt = postObj->mcstrt_ ;
+  int *hincol = postObj->hincol_ ;
+  CoinBigIndex *link = postObj->link_ ;
+
+  double *clo = postObj->clo_ ;
+  double *cup = postObj->cup_ ;
+
+  double *dcost	= postObj->cost_ ;
+
+  double *sol = postObj->sol_ ;
+
+  char *cdone = postObj->cdone_ ;
+  char *rdone = postObj->rdone_ ;
+
+  const double ztoldj = postObj->ztoldj_ ;
+  const double ztolzb = postObj->ztolzb_ ;
+
+  double *rowduals = postObj->rowduals_ ;
+
+  double maxmin = postObj->maxmin_ ;
+  std::string strMaxmin((maxmin < 0)?"max":"min") ;
+  int checkCol = -1 ;
+/*
+  Scan all columns, but only check the ones that are marked as having been
+  postprocessed.
+*/
+  for (int j = 0 ; j < ncols0 ; j++)
+  { if (cdone[j] == 0) continue ;
+    const char *statjstr = postObj->columnStatusString(j) ;
+/*
+  Check the stored reduced cost for accuracy. See note above w.r.t. maxmin.
+*/
+    double dj = rcosts[j] ;
+    double wrndj = warned_rcosts[j] ;
+
+    { int ndx ;
+      CoinBigIndex k = mcstrt[j] ;
+      int len = hincol[j] ;
+      double chkdj = maxmin*dcost[j] ;
+      if (j == checkCol)
+        std::cout
+	  << "dj for " << j << " is " << dj << " - cost is " << chkdj
+	  << std::endl ;
+      for (ndx = 0 ; ndx < len ; ndx++)
+      { int row = hrow[k] ;
+	PRESOLVEASSERT(rdone[row] != 0) ;
+	chkdj -= rowduals[row]*colels[k] ;
+        if (j == checkCol)
+	  std::cout
+	    << "row " << row << " coeff " << colels[k] << " dual "
+	    << rowduals[row] << " => dj " << chkdj << std::endl ;
+	k = link[k] ; }
+      if (fabs(dj-chkdj) > ztoldj && wrndj != dj)
+      { std::cout
+          << "Inacc rcost: " << j << " " << statjstr << " "
+	  << strMaxmin << " have " << dj
+	  << " should be " << chkdj << " err " << fabs(dj-chkdj)
+	  << std::endl ; } }
+/*
+  Check the stored reduced cost for consistency with the variable's status.
+  The cases are
+    * basic: (reduced cost) == 0
+    * at upper bound and not at lower bound: (reduced cost)*(maxmin) <= 0
+    * at lower bound and not at upper bound: (reduced cost)*(maxmin) >= 0
+    * not at either bound: any sign is correct (the variable can move either
+      way) but superbasic status is sufficiently exotic that it always
+      deserves a message. (There should be no superbasic variables at the
+      completion of postsolve.)
+  As a courtesy, show the reduced cost with the proper sign.
+*/
+    { double xj = sol[j] ;
+      double lj = clo[j] ;
+      double uj = cup[j] ;
+
+      if (postObj->columnIsBasic(j))
+      { if (fabs(dj) > ztoldj && wrndj != dj)
+	{ std::cout
+	    << "Bad rcost: " << j << " " << maxmin*dj
+	    << " " << statjstr << " " << strMaxmin << std::endl ; } }
+      else
+      if (fabs(xj-uj) < ztolzb && fabs(xj-lj) > ztolzb)
+      { if (dj >= ztoldj && wrndj != dj)
+	{ std::cout
+	    << "Bad rcost: " << j << " " << maxmin*dj
+	    << " " << statjstr << " " << strMaxmin << std::endl ; } }
+      else
+      if (fabs(xj-lj) < ztolzb && fabs(xj-uj) > ztolzb)
+      { if (dj <= -ztoldj && wrndj != dj)
+	{ std::cout
+	    << "Bad rcost: " << j << " " << maxmin*dj
+	    << " " << statjstr << " " << strMaxmin << std::endl ; } }
+      else
+      if (fabs(xj-lj) > ztolzb && fabs(xj-uj) > ztolzb)
+      { if (fabs(dj) > ztoldj && wrndj != dj)
+        { std::cout
+	    << "Superbasic rcost: " << j << " " << maxmin*dj
+	    << " " << statjstr << " " << strMaxmin
+	    << " lb "<< lj << " val " << xj << " ub "<< uj << std::endl ; } }
+    }
+
+    warned_rcosts[j] = rcosts[j] ; }
+
+}
+
+/*
+  CoinPostsolveMatrix
+
+  This routine checks the value and status of the dual variables. It
+  checks that the value and status of the dual agree with the row activity.
+  Errors are reported as "Bad dual"
+
+  See presolve_check_reduced_costs for an explanation of the use of maxmin.
+
+  Specific to CoinPostsolveMatrix due to the use of rdone. This could be fixed,
+  but probably better to clone the function and specialise it for
+  CoinPresolveMatrix.
+*/
+
+void presolve_check_duals (const CoinPostsolveMatrix *postObj)
+{
+
+
+  int nrows0 = postObj->nrows0_ ;
+
+  double *rowduals = postObj->rowduals_ ;
+
+  double *acts = postObj->acts_ ;
+  double *rup = postObj->rup_ ;
+  double *rlo = postObj->rlo_ ;
+
+  char *rdone = postObj->rdone_ ;
+
+  const double ztoldj = postObj->ztoldj_ ;
+  const double ztolzb = postObj->ztolzb_ ;
+
+  double maxmin = postObj->maxmin_ ;
+  std::string strMaxmin((maxmin < 0)?"max":"min") ;
+
+/*
+  Scan all processed rows. The rules are as for normal reduced costs, but
+  we need to remember the various flips and inversions. In summary, the correct
+  situation at optimality (minimisation) is:
+    * acts[i] == rup[i] ==> artificial NBLB ==> dual[i] < 0
+    * acts[i] == rlo[i] ==> artificial NBUB ==> dual[i] > 0
+
+  We can't say much about the dual for an equality. It can go either way. As a
+  courtesy, show the dual with the proper sign.
+*/
+  for (int i = 0 ; i < nrows0 ; i++)
+  { if (rdone[i] == 0) continue ;
+
+    double ui = rup[i] ;
+    double li = rlo[i] ;
+
+    if (ui-li < 1.0e-6) continue ;
+
+    double yi = rowduals[i] ;
+    double lhsi = acts[i] ;
+    const char *statistr = postObj->rowStatusString(i) ;
+
+
+    if (fabs(lhsi-li) < ztolzb)
+    { if (yi < -ztoldj)
+      { std::cout
+	  << "Bad dual: " << i << " " << maxmin*yi
+	  << " " << statistr << " " << strMaxmin << std::endl ; } }
+    else
+    if (fabs(lhsi-ui) < ztolzb)
+    { if (yi > ztoldj)
+      { std::cout
+	  << "Bad dual: " << i << " " << maxmin*yi
+	  << " " << statistr << " " << strMaxmin << std::endl ; } }
+    else
+    if (li < lhsi && lhsi < ui)
+    { if (fabs(yi) > ztoldj)
+      { std::cout
+	  << "Bad dual: " << i << " " << maxmin*yi
+	  << " " << statistr << " " << strMaxmin << std::endl ; } } }
+  return ; }
+
+
+
+/*
+  CoinPresolveMatrix
+
+  This routine will check the primal (column) solution for feasibility and
+  status. If there's no column solution (sol_), the routine bails out. If the
+  column solution is present, all else is assumed to be present.
+
+  chkColSol:	check colum solution (primal variables)
+		0 - checks off
+		1 - check for NaN/Inf
+	       *2 - check for above/below column bounds
+  chkRowAct:	check row solution (evaluate constraint lhs)
+		0 - checks off
+	       *1 - check for NaN/Inf
+		2 - check for inaccuracy, above/below row bounds
+  chkStatus:	check for valid status of variables
+		0 - checks off
+	       *1 - check status of architecturals, if colstat_ exists
+	        2 - check status rows, if rowstat_ exists
+
+  In order to check row status we need accurate row activity. Setting
+  chkStatus to 2 forces chkRowAct to 2.
+
+  CoinPrePostsolveMatrix plays games with colstat_ and rowstat_, allocating
+  them as a single vector, so if colstat_ exists, rowstat_ really should
+  exist. Check it anyway; this is a debug method, be robust.
+
+  In general, the presolve transforms are not prepared to properly adjust the
+  row activity (reported as `Inacc RSOL'). Postsolve transforms do better. On
+  the bright side, the code seems to work just fine without maintaining row
+  activity.  You probably don't want to use the level 2 checks for the row
+  solution, particularly in presolve.
+
+  With a bit of thought, the various checks could be more cleanly separated
+  to require only the minimum information for each check.
+*/
+void presolve_check_sol (const CoinPresolveMatrix *preObj,
+			 int chkColSol, int chkRowAct, int chkStatus)
+
+{
+  double *colels = preObj->colels_ ;
+  int *hrow = preObj->hrow_ ;
+  int *mcstrt = preObj->mcstrt_ ;
+  int *hincol = preObj->hincol_ ;
+  int *hinrow = preObj->hinrow_ ;
+
+  int n	= preObj->ncols_ ;
+  int m = preObj->nrows_ ;
+
+/*
+  If there's no column solution, bail out now.
+*/
+  if (preObj->sol_ == 0) return ;
+
+  double *csol = preObj->sol_ ;
+  double *acts = preObj->acts_ ;
+  double *clo = preObj->clo_ ;
+  double *cup = preObj->cup_ ;
+  double *rlo = preObj->rlo_ ;
+  double *rup = preObj->rup_ ;
+
+  double tol = preObj->ztolzb_ ;
+
+  if (chkStatus >= 2) chkRowAct = 2 ;
+
+  double *rsol = 0 ;
+  if (chkRowAct)
+  { rsol = new double[m] ;
+    memset(rsol,0,m*sizeof(double)) ; }
+
+/*
+  Open a loop to scan each column. For each column, do the following:
+    * Update the row solution (lhs value) by adding the contribution from
+      this column.
+    * Check for bogus values (NaN, infinity)
+    * Check for feasibility (value within column bounds)
+    * Check that the status of the variable agrees with the value and with the
+      lower and upper bounds. Free should have no bounds, superbasic should
+      have at least one.
+*/
+  for (int j = 0 ; j < n ; ++j)
+  { CoinBigIndex v = mcstrt[j] ;
+    int colLen = hincol[j] ;
+    double xj = csol[j] ;
+    double lj = clo[j] ;
+    double uj = cup[j] ;
+
+    if (chkRowAct >= 1)
+    { for (int u = 0 ; u < colLen ; ++u)
+      { int i = hrow[v] ;
+	  double aij = colels[v] ;
+	  v++ ;
+	  rsol[i] += aij*xj ; } }
+
+    if (chkColSol > 0)
+    { if (CoinIsnan(xj))
+      { printf("NaN CSOL: %d  : lb = %g x = %g ub = %g\n",j,lj,xj,uj) ; }
+      if (xj <= -PRESOLVE_INF || xj >= PRESOLVE_INF)
+      { printf("Inf CSOL: %d  : lb = %g x = %g ub = %g\n",j,lj,xj,uj) ; }
+      if (chkColSol > 1)
+      { if (xj < lj-tol)
+	{ printf("low CSOL: %d  : lb = %g x = %g ub = %g\n",j,lj,xj,uj) ; }
+	else
+	if (xj > uj+tol)
+	{ printf("high CSOL: %d  : lb = %g x = %g ub = %g\n",
+		 j,lj,xj,uj) ; } } }
+    if (chkStatus && preObj->colstat_)
+    { CoinPrePostsolveMatrix::Status statj = preObj->getColumnStatus(j) ;
+      switch (statj)
+      { case CoinPrePostsolveMatrix::atUpperBound:
+	{ if (uj >= PRESOLVE_INF || fabs(xj-uj) > tol)
+	  { printf("Bad status CSOL: %d : status atUpperBound : ",j) ;
+	    printf("lb = %g x = %g ub = %g\n",lj,xj,uj) ; }
+	  break ; }
+        case CoinPrePostsolveMatrix::atLowerBound:
+	{ if (lj <= -PRESOLVE_INF || fabs(xj-lj) > tol)
+	  { printf("Bad status CSOL: %d : status atLowerBound : ",j) ;
+	    printf("lb = %g x = %g ub = %g\n",lj,xj,uj) ; }
+	  break ; }
+        case CoinPrePostsolveMatrix::isFree:
+	{ if (lj > -PRESOLVE_INF || uj < PRESOLVE_INF)
+	  { printf("Bad status CSOL: %d : status isFree : ",j) ;
+	    printf("lb = %g x = %g ub = %g\n",lj,xj,uj) ; }
+	  break ; }
+        case CoinPrePostsolveMatrix::superBasic:
+	{ if (!(lj > -PRESOLVE_INF || uj < PRESOLVE_INF))
+	  { printf("Bad status CSOL: %d : status superBasic : ",j) ;
+	    printf("lb = %g x = %g ub = %g\n",lj,xj,uj) ; }
+	  break ; }
+        case CoinPrePostsolveMatrix::basic:
+	{ /* Nothing to do here. */
+	  break ; }
+	default:
+	{ printf("Bad status CSOL: %d : status unrecognized : ",j) ;
+	  break ; } } } }
+/*
+  Now check the row solution. acts[i] is what presolve thinks we have, rsol[i]
+  is what we've just calculated while scanning the columns. We need only
+  check nontrivial rows (i.e., rows with length > 0). For each row,
+    * Check for bogus values (NaN, infinity)
+    * Check for accuracy (acts == rsol)
+    * Check for feasibility (rsol within row bounds)
+*/
+  tol *=1.0e3;
+  if (chkRowAct >= 1)
+  { for (int i = 0 ; i < m ; ++i)
+    { if (hinrow[i])
+      { double lhsi = acts[i] ;
+	double evali = rsol[i] ;
+	double li = rlo[i] ;
+	double ui = rup[i] ;
+
+	if (CoinIsnan(evali) || CoinIsnan(lhsi))
+	{ printf("NaN RSOL: %d  : lb = %g eval = %g (expected %g) ub = %g\n",
+		 i,li,evali,lhsi,ui) ; }
+	if (evali <= -PRESOLVE_INF || evali >= PRESOLVE_INF ||
+	    lhsi <= -PRESOLVE_INF || lhsi >= PRESOLVE_INF)
+	{ printf("Inf RSOL: %d  : lb = %g eval = %g (expected %g) ub = %g\n",
+		 i,li,evali,lhsi,ui) ; }
+	if (chkRowAct >= 2)
+	{ if (fabs(evali-lhsi) > tol)
+	  { printf("Inacc RSOL: %d : lb = %g eval = %g (expected %g) ub = %g\n",
+		   i,li,evali,lhsi,ui) ; }
+	  if (evali < li-tol || lhsi < li-tol)
+	  { printf("low RSOL: %d : lb = %g eval = %g (expected %g) ub = %g\n",
+		   i,li,evali,lhsi,ui) ; }
+	  else
+	  if (evali > ui+tol || lhsi > ui+tol)
+	  { printf("high RSOL: %d : lb = %g eval = %g (expected %g) ub = %g\n",
+		   i,li,evali,lhsi,ui) ; } }
+	if (chkStatus >= 2 && preObj->rowstat_)
+	{ CoinPrePostsolveMatrix::Status stati = preObj->getRowStatus(i) ;
+	  switch (stati)
+	  { case CoinPrePostsolveMatrix::atUpperBound:
+	    { if (li <= -PRESOLVE_INF || fabs(lhsi-li) > tol)
+	      { printf("Bad status RSOL: %d : status atUpperBound : ",i) ;
+		printf("LB = %g lhs = %g UB = %g\n",li,lhsi,ui) ; }
+	      break ; }
+	    case CoinPrePostsolveMatrix::atLowerBound:
+	    { if (ui >= PRESOLVE_INF || fabs(lhsi-ui) > tol)
+	      { printf("Bad status RSOL: %d : status atLowerBound : ",i) ;
+		printf("LB = %g lhs = %g UB = %g\n",li,lhsi,ui) ; }
+	      break ; }
+	    case CoinPrePostsolveMatrix::isFree:
+	    { if (li > -PRESOLVE_INF || ui < PRESOLVE_INF)
+	      { printf("Bad status RSOL: %d : status isFree : ",i) ;
+		printf("LB = %g lhs = %g UB = %g\n",li,lhsi,ui) ; }
+	      break ; }
+	    case CoinPrePostsolveMatrix::superBasic:
+	    { printf("Bad status RSOL: %d : status superBasic : ",i) ;
+	      printf("LB = %g lhs = %g UB = %g\n",li,lhsi,ui) ;
+	      break ; }
+	    case CoinPrePostsolveMatrix::basic:
+	    { /* Nothing to do here. */
+	      break ; }
+	    default:
+	    { printf("Bad status RSOL: %d : status unrecognized : ",i) ;
+	      break ; } } } } }
+    delete [] rsol ; }
+  return ; }
+
+/*
+  CoinPostsolveMatrix
+
+  check_sol overload for CoinPostsolveMatrix. Parameters and functionality
+  identical to check_sol immediately above, but we have to remember we're
+  working with a threaded column-major representation.
+*/
+void presolve_check_sol (const CoinPostsolveMatrix *postObj,
+			 int chkColSol, int chkRowAct, int chkStatus)
+
+{
+  double *colels = postObj->colels_ ;
+  int *hrow = postObj->hrow_ ;
+  int *mcstrt = postObj->mcstrt_ ;
+  int *hincol = postObj->hincol_ ;
+  int *link = postObj->link_ ;
+
+  int n	= postObj->ncols_ ;
+  int m = postObj->nrows_ ;
+
+  double *csol = postObj->sol_ ;
+  double *acts = postObj->acts_ ;
+  double *clo = postObj->clo_ ;
+  double *cup = postObj->cup_ ;
+  double *rlo = postObj->rlo_ ;
+  double *rup = postObj->rup_ ;
+
+  double tol = postObj->ztolzb_ ;
+
+  if (chkStatus >= 2) chkRowAct = 2 ;
+  double *rsol = 0 ;
+  if (chkRowAct >= 1)
+  { rsol = new double[m] ;
+    memset(rsol,0,m*sizeof(double)) ; }
+
+/*
+  Open a loop to scan each column. For each column, do the following:
+    * Update the row solution (lhs value) by adding the contribution from
+      this column.
+    * Check for bogus values (NaN, infinity)
+    * check that the status of the variable agrees with the value and with the
+      lower and upper bounds. Free should have no bounds, superbasic should
+      have at least one.
+*/
+  for (int j = 0 ; j < n ; ++j)
+  { CoinBigIndex v = mcstrt[j] ;
+    int colLen = hincol[j] ;
+    double xj = csol[j] ;
+    double lj = clo[j] ;
+    double uj = cup[j] ;
+
+    if (chkRowAct >= 1)
+    { for (int u = 0 ; u < colLen ; ++u)
+      { int i = hrow[v] ;
+	  double aij = colels[v] ;
+	  v = link[v] ;
+	  rsol[i] += aij*xj ; } }
+    if (chkColSol >= 1)
+    { if (CoinIsnan(xj))
+      { printf("NaN CSOL: %d  : lb = %g x = %g ub = %g\n",j,lj,xj,uj) ; }
+      if (xj <= -PRESOLVE_INF || xj >= PRESOLVE_INF)
+      { printf("Inf CSOL: %d  : lb = %g x = %g ub = %g\n",j,lj,xj,uj) ; }
+      if (chkColSol >= 2)
+      { if (xj < lj-tol)
+	{ printf("low CSOL: %d  : lb = %g x = %g ub = %g\n",j,lj,xj,uj) ; }
+	else
+	if (xj > uj+tol)
+	{ printf("high CSOL: %d  : lb = %g x = %g ub = %g\n",
+		 j,lj,xj,uj) ; } } }
+    if (chkStatus >= 1 && postObj->colstat_)
+    { CoinPrePostsolveMatrix::Status statj = postObj->getColumnStatus(j) ;
+      switch (statj)
+      { case CoinPrePostsolveMatrix::atUpperBound:
+	{ if (uj >= PRESOLVE_INF || fabs(xj-uj) > tol)
+	  { printf("Bad status CSOL: %d : status atUpperBound : ",j) ;
+	    printf("lb = %g x = %g ub = %g\n",lj,xj,uj) ; }
+	  break ; }
+        case CoinPrePostsolveMatrix::atLowerBound:
+	{ if (lj <= -PRESOLVE_INF || fabs(xj-lj) > tol)
+	  { printf("Bad status CSOL: %d : status atLowerBound : ",j) ;
+	    printf("lb = %g x = %g ub = %g\n",lj,xj,uj) ; }
+	  break ; }
+        case CoinPrePostsolveMatrix::isFree:
+	{ if (lj > -PRESOLVE_INF || uj < PRESOLVE_INF)
+	  { printf("Bad status CSOL: %d : status isFree : ",j) ;
+	    printf("lb = %g x = %g ub = %g\n",lj,xj,uj) ; }
+	  break ; }
+        case CoinPrePostsolveMatrix::superBasic:
+	{ if (!(lj > -PRESOLVE_INF || uj < PRESOLVE_INF))
+	  { printf("Bad status CSOL: %d : status superBasic : ",j) ;
+	    printf("lb = %g x = %g ub = %g\n",lj,xj,uj) ; }
+	  break ; }
+        case CoinPrePostsolveMatrix::basic:
+	{ /* Nothing to do here. */
+	  break ; }
+	default:
+	{ printf("Bad status CSOL: %d : status unrecognized : ",j) ;
+	  break ; } } } }
+/*
+  Now check the row solution. acts[i] is what presolve thinks we have, rsol[i]
+  is what we've just calculated while scanning the columns. CoinPostsolveMatrix
+  does not contain hinrow_, so we can't check for trivial rows (cf. check_sol
+  for CoinPresolveMatrix).  For each row,
+    * Check for bogus values (NaN, infinity)
+*/
+  tol *= 1.0e4;
+  if (chkRowAct >= 1)
+  { for (int i = 0 ; i < m ; ++i)
+    { double lhsi = acts[i] ;
+      double evali = rsol[i] ;
+      double li = rlo[i] ;
+      double ui = rup[i] ;
+      
+      if (CoinIsnan(evali) || CoinIsnan(lhsi))
+      { printf("NaN RSOL: %d  : lb = %g eval = %g (expected %g) ub = %g\n",
+	       i,li,evali,lhsi,ui) ; }
+      if (evali <= -PRESOLVE_INF || evali >= PRESOLVE_INF ||
+	  lhsi <= -PRESOLVE_INF || lhsi >= PRESOLVE_INF)
+      { printf("Inf RSOL: %d  : lb = %g eval = %g (expected %g) ub = %g\n",
+	       i,li,evali,lhsi,ui) ; }
+      if (chkRowAct >= 2)
+      { if (fabs(evali-lhsi) > tol)
+	{ printf("Inacc RSOL: %d : lb = %g eval = %g (expected %g) ub = %g\n",
+		 i,li,evali,lhsi,ui) ; }
+        if (evali < li-tol || lhsi < li-tol)
+	{ printf("low RSOL: %d : lb = %g eval = %g (expected %g) ub = %g\n",
+		 i,li,evali,lhsi,ui) ; }
+	else
+	if (evali > ui+tol || lhsi > ui+tol)
+	{ printf("high RSOL: %d : lb = %g eval = %g (expected %g) ub = %g\n",
+		 i,li,evali,lhsi,ui) ; } }
+      if (chkStatus >= 2 && postObj->rowstat_)
+      { CoinPrePostsolveMatrix::Status stati = postObj->getRowStatus(i) ;
+	switch (stati)
+	{ case CoinPrePostsolveMatrix::atUpperBound:
+	  { if (li <= -PRESOLVE_INF || fabs(lhsi-li) > tol)
+	    { printf("Bad status RSOL: %d : status atUpperBound : ",i) ;
+	      printf("LB = %g lhs = %g UB = %g\n",li,lhsi,ui) ; }
+	    break ; }
+	  case CoinPrePostsolveMatrix::atLowerBound:
+	  { if (ui >= PRESOLVE_INF || fabs(lhsi-ui) > tol)
+	    { printf("Bad status RSOL: %d : status atLowerBound : ",i) ;
+	      printf("LB = %g lhs = %g UB = %g\n",li,lhsi,ui) ; }
+	    break ; }
+	  case CoinPrePostsolveMatrix::isFree:
+	  { if (li > -PRESOLVE_INF || ui < PRESOLVE_INF)
+	    { printf("Bad status RSOL: %d : status isFree : ",i) ;
+	      printf("LB = %g lhs = %g UB = %g\n",li,lhsi,ui) ; }
+	    break ; }
+	  case CoinPrePostsolveMatrix::superBasic:
+	  { printf("Bad status RSOL: %d : status superBasic : ",i) ;
+	    printf("LB = %g lhs = %g UB = %g\n",li,lhsi,ui) ;
+	    break ; }
+	  case CoinPrePostsolveMatrix::basic:
+	  { /* Nothing to do here. */
+	    break ; }
+	  default:
+	  { printf("Bad status RSOL: %d : status unrecognized : ",i) ;
+	    break ; } } } }
+  delete [] rsol ; }
+  return ; }
+
+/*
+  CoinPostsolveMatrix
+
+  Make sure that the number of basic variables is correct.
+*/
+void presolve_check_nbasic (const CoinPostsolveMatrix *postObj)
+
+{
+
+  int ncols0 = postObj->ncols0_ ;
+  int nrows0 = postObj->nrows0_ ;
+
+  char *cdone = postObj->cdone_ ;
+  char *rdone = postObj->rdone_ ;
+
+  int nbasic = 0 ;
+  int ncdone = 0;
+  int nrdone = 0; 
+  int ncb = 0;
+  int nrb = 0;
+
+  for (int j = 0 ; j < ncols0 ; j++)
+  { 
+    if (cdone[j] != 0 && postObj->columnIsBasic(j))
+    { nbasic++ ;
+      ncb++ ; }
+    if (cdone[j])
+      ncdone++ ;
+  }
+
+  for (int i = 0 ; i < nrows0 ; i++)
+  {
+    if (rdone[i] && postObj->rowIsBasic(i))
+    { nbasic++ ;
+      nrb++ ; }
+    if (rdone[i])
+      nrdone++ ;
+  }
+
+  if (nbasic != postObj->nrows_)
+  { printf("NBASIC (ERROR): %d basic variables, should be %d; ",
+	   nbasic,postObj->nrows_) ;
+    printf("cdone %d, col basic %d, rdone %d, row basic %d.\n",
+	   ncdone,ncb,nrdone,nrb) ;
+    fflush(stdout) ; }
+# if PRESOLVE_DEBUG > 1
+  else
+  { std::cout
+      << "NBASIC: " << nbasic << " basic variables; cdone " << ncdone
+      << ", col basic " << ncb << ", rdone " << nrdone << ", row basic "
+      << nrb << std::endl ;
+    std::cout << std::flush ;
+  }
+# endif
+  return ; }
+
+
+/*
+  CoinPresolveMatrix
+
+  Overload of presolve_check_nbasic for a CoinPresolveMatrix. There may not be
+  a solution, eh?
+*/
+void presolve_check_nbasic (const CoinPresolveMatrix *preObj)
+
+{
+
+  if (preObj->sol_ == 0) return ;
+
+  int ncols = preObj->ncols_ ;
+  int nrows = preObj->nrows_ ;
+
+  int nbasic = 0 ;
+  int ncb = 0;
+  int nrb = 0;
+
+  for (int j = 0 ; j < ncols ; j++)
+  { 
+    if (preObj->columnIsBasic(j))
+    { nbasic++ ;
+      ncb++ ; }
+  }
+
+  for (int i = 0 ; i < nrows ; i++)
+  {
+    if (preObj->rowIsBasic(i))
+    { nbasic++ ;
+      nrb++ ; }
+  }
+
+  if (nbasic != nrows)
+  { printf("WRONG NUMBER NBASIC:  is:  %d  should be:  %d;",
+	   nbasic,nrows) ;
+    printf(" cb %d, rb %d.\n",ncb,nrb);
+    fflush(stdout) ; }
+  return ; }
+
+#endif
+/*
+  Original comment: I've forgotton what this is all about
+
+  Looks to me like it's confirming that the columns flagged as basic indeed
+  have enough coefficients between them to cover the basis. It'd be serious
+  work to get this going again. Waaaaaay out of date.   -- lh, 040831 --
+*/
+# if 0
+void check_pivots (const int *mrstrt, const int *hinrow, const int *hcol,
+		   int nrows, const unsigned char *colstat,
+		   const unsigned char *rowstat, int ncols)
+{
+  int i ;
+  int nbasic = 0 ;
+  int gotone = 1 ;
+  int stillmore ;
+
+  return ;
+
+  int *bcol = new int[nrows] ;
+  memset(bcol, -1, nrows*sizeof(int)) ;
+
+  char *coldone = new char[ncols] ;
+  memset(coldone, 0, ncols) ;
+
+  while (gotone) {
+    gotone = 0 ;
+    stillmore = 0 ;
+    for (i=0; i<nrows; i++)
+      if (!postObj->rowIsBasic(i)) {
+	int krs = mrstrt[i] ;
+	int kre = mrstrt[i] + hinrow[i] ;
+	int nb = 0 ;
+	int kk ;
+	for (int k=krs; k<kre; k++)
+	  if (postObj->columnIsBasic(hcol[k]) && !coldone[hcol[k]]) {
+	    nb++ ;
+	    kk = k ;
+	    if (nb > 1)
+	      break ;
+	  }
+	if (nb == 1) {
+	  PRESOLVEASSERT(bcol[i] == -1) ;
+	  bcol[i] = hcol[kk] ;
+	  coldone[hcol[kk]] = 1 ;
+	  nbasic++ ;
+	  gotone = 1 ;
+	}
+	else
+	  stillmore = 1 ;
+      }
+  }
+  PRESOLVEASSERT(!stillmore) ;
+
+  for (i=0; i<nrows; i++)
+    if (postObj->rowIsBasic(i)) {
+      int krs = mrstrt[i] ;
+      int kre = mrstrt[i] + hinrow[i] ;
+      for (int k=krs; k<kre; k++)
+	PRESOLVEASSERT(!postObj->columnIsBasic(hcol[k]) || coldone[hcol[k]]) ;
+      nbasic++ ;
+    }
+  PRESOLVEASSERT(nbasic == nrows) ;
+}
+
+# endif
diff --git a/cbits/coin/CoinPresolvePsdebug.hpp b/cbits/coin/CoinPresolvePsdebug.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolvePsdebug.hpp
@@ -0,0 +1,166 @@
+/* $Id: CoinPresolvePsdebug.hpp 1560 2012-11-24 00:29:01Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolvePsdebug_H
+#define CoinPresolvePsdebug_H
+
+/*
+  The current idea of the relation between PRESOLVE_DEBUG and
+  PRESOLVE_CONSISTENCY is that PRESOLVE_CONSISTENCY triggers the consistency
+  checks and PRESOLVE_DEBUG triggers consistency checks and output.
+  This isn't always true in the code, but that's the goal.  Really,
+  the whole compile-time scheme should be replaced with something more
+  user-friendly (control variables that can be changed during the run).
+
+  Also floating about are PRESOLVE_SUMMARY and COIN_PRESOLVE_TUNING.
+  -- lh, 111208 --
+*/
+/*! \defgroup PresolveDebugFunctions Presolve Debug Functions
+
+  These functions implement consistency checks on data structures involved
+  in presolve and postsolve and on the components of the lp solution.
+
+  To use these functions, include CoinPresolvePsdebug.hpp in your file and
+  define the compile-time constants PRESOLVE_SUMMARY, PRESOLVE_DEBUG, and
+  PRESOLVE_CONSISTENCY. A value is needed (<i>i.e.</i>, PRESOLVE_DEBUG=1).
+  In a few places, higher values will get you a bit more output.
+
+                        ********
+
+  Define the symbols PRESOLVE_DEBUG and PRESOLVE_CONSISTENCY on the configure
+  command line (use ADD_CXXFLAGS), in a Makefile, or similar and do a full
+  rebuild (including any presolve driver code). If the symbols are not
+  consistently nonzero across *all* presolve code, you'll get something
+  between garbage and a core dump! Debugging adds messages to CoinMessage
+  and allocates and maintains arrays that hold debug information.
+
+  That said, given that you've configured and built with PRESOLVE_DEBUG and
+  PRESOLVE_CONSISTENCY nonzero everywhere, it's safe to adjust PRESOLVE_DEBUG
+  to values in the range 1..n in individual files to increase or decrease the
+  amount of output.
+
+  The suggested approach for PRESOLVE_DEBUG is to define it to 1 in the build
+  and then increase it in individual presolve code files to get more detail.
+
+                        ********
+*/
+//@{
+
+/*! \relates CoinPresolveMatrix
+    \brief Check column-major and/or row-major matrices for duplicate
+	   entries in the major vectors.
+
+  By default, scans both the column- and row-major matrices. Set doCol (doRow)
+  to false to suppress the column (row) scan.
+*/
+void presolve_no_dups(const CoinPresolveMatrix *preObj,
+		      bool doCol = true, bool doRow = true) ;
+
+/*! \relates CoinPresolveMatrix
+    \brief Check the links which track storage order for major vectors in
+    the bulk storage area.
+
+  By default, scans both the column- and row-major matrix. Set doCol = false to
+  suppress the column-major scan. Set doRow = false to suppres the row-major
+  scan. 
+*/
+void presolve_links_ok(const CoinPresolveMatrix *preObj,
+		       bool doCol = true, bool doRow = true) ;
+
+/*! \relates CoinPresolveMatrix
+    \brief Check for explicit zeros in the column- and/or row-major matrices.
+
+  By default, scans both the column- and row-major matrices. Set doCol (doRow)
+  to false to suppress the column (row) scan.
+*/
+void presolve_no_zeros(const CoinPresolveMatrix *preObj,
+		       bool doCol = true, bool doRow = true) ;
+
+/*! \relates CoinPresolveMatrix
+    \brief Checks for equivalence of the column- and row-major matrices.
+
+  Normally the routine will test for coefficient presence and value. Set
+  \p chkvals to false to suppress the check for equal value.
+*/
+void presolve_consistent(const CoinPresolveMatrix *preObj,
+			 bool chkvals = true) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Checks that column threads agree with column lengths
+*/
+void presolve_check_threads(const CoinPostsolveMatrix *obj) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Checks the free list
+
+    Scans the thread of free locations in the bulk store and checks that all
+    entries are reasonable (0 <= index < bulk0_). If chkElemCnt is true, it
+    also checks that the total number of entries in the matrix plus the
+    locations on the free list total to the size of the bulk store. Postsolve
+    routines do not maintain an accurate element count, but this is useful
+    for checking a newly constructed postsolve matrix.
+*/
+void presolve_check_free_list(const CoinPostsolveMatrix *obj,
+			      bool chkElemCnt = false) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Check stored reduced costs for accuracy and consistency with
+	   variable status.
+
+  The routine will check the value of the reduced costs for architectural
+  variables (CoinPrePostsolveMatrix::rcosts_). It performs an accuracy check
+  by recalculating the reduced cost from scratch. It will also check the
+  value for consistency with the status information in
+  CoinPrePostsolveMatrix::colstat_.
+*/
+void presolve_check_reduced_costs(const CoinPostsolveMatrix *obj) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Check the dual variables for consistency with row activity.
+
+  The routine checks that the value of the dual variable is consistent
+  with the state of the constraint (loose, tight at lower bound, or tight at
+  upper bound).
+*/
+void presolve_check_duals(const CoinPostsolveMatrix *postObj) ;
+
+/*! \relates CoinPresolveMatrix
+    \brief Check primal solution and architectural variable status.
+
+    The architectural variables can be checked for bogus values, feasibility,
+    and valid status. The row activity is checked for bogus values, accuracy,
+    and feasibility.  By default, row activity is not checked (presolve is
+    sloppy about maintaining it). See the definitions in
+    CoinPresolvePsdebug.cpp for more information.
+*/
+void presolve_check_sol(const CoinPresolveMatrix *preObj,
+			int chkColSol = 2, int chkRowAct = 1,
+			int chkStatus = 1) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Check primal solution and architectural variable status.
+
+    The architectural variables can be checked for bogus values, feasibility,
+    and valid status. The row activity is checked for bogus values, accuracy,
+    and feasibility. See the definitions in CoinPresolvePsdebug.cpp for more
+    information.
+*/
+void presolve_check_sol(const CoinPostsolveMatrix *postObj,
+			int chkColSol = 2, int chkRowAct = 2,
+			int chkStatus = 1) ;
+
+/*! \relates CoinPresolveMatrix
+    \brief Check for the proper number of basic variables.
+*/
+void presolve_check_nbasic(const CoinPresolveMatrix *preObj) ;
+
+/*! \relates CoinPostsolveMatrix
+    \brief Check for the proper number of basic variables.
+*/
+void presolve_check_nbasic(const CoinPostsolveMatrix *postObj) ;
+
+//@}
+
+#endif
diff --git a/cbits/coin/CoinPresolveSingleton.cpp b/cbits/coin/CoinPresolveSingleton.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveSingleton.cpp
@@ -0,0 +1,1040 @@
+/* $Id: CoinPresolveSingleton.cpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+
+#include "CoinPresolveEmpty.hpp"	// for DROP_COL/DROP_ROW
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveSingleton.hpp"
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+#include "CoinMessage.hpp"
+#include "CoinFinite.hpp"
+
+
+/*
+ * Original comment:
+ *
+ * Transfers singleton row bound information to the corresponding column bounds.
+ * What I refer to as a row singleton would be called a doubleton
+ * in the paper, since my terminology doesn't refer to the slacks.
+ * In terms of the paper, we transfer the bounds of the slack onto
+ * the variable (vii) and then "substitute" the slack out of the problem 
+ * (which is a noop).
+ */
+/*
+  Given blow(i) <= a(ij)x(j) <= b(i), we can transfer the bounds enforced by
+  the constraint to the column bounds l(j) and u(j) on x(j) and delete the
+  row.
+
+  You can think of this as a specialised instance of doubleton_action, where
+  the target variable is the logical that transforms an inequality to an
+  equality. Since the system doesn't have logicals at this point, the row is a
+  singleton.
+
+  At some time in the past, the main loop was written to scan all rows but
+  was limited in the number of rows it could process in one call. The
+  notFinished parameter is the only remaining vestige of this behaviour and
+  should probably be removed. For now, make sure it's forced to false for the
+  benefit of code that looks at the returned value.  -- lh, 121015 --
+*/
+const CoinPresolveAction *
+slack_doubleton_action::presolve(CoinPresolveMatrix *prob,
+				 const CoinPresolveAction *next,
+				 bool &notFinished)
+{
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Entering slack_doubleton_action::presolve." << std::endl ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# endif
+
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int startEmptyRows = prob->countEmptyRows() ;
+  int startEmptyColumns = prob->countEmptyCols() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0 ;
+  if (prob->tuning_) {
+    startTime = CoinCpuTime() ;
+  }
+# endif
+# endif
+
+  notFinished = false ;
+
+/*
+  Unpack the problem representation.
+*/
+  double *colels = prob->colels_ ;
+  int *hrow = prob->hrow_ ;
+  CoinBigIndex *mcstrt = prob->mcstrt_ ;
+  int *hincol = prob->hincol_ ;
+
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+
+  double *rowels = prob->rowels_ ;
+  const int *hcol = prob->hcol_ ;
+  const CoinBigIndex *mrstrt = prob->mrstrt_ ;
+  int *hinrow = prob->hinrow_ ;
+
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+
+/*
+  Rowstat is used to decide if the solution is present.
+*/
+  unsigned char *rowstat = prob->rowstat_ ;
+  double *acts = prob->acts_ ;
+  double *sol = prob->sol_ ;
+
+  const unsigned char *integerType = prob->integerType_ ;
+
+  const double ztolzb	= prob->ztolzb_ ;
+
+  int numberLook = prob->numberRowsToDo_ ;
+  int *look = prob->rowsToDo_ ;
+  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+
+  action *actions = new action[numberLook] ;
+  int nactions = 0 ;
+
+  int *fixed_cols = prob->usefulColumnInt_ ;
+  int nfixed_cols = 0 ;
+
+  bool infeas = false ;
+
+/*
+  Walk the rows looking for singletons.
+*/
+  for (int iLook = 0 ; iLook < numberLook ; iLook++) {
+    int i = look[iLook] ;
+
+    if (hinrow[i] != 1) continue ;
+    int j = hcol[mrstrt[i]] ;
+    double aij = rowels[mrstrt[i]] ;
+    double lo = rlo[i] ;
+    double up = rup[i] ;
+    double abs_aij = fabs(aij) ;
+/*
+  A tiny value of a(ij) invites numerical error, since the new bound will be
+  (something)/a(ij). Columns that are already fixed are also uninteresting.
+*/
+    if (abs_aij < ZTOLDP2) continue ;
+    if (fabs(cup[j]-clo[j]) < ztolzb) continue ;
+
+    PRESOLVE_DETAIL_PRINT(printf("pre_singleton %dC %dR E\n",j,i)) ;
+
+/*
+  Get down to work. First create the postsolve action for row i / x(j).
+*/
+    action *s = &actions[nactions] ;
+    nactions++ ;
+    s->col = j ;
+    s->clo = clo[j] ;
+    s->cup = cup[j] ;
+    s->row = i ;
+    s->rlo = rlo[i] ;
+    s->rup = rup[i] ;
+    s->coeff = aij ;
+
+#   if PRESOLVE_DEBUG > 1
+    std::cout
+      << "  removing row " << i << ": " << rlo[i] << " <=  " << aij
+      << "*x(" << j << ") <= " << rup[i] << std::endl ;
+#   endif
+
+/*
+  Do the work of bounds transfer. Starting with
+    blow(i) <= a(ij)x(j) <= b(i),
+  we end up with
+    blow(i)/a(ij) <= x(j) <= b(i)/a(ij)		a(ij) > 0
+    blow(i)/a(ij) >= x(j) >= b(i)/a(ij)		a(ij) < 0
+  The code deals with a(ij) < 0 by swapping and negating the row bounds and
+  calculating with |a(ij)|. Be careful not to convert finite infinity to
+  finite, or vice versa.
+*/
+    if (aij < 0.0) {
+      CoinSwap(lo,up) ;
+      lo = -lo ;
+      up = -up ;
+    }
+    if (lo <= -PRESOLVE_INF)
+      lo = -PRESOLVE_INF ;
+    else {
+      lo /= abs_aij ;
+      if (lo <= -PRESOLVE_INF)
+	lo = -PRESOLVE_INF ;
+    }
+    if (up > PRESOLVE_INF)
+      up = PRESOLVE_INF ;
+    else {
+      up /= abs_aij ;
+      if (up > PRESOLVE_INF)
+	up = PRESOLVE_INF ;
+    }
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "    l(" << j << ") = " << clo[j] << " ==> " << lo << ", delta "
+      << (lo-clo[j]) << std::endl ;
+    std::cout
+      << "    u(" << j << ") = " << cup[j] << " ==> " << up << ", delta "
+      << (cup[j]-up) << std::endl ;
+#   endif
+/*
+  lo and up are now the new l(j) and u(j), respectively. If they're better than
+  the existing bounds, update. Have a care with integer variables --- don't let
+  numerical inaccuracy pull us off an integral bound.
+*/
+    if (clo[j] < lo) {
+      // If integer be careful
+      if (integerType[j]) {
+	if (fabs(lo-floor(lo+0.5)) < 0.000001) lo = floor(lo+0.5) ;
+	if (clo[j] < lo) clo[j] = lo ;
+      } else {
+	clo[j] = lo ;
+      }
+    }
+    if (cup[j] > up) {
+      if (integerType[j]) {
+	if (fabs(up-floor(up+0.5)) < 0.000001) up = floor(up+0.5) ;
+	if (cup[j] > up) cup[j] = up ;
+      } else {
+	cup[j] = up ;
+      }
+    }
+/*
+  Is x(j) now fixed? Remember it for later.
+*/
+    if (fabs(cup[j] - clo[j]) < ZTOLDP) {
+      fixed_cols[nfixed_cols++] = j ;
+    }
+/*
+  Is x(j) infeasible? Fix it if we're within the feasibility tolerance, or if
+  the user was so foolish as to request repair of infeasibility. Integer values
+  are preferred, if close enough.
+
+  If the infeasibility is too large to ignore, mark the problem infeasible and
+  head for the exit.
+*/
+    if (lo > up) {
+      if (lo <= up+prob->feasibilityTolerance_ || fixInfeasibility) {
+	double nearest = floor(lo+0.5) ;
+	if (fabs(nearest-lo)<2.0*prob->feasibilityTolerance_) {
+	  lo = nearest ;
+	  up = nearest ;
+	} else {
+	  lo = up ;
+	}
+	clo[j] = lo ;
+	cup[j] = up ;
+      } else {
+	prob->status_ |= 1 ;
+	prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS,
+					prob->messages())
+	    << j << lo << up << CoinMessageEol ;
+	infeas = true ;
+	break ;
+      }
+    }
+
+#   if PRESOLVE_DEBUG > 1
+    printf("SINGLETON R-%d C-%d\n", i, j) ;
+#   endif
+
+/*
+  Remove the row from the row-major representation.
+*/
+    hinrow[i] = 0 ;
+    PRESOLVE_REMOVE_LINK(prob->rlink_,i) ;
+    rlo[i] = 0.0 ;
+    rup[i] = 0.0 ;
+/*
+  Remove the row from this col in the column-major representation. It can
+  happen that this will empty the column, in which case we can delink it.
+  If the column isn't empty, queue it for further processing.
+*/
+    presolve_delete_from_col(i,j,mcstrt,hincol,hrow,colels) ;
+    if (hincol[j] == 0) {
+      PRESOLVE_REMOVE_LINK(prob->clink_,j) ;
+    } else {
+      prob->addCol(j) ;
+    }
+/*
+  Update the solution, if it's present. The trick is maintaining the right
+  number of basic variables. We've deleted a row, so we need to reduce the
+  basis by one.
+
+  There's a corner case that doesn't seem to be covered. What happens if
+  both x(j) and s(i) are nonbasic? The number of basic variables will not
+  be reduced.  This is admittedly a pathological situation: It implies
+  that there's an existing bound l(j) or u(j) exactly equal to the bound
+  imposed by this constraint, so that x(j) can be nonbasic at bound and
+  the constraint can be simultaneously tight.   -- lh, 121115 --
+*/
+    if (rowstat) {
+      int basisChoice = 0 ;
+      int numberBasic = 0 ;
+      double movement = 0 ;
+      if (prob->columnIsBasic(j)) {
+	numberBasic++ ;
+	basisChoice = 2 ; // move to row to keep consistent
+      }
+      if (prob->rowIsBasic(i))
+	numberBasic++ ;
+      PRESOLVEASSERT(numberBasic > 0) ;
+      if (sol[j] <= clo[j]+ztolzb) {
+	movement = clo[j]-sol[j] ;
+	sol[j] = clo[j] ;
+	prob->setColumnStatus(j,CoinPrePostsolveMatrix::atLowerBound) ;
+      } else if (sol[j] >= cup[j]-ztolzb) {
+	movement = cup[j]-sol[j] ;
+	sol[j] = cup[j] ;
+	prob->setColumnStatus(j,CoinPrePostsolveMatrix::atUpperBound) ;
+      } else {
+	basisChoice = 1 ;
+      }
+      if (numberBasic > 1 || basisChoice == 1)
+	prob->setColumnStatus(j,CoinPrePostsolveMatrix::basic) ;
+      else if (basisChoice==2)
+	prob->setRowStatus(i,CoinPrePostsolveMatrix::basic) ;
+      if (movement) {
+	const CoinBigIndex &kcs = mcstrt[j] ;
+	const CoinBigIndex kce = kcs+hincol[j] ;
+	for (CoinBigIndex kcol = kcs ; kcol < kce ; kcol++) {
+	  int k = hrow[kcol] ;
+	  PRESOLVEASSERT(hinrow[k] > 0) ;
+	  acts[k] += movement*colels[kcol] ;
+	}
+      }
+    }
+  }
+/*
+  Done with processing. Time to deal with the results. First add the postsolve
+  actions for the singletons to the postsolve list. Then call
+  remove_fixed_action to handle variables that were fixed during the loop.
+  (We've already adjusted the solution, so make_fixed_action is not needed.)
+*/
+  if (!infeas && nactions) {
+#   if PRESOLVE_SUMMARY
+    std::cout
+      << "SINGLETON ROWS: " << nactions << std::endl ;
+#   endif
+    action *save_actions = new action[nactions] ;
+    CoinMemcpyN(actions, nactions, save_actions) ;
+    next = new slack_doubleton_action(nactions,save_actions,next) ;
+
+    if (nfixed_cols)
+      next = remove_fixed_action::presolve(prob,fixed_cols,nfixed_cols,next) ;
+  }
+  delete[] actions ;
+
+# if COIN_PRESOLVE_TUNING > 0
+  double thisTime ;
+  if (prob->tuning_) double thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving slack_doubleton_action::presolve, "
+    << droppedRows << " rows, " << droppedColumns
+    << " columns dropped" ;
+#if COIN_PRESOLVE_TUNING > 0
+  std::cout
+    << " in " << (thisTime-startTime) << "s, total "
+    << (thisTime-prob->startTime_) ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+void slack_doubleton_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_ ;
+  const int nactions = nactions_ ;
+
+  double *colels = prob->colels_ ;
+  int *hrow = prob->hrow_ ;
+  CoinBigIndex *mcstrt = prob->mcstrt_ ;
+  int *hincol = prob->hincol_ ;
+  int *link = prob->link_ ;
+
+  double *clo = prob->clo_ ;
+  double *cup = prob->cup_ ;
+  double *sol = prob->sol_ ;
+  double *rcosts = prob->rcosts_ ;
+  unsigned char *colstat = prob->colstat_ ;
+
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+  double *acts = prob->acts_ ;
+  double *rowduals = prob->rowduals_ ;
+
+
+# if PRESOLVE_DEBUG
+  char *rdone = prob->rdone_ ;
+  std::cout
+    << "Entering slack_doubleton_action::postsolve, "
+    << nactions << " constraints to process." << std::endl ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  CoinBigIndex &free_list = prob->free_list_ ;
+
+  const double ztolzb	= prob->ztolzb_ ;
+
+  for (const action *f = &actions[nactions-1] ; actions <= f ; f--) {
+    int irow = f->row ;
+    double lo0 = f->clo ;
+    double up0 = f->cup ;
+    double coeff = f->coeff ;
+    int jcol = f->col ;
+
+    rlo[irow] = f->rlo ;
+    rup[irow] = f->rup ;
+
+    clo[jcol] = lo0 ;
+    cup[jcol] = up0 ;
+
+    acts[irow] = coeff*sol[jcol] ;
+    /*
+      Create the row and restore the single coefficient, linking the new
+      coefficient at the start of the column.
+    */
+    {
+      CoinBigIndex k = free_list ;
+      assert(k >= 0 && k < prob->bulk0_) ;
+      free_list = link[free_list] ;
+      hrow[k] = irow ;
+      colels[k] = coeff ;
+      link[k] = mcstrt[jcol] ;
+      mcstrt[jcol] = k ;
+      hincol[jcol]++ ;
+    }
+
+    /*
+      Since we are adding a row, we have to set the row status and dual
+      to satisfy complimentary slackness.  We may also have to modify
+      the column status and reduced cost if bounds have been relaxed.
+     */
+    if (!colstat) {
+      // ????
+      rowduals[irow] = 0.0 ;
+    } else {
+      if (prob->columnIsBasic(jcol)) {
+	/*
+	  The variable is basic, hence the slack must be basic, hence the dual
+	  for the row is zero.  Relaxing the bounds on a basic variable
+	  doesn't change anything.
+	*/
+	prob->setRowStatus(irow,CoinPrePostsolveMatrix::basic) ;
+	rowduals[irow] = 0.0 ;
+      } else if ((fabs(sol[jcol]-lo0) <= ztolzb && rcosts[jcol] >= 0) ||
+		 (fabs(sol[jcol]-up0) <= ztolzb && rcosts[jcol] <= 0)) {
+	/*
+	  The variable is nonbasic and the sign of the reduced cost is correct
+	  for the bound. Again, the slack will be basic and the dual zero.
+	*/
+	prob->setRowStatus(irow,CoinPrePostsolveMatrix::basic) ;
+	rowduals[irow] = 0.0 ;
+      } else if (!(fabs(sol[jcol]-lo0) <= ztolzb) &&
+		 !(fabs(sol[jcol]-up0) <= ztolzb)) {
+	/*
+	  The variable was not basic but transferring bounds back to the
+	  constraint has relaxed the column bounds. The variable will need to
+	  be made basic. The constraint must then be tight and the dual must
+	  be set so that the reduced cost of the variable becomes zero.
+	*/
+	prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::basic) ;
+	prob->setRowStatusUsingValue(irow) ;
+	rowduals[irow] = rcosts[jcol]/coeff ;
+	rcosts[jcol] = 0.0 ;
+      } else {
+	/*
+	  The variable is at bound, but the reduced cost is wrong. Again
+	  set the row dual to bring the reduced cost to zero. This implies
+	  that the constraint is tight and the slack will be nonbasic.
+	*/
+	prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::basic) ;
+	prob->setRowStatusUsingValue(irow) ;
+	rowduals[irow] = rcosts[jcol]/coeff ;
+	rcosts[jcol] = 0.0 ;
+      }
+    }
+
+#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+    rdone[irow] = SLACK_DOUBLETON ;
+#   endif
+  }
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving slack_doubleton_action::postsolve." << std::endl ;
+# endif
+
+  return ; 
+}
+/*
+    If we have a variable with one entry and no cost then we can
+    transform the row from E to G etc.
+    If there is a row objective region then we may be able to do
+    this even with a cost.
+*/
+const CoinPresolveAction *
+slack_singleton_action::presolve(CoinPresolveMatrix *prob,
+				 const CoinPresolveAction *next,
+                                 double * rowObjective)
+{
+  double startTime = 0.0 ;
+  int startEmptyRows=0 ;
+  int startEmptyColumns = 0 ;
+  if (prob->tuning_) {
+    startTime = CoinCpuTime() ;
+    startEmptyRows = prob->countEmptyRows() ;
+    startEmptyColumns = prob->countEmptyCols() ;
+  }
+  double *colels	= prob->colels_ ;
+  int *hrow		= prob->hrow_ ;
+  CoinBigIndex *mcstrt	= prob->mcstrt_ ;
+  int *hincol		= prob->hincol_ ;
+  //int ncols		= prob->ncols_ ;
+
+  double *clo		= prob->clo_ ;
+  double *cup		= prob->cup_ ;
+
+  double *rowels	= prob->rowels_ ;
+  int *hcol	= prob->hcol_ ;
+  CoinBigIndex *mrstrt	= prob->mrstrt_ ;
+  int *hinrow		= prob->hinrow_ ;
+  int nrows		= prob->nrows_ ;
+
+  double *rlo		= prob->rlo_ ;
+  double *rup		= prob->rup_ ;
+
+  // Existence of 
+  unsigned char *rowstat	= prob->rowstat_ ;
+  double *acts	= prob->acts_ ;
+  double * sol = prob->sol_ ;
+
+  const unsigned char *integerType = prob->integerType_ ;
+
+  const double ztolzb	= prob->ztolzb_ ;
+  double *dcost	= prob->cost_ ;
+  //const double maxmin	= prob->maxmin_ ;
+
+# if PRESOLVE_DEBUG
+  std::cout << "Entering slack_singleton_action::presolve." << std::endl ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  int numberLook = prob->numberColsToDo_ ;
+  int iLook ;
+  int * look = prob->colsToDo_ ;
+  // Make sure we allocate at least one action
+  int maxActions = CoinMin(numberLook,nrows/10)+1 ;
+  action * actions = new action[maxActions] ;
+  int nactions = 0 ;
+  int * fixed_cols = new int [numberLook] ;
+  int nfixed_cols=0 ;
+  int nWithCosts=0 ;
+  double costOffset=0.0 ;
+  for (iLook=0;iLook<numberLook;iLook++) {
+    int iCol = look[iLook] ;
+    if (dcost[iCol])
+      continue ;
+    if (hincol[iCol] == 1) {
+      int iRow=hrow[mcstrt[iCol]] ;
+      double coeff = colels[mcstrt[iCol]] ;
+      double acoeff = fabs(coeff) ;
+      if (acoeff < ZTOLDP2)
+	continue ;
+      // don't bother with fixed cols
+      if (fabs(cup[iCol] - clo[iCol]) < ztolzb)
+	continue ;
+      if (integerType&&integerType[iCol]) {
+	// only possible if everything else integer and unit coefficient
+	// check everything else a bit later
+	if (acoeff!=1.0)
+	  continue ;
+        double currentLower = rlo[iRow] ;
+        double currentUpper = rup[iRow] ;
+	if (coeff==1.0&&currentLower==1.0&&currentUpper==1.0) {
+	  // leave if integer slack on sum x == 1
+	  bool allInt=true ;
+	  for (CoinBigIndex j=mrstrt[iRow] ;
+	       j<mrstrt[iRow]+hinrow[iRow];j++) {
+	    int iColumn = hcol[j] ;
+	    double value = fabs(rowels[j]) ;
+	    if (!integerType[iColumn]||value!=1.0) {
+	      allInt=false ;
+	      break ;
+	    }
+	  }
+	  if (allInt)
+	    continue; // leave as may help search
+	}
+      }
+      if (!prob->colProhibited(iCol)) {
+        double currentLower = rlo[iRow] ;
+        double currentUpper = rup[iRow] ;
+        if (!rowObjective) {
+          if (dcost[iCol])
+            continue ;
+        } else if ((dcost[iCol]&&currentLower!=currentUpper)||rowObjective[iRow]) {
+          continue ;
+        }
+        double newLower=currentLower ;
+        double newUpper=currentUpper ;
+        if (coeff<0.0) {
+          if (currentUpper>1.0e20||cup[iCol]>1.0e20) {
+            newUpper=COIN_DBL_MAX ;
+          } else {
+            newUpper -= coeff*cup[iCol] ;
+            if (newUpper>1.0e20)
+              newUpper=COIN_DBL_MAX ;
+          }
+          if (currentLower<-1.0e20||clo[iCol]<-1.0e20) {
+            newLower=-COIN_DBL_MAX ;
+          } else {
+            newLower -= coeff*clo[iCol] ;
+            if (newLower<-1.0e20)
+              newLower=-COIN_DBL_MAX ;
+          }
+        } else {
+          if (currentUpper>1.0e20||clo[iCol]<-1.0e20) {
+            newUpper=COIN_DBL_MAX ;
+          } else {
+            newUpper -= coeff*clo[iCol] ;
+            if (newUpper>1.0e20)
+              newUpper=COIN_DBL_MAX ;
+          }
+          if (currentLower<-1.0e20||cup[iCol]>1.0e20) {
+            newLower=-COIN_DBL_MAX ;
+          } else {
+            newLower -= coeff*cup[iCol] ;
+            if (newLower<-1.0e20)
+              newLower=-COIN_DBL_MAX ;
+          }
+        }
+	if (integerType&&integerType[iCol]) {
+	  // only possible if everything else integer
+	  if (newLower>-1.0e30) {
+	    if (newLower!=floor(newLower+0.5))
+	      continue ;
+	  }
+	  if (newUpper<1.0e30) {
+	    if (newUpper!=floor(newUpper+0.5))
+	      continue ;
+	  }
+	  bool allInt=true ;
+	  for (CoinBigIndex j=mrstrt[iRow] ;
+	       j<mrstrt[iRow]+hinrow[iRow];j++) {
+	    int iColumn = hcol[j] ;
+	    double value = fabs(rowels[j]) ;
+	    if (!integerType[iColumn]||value!=floor(value+0.5)) {
+	      allInt=false ;
+	      break ;
+	    }
+	  }
+	  if (!allInt)
+	    continue; // no good
+	}
+        if (nactions>=maxActions) {
+          maxActions += CoinMin(numberLook-iLook,maxActions) ;
+          action * temp = new action[maxActions] ;
+	  memcpy(temp,actions,nactions*sizeof(action)) ;
+          // changed as 4.6 compiler bug! CoinMemcpyN(actions,nactions,temp) ;
+          delete [] actions ;
+          actions=temp ;
+        }
+          
+	action *s = &actions[nactions] ;
+	nactions++ ;
+
+	s->col = iCol ;
+	s->clo = clo[iCol] ;
+	s->cup = cup[iCol] ;
+
+	s->row = iRow ;
+	s->rlo = rlo[iRow] ;
+	s->rup = rup[iRow] ;
+
+	s->coeff = coeff ;
+
+        presolve_delete_from_row(iRow,iCol,mrstrt,hinrow,hcol,rowels) ;
+        if (!hinrow[iRow])
+          PRESOLVE_REMOVE_LINK(prob->rlink_,iRow) ;
+        // put row on stack of things to do next time
+        prob->addRow(iRow) ;
+#ifdef PRINTCOST        
+        if (rowObjective&&dcost[iCol]) {
+          printf("Singleton %d had coeff of %g in row %d - bounds %g %g - cost %g\n",
+                 iCol,coeff,iRow,clo[iCol],cup[iCol],dcost[iCol]) ;
+          printf("Row bounds were %g %g now %g %g\n",
+                 rlo[iRow],rup[iRow],newLower,newUpper) ;
+        }
+#endif
+        // Row may be redundant but let someone else do that
+        rlo[iRow]=newLower ;
+        rup[iRow]=newUpper ;
+        if (rowstat&&sol) {
+          // update solution and basis
+          if ((sol[iCol] < cup[iCol]-ztolzb&&
+	       sol[iCol] > clo[iCol]+ztolzb)||prob->columnIsBasic(iCol))
+            prob->setRowStatus(iRow,CoinPrePostsolveMatrix::basic) ;
+          prob->setColumnStatusUsingValue(iCol) ;
+        }
+        // Force column to zero
+        clo[iCol]=0.0 ;
+        cup[iCol]=0.0 ;
+        if (rowObjective&&dcost[iCol]) {
+          rowObjective[iRow]=-dcost[iCol]/coeff ;
+            nWithCosts++ ;
+          // adjust offset
+          costOffset += currentLower*rowObjective[iRow] ;
+          prob->dobias_ -= currentLower*rowObjective[iRow] ;
+        }
+	if (sol) {
+	  double movement ;
+	  if (fabs(sol[iCol]-clo[iCol])<fabs(sol[iCol]-cup[iCol])) {
+	    movement = clo[iCol]-sol[iCol] ;
+	    sol[iCol]=clo[iCol] ;
+	  } else {
+	    movement = cup[iCol]-sol[iCol] ;
+	    sol[iCol]=cup[iCol] ;
+	  }
+	  if (movement) 
+	    acts[iRow] += movement*coeff ;
+	}
+        /*
+          Remove the row from this col in the col rep.and delink it.
+        */
+        presolve_delete_from_col(iRow,iCol,mcstrt,hincol,hrow,colels) ;
+        assert (hincol[iCol] == 0) ;
+        PRESOLVE_REMOVE_LINK(prob->clink_,iCol) ; 
+	//clo[iCol] = 0.0 ;
+	//cup[iCol] = 0.0 ;
+	fixed_cols[nfixed_cols++] = iCol ;
+        //presolve_consistent(prob) ;
+      }
+    }   
+  }
+  
+  if (nactions) {
+#   if PRESOLVE_SUMMARY
+    printf("SINGLETON COLS:  %d\n", nactions) ;
+#   endif
+#ifdef COIN_DEVELOP
+    printf("%d singletons, %d with costs - offset %g\n",nactions,
+           nWithCosts, costOffset) ;
+#endif
+    action *save_actions = new action[nactions] ;
+    CoinMemcpyN(actions, nactions, save_actions) ;
+    next = new slack_singleton_action(nactions, save_actions, next) ;
+
+    if (nfixed_cols)
+      next = make_fixed_action::presolve(prob, fixed_cols, nfixed_cols,
+					 true, // arbitrary
+					 next) ;
+  }
+  delete [] actions ;
+  delete [] fixed_cols ;
+  if (prob->tuning_) {
+    double thisTime=CoinCpuTime() ;
+    int droppedRows = prob->countEmptyRows() - startEmptyRows ;
+    int droppedColumns =  prob->countEmptyCols() - startEmptyColumns ;
+    printf("CoinPresolveSingleton(3) - %d rows, %d columns dropped in time %g, total %g\n",
+	   droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_) ;
+  }
+
+# if PRESOLVE_DEBUG
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+  std::cout << "Leaving slack_singleton_action::presolve." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+void slack_singleton_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_ ;
+  const int nactions = nactions_ ;
+
+  double *colels	= prob->colels_ ;
+  int *hrow		= prob->hrow_ ;
+  CoinBigIndex *mcstrt		= prob->mcstrt_ ;
+  int *hincol		= prob->hincol_ ;
+  int *link		= prob->link_ ;
+  //  int ncols		= prob->ncols_ ;
+
+  //double *rowels	= prob->rowels_ ;
+  //int *hcol	= prob->hcol_ ;
+  //CoinBigIndex *mrstrt	= prob->mrstrt_ ;
+  //int *hinrow		= prob->hinrow_ ;
+
+  double *clo		= prob->clo_ ;
+  double *cup		= prob->cup_ ;
+
+  double *rlo		= prob->rlo_ ;
+  double *rup		= prob->rup_ ;
+
+  double *sol		= prob->sol_ ;
+  double *rcosts	= prob->rcosts_ ;
+
+  double *acts		= prob->acts_ ;
+  double *rowduals 	= prob->rowduals_ ;
+  double *dcost	= prob->cost_ ;
+  //const double maxmin	= prob->maxmin_ ;
+
+  unsigned char *colstat		= prob->colstat_ ;
+  //  unsigned char *rowstat		= prob->rowstat_ ;
+
+# if PRESOLVE_DEBUG
+  char *rdone		= prob->rdone_ ;
+
+  std::cout << "Entering slack_singleton_action::postsolve." << std::endl ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  CoinBigIndex &free_list		= prob->free_list_ ;
+
+  const double ztolzb	= prob->ztolzb_ ;
+#ifdef CHECK_ONE_ROW
+  {
+    double act=0.0 ;
+    for (int i=0;i<prob->ncols_;i++) {
+      double solV = sol[i] ;
+      assert (solV>=clo[i]-ztolzb&&solV<=cup[i]+ztolzb) ;
+      int j=mcstrt[i] ;
+      for (int k=0;k<hincol[i];k++) {
+	if (hrow[j]==CHECK_ONE_ROW) {
+	  act += colels[j]*solV ;
+	}
+	j=link[j] ;
+      }
+    }
+    assert (act>=rlo[CHECK_ONE_ROW]-ztolzb&&act<=rup[CHECK_ONE_ROW]+ztolzb) ;
+    printf("start %g %g %g %g\n",rlo[CHECK_ONE_ROW],act,acts[CHECK_ONE_ROW],rup[CHECK_ONE_ROW]) ;
+  }
+#endif
+  for (const action *f = &actions[nactions-1]; actions<=f; f--) {
+    int iRow = f->row ;
+    double lo0 = f->clo ;
+    double up0 = f->cup ;
+    double coeff = f->coeff ;
+    int iCol = f->col ;
+    assert (!hincol[iCol]) ;
+#ifdef CHECK_ONE_ROW
+    if (iRow==CHECK_ONE_ROW)
+      printf("Col %d coeff %g old bounds %g,%g new %g,%g - new rhs %g,%g - act %g\n",
+	     iCol,coeff,clo[iCol],cup[iCol],lo0,up0,f->rlo,f->rup,acts[CHECK_ONE_ROW]) ;
+#endif
+    rlo[iRow] = f->rlo ;
+    rup[iRow] = f->rup ;
+
+    clo[iCol] = lo0 ;
+    cup[iCol] = up0 ;
+    double movement=0.0 ;
+    // acts was without coefficient - adjust
+    acts[iRow] += coeff*sol[iCol] ;
+    if (acts[iRow]<rlo[iRow]-ztolzb) 
+      movement = rlo[iRow]-acts[iRow] ;
+    else if (acts[iRow]>rup[iRow]+ztolzb)
+      movement = rup[iRow]-acts[iRow] ;
+    double cMove = movement/coeff ;
+    sol[iCol] += cMove ;
+    acts[iRow] += movement ;
+    if (!dcost[iCol]) {
+      // and to get column feasible
+      cMove=0.0 ;
+      if (sol[iCol]>cup[iCol]+ztolzb) 
+        cMove = cup[iCol]-sol[iCol] ;
+      else if (sol[iCol]<clo[iCol]-ztolzb) 
+        cMove = clo[iCol]-sol[iCol] ;
+      sol[iCol] += cMove ;
+      acts[iRow] += cMove*coeff ;
+      /*
+       * Have to compute status.  At most one can be basic. It's possible that
+	 both are nonbasic and nonbasic status must change.
+       */
+      if (colstat) {
+        int numberBasic =0 ;
+        if (prob->columnIsBasic(iCol)) 
+          numberBasic++ ;
+        if (prob->rowIsBasic(iRow)) 
+          numberBasic++ ;
+#ifdef COIN_DEVELOP
+        if (numberBasic>1)
+          printf("odd in singleton\n") ;
+#endif
+        if (sol[iCol]>clo[iCol]+ztolzb&&sol[iCol]<cup[iCol]-ztolzb) {
+          prob->setColumnStatus(iCol,CoinPrePostsolveMatrix::basic) ;
+          prob->setRowStatusUsingValue(iRow) ;
+        } else if (acts[iRow]>rlo[iRow]+ztolzb&&acts[iRow]<rup[iRow]-ztolzb) {
+          prob->setRowStatus(iRow,CoinPrePostsolveMatrix::basic) ;
+          prob->setColumnStatusUsingValue(iCol) ;
+        } else if (numberBasic) {
+          prob->setRowStatus(iRow,CoinPrePostsolveMatrix::basic) ;
+          prob->setColumnStatusUsingValue(iCol) ;
+        } else {
+          prob->setRowStatusUsingValue(iRow) ;
+          prob->setColumnStatusUsingValue(iCol) ;
+	}
+      }
+#     if PRESOLVE_DEBUG > 1
+      printf("SLKSING: %d = %g restored %d lb = %g ub = %g.\n",
+	     iCol,sol[iCol],prob->getColumnStatus(iCol),clo[iCol],cup[iCol]) ;
+#     endif
+    } else {
+      // must have been equality row
+      assert (rlo[iRow]==rup[iRow]) ;
+      double cost = rcosts[iCol] ;
+      // adjust for coefficient
+      cost -= rowduals[iRow]*coeff ;
+      bool basic=true ;
+      if (fabs(sol[iCol]-cup[iCol])<ztolzb&&cost<-1.0e-6) 
+        basic=false ;
+      else if (fabs(sol[iCol]-clo[iCol])<ztolzb&&cost>1.0e-6) 
+        basic=false ;
+      //printf("Singleton %d had coeff of %g in row %d (dual %g) - bounds %g %g - cost %g, (dj %g)\n",
+      //     iCol,coeff,iRow,rowduals[iRow],clo[iCol],cup[iCol],dcost[iCol],rcosts[iCol]) ;
+      //if (prob->columnIsBasic(iCol)) 
+      //printf("column basic! ") ;
+      //if (prob->rowIsBasic(iRow)) 
+      //printf("row basic ") ;
+      //printf("- make column basic %s\n",basic ? "yes" : "no") ;
+      if (basic&&!prob->rowIsBasic(iRow)) {
+#ifdef PRINTCOST        
+        printf("Singleton %d had coeff of %g in row %d (dual %g) - bounds %g %g - cost %g, (dj %g - new %g)\n",
+               iCol,coeff,iRow,rowduals[iRow],clo[iCol],cup[iCol],dcost[iCol],rcosts[iCol],cost) ;
+#endif
+#ifdef COIN_DEVELOP
+        if (prob->columnIsBasic(iCol)) 
+          printf("column basic!\n") ;
+#endif
+        basic=false ;
+      }
+      if (fabs(rowduals[iRow])>1.0e-6&&prob->rowIsBasic(iRow))
+        basic=true ;
+      if (basic) {
+        // Make basic have zero reduced cost 
+	rowduals[iRow] = rcosts[iCol] / coeff ;
+	rcosts[iCol] = 0.0 ;
+      } else {
+        rcosts[iCol]=cost ;
+        //rowduals[iRow]=0.0 ;
+      }
+      if (colstat) {
+        if (basic) {
+          if (!prob->rowIsBasic(iRow)) {
+#if 0
+            // find column in row
+            int jCol=-1 ;
+            //for (CoinBigIndex j=mrstrt[iRow];j<mrstrt
+            for (int k=0;k<prob->ncols0_;k++) {
+              CoinBigIndex j=mcstrt[k] ;
+              for (int i=0;i<hincol[k];i++) {
+                if (hrow[k]==iRow) {
+                  break ;
+                }
+                k=link[k] ;
+              }
+            }
+#endif
+          } else {
+            prob->setColumnStatus(iCol,CoinPrePostsolveMatrix::basic) ;
+          }
+          prob->setRowStatusUsingValue(iRow) ;
+        } else {
+          //prob->setRowStatus(iRow,CoinPrePostsolveMatrix::basic) ;
+          prob->setColumnStatusUsingValue(iCol) ;
+        }
+      }
+    }
+#if 0
+    int nb=0 ;
+    int kk ;
+    for (kk=0;kk<prob->nrows_;kk++)
+      if (prob->rowIsBasic(kk))
+        nb++ ;
+    for (kk=0;kk<prob->ncols_;kk++)
+      if (prob->columnIsBasic(kk))
+        nb++ ;
+    assert (nb==prob->nrows_) ;
+#endif
+    // add new element
+    {
+      CoinBigIndex k = free_list ;
+      assert(k >= 0 && k < prob->bulk0_) ;
+      free_list = link[free_list] ;
+      hrow[k] = iRow ;
+      colels[k] = coeff ;
+      link[k] = mcstrt[iCol] ;
+      mcstrt[iCol] = k ;
+    }
+    hincol[iCol]++;	// right?
+#ifdef CHECK_ONE_ROW
+    {
+      double act=0.0 ;
+      for (int i=0;i<prob->ncols_;i++) {
+	double solV = sol[i] ;
+	assert (solV>=clo[i]-ztolzb&&solV<=cup[i]+ztolzb) ;
+	int j=mcstrt[i] ;
+	for (int k=0;k<hincol[i];k++) {
+	  if (hrow[j]==CHECK_ONE_ROW) {
+	    //printf("c %d el %g sol %g old act %g new %g\n",
+	    //   i,colels[j],solV,act, act+colels[j]*solV) ;
+	    act += colels[j]*solV ;
+	  }
+	  j=link[j] ;
+	}
+      }
+      assert (act>=rlo[CHECK_ONE_ROW]-ztolzb&&act<=rup[CHECK_ONE_ROW]+ztolzb) ;
+      printf("rhs now %g %g %g %g\n",rlo[CHECK_ONE_ROW],act,acts[CHECK_ONE_ROW],rup[CHECK_ONE_ROW]) ;
+    }
+#endif
+
+#   if PRESOLVE_DEBUG
+    rdone[iRow] = SLACK_SINGLETON ;
+#   endif
+  }
+
+# if PRESOLVE_DEBUG
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+  std::cout << "Leaving slack_singleton_action::postsolve." << std::endl ;
+# endif
+
+  return ; 
+}
+
diff --git a/cbits/coin/CoinPresolveSingleton.hpp b/cbits/coin/CoinPresolveSingleton.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveSingleton.hpp
@@ -0,0 +1,112 @@
+/* $Id: CoinPresolveSingleton.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveSingleton_H
+#define CoinPresolveSingleton_H
+#define	SLACK_DOUBLETON	2
+#define	SLACK_SINGLETON	8
+
+/*!
+  \file
+*/
+
+//const int MAX_SLACK_DOUBLETONS	= 1000;
+
+/*! \class slack_doubleton_action
+    \brief Convert an explicit bound constraint to a column bound
+
+  This transform looks for explicit bound constraints for a variable and
+  transfers the bound to the appropriate column bound array.
+  The constraint is removed from the constraint system.
+*/
+class slack_doubleton_action : public CoinPresolveAction {
+  struct action {
+    double clo;
+    double cup;
+
+    double rlo;
+    double rup;
+
+    double coeff;
+
+    int col;
+    int row;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  slack_doubleton_action(int nactions,
+			 const action *actions,
+			 const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions),
+    actions_(actions)
+{}
+
+ public:
+  const char *name() const { return ("slack_doubleton_action"); }
+
+  /*! \brief Convert explicit bound constraints to column bounds.
+  
+    Not now There is a hard limit (#MAX_SLACK_DOUBLETONS) on the number of
+    constraints processed in a given call. \p notFinished is set to true
+    if candidates remain.
+  */
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					   const CoinPresolveAction *next,
+					bool &notFinished);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+
+  virtual ~slack_doubleton_action() { deleteAction(actions_,action*); }
+};
+/*! \class slack_singleton_action
+    \brief For variables with one entry
+
+    If we have a variable with one entry and no cost then we can
+    transform the row from E to G etc.
+    If there is a row objective region then we may be able to do
+    this even with a cost.
+*/
+class slack_singleton_action : public CoinPresolveAction {
+  struct action {
+    double clo;
+    double cup;
+
+    double rlo;
+    double rup;
+
+    double coeff;
+
+    int col;
+    int row;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  slack_singleton_action(int nactions,
+			 const action *actions,
+			 const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions),
+    actions_(actions)
+{}
+
+ public:
+  const char *name() const { return ("slack_singleton_action"); }
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+                                            const CoinPresolveAction *next,
+                                            double * rowObjective);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+
+  virtual ~slack_singleton_action() { deleteAction(actions_,action*); }
+};
+#endif
diff --git a/cbits/coin/CoinPresolveSubst.cpp b/cbits/coin/CoinPresolveSubst.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveSubst.cpp
@@ -0,0 +1,1109 @@
+/* $Id: CoinPresolveSubst.cpp 1581 2013-04-06 12:48:50Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveEmpty.hpp"	// for DROP_COL/DROP_ROW
+#include "CoinPresolvePsdebug.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveZeros.hpp"
+#include "CoinPresolveSubst.hpp"
+#include "CoinMessage.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+#include "CoinFinite.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+
+namespace {	// begin unnamed file-local namespace
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+/*
+  Special-purpose debug utility to look for coefficient a(i,j) in column j.
+  Intended to be inserted as needed and removed when debugging is complete.
+*/
+void dbg_find_elem (const CoinPostsolveMatrix *postMtx, int i, int j)
+{
+  const CoinBigIndex kcs = postMtx->mcstrt_[j] ;
+  const CoinBigIndex lenj = postMtx->hincol_[j] ;
+  CoinBigIndex krow =
+    presolve_find_row3(i,kcs,lenj,postMtx->hrow_,postMtx->link_) ;
+  if (krow >= 0) {
+    std::cout
+      << "  row " << i << " present in column " << j 
+      << ", a(" << i << "," << j
+      << ") = " << postMtx->colels_[krow] << std::endl ;
+  } else {
+    std::cout
+      << "  row " << i << " not present in column " << j << std::endl ;
+  }
+}
+#endif
+
+/*
+  Add coeff_factor*rowy to rowx, for coefficients and row bounds. In the
+  terminology used in ::presolve, rowy is the target row, and rowx is an
+  entangled row (entangled with the target column).
+
+  If a coefficient is < kill_ratio * coeff_factor then kill it
+
+  Column indices in irowx and iroy must be sorted in increasing order.
+  Normally one might do that here, but this routine is only called from
+  subst_constraint_action::presolve and rowy will be the same over several
+  calls. More efficient to sort in sca::presolve.
+
+  Given we're called from sca::presolve, rowx will be an equality, with
+  finite rlo[rowx] = rup[rowx] = rhsy.
+
+  Fill-in in rowx has the potential to trigger compaction of the row-major
+  bulk store. *All* indices into the bulk store are *not* constant if this
+  happens.
+
+  Returns false if the addition completes without error, true if there's a
+  problem.
+*/
+bool add_row (CoinBigIndex *mrstrt, double *rlo, double *acts, double *rup,
+	     double *rowels, int *hcol, int *hinrow, presolvehlink *rlink,
+	      int nrows, double coeff_factor, double kill_ratio,  int irowx, int irowy,
+	     int *x_to_y)
+{
+  CoinBigIndex krsy = mrstrt[irowy] ;
+  CoinBigIndex krey = krsy+hinrow[irowy] ;
+  CoinBigIndex krsx = mrstrt[irowx] ;
+  CoinBigIndex krex = krsx+hinrow[irowx] ;
+
+# if PRESOLVE_DEBUG > 3
+  std::cout
+    << "  ADD_ROW: adding (" << coeff_factor << ")*(row " << irowy
+    << ") to row " << irowx << "; len y = " << hinrow[irowy]
+    << ", len x = " << hinrow[irowx] << "." << std::endl ;
+# endif
+
+/*
+  Do the simple part first: adjust the row lower and upper bounds, but only if
+  they're finite.
+*/
+  const double rhsy = rlo[irowy] ;
+  const double rhscorr = rhsy*coeff_factor ;
+  const double tolerance = kill_ratio*coeff_factor;
+
+  if (-PRESOLVE_INF < rlo[irowx]) {
+    const double newrlo = rlo[irowx]+rhscorr ;
+#   if PRESOLVE_DEBUG > 3
+    if (rhscorr)
+      std::cout
+        << "  rlo(" << irowx << ") " << rlo[irowx] << " -> "
+	<< newrlo << "." << std::endl ;
+#   endif
+    rlo[irowx] = newrlo ;
+  }
+  if (rup[irowx] < PRESOLVE_INF) {
+    const double newrup = rup[irowx]+rhscorr ;
+#   if PRESOLVE_DEBUG > 3
+    if (rhscorr)
+      std::cout
+        << "  rup(" << irowx << ") " << rup[irowx] << " -> "
+	<< newrup << "." << std::endl ;
+#   endif
+    rup[irowx] = newrup ;
+  }
+  if (acts)
+  { acts[irowx] += rhscorr ; }
+/*
+  On to the main show. Open a loop to walk row y.  krowx is keeping track
+  of where we're at in row x.  To find column j in row x, start from the
+  current position and search forward, but no further than the last original
+  coefficient of row x (fill will be added after this element).
+*/
+  CoinBigIndex krowx = krsx ;
+  CoinBigIndex krex0 = krex ;
+  int x_to_y_i = 0 ;
+
+# if PRESOLVE_DEBUG > 3
+  std::cout << "  ycols:" ;
+# endif
+  for (CoinBigIndex krowy = krsy ; krowy < krey ; krowy++) {
+    int j = hcol[krowy] ;
+
+    PRESOLVEASSERT(krex == krsx+hinrow[irowx]) ;
+
+    while (krowx < krex0 && hcol[krowx] < j) krowx++ ;
+
+#   if PRESOLVE_DEBUG > 3
+    std::cout << " a(" << irowx << "," << j << ") " ;
+#   endif
+/*
+  The easy case: coeff a(xj) already exists and all we need to is modify it.
+*/
+    if (krowx < krex0 && hcol[krowx] == j) {
+      double newcoeff = rowels[krowx]+rowels[krowy]*coeff_factor ;
+
+#     if PRESOLVE_DEBUG > 3
+      std::cout << rowels[krowx] << " -> " << newcoeff << ";" ;
+#     endif
+
+      // kill small 
+      if (fabs(newcoeff) <tolerance) 
+	newcoeff=0.0;
+      rowels[krowx] = newcoeff ;
+      x_to_y[x_to_y_i++] = krowx-krsx ;
+      krowx++ ;
+    } else {
+/*
+  The hard case: a(xj) will be fill-in for row x. Make sure we have room. The
+  process of making room can trigger bulk store compaction which can move all
+  rows, so recalculate all pointers into the bulk store. Only then can we add
+  the new coefficient.
+*/
+      double newValue = rowels[krowy]*coeff_factor ;
+      bool outOfSpace = presolve_expand_row(mrstrt,rowels,hcol,
+					    hinrow,rlink,nrows,irowx) ;
+      if (outOfSpace) return (true) ;
+      
+      krowy = mrstrt[irowy]+(krowy-krsy) ;
+      krsy = mrstrt[irowy] ;
+      krey = krsy+hinrow[irowy] ;
+      
+      krowx = mrstrt[irowx]+(krowx-krsx) ;
+      krex0 = mrstrt[irowx]+(krex0-krsx) ;
+      krsx = mrstrt[irowx] ;
+      krex = krsx+hinrow[irowx] ;
+      
+      hcol[krex] = j ;
+      rowels[krex] = newValue;
+      x_to_y[x_to_y_i++] = krex-krsx ;
+      hinrow[irowx]++ ;
+      krex++ ;
+      
+#     if PRESOLVE_DEBUG > 3
+      std::cout << rowels[krex-1] << ";" ;
+#     endif
+    }
+  }
+
+# if PRESOLVE_DEBUG > 3
+  std::cout << std::endl ;
+# endif
+  return (false) ;
+}
+
+
+
+} // end unnamed file-local namespace
+
+
+const char *subst_constraint_action::name() const
+{
+  return ("subst_constraint_action");
+}
+
+/*
+  This transform is called only from implied_free_action. See the comments at
+  the head of CoinPresolveImpledFree.cpp for background.
+
+  In addition to natural implied free singletons, implied_free_action will
+  identify implied free variables that are not (yet) column singletons. This
+  transform will process them.
+
+  Suppose we have a variable x(t) and an equality r which satisfy the implied
+  free condition (i.e., r imposes bounds on x(t) which are equal or better
+  than the original column bounds). Then we can solve r for x(t) to get a
+  substitution formula for x(t). We can use the substitution formula to
+  eliminate x(t) from all other constraints where it is entangled. x(t) is now
+  an implied free column singleton with equality r and we can remove x(t)
+  and equality r from the constraint system.
+
+  The paired parameter vectors implied_free and whichFree specify the indices
+  for equality r and variable t, respectively. NOTE that these vectors are
+  held in the first two blocks of usefulColumnInt_. Don't reuse them!
+
+  Fill-in can cause a major vector to be moved to free space at the end
+  of the bulk store. If there's not enough free space, this can trigger
+  compaction of the entire bulk store. The upshot is that *all* major vector
+  starts and ends are *not* constant over calls that could expand a major
+  vector. Deletion, on the other hand, will never move a major vector (but
+  it will move the end element into the hole left by the deleted element).
+*/
+
+const CoinPresolveAction *subst_constraint_action::presolve (
+    CoinPresolveMatrix *prob,
+    const int *implied_free, const int *whichFree, int numberFree,
+    const CoinPresolveAction *next, int maxLook)
+{
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering subst_constraint_action::presolve, fill level "
+    << maxLook << ", " << numberFree << " candidates." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int startEmptyRows = 0 ;
+  int startEmptyColumns = 0 ;
+  startEmptyRows = prob->countEmptyRows() ;
+  startEmptyColumns = prob->countEmptyCols() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0 ;
+  if (prob->tuning_) startTime = CoinCpuTime() ;
+# endif
+# endif
+
+/*
+  Unpack the row- and column-major representations.
+*/
+  const int ncols = prob->ncols_ ;
+  const int nrows = prob->nrows_ ;
+
+  CoinBigIndex *rowStarts = prob->mrstrt_ ;
+  int *rowLengths = prob->hinrow_ ;
+  double *rowCoeffs = prob->rowels_ ;
+  int *colIndices = prob->hcol_ ;
+  presolvehlink *rlink = prob->rlink_ ;
+
+  CoinBigIndex *colStarts = prob->mcstrt_ ;
+  int *colLengths = prob->hincol_ ;
+  double *colCoeffs = prob->colels_ ;
+  int *rowIndices = prob->hrow_ ;
+  presolvehlink *clink = prob->clink_ ;
+
+/*
+  Row bounds and activity, objective.
+*/
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+  double *acts = prob->acts_ ;
+  double *cost = prob->cost_ ;
+
+
+  const double tol = prob->feasibilityTolerance_ ;
+
+  action *actions = new action [ncols] ;
+# ifdef ZEROFAULT
+  CoinZeroN(reinterpret_cast<char *>(actions),ncols*sizeof(action)) ;
+# endif
+  int nactions = 0 ;
+/*
+  This array is used to hold the indices of columns involved in substitutions,
+  where we have the potential for cancellation. At the end they'll be
+  checked to eliminate any actual zeros that may result. At the end of
+  processing of each target row, the column indices of the target row are
+  copied into zerocols.
+
+  NOTE that usefulColumnInt_ is already in use for parameters implied_free and
+  whichFree when this routine is called from implied_free.
+*/
+  int *zerocols = new int[ncols] ;
+  int nzerocols = 0 ;
+
+  int *x_to_y = new int[ncols] ;
+
+  int *rowsUsed = &prob->usefulRowInt_[0] ;
+  int nRowsUsed = 0 ;
+/*
+  Open a loop to process the (equality r, implied free variable t) pairs
+  in whichFree and implied_free.
+
+  It can happen that removal of (row, natural singleton) pairs back in
+  implied_free will reduce the length of column t. It can also happen
+  that previous processing here has resulted in fillin or cancellation. So
+  check again for column length and exclude natural singletons and overly
+  dense columns.
+*/
+  for (int iLook = 0 ; iLook < numberFree ; iLook++) {
+    const int tgtcol = whichFree[iLook] ;
+    const int tgtcol_len = colLengths[tgtcol] ;
+    const int tgtrow = implied_free[iLook] ;
+    const int tgtrow_len = rowLengths[tgtrow] ;
+
+    assert(fabs(rlo[tgtrow]-rup[tgtrow]) < tol) ;
+
+    if (colLengths[tgtcol] < 2 || colLengths[tgtcol] > maxLook) {
+#     if PRESOLVE_DEBUG > 3
+      std::cout
+        << "    skipping eqn " << tgtrow << " x(" << tgtcol
+	<< "); length now " << colLengths[tgtcol] << "." << std::endl ;
+#     endif
+      continue ;
+    }
+
+    CoinBigIndex tgtcs = colStarts[tgtcol] ;
+    CoinBigIndex tgtce = tgtcs+colLengths[tgtcol] ;
+/*
+  A few checks to make sure that the candidate pair is still suitable.
+  Processing candidates earlier in the list can eliminate coefficients.
+    * Don't use this pair if any involved row i has become a row singleton
+      or empty.
+    * Don't use this pair if any involved row has been modified as part of
+      the processing for a previous candidate pair on this call.
+    * Don't use this pair if a(i,tgtcol) has become zero.
+
+  The checks on a(i,tgtcol) seem superfluous but it's possible that
+  implied_free identified two candidate pairs to eliminate the same column. If
+  we've already processed one of them, we could be in trouble.
+*/
+    double tgtcoeff = 0.0 ;
+    bool dealBreaker = false ;
+    for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
+      const int i = rowIndices[kcol] ;
+      if (rowLengths[i] < 2 || prob->rowUsed(i)) {
+        dealBreaker = true ;
+	break ;
+      }
+      const double aij = colCoeffs[kcol] ;
+      if (fabs(aij) <= ZTOLDP2) {
+	dealBreaker = true ;
+	break ;
+      }
+      if (i == tgtrow) tgtcoeff = aij ;
+    }
+
+    if (dealBreaker == true) {
+#     if PRESOLVE_DEBUG > 3
+      std::cout
+        << "    skipping eqn " << tgtrow << " x(" << tgtcol
+	<< "); deal breaker (1)." << std::endl ;
+#     endif
+      continue ;
+    }
+/*
+  Check for numerical stability.A large coeff_factor will inflate the
+  coefficients in the substitution formula.
+*/
+    dealBreaker = false ;
+    for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
+      const double coeff_factor = fabs(colCoeffs[kcol]/tgtcoeff) ;
+      if (coeff_factor > 10.0)
+	dealBreaker = true ;
+    }
+/*
+  Given enough target rows with sufficient overlap, there's an outside chance
+  we could overflow zerocols. Unlikely to ever happen.
+*/
+    if (!dealBreaker && nzerocols+rowLengths[tgtrow] >= ncols)
+      dealBreaker = true ;
+    if (dealBreaker == true) {
+#     if PRESOLVE_DEBUG > 3
+      std::cout
+        << "    skipping eqn " << tgtrow << " x(" << tgtcol
+	<< "); deal breaker (2)." << std::endl ;
+#     endif
+      continue ;
+    }
+/*
+  If c(t) != 0, we will need to modify the objective coefficients and remember
+  the original objective.
+*/
+    const bool nonzero_cost = (fabs(cost[tgtcol]) > tol) ;
+    double *costsx = (nonzero_cost?new double[rowLengths[tgtrow]]:0) ;
+
+#   if PRESOLVE_DEBUG > 1
+    std::cout << "  Eliminating row " << tgtrow << ", col " << tgtcol ;
+    if (nonzero_cost) std::cout << ", cost " << cost[tgtcol] ;
+    std::cout << "." << std::endl ;
+#   endif
+
+/*
+  Count up the total number of coefficients in entangled rows and mark them as
+  contaminated.
+*/
+    int ntotels = 0 ;
+    for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
+      const int i = rowIndices[kcol] ;
+      ntotels += rowLengths[i] ;
+      PRESOLVEASSERT(!prob->rowUsed(i)) ;
+      prob->setRowUsed(i) ;
+      rowsUsed[nRowsUsed++] = i ;
+    }
+/*
+  Create the postsolve object. Copy in all the affected rows. Take the
+  opportunity to mark the entangled rows as changed and put them on the list
+  of rows to process in the next round.
+
+  coeffxs in particular holds the coefficients of the target column.
+*/
+    action *ap = &actions[nactions++] ;
+
+    ap->col = tgtcol ;
+    ap->rowy = tgtrow ;
+    PRESOLVE_DETAIL_PRINT(printf("pre_subst %dC %dR E\n",tgtcol,tgtrow)) ;
+
+    ap->nincol = tgtcol_len ;
+    ap->rows = new int[tgtcol_len] ;
+    ap->rlos = new double[tgtcol_len] ;
+    ap->rups = new double[tgtcol_len] ;
+
+    ap->costsx = costsx ;
+    ap->coeffxs = new double[tgtcol_len] ;
+
+    ap->ninrowxs = new int[tgtcol_len] ;
+    ap->rowcolsxs = new int[ntotels] ;
+    ap->rowelsxs = new double[ntotels] ;
+
+    ntotels = 0 ;
+    for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) {
+      const int ndx = kcol-tgtcs ;
+      const int i = rowIndices[kcol] ;
+      const CoinBigIndex krs = rowStarts[i] ;
+      prob->addRow(i) ;
+      ap->rows[ndx] = i ;
+      ap->ninrowxs[ndx] = rowLengths[i] ;
+      ap->rlos[ndx] = rlo[i] ;
+      ap->rups[ndx] = rup[i] ;
+      ap->coeffxs[ndx] = colCoeffs[kcol] ;
+
+      CoinMemcpyN(&colIndices[krs],rowLengths[i],&ap->rowcolsxs[ntotels]) ;
+      CoinMemcpyN(&rowCoeffs[krs],rowLengths[i],&ap->rowelsxs[ntotels]) ;
+
+      ntotels += rowLengths[i] ;
+    }
+
+    CoinBigIndex tgtrs = rowStarts[tgtrow] ;
+    CoinBigIndex tgtre = tgtrs+rowLengths[tgtrow] ;
+
+/*
+  Adjust the objective coefficients based on the substitution formula
+    c'(j) = c(j) - a(rj)c(t)/a(rt)
+*/
+    if (nonzero_cost) {
+      const double tgtcost = cost[tgtcol] ;
+      for (CoinBigIndex krow = tgtrs ; krow < tgtre ; krow ++) {
+	const int j = colIndices[krow] ;
+	prob->addCol(j) ;
+	costsx[krow-tgtrs] = cost[j] ;
+	double coeff = rowCoeffs[krow] ;
+	cost[j] -= (tgtcost*coeff)/tgtcoeff ;
+      }
+      prob->change_bias(tgtcost*rlo[tgtrow]/tgtcoeff) ;
+      cost[tgtcol] = 0.0 ;
+    }
+
+#   if PRESOLVE_DEBUG > 1
+    std::cout << "  tgt (" << tgtrow << ") (" << tgtrow_len << "): " ;
+    for (CoinBigIndex krow = tgtrs ; krow < tgtre ; ++krow) {
+      const int j = colIndices[krow] ;
+      const double arj = rowCoeffs[krow] ;
+      std::cout
+	<< "x(" << j << ") = " << arj << " (" << colLengths[j] << ") " ;
+    }
+    std::cout << std::endl ;
+#   endif
+
+/*
+  Sort the target row for efficiency when doing elimination.
+*/
+      CoinSort_2(colIndices+tgtrs,colIndices+tgtre,rowCoeffs+tgtrs) ;
+/*
+  Get down to the business of substituting for tgtcol in the entangled rows.
+  Open a loop to walk the target column. We walk the saved column because the
+  bulk store can change as we work. We don't want to repeat or miss a row.
+*/
+    for (int colndx = 0 ; colndx < tgtcol_len ; ++colndx) {
+      int i = ap->rows[colndx] ;
+      if (i == tgtrow) continue ;
+
+      double ait = ap->coeffxs[colndx] ;
+      double coeff_factor = -ait/tgtcoeff ;
+      
+      CoinBigIndex krs = rowStarts[i] ;
+      CoinBigIndex kre = krs+rowLengths[i] ;
+
+#     if PRESOLVE_DEBUG > 1
+      std::cout
+	<< "  subst pre (" << i << ") (" << rowLengths[i] << "): " ;
+      for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
+	const int j = colIndices[krow] ;
+	const double aij = rowCoeffs[krow] ;
+	std::cout
+	  << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ;
+      }
+      std::cout << std::endl ;
+#     endif
+
+/*
+  Sort the row for efficiency and call add_row to do the actual business of
+  changing coefficients due to substitution. This has the potential to trigger
+  compaction of the row-major bulk store, so update bulk store indices.
+*/
+      CoinSort_2(colIndices+krs,colIndices+kre,rowCoeffs+krs) ;
+      // kill small if wanted
+      double tolerance = ((prob->presolveOptions()&0x20000)!=0) ?
+	1.0e-9*coeff_factor : 1.0e-12*coeff_factor;
+      
+      bool outOfSpace = add_row(rowStarts,rlo,acts,rup,rowCoeffs,colIndices,
+				rowLengths,rlink,nrows,coeff_factor,tolerance,i,tgtrow,
+				x_to_y) ;
+      if (outOfSpace)
+	throwCoinError("out of memory","CoinImpliedFree::presolve") ;
+
+      krs = rowStarts[i] ;
+      kre = krs+rowLengths[i] ;
+      tgtrs = rowStarts[tgtrow] ;
+      tgtre = tgtrs+rowLengths[tgtrow] ;
+
+#     if PRESOLVE_DEBUG > 1
+      std::cout
+	<< "  subst aft (" << i << ") (" << rowLengths[i] << "): " ;
+      for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
+	const int j = colIndices[krow] ;
+	const double aij = rowCoeffs[krow] ;
+	std::cout
+	  << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ;
+      }
+      std::cout << std::endl ;
+#     endif
+
+/*
+  Now update the column-major representation from the row-major
+  representation. This is easy if the coefficient already exists, but
+  painful if there's fillin. presolve_find_row1 will return the index of
+  the row in the column vector, or one past the end if it's missing. If the
+  coefficient is fill, presolve_expand_col will make sure that there's room in
+  the column for one more coefficient. This may require that the column be
+  moved in the bulk store, so we need to update kcs and kce.
+
+  Once we're done, a(it) = 0 (i.e., we've eliminated x(t) from row i).
+  Physically remove the explicit zero from the row-major representation
+  with presolve_delete_from_row.
+*/
+      for (CoinBigIndex rowndx = 0 ; rowndx < tgtrow_len ; ++rowndx) {
+	const CoinBigIndex ktgt = tgtrs+rowndx ;
+	const int j = colIndices[ktgt] ;
+	CoinBigIndex kcs = colStarts[j] ;
+	CoinBigIndex kce = kcs+colLengths[j] ;
+
+	assert(colIndices[krs+x_to_y[rowndx]] == j) ;
+
+	const double coeff = rowCoeffs[krs+x_to_y[rowndx]] ;
+
+	CoinBigIndex kcol = presolve_find_row1(i,kcs,kce,rowIndices) ;
+	
+	if (kcol < kce) {
+	  colCoeffs[kcol] = coeff ;
+	} else {
+	  outOfSpace = presolve_expand_col(colStarts,colCoeffs,rowIndices,
+	  				   colLengths,clink,ncols,j) ;
+	  if (outOfSpace)
+	    throwCoinError("out of memory","CoinImpliedFree::presolve") ;
+	  kcs = colStarts[j] ;
+	  kce = kcs+colLengths[j] ;
+	  
+	  rowIndices[kce] = i ;
+	  colCoeffs[kce] = coeff ;
+	  colLengths[j]++ ;
+	}
+      }
+      presolve_delete_from_row(i,tgtcol,
+      			       rowStarts,rowLengths,colIndices,rowCoeffs) ;
+#     if PRESOLVE_DEBUG > 1
+      kre-- ;
+      std::cout
+	<< "  subst fin (" << i << ") (" << rowLengths[i] << "): " ;
+      for (CoinBigIndex krow = krs ; krow < kre ; ++krow) {
+	const int j = colIndices[krow] ;
+	const double aij = rowCoeffs[krow] ;
+	std::cout
+	  << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ;
+      }
+      std::cout << std::endl ;
+#     endif
+      
+    }
+/*
+  End of the substitution loop.
+
+  Record the column indices of the target row so we can groom these columns
+  later to remove possible explicit zeros.
+*/
+    CoinMemcpyN(&colIndices[rowStarts[tgtrow]],rowLengths[tgtrow],
+    		&zerocols[nzerocols]) ;
+    nzerocols += rowLengths[tgtrow] ;
+/*
+  Remove the target equality from the column- and row-major representations
+  Somewhat painful in the colum-major representation.  We have to walk the
+  target row in the row-major representation and look up each coefficient
+  in the column-major representation.
+*/
+    for (CoinBigIndex krow = tgtrs ; krow < tgtre ; ++krow) {
+      const int j = colIndices[krow] ;
+#     if PRESOLVE_DEBUG > 1
+      std::cout
+        << "  removing row " << tgtrow << " from col " << j << std::endl ;
+#     endif
+      presolve_delete_from_col(tgtrow,j,
+      			       colStarts,colLengths,rowIndices,colCoeffs) ;
+      if (colLengths[j] == 0) {
+        PRESOLVE_REMOVE_LINK(clink,j) ;
+      }
+    }
+/*
+  Finally, physically remove the column from the column-major representation
+  and the row from the row-major representation.
+*/
+    PRESOLVE_REMOVE_LINK(clink, tgtcol) ;
+    colLengths[tgtcol] = 0 ;
+
+    PRESOLVE_REMOVE_LINK(rlink, tgtrow) ;
+    rowLengths[tgtrow] = 0 ;
+
+    rlo[tgtrow] = 0.0 ;
+    rup[tgtrow] = 0.0 ;
+
+#   if PRESOLVE_CONSISTENCY > 0
+    presolve_links_ok(prob) ;
+    presolve_consistent(prob) ;
+#   endif
+
+  }
+/*
+  That's it, we've processed all the candidate pairs.
+
+  Clear the row used flags.
+*/
+  for (int i = 0 ; i < nRowsUsed ; i++) prob->unsetRowUsed(rowsUsed[i]) ;
+/*
+  Trim the array of substitution transforms and queue up objects for postsolve.
+  Also groom the problem representation to remove explicit zeros.
+*/
+  if (nactions) {
+#   if PRESOLVE_SUMMARY > 0
+    std::cout << "NSUBSTS: " << nactions << std::endl ;
+#   endif
+    next = new subst_constraint_action(nactions,
+				   CoinCopyOfArray(actions,nactions),next) ;
+    next = drop_zero_coefficients_action::presolve(prob,zerocols,
+    						   nzerocols, next) ;
+#   if PRESOLVE_CONSISTENCY > 0
+    presolve_links_ok(prob) ;
+    presolve_consistent(prob) ;
+#   endif
+  }
+
+  deleteAction(actions,action*) ;
+  delete [] x_to_y ;
+  delete [] zerocols ;
+
+# if COIN_PRESOLVE_TUNING > 0
+  if (prob->tuning_) double thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_sol(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving subst_constraint_action::presolve, "
+    << droppedRows << " rows, " << droppedColumns << " columns dropped" ;
+# if COIN_PRESOLVE_TUNING > 0
+  std::cout << " in " << thisTime-startTime << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+
+/*
+  Undo the substitutions from presolve and reintroduce the target constraint
+  and column.
+*/
+void subst_constraint_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering subst_constraint_action::postsolve, "
+    << nactions_ << " constraints to process." << std::endl ;
+# endif
+  int ncols = prob->ncols_ ;
+  char *cdone = prob->cdone_ ;
+  char *rdone = prob->rdone_ ;
+  const double ztolzb = prob->ztolzb_ ;
+
+  presolve_check_threads(prob) ;
+  presolve_check_free_list(prob) ;
+  presolve_check_reduced_costs(prob) ;
+  presolve_check_duals(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+/*
+  Unpack the column-major representation.
+*/
+  CoinBigIndex *colStarts = prob->mcstrt_ ;
+  int *colLengths = prob->hincol_ ;
+  int *rowIndices = prob->hrow_ ;
+  double *colCoeffs = prob->colels_ ;
+/*
+  Rim vectors, solution, reduced costs, duals, row activity.
+*/
+  double *rlo = prob->rlo_ ;
+  double *rup = prob->rup_ ;
+  double *cost = prob->cost_ ;
+  double *sol = prob->sol_ ;
+  double *rcosts = prob->rcosts_ ;
+  double *acts = prob->acts_ ;
+  double *rowduals = prob->rowduals_ ;
+
+  CoinBigIndex *link = prob->link_ ;
+  CoinBigIndex &free_list = prob->free_list_ ;
+
+  const double maxmin = prob->maxmin_ ;
+
+  const action *const actions = actions_ ;
+  const int nactions = nactions_ ;
+
+/*
+  Open the main loop to step through the postsolve objects.
+
+  First activity is to unpack the postsolve object. We have the target
+  column and row indices, the full target column, and complete copies of
+  all entangled rows (column indices, coefficients, lower and upper bounds).
+  There may be a vector of objective coefficients which we'll get to later.
+*/
+  for (const action *f = &actions[nactions-1] ; actions <= f ; f--) {
+    const int tgtcol = f->col ;
+    const int tgtrow = f->rowy ;
+
+    const int tgtcol_len = f->nincol ;
+    const double *tgtcol_coeffs = f->coeffxs ;
+
+    const int *entngld_rows = f->rows ;
+    const int *entngld_lens = f->ninrowxs ;
+    const int *entngld_colndxs = f->rowcolsxs ;
+    const double *entngld_colcoeffs = f->rowelsxs ;
+    const double *entngld_rlos = f->rlos ;
+    const double *entngld_rups = f->rups ;
+    const double *costs = f->costsx ;
+
+#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#   if PRESOLVE_DEBUG > 1
+    std::cout
+      << "  reintroducing column x(" << tgtcol << ") and row " << tgtrow ;
+      if (costs) std::cout << ", nonzero costs" ;
+      std::cout << "." << std::endl ;
+#   endif
+/*
+  We're about to reintroduce the target row and column; empty stubs should be
+  present. All other rows should already be present.
+*/
+    PRESOLVEASSERT(cdone[tgtcol] == DROP_COL) ;
+    PRESOLVEASSERT(colLengths[tgtcol] == 0) ;
+    PRESOLVEASSERT(rdone[tgtrow] == DROP_ROW) ;
+    for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
+      if (entngld_rows[cndx] != tgtrow)
+	PRESOLVEASSERT(rdone[entngld_rows[cndx]]) ;
+    }
+/*
+  In a postsolve matrix, we can't just check that the length of the row is
+  zero. We need to look at all columns and confirm its absence.
+*/
+    for (int j = 0 ; j < ncols ; ++j) {
+      if (colLengths[j] > 0 && cdone[j]) {
+        const CoinBigIndex kcs = colStarts[j] ;
+        const int lenj = colLengths[j] ;
+	CoinBigIndex krow =
+	  presolve_find_row3(tgtrow,kcs,lenj,rowIndices,link) ;
+	if (krow >= 0) {
+	  std::cout
+	    << "  BAD COEFF! row " << tgtrow << " present in column " << j
+	    << " before reintroduction; a(" << tgtrow << "," << j
+	    << ") = " << colCoeffs[krow] << "; x(" << j << ") = " << sol[j]
+	    << "; cdone " << static_cast<int>(cdone[j]) << "." << std::endl ;
+	}
+      }
+    }
+#   endif
+
+/*
+  Find the copy of the target row. Restore the upper and lower bounds
+  of entangled rows while we're looking. Recall that the target row is
+  an equality.
+*/
+    int tgtrow_len = -1 ;
+    const int *tgtrow_colndxs = NULL ;
+    const double *tgtrow_coeffs = NULL ;
+    double tgtcoeff = 0.0 ;
+    double tgtrhs = 1.0e50 ;
+
+    int nel = 0 ;
+    for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
+      int i = entngld_rows[cndx] ;
+      rlo[i] = entngld_rlos[cndx] ;
+      rup[i] = entngld_rups[cndx] ;
+      if (i == tgtrow) {
+	tgtrow_len = entngld_lens[cndx] ;
+	tgtrow_colndxs = &entngld_colndxs[nel] ;
+	tgtrow_coeffs  = &entngld_colcoeffs[nel] ;
+	tgtcoeff = tgtcol_coeffs[cndx] ;
+	tgtrhs = rlo[i] ;
+      }
+      nel += entngld_lens[cndx] ;
+    }
+/*
+  Solve the target equality to find the solution for the eliminated col.
+  tgtcol is present in tgtrow_colndxs, so initialise sol[tgtcol] to zero
+  to make sure it doesn't contribute.
+
+  If we're debugging, check that the result is within bounds.
+*/
+    double tgtexp = tgtrhs ;
+    sol[tgtcol] = 0.0 ;
+    for (int ndx = 0 ; ndx < tgtrow_len ; ++ndx) {
+      int j = tgtrow_colndxs[ndx] ;
+      double coeffj = tgtrow_coeffs[ndx] ;
+      tgtexp -= coeffj*sol[j] ;
+    }
+    sol[tgtcol] = tgtexp/tgtcoeff ;
+
+#   if PRESOLVE_DEBUG > 0
+    double *clo = prob->clo_ ;
+    double *cup = prob->cup_ ;
+
+    if (!(sol[tgtcol] > (clo[tgtcol]-ztolzb) &&
+	  (cup[tgtcol]+ztolzb) > sol[tgtcol])) {
+      std::cout
+	<< "BAD SOL: x(" << tgtcol << ") " << sol[tgtcol]
+	<< "; lb " << clo[tgtcol] << "; ub " << cup[tgtcol] << "."
+	<< std::endl ;
+    }
+#   endif
+/*
+  Now restore the original entangled rows. We first delete any columns present
+  in tgtrow. This will remove any fillin, but may also remove columns that
+  were originally present in both the entangled row and the target row.
+
+  Note that even cancellations (explicit zeros) are present at this
+  point --- in presolve, they were removed after the substition transform
+  completed, hence they're already restored. What isn't present is the target
+  column, which is deleted as part of the transform.
+*/
+    {
+#     if PRESOLVE_DEBUG > 2
+      std::cout << "    removing coefficients:" ;
+#     endif
+      for (int rndx = 0 ; rndx < tgtrow_len ; ++rndx) {
+	int j = tgtrow_colndxs[rndx] ;
+	if (j != tgtcol)
+	  for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
+	    if (entngld_rows[cndx] != tgtrow) {
+#             if PRESOLVE_DEBUG > 2
+	      std::cout << " a(" << entngld_rows[cndx] << "," << j << ")" ;
+#             endif
+	      presolve_delete_from_col2(entngld_rows[cndx],j,colStarts,
+				      colLengths,rowIndices,link,&free_list) ;
+	    }
+	  }
+      }
+#     if PRESOLVE_DEBUG > 2
+      std::cout << std::endl ;
+#     endif
+#     if PRESOLVE_CONSISTENCY > 0
+      presolve_check_threads(prob) ;
+      presolve_check_free_list(prob) ;
+#     endif
+/*
+  Next we restore the original coefficients. The outer loop walks tgtcol;
+  cols_i and coeffs_i are advanced as we go to point to each entangled
+  row. The inner loop walks the entangled row and restores the row's
+  coefficients. Tgtcol is handled as any other column. Skip tgtrow, we'll
+  do it below.
+
+  Since we don't have a row-major representation, we have to look for a(i,j)
+  from entangled row i in the existing column j. If we find a(i,j), simply
+  update it (and a(tgtrow,j) should not exist). If we don't find a(i,j),
+  introduce it (and a(tgtrow,j) should exist).
+
+  Recalculate the row activity while we're at it.
+*/
+#     if PRESOLVE_DEBUG > 2
+      std::cout << "    restoring coefficients:" ;
+#     endif
+
+      colLengths[tgtcol] = 0 ;
+      const int *cols_i = entngld_colndxs ;
+      const double *coeffs_i = entngld_colcoeffs ;
+
+      for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
+	const int leni = entngld_lens[cndx] ;
+	const int i = entngld_rows[cndx] ;
+
+	if (i != tgtrow) {
+	  double acti = 0.0 ;
+	  for (int rndx = 0 ; rndx < leni ; ++rndx) {
+	    const int j = cols_i[rndx] ;
+	    CoinBigIndex kcoli =
+	      presolve_find_row3(i,colStarts[j],
+	      			 colLengths[j],rowIndices,link) ;
+	    if (kcoli != -1) {
+#             if PRESOLVE_DEBUG > 2
+	      std::cout << " u a(" << i << "," << j << ")" ;
+	      PRESOLVEASSERT(presolve_find_col1(j,0,tgtrow_len,
+	      					tgtrow_colndxs) == tgtrow_len) ;
+#	      endif
+	      colCoeffs[kcoli] = coeffs_i[rndx] ;
+	    } else {
+#             if PRESOLVE_DEBUG > 2
+	      std::cout << " f a(" << i << "," << j << ")" ;
+	      PRESOLVEASSERT(presolve_find_col1(j,0,tgtrow_len,
+						tgtrow_colndxs) < tgtrow_len) ;
+#	      endif
+	      CoinBigIndex kk = free_list ;
+	      assert(kk >= 0 && kk < prob->bulk0_) ;
+	      free_list = link[free_list] ;
+	      link[kk] = colStarts[j] ;
+	      colStarts[j] = kk ;
+	      colCoeffs[kk] = coeffs_i[rndx] ;
+	      rowIndices[kk] = i ;
+	      ++colLengths[j] ;
+	    }
+	    acti += coeffs_i[rndx]*sol[j] ;
+	  }
+	  acts[i] = acti ;
+	}
+	cols_i += leni ;
+	coeffs_i += leni ;
+      }
+#     if PRESOLVE_DEBUG > 2
+      std::cout << std::endl ;
+#     endif
+#     if PRESOLVE_CONSISTENCY > 0
+      presolve_check_threads(prob) ;
+      presolve_check_free_list(prob) ;
+#     endif
+/*
+  Restore tgtrow. Arguably we could to this in the previous loop, but we'd do
+  a lot of unnecessary work. By construction, the target row is tight.
+*/
+#     if PRESOLVE_DEBUG > 2
+      std::cout << "    restoring row " << tgtrow << ":" ;
+#     endif
+
+      for (int rndx = 0 ; rndx < tgtrow_len ; ++rndx) {
+	int j = tgtrow_colndxs[rndx] ;
+#       if PRESOLVE_DEBUG > 2
+	std::cout << " a(" << tgtrow << "," << j << ")" ;
+#       endif
+	CoinBigIndex kk = free_list ;
+	assert(kk >= 0 && kk < prob->bulk0_) ;
+	free_list = link[free_list] ;
+	link[kk] = colStarts[j] ;
+	colStarts[j] = kk ;
+	colCoeffs[kk] = tgtrow_coeffs[rndx] ;
+	rowIndices[kk] = tgtrow ;
+	++colLengths[j] ;
+      }
+      acts[tgtrow] = tgtrhs ;
+
+#     if PRESOLVE_DEBUG > 2
+      std::cout << std::endl ;
+#     endif
+#     if PRESOLVE_CONSISTENCY > 0
+      presolve_check_threads(prob) ;
+      presolve_check_free_list(prob) ;
+#     endif
+    }
+/*
+  Restore original cost coefficients, if necessary.
+*/
+    if (costs) {
+      for (int ndx = 0 ; ndx < tgtrow_len ; ++ndx) {
+	cost[tgtrow_colndxs[ndx]] = costs[ndx] ;
+      }
+    }
+/*
+  Calculate the reduced cost for the column absent any contribution from
+  tgtrow, then set the dual for tgtrow so that the reduced cost of tgtcol
+  is zero.
+*/
+    double dj = maxmin*cost[tgtcol] ;
+    rowduals[tgtrow] = 0.0 ;
+    for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
+      int i = entngld_rows[cndx] ;
+      double coeff = tgtcol_coeffs[cndx] ;
+      dj -= rowduals[i]*coeff ;
+    }
+    rowduals[tgtrow] = dj/tgtcoeff ;
+    rcosts[tgtcol] = 0.0 ;
+    if (rowduals[tgtrow] > 0)
+      prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atUpperBound) ;
+    else
+      prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atLowerBound) ;
+    prob->setColumnStatus(tgtcol,CoinPrePostsolveMatrix::basic) ;
+
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  row " << tgtrow << " "
+      << prob->rowStatusString(prob->getRowStatus(tgtrow))
+      << " dual " << rowduals[tgtrow] << std::endl ;
+    std::cout
+      << "  col " << tgtcol << " "
+      << prob->columnStatusString(prob->getColumnStatus(tgtcol))
+      << " dj " << dj << std::endl ;
+#   endif
+
+#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+    cdone[tgtcol] = SUBST_ROW ;
+    rdone[tgtrow] = SUBST_ROW ;
+#   endif
+  }
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_threads(prob) ;
+  presolve_check_free_list(prob) ;
+  presolve_check_reduced_costs(prob) ;
+  presolve_check_duals(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving subst_constraint_action::postsolve." << std::endl ;
+# endif
+# endif
+
+  return ;
+}
+
+
+/*
+  Next time someone builds this code on Windows, check to see if deleteAction
+  is still necessary.   -- lh, 121114 --
+*/
+subst_constraint_action::~subst_constraint_action()
+{
+  const action *actions = actions_ ;
+
+  for (int i = 0 ; i < nactions_ ; ++i) {
+    delete [] actions[i].rows ;
+    delete [] actions[i].rlos ;
+    delete [] actions[i].rups ;
+    delete [] actions[i].coeffxs ;
+    delete [] actions[i].ninrowxs ;
+    delete [] actions[i].rowcolsxs ;
+    delete [] actions[i].rowelsxs ;
+
+
+    //delete [](double*)actions[i].costsx ;
+    deleteAction(actions[i].costsx,double*) ;
+  }
+
+  // Must add cast to placate MS compiler
+  //delete [] (subst_constraint_action::action*)actions_ ;
+  deleteAction(actions_,subst_constraint_action::action*) ;
+}
diff --git a/cbits/coin/CoinPresolveSubst.hpp b/cbits/coin/CoinPresolveSubst.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveSubst.hpp
@@ -0,0 +1,101 @@
+/* $Id: CoinPresolveSubst.hpp 1562 2012-11-24 00:36:15Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveSubst_H
+#define CoinPresolveSubst_H
+
+/*!
+  \file
+*/
+  
+#define	SUBST_ROW	21
+
+#include "CoinPresolveMatrix.hpp"
+
+/*! \class subst_constraint_action
+    \brief Detect and process implied free variables
+
+  Consider a variable x. Suppose that we can find an equality such that the
+  bound on the equality, combined with
+  the bounds on the other variables involved in the equality, are such that
+  even the worst case values of the other variables still imply bounds for x
+  which are tighter than the variable's original bounds. Since x can never
+  reach its upper or lower bounds, it is an implied free variable. By solving
+  the equality for x and substituting for x in every other constraint
+  entangled with x, we can make x into a column singleton. Now x is an implied
+  free column singleton and both x and the equality can be removed.
+
+  A similar transform for the case where the variable is a natural column
+  singleton is handled by #implied_free_action. In the current presolve
+  architecture, #implied_free_action is responsible for detecting implied free
+  variables that are natural column singletons or can be reduced to column
+  singletons. #implied_free_action calls subst_constraint_action to process
+  variables that must be reduced to column singletons.
+*/
+class subst_constraint_action : public CoinPresolveAction {
+private:
+  subst_constraint_action();
+  subst_constraint_action(const subst_constraint_action& rhs);
+  subst_constraint_action& operator=(const subst_constraint_action& rhs);
+
+  struct action {
+    double *rlos;
+    double *rups;
+
+    double *coeffxs;
+    int *rows;
+    
+    int *ninrowxs;
+    int *rowcolsxs;
+    double *rowelsxs;
+
+    const double *costsx;
+    int col;
+    int rowy;
+
+    int nincol;
+  };
+
+  const int nactions_;
+  // actions_ is owned by the class and must be deleted at destruction
+  const action *const actions_;
+
+  subst_constraint_action(int nactions,
+			  action *actions,
+			  const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions) {}
+
+ public:
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix * prob,
+					    const int *implied_free,
+					    const int * which,
+					    int numberFree,
+					    const CoinPresolveAction *next,
+					    int fill_level);
+  static const CoinPresolveAction *presolveX(CoinPresolveMatrix * prob,
+				  const CoinPresolveAction *next,
+				  int fillLevel);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~subst_constraint_action();
+};
+
+
+
+
+
+/*static*/ void implied_bounds(const double *els,
+			   const double *clo, const double *cup,
+			   const int *hcol,
+			   CoinBigIndex krs, CoinBigIndex kre,
+			   double *maxupp, double *maxdownp,
+			   int jcol,
+			   double rlo, double rup,
+			   double *iclb, double *icub);
+#endif
diff --git a/cbits/coin/CoinPresolveTighten.cpp b/cbits/coin/CoinPresolveTighten.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveTighten.cpp
@@ -0,0 +1,508 @@
+/* $Id: CoinPresolveTighten.cpp 1518 2011-12-10 23:44:40Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveTighten.hpp"
+#include "CoinPresolveUseless.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinFinite.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+
+const char *do_tighten_action::name() const
+{
+  return ("do_tighten_action");
+}
+
+/*
+  This is ekkredc2.  This fairly simple transformation is not mentioned
+  in the paper.  Say there is a costless variable x<t> such that all the
+  constraints it's entangled with (i.e., a<it> != 0) would be satisfied
+  as it approaches plus or minus infinity, because all its constraints
+  have only one bound, and increasing/decreasing the variable makes the
+  row activity grow away from the bound (in the right direction).
+
+  If x<j> is unbounded in that direction, it can always be made large
+  enough to satisfy the constraints, so we can just drop the variable and
+  the entangled constraints from the problem.
+
+  If x<j> *is* bounded in that direction, there is no reason not to set
+  it to that bound.  This effectively weakens the constraints, which in
+  fact may be subsequently presolved away.
+
+  Note that none of the constraints may be bounded both above and below,
+  since then we don't know which way to move the variable in order to
+  satisfy the constraint.
+
+  To drop constraints, we just make them useless and let other transformations
+  take care of the rest.
+
+  Note that more than one such costless unbounded variable may be part of
+  a given constraint.  In that case, the first one processed will make
+  the constraint useless, and the second will ignore it.  In postsolve,
+  the first will be responsible for satisfying the constraint.
+
+  Note that if the constraints are dropped (as in the first case), then we
+  just make them useless.  It will subsequently be discovered the the variable
+  does not appear in any constraints, and since it has no cost it is just set
+  to some value (either zero or a bound) and removed (by remove_empty_cols).
+
+  Oddly, pilots and baxter do *worse* when this transform is applied.
+
+  It's informative to compare this transform to the very similar transform
+  implemented in remove_dual_action. Surely they could be merged.
+*/
+
+const CoinPresolveAction *do_tighten_action::presolve(CoinPresolveMatrix *prob,
+					       const CoinPresolveAction *next)
+{
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt		= prob->mcstrt_;
+  int *hincol		= prob->hincol_;
+  int ncols		= prob->ncols_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  double *dcost	= prob->cost_;
+
+  const unsigned char *integerType = prob->integerType_;
+
+  int *fix_cols	= prob->usefulColumnInt_;
+  int nfixup_cols	= 0;
+
+  int nfixdown_cols	= ncols;
+
+  int *useless_rows	= prob->usefulRowInt_;
+  int nuseless_rows	= 0;
+  
+  action *actions	= new action [ncols];
+  int nactions		= 0;
+
+  int numberLook = prob->numberColsToDo_;
+  int iLook;
+  int * look = prob->colsToDo_;
+  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering do_tighten_action::presolve; considering " << numberLook
+    << " rows." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int startEmptyRows = 0 ;
+  int startEmptyColumns = 0 ;
+  startEmptyRows = prob->countEmptyRows() ;
+  startEmptyColumns = prob->countEmptyCols() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0;
+  if (prob->tuning_) startTime = CoinCpuTime() ;
+# endif
+# endif
+
+
+  // singleton columns are especially likely to be caught here
+  for (iLook=0;iLook<numberLook;iLook++) {
+    int j = look[iLook];
+    // modify bounds if integer
+    if (integerType[j]) {
+      clo[j] = ceil(clo[j]-1.0e-12);
+      cup[j] = floor(cup[j]+1.0e-12);
+      if (clo[j]>cup[j]&&!fixInfeasibility) {
+        // infeasible
+	prob->status_|= 1;
+	prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS,
+					     prob->messages())
+				 	       <<j
+					       <<clo[j]
+					       <<cup[j]
+					       <<CoinMessageEol;
+      }
+    }
+    if (dcost[j]==0.0) {
+      int iflag=0; /* 1 - up is towards feasibility, -1 down is towards */
+      int nonFree=0; // Number of non-free rows
+
+      CoinBigIndex kcs = mcstrt[j];
+      CoinBigIndex kce = kcs + hincol[j];
+
+      // check constraints
+      for (CoinBigIndex k=kcs; k<kce; ++k) {
+	int i = hrow[k];
+	double coeff = colels[k];
+	double rlb = rlo[i];
+	double rub = rup[i];
+
+	if (-1.0e28 < rlb && rub < 1.0e28) {
+	  // bounded - we lose
+	  iflag=0;
+	  break;
+	} else if (-1.0e28 < rlb || rub < 1.0e28) {
+	  nonFree++;
+	}
+
+	PRESOLVEASSERT(fabs(coeff) > ZTOLDP);
+
+	// see what this particular row says
+	// jflag == 1 ==> up is towards feasibility
+	int jflag = (coeff > 0.0
+		     ? (rub >  1.0e28 ? 1 : -1)
+		     : (rlb < -1.0e28 ? 1 : -1));
+
+	if (iflag) {
+	  // check that it agrees with iflag.
+	  if (iflag!=jflag) {
+	    iflag=0;
+	    break;
+	  }
+	} else {
+	  // first row -- initialize iflag
+	  iflag=jflag;
+	}
+      }
+      // done checking constraints
+      if (!nonFree)
+	iflag=0; // all free anyway
+      if (iflag) {
+	if (iflag==1 && cup[j]<1.0e10) {
+#if	PRESOLVE_DEBUG > 1
+	  printf("TIGHTEN UP:  %d\n", j);
+#endif
+	  fix_cols[nfixup_cols++] = j;
+
+	} else if (iflag==-1&&clo[j]>-1.0e10) {
+	  // symmetric case
+	  //mpre[j] = PRESOLVE_XUP;
+
+#if	PRESOLVE_DEBUG > 1
+	  printf("TIGHTEN DOWN:  %d\n", j);
+#endif
+
+	  fix_cols[--nfixdown_cols] = j;
+
+	} else {
+#if 0
+	  static int limit;
+	  static int which = atoi(getenv("WZ"));
+	  if (which == -1)
+	    ;
+	  else if (limit != which) {
+	    limit++;
+	    continue;
+	  } else
+	    limit++;
+
+	  printf("TIGHTEN STATS %d %g %g %d:  \n", j, clo[j], cup[j], integerType[j]); 
+  double *rowels	= prob->rowels_;
+  int *hcol		= prob->hcol_;
+  int *mrstrt		= prob->mrstrt_;
+  int *hinrow		= prob->hinrow_;
+	  for (CoinBigIndex k=kcs; k<kce; ++k) {
+	    int irow = hrow[k];
+	    CoinBigIndex krs = mrstrt[irow];
+	    CoinBigIndex kre = krs + hinrow[irow];
+	    printf("%d  %g %g %g:  ",
+		   irow, rlo[irow], rup[irow], colels[irow]);
+	    for (CoinBigIndex kk=krs; kk<kre; ++kk)
+	      printf("%d(%g) ", hcol[kk], rowels[kk]);
+	    printf("\n");
+	  }
+#endif
+
+	  {
+	    action *s = &actions[nactions];	  
+	    nactions++;
+	    s->col = j;
+	    PRESOLVE_DETAIL_PRINT(printf("pre_tighten %dC E\n",j));
+	    if (integerType[j]) {
+	      assert (iflag==-1||iflag==1);
+	      iflag *= 2; // say integer
+	    }
+	    s->direction = iflag;
+
+	    s->rows =   new int[hincol[j]];
+	    s->lbound = new double[hincol[j]];
+	    s->ubound = new double[hincol[j]];
+#if         PRESOLVE_DEBUG > 1
+	    printf("TIGHTEN FREE:  %d   ", j);
+#endif
+	    int nr = 0;
+            prob->addCol(j);
+	    for (CoinBigIndex k=kcs; k<kce; ++k) {
+	      int irow = hrow[k];
+	      // ignore this if we've already made it useless
+	      if (! (rlo[irow] == -PRESOLVE_INF && rup[irow] == PRESOLVE_INF)) {
+		prob->addRow(irow);
+		s->rows  [nr] = irow;
+		s->lbound[nr] = rlo[irow];
+		s->ubound[nr] = rup[irow];
+		nr++;
+
+		useless_rows[nuseless_rows++] = irow;
+
+		rlo[irow] = -PRESOLVE_INF;
+		rup[irow] = PRESOLVE_INF;
+
+#if             PRESOLVE_DEBUG > 1
+		printf("%d ", irow);
+#endif
+	      }
+	    }
+	    s->nrows = nr;
+
+#if         PRESOLVE_DEBUG > 1
+	    printf("\n");
+#endif
+	  }
+	}
+      }
+    }
+  }
+
+
+#if	PRESOLVE_SUMMARY > 0
+  if (nfixdown_cols<ncols || nfixup_cols || nuseless_rows) {
+    printf("NTIGHTENED:  %d %d %d\n", ncols-nfixdown_cols, nfixup_cols, nuseless_rows);
+  }
+#endif
+
+  if (nuseless_rows) {
+    next = new do_tighten_action(nactions, CoinCopyOfArray(actions,nactions), next);
+
+    next = useless_constraint_action::presolve(prob,
+					       useless_rows, nuseless_rows,
+					       next);
+  }
+  deleteAction(actions, action*);
+  //delete[]useless_rows;
+
+  if (nfixdown_cols<ncols) {
+    int * fixdown_cols = fix_cols+nfixdown_cols; 
+    nfixdown_cols = ncols-nfixdown_cols;
+    next = make_fixed_action::presolve(prob, fixdown_cols, nfixdown_cols,
+				       true,
+				       next);
+  }
+  //delete[]fixdown_cols;
+
+  if (nfixup_cols) {
+    next = make_fixed_action::presolve(prob, fix_cols, nfixup_cols,
+				       false,
+				       next);
+  }
+  //delete[]fixup_cols;
+
+# if COIN_PRESOLVE_TUNING > 0
+  if (prob->tuning_) double thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_sol(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving do_tighten_action::presolve, " << droppedRows << " rows, "
+    << droppedColumns << " columns dropped" ;
+# if COIN_PRESOLVE_TUNING > 0
+  std::cout << " in " << thisTime-startTime << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next);
+}
+
+void do_tighten_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_;
+  const int nactions	= nactions_;
+
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt		= prob->mcstrt_;
+  int *hincol		= prob->hincol_;
+  int *link		= prob->link_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  double *sol	= prob->sol_;
+  double *acts	= prob->acts_;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  char *cdone	= prob->cdone_;
+  char *rdone	= prob->rdone_;
+
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Entering do_tighten_action::postsolve." << std::endl ;
+# endif
+# endif
+
+  for (const action *f = &actions[nactions-1]; actions<=f; f--) {
+    int jcol = f->col;
+    int iflag = f->direction;
+    int nr   = f->nrows;
+    const int *rows = f->rows;
+    const double *lbound = f->lbound;
+    const double *ubound = f->ubound;
+
+    PRESOLVEASSERT(prob->getColumnStatus(jcol)!=CoinPrePostsolveMatrix::basic);
+    int i;
+    for (i=0;i<nr; ++i) {
+      int irow = rows[i];
+
+      rlo[irow] = lbound[i];
+      rup[irow] = ubound[i];
+
+     PRESOLVEASSERT(prob->getRowStatus(irow)==CoinPrePostsolveMatrix::basic);
+    }
+
+    // We have just tightened the row bounds.
+    // That means we'll have to compute a new value
+    // for this variable that will satisfy everybody.
+    // We are supposed to be in a position where this
+    // is always possible.
+
+    // Each constraint has exactly one bound.
+    // The correction should only ever be forced to move in one direction.
+    //    double orig_sol = sol[jcol];
+    double correction = 0.0;
+    
+    int last_corrected = -1;
+    CoinBigIndex k = mcstrt[jcol];
+    int nk = hincol[jcol];
+    for (i=0; i<nk; ++i) {
+      int irow = hrow[k];
+      double coeff = colels[k];
+      k = link[k];
+      double newrlo = rlo[irow];
+      double newrup = rup[irow];
+      double activity = acts[irow];
+
+      if (activity + correction * coeff < newrlo) {
+	// only one of these two should fire
+	PRESOLVEASSERT( ! (activity + correction * coeff > newrup) );
+
+	last_corrected = irow;
+
+	// adjust to just meet newrlo (solve for correction)
+	double new_correction = (newrlo - activity) / coeff;
+	//adjust if integer
+	if (iflag==-2||iflag==2) {
+	  new_correction += sol[jcol];
+	  if (fabs(floor(new_correction+0.5)-new_correction)>1.0e-4) {
+	    new_correction = ceil(new_correction)-sol[jcol];
+#ifdef COIN_DEVELOP
+	    printf("integer postsolve changing correction from %g to %g - flag %d\n",
+		   (newrlo-activity)/coeff,new_correction,iflag);
+#endif
+	  }
+	}
+	correction = new_correction;
+      } else if (activity + correction * coeff > newrup) {
+	last_corrected = irow;
+
+	double new_correction = (newrup - activity) / coeff;
+	//adjust if integer
+	if (iflag==-2||iflag==2) {
+	  new_correction += sol[jcol];
+	  if (fabs(floor(new_correction+0.5)-new_correction)>1.0e-4) {
+	    new_correction = ceil(new_correction)-sol[jcol];
+#ifdef COIN_DEVELOP
+	    printf("integer postsolve changing correction from %g to %g - flag %d\n",
+		   (newrup-activity)/coeff,new_correction,iflag);
+#endif
+	  }
+	}
+	correction = new_correction;
+      }
+    }
+
+    if (last_corrected>=0) {
+      sol[jcol] += correction;
+      
+      // by construction, the last row corrected (if there was one)
+      // must be at its bound, so it can be non-basic.
+      // All other rows may not be at a bound (but may if the difference
+      // is very small, causing a new correction by a tiny amount).
+      
+      // now adjust the activities
+      k = mcstrt[jcol];
+      for (i=0; i<nk; ++i) {
+	int irow = hrow[k];
+	double coeff = colels[k];
+	k = link[k];
+	//      double activity = acts[irow];
+
+	acts[irow] += correction * coeff;
+      }
+      /*
+        If the col happens to get pushed to its bound, we may as well leave
+	it non-basic. Otherwise, set the status to basic.
+
+	Why do we correct the row status only when the column is made basic?
+	Need to look at preceding code.  -- lh, 110528 --
+      */
+      if (fabs(sol[jcol]-clo[jcol]) > ZTOLDP &&
+          fabs(sol[jcol]-cup[jcol]) > ZTOLDP) {
+        
+        prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::basic);
+	if (acts[last_corrected]-rlo[last_corrected] <
+				rup[last_corrected]-acts[last_corrected])
+	  prob->setRowStatus(last_corrected,
+	  		     CoinPrePostsolveMatrix::atUpperBound);
+	else
+	  prob->setRowStatus(last_corrected,
+	  		     CoinPrePostsolveMatrix::atLowerBound);
+      }
+    }
+  }
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving do_tighten_action::postsolve." << std::endl ;
+# endif
+# endif
+}
+
+do_tighten_action::~do_tighten_action()
+{
+    if (nactions_ > 0) {
+	for (int i = nactions_ - 1; i >= 0; --i) {
+	    delete[] actions_[i].rows;
+	    delete[] actions_[i].lbound;
+	    delete[] actions_[i].ubound;
+	}
+	deleteAction(actions_, action*);
+    }
+}
diff --git a/cbits/coin/CoinPresolveTighten.hpp b/cbits/coin/CoinPresolveTighten.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveTighten.hpp
@@ -0,0 +1,55 @@
+/* $Id: CoinPresolveTighten.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveTighten_H
+#define CoinPresolveTighten_H
+
+#include "CoinPresolveMatrix.hpp"
+
+// This action has no separate class;
+// instead, it decides which columns can be made fixed
+// and calls make_fixed_action::presolve.
+const CoinPresolveAction *tighten_zero_cost(CoinPresolveMatrix *prob,
+					 const CoinPresolveAction *next);
+
+#define	DO_TIGHTEN	30
+
+class do_tighten_action : public CoinPresolveAction {
+  do_tighten_action();
+  do_tighten_action(const do_tighten_action& rhs);
+  do_tighten_action& operator=(const do_tighten_action& rhs);
+
+  struct action {
+    int *rows;
+    double *lbound;
+    double *ubound;
+    int col;
+    int nrows;
+    int direction;	// just for assertions
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  do_tighten_action(int nactions,
+		      const action *actions,
+		      const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions) {}
+
+ public:
+  const char *name() const;
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~do_tighten_action();
+
+};
+#endif
+
+
diff --git a/cbits/coin/CoinPresolveTripleton.cpp b/cbits/coin/CoinPresolveTripleton.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveTripleton.cpp
@@ -0,0 +1,1101 @@
+/* $Id: CoinPresolveTripleton.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinFinite.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+
+#include "CoinPresolveEmpty.hpp"	// for DROP_COL/DROP_ROW
+#include "CoinPresolveZeros.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveTripleton.hpp"
+
+#include "CoinPresolvePsdebug.hpp"
+#include "CoinMessage.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+/*
+ * Substituting y away:
+ *
+ *	 y = (c - a x - d z) / b
+ *
+ * so adjust bounds by:   c/b
+ *           and x  by:  -a/b
+ *           and z  by:  -d/b
+ *
+ * This affects both the row and col representations.
+ *
+ * mcstrt only modified if the column must be moved.
+ *
+ * for every row in icoly
+ *	if icolx is also has an entry for row
+ *		modify the icolx entry for row
+ *		drop the icoly entry from row and modify the icolx entry
+ *	else 
+ *		add a new entry to icolx column
+ *		create a new icolx entry
+ *		(this may require moving the column in memory)
+ *		replace icoly entry from row and replace with icolx entry
+ *
+ *   same for icolz
+ * The row and column reps are inconsistent during the routine,
+ * because icolx in the column rep is updated, and the entries corresponding
+ * to icolx in the row rep are updated, but nothing concerning icoly
+ * in the col rep is changed.  icoly entries in the row rep are deleted,
+ * and icolx entries in both reps are consistent.
+ * At the end, we set the length of icoly to be zero, so the reps would
+ * be consistent if the row were deleted from the row rep.
+ * Both the row and icoly must be removed from both reps.
+ * In the col rep, icoly will be eliminated entirely, at the end of the routine;
+ * irow occurs in just two columns, one of which (icoly) is eliminated
+ * entirely, the other is icolx, which is not deleted here.
+ * In the row rep, irow will be eliminated entirely, but not here;
+ * icoly is removed from the rows it occurs in.
+ */
+static bool elim_tripleton(const char * 
+#if PRESOLVE_DEBUG > 1
+msg
+#endif
+			   ,
+			   CoinBigIndex *mcstrt, 
+			   double *rlo, double * acts, double *rup,
+			   double *colels,
+			   int *hrow, int *hcol,
+			   int *hinrow, int *hincol,
+			   presolvehlink *clink, int ncols,
+			   presolvehlink *rlink, int nrows,
+			   CoinBigIndex *mrstrt, double *rowels,
+			   //double a, double b, double c,
+			   double coeff_factorx,double coeff_factorz,
+			   double bounds_factor,
+			   int row0, int icolx, int icoly, int icolz)
+{
+  CoinBigIndex kcs = mcstrt[icoly];
+  CoinBigIndex kce = kcs + hincol[icoly];
+  CoinBigIndex kcsx = mcstrt[icolx];
+  CoinBigIndex kcex = kcsx + hincol[icolx];
+  CoinBigIndex kcsz = mcstrt[icolz];
+  CoinBigIndex kcez = kcsz + hincol[icolz];
+
+# if PRESOLVE_DEBUG > 1
+  printf("%s %d x=%d y=%d z=%d cfx=%g cfz=%g nx=%d yrows=(", msg,
+	 row0,icolx,icoly,icolz,coeff_factorx,coeff_factorz,hincol[icolx]) ;
+# endif
+  for (CoinBigIndex kcoly=kcs; kcoly<kce; kcoly++) {
+    int row = hrow[kcoly];
+
+    // even though these values are updated, they remain consistent
+    PRESOLVEASSERT(kcex == kcsx + hincol[icolx]);
+    PRESOLVEASSERT(kcez == kcsz + hincol[icolz]);
+
+    // we don't need to update the row being eliminated 
+    if (row != row0/* && hinrow[row] > 0*/) {
+      if (bounds_factor != 0.0) {
+	// (1)
+	if (-PRESOLVE_INF < rlo[row])
+	  rlo[row] -= colels[kcoly] * bounds_factor;
+
+	// (2)
+	if (rup[row] < PRESOLVE_INF)
+	  rup[row] -= colels[kcoly] * bounds_factor;
+
+	// and solution
+	if (acts)
+	{ acts[row] -= colels[kcoly] * bounds_factor; }
+      }
+      // see if row appears in colx
+      CoinBigIndex kcolx = presolve_find_row1(row, kcsx, kcex, hrow);
+#     if PRESOLVE_DEBUG > 1
+      printf("%d%s ",row,(kcolx<kcex)?"x+":"") ;
+#     endif
+      // see if row appears in colz
+      CoinBigIndex kcolz = presolve_find_row1(row, kcsz, kcez, hrow);
+#     if PRESOLVE_DEBUG > 1
+      printf("%d%s ",row,(kcolz<kcez)?"x+":"") ;
+#     endif
+
+      if (kcolx>=kcex&&kcolz<kcez) {
+	// swap
+	int iTemp;
+	iTemp=kcolx;
+	kcolx=kcolz;
+	kcolz=iTemp;
+	iTemp=kcsx;
+	kcsx=kcsz;
+	kcsz=iTemp;
+	iTemp=kcex;
+	kcex=kcez;
+	kcez=iTemp;
+	iTemp=icolx;
+	icolx=icolz;
+	icolz=iTemp;
+	double dTemp=coeff_factorx;
+	coeff_factorx=coeff_factorz;
+	coeff_factorz=dTemp;
+      }
+      if (kcolx<kcex) {
+	// before:  both x and y are in the row
+	// after:   only x is in the row
+	// so: number of elems in col x unchanged, and num elems in row is one less
+
+	// update col rep - just modify coefficent
+	// column y is deleted as a whole at the end of the loop
+	colels[kcolx] += colels[kcoly] * coeff_factorx;
+	// update row rep
+	// first, copy new value for col x into proper place in rowels
+	CoinBigIndex k2 = presolve_find_col(icolx, mrstrt[row], mrstrt[row]+hinrow[row], hcol);
+	rowels[k2] = colels[kcolx];
+	if (kcolz<kcez) {
+	  // before:  both z and y are in the row
+	  // after:   only z is in the row
+	  // so: number of elems in col z unchanged, and num elems in row is one less
+	  
+	  // update col rep - just modify coefficent
+	  // column y is deleted as a whole at the end of the loop
+	  colels[kcolz] += colels[kcoly] * coeff_factorz;
+	  // update row rep
+	  // first, copy new value for col z into proper place in rowels
+	  CoinBigIndex k2 = presolve_find_col(icolz, mrstrt[row], mrstrt[row]+hinrow[row], hcol);
+	  rowels[k2] = colels[kcolz];
+	  // now delete col y from the row; this changes hinrow[row]
+	  presolve_delete_from_row(row, icoly, mrstrt, hinrow, hcol, rowels);
+	} else {
+	  // before:  only y is in the row
+	  // after:   only z is in the row
+	  // so: number of elems in col z is one greater, but num elems in row remains same
+	  // update entry corresponding to icolz in row rep 
+	  // by just overwriting the icoly entry
+	  {
+	    CoinBigIndex k2 = presolve_find_col(icoly, mrstrt[row], mrstrt[row]+hinrow[row], hcol);
+	    hcol[k2] = icolz;
+	    rowels[k2] = colels[kcoly] * coeff_factorz;
+	  }
+	  
+	  {
+	    bool no_mem = presolve_expand_col(mcstrt,colels,hrow,hincol,
+					      clink,ncols,icolz);
+	    if (no_mem)
+	      return (true);
+	    
+	    // have to adjust various induction variables
+ 	    kcolx = mcstrt[icolx] + (kcolx - kcsx);
+ 	    kcsx = mcstrt[icolx];			
+ 	    kcex = mcstrt[icolx] + hincol[icolx];
+	    kcoly = mcstrt[icoly] + (kcoly - kcs);
+	    kcs = mcstrt[icoly];			// do this for ease of debugging
+	    kce = mcstrt[icoly] + hincol[icoly];
+	    
+	    kcolz = mcstrt[icolz] + (kcolz - kcs);	// don't really need to do this
+	    kcsz = mcstrt[icolz];
+	    kcez = mcstrt[icolz] + hincol[icolz];
+	  }
+	  
+	  // there is now an unused entry in the memory after the column - use it
+	  // mcstrt[ncols] == penultimate index of arrays hrow/colels
+	  hrow[kcez] = row;
+	  colels[kcez] = colels[kcoly] * coeff_factorz;	// y factor is 0.0 
+	  hincol[icolz]++, kcez++;	// expand the col
+	}
+      } else {
+	// before:  only y is in the row
+	// after:   only x and z are in the row
+	// update entry corresponding to icolx in row rep 
+	// by just overwriting the icoly entry
+	{
+	  CoinBigIndex k2 = presolve_find_col(icoly, mrstrt[row], mrstrt[row]+hinrow[row], hcol);
+	  hcol[k2] = icolx;
+	  rowels[k2] = colels[kcoly] * coeff_factorx;
+	}
+	presolve_expand_row(mrstrt,rowels,hcol,hinrow,rlink,nrows,row) ;
+	// there is now an unused entry in the memory after the column - use it
+	int krez = mrstrt[row]+hinrow[row];
+	hcol[krez] = icolz;
+	rowels[krez] = colels[kcoly] * coeff_factorz;
+	hinrow[row]++;
+
+	{
+	  bool no_mem = presolve_expand_col(mcstrt,colels,hrow,hincol,
+					    clink,ncols,icolx) ;
+	  if (no_mem)
+	    return (true);
+
+	  // have to adjust various induction variables
+	  kcoly = mcstrt[icoly] + (kcoly - kcs);
+	  kcs = mcstrt[icoly];			// do this for ease of debugging
+	  kce = mcstrt[icoly] + hincol[icoly];
+	    
+	  kcolx = mcstrt[icolx] + (kcolx - kcs);	// don't really need to do this
+	  kcsx = mcstrt[icolx];
+	  kcex = mcstrt[icolx] + hincol[icolx];
+	  kcolz = mcstrt[icolz] + (kcolz - kcs);	// don't really need to do this
+	  kcsz = mcstrt[icolz];
+	  kcez = mcstrt[icolz] + hincol[icolz];
+	}
+
+	// there is now an unused entry in the memory after the column - use it
+	hrow[kcex] = row;
+	colels[kcex] = colels[kcoly] * coeff_factorx;	// y factor is 0.0 
+	hincol[icolx]++, kcex++;	// expand the col
+
+	{
+	  bool no_mem = presolve_expand_col(mcstrt,colels,hrow,hincol,clink,
+					    ncols,icolz);
+	  if (no_mem)
+	    return (true);
+
+	  // have to adjust various induction variables
+	  kcoly = mcstrt[icoly] + (kcoly - kcs);
+	  kcs = mcstrt[icoly];			// do this for ease of debugging
+	  kce = mcstrt[icoly] + hincol[icoly];
+	    
+	  kcsx = mcstrt[icolx];
+	  kcex = mcstrt[icolx] + hincol[icolx];
+	  kcsz = mcstrt[icolz];
+	  kcez = mcstrt[icolz] + hincol[icolz];
+	}
+
+	// there is now an unused entry in the memory after the column - use it
+	hrow[kcez] = row;
+	colels[kcez] = colels[kcoly] * coeff_factorz;	// y factor is 0.0 
+	hincol[icolz]++, kcez++;	// expand the col
+      }
+    }
+  }
+
+# if PRESOLVE_DEBUG > 1
+  printf(")\n") ;
+# endif
+
+  // delete the whole column
+  hincol[icoly] = 0;
+
+  return (false);
+}
+
+
+
+
+/*
+ *
+ * The col rep and row rep must be consistent.
+ */
+const CoinPresolveAction *tripleton_action::presolve(CoinPresolveMatrix *prob,
+						  const CoinPresolveAction *next)
+{
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt		= prob->mcstrt_;
+  int *hincol		= prob->hincol_;
+  int ncols		= prob->ncols_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+
+  double *rowels	= prob->rowels_;
+  int *hcol		= prob->hcol_;
+  CoinBigIndex *mrstrt		= prob->mrstrt_;
+  int *hinrow		= prob->hinrow_;
+  int nrows		= prob->nrows_;
+
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  presolvehlink *clink = prob->clink_;
+  presolvehlink *rlink = prob->rlink_;
+
+  const unsigned char *integerType = prob->integerType_;
+
+  double *cost	= prob->cost_;
+
+  int numberLook = prob->numberRowsToDo_;
+  int iLook;
+  int * look = prob->rowsToDo_;
+  const double ztolzb	= prob->ztolzb_;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering tripleton_action::presolve; considering " << numberLook
+    << " rows." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int startEmptyRows = 0 ;
+  int startEmptyColumns = 0 ;
+  startEmptyRows = prob->countEmptyRows() ;
+  startEmptyColumns = prob->countEmptyCols() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0;
+  if (prob->tuning_) startTime = CoinCpuTime() ;
+# endif
+# endif
+
+  action * actions = new action [nrows];
+# ifdef ZEROFAULT
+  // initialise alignment padding bytes
+  memset(actions,0,nrows*sizeof(action)) ;
+# endif
+  int nactions = 0;
+
+  int *zeros	= prob->usefulColumnInt_; //new int[ncols];
+  char * mark = reinterpret_cast<char *>(zeros+ncols);
+  memset(mark,0,ncols);
+  int nzeros	= 0;
+
+  // If rowstat exists then all do
+  unsigned char *rowstat	= prob->rowstat_;
+  double *acts	= prob->acts_;
+  //  unsigned char * colstat = prob->colstat_;
+
+
+# if PRESOLVE_CONSISTENCY > 0
+  presolve_links_ok(prob) ;
+# endif
+
+  // wasfor (int irow=0; irow<nrows; irow++)
+  for (iLook=0;iLook<numberLook;iLook++) {
+    int irow = look[iLook];
+    if (hinrow[irow] == 3 &&
+	fabs(rup[irow] - rlo[irow]) <= ZTOLDP) {
+      double rhs = rlo[irow];
+      CoinBigIndex krs = mrstrt[irow];
+      CoinBigIndex kre = krs + hinrow[irow];
+      int icolx, icoly, icolz;
+      double coeffx, coeffy, coeffz;
+      CoinBigIndex k;
+      
+      /* locate first column */
+      for (k=krs; k<kre; k++) {
+	if (hincol[hcol[k]] > 0) {
+	  break;
+	}
+      }
+      PRESOLVEASSERT(k<kre);
+      coeffx = rowels[k];
+      if (fabs(coeffx) < ZTOLDP2)
+	continue;
+      icolx = hcol[k];
+      
+      
+      /* locate second column */
+      for (k++; k<kre; k++) {
+	if (hincol[hcol[k]] > 0) {
+	  break;
+	}
+      }
+      PRESOLVEASSERT(k<kre);
+      coeffy = rowels[k];
+      if (fabs(coeffy) < ZTOLDP2)
+	continue;
+      icoly = hcol[k];
+      
+      /* locate third column */
+      for (k++; k<kre; k++) {
+	if (hincol[hcol[k]] > 0) {
+	  break;
+	}
+      }
+      PRESOLVEASSERT(k<kre);
+      coeffz = rowels[k];
+      if (fabs(coeffz) < ZTOLDP2)
+	continue;
+      icolz = hcol[k];
+      
+      // For now let's do obvious one
+      if (coeffx*coeffz>0.0) {
+	if(coeffx*coeffy>0.0) 
+	  continue;
+      } else if (coeffx*coeffy>0.0) {
+	int iTemp = icoly;
+	icoly=icolz;
+	icolz=iTemp;
+	double dTemp = coeffy;
+	coeffy=coeffz;
+	coeffz=dTemp;
+      } else {
+	int iTemp = icoly;
+	icoly=icolx;
+	icolx=iTemp;
+	double dTemp = coeffy;
+	coeffy=coeffx;
+	coeffx=dTemp;
+      }
+      // Not all same sign and y is odd one out
+      // don't bother with fixed variables
+      if (!(fabs(cup[icolx] - clo[icolx]) < ZTOLDP) &&
+	  !(fabs(cup[icoly] - clo[icolx]) < ZTOLDP) &&
+	  !(fabs(cup[icolz] - clo[icoly]) < ZTOLDP)) {
+	assert (coeffx*coeffz>0.0&&coeffx*coeffy<0.0);
+	// Only do if does not give implicit bounds on x and z
+	double cx = - coeffx/coeffy;
+	double cz = - coeffz/coeffy;
+	/* don't do if y integer for now */
+	if (integerType[icoly]) {
+#define PRESOLVE_DANGEROUS
+#ifndef PRESOLVE_DANGEROUS
+	  continue;
+#else
+	  if (!integerType[icolx]||!integerType[icolz])
+	    continue;
+	  if (cx!=floor(cx+0.5)||cz!=floor(cz+0.5))
+	    continue;
+#endif
+	}
+	double rhsRatio = rhs/coeffy;
+	if (clo[icoly]>-1.0e30) {
+	  if (clo[icolx]<-1.0e30||clo[icolz]<-1.0e30)
+	    continue;
+	  if (cx*clo[icolx]+cz*clo[icolz]+rhsRatio<clo[icoly]-ztolzb)
+	    continue;
+	}
+	if (cup[icoly]<1.0e30) {
+	  if (cup[icolx]>1.0e30||cup[icolz]>1.0e30)
+	    continue;
+	  if (cx*cup[icolx]+cz*cup[icolz]+rhsRatio>cup[icoly]+ztolzb)
+	    continue;
+	}
+	/* find this row in each of the columns and do counts */
+	bool singleton=false;
+	for (k=mcstrt[icoly]; k<mcstrt[icoly]+hincol[icoly]; k++) {
+	  int jrow=hrow[k];
+	  if (hinrow[jrow]==1)
+	    singleton=true;
+	  if (jrow != irow)
+	    prob->setRowUsed(jrow);
+	}
+	int nDuplicate=0;
+	for (k=mcstrt[icolx]; k<mcstrt[icolx]+hincol[icolx]; k++) {
+	  int jrow=hrow[k];
+	  if (jrow != irow && prob->rowUsed(jrow))
+	    nDuplicate++;;
+	}
+	for (k=mcstrt[icolz]; k<mcstrt[icolz]+hincol[icolz]; k++) {
+	  int jrow=hrow[k];
+	  if (jrow != irow && prob->rowUsed(jrow))
+	    nDuplicate++;;
+	}
+	int nAdded=hincol[icoly]-3-nDuplicate;
+	for (k=mcstrt[icoly]; k<mcstrt[icoly]+hincol[icoly]; k++) {
+	  int jrow=hrow[k];
+	  prob->unsetRowUsed(jrow);
+	}
+	// let singleton rows be taken care of first
+	if (singleton)
+	  continue;
+	//if (nAdded<=1) 
+	//printf("%d elements added, hincol %d , dups %d\n",nAdded,hincol[icoly],nDuplicate);
+	if (nAdded>2)
+	  continue;
+
+	// it is possible that both x/z and y are singleton columns
+	// that can cause problems
+	if ((hincol[icolx] == 1 ||hincol[icolz] == 1) && hincol[icoly] == 1)
+	  continue;
+
+	// common equations are of the form ax + by = 0, or x + y >= lo
+	{
+	  action *s = &actions[nactions];	  
+	  nactions++;
+	  PRESOLVE_DETAIL_PRINT(printf("pre_tripleton %dR %dC %dC %dC E\n",
+				       irow,icoly,icolx,icolz));
+	  
+	  s->row = irow;
+	  s->icolx = icolx;
+	  s->icolz = icolz;
+	  
+	  s->icoly = icoly;
+	  s->cloy = clo[icoly];
+	  s->cupy = cup[icoly];
+	  s->costy = cost[icoly];
+	  
+	  s->rlo = rlo[irow];
+	  s->rup = rup[irow];
+	  
+	  s->coeffx = coeffx;
+	  s->coeffy = coeffy;
+	  s->coeffz = coeffz;
+	  
+	  s->ncoly	= hincol[icoly];
+	  s->colel	= presolve_dupmajor(colels, hrow, hincol[icoly],
+					    mcstrt[icoly]);
+	}
+
+	// costs
+	// the effect of maxmin cancels out
+	cost[icolx] += cost[icoly] * cx;
+	cost[icolz] += cost[icoly] * cz;
+
+	prob->change_bias(cost[icoly] * rhs / coeffy);
+	//if (cost[icoly]*rhs)
+	//printf("change %g col %d cost %g rhs %g coeff %g\n",cost[icoly]*rhs/coeffy,
+	// icoly,cost[icoly],rhs,coeffy);
+
+	if (rowstat) {
+	  // update solution and basis
+	  int numberBasic=0;
+	  if (prob->columnIsBasic(icoly))
+	    numberBasic++;
+	  if (prob->rowIsBasic(irow))
+	    numberBasic++;
+	  if (numberBasic>1) {
+	    if (!prob->columnIsBasic(icolx))
+	      prob->setColumnStatus(icolx,CoinPrePostsolveMatrix::basic);
+	    else
+	      prob->setColumnStatus(icolz,CoinPrePostsolveMatrix::basic);
+	  }
+	}
+	  
+	// Update next set of actions
+	{
+	  prob->addCol(icolx);
+	  int i,kcs,kce;
+	  kcs = mcstrt[icoly];
+	  kce = kcs + hincol[icoly];
+	  for (i=kcs;i<kce;i++) {
+	    int row = hrow[i];
+	    prob->addRow(row);
+	  }
+	  kcs = mcstrt[icolx];
+	  kce = kcs + hincol[icolx];
+	  for (i=kcs;i<kce;i++) {
+	    int row = hrow[i];
+	    prob->addRow(row);
+	  }
+	  prob->addCol(icolz);
+	  kcs = mcstrt[icolz];
+	  kce = kcs + hincol[icolz];
+	  for (i=kcs;i<kce;i++) {
+	    int row = hrow[i];
+	    prob->addRow(row);
+	  }
+	}
+
+	/* transfer the colx factors to coly */
+	bool no_mem = elim_tripleton("ELIMT",
+				     mcstrt, rlo, acts, rup, colels,
+				     hrow, hcol, hinrow, hincol,
+				     clink, ncols, rlink, nrows,
+				     mrstrt, rowels,
+				     cx,
+				     cz,
+				     rhs / coeffy,
+				     irow, icolx, icoly,icolz);
+	if (no_mem) 
+	  throwCoinError("out of memory",
+			 "tripleton_action::presolve");
+
+	// now remove irow from icolx and icolz in the col rep
+	// better if this were first.
+	presolve_delete_from_col(irow,icolx,mcstrt,hincol,hrow,colels) ;
+	presolve_delete_from_col(irow,icolz,mcstrt,hincol,hrow,colels) ;
+
+	// eliminate irow entirely from the row rep
+	hinrow[irow] = 0;
+
+	// eliminate irow entirely from the row rep
+	PRESOLVE_REMOVE_LINK(rlink, irow);
+
+	// eliminate coly entirely from the col rep
+	PRESOLVE_REMOVE_LINK(clink, icoly);
+	cost[icoly] = 0.0;
+
+	rlo[irow] = 0.0;
+	rup[irow] = 0.0;
+
+	if (!mark[icolx]) {
+	  mark[icolx]=1;
+	  zeros[nzeros++]=icolx;
+	}
+	if (!mark[icolz]) {
+	  mark[icolz]=1;
+	  zeros[nzeros++]=icolz;
+	}
+      }
+      
+#     if PRESOLVE_CONSISTENCY > 0
+      presolve_links_ok(prob) ;
+      presolve_consistent(prob);
+#     endif
+    }
+  }
+  if (nactions) {
+#   if PRESOLVE_SUMMARY > 0
+    printf("NTRIPLETONS:  %d\n", nactions);
+#   endif
+    action *actions1 = new action[nactions];
+    CoinMemcpyN(actions, nactions, actions1);
+
+    next = new tripleton_action(nactions, actions1, next);
+
+    if (nzeros) {
+      next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next);
+    }
+  }
+
+  //delete[]zeros;
+  deleteAction(actions,action*);
+
+# if COIN_PRESOLVE_TUNING > 0
+  if (prob->tuning_) double thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_check_sol(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
+  std::cout
+    << "Leaving tripleton_action::presolve, " << droppedRows << " rows, "
+    << droppedColumns << " columns dropped" ;
+# if COIN_PRESOLVE_TUNING > 0
+  std::cout << " in " << thisTime-startTime << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next);
+}
+
+
+void tripleton_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_;
+  const int nactions = nactions_;
+
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt		= prob->mcstrt_;
+  int *hincol		= prob->hincol_;
+  int *link		= prob->link_;
+
+  double *clo	= prob->clo_;
+  double *cup	= prob->cup_;
+
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  double *dcost	= prob->cost_;
+
+  double *sol	= prob->sol_;
+  double *rcosts	= prob->rcosts_;
+
+  double *acts	= prob->acts_;
+  double *rowduals = prob->rowduals_;
+
+  unsigned char *colstat	= prob->colstat_;
+  unsigned char *rowstat	= prob->rowstat_;
+
+  const double maxmin	= prob->maxmin_;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  char *cdone	= prob->cdone_;
+  char *rdone	= prob->rdone_;
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Entering tripleton_action::postsolve." << std::endl ;
+# endif
+# endif
+
+  CoinBigIndex &free_list = prob->free_list_;
+
+  const double ztolzb	= prob->ztolzb_;
+  const double ztoldj	= prob->ztoldj_;
+
+  // Space for accumulating two columns
+  int nrows = prob->nrows_;
+  int * index1 = new int[nrows];
+  double * element1 = new double[nrows];
+  memset(element1,0,nrows*sizeof(double));
+  int * index2 = new int[nrows];
+  double * element2 = new double[nrows];
+  memset(element2,0,nrows*sizeof(double));
+
+  for (const action *f = &actions[nactions-1]; actions<=f; f--) {
+    int irow = f->row;
+
+    // probably don't need this
+    double ylo0 = f->cloy;
+    double yup0 = f->cupy;
+
+    double coeffx = f->coeffx;
+    double coeffy = f->coeffy;
+    double coeffz = f->coeffz;
+    int jcolx = f->icolx;
+    int jcoly = f->icoly;
+    int jcolz = f->icolz;
+
+    // needed?
+    double rhs = f->rlo;
+
+    /* the column was in the reduced problem */
+    PRESOLVEASSERT(cdone[jcolx] && rdone[irow]==DROP_ROW&&cdone[jcolz]);
+    PRESOLVEASSERT(cdone[jcoly]==DROP_COL);
+
+    // probably don't need this
+    rlo[irow] = f->rlo;
+    rup[irow] = f->rup;
+
+    // probably don't need this
+    clo[jcoly] = ylo0;
+    cup[jcoly] = yup0;
+
+    dcost[jcoly] = f->costy;
+    dcost[jcolx] += f->costy*coeffx/coeffy;
+    dcost[jcolz] += f->costy*coeffz/coeffy;
+
+    // this is why we want coeffx < coeffy (55)
+    sol[jcoly] = (rhs - coeffx * sol[jcolx] - coeffz * sol[jcolz]) / coeffy;
+	  
+    // since this row is fixed 
+    acts[irow] = rhs;
+
+    // acts[irow] always ok, since slack is fixed
+    if (rowstat)
+      prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound);
+
+
+    // CLAIM:
+    // if the new pi value is chosen to keep the reduced cost
+    // of col x at its prior value, then the reduced cost of
+    // col y will be 0.
+    
+    // also have to update row activities and bounds for rows affected by jcoly
+    //
+    // sol[jcolx] was found for coeffx that
+    // was += colels[kcoly] * coeff_factor;
+    // where coeff_factor == -coeffx / coeffy
+    //
+    // its contribution to activity was
+    // (colels[kcolx] + colels[kcoly] * coeff_factor) * sol[jcolx]	(1)
+    //
+    // After adjustment, the two columns contribute:
+    // colels[kcoly] * sol[jcoly] + colels[kcolx] * sol[jcolx]
+    // == colels[kcoly] * ((rhs - coeffx * sol[jcolx]) / coeffy) + colels[kcolx] * sol[jcolx]
+    // == colels[kcoly] * rhs/coeffy + colels[kcoly] * coeff_factor * sol[jcolx] + colels[kcolx] * sol[jcolx]
+    // colels[kcoly] * rhs/coeffy + the expression (1)
+    //
+    // therefore, we must increase the row bounds by colels[kcoly] * rhs/coeffy,
+    // which is similar to the bias
+    double djy = maxmin * dcost[jcoly];
+    double djx = maxmin * dcost[jcolx];
+    double djz = maxmin * dcost[jcolz];
+    double bounds_factor = rhs/coeffy;
+    // need to reconstruct x and z
+    double multiplier1 = coeffx/coeffy;
+    double multiplier2 = coeffz/coeffy;
+    int * indy = reinterpret_cast<int *>(f->colel+f->ncoly);
+    int ystart = NO_LINK;
+    int nX=0,nZ=0;
+    int i,iRow;
+    for (i=0; i<f->ncoly; ++i) {
+      int iRow = indy[i];
+      double yValue = f->colel[i];
+      CoinBigIndex k = free_list;
+      assert(k >= 0 && k < prob->bulk0_) ;
+      free_list = link[free_list];
+      if (iRow != irow) {
+	// are these tests always true???
+
+	// undo elim_tripleton(1)
+	if (-PRESOLVE_INF < rlo[iRow])
+	  rlo[iRow] += yValue * bounds_factor;
+
+	// undo elim_tripleton(2)
+	if (rup[iRow] < PRESOLVE_INF)
+	  rup[iRow] += yValue * bounds_factor;
+
+	acts[iRow] += yValue * bounds_factor;
+
+	djy -= rowduals[iRow] * yValue;
+      } 
+      
+      hrow[k] = iRow;
+      PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow);
+      colels[k] = yValue;
+      link[k] = ystart;
+      ystart = k;
+      element1[iRow]=yValue*multiplier1;
+      index1[nX++]=iRow;
+      element2[iRow]=yValue*multiplier2;
+      index2[nZ++]=iRow;
+    }
+#   if PRESOLVE_CONSISTENCY > 0
+    presolve_check_free_list(prob) ;
+#   endif
+    mcstrt[jcoly] = ystart;
+    hincol[jcoly] = f->ncoly;
+    // find the tail
+    CoinBigIndex k=mcstrt[jcolx];
+    CoinBigIndex last = NO_LINK;
+    int numberInColumn = hincol[jcolx];
+    int numberToDo=numberInColumn;
+    for (i=0; i<numberToDo; ++i) {
+      iRow = hrow[k];
+      assert (iRow>=0&&iRow<nrows);
+      double value = colels[k]+element1[iRow];
+      element1[iRow]=0.0;
+      if (fabs(value)>=1.0e-15) {
+	colels[k]=value;
+	last=k;
+	k = link[k];
+	if (iRow != irow) 
+	  djx -= rowduals[iRow] * value;
+      } else {
+	numberInColumn--;
+	// add to free list
+	int nextk = link[k];
+	link[k]=free_list;
+	free_list=k;
+	assert (k>=0);
+	k=nextk;
+	if (last!=NO_LINK)
+	  link[last]=k;
+	else
+	  mcstrt[jcolx]=k;
+      }
+    }
+    for (i=0;i<nX;i++) {
+      int iRow = index1[i];
+      double xValue = element1[iRow];
+      element1[iRow]=0.0;
+      if (fabs(xValue)>=1.0e-15) {
+	if (iRow != irow)
+	  djx -= rowduals[iRow] * xValue;
+	numberInColumn++;
+	CoinBigIndex k = free_list;
+	assert(k >= 0 && k < prob->bulk0_) ;
+	free_list = link[free_list];
+	hrow[k] = iRow;
+	PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow);
+	colels[k] = xValue;
+	if (last!=NO_LINK)
+	  link[last]=k;
+	else
+	  mcstrt[jcolx]=k;
+	last = k;
+      }
+    }
+#   if PRESOLVE_CONSISTENCY > 0
+    presolve_check_free_list(prob) ;
+#   endif
+    link[last]=NO_LINK;
+    assert(numberInColumn);
+    hincol[jcolx] = numberInColumn;
+    // find the tail
+    k=mcstrt[jcolz];
+    last = NO_LINK;
+    numberInColumn = hincol[jcolz];
+    numberToDo=numberInColumn;
+    for (i=0; i<numberToDo; ++i) {
+      iRow = hrow[k];
+      assert (iRow>=0&&iRow<nrows);
+      double value = colels[k]+element2[iRow];
+      element2[iRow]=0.0;
+      if (fabs(value)>=1.0e-15) {
+	colels[k]=value;
+	last=k;
+	k = link[k];
+	if (iRow != irow) 
+	  djz -= rowduals[iRow] * value;
+      } else {
+	numberInColumn--;
+	// add to free list
+	int nextk = link[k];
+	assert(free_list>=0);
+	link[k]=free_list;
+	free_list=k;
+	assert (k>=0);
+	k=nextk;
+	if (last!=NO_LINK)
+	  link[last]=k;
+	else
+	  mcstrt[jcolz]=k;
+      }
+    }
+    for (i=0;i<nZ;i++) {
+      int iRow = index2[i];
+      double zValue = element2[iRow];
+      element2[iRow]=0.0;
+      if (fabs(zValue)>=1.0e-15) {
+	if (iRow != irow)
+	  djz -= rowduals[iRow] * zValue;
+	numberInColumn++;
+	CoinBigIndex k = free_list;
+	assert(k >= 0 && k < prob->bulk0_) ;
+	free_list = link[free_list];
+	hrow[k] = iRow;
+	PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow);
+	colels[k] = zValue;
+	if (last!=NO_LINK)
+	  link[last]=k;
+	else
+	  mcstrt[jcolz]=k;
+	last = k;
+      }
+    }
+#   if PRESOLVE_CONSISTENCY > 0
+    presolve_check_free_list(prob) ;
+#   endif
+    link[last]=NO_LINK;
+    assert(numberInColumn);
+    hincol[jcolz] = numberInColumn;
+    
+    
+    
+    // The only problem with keeping the reduced costs the way they were
+    // was that the variable's bound may have moved, requiring it
+    // to become basic.
+    //printf("djs x - %g (%g), y - %g (%g)\n",djx,coeffx,djy,coeffy);
+    if (colstat) {
+      if (prob->columnIsBasic(jcolx) ||
+	  (fabs(clo[jcolx] - sol[jcolx]) < ztolzb && rcosts[jcolx] >= -ztoldj) ||
+	  (fabs(cup[jcolx] - sol[jcolx]) < ztolzb && rcosts[jcolx] <= ztoldj) ||
+	  (prob->getColumnStatus(jcolx) ==CoinPrePostsolveMatrix::isFree&&
+           fabs(rcosts[jcolx]) <= ztoldj)) {
+	// colx or y is fine as it is - make coly basic
+
+	prob->setColumnStatus(jcoly,CoinPrePostsolveMatrix::basic);
+	// this is the coefficient we need to force col y's reduced cost to 0.0;
+	// for example, this is obviously true if y is a singleton column
+	rowduals[irow] = djy / coeffy;
+	rcosts[jcolx] = djx - rowduals[irow] * coeffx;
+#       if PRESOLVE_DEBUG > 0
+	if (prob->columnIsBasic(jcolx)&&fabs(rcosts[jcolx])>1.0e-5)
+	  printf("bad dj %d %g\n",jcolx,rcosts[jcolx]);
+#       endif
+	rcosts[jcolz] = djz - rowduals[irow] * coeffz;
+	//if (prob->columnIsBasic(jcolz))
+	//assert (fabs(rcosts[jcolz])<1.0e-5);
+	rcosts[jcoly] = 0.0;
+      } else {
+	prob->setColumnStatus(jcolx,CoinPrePostsolveMatrix::basic);
+	prob->setColumnStatusUsingValue(jcoly);
+
+	// change rowduals[jcolx] enough to cancel out rcosts[jcolx]
+	rowduals[irow] = djx / coeffx;
+	rcosts[jcolx] = 0.0;
+	// change rowduals[jcolx] enough to cancel out rcosts[jcolx]
+	//rowduals[irow] = djz / coeffz;
+	//rcosts[jcolz] = 0.0;
+	rcosts[jcolz] = djz - rowduals[irow] * coeffz;
+	rcosts[jcoly] = djy - rowduals[irow] * coeffy;
+      }
+    } else {
+      // No status array
+      // this is the coefficient we need to force col y's reduced cost to 0.0;
+      // for example, this is obviously true if y is a singleton column
+      rowduals[irow] = djy / coeffy;
+      rcosts[jcoly] = 0.0;
+    }
+    
+    // DEBUG CHECK
+#   if PRESOLVE_DEBUG > 0
+    {
+      CoinBigIndex k = mcstrt[jcolx];
+      int nx = hincol[jcolx];
+      double dj = maxmin * dcost[jcolx];
+      
+      for (int i=0; i<nx; ++i) {
+	int row = hrow[k];
+	double coeff = colels[k];
+	k = link[k];
+
+	dj -= rowduals[row] * coeff;
+      }
+      if (! (fabs(rcosts[jcolx] - dj) < 100*ZTOLDP))
+	printf("BAD DOUBLE X DJ:  %d %d %g %g\n",
+	       irow, jcolx, rcosts[jcolx], dj);
+      rcosts[jcolx]=dj;
+    }
+    {
+      CoinBigIndex k = mcstrt[jcoly];
+      int ny = hincol[jcoly];
+      double dj = maxmin * dcost[jcoly];
+      
+      for (int i=0; i<ny; ++i) {
+	int row = hrow[k];
+	double coeff = colels[k];
+	k = link[k];
+
+	dj -= rowduals[row] * coeff;
+	//printf("b %d coeff %g dual %g dj %g\n",
+	// row,coeff,rowduals[row],dj);
+      }
+      if (! (fabs(rcosts[jcoly] - dj) < 100*ZTOLDP))
+	printf("BAD DOUBLE Y DJ:  %d %d %g %g\n",
+	       irow, jcoly, rcosts[jcoly], dj);
+      rcosts[jcoly]=dj;
+      //exit(0);
+    }
+#   endif
+    
+#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+    cdone[jcoly] = TRIPLETON;
+    rdone[irow] = TRIPLETON;
+#   endif
+  }
+  delete [] index1;
+  delete [] element1;
+  delete [] index2;
+  delete [] element2;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob,2,2,2) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving tripleton_action::postsolve." << std::endl ;
+# endif
+# endif
+}
+
+
+tripleton_action::~tripleton_action()
+{
+  for (int i=nactions_-1; i>=0; i--) {
+    delete[]actions_[i].colel;
+  }
+  deleteAction(actions_,action*);
+}
+
+
+
+static double *tripleton_mult;
+static int *tripleton_id;
+void check_tripletons(const CoinPresolveAction * paction)
+{
+  const CoinPresolveAction * paction0 = paction;
+  
+  if (paction) {
+    check_tripletons(paction->next);
+    
+    if (strcmp(paction0->name(), "tripleton_action") == 0) {
+      const tripleton_action *daction = reinterpret_cast<const tripleton_action *>(paction0);
+      for (int i=daction->nactions_-1; i>=0; --i) {
+	int icolx = daction->actions_[i].icolx;
+	int icoly = daction->actions_[i].icoly;
+	double coeffx = daction->actions_[i].coeffx;
+	double coeffy = daction->actions_[i].coeffy;
+
+	tripleton_mult[icoly] = -coeffx/coeffy;
+	tripleton_id[icoly] = icolx;
+      }
+    }
+  }
+}
+
diff --git a/cbits/coin/CoinPresolveTripleton.hpp b/cbits/coin/CoinPresolveTripleton.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveTripleton.hpp
@@ -0,0 +1,66 @@
+/* $Id: CoinPresolveTripleton.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveTripleton_H
+#define CoinPresolveTripleton_H
+#define TRIPLETON 11
+/** We are only going to do this if it does not increase number of elements?.
+    It could be generalized to more than three but it seems unlikely it would
+    help.
+
+    As it is adapted from doubleton icoly is one dropped.
+ */
+class tripleton_action : public CoinPresolveAction {
+ public:
+  struct action {
+    int icolx;
+    int icolz;
+    int row;
+
+    int icoly;
+    double cloy;
+    double cupy;
+    double costy;
+    double clox;
+    double cupx;
+    double costx;
+
+    double rlo;
+    double rup;
+
+    double coeffx;
+    double coeffy;
+    double coeffz;
+
+    double *colel;
+
+    int ncolx;
+    int ncoly;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+ private:
+  tripleton_action(int nactions,
+		      const action *actions,
+		      const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nactions_(nactions), actions_(actions)
+{}
+
+ public:
+  const char *name() const { return ("tripleton_action"); }
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *,
+					 const CoinPresolveAction *next);
+  
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~tripleton_action();
+};
+#endif
+
+
diff --git a/cbits/coin/CoinPresolveUseless.cpp b/cbits/coin/CoinPresolveUseless.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveUseless.cpp
@@ -0,0 +1,824 @@
+/* $Id: CoinPresolveUseless.cpp 1566 2012-11-29 19:33:56Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveUseless.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinFinite.hpp"
+
+#if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+/*
+  This routine implements a greedy algorithm to find a set of necessary
+  constraints which imply tighter bounds for some subset of the variables. It
+  then uses the tighter column bounds to identify constraints that are
+  useless as long as the necessary set is present.
+
+  The algorithm is as follows:
+    * Initially mark all constraints as in play.
+    * For each in play constraint, calculate row activity bounds L(i) and U(i).
+      Use these bounds in an attempt to tighten column bounds for all
+      variables entangled with the row.
+    * If some column bound is tightened, the row is necessary. Mark it as
+      such, taking it out of play.
+  Eventually the rows are divided into two sets, necessary and unnecessary. Go
+  through the unnecessary rows and check L(i) and U(i) using the tightened
+  column bounds. Remove any useless rows where row activity cannot exceed the
+  row bounds.
+
+  For efficiency, rows are marked as processed when L(i) and U(i) are first
+  calculated and these values are not recalculated unless a column bound
+  changes.
+  
+*/
+const CoinPresolveAction *testRedundant (CoinPresolveMatrix *prob,
+					 const CoinPresolveAction *next)
+{
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering testRedundant, considering " << prob->nrows_
+    << " rows." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  const int startEmptyRows = prob->countEmptyRows() ;
+# if COIN_PRESOLVE_TUNING > 0
+  double startTime = 0.0 ;
+  if (prob->tuning_) startTime = CoinCpuTime() ;
+# endif
+# endif
+
+  const int m = prob->nrows_ ;
+  const int n = prob->ncols_ ;
+/*
+  Unpack the row- and column-major representations.
+*/
+  const CoinBigIndex *rowStarts = prob->mrstrt_ ;
+  const int *rowLengths = prob->hinrow_ ;
+  const double *rowCoeffs = prob->rowels_ ;
+  const int *colIndices = prob->hcol_ ;
+
+  const CoinBigIndex *colStarts = prob->mcstrt_ ;
+  const int *rowIndices = prob->hrow_ ;
+  const int *colLengths = prob->hincol_ ;
+/*
+  Rim vectors.
+  
+  We need copies of the column bounds to modify as we do bound propagation.
+*/
+  const double *rlo = prob->rlo_ ;
+  const double *rup = prob->rup_ ;
+
+  double *columnLower = new double[n] ;
+  double *columnUpper = new double[n] ;
+  CoinMemcpyN(prob->clo_,n,columnLower) ;
+  CoinMemcpyN(prob->cup_,n,columnUpper) ;
+/*
+  And we'll need somewhere to record the unnecessary rows.
+*/
+  int *useless_rows = prob->usefulRowInt_+m ;
+  int nuseless_rows = 0 ;
+
+/*
+  The usual finite infinity.
+*/
+# define USE_SMALL_LARGE
+# ifdef USE_SMALL_LARGE
+  const double large = 1.0e15 ;
+# else
+  const double large = 1.0e20 ;
+# endif
+# ifndef NDEBUG
+  const double large2 = 1.0e10*large ;
+# endif
+
+  double feasTol = prob->feasibilityTolerance_ ;
+  double relaxedTol = 100.0*feasTol ;
+
+/*
+  More like `ignore infeasibility.'
+*/
+  bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ;
+
+/*
+  Scan the rows and do an initial classification. MarkIgnore is used for
+  constraints that are not in play in bound propagation for whatever reason,
+  either because they're not interesting, or, later, because they're
+  necessary.
+
+  Interesting rows are nonempty with at least one finite row bound. The
+  rest we can ignore during propagation. Nonempty rows with no finite row
+  bounds are useless; record them for later.
+*/
+  const char markIgnore = 1 ;
+  const char markInPlay = -1 ;
+  const char markActOK = -2 ;
+  char *markRow = reinterpret_cast<char *>(prob->usefulRowInt_) ;
+
+  for (int i = 0 ; i < m ; i++) {
+    if ((rlo[i] > -large || rup[i] < large) && rowLengths[i] > 0) {
+      markRow[i] = markInPlay ;
+    } else {
+      markRow[i] = markIgnore ;
+      if (rowLengths[i] > 0) {
+	useless_rows[nuseless_rows++] = i ;
+	prob->addRow(i) ;
+      }
+    }
+  }
+
+/*
+  Open the main loop. We'll keep trying to tighten bounds until we get to
+  diminishing returns. numberCheck is set at the end of the loop based on how
+  well we did in the first pass. numberChanged tracks how well we do on the
+  current pass.
+*/
+
+  int numberInfeasible = 0 ;
+  int numberChanged = 0 ;
+  int totalTightened = 0 ;
+  int numberCheck = -1 ;
+
+  const int MAXPASS = 10 ;
+  int iPass = -1 ;
+  while (iPass < MAXPASS && numberChanged > numberCheck) {
+    iPass++ ;
+    numberChanged = 0 ;
+/*
+  Open a loop to work through the rows computing upper and lower bounds
+  on row activity. Each bound is calculated as a finite component and an
+  infinite component.
+
+  The state transitions for a row i go like this:
+    * Row i starts out marked with markInPlay.
+    * When row i is processed by the loop, L(i) and U(i) are calculated and
+      we try to tighten the column bounds of entangled columns. If nothing
+      happens, row i is marked with markActOK. It's still in play but
+      won't be processed again unless the mark changes back to markInPlay.
+    * If a column bound is tightened when we process row i, it's necessary.
+      Mark row i with markIgnore and do not process it again.
+      Other rows k entangled with the column and marked with markActOK are
+      remarked to markInPlay and L(k) and U(k) will be recalculated on
+      the next major pass.
+
+  If the row is not marked as markInPlay, either we're ignoring the row or
+  L(i) and U(i) have not changed since the last time the row was processed.
+  There's nothing to gain by processing it again.
+*/
+    for (int i = 0 ; i < m ; i++) {
+
+      if (markRow[i] != markInPlay) continue ;
+
+      int infUpi = 0 ;
+      int infLoi = 0 ;
+      double finUpi = 0.0 ;
+      double finDowni = 0.0 ;
+      const CoinBigIndex krs = rowStarts[i] ;
+      const CoinBigIndex kre = krs+rowLengths[i] ;
+/*
+  Open a loop to walk the row and calculate upper (U) and lower (L) bounds
+  on row activity. Expand the finite component just a wee bit to make sure the
+  bounds are conservative, then add in a whopping big value to account for the
+  infinite component.
+*/
+      for (CoinBigIndex kcol = krs ; kcol < kre ; ++kcol) {
+	const double value = rowCoeffs[kcol] ;
+	const int j = colIndices[kcol] ;
+	if (value > 0.0) {
+	  if (columnUpper[j] < large) 
+	    finUpi += columnUpper[j]*value ;
+	  else
+	    ++infUpi ;
+	  if (columnLower[j] > -large) 
+	    finDowni += columnLower[j]*value ;
+	  else
+	    ++infLoi ;
+	} else if (value<0.0) {
+	  if (columnUpper[j] < large) 
+	    finDowni += columnUpper[j]*value ;
+	  else
+	    ++infLoi ;
+	  if (columnLower[j] > -large) 
+	    finUpi += columnLower[j]*value ;
+	  else
+	    ++infUpi ;
+	}
+      }
+      markRow[i] = markActOK ;
+      finUpi += 1.0e-8*fabs(finUpi) ;
+      finDowni -= 1.0e-8*fabs(finDowni) ;
+      const double maxUpi = finUpi+infUpi*1.0e31 ;
+      const double maxDowni = finDowni-infLoi*1.0e31 ;
+/*
+  If LB(i) > rup(i) or UB(i) < rlo(i), we're infeasible. Break for the exit,
+  unless the user has been so foolish as to tell us to ignore infeasibility,
+  in which case just move on to the next row.
+*/
+      if (maxUpi < rlo[i]-relaxedTol || maxDowni > rup[i]+relaxedTol) {
+	if (!fixInfeasibility) {
+	  numberInfeasible++ ;
+	  prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS,
+					  prob->messages())
+	      << i << rlo[i] << rup[i] << CoinMessageEol ;
+	  break ;
+	} else {
+	  continue ;
+	}
+      }
+/*
+  Remember why we're here --- this is presolve. If the constraint satisfies
+  this condition, it already qualifies as useless and it's highly unlikely
+  to produce tightened column bounds. But don't record it as useless just yet;
+  leave that for phase 2.
+
+  LOU: Well, why not mark it as useless? A possible optimisation.
+*/
+      if (maxUpi <= rup[i]+feasTol && maxDowni >= rlo[i]-feasTol) continue ;
+/*
+  We're not infeasible and one of U(i) or L(i) is not inside the row bounds.
+  If we have something that looks like a forcing constraint but is just over
+  the line, force the bound to exact equality to ensure conservative column
+  bounds.
+*/
+      const double rloi = rlo[i] ;
+      const double rupi = rup[i] ;
+      if (finUpi < rloi && finUpi > rloi-relaxedTol)
+	finUpi = rloi ;
+      if (finDowni > rupi && finDowni < rupi+relaxedTol)
+	finDowni = rupi ;
+/*
+  Open a loop to walk the row and try to tighten column bounds.
+*/
+      for (CoinBigIndex kcol = krs ; kcol < kre ; ++kcol) {
+	const double ait = rowCoeffs[kcol] ;
+	const int t = colIndices[kcol] ;
+	double lt = columnLower[t] ;
+	double ut = columnUpper[t] ;
+	double newlt = COIN_DBL_MAX ;
+	double newut = -COIN_DBL_MAX ;
+/*
+  For a target variable x(t) with a(it) > 0, we have
+
+    new l(t) = (rlo(i)-(U(i)-a(it)u(t)))/a(it) = u(t) + (rlo(i)-U(i))/a(it)
+    new u(t) = (rup(i)-(L(i)-a(it)l(t)))/a(it) = l(t) + (rup(i)-L(i))/a(it)
+
+  Notice that if there's a single infinite contribution to L(i) or U(i) and it
+  comes from x(t), then the finite portion finDowni or finUpi is correct and
+  finite.
+
+  Start by calculating new l(t) against rlo(i) and U(i). If the change is
+  large, put some slack in the bound.
+*/
+
+	if (ait > 0.0) {
+	  if (rloi > -large) {
+	    if (!infUpi) {
+	      assert(ut < large2) ;
+	      newlt = ut+(rloi-finUpi)/ait ;
+	      if (fabs(finUpi) > 1.0e8)
+		newlt -= 1.0e-12*fabs(finUpi) ;
+	    } else if (infUpi == 1 && ut >= large) {
+	      newlt = (rloi-finUpi)/ ait ;
+	      if (fabs(finUpi) > 1.0e8)
+		newlt -= 1.0e-12*fabs(finUpi) ;
+	    } else {
+	      newlt = -COIN_DBL_MAX ;
+	    }
+/*
+  Did we improve the bound? If we're infeasible, head for the exit. If we're
+  still feasible, walk the column and reset the marks on the entangled rows
+  so that the activity bounds will be recalculated. Mark this constraint
+  so we don't use it again, and correct L(i).
+*/
+	    if (newlt > lt+1.0e-12 && newlt > -large) {
+	      if (ut-newlt < -relaxedTol) {
+		numberInfeasible++ ;
+		break ;
+	      }
+	      columnLower[t] = newlt ;
+	      markRow[i] = markIgnore ;
+	      numberChanged++ ;
+	      const CoinBigIndex kcs = colStarts[t] ;
+	      const CoinBigIndex kce = kcs+colLengths[t] ;
+	      for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
+		const int k = rowIndices[kcol] ;
+		if (markRow[k] == markActOK) {
+		  markRow[k] = markInPlay ;
+		}
+	      }
+	      if (lt <= -large) {
+		finDowni += newlt*ait ;
+		infLoi-- ;
+	      } else {
+		finDowni += (newlt-lt)*ait ;
+	      }
+	      lt = newlt ;
+	    }
+	  }
+/*
+  Perform the same actions, for new u(t) against rup(i) and L(i).
+*/
+	  if (rupi < large) {
+	    if (!infLoi) {
+	      assert(lt >- large2) ;
+	      newut = lt+(rupi-finDowni)/ait ;
+	      if (fabs(finDowni) > 1.0e8)
+		newut += 1.0e-12*fabs(finDowni) ;
+	    } else if (infLoi == 1 && lt <= -large) {
+	      newut = (rupi-finDowni)/ait ;
+	      if (fabs(finDowni) > 1.0e8)
+		newut += 1.0e-12*fabs(finDowni) ;
+	    } else {
+	      newut = COIN_DBL_MAX ;
+	    }
+	    if (newut < ut-1.0e-12 && newut < large) {
+	      columnUpper[t] = newut ;
+	      if (newut-lt < -relaxedTol) {
+		numberInfeasible++ ;
+		break ;
+	      }
+	      markRow[i] = markIgnore ;
+	      numberChanged++ ;
+	      const CoinBigIndex kcs = colStarts[t] ;
+	      const CoinBigIndex kce = kcs+colLengths[t] ;
+	      for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
+		const int k = rowIndices[kcol] ;
+		if (markRow[k] == markActOK) {
+		  markRow[k] = markInPlay ;
+		}
+	      }
+	      if (ut >= large) {
+		finUpi += newut*ait ;
+		infUpi-- ;
+	      } else {
+		finUpi += (newut-ut)*ait ;
+	      }
+	      ut = newut ;
+	    }
+	  }
+	} else {
+/*
+  And repeat both sets with the appropriate flips for a(it) < 0.
+*/
+	  if (rloi > -large) {
+	    if (!infUpi) {
+	      assert(lt < large2) ;
+	      newut = lt+(rloi-finUpi)/ait ;
+	      if (fabs(finUpi) > 1.0e8)
+		newut += 1.0e-12*fabs(finUpi) ;
+	    } else if (infUpi == 1 && lt <= -large) {
+	      newut = (rloi-finUpi)/ait ;
+	      if (fabs(finUpi) > 1.0e8)
+		newut += 1.0e-12*fabs(finUpi) ;
+	    } else {
+	      newut = COIN_DBL_MAX ;
+	    }
+	    if (newut < ut-1.0e-12 && newut < large) {
+	      columnUpper[t] = newut  ;
+	      if (newut-lt < -relaxedTol) {
+		numberInfeasible++ ;
+		break ;
+	      }
+	      markRow[i] = markIgnore ;
+	      numberChanged++ ;
+	      const CoinBigIndex kcs = colStarts[t] ;
+	      const CoinBigIndex kce = kcs+colLengths[t] ;
+	      for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
+		const int k = rowIndices[kcol] ;
+		if (markRow[k] == markActOK) {
+		  markRow[k] = markInPlay ;
+		}
+	      }
+	      if (ut >= large) {
+		finDowni += newut*ait ;
+		infLoi-- ;
+	      } else {
+		finDowni += (newut-ut)*ait ;
+	      }
+	      ut = newut  ;
+	    }
+	  }
+	  if (rupi < large) {
+	    if (!infLoi) {
+	      assert(ut < large2) ;
+	      newlt = ut+(rupi-finDowni)/ait ;
+	      if (fabs(finDowni) > 1.0e8)
+		newlt -= 1.0e-12*fabs(finDowni) ;
+	    } else if (infLoi == 1 && ut >= large) {
+	      newlt = (rupi-finDowni)/ait ;
+	      if (fabs(finDowni) > 1.0e8)
+		newlt -= 1.0e-12*fabs(finDowni) ;
+	    } else {
+	      newlt = -COIN_DBL_MAX ;
+	    }
+	    if (newlt > lt+1.0e-12 && newlt > -large) {
+	      columnLower[t] = newlt ;
+	      if (ut-newlt < -relaxedTol) {
+		numberInfeasible++ ;
+		break ;
+	      }
+	      markRow[i] = markIgnore ;
+	      numberChanged++ ;
+	      const CoinBigIndex kcs = colStarts[t] ;
+	      const CoinBigIndex kce = kcs+colLengths[t] ;
+	      for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
+		const int k = rowIndices[kcol] ;
+		if (markRow[k] == markActOK) {
+		  markRow[k] = markInPlay ;
+		}
+	      }
+	      if (lt <= -large) {
+		finUpi += newlt*ait ;
+		infUpi-- ;
+	      } else {
+		finUpi += (newlt-lt)*ait ;
+	      }
+	      lt = newlt ;
+	    }
+	  }
+	}
+      }
+    }
+
+    totalTightened += numberChanged ;
+    if (iPass == 1)
+      numberCheck = CoinMax(10,numberChanged>>5) ;
+    if (numberInfeasible) {
+      prob->status_ = 1 ;
+      break ;
+    }
+  }
+/*
+  At this point, we have rows marked with markIgnore, markInPlay, and
+  markActOK. Rows marked with markIgnore may have been used to tighten the
+  column bound on some variable, hence they are necessary. (Or they may
+  have been marked in the initial scan, in which case they're already on
+  the useless list or empty.)  Rows marked with markInPlay or markActOK
+  are candidates for forcing or useless constraints.
+*/
+  if (!numberInfeasible) {
+/*
+  Open a loop to scan the rows again looking for useless constraints.
+*/
+    for (int i = 0 ; i < m ; i++) {
+      
+      if (markRow[i] == markIgnore) continue ;
+/*
+  Recalculate L(i) and U(i).
+
+  LOU: Arguably this would not be necessary if we saved L(i) and U(i).
+*/
+      int infUpi = 0 ;
+      int infLoi = 0 ;
+      double finUpi = 0.0 ;
+      double finDowni = 0.0 ;
+      const CoinBigIndex krs = rowStarts[i] ;
+      const CoinBigIndex kre = krs+rowLengths[i] ;
+
+      for (CoinBigIndex krow = krs; krow < kre; ++krow) {
+	const double value = rowCoeffs[krow] ;
+	const int j = colIndices[krow] ;
+	if (value > 0.0) {
+	  if (columnUpper[j] < large) 
+	    finUpi += columnUpper[j] * value ;
+	  else
+	    ++infUpi ;
+	  if (columnLower[j] > -large) 
+	    finDowni += columnLower[j] * value ;
+	  else
+	    ++infLoi ;
+	} else if (value<0.0) {
+	  if (columnUpper[j] < large) 
+	    finDowni += columnUpper[j] * value ;
+	  else
+	    ++infLoi ;
+	  if (columnLower[j] > -large) 
+	    finUpi += columnLower[j] * value ;
+	  else
+	    ++infUpi ;
+	}
+      }
+      finUpi += 1.0e-8*fabs(finUpi) ;
+      finDowni -= 1.0e-8*fabs(finDowni) ;
+      const double maxUpi = finUpi+infUpi*1.0e31 ;
+      const double maxDowni = finDowni-infLoi*1.0e31 ;
+/*
+  If we have L(i) and U(i) at or inside the row bounds, we have a useless
+  constraint.
+
+  You would think we could detect forcing constraints here but that's a bit of
+  a problem, because the tightened column bounds we're working with will not
+  escape this routine.
+*/
+      if (maxUpi <= rup[i]+feasTol && maxDowni >= rlo[i]-feasTol) {
+	useless_rows[nuseless_rows++] = i ;
+      }
+    }
+
+    if (nuseless_rows) {
+      next = useless_constraint_action::presolve(prob,
+						 useless_rows,nuseless_rows,
+						 next) ;
+    }
+/*
+  See if we can transfer tightened bounds from the work above. This is
+  problematic. When we loosen these bounds in postsolve it's entirely possible
+  that the variable will end up superbasic.
+
+  Original comment: may not unroll
+*/
+    if (prob->presolveOptions_&0x10) {
+      const unsigned char *integerType = prob->integerType_ ;
+      double *csol  = prob->sol_ ;
+      double *clo = prob->clo_ ;
+      double *cup = prob->cup_ ;
+      int *fixed = prob->usefulColumnInt_ ;
+      int nFixed = 0 ;
+      int nChanged = 0 ;
+      for (int j = 0 ; j < n ; j++) {
+	if (clo[j] == cup[j])
+	  continue ;
+	double lower = columnLower[j] ;
+	double upper = columnUpper[j] ;
+	if (integerType[j]) {
+	  upper = floor(upper+1.0e-4) ;
+	  lower = ceil(lower-1.0e-4) ;
+	}
+	if (upper-lower < 1.0e-8) {
+	  if (upper-lower < -feasTol)
+	    numberInfeasible++ ;
+	  if (CoinMin(fabs(upper),fabs(lower)) <= 1.0e-7) 
+	    upper = 0.0 ;
+	  fixed[nFixed++] = j ;
+	  prob->addCol(j) ;
+	  cup[j] = upper ;
+	  clo[j] = upper ;
+	  if (csol != 0) 
+	    csol[j] = upper ;
+	} else {
+	  if (integerType[j]) {
+	    if (upper < cup[j]) {
+	      cup[j] = upper ;
+	      nChanged++ ;
+	      prob->addCol(j) ;
+	    }
+	    if (lower > clo[j]) {
+	      clo[j] = lower ;
+	      nChanged++ ;
+	      prob->addCol(j) ;
+	    }
+	  }
+	}
+      }
+#     ifdef CLP_INVESTIGATE
+      if (nFixed||nChanged)
+	printf("%d fixed in impliedfree, %d changed\n",nFixed,nChanged) ;
+#     endif
+      if (nFixed)
+	next = remove_fixed_action::presolve(prob,fixed,nFixed,next) ; 
+    }
+  }
+
+  delete [] columnLower ;
+  delete [] columnUpper ;
+
+# if COIN_PRESOLVE_TUNING > 0
+  double thisTime ;
+  if (prob->tuning_) thisTime = CoinCpuTime() ;
+# endif
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
+  std::cout << "Leaving testRedundant, " << droppedRows << " rows dropped" ;
+# if COIN_PRESOLVE_TUNING > 0
+  std::cout << " in " << thisTime-startTime << "s" ;
+# endif
+  std::cout << "." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+
+
+
+
+
+// WHAT HAPPENS IF COLS ARE DROPPED AS A RESULT??
+// should be like do_tighten.
+// not really - one could fix costed variables to appropriate bound.
+// ok, don't bother about it.  If it is costed, it will be checked
+// when it is eliminated as an empty col; if it is costed in the
+// wrong direction, the problem is unbounded, otherwise it is pegged
+// at its bound.  no special action need be taken here.
+const CoinPresolveAction *useless_constraint_action::presolve(CoinPresolveMatrix * prob,
+								  const int *useless_rows,
+								  int nuseless_rows,
+				       const CoinPresolveAction *next)
+{
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering useless_constraint_action::presolve, "
+    << nuseless_rows << " rows." << std::endl ;
+# endif
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  // may be modified by useless constraint
+  double *colels	= prob->colels_;
+
+  // may be modified by useless constraint
+        int *hrow	= prob->hrow_;
+
+  const CoinBigIndex *mcstrt	= prob->mcstrt_;
+
+  // may be modified by useless constraint
+        int *hincol	= prob->hincol_;
+
+	//  double *clo	= prob->clo_;
+	//  double *cup	= prob->cup_;
+
+  const double *rowels	= prob->rowels_;
+  const int *hcol	= prob->hcol_;
+  const CoinBigIndex *mrstrt	= prob->mrstrt_;
+
+  // may be written by useless constraint
+        int *hinrow	= prob->hinrow_;
+	//  const int nrows	= prob->nrows_;
+
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  action *actions	= new action [nuseless_rows];
+
+  for (int i=0; i<nuseless_rows; ++i) {
+    int irow = useless_rows[i];
+#   if PRESOLVE_DEBUG > 2
+    std::cout << "  removing row " << irow << std::endl ;
+#   endif
+    CoinBigIndex krs = mrstrt[irow];
+    CoinBigIndex kre = krs + hinrow[irow];
+    PRESOLVE_DETAIL_PRINT(printf("pre_useless %dR E\n",irow));
+
+    action *f = &actions[i];
+
+    f->row = irow;
+    f->ninrow = hinrow[irow];
+    f->rlo = rlo[irow];
+    f->rup = rup[irow];
+    f->rowcols = CoinCopyOfArray(&hcol[krs], hinrow[irow]);
+    f->rowels  = CoinCopyOfArray(&rowels[krs], hinrow[irow]);
+
+    for (CoinBigIndex k=krs; k<kre; k++)
+    { presolve_delete_from_col(irow,hcol[k],mcstrt,hincol,hrow,colels) ;
+      if (hincol[hcol[k]] == 0)
+      { PRESOLVE_REMOVE_LINK(prob->clink_,hcol[k]) ; } }
+    hinrow[irow] = 0;
+    PRESOLVE_REMOVE_LINK(prob->rlink_,irow) ;
+
+    // just to make things squeeky
+    rlo[irow] = 0.0;
+    rup[irow] = 0.0;
+  }
+
+  next = new useless_constraint_action(nuseless_rows,actions,next) ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving useless_constraint_action::presolve." << std::endl ;
+# endif
+# endif
+
+  return (next) ;
+}
+
+// Put constructors here
+useless_constraint_action::useless_constraint_action(int nactions,
+                                                     const action *actions,
+                                                     const CoinPresolveAction *next) 
+  :   CoinPresolveAction(next),
+      nactions_(nactions),
+      actions_(actions)
+{}
+useless_constraint_action::~useless_constraint_action() 
+{
+  for (int i=0;i<nactions_;i++) {
+    deleteAction(actions_[i].rowcols, int *);
+    deleteAction(actions_[i].rowels, double *);
+  }
+  deleteAction(actions_, action *);
+}
+
+const char *useless_constraint_action::name() const
+{
+  return ("useless_constraint_action");
+}
+
+void useless_constraint_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const action *const actions = actions_;
+  const int nactions = nactions_;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering useless_constraint_action::postsolve, "
+    << nactions << " rows." << std::endl ;
+# endif
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+  double *colels	= prob->colels_;
+  int *hrow		= prob->hrow_;
+  CoinBigIndex *mcstrt		= prob->mcstrt_;
+  int *link		= prob->link_;
+  int *hincol		= prob->hincol_;
+  
+  //  double *rowduals	= prob->rowduals_;
+  double *rowacts	= prob->acts_;
+  const double *sol	= prob->sol_;
+
+
+  CoinBigIndex &free_list		= prob->free_list_;
+
+  double *rlo	= prob->rlo_;
+  double *rup	= prob->rup_;
+
+  for (const action *f = &actions[nactions-1]; actions<=f; f--) {
+
+    int irow	= f->row;
+    int ninrow	= f->ninrow;
+    const int *rowcols	= f->rowcols;
+    const double *rowels = f->rowels;
+    double rowact = 0.0;
+
+    rup[irow] = f->rup;
+    rlo[irow] = f->rlo;
+
+    for (CoinBigIndex k=0; k<ninrow; k++) {
+      int jcol = rowcols[k];
+      //      CoinBigIndex kk = mcstrt[jcol];
+
+      // append deleted row element to each col
+      {
+	CoinBigIndex kk = free_list;
+	assert(kk >= 0 && kk < prob->bulk0_) ;
+	free_list = link[free_list];
+	hrow[kk] = irow;
+	colels[kk] = rowels[k];
+	link[kk] = mcstrt[jcol];
+	mcstrt[jcol] = kk;
+      }
+      
+      rowact += rowels[k] * sol[jcol];
+      hincol[jcol]++;
+    }
+#   if PRESOLVE_CONSISTENCY
+    presolve_check_free_list(prob) ;
+#   endif
+    
+    // I don't know if this is always true
+    PRESOLVEASSERT(prob->getRowStatus(irow)==CoinPrePostsolveMatrix::basic);
+    // rcosts are unaffected since rowdual is 0
+
+    rowacts[irow] = rowact;
+    // leave until desctructor
+    //deleteAction(rowcols,int *);
+    //deleteAction(rowels,double *);
+  }
+
+  //deleteAction(actions_,action *);
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  presolve_check_threads(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Leaving useless_constraint_action::postsolve." << std::endl ;
+# endif
+# endif
+
+}
diff --git a/cbits/coin/CoinPresolveUseless.hpp b/cbits/coin/CoinPresolveUseless.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveUseless.hpp
@@ -0,0 +1,63 @@
+/* $Id: CoinPresolveUseless.hpp 1566 2012-11-29 19:33:56Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveUseless_H
+#define CoinPresolveUseless_H
+#define	USELESS		20
+
+class useless_constraint_action : public CoinPresolveAction {
+  struct action {
+    double rlo;
+    double rup;
+    const int *rowcols;
+    const double *rowels;
+    int row;
+    int ninrow;
+  };
+
+  const int nactions_;
+  const action *const actions_;
+
+  useless_constraint_action(int nactions,
+                            const action *actions,
+                            const CoinPresolveAction *next);
+
+ public:
+  const char *name() const;
+
+  // These rows are asserted to be useless,
+  // that is, given a solution the row activity
+  // must be in range.
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix * prob,
+					 const int *useless_rows,
+					 int nuseless_rows,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~useless_constraint_action();
+
+};
+
+/*! \relates useless_constraint_action
+    \brief Scan constraints looking for useless constraints
+
+  A front end to identify useless constraints and hand them to
+  useless_constraint_action::presolve() for processing.
+
+  In a bit more detail, the routine implements a greedy algorithm that
+  identifies a set of necessary constraints. A constraint is necessary if it
+  implies a tighter bound on a variable than the original column bound. These
+  tighter column bounds are then used to calculate row activity and identify
+  constraints that are useless given the presence of the necessary
+  constraints. 
+*/
+
+const CoinPresolveAction *testRedundant(CoinPresolveMatrix *prob,
+					const CoinPresolveAction *next) ;
+
+
+
+#endif
diff --git a/cbits/coin/CoinPresolveZeros.cpp b/cbits/coin/CoinPresolveZeros.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveZeros.cpp
@@ -0,0 +1,332 @@
+/* $Id: CoinPresolveZeros.cpp 1561 2012-11-24 00:32:16Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stdio.h>
+#include <math.h>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinPresolveMatrix.hpp"
+#include "CoinPresolveZeros.hpp"
+
+#if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+#include "CoinPresolvePsdebug.hpp"
+#endif
+
+namespace {	// begin unnamed file-local namespace
+
+/*
+  Count the number of zeros in the columns listed in checkcols. Trim back
+  checkcols to just the columns with zeros.
+*/
+int count_col_zeros (int &ncheckcols, int *checkcols,
+		     const CoinBigIndex *mcstrt, const double *colels,
+		     const int *hincol)
+{
+  int nzeros = 0 ;
+  int zeroCols = 0 ;
+
+  for (int ndx = 0 ; ndx < ncheckcols ; ndx++) {
+    const int j = checkcols[ndx] ;
+    const CoinBigIndex kcs = mcstrt[j] ;
+    const CoinBigIndex kce = kcs+hincol[j] ;
+    int zerosj = 0 ;
+
+    for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) {
+      if (fabs(colels[kcol]) < ZTOLDP) {
+	zerosj++ ;
+      }
+    }
+    if (zerosj) {
+      checkcols[zeroCols++] = j ;
+      nzeros += zerosj ;
+    }
+  }
+  ncheckcols = zeroCols ;
+  return (nzeros) ;
+}
+
+/*
+  Count the number of zeros. Intended for the case where all columns 0 ..
+  ncheckcols should be scanned. Typically ncheckcols is the number of columns
+  in the matrix. Leave a list of columns with explicit zeros at the front of
+  checkcols, with the count in ncheckcols.
+*/
+int count_col_zeros2 (int &ncheckcols, int *checkcols,
+		      const CoinBigIndex *mcstrt, const double *colels,
+		      const int *hincol)
+{
+  int nzeros = 0 ;
+  int zeroCols = 0 ;
+
+  for (int j = 0 ; j < ncheckcols ; j++) {
+    const CoinBigIndex kcs = mcstrt[j] ;
+    CoinBigIndex kce = kcs+hincol[j] ;
+
+    int zerosj = 0 ;
+    for (CoinBigIndex k = kcs ; k < kce ; ++k) {
+      if (fabs(colels[k]) < ZTOLDP) {
+        zerosj++ ;
+      }
+    }
+    if (zerosj) {
+      checkcols[zeroCols++] = j ;
+      nzeros += zerosj ;
+    }
+  }
+  ncheckcols = zeroCols ;
+  return (nzeros) ;
+}
+
+/*
+  Searches the cols in checkcols for zero entries.
+  Creates a dropped_zero entry for each one; doesn't check for out-of-memory.
+  Returns number of zeros found.
+*/
+int drop_col_zeros (int ncheckcols, const int *checkcols,
+		    const CoinBigIndex *mcstrt, double *colels, int *hrow,
+		    int *hincol, presolvehlink *clink,
+		    dropped_zero *actions)
+{
+  int nactions = 0 ;
+
+/*
+  Physically remove explicit zeros. To maintain loose packing, move the
+  element at the end of the column into the empty space. Of course, that
+  element could also be zero, so recheck the position.
+*/
+  for (int i = 0 ; i < ncheckcols ; i++) {
+    int col = checkcols[i] ;
+    const CoinBigIndex kcs = mcstrt[col] ;
+    CoinBigIndex kce = kcs+hincol[col] ;
+
+#   if PRESOLVE_DEBUG > 1
+    std::cout << "  scanning column " << col << "..." ;
+#   endif
+
+    for (CoinBigIndex k = kcs ; k < kce ; ++k) {
+      if (fabs(colels[k]) < ZTOLDP) {
+	actions[nactions].col = col ;
+	actions[nactions].row = hrow[k] ;
+
+#       if PRESOLVE_DEBUG > 2
+	std::cout << " (" << hrow[k] << "," << col << ") " ;
+#       endif
+
+	nactions++ ;
+
+	kce-- ;
+	colels[k] = colels[kce] ;
+	hrow[k] = hrow[kce] ;
+	hincol[col]-- ;
+
+	--k ;
+      }
+    }
+#   if PRESOLVE_DEBUG > 1
+    if (nactions)
+      std::cout << std::endl ;
+#   endif
+
+    if (hincol[col] == 0)
+      PRESOLVE_REMOVE_LINK(clink,col) ;
+  }
+  return (nactions) ;
+}
+
+/*
+  Scan rows to remove explicit zeros.
+
+  This will, in general, scan a row once for each explicit zero in the row,
+  but will remove all zeros the first time through. It's tempting to try and
+  do something about this, but given the relatively small number of explicit
+  zeros created by presolve, the bookkeeping likely exceeds the gain.
+*/
+void drop_row_zeros(int nzeros, const dropped_zero *zeros,
+		    const CoinBigIndex *mrstrt, double *rowels, int *hcol,
+		    int *hinrow, presolvehlink *rlink)
+{
+  for (int i = 0 ; i < nzeros ; i++) {
+    int row = zeros[i].row ;
+    const CoinBigIndex krs = mrstrt[row] ;
+    CoinBigIndex kre = krs+hinrow[row] ;
+
+#   if PRESOLVE_DEBUG > 2
+    std::cout
+      << "  scanning row " << row <<  " for a(" << row << "," << zeros[i].col
+      << ") ..." ;
+    bool found = false ;
+#   endif
+
+    for (CoinBigIndex k = krs ; k < kre ; k++) {
+      if (fabs(rowels[k]) < ZTOLDP) {
+
+#       if PRESOLVE_DEBUG > 2
+	std::cout << " (" << row << "," << hcol[k] << ") " ;
+        found = true ;
+#       endif
+
+	rowels[k] = rowels[kre-1] ;
+	hcol[k] = hcol[kre-1] ;
+	kre-- ;
+	hinrow[row]-- ;
+
+	--k ;
+      }
+    }
+
+#   if PRESOLVE_DEBUG > 2
+    if (found)
+      std::cout
+        << " found; " << hinrow[row] << " coeffs remaining." << std::endl ;
+#   endif
+
+    if (hinrow[row] == 0)
+      PRESOLVE_REMOVE_LINK(rlink,row) ;
+  }
+}
+
+}	// end unnamed file-local namespace
+
+/*
+  Scan the columns listed in checkcols for explicit zeros and eliminate them.
+
+  For the special case where all columns should be scanned (ncheckcols ==
+  prob->ncols_), there is no need to initialise checkcols.
+*/
+const CoinPresolveAction
+  *drop_zero_coefficients_action::presolve (CoinPresolveMatrix *prob,
+					    int *checkcols,
+					    int ncheckcols,
+					    const CoinPresolveAction *next)
+{
+  double *colels = prob->colels_ ;
+  int *hrow = prob->hrow_ ;
+  CoinBigIndex *mcstrt = prob->mcstrt_ ;
+  int *hincol = prob->hincol_ ;
+  presolvehlink *clink = prob->clink_ ;
+  presolvehlink *rlink = prob->rlink_ ;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+# if PRESOLVE_DEBUG > 0
+  std::cout
+    << "Entering drop_zero_action::presolve, " << ncheckcols
+    << " columns to scan." << std::endl ;
+# endif
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+
+/*
+  Scan for zeros.
+*/
+  int nzeros ;
+  if (ncheckcols == prob->ncols_) {
+    nzeros = count_col_zeros2(ncheckcols,checkcols,mcstrt,colels,hincol) ;
+  } else {
+    nzeros = count_col_zeros(ncheckcols,checkcols,mcstrt,colels,hincol) ;
+  }
+# if PRESOLVE_DEBUG > 1
+  std::cout
+    << "  drop_zero_action: " << nzeros << " zeros in " << ncheckcols
+    << " columns." << std::endl ;
+# endif
+/*
+  Do we have zeros to remove? If so, get to it.
+*/
+  if (nzeros != 0) {
+/*
+  We have zeros to remove. drop_col_zeros will scan the columns and remove
+  zeros, adding records of the dropped entries to zeros. The we need to clean
+  the row representation.
+*/
+    dropped_zero *zeros = new dropped_zero[nzeros] ;
+
+    nzeros = drop_col_zeros(ncheckcols,checkcols,mcstrt,colels,
+    			    hrow,hincol,clink,zeros) ;
+
+    double *rowels = prob->rowels_ ;
+    int *hcol = prob->hcol_ ;
+    CoinBigIndex *mrstrt = prob->mrstrt_ ;
+    int *hinrow = prob->hinrow_ ;
+    drop_row_zeros(nzeros,zeros,mrstrt,rowels,hcol,hinrow,rlink) ;
+    next = new drop_zero_coefficients_action(nzeros,zeros,next) ;
+  }
+
+# if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
+  presolve_consistent(prob) ;
+  presolve_links_ok(prob) ;
+  presolve_check_sol(prob) ;
+  presolve_check_nbasic(prob) ;
+# endif
+# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
+  std::cout
+    << "Leaving drop_zero_action::presolve, dropped " << nzeros
+    << " zeroes." << std::endl ;
+# endif
+
+  return (next) ;
+}
+
+
+/*
+  This wrapper initialises checkcols for the case where the entire matrix
+  should be scanned. Typically used from the presolve driver as part of final
+  cleanup.
+*/
+const CoinPresolveAction
+  *drop_zero_coefficients (CoinPresolveMatrix *prob,
+			   const CoinPresolveAction *next)
+{
+  int ncheck = prob->ncols_ ;
+  int *checkcols = new int[ncheck] ;
+
+  if (prob->anyProhibited()) {
+    ncheck = 0 ;
+    for (int i = 0 ; i < prob->ncols_ ; i++)
+      if (!prob->colProhibited(i))
+	checkcols[ncheck++] = i ;
+  }
+
+  const CoinPresolveAction *retval =
+      drop_zero_coefficients_action::presolve(prob,checkcols,ncheck,next) ;
+
+  delete [] checkcols ;
+  return (retval) ;
+}
+
+void drop_zero_coefficients_action::postsolve(CoinPostsolveMatrix *prob) const
+{
+  const int nzeros = nzeros_ ;
+  const dropped_zero *const zeros = zeros_ ;
+
+  double *colels = prob->colels_ ;
+  int *hrow = prob->hrow_ ;
+  CoinBigIndex *mcstrt = prob->mcstrt_ ;
+  int *hincol = prob->hincol_ ;
+  int *link = prob->link_ ;
+  CoinBigIndex &free_list = prob->free_list_ ;
+
+  for (const dropped_zero *z = &zeros[nzeros-1] ; zeros <= z ; z--) {
+    const int i = z->row ;
+    const int j = z->col ;
+
+    CoinBigIndex k = free_list ;
+    assert(k >= 0 && k < prob->bulk0_) ;
+    free_list = link[free_list] ;
+    hrow[k] = i ;
+    colels[k] = 0.0 ;
+    link[k] = mcstrt[j] ;
+    mcstrt[j] = k ;
+
+    hincol[j]++ ;
+  }
+
+# if PRESOLVE_CONSISTENCY > 0
+  presolve_check_free_list(prob) ;
+# endif
+
+}
diff --git a/cbits/coin/CoinPresolveZeros.hpp b/cbits/coin/CoinPresolveZeros.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinPresolveZeros.hpp
@@ -0,0 +1,60 @@
+/* $Id: CoinPresolveZeros.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinPresolveZeros_H
+#define CoinPresolveZeros_H
+
+/*! \file
+
+  Drop/reintroduce explicit zeros.
+*/
+
+#define	DROP_ZERO	8
+
+/*! \brief Tracking information for an explicit zero coefficient
+
+  \todo Why isn't this a nested class in drop_zero_coefficients_action?
+	That would match the structure of other presolve classes.
+*/
+
+struct dropped_zero {
+  int row;
+  int col;
+};
+
+/*! \brief Removal of explicit zeros
+
+  The presolve action for this class removes explicit zeros from the constraint
+  matrix. The postsolve action puts them back.
+*/
+class drop_zero_coefficients_action : public CoinPresolveAction {
+
+  const int nzeros_;
+  const dropped_zero *const zeros_;
+
+  drop_zero_coefficients_action(int nzeros,
+				const dropped_zero *zeros,
+				const CoinPresolveAction *next) :
+    CoinPresolveAction(next),
+    nzeros_(nzeros), zeros_(zeros)
+{}
+
+ public:
+  const char *name() const { return ("drop_zero_coefficients_action"); }
+
+  static const CoinPresolveAction *presolve(CoinPresolveMatrix *prob,
+					 int *checkcols,
+					 int ncheckcols,
+					 const CoinPresolveAction *next);
+
+  void postsolve(CoinPostsolveMatrix *prob) const;
+
+  virtual ~drop_zero_coefficients_action() { deleteAction(zeros_,dropped_zero*); }
+};
+
+const CoinPresolveAction *drop_zero_coefficients(CoinPresolveMatrix *prob,
+					      const CoinPresolveAction *next);
+
+#endif
diff --git a/cbits/coin/CoinSearchTree.cpp b/cbits/coin/CoinSearchTree.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinSearchTree.cpp
@@ -0,0 +1,109 @@
+/* $Id: CoinSearchTree.cpp 1590 2013-04-10 16:48:33Z stefan $ */
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdio>
+#include "CoinSearchTree.hpp"
+
+BitVector128::BitVector128()
+{
+  bits_[0] = 0;
+  bits_[1] = 0;
+  bits_[2] = 0;
+  bits_[3] = 0;
+}
+
+BitVector128::BitVector128(unsigned int bits[4])
+{
+   set(bits);
+}
+
+void
+BitVector128::set(unsigned int bits[4])
+{
+   bits_[0] = bits[0];
+   bits_[1] = bits[1];
+   bits_[2] = bits[2];
+   bits_[3] = bits[3];
+}
+
+void
+BitVector128::setBit(int i)
+{
+  int byte = i >> 5;
+  int bit = i & 31;
+  bits_[byte] |= (1 << bit);
+}
+  
+void
+BitVector128::clearBit(int i)
+{
+  int byte = i >> 5;
+  int bit = i & 31;
+  bits_[byte] &= ~(1 << bit);
+}
+
+std::string
+BitVector128::str() const
+{
+  char output[33];
+  output[32] = 0;
+  sprintf(output, "%08X%08X%08X%08X",
+	  bits_[3], bits_[2], bits_[1], bits_[0]);
+  return output;
+}
+  
+bool
+operator<(const BitVector128& b0, const BitVector128& b1)
+{
+  if (b0.bits_[3] < b1.bits_[3])
+    return true;
+  if (b0.bits_[3] > b1.bits_[3])
+    return false;
+  if (b0.bits_[2] < b1.bits_[2])
+    return true;
+  if (b0.bits_[2] > b1.bits_[2])
+    return false;
+  if (b0.bits_[1] < b1.bits_[1])
+    return true;
+  if (b0.bits_[1] > b1.bits_[1])
+    return false;
+  return (b0.bits_[0] < b1.bits_[0]);
+}
+
+void
+CoinSearchTreeManager::newSolution(double solValue)
+{
+    ++numSolution;
+    hasUB_ = true;
+    CoinTreeNode* top = candidates_->top();
+    const double q = top ? top->getQuality() : solValue;
+    const bool switchToDFS = fabs(q) < 1e-3 ?
+	(fabs(solValue) < 0.005) : ((solValue-q)/fabs(q) < 0.005);
+    if (switchToDFS &&
+	dynamic_cast<CoinSearchTree<CoinSearchTreeCompareDepth>*>(candidates_) == NULL) {
+	CoinSearchTree<CoinSearchTreeCompareDepth>* cands =
+	    new CoinSearchTree<CoinSearchTreeCompareDepth>(*candidates_);
+	delete candidates_;
+	candidates_ = cands;
+    }
+}
+
+void
+CoinSearchTreeManager::reevaluateSearchStrategy()
+{
+    const int n = candidates_->numInserted() % 1000;
+    /* the tests below ensure that even if this method is not invoked after
+       every push(), the search strategy will be reevaluated when n is ~500 */
+    if (recentlyReevaluatedSearchStrategy_) {
+	if (n > 250 && n <= 500) {
+	    recentlyReevaluatedSearchStrategy_ = false;
+	}
+    } else {
+	if (n > 500) {
+	    recentlyReevaluatedSearchStrategy_ = true;
+	    /* we can reevaluate things... */
+	}
+    }
+}
diff --git a/cbits/coin/CoinSearchTree.hpp b/cbits/coin/CoinSearchTree.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinSearchTree.hpp
@@ -0,0 +1,465 @@
+/* $Id: CoinSearchTree.hpp 1590 2013-04-10 16:48:33Z stefan $ */
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinSearchTree_H
+#define CoinSearchTree_H
+
+#include <vector>
+#include <algorithm>
+#include <cmath>
+#include <string>
+
+#include "CoinFinite.hpp"
+#include "CoinHelperFunctions.hpp"
+
+// #define DEBUG_PRINT
+
+//#############################################################################
+
+class BitVector128 {
+  friend bool operator<(const BitVector128& b0, const BitVector128& b1);
+private:
+  unsigned int bits_[4];
+public:
+  BitVector128();
+  BitVector128(unsigned int bits[4]);
+  ~BitVector128() {}
+  void set(unsigned int bits[4]);
+  void setBit(int i);
+  void clearBit(int i);
+  std::string str() const;
+};
+
+bool operator<(const BitVector128& b0, const BitVector128& b1);
+
+//#############################################################################
+
+/** A class from which the real tree nodes should be derived from. Some of the
+    data that undoubtedly exist in the real tree node is replicated here for
+    fast access. This class is used in the various comparison functions. */
+class CoinTreeNode {
+protected:
+    CoinTreeNode() :
+	depth_(-1),
+	fractionality_(-1),
+	quality_(-COIN_DBL_MAX),
+	true_lower_bound_(-COIN_DBL_MAX),
+	preferred_() {}
+    CoinTreeNode(int d,
+		 int f = -1,
+		 double q = -COIN_DBL_MAX,
+		 double tlb = -COIN_DBL_MAX,
+		 BitVector128 p = BitVector128()) :
+	depth_(d),
+	fractionality_(f),
+	quality_(q),
+	true_lower_bound_(tlb),
+	preferred_(p) {}
+    CoinTreeNode(const CoinTreeNode& x) :
+	depth_(x.depth_),
+	fractionality_(x.fractionality_),
+	quality_(x.quality_),
+	true_lower_bound_(x.true_lower_bound_),
+	preferred_(x.preferred_) {}
+    CoinTreeNode& operator=(const CoinTreeNode& x) {
+        if (this != &x) {
+	  depth_ = x.depth_;
+	  fractionality_ = x.fractionality_;
+	  quality_ = x.quality_;
+	  true_lower_bound_ = x.true_lower_bound_;
+	  preferred_ = x.preferred_;
+	}
+	return *this;
+    }
+private:
+    /// The depth of the node in the tree
+    int depth_;
+    /** A measure of fractionality, e.g., the number of unsatisfied
+	integrality requirements */
+    int fractionality_;
+    /** Some quality for the node. For normal branch-and-cut problems the LP
+	relaxation value will do just fine. It is probably an OK approximation
+	even if column generation is done. */
+    double quality_;
+    /** A true lower bound on the node. May be -infinity. For normal
+	branch-and-cut problems the LP relaxation value is OK. It is different
+	when column generation is done. */
+    double true_lower_bound_;
+    /** */
+    BitVector128 preferred_;
+public:
+    virtual ~CoinTreeNode() {}
+
+    inline int          getDepth()         const { return depth_; }
+    inline int          getFractionality() const { return fractionality_; }
+    inline double       getQuality()       const { return quality_; }
+    inline double       getTrueLB()        const { return true_lower_bound_; }
+    inline BitVector128 getPreferred()     const { return preferred_; }
+    
+    inline void setDepth(int d)              { depth_ = d; }
+    inline void setFractionality(int f)      { fractionality_ = f; }
+    inline void setQuality(double q)         { quality_ = q; }
+    inline void setTrueLB(double tlb)        { true_lower_bound_ = tlb; }
+    inline void setPreferred(BitVector128 p) { preferred_ = p; }
+};
+
+//==============================================================================
+
+class CoinTreeSiblings {
+private:
+    CoinTreeSiblings();
+    CoinTreeSiblings& operator=(const CoinTreeSiblings&);
+private:
+    int current_;
+    int numSiblings_;
+    CoinTreeNode** siblings_;
+public:
+    CoinTreeSiblings(const int n, CoinTreeNode** nodes) :
+	current_(0), numSiblings_(n), siblings_(new CoinTreeNode*[n])
+    {
+	CoinDisjointCopyN(nodes, n, siblings_);
+    }
+    CoinTreeSiblings(const CoinTreeSiblings& s) :
+	current_(s.current_),
+	numSiblings_(s.numSiblings_),
+	siblings_(new CoinTreeNode*[s.numSiblings_])
+    {
+	CoinDisjointCopyN(s.siblings_, s.numSiblings_, siblings_);
+    }
+    ~CoinTreeSiblings() { delete[] siblings_; }
+    inline CoinTreeNode* currentNode() const { return siblings_[current_]; }
+    /** returns false if cannot be advanced */
+    inline bool advanceNode() { return ++current_ != numSiblings_; }
+    inline int toProcess() const { return numSiblings_ - current_; }
+    inline int size() const { return numSiblings_; }
+    inline void printPref() const {
+      for (int i = 0; i < numSiblings_; ++i) {
+	std::string pref = siblings_[i]->getPreferred().str();
+	printf("prefs of sibligs: sibling[%i]: %s\n", i, pref.c_str());
+      }
+    }
+};
+
+//#############################################################################
+
+/** Function objects to compare search tree nodes. The comparison function
+    must return true if the first argument is "better" than the second one,
+    i.e., it should be processed first. */
+/*@{*/
+/** Depth First Search. */
+struct CoinSearchTreeComparePreferred {
+  static inline const char* name() { return "CoinSearchTreeComparePreferred"; }
+  inline bool operator()(const CoinTreeSiblings* x,
+			 const CoinTreeSiblings* y) const {
+    register const CoinTreeNode* xNode = x->currentNode();
+    register const CoinTreeNode* yNode = y->currentNode();
+    const BitVector128 xPref = xNode->getPreferred();
+    const BitVector128 yPref = yNode->getPreferred();
+    bool retval = true;
+    if (xPref < yPref) {
+      retval = true;
+    } else if (yPref < xPref) {
+      retval = false;
+    } else {
+      retval = xNode->getQuality() < yNode->getQuality();
+    }
+#ifdef DEBUG_PRINT
+    printf("Comparing xpref (%s) and ypref (%s) : %s\n",
+	   xpref.str().c_str(), ypref.str().c_str(), retval ? "T" : "F");
+#endif
+    return retval;
+  }
+};
+
+//-----------------------------------------------------------------------------
+/** Depth First Search. */
+struct CoinSearchTreeCompareDepth {
+  static inline const char* name() { return "CoinSearchTreeCompareDepth"; }
+  inline bool operator()(const CoinTreeSiblings* x,
+			 const CoinTreeSiblings* y) const {
+#if 1
+    return x->currentNode()->getDepth() >= y->currentNode()->getDepth();
+#else
+    if(x->currentNode()->getDepth() > y->currentNode()->getDepth())
+      return 1;
+    if(x->currentNode()->getDepth() == y->currentNode()->getDepth() &&
+       x->currentNode()->getQuality() <= y->currentNode()->getQuality())
+      return 1;
+    return 0;
+#endif
+  }
+};
+
+//-----------------------------------------------------------------------------
+/* Breadth First Search */
+struct CoinSearchTreeCompareBreadth {
+  static inline const char* name() { return "CoinSearchTreeCompareBreadth"; }
+  inline bool operator()(const CoinTreeSiblings* x,
+			 const CoinTreeSiblings* y) const {
+    return x->currentNode()->getDepth() < y->currentNode()->getDepth();
+  }
+};
+
+//-----------------------------------------------------------------------------
+/** Best first search */
+struct CoinSearchTreeCompareBest {
+  static inline const char* name() { return "CoinSearchTreeCompareBest"; }
+  inline bool operator()(const CoinTreeSiblings* x,
+			 const CoinTreeSiblings* y) const {
+    return x->currentNode()->getQuality() < y->currentNode()->getQuality();
+  }
+};
+
+//#############################################################################
+
+class CoinSearchTreeBase
+{
+private:
+    CoinSearchTreeBase(const CoinSearchTreeBase&);
+    CoinSearchTreeBase& operator=(const CoinSearchTreeBase&);
+
+protected:
+    std::vector<CoinTreeSiblings*> candidateList_;
+    int numInserted_;
+    int size_;
+
+protected:
+    CoinSearchTreeBase() : candidateList_(), numInserted_(0), size_(0) {}
+
+    virtual void realpop() = 0;
+    virtual void realpush(CoinTreeSiblings* s) = 0;
+    virtual void fixTop() = 0;
+
+public:
+    virtual ~CoinSearchTreeBase() {}
+    virtual const char* compName() const = 0;
+
+    inline const std::vector<CoinTreeSiblings*>& getCandidates() const {
+	return candidateList_;
+    }
+    inline bool empty() const { return candidateList_.empty(); }
+    inline int size() const { return size_; }
+    inline int numInserted() const { return numInserted_; }
+    inline CoinTreeNode* top() const {
+      if (size_ == 0)
+	return NULL;
+#ifdef DEBUG_PRINT
+      char output[44];
+      output[43] = 0;
+      candidateList_.front()->currentNode()->getPreferred().print(output);
+      printf("top's pref: %s\n", output);
+#endif
+      return candidateList_.front()->currentNode();
+    }
+    /** pop will advance the \c next pointer among the siblings on the top and
+	then moves the top to its correct position. #realpop is the method
+	that actually removes the element from the heap */
+    inline void pop() {
+	CoinTreeSiblings* s = candidateList_.front();
+	if (!s->advanceNode()) {
+	    realpop();
+	    delete s;
+	} else {
+	    fixTop();
+	}
+	--size_;
+    }
+    inline void push(int numNodes, CoinTreeNode** nodes,
+		     const bool incrInserted = true) {
+	CoinTreeSiblings* s = new CoinTreeSiblings(numNodes, nodes);
+	realpush(s);
+	if (incrInserted) {
+	    numInserted_ += numNodes;
+	}
+	size_ += numNodes;
+    }
+    inline void push(const CoinTreeSiblings& sib,
+		     const bool incrInserted = true) {
+	CoinTreeSiblings* s = new CoinTreeSiblings(sib);
+#ifdef DEBUG_PRINT
+	s->printPref();
+#endif
+	realpush(s);
+	if (incrInserted) {
+	    numInserted_ += sib.toProcess();
+	}
+	size_ += sib.size();
+    }
+};
+
+//#############################################################################
+
+// #define CAN_TRUST_STL_HEAP
+#ifdef CAN_TRUST_STL_HEAP
+
+template <class Comp>
+class CoinSearchTree : public CoinSearchTreeBase
+{
+private:
+    Comp comp_;
+protected:
+    virtual void realpop() {
+	candidateList_.pop_back();
+    }
+    virtual void fixTop() {
+	CoinTreeSiblings* s = top();
+	realpop();
+	push(s, false);
+    }
+    virtual void realpush(CoinTreeSiblings* s) {
+	nodes_.push_back(s);
+	std::push_heap(candidateList_.begin(), candidateList_.end(), comp_);
+    }
+public:
+    CoinSearchTree() : CoinSearchTreeBase(), comp_() {}
+    CoinSearchTree(const CoinSearchTreeBase& t) :
+	CoinSearchTreeBase(), comp_() {
+	candidateList_ = t.getCandidates();
+	std::make_heap(candidateList_.begin(), candidateList_.end(), comp_);
+	numInserted_ = t.numInserted_;
+	size_ = t.size_;
+    }
+    ~CoinSearchTree() {}
+    const char* compName() const { return Comp::name(); }
+};
+
+#else
+
+template <class Comp>
+class CoinSearchTree : public CoinSearchTreeBase
+{
+private:
+    Comp comp_;
+
+protected:
+    virtual void realpop() {
+	candidateList_[0] = candidateList_.back();
+	candidateList_.pop_back();
+	fixTop();
+    }
+    /** After changing data in the top node, fix the heap */
+    virtual void fixTop() {
+	const size_t size = candidateList_.size();
+	if (size > 1) {
+	    CoinTreeSiblings** candidates = &candidateList_[0];
+	    CoinTreeSiblings* s = candidates[0];
+	    --candidates;
+	    size_t pos = 1;
+	    size_t ch;
+	    for (ch = 2; ch < size; pos = ch, ch *= 2) {
+		if (comp_(candidates[ch+1], candidates[ch]))
+		    ++ch;
+		if (comp_(s, candidates[ch]))
+		    break;
+		candidates[pos] = candidates[ch];
+	    }
+	    if (ch == size) {
+		if (comp_(candidates[ch], s)) {
+		    candidates[pos] = candidates[ch];
+		    pos = ch;
+		}
+	    }
+	    candidates[pos] = s;
+	}
+    }
+    virtual void realpush(CoinTreeSiblings* s) {
+	candidateList_.push_back(s);
+	CoinTreeSiblings** candidates = &candidateList_[0];
+	--candidates;
+	size_t pos = candidateList_.size();
+	size_t ch;
+	for (ch = pos/2; ch != 0; pos = ch, ch /= 2) {
+	    if (comp_(candidates[ch], s))
+		break;
+	    candidates[pos] = candidates[ch];
+	}
+	candidates[pos] = s;
+    }
+  
+public:
+    CoinSearchTree() : CoinSearchTreeBase(), comp_() {}
+    CoinSearchTree(const CoinSearchTreeBase& t) :
+	CoinSearchTreeBase(), comp_() {
+	candidateList_ = t.getCandidates();
+	std::sort(candidateList_.begin(), candidateList_.end(), comp_);
+	numInserted_ = t.numInserted();
+	size_ = t.size();
+    }
+    virtual ~CoinSearchTree() {}
+    const char* compName() const { return Comp::name(); }
+};
+
+#endif
+
+//#############################################################################
+
+enum CoinNodeAction {
+    CoinAddNodeToCandidates,
+    CoinTestNodeForDiving,
+    CoinDiveIntoNode
+};
+
+class CoinSearchTreeManager
+{
+private:
+    CoinSearchTreeManager(const CoinSearchTreeManager&);
+    CoinSearchTreeManager& operator=(const CoinSearchTreeManager&);
+private:
+    CoinSearchTreeBase* candidates_;
+    int numSolution;
+    /** Whether there is an upper bound or not. The upper bound may have come
+	as input, not necessarily from a solution */
+    bool hasUB_;
+
+    /** variable used to test whether we need to reevaluate search strategy */
+    bool recentlyReevaluatedSearchStrategy_;
+    
+public:
+    CoinSearchTreeManager() :
+	candidates_(NULL),
+	numSolution(0),
+	recentlyReevaluatedSearchStrategy_(true)
+    {}
+    virtual ~CoinSearchTreeManager() {
+	delete candidates_;
+    }
+    
+    inline void setTree(CoinSearchTreeBase* t) {
+	delete candidates_;
+	candidates_ = t;
+    }
+    inline CoinSearchTreeBase* getTree() const {
+	return candidates_;
+    }
+
+    inline bool empty() const { return candidates_->empty(); }
+    inline size_t size() const { return candidates_->size(); }
+    inline size_t numInserted() const { return candidates_->numInserted(); }
+    inline CoinTreeNode* top() const { return candidates_->top(); }
+    inline void pop() { candidates_->pop(); }
+    inline void push(CoinTreeNode* node, const bool incrInserted = true) {
+	candidates_->push(1, &node, incrInserted);
+    }
+    inline void push(const CoinTreeSiblings& s, const bool incrInserted=true) {
+	candidates_->push(s, incrInserted);
+    }
+    inline void push(const int n, CoinTreeNode** nodes,
+		     const bool incrInserted = true) {
+	candidates_->push(n, nodes, incrInserted);
+    }
+
+    inline CoinTreeNode* bestQualityCandidate() const {
+	return candidates_->top();
+    }
+    inline double bestQuality() const {
+	return candidates_->top()->getQuality();
+    }
+    void newSolution(double solValue);
+    void reevaluateSearchStrategy();
+};
+
+//#############################################################################
+
+#endif
diff --git a/cbits/coin/CoinShallowPackedVector.cpp b/cbits/coin/CoinShallowPackedVector.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinShallowPackedVector.cpp
@@ -0,0 +1,182 @@
+/* $Id: CoinShallowPackedVector.cpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinShallowPackedVector.hpp"
+
+//#############################################################################
+
+void
+CoinShallowPackedVector::clear()
+{
+   clearBase();
+   indices_ = NULL;
+   elements_ = NULL;
+   nElements_ = 0;
+}
+
+//#############################################################################
+
+CoinShallowPackedVector&
+CoinShallowPackedVector::operator=(const CoinPackedVectorBase & x)
+{
+   if (&x != this) {
+      indices_ = x.getIndices();
+      elements_ = x.getElements();
+      nElements_ = x.getNumElements();
+      CoinPackedVectorBase::clearBase();
+      CoinPackedVectorBase::copyMaxMinIndex(x);
+      try {
+	 CoinPackedVectorBase::duplicateIndex();
+      }
+      catch (CoinError& e) {
+	 throw CoinError("duplicate index", "operator= from base",
+			"CoinShallowPackedVector");
+      }
+   }
+   return *this;
+}
+
+//#############################################################################
+
+CoinShallowPackedVector&
+CoinShallowPackedVector::operator=(const CoinShallowPackedVector & x)
+{
+   if (&x != this) {
+      indices_ = x.indices_;
+      elements_ = x.elements_;
+      nElements_ = x.nElements_;
+      CoinPackedVectorBase::clearBase();
+      CoinPackedVectorBase::copyMaxMinIndex(x);
+      try {
+	 CoinPackedVectorBase::duplicateIndex();
+      }
+      catch (CoinError& e) {
+	 throw CoinError("duplicate index", "operator=",
+			"CoinShallowPackedVector");
+      }
+   }
+   return *this;
+}
+
+//#############################################################################
+
+void
+CoinShallowPackedVector::setVector(int size,
+				  const int * inds, const double * elems,
+				  bool testForDuplicateIndex)
+{
+   indices_ = inds;
+   elements_ = elems;
+   nElements_ = size;
+   CoinPackedVectorBase::clearBase();
+   try {
+      CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex);
+   }
+   catch (CoinError& e) {
+      throw CoinError("duplicate index", "setVector",
+		     "CoinShallowPackedVector");
+   }
+}
+
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default
+//-------------------------------------------------------------------
+CoinShallowPackedVector::CoinShallowPackedVector(bool testForDuplicateIndex) :
+   CoinPackedVectorBase(),
+   indices_(NULL),
+   elements_(NULL),
+   nElements_(0)
+{
+   try {
+      CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex);
+   }
+   catch (CoinError& e) {
+      throw CoinError("duplicate index", "default constructor",
+		     "CoinShallowPackedVector");
+   }
+}
+   
+//-------------------------------------------------------------------
+// Explicit
+//-------------------------------------------------------------------
+CoinShallowPackedVector::CoinShallowPackedVector(int size, 
+					       const int * inds,
+					       const double * elems,
+					       bool testForDuplicateIndex) :
+   CoinPackedVectorBase(),
+   indices_(inds),
+   elements_(elems),
+   nElements_(size)
+{
+   try {
+      CoinPackedVectorBase::setTestForDuplicateIndex(testForDuplicateIndex);
+   }
+   catch (CoinError& e) {
+      throw CoinError("duplicate index", "explicit constructor",
+		     "CoinShallowPackedVector");
+   }
+}
+
+//-------------------------------------------------------------------
+// Copy
+//-------------------------------------------------------------------
+CoinShallowPackedVector::CoinShallowPackedVector(const CoinPackedVectorBase& x) :
+   CoinPackedVectorBase(),
+   indices_(x.getIndices()),
+   elements_(x.getElements()),
+   nElements_(x.getNumElements())
+{
+   CoinPackedVectorBase::copyMaxMinIndex(x);
+   try {
+      CoinPackedVectorBase::setTestForDuplicateIndex(x.testForDuplicateIndex());
+   }
+   catch (CoinError& e) {
+      throw CoinError("duplicate index", "copy constructor from base",
+		     "CoinShallowPackedVector");
+   }
+}
+
+//-------------------------------------------------------------------
+// Copy
+//-------------------------------------------------------------------
+CoinShallowPackedVector::CoinShallowPackedVector(const
+					       CoinShallowPackedVector& x) :
+   CoinPackedVectorBase(),
+   indices_(x.getIndices()),
+   elements_(x.getElements()),
+   nElements_(x.getNumElements())
+{
+   CoinPackedVectorBase::copyMaxMinIndex(x);
+   try {
+      CoinPackedVectorBase::setTestForDuplicateIndex(x.testForDuplicateIndex());
+   }
+   catch (CoinError& e) {
+      throw CoinError("duplicate index", "copy constructor",
+		     "CoinShallowPackedVector");
+   }
+}
+
+//-------------------------------------------------------------------
+// Print
+//-------------------------------------------------------------------
+void CoinShallowPackedVector::print()
+{
+for (int i=0; i < nElements_; i++)
+  {
+  std::cout << indices_[i] << ":" << elements_[i];
+  if (i < nElements_-1)
+    std::cout << ", ";
+  }
+ std::cout << std::endl;
+}
+
diff --git a/cbits/coin/CoinShallowPackedVector.hpp b/cbits/coin/CoinShallowPackedVector.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinShallowPackedVector.hpp
@@ -0,0 +1,148 @@
+/* $Id: CoinShallowPackedVector.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinShallowPackedVector_H
+#define CoinShallowPackedVector_H
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinError.hpp"
+#include "CoinPackedVectorBase.hpp"
+
+/** Shallow Sparse Vector
+ 
+This class is for sparse vectors where the indices and 
+elements are stored elsewhere.  This class only maintains
+pointers to the indices and elements.  Since this class
+does not own the index and element data it provides
+read only access to to the data.  An CoinSparsePackedVector
+must be used when the sparse vector's data will be altered.
+
+This class stores pointers to the vectors.
+It does not actually contain the vectors.
+
+Here is a sample usage:
+@verbatim
+   const int ne = 4; 
+   int inx[ne] =   {  1,   4,  0,   2 }; 
+   double el[ne] = { 10., 40., 1., 50. }; 
+ 
+   // Create vector and set its value 
+   CoinShallowPackedVector r(ne,inx,el); 
+ 
+   // access each index and element 
+   assert( r.indices ()[0]== 1  ); 
+   assert( r.elements()[0]==10. ); 
+   assert( r.indices ()[1]== 4  ); 
+   assert( r.elements()[1]==40. ); 
+   assert( r.indices ()[2]== 0  ); 
+   assert( r.elements()[2]== 1. ); 
+   assert( r.indices ()[3]== 2  ); 
+   assert( r.elements()[3]==50. ); 
+ 
+   // access as a full storage vector 
+   assert( r[ 0]==1. ); 
+   assert( r[ 1]==10.); 
+   assert( r[ 2]==50.); 
+   assert( r[ 3]==0. ); 
+   assert( r[ 4]==40.); 
+ 
+   // Tests for equality and equivalence
+   CoinShallowPackedVector r1; 
+   r1=r; 
+   assert( r==r1 ); 
+   r.sort(CoinIncrElementOrdered()); 
+   assert( r!=r1 ); 
+ 
+   // Add packed vectors. 
+   // Similarly for subtraction, multiplication, 
+   // and division. 
+   CoinPackedVector add = r + r1; 
+   assert( add[0] ==  1.+ 1. ); 
+   assert( add[1] == 10.+10. ); 
+   assert( add[2] == 50.+50. ); 
+   assert( add[3] ==  0.+ 0. ); 
+   assert( add[4] == 40.+40. ); 
+   assert( r.sum() == 10.+40.+1.+50. ); 
+@endverbatim
+*/
+class CoinShallowPackedVector : public CoinPackedVectorBase {
+   friend void CoinShallowPackedVectorUnitTest();
+
+public:
+  
+   /**@name Get methods */
+   //@{
+   /// Get length of indices and elements vectors
+   virtual int getNumElements() const { return nElements_; }
+   /// Get indices of elements
+   virtual const int * getIndices() const { return indices_; }
+   /// Get element values
+   virtual const double * getElements() const { return elements_; }
+   //@}
+
+   /**@name Set methods */
+   //@{
+   /// Reset the vector (as if were just created an empty vector)
+   void clear();
+   /** Assignment operator. */
+   CoinShallowPackedVector& operator=(const CoinShallowPackedVector & x);
+   /** Assignment operator from a CoinPackedVectorBase. */
+   CoinShallowPackedVector& operator=(const CoinPackedVectorBase & x);
+   /** just like the explicit constructor */
+   void setVector(int size, const int * indices, const double * elements,
+		  bool testForDuplicateIndex = true);
+   //@}
+
+   /**@name Methods to create, set and destroy */
+   //@{
+   /** Default constructor. */
+   CoinShallowPackedVector(bool testForDuplicateIndex = true);
+   /** Explicit Constructor.
+       Set vector size, indices, and elements. Size is the length of both the
+       indices and elements vectors. The indices and elements vectors are not
+       copied into this class instance. The ShallowPackedVector only maintains
+       the pointers to the indices and elements vectors. <br>
+       The last argument specifies whether the creator of the object knows in
+       advance that there are no duplicate indices.
+   */
+   CoinShallowPackedVector(int size,
+			  const int * indices, const double * elements,
+			  bool testForDuplicateIndex = true);
+   /** Copy constructor from the base class. */
+   CoinShallowPackedVector(const CoinPackedVectorBase &);
+   /** Copy constructor. */
+   CoinShallowPackedVector(const CoinShallowPackedVector &);
+   /** Destructor. */
+   virtual ~CoinShallowPackedVector() {}
+   /// Print vector information.
+   void print();
+   //@}
+
+private:
+   /**@name Private member data */
+   //@{
+   /// Vector indices
+   const int * indices_;
+   ///Vector elements
+   const double * elements_;
+   /// Size of indices and elements vectors
+   int nElements_;
+   //@}
+};
+
+//#############################################################################
+/** A function that tests the methods in the CoinShallowPackedVector class. The
+    only reason for it not to be a member method is that this way it doesn't
+    have to be compiled into the library. And that's a gain, because the
+    library should be compiled with optimization on, but this method should be
+    compiled with debugging. */
+void
+CoinShallowPackedVectorUnitTest();
+
+#endif
diff --git a/cbits/coin/CoinSignal.hpp b/cbits/coin/CoinSignal.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinSignal.hpp
@@ -0,0 +1,117 @@
+/* $Id: CoinSignal.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef _CoinSignal_hpp
+#define _CoinSignal_hpp
+
+// This file is fully docified.
+// There's nothing to docify...
+
+//#############################################################################
+
+#include <csignal>
+
+//#############################################################################
+
+#if defined(_MSC_VER)
+   typedef void (__cdecl *CoinSighandler_t) (int);
+#  define CoinSighandler_t_defined
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if (defined(__GNUC__) && defined(__linux__))
+  typedef sighandler_t CoinSighandler_t;
+# define CoinSighandler_t_defined
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if defined(__CYGWIN__) && defined(__GNUC__)
+   typedef typeof(SIG_DFL) CoinSighandler_t;
+#  define CoinSighandler_t_defined
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if defined(__MINGW32__) && defined(__GNUC__)
+   typedef typeof(SIG_DFL) CoinSighandler_t;
+#  define CoinSighandler_t_defined
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if defined(__FreeBSD__) && defined(__GNUC__)
+   typedef typeof(SIG_DFL) CoinSighandler_t;
+#  define CoinSighandler_t_defined
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if defined(__NetBSD__) && defined(__GNUC__)
+   typedef typeof(SIG_DFL) CoinSighandler_t;
+#  define CoinSighandler_t_defined
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if defined(_AIX)
+#  if defined(__GNUC__)
+      typedef typeof(SIG_DFL) CoinSighandler_t;
+#     define CoinSighandler_t_defined
+#  endif
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if defined (__hpux)
+#  define CoinSighandler_t_defined
+#  if defined(__GNUC__)
+      typedef typeof(SIG_DFL) CoinSighandler_t;
+#  else
+      extern "C" {
+         typedef void (*CoinSighandler_t) (int);
+      }
+#  endif
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if defined(__sun)
+#  if defined(__SUNPRO_CC)
+#     include <signal.h>
+      extern "C" {
+         typedef void (*CoinSighandler_t) (int);
+      }
+#     define CoinSighandler_t_defined
+#  endif
+#  if defined(__GNUC__)
+      typedef typeof(SIG_DFL) CoinSighandler_t;
+#     define CoinSighandler_t_defined
+#  endif
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if defined(__MACH__) && defined(__GNUC__)
+   typedef typeof(SIG_DFL) CoinSighandler_t;
+#  define CoinSighandler_t_defined
+#endif
+
+//#############################################################################
+
+#ifndef CoinSighandler_t_defined
+#  warning("OS and/or compiler is not recognized. Defaulting to:");
+#  warning("extern "C" {")
+#  warning("   typedef void (*CoinSighandler_t) (int);")
+#  warning("}")
+   extern "C" {
+      typedef void (*CoinSighandler_t) (int);
+   }
+#endif
+
+//#############################################################################
+
+#endif
diff --git a/cbits/coin/CoinSimpFactorization.cpp b/cbits/coin/CoinSimpFactorization.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinSimpFactorization.cpp
@@ -0,0 +1,2666 @@
+/* $Id: CoinSimpFactorization.cpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinUtilsConfig.h"
+
+#include <cassert>
+#include "CoinPragma.hpp"
+#include "CoinSimpFactorization.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinFinite.hpp"
+#include <stdio.h>
+
+
+
+#define ARRAY 0 
+
+
+
+FactorPointers::FactorPointers( int numRows, int numColumns,
+				int *UrowLengths_, 
+				int *UcolLengths_ ){
+    
+    rowMax = new double[numRows];
+    double *current=rowMax;
+    const double *end=current+numRows;
+    for ( ; current!=end; ++current ) *current=-1.0;
+
+    firstRowKnonzeros = new int[numRows+1];
+    CoinFillN(firstRowKnonzeros, numRows+1, -1 ); 
+
+    prevRow = new int[numRows];
+    nextRow = new int[numRows];
+    firstColKnonzeros = new int[numRows+1];
+    memset(firstColKnonzeros, -1, (numRows+1)*sizeof(int) ); 
+
+    prevColumn = new int[numColumns];
+    nextColumn = new int[numColumns];
+    newCols = new int[numRows];
+    
+
+    for ( int i=numRows-1; i>=0; --i ){
+	int length=UrowLengths_[i];
+	prevRow[i]=-1;
+	nextRow[i]=firstRowKnonzeros[length];
+	if ( nextRow[i]!=-1 ) prevRow[nextRow[i]]=i;
+	firstRowKnonzeros[length]=i;
+    }
+    for ( int i=numColumns-1; i>=0; --i ){
+	int length=UcolLengths_[i];
+	prevColumn[i]=-1;
+	nextColumn[i]=firstColKnonzeros[length];
+	if ( nextColumn[i]!=-1 ) prevColumn[nextColumn[i]]=i;
+	firstColKnonzeros[length]=i;
+    }
+}
+FactorPointers::~ FactorPointers(){
+    delete [] rowMax;
+    delete [] firstRowKnonzeros;
+    delete [] prevRow;
+    delete [] nextRow;
+    delete [] firstColKnonzeros;
+    delete [] prevColumn;
+    delete [] nextColumn;
+    delete [] newCols;
+}
+
+
+//:class CoinSimpFactorization.  Deals with Factorization and Updates
+//  CoinSimpFactorization.  Constructor
+CoinSimpFactorization::CoinSimpFactorization (  )
+  : CoinOtherFactorization()
+{
+  gutsOfInitialize();
+}
+
+/// Copy constructor 
+CoinSimpFactorization::CoinSimpFactorization ( const CoinSimpFactorization &other)
+  : CoinOtherFactorization(other)
+{
+  gutsOfInitialize();
+  gutsOfCopy(other);
+}
+// Clone
+CoinOtherFactorization * 
+CoinSimpFactorization::clone() const 
+{
+  return new CoinSimpFactorization(*this);
+}
+/// The real work of constructors etc
+void CoinSimpFactorization::gutsOfDestructor()
+{
+  delete [] elements_;
+  delete [] pivotRow_;
+  delete [] workArea_;
+  elements_ = NULL;
+  pivotRow_ = NULL;
+  workArea_ = NULL;
+  numberRows_ = 0;
+  numberColumns_ = 0;
+  numberGoodU_ = 0;
+  status_ = -1;
+  maximumRows_=0;
+  maximumSpace_=0;  
+  numberSlacks_=0;
+  firstNumberSlacks_=0;
+  //
+  delete [] denseVector_;
+  delete [] workArea2_;
+  delete [] workArea3_;
+  delete [] vecLabels_;
+  delete [] indVector_;
+  
+  delete [] auxVector_;
+  delete [] auxInd_;
+  
+  delete [] vecKeep_;
+  delete [] indKeep_;
+   
+  delete [] LrowStarts_;
+  delete [] LrowLengths_;
+  delete [] Lrows_;
+  delete [] LrowInd_;
+    
+  
+  delete [] LcolStarts_;
+  delete [] LcolLengths_;
+  delete [] Lcolumns_;
+  delete [] LcolInd_;
+  
+  delete [] UrowStarts_;
+  delete [] UrowLengths_;
+#ifdef COIN_SIMP_CAPACITY
+  delete [] UrowCapacities_;
+#endif
+  delete [] Urows_;
+  delete [] UrowInd_;
+  
+  delete [] prevRowInU_;
+  delete [] nextRowInU_;
+  
+  delete [] UcolStarts_;
+  delete [] UcolLengths_;
+#ifdef COIN_SIMP_CAPACITY
+  delete [] UcolCapacities_;
+#endif
+  delete [] Ucolumns_;
+  delete [] UcolInd_;
+  delete [] prevColInU_;
+  delete [] nextColInU_;
+  delete [] colSlack_;
+  
+  delete [] invOfPivots_;
+  
+  delete [] colOfU_;
+  delete [] colPosition_;
+  delete [] rowOfU_;
+  delete [] rowPosition_;
+  delete [] secRowOfU_;
+  delete [] secRowPosition_;
+  
+  delete [] EtaPosition_;
+  delete [] EtaStarts_;
+  delete [] EtaLengths_;
+  delete [] EtaInd_;
+  delete [] Eta_;
+ 
+  denseVector_=NULL;
+  workArea2_=NULL;
+  workArea3_=NULL;
+  vecLabels_=NULL;
+  indVector_=NULL;
+  
+  auxVector_=NULL;
+  auxInd_=NULL;
+  
+  vecKeep_=NULL;
+  indKeep_=NULL;
+   
+  LrowStarts_=NULL;
+  LrowLengths_=NULL;
+  Lrows_=NULL;
+  LrowInd_=NULL;
+  
+  
+  LcolStarts_=NULL;
+  LcolLengths_=NULL;
+  Lcolumns_=NULL;
+  LcolInd_=NULL;
+  
+  UrowStarts_=NULL;
+  UrowLengths_=NULL;
+#ifdef COIN_SIMP_CAPACITY
+  UrowCapacities_=NULL;
+#endif
+  Urows_=NULL;
+  UrowInd_=NULL;
+  
+  prevRowInU_=NULL;
+  nextRowInU_=NULL;
+  
+  UcolStarts_=NULL;
+  UcolLengths_=NULL;
+#ifdef COIN_SIMP_CAPACITY
+  UcolCapacities_=NULL;
+#endif
+  Ucolumns_=NULL;
+  UcolInd_=NULL;
+  prevColInU_=NULL;
+  nextColInU_=NULL;
+  colSlack_=NULL;
+  
+  invOfPivots_=NULL;
+  
+  colOfU_=NULL;
+  colPosition_=NULL;
+  rowOfU_=NULL;
+  rowPosition_=NULL;
+  secRowOfU_=NULL;
+  secRowPosition_=NULL;
+  
+  EtaPosition_=NULL;
+  EtaStarts_=NULL;
+  EtaLengths_=NULL;
+  EtaInd_=NULL;
+  Eta_=NULL;
+}
+void CoinSimpFactorization::gutsOfInitialize()
+{
+  pivotTolerance_ = 1.0e-1;
+  zeroTolerance_ = 1.0e-13;
+#ifndef COIN_FAST_CODE
+  slackValue_ = -1.0;
+#endif
+  maximumPivots_=200;
+  relaxCheck_=1.0;
+  numberRows_ = 0;
+  numberColumns_ = 0;
+  numberGoodU_ = 0;
+  status_ = -1;
+  numberPivots_ = 0;
+  maximumRows_=0;
+  maximumSpace_=0;  
+  numberSlacks_=0;
+  firstNumberSlacks_=0;
+  elements_ = NULL;
+  pivotRow_ = NULL;
+  workArea_ = NULL;
+
+  denseVector_=NULL;
+  workArea2_=NULL;
+  workArea3_=NULL;
+  vecLabels_=NULL;
+  indVector_=NULL;
+  
+  auxVector_=NULL;
+  auxInd_=NULL;
+  
+  vecKeep_=NULL;
+  indKeep_=NULL;
+  
+  LrowStarts_=NULL;
+  LrowLengths_=NULL;
+  Lrows_=NULL;
+  LrowInd_=NULL;
+  
+  
+  LcolStarts_=NULL;
+  LcolLengths_=NULL;
+  Lcolumns_=NULL;
+  LcolInd_=NULL;
+  
+  UrowStarts_=NULL;
+  UrowLengths_=NULL;
+#ifdef COIN_SIMP_CAPACITY
+  UrowCapacities_=NULL;
+#endif
+  Urows_=NULL;
+  UrowInd_=NULL;
+  
+  prevRowInU_=NULL;
+  nextRowInU_=NULL;
+  
+  UcolStarts_=NULL;
+  UcolLengths_=NULL;
+#ifdef COIN_SIMP_CAPACITY
+  UcolCapacities_=NULL;
+#endif
+  Ucolumns_=NULL;
+  UcolInd_=NULL;
+  prevColInU_=NULL;
+  nextColInU_=NULL;
+  colSlack_=NULL;
+  
+  invOfPivots_=NULL;
+  
+  colOfU_=NULL;
+  colPosition_=NULL;
+  rowOfU_=NULL;
+  rowPosition_=NULL;
+  secRowOfU_=NULL;
+  secRowPosition_=NULL;
+  
+  EtaPosition_=NULL;
+  EtaStarts_=NULL;
+  EtaLengths_=NULL;
+  EtaInd_=NULL;
+  Eta_=NULL;
+}
+void CoinSimpFactorization::initialSomeNumbers(){
+    keepSize_=-1;
+    LrowSize_=-1;
+    // LrowCap_ in allocateSomeArrays
+    LcolSize_=-1;
+    // LcolCap_ in allocateSomeArrays
+    // UrowMaxCap_ in allocateSomeArrays
+    UrowEnd_=-1;
+    firstRowInU_=-1;
+    lastRowInU_=-1; 
+    firstColInU_=-1;
+    lastColInU_=-1;
+    //UcolMaxCap_ in allocateSomeArrays
+    UcolEnd_=-1;
+    
+    
+    EtaSize_=0;
+    lastEtaRow_=-1;
+    //maxEtaRows_ in allocateSomeArrays
+    //EtaMaxCap_ in allocateSomeArrays
+        
+    // minIncrease_ in allocateSomeArrays 
+    updateTol_=1.0e12;
+
+    doSuhlHeuristic_=true;
+    maxU_=-1.0;
+    maxGrowth_=1.e12;
+    maxA_=-1.0;
+    pivotCandLimit_=4;
+    minIncrease_=10; 
+
+}
+
+//  ~CoinSimpFactorization.  Destructor
+CoinSimpFactorization::~CoinSimpFactorization (  )
+{
+  gutsOfDestructor();
+}
+//  =
+CoinSimpFactorization & CoinSimpFactorization::operator = ( const CoinSimpFactorization & other ) {
+  if (this != &other) {    
+    gutsOfDestructor();
+    gutsOfInitialize();
+    gutsOfCopy(other);
+  }
+  return *this;
+}
+void CoinSimpFactorization::gutsOfCopy(const CoinSimpFactorization &other)
+{
+  pivotTolerance_ = other.pivotTolerance_;
+  zeroTolerance_ = other.zeroTolerance_;
+#ifndef COIN_FAST_CODE
+  slackValue_ = other.slackValue_;
+#endif
+  relaxCheck_ = other.relaxCheck_;
+  numberRows_ = other.numberRows_;
+  numberColumns_ = other.numberColumns_;
+  maximumRows_ = other.maximumRows_;
+  maximumSpace_ = other.maximumSpace_;
+  numberGoodU_ = other.numberGoodU_;
+  maximumPivots_ = other.maximumPivots_;
+  numberPivots_ = other.numberPivots_;
+  factorElements_ = other.factorElements_;
+  status_ = other.status_;
+  numberSlacks_ = other.numberSlacks_;
+  firstNumberSlacks_ = other.firstNumberSlacks_;
+  if (other.pivotRow_) {
+    pivotRow_ = new int [2*maximumRows_+maximumPivots_];
+    memcpy(pivotRow_,other.pivotRow_,(2*maximumRows_+numberPivots_)*sizeof(int));
+    elements_ = new CoinFactorizationDouble [maximumSpace_];
+    memcpy(elements_,other.elements_,(maximumRows_+numberPivots_)*maximumRows_*sizeof(CoinFactorizationDouble));
+    workArea_ = new CoinFactorizationDouble [maximumRows_];
+  } else {
+    elements_ = NULL;
+    pivotRow_ = NULL;
+    workArea_ = NULL;
+  }
+
+  keepSize_ = other.keepSize_;
+  
+  LrowSize_ = other.LrowSize_;
+  LrowCap_ = other.LrowCap_;
+ 
+  LcolSize_ = other.LcolSize_;
+  LcolCap_ = other.LcolCap_;
+  
+  UrowMaxCap_ = other.UrowMaxCap_;
+  UrowEnd_ = other.UrowEnd_;
+  firstRowInU_ = other.firstRowInU_;
+  lastRowInU_ = other.lastRowInU_;
+  
+  firstColInU_ = other.firstColInU_;
+  lastColInU_ = other.lastColInU_;
+  UcolMaxCap_ = other.UcolMaxCap_;
+  UcolEnd_ = other.UcolEnd_;
+
+  EtaSize_ = other.EtaSize_;
+  lastEtaRow_ = other.lastEtaRow_;
+  maxEtaRows_ = other.maxEtaRows_;
+  EtaMaxCap_ = other.EtaMaxCap_;
+  
+  
+  minIncrease_ = other.minIncrease_;
+  updateTol_ = other.updateTol_;
+
+
+
+  if (other.denseVector_)
+      {
+	  denseVector_ = new double[maximumRows_];
+	  memcpy(denseVector_,other.denseVector_,maximumRows_*sizeof(double));
+      } else denseVector_=NULL;
+  if (other.workArea2_)
+      {
+	  workArea2_ = new double[maximumRows_];
+	  memcpy(workArea2_,other.workArea2_,maximumRows_*sizeof(double));
+      } else workArea2_=NULL;
+  if (other.workArea3_)
+      {
+	  workArea3_ = new double[maximumRows_];
+	  memcpy(workArea3_,other.workArea3_,maximumRows_*sizeof(double));
+      } else workArea3_=NULL;
+  if (other.vecLabels_)
+      {
+	  vecLabels_ = new int[maximumRows_];
+	  memcpy(vecLabels_,other.vecLabels_,maximumRows_*sizeof(int));
+      } else vecLabels_=NULL;
+  if (other.indVector_)
+      {
+	  indVector_ = new int[maximumRows_];
+	  memcpy(indVector_ ,other.indVector_ , maximumRows_ *sizeof(int ));
+      } else indVector_=NULL;
+  
+  if (other.auxVector_)
+      {
+	  auxVector_ = new double[maximumRows_]; 
+	  memcpy(auxVector_ ,other.auxVector_ , maximumRows_ *sizeof(double ));
+      } else auxVector_=NULL;
+  if (other.auxInd_)
+      {
+	  auxInd_ = new int[maximumRows_];
+	  memcpy(auxInd_ , other.auxInd_, maximumRows_ *sizeof(int));
+      } else auxInd_=NULL;
+  
+  if (other.vecKeep_)
+      {
+	  vecKeep_ = new double[maximumRows_]; 
+	  memcpy(vecKeep_ ,other.vecKeep_ , maximumRows_ *sizeof(double));
+      } else vecKeep_=NULL;
+  if (other.indKeep_)
+      {
+	  indKeep_ = new int[maximumRows_];
+	  memcpy(indKeep_ , other.indKeep_, maximumRows_ *sizeof(int));
+      } else indKeep_=NULL;
+  if (other.LrowStarts_)
+      {
+	  LrowStarts_ = new int[maximumRows_]; 
+	  memcpy(LrowStarts_ , other.LrowStarts_, maximumRows_ *sizeof(int));
+      } else LrowStarts_=NULL;
+  if (other.LrowLengths_)
+      {
+	  LrowLengths_ = new int[maximumRows_]; 
+	  memcpy(LrowLengths_ , other.LrowLengths_ , maximumRows_ *sizeof(int));
+      } else LrowLengths_=NULL;
+  if (other.Lrows_)
+      {
+	  Lrows_ = new double[other.LrowCap_]; 
+	  memcpy(Lrows_ , other.Lrows_, other.LrowCap_*sizeof(double));
+      } else Lrows_=NULL;
+  if (other.LrowInd_)
+      {
+	  LrowInd_ = new int[other.LrowCap_];
+	  memcpy(LrowInd_, other.LrowInd_,  other.LrowCap_*sizeof(int));
+      } else LrowInd_=NULL;
+  
+  if (other.LcolStarts_)
+      {
+	  LcolStarts_ = new int[maximumRows_];
+	  memcpy(LcolStarts_ ,other.LcolStarts_ , maximumRows_*sizeof(int));
+      } else LcolStarts_=NULL;
+  if (other.LcolLengths_)
+      {
+	  LcolLengths_ = new int[maximumRows_];
+	  memcpy(LcolLengths_ , other.LcolLengths_ , maximumRows_ *sizeof(int));
+      } else LcolLengths_=NULL;
+  if (other.Lcolumns_)
+      {
+	  Lcolumns_ = new double[other.LcolCap_];
+	  memcpy(Lcolumns_ ,other.Lcolumns_ , other.LcolCap_ *sizeof(double));
+      } else Lcolumns_=NULL;
+  if (other.LcolInd_)
+      {
+	  LcolInd_ = new int[other.LcolCap_];  
+	  memcpy(LcolInd_ , other.LcolInd_, other.LcolCap_*sizeof(int));
+      } else LcolInd_=NULL;
+  
+  if (other.UrowStarts_)
+      {
+	  UrowStarts_ = new int[maximumRows_];
+	  memcpy(UrowStarts_ ,other.UrowStarts_ , maximumRows_ *sizeof(int));
+      } else UrowStarts_=NULL;
+  if (other.UrowLengths_)
+      {
+	  UrowLengths_ = new int[maximumRows_];
+	  memcpy(UrowLengths_ ,other.UrowLengths_ , maximumRows_ *sizeof(int));
+      } else UrowLengths_=NULL;
+#ifdef COIN_SIMP_CAPACITY
+  if (other.UrowCapacities_)
+      {
+	  UrowCapacities_ = new int[maximumRows_];
+	  memcpy(UrowCapacities_ ,other.UrowCapacities_ , maximumRows_ *sizeof(int));
+      } else UrowCapacities_=NULL;
+#endif
+  if (other.Urows_)
+      {
+	  Urows_ = new double[other.UrowMaxCap_];
+	  memcpy(Urows_ ,other.Urows_ , other.UrowMaxCap_ *sizeof(double));
+      } else Urows_=NULL;
+  if (other.UrowInd_)
+      {
+	  UrowInd_ = new int[other.UrowMaxCap_];
+	  memcpy(UrowInd_,other.UrowInd_, other.UrowMaxCap_*sizeof(int));
+      } else UrowInd_=NULL;
+  
+  if (other.prevRowInU_)
+      {
+	  prevRowInU_ = new int[maximumRows_];
+	  memcpy(prevRowInU_ , other.prevRowInU_, maximumRows_*sizeof(int));
+      } else prevRowInU_=NULL;
+  if (other.nextRowInU_)
+      {
+	  nextRowInU_ = new int[maximumRows_];
+	  memcpy(nextRowInU_, other.nextRowInU_, maximumRows_*sizeof(int));
+      } else nextRowInU_=NULL;
+  
+  if (other.UcolStarts_)
+      {
+	  UcolStarts_ = new int[maximumRows_]; 
+	  memcpy(UcolStarts_ , other.UcolStarts_, maximumRows_*sizeof(int));
+      } else UcolStarts_=NULL;
+  if (other.UcolLengths_)
+      {
+	  UcolLengths_ = new int[maximumRows_]; 
+	  memcpy(UcolLengths_ , other.UcolLengths_,  maximumRows_*sizeof(int));
+      } else UcolLengths_=NULL;
+#ifdef COIN_SIMP_CAPACITY
+  if (other.UcolCapacities_)
+      {
+	  UcolCapacities_ = new int[maximumRows_]; 
+	  memcpy(UcolCapacities_ ,other.UcolCapacities_ , maximumRows_*sizeof(int));
+      } else UcolCapacities_=NULL;
+#endif
+  if (other.Ucolumns_)
+      {
+	  Ucolumns_ = new double[other.UcolMaxCap_];
+	  memcpy(Ucolumns_ ,other.Ucolumns_ , other.UcolMaxCap_*sizeof(double));
+      } else Ucolumns_=NULL;
+  if (other.UcolInd_)
+      {
+	  UcolInd_ = new int[other.UcolMaxCap_];
+	  memcpy(UcolInd_ , other.UcolInd_ , other.UcolMaxCap_*sizeof(int));
+      } else UcolInd_=NULL;
+  if (other.prevColInU_)
+      {
+	  prevColInU_ = new int[maximumRows_];
+	  memcpy(prevColInU_ , other.prevColInU_ , maximumRows_*sizeof(int));
+      } else prevColInU_=NULL;
+  if (other.nextColInU_)
+      {
+	  nextColInU_ = new int[maximumRows_];
+	  memcpy(nextColInU_ ,other.nextColInU_ , maximumRows_*sizeof(int));
+      } else nextColInU_=NULL;
+  if (other.colSlack_)
+      {
+	  colSlack_ = new int[maximumRows_];
+	  memcpy(colSlack_, other.colSlack_, maximumRows_*sizeof(int));
+      }
+
+  
+  if (other.invOfPivots_)
+      {
+	  invOfPivots_ = new double[maximumRows_];
+	  memcpy(invOfPivots_ , other.invOfPivots_,  maximumRows_*sizeof(double));
+      } else invOfPivots_=NULL;
+  
+  if (other.colOfU_)
+      {
+	  colOfU_ = new int[maximumRows_];
+	  memcpy(colOfU_ , other.colOfU_, maximumRows_*sizeof(int));
+      } else colOfU_=NULL;
+  if (other.colPosition_)
+      {
+	  colPosition_ = new int[maximumRows_];
+	  memcpy(colPosition_, other.colPosition_,  maximumRows_*sizeof(int));
+      } else colPosition_=NULL;
+  if (other.rowOfU_)
+      {
+	  rowOfU_ = new int[maximumRows_];
+	  memcpy(rowOfU_ , other.rowOfU_, maximumRows_*sizeof(int));
+      } else rowOfU_=NULL;
+  if (other.rowPosition_)
+      {
+	  rowPosition_ = new int[maximumRows_];
+	  memcpy(rowPosition_ , other.rowPosition_,  maximumRows_*sizeof(int));
+      } else rowPosition_=NULL;
+  if (other.secRowOfU_)
+      {
+	  secRowOfU_ = new int[maximumRows_];
+	  memcpy(secRowOfU_ , other.secRowOfU_,  maximumRows_*sizeof(int));
+      } else secRowOfU_=NULL;
+  if (other.secRowPosition_)
+      {
+	  secRowPosition_ = new int[maximumRows_];
+	  memcpy(secRowPosition_ , other.secRowPosition_, maximumRows_*sizeof(int));
+      } else secRowPosition_=NULL;
+  
+  if (other.EtaPosition_)
+      {
+	  EtaPosition_ = new int[other.maxEtaRows_];
+	  memcpy(EtaPosition_ ,other.EtaPosition_ , other.maxEtaRows_ *sizeof(int));
+      } else EtaPosition_=NULL;
+  if (other.EtaStarts_)
+      {
+	  EtaStarts_ = new int[other.maxEtaRows_];
+	  memcpy(EtaStarts_, other.EtaStarts_, other.maxEtaRows_*sizeof(int));
+      } else EtaStarts_=NULL;
+  if (other.EtaLengths_)
+      {
+	  EtaLengths_ = new int[other.maxEtaRows_];
+	  memcpy(EtaLengths_, other.EtaLengths_, other.maxEtaRows_*sizeof(int));
+      } else EtaLengths_=NULL;
+  if (other.EtaInd_)
+      {
+	  EtaInd_	= new int[other.EtaMaxCap_];
+	  memcpy(EtaInd_, other.EtaInd_, other.EtaMaxCap_*sizeof(int));
+      } else EtaInd_=NULL;
+  if (other.Eta_)
+      {
+	  Eta_ = new double[other.EtaMaxCap_];
+	  memcpy(Eta_ , other.Eta_,  other.EtaMaxCap_*sizeof(double));
+      } else Eta_=NULL;
+  
+  
+  
+  doSuhlHeuristic_ = other.doSuhlHeuristic_;
+  maxU_ = other.maxU_;
+  maxGrowth_ = other.maxGrowth_;
+  maxA_ = other.maxA_;
+  pivotCandLimit_ = other.pivotCandLimit_;
+}
+
+//  getAreas.  Gets space for a factorization
+//called by constructors
+void
+CoinSimpFactorization::getAreas ( int numberOfRows,
+			 int numberOfColumns,
+			 CoinBigIndex ,
+			 CoinBigIndex  )
+{
+
+  numberRows_ = numberOfRows;
+  numberColumns_ = numberOfColumns;
+  CoinBigIndex size = numberRows_*(numberRows_+CoinMax(maximumPivots_,(numberRows_+1)>>1));
+  if (size>maximumSpace_) {
+    delete [] elements_;
+    elements_ = new CoinFactorizationDouble [size];
+    maximumSpace_ = size;
+  }
+  if (numberRows_>maximumRows_) {
+    maximumRows_ = numberRows_;
+    delete [] pivotRow_;
+    delete [] workArea_;
+    pivotRow_ = new int [2*maximumRows_+maximumPivots_];
+    workArea_ = new CoinFactorizationDouble [maximumRows_];    
+    allocateSomeArrays(); 
+  }
+}
+
+//  preProcess.  
+void
+CoinSimpFactorization::preProcess ()
+{
+    CoinBigIndex put = numberRows_*numberRows_;
+    int *indexRow = reinterpret_cast<int *> (elements_+put);
+    CoinBigIndex * starts = reinterpret_cast<CoinBigIndex *> (pivotRow_); 
+    initialSomeNumbers();
+
+    // compute sizes for Urows_ and Ucolumns_
+    //for ( int row=0; row < numberRows_; ++row )
+    //UrowLengths_[row]=0;
+    int k=0;
+    for ( int column=0; column < numberColumns_; ++column ){
+	UcolStarts_[column]=k;
+ 	//for (CoinBigIndex j=starts[column];j<starts[column+1];j++) {
+	//  int iRow = indexRow[j];
+	//  ++UrowLengths_[iRow];
+	//	}
+	UcolLengths_[column]=starts[column+1]-starts[column];
+#ifdef COIN_SIMP_CAPACITY
+	UcolCapacities_[column]=numberRows_;
+#endif
+	//k+=UcolLengths_[column]+minIncrease_;
+	k+=numberRows_;
+    }
+    
+    // create space for Urows_
+    k=0;
+    for ( int row=0; row < numberRows_; ++row ){
+	prevRowInU_[row]=row-1;
+	nextRowInU_[row]=row+1;
+	UrowStarts_[row]=k;
+	//k+=UrowLengths_[row]+minIncrease_;
+	k+=numberRows_;
+	UrowLengths_[row]=0;
+#ifdef COIN_SIMP_CAPACITY
+	UrowCapacities_[row]=numberRows_;
+#endif
+    }
+    UrowEnd_=k;
+    nextRowInU_[numberRows_-1]=-1;
+    firstRowInU_=0;
+    lastRowInU_=numberRows_-1;
+    maxA_=-1.0;
+    // build Ucolumns_ and Urows_
+    int colBeg, colEnd;
+    for ( int column=0; column < numberColumns_; ++column ){
+	prevColInU_[column]=column-1;
+	nextColInU_[column]=column+1;
+	k=0;
+	colBeg=starts[column];
+	colEnd=starts[column+1];
+	// identify slacks
+	if ( colEnd == colBeg+1 && elements_[colBeg]==slackValue_ )
+	    colSlack_[column]=1;
+	else colSlack_[column]=0;
+	//
+	for (int j=colBeg; j < colEnd; j++) {
+	    // Ucolumns_
+	    int iRow = indexRow[j];
+	    UcolInd_[UcolStarts_[column] + k]=iRow;
+	    ++k;
+	    // Urow_	    
+	    int ind=UrowStarts_[iRow]+UrowLengths_[iRow];
+	    UrowInd_[ind]=column;
+	    Urows_[ind]=elements_[j];
+	    //maxA_=CoinMax( maxA_, fabs(Urows_[ind]) );
+	    ++UrowLengths_[iRow];
+	}
+    }
+    nextColInU_[numberColumns_-1]=-1;
+    firstColInU_=0;
+    lastColInU_=numberColumns_-1;
+
+    // Initialize L
+    LcolSize_=0;
+    //LcolCap_=numberRows_*minIncrease_;
+    memset(LrowStarts_,-1,numberRows_ * sizeof(int));
+    memset(LrowLengths_,0,numberRows_ * sizeof(int));
+    memset(LcolStarts_,-1,numberRows_ * sizeof(int));
+    memset(LcolLengths_,0,numberRows_ * sizeof(int));
+
+    // initialize permutations    
+    for ( int i=0; i<numberRows_; ++i ){
+	rowOfU_[i]=i;
+	rowPosition_[i]=i;
+    } 
+    for ( int i=0; i<numberColumns_; ++i ){
+	colOfU_[i]=i;
+	colPosition_[i]=i;
+    }
+    //
+
+    doSuhlHeuristic_=true;
+
+}
+
+void CoinSimpFactorization::factorize(int numberOfRows,
+				     int numberOfColumns,
+				     const int colStarts[],
+				     const int indicesRow[],
+				     const double elements[])
+{
+    CoinBigIndex maximumL=0;
+    CoinBigIndex maximumU=0;
+    getAreas ( numberOfRows, numberOfColumns, maximumL, maximumU );
+
+    CoinBigIndex put = numberRows_*numberRows_;
+    int *indexRow = reinterpret_cast<int *> (elements_+put);
+    CoinBigIndex * starts = reinterpret_cast<CoinBigIndex *> (pivotRow_); 
+    for ( int column=0; column <= numberColumns_; ++column ){
+	starts[column]=colStarts[column];
+    }
+    const int limit=colStarts[numberColumns_];
+    for ( int i=0; i<limit; ++i ){
+	indexRow[i]=indicesRow[i];
+	elements_[i]=elements[i];
+    }
+
+    preProcess();
+    factor();
+}
+
+//Does factorization
+int
+CoinSimpFactorization::factor ( )
+{
+  numberPivots_=0;
+  status_= 0;
+
+  FactorPointers pointers(numberRows_, numberColumns_, UrowLengths_, UcolLengths_);
+  int rc=mainLoopFactor (pointers);
+  // rc=0 success
+  if ( rc != 0 ) { // failure
+      status_ = -1;
+      //return status_; // failure
+  }
+  //if ( rc == -3 ) {  // numerical instability
+  //    status_ = -1;
+  //    return status_;
+  //}
+
+  //copyLbyRows();
+  copyUbyColumns();
+  copyRowPermutations();  
+  firstNumberSlacks_=numberSlacks_;
+  // row permutations
+  if ( status_==-1 || numberColumns_ < numberRows_ ){
+      for (int j=0;j<numberRows_;j++)
+	  pivotRow_[j+numberRows_]=rowOfU_[j];
+      for (int j=0;j<numberRows_;j++) {
+	  int k = pivotRow_[j+numberRows_];
+	  pivotRow_[k]=j;
+      }
+  }
+  else // no permutations
+      for (int j=0;j<numberRows_;j++){
+	  pivotRow_[j]=j;
+	  pivotRow_[j+numberRows_]=j;
+      }
+
+  return status_;
+}
+//
+
+
+
+// Makes a non-singular basis by replacing variables
+void 
+CoinSimpFactorization::makeNonSingular(int * sequence, int numberColumns)
+{
+  // Replace bad ones by correct slack
+  int * workArea= reinterpret_cast<int *> (workArea_);
+  int i;
+  for ( i=0;i<numberRows_;i++) 
+    workArea[i]=-1;
+  for ( i=0;i<numberGoodU_;i++) {
+    int iOriginal = pivotRow_[i+numberRows_];
+    workArea[iOriginal]=i;
+    //workArea[i]=iOriginal;
+  }
+  int lastRow=-1;
+  for ( i=0;i<numberRows_;i++) {
+    if (workArea[i]==-1) {
+      lastRow=i;
+      break;
+    }
+  }
+  assert (lastRow>=0);
+  for ( i=numberGoodU_;i<numberRows_;i++) {
+    assert (lastRow<numberRows_);
+    // Put slack in basis
+    sequence[i]=lastRow+numberColumns;
+    lastRow++;
+    for (;lastRow<numberRows_;lastRow++) {
+      if (workArea[lastRow]==-1)
+	break;
+    }
+  }
+}
+// Does post processing on valid factorization - putting variables on correct rows
+void 
+CoinSimpFactorization::postProcess(const int * sequence, int * pivotVariable)
+{
+  for (int i=0;i<numberRows_;i++) {
+    int k = sequence[i];
+    pivotVariable[pivotRow_[i+numberRows_]]=k;
+  }
+}
+/* Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+   If checkBeforeModifying is true will do all accuracy checks
+   before modifying factorization.  Whether to set this depends on
+   speed considerations.  You could just do this on first iteration
+   after factorization and thereafter re-factorize
+   partial update already in U */
+int 
+CoinSimpFactorization::replaceColumn ( CoinIndexedVector * ,
+				      int pivotRow,
+				      double pivotCheck ,
+				       bool ,
+				       double )
+{
+    if (numberPivots_==maximumPivots_) 
+	return 3; 
+
+    double pivotValue = pivotCheck;
+    if (fabs(pivotValue)<zeroTolerance_)
+	return 2;
+    int realPivotRow = pivotRow_[pivotRow];
+
+    LUupdate(pivotRow);
+
+    pivotRow_[2*numberRows_+numberPivots_]=realPivotRow; 
+    numberPivots_++; 
+
+    return 0;
+}
+int 
+CoinSimpFactorization::updateColumn ( CoinIndexedVector * regionSparse,
+				       CoinIndexedVector * regionSparse2,
+				       bool noPermute) const
+{
+    return upColumn(regionSparse, regionSparse2, noPermute, false);
+}
+int 
+CoinSimpFactorization::updateColumnFT( CoinIndexedVector * regionSparse,
+				       CoinIndexedVector * regionSparse2,
+				       bool noPermute)
+{    
+
+    int rc=upColumn(regionSparse, regionSparse2, noPermute, true);
+    return rc;
+}
+
+
+int 
+CoinSimpFactorization::upColumn( CoinIndexedVector * regionSparse,
+				  CoinIndexedVector * regionSparse2,
+				  bool , bool save) const
+{
+    assert (numberRows_==numberColumns_);
+    double *region2 = regionSparse2->denseVector (  );
+    int *regionIndex = regionSparse2->getIndices (  );
+    int numberNonZero = regionSparse2->getNumElements (  );
+    double *region=regionSparse->denseVector (  );
+    if (!regionSparse2->packedMode()) {
+	region=regionSparse2->denseVector (  );
+    } 
+    else { // packed mode
+	for (int j=0;j<numberNonZero;j++) {
+	    region[regionIndex[j]]=region2[j];
+	    region2[j]=0.0;
+	}
+    } 
+
+    double *solution=workArea2_;
+    ftran(region, solution, save);
+
+    // get nonzeros
+    numberNonZero=0;
+    if (!regionSparse2->packedMode()) {
+	for (int i=0;i<numberRows_;i++) {
+	    const double value=solution[i];
+	    if ( fabs(value) > zeroTolerance_ ){
+		region[i]=value;
+		regionIndex[numberNonZero++]=i;
+	    }
+	    else
+		region[i]=0.0;	
+	}
+    } 
+    else { // packed mode
+	memset(region,0,numberRows_*sizeof(double));
+	for (int i=0;i<numberRows_;i++) {
+	    const double value=solution[i];
+	    if ( fabs(value) > zeroTolerance_ ){
+		region2[numberNonZero] = value;
+		regionIndex[numberNonZero++]=i;
+	    }
+	}
+    }
+    regionSparse2->setNumElements(numberNonZero);
+    return 0;
+}
+
+
+int 
+CoinSimpFactorization::updateTwoColumnsFT(CoinIndexedVector * regionSparse1,
+					  CoinIndexedVector * regionSparse2,
+					  CoinIndexedVector * regionSparse3,
+					  bool )
+{
+    assert (numberRows_==numberColumns_);
+
+    double *region2 = regionSparse2->denseVector (  );
+    int *regionIndex2 = regionSparse2->getIndices (  );
+    int numberNonZero2 = regionSparse2->getNumElements (  );
+
+    double *vec1=regionSparse1->denseVector (  );
+    if (!regionSparse2->packedMode()) {
+	vec1=regionSparse2->denseVector (  );
+    } 
+    else { // packed mode
+	for (int j=0;j<numberNonZero2;j++) {
+	    vec1[regionIndex2[j]]=region2[j];
+	    region2[j]=0.0;
+	}
+    }
+    //
+    double *region3 = regionSparse3->denseVector (  );
+    int *regionIndex3 = regionSparse3->getIndices (  );
+    int numberNonZero3 = regionSparse3->getNumElements (  );
+    double *vec2=auxVector_;
+    if (!regionSparse3->packedMode()) {
+	vec2=regionSparse3->denseVector (  );
+    } 
+    else { // packed mode
+	memset(vec2,0,numberRows_*sizeof(double));
+	for (int j=0;j<numberNonZero3;j++) {
+	    vec2[regionIndex3[j]]=region3[j];
+	    region3[j]=0.0;
+	}
+    }
+
+    double *solution1=workArea2_;
+    double *solution2=workArea3_;
+    ftran2(vec1, solution1, vec2, solution2);
+
+    // get nonzeros
+    numberNonZero2=0;
+    if (!regionSparse2->packedMode()) {
+	double value;
+	for (int i=0;i<numberRows_;i++) {
+	    value=solution1[i];
+	    if ( fabs(value) > zeroTolerance_ ){
+		vec1[i]=value;
+		regionIndex2[numberNonZero2++]=i;
+	    }
+	    else
+		vec1[i]=0.0;	
+	}
+    } 
+    else { // packed mode
+	double value;
+	for (int i=0;i<numberRows_;i++) {
+	    vec1[i]=0.0;
+	    value=solution1[i];
+	    if ( fabs(value) > zeroTolerance_ ){
+		region2[numberNonZero2] = value;
+		regionIndex2[numberNonZero2++]=i;
+	    }
+	}
+    }
+    regionSparse2->setNumElements(numberNonZero2);
+    //
+    numberNonZero3=0;
+    if (!regionSparse3->packedMode()) {
+	double value;
+	for (int i=0;i<numberRows_;i++) {
+	    value=solution2[i];
+	    if ( fabs(value) > zeroTolerance_ ){
+		vec2[i]=value;
+		regionIndex3[numberNonZero3++]=i;
+	    }
+	    else
+		vec2[i]=0.0;	
+	}
+    } 
+    else { // packed mode
+	double value;
+	for (int i=0;i<numberRows_;i++) {
+	    value=solution2[i];
+	    if ( fabs(value) > zeroTolerance_ ){
+		region3[numberNonZero3] = value;
+		regionIndex3[numberNonZero3++]=i;
+	    }
+	}
+    }
+    regionSparse3->setNumElements(numberNonZero3);
+    return 0;
+}
+
+
+
+int 
+CoinSimpFactorization::updateColumnTranspose ( CoinIndexedVector * regionSparse,
+					       CoinIndexedVector * regionSparse2) const
+{
+    upColumnTranspose(regionSparse, regionSparse2);
+    return 0;
+}
+
+int 
+CoinSimpFactorization::upColumnTranspose ( CoinIndexedVector * regionSparse,
+					       CoinIndexedVector * regionSparse2) const
+{
+    assert (numberRows_==numberColumns_);
+    double *region2 = regionSparse2->denseVector (  );
+    int *regionIndex = regionSparse2->getIndices (  );
+    int numberNonZero = regionSparse2->getNumElements (  );
+    double *region = regionSparse->denseVector (  );
+    if (!regionSparse2->packedMode()) {
+	region=regionSparse2->denseVector (  );
+    }
+    else { // packed
+	for (int j=0;j<numberNonZero;j++) {
+	    region[regionIndex[j]]=region2[j];
+	    region2[j]=0.0;  
+	}
+    }
+    double *solution=workArea2_;
+    btran(region, solution);
+    // get nonzeros
+    numberNonZero=0;
+    if (!regionSparse2->packedMode()) {
+	double value;
+	for (int i=0;i<numberRows_;i++) {
+	    value=solution[i];
+	    if ( fabs(value) > zeroTolerance_ ){
+		region[i]=value;
+		regionIndex[numberNonZero++]=i;
+	    }
+	    else
+		region[i]=0.0;	
+	}
+    } 
+    else { // packed mode
+	memset(region,0,numberRows_*sizeof(double));
+	for (int i=0;i<numberRows_;i++) {
+	    const double value=solution[i];
+	    if ( fabs(value) > zeroTolerance_ ){
+		region2[numberNonZero] = value;
+		regionIndex[numberNonZero++]=i;
+	    }
+	}
+    }
+    regionSparse2->setNumElements(numberNonZero);
+    return 0;
+}
+
+
+
+int
+CoinSimpFactorization::mainLoopFactor (FactorPointers &pointers )
+{
+    numberGoodU_=0;
+    numberSlacks_=0;
+    bool ifSlack=true;
+    for ( int i=0; i<numberColumns_; ++i ){
+	int r, s;
+	//s=i; 
+	if ( findPivot(pointers,r,s,ifSlack) ){
+	    return -1;
+	}
+	if ( ifSlack ) ++numberSlacks_;
+	const int rowPos=rowPosition_[r];
+	const int colPos=colPosition_[s];
+	assert( i <= rowPos && rowPos < numberRows_);
+	assert( i <= colPos && colPos < numberColumns_);
+	// permute columns
+	int j=colOfU_[i];
+	colOfU_[i]=colOfU_[colPos];
+	colOfU_[colPos]=j;
+	colPosition_[colOfU_[i]]=i;
+	colPosition_[colOfU_[colPos]]=colPos;
+	// permute rows
+	j=rowOfU_[i];
+	rowOfU_[i]=rowOfU_[rowPos];
+	rowOfU_[rowPos]=j;
+	rowPosition_[rowOfU_[i]]=i;
+	rowPosition_[rowOfU_[rowPos]]=rowPos;
+	GaussEliminate(pointers,r,s);
+	//if ( maxU_ > maxGrowth_ * maxA_  ){
+	//  return -3;
+	//}
+	++numberGoodU_;
+    }
+    return 0;
+}
+/// find a pivot in the active part of U
+int CoinSimpFactorization::findPivot(FactorPointers &pointers, int &r,
+				     int &s, bool &ifSlack){
+    int *firstRowKnonzeros=pointers.firstRowKnonzeros;
+    int *nextRow=pointers.nextRow;
+    int *firstColKnonzeros=pointers.firstColKnonzeros;
+    int *prevColumn=pointers.prevColumn;
+    int *nextColumn=pointers.nextColumn;
+    r=s=-1;
+    int numCandidates=0;
+    double bestMarkowitzCount=COIN_DBL_MAX;
+    // if there is a column with one element choose it as pivot
+    int column=firstColKnonzeros[1];
+    if ( column!=-1 ){
+	assert( UcolLengths_[column] == 1 );
+	r=UcolInd_[UcolStarts_[column]];
+	s=column;
+	if ( !colSlack_[column] )
+	    ifSlack=false;
+	return 0;
+    } 
+    // from now on no more slacks
+    ifSlack=false;
+    // if there is a  row with one element choose it
+    int row=firstRowKnonzeros[1];
+    if ( row!=-1 ){
+	assert( UrowLengths_[row] == 1 );
+	s=UrowInd_[UrowStarts_[row]];
+	r=row;
+	return 0;
+    }
+    // consider other rows and columns
+    for ( int length=2; length <=numberRows_; ++length){
+	int nextCol=-1;
+	for ( column=firstColKnonzeros[length]; column!=-1; column=nextCol ){
+	    nextCol=nextColumn[column];
+	    int minRow, minRowLength;
+	    int rc=findShortRow(column, length, minRow, minRowLength, pointers);
+	    if ( rc== 0 ){
+		r=minRow;
+		s=column;
+		return 0;
+	    }
+	    if ( minRow != -1 ){
+		++numCandidates;
+		double MarkowitzCount=static_cast<double>(minRowLength-1)*(length-1);
+		if ( MarkowitzCount < bestMarkowitzCount ){
+		    r=minRow; s=column;
+		    bestMarkowitzCount=MarkowitzCount;
+		}
+		if ( numCandidates == pivotCandLimit_ ) return 0;
+	    }
+	    else {
+		if ( doSuhlHeuristic_ ){ 
+		    // this column did not give a candidate, it will be
+		    // removed until it becomes a singleton
+		    removeColumnFromActSet(column, pointers);
+		    prevColumn[column]=nextColumn[column]=column;
+		}
+	    }
+	} // end for ( column= ....
+	// now rows
+	for ( row=firstRowKnonzeros[length]; row!=-1; row=nextRow[row] ){
+	    int minCol, minColLength;
+	    int rc=findShortColumn(row, length, minCol, minColLength, pointers);
+	    if ( rc==0 ){
+		r=row;
+		s=minCol;
+		return 0;
+	    }
+	    if ( minCol != -1 ){
+		++numCandidates;
+		double MarkowitzCount=static_cast<double>(minColLength-1)*(length-1);
+		if ( MarkowitzCount < bestMarkowitzCount ){
+		    r=row; s=minCol;
+		    bestMarkowitzCount=MarkowitzCount;
+		}
+		if ( numCandidates == pivotCandLimit_ ) return 0;
+	    }
+	    //else abort();
+	}// end for ( row= ...
+    }// end for ( int length= ...
+    if ( r== -1 || s==-1 ) return 1;
+    else return 0; 
+}
+//
+int CoinSimpFactorization::findPivotShCol(FactorPointers &pointers, int &r, int &s)
+{
+    int *firstColKnonzeros=pointers.firstColKnonzeros;
+    r=s=-1;
+    // if there is a column with one element choose it as pivot
+    int column=firstColKnonzeros[1];
+    if ( column!=-1 ){
+	assert( UcolLengths_[column] == 1 );
+	r=UcolInd_[UcolStarts_[column]];
+	s=column;
+	return 0;
+    }
+    // consider other columns
+    for ( int length=2; length <=numberRows_; ++length){
+	column=firstColKnonzeros[length];
+	if ( column != -1 ) break;
+    }
+    if ( column == -1 ) return 1;
+    // find largest element
+    const int colBeg=UcolStarts_[column];
+    const int colEnd=colBeg+UcolLengths_[column];
+    double largest=0.0;
+    int rowLargest=-1;
+    for ( int j=colBeg; j<colEnd; ++j ){
+	const int row=UcolInd_[j];
+	const int columnIndx=findInRow(row,column);
+	assert(columnIndx!=-1);
+	double coeff=fabs(Urows_[columnIndx]);
+	if ( coeff < largest ) continue;
+	largest=coeff;
+	rowLargest=row;
+    }
+    assert(rowLargest != -1);
+    s=column;
+    r=rowLargest;
+    return 0;
+}
+
+int CoinSimpFactorization::findPivotSimp(FactorPointers &, int &r, int &s){
+    r=-1;
+    int column=s;    
+    const int colBeg=UcolStarts_[column];
+    const int colEnd=colBeg+UcolLengths_[column];
+    double largest=0.0;
+    int rowLargest=-1;
+    for ( int j=colBeg; j<colEnd; ++j ){
+	const int row=UcolInd_[j];
+	const int columnIndx=findInRow(row,column);
+	assert(columnIndx!=-1);
+	double coeff=fabs(Urows_[columnIndx]);
+	if ( coeff < largest ) continue;
+	largest=coeff;
+	rowLargest=row;
+    }
+    if ( rowLargest != -1 ){
+	r=rowLargest;
+	return 0;
+    }
+    else return 1; 
+}
+
+
+int CoinSimpFactorization::findShortRow(const int column,
+				       const int length,
+				       int &minRow, 
+				       int &minRowLength,
+				       FactorPointers &pointers)
+{
+    const int colBeg=UcolStarts_[column];
+    const int colEnd=colBeg+UcolLengths_[column];
+    minRow=-1;
+    minRowLength= COIN_INT_MAX;
+    for ( int j=colBeg; j<colEnd; ++j ){
+	int row=UcolInd_[j];
+	if ( UrowLengths_[row] >= minRowLength ) continue;
+	double largestInRow=findMaxInRrow(row,pointers);
+	// find column in row
+	int columnIndx=findInRow(row,column);
+	assert(columnIndx!=-1);
+	double coeff=Urows_[columnIndx];
+	if ( fabs(coeff) < pivotTolerance_ * largestInRow ) continue;
+	minRow=row; minRowLength=UrowLengths_[row];
+	if ( UrowLengths_[row] <= length ) return 0;
+    }
+    return 1;
+}
+int CoinSimpFactorization::findShortColumn(const int row,
+					  const int length,
+					  int &minCol,
+					  int &minColLength,
+					  FactorPointers &pointers)
+{	
+    const int rowBeg=UrowStarts_[row];
+    const int rowEnd=rowBeg+UrowLengths_[row];    
+    minCol=-1;
+    minColLength=COIN_INT_MAX;
+    double largestInRow=findMaxInRrow(row,pointers);
+    for ( int i=rowBeg; i<rowEnd; ++i ){
+	int column=UrowInd_[i];
+	if ( UcolLengths_[column] >= minColLength ) continue;
+	double coeff=Urows_[i];
+	if ( fabs(coeff) < pivotTolerance_ * largestInRow ) continue;
+	minCol=column;
+	minColLength=UcolLengths_[column];
+	if ( minColLength <= length ) return 0;
+    }
+    return 1;
+}
+// Gaussian elimination
+void CoinSimpFactorization::GaussEliminate(FactorPointers &pointers, int &pivotRow, int &pivotCol)
+{
+    assert( pivotRow >= 0 && pivotRow < numberRows_ );
+    assert( pivotCol >= 0 && pivotCol < numberRows_ );
+    int *firstColKnonzeros=pointers.firstColKnonzeros;
+    int *prevColumn=pointers.prevColumn;
+    int *nextColumn=pointers.nextColumn;
+    int *colLabels=vecLabels_;
+    double *denseRow=denseVector_;
+    removeRowFromActSet(pivotRow, pointers);
+    removeColumnFromActSet(pivotCol, pointers);
+    // find column s 
+    int indxColS=findInRow(pivotRow, pivotCol);
+    assert( indxColS >= 0 );
+    // store the inverse of the pivot and remove it from row
+    double invPivot=1.0/Urows_[indxColS];
+    invOfPivots_[pivotRow]=invPivot;    
+    int rowBeg=UrowStarts_[pivotRow];
+    int rowEnd=rowBeg+UrowLengths_[pivotRow];
+    Urows_[indxColS]=Urows_[rowEnd-1];
+    UrowInd_[indxColS]=UrowInd_[rowEnd-1];
+    --UrowLengths_[pivotRow];
+    --rowEnd;
+    // now remove pivot from column
+    int indxRowR=findInColumn(pivotCol,pivotRow);
+    assert( indxRowR >= 0 );
+    const int pivColEnd=UcolStarts_[pivotCol]+UcolLengths_[pivotCol];
+    UcolInd_[indxRowR]=UcolInd_[pivColEnd-1];
+    --UcolLengths_[pivotCol];
+    // go through pivot row
+    for ( int i=rowBeg; i<rowEnd; ++i ){
+	int column=UrowInd_[i];
+	colLabels[column]=1;
+	denseRow[column]=Urows_[i];
+	// remove this column from bucket because it will change
+	removeColumnFromActSet(column, pointers);
+	// remove element (pivotRow, column) from column
+	int indxRow=findInColumn(column,pivotRow);
+	assert( indxRow>=0 );
+	const int colEnd=UcolStarts_[column]+UcolLengths_[column];
+	UcolInd_[indxRow]=UcolInd_[colEnd-1];
+	--UcolLengths_[column];
+    }
+    //
+    pivoting(pivotRow, pivotCol, invPivot, pointers);
+    //    
+    rowBeg=UrowStarts_[pivotRow];
+    rowEnd=rowBeg+UrowLengths_[pivotRow];
+    for ( int i=rowBeg; i<rowEnd; ++i ){
+	int column=UrowInd_[i];
+	// clean back these two arrays
+	colLabels[column]=0;
+	denseRow[column]=0.0;
+	// column goes into a bucket, if Suhl' heuristic had removed it, it
+	// can go back only if it is a singleton
+	if ( UcolLengths_[column] != 1 || 
+	     prevColumn[column]!=column || nextColumn[column]!=column )
+	    {
+		prevColumn[column]=-1;
+		nextColumn[column]=firstColKnonzeros[UcolLengths_[column]];
+		if ( nextColumn[column] != -1 )
+		    prevColumn[nextColumn[column]]=column;
+		firstColKnonzeros[UcolLengths_[column]]=column;
+	    }
+    }
+}
+void CoinSimpFactorization::pivoting(const int pivotRow,
+				    const int pivotColumn,
+				    const double invPivot,
+				    FactorPointers &pointers)
+{   
+    // initialize the new column of L
+    LcolStarts_[pivotRow]=LcolSize_;
+    // go trough pivot column
+    const int colBeg=UcolStarts_[pivotColumn];
+    int colEnd=colBeg+UcolLengths_[pivotColumn];
+    for ( int i=colBeg; i<colEnd; ++i ){
+	int row=UcolInd_[i];
+	// remove row from bucket because it will change
+	removeRowFromActSet(row, pointers);
+	// find pivot column 
+	int pivotColInRow=findInRow(row,pivotColumn);
+	assert(pivotColInRow >= 0);
+	const double multiplier=Urows_[pivotColInRow]*invPivot;
+	// remove element (row,pivotColumn) from row
+	const int currentRowEnd=UrowStarts_[row]+UrowLengths_[row];
+	Urows_[pivotColInRow]=Urows_[currentRowEnd-1];
+	UrowInd_[pivotColInRow]=UrowInd_[currentRowEnd-1];
+	--UrowLengths_[row];
+	int newNonZeros=UrowLengths_[pivotRow];
+	updateCurrentRow(pivotRow, row, multiplier, pointers, 
+			 newNonZeros); 
+	// store multiplier
+	if ( LcolSize_ == LcolCap_ ) increaseLsize();
+	Lcolumns_[LcolSize_]=multiplier;
+	LcolInd_[LcolSize_++]=row;
+	++LcolLengths_[pivotRow];
+    }
+    // remove elements of pivot column
+    UcolLengths_[pivotColumn]=0;
+    // remove pivot column from Ucol_
+    if ( prevColInU_[pivotColumn]==-1 )
+	firstColInU_=nextColInU_[pivotColumn];
+    else{
+	nextColInU_[prevColInU_[pivotColumn]]=nextColInU_[pivotColumn];
+#ifdef COIN_SIMP_CAPACITY
+	UcolCapacities_[prevColInU_[pivotColumn]]+=UcolCapacities_[pivotColumn];
+	UcolCapacities_[pivotColumn]=0;
+#endif
+    }
+    if ( nextColInU_[pivotColumn] == -1 )
+	lastColInU_=prevColInU_[pivotColumn];
+    else
+	prevColInU_[nextColInU_[pivotColumn]]=prevColInU_[pivotColumn];
+}
+
+
+
+void CoinSimpFactorization::updateCurrentRow(const int pivotRow,
+					    const int row, 
+					    const double multiplier,
+					    FactorPointers &pointers,
+					    int &newNonZeros)
+{   
+    double *rowMax=pointers.rowMax; 
+    int *firstRowKnonzeros=pointers.firstRowKnonzeros;
+    int *prevRow=pointers.prevRow;
+    int *nextRow=pointers.nextRow;
+    int *colLabels=vecLabels_;
+    double *denseRow=denseVector_;
+    const int rowBeg=UrowStarts_[row];
+    int rowEnd=rowBeg+UrowLengths_[row];
+    // treat old nonzeros
+    for ( int i=rowBeg; i<rowEnd; ++i ){
+	const int column=UrowInd_[i];
+	if ( colLabels[column] ){
+	    Urows_[i]-= multiplier*denseRow[column];
+	    const double absNewCoeff=fabs(Urows_[i]);
+	    colLabels[column]=0;
+	    --newNonZeros;
+	    if ( absNewCoeff < zeroTolerance_ ){
+		// remove it from row
+		UrowInd_[i]=UrowInd_[rowEnd-1];
+		Urows_[i]=Urows_[rowEnd-1];
+		--UrowLengths_[row];
+		--i;
+		--rowEnd;
+		// remove it from column
+		int indxRow=findInColumn(column, row);
+		assert( indxRow >= 0 );
+		const int colEnd=UcolStarts_[column]+UcolLengths_[column];
+		UcolInd_[indxRow]=UcolInd_[colEnd-1];
+		--UcolLengths_[column];
+	    }
+	    else
+		{
+		    if ( maxU_ < absNewCoeff )
+			maxU_=absNewCoeff;	
+		}
+	}
+    }
+    // now add the new nonzeros to the row
+#ifdef COIN_SIMP_CAPACITY
+    if ( UrowLengths_[row] + newNonZeros > UrowCapacities_[row] )
+	increaseRowSize(row, UrowLengths_[row] + newNonZeros);
+#endif
+    const int pivotRowBeg=UrowStarts_[pivotRow];
+    const int pivotRowEnd=pivotRowBeg+UrowLengths_[pivotRow];
+    int numNew=0;
+    int *newCols=pointers.newCols;
+    for ( int i=pivotRowBeg; i<pivotRowEnd; ++i ){
+	const int column=UrowInd_[i];
+	if ( colLabels[column] ){
+	    const double value= -multiplier*denseRow[column];
+	    const double absNewCoeff=fabs(value);
+	    if ( absNewCoeff >= zeroTolerance_ ){
+		const int newInd=UrowStarts_[row]+UrowLengths_[row];
+		Urows_[newInd]=value;
+		UrowInd_[newInd]=column;
+		++UrowLengths_[row];
+		newCols[numNew++]=column;
+		if ( maxU_ < absNewCoeff ) maxU_=absNewCoeff;
+	    }
+	}
+	else colLabels[column]=1;
+    }
+    // add the new nonzeros to the columns
+    for ( int i=0; i<numNew; ++i){
+	const int column=newCols[i];
+#ifdef COIN_SIMP_CAPACITY
+	if ( UcolLengths_[column] + 1 > UcolCapacities_[column] ){
+	    increaseColSize(column, UcolLengths_[column] + 1, false);
+	}
+#endif 
+	const int newInd=UcolStarts_[column]+UcolLengths_[column];
+	UcolInd_[newInd]=row;
+	++UcolLengths_[column];
+    }
+    // the row goes to a new bucket
+    prevRow[row]=-1;
+    nextRow[row]=firstRowKnonzeros[UrowLengths_[row]];
+    if ( nextRow[row]!=-1 ) prevRow[nextRow[row]]=row;
+    firstRowKnonzeros[UrowLengths_[row]]=row;
+    //
+    rowMax[row]=-1.0;
+}
+#ifdef COIN_SIMP_CAPACITY
+
+void CoinSimpFactorization::increaseRowSize(const int row,
+					   const int newSize)
+{
+    assert( newSize > UrowCapacities_[row] );
+    const int newNumElements=newSize + minIncrease_;
+    if ( UrowMaxCap_ < UrowEnd_ + newNumElements ){
+	enlargeUrow( UrowEnd_ + newNumElements - UrowMaxCap_ );
+    }
+    int currentCapacity=UrowCapacities_[row];
+    memcpy(&Urows_[UrowEnd_],&Urows_[UrowStarts_[row]],
+	    UrowLengths_[row] * sizeof(double));
+    memcpy(&UrowInd_[UrowEnd_],&UrowInd_[UrowStarts_[row]],
+	    UrowLengths_[row] * sizeof(int));
+    UrowStarts_[row]=UrowEnd_;
+    UrowCapacities_[row]=newNumElements;
+    UrowEnd_+=UrowCapacities_[row];
+    if ( firstRowInU_==lastRowInU_ ) return; // only one element
+    // remove row from list
+    if( prevRowInU_[row]== -1)
+	firstRowInU_=nextRowInU_[row];
+    else {
+	nextRowInU_[prevRowInU_[row]]=nextRowInU_[row];
+	UrowCapacities_[prevRowInU_[row]]+=currentCapacity;
+    }
+    if ( nextRowInU_[row]==-1 )
+	lastRowInU_=prevRowInU_[row];
+    else
+	prevRowInU_[nextRowInU_[row]]=prevRowInU_[row];
+    // add row at the end of list
+    nextRowInU_[lastRowInU_]=row;
+    nextRowInU_[row]=-1;
+    prevRowInU_[row]=lastRowInU_;
+    lastRowInU_=row;
+}
+#endif 
+#ifdef COIN_SIMP_CAPACITY
+void CoinSimpFactorization::increaseColSize(const int column,
+					   const int newSize,
+					   const bool ifElements)
+{
+    assert( newSize > UcolCapacities_[column] );
+    const int newNumElements=newSize+minIncrease_;
+    if ( UcolMaxCap_ < UcolEnd_ + newNumElements ){
+	enlargeUcol(UcolEnd_ + newNumElements - UcolMaxCap_,
+		    ifElements);
+    }
+    int currentCapacity=UcolCapacities_[column];
+    memcpy(&UcolInd_[UcolEnd_], &UcolInd_[UcolStarts_[column]],
+	    UcolLengths_[column] * sizeof(int));
+    if ( ifElements ){
+	memcpy(&Ucolumns_[UcolEnd_], &Ucolumns_[UcolStarts_[column]],
+	       UcolLengths_[column] * sizeof(double) );       
+    }
+    UcolStarts_[column]=UcolEnd_;
+    UcolCapacities_[column]=newNumElements;
+    UcolEnd_+=UcolCapacities_[column];
+    if ( firstColInU_==lastColInU_ ) return; // only one column
+    // remove from list
+    if ( prevColInU_[column]==-1 )
+	firstColInU_=nextColInU_[column];
+    else {
+	nextColInU_[prevColInU_[column]]=nextColInU_[column];
+	UcolCapacities_[prevColInU_[column]]+=currentCapacity;
+    }
+    if ( nextColInU_[column]==-1 )
+	lastColInU_=prevColInU_[column];
+    else
+	prevColInU_[nextColInU_[column]]=prevColInU_[column];
+    // add column at the end
+    nextColInU_[lastColInU_]=column;
+    nextColInU_[column]=-1;
+    prevColInU_[column]=lastColInU_;
+    lastColInU_=column;    
+}
+#endif 
+double CoinSimpFactorization::findMaxInRrow(const int row,
+					    FactorPointers &pointers)
+{
+    double *rowMax=pointers.rowMax; 
+    double largest=rowMax[row];
+    if ( largest >= 0.0 ) return largest;
+    const int rowBeg=UrowStarts_[row];
+    const int rowEnd=rowBeg+UrowLengths_[row];
+    for ( int i=rowBeg; i<rowEnd; ++i ) {
+	const double absValue=fabs(Urows_[i]);
+	if ( absValue  > largest )
+	    largest=absValue;
+    }
+    rowMax[row]=largest;
+    return largest;
+}
+void CoinSimpFactorization::increaseLsize()
+{
+    int newcap= LcolCap_ + minIncrease_;
+
+    double *aux=new double[newcap];
+    memcpy(aux, Lcolumns_, LcolCap_ * sizeof(double));
+    delete [] Lcolumns_;
+    Lcolumns_=aux;
+    
+    int *iaux=new int[newcap];
+    memcpy(iaux, LcolInd_, LcolCap_ * sizeof(int));
+    delete [] LcolInd_;
+    LcolInd_=iaux;
+
+    LcolCap_=newcap;
+}
+void CoinSimpFactorization::enlargeUcol(const int numNewElements, const bool ifElements)
+{
+    int *iaux=new int[UcolMaxCap_+numNewElements];
+    memcpy(iaux, UcolInd_, UcolMaxCap_*sizeof(int) );
+    delete [] UcolInd_;
+    UcolInd_=iaux;
+
+    if ( ifElements ){
+	double *aux=new double[UcolMaxCap_+numNewElements];
+	memcpy(aux, Ucolumns_, UcolMaxCap_*sizeof(double) );
+	delete [] Ucolumns_;
+	Ucolumns_=aux;
+    }
+
+    UcolMaxCap_+=numNewElements;
+}
+void CoinSimpFactorization::enlargeUrow(const int numNewElements)
+{
+    int *iaux=new int[UrowMaxCap_+numNewElements];
+    memcpy(iaux, UrowInd_, UrowMaxCap_*sizeof(int) );
+    delete [] UrowInd_;
+    UrowInd_=iaux;
+    
+    double *aux=new double[UrowMaxCap_+numNewElements];
+    memcpy(aux, Urows_, UrowMaxCap_*sizeof(double) );
+    delete [] Urows_;
+    Urows_=aux;
+
+    UrowMaxCap_+=numNewElements;
+}
+
+void CoinSimpFactorization::copyUbyColumns()
+{
+    memset(UcolLengths_,0,numberColumns_*sizeof(int));
+    for ( int column=0; column<numberColumns_; ++column ){
+	prevColInU_[column]=column-1;
+	nextColInU_[column]=column+1;
+    }   
+    nextColInU_[numberColumns_-1]=-1;
+    firstColInU_=0;
+    lastColInU_=numberColumns_-1;
+    //int nonZeros=0;
+    //for ( int row=0; row<numberRows_; ++row ){
+    //const int rowBeg=UrowStarts_[row];
+    //const int rowEnd=rowBeg+UrowLengths_[row];
+    //for ( int j=rowBeg; j<rowEnd; ++j )
+    //   ++UcolCapacities_[UrowInd_[j]];
+    //	nonZeros+=UrowLengths_[row];
+    //   }
+    // 
+    //memset(UcolCapacities_, numberRows_, numberColumns_ * sizeof(int));
+#ifdef COIN_SIMP_CAPACITY
+    for ( int i=0; i<numberColumns_; ++i ) UcolCapacities_[i]=numberRows_;
+#endif 
+    int k=0;
+    for ( int column=0; column<numberColumns_; ++column ){
+	UcolStarts_[column]=k;
+	//UcolCapacities_[column]+=minIncrease_;
+	//k+=UcolCapacities_[column];
+	k+=numberRows_;
+    }
+    UcolEnd_=k;
+    // go through the rows and fill the columns, assume UcolLengths_[]=0
+    for ( int row=0; row<numberRows_; ++row ){
+	const int rowBeg=UrowStarts_[row];
+	int rowEnd=rowBeg+UrowLengths_[row];
+	for ( int j=rowBeg; j<rowEnd; ++j ){
+	    // remove els close to zero
+	    while( fabs( Urows_[j] ) < zeroTolerance_ ){
+		--UrowLengths_[row];
+		--rowEnd;
+		if ( j < rowEnd ){
+		    Urows_[j]=Urows_[rowEnd];
+		    UrowInd_[j]=UrowInd_[rowEnd];
+		}
+		else break;
+	    }
+	    if ( j==rowEnd ) continue;
+	    //
+	    const int column=UrowInd_[j];
+	    const int indx=UcolStarts_[column]+UcolLengths_[column];
+	    Ucolumns_[indx]=Urows_[j];
+	    UcolInd_[indx]=row;
+	    ++UcolLengths_[column];
+	}
+    }
+}
+void CoinSimpFactorization::copyLbyRows()
+{
+    int nonZeros=0;
+    memset(LrowLengths_,0,numberRows_*sizeof(int));
+    for ( int column=0; column<numberRows_; ++column ){
+	const int colBeg=LcolStarts_[column];
+	const int colEnd=colBeg+LcolLengths_[column];
+	for ( int j=colBeg; j<colEnd; ++j )
+	    ++LrowLengths_[LcolInd_[j]];
+	nonZeros+=LcolLengths_[column];
+    }
+    //
+    LrowSize_=nonZeros;
+    int k=0;
+    for ( int row=0; row<numberRows_; ++row ){
+	LrowStarts_[row]=k;
+	k+=LrowLengths_[row];
+    }
+#ifdef COIN_SIMP_CAPACITY
+    //memset(LrowLengths_,0,numberRows_*sizeof(int));
+    // fill the rows
+    for ( int column=0; column<numberRows_; ++column ){
+	const int colBeg=LcolStarts_[column];
+	const int colEnd=colBeg+LcolLengths_[column];
+	for ( int j=colBeg; j<colEnd; ++j ){
+	    const int row=LcolInd_[j];
+	    const int indx=LrowStarts_[row]++;
+	    Lrows_[indx]=Lcolumns_[j];
+	    LrowInd_[indx]=column;
+	}
+    }
+    // Put back starts
+    k=0;
+    for ( int row=0; row<numberRows_; ++row ){
+      int next = LrowStarts_[row];
+      LrowStarts_[row]=k;
+      k=next;
+    }
+#else
+    memset(LrowLengths_,0,numberRows_*sizeof(int));
+    // fill the rows
+    for ( int column=0; column<numberRows_; ++column ){
+	const int colBeg=LcolStarts_[column];
+	const int colEnd=colBeg+LcolLengths_[column];
+	for ( int j=colBeg; j<colEnd; ++j ){
+	    const int row=LcolInd_[j];
+	    const int indx=LrowStarts_[row] + LrowLengths_[row];
+	    Lrows_[indx]=Lcolumns_[j];
+	    LrowInd_[indx]=column;
+	    ++LrowLengths_[row];
+	}
+    }
+#endif
+}
+
+
+int CoinSimpFactorization::findInRow(const int row,
+				    const int column)
+{
+    const int rowBeg=UrowStarts_[row]; 
+    const int rowEnd=rowBeg+UrowLengths_[row];
+    int columnIndx=-1;
+    for ( int i=rowBeg; i<rowEnd; ++i ){
+	if ( UrowInd_[i]==column ){
+	    columnIndx=i;
+	    break;
+	}
+    }
+    return columnIndx;
+}
+int CoinSimpFactorization::findInColumn(const int column,
+				       const int row)
+{
+    int indxRow=-1; 
+    const int colBeg=UcolStarts_[column];
+    const int colEnd=colBeg+UcolLengths_[column];
+    for ( int i=colBeg; i<colEnd; ++i ){
+	if (UcolInd_[i]==row){
+	    indxRow=i;
+	    break;
+	}
+    }
+    return indxRow;
+}
+void CoinSimpFactorization::removeRowFromActSet(const int row, 
+					       FactorPointers &pointers)
+{    
+    int *firstRowKnonzeros=pointers.firstRowKnonzeros;
+    int *prevRow=pointers.prevRow;
+    int *nextRow=pointers.nextRow;
+    if ( prevRow[row]==-1 )
+	firstRowKnonzeros[UrowLengths_[row]]=nextRow[row];
+    else nextRow[prevRow[row]]=nextRow[row];
+    if ( nextRow[row] != -1)
+	prevRow[nextRow[row]]=prevRow[row];
+}
+void CoinSimpFactorization::removeColumnFromActSet(const int column,
+						  FactorPointers &pointers)
+{
+    int *firstColKnonzeros=pointers.firstColKnonzeros;
+    int *prevColumn=pointers.prevColumn;
+    int *nextColumn=pointers.nextColumn;
+    if ( prevColumn[column]==-1 )
+	firstColKnonzeros[UcolLengths_[column]]=nextColumn[column];
+    else nextColumn[prevColumn[column]]=nextColumn[column];
+    if ( nextColumn[column] != -1 )
+	prevColumn[nextColumn[column]]=prevColumn[column];	
+}
+void CoinSimpFactorization::allocateSomeArrays()
+{
+    if (denseVector_) delete [] denseVector_;
+    denseVector_ = new double[numberRows_];
+    memset(denseVector_,0,numberRows_*sizeof(double));
+    if(workArea2_) delete [] workArea2_;
+    workArea2_ = new double[numberRows_];
+    if(workArea3_) delete [] workArea3_;
+    workArea3_ = new double[numberRows_];
+
+    if(vecLabels_) delete [] vecLabels_; 
+    vecLabels_ = new int[numberRows_];
+    memset(vecLabels_,0, numberRows_*sizeof(int)); 
+    if(indVector_) delete [] indVector_;
+    indVector_ = new int[numberRows_];
+
+    if (auxVector_) delete [] auxVector_;
+    auxVector_ = new double[numberRows_]; 
+    if (auxInd_) delete [] auxInd_;
+    auxInd_ = new int[numberRows_];
+
+    if (vecKeep_) delete [] vecKeep_;
+    vecKeep_ = new double[numberRows_];
+    if (indKeep_) delete [] indKeep_;
+    indKeep_ = new int[numberRows_];
+
+    if (LrowStarts_) delete [] LrowStarts_;
+    LrowStarts_ = new int[numberRows_];
+    if (LrowLengths_) delete [] LrowLengths_;
+    LrowLengths_ = new int[numberRows_];
+
+    LrowCap_=(numberRows_*(numberRows_-1))/2;
+    if (Lrows_) delete [] Lrows_;
+    Lrows_ = new double[LrowCap_];
+    if (LrowInd_) delete [] LrowInd_;
+    LrowInd_ = new int[LrowCap_];
+
+    if (LcolStarts_) delete [] LcolStarts_;
+    LcolStarts_ = new int[numberRows_];
+    if (LcolLengths_) delete [] LcolLengths_;
+    LcolLengths_ = new int[numberRows_];
+    LcolCap_=LrowCap_;
+    if (Lcolumns_) delete [] Lcolumns_;
+    Lcolumns_ = new double[LcolCap_];
+    if (LcolInd_) delete [] LcolInd_;
+    LcolInd_ = new int[LcolCap_];
+
+    if (UrowStarts_) delete [] UrowStarts_; 
+    UrowStarts_ = new int[numberRows_];
+    if (UrowLengths_) delete [] UrowLengths_;
+    UrowLengths_ = new int[numberRows_];
+#ifdef COIN_SIMP_CAPACITY
+    if (UrowCapacities_) delete [] UrowCapacities_;
+    UrowCapacities_ = new int[numberRows_];
+#endif 
+
+    minIncrease_=10;
+    UrowMaxCap_=numberRows_*(numberRows_+minIncrease_);
+    if (Urows_) delete [] Urows_;
+    Urows_ = new double[UrowMaxCap_];
+    if (UrowInd_) delete [] UrowInd_;
+    UrowInd_ = new int[UrowMaxCap_];
+
+    if (prevRowInU_) delete [] prevRowInU_;
+    prevRowInU_ = new int[numberRows_];
+    if (nextRowInU_) delete [] nextRowInU_;
+    nextRowInU_ = new int[numberRows_];
+
+    if (UcolStarts_) delete [] UcolStarts_;
+    UcolStarts_ = new int[numberRows_];
+    if (UcolLengths_) delete [] UcolLengths_;
+    UcolLengths_ = new int[numberRows_];
+#ifdef COIN_SIMP_CAPACITY
+    if (UcolCapacities_) delete [] UcolCapacities_;
+    UcolCapacities_ = new int[numberRows_]; 
+#endif 
+
+    UcolMaxCap_=UrowMaxCap_;
+    if (Ucolumns_) delete [] Ucolumns_;
+    Ucolumns_ = new double[UcolMaxCap_];
+    if (UcolInd_) delete [] UcolInd_;
+    UcolInd_ = new int[UcolMaxCap_];
+
+    if (prevColInU_) delete [] prevColInU_;
+    prevColInU_ = new int[numberRows_]; 
+    if (nextColInU_) delete [] nextColInU_;
+    nextColInU_ = new int[numberRows_];
+    if (colSlack_) delete [] colSlack_;
+    colSlack_ = new int[numberRows_]; 
+
+    if (invOfPivots_) delete [] invOfPivots_;
+    invOfPivots_ = new double[numberRows_];
+
+    if (colOfU_) delete [] colOfU_;
+    colOfU_ = new int[numberRows_];
+    if (colPosition_) delete [] colPosition_;
+    colPosition_ = new int[numberRows_];
+    if (rowOfU_) delete [] rowOfU_;
+    rowOfU_ = new int[numberRows_];
+    if (rowPosition_) delete [] rowPosition_;
+    rowPosition_ = new int[numberRows_];
+    if (secRowOfU_) delete [] secRowOfU_;
+    secRowOfU_ = new int[numberRows_];
+    if (secRowPosition_) delete [] secRowPosition_;
+    secRowPosition_ = new int[numberRows_];
+    
+    if (EtaPosition_) delete [] EtaPosition_;
+    EtaPosition_ = new int[maximumPivots_];
+    if (EtaStarts_) delete [] EtaStarts_;
+    EtaStarts_ = new int[maximumPivots_];
+    if (EtaLengths_) delete [] EtaLengths_;
+    EtaLengths_ = new int[maximumPivots_];
+    maxEtaRows_=maximumPivots_;
+
+    EtaMaxCap_=maximumPivots_*minIncrease_;
+    if (EtaInd_) delete [] EtaInd_;
+    EtaInd_ = new int[EtaMaxCap_];
+    if (Eta_) delete [] Eta_;
+    Eta_ = new double[EtaMaxCap_];
+ 
+}
+
+void CoinSimpFactorization::Lxeqb(double *b) const
+{
+    double *rhs=b;
+    int k, colBeg, *ind, *indEnd;
+    double xk, *Lcol;
+    // now solve
+    for ( int j=firstNumberSlacks_; j<numberRows_; ++j ){
+	k=rowOfU_[j];
+	xk=rhs[k];	
+	if ( xk!=0.0 ) {
+	    //if ( fabs(xk)>zeroTolerance_ ) {
+	    colBeg=LcolStarts_[k];
+	    ind=LcolInd_+colBeg;
+	    indEnd=ind+LcolLengths_[k];
+	    Lcol=Lcolumns_+colBeg;
+	    for ( ; ind!=indEnd; ++ind ){
+		rhs[ *ind ]-= (*Lcol) * xk;
+		++Lcol;
+	    }
+	} 
+    }
+}
+
+
+
+void CoinSimpFactorization::Lxeqb2(double *b1, double *b2) const
+{
+    double *rhs1=b1;
+    double *rhs2=b2;
+    double x1, x2, *Lcol;
+    int k, colBeg, *ind, *indEnd, j; 
+    // now solve
+    for ( j=firstNumberSlacks_; j<numberRows_; ++j ){
+	k=rowOfU_[j];
+	x1=rhs1[k];
+	x2=rhs2[k];	
+	if ( x1 == 0.0 ) {
+	    if (x2 == 0.0 ) {
+	    } else {
+		colBeg=LcolStarts_[k];
+		ind=LcolInd_+colBeg;
+		indEnd=ind+LcolLengths_[k];
+		Lcol=Lcolumns_+colBeg;
+		for ( ; ind!=indEnd; ++ind ){
+#if 0
+		    rhs2[ *ind ]-= (*Lcol) * x2;
+#else
+		    double value=rhs2[ *ind ];
+		    rhs2[ *ind ]= value -(*Lcol) * x2;
+#endif
+		    ++Lcol;
+		}
+	    }
+	} else {
+	    if ( x2 == 0.0 ) {
+		colBeg=LcolStarts_[k];
+		ind=LcolInd_+colBeg;
+		indEnd=ind+LcolLengths_[k];
+		Lcol=Lcolumns_+colBeg;
+		for ( ; ind!=indEnd; ++ind ){
+#if 0
+		    rhs1[ *ind ]-= (*Lcol) * x1;
+#else
+		    double value=rhs1[ *ind ];
+		    rhs1[ *ind ]= value -(*Lcol) * x1;
+#endif
+		    ++Lcol;
+		}
+	    } else {
+		colBeg=LcolStarts_[k];
+		ind=LcolInd_+colBeg;
+		indEnd=ind+LcolLengths_[k];
+		Lcol=Lcolumns_+colBeg;
+		for ( ; ind!=indEnd; ++ind ){
+#if 0
+		    rhs1[ *ind ]-= (*Lcol) * x1;
+		    rhs2[ *ind ]-= (*Lcol) * x2;
+#else
+		    double value1=rhs1[ *ind ];
+		    rhs1[ *ind ]= value1 - (*Lcol) * x1;
+		    double value2=rhs2[ *ind ];
+		    rhs2[ *ind ]= value2 - (*Lcol) * x2;
+#endif
+		    ++Lcol;
+		}
+	    }
+	}
+    } 
+}
+
+void CoinSimpFactorization::Uxeqb(double *b, double *sol) const
+{
+    double *rhs=b;
+    int row, column, colBeg, *ind, *indEnd, k;
+    double x, *uCol;
+    // now solve
+    for ( k=numberRows_-1; k>=numberSlacks_; --k ){ 
+	row=secRowOfU_[k];
+	x=rhs[row];
+	column=colOfU_[k];	
+	if ( x!=0.0 ) {
+	    //if ( fabs(x) > zeroTolerance_ ) {
+	    x*=invOfPivots_[row];
+	    colBeg=UcolStarts_[column];
+	    ind=UcolInd_+colBeg;
+	    indEnd=ind+UcolLengths_[column];
+	    uCol=Ucolumns_+colBeg;
+	    for ( ; ind!=indEnd; ++ind ){
+#if 0 
+		rhs[ *ind ]-= (*uCol) * x;
+#else
+		double value=rhs[ *ind ];
+		rhs[ *ind ] = value - (*uCol) * x;
+#endif
+		++uCol;
+	    }
+	    sol[column]=x;
+	}
+	else sol[column]=0.0;
+    }
+    for ( k=numberSlacks_-1; k>=0; --k ){ 
+	row=secRowOfU_[k];
+	column=colOfU_[k];
+	sol[column]=-rhs[row];
+    }
+}
+
+
+
+void CoinSimpFactorization::Uxeqb2(double *b1, double *sol1, double *b2, double *sol2) const
+{
+    double *rhs1=b1;
+    double *rhs2=b2;
+    int row, column, colBeg, *ind, *indEnd;
+    double x1, x2, *uCol;
+    // now solve
+    for ( int k=numberRows_-1; k>=numberSlacks_; --k ){ 
+	row=secRowOfU_[k];
+	x1=rhs1[row];
+	x2=rhs2[row];
+	column=colOfU_[k];	
+	if (x1 == 0.0) {
+	    if (x2 == 0.0) {
+		sol1[column]=0.0;
+		sol2[column]=0.0;
+	    } else {
+		x2*=invOfPivots_[row];
+		colBeg=UcolStarts_[column];
+		ind=UcolInd_+colBeg;
+		indEnd=ind+UcolLengths_[column];
+		uCol=Ucolumns_+colBeg;
+		for ( ; ind!=indEnd; ++ind ){
+#if 0
+		    rhs2[ *ind ]-= (*uCol) * x2;
+#else
+		    double value=rhs2[ *ind ];
+		    rhs2[ *ind ]= value - (*uCol) * x2;
+#endif
+		    ++uCol;
+		}
+		sol1[column]=0.0;
+		sol2[column]=x2;  
+	    }
+	} else {
+	    if (x2 == 0.0) {
+		x1*=invOfPivots_[row];
+		colBeg=UcolStarts_[column];
+		ind=UcolInd_+colBeg;
+		indEnd=ind+UcolLengths_[column];
+		uCol=Ucolumns_+colBeg;
+		for ( ; ind!=indEnd; ++ind ){
+#if 0
+		    rhs1[ *ind ]-= (*uCol) * x1;
+#else
+		    double value=rhs1[ *ind ];
+		    rhs1[ *ind ] = value - (*uCol) * x1;
+#endif
+		    ++uCol;
+		}
+		sol1[column]=x1;
+		sol2[column]=0.0;  
+	    } else {
+		x1*=invOfPivots_[row];
+		x2*=invOfPivots_[row];
+		colBeg=UcolStarts_[column];
+		ind=UcolInd_+colBeg;
+		indEnd=ind+UcolLengths_[column];
+		uCol=Ucolumns_+colBeg;
+		for ( ; ind!=indEnd; ++ind ){
+#if 0
+		    rhs1[ *ind ]-= (*uCol) * x1;
+		    rhs2[ *ind ]-= (*uCol) * x2;
+#else
+		    double value1=rhs1[ *ind ];
+		    rhs1[ *ind ] = value1 - (*uCol) * x1; 
+		    double value2=rhs2[ *ind ];
+		    rhs2[ *ind ] = value2 - (*uCol) * x2;
+#endif
+		    ++uCol;
+		}
+		sol1[column]=x1;
+		sol2[column]=x2;
+	    }
+	}
+    }
+    for ( int k=numberSlacks_-1; k>=0; --k ){ 
+	row=secRowOfU_[k];
+	column=colOfU_[k];
+	sol1[column]=-rhs1[row];
+	sol2[column]=-rhs2[row];
+    }	 
+}
+
+
+void CoinSimpFactorization::xLeqb(double *b) const
+{
+    double *rhs=b;
+    int k, *ind, *indEnd, j;
+    int colBeg; 
+    double x, *Lcol;
+    // find last nonzero
+    int last;
+    for ( last=numberColumns_-1; last >= 0; --last ){
+	if ( rhs[ rowOfU_[last] ] ) break;
+    }
+    // this seems to be faster
+    if ( last >= 0 ){
+	for ( j=last; j >=firstNumberSlacks_ ; --j ){
+	    k=rowOfU_[j];
+	    x=rhs[k];
+	    colBeg=LcolStarts_[k];
+	    ind=LcolInd_+colBeg;
+	    indEnd=ind+LcolLengths_[k];
+	    Lcol=Lcolumns_+colBeg;
+	    for ( ; ind!=indEnd; ++ind ){
+		x -= (*Lcol) * rhs[ *ind ];
+		++Lcol;
+	    }
+	    rhs[k]=x; 
+	}
+    } // if ( last >= 0 ){
+}
+ 
+
+
+void CoinSimpFactorization::xUeqb(double *b, double *sol) const
+{
+    double *rhs=b;
+    int row, col, *ind, *indEnd, k;
+    double xr;
+    // now solve
+#if 1
+    int rowBeg;
+    double * uRow;
+    for ( k=0; k<numberSlacks_; ++k ){
+	row=secRowOfU_[k];
+	col=colOfU_[k];
+	xr=rhs[col];	
+	if ( xr!=0.0 ) {
+	    //if ( fabs(xr)> zeroTolerance_ ) {
+	    xr=-xr;
+	    rowBeg=UrowStarts_[row];
+	    ind=UrowInd_+rowBeg;
+	    indEnd=ind+UrowLengths_[row];
+	    uRow=Urows_+rowBeg;
+	    for ( ; ind!=indEnd; ++ind ){
+		rhs[ *ind ]-= (*uRow) * xr;
+		++uRow;
+	    }
+	    sol[row]=xr;
+	}
+	else sol[row]=0.0;
+    }
+    for ( k=numberSlacks_; k<numberRows_; ++k ){
+	row=secRowOfU_[k];
+	col=colOfU_[k];
+	xr=rhs[col];	
+	if ( xr!=0.0 ) {
+	    //if ( fabs(xr)> zeroTolerance_ ) {
+	    xr*=invOfPivots_[row];
+	    rowBeg=UrowStarts_[row];
+	    ind=UrowInd_+rowBeg;
+	    indEnd=ind+UrowLengths_[row];
+	    uRow=Urows_+rowBeg;
+	    for ( ; ind!=indEnd; ++ind ){
+		rhs[ *ind ]-= (*uRow) * xr;
+		++uRow;
+	    }
+	    sol[row]=xr;
+	}
+	else sol[row]=0.0;
+    }
+#else
+    for ( k=0; k<numberSlacks_; ++k ){
+	row=secRowOfU_[k];
+	col=colOfU_[k];
+	sol[row]=-rhs[col];
+    }
+    for ( k=numberSlacks_; k<numberRows_; ++k ){
+	row=secRowOfU_[k];
+	col=colOfU_[k];
+	xr=rhs[col];	
+	int colBeg=UcolStarts_[col];
+	ind=UcolInd_+colBeg;
+	indEnd=ind+UcolLengths_[col];
+	double * uCol=Ucolumns_+colBeg;
+	for ( ; ind!=indEnd; ++ind,++uCol ){
+	  int iRow = *ind;
+	  double value = sol[iRow];
+	  double elementValue = *uCol;
+	  xr -= value*elementValue;
+	}
+	if ( xr!=0.0 ) {
+	  xr*=invOfPivots_[row];
+	  sol[row]=xr;
+	}
+	else sol[row]=0.0;
+    }
+#endif
+}
+
+
+	
+int CoinSimpFactorization::LUupdate(int newBasicCol)
+{    
+    //checkU();
+    // recover vector kept in ftran
+    double *newColumn=vecKeep_;
+    int *indNewColumn=indKeep_;
+    int sizeNewColumn=keepSize_;
+
+    // remove elements of new column of U
+    const int colBeg=UcolStarts_[newBasicCol];
+    const int colEnd=colBeg+UcolLengths_[newBasicCol];
+    for ( int i=colBeg; i<colEnd; ++i ){
+	const int row=UcolInd_[i];
+	const int colInRow=findInRow(row,newBasicCol);
+	assert(colInRow >= 0);
+	// remove from row
+	const int rowEnd=UrowStarts_[row]+UrowLengths_[row];
+	Urows_[colInRow]=Urows_[rowEnd-1];
+	UrowInd_[colInRow]=UrowInd_[rowEnd-1];
+	--UrowLengths_[row];
+    }
+    UcolLengths_[newBasicCol]=0;
+    // now add new column to U
+    int lastRowInU=-1;
+    for ( int i=0; i < sizeNewColumn; ++i ){
+	//if ( fabs(newColumn[i]) < zeroTolerance_ ) continue;
+	const int row=indNewColumn[i];
+	// add to row
+#ifdef COIN_SIMP_CAPACITY
+	if ( UrowLengths_[row] + 1 > UrowCapacities_[row] )
+	    increaseRowSize(row, UrowLengths_[row] + 1);
+#endif 
+	const int rowEnd=UrowStarts_[row]+UrowLengths_[row];
+	UrowInd_[rowEnd]=newBasicCol;
+	Urows_[rowEnd]=newColumn[i];
+	++UrowLengths_[row];
+	if ( lastRowInU < secRowPosition_[row] ) lastRowInU=secRowPosition_[row];
+    }	
+    // add to Ucolumns
+#ifdef COIN_SIMP_CAPACITY
+    if ( sizeNewColumn > UcolCapacities_[newBasicCol] )
+	increaseColSize(newBasicCol, sizeNewColumn , true);
+#endif 
+    memcpy(&Ucolumns_[ UcolStarts_[newBasicCol] ], &newColumn[0], 
+	   sizeNewColumn * sizeof(double) );
+    memcpy(&UcolInd_[ UcolStarts_[newBasicCol] ], &indNewColumn[0],
+	   sizeNewColumn * sizeof(int) );
+    UcolLengths_[newBasicCol]=sizeNewColumn;
+ 
+
+    const int posNewCol=colPosition_[newBasicCol];
+    if ( lastRowInU < posNewCol ){
+	// matrix is singular
+	return 1;
+    }
+    // permutations
+    const int rowInU=secRowOfU_[posNewCol];
+    const int colInU=colOfU_[posNewCol];
+    for ( int i=posNewCol; i<lastRowInU; ++i ){
+	int indx=secRowOfU_[i+1];
+	secRowOfU_[i]=indx;
+	secRowPosition_[indx]=i;
+	int jndx=colOfU_[i+1];
+	colOfU_[i]=jndx;
+	colPosition_[jndx]=i;
+    }
+    secRowOfU_[lastRowInU]=rowInU;
+    secRowPosition_[rowInU]=lastRowInU;
+    colOfU_[lastRowInU]=colInU;
+    colPosition_[colInU]=lastRowInU;    
+    if ( posNewCol < numberSlacks_ ){
+	if ( lastRowInU >= numberSlacks_ )
+	    --numberSlacks_; 
+	else
+	    numberSlacks_= lastRowInU;
+    }
+    // rowInU will be transformed
+    // denseVector_ is assumed to be initialized to zero
+    const int rowBeg=UrowStarts_[rowInU];
+    const int rowEnd=rowBeg+UrowLengths_[rowInU];
+    for ( int i=rowBeg; i<rowEnd; ++i ){
+	const int column=UrowInd_[i];
+	denseVector_[column]=Urows_[i];
+	// remove element
+	const int indxRow=findInColumn(column,rowInU);
+	assert( indxRow >= 0 );
+	const int colEnd=UcolStarts_[column]+UcolLengths_[column];
+	UcolInd_[indxRow]=UcolInd_[colEnd-1];
+	Ucolumns_[indxRow]=Ucolumns_[colEnd-1];
+	--UcolLengths_[column];
+    }
+    UrowLengths_[rowInU]=0;
+    // rowInU is empty
+    // increase Eta by (lastRowInU-posNewCol) elements
+    newEta(rowInU, lastRowInU-posNewCol );
+    assert(!EtaLengths_[lastEtaRow_]);
+    int saveSize = EtaSize_;;
+    for ( int i=posNewCol; i<lastRowInU; ++i ){
+	const int row=secRowOfU_[i];
+	const int column=colOfU_[i];
+	if ( denseVector_[column]==0.0 ) continue;
+	register const double multiplier=denseVector_[column]*invOfPivots_[row];
+	denseVector_[column]=0.0;
+	const int rowBeg=UrowStarts_[row];
+	const int rowEnd=rowBeg+UrowLengths_[row];
+#if ARRAY
+	for ( int j=rowBeg; j<rowEnd; ++j ){
+	    denseVector_[ UrowInd_[j] ]-= multiplier*Urows_[j];
+	}
+#else
+	int *ind=UrowInd_+rowBeg;
+	int *indEnd=UrowInd_+rowEnd;
+	double *uRow=Urows_+rowBeg;
+	for ( ; ind!=indEnd; ++ind ){
+	    denseVector_[ *ind ]-= multiplier * (*uRow); 
+	    ++uRow;
+	}
+#endif
+	// store multiplier
+	Eta_[EtaSize_]=multiplier;
+	EtaInd_[EtaSize_++]=row;
+    }
+    if (EtaSize_!=saveSize)
+      EtaLengths_[lastEtaRow_]=EtaSize_ - saveSize;
+    else
+      --lastEtaRow_;
+    // inverse of diagonal
+    invOfPivots_[rowInU]=1.0/denseVector_[ colOfU_[lastRowInU] ];
+    denseVector_[ colOfU_[lastRowInU] ]=0.0;
+    // now store row
+    int newEls=0;
+    for ( int i=lastRowInU+1; i<numberColumns_; ++i ){
+	const int column=colOfU_[i];
+	const double coeff=denseVector_[column];
+	denseVector_[column]=0.0;
+	if ( fabs(coeff) < zeroTolerance_ ) continue;
+#ifdef COIN_SIMP_CAPACITY
+	if ( UcolLengths_[column] + 1 > UcolCapacities_[column] ){
+	    increaseColSize(column, UcolLengths_[column] + 1, true);
+	}
+#endif 
+	const int newInd=UcolStarts_[column]+UcolLengths_[column];
+	UcolInd_[newInd]=rowInU;
+	Ucolumns_[newInd]=coeff;
+	++UcolLengths_[column];
+	workArea2_[newEls]=coeff;
+	indVector_[newEls++]=column;
+    }
+#ifdef COIN_SIMP_CAPACITY
+    if ( UrowCapacities_[rowInU] < newEls )
+	increaseRowSize(rowInU, newEls);
+#endif 
+    const int startRow=UrowStarts_[rowInU];
+    memcpy(&Urows_[startRow],&workArea2_[0], newEls*sizeof(double) );
+    memcpy(&UrowInd_[startRow],&indVector_[0], newEls*sizeof(int) );
+    UrowLengths_[rowInU]=newEls;
+    //
+    if ( fabs( invOfPivots_[rowInU] ) > updateTol_ )
+	return 2;
+
+    return 0;
+}
+
+
+void CoinSimpFactorization::newEta(int row, int numNewElements){
+    if ( lastEtaRow_ == maxEtaRows_-1 ){
+	int *iaux=new int[maxEtaRows_ + minIncrease_];
+	memcpy(iaux, EtaPosition_, maxEtaRows_ * sizeof(int));
+	delete [] EtaPosition_;
+	EtaPosition_=iaux;
+
+	int *jaux=new int[maxEtaRows_ + minIncrease_];
+	memcpy(jaux, EtaStarts_, maxEtaRows_ * sizeof(int));
+	delete [] EtaStarts_;
+	EtaStarts_=jaux;
+
+	int *kaux=new int[maxEtaRows_ + minIncrease_];
+	memcpy(kaux, EtaLengths_, maxEtaRows_ * sizeof(int));
+	delete [] EtaLengths_;
+	EtaLengths_=kaux;
+
+	maxEtaRows_+=minIncrease_;
+    }
+    if ( EtaSize_ + numNewElements > EtaMaxCap_ ){
+	int number= CoinMax(EtaSize_ + numNewElements - EtaMaxCap_, minIncrease_);
+
+	int *iaux=new int[EtaMaxCap_ + number];
+	memcpy(iaux, EtaInd_, EtaSize_ * sizeof(int));
+	delete [] EtaInd_;
+	EtaInd_=iaux;
+
+	double *aux=new double[EtaMaxCap_ + number];
+	memcpy(aux, Eta_, EtaSize_ * sizeof(double));
+	delete [] Eta_;
+	Eta_=aux;
+
+	EtaMaxCap_+=number;	
+    }
+    EtaPosition_[++lastEtaRow_]=row;
+    EtaStarts_[lastEtaRow_]=EtaSize_;
+    EtaLengths_[lastEtaRow_]=0;
+    
+}
+void CoinSimpFactorization::copyRowPermutations()
+{
+    memcpy(&secRowOfU_[0], &rowOfU_[0], 
+	   numberRows_ * sizeof(int) );
+    memcpy(&secRowPosition_[0], &rowPosition_[0],
+	   numberRows_ * sizeof(int) );
+}
+
+void CoinSimpFactorization::Hxeqb(double *b) const
+{
+    double *rhs=b;
+    int row, rowBeg, *ind, *indEnd;
+    double xr, *eta;
+    // now solve 
+    for ( int k=0; k <= lastEtaRow_; ++k ){
+	row=EtaPosition_[k];
+	rowBeg=EtaStarts_[k];
+	xr=0.0;
+	ind=EtaInd_+rowBeg;
+	indEnd=ind+EtaLengths_[k];
+	eta=Eta_+rowBeg;
+	for ( ; ind!=indEnd; ++ind ){
+	    xr += rhs[ *ind ] * (*eta);
+	    ++eta;
+	}
+	rhs[row]-=xr;
+    }
+}
+
+
+
+void CoinSimpFactorization::Hxeqb2(double *b1, double *b2) const
+{
+    double *rhs1=b1;
+    double *rhs2=b2;
+    int row, rowBeg, *ind, *indEnd;
+    double x1, x2, *eta;
+    // now solve 
+    for ( int k=0; k <= lastEtaRow_; ++k ){
+	row=EtaPosition_[k];
+	rowBeg=EtaStarts_[k];
+	x1=0.0;
+	x2=0.0;
+	ind=EtaInd_+rowBeg;
+	indEnd=ind+EtaLengths_[k];
+	eta=Eta_+rowBeg;
+	for ( ; ind!=indEnd; ++ind ){
+	    x1 += rhs1[ *ind ] * (*eta);
+	    x2 += rhs2[ *ind ] * (*eta);
+	    ++eta;
+	}
+	rhs1[row]-=x1;
+	rhs2[row]-=x2;
+    }
+}
+
+
+
+
+void CoinSimpFactorization::xHeqb(double *b) const
+{    
+    double *rhs=b;
+    int row, rowBeg, *ind, *indEnd;
+    double xr, *eta; 
+    // now solve 
+    for ( int k=lastEtaRow_; k >= 0; --k ){
+	row=EtaPosition_[k];
+	xr=rhs[row];
+	if ( xr==0.0 ) continue;
+	//if ( fabs(xr) <= zeroTolerance_ ) continue;
+	rowBeg=EtaStarts_[k];
+	ind=EtaInd_+rowBeg;
+	indEnd=ind+EtaLengths_[k];
+	eta=Eta_+rowBeg;
+	for ( ; ind!=indEnd; ++ind ){
+	    rhs[ *ind ]-= xr * (*eta);
+	    ++eta;
+	}
+    }
+}
+
+
+
+void CoinSimpFactorization::ftran(double *b, double *sol, bool save) const
+{    
+    Lxeqb(b);
+    Hxeqb(b);
+    if ( save ){
+	// keep vector
+	keepSize_=0;
+	for ( int i=0; i<numberRows_; ++i ){
+	    if ( fabs(b[i]) < zeroTolerance_ ) continue;
+	    vecKeep_[keepSize_]=b[i];
+	    indKeep_[keepSize_++]=i;
+	}
+    }
+    Uxeqb(b,sol);
+}
+
+void CoinSimpFactorization::ftran2(double *b1, double *sol1, double *b2, double *sol2) const
+{    
+    Lxeqb2(b1,b2);
+    Hxeqb2(b1,b2);
+    // keep vector
+    keepSize_=0;
+    for ( int i=0; i<numberRows_; ++i ){
+	if ( fabs(b1[i]) < zeroTolerance_ ) continue;
+	vecKeep_[keepSize_]=b1[i];
+	indKeep_[keepSize_++]=i;
+    }
+    Uxeqb2(b1,sol1,b2,sol2);
+}
+
+
+
+void CoinSimpFactorization::btran(double *b, double *sol) const
+{    
+    xUeqb(b, sol);
+    xHeqb(sol);
+    xLeqb(sol);
+}
+
diff --git a/cbits/coin/CoinSimpFactorization.hpp b/cbits/coin/CoinSimpFactorization.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinSimpFactorization.hpp
@@ -0,0 +1,431 @@
+/* $Id: CoinSimpFactorization.hpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/* 
+   This is a simple factorization of the LP Basis
+ */
+#ifndef CoinSimpFactorization_H
+#define CoinSimpFactorization_H
+
+#include <iostream>
+#include <string>
+#include <cassert>
+#include "CoinTypes.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinDenseFactorization.hpp"
+class CoinPackedMatrix;
+
+
+/// pointers used during factorization
+class FactorPointers{
+public:
+    double *rowMax;
+    int *firstRowKnonzeros;
+    int *prevRow;
+    int *nextRow;
+    int *firstColKnonzeros;
+    int *prevColumn;
+    int *nextColumn;
+    int *newCols;
+    //constructor
+    FactorPointers( int numRows, int numCols, int *UrowLengths_, int *UcolLengths_ );
+    // destructor
+    ~ FactorPointers();
+};
+
+class CoinSimpFactorization : public CoinOtherFactorization {
+   friend void CoinSimpFactorizationUnitTest( const std::string & mpsDir );
+
+public:
+
+  /**@name Constructors and destructor and copy */
+  //@{
+  /// Default constructor
+  CoinSimpFactorization (  );
+  /// Copy constructor 
+  CoinSimpFactorization ( const CoinSimpFactorization &other);
+  
+  /// Destructor
+  virtual ~CoinSimpFactorization (  );
+  /// = copy
+  CoinSimpFactorization & operator = ( const CoinSimpFactorization & other );
+  /// Clone
+  virtual CoinOtherFactorization * clone() const ;
+  //@}
+
+  /**@name Do factorization - public */
+  //@{
+  /// Gets space for a factorization
+  virtual void getAreas ( int numberRows,
+		  int numberColumns,
+		  CoinBigIndex maximumL,
+		  CoinBigIndex maximumU );
+  
+  /// PreProcesses column ordered copy of basis
+  virtual void preProcess ( );
+  /** Does most of factorization returning status
+      0 - OK
+      -99 - needs more memory
+      -1 - singular - use numberGoodColumns and redo
+  */
+  virtual int factor ( );
+  /// Does post processing on valid factorization - putting variables on correct rows
+  virtual void postProcess(const int * sequence, int * pivotVariable);
+  /// Makes a non-singular basis by replacing variables
+  virtual void makeNonSingular(int * sequence, int numberColumns);
+  //@}
+
+  /**@name general stuff such as status */
+  //@{ 
+  /// Total number of elements in factorization
+  virtual inline int numberElements (  ) const {
+    return numberRows_*(numberColumns_+numberPivots_);
+  }
+  /// Returns maximum absolute value in factorization
+  double maximumCoefficient() const;
+  //@}
+
+  /**@name rank one updates which do exist */
+  //@{
+
+  /** Replaces one Column to basis,
+   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
+      If checkBeforeModifying is true will do all accuracy checks
+      before modifying factorization.  Whether to set this depends on
+      speed considerations.  You could just do this on first iteration
+      after factorization and thereafter re-factorize
+   partial update already in U */
+  virtual int replaceColumn ( CoinIndexedVector * regionSparse,
+		      int pivotRow,
+		      double pivotCheck ,
+			      bool checkBeforeModifying=false,
+			      double acceptablePivot=1.0e-8);
+  //@}
+
+  /**@name various uses of factorization (return code number elements) 
+   which user may want to know about */
+  //@{
+  /** Updates one column (FTRAN) from regionSparse2
+      Tries to do FT update
+      number returned is negative if no room
+      regionSparse starts as zero and is zero at end.
+      Note - if regionSparse2 packed on input - will be packed on output
+  */
+
+    virtual int updateColumnFT ( CoinIndexedVector * regionSparse,
+			 CoinIndexedVector * regionSparse2,
+			 bool noPermute=false);
+    
+    /** This version has same effect as above with FTUpdate==false
+	so number returned is always >=0 */
+    virtual int updateColumn ( CoinIndexedVector * regionSparse,
+		       CoinIndexedVector * regionSparse2,
+		       bool noPermute=false) const;
+    /// does FTRAN on two columns
+    virtual int updateTwoColumnsFT(CoinIndexedVector * regionSparse1,
+			   CoinIndexedVector * regionSparse2,
+			   CoinIndexedVector * regionSparse3,
+			   bool noPermute=false);
+    /// does updatecolumn if save==true keeps column for replace column
+    int upColumn ( CoinIndexedVector * regionSparse,
+		   CoinIndexedVector * regionSparse2,
+		   bool noPermute=false, bool save=false) const;
+    /** Updates one column (BTRAN) from regionSparse2
+	regionSparse starts as zero and is zero at end 
+	Note - if regionSparse2 packed on input - will be packed on output
+    */
+    virtual int updateColumnTranspose ( CoinIndexedVector * regionSparse,
+				CoinIndexedVector * regionSparse2) const;
+    /// does updateColumnTranspose, the other is a wrapper
+    int upColumnTranspose ( CoinIndexedVector * regionSparse,
+				CoinIndexedVector * regionSparse2) const;
+    //@}
+    /// *** Below this user may not want to know about
+
+  /**@name various uses of factorization
+   which user may not want to know about (left over from my LP code) */
+  //@{
+  /// Get rid of all memory
+  inline void clearArrays()
+  { gutsOfDestructor();}
+  /// Returns array to put basis indices in
+  inline int * indices() const
+  { return reinterpret_cast<int *> (elements_+numberRows_*numberRows_);}
+  /// Returns permute in
+  virtual inline int * permute() const
+  { return pivotRow_;}
+  //@}
+
+  /// The real work of destructor 
+  void gutsOfDestructor();
+  /// The real work of constructor
+  void gutsOfInitialize();
+  /// The real work of copy
+  void gutsOfCopy(const CoinSimpFactorization &other);
+
+    
+    /// calls factorization
+  void factorize(int numberOfRows,
+		 int numberOfColumns,
+		 const int colStarts[],
+		 const int indicesRow[],
+		 const double elements[]);
+    /// main loop of factorization
+    int mainLoopFactor (FactorPointers &pointers );
+    /// copies L by rows
+    void copyLbyRows();
+    /// copies U by columns
+    void copyUbyColumns();
+    /// finds a pivot element using Markowitz count
+    int findPivot(FactorPointers &pointers, int &r, int &s, bool &ifSlack);
+    /// finds a pivot in a shortest column
+    int findPivotShCol(FactorPointers &pointers, int &r, int &s);
+    /// finds a pivot in the first column available
+    int findPivotSimp(FactorPointers &pointers, int &r, int &s);
+    /// does Gauss elimination
+    void GaussEliminate(FactorPointers &pointers, int &r, int &s);
+    /// finds short row that intersects a given column
+    int findShortRow(const int column, const int length, int &minRow, 
+		     int &minRowLength, FactorPointers &pointers);
+    /// finds short column that intersects a given row
+    int findShortColumn(const int row, const int length, int &minCol, 
+			int &minColLength, FactorPointers &pointers);
+    /// finds maximum absolute value in a row
+    double findMaxInRrow(const int row, FactorPointers &pointers);
+    /// does pivoting
+    void pivoting(const int pivotRow, const int pivotColumn,
+		  const double invPivot, FactorPointers &pointers);
+    /// part of pivoting
+    void updateCurrentRow(const int pivotRow, const int row, 
+			  const double multiplier, FactorPointers &pointers,
+			  int &newNonZeros);
+    /// allocates more space for L
+    void increaseLsize();
+    /// allocates more space for a row of U
+    void increaseRowSize(const int row, const int newSize);
+    /// allocates more space for a column of U
+    void increaseColSize(const int column, const int newSize, const bool b);
+    /// allocates more space for rows of U
+    void enlargeUrow(const int numNewElements);
+    /// allocates more space for columns of U
+    void enlargeUcol(const int numNewElements, const bool b);
+    /// finds a given row in a column
+    int findInRow(const int row, const int column);
+    /// finds a given column in a row
+    int findInColumn(const int column, const int row);
+    /// declares a row inactive
+    void removeRowFromActSet(const int row, FactorPointers &pointers);
+    /// declares a column inactive
+    void removeColumnFromActSet(const int column, FactorPointers &pointers);
+    /// allocates space for U
+    void allocateSpaceForU();
+    /// allocates several working arrays
+    void allocateSomeArrays();
+    /// initializes some numbers
+    void initialSomeNumbers();
+    /// solves L x = b
+    void Lxeqb(double *b) const;
+    /// same as above but with two rhs
+    void Lxeqb2(double *b1, double *b2) const;
+    /// solves U x = b
+    void Uxeqb(double *b, double *sol) const;
+    /// same as above but with two rhs
+    void Uxeqb2(double *b1, double *sol1, double *sol2, double *b2) const;
+    /// solves x L = b
+    void xLeqb(double *b) const;
+    /// solves x U = b
+    void xUeqb(double *b, double *sol) const;
+    /// updates factorization after a Simplex iteration
+    int LUupdate(int newBasicCol);
+    /// creates a new eta vector
+    void newEta(int row, int numNewElements);
+    /// makes a copy of row permutations
+    void copyRowPermutations();
+    /// solves H x = b, where H is a product of eta matrices
+    void Hxeqb(double *b) const;
+    /// same as above but with two rhs
+    void Hxeqb2(double *b1, double *b2) const;
+    /// solves x H = b
+    void xHeqb(double *b) const;
+    /// does FTRAN
+    void ftran(double *b, double *sol, bool save) const;
+    /// same as above but with two columns
+    void ftran2(double *b1, double *sol1, double *b2, double *sol2) const;
+    /// does BTRAN
+    void btran(double *b, double *sol) const;
+   ///---------------------------------------
+
+
+
+  //@}
+protected:
+  /** Returns accuracy status of replaceColumn
+      returns 0=OK, 1=Probably OK, 2=singular */
+  int checkPivot(double saveFromU, double oldPivot) const;
+////////////////// data //////////////////
+protected:
+
+  /**@name data */
+  //@{
+    /// work array (should be initialized to zero)
+    double *denseVector_;
+    /// work array 
+    double *workArea2_; 
+    /// work array 
+    double *workArea3_;
+    /// array of labels (should be initialized to zero)
+    int *vecLabels_;
+    /// array of indices
+    int *indVector_;
+
+    /// auxiliary vector 
+    double *auxVector_;
+    /// auxiliary vector 
+    int *auxInd_;
+
+    /// vector to keep for LUupdate
+    double *vecKeep_;
+    /// indices of this vector
+    int *indKeep_;
+    /// number of nonzeros
+    mutable int keepSize_;
+
+    
+
+    /// Starts of the rows of L
+    int *LrowStarts_;
+    /// Lengths of the rows of L
+    int *LrowLengths_;
+    /// L by rows
+    double *Lrows_;
+    /// indices in the rows of L
+    int *LrowInd_;
+    /// Size of Lrows_;
+    int LrowSize_; 
+    /// Capacity of Lrows_
+    int LrowCap_;
+
+    /// Starts of the columns of L
+    int *LcolStarts_;
+    /// Lengths of the columns of L
+    int *LcolLengths_;
+    /// L by columns
+    double *Lcolumns_;
+    /// indices in the columns of L
+    int *LcolInd_;
+    /// numbers of elements in L
+    int LcolSize_;
+    /// maximum capacity of L
+    int LcolCap_;
+   
+
+    /// Starts of the rows of U
+    int *UrowStarts_;
+    /// Lengths of the rows of U
+    int *UrowLengths_;
+#ifdef COIN_SIMP_CAPACITY
+    /// Capacities of the rows of U
+    int *UrowCapacities_;
+#endif
+    /// U by rows
+    double *Urows_;
+    /// Indices in the rows of U
+    int *UrowInd_;
+    /// maximum capacity of Urows
+    int UrowMaxCap_;
+    /// number of used places in Urows
+    int UrowEnd_;
+    /// first row in U
+    int firstRowInU_;
+    /// last row in U
+    int lastRowInU_;
+    /// previous row in U
+    int *prevRowInU_;
+    /// next row in U
+    int *nextRowInU_;
+
+    /// Starts of the columns of U
+    int *UcolStarts_;
+    /// Lengths of the columns of U
+    int *UcolLengths_;
+#ifdef COIN_SIMP_CAPACITY
+    /// Capacities of the columns of U
+    int *UcolCapacities_;
+#endif
+    /// U by columns
+    double *Ucolumns_;
+    /// Indices in the columns of U
+    int *UcolInd_;
+    /// previous column in U
+    int *prevColInU_;
+    /// next column in U
+    int *nextColInU_;
+    /// first column in U
+    int firstColInU_;
+    /// last column in U
+    int lastColInU_;
+    /// maximum capacity of Ucolumns_
+    int UcolMaxCap_;
+    /// last used position in Ucolumns_
+    int UcolEnd_;    
+    /// indicator of slack variables
+    int *colSlack_;
+ 
+    /// inverse values of the elements of diagonal of U
+    double *invOfPivots_;
+
+    /// permutation of columns 
+    int *colOfU_;
+    /// position of column after permutation
+    int *colPosition_;
+    /// permutations of rows
+    int *rowOfU_;
+    /// position of row after permutation
+    int *rowPosition_;
+    /// permutations of rows during LUupdate
+    int *secRowOfU_;
+    /// position of row after permutation during LUupdate
+    int *secRowPosition_;
+    
+    /// position of Eta vector
+    int *EtaPosition_;
+    /// Starts of eta vectors
+    int *EtaStarts_;
+    /// Lengths of eta vectors
+    int *EtaLengths_;
+    /// columns of eta vectors
+    int *EtaInd_;
+    /// elements of eta vectors
+    double *Eta_;
+    /// number of elements in Eta_
+    int EtaSize_;
+    /// last eta row
+    int lastEtaRow_;
+    /// maximum number of eta vectors
+    int maxEtaRows_;
+    /// Capacity of Eta_
+    int EtaMaxCap_;
+    
+    /// minimum storage increase
+    int minIncrease_;
+    /// maximum size for the diagonal of U after update
+    double updateTol_;
+    /// do Shul heuristic
+    bool doSuhlHeuristic_;
+    /// maximum of U
+    double maxU_;
+    /// bound on the growth rate
+    double maxGrowth_;
+    /// maximum of A
+    double maxA_;
+    /// maximum number of candidates for pivot
+    int pivotCandLimit_;    
+    /// number of slacks in basis
+    int numberSlacks_;    
+    /// number of slacks in irst basis
+    int firstNumberSlacks_;
+    //@}
+};
+#endif
diff --git a/cbits/coin/CoinSnapshot.cpp b/cbits/coin/CoinSnapshot.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinSnapshot.cpp
@@ -0,0 +1,528 @@
+/* $Id: CoinSnapshot.cpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include "CoinUtilsConfig.h"
+#include "CoinHelperFunctions.hpp"
+#include "CoinSnapshot.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinFinite.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinSnapshot::CoinSnapshot () 
+{
+  gutsOfDestructor(13);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinSnapshot::CoinSnapshot (const CoinSnapshot & rhs) 
+{
+  gutsOfDestructor(13);
+  gutsOfCopy(rhs);
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinSnapshot::~CoinSnapshot ()
+{
+  gutsOfDestructor(15);
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinSnapshot &
+CoinSnapshot::operator=(const CoinSnapshot& rhs)
+{
+  if (this != &rhs) {
+    gutsOfDestructor(15);
+    gutsOfCopy(rhs);
+  }
+  return *this;
+}
+// Does main work of destructor
+void 
+CoinSnapshot::gutsOfDestructor(int type)
+{
+  if ((type&2)!=0) {
+    if (owned_.colLower)
+      delete [] colLower_;
+    if (owned_.colUpper)
+      delete [] colUpper_;
+    if (owned_.rowLower)
+      delete [] rowLower_;
+    if (owned_.rowUpper)
+      delete [] rowUpper_;
+    if (owned_.rightHandSide)
+      delete [] rightHandSide_;
+    if (owned_.objCoefficients)
+      delete [] objCoefficients_;
+    if (owned_.colType)
+      delete [] colType_;
+    if (owned_.matrixByRow)
+      delete matrixByRow_;
+    if (owned_.matrixByCol)
+      delete matrixByCol_;
+    if (owned_.originalMatrixByRow)
+      delete originalMatrixByRow_;
+    if (owned_.originalMatrixByCol)
+      delete originalMatrixByCol_;
+    if (owned_.colSolution)
+      delete [] colSolution_;
+    if (owned_.rowPrice)
+      delete [] rowPrice_;
+    if (owned_.reducedCost)
+      delete [] reducedCost_;
+    if (owned_.rowActivity)
+      delete [] rowActivity_;
+    if (owned_.doNotSeparateThis)
+      delete [] doNotSeparateThis_;
+  }
+  if ((type&4)!=0) {
+    objSense_ = 1.0;
+    infinity_ = COIN_DBL_MAX;
+    dualTolerance_ = 1.0e-7;
+    primalTolerance_ = 1.0e-7;
+    integerTolerance_ = 1.0e-7;
+  }
+  if ((type&8)!=0) {
+    objValue_ = COIN_DBL_MAX;
+    objOffset_ = 0.0;
+    integerUpperBound_ = COIN_DBL_MAX;
+    integerLowerBound_ = -COIN_DBL_MAX;
+  }
+  if ((type&1)!=0) {
+    colLower_ = NULL;
+    colUpper_ = NULL;
+    rowLower_ = NULL;
+    rowUpper_ = NULL;
+    rightHandSide_ = NULL;
+    objCoefficients_ = NULL;
+    colType_ = NULL;
+    matrixByRow_ = NULL;
+    matrixByCol_ = NULL;
+    originalMatrixByRow_ = NULL;
+    originalMatrixByCol_ = NULL;
+    colSolution_ = NULL;
+    rowPrice_ = NULL;
+    reducedCost_ = NULL;
+    rowActivity_ = NULL;
+    doNotSeparateThis_ = NULL;
+    numCols_ = 0;
+    numRows_ = 0;
+    numElements_ = 0;
+    numIntegers_ = 0;
+    // say nothing owned
+    memset(&owned_,0,sizeof(owned_));
+  }
+}
+// Does main work of copy
+void 
+CoinSnapshot::gutsOfCopy(const CoinSnapshot & rhs)
+{
+  objSense_ = rhs.objSense_;
+  infinity_ = rhs.infinity_;
+  objValue_ = rhs.objValue_;
+  objOffset_ = rhs.objOffset_;
+  dualTolerance_ = rhs.dualTolerance_;
+  primalTolerance_ = rhs.primalTolerance_;
+  integerTolerance_ = rhs.integerTolerance_;
+  integerUpperBound_ = rhs.integerUpperBound_;
+  integerLowerBound_ = rhs.integerLowerBound_;
+  numCols_ = rhs.numCols_;
+  numRows_ = rhs.numRows_;
+  numElements_ = rhs.numElements_;
+  numIntegers_ = rhs.numIntegers_;
+  owned_ = rhs.owned_;
+  if (owned_.colLower)
+    colLower_ = CoinCopyOfArray(rhs.colLower_,numCols_);
+  else
+    colLower_ = rhs.colLower_;
+  if (owned_.colUpper)
+    colUpper_ = CoinCopyOfArray(rhs.colUpper_,numCols_);
+  else
+    colUpper_ = rhs.colUpper_;
+  if (owned_.rowLower)
+    rowLower_ = CoinCopyOfArray(rhs.rowLower_,numRows_);
+  else
+    rowLower_ = rhs.rowLower_;
+  if (owned_.rowUpper)
+    rowUpper_ = CoinCopyOfArray(rhs.rowUpper_,numRows_);
+  else
+    rowUpper_ = rhs.rowUpper_;
+  if (owned_.rightHandSide)
+    rightHandSide_ = CoinCopyOfArray(rhs.rightHandSide_,numRows_);
+  else
+    rightHandSide_ = rhs.rightHandSide_;
+  if (owned_.objCoefficients)
+    objCoefficients_ = CoinCopyOfArray(rhs.objCoefficients_,numCols_);
+  else
+    objCoefficients_ = rhs.objCoefficients_;
+  if (owned_.colType)
+    colType_ = CoinCopyOfArray(rhs.colType_,numCols_);
+  else
+    colType_ = rhs.colType_;
+  if (owned_.colSolution)
+    colSolution_ = CoinCopyOfArray(rhs.colSolution_,numCols_);
+  else
+    colSolution_ = rhs.colSolution_;
+  if (owned_.rowPrice)
+    rowPrice_ = CoinCopyOfArray(rhs.rowPrice_,numRows_);
+  else
+    rowPrice_ = rhs.rowPrice_;
+  if (owned_.reducedCost)
+    reducedCost_ = CoinCopyOfArray(rhs.reducedCost_,numCols_);
+  else
+    reducedCost_ = rhs.reducedCost_;
+  if (owned_.rowActivity)
+    rowActivity_ = CoinCopyOfArray(rhs.rowActivity_,numRows_);
+  else
+    rowActivity_ = rhs.rowActivity_;
+  if (owned_.doNotSeparateThis)
+    doNotSeparateThis_ = CoinCopyOfArray(rhs.doNotSeparateThis_,numCols_);
+  else
+    doNotSeparateThis_ = rhs.doNotSeparateThis_;
+  if (owned_.matrixByRow)
+    matrixByRow_ = new CoinPackedMatrix(*rhs.matrixByRow_);
+  else
+    matrixByRow_ = rhs.matrixByRow_;
+  if (owned_.matrixByCol)
+    matrixByCol_ = new CoinPackedMatrix(*rhs.matrixByCol_);
+  else
+    matrixByCol_ = rhs.matrixByCol_;
+  if (owned_.originalMatrixByRow)
+    originalMatrixByRow_ = new CoinPackedMatrix(*rhs.originalMatrixByRow_);
+  else
+    originalMatrixByRow_ = rhs.originalMatrixByRow_;
+  if (owned_.originalMatrixByCol)
+    originalMatrixByCol_ = new CoinPackedMatrix(*rhs.originalMatrixByCol_);
+  else
+    originalMatrixByCol_ = rhs.originalMatrixByCol_;
+}
+/* Load in an problem by copying the arguments (the constraints on the
+   rows are given by lower and upper bounds). If a pointer is NULL then the
+   following values are the default:
+   <ul>
+   <li> <code>colub</code>: all columns have upper bound infinity
+   <li> <code>collb</code>: all columns have lower bound 0 
+   <li> <code>rowub</code>: all rows have upper bound infinity
+   <li> <code>rowlb</code>: all rows have lower bound -infinity
+   <li> <code>obj</code>: all variables have 0 objective coefficient
+      </ul>
+*/
+void 
+CoinSnapshot::loadProblem(const CoinPackedMatrix& matrix,
+			  const double* collb, const double* colub,   
+			  const double* obj,
+			  const double* rowlb, const double* rowub,
+			  bool makeRowCopy)
+{
+  // Keep scalars (apart from objective value etc)
+  gutsOfDestructor(3+8);
+  numRows_ = matrix.getNumRows();
+  numCols_ = matrix.getNumCols();
+  numElements_ = matrix.getNumElements();
+  owned_.matrixByCol = 1;
+  matrixByCol_ = new CoinPackedMatrix(matrix);
+  if (makeRowCopy) {
+    owned_.matrixByRow = 1;
+    CoinPackedMatrix * matrixByRow = new CoinPackedMatrix(matrix);
+    matrixByRow->reverseOrdering();
+    matrixByRow_ = matrixByRow;
+  }
+  colLower_ = CoinCopyOfArray(collb,numCols_,0.0);
+  colUpper_ = CoinCopyOfArray(colub,numCols_,infinity_);
+  objCoefficients_ = CoinCopyOfArray(obj,numCols_,0.0);
+  rowLower_ = CoinCopyOfArray(rowlb,numRows_,-infinity_);
+  rowUpper_ = CoinCopyOfArray(rowub,numRows_,infinity_);
+  // do rhs as well
+  createRightHandSide();
+}
+  
+// Set pointer to array[getNumCols()] of column lower bounds
+void 
+CoinSnapshot::setColLower(const double * array, bool copyIn)
+{
+  if (owned_.colLower)
+    delete [] colLower_;
+  if (copyIn) {
+    owned_.colLower=1;
+    colLower_ = CoinCopyOfArray(array,numCols_);
+  } else {
+    owned_.colLower=0;
+    colLower_ = array;
+  }
+}
+// Set pointer to array[getNumCols()] of column upper bounds
+void 
+CoinSnapshot::setColUpper(const double * array, bool copyIn)
+{
+  if (owned_.colUpper)
+    delete [] colUpper_;
+  if (copyIn) {
+    owned_.colUpper=1;
+    colUpper_ = CoinCopyOfArray(array,numCols_);
+  } else {
+    owned_.colUpper=0;
+    colUpper_ = array;
+  }
+}
+// Set pointer to array[getNumRows()] of row lower bounds
+void 
+CoinSnapshot::setRowLower(const double * array, bool copyIn)
+{
+  if (owned_.rowLower)
+    delete [] rowLower_;
+  if (copyIn) {
+    owned_.rowLower=1;
+    rowLower_ = CoinCopyOfArray(array,numRows_);
+  } else {
+    owned_.rowLower=0;
+    rowLower_ = array;
+  }
+}
+// Set pointer to array[getNumRows()] of row upper bounds
+void 
+CoinSnapshot::setRowUpper(const double * array, bool copyIn)
+{
+  if (owned_.rowUpper)
+    delete [] rowUpper_;
+  if (copyIn) {
+    owned_.rowUpper=1;
+    rowUpper_ = CoinCopyOfArray(array,numRows_);
+  } else {
+    owned_.rowUpper=0;
+    rowUpper_ = array;
+  }
+}
+/* Set pointer to array[getNumRows()] of rhs side values
+   This gives same results as OsiSolverInterface for useful cases
+   If getRowUpper()[i] != infinity then
+     getRightHandSide()[i] == getRowUpper()[i]
+   else
+     getRightHandSide()[i] == getRowLower()[i]
+*/
+void 
+CoinSnapshot::setRightHandSide(const double * array, bool copyIn)
+{
+  if (owned_.rightHandSide)
+    delete [] rightHandSide_;
+  if (copyIn) {
+    owned_.rightHandSide=1;
+    rightHandSide_ = CoinCopyOfArray(array,numRows_);
+  } else {
+    owned_.rightHandSide=0;
+    rightHandSide_ = array;
+  }
+}
+/* Create array[getNumRows()] of rhs side values
+   This gives same results as OsiSolverInterface for useful cases
+   If getRowUpper()[i] != infinity then
+     getRightHandSide()[i] == getRowUpper()[i]
+   else
+     getRightHandSide()[i] == getRowLower()[i]
+*/
+void 
+CoinSnapshot::createRightHandSide()
+{
+  if (owned_.rightHandSide)
+    delete [] rightHandSide_;
+  owned_.rightHandSide=1;
+  assert (rowUpper_);
+  assert (rowLower_);
+  double * rightHandSide = CoinCopyOfArray(rowUpper_,numRows_);
+  for (int i=0;i<numRows_;i++) {
+    if (rightHandSide[i]==infinity_)
+      rightHandSide[i] = rowLower_[i];
+  }
+  rightHandSide_ = rightHandSide;
+}
+// Set pointer to array[getNumCols()] of objective function coefficients
+void 
+CoinSnapshot::setObjCoefficients(const double * array, bool copyIn)
+{
+  if (owned_.objCoefficients)
+    delete [] objCoefficients_;
+  if (copyIn) {
+    owned_.objCoefficients=1;
+    objCoefficients_ = CoinCopyOfArray(array,numCols_);
+  } else {
+    owned_.objCoefficients=0;
+    objCoefficients_ = array;
+  }
+}
+// Set colType array ('B', 'I', or 'C' for Binary, Integer and Continuous) 
+void 
+CoinSnapshot::setColType(const char *array, bool copyIn)
+{
+  if (owned_.colType)
+    delete [] colType_;
+  if (copyIn) {
+    owned_.colType=1;
+    colType_ = CoinCopyOfArray(array,numCols_);
+  } else {
+    owned_.colType=0;
+    colType_ = array;
+  }
+  int i;
+  numIntegers_=0;
+  for (i=0;i<numCols_;i++) {
+    if (colType_[i]=='B'||colType_[i]=='I')
+      numIntegers_++;
+  }
+}
+// Set pointer to row-wise copy of current matrix
+void 
+CoinSnapshot::setMatrixByRow(const CoinPackedMatrix * matrix, bool copyIn)
+{
+  if (owned_.matrixByRow)
+    delete matrixByRow_;
+  if (copyIn) {
+    owned_.matrixByRow=1;
+    matrixByRow_ = new CoinPackedMatrix(*matrix);
+  } else {
+    owned_.matrixByRow=0;
+    matrixByRow_ = matrix;
+  }
+  assert (matrixByRow_->getNumCols()==numCols_);
+  assert (matrixByRow_->getNumRows()==numRows_);
+}
+// Create row-wise copy from MatrixByCol
+void 
+CoinSnapshot::createMatrixByRow()
+{
+  if (owned_.matrixByRow)
+    delete matrixByRow_;
+  assert (matrixByCol_);
+  owned_.matrixByRow = 1;
+  CoinPackedMatrix * matrixByRow = new CoinPackedMatrix(*matrixByCol_);
+  matrixByRow->reverseOrdering();
+  matrixByRow_ = matrixByRow;
+}
+// Set pointer to column-wise copy of current matrix
+void 
+CoinSnapshot::setMatrixByCol(const CoinPackedMatrix * matrix, bool copyIn)
+{
+  if (owned_.matrixByCol)
+    delete matrixByCol_;
+  if (copyIn) {
+    owned_.matrixByCol=1;
+    matrixByCol_ = new CoinPackedMatrix(*matrix);
+  } else {
+    owned_.matrixByCol=0;
+    matrixByCol_ = matrix;
+  }
+  assert (matrixByCol_->getNumCols()==numCols_);
+  assert (matrixByCol_->getNumRows()==numRows_);
+}
+// Set pointer to row-wise copy of "original" matrix
+void 
+CoinSnapshot::setOriginalMatrixByRow(const CoinPackedMatrix * matrix, bool copyIn)
+{
+  if (owned_.originalMatrixByRow)
+    delete originalMatrixByRow_;
+  if (copyIn) {
+    owned_.originalMatrixByRow=1;
+    originalMatrixByRow_ = new CoinPackedMatrix(*matrix);
+  } else {
+    owned_.originalMatrixByRow=0;
+    originalMatrixByRow_ = matrix;
+  }
+  assert (matrixByRow_->getNumCols()==numCols_);
+}
+// Set pointer to column-wise copy of "original" matrix
+void 
+CoinSnapshot::setOriginalMatrixByCol(const CoinPackedMatrix * matrix, bool copyIn)
+{
+  if (owned_.originalMatrixByCol)
+    delete originalMatrixByCol_;
+  if (copyIn) {
+    owned_.originalMatrixByCol=1;
+    originalMatrixByCol_ = new CoinPackedMatrix(*matrix);
+  } else {
+    owned_.originalMatrixByCol=0;
+    originalMatrixByCol_ = matrix;
+  }
+  assert (matrixByCol_->getNumCols()==numCols_);
+}
+// Set pointer to array[getNumCols()] of primal variable values
+void 
+CoinSnapshot::setColSolution(const double * array, bool copyIn)
+{
+  if (owned_.colSolution)
+    delete [] colSolution_;
+  if (copyIn) {
+    owned_.colSolution=1;
+    colSolution_ = CoinCopyOfArray(array,numCols_);
+  } else {
+    owned_.colSolution=0;
+    colSolution_ = array;
+  }
+}
+// Set pointer to array[getNumRows()] of dual variable values
+void 
+CoinSnapshot::setRowPrice(const double * array, bool copyIn)
+{
+  if (owned_.rowPrice)
+    delete [] rowPrice_;
+  if (copyIn) {
+    owned_.rowPrice=1;
+    rowPrice_ = CoinCopyOfArray(array,numRows_);
+  } else {
+    owned_.rowPrice=0;
+    rowPrice_ = array;
+  }
+}
+// Set a pointer to array[getNumCols()] of reduced costs
+void 
+CoinSnapshot::setReducedCost(const double * array, bool copyIn)
+{
+  if (owned_.reducedCost)
+    delete [] reducedCost_;
+  if (copyIn) {
+    owned_.reducedCost=1;
+    reducedCost_ = CoinCopyOfArray(array,numCols_);
+  } else {
+    owned_.reducedCost=0;
+    reducedCost_ = array;
+  }
+}
+// Set pointer to array[getNumRows()] of row activity levels (constraint matrix times the solution vector). 
+void 
+CoinSnapshot::setRowActivity(const double * array, bool copyIn)
+{
+  if (owned_.rowActivity)
+    delete [] rowActivity_;
+  if (copyIn) {
+    owned_.rowActivity=1;
+    rowActivity_ = CoinCopyOfArray(array,numRows_);
+  } else {
+    owned_.rowActivity=0;
+    rowActivity_ = array;
+  }
+}
+// Set pointer to array[getNumCols()] of primal variable values which should not be separated (for debug)
+void 
+CoinSnapshot::setDoNotSeparateThis(const double * array, bool copyIn)
+{
+  if (owned_.doNotSeparateThis)
+    delete [] doNotSeparateThis_;
+  if (copyIn) {
+    owned_.doNotSeparateThis=1;
+    doNotSeparateThis_ = CoinCopyOfArray(array,numCols_);
+  } else {
+    owned_.doNotSeparateThis=0;
+    doNotSeparateThis_ = array;
+  }
+}
diff --git a/cbits/coin/CoinSnapshot.hpp b/cbits/coin/CoinSnapshot.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinSnapshot.hpp
@@ -0,0 +1,476 @@
+/* $Id: CoinSnapshot.hpp 1416 2011-04-17 09:57:29Z stefan $ */
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinSnapshot_H
+#define CoinSnapshot_H
+
+class CoinPackedMatrix;
+#include "CoinTypes.hpp"
+
+//#############################################################################
+
+/** NON Abstract Base Class for interfacing with cut generators or branching code or ..
+    It is designed to be snapshot of a problem at a node in tree
+    
+  The class may or may not own the arrays - see owned_
+
+
+  Querying a problem that has no data associated with it will result in
+  zeros for the number of rows and columns, and NULL pointers from
+  the methods that return arrays.
+*/
+
+class CoinSnapshot  {
+  
+public:
+  
+  //---------------------------------------------------------------------------
+  /**@name Problem query methods
+     
+     The Matrix pointers may be NULL
+  */
+  //@{
+  /// Get number of columns
+  inline int getNumCols() const
+  { return numCols_;}
+  
+  /// Get number of rows
+  inline int getNumRows() const
+  { return numRows_;}
+  
+  /// Get number of nonzero elements
+  inline int getNumElements() const
+  { return numElements_;}
+  
+  /// Get number of integer variables
+  inline int getNumIntegers() const
+  { return numIntegers_;}
+  
+  /// Get pointer to array[getNumCols()] of column lower bounds
+  inline const double * getColLower() const
+  { return colLower_;}
+  
+  /// Get pointer to array[getNumCols()] of column upper bounds
+  inline const double * getColUpper() const
+  { return colUpper_;}
+  
+  /// Get pointer to array[getNumRows()] of row lower bounds
+  inline const double * getRowLower() const
+  { return rowLower_;}
+  
+  /// Get pointer to array[getNumRows()] of row upper bounds
+  inline const double * getRowUpper() const
+  { return rowUpper_;}
+  
+  /** Get pointer to array[getNumRows()] of row right-hand sides
+      This gives same results as OsiSolverInterface for useful cases
+      If getRowUpper()[i] != infinity then
+        getRightHandSide()[i] == getRowUpper()[i]
+      else
+        getRightHandSide()[i] == getRowLower()[i]
+  */
+  inline const double * getRightHandSide() const
+  { return rightHandSide_;}
+
+  /// Get pointer to array[getNumCols()] of objective function coefficients
+  inline const double * getObjCoefficients() const
+  { return objCoefficients_;}
+  
+  /// Get objective function sense (1 for min (default), -1 for max)
+  inline double getObjSense() const
+  { return objSense_;}
+  
+  /// Return true if variable is continuous
+  inline bool isContinuous(int colIndex) const
+  { return colType_[colIndex]=='C';}
+  
+  /// Return true if variable is binary
+  inline bool isBinary(int colIndex) const
+  { return colType_[colIndex]=='B';}
+  
+  /// Return true if column is integer.
+  inline bool isInteger(int colIndex) const
+  { return colType_[colIndex]=='B'||colType_[colIndex]=='I';}
+  
+  /// Return true if variable is general integer
+  inline bool isIntegerNonBinary(int colIndex) const
+  { return colType_[colIndex]=='I';}
+  
+  /// Return true if variable is binary and not fixed at either bound
+  inline bool isFreeBinary(int colIndex) const
+  { return colType_[colIndex]=='B'&&colUpper_[colIndex]>colLower_[colIndex];}
+
+  /// Get colType array ('B', 'I', or 'C' for Binary, Integer and Continuous) 
+  inline const char * getColType() const
+  { return colType_;}
+  
+  /// Get pointer to row-wise copy of current matrix
+  inline const CoinPackedMatrix * getMatrixByRow() const
+  { return matrixByRow_;}
+  
+  /// Get pointer to column-wise copy of current matrix
+  inline const CoinPackedMatrix * getMatrixByCol() const
+  { return matrixByCol_;}
+  
+  /// Get pointer to row-wise copy of "original" matrix
+  inline const CoinPackedMatrix * getOriginalMatrixByRow() const
+  { return originalMatrixByRow_;}
+  
+  /// Get pointer to column-wise copy of "original" matrix
+  inline const CoinPackedMatrix * getOriginalMatrixByCol() const
+  { return originalMatrixByCol_;}
+  //@}
+  
+  /**@name Solution query methods */
+  //@{
+  /// Get pointer to array[getNumCols()] of primal variable values
+  inline const double * getColSolution() const
+  { return colSolution_;}
+  
+  /// Get pointer to array[getNumRows()] of dual variable values
+  inline const double * getRowPrice() const
+  { return rowPrice_;}
+  
+  /// Get a pointer to array[getNumCols()] of reduced costs
+  inline const double * getReducedCost() const
+  { return reducedCost_;}
+  
+  /// Get pointer to array[getNumRows()] of row activity levels (constraint matrix times the solution vector). 
+  inline const double * getRowActivity() const
+  { return rowActivity_;}
+  
+  /// Get pointer to array[getNumCols()] of primal variable values which should not be separated (for debug)
+  inline const double * getDoNotSeparateThis() const
+  { return doNotSeparateThis_;}
+  //@}
+  
+  /**@name Other scalar get methods */
+  //@{
+  /// Get solver's value for infinity
+  inline double getInfinity() const
+  { return infinity_;}
+  
+  /** Get objective function value - includinbg any offset i.e.
+      sum c sub j * x subj - objValue = objOffset */
+  inline double getObjValue() const
+  { return objValue_;}
+
+  /// Get objective offset i.e. sum c sub j * x subj -objValue = objOffset 
+  inline double getObjOffset() const
+  { return objOffset_;}
+
+  /// Get dual tolerance
+  inline double getDualTolerance() const
+  { return dualTolerance_;}
+
+  /// Get primal tolerance
+  inline double getPrimalTolerance() const
+  { return primalTolerance_;}
+
+  /// Get integer tolerance
+  inline double getIntegerTolerance() const
+  { return integerTolerance_;}
+
+  /// Get integer upper bound i.e. best solution * getObjSense
+  inline double getIntegerUpperBound() const
+  { return integerUpperBound_;}
+
+  /// Get integer lower bound i.e. best possible solution * getObjSense
+  inline double getIntegerLowerBound() const
+  { return integerLowerBound_;}
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+  /**@name Method to input a problem */
+  //@{
+  /** Load in an problem by copying the arguments (the constraints on the
+      rows are given by lower and upper bounds). If a pointer is NULL then the
+      following values are the default:
+      <ul>
+      <li> <code>colub</code>: all columns have upper bound infinity
+      <li> <code>collb</code>: all columns have lower bound 0 
+      <li> <code>rowub</code>: all rows have upper bound infinity
+      <li> <code>rowlb</code>: all rows have lower bound -infinity
+      <li> <code>obj</code>: all variables have 0 objective coefficient
+      </ul>
+      All solution type arrays will be deleted
+  */
+  void loadProblem(const CoinPackedMatrix& matrix,
+		   const double* collb, const double* colub,   
+		   const double* obj,
+		   const double* rowlb, const double* rowub,
+		   bool makeRowCopy=false);
+  
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+  /**@name Methods to set data */
+  //@{
+  /// Set number of columns
+  inline void setNumCols(int value)
+  { numCols_ = value;}
+  
+  /// Set number of rows
+  inline void setNumRows(int value)
+  { numRows_ = value;}
+  
+  /// Set number of nonzero elements
+  inline void setNumElements(int value)
+  { numElements_ = value;}
+  
+  /// Set number of integer variables
+  inline void setNumIntegers(int value)
+  { numIntegers_ = value;}
+  
+  /// Set pointer to array[getNumCols()] of column lower bounds
+  void setColLower(const double * array, bool copyIn=true);
+  
+  /// Set pointer to array[getNumCols()] of column upper bounds
+  void setColUpper(const double * array, bool copyIn=true);
+  
+  /// Set pointer to array[getNumRows()] of row lower bounds
+  void setRowLower(const double * array, bool copyIn=true);
+  
+  /// Set pointer to array[getNumRows()] of row upper bounds
+  void setRowUpper(const double * array, bool copyIn=true);
+  
+  /** Set pointer to array[getNumRows()] of row right-hand sides
+      This gives same results as OsiSolverInterface for useful cases
+      If getRowUpper()[i] != infinity then
+        getRightHandSide()[i] == getRowUpper()[i]
+      else
+        getRightHandSide()[i] == getRowLower()[i]
+  */
+  void setRightHandSide(const double * array, bool copyIn=true);
+
+  /** Create array[getNumRows()] of row right-hand sides
+      using existing information
+      This gives same results as OsiSolverInterface for useful cases
+      If getRowUpper()[i] != infinity then
+        getRightHandSide()[i] == getRowUpper()[i]
+      else
+        getRightHandSide()[i] == getRowLower()[i]
+  */
+  void createRightHandSide();
+
+  /// Set pointer to array[getNumCols()] of objective function coefficients
+  void setObjCoefficients(const double * array, bool copyIn=true);
+  
+  /// Set objective function sense (1 for min (default), -1 for max)
+  inline void setObjSense(double value)
+  { objSense_ = value;}
+  
+  /// Set colType array ('B', 'I', or 'C' for Binary, Integer and Continuous) 
+  void setColType(const char *array, bool copyIn=true);
+  
+  /// Set pointer to row-wise copy of current matrix
+  void setMatrixByRow(const CoinPackedMatrix * matrix, bool copyIn=true);
+  
+  /// Create row-wise copy from MatrixByCol
+  void createMatrixByRow();
+  
+  /// Set pointer to column-wise copy of current matrix
+  void setMatrixByCol(const CoinPackedMatrix * matrix, bool copyIn=true);
+  
+  /// Set pointer to row-wise copy of "original" matrix
+  void setOriginalMatrixByRow(const CoinPackedMatrix * matrix, bool copyIn=true);
+  
+  /// Set pointer to column-wise copy of "original" matrix
+  void setOriginalMatrixByCol(const CoinPackedMatrix * matrix, bool copyIn=true);
+
+  /// Set pointer to array[getNumCols()] of primal variable values
+  void setColSolution(const double * array, bool copyIn=true);
+  
+  /// Set pointer to array[getNumRows()] of dual variable values
+  void setRowPrice(const double * array, bool copyIn=true);
+  
+  /// Set a pointer to array[getNumCols()] of reduced costs
+  void setReducedCost(const double * array, bool copyIn=true);
+  
+  /// Set pointer to array[getNumRows()] of row activity levels (constraint matrix times the solution vector). 
+  void setRowActivity(const double * array, bool copyIn=true);
+  
+  /// Set pointer to array[getNumCols()] of primal variable values which should not be separated (for debug)
+  void setDoNotSeparateThis(const double * array, bool copyIn=true);
+
+  /// Set solver's value for infinity
+  inline void setInfinity(double value)
+  { infinity_ = value;}
+  
+  /// Set objective function value (including any rhs offset)
+  inline void setObjValue(double value)
+  { objValue_ = value;}
+
+  /// Set objective offset i.e. sum c sub j * x subj -objValue = objOffset 
+  inline void setObjOffset(double value)
+  { objOffset_ = value;}
+
+  /// Set dual tolerance
+  inline void setDualTolerance(double value)
+  { dualTolerance_ = value;}
+
+  /// Set primal tolerance
+  inline void setPrimalTolerance(double value)
+  { primalTolerance_ = value;}
+
+  /// Set integer tolerance
+  inline void setIntegerTolerance(double value)
+  { integerTolerance_ = value;}
+
+  /// Set integer upper bound i.e. best solution * getObjSense
+  inline void setIntegerUpperBound(double value)
+  { integerUpperBound_ = value;}
+
+  /// Set integer lower bound i.e. best possible solution * getObjSense
+  inline void setIntegerLowerBound(double value)
+  { integerLowerBound_ = value;}
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+  ///@name Constructors and destructors
+  //@{
+  /// Default Constructor
+  CoinSnapshot(); 
+    
+  /// Copy constructor 
+  CoinSnapshot(const CoinSnapshot &);
+  
+  /// Assignment operator 
+  CoinSnapshot & operator=(const CoinSnapshot& rhs);
+  
+  /// Destructor 
+  virtual ~CoinSnapshot ();
+  
+  //@}
+
+private:
+  ///@name private functions
+  //@{
+  /** Does main work of destructor - type (or'ed)
+      1 - NULLify pointers
+      2 - delete pointers
+      4 - initialize scalars (tolerances etc)
+      8 - initialize scalars (objValue etc0
+  */
+  void gutsOfDestructor(int type);
+  /// Does main work of copy
+  void gutsOfCopy(const CoinSnapshot & rhs);
+  //@}
+
+  ///@name Private member data 
+
+  /// objective function sense (1 for min (default), -1 for max)
+  double objSense_;
+  
+  /// solver's value for infinity
+  double infinity_;
+  
+  /// objective function value (including any rhs offset)
+  double objValue_;
+
+  /// objective offset i.e. sum c sub j * x subj -objValue = objOffset 
+  double objOffset_;
+
+  /// dual tolerance
+  double dualTolerance_;
+
+  /// primal tolerance
+  double primalTolerance_;
+
+  /// integer tolerance
+  double integerTolerance_;
+
+  /// integer upper bound i.e. best solution * getObjSense
+  double integerUpperBound_;
+
+  /// integer lower bound i.e. best possible solution * getObjSense
+  double integerLowerBound_;
+
+  /// pointer to array[getNumCols()] of column lower bounds
+  const double * colLower_;
+  
+  /// pointer to array[getNumCols()] of column upper bounds
+  const double * colUpper_;
+  
+  /// pointer to array[getNumRows()] of row lower bounds
+  const double * rowLower_;
+  
+  /// pointer to array[getNumRows()] of row upper bounds
+  const double * rowUpper_;
+  
+  /// pointer to array[getNumRows()] of rhs side values
+  const double * rightHandSide_;
+  
+  /// pointer to array[getNumCols()] of objective function coefficients
+  const double * objCoefficients_;
+  
+  /// colType array ('B', 'I', or 'C' for Binary, Integer and Continuous) 
+  const char * colType_;
+  
+  /// pointer to row-wise copy of current matrix
+  const CoinPackedMatrix * matrixByRow_;
+  
+  /// pointer to column-wise copy of current matrix
+  const CoinPackedMatrix * matrixByCol_;
+  
+  /// pointer to row-wise copy of "original" matrix
+  const CoinPackedMatrix * originalMatrixByRow_;
+  
+  /// pointer to column-wise copy of "original" matrix
+  const CoinPackedMatrix * originalMatrixByCol_;
+
+  /// pointer to array[getNumCols()] of primal variable values
+  const double * colSolution_;
+  
+  /// pointer to array[getNumRows()] of dual variable values
+  const double * rowPrice_;
+  
+  /// a pointer to array[getNumCols()] of reduced costs
+  const double * reducedCost_;
+  
+  /// pointer to array[getNumRows()] of row activity levels (constraint matrix times the solution vector). 
+  const double * rowActivity_;
+  
+  /// pointer to array[getNumCols()] of primal variable values which should not be separated (for debug)
+  const double * doNotSeparateThis_;
+
+  /// number of columns
+  int numCols_;
+  
+  /// number of rows
+  int numRows_;
+  
+  /// number of nonzero elements
+  int numElements_;
+  
+  /// number of integer variables
+  int numIntegers_;
+
+  /// To say whether arrays etc are owned by CoinSnapshot
+    typedef struct {
+      unsigned int colLower:1;
+      unsigned int colUpper:1;
+      unsigned int rowLower:1;
+      unsigned int rowUpper:1;
+      unsigned int rightHandSide:1;
+      unsigned int objCoefficients:1;
+      unsigned int colType:1;
+      unsigned int matrixByRow:1;
+      unsigned int matrixByCol:1;
+      unsigned int originalMatrixByRow:1;
+      unsigned int originalMatrixByCol:1;
+      unsigned int colSolution:1;
+      unsigned int rowPrice:1;
+      unsigned int reducedCost:1;
+      unsigned int rowActivity:1;
+      unsigned int doNotSeparateThis:1;
+  } coinOwned;
+  coinOwned owned_;
+  //@}
+};  
+#endif
diff --git a/cbits/coin/CoinSort.hpp b/cbits/coin/CoinSort.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinSort.hpp
@@ -0,0 +1,678 @@
+/* $Id: CoinSort.hpp 1596 2013-04-25 14:29:25Z stefan $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinSort_H
+#define CoinSort_H
+
+#include <functional>
+#include <new>
+#include <algorithm>
+#include "CoinDistance.hpp"
+
+// Uncomment the next three lines to get thorough initialisation of memory.
+// #ifndef ZEROFAULT
+// #define ZEROFAULT
+// #endif
+
+#ifdef COIN_FAST_CODE
+#ifndef COIN_USE_EKK_SORT
+#define COIN_USE_EKK_SORT
+#endif
+#endif
+
+//#############################################################################
+
+/** An ordered pair. It's the same as std::pair, just this way it'll have the
+    same look as the triple sorting. */
+template <class S, class T>
+struct CoinPair {
+public:
+  /// First member of pair
+  S first;
+  /// Second member of pair
+  T second;
+public:
+  /// Construct from ordered pair
+  CoinPair(const S& s, const T& t) : first(s), second(t) {}
+};
+
+//#############################################################################
+
+/**@name Comparisons on first element of two ordered pairs */
+//@{   
+/** Function operator.
+    Returns true if t1.first &lt; t2.first (i.e., increasing). */
+template < class S, class T>
+class CoinFirstLess_2 {
+public:
+  /// Compare function
+  inline bool operator()(const CoinPair<S,T>& t1,
+			 const CoinPair<S,T>& t2) const
+  { return t1.first < t2.first; }
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Returns true if t1.first &gt; t2.first (i.e, decreasing). */
+template < class S, class T>
+class CoinFirstGreater_2 {
+public:
+  /// Compare function
+  inline bool operator()(const CoinPair<S,T>& t1,
+			 const CoinPair<S,T>& t2) const
+  { return t1.first > t2.first; }
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Returns true if abs(t1.first) &lt; abs(t2.first) (i.e., increasing). */
+template < class S, class T>
+class CoinFirstAbsLess_2 {
+public:
+  /// Compare function
+  inline bool operator()(const CoinPair<S,T>& t1,
+			 const CoinPair<S,T>& t2) const
+  { 
+    const T t1Abs = t1.first < static_cast<T>(0) ? -t1.first : t1.first;
+    const T t2Abs = t2.first < static_cast<T>(0) ? -t2.first : t2.first;
+    return t1Abs < t2Abs; 
+  }
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Returns true if abs(t1.first) &gt; abs(t2.first) (i.e., decreasing). */
+template < class S, class T>
+class CoinFirstAbsGreater_2 {
+public:
+  /// Compare function
+  inline bool operator()(CoinPair<S,T> t1, CoinPair<S,T> t2) const
+  { 
+    const T t1Abs = t1.first < static_cast<T>(0) ? -t1.first : t1.first;
+    const T t2Abs = t2.first < static_cast<T>(0) ? -t2.first : t2.first;
+    return t1Abs > t2Abs; 
+  }
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Compare based on the entries of an external vector, i.e., returns true if
+    vec[t1.first &lt; vec[t2.first] (i.e., increasing wrt. vec). Note that to
+    use this comparison operator .first must be a data type automatically
+    convertible to int. */
+template < class S, class T, class V>
+class CoinExternalVectorFirstLess_2 {
+private:
+  CoinExternalVectorFirstLess_2();
+private:
+  const V* vec_;
+public:
+  inline bool operator()(const CoinPair<S,T>& t1,
+			 const CoinPair<S,T>& t2) const
+  { return vec_[t1.first] < vec_[t2.first]; }
+  CoinExternalVectorFirstLess_2(const V* v) : vec_(v) {}
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Compare based on the entries of an external vector, i.e., returns true if
+    vec[t1.first &gt; vec[t2.first] (i.e., decreasing wrt. vec). Note that to
+    use this comparison operator .first must be a data type automatically
+    convertible to int. */
+template < class S, class T, class V>
+class CoinExternalVectorFirstGreater_2 {
+private:
+  CoinExternalVectorFirstGreater_2();
+private:
+  const V* vec_;
+public:
+  inline bool operator()(const CoinPair<S,T>& t1,
+			 const CoinPair<S,T>& t2) const
+  { return vec_[t1.first] > vec_[t2.first]; }
+  CoinExternalVectorFirstGreater_2(const V* v) : vec_(v) {}
+};
+//@}
+
+//#############################################################################
+
+/** Sort a pair of containers.<br>
+
+    Iter_S - iterator for first container<br>
+    Iter_T - iterator for 2nd container<br>
+    CoinCompare2 - class comparing CoinPairs<br>
+*/
+
+#ifdef COIN_SORT_ARBITRARY_CONTAINERS
+template <class Iter_S, class Iter_T, class CoinCompare2> void
+CoinSort_2(Iter_S sfirst, Iter_S slast, Iter_T tfirst, const CoinCompare2& pc)
+{
+  typedef typename std::iterator_traits<Iter_S>::value_type S;
+  typedef typename std::iterator_traits<Iter_T>::value_type T;
+  const size_t len = coinDistance(sfirst, slast);
+  if (len <= 1)
+    return;
+
+  typedef CoinPair<S,T> ST_pair;
+  ST_pair* x = static_cast<ST_pair*>(::operator new(len * sizeof(ST_pair)));
+# ifdef ZEROFAULT
+  memset(x,0,(len*sizeof(ST_pair))) ;
+# endif
+
+  int i = 0;
+  Iter_S scurrent = sfirst;
+  Iter_T tcurrent = tfirst;
+  while (scurrent != slast) {
+    new (x+i++) ST_pair(*scurrent++, *tcurrent++);
+  }
+
+  std::sort(x.begin(), x.end(), pc);
+
+  scurrent = sfirst;
+  tcurrent = tfirst;
+  for (i = 0; i < len; ++i) {
+    *scurrent++ = x[i].first;
+    *tcurrent++ = x[i].second;
+  }
+
+  ::operator delete(x);
+}
+//-----------------------------------------------------------------------------
+template <class Iter_S, class Iter_T> void
+CoinSort_2(Iter_S sfirst, Iter_S slast, Iter_T tfirst)
+{
+  typedef typename std::iterator_traits<Iter_S>::value_type S;
+  typedef typename std::iterator_traits<Iter_T>::value_type T;
+  CoinSort_2(sfirst, slast, tfirst, CoinFirstLess_2<S,T>());
+}
+
+#else //=======================================================================
+
+template <class S, class T, class CoinCompare2> void
+CoinSort_2(S* sfirst, S* slast, T* tfirst, const CoinCompare2& pc)
+{
+  const size_t len = coinDistance(sfirst, slast);
+  if (len <= 1)
+    return;
+
+  typedef CoinPair<S,T> ST_pair;
+  ST_pair* x = static_cast<ST_pair*>(::operator new(len * sizeof(ST_pair)));
+# ifdef ZEROFAULT
+  // Can show RUI errors on some systems due to copy of ST_pair with gaps.
+  // E.g., <int, double> has 4 byte alignment gap on Solaris/SUNWspro.
+  memset(x,0,(len*sizeof(ST_pair))) ;
+# endif
+
+  size_t i = 0;
+  S* scurrent = sfirst;
+  T* tcurrent = tfirst;
+  while (scurrent != slast) {
+    new (x+i++) ST_pair(*scurrent++, *tcurrent++);
+  }
+
+  std::sort(x, x + len, pc);
+
+  scurrent = sfirst;
+  tcurrent = tfirst;
+  for (i = 0; i < len; ++i) {
+    *scurrent++ = x[i].first;
+    *tcurrent++ = x[i].second;
+  }
+
+  ::operator delete(x);
+}
+template <class S, class T> void
+// This Always uses std::sort
+CoinSort_2Std(S* sfirst, S* slast, T* tfirst)
+{
+  CoinSort_2(sfirst, slast, tfirst, CoinFirstLess_2<S,T>());
+}
+#ifndef COIN_USE_EKK_SORT
+//-----------------------------------------------------------------------------
+template <class S, class T> void
+CoinSort_2(S* sfirst, S* slast, T* tfirst)
+{
+  CoinSort_2(sfirst, slast, tfirst, CoinFirstLess_2<S,T>());
+}
+#else
+//-----------------------------------------------------------------------------
+extern int boundary_sort;
+extern int boundary_sort2;
+extern int boundary_sort3;
+/// Sort without new and delete
+template <class S, class T> void
+CoinSort_2(S* key, S* lastKey, T* array2)
+{
+  const size_t number = coinDistance(key, lastKey);
+  if (number <= 1) {
+    return;
+  } else if (number>10000) {
+    CoinSort_2Std(key, lastKey, array2);
+    return;
+  }
+#if 0
+  if (number==boundary_sort3) {
+    printf("before sort %d entries\n",number);
+    for (int j=0;j<number;j++) {
+      std::cout<<" ( "<<key[j]<<","<<array2[j]<<")";
+    }
+    std::cout<<std::endl;
+  }
+#endif
+  int minsize=10;
+  int n = static_cast<int>(number);
+  int sp;
+  S *v = key;
+  S *m, t;
+  S * ls[32] , * rs[32];
+  S *l , *r , c;
+  T it;
+  int j;
+  /*check already sorted  */
+  S last=key[0];
+  for (j=1;j<n;j++) {
+    if (key[j]>=last) {
+      last=key[j];
+    } else {
+      break;
+    } /* endif */
+  } /* endfor */
+  if (j==n) {
+    return;
+  } /* endif */
+  sp = 0 ; ls[sp] = v ; rs[sp] = v + (n-1) ;
+  while( sp >= 0 )
+  {
+     if ( rs[sp] - ls[sp] > minsize )
+     {
+        l = ls[sp] ; r = rs[sp] ; m = l + (r-l)/2 ;
+        if ( *l > *m )
+        {
+           t = *l ; *l = *m ; *m = t ;
+           it = array2[l-v] ; array2[l-v] = array2[m-v] ; array2[m-v] = it ;
+        }
+        if ( *m > *r )
+        {
+           t = *m ; *m = *r ; *r = t ;
+           it = array2[m-v] ; array2[m-v] = array2[r-v] ; array2[r-v] = it ;
+           if ( *l > *m )
+           {
+              t = *l ; *l = *m ; *m = t ;
+              it = array2[l-v] ; array2[l-v] = array2[m-v] ; array2[m-v] = it ;
+           }
+        }
+        c = *m ;
+        while ( r - l > 1 )
+        {
+           while ( *(++l) < c ) ;
+           while ( *(--r) > c ) ;
+           t = *l ; *l = *r ; *r = t ;
+           it = array2[l-v] ; array2[l-v] = array2[r-v] ; array2[r-v] = it ;
+        }
+        l = r - 1 ;
+        if ( l < m )
+        {  ls[sp+1] = ls[sp] ;
+           rs[sp+1] = l      ;
+           ls[sp  ] = r      ;
+        }
+        else
+        {  ls[sp+1] = r      ;
+           rs[sp+1] = rs[sp] ;
+           rs[sp  ] = l      ;
+        }
+        sp++ ;
+     }
+     else sp-- ;
+  }
+  for ( l = v , m = v + (n-1) ; l < m ; l++ )
+  {  if ( *l > *(l+1) )
+     {
+        c = *(l+1) ;
+        it = array2[(l-v)+1] ;
+        for ( r = l ; r >= v && *r > c ; r-- )
+        {
+            *(r+1) = *r ;
+            array2[(r-v)+1] = array2[(r-v)] ;
+        }
+        *(r+1) = c ;
+        array2[(r-v)+1] = it ;
+     }
+  }
+#if 0
+  if (number==boundary_sort3) {
+    printf("after sort %d entries\n",number);
+    for (int j=0;j<number;j++) {
+      std::cout<<" ( "<<key[j]<<","<<array2[j]<<")";
+    }
+    std::cout<<std::endl;
+    CoinSort_2Many(key, lastKey, array2);
+    printf("after2 sort %d entries\n",number);
+    for (int j=0;j<number;j++) {
+      std::cout<<" ( "<<key[j]<<","<<array2[j]<<")";
+    }
+    std::cout<<std::endl;
+  }
+#endif
+}
+#endif
+#endif
+/// Sort without new and delete
+template <class S, class T> void
+CoinShortSort_2(S* key, S* lastKey, T* array2)
+{
+  const size_t number = coinDistance(key, lastKey);
+  if (number <= 2) {
+    if (number == 2 && key[0] > key[1]) {
+      S tempS = key[0];
+      T tempT = array2[0];
+      key[0] = key[1];
+      array2[0] = array2[1];
+      key[1] = tempS;
+      array2[1] = tempT;
+    } 
+    return;
+  } else if (number>10000) {
+    CoinSort_2Std(key, lastKey, array2);
+    return;
+  }
+  int minsize=10;
+  size_t n = number;
+  int sp;
+  S *v = key;
+  S *m, t;
+  S * ls[32] , * rs[32];
+  S *l , *r , c;
+  T it;
+  size_t j;
+  /*check already sorted  */
+  S last=key[0];
+  for (j=1;j<n;j++) {
+    if (key[j]>=last) {
+      last=key[j];
+    } else {
+      break;
+    } /* endif */
+  } /* endfor */
+  if (j==n) {
+    return;
+  } /* endif */
+  sp = 0 ; ls[sp] = v ; rs[sp] = v + (n-1) ;
+  while( sp >= 0 )
+  {
+     if ( rs[sp] - ls[sp] > minsize )
+     {
+        l = ls[sp] ; r = rs[sp] ; m = l + (r-l)/2 ;
+        if ( *l > *m )
+        {
+           t = *l ; *l = *m ; *m = t ;
+           it = array2[l-v] ; array2[l-v] = array2[m-v] ; array2[m-v] = it ;
+        }
+        if ( *m > *r )
+        {
+           t = *m ; *m = *r ; *r = t ;
+           it = array2[m-v] ; array2[m-v] = array2[r-v] ; array2[r-v] = it ;
+           if ( *l > *m )
+           {
+              t = *l ; *l = *m ; *m = t ;
+              it = array2[l-v] ; array2[l-v] = array2[m-v] ; array2[m-v] = it ;
+           }
+        }
+        c = *m ;
+        while ( r - l > 1 )
+        {
+           while ( *(++l) < c ) ;
+           while ( *(--r) > c ) ;
+           t = *l ; *l = *r ; *r = t ;
+           it = array2[l-v] ; array2[l-v] = array2[r-v] ; array2[r-v] = it ;
+        }
+        l = r - 1 ;
+        if ( l < m )
+        {  ls[sp+1] = ls[sp] ;
+           rs[sp+1] = l      ;
+           ls[sp  ] = r      ;
+        }
+        else
+        {  ls[sp+1] = r      ;
+           rs[sp+1] = rs[sp] ;
+           rs[sp  ] = l      ;
+        }
+        sp++ ;
+     }
+     else sp-- ;
+  }
+  for ( l = v , m = v + (n-1) ; l < m ; l++ )
+  {  if ( *l > *(l+1) )
+     {
+        c = *(l+1) ;
+        it = array2[(l-v)+1] ;
+        for ( r = l ; r >= v && *r > c ; r-- )
+        {
+            *(r+1) = *r ;
+            array2[(r-v)+1] = array2[(r-v)] ;
+        }
+        *(r+1) = c ;
+        array2[(r-v)+1] = it ;
+     }
+  }
+}
+//#############################################################################
+//#############################################################################
+
+/**@name Ordered Triple Struct */
+template <class S, class T, class U>
+class CoinTriple {
+public:
+  /// First member of triple
+  S first;
+  /// Second member of triple
+  T second;
+  /// Third member of triple
+  U third;
+public:  
+  /// Construct from ordered triple
+  CoinTriple(const S& s, const T& t, const U& u):first(s),second(t),third(u) {}
+};
+
+//#############################################################################
+/**@name Comparisons on first element of two ordered triples */
+//@{   
+/** Function operator.
+    Returns true if t1.first &lt; t2.first (i.e., increasing). */
+template < class S, class T, class U >
+class CoinFirstLess_3 {
+public:
+  /// Compare function
+  inline bool operator()(const CoinTriple<S,T,U>& t1,
+			 const CoinTriple<S,T,U>& t2) const
+  { return t1.first < t2.first; }
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Returns true if t1.first &gt; t2.first (i.e, decreasing). */
+template < class S, class T, class U >
+class CoinFirstGreater_3 {
+public:
+  /// Compare function
+  inline bool operator()(const CoinTriple<S,T,U>& t1,
+			 const CoinTriple<S,T,U>& t2) const
+  { return t1.first>t2.first; }
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Returns true if abs(t1.first) &lt; abs(t2.first) (i.e., increasing). */
+template < class S, class T, class U >
+class CoinFirstAbsLess_3 {
+public:
+  /// Compare function
+  inline bool operator()(const CoinTriple<S,T,U>& t1,
+			 const CoinTriple<S,T,U>& t2) const
+  { 
+    const T t1Abs = t1.first < static_cast<T>(0) ? -t1.first : t1.first;
+    const T t2Abs = t2.first < static_cast<T>(0) ? -t2.first : t2.first;
+    return t1Abs < t2Abs; 
+  }
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Returns true if abs(t1.first) &gt; abs(t2.first) (i.e., decreasing). */
+template < class S, class T, class U >
+class CoinFirstAbsGreater_3 {
+public:
+  /// Compare function
+  inline bool operator()(const CoinTriple<S,T,U>& t1,
+			 const CoinTriple<S,T,U>& t2) const
+  { 
+    const T t1Abs = t1.first < static_cast<T>(0) ? -t1.first : t1.first;
+    const T t2Abs = t2.first < static_cast<T>(0) ? -t2.first : t2.first;
+    return t1Abs > t2Abs; 
+  }
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Compare based on the entries of an external vector, i.e., returns true if
+    vec[t1.first &lt; vec[t2.first] (i.e., increasing wrt. vec). Note that to
+    use this comparison operator .first must be a data type automatically
+    convertible to int. */
+template < class S, class T, class U, class V>
+class CoinExternalVectorFirstLess_3 {
+private:
+  CoinExternalVectorFirstLess_3();
+private:
+  const V* vec_;
+public:
+  inline bool operator()(const CoinTriple<S,T,U>& t1,
+			 const CoinTriple<S,T,U>& t2) const
+  { return vec_[t1.first] < vec_[t2.first]; }
+  CoinExternalVectorFirstLess_3(const V* v) : vec_(v) {}
+};
+//-----------------------------------------------------------------------------
+/** Function operator.
+    Compare based on the entries of an external vector, i.e., returns true if
+    vec[t1.first &gt; vec[t2.first] (i.e., decreasing wrt. vec). Note that to
+    use this comparison operator .first must be a data type automatically
+    convertible to int. */
+template < class S, class T, class U, class V>
+class CoinExternalVectorFirstGreater_3 {
+private:
+  CoinExternalVectorFirstGreater_3();
+private:
+  const V* vec_;
+public:
+  inline bool operator()(const CoinTriple<S,T,U>& t1,
+			 const CoinTriple<S,T,U>& t2) const
+  { return vec_[t1.first] > vec_[t2.first]; }
+  CoinExternalVectorFirstGreater_3(const V* v) : vec_(v) {}
+};
+//@}
+
+//#############################################################################
+
+/**@name Typedefs for sorting the entries of a packed vector based on an
+   external vector. */
+//@{
+/// Sort packed vector in increasing order of the external vector
+typedef CoinExternalVectorFirstLess_3<int, int, double, double>
+CoinIncrSolutionOrdered;
+/// Sort packed vector in decreasing order of the external vector
+typedef CoinExternalVectorFirstGreater_3<int, int, double, double>
+CoinDecrSolutionOrdered;
+//@}
+
+//#############################################################################
+
+/** Sort a triple of containers.<br>
+
+    Iter_S - iterator for first container<br>
+    Iter_T - iterator for 2nd container<br>
+    Iter_U - iterator for 3rd container<br>
+    CoinCompare3 - class comparing CoinTriples<br>
+*/
+#ifdef COIN_SORT_ARBITRARY_CONTAINERS
+template <class Iter_S, class Iter_T, class Iter_U, class CoinCompare3> void
+CoinSort_3(Iter_S sfirst, Iter_S slast, Iter_T tfirst, Iter_U, ufirst,
+	  const CoinCompare3& tc)
+{
+  typedef typename std::iterator_traits<Iter_S>::value_type S;
+  typedef typename std::iterator_traits<Iter_T>::value_type T;
+  typedef typename std::iterator_traits<Iter_U>::value_type U;
+  const size_t len = coinDistance(sfirst, slast);
+  if (len <= 1)
+    return;
+
+  typedef CoinTriple<S,T,U> STU_triple;
+  STU_triple* x =
+    static_cast<STU_triple*>(::operator new(len * sizeof(STU_triple)));
+
+  int i = 0;
+  Iter_S scurrent = sfirst;
+  Iter_T tcurrent = tfirst;
+  Iter_U ucurrent = ufirst;
+  while (scurrent != slast) {
+    new (x+i++) STU_triple(*scurrent++, *tcurrent++, *ucurrent++);
+  }
+
+  std::sort(x, x+len, tc);
+
+  scurrent = sfirst;
+  tcurrent = tfirst;
+  ucurrent = ufirst;
+  for (i = 0; i < len; ++i) {
+    *scurrent++ = x[i].first;
+    *tcurrent++ = x[i].second;
+    *ucurrent++ = x[i].third;
+  }
+
+  ::operator delete(x);
+}
+//-----------------------------------------------------------------------------
+template <class Iter_S, class Iter_T, class Iter_U> void
+CoinSort_3(Iter_S sfirst, Iter_S slast, Iter_T tfirst, Iter_U, ufirst)
+{
+  typedef typename std::iterator_traits<Iter_S>::value_type S;
+  typedef typename std::iterator_traits<Iter_T>::value_type T;
+  typedef typename std::iterator_traits<Iter_U>::value_type U;
+  CoinSort_3(sfirts, slast, tfirst, ufirst, CoinFirstLess_3<S,T,U>());
+}
+
+#else //=======================================================================
+
+template <class S, class T, class U, class CoinCompare3> void
+CoinSort_3(S* sfirst, S* slast, T* tfirst, U* ufirst, const CoinCompare3& tc)
+{
+  const size_t len = coinDistance(sfirst,slast);
+  if (len <= 1)
+    return;
+
+  typedef CoinTriple<S,T,U> STU_triple;
+  STU_triple* x =
+    static_cast<STU_triple*>(::operator new(len * sizeof(STU_triple)));
+
+  size_t i = 0;
+  S* scurrent = sfirst;
+  T* tcurrent = tfirst;
+  U* ucurrent = ufirst;
+  while (scurrent != slast) {
+    new (x+i++) STU_triple(*scurrent++, *tcurrent++, *ucurrent++);
+  }
+
+  std::sort(x, x+len, tc);
+
+  scurrent = sfirst;
+  tcurrent = tfirst;
+  ucurrent = ufirst;
+  for (i = 0; i < len; ++i) {
+    *scurrent++ = x[i].first;
+    *tcurrent++ = x[i].second;
+    *ucurrent++ = x[i].third;
+  }
+
+  ::operator delete(x);
+}
+//-----------------------------------------------------------------------------
+template <class S, class T, class U> void
+CoinSort_3(S* sfirst, S* slast, T* tfirst, U* ufirst)
+{
+  CoinSort_3(sfirst, slast, tfirst, ufirst, CoinFirstLess_3<S,T,U>());
+}
+
+#endif
+
+//#############################################################################
+
+#endif
diff --git a/cbits/coin/CoinStructuredModel.cpp b/cbits/coin/CoinStructuredModel.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinStructuredModel.cpp
@@ -0,0 +1,1885 @@
+/* $Id: CoinStructuredModel.cpp 1585 2013-04-06 20:42:02Z stefan $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#include "CoinUtilsConfig.h"
+#include "CoinHelperFunctions.hpp"
+#include "CoinStructuredModel.hpp"
+#include "CoinSort.hpp"
+#include "CoinMpsIO.hpp"
+#include "CoinFloatEqual.hpp"
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+CoinStructuredModel::CoinStructuredModel () 
+  :  CoinBaseModel(),
+     numberRowBlocks_(0),
+     numberColumnBlocks_(0),
+     numberElementBlocks_(0),
+     maximumElementBlocks_(0),
+     blocks_(NULL),
+     coinModelBlocks_(NULL),
+     blockType_(NULL)
+{
+}
+/* Read a problem in MPS or GAMS format from the given filename.
+ */
+CoinStructuredModel::CoinStructuredModel(const char *fileName, 
+					 int decomposeType,
+					 int maxBlocks)
+  :  CoinBaseModel(),
+     numberRowBlocks_(0),
+     numberColumnBlocks_(0),
+     numberElementBlocks_(0),
+     maximumElementBlocks_(0),
+     blocks_(NULL),
+     coinModelBlocks_(NULL),
+     blockType_(NULL)
+{
+  CoinModel coinModel(fileName,false);
+  if (coinModel.numberRows()) {
+    problemName_ = coinModel.getProblemName();
+    optimizationDirection_ = coinModel.optimizationDirection();
+    objectiveOffset_ = coinModel.objectiveOffset();
+    if (!decomposeType) {
+      addBlock("row_master","column_master",coinModel);
+    } else {
+      const CoinPackedMatrix * matrix = coinModel.packedMatrix();
+      if (!matrix) 
+	coinModel.convertMatrix();
+      decompose(coinModel,decomposeType,maxBlocks);
+      //addBlock("row_master","column_master",coinModel);
+    }
+  }
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+CoinStructuredModel::CoinStructuredModel (const CoinStructuredModel & rhs) 
+  : CoinBaseModel(rhs),
+    numberRowBlocks_(rhs.numberRowBlocks_),
+    numberColumnBlocks_(rhs.numberColumnBlocks_),
+    numberElementBlocks_(rhs.numberElementBlocks_),
+    maximumElementBlocks_(rhs.maximumElementBlocks_)
+{
+  if (maximumElementBlocks_) {
+    blocks_ = CoinCopyOfArray(rhs.blocks_,maximumElementBlocks_);
+    for (int i=0;i<numberElementBlocks_;i++)
+      blocks_[i]= rhs.blocks_[i]->clone();
+    blockType_ = CoinCopyOfArray(rhs.blockType_,maximumElementBlocks_);
+    if (rhs.coinModelBlocks_) {
+      coinModelBlocks_ = CoinCopyOfArray(rhs.coinModelBlocks_,
+					 maximumElementBlocks_);
+      for (int i=0;i<numberElementBlocks_;i++)
+	coinModelBlocks_[i]= new CoinModel(*rhs.coinModelBlocks_[i]);
+    } else {
+      coinModelBlocks_ = NULL;
+    }
+  } else {
+    blocks_ = NULL;
+    blockType_ = NULL;
+    coinModelBlocks_ = NULL;
+  }
+  rowBlockNames_ = rhs.rowBlockNames_;
+  columnBlockNames_ = rhs.columnBlockNames_;
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+CoinStructuredModel::~CoinStructuredModel ()
+{
+  for (int i=0;i<numberElementBlocks_;i++)
+    delete blocks_[i];
+  delete [] blocks_;
+  delete [] blockType_;
+  if (coinModelBlocks_) {
+    for (int i=0;i<numberElementBlocks_;i++)
+      delete coinModelBlocks_[i];
+    delete [] coinModelBlocks_;
+  }
+}
+
+// Clone
+CoinBaseModel *
+CoinStructuredModel::clone() const
+{
+  return new CoinStructuredModel(*this);
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+CoinStructuredModel &
+CoinStructuredModel::operator=(const CoinStructuredModel& rhs)
+{
+  if (this != &rhs) {
+    CoinBaseModel::operator=(rhs);
+    for (int i=0;i<numberElementBlocks_;i++)
+      delete blocks_[i];
+    delete [] blocks_;
+    delete [] blockType_;
+    if (coinModelBlocks_) {
+      for (int i=0;i<numberElementBlocks_;i++)
+	delete coinModelBlocks_[i];
+      delete [] coinModelBlocks_;
+    }
+    numberRowBlocks_ = rhs.numberRowBlocks_;
+    numberColumnBlocks_ = rhs.numberColumnBlocks_;
+    numberElementBlocks_ = rhs.numberElementBlocks_;
+    maximumElementBlocks_ = rhs.maximumElementBlocks_;
+    if (maximumElementBlocks_) {
+      blocks_ = CoinCopyOfArray(rhs.blocks_,maximumElementBlocks_);
+      for (int i=0;i<numberElementBlocks_;i++)
+	blocks_[i]= rhs.blocks_[i]->clone();
+      blockType_ = CoinCopyOfArray(rhs.blockType_,maximumElementBlocks_);
+      if (rhs.coinModelBlocks_) {
+	coinModelBlocks_ = CoinCopyOfArray(rhs.coinModelBlocks_,
+					   maximumElementBlocks_);
+	for (int i=0;i<numberElementBlocks_;i++)
+	  coinModelBlocks_[i]= new CoinModel(*rhs.coinModelBlocks_[i]);
+      } else {
+	coinModelBlocks_ = NULL;
+      }
+    } else {
+      blocks_ = NULL;
+      blockType_ = NULL;
+      coinModelBlocks_ = NULL;
+    }
+    rowBlockNames_ = rhs.rowBlockNames_;
+    columnBlockNames_ = rhs.columnBlockNames_;
+  }
+  return *this;
+}
+static bool sameValues(const double * a, const double *b, int n)
+{
+  int i;
+  for ( i=0;i<n;i++) {
+    if (a[i]!=b[i])
+      break;
+  }
+  return (i==n);
+}
+static bool sameValues(const int * a, const int *b, int n)
+{
+  int i;
+  for ( i=0;i<n;i++) {
+    if (a[i]!=b[i])
+      break;
+  }
+  return (i==n);
+}
+static bool sameValues(const CoinModel * a, const CoinModel *b, bool doRows)
+{
+  int i=0;
+  int n=0;
+  if (doRows) {
+    n = a->numberRows();
+    for ( i=0;i<n;i++) {
+      const char * aName = a->getRowName(i);
+      const char * bName = b->getRowName(i);
+      bool good=true;
+      if (aName) {
+	if (!bName||strcmp(aName,bName))
+	  good=false;
+      } else if (bName) {
+	good=false;
+      }
+      if (!good)
+	break;
+    }
+  } else {
+    n = a->numberColumns();
+    for ( i=0;i<n;i++) {
+      const char * aName = a->getColumnName(i);
+      const char * bName = b->getColumnName(i);
+      bool good=true;
+      if (aName) {
+	if (!bName||strcmp(aName,bName))
+	  good=false;
+      } else if (bName) {
+	good=false;
+      }
+      if (!good)
+	break;
+    }
+  }
+  return (i==n);
+}
+// Add a row block name and number of rows
+int
+CoinStructuredModel::addRowBlock(int numberRows,const std::string &name) 
+{
+  int iRowBlock;
+  for (iRowBlock=0;iRowBlock<numberRowBlocks_;iRowBlock++) {
+    if (name==rowBlockNames_[iRowBlock])
+      break;
+  }
+  if (iRowBlock==numberRowBlocks_) {
+    rowBlockNames_.push_back(name);
+    numberRowBlocks_++;
+    numberRows_ += numberRows;
+  }
+  return iRowBlock;
+}
+// Return a row block index given a row block name
+int 
+CoinStructuredModel::rowBlock(const std::string &name) const
+{
+  int iRowBlock;
+  for (iRowBlock=0;iRowBlock<numberRowBlocks_;iRowBlock++) {
+    if (name==rowBlockNames_[iRowBlock])
+      break;
+  }
+  if (iRowBlock==numberRowBlocks_) 
+    iRowBlock=-1;
+  return iRowBlock;
+}
+// Add a column block name and number of columns
+int
+CoinStructuredModel::addColumnBlock(int numberColumns,const std::string &name) 
+{
+  int iColumnBlock;
+  for (iColumnBlock=0;iColumnBlock<numberColumnBlocks_;iColumnBlock++) {
+    if (name==columnBlockNames_[iColumnBlock])
+      break;
+  }
+  if (iColumnBlock==numberColumnBlocks_) {
+    columnBlockNames_.push_back(name);
+    numberColumnBlocks_++;
+    numberColumns_ += numberColumns;
+  }
+  return iColumnBlock;
+}
+// Return a column block index given a column block name
+int 
+CoinStructuredModel::columnBlock(const std::string &name) const
+{
+  int iColumnBlock;
+  for (iColumnBlock=0;iColumnBlock<numberColumnBlocks_;iColumnBlock++) {
+    if (name==columnBlockNames_[iColumnBlock])
+      break;
+  }
+  if (iColumnBlock==numberColumnBlocks_) 
+    iColumnBlock=-1;
+  return iColumnBlock;
+}
+// Return number of elements
+CoinBigIndex 
+CoinStructuredModel::numberElements() const
+{
+  CoinBigIndex numberElements=0;
+  for (int iBlock=0;iBlock<numberElementBlocks_;iBlock++) {
+    numberElements += blocks_[iBlock]->numberElements();
+  }
+  return numberElements;
+}
+// Return i'th block as CoinModel (or NULL)
+CoinModel * 
+CoinStructuredModel::coinBlock(int i) const
+{ 
+  CoinModel * block = dynamic_cast<CoinModel *>(blocks_[i]);
+  if (block) 
+    return block;
+  else if (coinModelBlocks_)
+    return coinModelBlocks_[i];
+  else
+    return NULL;
+}
+
+/* Return block as a CoinModel block
+   and fill in info structure and update counts
+*/
+CoinModel *  
+CoinStructuredModel::coinModelBlock(CoinModelBlockInfo & info)
+{
+  // CoinStructuredModel
+  int numberRows=this->numberRows();
+  int numberColumns =this-> numberColumns();
+  int numberRowBlocks=this->numberRowBlocks();
+  int numberColumnBlocks =this-> numberColumnBlocks();
+  int numberElementBlocks =this-> numberElementBlocks();
+  CoinBigIndex numberElements=this->numberElements();
+  // See what is needed
+  double * rowLower = NULL;
+  double * rowUpper = NULL;
+  double * columnLower = NULL;
+  double * columnUpper = NULL;
+  double * objective = NULL;
+  int * integerType = NULL;
+  info = CoinModelBlockInfo();
+  CoinModel ** blocks = new CoinModel * [numberElementBlocks];
+  for (int iBlock=0;iBlock<numberElementBlocks;iBlock++) {
+    CoinModelBlockInfo thisInfo=blockType_[iBlock];
+    CoinStructuredModel * subModel = dynamic_cast<CoinStructuredModel *>(blocks_[iBlock]);
+    CoinModel * thisBlock;
+    if (subModel) {
+      thisBlock = subModel->coinModelBlock(thisInfo);
+      fillInfo(thisInfo,subModel);
+      setCoinModel(thisBlock,iBlock);
+    } else {
+      thisBlock = dynamic_cast<CoinModel *>(blocks_[iBlock]);
+      assert (thisBlock);
+      fillInfo(thisInfo,thisBlock);
+    }
+    blocks[iBlock]=thisBlock;
+    if (thisInfo.rhs&&!info.rhs) {
+      info.rhs=1;
+      rowLower = new double [numberRows];
+      rowUpper = new double [numberRows];
+      CoinFillN(rowLower,numberRows,-COIN_DBL_MAX);
+      CoinFillN(rowUpper,numberRows,COIN_DBL_MAX);
+    }
+    if (thisInfo.bounds&&!info.bounds) {
+      info.bounds=1;
+      columnLower = new double [numberColumns];
+      columnUpper = new double [numberColumns];
+      objective = new double [numberColumns];
+      CoinFillN(columnLower,numberColumns,0.0);
+      CoinFillN(columnUpper,numberColumns,COIN_DBL_MAX);
+      CoinFillN(objective,numberColumns,0.0);
+    }
+    if (thisInfo.integer&&!info.integer) {
+      info.integer=1;
+      integerType = new int [numberColumns];
+      CoinFillN(integerType,numberColumns,0);
+    }
+    if (thisInfo.rowName&&!info.rowName) {
+      info.rowName=1;
+    }
+    if (thisInfo.columnName&&!info.columnName) {
+      info.columnName=1;
+    }
+  }
+  // Space for elements
+  int * row = new int[numberElements];
+  int * column = new int[numberElements];
+  double * element = new double[numberElements];
+  numberElements=0;
+  // Bases for blocks
+  int * rowBase = new int[numberRowBlocks];
+  CoinFillN(rowBase,numberRowBlocks,-1);
+  CoinModelBlockInfo * rowBlockInfo = 
+    new CoinModelBlockInfo [numberRowBlocks];
+  int * columnBase = new int[numberColumnBlocks];
+  CoinFillN(columnBase,numberColumnBlocks,-1);
+  CoinModelBlockInfo * columnBlockInfo = 
+    new CoinModelBlockInfo [numberColumnBlocks];
+  for (int iBlock=0;iBlock<numberElementBlocks;iBlock++) {
+    int iRowBlock = rowBlock(blocks[iBlock]->getRowBlock());
+    assert (iRowBlock>=0&&iRowBlock<numberRowBlocks);
+    if (rowBase[iRowBlock]==-1) 
+      rowBase[iRowBlock]=blocks[iBlock]->numberRows();
+    else
+      assert (rowBase[iRowBlock]==blocks[iBlock]->numberRows());
+    int iColumnBlock = columnBlock(blocks[iBlock]->getColumnBlock());
+    assert (iColumnBlock>=0&&iColumnBlock<numberColumnBlocks);
+    if (columnBase[iColumnBlock]==-1) 
+      columnBase[iColumnBlock]=blocks[iBlock]->numberColumns();
+    else
+      assert (columnBase[iColumnBlock]==blocks[iBlock]->numberColumns());
+  }
+  int n=0;
+  for (int iBlock=0;iBlock<numberRowBlocks;iBlock++) {
+    int k = rowBase[iBlock];
+    rowBase[iBlock]=n;
+    assert (k>=0);
+    n+=k;
+  }
+  assert (n==numberRows);
+  n=0;
+  for (int iBlock=0;iBlock<numberColumnBlocks;iBlock++) {
+    int k = columnBase[iBlock];
+    columnBase[iBlock]=n;
+    assert (k>=0);
+    n+=k;
+  }
+  assert (n==numberColumns);
+  for (int iBlock=0;iBlock<numberElementBlocks;iBlock++) {
+    CoinModelBlockInfo thisInfo=blockType_[iBlock];
+    CoinModel * thisBlock = blocks[iBlock];
+    int iRowBlock = rowBlock(blocks[iBlock]->getRowBlock());
+    int iRowBase = rowBase[iRowBlock];
+    int nRows = thisBlock->numberRows();
+    // could check if identical before error
+    if (thisInfo.rhs) { 
+      assert (!rowBlockInfo[iRowBlock].rhs);
+      rowBlockInfo[iRowBlock].rhs=1;
+      memcpy(rowLower+iRowBase,thisBlock->rowLowerArray(),
+	     nRows*sizeof(double));
+      memcpy(rowUpper+iRowBase,thisBlock->rowUpperArray(),
+	     nRows*sizeof(double));
+    }
+    int iColumnBlock = columnBlock(blocks[iBlock]->getColumnBlock());
+    int iColumnBase = columnBase[iColumnBlock];
+    int nColumns = thisBlock->numberColumns();
+    if (thisInfo.bounds) {
+      assert (!columnBlockInfo[iColumnBlock].bounds);
+      columnBlockInfo[iColumnBlock].bounds=1;
+      memcpy(columnLower+iColumnBase,thisBlock->columnLowerArray(),
+	     nColumns*sizeof(double));
+      memcpy(columnUpper+iColumnBase,thisBlock->columnUpperArray(),
+	     nColumns*sizeof(double));
+      memcpy(objective+iColumnBase,thisBlock->objectiveArray(),
+	     nColumns*sizeof(double));
+    }
+    if (thisInfo.integer) {
+      assert (!columnBlockInfo[iColumnBlock].integer);
+      columnBlockInfo[iColumnBlock].integer=1;
+      memcpy(integerType+iColumnBase,thisBlock->integerTypeArray(),
+	     nColumns*sizeof(int));
+    }
+    const CoinPackedMatrix * elementBlock = thisBlock->packedMatrix();
+    // get matrix data pointers
+    const int * row2 = elementBlock->getIndices();
+    const CoinBigIndex * columnStart = elementBlock->getVectorStarts();
+    const double * elementByColumn = elementBlock->getElements();
+    const int * columnLength = elementBlock->getVectorLengths(); 
+    int n = elementBlock->getNumCols();
+    assert (elementBlock->isColOrdered());
+    for (int iColumn=0;iColumn<n;iColumn++) {
+      CoinBigIndex j;
+      int jColumn = iColumn+iColumnBase;
+      for (j=columnStart[iColumn];
+	   j<columnStart[iColumn]+columnLength[iColumn];j++) {
+	row[numberElements]=row2[j]+iRowBase;
+	column[numberElements]=jColumn;
+	element[numberElements++]=elementByColumn[j];
+	}
+    }
+  }
+  delete [] rowBlockInfo;
+  delete [] columnBlockInfo;
+  CoinPackedMatrix matrix(true,row,column,element,numberElements);
+  if (numberElements)
+    info.matrix=1;
+  delete [] row;
+  delete [] column;
+  delete [] element;
+  CoinModel * block = new CoinModel(numberRows, numberColumns,
+			&matrix,
+			rowLower, rowUpper, 
+			columnLower, columnUpper, objective);
+  delete [] rowLower;
+  delete [] rowUpper;
+  delete [] columnLower;
+  delete [] columnUpper;
+  delete [] objective;
+  // Do integers if wanted
+  if (integerType) {
+    for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+      block->setColumnIsInteger(iColumn,integerType[iColumn]!=0);
+    }
+  }
+  delete [] integerType;
+  block->setObjectiveOffset(objectiveOffset());
+  if (info.rowName||info.columnName) {
+    for (int iBlock=0;iBlock<numberElementBlocks;iBlock++) {
+      CoinModelBlockInfo thisInfo;
+      CoinModel * thisBlock = blocks[iBlock];
+      int iRowBlock = rowBlock(thisBlock->getRowBlock());
+      int iRowBase = rowBase[iRowBlock];
+      if (thisInfo.rowName) {
+	int numberItems = thisBlock->rowNames()->numberItems();
+	assert( thisBlock->numberRows()>=numberItems);
+	if (numberItems) {
+	  const char *const * rowNames=thisBlock->rowNames()->names();
+	  for (int i=0;i<numberItems;i++) {
+	    std::string name = rowNames[i];
+	    block->setRowName(i+iRowBase,name.c_str());
+	  }
+	}
+      }
+      int iColumnBlock = columnBlock(thisBlock->getColumnBlock());
+      int iColumnBase = columnBase[iColumnBlock];
+      if (thisInfo.columnName) {
+	int numberItems = thisBlock->columnNames()->numberItems();
+	assert( thisBlock->numberColumns()>=numberItems);
+	if (numberItems) {
+	  const char *const * columnNames=thisBlock->columnNames()->names();
+	  for (int i=0;i<numberItems;i++) {
+	    std::string name = columnNames[i];
+	    block->setColumnName(i+iColumnBase,name.c_str());
+	  }
+	}
+      }
+    }
+  }
+  delete [] rowBase;
+  delete [] columnBase;
+  for (int iBlock=0;iBlock<numberElementBlocks;iBlock++) {
+    if (static_cast<CoinBaseModel *> (blocks[iBlock])!=
+	static_cast<CoinBaseModel *> (blocks_[iBlock]))
+      delete blocks[iBlock];
+  }
+  delete [] blocks;
+  return block;
+}
+// Sets given block into coinModelBlocks_
+void 
+CoinStructuredModel::setCoinModel(CoinModel * block, int iBlock)
+{
+ if (!coinModelBlocks_) {
+    coinModelBlocks_ = new CoinModel * [maximumElementBlocks_];
+    CoinZeroN(coinModelBlocks_,maximumElementBlocks_);
+  }
+  delete coinModelBlocks_[iBlock];
+  coinModelBlocks_[iBlock]=block;
+ }
+// Refresh info in blockType_
+void 
+CoinStructuredModel::refresh(int iBlock)
+{
+  fillInfo(blockType_[iBlock],coinBlock(iBlock));
+}
+/* Fill in info structure and update counts
+   Returns number of inconsistencies on border
+*/
+int 
+CoinStructuredModel::fillInfo(CoinModelBlockInfo & info,
+			      const CoinModel * block) 
+{
+  int whatsSet = block->whatIsSet();
+  info.matrix = static_cast<char>(((whatsSet&1)!=0) ? 1 : 0);
+  info.rhs = static_cast<char>(((whatsSet&2)!=0) ? 1 : 0);
+  info.rowName = static_cast<char>(((whatsSet&4)!=0) ? 1 : 0);
+  info.integer = static_cast<char>(((whatsSet&32)!=0) ? 1 : 0);
+  info.bounds = static_cast<char>(((whatsSet&8)!=0) ? 1 : 0);
+  info.columnName = static_cast<char>(((whatsSet&16)!=0) ? 1 : 0);
+  int numberRows = block->numberRows();
+  int numberColumns = block->numberColumns();
+  // Which block
+  int iRowBlock=addRowBlock(numberRows,block->getRowBlock());
+  info.rowBlock=iRowBlock;
+  int iColumnBlock=addColumnBlock(numberColumns,block->getColumnBlock());
+  info.columnBlock=iColumnBlock;
+  int numberErrors=0;
+  CoinModelBlockInfo sumInfo=blockType_[numberElementBlocks_-1];
+  int iRhs=(sumInfo.rhs) ? numberElementBlocks_-1 : -1;
+  int iRowName=(sumInfo.rowName) ? numberElementBlocks_-1 : -1;
+  int iBounds=(sumInfo.bounds) ? numberElementBlocks_-1 : -1;
+  int iColumnName=(sumInfo.columnName) ? numberElementBlocks_-1 : -1;
+  int iInteger=(sumInfo.integer) ? numberElementBlocks_-1 : -1;
+  for (int i=0;i<numberElementBlocks_-1;i++) {
+    if (iRowBlock==blockType_[i].rowBlock) {
+      if (numberRows!=blocks_[i]->numberRows())
+	numberErrors+=1000;
+      if (blockType_[i].rhs) {
+	if (iRhs<0) {
+	  iRhs=i;
+	} else {
+	  // check
+	  const double * a = static_cast<CoinModel *>(blocks_[iRhs])->rowLowerArray();
+	  const double * b = static_cast<CoinModel *>(blocks_[i])->rowLowerArray();
+	  if (!sameValues(a,b,numberRows))
+	    numberErrors++;
+	  a = static_cast<CoinModel *>(blocks_[iRhs])->rowUpperArray();
+	  b = static_cast<CoinModel *>(blocks_[i])->rowUpperArray();
+	  if (!sameValues(a,b,numberRows))
+	    numberErrors++;
+	}
+      }
+      if (blockType_[i].rowName) {
+	if (iRowName<0) {
+	  iRowName=i;
+	} else {
+	  // check
+	  if (!sameValues(static_cast<CoinModel *>(blocks_[iRowName]),
+			  static_cast<CoinModel *>(blocks_[i]),true))
+	    numberErrors++;
+	}
+      }
+    }
+    if (iColumnBlock==blockType_[i].columnBlock) {
+      if (numberColumns!=blocks_[i]->numberColumns())
+	numberErrors+=1000;
+      if (blockType_[i].bounds) {
+	if (iBounds<0) {
+	  iBounds=i;
+	} else {
+	  // check
+	  const double * a = static_cast<CoinModel *>(blocks_[iBounds])->columnLowerArray();
+	  const double * b = static_cast<CoinModel *>(blocks_[i])->columnLowerArray();
+	  if (!sameValues(a,b,numberColumns))
+	    numberErrors++;
+	  a = static_cast<CoinModel *>(blocks_[iBounds])->columnUpperArray();
+	  b = static_cast<CoinModel *>(blocks_[i])->columnUpperArray();
+	  if (!sameValues(a,b,numberColumns))
+	    numberErrors++;
+	  a = static_cast<CoinModel *>(blocks_[iBounds])->objectiveArray();
+	  b = static_cast<CoinModel *>(blocks_[i])->objectiveArray();
+	  if (!sameValues(a,b,numberColumns))
+	    numberErrors++;
+	}
+      }
+      if (blockType_[i].columnName) {
+	if (iColumnName<0) {
+	  iColumnName=i;
+	} else {
+	  // check
+	  if (!sameValues(static_cast<CoinModel *>(blocks_[iColumnName]),
+			  static_cast<CoinModel *>(blocks_[i]),false))
+	    numberErrors++;
+	}
+      }
+      if (blockType_[i].integer) {
+	if (iInteger<0) {
+	  iInteger=i;
+	} else {
+	  // check
+	  const int * a = static_cast<CoinModel *>(blocks_[iInteger])->integerTypeArray();
+	  const int * b = static_cast<CoinModel *>(blocks_[i])->integerTypeArray();
+	  if (!sameValues(a,b,numberColumns))
+	    numberErrors++;
+	}
+      }
+    }
+  }
+  return numberErrors;
+}
+/* Fill in info structure and update counts
+*/
+void
+CoinStructuredModel::fillInfo(CoinModelBlockInfo & info,
+			      const CoinStructuredModel * block) 
+{
+  int numberRows = block->numberRows();
+  int numberColumns = block->numberColumns();
+  // Which block
+  int iRowBlock=addRowBlock(numberRows,block->rowBlockName_);
+  info.rowBlock=iRowBlock;
+  int iColumnBlock=addColumnBlock(numberColumns,block->columnBlockName_);
+  info.columnBlock=iColumnBlock;
+}
+/* add a block from a CoinModel without names*/
+int 
+CoinStructuredModel::addBlock(const std::string & rowBlock,
+			      const std::string & columnBlock,
+			      const CoinBaseModel & block)
+{
+  CoinBaseModel * block2 = block.clone();
+  return addBlock(rowBlock,columnBlock,block2);
+}
+/* add a block using names 
+ */
+int 
+CoinStructuredModel::addBlock(const std::string & rowBlock,
+			      const std::string & columnBlock,
+			      const CoinPackedMatrix & matrix,
+			      const double * rowLower, const double * rowUpper,
+			      const double * columnLower, const double * columnUpper,
+			      const double * objective)
+{
+  CoinModel * block = new CoinModel();
+  block->loadBlock(matrix,columnLower,columnUpper,objective,
+		   rowLower,rowUpper);
+  return addBlock(rowBlock,columnBlock,block);
+}
+/* add a block from a CoinModel without names*/
+int 
+CoinStructuredModel::addBlock(const std::string & rowBlock,
+			      const std::string & columnBlock,
+			      CoinBaseModel * block)
+{
+  if (numberElementBlocks_==maximumElementBlocks_) {
+    maximumElementBlocks_ = 3*(maximumElementBlocks_+10)/2;
+    CoinBaseModel ** temp = new CoinBaseModel * [maximumElementBlocks_];
+    memcpy(temp,blocks_,numberElementBlocks_*sizeof(CoinBaseModel *));
+    delete [] blocks_;
+    blocks_ = temp;
+    CoinModelBlockInfo * temp2 = new CoinModelBlockInfo [maximumElementBlocks_];
+    memcpy(temp2,blockType_,numberElementBlocks_*sizeof(CoinModelBlockInfo));
+    delete [] blockType_;
+    blockType_ = temp2;
+    if (coinModelBlocks_) {
+      CoinModel ** temp = new CoinModel * [maximumElementBlocks_];
+      CoinZeroN(temp,maximumElementBlocks_);
+      memcpy(temp,coinModelBlocks_,numberElementBlocks_*sizeof(CoinModel *));
+      delete [] coinModelBlocks_;
+      coinModelBlocks_ = temp;
+    }
+  }
+  blocks_[numberElementBlocks_++]=block;
+  block->setRowBlock(rowBlock);
+  block->setColumnBlock(columnBlock);
+  int numberErrors=0;
+  CoinModel * coinBlock = dynamic_cast<CoinModel *>(block);
+  if (coinBlock) {
+    // Convert matrix
+    if (coinBlock->type()!=3)
+      coinBlock->convertMatrix();
+    numberErrors=fillInfo(blockType_[numberElementBlocks_-1],coinBlock);
+  } else {
+    CoinStructuredModel * subModel = dynamic_cast<CoinStructuredModel *>(block);
+    assert (subModel);
+    CoinModel * blockX = 
+      subModel->coinModelBlock(blockType_[numberElementBlocks_-1]);
+    fillInfo(blockType_[numberElementBlocks_-1],subModel);
+    setCoinModel(blockX,numberElementBlocks_-1);
+  }
+  return numberErrors;
+}
+
+/* add a block from a CoinModel with names*/
+int
+CoinStructuredModel::addBlock(const CoinBaseModel & block)
+{
+  
+  //inline const std::string & getRowBlock() const
+  //abort();
+  return addBlock(block.getRowBlock(),block.getColumnBlock(),
+		  block);
+}
+/* Decompose a model specified as arrays + CoinPackedMatrix
+   1 - try D-W
+   2 - try Benders
+   3 - try Staircase
+   Returns number of blocks or zero if no structure
+*/
+int 
+CoinStructuredModel::decompose(const CoinPackedMatrix & matrix,
+			       const double * rowLower, const double * rowUpper,
+			       const double * columnLower, const double * columnUpper,
+			       const double * objective, int type,int maxBlocks,
+			       double objectiveOffset)
+{
+  setObjectiveOffset(objectiveOffset);
+  int numberBlocks=0;
+  if (type==1) {
+    // get row copy
+    CoinPackedMatrix rowCopy = matrix;
+    rowCopy.reverseOrdering();
+    const int * row = matrix.getIndices();
+    const int * columnLength = matrix.getVectorLengths();
+    const CoinBigIndex * columnStart = matrix.getVectorStarts();
+    //const double * elementByColumn = matrix.getElements();
+    const int * column = rowCopy.getIndices();
+    const int * rowLength = rowCopy.getVectorLengths();
+    const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+    //const double * elementByRow = rowCopy.getElements();
+    int numberRows = matrix.getNumRows();
+    int * rowBlock = new int[numberRows+1];
+    int iRow;
+    // Row counts (maybe look at long rows for master)
+    CoinZeroN(rowBlock,numberRows+1);
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int length = rowLength[iRow];
+      rowBlock[length]++;
+    }
+    for (iRow=0;iRow<numberRows+1;iRow++) {
+      if (rowBlock[iRow])
+	printf("%d rows have %d elements\n",rowBlock[iRow],iRow);
+    }
+    bool newWay=true;
+    // to say if column looked at
+    int numberColumns = matrix.getNumCols();
+    int * columnBlock = new int[numberColumns];
+    int iColumn;
+    int * whichRow = new int [numberRows];
+    int * whichColumn = new int [numberColumns];
+    int * stack = new int [numberRows];
+    if (newWay) {
+      //double best2[3]={COIN_DBL_MAX,COIN_DBL_MAX,COIN_DBL_MAX};
+      double best2[3]={0.0,0.0,0.0};
+      int row2[3]={-1,-1,-1};
+      // try forward and backward and sorted
+      for (int iWay=0;iWay<3;iWay++) {
+	if (iWay==0) {
+	  // forwards
+	  for (int i=0;i<numberRows;i++)
+	    stack[i]=i;
+	} else if (iWay==1) {
+	  // backwards
+	  for (int i=0;i<numberRows;i++)
+	    stack[i]=numberRows-1-i;
+	} else {
+	  // sparsest first
+	  for (int i=0;i<numberRows;i++) {
+	    rowBlock[i]=rowLength[i];
+	    stack[i]=i;
+	  }
+	  CoinSort_2(rowBlock,rowBlock+numberRows,stack);
+	}
+	CoinFillN(rowBlock,numberRows,-1);
+	rowBlock[numberRows]=0;
+	CoinFillN(whichRow,numberRows,-1);
+	CoinFillN(columnBlock,numberColumns,-1);
+	CoinFillN(whichColumn,numberColumns,-1);
+	int numberMarkedColumns = 0;
+	numberBlocks=0;
+	int bestRow = -1;
+	int maximumInBlock = 0;
+	int rowsDone=0;
+	int checkAfterRows = (5*numberRows)/10+1;
+#define OSL_WAY
+#ifdef OSL_WAY
+	double best = COIN_DBL_MAX;
+	int bestRowsDone=-1;
+#else
+	double best = 0.0; //COIN_DBL_MAX;
+#endif
+	int numberGoodBlocks=0;
+	
+	for (int kRow=0;kRow<numberRows;kRow++) {
+	  iRow = stack[kRow];
+	  CoinBigIndex start = rowStart[iRow];
+	  CoinBigIndex end = start+rowLength[iRow];
+	  int iBlock=-1;
+	  for (CoinBigIndex j=start;j<end;j++) {
+	    int iColumn = column[j];
+	    if (columnBlock[iColumn]>=0) {
+	      // already marked
+	      if (iBlock<0) {
+		iBlock = columnBlock[iColumn];
+	      } else if (iBlock != columnBlock[iColumn]) {
+		// join two blocks
+		int jBlock = columnBlock[iColumn];
+		numberGoodBlocks--;
+		// Increase count of iBlock
+		rowBlock[iBlock] += rowBlock[jBlock];
+		rowBlock[jBlock]=0;
+		// First column of block jBlock
+		int jColumn = whichRow[jBlock];
+		while (jColumn>=0) {
+		  columnBlock[jColumn]=iBlock;
+		  iColumn = jColumn;
+		  jColumn = whichColumn[jColumn];
+		}
+		whichColumn[iColumn] = whichRow[iBlock];
+		whichRow[iBlock] = whichRow[jBlock];
+		whichRow[jBlock]=-1;
+	      }
+	    }
+	  }
+	  int n=end-start;
+	  // If not in block - then start one
+	  if (iBlock<0) {
+	    // unless null row
+	    if (n) {
+	      iBlock = numberBlocks;
+	      numberBlocks++;
+	      numberGoodBlocks++;
+	      int jColumn = column[start];
+	      columnBlock[jColumn]=iBlock;
+	      whichRow[iBlock]=jColumn;
+	      numberMarkedColumns += n;
+	      rowBlock[iBlock] = n;
+	      for (CoinBigIndex j=start+1;j<end;j++) {
+		int iColumn = column[j];
+		columnBlock[iColumn]=iBlock;
+		whichColumn[jColumn]=iColumn;
+		jColumn=iColumn;
+	      }
+	    } else {
+	      rowBlock[numberRows]++;
+	    }
+	  } else {
+	    // add all to this block if not already in
+	    int jColumn = whichRow[iBlock];
+	    for (CoinBigIndex j=start;j<end;j++) {
+	      int iColumn = column[j];
+	      if (columnBlock[iColumn]<0) {
+		numberMarkedColumns++;
+		rowBlock[iBlock]++;
+		columnBlock[iColumn]=iBlock;
+		whichColumn[iColumn]=jColumn;
+		jColumn=iColumn;
+	      }
+	    }
+	    whichRow[iBlock]=jColumn;
+	  }
+#if 0
+	  {
+	    int nn=0;
+	    int * temp = new int [numberRows];
+	    CoinZeroN(temp,numberRows);
+	    for (int i=0;i<numberColumns;i++) {
+	      int iBlock = columnBlock[i];
+	      if (iBlock>=0) {
+		nn++;
+		assert (iBlock<numberBlocks);
+		temp[iBlock]++;
+	      }
+	    }
+	    for (int i=0;i<numberBlocks;i++)
+	      assert (temp[i]==rowBlock[i]);
+	    assert (nn==numberMarkedColumns);
+	    for (int i=0;i<numberBlocks;i++) {
+	      // First column of block i
+	      int jColumn = whichRow[i];
+	      int n=0;
+	      while (jColumn>=0) {
+		n++;
+		jColumn = whichColumn[jColumn];
+	      }
+	      assert (n==temp[i]);
+	    }
+	    delete [] temp;
+	  }
+#endif
+	  rowsDone++;
+	  if (iBlock>=0) 
+	    maximumInBlock = CoinMax(maximumInBlock,rowBlock[iBlock]);
+	  if (rowsDone>=checkAfterRows) {
+	    assert (numberGoodBlocks>0);
+	    double averageSize = static_cast<double>(numberMarkedColumns)/
+	      static_cast<double>(numberGoodBlocks);
+#ifndef OSL_WAY
+	    double notionalBlocks = static_cast<double>(numberMarkedColumns)/
+	      averageSize;
+	    if (maximumInBlock<3*averageSize&&numberGoodBlocks>2) {
+	      if(best*(numberRows-rowsDone) < notionalBlocks) {
+		best = notionalBlocks/
+		  static_cast<double> (numberRows-rowsDone); 
+		bestRow = kRow;
+	      }
+	    }
+#else
+	    if (maximumInBlock*10<numberColumns*11&&numberGoodBlocks>1) {
+	      double test = maximumInBlock + 0.0*averageSize;
+	      if(best*static_cast<double>(rowsDone) > test) {
+		best = test/static_cast<double> (rowsDone); 
+		bestRow = kRow;
+		bestRowsDone=rowsDone;
+	      }
+	    }
+#endif
+	  }	      
+	}
+#ifndef OSL_WAY
+	best2[iWay]=best;
+#else
+	if (bestRowsDone<numberRows)
+	  best2[iWay]=-(numberRows-bestRowsDone);
+	else
+	  best2[iWay]=-numberRows;
+#endif
+	row2[iWay]=bestRow;
+      }
+      // mark rows
+      int nMaster;
+      CoinFillN(rowBlock,numberRows,-2);
+      if (best2[2]<best2[0]||best2[2]<best2[1]) {
+	int iRow1;
+	int iRow2;
+	if (best2[0]>best2[1]) {
+	  // Bottom rows in master
+	  iRow1=row2[0]+1;
+	  iRow2=numberRows;
+	} else {
+	  // Top rows in master
+	  iRow1=0;
+	  iRow2=numberRows-row2[1];
+	}
+	nMaster = iRow2-iRow1;
+	CoinFillN(rowBlock+iRow1,nMaster,-1);
+      } else {
+	// sorted
+	// Bottom rows in master (in order)
+	int iRow1=row2[2]+1;
+	nMaster = numberRows-iRow1;
+	for (int i=iRow1;i<numberRows;i++)
+	  rowBlock[stack[i]]=-1;
+      }
+      if (nMaster*2>numberRows) {
+	printf("%d rows out of %d would be in master - no good\n",
+	       nMaster,numberRows);
+	delete [] rowBlock;
+	delete [] columnBlock;
+	delete [] whichRow;
+	delete [] whichColumn;
+	delete [] stack;
+	CoinModel model(numberRows,numberColumns,&matrix, rowLower, rowUpper,
+			columnLower,columnUpper,objective);
+	model.setObjectiveOffset(objectiveOffset);
+	addBlock("row_master","column_master",model);
+	return 0;
+      }
+    } else {
+      for (iRow=0;iRow<numberRows;iRow++)
+	rowBlock[iRow]=-2;
+      // these are master rows
+      if (numberRows==105127) {
+	// ken-18
+	for (iRow=104976;iRow<numberRows;iRow++)
+	  rowBlock[iRow]=-1;
+      } else if (numberRows==2426) {
+	// ken-7
+	for (iRow=2401;iRow<numberRows;iRow++)
+	  rowBlock[iRow]=-1;
+      } else if (numberRows==810) {
+	for (iRow=81;iRow<84;iRow++)
+	  rowBlock[iRow]=-1;
+      } else if (numberRows==5418) {
+	for (iRow=564;iRow<603;iRow++)
+	  rowBlock[iRow]=-1;
+      } else if (numberRows==10280) {
+	// osa-60
+	for (iRow=10198;iRow<10280;iRow++)
+	  rowBlock[iRow]=-1;
+      } else if (numberRows==1503) {
+	// degen3
+	for (iRow=0;iRow<561;iRow++)
+	  rowBlock[iRow]=-1;
+      } else if (numberRows==929) {
+	// czprob
+	for (iRow=0;iRow<39;iRow++)
+	  rowBlock[iRow]=-1;
+      } else if (numberRows==33874) {
+	// pds-20
+	for (iRow=31427;iRow<33874;iRow++)
+	  rowBlock[iRow]=-1;
+      } else if (numberRows==24902) {
+	// allgrade
+	int kRow=818;
+	for (iRow=0;iRow<kRow;iRow++)
+	  rowBlock[iRow]=-1;
+      }
+    }
+    numberBlocks=0;
+    CoinFillN(columnBlock,numberColumns,-2);
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      int kstart = columnStart[iColumn];
+      int kend = columnStart[iColumn]+columnLength[iColumn];
+      if (columnBlock[iColumn]==-2) {
+	// column not allocated
+	int j;
+	int nstack=0;
+	for (j=kstart;j<kend;j++) {
+	  int iRow= row[j];
+	  if (rowBlock[iRow]!=-1) {
+	    assert(rowBlock[iRow]==-2);
+	    rowBlock[iRow]=numberBlocks; // mark
+	    stack[nstack++] = iRow;
+	  }
+	}
+	if (nstack) {
+	  // new block - put all connected in
+	  numberBlocks++;
+	  columnBlock[iColumn]=numberBlocks-1;
+	  while (nstack) {
+	    int iRow = stack[--nstack];
+	    int k;
+	    for (k=rowStart[iRow];k<rowStart[iRow]+rowLength[iRow];k++) {
+	      int iColumn = column[k];
+	      int kkstart = columnStart[iColumn];
+	      int kkend = kkstart + columnLength[iColumn];
+	      if (columnBlock[iColumn]==-2) {
+		columnBlock[iColumn]=numberBlocks-1; // mark
+		// column not allocated
+		int jj;
+		for (jj=kkstart;jj<kkend;jj++) {
+		  int jRow= row[jj];
+		  if (rowBlock[jRow]==-2) {
+		    rowBlock[jRow]=numberBlocks-1;
+		    stack[nstack++]=jRow;
+		  }
+		}
+	      } else {
+		assert (columnBlock[iColumn]==numberBlocks-1);
+	      }
+	    }
+	  }
+	} else {
+	  // Only in master
+	  columnBlock[iColumn]=-1;
+	}
+      }
+    }
+    delete [] stack;
+    int numberMasterRows=0;
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int iBlock = rowBlock[iRow];
+      if (iBlock==-1)
+	numberMasterRows++;
+    }
+    int numberMasterColumns=0;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      int iBlock = columnBlock[iColumn];
+      if (iBlock==-1)
+	numberMasterColumns++;
+    }
+    if (numberBlocks<=maxBlocks)
+      printf("%d blocks found - %d rows, %d columns in master\n",
+	     numberBlocks,numberMasterRows,numberMasterColumns);
+    else
+      printf("%d blocks found (reduced to %d) - %d rows, %d columns in master\n",
+	     numberBlocks,maxBlocks,numberMasterRows,numberMasterColumns);
+    if (numberBlocks) {
+      if (numberBlocks>maxBlocks) {
+	int iBlock;
+	for (iRow=0;iRow<numberRows;iRow++) {
+	  iBlock = rowBlock[iRow];
+	  if (iBlock>=0)
+	    rowBlock[iRow] = iBlock%maxBlocks;
+	}
+	for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	  iBlock = columnBlock[iColumn];
+	  if (iBlock>=0)
+	    columnBlock[iColumn] = iBlock%maxBlocks;
+	}
+	numberBlocks=maxBlocks;
+      }
+    }
+    // make up problems
+    // Create all sub problems
+    // Space for creating
+    double * obj = new double [numberColumns];
+    double * columnLo = new double [numberColumns];
+    double * columnUp = new double [numberColumns];
+    double * rowLo = new double [numberRows];
+    double * rowUp = new double [numberRows];
+    // Counts
+    int * rowCount = reinterpret_cast<int *>(rowLo);
+    CoinZeroN(rowCount,numberBlocks);
+    for (int i=0;i<numberRows;i++) {
+      int iBlock=rowBlock[i];
+      if (iBlock>=0)
+	rowCount[iBlock]++;
+    }
+    // allocate empty rows
+    for (int i=0;i<numberRows;i++) {
+      int iBlock=rowBlock[i];
+      if (iBlock==-2) {
+	// find block with smallest count
+	int iSmall=-1;
+	int smallest = numberRows;
+	for (int j=0;j<numberBlocks;j++) {
+	  if (rowCount[j]<smallest) {
+	    iSmall=j;
+	    smallest=rowCount[j];
+	  }
+	}
+	rowBlock[i]=iSmall;
+	rowCount[iSmall]++;
+      }
+    }
+    int * columnCount = reinterpret_cast<int *>(rowUp);
+    CoinZeroN(columnCount,numberBlocks);
+    for (int i=0;i<numberColumns;i++) {
+      int iBlock=columnBlock[i];
+      if (iBlock>=0)
+	columnCount[iBlock]++;
+    }
+    int maximumSize=0;
+    for (int i=0;i<numberBlocks;i++) {
+      printf("Block %d has %d rows and %d columns\n",i,
+	     rowCount[i],columnCount[i]);
+      int k=2*rowCount[i]+columnCount[i];
+      maximumSize = CoinMax(maximumSize,k);
+    }
+    if (maximumSize*10>4*(2*numberRows+numberColumns)) {
+      // No good
+      printf("Doesn't look good\n");
+      delete [] rowBlock;
+      delete [] columnBlock;
+      delete [] whichRow;
+      delete [] whichColumn;
+      delete [] obj ; 
+      delete [] columnLo ; 
+      delete [] columnUp ; 
+      delete [] rowLo ; 
+      delete [] rowUp ; 
+      CoinModel model(numberRows,numberColumns,&matrix, rowLower, rowUpper,
+		      columnLower,columnUpper,objective);
+      model.setObjectiveOffset(objectiveOffset);
+      addBlock("row_master","column_master",model);
+      return 0;
+    }
+    // Name for master so at top
+    addRowBlock(numberMasterRows,"row_master");
+    // Arrays
+    // get full matrix
+    CoinPackedMatrix fullMatrix = matrix;
+    int numberRow2,numberColumn2;
+    int iBlock;
+    for (iBlock=0;iBlock<numberBlocks;iBlock++) {
+      char rowName[20];
+      sprintf(rowName,"row_%d",iBlock);
+      char columnName[20];
+      sprintf(columnName,"column_%d",iBlock);
+      numberRow2=0;
+      numberColumn2=0;
+      for (iRow=0;iRow<numberRows;iRow++) {
+	if (iBlock==rowBlock[iRow]) {
+	  rowLo[numberRow2]=rowLower[iRow];
+	  rowUp[numberRow2]=rowUpper[iRow];
+	  whichRow[numberRow2++]=iRow;
+	}
+      }
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	if (iBlock==columnBlock[iColumn]) {
+	  obj[numberColumn2]=objective[iColumn];
+	  columnLo[numberColumn2]=columnLower[iColumn];
+	  columnUp[numberColumn2]=columnUpper[iColumn];
+	  whichColumn[numberColumn2++]=iColumn;
+	}
+      }
+      // Diagonal block
+      CoinPackedMatrix mat(fullMatrix,
+			   numberRow2,whichRow,
+			   numberColumn2,whichColumn);
+      // make sure correct dimensions
+      mat.setDimensions(numberRow2,numberColumn2);
+      CoinModel * block = new CoinModel(numberRow2,numberColumn2,&mat,
+					rowLo,rowUp,NULL,NULL,NULL);
+      block->setOriginalIndices(whichRow,whichColumn);
+      addBlock(rowName,columnName,block); // takes ownership
+      // and top block
+      numberRow2=0;
+      // get top matrix
+      for (iRow=0;iRow<numberRows;iRow++) {
+	int iBlock = rowBlock[iRow];
+	if (iBlock==-1) {
+	  whichRow[numberRow2++]=iRow;
+	}
+      }
+      CoinPackedMatrix top(fullMatrix,
+			   numberRow2,whichRow,
+			   numberColumn2,whichColumn);
+      // make sure correct dimensions
+      top.setDimensions(numberRow2,numberColumn2);
+      block = new CoinModel(numberMasterRows,numberColumn2,&top,
+			    NULL,NULL,columnLo,columnUp,obj);
+      block->setOriginalIndices(whichRow,whichColumn);
+      addBlock("row_master",columnName,block); // takes ownership
+    }
+    // and master
+    numberRow2=0;
+    numberColumn2=0;
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int iBlock = rowBlock[iRow];
+      if (iBlock==-1) {
+	rowLo[numberRow2]=rowLower[iRow];
+	rowUp[numberRow2]=rowUpper[iRow];
+	whichRow[numberRow2++]=iRow;
+      }
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      int iBlock = columnBlock[iColumn];
+      if (iBlock<0) {
+	obj[numberColumn2]=objective[iColumn];
+	columnLo[numberColumn2]=columnLower[iColumn];
+	columnUp[numberColumn2]=columnUpper[iColumn];
+	whichColumn[numberColumn2++]=iColumn;
+      }
+    }
+    delete [] rowBlock;
+    delete [] columnBlock;
+    CoinPackedMatrix top(fullMatrix,
+			 numberRow2,whichRow,
+			 numberColumn2,whichColumn);
+    // make sure correct dimensions
+    top.setDimensions(numberRow2,numberColumn2);
+    CoinModel * block = new CoinModel(numberRow2,numberColumn2,&top,
+				      rowLo,rowUp,
+				      columnLo,columnUp,obj);
+    block->setOriginalIndices(whichRow,whichColumn);
+    addBlock("row_master","column_master",block); // takes ownership
+    delete [] whichRow;
+    delete [] whichColumn;
+    delete [] obj ; 
+    delete [] columnLo ; 
+    delete [] columnUp ; 
+    delete [] rowLo ; 
+    delete [] rowUp ; 
+  } else if (type==2) {
+    // get row copy
+    CoinPackedMatrix rowCopy = matrix;
+    rowCopy.reverseOrdering();
+    const int * row = matrix.getIndices();
+    const int * columnLength = matrix.getVectorLengths();
+    const CoinBigIndex * columnStart = matrix.getVectorStarts();
+    //const double * elementByColumn = matrix.getElements();
+    const int * column = rowCopy.getIndices();
+    const int * rowLength = rowCopy.getVectorLengths();
+    const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
+    //const double * elementByRow = rowCopy.getElements();
+    int numberColumns = matrix.getNumCols();
+    int * columnBlock = new int[numberColumns+1];
+    int iColumn;
+    // Column counts (maybe look at long columns for master)
+    CoinZeroN(columnBlock,numberColumns+1);
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      int length = columnLength[iColumn];
+      columnBlock[length]++;
+    }
+    for (iColumn=0;iColumn<numberColumns+1;iColumn++) {
+      if (columnBlock[iColumn])
+	printf("%d columns have %d elements\n",columnBlock[iColumn],iColumn);
+    }
+    bool newWay=false;
+    // to say if row looked at
+    int numberRows = matrix.getNumRows();
+    int * rowBlock = new int[numberRows];
+    int iRow;
+    int * whichRow = new int [numberRows];
+    int * whichColumn = new int [numberColumns];
+    int * stack = new int [numberColumns];
+    if (newWay) {
+      //double best2[3]={COIN_DBL_MAX,COIN_DBL_MAX,COIN_DBL_MAX};
+      double best2[3]={0.0,0.0,0.0};
+      int column2[3]={-1,-1,-1};
+      // try forward and backward and sorted
+      for (int iWay=0;iWay<3;iWay++) {
+	if (iWay==0) {
+	  // forwards
+	  for (int i=0;i<numberColumns;i++)
+	    stack[i]=i;
+	} else if (iWay==1) {
+	  // backwards
+	  for (int i=0;i<numberColumns;i++)
+	    stack[i]=numberColumns-1-i;
+	} else {
+	  // sparsest first
+	  for (int i=0;i<numberColumns;i++) {
+	    columnBlock[i]=columnLength[i];
+	    stack[i]=i;
+	  }
+	  CoinSort_2(columnBlock,columnBlock+numberColumns,stack);
+	}
+	CoinFillN(columnBlock,numberColumns,-1);
+	columnBlock[numberColumns]=0;
+	CoinFillN(whichColumn,numberColumns,-1);
+	CoinFillN(rowBlock,numberRows,-1);
+	CoinFillN(whichRow,numberRows,-1);
+	int numberMarkedRows = 0;
+	numberBlocks=0;
+	int bestColumn = -1;
+	int maximumInBlock = 0;
+	int columnsDone=0;
+	int checkAfterColumns = (5*numberColumns)/10+1;
+#ifdef OSL_WAY
+	double best = COIN_DBL_MAX;
+	int bestColumnsDone=-1;
+#else
+	double best = 0.0; //COIN_DBL_MAX;
+#endif
+	int numberGoodBlocks=0;
+	
+	for (int kColumn=0;kColumn<numberColumns;kColumn++) {
+	  iColumn = stack[kColumn];
+	  CoinBigIndex start = columnStart[iColumn];
+	  CoinBigIndex end = start+columnLength[iColumn];
+	  int iBlock=-1;
+	  for (CoinBigIndex j=start;j<end;j++) {
+	    int iRow = row[j];
+	    if (rowBlock[iRow]>=0) {
+	      // already marked
+	      if (iBlock<0) {
+		iBlock = rowBlock[iRow];
+	      } else if (iBlock != rowBlock[iRow]) {
+		// join two blocks
+		int jBlock = rowBlock[iRow];
+		numberGoodBlocks--;
+		// Increase count of iBlock
+		columnBlock[iBlock] += columnBlock[jBlock];
+		columnBlock[jBlock]=0;
+		// First row of block jBlock
+		int jRow = whichColumn[jBlock];
+		while (jRow>=0) {
+		  rowBlock[jRow]=iBlock;
+		  iRow = jRow;
+		  jRow = whichRow[jRow];
+		}
+		whichRow[iRow] = whichColumn[iBlock];
+		whichColumn[iBlock] = whichColumn[jBlock];
+		whichColumn[jBlock]=-1;
+	      }
+	    }
+	  }
+	  int n=end-start;
+	  // If not in block - then start one
+	  if (iBlock<0) {
+	    // unless null column
+	    if (n) {
+	      iBlock = numberBlocks;
+	      numberBlocks++;
+	      numberGoodBlocks++;
+	      int jRow = row[start];
+	      rowBlock[jRow]=iBlock;
+	      whichColumn[iBlock]=jRow;
+	      numberMarkedRows += n;
+	      columnBlock[iBlock] = n;
+	      for (CoinBigIndex j=start+1;j<end;j++) {
+		int iRow = row[j];
+		rowBlock[iRow]=iBlock;
+		whichRow[jRow]=iRow;
+		jRow=iRow;
+	      }
+	    } else {
+	      columnBlock[numberColumns]++;
+	    }
+	  } else {
+	    // add all to this block if not already in
+	    int jRow = whichColumn[iBlock];
+	    for (CoinBigIndex j=start;j<end;j++) {
+	      int iRow = row[j];
+	      if (rowBlock[iRow]<0) {
+		numberMarkedRows++;
+		columnBlock[iBlock]++;
+		rowBlock[iRow]=iBlock;
+		whichRow[iRow]=jRow;
+		jRow=iRow;
+	      }
+	    }
+	    whichColumn[iBlock]=jRow;
+	  }
+	  columnsDone++;
+	  if (iBlock>=0) 
+	    maximumInBlock = CoinMax(maximumInBlock,columnBlock[iBlock]);
+	  if (columnsDone>=checkAfterColumns) {
+	    assert (numberGoodBlocks>0);
+	    double averageSize = static_cast<double>(numberMarkedRows)/
+	      static_cast<double>(numberGoodBlocks);
+#ifndef OSL_WAY
+	    double notionalBlocks = static_cast<double>(numberMarkedRows)/
+	      averageSize;
+	    if (maximumInBlock<3*averageSize&&numberGoodBlocks>2) {
+	      if(best*(numberColumns-columnsDone) < notionalBlocks) {
+		best = notionalBlocks/
+		  static_cast<double> (numberColumns-columnsDone); 
+		bestColumn = kColumn;
+	      }
+	    }
+#else
+	    if (maximumInBlock*10<numberRows*11&&numberGoodBlocks>1) {
+	      double test = maximumInBlock + 0.0*averageSize;
+	      if(best*static_cast<double>(columnsDone) > test) {
+		best = test/static_cast<double> (columnsDone); 
+		bestColumn = kColumn;
+		bestColumnsDone=columnsDone;
+	      }
+	    }
+#endif
+	  }	      
+	}
+#ifndef OSL_WAY
+	best2[iWay]=best;
+#else
+	if (bestColumnsDone<numberColumns)
+	  best2[iWay]=-(numberColumns-bestColumnsDone);
+	else
+	  best2[iWay]=-numberColumns;
+#endif
+	column2[iWay]=bestColumn;
+      }
+      // mark columns
+      int nMaster;
+      CoinFillN(columnBlock,numberColumns,-2);
+      if (best2[2]<best2[0]||best2[2]<best2[1]) {
+	int iColumn1;
+	int iColumn2;
+	if (best2[0]>best2[1]) {
+	  // End columns in master
+	  iColumn1=column2[0]+1;
+	  iColumn2=numberColumns;
+	} else {
+	  // Beginning columns in master
+	  iColumn1=0;
+	  iColumn2=numberColumns-column2[1];
+	}
+	nMaster = iColumn2-iColumn1;
+	CoinFillN(columnBlock+iColumn1,nMaster,-1);
+      } else {
+	// sorted
+	// End columns in master (in order)
+	int iColumn1=column2[2]+1;
+	nMaster = numberColumns-iColumn1;
+	for (int i=iColumn1;i<numberColumns;i++)
+	  columnBlock[stack[i]]=-1;
+      }
+      if (nMaster*2>numberColumns) {
+	printf("%d columns out of %d would be in master - no good\n",
+	       nMaster,numberColumns);
+	delete [] rowBlock;
+	delete [] columnBlock;
+	delete [] whichRow;
+	delete [] whichColumn;
+	delete [] stack;
+	CoinModel model(numberRows,numberColumns,&matrix, rowLower, rowUpper,
+			columnLower,columnUpper,objective);
+	model.setObjectiveOffset(objectiveOffset);
+	addBlock("row_master","column_master",model);
+	return 0;
+      }
+    } else {
+      for (iColumn=0;iColumn<numberColumns;iColumn++)
+	columnBlock[iColumn]=-2;
+      // these are master columns
+      if (numberColumns==2426) {
+	// ken-7 dual
+	for (iColumn=2401;iColumn<numberColumns;iColumn++)
+	  columnBlock[iColumn]=-1;
+      }
+    }
+    numberBlocks=0;
+    CoinFillN(rowBlock,numberRows,-2);
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int kstart = rowStart[iRow];
+      int kend = rowStart[iRow]+rowLength[iRow];
+      if (rowBlock[iRow]==-2) {
+	// row not allocated
+	int j;
+	int nstack=0;
+	for (j=kstart;j<kend;j++) {
+	  int iColumn= column[j];
+	  if (columnBlock[iColumn]!=-1) {
+	    assert(columnBlock[iColumn]==-2);
+	    columnBlock[iColumn]=numberBlocks; // mark
+	    stack[nstack++] = iColumn;
+	  }
+	}
+	if (nstack) {
+	  // new block - put all connected in
+	  numberBlocks++;
+	  rowBlock[iRow]=numberBlocks-1;
+	  while (nstack) {
+	    int iColumn = stack[--nstack];
+	    int k;
+	    for (k=columnStart[iColumn];k<columnStart[iColumn]+columnLength[iColumn];k++) {
+	      int iRow = row[k];
+	      int kkstart = rowStart[iRow];
+	      int kkend = kkstart + rowLength[iRow];
+	      if (rowBlock[iRow]==-2) {
+		rowBlock[iRow]=numberBlocks-1; // mark
+		// row not allocated
+		int jj;
+		for (jj=kkstart;jj<kkend;jj++) {
+		  int jColumn= column[jj];
+		  if (columnBlock[jColumn]==-2) {
+		    columnBlock[jColumn]=numberBlocks-1;
+		    stack[nstack++]=jColumn;
+		  }
+		}
+	      } else {
+		assert (rowBlock[iRow]==numberBlocks-1);
+	      }
+	    }
+	  }
+	} else {
+	  // Only in master
+	  rowBlock[iRow]=-1;
+	}
+      }
+    }
+    delete [] stack;
+    int numberMasterColumns=0;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      int iBlock = columnBlock[iColumn];
+      if (iBlock==-1)
+	numberMasterColumns++;
+    }
+    int numberMasterRows=0;
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int iBlock = rowBlock[iRow];
+      if (iBlock==-1)
+	numberMasterRows++;
+    }
+    if (numberBlocks<=maxBlocks)
+      printf("%d blocks found - %d columns, %d rows in master\n",
+	     numberBlocks,numberMasterColumns,numberMasterRows);
+    else
+      printf("%d blocks found (reduced to %d) - %d columns, %d rows in master\n",
+	     numberBlocks,maxBlocks,numberMasterColumns,numberMasterRows);
+    if (numberBlocks) {
+      if (numberBlocks>maxBlocks) {
+	int iBlock;
+	for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	  iBlock = columnBlock[iColumn];
+	  if (iBlock>=0)
+	    columnBlock[iColumn] = iBlock%maxBlocks;
+	}
+	for (iRow=0;iRow<numberRows;iRow++) {
+	  iBlock = rowBlock[iRow];
+	  if (iBlock>=0)
+	    rowBlock[iRow] = iBlock%maxBlocks;
+	}
+	numberBlocks=maxBlocks;
+      }
+    }
+    // make up problems
+    // Create all sub problems
+    // Space for creating
+    double * obj = new double [numberColumns];
+    double * rowLo = new double [numberRows];
+    double * rowUp = new double [numberRows];
+    double * columnLo = new double [numberColumns];
+    double * columnUp = new double [numberColumns];
+    // Counts
+    int * columnCount = reinterpret_cast<int *>(columnLo);
+    CoinZeroN(columnCount,numberBlocks);
+    for (int i=0;i<numberColumns;i++) {
+      int iBlock=columnBlock[i];
+      if (iBlock>=0)
+	columnCount[iBlock]++;
+    }
+    // allocate empty columns
+    for (int i=0;i<numberColumns;i++) {
+      int iBlock=columnBlock[i];
+      if (iBlock==-2) {
+	// find block with smallest count
+	int iSmall=-1;
+	int smallest = numberColumns;
+	for (int j=0;j<numberBlocks;j++) {
+	  if (columnCount[j]<smallest) {
+	    iSmall=j;
+	    smallest=columnCount[j];
+	  }
+	}
+	columnBlock[i]=iSmall;
+	columnCount[iSmall]++;
+      }
+    }
+    int * rowCount = reinterpret_cast<int *>(columnUp);
+    CoinZeroN(rowCount,numberBlocks);
+    for (int i=0;i<numberRows;i++) {
+      int iBlock=rowBlock[i];
+      if (iBlock>=0)
+	rowCount[iBlock]++;
+    }
+    int maximumSize=0;
+    for (int i=0;i<numberBlocks;i++) {
+      printf("Block %d has %d columns and %d rows\n",i,
+	     columnCount[i],rowCount[i]);
+      int k=2*columnCount[i]+rowCount[i];
+      maximumSize = CoinMax(maximumSize,k);
+    }
+    if (maximumSize*10>4*(2*numberColumns+numberRows)) {
+      // No good
+      printf("Doesn't look good\n");
+      delete [] rowBlock;
+      delete [] columnBlock;
+      delete [] whichRow;
+      delete [] whichColumn;
+      delete [] obj ; 
+      delete [] columnLo ; 
+      delete [] columnUp ; 
+      delete [] rowLo ; 
+      delete [] rowUp ; 
+      CoinModel model(numberRows,numberColumns,&matrix, rowLower, rowUpper,
+		      columnLower,columnUpper,objective);
+      model.setObjectiveOffset(objectiveOffset);
+      addBlock("row_master","column_master",model);
+      return 0;
+    }
+    // Name for master so at beginning
+    addColumnBlock(numberMasterColumns,"column_master");
+    // Arrays
+    // get full matrix
+    CoinPackedMatrix fullMatrix = matrix;
+    int numberRow2,numberColumn2;
+    int iBlock;
+    for (iBlock=0;iBlock<numberBlocks;iBlock++) {
+      char rowName[20];
+      sprintf(rowName,"row_%d",iBlock);
+      char columnName[20];
+      sprintf(columnName,"column_%d",iBlock);
+      numberRow2=0;
+      numberColumn2=0;
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	if (iBlock==columnBlock[iColumn]) {
+	  obj[numberColumn2]=objective[iColumn];
+	  columnLo[numberColumn2]=columnLower[iColumn];
+	  columnUp[numberColumn2]=columnUpper[iColumn];
+	  whichColumn[numberColumn2++]=iColumn;
+	}
+      }
+      for (iRow=0;iRow<numberRows;iRow++) {
+	if (iBlock==rowBlock[iRow]) {
+	  rowLo[numberRow2]=rowLower[iRow];
+	  rowUp[numberRow2]=rowUpper[iRow];
+	  whichRow[numberRow2++]=iRow;
+	}
+      }
+      // Diagonal block
+      CoinPackedMatrix mat(fullMatrix,
+			   numberRow2,whichRow,
+			   numberColumn2,whichColumn);
+      // make sure correct dimensions
+      mat.setDimensions(numberRow2,numberColumn2);
+      CoinModel * block = new CoinModel(numberRow2,numberColumn2,&mat,
+					rowLo,rowUp,columnLo,columnUp,obj);
+      block->setOriginalIndices(whichRow,whichColumn);
+      addBlock(rowName,columnName,block); // takes ownership
+      // and beginning block
+      numberColumn2=0;
+      // get beginning matrix
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	int iBlock = columnBlock[iColumn];
+	if (iBlock==-1) {
+	  whichColumn[numberColumn2++]=iColumn;
+	}
+      }
+      CoinPackedMatrix beginning(fullMatrix,
+			   numberRow2,whichRow,
+			   numberColumn2,whichColumn);
+      // make sure correct dimensions *********
+      beginning.setDimensions(numberRow2,numberColumn2);
+      block = new CoinModel(numberRow2,numberMasterColumns,&beginning,
+			    NULL,NULL,NULL,NULL,NULL);
+      block->setOriginalIndices(whichRow,whichColumn);
+      addBlock(rowName,"column_master",block); // takes ownership
+    }
+    // and master
+    numberRow2=0;
+    numberColumn2=0;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      int iBlock = columnBlock[iColumn];
+      if (iBlock==-1) {
+	obj[numberColumn2]=objective[iColumn];
+	columnLo[numberColumn2]=columnLower[iColumn];
+	columnUp[numberColumn2]=columnUpper[iColumn];
+	whichColumn[numberColumn2++]=iColumn;
+      }
+    }
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int iBlock = rowBlock[iRow];
+      if (iBlock<0) {
+	rowLo[numberRow2]=rowLower[iRow];
+	rowUp[numberRow2]=rowUpper[iRow];
+	whichRow[numberRow2++]=iRow;
+      }
+    }
+    delete [] rowBlock;
+    delete [] columnBlock;
+    CoinPackedMatrix beginning(fullMatrix,
+			 numberRow2,whichRow,
+			 numberColumn2,whichColumn);
+    // make sure correct dimensions
+    beginning.setDimensions(numberRow2,numberColumn2);
+    CoinModel * block = new CoinModel(numberRow2,numberColumn2,&beginning,
+				      rowLo,rowUp,
+				      columnLo,columnUp,obj);
+    block->setOriginalIndices(whichRow,whichColumn);
+    addBlock("row_master","column_master",block); // takes ownership
+    delete [] whichRow;
+    delete [] whichColumn;
+    delete [] obj ; 
+    delete [] columnLo ; 
+    delete [] columnUp ; 
+    delete [] rowLo ; 
+    delete [] rowUp ; 
+  } else {
+    abort();
+  }
+  return numberBlocks;
+}
+/* Decompose a CoinModel
+   1 - try D-W
+   2 - try Benders
+   3 - try Staircase
+   Returns number of blocks or zero if no structure
+*/
+int 
+CoinStructuredModel::decompose(const CoinModel & coinModel, int type,
+			       int maxBlocks)
+{
+  const CoinPackedMatrix * matrix = coinModel.packedMatrix();
+  assert (matrix!=NULL);
+  // Arrays
+  const double * objective = coinModel.objectiveArray();
+  const double * columnLower = coinModel.columnLowerArray();
+  const double * columnUpper = coinModel.columnUpperArray();
+  const double * rowLower = coinModel.rowLowerArray();
+  const double * rowUpper = coinModel.rowUpperArray();
+  return decompose(*matrix,
+		   rowLower,  rowUpper,
+		   columnLower,  columnUpper,
+		   objective, type,maxBlocks,
+		   coinModel.objectiveOffset());
+}
+// Return block corresponding to row and column
+const CoinBaseModel *  
+CoinStructuredModel::block(int row,int column) const
+{
+  const CoinBaseModel * block = NULL;
+  if (blockType_) {
+    for (int iBlock=0;iBlock<numberElementBlocks_;iBlock++) {
+      if (blockType_[iBlock].rowBlock==row&&
+	  blockType_[iBlock].columnBlock==column) {
+	block = blocks_[iBlock];
+	break;
+      }
+    }
+  }
+  return block;
+}
+// Return block corresponding to row and column as CoinModel
+const CoinBaseModel *  
+CoinStructuredModel::coinBlock(int row,int column) const
+{
+  const CoinModel * block = NULL;
+  if (blockType_) {
+    for (int iBlock=0;iBlock<numberElementBlocks_;iBlock++) {
+      if (blockType_[iBlock].rowBlock==row&&
+	  blockType_[iBlock].columnBlock==column) {
+	block = dynamic_cast<CoinModel *>(blocks_[iBlock]);
+	assert (block);
+	break;
+      }
+    }
+  }
+  return block;
+}
+/* Fill pointers corresponding to row and column.
+   False if any missing */
+CoinModelBlockInfo 
+CoinStructuredModel::block(int row,int column,
+			   const double * & rowLower, const double * & rowUpper,
+			   const double * & columnLower, const double * & columnUpper,
+			   const double * & objective) const
+{
+  CoinModelBlockInfo info;
+  //memset(&info,0,sizeof(info));
+  rowLower=NULL;
+  rowUpper=NULL;
+  columnLower=NULL;
+  columnUpper=NULL;
+  objective=NULL;
+  if (blockType_) {
+    for (int iBlock=0;iBlock<numberElementBlocks_;iBlock++) {
+      CoinModel * thisBlock = coinBlock(iBlock);
+      if (blockType_[iBlock].rowBlock==row) {
+	if (blockType_[iBlock].rhs) {
+	  info.rhs=1;
+	  rowLower = thisBlock->rowLowerArray();
+	  rowUpper = thisBlock->rowUpperArray();
+	}
+      }
+      if (blockType_[iBlock].columnBlock==column) {
+	if (blockType_[iBlock].bounds) {
+	  info.bounds=1;
+	  columnLower = thisBlock->columnLowerArray();
+	  columnUpper = thisBlock->columnUpperArray();
+	  objective = thisBlock->objectiveArray();
+	}
+      }
+    }
+  }
+  return info;
+}
+// Return block number corresponding to row and column
+int  
+CoinStructuredModel::blockIndex(int row,int column) const
+{
+  int block=-1;
+  if (blockType_) {
+    for (int iBlock=0;iBlock<numberElementBlocks_;iBlock++) {
+      if (blockType_[iBlock].rowBlock==row&&
+	  blockType_[iBlock].columnBlock==column) {
+	block = iBlock;
+	break;
+      }
+    }
+  }
+  return block;
+}
diff --git a/cbits/coin/CoinStructuredModel.hpp b/cbits/coin/CoinStructuredModel.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinStructuredModel.hpp
@@ -0,0 +1,241 @@
+/* $Id: CoinStructuredModel.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2008, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinStructuredModel_H
+#define CoinStructuredModel_H
+
+#include "CoinModel.hpp"
+#include <vector>
+
+/** 
+    This is a model which is made up of Coin(Structured)Model blocks.
+*/
+  typedef struct CoinModelInfo2 {
+    int rowBlock; // Which row block
+    int columnBlock; // Which column block
+    char matrix; // nonzero if matrix exists
+    char rhs; // nonzero if non default rhs exists
+    char rowName; // nonzero if row names exists
+    char integer; // nonzero if integer information exists
+    char bounds; // nonzero if non default bounds/objective exists
+    char columnName; // nonzero if column names exists
+    CoinModelInfo2() : 
+      rowBlock(0),
+      columnBlock(0),
+      matrix(0),
+      rhs(0),
+      rowName(0),
+      integer(0),
+      bounds(0),
+      columnName(0)
+    {}
+} CoinModelBlockInfo;
+
+class CoinStructuredModel : public CoinBaseModel {
+  
+public:
+  /**@name Useful methods for building model */
+  //@{
+  /** add a block from a CoinModel using names given as parameters 
+      returns number of errors (e.g. both have objectives but not same)
+   */
+  int addBlock(const std::string & rowBlock,
+		const std::string & columnBlock,
+		const CoinBaseModel & block);
+  /** add a block from a CoinModel with names in model
+      returns number of errors (e.g. both have objectives but not same)
+ */
+  int addBlock(const CoinBaseModel & block);
+  /** add a block from a CoinModel using names given as parameters 
+      returns number of errors (e.g. both have objectives but not same)
+      This passes in block - structured model takes ownership
+   */
+  int addBlock(const std::string & rowBlock,
+		const std::string & columnBlock,
+		CoinBaseModel * block);
+  /** add a block using names 
+   */
+  int addBlock(const std::string & rowBlock,
+	       const std::string & columnBlock,
+	       const CoinPackedMatrix & matrix,
+	       const double * rowLower, const double * rowUpper,
+	       const double * columnLower, const double * columnUpper,
+	       const double * objective);
+
+  /** Write the problem in MPS format to a file with the given filename.
+      
+  \param compression can be set to three values to indicate what kind
+  of file should be written
+  <ul>
+  <li> 0: plain text (default)
+  <li> 1: gzip compressed (.gz is appended to \c filename)
+  <li> 2: bzip2 compressed (.bz2 is appended to \c filename) (TODO)
+  </ul>
+  If the library was not compiled with the requested compression then
+  writeMps falls back to writing a plain text file.
+  
+  \param formatType specifies the precision to used for values in the
+  MPS file
+  <ul>
+  <li> 0: normal precision (default)
+  <li> 1: extra accuracy
+  <li> 2: IEEE hex
+  </ul>
+  
+  \param numberAcross specifies whether 1 or 2 (default) values should be
+  specified on every data line in the MPS file.
+  
+  not const as may change model e.g. fill in default bounds
+  */
+  int writeMps(const char *filename, int compression = 0,
+               int formatType = 0, int numberAcross = 2, bool keepStrings=false) ;
+  /** Decompose a CoinModel
+      1 - try D-W
+      2 - try Benders
+      3 - try Staircase
+      Returns number of blocks or zero if no structure
+  */
+  int decompose(const CoinModel &model,int type,
+		int maxBlocks=50);
+  /** Decompose a model specified as arrays + CoinPackedMatrix
+      1 - try D-W
+      2 - try Benders
+      3 - try Staircase
+      Returns number of blocks or zero if no structure
+  */
+  int decompose(const CoinPackedMatrix & matrix,
+		const double * rowLower, const double * rowUpper,
+		const double * columnLower, const double * columnUpper,
+		const double * objective, int type,int maxBlocks=50,
+		double objectiveOffset=0.0);
+  
+   //@}
+
+
+  /**@name For getting information */
+   //@{
+   /// Return number of row blocks
+  inline int numberRowBlocks() const
+  { return numberRowBlocks_;}
+   /// Return number of column blocks
+  inline int numberColumnBlocks() const
+  { return numberColumnBlocks_;}
+   /// Return number of elementBlocks
+  inline CoinBigIndex numberElementBlocks() const
+  { return numberElementBlocks_;}
+   /// Return number of elements
+  CoinBigIndex numberElements() const;
+  /// Return the i'th row block name
+  inline const std::string & getRowBlock(int i) const
+  { return rowBlockNames_[i];}
+  /// Set i'th row block name
+  inline void setRowBlock(int i,const std::string &name) 
+  { rowBlockNames_[i] = name;}
+  /// Add or check a row block name and number of rows
+  int addRowBlock(int numberRows,const std::string &name) ;
+  /// Return a row block index given a row block name
+  int rowBlock(const std::string &name) const;
+  /// Return i'th the column block name
+  inline const std::string & getColumnBlock(int i) const
+  { return columnBlockNames_[i];}
+  /// Set i'th column block name
+  inline void setColumnBlock(int i,const std::string &name) 
+  { columnBlockNames_[i] = name;}
+  /// Add or check a column block name and number of columns
+  int addColumnBlock(int numberColumns,const std::string &name) ;
+  /// Return a column block index given a column block name
+  int columnBlock(const std::string &name) const;
+  /// Return i'th block type
+  inline const CoinModelBlockInfo &  blockType(int i) const
+  { return blockType_[i];}
+  /// Return i'th block
+  inline CoinBaseModel * block(int i) const
+  { return blocks_[i];}
+  /// Return block corresponding to row and column
+  const CoinBaseModel *  block(int row,int column) const;
+  /// Return i'th block as CoinModel (or NULL)
+  CoinModel * coinBlock(int i) const;
+  /// Return block corresponding to row and column as CoinModel
+  const CoinBaseModel *  coinBlock(int row,int column) const;
+  /// Return block number corresponding to row and column
+  int  blockIndex(int row,int column) const;
+  /** Return model as a CoinModel block
+      and fill in info structure and update counts
+      */
+  CoinModel * coinModelBlock(CoinModelBlockInfo & info) ;
+  /// Sets given block into coinModelBlocks_
+  void setCoinModel(CoinModel * block, int iBlock);
+  /// Refresh info in blockType_
+  void refresh(int iBlock);
+  /** Fill pointers corresponding to row and column */
+
+  CoinModelBlockInfo block(int row,int column,
+	     const double * & rowLower, const double * & rowUpper,
+	     const double * & columnLower, const double * & columnUpper,
+	     const double * & objective) const;
+  /// Direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+  inline double optimizationDirection() const {
+    return  optimizationDirection_;
+  }
+  /// Set direction of optimization (1 - minimize, -1 - maximize, 0 - ignore
+  inline void setOptimizationDirection(double value)
+  { optimizationDirection_=value;}
+   //@}
+
+  /**@name Constructors, destructor */
+   //@{
+   /** Default constructor. */
+  CoinStructuredModel();
+  /** Read a problem in MPS format from the given filename.
+      May try and decompose
+   */
+  CoinStructuredModel(const char *fileName,int decompose=0,
+		      int maxBlocks=50);
+   /** Destructor */
+   virtual ~CoinStructuredModel();
+   //@}
+
+   /**@name Copy method */
+   //@{
+   /** The copy constructor. */
+   CoinStructuredModel(const CoinStructuredModel&);
+  /// =
+   CoinStructuredModel& operator=(const CoinStructuredModel&);
+  /// Clone
+  virtual CoinBaseModel * clone() const;
+   //@}
+
+private:
+
+  /** Fill in info structure and update counts
+      Returns number of inconsistencies on border
+  */
+  int fillInfo(CoinModelBlockInfo & info,const CoinModel * block);
+  /** Fill in info structure and update counts
+  */
+  void fillInfo(CoinModelBlockInfo & info,const CoinStructuredModel * block);
+  /**@name Data members */
+   //@{
+  /// Current number of row blocks
+  int numberRowBlocks_;
+  /// Current number of column blocks
+  int numberColumnBlocks_;
+  /// Current number of element blocks
+  int numberElementBlocks_;
+  /// Maximum number of element blocks
+  int maximumElementBlocks_;
+  /// Rowblock name
+  std::vector<std::string> rowBlockNames_;
+  /// Columnblock name
+  std::vector<std::string> columnBlockNames_;
+  /// Blocks
+  CoinBaseModel ** blocks_;
+  /// CoinModel copies of blocks or NULL if original CoinModel
+  CoinModel ** coinModelBlocks_;
+  /// Which parts of model are set in block
+  CoinModelBlockInfo * blockType_;
+   //@}
+};
+#endif
diff --git a/cbits/coin/CoinTime.hpp b/cbits/coin/CoinTime.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinTime.hpp
@@ -0,0 +1,310 @@
+/* $Id: CoinTime.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef _CoinTime_hpp
+#define _CoinTime_hpp
+
+// Uncomment the next three lines for thorough memory initialisation.
+// #ifndef ZEROFAULT
+// # define ZEROFAULT
+// #endif
+
+//#############################################################################
+
+#include <ctime>
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#else
+// MacOS-X and FreeBSD needs sys/time.h
+#if defined(__MACH__) || defined (__FreeBSD__)
+#include <sys/time.h>
+#endif
+#if !defined(__MSVCRT__)
+#include <sys/resource.h>
+#endif
+#endif
+
+//#############################################################################
+
+#if defined(_MSC_VER)
+
+#if 0 // change this to 1 if want to use the win32 API
+#include <windows.h>
+#ifdef small
+/* for some unfathomable reason (to me) rpcndr.h (pulled in by windows.h) does a
+   '#define small char' */
+#undef small
+#endif
+#define TWO_TO_THE_THIRTYTWO 4294967296.0
+#define DELTA_EPOCH_IN_SECS  11644473600.0
+inline double CoinGetTimeOfDay()
+{
+  FILETIME ft;
+ 
+  GetSystemTimeAsFileTime(&ft);
+  double t = ft.dwHighDateTime * TWO_TO_THE_THIRTYTWO + ft.dwLowDateTime;
+  t = t/10000000.0 - DELTA_EPOCH_IN_SECS;
+  return t;
+}
+#else
+#include <sys/types.h>
+#include <sys/timeb.h>
+inline double CoinGetTimeOfDay()
+{
+  struct _timeb timebuffer;
+#pragma warning(disable:4996)
+  _ftime( &timebuffer ); // C4996
+#pragma warning(default:4996)
+  return timebuffer.time + timebuffer.millitm/1000.0;
+}
+#endif
+
+#else
+
+#include <sys/time.h>
+
+inline double CoinGetTimeOfDay()
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return static_cast<double>(tv.tv_sec) + static_cast<int>(tv.tv_usec)/1000000.0;
+}
+
+#endif // _MSC_VER
+
+/**
+   Query the elapsed wallclock time since the first call to this function. If
+   a positive argument is passed to the function then the time of the first
+   call is set to that value (this kind of argument is allowed only at the
+   first call!). If a negative argument is passed to the function then it
+   returns the time when it was set.
+*/
+
+inline double CoinWallclockTime(double callType = 0)
+{
+    double callTime = CoinGetTimeOfDay();
+    static const double firstCall = callType > 0 ? callType : callTime;
+    return callType < 0 ? firstCall : callTime - firstCall;
+}
+
+//#############################################################################
+
+//#define HAVE_SDK // if SDK under Win32 is installed, for CPU instead of elapsed time under Win 
+#ifdef HAVE_SDK
+#include <windows.h>
+#ifdef small
+/* for some unfathomable reason (to me) rpcndr.h (pulled in by windows.h) does a
+   '#define small char' */
+#undef small
+#endif
+#define TWO_TO_THE_THIRTYTWO 4294967296.0
+#endif
+
+static inline double CoinCpuTime()
+{
+  double cpu_temp;
+#if defined(_MSC_VER) || defined(__MSVCRT__)
+#ifdef HAVE_SDK
+  FILETIME creation;
+  FILETIME exit;
+  FILETIME kernel;
+  FILETIME user;
+  GetProcessTimes(GetCurrentProcess(), &creation, &exit, &kernel, &user);
+  double t = user.dwHighDateTime * TWO_TO_THE_THIRTYTWO + user.dwLowDateTime;
+  return t/10000000.0;
+#else
+  unsigned int ticksnow;        /* clock_t is same as int */
+  ticksnow = (unsigned int)clock();
+  cpu_temp = (double)((double)ticksnow/CLOCKS_PER_SEC);
+#endif
+
+#else
+  struct rusage usage;
+# ifdef ZEROFAULT
+  usage.ru_utime.tv_sec = 0 ;
+  usage.ru_utime.tv_usec = 0 ;
+# endif
+  getrusage(RUSAGE_SELF,&usage);
+  cpu_temp = static_cast<double>(usage.ru_utime.tv_sec);
+  cpu_temp += 1.0e-6*(static_cast<double> (usage.ru_utime.tv_usec));
+#endif
+  return cpu_temp;
+}
+
+//#############################################################################
+
+
+
+static inline double CoinSysTime()
+{
+  double sys_temp;
+#if defined(_MSC_VER) || defined(__MSVCRT__)
+  sys_temp = 0.0;
+#else
+  struct rusage usage;
+# ifdef ZEROFAULT
+  usage.ru_utime.tv_sec = 0 ;
+  usage.ru_utime.tv_usec = 0 ;
+# endif
+  getrusage(RUSAGE_SELF,&usage);
+  sys_temp = static_cast<double>(usage.ru_stime.tv_sec);
+  sys_temp += 1.0e-6*(static_cast<double> (usage.ru_stime.tv_usec));
+#endif
+  return sys_temp;
+}
+
+//#############################################################################
+// On most systems SELF seems to include children threads, This is for when it doesn't
+static inline double CoinCpuTimeJustChildren()
+{
+  double cpu_temp;
+#if defined(_MSC_VER) || defined(__MSVCRT__)
+  cpu_temp = 0.0;
+#else
+  struct rusage usage;
+# ifdef ZEROFAULT
+  usage.ru_utime.tv_sec = 0 ;
+  usage.ru_utime.tv_usec = 0 ;
+# endif
+  getrusage(RUSAGE_CHILDREN,&usage);
+  cpu_temp = static_cast<double>(usage.ru_utime.tv_sec);
+  cpu_temp += 1.0e-6*(static_cast<double> (usage.ru_utime.tv_usec));
+#endif
+  return cpu_temp;
+}
+//#############################################################################
+
+#include <fstream>
+
+/**
+ This class implements a timer that also implements a tracing functionality.
+
+ The timer stores the start time of the timer, for how much time it was set to
+ and when does it expire (start + limit = end). Queries can be made that tell
+ whether the timer is expired, is past an absolute time, is past a percentage
+ of the length of the timer. All times are given in seconds, but as double
+ numbers, so there can be fractional values.
+
+ The timer can also be initialized with a stream and a specification whether
+ to write to or read from the stream. In the former case the result of every
+ query is written into the stream, in the latter case timing is not tested at
+ all, rather the supposed result is read out from the stream. This makes it
+ possible to exactly retrace time sensitive program execution.
+*/
+class CoinTimer
+{
+private:
+   /// When the timer was initialized/reset/restarted
+   double start;
+   /// 
+   double limit;
+   double end;
+#ifdef COIN_COMPILE_WITH_TRACING
+   std::fstream* stream;
+   bool write_stream;
+#endif
+
+private:
+#ifdef COIN_COMPILE_WITH_TRACING
+   inline bool evaluate(bool b_tmp) const {
+      int i_tmp = b_tmp;
+      if (stream) {
+	 if (write_stream)
+	    (*stream) << i_tmp << "\n";
+	 else 
+	    (*stream) >> i_tmp;
+      }
+      return i_tmp;
+   }
+   inline double evaluate(double d_tmp) const {
+      if (stream) {
+	 if (write_stream)
+	    (*stream) << d_tmp << "\n";
+	 else 
+	    (*stream) >> d_tmp;
+      }
+      return d_tmp;
+   }
+#else
+   inline bool evaluate(const bool b_tmp) const {
+      return b_tmp;
+   }
+   inline double evaluate(const double d_tmp) const {
+      return d_tmp;
+   }
+#endif   
+
+public:
+   /// Default constructor creates a timer with no time limit and no tracing
+   CoinTimer() :
+      start(0), limit(1e100), end(1e100)
+#ifdef COIN_COMPILE_WITH_TRACING
+      , stream(0), write_stream(true)
+#endif
+   {}
+
+   /// Create a timer with the given time limit and with no tracing
+   CoinTimer(double lim) :
+      start(CoinCpuTime()), limit(lim), end(start+lim)
+#ifdef COIN_COMPILE_WITH_TRACING
+      , stream(0), write_stream(true)
+#endif
+   {}
+
+#ifdef COIN_COMPILE_WITH_TRACING
+   /** Create a timer with no time limit and with writing/reading the trace
+       to/from the given stream, depending on the argument \c write. */
+   CoinTimer(std::fstream* s, bool write) :
+      start(0), limit(1e100), end(1e100),
+      stream(s), write_stream(write) {}
+   
+   /** Create a timer with the given time limit and with writing/reading the
+       trace to/from the given stream, depending on the argument \c write. */
+   CoinTimer(double lim, std::fstream* s, bool w) :
+      start(CoinCpuTime()), limit(lim), end(start+lim),
+      stream(s), write_stream(w) {}
+#endif
+   
+   /// Restart the timer (keeping the same time limit)
+   inline void restart() { start=CoinCpuTime(); end=start+limit; }
+   /// An alternate name for \c restart()
+   inline void reset() { restart(); }
+   /// Reset (and restart) the timer and change its time limit
+   inline void reset(double lim) { limit=lim; restart(); }
+
+   /** Return whether the given percentage of the time limit has elapsed since
+       the timer was started */
+   inline bool isPastPercent(double pct) const {
+      return evaluate(start + limit * pct < CoinCpuTime());
+   }
+   /** Return whether the given amount of time has elapsed since the timer was
+       started */
+   inline bool isPast(double lim) const {
+      return evaluate(start + lim < CoinCpuTime());
+   }
+   /** Return whether the originally specified time limit has passed since the
+       timer was started */
+   inline bool isExpired() const {
+      return evaluate(end < CoinCpuTime());
+   }
+
+   /** Return how much time is left on the timer */
+   inline double timeLeft() const {
+      return evaluate(end - CoinCpuTime());
+   }
+
+   /** Return how much time has elapsed */
+   inline double timeElapsed() const {
+      return evaluate(CoinCpuTime() - start);
+   }
+
+   inline void setLimit(double l) {
+      limit = l;
+      return;
+   }
+};
+
+#endif
diff --git a/cbits/coin/CoinTypes.hpp b/cbits/coin/CoinTypes.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinTypes.hpp
@@ -0,0 +1,61 @@
+/* $Id: CoinTypes.hpp 1628 2013-09-14 17:43:51Z stefan $ */
+// Copyright (C) 2004, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef _CoinTypes_hpp
+#define _CoinTypes_hpp
+
+#include "CoinUtilsConfig.h"
+/* On some systems, we require stdint.h to have the 64bit integer type defined. */
+#ifdef COINUTILS_HAS_STDINT_H
+#include <stdint.h>
+#endif
+
+#define CoinInt64 COIN_INT64_T
+#define CoinUInt64 COIN_UINT64_T
+#define CoinIntPtr COIN_INTPTR_T
+
+//=============================================================================
+#ifndef COIN_BIG_INDEX
+#define COIN_BIG_INDEX 0
+#endif
+
+#if COIN_BIG_INDEX==0
+typedef int CoinBigIndex;
+#elif COIN_BIG_INDEX==1
+typedef long CoinBigIndex;
+#else
+typedef long long CoinBigIndex;
+#endif
+
+//=============================================================================
+#ifndef COIN_BIG_DOUBLE
+#define COIN_BIG_DOUBLE 0
+#endif
+
+// See if we want the ability to have long double work arrays
+#if COIN_BIG_DOUBLE==2
+#undef COIN_BIG_DOUBLE
+#define COIN_BIG_DOUBLE 0
+#define COIN_LONG_WORK 1
+typedef long double CoinWorkDouble;
+#elif COIN_BIG_DOUBLE==3
+#undef COIN_BIG_DOUBLE
+#define COIN_BIG_DOUBLE 1
+#define COIN_LONG_WORK 1
+typedef long double CoinWorkDouble;
+#else
+#define COIN_LONG_WORK 0
+typedef double CoinWorkDouble;
+#endif
+
+#if COIN_BIG_DOUBLE==0
+typedef double CoinFactorizationDouble;
+#elif COIN_BIG_DOUBLE==1
+typedef long double CoinFactorizationDouble;
+#else
+typedef double CoinFactorizationDouble;
+#endif
+
+#endif
diff --git a/cbits/coin/CoinUtilsConfig.h b/cbits/coin/CoinUtilsConfig.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinUtilsConfig.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2011
+ * All Rights Reserved.
+ * This code is published under the Eclipse Public License.
+ *
+ * $Id: CoinUtilsConfig.h 1434 2011-06-06 13:47:41Z stefan $
+ *
+ * Include file for the configuration of CoinUtils.
+ *
+ * On systems where the code is configured with the configure script
+ * (i.e., compilation is always done with HAVE_CONFIG_H defined), this
+ * header file includes the automatically generated header file, and
+ * undefines macros that might configure with other Config.h files.
+ *
+ * On systems that are compiled in other ways (e.g., with the
+ * Developer Studio), a header files is included to define those
+ * macros that depend on the operating system and the compiler.  The
+ * macros that define the configuration of the particular user setting
+ * (e.g., presence of other COIN-OR packages or third party code) are set
+ * by the files config_*default.h. The project maintainer needs to remember
+ * to update these file and choose reasonable defines.
+ * A user can modify the default setting by editing the config_*default.h files.
+ *
+ */
+
+#ifndef __COINUTILSCONFIG_H__
+#define __COINUTILSCONFIG_H__
+
+#ifdef HAVE_CONFIG_H
+#ifdef COINUTILS_BUILD
+#include "config.h"
+#else
+#include "config_coinutils.h"
+#endif
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef COINUTILS_BUILD
+#include "config_default.h"
+#else
+#include "config_coinutils_default.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+#endif /*__COINUTILSCONFIG_H__*/
diff --git a/cbits/coin/CoinWarmStart.hpp b/cbits/coin/CoinWarmStart.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStart.hpp
@@ -0,0 +1,58 @@
+/* $Id: CoinWarmStart.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinWarmStart_H
+#define CoinWarmStart_H
+
+//#############################################################################
+
+class CoinWarmStartDiff;
+
+/** Abstract base class for warm start information.
+
+    Really nothing can be generalized for warm start information --- all we
+    know is that it exists. Hence the abstract base class contains only a
+    virtual destructor and a virtual clone function (a virtual constructor),
+    so that derived classes can provide these functions.
+*/
+
+class CoinWarmStart {
+public:
+
+  /// Abstract destructor
+  virtual ~CoinWarmStart() {}
+
+  /// `Virtual constructor'
+  virtual CoinWarmStart *clone() const = 0 ;
+   
+  virtual CoinWarmStartDiff*
+  generateDiff (const CoinWarmStart *const ) const { return 0; }
+   
+   
+  virtual void
+  applyDiff (const CoinWarmStartDiff *const ) {}
+
+};
+
+
+/*! \class CoinWarmStartDiff
+    \brief Abstract base class for warm start `diff' objects
+
+  For those types of warm start objects where the notion of a `diff' makes
+  sense, this virtual base class is provided. As with CoinWarmStart, its sole
+  reason for existence is to make it possible to write solver-independent code.
+*/
+
+class CoinWarmStartDiff {
+public:
+
+  /// Abstract destructor
+  virtual ~CoinWarmStartDiff() {}
+
+  /// `Virtual constructor'
+  virtual CoinWarmStartDiff *clone() const = 0 ;
+};
+
+#endif
diff --git a/cbits/coin/CoinWarmStartBasis.cpp b/cbits/coin/CoinWarmStartBasis.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStartBasis.cpp
@@ -0,0 +1,771 @@
+/* $Id: CoinWarmStartBasis.cpp 1515 2011-12-10 23:38:04Z lou $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinUtilsConfig.h"
+#include <cassert>
+
+#include "CoinWarmStartBasis.hpp"
+#include "CoinHelperFunctions.hpp"
+#include <cmath>
+#include <iostream>
+
+//#############################################################################
+
+void 
+CoinWarmStartBasis::setSize(int ns, int na) {
+  // Round all so arrays multiple of 4
+  int nintS = (ns+15) >> 4;
+  int nintA = (na+15) >> 4;
+  int size = nintS+nintA;
+  if (size) {
+    if (size>maxSize_) {
+      delete[] structuralStatus_;
+      maxSize_ = size+10;
+      structuralStatus_ = new char[4*maxSize_];
+    }
+    memset (structuralStatus_, 0, (4*nintS) * sizeof(char));
+    artificialStatus_ = structuralStatus_+4*nintS;
+    memset (artificialStatus_, 0, (4*nintA) * sizeof(char));
+  } else {
+    artificialStatus_ = NULL;
+  }
+  numArtificial_ = na;
+  numStructural_ = ns;
+}
+
+void 
+CoinWarmStartBasis::assignBasisStatus(int ns, int na, char*& sStat, 
+				     char*& aStat) {
+  // Round all so arrays multiple of 4
+  int nintS = (ns+15) >> 4;
+  int nintA = (na+15) >> 4;
+  int size = nintS+nintA;
+  if (size) {
+    if (size>maxSize_) {
+      delete[] structuralStatus_;
+      maxSize_ = size+10;
+      structuralStatus_ = new char[4*maxSize_];
+    }
+    CoinMemcpyN( sStat,(4*nintS), structuralStatus_);
+    artificialStatus_ = structuralStatus_+4*nintS;
+    CoinMemcpyN( aStat,(4*nintA), artificialStatus_);
+  } else {
+    artificialStatus_ = NULL;
+  }
+  numStructural_ = ns;
+  numArtificial_ = na;
+  delete [] sStat;
+  delete [] aStat;
+  sStat = NULL;
+  aStat = NULL;
+}
+CoinWarmStartBasis::CoinWarmStartBasis(int ns, int na, 
+				     const char* sStat, const char* aStat) :
+  numStructural_(ns), numArtificial_(na),
+  structuralStatus_(NULL), artificialStatus_(NULL) {
+  // Round all so arrays multiple of 4
+  int nintS = ((ns+15) >> 4);
+  int nintA = ((na+15) >> 4);
+  maxSize_ = nintS+nintA;
+  if (maxSize_ > 0) {
+    structuralStatus_ = new char[4*maxSize_];
+    if (nintS>0) {
+      structuralStatus_[4*nintS-3]=0;
+      structuralStatus_[4*nintS-2]=0;
+      structuralStatus_[4*nintS-1]=0;
+      CoinMemcpyN( sStat,((ns+3)/4), structuralStatus_);
+    }
+    artificialStatus_ = structuralStatus_+4*nintS;
+    if (nintA > 0) {
+      artificialStatus_[4*nintA-3]=0;
+      artificialStatus_[4*nintA-2]=0;
+      artificialStatus_[4*nintA-1]=0;
+      CoinMemcpyN( aStat,((na+3)/4), artificialStatus_);
+    }
+  }
+}
+
+CoinWarmStartBasis::CoinWarmStartBasis(const CoinWarmStartBasis& ws) :
+  numStructural_(ws.numStructural_), numArtificial_(ws.numArtificial_),
+  structuralStatus_(NULL), artificialStatus_(NULL) {
+  // Round all so arrays multiple of 4
+  int nintS = (numStructural_+15) >> 4;
+  int nintA = (numArtificial_+15) >> 4;
+  maxSize_ = nintS+nintA;
+  if (maxSize_ > 0) {
+    structuralStatus_ = new char[4*maxSize_];
+    CoinMemcpyN( ws.structuralStatus_,	(4*nintS), structuralStatus_);
+    artificialStatus_ = structuralStatus_+4*nintS;
+    CoinMemcpyN( ws.artificialStatus_,	(4*nintA), artificialStatus_);
+  }
+}
+
+CoinWarmStartBasis& 
+CoinWarmStartBasis::operator=(const CoinWarmStartBasis& rhs)
+{
+  if (this != &rhs) {
+    numStructural_=rhs.numStructural_;
+    numArtificial_=rhs.numArtificial_;
+    // Round all so arrays multiple of 4
+    int nintS = (numStructural_+15) >> 4;
+    int nintA = (numArtificial_+15) >> 4;
+    int size = nintS+nintA;
+    if (size>maxSize_) {
+      delete[] structuralStatus_;
+      maxSize_ = size+10;
+      structuralStatus_ = new char[4*maxSize_];
+    }
+    if (size > 0) {
+      CoinMemcpyN( rhs.structuralStatus_,	(4*nintS), structuralStatus_);
+      artificialStatus_ = structuralStatus_+4*nintS;
+      CoinMemcpyN( rhs.artificialStatus_,	(4*nintA), artificialStatus_);
+    } else {
+      artificialStatus_ = NULL;
+    }
+  }
+  return *this;
+}
+
+// Resizes 
+void 
+CoinWarmStartBasis::resize (int newNumberRows, int newNumberColumns)
+{
+  int i , nCharNewS, nCharOldS, nCharNewA, nCharOldA;
+  if (newNumberRows!=numArtificial_||newNumberColumns!=numStructural_) {
+    nCharOldS  = 4*((numStructural_+15)>>4);
+    int nIntS  = (newNumberColumns+15)>>4;
+    nCharNewS  = 4*nIntS;
+    nCharOldA  = 4*((numArtificial_+15)>>4);
+    int nIntA  = (newNumberRows+15)>>4;
+    nCharNewA  = 4*nIntA;
+    int size = nIntS+nIntA;
+    // Do slowly if number of columns increases or need new array
+    if (newNumberColumns>numStructural_||
+	size>maxSize_) {
+      if (size>maxSize_)
+	maxSize_ = size+10;
+      char * array = new char[4*maxSize_];
+      // zap all for clarity and zerofault etc
+      memset(array,0,4*maxSize_*sizeof(char));
+      CoinMemcpyN(structuralStatus_,(nCharOldS>nCharNewS)?nCharNewS:nCharOldS,array);
+      CoinMemcpyN(artificialStatus_,	     (nCharOldA>nCharNewA)?nCharNewA:nCharOldA,
+                   array+nCharNewS);
+      delete [] structuralStatus_;
+      structuralStatus_ = array;
+      artificialStatus_ = array+nCharNewS;
+      for (i=numStructural_;i<newNumberColumns;i++) 
+	setStructStatus(i, atLowerBound);
+      for (i=numArtificial_;i<newNumberRows;i++) 
+	setArtifStatus(i, basic);
+    } else {
+      // can do faster
+      if (newNumberColumns!=numStructural_) {
+	memmove(structuralStatus_+nCharNewS,artificialStatus_,
+		(nCharOldA>nCharNewA)?nCharNewA:nCharOldA);
+	artificialStatus_ = structuralStatus_+4*nIntS;
+      }
+      for (i=numArtificial_;i<newNumberRows;i++) 
+	setArtifStatus(i, basic);
+    }
+    numStructural_ = newNumberColumns;
+    numArtificial_ = newNumberRows;
+  }
+}
+
+/*
+  compressRows takes an ascending list of target indices without duplicates
+  and removes them, compressing the artificialStatus_ array in place. It will
+  fail spectacularly if the indices are not sorted. Use deleteRows if you
+  need to preprocess the target indices to satisfy the conditions.
+*/
+void CoinWarmStartBasis::compressRows (int tgtCnt, const int *tgts)
+{ 
+  int i,keep,t,blkStart,blkEnd ;
+/*
+  Depending on circumstances, constraint indices may be larger than the size
+  of the basis. Check for that now. Scan from top, betting that in most cases
+  the majority of indices will be valid.
+*/
+  for (t = tgtCnt-1 ; t >= 0 && tgts[t] >= numArtificial_ ; t--) ;
+  // temporary trap to make sure that scan from top is correct choice.
+  // if ((t+1) < tgtCnt/2)
+  // { printf("CWSB: tgtCnt %d, t %d; BAD CASE",tgtCnt,t+1) ; }
+  if (t < 0) return ;
+  tgtCnt = t+1 ;
+  Status stati ;
+
+# ifdef COIN_DEBUG
+/*
+  If we're debugging, scan to see if we're deleting nonbasic artificials.
+  (In other words, are we deleting tight constraints?) Easiest to just do this
+  up front as opposed to integrating it with the loops below.
+*/
+  int nbCnt = 0 ;
+  for (t = 0 ; t < tgtCnt ; t++)
+  { i = tgts[t] ;
+    stati = getStatus(artificialStatus_,i) ;
+    if (stati != CoinWarmStartBasis::basic)
+    { nbCnt++ ; } }
+  if (nbCnt > 0)
+  { std::cout << nbCnt << " nonbasic artificials deleted." << std::endl ; }
+# endif
+
+/*
+  Preserve all entries before the first target. Skip across consecutive
+  target indices to establish the start of the first block to be retained.
+*/
+  keep = tgts[0] ;
+  for (t = 0 ; t < tgtCnt-1 && tgts[t]+1 == tgts[t+1] ; t++) ;
+  blkStart = tgts[t]+1 ;
+/*
+  Outer loop works through the indices to be deleted. Inner loop copies runs
+  of indices to keep.
+*/
+  while (t < tgtCnt-1)
+  { blkEnd = tgts[t+1]-1 ;
+    for (i = blkStart ; i <= blkEnd ; i++)
+    { stati = getStatus(artificialStatus_,i) ;
+      setStatus(artificialStatus_,keep++,stati) ; }
+    for (t++ ; t < tgtCnt-1 && tgts[t]+1 == tgts[t+1] ; t++) ;
+    blkStart = tgts[t]+1 ; }
+/*
+  Finish off by copying from last deleted index to end of status array.
+*/
+  for (i = blkStart ; i < numArtificial_ ; i++)
+  { stati = getStatus(artificialStatus_,i) ;
+    setStatus(artificialStatus_,keep++,stati) ; }
+
+  numArtificial_ -= tgtCnt ;
+
+  return ; }
+
+/*
+  deleteRows takes an unordered list of target indices with duplicates and
+  removes them from the basis. The strategy is to preprocesses the list into
+  an ascending list without duplicates, suitable for compressRows.
+*/
+void 
+CoinWarmStartBasis::deleteRows (int rawTgtCnt, const int *rawTgts)
+{ if (rawTgtCnt <= 0) return ;
+
+  int i;
+  int last=-1;
+  bool ordered=true;
+  for (i=0;i<rawTgtCnt;i++) {
+    int iRow = rawTgts[i];
+    if (iRow>last) {
+      last=iRow;
+    } else {
+      ordered=false;
+      break;
+    }
+  }
+  if (ordered) {
+    compressRows(rawTgtCnt,rawTgts) ;
+  } else {
+    int * tgts = new int[rawTgtCnt] ;
+    CoinMemcpyN(rawTgts,rawTgtCnt,tgts);
+    int *first = &tgts[0] ;
+    int *last = &tgts[rawTgtCnt] ;
+    int *endUnique ;
+    std::sort(first,last) ;
+    endUnique = std::unique(first,last) ;
+    int tgtCnt = static_cast<int>(endUnique-first) ;
+    compressRows(tgtCnt,tgts) ;
+    delete [] tgts ;
+  }
+  return  ; }
+
+// Deletes columns
+void 
+CoinWarmStartBasis::deleteColumns(int number, const int * which)
+{
+  int i ;
+  char * deleted = new char[numStructural_];
+  int numberDeleted=0;
+  memset(deleted,0,numStructural_*sizeof(char));
+  for (i=0;i<number;i++) {
+    int j = which[i];
+    if (j>=0&&j<numStructural_&&!deleted[j]) {
+      numberDeleted++;
+      deleted[j]=1;
+    }
+  }
+  int nCharNewS  = 4*((numStructural_-numberDeleted+15)>>4);
+  int nCharNewA  = 4*((numArtificial_+15)>>4);
+  char * array = new char[4*maxSize_];
+# ifdef ZEROFAULT
+  memset(array,0,(4*maxSize_*sizeof(char))) ;
+# endif
+  CoinMemcpyN(artificialStatus_,nCharNewA,array+nCharNewS);
+  int put=0;
+# ifdef COIN_DEBUG
+  int numberBasic=0;
+# endif
+  for (i=0;i<numStructural_;i++) {
+    Status status = getStructStatus(i);
+    if (!deleted[i]) {
+      setStatus(array,put,status) ;
+      put++; }
+#   ifdef COIN_DEBUG
+    else
+    if (status==CoinWarmStartBasis::basic)
+    { numberBasic++ ; }
+#   endif
+  }
+  delete [] structuralStatus_;
+  structuralStatus_ = array;
+  artificialStatus_ = structuralStatus_ + nCharNewS;
+  delete [] deleted;
+  numStructural_ -= numberDeleted;
+#ifdef COIN_DEBUG
+  if (numberBasic)
+    std::cout<<numberBasic<<" basic structurals deleted"<<std::endl;
+#endif
+}
+
+/*
+  Merge the specified entries from the source basis (src) into the target
+  basis (this). For each entry in xferCols, xferRows, first is the source index,
+  second is the target index, and third is the run length.
+  
+  This routine was originally created to solve the problem of correctly
+  expanding an existing basis but can be used in a general context to merge
+  two bases.
+
+  If the xferRows (xferCols) vector is missing, no row (column) information
+  will be transferred from src to tgt.
+*/
+
+void CoinWarmStartBasis::mergeBasis (const CoinWarmStartBasis *src,
+				     const XferVec *xferRows,
+				     const XferVec *xferCols)
+
+{ assert(src) ;
+  int srcCols = src->getNumStructural() ;
+  int srcRows = src->getNumArtificial() ;
+/*
+  Merge the structural variable status.
+*/
+  if (srcCols > 0 && xferCols != NULL)
+  { XferVec::const_iterator xferSpec = xferCols->begin() ;
+    XferVec::const_iterator xferEnd = xferCols->end() ;
+    for ( ; xferSpec != xferEnd ; xferSpec++)
+    { int srcNdx = (*xferSpec).first ;
+      int tgtNdx = (*xferSpec).second ;
+      int runLen = (*xferSpec).third ;
+      assert(srcNdx >= 0 && srcNdx+runLen <= srcCols) ;
+      assert(tgtNdx >= 0 && tgtNdx+runLen <= getNumStructural()) ;
+      for (int i = 0 ; i < runLen ; i++)
+      { CoinWarmStartBasis::Status stat = src->getStructStatus(srcNdx+i) ;
+	setStructStatus(tgtNdx+i,stat) ; } } }
+/*
+  Merge the row (artificial variable) status.
+*/
+  if (srcRows > 0 && xferRows != NULL)
+  { XferVec::const_iterator xferSpec = xferRows->begin() ;
+    XferVec::const_iterator xferEnd = xferRows->end() ;
+    for ( ; xferSpec != xferEnd ; xferSpec++)
+    { int srcNdx = (*xferSpec).first ;
+      int tgtNdx = (*xferSpec).second ;
+      int runLen = (*xferSpec).third ;
+      assert(srcNdx >= 0 && srcNdx+runLen <= srcRows) ;
+      assert(tgtNdx >= 0 && tgtNdx+runLen <= getNumArtificial()) ;
+      for (int i = 0 ; i < runLen ; i++)
+      { CoinWarmStartBasis::Status stat = src->getArtifStatus(srcNdx+i) ;
+	setArtifStatus(tgtNdx+i,stat) ; } } }
+
+  return ; }
+
+// Prints in readable format (for debug)
+void 
+CoinWarmStartBasis::print() const
+{
+  int i ;
+  int numberBasic=0;
+  for (i=0;i<numStructural_;i++) {
+    Status status = getStructStatus(i);
+    if (status==CoinWarmStartBasis::basic) 
+      numberBasic++;
+  }
+  int numberStructBasic = numberBasic;
+  for (i=0;i<numArtificial_;i++) {
+    Status status = getArtifStatus(i);
+    if (status==CoinWarmStartBasis::basic) 
+      numberBasic++;
+  }
+  std::cout<<"Basis "<<this<<" has "<<numArtificial_<<" rows and "
+	   <<numStructural_<<" columns, "
+	   <<numberBasic<<" basic, of which "<<numberStructBasic
+	   <<" were columns"<<std::endl;
+  std::cout<<"Rows:"<<std::endl;
+  char type[]={'F','B','U','L'};
+
+  for (i=0;i<numArtificial_;i++) 
+    std::cout<<type[getArtifStatus(i)];
+  std::cout<<std::endl;
+  std::cout<<"Columns:"<<std::endl;
+
+  for (i=0;i<numStructural_;i++) 
+    std::cout<<type[getStructStatus(i)];
+  std::cout<<std::endl;
+}
+CoinWarmStartBasis::CoinWarmStartBasis()
+{
+  
+  numStructural_ = 0;
+  numArtificial_ = 0;
+  maxSize_ = 0;
+  structuralStatus_ = NULL;
+  artificialStatus_ = NULL;
+}
+CoinWarmStartBasis::~CoinWarmStartBasis()
+{
+  delete[] structuralStatus_;
+}
+// Returns number of basic structurals
+int
+CoinWarmStartBasis::numberBasicStructurals() const
+{
+  int i ;
+  int numberBasic=0;
+  for (i=0;i<numStructural_;i++) {
+    Status status = getStructStatus(i);
+    if (status==CoinWarmStartBasis::basic) 
+      numberBasic++;
+  }
+  return numberBasic;
+}
+// Returns true if full basis (for debug)
+bool 
+CoinWarmStartBasis::fullBasis() const
+{
+  int i ;
+  int numberBasic=0;
+  for (i=0;i<numStructural_;i++) {
+    Status status = getStructStatus(i);
+    if (status==CoinWarmStartBasis::basic) 
+      numberBasic++;
+  }
+  for (i=0;i<numArtificial_;i++) {
+    Status status = getArtifStatus(i);
+    if (status==CoinWarmStartBasis::basic) 
+      numberBasic++;
+  }
+#ifdef COIN_DEVELOP
+  if (numberBasic!=numArtificial_)
+    printf("mismatch - basis has %d rows, %d basic\n",
+	   numArtificial_,numberBasic);
+#endif
+  return numberBasic==numArtificial_;
+}
+// Returns true if full basis and fixes up (for debug)
+bool 
+CoinWarmStartBasis::fixFullBasis() 
+{
+  int i ;
+  int numberBasic=0;
+  for (i=0;i<numStructural_;i++) {
+    Status status = getStructStatus(i);
+    if (status==CoinWarmStartBasis::basic) 
+      numberBasic++;
+  }
+  for (i=0;i<numArtificial_;i++) {
+    Status status = getArtifStatus(i);
+    if (status==CoinWarmStartBasis::basic) 
+      numberBasic++;
+  }
+#ifdef COIN_DEVELOP
+  if (numberBasic!=numArtificial_)
+    printf("mismatch - basis has %d rows, %d basic\n",
+	   numArtificial_,numberBasic);
+#endif
+  bool returnCode = (numberBasic==numArtificial_);
+  if (numberBasic>numArtificial_) {
+    for (i=0;i<numStructural_;i++) {
+      Status status = getStructStatus(i);
+      if (status==CoinWarmStartBasis::basic) 
+	setStructStatus(i,atLowerBound);
+	numberBasic--;
+	if (numberBasic==numArtificial_)
+	  break;
+    }
+  } else if (numberBasic<numArtificial_) {
+    for (i=0;i<numArtificial_;i++) {
+      Status status = getArtifStatus(i);
+      if (status!=CoinWarmStartBasis::basic) {
+	setArtifStatus(i,basic);
+	numberBasic++;
+	if (numberBasic==numArtificial_)
+	  break;
+      }
+    }
+  }
+  return returnCode;
+}
+/*
+  Generate a diff that'll convert oldCWS into the basis pointed to by this.
+
+  This routine is a bit of a hack, for efficiency's sake. Rather than work
+  with individual status vector entries, we're going to treat the vectors as
+  int's --- in effect, we create one diff entry for each block of 16 status
+  entries. Diffs for logicals are tagged with 0x80000000.
+*/
+
+CoinWarmStartDiff*
+CoinWarmStartBasis::generateDiff (const CoinWarmStart *const oldCWS) const
+{
+/*
+  Make sure the parameter is CoinWarmStartBasis or derived class.
+*/
+  const CoinWarmStartBasis *oldBasis =
+      dynamic_cast<const CoinWarmStartBasis *>(oldCWS) ;
+#ifndef NDEBUG 
+  if (!oldBasis)
+  { throw CoinError("Old basis not derived from CoinWarmStartBasis.",
+		    "generateDiff","CoinWarmStartBasis") ; }
+#endif
+  const CoinWarmStartBasis *newBasis = this ;
+/*
+  Make sure newBasis is equal or bigger than oldBasis. Calculate the worst case
+  number of diffs and allocate vectors to hold them.
+*/
+  const int oldArtifCnt = oldBasis->getNumArtificial() ;
+  const int oldStructCnt = oldBasis->getNumStructural() ;
+  const int newArtifCnt = newBasis->getNumArtificial() ;
+  const int newStructCnt = newBasis->getNumStructural() ;
+
+  assert(newArtifCnt >= oldArtifCnt) ;
+  assert(newStructCnt >= oldStructCnt) ;
+
+  int sizeOldArtif = (oldArtifCnt+15)>>4 ;
+  int sizeNewArtif = (newArtifCnt+15)>>4 ;
+  int sizeOldStruct = (oldStructCnt+15)>>4 ;
+  int sizeNewStruct = (newStructCnt+15)>>4 ;
+  int maxBasisLength = sizeNewArtif+sizeNewStruct ;
+
+  unsigned int *diffNdx = new unsigned int [2*maxBasisLength]; 
+  unsigned int *diffVal = diffNdx + maxBasisLength; 
+/*
+  Ok, setup's over. Now scan the logicals (aka artificials, standing in for
+  constraints). For the portion of the status arrays which overlap, create
+  diffs. Then add any additional status from newBasis.
+
+  I removed the following bit of code & comment:
+
+    if (sizeNew == sizeOld) sizeOld--; // make sure all taken
+
+  I assume this is meant to trap cases where oldBasis does not occupy all of
+  the final int, but I can't see where it's necessary.
+*/
+  const unsigned int *oldStatus =
+      reinterpret_cast<const unsigned int *>(oldBasis->getArtificialStatus()) ;
+  const unsigned int *newStatus = 
+      reinterpret_cast<const unsigned int *>(newBasis->getArtificialStatus()) ;
+  int numberChanged = 0 ;
+  int i ;
+  for (i = 0 ; i < sizeOldArtif ; i++)
+  { if (oldStatus[i] != newStatus[i])
+    { diffNdx[numberChanged] = i|0x80000000 ;
+      diffVal[numberChanged++] = newStatus[i] ; } }
+  for ( ; i < sizeNewArtif ; i++)
+  { diffNdx[numberChanged] = i|0x80000000 ;
+    diffVal[numberChanged++] = newStatus[i] ; }
+/*
+  Repeat for structural variables.
+*/
+  oldStatus =
+      reinterpret_cast<const unsigned int *>(oldBasis->getStructuralStatus()) ;
+  newStatus =
+      reinterpret_cast<const unsigned int *>(newBasis->getStructuralStatus()) ;
+  for (i = 0 ; i < sizeOldStruct ; i++)
+  { if (oldStatus[i] != newStatus[i])
+    { diffNdx[numberChanged] = i ;
+      diffVal[numberChanged++] = newStatus[i] ; } }
+  for ( ; i < sizeNewStruct ; i++)
+  { diffNdx[numberChanged] = i ;
+    diffVal[numberChanged++] = newStatus[i] ; }
+/*
+  Create the object of our desire.
+*/
+  CoinWarmStartBasisDiff *diff;
+  if ((numberChanged*2<maxBasisLength+1||!newStructCnt)&&true)
+    diff = new CoinWarmStartBasisDiff(numberChanged,diffNdx,diffVal) ;
+  else
+    diff = new CoinWarmStartBasisDiff(newBasis) ;
+/*
+  Clean up and return.
+*/
+  delete[] diffNdx ;
+
+  return (static_cast<CoinWarmStartDiff *>(diff)) ; }
+
+
+/*
+  Apply a diff to the basis pointed to by this.  It's assumed that the
+  allocated capacity of the basis is sufficiently large.
+*/
+void CoinWarmStartBasis::applyDiff (const CoinWarmStartDiff *const cwsdDiff)
+{
+/*
+  Make sure we have a CoinWarmStartBasisDiff
+*/
+  const CoinWarmStartBasisDiff *diff =
+    dynamic_cast<const CoinWarmStartBasisDiff *>(cwsdDiff) ;
+#ifndef NDEBUG 
+  if (!diff)
+  { throw CoinError("Diff not derived from CoinWarmStartBasisDiff.",
+		    "applyDiff","CoinWarmStartBasis") ; }
+#endif
+/*
+  Application is by straighforward replacement of words in the status arrays.
+  Index entries for logicals (aka artificials) are tagged with 0x80000000.
+*/
+  const int numberChanges = diff->sze_ ;
+  unsigned int *structStatus =
+    reinterpret_cast<unsigned int *>(this->getStructuralStatus()) ;
+  unsigned int *artifStatus =
+    reinterpret_cast<unsigned int *>(this->getArtificialStatus()) ;
+  if (numberChanges>=0) {
+    const unsigned int *diffNdxs = diff->difference_ ;
+    const unsigned int *diffVals = diffNdxs+numberChanges ;
+    
+    for (int i = 0 ; i < numberChanges ; i++)
+      { unsigned int diffNdx = diffNdxs[i] ;
+      unsigned int diffVal = diffVals[i] ;
+      if ((diffNdx&0x80000000) == 0)
+	{ structStatus[diffNdx] = diffVal ; }
+      else
+	{ artifStatus[diffNdx&0x7fffffff] = diffVal ; } }
+  } else {
+    // just replace
+    const unsigned int * diffA = diff->difference_ -1;
+    const int artifCnt = static_cast<int> (diffA[0]);
+    const int structCnt = -numberChanges;
+    int sizeArtif = (artifCnt+15)>>4 ;
+    int sizeStruct = (structCnt+15)>>4 ;
+    CoinMemcpyN(diffA+1,sizeStruct,structStatus);
+    CoinMemcpyN(diffA+1+sizeStruct,sizeArtif,artifStatus);
+  }
+  return ; }
+
+const char *statusName (CoinWarmStartBasis::Status status) {
+  switch (status) {
+    case CoinWarmStartBasis::isFree: { return ("NBFR") ; }
+    case CoinWarmStartBasis::basic: { return ("B") ; }
+    case CoinWarmStartBasis::atUpperBound: { return ("NBUB") ; }
+    case CoinWarmStartBasis::atLowerBound: { return ("NBLB") ; }
+    default: { return ("INVALID!") ; }
+  }
+}
+
+/* Routines for CoinWarmStartBasisDiff */
+
+/*
+  Constructor given diff data.
+*/
+CoinWarmStartBasisDiff::CoinWarmStartBasisDiff (int sze,
+  const unsigned int *const diffNdxs, const unsigned int *const diffVals)
+  : sze_(sze),
+    difference_(NULL)
+
+{ if (sze > 0)
+  { difference_ = new unsigned int[2*sze] ;
+    CoinMemcpyN(diffNdxs,sze,difference_);
+    CoinMemcpyN(diffVals,sze,difference_+sze_); }
+  
+  return ; }
+/*
+  Constructor when full is smaller than diff!
+*/
+CoinWarmStartBasisDiff::CoinWarmStartBasisDiff (const CoinWarmStartBasis * rhs)
+  : sze_(0),
+    difference_(0)
+{
+  const int artifCnt = rhs->getNumArtificial() ;
+  const int structCnt = rhs->getNumStructural() ;
+  int sizeArtif = (artifCnt+15)>>4 ;
+  int sizeStruct = (structCnt+15)>>4 ;
+  int maxBasisLength = sizeArtif+sizeStruct ;
+  assert (maxBasisLength&&structCnt);
+  sze_ = - structCnt;
+  difference_ = new unsigned int [maxBasisLength+1];
+  difference_[0]=artifCnt;
+  difference_++;
+  CoinMemcpyN(reinterpret_cast<const unsigned int *> (rhs->getStructuralStatus()),sizeStruct,
+	      difference_);
+  CoinMemcpyN(reinterpret_cast<const unsigned int *> (rhs->getArtificialStatus()),sizeArtif,
+	      difference_+sizeStruct);
+}
+
+/*
+  Copy constructor.
+*/
+
+CoinWarmStartBasisDiff::CoinWarmStartBasisDiff
+  (const CoinWarmStartBasisDiff &rhs)
+  : sze_(rhs.sze_),
+    difference_(0)
+{ if (sze_ >0)
+    { difference_ = CoinCopyOfArray(rhs.difference_,2*sze_); }
+  else if (sze_<0) {
+    const unsigned int * diff = rhs.difference_ -1;
+    const int artifCnt = static_cast<int> (diff[0]);
+    const int structCnt = -sze_;
+    int sizeArtif = (artifCnt+15)>>4 ;
+    int sizeStruct = (structCnt+15)>>4 ;
+    int maxBasisLength = sizeArtif+sizeStruct ;
+    difference_ = CoinCopyOfArray(diff,maxBasisLength+1);
+    difference_++;
+  }
+
+  return ; }
+
+/*
+  Assignment --- for convenience when assigning objects containing
+  CoinWarmStartBasisDiff objects.
+*/
+CoinWarmStartBasisDiff&
+CoinWarmStartBasisDiff::operator= (const CoinWarmStartBasisDiff &rhs)
+
+{ if (this != &rhs)
+  { if (sze_>0 )
+      { delete[] difference_ ; }
+      else if (sze_<0) {
+	unsigned int * diff = difference_ -1;
+	delete [] diff;
+      }
+    sze_ = rhs.sze_ ;
+    if (sze_ > 0)
+      { difference_ = CoinCopyOfArray(rhs.difference_,2*sze_); }
+    else if (sze_<0) {
+      const unsigned int * diff = rhs.difference_ -1;
+      const int artifCnt = static_cast<int> (diff[0]);
+      const int structCnt = -sze_;
+      int sizeArtif = (artifCnt+15)>>4 ;
+      int sizeStruct = (structCnt+15)>>4 ;
+      int maxBasisLength = sizeArtif+sizeStruct ;
+      difference_ = CoinCopyOfArray(diff,maxBasisLength+1);
+      difference_++;
+    }
+    else
+    { difference_ = 0 ; } }
+  
+  return (*this) ; }
+/*brief Destructor */
+CoinWarmStartBasisDiff::~CoinWarmStartBasisDiff()
+{
+  if (sze_>0 ) {
+    delete[] difference_ ;
+  } else if (sze_<0) {
+    unsigned int * diff = difference_ -1;
+    delete [] diff;
+  }
+}
diff --git a/cbits/coin/CoinWarmStartBasis.hpp b/cbits/coin/CoinWarmStartBasis.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStartBasis.hpp
@@ -0,0 +1,456 @@
+/* $Id: CoinWarmStartBasis.hpp 1515 2011-12-10 23:38:04Z lou $ */
+/*! \legal
+  Copyright (C) 2000 -- 2003, International Business Machines Corporation
+  and others.  All Rights Reserved.
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+
+/*! \file CoinWarmStart.hpp
+    \brief Declaration of the generic simplex (basis-oriented) warm start
+	   class. Also contains a basis diff class.
+*/
+
+#ifndef CoinWarmStartBasis_H
+#define CoinWarmStartBasis_H
+
+#include <vector>
+
+#include "CoinSort.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinWarmStart.hpp"
+
+//#############################################################################
+
+/*! \class CoinWarmStartBasis
+    \brief The default COIN simplex (basis-oriented) warm start class
+    
+    CoinWarmStartBasis provides for a warm start object which contains the
+    status of each variable (structural and artificial).
+
+    \todo Modify this class so that the number of status entries per byte
+	  and bytes per status vector allocation unit are not hardcoded.
+	  At the least, collect this into a couple of macros.
+    
+    \todo Consider separate fields for allocated capacity and actual basis
+	  size. We could avoid some reallocation, at the price of retaining
+	  more space than we need. Perhaps more important, we could do much
+	  better sanity checks.
+*/
+
+class CoinWarmStartBasis : public virtual CoinWarmStart {
+public:
+
+  /*! \brief Enum for status of variables
+
+    Matches CoinPrePostsolveMatrix::Status, without superBasic. Most code that
+    converts between CoinPrePostsolveMatrix::Status and
+    CoinWarmStartBasis::Status will break if this correspondence is broken.
+
+    The status vectors are currently packed using two bits per status code,
+    four codes per byte. The location of the status information for
+    variable \c i is in byte <code>i>>2</code> and occupies bits 0:1
+    if <code>i\%4 == 0</code>, bits 2:3 if <code>i\%4 == 1</code>, etc.
+    The non-member functions getStatus(const char*,int) and
+    setStatus(char*,int,CoinWarmStartBasis::Status) are provided to hide
+    details of the packing.
+  */
+  enum Status {
+    isFree = 0x00,		///< Nonbasic free variable
+    basic = 0x01,		///< Basic variable
+    atUpperBound = 0x02,	///< Nonbasic at upper bound
+    atLowerBound = 0x03		///< Nonbasic at lower bound
+  };
+
+  /** \brief Transfer vector entry for
+	 mergeBasis(const CoinWarmStartBasis*,const XferVec*,const XferVec*)
+  */
+  typedef CoinTriple<int,int,int> XferEntry ;
+
+  /** \brief Transfer vector for
+	 mergeBasis(const CoinWarmStartBasis*,const XferVec*,const XferVec*)
+  */
+  typedef std::vector<XferEntry> XferVec ;
+
+public:
+
+/*! \name Methods to get and set basis information.
+
+  The status of variables is kept in a pair of arrays, one for structural
+  variables, and one for artificials (aka logicals and slacks). The status
+  is coded using the values of the Status enum.
+
+  \sa CoinWarmStartBasis::Status for a description of the packing used in
+  the status arrays.
+*/
+//@{
+  /// Return the number of structural variables
+  inline int getNumStructural() const { return numStructural_; }
+
+  /// Return the number of artificial variables
+  inline int getNumArtificial() const { return numArtificial_; }
+
+  /** Return the number of basic structurals
+  
+    A fast test for an all-slack basis.
+  */
+  int numberBasicStructurals() const ;
+
+  /// Return the status of the specified structural variable.
+  inline Status getStructStatus(int i) const {
+    const int st = (structuralStatus_[i>>2] >> ((i&3)<<1)) & 3;
+    return static_cast<CoinWarmStartBasis::Status>(st);
+  }
+
+  /// Set the status of the specified structural variable.
+  inline void setStructStatus(int i, Status st) {
+    char& st_byte = structuralStatus_[i>>2];
+    st_byte = static_cast<char>(st_byte & ~(3 << ((i&3)<<1))) ;
+    st_byte = static_cast<char>(st_byte | (st << ((i&3)<<1))) ;
+  }
+
+  /** Return the status array for the structural variables
+  
+    The status information is stored using the codes defined in the
+    Status enum, 2 bits per variable, packed 4 variables per byte.
+  */
+  inline char * getStructuralStatus() { return structuralStatus_; }
+
+  /** \c const overload for
+    \link CoinWarmStartBasis::getStructuralStatus()
+    	  getStructuralStatus()
+    \endlink
+  */
+  inline const char * getStructuralStatus() const { return structuralStatus_; }
+
+  /** As for \link getStructuralStatus() getStructuralStatus \endlink,
+      but returns the status array for the artificial variables.
+  */
+  inline char * getArtificialStatus() { return artificialStatus_; }
+
+  /// Return the status of the specified artificial variable.
+  inline Status getArtifStatus(int i) const {
+    const int st = (artificialStatus_[i>>2] >> ((i&3)<<1)) & 3;
+    return static_cast<CoinWarmStartBasis::Status>(st);
+  }
+
+  /// Set the status of the specified artificial variable.
+  inline void setArtifStatus(int i, Status st) {
+    char& st_byte = artificialStatus_[i>>2];
+    st_byte = static_cast<char>(st_byte & ~(3 << ((i&3)<<1))) ;
+    st_byte = static_cast<char>(st_byte | (st << ((i&3)<<1))) ;
+  }
+
+  /** \c const overload for
+    \link CoinWarmStartBasis::getArtificialStatus()
+    	  getArtificialStatus()
+    \endlink
+  */
+  inline const char * getArtificialStatus() const { return artificialStatus_; }
+
+//@}
+
+/*! \name Basis `diff' methods */
+//@{
+
+  /*! \brief Generate a `diff' that can convert the warm start basis passed as
+	     a parameter to the warm start basis specified by \c this.
+
+    The capabilities are limited: the basis passed as a parameter can be no
+    larger than the basis pointed to by \c this.
+  */
+
+  virtual CoinWarmStartDiff*
+  generateDiff (const CoinWarmStart *const oldCWS) const ;
+
+  /*! \brief Apply \p diff to this basis
+
+    Update this basis by applying \p diff. It's assumed that the allocated
+    capacity of the basis is sufficiently large.
+  */
+
+  virtual void
+  applyDiff (const CoinWarmStartDiff *const cwsdDiff) ;
+
+//@}
+
+
+/*! \name Methods to modify the warm start object */
+//@{
+
+  /*! \brief Set basis capacity; existing basis is discarded.
+
+    After execution of this routine, the warm start object does not describe
+    a valid basis: all structural and artificial variables have status isFree.
+  */
+  virtual void setSize(int ns, int na) ;
+
+  /*! \brief Set basis capacity; existing basis is maintained.
+
+    After execution of this routine, the warm start object describes a valid
+    basis: the status of new structural variables (added columns) is set to
+    nonbasic at lower bound, and the status of new artificial variables
+    (added rows) is set to basic. (The basis can be invalid if new structural
+    variables do not have a finite lower bound.)
+  */
+  virtual void resize (int newNumberRows, int newNumberColumns);
+
+  /** \brief Delete a set of rows from the basis
+
+    \warning
+    This routine assumes that the set of indices to be deleted is sorted in
+    ascending order and contains no duplicates. Use deleteRows() if this is
+    not the case.
+
+    \warning
+    The resulting basis is guaranteed valid only if all deleted
+    constraints are slack (hence the associated logicals are basic).
+
+    Removal of a tight constraint with a nonbasic logical implies that
+    some basic variable must be made nonbasic. This correction is left to
+    the client.
+  */
+
+  virtual void compressRows (int tgtCnt, const int *tgts) ;
+
+  /** \brief Delete a set of rows from the basis
+
+    \warning
+    The resulting basis is guaranteed valid only if all deleted
+    constraints are slack (hence the associated logicals are basic).
+
+    Removal of a tight constraint with a nonbasic logical implies that
+    some basic variable must be made nonbasic. This correction is left to
+    the client.
+  */
+
+  virtual void deleteRows(int rawTgtCnt, const int *rawTgts) ;
+
+  /** \brief Delete a set of columns from the basis
+
+    \warning
+    The resulting basis is guaranteed valid only if all deleted variables
+    are nonbasic.
+
+    Removal of a basic variable implies that some nonbasic variable must be
+    made basic. This correction is left to the client.
+ */
+
+  virtual void deleteColumns(int number, const int * which);
+
+  /** \brief Merge entries from a source basis into this basis.
+
+    \warning
+    It's the client's responsibility to ensure validity of the merged basis,
+    if that's important to the application.
+
+    The vector xferCols (xferRows) specifies runs of entries to be taken from
+    the source basis and placed in this basis. Each entry is a CoinTriple,
+    with first specifying the starting source index of a run, second
+    specifying the starting destination index, and third specifying the run
+    length.
+  */
+  virtual void mergeBasis(const CoinWarmStartBasis *src,
+			  const XferVec *xferRows,
+			  const XferVec *xferCols) ;
+
+//@}
+
+/*! \name Constructors, destructors, and related functions */
+
+//@{
+
+  /** Default constructor
+
+    Creates a warm start object representing an empty basis
+    (0 rows, 0 columns).
+  */
+  CoinWarmStartBasis();
+
+  /** Constructs a warm start object with the specified status vectors.
+
+    The parameters are copied.
+    Consider assignBasisStatus(int,int,char*&,char*&) if the object should
+    assume ownership.
+
+    \sa CoinWarmStartBasis::Status for a description of the packing used in
+    the status arrays.
+  */
+  CoinWarmStartBasis(int ns, int na, const char* sStat, const char* aStat) ;
+
+  /** Copy constructor */
+  CoinWarmStartBasis(const CoinWarmStartBasis& ws) ;
+
+  /** `Virtual constructor' */
+  virtual CoinWarmStart *clone() const
+  {
+     return new CoinWarmStartBasis(*this);
+  }
+
+  /** Destructor */
+  virtual ~CoinWarmStartBasis();
+
+  /** Assignment */
+
+  virtual CoinWarmStartBasis& operator=(const CoinWarmStartBasis& rhs) ;
+
+  /** Assign the status vectors to be the warm start information.
+  
+      In this method the CoinWarmStartBasis object assumes ownership of the
+      pointers and upon return the argument pointers will be NULL.
+      If copying is desirable, use the
+      \link CoinWarmStartBasis(int,int,const char*,const char*)
+	    array constructor \endlink
+      or the
+      \link operator=(const CoinWarmStartBasis&)
+	    assignment operator \endlink.
+
+      \note
+      The pointers passed to this method will be
+      freed using delete[], so they must be created using new[].
+  */
+  virtual void assignBasisStatus(int ns, int na, char*& sStat, char*& aStat) ;
+//@}
+
+/*! \name Miscellaneous methods */
+//@{
+
+  /// Prints in readable format (for debug)
+  virtual void print() const;
+  /// Returns true if full basis (for debug)
+  bool fullBasis() const;
+  /// Returns true if full basis and fixes up (for debug)
+  bool fixFullBasis();
+
+//@}
+
+protected:
+  /** \name Protected data members
+
+    \sa CoinWarmStartBasis::Status for a description of the packing used in
+    the status arrays.
+  */
+  //@{
+    /// The number of structural variables
+    int numStructural_;
+    /// The number of artificial variables
+    int numArtificial_;
+    /// The maximum sise (in ints - actually 4*char) (so resize does not need to do new)
+    int maxSize_;
+    /** The status of the structural variables. */
+    char * structuralStatus_;
+    /** The status of the artificial variables. */
+    char * artificialStatus_;
+  //@}
+};
+
+
+/*! \relates CoinWarmStartBasis
+    \brief Get the status of the specified variable in the given status array.
+*/
+
+inline CoinWarmStartBasis::Status getStatus(const char *array, int i)  {
+  const int st = (array[i>>2] >> ((i&3)<<1)) & 3;
+  return static_cast<CoinWarmStartBasis::Status>(st);
+}
+
+/*! \relates CoinWarmStartBasis
+    \brief Set the status of the specified variable in the given status array.
+*/
+
+inline void setStatus(char * array, int i, CoinWarmStartBasis::Status st) {
+  char& st_byte = array[i>>2];
+  st_byte = static_cast<char>(st_byte & ~(3 << ((i&3)<<1))) ;
+  st_byte = static_cast<char>(st_byte | (st << ((i&3)<<1))) ;
+}
+
+/*! \relates CoinWarmStartBasis
+    \brief Generate a print string for a status code
+*/
+const char *statusName(CoinWarmStartBasis::Status status) ;
+
+
+/*! \class CoinWarmStartBasisDiff
+    \brief A `diff' between two CoinWarmStartBasis objects
+
+  This class exists in order to hide from the world the details of
+  calculating and representing a `diff' between two CoinWarmStartBasis
+  objects. For convenience, assignment, cloning, and deletion are visible to
+  the world, and default and copy constructors are made available to derived
+  classes.  Knowledge of the rest of this structure, and of generating and
+  applying diffs, is restricted to the friend functions
+  CoinWarmStartBasis::generateDiff() and CoinWarmStartBasis::applyDiff().
+
+  The actual data structure is an unsigned int vector, #difference_ which
+  starts with indices of changed and then has values starting after #sze_
+
+  \todo This is a pretty generic structure, and vector diff is a pretty generic
+	activity. We should be able to convert this to a template.
+
+  \todo Using unsigned int as the data type for the diff vectors might help
+	to contain the damage when this code is inevitably compiled for 64 bit
+	architectures. But the notion of int as 4 bytes is hardwired into
+	CoinWarmStartBasis, so changes are definitely required.
+*/
+
+class CoinWarmStartBasisDiff : public virtual CoinWarmStartDiff
+{ public:
+
+  /*! \brief `Virtual constructor' */
+  virtual CoinWarmStartDiff *clone() const
+  { CoinWarmStartBasisDiff *cwsbd =  new CoinWarmStartBasisDiff(*this) ;
+    return (dynamic_cast<CoinWarmStartDiff *>(cwsbd)) ; }
+
+  /*! \brief Assignment */
+  virtual
+    CoinWarmStartBasisDiff &operator= (const CoinWarmStartBasisDiff &rhs) ;
+
+  /*! \brief Destructor */
+  virtual ~CoinWarmStartBasisDiff();
+
+  protected:
+
+  /*! \brief Default constructor
+  
+    This is protected (rather than private) so that derived classes can
+    see it when they make <i>their</i> default constructor protected or
+    private.
+  */
+  CoinWarmStartBasisDiff () : sze_(0), difference_(0) { } 
+
+  /*! \brief Copy constructor
+  
+    For convenience when copying objects containing CoinWarmStartBasisDiff
+    objects. But consider whether you should be using #clone() to retain
+    polymorphism.
+
+    This is protected (rather than private) so that derived classes can
+    see it when they make <i>their</i> copy constructor protected or
+    private.
+  */
+  CoinWarmStartBasisDiff (const CoinWarmStartBasisDiff &cwsbd) ;
+
+  /*! \brief Standard constructor */
+  CoinWarmStartBasisDiff (int sze, const unsigned int *const diffNdxs,
+			  const unsigned int *const diffVals) ;
+
+  /*! \brief Constructor when full is smaller than diff!*/
+  CoinWarmStartBasisDiff (const CoinWarmStartBasis * rhs);
+  
+  private:
+
+  friend CoinWarmStartDiff*
+    CoinWarmStartBasis::generateDiff(const CoinWarmStart *const oldCWS) const ;
+  friend void
+    CoinWarmStartBasis::applyDiff(const CoinWarmStartDiff *const diff) ;
+
+  /*! \brief Number of entries (and allocated capacity), in units of \c int. */
+  int sze_ ;
+
+  /*! \brief Array of diff indices and diff values */
+
+  unsigned int *difference_ ;
+
+} ;
+
+
+#endif
diff --git a/cbits/coin/CoinWarmStartDual.cpp b/cbits/coin/CoinWarmStartDual.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStartDual.cpp
@@ -0,0 +1,66 @@
+/* $Id: CoinWarmStartDual.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+
+#include "CoinWarmStartDual.hpp"
+#include <cmath>
+
+//#############################################################################
+
+/*
+  Generate a `diff' that can convert the warm start passed as a parameter to
+  the warm start specified by this.
+
+  The capabilities are limited: the basis passed as a parameter can be no
+  larger than the basis pointed to by this.
+*/
+
+CoinWarmStartDiff*
+CoinWarmStartDual::generateDiff (const CoinWarmStart *const oldCWS) const
+{ 
+/*
+  Make sure the parameter is CoinWarmStartDual or derived class.
+*/
+  const CoinWarmStartDual *oldDual =
+      dynamic_cast<const CoinWarmStartDual *>(oldCWS) ;
+  if (!oldDual)
+  { throw CoinError("Old warm start not derived from CoinWarmStartDual.",
+		    "generateDiff","CoinWarmStartDual") ; }
+
+  CoinWarmStartDualDiff* diff = new CoinWarmStartDualDiff;
+  CoinWarmStartDiff* vecdiff = dual_.generateDiff(&oldDual->dual_);
+  diff->diff_.swap(*dynamic_cast<CoinWarmStartVectorDiff<double>*>(vecdiff));
+  delete vecdiff;
+
+  return diff;
+}
+
+//=============================================================================
+/*
+  Apply diff to this warm start.
+
+  Update this warm start by applying diff. It's assumed that the
+  allocated capacity of the warm start is sufficiently large.
+*/
+
+void CoinWarmStartDual::applyDiff (const CoinWarmStartDiff *const cwsdDiff)
+{
+/*
+  Make sure we have a CoinWarmStartDualDiff
+*/
+  const CoinWarmStartDualDiff *diff =
+    dynamic_cast<const CoinWarmStartDualDiff *>(cwsdDiff) ;
+  if (!diff)
+  { throw CoinError("Diff not derived from CoinWarmStartDualDiff.",
+		    "applyDiff","CoinWarmStartDual") ; }
+
+  dual_.applyDiff(&diff->diff_);
+}
diff --git a/cbits/coin/CoinWarmStartDual.hpp b/cbits/coin/CoinWarmStartDual.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStartDual.hpp
@@ -0,0 +1,166 @@
+/* $Id: CoinWarmStartDual.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinWarmStartDual_H
+#define CoinWarmStartDual_H
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinWarmStart.hpp"
+#include "CoinWarmStartVector.hpp"
+
+
+//#############################################################################
+
+/** WarmStart information that is only a dual vector */
+
+class CoinWarmStartDual : public virtual CoinWarmStart {
+public:
+   /// return the size of the dual vector
+   inline int size() const { return dual_.size(); }
+   /// return a pointer to the array of duals
+   inline const double * dual() const { return dual_.values(); }
+
+   /** Assign the dual vector to be the warmstart information. In this method
+       the object assumes ownership of the pointer and upon return "dual" will
+       be a NULL pointer. If copying is desirable use the constructor. */
+   inline void assignDual(int size, double *& dual)
+    { dual_.assignVector(size, dual); }
+
+   CoinWarmStartDual() {}
+
+   CoinWarmStartDual(int size, const double * dual) : dual_(size, dual) {}
+
+   CoinWarmStartDual(const CoinWarmStartDual& rhs) : dual_(rhs.dual_) {}
+
+   CoinWarmStartDual& operator=(const CoinWarmStartDual& rhs) {
+     if (this != &rhs) {
+       dual_ = rhs.dual_;
+     }
+     return *this;
+   }
+
+   /** `Virtual constructor' */
+   virtual CoinWarmStart *clone() const {
+      return new CoinWarmStartDual(*this);
+   }
+
+   virtual ~CoinWarmStartDual() {}
+
+/*! \name Dual warm start `diff' methods */
+//@{
+
+  /*! \brief Generate a `diff' that can convert the warm start passed as a
+	     parameter to the warm start specified by \c this.
+
+    The capabilities are limited: the basis passed as a parameter can be no
+    larger than the basis pointed to by \c this.
+  */
+
+  virtual CoinWarmStartDiff*
+  generateDiff (const CoinWarmStart *const oldCWS) const ;
+
+  /*! \brief Apply \p diff to this warm start.
+
+    Update this warm start by applying \p diff. It's assumed that the
+    allocated capacity of the warm start is sufficiently large.
+  */
+
+  virtual void applyDiff (const CoinWarmStartDiff *const cwsdDiff) ;
+
+#if 0
+protected:
+  inline const CoinWarmStartVector<double>& warmStartVector() const { return dual_; }
+#endif
+
+//@}
+
+private:
+   ///@name Private data members
+  CoinWarmStartVector<double> dual_;
+};
+
+//#############################################################################
+
+/*! \class CoinWarmStartDualDiff
+    \brief A `diff' between two CoinWarmStartDual objects
+
+  This class exists in order to hide from the world the details of
+  calculating and representing a `diff' between two CoinWarmStartDual
+  objects. For convenience, assignment, cloning, and deletion are visible to
+  the world, and default and copy constructors are made available to derived
+  classes.  Knowledge of the rest of this structure, and of generating and
+  applying diffs, is restricted to the friend functions
+  CoinWarmStartDual::generateDiff() and CoinWarmStartDual::applyDiff().
+
+  The actual data structure is a pair of vectors, #diffNdxs_ and #diffVals_.
+    
+*/
+
+class CoinWarmStartDualDiff : public virtual CoinWarmStartDiff
+{ public:
+
+  /*! \brief `Virtual constructor' */
+  virtual CoinWarmStartDiff *clone() const
+  {
+      return new CoinWarmStartDualDiff(*this) ;
+  }
+
+  /*! \brief Assignment */
+  virtual CoinWarmStartDualDiff &operator= (const CoinWarmStartDualDiff &rhs)
+  {
+      if (this != &rhs) {
+	  diff_ = rhs.diff_;
+      }
+      return *this;
+  }
+
+  /*! \brief Destructor */
+  virtual ~CoinWarmStartDualDiff() {}
+
+  protected:
+
+  /*! \brief Default constructor
+  
+    This is protected (rather than private) so that derived classes can
+    see it when they make <i>their</i> default constructor protected or
+    private.
+  */
+  CoinWarmStartDualDiff () : diff_() {}
+
+  /*! \brief Copy constructor
+  
+    For convenience when copying objects containing CoinWarmStartDualDiff
+    objects. But consider whether you should be using #clone() to retain
+    polymorphism.
+
+    This is protected (rather than private) so that derived classes can
+    see it when the make <i>their</i> copy constructor protected or
+    private.
+  */
+  CoinWarmStartDualDiff (const CoinWarmStartDualDiff &rhs) :
+      diff_(rhs.diff_) {}
+
+  private:
+
+  friend CoinWarmStartDiff*
+    CoinWarmStartDual::generateDiff(const CoinWarmStart *const oldCWS) const ;
+  friend void
+    CoinWarmStartDual::applyDiff(const CoinWarmStartDiff *const diff) ;
+
+  /*! \brief Standard constructor */
+  CoinWarmStartDualDiff (int sze, const unsigned int *const diffNdxs,
+			 const double *const diffVals) :
+      diff_(sze, diffNdxs, diffVals) {}
+
+  /*!
+      \brief The difference in the dual vector is simply the difference in a
+      vector.
+  */
+  CoinWarmStartVectorDiff<double> diff_;
+};
+
+
+#endif
+
diff --git a/cbits/coin/CoinWarmStartPrimalDual.cpp b/cbits/coin/CoinWarmStartPrimalDual.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStartPrimalDual.cpp
@@ -0,0 +1,73 @@
+/* $Id: CoinWarmStartPrimalDual.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+
+#include "CoinWarmStartPrimalDual.hpp"
+#include <cmath>
+
+//#############################################################################
+
+/*
+  Generate a `diff' that can convert the warm start passed as a parameter to
+  the warm start specified by this.
+
+  The capabilities are limited: the basis passed as a parameter can be no
+  larger than the basis pointed to by this.
+*/
+
+CoinWarmStartDiff*
+CoinWarmStartPrimalDual::generateDiff (const CoinWarmStart *const oldCWS) const
+{ 
+/*
+  Make sure the parameter is CoinWarmStartPrimalDual or derived class.
+*/
+  const CoinWarmStartPrimalDual *old =
+      dynamic_cast<const CoinWarmStartPrimalDual *>(oldCWS) ;
+  if (!old)
+  { throw CoinError("Old warm start not derived from CoinWarmStartPrimalDual.",
+		    "generateDiff","CoinWarmStartPrimalDual") ; }
+
+  CoinWarmStartPrimalDualDiff* diff = new CoinWarmStartPrimalDualDiff;
+  CoinWarmStartDiff* vecdiff;
+  vecdiff = primal_.generateDiff(&old->primal_);
+  diff->primalDiff_.swap(*dynamic_cast<CoinWarmStartVectorDiff<double>*>(vecdiff));
+  delete vecdiff;
+  vecdiff = dual_.generateDiff(&old->dual_);
+  diff->dualDiff_.swap(*dynamic_cast<CoinWarmStartVectorDiff<double>*>(vecdiff));
+  delete vecdiff;
+
+  return diff;
+}
+
+//#############################################################################
+
+/*
+  Apply diff to this warm start.
+
+  Update this warm start by applying diff. It's assumed that the
+  allocated capacity of the warm start is sufficiently large.
+*/
+
+void
+CoinWarmStartPrimalDual::applyDiff (const CoinWarmStartDiff *const cwsdDiff)
+{
+/*
+  Make sure we have a CoinWarmStartPrimalDualDiff
+*/
+  const CoinWarmStartPrimalDualDiff *diff =
+    dynamic_cast<const CoinWarmStartPrimalDualDiff *>(cwsdDiff) ;
+  if (!diff)
+  { throw CoinError("Diff not derived from CoinWarmStartPrimalDualDiff.",
+		    "applyDiff","CoinWarmStartPrimalDual") ; }
+
+  primal_.applyDiff(&diff->primalDiff_);
+  dual_.applyDiff(&diff->dualDiff_);
+}
diff --git a/cbits/coin/CoinWarmStartPrimalDual.hpp b/cbits/coin/CoinWarmStartPrimalDual.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStartPrimalDual.hpp
@@ -0,0 +1,211 @@
+/* $Id: CoinWarmStartPrimalDual.hpp 1372 2011-01-03 23:31:00Z lou $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinWarmStartPrimalDual_H
+#define CoinWarmStartPrimalDual_H
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinWarmStart.hpp"
+#include "CoinWarmStartVector.hpp"
+
+
+//#############################################################################
+
+/** WarmStart information that is only a dual vector */
+
+class CoinWarmStartPrimalDual : public virtual CoinWarmStart {
+public:
+  /// return the size of the dual vector
+  inline int dualSize() const { return dual_.size(); }
+  /// return a pointer to the array of duals
+  inline const double * dual() const { return dual_.values(); }
+
+  /// return the size of the primal vector
+  inline int primalSize() const { return primal_.size(); }
+  /// return a pointer to the array of primals
+  inline const double * primal() const { return primal_.values(); }
+
+  /** Assign the primal/dual vectors to be the warmstart information. In this
+      method the object assumes ownership of the pointers and upon return \c
+      primal and \c dual will be a NULL pointers. If copying is desirable use
+      the constructor.
+
+      NOTE: \c primal and \c dual must have been allocated by new double[],
+      because they will be freed by delete[] upon the desructtion of this
+      object...
+  */
+  void assign(int primalSize, int dualSize, double*& primal, double *& dual) {
+    primal_.assignVector(primalSize, primal);
+    dual_.assignVector(dualSize, dual);
+  }
+
+  CoinWarmStartPrimalDual() : primal_(), dual_() {}
+
+  CoinWarmStartPrimalDual(int primalSize, int dualSize,
+			  const double* primal, const double * dual) :
+    primal_(primalSize, primal), dual_(dualSize, dual) {}
+
+  CoinWarmStartPrimalDual(const CoinWarmStartPrimalDual& rhs) :
+    primal_(rhs.primal_), dual_(rhs.dual_) {}
+
+  CoinWarmStartPrimalDual& operator=(const CoinWarmStartPrimalDual& rhs) {
+    if (this != &rhs) {
+      primal_ = rhs.primal_;
+      dual_ = rhs.dual_;
+    }
+    return *this;
+  }
+
+  /*! \brief Clear the data
+
+  Make it appear as if the warmstart was just created using the default
+  constructor.
+  */
+  inline void clear() {
+    primal_.clear();
+    dual_.clear();
+  }
+
+  inline void swap(CoinWarmStartPrimalDual& rhs) {
+    if (this != &rhs) {
+      primal_.swap(rhs.primal_);
+      dual_.swap(rhs.dual_);
+    }
+  }
+
+  /** `Virtual constructor' */
+  virtual CoinWarmStart *clone() const {
+    return new CoinWarmStartPrimalDual(*this);
+  }
+
+  virtual ~CoinWarmStartPrimalDual() {}
+
+  /*! \name PrimalDual warm start `diff' methods */
+  //@{
+
+  /*! \brief Generate a `diff' that can convert the warm start passed as a
+    parameter to the warm start specified by \c this.
+
+    The capabilities are limited: the basis passed as a parameter can be no
+    larger than the basis pointed to by \c this.
+  */
+
+  virtual CoinWarmStartDiff*
+  generateDiff (const CoinWarmStart *const oldCWS) const ;
+
+  /*! \brief Apply \p diff to this warm start.
+
+  Update this warm start by applying \p diff. It's assumed that the
+  allocated capacity of the warm start is sufficiently large.
+  */
+
+  virtual void applyDiff (const CoinWarmStartDiff *const cwsdDiff) ;
+
+  //@}
+
+#if 0
+protected:
+  inline const CoinWarmStartVector<double>& primalWarmStartVector() const
+  { return primal_; }
+  inline const CoinWarmStartVector<double>& dualWarmStartVector() const
+  { return dual_; }
+#endif
+
+private:
+  ///@name Private data members
+  //@{
+  CoinWarmStartVector<double> primal_;
+  CoinWarmStartVector<double> dual_;
+  //@}
+};
+
+//#############################################################################
+
+/*! \class CoinWarmStartPrimalDualDiff
+  \brief A `diff' between two CoinWarmStartPrimalDual objects
+
+  This class exists in order to hide from the world the details of calculating
+  and representing a `diff' between two CoinWarmStartPrimalDual objects. For
+  convenience, assignment, cloning, and deletion are visible to the world, and
+  default and copy constructors are made available to derived classes.
+  Knowledge of the rest of this structure, and of generating and applying
+  diffs, is restricted to the friend functions
+  CoinWarmStartPrimalDual::generateDiff() and
+  CoinWarmStartPrimalDual::applyDiff().
+
+  The actual data structure is a pair of vectors, #diffNdxs_ and #diffVals_.
+    
+*/
+
+class CoinWarmStartPrimalDualDiff : public virtual CoinWarmStartDiff
+{
+  friend CoinWarmStartDiff*
+  CoinWarmStartPrimalDual::generateDiff(const CoinWarmStart *const oldCWS) const;
+  friend void
+  CoinWarmStartPrimalDual::applyDiff(const CoinWarmStartDiff *const diff) ;
+
+public:
+
+  /*! \brief `Virtual constructor'. To be used when retaining polymorphism is
+    important */
+  virtual CoinWarmStartDiff *clone() const
+  {
+    return new CoinWarmStartPrimalDualDiff(*this);
+  }
+
+  /*! \brief Destructor */
+  virtual ~CoinWarmStartPrimalDualDiff() {}
+
+protected:
+
+  /*! \brief Default constructor
+  
+  This is protected (rather than private) so that derived classes can
+  see it when they make <i>their</i> default constructor protected or
+  private.
+  */
+  CoinWarmStartPrimalDualDiff () : primalDiff_(), dualDiff_() {}
+
+  /*! \brief Copy constructor
+  
+  For convenience when copying objects containing
+  CoinWarmStartPrimalDualDiff objects. But consider whether you should be
+  using #clone() to retain polymorphism.
+
+  This is protected (rather than private) so that derived classes can
+  see it when the make <i>their</i> copy constructor protected or
+  private.
+  */
+  CoinWarmStartPrimalDualDiff (const CoinWarmStartPrimalDualDiff &rhs) :
+    primalDiff_(rhs.primalDiff_), dualDiff_(rhs.dualDiff_) {}
+
+  /*! \brief Clear the data
+
+  Make it appear as if the diff was just created using the default
+  constructor.
+  */
+  inline void clear() {
+    primalDiff_.clear();
+    dualDiff_.clear();
+  }
+
+  inline void swap(CoinWarmStartPrimalDualDiff& rhs) {
+    if (this != &rhs) {
+      primalDiff_.swap(rhs.primalDiff_);
+      dualDiff_.swap(rhs.dualDiff_);
+    }
+  }
+
+private:
+
+  /*!
+    \brief These two differences describe the differences in the primal and
+    in the dual vector.
+  */
+  CoinWarmStartVectorDiff<double> primalDiff_;
+  CoinWarmStartVectorDiff<double> dualDiff_;
+} ;
+
+#endif
diff --git a/cbits/coin/CoinWarmStartVector.cpp b/cbits/coin/CoinWarmStartVector.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStartVector.cpp
@@ -0,0 +1,10 @@
+/* $Id: CoinWarmStartVector.cpp 1373 2011-01-03 23:57:44Z lou $ */
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This lack of code is licensed under the terms of the Eclipse Public License
+// (EPL).
+
+/*
+  Code crammed into CoinWarmStartVector.hpp at r923, 080110.
+  -- lh, 110103 --
+*/
diff --git a/cbits/coin/CoinWarmStartVector.hpp b/cbits/coin/CoinWarmStartVector.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/CoinWarmStartVector.hpp
@@ -0,0 +1,488 @@
+/* $Id: CoinWarmStartVector.hpp 1498 2011-11-02 15:25:35Z mjs $ */
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef CoinWarmStartVector_H
+#define CoinWarmStartVector_H
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <cassert>
+#include <cmath>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinWarmStart.hpp"
+
+
+//#############################################################################
+
+/** WarmStart information that is only a vector */
+
+template <typename T>
+class CoinWarmStartVector : public virtual CoinWarmStart
+{
+protected:
+  inline void gutsOfDestructor() {
+    delete[] values_;
+  }
+  inline void gutsOfCopy(const CoinWarmStartVector<T>& rhs) {
+    size_  = rhs.size_;
+    values_ = new T[size_];
+    CoinDisjointCopyN(rhs.values_, size_, values_);
+  }
+
+public:
+  /// return the size of the vector
+  int size() const { return size_; }
+  /// return a pointer to the array of vectors
+  const T* values() const { return values_; }
+
+  /** Assign the vector to be the warmstart information. In this method
+      the object assumes ownership of the pointer and upon return #vector will
+      be a NULL pointer. If copying is desirable use the constructor. */
+  void assignVector(int size, T*& vec) {
+    size_ = size;
+    delete[] values_;
+    values_ = vec;
+    vec = NULL;
+  }
+
+  CoinWarmStartVector() : size_(0), values_(NULL) {}
+
+  CoinWarmStartVector(int size, const T* vec) :
+    size_(size), values_(new T[size]) {
+    CoinDisjointCopyN(vec, size, values_);
+  }
+
+  CoinWarmStartVector(const CoinWarmStartVector& rhs) {
+    gutsOfCopy(rhs);
+  }
+
+  CoinWarmStartVector& operator=(const CoinWarmStartVector& rhs) {
+    if (this != &rhs) {
+      gutsOfDestructor();
+      gutsOfCopy(rhs);
+    }
+    return *this;
+  }
+
+  inline void swap(CoinWarmStartVector& rhs) {
+    if (this != &rhs) {
+      std::swap(size_, rhs.size_);
+      std::swap(values_, rhs.values_);
+    }
+  }
+
+  /** `Virtual constructor' */
+  virtual CoinWarmStart *clone() const {
+    return new CoinWarmStartVector(*this);
+  }
+     
+  virtual ~CoinWarmStartVector() {
+    gutsOfDestructor();
+  }
+
+  /*! \brief Clear the data
+
+  Make it appear as if the warmstart was just created using the default
+  constructor.
+  */
+  inline void clear() {
+    size_ = 0;
+    delete[] values_;
+    values_ = NULL;
+  }
+
+  /*! \name Vector warm start `diff' methods */
+  //@{
+
+  /*! \brief Generate a `diff' that can convert the warm start passed as a
+    parameter to the warm start specified by \c this.
+
+    The capabilities are limited: the basis passed as a parameter can be no
+    larger than the basis pointed to by \c this.
+  */
+
+  virtual CoinWarmStartDiff*
+  generateDiff (const CoinWarmStart *const oldCWS) const ;
+
+  /*! \brief Apply \p diff to this warm start.
+
+  Update this warm start by applying \p diff. It's assumed that the
+  allocated capacity of the warm start is sufficiently large.
+  */
+
+  virtual void applyDiff (const CoinWarmStartDiff *const cwsdDiff) ;
+
+  //@}
+
+private:
+  ///@name Private data members
+  //@{
+  /// the size of the vector
+  int size_;
+  /// the vector itself
+  T* values_;
+  //@}
+};
+
+//=============================================================================
+
+/*! \class CoinWarmStartVectorDiff
+  \brief A `diff' between two CoinWarmStartVector objects
+
+  This class exists in order to hide from the world the details of calculating
+  and representing a `diff' between two CoinWarmStartVector objects. For
+  convenience, assignment, cloning, and deletion are visible to the world, and
+  default and copy constructors are made available to derived classes.
+  Knowledge of the rest of this structure, and of generating and applying
+  diffs, is restricted to the friend functions
+  CoinWarmStartVector::generateDiff() and CoinWarmStartVector::applyDiff().
+
+  The actual data structure is a pair of vectors, #diffNdxs_ and #diffVals_.
+    
+*/
+
+template <typename T>
+class CoinWarmStartVectorDiff : public virtual CoinWarmStartDiff
+{
+  friend CoinWarmStartDiff*
+  CoinWarmStartVector<T>::generateDiff(const CoinWarmStart *const oldCWS) const;
+  friend void
+  CoinWarmStartVector<T>::applyDiff(const CoinWarmStartDiff *const diff) ;
+
+public:
+
+  /*! \brief `Virtual constructor' */
+  virtual CoinWarmStartDiff * clone() const {
+    return new CoinWarmStartVectorDiff(*this) ;
+  }
+
+  /*! \brief Assignment */
+  virtual CoinWarmStartVectorDiff &
+  operator= (const CoinWarmStartVectorDiff<T>& rhs) ;
+
+  /*! \brief Destructor */
+  virtual ~CoinWarmStartVectorDiff() {
+    delete[] diffNdxs_ ;
+    delete[] diffVals_ ;
+  }
+
+  inline void swap(CoinWarmStartVectorDiff& rhs) {
+    if (this != &rhs) {
+      std::swap(sze_, rhs.sze_);
+      std::swap(diffNdxs_, rhs.diffNdxs_);
+      std::swap(diffVals_, rhs.diffVals_);
+    }
+  }
+
+  /*! \brief Default constructor
+   */
+  CoinWarmStartVectorDiff () : sze_(0), diffNdxs_(0), diffVals_(NULL) {} 
+
+  /*! \brief Copy constructor
+  
+  For convenience when copying objects containing CoinWarmStartVectorDiff
+  objects. But consider whether you should be using #clone() to retain
+  polymorphism.
+  */
+  CoinWarmStartVectorDiff(const CoinWarmStartVectorDiff<T>& rhs) ;
+
+  /*! \brief Standard constructor */
+  CoinWarmStartVectorDiff(int sze, const unsigned int* const diffNdxs,
+			  const T* const diffVals) ;
+  
+  /*! \brief Clear the data
+
+  Make it appear as if the diff was just created using the default
+  constructor.
+  */
+  inline void clear() {
+    sze_ = 0;
+    delete[] diffNdxs_;  diffNdxs_ = NULL;
+    delete[] diffVals_;  diffVals_ = NULL;
+  }
+
+private:
+
+  /*!
+    \brief Number of entries (and allocated capacity), in units of \c T.
+  */
+  int sze_ ;
+
+  /*! \brief Array of diff indices */
+
+  unsigned int* diffNdxs_ ;
+
+  /*! \brief Array of diff values */
+
+  T* diffVals_ ;
+};
+
+//##############################################################################
+
+template <typename T, typename U>
+class CoinWarmStartVectorPair : public virtual CoinWarmStart 
+{
+private:
+  CoinWarmStartVector<T> t_;
+  CoinWarmStartVector<U> u_;
+
+public:
+  inline int size0() const { return t_.size(); }
+  inline int size1() const { return u_.size(); }
+  inline const T* values0() const { return t_.values(); }
+  inline const U* values1() const { return u_.values(); }
+
+  inline void assignVector0(int size, T*& vec) { t_.assignVector(size, vec); }
+  inline void assignVector1(int size, U*& vec) { u_.assignVector(size, vec); }
+
+  CoinWarmStartVectorPair() {}
+  CoinWarmStartVectorPair(int s0, const T* v0, int s1, const U* v1) :
+    t_(s0, v0), u_(s1, v1) {}
+
+  CoinWarmStartVectorPair(const CoinWarmStartVectorPair<T,U>& rhs) :
+    t_(rhs.t_), u_(rhs.u_) {}
+  CoinWarmStartVectorPair& operator=(const CoinWarmStartVectorPair<T,U>& rhs) {
+    if (this != &rhs) {
+      t_ = rhs.t_;
+      u_ = rhs.u_;
+    }	
+    return *this;
+  }
+
+  inline void swap(CoinWarmStartVectorPair<T,U>& rhs) {
+    t_.swap(rhs.t_);
+    u_.swap(rhs.u_);
+  }
+
+  virtual CoinWarmStart *clone() const {
+    return new CoinWarmStartVectorPair(*this);
+  }
+
+  virtual ~CoinWarmStartVectorPair() {}
+
+  inline void clear() {
+    t_.clear();
+    u_.clear();
+  }
+
+  virtual CoinWarmStartDiff*
+  generateDiff (const CoinWarmStart *const oldCWS) const ;
+
+  virtual void applyDiff (const CoinWarmStartDiff *const cwsdDiff) ;
+};
+
+//=============================================================================
+
+template <typename T, typename U>
+class CoinWarmStartVectorPairDiff : public virtual CoinWarmStartDiff
+{
+  friend CoinWarmStartDiff*
+  CoinWarmStartVectorPair<T,U>::generateDiff(const CoinWarmStart *const oldCWS) const;
+  friend void
+  CoinWarmStartVectorPair<T,U>::applyDiff(const CoinWarmStartDiff *const diff) ;
+
+private:
+  CoinWarmStartVectorDiff<T> tdiff_;
+  CoinWarmStartVectorDiff<U> udiff_;
+
+public:
+  CoinWarmStartVectorPairDiff() {}
+  CoinWarmStartVectorPairDiff(const CoinWarmStartVectorPairDiff<T,U>& rhs) :
+    tdiff_(rhs.tdiff_), udiff_(rhs.udiff_) {}
+  virtual ~CoinWarmStartVectorPairDiff() {}
+
+  virtual CoinWarmStartVectorPairDiff&
+  operator=(const CoinWarmStartVectorPairDiff<T,U>& rhs) {
+	  if (this != &rhs) {
+		  tdiff_ = rhs.tdiff_;
+		  udiff_ = rhs.udiff_;
+	  }
+    return *this;
+  }
+
+  virtual CoinWarmStartDiff * clone() const {
+    return new CoinWarmStartVectorPairDiff(*this) ;
+  }
+
+  inline void swap(CoinWarmStartVectorPairDiff<T,U>& rhs) {
+    tdiff_.swap(rhs.tdiff_);
+    udiff_.swap(rhs.udiff_);
+  }
+
+  inline void clear() {
+    tdiff_.clear();
+    udiff_.clear();
+  }
+};
+
+//##############################################################################
+//#############################################################################
+
+/*
+  Generate a `diff' that can convert the warm start passed as a parameter to
+  the warm start specified by this.
+
+  The capabilities are limited: the basis passed as a parameter can be no
+  larger than the basis pointed to by this.
+*/
+
+template <typename T> CoinWarmStartDiff*
+CoinWarmStartVector<T>::generateDiff(const CoinWarmStart *const oldCWS) const
+{ 
+/*
+  Make sure the parameter is CoinWarmStartVector or derived class.
+*/
+  const CoinWarmStartVector<T>* oldVector =
+    dynamic_cast<const CoinWarmStartVector<T>*>(oldCWS);
+  if (!oldVector)
+    { throw CoinError("Old warm start not derived from CoinWarmStartVector.",
+		      "generateDiff","CoinWarmStartVector") ; }
+  const CoinWarmStartVector<T>* newVector = this ;
+  /*
+    Make sure newVector is equal or bigger than oldVector. Calculate the worst
+    case number of diffs and allocate vectors to hold them.
+  */
+  const int oldCnt = oldVector->size() ;
+  const int newCnt = newVector->size() ;
+
+  assert(newCnt >= oldCnt) ;
+
+  unsigned int *diffNdx = new unsigned int [newCnt]; 
+  T* diffVal = new T[newCnt]; 
+  /*
+    Scan the vector vectors.  For the portion of the vectors which overlap,
+    create diffs. Then add any additional entries from newVector.
+  */
+  const T*oldVal = oldVector->values() ;
+  const T*newVal = newVector->values() ;
+  int numberChanged = 0 ;
+  int i ;
+  for (i = 0 ; i < oldCnt ; i++) {
+    if (oldVal[i] != newVal[i]) {
+      diffNdx[numberChanged] = i ;
+      diffVal[numberChanged++] = newVal[i] ;
+    }
+  }
+  for ( ; i < newCnt ; i++) {
+    diffNdx[numberChanged] = i ;
+    diffVal[numberChanged++] = newVal[i] ;
+  }
+  /*
+    Create the object of our desire.
+  */
+  CoinWarmStartVectorDiff<T> *diff =
+    new CoinWarmStartVectorDiff<T>(numberChanged,diffNdx,diffVal) ;
+  /*
+    Clean up and return.
+  */
+  delete[] diffNdx ;
+  delete[] diffVal ;
+
+  return diff;
+  //  return (dynamic_cast<CoinWarmStartDiff<T>*>(diff)) ;
+}
+
+
+/*
+  Apply diff to this warm start.
+  
+  Update this warm start by applying diff. It's assumed that the
+  allocated capacity of the warm start is sufficiently large.
+*/
+
+template <typename T> void
+CoinWarmStartVector<T>::applyDiff (const CoinWarmStartDiff *const cwsdDiff)
+{
+  /*
+    Make sure we have a CoinWarmStartVectorDiff
+  */
+  const CoinWarmStartVectorDiff<T>* diff =
+    dynamic_cast<const CoinWarmStartVectorDiff<T>*>(cwsdDiff) ;
+  if (!diff) {
+    throw CoinError("Diff not derived from CoinWarmStartVectorDiff.",
+		    "applyDiff","CoinWarmStartVector") ;
+  }
+  /*
+    Application is by straighforward replacement of words in the vector vector.
+  */
+  const int numberChanges = diff->sze_ ;
+  const unsigned int *diffNdxs = diff->diffNdxs_ ;
+  const T* diffVals = diff->diffVals_ ;
+  T* vals = this->values_ ;
+
+  for (int i = 0 ; i < numberChanges ; i++) {
+    unsigned int diffNdx = diffNdxs[i] ;
+    T diffVal = diffVals[i] ;
+    vals[diffNdx] = diffVal ;
+  }
+}
+
+//#############################################################################
+
+
+// Assignment
+
+template <typename T> CoinWarmStartVectorDiff<T>&
+CoinWarmStartVectorDiff<T>::operator=(const CoinWarmStartVectorDiff<T> &rhs)
+{
+  if (this != &rhs) {
+    if (sze_ > 0) {
+      delete[] diffNdxs_ ;
+      delete[] diffVals_ ;
+    }
+    sze_ = rhs.sze_ ;
+    if (sze_ > 0) {
+      diffNdxs_ = new unsigned int[sze_] ;
+      memcpy(diffNdxs_,rhs.diffNdxs_,sze_*sizeof(unsigned int)) ;
+      diffVals_ = new T[sze_] ;
+      memcpy(diffVals_,rhs.diffVals_,sze_*sizeof(T)) ;
+    } else {
+      diffNdxs_ = 0 ;
+      diffVals_ = 0 ;
+    }
+  }
+
+  return (*this) ;
+}
+
+
+// Copy constructor
+
+template <typename T>
+CoinWarmStartVectorDiff<T>::CoinWarmStartVectorDiff(const CoinWarmStartVectorDiff<T> &rhs)
+  : sze_(rhs.sze_),
+    diffNdxs_(0),
+    diffVals_(0)
+{
+  if (sze_ > 0) {
+    diffNdxs_ = new unsigned int[sze_] ;
+    memcpy(diffNdxs_,rhs.diffNdxs_,sze_*sizeof(unsigned int)) ;
+    diffVals_ = new T[sze_] ;
+    memcpy(diffVals_,rhs.diffVals_,sze_*sizeof(T)) ;
+  }
+}
+
+/// Standard constructor
+
+template <typename T>
+CoinWarmStartVectorDiff<T>::CoinWarmStartVectorDiff
+(int sze, const unsigned int *const diffNdxs, const T *const diffVals)
+  : sze_(sze),
+    diffNdxs_(0),
+    diffVals_(0)
+{
+  if (sze > 0) {
+    diffNdxs_ = new unsigned int[sze] ;
+    memcpy(diffNdxs_,diffNdxs,sze*sizeof(unsigned int)) ;
+    diffVals_ = new T[sze] ;
+    memcpy(diffVals_,diffVals,sze*sizeof(T)) ;
+  }
+}
+
+#endif
diff --git a/cbits/coin/Coin_C_defines.h b/cbits/coin/Coin_C_defines.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Coin_C_defines.h
@@ -0,0 +1,115 @@
+/* $Id: Coin_C_defines.h 1419 2011-04-29 17:39:07Z stefan $ */
+/*
+  Copyright (C) 2002, 2003 International Business Machines Corporation
+  and others.  All Rights Reserved.
+
+  This code is licensed under the terms of the Eclipse Public License (EPL).
+*/
+#ifndef CoinCDefine_H
+#define CoinCDefine_H
+
+/** This has #defines etc for the "C" interface to Coin.
+    If COIN_EXTERN_C defined then an extra extern C
+*/
+
+#if defined (CLP_EXTERN_C)
+#define COIN_EXTERN_C
+#define COIN_NO_SBB
+#define COIN_NO_CBC
+#endif
+#if defined (SBB_EXTERN_C)
+#define COIN_EXTERN_C
+#define COIN_NO_CLP
+#endif
+#if defined (CBC_EXTERN_C)
+#define COIN_EXTERN_C
+#define COIN_NO_CLP
+#endif
+/* We need to allow for Microsoft */
+#ifndef COINLIBAPI
+
+#if defined(CBCCINTERFACEDLL_EXPORTS) || defined(CLPMSDLL)
+#if defined (COIN_EXTERN_C)
+#   define COINLIBAPI __declspec(dllexport)
+#else
+#   define COINLIBAPI __declspec(dllexport)
+#endif
+#   define COINLINKAGE  __stdcall
+#   define COINLINKAGE_CB  __cdecl
+#else
+#if defined (COIN_EXTERN_C)
+#   define COINLIBAPI extern "C"
+#else
+#   define COINLIBAPI 
+#endif
+#   define COINLINKAGE
+#   define COINLINKAGE_CB 
+#endif
+
+#endif
+/** User does not need to see structure of model but C++ code does */
+#if defined (CLP_EXTERN_C)
+/* Real typedef for structure */
+class CMessageHandler;
+typedef struct {
+  ClpSimplex * model_;
+  CMessageHandler * handler_;
+} Clp_Simplex;
+#else
+typedef void Clp_Simplex;
+#endif
+
+#ifndef COIN_NO_CLP
+/** typedef for user call back.
+ The cvec are constructed so don't need to be const*/
+typedef  void (COINLINKAGE_CB *clp_callback) (Clp_Simplex * model,int  msgno, int ndouble,
+                            const double * dvec, int nint, const int * ivec,
+                            int nchar, char ** cvec);
+#endif
+/** User does not need to see structure of model but C++ code does */
+#if defined (SBB_EXTERN_C)
+/* Real typedef for structure */
+class Sbb_MessageHandler;
+typedef struct {
+  OsiClpSolverInterface * solver_;
+  SbbModel              * model_;
+  Sbb_MessageHandler    * handler_;
+  char                  * information_;
+} Sbb_Model;
+#else
+typedef void Sbb_Model;
+#endif
+#if defined (CBC_EXTERN_C)
+/* Real typedef for structure */
+class Cbc_MessageHandler;
+typedef struct {
+  OsiClpSolverInterface * solver_;
+  CbcModel              * model_;
+  Cbc_MessageHandler    * handler_;
+  char                  * information_;
+} Cbc_Model;
+#else
+typedef void Cbc_Model;
+#endif
+#ifndef COIN_NO_SBB
+/** typedef for user call back.
+ The cvec are constructed so don't need to be const*/
+typedef  void (COINLINKAGE_CB *sbb_callback) (Sbb_Model * model,int  msgno, int ndouble,
+                            const double * dvec, int nint, const int * ivec,
+                            int nchar, char ** cvec);
+typedef  void (COINLINKAGE_CB *cbc_callback) (Cbc_Model * model,int  msgno, int ndouble,
+                            const double * dvec, int nint, const int * ivec,
+                            int nchar, char ** cvec);
+#endif
+#if COIN_BIG_INDEX==0
+typedef int CoinBigIndex;
+#elif COIN_BIG_INDEX==1
+typedef long CoinBigIndex;
+#else
+typedef long long CoinBigIndex;
+#endif
+/* just in case used somewhere */
+#undef COIN_NO_CLP
+#undef COIN_NO_SBB
+#undef COIN_NO_CBC
+#endif
diff --git a/cbits/coin/IdiSolve.cpp b/cbits/coin/IdiSolve.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/IdiSolve.cpp
@@ -0,0 +1,1245 @@
+/* $Id: IdiSolve.cpp 1878 2012-08-30 15:43:19Z forrest $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <math.h>
+#include "CoinHelperFunctions.hpp"
+#include "Idiot.hpp"
+#define FIT
+#ifdef FIT
+#define HISTORY 8
+#else
+#define HISTORY 7
+#endif
+#define NSOLVE HISTORY-1
+static void solveSmall(int nsolve, double **aIn, double **a, double * b)
+{
+     int i, j;
+     /* copy */
+     for (i = 0; i < nsolve; i++) {
+          for (j = 0; j < nsolve; j++) {
+               a[i][j] = aIn[i][j];
+          }
+     }
+     for (i = 0; i < nsolve; i++) {
+          /* update using all previous */
+          double diagonal;
+          int j;
+          for (j = i; j < nsolve; j++) {
+               int k;
+               double value = a[i][j];
+               for (k = 0; k < i; k++) {
+                    value -= a[k][i] * a[k][j];
+               }
+               a[i][j] = value;
+          }
+          diagonal = a[i][i];
+          if (diagonal < 1.0e-20) {
+               diagonal = 0.0;
+          } else {
+               diagonal = 1.0 / sqrt(diagonal);
+          }
+          a[i][i] = diagonal;
+          for (j = i + 1; j < nsolve; j++) {
+               a[i][j] *= diagonal;
+          }
+     }
+     /* update */
+     for (i = 0; i < nsolve; i++) {
+          int j;
+          double value = b[i];
+          for (j = 0; j < i; j++) {
+               value -= b[j] * a[j][i];
+          }
+          value *= a[i][i];
+          b[i] = value;
+     }
+     for (i = nsolve - 1; i >= 0; i--) {
+          int j;
+          double value = b[i];
+          for (j = i + 1; j < nsolve; j++) {
+               value -= b[j] * a[i][j];
+          }
+          value *= a[i][i];
+          b[i] = value;
+     }
+}
+IdiotResult
+Idiot::objval(int nrows, int ncols, double * rowsol , double * colsol,
+              double * pi, double * /*djs*/, const double * cost ,
+              const double * /*rowlower*/,
+              const double * rowupper, const double * /*lower*/,
+              const double * /*upper*/, const double * elemnt,
+              const int * row, const CoinBigIndex * columnStart,
+              const int * length, int extraBlock, int * rowExtra,
+              double * solExtra, double * elemExtra, double * /*upperExtra*/,
+              double * costExtra, double weight)
+{
+     IdiotResult result;
+     double objvalue = 0.0;
+     double sum1 = 0.0, sum2 = 0.0;
+     int i;
+     for (i = 0; i < nrows; i++) {
+          rowsol[i] = -rowupper[i];
+     }
+     for (i = 0; i < ncols; i++) {
+          CoinBigIndex j;
+          double value = colsol[i];
+          if (value) {
+               objvalue += value * cost[i];
+               if (elemnt) {
+                    for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                         int irow = row[j];
+                         rowsol[irow] += elemnt[j] * value;
+                    }
+               } else {
+                    for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                         int irow = row[j];
+                         rowsol[irow] += value;
+                    }
+               }
+          }
+     }
+     /* adjust to make as feasible as possible */
+     /* no */
+     if (extraBlock) {
+          for (i = 0; i < extraBlock; i++) {
+               double element = elemExtra[i];
+               int irow = rowExtra[i];
+               objvalue += solExtra[i] * costExtra[i];
+               rowsol[irow] += solExtra[i] * element;
+          }
+     }
+     for (i = 0; i < nrows; i++) {
+          double value = rowsol[i];
+          sum1 += fabs(value);
+          sum2 += value * value;
+          pi[i] = -2.0 * weight * value;
+     }
+     result.infeas = sum1;
+     result.objval = objvalue;
+     result.weighted = objvalue + weight * sum2;
+     result.sumSquared = sum2;
+     return result;
+}
+IdiotResult
+Idiot::IdiSolve(
+     int nrows, int ncols, double * COIN_RESTRICT rowsol , double * COIN_RESTRICT colsol,
+     double * COIN_RESTRICT pi, double * COIN_RESTRICT djs, const double * COIN_RESTRICT origcost , double * COIN_RESTRICT rowlower,
+     double * COIN_RESTRICT rowupper, const double * COIN_RESTRICT lower,
+     const double * COIN_RESTRICT upper, const double * COIN_RESTRICT elemnt,
+     const int * row, const CoinBigIndex * columnStart,
+     const int * length, double * COIN_RESTRICT lambda,
+     int maxIts, double mu, double drop,
+     double maxmin, double offset,
+     int strategy, double djTol, double djExit, double djFlag,
+     CoinThreadRandom * randomNumberGenerator)
+{
+     IdiotResult result;
+     int  i, j, k, iter;
+     double value = 0.0, objvalue = 0.0, weightedObj = 0.0;
+     double tolerance = 1.0e-8;
+     double * history[HISTORY+1];
+     int ncolx;
+     int nChange;
+     int extraBlock = 0;
+     int * rowExtra = NULL;
+     double * COIN_RESTRICT solExtra = NULL;
+     double * COIN_RESTRICT elemExtra = NULL;
+     double * COIN_RESTRICT upperExtra = NULL;
+     double * COIN_RESTRICT costExtra = NULL;
+     double * COIN_RESTRICT useCostExtra = NULL;
+     double * COIN_RESTRICT saveExtra = NULL;
+     double * COIN_RESTRICT cost = NULL;
+     double saveValue = 1.0e30;
+     double saveOffset = offset;
+     double useOffset = offset;
+     /*#define NULLVECTOR*/
+#ifndef NULLVECTOR
+     int nsolve = NSOLVE;
+#else
+     int nsolve = NSOLVE + 1; /* allow for null vector */
+#endif
+     int nflagged;
+     double * COIN_RESTRICT thetaX;
+     double * COIN_RESTRICT djX;
+     double * COIN_RESTRICT bX;
+     double * COIN_RESTRICT vX;
+     double ** aX;
+     double **aworkX;
+     double ** allsum;
+     double * COIN_RESTRICT saveSol = 0;
+     const double * COIN_RESTRICT useCost = cost;
+     double bestSol = 1.0e60;
+     double weight = 0.5 / mu;
+     char * statusSave = new char[2*ncols];
+     char * statusWork = statusSave + ncols;
+#define DJTEST 5
+     double djSave[DJTEST];
+     double largestDj = 0.0;
+     double smallestDj = 1.0e60;
+     double maxDj = 0.0;
+     int doFull = 0;
+#define SAVEHISTORY 10
+#define EVERY (2*SAVEHISTORY)
+#define AFTER SAVEHISTORY*(HISTORY+1)
+#define DROP 5
+     double after = AFTER;
+     double obj[DROP];
+     double kbad = 0, kgood = 0;
+     if (strategy & 128) after = 999999; /* no acceleration at all */
+     for (i = 0; i < DROP; i++) {
+          obj[i] = 1.0e70;
+     }
+     //#define FOUR_GOES 2
+#ifdef FOUR_GOES
+     double * COIN_RESTRICT pi2 = new double [3*nrows];
+     double * COIN_RESTRICT rowsol2 = new double [3*nrows];
+     double * COIN_RESTRICT piX[4];
+     double * COIN_RESTRICT rowsolX[4];
+     int startsX[2][5];
+     int nChangeX[4];
+     double maxDjX[4];
+     double objvalueX[4];
+     int nflaggedX[4];
+     piX[0]=pi;
+     piX[1]=pi2;
+     piX[2]=pi2+nrows;
+     piX[3]=piX[2]+nrows;
+     rowsolX[0]=rowsol;
+     rowsolX[1]=rowsol2;
+     rowsolX[2]=rowsol2+nrows;
+     rowsolX[3]=rowsolX[2]+nrows;
+#endif
+     allsum = new double * [nsolve];
+     aX = new double * [nsolve];
+     aworkX = new double * [nsolve];
+     thetaX = new double[nsolve];
+     vX = new double[nsolve];
+     bX = new double[nsolve];
+     djX = new double[nsolve];
+     allsum[0] = pi;
+     for (i = 0; i < nsolve; i++) {
+          if (i) allsum[i] = new double[nrows];
+          aX[i] = new double[nsolve];
+          aworkX[i] = new double[nsolve];
+     }
+     /* check = rows */
+     for (i = 0; i < nrows; i++) {
+          if (rowupper[i] - rowlower[i] > tolerance) {
+               extraBlock++;
+          }
+     }
+     cost = new double[ncols];
+     memset(rowsol, 0, nrows * sizeof(double));
+     for (i = 0; i < ncols; i++) {
+          CoinBigIndex j;
+          double value = origcost[i] * maxmin;
+          double value2 = colsol[i];
+          if (elemnt) {
+               for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                    int irow = row[j];
+                    value += elemnt[j] * lambda[irow];
+                    rowsol[irow] += elemnt[j] * value2;
+               }
+          } else {
+               for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                    int irow = row[j];
+                    value += lambda[irow];
+                    rowsol[irow] += value2;
+               }
+          }
+          cost[i] = value;
+     }
+     if (extraBlock) {
+          rowExtra = new int[extraBlock];
+          solExtra = new double[extraBlock];
+          elemExtra = new double[extraBlock];
+          upperExtra = new double[extraBlock];
+          costExtra = new double[extraBlock];
+          saveExtra = new double[extraBlock];
+          extraBlock = 0;
+          int nbad = 0;
+          for (i = 0; i < nrows; i++) {
+               if (rowupper[i] - rowlower[i] > tolerance) {
+                    double smaller, difference;
+                    double value;
+                    saveExtra[extraBlock] = rowupper[i];
+                    if (fabs(rowupper[i]) > fabs(rowlower[i])) {
+                         smaller = rowlower[i];
+                         value = -1.0;
+                    } else {
+                         smaller = rowupper[i];
+                         value = 1.0;
+                    }
+                    if (fabs(smaller) > 1.0e10) {
+                         if (!nbad)
+                              COIN_DETAIL_PRINT(printf("Can't handle rows where both bounds >1.0e10 %d %g\n",
+						       i, smaller));
+                         nbad++;
+                         if (rowupper[i] < 0.0 || rowlower[i] > 0.0)
+                              abort();
+                         if (fabs(rowupper[i]) > fabs(rowlower[i])) {
+                              rowlower[i] = -0.9e10;
+                              smaller = rowlower[i];
+                              value = -1.0;
+                         } else {
+                              rowupper[i] = 0.9e10;
+                              saveExtra[extraBlock] = rowupper[i];
+                              smaller = rowupper[i];
+                              value = 1.0;
+                         }
+                    }
+                    difference = rowupper[i] - rowlower[i];
+                    difference = CoinMin(difference, 1.0e31);
+                    rowupper[i] = smaller;
+                    elemExtra[extraBlock] = value;
+                    solExtra[extraBlock] = (rowupper[i] - rowsol[i]) / value;
+                    if (solExtra[extraBlock] < 0.0) solExtra[extraBlock] = 0.0;
+                    if (solExtra[extraBlock] > difference) solExtra[extraBlock] = difference;
+                    costExtra[extraBlock] = lambda[i] * value;
+                    upperExtra[extraBlock] = difference;
+                    rowsol[i] += value * solExtra[extraBlock];
+                    rowExtra[extraBlock++] = i;
+               }
+          }
+          if (nbad)
+	    COIN_DETAIL_PRINT(printf("%d bad values - results may be wrong\n", nbad));
+     }
+     for (i = 0; i < nrows; i++) {
+          offset += lambda[i] * rowsol[i];
+     }
+     if ((strategy & 256) != 0) {
+          /* save best solution */
+          saveSol = new double[ncols];
+          CoinMemcpyN(colsol, ncols, saveSol);
+          if (extraBlock) {
+               useCostExtra = new double[extraBlock];
+               memset(useCostExtra, 0, extraBlock * sizeof(double));
+          }
+          useCost = origcost;
+          useOffset = saveOffset;
+     } else {
+          useCostExtra = costExtra;
+          useCost = cost;
+          useOffset = offset;
+     }
+     ncolx = ncols + extraBlock;
+     for (i = 0; i < HISTORY + 1; i++) {
+          history[i] = new double[ncolx];
+     }
+     for (i = 0; i < DJTEST; i++) {
+          djSave[i] = 1.0e30;
+     }
+     for (i = 0; i < ncols; i++) {
+          if (upper[i] - lower[i]) {
+               statusSave[i] = 0;
+          } else {
+               statusSave[i] = 1;
+          }
+     }
+     // for two pass method
+     int start[2];
+     int stop[2];
+     int direction = -1;
+     start[0] = 0;
+     stop[0] = ncols;
+     start[1] = 0;
+     stop[1] = 0;
+     iter = 0;
+     for (; iter < maxIts; iter++) {
+          double sum1 = 0.0, sum2 = 0.0;
+          double lastObj = 1.0e70;
+          int good = 0, doScale = 0;
+          if (strategy & 16) {
+               int ii = iter / EVERY + 1;
+               ii = ii * EVERY;
+               if (iter > ii - HISTORY * 2 && (iter & 1) == 0) {
+                    double * COIN_RESTRICT x = history[HISTORY-1];
+                    for (i = HISTORY - 1; i > 0; i--) {
+                         history[i] = history[i-1];
+                    }
+                    history[0] = x;
+                    CoinMemcpyN(colsol, ncols, history[0]);
+                    CoinMemcpyN(solExtra, extraBlock, history[0] + ncols);
+               }
+          }
+          if ((iter % SAVEHISTORY) == 0 || doFull) {
+               if ((strategy & 16) == 0) {
+                    double * COIN_RESTRICT x = history[HISTORY-1];
+                    for (i = HISTORY - 1; i > 0; i--) {
+                         history[i] = history[i-1];
+                    }
+                    history[0] = x;
+                    CoinMemcpyN(colsol, ncols, history[0]);
+                    CoinMemcpyN(solExtra, extraBlock, history[0] + ncols);
+               }
+          }
+          /* start full try */
+          if ((iter % EVERY) == 0 || doFull) {
+               // for next pass
+               direction = - direction;
+               // randomize.
+               // The cast is to avoid gcc compiler warning
+               int kcol = static_cast<int>(ncols * randomNumberGenerator->randomDouble());
+               if (kcol == ncols)
+                    kcol = ncols - 1;
+               if (direction > 0) {
+                    start[0] = kcol;
+                    stop[0] = ncols;
+                    start[1] = 0;
+                    stop[1] = kcol;
+#ifdef FOUR_GOES
+		    for (int itry=0;itry<2;itry++) {
+		      int chunk=(stop[itry]-start[itry]+FOUR_GOES-1)/FOUR_GOES;
+		      startsX[itry][0]=start[itry];
+		      for (int i=1;i<5;i++)
+			startsX[itry][i]=CoinMin(stop[itry],startsX[itry][i-1]+chunk);
+		    }
+#endif
+               } else {
+                    start[0] = kcol;
+                    stop[0] = -1;
+                    start[1] = ncols - 1;
+                    stop[1] = kcol;
+#ifdef FOUR_GOES
+		    for (int itry=0;itry<2;itry++) {
+		      int chunk=(start[itry]-stop[itry]+FOUR_GOES-1)/FOUR_GOES;
+		      startsX[itry][0]=start[itry];
+		      for (int i=1;i<5;i++)
+			startsX[itry][i]=CoinMax(stop[itry],startsX[itry][i-1]-chunk);
+		    }
+#endif
+               }
+               int itry = 0;
+               /*if ((strategy&16)==0) {
+               	double * COIN_RESTRICT x=history[HISTORY-1];
+               	for (i=HISTORY-1;i>0;i--) {
+               	history[i]=history[i-1];
+               	}
+               	history[0]=x;
+               	CoinMemcpyN(colsol,ncols,history[0]);
+                 CoinMemcpyN(solExtra,extraBlock,history[0]+ncols);
+               	}*/
+               while (!good) {
+                    itry++;
+#define MAXTRY 5
+                    if (iter > after && doScale < 2 && itry < MAXTRY) {
+                         /* now full one */
+                         for (i = 0; i < nrows; i++) {
+                              rowsol[i] = -rowupper[i];
+                         }
+                         sum2 = 0.0;
+                         objvalue = 0.0;
+                         memset(pi, 0, nrows * sizeof(double));
+                         {
+                              double * COIN_RESTRICT theta = thetaX;
+                              double * COIN_RESTRICT dj = djX;
+                              double * COIN_RESTRICT b = bX;
+                              double ** a = aX;
+                              double ** awork = aworkX;
+                              double * COIN_RESTRICT v = vX;
+                              double c;
+#ifdef FIT
+                              int ntot = 0, nsign = 0, ngood = 0, mgood[4] = {0, 0, 0, 0};
+                              double diff1, diff2, val0, val1, val2, newValue;
+                              CoinMemcpyN(colsol, ncols, history[HISTORY-1]);
+                              CoinMemcpyN(solExtra, extraBlock, history[HISTORY-1] + ncols);
+#endif
+                              dj[0] = 0.0;
+                              for (i = 1; i < nsolve; i++) {
+                                   dj[i] = 0.0;
+                                   memset(allsum[i], 0, nrows * sizeof(double));
+                              }
+                              for (i = 0; i < ncols; i++) {
+                                   double value2 = colsol[i];
+                                   if (value2 > lower[i] + tolerance) {
+                                        if(value2 < (upper[i] - tolerance)) {
+                                             int k;
+                                             objvalue += value2 * cost[i];
+#ifdef FIT
+                                             ntot++;
+                                             val0 = history[0][i];
+                                             val1 = history[1][i];
+                                             val2 = history[2][i];
+                                             diff1 = val0 - val1;
+                                             diff2 = val1 - val2;
+                                             if (diff1*diff2 >= 0.0) {
+                                                  nsign++;
+                                                  if (fabs(diff1) < fabs(diff2)) {
+                                                       int ii = static_cast<int>(fabs(4.0 * diff1 / diff2));
+                                                       if (ii == 4) ii = 3;
+                                                       mgood[ii]++;
+                                                       ngood++;
+                                                  }
+                                                  if (fabs(diff1) < 0.75 * fabs(diff2)) {
+                                                       newValue = val1 + (diff1 * diff2) / (diff2 - diff1);
+                                                  } else {
+                                                       newValue = val1 + 4.0 * diff1;
+                                                  }
+                                             } else {
+                                                  newValue = 0.333333333 * (val0 + val1 + val2);
+                                             }
+                                             if (newValue > upper[i] - tolerance) {
+                                                  newValue = upper[i];
+                                             } else if (newValue < lower[i] + tolerance) {
+                                                  newValue = lower[i];
+                                             }
+                                             history[HISTORY-1][i] = newValue;
+#endif
+                                             for (k = 0; k < HISTORY - 1; k++) {
+                                                  value = history[k][i] - history[k+1][i];
+                                                  dj[k] += value * cost[i];
+                                                  v[k] = value;
+                                             }
+                                             if (elemnt) {
+                                                  for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                                                       int irow = row[j];
+                                                       for (k = 0; k < HISTORY - 1; k++) {
+                                                            allsum[k][irow] += elemnt[j] * v[k];
+                                                       }
+                                                       rowsol[irow] += elemnt[j] * value2;
+                                                  }
+                                             } else {
+                                                  for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                                                       int irow = row[j];
+                                                       for (k = 0; k < HISTORY - 1; k++) {
+                                                            allsum[k][irow] += v[k];
+                                                       }
+                                                       rowsol[irow] += value2;
+                                                  }
+                                             }
+                                        } else {
+                                             /* at ub */
+                                             colsol[i] = upper[i];
+                                             value2 = colsol[i];
+                                             objvalue += value2 * cost[i];
+                                             if (elemnt) {
+                                                  for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                                                       int irow = row[j];
+                                                       rowsol[irow] += elemnt[j] * value2;
+                                                  }
+                                             } else {
+                                                  for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                                                       int irow = row[j];
+                                                       rowsol[irow] += value2;
+                                                  }
+                                             }
+                                        }
+                                   } else {
+                                        /* at lb */
+                                        if (value2) {
+                                             objvalue += value2 * cost[i];
+                                             if (elemnt) {
+                                                  for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                                                       int irow = row[j];
+                                                       rowsol[irow] += elemnt[j] * value2;
+                                                  }
+                                             } else {
+                                                  for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                                                       int irow = row[j];
+                                                       rowsol[irow] += value2;
+                                                  }
+                                             }
+                                        }
+                                   }
+                              }
+#ifdef FIT
+                              /*printf("total %d, same sign %d, good %d %d %d %d %d\n",
+                                ntot,nsign,ngood,mgood[0],mgood[1],mgood[2],mgood[3]);*/
+#endif
+                              if (extraBlock) {
+                                   for (i = 0; i < extraBlock; i++) {
+                                        double element = elemExtra[i];
+                                        int irow = rowExtra[i];
+                                        objvalue += solExtra[i] * costExtra[i];
+                                        if (solExtra[i] > tolerance
+                                                  && solExtra[i] < (upperExtra[i] - tolerance)) {
+                                             double value2 = solExtra[i];
+                                             int k;
+                                             for (k = 0; k < HISTORY - 1; k++) {
+                                                  value = history[k][i+ncols] - history[k+1][i+ncols];
+                                                  dj[k] += value * costExtra[i];
+                                                  allsum[k][irow] += element * value;
+                                             }
+                                             rowsol[irow] += element * value2;
+                                        } else {
+                                             double value2 = solExtra[i];
+                                             double element = elemExtra[i];
+                                             int irow = rowExtra[i];
+                                             rowsol[irow] += element * value2;
+                                        }
+                                   }
+                              }
+#ifdef NULLVECTOR
+                              if ((strategy & 64)) {
+                                   double djVal = dj[0];
+                                   for (i = 0; i < ncols - nrows; i++) {
+                                        double value2 = colsol[i];
+                                        if (value2 > lower[i] + tolerance && value2 < upper[i] - tolerance) {
+                                             value = history[0][i] - history[1][i];
+                                        } else {
+                                             value = 0.0;
+                                        }
+                                        history[HISTORY][i] = value;
+                                   }
+                                   for (; i < ncols; i++) {
+                                        double value2 = colsol[i];
+                                        double delta;
+                                        int irow = i - (ncols - nrows);
+                                        double oldSum = allsum[0][irow];;
+                                        if (value2 > lower[i] + tolerance && value2 < upper[i] - tolerance) {
+                                             delta = history[0][i] - history[1][i];
+                                        } else {
+                                             delta = 0.0;
+                                        }
+                                        djVal -= delta * cost[i];
+                                        oldSum -= delta;
+                                        delta = - oldSum;
+                                        djVal += delta * cost[i];
+                                        history[HISTORY][i] = delta;
+                                   }
+                                   dj[HISTORY-1] = djVal;
+                                   djVal = 0.0;
+                                   for (i = 0; i < ncols; i++) {
+                                        double value2 = colsol[i];
+                                        if (value2 > lower[i] + tolerance && value2 < upper[i] - tolerance ||
+                                                  i >= ncols - nrows) {
+                                             int k;
+                                             value = history[HISTORY][i];
+                                             djVal += value * cost[i];
+                                             for (j = columnStart[i]; j < columnStart[i] + length[i]; j++) {
+                                                  int irow = row[j];
+                                                  allsum[nsolve-1][irow] += value;
+                                             }
+                                        }
+                                   }
+                                   printf("djs %g %g\n", dj[HISTORY-1], djVal);
+                              }
+#endif
+                              for (i = 0; i < nsolve; i++) {
+                                   int j;
+                                   b[i] = 0.0;
+                                   for (j = 0; j < nsolve; j++) {
+                                        a[i][j] = 0.0;
+                                   }
+                              }
+                              c = 0.0;
+                              for (i = 0; i < nrows; i++) {
+                                   double value = rowsol[i];
+                                   for (k = 0; k < nsolve; k++) {
+                                        v[k] = allsum[k][i];
+                                        b[k] += v[k] * value;
+                                   }
+                                   c += value * value;
+                                   for (k = 0; k < nsolve; k++) {
+                                        for (j = k; j < nsolve; j++) {
+                                             a[k][j] += v[k] * v[j];
+                                        }
+                                   }
+                              }
+                              sum2 = c;
+                              if (itry == 1) {
+                                   lastObj = objvalue + weight * sum2;
+                              }
+                              for (k = 0; k < nsolve; k++) {
+                                   b[k] = - (weight * b[k] + 0.5 * dj[k]);
+                                   for (j = k; j < nsolve; j++) {
+                                        a[k][j] *= weight;
+                                        a[j][k] = a[k][j];
+                                   }
+                              }
+                              c *= weight;
+                              for (k = 0; k < nsolve; k++) {
+                                   theta[k] = b[k];
+                              }
+                              solveSmall(nsolve, a, awork, theta);
+                              if ((strategy & 64) != 0) {
+                                   value = 10.0;
+                                   for (k = 0; k < nsolve; k++) {
+                                        value  = CoinMax(value, fabs(theta[k]));
+                                   }
+                                   if (value > 10.0 && ((logLevel_ & 4) != 0)) {
+                                        printf("theta %g %g %g\n", theta[0], theta[1], theta[2]);
+                                   }
+                                   value = 10.0 / value;
+                                   for (k = 0; k < nsolve; k++) {
+                                        theta[k] *= value;
+                                   }
+                              }
+                              for (i = 0; i < ncolx; i++) {
+                                   double valueh = 0.0;
+                                   for (k = 0; k < HISTORY - 1; k++) {
+                                        value = history[k][i] - history[k+1][i];
+                                        valueh += value * theta[k];
+                                   }
+#ifdef NULLVECTOR
+                                   value = history[HISTORY][i];
+                                   valueh += value * theta[HISTORY-1];
+#endif
+                                   history[HISTORY][i] = valueh;
+                              }
+                         }
+#ifdef NULLVECTOR
+                         if ((strategy & 64)) {
+                              for (i = 0; i < ncols - nrows; i++) {
+                                   if (colsol[i] <= lower[i] + tolerance
+                                             || colsol[i] >= (upper[i] - tolerance)) {
+                                        history[HISTORY][i] = 0.0;;
+                                   }
+                              }
+                              tolerance = -tolerance; /* switch off test */
+                         }
+#endif
+                         if (!doScale) {
+                              for (i = 0; i < ncols; i++) {
+                                   if (colsol[i] > lower[i] + tolerance
+                                             && colsol[i] < (upper[i] - tolerance)) {
+                                        value = history[HISTORY][i];
+                                        colsol[i] += value;
+                                        if (colsol[i] < lower[i] + tolerance) {
+                                             colsol[i] = lower[i];
+                                        } else if (colsol[i] > upper[i] - tolerance) {
+                                             colsol[i] = upper[i];
+                                        }
+                                   }
+                              }
+                              if (extraBlock) {
+                                   for (i = 0; i < extraBlock; i++) {
+                                        if (solExtra[i] > tolerance
+                                                  && solExtra[i] < (upperExtra[i] - tolerance)) {
+                                             value = history[HISTORY][i+ncols];
+                                             solExtra[i] += value;
+                                             if (solExtra[i] < 0.0) {
+                                                  solExtra[i] = 0.0;
+                                             } else if (solExtra[i] > upperExtra[i]) {
+                                                  solExtra[i] = upperExtra[i];
+                                             }
+                                        }
+                                   }
+                              }
+                         } else {
+                              double theta = 1.0;
+                              double saveTheta = theta;
+                              for (i = 0; i < ncols; i++) {
+                                   if (colsol[i] > lower[i] + tolerance
+                                             && colsol[i] < (upper[i] - tolerance)) {
+                                        value = history[HISTORY][i];
+                                        if (value > 0) {
+                                             if (theta * value + colsol[i] > upper[i]) {
+                                                  theta = (upper[i] - colsol[i]) / value;
+                                             }
+                                        } else if (value < 0) {
+                                             if (colsol[i] + theta * value < lower[i]) {
+                                                  theta = (lower[i] - colsol[i]) / value;
+                                             }
+                                        }
+                                   }
+                              }
+                              if (extraBlock) {
+                                   for (i = 0; i < extraBlock; i++) {
+                                        if (solExtra[i] > tolerance
+                                                  && solExtra[i] < (upperExtra[i] - tolerance)) {
+                                             value = history[HISTORY][i+ncols];
+                                             if (value > 0) {
+                                                  if (theta * value + solExtra[i] > upperExtra[i]) {
+                                                       theta = (upperExtra[i] - solExtra[i]) / value;
+                                                  }
+                                             } else if (value < 0) {
+                                                  if (solExtra[i] + theta * value < 0.0) {
+                                                       theta = -solExtra[i] / value;
+                                                  }
+                                             }
+                                        }
+                                   }
+                              }
+                              if ((iter % 100 == 0) && (logLevel_ & 8) != 0) {
+                                   if (theta < saveTheta) {
+                                        printf(" - modified theta %g\n", theta);
+                                   }
+                              }
+                              for (i = 0; i < ncols; i++) {
+                                   if (colsol[i] > lower[i] + tolerance
+                                             && colsol[i] < (upper[i] - tolerance)) {
+                                        value = history[HISTORY][i];
+                                        colsol[i] += value * theta;
+                                   }
+                              }
+                              if (extraBlock) {
+                                   for (i = 0; i < extraBlock; i++) {
+                                        if (solExtra[i] > tolerance
+                                                  && solExtra[i] < (upperExtra[i] - tolerance)) {
+                                             value = history[HISTORY][i+ncols];
+                                             solExtra[i] += value * theta;
+                                        }
+                                   }
+                              }
+                         }
+#ifdef NULLVECTOR
+                         tolerance = fabs(tolerance); /* switch back on */
+#endif
+                         if ((iter % 100) == 0 && (logLevel_ & 8) != 0) {
+                              printf("\n");
+                         }
+                    }
+                    good = 1;
+                    result = objval(nrows, ncols, rowsol, colsol, pi, djs, useCost,
+                                    rowlower, rowupper, lower, upper,
+                                    elemnt, row, columnStart, length, extraBlock, rowExtra,
+                                    solExtra, elemExtra, upperExtra, useCostExtra,
+                                    weight);
+                    weightedObj = result.weighted;
+                    if (!iter) saveValue = weightedObj;
+                    objvalue = result.objval;
+                    sum1 = result.infeas;
+                    if (saveSol) {
+                         if (result.weighted < bestSol) {
+                              COIN_DETAIL_PRINT(printf("%d %g better than %g\n", iter,
+						       result.weighted * maxmin - useOffset, bestSol * maxmin - useOffset));
+                              bestSol = result.weighted;
+                              CoinMemcpyN(colsol, ncols, saveSol);
+                         }
+                    }
+#ifdef FITz
+                    if (iter > after) {
+                         IdiotResult result2;
+                         double ww, oo, ss;
+                         if (extraBlock) abort();
+                         result2 = objval(nrows, ncols, row2, sol2, pi2, djs, cost,
+                                          rowlower, rowupper, lower, upper,
+                                          elemnt, row, columnStart, extraBlock, rowExtra,
+                                          solExtra, elemExtra, upperExtra, costExtra,
+                                          weight);
+                         ww = result2.weighted;
+                         oo = result2.objval;
+                         ss = result2.infeas;
+                         printf("wobj %g obj %g inf %g last %g\n", ww, oo, ss, lastObj);
+                         if (ww < weightedObj && ww < lastObj) {
+                              printf(" taken");
+                              ntaken++;
+                              saving += weightedObj - ww;
+                              weightedObj = ww;
+                              objvalue = oo;
+                              sum1 = ss;
+                              CoinMemcpyN(row2, nrows, rowsol);
+                              CoinMemcpyN(pi2, nrows, pi);
+                              CoinMemcpyN(sol2, ncols, colsol);
+                              result = objval(nrows, ncols, rowsol, colsol, pi, djs, cost,
+                                              rowlower, rowupper, lower, upper,
+                                              elemnt, row, columnStart, extraBlock, rowExtra,
+                                              solExtra, elemExtra, upperExtra, costExtra,
+                                              weight);
+                              weightedObj = result.weighted;
+                              objvalue = result.objval;
+                              sum1 = result.infeas;
+                              if (ww < weightedObj) abort();
+                         } else {
+                              printf(" not taken");
+                              nottaken++;
+                         }
+                    }
+#endif
+                    /*printf("%d %g %g %g %g\n",itry,lastObj,weightedObj,objvalue,sum1);*/
+                    if (weightedObj > lastObj + 1.0e-4 && itry < MAXTRY) {
+                         if((logLevel_ & 16) != 0 && doScale) {
+                              printf("Weighted objective from %g to %g **** bad move\n",
+                                     lastObj, weightedObj);
+                         }
+                         if (doScale) {
+                              good = 1;
+                         }
+                         if ((strategy & 3) == 1) {
+                              good = 0;
+                              if (weightedObj > lastObj + djExit) {
+                                   if ((logLevel_ & 16) != 0) {
+                                        printf("Weighted objective from %g to %g ?\n", lastObj, weightedObj);
+                                   }
+                                   CoinMemcpyN(history[0], ncols, colsol);
+                                   CoinMemcpyN(history[0] + ncols, extraBlock, solExtra);
+                                   good = 1;
+                              }
+                         } else if ((strategy & 3) == 2) {
+                              if (weightedObj > lastObj + 0.1 * maxDj) {
+                                   CoinMemcpyN(history[0], ncols, colsol);
+                                   CoinMemcpyN(history[0] + ncols, extraBlock, solExtra);
+                                   doScale++;
+                                   good = 0;
+                              }
+                         } else if ((strategy & 3) == 3) {
+                              if (weightedObj > lastObj + 0.001 * maxDj) {
+                                   /*doScale++;*/
+                                   good = 0;
+                              }
+                         }
+                    }
+               }
+               if ((iter % checkFrequency_) == 0) {
+                    double best = weightedObj;
+                    double test = obj[0];
+                    for (i = 1; i < DROP; i++) {
+                         obj[i-1] = obj[i];
+                         if (best > obj[i]) best = obj[i];
+                    }
+                    obj[DROP-1] = best;
+                    if (test - best < drop && (strategy & 8) == 0) {
+                         if ((logLevel_ & 8) != 0) {
+                              printf("Exiting as drop in %d its is %g after %d iterations\n",
+                                     DROP * checkFrequency_, test - best, iter);
+                         }
+                         goto RETURN;
+                    }
+               }
+               if ((iter % logFreq_) == 0) {
+                    double piSum = 0.0;
+                    for (i = 0; i < nrows; i++) {
+                         piSum += (rowsol[i] + rowupper[i]) * pi[i];
+                    }
+                    if ((logLevel_ & 2) != 0) {
+                         printf("%d Infeas %g, obj %g - wtObj %g dual %g maxDj %g\n",
+                                iter, sum1, objvalue * maxmin - useOffset, weightedObj - useOffset,
+                                piSum * maxmin - useOffset, maxDj);
+                    }
+               }
+               CoinMemcpyN(statusSave, ncols, statusWork);
+               nflagged = 0;
+          }
+          nChange = 0;
+          doFull = 0;
+          maxDj = 0.0;
+          // go through forwards or backwards and starting at odd places
+#ifdef FOUR_GOES
+	  for (int i=1;i<FOUR_GOES;i++) {
+	    cilk_spawn memcpy(piX[i], pi, nrows * sizeof(double));
+	    cilk_spawn memcpy(rowsolX[i], rowsol, nrows * sizeof(double));
+	  }
+	  for (int i=0;i<FOUR_GOES;i++) {
+	    nChangeX[i]=0;
+	    maxDjX[i]=0.0;
+	    objvalueX[i]=0.0;
+	    nflaggedX[i]=0;
+	  }
+	  cilk_sync;
+#endif
+	  //printf("PASS\n");
+#ifdef FOUR_GOES
+               cilk_for (int iPar = 0; iPar < FOUR_GOES; iPar++) {
+                    double * COIN_RESTRICT pi=piX[iPar];
+                    double * COIN_RESTRICT rowsol = rowsolX[iPar];
+          for (int itry = 0; itry < 2; itry++) {
+		    int istop;
+		    int istart;
+#if 0
+		    int chunk = (start[itry]+stop[itry]+FOUR_GOES-1)/FOUR_GOES;
+                    if (iPar == 0) {
+		      istart=start[itry];
+		      istop=(start[itry]+stop[itry])>>1;
+                    } else {
+		      istart=(start[itry]+stop[itry])>>1;
+		      istop = stop[itry];
+                    }
+#endif
+#if 0
+		    printf("istart %d istop %d direction %d array %d %d new %d %d\n",
+		    	   istart,istop,direction,start[itry],stop[itry],
+		    	   startsX[itry][iPar],startsX[itry][iPar+1]);
+#endif
+		    istart=startsX[itry][iPar];
+		    istop=startsX[itry][iPar+1];
+#else
+          for (int itry = 0; itry < 2; itry++) {
+               int istart = start[itry];
+               int istop = stop[itry];
+#endif
+                    for (int icol=istart; icol != istop; icol += direction) {
+                         if (!statusWork[icol]) {
+                              CoinBigIndex j;
+                              double value = colsol[icol];
+                              double djval = cost[icol];
+                              double djval2, value2;
+                              double theta, a, b, c;
+                              if (elemnt) {
+                                   for (j = columnStart[icol]; j < columnStart[icol] + length[icol]; j++) {
+                                        int irow = row[j];
+                                        djval -= elemnt[j] * pi[irow];
+                                   }
+                              } else {
+                                   for (j = columnStart[icol]; j < columnStart[icol] + length[icol]; j++) {
+                                        int irow = row[j];
+                                        djval -= pi[irow];
+                                   }
+                              }
+                              /*printf("xx iter %d seq %d djval %g value %g\n",
+                                iter,i,djval,value);*/
+                              if (djval > 1.0e-5) {
+                                   value2 = (lower[icol] - value);
+                              } else {
+                                   value2 = (upper[icol] - value);
+                              }
+                              djval2 = djval * value2;
+                              djval = fabs(djval);
+                              if (djval > djTol) {
+                                   if (djval2 < -1.0e-4) {
+#ifndef FOUR_GOES
+                                        nChange++;
+                                        if (djval > maxDj) maxDj = djval;
+#else
+                                        nChangeX[iPar]++;
+                                        if (djval > maxDjX[iPar]) maxDjX[iPar] = djval;
+#endif
+                                        /*if (djval>3.55e6) {
+                                        		printf("big\n");
+                                        		}*/
+                                        a = 0.0;
+                                        b = 0.0;
+                                        c = 0.0;
+                                        djval2 = cost[icol];
+                                        if (elemnt) {
+                                             for (j = columnStart[icol]; j < columnStart[icol] + length[icol]; j++) {
+                                                  int irow = row[j];
+                                                  double value = rowsol[irow];
+                                                  c += value * value;
+                                                  a += elemnt[j] * elemnt[j];
+                                                  b += value * elemnt[j];
+                                             }
+                                        } else {
+                                             for (j = columnStart[icol]; j < columnStart[icol] + length[icol]; j++) {
+                                                  int irow = row[j];
+                                                  double value = rowsol[irow];
+                                                  c += value * value;
+                                                  a += 1.0;
+                                                  b += value;
+                                             }
+                                        }
+                                        a *= weight;
+                                        b = b * weight + 0.5 * djval2;
+                                        c *= weight;
+                                        /* solve */
+                                        theta = -b / a;
+#ifndef FOUR_GOES
+                                        if ((strategy & 4) != 0) {
+					  double valuep, thetap;
+                                             value2 = a * theta * theta + 2.0 * b * theta;
+                                             thetap = 2.0 * theta;
+                                             valuep = a * thetap * thetap + 2.0 * b * thetap;
+                                             if (valuep < value2 + djTol) {
+                                                  theta = thetap;
+                                                  kgood++;
+                                             } else {
+                                                  kbad++;
+                                             }
+                                        }
+#endif
+                                        if (theta > 0.0) {
+                                             if (theta < upper[icol] - colsol[icol]) {
+                                                  value2 = theta;
+                                             } else {
+                                                  value2 = upper[icol] - colsol[icol];
+                                             }
+                                        } else {
+                                             if (theta > lower[icol] - colsol[icol]) {
+                                                  value2 = theta;
+                                             } else {
+                                                  value2 = lower[icol] - colsol[icol];
+                                             }
+                                        }
+                                        colsol[icol] += value2;
+#ifndef FOUR_GOES
+                                        objvalue += cost[icol] * value2;
+#else
+                                        objvalueX[iPar] += cost[icol] * value2;
+#endif
+                                        if (elemnt) {
+                                             for (j = columnStart[icol]; j < columnStart[icol] + length[icol]; j++) {
+                                                  int irow = row[j];
+                                                  double value;
+                                                  rowsol[irow] += elemnt[j] * value2;
+                                                  value = rowsol[irow];
+                                                  pi[irow] = -2.0 * weight * value;
+                                             }
+                                        } else {
+                                             for (j = columnStart[icol]; j < columnStart[icol] + length[icol]; j++) {
+                                                  int irow = row[j];
+                                                  double value;
+                                                  rowsol[irow] += value2;
+                                                  value = rowsol[irow];
+                                                  pi[irow] = -2.0 * weight * value;
+                                             }
+                                        }
+                                   } else {
+                                        /* dj but at bound */
+                                        if (djval > djFlag) {
+                                             statusWork[icol] = 1;
+#ifndef FOUR_GOES
+                                             nflagged++;
+#else
+                                             nflaggedX[iPar]++;
+#endif
+                                        }
+                                   }
+                              }
+                         }
+                    }
+#ifdef FOUR_GOES
+               }
+#endif
+          }
+#ifdef FOUR_GOES
+	  for (int i=0;i<FOUR_GOES;i++) {
+	    nChange += nChangeX[i];
+	    maxDj = CoinMax(maxDj,maxDjX[i]);
+	    objvalue += objvalueX[i];
+	    nflagged += nflaggedX[i];
+	  }
+          cilk_for (int i = 0; i < nrows; i++) {
+#if FOUR_GOES==2
+	    rowsol[i] = 0.5 * (rowsolX[0][i] + rowsolX[1][i]);
+	    pi[i] = 0.5 * (piX[0][i] + piX[1][i]);
+#elif FOUR_GOES==3
+	    pi[i] = 0.33333333333333 * (piX[0][i] + piX[1][i]+piX[2][i]);
+	    rowsol[i] = 0.3333333333333 * (rowsolX[0][i] + rowsolX[1][i]+rowsolX[2][i]);
+#else
+	    pi[i] = 0.25 * (piX[0][i] + piX[1][i]+piX[2][i]+piX[3][i]);
+	    rowsol[i] = 0.25 * (rowsolX[0][i] + rowsolX[1][i]+rowsolX[2][i]+rowsolX[3][i]);
+#endif
+          }
+#endif
+          if (extraBlock) {
+               for (int i = 0; i < extraBlock; i++) {
+                    double value = solExtra[i];
+                    double djval = costExtra[i];
+                    double djval2, value2;
+                    double element = elemExtra[i];
+                    double theta, a, b, c;
+                    int irow = rowExtra[i];
+                    djval -= element * pi[irow];
+                    /*printf("xxx iter %d extra %d djval %g value %g\n",
+                    	  iter,irow,djval,value);*/
+                    if (djval > 1.0e-5) {
+                         value2 = -value;
+                    } else {
+                         value2 = (upperExtra[i] - value);
+                    }
+                    djval2 = djval * value2;
+                    if (djval2 < -1.0e-4 && fabs(djval) > djTol) {
+                         nChange++;
+                         a = 0.0;
+                         b = 0.0;
+                         c = 0.0;
+                         djval2 = costExtra[i];
+                         value = rowsol[irow];
+                         c += value * value;
+                         a += element * element;
+                         b += element * value;
+                         a *= weight;
+                         b = b * weight + 0.5 * djval2;
+                         c *= weight;
+                         /* solve */
+                         theta = -b / a;
+                         if (theta > 0.0) {
+                              value2 = CoinMin(theta, upperExtra[i] - solExtra[i]);
+                         } else {
+                              value2 = CoinMax(theta, -solExtra[i]);
+                         }
+                         solExtra[i] += value2;
+                         rowsol[irow] += element * value2;
+                         value = rowsol[irow];
+                         pi[irow] = -2.0 * weight * value;
+                    }
+               }
+          }
+          if ((iter % 10) == 2) {
+               for (int i = DJTEST - 1; i > 0; i--) {
+                    djSave[i] = djSave[i-1];
+               }
+               djSave[0] = maxDj;
+               largestDj = CoinMax(largestDj, maxDj);
+               smallestDj = CoinMin(smallestDj, maxDj);
+               for (int i = DJTEST - 1; i > 0; i--) {
+                    maxDj += djSave[i];
+               }
+               maxDj = maxDj / static_cast<double> (DJTEST);
+               if (maxDj < djExit && iter > 50) {
+                    //printf("Exiting on low dj %g after %d iterations\n",maxDj,iter);
+                    break;
+               }
+               if (nChange < 100) {
+                    djTol *= 0.5;
+               }
+          }
+     }
+RETURN:
+     if (kgood || kbad) {
+       COIN_DETAIL_PRINT(printf("%g good %g bad\n", kgood, kbad));
+     }
+     result = objval(nrows, ncols, rowsol, colsol, pi, djs, useCost,
+                     rowlower, rowupper, lower, upper,
+                     elemnt, row, columnStart, length, extraBlock, rowExtra,
+                     solExtra, elemExtra, upperExtra, useCostExtra,
+                     weight);
+     result.djAtBeginning = largestDj;
+     result.djAtEnd = smallestDj;
+     result.dropThis = saveValue - result.weighted;
+     if (saveSol) {
+          if (result.weighted < bestSol) {
+               bestSol = result.weighted;
+               CoinMemcpyN(colsol, ncols, saveSol);
+          } else {
+               COIN_DETAIL_PRINT(printf("restoring previous - now %g best %g\n",
+					result.weighted * maxmin - useOffset, bestSol * maxmin - useOffset));
+          }
+     }
+     if (saveSol) {
+          if (extraBlock) {
+               delete [] useCostExtra;
+          }
+          CoinMemcpyN(saveSol, ncols, colsol);
+          delete [] saveSol;
+     }
+     for (i = 0; i < nsolve; i++) {
+          if (i) delete [] allsum[i];
+          delete [] aX[i];
+          delete [] aworkX[i];
+     }
+     delete [] thetaX;
+     delete [] djX;
+     delete [] bX;
+     delete [] vX;
+     delete [] aX;
+     delete [] aworkX;
+     delete [] allsum;
+     delete [] cost;
+#ifdef FOUR_GOES
+     delete [] pi2 ;
+     delete [] rowsol2 ;
+#endif
+     for (i = 0; i < HISTORY + 1; i++) {
+          delete [] history[i];
+     }
+     delete [] statusSave;
+     /* do original costs objvalue*/
+     result.objval = 0.0;
+     for (i = 0; i < ncols; i++) {
+          result.objval += colsol[i] * origcost[i];
+     }
+     if (extraBlock) {
+          for (i = 0; i < extraBlock; i++) {
+               int irow = rowExtra[i];
+               rowupper[irow] = saveExtra[i];
+          }
+          delete [] rowExtra;
+          delete [] solExtra;
+          delete [] elemExtra;
+          delete [] upperExtra;
+          delete [] costExtra;
+          delete [] saveExtra;
+     }
+     result.iteration = iter;
+     result.objval -= saveOffset;
+     result.weighted = result.objval + weight * result.sumSquared;
+     return result;
+}
diff --git a/cbits/coin/Idiot.cpp b/cbits/coin/Idiot.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Idiot.cpp
@@ -0,0 +1,2049 @@
+/* $Id: Idiot.cpp 1931 2013-04-06 20:44:29Z stefan $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include "CoinPragma.hpp"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ClpPresolve.hpp"
+#include "Idiot.hpp"
+#include "CoinTime.hpp"
+#include "CoinSort.hpp"
+#include "CoinMessageHandler.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "AbcCommon.hpp"
+// Redefine stuff for Clp
+#ifndef OSI_IDIOT
+#include "ClpMessage.hpp"
+#define OsiObjOffset ClpObjOffset
+#endif
+/**** strategy 4 - drop, exitDrop and djTolerance all relative:
+For first two major iterations these are small.  Then:
+
+drop - exit a major iteration if drop over 5*checkFrequency < this is
+used as info->drop*(10.0+fabs(last weighted objective))
+
+exitDrop - exit idiot if feasible and drop < this is
+used as info->exitDrop*(10.0+fabs(last objective))
+
+djExit - exit a major iteration if largest dj (averaged over 5 checks)
+drops below this - used as info->djTolerance*(10.0+fabs(last weighted objective)
+
+djFlag - mostly skip variables with bad dj worse than this => 2*djExit
+
+djTol - only look at variables with dj better than this => 0.01*djExit
+****************/
+
+#define IDIOT_FIX_TOLERANCE 1e-6
+#define SMALL_IDIOT_FIX_TOLERANCE 1e-10
+int
+Idiot::dropping(IdiotResult result,
+                double tolerance,
+                double small,
+                int *nbad)
+{
+     if (result.infeas <= small) {
+          double value = CoinMax(fabs(result.objval), fabs(result.dropThis)) + 1.0;
+          if (result.dropThis > tolerance * value) {
+               *nbad = 0;
+               return 1;
+          } else {
+               (*nbad)++;
+               if (*nbad > 4) {
+                    return 0;
+               } else {
+                    return 1;
+               }
+          }
+     } else {
+          *nbad = 0;
+          return 1;
+     }
+}
+// Deals with whenUsed and slacks
+int
+Idiot::cleanIteration(int iteration, int ordinaryStart, int ordinaryEnd,
+                      double * colsol, const double * lower, const double * upper,
+                      const double * rowLower, const double * rowUpper,
+                      const double * cost, const double * element, double fixTolerance,
+                      double & objValue, double & infValue)
+{
+     int n = 0;
+     if ((strategy_ & 16384) == 0) {
+          for (int i = ordinaryStart; i < ordinaryEnd; i++) {
+               if (colsol[i] > lower[i] + fixTolerance) {
+                    if (colsol[i] < upper[i] - fixTolerance) {
+                         n++;
+                    } else {
+                         colsol[i] = upper[i];
+                    }
+                    whenUsed_[i] = iteration;
+               } else {
+                    colsol[i] = lower[i];
+               }
+          }
+          return n;
+     } else {
+#ifdef COIN_DEVELOP
+          printf("entering inf %g, obj %g\n", infValue, objValue);
+#endif
+          int nrows = model_->getNumRows();
+          int ncols = model_->getNumCols();
+          int * posSlack = whenUsed_ + ncols;
+          int * negSlack = posSlack + nrows;
+          int * nextSlack = negSlack + nrows;
+          double * rowsol = reinterpret_cast<double *> (nextSlack + ncols);
+          memset(rowsol, 0, nrows * sizeof(double));
+#ifdef OSI_IDIOT
+          const CoinPackedMatrix * matrix = model_->getMatrixByCol();
+#else
+          ClpMatrixBase * matrix = model_->clpMatrix();
+#endif
+          const int * row = matrix->getIndices();
+          const CoinBigIndex * columnStart = matrix->getVectorStarts();
+          const int * columnLength = matrix->getVectorLengths();
+          //const double * element = matrix->getElements();
+          int i;
+          objValue = 0.0;
+          infValue = 0.0;
+          for ( i = 0; i < ncols; i++) {
+               if (nextSlack[i] == -1) {
+                    // not a slack
+                    if (colsol[i] > lower[i] + fixTolerance) {
+                         if (colsol[i] < upper[i] - fixTolerance) {
+                              n++;
+                              whenUsed_[i] = iteration;
+                         } else {
+                              colsol[i] = upper[i];
+                         }
+                         whenUsed_[i] = iteration;
+                    } else {
+                         colsol[i] = lower[i];
+                    }
+                    double value = colsol[i];
+                    if (value) {
+                         objValue += cost[i] * value;
+                         CoinBigIndex j;
+                         for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                              int iRow = row[j];
+                              rowsol[iRow] += value * element[j];
+                         }
+                    }
+               }
+          }
+          // temp fix for infinite lbs - just limit to -1000
+          for (i = 0; i < nrows; i++) {
+               double rowSave = rowsol[i];
+               int iCol;
+               iCol = posSlack[i];
+               if (iCol >= 0) {
+                    // slide all slack down
+                    double rowValue = rowsol[i];
+                    CoinBigIndex j = columnStart[iCol];
+                    double lowerValue = CoinMax(CoinMin(colsol[iCol], 0.0) - 1000.0, lower[iCol]);
+                    rowSave += (colsol[iCol] - lowerValue) * element[j];
+                    colsol[iCol] = lowerValue;
+                    while (nextSlack[iCol] >= 0) {
+                         iCol = nextSlack[iCol];
+                         double lowerValue = CoinMax(CoinMin(colsol[iCol], 0.0) - 1000.0, lower[iCol]);
+                         j = columnStart[iCol];
+                         rowSave += (colsol[iCol] - lowerValue) * element[j];
+                         colsol[iCol] = lowerValue;
+                    }
+                    iCol = posSlack[i];
+                    while (rowValue < rowLower[i] && iCol >= 0) {
+                         // want to increase
+                         double distance = rowLower[i] - rowValue;
+                         double value = element[columnStart[iCol]];
+                         double thisCost = cost[iCol];
+                         if (distance <= value*(upper[iCol] - colsol[iCol])) {
+                              // can get there
+                              double movement = distance / value;
+                              objValue += movement * thisCost;
+                              rowValue = rowLower[i];
+                              colsol[iCol] += movement;
+                         } else {
+                              // can't get there
+                              double movement = upper[iCol] - colsol[iCol];
+                              objValue += movement * thisCost;
+                              rowValue += movement * value;
+                              colsol[iCol] = upper[iCol];
+                              iCol = nextSlack[iCol];
+                         }
+                    }
+                    if (iCol >= 0) {
+                         // may want to carry on - because of cost?
+                         while (iCol >= 0 && cost[iCol] < 0 && rowValue < rowUpper[i]) {
+                              // want to increase
+                              double distance = rowUpper[i] - rowValue;
+                              double value = element[columnStart[iCol]];
+                              double thisCost = cost[iCol];
+                              if (distance <= value*(upper[iCol] - colsol[iCol])) {
+                                   // can get there
+                                   double movement = distance / value;
+                                   objValue += movement * thisCost;
+                                   rowValue = rowUpper[i];
+                                   colsol[iCol] += movement;
+                                   iCol = -1;
+                              } else {
+                                   // can't get there
+                                   double movement = upper[iCol] - colsol[iCol];
+                                   objValue += movement * thisCost;
+                                   rowValue += movement * value;
+                                   colsol[iCol] = upper[iCol];
+                                   iCol = nextSlack[iCol];
+                              }
+                         }
+                         if (iCol >= 0 && colsol[iCol] > lower[iCol] + fixTolerance &&
+                                   colsol[iCol] < upper[iCol] - fixTolerance) {
+                              whenUsed_[i] = iteration;
+                              n++;
+                         }
+                    }
+                    rowsol[i] = rowValue;
+               }
+               iCol = negSlack[i];
+               if (iCol >= 0) {
+                    // slide all slack down
+                    double rowValue = rowsol[i];
+                    CoinBigIndex j = columnStart[iCol];
+                    double lowerValue = CoinMax(CoinMin(colsol[iCol], 0.0) - 1000.0, lower[iCol]);
+                    rowSave += (colsol[iCol] - lowerValue) * element[j];
+                    colsol[iCol] = lowerValue;
+                    while (nextSlack[iCol] >= 0) {
+                         iCol = nextSlack[iCol];
+                         j = columnStart[iCol];
+			 double lowerValue = CoinMax(CoinMin(colsol[iCol], 0.0) - 1000.0, lower[iCol]);
+                         rowSave += (colsol[iCol] - lowerValue) * element[j];
+                         colsol[iCol] = lowerValue;
+                    }
+                    iCol = negSlack[i];
+                    while (rowValue > rowUpper[i] && iCol >= 0) {
+                         // want to increase
+                         double distance = -(rowUpper[i] - rowValue);
+                         double value = -element[columnStart[iCol]];
+                         double thisCost = cost[iCol];
+                         if (distance <= value*(upper[iCol] - lower[iCol])) {
+                              // can get there
+                              double movement = distance / value;
+                              objValue += movement * thisCost;
+                              rowValue = rowUpper[i];
+                              colsol[iCol] += movement;
+                         } else {
+                              // can't get there
+                              double movement = upper[iCol] - lower[iCol];
+                              objValue += movement * thisCost;
+                              rowValue -= movement * value;
+                              colsol[iCol] = upper[iCol];
+                              iCol = nextSlack[iCol];
+                         }
+                    }
+                    if (iCol >= 0) {
+                         // may want to carry on - because of cost?
+                         while (iCol >= 0 && cost[iCol] < 0 && rowValue > rowLower[i]) {
+                              // want to increase
+                              double distance = -(rowLower[i] - rowValue);
+                              double value = -element[columnStart[iCol]];
+                              double thisCost = cost[iCol];
+                              if (distance <= value*(upper[iCol] - colsol[iCol])) {
+                                   // can get there
+                                   double movement = distance / value;
+                                   objValue += movement * thisCost;
+                                   rowValue = rowLower[i];
+                                   colsol[iCol] += movement;
+                                   iCol = -1;
+                              } else {
+                                   // can't get there
+                                   double movement = upper[iCol] - colsol[iCol];
+                                   objValue += movement * thisCost;
+                                   rowValue -= movement * value;
+                                   colsol[iCol] = upper[iCol];
+                                   iCol = nextSlack[iCol];
+                              }
+                         }
+                         if (iCol >= 0 && colsol[iCol] > lower[iCol] + fixTolerance &&
+                                   colsol[iCol] < upper[iCol] - fixTolerance) {
+                              whenUsed_[i] = iteration;
+                              n++;
+                         }
+                    }
+                    rowsol[i] = rowValue;
+               }
+               infValue += CoinMax(CoinMax(0.0, rowLower[i] - rowsol[i]), rowsol[i] - rowUpper[i]);
+               // just change
+               rowsol[i] -= rowSave;
+          }
+          return n;
+     }
+}
+
+/* returns -1 if none or start of costed slacks or -2 if
+   there are costed slacks but it is messy */
+static int countCostedSlacks(OsiSolverInterface * model)
+{
+#ifdef OSI_IDIOT
+     const CoinPackedMatrix * matrix = model->getMatrixByCol();
+#else
+     ClpMatrixBase * matrix = model->clpMatrix();
+#endif
+     const int * row = matrix->getIndices();
+     const CoinBigIndex * columnStart = matrix->getVectorStarts();
+     const int * columnLength = matrix->getVectorLengths();
+     const double * element = matrix->getElements();
+     const double * rowupper = model->getRowUpper();
+     int nrows = model->getNumRows();
+     int ncols = model->getNumCols();
+     int slackStart = ncols - nrows;
+     int nSlacks = nrows;
+     int i;
+
+     if (ncols <= nrows) return -1;
+     while (1) {
+          for (i = 0; i < nrows; i++) {
+               int j = i + slackStart;
+               CoinBigIndex k = columnStart[j];
+               if (columnLength[j] == 1) {
+                    if (row[k] != i || element[k] != 1.0) {
+                         nSlacks = 0;
+                         break;
+                    }
+               } else {
+                    nSlacks = 0;
+                    break;
+               }
+               if (rowupper[i] <= 0.0) {
+                    nSlacks = 0;
+                    break;
+               }
+          }
+          if (nSlacks || !slackStart) break;
+          slackStart = 0;
+     }
+     if (!nSlacks) slackStart = -1;
+     return slackStart;
+}
+void
+Idiot::crash(int numberPass, CoinMessageHandler * handler,
+             const CoinMessages *messages, bool doCrossover)
+{
+     // lightweight options
+     int numberColumns = model_->getNumCols();
+     const double * objective = model_->getObjCoefficients();
+     int nnzero = 0;
+     double sum = 0.0;
+     int i;
+     for (i = 0; i < numberColumns; i++) {
+          if (objective[i]) {
+               sum += fabs(objective[i]);
+               nnzero++;
+          }
+     }
+     sum /= static_cast<double> (nnzero + 1);
+     if (maxIts_ == 5)
+          maxIts_ = 2;
+     if (numberPass <= 0)
+          majorIterations_ = static_cast<int>(2 + log10(static_cast<double>(numberColumns + 1)));
+     else
+          majorIterations_ = numberPass;
+     // If mu not changed then compute
+     if (mu_ == 1e-4)
+          mu_ = CoinMax(1.0e-3, sum * 1.0e-5);
+     if (maxIts2_ == 100) {
+          if (!lightWeight_) {
+               maxIts2_ = 105;
+          } else if (lightWeight_ == 1) {
+               mu_ *= 1000.0;
+               maxIts2_ = 23;
+          } else if (lightWeight_ == 2) {
+               maxIts2_ = 11;
+          } else {
+               maxIts2_ = 23;
+          }
+     }
+     //printf("setting mu to %g and doing %d passes\n",mu_,majorIterations_);
+     solve2(handler, messages);
+#ifndef OSI_IDIOT
+     if (doCrossover) {
+          double averageInfeas = model_->sumPrimalInfeasibilities() / static_cast<double> (model_->numberRows());
+          if ((averageInfeas < 0.01 && (strategy_ & 512) != 0) || (strategy_ & 8192) != 0)
+               crossOver(16 + 1);
+          else
+               crossOver(majorIterations_ < 1000000 ? 3 : 2);
+     }
+#endif
+}
+
+void
+Idiot::solve()
+{
+     CoinMessages dummy;
+     solve2(NULL, &dummy);
+}
+void
+Idiot::solve2(CoinMessageHandler * handler, const CoinMessages * messages)
+{
+     int strategy = 0;
+     double d2;
+     int i, n;
+     int allOnes = 1;
+     int iteration = 0;
+     int iterationTotal = 0;
+     int nTry = 0; /* number of tries at same weight */
+     double fixTolerance = IDIOT_FIX_TOLERANCE;
+     int maxBigIts = maxBigIts_;
+     int maxIts = maxIts_;
+     int logLevel = logLevel_;
+     int saveMajorIterations = majorIterations_;
+     majorIterations_ = majorIterations_ % 1000000;
+     if (handler) {
+          if (handler->logLevel() > 0 && handler->logLevel() < 3)
+               logLevel = 1;
+          else if (!handler->logLevel())
+               logLevel = 0;
+          else
+               logLevel = 7;
+     }
+     double djExit = djTolerance_;
+     double djFlag = 1.0 + 100.0 * djExit;
+     double djTol = 0.00001;
+     double mu = mu_;
+     double drop = drop_;
+     int maxIts2 = maxIts2_;
+     double factor = muFactor_;
+     double smallInfeas = smallInfeas_;
+     double reasonableInfeas = reasonableInfeas_;
+     double stopMu = stopMu_;
+     double maxmin, offset;
+     double lastWeighted = 1.0e50;
+     double exitDrop = exitDrop_;
+     double fakeSmall = smallInfeas;
+     double firstInfeas;
+     int badIts = 0;
+     int slackStart, ordStart, ordEnd;
+     int checkIteration = 0;
+     int lambdaIteration = 0;
+     int belowReasonable = 0; /* set if ever gone below reasonable infeas */
+     double bestWeighted = 1.0e60;
+     double bestFeasible = 1.0e60; /* best solution while feasible */
+     IdiotResult result, lastResult;
+     int saveStrategy = strategy_;
+     const int strategies[] = {0, 2, 128};
+     double saveLambdaScale = 0.0;
+     if ((saveStrategy & 128) != 0) {
+          fixTolerance = SMALL_IDIOT_FIX_TOLERANCE;
+     }
+#ifdef OSI_IDIOT
+     const CoinPackedMatrix * matrix = model_->getMatrixByCol();
+#else
+     ClpMatrixBase * matrix = model_->clpMatrix();
+#endif
+     const int * row = matrix->getIndices();
+     const CoinBigIndex * columnStart = matrix->getVectorStarts();
+     const int * columnLength = matrix->getVectorLengths();
+     const double * element = matrix->getElements();
+     int nrows = model_->getNumRows();
+     int ncols = model_->getNumCols();
+     double * rowsol, * colsol;
+     double * pi, * dj;
+#ifndef OSI_IDIOT
+     double * cost = model_->objective();
+     double * lower = model_->columnLower();
+     double * upper = model_->columnUpper();
+#else
+     double * cost = new double [ncols];
+     CoinMemcpyN( model_->getObjCoefficients(), ncols, cost);
+     const double * lower = model_->getColLower();
+     const double * upper = model_->getColUpper();
+#endif
+     const double *elemXX;
+     double * saveSol;
+     double * rowupper = new double[nrows]; // not const as modified
+     CoinMemcpyN(model_->getRowUpper(), nrows, rowupper);
+     double * rowlower = new double[nrows]; // not const as modified
+     CoinMemcpyN(model_->getRowLower(), nrows, rowlower);
+     CoinThreadRandom * randomNumberGenerator = model_->randomNumberGenerator();
+     int * whenUsed;
+     double * lambda;
+     saveSol = new double[ncols];
+     lambda = new double [nrows];
+     rowsol = new double[nrows];
+     colsol = new double [ncols];
+     CoinMemcpyN(model_->getColSolution(), ncols, colsol);
+     pi = new double[nrows];
+     dj = new double[ncols];
+     delete [] whenUsed_;
+     bool oddSlacks = false;
+     // See if any costed slacks
+     int numberSlacks = 0;
+     for (i = 0; i < ncols; i++) {
+          if (columnLength[i] == 1)
+               numberSlacks++;
+     }
+     if (!numberSlacks) {
+          whenUsed_ = new int[ncols];
+     } else {
+#ifdef COIN_DEVELOP
+          printf("%d slacks\n", numberSlacks);
+#endif
+          oddSlacks = true;
+          int extra = static_cast<int> (nrows * sizeof(double) / sizeof(int));
+          whenUsed_ = new int[2*ncols+2*nrows+extra];
+          int * posSlack = whenUsed_ + ncols;
+          int * negSlack = posSlack + nrows;
+          int * nextSlack = negSlack + nrows;
+          for (i = 0; i < nrows; i++) {
+               posSlack[i] = -1;
+               negSlack[i] = -1;
+          }
+          for (i = 0; i < ncols; i++)
+               nextSlack[i] = -1;
+          for (i = 0; i < ncols; i++) {
+               if (columnLength[i] == 1) {
+                    CoinBigIndex j = columnStart[i];
+                    int iRow = row[j];
+                    if (element[j] > 0.0) {
+                         if (posSlack[iRow] == -1) {
+                              posSlack[iRow] = i;
+                         } else {
+                              int iCol = posSlack[iRow];
+                              while (nextSlack[iCol] >= 0)
+                                   iCol = nextSlack[iCol];
+                              nextSlack[iCol] = i;
+                         }
+                    } else {
+                         if (negSlack[iRow] == -1) {
+                              negSlack[iRow] = i;
+                         } else {
+                              int iCol = negSlack[iRow];
+                              while (nextSlack[iCol] >= 0)
+                                   iCol = nextSlack[iCol];
+                              nextSlack[iCol] = i;
+                         }
+                    }
+               }
+          }
+          // now sort
+          for (i = 0; i < nrows; i++) {
+               int iCol;
+               iCol = posSlack[i];
+               if (iCol >= 0) {
+                    CoinBigIndex j = columnStart[iCol];
+#ifndef NDEBUG
+                    int iRow = row[j];
+#endif
+                    assert (element[j] > 0.0);
+                    assert (iRow == i);
+                    dj[0] = cost[iCol] / element[j];
+                    whenUsed_[0] = iCol;
+                    int n = 1;
+                    while (nextSlack[iCol] >= 0) {
+                         iCol = nextSlack[iCol];
+                         CoinBigIndex j = columnStart[iCol];
+#ifndef NDEBUG
+                         int iRow = row[j];
+#endif
+                         assert (element[j] > 0.0);
+                         assert (iRow == i);
+                         dj[n] = cost[iCol] / element[j];
+                         whenUsed_[n++] = iCol;
+                    }
+                    for (j = 0; j < n; j++) {
+                         int jCol = whenUsed_[j];
+                         nextSlack[jCol] = -2;
+                    }
+                    CoinSort_2(dj, dj + n, whenUsed_);
+                    // put back
+                    iCol = whenUsed_[0];
+                    posSlack[i] = iCol;
+                    for (j = 1; j < n; j++) {
+                         int jCol = whenUsed_[j];
+                         nextSlack[iCol] = jCol;
+                         iCol = jCol;
+                    }
+               }
+               iCol = negSlack[i];
+               if (iCol >= 0) {
+                    CoinBigIndex j = columnStart[iCol];
+#ifndef NDEBUG
+                    int iRow = row[j];
+#endif
+                    assert (element[j] < 0.0);
+                    assert (iRow == i);
+                    dj[0] = -cost[iCol] / element[j];
+                    whenUsed_[0] = iCol;
+                    int n = 1;
+                    while (nextSlack[iCol] >= 0) {
+                         iCol = nextSlack[iCol];
+                         CoinBigIndex j = columnStart[iCol];
+#ifndef NDEBUG
+                         int iRow = row[j];
+#endif
+                         assert (element[j] < 0.0);
+                         assert (iRow == i);
+                         dj[n] = -cost[iCol] / element[j];
+                         whenUsed_[n++] = iCol;
+                    }
+                    for (j = 0; j < n; j++) {
+                         int jCol = whenUsed_[j];
+                         nextSlack[jCol] = -2;
+                    }
+                    CoinSort_2(dj, dj + n, whenUsed_);
+                    // put back
+                    iCol = whenUsed_[0];
+                    negSlack[i] = iCol;
+                    for (j = 1; j < n; j++) {
+                         int jCol = whenUsed_[j];
+                         nextSlack[iCol] = jCol;
+                         iCol = jCol;
+                    }
+               }
+          }
+     }
+     whenUsed = whenUsed_;
+     if (model_->getObjSense() == -1.0) {
+          maxmin = -1.0;
+     } else {
+          maxmin = 1.0;
+     }
+     model_->getDblParam(OsiObjOffset, offset);
+     if (!maxIts2) maxIts2 = maxIts;
+     strategy = strategy_;
+     strategy &= 3;
+     memset(lambda, 0, nrows * sizeof(double));
+     slackStart = countCostedSlacks(model_);
+     if (slackStart >= 0) {
+       COIN_DETAIL_PRINT(printf("This model has costed slacks\n"));
+          if (slackStart) {
+               ordStart = 0;
+               ordEnd = slackStart;
+          } else {
+               ordStart = nrows;
+               ordEnd = ncols;
+          }
+     } else {
+          ordStart = 0;
+          ordEnd = ncols;
+     }
+     if (offset && logLevel > 2) {
+          printf("** Objective offset is %g\n", offset);
+     }
+     /* compute reasonable solution cost */
+     for (i = 0; i < nrows; i++) {
+          rowsol[i] = 1.0e31;
+     }
+     for (i = 0; i < ncols; i++) {
+          CoinBigIndex j;
+          for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+               if (element[j] != 1.0) {
+                    allOnes = 0;
+                    break;
+               }
+          }
+     }
+     if (allOnes) {
+          elemXX = NULL;
+     } else {
+          elemXX = element;
+     }
+     // Do scaling if wanted
+     bool scaled = false;
+#ifndef OSI_IDIOT
+     if ((strategy_ & 32) != 0 && !allOnes) {
+          if (model_->scalingFlag() > 0)
+               scaled = model_->clpMatrix()->scale(model_) == 0;
+          if (scaled) {
+               const double * rowScale = model_->rowScale();
+               const double * columnScale = model_->columnScale();
+               double * oldLower = lower;
+               double * oldUpper = upper;
+               double * oldCost = cost;
+               lower = new double[ncols];
+               upper = new double[ncols];
+               cost = new double[ncols];
+               CoinMemcpyN(oldLower, ncols, lower);
+               CoinMemcpyN(oldUpper, ncols, upper);
+               CoinMemcpyN(oldCost, ncols, cost);
+               int icol, irow;
+               for (icol = 0; icol < ncols; icol++) {
+                    double multiplier = 1.0 / columnScale[icol];
+                    if (lower[icol] > -1.0e50)
+                         lower[icol] *= multiplier;
+                    if (upper[icol] < 1.0e50)
+                         upper[icol] *= multiplier;
+                    colsol[icol] *= multiplier;
+                    cost[icol] *= columnScale[icol];
+               }
+               CoinMemcpyN(model_->rowLower(), nrows, rowlower);
+               for (irow = 0; irow < nrows; irow++) {
+                    double multiplier = rowScale[irow];
+                    if (rowlower[irow] > -1.0e50)
+                         rowlower[irow] *= multiplier;
+                    if (rowupper[irow] < 1.0e50)
+                         rowupper[irow] *= multiplier;
+                    rowsol[irow] *= multiplier;
+               }
+               int length = columnStart[ncols-1] + columnLength[ncols-1];
+               double * elemYY = new double[length];
+               for (i = 0; i < ncols; i++) {
+                    CoinBigIndex j;
+                    double scale = columnScale[i];
+                    for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                         int irow = row[j];
+                         elemYY[j] = element[j] * scale * rowScale[irow];
+                    }
+               }
+               elemXX = elemYY;
+          }
+     }
+#endif
+     for (i = 0; i < ncols; i++) {
+          CoinBigIndex j;
+          double dd = columnLength[i];
+          dd = cost[i] / dd;
+          for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+               int irow = row[j];
+               if (dd < rowsol[irow]) {
+                    rowsol[irow] = dd;
+               }
+          }
+     }
+     d2 = 0.0;
+     for (i = 0; i < nrows; i++) {
+          d2 += rowsol[i];
+     }
+     d2 *= 2.0; /* for luck */
+
+     d2 = d2 / static_cast<double> (4 * nrows + 8000);
+     d2 *= 0.5; /* halve with more flexible method */
+     if (d2 < 5.0) d2 = 5.0;
+     if (djExit == 0.0) {
+          djExit = d2;
+     }
+     if ((saveStrategy & 4) != 0) {
+          /* go to relative tolerances - first small */
+          djExit = 1.0e-10;
+          djFlag = 1.0e-5;
+          drop = 1.0e-10;
+     }
+     memset(whenUsed, 0, ncols * sizeof(int));
+     strategy = strategies[strategy];
+     if ((saveStrategy & 8) != 0) strategy |= 64; /* don't allow large theta */
+     CoinMemcpyN(colsol, ncols, saveSol);
+
+     lastResult = IdiSolve(nrows, ncols, rowsol , colsol, pi,
+                           dj, cost, rowlower, rowupper,
+                           lower, upper, elemXX, row, columnStart, columnLength, lambda,
+                           0, mu, drop,
+                           maxmin, offset, strategy, djTol, djExit, djFlag, randomNumberGenerator);
+     // update whenUsed_
+     n = cleanIteration(iteration, ordStart, ordEnd,
+                        colsol,  lower,  upper,
+                        rowlower, rowupper,
+                        cost, elemXX, fixTolerance, lastResult.objval, lastResult.infeas);
+     if ((strategy_ & 16384) != 0) {
+          int * posSlack = whenUsed_ + ncols;
+          int * negSlack = posSlack + nrows;
+          int * nextSlack = negSlack + nrows;
+          double * rowsol2 = reinterpret_cast<double *> (nextSlack + ncols);
+          for (i = 0; i < nrows; i++)
+               rowsol[i] += rowsol2[i];
+     }
+     if ((logLevel_ & 1) != 0) {
+#ifndef OSI_IDIOT
+          if (!handler) {
+#endif
+               printf("Iteration %d infeasibility %g, objective %g - mu %g, its %d, %d interior\n",
+                      iteration, lastResult.infeas, lastResult.objval, mu, lastResult.iteration, n);
+#ifndef OSI_IDIOT
+          } else {
+               handler->message(CLP_IDIOT_ITERATION, *messages)
+                         << iteration << lastResult.infeas << lastResult.objval << mu << lastResult.iteration << n
+                         << CoinMessageEol;
+          }
+#endif
+     }
+     int numberBaseTrys = 0; // for first time
+     int numberAway = -1;
+     iterationTotal = lastResult.iteration;
+     firstInfeas = lastResult.infeas;
+     if ((strategy_ & 1024) != 0) reasonableInfeas = 0.5 * firstInfeas;
+     if (lastResult.infeas < reasonableInfeas) lastResult.infeas = reasonableInfeas;
+     double keepinfeas = 1.0e31;
+     double lastInfeas = 1.0e31;
+     double bestInfeas = 1.0e31;
+     while ((mu > stopMu && lastResult.infeas > smallInfeas) ||
+               (lastResult.infeas <= smallInfeas &&
+                dropping(lastResult, exitDrop, smallInfeas, &badIts)) ||
+               checkIteration < 2 || lambdaIteration < lambdaIterations_) {
+          if (lastResult.infeas <= exitFeasibility_)
+               break;
+          iteration++;
+          checkIteration++;
+          if (lastResult.infeas <= smallInfeas && lastResult.objval < bestFeasible) {
+               bestFeasible = lastResult.objval;
+          }
+          if (lastResult.infeas + mu * lastResult.objval < bestWeighted) {
+               bestWeighted = lastResult.objval + mu * lastResult.objval;
+          }
+          if ((saveStrategy & 4096)) strategy |= 256;
+          if ((saveStrategy & 4) != 0 && iteration > 2) {
+               /* go to relative tolerances */
+               double weighted = 10.0 + fabs(lastWeighted);
+               djExit = djTolerance_ * weighted;
+               djFlag = 2.0 * djExit;
+               drop = drop_ * weighted;
+               djTol = 0.01 * djExit;
+          }
+          CoinMemcpyN(colsol, ncols, saveSol);
+          result = IdiSolve(nrows, ncols, rowsol , colsol, pi, dj,
+                            cost, rowlower, rowupper,
+                            lower, upper, elemXX, row, columnStart, columnLength, lambda,
+                            maxIts, mu, drop,
+                            maxmin, offset, strategy, djTol, djExit, djFlag, randomNumberGenerator);
+          n = cleanIteration(iteration, ordStart, ordEnd,
+                             colsol,  lower,  upper,
+                             rowlower, rowupper,
+                             cost, elemXX, fixTolerance, result.objval, result.infeas);
+          if ((strategy_ & 16384) != 0) {
+               int * posSlack = whenUsed_ + ncols;
+               int * negSlack = posSlack + nrows;
+               int * nextSlack = negSlack + nrows;
+               double * rowsol2 = reinterpret_cast<double *> (nextSlack + ncols);
+               for (i = 0; i < nrows; i++)
+                    rowsol[i] += rowsol2[i];
+          }
+          if ((logLevel_ & 1) != 0) {
+#ifndef OSI_IDIOT
+               if (!handler) {
+#endif
+                    printf("Iteration %d infeasibility %g, objective %g - mu %g, its %d, %d interior\n",
+                           iteration, result.infeas, result.objval, mu, result.iteration, n);
+#ifndef OSI_IDIOT
+               } else {
+                    handler->message(CLP_IDIOT_ITERATION, *messages)
+                              << iteration << result.infeas << result.objval << mu << result.iteration << n
+                              << CoinMessageEol;
+               }
+#endif
+          }
+          if (iteration > 50 && n == numberAway ) {
+	    if((result.infeas < 1.0e-4 && majorIterations_<200)||result.infeas<1.0e-8) {
+#ifdef CLP_INVESTIGATE
+               printf("infeas small %g\n", result.infeas);
+#endif
+               break; // not much happening
+	    }
+          }
+          if (lightWeight_ == 1 && iteration > 10 && result.infeas > 1.0 && maxIts != 7) {
+               if (lastInfeas != bestInfeas && CoinMin(result.infeas, lastInfeas) > 0.95 * bestInfeas)
+                    majorIterations_ = CoinMin(majorIterations_, iteration); // not getting feasible
+          }
+          lastInfeas = result.infeas;
+          numberAway = n;
+          keepinfeas = result.infeas;
+          lastWeighted = result.weighted;
+          iterationTotal += result.iteration;
+          if (iteration == 1) {
+               if ((strategy_ & 1024) != 0 && mu < 1.0e-10)
+                    result.infeas = firstInfeas * 0.8;
+               if (majorIterations_ >= 50 || dropEnoughFeasibility_ <= 0.0)
+                    result.infeas *= 0.8;
+               if (result.infeas > firstInfeas * 0.9
+                         && result.infeas > reasonableInfeas) {
+                    iteration--;
+                    if (majorIterations_ < 50)
+                         mu *= 1.0e-1;
+                    else
+                         mu *= 0.7;
+                    bestFeasible = 1.0e31;
+                    bestWeighted = 1.0e60;
+                    numberBaseTrys++;
+                    if (mu < 1.0e-30 || (numberBaseTrys > 10 && lightWeight_)) {
+                         // back to all slack basis
+                         lightWeight_ = 2;
+                         break;
+                    }
+                    CoinMemcpyN(saveSol, ncols, colsol);
+               } else {
+                    maxIts = maxIts2;
+                    checkIteration = 0;
+                    if ((strategy_ & 1024) != 0) mu *= 1.0e-1;
+               }
+          } else {
+          }
+          bestInfeas = CoinMin(bestInfeas, result.infeas);
+	  if (majorIterations_>100&&majorIterations_<200) {
+	    if (iteration==majorIterations_-100) {
+	      // redo
+	      double muX=mu*10.0;
+	      bestInfeas=1.0e3;
+	      mu=muX;
+	      nTry=0;
+	    }
+	  }
+          if (iteration) {
+               /* this code is in to force it to terminate sometime */
+               double changeMu = factor;
+               if ((saveStrategy & 64) != 0) {
+                    keepinfeas = 0.0; /* switch off ranga's increase */
+                    fakeSmall = smallInfeas;
+               } else {
+                    fakeSmall = -1.0;
+               }
+               saveLambdaScale = 0.0;
+               if (result.infeas > reasonableInfeas ||
+                         (nTry + 1 == maxBigIts && result.infeas > fakeSmall)) {
+                    if (result.infeas > lastResult.infeas*(1.0 - dropEnoughFeasibility_) ||
+                              nTry + 1 == maxBigIts ||
+                              (result.infeas > lastResult.infeas * 0.9
+                               && result.weighted > lastResult.weighted
+                               - dropEnoughWeighted_ * CoinMax(fabs(lastResult.weighted), fabs(result.weighted)))) {
+                         mu *= changeMu;
+                         if ((saveStrategy & 32) != 0 && result.infeas < reasonableInfeas && 0) {
+                              reasonableInfeas = CoinMax(smallInfeas, reasonableInfeas * sqrt(changeMu));
+                              COIN_DETAIL_PRINT(printf("reasonable infeas now %g\n", reasonableInfeas));
+                         }
+                         result.weighted = 1.0e60;
+                         nTry = 0;
+                         bestFeasible = 1.0e31;
+                         bestWeighted = 1.0e60;
+                         checkIteration = 0;
+                         lambdaIteration = 0;
+#define LAMBDA
+#ifdef LAMBDA
+                         if ((saveStrategy & 2048) == 0) {
+                              memset(lambda, 0, nrows * sizeof(double));
+                         }
+#else
+                         memset(lambda, 0, nrows * sizeof(double));
+#endif
+                    } else {
+                         nTry++;
+                    }
+               } else if (lambdaIterations_ >= 0) {
+                    /* update lambda  */
+                    double scale = 1.0 / mu;
+                    int i, nnz = 0;
+                    saveLambdaScale = scale;
+                    lambdaIteration++;
+                    if ((saveStrategy & 4) == 0) drop = drop_ / 50.0;
+                    if (lambdaIteration > 4 &&
+                              (((lambdaIteration % 10) == 0 && smallInfeas < keepinfeas) ||
+                               ((lambdaIteration % 5) == 0 && 1.5 * smallInfeas < keepinfeas))) {
+                         //printf(" Increasing smallInfeas from %f to %f\n",smallInfeas,1.5*smallInfeas);
+                         smallInfeas *= 1.5;
+                    }
+                    if ((saveStrategy & 2048) == 0) {
+                         for (i = 0; i < nrows; i++) {
+                              if (lambda[i]) nnz++;
+                              lambda[i] += scale * rowsol[i];
+                         }
+                    } else {
+                         nnz = 1;
+#ifdef LAMBDA
+                         for (i = 0; i < nrows; i++) {
+                              lambda[i] += scale * rowsol[i];
+                         }
+#else
+                         for (i = 0; i < nrows; i++) {
+                              lambda[i] = scale * rowsol[i];
+                         }
+                         for (i = 0; i < ncols; i++) {
+                              CoinBigIndex j;
+                              double value = cost[i] * maxmin;
+                              for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                                   int irow = row[j];
+                                   value += element[j] * lambda[irow];
+                              }
+                              cost[i] = value * maxmin;
+                         }
+                         for (i = 0; i < nrows; i++) {
+                              offset += lambda[i] * rowupper[i];
+                              lambda[i] = 0.0;
+                         }
+#ifdef DEBUG
+                         printf("offset %g\n", offset);
+#endif
+                         model_->setDblParam(OsiObjOffset, offset);
+#endif
+                    }
+                    nTry++;
+                    if (!nnz) {
+                         bestFeasible = 1.0e32;
+                         bestWeighted = 1.0e60;
+                         checkIteration = 0;
+                         result.weighted = 1.0e31;
+                    }
+#ifdef DEBUG
+                    double trueCost = 0.0;
+                    for (i = 0; i < ncols; i++) {
+                         int j;
+                         trueCost += cost[i] * colsol[i];
+                    }
+                    printf("True objective %g\n", trueCost - offset);
+#endif
+               } else {
+                    nTry++;
+               }
+               lastResult = result;
+               if (result.infeas < reasonableInfeas && !belowReasonable) {
+                    belowReasonable = 1;
+                    bestFeasible = 1.0e32;
+                    bestWeighted = 1.0e60;
+                    checkIteration = 0;
+                    result.weighted = 1.0e31;
+               }
+          }
+          if (iteration >= majorIterations_) {
+               // If not feasible and crash then dive dive dive
+               if (mu > 1.0e-12 && result.infeas > 1.0 && majorIterations_ < 40) {
+                    mu = 1.0e-30;
+                    majorIterations_ = iteration + 1;
+                    stopMu = 0.0;
+               } else {
+                    if (logLevel > 2)
+                         printf("Exiting due to number of major iterations\n");
+                    break;
+               }
+          }
+     }
+     majorIterations_ = saveMajorIterations;
+#ifndef OSI_IDIOT
+     if (scaled) {
+          // Scale solution and free arrays
+          const double * rowScale = model_->rowScale();
+          const double * columnScale = model_->columnScale();
+          int icol, irow;
+          for (icol = 0; icol < ncols; icol++) {
+               colsol[icol] *= columnScale[icol];
+               saveSol[icol] *= columnScale[icol];
+               dj[icol] /= columnScale[icol];
+          }
+          for (irow = 0; irow < nrows; irow++) {
+               rowsol[irow] /= rowScale[irow];
+               pi[irow] *= rowScale[irow];
+          }
+          // Don't know why getting Microsoft problems
+#if defined (_MSC_VER)
+          delete [] ( double *) elemXX;
+#else
+          delete [] elemXX;
+#endif
+          model_->setRowScale(NULL);
+          model_->setColumnScale(NULL);
+          delete [] lower;
+          delete [] upper;
+          delete [] cost;
+          lower = model_->columnLower();
+          upper = model_->columnUpper();
+          cost = model_->objective();
+          //rowlower = model_->rowLower();
+     }
+#endif
+#define TRYTHIS
+#ifdef TRYTHIS
+     if ((saveStrategy & 2048) != 0) {
+          double offset;
+          model_->getDblParam(OsiObjOffset, offset);
+          for (i = 0; i < ncols; i++) {
+               CoinBigIndex j;
+               double djval = cost[i] * maxmin;
+               for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                    int irow = row[j];
+                    djval -= element[j] * lambda[irow];
+               }
+               cost[i] = djval;
+          }
+          for (i = 0; i < nrows; i++) {
+               offset += lambda[i] * rowupper[i];
+          }
+          model_->setDblParam(OsiObjOffset, offset);
+     }
+#endif
+     if (saveLambdaScale) {
+          /* back off last update */
+          for (i = 0; i < nrows; i++) {
+               lambda[i] -= saveLambdaScale * rowsol[i];
+          }
+     }
+     muAtExit_ = mu;
+     // For last iteration make as feasible as possible
+     if (oddSlacks)
+          strategy_ |= 16384;
+     // not scaled
+     n = cleanIteration(iteration, ordStart, ordEnd,
+                        colsol,  lower,  upper,
+                        model_->rowLower(), model_->rowUpper(),
+                        cost, element, fixTolerance, lastResult.objval, lastResult.infeas);
+#if 0
+     if ((logLevel & 1) == 0 || (strategy_ & 16384) != 0) {
+          printf(
+               "%d - mu %g, infeasibility %g, objective %g, %d interior\n",
+               iteration, mu, lastResult.infeas, lastResult.objval, n);
+     }
+#endif
+#ifndef OSI_IDIOT
+     model_->setSumPrimalInfeasibilities(lastResult.infeas);
+#endif
+     // Put back more feasible solution
+     double saveInfeas[] = {0.0, 0.0};
+     for (int iSol = 0; iSol < 3; iSol++) {
+          const double * solution = iSol ? colsol : saveSol;
+          if (iSol == 2 && saveInfeas[0] < saveInfeas[1]) {
+               // put back best solution
+               CoinMemcpyN(saveSol, ncols, colsol);
+          }
+          double large = 0.0;
+          int i;
+          memset(rowsol, 0, nrows * sizeof(double));
+          for (i = 0; i < ncols; i++) {
+               CoinBigIndex j;
+               double value = solution[i];
+               for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+                    int irow = row[j];
+                    rowsol[irow] += element[j] * value;
+               }
+          }
+          for (i = 0; i < nrows; i++) {
+               if (rowsol[i] > rowupper[i]) {
+                    double diff = rowsol[i] - rowupper[i];
+                    if (diff > large)
+                         large = diff;
+               } else if (rowsol[i] < rowlower[i]) {
+                    double diff = rowlower[i] - rowsol[i];
+                    if (diff > large)
+                         large = diff;
+               }
+          }
+          if (iSol < 2)
+               saveInfeas[iSol] = large;
+          if (logLevel > 2)
+               printf("largest infeasibility is %g\n", large);
+     }
+     /* subtract out lambda */
+     for (i = 0; i < nrows; i++) {
+          pi[i] -= lambda[i];
+     }
+     for (i = 0; i < ncols; i++) {
+          CoinBigIndex j;
+          double djval = cost[i] * maxmin;
+          for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+               int irow = row[j];
+               djval -= element[j] * pi[irow];
+          }
+          dj[i] = djval;
+     }
+     if ((strategy_ & 1024) != 0) {
+          double ratio = static_cast<double> (ncols) / static_cast<double> (nrows);
+          COIN_DETAIL_PRINT(printf("col/row ratio %g infeas ratio %g\n", ratio, lastResult.infeas / firstInfeas));
+          if (lastResult.infeas > 0.01 * firstInfeas * ratio) {
+               strategy_ &= (~1024);
+               COIN_DETAIL_PRINT(printf(" - layer off\n"));
+          } else {
+	    COIN_DETAIL_PRINT(printf(" - layer on\n"));
+          }
+     }
+     delete [] saveSol;
+     delete [] lambda;
+     // save solution
+     // duals not much use - but save anyway
+#ifndef OSI_IDIOT
+     CoinMemcpyN(rowsol, nrows, model_->primalRowSolution());
+     CoinMemcpyN(colsol, ncols, model_->primalColumnSolution());
+     CoinMemcpyN(pi, nrows, model_->dualRowSolution());
+     CoinMemcpyN(dj, ncols, model_->dualColumnSolution());
+#else
+     model_->setColSolution(colsol);
+     model_->setRowPrice(pi);
+     delete [] cost;
+#endif
+     delete [] rowsol;
+     delete [] colsol;
+     delete [] pi;
+     delete [] dj;
+     delete [] rowlower;
+     delete [] rowupper;
+     return ;
+}
+#ifndef OSI_IDIOT
+void
+Idiot::crossOver(int mode)
+{
+     if (lightWeight_ == 2) {
+          // total failure
+          model_->allSlackBasis();
+          return;
+     }
+     double fixTolerance = IDIOT_FIX_TOLERANCE;
+#ifdef COIN_DEVELOP
+     double startTime = CoinCpuTime();
+#endif
+     ClpSimplex * saveModel = NULL;
+     ClpMatrixBase * matrix = model_->clpMatrix();
+     const int * row = matrix->getIndices();
+     const CoinBigIndex * columnStart = matrix->getVectorStarts();
+     const int * columnLength = matrix->getVectorLengths();
+     const double * element = matrix->getElements();
+     const double * rowupper = model_->getRowUpper();
+     int nrows = model_->getNumRows();
+     int ncols = model_->getNumCols();
+     double * rowsol, * colsol;
+     // different for Osi
+     double * lower = model_->columnLower();
+     double * upper = model_->columnUpper();
+     const double * rowlower = model_->getRowLower();
+     int * whenUsed = whenUsed_;
+     rowsol = model_->primalRowSolution();
+     colsol = model_->primalColumnSolution();;
+     double * cost = model_->objective();
+
+     int slackEnd, ordStart, ordEnd;
+     int slackStart = countCostedSlacks(model_);
+
+     int addAll = mode & 7;
+     int presolve = 0;
+
+     double djTolerance = djTolerance_;
+     if (djTolerance > 0.0 && djTolerance < 1.0)
+          djTolerance = 1.0;
+     int iteration;
+     int i, n = 0;
+     double ratio = 1.0;
+     double objValue = 0.0;
+     if ((strategy_ & 128) != 0) {
+          fixTolerance = SMALL_IDIOT_FIX_TOLERANCE;
+     }
+     if ((mode & 16) != 0 && addAll < 3) presolve = 1;
+     double * saveUpper = NULL;
+     double * saveLower = NULL;
+     double * saveRowUpper = NULL;
+     double * saveRowLower = NULL;
+     bool allowInfeasible = ((strategy_ & 8192) != 0) || (majorIterations_ > 1000000);
+     if (addAll < 3) {
+          saveUpper = new double [ncols];
+          saveLower = new double [ncols];
+          CoinMemcpyN(upper, ncols, saveUpper);
+          CoinMemcpyN(lower, ncols, saveLower);
+          if (allowInfeasible) {
+               saveRowUpper = new double [nrows];
+               saveRowLower = new double [nrows];
+               CoinMemcpyN(rowupper, nrows, saveRowUpper);
+               CoinMemcpyN(rowlower, nrows, saveRowLower);
+               double averageInfeas = model_->sumPrimalInfeasibilities() / static_cast<double> (model_->numberRows());
+               fixTolerance = CoinMax(fixTolerance, 1.0e-5 * averageInfeas);
+          }
+     }
+     if (slackStart >= 0) {
+          slackEnd = slackStart + nrows;
+          if (slackStart) {
+               ordStart = 0;
+               ordEnd = slackStart;
+          } else {
+               ordStart = nrows;
+               ordEnd = ncols;
+          }
+     } else {
+          slackEnd = slackStart;
+          ordStart = 0;
+          ordEnd = ncols;
+     }
+     /* get correct rowsol (without known slacks) */
+     memset(rowsol, 0, nrows * sizeof(double));
+     for (i = ordStart; i < ordEnd; i++) {
+          CoinBigIndex j;
+          double value = colsol[i];
+          if (value < lower[i] + fixTolerance) {
+               value = lower[i];
+               colsol[i] = value;
+          }
+          for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
+               int irow = row[j];
+               rowsol[irow] += value * element[j];
+          }
+     }
+     if (slackStart >= 0) {
+          for (i = 0; i < nrows; i++) {
+               if (ratio * rowsol[i] > rowlower[i] && rowsol[i] > 1.0e-8) {
+                    ratio = rowlower[i] / rowsol[i];
+               }
+          }
+          for (i = 0; i < nrows; i++) {
+               rowsol[i] *= ratio;
+          }
+          for (i = ordStart; i < ordEnd; i++) {
+               double value = colsol[i] * ratio;
+               colsol[i] = value;
+               objValue += value * cost[i];
+          }
+          for (i = 0; i < nrows; i++) {
+               double value = rowlower[i] - rowsol[i];
+               colsol[i+slackStart] = value;
+               objValue += value * cost[i+slackStart];
+          }
+          COIN_DETAIL_PRINT(printf("New objective after scaling %g\n", objValue));
+     }
+#if 0
+     maybe put back - but just get feasible ?
+     // If not many fixed then just exit
+     int numberFixed = 0;
+     for (i = ordStart; i < ordEnd; i++) {
+          if (colsol[i] < lower[i] + fixTolerance)
+               numberFixed++;
+          else if (colsol[i] > upper[i] - fixTolerance)
+               numberFixed++;
+     }
+     if (numberFixed < ncols / 2) {
+          addAll = 3;
+          presolve = 0;
+     }
+#endif
+#ifdef FEB_TRY
+     int savePerturbation = model_->perturbation();
+     int saveOptions = model_->specialOptions();
+     model_->setSpecialOptions(saveOptions | 8192);
+     if (savePerturbation_ == 50)
+          model_->setPerturbation(56);
+#endif
+     model_->createStatus();
+     /* addAll
+        0 - chosen,all used, all
+        1 - chosen, all
+        2 - all
+        3 - do not do anything  - maybe basis
+     */
+     for (i = ordStart; i < ordEnd; i++) {
+          if (addAll < 2) {
+               if (colsol[i] < lower[i] + fixTolerance) {
+                    upper[i] = lower[i];
+                    colsol[i] = lower[i];
+               } else if (colsol[i] > upper[i] - fixTolerance) {
+                    lower[i] = upper[i];
+                    colsol[i] = upper[i];
+               }
+          }
+          model_->setColumnStatus(i, ClpSimplex::superBasic);
+     }
+     if ((strategy_ & 16384) != 0) {
+          // put in basis
+          int * posSlack = whenUsed_ + ncols;
+          int * negSlack = posSlack + nrows;
+          int * nextSlack = negSlack + nrows;
+          /* Laci - try both ways - to see what works -
+             you can change second part as much as you want */
+#ifndef LACI_TRY  // was #if 1
+          // Array for sorting out slack values
+          double * ratio = new double [ncols];
+          int * which = new int [ncols];
+          for (i = 0; i < nrows; i++) {
+               if (posSlack[i] >= 0 || negSlack[i] >= 0) {
+                    int iCol;
+                    int nPlus = 0;
+                    int nMinus = 0;
+                    bool possible = true;
+                    // Get sum
+                    double sum = 0.0;
+                    iCol = posSlack[i];
+                    while (iCol >= 0) {
+                         double value = element[columnStart[iCol]];
+                         sum += value * colsol[iCol];
+                         if (lower[iCol]) {
+                              possible = false;
+                              break;
+                         } else {
+                              nPlus++;
+                         }
+                         iCol = nextSlack[iCol];
+                    }
+                    iCol = negSlack[i];
+                    while (iCol >= 0) {
+                         double value = -element[columnStart[iCol]];
+                         sum -= value * colsol[iCol];
+                         if (lower[iCol]) {
+                              possible = false;
+                              break;
+                         } else {
+                              nMinus++;
+                         }
+                         iCol = nextSlack[iCol];
+                    }
+                    //printf("%d plus, %d minus",nPlus,nMinus);
+                    //printf("\n");
+                    if ((rowsol[i] - rowlower[i] < 1.0e-7 ||
+                              rowupper[i] - rowsol[i] < 1.0e-7) &&
+                              nPlus + nMinus < 2)
+                         possible = false;
+                    if (possible) {
+                         // Amount contributed by other varaibles
+                         sum = rowsol[i] - sum;
+                         double lo = rowlower[i];
+                         if (lo > -1.0e20)
+                              lo -= sum;
+                         double up = rowupper[i];
+                         if (up < 1.0e20)
+                              up -= sum;
+                         //printf("row bounds %g %g\n",lo,up);
+                         if (0) {
+                              double sum = 0.0;
+                              double x = 0.0;
+                              for (int k = 0; k < ncols; k++) {
+                                   CoinBigIndex j;
+                                   double value = colsol[k];
+                                   x += value * cost[k];
+                                   for (j = columnStart[k]; j < columnStart[k] + columnLength[k]; j++) {
+                                        int irow = row[j];
+                                        if (irow == i)
+                                             sum += element[j] * value;
+                                   }
+                              }
+                              printf("Before sum %g <= %g <= %g cost %.18g\n",
+                                     rowlower[i], sum, rowupper[i], x);
+                         }
+                         // set all to zero
+                         iCol = posSlack[i];
+                         while (iCol >= 0) {
+                              colsol[iCol] = 0.0;
+                              iCol = nextSlack[iCol];
+                         }
+                         iCol = negSlack[i];
+                         while (iCol >= 0) {
+                              colsol[iCol] = 0.0;
+                              iCol = nextSlack[iCol];
+                         }
+                         {
+                              int iCol;
+                              iCol = posSlack[i];
+                              while (iCol >= 0) {
+                                   //printf("col %d el %g sol %g bounds %g %g cost %g\n",
+                                   //     iCol,element[columnStart[iCol]],
+                                   //     colsol[iCol],lower[iCol],upper[iCol],cost[iCol]);
+                                   iCol = nextSlack[iCol];
+                              }
+                              iCol = negSlack[i];
+                              while (iCol >= 0) {
+                                   //printf("col %d el %g sol %g bounds %g %g cost %g\n",
+                                   //     iCol,element[columnStart[iCol]],
+                                   //     colsol[iCol],lower[iCol],upper[iCol],cost[iCol]);
+                                   iCol = nextSlack[iCol];
+                              }
+                         }
+                         //printf("now what?\n");
+                         int n = 0;
+                         bool basic = false;
+                         if (lo > 0.0) {
+                              // Add in positive
+                              iCol = posSlack[i];
+                              while (iCol >= 0) {
+                                   double value = element[columnStart[iCol]];
+                                   ratio[n] = cost[iCol] / value;
+                                   which[n++] = iCol;
+                                   iCol = nextSlack[iCol];
+                              }
+                              CoinSort_2(ratio, ratio + n, which);
+                              for (int i = 0; i < n; i++) {
+                                   iCol = which[i];
+                                   double value = element[columnStart[iCol]];
+                                   if (lo >= upper[iCol]*value) {
+                                        value *= upper[iCol];
+                                        sum += value;
+                                        lo -= value;
+                                        colsol[iCol] = upper[iCol];
+                                   } else {
+                                        value = lo / value;
+                                        sum += lo;
+                                        lo = 0.0;
+                                        colsol[iCol] = value;
+                                        model_->setColumnStatus(iCol, ClpSimplex::basic);
+                                        basic = true;
+                                   }
+                                   if (lo < 1.0e-7)
+                                        break;
+                              }
+                         } else if (up < 0.0) {
+                              // Use lo so coding is more similar
+                              lo = -up;
+                              // Add in negative
+                              iCol = negSlack[i];
+                              while (iCol >= 0) {
+                                   double value = -element[columnStart[iCol]];
+                                   ratio[n] = cost[iCol] / value;
+                                   which[n++] = iCol;
+                                   iCol = nextSlack[iCol];
+                              }
+                              CoinSort_2(ratio, ratio + n, which);
+                              for (int i = 0; i < n; i++) {
+                                   iCol = which[i];
+                                   double value = -element[columnStart[iCol]];
+                                   if (lo >= upper[iCol]*value) {
+                                        value *= upper[iCol];
+                                        sum += value;
+                                        lo -= value;
+                                        colsol[iCol] = upper[iCol];
+                                   } else {
+                                        value = lo / value;
+                                        sum += lo;
+                                        lo = 0.0;
+                                        colsol[iCol] = value;
+                                        model_->setColumnStatus(iCol, ClpSimplex::basic);
+                                        basic = true;
+                                   }
+                                   if (lo < 1.0e-7)
+                                        break;
+                              }
+                         }
+                         if (0) {
+                              double sum2 = 0.0;
+                              double x = 0.0;
+                              for (int k = 0; k < ncols; k++) {
+                                   CoinBigIndex j;
+                                   double value = colsol[k];
+                                   x += value * cost[k];
+                                   for (j = columnStart[k]; j < columnStart[k] + columnLength[k]; j++) {
+                                        int irow = row[j];
+                                        if (irow == i)
+                                             sum2 += element[j] * value;
+                                   }
+                              }
+                              printf("after sum %g <= %g <= %g cost %.18g (sum = %g)\n",
+                                     rowlower[i], sum2, rowupper[i], x, sum);
+                         }
+                         rowsol[i] = sum;
+                         if (basic) {
+                              if (fabs(rowsol[i] - rowlower[i]) < fabs(rowsol[i] - rowupper[i]))
+                                   model_->setRowStatus(i, ClpSimplex::atLowerBound);
+                              else
+                                   model_->setRowStatus(i, ClpSimplex::atUpperBound);
+                         }
+                    } else {
+                         int n = 0;
+                         int iCol;
+                         iCol = posSlack[i];
+                         while (iCol >= 0) {
+                              if (colsol[iCol] > lower[iCol] + 1.0e-8 &&
+                                        colsol[iCol] < upper[iCol] - 1.0e-8) {
+                                   model_->setColumnStatus(iCol, ClpSimplex::basic);
+                                   n++;
+                              }
+                              iCol = nextSlack[iCol];
+                         }
+                         iCol = negSlack[i];
+                         while (iCol >= 0) {
+                              if (colsol[iCol] > lower[iCol] + 1.0e-8 &&
+                                        colsol[iCol] < upper[iCol] - 1.0e-8) {
+                                   model_->setColumnStatus(iCol, ClpSimplex::basic);
+                                   n++;
+                              }
+                              iCol = nextSlack[iCol];
+                         }
+                         if (n) {
+                              if (fabs(rowsol[i] - rowlower[i]) < fabs(rowsol[i] - rowupper[i]))
+                                   model_->setRowStatus(i, ClpSimplex::atLowerBound);
+                              else
+                                   model_->setRowStatus(i, ClpSimplex::atUpperBound);
+#ifdef CLP_INVESTIGATE
+                              if (n > 1)
+                                   printf("%d basic on row %d!\n", n, i);
+#endif
+                         }
+                    }
+               }
+          }
+          delete [] ratio;
+          delete [] which;
+#else
+          for (i = 0; i < nrows; i++) {
+               int n = 0;
+               int iCol;
+               iCol = posSlack[i];
+               while (iCol >= 0) {
+                    if (colsol[iCol] > lower[iCol] + 1.0e-8 &&
+                              colsol[iCol] < upper[iCol] - 1.0e-8) {
+                         model_->setColumnStatus(iCol, ClpSimplex::basic);
+                         n++;
+                    }
+                    iCol = nextSlack[iCol];
+               }
+               iCol = negSlack[i];
+               while (iCol >= 0) {
+                    if (colsol[iCol] > lower[iCol] + 1.0e-8 &&
+                              colsol[iCol] < upper[iCol] - 1.0e-8) {
+                         model_->setColumnStatus(iCol, ClpSimplex::basic);
+                         n++;
+                    }
+                    iCol = nextSlack[iCol];
+               }
+               if (n) {
+                    if (fabs(rowsol[i] - rowlower[i]) < fabs(rowsol[i] - rowupper[i]))
+                         model_->setRowStatus(i, ClpSimplex::atLowerBound);
+                    else
+                         model_->setRowStatus(i, ClpSimplex::atUpperBound);
+#ifdef CLP_INVESTIGATE
+                    if (n > 1)
+                         printf("%d basic on row %d!\n", n, i);
+#endif
+               }
+          }
+#endif
+     }
+     double maxmin;
+     if (model_->getObjSense() == -1.0) {
+          maxmin = -1.0;
+     } else {
+          maxmin = 1.0;
+     }
+     bool justValuesPass = majorIterations_ > 1000000;
+     if (slackStart >= 0) {
+          for (i = 0; i < nrows; i++) {
+               model_->setRowStatus(i, ClpSimplex::superBasic);
+          }
+          for (i = slackStart; i < slackEnd; i++) {
+               model_->setColumnStatus(i, ClpSimplex::basic);
+          }
+     } else {
+          /* still try and put singletons rather than artificials in basis */
+          int ninbas = 0;
+          for (i = 0; i < nrows; i++) {
+               model_->setRowStatus(i, ClpSimplex::basic);
+          }
+          for (i = 0; i < ncols; i++) {
+               if (columnLength[i] == 1 && upper[i] > lower[i] + 1.0e-5) {
+                    CoinBigIndex j = columnStart[i];
+                    double value = element[j];
+                    int irow = row[j];
+                    double rlo = rowlower[irow];
+                    double rup = rowupper[irow];
+                    double clo = lower[i];
+                    double cup = upper[i];
+                    double csol = colsol[i];
+                    /* adjust towards feasibility */
+                    double move = 0.0;
+                    if (rowsol[irow] > rup) {
+                         move = (rup - rowsol[irow]) / value;
+                         if (value > 0.0) {
+                              /* reduce */
+                              if (csol + move < clo) move = CoinMin(0.0, clo - csol);
+                         } else {
+                              /* increase */
+                              if (csol + move > cup) move = CoinMax(0.0, cup - csol);
+                         }
+                    } else if (rowsol[irow] < rlo) {
+                         move = (rlo - rowsol[irow]) / value;
+                         if (value > 0.0) {
+                              /* increase */
+                              if (csol + move > cup) move = CoinMax(0.0, cup - csol);
+                         } else {
+                              /* reduce */
+                              if (csol + move < clo) move = CoinMin(0.0, clo - csol);
+                         }
+                    } else {
+                         /* move to improve objective */
+                         if (cost[i]*maxmin > 0.0) {
+                              if (value > 0.0) {
+                                   move = (rlo - rowsol[irow]) / value;
+                                   /* reduce */
+                                   if (csol + move < clo) move = CoinMin(0.0, clo - csol);
+                              } else {
+                                   move = (rup - rowsol[irow]) / value;
+                                   /* increase */
+                                   if (csol + move > cup) move = CoinMax(0.0, cup - csol);
+                              }
+                         } else if (cost[i]*maxmin < 0.0) {
+                              if (value > 0.0) {
+                                   move = (rup - rowsol[irow]) / value;
+                                   /* increase */
+                                   if (csol + move > cup) move = CoinMax(0.0, cup - csol);
+                              } else {
+                                   move = (rlo - rowsol[irow]) / value;
+                                   /* reduce */
+                                   if (csol + move < clo) move = CoinMin(0.0, clo - csol);
+                              }
+                         }
+                    }
+                    rowsol[irow] += move * value;
+                    colsol[i] += move;
+                    /* put in basis if row was artificial */
+                    if (rup - rlo < 1.0e-7 && model_->getRowStatus(irow) == ClpSimplex::basic) {
+                         model_->setRowStatus(irow, ClpSimplex::superBasic);
+                         model_->setColumnStatus(i, ClpSimplex::basic);
+                         ninbas++;
+                    }
+               }
+          }
+          /*printf("%d in basis\n",ninbas);*/
+     }
+     bool wantVector = false;
+     if (dynamic_cast< ClpPackedMatrix*>(model_->clpMatrix())) {
+          // See if original wanted vector
+          ClpPackedMatrix * clpMatrixO = dynamic_cast< ClpPackedMatrix*>(model_->clpMatrix());
+          wantVector = clpMatrixO->wantsSpecialColumnCopy();
+     }
+     if (addAll < 3) {
+          ClpPresolve pinfo;
+          if (presolve) {
+               if (allowInfeasible) {
+                    // fix up so will be feasible
+                    double * rhs = new double[nrows];
+                    memset(rhs, 0, nrows * sizeof(double));
+                    model_->clpMatrix()->times(1.0, colsol, rhs);
+                    double * rowupper = model_->rowUpper();
+                    double * rowlower = model_->rowLower();
+                    saveRowUpper = CoinCopyOfArray(rowupper, nrows);
+                    saveRowLower = CoinCopyOfArray(rowlower, nrows);
+                    double sum = 0.0;
+                    for (i = 0; i < nrows; i++) {
+                         if (rhs[i] > rowupper[i]) {
+                              sum += rhs[i] - rowupper[i];
+                              rowupper[i] = rhs[i];
+                         }
+                         if (rhs[i] < rowlower[i]) {
+                              sum += rowlower[i] - rhs[i];
+                              rowlower[i] = rhs[i];
+                         }
+                    }
+                    COIN_DETAIL_PRINT(printf("sum of infeasibilities %g\n", sum));
+                    delete [] rhs;
+               }
+               saveModel = model_;
+               pinfo.setPresolveActions(pinfo.presolveActions() | 16384);
+               model_ = pinfo.presolvedModel(*model_, 1.0e-8, false, 5);
+          }
+          if (model_) {
+               if (!wantVector) {
+                    //#define TWO_GOES
+#ifdef ABC_INHERIT
+#ifndef TWO_GOES
+                    model_->dealWithAbc(1,justValuesPass ? 2 : 1);
+#else
+                    model_->dealWithAbc(1,1 + 11);
+#endif
+#else
+#ifndef TWO_GOES
+                    model_->primal(justValuesPass ? 2 : 1);
+#else
+                    model_->primal(1 + 11);
+#endif
+#endif
+               } else {
+                    ClpMatrixBase * matrix = model_->clpMatrix();
+                    ClpPackedMatrix * clpMatrix = dynamic_cast< ClpPackedMatrix*>(matrix);
+                    assert (clpMatrix);
+                    clpMatrix->makeSpecialColumnCopy();
+#ifdef ABC_INHERIT
+                    model_->dealWithAbc(1,1);
+#else
+                    model_->primal(1);
+#endif
+                    clpMatrix->releaseSpecialColumnCopy();
+               }
+               if (presolve) {
+		 model_->primal();
+                    pinfo.postsolve(true);
+                    delete model_;
+                    model_ = saveModel;
+                    saveModel = NULL;
+               }
+          } else {
+               // not feasible
+               addAll = 1;
+               presolve = 0;
+               model_ = saveModel;
+               saveModel = NULL;
+               if (justValuesPass)
+#ifdef ABC_INHERIT
+                    model_->dealWithAbc(1,2);
+#else
+                    model_->primal(2);
+#endif
+          }
+          if (allowInfeasible) {
+               CoinMemcpyN(saveRowUpper, nrows, model_->rowUpper());
+               CoinMemcpyN(saveRowLower, nrows, model_->rowLower());
+               delete [] saveRowUpper;
+               delete [] saveRowLower;
+               saveRowUpper = NULL;
+               saveRowLower = NULL;
+          }
+          if (addAll < 2) {
+               n = 0;
+               if (!addAll ) {
+                    /* could do scans to get a good number */
+                    iteration = 1;
+                    for (i = ordStart; i < ordEnd; i++) {
+                         if (whenUsed[i] >= iteration) {
+                              if (upper[i] - lower[i] < 1.0e-5 && saveUpper[i] - saveLower[i] > 1.0e-5) {
+                                   n++;
+                                   upper[i] = saveUpper[i];
+                                   lower[i] = saveLower[i];
+                              }
+                         }
+                    }
+               } else {
+                    for (i = ordStart; i < ordEnd; i++) {
+                         if (upper[i] - lower[i] < 1.0e-5 && saveUpper[i] - saveLower[i] > 1.0e-5) {
+                              n++;
+                              upper[i] = saveUpper[i];
+                              lower[i] = saveLower[i];
+                         }
+                    }
+                    delete [] saveUpper;
+                    delete [] saveLower;
+                    saveUpper = NULL;
+                    saveLower = NULL;
+               }
+#ifdef COIN_DEVELOP
+               printf("Time so far %g, %d now added from previous iterations\n",
+                      CoinCpuTime() - startTime, n);
+#endif
+               if (justValuesPass)
+                    return;
+               if (addAll)
+                    presolve = 0;
+               if (presolve) {
+                    saveModel = model_;
+                    model_ = pinfo.presolvedModel(*model_, 1.0e-8, false, 5);
+               } else {
+                    presolve = 0;
+               }
+               if (!wantVector) {
+#ifdef ABC_INHERIT
+                    model_->dealWithAbc(1,1);
+#else
+                    model_->primal(1);
+#endif
+               } else {
+                    ClpMatrixBase * matrix = model_->clpMatrix();
+                    ClpPackedMatrix * clpMatrix = dynamic_cast< ClpPackedMatrix*>(matrix);
+                    assert (clpMatrix);
+                    clpMatrix->makeSpecialColumnCopy();
+#ifdef ABC_INHERIT
+                    model_->dealWithAbc(1,1);
+#else
+                    model_->primal(1);
+#endif
+                    clpMatrix->releaseSpecialColumnCopy();
+               }
+               if (presolve) {
+                    pinfo.postsolve(true);
+                    delete model_;
+                    model_ = saveModel;
+                    saveModel = NULL;
+               }
+               if (!addAll) {
+                    n = 0;
+                    for (i = ordStart; i < ordEnd; i++) {
+                         if (upper[i] - lower[i] < 1.0e-5 && saveUpper[i] - saveLower[i] > 1.0e-5) {
+                              n++;
+                              upper[i] = saveUpper[i];
+                              lower[i] = saveLower[i];
+                         }
+                    }
+                    delete [] saveUpper;
+                    delete [] saveLower;
+                    saveUpper = NULL;
+                    saveLower = NULL;
+#ifdef COIN_DEVELOP
+                    printf("Time so far %g, %d now added from previous iterations\n",
+                           CoinCpuTime() - startTime, n);
+#endif
+               }
+               if (presolve) {
+                    saveModel = model_;
+                    model_ = pinfo.presolvedModel(*model_, 1.0e-8, false, 5);
+               } else {
+                    presolve = 0;
+               }
+               if (!wantVector) {
+#ifdef ABC_INHERIT
+                    model_->dealWithAbc(1,1);
+#else
+                    model_->primal(1);
+#endif
+               } else {
+                    ClpMatrixBase * matrix = model_->clpMatrix();
+                    ClpPackedMatrix * clpMatrix = dynamic_cast< ClpPackedMatrix*>(matrix);
+                    assert (clpMatrix);
+                    clpMatrix->makeSpecialColumnCopy();
+#ifdef ABC_INHERIT
+                    model_->dealWithAbc(1,1);
+#else
+                    model_->primal(1);
+#endif
+                    clpMatrix->releaseSpecialColumnCopy();
+               }
+               if (presolve) {
+                    pinfo.postsolve(true);
+                    delete model_;
+                    model_ = saveModel;
+                    saveModel = NULL;
+               }
+          }
+#ifdef COIN_DEVELOP
+          printf("Total time in crossover %g\n", CoinCpuTime() - startTime);
+#endif
+          delete [] saveUpper;
+          delete [] saveLower;
+     }
+#ifdef FEB_TRY
+     model_->setSpecialOptions(saveOptions);
+     model_->setPerturbation(savePerturbation);
+#endif
+     return ;
+}
+#endif
+/*****************************************************************************/
+
+// Default contructor
+Idiot::Idiot()
+{
+     model_ = NULL;
+     maxBigIts_ = 3;
+     maxIts_ = 5;
+     logLevel_ = 1;
+     logFreq_ = 100;
+     maxIts2_ = 100;
+     djTolerance_ = 1e-1;
+     mu_ = 1e-4;
+     drop_ = 5.0;
+     exitDrop_ = -1.0e20;
+     muFactor_ = 0.3333;
+     stopMu_ = 1e-12;
+     smallInfeas_ = 1e-1;
+     reasonableInfeas_ = 1e2;
+     muAtExit_ = 1.0e31;
+     strategy_ = 8;
+     lambdaIterations_ = 0;
+     checkFrequency_ = 100;
+     whenUsed_ = NULL;
+     majorIterations_ = 30;
+     exitFeasibility_ = -1.0;
+     dropEnoughFeasibility_ = 0.02;
+     dropEnoughWeighted_ = 0.01;
+     // adjust
+     double nrows = 10000.0;
+     int baseIts = static_cast<int> (sqrt(static_cast<double>(nrows)));
+     baseIts = baseIts / 10;
+     baseIts *= 10;
+     maxIts2_ = 200 + baseIts + 5;
+     maxIts2_ = 100;
+     reasonableInfeas_ = static_cast<double> (nrows) * 0.05;
+     lightWeight_ = 0;
+}
+// Constructor from model
+Idiot::Idiot(OsiSolverInterface &model)
+{
+     model_ = & model;
+     maxBigIts_ = 3;
+     maxIts_ = 5;
+     logLevel_ = 1;
+     logFreq_ = 100;
+     maxIts2_ = 100;
+     djTolerance_ = 1e-1;
+     mu_ = 1e-4;
+     drop_ = 5.0;
+     exitDrop_ = -1.0e20;
+     muFactor_ = 0.3333;
+     stopMu_ = 1e-12;
+     smallInfeas_ = 1e-1;
+     reasonableInfeas_ = 1e2;
+     muAtExit_ = 1.0e31;
+     strategy_ = 8;
+     lambdaIterations_ = 0;
+     checkFrequency_ = 100;
+     whenUsed_ = NULL;
+     majorIterations_ = 30;
+     exitFeasibility_ = -1.0;
+     dropEnoughFeasibility_ = 0.02;
+     dropEnoughWeighted_ = 0.01;
+     // adjust
+     double nrows;
+     if (model_)
+          nrows = model_->getNumRows();
+     else
+          nrows = 10000.0;
+     int baseIts = static_cast<int> (sqrt(static_cast<double>(nrows)));
+     baseIts = baseIts / 10;
+     baseIts *= 10;
+     maxIts2_ = 200 + baseIts + 5;
+     maxIts2_ = 100;
+     reasonableInfeas_ = static_cast<double> (nrows) * 0.05;
+     lightWeight_ = 0;
+}
+// Copy constructor.
+Idiot::Idiot(const Idiot &rhs)
+{
+     model_ = rhs.model_;
+     if (model_ && rhs.whenUsed_) {
+          int numberColumns = model_->getNumCols();
+          whenUsed_ = new int [numberColumns];
+          CoinMemcpyN(rhs.whenUsed_, numberColumns, whenUsed_);
+     } else {
+          whenUsed_ = NULL;
+     }
+     djTolerance_ = rhs.djTolerance_;
+     mu_ = rhs.mu_;
+     drop_ = rhs.drop_;
+     muFactor_ = rhs.muFactor_;
+     stopMu_ = rhs.stopMu_;
+     smallInfeas_ = rhs.smallInfeas_;
+     reasonableInfeas_ = rhs.reasonableInfeas_;
+     exitDrop_ = rhs.exitDrop_;
+     muAtExit_ = rhs.muAtExit_;
+     exitFeasibility_ = rhs.exitFeasibility_;
+     dropEnoughFeasibility_ = rhs.dropEnoughFeasibility_;
+     dropEnoughWeighted_ = rhs.dropEnoughWeighted_;
+     maxBigIts_ = rhs.maxBigIts_;
+     maxIts_ = rhs.maxIts_;
+     majorIterations_ = rhs.majorIterations_;
+     logLevel_ = rhs.logLevel_;
+     logFreq_ = rhs.logFreq_;
+     checkFrequency_ = rhs.checkFrequency_;
+     lambdaIterations_ = rhs.lambdaIterations_;
+     maxIts2_ = rhs.maxIts2_;
+     strategy_ = rhs.strategy_;
+     lightWeight_ = rhs.lightWeight_;
+}
+// Assignment operator. This copies the data
+Idiot &
+Idiot::operator=(const Idiot & rhs)
+{
+     if (this != &rhs) {
+          delete [] whenUsed_;
+          model_ = rhs.model_;
+          if (model_ && rhs.whenUsed_) {
+               int numberColumns = model_->getNumCols();
+               whenUsed_ = new int [numberColumns];
+               CoinMemcpyN(rhs.whenUsed_, numberColumns, whenUsed_);
+          } else {
+               whenUsed_ = NULL;
+          }
+          djTolerance_ = rhs.djTolerance_;
+          mu_ = rhs.mu_;
+          drop_ = rhs.drop_;
+          muFactor_ = rhs.muFactor_;
+          stopMu_ = rhs.stopMu_;
+          smallInfeas_ = rhs.smallInfeas_;
+          reasonableInfeas_ = rhs.reasonableInfeas_;
+          exitDrop_ = rhs.exitDrop_;
+          muAtExit_ = rhs.muAtExit_;
+          exitFeasibility_ = rhs.exitFeasibility_;
+          dropEnoughFeasibility_ = rhs.dropEnoughFeasibility_;
+          dropEnoughWeighted_ = rhs.dropEnoughWeighted_;
+          maxBigIts_ = rhs.maxBigIts_;
+          maxIts_ = rhs.maxIts_;
+          majorIterations_ = rhs.majorIterations_;
+          logLevel_ = rhs.logLevel_;
+          logFreq_ = rhs.logFreq_;
+          checkFrequency_ = rhs.checkFrequency_;
+          lambdaIterations_ = rhs.lambdaIterations_;
+          maxIts2_ = rhs.maxIts2_;
+          strategy_ = rhs.strategy_;
+          lightWeight_ = rhs.lightWeight_;
+     }
+     return *this;
+}
+Idiot::~Idiot()
+{
+     delete [] whenUsed_;
+}
diff --git a/cbits/coin/Idiot.hpp b/cbits/coin/Idiot.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/Idiot.hpp
@@ -0,0 +1,288 @@
+/* $Id: Idiot.hpp 1665 2011-01-04 17:55:54Z lou $ */
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+// "Idiot" as the name of this algorithm is copylefted.  If you want to change
+// the name then it should be something equally stupid (but not "Stupid") or
+// even better something witty.
+
+#ifndef Idiot_H
+#define Idiot_H
+#ifndef OSI_IDIOT
+#include "ClpSimplex.hpp"
+#define OsiSolverInterface ClpSimplex
+#else
+#include "OsiSolverInterface.hpp"
+typedef int CoinBigIndex;
+#endif
+class CoinMessageHandler;
+class CoinMessages;
+/// for use internally
+typedef struct {
+     double infeas;
+     double objval;
+     double dropThis;
+     double weighted;
+     double sumSquared;
+     double djAtBeginning;
+     double djAtEnd;
+     int iteration;
+} IdiotResult;
+/** This class implements a very silly algorithm.  It has no merit
+    apart from the fact that it gets an approximate solution to
+    some classes of problems.  Better if vaguely homogeneous.
+    It works on problems where volume algorithm works and often
+    gets a better primal solution but it has no dual solution.
+
+    It can also be used as a "crash" to get a problem started.  This
+    is probably its most useful function.
+
+    It is based on the idea that algorithms with terrible convergence
+    properties may be okay at first.  Throw in some random dubious tricks
+    and the resulting code may be worth keeping as long as you don't
+    look at it.
+
+*/
+
+class Idiot {
+
+public:
+
+     /**@name Constructors and destructor
+        Just a pointer to model is kept
+      */
+     //@{
+     /// Default constructor
+     Idiot (  );
+     /// Constructor with model
+     Idiot ( OsiSolverInterface & model );
+
+     /// Copy constructor.
+     Idiot(const Idiot &);
+     /// Assignment operator. This copies the data
+     Idiot & operator=(const Idiot & rhs);
+     /// Destructor
+     ~Idiot (  );
+     //@}
+
+
+     /**@name Algorithmic calls
+      */
+     //@{
+     /// Get an approximate solution with the idiot code
+     void solve();
+     /// Lightweight "crash"
+     void crash(int numberPass, CoinMessageHandler * handler,
+                const CoinMessages * messages, bool doCrossover = true);
+     /** Use simplex to get an optimal solution
+         mode is how many steps the simplex crossover should take to
+         arrive to an extreme point:
+         0 - chosen,all ever used, all
+         1 - chosen, all
+         2 - all
+         3 - do not do anything  - maybe basis
+         + 16 do presolves
+     */
+     void crossOver(int mode);
+     //@}
+
+
+     /**@name Gets and sets of most useful data
+      */
+     //@{
+     /** Starting weight - small emphasizes feasibility,
+         default 1.0e-4 */
+     inline double getStartingWeight() const {
+          return mu_;
+     }
+     inline void setStartingWeight(double value) {
+          mu_ = value;
+     }
+     /** Weight factor - weight multiplied by this when changes,
+         default 0.333 */
+     inline double getWeightFactor() const {
+          return muFactor_;
+     }
+     inline void setWeightFactor(double value) {
+          muFactor_ = value;
+     }
+     /** Feasibility tolerance - problem essentially feasible if
+         individual infeasibilities less than this.
+         default 0.1 */
+     inline double getFeasibilityTolerance() const {
+          return smallInfeas_;
+     }
+     inline void setFeasibilityTolerance(double value) {
+          smallInfeas_ = value;
+     }
+     /** Reasonably feasible.  Dubious method concentrates more on
+         objective when sum of infeasibilities less than this.
+         Very dubious default value of (Number of rows)/20 */
+     inline double getReasonablyFeasible() const {
+          return reasonableInfeas_;
+     }
+     inline void setReasonablyFeasible(double value) {
+          reasonableInfeas_ = value;
+     }
+     /** Exit infeasibility - exit if sum of infeasibilities less than this.
+         Default -1.0 (i.e. switched off) */
+     inline double getExitInfeasibility() const {
+          return exitFeasibility_;
+     }
+     inline void setExitInfeasibility(double value) {
+          exitFeasibility_ = value;
+     }
+     /** Major iterations.  stop after this number.
+         Default 30.  Use 2-5 for "crash" 50-100 for serious crunching */
+     inline int getMajorIterations() const {
+          return majorIterations_;
+     }
+     inline void setMajorIterations(int value) {
+          majorIterations_ = value;
+     }
+     /** Minor iterations.  Do this number of tiny steps before
+         deciding whether to change weights etc.
+         Default - dubious sqrt(Number of Rows).
+         Good numbers 105 to 405 say (5 is dubious method of making sure
+         idiot is not trying to be clever which it may do every 10 minor
+         iterations) */
+     inline int getMinorIterations() const {
+          return maxIts2_;
+     }
+     inline void setMinorIterations(int value) {
+          maxIts2_ = value;
+     }
+     // minor iterations for first time
+     inline int getMinorIterations0() const {
+          return maxIts_;
+     }
+     inline void setMinorIterations0(int value) {
+          maxIts_ = value;
+     }
+     /** Reduce weight after this many major iterations.  It may
+         get reduced before this but this is a maximum.
+         Default 3.  3-10 plausible. */
+     inline int getReduceIterations() const {
+          return maxBigIts_;
+     }
+     inline void setReduceIterations(int value) {
+          maxBigIts_ = value;
+     }
+     /// Amount of information - default of 1 should be okay
+     inline int getLogLevel() const {
+          return logLevel_;
+     }
+     inline void setLogLevel(int value) {
+          logLevel_ = value;
+     }
+     /// How lightweight - 0 not, 1 yes, 2 very lightweight
+     inline int getLightweight() const {
+          return lightWeight_;
+     }
+     inline void setLightweight(int value) {
+          lightWeight_ = value;
+     }
+     /// strategy
+     inline int getStrategy() const {
+          return strategy_;
+     }
+     inline void setStrategy(int value) {
+          strategy_ = value;
+     }
+     /// Fine tuning - okay if feasibility drop this factor
+     inline double getDropEnoughFeasibility() const {
+          return dropEnoughFeasibility_;
+     }
+     inline void setDropEnoughFeasibility(double value) {
+          dropEnoughFeasibility_ = value;
+     }
+     /// Fine tuning - okay if weighted obj drop this factor
+     inline double getDropEnoughWeighted() const {
+          return dropEnoughWeighted_;
+     }
+     inline void setDropEnoughWeighted(double value) {
+          dropEnoughWeighted_ = value;
+     }
+     //@}
+
+
+/// Stuff for internal use
+private:
+
+     /// Does actual work
+     // allow public!
+public:
+     void solve2(CoinMessageHandler * handler, const CoinMessages *messages);
+private:
+     IdiotResult IdiSolve(
+          int nrows, int ncols, double * rowsol , double * colsol,
+          double * pi, double * djs, const double * origcost ,
+          double * rowlower,
+          double * rowupper, const double * lower,
+          const double * upper, const double * element,
+          const int * row, const CoinBigIndex * colcc,
+          const int * length, double * lambda,
+          int maxIts, double mu, double drop,
+          double maxmin, double offset,
+          int strategy, double djTol, double djExit, double djFlag,
+          CoinThreadRandom * randomNumberGenerator);
+     int dropping(IdiotResult result,
+                  double tolerance,
+                  double small,
+                  int *nbad);
+     IdiotResult objval(int nrows, int ncols, double * rowsol , double * colsol,
+                        double * pi, double * djs, const double * cost ,
+                        const double * rowlower,
+                        const double * rowupper, const double * lower,
+                        const double * upper, const double * elemnt,
+                        const int * row, const CoinBigIndex * columnStart,
+                        const int * length, int extraBlock, int * rowExtra,
+                        double * solExtra, double * elemExtra, double * upperExtra,
+                        double * costExtra, double weight);
+     // Deals with whenUsed and slacks
+     int cleanIteration(int iteration, int ordinaryStart, int ordinaryEnd,
+                        double * colsol, const double * lower, const double * upper,
+                        const double * rowLower, const double * rowUpper,
+                        const double * cost, const double * element, double fixTolerance, double & objChange,
+                        double & infChange);
+private:
+     /// Underlying model
+     OsiSolverInterface * model_;
+
+     double djTolerance_;
+     double mu_;  /* starting mu */
+     double drop_; /* exit if drop over 5 checks less than this */
+     double muFactor_; /* reduce mu by this */
+     double stopMu_; /* exit if mu gets smaller than this */
+     double smallInfeas_; /* feasibility tolerance */
+     double reasonableInfeas_; /* use lambdas if feasibility less than this */
+     double exitDrop_; /* candidate for stopping after a major iteration */
+     double muAtExit_; /* mu on exit */
+     double exitFeasibility_; /* exit if infeasibility less than this */
+     double dropEnoughFeasibility_; /* okay if feasibility drop this factor */
+     double dropEnoughWeighted_; /* okay if weighted obj drop this factor */
+     int * whenUsed_; /* array to say what was used */
+     int maxBigIts_; /* always reduce mu after this */
+     int maxIts_; /* do this many iterations on first go */
+     int majorIterations_;
+     int logLevel_;
+     int logFreq_;
+     int checkFrequency_; /* can exit after 5 * this iterations (on drop) */
+     int lambdaIterations_; /* do at least this many lambda iterations */
+     int maxIts2_; /* do this many iterations on subsequent goes */
+     int strategy_;   /* 0 - default strategy
+		     1 - do accelerator step but be cautious
+		     2 - do not do accelerator step
+		     4 - drop, exitDrop and djTolerance all relative
+		     8 - keep accelerator step to theta=10.0
+
+                    32 - Scale
+		   512 - crossover
+                  2048 - keep lambda across mu change
+		  4096 - return best solution (not last found)
+		  8192 - always do a presolve in crossover
+		 16384 - costed slacks found - so whenUsed_ longer */
+     int lightWeight_; // 0 - normal, 1 lightweight
+};
+#endif
diff --git a/cbits/coin/OsiAuxInfo.cpp b/cbits/coin/OsiAuxInfo.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiAuxInfo.cpp
@@ -0,0 +1,188 @@
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiAuxInfo.hpp"
+
+// Default Constructor
+OsiAuxInfo::OsiAuxInfo(void * appData) 
+  : appData_(appData)
+{
+}
+
+// Destructor 
+OsiAuxInfo::~OsiAuxInfo ()
+{
+}
+
+// Clone
+OsiAuxInfo *
+OsiAuxInfo::clone() const
+{
+  return new OsiAuxInfo(*this);
+}
+
+// Copy constructor 
+OsiAuxInfo::OsiAuxInfo(const OsiAuxInfo & rhs)
+:
+  appData_(rhs.appData_)
+{
+}
+OsiAuxInfo &
+OsiAuxInfo::operator=(const OsiAuxInfo &rhs)
+{
+  if (this != &rhs) {
+    appData_ = rhs.appData_;
+  }
+  return *this;
+}
+// Default Constructor
+OsiBabSolver::OsiBabSolver(int solverType) 
+  :OsiAuxInfo(),
+   bestObjectiveValue_(1.0e100),
+   mipBound_(-1.0e100),
+   solver_(NULL),
+   bestSolution_(NULL),
+   beforeLower_(NULL),
+   beforeUpper_(NULL),
+   solverType_(solverType),
+   sizeSolution_(0),
+   extraCharacteristics_(0)
+{
+}
+
+// Destructor 
+OsiBabSolver::~OsiBabSolver ()
+{
+  delete [] bestSolution_;
+}
+
+// Clone
+OsiAuxInfo *
+OsiBabSolver::clone() const
+{
+  return new OsiBabSolver(*this);
+}
+
+// Copy constructor 
+OsiBabSolver::OsiBabSolver(const OsiBabSolver & rhs)
+:
+  OsiAuxInfo(rhs),
+  bestObjectiveValue_(rhs.bestObjectiveValue_),
+  mipBound_(rhs.mipBound_),
+  solver_(rhs.solver_),
+  bestSolution_(NULL),
+  beforeLower_(rhs.beforeLower_),
+  beforeUpper_(rhs.beforeUpper_),
+  solverType_(rhs.solverType_),
+  sizeSolution_(rhs.sizeSolution_),
+  extraCharacteristics_(rhs.extraCharacteristics_)
+{
+  if (rhs.bestSolution_) {
+    assert (solver_);
+    bestSolution_ = CoinCopyOfArray(rhs.bestSolution_,sizeSolution_);
+  }
+}
+OsiBabSolver &
+OsiBabSolver::operator=(const OsiBabSolver &rhs)
+{
+  if (this != &rhs) {
+    OsiAuxInfo::operator=(rhs);
+    delete [] bestSolution_;
+    solver_ = rhs.solver_;
+    solverType_ = rhs.solverType_;
+    bestObjectiveValue_ = rhs.bestObjectiveValue_;
+    bestSolution_ = NULL;
+    mipBound_ = rhs.mipBound_;
+    sizeSolution_ = rhs.sizeSolution_;
+    extraCharacteristics_ = rhs.extraCharacteristics_;
+    beforeLower_ = rhs.beforeLower_;
+    beforeUpper_ = rhs.beforeUpper_;
+    if (rhs.bestSolution_) {
+      assert (solver_);
+      bestSolution_ = CoinCopyOfArray(rhs.bestSolution_,sizeSolution_);
+    }
+  }
+  return *this;
+}
+// Returns 1 if solution, 0 if not
+int
+OsiBabSolver::solution(double & solutionValue,
+                       double * betterSolution,
+                       int numberColumns)
+{
+  if (!solver_)
+    return 0;
+  //printf("getSol %x solution_address %x - value %g\n",
+  //       this,bestSolution_,bestObjectiveValue_);
+  if (bestObjectiveValue_<solutionValue&&bestSolution_) {
+    // new solution
+    memcpy(betterSolution,bestSolution_,CoinMin(numberColumns,sizeSolution_)*sizeof(double));
+    if (sizeSolution_<numberColumns)
+      CoinZeroN(betterSolution+sizeSolution_,numberColumns-sizeSolution_);
+    solutionValue = bestObjectiveValue_;
+    // free up
+    //delete [] bestSolution_;
+    //bestSolution_=NULL;
+    //bestObjectiveValue_=1.0e100;
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+bool
+OsiBabSolver::hasSolution(double & solutionValue, double * solution)
+{
+  if (! bestSolution_)
+    return false;
+  
+  int numberColumns = solver_->getNumCols();
+  memcpy(solution,bestSolution_,numberColumns*sizeof(double));
+  solutionValue = bestObjectiveValue_;
+  return true;
+}
+
+// set solution
+void
+OsiBabSolver::setSolution(const double * solution, int numberColumns, double objectiveValue)
+{
+  assert (solver_);
+  // just in case size has changed
+  delete [] bestSolution_;
+  sizeSolution_ = CoinMin(solver_->getNumCols(),numberColumns);
+  bestSolution_ = new double [sizeSolution_];
+  CoinZeroN(bestSolution_,sizeSolution_);
+  CoinMemcpyN(solution,CoinMin(sizeSolution_,numberColumns),bestSolution_);
+  bestObjectiveValue_ = objectiveValue*solver_->getObjSense();
+}
+// Get objective  (well mip bound)
+double 
+OsiBabSolver::mipBound() const
+{
+  assert (solver_);
+  if (solverType_!=3)
+    return solver_->getObjSense()*solver_->getObjValue();
+  else
+    return mipBound_;
+}
+// Returns true if node feasible
+bool 
+OsiBabSolver::mipFeasible() const
+{
+  assert (solver_);
+  if (solverType_==0)
+    return true;
+  else if (solverType_!=3)
+    return solver_->isProvenOptimal();
+  else
+    return mipBound_<1.0e50;
+}
diff --git a/cbits/coin/OsiAuxInfo.hpp b/cbits/coin/OsiAuxInfo.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiAuxInfo.hpp
@@ -0,0 +1,206 @@
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiAuxInfo_H
+#define OsiAuxInfo_H
+
+class OsiSolverInterface;
+
+//#############################################################################
+/** This class allows for a more structured use of algorithmic tweaking to
+    an OsiSolverInterface.  It is designed to replace the simple use of
+    appData_ pointer.
+
+    This has been done to make it easier to use NonLinear solvers and other
+    exotic beasts in a branch and bound mode.  After this class definition
+    there is one for a derived class for just such a purpose.
+
+*/
+
+class OsiAuxInfo {
+public:
+  // Default Constructor 
+  OsiAuxInfo (void * appData = NULL);
+
+  // Copy Constructor 
+  OsiAuxInfo (const OsiAuxInfo & rhs);
+  // Destructor
+  virtual ~OsiAuxInfo();
+  
+  /// Clone
+  virtual OsiAuxInfo * clone() const;
+  /// Assignment operator 
+  OsiAuxInfo & operator=(const OsiAuxInfo& rhs);
+  
+  /// Get application data
+  inline void * getApplicationData() const
+  { return appData_;}
+protected:
+    /// Pointer to user-defined data structure
+    void * appData_;
+};
+//#############################################################################
+/** This class allows for the use of more exotic solvers e.g. Non-Linear or Volume.
+
+    You can derive from this although at present I can't see the need.
+*/
+
+class OsiBabSolver : public OsiAuxInfo {
+public:
+  // Default Constructor 
+  OsiBabSolver (int solverType=0);
+
+  // Copy Constructor 
+  OsiBabSolver (const OsiBabSolver & rhs);
+  // Destructor
+  virtual ~OsiBabSolver();
+  
+  /// Clone
+  virtual OsiAuxInfo * clone() const;
+  /// Assignment operator 
+  OsiBabSolver & operator=(const OsiBabSolver& rhs);
+  
+  /// Update solver 
+  inline void setSolver(const OsiSolverInterface * solver)
+  { solver_ = solver;}
+  /// Update solver 
+  inline void setSolver(const OsiSolverInterface & solver)
+  { solver_ = &solver;}
+
+  /** returns 0 if no heuristic solution, 1 if valid solution
+      with better objective value than one passed in
+      Sets solution values if good, sets objective value 
+      numberColumns is size of newSolution
+  */
+  int solution(double & objectiveValue,
+		       double * newSolution, int numberColumns);
+  /** Set solution and objective value.
+      Number of columns and optimization direction taken from current solver.
+      Size of solution is numberColumns (may be padded or truncated in function) */
+  void setSolution(const double * solution, int numberColumns, double objectiveValue);
+
+  /** returns true if the object stores a solution, false otherwise. If there
+	  is a solution then solutionValue and solution will be filled out as well.
+      In that case the user needs to allocate solution to be a big enough
+	  array.
+  */
+  bool hasSolution(double & solutionValue, double * solution);
+
+  /** Sets solver type
+      0 - normal LP solver
+      1 - DW - may also return heuristic solutions
+      2 - NLP solver or similar - can't compute objective value just from solution
+          check solver to see if feasible and what objective value is
+          - may also return heuristic solution
+      3 - NLP solver or similar - can't compute objective value just from solution
+          check this (rather than solver) to see if feasible and what objective value is.
+          Using Outer Approximation so called lp based
+          - may also return heuristic solution
+      4 - normal solver but cuts are needed for integral solution    
+  */
+  inline void setSolverType(int value)
+  { solverType_=value;}
+  /** gets solver type
+      0 - normal LP solver
+      1 - DW - may also return heuristic solutions
+      2 - NLP solver or similar - can't compute objective value just from solution
+          check this (rather than solver) to see if feasible and what objective value is
+          - may also return heuristic solution
+      3 - NLP solver or similar - can't compute objective value just from solution
+          check this (rather than solver) to see if feasible and what objective value is.
+          Using Outer Approximation so called lp based
+          - may also return heuristic solution
+      4 - normal solver but cuts are needed for integral solution    
+  */
+  inline int solverType() const
+  { return solverType_;}
+  /** Return true if getting solution may add cuts so hot start etc will
+      be obsolete */
+  inline bool solutionAddsCuts() const
+  { return solverType_==3;}
+  /// Return true if we should try cuts at root even if looks satisfied
+  inline bool alwaysTryCutsAtRootNode() const
+  { return solverType_==4;}
+  /** Returns true if can use solver objective or feasible values,
+      otherwise use mipBound etc */
+  inline bool solverAccurate() const
+  { return solverType_==0||solverType_==2||solverType_==4;}
+  /// Returns true if can use reduced costs for fixing
+  inline bool reducedCostsAccurate() const
+  { return solverType_==0||solverType_==4;}
+  /// Get objective  (well mip bound)
+  double mipBound() const;
+  /// Returns true if node feasible
+  bool mipFeasible() const;
+  /// Set mip bound (only used for some solvers)
+  inline void setMipBound(double value)
+  { mipBound_ = value;}
+  /// Get objective value of saved solution
+  inline double bestObjectiveValue() const
+  { return bestObjectiveValue_;}
+  /// Says whether we want to try cuts at all
+  inline bool tryCuts() const
+  { return solverType_!=2;}
+  /// Says whether we have a warm start (so can do strong branching)
+  inline bool warmStart() const
+  { return solverType_!=2;}
+  /** Get bit mask for odd actions of solvers
+      1 - solution or bound arrays may move in mysterious ways e.g. cplex
+      2 - solver may want bounds before branch
+  */
+  inline int extraCharacteristics() const
+  { return extraCharacteristics_;}
+  /** Set bit mask for odd actions of solvers
+      1 - solution or bound arrays may move in mysterious ways e.g. cplex
+      2 - solver may want bounds before branch
+  */
+  inline void setExtraCharacteristics(int value)
+  { extraCharacteristics_=value;}
+  /// Pointer to lower bounds before branch (only if extraCharacteristics set)
+  inline const double * beforeLower() const
+  { return beforeLower_;}
+  /// Set pointer to lower bounds before branch (only if extraCharacteristics set)
+  inline void setBeforeLower(const double * array)
+  { beforeLower_ = array;}
+  /// Pointer to upper bounds before branch (only if extraCharacteristics set)
+  inline const double * beforeUpper() const
+  { return beforeUpper_;}
+  /// Set pointer to upper bounds before branch (only if extraCharacteristics set)
+  inline void setBeforeUpper(const double * array)
+  { beforeUpper_ = array;}
+protected:
+  /// Objective value of best solution (if there is one) (minimization)
+  double bestObjectiveValue_;
+  /// Current lower bound on solution ( if > 1.0e50 infeasible)
+  double mipBound_;
+  /// Solver to use for getting/setting solutions etc
+  const OsiSolverInterface * solver_;
+  /// Best integer feasible solution
+  double * bestSolution_;
+  /// Pointer to lower bounds before branch (only if extraCharacteristics set)
+  const double * beforeLower_;
+  /// Pointer to upper bounds before branch (only if extraCharacteristics set)
+  const double * beforeUpper_;
+  /** Solver type
+      0 - normal LP solver
+      1 - DW - may also return heuristic solutions
+      2 - NLP solver or similar - can't compute objective value just from solution
+          check this (rather than solver) to see if feasible and what objective value is
+          - may also return heuristic solution
+      3 - NLP solver or similar - can't compute objective value just from solution
+          check this (rather than solver) to see if feasible and what objective value is.
+          Using Outer Approximation so called lp based
+          - may also return heuristic solution
+  */
+  int solverType_;
+  /// Size of solution
+  int sizeSolution_;
+  /** Bit mask for odd actions of solvers
+      1 - solution or bound arrays may move in mysterious ways e.g. cplex
+      2 - solver may want bounds before branch
+  */
+  int extraCharacteristics_;
+};
+
+#endif
diff --git a/cbits/coin/OsiBranchingObject.cpp b/cbits/coin/OsiBranchingObject.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiBranchingObject.cpp
@@ -0,0 +1,2004 @@
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+#include <cassert>
+#include <cstdlib>
+#include <cmath>
+#include <cfloat>
+//#define OSI_DEBUG
+#include "OsiSolverInterface.hpp"
+#include "OsiBranchingObject.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinSort.hpp"
+#include "CoinError.hpp"
+#include "CoinFinite.hpp"
+
+// Default Constructor
+OsiObject::OsiObject() 
+  :infeasibility_(0.0),
+   whichWay_(0),
+   numberWays_(2),
+   priority_(1000)
+{
+}
+
+
+// Destructor 
+OsiObject::~OsiObject ()
+{
+}
+
+// Copy constructor 
+OsiObject::OsiObject ( const OsiObject & rhs)
+{
+  infeasibility_ = rhs.infeasibility_;
+  whichWay_ = rhs.whichWay_;
+  priority_ = rhs.priority_;
+  numberWays_ = rhs.numberWays_;
+}
+
+// Assignment operator 
+OsiObject & 
+OsiObject::operator=( const OsiObject& rhs)
+{
+  if (this!=&rhs) {
+    infeasibility_ = rhs.infeasibility_;
+    whichWay_ = rhs.whichWay_;
+    priority_ = rhs.priority_;
+    numberWays_ = rhs.numberWays_;
+  }
+  return *this;
+}
+// Return "up" estimate (default 1.0e-5)
+double 
+OsiObject::upEstimate() const
+{
+  return 1.0e-5;
+}
+// Return "down" estimate (default 1.0e-5)
+double 
+OsiObject::downEstimate() const
+{
+  return 1.0e-5;
+}
+// Column number if single column object -1 otherwise
+int 
+OsiObject::columnNumber() const
+{
+  return -1;
+}
+// Infeasibility - large is 0.5
+double 
+OsiObject::infeasibility(const OsiSolverInterface * solver, int & preferredWay) const
+{
+  // Can't guarantee has matrix
+  OsiBranchingInformation info(solver,false,false);
+  return infeasibility(&info,preferredWay);
+}
+// This does NOT set mutable stuff
+double 
+OsiObject::checkInfeasibility(const OsiBranchingInformation * info) const
+{
+  int way;
+  double saveInfeasibility = infeasibility_;
+  short int saveWhichWay = whichWay_ ;
+  double value = infeasibility(info,way);
+  infeasibility_ = saveInfeasibility;
+  whichWay_ = saveWhichWay;
+  return value;
+}
+
+/* For the variable(s) referenced by the object,
+   look at the current solution and set bounds to match the solution.
+   Returns measure of how much it had to move solution to make feasible
+*/
+double 
+OsiObject::feasibleRegion(OsiSolverInterface * solver) const 
+{
+  // Can't guarantee has matrix
+  OsiBranchingInformation info(solver,false,false);
+  return feasibleRegion(solver,&info);
+}
+
+// Default Constructor
+OsiObject2::OsiObject2() 
+  : OsiObject(),
+    preferredWay_(-1),
+    otherInfeasibility_(0.0)
+{
+}
+
+
+// Destructor 
+OsiObject2::~OsiObject2 ()
+{
+}
+
+// Copy constructor 
+OsiObject2::OsiObject2 ( const OsiObject2 & rhs)
+  : OsiObject(rhs),
+    preferredWay_(rhs.preferredWay_),
+    otherInfeasibility_ (rhs.otherInfeasibility_)
+{
+}
+
+// Assignment operator 
+OsiObject2 & 
+OsiObject2::operator=( const OsiObject2& rhs)
+{
+  if (this!=&rhs) {
+    OsiObject::operator=(rhs);
+    preferredWay_ = rhs.preferredWay_;
+    otherInfeasibility_ = rhs.otherInfeasibility_;
+  }
+  return *this;
+}
+// Default Constructor 
+OsiBranchingObject::OsiBranchingObject()
+{
+  originalObject_=NULL;
+  branchIndex_=0;
+  value_=0.0;
+  numberBranches_=2;
+}
+
+// Useful constructor
+OsiBranchingObject::OsiBranchingObject (OsiSolverInterface * ,
+					 double value)
+{
+  originalObject_=NULL;
+  branchIndex_=0;
+  value_=value;
+  numberBranches_=2;
+}
+
+// Copy constructor 
+OsiBranchingObject::OsiBranchingObject ( const OsiBranchingObject & rhs)
+{
+  originalObject_=rhs.originalObject_;
+  branchIndex_=rhs.branchIndex_;
+  value_=rhs.value_;
+  numberBranches_=rhs.numberBranches_;
+}
+
+// Assignment operator 
+OsiBranchingObject & 
+OsiBranchingObject::operator=( const OsiBranchingObject& rhs)
+{
+  if (this != &rhs) {
+    originalObject_=rhs.originalObject_;
+    branchIndex_=rhs.branchIndex_;
+    value_=rhs.value_;
+    numberBranches_=rhs.numberBranches_;
+  }
+  return *this;
+}
+
+// Destructor 
+OsiBranchingObject::~OsiBranchingObject ()
+{
+}
+// For debug
+int 
+OsiBranchingObject::columnNumber() const
+{
+  if (originalObject_)
+    return originalObject_->columnNumber();
+  else
+    return -1;
+}
+/** Default Constructor
+
+*/
+OsiBranchingInformation::OsiBranchingInformation ()
+  : objectiveValue_(COIN_DBL_MAX),
+    cutoff_(COIN_DBL_MAX),
+    direction_(COIN_DBL_MAX),
+    integerTolerance_(1.0e-7),
+    primalTolerance_(1.0e-7),
+    timeRemaining_(COIN_DBL_MAX),
+    defaultDual_(-1.0),
+    solver_(NULL),
+    numberColumns_(0),
+    lower_(NULL),
+    solution_(NULL),
+    upper_(NULL),
+    hotstartSolution_(NULL),
+    pi_(NULL),
+    rowActivity_(NULL),
+    objective_(NULL),
+    rowLower_(NULL),
+    rowUpper_(NULL),
+    elementByColumn_(NULL),
+    columnStart_(NULL),
+    columnLength_(NULL),
+    row_(NULL),
+    usefulRegion_(NULL),
+    indexRegion_(NULL),
+    numberSolutions_(0),
+    numberBranchingSolutions_(0),
+    depth_(0),
+    owningSolution_(false)
+{
+}
+
+/** Useful constructor
+*/
+OsiBranchingInformation::OsiBranchingInformation (const OsiSolverInterface * solver,
+						  bool /*normalSolver*/,
+						  bool owningSolution)
+  : timeRemaining_(COIN_DBL_MAX),
+    defaultDual_(-1.0),
+    solver_(solver),
+    hotstartSolution_(NULL),
+    usefulRegion_(NULL),
+    indexRegion_(NULL),
+    numberSolutions_(0),
+    numberBranchingSolutions_(0),
+    depth_(0),
+    owningSolution_(owningSolution)
+{
+  direction_ = solver_->getObjSense();
+  objectiveValue_ = solver_->getObjValue();
+  objectiveValue_ *= direction_;
+  solver_->getDblParam(OsiDualObjectiveLimit,cutoff_) ;
+  cutoff_ *= direction_;
+  integerTolerance_ = solver_->getIntegerTolerance();
+  solver_->getDblParam(OsiPrimalTolerance,primalTolerance_) ;
+  numberColumns_ = solver_->getNumCols();
+  lower_ = solver_->getColLower();
+  if (owningSolution_)
+    solution_ = CoinCopyOfArray(solver_->getColSolution(),numberColumns_);
+  else
+    solution_ = solver_->getColSolution();
+  upper_ = solver_->getColUpper();
+  pi_ = solver_->getRowPrice();
+  rowActivity_ = solver_->getRowActivity();
+  objective_ = solver_->getObjCoefficients();
+  rowLower_ = solver_->getRowLower();
+  rowUpper_ = solver_->getRowUpper();
+  const CoinPackedMatrix* matrix = solver_->getMatrixByCol();
+  if (matrix) {
+    // Column copy of matrix if matrix exists
+    elementByColumn_ = matrix->getElements();
+    row_ = matrix->getIndices();
+    columnStart_ = matrix->getVectorStarts();
+    columnLength_ = matrix->getVectorLengths();
+  } else {
+    // Matrix does not exist
+    elementByColumn_ = NULL;
+    row_ = NULL;
+    columnStart_ = NULL;
+    columnLength_ = NULL;
+  }
+}
+// Copy constructor 
+OsiBranchingInformation::OsiBranchingInformation ( const OsiBranchingInformation & rhs)
+{
+  objectiveValue_ = rhs.objectiveValue_;
+  cutoff_ = rhs.cutoff_;
+  direction_ = rhs.direction_;
+  integerTolerance_ = rhs.integerTolerance_;
+  primalTolerance_ = rhs.primalTolerance_;
+  timeRemaining_ = rhs.timeRemaining_;
+  defaultDual_ = rhs.defaultDual_;
+  solver_ = rhs.solver_;
+  numberColumns_ = rhs.numberColumns_;
+  lower_ = rhs.lower_;
+  owningSolution_ = rhs.owningSolution_;
+  if (owningSolution_)
+    solution_ = CoinCopyOfArray(rhs.solution_,numberColumns_);
+  else
+    solution_ = rhs.solution_;
+  upper_ = rhs.upper_;
+  hotstartSolution_ = rhs.hotstartSolution_;
+  pi_ = rhs.pi_;
+  rowActivity_ = rhs.rowActivity_;
+  objective_ = rhs.objective_;
+  rowLower_ = rhs.rowLower_;
+  rowUpper_ = rhs.rowUpper_;
+  elementByColumn_ = rhs.elementByColumn_;
+  row_ = rhs.row_;
+  columnStart_ = rhs.columnStart_;
+  columnLength_ = rhs.columnLength_;
+  usefulRegion_ = rhs.usefulRegion_;
+  assert (!usefulRegion_);
+  indexRegion_ = rhs.indexRegion_;
+  numberSolutions_ = rhs.numberSolutions_;
+  numberBranchingSolutions_ = rhs.numberBranchingSolutions_;
+  depth_ = rhs.depth_;
+}
+
+// Clone
+OsiBranchingInformation *
+OsiBranchingInformation::clone() const
+{
+  return new OsiBranchingInformation(*this);
+}
+
+// Assignment operator 
+OsiBranchingInformation & 
+OsiBranchingInformation::operator=( const OsiBranchingInformation& rhs)
+{
+  if (this!=&rhs) {
+    objectiveValue_ = rhs.objectiveValue_;
+    cutoff_ = rhs.cutoff_;
+    direction_ = rhs.direction_;
+    integerTolerance_ = rhs.integerTolerance_;
+    primalTolerance_ = rhs.primalTolerance_;
+    timeRemaining_ = rhs.timeRemaining_;
+    defaultDual_ = rhs.defaultDual_;
+    numberColumns_ = rhs.numberColumns_;
+    lower_ = rhs.lower_;
+    owningSolution_ = rhs.owningSolution_;
+    if (owningSolution_) {
+      solution_ = CoinCopyOfArray(rhs.solution_,numberColumns_);
+      delete [] solution_;
+    } else {
+      solution_ = rhs.solution_;
+    }
+    upper_ = rhs.upper_;
+    hotstartSolution_ = rhs.hotstartSolution_;
+    pi_ = rhs.pi_;
+    rowActivity_ = rhs.rowActivity_;
+    objective_ = rhs.objective_;
+    rowLower_ = rhs.rowLower_;
+    rowUpper_ = rhs.rowUpper_;
+    elementByColumn_ = rhs.elementByColumn_;
+    row_ = rhs.row_;
+    columnStart_ = rhs.columnStart_;
+    columnLength_ = rhs.columnLength_;
+    usefulRegion_ = rhs.usefulRegion_;
+    assert (!usefulRegion_);
+    indexRegion_ = rhs.indexRegion_;
+    numberSolutions_ = rhs.numberSolutions_;
+    numberBranchingSolutions_ = rhs.numberBranchingSolutions_;
+    depth_ = rhs.depth_;
+  }
+  return *this;
+}
+
+// Destructor 
+OsiBranchingInformation::~OsiBranchingInformation ()
+{
+  if (owningSolution_) 
+    delete[] solution_;
+}
+// Default Constructor 
+OsiTwoWayBranchingObject::OsiTwoWayBranchingObject()
+  :OsiBranchingObject()
+{
+  firstBranch_=0;
+}
+
+// Useful constructor
+OsiTwoWayBranchingObject::OsiTwoWayBranchingObject (OsiSolverInterface * solver, 
+						      const OsiObject * object,
+						      int way , double value)
+  :OsiBranchingObject(solver,value)
+{
+  originalObject_ = object;
+  firstBranch_=way;
+}
+  
+
+// Copy constructor 
+OsiTwoWayBranchingObject::OsiTwoWayBranchingObject ( const OsiTwoWayBranchingObject & rhs) :OsiBranchingObject(rhs)
+{
+  firstBranch_=rhs.firstBranch_;
+}
+
+// Assignment operator 
+OsiTwoWayBranchingObject & 
+OsiTwoWayBranchingObject::operator=( const OsiTwoWayBranchingObject& rhs)
+{
+  if (this != &rhs) {
+    OsiBranchingObject::operator=(rhs);
+    firstBranch_=rhs.firstBranch_;
+  }
+  return *this;
+}
+
+// Destructor 
+OsiTwoWayBranchingObject::~OsiTwoWayBranchingObject ()
+{
+}
+
+/********* Simple Integers *******************************/
+/** Default Constructor
+
+  Equivalent to an unspecified binary variable.
+*/
+OsiSimpleInteger::OsiSimpleInteger ()
+  : OsiObject2(),
+    originalLower_(0.0),
+    originalUpper_(1.0),
+    columnNumber_(-1)
+{
+}
+
+/** Useful constructor
+
+  Loads actual upper & lower bounds for the specified variable.
+*/
+OsiSimpleInteger::OsiSimpleInteger (const OsiSolverInterface * solver, int iColumn)
+  : OsiObject2()
+{
+  columnNumber_ = iColumn ;
+  originalLower_ = solver->getColLower()[columnNumber_] ;
+  originalUpper_ = solver->getColUpper()[columnNumber_] ;
+}
+
+  
+// Useful constructor - passed solver index and original bounds
+OsiSimpleInteger::OsiSimpleInteger ( int iColumn, double lower, double upper)
+  : OsiObject2()
+{
+  columnNumber_ = iColumn ;
+  originalLower_ = lower;
+  originalUpper_ = upper;
+}
+
+// Copy constructor 
+OsiSimpleInteger::OsiSimpleInteger ( const OsiSimpleInteger & rhs)
+  :OsiObject2(rhs)
+
+{
+  columnNumber_ = rhs.columnNumber_;
+  originalLower_ = rhs.originalLower_;
+  originalUpper_ = rhs.originalUpper_;
+}
+
+// Clone
+OsiObject *
+OsiSimpleInteger::clone() const
+{
+  return new OsiSimpleInteger(*this);
+}
+
+// Assignment operator 
+OsiSimpleInteger & 
+OsiSimpleInteger::operator=( const OsiSimpleInteger& rhs)
+{
+  if (this!=&rhs) {
+    OsiObject2::operator=(rhs);
+    columnNumber_ = rhs.columnNumber_;
+    originalLower_ = rhs.originalLower_;
+    originalUpper_ = rhs.originalUpper_;
+  }
+  return *this;
+}
+
+// Destructor 
+OsiSimpleInteger::~OsiSimpleInteger ()
+{
+}
+/* Reset variable bounds to their original values.
+   
+Bounds may be tightened, so it may be good to be able to reset them to
+their original values.
+*/
+void 
+OsiSimpleInteger::resetBounds(const OsiSolverInterface * solver) 
+{
+  originalLower_ = solver->getColLower()[columnNumber_] ;
+  originalUpper_ = solver->getColUpper()[columnNumber_] ;
+}
+// Redoes data when sequence numbers change
+void 
+OsiSimpleInteger::resetSequenceEtc(int numberColumns, const int * originalColumns)
+{
+  int i;
+  for (i=0;i<numberColumns;i++) {
+    if (originalColumns[i]==columnNumber_)
+      break;
+  }
+  if (i<numberColumns)
+    columnNumber_=i;
+  else
+    abort(); // should never happen
+}
+
+// Infeasibility - large is 0.5
+double 
+OsiSimpleInteger::infeasibility(const OsiBranchingInformation * info, int & whichWay) const
+{
+  double value = info->solution_[columnNumber_];
+  value = CoinMax(value, info->lower_[columnNumber_]);
+  value = CoinMin(value, info->upper_[columnNumber_]);
+  double nearest = floor(value+(1.0-0.5));
+  if (nearest>value) { 
+    whichWay=1;
+  } else {
+    whichWay=0;
+  }
+  infeasibility_ = fabs(value-nearest);
+  double returnValue = infeasibility_;
+  if (infeasibility_<=info->integerTolerance_) {
+    otherInfeasibility_ = 1.0;
+    returnValue = 0.0;
+  } else if (info->defaultDual_<0.0) {
+    otherInfeasibility_ = 1.0-infeasibility_;
+  } else {
+    const double * pi = info->pi_;
+    const double * activity = info->rowActivity_;
+    const double * lower = info->rowLower_;
+    const double * upper = info->rowUpper_;
+    const double * element = info->elementByColumn_;
+    const int * row = info->row_;
+    const CoinBigIndex * columnStart = info->columnStart_;
+    const int * columnLength = info->columnLength_;
+    double direction = info->direction_;
+    double downMovement = value - floor(value);
+    double upMovement = 1.0-downMovement;
+    double valueP = info->objective_[columnNumber_]*direction;
+    CoinBigIndex start = columnStart[columnNumber_];
+    CoinBigIndex end = start + columnLength[columnNumber_];
+    double upEstimate = 0.0;
+    double downEstimate = 0.0;
+    if (valueP>0.0)
+      upEstimate = valueP*upMovement;
+    else
+      downEstimate -= valueP*downMovement;
+    double tolerance = info->primalTolerance_;
+    for (CoinBigIndex j=start;j<end;j++) {
+      int iRow = row[j];
+      if (lower[iRow]<-1.0e20) 
+	assert (pi[iRow]<=1.0e-4);
+      if (upper[iRow]>1.0e20) 
+	assert (pi[iRow]>=-1.0e-4);
+      valueP = pi[iRow]*direction;
+      double el2 = element[j];
+      double value2 = valueP*el2;
+      double u=0.0;
+      double d=0.0;
+      if (value2>0.0)
+	u = value2;
+      else
+	d = -value2;
+      // if up makes infeasible then make at least default
+      double newUp = activity[iRow] + upMovement*el2;
+      if (newUp>upper[iRow]+tolerance||newUp<lower[iRow]-tolerance)
+	u = CoinMax(u,info->defaultDual_);
+      upEstimate += u*upMovement;
+      // if down makes infeasible then make at least default
+      double newDown = activity[iRow] - downMovement*el2;
+      if (newDown>upper[iRow]+tolerance||newDown<lower[iRow]-tolerance)
+	d = CoinMax(d,info->defaultDual_);
+      downEstimate += d*downMovement;
+    }
+    if (downEstimate>=upEstimate) {
+      infeasibility_ = CoinMax(1.0e-12,upEstimate);
+      otherInfeasibility_ = CoinMax(1.0e-12,downEstimate);
+      whichWay = 1;
+    } else {
+      infeasibility_ = CoinMax(1.0e-12,downEstimate);
+      otherInfeasibility_ = CoinMax(1.0e-12,upEstimate);
+      whichWay = 0;
+    }
+    returnValue = infeasibility_;
+  }
+  if (preferredWay_>=0&&returnValue)
+    whichWay = preferredWay_;
+  whichWay_ = static_cast<short int>(whichWay) ;
+  return returnValue;
+}
+
+// This looks at solution and sets bounds to contain solution
+/** More precisely: it first forces the variable within the existing
+    bounds, and then tightens the bounds to fix the variable at the
+    nearest integer value.
+*/
+double
+OsiSimpleInteger::feasibleRegion(OsiSolverInterface * solver,
+				 const OsiBranchingInformation * info) const
+{
+  double value = info->solution_[columnNumber_];
+  double newValue = CoinMax(value, info->lower_[columnNumber_]);
+  newValue = CoinMin(newValue, info->upper_[columnNumber_]);
+  newValue = floor(newValue+0.5);
+  solver->setColLower(columnNumber_,newValue);
+  solver->setColUpper(columnNumber_,newValue);
+  return fabs(value-newValue);
+}
+/* Column number if single column object -1 otherwise,
+   so returns >= 0
+   Used by heuristics
+*/
+int 
+OsiSimpleInteger::columnNumber() const
+{
+  return columnNumber_;
+}
+// Creates a branching object
+OsiBranchingObject * 
+OsiSimpleInteger::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const 
+{
+  double value = info->solution_[columnNumber_];
+  value = CoinMax(value, info->lower_[columnNumber_]);
+  value = CoinMin(value, info->upper_[columnNumber_]);
+  assert (info->upper_[columnNumber_]>info->lower_[columnNumber_]);
+#ifndef NDEBUG
+  double nearest = floor(value+0.5);
+  assert (fabs(value-nearest)>info->integerTolerance_);
+#endif
+  OsiBranchingObject * branch = new OsiIntegerBranchingObject(solver,this,way,
+					     value);
+  return branch;
+}
+// Return "down" estimate
+double 
+OsiSimpleInteger::downEstimate() const
+{
+  if (whichWay_)
+    return 1.0-infeasibility_;
+  else
+    return infeasibility_;
+}
+// Return "up" estimate
+double 
+OsiSimpleInteger::upEstimate() const
+{
+  if (!whichWay_)
+    return 1.0-infeasibility_;
+  else
+    return infeasibility_;
+}
+
+// Default Constructor 
+OsiIntegerBranchingObject::OsiIntegerBranchingObject()
+  :OsiTwoWayBranchingObject()
+{
+  down_[0] = 0.0;
+  down_[1] = 0.0;
+  up_[0] = 0.0;
+  up_[1] = 0.0;
+}
+
+// Useful constructor
+OsiIntegerBranchingObject::OsiIntegerBranchingObject (OsiSolverInterface * solver, 
+						      const OsiSimpleInteger * object,
+						      int way , double value)
+  :OsiTwoWayBranchingObject(solver,object, way, value)
+{
+  int iColumn = object->columnNumber();
+  down_[0] = solver->getColLower()[iColumn];
+  down_[1] = floor(value_);
+  up_[0] = ceil(value_);
+  up_[1] = solver->getColUpper()[iColumn];
+}
+/* Create a standard floor/ceiling branch object
+   Specifies a simple two-way branch in a more flexible way. One arm of the
+   branch will be lb <= x <= downUpperBound, the other upLowerBound <= x <= ub.
+   Specify way = -1 to set the object state to perform the down arm first,
+   way = 1 for the up arm.
+*/
+OsiIntegerBranchingObject::OsiIntegerBranchingObject (OsiSolverInterface * solver, 
+						      const OsiSimpleInteger * object,
+						      int way , double value, double downUpperBound, 
+						      double upLowerBound) 
+  :OsiTwoWayBranchingObject(solver,object, way, value)
+{
+  int iColumn = object->columnNumber();
+  down_[0] = solver->getColLower()[iColumn];
+  down_[1] = downUpperBound;
+  up_[0] = upLowerBound;
+  up_[1] = solver->getColUpper()[iColumn];
+}
+  
+
+// Copy constructor 
+OsiIntegerBranchingObject::OsiIntegerBranchingObject ( const OsiIntegerBranchingObject & rhs) :OsiTwoWayBranchingObject(rhs)
+{
+  down_[0] = rhs.down_[0];
+  down_[1] = rhs.down_[1];
+  up_[0] = rhs.up_[0];
+  up_[1] = rhs.up_[1];
+}
+
+// Assignment operator 
+OsiIntegerBranchingObject & 
+OsiIntegerBranchingObject::operator=( const OsiIntegerBranchingObject& rhs)
+{
+  if (this != &rhs) {
+    OsiTwoWayBranchingObject::operator=(rhs);
+    down_[0] = rhs.down_[0];
+    down_[1] = rhs.down_[1];
+    up_[0] = rhs.up_[0];
+    up_[1] = rhs.up_[1];
+  }
+  return *this;
+}
+OsiBranchingObject * 
+OsiIntegerBranchingObject::clone() const
+{ 
+  return (new OsiIntegerBranchingObject(*this));
+}
+
+
+// Destructor 
+OsiIntegerBranchingObject::~OsiIntegerBranchingObject ()
+{
+}
+
+/*
+  Perform a branch by adjusting the bounds of the specified variable. Note
+  that each arm of the branch advances the object to the next arm by
+  advancing the value of branchIndex_.
+
+  Providing new values for the variable's lower and upper bounds for each
+  branching direction gives a little bit of additional flexibility and will
+  be easily extensible to multi-way branching.
+  Returns change in guessed objective on next branch
+*/
+double
+OsiIntegerBranchingObject::branch(OsiSolverInterface * solver)
+{
+  const OsiSimpleInteger * obj =
+    dynamic_cast <const OsiSimpleInteger *>(originalObject_) ;
+  assert (obj);
+  int iColumn = obj->columnNumber();
+  double olb,oub ;
+  olb = solver->getColLower()[iColumn] ;
+  oub = solver->getColUpper()[iColumn] ;
+  int way = (!branchIndex_) ? (2*firstBranch_-1) : -(2*firstBranch_-1);
+  if (0) {
+    printf("branching %s on %d bounds %g %g / %g %g\n",
+	   (way==-1) ? "down" :"up",iColumn,
+	   down_[0],down_[1],up_[0],up_[1]);
+    const double * lower = solver->getColLower();
+    const double * upper = solver->getColUpper();
+    for (int i=0;i<8;i++) 
+      printf(" [%d (%g,%g)]",i,lower[i],upper[i]);
+    printf("\n");
+  }
+  if (way<0) {
+#ifdef OSI_DEBUG
+  { double olb,oub ;
+    olb = solver->getColLower()[iColumn] ;
+    oub = solver->getColUpper()[iColumn] ;
+    printf("branching down on var %d: [%g,%g] => [%g,%g]\n",
+	   iColumn,olb,oub,down_[0],down_[1]) ; }
+#endif
+    solver->setColLower(iColumn,down_[0]);
+    solver->setColUpper(iColumn,down_[1]);
+  } else {
+#ifdef OSI_DEBUG
+  { double olb,oub ;
+    olb = solver->getColLower()[iColumn] ;
+    oub = solver->getColUpper()[iColumn] ;
+    printf("branching up on var %d: [%g,%g] => [%g,%g]\n",
+	   iColumn,olb,oub,up_[0],up_[1]) ; }
+#endif
+    solver->setColLower(iColumn,up_[0]);
+    solver->setColUpper(iColumn,up_[1]);
+  }
+  double nlb = solver->getColLower()[iColumn];
+  if (nlb<olb) {
+#ifndef NDEBUG
+    printf("bad lb change for column %d from %g to %g\n",iColumn,olb,nlb);
+#endif
+    solver->setColLower(iColumn,olb);
+  }
+  double nub = solver->getColUpper()[iColumn];
+  if (nub>oub) {
+#ifndef NDEBUG
+    printf("bad ub change for column %d from %g to %g\n",iColumn,oub,nub);
+#endif
+    solver->setColUpper(iColumn,oub);
+  }
+#ifndef NDEBUG
+  if (nlb<olb+1.0e-8&&nub>oub-1.0e-8)
+    printf("bad null change for column %d - bounds %g,%g\n",iColumn,olb,oub);
+#endif
+  branchIndex_++;
+  return 0.0;
+}
+// Print what would happen  
+void
+OsiIntegerBranchingObject::print(const OsiSolverInterface * solver)
+{
+  const OsiSimpleInteger * obj =
+    dynamic_cast <const OsiSimpleInteger *>(originalObject_) ;
+  assert (obj);
+  int iColumn = obj->columnNumber();
+  int way = (!branchIndex_) ? (2*firstBranch_-1) : -(2*firstBranch_-1);
+  if (way<0) {
+  { double olb,oub ;
+    olb = solver->getColLower()[iColumn] ;
+    oub = solver->getColUpper()[iColumn] ;
+    printf("OsiInteger would branch down on var %d : [%g,%g] => [%g,%g]\n",
+	   iColumn,olb,oub,down_[0],down_[1]) ; }
+  } else {
+  { double olb,oub ;
+    olb = solver->getColLower()[iColumn] ;
+    oub = solver->getColUpper()[iColumn] ;
+    printf("OsiInteger would branch up on var %d : [%g,%g] => [%g,%g]\n",
+	   iColumn,olb,oub,up_[0],up_[1]) ; }
+  }
+}
+// Default Constructor 
+OsiSOS::OsiSOS ()
+  : OsiObject2(),
+    members_(NULL),
+    weights_(NULL),
+    numberMembers_(0),
+    sosType_(-1),
+    integerValued_(false)
+{
+}
+
+// Useful constructor (which are indices)
+OsiSOS::OsiSOS (const OsiSolverInterface * ,  int numberMembers,
+	   const int * which, const double * weights, int type)
+  : OsiObject2(),
+    numberMembers_(numberMembers),
+    sosType_(type)
+{
+  integerValued_ = type==1; // not strictly true - should check problem
+  if (numberMembers_) {
+    members_ = new int[numberMembers_];
+    weights_ = new double[numberMembers_];
+    memcpy(members_,which,numberMembers_*sizeof(int));
+    if (weights) {
+      memcpy(weights_,weights,numberMembers_*sizeof(double));
+    } else {
+      for (int i=0;i<numberMembers_;i++)
+        weights_[i]=i;
+    }
+    // sort so weights increasing
+    CoinSort_2(weights_,weights_+numberMembers_,members_);
+    double last = -COIN_DBL_MAX;
+    int i;
+    for (i=0;i<numberMembers_;i++) {
+      double possible = CoinMax(last+1.0e-10,weights_[i]);
+      weights_[i] = possible;
+      last=possible;
+    }
+  } else {
+    members_ = NULL;
+    weights_ = NULL;
+  }
+  assert (sosType_>0&&sosType_<3);
+}
+
+// Copy constructor 
+OsiSOS::OsiSOS ( const OsiSOS & rhs)
+  :OsiObject2(rhs)
+{
+  numberMembers_ = rhs.numberMembers_;
+  sosType_ = rhs.sosType_;
+  integerValued_ = rhs.integerValued_;
+  if (numberMembers_) {
+    members_ = new int[numberMembers_];
+    weights_ = new double[numberMembers_];
+    memcpy(members_,rhs.members_,numberMembers_*sizeof(int));
+    memcpy(weights_,rhs.weights_,numberMembers_*sizeof(double));
+  } else {
+    members_ = NULL;
+    weights_ = NULL;
+  }
+}
+
+// Clone
+OsiObject *
+OsiSOS::clone() const
+{
+  return new OsiSOS(*this);
+}
+
+// Assignment operator 
+OsiSOS & 
+OsiSOS::operator=( const OsiSOS& rhs)
+{
+  if (this!=&rhs) {
+    OsiObject2::operator=(rhs);
+    delete [] members_;
+    delete [] weights_;
+    numberMembers_ = rhs.numberMembers_;
+    sosType_ = rhs.sosType_;
+    integerValued_ = rhs.integerValued_;
+    if (numberMembers_) {
+      members_ = new int[numberMembers_];
+      weights_ = new double[numberMembers_];
+      memcpy(members_,rhs.members_,numberMembers_*sizeof(int));
+      memcpy(weights_,rhs.weights_,numberMembers_*sizeof(double));
+    } else {
+      members_ = NULL;
+      weights_ = NULL;
+    }
+  }
+  return *this;
+}
+
+// Destructor 
+OsiSOS::~OsiSOS ()
+{
+  delete [] members_;
+  delete [] weights_;
+}
+
+// Infeasibility - large is 0.5
+double 
+OsiSOS::infeasibility(const OsiBranchingInformation * info,int & whichWay) const
+{
+  int j;
+  int firstNonZero=-1;
+  int lastNonZero = -1;
+  int firstNonFixed=-1;
+  int lastNonFixed = -1;
+  const double * solution = info->solution_;
+  //const double * lower = info->lower_;
+  const double * upper = info->upper_;
+  //double largestValue=0.0;
+  double integerTolerance = info->integerTolerance_;
+  double primalTolerance = info->primalTolerance_;
+  double weight = 0.0;
+  double sum =0.0;
+
+  // check bounds etc
+  double lastWeight=-1.0e100;
+  for (j=0;j<numberMembers_;j++) {
+    int iColumn = members_[j];
+    if (lastWeight>=weights_[j]-1.0e-12)
+      throw CoinError("Weights too close together in SOS","infeasibility","OsiSOS");
+    lastWeight = weights_[j];
+    if (upper[iColumn]) {
+      double value = CoinMax(0.0,solution[iColumn]);
+      if (value>integerTolerance) {
+	// Possibly due to scaling a fixed variable might slip through
+#ifdef COIN_DEVELOP
+	if (value>upper[iColumn]+10.0*primalTolerance)
+	  printf("** Variable %d (%d) has value %g and upper bound of %g\n",
+		 iColumn,j,value,upper[iColumn]);
+#endif
+	if (value>upper[iColumn]) {
+	  value=upper[iColumn];
+	} 
+	sum += value;
+	weight += weights_[j]*value;
+	if (firstNonZero<0)
+	  firstNonZero=j;
+	lastNonZero=j;
+      }
+      if (firstNonFixed<0)
+	firstNonFixed=j;
+      lastNonFixed=j;
+    }
+  }
+  whichWay=1;
+  whichWay_=1;
+  if (lastNonZero-firstNonZero>=sosType_) {
+    // find where to branch
+    assert (sum>0.0);
+    // probably best to use pseudo duals
+    double value = lastNonZero-firstNonZero+1;
+    value *= 0.5/static_cast<double> (numberMembers_);
+    infeasibility_=value;
+    otherInfeasibility_=1.0-value;
+    if (info->defaultDual_>=0.0) {
+      // Using pseudo shadow prices
+      weight /= sum;
+      int iWhere;
+      for (iWhere=firstNonZero;iWhere<lastNonZero;iWhere++) 
+	if (weight<weights_[iWhere+1])
+	  break;
+      assert (iWhere!=lastNonZero);
+      /* Complicated - infeasibility is being used for branching so we
+	 don't want estimate of satisfying set but of each way on branch.
+	 So let us suppose that all on side being fixed to 0 goes to closest
+      */
+      int lastDown=iWhere;
+      int firstUp=iWhere+1;
+      if (sosType_==2) {
+	// SOS 2 - choose nearest
+	if (weight-weights_[iWhere]>=weights_[iWhere+1]-weight)
+	  lastDown++;
+	// But make sure OK
+	if (lastDown==firstNonFixed) {
+	  lastDown ++;
+	} else if (lastDown==lastNonFixed) {
+	  lastDown --;
+	} 
+	firstUp=lastDown;
+      }
+      // Now get current contribution and compute weight for end points
+      double weightDown = 0.0;
+      double weightUp = 0.0;
+      const double * element = info->elementByColumn_;
+      const int * row = info->row_;
+      const CoinBigIndex * columnStart = info->columnStart_;
+      const int * columnLength = info->columnLength_;
+      double direction = info->direction_;
+      const double * objective = info->objective_;
+      // Compute where we would move to
+      double objValue=0.0;
+      double * useful = info->usefulRegion_;
+      int * index = info->indexRegion_;
+      int n=0;
+      for (j=firstNonZero;j<=lastNonZero;j++) {
+	int iColumn = members_[j];
+	double multiplier = solution[iColumn];
+	if (j>=lastDown)
+	  weightDown += multiplier;
+	if (j<=firstUp)
+	  weightUp += multiplier;
+	if (multiplier>0.0) {
+	  objValue += objective[iColumn]*multiplier;
+	  CoinBigIndex start = columnStart[iColumn];
+	  CoinBigIndex end = start + columnLength[iColumn];
+	  for (CoinBigIndex j=start;j<end;j++) {
+	    int iRow = row[j];
+	    double value = element[j]*multiplier;
+	    if (useful[iRow]) {
+	      value += useful[iRow];
+	      if (!value)
+		value = 1.0e-100;
+	    } else {
+	      assert (value);
+	      index[n++]=iRow;
+	    }
+	    useful[iRow] = value;
+	  }
+	}
+      }
+      if (sosType_==2) 
+	assert (fabs(weightUp+weightDown-sum-solution[members_[lastDown]])<1.0e-4);
+      int startX[2];
+      int endX[2];
+      startX[0]=firstNonZero;
+      startX[1]=firstUp;
+      endX[0]=lastDown;
+      endX[1]=lastNonZero;
+      double fakeSolution[2];
+      int check[2];
+      fakeSolution[0]=weightDown;
+      check[0]=members_[lastDown];
+      fakeSolution[1]=weightUp;
+      check[1]=members_[firstUp];
+      const double * pi = info->pi_;
+      const double * activity = info->rowActivity_;
+      const double * lower = info->rowLower_;
+      const double * upper = info->rowUpper_;
+      int numberRows = info->solver_->getNumRows();
+      double * useful2 = useful+numberRows;
+      int * index2 = index+numberRows;
+      for (int i=0;i<2;i++) {
+	double obj=0.0;
+	int n2=0;
+	for (j=startX[i];j<=endX[i];j++) {
+	  int iColumn = members_[j];
+	  double multiplier = solution[iColumn];
+	  if (iColumn==check[i])
+	    multiplier=fakeSolution[i];
+	  if (multiplier>0.0) {
+	    obj += objective[iColumn]*multiplier;
+	    CoinBigIndex start = columnStart[iColumn];
+	    CoinBigIndex end = start + columnLength[iColumn];
+	    for (CoinBigIndex j=start;j<end;j++) {
+	      int iRow = row[j];
+	      double value = element[j]*multiplier;
+	      if (useful2[iRow]) {
+		value += useful2[iRow];
+		if (!value)
+		  value = 1.0e-100;
+	      } else {
+		assert (value);
+		index2[n2++]=iRow;
+	      }
+	      useful2[iRow] = value;
+	    }
+	  }
+	}
+	// movement in objective
+	obj = (obj-objValue) * direction;
+	double estimate = (obj>0.0) ? obj : 0.0;
+	for (j=0;j<n;j++) {
+	  int iRow = index[j];
+	  // movement
+	  double movement = useful2[iRow]-useful[iRow];
+	  useful[iRow]=0.0;
+	  useful2[iRow]=0.0;
+	  double valueP = pi[iRow]*direction;
+	  if (lower[iRow]<-1.0e20) 
+	    assert (valueP<=1.0e-4);
+	  if (upper[iRow]>1.0e20) 
+	    assert (valueP>=-1.0e-4);
+	  double value2 = valueP*movement;
+	  double thisEstimate = (value2>0.0) ? value2 : 0;
+	  // if makes infeasible then make at least default
+	  double newValue = activity[iRow] + movement;
+	  if (newValue>upper[iRow]+primalTolerance||newValue<lower[iRow]-primalTolerance)
+	    thisEstimate = CoinMax(thisEstimate,info->defaultDual_);
+	  estimate += thisEstimate;
+	}
+	for (j=0;j<n2;j++) {
+	  int iRow = index2[j];
+	  // movement
+	  double movement = useful2[iRow]-useful[iRow];
+	  useful[iRow]=0.0;
+	  useful2[iRow]=0.0;
+	  if (movement) {
+	    double valueP = pi[iRow]*direction;
+	    if (lower[iRow]<-1.0e20) 
+	      assert (valueP<=1.0e-4);
+	    if (upper[iRow]>1.0e20) 
+	      assert (valueP>=-1.0e-4);
+	    double value2 = valueP*movement;
+	    double thisEstimate = (value2>0.0) ? value2 : 0;
+	    // if makes infeasible then make at least default
+	    double newValue = activity[iRow] + movement;
+	    if (newValue>upper[iRow]+primalTolerance||newValue<lower[iRow]-primalTolerance)
+	      thisEstimate = CoinMax(thisEstimate,info->defaultDual_);
+	    estimate += thisEstimate;
+	  }
+	}
+	// store in fakeSolution
+	fakeSolution[i]=estimate;
+      }
+      double downEstimate = fakeSolution[0];
+      double upEstimate = fakeSolution[1];
+      if (downEstimate>=upEstimate) {
+	infeasibility_ = CoinMax(1.0e-12,upEstimate);
+	otherInfeasibility_ = CoinMax(1.0e-12,downEstimate);
+	whichWay = 1;
+      } else {
+	infeasibility_ = CoinMax(1.0e-12,downEstimate);
+	otherInfeasibility_ = CoinMax(1.0e-12,upEstimate);
+	whichWay = 0;
+      }
+      whichWay_=static_cast<short>(whichWay);
+      value=infeasibility_;
+    }
+    return value;
+  } else {
+    infeasibility_=0.0;
+    otherInfeasibility_=1.0;
+    return 0.0; // satisfied
+  }
+}
+
+// This looks at solution and sets bounds to contain solution
+double
+OsiSOS::feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const
+{
+  int j;
+  int firstNonZero=-1;
+  int lastNonZero = -1;
+  const double * solution = info->solution_;
+  //const double * lower = info->lower_;
+  const double * upper = info->upper_;
+  double sum =0.0;
+  // Find largest one or pair
+  double movement=0.0;
+  if (sosType_==1) {
+    for (j=0;j<numberMembers_;j++) {
+      int iColumn = members_[j];
+      double value = CoinMax(0.0,solution[iColumn]);
+      if (value>sum&&upper[iColumn]) {
+	firstNonZero=j;
+	sum=value;
+      }
+    }
+    lastNonZero=firstNonZero;
+  } else {
+    // type 2
+    for (j=1;j<numberMembers_;j++) {
+      int iColumn = members_[j];
+      int jColumn = members_[j-1];
+      double value1 = CoinMax(0.0,solution[iColumn]);
+      double value0 = CoinMax(0.0,solution[jColumn]);
+      double value = value0+value1;
+      if (value>sum) {
+	if (upper[iColumn]||upper[jColumn]) {
+	  firstNonZero=upper[jColumn] ? j-1 : j;
+	  lastNonZero=upper[iColumn] ? j : j-1;
+	  sum=value;
+	}
+      }
+    }
+  }
+  for (j=0;j<numberMembers_;j++) {
+    if (j<firstNonZero||j>lastNonZero) {
+      int iColumn = members_[j];
+      double value = CoinMax(0.0,solution[iColumn]);
+      movement += value;
+      solver->setColUpper(iColumn,0.0);
+    }
+  }
+  return movement;
+}
+// Redoes data when sequence numbers change
+void 
+OsiSOS::resetSequenceEtc(int numberColumns, const int * originalColumns)
+{
+  int n2=0;
+  for (int j=0;j<numberMembers_;j++) {
+    int iColumn = members_[j];
+    int i;
+    for (i=0;i<numberColumns;i++) {
+      if (originalColumns[i]==iColumn)
+        break;
+    }
+    if (i<numberColumns) {
+      members_[n2]=i;
+      weights_[n2++]=weights_[j];
+    }
+  }
+  if (n2<numberMembers_) {
+    printf("** SOS number of members reduced from %d to %d!\n",numberMembers_,n2);
+    numberMembers_=n2;
+  }
+}
+// Return "down" estimate
+double 
+OsiSOS::downEstimate() const
+{
+  if (whichWay_)
+    return otherInfeasibility_;
+  else
+    return infeasibility_;
+}
+// Return "up" estimate
+double 
+OsiSOS::upEstimate() const
+{
+  if (!whichWay_)
+    return otherInfeasibility_;
+  else
+    return infeasibility_;
+}
+
+// Creates a branching object
+OsiBranchingObject * 
+OsiSOS::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const
+{
+  int j;
+  const double * solution = info->solution_;
+  double tolerance = info->primalTolerance_;
+  const double * upper = info->upper_;
+  int firstNonFixed=-1;
+  int lastNonFixed=-1;
+  int firstNonZero=-1;
+  int lastNonZero = -1;
+  double weight = 0.0;
+  double sum =0.0;
+  for (j=0;j<numberMembers_;j++) {
+    int iColumn = members_[j];
+    if (upper[iColumn]) {
+      double value = CoinMax(0.0,solution[iColumn]);
+      sum += value;
+      if (firstNonFixed<0)
+	firstNonFixed=j;
+      lastNonFixed=j;
+      if (value>tolerance) {
+	weight += weights_[j]*value;
+	if (firstNonZero<0)
+	  firstNonZero=j;
+	lastNonZero=j;
+      }
+    }
+  }
+  assert (lastNonZero-firstNonZero>=sosType_) ;
+  // find where to branch
+  assert (sum>0.0);
+  weight /= sum;
+  int iWhere;
+  double separator=0.0;
+  for (iWhere=firstNonZero;iWhere<lastNonZero;iWhere++) 
+    if (weight<weights_[iWhere+1])
+      break;
+  if (sosType_==1) {
+    // SOS 1
+    separator = 0.5 *(weights_[iWhere]+weights_[iWhere+1]);
+  } else {
+    // SOS 2
+    if (iWhere==lastNonFixed-1)
+      iWhere = lastNonFixed-2;
+    separator = weights_[iWhere+1];
+  }
+  // create object
+  OsiBranchingObject * branch;
+  branch = new OsiSOSBranchingObject(solver,this,way,separator);
+  return branch;
+}
+// Default Constructor 
+OsiSOSBranchingObject::OsiSOSBranchingObject()
+  :OsiTwoWayBranchingObject()
+{
+}
+
+// Useful constructor
+OsiSOSBranchingObject::OsiSOSBranchingObject (OsiSolverInterface * solver,
+					      const OsiSOS * set,
+					      int way ,
+					      double separator)
+  :OsiTwoWayBranchingObject(solver, set,way,separator)
+{
+}
+
+// Copy constructor 
+OsiSOSBranchingObject::OsiSOSBranchingObject ( const OsiSOSBranchingObject & rhs) :OsiTwoWayBranchingObject(rhs)
+{
+}
+
+// Assignment operator 
+OsiSOSBranchingObject & 
+OsiSOSBranchingObject::operator=( const OsiSOSBranchingObject& rhs)
+{
+  if (this != &rhs) {
+    OsiTwoWayBranchingObject::operator=(rhs);
+  }
+  return *this;
+}
+OsiBranchingObject * 
+OsiSOSBranchingObject::clone() const
+{ 
+  return (new OsiSOSBranchingObject(*this));
+}
+
+
+// Destructor 
+OsiSOSBranchingObject::~OsiSOSBranchingObject ()
+{
+}
+double
+OsiSOSBranchingObject::branch(OsiSolverInterface * solver)
+{
+  const OsiSOS * set =
+    dynamic_cast <const OsiSOS *>(originalObject_) ;
+  assert (set);
+  int way = (!branchIndex_) ? (2*firstBranch_-1) : -(2*firstBranch_-1);
+  branchIndex_++;
+  int numberMembers = set->numberMembers();
+  const int * which = set->members();
+  const double * weights = set->weights();
+  //const double * lower = solver->getColLower();
+  //const double * upper = solver->getColUpper();
+  // *** for way - up means fix all those in down section
+  if (way<0) {
+    int i;
+    for ( i=0;i<numberMembers;i++) {
+      if (weights[i] > value_)
+	break;
+    }
+    assert (i<numberMembers);
+    for (;i<numberMembers;i++) 
+      solver->setColUpper(which[i],0.0);
+  } else {
+    int i;
+    for ( i=0;i<numberMembers;i++) {
+      if (weights[i] >= value_)
+	break;
+      else
+	solver->setColUpper(which[i],0.0);
+    }
+    assert (i<numberMembers);
+  }
+  return 0.0;
+}
+// Print what would happen  
+void
+OsiSOSBranchingObject::print(const OsiSolverInterface * solver)
+{
+  const OsiSOS * set =
+    dynamic_cast <const OsiSOS *>(originalObject_) ;
+  assert (set);
+  int way = (!branchIndex_) ? (2*firstBranch_-1) : -(2*firstBranch_-1);
+  int numberMembers = set->numberMembers();
+  const int * which = set->members();
+  const double * weights = set->weights();
+  //const double * lower = solver->getColLower();
+  const double * upper = solver->getColUpper();
+  int first=numberMembers;
+  int last=-1;
+  int numberFixed=0;
+  int numberOther=0;
+  int i;
+  for ( i=0;i<numberMembers;i++) {
+    double bound = upper[which[i]];
+    if (bound) {
+      first = CoinMin(first,i);
+      last = CoinMax(last,i);
+    }
+  }
+  // *** for way - up means fix all those in down section
+  if (way<0) {
+    printf("SOS Down");
+    for ( i=0;i<numberMembers;i++) {
+      double bound = upper[which[i]];
+      if (weights[i] > value_)
+	break;
+      else if (bound)
+	numberOther++;
+    }
+    assert (i<numberMembers);
+    for (;i<numberMembers;i++) {
+      double bound = upper[which[i]];
+      if (bound)
+	numberFixed++;
+    }
+  } else {
+    printf("SOS Up");
+    for ( i=0;i<numberMembers;i++) {
+      double bound = upper[which[i]];
+      if (weights[i] >= value_)
+	break;
+      else if (bound)
+	numberFixed++;
+    }
+    assert (i<numberMembers);
+    for (;i<numberMembers;i++) {
+      double bound = upper[which[i]];
+      if (bound)
+	numberOther++;
+    }
+  }
+  printf(" - at %g, free range %d (%g) => %d (%g), %d would be fixed, %d other way\n",
+	 value_,which[first],weights[first],which[last],weights[last],numberFixed,numberOther);
+}
+/** Default Constructor
+
+*/
+OsiLotsize::OsiLotsize ()
+  : OsiObject2(),
+    columnNumber_(-1),
+    rangeType_(0),
+    numberRanges_(0),
+    largestGap_(0),
+    bound_(NULL),
+    range_(0)
+{
+}
+
+/** Useful constructor
+
+  Loads actual upper & lower bounds for the specified variable.
+*/
+OsiLotsize::OsiLotsize (const OsiSolverInterface * , 
+				    int iColumn, int numberPoints,
+			const double * points, bool range)
+  : OsiObject2()
+{
+  assert (numberPoints>0);
+  columnNumber_ = iColumn ;
+  // sort ranges
+  int * sort = new int[numberPoints];
+  double * weight = new double [numberPoints];
+  int i;
+  if (range) {
+    rangeType_=2;
+  } else {
+    rangeType_=1;
+  }
+  for (i=0;i<numberPoints;i++) {
+    sort[i]=i;
+    weight[i]=points[i*rangeType_];
+  }
+  CoinSort_2(weight,weight+numberPoints,sort);
+  numberRanges_=1;
+  largestGap_=0;
+  if (rangeType_==1) {
+    bound_ = new double[numberPoints+1];
+    bound_[0]=weight[0];
+    for (i=1;i<numberPoints;i++) {
+      if (weight[i]!=weight[i-1]) 
+	bound_[numberRanges_++]=weight[i];
+    }
+    // and for safety
+    bound_[numberRanges_]=bound_[numberRanges_-1];
+    for (i=1;i<numberRanges_;i++) {
+      largestGap_ = CoinMax(largestGap_,bound_[i]-bound_[i-1]);
+    }
+  } else {
+    bound_ = new double[2*numberPoints+2];
+    bound_[0]=points[sort[0]*2];
+    bound_[1]=points[sort[0]*2+1];
+    double hi=bound_[1];
+    assert (hi>=bound_[0]);
+    for (i=1;i<numberPoints;i++) {
+      double thisLo =points[sort[i]*2];
+      double thisHi =points[sort[i]*2+1];
+      assert (thisHi>=thisLo);
+      if (thisLo>hi) {
+	bound_[2*numberRanges_]=thisLo;
+	bound_[2*numberRanges_+1]=thisHi;
+	numberRanges_++;
+	hi=thisHi;
+      } else {
+	//overlap
+	hi=CoinMax(hi,thisHi);
+	bound_[2*numberRanges_-1]=hi;
+      }
+    }
+    // and for safety
+    bound_[2*numberRanges_]=bound_[2*numberRanges_-2];
+    bound_[2*numberRanges_+1]=bound_[2*numberRanges_-1];
+    for (i=1;i<numberRanges_;i++) {
+      largestGap_ = CoinMax(largestGap_,bound_[2*i]-bound_[2*i-1]);
+    }
+  }
+  delete [] sort;
+  delete [] weight;
+  range_=0;
+}
+
+// Copy constructor 
+OsiLotsize::OsiLotsize ( const OsiLotsize & rhs)
+  :OsiObject2(rhs)
+
+{
+  columnNumber_ = rhs.columnNumber_;
+  rangeType_ = rhs.rangeType_;
+  numberRanges_ = rhs.numberRanges_;
+  range_ = rhs.range_;
+  largestGap_ = rhs.largestGap_;
+  if (numberRanges_) {
+    assert (rangeType_>0&&rangeType_<3);
+    bound_= new double [(numberRanges_+1)*rangeType_];
+    memcpy(bound_,rhs.bound_,(numberRanges_+1)*rangeType_*sizeof(double));
+  } else {
+    bound_=NULL;
+  }
+}
+
+// Clone
+OsiObject *
+OsiLotsize::clone() const
+{
+  return new OsiLotsize(*this);
+}
+
+// Assignment operator 
+OsiLotsize & 
+OsiLotsize::operator=( const OsiLotsize& rhs)
+{
+  if (this!=&rhs) {
+    OsiObject2::operator=(rhs);
+    columnNumber_ = rhs.columnNumber_;
+    rangeType_ = rhs.rangeType_;
+    numberRanges_ = rhs.numberRanges_;
+    largestGap_ = rhs.largestGap_;
+    delete [] bound_;
+    range_ = rhs.range_;
+    if (numberRanges_) {
+      assert (rangeType_>0&&rangeType_<3);
+      bound_= new double [(numberRanges_+1)*rangeType_];
+      memcpy(bound_,rhs.bound_,(numberRanges_+1)*rangeType_*sizeof(double));
+    } else {
+      bound_=NULL;
+    }
+  }
+  return *this;
+}
+
+// Destructor 
+OsiLotsize::~OsiLotsize ()
+{
+  delete [] bound_;
+}
+/* Finds range of interest so value is feasible in range range_ or infeasible 
+   between hi[range_] and lo[range_+1].  Returns true if feasible.
+*/
+bool 
+OsiLotsize::findRange(double value, double integerTolerance) const
+{
+  assert (range_>=0&&range_<numberRanges_+1);
+  int iLo;
+  int iHi;
+  double infeasibility=0.0;
+  if (rangeType_==1) {
+    if (value<bound_[range_]-integerTolerance) {
+      iLo=0;
+      iHi=range_-1;
+    } else if (value<bound_[range_]+integerTolerance) {
+      return true;
+    } else if (value<bound_[range_+1]-integerTolerance) {
+      return false;
+    } else {
+      iLo=range_+1;
+      iHi=numberRanges_-1;
+    }
+    // check lo and hi
+    bool found=false;
+    if (value>bound_[iLo]-integerTolerance&&value<bound_[iLo+1]+integerTolerance) {
+      range_=iLo;
+      found=true;
+    } else if (value>bound_[iHi]-integerTolerance&&value<bound_[iHi+1]+integerTolerance) {
+      range_=iHi;
+      found=true;
+    } else {
+      range_ = (iLo+iHi)>>1;
+    }
+    //points
+    while (!found) {
+      if (value<bound_[range_]) {
+	if (value>=bound_[range_-1]) {
+	  // found
+	  range_--;
+	  break;
+	} else {
+	  iHi = range_;
+	}
+      } else {
+	if (value<bound_[range_+1]) {
+	  // found
+	  break;
+	} else {
+	  iLo = range_;
+	}
+      }
+      range_ = (iLo+iHi)>>1;
+    }
+    if (value-bound_[range_]<=bound_[range_+1]-value) {
+      infeasibility = value-bound_[range_];
+    } else {
+      infeasibility = bound_[range_+1]-value;
+      if (infeasibility<integerTolerance)
+	range_++;
+    }
+    return (infeasibility<integerTolerance);
+  } else {
+    // ranges
+    if (value<bound_[2*range_]-integerTolerance) {
+      iLo=0;
+      iHi=range_-1;
+    } else if (value<bound_[2*range_+1]+integerTolerance) {
+      return true;
+    } else if (value<bound_[2*range_+2]-integerTolerance) {
+      return false;
+    } else {
+      iLo=range_+1;
+      iHi=numberRanges_-1;
+    }
+    // check lo and hi
+    bool found=false;
+    if (value>bound_[2*iLo]-integerTolerance&&value<bound_[2*iLo+2]-integerTolerance) {
+      range_=iLo;
+      found=true;
+    } else if (value>=bound_[2*iHi]-integerTolerance) {
+      range_=iHi;
+      found=true;
+    } else {
+      range_ = (iLo+iHi)>>1;
+    }
+    //points
+    while (!found) {
+      if (value<bound_[2*range_]) {
+	if (value>=bound_[2*range_-2]) {
+	  // found
+	  range_--;
+	  break;
+	} else {
+	  iHi = range_;
+	}
+      } else {
+	if (value<bound_[2*range_+2]) {
+	  // found
+	  break;
+	} else {
+	  iLo = range_;
+	}
+      }
+      range_ = (iLo+iHi)>>1;
+    }
+    if (value>=bound_[2*range_]-integerTolerance&&value<=bound_[2*range_+1]+integerTolerance)
+      infeasibility=0.0;
+    else if (value-bound_[2*range_+1]<bound_[2*range_+2]-value) {
+      infeasibility = value-bound_[2*range_+1];
+    } else {
+      infeasibility = bound_[2*range_+2]-value;
+    }
+    return (infeasibility<integerTolerance);
+  }
+}
+/* Returns floor and ceiling
+ */
+void 
+OsiLotsize::floorCeiling(double & floorLotsize, double & ceilingLotsize, double value,
+			 double tolerance) const
+{
+  bool feasible=findRange(value,tolerance);
+  if (rangeType_==1) {
+    floorLotsize=bound_[range_];
+    ceilingLotsize=bound_[range_+1];
+    // may be able to adjust
+    if (feasible&&fabs(value-floorLotsize)>fabs(value-ceilingLotsize)) {
+      floorLotsize=bound_[range_+1];
+      ceilingLotsize=bound_[range_+2];
+    }
+  } else {
+    // ranges
+    assert (value>=bound_[2*range_+1]);
+    floorLotsize=bound_[2*range_+1];
+    ceilingLotsize=bound_[2*range_+2];
+  }
+}
+
+// Infeasibility - large is 0.5
+double 
+OsiLotsize::infeasibility(const OsiBranchingInformation * info, int & preferredWay) const
+{
+  const double * solution = info->solution_;
+  const double * lower = info->lower_;
+  const double * upper = info->upper_;
+  double value = solution[columnNumber_];
+  value = CoinMax(value, lower[columnNumber_]);
+  value = CoinMin(value, upper[columnNumber_]);
+  double integerTolerance = info->integerTolerance_;
+  /*printf("%d %g %g %g %g\n",columnNumber_,value,lower[columnNumber_],
+    solution[columnNumber_],upper[columnNumber_]);*/
+  assert (value>=bound_[0]-integerTolerance
+          &&value<=bound_[rangeType_*numberRanges_-1]+integerTolerance);
+  infeasibility_=0.0;
+  bool feasible = findRange(value,integerTolerance);
+  if (!feasible) {
+    if (rangeType_==1) {
+      if (value-bound_[range_]<bound_[range_+1]-value) {
+	preferredWay=-1;
+	infeasibility_ = value-bound_[range_];
+	otherInfeasibility_ = bound_[range_+1] - value ;
+      } else {
+	preferredWay=1;
+	infeasibility_ = bound_[range_+1]-value;
+	otherInfeasibility_ = value-bound_[range_];
+      }
+    } else {
+      // ranges
+      if (value-bound_[2*range_+1]<bound_[2*range_+2]-value) {
+	preferredWay=-1;
+	infeasibility_ = value-bound_[2*range_+1];
+	otherInfeasibility_ = bound_[2*range_+2]-value;
+      } else {
+	preferredWay=1;
+	infeasibility_ = bound_[2*range_+2]-value;
+	otherInfeasibility_ = value-bound_[2*range_+1];
+      }
+    }
+  } else {
+    // always satisfied
+    preferredWay=-1;
+    otherInfeasibility_ = 1.0;
+  }
+  if (infeasibility_<integerTolerance)
+    infeasibility_=0.0;
+  else
+    infeasibility_ /= largestGap_;
+  return infeasibility_;
+}
+/* Column number if single column object -1 otherwise,
+   so returns >= 0
+   Used by heuristics
+*/
+int 
+OsiLotsize::columnNumber() const
+{
+  return columnNumber_;
+}
+/* Set bounds to contain the current solution.
+   More precisely, for the variable associated with this object, take the
+   value given in the current solution, force it within the current bounds
+   if required, then set the bounds to fix the variable at the integer
+   nearest the solution value.  Returns amount it had to move variable.
+*/
+double 
+OsiLotsize::feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const
+{
+  const double * lower = solver->getColLower();
+  const double * upper = solver->getColUpper();
+  const double * solution = info->solution_;
+  double value = solution[columnNumber_];
+  value = CoinMax(value, lower[columnNumber_]);
+  value = CoinMin(value, upper[columnNumber_]);
+  findRange(value,info->integerTolerance_);
+  double nearest;
+  if (rangeType_==1) {
+    nearest = bound_[range_];
+    solver->setColLower(columnNumber_,nearest);
+    solver->setColUpper(columnNumber_,nearest);
+  } else {
+    // ranges
+    solver->setColLower(columnNumber_,bound_[2*range_]);
+    solver->setColUpper(columnNumber_,bound_[2*range_+1]);
+    if (value>bound_[2*range_+1]) 
+      nearest=bound_[2*range_+1];
+    else if (value<bound_[2*range_]) 
+      nearest = bound_[2*range_];
+    else
+      nearest = value;
+  }
+  // Scaling may have moved it a bit
+  // Lotsizing variables could be a lot larger
+#ifndef NDEBUG
+  assert (fabs(value-nearest)<=(100.0+10.0*fabs(nearest))*info->integerTolerance_);
+#endif
+  return fabs(value-nearest);
+}
+
+// Creates a branching object
+// Creates a branching object
+OsiBranchingObject * 
+OsiLotsize::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const 
+{
+  const double * solution = info->solution_;
+  const double * lower = solver->getColLower();
+  const double * upper = solver->getColUpper();
+  double value = solution[columnNumber_];
+  value = CoinMax(value, lower[columnNumber_]);
+  value = CoinMin(value, upper[columnNumber_]);
+  assert (!findRange(value,info->integerTolerance_));
+  return new OsiLotsizeBranchingObject(solver,this,way,
+					     value);
+}
+
+  
+/*
+  Bounds may be tightened, so it may be good to be able to refresh the local
+  copy of the original bounds.
+ */
+void 
+OsiLotsize::resetBounds(const OsiSolverInterface * )
+{
+}
+// Return "down" estimate
+double 
+OsiLotsize::downEstimate() const
+{
+  if (whichWay_)
+    return otherInfeasibility_;
+  else
+    return infeasibility_;
+}
+// Return "up" estimate
+double 
+OsiLotsize::upEstimate() const
+{
+  if (!whichWay_)
+    return otherInfeasibility_;
+  else
+    return infeasibility_;
+}
+// Redoes data when sequence numbers change
+void 
+OsiLotsize::resetSequenceEtc(int numberColumns, const int * originalColumns)
+{
+  int i;
+  for (i=0;i<numberColumns;i++) {
+    if (originalColumns[i]==columnNumber_)
+      break;
+  }
+  if (i<numberColumns)
+    columnNumber_=i;
+  else
+    abort(); // should never happen
+}
+
+
+// Default Constructor 
+OsiLotsizeBranchingObject::OsiLotsizeBranchingObject()
+  :OsiTwoWayBranchingObject()
+{
+  down_[0] = 0.0;
+  down_[1] = 0.0;
+  up_[0] = 0.0;
+  up_[1] = 0.0;
+}
+
+// Useful constructor
+OsiLotsizeBranchingObject::OsiLotsizeBranchingObject (OsiSolverInterface * solver, 
+						      const OsiLotsize * originalObject, 
+						      int way , double value)
+  :OsiTwoWayBranchingObject(solver,originalObject,way,value)
+{
+  int iColumn = originalObject->columnNumber();
+  down_[0] = solver->getColLower()[iColumn];
+  double integerTolerance = solver->getIntegerTolerance();
+  originalObject->floorCeiling(down_[1],up_[0],value,integerTolerance);
+  up_[1] = solver->getColUpper()[iColumn];
+}
+
+// Copy constructor 
+OsiLotsizeBranchingObject::OsiLotsizeBranchingObject ( const OsiLotsizeBranchingObject & rhs) :OsiTwoWayBranchingObject(rhs)
+{
+  down_[0] = rhs.down_[0];
+  down_[1] = rhs.down_[1];
+  up_[0] = rhs.up_[0];
+  up_[1] = rhs.up_[1];
+}
+
+// Assignment operator 
+OsiLotsizeBranchingObject & 
+OsiLotsizeBranchingObject::operator=( const OsiLotsizeBranchingObject& rhs)
+{
+  if (this != &rhs) {
+    OsiTwoWayBranchingObject::operator=(rhs);
+    down_[0] = rhs.down_[0];
+    down_[1] = rhs.down_[1];
+    up_[0] = rhs.up_[0];
+    up_[1] = rhs.up_[1];
+  }
+  return *this;
+}
+OsiBranchingObject * 
+OsiLotsizeBranchingObject::clone() const
+{ 
+  return (new OsiLotsizeBranchingObject(*this));
+}
+
+
+// Destructor 
+OsiLotsizeBranchingObject::~OsiLotsizeBranchingObject ()
+{
+}
+
+/*
+  Perform a branch by adjusting the bounds of the specified variable. Note
+  that each arm of the branch advances the object to the next arm by
+  advancing the value of way_.
+
+  Providing new values for the variable's lower and upper bounds for each
+  branching direction gives a little bit of additional flexibility and will
+  be easily extensible to multi-way branching.
+*/
+double
+OsiLotsizeBranchingObject::branch(OsiSolverInterface * solver)
+{
+  const OsiLotsize * obj =
+    dynamic_cast <const OsiLotsize *>(originalObject_) ;
+  assert (obj);
+  int iColumn = obj->columnNumber();
+  int way = (!branchIndex_) ? (2*firstBranch_-1) : -(2*firstBranch_-1);
+  if (way<0) {
+#ifdef OSI_DEBUG
+  { double olb,oub ;
+    olb = solver->getColLower()[iColumn] ;
+    oub = solver->getColUpper()[iColumn] ;
+    printf("branching down on var %d: [%g,%g] => [%g,%g]\n",
+	   iColumn,olb,oub,down_[0],down_[1]) ; }
+#endif
+    solver->setColLower(iColumn,down_[0]);
+    solver->setColUpper(iColumn,down_[1]);
+  } else {
+#ifdef OSI_DEBUG
+  { double olb,oub ;
+    olb = solver->getColLower()[iColumn] ;
+    oub = solver->getColUpper()[iColumn] ;
+    printf("branching up on var %d: [%g,%g] => [%g,%g]\n",
+	   iColumn,olb,oub,up_[0],up_[1]) ; }
+#endif
+    solver->setColLower(iColumn,up_[0]);
+    solver->setColUpper(iColumn,up_[1]);
+  }
+  branchIndex_++;
+  return 0.0;
+}
+// Print
+void
+OsiLotsizeBranchingObject::print(const OsiSolverInterface * solver)
+{
+  const OsiLotsize * obj =
+    dynamic_cast <const OsiLotsize *>(originalObject_) ;
+  assert (obj);
+  int iColumn = obj->columnNumber();
+  int way = (!branchIndex_) ? (2*firstBranch_-1) : -(2*firstBranch_-1);
+  if (way<0) {
+  { double olb,oub ;
+    olb = solver->getColLower()[iColumn] ;
+    oub = solver->getColUpper()[iColumn] ;
+    printf("branching down on var %d: [%g,%g] => [%g,%g]\n",
+	   iColumn,olb,oub,down_[0],down_[1]) ; }
+  } else {
+  { double olb,oub ;
+    olb = solver->getColLower()[iColumn] ;
+    oub = solver->getColUpper()[iColumn] ;
+    printf("branching up on var %d: [%g,%g] => [%g,%g]\n",
+	   iColumn,olb,oub,up_[0],up_[1]) ; }
+  }
+}
+  
diff --git a/cbits/coin/OsiBranchingObject.hpp b/cbits/coin/OsiBranchingObject.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiBranchingObject.hpp
@@ -0,0 +1,1005 @@
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiBranchingObject_H
+#define OsiBranchingObject_H
+
+#include <cassert>
+#include <string>
+#include <vector>
+
+#include "CoinError.hpp"
+#include "CoinTypes.hpp"
+
+class OsiSolverInterface;
+class OsiSolverBranch;
+
+class OsiBranchingObject;
+class OsiBranchingInformation;
+
+//#############################################################################
+//This contains the abstract base class for an object and for branching.
+//It also contains a simple integer class
+//#############################################################################
+
+/** Abstract base class for `objects'.
+
+  The branching model used in Osi is based on the idea of an <i>object</i>.
+  In the abstract, an object is something that has a feasible region, can be
+  evaluated for infeasibility, can be branched on (<i>i.e.</i>, there's some
+  constructive action to be taken to move toward feasibility), and allows
+  comparison of the effect of branching.
+
+  This class (OsiObject) is the base class for an object. To round out the
+  branching model, the class OsiBranchingObject describes how to perform a
+  branch, and the class OsiBranchDecision describes how to compare two
+  OsiBranchingObjects.
+
+  To create a new type of object you need to provide three methods:
+  #infeasibility(), #feasibleRegion(), and #createBranch(), described below.
+
+  This base class is primarily virtual to allow for any form of structure.
+  Any form of discontinuity is allowed.
+
+  As there is an overhead in getting information from solvers and because
+  other useful information is available there is also an OsiBranchingInformation 
+  class which can contain pointers to information.
+  If used it must at minimum contain pointers to current value of objective,
+  maximum allowed objective and pointers to arrays for bounds and solution
+  and direction of optimization.  Also integer and primal tolerance.
+  
+  Classes which inherit might have other information such as depth, number of
+  solutions, pseudo-shadow prices etc etc.
+  May be easier just to throw in here - as I keep doing
+*/
+class OsiObject {
+
+public:
+  
+  /// Default Constructor 
+  OsiObject ();
+  
+  /// Copy constructor 
+  OsiObject ( const OsiObject &);
+  
+  /// Assignment operator 
+  OsiObject & operator=( const OsiObject& rhs);
+  
+  /// Clone
+  virtual OsiObject * clone() const=0;
+  
+  /// Destructor 
+  virtual ~OsiObject ();
+  
+  /** Infeasibility of the object
+      
+    This is some measure of the infeasibility of the object. 0.0 
+    indicates that the object is satisfied.
+  
+    The preferred branching direction is returned in whichWay, where for
+    normal two-way branching 0 is down, 1 is up
+  
+    This is used to prepare for strong branching but should also think of
+    case when no strong branching
+  
+    The object may also compute an estimate of cost of going "up" or "down".
+    This will probably be based on pseudo-cost ideas
+
+    This should also set mutable infeasibility_ and whichWay_
+    This is for instant re-use for speed
+
+    Default for this just calls infeasibility with OsiBranchingInformation
+    NOTE - Convention says that an infeasibility of COIN_DBL_MAX means 
+    object has worked out it can't be satisfied!
+  */
+  double infeasibility(const OsiSolverInterface * solver,int &whichWay) const ;
+  // Faster version when more information available
+  virtual double infeasibility(const OsiBranchingInformation * info, int &whichWay) const =0;
+  // This does NOT set mutable stuff
+  virtual double checkInfeasibility(const OsiBranchingInformation * info) const;
+  
+  /** For the variable(s) referenced by the object,
+      look at the current solution and set bounds to match the solution.
+      Returns measure of how much it had to move solution to make feasible
+  */
+  virtual double feasibleRegion(OsiSolverInterface * solver) const ;
+  /** For the variable(s) referenced by the object,
+      look at the current solution and set bounds to match the solution.
+      Returns measure of how much it had to move solution to make feasible
+      Faster version
+  */
+  virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const =0;
+  
+  /** Create a branching object and indicate which way to branch first.
+      
+      The branching object has to know how to create branches (fix
+      variables, etc.)
+  */
+  virtual OsiBranchingObject * createBranch(OsiSolverInterface * /*solver*/,
+					    const OsiBranchingInformation * /*info*/,
+					    int /*way*/) const {throw CoinError("Need code","createBranch","OsiBranchingObject"); return NULL; }
+  
+  /** \brief Return true if object can take part in normal heuristics
+  */
+  virtual bool canDoHeuristics() const 
+  {return true;}
+  /** \brief Return true if object can take part in move to nearest heuristic
+  */
+  virtual bool canMoveToNearest() const 
+  {return false;}
+  /** Column number if single column object -1 otherwise,
+      Used by heuristics
+  */
+  virtual int columnNumber() const;
+  /// Return Priority - note 1 is highest priority
+  inline int priority() const
+  { return priority_;}
+  /// Set priority
+  inline void setPriority(int priority)
+  { priority_ = priority;}
+  /** \brief Return true if branch should only bound variables
+  */
+  virtual bool boundBranch() const 
+  {return true;}
+  /// Return true if knows how to deal with Pseudo Shadow Prices
+  virtual bool canHandleShadowPrices() const
+  { return false;}
+  /// Return maximum number of ways branch may have
+  inline int numberWays() const
+  { return numberWays_;}
+  /// Set maximum number of ways branch may have
+  inline void setNumberWays(int numberWays)
+  { numberWays_ = static_cast<short int>(numberWays) ; }
+  /** Return preferred way to branch.  If two
+      then way=0 means down and 1 means up, otherwise
+      way points to preferred branch
+  */
+  inline void setWhichWay(int way)
+  { whichWay_ = static_cast<short int>(way) ; }
+  /** Return current preferred way to branch.  If two
+      then way=0 means down and 1 means up, otherwise
+      way points to preferred branch
+  */
+  inline int whichWay() const
+  { return whichWay_;}
+  /// Get pre-emptive preferred way of branching - -1 off, 0 down, 1 up (for 2-way)
+  virtual int preferredWay() const
+  { return -1;}
+  /// Return infeasibility
+  inline double infeasibility() const
+  { return infeasibility_;}
+  /// Return "up" estimate (default 1.0e-5)
+  virtual double upEstimate() const;
+  /// Return "down" estimate (default 1.0e-5)
+  virtual double downEstimate() const;
+  /** Reset variable bounds to their original values.
+    Bounds may be tightened, so it may be good to be able to reset them to
+    their original values.
+   */
+  virtual void resetBounds(const OsiSolverInterface * ) {}
+  /**  Change column numbers after preprocessing
+   */
+  virtual void resetSequenceEtc(int , const int * ) {}
+  /// Updates stuff like pseudocosts before threads
+  virtual void updateBefore(const OsiObject * ) {}
+  /// Updates stuff like pseudocosts after threads finished
+  virtual void updateAfter(const OsiObject * , const OsiObject * ) {}
+
+protected:
+  /// data
+
+  /// Computed infeasibility
+  mutable double infeasibility_;
+  /// Computed preferred way to branch 
+  mutable short whichWay_;
+  /// Maximum number of ways on branch
+  short  numberWays_;
+  /// Priority
+  int priority_;
+
+};
+/// Define a class to add a bit of complexity to OsiObject
+/// This assumes 2 way branching
+
+
+class OsiObject2 : public OsiObject {
+
+public:
+
+  /// Default Constructor 
+  OsiObject2 ();
+
+  /// Copy constructor 
+  OsiObject2 ( const OsiObject2 &);
+   
+  /// Assignment operator 
+  OsiObject2 & operator=( const OsiObject2& rhs);
+
+  /// Destructor 
+  virtual ~OsiObject2 ();
+  
+  /// Set preferred way of branching - -1 off, 0 down, 1 up (for 2-way)
+  inline void setPreferredWay(int value)
+  {preferredWay_=value;}
+  
+  /// Get preferred way of branching - -1 off, 0 down, 1 up (for 2-way)
+  virtual int preferredWay() const
+  { return preferredWay_;}
+protected:
+  /// Preferred way of branching - -1 off, 0 down, 1 up (for 2-way)
+  int preferredWay_;
+  /// "Infeasibility" on other way
+  mutable double otherInfeasibility_;
+  
+};
+
+/** \brief Abstract branching object base class
+
+  In the abstract, an OsiBranchingObject contains instructions for how to
+  branch. We want an abstract class so that we can describe how to branch on
+  simple objects (<i>e.g.</i>, integers) and more exotic objects
+  (<i>e.g.</i>, cliques or hyperplanes).
+
+  The #branch() method is the crucial routine: it is expected to be able to
+  step through a set of branch arms, executing the actions required to create
+  each subproblem in turn. The base class is primarily virtual to allow for
+  a wide range of problem modifications.
+
+  See OsiObject for an overview of the two classes (OsiObject and
+  OsiBranchingObject) which make up Osi's branching
+  model.
+*/
+
+class OsiBranchingObject {
+
+public:
+
+  /// Default Constructor 
+  OsiBranchingObject ();
+
+  /// Constructor 
+  OsiBranchingObject (OsiSolverInterface * solver, double value);
+  
+  /// Copy constructor 
+  OsiBranchingObject ( const OsiBranchingObject &);
+   
+  /// Assignment operator 
+  OsiBranchingObject & operator=( const OsiBranchingObject& rhs);
+
+  /// Clone
+  virtual OsiBranchingObject * clone() const=0;
+
+  /// Destructor 
+  virtual ~OsiBranchingObject ();
+
+  /// The number of branch arms created for this branching object
+  inline int numberBranches() const
+  {return numberBranches_;}
+
+  /// The number of branch arms left for this branching object
+  inline int numberBranchesLeft() const
+  {return numberBranches_-branchIndex_;}
+
+  /// Increment the number of branch arms left for this branching object
+  inline void incrementNumberBranchesLeft()
+  { numberBranches_ ++;}
+
+  /** Set the number of branch arms left for this branching object
+      Just for forcing
+  */
+  inline void setNumberBranchesLeft(int /*value*/)
+  {/*assert (value==1&&!branchIndex_);*/ numberBranches_=1;}
+
+  /// Decrement the number of branch arms left for this branching object
+  inline void decrementNumberBranchesLeft()
+  {branchIndex_++;}
+
+  /** \brief Execute the actions required to branch, as specified by the
+	     current state of the branching object, and advance the object's
+	     state. 
+	     Returns change in guessed objective on next branch
+  */
+  virtual double branch(OsiSolverInterface * solver)=0;
+  /** \brief Execute the actions required to branch, as specified by the
+	     current state of the branching object, and advance the object's
+	     state. 
+	     Returns change in guessed objective on next branch
+  */
+  virtual double branch() {return branch(NULL);}
+  /** \brief Return true if branch should fix variables
+  */
+  virtual bool boundBranch() const 
+  {return true;}
+  /** Get the state of the branching object
+      This is just the branch index
+  */
+  inline int branchIndex() const
+  {return branchIndex_;}
+
+  /** Set the state of the branching object.
+  */
+  inline void setBranchingIndex(int branchIndex)
+  { branchIndex_ = static_cast<short int>(branchIndex) ; }
+
+  /// Current value
+  inline double value() const
+  {return value_;}
+  
+  /// Return pointer back to object which created
+  inline const OsiObject * originalObject() const
+  {return  originalObject_;}
+  /// Set pointer back to object which created
+  inline void setOriginalObject(const OsiObject * object)
+  {originalObject_=object;}
+  /** Double checks in case node can change its mind!
+      Returns objective value
+      Can change objective etc */
+  virtual void checkIsCutoff(double ) {}
+  /// For debug
+  int columnNumber() const;
+  /** \brief Print something about branch - only if log level high
+  */
+  virtual void print(const OsiSolverInterface * =NULL) const {}
+
+protected:
+
+  /// Current value - has some meaning about branch
+  double value_;
+
+  /// Pointer back to object which created
+  const OsiObject * originalObject_;
+
+  /** Number of branches
+  */
+  int numberBranches_;
+
+  /** The state of the branching object. i.e. branch index
+      This starts at 0 when created
+  */
+  short branchIndex_;
+
+};
+/* This contains information
+   This could also contain pseudo shadow prices
+   or information for dealing with computing and trusting pseudo-costs
+*/
+class OsiBranchingInformation {
+
+public:
+  
+  /// Default Constructor 
+  OsiBranchingInformation ();
+  
+  /** Useful Constructor 
+      (normalSolver true if has matrix etc etc)
+      copySolution true if constructot should make a copy
+  */
+  OsiBranchingInformation (const OsiSolverInterface * solver, bool normalSolver,bool copySolution=false);
+  
+  /// Copy constructor 
+  OsiBranchingInformation ( const OsiBranchingInformation &);
+  
+  /// Assignment operator 
+  OsiBranchingInformation & operator=( const OsiBranchingInformation& rhs);
+  
+  /// Clone
+  virtual OsiBranchingInformation * clone() const;
+  
+  /// Destructor 
+  virtual ~OsiBranchingInformation ();
+  
+  // Note public
+public:
+  /// data
+
+  /** State of search
+      0 - no solution
+      1 - only heuristic solutions
+      2 - branched to a solution 
+      3 - no solution but many nodes
+  */
+  int stateOfSearch_;
+  /// Value of objective function (in minimization sense)
+  double objectiveValue_;
+  /// Value of objective cutoff (in minimization sense)
+  double cutoff_;
+  /// Direction 1.0 for minimization, -1.0 for maximization
+  double direction_;
+  /// Integer tolerance
+  double integerTolerance_;
+  /// Primal tolerance
+  double primalTolerance_;
+  /// Maximum time remaining before stopping on time
+  double timeRemaining_;
+  /// Dual to use if row bound violated (if negative then pseudoShadowPrices off)
+  double defaultDual_;
+  /// Pointer to solver
+  mutable const OsiSolverInterface * solver_;
+  /// The number of columns
+  int numberColumns_;
+  /// Pointer to current lower bounds on columns
+  mutable const double * lower_;
+  /// Pointer to current solution
+  mutable const double * solution_;
+  /// Pointer to current upper bounds on columns
+  mutable const double * upper_;
+  /// Highly optional target (hot start) solution
+  const double * hotstartSolution_;
+  /// Pointer to duals
+  const double * pi_;
+  /// Pointer to row activity
+  const double * rowActivity_;
+  /// Objective
+  const double * objective_;
+  /// Pointer to current lower bounds on rows
+  const double * rowLower_;
+  /// Pointer to current upper bounds on rows
+  const double * rowUpper_;
+  /// Elements in column copy of matrix
+  const double * elementByColumn_;
+  /// Column starts
+  const CoinBigIndex * columnStart_;
+  /// Column lengths
+  const int * columnLength_;
+  /// Row indices
+  const int * row_;
+  /** Useful region of length CoinMax(numberColumns,2*numberRows)
+      This is allocated and deleted before OsiObject::infeasibility
+      It is zeroed on entry and should be so on exit
+      It only exists if defaultDual_>=0.0
+  */
+  double * usefulRegion_;
+  /// Useful index region to go with usefulRegion_
+  int * indexRegion_;
+  /// Number of solutions found
+  int numberSolutions_;
+  /// Number of branching solutions found (i.e. exclude heuristics)
+  int numberBranchingSolutions_;
+  /// Depth in tree
+  int depth_;
+  /// TEMP
+  bool owningSolution_;
+};
+
+/// This just adds two-wayness to a branching object
+
+class OsiTwoWayBranchingObject : public OsiBranchingObject {
+
+public:
+
+  /// Default constructor 
+  OsiTwoWayBranchingObject ();
+
+  /** Create a standard tw0-way branch object
+
+    Specifies a simple two-way branch.
+    Specify way = -1 to set the object state to perform the down arm first,
+    way = 1 for the up arm.
+  */
+  OsiTwoWayBranchingObject (OsiSolverInterface *solver,const OsiObject * originalObject,
+			     int way , double value) ;
+    
+  /// Copy constructor 
+  OsiTwoWayBranchingObject ( const OsiTwoWayBranchingObject &);
+   
+  /// Assignment operator 
+  OsiTwoWayBranchingObject & operator= (const OsiTwoWayBranchingObject& rhs);
+
+  /// Destructor 
+  virtual ~OsiTwoWayBranchingObject ();
+
+  using OsiBranchingObject::branch ;
+  /** \brief Sets the bounds for the variable according to the current arm
+	     of the branch and advances the object state to the next arm.
+	     state. 
+	     Returns change in guessed objective on next branch
+  */
+  virtual double branch(OsiSolverInterface * solver)=0;
+
+  inline int firstBranch() const { return firstBranch_; }
+  /// Way returns -1 on down +1 on up
+  inline int way() const
+  { return !branchIndex_ ? firstBranch_ : -firstBranch_;}
+protected:
+  /// Which way was first branch -1 = down, +1 = up
+  int firstBranch_;
+};
+/// Define a single integer class
+
+
+class OsiSimpleInteger : public OsiObject2 {
+
+public:
+
+  /// Default Constructor 
+  OsiSimpleInteger ();
+
+  /// Useful constructor - passed solver index
+  OsiSimpleInteger (const OsiSolverInterface * solver, int iColumn);
+  
+  /// Useful constructor - passed solver index and original bounds
+  OsiSimpleInteger (int iColumn, double lower, double upper);
+  
+  /// Copy constructor 
+  OsiSimpleInteger ( const OsiSimpleInteger &);
+   
+  /// Clone
+  virtual OsiObject * clone() const;
+
+  /// Assignment operator 
+  OsiSimpleInteger & operator=( const OsiSimpleInteger& rhs);
+
+  /// Destructor 
+  virtual ~OsiSimpleInteger ();
+  
+  using OsiObject::infeasibility ;
+  /// Infeasibility - large is 0.5
+  virtual double infeasibility(const OsiBranchingInformation * info, int & whichWay) const;
+
+  using OsiObject::feasibleRegion ;
+  /** Set bounds to fix the variable at the current (integer) value.
+
+    Given an integer value, set the lower and upper bounds to fix the
+    variable. Returns amount it had to move variable.
+  */
+  virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+  /** Creates a branching object
+
+    The preferred direction is set by \p way, 0 for down, 1 for up.
+  */
+  virtual OsiBranchingObject * createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+
+
+  /// Set solver column number
+  inline void setColumnNumber(int value)
+  {columnNumber_=value;}
+  
+  /** Column number if single column object -1 otherwise,
+      so returns >= 0
+      Used by heuristics
+  */
+  virtual int columnNumber() const;
+
+  /// Original bounds
+  inline double originalLowerBound() const
+  { return originalLower_;}
+  inline void setOriginalLowerBound(double value)
+  { originalLower_=value;}
+  inline double originalUpperBound() const
+  { return originalUpper_;}
+  inline void setOriginalUpperBound(double value)
+  { originalUpper_=value;}
+  /** Reset variable bounds to their original values.
+    Bounds may be tightened, so it may be good to be able to reset them to
+    their original values.
+   */
+  virtual void resetBounds(const OsiSolverInterface * solver) ;
+  /**  Change column numbers after preprocessing
+   */
+  virtual void resetSequenceEtc(int numberColumns, const int * originalColumns);
+  
+  /// Return "up" estimate (default 1.0e-5)
+  virtual double upEstimate() const;
+  /// Return "down" estimate (default 1.0e-5)
+  virtual double downEstimate() const;
+  /// Return true if knows how to deal with Pseudo Shadow Prices
+  virtual bool canHandleShadowPrices() const
+  { return false;}
+protected:
+  /// data
+  /// Original lower bound
+  double originalLower_;
+  /// Original upper bound
+  double originalUpper_;
+  /// Column number in solver
+  int columnNumber_;
+  
+};
+/** Simple branching object for an integer variable
+
+  This object can specify a two-way branch on an integer variable. For each
+  arm of the branch, the upper and lower bounds on the variable can be
+  independently specified. 0 -> down, 1-> up.
+*/
+
+class OsiIntegerBranchingObject : public OsiTwoWayBranchingObject {
+
+public:
+
+  /// Default constructor 
+  OsiIntegerBranchingObject ();
+
+  /** Create a standard floor/ceiling branch object
+
+    Specifies a simple two-way branch. Let \p value = x*. One arm of the
+    branch will be lb <= x <= floor(x*), the other ceil(x*) <= x <= ub.
+    Specify way = -1 to set the object state to perform the down arm first,
+    way = 1 for the up arm.
+  */
+  OsiIntegerBranchingObject (OsiSolverInterface *solver,const OsiSimpleInteger * originalObject,
+			     int way , double value) ;
+  /** Create a standard floor/ceiling branch object
+
+    Specifies a simple two-way branch in a more flexible way. One arm of the
+    branch will be lb <= x <= downUpperBound, the other upLowerBound <= x <= ub.
+    Specify way = -1 to set the object state to perform the down arm first,
+    way = 1 for the up arm.
+  */
+  OsiIntegerBranchingObject (OsiSolverInterface *solver,const OsiSimpleInteger * originalObject,
+			     int way , double value, double downUpperBound, double upLowerBound) ;
+    
+  /// Copy constructor 
+  OsiIntegerBranchingObject ( const OsiIntegerBranchingObject &);
+   
+  /// Assignment operator 
+  OsiIntegerBranchingObject & operator= (const OsiIntegerBranchingObject& rhs);
+
+  /// Clone
+  virtual OsiBranchingObject * clone() const;
+
+  /// Destructor 
+  virtual ~OsiIntegerBranchingObject ();
+  
+  using OsiBranchingObject::branch ;
+  /** \brief Sets the bounds for the variable according to the current arm
+	     of the branch and advances the object state to the next arm.
+	     state. 
+	     Returns change in guessed objective on next branch
+  */
+  virtual double branch(OsiSolverInterface * solver);
+
+  using OsiBranchingObject::print ;
+  /** \brief Print something about branch - only if log level high
+  */
+  virtual void print(const OsiSolverInterface * solver=NULL);
+
+protected:
+  // Probably could get away with just value which is already stored 
+  /// Lower [0] and upper [1] bounds for the down arm (way_ = -1)
+  double down_[2];
+  /// Lower [0] and upper [1] bounds for the up arm (way_ = 1)
+  double up_[2];
+};
+
+
+/** Define Special Ordered Sets of type 1 and 2.  These do not have to be
+    integer - so do not appear in lists of integers.
+    
+    which_ points columns of matrix
+*/
+
+
+class OsiSOS : public OsiObject2 {
+
+public:
+
+  // Default Constructor 
+  OsiSOS ();
+
+  /** Useful constructor - which are indices
+      and  weights are also given.  If null then 0,1,2..
+      type is SOS type
+  */
+  OsiSOS (const OsiSolverInterface * solver, int numberMembers,
+	   const int * which, const double * weights, int type=1);
+  
+  // Copy constructor 
+  OsiSOS ( const OsiSOS &);
+   
+  /// Clone
+  virtual OsiObject * clone() const;
+
+  // Assignment operator 
+  OsiSOS & operator=( const OsiSOS& rhs);
+
+  // Destructor 
+  virtual ~OsiSOS ();
+  
+  using OsiObject::infeasibility ;
+  /// Infeasibility - large is 0.5
+  virtual double infeasibility(const OsiBranchingInformation * info,int & whichWay) const;
+
+  using OsiObject::feasibleRegion ;
+  /** Set bounds to fix the variable at the current (integer) value.
+
+    Given an integer value, set the lower and upper bounds to fix the
+    variable. Returns amount it had to move variable.
+  */
+  virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+  /** Creates a branching object
+
+    The preferred direction is set by \p way, 0 for down, 1 for up.
+  */
+  virtual OsiBranchingObject * createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+  /// Return "up" estimate (default 1.0e-5)
+  virtual double upEstimate() const;
+  /// Return "down" estimate (default 1.0e-5)
+  virtual double downEstimate() const;
+  
+  /// Redoes data when sequence numbers change
+  virtual void resetSequenceEtc(int numberColumns, const int * originalColumns);
+  
+  /// Number of members
+  inline int numberMembers() const
+  {return numberMembers_;}
+
+  /// Members (indices in range 0 ... numberColumns-1)
+  inline const int * members() const
+  {return members_;}
+
+  /// SOS type
+  inline int sosType() const
+  {return sosType_;}
+
+  /// SOS type
+  inline int setType() const
+  {return sosType_;}
+
+  /** Array of weights */
+  inline const double * weights() const
+  { return weights_;}
+
+  /** \brief Return true if object can take part in normal heuristics
+  */
+  virtual bool canDoHeuristics() const 
+  {return (sosType_==1&&integerValued_);}
+  /// Set whether set is integer valued or not
+  inline void setIntegerValued(bool yesNo)
+  { integerValued_=yesNo;}
+  /// Return true if knows how to deal with Pseudo Shadow Prices
+  virtual bool canHandleShadowPrices() const
+  { return true;}
+  /// Set number of members
+  inline void setNumberMembers(int value)
+  {numberMembers_=value;}
+
+  /// Members (indices in range 0 ... numberColumns-1)
+  inline int * mutableMembers() const
+  {return members_;}
+
+  /// Set SOS type
+  inline void setSosType(int value)
+  {sosType_=value;}
+
+  /** Array of weights */
+  inline  double * mutableWeights() const
+  { return weights_;}
+protected:
+  /// data
+
+  /// Members (indices in range 0 ... numberColumns-1)
+  int * members_;
+  /// Weights
+  double * weights_;
+
+  /// Number of members
+  int numberMembers_;
+  /// SOS type
+  int sosType_;
+  /// Whether integer valued
+  bool integerValued_;
+};
+
+/** Branching object for Special ordered sets
+
+ */
+class OsiSOSBranchingObject : public OsiTwoWayBranchingObject {
+
+public:
+
+  // Default Constructor 
+  OsiSOSBranchingObject ();
+
+  // Useful constructor
+  OsiSOSBranchingObject (OsiSolverInterface * solver,  const OsiSOS * originalObject,
+			    int way,
+			 double separator);
+  
+  // Copy constructor 
+  OsiSOSBranchingObject ( const OsiSOSBranchingObject &);
+   
+  // Assignment operator 
+  OsiSOSBranchingObject & operator=( const OsiSOSBranchingObject& rhs);
+
+  /// Clone
+  virtual OsiBranchingObject * clone() const;
+
+  // Destructor 
+  virtual ~OsiSOSBranchingObject ();
+  
+  using OsiBranchingObject::branch ;
+  /// Does next branch and updates state
+  virtual double branch(OsiSolverInterface * solver);
+
+  using OsiBranchingObject::print ;
+  /** \brief Print something about branch - only if log level high
+  */
+  virtual void print(const OsiSolverInterface * solver=NULL);
+private:
+  /// data
+};
+/** Lotsize class */
+
+
+class OsiLotsize : public OsiObject2 {
+
+public:
+
+  // Default Constructor 
+  OsiLotsize ();
+
+  /* Useful constructor - passed model index.
+     Also passed valid values - if range then pairs
+  */
+  OsiLotsize (const OsiSolverInterface * solver, int iColumn,
+	      int numberPoints, const double * points, bool range=false);
+  
+  // Copy constructor 
+  OsiLotsize ( const OsiLotsize &);
+   
+  /// Clone
+  virtual OsiObject * clone() const;
+
+  // Assignment operator 
+  OsiLotsize & operator=( const OsiLotsize& rhs);
+
+  // Destructor 
+  virtual ~OsiLotsize ();
+  
+  using OsiObject::infeasibility ;
+  /// Infeasibility - large is 0.5
+  virtual double infeasibility(const OsiBranchingInformation * info, int & whichWay) const;
+
+  using OsiObject::feasibleRegion ;
+  /** Set bounds to contain the current solution.
+
+    More precisely, for the variable associated with this object, take the
+    value given in the current solution, force it within the current bounds
+    if required, then set the bounds to fix the variable at the integer
+    nearest the solution value.  Returns amount it had to move variable.
+  */
+  virtual double feasibleRegion(OsiSolverInterface * solver, const OsiBranchingInformation * info) const;
+
+  /** Creates a branching object
+
+    The preferred direction is set by \p way, 0 for down, 1 for up.
+  */
+  virtual OsiBranchingObject * createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const;
+
+
+  /// Set solver column number
+  inline void setColumnNumber(int value)
+  {columnNumber_=value;}
+  
+  /** Column number if single column object -1 otherwise,
+      so returns >= 0
+      Used by heuristics
+  */
+  virtual int columnNumber() const;
+  /** Reset original upper and lower bound values from the solver.
+  
+    Handy for updating bounds held in this object after bounds held in the
+    solver have been tightened.
+   */
+  virtual void resetBounds(const OsiSolverInterface * solver);
+
+  /** Finds range of interest so value is feasible in range range_ or infeasible 
+      between hi[range_] and lo[range_+1].  Returns true if feasible.
+  */
+  bool findRange(double value, double integerTolerance) const;
+  
+  /** Returns floor and ceiling
+  */
+  virtual void floorCeiling(double & floorLotsize, double & ceilingLotsize, double value,
+			    double tolerance) const;
+  
+  /// Original bounds
+  inline double originalLowerBound() const
+  { return bound_[0];}
+  inline double originalUpperBound() const
+  { return bound_[rangeType_*numberRanges_-1];}
+  /// Type - 1 points, 2 ranges
+  inline int rangeType() const
+  { return rangeType_;}
+  /// Number of points
+  inline int numberRanges() const
+  { return numberRanges_;}
+  /// Ranges
+  inline double * bound() const
+  { return bound_;}
+  /**  Change column numbers after preprocessing
+   */
+  virtual void resetSequenceEtc(int numberColumns, const int * originalColumns);
+  
+  /// Return "up" estimate (default 1.0e-5)
+  virtual double upEstimate() const;
+  /// Return "down" estimate (default 1.0e-5)
+  virtual double downEstimate() const;
+  /// Return true if knows how to deal with Pseudo Shadow Prices
+  virtual bool canHandleShadowPrices() const
+  { return true;}
+  /** \brief Return true if object can take part in normal heuristics
+  */
+  virtual bool canDoHeuristics() const 
+  {return false;}
+
+private:
+  /// data
+
+  /// Column number in model
+  int columnNumber_;
+  /// Type - 1 points, 2 ranges
+  int rangeType_;
+  /// Number of points
+  int numberRanges_;
+  // largest gap
+  double largestGap_;
+  /// Ranges
+  double * bound_;
+  /// Current range
+  mutable int range_;
+};
+
+
+/** Lotsize branching object
+
+  This object can specify a two-way branch on an integer variable. For each
+  arm of the branch, the upper and lower bounds on the variable can be
+  independently specified.
+  
+  Variable_ holds the index of the integer variable in the integerVariable_
+  array of the model.
+*/
+
+class OsiLotsizeBranchingObject : public OsiTwoWayBranchingObject {
+
+public:
+
+  /// Default constructor 
+  OsiLotsizeBranchingObject ();
+
+  /** Create a lotsize floor/ceiling branch object
+
+    Specifies a simple two-way branch. Let \p value = x*. One arm of the
+    branch will be is lb <= x <= valid range below(x*), the other valid range above(x*) <= x <= ub.
+    Specify way = -1 to set the object state to perform the down arm first,
+    way = 1 for the up arm.
+  */
+  OsiLotsizeBranchingObject (OsiSolverInterface *solver,const OsiLotsize * originalObject, 
+			     int way , double value) ;
+  
+  /// Copy constructor 
+  OsiLotsizeBranchingObject ( const OsiLotsizeBranchingObject &);
+   
+  /// Assignment operator 
+  OsiLotsizeBranchingObject & operator= (const OsiLotsizeBranchingObject& rhs);
+
+  /// Clone
+  virtual OsiBranchingObject * clone() const;
+
+  /// Destructor 
+  virtual ~OsiLotsizeBranchingObject ();
+
+  using OsiBranchingObject::branch ;
+  /** \brief Sets the bounds for the variable according to the current arm
+	     of the branch and advances the object state to the next arm.
+	     state. 
+	     Returns change in guessed objective on next branch
+  */
+  virtual double branch(OsiSolverInterface * solver);
+
+  using OsiBranchingObject::print ;
+  /** \brief Print something about branch - only if log level high
+  */
+  virtual void print(const OsiSolverInterface * solver=NULL);
+
+protected:
+  /// Lower [0] and upper [1] bounds for the down arm (way_ = -1)
+  double down_[2];
+  /// Lower [0] and upper [1] bounds for the up arm (way_ = 1)
+  double up_[2];
+};
+#endif
diff --git a/cbits/coin/OsiCbcSolverInterface.cpp b/cbits/coin/OsiCbcSolverInterface.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiCbcSolverInterface.cpp
@@ -0,0 +1,896 @@
+// $Id: OsiCbcSolverInterface.cpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cassert>
+
+#include "OsiConfig.h"
+#include "CoinTime.hpp"
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinIndexedVector.hpp"
+
+/*
+  Default solver configuration: In any environment, clp is the default if you
+  do nothing.
+  
+  The necessary definitions will be handled by the configure script (based on
+  the value specified for --with-osicbc-default-solver) in any environment
+  where configure is available. The results can be found in inc/config_osi.h,
+  which is created during configuration from config_osi.h.in and placed
+  in the build directory.
+
+  In an environment which does not use configure (MS Visual Studio, for example)
+  the preferred method is to edit the definitions in inc/OsiConfig.h. The
+  symbols are left undefined by default because some older environments (e.g.,
+  MS Visual Studio v7 or earlier) will not accept an #include directive which
+  uses a macro to specify the file. In such an environment, if you want to use
+  a solver other than OsiClp, you'll need to make the changes here.
+*/
+
+#ifndef OSICBC_DFLT_SOLVER
+#define OSICBC_DFLT_SOLVER OsiClpSolverInterface
+#define OSICBC_CLP_DFLT_SOLVER
+#include "OsiClpSolverInterface.hpp"
+#else
+#include OSICBC_DFLT_SOLVER_HPP
+#endif
+
+#include "OsiCbcSolverInterface.hpp"
+#include "OsiCuts.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiColCut.hpp"
+#ifdef OSICBC_CLP_DFLT_SOLVER
+#include "ClpPresolve.hpp"
+#endif
+//#############################################################################
+// Solve methods
+//#############################################################################
+void OsiCbcSolverInterface::initialSolve()
+{
+  modelPtr_->solver()->initialSolve();
+}
+
+//-----------------------------------------------------------------------------
+void OsiCbcSolverInterface::resolve()
+{
+  modelPtr_->solver()->resolve();
+}
+//#############################################################################
+// Parameter related methods
+//#############################################################################
+
+bool
+OsiCbcSolverInterface::setIntParam(OsiIntParam key, int value)
+{
+  return modelPtr_->solver()->setIntParam(key,value);;
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiCbcSolverInterface::setDblParam(OsiDblParam key, double value)
+{
+  return modelPtr_->solver()->setDblParam(key,value);
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiCbcSolverInterface::setStrParam(OsiStrParam key, const std::string & value)
+{
+  return modelPtr_->solver()->setStrParam(key,value);
+}
+
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiCbcSolverInterface::getIntParam(OsiIntParam key, int& value) const 
+{
+  return modelPtr_->solver()->getIntParam(key,value);
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiCbcSolverInterface::getDblParam(OsiDblParam key, double& value) const
+{
+  return modelPtr_->solver()->getDblParam(key,value);
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiCbcSolverInterface::getStrParam(OsiStrParam key, std::string & value) const
+{
+  if ( key==OsiSolverName ) {
+    std::string value2;
+    modelPtr_->solver()->getStrParam(key,value2);
+    value = "cbc"+value2;
+    return true;
+  }
+  return modelPtr_->solver()->getStrParam(key,value);
+}
+
+
+//#############################################################################
+// Methods returning info on how the solution process terminated
+//#############################################################################
+
+bool OsiCbcSolverInterface::isAbandoned() const
+{
+  return modelPtr_->solver()->isAbandoned();
+}
+
+bool OsiCbcSolverInterface::isProvenOptimal() const
+{
+  return modelPtr_->solver()->isProvenOptimal();
+}
+
+bool OsiCbcSolverInterface::isProvenPrimalInfeasible() const
+{
+  return modelPtr_->solver()->isProvenPrimalInfeasible();
+}
+
+bool OsiCbcSolverInterface::isProvenDualInfeasible() const
+{
+  return modelPtr_->solver()->isProvenDualInfeasible();
+}
+bool OsiCbcSolverInterface::isPrimalObjectiveLimitReached() const
+{
+  return modelPtr_->solver()->isPrimalObjectiveLimitReached();
+}
+
+bool OsiCbcSolverInterface::isDualObjectiveLimitReached() const
+{
+  return modelPtr_->solver()->isDualObjectiveLimitReached();
+}
+
+bool OsiCbcSolverInterface::isIterationLimitReached() const
+{
+  return modelPtr_->solver()->isIterationLimitReached();
+}
+
+//#############################################################################
+// WarmStart related methods
+//#############################################################################
+CoinWarmStart *OsiCbcSolverInterface::getEmptyWarmStart () const
+{
+  return modelPtr_->solver()->getEmptyWarmStart();
+}
+
+CoinWarmStart* OsiCbcSolverInterface::getWarmStart() const
+{
+  return modelPtr_->solver()->getWarmStart();
+}
+
+//-----------------------------------------------------------------------------
+
+bool OsiCbcSolverInterface::setWarmStart(const CoinWarmStart* warmstart)
+{
+  return modelPtr_->solver()->setWarmStart(warmstart);
+}
+
+//#############################################################################
+// Hotstart related methods (primarily used in strong branching)
+//#############################################################################
+
+void OsiCbcSolverInterface::markHotStart()
+{
+  modelPtr_->solver()->markHotStart();
+}
+
+void OsiCbcSolverInterface::solveFromHotStart()
+{
+  modelPtr_->solver()->solveFromHotStart();
+}
+
+void OsiCbcSolverInterface::unmarkHotStart()
+{
+  modelPtr_->solver()->unmarkHotStart();
+}
+
+//#############################################################################
+// Problem information methods (original data)
+//#############################################################################
+
+//------------------------------------------------------------------
+const char * OsiCbcSolverInterface::getRowSense() const
+{
+  return modelPtr_->solver()->getRowSense();
+}
+//------------------------------------------------------------------
+const double * OsiCbcSolverInterface::getRightHandSide() const
+{
+  return modelPtr_->solver()->getRightHandSide();
+}
+//------------------------------------------------------------------
+const double * OsiCbcSolverInterface::getRowRange() const
+{
+  return modelPtr_->solver()->getRowRange();
+}
+//------------------------------------------------------------------
+// Return information on integrality
+//------------------------------------------------------------------
+bool OsiCbcSolverInterface::isContinuous(int colNumber) const
+{
+  return modelPtr_->solver()->isContinuous(colNumber);
+}
+//------------------------------------------------------------------
+
+//------------------------------------------------------------------
+// Row and column copies of the matrix ...
+//------------------------------------------------------------------
+const CoinPackedMatrix * OsiCbcSolverInterface::getMatrixByRow() const
+{
+  return modelPtr_->solver()->getMatrixByRow();
+}
+
+const CoinPackedMatrix * OsiCbcSolverInterface::getMatrixByCol() const
+{
+  return modelPtr_->solver()->getMatrixByCol();
+}
+
+//------------------------------------------------------------------
+std::vector<double*> OsiCbcSolverInterface::getDualRays(int maxNumRays,
+							bool fullRay) const
+{
+  return modelPtr_->solver()->getDualRays(maxNumRays,fullRay);
+}
+//------------------------------------------------------------------
+std::vector<double*> OsiCbcSolverInterface::getPrimalRays(int maxNumRays) const
+{
+  return modelPtr_->solver()->getPrimalRays(maxNumRays);
+}
+//#############################################################################
+void
+OsiCbcSolverInterface::setContinuous(int index)
+{
+  modelPtr_->solver()->setContinuous(index);
+}
+//-----------------------------------------------------------------------------
+void
+OsiCbcSolverInterface::setInteger(int index)
+{
+  modelPtr_->solver()->setInteger(index);
+}
+//-----------------------------------------------------------------------------
+void
+OsiCbcSolverInterface::setContinuous(const int* indices, int len)
+{
+  modelPtr_->solver()->setContinuous(indices,len);
+}
+//-----------------------------------------------------------------------------
+void
+OsiCbcSolverInterface::setInteger(const int* indices, int len)
+{
+  modelPtr_->solver()->setInteger(indices,len);
+}
+//-----------------------------------------------------------------------------
+void OsiCbcSolverInterface::setColSolution(const double * cs) 
+{
+  modelPtr_->solver()->setColSolution(cs);
+}
+//-----------------------------------------------------------------------------
+void OsiCbcSolverInterface::setRowPrice(const double * rs) 
+{
+  modelPtr_->solver()->setRowPrice(rs);
+}
+
+//#############################################################################
+// Problem modifying methods (matrix)
+//#############################################################################
+void 
+OsiCbcSolverInterface::addCol(const CoinPackedVectorBase& vec,
+			      const double collb, const double colub,   
+			      const double obj)
+{
+  modelPtr_->solver()->addCol(vec,collb,colub,obj);
+}
+/* Add a column (primal variable) to the problem. */
+void 
+OsiCbcSolverInterface::addCol(int numberElements, const int * rows, const double * elements,
+			   const double collb, const double colub,   
+			   const double obj) 
+{
+  modelPtr_->solver()->addCol(numberElements, rows, elements,
+                              collb,colub,obj);
+}
+//-----------------------------------------------------------------------------
+void 
+OsiCbcSolverInterface::addCols(const int numcols,
+			       const CoinPackedVectorBase * const * cols,
+			       const double* collb, const double* colub,   
+			       const double* obj)
+{
+  modelPtr_->solver()->addCols(numcols,cols,collb,colub,obj);
+}
+//-----------------------------------------------------------------------------
+void 
+OsiCbcSolverInterface::deleteCols(const int num, const int * columnIndices)
+{
+  modelPtr_->solver()->deleteCols(num,columnIndices);
+}
+//-----------------------------------------------------------------------------
+void 
+OsiCbcSolverInterface::addRow(const CoinPackedVectorBase& vec,
+			      const double rowlb, const double rowub)
+{
+  modelPtr_->solver()->addRow(vec,rowlb,rowub);
+}
+//-----------------------------------------------------------------------------
+void 
+OsiCbcSolverInterface::addRow(const CoinPackedVectorBase& vec,
+			      const char rowsen, const double rowrhs,   
+			      const double rowrng)
+{
+  modelPtr_->solver()->addRow(vec,rowsen,rowrhs,rowrng);
+}
+//-----------------------------------------------------------------------------
+void 
+OsiCbcSolverInterface::addRows(const int numrows,
+			       const CoinPackedVectorBase * const * rows,
+			       const double* rowlb, const double* rowub)
+{
+  modelPtr_->solver()->addRows(numrows,rows,rowlb,rowub);
+}
+//-----------------------------------------------------------------------------
+void 
+OsiCbcSolverInterface::addRows(const int numrows,
+			       const CoinPackedVectorBase * const * rows,
+			       const char* rowsen, const double* rowrhs,   
+			       const double* rowrng)
+{
+  modelPtr_->solver()->addRows(numrows,rows,rowsen,rowrhs,rowrng);
+}
+//-----------------------------------------------------------------------------
+void 
+OsiCbcSolverInterface::deleteRows(const int num, const int * rowIndices)
+{
+  modelPtr_->solver()->deleteRows(num,rowIndices);
+}
+
+//#############################################################################
+// Methods to input a problem
+//#############################################################################
+
+void
+OsiCbcSolverInterface::loadProblem(const CoinPackedMatrix& matrix,
+				   const double* collb, const double* colub,   
+				   const double* obj,
+				   const double* rowlb, const double* rowub)
+{
+  modelPtr_->solver()->loadProblem(matrix,collb,colub,obj,rowlb,rowub);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+OsiCbcSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
+				     double*& collb, double*& colub,
+				     double*& obj,
+				     double*& rowlb, double*& rowub)
+{
+  modelPtr_->solver()->assignProblem(matrix,collb,colub,obj,rowlb,rowub);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+OsiCbcSolverInterface::loadProblem(const CoinPackedMatrix& matrix,
+				   const double* collb, const double* colub,
+				   const double* obj,
+				   const char* rowsen, const double* rowrhs,   
+				   const double* rowrng)
+{
+  modelPtr_->solver()->loadProblem(matrix,collb,colub,obj,rowsen,rowrhs,rowrng);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+OsiCbcSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
+				     double*& collb, double*& colub,
+				     double*& obj,
+				     char*& rowsen, double*& rowrhs,
+				     double*& rowrng)
+{
+  modelPtr_->solver()->assignProblem(matrix,collb,colub,obj,rowsen,rowrhs,rowrng);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+OsiCbcSolverInterface::loadProblem(const int numcols, const int numrows,
+				   const CoinBigIndex * start, const int* index,
+				   const double* value,
+				   const double* collb, const double* colub,
+				   const double* obj,
+				   const double* rowlb, const double* rowub)
+{
+  modelPtr_->solver()->loadProblem(numcols,numrows,start,index,value,
+                                   collb,colub,obj,rowlb,rowub);
+}
+//-----------------------------------------------------------------------------
+
+void
+OsiCbcSolverInterface::loadProblem(const int numcols, const int numrows,
+				   const CoinBigIndex * start, const int* index,
+				   const double* value,
+				   const double* collb, const double* colub,
+				   const double* obj,
+				   const char* rowsen, const double* rowrhs,   
+				   const double* rowrng)
+{
+  modelPtr_->solver()->loadProblem(numcols,numrows,start,index,value,
+                                   collb,colub,obj,rowsen,rowrhs,rowrng);
+}
+
+//-----------------------------------------------------------------------------
+// Write mps files
+//-----------------------------------------------------------------------------
+
+void OsiCbcSolverInterface::writeMps(const char * filename,
+				     const char * extension,
+				     double objSense) const
+{
+  modelPtr_->solver()->writeMps(filename,extension,objSense);
+}
+
+int 
+OsiCbcSolverInterface::writeMpsNative(const char *filename, 
+		  const char ** rowNames, const char ** columnNames,
+		  int formatType,int numberAcross,double objSense) const 
+{
+  return modelPtr_->solver()->writeMpsNative(filename, rowNames, columnNames,
+			       formatType, numberAcross,objSense);
+}
+
+//#############################################################################
+// Constructors, destructors clone and assignment
+//#############################################################################
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiCbcSolverInterface::OsiCbcSolverInterface (OsiSolverInterface * solver,
+                                              CbcStrategy * strategy)
+:
+OsiSolverInterface()
+{
+  if (solver) {
+    modelPtr_=new CbcModel(*solver);
+  } else {
+    OSICBC_DFLT_SOLVER solverDflt;
+    modelPtr_=new CbcModel(solverDflt);
+  }
+  if (strategy) {
+    modelPtr_->setStrategy(*strategy);
+  } else {
+    CbcStrategyDefault defaultStrategy;
+    modelPtr_->setStrategy(defaultStrategy);
+  }
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+OsiSolverInterface * OsiCbcSolverInterface::clone(bool CopyData) const
+{
+   if (CopyData) {
+      return new OsiCbcSolverInterface(*this);
+   } else {
+      return new OsiCbcSolverInterface();
+   }
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiCbcSolverInterface::OsiCbcSolverInterface (
+                  const OsiCbcSolverInterface & rhs)
+:
+OsiSolverInterface(rhs)
+{
+  assert (rhs.modelPtr_);
+  modelPtr_ = new CbcModel(*rhs.modelPtr_);
+}
+    
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiCbcSolverInterface::~OsiCbcSolverInterface ()
+{
+  delete modelPtr_;
+}
+
+//-------------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiCbcSolverInterface &
+OsiCbcSolverInterface::operator=(const OsiCbcSolverInterface& rhs)
+{
+  if (this != &rhs) {    
+    OsiSolverInterface::operator=(rhs);
+    delete modelPtr_;
+    modelPtr_=new CbcModel(*rhs.modelPtr_);
+  }
+  return *this;
+}
+
+//#############################################################################
+// Applying cuts
+//#############################################################################
+
+void OsiCbcSolverInterface::applyRowCut( const OsiRowCut & rowCut )
+{
+  modelPtr_->solver()->applyRowCuts(1,&rowCut);
+}
+/* Apply a collection of row cuts which are all effective.
+   applyCuts seems to do one at a time which seems inefficient.
+*/
+void 
+OsiCbcSolverInterface::applyRowCuts(int numberCuts, const OsiRowCut * cuts)
+{
+  modelPtr_->solver()->applyRowCuts(numberCuts,cuts);
+}
+/* Apply a collection of row cuts which are all effective.
+   applyCuts seems to do one at a time which seems inefficient.
+*/
+void 
+OsiCbcSolverInterface::applyRowCuts(int numberCuts, const OsiRowCut ** cuts)
+{
+  modelPtr_->solver()->applyRowCuts(numberCuts, cuts);
+}
+//-----------------------------------------------------------------------------
+
+void OsiCbcSolverInterface::applyColCut( const OsiColCut & cc )
+{
+  const double * lower = modelPtr_->solver()->getColLower();
+  const double * upper = modelPtr_->solver()->getColUpper();
+  const CoinPackedVector & lbs = cc.lbs();
+  const CoinPackedVector & ubs = cc.ubs();
+  int i;
+
+  for ( i=0; i<lbs.getNumElements(); i++ ) {
+    int iCol = lbs.getIndices()[i];
+    double value = lbs.getElements()[i];
+    if ( value > lower[iCol] )
+      modelPtr_->solver()->setColLower(iCol, value);
+  }
+  for ( i=0; i<ubs.getNumElements(); i++ ) {
+    int iCol = ubs.getIndices()[i];
+    double value = ubs.getElements()[i];
+    if ( value < upper[iCol] )
+      modelPtr_->solver()->setColUpper(iCol, value);
+  }
+}
+/* Read an mps file from the given filename (defaults to Osi reader) - returns
+   number of errors (see OsiMpsReader class) */
+int 
+OsiCbcSolverInterface::readMps(const char *filename,
+			       const char *extension ) 
+{
+  return modelPtr_->solver()->readMps(filename,extension);
+}
+// Get pointer to array[getNumCols()] of primal solution vector
+const double * 
+OsiCbcSolverInterface::getColSolution() const 
+{ 
+  return modelPtr_->solver()->getColSolution();
+}
+  
+// Get pointer to array[getNumRows()] of dual prices
+const double * 
+OsiCbcSolverInterface::getRowPrice() const
+{ 
+  return modelPtr_->solver()->getRowPrice();
+}
+  
+// Get a pointer to array[getNumCols()] of reduced costs
+const double * 
+OsiCbcSolverInterface::getReducedCost() const 
+{ 
+  return modelPtr_->solver()->getReducedCost();
+}
+
+/* Get pointer to array[getNumRows()] of row activity levels (constraint
+   matrix times the solution vector */
+const double * 
+OsiCbcSolverInterface::getRowActivity() const 
+{ 
+  return modelPtr_->solver()->getRowActivity();
+}
+double 
+OsiCbcSolverInterface::getObjValue() const 
+{
+  return modelPtr_->solver()->getObjValue();
+}
+
+/* Set an objective function coefficient */
+void 
+OsiCbcSolverInterface::setObjCoeff( int elementIndex, double elementValue )
+{
+  modelPtr_->solver()->setObjCoeff(elementIndex,elementValue);
+}
+
+/* Set a single column lower bound<br>
+   Use -DBL_MAX for -infinity. */
+void 
+OsiCbcSolverInterface::setColLower( int elementIndex, double elementValue )
+{
+  modelPtr_->solver()->setColLower(elementIndex,elementValue);
+}
+      
+/* Set a single column upper bound<br>
+   Use DBL_MAX for infinity. */
+void 
+OsiCbcSolverInterface::setColUpper( int elementIndex, double elementValue )
+{
+  modelPtr_->solver()->setColUpper(elementIndex,elementValue);
+}
+
+/* Set a single column lower and upper bound */
+void 
+OsiCbcSolverInterface::setColBounds( int elementIndex,
+				     double lower, double upper )
+{
+  modelPtr_->solver()->setColBounds(elementIndex,lower,upper);
+}
+void OsiCbcSolverInterface::setColSetBounds(const int* indexFirst,
+					    const int* indexLast,
+					    const double* boundList)
+{
+  modelPtr_->solver()->setColSetBounds(indexFirst,indexLast,boundList);
+}
+//------------------------------------------------------------------
+/* Set a single row lower bound<br>
+   Use -DBL_MAX for -infinity. */
+void 
+OsiCbcSolverInterface::setRowLower( int elementIndex, double elementValue ) {
+  modelPtr_->solver()->setRowLower(elementIndex,elementValue);
+}
+      
+/* Set a single row upper bound<br>
+   Use DBL_MAX for infinity. */
+void 
+OsiCbcSolverInterface::setRowUpper( int elementIndex, double elementValue ) {
+  modelPtr_->solver()->setRowUpper(elementIndex,elementValue);
+}
+    
+/* Set a single row lower and upper bound */
+void 
+OsiCbcSolverInterface::setRowBounds( int elementIndex,
+	      double lower, double upper ) {
+  modelPtr_->solver()->setRowBounds(elementIndex,lower,upper);
+}
+//-----------------------------------------------------------------------------
+void
+OsiCbcSolverInterface::setRowType(int i, char sense, double rightHandSide,
+				  double range)
+{
+  modelPtr_->solver()->setRowType(i,sense,rightHandSide,range);
+}
+//-----------------------------------------------------------------------------
+void OsiCbcSolverInterface::setRowSetBounds(const int* indexFirst,
+					    const int* indexLast,
+					    const double* boundList)
+{
+  modelPtr_->solver()->setRowSetBounds(indexFirst,indexLast,boundList);
+}
+//-----------------------------------------------------------------------------
+void
+OsiCbcSolverInterface::setRowSetTypes(const int* indexFirst,
+				      const int* indexLast,
+				      const char* senseList,
+				      const double* rhsList,
+				      const double* rangeList)
+{
+  modelPtr_->solver()->setRowSetTypes(indexFirst,indexLast,senseList,rhsList,rangeList);
+}
+// Set a hint parameter
+bool 
+OsiCbcSolverInterface::setHintParam(OsiHintParam key, bool yesNo,
+                                    OsiHintStrength strength,
+                                    void * otherInformation) 
+{
+  return modelPtr_->solver()->setHintParam(key,yesNo, strength, otherInformation);
+}
+
+// Get a hint parameter
+bool 
+OsiCbcSolverInterface::getHintParam(OsiHintParam key, bool & yesNo,
+                                    OsiHintStrength & strength,
+                                    void *& otherInformation) const
+{
+  return modelPtr_->solver()->getHintParam(key,yesNo, strength, otherInformation);
+}
+
+// Get a hint parameter
+bool 
+OsiCbcSolverInterface::getHintParam(OsiHintParam key, bool & yesNo,
+                                    OsiHintStrength & strength) const
+{
+  return modelPtr_->solver()->getHintParam(key,yesNo, strength);
+}
+
+
+int 
+OsiCbcSolverInterface::getNumCols() const
+{
+  return modelPtr_->solver()->getNumCols();
+}
+int 
+OsiCbcSolverInterface::getNumRows() const
+{
+  return modelPtr_->solver()->getNumRows();
+}
+int 
+OsiCbcSolverInterface::getNumElements() const
+{
+  return modelPtr_->solver()->getNumElements();
+}
+const double * 
+OsiCbcSolverInterface::getColLower() const
+{
+  return modelPtr_->solver()->getColLower();
+}
+const double * 
+OsiCbcSolverInterface::getColUpper() const
+{
+  return modelPtr_->solver()->getColUpper();
+}
+const double * 
+OsiCbcSolverInterface::getRowLower() const
+{
+  return modelPtr_->solver()->getRowLower();
+}
+const double * 
+OsiCbcSolverInterface::getRowUpper() const
+{
+  return modelPtr_->solver()->getRowUpper();
+}
+const double * 
+OsiCbcSolverInterface::getObjCoefficients() const 
+{
+  return modelPtr_->solver()->getObjCoefficients();
+}
+double 
+OsiCbcSolverInterface::getObjSense() const 
+{
+  return modelPtr_->solver()->getObjSense();
+}
+double 
+OsiCbcSolverInterface::getInfinity() const
+{
+  return modelPtr_->solver()->getInfinity();
+}
+int 
+OsiCbcSolverInterface::getIterationCount() const 
+{
+  return modelPtr_->solver()->getIterationCount();
+}
+void 
+OsiCbcSolverInterface::setObjSense(double s )
+{
+  modelPtr_->setObjSense(s);
+}
+// Invoke solver's built-in enumeration algorithm
+void 
+OsiCbcSolverInterface::branchAndBound()
+{
+  *messageHandler() << "Warning: Use of OsiCbc is deprecated." << CoinMessageEol;
+  *messageHandler() << "To enjoy the full performance of Cbc, use the CbcSolver interface." << CoinMessageEol;
+  modelPtr_->branchAndBound();
+}
+
+/*
+  Name discipline support   -- lh, 070328 --
+
+  For safety, there's really nothing to it but to pass each call of an impure
+  virtual method on to the underlying solver. Otherwise we just can't know if
+  it's been overridden or not.
+*/
+
+std::string
+OsiCbcSolverInterface::dfltRowColName (char rc, int ndx, unsigned digits) const
+{
+  return (modelPtr_->solver()->dfltRowColName(rc,ndx,digits)) ;
+}
+
+std::string OsiCbcSolverInterface::getObjName (unsigned maxLen) const
+{
+  return (modelPtr_->solver()->getObjName(maxLen)) ;
+}
+
+std::string OsiCbcSolverInterface::getRowName (int ndx, unsigned maxLen) const
+{
+  return (modelPtr_->solver()->getRowName(ndx,maxLen)) ;
+}
+
+const OsiSolverInterface::OsiNameVec &OsiCbcSolverInterface::getRowNames ()
+{
+  return (modelPtr_->solver()->getRowNames()) ;
+}
+
+std::string OsiCbcSolverInterface::getColName (int ndx, unsigned maxLen) const
+{
+  return (modelPtr_->solver()->getColName(ndx,maxLen)) ;
+}
+
+const OsiSolverInterface::OsiNameVec &OsiCbcSolverInterface::getColNames ()
+{
+  return (modelPtr_->solver()->getColNames()) ;
+}
+
+void OsiCbcSolverInterface::setRowNames (OsiNameVec &srcNames,
+					 int srcStart, int len, int tgtStart)
+{
+  modelPtr_->solver()->setRowNames(srcNames,srcStart,len,tgtStart) ;
+}
+
+void OsiCbcSolverInterface::deleteRowNames (int tgtStart, int len)
+{
+  modelPtr_->solver()->deleteRowNames(tgtStart,len) ;
+}
+
+void OsiCbcSolverInterface::setColNames (OsiNameVec &srcNames,
+					 int srcStart, int len, int tgtStart)
+{
+  modelPtr_->solver()->setColNames(srcNames,srcStart,len,tgtStart) ;
+}
+
+void OsiCbcSolverInterface::deleteColNames (int tgtStart, int len)
+{
+  modelPtr_->solver()->deleteColNames(tgtStart,len) ;
+}
+
+/*
+  These last three are the only functions that would normally be overridden.
+*/
+
+/*
+  Set objective function name.
+*/
+void OsiCbcSolverInterface::setObjName (std::string name)
+{
+  modelPtr_->solver()->setObjName(name) ;
+}
+
+/*
+  Set a row name, to make sure both the solver and OSI see the same name.
+*/
+void OsiCbcSolverInterface::setRowName (int ndx, std::string name)
+
+{ 
+  modelPtr_->solver()->setRowName(ndx,name) ;
+}
+
+/*
+  Set a column name, to make sure both the solver and OSI see the same name.
+*/
+void OsiCbcSolverInterface::setColName (int ndx, std::string name)
+
+{ 
+  modelPtr_->solver()->setColName(ndx,name) ;
+}
+// Pass in Message handler (not deleted at end)
+void 
+OsiCbcSolverInterface::passInMessageHandler(CoinMessageHandler * handler)
+{
+  OsiSolverInterface::passInMessageHandler(handler);
+  if (modelPtr_)
+    modelPtr_->passInMessageHandler(handler);
+}
+// So unit test can find out if NDEBUG set
+bool OsiCbcHasNDEBUG() 
+{
+#ifdef NDEBUG
+  return true;
+#else
+  return false;
+#endif
+}
diff --git a/cbits/coin/OsiCbcSolverInterface.hpp b/cbits/coin/OsiCbcSolverInterface.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiCbcSolverInterface.hpp
@@ -0,0 +1,764 @@
+// $Id: OsiCbcSolverInterface.hpp 1902 2013-04-10 16:58:16Z stefan $
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiCbcSolverInterface_H
+#define OsiCbcSolverInterface_H
+
+#include <string>
+#include <cfloat>
+#include <map>
+#include "CbcModel.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "OsiSolverInterface.hpp"
+#include "CbcStrategy.hpp"
+#include "CoinWarmStartBasis.hpp"
+
+class OsiRowCut;
+class OsiClpSolverInterface;
+static const double OsiCbcInfinity = COIN_DBL_MAX;
+
+//#############################################################################
+
+/** Cbc Solver Interface
+    
+Instantiation of OsiCbcSolverInterface for the Model Algorithm.
+
+*/
+
+class OsiCbcSolverInterface :
+  virtual public OsiSolverInterface {
+  friend void OsiCbcSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir);
+  
+public:
+  //---------------------------------------------------------------------------
+  /**@name Solve methods */
+  //@{
+  /// Solve initial LP relaxation 
+  virtual void initialSolve();
+  
+  /// Resolve an LP relaxation after problem modification
+  virtual void resolve();
+  
+  /// Invoke solver's built-in enumeration algorithm
+  virtual void branchAndBound();
+  //@}
+  
+  //---------------------------------------------------------------------------
+  /**@name Parameter set/get methods
+     
+  The set methods return true if the parameter was set to the given value,
+  false otherwise. There can be various reasons for failure: the given
+  parameter is not applicable for the solver (e.g., refactorization
+  frequency for the cbc algorithm), the parameter is not yet implemented
+  for the solver or simply the value of the parameter is out of the range
+  the solver accepts. If a parameter setting call returns false check the
+  details of your solver.
+  
+  The get methods return true if the given parameter is applicable for the
+  solver and is implemented. In this case the value of the parameter is
+  returned in the second argument. Otherwise they return false.
+  */
+  //@{
+  // Set an integer parameter
+  bool setIntParam(OsiIntParam key, int value);
+  // Set an double parameter
+  bool setDblParam(OsiDblParam key, double value);
+  // Set a string parameter
+  bool setStrParam(OsiStrParam key, const std::string & value);
+  // Get an integer parameter
+  bool getIntParam(OsiIntParam key, int& value) const;
+  // Get an double parameter
+  bool getDblParam(OsiDblParam key, double& value) const;
+  // Get a string parameter
+  bool getStrParam(OsiStrParam key, std::string& value) const;
+  // Set a hint parameter - overrides OsiSolverInterface
+  virtual bool setHintParam(OsiHintParam key, bool yesNo=true,
+                            OsiHintStrength strength=OsiHintTry,
+                            void * otherInformation=NULL);
+  /// Get a hint parameter
+    virtual bool getHintParam(OsiHintParam key, bool& yesNo,
+			      OsiHintStrength& strength,
+			      void *& otherInformation) const;
+
+  using OsiSolverInterface::getHintParam ;
+  /// Get a hint parameter
+    virtual bool getHintParam(OsiHintParam key, bool& yesNo,
+			      OsiHintStrength& strength) const;
+  //@}
+  
+  //---------------------------------------------------------------------------
+  ///@name Methods returning info on how the solution process terminated
+  //@{
+  /// Are there a numerical difficulties?
+  virtual bool isAbandoned() const;
+  /// Is optimality proven?
+  virtual bool isProvenOptimal() const;
+  /// Is primal infeasiblity proven?
+  virtual bool isProvenPrimalInfeasible() const;
+  /// Is dual infeasiblity proven?
+  virtual bool isProvenDualInfeasible() const;
+  /// Is the given primal objective limit reached?
+  virtual bool isPrimalObjectiveLimitReached() const;
+  /// Is the given dual objective limit reached?
+  virtual bool isDualObjectiveLimitReached() const;
+  /// Iteration limit reached?
+  virtual bool isIterationLimitReached() const;
+  //@}
+  
+  //---------------------------------------------------------------------------
+  /**@name WarmStart related methods */
+  //@{
+  
+  /*! \brief Get an empty warm start object
+    
+  This routine returns an empty CoinWarmStartBasis object. Its purpose is
+  to provide a way to give a client a warm start basis object of the
+  appropriate type, which can resized and modified as desired.
+  */
+  
+  virtual CoinWarmStart *getEmptyWarmStart () const;
+  
+  /// Get warmstarting information
+  virtual CoinWarmStart* getWarmStart() const;
+  /** Set warmstarting information. Return true/false depending on whether
+      the warmstart information was accepted or not. */
+  virtual bool setWarmStart(const CoinWarmStart* warmstart);
+  //@}
+  
+  //---------------------------------------------------------------------------
+  /**@name Hotstart related methods (primarily used in strong branching). <br>
+     The user can create a hotstart (a snapshot) of the optimization process
+     then reoptimize over and over again always starting from there.<br>
+     <strong>NOTE</strong>: between hotstarted optimizations only
+     bound changes are allowed. */
+  //@{
+  /// Create a hotstart point of the optimization process
+  virtual void markHotStart();
+  /// Optimize starting from the hotstart
+  virtual void solveFromHotStart();
+  /// Delete the snapshot
+  virtual void unmarkHotStart();
+  //@}
+  
+  //---------------------------------------------------------------------------
+  /**@name Problem information methods
+     
+  These methods call the solver's query routines to return
+  information about the problem referred to by the current object.
+  Querying a problem that has no data associated with it result in
+  zeros for the number of rows and columns, and NULL pointers from
+  the methods that return vectors.
+  
+  Const pointers returned from any data-query method are valid as
+  long as the data is unchanged and the solver is not called.
+  */
+  //@{
+  /**@name Methods related to querying the input data */
+  //@{
+  /// Get number of columns
+  virtual int getNumCols() const;
+  
+  /// Get number of rows
+  virtual int getNumRows() const;
+  
+  /// Get number of nonzero elements
+  virtual int getNumElements() const ;
+  
+  /// Get pointer to array[getNumCols()] of column lower bounds
+  virtual const double * getColLower() const;
+  
+  /// Get pointer to array[getNumCols()] of column upper bounds
+  virtual const double * getColUpper() const;
+  
+  /** Get pointer to array[getNumRows()] of row constraint senses.
+      <ul>
+      <li>'L' <= constraint
+      <li>'E' =  constraint
+      <li>'G' >= constraint
+      <li>'R' ranged constraint
+      <li>'N' free constraint
+      </ul>
+  */
+  virtual const char * getRowSense() const;
+  
+  /** Get pointer to array[getNumRows()] of rows right-hand sides
+      <ul>
+      <li> if rowsense()[i] == 'L' then rhs()[i] == rowupper()[i]
+      <li> if rowsense()[i] == 'G' then rhs()[i] == rowlower()[i]
+      <li> if rowsense()[i] == 'R' then rhs()[i] == rowupper()[i]
+      <li> if rowsense()[i] == 'N' then rhs()[i] == 0.0
+      </ul>
+  */
+  virtual const double * getRightHandSide() const ;
+  
+  /** Get pointer to array[getNumRows()] of row ranges.
+      <ul>
+      <li> if rowsense()[i] == 'R' then
+      rowrange()[i] == rowupper()[i] - rowlower()[i]
+      <li> if rowsense()[i] != 'R' then
+      rowrange()[i] is undefined
+      </ul>
+  */
+  virtual const double * getRowRange() const ;
+  
+  /// Get pointer to array[getNumRows()] of row lower bounds
+  virtual const double * getRowLower() const ;
+  
+  /// Get pointer to array[getNumRows()] of row upper bounds
+  virtual const double * getRowUpper() const ;
+  
+  /// Get pointer to array[getNumCols()] of objective function coefficients
+  virtual const double * getObjCoefficients() const; 
+  
+  /// Get objective function sense (1 for min (default), -1 for max)
+  virtual double getObjSense() const ;
+  
+  /// Return true if column is continuous
+  virtual bool isContinuous(int colNumber) const;
+  
+  
+  /// Get pointer to row-wise copy of matrix
+  virtual const CoinPackedMatrix * getMatrixByRow() const;
+  
+  /// Get pointer to column-wise copy of matrix
+  virtual const CoinPackedMatrix * getMatrixByCol() const;
+  
+  /// Get solver's value for infinity
+  virtual double getInfinity() const;
+  //@}
+  
+  /**@name Methods related to querying the solution */
+  //@{
+  /// Get pointer to array[getNumCols()] of primal solution vector
+  virtual const double * getColSolution() const; 
+  
+  /// Get pointer to array[getNumRows()] of dual prices
+  virtual const double * getRowPrice() const;
+  
+  /// Get a pointer to array[getNumCols()] of reduced costs
+  virtual const double * getReducedCost() const; 
+  
+  /** Get pointer to array[getNumRows()] of row activity levels (constraint
+      matrix times the solution vector */
+  virtual const double * getRowActivity() const; 
+  
+  /// Get objective function value
+  virtual double getObjValue() const;
+  
+  /** Get how many iterations it took to solve the problem (whatever
+      "iteration" mean to the solver. */
+  virtual int getIterationCount() const ;
+  
+  /** Get as many dual rays as the solver can provide. (In case of proven
+      primal infeasibility there should be at least one.)
+
+      The first getNumRows() ray components will always be associated with
+      the row duals (as returned by getRowPrice()). If \c fullRay is true,
+      the final getNumCols() entries will correspond to the ray components
+      associated with the nonbasic variables. If the full ray is requested
+      and the method cannot provide it, it will throw an exception.
+
+      <strong>NOTE for implementers of solver interfaces:</strong> <br>
+      The double pointers in the vector should point to arrays of length
+      getNumRows() and they should be allocated via new[]. <br>
+      
+      <strong>NOTE for users of solver interfaces:</strong> <br>
+      It is the user's responsibility to free the double pointers in the
+      vector using delete[].
+  */
+  virtual std::vector<double*> getDualRays(int maxNumRays,
+					   bool fullRay = false) const;
+  /** Get as many primal rays as the solver can provide. (In case of proven
+      dual infeasibility there should be at least one.)
+      
+      <strong>NOTE for implementers of solver interfaces:</strong> <br>
+      The double pointers in the vector should point to arrays of length
+      getNumCols() and they should be allocated via new[]. <br>
+      
+      <strong>NOTE for users of solver interfaces:</strong> <br>
+      It is the user's responsibility to free the double pointers in the
+      vector using delete[].
+  */
+  virtual std::vector<double*> getPrimalRays(int maxNumRays) const;
+  
+  //@}
+
+  /*! \name Methods for row and column names.
+
+    Because OsiCbc is a pass-through class, it's necessary to override any
+    virtual method in order to be sure we catch an override by the underlying
+    solver. See the OsiSolverInterface class documentation for detailed
+    descriptions.
+  */
+  //@{
+
+    /*! \brief Generate a standard name of the form Rnnnnnnn or Cnnnnnnn */
+
+    virtual std::string dfltRowColName(char rc,
+				 int ndx, unsigned digits = 7) const ;
+
+    /*! \brief Return the name of the objective function */
+
+    virtual std::string getObjName (unsigned maxLen = std::string::npos) const ;
+
+    /*! \brief Set the name of the objective function */
+
+    virtual void setObjName (std::string name) ;
+
+    /*! \brief Return the name of the row.  */
+
+    virtual std::string getRowName(int rowIndex,
+				   unsigned maxLen = std::string::npos) const ;
+
+    /*! \brief Return a pointer to a vector of row names */
+
+    virtual const OsiNameVec &getRowNames() ;
+
+    /*! \brief Set a row name */
+
+    virtual void setRowName(int ndx, std::string name) ;
+
+    /*! \brief Set multiple row names */
+
+    virtual void setRowNames(OsiNameVec &srcNames,
+		     int srcStart, int len, int tgtStart) ;
+
+    /*! \brief Delete len row names starting at index tgtStart */
+
+    virtual void deleteRowNames(int tgtStart, int len) ;
+  
+    /*! \brief Return the name of the column */
+
+    virtual std::string getColName(int colIndex,
+				   unsigned maxLen = std::string::npos) const ;
+
+    /*! \brief Return a pointer to a vector of column names */
+
+    virtual const OsiNameVec &getColNames() ;
+
+    /*! \brief Set a column name */
+
+    virtual void setColName(int ndx, std::string name) ;
+
+    /*! \brief Set multiple column names */
+
+    virtual void setColNames(OsiNameVec &srcNames,
+		     int srcStart, int len, int tgtStart) ;
+
+    /*! \brief Delete len column names starting at index tgtStart */
+    virtual void deleteColNames(int tgtStart, int len) ;
+
+  //@}
+
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+  /**@name Problem modifying methods */
+  //@{
+  //-------------------------------------------------------------------------
+  /**@name Changing bounds on variables and constraints */
+  //@{
+  /** Set an objective function coefficient */
+  virtual void setObjCoeff( int elementIndex, double elementValue );
+
+  using OsiSolverInterface::setColLower ;
+  /** Set a single column lower bound<br>
+      Use -DBL_MAX for -infinity. */
+  virtual void setColLower( int elementIndex, double elementValue );
+  
+  using OsiSolverInterface::setColUpper ;
+  /** Set a single column upper bound<br>
+      Use DBL_MAX for infinity. */
+  virtual void setColUpper( int elementIndex, double elementValue );
+  
+  /** Set a single column lower and upper bound */
+  virtual void setColBounds( int elementIndex,
+                             double lower, double upper );
+  
+  /** Set the bounds on a number of columns simultaneously<br>
+      The default implementation just invokes setColLower() and
+      setColUpper() over and over again.
+      @param indexFirst,indexLast pointers to the beginning and after the
+      end of the array of the indices of the variables whose
+      <em>either</em> bound changes
+      @param boundList the new lower/upper bound pairs for the variables
+  */
+  virtual void setColSetBounds(const int* indexFirst,
+                               const int* indexLast,
+                               const double* boundList);
+  
+  /** Set a single row lower bound<br>
+      Use -DBL_MAX for -infinity. */
+  virtual void setRowLower( int elementIndex, double elementValue );
+  
+  /** Set a single row upper bound<br>
+      Use DBL_MAX for infinity. */
+  virtual void setRowUpper( int elementIndex, double elementValue ) ;
+  
+  /** Set a single row lower and upper bound */
+  virtual void setRowBounds( int elementIndex,
+                             double lower, double upper ) ;
+  
+  /** Set the type of a single row<br> */
+  virtual void setRowType(int index, char sense, double rightHandSide,
+                          double range);
+  
+  /** Set the bounds on a number of rows simultaneously<br>
+      The default implementation just invokes setRowLower() and
+      setRowUpper() over and over again.
+      @param indexFirst,indexLast pointers to the beginning and after the
+      end of the array of the indices of the constraints whose
+      <em>either</em> bound changes
+      @param boundList the new lower/upper bound pairs for the constraints
+  */
+  virtual void setRowSetBounds(const int* indexFirst,
+                               const int* indexLast,
+                               const double* boundList);
+  
+  /** Set the type of a number of rows simultaneously<br>
+      The default implementation just invokes setRowType()
+      over and over again.
+      @param indexFirst,indexLast pointers to the beginning and after the
+      end of the array of the indices of the constraints whose
+      <em>any</em> characteristics changes
+      @param senseList the new senses
+      @param rhsList   the new right hand sides
+      @param rangeList the new ranges
+  */
+  virtual void setRowSetTypes(const int* indexFirst,
+                              const int* indexLast,
+                              const char* senseList,
+                              const double* rhsList,
+                              const double* rangeList);
+  //@}
+  
+  //-------------------------------------------------------------------------
+  /**@name Integrality related changing methods */
+  //@{
+  /** Set the index-th variable to be a continuous variable */
+  virtual void setContinuous(int index);
+  /** Set the index-th variable to be an integer variable */
+  virtual void setInteger(int index);
+  /** Set the variables listed in indices (which is of length len) to be
+      continuous variables */
+  virtual void setContinuous(const int* indices, int len);
+  /** Set the variables listed in indices (which is of length len) to be
+      integer variables */
+  virtual void setInteger(const int* indices, int len);
+  //@}
+  
+  //-------------------------------------------------------------------------
+  /// Set objective function sense (1 for min (default), -1 for max,)
+  virtual void setObjSense(double s ); 
+  
+  /** Set the primal solution column values
+      
+  colsol[numcols()] is an array of values of the problem column
+  variables. These values are copied to memory owned by the
+  solver object or the solver.  They will be returned as the
+  result of colsol() until changed by another call to
+  setColsol() or by a call to any solver routine.  Whether the
+  solver makes use of the solution in any way is
+  solver-dependent. 
+  */
+  virtual void setColSolution(const double * colsol);
+  
+  /** Set dual solution vector
+      
+  rowprice[numrows()] is an array of values of the problem row
+  dual variables. These values are copied to memory owned by the
+  solver object or the solver.  They will be returned as the
+  result of rowprice() until changed by another call to
+  setRowprice() or by a call to any solver routine.  Whether the
+  solver makes use of the solution in any way is
+  solver-dependent. 
+  */
+  virtual void setRowPrice(const double * rowprice);
+  
+  //-------------------------------------------------------------------------
+  /**@name Methods to expand a problem.<br>
+     Note that if a column is added then by default it will correspond to a
+     continuous variable. */
+  //@{
+  using OsiSolverInterface::addCol ;
+  /** */
+  virtual void addCol(const CoinPackedVectorBase& vec,
+                      const double collb, const double colub,   
+                      const double obj);
+  /** Add a column (primal variable) to the problem. */
+  virtual void addCol(int numberElements, const int * rows, const double * elements,
+                      const double collb, const double colub,   
+                      const double obj) ;
+
+  using OsiSolverInterface::addCols ;
+  /** */
+  virtual void addCols(const int numcols,
+                       const CoinPackedVectorBase * const * cols,
+                       const double* collb, const double* colub,   
+                       const double* obj);
+  /** */
+  virtual void deleteCols(const int num, const int * colIndices);
+  
+  using OsiSolverInterface::addRow ;
+  /** */
+  virtual void addRow(const CoinPackedVectorBase& vec,
+                      const double rowlb, const double rowub);
+  /** */
+  virtual void addRow(const CoinPackedVectorBase& vec,
+                      const char rowsen, const double rowrhs,   
+                      const double rowrng);
+
+  using OsiSolverInterface::addRows ;
+  /** */
+  virtual void addRows(const int numrows,
+                       const CoinPackedVectorBase * const * rows,
+                       const double* rowlb, const double* rowub);
+  /** */
+  virtual void addRows(const int numrows,
+                       const CoinPackedVectorBase * const * rows,
+                       const char* rowsen, const double* rowrhs,   
+                       const double* rowrng);
+  /** */
+  virtual void deleteRows(const int num, const int * rowIndices);
+  
+  //-----------------------------------------------------------------------
+  /** Apply a collection of row cuts which are all effective.
+      applyCuts seems to do one at a time which seems inefficient.
+  */
+  virtual void applyRowCuts(int numberCuts, const OsiRowCut * cuts);
+  /** Apply a collection of row cuts which are all effective.
+      applyCuts seems to do one at a time which seems inefficient.
+      This uses array of pointers
+  */
+  virtual void applyRowCuts(int numberCuts, const OsiRowCut ** cuts);
+  //@}
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+public:
+  
+  /**@name Methods to input a problem */
+  //@{
+  /** Load in an problem by copying the arguments (the constraints on the
+      rows are given by lower and upper bounds). If a pointer is 0 then the
+      following values are the default:
+      <ul>
+      <li> <code>colub</code>: all columns have upper bound infinity
+      <li> <code>collb</code>: all columns have lower bound 0 
+      <li> <code>rowub</code>: all rows have upper bound infinity
+      <li> <code>rowlb</code>: all rows have lower bound -infinity
+      <li> <code>obj</code>: all variables have 0 objective coefficient
+      </ul>
+  */
+  virtual void loadProblem(const CoinPackedMatrix& matrix,
+                           const double* collb, const double* colub,   
+                           const double* obj,
+                           const double* rowlb, const double* rowub);
+  
+  /** Load in an problem by assuming ownership of the arguments (the
+      constraints on the rows are given by lower and upper bounds). For
+      default values see the previous method.  <br>
+      <strong>WARNING</strong>: The arguments passed to this method will be
+      freed using the C++ <code>delete</code> and <code>delete[]</code>
+      functions. 
+  */
+  virtual void assignProblem(CoinPackedMatrix*& matrix,
+    			     double*& collb, double*& colub, double*& obj,
+    			     double*& rowlb, double*& rowub);
+  
+  /** Load in an problem by copying the arguments (the constraints on the
+      rows are given by sense/rhs/range triplets). If a pointer is 0 then the
+      following values are the default:
+      <ul>
+      <li> <code>colub</code>: all columns have upper bound infinity
+      <li> <code>collb</code>: all columns have lower bound 0 
+      <li> <code>obj</code>: all variables have 0 objective coefficient
+      <li> <code>rowsen</code>: all rows are >=
+      <li> <code>rowrhs</code>: all right hand sides are 0
+      <li> <code>rowrng</code>: 0 for the ranged rows
+      </ul>
+  */
+  virtual void loadProblem(const CoinPackedMatrix& matrix,
+    			   const double* collb, const double* colub,
+    			   const double* obj,
+    			   const char* rowsen, const double* rowrhs,   
+    			   const double* rowrng);
+  
+  /** Load in an problem by assuming ownership of the arguments (the
+      constraints on the rows are given by sense/rhs/range triplets). For
+      default values see the previous method. <br>
+      <strong>WARNING</strong>: The arguments passed to this method will be
+      freed using the C++ <code>delete</code> and <code>delete[]</code>
+      functions. 
+  */
+  virtual void assignProblem(CoinPackedMatrix*& matrix,
+    			     double*& collb, double*& colub, double*& obj,
+    			     char*& rowsen, double*& rowrhs,
+    			     double*& rowrng);
+  
+  /** Just like the other loadProblem() methods except that the matrix is
+      given in a standard column major ordered format (without gaps). */
+  virtual void loadProblem(const int numcols, const int numrows,
+                           const CoinBigIndex * start, const int* index,
+                           const double* value,
+                           const double* collb, const double* colub,   
+                           const double* obj,
+                           const double* rowlb, const double* rowub);
+  
+  /** Just like the other loadProblem() methods except that the matrix is
+      given in a standard column major ordered format (without gaps). */
+  virtual void loadProblem(const int numcols, const int numrows,
+                           const CoinBigIndex * start, const int* index,
+                           const double* value,
+                           const double* collb, const double* colub,   
+                           const double* obj,
+                           const char* rowsen, const double* rowrhs,   
+                           const double* rowrng);
+
+  using OsiSolverInterface::readMps ;
+  /** Read an mps file from the given filename (defaults to Osi reader) - returns
+      number of errors (see OsiMpsReader class) */
+  virtual int readMps(const char *filename,
+                      const char *extension = "mps") ;
+  
+  /** Write the problem into an mps file of the given filename.
+      If objSense is non zero then -1.0 forces the code to write a
+      maximization objective and +1.0 to write a minimization one.
+      If 0.0 then solver can do what it wants */
+  virtual void writeMps(const char *filename,
+                        const char *extension = "mps",
+                        double objSense=0.0) const;
+  /** Write the problem into an mps file of the given filename,
+      names may be null.  formatType is
+      0 - normal
+      1 - extra accuracy 
+      2 - IEEE hex (later)
+      
+      Returns non-zero on I/O error
+  */
+  virtual int writeMpsNative(const char *filename, 
+                             const char ** rowNames, const char ** columnNames,
+                             int formatType=0,int numberAcross=2,
+                             double objSense=0.0) const ;
+  //@}
+  
+  /**@name Message handling (extra for Cbc messages).
+     Normally I presume you would want the same language.
+     If not then you could use underlying model pointer */
+  //@{
+  /// Set language
+  void newLanguage(CoinMessages::Language language);
+  void setLanguage(CoinMessages::Language language)
+  {newLanguage(language);}
+  //@}
+  //---------------------------------------------------------------------------
+  
+  /**@name Cbc specific public interfaces */
+  //@{
+  /// Get pointer to Cbc model
+  inline CbcModel * getModelPtr() const 
+  { return modelPtr_;}
+  /// Get pointer to underlying solver
+  inline OsiSolverInterface * getRealSolverPtr() const 
+  { return modelPtr_->solver();}
+  /// Set cutoff bound on the objective function.
+  inline void setCutoff(double value) 
+  { modelPtr_->setCutoff(value);}
+  /// Get the cutoff bound on the objective function - always as minimize
+  inline double getCutoff() const
+  { return modelPtr_->getCutoff();}
+  /// Set the CbcModel::CbcMaxNumNode maximum node limit 
+  inline void setMaximumNodes( int value)
+  { modelPtr_->setMaximumNodes(value);}
+  /// Get the CbcModel::CbcMaxNumNode maximum node limit
+  inline int getMaximumNodes() const
+  { return modelPtr_->getMaximumNodes();}
+  /// Set the CbcModel::CbcMaxNumSol maximum number of solutions
+  inline void setMaximumSolutions( int value) 
+  { modelPtr_->setMaximumSolutions(value);}
+  /// Get the CbcModel::CbcMaxNumSol maximum number of solutions 
+  inline int getMaximumSolutions() const 
+  { return modelPtr_->getMaximumSolutions();}
+  /// Set the CbcModel::CbcMaximumSeconds maximum number of seconds 
+  inline void setMaximumSeconds( double value) 
+  { modelPtr_->setMaximumSeconds(value);}
+  /// Get the CbcModel::CbcMaximumSeconds maximum number of seconds 
+  inline double getMaximumSeconds() const 
+  { return modelPtr_->getMaximumSeconds();}
+  /// Node limit reached?
+  inline bool isNodeLimitReached() const
+  { return modelPtr_->isNodeLimitReached();}
+  /// Solution limit reached?
+  inline bool isSolutionLimitReached() const
+  { return modelPtr_->isSolutionLimitReached();}
+  /// Get how many Nodes it took to solve the problem.
+  inline int getNodeCount() const
+  { return modelPtr_->getNodeCount();}
+    /// Final status of problem - 0 finished, 1 stopped, 2 difficulties
+    inline int status() const
+  { return modelPtr_->status();}
+  /** Pass in a message handler
+  
+    It is the client's responsibility to destroy a message handler installed
+    by this routine; it will not be destroyed when the solver interface is
+    destroyed. 
+  */
+  virtual void passInMessageHandler(CoinMessageHandler * handler);
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+  /**@name Constructors and destructors */
+  //@{
+  /// Default Constructor
+  OsiCbcSolverInterface (OsiSolverInterface * solver=NULL,
+                         CbcStrategy * strategy=NULL);
+  
+  /// Clone
+  virtual OsiSolverInterface * clone(bool copyData = true) const;
+  
+  /// Copy constructor 
+  OsiCbcSolverInterface (const OsiCbcSolverInterface &);
+#if 0    
+  /// Borrow constructor - only delete one copy
+  OsiCbcSolverInterface (CbcModel * rhs, bool reallyOwn=false);
+  
+  /// Releases so won't error
+  void releaseCbc();
+#endif    
+  /// Assignment operator 
+  OsiCbcSolverInterface & operator=(const OsiCbcSolverInterface& rhs);
+  
+  /// Destructor 
+  virtual ~OsiCbcSolverInterface ();
+  
+  //@}
+  //---------------------------------------------------------------------------
+  
+protected:
+  ///@name Protected methods
+  //@{
+  /** Apply a row cut (append to constraint matrix). */
+  virtual void applyRowCut(const OsiRowCut& rc);
+  
+  /** Apply a column cut (adjust one or more bounds). */
+  virtual void applyColCut(const OsiColCut& cc);
+  //@}
+  /**@name Protected member data */
+  //@{
+  /// Cbc model represented by this class instance
+  mutable CbcModel * modelPtr_;
+  //@}
+};
+// So unit test can find out if NDEBUG set
+bool OsiCbcHasNDEBUG();
+
+//#############################################################################
+/** A function that tests the methods in the OsiCbcSolverInterface class. */
+void OsiCbcSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir);
+
+#endif
diff --git a/cbits/coin/OsiChooseVariable.cpp b/cbits/coin/OsiChooseVariable.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiChooseVariable.cpp
@@ -0,0 +1,1245 @@
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <string>
+#include <cassert>
+#include <cfloat>
+#include <cmath>
+#include "CoinPragma.hpp"
+#include "OsiSolverInterface.hpp"
+#include "OsiAuxInfo.hpp"
+#include "OsiSolverBranch.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinTime.hpp"
+#include "CoinSort.hpp"
+#include "CoinFinite.hpp"
+#include "OsiChooseVariable.hpp"
+using namespace std;
+
+OsiChooseVariable::OsiChooseVariable() :
+  goodObjectiveValue_(COIN_DBL_MAX),
+  upChange_(0.0),
+  downChange_(0.0),
+  goodSolution_(NULL),
+  list_(NULL),
+  useful_(NULL),
+  solver_(NULL),
+  status_(-1),
+  bestObjectIndex_(-1),
+  bestWhichWay_(-1),
+  firstForcedObjectIndex_(-1),
+  firstForcedWhichWay_(-1),
+  numberUnsatisfied_(0),
+  numberStrong_(0),
+  numberOnList_(0),
+  numberStrongDone_(0),
+  numberStrongIterations_(0),
+  numberStrongFixed_(0),
+  trustStrongForBound_(true),
+  trustStrongForSolution_(true)
+{
+}
+
+OsiChooseVariable::OsiChooseVariable(const OsiSolverInterface * solver) :
+  goodObjectiveValue_(COIN_DBL_MAX),
+  upChange_(0.0),
+  downChange_(0.0),
+  goodSolution_(NULL),
+  solver_(solver),
+  status_(-1),
+  bestObjectIndex_(-1),
+  bestWhichWay_(-1),
+  firstForcedObjectIndex_(-1),
+  firstForcedWhichWay_(-1),
+  numberUnsatisfied_(0),
+  numberStrong_(0),
+  numberOnList_(0),
+  numberStrongDone_(0),
+  numberStrongIterations_(0),
+  numberStrongFixed_(0),
+  trustStrongForBound_(true),
+  trustStrongForSolution_(true)
+{
+  // create useful arrays
+  int numberObjects = solver_->numberObjects();
+  list_ = new int [numberObjects];
+  useful_ = new double [numberObjects];
+}
+
+OsiChooseVariable::OsiChooseVariable(const OsiChooseVariable & rhs) 
+{  
+  goodObjectiveValue_ = rhs.goodObjectiveValue_;
+  upChange_ = rhs.upChange_;
+  downChange_ = rhs.downChange_;
+  status_ = rhs.status_;
+  bestObjectIndex_ = rhs.bestObjectIndex_;
+  bestWhichWay_ = rhs.bestWhichWay_;
+  firstForcedObjectIndex_ = rhs.firstForcedObjectIndex_;
+  firstForcedWhichWay_ = rhs.firstForcedWhichWay_;
+  numberUnsatisfied_ = rhs.numberUnsatisfied_;
+  numberStrong_ = rhs.numberStrong_;
+  numberOnList_ = rhs.numberOnList_;
+  numberStrongDone_ = rhs.numberStrongDone_;
+  numberStrongIterations_ = rhs.numberStrongIterations_;
+  numberStrongFixed_ = rhs.numberStrongFixed_;
+  trustStrongForBound_ = rhs.trustStrongForBound_;
+  trustStrongForSolution_ = rhs.trustStrongForSolution_;
+  solver_ = rhs.solver_;
+  if (solver_) {
+    int numberObjects = solver_->numberObjects();
+    int numberColumns = solver_->getNumCols();
+    if (rhs.goodSolution_) {
+      goodSolution_ = CoinCopyOfArray(rhs.goodSolution_,numberColumns);
+    } else {
+      goodSolution_ = NULL;
+    }
+    list_ = CoinCopyOfArray(rhs.list_,numberObjects);
+    useful_ = CoinCopyOfArray(rhs.useful_,numberObjects);
+  } else {
+    goodSolution_ = NULL;
+    list_ = NULL;
+    useful_ = NULL;
+  }
+}
+
+OsiChooseVariable &
+OsiChooseVariable::operator=(const OsiChooseVariable & rhs)
+{
+  if (this != &rhs) {
+    delete [] goodSolution_;
+    delete [] list_;
+    delete [] useful_;
+    goodObjectiveValue_ = rhs.goodObjectiveValue_;
+    upChange_ = rhs.upChange_;
+    downChange_ = rhs.downChange_;
+    status_ = rhs.status_;
+    bestObjectIndex_ = rhs.bestObjectIndex_;
+    bestWhichWay_ = rhs.bestWhichWay_;
+    firstForcedObjectIndex_ = rhs.firstForcedObjectIndex_;
+    firstForcedWhichWay_ = rhs.firstForcedWhichWay_;
+    numberUnsatisfied_ = rhs.numberUnsatisfied_;
+    numberStrong_ = rhs.numberStrong_;
+    numberOnList_ = rhs.numberOnList_;
+    numberStrongDone_ = rhs.numberStrongDone_;
+    numberStrongIterations_ = rhs.numberStrongIterations_;
+    numberStrongFixed_ = rhs.numberStrongFixed_;
+    trustStrongForBound_ = rhs.trustStrongForBound_;
+    trustStrongForSolution_ = rhs.trustStrongForSolution_;
+    solver_ = rhs.solver_;
+    if (solver_) {
+      int numberObjects = solver_->numberObjects();
+      int numberColumns = solver_->getNumCols();
+      if (rhs.goodSolution_) {
+	goodSolution_ = CoinCopyOfArray(rhs.goodSolution_,numberColumns);
+      } else {
+	goodSolution_ = NULL;
+      }
+      list_ = CoinCopyOfArray(rhs.list_,numberObjects);
+      useful_ = CoinCopyOfArray(rhs.useful_,numberObjects);
+    } else {
+      goodSolution_ = NULL;
+      list_ = NULL;
+      useful_ = NULL;
+    }
+  }
+  return *this;
+}
+
+
+OsiChooseVariable::~OsiChooseVariable ()
+{
+  delete [] goodSolution_;
+  delete [] list_;
+  delete [] useful_;
+}
+
+// Clone
+OsiChooseVariable *
+OsiChooseVariable::clone() const
+{
+  return new OsiChooseVariable(*this);
+}
+// Set solver and redo arrays
+void 
+OsiChooseVariable::setSolver (const OsiSolverInterface * solver) 
+{
+  solver_ = solver;
+  delete [] list_;
+  delete [] useful_;
+  // create useful arrays
+  int numberObjects = solver_->numberObjects();
+  list_ = new int [numberObjects];
+  useful_ = new double [numberObjects];
+}
+
+
+// Initialize
+int 
+OsiChooseVariable::setupList ( OsiBranchingInformation *info, bool initialize)
+{
+  if (initialize) {
+    status_=-2;
+    delete [] goodSolution_;
+    bestObjectIndex_=-1;
+    numberStrongDone_=0;
+    numberStrongIterations_ = 0;
+    numberStrongFixed_ = 0;
+    goodSolution_ = NULL;
+    goodObjectiveValue_ = COIN_DBL_MAX;
+  }
+  numberOnList_=0;
+  numberUnsatisfied_=0;
+  int numberObjects = solver_->numberObjects();
+  assert (numberObjects);
+  double check = 0.0;
+  int checkIndex=0;
+  int bestPriority=COIN_INT_MAX;
+  // pretend one strong even if none
+  int maximumStrong= numberStrong_ ? CoinMin(numberStrong_,numberObjects) : 1;
+  int putOther = numberObjects;
+  int i;
+  for (i=0;i<maximumStrong;i++) {
+    list_[i]=-1;
+    useful_[i]=0.0;
+  }
+  OsiObject ** object = info->solver_->objects();
+  // Say feasible
+  bool feasible = true;
+  for ( i=0;i<numberObjects;i++) {
+    int way;
+    double value = object[i]->infeasibility(info,way);
+    if (value>0.0) {
+      numberUnsatisfied_++;
+      if (value==COIN_DBL_MAX) {
+	// infeasible
+	feasible=false;
+	break;
+      }
+      int priorityLevel = object[i]->priority();
+      // Better priority? Flush choices.
+      if (priorityLevel<bestPriority) {
+	for (int j=0;j<maximumStrong;j++) {
+	  if (list_[j]>=0) {
+	    int iObject = list_[j];
+	    list_[j]=-1;
+	    useful_[j]=0.0;
+	    list_[--putOther]=iObject;
+	  }
+	}
+	bestPriority = priorityLevel;
+	check=0.0;
+      } 
+      if (priorityLevel==bestPriority) {
+	if (value>check) {
+	  //add to list
+	  int iObject = list_[checkIndex];
+	  if (iObject>=0)
+	    list_[--putOther]=iObject;  // to end
+	  list_[checkIndex]=i;
+	  useful_[checkIndex]=value;
+	  // find worst
+	  check=COIN_DBL_MAX;
+	  for (int j=0;j<maximumStrong;j++) {
+	    if (list_[j]>=0) {
+	      if (useful_[j]<check) {
+		check=useful_[j];
+		checkIndex=j;
+	      }
+	    } else {
+	      check=0.0;
+	      checkIndex = j;
+	      break;
+	    }
+	  }
+	} else {
+	  // to end
+	  list_[--putOther]=i;
+	}
+      } else {
+	// to end
+	list_[--putOther]=i;
+      }
+    }
+  }
+  // Get list
+  numberOnList_=0;
+  if (feasible) {
+    for (i=0;i<maximumStrong;i++) {
+      if (list_[i]>=0) {
+	list_[numberOnList_]=list_[i];
+	useful_[numberOnList_++]=-useful_[i];
+      }
+    }
+    if (numberOnList_) {
+      // Sort 
+      CoinSort_2(useful_,useful_+numberOnList_,list_);
+      // move others
+      i = numberOnList_;
+      for (;putOther<numberObjects;putOther++) 
+	list_[i++]=list_[putOther];
+      assert (i==numberUnsatisfied_);
+      if (!numberStrong_)
+	numberOnList_=0;
+    } 
+  } else {
+    // not feasible
+    numberUnsatisfied_=-1;
+  }
+  return numberUnsatisfied_;
+}
+/* Choose a variable
+   Returns - 
+   -1 Node is infeasible
+   0  Normal termination - we have a candidate
+   1  All looks satisfied - no candidate
+   2  We can change the bound on a variable - but we also have a strong branching candidate
+   3  We can change the bound on a variable - but we have a non-strong branching candidate
+   4  We can change the bound on a variable - no other candidates
+   We can pick up branch from whichObject() and whichWay()
+   We can pick up a forced branch (can change bound) from whichForcedObject() and whichForcedWay()
+   If we have a solution then we can pick up from goodObjectiveValue() and goodSolution()
+*/
+int 
+OsiChooseVariable::chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *, bool )
+{
+  if (numberUnsatisfied_) {
+    bestObjectIndex_=list_[0];
+    bestWhichWay_ = solver->object(bestObjectIndex_)->whichWay();
+    firstForcedObjectIndex_ = -1;
+    firstForcedWhichWay_ =-1;
+    return 0;
+  } else {
+    return 1;
+  }
+}
+// Returns true if solution looks feasible against given objects
+bool 
+OsiChooseVariable::feasibleSolution(const OsiBranchingInformation * info,
+				    const double * solution,
+				    int numberObjects,
+				    const OsiObject ** objects)
+{
+  bool satisfied=true;
+  const double * saveSolution = info->solution_;
+  info->solution_ = solution;
+  for (int i=0;i<numberObjects;i++) {
+    double value = objects[i]->checkInfeasibility(info);
+    if (value>0.0) {
+      satisfied=false;
+      break;
+    }
+  }
+  info->solution_ = saveSolution;
+  return satisfied;
+}
+// Saves a good solution
+void 
+OsiChooseVariable::saveSolution(const OsiSolverInterface * solver)
+{
+  delete [] goodSolution_;
+  int numberColumns = solver->getNumCols();
+  goodSolution_ = CoinCopyOfArray(solver->getColSolution(),numberColumns);
+  goodObjectiveValue_ = solver->getObjSense()*solver->getObjValue();
+}
+// Clears out good solution after use
+void 
+OsiChooseVariable::clearGoodSolution()
+{
+  delete [] goodSolution_;
+  goodSolution_ = NULL;
+  goodObjectiveValue_ = COIN_DBL_MAX;
+}
+
+/*  This is a utility function which does strong branching on
+    a list of objects and stores the results in OsiHotInfo.objects.
+    On entry the object sequence is stored in the OsiHotInfo object
+    and maybe more.
+    It returns -
+    -1 - one branch was infeasible both ways
+     0 - all inspected - nothing can be fixed
+     1 - all inspected - some can be fixed (returnCriterion==0)
+     2 - may be returning early - one can be fixed (last one done) (returnCriterion==1) 
+     3 - returning because max time
+*/
+int 
+OsiChooseStrong::doStrongBranching( OsiSolverInterface * solver, 
+				    OsiBranchingInformation *info,
+				    int numberToDo, int returnCriterion)
+{
+
+  // Might be faster to extend branch() to return bounds changed
+  double * saveLower = NULL;
+  double * saveUpper = NULL;
+  int numberColumns = solver->getNumCols();
+  solver->markHotStart();
+  const double * lower = info->lower_;
+  const double * upper = info->upper_;
+  saveLower = CoinCopyOfArray(info->lower_,numberColumns);
+  saveUpper = CoinCopyOfArray(info->upper_,numberColumns);
+  numResults_=0;
+  int returnCode=0;
+  double timeStart = CoinCpuTime();
+  for (int iDo=0;iDo<numberToDo;iDo++) {
+    OsiHotInfo * result = results_ + iDo;
+    // For now just 2 way
+    OsiBranchingObject * branch = result->branchingObject();
+    assert (branch->numberBranches()==2);
+    /*
+      Try the first direction.  Each subsequent call to branch() performs the
+      specified branch and advances the branch object state to the next branch
+      alternative.)
+    */
+    OsiSolverInterface * thisSolver = solver; 
+    if (branch->boundBranch()) {
+      // ordinary
+      branch->branch(solver);
+      // maybe we should check bounds for stupidities here?
+      solver->solveFromHotStart() ;
+    } else {
+      // adding cuts or something 
+      thisSolver = solver->clone();
+      branch->branch(thisSolver);
+      // set hot start iterations
+      int limit;
+      thisSolver->getIntParam(OsiMaxNumIterationHotStart,limit);
+      thisSolver->setIntParam(OsiMaxNumIteration,limit); 
+      thisSolver->resolve();
+    }
+    // can check if we got solution
+    // status is 0 finished, 1 infeasible and 2 unfinished and 3 is solution
+    int status0 = result->updateInformation(thisSolver,info,this);
+    numberStrongIterations_ += thisSolver->getIterationCount();
+    if (status0==3) {
+      // new solution already saved
+      if (trustStrongForSolution_) {
+	info->cutoff_ = goodObjectiveValue_;
+	status0=0;
+      }
+    }
+    if (solver!=thisSolver)
+      delete thisSolver;
+    // Restore bounds
+    for (int j=0;j<numberColumns;j++) {
+      if (saveLower[j] != lower[j])
+	solver->setColLower(j,saveLower[j]);
+      if (saveUpper[j] != upper[j])
+	solver->setColUpper(j,saveUpper[j]);
+    }
+    /*
+      Try the next direction
+    */
+    thisSolver = solver; 
+    if (branch->boundBranch()) {
+      // ordinary
+      branch->branch(solver);
+      // maybe we should check bounds for stupidities here?
+      solver->solveFromHotStart() ;
+    } else {
+      // adding cuts or something 
+      thisSolver = solver->clone();
+      branch->branch(thisSolver);
+      // set hot start iterations
+      int limit;
+      thisSolver->getIntParam(OsiMaxNumIterationHotStart,limit);
+      thisSolver->setIntParam(OsiMaxNumIteration,limit); 
+      thisSolver->resolve();
+    }
+    // can check if we got solution
+    // status is 0 finished, 1 infeasible and 2 unfinished and 3 is solution
+    int status1 = result->updateInformation(thisSolver,info,this);
+    numberStrongDone_++;
+    numberStrongIterations_ += thisSolver->getIterationCount();
+    if (status1==3) {
+      // new solution already saved
+      if (trustStrongForSolution_) {
+	info->cutoff_ = goodObjectiveValue_;
+	status1=0;
+      }
+    }
+    if (solver!=thisSolver)
+      delete thisSolver;
+    // Restore bounds
+    for (int j=0;j<numberColumns;j++) {
+      if (saveLower[j] != lower[j])
+	solver->setColLower(j,saveLower[j]);
+      if (saveUpper[j] != upper[j])
+	solver->setColUpper(j,saveUpper[j]);
+    }
+    /*
+      End of evaluation for this candidate variable. Possibilities are:
+      * Both sides below cutoff; this variable is a candidate for branching.
+      * Both sides infeasible or above the objective cutoff: no further action
+      here. Break from the evaluation loop and assume the node will be purged
+      by the caller.
+      * One side below cutoff: Install the branch (i.e., fix the variable). Possibly break
+      from the evaluation loop and assume the node will be reoptimised by the
+      caller.
+    */
+    numResults_++;
+    if (status0==1&&status1==1) {
+      // infeasible
+      returnCode=-1;
+      break; // exit loop
+    } else if (status0==1||status1==1) {
+      numberStrongFixed_++;
+      if (!returnCriterion) {
+	returnCode=1;
+      } else {
+	returnCode=2;
+	break;
+      }
+    }
+    bool hitMaxTime = ( CoinCpuTime()-timeStart > info->timeRemaining_);
+    if (hitMaxTime) {
+      returnCode=3;
+      break;
+    }
+  }
+  delete [] saveLower;
+  delete [] saveUpper;
+  // Delete the snapshot
+  solver->unmarkHotStart();
+  return returnCode;
+}
+
+// Given a candidate fill in useful information e.g. estimates
+void 
+OsiChooseVariable::updateInformation(const OsiBranchingInformation *info,
+				  int , OsiHotInfo * hotInfo)
+{
+  int index = hotInfo->whichObject();
+  assert (index<solver_->numberObjects());
+  //assert (branch<2);
+  OsiObject ** object = info->solver_->objects();
+  upChange_ = object[index]->upEstimate();
+  downChange_ = object[index]->downEstimate();
+}
+#if 1
+// Given a branch fill in useful information e.g. estimates
+void 
+OsiChooseVariable::updateInformation( int index, int branch, 
+				      double , double ,
+				      int )
+{
+  assert (index<solver_->numberObjects());
+  assert (branch<2);
+  OsiObject ** object = solver_->objects();
+  if (branch)
+    upChange_ = object[index]->upEstimate();
+  else
+    downChange_ = object[index]->downEstimate();
+}
+#endif
+
+//##############################################################################
+
+void
+OsiPseudoCosts::gutsOfDelete()
+{
+  if (numberObjects_ > 0) {
+    numberObjects_ = 0;
+    numberBeforeTrusted_ = 0;
+    delete[] upTotalChange_;   upTotalChange_ = NULL;
+    delete[] downTotalChange_; downTotalChange_ = NULL;
+    delete[] upNumber_;        upNumber_ = NULL;
+    delete[] downNumber_;      downNumber_ = NULL;
+  }
+}
+
+void
+OsiPseudoCosts::gutsOfCopy(const OsiPseudoCosts& rhs)
+{
+  numberObjects_ = rhs.numberObjects_;
+  numberBeforeTrusted_ = rhs.numberBeforeTrusted_;
+  if (numberObjects_ > 0) {
+    upTotalChange_ = CoinCopyOfArray(rhs.upTotalChange_,numberObjects_);
+    downTotalChange_ = CoinCopyOfArray(rhs.downTotalChange_,numberObjects_);
+    upNumber_ = CoinCopyOfArray(rhs.upNumber_,numberObjects_);
+    downNumber_ = CoinCopyOfArray(rhs.downNumber_,numberObjects_);
+  }
+}
+
+OsiPseudoCosts::OsiPseudoCosts() :
+  upTotalChange_(NULL),
+  downTotalChange_(NULL),
+  upNumber_(NULL),
+  downNumber_(NULL),
+  numberObjects_(0),
+  numberBeforeTrusted_(0)
+{
+}
+
+OsiPseudoCosts::~OsiPseudoCosts()
+{
+  gutsOfDelete();
+}
+
+OsiPseudoCosts::OsiPseudoCosts(const OsiPseudoCosts& rhs) :
+  upTotalChange_(NULL),
+  downTotalChange_(NULL),
+  upNumber_(NULL),
+  downNumber_(NULL),
+  numberObjects_(0),
+  numberBeforeTrusted_(0)
+{
+  gutsOfCopy(rhs);
+}
+
+OsiPseudoCosts&
+OsiPseudoCosts::operator=(const OsiPseudoCosts& rhs)
+{
+  if (this != &rhs) {
+    gutsOfDelete();
+    gutsOfCopy(rhs);
+  }
+  return *this;
+}
+
+void
+OsiPseudoCosts::initialize(int n)
+{
+  gutsOfDelete();
+  numberObjects_ = n;
+  if (numberObjects_ > 0) {
+    upTotalChange_ = new double [numberObjects_];
+    downTotalChange_ = new double [numberObjects_];
+    upNumber_ = new int [numberObjects_];
+    downNumber_ = new int [numberObjects_];
+    CoinZeroN(upTotalChange_,numberObjects_);
+    CoinZeroN(downTotalChange_,numberObjects_);
+    CoinZeroN(upNumber_,numberObjects_);
+    CoinZeroN(downNumber_,numberObjects_);
+  }
+}
+  
+
+//##############################################################################
+
+OsiChooseStrong::OsiChooseStrong() :
+  OsiChooseVariable(),
+  shadowPriceMode_(0),
+  pseudoCosts_(),
+  results_(NULL),
+  numResults_(0)
+{
+}
+
+OsiChooseStrong::OsiChooseStrong(const OsiSolverInterface * solver) :
+  OsiChooseVariable(solver),
+  shadowPriceMode_(0),
+  pseudoCosts_(),
+  results_(NULL),
+  numResults_(0)
+{
+  // create useful arrays
+  pseudoCosts_.initialize(solver_->numberObjects());
+}
+
+OsiChooseStrong::OsiChooseStrong(const OsiChooseStrong & rhs) :
+  OsiChooseVariable(rhs),
+  shadowPriceMode_(rhs.shadowPriceMode_),
+  pseudoCosts_(rhs.pseudoCosts_),
+  results_(NULL),
+  numResults_(0)
+{  
+}
+
+OsiChooseStrong &
+OsiChooseStrong::operator=(const OsiChooseStrong & rhs)
+{
+  if (this != &rhs) {
+    OsiChooseVariable::operator=(rhs);
+    shadowPriceMode_ = rhs.shadowPriceMode_;
+    pseudoCosts_ = rhs.pseudoCosts_;
+    delete[] results_;
+    results_ = NULL;
+    numResults_ = 0;
+  }
+  return *this;
+}
+
+
+OsiChooseStrong::~OsiChooseStrong ()
+{
+  delete[] results_;
+}
+
+// Clone
+OsiChooseVariable *
+OsiChooseStrong::clone() const
+{
+  return new OsiChooseStrong(*this);
+}
+#define MAXMIN_CRITERION 0.85
+// Initialize
+int 
+OsiChooseStrong::setupList ( OsiBranchingInformation *info, bool initialize)
+{
+  if (initialize) {
+    status_=-2;
+    delete [] goodSolution_;
+    bestObjectIndex_=-1;
+    numberStrongDone_=0;
+    numberStrongIterations_ = 0;
+    numberStrongFixed_ = 0;
+    goodSolution_ = NULL;
+    goodObjectiveValue_ = COIN_DBL_MAX;
+  }
+  numberOnList_=0;
+  numberUnsatisfied_=0;
+  int numberObjects = solver_->numberObjects();
+  if (numberObjects>pseudoCosts_.numberObjects()) {
+    // redo useful arrays
+    pseudoCosts_.initialize(numberObjects);
+  }
+  double check = -COIN_DBL_MAX;
+  int checkIndex=0;
+  int bestPriority=COIN_INT_MAX;
+  int maximumStrong= CoinMin(numberStrong_,numberObjects) ;
+  int putOther = numberObjects;
+  int i;
+  for (i=0;i<numberObjects;i++) {
+    list_[i]=-1;
+    useful_[i]=0.0;
+  }
+  OsiObject ** object = info->solver_->objects();
+  // Get average pseudo costs and see if pseudo shadow prices possible
+  int shadowPossible=shadowPriceMode_;
+  if (shadowPossible) {
+    for ( i=0;i<numberObjects;i++) {
+      if ( !object[i]->canHandleShadowPrices()) {
+	shadowPossible=0;
+	break;
+      }
+    }
+    if (shadowPossible) {
+      int numberRows = solver_->getNumRows();
+      const double * pi = info->pi_;
+      double sumPi=0.0;
+      for (i=0;i<numberRows;i++) 
+	sumPi += fabs(pi[i]);
+      sumPi /= static_cast<double> (numberRows);
+      // and scale back
+      sumPi *= 0.01;
+      info->defaultDual_ = sumPi; // switch on
+      int numberColumns = solver_->getNumCols();
+      int size = CoinMax(numberColumns,2*numberRows);
+      info->usefulRegion_ = new double [size];
+      CoinZeroN(info->usefulRegion_,size);
+      info->indexRegion_ = new int [size];
+    }
+  }
+  double sumUp=0.0;
+  double numberUp=0.0;
+  double sumDown=0.0;
+  double numberDown=0.0;
+  const double* upTotalChange = pseudoCosts_.upTotalChange();
+  const double* downTotalChange = pseudoCosts_.downTotalChange();
+  const int* upNumber = pseudoCosts_.upNumber();
+  const int* downNumber = pseudoCosts_.downNumber();
+  const int numberBeforeTrusted = pseudoCosts_.numberBeforeTrusted();
+  for ( i=0;i<numberObjects;i++) {
+    sumUp += upTotalChange[i];
+    numberUp += upNumber[i];
+    sumDown += downTotalChange[i];
+    numberDown += downNumber[i];
+  }
+  double upMultiplier=(1.0+sumUp)/(1.0+numberUp);
+  double downMultiplier=(1.0+sumDown)/(1.0+numberDown);
+  // Say feasible
+  bool feasible = true;
+#if 0
+  int pri[]={10,1000,10000};
+  int priCount[]={0,0,0};
+#endif
+  for ( i=0;i<numberObjects;i++) {
+    int way;
+    double value = object[i]->infeasibility(info,way);
+    if (value>0.0) {
+      numberUnsatisfied_++;
+      if (value==COIN_DBL_MAX) {
+	// infeasible
+	feasible=false;
+	break;
+      }
+      int priorityLevel = object[i]->priority();
+#if 0
+      for (int k=0;k<3;k++) {
+	if (priorityLevel==pri[k])
+	  priCount[k]++;
+      }
+#endif
+      // Better priority? Flush choices.
+      if (priorityLevel<bestPriority) {
+	for (int j=maximumStrong-1;j>=0;j--) {
+	  if (list_[j]>=0) {
+	    int iObject = list_[j];
+	    list_[j]=-1;
+	    useful_[j]=0.0;
+	    list_[--putOther]=iObject;
+	  }
+	}
+	maximumStrong = CoinMin(maximumStrong,putOther);
+	bestPriority = priorityLevel;
+	check=-COIN_DBL_MAX;
+	checkIndex=0;
+      } 
+      if (priorityLevel==bestPriority) {
+	// Modify value
+	sumUp = upTotalChange[i]+1.0e-30;
+	numberUp = upNumber[i];
+	sumDown = downTotalChange[i]+1.0e-30;
+	numberDown = downNumber[i];
+	double upEstimate = object[i]->upEstimate();
+	double downEstimate = object[i]->downEstimate();
+	if (shadowPossible<2) {
+	  upEstimate = numberUp ? ((upEstimate*sumUp)/numberUp) : (upEstimate*upMultiplier);
+	  if (numberUp<numberBeforeTrusted)
+	    upEstimate *= (numberBeforeTrusted+1.0)/(numberUp+1.0);
+	  downEstimate = numberDown ? ((downEstimate*sumDown)/numberDown) : (downEstimate*downMultiplier);
+	  if (numberDown<numberBeforeTrusted)
+	    downEstimate *= (numberBeforeTrusted+1.0)/(numberDown+1.0);
+	} else {
+	  // use shadow prices always
+	}
+	value = MAXMIN_CRITERION*CoinMin(upEstimate,downEstimate) + (1.0-MAXMIN_CRITERION)*CoinMax(upEstimate,downEstimate);
+	if (value>check) {
+	  //add to list
+	  int iObject = list_[checkIndex];
+	  if (iObject>=0) {
+	    assert (list_[putOther-1]<0);
+	    list_[--putOther]=iObject;  // to end
+	  }
+	  list_[checkIndex]=i;
+	  assert (checkIndex<putOther);
+	  useful_[checkIndex]=value;
+	  // find worst
+	  check=COIN_DBL_MAX;
+	  maximumStrong = CoinMin(maximumStrong,putOther);
+	  for (int j=0;j<maximumStrong;j++) {
+	    if (list_[j]>=0) {
+	      if (useful_[j]<check) {
+		check=useful_[j];
+		checkIndex=j;
+	      }
+	    } else {
+	      check=0.0;
+	      checkIndex = j;
+	      break;
+	    }
+	  }
+	} else {
+	  // to end
+	  assert (list_[putOther-1]<0);
+	  list_[--putOther]=i;
+	  maximumStrong = CoinMin(maximumStrong,putOther);
+	}
+      } else {
+	// worse priority
+	// to end
+	assert (list_[putOther-1]<0);
+	list_[--putOther]=i;
+	maximumStrong = CoinMin(maximumStrong,putOther);
+      }
+    }
+  }
+#if 0
+  printf("%d at %d, %d at %d and %d at %d\n",priCount[0],pri[0],
+	 priCount[1],pri[1],priCount[2],pri[2]);
+#endif
+  // Get list
+  numberOnList_=0;
+  if (feasible) {
+    for (i=0;i<CoinMin(maximumStrong,putOther);i++) {
+      if (list_[i]>=0) {
+	list_[numberOnList_]=list_[i];
+	useful_[numberOnList_++]=-useful_[i];
+      }
+    }
+    if (numberOnList_) {
+      // Sort 
+      CoinSort_2(useful_,useful_+numberOnList_,list_);
+      // move others
+      i = numberOnList_;
+      for (;putOther<numberObjects;putOther++) 
+	list_[i++]=list_[putOther];
+      assert (i==numberUnsatisfied_);
+      if (!numberStrong_)
+	numberOnList_=0;
+    }
+  } else {
+    // not feasible
+    numberUnsatisfied_=-1;
+  }
+  // Get rid of any shadow prices info
+  info->defaultDual_ = -1.0; // switch off
+  delete [] info->usefulRegion_;
+  delete [] info->indexRegion_;
+  return numberUnsatisfied_;
+}
+
+void
+OsiChooseStrong::resetResults(int num)
+{
+  delete[] results_;
+  numResults_ = 0;
+  results_ = new OsiHotInfo[num];
+}
+  
+/* Choose a variable
+   Returns - 
+   -1 Node is infeasible
+   0  Normal termination - we have a candidate
+   1  All looks satisfied - no candidate
+   2  We can change the bound on a variable - but we also have a strong branching candidate
+   3  We can change the bound on a variable - but we have a non-strong branching candidate
+   4  We can change the bound on a variable - no other candidates
+   We can pick up branch from whichObject() and whichWay()
+   We can pick up a forced branch (can change bound) from whichForcedObject() and whichForcedWay()
+   If we have a solution then we can pick up from goodObjectiveValue() and goodSolution()
+*/
+int 
+OsiChooseStrong::chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *info, bool fixVariables)
+{
+  if (numberUnsatisfied_) {
+    const double* upTotalChange = pseudoCosts_.upTotalChange();
+    const double* downTotalChange = pseudoCosts_.downTotalChange();
+    const int* upNumber = pseudoCosts_.upNumber();
+    const int* downNumber = pseudoCosts_.downNumber();
+    int numberBeforeTrusted = pseudoCosts_.numberBeforeTrusted();
+    // Somehow we can get here with it 0 !
+    if (!numberBeforeTrusted) {
+      numberBeforeTrusted=5;
+      pseudoCosts_.setNumberBeforeTrusted(numberBeforeTrusted);
+    }
+
+    int numberLeft = CoinMin(numberStrong_-numberStrongDone_,numberUnsatisfied_);
+    int numberToDo=0;
+    resetResults(numberLeft);
+    int returnCode=0;
+    bestObjectIndex_ = -1;
+    bestWhichWay_ = -1;
+    firstForcedObjectIndex_ = -1;
+    firstForcedWhichWay_ =-1;
+    double bestTrusted=-COIN_DBL_MAX;
+    for (int i=0;i<numberLeft;i++) {
+      int iObject = list_[i];
+      if (upNumber[iObject]<numberBeforeTrusted||downNumber[iObject]<numberBeforeTrusted) {
+	results_[numberToDo++] = OsiHotInfo(solver, info,
+					    solver->objects(), iObject);
+      } else {
+	const OsiObject * obj = solver->object(iObject);
+	double upEstimate = (upTotalChange[iObject]*obj->upEstimate())/upNumber[iObject];
+	double downEstimate = (downTotalChange[iObject]*obj->downEstimate())/downNumber[iObject];
+	double value = MAXMIN_CRITERION*CoinMin(upEstimate,downEstimate) + (1.0-MAXMIN_CRITERION)*CoinMax(upEstimate,downEstimate);
+	if (value > bestTrusted) {
+	  bestObjectIndex_=iObject;
+	  bestWhichWay_ = upEstimate>downEstimate ? 0 : 1;
+	  bestTrusted = value;
+	}
+      }
+    }
+    int numberFixed=0;
+    if (numberToDo) {
+      returnCode = doStrongBranching(solver, info, numberToDo, 1);
+      if (returnCode>=0&&returnCode<=2) {
+	if (returnCode) {
+	  returnCode=4;
+	  if (bestObjectIndex_>=0)
+	    returnCode=3;
+	}
+	for (int i=0;i<numResults_;i++) {
+	  int iObject = results_[i].whichObject();
+	  double upEstimate;
+	  if (results_[i].upStatus()!=1) {
+	    assert (results_[i].upStatus()>=0);
+	    upEstimate = results_[i].upChange();
+	  } else {
+	    // infeasible - just say expensive
+	    if (info->cutoff_<1.0e50)
+	      upEstimate = 2.0*(info->cutoff_-info->objectiveValue_);
+	    else
+	      upEstimate = 2.0*fabs(info->objectiveValue_);
+	    if (firstForcedObjectIndex_ <0) {
+	      firstForcedObjectIndex_ = iObject;
+	      firstForcedWhichWay_ =0;
+	    }
+	    numberFixed++;
+	    if (fixVariables) {
+	      const OsiObject * obj = solver->object(iObject);
+	      OsiBranchingObject * branch = obj->createBranch(solver,info,0);
+	      branch->branch(solver);
+	      delete branch;
+	    }
+	  }
+	  double downEstimate;
+	  if (results_[i].downStatus()!=1) {
+	    assert (results_[i].downStatus()>=0);
+	    downEstimate = results_[i].downChange();
+	  } else {
+	    // infeasible - just say expensive
+	    if (info->cutoff_<1.0e50)
+	      downEstimate = 2.0*(info->cutoff_-info->objectiveValue_);
+	    else
+	      downEstimate = 2.0*fabs(info->objectiveValue_);
+	    if (firstForcedObjectIndex_ <0) {
+	      firstForcedObjectIndex_ = iObject;
+	      firstForcedWhichWay_ =1;
+	    }
+	    numberFixed++;
+	    if (fixVariables) {
+	      const OsiObject * obj = solver->object(iObject);
+	      OsiBranchingObject * branch = obj->createBranch(solver,info,1);
+	      branch->branch(solver);
+	      delete branch;
+	    }
+	  }
+	  double value = MAXMIN_CRITERION*CoinMin(upEstimate,downEstimate) + (1.0-MAXMIN_CRITERION)*CoinMax(upEstimate,downEstimate);
+	  if (value>bestTrusted) {
+	    bestTrusted = value;
+	    bestObjectIndex_ = iObject;
+	    bestWhichWay_ = upEstimate>downEstimate ? 0 : 1;
+	    // but override if there is a preferred way
+	    const OsiObject * obj = solver->object(iObject);
+	    if (obj->preferredWay()>=0&&obj->infeasibility())
+	      bestWhichWay_ = obj->preferredWay();
+	    if (returnCode)
+	      returnCode=2;
+	  }
+	}
+      } else if (returnCode==3) {
+	// max time - just choose one
+	bestObjectIndex_ = list_[0];
+	bestWhichWay_ = 0;
+	returnCode=0;
+      }
+    } else {
+      bestObjectIndex_=list_[0];
+    }
+    if ( bestObjectIndex_ >=0 ) {
+      OsiObject * obj = solver->objects()[bestObjectIndex_];
+      obj->setWhichWay(	bestWhichWay_);
+    }
+    if (numberFixed==numberUnsatisfied_&&numberFixed)
+      returnCode=4;
+    return returnCode;
+  } else {
+    return 1;
+  }
+}
+// Given a candidate  fill in useful information e.g. estimates
+void 
+OsiPseudoCosts::updateInformation(const OsiBranchingInformation *info,
+				  int branch, OsiHotInfo * hotInfo)
+{
+  int index = hotInfo->whichObject();
+  assert (index<info->solver_->numberObjects());
+  const OsiObject * object = info->solver_->object(index);
+  assert (object->upEstimate()>0.0&&object->downEstimate()>0.0);
+  assert (branch<2);
+  if (branch) {
+    if (hotInfo->upStatus()!=1) {
+      assert (hotInfo->upStatus()>=0);
+      upTotalChange_[index] += hotInfo->upChange()/object->upEstimate();
+      upNumber_[index]++;
+    } else {
+#if 0
+      // infeasible - just say expensive
+      if (info->cutoff_<1.0e50)
+	upTotalChange_[index] += 2.0*(info->cutoff_-info->objectiveValue_)/object->upEstimate();
+      else
+	upTotalChange_[index] += 2.0*fabs(info->objectiveValue_)/object->upEstimate();
+#endif
+    }
+  } else {
+    if (hotInfo->downStatus()!=1) {
+      assert (hotInfo->downStatus()>=0);
+      downTotalChange_[index] += hotInfo->downChange()/object->downEstimate();
+      downNumber_[index]++;
+    } else {
+#if 0
+      // infeasible - just say expensive
+      if (info->cutoff_<1.0e50)
+	downTotalChange_[index] += 2.0*(info->cutoff_-info->objectiveValue_)/object->downEstimate();
+      else
+	downTotalChange_[index] += 2.0*fabs(info->objectiveValue_)/object->downEstimate();
+#endif
+    }
+  }  
+}
+#if 1
+// Given a branch fill in useful information e.g. estimates
+void 
+OsiPseudoCosts::updateInformation(int index, int branch, 
+				  double changeInObjective,
+				  double changeInValue,
+				  int status)
+{
+  //assert (index<solver_->numberObjects());
+  assert (branch<2);
+  assert (changeInValue>0.0);
+  assert (branch<2);
+  if (branch) {
+    if (status!=1) {
+      assert (status>=0);
+      upTotalChange_[index] += changeInObjective/changeInValue;
+      upNumber_[index]++;
+    }
+  } else {
+    if (status!=1) {
+      assert (status>=0);
+      downTotalChange_[index] += changeInObjective/changeInValue;
+      downNumber_[index]++;
+    }
+  }  
+}
+#endif
+
+OsiHotInfo::OsiHotInfo() :
+  originalObjectiveValue_(COIN_DBL_MAX),
+  changes_(NULL),
+  iterationCounts_(NULL),
+  statuses_(NULL),
+  branchingObject_(NULL),
+  whichObject_(-1)
+{
+}
+
+OsiHotInfo::OsiHotInfo(OsiSolverInterface * solver,
+		       const OsiBranchingInformation * info,
+		       const OsiObject * const * objects,
+		       int whichObject) :
+  originalObjectiveValue_(COIN_DBL_MAX),
+  whichObject_(whichObject)
+{
+  originalObjectiveValue_ = info->objectiveValue_;
+  const OsiObject * object = objects[whichObject_];
+  // create object - "down" first
+  branchingObject_ = object->createBranch(solver,info,0);
+  // create arrays
+  int numberBranches = branchingObject_->numberBranches();
+  changes_ = new double [numberBranches];
+  iterationCounts_ = new int [numberBranches];
+  statuses_ = new int [numberBranches];
+  CoinZeroN(changes_,numberBranches);
+  CoinZeroN(iterationCounts_,numberBranches);
+  CoinFillN(statuses_,numberBranches,-1);
+}
+
+OsiHotInfo::OsiHotInfo(const OsiHotInfo & rhs) 
+{  
+  originalObjectiveValue_ = rhs.originalObjectiveValue_;
+  whichObject_ = rhs.whichObject_;
+  if (rhs.branchingObject_) {
+    branchingObject_ = rhs.branchingObject_->clone();
+    int numberBranches = branchingObject_->numberBranches();
+    changes_ = CoinCopyOfArray(rhs.changes_,numberBranches);
+    iterationCounts_ = CoinCopyOfArray(rhs.iterationCounts_,numberBranches);
+    statuses_ = CoinCopyOfArray(rhs.statuses_,numberBranches);
+  } else {
+    branchingObject_ = NULL;
+    changes_ = NULL;
+    iterationCounts_ = NULL;
+    statuses_ = NULL;
+  }
+}
+
+OsiHotInfo &
+OsiHotInfo::operator=(const OsiHotInfo & rhs)
+{
+  if (this != &rhs) {
+    delete branchingObject_;
+    delete [] changes_;
+    delete [] iterationCounts_;
+    delete [] statuses_;
+    originalObjectiveValue_ = rhs.originalObjectiveValue_;
+    whichObject_ = rhs.whichObject_;
+    if (rhs.branchingObject_) {
+      branchingObject_ = rhs.branchingObject_->clone();
+      int numberBranches = branchingObject_->numberBranches();
+      changes_ = CoinCopyOfArray(rhs.changes_,numberBranches);
+      iterationCounts_ = CoinCopyOfArray(rhs.iterationCounts_,numberBranches);
+      statuses_ = CoinCopyOfArray(rhs.statuses_,numberBranches);
+    } else {
+      branchingObject_ = NULL;
+      changes_ = NULL;
+      iterationCounts_ = NULL;
+      statuses_ = NULL;
+    }
+  }
+  return *this;
+}
+
+
+OsiHotInfo::~OsiHotInfo ()
+{
+  delete branchingObject_;
+  delete [] changes_;
+  delete [] iterationCounts_;
+  delete [] statuses_;
+}
+
+// Clone
+OsiHotInfo *
+OsiHotInfo::clone() const
+{
+  return new OsiHotInfo(*this);
+}
+/* Fill in useful information after strong branch 
+ */
+int OsiHotInfo::updateInformation( const OsiSolverInterface * solver, const OsiBranchingInformation * info,
+				   OsiChooseVariable * choose)
+{
+  int iBranch = branchingObject_->branchIndex()-1;
+  assert (iBranch>=0&&iBranch<branchingObject_->numberBranches());
+  iterationCounts_[iBranch] += solver->getIterationCount();
+  int status;
+  if (solver->isProvenOptimal())
+    status=0; // optimal
+  else if (solver->isIterationLimitReached()
+	   &&!solver->isDualObjectiveLimitReached())
+    status=2; // unknown 
+  else
+    status=1; // infeasible
+  // Could do something different if we can't trust
+  double newObjectiveValue = solver->getObjSense()*solver->getObjValue();
+  changes_[iBranch] =CoinMax(0.0,newObjectiveValue-originalObjectiveValue_);
+  // we might have got here by primal
+  if (choose->trustStrongForBound()) {
+    if (!status&&newObjectiveValue>=info->cutoff_) {
+      status=1; // infeasible
+      changes_[iBranch] = 1.0e100;
+    }
+  }
+  statuses_[iBranch] = status;
+  if (!status&&choose->trustStrongForSolution()&&newObjectiveValue<choose->goodObjectiveValue()) {
+    // check if solution
+    const OsiSolverInterface * saveSolver = info->solver_;
+    info->solver_=solver;
+    const double * saveLower = info->lower_;
+    info->lower_ = solver->getColLower();
+    const double * saveUpper = info->upper_;
+    info->upper_ = solver->getColUpper();
+    // also need to make sure bounds OK as may not be info solver
+#if 0
+    if (saveSolver->getMatrixByCol()) {
+	const CoinBigIndex * columnStart = info->columnStart_;
+	assert (saveSolver->getMatrixByCol()->getVectorStarts()==columnStart);
+    }
+#endif
+    if (choose->feasibleSolution(info,solver->getColSolution(),solver->numberObjects(),
+				 const_cast<const OsiObject **> (solver->objects()))) {
+      // put solution somewhere
+      choose->saveSolution(solver);
+      status=3;
+    }
+    info->solver_=saveSolver;
+    info->lower_ = saveLower;
+    info->upper_ = saveUpper;
+  }
+  // Now update - possible strong branching info
+  choose->updateInformation( info,iBranch,this);
+  return status;
+}
diff --git a/cbits/coin/OsiChooseVariable.hpp b/cbits/coin/OsiChooseVariable.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiChooseVariable.hpp
@@ -0,0 +1,534 @@
+// Copyright (C) 2006, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiChooseVariable_H
+#define OsiChooseVariable_H
+
+#include <string>
+#include <vector>
+
+#include "CoinWarmStartBasis.hpp"
+#include "OsiBranchingObject.hpp"
+
+class OsiSolverInterface;
+class OsiHotInfo;
+
+/** This class chooses a variable to branch on
+
+    The base class just chooses the variable and direction without strong branching but it 
+    has information which would normally be used by strong branching e.g. to re-enter
+    having fixed a variable but using same candidates for strong branching.
+
+    The flow is :
+    a) initialize the process.  This decides on strong branching list
+       and stores indices of all infeasible objects  
+    b) do strong branching on list.  If list is empty then just
+       choose one candidate and return without strong branching.  If not empty then
+       go through list and return best.  However we may find that the node is infeasible
+       or that we can fix a variable.  If so we return and it is up to user to call
+       again (after fixing a variable).
+*/
+
+class OsiChooseVariable  {
+ 
+public:
+    
+  /// Default Constructor 
+  OsiChooseVariable ();
+
+  /// Constructor from solver (so we can set up arrays etc)
+  OsiChooseVariable (const OsiSolverInterface * solver);
+
+  /// Copy constructor 
+  OsiChooseVariable (const OsiChooseVariable &);
+   
+  /// Assignment operator 
+  OsiChooseVariable & operator= (const OsiChooseVariable& rhs);
+
+  /// Clone
+  virtual OsiChooseVariable * clone() const;
+
+  /// Destructor 
+  virtual ~OsiChooseVariable ();
+
+  /** Sets up strong list and clears all if initialize is true.
+      Returns number of infeasibilities. 
+      If returns -1 then has worked out node is infeasible!
+  */
+  virtual int setupList ( OsiBranchingInformation *info, bool initialize);
+  /** Choose a variable
+      Returns - 
+     -1 Node is infeasible
+     0  Normal termination - we have a candidate
+     1  All looks satisfied - no candidate
+     2  We can change the bound on a variable - but we also have a strong branching candidate
+     3  We can change the bound on a variable - but we have a non-strong branching candidate
+     4  We can change the bound on a variable - no other candidates
+     We can pick up branch from bestObjectIndex() and bestWhichWay()
+     We can pick up a forced branch (can change bound) from firstForcedObjectIndex() and firstForcedWhichWay()
+     If we have a solution then we can pick up from goodObjectiveValue() and goodSolution()
+     If fixVariables is true then 2,3,4 are all really same as problem changed
+  */
+  virtual int chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *info, bool fixVariables);
+  /// Returns true if solution looks feasible against given objects
+  virtual bool feasibleSolution(const OsiBranchingInformation * info,
+			const double * solution,
+			int numberObjects,
+			const OsiObject ** objects);
+  /// Saves a good solution
+  void saveSolution(const OsiSolverInterface * solver);
+  /// Clears out good solution after use
+  void clearGoodSolution();
+  /// Given a candidate fill in useful information e.g. estimates
+  virtual void updateInformation( const OsiBranchingInformation *info,
+				  int branch, OsiHotInfo * hotInfo);
+#if 1
+  /// Given a branch fill in useful information e.g. estimates
+  virtual void updateInformation( int whichObject, int branch, 
+				  double changeInObjective, double changeInValue,
+				  int status);
+#endif
+  /// Objective value for feasible solution
+  inline double goodObjectiveValue() const
+  { return goodObjectiveValue_;}
+  /// Estimate of up change or change on chosen if n-way
+  inline double upChange() const
+  { return upChange_;}
+  /// Estimate of down change or max change on other possibilities if n-way
+  inline double downChange() const
+  { return downChange_;}
+  /// Good solution - deleted by finalize
+  inline const double * goodSolution() const
+  { return goodSolution_;}
+  /// Index of chosen object
+  inline int bestObjectIndex() const
+  { return bestObjectIndex_;}
+  /// Set index of chosen object
+  inline void setBestObjectIndex(int value)
+  { bestObjectIndex_ = value;}
+  /// Preferred way of chosen object
+  inline int bestWhichWay() const
+  { return bestWhichWay_;}
+  /// Set preferred way of chosen object
+  inline void setBestWhichWay(int value)
+  { bestWhichWay_ = value;}
+  /// Index of forced object
+  inline int firstForcedObjectIndex() const
+  { return firstForcedObjectIndex_;}
+  /// Set index of forced object
+  inline void setFirstForcedObjectIndex(int value)
+  { firstForcedObjectIndex_ = value;}
+  /// Preferred way of forced object
+  inline int firstForcedWhichWay() const
+  { return firstForcedWhichWay_;}
+  /// Set preferred way of forced object
+  inline void setFirstForcedWhichWay(int value)
+  { firstForcedWhichWay_ = value;}
+  /// Get the number of objects unsatisfied at this node - accurate on first pass
+  inline int numberUnsatisfied() const
+  {return numberUnsatisfied_;}
+  /// Number of objects to choose for strong branching
+  inline int numberStrong() const
+  { return numberStrong_;}
+  /// Set number of objects to choose for strong branching
+  inline void setNumberStrong(int value)
+  { numberStrong_ = value;}
+  /// Number left on strong list
+  inline int numberOnList() const
+  { return numberOnList_;}
+  /// Number of strong branches actually done 
+  inline int numberStrongDone() const
+  { return numberStrongDone_;}
+  /// Number of strong iterations actually done 
+  inline int numberStrongIterations() const
+  { return numberStrongIterations_;}
+  /// Number of strong branches which changed bounds 
+  inline int numberStrongFixed() const
+  { return numberStrongFixed_;}
+  /// List of candidates
+  inline const int * candidates() const
+  { return list_;}
+  /// Trust results from strong branching for changing bounds
+  inline bool trustStrongForBound() const
+  { return trustStrongForBound_;}
+  /// Set trust results from strong branching for changing bounds
+  inline void setTrustStrongForBound(bool yesNo)
+  { trustStrongForBound_ = yesNo;}
+  /// Trust results from strong branching for valid solution
+  inline bool trustStrongForSolution() const
+  { return trustStrongForSolution_;}
+  /// Set trust results from strong branching for valid solution
+  inline void setTrustStrongForSolution(bool yesNo)
+  { trustStrongForSolution_ = yesNo;}
+  /// Set solver and redo arrays
+  void setSolver (const OsiSolverInterface * solver);
+  /** Return status - 
+     -1 Node is infeasible
+     0  Normal termination - we have a candidate
+     1  All looks satisfied - no candidate
+     2  We can change the bound on a variable - but we also have a strong branching candidate
+     3  We can change the bound on a variable - but we have a non-strong branching candidate
+     4  We can change the bound on a variable - no other candidates
+     We can pick up branch from bestObjectIndex() and bestWhichWay()
+     We can pick up a forced branch (can change bound) from firstForcedObjectIndex() and firstForcedWhichWay()
+     If we have a solution then we can pick up from goodObjectiveValue() and goodSolution()
+  */
+  inline int status() const
+  { return status_;}
+  inline void setStatus(int value)
+  { status_ = value;}
+
+
+protected:
+  // Data
+  /// Objective value for feasible solution
+  double goodObjectiveValue_;
+  /// Estimate of up change or change on chosen if n-way
+  double upChange_;
+  /// Estimate of down change or max change on other possibilities if n-way
+  double downChange_;
+  /// Good solution - deleted by finalize
+  double * goodSolution_;
+  /// List of candidates
+  int * list_;
+  /// Useful array (for sorting etc)
+  double * useful_;
+  /// Pointer to solver
+  const OsiSolverInterface * solver_;
+  /* Status -
+     -1 Node is infeasible
+     0  Normal termination - we have a candidate
+     1  All looks satisfied - no candidate
+     2  We can change the bound on a variable - but we also have a strong branching candidate
+     3  We can change the bound on a variable - but we have a non-strong branching candidate
+     4  We can change the bound on a variable - no other candidates
+  */
+  int status_;
+  /// Index of chosen object
+  int bestObjectIndex_;
+  /// Preferred way of chosen object
+  int bestWhichWay_;
+  /// Index of forced object
+  int firstForcedObjectIndex_;
+  /// Preferred way of forced object
+  int firstForcedWhichWay_;
+  /// The number of objects unsatisfied at this node.
+  int numberUnsatisfied_;
+  /// Number of objects to choose for strong branching
+  int numberStrong_;
+  /// Number left on strong list
+  int numberOnList_;
+  /// Number of strong branches actually done 
+  int numberStrongDone_;
+  /// Number of strong iterations actually done 
+  int numberStrongIterations_;
+  /// Number of bound changes due to strong branching
+  int numberStrongFixed_;
+  /// List of unsatisfied objects - first numberOnList_ for strong branching
+  /// Trust results from strong branching for changing bounds
+  bool trustStrongForBound_;
+  /// Trust results from strong branching for valid solution
+  bool trustStrongForSolution_;
+};
+
+/** This class is the placeholder for the pseudocosts used by OsiChooseStrong.
+    It can also be used by any other pseudocost based strong branching
+    algorithm.
+*/
+
+class OsiPseudoCosts {
+protected:
+   // Data
+  /// Total of all changes up
+  double * upTotalChange_;
+  /// Total of all changes down
+  double * downTotalChange_;
+  /// Number of times up
+  int * upNumber_;
+  /// Number of times down
+  int * downNumber_;
+  /// Number of objects (could be found from solver)
+  int numberObjects_;
+  /// Number before we trust
+  int numberBeforeTrusted_;
+
+private:
+  void gutsOfDelete();
+  void gutsOfCopy(const OsiPseudoCosts& rhs);
+
+public:
+  OsiPseudoCosts();
+  virtual ~OsiPseudoCosts();
+  OsiPseudoCosts(const OsiPseudoCosts& rhs);
+  OsiPseudoCosts& operator=(const OsiPseudoCosts& rhs);
+
+  /// Number of times before trusted
+  inline int numberBeforeTrusted() const
+  { return numberBeforeTrusted_; }
+  /// Set number of times before trusted
+  inline void setNumberBeforeTrusted(int value)
+  { numberBeforeTrusted_ = value; }
+  /// Initialize the pseudocosts with n entries
+  void initialize(int n);
+  /// Give the number of objects for which pseudo costs are stored
+  inline int numberObjects() const
+  { return numberObjects_; }
+
+  /** @name Accessor methods to pseudo costs data */
+  //@{
+  inline double* upTotalChange()               { return upTotalChange_; }
+  inline const double* upTotalChange() const   { return upTotalChange_; }
+
+  inline double* downTotalChange()             { return downTotalChange_; }
+  inline const double* downTotalChange() const { return downTotalChange_; }
+
+  inline int* upNumber()                       { return upNumber_; }
+  inline const int* upNumber() const           { return upNumber_; }
+
+  inline int* downNumber()                     { return downNumber_; }
+  inline const int* downNumber() const         { return downNumber_; }
+  //@}
+
+  /// Given a candidate fill in useful information e.g. estimates
+  virtual void updateInformation(const OsiBranchingInformation *info,
+				  int branch, OsiHotInfo * hotInfo);
+#if 1 
+  /// Given a branch fill in useful information e.g. estimates
+  virtual void updateInformation( int whichObject, int branch, 
+				  double changeInObjective, double changeInValue,
+				  int status);
+#endif
+};
+
+/** This class chooses a variable to branch on
+
+    This chooses the variable and direction with reliability strong branching.
+
+    The flow is :
+    a) initialize the process.  This decides on strong branching list
+       and stores indices of all infeasible objects  
+    b) do strong branching on list.  If list is empty then just
+       choose one candidate and return without strong branching.  If not empty then
+       go through list and return best.  However we may find that the node is infeasible
+       or that we can fix a variable.  If so we return and it is up to user to call
+       again (after fixing a variable).
+*/
+
+class OsiChooseStrong  : public OsiChooseVariable {
+ 
+public:
+    
+  /// Default Constructor 
+  OsiChooseStrong ();
+
+  /// Constructor from solver (so we can set up arrays etc)
+  OsiChooseStrong (const OsiSolverInterface * solver);
+
+  /// Copy constructor 
+  OsiChooseStrong (const OsiChooseStrong &);
+   
+  /// Assignment operator 
+  OsiChooseStrong & operator= (const OsiChooseStrong& rhs);
+
+  /// Clone
+  virtual OsiChooseVariable * clone() const;
+
+  /// Destructor 
+  virtual ~OsiChooseStrong ();
+
+  /** Sets up strong list and clears all if initialize is true.
+      Returns number of infeasibilities. 
+      If returns -1 then has worked out node is infeasible!
+  */
+  virtual int setupList ( OsiBranchingInformation *info, bool initialize);
+  /** Choose a variable
+      Returns - 
+     -1 Node is infeasible
+     0  Normal termination - we have a candidate
+     1  All looks satisfied - no candidate
+     2  We can change the bound on a variable - but we also have a strong branching candidate
+     3  We can change the bound on a variable - but we have a non-strong branching candidate
+     4  We can change the bound on a variable - no other candidates
+     We can pick up branch from bestObjectIndex() and bestWhichWay()
+     We can pick up a forced branch (can change bound) from firstForcedObjectIndex() and firstForcedWhichWay()
+     If we have a solution then we can pick up from goodObjectiveValue() and goodSolution()
+     If fixVariables is true then 2,3,4 are all really same as problem changed
+  */
+  virtual int chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation *info, bool fixVariables);
+
+  /** Pseudo Shadow Price mode
+      0 - off
+      1 - use if no strong info
+      2 - use if strong not trusted
+      3 - use even if trusted
+  */
+  inline int shadowPriceMode() const
+  { return shadowPriceMode_;}
+  /// Set Shadow price mode
+  inline void setShadowPriceMode(int value)
+  { shadowPriceMode_ = value;}
+
+  /** Accessor method to pseudo cost object*/
+  const OsiPseudoCosts& pseudoCosts() const
+  { return pseudoCosts_; }
+
+  /** Accessor method to pseudo cost object*/
+  OsiPseudoCosts& pseudoCosts()
+  { return pseudoCosts_; }
+
+  /** A feww pass-through methods to access members of pseudoCosts_ as if they
+      were members of OsiChooseStrong object */
+  inline int numberBeforeTrusted() const {
+    return pseudoCosts_.numberBeforeTrusted(); }
+  inline void setNumberBeforeTrusted(int value) {
+    pseudoCosts_.setNumberBeforeTrusted(value); }
+  inline int numberObjects() const {
+    return pseudoCosts_.numberObjects(); }
+
+protected:
+
+  /**  This is a utility function which does strong branching on
+       a list of objects and stores the results in OsiHotInfo.objects.
+       On entry the object sequence is stored in the OsiHotInfo object
+       and maybe more.
+       It returns -
+       -1 - one branch was infeasible both ways
+       0 - all inspected - nothing can be fixed
+       1 - all inspected - some can be fixed (returnCriterion==0)
+       2 - may be returning early - one can be fixed (last one done) (returnCriterion==1) 
+       3 - returning because max time
+       
+  */
+  int doStrongBranching( OsiSolverInterface * solver, 
+			 OsiBranchingInformation *info,
+			 int numberToDo, int returnCriterion);
+
+  /** Clear out the results array */
+  void resetResults(int num);
+
+protected:
+  /** Pseudo Shadow Price mode
+      0 - off
+      1 - use and multiply by strong info
+      2 - use 
+  */
+  int shadowPriceMode_;
+
+  /** The pseudo costs for the chooser */
+  OsiPseudoCosts pseudoCosts_;
+
+  /** The results of the strong branching done on the candidates where the
+      pseudocosts were not sufficient */
+  OsiHotInfo* results_;
+  /** The number of OsiHotInfo objetcs that contain information */
+  int numResults_;
+};
+
+/** This class contains the result of strong branching on a variable
+    When created it stores enough information for strong branching
+*/
+
+class OsiHotInfo  {
+ 
+public:
+    
+  /// Default Constructor 
+  OsiHotInfo ();
+
+  /// Constructor from useful information
+  OsiHotInfo ( OsiSolverInterface * solver, 
+	       const OsiBranchingInformation *info,
+	       const OsiObject * const * objects,
+	       int whichObject);
+
+  /// Copy constructor 
+  OsiHotInfo (const OsiHotInfo &);
+   
+  /// Assignment operator 
+  OsiHotInfo & operator= (const OsiHotInfo& rhs);
+
+  /// Clone
+  virtual OsiHotInfo * clone() const;
+
+  /// Destructor 
+  virtual ~OsiHotInfo ();
+
+  /** Fill in useful information after strong branch.
+      Return status
+  */
+  int updateInformation( const OsiSolverInterface * solver, const OsiBranchingInformation * info,
+			 OsiChooseVariable * choose);
+  /// Original objective value
+  inline double originalObjectiveValue() const
+  { return originalObjectiveValue_;}
+  /// Up change  - invalid if n-way
+  inline double upChange() const
+  { assert (branchingObject_->numberBranches()==2); return changes_[1];}
+  /// Down change  - invalid if n-way
+  inline double downChange() const
+  { assert (branchingObject_->numberBranches()==2); return changes_[0];}
+  /// Set up change  - invalid if n-way
+  inline void setUpChange(double value)
+  { assert (branchingObject_->numberBranches()==2); changes_[1] = value;}
+  /// Set down change  - invalid if n-way
+  inline void setDownChange(double value)
+  { assert (branchingObject_->numberBranches()==2); changes_[0] = value;}
+  /// Change on way k
+  inline double change(int k) const
+  { return changes_[k];}
+
+  /// Up iteration count  - invalid if n-way
+  inline int upIterationCount() const
+  { assert (branchingObject_->numberBranches()==2); return iterationCounts_[1];}
+  /// Down iteration count  - invalid if n-way
+  inline int downIterationCount() const
+  { assert (branchingObject_->numberBranches()==2); return iterationCounts_[0];}
+  /// Iteration count on way k
+  inline int iterationCount(int k) const
+  { return iterationCounts_[k];}
+
+  /// Up status  - invalid if n-way
+  inline int upStatus() const
+  { assert (branchingObject_->numberBranches()==2); return statuses_[1];}
+  /// Down status  - invalid if n-way
+  inline int downStatus() const
+  { assert (branchingObject_->numberBranches()==2); return statuses_[0];}
+  /// Set up status  - invalid if n-way
+  inline void setUpStatus(int value)
+  { assert (branchingObject_->numberBranches()==2); statuses_[1] = value;}
+  /// Set down status  - invalid if n-way
+  inline void setDownStatus(int value)
+  { assert (branchingObject_->numberBranches()==2); statuses_[0] = value;}
+  /// Status on way k
+  inline int status(int k) const
+  { return statuses_[k];}
+  /// Branching object
+  inline OsiBranchingObject * branchingObject() const
+  { return branchingObject_;}
+  inline int whichObject() const
+  { return whichObject_;}
+
+protected:
+  // Data
+  /// Original objective value
+  double originalObjectiveValue_;
+    /// Objective changes
+  double * changes_;
+  /// Iteration counts
+  int * iterationCounts_;
+  /** Status
+      -1 - not done
+      0 - feasible and finished
+      1 -  infeasible
+      2 - not finished
+  */
+  int * statuses_;
+  /// Branching object
+  OsiBranchingObject * branchingObject_;
+  /// Which object on list
+  int whichObject_;
+};
+
+
+#endif
diff --git a/cbits/coin/OsiClpSolverInterface.cpp b/cbits/coin/OsiClpSolverInterface.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiClpSolverInterface.cpp
@@ -0,0 +1,9515 @@
+// $Id$
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cassert>
+#ifdef CBC_STATISTICS
+extern int osi_crunch;
+extern int osi_primal;
+extern int osi_dual;
+extern int osi_hot;
+#endif 
+#include "CoinTime.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinModel.hpp"
+#include "CoinMpsIO.hpp"
+#include "CoinSort.hpp"
+#include "ClpDualRowSteepest.hpp"
+#include "ClpPrimalColumnSteepest.hpp"
+#include "ClpPackedMatrix.hpp"
+#include "ClpDualRowDantzig.hpp"
+#include "ClpPrimalColumnDantzig.hpp"
+#include "ClpFactorization.hpp"
+#include "ClpObjective.hpp"
+#include "ClpSimplex.hpp"
+#include "ClpSimplexOther.hpp"
+#include "ClpSimplexPrimal.hpp"
+#include "ClpSimplexDual.hpp"
+#include "ClpNonLinearCost.hpp"
+#include "OsiClpSolverInterface.hpp"
+#include "OsiBranchingObject.hpp"
+#include "OsiCuts.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiColCut.hpp"
+#include "ClpPresolve.hpp"
+#include "CoinLpIO.hpp"
+static double totalTime=0.0;
+//#define SAVE_MODEL 1
+#ifdef SAVE_MODEL
+static int resolveTry=0;
+static int loResolveTry=0;
+static int hiResolveTry=9999999;
+#endif
+//#############################################################################
+// Solve methods
+//#############################################################################
+void OsiClpSolverInterface::initialSolve()
+{
+#define KEEP_SMALL
+#ifdef KEEP_SMALL
+  if (smallModel_) {
+    delete [] spareArrays_;
+    spareArrays_ = NULL;
+    delete smallModel_;
+    smallModel_=NULL;
+  }
+#endif
+  if ((specialOptions_&2097152)!=0||(specialOptions_&4194304)!=0) {
+    bool takeHint;
+    OsiHintStrength strength;
+    int algorithm = 0;
+    getHintParam(OsiDoDualInInitial,takeHint,strength);
+    if (strength!=OsiHintIgnore)
+      algorithm = takeHint ? -1 : 1;
+    if (algorithm>0||(specialOptions_&4194304)!=0) {
+      // Gub
+      resolveGub((9*modelPtr_->numberRows())/10);
+      return;
+    }
+  }
+  bool deleteSolver;
+  ClpSimplex * solver;
+  double time1 = CoinCpuTime();
+  int userFactorizationFrequency = modelPtr_->factorization()->maximumPivots();
+  int totalIterations=0;
+  bool abortSearch=false;
+  ClpObjective * savedObjective=NULL;
+  double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit];
+  if (fakeObjective_) {
+    // Clear (no objective, 0-1 and in B&B)
+    modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~128));
+    // See if all with costs fixed
+    int numberColumns = modelPtr_->numberColumns_;
+    const double * obj = modelPtr_->objective();
+    const double * lower = modelPtr_->columnLower();
+    const double * upper = modelPtr_->columnUpper();
+    int i;
+    for (i=0;i<numberColumns;i++) {
+      double objValue = obj[i];
+      if (objValue) {
+	if (lower[i]!=upper[i])
+	  break;
+      }
+    }
+    if (i==numberColumns) {
+      // Check (Clp fast dual)
+      if ((specialOptions_&524288)==0) {
+	// Set fake
+	savedObjective=modelPtr_->objective_;
+	modelPtr_->objective_=fakeObjective_;
+	modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX;
+      } else {
+	// Set (no objective, 0-1 and in B&B)
+	modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()|128);
+      }
+    }
+  }
+  // Check (in branch and bound)
+  if ((specialOptions_&1024)==0) {
+    solver = new ClpSimplex(true);
+    deleteSolver=true;
+    solver->borrowModel(*modelPtr_);
+    // See if user set factorization frequency
+    // borrowModel does not move
+    solver->factorization()->maximumPivots(userFactorizationFrequency);
+  } else {
+    solver = modelPtr_;
+    deleteSolver=false;
+  }
+  // Treat as if user simplex not enabled
+  int saveSolveType=solver->solveType();
+  bool doingPrimal = solver->algorithm()>0;
+  if (saveSolveType==2) {
+    disableSimplexInterface();
+    solver->setSolveType(1);
+  }
+  int saveOptions = solver->specialOptions();
+  solver->setSpecialOptions(saveOptions|64|32768); // go as far as possible
+  // get original log levels
+  int saveMessageLevel=modelPtr_->logLevel();
+  int messageLevel=messageHandler()->logLevel();
+  int saveMessageLevel2 = messageLevel;
+  // Set message handler
+  if (!defaultHandler_)
+    solver->passInMessageHandler(handler_);
+  // But keep log level
+  solver->messageHandler()->setLogLevel(saveMessageLevel);
+  // set reasonable defaults
+  bool takeHint;
+  OsiHintStrength strength;
+  // Switch off printing if asked to
+  bool gotHint = (getHintParam(OsiDoReducePrint,takeHint,strength));
+  assert (gotHint);
+  if (strength!=OsiHintIgnore&&takeHint) {
+    if (messageLevel>0)
+      messageLevel--;
+  }
+  if (messageLevel<saveMessageLevel)
+    solver->messageHandler()->setLogLevel(messageLevel);
+  // Allow for specialOptions_==1+8 forcing saving factorization
+  int startFinishOptions=0;
+  if ((specialOptions_&9)==(1+8)) {
+    startFinishOptions =1+2+4; // allow re-use of factorization
+  }
+  bool defaultHints=true;
+  {
+    int hint;
+    for (hint=OsiDoPresolveInInitial;hint<OsiLastHintParam;hint++) {
+      if (hint!=OsiDoReducePrint&&
+          hint!=OsiDoInBranchAndCut) {
+        bool yesNo;
+        OsiHintStrength strength;
+        getHintParam(static_cast<OsiHintParam> (hint),yesNo,strength);
+        if (yesNo) {
+          defaultHints=false;
+          break;
+        }
+        if (strength != OsiHintIgnore) {
+          defaultHints=false;
+          break;
+        }
+      }
+    }
+  }
+  ClpPresolve * pinfo = NULL;
+  /*
+    If basis then do primal (as user could do dual with resolve)
+    If not then see if dual feasible (and allow for gubs etc?)
+  */
+  bool doPrimal = (basis_.numberBasicStructurals()>0);
+  setBasis(basis_,solver);
+  bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
+  if ((!defaultHints||doPrimal)&&!solveOptions_.getSpecialOption(6)) {
+    // scaling
+    // save initial state
+    const double * rowScale1 = solver->rowScale();
+    if (modelPtr_->solveType()==1) {
+      gotHint = (getHintParam(OsiDoScale,takeHint,strength));
+      assert (gotHint);
+      if (strength==OsiHintIgnore||takeHint) {
+        if (!solver->scalingFlag())
+          solver->scaling(3);
+      } else {
+        solver->scaling(0);
+      }
+    } else {
+      solver->scaling(0);
+    }
+    //solver->setDualBound(1.0e6);
+    //solver->setDualTolerance(1.0e-7);
+    
+    //ClpDualRowSteepest steep;
+    //solver->setDualRowPivotAlgorithm(steep);
+    //solver->setPrimalTolerance(1.0e-8);
+    //ClpPrimalColumnSteepest steepP;
+    //solver->setPrimalColumnPivotAlgorithm(steepP);
+    
+    // sort out hints;
+    // algorithm 0 whatever, -1 force dual, +1 force primal
+    int algorithm = 0;
+    gotHint = (getHintParam(OsiDoDualInInitial,takeHint,strength));
+    assert (gotHint);
+    if (strength!=OsiHintIgnore)
+      algorithm = takeHint ? -1 : 1;
+    // crash 0 do lightweight if all slack, 1 do, -1 don't
+    int doCrash=0;
+    gotHint = (getHintParam(OsiDoCrash,takeHint,strength));
+    assert (gotHint);
+    if (strength!=OsiHintIgnore)
+      doCrash = takeHint ? 1 : -1;
+    // doPrimal set true if any structurals in basis so switch off crash
+    if (doPrimal)
+      doCrash = -1;
+    
+    // presolve
+    gotHint = (getHintParam(OsiDoPresolveInInitial,takeHint,strength));
+    assert (gotHint);
+    if (strength!=OsiHintIgnore&&takeHint) {
+      pinfo = new ClpPresolve();
+      ClpSimplex * model2 = pinfo->presolvedModel(*solver,1.0e-8);
+      if (!model2) {
+        // problem found to be infeasible - whats best?
+        model2 = solver;
+	delete pinfo;
+	pinfo = NULL;
+      } else {
+	model2->setSpecialOptions(solver->specialOptions());
+      }
+      
+      // change from 200 (unless changed)
+      if (modelPtr_->factorization()->maximumPivots()==200)
+        model2->factorization()->maximumPivots(100+model2->numberRows()/50);
+      else
+        model2->factorization()->maximumPivots(userFactorizationFrequency);
+      int savePerturbation = model2->perturbation();
+      if (savePerturbation==100)
+        model2->setPerturbation(50);
+      if (!doPrimal) {
+        // faster if bounds tightened
+        //int numberInfeasibilities = model2->tightenPrimalBounds();
+        model2->tightenPrimalBounds();
+        // look further
+        bool crashResult=false;
+        if (doCrash>0)
+          crashResult =  (solver->crash(1000.0,1)>0);
+        else if (doCrash==0&&algorithm>0)
+          crashResult =  (solver->crash(1000.0,1)>0);
+        doPrimal=crashResult;
+      }
+      if (algorithm<0)
+        doPrimal=false;
+      else if (algorithm>0)
+        doPrimal=true;
+      if (!doPrimal) {
+        //if (numberInfeasibilities)
+        //std::cout<<"** Analysis indicates model infeasible"
+        //       <<std::endl;
+        // up dual bound for safety
+        //model2->setDualBound(1.0e11);
+	disasterHandler_->setOsiModel(this);
+	if (inCbcOrOther) {
+	  disasterHandler_->setSimplex(model2);
+	  disasterHandler_->setWhereFrom(4);
+	  model2->setDisasterHandler(disasterHandler_);
+	}
+        model2->dual(0);
+	totalIterations += model2->numberIterations();
+	if (inCbcOrOther) {
+	  if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	    printf("dual trouble a\n");
+#endif
+	    if (disasterHandler_->typeOfDisaster()) {
+	      // We want to abort 
+	      abortSearch=true;
+	      goto disaster;
+	    }
+	    // try just going back in
+	    disasterHandler_->setPhase(1);
+	    model2->dual();
+	    totalIterations += model2->numberIterations();
+	    if (disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("dual trouble b\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      // try primal with original basis
+	      disasterHandler_->setPhase(2);
+	      setBasis(basis_,model2);
+	      model2->primal();
+	      totalIterations += model2->numberIterations();
+	    }
+	    if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("disaster - treat as infeasible\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      model2->setProblemStatus(1);
+	    }
+	  }
+	  // reset
+	  model2->setDisasterHandler(NULL);
+	}
+        // check if clp thought it was in a loop
+        if (model2->status()==3&&!model2->hitMaximumIterations()) {
+          // switch algorithm
+	  disasterHandler_->setOsiModel(this);
+	  if (inCbcOrOther) {
+	    disasterHandler_->setSimplex(model2);
+	    disasterHandler_->setWhereFrom(6);
+	    model2->setDisasterHandler(disasterHandler_);
+	  }
+          model2->primal();
+	  totalIterations += model2->numberIterations();
+	  if (inCbcOrOther) {
+	    if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("primal trouble a\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      // try just going back in (but with dual)
+	      disasterHandler_->setPhase(1);
+	      model2->dual();
+	      totalIterations += model2->numberIterations();
+	      if (disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+		printf("primal trouble b\n");
+#endif
+		if (disasterHandler_->typeOfDisaster()) {
+		  // We want to abort 
+		  abortSearch=true;
+		  goto disaster;
+		}
+		// try primal with original basis
+		disasterHandler_->setPhase(2);
+		setBasis(basis_,model2);
+		model2->dual();
+		totalIterations += model2->numberIterations();
+	      }
+	      if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+		printf("disaster - treat as infeasible\n");
+#endif
+		if (disasterHandler_->typeOfDisaster()) {
+		  // We want to abort 
+		  abortSearch=true;
+		  goto disaster;
+		}
+		model2->setProblemStatus(1);
+	      }
+	    }
+	    // reset
+	    model2->setDisasterHandler(NULL);
+	  }
+        }
+      } else {
+        // up infeasibility cost for safety
+        //model2->setInfeasibilityCost(1.0e10);
+	disasterHandler_->setOsiModel(this);
+	if (inCbcOrOther) {
+	  disasterHandler_->setSimplex(model2);
+	  disasterHandler_->setWhereFrom(6);
+	  model2->setDisasterHandler(disasterHandler_);
+	}
+        model2->primal(1);
+	totalIterations += model2->numberIterations();
+	if (inCbcOrOther) {
+	  if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	    printf("primal trouble a\n");
+#endif
+	    if (disasterHandler_->typeOfDisaster()) {
+	      // We want to abort 
+	      abortSearch=true;
+	      goto disaster;
+	    }
+	    // try just going back in (but with dual)
+	    disasterHandler_->setPhase(1);
+	    model2->dual();
+	    totalIterations += model2->numberIterations();
+	    if (disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("primal trouble b\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      // try primal with original basis
+	      disasterHandler_->setPhase(2);
+	      setBasis(basis_,model2);
+	      model2->dual();
+	      totalIterations += model2->numberIterations();
+	    }
+	    if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("disaster - treat as infeasible\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      model2->setProblemStatus(1);
+	    }
+	  }
+	  // reset
+	  model2->setDisasterHandler(NULL);
+	}
+        // check if clp thought it was in a loop
+        if (model2->status()==3&&!model2->hitMaximumIterations()) {
+          // switch algorithm
+	  disasterHandler_->setOsiModel(this);
+	  if (inCbcOrOther) {
+	    disasterHandler_->setSimplex(model2);
+	    disasterHandler_->setWhereFrom(4);
+	    model2->setDisasterHandler(disasterHandler_);
+	  }
+	  model2->dual(0);
+	  totalIterations += model2->numberIterations();
+	  if (inCbcOrOther) {
+	    if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("dual trouble a\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      // try just going back in
+	      disasterHandler_->setPhase(1);
+	      model2->dual();
+	      totalIterations += model2->numberIterations();
+	      if (disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+		printf("dual trouble b\n");
+#endif
+		if (disasterHandler_->typeOfDisaster()) {
+		  // We want to abort 
+		  abortSearch=true;
+		goto disaster;
+		}
+		// try primal with original basis
+		disasterHandler_->setPhase(2);
+		setBasis(basis_,model2);
+		model2->primal();
+		totalIterations += model2->numberIterations();
+	      }
+	      if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+		printf("disaster - treat as infeasible\n");
+#endif
+		if (disasterHandler_->typeOfDisaster()) {
+		  // We want to abort 
+		  abortSearch=true;
+		  goto disaster;
+		}
+		model2->setProblemStatus(1);
+	      }
+	    }
+	    // reset
+	    model2->setDisasterHandler(NULL);
+	  }
+        }
+      }
+      model2->setPerturbation(savePerturbation);
+      if (model2!=solver) {
+        int presolvedStatus = model2->status();
+        pinfo->postsolve(true);
+	delete pinfo;
+	pinfo = NULL;
+        
+        delete model2;
+	int oldStatus=solver->status();
+	solver->setProblemStatus(presolvedStatus);
+	if (solver->logLevel()==63) // for gcc 4.6 bug
+	  printf("pstat %d stat %d\n",presolvedStatus,oldStatus);
+        //printf("Resolving from postsolved model\n");
+        // later try without (1) and check duals before solve
+	if (presolvedStatus!=3
+	    &&(presolvedStatus||oldStatus==-1)) {
+	  if (!inCbcOrOther||presolvedStatus!=1) {
+	    disasterHandler_->setOsiModel(this);
+	    if (inCbcOrOther) {
+	      disasterHandler_->setSimplex(solver); // as "borrowed"
+	      disasterHandler_->setWhereFrom(6);
+	      solver->setDisasterHandler(disasterHandler_);
+	    }
+	    solver->primal(1);
+	    totalIterations += solver->numberIterations();
+	    if (inCbcOrOther) {
+	      if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+		printf("primal trouble a\n");
+#endif
+		if (disasterHandler_->typeOfDisaster()) {
+		  // We want to abort 
+		  abortSearch=true;
+		  goto disaster;
+		}
+		// try just going back in (but with dual)
+		disasterHandler_->setPhase(1);
+		solver->dual();
+		totalIterations += solver->numberIterations();
+		if (disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+		  printf("primal trouble b\n");
+#endif
+		  if (disasterHandler_->typeOfDisaster()) {
+		    // We want to abort 
+		    abortSearch=true;
+		    goto disaster;
+		  }
+		  // try primal with original basis
+		  disasterHandler_->setPhase(2);
+		  setBasis(basis_,solver);
+		  solver->dual();
+		  totalIterations += solver->numberIterations();
+		}
+		if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+		  printf("disaster - treat as infeasible\n");
+#endif
+		  if (disasterHandler_->typeOfDisaster()) {
+		    // We want to abort 
+		    abortSearch=true;
+		    goto disaster;
+		  }
+		  solver->setProblemStatus(1);
+		}
+	      }
+	      // reset
+	      solver->setDisasterHandler(NULL);
+	    }
+	  }
+	}
+      }
+      lastAlgorithm_=1; // primal
+      //if (solver->numberIterations())
+      //printf("****** iterated %d\n",solver->numberIterations());
+    } else {
+      // do we want crash
+      if (doCrash>0)
+        solver->crash(1000.0,2);
+      else if (doCrash==0)
+        solver->crash(1000.0,0);
+      if (algorithm<0)
+        doPrimal=false;
+      else if (algorithm>0)
+        doPrimal=true;
+      disasterHandler_->setOsiModel(this);
+      disasterHandler_->setSimplex(solver); // as "borrowed"
+      bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
+      if (!doPrimal) 
+	disasterHandler_->setWhereFrom(4);
+      else
+	disasterHandler_->setWhereFrom(6);
+      if (inCbcOrOther)
+	solver->setDisasterHandler(disasterHandler_);
+      if (!doPrimal) {
+        //printf("doing dual\n");
+        solver->dual(0);
+	totalIterations += solver->numberIterations();
+	if (inCbcOrOther) {
+	  if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	    printf("dual trouble a\n");
+#endif
+	    if (disasterHandler_->typeOfDisaster()) {
+	      // We want to abort 
+	      abortSearch=true;
+	      goto disaster;
+	    }
+	    // try just going back in
+	    disasterHandler_->setPhase(1);
+	    solver->dual();
+	    totalIterations += solver->numberIterations();
+	    if (disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("dual trouble b\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      // try primal with original basis
+	      disasterHandler_->setPhase(2);
+	      setBasis(basis_,solver);
+	      solver->primal();
+	      totalIterations += solver->numberIterations();
+	    }
+	    if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("disaster - treat as infeasible\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      solver->setProblemStatus(1);
+	    }
+	  }
+	  // reset
+	  solver->setDisasterHandler(NULL);
+	}
+        lastAlgorithm_=2; // dual
+        // check if clp thought it was in a loop
+        if (solver->status()==3&&!solver->hitMaximumIterations()) {
+          // switch algorithm
+          solver->primal(0);
+	  totalIterations += solver->numberIterations();
+          lastAlgorithm_=1; // primal
+        }
+      } else {
+        //printf("doing primal\n");
+        solver->primal(1);
+	totalIterations += solver->numberIterations();
+	if (inCbcOrOther) {
+	  if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	    printf("primal trouble a\n");
+#endif
+	    if (disasterHandler_->typeOfDisaster()) {
+	      // We want to abort 
+	      abortSearch=true;
+	      goto disaster;
+	    }
+	    // try just going back in (but with dual)
+	    disasterHandler_->setPhase(1);
+	    solver->dual();
+	    totalIterations += solver->numberIterations();
+	    if (disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("primal trouble b\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      // try primal with original basis
+	      disasterHandler_->setPhase(2);
+	      setBasis(basis_,solver);
+	      solver->dual();
+	      totalIterations += solver->numberIterations();
+	    }
+	    if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("disaster - treat as infeasible\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      solver->setProblemStatus(1);
+	    }
+	  }
+	  // reset
+	  solver->setDisasterHandler(NULL);
+	}
+        lastAlgorithm_=1; // primal
+        // check if clp thought it was in a loop
+        if (solver->status()==3&&!solver->hitMaximumIterations()) {
+          // switch algorithm
+          solver->dual(0);
+	  totalIterations += solver->numberIterations();
+          lastAlgorithm_=2; // dual
+        }
+      }
+    }
+    // If scaled feasible but unscaled infeasible take action
+    if (!solver->status()&&cleanupScaling_) {
+      solver->cleanup(cleanupScaling_);
+    }
+    basis_ = getBasis(solver);
+    //basis_.print();
+    const double * rowScale2 = solver->rowScale();
+    solver->setSpecialOptions(saveOptions);
+    if (!rowScale1&&rowScale2) {
+      // need to release memory
+      if (!solver->savedRowScale_) {
+	solver->setRowScale(NULL);
+	solver->setColumnScale(NULL);
+      } else {
+	solver->rowScale_=NULL;
+	solver->columnScale_=NULL;
+      }
+    }
+  } else {
+    // User doing nothing and all slack basis
+    ClpSolve options=solveOptions_;
+    bool yesNo;
+    OsiHintStrength strength;
+    getHintParam(OsiDoInBranchAndCut,yesNo,strength);
+    if (yesNo) {
+      solver->setSpecialOptions(solver->specialOptions()|1024);
+    }
+    solver->initialSolve(options);
+    totalIterations += solver->numberIterations();
+    lastAlgorithm_ = 2; // say dual
+    // If scaled feasible but unscaled infeasible take action
+    if (!solver->status()&&cleanupScaling_) {
+      solver->cleanup(cleanupScaling_);
+    }
+    basis_ = getBasis(solver);
+    //basis_.print();
+  }
+  solver->messageHandler()->setLogLevel(saveMessageLevel);
+ disaster:
+  if (deleteSolver) {
+    solver->returnModel(*modelPtr_);
+    delete solver;
+  }
+  if (startFinishOptions) {
+    int save = modelPtr_->logLevel();
+    if (save<2) modelPtr_->setLogLevel(0);
+    modelPtr_->dual(0,startFinishOptions);
+    totalIterations += modelPtr_->numberIterations();
+    modelPtr_->setLogLevel(save);
+  }
+  if (saveSolveType==2) {
+    enableSimplexInterface(doingPrimal);
+  }
+  if (savedObjective) {
+    // fix up
+    modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
+    //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
+    modelPtr_->objective_=savedObjective;
+    if (!modelPtr_->problemStatus_) {
+      CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
+      CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
+      if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
+	CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
+      modelPtr_->computeObjectiveValue();
+    }
+  }
+  modelPtr_->setNumberIterations(totalIterations);
+  handler_->setLogLevel(saveMessageLevel2);
+  if (modelPtr_->problemStatus_==3&&lastAlgorithm_==2)
+    modelPtr_->computeObjectiveValue();
+  // mark so we can pick up objective value quickly
+  modelPtr_->upperIn_=0.0;
+  time1 = CoinCpuTime()-time1;
+  totalTime += time1;
+  assert (!modelPtr_->disasterHandler());
+  if (lastAlgorithm_<1||lastAlgorithm_>2)
+    lastAlgorithm_=1;
+  if (abortSearch) {
+    lastAlgorithm_=-911;
+    modelPtr_->setProblemStatus(4);
+  }
+  modelPtr_->whatsChanged_ |= 0x30000;
+#if 0
+  // delete scaled matrix and rowcopy for safety
+  delete modelPtr_->scaledMatrix_;
+  modelPtr_->scaledMatrix_=NULL;
+  delete modelPtr_->rowCopy_;
+  modelPtr_->rowCopy_=NULL;
+#endif
+  //std::cout<<time1<<" seconds - total "<<totalTime<<std::endl;
+  delete pinfo;
+}
+//-----------------------------------------------------------------------------
+void OsiClpSolverInterface::resolve()
+{
+#ifdef COIN_DEVELOP
+  {
+    int i;
+    int n = getNumCols();
+    const double *lower = getColLower() ;
+    const double *upper = getColUpper() ;
+    for (i=0;i<n;i++) {
+      assert (lower[i]<1.0e12);
+      assert (upper[i]>-1.0e12);
+    }
+    n = getNumRows();
+    lower = getRowLower() ;
+    upper = getRowUpper() ;
+    for (i=0;i<n;i++) {
+      assert (lower[i]<1.0e12);
+      assert (upper[i]>-1.0e12);
+    }
+  }
+#endif
+  if ((stuff_.solverOptions_&65536)!=0) {
+    modelPtr_->fastDual2(&stuff_);
+    return;
+  }
+  if ((specialOptions_&2097152)!=0||(specialOptions_&4194304)!=0) {
+    bool takeHint;
+    OsiHintStrength strength;
+    int algorithm = 0;
+    getHintParam(OsiDoDualInResolve,takeHint,strength);
+    if (strength!=OsiHintIgnore)
+      algorithm = takeHint ? -1 : 1;
+    if (algorithm>0||(specialOptions_&4194304)!=0) {
+      // Gub
+      resolveGub((9*modelPtr_->numberRows())/10);
+      return;
+    }
+  }
+  //void pclp(char *);
+  //pclp("res");
+  bool takeHint;
+  OsiHintStrength strength;
+  bool gotHint = (getHintParam(OsiDoInBranchAndCut,takeHint,strength));
+  assert (gotHint);
+  // mark so we can pick up objective value quickly
+  modelPtr_->upperIn_=0.0;
+  if ((specialOptions_&4096)!=0) {
+    // Quick check to see if optimal
+    modelPtr_->checkSolutionInternal();
+    if (modelPtr_->problemStatus()==0) {
+      modelPtr_->setNumberIterations(0);
+      return;
+    }
+  }
+  int totalIterations=0;
+  bool abortSearch=false;
+  ClpObjective * savedObjective=NULL;
+  double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit];
+  if (fakeObjective_) {
+    modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~128));
+    // See if all with costs fixed
+    int numberColumns = modelPtr_->numberColumns_;
+    const double * obj = modelPtr_->objective();
+    const double * lower = modelPtr_->columnLower();
+    const double * upper = modelPtr_->columnUpper();
+    int i;
+    for (i=0;i<numberColumns;i++) {
+      double objValue = obj[i];
+      if (objValue) {
+	if (lower[i]!=upper[i])
+	  break;
+      }
+    }
+    if (i==numberColumns) {
+      if ((specialOptions_&524288)==0) {
+	// Set fake
+	savedObjective=modelPtr_->objective_;
+	modelPtr_->objective_=fakeObjective_;
+	modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX;
+      } else {
+	modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()|128);
+      }
+    }
+  }
+  // If using Clp initialSolve and primal - just do here
+  gotHint = (getHintParam(OsiDoDualInResolve,takeHint,strength));
+  assert (gotHint);
+  if (strength!=OsiHintIgnore&&!takeHint&&solveOptions_.getSpecialOption(6)) {
+    ClpSolve options=solveOptions_;
+    // presolve
+    getHintParam(OsiDoPresolveInResolve,takeHint,strength);
+    if (strength!=OsiHintIgnore&&!takeHint)
+      options.setPresolveType(ClpSolve::presolveOff);
+    int saveOptions = modelPtr_->specialOptions();
+    getHintParam(OsiDoInBranchAndCut,takeHint,strength);
+    if (takeHint) {
+      modelPtr_->setSpecialOptions(modelPtr_->specialOptions()|1024);
+    }
+    setBasis(basis_,modelPtr_);
+    modelPtr_->initialSolve(options);
+    lastAlgorithm_ = 1; // say primal
+    // If scaled feasible but unscaled infeasible take action
+    if (!modelPtr_->status()&&cleanupScaling_) {
+      modelPtr_->cleanup(cleanupScaling_);
+    }
+    modelPtr_->setSpecialOptions(saveOptions); // restore
+    basis_ = getBasis(modelPtr_);
+  }
+  int saveSolveType=modelPtr_->solveType();
+  bool doingPrimal = modelPtr_->algorithm()>0;
+  if (saveSolveType==2) {
+    disableSimplexInterface();
+  }
+  int saveOptions = modelPtr_->specialOptions();
+  int startFinishOptions=0;
+  if (specialOptions_!=0x80000000) {
+    if((specialOptions_&1)==0) {
+      startFinishOptions=0;
+      modelPtr_->setSpecialOptions(saveOptions|(64|1024|32768));
+    } else {
+      startFinishOptions=1+4;
+      if ((specialOptions_&8)!=0)
+        startFinishOptions +=2; // allow re-use of factorization
+      if((specialOptions_&4)==0||!takeHint) 
+        modelPtr_->setSpecialOptions(saveOptions|(64|128|512|1024|4096|32768));
+      else
+        modelPtr_->setSpecialOptions(saveOptions|(64|128|512|1024|2048|4096|32768));
+    }
+  } else {
+    modelPtr_->setSpecialOptions(saveOptions|64|32768);
+  }
+  //printf("options %d size %d\n",modelPtr_->specialOptions(),modelPtr_->numberColumns());
+  //modelPtr_->setSolveType(1);
+  // Set message handler to have same levels etc
+  int saveMessageLevel=modelPtr_->logLevel();
+  int messageLevel=messageHandler()->logLevel();
+  bool oldDefault;
+  CoinMessageHandler * saveHandler = NULL;
+  if (!defaultHandler_)
+    saveHandler = modelPtr_->pushMessageHandler(handler_,oldDefault);
+  //printf("basis before dual\n");
+  //basis_.print();
+  setBasis(basis_,modelPtr_);
+#ifdef SAVE_MODEL
+  resolveTry++;
+#if SAVE_MODEL > 1
+  if (resolveTry>=loResolveTry&&
+      resolveTry<=hiResolveTry) {
+    char fileName[20];
+    sprintf(fileName,"save%d.mod",resolveTry);
+    modelPtr_->saveModel(fileName);
+  }
+#endif
+#endif
+  // set reasonable defaults
+  // Switch off printing if asked to
+  gotHint = (getHintParam(OsiDoReducePrint,takeHint,strength));
+  assert (gotHint);
+  if (strength!=OsiHintIgnore&&takeHint) {
+    if (messageLevel>0)
+      messageLevel--;
+  }
+  if (messageLevel<modelPtr_->messageHandler()->logLevel())
+    modelPtr_->messageHandler()->setLogLevel(messageLevel);
+  // See if user set factorization frequency
+  int userFactorizationFrequency = modelPtr_->factorization()->maximumPivots();
+  // scaling
+  if (modelPtr_->solveType()==1) {
+    gotHint = (getHintParam(OsiDoScale,takeHint,strength));
+    assert (gotHint);
+    if (strength==OsiHintIgnore||takeHint) {
+      if (!modelPtr_->scalingFlag())
+	modelPtr_->scaling(3);
+    } else {
+      modelPtr_->scaling(0);
+    }
+  } else {
+    modelPtr_->scaling(0);
+  }
+  // sort out hints;
+  // algorithm -1 force dual, +1 force primal
+  int algorithm = -1;
+  gotHint = (getHintParam(OsiDoDualInResolve,takeHint,strength));
+  assert (gotHint);
+  if (strength!=OsiHintIgnore)
+    algorithm = takeHint ? -1 : 1;
+  //modelPtr_->saveModel("save.bad");
+  // presolve
+  gotHint = (getHintParam(OsiDoPresolveInResolve,takeHint,strength));
+  assert (gotHint);
+  if (strength!=OsiHintIgnore&&takeHint) {
+#ifdef KEEP_SMALL
+    if (smallModel_) {
+      delete [] spareArrays_;
+      spareArrays_ = NULL;
+      delete smallModel_;
+      smallModel_=NULL;
+    }
+#endif
+    ClpPresolve pinfo;
+    if ((specialOptions_&128)!=0) {
+      specialOptions_ &= ~128;
+    }
+    if ((modelPtr_->specialOptions()&1024)!=0) {
+      pinfo.setDoDual(false);
+      pinfo.setDoTripleton(false);
+      pinfo.setDoDupcol(false);
+      pinfo.setDoDuprow(false);
+      pinfo.setDoSingletonColumn(false);
+    }
+    ClpSimplex * model2 = pinfo.presolvedModel(*modelPtr_,1.0e-8);
+    if (!model2) {
+      // problem found to be infeasible - whats best?
+      model2 = modelPtr_;
+    }
+    // return number of rows
+    int * stats = reinterpret_cast<int *> (getApplicationData());
+    if (stats) {
+      stats[0]=model2->numberRows();
+      stats[1]=model2->numberColumns();
+    }
+    //printf("rows %d -> %d, columns %d -> %d\n",
+    //     modelPtr_->numberRows(),model2->numberRows(),
+    //     modelPtr_->numberColumns(),model2->numberColumns());
+    // change from 200
+    if (modelPtr_->factorization()->maximumPivots()==200)
+      model2->factorization()->maximumPivots(100+model2->numberRows()/50);
+    else
+      model2->factorization()->maximumPivots(userFactorizationFrequency);
+    if (algorithm<0) {
+      model2->dual();
+      totalIterations += model2->numberIterations();
+      // check if clp thought it was in a loop
+      if (model2->status()==3&&!model2->hitMaximumIterations()) {
+	// switch algorithm
+	model2->primal();
+	totalIterations += model2->numberIterations();
+      }
+    } else {
+      model2->primal(1);
+      totalIterations += model2->numberIterations();
+      // check if clp thought it was in a loop
+      if (model2->status()==3&&!model2->hitMaximumIterations()) {
+	// switch algorithm
+	model2->dual();
+	totalIterations += model2->numberIterations();
+      }
+    }
+    if (model2!=modelPtr_) {
+      int finalStatus=model2->status();
+      pinfo.postsolve(true);
+    
+      delete model2;
+      // later try without (1) and check duals before solve
+      if (finalStatus!=3&&(finalStatus||modelPtr_->status()==-1)) {
+        modelPtr_->primal(1);
+	totalIterations += modelPtr_->numberIterations();
+        lastAlgorithm_=1; // primal
+        //if (modelPtr_->numberIterations())
+        //printf("****** iterated %d\n",modelPtr_->numberIterations());
+      }
+    }
+  } else {
+    //modelPtr_->setLogLevel(63);
+    //modelPtr_->setDualTolerance(1.0e-7);
+    if (false&&modelPtr_->scalingFlag_>0&&!modelPtr_->rowScale_&&
+	!modelPtr_->rowCopy_&&matrixByRow_) {
+      assert (matrixByRow_->getNumElements()==modelPtr_->clpMatrix()->getNumElements());
+      modelPtr_->setNewRowCopy(new ClpPackedMatrix(*matrixByRow_));
+    }
+    if (algorithm<0) {
+      //writeMps("try1");
+      int savePerturbation = modelPtr_->perturbation();
+      if ((specialOptions_&2)!=0)
+	modelPtr_->setPerturbation(100);
+      //modelPtr_->messageHandler()->setLogLevel(1);
+      //writeMpsNative("bad",NULL,NULL,2,1,1.0);
+      disasterHandler_->setOsiModel(this);
+      bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
+#if 0
+      // See how many integers fixed
+      bool skipCrunch=true;
+      const char * integerInformation = modelPtr_->integerType_;
+      if (integerInformation) {
+	int numberColumns = modelPtr_->numberColumns_;
+	const double * lower = modelPtr_->columnLower();
+	const double * upper = modelPtr_->columnUpper();
+	int target=CoinMax(1,numberColumns/10000);
+	for (int i=0;i<numberColumns;i++) {
+	  if (integerInformation[i]) {
+	    if (lower[i]==upper[i]) {
+	      target--;
+	      if (!target) {
+		skipCrunch=false;
+		break;
+	      }
+	    }
+	  }
+	}
+      }
+#endif
+      if((specialOptions_&1)==0||(specialOptions_&2048)!=0/*||skipCrunch*/) {
+	disasterHandler_->setWhereFrom(0); // dual
+	if (inCbcOrOther)
+	  modelPtr_->setDisasterHandler(disasterHandler_);
+	bool specialScale;
+	if ((specialOptions_&131072)!=0&&!modelPtr_->rowScale_) {
+	  modelPtr_->rowScale_ = rowScale_.array();
+	  modelPtr_->columnScale_ = columnScale_.array();
+	  specialScale=true;
+	} else {
+	  specialScale=false;
+	}
+#ifdef KEEP_SMALL
+	if (smallModel_) {
+	  delete [] spareArrays_;
+	  spareArrays_ = NULL;
+	  delete smallModel_;
+	  smallModel_=NULL;
+	}
+#endif
+#ifdef CBC_STATISTICS
+	osi_dual++;
+#endif 
+	modelPtr_->dual(0,startFinishOptions);
+	totalIterations += modelPtr_->numberIterations();
+	if (specialScale) {
+	  modelPtr_->rowScale_ = NULL;
+	  modelPtr_->columnScale_ = NULL;
+	}
+      } else {
+#ifdef CBC_STATISTICS
+	osi_crunch++;
+#endif 
+	crunch();
+	totalIterations += modelPtr_->numberIterations();
+	if (modelPtr_->problemStatus()==4)
+	  goto disaster;
+	// should have already been fixed if problems
+	inCbcOrOther=false;
+      }
+      if (inCbcOrOther) {
+	if(disasterHandler_->inTrouble()) {
+	  if (disasterHandler_->typeOfDisaster()) {
+	    // We want to abort 
+	    abortSearch=true;
+	    goto disaster;
+	  }
+	  // try just going back in
+	  disasterHandler_->setPhase(1);
+	  modelPtr_->dual();
+	  totalIterations += modelPtr_->numberIterations();
+	  if (disasterHandler_->inTrouble()) {
+	    if (disasterHandler_->typeOfDisaster()) {
+	      // We want to abort 
+	      abortSearch=true;
+	      goto disaster;
+	    }
+	    // try primal with original basis
+	    disasterHandler_->setPhase(2);
+	    setBasis(basis_,modelPtr_);
+	    modelPtr_->primal();
+	    totalIterations += modelPtr_->numberIterations();
+	  }
+	  if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	    printf("disaster - treat as infeasible\n");
+#endif
+	    if (disasterHandler_->typeOfDisaster()) {
+	      // We want to abort 
+	      abortSearch=true;
+	      goto disaster;
+	    }
+	    modelPtr_->setProblemStatus(1);
+	  }
+	}
+	// reset
+	modelPtr_->setDisasterHandler(NULL);
+      }
+      if (modelPtr_->problemStatus()==4) {
+	// bad bounds?
+	modelPtr_->setProblemStatus(1);
+      }
+      if (!modelPtr_->problemStatus()&&0) {
+        int numberColumns = modelPtr_->numberColumns();
+        const double * columnLower = modelPtr_->columnLower();
+        const double * columnUpper = modelPtr_->columnUpper();
+        int nBad=0;
+        for (int i=0;i<numberColumns;i++) {
+          if (columnLower[i]==columnUpper[i]&&modelPtr_->getColumnStatus(i)==ClpSimplex::basic) {
+            nBad++;
+            modelPtr_->setColumnStatus(i,ClpSimplex::isFixed);
+          }
+        }
+        if (nBad) {
+          modelPtr_->primal(1);
+    totalIterations += modelPtr_->numberIterations();
+          printf("%d fixed basic - %d iterations\n",nBad,modelPtr_->numberIterations());
+        }
+      }
+      assert (modelPtr_->objectiveValue()<1.0e100);
+      modelPtr_->setPerturbation(savePerturbation);
+      lastAlgorithm_=2; // dual
+      // check if clp thought it was in a loop
+      if (modelPtr_->status()==3&&!modelPtr_->hitMaximumIterations()) {
+	modelPtr_->setSpecialOptions(saveOptions);
+	// switch algorithm
+	//modelPtr_->messageHandler()->setLogLevel(63);
+	// Allow for catastrophe
+	int saveMax = modelPtr_->maximumIterations();
+	int numberIterations = modelPtr_->numberIterations();
+	int numberRows = modelPtr_->numberRows();
+	int numberColumns = modelPtr_->numberColumns();
+	if (modelPtr_->maximumIterations()>100000+numberIterations)
+	  modelPtr_->setMaximumIterations(numberIterations + 1000 + 2*numberRows+numberColumns);
+	modelPtr_->primal(0,startFinishOptions);
+	totalIterations += modelPtr_->numberIterations();
+	modelPtr_->setMaximumIterations(saveMax);
+	lastAlgorithm_=1; // primal
+        if (modelPtr_->status()==3&&!modelPtr_->hitMaximumIterations()) {
+#ifdef COIN_DEVELOP
+	  printf("in trouble - try all slack\n");
+#endif
+	  CoinWarmStartBasis allSlack;
+	  setBasis(allSlack,modelPtr_);
+	  modelPtr_->dual();
+	  totalIterations += modelPtr_->numberIterations();
+          if (modelPtr_->status()==3&&!modelPtr_->hitMaximumIterations()) {
+	    if (modelPtr_->numberPrimalInfeasibilities()) {
+#ifdef COIN_DEVELOP
+	      printf("Real real trouble - treat as infeasible\n");
+#endif
+	      modelPtr_->setProblemStatus(1);
+	    } else {
+#ifdef COIN_DEVELOP
+	      printf("Real real trouble - treat as optimal\n");
+#endif
+	      modelPtr_->setProblemStatus(0);
+	    }
+	  }
+	}
+      }
+      assert (modelPtr_->objectiveValue()<1.0e100);
+    } else {
+#ifdef KEEP_SMALL
+      if (smallModel_) {
+	delete [] spareArrays_;
+	spareArrays_ = NULL;
+	delete smallModel_;
+	smallModel_=NULL;
+      }
+#endif
+      //printf("doing primal\n");
+#ifdef CBC_STATISTICS
+      osi_primal++;
+#endif 
+      modelPtr_->primal(1,startFinishOptions);
+      totalIterations += modelPtr_->numberIterations();
+      lastAlgorithm_=1; // primal
+      // check if clp thought it was in a loop
+      if (modelPtr_->status()==3&&!modelPtr_->hitMaximumIterations()) {
+	// switch algorithm
+	modelPtr_->dual();
+	totalIterations += modelPtr_->numberIterations();
+	lastAlgorithm_=2; // dual
+      }
+    }
+  }
+  // If scaled feasible but unscaled infeasible take action
+  //if (!modelPtr_->status()&&cleanupScaling_) {
+  if (cleanupScaling_) {
+    modelPtr_->cleanup(cleanupScaling_);
+  }
+  basis_ = getBasis(modelPtr_);
+ disaster:
+  //printf("basis after dual\n");
+  //basis_.print();
+  if (!defaultHandler_)
+    modelPtr_->popMessageHandler(saveHandler,oldDefault);
+  modelPtr_->messageHandler()->setLogLevel(saveMessageLevel);
+  if (saveSolveType==2) {
+    int saveStatus = modelPtr_->problemStatus_;
+    enableSimplexInterface(doingPrimal);
+    modelPtr_->problemStatus_=saveStatus;
+  }
+#ifdef COIN_DEVELOP_x
+  extern bool doingDoneBranch;
+  if (doingDoneBranch) {
+    if (modelPtr_->numberIterations())
+      printf("***** done %d iterations after general\n",modelPtr_->numberIterations());
+    doingDoneBranch=false;
+  }
+#endif
+  modelPtr_->setNumberIterations(totalIterations);
+  //modelPtr_->setSolveType(saveSolveType);
+  if (abortSearch) {
+    lastAlgorithm_=-911;
+    modelPtr_->setProblemStatus(4);
+  }
+  if (savedObjective) {
+    // fix up
+    modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
+    //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
+    modelPtr_->objective_=savedObjective;
+    if (!modelPtr_->problemStatus_) {
+      CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
+      CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
+      if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
+	CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
+      modelPtr_->computeObjectiveValue();
+    }
+  }
+  modelPtr_->setSpecialOptions(saveOptions); // restore
+  if (modelPtr_->problemStatus_==3&&lastAlgorithm_==2)
+    modelPtr_->computeObjectiveValue();
+  if (lastAlgorithm_<1||lastAlgorithm_>2)
+    lastAlgorithm_=1;
+#ifdef SAVE_MODEL
+  if (resolveTry>=loResolveTry&&
+      resolveTry<=hiResolveTry) {
+    printf("resolve %d took %d iterations - algorithm %d\n",resolveTry,modelPtr_->numberIterations(),lastAlgorithm_);
+  }
+#endif
+  // Make sure whatsChanged not out of sync
+  if (!modelPtr_->columnUpperWork_)
+    modelPtr_->whatsChanged_ &= ~0xffff;
+  modelPtr_->whatsChanged_ |= 0x30000;
+}
+#include "ClpSimplexOther.hpp"
+// Resolve an LP relaxation after problem modification (try GUB)
+void 
+OsiClpSolverInterface::resolveGub(int needed)
+{
+  bool takeHint;
+  OsiHintStrength strength;
+  // Switch off printing if asked to
+  getHintParam(OsiDoReducePrint,takeHint,strength);
+  int saveMessageLevel=modelPtr_->logLevel();
+  if (strength!=OsiHintIgnore&&takeHint) {
+    int messageLevel=messageHandler()->logLevel();
+    if (messageLevel>0)
+      modelPtr_->messageHandler()->setLogLevel(messageLevel-1);
+    else
+      modelPtr_->messageHandler()->setLogLevel(0);
+  }
+  //modelPtr_->messageHandler()->setLogLevel(1);
+  setBasis(basis_,modelPtr_);
+  // find gub
+  int numberRows = modelPtr_->numberRows();
+  int * which = new int[numberRows];
+  int numberColumns = modelPtr_->numberColumns();
+  int * whichC = new int[numberColumns+numberRows];
+  ClpSimplex * model2 = 
+    static_cast<ClpSimplexOther *> (modelPtr_)->gubVersion(which,whichC,
+							   needed,100);
+  if (model2) {
+    // move in solution
+    static_cast<ClpSimplexOther *> (model2)->setGubBasis(*modelPtr_,
+							 which,whichC);
+    model2->setLogLevel(CoinMin(1,model2->logLevel()));
+    ClpPrimalColumnSteepest steepest(5);
+    model2->setPrimalColumnPivotAlgorithm(steepest);
+    //double time1 = CoinCpuTime();
+    model2->primal();
+    //printf("Primal took %g seconds\n",CoinCpuTime()-time1);
+    static_cast<ClpSimplexOther *> (model2)->getGubBasis(*modelPtr_,
+							 which,whichC);
+    int totalIterations = model2->numberIterations();
+    delete model2;
+    //modelPtr_->setLogLevel(63);
+    modelPtr_->primal(1);
+    modelPtr_->setNumberIterations(totalIterations+modelPtr_->numberIterations());
+  } else {
+    modelPtr_->dual();
+  }
+  delete [] which;
+  delete [] whichC;
+  basis_ = getBasis(modelPtr_);
+  modelPtr_->messageHandler()->setLogLevel(saveMessageLevel);
+}
+// Sort of lexicographic resolve
+void 
+OsiClpSolverInterface::lexSolve()
+{
+#if 1
+  abort();
+#else
+  ((ClpSimplexPrimal *) modelPtr_)->lexSolve();
+  printf("itA %d\n",modelPtr_->numberIterations());
+  modelPtr_->primal();
+  printf("itB %d\n",modelPtr_->numberIterations());
+  basis_ = getBasis(modelPtr_);
+#endif
+}
+
+/* Sets up solver for repeated use by Osi interface.
+   The normal usage does things like keeping factorization around so can be used.
+   Will also do things like keep scaling and row copy of matrix if
+   matrix does not change.
+   adventure:
+   0 - safe stuff as above
+   1 - will take more risks - if it does not work then bug which will be fixed
+   2 - don't bother doing most extreme termination checks e.g. don't bother
+       re-factorizing if less than 20 iterations.
+   3 - Actually safer than 1 (mainly just keeps factorization)
+
+   printOut - -1 always skip round common messages instead of doing some work
+               0 skip if normal defaults
+               1 leaves
+  */
+void 
+OsiClpSolverInterface::setupForRepeatedUse(int senseOfAdventure, int printOut)
+{
+  // First try
+  switch (senseOfAdventure) {
+  case 0:
+    specialOptions_=8;
+    break;
+  case 1:
+    specialOptions_=1+2+8;
+    break;
+  case 2:
+    specialOptions_=1+2+4+8;
+    break;
+  case 3:
+    specialOptions_=1+8;
+    break;
+  }
+  bool stopPrinting=false;
+  if (printOut<0) {
+    stopPrinting=true;
+  } else if (!printOut) {
+    bool takeHint;
+    OsiHintStrength strength;
+    getHintParam(OsiDoReducePrint,takeHint,strength);
+    int messageLevel=messageHandler()->logLevel();
+    if (strength!=OsiHintIgnore&&takeHint) 
+      messageLevel--;
+    stopPrinting = (messageLevel<=0);
+  }
+#ifndef COIN_DEVELOP
+  if (stopPrinting) {
+    CoinMessages * messagesPointer = modelPtr_->messagesPointer();
+    // won't even build messages 
+    messagesPointer->setDetailMessages(100,10000,reinterpret_cast<int *> (NULL));
+  }
+#endif
+}
+#ifndef NDEBUG
+// For errors to make sure print to screen
+// only called in debug mode
+static void indexError(int index,
+			std::string methodName)
+{
+  std::cerr<<"Illegal index "<<index<<" in OsiClpSolverInterface::"<<methodName<<std::endl;
+  throw CoinError("Illegal index",methodName,"OsiClpSolverInterface");
+}
+#endif
+//#############################################################################
+// Parameter related methods
+//#############################################################################
+
+bool
+OsiClpSolverInterface::setIntParam(OsiIntParam key, int value)
+{
+  return modelPtr_->setIntParam(static_cast<ClpIntParam> (key), value);
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiClpSolverInterface::setDblParam(OsiDblParam key, double value)
+{
+  if (key != OsiLastDblParam ) {
+    if (key==OsiDualObjectiveLimit||key==OsiPrimalObjectiveLimit)
+      value *= modelPtr_->optimizationDirection();
+    return modelPtr_->setDblParam(static_cast<ClpDblParam> (key), value);
+  } else {
+    return false;
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiClpSolverInterface::setStrParam(OsiStrParam key, const std::string & value)
+{
+  assert (key!=OsiSolverName);
+  if (key != OsiLastStrParam ) {
+    return modelPtr_->setStrParam(static_cast<ClpStrParam> (key), value);
+  } else {
+    return false;
+  }
+}
+
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiClpSolverInterface::getIntParam(OsiIntParam key, int& value) const 
+{
+  return modelPtr_->getIntParam(static_cast<ClpIntParam> (key), value);
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiClpSolverInterface::getDblParam(OsiDblParam key, double& value) const
+{
+  if (key != OsiLastDblParam ) {
+    bool condition =  modelPtr_->getDblParam(static_cast<ClpDblParam> (key), value);
+    if (key==OsiDualObjectiveLimit||key==OsiPrimalObjectiveLimit)
+      value *= modelPtr_->optimizationDirection();
+    return condition;
+  } else {
+    return false;
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+OsiClpSolverInterface::getStrParam(OsiStrParam key, std::string & value) const
+{
+  if ( key==OsiSolverName ) {
+    value = "clp";
+    return true;
+  }
+  if (key != OsiLastStrParam ) {
+    return modelPtr_->getStrParam(static_cast<ClpStrParam> (key), value);
+  } else {
+    return false;
+  }
+}
+
+
+//#############################################################################
+// Methods returning info on how the solution process terminated
+//#############################################################################
+
+bool OsiClpSolverInterface::isAbandoned() const
+{
+  // not sure about -1 (should not happen)
+  return (modelPtr_->status()==4||modelPtr_->status()==-1||
+	  (modelPtr_->status()==1&&modelPtr_->secondaryStatus()==8));
+}
+
+bool OsiClpSolverInterface::isProvenOptimal() const
+{
+
+  const int stat = modelPtr_->status();
+  return (stat == 0);
+}
+
+bool OsiClpSolverInterface::isProvenPrimalInfeasible() const
+{
+
+  const int stat = modelPtr_->status();
+  if (stat != 1)
+     return false;
+  return true;
+}
+
+bool OsiClpSolverInterface::isProvenDualInfeasible() const
+{
+  const int stat = modelPtr_->status();
+  return stat == 2;
+}
+/* 
+   NOTE - Coding if limit > 1.0e30 says that 1.0e29 is loose bound
+   so all maximization tests are changed 
+*/
+bool OsiClpSolverInterface::isPrimalObjectiveLimitReached() const
+{
+  double limit = 0.0;
+  modelPtr_->getDblParam(ClpPrimalObjectiveLimit, limit);
+  if (fabs(limit) > 1e30) {
+    // was not ever set
+    return false;
+  }
+   
+  const double obj = modelPtr_->objectiveValue();
+  int maxmin = static_cast<int> (modelPtr_->optimizationDirection());
+
+  switch (lastAlgorithm_) {
+   case 0: // no simplex was needed
+     return maxmin > 0 ? (obj < limit) /*minim*/ : (-obj < limit) /*maxim*/;
+   case 2: // dual simplex
+     if (modelPtr_->status() == 0) // optimal
+	return maxmin > 0 ? (obj < limit) /*minim*/ : (-obj < limit) /*maxim*/;
+     return false;
+   case 1: // primal simplex
+     return maxmin > 0 ? (obj < limit) /*minim*/ : (-obj < limit) /*maxim*/;
+  }
+  return false; // fake return
+}
+
+bool OsiClpSolverInterface::isDualObjectiveLimitReached() const
+{
+
+  const int stat = modelPtr_->status();
+  if (stat == 1)
+  return true;
+  double limit = 0.0;
+  modelPtr_->getDblParam(ClpDualObjectiveLimit, limit);
+  if (fabs(limit) > 1e30) {
+    // was not ever set
+    return false;
+  }
+   
+  const double obj = modelPtr_->objectiveValue();
+  int maxmin = static_cast<int> (modelPtr_->optimizationDirection());
+
+  switch (lastAlgorithm_) {
+   case 0: // no simplex was needed
+     return maxmin > 0 ? (obj > limit) /*minim*/ : (-obj > limit) /*maxim*/;
+   case 1: // primal simplex
+     if (stat == 0) // optimal
+	return maxmin > 0 ? (obj > limit) /*minim*/ : (-obj > limit) /*maxim*/;
+     return false;
+   case 2: // dual simplex
+     if (stat != 0 && stat != 3)
+	// over dual limit
+	return true;
+     return maxmin > 0 ? (obj > limit) /*minim*/ : (-obj > limit) /*maxim*/;
+  }
+  return false; // fake return
+}
+
+bool OsiClpSolverInterface::isIterationLimitReached() const
+{
+  const int stat = modelPtr_->status();
+  return (stat == 3);
+}
+
+//#############################################################################
+// WarmStart related methods
+//#############################################################################
+CoinWarmStart *OsiClpSolverInterface::getEmptyWarmStart () const
+  { return (static_cast<CoinWarmStart *>(new CoinWarmStartBasis())) ; }
+
+CoinWarmStart* OsiClpSolverInterface::getWarmStart() const
+{
+
+  return new CoinWarmStartBasis(basis_);
+}
+/* Get warm start information.
+   Return warm start information for the current state of the solver
+   interface. If there is no valid warm start information, an empty warm
+   start object wil be returned.  This does not necessarily create an 
+   object - may just point to one.  must Delete set true if user
+   should delete returned object.
+   OsiClp version always returns pointer and false.
+*/
+CoinWarmStart* 
+OsiClpSolverInterface::getPointerToWarmStart(bool & mustDelete) 
+{
+  mustDelete = false;
+  return &basis_;
+}
+
+//-----------------------------------------------------------------------------
+
+bool OsiClpSolverInterface::setWarmStart(const CoinWarmStart* warmstart)
+{
+  modelPtr_->whatsChanged_ &= 0xffff;
+  const CoinWarmStartBasis* ws =
+    dynamic_cast<const CoinWarmStartBasis*>(warmstart);
+  if (ws) {
+    basis_ = CoinWarmStartBasis(*ws);
+    return true;
+  } else if (!warmstart) {
+    // create from current basis
+    basis_ = getBasis(modelPtr_);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+//#############################################################################
+// Hotstart related methods (primarily used in strong branching)
+//#############################################################################
+void OsiClpSolverInterface::markHotStart()
+{
+#ifdef CBC_STATISTICS
+  osi_hot++;
+#endif 
+  //printf("HotStart options %x changed %x, small %x spare %x\n",
+  // specialOptions_,modelPtr_->whatsChanged_,
+  // smallModel_,spareArrays_);
+  modelPtr_->setProblemStatus(0);
+  saveData_.perturbation_=0;
+  saveData_.specialOptions_ = modelPtr_->specialOptions_;
+  modelPtr_->specialOptions_ |= 0x1000000;
+  modelPtr_->specialOptions_ = saveData_.specialOptions_; 
+  ClpObjective * savedObjective=NULL;
+  double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit];
+  if (fakeObjective_) {
+    modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~128));
+    // See if all with costs fixed
+    int numberColumns = modelPtr_->numberColumns_;
+    const double * obj = modelPtr_->objective();
+    const double * lower = modelPtr_->columnLower();
+    const double * upper = modelPtr_->columnUpper();
+    int i;
+    for (i=0;i<numberColumns;i++) {
+      double objValue = obj[i];
+      if (objValue) {
+	if (lower[i]!=upper[i])
+	  break;
+      }
+    }
+    if (i==numberColumns) {
+      if ((specialOptions_&524288)==0) {
+	// Set fake
+	savedObjective=modelPtr_->objective_;
+	modelPtr_->objective_=fakeObjective_;
+	modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX;
+	saveData_.perturbation_=1;
+      } else {
+	modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()|128);
+      }
+    }
+  }
+#define CLEAN_HOT_START
+#ifdef CLEAN_HOT_START
+  if ((specialOptions_&65536)!=0) {
+    //specialOptions_ |= 65536;
+    saveData_.scalingFlag_=modelPtr_->logLevel();
+    if (modelPtr_->logLevel()<2)
+      modelPtr_->setLogLevel(0);
+    assert ((specialOptions_&128)==0);
+    // space for save arrays
+    int numberColumns = modelPtr_->numberColumns();
+    int numberRows = modelPtr_->numberRows();
+    // Get space for strong branching 
+    int size = static_cast<int>((1+4*(numberRows+numberColumns))*sizeof(double));
+    // and for save of original column bounds
+    size += static_cast<int>(2*numberColumns*sizeof(double));
+    size += static_cast<int>((1+4*numberRows+2*numberColumns)*sizeof(int));
+    size += numberRows+numberColumns;
+    assert (spareArrays_==NULL);
+    spareArrays_ = new char[size];
+    //memset(spareArrays_,0x20,size);
+    // Setup for strong branching
+    assert (factorization_==NULL);
+    if ((specialOptions_&131072)!=0) {
+      assert (lastNumberRows_>=0);
+      if (modelPtr_->rowScale_!=rowScale_.array()) {
+	assert(modelPtr_->columnScale_!=columnScale_.array());
+	delete [] modelPtr_->rowScale_;
+	modelPtr_->rowScale_=NULL;
+	delete [] modelPtr_->columnScale_;
+	modelPtr_->columnScale_=NULL;
+	if (lastNumberRows_==modelPtr_->numberRows()) {
+	  // use scaling
+	  modelPtr_->rowScale_ = rowScale_.array();
+	  modelPtr_->columnScale_ = columnScale_.array();
+	} else {
+	  specialOptions_ &= ~131072;
+	}
+      }
+      lastNumberRows_ = -1 -lastNumberRows_;
+    }
+    factorization_ = static_cast<ClpSimplexDual *>(modelPtr_)->setupForStrongBranching(spareArrays_,numberRows,
+										       numberColumns,true);
+    double * arrayD = reinterpret_cast<double *> (spareArrays_);
+    arrayD[0]=modelPtr_->objectiveValue()* modelPtr_->optimizationDirection();
+    double * saveSolution = arrayD+1;
+    double * saveLower = saveSolution + (numberRows+numberColumns);
+    double * saveUpper = saveLower + (numberRows+numberColumns);
+    double * saveObjective = saveUpper + (numberRows+numberColumns);
+    double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
+    double * saveUpperOriginal = saveLowerOriginal + numberColumns;
+    CoinMemcpyN( modelPtr_->columnLower(),numberColumns, saveLowerOriginal);
+    CoinMemcpyN( modelPtr_->columnUpper(),numberColumns, saveUpperOriginal);
+#if 0
+    if (whichRange_&&whichRange_[0]) {
+      // get ranging information
+      int numberToDo = whichRange_[0];
+      int * which = new int [numberToDo];
+      // Convert column numbers
+      int * backColumn = whichColumn+numberColumns;
+      for (int i=0;i<numberToDo;i++) {
+	int iColumn = whichRange_[i+1];
+	which[i]=backColumn[iColumn];
+      }
+      double * downRange=new double [numberToDo];
+      double * upRange=new double [numberToDo];
+      int * whichDown = new int [numberToDo];
+      int * whichUp = new int [numberToDo];
+      modelPtr_->gutsOfSolution(NULL,NULL,false);
+      // Tell code we can increase costs in some cases
+      modelPtr_->setCurrentDualTolerance(0.0);
+      ((ClpSimplexOther *) modelPtr_)->dualRanging(numberToDo,which,
+						   upRange, whichUp, downRange, whichDown);
+      delete [] whichDown;
+      delete [] whichUp;
+      delete [] which;
+      rowActivity_=upRange;
+      columnActivity_=downRange;
+    }
+#endif 
+    if (savedObjective) {
+      // fix up
+      modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
+      //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
+      modelPtr_->objective_=savedObjective;
+      if (!modelPtr_->problemStatus_) {
+	CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
+	CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
+	if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
+	  CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
+	modelPtr_->computeObjectiveValue();
+      }
+    }
+    return;
+  }
+#endif
+  if ((specialOptions_&8192)==0&&false) { // ||(specialOptions_&65536)!=0) {
+    delete ws_;
+    ws_ = dynamic_cast<CoinWarmStartBasis*>(getWarmStart());
+    int numberRows = modelPtr_->numberRows();
+    rowActivity_= new double[numberRows];
+    CoinMemcpyN(modelPtr_->primalRowSolution(),numberRows,rowActivity_);
+    int numberColumns = modelPtr_->numberColumns();
+    columnActivity_= new double[numberColumns];
+    CoinMemcpyN(modelPtr_->primalColumnSolution(),numberColumns,columnActivity_);
+  } else {
+#if 0
+    int saveLevel = modelPtr_->logLevel();
+    modelPtr_->setLogLevel(0);
+    //modelPtr_->dual();
+    OsiClpSolverInterface::resolve();
+    if (modelPtr_->numberIterations()>0)
+      printf("**** iterated large %d\n",modelPtr_->numberIterations());
+    //else
+    //printf("no iterations\n");
+    modelPtr_->setLogLevel(saveLevel);
+#endif
+    // called from CbcNode
+    int numberColumns = modelPtr_->numberColumns();
+    int numberRows = modelPtr_->numberRows();
+    // Get space for crunch and strong branching (too much)
+    int size = static_cast<int>((1+4*(numberRows+numberColumns))*sizeof(double));
+    // and for save of original column bounds
+    size += static_cast<int>(2*numberColumns*sizeof(double));
+    size += static_cast<int>((1+4*numberRows+2*numberColumns)*sizeof(int));
+    size += numberRows+numberColumns;
+#ifdef KEEP_SMALL
+    if(smallModel_&&(modelPtr_->whatsChanged_&0x30000)!=0x30000) {
+      //printf("Bounds changed ? %x\n",modelPtr_->whatsChanged_);
+      delete smallModel_;
+      smallModel_=NULL;
+    }
+    if (!smallModel_) {
+      delete [] spareArrays_;
+      spareArrays_ = NULL;
+    }
+#endif
+    if (spareArrays_==NULL) {
+      //if (smallModel_)
+      //printf("small model %x\n",smallModel_);
+      delete smallModel_;
+      smallModel_=NULL;
+      spareArrays_ = new char[size];
+      //memset(spareArrays_,0x20,size);
+    } else {
+      double * arrayD = reinterpret_cast<double *> (spareArrays_);
+      double * saveSolution = arrayD+1;
+      double * saveLower = saveSolution + (numberRows+numberColumns);
+      double * saveUpper = saveLower + (numberRows+numberColumns);
+      double * saveObjective = saveUpper + (numberRows+numberColumns);
+      double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
+      double * saveUpperOriginal = saveLowerOriginal + numberColumns;
+      double * lowerOriginal = modelPtr_->columnLower();
+      double * upperOriginal = modelPtr_->columnUpper();
+      arrayD = saveUpperOriginal + numberColumns;
+      int * savePivot = reinterpret_cast<int *> (arrayD);
+      int * whichRow = savePivot+numberRows;
+      int * whichColumn = whichRow + 3*numberRows;
+      int nSame=0;
+      int nSub=0;
+      for (int i=0;i<numberColumns;i++) {
+	double lo = lowerOriginal[i];
+	//char * xx = (char *) (saveLowerOriginal+i);
+	//assert (xx[0]!=0x20||xx[1]!=0x20);
+	//xx = (char *) (saveUpperOriginal+i);
+	//assert (xx[0]!=0x20||xx[1]!=0x20);
+	double loOld = saveLowerOriginal[i];
+	//assert (!loOld||fabs(loOld)>1.0e-30);
+	double up = upperOriginal[i];
+	double upOld = saveUpperOriginal[i];
+	if (lo>=loOld&&up<=upOld) {
+	  if (lo==loOld&&up==upOld) {
+	    nSame++;
+	  } else {
+	    nSub++;
+	    //if (!isInteger(i))
+	    //nSub+=10;
+	  }
+	}
+      }
+      //printf("Mark Hot %d bounds same, %d interior, %d bad\n",
+      //     nSame,nSub,numberColumns-nSame-nSub);
+      if (nSame<numberColumns) {
+	if (nSame+nSub<numberColumns) {
+	  delete smallModel_;
+	  smallModel_=NULL;
+	} else {
+	  // we can fix up (but should we if large number fixed?)
+	  assert (smallModel_);
+	  double * lowerSmall = smallModel_->columnLower();
+	  double * upperSmall = smallModel_->columnUpper();
+	  int numberColumns2 = smallModel_->numberColumns();
+	  for (int i=0;i<numberColumns2;i++) {
+	    int iColumn = whichColumn[i];
+	    lowerSmall[i]=lowerOriginal[iColumn];
+	    upperSmall[i]=upperOriginal[iColumn];
+	  }
+	}
+      }
+    }
+    double * arrayD = reinterpret_cast<double *> (spareArrays_);
+    arrayD[0]=modelPtr_->objectiveValue()* modelPtr_->optimizationDirection();
+    double * saveSolution = arrayD+1;
+    double * saveLower = saveSolution + (numberRows+numberColumns);
+    double * saveUpper = saveLower + (numberRows+numberColumns);
+    double * saveObjective = saveUpper + (numberRows+numberColumns);
+    double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
+    double * saveUpperOriginal = saveLowerOriginal + numberColumns;
+    arrayD = saveUpperOriginal + numberColumns;
+    int * savePivot = reinterpret_cast<int *> (arrayD);
+    int * whichRow = savePivot+numberRows;
+    int * whichColumn = whichRow + 3*numberRows;
+    int * arrayI = whichColumn + 2*numberColumns;
+    //unsigned char * saveStatus = (unsigned char *) (arrayI+1);
+    // Use dual region
+    double * rhs = modelPtr_->dualRowSolution();
+    int nBound=0;
+    ClpSimplex * small;
+#ifndef KEEP_SMALL
+    assert (!smallModel_);
+    small = static_cast<ClpSimplexOther *> (modelPtr_)->crunch(rhs,whichRow,whichColumn,nBound,true);
+    bool needSolveInSetupHotStart=true;
+#else
+    bool needSolveInSetupHotStart=true;
+    if (!smallModel_) {
+#ifndef NDEBUG
+      CoinFillN(whichRow,3*numberRows+2*numberColumns,-1);
+#endif
+      small = static_cast<ClpSimplexOther *> (modelPtr_)->crunch(rhs,whichRow,whichColumn,nBound,true);
+#ifndef NDEBUG
+      int nCopy = 3*numberRows+2*numberColumns;
+      for (int i=0;i<nCopy;i++)
+	assert (whichRow[i]>=-CoinMax(numberRows,numberColumns)&&whichRow[i]<CoinMax(numberRows,numberColumns));
+#endif
+      smallModel_=small;
+      //int hotIts = small->intParam_[ClpMaxNumIterationHotStart];
+      //if (5*small->factorization_->maximumPivots()>
+      //  4*hotIts)
+      //small->factorization_->maximumPivots(hotIts+1);
+    } else {
+      assert((modelPtr_->whatsChanged_&0x30000)==0x30000);
+      //delete [] spareArrays_;
+      //spareArrays_ = NULL;
+      assert (spareArrays_);
+      int nCopy = 3*numberRows+2*numberColumns;
+      nBound = whichRow[nCopy];
+#ifndef NDEBUG
+      for (int i=0;i<nCopy;i++)
+	assert (whichRow[i]>=-CoinMax(numberRows,numberColumns)&&whichRow[i]<CoinMax(numberRows,numberColumns));
+#endif
+      needSolveInSetupHotStart=false;
+      small = smallModel_;
+    }
+#endif
+    if (small) {
+      small->specialOptions_ |= 262144;
+      small->specialOptions_ &= ~65536;
+    }
+    if (small&&(specialOptions_&131072)!=0) {
+      assert (lastNumberRows_>=0);
+      int numberRows2 = small->numberRows();
+      int numberColumns2 = small->numberColumns();
+      double * rowScale2 = new double [2*numberRows2];
+      const double * rowScale = rowScale_.array();
+      double * inverseScale2 = rowScale2+numberRows2;
+      const double * inverseScale = rowScale+modelPtr_->numberRows_;
+      int i;
+      for (i=0;i<numberRows2;i++) {
+	int iRow = whichRow[i];
+	rowScale2[i]=rowScale[iRow];
+	inverseScale2[i]=inverseScale[iRow];
+      }
+      small->setRowScale(rowScale2);
+      double * columnScale2 = new double [2*numberColumns2];
+      const double * columnScale = columnScale_.array();
+      inverseScale2 = columnScale2+numberColumns2;
+      inverseScale = columnScale+modelPtr_->numberColumns_;
+      for (i=0;i<numberColumns2;i++) {
+	int iColumn = whichColumn[i];
+	columnScale2[i]=columnScale[iColumn];
+	inverseScale2[i]=inverseScale[iColumn];
+      }
+      small->setColumnScale(columnScale2);
+    }
+    if (!small) {
+      // should never be infeasible .... but
+      delete [] spareArrays_;
+      spareArrays_=NULL;
+      delete ws_;
+      ws_ = dynamic_cast<CoinWarmStartBasis*>(getWarmStart());
+      int numberRows = modelPtr_->numberRows();
+      rowActivity_= new double[numberRows];
+      CoinMemcpyN(modelPtr_->primalRowSolution(),numberRows,rowActivity_);
+      int numberColumns = modelPtr_->numberColumns();
+      columnActivity_= new double[numberColumns];
+      CoinMemcpyN(modelPtr_->primalColumnSolution(),numberColumns,columnActivity_);
+      modelPtr_->setProblemStatus(1);
+      if (savedObjective) {
+	// fix up
+	modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
+	//modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
+	modelPtr_->objective_=savedObjective;
+      }
+      return;
+    }
+    int clpOptions = modelPtr_->specialOptions();
+    clpOptions &= ~65536;
+    if((specialOptions_&1)==0) {
+      small->setSpecialOptions(clpOptions|(64|1024));
+    } else {
+      if((specialOptions_&4)==0) 
+        small->setSpecialOptions(clpOptions|(64|128|512|1024|4096));
+      else
+        small->setSpecialOptions(clpOptions|(64|128|512|1024|2048|4096));
+    }
+    arrayI[0]=nBound;
+    assert (smallModel_==NULL||small==smallModel_);
+    if ((specialOptions_&256)!=0||1) {
+      // only need to do this on second pass in CbcNode
+      if (modelPtr_->logLevel()<2) small->setLogLevel(0);
+      small->specialOptions_ |= 262144;
+      small->moreSpecialOptions_ = modelPtr_->moreSpecialOptions_;
+#define SETUP_HOT
+#ifndef SETUP_HOT
+      small->dual();
+#else
+      assert (factorization_==NULL);
+      //needSolveInSetupHotStart=true;
+      ClpFactorization * factorization = static_cast<ClpSimplexDual *>(small)->setupForStrongBranching(spareArrays_,
+		       numberRows,numberColumns,
+												       needSolveInSetupHotStart);
+#endif
+      if (small->numberIterations()>0&&small->logLevel()>2)
+	printf("**** iterated small %d\n",small->numberIterations());
+      //small->setLogLevel(0);
+      // Could be infeasible if forced one way (and other way stopped on iterations)
+      // could also be stopped on iterations
+      if (small->status()) {
+#ifndef KEEP_SMALL
+	if (small!=modelPtr_)
+	  delete small;
+	//delete smallModel_;
+	//smallModel_=NULL;
+	assert (!smallModel_);
+#else
+	assert (small==smallModel_);
+	if (smallModel_!=modelPtr_) {
+	  delete smallModel_;
+	}
+	smallModel_=NULL;
+#endif
+	delete [] spareArrays_;
+	spareArrays_=NULL;
+	delete ws_;
+	ws_ = dynamic_cast<CoinWarmStartBasis*>(getWarmStart());
+	int numberRows = modelPtr_->numberRows();
+	rowActivity_= new double[numberRows];
+ CoinMemcpyN(modelPtr_->primalRowSolution(),	numberRows,rowActivity_);
+	int numberColumns = modelPtr_->numberColumns();
+	columnActivity_= new double[numberColumns];
+ CoinMemcpyN(modelPtr_->primalColumnSolution(),	numberColumns,columnActivity_);
+	modelPtr_->setProblemStatus(1);
+	if (savedObjective) {
+	  // fix up
+	  modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
+	  //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
+	  modelPtr_->objective_=savedObjective;
+	}
+	return;
+      } else {
+	// update model
+	static_cast<ClpSimplexOther *> (modelPtr_)->afterCrunch(*small,whichRow,whichColumn,nBound);
+      } 
+#ifndef SETUP_HOT
+      assert (factorization_==NULL);
+      factorization_ = static_cast<ClpSimplexDual *>(small)->setupForStrongBranching(spareArrays_,numberRows,
+			     numberColumns,false);
+#else
+      assert (factorization!=NULL || small->problemStatus_ );
+      factorization_ = factorization;
+#endif
+    } else {
+      assert (factorization_==NULL);
+      factorization_ = static_cast<ClpSimplexDual *>(small)->setupForStrongBranching(spareArrays_,numberRows,
+										     numberColumns,false);
+    }
+    smallModel_=small;
+    if (modelPtr_->logLevel()<2) smallModel_->setLogLevel(0);
+    // Setup for strong branching
+    int numberColumns2 = smallModel_->numberColumns();
+    CoinMemcpyN( modelPtr_->columnLower(),numberColumns, saveLowerOriginal);
+    CoinMemcpyN( modelPtr_->columnUpper(),numberColumns, saveUpperOriginal);
+    const double * smallLower = smallModel_->columnLower();
+    const double * smallUpper = smallModel_->columnUpper();
+    // But modify if bounds changed in small
+    for (int i=0;i<numberColumns2;i++) {
+      int iColumn = whichColumn[i];
+      saveLowerOriginal[iColumn] = CoinMax(saveLowerOriginal[iColumn],
+					   smallLower[i]);
+      saveUpperOriginal[iColumn] = CoinMin(saveUpperOriginal[iColumn],
+					   smallUpper[i]);
+    }
+    if (whichRange_&&whichRange_[0]) {
+      // get ranging information
+      int numberToDo = whichRange_[0];
+      int * which = new int [numberToDo];
+      // Convert column numbers
+      int * backColumn = whichColumn+numberColumns;
+      for (int i=0;i<numberToDo;i++) {
+        int iColumn = whichRange_[i+1];
+        which[i]=backColumn[iColumn];
+      }
+      double * downRange=new double [numberToDo];
+      double * upRange=new double [numberToDo];
+      int * whichDown = new int [numberToDo];
+      int * whichUp = new int [numberToDo];
+      smallModel_->setFactorization(*factorization_);
+      smallModel_->gutsOfSolution(NULL,NULL,false);
+      // Tell code we can increase costs in some cases
+      smallModel_->setCurrentDualTolerance(0.0);
+      static_cast<ClpSimplexOther *> (smallModel_)->dualRanging(numberToDo,which,
+                         upRange, whichUp, downRange, whichDown);
+      delete [] whichDown;
+      delete [] whichUp;
+      delete [] which;
+      rowActivity_=upRange;
+      columnActivity_=downRange;
+    }
+  }
+    if (savedObjective) {
+      // fix up
+      modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
+      //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
+      modelPtr_->objective_=savedObjective;
+      if (!modelPtr_->problemStatus_) {
+	CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
+	CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
+	if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
+	  CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
+	modelPtr_->computeObjectiveValue();
+      }
+    }
+}
+
+void OsiClpSolverInterface::solveFromHotStart()
+{
+#ifdef KEEP_SMALL
+  if (!spareArrays_) {
+    assert (!smallModel_);
+    assert (modelPtr_->problemStatus_==1);
+    return;
+  }
+#endif
+  ClpObjective * savedObjective=NULL;
+  double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit];
+  if (saveData_.perturbation_) {
+    // Set fake
+    savedObjective=modelPtr_->objective_;
+    modelPtr_->objective_=fakeObjective_;
+    modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX;
+  }
+  int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  modelPtr_->getIntParam(ClpMaxNumIteration,itlimOrig_);
+  int itlim;
+  modelPtr_->getIntParam(ClpMaxNumIterationHotStart, itlim);
+  // Is there an extra copy of scaled bounds
+  int extraCopy = (modelPtr_->maximumRows_>0) ? modelPtr_->maximumRows_+modelPtr_->maximumColumns_ : 0; 
+#ifdef CLEAN_HOT_START
+  if ((specialOptions_&65536)!=0) {
+    double * arrayD = reinterpret_cast<double *> (spareArrays_);
+    double saveObjectiveValue = arrayD[0];
+    double * saveSolution = arrayD+1;
+    int number = numberRows+numberColumns;
+    CoinMemcpyN(saveSolution,number,modelPtr_->solutionRegion());
+    double * saveLower = saveSolution + (numberRows+numberColumns);
+    CoinMemcpyN(saveLower,number,modelPtr_->lowerRegion());
+    double * saveUpper = saveLower + (numberRows+numberColumns);
+    CoinMemcpyN(saveUpper,number,modelPtr_->upperRegion());
+    double * saveObjective = saveUpper + (numberRows+numberColumns);
+    CoinMemcpyN(saveObjective,number,modelPtr_->costRegion());
+    double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
+    double * saveUpperOriginal = saveLowerOriginal + numberColumns;
+    arrayD = saveUpperOriginal + numberColumns;
+    int * savePivot = reinterpret_cast<int *> (arrayD);
+    CoinMemcpyN(savePivot,numberRows,modelPtr_->pivotVariable());
+    int * whichRow = savePivot+numberRows;
+    int * whichColumn = whichRow + 3*numberRows;
+    int * arrayI = whichColumn + 2*numberColumns;
+    unsigned char * saveStatus = reinterpret_cast<unsigned char *> (arrayI+1);
+    CoinMemcpyN(saveStatus,number,modelPtr_->statusArray());
+    modelPtr_->setFactorization(*factorization_);
+    double * columnLower = modelPtr_->columnLower();
+    double * columnUpper = modelPtr_->columnUpper();
+    // make sure whatsChanged_ has 1 set
+    modelPtr_->setWhatsChanged(511);
+    double * lowerInternal = modelPtr_->lowerRegion();
+    double * upperInternal = modelPtr_->upperRegion();
+    double rhsScale = modelPtr_->rhsScale();
+    const double * columnScale = NULL;
+    if (modelPtr_->scalingFlag()>0) 
+      columnScale = modelPtr_->columnScale() ;
+    // and do bounds in case dual needs them
+    int iColumn;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if (columnLower[iColumn]>saveLowerOriginal[iColumn]) {
+	double value = columnLower[iColumn];
+	value *= rhsScale;
+	if (columnScale)
+	  value /= columnScale[iColumn];
+	lowerInternal[iColumn]=value;
+	if (extraCopy)
+	  lowerInternal[iColumn+extraCopy]=value;
+      }
+      if (columnUpper[iColumn]<saveUpperOriginal[iColumn]) {
+	double value = columnUpper[iColumn];
+	value *= rhsScale;
+	if (columnScale)
+	  value /= columnScale[iColumn];
+	upperInternal[iColumn]=value;
+	if (extraCopy)
+	  upperInternal[iColumn+extraCopy]=value;
+      }
+    }
+    // Start of fast iterations
+    bool alwaysFinish= ((specialOptions_&32)==0) ? true : false;
+    //modelPtr_->setLogLevel(1);
+    modelPtr_->setIntParam(ClpMaxNumIteration,itlim);
+    int saveNumberFake = (static_cast<ClpSimplexDual *>(modelPtr_))->numberFake_;
+    int status = (static_cast<ClpSimplexDual *>(modelPtr_))->fastDual(alwaysFinish);
+    (static_cast<ClpSimplexDual *>(modelPtr_))->numberFake_ = saveNumberFake;
+    
+    int problemStatus = modelPtr_->problemStatus();
+    double objectiveValue =modelPtr_->objectiveValue() * modelPtr_->optimizationDirection();
+    CoinAssert (modelPtr_->problemStatus()||modelPtr_->objectiveValue()<1.0e50);
+    // make sure plausible
+    double obj = CoinMax(objectiveValue,saveObjectiveValue);
+    if (problemStatus==10||problemStatus<0) {
+      // was trying to clean up or something odd
+      if (problemStatus==10)
+	lastAlgorithm_=1; // so won't fail on cutoff (in CbcNode)
+      status=1;
+    }
+    if (status) {
+      // not finished - might be optimal
+      modelPtr_->checkPrimalSolution(modelPtr_->solutionRegion(0),
+                                     modelPtr_->solutionRegion(1));
+      //modelPtr_->gutsOfSolution(NULL,NULL,0);
+      //if (problemStatus==3)
+      //modelPtr_->computeObjectiveValue();
+      objectiveValue =modelPtr_->objectiveValue() *
+	modelPtr_->optimizationDirection();
+      obj = CoinMax(objectiveValue,saveObjectiveValue);
+      if (!modelPtr_->numberDualInfeasibilities()) { 
+	double limit = 0.0;
+	modelPtr_->getDblParam(ClpDualObjectiveLimit, limit);
+	if (modelPtr_->secondaryStatus()==1&&!problemStatus&&obj<limit) {
+	  obj=limit;
+	  problemStatus=3;
+	}
+	if (!modelPtr_->numberPrimalInfeasibilities()&&obj<limit) { 
+	  problemStatus=0;
+	} else if (problemStatus==10) {
+	  problemStatus=3;
+	} else if (!modelPtr_->numberPrimalInfeasibilities()) {
+	  problemStatus=1; // infeasible
+	} 
+      } else {
+	// can't say much
+	//if (problemStatus==3)
+	//modelPtr_->computeObjectiveValue();
+	lastAlgorithm_=1; // so won't fail on cutoff (in CbcNode)
+	problemStatus=3;
+      }
+    } else if (!problemStatus) {
+      if (modelPtr_->isDualObjectiveLimitReached()) 
+	problemStatus=1; // infeasible
+    }
+    if (status&&!problemStatus) {
+      problemStatus=3; // can't be sure
+      lastAlgorithm_=1;
+    }
+    if (problemStatus<0)
+      problemStatus=3;
+    modelPtr_->setProblemStatus(problemStatus);
+    modelPtr_->setObjectiveValue(obj*modelPtr_->optimizationDirection());
+    double * solution = modelPtr_->primalColumnSolution();
+    const double * solution2 = modelPtr_->solutionRegion();
+    // could just do changed bounds - also try double size scale so can use * not /
+    if (!columnScale) {
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	solution[iColumn]= solution2[iColumn];
+      }
+    } else {
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	solution[iColumn]= solution2[iColumn]*columnScale[iColumn];
+      }
+    }
+    CoinMemcpyN(saveLowerOriginal,numberColumns,columnLower);
+    CoinMemcpyN(saveUpperOriginal,numberColumns,columnUpper);
+#if 0
+    // could combine with loop above
+    if (modelPtr_==modelPtr_)
+      modelPtr_->computeObjectiveValue();
+    if (status&&!problemStatus) {
+      memset(modelPtr_->primalRowSolution(),0,numberRows*sizeof(double));
+      modelPtr_->clpMatrix()->times(1.0,solution,modelPtr_->primalRowSolution());
+      modelPtr_->checkSolutionInternal();
+      //modelPtr_->setLogLevel(1);
+      //modelPtr_->allSlackBasis();
+      //modelPtr_->primal(1);
+      //memset(modelPtr_->primalRowSolution(),0,numberRows*sizeof(double));
+      //modelPtr_->clpMatrix()->times(1.0,solution,modelPtr_->primalRowSolution());
+      //modelPtr_->checkSolutionInternal();
+      assert (!modelPtr_->problemStatus());
+    }
+#endif
+    // and back bounds
+    CoinMemcpyN(saveLower,number,modelPtr_->lowerRegion());
+    CoinMemcpyN(saveUpper,number,modelPtr_->upperRegion());
+    if (extraCopy) {
+      CoinMemcpyN(saveLower,number,modelPtr_->lowerRegion()+extraCopy);
+      CoinMemcpyN(saveUpper,number,modelPtr_->upperRegion()+extraCopy);
+    }
+    modelPtr_->setIntParam(ClpMaxNumIteration,itlimOrig_);
+    if (savedObjective) {
+      // fix up
+      modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
+      //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
+      modelPtr_->objective_=savedObjective;
+      if (!modelPtr_->problemStatus_) {
+	CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
+	CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
+	if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
+	  CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
+	modelPtr_->computeObjectiveValue();
+      }
+    }
+    return;
+  }
+#endif
+  if (smallModel_==NULL) {
+    setWarmStart(ws_);
+    CoinMemcpyN(           rowActivity_,numberRows,modelPtr_->primalRowSolution());
+    CoinMemcpyN(columnActivity_,numberColumns,modelPtr_->primalColumnSolution());
+    modelPtr_->setIntParam(ClpMaxNumIteration,CoinMin(itlim,9999));
+    resolve();
+  } else {
+    assert (spareArrays_);
+    double * arrayD = reinterpret_cast<double *> (spareArrays_);
+    double saveObjectiveValue = arrayD[0];
+    double * saveSolution = arrayD+1;
+    // double check arrays exist (? for nonlinear)
+    //if (!smallModel_->solutionRegion())
+    //smallModel_->createRim(63);
+    int numberRows2 = smallModel_->numberRows();
+    int numberColumns2 = smallModel_->numberColumns();
+    int number = numberRows2+numberColumns2;
+    CoinMemcpyN(saveSolution,number,smallModel_->solutionRegion());
+    double * saveLower = saveSolution + (numberRows+numberColumns);
+    CoinMemcpyN(saveLower,number,smallModel_->lowerRegion());
+    double * saveUpper = saveLower + (numberRows+numberColumns);
+    CoinMemcpyN(saveUpper,number,smallModel_->upperRegion());
+    double * saveObjective = saveUpper + (numberRows+numberColumns);
+    CoinMemcpyN(saveObjective,number,smallModel_->costRegion());
+    double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
+    double * saveUpperOriginal = saveLowerOriginal + numberColumns;
+    arrayD = saveUpperOriginal + numberColumns;
+    int * savePivot = reinterpret_cast<int *> (arrayD);
+    CoinMemcpyN(savePivot,numberRows2,smallModel_->pivotVariable());
+    int * whichRow = savePivot+numberRows;
+    int * whichColumn = whichRow + 3*numberRows;
+    int * arrayI = whichColumn + 2*numberColumns;
+    unsigned char * saveStatus = reinterpret_cast<unsigned char *> (arrayI+1);
+    CoinMemcpyN(saveStatus,number,smallModel_->statusArray());
+    /* If factorization_ NULL then infeasible
+       not really sure how could have slipped through.
+       But this can't make situation worse */
+    if (factorization_) 
+      smallModel_->setFactorization(*factorization_);
+    //int * backColumn = whichColumn+numberColumns;
+    const double * lowerBig = modelPtr_->columnLower();
+    const double * upperBig = modelPtr_->columnUpper();
+    // make sure whatsChanged_ has 1 set
+    smallModel_->setWhatsChanged(511);
+    double * lowerSmall = smallModel_->lowerRegion();
+    double * upperSmall = smallModel_->upperRegion();
+    double * lowerSmallReal = smallModel_->columnLower();
+    double * upperSmallReal = smallModel_->columnUpper();
+    int i;
+    double rhsScale = smallModel_->rhsScale();
+    const double * columnScale = NULL;
+    if (smallModel_->scalingFlag()>0) {
+      columnScale = smallModel_->columnScale();
+    }
+    // and do bounds in case dual needs them
+    // may be infeasible
+    for (i=0;i<numberColumns2;i++) {
+      int iColumn = whichColumn[i];
+      if (lowerBig[iColumn]>saveLowerOriginal[iColumn]) {
+        double value = lowerBig[iColumn];
+        lowerSmallReal[i]=value;
+        value *= rhsScale;
+        if (columnScale)
+          value /= columnScale[i];
+        lowerSmall[i]=value;
+      }
+      if (upperBig[iColumn]<saveUpperOriginal[iColumn]) {
+        double value = upperBig[iColumn];
+        upperSmallReal[i]=value;
+        value *= rhsScale;
+        if (columnScale)
+          value /= columnScale[i];
+        upperSmall[i]=value;
+      }
+      if (upperSmall[i]<lowerSmall[i]-1.0e-8)
+	break;
+    }
+    /* If factorization_ NULL then infeasible
+       not really sure how could have slipped through.
+       But this can't make situation worse */
+    bool infeasible = (i<numberColumns2||!factorization_);
+    // Start of fast iterations
+    bool alwaysFinish= ((specialOptions_&32)==0) ? true : false;
+    //smallModel_->setLogLevel(1);
+    smallModel_->setIntParam(ClpMaxNumIteration,itlim);
+    int saveNumberFake = (static_cast<ClpSimplexDual *>(smallModel_))->numberFake_;
+    int status;
+    if (!infeasible) {
+      status = static_cast<ClpSimplexDual *>(smallModel_)->fastDual(alwaysFinish);
+    } else {
+      status=0;
+      smallModel_->setProblemStatus(1);
+    }
+    (static_cast<ClpSimplexDual *>(smallModel_))->numberFake_ = saveNumberFake;
+    if (smallModel_->numberIterations()==-98) {
+      printf("rrrrrrrrrrrr\n");
+      smallModel_->checkPrimalSolution(smallModel_->solutionRegion(0),
+                                     smallModel_->solutionRegion(1));
+      //smallModel_->gutsOfSolution(NULL,NULL,0);
+      //if (problemStatus==3)
+      //smallModel_->computeObjectiveValue();
+      printf("robj %g\n",smallModel_->objectiveValue() *
+	     modelPtr_->optimizationDirection());
+      writeMps("rr.mps");
+      smallModel_->writeMps("rr_small.mps");
+      ClpSimplex temp = *smallModel_;
+      printf("small\n");
+      temp.setLogLevel(63);
+      temp.dual();
+      double limit = 0.0;
+      modelPtr_->getDblParam(ClpDualObjectiveLimit, limit);
+      if (temp.problemStatus()==0&&temp.objectiveValue()<limit) {
+	printf("inf obj %g, true %g - offsets %g %g\n",smallModel_->objectiveValue(),
+	       temp.objectiveValue(),
+	       smallModel_->objectiveOffset(),temp.objectiveOffset());
+      }
+      printf("big\n");
+      temp = *modelPtr_;
+      temp.dual();
+      if (temp.problemStatus()==0&&temp.objectiveValue()<limit) {
+	printf("inf obj %g, true %g - offsets %g %g\n",smallModel_->objectiveValue(),
+	       temp.objectiveValue(),
+	       smallModel_->objectiveOffset(),temp.objectiveOffset());
+      }
+    }
+    int problemStatus = smallModel_->problemStatus();
+    double objectiveValue =smallModel_->objectiveValue() * modelPtr_->optimizationDirection();
+    CoinAssert (smallModel_->problemStatus()||smallModel_->objectiveValue()<1.0e50);
+    // make sure plausible
+    double obj = CoinMax(objectiveValue,saveObjectiveValue);
+    if (problemStatus==10||problemStatus<0) {
+      // was trying to clean up or something odd
+      if (problemStatus==10)
+        lastAlgorithm_=1; // so won't fail on cutoff (in CbcNode)
+      status=1;
+    }
+    if (status) {
+      // not finished - might be optimal
+      smallModel_->checkPrimalSolution(smallModel_->solutionRegion(0),
+                                     smallModel_->solutionRegion(1));
+      //smallModel_->gutsOfSolution(NULL,NULL,0);
+      //if (problemStatus==3)
+      //smallModel_->computeObjectiveValue();
+      objectiveValue =smallModel_->objectiveValue() *
+        modelPtr_->optimizationDirection();
+      if (problemStatus!=10)
+	obj = CoinMax(objectiveValue,saveObjectiveValue);
+      if (!smallModel_->numberDualInfeasibilities()) { 
+        double limit = 0.0;
+        modelPtr_->getDblParam(ClpDualObjectiveLimit, limit);
+        if (smallModel_->secondaryStatus()==1&&!problemStatus&&obj<limit) {
+#if 0
+          // switch off
+          ClpSimplex temp = *smallModel_;
+          temp.dual();
+          if (temp.problemStatus()==0&&temp.objectiveValue()<limit) {
+            printf("inf obj %g, true %g - offsets %g %g\n",smallModel_->objectiveValue(),
+                   temp.objectiveValue(),
+                   smallModel_->objectiveOffset(),temp.objectiveOffset());
+          }
+          lastAlgorithm_=1;
+          obj=limit;
+          problemStatus=10;
+#else
+          obj=limit;
+          problemStatus=3;
+#endif
+        }
+        if (!smallModel_->numberPrimalInfeasibilities()&&obj<limit) { 
+          problemStatus=0;
+#if 0
+          ClpSimplex temp = *smallModel_;
+          temp.dual();
+          if (temp.numberIterations())
+            printf("temp iterated\n");
+          assert (temp.problemStatus()==0&&temp.objectiveValue()<limit);
+#endif
+        } else if (problemStatus==10) {
+          problemStatus=3;
+        } else if (!smallModel_->numberPrimalInfeasibilities()) {
+          problemStatus=1; // infeasible
+        } 
+      } else {
+        // can't say much
+        //if (problemStatus==3)
+        //smallModel_->computeObjectiveValue();
+        lastAlgorithm_=1; // so won't fail on cutoff (in CbcNode)
+        problemStatus=3;
+      }
+    } else if (!problemStatus) {
+      if (smallModel_->isDualObjectiveLimitReached()) 
+        problemStatus=1; // infeasible
+    }
+    if (status&&!problemStatus) {
+      problemStatus=3; // can't be sure
+      lastAlgorithm_=1;
+    }
+    if (problemStatus<0)
+      problemStatus=3;
+    modelPtr_->setProblemStatus(problemStatus);
+    modelPtr_->setObjectiveValue(obj*modelPtr_->optimizationDirection());
+    modelPtr_->setSumDualInfeasibilities(smallModel_->sumDualInfeasibilities());
+    modelPtr_->setNumberDualInfeasibilities(smallModel_->numberDualInfeasibilities());
+    modelPtr_->setSumPrimalInfeasibilities(smallModel_->sumPrimalInfeasibilities());
+    modelPtr_->setNumberPrimalInfeasibilities(smallModel_->numberPrimalInfeasibilities());
+    double * solution = modelPtr_->primalColumnSolution();
+    const double * solution2 = smallModel_->solutionRegion();
+    if (!columnScale) {
+      for (i=0;i<numberColumns2;i++) {
+        int iColumn = whichColumn[i];
+        solution[iColumn]= solution2[i];
+        lowerSmallReal[i]=saveLowerOriginal[iColumn];
+        upperSmallReal[i]=saveUpperOriginal[iColumn];
+      }
+    } else {
+      for (i=0;i<numberColumns2;i++) {
+        int iColumn = whichColumn[i];
+        solution[iColumn]= solution2[i]*columnScale[i];
+        lowerSmallReal[i]=saveLowerOriginal[iColumn];
+        upperSmallReal[i]=saveUpperOriginal[iColumn];
+      }
+    }
+    // could combine with loop above
+    if (modelPtr_==smallModel_)
+      modelPtr_->computeObjectiveValue();
+#if 1
+    if (status&&!problemStatus) {
+      memset(modelPtr_->primalRowSolution(),0,numberRows*sizeof(double));
+      modelPtr_->clpMatrix()->times(1.0,solution,modelPtr_->primalRowSolution());
+      modelPtr_->checkSolutionInternal();
+      //modelPtr_->setLogLevel(1);
+      //modelPtr_->allSlackBasis();
+      //modelPtr_->primal(1);
+      //memset(modelPtr_->primalRowSolution(),0,numberRows*sizeof(double));
+      //modelPtr_->clpMatrix()->times(1.0,solution,modelPtr_->primalRowSolution());
+      //modelPtr_->checkSolutionInternal();
+      assert (!modelPtr_->problemStatus());
+    }
+#endif
+    modelPtr_->setNumberIterations(smallModel_->numberIterations());
+    // and back bounds
+    CoinMemcpyN(saveLower,number,smallModel_->lowerRegion());
+    CoinMemcpyN(saveUpper,number,smallModel_->upperRegion());
+  }
+  if (savedObjective) {
+    // fix up
+    modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
+    //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
+    modelPtr_->objective_=savedObjective;
+    if (!modelPtr_->problemStatus_) {
+      CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
+      CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
+      if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
+	CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
+      modelPtr_->computeObjectiveValue();
+    }
+  }
+  modelPtr_->setIntParam(ClpMaxNumIteration,itlimOrig_);
+}
+
+void OsiClpSolverInterface::unmarkHotStart()
+{
+#ifdef CLEAN_HOT_START
+  if ((specialOptions_&65536)!=0) {
+    modelPtr_->setLogLevel(saveData_.scalingFlag_);
+    modelPtr_->deleteRim(0);
+    if (lastNumberRows_<0) {
+      specialOptions_ |= 131072;
+      lastNumberRows_ = -1 -lastNumberRows_;
+      if (modelPtr_->rowScale_) {
+	if (modelPtr_->rowScale_!=rowScale_.array()) {
+	  delete [] modelPtr_->rowScale_;
+	  delete [] modelPtr_->columnScale_;
+	}
+	modelPtr_->rowScale_=NULL;
+	modelPtr_->columnScale_=NULL;
+      }
+    }
+    delete factorization_;
+    delete [] spareArrays_;
+    smallModel_=NULL;
+    spareArrays_=NULL;
+    factorization_=NULL;
+    delete [] rowActivity_;
+    delete [] columnActivity_;
+    rowActivity_=NULL;
+    columnActivity_=NULL;
+    return;
+  }
+#endif
+  if (smallModel_==NULL) {
+    setWarmStart(ws_);
+    int numberRows = modelPtr_->numberRows();
+    int numberColumns = modelPtr_->numberColumns();
+    CoinMemcpyN(           rowActivity_,numberRows,modelPtr_->primalRowSolution());
+    CoinMemcpyN(columnActivity_,numberColumns,modelPtr_->primalColumnSolution());
+    delete ws_;
+    ws_ = NULL;
+  } else {
+#ifndef KEEP_SMALL
+    if (smallModel_!=modelPtr_)
+      delete smallModel_;
+    smallModel_=NULL;
+#else
+    if (smallModel_==modelPtr_) {
+      smallModel_=NULL;
+    } else if (smallModel_) {
+      if(!spareArrays_) {
+	delete smallModel_;
+	smallModel_=NULL;
+	delete factorization_;
+	factorization_=NULL;
+      } else {
+	static_cast<ClpSimplexDual *> (smallModel_)->cleanupAfterStrongBranching( factorization_);
+	if ((smallModel_->specialOptions_&4096)==0) {
+	  delete factorization_;
+	}
+      }
+    }
+#endif
+    //delete [] spareArrays_;
+    //spareArrays_=NULL;
+    factorization_=NULL;
+  }
+  delete [] rowActivity_;
+  delete [] columnActivity_;
+  rowActivity_=NULL;
+  columnActivity_=NULL;
+  // Make sure whatsChanged not out of sync
+  if (!modelPtr_->columnUpperWork_)
+    modelPtr_->whatsChanged_ &= ~0xffff;
+  modelPtr_->specialOptions_ = saveData_.specialOptions_; 
+}
+
+//#############################################################################
+// Problem information methods (original data)
+//#############################################################################
+
+//------------------------------------------------------------------
+const char * OsiClpSolverInterface::getRowSense() const
+{
+  extractSenseRhsRange();
+  return rowsense_;
+}
+//------------------------------------------------------------------
+const double * OsiClpSolverInterface::getRightHandSide() const
+{
+  extractSenseRhsRange();
+  return rhs_;
+}
+//------------------------------------------------------------------
+const double * OsiClpSolverInterface::getRowRange() const
+{
+  extractSenseRhsRange();
+  return rowrange_;
+}
+//------------------------------------------------------------------
+// Return information on integrality
+//------------------------------------------------------------------
+bool OsiClpSolverInterface::isContinuous(int colNumber) const
+{
+  if ( integerInformation_==NULL ) return true;
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (colNumber<0||colNumber>=n) {
+    indexError(colNumber,"isContinuous");
+  }
+#endif
+  if ( integerInformation_[colNumber]==0 ) return true;
+  return false;
+}
+bool 
+OsiClpSolverInterface::isBinary(int colNumber) const
+{
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (colNumber<0||colNumber>=n) {
+    indexError(colNumber,"isBinary");
+  }
+#endif
+  if ( integerInformation_==NULL || integerInformation_[colNumber]==0 ) {
+    return false;
+  } else {
+    const double * cu = getColUpper();
+    const double * cl = getColLower();
+    if ((cu[colNumber]== 1 || cu[colNumber]== 0) && 
+	(cl[colNumber]== 0 || cl[colNumber]==1))
+      return true;
+    else 
+      return false;
+  }
+}
+//-----------------------------------------------------------------------------
+bool 
+OsiClpSolverInterface::isInteger(int colNumber) const
+{
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (colNumber<0||colNumber>=n) {
+    indexError(colNumber,"isInteger");
+  }
+#endif
+  if ( integerInformation_==NULL || integerInformation_[colNumber]==0 ) 
+    return false;
+  else
+    return true;
+}
+//-----------------------------------------------------------------------------
+bool 
+OsiClpSolverInterface::isIntegerNonBinary(int colNumber) const
+{
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (colNumber<0||colNumber>=n) {
+    indexError(colNumber,"isIntegerNonBinary");
+  }
+#endif
+  if ( integerInformation_==NULL || integerInformation_[colNumber]==0 ) {
+    return false;
+  } else {
+    return !isBinary(colNumber);
+  }
+}
+//-----------------------------------------------------------------------------
+bool 
+OsiClpSolverInterface::isFreeBinary(int colNumber) const
+{
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (colNumber<0||colNumber>=n) {
+    indexError(colNumber,"isFreeBinary");
+  }
+#endif
+  if ( integerInformation_==NULL || integerInformation_[colNumber]==0 ) {
+    return false;
+  } else {
+    const double * cu = getColUpper();
+    const double * cl = getColLower();
+    if ((cu[colNumber]== 1) && (cl[colNumber]== 0))
+      return true;
+    else 
+      return false;
+  }
+}
+/*  Return array of column length
+    0 - continuous
+    1 - binary (may get fixed later)
+    2 - general integer (may get fixed later)
+*/
+const char * 
+OsiClpSolverInterface::getColType(bool refresh) const
+{
+  if (!columnType_||refresh) {
+    const int numCols = getNumCols() ;
+    if (!columnType_)
+      columnType_ = new char [numCols];
+    if ( integerInformation_==NULL ) {
+      memset(columnType_,0,numCols);
+    } else {
+      const double * cu = getColUpper();
+      const double * cl = getColLower();
+      for (int i = 0 ; i < numCols ; ++i) {
+	if (integerInformation_[i]) {
+	  if ((cu[i]== 1 || cu[i]== 0) && 
+	      (cl[i]== 0 || cl[i]==1))
+	    columnType_[i]=1;
+	  else
+	    columnType_[i]=2;
+	} else {
+	  columnType_[i]=0;
+	}
+      }
+    }
+  }
+  return columnType_;
+}
+
+/* Return true if column is integer but does not have to
+   be declared as such.
+   Note: This function returns true if the the column
+   is binary or a general integer.
+*/
+bool 
+OsiClpSolverInterface::isOptionalInteger(int colNumber) const
+{
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (colNumber<0||colNumber>=n) {
+    indexError(colNumber,"isInteger");
+  }
+#endif
+  if ( integerInformation_==NULL || integerInformation_[colNumber]!=2 ) 
+    return false;
+  else
+    return true;
+}
+/* Set the index-th variable to be an optional integer variable */
+void 
+OsiClpSolverInterface::setOptionalInteger(int index)
+{
+  if (!integerInformation_) {
+    integerInformation_ = new char[modelPtr_->numberColumns()];
+    CoinFillN ( integerInformation_, modelPtr_->numberColumns(),static_cast<char> (0));
+  }
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (index<0||index>=n) {
+    indexError(index,"setInteger");
+  }
+#endif
+  integerInformation_[index]=2;
+  modelPtr_->setInteger(index);
+}
+
+//------------------------------------------------------------------
+// Row and column copies of the matrix ...
+//------------------------------------------------------------------
+const CoinPackedMatrix * OsiClpSolverInterface::getMatrixByRow() const
+{
+  if ( matrixByRow_ == NULL ||
+       matrixByRow_->getNumElements() != 
+       modelPtr_->clpMatrix()->getNumElements() ) {
+    delete matrixByRow_;
+    matrixByRow_ = new CoinPackedMatrix();
+    matrixByRow_->setExtraGap(0.0);
+    matrixByRow_->setExtraMajor(0.0);
+    matrixByRow_->reverseOrderedCopyOf(*modelPtr_->matrix());
+    //matrixByRow_->removeGaps();
+#if 0
+    CoinPackedMatrix back;
+    std::cout<<"start check"<<std::endl;
+    back.reverseOrderedCopyOf(*matrixByRow_);
+    modelPtr_->matrix()->isEquivalent2(back);
+    std::cout<<"stop check"<<std::endl;
+#endif
+  }
+  assert (matrixByRow_->getNumElements()==modelPtr_->clpMatrix()->getNumElements());
+  return matrixByRow_;
+}
+
+const CoinPackedMatrix * OsiClpSolverInterface::getMatrixByCol() const
+{
+  return modelPtr_->matrix();
+}
+  
+// Get pointer to mutable column-wise copy of matrix (returns NULL if not meaningful)
+CoinPackedMatrix * 
+OsiClpSolverInterface::getMutableMatrixByCol() const 
+{
+  ClpPackedMatrix * matrix = dynamic_cast<ClpPackedMatrix *>(modelPtr_->matrix_) ;
+  if (matrix)
+    return matrix->getPackedMatrix();
+  else
+    return NULL;
+}
+
+//------------------------------------------------------------------
+std::vector<double*> OsiClpSolverInterface::getDualRays(int /*maxNumRays*/,
+							bool fullRay) const
+{
+  return std::vector<double*>(1, modelPtr_->infeasibilityRay(fullRay));
+}
+//------------------------------------------------------------------
+std::vector<double*> OsiClpSolverInterface::getPrimalRays(int /*maxNumRays*/) const
+{
+  return std::vector<double*>(1, modelPtr_->unboundedRay());
+}
+//#############################################################################
+void
+OsiClpSolverInterface::setContinuous(int index)
+{
+
+  if (integerInformation_) {
+#ifndef NDEBUG
+    int n = modelPtr_->numberColumns();
+    if (index<0||index>=n) {
+      indexError(index,"setContinuous");
+    }
+#endif
+    integerInformation_[index]=0;
+  }
+  modelPtr_->setContinuous(index);
+}
+//-----------------------------------------------------------------------------
+void
+OsiClpSolverInterface::setInteger(int index)
+{
+  if (!integerInformation_) {
+    integerInformation_ = new char[modelPtr_->numberColumns()];
+    CoinFillN ( integerInformation_, modelPtr_->numberColumns(),static_cast<char> (0));
+  }
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (index<0||index>=n) {
+    indexError(index,"setInteger");
+  }
+#endif
+  integerInformation_[index]=1;
+  modelPtr_->setInteger(index);
+}
+//-----------------------------------------------------------------------------
+void
+OsiClpSolverInterface::setContinuous(const int* indices, int len)
+{
+  if (integerInformation_) {
+#ifndef NDEBUG
+    int n = modelPtr_->numberColumns();
+#endif
+    int i;
+    for (i=0; i<len;i++) {
+      int colNumber = indices[i];
+#ifndef NDEBUG
+      if (colNumber<0||colNumber>=n) {
+	indexError(colNumber,"setContinuous");
+      }
+#endif
+      integerInformation_[colNumber]=0;
+      modelPtr_->setContinuous(colNumber);
+    }
+  }
+}
+//-----------------------------------------------------------------------------
+void
+OsiClpSolverInterface::setInteger(const int* indices, int len)
+{
+  if (!integerInformation_) {
+    integerInformation_ = new char[modelPtr_->numberColumns()];
+    CoinFillN ( integerInformation_, modelPtr_->numberColumns(),static_cast<char> (0));
+  }
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+#endif
+  int i;
+  for (i=0; i<len;i++) {
+    int colNumber = indices[i];
+#ifndef NDEBUG
+    if (colNumber<0||colNumber>=n) {
+      indexError(colNumber,"setInteger");
+    }
+#endif
+    integerInformation_[colNumber]=1;
+    modelPtr_->setInteger(colNumber);
+  }
+}
+/* Set the objective coefficients for all columns
+    array [getNumCols()] is an array of values for the objective.
+    This defaults to a series of set operations and is here for speed.
+*/
+void 
+OsiClpSolverInterface::setObjective(const double * array)
+{
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  modelPtr_->whatsChanged_ &= (0xffff&~64);
+  int n = modelPtr_->numberColumns() ;
+  if (fakeMinInSimplex_) {
+    std::transform(array,array+n,
+  		   modelPtr_->objective(),std::negate<double>()) ;
+  } else {
+    CoinMemcpyN(array,n,modelPtr_->objective());
+  }
+}
+/* Set the lower bounds for all columns
+    array [getNumCols()] is an array of values for the objective.
+    This defaults to a series of set operations and is here for speed.
+*/
+void 
+OsiClpSolverInterface::setColLower(const double * array)
+{
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  modelPtr_->whatsChanged_ &= (0x1ffff&128);
+  CoinMemcpyN(array,modelPtr_->numberColumns(),
+		    modelPtr_->columnLower());
+}
+/* Set the upper bounds for all columns
+    array [getNumCols()] is an array of values for the objective.
+    This defaults to a series of set operations and is here for speed.
+*/
+void 
+OsiClpSolverInterface::setColUpper(const double * array)
+{
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  modelPtr_->whatsChanged_ &= (0x1ffff&256);
+  CoinMemcpyN(array,modelPtr_->numberColumns(),
+		    modelPtr_->columnUpper());
+}
+//-----------------------------------------------------------------------------
+void OsiClpSolverInterface::setColSolution(const double * cs) 
+{
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  CoinDisjointCopyN(cs,modelPtr_->numberColumns(),
+		    modelPtr_->primalColumnSolution());
+  if (modelPtr_->solveType()==2) {
+    // directly into code as well
+    CoinDisjointCopyN(cs,modelPtr_->numberColumns(),
+		      modelPtr_->solutionRegion(1));
+  }
+  // compute row activity
+  memset(modelPtr_->primalRowSolution(),0,modelPtr_->numberRows()*sizeof(double));
+  modelPtr_->times(1.0,modelPtr_->primalColumnSolution(),modelPtr_->primalRowSolution());
+}
+//-----------------------------------------------------------------------------
+void OsiClpSolverInterface::setRowPrice(const double * rs) 
+{
+  CoinDisjointCopyN(rs,modelPtr_->numberRows(),
+		    modelPtr_->dualRowSolution());
+  if (modelPtr_->solveType()==2) {
+    // directly into code as well (? sign )
+    CoinDisjointCopyN(rs,modelPtr_->numberRows(),
+		      modelPtr_->djRegion(0));
+  }
+  // compute reduced costs
+  memcpy(modelPtr_->dualColumnSolution(),modelPtr_->objective(),
+	 modelPtr_->numberColumns()*sizeof(double));
+  modelPtr_->transposeTimes(-1.0,modelPtr_->dualRowSolution(),modelPtr_->dualColumnSolution());
+}
+
+//#############################################################################
+// Problem modifying methods (matrix)
+//#############################################################################
+void 
+OsiClpSolverInterface::addCol(const CoinPackedVectorBase& vec,
+			      const double collb, const double colub,   
+			      const double obj)
+{
+  int numberColumns = modelPtr_->numberColumns();
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|8|64|128|256));
+  modelPtr_->resize(modelPtr_->numberRows(),numberColumns+1);
+  linearObjective_ = modelPtr_->objective();
+  basis_.resize(modelPtr_->numberRows(),numberColumns+1);
+  setColBounds(numberColumns,collb,colub);
+  setObjCoeff(numberColumns,obj);
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendCol(vec);
+  if (integerInformation_) {
+    char * temp = new char[numberColumns+1];
+    CoinMemcpyN(integerInformation_,numberColumns,temp);
+    delete [] integerInformation_;
+    integerInformation_ = temp;
+    integerInformation_[numberColumns]=0;
+  }
+  freeCachedResults();
+}
+//-----------------------------------------------------------------------------
+/* Add a column (primal variable) to the problem. */
+void 
+OsiClpSolverInterface::addCol(int numberElements, const int * rows, const double * elements,
+			   const double collb, const double colub,   
+			   const double obj) 
+{
+  CoinPackedVector column(numberElements, rows, elements);
+  addCol(column,collb,colub,obj);
+}
+// Add a named column (primal variable) to the problem.
+void 
+OsiClpSolverInterface::addCol(const CoinPackedVectorBase& vec,
+		      const double collb, const double colub,   
+		      const double obj, std::string name) 
+{
+  int ndx = getNumCols() ;
+  addCol(vec,collb,colub,obj) ;
+  setColName(ndx,name) ;
+}
+//-----------------------------------------------------------------------------
+void 
+OsiClpSolverInterface::addCols(const int numcols,
+			       const CoinPackedVectorBase * const * cols,
+			       const double* collb, const double* colub,   
+			       const double* obj)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|8|64|128|256));
+  int numberColumns = modelPtr_->numberColumns();
+  modelPtr_->resize(modelPtr_->numberRows(),numberColumns+numcols);
+  linearObjective_ = modelPtr_->objective();
+  basis_.resize(modelPtr_->numberRows(),numberColumns+numcols);
+  double * lower = modelPtr_->columnLower()+numberColumns;
+  double * upper = modelPtr_->columnUpper()+numberColumns;
+  double * objective = modelPtr_->objective()+numberColumns;
+  int iCol;
+  if (collb) {
+    for (iCol = 0; iCol < numcols; iCol++) {
+      lower[iCol]= forceIntoRange(collb[iCol], -OsiClpInfinity, OsiClpInfinity);
+      if (lower[iCol]<-1.0e27)
+	lower[iCol]=-COIN_DBL_MAX;
+    }
+  } else {
+    CoinFillN ( lower, numcols,0.0);
+  }
+  if (colub) {
+    for (iCol = 0; iCol < numcols; iCol++) {
+      upper[iCol]= forceIntoRange(colub[iCol], -OsiClpInfinity, OsiClpInfinity);
+      if (upper[iCol]>1.0e27)
+	upper[iCol]=COIN_DBL_MAX;
+    }
+  } else {
+    CoinFillN ( upper, numcols,COIN_DBL_MAX);
+  }
+  if (obj) {
+    for (iCol = 0; iCol < numcols; iCol++) {
+      objective[iCol] = obj[iCol];
+    }
+  } else {
+    CoinFillN ( objective, numcols,0.0);
+  }
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendCols(numcols,cols);
+  if (integerInformation_) {
+    char * temp = new char[numberColumns+numcols];
+    CoinMemcpyN(integerInformation_,numberColumns,temp);
+    delete [] integerInformation_;
+    integerInformation_ = temp;
+    for (iCol = 0; iCol < numcols; iCol++) 
+      integerInformation_[numberColumns+iCol]=0;
+  }
+  freeCachedResults();
+}
+void 
+OsiClpSolverInterface::addCols(const int numcols,
+			       const int * columnStarts, const int * rows, const double * elements,
+			       const double* collb, const double* colub,   
+			       const double* obj)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|8|64|128|256));
+  int numberColumns = modelPtr_->numberColumns();
+  modelPtr_->resize(modelPtr_->numberRows(),numberColumns+numcols);
+  linearObjective_ = modelPtr_->objective();
+  basis_.resize(modelPtr_->numberRows(),numberColumns+numcols);
+  double * lower = modelPtr_->columnLower()+numberColumns;
+  double * upper = modelPtr_->columnUpper()+numberColumns;
+  double * objective = modelPtr_->objective()+numberColumns;
+  int iCol;
+  if (collb) {
+    for (iCol = 0; iCol < numcols; iCol++) {
+      lower[iCol]= forceIntoRange(collb[iCol], -OsiClpInfinity, OsiClpInfinity);
+      if (lower[iCol]<-1.0e27)
+	lower[iCol]=-COIN_DBL_MAX;
+    }
+  } else {
+    CoinFillN ( lower, numcols,0.0);
+  }
+  if (colub) {
+    for (iCol = 0; iCol < numcols; iCol++) {
+      upper[iCol]= forceIntoRange(colub[iCol], -OsiClpInfinity, OsiClpInfinity);
+      if (upper[iCol]>1.0e27)
+	upper[iCol]=COIN_DBL_MAX;
+    }
+  } else {
+    CoinFillN ( upper, numcols,COIN_DBL_MAX);
+  }
+  if (obj) {
+    for (iCol = 0; iCol < numcols; iCol++) {
+      objective[iCol] = obj[iCol];
+    }
+  } else {
+    CoinFillN ( objective, numcols,0.0);
+  }
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendCols(numcols,columnStarts,rows,elements);
+  if (integerInformation_) {
+    char * temp = new char[numberColumns+numcols];
+    CoinMemcpyN(integerInformation_,numberColumns,temp);
+    delete [] integerInformation_;
+    integerInformation_ = temp;
+    for (iCol = 0; iCol < numcols; iCol++) 
+      integerInformation_[numberColumns+iCol]=0;
+  }
+  freeCachedResults();
+}
+//-----------------------------------------------------------------------------
+void 
+OsiClpSolverInterface::deleteCols(const int num, const int * columnIndices)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|8|64|128|256));
+  findIntegers(false);
+  deleteBranchingInfo(num,columnIndices);
+  modelPtr_->deleteColumns(num,columnIndices);
+  int nameDiscipline;
+  getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (num&&nameDiscipline) {
+    // Very clumsy (and inefficient) - need to sort and then go backwards in ? chunks
+    int * indices = CoinCopyOfArray(columnIndices,num);
+    std::sort(indices,indices+num);
+    int num2=num;
+    while(num2) {
+      int next = indices[num2-1];
+      int firstDelete = num2-1;
+      int i;
+      for (i=num2-2;i>=0;i--) {
+	if (indices[i]+1==next) {
+	  next --;
+	  firstDelete=i;
+	} else {
+	  break;
+	}
+      }
+      OsiSolverInterface::deleteColNames(indices[firstDelete],num2-firstDelete);
+      num2 = firstDelete;
+      assert (num2>=0);
+    }
+    delete [] indices;
+  }
+  // synchronize integers (again)
+  if (integerInformation_) {
+    int numberColumns = modelPtr_->numberColumns();
+    for (int i=0;i<numberColumns;i++) {
+      if (modelPtr_->isInteger(i))
+	integerInformation_[i]=1;
+      else
+	integerInformation_[i]=0;
+    }
+  }
+  basis_.deleteColumns(num,columnIndices);
+  linearObjective_ = modelPtr_->objective();
+  freeCachedResults();
+}
+//-----------------------------------------------------------------------------
+void 
+OsiClpSolverInterface::addRow(const CoinPackedVectorBase& vec,
+			      const double rowlb, const double rowub)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
+  freeCachedResults0();
+  int numberRows = modelPtr_->numberRows();
+  modelPtr_->resize(numberRows+1,modelPtr_->numberColumns());
+  basis_.resize(numberRows+1,modelPtr_->numberColumns());
+  setRowBounds(numberRows,rowlb,rowub);
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendRow(vec);
+  freeCachedResults1();
+}
+//-----------------------------------------------------------------------------
+void OsiClpSolverInterface::addRow(const CoinPackedVectorBase& vec,
+				const double rowlb, const double rowub,
+				std::string name)
+{
+  int ndx = getNumRows() ;
+  addRow(vec,rowlb,rowub) ;
+  setRowName(ndx,name) ;
+}
+//-----------------------------------------------------------------------------
+void 
+OsiClpSolverInterface::addRow(const CoinPackedVectorBase& vec,
+			      const char rowsen, const double rowrhs,   
+			      const double rowrng)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
+  freeCachedResults0();
+  int numberRows = modelPtr_->numberRows();
+  modelPtr_->resize(numberRows+1,modelPtr_->numberColumns());
+  basis_.resize(numberRows+1,modelPtr_->numberColumns());
+  double rowlb = 0, rowub = 0;
+  convertSenseToBound(rowsen, rowrhs, rowrng, rowlb, rowub);
+  setRowBounds(numberRows,rowlb,rowub);
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendRow(vec);
+  freeCachedResults1();
+}
+//-----------------------------------------------------------------------------
+void 
+OsiClpSolverInterface::addRow(int numberElements, const int * columns, const double * elements,
+			   const double rowlb, const double rowub) 
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
+  freeCachedResults0();
+  int numberRows = modelPtr_->numberRows();
+  modelPtr_->resize(numberRows+1,modelPtr_->numberColumns());
+  basis_.resize(numberRows+1,modelPtr_->numberColumns());
+  setRowBounds(numberRows,rowlb,rowub);
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendRow(numberElements, columns, elements);
+  CoinBigIndex starts[2];
+  starts[0]=0;
+  starts[1]=numberElements;
+  redoScaleFactors( 1,starts, columns, elements);
+  freeCachedResults1();
+}
+//-----------------------------------------------------------------------------
+void 
+OsiClpSolverInterface::addRows(const int numrows,
+			       const CoinPackedVectorBase * const * rows,
+			       const double* rowlb, const double* rowub)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
+  freeCachedResults0();
+  int numberRows = modelPtr_->numberRows();
+  modelPtr_->resize(numberRows+numrows,modelPtr_->numberColumns());
+  basis_.resize(numberRows+numrows,modelPtr_->numberColumns());
+  double * lower = modelPtr_->rowLower()+numberRows;
+  double * upper = modelPtr_->rowUpper()+numberRows;
+  int iRow;
+  for (iRow = 0; iRow < numrows; iRow++) {
+    if (rowlb) 
+      lower[iRow]= forceIntoRange(rowlb[iRow], -OsiClpInfinity, OsiClpInfinity);
+    else 
+      lower[iRow]=-OsiClpInfinity;
+    if (rowub) 
+      upper[iRow]= forceIntoRange(rowub[iRow], -OsiClpInfinity, OsiClpInfinity);
+    else 
+      upper[iRow]=OsiClpInfinity;
+    if (lower[iRow]<-1.0e27)
+      lower[iRow]=-COIN_DBL_MAX;
+    if (upper[iRow]>1.0e27)
+      upper[iRow]=COIN_DBL_MAX;
+  }
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendRows(numrows,rows);
+  freeCachedResults1();
+}
+//-----------------------------------------------------------------------------
+void 
+OsiClpSolverInterface::addRows(const int numrows,
+			       const CoinPackedVectorBase * const * rows,
+			       const char* rowsen, const double* rowrhs,   
+			       const double* rowrng)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
+  freeCachedResults0();
+  int numberRows = modelPtr_->numberRows();
+  modelPtr_->resize(numberRows+numrows,modelPtr_->numberColumns());
+  basis_.resize(numberRows+numrows,modelPtr_->numberColumns());
+  double * lower = modelPtr_->rowLower()+numberRows;
+  double * upper = modelPtr_->rowUpper()+numberRows;
+  int iRow;
+  for (iRow = 0; iRow < numrows; iRow++) {
+    double rowlb = 0, rowub = 0;
+    convertSenseToBound(rowsen[iRow], rowrhs[iRow], rowrng[iRow], 
+			rowlb, rowub);
+    lower[iRow]= forceIntoRange(rowlb, -OsiClpInfinity, OsiClpInfinity);
+    upper[iRow]= forceIntoRange(rowub, -OsiClpInfinity, OsiClpInfinity);
+    if (lower[iRow]<-1.0e27)
+      lower[iRow]=-COIN_DBL_MAX;
+    if (upper[iRow]>1.0e27)
+      upper[iRow]=COIN_DBL_MAX;
+  }
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendRows(numrows,rows);
+  freeCachedResults1();
+}
+void 
+OsiClpSolverInterface::addRows(const int numrows,
+			       const int * rowStarts, const int * columns, const double * element,
+			       const double* rowlb, const double* rowub)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
+  freeCachedResults0();
+  int numberRows = modelPtr_->numberRows();
+  modelPtr_->resize(numberRows+numrows,modelPtr_->numberColumns());
+  basis_.resize(numberRows+numrows,modelPtr_->numberColumns());
+  double * lower = modelPtr_->rowLower()+numberRows;
+  double * upper = modelPtr_->rowUpper()+numberRows;
+  int iRow;
+  for (iRow = 0; iRow < numrows; iRow++) {
+    if (rowlb) 
+      lower[iRow]= forceIntoRange(rowlb[iRow], -OsiClpInfinity, OsiClpInfinity);
+    else 
+      lower[iRow]=-OsiClpInfinity;
+    if (rowub) 
+      upper[iRow]= forceIntoRange(rowub[iRow], -OsiClpInfinity, OsiClpInfinity);
+    else 
+      upper[iRow]=OsiClpInfinity;
+    if (lower[iRow]<-1.0e27)
+      lower[iRow]=-COIN_DBL_MAX;
+    if (upper[iRow]>1.0e27)
+      upper[iRow]=COIN_DBL_MAX;
+  }
+  if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  modelPtr_->matrix()->appendRows(numrows,rowStarts,columns,element);
+  redoScaleFactors( numrows,rowStarts, columns, element);
+  freeCachedResults1();
+}
+//-----------------------------------------------------------------------------
+void 
+OsiClpSolverInterface::deleteRows(const int num, const int * rowIndices)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
+  // will still be optimal if all rows basic
+  bool allBasic=true;
+  int numBasis = basis_.getNumArtificial();
+  for (int i=0;i<num;i++) {
+    int iRow = rowIndices[i];
+    if (iRow<numBasis) {
+      if (basis_.getArtifStatus(iRow)!=CoinWarmStartBasis::basic) {
+	allBasic=false;
+	break;
+      }
+    }
+  }
+  int saveAlgorithm = allBasic ? lastAlgorithm_ : 999;
+  modelPtr_->deleteRows(num,rowIndices);
+  int nameDiscipline;
+  getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (num&&nameDiscipline) {
+    // Very clumsy (and inefficient) - need to sort and then go backwards in ? chunks
+    int * indices = CoinCopyOfArray(rowIndices,num);
+    std::sort(indices,indices+num);
+    int num2=num;
+    while(num2) {
+      int next = indices[num2-1];
+      int firstDelete = num2-1;
+      int i;
+      for (i=num2-2;i>=0;i--) {
+	if (indices[i]+1==next) {
+	  next --;
+	  firstDelete=i;
+	} else {
+	  break;
+	}
+      }
+      OsiSolverInterface::deleteRowNames(indices[firstDelete],num2-firstDelete);
+      num2 = firstDelete;
+      assert (num2>=0);
+    }
+    delete [] indices;
+  }
+  basis_.deleteRows(num,rowIndices);
+  CoinPackedMatrix * saveRowCopy = matrixByRow_;
+  matrixByRow_=NULL;
+  freeCachedResults();
+  modelPtr_->setNewRowCopy(NULL);
+  delete modelPtr_->scaledMatrix_;
+  modelPtr_->scaledMatrix_=NULL;
+  if (saveRowCopy) {
+    matrixByRow_=saveRowCopy;
+    matrixByRow_->deleteRows(num,rowIndices);
+    if (matrixByRow_->getNumElements()!=modelPtr_->clpMatrix()->getNumElements()) {
+      delete matrixByRow_; // odd type matrix
+      matrixByRow_=NULL;
+    }
+  }
+  lastAlgorithm_ = saveAlgorithm;
+  if ((specialOptions_&131072)!=0) 
+    lastNumberRows_=modelPtr_->numberRows();
+}
+
+//#############################################################################
+// Methods to input a problem
+//#############################################################################
+
+void
+OsiClpSolverInterface::loadProblem(const CoinPackedMatrix& matrix,
+				   const double* collb, const double* colub,   
+				   const double* obj,
+				   const double* rowlb, const double* rowub)
+{
+  modelPtr_->whatsChanged_ = 0;
+  // Get rid of integer information (modelPtr will get rid of its copy)
+  delete [] integerInformation_;
+  integerInformation_=NULL;
+  modelPtr_->loadProblem(matrix, collb, colub, obj, rowlb, rowub);
+  linearObjective_ = modelPtr_->objective();
+  freeCachedResults();
+  basis_=CoinWarmStartBasis();
+  if (ws_) {
+     delete ws_;
+     ws_ = 0;
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+/*
+  Expose the method that takes ClpMatrixBase. User request. Can't hurt, given
+  the number of non-OSI methods already here.
+*/
+void OsiClpSolverInterface::loadProblem (const ClpMatrixBase& matrix,
+					 const double* collb,
+					 const double* colub,   
+					 const double* obj,
+					 const double* rowlb,
+					 const double* rowub)
+{
+  modelPtr_->whatsChanged_ = 0;
+  // Get rid of integer information (modelPtr will get rid of its copy)
+  delete [] integerInformation_;
+  integerInformation_=NULL;
+  modelPtr_->loadProblem(matrix,collb,colub,obj,rowlb,rowub);
+  linearObjective_ = modelPtr_->objective();
+  freeCachedResults();
+  basis_=CoinWarmStartBasis();
+  if (ws_) {
+     delete ws_;
+     ws_ = 0;
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+OsiClpSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
+				     double*& collb, double*& colub,
+				     double*& obj,
+				     double*& rowlb, double*& rowub)
+{
+  modelPtr_->whatsChanged_ = 0;
+  // Get rid of integer information (modelPtr will get rid of its copy)
+  loadProblem(*matrix, collb, colub, obj, rowlb, rowub);
+  delete matrix;   matrix = NULL;
+  delete[] collb;  collb = NULL;
+  delete[] colub;  colub = NULL;
+  delete[] obj;    obj = NULL;
+  delete[] rowlb;  rowlb = NULL;
+  delete[] rowub;  rowub = NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+OsiClpSolverInterface::loadProblem(const CoinPackedMatrix& matrix,
+				   const double* collb, const double* colub,
+				   const double* obj,
+				   const char* rowsen, const double* rowrhs,   
+				   const double* rowrng)
+{
+  modelPtr_->whatsChanged_ = 0;
+  // Get rid of integer information (modelPtr will get rid of its copy)
+  // assert( rowsen != NULL );
+  // assert( rowrhs != NULL );
+  // If any of Rhs NULLs then create arrays
+  int numrows = matrix.getNumRows();
+  const char * rowsenUse = rowsen;
+  if (!rowsen) {
+    char * rowsen = new char [numrows];
+    for (int i=0;i<numrows;i++)
+      rowsen[i]='G';
+    rowsenUse = rowsen;
+  } 
+  const double * rowrhsUse = rowrhs;
+  if (!rowrhs) {
+    double * rowrhs = new double [numrows];
+    for (int i=0;i<numrows;i++)
+      rowrhs[i]=0.0;
+    rowrhsUse = rowrhs;
+  }
+  const double * rowrngUse = rowrng;
+  if (!rowrng) {
+    double * rowrng = new double [numrows];
+    for (int i=0;i<numrows;i++)
+      rowrng[i]=0.0;
+    rowrngUse = rowrng;
+  }
+  double * rowlb = new double[numrows];
+  double * rowub = new double[numrows];
+  for (int i = numrows-1; i >= 0; --i) {   
+    convertSenseToBound(rowsenUse[i],rowrhsUse[i],rowrngUse[i],rowlb[i],rowub[i]);
+  }
+  if (rowsen!=rowsenUse)
+    delete [] rowsenUse;
+  if (rowrhs!=rowrhsUse)
+    delete [] rowrhsUse;
+  if (rowrng!=rowrngUse)
+    delete [] rowrngUse;
+  loadProblem(matrix, collb, colub, obj, rowlb, rowub);
+  delete [] rowlb;
+  delete [] rowub;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+OsiClpSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
+				     double*& collb, double*& colub,
+				     double*& obj,
+				     char*& rowsen, double*& rowrhs,
+				     double*& rowrng)
+{
+  modelPtr_->whatsChanged_ = 0;
+  // Get rid of integer information (modelPtr will get rid of its copy)
+  loadProblem(*matrix, collb, colub, obj, rowsen, rowrhs, rowrng);
+  delete matrix;   matrix = NULL;
+  delete[] collb;  collb = NULL;
+  delete[] colub;  colub = NULL;
+  delete[] obj;    obj = NULL;
+  delete[] rowsen; rowsen = NULL;
+  delete[] rowrhs; rowrhs = NULL;
+  delete[] rowrng; rowrng = NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+OsiClpSolverInterface::loadProblem(const int numcols, const int numrows,
+				   const CoinBigIndex * start, const int* index,
+				   const double* value,
+				   const double* collb, const double* colub,
+				   const double* obj,
+				   const double* rowlb, const double* rowub)
+{
+  modelPtr_->whatsChanged_ = 0;
+  // Get rid of integer information (modelPtr will get rid of its copy)
+  delete [] integerInformation_;
+  integerInformation_=NULL;
+  modelPtr_->loadProblem(numcols, numrows, start,  index,
+	    value, collb, colub, obj,
+	    rowlb,  rowub);
+  linearObjective_ = modelPtr_->objective();
+  freeCachedResults();
+  basis_=CoinWarmStartBasis();
+  if (ws_) {
+     delete ws_;
+     ws_ = 0;
+  }
+}
+//-----------------------------------------------------------------------------
+
+void
+OsiClpSolverInterface::loadProblem(const int numcols, const int numrows,
+				   const CoinBigIndex * start, const int* index,
+				   const double* value,
+				   const double* collb, const double* colub,
+				   const double* obj,
+				   const char* rowsen, const double* rowrhs,   
+				   const double* rowrng)
+{
+  modelPtr_->whatsChanged_ = 0;
+  // Get rid of integer information (modelPtr will get rid of its copy)
+  // If any of Rhs NULLs then create arrays
+  const char * rowsenUse = rowsen;
+  if (!rowsen) {
+    char * rowsen = new char [numrows];
+    for (int i=0;i<numrows;i++)
+      rowsen[i]='G';
+    rowsenUse = rowsen;
+  } 
+  const double * rowrhsUse = rowrhs;
+  if (!rowrhs) {
+    double * rowrhs = new double [numrows];
+    for (int i=0;i<numrows;i++)
+      rowrhs[i]=0.0;
+    rowrhsUse = rowrhs;
+  }
+  const double * rowrngUse = rowrng;
+  if (!rowrng) {
+    double * rowrng = new double [numrows];
+    for (int i=0;i<numrows;i++)
+      rowrng[i]=0.0;
+    rowrngUse = rowrng;
+  }
+  double * rowlb = new double[numrows];
+  double * rowub = new double[numrows];
+  for (int i = numrows-1; i >= 0; --i) {   
+    convertSenseToBound(rowsenUse[i],rowrhsUse[i],rowrngUse[i],rowlb[i],rowub[i]);
+  }
+  if (rowsen!=rowsenUse)
+    delete [] rowsenUse;
+  if (rowrhs!=rowrhsUse)
+    delete [] rowrhsUse;
+  if (rowrng!=rowrngUse)
+    delete [] rowrngUse;
+  loadProblem(numcols, numrows, start,  index, value, collb, colub, obj,
+	      rowlb,  rowub);
+  delete[] rowlb;
+  delete[] rowub;
+}
+// This loads a model from a coinModel object - returns number of errors
+int 
+OsiClpSolverInterface::loadFromCoinModel (  CoinModel & modelObject, bool keepSolution)
+{
+  modelPtr_->whatsChanged_ = 0;
+  int numberErrors = 0;
+  // Set arrays for normal use
+  double * rowLower = modelObject.rowLowerArray();
+  double * rowUpper = modelObject.rowUpperArray();
+  double * columnLower = modelObject.columnLowerArray();
+  double * columnUpper = modelObject.columnUpperArray();
+  double * objective = modelObject.objectiveArray();
+  int * integerType = modelObject.integerTypeArray();
+  double * associated = modelObject.associatedArray();
+  // If strings then do copies
+  if (modelObject.stringsExist()) {
+    numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                            objective, integerType,associated);
+  }
+  CoinPackedMatrix matrix;
+  modelObject.createPackedMatrix(matrix,associated);
+  int numberRows = modelObject.numberRows();
+  int numberColumns = modelObject.numberColumns();
+  CoinWarmStart * ws = getWarmStart();
+  bool restoreBasis = keepSolution && numberRows&&numberRows==getNumRows()&&
+    numberColumns==getNumCols();
+  loadProblem(matrix, 
+              columnLower, columnUpper, objective, rowLower, rowUpper);
+  if (restoreBasis)
+    setWarmStart(ws);
+  delete ws;
+  // Do names if wanted
+  int numberItems;
+  numberItems = modelObject.rowNames()->numberItems();
+  if (numberItems) {
+    const char *const * rowNames=modelObject.rowNames()->names();
+    modelPtr_->copyRowNames(rowNames,0,numberItems);
+  }
+  numberItems = modelObject.columnNames()->numberItems();
+  if (numberItems) {
+    const char *const * columnNames=modelObject.columnNames()->names();
+    modelPtr_->copyColumnNames(columnNames,0,numberItems);
+  }
+  // Do integers if wanted
+  assert(integerType);
+  for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (integerType[iColumn])
+      setInteger(iColumn);
+  }
+  if (rowLower!=modelObject.rowLowerArray()||
+      columnLower!=modelObject.columnLowerArray()) {
+    delete [] rowLower;
+    delete [] rowUpper;
+    delete [] columnLower;
+    delete [] columnUpper;
+    delete [] objective;
+    delete [] integerType;
+    delete [] associated;
+    //if (numberErrors)
+    //  handler_->message(CLP_BAD_STRING_VALUES,messages_)
+    //    <<numberErrors
+    //    <<CoinMessageEol;
+  }
+  modelPtr_->optimizationDirection_ = modelObject.optimizationDirection();  
+  return numberErrors;
+}
+
+//-----------------------------------------------------------------------------
+// Write mps files
+//-----------------------------------------------------------------------------
+
+void OsiClpSolverInterface::writeMps(const char * filename,
+				     const char * extension,
+				     double objSense) const
+{
+  std::string f(filename);
+  std::string e(extension);
+  std::string fullname;
+  if (e!="") {
+    fullname = f + "." + e;
+  } else {
+    // no extension so no trailing period
+    fullname = f;
+  }
+  // get names
+  const char * const * const rowNames = modelPtr_->rowNamesAsChar();
+  const char * const * const columnNames = modelPtr_->columnNamesAsChar();
+  // Fall back on Osi version - possibly with names
+  OsiSolverInterface::writeMpsNative(fullname.c_str(), 
+				     const_cast<const char **>(rowNames),
+                                     const_cast<const char **>(columnNames),0,2,objSense,
+				     numberSOS_,setInfo_);
+  if (rowNames) {
+    modelPtr_->deleteNamesAsChar(rowNames, modelPtr_->numberRows_+1);
+    modelPtr_->deleteNamesAsChar(columnNames, modelPtr_->numberColumns_);
+  }
+}
+
+int 
+OsiClpSolverInterface::writeMpsNative(const char *filename, 
+		  const char ** rowNames, const char ** columnNames,
+		  int formatType,int numberAcross,double objSense) const 
+{
+  return OsiSolverInterface::writeMpsNative(filename, rowNames, columnNames,
+			       formatType, numberAcross,objSense,
+					    numberSOS_,setInfo_);
+}
+
+//#############################################################################
+// CLP specific public interfaces
+//#############################################################################
+
+ClpSimplex * OsiClpSolverInterface::getModelPtr() const
+{
+  int saveAlgorithm = lastAlgorithm_;
+  //freeCachedResults();
+  lastAlgorithm_ = saveAlgorithm;
+  //bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
+  return modelPtr_;
+}
+
+//------------------------------------------------------------------- 
+
+//#############################################################################
+// Constructors, destructors clone and assignment
+//#############################################################################
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiClpSolverInterface::OsiClpSolverInterface ()
+:
+OsiSolverInterface(),
+rowsense_(NULL),
+rhs_(NULL),
+rowrange_(NULL),
+ws_(NULL),
+rowActivity_(NULL),
+columnActivity_(NULL),
+numberSOS_(0),
+setInfo_(NULL),
+smallModel_(NULL),
+factorization_(NULL),
+smallestElementInCut_(1.0e-15),
+smallestChangeInCut_(1.0e-10),
+largestAway_(-1.0),
+spareArrays_(NULL),
+matrixByRow_(NULL),
+matrixByRowAtContinuous_(NULL),  
+integerInformation_(NULL),
+whichRange_(NULL),
+fakeMinInSimplex_(false),
+linearObjective_(NULL),
+cleanupScaling_(0),
+specialOptions_(0x80000000),
+baseModel_(NULL),
+lastNumberRows_(0),
+continuousModel_(NULL),
+fakeObjective_(NULL)
+{
+  //printf("in default %x\n",this);
+  modelPtr_=NULL;
+  notOwned_=false;
+  disasterHandler_ = new OsiClpDisasterHandler();
+  reset();
+}
+
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+OsiSolverInterface * OsiClpSolverInterface::clone(bool CopyData) const
+{
+  //printf("in clone %x\n",this);
+  OsiClpSolverInterface * newSolver;
+  if (CopyData) {
+    newSolver = new OsiClpSolverInterface(*this);
+  } else {
+    newSolver = new OsiClpSolverInterface();
+  }
+#if 0
+  const double * obj = newSolver->getObjCoefficients();
+  const double * oldObj = getObjCoefficients();
+  if(newSolver->getNumCols()>3787)
+    printf("%x - obj %x (from %x) val %g\n",newSolver,obj,oldObj,obj[3787]);
+#endif
+  return newSolver;
+}
+
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiClpSolverInterface::OsiClpSolverInterface (
+                  const OsiClpSolverInterface & rhs)
+: OsiSolverInterface(rhs),
+rowsense_(NULL),
+rhs_(NULL),
+rowrange_(NULL),
+ws_(NULL),
+rowActivity_(NULL),
+columnActivity_(NULL),
+  stuff_(rhs.stuff_),
+numberSOS_(rhs.numberSOS_),
+setInfo_(NULL),
+smallModel_(NULL),
+factorization_(NULL),
+smallestElementInCut_(rhs.smallestElementInCut_),
+smallestChangeInCut_(rhs.smallestChangeInCut_),
+largestAway_(-1.0),
+spareArrays_(NULL),
+basis_(),
+itlimOrig_(9999999),
+lastAlgorithm_(0),
+notOwned_(false),
+matrixByRow_(NULL),
+matrixByRowAtContinuous_(NULL),  
+integerInformation_(NULL),
+whichRange_(NULL),
+fakeMinInSimplex_(rhs.fakeMinInSimplex_)
+{
+  //printf("in copy %x - > %x\n",&rhs,this);
+  if ( rhs.modelPtr_  ) 
+    modelPtr_ = new ClpSimplex(*rhs.modelPtr_);
+  else
+    modelPtr_ = new ClpSimplex();
+  if ( rhs.baseModel_  ) 
+    baseModel_ = new ClpSimplex(*rhs.baseModel_);
+  else
+    baseModel_ = NULL;
+  if ( rhs.continuousModel_  ) 
+    continuousModel_ = new ClpSimplex(*rhs.continuousModel_);
+  else
+    continuousModel_ = NULL;
+  if (rhs.matrixByRowAtContinuous_)
+    matrixByRowAtContinuous_ = new CoinPackedMatrix(*rhs.matrixByRowAtContinuous_);
+  if ( rhs.disasterHandler_  ) 
+    disasterHandler_ = dynamic_cast<OsiClpDisasterHandler *>(rhs.disasterHandler_->clone());
+  else
+    disasterHandler_ = NULL;
+  if (rhs.fakeObjective_)
+    fakeObjective_ = new ClpLinearObjective(*rhs.fakeObjective_);
+  else
+    fakeObjective_ = NULL;
+  linearObjective_ = modelPtr_->objective();
+  if ( rhs.ws_ ) 
+    ws_ = new CoinWarmStartBasis(*rhs.ws_);
+  basis_ = rhs.basis_;
+  if (rhs.integerInformation_) {
+    int numberColumns = modelPtr_->numberColumns();
+    integerInformation_ = new char[numberColumns];
+    CoinMemcpyN(rhs.integerInformation_,	numberColumns,integerInformation_);
+  }
+  saveData_ = rhs.saveData_;
+  solveOptions_  = rhs.solveOptions_;
+  cleanupScaling_ = rhs.cleanupScaling_;
+  specialOptions_ = rhs.specialOptions_;
+  lastNumberRows_ = rhs.lastNumberRows_;
+  rowScale_ = rhs.rowScale_;
+  columnScale_ = rhs.columnScale_;
+  fillParamMaps();
+  messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
+  if (numberSOS_) {
+    setInfo_ = new CoinSet[numberSOS_];
+    for (int i=0;i<numberSOS_;i++)
+      setInfo_[i]=rhs.setInfo_[i];
+  }
+}
+
+// Borrow constructor - only delete one copy
+OsiClpSolverInterface::OsiClpSolverInterface (ClpSimplex * rhs,
+					      bool reallyOwn)
+:
+OsiSolverInterface(),
+rowsense_(NULL),
+rhs_(NULL),
+rowrange_(NULL),
+ws_(NULL),
+rowActivity_(NULL),
+columnActivity_(NULL),
+numberSOS_(0),
+setInfo_(NULL),
+smallModel_(NULL),
+factorization_(NULL),
+smallestElementInCut_(1.0e-15),
+smallestChangeInCut_(1.0e-10),
+largestAway_(-1.0),
+spareArrays_(NULL),
+basis_(),
+itlimOrig_(9999999),
+lastAlgorithm_(0),
+notOwned_(false),
+matrixByRow_(NULL),
+matrixByRowAtContinuous_(NULL),  
+integerInformation_(NULL),
+whichRange_(NULL),
+fakeMinInSimplex_(false),
+cleanupScaling_(0),
+specialOptions_(0x80000000),
+baseModel_(NULL),
+lastNumberRows_(0),
+continuousModel_(NULL),
+fakeObjective_(NULL)
+{
+  disasterHandler_ = new OsiClpDisasterHandler();
+  //printf("in borrow %x - > %x\n",&rhs,this);
+  modelPtr_ = rhs;
+  basis_.resize(modelPtr_->numberRows(),modelPtr_->numberColumns());
+  linearObjective_ = modelPtr_->objective();
+  if (rhs) {
+    notOwned_=!reallyOwn;
+
+    if (rhs->integerInformation()) {
+      int numberColumns = modelPtr_->numberColumns();
+      integerInformation_ = new char[numberColumns];
+      CoinMemcpyN(rhs->integerInformation(),	numberColumns,integerInformation_);
+    }
+  }
+  fillParamMaps();
+}
+    
+// Releases so won't error
+void 
+OsiClpSolverInterface::releaseClp()
+{
+  modelPtr_=NULL;
+  notOwned_=false;
+}
+    
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiClpSolverInterface::~OsiClpSolverInterface ()
+{
+  //printf("in destructor %x\n",this);
+  freeCachedResults();
+  if (!notOwned_)
+    delete modelPtr_;
+  delete baseModel_;
+  delete continuousModel_;
+  delete disasterHandler_;
+  delete fakeObjective_;
+  delete ws_;
+  delete [] rowActivity_;
+  delete [] columnActivity_;
+  delete [] setInfo_;
+#ifdef KEEP_SMALL
+  if (smallModel_) {
+    delete [] spareArrays_;
+    spareArrays_ = NULL;
+    delete smallModel_;
+    smallModel_=NULL;
+  }
+#endif
+  assert(smallModel_==NULL);
+  assert(factorization_==NULL);
+  assert(spareArrays_==NULL);
+  delete [] integerInformation_;
+  delete matrixByRowAtContinuous_;
+  delete matrixByRow_;
+}
+
+//-------------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiClpSolverInterface &
+OsiClpSolverInterface::operator=(const OsiClpSolverInterface& rhs)
+{
+  if (this != &rhs) {    
+    //printf("in = %x - > %x\n",&rhs,this);
+    OsiSolverInterface::operator=(rhs);
+    freeCachedResults();
+    if (!notOwned_)
+      delete modelPtr_;
+    delete ws_;
+    if ( rhs.modelPtr_  ) 
+      modelPtr_ = new ClpSimplex(*rhs.modelPtr_);
+    delete baseModel_;
+    if ( rhs.baseModel_  ) 
+      baseModel_ = new ClpSimplex(*rhs.baseModel_);
+    else
+      baseModel_ = NULL;
+    delete continuousModel_;
+    if ( rhs.continuousModel_  ) 
+      continuousModel_ = new ClpSimplex(*rhs.continuousModel_);
+    else
+      continuousModel_ = NULL;
+    delete matrixByRowAtContinuous_;
+    delete matrixByRow_;
+    matrixByRow_=NULL;
+    if (rhs.matrixByRowAtContinuous_)
+      matrixByRowAtContinuous_ = new CoinPackedMatrix(*rhs.matrixByRowAtContinuous_);
+    else
+      matrixByRowAtContinuous_=NULL;
+    delete disasterHandler_;
+    if ( rhs.disasterHandler_  ) 
+      disasterHandler_ = dynamic_cast<OsiClpDisasterHandler *>(rhs.disasterHandler_->clone());
+    else
+      disasterHandler_ = NULL;
+    delete fakeObjective_;
+    if (rhs.fakeObjective_)
+      fakeObjective_ = new ClpLinearObjective(*rhs.fakeObjective_);
+    else
+      fakeObjective_ = NULL;
+    notOwned_=false;
+    linearObjective_ = modelPtr_->objective();
+    saveData_ = rhs.saveData_;
+    solveOptions_  = rhs.solveOptions_;
+    cleanupScaling_ = rhs.cleanupScaling_;
+    specialOptions_ = rhs.specialOptions_;
+    lastNumberRows_ = rhs.lastNumberRows_;
+    rowScale_ = rhs.rowScale_;
+    columnScale_ = rhs.columnScale_;
+    basis_ = rhs.basis_;
+    stuff_ = rhs.stuff_;
+    if (rhs.integerInformation_) {
+      int numberColumns = modelPtr_->numberColumns();
+      integerInformation_ = new char[numberColumns];
+      CoinMemcpyN(rhs.integerInformation_,	numberColumns,integerInformation_);
+    }
+    if ( rhs.ws_ ) 
+      ws_ = new CoinWarmStartBasis(*rhs.ws_);
+    else
+      ws_=NULL;
+    delete [] rowActivity_;
+    delete [] columnActivity_;
+    rowActivity_=NULL;
+    columnActivity_=NULL;
+    delete [] setInfo_;
+    numberSOS_ = rhs.numberSOS_;
+    setInfo_=NULL;
+    if (numberSOS_) {
+      setInfo_ = new CoinSet[numberSOS_];
+      for (int i=0;i<numberSOS_;i++)
+	setInfo_[i]=rhs.setInfo_[i];
+    }
+    assert(smallModel_==NULL);
+    assert(factorization_==NULL);
+    smallestElementInCut_ = rhs.smallestElementInCut_;
+    smallestChangeInCut_ = rhs.smallestChangeInCut_;
+    largestAway_ = -1.0;
+    assert(spareArrays_==NULL);
+    basis_ = rhs.basis_;
+    fillParamMaps();
+    messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
+  }
+  return *this;
+}
+
+//#############################################################################
+// Applying cuts
+//#############################################################################
+
+void OsiClpSolverInterface::applyRowCut( const OsiRowCut & rowCut )
+{
+  applyRowCuts(1, &rowCut);
+}
+/* Apply a collection of row cuts which are all effective.
+   applyCuts seems to do one at a time which seems inefficient.
+*/
+void 
+OsiClpSolverInterface::applyRowCuts(int numberCuts, const OsiRowCut * cuts)
+{
+  if (numberCuts) {
+    // Say can't gurantee optimal basis etc
+    lastAlgorithm_=999;
+
+    // Thanks to js
+    const OsiRowCut * * cutsp = new const OsiRowCut * [numberCuts];
+    for (int i=0;i<numberCuts;i++) 
+      cutsp[i] = &cuts[i];
+    
+    applyRowCuts(numberCuts, cutsp);
+    
+    delete [] cutsp;
+  }
+}
+/* Apply a collection of row cuts which are all effective.
+   applyCuts seems to do one at a time which seems inefficient.
+*/
+void 
+OsiClpSolverInterface::applyRowCuts(int numberCuts, const OsiRowCut ** cuts)
+{
+  int i;
+  if (!numberCuts)
+    return;
+  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
+  CoinPackedMatrix * saveRowCopy = matrixByRow_;
+  matrixByRow_=NULL;
+#if 0 // was #ifndef NDEBUG
+  int nameDiscipline;
+  getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  assert (!nameDiscipline);
+#endif
+  freeCachedResults0();
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  int numberRows = modelPtr_->numberRows();
+  modelPtr_->resize(numberRows+numberCuts,modelPtr_->numberColumns());
+  basis_.resize(numberRows+numberCuts,modelPtr_->numberColumns());
+  // redo as relaxed - use modelPtr_-> addRows with starts etc
+  int size = 0;
+  for (i=0;i<numberCuts;i++) 
+    size += cuts[i]->row().getNumElements();
+  CoinBigIndex * starts = new CoinBigIndex [numberCuts+1];
+  int * indices = new int[size];
+  double * elements = new double[size];
+  double * lower = modelPtr_->rowLower()+numberRows;
+  double * upper = modelPtr_->rowUpper()+numberRows;
+  const double * columnLower = modelPtr_->columnLower();
+  const double * columnUpper = modelPtr_->columnUpper();
+  size=0;
+  for (i=0;i<numberCuts;i++) {
+    double rowLb = cuts[i]->lb();
+    double rowUb = cuts[i]->ub();
+    int n=cuts[i]->row().getNumElements();
+    const int * index = cuts[i]->row().getIndices();
+    const double * elem = cuts[i]->row().getElements();
+    starts[i]=size;
+    for (int j=0;j<n;j++) {
+      double value = elem[j];
+      int column = index[j];
+      if (fabs(value)>=smallestChangeInCut_) {
+        // always take
+        indices[size]=column;
+        elements[size++]=value;
+      } else if (fabs(value)>=smallestElementInCut_) {
+        double lowerValue = columnLower[column];
+        double upperValue = columnUpper[column];
+        double difference = upperValue-lowerValue;
+        if (difference<1.0e20&&difference*fabs(value)<smallestChangeInCut_&&
+            (rowLb<-1.0e20||rowUb>1.0e20)) {
+          // Take out and adjust to relax
+          //printf("small el %g adjusted\n",value);
+          if (rowLb>-1.0e20) {
+            // just lower bound on row
+            if (value>0.0) {
+              // pretend at upper
+              rowLb -= value*upperValue;
+            } else {
+              // pretend at lower
+              rowLb -= value*lowerValue;
+            }
+          } else {
+            // just upper bound on row
+            if (value>0.0) {
+              // pretend at lower
+              rowUb -= value*lowerValue;
+            } else {
+              // pretend at upper
+              rowUb -= value*upperValue;
+            }
+          }
+        } else {
+          // take (unwillingly)
+          indices[size]=column;
+          elements[size++]=value;
+        }
+      } else {
+        //printf("small el %g ignored\n",value);
+      }
+    }
+    lower[i]= forceIntoRange(rowLb, -OsiClpInfinity, OsiClpInfinity);
+    upper[i]= forceIntoRange(rowUb, -OsiClpInfinity, OsiClpInfinity);
+    if (lower[i]<-1.0e27)
+      lower[i]=-COIN_DBL_MAX;
+    if (upper[i]>1.0e27)
+      upper[i]=COIN_DBL_MAX;
+  }
+  starts[numberCuts]=size;
+ if (!modelPtr_->clpMatrix())
+    modelPtr_->createEmptyMatrix();
+  //modelPtr_->matrix()->appendRows(numberCuts,rows);
+  modelPtr_->clpMatrix()->appendMatrix(numberCuts,0,starts,indices,elements);
+  modelPtr_->setNewRowCopy(NULL);
+  modelPtr_->setClpScaledMatrix(NULL);
+  freeCachedResults1();
+  redoScaleFactors( numberCuts,starts, indices, elements);
+  if (saveRowCopy) {
+#if 1
+    matrixByRow_=saveRowCopy;
+    matrixByRow_->appendRows(numberCuts,starts,indices,elements,0);
+    if (matrixByRow_->getNumElements()!=modelPtr_->clpMatrix()->getNumElements()) {
+      delete matrixByRow_; // odd type matrix
+      matrixByRow_=NULL;
+    }
+#else
+    delete saveRowCopy;
+#endif
+  }
+  delete [] starts;
+  delete [] indices;
+  delete [] elements;
+
+}
+//#############################################################################
+// Apply Cuts
+//#############################################################################
+
+OsiSolverInterface::ApplyCutsReturnCode
+OsiClpSolverInterface::applyCuts( const OsiCuts & cs, double effectivenessLb ) 
+{
+  OsiSolverInterface::ApplyCutsReturnCode retVal;
+  int i;
+
+  // Loop once for each column cut
+  for ( i=0; i<cs.sizeColCuts(); i ++ ) {
+    if ( cs.colCut(i).effectiveness() < effectivenessLb ) {
+      retVal.incrementIneffective();
+      continue;
+    }
+    if ( !cs.colCut(i).consistent() ) {
+      retVal.incrementInternallyInconsistent();
+      continue;
+    }
+    if ( !cs.colCut(i).consistent(*this) ) {
+      retVal.incrementExternallyInconsistent();
+      continue;
+    }
+    if ( cs.colCut(i).infeasible(*this) ) {
+      retVal.incrementInfeasible();
+      continue;
+    }
+    applyColCut( cs.colCut(i) );
+    retVal.incrementApplied();
+  }
+
+  // Loop once for each row cut
+  const OsiRowCut ** addCuts = new const OsiRowCut* [cs.sizeRowCuts()];
+  int nAdd=0;
+  for ( i=0; i<cs.sizeRowCuts(); i ++ ) {
+    if ( cs.rowCut(i).effectiveness() < effectivenessLb ) {
+      retVal.incrementIneffective();
+      continue;
+    }
+    if ( !cs.rowCut(i).consistent() ) {
+      retVal.incrementInternallyInconsistent();
+      continue;
+    }
+    if ( !cs.rowCut(i).consistent(*this) ) {
+      retVal.incrementExternallyInconsistent();
+      continue;
+    }
+    if ( cs.rowCut(i).infeasible(*this) ) {
+      retVal.incrementInfeasible();
+      continue;
+    }
+    addCuts[nAdd++] = cs.rowCutPtr(i);
+    retVal.incrementApplied();
+  }
+  // now apply
+  applyRowCuts(nAdd,addCuts);
+  delete [] addCuts;
+  
+  return retVal;
+}
+// Extend scale factors
+void 
+OsiClpSolverInterface::redoScaleFactors(int numberAdd,const CoinBigIndex * starts,
+					const int * indices, const double * elements)
+{
+  if ((specialOptions_&131072)!=0) {
+    int numberRows = modelPtr_->numberRows()-numberAdd;
+    assert (lastNumberRows_==numberRows); // ???
+    int iRow;
+    int newNumberRows = numberRows + numberAdd;
+    rowScale_.extend(static_cast<int>(2*newNumberRows*sizeof(double)));
+    double * rowScale = rowScale_.array();
+    double * oldInverseScale = rowScale + lastNumberRows_;
+    double * inverseRowScale = rowScale + newNumberRows;
+    for (iRow=lastNumberRows_-1;iRow>=0;iRow--)
+      inverseRowScale[iRow] = oldInverseScale[iRow] ;
+    //int numberColumns = baseModel_->numberColumns();
+    const double * columnScale = columnScale_.array();
+    //const double * inverseColumnScale = columnScale + numberColumns;
+    // Geometric mean on row scales
+    // adjust arrays
+    rowScale += lastNumberRows_;
+    inverseRowScale += lastNumberRows_;
+    for (iRow=0;iRow<numberAdd;iRow++) {
+      CoinBigIndex j;
+      double largest=1.0e-20;
+      double smallest=1.0e50;
+      for (j=starts[iRow];j<starts[iRow+1];j++) {
+	int iColumn = indices[j];
+	double value = fabs(elements[j]);
+	// Don't bother with tiny elements
+	if (value>1.0e-20) {
+	  value *= columnScale[iColumn];
+	  largest = CoinMax(largest,value);
+	  smallest = CoinMin(smallest,value);
+	}
+      }
+      double scale=sqrt(smallest*largest);
+      scale=CoinMax(1.0e-10,CoinMin(1.0e10,scale));
+      inverseRowScale[iRow]=scale;
+      rowScale[iRow]=1.0/scale;
+    }
+    lastNumberRows_=newNumberRows;
+  }
+}
+// Delete all scale factor stuff and reset option
+void OsiClpSolverInterface::deleteScaleFactors()
+{
+  delete baseModel_;
+  baseModel_=NULL;
+  lastNumberRows_=0;
+  specialOptions_ &= ~131072;
+}
+//-----------------------------------------------------------------------------
+
+void OsiClpSolverInterface::applyColCut( const OsiColCut & cc )
+{
+  modelPtr_->whatsChanged_ &= (0x1ffff&~(128|256));
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  double * lower = modelPtr_->columnLower();
+  double * upper = modelPtr_->columnUpper();
+  const CoinPackedVector & lbs = cc.lbs();
+  const CoinPackedVector & ubs = cc.ubs();
+  int i;
+
+  for ( i=0; i<lbs.getNumElements(); i++ ) {
+    int iCol = lbs.getIndices()[i];
+    double value = lbs.getElements()[i];
+    if ( value > lower[iCol] )
+      lower[iCol]= value;
+  }
+  for ( i=0; i<ubs.getNumElements(); i++ ) {
+    int iCol = ubs.getIndices()[i];
+    double value = ubs.getElements()[i];
+    if ( value < upper[iCol] )
+      upper[iCol]= value;
+  }
+}
+//#############################################################################
+// Private methods
+//#############################################################################
+
+
+//------------------------------------------------------------------- 
+
+void OsiClpSolverInterface::freeCachedResults() const
+{  
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  delete [] rowsense_;
+  delete [] rhs_;
+  delete [] rowrange_;
+  delete matrixByRow_;
+  if (modelPtr_&&modelPtr_->scaledMatrix_) {
+    delete modelPtr_->scaledMatrix_;
+    modelPtr_->scaledMatrix_=NULL;
+  }
+  //delete ws_;
+  rowsense_=NULL;
+  rhs_=NULL;
+  rowrange_=NULL;
+  matrixByRow_=NULL;
+  //ws_ = NULL;
+  if (modelPtr_&&modelPtr_->clpMatrix()) {
+    modelPtr_->clpMatrix()->refresh(modelPtr_); // make sure all clean
+#ifndef NDEBUG
+    ClpPackedMatrix * clpMatrix = dynamic_cast<ClpPackedMatrix *> (modelPtr_->clpMatrix());
+    if (clpMatrix) {
+      if (clpMatrix->getNumCols())
+	assert (clpMatrix->getNumRows()==modelPtr_->getNumRows());
+      if (clpMatrix->getNumRows())
+	assert (clpMatrix->getNumCols()==modelPtr_->getNumCols());
+    }
+#endif
+  }
+}
+
+//------------------------------------------------------------------- 
+
+void OsiClpSolverInterface::freeCachedResults0() const
+{  
+  delete [] rowsense_;
+  delete [] rhs_;
+  delete [] rowrange_;
+  rowsense_=NULL;
+  rhs_=NULL;
+  rowrange_=NULL;
+}
+
+//------------------------------------------------------------------- 
+
+void OsiClpSolverInterface::freeCachedResults1() const
+{  
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  delete matrixByRow_;
+  matrixByRow_=NULL;
+  //ws_ = NULL;
+  if (modelPtr_&&modelPtr_->clpMatrix()) {
+    delete modelPtr_->scaledMatrix_;
+    modelPtr_->scaledMatrix_=NULL;
+    modelPtr_->clpMatrix()->refresh(modelPtr_); // make sure all clean
+#ifndef NDEBUG
+    ClpPackedMatrix * clpMatrix = dynamic_cast<ClpPackedMatrix *> (modelPtr_->clpMatrix());
+    if (clpMatrix) {
+      assert (clpMatrix->getNumRows()==modelPtr_->getNumRows());
+      assert (clpMatrix->getNumCols()==modelPtr_->getNumCols());
+    }
+#endif
+  }
+}
+
+//------------------------------------------------------------------
+void OsiClpSolverInterface::extractSenseRhsRange() const
+{
+  if (rowsense_ == NULL) {
+    // all three must be NULL
+    assert ((rhs_ == NULL) && (rowrange_ == NULL));
+    
+    int nr=modelPtr_->numberRows();
+    if ( nr!=0 ) {
+      rowsense_ = new char[nr];
+      rhs_ = new double[nr];
+      rowrange_ = new double[nr];
+      std::fill(rowrange_,rowrange_+nr,0.0);
+      
+      const double * lb = modelPtr_->rowLower();
+      const double * ub = modelPtr_->rowUpper();
+      
+      int i;
+      for ( i=0; i<nr; i++ ) {
+        convertBoundToSense(lb[i], ub[i], rowsense_[i], rhs_[i], rowrange_[i]);
+      }
+    }
+  }
+}
+// Set language
+void 
+OsiClpSolverInterface::newLanguage(CoinMessages::Language language)
+{
+  modelPtr_->newLanguage(language);
+  OsiSolverInterface::newLanguage(language);
+}
+//#############################################################################
+
+void
+OsiClpSolverInterface::fillParamMaps()
+{
+  assert (static_cast<int> (OsiMaxNumIteration)==        static_cast<int>(ClpMaxNumIteration));
+  assert (static_cast<int> (OsiMaxNumIterationHotStart)==static_cast<int>(ClpMaxNumIterationHotStart));
+  //assert (static_cast<int> (OsiLastIntParam)==           static_cast<int>(ClpLastIntParam));
+  
+  assert (static_cast<int> (OsiDualObjectiveLimit)==  static_cast<int>(ClpDualObjectiveLimit));
+  assert (static_cast<int> (OsiPrimalObjectiveLimit)==static_cast<int>(ClpPrimalObjectiveLimit));
+  assert (static_cast<int> (OsiDualTolerance)==       static_cast<int>(ClpDualTolerance));
+  assert (static_cast<int> (OsiPrimalTolerance)==     static_cast<int>(ClpPrimalTolerance));
+  assert (static_cast<int> (OsiObjOffset)==           static_cast<int>(ClpObjOffset));
+  //assert (static_cast<int> (OsiLastDblParam)==        static_cast<int>(ClpLastDblParam));
+  
+  assert (static_cast<int> (OsiProbName)==    static_cast<int> (ClpProbName));
+  //strParamMap_[OsiLastStrParam] = ClpLastStrParam;
+}
+// Sets up basis
+void 
+OsiClpSolverInterface::setBasis ( const CoinWarmStartBasis & basis)
+{
+  setBasis(basis,modelPtr_);
+  setWarmStart(&basis); 
+}
+// Warm start
+CoinWarmStartBasis
+OsiClpSolverInterface::getBasis(ClpSimplex * model) const
+{
+  int iRow,iColumn;
+  int numberRows = model->numberRows();
+  int numberColumns = model->numberColumns();
+  CoinWarmStartBasis basis;
+  basis.setSize(numberColumns,numberRows);
+  if (model->statusExists()) {
+    // Flip slacks
+    int lookupA[]={0,1,3,2,0,2};
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int iStatus = model->getRowStatus(iRow);
+      iStatus = lookupA[iStatus];
+      basis.setArtifStatus(iRow,static_cast<CoinWarmStartBasis::Status> (iStatus));
+    }
+    int lookupS[]={0,1,2,3,0,3};
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      int iStatus = model->getColumnStatus(iColumn);
+      iStatus = lookupS[iStatus];
+      basis.setStructStatus(iColumn,static_cast<CoinWarmStartBasis::Status> (iStatus));
+    }
+  }
+  //basis.print();
+  return basis;
+}
+// Warm start from statusArray
+CoinWarmStartBasis * 
+OsiClpSolverInterface::getBasis(const unsigned char * statusArray) const 
+{
+  int iRow,iColumn;
+  int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  CoinWarmStartBasis * basis = new CoinWarmStartBasis();
+  basis->setSize(numberColumns,numberRows);
+  // Flip slacks
+  int lookupA[]={0,1,3,2,0,2};
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int iStatus = statusArray[numberColumns+iRow]&7;
+    iStatus = lookupA[iStatus];
+    basis->setArtifStatus(iRow,static_cast<CoinWarmStartBasis::Status> (iStatus));
+  }
+  int lookupS[]={0,1,2,3,0,3};
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    int iStatus = statusArray[iColumn]&7;
+    iStatus = lookupS[iStatus];
+    basis->setStructStatus(iColumn,static_cast<CoinWarmStartBasis::Status> (iStatus));
+  }
+  //basis->print();
+  return basis;
+}
+// Sets up basis
+void 
+OsiClpSolverInterface::setBasis ( const CoinWarmStartBasis & basis,
+				  ClpSimplex * model)
+{
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  // transform basis to status arrays
+  int iRow,iColumn;
+  int numberRows = model->numberRows();
+  int numberColumns = model->numberColumns();
+  if (!model->statusExists()) {
+    /*
+      get status arrays
+      ClpBasis would seem to have overheads and we will need
+      extra bits anyway.
+    */
+    model->createStatus();
+  }
+  if (basis.getNumArtificial()!=numberRows||
+      basis.getNumStructural()!=numberColumns) {
+    CoinWarmStartBasis basis2 = basis;
+    // resize 
+    basis2.resize(numberRows,numberColumns);
+    // move status
+    model->createStatus();
+    // For rows lower and upper are flipped
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int stat = basis2.getArtifStatus(iRow);
+      if (stat>1)
+	stat = 5 - stat; // so 2->3 and 3->2
+      model->setRowStatus(iRow, static_cast<ClpSimplex::Status> (stat));
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      model->setColumnStatus(iColumn,
+			     static_cast<ClpSimplex::Status> (basis2.getStructStatus(iColumn)));
+    }
+  } else {
+    // move status
+    model->createStatus();
+    // For rows lower and upper are flipped
+    for (iRow=0;iRow<numberRows;iRow++) {
+      int stat = basis.getArtifStatus(iRow);
+      if (stat>1)
+	stat = 5 - stat; // so 2->3 and 3->2
+      model->setRowStatus(iRow, static_cast<ClpSimplex::Status> (stat));
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      model->setColumnStatus(iColumn,
+			     static_cast<ClpSimplex::Status> (basis.getStructStatus(iColumn)));
+    }
+  }
+}
+// Warm start difference from basis_ to statusArray
+CoinWarmStartDiff * 
+OsiClpSolverInterface::getBasisDiff(const unsigned char * statusArray) const
+{
+  int iRow,iColumn;
+  int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  CoinWarmStartBasis basis;
+  basis.setSize(numberColumns,numberRows);
+  assert (modelPtr_->statusExists());
+  int lookupS[]={0,1,2,3,0,3};
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    int iStatus = statusArray[iColumn]&7;
+    iStatus = lookupS[iStatus];
+    basis.setStructStatus(iColumn,static_cast<CoinWarmStartBasis::Status> (iStatus));
+  }
+  statusArray += numberColumns;
+  // Flip slacks
+  int lookupA[]={0,1,3,2,0,2};
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int iStatus = statusArray[iRow]&7;
+    iStatus = lookupA[iStatus];
+    basis.setArtifStatus(iRow,static_cast<CoinWarmStartBasis::Status> (iStatus));
+  }
+  // Now basis is what we want while basis_ is old
+  CoinWarmStartDiff * difference = basis.generateDiff(&basis_);
+  return difference;
+}
+/*
+  Read an mps file from the given filename - returns number of errors
+  (see CoinMpsIO class)
+*/
+int 
+OsiClpSolverInterface::readMps(const char *filename,
+			       const char *extension ) 
+{
+  // Get rid of integer stuff
+  delete [] integerInformation_;
+  integerInformation_=NULL;
+  freeCachedResults();
+  
+  CoinMpsIO m;
+  m.setInfinity(getInfinity());
+  m.passInMessageHandler(modelPtr_->messageHandler());
+  *m.messagesPointer()=modelPtr_->coinMessages();
+
+  delete [] setInfo_;
+  setInfo_=NULL;
+  numberSOS_=0;
+  CoinSet ** sets=NULL;
+  // Temporarily reduce log level to get CoinMpsIO to shut up.
+  int saveLogLevel = modelPtr_->messageHandler()->logLevel() ;
+  modelPtr_->messageHandler()->setLogLevel(0) ;
+  int numberErrors = m.readMps(filename,extension,numberSOS_,sets);
+  modelPtr_->messageHandler()->setLogLevel(saveLogLevel) ;
+  if (numberSOS_) {
+    setInfo_ = new CoinSet[numberSOS_];
+    for (int i=0;i<numberSOS_;i++) {
+      setInfo_[i]=*sets[i];
+      delete sets[i];
+    }
+    delete [] sets;
+  }
+  handler_->message(COIN_SOLVER_MPS,messages_)
+    <<m.getProblemName()<< numberErrors <<CoinMessageEol;
+  if (!numberErrors) {
+
+    // set objective function offest
+    setDblParam(OsiObjOffset,m.objectiveOffset());
+
+    // set problem name
+    setStrParam(OsiProbName,m.getProblemName());
+    
+    // no errors
+    loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
+		m.getObjCoefficients(),m.getRowSense(),m.getRightHandSide(),
+		m.getRowRange());
+    const char * integer = m.integerColumns();
+    int nCols=m.getNumCols();
+    int nRows=m.getNumRows();
+    if (integer) {
+      int i,n=0;
+      int * index = new int [nCols];
+      for (i=0;i<nCols;i++) {
+	if (integer[i]) {
+	  index[n++]=i;
+        }
+      }
+      setInteger(index,n);
+      delete [] index;
+      if (n) 
+        modelPtr_->copyInIntegerInformation(integer);
+    }
+
+    // set objective name
+    setObjName(m.getObjectiveName());
+
+    // Always keep names
+    int nameDiscipline;
+    getIntParam(OsiNameDiscipline,nameDiscipline) ;
+    int iRow;
+    std::vector<std::string> rowNames = std::vector<std::string> ();
+    std::vector<std::string> columnNames = std::vector<std::string> ();
+    rowNames.reserve(nRows);
+    for (iRow=0;iRow<nRows;iRow++) {
+      const char * name = m.rowName(iRow);
+      rowNames.push_back(name);
+      if (nameDiscipline) 
+	OsiSolverInterface::setRowName(iRow,name) ;
+    }
+    
+    int iColumn;
+    columnNames.reserve(nCols);
+    for (iColumn=0;iColumn<nCols;iColumn++) {
+      const char * name = m.columnName(iColumn);
+      columnNames.push_back(name);
+      if (nameDiscipline) 
+	OsiSolverInterface::setColName(iColumn,name) ;
+    }
+    modelPtr_->copyNames(rowNames,columnNames);
+  }
+  return numberErrors;
+}
+int 
+OsiClpSolverInterface::readMps(const char *filename, const char*extension,
+			    int & numberSets, CoinSet ** & sets)
+{
+  int numberErrors = readMps(filename,extension);
+  numberSets= numberSOS_;
+  sets = &setInfo_;
+  return numberErrors;
+}
+/* Read an mps file from the given filename returns
+   number of errors (see OsiMpsReader class) */
+int 
+OsiClpSolverInterface::readMps(const char *filename,bool keepNames,bool allowErrors)
+{
+  // Get rid of integer stuff
+  delete [] integerInformation_;
+  integerInformation_=NULL;
+  freeCachedResults();
+  
+  CoinMpsIO m;
+  m.setInfinity(getInfinity());
+  m.passInMessageHandler(modelPtr_->messageHandler());
+  *m.messagesPointer()=modelPtr_->coinMessages();
+  m.setSmallElementValue(CoinMax(modelPtr_->getSmallElementValue(), 
+				 m.getSmallElementValue()));
+
+  delete [] setInfo_;
+  setInfo_=NULL;
+  numberSOS_=0;
+  CoinSet ** sets=NULL;
+  int numberErrors = m.readMps(filename,"",numberSOS_,sets);
+  if (numberSOS_) {
+    setInfo_ = new CoinSet[numberSOS_];
+    for (int i=0;i<numberSOS_;i++) {
+      setInfo_[i]=*sets[i];
+      delete sets[i];
+    }
+    delete [] sets;
+  }
+  handler_->message(COIN_SOLVER_MPS,messages_)
+    <<m.getProblemName()<< numberErrors <<CoinMessageEol;
+  if (!numberErrors||((numberErrors>0&&numberErrors<100000)&&allowErrors)) {
+
+    // set objective function offest
+    setDblParam(OsiObjOffset,m.objectiveOffset());
+
+    // set problem name
+    setStrParam(OsiProbName,m.getProblemName());
+
+    // set objective name
+    setObjName(m.getObjectiveName());
+
+    // no errors
+    loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
+		m.getObjCoefficients(),m.getRowSense(),m.getRightHandSide(),
+		m.getRowRange());
+    int nCols=m.getNumCols();
+    // get quadratic part
+    if (m.reader()->whichSection (  ) == COIN_QUAD_SECTION ) {
+      int * start=NULL;
+      int * column = NULL;
+      double * element = NULL;
+      int status=m.readQuadraticMps(NULL,start,column,element,2);
+      if (!status) 
+	modelPtr_->loadQuadraticObjective(nCols,start,column,element);
+      delete [] start;
+      delete [] column;
+      delete [] element;
+    }
+    const char * integer = m.integerColumns();
+    int nRows=m.getNumRows();
+    if (integer) {
+      int i,n=0;
+      int * index = new int [nCols];
+      for (i=0;i<nCols;i++) {
+	if (integer[i]) {
+	  index[n++]=i;
+        }
+      }
+      setInteger(index,n);
+      delete [] index;
+      if (n) 
+        modelPtr_->copyInIntegerInformation(integer);
+    }
+    if (keepNames) {
+      // keep names
+      int nameDiscipline;
+      getIntParam(OsiNameDiscipline,nameDiscipline) ;
+      int iRow;
+      std::vector<std::string> rowNames = std::vector<std::string> ();
+      std::vector<std::string> columnNames = std::vector<std::string> ();
+      rowNames.reserve(nRows);
+      for (iRow=0;iRow<nRows;iRow++) {
+	const char * name = m.rowName(iRow);
+	rowNames.push_back(name);
+	if (nameDiscipline) 
+	  OsiSolverInterface::setRowName(iRow,name) ;
+      }
+      
+      int iColumn;
+      columnNames.reserve(nCols);
+      for (iColumn=0;iColumn<nCols;iColumn++) {
+	const char * name = m.columnName(iColumn);
+	columnNames.push_back(name);
+	if (nameDiscipline) 
+	  OsiSolverInterface::setColName(iColumn,name) ;
+      }
+      modelPtr_->copyNames(rowNames,columnNames);
+    }
+  }
+  return numberErrors;
+}
+// Read file in LP format (with names)
+int 
+OsiClpSolverInterface::readLp(const char *filename, const double epsilon )
+{
+  CoinLpIO m;
+  m.passInMessageHandler(modelPtr_->messageHandler());
+  *m.messagesPointer()=modelPtr_->coinMessages();
+  m.readLp(filename, epsilon);
+  freeCachedResults();
+
+  // set objective function offest
+  setDblParam(OsiObjOffset, 0);
+
+  // set problem name
+  setStrParam(OsiProbName, m.getProblemName());
+
+  // set objective name
+  setObjName(m.getObjName());
+
+  // no errors
+  loadProblem(*m.getMatrixByRow(), m.getColLower(), m.getColUpper(),
+	      m.getObjCoefficients(), m.getRowLower(), m.getRowUpper());
+
+  const char *integer = m.integerColumns();
+  int nCols = m.getNumCols();
+  int nRows = m.getNumRows();
+  if (integer) {
+    int i, n = 0;
+    int *index = new int [nCols];
+    for (i=0; i<nCols; i++) {
+      if (integer[i]) {
+	index[n++] = i;
+      }
+    }
+    setInteger(index,n);
+    delete [] index;
+  }
+  // Always keep names
+  int nameDiscipline;
+  getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  int iRow;
+  std::vector<std::string> rowNames = std::vector<std::string> ();
+  std::vector<std::string> columnNames = std::vector<std::string> ();
+  rowNames.reserve(nRows);
+  for (iRow=0;iRow<nRows;iRow++) {
+    const char * name = m.rowName(iRow);
+    rowNames.push_back(name);
+    if (nameDiscipline) 
+      OsiSolverInterface::setRowName(iRow,name) ;
+  }
+  
+  int iColumn;
+  columnNames.reserve(nCols);
+  for (iColumn=0;iColumn<nCols;iColumn++) {
+    const char * name = m.columnName(iColumn);
+    columnNames.push_back(name);
+    if (nameDiscipline) 
+      OsiSolverInterface::setColName(iColumn,name) ;
+  }
+  modelPtr_->copyNames(rowNames,columnNames);
+  return(0);
+}
+/* Write the problem into an Lp file of the given filename.
+   If objSense is non zero then -1.0 forces the code to write a
+   maximization objective and +1.0 to write a minimization one.
+   If 0.0 then solver can do what it wants.
+   This version calls writeLpNative with names */
+void 
+OsiClpSolverInterface::writeLp(const char *filename,
+                               const char *extension ,
+                               double epsilon ,
+                               int numberAcross ,
+                               int decimals ,
+                               double objSense ,
+                               bool changeNameOnRange) const
+{
+  std::string f(filename);
+  std::string e(extension);
+  std::string fullname;
+  if (e!="") {
+    fullname = f + "." + e;
+  } else {
+    // no extension so no trailing period
+    fullname = f;
+  }
+  // get names
+  const char * const * const rowNames = modelPtr_->rowNamesAsChar();
+  const char * const * const columnNames = modelPtr_->columnNamesAsChar();
+  // Fall back on Osi version - possibly with names
+  OsiSolverInterface::writeLpNative(fullname.c_str(), 
+				    rowNames,columnNames, epsilon, numberAcross,
+				    decimals, objSense,changeNameOnRange);
+  if (rowNames) {
+    modelPtr_->deleteNamesAsChar(rowNames, modelPtr_->numberRows_+1);
+    modelPtr_->deleteNamesAsChar(columnNames, modelPtr_->numberColumns_);
+  }
+}
+void 
+OsiClpSolverInterface::writeLp(FILE * fp,
+                               double epsilon ,
+                               int numberAcross ,
+                               int decimals ,
+                               double objSense ,
+                               bool changeNameOnRange) const
+{
+  // get names
+  const char * const * const rowNames = modelPtr_->rowNamesAsChar();
+  const char * const * const columnNames = modelPtr_->columnNamesAsChar();
+  // Fall back on Osi version - possibly with names
+  OsiSolverInterface::writeLpNative(fp,
+				    rowNames,columnNames, epsilon, numberAcross,
+				    decimals, objSense,changeNameOnRange);
+  if (rowNames) {
+    modelPtr_->deleteNamesAsChar(rowNames, modelPtr_->numberRows_+1);
+    modelPtr_->deleteNamesAsChar(columnNames, modelPtr_->numberColumns_);
+  }
+}
+/*
+  I (JJF) am getting incredibly annoyed because I can't just replace a matrix.
+  The default behavior of this is do nothing so only use where that would not matter
+  e.g. strengthening a matrix for MIP
+*/
+void 
+OsiClpSolverInterface::replaceMatrixOptional(const CoinPackedMatrix & matrix)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(2|4|8));
+  replaceMatrix(matrix);
+}
+// And if it does matter (not used at present)
+void 
+OsiClpSolverInterface::replaceMatrix(const CoinPackedMatrix & matrix)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(2|4|8));
+  delete modelPtr_->matrix_;
+  delete modelPtr_->rowCopy_;
+  modelPtr_->rowCopy_=NULL;
+  if (matrix.isColOrdered()) {
+    modelPtr_->matrix_=new ClpPackedMatrix(matrix);
+  } else {
+    CoinPackedMatrix matrix2;
+    matrix2.setExtraGap(0.0);
+    matrix2.setExtraMajor(0.0);
+    matrix2.reverseOrderedCopyOf(matrix);
+    modelPtr_->matrix_=new ClpPackedMatrix(matrix2);
+  }    
+  modelPtr_->matrix_->setDimensions(modelPtr_->numberRows_,modelPtr_->numberColumns_);
+  freeCachedResults();
+}
+// Get pointer to array[getNumCols()] of primal solution vector
+const double * 
+OsiClpSolverInterface::getColSolution() const 
+{ 
+  if (modelPtr_->solveType()!=2) {
+    return modelPtr_->primalColumnSolution();
+  } else {
+    // simplex interface
+    return modelPtr_->solutionRegion(1);
+  }
+}
+  
+// Get pointer to array[getNumRows()] of dual prices
+const double * 
+OsiClpSolverInterface::getRowPrice() const
+{ 
+  if (modelPtr_->solveType()!=2) {
+    return modelPtr_->dualRowSolution();
+  } else {
+    // simplex interface
+    //return modelPtr_->djRegion(0);
+    return modelPtr_->dualRowSolution();
+  }
+}
+  
+// Get a pointer to array[getNumCols()] of reduced costs
+const double * 
+OsiClpSolverInterface::getReducedCost() const 
+{ 
+  if (modelPtr_->solveType()!=2) {
+    return modelPtr_->dualColumnSolution();
+  } else {
+    // simplex interface
+    return modelPtr_->djRegion(1);
+  }
+}
+
+/* Get pointer to array[getNumRows()] of row activity levels (constraint
+   matrix times the solution vector */
+const double * 
+OsiClpSolverInterface::getRowActivity() const 
+{ 
+  if (modelPtr_->solveType()!=2) {
+    return modelPtr_->primalRowSolution();
+  } else {
+    // simplex interface
+    return modelPtr_->solutionRegion(0);
+  }
+}
+double 
+OsiClpSolverInterface::getObjValue() const 
+{
+  if (modelPtr_->numberIterations()||modelPtr_->upperIn_!=-COIN_DBL_MAX) {
+    // This does not pass unitTest when getObjValue is called before solve.
+    //printf("obj a %g %g\n",modelPtr_->objectiveValue(),
+    //     OsiSolverInterface::getObjValue());
+    if (fakeMinInSimplex_)
+      return -modelPtr_->objectiveValue() ;
+    else
+      return modelPtr_->objectiveValue();
+  } else {
+    return OsiSolverInterface::getObjValue();
+  }
+}
+
+/* Set an objective function coefficient */
+void 
+OsiClpSolverInterface::setObjCoeff( int elementIndex, double elementValue )
+{
+  modelPtr_->whatsChanged_ &= 0xffff;
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (elementIndex<0||elementIndex>=n) {
+    indexError(elementIndex,"setObjCoeff");
+  }
+#endif
+  modelPtr_->setObjectiveCoefficient(elementIndex,
+    ((fakeMinInSimplex_)?-elementValue:elementValue));
+}
+
+/* Set a single column lower bound<br>
+   Use -DBL_MAX for -infinity. */
+void 
+OsiClpSolverInterface::setColLower( int index, double elementValue )
+{
+  modelPtr_->whatsChanged_ &= 0x1ffff;
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (index<0||index>=n) {
+    indexError(index,"setColLower");
+  }
+#endif
+  double currentValue = modelPtr_->columnActivity_[index];
+  bool changed=(currentValue<elementValue-modelPtr_->primalTolerance()||
+                index>=basis_.getNumStructural()||
+                basis_.getStructStatus(index)==CoinWarmStartBasis::atLowerBound);
+  // Say can't gurantee optimal basis etc
+  if (changed)
+    lastAlgorithm_=999;
+  if (!modelPtr_->lower_)
+    modelPtr_->whatsChanged_ &= ~0xffff; // switch off
+  modelPtr_->setColumnLower(index,elementValue);
+}
+      
+/* Set a single column upper bound<br>
+   Use DBL_MAX for infinity. */
+void 
+OsiClpSolverInterface::setColUpper( int index, double elementValue )
+{
+  modelPtr_->whatsChanged_ &= 0x1ffff;
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (index<0||index>=n) {
+    indexError(index,"setColUpper");
+  }
+#endif
+  double currentValue = modelPtr_->columnActivity_[index];
+  bool changed=(currentValue>elementValue+modelPtr_->primalTolerance()||
+                index>=basis_.getNumStructural()||
+                basis_.getStructStatus(index)==CoinWarmStartBasis::atUpperBound);
+  // Say can't gurantee optimal basis etc
+  if (changed)
+    lastAlgorithm_=999;
+  if (!modelPtr_->upper_)
+    modelPtr_->whatsChanged_ &= ~0xffff; // switch off
+  modelPtr_->setColumnUpper(index,elementValue);
+}
+
+/* Set a single column lower and upper bound */
+void 
+OsiClpSolverInterface::setColBounds( int elementIndex,
+				     double lower, double upper )
+{
+  modelPtr_->whatsChanged_ &= 0x1ffff;
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  if (elementIndex<0||elementIndex>=n) {
+    indexError(elementIndex,"setColBounds");
+  }
+#endif
+  if (!modelPtr_->lower_)
+    modelPtr_->whatsChanged_ &= ~0xffff; // switch off
+  modelPtr_->setColumnBounds(elementIndex,lower,upper);
+}
+void OsiClpSolverInterface::setColSetBounds(const int* indexFirst,
+					    const int* indexLast,
+					    const double* boundList)
+{
+  modelPtr_->whatsChanged_ &= 0x1ffff;
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns();
+  const int * indexFirst2=indexFirst;
+  while (indexFirst2 != indexLast) {
+    const int iColumn=*indexFirst2++;
+    if (iColumn<0||iColumn>=n) {
+      indexError(iColumn,"setColSetBounds");
+    }
+  }
+#endif
+  modelPtr_->setColSetBounds(indexFirst,indexLast,boundList);
+}
+//------------------------------------------------------------------
+/* Set a single row lower bound<br>
+   Use -DBL_MAX for -infinity. */
+void 
+OsiClpSolverInterface::setRowLower( int elementIndex, double elementValue ) {
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  modelPtr_->whatsChanged_ &= 0xffff;
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+  if (elementIndex<0||elementIndex>=n) {
+    indexError(elementIndex,"setRowLower");
+  }
+#endif
+  modelPtr_->setRowLower(elementIndex , elementValue);
+  if (rowsense_!=NULL) {
+    assert ((rhs_ != NULL) && (rowrange_ != NULL));
+    convertBoundToSense(modelPtr_->rowLower_[elementIndex], 
+			modelPtr_->rowUpper_[elementIndex],
+			rowsense_[elementIndex], rhs_[elementIndex], rowrange_[elementIndex]);
+  }
+}
+      
+/* Set a single row upper bound<br>
+   Use DBL_MAX for infinity. */
+void 
+OsiClpSolverInterface::setRowUpper( int elementIndex, double elementValue ) {
+  modelPtr_->whatsChanged_ &= 0xffff;
+  // Say can't guarantee optimal basis etc
+  lastAlgorithm_=999;
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+  if (elementIndex<0||elementIndex>=n) {
+    indexError(elementIndex,"setRowUpper");
+  }
+#endif
+  modelPtr_->setRowUpper(elementIndex , elementValue);
+  if (rowsense_!=NULL) {
+    assert ((rhs_ != NULL) && (rowrange_ != NULL));
+    convertBoundToSense(modelPtr_->rowLower_[elementIndex], 
+			modelPtr_->rowUpper_[elementIndex],
+			rowsense_[elementIndex], rhs_[elementIndex], rowrange_[elementIndex]);
+  }
+}
+    
+/* Set a single row lower and upper bound */
+void 
+OsiClpSolverInterface::setRowBounds( int elementIndex,
+	      double lower, double upper ) {
+  modelPtr_->whatsChanged_ &= 0xffff;
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+  if (elementIndex<0||elementIndex>=n) {
+    indexError(elementIndex,"setRowBounds");
+  }
+#endif
+  modelPtr_->setRowBounds(elementIndex,lower,upper);
+  if (rowsense_!=NULL) {
+    assert ((rhs_ != NULL) && (rowrange_ != NULL));
+    convertBoundToSense(modelPtr_->rowLower_[elementIndex], 
+			modelPtr_->rowUpper_[elementIndex],
+			rowsense_[elementIndex], rhs_[elementIndex], rowrange_[elementIndex]);
+  }
+}
+//-----------------------------------------------------------------------------
+void
+OsiClpSolverInterface::setRowType(int i, char sense, double rightHandSide,
+				  double range)
+{
+  modelPtr_->whatsChanged_ &= 0xffff;
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+  if (i<0||i>=n) {
+    indexError(i,"setRowType");
+  }
+#endif
+  double lower = 0, upper = 0;
+  convertSenseToBound(sense, rightHandSide, range, lower, upper);
+  setRowBounds(i, lower, upper);
+  // If user is using sense then set
+  if (rowsense_) {
+    rowsense_[i] = sense;
+    rhs_[i] = rightHandSide;
+    rowrange_[i] = range;
+  }
+}
+// Set name of row
+void 
+//OsiClpSolverInterface::setRowName(int rowIndex, std::string & name) 
+OsiClpSolverInterface::setRowName(int rowIndex, std::string name) 
+{
+  if (rowIndex>=0&&rowIndex<modelPtr_->numberRows()) {
+    int nameDiscipline;
+    getIntParam(OsiNameDiscipline,nameDiscipline) ;
+    if (nameDiscipline) {
+      modelPtr_->setRowName(rowIndex,name);
+      OsiSolverInterface::setRowName(rowIndex,name) ;
+    }
+  }
+}
+// Return name of row if one exists or Rnnnnnnn
+// we ignore maxLen
+std::string 
+OsiClpSolverInterface::getRowName(int rowIndex, unsigned int /*maxLen*/) const
+{ 
+  if (rowIndex == getNumRows())
+    return getObjName();
+  int useNames;
+  getIntParam (OsiNameDiscipline,useNames);
+  if (useNames)
+    return modelPtr_->getRowName(rowIndex);
+  else
+    return dfltRowColName('r',rowIndex);
+}
+    
+// Set name of col
+void 
+//OsiClpSolverInterface::setColName(int colIndex, std::string & name) 
+OsiClpSolverInterface::setColName(int colIndex, std::string name) 
+{
+  if (colIndex>=0&&colIndex<modelPtr_->numberColumns()) {
+    int nameDiscipline;
+    getIntParam(OsiNameDiscipline,nameDiscipline) ;
+    if (nameDiscipline) {
+      modelPtr_->setColumnName(colIndex,name);
+      OsiSolverInterface::setColName(colIndex,name) ;
+    }
+  }
+}
+// Return name of col if one exists or Rnnnnnnn
+std::string 
+OsiClpSolverInterface::getColName(int colIndex, unsigned int /*maxLen*/) const
+{
+  int useNames;
+  getIntParam (OsiNameDiscipline,useNames);
+  if (useNames)
+    return modelPtr_->getColumnName(colIndex);
+  else
+    return dfltRowColName('c',colIndex);
+}
+    
+    
+//-----------------------------------------------------------------------------
+void OsiClpSolverInterface::setRowSetBounds(const int* indexFirst,
+					    const int* indexLast,
+					    const double* boundList)
+{
+  modelPtr_->whatsChanged_ &= 0xffff;
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+  const int * indexFirst2=indexFirst;
+  while (indexFirst2 != indexLast) {
+    const int iColumn=*indexFirst2++;
+    if (iColumn<0||iColumn>=n) {
+      indexError(iColumn,"setColumnSetBounds");
+    }
+  }
+#endif
+  modelPtr_->setRowSetBounds(indexFirst,indexLast,boundList);
+  if (rowsense_ != NULL) {
+    assert ((rhs_ != NULL) && (rowrange_ != NULL));
+    double * lower = modelPtr_->rowLower();
+    double * upper = modelPtr_->rowUpper();
+    while (indexFirst != indexLast) {
+      const int iRow=*indexFirst++;
+      convertBoundToSense(lower[iRow], upper[iRow],
+			  rowsense_[iRow], rhs_[iRow], rowrange_[iRow]);
+    }
+  }
+}
+//-----------------------------------------------------------------------------
+void
+OsiClpSolverInterface::setRowSetTypes(const int* indexFirst,
+				      const int* indexLast,
+				      const char* senseList,
+				      const double* rhsList,
+				      const double* rangeList)
+{
+  modelPtr_->whatsChanged_ &= 0xffff;
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+#endif
+  const int len = static_cast<int>(indexLast - indexFirst);
+  while (indexFirst != indexLast) {
+    const int iRow= *indexFirst++;
+#ifndef NDEBUG
+    if (iRow<0||iRow>=n) {
+      indexError(iRow,"isContinuous");
+    }
+#endif
+    double lowerValue = 0;
+    double upperValue = 0;
+    if (rangeList){
+      convertSenseToBound(*senseList++, *rhsList++, *rangeList++,
+			  lowerValue, upperValue);
+    } else {
+      convertSenseToBound(*senseList++, *rhsList++, 0,
+			  lowerValue, upperValue);
+    }
+    modelPtr_->setRowBounds(iRow,lowerValue,upperValue);
+  }
+  if (rowsense_ != NULL) {
+    assert ((rhs_ != NULL) && (rowrange_ != NULL));
+    indexFirst -= len;
+    senseList -= len;
+    rhsList -= len;
+    if (rangeList)
+       rangeList -= len;
+    while (indexFirst != indexLast) {
+      const int iRow=*indexFirst++;
+      rowsense_[iRow] = *senseList++;
+      rhs_[iRow] = *rhsList++;
+      if (rangeList)
+	 rowrange_[iRow] = *rangeList++;
+    }
+  }
+}
+
+/*
+  Clp's copy-in/copy-out design paradigm is a challenge for the simplex modes.
+  Normal operation goes like this:
+    * startup() loads clp's work arrays, performing scaling for numerical
+      stability and compensating for max.
+    * clp solves the problem
+    * finish() unloads the work arrays into answer arrays, undoing scaling
+      and max compensation.
+  There are two solutions: undo scaling and max on demand, or make them
+  into noops. The various getBInv* methods undo scaling on demand (but
+  see special option 512) and do not need to worry about max. Other get
+  solution methods are not coded to do this, so the second approach is
+  used. For simplex modes, turn off scaling (necessary for both primal and
+  dual solutions) and temporarily convert max to min (necessary for dual
+  solution). This makes the unscaling in getBInv* superfluous, but don't
+  remove it. Arguably the better solution here would be to go through and
+  add unscaling and max compensation to the get solution methods. Look for
+  fakeMinInSimplex to see the places this propagates to.
+
+  TODO: setRowPrice never has worked properly, and I didn't try to fix it in
+        this go-round.
+
+  As of 100907, change applied to [enable|disable]Factorization (mode 1).
+  Limitation of [enable|disable]SimplexInterface (mode 2) noted in
+  documentation.  -- lh, 100907 --
+*/
+/*
+  Enables normal operation of subsequent functions.  This method is supposed
+  to ensure that all typical things (like reduced costs, etc.) are updated
+  when individual pivots are executed and can be queried by other methods
+*/
+void 
+OsiClpSolverInterface::enableSimplexInterface(bool doingPrimal)
+{
+  modelPtr_->whatsChanged_ &= 0xffff;
+  if (modelPtr_->solveType()==2)
+    return;
+  assert (modelPtr_->solveType()==1);
+  int saveIts = modelPtr_->numberIterations_;
+  modelPtr_->setSolveType(2);
+  if (doingPrimal)
+    modelPtr_->setAlgorithm(1);
+  else
+    modelPtr_->setAlgorithm(-1);
+  // Do initialization
+  saveData_ = modelPtr_->saveData();
+  saveData_.scalingFlag_=modelPtr_->scalingFlag();
+  modelPtr_->scaling(0);
+  specialOptions_ = 0x80000000;
+  // set infeasibility cost up
+  modelPtr_->setInfeasibilityCost(1.0e12);
+  ClpDualRowDantzig dantzig;
+  modelPtr_->setDualRowPivotAlgorithm(dantzig);
+  ClpPrimalColumnDantzig dantzigP;
+  dantzigP.saveWeights(modelPtr_,0); // set modelPtr 
+  modelPtr_->setPrimalColumnPivotAlgorithm(dantzigP);
+  int saveOptions = modelPtr_->specialOptions_;
+  modelPtr_->specialOptions_ &= ~262144;
+  delete modelPtr_->scaledMatrix_;
+  modelPtr_->scaledMatrix_=NULL;
+  // make sure using standard factorization
+  modelPtr_->factorization()->forceOtherFactorization(4);
+#ifdef NDEBUG
+  modelPtr_->startup(0);
+#else
+  int returnCode=modelPtr_->startup(0);
+  assert (!returnCode||returnCode==2);
+#endif
+  modelPtr_->specialOptions_=saveOptions;
+  modelPtr_->numberIterations_=saveIts;
+}
+
+//Undo whatever setting changes the above method had to make
+void 
+OsiClpSolverInterface::disableSimplexInterface()
+{
+  modelPtr_->whatsChanged_ &= 0xffff;
+  assert (modelPtr_->solveType()==2);
+  // declare optimality anyway  (for message handler)
+  modelPtr_->setProblemStatus(0);
+  modelPtr_->setSolveType(1);
+  // message will not appear anyway
+  int saveMessageLevel=modelPtr_->messageHandler()->logLevel();
+  modelPtr_->messageHandler()->setLogLevel(0);
+  modelPtr_->finish();
+  modelPtr_->messageHandler()->setLogLevel(saveMessageLevel);
+  modelPtr_->restoreData(saveData_);
+  modelPtr_->scaling(saveData_.scalingFlag_);
+  ClpDualRowSteepest steepest;
+  modelPtr_->setDualRowPivotAlgorithm(steepest);
+  ClpPrimalColumnSteepest steepestP;
+  modelPtr_->setPrimalColumnPivotAlgorithm(steepestP);
+  basis_ = getBasis(modelPtr_);
+  modelPtr_->setSolveType(1);
+}
+
+/*
+  Force scaling off. If the client thinks we're maximising, arrange it so
+  that clp sees minimisation while the client still sees maximisation. In
+  keeping with the spirit of the getBInv methods, special option 512 will
+  leave all work to the client.
+*/
+void 
+OsiClpSolverInterface::enableFactorization() const
+{
+  saveData_.specialOptions_=specialOptions_;
+  // Try to preserve work regions, reuse factorization
+  if ((specialOptions_&(1+8))!=1+8)
+    setSpecialOptionsMutable((1+8)|specialOptions_);
+  // Are we allowed to make the output sensible to mere mortals?
+  if ((specialOptions_&512)==0) {
+    // Force scaling to off
+    saveData_.scalingFlag_ = modelPtr_->scalingFlag() ;
+    modelPtr_->scaling(0) ;
+    // Temporarily force to min but keep a copy of original objective.
+    if (getObjSense() < 0.0) {
+      fakeMinInSimplex_ = true ;
+      modelPtr_->setOptimizationDirection(1.0) ;
+      double *c = modelPtr_->objective() ;
+      int n = getNumCols() ;
+      linearObjective_ = new double[n] ;
+      CoinMemcpyN(c,n,linearObjective_) ;
+      std::transform(c,c+n,c,std::negate<double>()) ;
+    }
+  }
+  int saveStatus = modelPtr_->problemStatus_;
+#ifdef NDEBUG
+  modelPtr_->startup(0);
+#else
+  int returnCode=modelPtr_->startup(0);
+  assert (!returnCode||returnCode==2);
+#endif
+  modelPtr_->problemStatus_=saveStatus;
+}
+
+/*
+  Undo enableFactorization. Retrieve the special options and scaling and
+  remove the temporary objective used to fake minimisation in clp.
+*/
+void 
+OsiClpSolverInterface::disableFactorization() const
+{
+  specialOptions_=saveData_.specialOptions_;
+  // declare optimality anyway  (for message handler)
+  modelPtr_->setProblemStatus(0);
+  // message will not appear anyway
+  int saveMessageLevel=modelPtr_->messageHandler()->logLevel();
+  modelPtr_->messageHandler()->setLogLevel(0);
+  modelPtr_->finish();
+  modelPtr_->messageHandler()->setLogLevel(saveMessageLevel);
+  // Client asked for transforms on the way in, so back out.
+  if ((specialOptions_&512)==0) {
+    modelPtr_->scaling(saveData_.scalingFlag_) ;
+    if (fakeMinInSimplex_ == true) {
+      fakeMinInSimplex_ = false ;
+      modelPtr_->setOptimizationDirection(-1.0) ;
+      double *c = modelPtr_->objective() ;
+      int n = getNumCols() ;
+      std::transform(c,c+n,c,std::negate<double>()) ;
+      delete[] linearObjective_ ;
+    }
+  }
+}
+
+
+
+/* The following two methods may be replaced by the
+   methods of OsiSolverInterface using OsiWarmStartBasis if:
+   1. OsiWarmStartBasis resize operation is implemented
+   more efficiently and
+   2. It is ensured that effects on the solver are the same
+   
+   Returns a basis status of the structural/artificial variables 
+*/
+void 
+OsiClpSolverInterface::getBasisStatus(int* cstat, int* rstat) const
+{
+  int iRow,iColumn;
+  int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  const double * pi = modelPtr_->dualRowSolution();
+  const double * dj = modelPtr_->dualColumnSolution();
+  double multiplier = modelPtr_->optimizationDirection();
+  // Flip slacks
+  int lookupA[]={0,1,3,2,0,3};
+  for (iRow=0;iRow<numberRows;iRow++) {
+    int iStatus = modelPtr_->getRowStatus(iRow);
+    if (iStatus==5) {
+      // Fixed - look at reduced cost
+      if (pi[iRow]*multiplier>1.0e-7)
+        iStatus = 3;
+    }
+    iStatus = lookupA[iStatus];
+    rstat[iRow]=iStatus;
+  }
+  int lookupS[]={0,1,2,3,0,3};
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    int iStatus = modelPtr_->getColumnStatus(iColumn);
+    if (iStatus==5) {
+      // Fixed - look at reduced cost
+      if (dj[iColumn]*multiplier<-1.0e-7)
+        iStatus = 2;
+    }
+    iStatus = lookupS[iStatus];
+    cstat[iColumn]=iStatus;
+  }
+}
+
+//Set the status of structural/artificial variables 
+//Returns 0 if OK, 1 if problem is bad e.g. duplicate elements, too large ...
+int 
+OsiClpSolverInterface::setBasisStatus(const int* cstat, const int* rstat)
+{
+  modelPtr_->whatsChanged_ &= 0xffff;
+  // Say can't gurantee optimal basis etc
+  lastAlgorithm_=999;
+  modelPtr_->createStatus();
+  int i, n;
+  double * lower, * upper, * solution;
+  n=modelPtr_->numberRows();
+  lower = modelPtr_->rowLower();
+  upper = modelPtr_->rowUpper();
+  solution = modelPtr_->primalRowSolution();
+  // For rows lower and upper are flipped
+  int lookupA[]={0,1,3,2};
+  for (i=0;i<n;i++) {
+    int status = lookupA[rstat[i]];
+    if (status<0||status>3)
+      status = 3;
+    if (lower[i]<-1.0e50&&upper[i]>1.0e50&&status!=1)
+      status = 0; // set free if should be
+    else if (lower[i]<-1.0e50&&status==3)
+      status = 2; // can't be at lower bound
+    else if (upper[i]>1.0e50&&status==2)
+      status = 3; // can't be at upper bound
+    switch (status) {
+      // free or superbasic
+    case 0:
+      if (lower[i]<-1.0e50&&upper[i]>1.0e50) {
+	modelPtr_->setRowStatus(i,ClpSimplex::isFree);
+	if (fabs(solution[i])>1.0e20)
+	  solution[i]=0.0;
+      } else {
+	modelPtr_->setRowStatus(i,ClpSimplex::superBasic);
+	if (fabs(solution[i])>1.0e20)
+	  solution[i]=0.0;
+      }
+      break;
+    case 1:
+      // basic
+      modelPtr_->setRowStatus(i,ClpSimplex::basic);
+      break;
+    case 2:
+      // at upper bound
+      solution[i]=upper[i];
+      if (upper[i]>lower[i])
+	modelPtr_->setRowStatus(i,ClpSimplex::atUpperBound);
+      else
+	modelPtr_->setRowStatus(i,ClpSimplex::isFixed);
+      break;
+    case 3:
+      // at lower bound
+      solution[i]=lower[i];
+      if (upper[i]>lower[i])
+	modelPtr_->setRowStatus(i,ClpSimplex::atLowerBound);
+      else
+	modelPtr_->setRowStatus(i,ClpSimplex::isFixed);
+      break;
+    }
+  }
+  n=modelPtr_->numberColumns();
+  lower = modelPtr_->columnLower();
+  upper = modelPtr_->columnUpper();
+  solution = modelPtr_->primalColumnSolution();
+  for (i=0;i<n;i++) {
+    int status = cstat[i];
+    if (status<0||status>3)
+      status = 3;
+    if (lower[i]<-1.0e50&&upper[i]>1.0e50&&status!=1)
+      status = 0; // set free if should be
+    else if (lower[i]<-1.0e50&&status==3)
+      status = 2; // can't be at lower bound
+    else if (upper[i]>1.0e50&&status==2)
+      status = 3; // can't be at upper bound
+    switch (status) {
+      // free or superbasic
+    case 0:
+      if (lower[i]<-1.0e50&&upper[i]>1.0e50) {
+	modelPtr_->setColumnStatus(i,ClpSimplex::isFree);
+	if (fabs(solution[i])>1.0e20)
+	  solution[i]=0.0;
+      } else {
+	modelPtr_->setColumnStatus(i,ClpSimplex::superBasic);
+	if (fabs(solution[i])>1.0e20)
+	  solution[i]=0.0;
+      }
+      break;
+    case 1:
+      // basic
+      modelPtr_->setColumnStatus(i,ClpSimplex::basic);
+      break;
+    case 2:
+      // at upper bound
+      solution[i]=upper[i];
+      if (upper[i]>lower[i])
+	modelPtr_->setColumnStatus(i,ClpSimplex::atUpperBound);
+      else
+	modelPtr_->setColumnStatus(i,ClpSimplex::isFixed);
+      break;
+    case 3:
+      // at lower bound
+      solution[i]=lower[i];
+      if (upper[i]>lower[i])
+	modelPtr_->setColumnStatus(i,ClpSimplex::atLowerBound);
+      else
+	modelPtr_->setColumnStatus(i,ClpSimplex::isFixed);
+      break;
+    }
+  }
+  // say first time
+  modelPtr_->statusOfProblem(true);
+  // May be bad model
+  if (modelPtr_->status()==4)
+    return 1;
+  // Save 
+  basis_ = getBasis(modelPtr_);
+  return 0;
+}
+
+/* Perform a pivot by substituting a colIn for colOut in the basis. 
+   The status of the leaving variable is given in statOut. Where
+   1 is to upper bound, -1 to lower bound
+   Return code is 0 for okay,
+   1 if inaccuracy forced re-factorization (should be okay) and
+   -1 for singular factorization
+*/
+int 
+OsiClpSolverInterface::pivot(int colIn, int colOut, int outStatus)
+{
+  assert (modelPtr_->solveType()==2);
+  // convert to Clp style (what about flips?)
+  if (colIn<0) 
+    colIn = modelPtr_->numberColumns()+(-1-colIn);
+  if (colOut<0) 
+    colOut = modelPtr_->numberColumns()+(-1-colOut);
+  // in clp direction of out is reversed
+  outStatus = - outStatus;
+  // set in clp
+  modelPtr_->setDirectionOut(outStatus);
+  modelPtr_->setSequenceIn(colIn);
+  modelPtr_->setSequenceOut(colOut);
+  // do pivot
+  return modelPtr_->pivot();
+}
+
+/* Obtain a result of the primal pivot 
+   Outputs: colOut -- leaving column, outStatus -- its status,
+   t -- step size, and, if dx!=NULL, *dx -- primal ray direction.
+   Inputs: colIn -- entering column, sign -- direction of its change (+/-1).
+   Both for colIn and colOut, artificial variables are index by
+   the negative of the row index minus 1.
+   Return code (for now): 0 -- leaving variable found, 
+   -1 -- everything else?
+   Clearly, more informative set of return values is required 
+   Primal and dual solutions are updated
+*/
+int 
+OsiClpSolverInterface::primalPivotResult(int colIn, int sign, 
+					 int& colOut, int& outStatus, 
+					 double& t, CoinPackedVector* dx)
+{
+  assert (modelPtr_->solveType()==2);
+  // convert to Clp style
+  if (colIn<0) 
+    colIn = modelPtr_->numberColumns()+(-1-colIn);
+  // set in clp
+  modelPtr_->setDirectionIn(sign);
+  modelPtr_->setSequenceIn(colIn);
+  modelPtr_->setSequenceOut(-1);
+  int returnCode = modelPtr_->primalPivotResult();
+  t = modelPtr_->theta();
+  int numberColumns = modelPtr_->numberColumns();
+  if (dx) {
+    double * ray = modelPtr_->unboundedRay();
+    if  (ray)
+      dx->setFullNonZero(numberColumns,ray);
+    else
+      printf("No ray?\n");
+    delete [] ray;
+  }
+  outStatus = - modelPtr_->directionOut();
+  colOut = modelPtr_->sequenceOut();
+  if (colOut>= numberColumns) 
+    colOut = -1-(colOut - numberColumns);
+  return returnCode;
+}
+
+/* Obtain a result of the dual pivot (similar to the previous method)
+   Differences: entering variable and a sign of its change are now
+   the outputs, the leaving variable and its statuts -- the inputs
+   If dx!=NULL, then *dx contains dual ray
+   Return code: same
+*/
+int 
+OsiClpSolverInterface::dualPivotResult(int& /*colIn*/, int& /*sign*/, 
+				       int /*colOut*/, int /*outStatus*/, 
+				       double& /*t*/, CoinPackedVector* /*dx*/)
+{
+  assert (modelPtr_->solveType()==2);
+  abort();
+  return 0;
+}
+
+/*
+  This method should not leave a permanent change in the solver. For
+  this reason, save a copy of the cost region and replace it after we've
+  calculated the duals and reduced costs.
+
+  On the good side, if we're maximising, we should negate the objective on
+  the way in and negate the duals on the way out. Since clp won't be doing
+  anything more with c, we can exploit (-1)(-1) = 1 and do nothing.
+*/
+void 
+OsiClpSolverInterface::getReducedGradient(
+					  double* columnReducedCosts, 
+					  double * duals,
+					  const double * c) const
+{
+  //assert (modelPtr_->solveType()==2);
+  // could do this faster with coding inside Clp
+  // save current costs
+  int numberColumns = modelPtr_->numberColumns();
+  double * save = new double [numberColumns];
+  double * obj = modelPtr_->costRegion();
+  CoinMemcpyN(obj,numberColumns,save);
+  // Compute new duals and reduced costs.
+  const double * columnScale = modelPtr_->columnScale();
+  if (!columnScale) {
+    CoinMemcpyN(c,numberColumns,obj) ;
+  } else {
+    // need to scale
+    for (int i=0;i<numberColumns;i++)
+      obj[i] = c[i]*columnScale[i];
+  }
+  modelPtr_->computeDuals(NULL);
+
+  // Restore previous cost vector
+  CoinMemcpyN(save,numberColumns,obj);
+  delete [] save;
+
+  // Transfer results to parameters
+  int numberRows = modelPtr_->numberRows();
+  const double * dualScaled = modelPtr_->dualRowSolution();
+  const double * djScaled = modelPtr_->djRegion(1);
+  if (!columnScale) {
+      CoinMemcpyN(dualScaled,numberRows,duals) ;
+      CoinMemcpyN(djScaled,numberColumns,columnReducedCosts) ;
+  } else {
+    // need to scale
+    const double * rowScale = modelPtr_->rowScale();
+    for (int i=0;i<numberRows;i++)
+      duals[i] = dualScaled[i]*rowScale[i];
+    for (int i=0;i<numberColumns;i++)
+      columnReducedCosts[i] = djScaled[i]/columnScale[i];
+  }
+}
+
+#if 0
+
+  Deleted from OsiSimplex API 100828. Leave the code here for a bit just in
+  case someone yells.  -- lh, 100828 --
+
+/* Set a new objective and apply the old basis so that the
+   reduced costs are properly updated
+*/
+void OsiClpSolverInterface::setObjectiveAndRefresh(const double* c)
+{
+  modelPtr_->whatsChanged_ &= (0xffff&~(64));
+  assert (modelPtr_->solveType()==2);
+  int numberColumns = modelPtr_->numberColumns();
+  CoinMemcpyN(c,numberColumns,modelPtr_->objective());
+  if (modelPtr_->nonLinearCost()) {
+    modelPtr_->nonLinearCost()->refreshCosts(c);
+  }
+  CoinMemcpyN(c,numberColumns,modelPtr_->costRegion());
+  modelPtr_->computeDuals(NULL);
+}
+#endif
+
+//Get a row of the tableau (slack part in slack if not NULL)
+void 
+OsiClpSolverInterface::getBInvARow(int row, double* z, double * slack) const
+{
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+  if (row<0||row>=n) {
+    indexError(row,"getBInvARow");
+  }
+#endif
+  //assert (modelPtr_->solveType()==2||(specialOptions_&1));
+  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
+  CoinIndexedVector * rowArray1 = modelPtr_->rowArray(1);
+  CoinIndexedVector * columnArray0 = modelPtr_->columnArray(0);
+  CoinIndexedVector * columnArray1 = modelPtr_->columnArray(1);
+  rowArray0->clear();
+  rowArray1->clear();
+  columnArray0->clear();
+  columnArray1->clear();
+  int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  // put +1 in row 
+  // But swap if pivot variable was slack as clp stores slack as -1.0
+  const int * pivotVariable = modelPtr_->pivotVariable();
+  const double * rowScale = modelPtr_->rowScale();
+  const double * columnScale = modelPtr_->columnScale();
+  int pivot = pivotVariable[row];
+  double value;
+  // And if scaled then adjust
+  if (!rowScale) {
+    if (pivot<numberColumns)
+      value = 1.0;
+    else
+      value = -1.0;
+  } else {
+    if (pivot<numberColumns)
+      value = columnScale[pivot];
+    else
+      value = -1.0/rowScale[pivot-numberColumns];
+  }
+  rowArray1->insert(row,value);
+  modelPtr_->factorization()->updateColumnTranspose(rowArray0,rowArray1);
+  // put row of tableau in rowArray1 and columnArray0
+  modelPtr_->clpMatrix()->transposeTimes(modelPtr_,1.0,
+                                         rowArray1,columnArray1,columnArray0);
+  // If user is sophisticated then let her/him do work
+  if ((specialOptions_&512)==0) {
+    // otherwise copy and clear
+    if (!rowScale) {
+      CoinMemcpyN(columnArray0->denseVector(),numberColumns,z);
+    } else {
+      double * array = columnArray0->denseVector();
+      for (int i=0;i<numberColumns;i++)
+        z[i] = array[i]/columnScale[i];
+    }
+    if (slack) {
+      if (!rowScale) {
+        CoinMemcpyN(rowArray1->denseVector(),numberRows,slack);
+      } else {
+        double * array = rowArray1->denseVector();
+      for (int i=0;i<numberRows;i++)
+        slack[i] = array[i]*rowScale[i];
+      }
+    }
+    columnArray0->clear();
+    rowArray1->clear();
+  }
+  // don't need to clear everything always, but doesn't cost
+  rowArray0->clear();
+  columnArray1->clear();
+}
+//Get a row of the tableau (slack part in slack if not NULL)
+void 
+OsiClpSolverInterface::getBInvARow(int row, CoinIndexedVector * columnArray0, CoinIndexedVector * slack,
+				   bool keepScaled) const
+{
+#ifndef NDEBUG
+  int nx = modelPtr_->numberRows();
+  if (row<0||row>=nx) {
+    indexError(row,"getBInvARow");
+  }
+#endif
+  //assert (modelPtr_->solveType()==2||(specialOptions_&1));
+  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
+  CoinIndexedVector * rowArray1 = slack ? slack : modelPtr_->rowArray(1);
+  CoinIndexedVector * columnArray1 = modelPtr_->columnArray(1);
+  rowArray0->clear();
+  rowArray1->clear();
+  columnArray0->clear();
+  columnArray1->clear();
+  //int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  // put +1 in row 
+  // But swap if pivot variable was slack as clp stores slack as -1.0
+  const int * pivotVariable = modelPtr_->pivotVariable();
+  const double * rowScale = modelPtr_->rowScale();
+  const double * columnScale = modelPtr_->columnScale();
+  int pivot = pivotVariable[row];
+  double value;
+  // And if scaled then adjust
+  if (!rowScale) {
+    if (pivot<numberColumns)
+      value = 1.0;
+    else
+      value = -1.0;
+  } else {
+    if (pivot<numberColumns)
+      value = columnScale[pivot];
+    else
+      value = -1.0/rowScale[pivot-numberColumns];
+  }
+  rowArray1->insert(row,value);
+  modelPtr_->factorization()->updateColumnTranspose(rowArray0,rowArray1);
+  // put row of tableau in rowArray1 and columnArray0
+  modelPtr_->clpMatrix()->transposeTimes(modelPtr_,1.0,
+                                         rowArray1,columnArray1,columnArray0);
+  int n;
+  const int * which;
+  double * array;
+  // deal with scaling etc
+  if (rowScale&&!keepScaled) {
+    int j;
+    // First columns
+    n = columnArray0->getNumElements();
+    which = columnArray0->getIndices();
+    array = columnArray0->denseVector();
+    for (j=0; j < n; j++) {
+      int k=which[j];
+      array[k] /= columnScale[k];
+    }
+    if (slack) {
+      n = slack->getNumElements();
+      which = slack->getIndices();
+      array = slack->denseVector();
+      for(j=0; j < n; j++) {
+	int k=which[j];
+	array[k] *= rowScale[k];
+      }
+    }
+  }
+  if (!slack)
+    rowArray1->clear();
+}
+
+//Get a row of the basis inverse
+void 
+OsiClpSolverInterface::getBInvRow(int row, double* z) const
+
+{
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+  if (row<0||row>=n) {
+    indexError(row,"getBInvRow");
+  }
+#endif
+  //assert (modelPtr_->solveType()==2||(specialOptions_&1)!=0);
+  ClpFactorization * factorization = modelPtr_->factorization();
+  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
+  CoinIndexedVector * rowArray1 = modelPtr_->rowArray(1);
+  rowArray0->clear();
+  rowArray1->clear();
+  // put +1 in row
+  // But swap if pivot variable was slack as clp stores slack as -1.0
+  double value = (modelPtr_->pivotVariable()[row]<modelPtr_->numberColumns()) ? 1.0 : -1.0;
+  int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  const double * rowScale = modelPtr_->rowScale();
+  const double * columnScale = modelPtr_->columnScale();
+  const int * pivotVariable = modelPtr_->pivotVariable();
+  // but scale
+  if (rowScale) {
+    int pivot = pivotVariable[row];
+    if (pivot<numberColumns) 
+      value *= columnScale[pivot];
+    else
+      value /= rowScale[pivot-numberColumns];
+  }
+  rowArray1->insert(row,value);
+  factorization->updateColumnTranspose(rowArray0,rowArray1);
+  // If user is sophisticated then let her/him do work
+  if ((specialOptions_&512)==0) {
+    // otherwise copy and clear
+    if (!rowScale) {
+      CoinMemcpyN(rowArray1->denseVector(),modelPtr_->numberRows(),z);
+    } else {
+      double * array = rowArray1->denseVector();
+      for (int i=0;i<numberRows;i++) {
+        z[i] = array[i] * rowScale[i];
+      }
+    }
+    rowArray1->clear();
+  }
+}
+
+//Get a column of the tableau
+void 
+OsiClpSolverInterface::getBInvACol(int col, double* vec) const
+{
+  //assert (modelPtr_->solveType()==2||(specialOptions_&1)!=0);
+  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
+  CoinIndexedVector * rowArray1 = modelPtr_->rowArray(1);
+  rowArray0->clear();
+  rowArray1->clear();
+  // get column of matrix
+#ifndef NDEBUG
+  int n = modelPtr_->numberColumns()+modelPtr_->numberRows();
+  if (col<0||col>=n) {
+    indexError(col,"getBInvACol");
+  }
+#endif
+  int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  const int * pivotVariable = modelPtr_->pivotVariable();
+  const double * rowScale = modelPtr_->rowScale();
+  const double * columnScale = modelPtr_->columnScale();
+  if (!rowScale) {
+    if (col<numberColumns) {
+      modelPtr_->unpack(rowArray1,col);
+    } else {
+      rowArray1->insert(col-numberColumns,1.0);
+    }
+  } else {
+    if (col<numberColumns) {
+      modelPtr_->unpack(rowArray1,col);
+      double multiplier = 1.0/columnScale[col];
+      int number = rowArray1->getNumElements();
+      int * index = rowArray1->getIndices();
+      double * array = rowArray1->denseVector();
+      for (int i=0;i<number;i++) {
+	int iRow = index[i];
+	// make sure not packed
+	assert (array[iRow]);
+	array[iRow] *= multiplier;
+      }
+    } else {
+      rowArray1->insert(col-numberColumns,rowScale[col-numberColumns]);
+    }
+  }
+  modelPtr_->factorization()->updateColumn(rowArray0,rowArray1,false);
+  // If user is sophisticated then let her/him do work
+  if ((specialOptions_&512)==0) {
+    // otherwise copy and clear
+    // But swap if pivot variable was slack as clp stores slack as -1.0
+    double * array = rowArray1->denseVector();
+    if (!rowScale) {
+      for (int i=0;i<numberRows;i++) {
+        double multiplier = (pivotVariable[i]<numberColumns) ? 1.0 : -1.0;
+        vec[i] = multiplier * array[i];
+      }
+    } else {
+      for (int i=0;i<numberRows;i++) {
+        int pivot = pivotVariable[i];
+        if (pivot<numberColumns)
+          vec[i] = array[i] * columnScale[pivot];
+        else
+          vec[i] = - array[i] / rowScale[pivot-numberColumns];
+      }
+    }
+    rowArray1->clear();
+  }
+}
+//Get a column of the tableau
+void 
+OsiClpSolverInterface::getBInvACol(int col, CoinIndexedVector * rowArray1) const
+{
+  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
+  rowArray0->clear();
+  rowArray1->clear();
+  // get column of matrix
+#ifndef NDEBUG
+  int nx = modelPtr_->numberColumns()+modelPtr_->numberRows();
+  if (col<0||col>=nx) {
+    indexError(col,"getBInvACol");
+  }
+#endif
+  //int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  const int * pivotVariable = modelPtr_->pivotVariable();
+  const double * rowScale = modelPtr_->rowScale();
+  const double * columnScale = modelPtr_->columnScale();
+  if (!rowScale) {
+    if (col<numberColumns) {
+      modelPtr_->unpack(rowArray1,col);
+    } else {
+      rowArray1->insert(col-numberColumns,1.0);
+    }
+  } else {
+    if (col<numberColumns) {
+      modelPtr_->unpack(rowArray1,col);
+      double multiplier = 1.0/columnScale[col];
+      int number = rowArray1->getNumElements();
+      int * index = rowArray1->getIndices();
+      double * array = rowArray1->denseVector();
+      for (int i=0;i<number;i++) {
+	int iRow = index[i];
+	// make sure not packed
+	assert (array[iRow]);
+	array[iRow] *= multiplier;
+      }
+    } else {
+      rowArray1->insert(col-numberColumns,rowScale[col-numberColumns]);
+    }
+  }
+  modelPtr_->factorization()->updateColumn(rowArray0,rowArray1,false);
+  // Deal with stuff
+  int n = rowArray1->getNumElements();
+  const int * which = rowArray1->getIndices();
+  double * array = rowArray1->denseVector();
+  for(int j=0; j < n; j++){
+    int k=which[j];
+    // need to know pivot variable for +1/-1 (slack) and row/column scaling
+    int pivot = pivotVariable[k];
+    if (pivot<numberColumns) {
+      if (columnScale) 
+	array[k] *= columnScale[pivot];
+    } else {
+      if (!rowScale) {
+	array[k] = -array[k];
+      } else {
+	array[k] = -array[k]/rowScale[pivot-numberColumns];
+      }
+    }
+  }
+}
+
+//Get an updated column
+void 
+OsiClpSolverInterface::getBInvACol(CoinIndexedVector * rowArray1) const
+{
+  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
+  rowArray0->clear();
+  // get column of matrix
+  //int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  const int * pivotVariable = modelPtr_->pivotVariable();
+  const double * rowScale = modelPtr_->rowScale();
+  const double * columnScale = modelPtr_->columnScale();
+  // rowArray1 is not a column - so column scale can't be applied before
+  modelPtr_->factorization()->updateColumn(rowArray0,rowArray1,false);
+  // Deal with stuff
+  int n = rowArray1->getNumElements();
+  const int * which = rowArray1->getIndices();
+  double * array = rowArray1->denseVector();
+  for(int j=0; j < n; j++){
+    int k=which[j];
+    // need to know pivot variable for +1/-1 (slack) and row/column scaling
+    int pivot = pivotVariable[k];
+    if (pivot<numberColumns) {
+      if (columnScale) 
+	array[k] *= columnScale[pivot];
+    } else {
+      if (!rowScale) {
+	array[k] = -array[k];
+      } else {
+	array[k] = -array[k]/rowScale[pivot-numberColumns];
+      }
+    }
+  }
+}
+
+//Get a column of the basis inverse
+void 
+OsiClpSolverInterface::getBInvCol(int col, double* vec) const
+{
+  //assert (modelPtr_->solveType()==2||(specialOptions_&1)!=0);
+  ClpFactorization * factorization = modelPtr_->factorization();
+  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
+  CoinIndexedVector * rowArray1 = modelPtr_->rowArray(1);
+  rowArray0->clear();
+  rowArray1->clear();
+#ifndef NDEBUG
+  int n = modelPtr_->numberRows();
+  if (col<0||col>=n) {
+    indexError(col,"getBInvCol");
+  }
+#endif
+  // put +1 in row
+  int numberRows = modelPtr_->numberRows();
+  int numberColumns = modelPtr_->numberColumns();
+  const double * rowScale = modelPtr_->rowScale();
+  const double * columnScale = modelPtr_->columnScale();
+  const int * pivotVariable = modelPtr_->pivotVariable();
+  // but scale
+  double value;
+  if (!rowScale) {
+    value=1.0;
+  } else {
+    value = rowScale[col];
+  }
+  rowArray1->insert(col,value);
+  factorization->updateColumn(rowArray0,rowArray1,false);
+  // If user is sophisticated then let her/him do work
+  if ((specialOptions_&512)==0) {
+    // otherwise copy and clear
+    // But swap if pivot variable was slack as clp stores slack as -1.0
+    double * array = rowArray1->denseVector();
+    if (!rowScale) {
+      for (int i=0;i<numberRows;i++) {
+        double multiplier = (pivotVariable[i]<numberColumns) ? 1.0 : -1.0;
+        vec[i] = multiplier * array[i];
+      }
+    } else {
+      for (int i=0;i<numberRows;i++) {
+        int pivot = pivotVariable[i];
+        double value = array[i];
+        if (pivot<numberColumns) 
+          vec[i] = value * columnScale[pivot];
+        else
+          vec[i] = - value / rowScale[pivot-numberColumns];
+      }
+    }
+    rowArray1->clear();
+  }
+}
+
+/* Get basic indices (order of indices corresponds to the
+   order of elements in a vector returned by getBInvACol() and
+   getBInvCol()).
+*/
+void 
+OsiClpSolverInterface::getBasics(int* index) const
+{
+  //assert (modelPtr_->solveType()==2||(specialOptions_&1)!=0);
+  assert (index);
+  if (modelPtr_->pivotVariable()) {
+    CoinMemcpyN(modelPtr_->pivotVariable(),modelPtr_->numberRows(),index);
+  } else {
+    std::cerr<<"getBasics is only available with enableSimplexInterface."
+	     <<std::endl;
+    std::cerr<<"much of the same information can be had from getWarmStart."
+	     <<std::endl;
+    throw CoinError("No pivot variable array","getBasics",
+		    "OsiClpSolverInterface");
+  }
+}
+//Returns true if a basis is available and optimal
+bool 
+OsiClpSolverInterface::basisIsAvailable() const 
+{
+  return (lastAlgorithm_==1||lastAlgorithm_==2)&&(!modelPtr_->problemStatus_);
+}
+// Resets as if default constructor
+void 
+OsiClpSolverInterface::reset()
+{
+  setInitialData(); // clear base class
+  freeCachedResults();
+  if (!notOwned_)
+    delete modelPtr_;
+  delete ws_;
+  ws_ = NULL;
+  delete [] rowActivity_;
+  delete [] columnActivity_;
+  assert(smallModel_==NULL);
+  assert(factorization_==NULL);
+  smallestElementInCut_ = 1.0e-15;
+  smallestChangeInCut_ = 1.0e-10;
+  largestAway_ = -1.0;
+  assert(spareArrays_==NULL);
+  delete [] integerInformation_;
+  rowActivity_ = NULL;
+  columnActivity_ = NULL;
+  integerInformation_ = NULL;
+  basis_ = CoinWarmStartBasis();
+  itlimOrig_=9999999;
+  lastAlgorithm_=0;
+  notOwned_=false;
+  modelPtr_ = new ClpSimplex();
+  linearObjective_ = NULL;
+  fillParamMaps();
+}
+// Set a hint parameter
+bool 
+OsiClpSolverInterface::setHintParam(OsiHintParam key, bool yesNo,
+                                    OsiHintStrength strength,
+                                    void * otherInformation)
+{
+  if ( OsiSolverInterface::setHintParam(key,yesNo,strength,otherInformation)) {
+    // special coding for branch and cut
+    if (yesNo&&strength == OsiHintDo&&key==OsiDoInBranchAndCut) {
+      if ( specialOptions_==0x80000000) {
+        setupForRepeatedUse(0,0);
+        specialOptions_=0;
+      }
+      // set normal
+      specialOptions_ &= (2047|3*8192|15*65536|2097152|4194304);
+      if (otherInformation!=NULL) {
+        int * array = static_cast<int *> (otherInformation);
+        if (array[0]>=0||array[0]<=2)
+          specialOptions_ |= array[0]<<10;
+      }
+    }
+    // Printing
+    if (key==OsiDoReducePrint) {
+      handler_->setLogLevel(yesNo ? 0 : 1);
+    }
+    return true;
+  } else {
+    return false;
+  }
+}
+
+// Crunch down model
+void 
+OsiClpSolverInterface::crunch()
+{
+  //if (modelPtr_->scalingFlag_>0&&!modelPtr_->rowScale_&&
+  //  modelPtr_->rowCopy_) {
+  //printf("BBBB could crunch2\n");
+  //}
+  int numberColumns = modelPtr_->numberColumns();
+  int numberRows = modelPtr_->numberRows();
+  int totalIterations=0;
+  bool abortSearch=false;
+  // Use dual region
+  double * rhs = modelPtr_->dualRowSolution();
+  // Get space for strong branching 
+  int size = static_cast<int>((1+4*(numberRows+numberColumns))*sizeof(double));
+  // and for save of original column bounds
+  size += static_cast<int>(2*numberColumns*sizeof(double));
+  size += static_cast<int>((1+4*numberRows+2*numberColumns)*sizeof(int));
+  size += numberRows+numberColumns;
+#ifdef KEEP_SMALL
+  char * spareArrays = NULL;
+  if(!(modelPtr_->whatsChanged_&0x30000)) {
+    delete smallModel_;
+    smallModel_ = NULL;
+    delete [] spareArrays_;
+    spareArrays_ = NULL;
+  }
+  if (!spareArrays_) {
+    spareArrays = new char[size];
+    //memset(spareArrays,0x20,size);
+  } else {
+    spareArrays = spareArrays_;
+  }
+  double * arrayD = reinterpret_cast<double *> (spareArrays);
+  double * saveSolution = arrayD+1;
+  double * saveLower = saveSolution + (numberRows+numberColumns);
+  double * saveUpper = saveLower + (numberRows+numberColumns);
+  double * saveObjective = saveUpper + (numberRows+numberColumns);
+  double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
+  double * saveUpperOriginal = saveLowerOriginal + numberColumns;
+  double * lowerOriginal = modelPtr_->columnLower();
+  double * upperOriginal = modelPtr_->columnUpper();
+  int * savePivot = reinterpret_cast<int *> (saveUpperOriginal + numberColumns);
+  int * whichRow = savePivot+numberRows;
+  int * whichColumn = whichRow + 3*numberRows;
+  int * arrayI = whichColumn + 2*numberColumns;
+  if (spareArrays_) {
+    assert (smallModel_);
+    int nSame=0; 
+    int nSub=0;
+    for (int i=0;i<numberColumns;i++) {
+      double lo = lowerOriginal[i];
+      //char * xx = (char *) (saveLowerOriginal+i);
+      //assert (xx[0]!=0x20||xx[1]!=0x20);
+      double loOld = saveLowerOriginal[i];
+      //assert (!loOld||fabs(loOld)>1.0e-30);
+      double up = upperOriginal[i];
+      double upOld = saveUpperOriginal[i];
+      if (lo>=loOld&&up<=upOld) {
+	if (lo==loOld&&up==upOld) {
+	  nSame++;
+	} else {
+	  nSub++;
+	  //if (!isInteger(i))
+	  //nSub+=10;
+	}
+      }
+    }
+    //printf("%d bounds same, %d interior, %d bad\n",
+    //   nSame,nSub,numberColumns-nSame-nSub);
+    if (nSame<numberColumns) {
+      if (nSame+nSub<numberColumns||nSub>0) {
+	delete smallModel_;
+	smallModel_=NULL;
+      } else {
+	// we can fix up (but should we if large number fixed?)
+	assert (smallModel_);
+	double * lowerSmall = smallModel_->columnLower();
+	double * upperSmall = smallModel_->columnUpper();
+	int numberColumns2 = smallModel_->numberColumns();
+	for (int i=0;i<numberColumns2;i++) {
+	  int iColumn = whichColumn[i];
+	  lowerSmall[i]=lowerOriginal[iColumn];
+	  upperSmall[i]=upperOriginal[iColumn];
+	}
+      }
+    }
+  }
+  CoinMemcpyN( lowerOriginal,numberColumns, saveLowerOriginal);
+  CoinMemcpyN( upperOriginal,numberColumns, saveUpperOriginal);
+  if (smallModel_) {
+    if (!spareArrays_) {
+      assert((specialOptions_&131072)==0);
+#if 1
+      delete smallModel_;
+      smallModel_=NULL;
+#endif
+    }
+  }
+  //spareArrays=spareArrays_;
+  //spareArrays_ = NULL;
+#else
+  assert (spareArrays_==NULL);
+  int * whichRow = new int[3*numberRows+2*numberColumns];
+  int * whichColumn = whichRow+3*numberRows;
+#endif
+  int nBound;
+#ifdef KEEP_SMALL
+  bool tightenBounds = ((specialOptions_&64)==0) ? false : true; 
+  bool moreBounds=false;
+  ClpSimplex * small=NULL;
+  if (!smallModel_) {
+#ifndef NDEBUG
+    CoinFillN(whichRow,3*numberRows+2*numberColumns,-1);
+#endif
+    small = static_cast<ClpSimplexOther *> 
+      (modelPtr_)->crunch(rhs,whichRow,whichColumn,
+			  nBound,moreBounds,tightenBounds);
+#ifndef NDEBUG
+    int nCopy = 3*numberRows+2*numberColumns;
+    for (int i=0;i<nCopy;i++)
+      assert (whichRow[i]>=-CoinMax(numberRows,numberColumns)&&whichRow[i]<CoinMax(numberRows,numberColumns));
+#endif
+    smallModel_=small;
+    spareArrays_ = spareArrays;
+  } else {  
+    assert((modelPtr_->whatsChanged_&0x30000));
+    //delete [] spareArrays_;
+    //spareArrays_ = NULL;
+    assert (spareArrays_);
+    int nCopy = 3*numberRows+2*numberColumns;
+    nBound = whichRow[nCopy];
+#ifndef NDEBUG
+    for (int i=0;i<nCopy;i++)
+      assert (whichRow[i]>=-CoinMax(numberRows,numberColumns)&&whichRow[i]<CoinMax(numberRows,numberColumns));
+#endif
+    small = smallModel_;
+  }
+#if 0 //def CLP_INVESTIGATE
+#ifndef NDEBUG
+  if (smallModel_) {
+    int * whichColumn = whichRow+3*numberRows;
+    unsigned char * stat1=modelPtr_->status_;
+    int nr1=modelPtr_->numberRows_;
+    int nc1=modelPtr_->numberColumns_;
+    unsigned char * stat2=smallModel_->status_;
+    int nr2=smallModel_->numberRows_;
+    int nc2=smallModel_->numberColumns_;
+    int n=0;
+    for (int i=0;i<nr2+nc2;i++) {
+      if ((stat2[i]&7)==1)
+	n++;
+    }
+    assert (n==nr2);
+    n=0;
+    for (int i=0;i<nr1+nc1;i++) {
+      if ((stat1[i]&7)==1)
+	n++;
+    }
+    assert (n==nr1);
+    //const double * lo1=modelPtr_->columnLower_;
+    //const double * up1=modelPtr_->columnUpper_;
+    //const double * lo2=smallModel_->columnLower_;
+    //const double * up2=smallModel_->columnUpper_;
+    int nBad=0;
+    for (int i=0;i<nc2;i++) {
+      int j=whichColumn[i];
+      if ((stat2[i]&7)!=(stat1[j]&7)) {
+	if ((stat2[i]&7)==5) {
+	  if ((stat1[j]&7)==1)
+	    nBad++;
+	} else {
+	  assert ((stat2[i]&7)==(stat1[j]&7));
+	}
+      }
+    }
+    for (int i=0;i<nr2;i++) {
+      int j=whichRow[i];
+      if ((stat2[i+nc2]&7)!=(stat1[j+nc1]&7)) {
+	if ((stat2[i+nc2]&7)==5) {
+	  assert ((stat1[j+nc1]&7)!=1);
+	} else {
+	  assert ((stat2[i+nc2]&7)==(stat1[j+nc1]&7));
+	}
+      }
+    }
+    if (nBad) {
+      printf("%d basic moved to fixed\n",nBad);
+    }
+  }
+#endif
+#endif
+#else
+  bool tightenBounds = false;
+  bool moreBounds=true;
+#ifndef NDEBUG
+  CoinFillN(whichRow,3*numberRows+2*numberColumns,-1);
+#endif
+  ClpSimplex * small = static_cast<ClpSimplexOther *> 
+    (modelPtr_)->crunch(rhs,whichRow,whichColumn,
+			nBound,moreBounds,tightenBounds);
+#endif
+  bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
+  if (small) {
+    small->specialOptions_ |= 262144;
+    if ((specialOptions_&131072)!=0) {
+      assert (lastNumberRows_>=0);
+      int numberRows2 = small->numberRows();
+      int numberColumns2 = small->numberColumns();
+      double * rowScale2 = new double [2*numberRows2];
+      assert (rowScale_.getSize()>=2*numberRows);
+      const double * rowScale = rowScale_.array();
+      double * inverseScale2 = rowScale2+numberRows2;
+      const double * inverseScale = rowScale+modelPtr_->numberRows_;
+      int i;
+      for (i=0;i<numberRows2;i++) {
+	int iRow = whichRow[i];
+	assert (iRow>=0&&iRow<numberRows);
+	rowScale2[i]=rowScale[iRow];
+	inverseScale2[i]=inverseScale[iRow];
+      }
+      small->setRowScale(rowScale2);
+      double * columnScale2 = new double [2*numberColumns2];
+      assert (columnScale_.getSize()>=2*numberColumns);
+      const double * columnScale = columnScale_.array();
+      inverseScale2 = columnScale2+numberColumns2;
+      inverseScale = columnScale+modelPtr_->numberColumns_;
+      for (i=0;i<numberColumns2;i++) {
+	int iColumn = whichColumn[i];
+	//assert (iColumn<numberColumns);
+	columnScale2[i]=columnScale[iColumn];
+	inverseScale2[i]=inverseScale[iColumn];
+      }
+      small->setColumnScale(columnScale2);
+    }
+    disasterHandler_->setOsiModel(this);
+    if (inCbcOrOther) {
+      disasterHandler_->setSimplex(small);
+      disasterHandler_->setWhereFrom(1); // crunch
+      small->setDisasterHandler(disasterHandler_);
+    }
+#if 0
+    const double * obj =small->objective();
+    int numberColumns2 = small->numberColumns();
+    int iColumn;
+    for (iColumn=0;iColumn<numberColumns2;iColumn++) {
+      if (obj[iColumn])
+	break;
+    }
+    if (iColumn<numberColumns2)
+      small->dual();
+    else
+      small->primal(); // No objective - use primal!
+#else
+    small->moreSpecialOptions_ = modelPtr_->moreSpecialOptions_;
+    small->dual(0,7);
+#endif
+    totalIterations += small->numberIterations();
+    int problemStatus = small->problemStatus();
+    if (problemStatus>=0&&problemStatus<=2) {
+      modelPtr_->setProblemStatus(problemStatus);
+      if (!inCbcOrOther||!problemStatus) {
+	// Scaling may have changed - if so pass across
+	if (modelPtr_->scalingFlag()==4)
+	  modelPtr_->scaling(small->scalingFlag());
+	static_cast<ClpSimplexOther *> (modelPtr_)->afterCrunch(*small,whichRow,whichColumn,nBound);
+	if ((specialOptions_&1048576)==0) {
+	  // get correct rays
+	  if (problemStatus==2)
+	    modelPtr_->primal(1);
+	  else if (problemStatus==1)
+	    modelPtr_->dual();
+	} else {
+	  delete [] modelPtr_->ray_;
+	  modelPtr_->ray_=NULL;
+	  if (problemStatus==1&&small->ray_) {
+	    // get ray to full problem
+	    int numberRows = modelPtr_->numberRows();
+	    int numberRows2 = small->numberRows();
+	    double * ray = new double [numberRows];
+	    memset(ray,0,numberRows*sizeof(double));
+	    for (int i = 0; i < numberRows2; i++) {
+	      int iRow = whichRow[i];
+	      ray[iRow] = small->ray_[i];
+	    }
+	    // Column copy of matrix
+	    const double * element = getMatrixByCol()->getElements();
+	    const int * row = getMatrixByCol()->getIndices();
+	    const CoinBigIndex * columnStart = getMatrixByCol()->getVectorStarts();
+	    const int * columnLength = getMatrixByCol()->getVectorLengths();
+	    // translate
+	    //pivotRow=whichRow[pivotRow];
+	    //modelPtr_->spareIntArray_[3]=pivotRow;
+	    int pivotRow=-1;
+	    for (int jRow = nBound; jRow < 2 * numberRows; jRow++) {
+	      int iRow = whichRow[jRow];
+	      int iColumn = whichRow[jRow+numberRows];
+	      if (modelPtr_->getColumnStatus(iColumn) == ClpSimplex::basic) {
+		double value = 0.0;
+		double sum = 0.0;
+		for (CoinBigIndex j = columnStart[iColumn];
+		     j < columnStart[iColumn] + columnLength[iColumn]; j++) {
+		  if (iRow == row[j]) {
+		    value = element[j];
+		  } else {
+		    sum += ray[row[j]]*element[j];
+		  }
+		}
+		if (iRow!=pivotRow) {
+		  ray[iRow] = -sum / value;
+		} else {
+		  printf("what now - direction %d wanted %g sum %g value %g\n",
+			 small->directionOut_,ray[iRow],
+			 sum,value);
+		}
+	      }
+	    }
+	    for (int i=0;i<modelPtr_->numberColumns_;i++) {
+	      if (modelPtr_->getStatus(i)!=ClpSimplex::basic&&
+		  modelPtr_->columnLower_[i]==modelPtr_->columnUpper_[i])
+		modelPtr_->setStatus(i,ClpSimplex::isFixed);
+	    }
+	    modelPtr_->ray_=ray;
+	    modelPtr_->directionOut_=small->directionOut_;
+	  }
+	}
+      }
+#ifdef KEEP_SMALL
+      //assert (!smallModel_);
+      //smallModel_ = small;
+      small=NULL;
+      int nCopy = 3*numberRows+2*numberColumns;
+      //int * copy = CoinCopyOfArrayPartial(whichRow,nCopy+1,nCopy);
+      whichRow[nCopy]=nBound;
+      assert (arrayI[0]==nBound);
+      arrayI[0]=nBound; // same
+      spareArrays_ = spareArrays_;
+      spareArrays=NULL;
+#endif
+    } else if (problemStatus!=3) {
+      modelPtr_->setProblemStatus(1);
+    } else {
+      if (problemStatus==3) {
+	// may be problems
+	if (inCbcOrOther&&disasterHandler_->inTrouble()) {
+	  if (disasterHandler_->typeOfDisaster()) {
+	    // We want to abort 
+	    abortSearch=true;
+	    goto disaster;
+	  }
+	  // in case scaling bad
+	  small->setRowScale(NULL);
+	  small->setColumnScale(NULL);
+    	  // try just going back in
+	  disasterHandler_->setPhase(1);
+	  small->dual();
+	  totalIterations += small->numberIterations();
+	  if (disasterHandler_->inTrouble()) {
+	    if (disasterHandler_->typeOfDisaster()) {
+	      // We want to abort 
+	      abortSearch=true;
+	      goto disaster;
+	    }
+	    // try primal on original model
+	    disasterHandler_->setPhase(2);
+	    disasterHandler_->setOsiModel(this);
+	    modelPtr_->setDisasterHandler(disasterHandler_);
+	    modelPtr_->primal();
+	    totalIterations += modelPtr_->numberIterations();
+	    if(disasterHandler_->inTrouble()) {
+#ifdef COIN_DEVELOP
+	      printf("disaster crunch - treat as infeasible\n");
+#endif
+	      if (disasterHandler_->typeOfDisaster()) {
+		// We want to abort 
+		abortSearch=true;
+		goto disaster;
+	      }
+	      modelPtr_->setProblemStatus(1);
+	    }
+	    // give up for now
+	    modelPtr_->setDisasterHandler(NULL);
+	  } else {
+	    modelPtr_->setProblemStatus(small->problemStatus());
+	  }
+	} else {
+	  small->computeObjectiveValue();
+	  modelPtr_->setObjectiveValue(small->objectiveValue());
+	  modelPtr_->setProblemStatus(3);
+	}
+      } else {
+	modelPtr_->setProblemStatus(3);
+      }
+    }
+  disaster:
+    delete small;
+#ifdef KEEP_SMALL
+    if (small==smallModel_) {
+      smallModel_ = NULL;
+      delete [] spareArrays_;
+      spareArrays_ = NULL;
+      spareArrays = NULL;
+    }
+#endif
+  } else {
+    modelPtr_->setProblemStatus(1);
+#ifdef KEEP_SMALL
+    delete [] spareArrays_;
+    spareArrays_ = NULL;
+    spareArrays = NULL;
+#endif
+  }
+  modelPtr_->setNumberIterations(totalIterations);
+  if (abortSearch) {
+    lastAlgorithm_=-911;
+    modelPtr_->setProblemStatus(4);
+  }
+#ifdef KEEP_SMALL
+  delete [] spareArrays;
+#else
+  delete [] whichRow;
+#endif
+}
+// Synchronize model 
+void 
+OsiClpSolverInterface::synchronizeModel() 
+{
+  if ((specialOptions_ &128)!=0) {
+    if (!modelPtr_->rowScale_&&(specialOptions_&131072)!=0) {
+      assert (lastNumberRows_==modelPtr_->numberRows_);
+      int numberRows = modelPtr_->numberRows();
+      int numberColumns = modelPtr_->numberColumns();
+      double * rowScale = CoinCopyOfArray(rowScale_.array(),2*numberRows);
+      modelPtr_->setRowScale(rowScale);
+      double * columnScale = CoinCopyOfArray(columnScale_.array(),2*numberColumns);
+      modelPtr_->setColumnScale(columnScale);
+      modelPtr_->setRowScale(NULL);
+      modelPtr_->setColumnScale(NULL);
+    }
+  }
+}
+// Returns true if has OsiSimplex methods
+/* Returns 1 if can just do getBInv etc
+   2 if has all OsiSimplex methods
+   and 0 if it has none */
+int
+OsiClpSolverInterface::canDoSimplexInterface() const
+{
+  return 2;
+}
+// Pass in sos stuff from AMPl
+void 
+OsiClpSolverInterface::setSOSData(int numberSOS,const char * type,
+				  const int * start,const int * indices, const double * weights)
+{
+  delete [] setInfo_;
+  setInfo_=NULL;
+  numberSOS_=numberSOS;
+  if (numberSOS_) {
+    setInfo_ = new CoinSet[numberSOS_];
+    for (int i=0;i<numberSOS_;i++) {
+      int iStart = start[i];
+      setInfo_[i]=CoinSosSet(start[i+1]-iStart,indices+iStart,weights ? weights+iStart : NULL,
+			     type[i]);
+    }
+  }
+}
+/* Identify integer variables and SOS and create corresponding objects.
+  
+      Record integer variables and create an OsiSimpleInteger object for each
+      one.  All existing OsiSimpleInteger objects will be destroyed.
+      If the solver supports SOS then do the same for SOS.
+
+      If justCount then no objects created and we just store numberIntegers_
+      Returns number of SOS
+*/
+int 
+OsiClpSolverInterface::findIntegersAndSOS(bool justCount)
+{
+  findIntegers(justCount);
+  int nObjects=0;
+  OsiObject ** oldObject = object_;
+  int iObject;
+  int numberSOS=0;
+  for (iObject = 0;iObject<numberObjects_;iObject++) {
+    OsiSOS * obj =
+      dynamic_cast <OsiSOS *>(oldObject[iObject]) ;
+    if (obj) 
+      numberSOS++;
+  }
+  if (numberSOS_&&!numberSOS) {
+    // make a large enough array for new objects
+    nObjects = numberObjects_;
+    numberObjects_=numberSOS_+nObjects;
+    if (numberObjects_)
+      object_ = new OsiObject * [numberObjects_];
+    else
+      object_=NULL;
+    // copy
+    CoinMemcpyN(oldObject,nObjects,object_);
+    // Delete old array (just array)
+    delete [] oldObject;
+    
+    for (int i=0;i<numberSOS_;i++) {
+      CoinSet * set =  setInfo_+i;
+      object_[nObjects++] =
+	new OsiSOS(this,set->numberEntries(),set->which(),set->weights(),
+		   set->setType());
+    }
+  } else if (!numberSOS_&&numberSOS) {
+    // create Coin sets
+    assert (!setInfo_);
+    setInfo_ = new CoinSet[numberSOS];
+    for (iObject = 0;iObject<numberObjects_;iObject++) {
+      OsiSOS * obj =
+	dynamic_cast <OsiSOS *>(oldObject[iObject]) ;
+      if (obj) 
+	setInfo_[numberSOS_++]=CoinSosSet(obj->numberMembers(),obj->members(),obj->weights(),obj->sosType());
+    }
+  } else if (numberSOS!=numberSOS_) {
+    printf("mismatch on SOS\n");
+  }
+  return numberSOS_;
+}
+// below needed for pathetic branch and bound code
+#include <vector>
+#include <map>
+
+// Trivial class for Branch and Bound
+
+class OsiNodeSimple  {
+  
+public:
+    
+  // Default Constructor 
+  OsiNodeSimple ();
+
+  // Constructor from current state (and list of integers)
+  // Also chooses branching variable (if none set to -1)
+  OsiNodeSimple (OsiSolverInterface &model,
+                 int numberIntegers, int * integer,
+                 CoinWarmStart * basis);
+  void gutsOfConstructor (OsiSolverInterface &model,
+                 int numberIntegers, int * integer,
+                 CoinWarmStart * basis);
+  // Copy constructor 
+  OsiNodeSimple ( const OsiNodeSimple &);
+   
+  // Assignment operator 
+  OsiNodeSimple & operator=( const OsiNodeSimple& rhs);
+
+  // Destructor 
+  ~OsiNodeSimple ();
+  // Work of destructor
+  void gutsOfDestructor();
+  // Extension - true if other extension of this
+  bool extension(const OsiNodeSimple & other,
+		 const double * originalLower,
+		 const double * originalUpper) const;
+  inline void incrementDescendants()
+  { descendants_++;}
+  // Public data
+  // Basis (should use tree, but not as wasteful as bounds!)
+  CoinWarmStart * basis_;
+  // Objective value (COIN_DBL_MAX) if spare node
+  double objectiveValue_;
+  // Branching variable (0 is first integer) 
+  int variable_;
+  // Way to branch - -1 down (first), 1 up, -2 down (second), 2 up (second)
+  int way_;
+  // Number of integers (for length of arrays)
+  int numberIntegers_;
+  // Current value
+  double value_;
+  // Number of descendant nodes (so 2 is in interior)
+  int descendants_;
+  // Parent 
+  int parent_;
+  // Previous in chain
+  int previous_;
+  // Next in chain
+  int next_;
+  // Now I must use tree
+  // Bounds stored in full (for integers)
+  int * lower_;
+  int * upper_;
+};
+
+
+OsiNodeSimple::OsiNodeSimple() :
+  basis_(NULL),
+  objectiveValue_(COIN_DBL_MAX),
+  variable_(-100),
+  way_(-1),
+  numberIntegers_(0),
+  value_(0.5),
+  descendants_(-1),
+  parent_(-1),
+  previous_(-1),
+  next_(-1),
+  lower_(NULL),
+  upper_(NULL)
+{
+}
+OsiNodeSimple::OsiNodeSimple(OsiSolverInterface & model,
+		 int numberIntegers, int * integer,CoinWarmStart * basis)
+{
+  gutsOfConstructor(model,numberIntegers,integer,basis);
+}
+void
+OsiNodeSimple::gutsOfConstructor(OsiSolverInterface & model,
+		 int numberIntegers, int * integer,CoinWarmStart * basis)
+{
+  basis_ = basis;
+  variable_=-1;
+  way_=-1;
+  numberIntegers_=numberIntegers;
+  value_=0.0;
+  descendants_ = 0;
+  parent_ = -1;
+  previous_ = -1;
+  next_ = -1;
+  if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
+    objectiveValue_ = model.getObjSense()*model.getObjValue();
+  } else {
+    objectiveValue_ = 1.0e100;
+    lower_ = NULL;
+    upper_ = NULL;
+    return; // node cutoff
+  }
+  lower_ = new int [numberIntegers_];
+  upper_ = new int [numberIntegers_];
+  assert (upper_!=NULL);
+  const double * lower = model.getColLower();
+  const double * upper = model.getColUpper();
+  const double * solution = model.getColSolution();
+  int i;
+  // Hard coded integer tolerance
+#define INTEGER_TOLERANCE 1.0e-6
+  ///////// Start of Strong branching code - can be ignored
+  // Number of strong branching candidates
+#define STRONG_BRANCHING 5
+#ifdef STRONG_BRANCHING
+  double upMovement[STRONG_BRANCHING];
+  double downMovement[STRONG_BRANCHING];
+  double solutionValue[STRONG_BRANCHING];
+  int chosen[STRONG_BRANCHING];
+  int iSmallest=0;
+  // initialize distance from integer
+  for (i=0;i<STRONG_BRANCHING;i++) {
+    upMovement[i]=0.0;
+    chosen[i]=-1;
+  }
+  variable_=-1;
+  // This has hard coded integer tolerance
+  double mostAway=INTEGER_TOLERANCE;
+  int numberAway=0;
+  for (i=0;i<numberIntegers;i++) {
+    int iColumn = integer[i];
+    lower_[i]=static_cast<int>(lower[iColumn]);
+    upper_[i]=static_cast<int>(upper[iColumn]);
+    double value = solution[iColumn];
+    value = CoinMax(value,static_cast<double> (lower_[i]));
+    value = CoinMin(value,static_cast<double> (upper_[i]));
+    double nearest = floor(value+0.5);
+    if (fabs(value-nearest)>INTEGER_TOLERANCE)
+      numberAway++;
+    if (fabs(value-nearest)>mostAway) {
+      double away = fabs(value-nearest);
+      if (away>upMovement[iSmallest]) {
+	//add to list
+	upMovement[iSmallest]=away;
+	solutionValue[iSmallest]=value;
+	chosen[iSmallest]=i;
+	int j;
+	iSmallest=-1;
+	double smallest = 1.0;
+	for (j=0;j<STRONG_BRANCHING;j++) {
+	  if (upMovement[j]<smallest) {
+	    smallest=upMovement[j];
+	    iSmallest=j;
+	  }
+	}
+      }
+    }
+  }
+  int numberStrong=0;
+  for (i=0;i<STRONG_BRANCHING;i++) {
+    if (chosen[i]>=0) { 
+      numberStrong ++;
+      variable_ = chosen[i];
+    }
+  }
+  // out strong branching if bit set
+  OsiClpSolverInterface* clp =
+    dynamic_cast<OsiClpSolverInterface*>(&model);
+  if (clp&&(clp->specialOptions()&16)!=0&&numberStrong>1) {
+    int j;
+    int iBest=-1;
+    double best = 0.0;
+    for (j=0;j<STRONG_BRANCHING;j++) {
+      if (upMovement[j]>best) {
+        best=upMovement[j];
+        iBest=j;
+      }
+    }
+    numberStrong=1;
+    variable_=chosen[iBest];
+  }
+  if (numberStrong==1) {
+    // just one - makes it easy
+    int iColumn = integer[variable_];
+    double value = solution[iColumn];
+    value = CoinMax(value,static_cast<double> (lower_[variable_]));
+    value = CoinMin(value,static_cast<double> (upper_[variable_]));
+    double nearest = floor(value+0.5);
+    value_=value;
+    if (value<=nearest)
+      way_=1; // up
+    else
+      way_=-1; // down
+  } else if (numberStrong) {
+    // more than one - choose
+    bool chooseOne=true;
+    model.markHotStart();
+    for (i=0;i<STRONG_BRANCHING;i++) {
+      int iInt = chosen[i];
+      if (iInt>=0) {
+	int iColumn = integer[iInt];
+	double value = solutionValue[i]; // value of variable in original
+	double objectiveChange;
+	value = CoinMax(value,static_cast<double> (lower_[iInt]));
+	value = CoinMin(value,static_cast<double> (upper_[iInt]));
+
+	// try down
+
+	model.setColUpper(iColumn,floor(value));
+	model.solveFromHotStart();
+	model.setColUpper(iColumn,upper_[iInt]);
+	if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
+	  objectiveChange = model.getObjSense()*model.getObjValue()
+	    - objectiveValue_;
+	} else {
+	  objectiveChange = 1.0e100;
+	}
+	assert (objectiveChange>-1.0e-5);
+	objectiveChange = CoinMax(objectiveChange,0.0);
+	downMovement[i]=objectiveChange;
+
+	// try up
+
+	model.setColLower(iColumn,ceil(value));
+	model.solveFromHotStart();
+	model.setColLower(iColumn,lower_[iInt]);
+	if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
+	  objectiveChange = model.getObjSense()*model.getObjValue()
+	    - objectiveValue_;
+	} else {
+	  objectiveChange = 1.0e100;
+	}
+	assert (objectiveChange>-1.0e-5);
+	objectiveChange = CoinMax(objectiveChange,0.0);
+	upMovement[i]=objectiveChange;
+
+	/* Possibilities are:
+	   Both sides feasible - store
+	   Neither side feasible - set objective high and exit
+	   One side feasible - change bounds and resolve
+	*/
+	bool solveAgain=false;
+	if (upMovement[i]<1.0e100) {
+	  if(downMovement[i]<1.0e100) {
+	    // feasible - no action
+	  } else {
+	    // up feasible, down infeasible
+	    solveAgain = true;
+	    model.setColLower(iColumn,ceil(value));
+	  }
+	} else {
+	  if(downMovement[i]<1.0e100) {
+	    // down feasible, up infeasible
+	    solveAgain = true;
+	    model.setColUpper(iColumn,floor(value));
+	  } else {
+	    // neither side feasible
+	    objectiveValue_=1.0e100;
+	    chooseOne=false;
+	    break;
+	  }
+	}
+	if (solveAgain) {
+	  // need to solve problem again - signal this
+	  variable_ = numberIntegers;
+	  chooseOne=false;
+	  break;
+	}
+      }
+    }
+    if (chooseOne) {
+      // choose the one that makes most difference both ways
+      double best = -1.0;
+      double best2 = -1.0;
+      for (i=0;i<STRONG_BRANCHING;i++) {
+	int iInt = chosen[i];
+	if (iInt>=0) {
+	  //std::cout<<"Strong branching on "
+          //   <<i<<""<<iInt<<" down "<<downMovement[i]
+          //   <<" up "<<upMovement[i]
+          //   <<" value "<<solutionValue[i]
+          //   <<std::endl;
+	  bool better = false;
+	  if (CoinMin(upMovement[i],downMovement[i])>best) {
+	    // smaller is better
+	    better=true;
+	  } else if (CoinMin(upMovement[i],downMovement[i])>best-1.0e-5) {
+	    if (CoinMax(upMovement[i],downMovement[i])>best2+1.0e-5) {
+	      // smaller is about same, but larger is better
+	      better=true;
+	    }
+	  }
+	  if (better) {
+	    best = CoinMin(upMovement[i],downMovement[i]);
+	    best2 = CoinMax(upMovement[i],downMovement[i]);
+	    variable_ = iInt;
+	    double value = solutionValue[i];
+	    value = CoinMax(value,static_cast<double> (lower_[variable_]));
+	    value = CoinMin(value,static_cast<double> (upper_[variable_]));
+	    value_=value;
+	    if (upMovement[i]<=downMovement[i])
+	      way_=1; // up
+	    else
+	      way_=-1; // down
+	  }
+	}
+      }
+    }
+    // Delete the snapshot
+    model.unmarkHotStart();
+  }
+  ////// End of Strong branching
+#else
+  variable_=-1;
+  // This has hard coded integer tolerance
+  double mostAway=INTEGER_TOLERANCE;
+  int numberAway=0;
+  for (i=0;i<numberIntegers;i++) {
+    int iColumn = integer[i];
+    lower_[i]=static_cast<int>(lower[iColumn]);
+    upper_[i]=static_cast<int>(upper[iColumn]);
+    double value = solution[iColumn];
+    value = CoinMax(value,(double) lower_[i]);
+    value = CoinMin(value,(double) upper_[i]);
+    double nearest = floor(value+0.5);
+    if (fabs(value-nearest)>INTEGER_TOLERANCE)
+      numberAway++;
+    if (fabs(value-nearest)>mostAway) {
+      mostAway=fabs(value-nearest);
+      variable_=i;
+      value_=value;
+      if (value<=nearest)
+	way_=1; // up
+      else
+	way_=-1; // down
+    }
+  }
+#endif
+}
+
+OsiNodeSimple::OsiNodeSimple(const OsiNodeSimple & rhs) 
+{
+  if (rhs.basis_)
+    basis_=rhs.basis_->clone();
+  else
+    basis_ = NULL;
+  objectiveValue_=rhs.objectiveValue_;
+  variable_=rhs.variable_;
+  way_=rhs.way_;
+  numberIntegers_=rhs.numberIntegers_;
+  value_=rhs.value_;
+  descendants_ = rhs.descendants_;
+  parent_ = rhs.parent_;
+  previous_ = rhs.previous_;
+  next_ = rhs.next_;
+  lower_=NULL;
+  upper_=NULL;
+  if (rhs.lower_!=NULL) {
+    lower_ = new int [numberIntegers_];
+    upper_ = new int [numberIntegers_];
+    assert (upper_!=NULL);
+    CoinMemcpyN(rhs.lower_,numberIntegers_,lower_);
+    CoinMemcpyN(rhs.upper_,numberIntegers_,upper_);
+  }
+}
+
+OsiNodeSimple &
+OsiNodeSimple::operator=(const OsiNodeSimple & rhs)
+{
+  if (this != &rhs) {
+    gutsOfDestructor();
+    if (rhs.basis_)
+      basis_=rhs.basis_->clone();
+    objectiveValue_=rhs.objectiveValue_;
+    variable_=rhs.variable_;
+    way_=rhs.way_;
+    numberIntegers_=rhs.numberIntegers_;
+    value_=rhs.value_;
+    descendants_ = rhs.descendants_;
+    parent_ = rhs.parent_;
+    previous_ = rhs.previous_;
+    next_ = rhs.next_;
+    if (rhs.lower_!=NULL) {
+      lower_ = new int [numberIntegers_];
+      upper_ = new int [numberIntegers_];
+      assert (upper_!=NULL);
+      CoinMemcpyN(rhs.lower_,numberIntegers_,lower_);
+      CoinMemcpyN(rhs.upper_,numberIntegers_,upper_);
+    }
+  }
+  return *this;
+}
+
+
+OsiNodeSimple::~OsiNodeSimple ()
+{
+  gutsOfDestructor();
+}
+// Work of destructor
+void 
+OsiNodeSimple::gutsOfDestructor()
+{
+  delete [] lower_;
+  delete [] upper_;
+  delete basis_;
+  lower_ = NULL;
+  upper_ = NULL;
+  basis_ = NULL;
+  objectiveValue_ = COIN_DBL_MAX;
+}
+// Extension - true if other extension of this
+bool 
+OsiNodeSimple::extension(const OsiNodeSimple & other,
+			 const double * originalLower,
+			 const double * originalUpper) const
+{
+  bool ok=true;
+  for (int i=0;i<numberIntegers_;i++) {
+    if (upper_[i]<originalUpper[i]||
+	lower_[i]>originalLower[i]) {
+      if (other.upper_[i]>upper_[i]||
+	  other.lower_[i]<lower_[i]) {
+	ok=false;
+	break;
+      }
+    }
+  }
+  return ok;
+}
+
+#include <vector>
+#define FUNNY_BRANCHING 1
+#define FUNNY_TREE
+#ifndef FUNNY_TREE
+// Vector of OsiNodeSimples 
+typedef std::vector<OsiNodeSimple>    OsiVectorNode;
+#else
+// Must code up by hand
+class OsiVectorNode  {
+  
+public:
+    
+  // Default Constructor 
+  OsiVectorNode ();
+
+  // Copy constructor 
+  OsiVectorNode ( const OsiVectorNode &);
+   
+  // Assignment operator 
+  OsiVectorNode & operator=( const OsiVectorNode& rhs);
+
+  // Destructor 
+  ~OsiVectorNode ();
+  // Size
+  inline int size() const
+  { return size_-sizeDeferred_;}
+  // Push
+  void push_back(const OsiNodeSimple & node);
+  // Last one in (or other criterion)
+  OsiNodeSimple back() const;
+  // Get rid of last one
+  void pop_back();
+  // Works out best one
+  int best() const;
+  
+  // Public data
+  // Maximum size
+  int maximumSize_;
+  // Current size
+  int size_;
+  // Number still hanging around
+  int sizeDeferred_;
+  // First spare
+  int firstSpare_;
+  // First 
+  int first_;
+  // Last 
+  int last_;
+  // Chosen one
+  mutable int chosen_;
+  // Nodes
+  OsiNodeSimple * nodes_;
+};
+
+
+OsiVectorNode::OsiVectorNode() :
+  maximumSize_(10),
+  size_(0),
+  sizeDeferred_(0),
+  firstSpare_(0),
+  first_(-1),
+  last_(-1)
+{
+  nodes_ = new OsiNodeSimple[maximumSize_];
+  for (int i=0;i<maximumSize_;i++) {
+    nodes_[i].previous_=i-1;
+    nodes_[i].next_=i+1;
+  }
+}
+
+OsiVectorNode::OsiVectorNode(const OsiVectorNode & rhs) 
+{  
+  maximumSize_ = rhs.maximumSize_;
+  size_ = rhs.size_;
+  sizeDeferred_ = rhs.sizeDeferred_;
+  firstSpare_ = rhs.firstSpare_;
+  first_ = rhs.first_;
+  last_ = rhs.last_;
+  nodes_ = new OsiNodeSimple[maximumSize_];
+  for (int i=0;i<maximumSize_;i++) {
+    nodes_[i] = rhs.nodes_[i];
+  }
+}
+
+OsiVectorNode &
+OsiVectorNode::operator=(const OsiVectorNode & rhs)
+{
+  if (this != &rhs) {
+    delete [] nodes_;
+    maximumSize_ = rhs.maximumSize_;
+    size_ = rhs.size_;
+    sizeDeferred_ = rhs.sizeDeferred_;
+    firstSpare_ = rhs.firstSpare_;
+    first_ = rhs.first_;
+    last_ = rhs.last_;
+    nodes_ = new OsiNodeSimple[maximumSize_];
+    for (int i=0;i<maximumSize_;i++) {
+      nodes_[i] = rhs.nodes_[i];
+    }
+  }
+  return *this;
+}
+
+
+OsiVectorNode::~OsiVectorNode ()
+{
+  delete [] nodes_;
+}
+// Push
+void 
+OsiVectorNode::push_back(const OsiNodeSimple & node)
+{
+  if (size_==maximumSize_) {
+    assert (firstSpare_==size_);
+    maximumSize_ = (maximumSize_*3)+10;
+    OsiNodeSimple * temp = new OsiNodeSimple[maximumSize_];
+    int i;
+    for (i=0;i<size_;i++) {
+      temp[i]=nodes_[i];
+    }
+    delete [] nodes_;
+    nodes_ = temp;
+    //firstSpare_=size_;
+    int last = -1;
+    for ( i=size_;i<maximumSize_;i++) {
+      nodes_[i].previous_=last;
+      nodes_[i].next_=i+1;
+      last = i;
+    }
+  }
+  assert (firstSpare_<maximumSize_);
+  assert (nodes_[firstSpare_].previous_<0);
+  int next = nodes_[firstSpare_].next_;
+  nodes_[firstSpare_]=node;
+  if (last_>=0) {
+    assert (nodes_[last_].next_==-1);
+    nodes_[last_].next_=firstSpare_;
+  }
+  nodes_[firstSpare_].previous_=last_;
+  nodes_[firstSpare_].next_=-1;
+  if (last_==-1) {
+    assert (first_==-1);
+    first_ = firstSpare_;
+  }
+  last_=firstSpare_;
+  if (next>=0&&next<maximumSize_) {
+    firstSpare_ = next;
+    nodes_[firstSpare_].previous_=-1;
+  } else {
+    firstSpare_=maximumSize_;
+  }
+  chosen_ = -1;
+  //best();
+  size_++;
+  assert (node.descendants_<=2);
+  if (node.descendants_==2)
+    sizeDeferred_++;
+}
+// Works out best one
+int 
+OsiVectorNode::best() const
+{
+  // can modify
+  chosen_=-1;
+  if (chosen_<0) {
+    chosen_=last_;
+#if FUNNY_BRANCHING
+    while (nodes_[chosen_].descendants_==2) {
+      chosen_ = nodes_[chosen_].previous_;
+      assert (chosen_>=0);
+    }
+#endif
+  }
+  return chosen_;
+}
+// Last one in (or other criterion)
+OsiNodeSimple 
+OsiVectorNode::back() const
+{
+  assert (last_>=0);
+  return nodes_[best()];
+}
+// Get rid of last one
+void 
+OsiVectorNode::pop_back()
+{
+  // Temporary until more sophisticated
+  //assert (last_==chosen_);
+  if (nodes_[chosen_].descendants_==2)
+    sizeDeferred_--;
+  int previous = nodes_[chosen_].previous_;
+  int next = nodes_[chosen_].next_;
+  nodes_[chosen_].gutsOfDestructor();
+  if (previous>=0) {
+    nodes_[previous].next_=next;
+  } else {
+    first_ = next;
+  }
+  if (next>=0) {
+    nodes_[next].previous_ = previous;
+  } else {
+    last_ = previous;
+  }
+  nodes_[chosen_].previous_=-1;
+  if (firstSpare_>=0) {
+    nodes_[chosen_].next_ = firstSpare_;
+  } else {
+    nodes_[chosen_].next_ = -1;
+  }
+  firstSpare_ = chosen_;
+  chosen_ = -1;
+  assert (size_>0);
+  size_--;
+}
+#endif
+// Invoke solver's built-in enumeration algorithm
+void 
+OsiClpSolverInterface::branchAndBound() {
+  double time1 = CoinCpuTime();
+  // solve LP
+  initialSolve();
+  int funnyBranching=FUNNY_BRANCHING;
+
+  if (isProvenOptimal()&&!isDualObjectiveLimitReached()) {
+    // Continuous is feasible - find integers
+    int numberIntegers=0;
+    int numberColumns = getNumCols();
+    int iColumn;
+    int i;
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      if( isInteger(iColumn))
+        numberIntegers++;
+    }
+    if (!numberIntegers) {
+      std::cout<<"No integer variables"
+               <<std::endl;
+      return;
+    }
+    int * which = new int[numberIntegers]; // which variables are integer
+    // original bounds
+    int * originalLower = new int[numberIntegers];
+    int * originalUpper = new int[numberIntegers];
+    int * relaxedLower = new int[numberIntegers];
+    int * relaxedUpper = new int[numberIntegers];
+    {
+      const double * lower = getColLower();
+      const double * upper = getColUpper();
+      numberIntegers=0;
+      for (iColumn=0;iColumn<numberColumns;iColumn++) {
+	if( isInteger(iColumn)) {
+	  originalLower[numberIntegers]=static_cast<int> (lower[iColumn]);
+	  if (upper[iColumn]>1.0e9) {
+	    // This is not meant to be a bulletproof code
+	    setColUpper(iColumn,1.0e9);
+	  }
+	  originalUpper[numberIntegers]=static_cast<int> (upper[iColumn]);
+	  which[numberIntegers++]=iColumn;
+	}
+      }
+    }
+    double direction = getObjSense();
+    // empty tree
+    OsiVectorNode branchingTree;
+    
+    // Add continuous to it;
+    OsiNodeSimple rootNode(*this,numberIntegers,which,getWarmStart());
+    // something extra may have been fixed by strong branching
+    // if so go round again
+    while (rootNode.variable_==numberIntegers) {
+      resolve();
+      rootNode = OsiNodeSimple(*this,numberIntegers,which,getWarmStart());
+    }
+    if (rootNode.objectiveValue_<1.0e100) {
+      // push on stack
+      branchingTree.push_back(rootNode);
+    }
+    
+    // For printing totals
+    int numberIterations=0;
+    int numberNodes =0;
+    int nRedundantUp=0;
+    int nRedundantDown=0;
+    int nRedundantUp2=0;
+    int nRedundantDown2=0;
+    OsiNodeSimple bestNode;
+    ////// Start main while of branch and bound
+    // while until nothing on stack
+    while (branchingTree.size()) {
+      // last node
+      OsiNodeSimple node = branchingTree.back();
+      int kNode = branchingTree.chosen_;
+      branchingTree.pop_back();
+      assert (node.descendants_<2);
+      numberNodes++;
+      if (node.variable_>=0) {
+        // branch - do bounds
+        for (i=0;i<numberIntegers;i++) {
+          iColumn=which[i];
+          setColBounds( iColumn,node.lower_[i],node.upper_[i]);
+        }
+        // move basis
+        setWarmStart(node.basis_);
+        // do branching variable
+	node.incrementDescendants();
+        if (node.way_<0) {
+          setColUpper(which[node.variable_],floor(node.value_));
+          // now push back node if more to come
+          if (node.way_==-1) { 
+            node.way_=+2;	  // Swap direction
+            branchingTree.push_back(node);
+          } else if (funnyBranching) {
+	    // put back on tree anyway
+            branchingTree.push_back(node);
+	  }
+        } else {
+          setColLower(which[node.variable_],ceil(node.value_));
+          // now push back node if more to come
+          if (node.way_==1) { 
+            node.way_=-2;	  // Swap direction
+            branchingTree.push_back(node);
+          } else if (funnyBranching) {
+	    // put back on tree anyway
+            branchingTree.push_back(node);
+          }
+        }
+
+        // solve
+        resolve();
+        CoinWarmStart * ws = getWarmStart();
+        const CoinWarmStartBasis* wsb =
+          dynamic_cast<const CoinWarmStartBasis*>(ws);
+        assert (wsb!=NULL); // make sure not volume
+        numberIterations += getIterationCount();
+        // fix on reduced costs
+        int nFixed0=0,nFixed1=0;
+        double cutoff;
+        getDblParam(OsiDualObjectiveLimit,cutoff);
+        double gap=(cutoff-modelPtr_->objectiveValue())*direction+1.0e-4;
+        if (gap<1.0e10&&isProvenOptimal()&&!isDualObjectiveLimitReached()) {
+          const double * dj = getReducedCost();
+          const double * lower = getColLower();
+          const double * upper = getColUpper();
+          for (i=0;i<numberIntegers;i++) {
+            iColumn=which[i];
+            if (upper[iColumn]>lower[iColumn]) {
+              double djValue = dj[iColumn]*direction;
+              if (wsb->getStructStatus(iColumn)==CoinWarmStartBasis::atLowerBound&&
+                  djValue>gap) {
+                nFixed0++;
+                setColUpper(iColumn,lower[iColumn]);
+              } else if (wsb->getStructStatus(iColumn)==CoinWarmStartBasis::atUpperBound&&
+                         -djValue>gap) {
+                nFixed1++;
+                setColLower(iColumn,upper[iColumn]);
+              }
+            }
+          }
+          //if (nFixed0+nFixed1)
+          //printf("%d fixed to lower, %d fixed to upper\n",nFixed0,nFixed1);
+        }
+        if (!isIterationLimitReached()) {
+	  if (isProvenOptimal()&&!isDualObjectiveLimitReached()) {
+#if FUNNY_BRANCHING
+	    // See if branched variable off bounds
+	    const double * dj = getReducedCost();
+	    const double * lower = getColLower();
+	    const double * upper = getColUpper();
+	    const double * solution = getColSolution();
+	    // Better to use "natural" value - need flag to say fixed
+	    for (i=0;i<numberIntegers;i++) {
+	      iColumn=which[i];
+	      relaxedLower[i]=originalLower[i];
+	      relaxedUpper[i]=originalUpper[i];
+	      double djValue = dj[iColumn]*direction;
+	      if (djValue>1.0e-6) {
+		// wants to go down
+		if (lower[iColumn]>originalLower[i]) {
+		  // Lower bound active
+		  relaxedLower[i]=static_cast<int> (lower[iColumn]);
+		}
+		if (upper[iColumn]<originalUpper[i]) {
+		  // Upper bound NOT active
+		}
+	      } else if (djValue<-1.0e-6) {
+		// wants to go up
+		if (lower[iColumn]>originalLower[i]) {
+		  // Lower bound NOT active
+		}
+		if (upper[iColumn]<originalUpper[i]) {
+		  // Upper bound active
+		  relaxedUpper[i]=static_cast<int> (upper[iColumn]);
+		}
+	      }
+	    }
+	    // See if can do anything
+	    {
+	      /*
+		If kNode is on second branch then
+		a) If other feasible could free up as well
+		b) If other infeasible could do something clever.
+		For now - we have to give up
+	      */
+	      int jNode=branchingTree.nodes_[kNode].parent_;
+	      bool canDelete = (branchingTree.nodes_[kNode].descendants_<2);
+	      while (jNode>=0) {
+		OsiNodeSimple & node = branchingTree.nodes_[jNode];
+		int next = node.parent_;
+		if (node.descendants_<2) {
+		  int variable = node.variable_;
+		  iColumn=which[variable];
+		  double value = node.value_;
+		  double djValue = dj[iColumn]*direction;
+		  assert (node.way_==2||node.way_==-2);
+		  // we don't know which branch it was - look at current bounds
+		  if (upper[iColumn]<value&&node.lower_[variable]<upper[iColumn]) {
+		    // must have been down branch
+		    if (djValue>1.0e-3||solution[iColumn]<upper[iColumn]-1.0e-5) {
+		      if (canDelete) {
+			nRedundantDown++;
+#if 1
+			printf("%d redundant branch down with value %g current upper %g solution %g dj %g\n",
+			       variable,node.value_,upper[iColumn],solution[iColumn],djValue);
+#endif
+			node.descendants_=2; // ignore
+			branchingTree.sizeDeferred_++;
+			int newUpper = originalUpper[variable];
+			if (next>=0) {
+			  OsiNodeSimple & node2 = branchingTree.nodes_[next];
+			  newUpper = node2.upper_[variable];
+			}
+			if (branchingTree.nodes_[jNode].parent_!=next)
+			  assert (newUpper>upper[iColumn]);
+			setColUpper(iColumn,newUpper);
+			int kNode2=next;
+			int jNode2=branchingTree.nodes_[kNode].parent_;
+			assert (newUpper>branchingTree.nodes_[kNode].upper_[variable]);
+			branchingTree.nodes_[kNode].upper_[variable]= newUpper;
+			while (jNode2!=kNode2) {
+			  OsiNodeSimple & node2 = branchingTree.nodes_[jNode2];
+			  int next = node2.parent_;
+			  if (next!=kNode2)
+			    assert (newUpper>node2.upper_[variable]);
+			  node2.upper_[variable]= newUpper;
+			  jNode2=next;
+			}
+		      } else {
+			// can't delete but can add other way to jNode
+			nRedundantDown2++;
+			OsiNodeSimple & node2 = branchingTree.nodes_[kNode];
+			assert (node2.way_==2||node2.way_==-2);
+			double value2 = node2.value_;
+			int variable2 = node2.variable_;
+			int iColumn2 = which[variable2];
+			if (variable != variable2) {
+			  if (node2.way_==2&&upper[iColumn2]<value2) {
+			    // must have been down branch which was done - carry over
+			    int newUpper = static_cast<int> (floor(value2));
+			    assert (newUpper<node.upper_[variable2]);
+			    node.upper_[variable2]=newUpper;
+			  } else if (node2.way_==-2&&lower[iColumn2]>value2) {
+			    // must have been up branch which was done - carry over
+			    int newLower = static_cast<int> (ceil(value2));
+			    assert (newLower>node.lower_[variable2]);
+			    node.lower_[variable2]=newLower;
+			  }
+			  if (node.lower_[variable2]>node.upper_[variable2]) {
+			    // infeasible
+			    node.descendants_=2; // ignore
+			    branchingTree.sizeDeferred_++;
+			  }
+			}
+		      }
+		      break;
+		    } 
+		    // we don't know which branch it was - look at current bounds
+		  } else if (lower[iColumn]>value&&node.upper_[variable]>lower[iColumn]) {
+		    // must have been up branch
+		    if (djValue<-1.0e-3||solution[iColumn]>lower[iColumn]+1.0e-5) {
+		      if (canDelete) {
+			nRedundantUp++;
+#if 1
+			printf("%d redundant branch up with value %g current lower %g solution %g dj %g\n",
+			       variable,node.value_,lower[iColumn],solution[iColumn],djValue);
+#endif
+			node.descendants_=2; // ignore
+			branchingTree.sizeDeferred_++;
+			int newLower = originalLower[variable];
+			if (next>=0) {
+			  OsiNodeSimple & node2 = branchingTree.nodes_[next];
+			  newLower = node2.lower_[variable];
+			}
+			if (branchingTree.nodes_[jNode].parent_!=next)
+			  assert (newLower<lower[iColumn]);
+			setColLower(iColumn,newLower);
+			int kNode2=next;
+			int jNode2=branchingTree.nodes_[kNode].parent_;
+			assert (newLower<branchingTree.nodes_[kNode].lower_[variable]);
+			branchingTree.nodes_[kNode].lower_[variable]= newLower;
+			while (jNode2!=kNode2) {
+			  OsiNodeSimple & node2 = branchingTree.nodes_[jNode2];
+			  int next = node2.parent_;
+			  if (next!=kNode2)
+			    assert (newLower<node2.lower_[variable]);
+			  node2.lower_[variable]=newLower;
+			  jNode2=next;
+			}
+		      } else {
+			// can't delete but can add other way to jNode
+			nRedundantUp2++;
+			OsiNodeSimple & node2 = branchingTree.nodes_[kNode];
+			assert (node2.way_==2||node2.way_==-2);
+			double value2 = node2.value_;
+			int variable2 = node2.variable_;
+			int iColumn2 = which[variable2];
+			if (variable != variable2) {
+			  if (node2.way_==2&&upper[iColumn2]<value2) {
+			    // must have been down branch which was done - carry over
+			    int newUpper = static_cast<int> (floor(value2));
+			    assert (newUpper<node.upper_[variable2]);
+			    node.upper_[variable2]=newUpper;
+			  } else if (node2.way_==-2&&lower[iColumn2]>value2) {
+			    // must have been up branch which was done - carry over
+			    int newLower = static_cast<int> (ceil(value2));
+			    assert (newLower>node.lower_[variable2]);
+			    node.lower_[variable2]=newLower;
+			  }
+			  if (node.lower_[variable2]>node.upper_[variable2]) {
+			    // infeasible
+			    node.descendants_=2; // ignore
+			    branchingTree.sizeDeferred_++;
+			  }
+			}
+		      }
+		      break;
+		    } 
+		  }
+		} else {
+		  break;
+		}
+		jNode=next;
+	      }
+	    }
+	    // solve
+	    //resolve();
+	    //assert(!getIterationCount());
+	    if ((numberNodes%1000)==0) 
+	      printf("%d nodes, redundant down %d (%d) up %d (%d) tree size %d\n",
+		     numberNodes,nRedundantDown,nRedundantDown2,nRedundantUp,nRedundantUp2,branchingTree.size());
+#else
+	    if ((numberNodes%1000)==0) 
+	      printf("%d nodes, tree size %d\n",
+		     numberNodes,branchingTree.size());
+#endif
+	    if (CoinCpuTime()-time1>3600.0) {
+	      printf("stopping after 3600 seconds\n");
+	      exit(77);
+	    }
+	    OsiNodeSimple newNode(*this,numberIntegers,which,ws);
+	    // something extra may have been fixed by strong branching
+	    // if so go round again
+	    while (newNode.variable_==numberIntegers) {
+	      resolve();
+	      newNode = OsiNodeSimple(*this,numberIntegers,which,getWarmStart());
+	    }
+	    if (newNode.objectiveValue_<1.0e100) {
+	      if (newNode.variable_>=0) 
+		assert (fabs(newNode.value_-floor(newNode.value_+0.5))>1.0e-6);
+	      newNode.parent_ = kNode;
+	      // push on stack
+	      branchingTree.push_back(newNode);
+	    }
+	  } else {
+	    // infeasible
+	    delete ws;
+ 	  }
+        } else {
+          // maximum iterations - exit
+          std::cout<<"Exiting on maximum iterations"
+                   <<std::endl;
+	  break;
+        }
+      } else {
+        // integer solution - save
+        bestNode = node;
+        // set cutoff (hard coded tolerance)
+        setDblParam(OsiDualObjectiveLimit,(bestNode.objectiveValue_-1.0e-5)*direction);
+        std::cout<<"Integer solution of "
+                 <<bestNode.objectiveValue_
+                 <<" found after "<<numberIterations
+                 <<" iterations and "<<numberNodes<<" nodes"
+                 <<std::endl;
+      }
+    }
+    ////// End main while of branch and bound
+    std::cout<<"Search took "
+             <<numberIterations
+             <<" iterations and "<<numberNodes<<" nodes"
+             <<std::endl;
+    if (bestNode.numberIntegers_) {
+      // we have a solution restore
+      // do bounds
+      for (i=0;i<numberIntegers;i++) {
+        iColumn=which[i];
+        setColBounds( iColumn,bestNode.lower_[i],bestNode.upper_[i]);
+      }
+      // move basis
+      setWarmStart(bestNode.basis_);
+      // set cutoff so will be good (hard coded tolerance)
+      setDblParam(OsiDualObjectiveLimit,(bestNode.objectiveValue_+1.0e-5)*direction);
+      resolve();
+    } else {
+      modelPtr_->setProblemStatus(1);
+    }
+    delete [] which;
+    delete [] originalLower;
+    delete [] originalUpper;
+    delete [] relaxedLower;
+    delete [] relaxedUpper;
+  } else {
+    if(messageHandler())
+      *messageHandler() <<"The LP relaxation is infeasible" <<CoinMessageEol;
+    modelPtr_->setProblemStatus(1);
+    //throw CoinError("The LP relaxation is infeasible or too expensive",
+    //"branchAndBound", "OsiClpSolverInterface");
+  }
+}
+void 
+OsiClpSolverInterface::setSpecialOptions(unsigned int value)
+{ 
+  if ((value&131072)!=0&&(specialOptions_&131072)==0) {
+    // Try and keep scaling factors around
+    delete baseModel_;
+    baseModel_ = new ClpSimplex(*modelPtr_);
+    ClpPackedMatrix * clpMatrix = 
+      dynamic_cast< ClpPackedMatrix*>(baseModel_->matrix_);
+    if (!clpMatrix||clpMatrix->scale(baseModel_)) {
+      // switch off again
+      delete baseModel_;
+      baseModel_=NULL;
+      value &= ~131072;
+    } else {
+      // Off current scaling
+      modelPtr_->setRowScale(NULL);
+      modelPtr_->setColumnScale(NULL);
+      lastNumberRows_=baseModel_->numberRows();
+      rowScale_ = CoinDoubleArrayWithLength(2*lastNumberRows_,0);
+      int i;
+      double * scale;
+      double * inverseScale;
+      scale = rowScale_.array();
+      inverseScale = scale + lastNumberRows_;
+      const double * rowScale = baseModel_->rowScale_;
+      for (i=0;i<lastNumberRows_;i++) {
+	scale[i] = rowScale[i];
+	inverseScale[i] = 1.0/scale[i];
+      }
+      int numberColumns = baseModel_->numberColumns();
+      columnScale_ = CoinDoubleArrayWithLength(2*numberColumns,0);
+      scale = columnScale_.array();
+      inverseScale = scale + numberColumns;
+      const double * columnScale = baseModel_->columnScale_;
+      for (i=0;i<numberColumns;i++) {
+	scale[i] = columnScale[i];
+	inverseScale[i] = 1.0/scale[i];
+      }
+    }
+  }
+  specialOptions_=value;
+  if ((specialOptions_&0x80000000)!=0) {
+    // unset top bit if anything set
+    if (specialOptions_!=0x80000000) 
+      specialOptions_ &= 0x7fffffff;
+  }
+}
+void 
+OsiClpSolverInterface::setSpecialOptionsMutable(unsigned int value) const
+{ 
+  specialOptions_=value;
+  if ((specialOptions_&0x80000000)!=0) {
+    // unset top bit if anything set
+    if (specialOptions_!=0x80000000) 
+      specialOptions_ &= 0x7fffffff;
+  }
+}
+/*  If solver wants it can save a copy of "base" (continuous) model here
+ */
+void 
+OsiClpSolverInterface::saveBaseModel() 
+{
+  delete continuousModel_;
+  continuousModel_ = new ClpSimplex(*modelPtr_);
+  delete matrixByRowAtContinuous_;
+  matrixByRowAtContinuous_ = new CoinPackedMatrix();
+  matrixByRowAtContinuous_->setExtraGap(0.0);
+  matrixByRowAtContinuous_->setExtraMajor(0.0);
+  matrixByRowAtContinuous_->reverseOrderedCopyOf(*modelPtr_->matrix());
+  //continuousModel_->createRim(63);
+}
+// Pass in disaster handler
+void 
+OsiClpSolverInterface::passInDisasterHandler(OsiClpDisasterHandler * handler)
+{
+  delete disasterHandler_;
+  if ( handler  ) 
+    disasterHandler_ = dynamic_cast<OsiClpDisasterHandler *>(handler->clone());
+  else
+    disasterHandler_ = NULL;
+}
+/*  Strip off rows to get to this number of rows.
+    If solver wants it can restore a copy of "base" (continuous) model here
+*/
+void 
+OsiClpSolverInterface::restoreBaseModel(int numberRows)
+{
+  if (continuousModel_&&continuousModel_->numberRows()==numberRows) {
+    modelPtr_->numberRows_ = numberRows;
+    //ClpDisjointCopyN ( continuousModel_->columnLower_, modelPtr_->numberColumns_,modelPtr_->columnLower_ );
+    //ClpDisjointCopyN ( continuousModel_->columnUpper_, modelPtr_->numberColumns_,modelPtr_->columnUpper_ );
+    // Could keep copy of scaledMatrix_ around??
+    delete modelPtr_->scaledMatrix_;
+    modelPtr_->scaledMatrix_=NULL;
+    if (continuousModel_->rowCopy_) {
+      modelPtr_->copy(continuousModel_->rowCopy_,modelPtr_->rowCopy_);
+    } else {
+      delete modelPtr_->rowCopy_;
+      modelPtr_->rowCopy_=NULL;
+    }
+    modelPtr_->copy(continuousModel_->matrix_,modelPtr_->matrix_);
+    if (matrixByRowAtContinuous_) {
+      if (matrixByRow_) {
+	*matrixByRow_ = *matrixByRowAtContinuous_;
+      } else {
+	//printf("BBBB could new\n");
+	// matrixByRow_ = new CoinPackedMatrix(*matrixByRowAtContinuous_);
+      }
+    } else {
+      delete matrixByRow_;
+      matrixByRow_=NULL;
+    }
+  } else {
+    OsiSolverInterface::restoreBaseModel(numberRows);
+  }
+}
+// Tighten bounds - lightweight
+int 
+OsiClpSolverInterface::tightenBounds(int lightweight)
+{
+  if (!integerInformation_||(specialOptions_&262144)!=0)
+    return 0; // no integers
+  //CoinPackedMatrix matrixByRow(*getMatrixByRow());
+  int numberRows = getNumRows();
+  int numberColumns = getNumCols();
+
+  int iRow,iColumn;
+
+  // Row copy
+  //const double * elementByRow = matrixByRow.getElements();
+  //const int * column = matrixByRow.getIndices();
+  //const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
+  //const int * rowLength = matrixByRow.getVectorLengths();
+
+  const double * columnUpper = getColUpper();
+  const double * columnLower = getColLower();
+  const double * rowUpper = getRowUpper();
+  const double * rowLower = getRowLower();
+
+  // Column copy of matrix
+  const double * element = getMatrixByCol()->getElements();
+  const int * row = getMatrixByCol()->getIndices();
+  const CoinBigIndex * columnStart = getMatrixByCol()->getVectorStarts();
+  const int * columnLength = getMatrixByCol()->getVectorLengths();
+  const double *objective = getObjCoefficients() ;
+  double direction = getObjSense();
+  double * down = new double [numberRows];
+  if (lightweight>0) {
+    int * first = new int[numberRows];
+    CoinZeroN(first,numberRows);
+    CoinZeroN(down,numberRows);
+    double * sum = new double [numberRows];
+    CoinZeroN(sum,numberRows);
+    int numberTightened=0;
+    for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+      CoinBigIndex start = columnStart[iColumn];
+      CoinBigIndex end = start + columnLength[iColumn];
+      double lower = columnLower[iColumn];
+      double upper = columnUpper[iColumn];
+      if (lower==upper) {
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  double value = element[j];
+	  down[iRow] += value*lower;
+	  sum[iRow] += fabs(value*lower);
+	}
+      } else {
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  int n=first[iRow];
+	  if (n==0&&element[j])
+	    first[iRow]=-iColumn-1;
+	  else if (n<0) 
+	    first[iRow]=2;
+	}
+      }
+    }
+    double tolerance = 1.0e-6;
+    const char * integerInformation = modelPtr_->integerType_;
+    for (int iRow=0;iRow<numberRows;iRow++) {
+      int iColumn = first[iRow];
+      if (iColumn<0) {
+	iColumn = -iColumn-1;
+	if ((integerInformation&&integerInformation[iColumn])||lightweight==2) {
+	  double lowerRow = rowLower[iRow];
+	  if (lowerRow>-1.0e20)
+	    lowerRow -= down[iRow];
+	  double upperRow = rowUpper[iRow];
+	  if (upperRow<1.0e20)
+	    upperRow -= down[iRow];
+	  double lower = columnLower[iColumn];
+	  double upper = columnUpper[iColumn];
+	  double value=0.0;
+	  for (CoinBigIndex j = columnStart[iColumn];
+	       j<columnStart[iColumn]+columnLength[iColumn];j++) {
+	    if (iRow==row[j]) {
+	      value=element[j];
+	      break;
+	    }
+	  }
+	  assert (value);
+	  // convert rowLower and Upper to implied bounds on column
+	  double newLower=-COIN_DBL_MAX;
+	  double newUpper=COIN_DBL_MAX;
+	  if (value>0.0) {
+	    if (lowerRow>-1.0e20)
+	      newLower = lowerRow/value;
+	    if (upperRow<1.0e20)
+	      newUpper = upperRow/value;
+	  } else {
+	    if (upperRow<1.0e20)
+	      newLower = upperRow/value;
+	    if (lowerRow>-1.0e20)
+	      newUpper = lowerRow/value;
+	  }
+	  double tolerance2 = 1.0e-6+1.0e-8*sum[iRow];
+	  if (integerInformation&&integerInformation[iColumn]) {
+	    if (newLower-floor(newLower)<tolerance2) 
+	      newLower=floor(newLower);
+	    else
+	      newLower=ceil(newLower);
+	    if (ceil(newUpper)-newUpper<tolerance2) 
+	      newUpper=ceil(newUpper);
+	    else
+	      newUpper=floor(newUpper);
+	  }
+	  if (newLower>lower+10.0*tolerance2||
+	      newUpper<upper-10.0*tolerance2) {
+	    numberTightened++;
+	    newLower = CoinMax(lower,newLower);
+	    newUpper = CoinMin(upper,newUpper);
+	    if (newLower>newUpper+tolerance) {
+	      //printf("XXYY inf on bound\n");
+	      numberTightened=-1;
+	      break;
+	    }
+	    setColLower(iColumn,newLower);
+	    setColUpper(iColumn,CoinMax(newLower,newUpper));
+	  }
+	}
+      }
+    }
+    delete [] first;
+    delete [] down;
+    delete [] sum;
+    return numberTightened;
+  }
+  double * up = new double [numberRows];
+  double * sum = new double [numberRows];
+  int * type = new int [numberRows];
+  CoinZeroN(down,numberRows);
+  CoinZeroN(up,numberRows);
+  CoinZeroN(sum,numberRows);
+  CoinZeroN(type,numberRows);
+  double infinity = getInfinity();
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    CoinBigIndex start = columnStart[iColumn];
+    CoinBigIndex end = start + columnLength[iColumn];
+    double lower = columnLower[iColumn];
+    double upper = columnUpper[iColumn];
+    if (lower==upper) {
+      for (CoinBigIndex j=start;j<end;j++) {
+	int iRow = row[j];
+	double value = element[j];
+	sum[iRow]+=2.0*fabs(value*lower);
+	if ((type[iRow]&1)==0)
+	  down[iRow] += value*lower;
+	if ((type[iRow]&2)==0)
+	  up[iRow] += value*lower;
+      }
+    } else {
+      for (CoinBigIndex j=start;j<end;j++) {
+	int iRow = row[j];
+	double value = element[j];
+	if (value>0.0) {
+	  if ((type[iRow]&1)==0) {
+	    if (lower!=-infinity) {
+	      down[iRow] += value*lower;
+	      sum[iRow]+=fabs(value*lower);
+	    } else {
+	      type[iRow] |= 1;
+	    }
+	  }
+	  if ((type[iRow]&2)==0) {
+	    if (upper!=infinity) {
+	      up[iRow] += value*upper;
+	      sum[iRow]+=fabs(value*upper);
+	    } else {
+	      type[iRow] |= 2;
+	    }
+	  }
+	} else {
+	  if ((type[iRow]&1)==0) {
+	    if (upper!=infinity) {
+	      down[iRow] += value*upper;
+	      sum[iRow]+=fabs(value*upper);
+	    } else {
+	      type[iRow] |= 1;
+	    }
+	  }
+	  if ((type[iRow]&2)==0) {
+	    if (lower!=-infinity) {
+	      up[iRow] += value*lower;
+	      sum[iRow]+=fabs(value*lower);
+	    } else {
+	      type[iRow] |= 2;
+	    }
+	  }
+	}
+      }
+    }
+  }
+  int nTightened=0;
+  double tolerance = 1.0e-6;
+  for (iRow=0;iRow<numberRows;iRow++) {
+    if ((type[iRow]&1)!=0)
+      down[iRow]=-infinity;
+    if (down[iRow]>rowUpper[iRow]) {
+      if (down[iRow]>rowUpper[iRow]+tolerance+1.0e-8*sum[iRow]) {
+	// infeasible
+#ifdef COIN_DEVELOP
+	printf("infeasible on row %d\n",iRow);
+#endif
+	nTightened=-1;
+	break;
+      } else {
+	down[iRow]=rowUpper[iRow];
+      }
+    }
+    if ((type[iRow]&2)!=0)
+      up[iRow]=infinity;
+    if (up[iRow]<rowLower[iRow]) {
+      if (up[iRow]<rowLower[iRow]-tolerance-1.0e-8*sum[iRow]) {
+	// infeasible
+#ifdef COIN_DEVELOP
+	printf("infeasible on row %d\n",iRow);
+#endif
+	nTightened=-1;
+	break;
+      } else {
+	up[iRow]=rowLower[iRow];
+      }
+    }
+  }
+  if (nTightened)
+    numberColumns=0; // so will skip
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    double lower = columnLower[iColumn];
+    double upper = columnUpper[iColumn];
+    double gap = upper-lower;
+    if (!gap)
+      continue;
+    int canGo=0;
+    CoinBigIndex start = columnStart[iColumn];
+    CoinBigIndex end = start + columnLength[iColumn];
+    if (lower<-1.0e8&&upper>1.0e8)
+      continue; // Could do severe damage to accuracy
+    if (integerInformation_[iColumn]) {
+      if (lower!=floor(lower+0.5)) {
+#ifdef COIN_DEVELOP
+	printf("increasing lower bound on %d from %g to %g\n",iColumn,
+	       lower,ceil(lower));
+#endif
+	lower=ceil(lower);
+	gap=upper-lower;
+	setColLower(iColumn,lower);
+      }
+      if (upper!=floor(upper+0.5)) {
+#ifdef COIN_DEVELOP
+	printf("decreasing upper bound on %d from %g to %g\n",iColumn,
+	       upper,floor(upper));
+#endif
+	upper=floor(upper);
+	gap=upper-lower;
+	setColUpper(iColumn,upper);
+      }
+      double newLower=lower;
+      double newUpper=upper;
+      for (CoinBigIndex j=start;j<end;j++) {
+	int iRow = row[j];
+	double value = element[j];
+	if (value>0.0) {
+	  if ((type[iRow]&1)==0) {
+	    // has to be at most something
+	    if (down[iRow] + value*gap > rowUpper[iRow]+tolerance) {
+	      double newGap = (rowUpper[iRow]-down[iRow])/value;
+	      // adjust
+	      newGap += 1.0e-10*sum[iRow];
+	      newGap = floor(newGap);
+	      if (lower+newGap<newUpper)
+		newUpper=lower+newGap;
+	    }
+	  }
+	  if (down[iRow]<rowLower[iRow])
+	    canGo |=1; // can't go down without affecting result
+	  if ((type[iRow]&2)==0) {
+	    // has to be at least something
+	    if (up[iRow] - value*gap < rowLower[iRow]-tolerance) {
+	      double newGap = (up[iRow]-rowLower[iRow])/value;
+	      // adjust
+	      newGap += 1.0e-10*sum[iRow];
+	      newGap = floor(newGap);
+	      if (upper-newGap>newLower)
+		newLower=upper-newGap;
+	    }
+	  }
+	  if (up[iRow]>rowUpper[iRow])
+	    canGo |=2; // can't go up without affecting result
+	} else {
+	  if ((type[iRow]&1)==0) {
+	    // has to be at least something
+	    if (down[iRow] - value*gap > rowUpper[iRow]+tolerance) {
+	      double newGap = -(rowUpper[iRow]-down[iRow])/value;
+	      // adjust
+	      newGap += 1.0e-10*sum[iRow];
+	      newGap = floor(newGap);
+	      if (upper-newGap>newLower)
+		newLower=upper-newGap;
+	    }
+	  }
+	  if (up[iRow]>rowUpper[iRow])
+	    canGo |=1; // can't go down without affecting result
+	  if ((type[iRow]&2)==0) {
+	    // has to be at most something
+	    if (up[iRow] + value*gap < rowLower[iRow]-tolerance) {
+	      double newGap = -(up[iRow]-rowLower[iRow])/value;
+	      // adjust
+	      newGap += 1.0e-10*sum[iRow];
+	      newGap = floor(newGap);
+	      if (lower+newGap<newUpper)
+		newUpper=lower+newGap;
+	    }
+	  }
+	  if (down[iRow]<rowLower[iRow])
+	    canGo |=2; // can't go up without affecting result
+	}
+      }
+      if (newUpper<upper||newLower>lower) {
+	nTightened++;
+	if (newLower>newUpper) {
+	  // infeasible
+#if COIN_DEVELOP>1
+	  printf("infeasible on column %d\n",iColumn);
+#endif
+	  nTightened=-1;
+	  break;
+	} else {
+	  setColLower(iColumn,newLower);
+	  setColUpper(iColumn,newUpper);
+	}
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  double value = element[j];
+	  if (value>0.0) {
+	    if ((type[iRow]&1)==0) {
+	      down[iRow] += value*(newLower-lower);
+	    }
+	    if ((type[iRow]&2)==0) {
+	      up[iRow] += value*(newUpper-upper);
+	    }
+	  } else {
+	    if ((type[iRow]&1)==0) {
+	      down[iRow] += value*(newUpper-upper);
+	    }
+	    if ((type[iRow]&2)==0) {
+	      up[iRow] += value*(newLower-lower);
+	    }
+	  }
+	}
+      } else {
+	if (canGo!=3) {
+	  double objValue = direction*objective[iColumn];
+	  if (objValue>=0.0&&(canGo&1)==0) {
+#if COIN_DEVELOP>2
+	    printf("dual fix down on column %d\n",iColumn);
+#endif
+	    // Only if won't cause numerical problems
+	    if (lower>-1.0e10) {
+	      nTightened++;
+	      setColUpper(iColumn,lower);
+	    }
+	  } else if (objValue<=0.0&&(canGo&2)==0) {
+#if COIN_DEVELOP>2
+	    printf("dual fix up on column %d\n",iColumn);
+#endif
+	    // Only if won't cause numerical problems
+	    if (upper<1.0e10) {
+	      nTightened++;
+	      setColLower(iColumn,upper);
+	    }
+	  }
+	}	    
+      }
+    } else {
+      // just do dual tests
+      for (CoinBigIndex j=start;j<end;j++) {
+	int iRow = row[j];
+	double value = element[j];
+	if (value>0.0) {
+	  if (down[iRow]<rowLower[iRow])
+	    canGo |=1; // can't go down without affecting result
+	  if (up[iRow]>rowUpper[iRow])
+	    canGo |=2; // can't go up without affecting result
+	} else {
+	  if (up[iRow]>rowUpper[iRow])
+	    canGo |=1; // can't go down without affecting result
+	  if (down[iRow]<rowLower[iRow])
+	    canGo |=2; // can't go up without affecting result
+	}
+      }
+      if (canGo!=3) {
+	double objValue = direction*objective[iColumn];
+	if (objValue>=0.0&&(canGo&1)==0) {
+#if COIN_DEVELOP>2
+	  printf("dual fix down on continuous column %d lower %g\n",
+		 iColumn,lower);
+#endif
+	  // Only if won't cause numerical problems
+	  if (lower>-1.0e10) {
+	    nTightened++;
+	    setColUpper(iColumn,lower);
+	  }
+	} else if (objValue<=0.0&&(canGo&2)==0) {
+#if COIN_DEVELOP>2
+	  printf("dual fix up on continuous column %d upper %g\n",
+		 iColumn,upper);
+#endif
+	  // Only if won't cause numerical problems
+	  if (upper<1.0e10) {
+	    nTightened++;
+	    setColLower(iColumn,upper);
+	  }
+	}
+      }
+    }
+  }
+  if (lightweight<0) {
+    // get max down and up again
+    CoinZeroN(down,numberRows);
+    CoinZeroN(up,numberRows);
+    CoinZeroN(type,numberRows);
+    int * seqDown = new int [2*numberRows];
+    int * seqUp=seqDown+numberRows;
+    for (int i=0;i<numberRows;i++) {
+      seqDown[i]=-1;
+      seqUp[i]=-1;
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      CoinBigIndex start = columnStart[iColumn];
+      CoinBigIndex end = start + columnLength[iColumn];
+      double lower = columnLower[iColumn];
+      double upper = columnUpper[iColumn];
+      if (lower==upper) {
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  double value = element[j];
+	  if ((type[iRow]&1)==0)
+	    down[iRow] += value*lower;
+	  if ((type[iRow]&2)==0)
+	    up[iRow] += value*lower;
+	}
+      } else {
+	for (CoinBigIndex j=start;j<end;j++) {
+	  int iRow = row[j];
+	  double value = element[j];
+	  if (value>0.0) {
+	    if ((type[iRow]&1)==0) {
+	      if (lower>-1.0e8) {
+		down[iRow] += value*lower;
+	      } else if (seqDown[iRow]<0) {
+		seqDown[iRow]=iColumn;
+	      } else {
+		type[iRow] |= 1;
+	      }
+	    }
+	    if ((type[iRow]&2)==0) {
+	      if (upper<1.0e8) {
+		up[iRow] += value*upper;
+		sum[iRow]+=fabs(value*upper);
+	      } else if (seqUp[iRow]<0) {
+		seqUp[iRow]=iColumn;
+	      } else {
+		type[iRow] |= 2;
+	      }
+	    }
+	  } else {
+	    if ((type[iRow]&1)==0) {
+	      if (upper<1.0e8) {
+		down[iRow] += value*upper;
+		sum[iRow]+=fabs(value*upper);
+	      } else if (seqDown[iRow]<0) {
+		seqDown[iRow]=iColumn;
+	      } else {
+		type[iRow] |= 1;
+	      }
+	    }
+	    if ((type[iRow]&2)==0) {
+	      if (lower>-1.0e8) {
+		up[iRow] += value*lower;
+		sum[iRow]+=fabs(value*lower);
+	      } else if (seqUp[iRow]<0) {
+		seqUp[iRow]=iColumn;
+	      } else {
+		type[iRow] |= 2;
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    for (iColumn=0;iColumn<numberColumns;iColumn++) {
+      double lower = columnLower[iColumn];
+      double upper = columnUpper[iColumn];
+      double gap = upper-lower;
+      if (!gap)
+	continue;
+      CoinBigIndex start = columnStart[iColumn];
+      CoinBigIndex end = start + columnLength[iColumn];
+      if (lower<-1.0e8&&upper>1.0e8)
+	continue; // Could do severe damage to accuracy
+      double newLower=upper;
+      double newUpper=lower;
+      bool badUpper=false;
+      bool badLower=false;
+      double objValue = objective[iColumn]*direction;
+      for (CoinBigIndex j=start;j<end;j++) {
+	int iRow = row[j];
+	double value = element[j];
+	if (value>0.0) {
+	  if (rowLower[iRow]>-COIN_DBL_MAX) {
+	    if (!badUpper&&(type[iRow]&1)==0&&
+		(seqDown[iRow]<0||seqDown[iRow]==iColumn)) {
+	      double s=down[iRow];
+	      if (seqDown[iRow]!=iColumn)
+		s -= lower*value;
+	      if (s+newUpper*value<rowLower[iRow]) {
+		newUpper = CoinMax(newUpper,(rowLower[iRow]-s)/value);
+	      }
+	    } else {
+	      badUpper=true;
+	    }
+	  }
+	  if (rowUpper[iRow]<COIN_DBL_MAX) {
+	    if (!badLower&&(type[iRow]&2)==0&&
+		(seqUp[iRow]<0||seqUp[iRow]==iColumn)) {
+	      double s=up[iRow];
+	      if (seqUp[iRow]!=iColumn)
+		s -= upper*value;
+	      if (s+newLower*value>rowUpper[iRow]) {
+		newLower = CoinMin(newLower,(rowUpper[iRow]-s)/value);
+	      }
+	    } else {
+	      badLower=true;
+	    }
+	  }
+	} else {
+	  if (rowUpper[iRow]<COIN_DBL_MAX) {
+	    if (!badUpper&&(type[iRow]&2)==0&&
+		(seqUp[iRow]<0||seqUp[iRow]==iColumn)) {
+	      double s=up[iRow];
+	      if (seqUp[iRow]!=iColumn)
+		s -= lower*value;
+	      if (s+newUpper*value>rowUpper[iRow]) {
+		newUpper = CoinMax(newUpper,(rowUpper[iRow]-s)/value);
+	      }
+	    } else {
+	      badUpper=true;
+	    }
+	  }
+	  if (rowLower[iRow]>-COIN_DBL_MAX) {
+	    if (!badLower&&(type[iRow]&1)==0&&
+		(seqDown[iRow]<0||seqDown[iRow]==iColumn)) {
+	      double s=down[iRow];
+	      if (seqDown[iRow]!=iColumn)
+		s -= lower*value;
+	      if (s+newLower*value<rowLower[iRow]) {
+		newLower = CoinMin(newLower,(rowLower[iRow]-s)/value);
+	      }
+	    } else {
+	      badLower=true;
+	    }
+	  }
+	}
+      }
+      if (badLower||objValue>0.0)
+	newLower=lower;
+      if (badUpper||objValue<0.0)
+	newUpper=upper;
+      if (newUpper<upper||newLower>lower) {
+	nTightened++;
+	if (newLower>newUpper) {
+	  // infeasible
+#if COIN_DEVELOP>0
+	  printf("infeasible on column %d\n",iColumn);
+#endif
+	  nTightened=-1;
+	  break;
+	} else {
+	  newLower=CoinMax(newLower,lower);
+	  newUpper=CoinMin(newUpper,upper);
+	  if (integerInformation_[iColumn]) {
+	    newLower=ceil(newLower-1.0e-5);
+	    newUpper=floor(newUpper+1.0e-5);
+	  }
+	  setColLower(iColumn,newLower);
+	  setColUpper(iColumn,newUpper);
+	}
+      }
+    }
+    delete [] seqDown;
+  }
+  delete [] type;
+  delete [] down;
+  delete [] up;
+  delete [] sum;
+  return nTightened;
+}
+// Return number of entries in L part of current factorization
+CoinBigIndex 
+OsiClpSolverInterface::getSizeL() const
+{
+  return modelPtr_->factorization_->numberElementsL();
+}
+// Return number of entries in U part of current factorization
+CoinBigIndex 
+OsiClpSolverInterface::getSizeU() const
+{
+  return modelPtr_->factorization_->numberElementsU();
+}
+/* Add a named row (constraint) to the problem.
+ */
+void 
+OsiClpSolverInterface::addRow(const CoinPackedVectorBase& vec,
+       const char rowsen, const double rowrhs,   
+       const double rowrng, std::string name) 
+{
+  int ndx = getNumRows() ;
+  addRow(vec,rowsen,rowrhs,rowrng) ;
+  setRowName(ndx,name) ;
+}
+/* Add a named column (primal variable) to the problem.
+ */
+void 
+OsiClpSolverInterface::addCol(int numberElements,
+       const int* rows, const double* elements,
+       const double collb, const double colub,   
+       const double obj, std::string name) 
+{
+  int ndx = getNumCols() ;
+  addCol(numberElements,rows,elements,collb,colub,obj) ;
+  setColName(ndx,name) ;
+}
+/* Start faster dual - returns negative if problems 1 if infeasible,
+   Options to pass to solver
+   1 - create external reduced costs for columns
+   2 - create external reduced costs for rows
+   4 - create external row activity (columns always done)
+   Above only done if feasible
+   When set resolve does less work
+*/
+int 
+OsiClpSolverInterface::startFastDual(int options)
+{
+  stuff_.zap(3);
+  stuff_.solverOptions_=options;
+  return modelPtr_->startFastDual2(&stuff_);
+}
+// Sets integer tolerance and increment
+void
+OsiClpSolverInterface::setStuff(double tolerance,double increment)
+{
+  stuff_.integerTolerance_ = tolerance;
+  stuff_.integerIncrement_ = increment;
+}
+// Stops faster dual
+void 
+OsiClpSolverInterface::stopFastDual()
+{
+  modelPtr_->stopFastDual2(&stuff_);
+}
+// Compute largest amount any at continuous away from bound
+void 
+OsiClpSolverInterface::computeLargestAway()
+{
+  // get largest scaled away from bound
+  ClpSimplex temp=*modelPtr_;
+  // save logLevel (in case derived message handler)
+  int saveLogLevel=temp.logLevel();
+  temp.setLogLevel(0);
+  temp.dual();
+  if (temp.status()==1)
+    temp.primal(); // may mean we have optimal so continuous cutoff
+  temp.dual(0,7);
+  temp.setLogLevel(saveLogLevel);
+  double largestScaled=1.0e-12;
+  double largest=1.0e-12;
+  int numberRows = temp.numberRows();
+  const double * rowPrimal = temp.primalRowSolution();
+  const double * rowLower = temp.rowLower();
+  const double * rowUpper = temp.rowUpper();
+  const double * rowScale = temp.rowScale();
+  int iRow;
+  for (iRow=0;iRow<numberRows;iRow++) {
+    double value = rowPrimal[iRow];
+    double above = value-rowLower[iRow];
+    double below = rowUpper[iRow]-value;
+    if (above<1.0e12) {
+      largest = CoinMax(largest,above);
+    }
+    if (below<1.0e12) {
+      largest = CoinMax(largest,below);
+    }
+    if (rowScale) {
+      double multiplier = rowScale[iRow];
+      above *= multiplier;
+      below *= multiplier;
+    }
+    if (above<1.0e12) {
+      largestScaled = CoinMax(largestScaled,above);
+    }
+    if (below<1.0e12) {
+      largestScaled = CoinMax(largestScaled,below);
+    }
+  }
+  
+  int numberColumns = temp.numberColumns();
+  const double * columnPrimal = temp.primalColumnSolution();
+  const double * columnLower = temp.columnLower();
+  const double * columnUpper = temp.columnUpper();
+  const double * columnScale = temp.columnScale();
+  int iColumn;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    double value = columnPrimal[iColumn];
+    double above = value-columnLower[iColumn];
+    double below = columnUpper[iColumn]-value;
+    if (above<1.0e12) {
+      largest = CoinMax(largest,above);
+    }
+    if (below<1.0e12) {
+      largest = CoinMax(largest,below);
+    }
+    if (columnScale) {
+      double multiplier = 1.0/columnScale[iColumn];
+      above *= multiplier;
+      below *= multiplier;
+    }
+    if (above<1.0e12) {
+      largestScaled = CoinMax(largestScaled,above);
+    }
+    if (below<1.0e12) {
+      largestScaled = CoinMax(largestScaled,below);
+    }
+  }
+#ifdef COIN_DEVELOP
+  std::cout<<"Largest (scaled) away from bound "<<largestScaled
+	   <<" unscaled "<<largest<<std::endl;
+#endif
+  largestAway_ = largestScaled;
+  // go for safety
+  if (numberRows>4000)
+    modelPtr_->setSpecialOptions(modelPtr_->specialOptions()&~(2048+4096));
+}
+// Pass in Message handler (not deleted at end)
+void 
+OsiClpSolverInterface::passInMessageHandler(CoinMessageHandler * handler)
+{
+  if (defaultHandler_) {
+    delete handler_;
+    handler_ = NULL;
+  }
+  defaultHandler_=false;
+  handler_=handler;
+  if (modelPtr_)
+    modelPtr_->passInMessageHandler(handler);
+}
+// Set log level (will also set underlying solver's log level)
+void 
+OsiClpSolverInterface::setLogLevel(int value)
+{
+  handler_->setLogLevel(value);
+  if (modelPtr_)
+    modelPtr_->setLogLevel(value);
+}
+// Set fake objective (and take ownership)
+void 
+OsiClpSolverInterface::setFakeObjective(ClpLinearObjective * fakeObjective)
+{
+  delete fakeObjective_;
+  fakeObjective_ = fakeObjective;
+}
+// Set fake objective
+void 
+OsiClpSolverInterface::setFakeObjective(double * fakeObjective)
+{
+  delete fakeObjective_;
+  if (fakeObjective)
+    fakeObjective_ = new ClpLinearObjective(fakeObjective,
+					    modelPtr_->numberColumns_);
+  else
+    fakeObjective_ = NULL;
+}
+/* Solve when primal column and dual row solutions are near-optimal
+   options - 0 no presolve (use primal and dual)
+             1 presolve (just use primal)
+	     2 no presolve (just use primal)
+   basis - 0 use all slack basis
+           1 try and put some in basis
+*/
+void 
+OsiClpSolverInterface::crossover(int options,int basis)
+{
+  int numberRows = modelPtr_->getNumRows();
+  int numberColumns = modelPtr_->getNumCols();
+  // Get row activities and column reduced costs
+  const double * objective = modelPtr_->objective();
+  double direction = modelPtr_->optimizationDirection();
+  double * dual = modelPtr_->dualRowSolution();
+  double * dj = modelPtr_->dualColumnSolution();
+  CoinMemcpyN(objective,numberColumns,dj);
+  if (direction==-1.0) {
+    for (int i=0;i<numberColumns;i++)
+      dj[i] = - dj[i];
+  }
+  modelPtr_->clpMatrix()->transposeTimes(-1.0,dual,dj);
+  double * rowActivity = modelPtr_->primalRowSolution();
+  double * columnActivity = modelPtr_->primalColumnSolution();
+  CoinZeroN(rowActivity,numberRows);
+  modelPtr_->clpMatrix()->times(1.0,columnActivity,rowActivity);
+  modelPtr_->checkSolution();
+  printf("%d primal infeasibilities summing to %g\n",
+	 modelPtr_->numberPrimalInfeasibilities(),
+	 modelPtr_->sumPrimalInfeasibilities());
+  printf("%d dual infeasibilities summing to %g\n",
+	 modelPtr_->numberDualInfeasibilities(),
+	 modelPtr_->sumDualInfeasibilities());
+  // get which variables are fixed
+  double * saveLower=NULL;
+  double * saveUpper=NULL;
+  ClpPresolve pinfo2;
+  bool extraPresolve=false;
+  bool useBoth= (options==0);
+  // create all slack basis
+  modelPtr_->createStatus();
+  // Point to model - so can use in presolved model
+  ClpSimplex * model2 = modelPtr_;
+  double tolerance = modelPtr_->primalTolerance()*10.0;
+  if (options==1) {
+    int numberTotal = numberRows+numberColumns;
+    saveLower = new double [numberTotal];
+    saveUpper = new double [numberTotal];
+    CoinMemcpyN(modelPtr_->columnLower(),numberColumns,saveLower);
+    CoinMemcpyN(modelPtr_->rowLower(),numberRows,saveLower+numberColumns);
+    CoinMemcpyN(modelPtr_->columnUpper(),numberColumns,saveUpper);
+    CoinMemcpyN(modelPtr_->rowUpper(),numberRows,saveUpper+numberColumns);
+    double * lower = modelPtr_->columnLower();
+    double * upper = modelPtr_->columnUpper();
+    double * solution = modelPtr_->primalColumnSolution();
+    int nFix=0;
+    for (int i=0;i<numberColumns;i++) {
+      if (lower[i]<upper[i]&&(lower[i]>-1.0e10||upper[i]<1.0e10)) {
+	double value = solution[i];
+	if (value<lower[i]+tolerance&&value-lower[i]<upper[i]-value) {
+	  solution[i]=lower[i];
+	  upper[i]=lower[i];
+	  nFix++;
+	} else if (value>upper[i]-tolerance&&value-lower[i]>upper[i]-value) {
+	  solution[i]=upper[i];
+	  lower[i]=upper[i];
+	  nFix++;
+	}
+      }
+    }
+#ifdef CLP_INVESTIGATE
+    printf("%d columns fixed\n",nFix);
+#endif
+#if 0
+    int nr=modelPtr_->numberRows();
+    lower = modelPtr_->rowLower();
+    upper = modelPtr_->rowUpper();
+    solution = modelPtr_->primalRowSolution();
+    nFix=0;
+    for (int i=0;i<nr;i++) {
+      if (lower[i]<upper[i]) {
+	double value = solution[i];
+	if (value<lower[i]+tolerance&&value-lower[i]<upper[i]-value) {
+	  solution[i]=lower[i];
+	  upper[i]=lower[i];
+	  nFix++;
+	} else if (value>upper[i]-tolerance&&value-lower[i]>upper[i]-value) {
+	  solution[i]=upper[i];
+	  lower[i]=upper[i];
+	  nFix++;
+	}
+      }
+    }
+#ifdef CLP_INVESTIGATE
+    printf("%d row slacks fixed\n",nFix);
+#endif
+#endif
+    extraPresolve=true;
+    // do presolve
+    model2 = pinfo2.presolvedModel(*modelPtr_,modelPtr_->presolveTolerance(),
+				   false,5,true);
+    if (!model2) {
+      model2=modelPtr_;
+      CoinMemcpyN(saveLower,numberColumns,model2->columnLower());
+      CoinMemcpyN(saveLower+numberColumns,numberRows,model2->rowLower());
+      delete [] saveLower;
+      CoinMemcpyN(saveUpper,numberColumns,model2->columnUpper());
+      CoinMemcpyN(saveUpper+numberColumns,numberRows,model2->rowUpper());
+      delete [] saveUpper;
+      saveLower=NULL;
+      saveUpper=NULL;
+      extraPresolve=false;
+    }
+  }
+  if (model2->factorizationFrequency()==200) {
+    // User did not touch preset
+    model2->defaultFactorizationFrequency();
+  }
+  if (basis) {
+    // throw some into basis 
+    int numberRows = model2->numberRows();
+    int numberColumns = model2->numberColumns();
+    double * dsort = new double[numberColumns];
+    int * sort = new int[numberColumns];
+    int n=0;
+    const double * columnLower = model2->columnLower();
+    const double * columnUpper = model2->columnUpper();
+    double * primalSolution = model2->primalColumnSolution();
+    const double * dualSolution = model2->dualColumnSolution();
+    int i;
+    for ( i=0;i<numberRows;i++) 
+      model2->setRowStatus(i,ClpSimplex::superBasic);
+    for ( i=0;i<numberColumns;i++) {
+      double distance = CoinMin(columnUpper[i]-primalSolution[i],
+				primalSolution[i]-columnLower[i]);
+      if (distance>tolerance) {
+	if (fabs(dualSolution[i])<1.0e-5)
+	  distance *= 100.0;
+	dsort[n]=-distance;
+	sort[n++]=i;
+	model2->setStatus(i,ClpSimplex::superBasic);
+      } else if (distance>tolerance) {
+	model2->setStatus(i,ClpSimplex::superBasic);
+      } else if (primalSolution[i]<=columnLower[i]+tolerance) {
+	model2->setStatus(i,ClpSimplex::atLowerBound);
+	primalSolution[i]=columnLower[i];
+      } else {
+	model2->setStatus(i,ClpSimplex::atUpperBound);
+	primalSolution[i]=columnUpper[i];
+      }
+    }
+    CoinSort_2(dsort,dsort+n,sort);
+    n = CoinMin(numberRows,n);
+    for ( i=0;i<n;i++) {
+      int iColumn = sort[i];
+      model2->setStatus(iColumn,ClpSimplex::basic);
+    }
+    delete [] sort;
+    delete [] dsort;
+  }
+  // Start crossover
+  if (useBoth) {
+    int numberRows = model2->numberRows();
+    int numberColumns = model2->numberColumns();
+    double * rowPrimal = new double [numberRows];
+    double * columnPrimal = new double [numberColumns];
+    double * rowDual = new double [numberRows];
+    double * columnDual = new double [numberColumns];
+    // move solutions
+    CoinMemcpyN(model2->primalRowSolution(),
+		numberRows,rowPrimal);
+    CoinMemcpyN(model2->dualRowSolution(),
+		numberRows,rowDual);
+    CoinMemcpyN(model2->primalColumnSolution(),
+		numberColumns,columnPrimal);
+    CoinMemcpyN(model2->dualColumnSolution(),
+		numberColumns,columnDual);
+    // primal values pass
+    double saveScale = model2->objectiveScale();
+    model2->setObjectiveScale(1.0e-3);
+    model2->primal(2);
+    model2->setObjectiveScale(saveScale);
+    // save primal solution and copy back dual
+    CoinMemcpyN(model2->primalRowSolution(),
+		numberRows,rowPrimal);
+    CoinMemcpyN(rowDual,
+		numberRows,model2->dualRowSolution());
+    CoinMemcpyN(model2->primalColumnSolution(),
+		numberColumns,columnPrimal);
+    CoinMemcpyN(columnDual,
+		numberColumns,model2->dualColumnSolution());
+    // clean up reduced costs and flag variables
+    double * dj = model2->dualColumnSolution();
+    double * cost = model2->objective();
+    double * saveCost = new double[numberColumns];
+    CoinMemcpyN(cost,numberColumns,saveCost);
+    double * saveLower = new double[numberColumns];
+    double * lower = model2->columnLower();
+    CoinMemcpyN(lower,numberColumns,saveLower);
+    double * saveUpper = new double[numberColumns];
+    double * upper = model2->columnUpper();
+    CoinMemcpyN(upper,numberColumns,saveUpper);
+    int i;
+    for ( i=0;i<numberColumns;i++) {
+      if (model2->getStatus(i)==ClpSimplex::basic) {
+	dj[i]=0.0;
+      } else if (model2->getStatus(i)==ClpSimplex::atLowerBound) {
+	if (direction*dj[i]<tolerance) {
+	  if (direction*dj[i]<0.0) {
+	    //if (dj[i]<-1.0e-3)
+	    //printf("bad dj at lb %d %g\n",i,dj[i]);
+	    cost[i] -= dj[i];
+	    dj[i]=0.0;
+	  }
+	} else {
+	  upper[i]=lower[i];
+	}
+      } else if (model2->getStatus(i)==ClpSimplex::atUpperBound) {
+	if (direction*dj[i]>tolerance) {
+	  if (direction*dj[i]>0.0) {
+	    //if (dj[i]>1.0e-3)
+	    //printf("bad dj at ub %d %g\n",i,dj[i]);
+	    cost[i] -= dj[i];
+	    dj[i]=0.0;
+	  }
+	} else {
+	  lower[i]=upper[i];
+	}
+      }
+    }
+    // just dual values pass
+    model2->dual(2);
+    CoinMemcpyN(saveCost,numberColumns,cost);
+    delete [] saveCost;
+    CoinMemcpyN(saveLower,numberColumns,lower);
+    delete [] saveLower;
+    CoinMemcpyN(saveUpper,numberColumns,upper);
+    delete [] saveUpper;
+    // move solutions
+    CoinMemcpyN(rowPrimal,
+		numberRows,model2->primalRowSolution());
+    CoinMemcpyN(columnPrimal,
+		numberColumns,model2->primalColumnSolution());
+    // and finish
+    delete [] rowPrimal;
+    delete [] columnPrimal;
+    delete [] rowDual;
+    delete [] columnDual;
+    model2->setObjectiveScale(1.0e-3);
+    model2->primal(2);
+    model2->setObjectiveScale(saveScale);
+    model2->primal(1);
+  } else {
+    // primal values pass
+    double saveScale = model2->objectiveScale();
+    model2->setObjectiveScale(1.0e-3);
+    model2->primal(2);
+    model2->setObjectiveScale(saveScale);
+    model2->primal(1);
+  }
+  if (extraPresolve) {
+    pinfo2.postsolve(true);
+    delete model2;
+    modelPtr_->primal(1);
+    CoinMemcpyN(saveLower,numberColumns,modelPtr_->columnLower());
+    CoinMemcpyN(saveLower+numberColumns,numberRows,modelPtr_->rowLower());
+    CoinMemcpyN(saveUpper,numberColumns,modelPtr_->columnUpper());
+    CoinMemcpyN(saveUpper+numberColumns,numberRows,modelPtr_->rowUpper());
+    delete [] saveLower;
+    delete [] saveUpper;
+    modelPtr_->primal(1);
+  }
+  // Save basis in Osi object
+  setWarmStart(NULL);
+}
+  
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiClpDisasterHandler::OsiClpDisasterHandler (OsiClpSolverInterface * model) 
+  : ClpDisasterHandler(),
+    osiModel_(model),
+    whereFrom_(0),
+    phase_(0),
+    inTrouble_(false)
+{
+  if (model)
+    setSimplex(model->getModelPtr());
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiClpDisasterHandler::OsiClpDisasterHandler (const OsiClpDisasterHandler & rhs) 
+  : ClpDisasterHandler(rhs),
+    osiModel_(rhs.osiModel_),
+    whereFrom_(rhs.whereFrom_),
+    phase_(rhs.phase_),
+    inTrouble_(rhs.inTrouble_)
+{  
+}
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiClpDisasterHandler::~OsiClpDisasterHandler ()
+{
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiClpDisasterHandler &
+OsiClpDisasterHandler::operator=(const OsiClpDisasterHandler& rhs)
+{
+  if (this != &rhs) {
+    ClpDisasterHandler::operator=(rhs);
+    osiModel_ = rhs.osiModel_;
+    whereFrom_ = rhs.whereFrom_;
+    phase_ = rhs.phase_;
+    inTrouble_ = rhs.inTrouble_;
+  }
+  return *this;
+}
+//-------------------------------------------------------------------
+// Clone
+//-------------------------------------------------------------------
+ClpDisasterHandler * OsiClpDisasterHandler::clone() const
+{
+  return new OsiClpDisasterHandler(*this);
+}
+
+void
+OsiClpDisasterHandler::intoSimplex()
+{
+  inTrouble_=false;
+}
+bool
+OsiClpDisasterHandler::check() const
+{
+  // Exit if really large number of iterations
+  if (model_->numberIterations()> model_->baseIteration()+100000+100*(model_->numberRows()+model_->numberColumns()))
+    return true;
+  if ((whereFrom_&2)==0||!model_->nonLinearCost()) {
+    // dual
+    if (model_->numberIterations()<model_->baseIteration()+model_->numberRows()+1000) {
+      return false;
+    } else if (phase_<2) {
+      if (model_->numberIterations()> model_->baseIteration()+2*model_->numberRows()+model_->numberColumns()+2000||
+	  model_->largestDualError()>=1.0e-1) {
+	// had model_->numberDualInfeasibilitiesWithoutFree()||
+#ifdef COIN_DEVELOP
+	printf("trouble in phase %d\n",phase_);
+#endif
+	if (osiModel_->largestAway()>0.0) {
+	  // go for safety
+	  model_->setSpecialOptions(model_->specialOptions()&~(2048+4096));
+	  int frequency = model_->factorizationFrequency();
+	  if (frequency>100)
+	    frequency=100;
+	  model_->setFactorizationFrequency(frequency);
+	  double oldBound = model_->dualBound();
+	  double newBound = CoinMax(1.0001e8,
+				    CoinMin(10.0*osiModel_->largestAway(),1.e10));
+	  if (newBound!=oldBound) {
+	    model_->setDualBound(newBound);
+	    if (model_->upperRegion()&&model_->algorithm()<0) {
+	      // need to fix up fake bounds
+	      (static_cast<ClpSimplexDual *>(model_))->resetFakeBounds(0);
+	    }
+	  }
+	  osiModel_->setLargestAway(-1.0);
+	}
+	return true;
+      } else {
+	return false;
+      }
+    } else {
+      assert (phase_==2);
+      if (model_->numberIterations()> model_->baseIteration()+3*model_->numberRows()+model_->numberColumns()+2000||
+	  model_->largestPrimalError()>=1.0e3) {
+#ifdef COIN_DEVELOP
+	printf("trouble in phase %d\n",phase_);
+#endif
+	return true;
+      } else {
+	return false;
+      }
+    }
+  } else {
+    // primal
+    if (model_->numberIterations()<model_->baseIteration()+2*model_->numberRows()+model_->numberColumns()+4000) {
+      return false;
+    } else if (phase_<2) {
+      if (model_->numberIterations()> model_->baseIteration()+3*model_->numberRows()+2000+
+	  model_->numberColumns()&&
+	  model_->numberDualInfeasibilitiesWithoutFree()>0&&
+	  model_->numberPrimalInfeasibilities()>0&&
+	  model_->nonLinearCost()->changeInCost()>1.0e8) {
+#ifdef COIN_DEVELOP
+	printf("trouble in phase %d\n",phase_);
+#endif
+	return true;
+      } else {
+	return false;
+      }
+    } else {
+      assert (phase_==2);
+      if (model_->numberIterations()> model_->baseIteration()+3*model_->numberRows()+2000||
+	  model_->largestPrimalError()>=1.0e3) {
+#ifdef COIN_DEVELOP
+	printf("trouble in phase %d\n",phase_);
+#endif
+	return true;
+      } else {
+	return false;
+      }
+    }
+  }
+}
+void
+OsiClpDisasterHandler::saveInfo()
+{
+  inTrouble_=true;
+}
+// Type of disaster 0 can fix, 1 abort
+int 
+OsiClpDisasterHandler::typeOfDisaster()
+{
+  return 0;
+}
+/* set model. */
+void 
+OsiClpDisasterHandler::setOsiModel(OsiClpSolverInterface * model)
+{
+  osiModel_=model;
+  model_=model->getModelPtr();
+}
+// Create C++ lines to get to current state
+void 
+OsiClpSolverInterface::generateCpp( FILE * fp)
+{
+  modelPtr_->generateCpp(fp,true);
+  // Stuff that can't be done easily
+  // setupForRepeatedUse here
+  if (!messageHandler()->prefix())
+    fprintf(fp,"3  clpModel->messageHandler()->setPrefix(false);\n");
+  OsiClpSolverInterface defaultModel;
+  OsiClpSolverInterface * other = &defaultModel;
+  int iValue1, iValue2;
+  double dValue1, dValue2;
+  bool takeHint1,takeHint2;
+  int add;
+  OsiHintStrength strength1,strength2;
+  std::string strengthName[] = {"OsiHintIgnore","OsiHintTry","OsiHintDo",
+				"OsiForceDo"};
+  iValue1 = this->specialOptions();
+  iValue2 = other->specialOptions();
+  fprintf(fp,"%d  int save_specialOptions = osiclpModel->specialOptions();\n",iValue1==iValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->setSpecialOptions(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
+  fprintf(fp,"%d  osiclpModel->setSpecialOptions(save_specialOptions);\n",iValue1==iValue2 ? 7 : 6);
+  iValue1 = this->messageHandler()->logLevel();
+  iValue2 = other->messageHandler()->logLevel();
+  fprintf(fp,"%d  int save_messageHandler = osiclpModel->messageHandler()->logLevel();\n",iValue1==iValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->messageHandler()->setLogLevel(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
+  fprintf(fp,"%d  osiclpModel->messageHandler()->setLogLevel(save_messageHandler);\n",iValue1==iValue2 ? 7 : 6);
+  iValue1 = this->cleanupScaling();
+  iValue2 = other->cleanupScaling();
+  fprintf(fp,"%d  int save_cleanupScaling = osiclpModel->cleanupScaling();\n",iValue1==iValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->setCleanupScaling(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
+  fprintf(fp,"%d  osiclpModel->setCleanupScaling(save_cleanupScaling);\n",iValue1==iValue2 ? 7 : 6);
+  dValue1 = this->smallestElementInCut();
+  dValue2 = other->smallestElementInCut();
+  fprintf(fp,"%d  double save_smallestElementInCut = osiclpModel->smallestElementInCut();\n",dValue1==dValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->setSmallestElementInCut(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
+  fprintf(fp,"%d  osiclpModel->setSmallestElementInCut(save_smallestElementInCut);\n",dValue1==dValue2 ? 7 : 6);
+  dValue1 = this->smallestChangeInCut();
+  dValue2 = other->smallestChangeInCut();
+  fprintf(fp,"%d  double save_smallestChangeInCut = osiclpModel->smallestChangeInCut();\n",dValue1==dValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->setSmallestChangeInCut(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
+  fprintf(fp,"%d  osiclpModel->setSmallestChangeInCut(save_smallestChangeInCut);\n",dValue1==dValue2 ? 7 : 6);
+  this->getIntParam(OsiMaxNumIterationHotStart,iValue1);
+  other->getIntParam(OsiMaxNumIterationHotStart,iValue2);
+  fprintf(fp,"%d  int save_OsiMaxNumIterationHotStart;\n",iValue1==iValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->getIntParam(OsiMaxNumIterationHotStart,save_OsiMaxNumIterationHotStart);\n",iValue1==iValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->setIntParam(OsiMaxNumIterationHotStart,%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
+  fprintf(fp,"%d  osiclpModel->setIntParam(OsiMaxNumIterationHotStart,save_OsiMaxNumIterationHotStart);\n",iValue1==iValue2 ? 7 : 6);
+  this->getDblParam(OsiDualObjectiveLimit,dValue1);
+  other->getDblParam(OsiDualObjectiveLimit,dValue2);
+  fprintf(fp,"%d  double save_OsiDualObjectiveLimit;\n",dValue1==dValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->getDblParam(OsiDualObjectiveLimit,save_OsiDualObjectiveLimit);\n",dValue1==dValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->setDblParam(OsiDualObjectiveLimit,%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
+  fprintf(fp,"%d  osiclpModel->setDblParam(OsiDualObjectiveLimit,save_OsiDualObjectiveLimit);\n",dValue1==dValue2 ? 7 : 6);
+  this->getDblParam(OsiPrimalObjectiveLimit,dValue1);
+  other->getDblParam(OsiPrimalObjectiveLimit,dValue2);
+  fprintf(fp,"%d  double save_OsiPrimalObjectiveLimit;\n",dValue1==dValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->getDblParam(OsiPrimalObjectiveLimit,save_OsiPrimalObjectiveLimit);\n",dValue1==dValue2 ? 2 : 1);
+  fprintf(fp,"%d  osiclpModel->setDblParam(OsiPrimalObjectiveLimit,%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
+  fprintf(fp,"%d  osiclpModel->setDblParam(OsiPrimalObjectiveLimit,save_OsiPrimalObjectiveLimit);\n",dValue1==dValue2 ? 7 : 6);
+  this->getHintParam(OsiDoPresolveInInitial,takeHint1,strength1);
+  other->getHintParam(OsiDoPresolveInInitial,takeHint2,strength2);
+  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
+  fprintf(fp,"%d  bool saveHint_OsiDoPresolveInInitial;\n",add+1);
+  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoPresolveInInitial;\n",add+1);
+  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoPresolveInInitial,saveHint_OsiDoPresolveInInitial,saveStrength_OsiDoPresolveInInitial);\n",add+1);
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoPresolveInInitial,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoPresolveInInitial,saveHint_OsiDoPresolveInInitial,saveStrength_OsiDoPresolveInInitial);\n",add+6);
+  this->getHintParam(OsiDoDualInInitial,takeHint1,strength1);
+  other->getHintParam(OsiDoDualInInitial,takeHint2,strength2);
+  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
+  fprintf(fp,"%d  bool saveHint_OsiDoDualInInitial;\n",add+1);
+  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoDualInInitial;\n",add+1);
+  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoDualInInitial,saveHint_OsiDoDualInInitial,saveStrength_OsiDoDualInInitial);\n",add+1);
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoDualInInitial,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoDualInInitial,saveHint_OsiDoDualInInitial,saveStrength_OsiDoDualInInitial);\n",add+6);
+  this->getHintParam(OsiDoPresolveInResolve,takeHint1,strength1);
+  other->getHintParam(OsiDoPresolveInResolve,takeHint2,strength2);
+  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
+  fprintf(fp,"%d  bool saveHint_OsiDoPresolveInResolve;\n",add+1);
+  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoPresolveInResolve;\n",add+1);
+  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoPresolveInResolve,saveHint_OsiDoPresolveInResolve,saveStrength_OsiDoPresolveInResolve);\n",add+1);
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoPresolveInResolve,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoPresolveInResolve,saveHint_OsiDoPresolveInResolve,saveStrength_OsiDoPresolveInResolve);\n",add+6);
+  this->getHintParam(OsiDoDualInResolve,takeHint1,strength1);
+  other->getHintParam(OsiDoDualInResolve,takeHint2,strength2);
+  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
+  fprintf(fp,"%d  bool saveHint_OsiDoDualInResolve;\n",add+1);
+  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoDualInResolve;\n",add+1);
+  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoDualInResolve,saveHint_OsiDoDualInResolve,saveStrength_OsiDoDualInResolve);\n",add+1);
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoDualInResolve,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoDualInResolve,saveHint_OsiDoDualInResolve,saveStrength_OsiDoDualInResolve);\n",add+6);
+  this->getHintParam(OsiDoScale,takeHint1,strength1);
+  other->getHintParam(OsiDoScale,takeHint2,strength2);
+  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
+  fprintf(fp,"%d  bool saveHint_OsiDoScale;\n",add+1);
+  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoScale;\n",add+1);
+  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoScale,saveHint_OsiDoScale,saveStrength_OsiDoScale);\n",add+1);
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoScale,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoScale,saveHint_OsiDoScale,saveStrength_OsiDoScale);\n",add+6);
+  this->getHintParam(OsiDoCrash,takeHint1,strength1);
+  other->getHintParam(OsiDoCrash,takeHint2,strength2);
+  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
+  fprintf(fp,"%d  bool saveHint_OsiDoCrash;\n",add+1);
+  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoCrash;\n",add+1);
+  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoCrash,saveHint_OsiDoCrash,saveStrength_OsiDoCrash);\n",add+1);
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoCrash,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoCrash,saveHint_OsiDoCrash,saveStrength_OsiDoCrash);\n",add+6);
+  this->getHintParam(OsiDoReducePrint,takeHint1,strength1);
+  other->getHintParam(OsiDoReducePrint,takeHint2,strength2);
+  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
+  fprintf(fp,"%d  bool saveHint_OsiDoReducePrint;\n",add+1);
+  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoReducePrint;\n",add+1);
+  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoReducePrint,saveHint_OsiDoReducePrint,saveStrength_OsiDoReducePrint);\n",add+1);
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoReducePrint,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
+  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoReducePrint,saveHint_OsiDoReducePrint,saveStrength_OsiDoReducePrint);\n",add+6);
+}
+// So unit test can find out if NDEBUG set
+bool OsiClpHasNDEBUG() 
+{
+#ifdef NDEBUG
+  return true;
+#else
+  return false;
+#endif
+}
diff --git a/cbits/coin/OsiClpSolverInterface.hpp b/cbits/coin/OsiClpSolverInterface.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiClpSolverInterface.hpp
@@ -0,0 +1,1495 @@
+// $Id$
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+
+#ifndef OsiClpSolverInterface_H
+#define OsiClpSolverInterface_H
+
+#include <string>
+#include <cfloat>
+#include <map>
+
+#include "ClpSimplex.hpp"
+#include "ClpLinearObjective.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "OsiSolverInterface.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "ClpEventHandler.hpp"
+#include "ClpNode.hpp"
+#include "CoinIndexedVector.hpp"
+#include "CoinFinite.hpp"
+
+class OsiRowCut;
+class OsiClpUserSolver;
+class OsiClpDisasterHandler;
+class CoinSet;
+static const double OsiClpInfinity = COIN_DBL_MAX;
+
+//#############################################################################
+
+/** Clp Solver Interface
+    
+Instantiation of OsiClpSolverInterface for the Model Algorithm.
+
+*/
+
+class OsiClpSolverInterface :
+  virtual public OsiSolverInterface {
+  friend void OsiClpSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir);
+  
+public:
+  //---------------------------------------------------------------------------
+  /**@name Solve methods */
+  //@{
+  /// Solve initial LP relaxation 
+  virtual void initialSolve();
+  
+  /// Resolve an LP relaxation after problem modification
+  virtual void resolve();
+  
+  /// Resolve an LP relaxation after problem modification (try GUB)
+  virtual void resolveGub(int needed);
+  
+  /// Invoke solver's built-in enumeration algorithm
+  virtual void branchAndBound();
+
+  /** Solve when primal column and dual row solutions are near-optimal
+      options - 0 no presolve (use primal and dual)
+                1 presolve (just use primal)
+		2 no presolve (just use primal)
+      basis -   0 use all slack basis
+                1 try and put some in basis
+  */
+  void crossover(int options,int basis);
+  //@}
+  
+  /*! @name OsiSimplexInterface methods
+      \brief Methods for the Osi Simplex API.
+
+    The current implementation should work for both minimisation and
+    maximisation in mode 1 (tableau access). In mode 2 (single pivot), only
+    minimisation is supported as of 100907.
+  */
+  //@{
+  /** \brief Simplex API capability.
+  
+    Returns
+     - 0 if no simplex API
+     - 1 if can just do getBInv etc
+     - 2 if has all OsiSimplex methods
+  */
+  virtual int canDoSimplexInterface() const;
+
+  /*! \brief Enables simplex mode 1 (tableau access)
+  
+    Tells solver that calls to getBInv etc are about to take place.
+    Underlying code may need mutable as this may be called from 
+    CglCut::generateCuts which is const.  If that is too horrific then
+    each solver e.g. BCP or CBC will have to do something outside
+    main loop.
+  */
+  virtual void enableFactorization() const;
+
+  /*! \brief Undo any setting changes made by #enableFactorization */
+  virtual void disableFactorization() const;
+  
+  /** Returns true if a basis is available
+      AND problem is optimal.  This should be used to see if
+      the BInvARow type operations are possible and meaningful. 
+  */
+  virtual bool basisIsAvailable() const;
+  
+  /** The following two methods may be replaced by the
+      methods of OsiSolverInterface using OsiWarmStartBasis if:
+      1. OsiWarmStartBasis resize operation is implemented
+      more efficiently and
+      2. It is ensured that effects on the solver are the same
+      
+      Returns a basis status of the structural/artificial variables 
+      At present as warm start i.e 0 free, 1 basic, 2 upper, 3 lower
+      
+      NOTE  artificials are treated as +1 elements so for <= rhs
+      artificial will be at lower bound if constraint is tight
+      
+      This means that Clpsimplex flips artificials as it works
+      in terms of row activities
+  */
+  virtual void getBasisStatus(int* cstat, int* rstat) const;
+  
+  /** Set the status of structural/artificial variables and
+      factorize, update solution etc 
+      
+      NOTE  artificials are treated as +1 elements so for <= rhs
+      artificial will be at lower bound if constraint is tight
+      
+      This means that Clpsimplex flips artificials as it works
+      in terms of row activities
+      Returns 0 if OK, 1 if problem is bad e.g. duplicate elements, too large ...
+  */
+  virtual int setBasisStatus(const int* cstat, const int* rstat);
+  
+  ///Get the reduced gradient for the cost vector c 
+  virtual void getReducedGradient(double* columnReducedCosts, 
+				  double * duals,
+				  const double * c) const ;
+  
+  ///Get a row of the tableau (slack part in slack if not NULL)
+  virtual void getBInvARow(int row, double* z, double * slack=NULL) const;
+  
+  /** Get a row of the tableau (slack part in slack if not NULL)
+      If keepScaled is true then scale factors not applied after so
+      user has to use coding similar to what is in this method
+  */
+  virtual void getBInvARow(int row, CoinIndexedVector * z, CoinIndexedVector * slack=NULL,
+			   bool keepScaled=false) const;
+  
+  ///Get a row of the basis inverse
+  virtual void getBInvRow(int row, double* z) const;
+  
+  ///Get a column of the tableau
+  virtual void getBInvACol(int col, double* vec) const ;
+  
+  ///Get a column of the tableau
+  virtual void getBInvACol(int col, CoinIndexedVector * vec) const ;
+  
+  /** Update (i.e. ftran) the vector passed in.
+      Unscaling is applied after - can't be applied before
+  */
+  
+  virtual void getBInvACol(CoinIndexedVector * vec) const ;
+  
+  ///Get a column of the basis inverse
+  virtual void getBInvCol(int col, double* vec) const ;
+  
+  /** Get basic indices (order of indices corresponds to the
+      order of elements in a vector retured by getBInvACol() and
+      getBInvCol()).
+  */
+  virtual void getBasics(int* index) const;
+
+  /*! \brief Enables simplex mode 2 (individual pivot control)
+
+     This method is supposed to ensure that all typical things (like
+     reduced costs, etc.) are updated when individual pivots are executed
+     and can be queried by other methods.
+  */
+  virtual void enableSimplexInterface(bool doingPrimal);
+  /// Copy across enabled stuff from one solver to another
+  void copyEnabledSuff(OsiClpSolverInterface & rhs);
+  
+  /*! \brief Undo setting changes made by #enableSimplexInterface */
+  virtual void disableSimplexInterface();
+  /// Copy across enabled stuff from one solver to another
+  void copyEnabledStuff(ClpSimplex & rhs);
+
+  /** Perform a pivot by substituting a colIn for colOut in the basis. 
+      The status of the leaving variable is given in statOut. Where
+      1 is to upper bound, -1 to lower bound
+      Return code is 0 for okay,
+      1 if inaccuracy forced re-factorization (should be okay) and
+      -1 for singular factorization
+  */
+  virtual int pivot(int colIn, int colOut, int outStatus);
+  
+  /** Obtain a result of the primal pivot 
+      Outputs: colOut -- leaving column, outStatus -- its status,
+      t -- step size, and, if dx!=NULL, *dx -- primal ray direction.
+      Inputs: colIn -- entering column, sign -- direction of its change (+/-1).
+      Both for colIn and colOut, artificial variables are index by
+      the negative of the row index minus 1.
+      Return code (for now): 0 -- leaving variable found, 
+      -1 -- everything else?
+      Clearly, more informative set of return values is required 
+      Primal and dual solutions are updated
+  */
+  virtual int primalPivotResult(int colIn, int sign, 
+				int& colOut, int& outStatus, 
+				double& t, CoinPackedVector* dx);
+  
+  /** Obtain a result of the dual pivot (similar to the previous method)
+      Differences: entering variable and a sign of its change are now
+      the outputs, the leaving variable and its statuts -- the inputs
+      If dx!=NULL, then *dx contains dual ray
+      Return code: same
+  */
+  virtual int dualPivotResult(int& colIn, int& sign, 
+			      int colOut, int outStatus, 
+			      double& t, CoinPackedVector* dx);
+  
+  
+  //@}
+  //---------------------------------------------------------------------------
+  /**@name Parameter set/get methods
+     
+  The set methods return true if the parameter was set to the given value,
+  false otherwise. There can be various reasons for failure: the given
+  parameter is not applicable for the solver (e.g., refactorization
+  frequency for the clp algorithm), the parameter is not yet implemented
+  for the solver or simply the value of the parameter is out of the range
+  the solver accepts. If a parameter setting call returns false check the
+  details of your solver.
+  
+  The get methods return true if the given parameter is applicable for the
+  solver and is implemented. In this case the value of the parameter is
+  returned in the second argument. Otherwise they return false.
+  */
+  //@{
+  // Set an integer parameter
+  bool setIntParam(OsiIntParam key, int value);
+  // Set an double parameter
+  bool setDblParam(OsiDblParam key, double value);
+  // Set a string parameter
+  bool setStrParam(OsiStrParam key, const std::string & value);
+  // Get an integer parameter
+  bool getIntParam(OsiIntParam key, int& value) const;
+  // Get an double parameter
+  bool getDblParam(OsiDblParam key, double& value) const;
+  // Get a string parameter
+  bool getStrParam(OsiStrParam key, std::string& value) const;
+  // Set a hint parameter - overrides OsiSolverInterface
+  virtual bool setHintParam(OsiHintParam key, bool yesNo=true,
+                            OsiHintStrength strength=OsiHintTry,
+                            void * otherInformation=NULL);
+  //@}
+  
+  //---------------------------------------------------------------------------
+  ///@name Methods returning info on how the solution process terminated
+  //@{
+  /// Are there a numerical difficulties?
+  virtual bool isAbandoned() const;
+  /// Is optimality proven?
+  virtual bool isProvenOptimal() const;
+  /// Is primal infeasiblity proven?
+  virtual bool isProvenPrimalInfeasible() const;
+  /// Is dual infeasiblity proven?
+  virtual bool isProvenDualInfeasible() const;
+  /// Is the given primal objective limit reached?
+  virtual bool isPrimalObjectiveLimitReached() const;
+  /// Is the given dual objective limit reached?
+  virtual bool isDualObjectiveLimitReached() const;
+  /// Iteration limit reached?
+  virtual bool isIterationLimitReached() const;
+  //@}
+  
+  //---------------------------------------------------------------------------
+  /**@name WarmStart related methods */
+  //@{
+  
+  /*! \brief Get an empty warm start object
+    
+  This routine returns an empty CoinWarmStartBasis object. Its purpose is
+  to provide a way to give a client a warm start basis object of the
+  appropriate type, which can resized and modified as desired.
+  */
+  
+  virtual CoinWarmStart *getEmptyWarmStart () const;
+  
+  /// Get warmstarting information
+  virtual CoinWarmStart* getWarmStart() const;
+  /// Get warmstarting information
+  inline CoinWarmStartBasis* getPointerToWarmStart() 
+  { return &basis_;}
+  /// Get warmstarting information
+  inline const CoinWarmStartBasis* getConstPointerToWarmStart() const 
+  { return &basis_;}
+  /** Set warmstarting information. Return true/false depending on whether
+      the warmstart information was accepted or not. */
+  virtual bool setWarmStart(const CoinWarmStart* warmstart);
+  /** \brief Get warm start information.
+      
+      Return warm start information for the current state of the solver
+      interface. If there is no valid warm start information, an empty warm
+      start object wil be returned.  This does not necessarily create an 
+      object - may just point to one.  must Delete set true if user
+      should delete returned object.
+      OsiClp version always returns pointer and false.
+  */
+  virtual CoinWarmStart* getPointerToWarmStart(bool & mustDelete) ;
+
+  //@}
+  
+  //---------------------------------------------------------------------------
+  /**@name Hotstart related methods (primarily used in strong branching).
+     The user can create a hotstart (a snapshot) of the optimization process
+     then reoptimize over and over again always starting from there.<br>
+     <strong>NOTE</strong>: between hotstarted optimizations only
+     bound changes are allowed. */
+  //@{
+  /// Create a hotstart point of the optimization process
+  virtual void markHotStart();
+  /// Optimize starting from the hotstart
+  virtual void solveFromHotStart();
+  /// Delete the snapshot
+  virtual void unmarkHotStart();
+  /** Start faster dual - returns negative if problems 1 if infeasible,
+      Options to pass to solver
+      1 - create external reduced costs for columns
+      2 - create external reduced costs for rows
+      4 - create external row activity (columns always done)
+      Above only done if feasible
+      When set resolve does less work
+  */
+  int startFastDual(int options);
+  /// Stop fast dual
+  void stopFastDual();
+  /// Sets integer tolerance and increment
+  void setStuff(double tolerance,double increment);
+  //@}
+  
+  //---------------------------------------------------------------------------
+  /**@name Problem information methods
+     
+  These methods call the solver's query routines to return
+  information about the problem referred to by the current object.
+  Querying a problem that has no data associated with it result in
+  zeros for the number of rows and columns, and NULL pointers from
+  the methods that return vectors.
+  
+  Const pointers returned from any data-query method are valid as
+  long as the data is unchanged and the solver is not called.
+  */
+  //@{
+  /**@name Methods related to querying the input data */
+  //@{
+  /// Get number of columns
+  virtual int getNumCols() const {
+    return modelPtr_->numberColumns(); }
+  
+  /// Get number of rows
+  virtual int getNumRows() const {
+    return modelPtr_->numberRows(); }
+  
+  /// Get number of nonzero elements
+  virtual int getNumElements() const {
+    int retVal = 0;
+    const CoinPackedMatrix * matrix =modelPtr_->matrix();
+    if ( matrix != NULL ) retVal=matrix->getNumElements();
+    return retVal; }
+
+    /// Return name of row if one exists or Rnnnnnnn
+    /// maxLen is currently ignored and only there to match the signature from the base class! 
+    virtual std::string getRowName(int rowIndex,
+				   unsigned maxLen = static_cast<unsigned>(std::string::npos)) const;
+    
+    /// Return name of column if one exists or Cnnnnnnn
+    /// maxLen is currently ignored and only there to match the signature from the base class! 
+    virtual std::string getColName(int colIndex,
+				   unsigned maxLen = static_cast<unsigned>(std::string::npos)) const;
+    
+  
+  /// Get pointer to array[getNumCols()] of column lower bounds
+  virtual const double * getColLower() const { return modelPtr_->columnLower(); }
+  
+  /// Get pointer to array[getNumCols()] of column upper bounds
+  virtual const double * getColUpper() const { return modelPtr_->columnUpper(); }
+  
+  /** Get pointer to array[getNumRows()] of row constraint senses.
+      <ul>
+      <li>'L' <= constraint
+      <li>'E' =  constraint
+      <li>'G' >= constraint
+      <li>'R' ranged constraint
+      <li>'N' free constraint
+      </ul>
+  */
+  virtual const char * getRowSense() const;
+  
+  /** Get pointer to array[getNumRows()] of rows right-hand sides
+      <ul>
+      <li> if rowsense()[i] == 'L' then rhs()[i] == rowupper()[i]
+      <li> if rowsense()[i] == 'G' then rhs()[i] == rowlower()[i]
+      <li> if rowsense()[i] == 'R' then rhs()[i] == rowupper()[i]
+      <li> if rowsense()[i] == 'N' then rhs()[i] == 0.0
+      </ul>
+  */
+  virtual const double * getRightHandSide() const ;
+  
+  /** Get pointer to array[getNumRows()] of row ranges.
+      <ul>
+      <li> if rowsense()[i] == 'R' then
+      rowrange()[i] == rowupper()[i] - rowlower()[i]
+      <li> if rowsense()[i] != 'R' then
+      rowrange()[i] is undefined
+      </ul>
+  */
+  virtual const double * getRowRange() const ;
+  
+  /// Get pointer to array[getNumRows()] of row lower bounds
+  virtual const double * getRowLower() const { return modelPtr_->rowLower(); }
+  
+  /// Get pointer to array[getNumRows()] of row upper bounds
+  virtual const double * getRowUpper() const { return modelPtr_->rowUpper(); }
+  
+  /// Get pointer to array[getNumCols()] of objective function coefficients
+  virtual const double * getObjCoefficients() const 
+  { if (fakeMinInSimplex_)
+      return linearObjective_ ;
+    else
+      return modelPtr_->objective(); }
+  
+  /// Get objective function sense (1 for min (default), -1 for max)
+  virtual double getObjSense() const 
+  { return ((fakeMinInSimplex_)?-modelPtr_->optimizationDirection():
+  				 modelPtr_->optimizationDirection()); }
+  
+  /// Return true if column is continuous
+  virtual bool isContinuous(int colNumber) const;
+  /// Return true if variable is binary
+  virtual bool isBinary(int colIndex) const;
+  
+  /** Return true if column is integer.
+      Note: This function returns true if the the column
+      is binary or a general integer.
+  */
+  virtual bool isInteger(int colIndex) const;
+  
+  /// Return true if variable is general integer
+  virtual bool isIntegerNonBinary(int colIndex) const;
+  
+  /// Return true if variable is binary and not fixed at either bound
+  virtual bool isFreeBinary(int colIndex) const; 
+  /**  Return array of column length
+       0 - continuous
+       1 - binary (may get fixed later)
+       2 - general integer (may get fixed later)
+  */
+  virtual const char * getColType(bool refresh=false) const;
+  
+  /** Return true if column is integer but does not have to
+      be declared as such.
+      Note: This function returns true if the the column
+      is binary or a general integer.
+  */
+  bool isOptionalInteger(int colIndex) const;
+  /** Set the index-th variable to be an optional integer variable */
+  void setOptionalInteger(int index);
+  
+  /// Get pointer to row-wise copy of matrix
+  virtual const CoinPackedMatrix * getMatrixByRow() const;
+  
+  /// Get pointer to column-wise copy of matrix
+  virtual const CoinPackedMatrix * getMatrixByCol() const;
+  
+  /// Get pointer to mutable column-wise copy of matrix
+  virtual CoinPackedMatrix * getMutableMatrixByCol() const;
+  
+    /// Get solver's value for infinity
+  virtual double getInfinity() const { return OsiClpInfinity; }
+  //@}
+  
+  /**@name Methods related to querying the solution */
+  //@{
+  /// Get pointer to array[getNumCols()] of primal solution vector
+  virtual const double * getColSolution() const; 
+  
+  /// Get pointer to array[getNumRows()] of dual prices
+  virtual const double * getRowPrice() const;
+  
+  /// Get a pointer to array[getNumCols()] of reduced costs
+  virtual const double * getReducedCost() const; 
+  
+  /** Get pointer to array[getNumRows()] of row activity levels (constraint
+      matrix times the solution vector */
+  virtual const double * getRowActivity() const; 
+  
+  /// Get objective function value
+  virtual double getObjValue() const;
+  
+  /** Get how many iterations it took to solve the problem (whatever
+      "iteration" mean to the solver. */
+  virtual int getIterationCount() const 
+  { return modelPtr_->numberIterations(); }
+  
+  /** Get as many dual rays as the solver can provide. (In case of proven
+      primal infeasibility there should be at least one.)
+
+      The first getNumRows() ray components will always be associated with
+      the row duals (as returned by getRowPrice()). If \c fullRay is true,
+      the final getNumCols() entries will correspond to the ray components
+      associated with the nonbasic variables. If the full ray is requested
+      and the method cannot provide it, it will throw an exception.
+
+      <strong>NOTE for implementers of solver interfaces:</strong> <br>
+      The double pointers in the vector should point to arrays of length
+      getNumRows() and they should be allocated via new[]. <br>
+      
+      <strong>NOTE for users of solver interfaces:</strong> <br>
+      It is the user's responsibility to free the double pointers in the
+      vector using delete[].
+  */
+  virtual std::vector<double*> getDualRays(int maxNumRays,
+					   bool fullRay = false) const;
+  /** Get as many primal rays as the solver can provide. (In case of proven
+      dual infeasibility there should be at least one.)
+      
+      <strong>NOTE for implementers of solver interfaces:</strong> <br>
+      The double pointers in the vector should point to arrays of length
+      getNumCols() and they should be allocated via new[]. <br>
+      
+      <strong>NOTE for users of solver interfaces:</strong> <br>
+      It is the user's responsibility to free the double pointers in the
+      vector using delete[].
+  */
+  virtual std::vector<double*> getPrimalRays(int maxNumRays) const;
+  
+  //@}
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+  /**@name Problem modifying methods */
+  //@{
+  //-------------------------------------------------------------------------
+  /**@name Changing bounds on variables and constraints */
+  //@{
+  /** Set an objective function coefficient */
+  virtual void setObjCoeff( int elementIndex, double elementValue );
+  
+  /** Set a single column lower bound<br>
+      Use -DBL_MAX for -infinity. */
+  virtual void setColLower( int elementIndex, double elementValue );
+  
+  /** Set a single column upper bound<br>
+      Use DBL_MAX for infinity. */
+  virtual void setColUpper( int elementIndex, double elementValue );
+  
+  /** Set a single column lower and upper bound */
+  virtual void setColBounds( int elementIndex,
+                             double lower, double upper );
+  
+  /** Set the bounds on a number of columns simultaneously<br>
+      The default implementation just invokes setColLower() and
+      setColUpper() over and over again.
+      @param indexFirst,indexLast pointers to the beginning and after the
+      end of the array of the indices of the variables whose
+      <em>either</em> bound changes
+      @param boundList the new lower/upper bound pairs for the variables
+  */
+  virtual void setColSetBounds(const int* indexFirst,
+                               const int* indexLast,
+                               const double* boundList);
+  
+  /** Set a single row lower bound<br>
+      Use -DBL_MAX for -infinity. */
+  virtual void setRowLower( int elementIndex, double elementValue );
+  
+  /** Set a single row upper bound<br>
+      Use DBL_MAX for infinity. */
+  virtual void setRowUpper( int elementIndex, double elementValue ) ;
+  
+  /** Set a single row lower and upper bound */
+  virtual void setRowBounds( int elementIndex,
+                             double lower, double upper ) ;
+  
+  /** Set the type of a single row<br> */
+  virtual void setRowType(int index, char sense, double rightHandSide,
+                          double range);
+  
+  /** Set the bounds on a number of rows simultaneously<br>
+      The default implementation just invokes setRowLower() and
+      setRowUpper() over and over again.
+      @param indexFirst,indexLast pointers to the beginning and after the
+      end of the array of the indices of the constraints whose
+      <em>either</em> bound changes
+      @param boundList the new lower/upper bound pairs for the constraints
+  */
+  virtual void setRowSetBounds(const int* indexFirst,
+                               const int* indexLast,
+                               const double* boundList);
+  
+  /** Set the type of a number of rows simultaneously<br>
+      The default implementation just invokes setRowType()
+      over and over again.
+      @param indexFirst,indexLast pointers to the beginning and after the
+      end of the array of the indices of the constraints whose
+      <em>any</em> characteristics changes
+      @param senseList the new senses
+      @param rhsList   the new right hand sides
+      @param rangeList the new ranges
+  */
+  virtual void setRowSetTypes(const int* indexFirst,
+                              const int* indexLast,
+                              const char* senseList,
+                              const double* rhsList,
+                              const double* rangeList);
+    /** Set the objective coefficients for all columns
+	array [getNumCols()] is an array of values for the objective.
+        This defaults to a series of set operations and is here for speed.
+    */
+    virtual void setObjective(const double * array);
+
+    /** Set the lower bounds for all columns
+	array [getNumCols()] is an array of values for the objective.
+        This defaults to a series of set operations and is here for speed.
+    */
+    virtual void setColLower(const double * array);
+
+    /** Set the upper bounds for all columns
+	array [getNumCols()] is an array of values for the objective.
+        This defaults to a series of set operations and is here for speed.
+    */
+    virtual void setColUpper(const double * array);
+
+//    using OsiSolverInterface::setRowName ;
+    /// Set name of row
+//    virtual void setRowName(int rowIndex, std::string & name) ;
+    virtual void setRowName(int rowIndex, std::string  name) ;
+    
+//    using OsiSolverInterface::setColName ;
+    /// Set name of column
+//    virtual void setColName(int colIndex, std::string & name) ;
+    virtual void setColName(int colIndex, std::string  name) ;
+    
+  //@}
+  
+  //-------------------------------------------------------------------------
+  /**@name Integrality related changing methods */
+  //@{
+  /** Set the index-th variable to be a continuous variable */
+  virtual void setContinuous(int index);
+  /** Set the index-th variable to be an integer variable */
+  virtual void setInteger(int index);
+  /** Set the variables listed in indices (which is of length len) to be
+      continuous variables */
+  virtual void setContinuous(const int* indices, int len);
+  /** Set the variables listed in indices (which is of length len) to be
+      integer variables */
+  virtual void setInteger(const int* indices, int len);
+  /// Number of SOS sets
+  inline int numberSOS() const
+  { return numberSOS_;}
+  /// SOS set info
+  inline const CoinSet * setInfo() const
+  { return setInfo_;}
+  /** \brief Identify integer variables and SOS and create corresponding objects.
+  
+    Record integer variables and create an OsiSimpleInteger object for each
+    one.  All existing OsiSimpleInteger objects will be destroyed.
+    If the solver supports SOS then do the same for SOS.
+     If justCount then no objects created and we just store numberIntegers_
+    Returns number of SOS
+  */
+
+  virtual int findIntegersAndSOS(bool justCount);
+  //@}
+  
+  //-------------------------------------------------------------------------
+  /// Set objective function sense (1 for min (default), -1 for max,)
+  virtual void setObjSense(double s ) 
+  { modelPtr_->setOptimizationDirection( s < 0 ? -1 : 1); }
+  
+  /** Set the primal solution column values
+      
+  colsol[numcols()] is an array of values of the problem column
+  variables. These values are copied to memory owned by the
+  solver object or the solver.  They will be returned as the
+  result of colsol() until changed by another call to
+  setColsol() or by a call to any solver routine.  Whether the
+  solver makes use of the solution in any way is
+  solver-dependent. 
+  */
+  virtual void setColSolution(const double * colsol);
+  
+  /** Set dual solution vector
+      
+  rowprice[numrows()] is an array of values of the problem row
+  dual variables. These values are copied to memory owned by the
+  solver object or the solver.  They will be returned as the
+  result of rowprice() until changed by another call to
+  setRowprice() or by a call to any solver routine.  Whether the
+  solver makes use of the solution in any way is
+  solver-dependent. 
+  */
+  virtual void setRowPrice(const double * rowprice);
+  
+  //-------------------------------------------------------------------------
+  /**@name Methods to expand a problem.<br>
+     Note that if a column is added then by default it will correspond to a
+     continuous variable. */
+  //@{
+
+  //using OsiSolverInterface::addCol ;
+  /** */
+  virtual void addCol(const CoinPackedVectorBase& vec,
+                      const double collb, const double colub,   
+                      const double obj);
+  /*! \brief Add a named column (primal variable) to the problem.
+  */
+  virtual void addCol(const CoinPackedVectorBase& vec,
+		      const double collb, const double colub,   
+		      const double obj, std::string name) ;
+  /** Add a column (primal variable) to the problem. */
+  virtual void addCol(int numberElements, const int * rows, const double * elements,
+                      const double collb, const double colub,   
+                      const double obj) ;
+  /*! \brief Add a named column (primal variable) to the problem.
+   */
+  virtual void addCol(int numberElements,
+		      const int* rows, const double* elements,
+		      const double collb, const double colub,   
+		      const double obj, std::string name) ;
+  /** */
+  virtual void addCols(const int numcols,
+                       const CoinPackedVectorBase * const * cols,
+                       const double* collb, const double* colub,   
+                       const double* obj);
+  /**  */
+  virtual void addCols(const int numcols,
+		       const int * columnStarts, const int * rows, const double * elements,
+		       const double* collb, const double* colub,   
+		       const double* obj);
+  /** */
+  virtual void deleteCols(const int num, const int * colIndices);
+  
+  /** */
+  virtual void addRow(const CoinPackedVectorBase& vec,
+                      const double rowlb, const double rowub);
+  /** */
+    /*! \brief Add a named row (constraint) to the problem.
+    
+      The default implementation adds the row, then changes the name. This
+      can surely be made more efficient within an OsiXXX class.
+    */
+    virtual void addRow(const CoinPackedVectorBase& vec,
+			const double rowlb, const double rowub,
+			std::string name) ;
+  virtual void addRow(const CoinPackedVectorBase& vec,
+                      const char rowsen, const double rowrhs,   
+                      const double rowrng);
+  /** Add a row (constraint) to the problem. */
+  virtual void addRow(int numberElements, const int * columns, const double * element,
+		      const double rowlb, const double rowub) ;
+    /*! \brief Add a named row (constraint) to the problem.
+    */
+    virtual void addRow(const CoinPackedVectorBase& vec,
+			const char rowsen, const double rowrhs,   
+			const double rowrng, std::string name) ;
+  /** */
+  virtual void addRows(const int numrows,
+                       const CoinPackedVectorBase * const * rows,
+                       const double* rowlb, const double* rowub);
+  /** */
+  virtual void addRows(const int numrows,
+                       const CoinPackedVectorBase * const * rows,
+                       const char* rowsen, const double* rowrhs,   
+                       const double* rowrng);
+
+  /** */
+  virtual void addRows(const int numrows,
+		       const int * rowStarts, const int * columns, const double * element,
+		       const double* rowlb, const double* rowub);
+  ///
+  void modifyCoefficient(int row, int column, double newElement,
+			bool keepZero=false)
+	{modelPtr_->modifyCoefficient(row,column,newElement, keepZero);}
+
+  /** */
+  virtual void deleteRows(const int num, const int * rowIndices);
+  /**  If solver wants it can save a copy of "base" (continuous) model here
+   */
+  virtual void saveBaseModel() ;
+  /**  Strip off rows to get to this number of rows.
+       If solver wants it can restore a copy of "base" (continuous) model here
+  */
+  virtual void restoreBaseModel(int numberRows);
+  
+  //-----------------------------------------------------------------------
+  /** Apply a collection of row cuts which are all effective.
+      applyCuts seems to do one at a time which seems inefficient.
+  */
+  virtual void applyRowCuts(int numberCuts, const OsiRowCut * cuts);
+  /** Apply a collection of row cuts which are all effective.
+      applyCuts seems to do one at a time which seems inefficient.
+      This uses array of pointers
+  */
+  virtual void applyRowCuts(int numberCuts, const OsiRowCut ** cuts);
+    /** Apply a collection of cuts.
+
+	Only cuts which have an <code>effectiveness >= effectivenessLb</code>
+	are applied.
+	<ul>
+	  <li> ReturnCode.getNumineffective() -- number of cuts which were
+	       not applied because they had an
+	       <code>effectiveness < effectivenessLb</code>
+	  <li> ReturnCode.getNuminconsistent() -- number of invalid cuts
+	  <li> ReturnCode.getNuminconsistentWrtIntegerModel() -- number of
+	       cuts that are invalid with respect to this integer model
+	  <li> ReturnCode.getNuminfeasible() -- number of cuts that would
+	       make this integer model infeasible
+	  <li> ReturnCode.getNumApplied() -- number of integer cuts which
+	       were applied to the integer model
+	  <li> cs.size() == getNumineffective() +
+			    getNuminconsistent() +
+			    getNuminconsistentWrtIntegerModel() +
+			    getNuminfeasible() +
+			    getNumApplied()
+	</ul>
+    */
+    virtual ApplyCutsReturnCode applyCuts(const OsiCuts & cs,
+					  double effectivenessLb = 0.0);
+
+  //@}
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+public:
+  
+  /**@name Methods to input a problem */
+  //@{
+  /** Load in an problem by copying the arguments (the constraints on the
+      rows are given by lower and upper bounds). If a pointer is NULL then the
+      following values are the default:
+      <ul>
+      <li> <code>colub</code>: all columns have upper bound infinity
+      <li> <code>collb</code>: all columns have lower bound 0 
+      <li> <code>rowub</code>: all rows have upper bound infinity
+      <li> <code>rowlb</code>: all rows have lower bound -infinity
+      <li> <code>obj</code>: all variables have 0 objective coefficient
+      </ul>
+  */
+  virtual void loadProblem(const CoinPackedMatrix& matrix,
+                           const double* collb, const double* colub,   
+                           const double* obj,
+                           const double* rowlb, const double* rowub);
+  
+  /** Load in an problem by assuming ownership of the arguments (the
+      constraints on the rows are given by lower and upper bounds). For
+      default values see the previous method.  <br>
+      <strong>WARNING</strong>: The arguments passed to this method will be
+      freed using the C++ <code>delete</code> and <code>delete[]</code>
+      functions. 
+  */
+  virtual void assignProblem(CoinPackedMatrix*& matrix,
+    			     double*& collb, double*& colub, double*& obj,
+    			     double*& rowlb, double*& rowub);
+  
+  /** Load in an problem by copying the arguments (the constraints on the
+      rows are given by sense/rhs/range triplets). If a pointer is NULL then the
+      following values are the default:
+      <ul>
+      <li> <code>colub</code>: all columns have upper bound infinity
+      <li> <code>collb</code>: all columns have lower bound 0 
+      <li> <code>obj</code>: all variables have 0 objective coefficient
+      <li> <code>rowsen</code>: all rows are >=
+      <li> <code>rowrhs</code>: all right hand sides are 0
+      <li> <code>rowrng</code>: 0 for the ranged rows
+      </ul>
+  */
+  virtual void loadProblem(const CoinPackedMatrix& matrix,
+    			   const double* collb, const double* colub,
+    			   const double* obj,
+    			   const char* rowsen, const double* rowrhs,   
+    			   const double* rowrng);
+  
+  /** Load in an problem by assuming ownership of the arguments (the
+      constraints on the rows are given by sense/rhs/range triplets). For
+      default values see the previous method. <br>
+      <strong>WARNING</strong>: The arguments passed to this method will be
+      freed using the C++ <code>delete</code> and <code>delete[]</code>
+      functions. 
+  */
+  virtual void assignProblem(CoinPackedMatrix*& matrix,
+    			     double*& collb, double*& colub, double*& obj,
+    			     char*& rowsen, double*& rowrhs,
+    			     double*& rowrng);
+  
+  /** Just like the other loadProblem() methods except that the matrix is
+      given as a ClpMatrixBase. */
+  virtual void loadProblem(const ClpMatrixBase& matrix,
+			   const double* collb, const double* colub,
+			   const double* obj,
+			   const double* rowlb, const double* rowub) ;
+
+  /** Just like the other loadProblem() methods except that the matrix is
+      given in a standard column major ordered format (without gaps). */
+  virtual void loadProblem(const int numcols, const int numrows,
+                           const CoinBigIndex * start, const int* index,
+                           const double* value,
+                           const double* collb, const double* colub,   
+                           const double* obj,
+                           const double* rowlb, const double* rowub);
+  
+  /** Just like the other loadProblem() methods except that the matrix is
+      given in a standard column major ordered format (without gaps). */
+  virtual void loadProblem(const int numcols, const int numrows,
+                           const CoinBigIndex * start, const int* index,
+                           const double* value,
+                           const double* collb, const double* colub,   
+                           const double* obj,
+                           const char* rowsen, const double* rowrhs,   
+                           const double* rowrng);
+  /// This loads a model from a coinModel object - returns number of errors
+  virtual int loadFromCoinModel (  CoinModel & modelObject, bool keepSolution=false);
+
+  using OsiSolverInterface::readMps ;
+  /** Read an mps file from the given filename (defaults to Osi reader) - returns
+      number of errors (see OsiMpsReader class) */
+  virtual int readMps(const char *filename,
+                      const char *extension = "mps") ;
+  /** Read an mps file from the given filename returns
+      number of errors (see OsiMpsReader class) */
+  int readMps(const char *filename,bool keepNames,bool allowErrors);
+  /// Read an mps file
+  virtual int readMps (const char *filename, const char*extension,
+			int & numberSets, CoinSet ** & sets);
+  
+  /** Write the problem into an mps file of the given filename.
+      If objSense is non zero then -1.0 forces the code to write a
+      maximization objective and +1.0 to write a minimization one.
+      If 0.0 then solver can do what it wants */
+  virtual void writeMps(const char *filename,
+                        const char *extension = "mps",
+                        double objSense=0.0) const;
+  /** Write the problem into an mps file of the given filename,
+      names may be null.  formatType is
+      0 - normal
+      1 - extra accuracy 
+      2 - IEEE hex (later)
+      
+      Returns non-zero on I/O error
+  */
+  virtual int writeMpsNative(const char *filename, 
+                             const char ** rowNames, const char ** columnNames,
+                             int formatType=0,int numberAcross=2,
+                             double objSense=0.0) const ;
+  /// Read file in LP format (with names)
+  virtual int readLp(const char *filename, const double epsilon = 1e-5);
+  /** Write the problem into an Lp file of the given filename.
+      If objSense is non zero then -1.0 forces the code to write a
+      maximization objective and +1.0 to write a minimization one.
+      If 0.0 then solver can do what it wants.
+      This version calls writeLpNative with names */
+  virtual void writeLp(const char *filename,
+                       const char *extension = "lp",
+                       double epsilon = 1e-5,
+                       int numberAcross = 10,
+                       int decimals = 5,
+                       double objSense = 0.0,
+                       bool useRowNames = true) const;
+  /** Write the problem into the file pointed to by the parameter fp. 
+      Other parameters are similar to 
+      those of writeLp() with first parameter filename.
+  */
+  virtual void writeLp(FILE *fp,
+               double epsilon = 1e-5,
+               int numberAcross = 10,
+               int decimals = 5,
+               double objSense = 0.0,
+	       bool useRowNames = true) const;
+  /**
+     I (JJF) am getting annoyed because I can't just replace a matrix.
+     The default behavior of this is do nothing so only use where that would not matter
+     e.g. strengthening a matrix for MIP
+  */
+  virtual void replaceMatrixOptional(const CoinPackedMatrix & matrix);
+  /// And if it does matter (not used at present)
+  virtual void replaceMatrix(const CoinPackedMatrix & matrix) ;
+  //@}
+  
+  /**@name Message handling (extra for Clp messages).
+     Normally I presume you would want the same language.
+     If not then you could use underlying model pointer */
+  //@{
+  /** Pass in a message handler
+      
+      It is the client's responsibility to destroy a message handler installed
+      by this routine; it will not be destroyed when the solver interface is
+      destroyed. 
+  */
+  virtual void passInMessageHandler(CoinMessageHandler * handler);
+  /// Set language
+  void newLanguage(CoinMessages::Language language);
+  void setLanguage(CoinMessages::Language language)
+  {newLanguage(language);}
+  /// Set log level (will also set underlying solver's log level)
+  void setLogLevel(int value);
+  /// Create C++ lines to get to current state
+  void generateCpp( FILE * fp);
+  //@}
+  //---------------------------------------------------------------------------
+  
+  /**@name Clp specific public interfaces */
+  //@{
+  /// Get pointer to Clp model
+  ClpSimplex * getModelPtr() const ;
+  /// Set pointer to Clp model and return old
+  inline ClpSimplex * swapModelPtr(ClpSimplex * newModel)
+  { ClpSimplex * model = modelPtr_; modelPtr_=newModel;return model;}
+  /// Get special options
+  inline unsigned int specialOptions() const
+  { return specialOptions_;}
+  void setSpecialOptions(unsigned int value);
+  /// Last algorithm used , 1 = primal, 2 = dual other unknown
+  inline int lastAlgorithm() const
+  { return lastAlgorithm_;}
+  /// Set last algorithm used , 1 = primal, 2 = dual other unknown
+  inline void setLastAlgorithm(int value)
+  { lastAlgorithm_ = value;}
+  /// Get scaling action option
+  inline int cleanupScaling() const
+  { return cleanupScaling_;}
+  /** Set Scaling option
+      When scaling is on it is possible that the scaled problem
+      is feasible but the unscaled is not.  Clp returns a secondary
+      status code to that effect.  This option allows for a cleanup.
+      If you use it I would suggest 1.
+      This only affects actions when scaled optimal
+      0 - no action
+      1 - clean up using dual if primal infeasibility
+      2 - clean up using dual if dual infeasibility
+      3 - clean up using dual if primal or dual infeasibility
+      11,12,13 - as 1,2,3 but use primal
+  */
+  inline void setCleanupScaling(int value)
+  { cleanupScaling_=value;}
+  /** Get smallest allowed element in cut.
+      If smaller than this then ignored */
+  inline double smallestElementInCut() const
+  { return smallestElementInCut_;}
+  /** Set smallest allowed element in cut.
+      If smaller than this then ignored */
+  inline void setSmallestElementInCut(double value)
+  { smallestElementInCut_=value;}
+  /** Get smallest change in cut.
+      If (upper-lower)*element < this then element is
+      taken out and cut relaxed. 
+      (upper-lower) is taken to be at least 1.0 and
+      this is assumed >= smallestElementInCut_
+  */
+  inline double smallestChangeInCut() const
+  { return smallestChangeInCut_;}
+  /** Set smallest change in cut.
+      If (upper-lower)*element < this then element is
+      taken out and cut relaxed. 
+      (upper-lower) is taken to be at least 1.0 and
+      this is assumed >= smallestElementInCut_
+  */
+  inline void setSmallestChangeInCut(double value)
+  { smallestChangeInCut_=value;}
+  /// Pass in initial solve options
+  inline void setSolveOptions(const ClpSolve & options)
+  { solveOptions_ = options;}
+  /** Tighten bounds - lightweight or very lightweight
+      0 - normal, 1 lightweight but just integers, 2 lightweight and all
+  */
+  virtual int tightenBounds(int lightweight=0);
+  /// Return number of entries in L part of current factorization
+  virtual CoinBigIndex getSizeL() const;
+  /// Return number of entries in U part of current factorization
+  virtual CoinBigIndex getSizeU() const;
+  /// Get disaster handler
+  const OsiClpDisasterHandler * disasterHandler() const
+  { return disasterHandler_;}
+  /// Pass in disaster handler
+  void passInDisasterHandler(OsiClpDisasterHandler * handler);
+  /// Get fake objective
+  ClpLinearObjective * fakeObjective() const
+  { return fakeObjective_;}
+  /// Set fake objective (and take ownership)
+  void setFakeObjective(ClpLinearObjective * fakeObjective);
+  /// Set fake objective
+  void setFakeObjective(double * fakeObjective);
+  /*! \brief Set up solver for repeated use by Osi interface.
+
+    The normal usage does things like keeping factorization around so can be
+    used.  Will also do things like keep scaling and row copy of matrix if
+    matrix does not change.
+
+    \p senseOfAdventure:
+    - 0 - safe stuff as above
+    - 1 - will take more risks - if it does not work then bug which will be
+          fixed
+    - 2 - don't bother doing most extreme termination checks e.g. don't bother
+	  re-factorizing if less than 20 iterations.
+    - 3 - Actually safer than 1 (mainly just keeps factorization)
+      
+    \p printOut
+    - -1 always skip round common messages instead of doing some work
+    -  0 skip if normal defaults
+    -  1 leaves
+  */
+  void setupForRepeatedUse(int senseOfAdventure=0, int printOut=0);
+  /// Synchronize model (really if no cuts in tree)
+  virtual void synchronizeModel();
+  /*! \brief Set special options in underlying clp solver.
+
+    Safe as const because #modelPtr_ is mutable.
+  */
+  void setSpecialOptionsMutable(unsigned int value) const;
+
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+  /**@name Constructors and destructors */
+  //@{
+  /// Default Constructor
+  OsiClpSolverInterface ();
+  
+  /// Clone
+  virtual OsiSolverInterface * clone(bool copyData = true) const;
+  
+  /// Copy constructor 
+  OsiClpSolverInterface (const OsiClpSolverInterface &);
+  
+  /// Borrow constructor - only delete one copy
+  OsiClpSolverInterface (ClpSimplex * rhs, bool reallyOwn=false);
+  
+  /// Releases so won't error
+  void releaseClp();
+  
+  /// Assignment operator 
+  OsiClpSolverInterface & operator=(const OsiClpSolverInterface& rhs);
+  
+  /// Destructor 
+  virtual ~OsiClpSolverInterface ();
+  
+  /// Resets as if default constructor
+  virtual void reset();
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+protected:
+  ///@name Protected methods
+  //@{
+  /** Apply a row cut (append to constraint matrix). */
+  virtual void applyRowCut(const OsiRowCut& rc);
+  
+  /** Apply a column cut (adjust one or more bounds). */
+  virtual void applyColCut(const OsiColCut& cc);
+  //@}
+  
+  //---------------------------------------------------------------------------
+  
+protected:
+  /**@name Protected methods */
+  //@{
+  /// The real work of a copy constructor (used by copy and assignment)
+  void gutsOfDestructor();
+  
+  /// Deletes all mutable stuff
+  void freeCachedResults() const;
+  
+  /// Deletes all mutable stuff for row ranges etc
+  void freeCachedResults0() const;
+  
+  /// Deletes all mutable stuff for matrix etc
+  void freeCachedResults1() const;
+  
+  /// A method that fills up the rowsense_, rhs_ and rowrange_ arrays
+  void extractSenseRhsRange() const;
+  
+  ///
+  void fillParamMaps();
+  /** Warm start
+      
+  NOTE  artificials are treated as +1 elements so for <= rhs
+  artificial will be at lower bound if constraint is tight
+  
+  This means that Clpsimplex flips artificials as it works
+  in terms of row activities
+  */
+  CoinWarmStartBasis getBasis(ClpSimplex * model) const;
+  /** Sets up working basis as a copy of input
+      
+  NOTE  artificials are treated as +1 elements so for <= rhs
+  artificial will be at lower bound if constraint is tight
+  
+  This means that Clpsimplex flips artificials as it works
+  in terms of row activities
+  */
+  void setBasis( const CoinWarmStartBasis & basis, ClpSimplex * model);
+  /// Crunch down problem a bit
+  void crunch();
+  /// Extend scale factors
+  void redoScaleFactors(int numberRows,const CoinBigIndex * starts,
+			const int * indices, const double * elements);
+public:
+  /** Sets up working basis as a copy of input and puts in as basis
+  */
+  void setBasis( const CoinWarmStartBasis & basis);
+  /// Just puts current basis_ into ClpSimplex model
+  inline void setBasis( )
+  { setBasis(basis_,modelPtr_);}
+  /// Warm start difference from basis_ to statusArray
+  CoinWarmStartDiff * getBasisDiff(const unsigned char * statusArray) const ;
+  /// Warm start from statusArray
+  CoinWarmStartBasis * getBasis(const unsigned char * statusArray) const ;
+  /// Delete all scale factor stuff and reset option
+  void deleteScaleFactors();
+  /// If doing fast hot start then ranges are computed
+  inline const double * upRange() const
+  { return rowActivity_;}
+  inline const double * downRange() const
+  { return columnActivity_;}
+  /// Pass in range array
+  inline void passInRanges(int * array)
+  { whichRange_=array;}
+  /// Pass in sos stuff from AMPl
+  void setSOSData(int numberSOS,const char * type,
+		  const int * start,const int * indices, const double * weights=NULL);
+  /// Compute largest amount any at continuous away from bound
+  void computeLargestAway();
+  /// Get largest amount continuous away from bound
+  inline double largestAway() const
+  { return largestAway_;}
+  /// Set largest amount continuous away from bound
+  inline void setLargestAway(double value)
+  { largestAway_ = value;}
+  /// Sort of lexicographic resolve
+  void lexSolve();
+  //@}
+  
+protected:
+  /**@name Protected member data */
+  //@{
+  /// Clp model represented by this class instance
+  mutable ClpSimplex * modelPtr_;
+  //@}
+  /**@name Cached information derived from the OSL model */
+  //@{
+  /// Pointer to dense vector of row sense indicators
+  mutable char    *rowsense_;
+  
+  /// Pointer to dense vector of row right-hand side values
+  mutable double  *rhs_;
+  
+  /** Pointer to dense vector of slack upper bounds for range 
+      constraints (undefined for non-range rows)
+  */
+  mutable double  *rowrange_;
+  
+  /** A pointer to the warmstart information to be used in the hotstarts.
+      This is NOT efficient and more thought should be given to it... */
+  mutable CoinWarmStartBasis* ws_;
+  /** also save row and column information for hot starts
+      only used in hotstarts so can be casual */
+  mutable double * rowActivity_;
+  mutable double * columnActivity_;
+  /// Stuff for fast dual
+  ClpNodeStuff stuff_;
+  /// Number of SOS sets
+  int numberSOS_;
+  /// SOS set info
+  CoinSet * setInfo_;
+  /// Alternate model (hot starts) - but also could be permanent and used for crunch
+  ClpSimplex * smallModel_;
+  /// factorization for hot starts
+  ClpFactorization * factorization_;
+  /** Smallest allowed element in cut.
+      If smaller than this then ignored */
+  double smallestElementInCut_;
+  /** Smallest change in cut.
+      If (upper-lower)*element < this then element is
+      taken out and cut relaxed. */
+  double smallestChangeInCut_;
+  /// Largest amount continuous away from bound
+  double largestAway_;
+  /// Arrays for hot starts
+  char * spareArrays_;
+  /** Warmstart information to be used in resolves. */
+  CoinWarmStartBasis basis_;
+  /** The original iteration limit before hotstarts started. */
+  int itlimOrig_;
+  
+  /*! \brief Last algorithm used
+  
+    Coded as
+    -    0 invalid
+    -    1 primal
+    -    2 dual
+    - -911 disaster in the algorithm that was attempted
+    -  999 current solution no longer optimal due to change in problem or
+           basis
+  */
+  mutable int lastAlgorithm_;
+  
+  /// To say if destructor should delete underlying model
+  bool notOwned_;
+  
+  /// Pointer to row-wise copy of problem matrix coefficients.
+  mutable CoinPackedMatrix *matrixByRow_;  
+  
+  /// Pointer to row-wise copy of continuous problem matrix coefficients.
+  CoinPackedMatrix *matrixByRowAtContinuous_;  
+  
+  /// Pointer to integer information
+  char * integerInformation_;
+  
+  /** Pointer to variables for which we want range information
+      The number is in [0]
+      memory is not owned by OsiClp
+  */
+  int * whichRange_;
+
+  //std::map<OsiIntParam, ClpIntParam> intParamMap_;
+  //std::map<OsiDblParam, ClpDblParam> dblParamMap_;
+  //std::map<OsiStrParam, ClpStrParam> strParamMap_;
+  
+  /*! \brief Faking min to get proper dual solution signs in simplex API */
+  mutable bool fakeMinInSimplex_ ;
+  /*! \brief Linear objective
+  
+    Normally a pointer to the linear coefficient array in the clp objective.
+    An independent copy when #fakeMinInSimplex_ is true, because we need
+    something permanent to point to when #getObjCoefficients is called.
+  */
+  mutable double *linearObjective_;
+
+  /// To save data in OsiSimplex stuff
+  mutable ClpDataSave saveData_;
+  /// Options for initialSolve
+  ClpSolve solveOptions_;
+  /** Scaling option
+      When scaling is on it is possible that the scaled problem
+      is feasible but the unscaled is not.  Clp returns a secondary
+      status code to that effect.  This option allows for a cleanup.
+      If you use it I would suggest 1.
+      This only affects actions when scaled optimal
+      0 - no action
+      1 - clean up using dual if primal infeasibility
+      2 - clean up using dual if dual infeasibility
+      3 - clean up using dual if primal or dual infeasibility
+      11,12,13 - as 1,2,3 but use primal
+  */
+  int cleanupScaling_;
+  /** Special options
+      0x80000000 off
+      0 simple stuff for branch and bound
+      1 try and keep work regions as much as possible
+      2 do not use any perturbation
+      4 allow exit before re-factorization
+      8 try and re-use factorization if no cuts
+      16 use standard strong branching rather than clp's
+      32 Just go to first factorization in fast dual
+      64 try and tighten bounds in crunch
+      128 Model will only change in column bounds
+      256 Clean up model before hot start
+      512 Give user direct access to Clp regions in getBInvARow etc (i.e.,
+          do not unscale, and do not return result in getBInv parameters;
+	  you have to know where to look for the answer)
+      1024 Don't "borrow" model in initialSolve
+      2048 Don't crunch
+      4096 quick check for optimality
+      Bits above 8192 give where called from in Cbc
+      At present 0 is normal, 1 doing fast hotstarts, 2 is can do quick check
+      65536 Keep simple i.e. no  crunch etc
+      131072 Try and keep scaling factors around
+      262144 Don't try and tighten bounds (funny global cuts)
+      524288 Fake objective and 0-1
+      1048576 Don't recompute ray after crunch
+      2097152 
+  */
+  mutable unsigned int specialOptions_;
+  /// Copy of model when option 131072 set
+  ClpSimplex * baseModel_;
+  /// Number of rows when last "scaled"
+  int lastNumberRows_;
+  /// Continuous model
+  ClpSimplex * continuousModel_;
+  /// Possible disaster handler
+  OsiClpDisasterHandler * disasterHandler_ ;
+  /// Fake objective
+  ClpLinearObjective * fakeObjective_;
+  /// Row scale factors (has inverse at end)
+  CoinDoubleArrayWithLength rowScale_; 
+  /// Column scale factors (has inverse at end)
+  CoinDoubleArrayWithLength columnScale_; 
+  //@}
+};
+  
+class OsiClpDisasterHandler : public ClpDisasterHandler {
+public:
+  /**@name Virtual methods that the derived classe should provide.
+  */
+  //@{
+  /// Into simplex
+  virtual void intoSimplex();
+  /// Checks if disaster
+  virtual bool check() const ;
+  /// saves information for next attempt
+  virtual void saveInfo();
+  /// Type of disaster 0 can fix, 1 abort
+  virtual int typeOfDisaster();
+  //@}
+  
+  
+  /**@name Constructors, destructor */
+
+  //@{
+  /** Default constructor. */
+  OsiClpDisasterHandler(OsiClpSolverInterface * model = NULL);
+  /** Destructor */
+  virtual ~OsiClpDisasterHandler();
+  // Copy
+  OsiClpDisasterHandler(const OsiClpDisasterHandler&);
+  // Assignment
+  OsiClpDisasterHandler& operator=(const OsiClpDisasterHandler&);
+  /// Clone
+  virtual ClpDisasterHandler * clone() const;
+
+  //@}
+  
+  /**@name Sets/gets */
+
+  //@{
+  /** set model. */
+  void setOsiModel(OsiClpSolverInterface * model);
+  /// Get model
+  inline OsiClpSolverInterface * osiModel() const
+  { return osiModel_;}
+  /// Set where from
+  inline void setWhereFrom(int value)
+  { whereFrom_=value;}
+  /// Get where from
+  inline int whereFrom() const
+  { return whereFrom_;}
+  /// Set phase 
+  inline void setPhase(int value)
+  { phase_=value;}
+  /// Get phase 
+  inline int phase() const
+  { return phase_;}
+  /// are we in trouble
+  inline bool inTrouble() const
+  { return inTrouble_;}
+  
+  //@}
+  
+  
+protected:
+  /**@name Data members
+     The data members are protected to allow access for derived classes. */
+  //@{
+  /// Pointer to model
+  OsiClpSolverInterface * osiModel_;
+  /** Where from 
+      0 dual (resolve)
+      1 crunch
+      2 primal (resolve)
+      4 dual (initialSolve)
+      6 primal (initialSolve)
+  */
+  int whereFrom_;
+  /** phase
+      0 initial
+      1 trying continuing with back in and maybe different perturb
+      2 trying continuing with back in and different scaling
+      3 trying dual from all slack
+      4 trying primal from previous stored basis
+  */
+  int phase_;
+  /// Are we in trouble
+  bool inTrouble_;
+  //@}
+};
+// So unit test can find out if NDEBUG set
+bool OsiClpHasNDEBUG();
+//#############################################################################
+/** A function that tests the methods in the OsiClpSolverInterface class. */
+void OsiClpSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir);
+#endif
diff --git a/cbits/coin/OsiColCut.cpp b/cbits/coin/OsiColCut.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiColCut.cpp
@@ -0,0 +1,124 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "OsiColCut.hpp"
+#include <cstdlib>
+#include <cstdio>
+#include <iostream>
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiColCut::OsiColCut() :
+   OsiCut(),
+   lbs_(),
+   ubs_()
+{
+  // nothing to do here
+}
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiColCut::OsiColCut(const OsiColCut & source) :
+   OsiCut(source),
+   lbs_(source.lbs_),
+   ubs_(source.ubs_)
+{  
+  // Nothing to do here
+}
+
+
+//----------------------------------------------------------------
+// Clone
+//----------------------------------------------------------------
+OsiColCut * OsiColCut::clone() const
+{ return (new OsiColCut(*this)); }
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiColCut::~OsiColCut ()
+{
+  // Nothing to do here
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiColCut &
+OsiColCut::operator=(const OsiColCut& rhs)
+{
+  if (this != &rhs) {
+    
+    OsiCut::operator=(rhs);
+    lbs_=rhs.lbs_;
+    ubs_=rhs.ubs_;
+  }
+  return *this;
+}
+//----------------------------------------------------------------
+// Print
+//-------------------------------------------------------------------
+
+void
+OsiColCut::print() const
+{
+  const CoinPackedVector & cutLbs = lbs();
+  const CoinPackedVector & cutUbs = ubs();
+  int i;
+  std::cout<<"Column cut has "
+	   <<cutLbs.getNumElements()
+	   <<" lower bound cuts and "
+	   <<cutUbs.getNumElements()
+	   <<" upper bound cuts"
+	   <<std::endl;
+  for ( i=0; i<cutLbs.getNumElements(); i++ ) {
+    int colIndx = cutLbs.getIndices()[i];
+    double newLb= cutLbs.getElements()[i];
+    std::cout<<"[ x"<<colIndx<<" >= "<<newLb<<"] ";
+  }
+  for ( i=0; i<cutUbs.getNumElements(); i++ ) {
+    int colIndx = cutUbs.getIndices()[i];
+    double newUb= cutUbs.getElements()[i];
+    std::cout<<"[ x"<<colIndx<<" <= "<<newUb<<"] ";
+  }
+  std::cout<<std::endl;
+}
+/* Returns infeasibility of the cut with respect to solution 
+    passed in i.e. is positive if cuts off that solution.  
+    solution is getNumCols() long..
+*/
+double 
+OsiColCut::violated(const double * solution) const
+{
+  const CoinPackedVector & cutLbs = lbs();
+  const CoinPackedVector & cutUbs = ubs();
+  double sum=0.0;
+  int i;
+  const int * column = cutLbs.getIndices();
+  int number = cutLbs.getNumElements();
+  const double * bound = cutLbs.getElements();
+  for ( i=0; i<number; i++ ) {
+    int colIndx = column[i];
+    double newLb = bound[i];
+    if (newLb>solution[colIndx])
+      sum += newLb - solution[colIndx];
+  }
+  column = cutUbs.getIndices();
+  number = cutUbs.getNumElements();
+  bound = cutUbs.getElements();
+  for ( i=0; i<number; i++ ) {
+    int colIndx = column[i];
+    double newUb = bound[i];
+    if (newUb<solution[colIndx])
+      sum +=  solution[colIndx] - newUb;
+  }
+  return sum;
+}
+
diff --git a/cbits/coin/OsiColCut.hpp b/cbits/coin/OsiColCut.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiColCut.hpp
@@ -0,0 +1,324 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiColCut_H
+#define OsiColCut_H
+
+#include <string>
+
+#include "CoinPackedVector.hpp"
+
+#include "OsiCollections.hpp"
+#include "OsiCut.hpp"
+
+/** Column Cut Class
+
+Column Cut Class has:
+  <ul>
+  <li>a sparse vector of column lower bounds
+  <li>a sparse vector of column upper bounds
+  </ul>
+*/
+class OsiColCut : public OsiCut {
+   friend void OsiColCutUnitTest(const OsiSolverInterface * baseSiP, 
+				 const std::string & mpsDir);
+  
+public:
+  
+  //----------------------------------------------------------------
+  
+  /**@name Setting column bounds */
+  //@{
+  /// Set column lower bounds 
+  inline void setLbs( 
+    int nElements, 
+    const int * colIndices, 
+    const double * lbElements );   
+  
+  /// Set column lower bounds from a packed vector
+  inline void setLbs( const CoinPackedVector & lbs );
+  
+  /// Set column upper bounds 
+  inline void setUbs( 
+    int nElements, 
+    const int * colIndices, 
+    const double * ubElements );
+  
+  /// Set column upper bounds from a packed vector
+  inline void setUbs( const CoinPackedVector & ubs );
+  //@}
+  
+  //----------------------------------------------------------------
+  
+  /**@name Getting column bounds */
+  //@{
+  /// Get column lower bounds
+  inline const CoinPackedVector & lbs() const;
+  /// Get column upper bounds
+  inline const CoinPackedVector & ubs() const;
+  //@}
+  
+  /**@name Comparison operators  */
+  //@{
+#if __GNUC__ != 2 
+  using OsiCut::operator== ;
+#endif
+  /** equal - true if lower bounds, upper bounds, 
+  and OsiCut are equal.
+  */
+  inline virtual bool operator==(const OsiColCut& rhs) const; 
+
+#if __GNUC__ != 2 
+  using OsiCut::operator!= ;
+#endif
+  /// not equal
+  inline virtual bool operator!=(const OsiColCut& rhs) const; 
+  //@}
+  
+  
+  //----------------------------------------------------------------
+  
+  /**@name Sanity checks on cut */
+  //@{
+  /** Returns true if the cut is consistent with respect to itself.
+  This checks to ensure that:
+  <ul>
+  <li>The bound vectors do not have duplicate indices,
+  <li>The bound vectors indices are >=0
+  </ul>
+  */
+  inline virtual bool consistent() const; 
+  
+  /** Returns true if cut is consistent with respect to the solver  
+  interface's model. This checks to ensure that
+  the lower & upperbound packed vectors:
+  <ul>
+  <li>do not have an index >= the number of column is the model.
+  </ul>
+  */
+  inline virtual bool consistent(const OsiSolverInterface& im) const;
+  
+  /** Returns true if the cut is infeasible with respect to its bounds and the 
+  column bounds in the solver interface's models.
+  This checks whether:
+  <ul>
+  <li>the maximum of the new and existing lower bounds is strictly 
+  greater than the minimum of the new and existing upper bounds.
+</ul>
+  */
+  inline virtual bool infeasible(const OsiSolverInterface &im) const;
+  /** Returns infeasibility of the cut with respect to solution 
+      passed in i.e. is positive if cuts off that solution.  
+      solution is getNumCols() long..
+  */
+  virtual double violated(const double * solution) const;
+  //@}
+  
+  //----------------------------------------------------------------
+  
+  /**@name Constructors and destructors */
+  //@{
+  /// Assignment operator 
+  OsiColCut & operator=( const OsiColCut& rhs);
+  
+  /// Copy constructor 
+  OsiColCut ( const OsiColCut &);
+  
+  /// Default Constructor 
+  OsiColCut ();
+  
+  /// Clone
+  virtual OsiColCut * clone() const;
+  
+  /// Destructor 
+  virtual ~OsiColCut ();
+  //@}
+  
+  /**@name Debug stuff */
+  //@{
+    /// Print cuts in collection
+  virtual void print() const;
+  //@}
+   
+private:
+  
+  /**@name Private member data */
+  //@{
+  /// Lower bounds
+  CoinPackedVector lbs_;
+  /// Upper bounds
+  CoinPackedVector ubs_;
+  //@}
+  
+};
+
+
+
+//-------------------------------------------------------------------
+// Set lower & upper bound vectors
+//------------------------------------------------------------------- 
+void OsiColCut::setLbs( 
+                       int size, 
+                       const int * colIndices, 
+                       const double * lbElements )
+{
+  lbs_.setVector(size,colIndices,lbElements);
+}
+//
+void OsiColCut::setUbs( 
+                       int size, 
+                       const int * colIndices, 
+                       const double * ubElements )
+{
+  ubs_.setVector(size,colIndices,ubElements);
+}
+//
+void OsiColCut::setLbs( const CoinPackedVector & lbs )
+{
+  lbs_ = lbs;
+}
+//
+void OsiColCut::setUbs( const CoinPackedVector & ubs )
+{
+  ubs_ = ubs;
+}
+
+//-------------------------------------------------------------------
+// Get Column Lower Bounds and Column Upper Bounds
+//-------------------------------------------------------------------
+const CoinPackedVector & OsiColCut::lbs() const 
+{ 
+  return lbs_; 
+}
+//
+const CoinPackedVector & OsiColCut::ubs() const 
+{ 
+  return ubs_; 
+}
+
+//----------------------------------------------------------------
+// == operator 
+//-------------------------------------------------------------------
+bool
+OsiColCut::operator==(
+                      const OsiColCut& rhs) const
+{
+  if ( this->OsiCut::operator!=(rhs) ) 
+    return false;
+  if ( lbs() != rhs.lbs() ) 
+    return false;
+  if ( ubs() != rhs.ubs() ) 
+    return false;
+  return true;
+}
+//
+bool
+OsiColCut::operator!=(
+                      const OsiColCut& rhs) const
+{
+  return !( (*this)==rhs );
+}
+
+//----------------------------------------------------------------
+// consistent & infeasible 
+//-------------------------------------------------------------------
+bool OsiColCut::consistent() const
+{
+  const CoinPackedVector & lb = lbs();
+  const CoinPackedVector & ub = ubs();
+  // Test for consistent cut.
+  // Are packed vectors consistent?
+  lb.duplicateIndex("consistent", "OsiColCut");
+  ub.duplicateIndex("consistent", "OsiColCut");
+  if ( lb.getMinIndex() < 0 ) return false;
+  if ( ub.getMinIndex() < 0 ) return false;
+  return true;
+}
+//
+bool OsiColCut::consistent(const OsiSolverInterface& im) const
+{  
+  const CoinPackedVector & lb = lbs();
+  const CoinPackedVector & ub = ubs();
+  
+  // Test for consistent cut.
+  if ( lb.getMaxIndex() >= im.getNumCols() ) return false;
+  if ( ub.getMaxIndex() >= im.getNumCols() ) return false;
+  
+  return true;
+}
+
+#if 0
+bool OsiColCut::feasible(const OsiSolverInterface &im) const
+{
+  const double * oldColLb = im.getColLower();
+  const double * oldColUb = im.getColUpper();
+  const CoinPackedVector & cutLbs = lbs();
+  const CoinPackedVector & cutUbs = ubs();
+  int i;
+  
+  for ( i=0; i<cutLbs.size(); i++ ) {
+    int colIndx = cutLbs.indices()[i];
+    double newLb;
+    if ( cutLbs.elements()[i] > oldColLb[colIndx] )
+      newLb = cutLbs.elements()[i];
+    else
+      newLb = oldColLb[colIndx];
+
+    double newUb = oldColUb[colIndx];
+    if ( cutUbs.indexExists(colIndx) )
+      if ( cutUbs[colIndx] < newUb ) newUb = cutUbs[colIndx];
+      if ( newLb > newUb ) 
+        return false;
+  }
+  
+  for ( i=0; i<cutUbs.size(); i++ ) {
+    int colIndx = cutUbs.indices()[i];
+    double newUb = cutUbs.elements()[i] < oldColUb[colIndx] ? cutUbs.elements()[i] : oldColUb[colIndx];
+    double newLb = oldColLb[colIndx];
+    if ( cutLbs.indexExists(colIndx) )
+      if ( cutLbs[colIndx] > newLb ) newLb = cutLbs[colIndx];
+      if ( newUb < newLb ) 
+        return false;
+  }
+  
+  return true;
+}
+#endif 
+
+
+bool OsiColCut::infeasible(const OsiSolverInterface &im) const
+{
+  const double * oldColLb = im.getColLower();
+  const double * oldColUb = im.getColUpper();
+  const CoinPackedVector & cutLbs = lbs();
+  const CoinPackedVector & cutUbs = ubs();
+  int i;
+  
+  for ( i=0; i<cutLbs.getNumElements(); i++ ) {
+    int colIndx = cutLbs.getIndices()[i];
+    double newLb= cutLbs.getElements()[i] > oldColLb[colIndx] ?
+       cutLbs.getElements()[i] : oldColLb[colIndx];
+
+    double newUb = oldColUb[colIndx];
+    if ( cutUbs.isExistingIndex(colIndx) )
+      if ( cutUbs[colIndx] < newUb ) newUb = cutUbs[colIndx];
+      if ( newLb > newUb ) 
+        return true;
+  }
+  
+  for ( i=0; i<cutUbs.getNumElements(); i++ ) {
+    int colIndx = cutUbs.getIndices()[i];
+    double newUb = cutUbs.getElements()[i] < oldColUb[colIndx] ?
+       cutUbs.getElements()[i] : oldColUb[colIndx];
+    double newLb = oldColLb[colIndx];
+    if ( cutLbs.isExistingIndex(colIndx) )
+      if ( cutLbs[colIndx] > newLb ) newLb = cutLbs[colIndx];
+      if ( newUb < newLb ) 
+        return true;
+  }
+  
+  return false;
+}
+
+#endif
diff --git a/cbits/coin/OsiCollections.hpp b/cbits/coin/OsiCollections.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiCollections.hpp
@@ -0,0 +1,35 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiCollections_H
+#define OsiCollections_H
+
+#include <vector>
+
+//Forward declarations
+class OsiColCut;
+class OsiRowCut;
+class OsiCut;
+
+
+
+/* Collection Classes */
+
+/**@name Typedefs for Standard Template Library collections of Osi Objects. */
+//@{
+/// Vector of int
+typedef std::vector<int>    OsiVectorInt;
+/// Vector of double
+typedef std::vector<double> OsiVectorDouble;
+/// Vector of OsiColCut pointers
+typedef std::vector<OsiColCut *> OsiVectorColCutPtr;
+/// Vector of OsiRowCut pointers
+typedef std::vector<OsiRowCut *> OsiVectorRowCutPtr;
+/// Vector of OsiCut pointers
+typedef std::vector<OsiCut *>    OsiVectorCutPtr;
+//@}
+
+
+
+#endif
diff --git a/cbits/coin/OsiConfig.h b/cbits/coin/OsiConfig.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiConfig.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011
+ * All Rights Reserved.
+ * This code is published under the Eclipse Public License.
+ *
+ * $Id: OsiConfig.h 1881 2013-01-28 00:05:47Z stefan $
+ *
+ * Include file for the configuration of Osi.
+ *
+ * On systems where the code is configured with the configure script
+ * (i.e., compilation is always done with HAVE_CONFIG_H defined), this
+ * header file includes the automatically generated header file.
+ *
+ * On systems that are compiled in other ways (e.g., with the
+ * Developer Studio), a header files is included to define those
+ * macros that depend on the operating system and the compiler.  The
+ * macros that define the configuration of the particular user setting
+ * (e.g., presence of other COIN-OR packages or third party code) are set
+ * by the files config_*default.h. The project maintainer needs to remember
+ * to update these file and choose reasonable defines.
+ * A user can modify the default setting by editing the config_*default.h files.
+ */
+
+#ifndef __OSICONFIG_H__
+#define __OSICONFIG_H__
+
+#ifdef HAVE_CONFIG_H
+#ifdef OSI_BUILD
+#include "config.h"
+#else
+#include "config_osi.h"
+#endif
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef OSI_BUILD
+#include "config_default.h"
+#else
+#include "config_osi_default.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+#endif /*__OSICONFIG_H__*/
diff --git a/cbits/coin/OsiCut.cpp b/cbits/coin/OsiCut.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiCut.cpp
@@ -0,0 +1,71 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "OsiCut.hpp"
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiCut::OsiCut ()
+:
+  effectiveness_(0.),
+  globallyValid_(0)
+//timesUsed_(0),
+//timesTested_(0)
+{
+  // nothing to do here
+}
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiCut::OsiCut (
+                  const OsiCut & source)
+:
+  effectiveness_(source.effectiveness_),
+  globallyValid_(source.globallyValid_)
+//timesUsed_(source.timesUsed_),
+//timesTested_(source.timesTested_)
+{  
+  // nothing to do here
+}
+
+#if 0
+//----------------------------------------------------------------
+// Clone
+//----------------------------------------------------------------
+OsiCut * OsiCut::clone() const
+{  return (new OsiCut(*this));}
+#endif
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiCut::~OsiCut ()
+{
+  // nothing to do here
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiCut &
+OsiCut::operator=(const OsiCut& rhs)
+{
+  if (this != &rhs) {
+    effectiveness_=rhs.effectiveness_;
+    globallyValid_ = rhs.globallyValid_;
+    //timesUsed_=rhs.timesUsed_;
+    //timesTested_=rhs.timesTested_;
+  }
+  return *this;
+}
+
+
+
+
diff --git a/cbits/coin/OsiCut.hpp b/cbits/coin/OsiCut.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiCut.hpp
@@ -0,0 +1,245 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiCut_H
+#define OsiCut_H
+
+#include "OsiCollections.hpp"
+#include "OsiSolverInterface.hpp"
+
+/** Base Class for cut.
+
+The Base cut class contains:
+  <ul>
+  <li>a measure of the cut's effectivness
+  </ul>
+*/
+
+/*
+  COIN_NOTEST_DUPLICATE is rooted in CoinUtils. Check there before you
+  meddle here.
+*/
+#ifdef COIN_FAST_CODE
+#ifndef COIN_NOTEST_DUPLICATE
+#define COIN_NOTEST_DUPLICATE
+#endif
+#endif
+
+#ifndef COIN_NOTEST_DUPLICATE
+#define COIN_DEFAULT_VALUE_FOR_DUPLICATE true
+#else
+#define COIN_DEFAULT_VALUE_FOR_DUPLICATE false
+#endif
+
+
+class OsiCut  {
+  
+public:
+    
+  //-------------------------------------------------------------------
+  /**@name Effectiveness */
+  //@{
+  /// Set effectiveness
+  inline void setEffectiveness( double e ); 
+  /// Get effectiveness
+  inline double effectiveness() const; 
+  //@}
+
+  /**@name GloballyValid */
+  //@{
+  /// Set globallyValid (nonzero true)
+  inline void setGloballyValid( bool trueFalse ) 
+  { globallyValid_=trueFalse ? 1 : 0;}
+  inline void setGloballyValid( ) 
+  { globallyValid_=1;}
+  inline void setNotGloballyValid( ) 
+  { globallyValid_=0;}
+  /// Get globallyValid
+  inline bool globallyValid() const
+  { return globallyValid_!=0;}
+  /// Set globallyValid as integer (nonzero true)
+  inline void setGloballyValidAsInteger( int trueFalse ) 
+  { globallyValid_=trueFalse;}
+  /// Get globallyValid
+  inline int globallyValidAsInteger() const
+  { return globallyValid_;}
+  //@}
+
+  /**@name Debug stuff */
+  //@{
+    /// Print cuts in collection
+  virtual void print() const {}
+  //@}
+   
+#if 0
+  / **@name Times used */
+  / /@{
+  / // Set times used
+  inline void setTimesUsed( int t );
+  / // Increment times used
+  inline void incrementTimesUsed();
+  / // Get times used
+  inline int timesUsed() const;
+  / /@}
+  
+  / **@name Times tested */
+  / /@{
+  / // Set times tested
+  inline void setTimesTested( int t );
+  / // Increment times tested
+  inline void incrementTimesTested();
+  / // Get times tested
+  inline int timesTested() const;
+  / /@}
+#endif
+
+  //----------------------------------------------------------------
+
+  /**@name Comparison operators  */
+  //@{
+    ///equal. 2 cuts are equal if there effectiveness are equal
+    inline virtual bool operator==(const OsiCut& rhs) const; 
+    /// not equal
+    inline virtual bool operator!=(const OsiCut& rhs) const; 
+    /// less than. True if this.effectiveness < rhs.effectiveness
+    inline virtual bool operator< (const OsiCut& rhs) const; 
+    /// less than. True if this.effectiveness > rhs.effectiveness
+    inline virtual bool operator> (const OsiCut& rhs) const; 
+  //@}
+
+  //----------------------------------------------------------------
+  // consistent() - returns true if the cut is consistent with repect to itself.
+  //         This might include checks to ensure that a packed vector
+  //         itself does not have a negative index.
+  // consistent(const OsiSolverInterface& si) - returns true if cut is consistent with
+  //         respect to the solver interface's model. This might include a check to 
+  //         make sure a column index is not greater than the number
+  //         of columns in the problem.
+  // infeasible(const OsiSolverInterface& si) - returns true if the cut is infeasible 
+  //         "with respect to itself". This might include a check to ensure 
+  //         the lower bound is greater than the upper bound, or if the
+  //         cut simply replaces bounds that the new bounds are feasible with 
+  //         respect to the old bounds.
+  //-----------------------------------------------------------------
+  /**@name Sanity checks on cut */
+  //@{
+  /** Returns true if the cut is consistent with respect to itself,
+      without considering any
+      data in the model. For example, it might check to ensure
+      that a column index is not negative.
+  */
+  inline virtual bool consistent() const=0; 
+
+  /** Returns true if cut is consistent when considering the solver
+      interface's model.  For example, it might check to ensure
+      that a column index is not greater than the number of columns
+      in the model. Assumes consistent() is true.
+  */
+  inline virtual bool consistent(const OsiSolverInterface& si) const=0;
+
+  /** Returns true if the cut is infeasible "with respect to itself" and
+      cannot be satisfied. This method does NOT check whether adding the
+      cut to the solver interface's model will make the -model- infeasble.
+      A cut which returns !infeasible(si) may very well make the model
+      infeasible. (Of course, adding a cut with returns infeasible(si) 
+      will make the model infeasible.)
+
+      The "with respect to itself" is in quotes becaues 
+      in the case where the cut
+      simply replaces existing bounds, it may make
+      sense to test infeasibility with respect to the current bounds
+      held in the solver interface's model. For example, if the cut 
+      has a single variable in it, it might check that the maximum
+      of new and existing lower bounds is greater than the minium of 
+      the new and existing upper bounds.
+
+      Assumes that consistent(si) is true.<br>
+      Infeasible cuts can be a useful mechanism for a cut generator to
+      inform the solver interface that its detected infeasibility of the
+      problem.
+  */
+  inline virtual bool infeasible(const OsiSolverInterface &si) const=0;
+
+  /** Returns infeasibility of the cut with respect to solution 
+      passed in i.e. is positive if cuts off that solution.  
+      solution is getNumCols() long..
+  */
+  virtual double violated(const double * solution) const=0;
+  //@}
+
+protected:
+
+  /**@name Constructors and destructors */
+  //@{
+  /// Default Constructor 
+  OsiCut ();
+  
+  /// Copy constructor 
+  OsiCut ( const OsiCut &);
+   
+  /// Assignment operator 
+  OsiCut & operator=( const OsiCut& rhs);
+
+  /// Destructor 
+  virtual ~OsiCut ();
+  //@}
+  
+private:
+  
+  /**@name Private member data */
+  //@{
+  /// Effectiveness
+  double effectiveness_;
+  /// If cut has global validity i.e. can be used anywhere in tree
+  int globallyValid_;
+#if 0
+  /// Times used
+  int timesUsed_;
+  /// Times tested
+  int timesTested_;
+#endif
+  //@}
+};
+
+
+//-------------------------------------------------------------------
+// Set/Get member data
+//-------------------------------------------------------------------
+void OsiCut::setEffectiveness(double e)  { effectiveness_=e; }
+double OsiCut::effectiveness() const { return effectiveness_; }
+
+#if 0
+void OsiCut::setTimesUsed( int t ) { timesUsed_=t; }
+void OsiCut::incrementTimesUsed() { timesUsed_++; }
+int OsiCut::timesUsed() const { return timesUsed_; }
+
+void OsiCut::setTimesTested( int t ) { timesTested_=t; }
+void OsiCut::incrementTimesTested() { timesTested_++; }
+int OsiCut::timesTested() const{ return timesTested_; }
+#endif
+
+//----------------------------------------------------------------
+// == operator 
+//-------------------------------------------------------------------
+bool
+OsiCut::operator==(const OsiCut& rhs) const
+{
+  return effectiveness()==rhs.effectiveness();
+}
+bool
+OsiCut::operator!=(const OsiCut& rhs) const
+{
+  return !( (*this)==rhs );
+}
+bool
+OsiCut::operator< (const OsiCut& rhs) const
+{
+  return effectiveness()<rhs.effectiveness();
+}
+bool
+OsiCut::operator> (const OsiCut& rhs) const
+{
+  return effectiveness()>rhs.effectiveness();
+}
+#endif
diff --git a/cbits/coin/OsiCuts.cpp b/cbits/coin/OsiCuts.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiCuts.cpp
@@ -0,0 +1,380 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <algorithm>
+#include <cassert>
+
+#include "OsiCuts.hpp"
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiCuts::OsiCuts ()
+:
+rowCutPtrs_(),
+colCutPtrs_()
+{
+  // nothing to do here
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiCuts::OsiCuts (const OsiCuts & source)
+:
+rowCutPtrs_(),
+colCutPtrs_()     
+{  
+  gutsOfCopy( source );
+}
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiCuts::~OsiCuts ()
+{
+  gutsOfDestructor();
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiCuts &
+OsiCuts::operator=(const OsiCuts& rhs)
+{
+  if (this != &rhs) {
+    gutsOfDestructor();
+    gutsOfCopy( rhs );
+  }
+  return *this;
+}
+
+
+
+//-------------------------------------------------------------------
+void OsiCuts::gutsOfCopy(const OsiCuts& source)
+{
+  assert( sizeRowCuts()==0 );
+  assert( sizeColCuts()==0 );
+  assert( sizeCuts()==0 );
+  int i;
+  int ne = source.sizeRowCuts();
+  for (i=0; i<ne; i++) insert( source.rowCut(i) );
+  ne = source.sizeColCuts();
+  for (i=0; i<ne; i++) insert( source.colCut(i) );
+
+}
+
+//-------------------------------------------------------------------
+void OsiCuts::gutsOfDestructor()
+{
+  int i;
+  
+  int ne = static_cast<int>(rowCutPtrs_.size());
+  for (i=0; i<ne; i++) {
+    if (rowCutPtrs_[i]->globallyValidAsInteger()!=2)
+      delete rowCutPtrs_[i];
+  }
+  rowCutPtrs_.clear();
+  
+  ne = static_cast<int>(colCutPtrs_.size());
+  for (i=0; i<ne; i++) {
+    if (colCutPtrs_[i]->globallyValidAsInteger()!=2)
+      delete colCutPtrs_[i];
+  }
+  colCutPtrs_.clear();
+  
+  assert( sizeRowCuts()==0 );
+  assert( sizeColCuts()==0 );
+  assert( sizeCuts()   ==0 );
+}
+
+
+//------------------------------------------------------------
+//
+// Embedded iterator class implementation
+//
+//------------------------------------------------------------
+OsiCuts::iterator::iterator(OsiCuts& cuts)
+: 
+cuts_(cuts),
+rowCutIndex_(-1),
+colCutIndex_(-1),
+cutP_(NULL)
+{
+  this->operator++();
+}
+
+OsiCuts::iterator::iterator(const OsiCuts::iterator &src)
+: 
+cuts_(src.cuts_),
+rowCutIndex_(src.rowCutIndex_),
+colCutIndex_(src.colCutIndex_),
+cutP_(src.cutP_)
+{
+  // nothing to do here
+}
+
+OsiCuts::iterator & OsiCuts::iterator::operator=(const OsiCuts::iterator &rhs)
+{
+  if (this != &rhs) {
+    cuts_=rhs.cuts_;
+    rowCutIndex_=rhs.rowCutIndex_;
+    colCutIndex_=rhs.colCutIndex_;
+    cutP_=rhs.cutP_;
+  }
+  return *this;
+}
+
+OsiCuts::iterator::~iterator()
+{
+  //nothing to do
+}
+
+OsiCuts::iterator OsiCuts::iterator::begin()
+{
+  rowCutIndex_=-1;
+  colCutIndex_=-1;
+  this->operator++();
+  return *this;
+}
+
+OsiCuts::iterator OsiCuts::iterator::end()
+{
+  rowCutIndex_=cuts_.sizeRowCuts();
+  colCutIndex_=cuts_.sizeColCuts()-1;
+  cutP_=NULL;
+  return *this;
+}
+
+OsiCuts::iterator OsiCuts::iterator::operator++() {
+  cutP_ = NULL;
+
+  // Are there any more row cuts to consider?
+  if ( (rowCutIndex_+1)>=cuts_.sizeRowCuts() ) {
+    // Only column cuts left.
+    colCutIndex_++;
+    // Only update cutP if there is a column cut.
+    // This is necessary for the iterator to work for
+    // OsiCuts that don't have any cuts.
+    if ( cuts_.sizeColCuts() > 0 && colCutIndex_<cuts_.sizeColCuts() ) 
+      cutP_= cuts_.colCutPtr(colCutIndex_);
+  }
+
+  // Are there any more col cuts to consider?
+  else if ( (colCutIndex_+1)>=cuts_.sizeColCuts() ) {
+    // Only row cuts left
+    rowCutIndex_++;
+    if ( rowCutIndex_<cuts_.sizeRowCuts() ) 
+      cutP_= cuts_.rowCutPtr(rowCutIndex_);
+  }
+
+  // There are still Row & column cuts left to consider
+  else {
+    double nextColCutE=cuts_.colCut(colCutIndex_+1).effectiveness();
+    double nextRowCutE=cuts_.rowCut(rowCutIndex_+1).effectiveness();
+    if ( nextColCutE>nextRowCutE ) {
+      colCutIndex_++;
+      cutP_=cuts_.colCutPtr(colCutIndex_);
+    }
+    else {
+      rowCutIndex_++;
+      cutP_=cuts_.rowCutPtr(rowCutIndex_);
+    }
+  }
+  return *this;
+}
+
+//------------------------------------------------------------
+//
+// Embedded const_iterator class implementation
+//
+//------------------------------------------------------------
+OsiCuts::const_iterator::const_iterator(const OsiCuts& cuts)
+: 
+cutsPtr_(&cuts),
+rowCutIndex_(-1),
+colCutIndex_(-1),
+cutP_(NULL)
+{
+  this->operator++();
+}
+
+OsiCuts::const_iterator::const_iterator(const OsiCuts::const_iterator &src)
+: 
+cutsPtr_(src.cutsPtr_),
+rowCutIndex_(src.rowCutIndex_),
+colCutIndex_(src.colCutIndex_),
+cutP_(src.cutP_)
+{
+  // nothing to do here
+}
+
+OsiCuts::const_iterator &
+OsiCuts::const_iterator::operator=(const OsiCuts::const_iterator &rhs)
+{
+  if (this != &rhs) {
+    cutsPtr_=rhs.cutsPtr_;
+    rowCutIndex_=rhs.rowCutIndex_;
+    colCutIndex_=rhs.colCutIndex_;
+    cutP_=rhs.cutP_;
+  }
+  return *this;
+}
+
+OsiCuts::const_iterator::~const_iterator()
+{
+  //nothing to do
+}
+
+OsiCuts::const_iterator OsiCuts::const_iterator::begin()
+{
+  rowCutIndex_=-1;
+  colCutIndex_=-1;
+  this->operator++();
+  return *this;
+}
+
+OsiCuts::const_iterator OsiCuts::const_iterator::end()
+{
+  rowCutIndex_=cutsPtr_->sizeRowCuts();
+  colCutIndex_=cutsPtr_->sizeColCuts()-1;
+  cutP_=NULL;
+  return *this;
+}
+
+
+OsiCuts::const_iterator OsiCuts::const_iterator::operator++() { 
+  cutP_ = NULL;
+
+  // Are there any more row cuts to consider?
+  if ( (rowCutIndex_+1)>=cutsPtr_->sizeRowCuts() ) {
+    // Only column cuts left.
+    colCutIndex_++;
+    // Only update cutP if there is a column cut.
+    // This is necessary for the iterator to work for
+    // OsiCuts that don't have any cuts.
+    if ( cutsPtr_->sizeRowCuts() > 0 && colCutIndex_<cutsPtr_->sizeColCuts() ) 
+      cutP_= cutsPtr_->colCutPtr(colCutIndex_);
+  }
+
+  // Are there any more col cuts to consider?
+  else if ( (colCutIndex_+1)>=cutsPtr_->sizeColCuts() ) {
+    // Only row cuts left
+    rowCutIndex_++;
+    if ( rowCutIndex_<cutsPtr_->sizeRowCuts() ) 
+      cutP_= cutsPtr_->rowCutPtr(rowCutIndex_);
+  }
+
+  // There are still Row & column cuts left to consider
+  else {
+    double nextColCutE=cutsPtr_->colCut(colCutIndex_+1).effectiveness();
+    double nextRowCutE=cutsPtr_->rowCut(rowCutIndex_+1).effectiveness();
+    if ( nextColCutE>nextRowCutE ) {
+      colCutIndex_++;
+      cutP_=cutsPtr_->colCutPtr(colCutIndex_);
+    }
+    else {
+      rowCutIndex_++;
+      cutP_=cutsPtr_->rowCutPtr(rowCutIndex_);
+    }
+  }
+  return *this;
+}
+
+/* Insert a row cut unless it is a duplicate (CoinAbsFltEq)*/
+void 
+OsiCuts::insertIfNotDuplicate( OsiRowCut & rc , CoinAbsFltEq treatAsSame)
+{
+  double newLb = rc.lb();
+  double newUb = rc.ub();
+  CoinPackedVector vector = rc.row();
+  int numberElements =vector.getNumElements();
+  int * newIndices = vector.getIndices();
+  double * newElements = vector.getElements();
+  CoinSort_2(newIndices,newIndices+numberElements,newElements);
+  bool notDuplicate=true;
+  int numberRowCuts = sizeRowCuts();
+  for ( int i =0; i<numberRowCuts;i++) {
+    const OsiRowCut * cutPtr = rowCutPtr(i);
+    if (cutPtr->row().getNumElements()!=numberElements)
+      continue;
+    if (!treatAsSame(cutPtr->lb(),newLb))
+      continue;
+    if (!treatAsSame(cutPtr->ub(),newUb))
+      continue;
+    const CoinPackedVector * thisVector = &(cutPtr->row());
+    const int * indices = thisVector->getIndices();
+    const double * elements = thisVector->getElements();
+    int j;
+    for(j=0;j<numberElements;j++) {
+      if (indices[j]!=newIndices[j])
+	break;
+      if (!treatAsSame(elements[j],newElements[j]))
+	break;
+    }
+    if (j==numberElements) {
+      notDuplicate=false;
+      break;
+    }
+  }
+  if (notDuplicate) {
+    OsiRowCut * newCutPtr = new OsiRowCut();
+    newCutPtr->setLb(newLb);
+    newCutPtr->setUb(newUb);
+    newCutPtr->setRow(vector);
+    rowCutPtrs_.push_back(newCutPtr);
+  }
+}
+
+/* Insert a row cut unless it is a duplicate (CoinRelFltEq)*/
+void 
+OsiCuts::insertIfNotDuplicate( OsiRowCut & rc , CoinRelFltEq treatAsSame)
+{
+  double newLb = rc.lb();
+  double newUb = rc.ub();
+  CoinPackedVector vector = rc.row();
+  int numberElements =vector.getNumElements();
+  int * newIndices = vector.getIndices();
+  double * newElements = vector.getElements();
+  CoinSort_2(newIndices,newIndices+numberElements,newElements);
+  bool notDuplicate=true;
+  int numberRowCuts = sizeRowCuts();
+  for ( int i =0; i<numberRowCuts;i++) {
+    const OsiRowCut * cutPtr = rowCutPtr(i);
+    if (cutPtr->row().getNumElements()!=numberElements)
+      continue;
+    if (!treatAsSame(cutPtr->lb(),newLb))
+      continue;
+    if (!treatAsSame(cutPtr->ub(),newUb))
+      continue;
+    const CoinPackedVector * thisVector = &(cutPtr->row());
+    const int * indices = thisVector->getIndices();
+    const double * elements = thisVector->getElements();
+    int j;
+    for(j=0;j<numberElements;j++) {
+      if (indices[j]!=newIndices[j])
+	break;
+      if (!treatAsSame(elements[j],newElements[j]))
+	break;
+    }
+    if (j==numberElements) {
+      notDuplicate=false;
+      break;
+    }
+  }
+  if (notDuplicate) {
+    OsiRowCut * newCutPtr = new OsiRowCut();
+    newCutPtr->setLb(newLb);
+    newCutPtr->setUb(newUb);
+    newCutPtr->setRow(vector);
+    rowCutPtrs_.push_back(newCutPtr);
+  }
+}
diff --git a/cbits/coin/OsiCuts.hpp b/cbits/coin/OsiCuts.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiCuts.hpp
@@ -0,0 +1,474 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiCuts_H
+#define OsiCuts_H
+
+#include "CoinPragma.hpp"
+
+#include <cmath>
+#include <cfloat>
+#include "OsiCollections.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiColCut.hpp"
+#include "CoinFloatEqual.hpp"
+
+/** Collections of row cuts and column cuts
+*/
+class OsiCuts {
+   friend void OsiCutsUnitTest();
+
+public:
+  /**@name Iterator classes
+   */
+  //@{
+    /** Iterator
+
+      This is a class for iterating over the collection of cuts.
+    */
+    class iterator {
+      friend class OsiCuts;
+    public:
+      iterator(OsiCuts& cuts); 
+      iterator(const iterator & src);
+      iterator & operator=( const iterator& rhs);    
+      ~iterator ();
+      OsiCut* operator*() const { return cutP_; }    
+      iterator operator++();
+
+      iterator operator++(int)
+      {
+        iterator temp = *this;
+        ++*this;
+        return temp;
+      }
+    
+      bool operator==(const iterator& it) const {
+        return (colCutIndex_+rowCutIndex_)==(it.colCutIndex_+it.rowCutIndex_);
+      }
+    
+      bool operator!=(const iterator& it) const {
+        return !((*this)==it);
+      }
+    
+      bool operator<(const iterator& it) const {
+        return (colCutIndex_+rowCutIndex_)<(it.colCutIndex_+it.rowCutIndex_);
+      }
+    
+    private: 
+      iterator();
+      // *THINK* : how to inline these without sticking the code here (ugly...)
+      iterator begin();
+      iterator end();
+      OsiCuts& cuts_;
+      int rowCutIndex_;
+      int colCutIndex_;
+      OsiCut * cutP_;
+    };
+   
+    /** Const Iterator
+
+      This is a class for iterating over the collection of cuts.
+    */ 
+    class const_iterator {
+      friend class OsiCuts;
+	public:
+	  typedef std::bidirectional_iterator_tag iterator_category;
+	  typedef OsiCut* value_type;
+	  typedef size_t difference_type;
+	  typedef OsiCut ** pointer;
+	  typedef OsiCut *& reference;
+
+    public:
+      const_iterator(const OsiCuts& cuts);
+      const_iterator(const const_iterator & src);
+      const_iterator & operator=( const const_iterator& rhs);     
+      ~const_iterator ();
+      const OsiCut* operator*() const { return cutP_; } 
+       
+      const_iterator operator++();
+    
+      const_iterator operator++(int)
+      {
+        const_iterator temp = *this;
+        ++*this;
+        return temp;
+      }
+    
+      bool operator==(const const_iterator& it) const {
+        return (colCutIndex_+rowCutIndex_)==(it.colCutIndex_+it.rowCutIndex_);
+      }
+    
+      bool operator!=(const const_iterator& it) const {
+        return !((*this)==it);
+      }
+    
+      bool operator<(const const_iterator& it) const {
+        return (colCutIndex_+rowCutIndex_)<(it.colCutIndex_+it.rowCutIndex_);
+      }
+    private:  
+      inline const_iterator();  
+      // *THINK* : how to inline these without sticking the code here (ugly...)
+      const_iterator begin();
+      const_iterator end();
+      const OsiCuts * cutsPtr_;
+      int rowCutIndex_;
+      int colCutIndex_;
+      const OsiCut * cutP_;
+    };
+  //@}
+
+  //-------------------------------------------------------------------
+  // 
+  // Cuts class definition begins here:
+  //
+  //------------------------------------------------------------------- 
+    
+  /** \name Inserting a cut into collection */
+  //@{
+    /** \brief Insert a row cut */
+    inline void insert( const OsiRowCut & rc );
+    /** \brief Insert a row cut unless it is a duplicate - cut may get sorted.
+       Duplicate is defined as CoinAbsFltEq says same*/
+    void insertIfNotDuplicate( OsiRowCut & rc , CoinAbsFltEq treatAsSame=CoinAbsFltEq(1.0e-12) );
+    /** \brief Insert a row cut unless it is a duplicate - cut may get sorted.
+       Duplicate is defined as CoinRelFltEq says same*/
+    void insertIfNotDuplicate( OsiRowCut & rc , CoinRelFltEq treatAsSame );
+    /** \brief Insert a column cut */
+    inline void insert( const OsiColCut & cc );
+
+    /** \brief Insert a row cut.
+    
+      The OsiCuts object takes control of the cut object.
+      On return, \c rcPtr is NULL.
+    */
+    inline void insert( OsiRowCut * & rcPtr );
+    /** \brief Insert a column cut.
+    
+      The OsiCuts object takes control of the cut object.
+      On return \c ccPtr is NULL.
+    */
+    inline void insert( OsiColCut * & ccPtr );
+#if 0
+    inline void insert( OsiCut    * & cPtr  );
+#endif
+    
+   /** \brief Insert a set of cuts */
+   inline void insert(const OsiCuts & cs);
+
+  //@}
+
+  /**@name Number of cuts in collection */
+  //@{
+    /// Number of row cuts in collection
+    inline int sizeRowCuts() const;
+    /// Number of column cuts in collection
+    inline int sizeColCuts() const;
+    /// Number of cuts in collection
+    inline int sizeCuts() const;
+  //@}
+   
+  /**@name Debug stuff */
+  //@{
+    /// Print cuts in collection
+    inline void printCuts() const;
+  //@}
+   
+  /**@name Get a cut from collection */
+  //@{
+    /// Get pointer to i'th row cut
+    inline OsiRowCut * rowCutPtr(int i);
+    /// Get const pointer to i'th row cut
+    inline const OsiRowCut * rowCutPtr(int i) const;
+    /// Get pointer to i'th column cut
+    inline OsiColCut * colCutPtr(int i);
+    /// Get const pointer to i'th column cut
+    inline const OsiColCut * colCutPtr(int i) const;
+
+    /// Get reference to i'th row cut
+    inline OsiRowCut & rowCut(int i);
+    /// Get const reference to i'th row cut
+    inline const OsiRowCut & rowCut(int i) const;
+    /// Get reference to i'th column cut
+    inline OsiColCut & colCut(int i);
+    /// Get const reference to i'th column cut
+    inline const OsiColCut & colCut(int i) const;
+
+    /// Get const pointer to the most effective cut
+    inline const OsiCut * mostEffectiveCutPtr() const;
+    /// Get pointer to the most effective cut
+    inline OsiCut * mostEffectiveCutPtr();
+  //@}
+
+  /**@name Deleting cut from collection */
+  //@{ 
+    /// Remove i'th row cut from collection
+    inline void eraseRowCut(int i);
+    /// Remove i'th column cut from collection
+    inline void eraseColCut(int i); 
+    /// Get pointer to i'th row cut and remove ptr from collection
+    inline OsiRowCut * rowCutPtrAndZap(int i);
+    /*! \brief Clear all row cuts without deleting them
+    
+      Handy in case one wants to use CGL without managing cuts in one of
+      the OSI containers. Client is ultimately responsible for deleting the
+      data structures holding the row cuts.
+    */
+    inline void dumpCuts() ;
+    /*! \brief Selective delete and clear for row cuts.
+
+      Deletes the cuts specified in \p to_erase then clears remaining cuts
+      without deleting them. A hybrid of eraseRowCut(int) and dumpCuts().
+      Client is ultimately responsible for deleting the data structures
+      for row cuts not specified in \p to_erase.
+    */
+    inline void eraseAndDumpCuts(const std::vector<int> to_erase) ;
+  //@}
+ 
+  /**@name Sorting collection */
+  //@{ 
+    /// Cuts with greatest effectiveness are first.
+    inline void sort();
+  //@}
+  
+   
+  /**@name Iterators 
+     Example of using an iterator to sum effectiveness
+     of all cuts in the collection.
+     <pre>
+     double sumEff=0.0;
+     for ( OsiCuts::iterator it=cuts.begin(); it!=cuts.end(); ++it )
+           sumEff+= (*it)->effectiveness();
+     </pre>
+  */
+  //@{ 
+    /// Get iterator to beginning of collection
+    inline iterator begin() { iterator it(*this); it.begin(); return it; }  
+    /// Get const iterator to beginning of collection
+    inline const_iterator begin() const { const_iterator it(*this); it.begin(); return it; }  
+    /// Get iterator to end of collection 
+    inline iterator end() { iterator it(*this); it.end(); return it; }
+    /// Get const iterator to end of collection 
+    inline const_iterator end() const { const_iterator it(*this); it.end(); return it; }  
+  //@}
+ 
+   
+  /**@name Constructors and destructors */
+  //@{
+    /// Default constructor
+    OsiCuts (); 
+
+    /// Copy constructor 
+    OsiCuts ( const OsiCuts &);
+  
+    /// Assignment operator 
+    OsiCuts & operator=( const OsiCuts& rhs);
+  
+    /// Destructor 
+    virtual ~OsiCuts ();
+  //@}
+
+private:
+  //*@name Function operator for sorting cuts by efectiveness */
+  //@{
+    class OsiCutCompare
+    { 
+    public:
+      /// Function for sorting cuts by effectiveness
+      inline bool operator()(const OsiCut * c1P,const OsiCut * c2P) 
+      { return c1P->effectiveness() > c2P->effectiveness(); }
+    };
+  //@}
+
+  /**@name Private methods */
+  //@{     
+    /// Copy internal data
+    void gutsOfCopy( const OsiCuts & source );
+    /// Delete internal data
+    void gutsOfDestructor();
+  //@}
+    
+  /**@name Private member data */
+  //@{   
+    /// Vector of row cuts pointers
+    OsiVectorRowCutPtr rowCutPtrs_;
+    /// Vector of column cuts pointers
+    OsiVectorColCutPtr colCutPtrs_;
+  //@}
+
+};
+
+
+//-------------------------------------------------------------------
+// insert cuts into collection
+//-------------------------------------------------------------------
+void OsiCuts::insert( const OsiRowCut & rc )
+{
+  OsiRowCut * newCutPtr = rc.clone();
+  //assert(dynamic_cast<OsiRowCut*>(newCutPtr) != NULL );
+  rowCutPtrs_.push_back(static_cast<OsiRowCut*>(newCutPtr));
+}
+void OsiCuts::insert( const OsiColCut & cc )
+{
+  OsiColCut * newCutPtr = cc.clone();
+  //assert(dynamic_cast<OsiColCut*>(newCutPtr) != NULL );
+  colCutPtrs_.push_back(static_cast<OsiColCut*>(newCutPtr));
+}
+
+void OsiCuts::insert( OsiRowCut* & rcPtr )
+{
+  rowCutPtrs_.push_back(rcPtr);
+  rcPtr = NULL;
+}
+void OsiCuts::insert( OsiColCut* &ccPtr )
+{
+  colCutPtrs_.push_back(ccPtr);
+  ccPtr = NULL;
+}
+#if 0
+void OsiCuts::insert( OsiCut* & cPtr )
+{
+  OsiRowCut * rcPtr = dynamic_cast<OsiRowCut*>(cPtr);
+  if ( rcPtr != NULL ) {
+    insert( rcPtr );
+    cPtr = rcPtr;
+  }
+  else {
+    OsiColCut * ccPtr = dynamic_cast<OsiColCut*>(cPtr);
+    assert( ccPtr != NULL );
+    insert( ccPtr );
+    cPtr = ccPtr;
+  }
+}
+#endif
+    
+// LANNEZ SEBASTIEN added Thu May 25 01:22:51 EDT 2006
+void OsiCuts::insert(const OsiCuts & cs)
+{
+  for (OsiCuts::const_iterator it = cs.begin (); it != cs.end (); it++)
+  {
+    const OsiRowCut * rCut = dynamic_cast <const OsiRowCut * >(*it);
+    const OsiColCut * cCut = dynamic_cast <const OsiColCut * >(*it);
+    assert (rCut || cCut);
+    if (rCut)
+      insert (*rCut);
+    else
+      insert (*cCut);
+  }
+}
+
+//-------------------------------------------------------------------
+// sort
+//------------------------------------------------------------------- 
+void OsiCuts::sort() 
+{
+  std::sort(colCutPtrs_.begin(),colCutPtrs_.end(),OsiCutCompare()); 
+  std::sort(rowCutPtrs_.begin(),rowCutPtrs_.end(),OsiCutCompare()); 
+}
+
+
+//-------------------------------------------------------------------
+// Get number of in collections
+//------------------------------------------------------------------- 
+int OsiCuts::sizeRowCuts() const {
+  return static_cast<int>(rowCutPtrs_.size()); }
+int OsiCuts::sizeColCuts() const {
+  return static_cast<int>(colCutPtrs_.size()); }
+int OsiCuts::sizeCuts()    const {
+  return static_cast<int>(sizeRowCuts()+sizeColCuts()); }
+
+//----------------------------------------------------------------
+// Get i'th cut from the collection
+//----------------------------------------------------------------
+const OsiRowCut * OsiCuts::rowCutPtr(int i) const { return rowCutPtrs_[i]; }
+const OsiColCut * OsiCuts::colCutPtr(int i) const { return colCutPtrs_[i]; }
+OsiRowCut * OsiCuts::rowCutPtr(int i) { return rowCutPtrs_[i]; }
+OsiColCut * OsiCuts::colCutPtr(int i) { return colCutPtrs_[i]; }
+
+const OsiRowCut & OsiCuts::rowCut(int i) const { return *rowCutPtr(i); }
+const OsiColCut & OsiCuts::colCut(int i) const { return *colCutPtr(i); }
+OsiRowCut & OsiCuts::rowCut(int i) { return *rowCutPtr(i); }
+OsiColCut & OsiCuts::colCut(int i) { return *colCutPtr(i); }
+
+//----------------------------------------------------------------
+// Get most effective cut from collection
+//----------------------------------------------------------------
+const OsiCut * OsiCuts::mostEffectiveCutPtr() const 
+{ 
+  const_iterator b=begin();
+  const_iterator e=end();
+  return *(std::min_element(b,e,OsiCutCompare()));
+}
+OsiCut * OsiCuts::mostEffectiveCutPtr()  
+{ 
+  iterator b=begin();
+  iterator e=end();
+  //return *(std::min_element(b,e,OsiCutCompare()));
+  OsiCut * retVal = NULL;
+  double maxEff = COIN_DBL_MIN;
+  for ( OsiCuts::iterator it=b; it!=e; ++it ) {
+    if (maxEff < (*it)->effectiveness() ) {
+      maxEff = (*it)->effectiveness();
+      retVal = *it;
+    }
+  }
+  return retVal;
+}
+
+//----------------------------------------------------------------
+// Print all cuts
+//----------------------------------------------------------------
+void
+OsiCuts::printCuts() const  
+{ 
+  // do all column cuts first
+  int i;
+  int numberColCuts=sizeColCuts();
+  for (i=0;i<numberColCuts;i++) {
+    const OsiColCut * cut = colCutPtr(i);
+    cut->print();
+  }
+  int numberRowCuts=sizeRowCuts();
+  for (i=0;i<numberRowCuts;i++) {
+    const OsiRowCut * cut = rowCutPtr(i);
+    cut->print();
+  }
+}
+
+//----------------------------------------------------------------
+// Erase i'th cut from the collection
+//----------------------------------------------------------------
+void OsiCuts::eraseRowCut(int i) 
+{
+  delete rowCutPtrs_[i];
+  rowCutPtrs_.erase( rowCutPtrs_.begin()+i ); 
+}
+void OsiCuts::eraseColCut(int i) 
+{   
+  delete colCutPtrs_[i];
+  colCutPtrs_.erase( colCutPtrs_.begin()+i );
+}
+/// Get pointer to i'th row cut and remove ptr from collection
+OsiRowCut * 
+OsiCuts::rowCutPtrAndZap(int i)
+{
+  OsiRowCut * cut = rowCutPtrs_[i];
+  rowCutPtrs_[i]=NULL;
+  rowCutPtrs_.erase( rowCutPtrs_.begin()+i ); 
+  return cut;
+}
+void OsiCuts::dumpCuts()
+{
+  rowCutPtrs_.clear() ;
+}
+void OsiCuts::eraseAndDumpCuts(const std::vector<int> to_erase)
+{
+  for (unsigned i=0; i<to_erase.size(); i++) {
+    delete rowCutPtrs_[to_erase[i]];
+  }
+  rowCutPtrs_.clear();
+}
+
+
+#endif
diff --git a/cbits/coin/OsiNames.cpp b/cbits/coin/OsiNames.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiNames.cpp
@@ -0,0 +1,808 @@
+// Copyright (C) 2007, Lou Hafer and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include <sstream>
+#include <iomanip>
+
+#include "OsiSolverInterface.hpp"
+#include "CoinLpIO.hpp"
+#include "CoinMpsIO.hpp"
+#include "CoinModel.hpp"
+
+/*
+  These routines support three name disciplines:
+
+    0: No names: No name information is retained. rowNames_ and colNames_ are
+       always vectors of length 0. Requests for individual names will return
+       a name of the form RowNNN or ColNNN, generated on request.
+
+    1: Lazy names: Name information supplied by the client is retained.
+       rowNames_ and colNames_ are sized to be large enough to hold names
+       supplied by the client, and no larger. If the client has left holes,
+       those entries will contain a null string. Requests for individual names
+       will return the name supplied by the client, or a generated name.
+       Requests for a vector of names will return a reference to rowNames_ or
+       colNames_, with no modification.
+
+       This mode is intended for applications like branch-and-cut, where the
+       client is only interested in the original constraint system and could
+       care less about names for generated constraints and variables. The
+       various read[Mps,GMPL,Lp] routines capture the names that are part of
+       the input format. If the client is building from scratch, they'll need
+       to supply the names as they install constraints and variables.
+
+    2: Full names: From the client's point of view, this looks exactly like
+       lazy names, except that when a vector of names is requested, the vector
+       is always sized to match the constraint system and all entries have
+       names (either supplied or generated). Internally, full names looks just
+       like lazy names, with the exception that if the client requests one of
+       the name vectors, we generate the full version on the spot and keep it
+       around for further use.
+
+       This approach sidesteps some ugly implementation issues. The base
+       routines to add a row or column, or load a problem from matrices, are
+       pure virtual. There's just no way to guarantee we can keep the name
+       vectors up-to-date with each modification. Nor do we want to be in the
+       business of generating a name as soon as the row or column appears, only
+       to have our generated name immediately overridden by the client.
+
+  Arguably these magic numbers should be an enum, but that's not the current
+  OSI style.
+*/
+
+namespace {
+
+/*
+  Generate a `name' that's really an error message. A separate routine
+  strictly for standardisation and ease of use.
+
+  The 'u' code is intended to be used when a routine is expecting one of 'r' or
+  'c' and saw something else.
+*/
+std::string invRowColName (char rcd, int ndx)
+
+{ std::ostringstream buildName ;
+
+  buildName << "!!invalid " ;
+  switch (rcd)
+  { case 'r':
+    { buildName << "Row " << ndx << "!!" ;
+      break ; }
+    case 'c':
+    { buildName << "Col " << ndx << "!!" ;
+      break ; }
+    case 'd':
+    { buildName << "Discipline " << ndx << "!!" ;
+      break ; }
+    case 'u':
+    { buildName << "Row/Col " << ndx << "!!" ;
+      break ; }
+    default:
+    { buildName << "!!Internal Confusion!!" ;
+      break ; } }
+
+  return (buildName.str()) ; }
+
+/*
+  Adjust the allocated capacity of the name vectors, if they're sufficiently
+  far off (more than 1000 elements). Use this routine only if you don't need
+  the current contents of the vectors. The `assignment & swap' bit is a trick
+  lifted from Stroustrop 16.3.8 to make sure we really give back some space.
+*/
+void reallocRowColNames (OsiSolverInterface::OsiNameVec &rowNames, int m,
+			 OsiSolverInterface::OsiNameVec &colNames, int n)
+
+{ int rowCap = static_cast<int>(rowNames.capacity()) ;
+  int colCap = static_cast<int>(colNames.capacity()) ;
+
+  if (rowCap-m > 1000)
+  { rowNames.resize(m) ;
+    OsiSolverInterface::OsiNameVec tmp = rowNames ;
+    rowNames.swap(tmp) ; }
+  else
+  if (rowCap < m)
+  { rowNames.reserve(m) ; }
+  assert(rowNames.capacity() >= static_cast<unsigned>(m)) ;
+
+  if (colCap-n > 1000)
+  { colNames.resize(n) ;
+    OsiSolverInterface::OsiNameVec tmp = colNames ;
+    colNames.swap(tmp) ; }
+  else
+  if (colCap < n)
+  { colNames.reserve(n) ; }
+  assert(colNames.capacity() >= static_cast<unsigned>(n)) ;
+
+  return ; }
+
+
+/*
+  It's handy to have a 0-length name vector hanging around to use as a return
+  value when the name discipline = auto. Then we don't have to worry
+  about what's actually occupying rowNames_ or colNames_.
+*/
+
+const OsiSolverInterface::OsiNameVec zeroLengthNameVec(0) ;
+
+}
+
+/*
+  Generate the default RNNNNNNN/CNNNNNNN. This is a separate routine so that
+  it's available to generate names for new rows and columns. If digits is
+  nonzero, it's used, otherwise the default is 7 digits after the initial R
+  or C.
+
+  If rc = 'o', return the default name for the objective function. Yes, it's
+  true that ndx = m is (by definition) supposed to refer to the objective
+  function. But ... we're often calling this routine to get a name *before*
+  installing the row. Unless you want all your rows to be named OBJECTIVE,
+  something different is needed here.
+*/
+
+std::string
+OsiSolverInterface::dfltRowColName (char rc, int ndx, unsigned digits) const
+
+{ std::ostringstream buildName ;
+
+  if (!(rc == 'r' || rc == 'c' || rc == 'o'))
+  { return (invRowColName('u',ndx)) ; }
+  if (ndx < 0)
+  { return (invRowColName(rc,ndx)) ; }
+  
+  if (digits <= 0)
+  { digits = 7 ; }
+
+  if (rc == 'o')
+  { std::string dfltObjName = "OBJECTIVE" ;
+    buildName << dfltObjName.substr(0,digits+1) ; }
+  else
+  { buildName << ((rc == 'r')?"R":"C") ;
+    buildName << std::setw(digits) << std::setfill('0') ;
+    buildName << ndx ; }
+
+  return buildName.str() ; }
+
+/*
+  Return the name of the objective function.
+*/
+std::string OsiSolverInterface::getObjName (unsigned maxLen) const
+{ std::string name ;
+  
+  if (objName_.length() == 0)
+  { name = dfltRowColName('o',0,maxLen) ; }
+  else
+  { name = objName_.substr(0,maxLen) ; }
+
+  return (name) ; }
+
+/*
+  Return a row name, according to the current name discipline, truncated if
+  necessary. If the row index is out of range, the name becomes an error
+  message. By definition, ndx = getNumRows() (i.e., one greater than the
+  largest valid row index) is the objective function.
+*/
+std::string OsiSolverInterface::getRowName (int ndx, unsigned maxLen) const
+
+{ int nameDiscipline ;
+  std::string name ;
+/*
+  Check for valid row index.
+*/
+  int m = getNumRows() ;
+  if (ndx < 0 || ndx > m)
+  { name = invRowColName('r',ndx) ;
+    return (name) ; }
+/*
+  The objective is kept separately, so we don't always have an entry at
+  index m in the names vector. If no name is set, return the default.
+*/
+  if (ndx == m)
+  { return (getObjName(maxLen)) ; }
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Find/generate the proper name, based on discipline.
+*/
+  switch (nameDiscipline)
+  { case 0:
+    { name = dfltRowColName('r',ndx) ;
+      break ; }
+    case 1:
+    case 2:
+    { name = "" ;
+      if (static_cast<unsigned>(ndx) < rowNames_.size())
+	name = rowNames_[ndx] ;
+      if (name.length() == 0)
+	name = dfltRowColName('r',ndx) ;
+      break ; }
+    default:
+    { name = invRowColName('d',nameDiscipline) ;
+      return (name) ; } }
+/*
+  Return the (possibly truncated) substring. The default for maxLen is npos
+  (no truncation).
+*/
+  return (name.substr(0,maxLen)) ; }
+
+
+/*
+  Return the vector of row names. The vector we need depends on the name
+  discipline:
+    0: return a vector of length 0
+    1: return rowNames_, no tweaking required
+    2: Check that rowNames_ is complete. Generate a complete vector on
+       the spot if we need it.
+*/
+const OsiSolverInterface::OsiNameVec &OsiSolverInterface::getRowNames ()
+
+{ int nameDiscipline ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Return the proper vector, as described at the head of the routine. If we
+  need to generate a full vector, resize the existing vector and scan, filling
+  in entries as required.
+*/
+  switch (nameDiscipline)
+  { case 0:
+    { return (zeroLengthNameVec) ; }
+    case 1:
+    { return (rowNames_) ; }
+    case 2:
+    { int m = getNumRows() ;
+      if (rowNames_.size() < static_cast<unsigned>(m+1))
+      { rowNames_.resize(m+1) ; }
+      for (int i = 0 ; i < m ; i++)
+      { if (rowNames_[i].length() == 0)
+	{ rowNames_[i] = dfltRowColName('r',i) ; } }
+      if (rowNames_[m].length() == 0)
+      { rowNames_[m] = getObjName() ; }
+      return (rowNames_) ; }
+    default:
+    { /* quietly fail */
+      return (zeroLengthNameVec) ; } }
+/*
+  We should never reach here.
+*/
+  assert(false) ;
+
+  return (zeroLengthNameVec) ; }
+  
+
+/*
+  Return a column name, according to the current name discipline, truncated if
+  necessary. If the column index is out of range, the name becomes an error
+  message.
+*/
+std::string OsiSolverInterface::getColName (int ndx, unsigned maxLen) const
+
+{ int nameDiscipline ;
+  std::string name ;
+/*
+  Check for valid column index.
+*/
+  if (ndx < 0 || ndx >= getNumCols())
+  { name = invRowColName('c',ndx) ;
+    return (name) ; }
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Find/generate the proper name, based on discipline.
+*/
+  switch (nameDiscipline)
+  { case 0:
+    { name = dfltRowColName('c',ndx) ;
+      break ; }
+    case 1:
+    case 2:
+    { name = "" ;
+      if (static_cast<unsigned>(ndx) < colNames_.size())
+	name = colNames_[ndx] ;
+      if (name.length() == 0)
+	name = dfltRowColName('c',ndx) ;
+      break ; }
+    default:
+    { name = invRowColName('d',nameDiscipline) ;
+      return (name) ; } }
+/*
+  Return the (possibly truncated) substring. The default for maxLen is npos
+  (no truncation).
+*/
+  return (name.substr(0,maxLen)) ; }
+
+
+/*
+  Return the vector of column names. The vector we need depends on the name
+  discipline:
+    0: return a vector of length 0
+    1: return colNames_, no tweaking required
+    2: Check that colNames_ is complete. Generate a complete vector on
+       the spot if we need it.
+*/
+const OsiSolverInterface::OsiNameVec &OsiSolverInterface::getColNames ()
+
+{ int nameDiscipline ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Return the proper vector, as described at the head of the routine. If we
+  need to generate a full vector, resize the existing vector and scan, filling
+  in entries as required.
+*/
+  switch (nameDiscipline)
+  { case 0:
+    { return (zeroLengthNameVec) ; }
+    case 1:
+    { return (colNames_) ; }
+    case 2:
+    { int n = getNumCols() ;
+      if (colNames_.size() < static_cast<unsigned>(n))
+      { colNames_.resize(n) ; }
+      for (int j = 0 ; j < n ; j++)
+      { if (colNames_[j].length() == 0)
+	{ colNames_[j] = dfltRowColName('c',j) ; } }
+      return (colNames_) ; }
+    default:
+    { /* quietly fail */
+      return (zeroLengthNameVec) ; } }
+/*
+  We should never reach here.
+*/
+  assert(false) ;
+
+  return (zeroLengthNameVec) ; }
+  
+
+/*
+  Set a single row name. Quietly does nothing if the index or name discipline
+  is invalid.
+*/
+void OsiSolverInterface::setRowName (int ndx, std::string name)
+
+{ int nameDiscipline ;
+/*
+  Quietly do nothing if the index is out of bounds. This should be changed,
+  but what's our error convention, eh? There's no precedent in
+  OsiSolverInterface.cpp.
+*/
+  if (ndx < 0 || ndx >= getNumRows())
+  { return ; }
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Do the right thing, according to the discipline.
+*/
+  switch (nameDiscipline)
+  { case 0:
+    { break ; }
+    case 1:
+    case 2:
+    { if (static_cast<unsigned>(ndx) > rowNames_.capacity())
+      { rowNames_.resize(ndx+1) ; }
+      else
+      if (static_cast<unsigned>(ndx) >= rowNames_.size())
+      { rowNames_.resize(ndx+1) ; }
+      rowNames_[ndx] = name ;
+      break ; }
+    default:
+    { break ; } }
+
+  return ; }
+
+/*
+  Set a run of row names. Quietly fail if the specified indices are invalid.
+
+  On the target side, [tgtStart, tgtStart+len-1] must be in the range
+  [0,m-1], where m is the number of rows.  On the source side, srcStart must
+  be zero or greater. If we run off the end of srcNames, we just generate
+  default names.
+*/
+void OsiSolverInterface::setRowNames (OsiNameVec &srcNames,
+				      int srcStart, int len, int tgtStart)
+
+{ int nameDiscipline ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  If the name discipline is auto, we're already done.
+*/
+  if (nameDiscipline == 0)
+  { return ; }
+/*
+  A little self-protection. Check that we're within [0,m-1] on the target side,
+  and that srcStart is zero or greater. Quietly fail if the indices don't fit.
+*/
+  int m = getNumRows() ;
+  if (tgtStart < 0 || tgtStart+len > m)
+  { return ; }
+  if (srcStart < 0)
+  { return ; }
+  int srcLen = static_cast<int>(srcNames.size()) ;
+/*
+  Load 'em up.
+*/
+  int srcNdx = srcStart ;
+  int tgtNdx = tgtStart ;
+  for ( ; tgtNdx < tgtStart+len ; srcNdx++,tgtNdx++)
+  { if (srcNdx < srcLen)
+    { setRowName(tgtNdx,srcNames[srcNdx]) ; }
+    else
+    { setRowName(tgtNdx,dfltRowColName('r',tgtNdx)) ; } }
+
+  return ; }
+
+/*
+  Delete one or more row names.
+*/
+void OsiSolverInterface::deleteRowNames (int tgtStart, int len)
+
+{ int nameDiscipline ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  If the name discipline is auto, we're done.
+*/
+  if (nameDiscipline == 0)
+  { return ; }
+/*
+  Trim the range to names that exist in the name vector. If we're doing lazy
+  names, it's quite likely that we don't need to do any work.
+*/
+  int lastNdx = static_cast<int>(rowNames_.size()) ;
+  if (tgtStart < 0 || tgtStart >= lastNdx)
+  { return ; }
+  if (tgtStart+len > lastNdx)
+  { len = lastNdx-tgtStart ; }
+/*
+  Erase the names.
+*/
+  OsiNameVec::iterator firstIter,lastIter ;
+  firstIter = rowNames_.begin()+tgtStart ;
+  lastIter = firstIter+len ;
+  rowNames_.erase(firstIter,lastIter) ;
+
+  return ; }
+  
+
+/*
+  Set a single column name. Quietly does nothing if the index or name
+  discipline is invalid.
+*/
+void OsiSolverInterface::setColName (int ndx, std::string name)
+
+{ int nameDiscipline ;
+/*
+  Quietly do nothing if the index is out of bounds. This should be changed,
+  but what's our error convention, eh? There's no precedent in
+  OsiSolverInterface.cpp.
+*/
+  if (ndx < 0 || ndx >= getNumCols())
+  { return ; }
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Do the right thing, according to the discipline.
+*/
+  switch (nameDiscipline)
+  { case 0:
+    { break ; }
+    case 1:
+    case 2:
+    { if (static_cast<unsigned>(ndx) > colNames_.capacity())
+      { colNames_.resize(ndx+1) ; }
+      else
+      if (static_cast<unsigned>(ndx) >= colNames_.size())
+      { colNames_.resize(ndx+1) ; }
+      colNames_[ndx] = name ;
+      break ; }
+    default:
+    { break ; } }
+
+  return ; }
+
+/*
+  Set a run of column names. Quietly fail if the specified indices are
+  invalid.
+
+  On the target side, [tgtStart, tgtStart+len-1] must be in the range
+  [0,n-1], where n is the number of columns.  On the source side, srcStart
+  must be zero or greater. If we run off the end of srcNames, we just
+  generate default names.
+*/
+void OsiSolverInterface::setColNames (OsiNameVec &srcNames,
+				      int srcStart, int len, int tgtStart)
+
+{ int nameDiscipline ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  If the name discipline is auto, we're already done.
+*/
+  if (nameDiscipline == 0)
+  { return ; }
+/*
+  A little self-protection. Check that we're within [0,m-1] on the target side,
+  and that srcStart is zero or greater. Quietly fail if the indices don't fit.
+*/
+  int n = getNumCols() ;
+  if (tgtStart < 0 || tgtStart+len > n)
+  { return ; }
+  if (srcStart < 0)
+  { return ; }
+  int srcLen = static_cast<int>(srcNames.size()) ;
+/*
+  Load 'em up.
+*/
+  int srcNdx = srcStart ;
+  int tgtNdx = tgtStart ;
+  for ( ; tgtNdx < tgtStart+len ; srcNdx++,tgtNdx++)
+  { if (srcNdx < srcLen)
+    { setColName(tgtNdx,srcNames[srcNdx]) ; }
+    else
+    { setColName(tgtNdx,dfltRowColName('c',tgtNdx)) ; } }
+
+  return ; }
+
+/*
+  Delete one or more column names. Quietly fail if firstNdx is less than zero
+  or if firstNdx+len is greater than the number of columns.
+*/
+void OsiSolverInterface::deleteColNames (int tgtStart, int len)
+
+{ int nameDiscipline ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  If the name discipline is auto, we're done.
+*/
+  if (nameDiscipline == 0)
+  { return ; }
+/*
+  Trim the range to names that exist in the name vector. If we're doing lazy
+  names, it's quite likely that we don't need to do any work.
+*/
+  int lastNdx = static_cast<int>(colNames_.size()) ;
+  if (tgtStart < 0 || tgtStart >= lastNdx)
+  { return ; }
+  if (tgtStart+len > lastNdx)
+  { len = lastNdx-tgtStart ; }
+/*
+  Erase the names.
+*/
+  OsiNameVec::iterator firstIter,lastIter ;
+  firstIter = colNames_.begin()+tgtStart ;
+  lastIter = firstIter+len ;
+  colNames_.erase(firstIter,lastIter) ;
+
+  return ; }
+
+/*
+  Install the name information from a CoinMpsIO object.
+*/
+void OsiSolverInterface::setRowColNames (const CoinMpsIO &mps)
+
+{ int nameDiscipline,m,n ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Whatever happens, we're about to clean out the current name vectors. Decide
+  on an appropriate size and call reallocRowColNames to adjust capacity.
+*/
+  if (nameDiscipline == 0)
+  { m = 0 ;
+    n = 0 ; }
+  else
+  { m = mps.getNumRows() ;
+    n = mps.getNumCols() ; }
+  reallocRowColNames(rowNames_,m,colNames_,n) ;
+/*
+  If name discipline is auto, we're done already. Otherwise, load 'em
+  up. If I understand MPS correctly, names are required.
+*/
+  if (nameDiscipline != 0)
+  { rowNames_.resize(m) ;
+    for (int i = 0 ; i < m ; i++)
+    { rowNames_[i] = mps.rowName(i) ; }
+    objName_ = mps.getObjectiveName() ;
+    colNames_.resize(n) ;
+    for (int j = 0 ; j < n ; j++)
+    { colNames_[j] = mps.columnName(j) ; } }
+
+  return ; }
+
+
+/*
+  Install the name information from a CoinModel object. CoinModel does not
+  maintain a name for the objective function (in fact, it has no concept of
+  objective function).
+*/
+void OsiSolverInterface::setRowColNames (CoinModel &mod)
+
+{ int nameDiscipline,m,n ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Whatever happens, we're about to clean out the current name vectors. Decide
+  on an appropriate size and call reallocRowColNames to adjust capacity.
+*/
+  if (nameDiscipline == 0)
+  { m = 0 ;
+    n = 0 ; }
+  else
+  { m = mod.rowNames()->numberItems() ;
+    n = mod.columnNames()->numberItems() ; }
+  reallocRowColNames(rowNames_,m,colNames_,n) ;
+/*
+  If name discipline is auto, we're done already. Otherwise, load 'em
+  up. As best I can see, there's no guarantee that we'll have names for all
+  rows and columns, so we need to pay attention.
+*/
+  if (nameDiscipline != 0)
+  { int maxRowNdx=-1, maxColNdx=-1 ;
+    const char *const *names = mod.rowNames()->names() ;
+    rowNames_.resize(m) ;
+    for (int i = 0 ; i < m ; i++)
+    { std::string nme = names[i] ;
+      if (nme.length() == 0)
+      { if (nameDiscipline == 2)
+	{ nme = dfltRowColName('r',i) ; } }
+      if (nme.length() > 0)
+      { maxRowNdx = i ; }
+      rowNames_[i] = nme ; }
+    rowNames_.resize(maxRowNdx+1) ;
+    names = mod.columnNames()->names() ;
+    colNames_.resize(n) ;
+    for (int j = 0 ; j < n ; j++)
+    { std::string nme = names[j] ;
+      if (nme.length() == 0)
+      { if (nameDiscipline == 2)
+	{ nme = dfltRowColName('c',j) ; } }
+      if (nme.length() > 0)
+      { maxColNdx = j ; }
+      colNames_[j] = nme ; }
+    colNames_.resize(maxColNdx+1) ; }
+/*
+  And we're done.
+*/
+  return ; }
+
+
+
+/*
+  Install the name information from a CoinLpIO object. Nearly identical to the
+  previous routine, but we start from a different object.
+*/
+void OsiSolverInterface::setRowColNames (CoinLpIO &mod)
+
+{ int nameDiscipline,m,n ;
+/*
+  Determine how we're handling names. It's possible that the underlying solver
+  has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that
+  case, we want to default to auto names
+*/
+  bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ;
+  if (recognisesOsiNames == false)
+  { nameDiscipline = 0 ; }
+/*
+  Whatever happens, we're about to clean out the current name vectors. Decide
+  on an appropriate size and call reallocRowColNames to adjust capacity.
+*/
+  if (nameDiscipline == 0)
+  { m = 0 ;
+    n = 0 ; }
+  else
+  { m = mod.getNumRows() ;
+    n = mod.getNumCols() ; }
+  reallocRowColNames(rowNames_,m,colNames_,n) ;
+/*
+  If name discipline is auto, we're done already. Otherwise, load 'em
+  up. I have no idea whether we can guarantee valid names for all rows and
+  columns, so we need to pay attention.
+*/
+  if (nameDiscipline != 0)
+  { int maxRowNdx=-1, maxColNdx=-1 ;
+    const char *const *names = mod.getRowNames() ;
+    rowNames_.resize(m) ;
+    for (int i = 0 ; i < m ; i++)
+    { std::string nme = names[i] ;
+      if (nme.length() == 0)
+      { if (nameDiscipline == 2)
+	{ nme = dfltRowColName('r',i) ; } }
+      if (nme.length() > 0)
+      { maxRowNdx = i ; }
+      rowNames_[i] = nme ; }
+    rowNames_.resize(maxRowNdx+1) ;
+    objName_ = mod.getObjName() ;
+    names = mod.getColNames() ;
+    colNames_.resize(n) ;
+    for (int j = 0 ; j < n ; j++)
+    { std::string nme = names[j] ;
+      if (nme.length() == 0)
+      { if (nameDiscipline == 2)
+	{ nme = dfltRowColName('c',j) ; } }
+      if (nme.length() > 0)
+      { maxColNdx = j ; }
+      colNames_[j] = nme ; }
+    colNames_.resize(maxColNdx+1) ; }
+/*
+  And we're done.
+*/
+  return ; }
+
diff --git a/cbits/coin/OsiPresolve.cpp b/cbits/coin/OsiPresolve.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiPresolve.cpp
@@ -0,0 +1,1769 @@
+// Copyright (C) 2002, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*
+  Debug compile symbols for CoinPresolve.
+
+  PRESOLVE_CONSISTENCY, PRESOLVE_DEBUG, and PRESOLVE_SUMMARY control
+  consistency checking and debugging in the continuous presolve. See the
+  comments in CoinPresolvePsdebug.hpp. DO NOT just define the symbols here in
+  this file. Unless these symbols are consistent across all presolve code,
+  you'll get something between garbage and a core dump.
+*/
+
+#include <stdio.h>
+
+#include <cassert>
+#include <iostream>
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinFinite.hpp"
+
+#include "CoinPackedMatrix.hpp"
+#include "CoinWarmStartBasis.hpp"
+#include "OsiSolverInterface.hpp"
+
+#include "OsiPresolve.hpp"
+#include "CoinPresolveMatrix.hpp"
+
+#if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 || PRESOLVE_SUMMARY > 0
+#include "CoinPresolvePsdebug.hpp"
+#include "CoinPresolveMonitor.hpp"
+#endif
+#include "CoinPresolveEmpty.hpp"
+#include "CoinPresolveFixed.hpp"
+#include "CoinPresolveSingleton.hpp"
+#include "CoinPresolveDoubleton.hpp"
+#include "CoinPresolveTripleton.hpp"
+#include "CoinPresolveZeros.hpp"
+#include "CoinPresolveSubst.hpp"
+#include "CoinPresolveForcing.hpp"
+#include "CoinPresolveDual.hpp"
+#include "CoinPresolveTighten.hpp"
+#include "CoinPresolveUseless.hpp"
+#include "CoinPresolveDupcol.hpp"
+#include "CoinPresolveImpliedFree.hpp"
+#include "CoinPresolveIsolated.hpp"
+#include "CoinMessage.hpp"
+
+
+OsiPresolve::OsiPresolve() :
+  originalModel_(NULL),
+  presolvedModel_(NULL),
+  nonLinearValue_(0.0),
+  originalColumn_(NULL),
+  originalRow_(NULL),
+  paction_(0),
+  ncols_(0),
+  nrows_(0),
+  nelems_(0),
+  presolveActions_(0),
+  numberPasses_(5)
+{
+}
+
+OsiPresolve::~OsiPresolve()
+{
+  gutsOfDestroy();
+}
+// Gets rid of presolve actions (e.g.when infeasible)
+void 
+OsiPresolve::gutsOfDestroy()
+{
+ const CoinPresolveAction *paction = paction_;
+  while (paction) {
+    const CoinPresolveAction *next = paction->next;
+    delete paction;
+    paction = next;
+  }
+  delete [] originalColumn_;
+  delete [] originalRow_;
+  paction_=NULL;
+  originalColumn_=NULL;
+  originalRow_=NULL;
+}
+
+/* This version of presolve returns a pointer to a new presolved 
+   model.  NULL if infeasible
+
+   doStatus controls activities required to transform an existing
+   solution to match the presolved problem. I'd (lh) argue that this should
+   default to false, but to maintain previous behaviour it defaults to true.
+   Really, this is only useful if you've already optimised before applying
+   presolve and also want to work with the solution after presolve.  I think
+   that this is the less common case. The more common situation is to apply
+   presolve before optimising.
+*/
+OsiSolverInterface * 
+OsiPresolve::presolvedModel(OsiSolverInterface & si,
+			    double feasibilityTolerance,
+			    bool keepIntegers,
+			    int numberPasses,
+                            const char * prohibited,
+			    bool doStatus,
+			    const char * rowProhibited)
+{
+  ncols_ = si.getNumCols();
+  nrows_ = si.getNumRows();
+  nelems_ = si.getNumElements();
+  numberPasses_ = numberPasses;
+
+  double maxmin = si.getObjSense();
+  originalModel_ = &si;
+  delete [] originalColumn_;
+  originalColumn_ = new int[ncols_];
+  delete [] originalRow_;
+  originalRow_ = new int[nrows_];
+  int i;
+  for (i=0;i<ncols_;i++) 
+    originalColumn_[i]=i;
+  for (i=0;i<nrows_;i++) 
+    originalRow_[i]=i;
+
+  // result is 0 - okay, 1 infeasible, -1 go round again
+  int result = -1;
+  
+  // User may have deleted - its their responsibility
+  presolvedModel_=NULL;
+  // Messages
+  CoinMessages msgs = CoinMessage(si.messages().language());
+  // Only go round 100 times even if integer preprocessing
+  int totalPasses=100;
+  while (result == -1) {
+
+    // make new copy
+    delete presolvedModel_;
+    presolvedModel_ = si.clone();
+    totalPasses--;
+
+    // drop integer information if wanted
+    if (!keepIntegers) {
+      int i;
+      for (i=0;i<ncols_;i++)
+	presolvedModel_->setContinuous(i);
+    }
+
+    
+    CoinPresolveMatrix prob(ncols_,
+			    maxmin,
+			    presolvedModel_,
+			    nrows_, nelems_,doStatus,nonLinearValue_,prohibited,
+			    rowProhibited);
+    // make sure row solution correct
+    if (doStatus) {
+      double *colels	= prob.colels_;
+      int *hrow		= prob.hrow_;
+      CoinBigIndex *mcstrt		= prob.mcstrt_;
+      int *hincol		= prob.hincol_;
+      int ncols		= prob.ncols_;
+      
+      
+      double * csol = prob.sol_;
+      double * acts = prob.acts_;
+      int nrows = prob.nrows_;
+
+      int colx;
+
+      memset(acts,0,nrows*sizeof(double));
+      
+      for (colx = 0; colx < ncols; ++colx) {
+	double solutionValue = csol[colx];
+	for (int i=mcstrt[colx]; i<mcstrt[colx]+hincol[colx]; ++i) {
+	  int row = hrow[i];
+	  double coeff = colels[i];
+	  acts[row] += solutionValue*coeff;
+	}
+      }
+    }
+
+    // move across feasibility tolerance
+    prob.feasibilityTolerance_ = feasibilityTolerance;
+
+/*
+  Do presolve. Allow for the possibility that presolve might be ineffective
+  (i.e., we're feasible but no postsolve actions are queued.
+*/
+    paction_ = presolve(&prob) ;
+    result = 0 ; 
+    // Get rid of useful arrays
+    prob.deleteStuff();
+/*
+  This we don't need to do unless presolve actually reduced the system.
+*/
+    if (prob.status_==0&&paction_) {
+      // Looks feasible but double check to see if anything slipped through
+      int n		= prob.ncols_;
+      double * lo = prob.clo_;
+      double * up = prob.cup_;
+      int i;
+      
+      for (i=0;i<n;i++) {
+	if (up[i]<lo[i]) {
+	  if (up[i]<lo[i]-1.0e-8) {
+	    // infeasible
+	    prob.status_=1;
+	  } else {
+	    up[i]=lo[i];
+	  }
+	}
+      }
+      
+      n = prob.nrows_;
+      lo = prob.rlo_;
+      up = prob.rup_;
+
+      for (i=0;i<n;i++) {
+	if (up[i]<lo[i]) {
+	  if (up[i]<lo[i]-1.0e-8) {
+	    // infeasible
+	    prob.status_=1;
+	  } else {
+	    up[i]=lo[i];
+	  }
+	}
+      }
+    }
+/*
+  If we're feasible, load the presolved system into the solver. Presumably we
+  could skip model update and copying of status and solution if presolve took
+  no action.
+*/
+    if (prob.status_ == 0) {
+    
+      prob.update_model(presolvedModel_, nrows_, ncols_, nelems_);
+
+# if PRESOLVE_CONSISTENCY > 0
+      if (doStatus)
+      { int basicCnt = 0 ;
+	int basicColumns = 0;
+	int i ;
+	CoinPresolveMatrix::Status status ;
+	for (i = 0 ; i < prob.ncols_ ; i++)
+	{ status = prob.getColumnStatus(i);
+	  if (status == CoinPrePostsolveMatrix::basic) basicColumns++ ; }
+	basicCnt = basicColumns;
+	for (i = 0 ; i < prob.nrows_ ; i++)
+	{ status = prob.getRowStatus(i);
+	  if (status == CoinPrePostsolveMatrix::basic) basicCnt++ ; }
+
+# if PRESOLVE_DEBUG > 0
+	presolve_check_nbasic(&prob) ;
+# endif
+	if (basicCnt>prob.nrows_) {
+	  // Take out slacks
+	  double * acts = prob.acts_;
+	  double * rlo = prob.rlo_;
+	  double * rup = prob.rup_;
+	  double infinity = si.getInfinity();
+	  for (i = 0 ; i < prob.nrows_ ; i++) {
+	    status = prob.getRowStatus(i);
+	    if (status == CoinPrePostsolveMatrix::basic) {
+	      basicCnt-- ;
+	      double down = acts[i]-rlo[i];
+	      double up = rup[i]-acts[i];
+	      if (CoinMin(up,down)<infinity) {
+		if (down<=up)
+		  prob.setRowStatus(i,CoinPrePostsolveMatrix::atLowerBound);
+		else
+		  prob.setRowStatus(i,CoinPrePostsolveMatrix::atUpperBound);
+	      } else {
+		prob.setRowStatus(i,CoinPrePostsolveMatrix::isFree);
+	      }
+	    }
+	    if (basicCnt==prob.nrows_)
+	      break;
+	  }
+	}
+      }
+#endif
+
+/*
+  Install the status and primal solution, if we've been carrying them along.
+
+  The code that copies status is efficient but brittle. The current definitions
+  for CoinWarmStartBasis::Status and CoinPrePostsolveMatrix::Status are in
+  one-to-one correspondence. This code will fail if that ever changes.
+*/
+      if (doStatus) {
+	presolvedModel_->setColSolution(prob.sol_);
+	CoinWarmStartBasis *basis = 
+	  dynamic_cast<CoinWarmStartBasis *>(presolvedModel_->getEmptyWarmStart());
+	basis->resize(prob.nrows_,prob.ncols_);
+	int i;
+	for (i=0;i<prob.ncols_;i++) {
+	  CoinWarmStartBasis::Status status = 
+	    static_cast<CoinWarmStartBasis::Status> (prob.getColumnStatus(i));
+	  basis->setStructStatus(i,status);
+	}
+	for (i=0;i<prob.nrows_;i++) {
+	  CoinWarmStartBasis::Status status = 
+	    static_cast<CoinWarmStartBasis::Status> (prob.getRowStatus(i));
+	  basis->setArtifStatus(i,status);
+	}
+	presolvedModel_->setWarmStart(basis);
+	delete basis ;
+	delete [] prob.sol_;
+	delete [] prob.acts_;
+	delete [] prob.colstat_;
+	prob.sol_=NULL;
+	prob.acts_=NULL;
+	prob.colstat_=NULL;
+      }
+/*
+  Copy original column and row information from the CoinPresolveMatrix object
+  so it'll be available for postsolve.
+*/
+      int ncolsNow = presolvedModel_->getNumCols();
+      memcpy(originalColumn_,prob.originalColumn_,ncolsNow*sizeof(int));
+      delete [] prob.originalColumn_;
+      prob.originalColumn_=NULL;
+      int nrowsNow = presolvedModel_->getNumRows();
+      memcpy(originalRow_,prob.originalRow_,nrowsNow*sizeof(int));
+      delete [] prob.originalRow_;
+      prob.originalRow_=NULL;
+
+      // now clean up integer variables.  This can modify original
+      {
+	int numberChanges=0;
+	const double * lower0 = originalModel_->getColLower();
+	const double * upper0 = originalModel_->getColUpper();
+	const double * lower = presolvedModel_->getColLower();
+	const double * upper = presolvedModel_->getColUpper();
+	for (i=0;i<ncolsNow;i++) {
+	  if (!presolvedModel_->isInteger(i))
+	    continue;
+	  int iOriginal = originalColumn_[i];
+	  double lowerValue0 = lower0[iOriginal];
+	  double upperValue0 = upper0[iOriginal];
+	  double lowerValue = ceil(lower[i]-1.0e-5);
+	  double upperValue = floor(upper[i]+1.0e-5);
+	  presolvedModel_->setColBounds(i,lowerValue,upperValue);
+	  if (lowerValue>upperValue) {
+	    numberChanges++;
+	    CoinMessageHandler *hdlr = presolvedModel_->messageHandler() ;
+	    hdlr->message(COIN_PRESOLVE_COLINFEAS,msgs)
+	        << iOriginal << lowerValue << upperValue << CoinMessageEol ;
+	    result=1;
+	  } else {
+	    if (lowerValue>lowerValue0+1.0e-8) {
+	      originalModel_->setColLower(iOriginal,lowerValue);
+	      numberChanges++;
+	    }
+	    if (upperValue<upperValue0-1.0e-8) {
+	      originalModel_->setColUpper(iOriginal,upperValue);
+	      numberChanges++;
+	    }
+	  }	  
+	}
+	if (numberChanges) {
+	  CoinMessageHandler *hdlr = presolvedModel_->messageHandler() ;
+	  hdlr->message(COIN_PRESOLVE_INTEGERMODS,msgs)
+	      << numberChanges << CoinMessageEol;
+	  // we can't go round again in integer if dupcols
+	  if (!result && totalPasses > 0 &&
+	      (prob.presolveOptions_&0x80000000) == 0) {
+	    result = -1; // round again
+	    const CoinPresolveAction *paction = paction_;
+	    while (paction) {
+	      const CoinPresolveAction *next = paction->next;
+	      delete paction;
+	      paction = next;
+	    }
+	    paction_=NULL;
+	  }
+	}
+      }
+    } else if (prob.status_ != 0) { 
+      // infeasible or unbounded
+      result = 1 ;
+    }
+  }
+  if (!result) {
+    int nrowsAfter = presolvedModel_->getNumRows();
+    int ncolsAfter = presolvedModel_->getNumCols();
+    CoinBigIndex nelsAfter = presolvedModel_->getNumElements();
+    CoinMessageHandler *hdlr = presolvedModel_->messageHandler() ;
+    hdlr->message(COIN_PRESOLVE_STATS,msgs)
+        << nrowsAfter << -(nrows_-nrowsAfter)
+	<< ncolsAfter << -(ncols_-ncolsAfter)
+        << nelsAfter << -(nelems_-nelsAfter) << CoinMessageEol ;
+  } else {
+    gutsOfDestroy();
+    delete presolvedModel_;
+    presolvedModel_=NULL;
+  }
+  return presolvedModel_;
+}
+
+// Return pointer to presolved model
+OsiSolverInterface * 
+OsiPresolve::model() const
+{
+  return presolvedModel_;
+}
+// Return pointer to original model
+OsiSolverInterface * 
+OsiPresolve::originalModel() const
+{
+  return originalModel_;
+}
+
+void 
+OsiPresolve::postsolve(bool updateStatus)
+{
+  // Messages
+  CoinMessages msgs = CoinMessage(presolvedModel_->messages().language()) ;
+  CoinMessageHandler *hdlr = presolvedModel_->messageHandler() ;
+  if (!presolvedModel_->isProvenOptimal()) {
+    hdlr->message(COIN_PRESOLVE_NONOPTIMAL,msgs) << CoinMessageEol ;
+  }
+
+  // this is the size of the original problem
+  const int ncols0  = ncols_ ;
+  const int nrows0  = nrows_ ;
+  const CoinBigIndex nelems0 = nelems_ ;
+
+  // reality check
+  assert(ncols0 == originalModel_->getNumCols()) ;
+  assert(nrows0 == originalModel_->getNumRows()) ;
+
+  // this is the reduced problem
+  int ncols = presolvedModel_->getNumCols() ;
+  int nrows = presolvedModel_->getNumRows() ;
+
+  double *acts = new double [nrows0] ;
+  double *sol = new double [ncols0] ;
+  CoinZeroN(acts,nrows0) ;
+  CoinZeroN(sol,ncols0) ;
+  
+  unsigned char *rowstat = NULL ;
+  unsigned char *colstat = NULL ;
+  CoinWarmStartBasis *presolvedBasis  = 
+    dynamic_cast<CoinWarmStartBasis*>(presolvedModel_->getWarmStart()) ;
+  if (!presolvedBasis) updateStatus = false ;
+  if (updateStatus) {
+    colstat = new unsigned char[ncols0+nrows0] ;
+#   ifdef ZEROFAULT
+    memset(colstat,0,((ncols0+nrows0)*sizeof(char))) ;
+#   endif
+    rowstat = colstat+ncols0 ;
+    for (int i = 0 ; i < ncols ; i++) {
+      colstat[i] = presolvedBasis->getStructStatus(i) ;
+    }
+    for (int i = 0 ; i < nrows ; i++) {
+      rowstat[i] = presolvedBasis->getArtifStatus(i) ;
+    }
+  } 
+  delete presolvedBasis ;
+
+# if PRESOLVE_CONSISTENCY > 0
+  if (updateStatus)
+  { int basicCnt = 0 ;
+    for (int i = 0 ; i < ncols ; i++)
+    { if (colstat[i] == CoinWarmStartBasis::basic) basicCnt++ ; }
+    for (int i = 0 ; i < nrows ; i++)
+    { if (rowstat[i] == CoinWarmStartBasis::basic) basicCnt++ ; }
+
+    assert (basicCnt == nrows) ;
+  }
+# endif
+
+/*
+  Postsolve back to the original problem.  The CoinPostsolveMatrix object
+  assumes ownership of sol, acts, colstat, and rowstat.
+*/
+  CoinPostsolveMatrix prob(presolvedModel_,ncols0,nrows0,nelems0,
+			   presolvedModel_->getObjSense(),
+			   sol,acts,colstat,rowstat) ;
+  postsolve(prob) ;
+
+# if PRESOLVE_CONSISTENCY > 0
+  if (updateStatus)
+  { int basicCnt = 0 ;
+    for (int i = 0 ; i < ncols0 ; i++)
+    { if (prob.getColumnStatus(i) == CoinPrePostsolveMatrix::basic)
+      basicCnt++ ; }
+    for (int i = 0 ; i < nrows0 ; i++)
+    { if (prob.getRowStatus(i) == CoinPrePostsolveMatrix::basic)
+      basicCnt++ ; }
+
+    assert (basicCnt == nrows0) ;
+  }
+# endif
+
+  originalModel_->setColSolution(sol) ;
+  if (updateStatus) {
+    CoinWarmStartBasis *basis = 
+      dynamic_cast<CoinWarmStartBasis *>(presolvedModel_->getEmptyWarmStart()) ;
+    basis->setSize(ncols0,nrows0) ;
+    for (int i = 0 ; i < ncols0 ; i++) {
+      CoinWarmStartBasis::Status status =
+          static_cast<CoinWarmStartBasis::Status>(prob.getColumnStatus(i)) ;
+      assert(status != CoinWarmStartBasis::atLowerBound || originalModel_->getColLower()[i] > -originalModel_->getInfinity()) ;
+      assert(status != CoinWarmStartBasis::atUpperBound || originalModel_->getColUpper()[i] <  originalModel_->getInfinity()) ;
+      basis->setStructStatus(i,status);
+    }
+
+# if PRESOLVE_DEBUG > 0
+  /*
+    Do a thorough check of row and column solutions. There should be no
+    inconsistencies at this point.
+  */
+  std::cout
+    << "Checking solution before transferring basis." << std::endl ;
+  presolve_check_sol(&prob,2,2,2) ;
+  int errs = 0 ;
+# endif
+    for (int i = 0 ; i < nrows0 ; i++) {
+      CoinWarmStartBasis::Status status =
+          static_cast<CoinWarmStartBasis::Status>(prob.getRowStatus(i)) ;
+      basis->setArtifStatus(i,status);
+    }
+    originalModel_->setWarmStart(basis);
+    delete basis ;
+  } 
+
+}
+
+// return pointer to original columns
+const int * 
+OsiPresolve::originalColumns() const
+{
+  return originalColumn_;
+}
+// return pointer to original rows
+const int * 
+OsiPresolve::originalRows() const
+{
+  return originalRow_;
+}
+// Set pointer to original model
+void 
+OsiPresolve::setOriginalModel(OsiSolverInterface * model)
+{
+  originalModel_=model;
+}
+
+#if 0
+// A lazy way to restrict which transformations are applied
+// during debugging.
+static int ATOI(const char *name)
+{
+ return true;
+#if	PRESOLVE_DEBUG > 0 || PRESOLVE_SUMMARY > 0
+  if (getenv(name)) {
+    int val = atoi(getenv(name));
+    printf("%s = %d\n", name, val);
+    return (val);
+  } else {
+    if (strcmp(name,"off"))
+      return (true);
+    else
+      return (false);
+  }
+#else
+  return (true);
+#endif
+}
+#endif
+
+#if PRESOLVE_DEBUG > 0
+// Anonymous namespace for debug routines
+namespace {
+
+/*
+  A control routine for debug checks --- keeps down the clutter in doPresolve.
+  Each time it's called, it prints a list of transforms applied since the last
+  call, then does checks.
+*/
+
+void check_and_tell (const CoinPresolveMatrix *const prob,
+		     const CoinPresolveAction *first,
+		     const CoinPresolveAction *&mark)
+
+{ const CoinPresolveAction *current ;
+
+  if (first != mark)
+  { printf("PRESOLVE: applied") ;
+    for (current = first ;
+	 current != mark && current != 0 ;
+	 current = current->next)
+    { printf(" %s",current->name()) ; }
+    printf("\n") ;
+
+    presolve_check_sol(prob) ;
+    presolve_check_nbasic(prob) ;
+    mark = first ; }
+
+  return ; }
+
+/*
+  At a guess, this code is intended to allow a known solution to be checked
+  against presolve progress. Pulled it into the local debug namespace, but
+  really should be integrated with CoinPresolvePsdebug.  At the least, needs
+  a method to conveniently set debugSolution.
+  -- lh, 110605 --
+*/
+double *debugSolution = NULL ;
+int debugNumberColumns = -1 ;
+int counter = 1000000 ;
+
+bool break2 (CoinPresolveMatrix *prob) {
+  if (counter > 0)
+    printf("break2: counter %d\n",counter) ;
+  counter-- ;
+  if (debugSolution && prob->ncols_ == debugNumberColumns) {
+    for (int i = 0 ; i < prob->ncols_ ; i++) {
+      double value = debugSolution[i] ;
+      if (value < prob->clo_[i]) {
+	printf("%d inf %g %g %g\n",i,prob->clo_[i],value,prob->cup_[i]) ;
+      } else if (value > prob->cup_[i]) {
+	printf("%d inf %g %g %g\n",i,prob->clo_[i],value,prob->cup_[i]) ;
+      }
+    }
+  }
+  if (!counter) {
+    printf("skipping next and all\n") ;
+  }
+  return (counter <= 0) ;
+}
+
+} // end anonymous namespace for debug routines
+#endif
+
+#if PRESOLVE_DEBUG > 0
+# define possibleBreak if (break2(prob)) break
+# define possibleSkip  if (!break2(prob)) 
+#else
+# define possibleBreak
+# define possibleSkip
+#endif
+
+// This is the presolve loop.
+// It is a separate virtual function so that it can be easily
+// customized by subclassing CoinPresolve.
+
+const CoinPresolveAction *OsiPresolve::presolve(CoinPresolveMatrix *prob)
+{
+  paction_ = 0 ;
+
+  prob->status_ = 0 ; // say feasible
+
+# if PRESOLVE_DEBUG > 0
+  const CoinPresolveAction *pactiond = 0 ;
+  presolve_check_sol(prob,2,1,1) ;
+
+  // CoinPresolveMonitor *monitor = new CoinPresolveMonitor(prob,true,22) ;
+  CoinPresolveMonitor *monitor = 0 ;
+# endif
+/*
+  Transfer costs off of singleton variables, and also between integer
+  variables when advantageous.
+
+  transferCosts is defined in CoinPresolveFixed.cpp
+*/
+  if ((presolveActions_&0x04) != 0) {
+    transferCosts(prob) ;
+#   if PRESOLVE_DEBUG > 0
+    if (monitor) monitor->checkAndTell(prob) ;
+#   endif
+  }
+/*
+  Fix variables before we get into the main transform loop.
+*/
+  paction_ = make_fixed(prob,paction_) ;
+
+# if PRESOLVE_DEBUG > 0
+  check_and_tell(prob,paction_,pactiond) ;
+  if (monitor) monitor->checkAndTell(prob) ;
+# endif
+
+  // if integers then switch off dual stuff
+  // later just do individually
+  bool doDualStuff = true ;
+  if ((presolveActions_&0x01) == 0) {
+    int ncol = presolvedModel_->getNumCols() ;
+    for (int i = 0 ; i < ncol ; i++)
+      if (presolvedModel_->isInteger(i))
+	doDualStuff = false ;
+  }
+  
+
+# if PRESOLVE_CONSISTENCY > 0
+  presolve_links_ok(prob) ;
+# endif
+
+/*
+  If we're feasible, set up for the main presolve transform loop.
+*/
+  if (!prob->status_) {
+# if 0
+/*
+  This block is used during debugging. See ATOI to see how it works. Some
+  editing will be required to turn it all on.
+*/
+    bool slackd = ATOI("SLACKD")!=0;
+    //bool forcing = ATOI("FORCING")!=0;
+    bool doubleton = ATOI("DOUBLETON")!=0;
+    bool forcing = ATOI("off")!=0;
+    bool ifree = ATOI("off")!=0;
+    bool zerocost = ATOI("off")!=0;
+    bool dupcol = ATOI("off")!=0;
+    bool duprow = ATOI("off")!=0;
+    bool dual = ATOI("off")!=0;
+# else
+# if 1
+    // normal operation --- all transforms enabled
+    bool slackSingleton = true;
+    bool slackd = true;
+    bool doubleton = true;
+    bool tripleton = true;
+    bool forcing = true;
+    bool ifree = true;
+    bool zerocost = true;
+    bool dupcol = true;
+    bool duprow = true;
+    bool dual = doDualStuff;
+# else
+    // compile time selection of transforms.
+    bool slackSingleton = true;
+    bool slackd = false;
+    bool doubleton = true;
+    bool tripleton = true;
+    bool forcing = true;
+    bool ifree = false;
+    bool zerocost = false;
+    bool dupcol = false;
+    bool duprow = false;
+    bool dual = false;
+# endif
+# endif
+/*
+  Process OsiPresolve options. Set corresponding CoinPresolve options and
+  control variables here.
+*/
+    // Switch off some stuff if would annoy set partitioning etc
+    if ((presolveActions_&0x02) != 0) {
+      doubleton = false;
+      tripleton = false;
+      ifree = false;
+    }
+    // stop x+y+z=1
+    if ((presolveActions_&0x08) != 0)
+      prob->setPresolveOptions(prob->presolveOptions()|0x04) ;
+    // switch on stuff which can't be unrolled easily
+    if ((presolveActions_&0x10) != 0)
+      prob->setPresolveOptions(prob->presolveOptions()|0x10) ;
+    // switch on gub stuff (unimplemented as of 110605 -- lh --)
+    if ((presolveActions_&0x20) != 0)
+      prob->setPresolveOptions(prob->presolveOptions()|0x20) ;
+    // allow duplicate column processing for integer columns
+    if ((presolveActions_&0x01) != 0)
+      prob->setPresolveOptions(prob->presolveOptions()|0x01) ;
+/*
+  Set [rows,cols]ToDo to process all rows & cols unless there are
+  specific prohibitions.
+*/
+    prob->initColsToDo() ;
+    prob->initRowsToDo() ;
+/*
+  Try to remove duplicate rows and columns.
+*/
+    if (dupcol) {
+      possibleSkip ;
+      paction_ = dupcol_action::presolve(prob,paction_) ;
+#     if PRESOLVE_DEBUG > 0
+      if (monitor) monitor->checkAndTell(prob) ;
+#     endif
+    }
+    if (duprow) {
+      possibleSkip ;
+      paction_ = duprow_action::presolve(prob,paction_) ;
+#     if PRESOLVE_DEBUG > 0
+      if (monitor) monitor->checkAndTell(prob) ;
+#     endif
+    }
+/*
+  The main loop starts with a minor loop that does inexpensive presolve
+  transforms until convergence. At each iteration of this loop,
+  next[Rows,Cols]ToDo is copied over to [rows,cols]ToDo.
+
+  Then there's a block to set [rows,cols]ToDo to examine all rows & cols,
+  followed by executions of expensive transforms. Then we come back around for
+  another iteration of the main loop. [rows,cols]ToDo is not reset as we come
+  back around, so we dive into the inexpensive loop set up to process all.
+
+  lastDropped is a count of total number of rows dropped by presolve. Used as
+  an additional criterion to end the main presolve loop.
+*/
+    int lastDropped = 0 ;
+    prob->pass_ = 0 ;
+    for (int iLoop = 0 ; iLoop < numberPasses_ ; iLoop++) {
+
+#     if PRESOLVE_SUMMARY > 0
+      std::cout << "Starting major pass " << (iLoop+1) << std::endl ;
+#     endif
+
+      const CoinPresolveAction *const paction0 = paction_ ;
+// #define IMPLIED 3
+#ifdef IMPLIED
+      int fill_level = 3 ;
+# define IMPLIED2 1
+# if IMPLIED != 3
+#   if IMPLIED > 0 && IMPLIED < 11
+      fill_level = IMPLIED ;
+      printf("** fill_level == %d !\n",fill_level) ;
+#   endif
+#   if IMPLIED > 11 && IMPLIED < 21
+      fill_level = -(IMPLIED-10) ;
+      printf("** fill_level == %d !\n",fill_level);
+#   endif
+# endif
+#else
+      // look for substitutions with no fill
+      int fill_level = 2 ;
+#endif
+      int whichPass = 0 ;
+/*
+  Apply inexpensive transforms until convergence or infeasible/unbounded.
+*/
+      while (true) {
+	whichPass++ ;
+	prob->pass_++ ;
+	const CoinPresolveAction *const paction1 = paction_ ;
+
+	if (slackd) {
+	  bool notFinished = true ;
+	  while (notFinished) {
+	    possibleBreak ;
+	    paction_ =
+	       slack_doubleton_action::presolve(prob,paction_,notFinished) ;
+	  }
+#	  if PRESOLVE_DEBUG > 0
+	  check_and_tell(prob,paction_,pactiond) ;
+	  if (monitor) monitor->checkAndTell(prob) ;
+#	  endif
+	  if (prob->status_) break ;
+	}
+
+	if (dual && whichPass == 1) {
+	  possibleBreak;
+	  // this can also make E rows so do one bit here
+	  paction_ = remove_dual_action::presolve(prob,paction_) ;
+#	  if PRESOLVE_DEBUG > 0
+	  check_and_tell(prob,paction_,pactiond) ;
+	  if (monitor) monitor->checkAndTell(prob) ;
+#	  endif
+	  if (prob->status_) break ;
+	}
+
+	if (doubleton) {
+	  possibleBreak ;
+	  paction_ = doubleton_action::presolve(prob,paction_) ;
+#	  if PRESOLVE_DEBUG > 0
+	  check_and_tell(prob,paction_,pactiond) ;
+	  if (monitor) monitor->checkAndTell(prob) ;
+#	  endif
+	  if (prob->status_) break ;
+	}
+
+	if (tripleton) {
+	  possibleBreak ;
+	  paction_ = tripleton_action::presolve(prob,paction_) ;
+#	  if PRESOLVE_DEBUG > 0
+	  check_and_tell(prob,paction_,pactiond) ;
+	  if (monitor) monitor->checkAndTell(prob) ;
+#	  endif
+	  if (prob->status_) break ;
+	}
+
+	if (zerocost) {
+	  possibleBreak ;
+	  paction_ = do_tighten_action::presolve(prob,paction_) ;
+#	  if PRESOLVE_DEBUG > 0
+	  check_and_tell(prob,paction_,pactiond) ;
+	  if (monitor) monitor->checkAndTell(prob) ;
+#	  endif
+	  if (prob->status_) break ;
+	}
+
+	if (forcing) {
+	  possibleBreak;
+	  paction_ = forcing_constraint_action::presolve(prob, paction_);
+#	  if PRESOLVE_DEBUG > 0
+	  check_and_tell(prob,paction_,pactiond) ;
+	  if (monitor) monitor->checkAndTell(prob) ;
+#	  endif
+	  if (prob->status_) break ;
+	}
+
+	if (ifree && (whichPass%5) == 1) {
+	  possibleBreak ;
+	  paction_ = implied_free_action::presolve(prob,paction_,fill_level) ;
+#	  if PRESOLVE_DEBUG > 0
+	  check_and_tell(prob,paction_,pactiond) ;
+	  if (monitor) monitor->checkAndTell(prob) ;
+#	  endif
+	  if (prob->status_) break ;
+	}
+
+#	if PRESOLVE_CONSISTENCY > 0
+	presolve_links_ok(prob) ;
+	presolve_no_zeros(prob) ;
+	presolve_consistent(prob) ;
+#	endif
+/*
+  Set up for next pass.
+  
+  Original comment adds: later do faster if many changes i.e. memset and memcpy
+*/
+        prob->stepRowsToDo() ;
+
+#	if PRESOLVE_DEBUG > 0
+	int rowCheck = -1 ;
+	bool rowFound = false ;
+	for (int i = 0 ; i < prob->numberRowsToDo_ ; i++) {
+	  int index = prob->rowsToDo_[i];
+	  if (index == rowCheck) {
+	    std::cout
+	      << "  row " << index << " on list after pass " << whichPass
+	      << std::endl ;
+	    rowFound = true ;
+	  }
+	}
+	if (!rowFound && rowCheck >= 0)
+	  prob->rowsToDo_[prob->numberRowsToDo_++] = rowCheck ;
+#	endif
+
+	prob->stepColsToDo() ;
+
+#	if PRESOLVE_DEBUG > 0
+	int colCheck = -1 ;
+	bool colFound = false ;
+	for (int i = 0 ; i < prob->numberNextColsToDo_ ; i++) {
+	  int index = prob->colsToDo_[i] ;
+	  if (index == colCheck) {
+	    std::cout
+	      << "  col " << index << " on list after pass " << whichPass
+	      << std::endl ;
+	    colFound = true ;
+	  }
+	}
+	if (!colFound && colCheck >= 0)
+	  prob->colsToDo_[prob->numberColsToDo_++] = colCheck ;
+#	endif
+/*
+  Break if nothing happened (no postsolve actions queued).
+
+  The check for fill_level > 0 is a hack to allow repeating the loop with some
+  modified fill level (playing with negative values).
+  
+  fill_level = 0 (as set in other places) will clearly be a problem.
+  -- lh, 110605 --
+*/
+	if (paction_ == paction1 && fill_level > 0) break ;
+      }
+/*
+  End of inexpensive transform loop.
+  Reset [rows,cols]ToDo to process all rows and columns unless there are
+  specfic prohibitions.
+*/
+      prob->initRowsToDo() ;
+      prob->initColsToDo() ;
+/*
+  Try expensive presolve transforms.
+
+  Original comment adds: this caused world.mps to run into numerical
+  			 difficulties
+*/
+#     if PRESOLVE_SUMMARY > 0
+      std::cout << "Starting expensive." << std::endl ;
+#     endif
+/*
+  Try and fix variables at upper or lower bound by calculating bounds on the
+  dual variables and propagating them to the reduced costs. Every other
+  iteration, see if this has created free variables.
+*/
+      if (dual) {
+	for (int itry = 0 ; itry < 5 ; itry++) {
+	  const CoinPresolveAction *const paction2 = paction_ ;
+	  possibleBreak ;
+	  paction_ = remove_dual_action::presolve(prob,paction_) ;
+#	  if PRESOLVE_DEBUG > 0
+	  check_and_tell(prob,paction_,pactiond) ;
+	  if (monitor) monitor->checkAndTell(prob) ;
+#	  endif
+	  if (prob->status_) break ;
+	  if (ifree) {
+#ifdef IMPLIED
+# if IMPLIED2 == 0
+	    int fill_level = 0 ; // switches off substitution
+# elif IMPLIED2 != 99
+	    int fill_level = IMPLIED2 ;
+# endif
+#endif
+	    if ((itry&1) == 0) {
+	      possibleBreak ;
+	      paction_ =
+	          implied_free_action::presolve(prob,paction_,fill_level) ;
+	    }
+#	    if PRESOLVE_DEBUG > 0
+	    check_and_tell(prob,paction_,pactiond) ;
+	    if (monitor) monitor->checkAndTell(prob) ;
+#	    endif
+	    if (prob->status_) break ;
+	  }
+	  if (paction_ == paction2) break ;
+	}
+      } else if (ifree) {
+/*
+  Just check for free variables.
+*/
+#ifdef IMPLIED
+# if IMPLIED2 == 0
+	int fill_level = 0 ; // switches off substitution
+# elif IMPLIED2 != 99
+	int fill_level = IMPLIED2 ;
+# endif
+#endif
+	possibleBreak ;
+	paction_ = implied_free_action::presolve(prob,paction_,fill_level) ;
+#	if PRESOLVE_DEBUG > 0
+	check_and_tell(prob,paction_,pactiond) ;
+	if (monitor) monitor->checkAndTell(prob) ;
+#	endif
+	if (prob->status_) break ;
+      }
+/*
+  Check if other transformations have produced duplicate rows or columns.
+*/
+      if (dupcol) {
+	possibleBreak ;
+	paction_ = dupcol_action::presolve(prob,paction_) ;
+#	if PRESOLVE_DEBUG > 0
+	check_and_tell(prob,paction_,pactiond) ;
+	if (monitor) monitor->checkAndTell(prob) ;
+#	endif
+	if (prob->status_) break ;
+      }
+      if (duprow) {
+	possibleBreak ;
+	paction_ = duprow_action::presolve(prob,paction_) ;
+#	if PRESOLVE_DEBUG > 0
+	check_and_tell(prob,paction_,pactiond) ;
+	if (monitor) monitor->checkAndTell(prob) ;
+#	endif
+	if (prob->status_) break ;
+      }
+      // Will trigger abort due to unimplemented postsolve  -- lh, 110605 --
+      if ((presolveActions_&0x20) != 0) {
+	possibleBreak ;
+	paction_ = gubrow_action::presolve(prob,paction_) ;
+      }
+/*
+  Count the number of empty rows and see if we've made progress in this pass.
+*/
+      bool stopLoop = false ;
+      {
+	const int *const hinrow = prob->hinrow_ ;
+	int numberDropped = 0 ;
+	for (int i = 0 ; i < nrows_ ; i++)
+	  if (!hinrow[i]) numberDropped++ ;
+#	if PRESOLVE_DEBUG > 0
+	std::cout
+	  << "  " << (numberDropped-lastDropped)
+	  << " rows dropped in pass " << iLoop << "." << std::endl ;
+#	endif
+	if (numberDropped == lastDropped)
+	  stopLoop = true ;
+	else
+	  lastDropped = numberDropped ;
+      }
+/*
+  Check for singleton variables that can act like a logical, allowing a
+  row to be transformed from an equality to an inequality.
+
+  The third parameter allows for costs for the existing logicals. This
+  is apparently used by clp; consult the clp presolve before implementing
+  it here.  -- lh, 110605 --
+
+  Original comment: Do this here as not very loopy
+*/
+      if (slackSingleton) {
+	possibleBreak ;
+	paction_ = slack_singleton_action::presolve(prob,paction_,NULL) ;
+#	if PRESOLVE_DEBUG > 0
+	check_and_tell(prob,paction_,pactiond) ;
+	if (monitor) monitor->checkAndTell(prob) ;
+#	endif
+      }
+#     if PRESOLVE_DEBUG > 0
+      presolve_check_sol(prob,1) ;
+#     endif
+
+      if (paction_ == paction0 || stopLoop) break ;
+	  
+    } // End of major pass loop
+  }
+/*
+  Final cleanup: drop zero coefficients from the matrix, then drop empty rows
+  and columns.
+*/
+  if (!prob->status_) {
+    paction_ = drop_zero_coefficients(prob,paction_) ;
+#   if PRESOLVE_DEBUG > 0
+    check_and_tell(prob,paction_,pactiond) ;
+    if (monitor) monitor->checkAndTell(prob) ;
+#   endif
+
+    paction_ = drop_empty_cols_action::presolve(prob,paction_) ;
+#   if PRESOLVE_DEBUG > 0
+    check_and_tell(prob,paction_,pactiond) ;
+#   endif
+
+    paction_ = drop_empty_rows_action::presolve(prob,paction_) ;
+#   if PRESOLVE_DEBUG > 0
+    check_and_tell(prob,paction_,pactiond) ;
+#   endif
+  }
+/*
+  Not feasible? Say something and clean up.
+*/
+  CoinMessageHandler *hdlr = prob->messageHandler() ;
+  CoinMessages msgs = CoinMessage(prob->messages().language());
+  if (prob->status_) {
+    if (prob->status_ == 1)
+      hdlr->message(COIN_PRESOLVE_INFEAS,msgs)
+	<< prob->feasibilityTolerance_ << CoinMessageEol ;
+    else if (prob->status_ == 2)
+      hdlr->message(COIN_PRESOLVE_UNBOUND,msgs) << CoinMessageEol ;
+    else
+      hdlr->message(COIN_PRESOLVE_INFEASUNBOUND,msgs) << CoinMessageEol ;
+    gutsOfDestroy() ;
+  }
+  return (paction_) ;
+}
+
+
+/*
+  We could have implemented this by having each postsolve routine directly
+  call the next one, but this makes it easier to add debugging checks.
+*/
+void OsiPresolve::postsolve (CoinPostsolveMatrix &prob)
+{
+  const CoinPresolveAction *paction = paction_;
+
+# if PRESOLVE_DEBUG > 0
+  std::cout << "Begin POSTSOLVING." << std::endl ;
+  if (prob.colstat_)
+  { presolve_check_nbasic(&prob) ;
+    presolve_check_sol(&prob,2,2,2) ; }
+  presolve_check_duals(&prob) ;
+# endif
+  
+  
+  while (paction) {
+#   if PRESOLVE_DEBUG > 0
+    std::cout << "POSTSOLVING " << paction->name() << std::endl ;
+#   endif
+
+    paction->postsolve(&prob);
+    
+#   if PRESOLVE_DEBUG > 0
+    if (prob.colstat_) {
+      presolve_check_nbasic(&prob) ;
+      presolve_check_sol(&prob,2,2,2) ;
+    }
+#   endif
+    paction = paction->next ;
+#   if PRESOLVE_DEBUG > 0
+    presolve_check_duals(&prob);
+#   endif
+  }    
+# if PRESOLVE_DEBUG > 0
+    std::cout << "End POSTSOLVING" << std::endl ;
+# endif
+  
+# if PRESOLVE_DEBUG > 0
+  for (int j = 0 ; j < prob.ncols_ ; j++) {
+    if (!prob.cdone_[j]) {
+      printf("!cdone[%d]\n", j) ;
+      abort() ;
+    }
+  }
+  for (int i = 0 ; i < prob.nrows_ ; i++) {
+    if (!prob.rdone_[i]) {
+      printf("!rdone[%d]\n", i) ;
+      abort() ;
+    }
+  }
+  for (int j = 0 ; j < prob.ncols_ ; j++) {
+    if (prob.sol_[j] < -1e10 || prob.sol_[j] > 1e10)
+      printf("!!!%d %g\n",j,prob.sol_[j]) ;
+  }
+# endif
+
+  /*
+    Put back duals. Flip sign for maximisation problems.
+  */
+  double maxmin = originalModel_->getObjSense() ;
+  if (maxmin < 0.0) {
+    double *pi = prob.rowduals_ ;
+    for (int i = 0 ; i < nrows_ ; i++) pi[i] = -pi[i] ;
+  }
+  originalModel_->setRowPrice(prob.rowduals_) ;
+}
+
+
+static inline double getTolerance(const OsiSolverInterface  *si, OsiDblParam key)
+{
+  double tol;
+  if (!si->getDblParam(key,tol)) {
+    CoinPresolveAction::throwCoinError("getDblParam failed",
+		    "CoinPrePostsolveMatrix::CoinPrePostsolveMatrix") ;
+  }
+  return (tol) ;
+}
+
+
+// Assumptions:
+// 1. nrows>=m.getNumRows()
+// 2. ncols>=m.getNumCols()
+//
+// In presolve, these values are equal.
+// In postsolve, they may be inequal, since the reduced problem
+// may be smaller, but we need room for the large problem.
+// ncols may be larger than si.getNumCols() in postsolve,
+// this at that point si will be the reduced problem,
+// but we need to reserve enough space for the original problem.
+
+CoinPrePostsolveMatrix::CoinPrePostsolveMatrix(const OsiSolverInterface * si,
+					     int ncols_in,
+					     int nrows_in,
+					     CoinBigIndex nelems_in) :
+  ncols_(si->getNumCols()),
+  nelems_(si->getNumElements()),
+  ncols0_(ncols_in),
+  nrows0_(nrows_in),
+  bulkRatio_(2.0),
+
+  mcstrt_(new CoinBigIndex[ncols_in+1]),
+  hincol_(new int[ncols_in+1]),
+
+  cost_(new double[ncols_in]),
+  clo_(new double[ncols_in]),
+  cup_(new double[ncols_in]),
+  rlo_(new double[nrows_in]),
+  rup_(new double[nrows_in]),
+  originalColumn_(new int[ncols_in]),
+  originalRow_(new int[nrows_in]),
+
+  ztolzb_(getTolerance(si, OsiPrimalTolerance)),
+  ztoldj_(getTolerance(si, OsiDualTolerance)),
+
+  maxmin_(si->getObjSense()),
+
+  handler_(0),
+  defaultHandler_(false),
+  messages_()
+
+{
+  bulk0_ = static_cast<CoinBigIndex>(bulkRatio_*nelems_in) ;
+  hrow_ = new int [bulk0_] ;
+  colels_ = new double[bulk0_] ;
+
+  si->getDblParam(OsiObjOffset,originalOffset_);
+  int ncols = si->getNumCols();
+  int nrows = si->getNumRows();
+
+  setMessageHandler(si->messageHandler()) ;
+
+  CoinDisjointCopyN(si->getColLower(), ncols, clo_);
+  CoinDisjointCopyN(si->getColUpper(), ncols, cup_);
+  CoinDisjointCopyN(si->getObjCoefficients(), ncols, cost_);
+  CoinDisjointCopyN(si->getRowLower(), nrows,  rlo_);
+  CoinDisjointCopyN(si->getRowUpper(), nrows,  rup_);
+  int i;
+  // initialize and clean up bounds
+  double infinity = si->getInfinity();
+  if (infinity!=COIN_DBL_MAX) {
+    for (i=0;i<ncols;i++) {
+      if (clo_[i]==-infinity)
+	clo_[i]=-COIN_DBL_MAX;
+      if (cup_[i]==infinity)
+	cup_[i]=COIN_DBL_MAX;
+    }
+    for (i=0;i<nrows;i++) {
+      if (rlo_[i]==-infinity)
+	rlo_[i]=-COIN_DBL_MAX;
+      if (rup_[i]==infinity)
+	rup_[i]=COIN_DBL_MAX;
+    }
+  }
+  for (i=0;i<ncols_in;i++) 
+    originalColumn_[i]=i;
+  for (i=0;i<nrows_in;i++) 
+    originalRow_[i]=i;
+  sol_=NULL;
+  rowduals_=NULL;
+  acts_=NULL;
+
+  rcosts_=NULL;
+  colstat_=NULL;
+  rowstat_=NULL;
+}
+
+// I am not familiar enough with CoinPackedMatrix to be confident
+// that I will implement a row-ordered version of toColumnOrderedGapFree
+// properly.
+static bool isGapFree(const CoinPackedMatrix& matrix)
+{
+  const CoinBigIndex * start = matrix.getVectorStarts();
+  const int * length = matrix.getVectorLengths();
+  int i;
+  for (i = matrix.getSizeVectorLengths() - 1; i >= 0; --i) {
+    if (start[i+1] - start[i] != length[i])
+      break;
+  }
+  return (! (i >= 0));
+}
+
+CoinPresolveMatrix::CoinPresolveMatrix(int ncols0_in,
+				       double maxmin,
+				       // end prepost members
+				       OsiSolverInterface * si,
+				       // rowrep
+				       int nrows_in,
+				       CoinBigIndex nelems_in,
+				       bool doStatus,
+				       double nonLinearValue,
+                                       const char * prohibited,
+				       const char * rowProhibited)
+  : CoinPrePostsolveMatrix(si,ncols0_in,nrows_in,nelems_in),
+    clink_(new presolvehlink[ncols0_in+1]),
+    rlink_(new presolvehlink[nrows_in+1]),
+    dobias_(0.0),
+
+    // temporary init
+    mrstrt_(new CoinBigIndex[nrows_in+1]),
+    hinrow_(new int[nrows_in+1]),
+    integerType_(new unsigned char[ncols0_in]),
+    tuning_(false),
+    startTime_(0.0),
+    feasibilityTolerance_(0.0),
+    status_(-1),
+    maxSubstLevel_(3),
+    colsToDo_(new int [ncols0_in]),
+    numberColsToDo_(0),
+    nextColsToDo_(new int[ncols0_in]),
+    numberNextColsToDo_(0),
+    rowsToDo_(new int [nrows_in]),
+    numberRowsToDo_(0),
+    nextRowsToDo_(new int[nrows_in]),
+    numberNextRowsToDo_(0),
+    presolveOptions_(0)
+{
+
+  rowels_ = new double [bulk0_] ;
+  hcol_ = new int [bulk0_] ;
+
+  nrows_ = si->getNumRows() ;
+  const CoinBigIndex bufsize = static_cast<CoinBigIndex>(bulkRatio_*nelems_in) ;
+
+  // Set up change bits
+  rowChanged_ = new unsigned char[nrows_];
+  memset(rowChanged_,0,nrows_);
+  colChanged_ = new unsigned char[ncols_];
+  memset(colChanged_,0,ncols_);
+  const CoinPackedMatrix * m1 = si->getMatrixByCol();
+
+  // The coefficient matrix is a big hunk of stuff.
+  // Do the copy here to try to avoid running out of memory.
+
+  const CoinBigIndex * start = m1->getVectorStarts();
+  const int * length = m1->getVectorLengths();
+  const int * row = m1->getIndices();
+  const double * element = m1->getElements();
+  int icol,nel=0;
+  mcstrt_[0]=0;
+  for (icol=0;icol<ncols_;icol++) {
+    int j;
+    for (j=start[icol];j<start[icol]+length[icol];j++) {
+      if (fabs(element[j])>ZTOLDP) {
+        hrow_[nel]=row[j];
+	colels_[nel++]=element[j];
+      }
+    }
+    hincol_[icol]=nel-mcstrt_[icol];
+    mcstrt_[icol+1]=nel;
+  }
+
+  // same thing for row rep
+  CoinPackedMatrix * m = new CoinPackedMatrix();
+  m->reverseOrderedCopyOf(*si->getMatrixByCol());
+  // do by hand because of zeros m->removeGaps();
+  CoinDisjointCopyN(m->getVectorStarts(),  nrows_,  mrstrt_);
+  mrstrt_[nrows_] = nelems_;
+  CoinDisjointCopyN(m->getVectorLengths(), nrows_,  hinrow_);
+  CoinDisjointCopyN(m->getIndices(),       nelems_, hcol_);
+  CoinDisjointCopyN(m->getElements(),      nelems_, rowels_);
+  start = m->getVectorStarts();
+  length = m->getVectorLengths();
+  const int * column = m->getIndices();
+  element = m->getElements();
+  // out zeros
+  int irow;
+  nel=0;
+  mrstrt_[0]=0;
+  for (irow=0;irow<nrows_;irow++) {
+    int j;
+    for (j=start[irow];j<start[irow]+length[irow];j++) {
+      if (fabs(element[j])>ZTOLDP) {
+        hcol_[nel]=column[j];
+        rowels_[nel++]=element[j];
+      }
+    }
+    hinrow_[irow]=nel-mrstrt_[irow];
+    mrstrt_[irow+1]=nel;
+  }
+  nelems_=nel;
+
+  delete m;
+  {
+    int i;
+    for (i=0;i<ncols_;i++) {
+      if (si->isInteger(i))  
+	integerType_[i] = 1;
+      else
+	integerType_[i] = 0;
+    }
+  }
+
+  // Set up prohibited bits if needed
+  if (nonLinearValue) {
+    anyProhibited_ = true;
+    for (icol=0;icol<ncols_;icol++) {
+      int j;
+      bool nonLinearColumn = false;
+      if (cost_[icol]==nonLinearValue)
+	nonLinearColumn=true;
+      for (j=mcstrt_[icol];j<mcstrt_[icol+1];j++) {
+	if (colels_[j]==nonLinearValue) {
+	  nonLinearColumn=true;
+	  setRowProhibited(hrow_[j]);
+	}
+      }
+      if (nonLinearColumn)
+	setColProhibited(icol);
+    }
+  } else if (prohibited) {
+    anyProhibited_ = true;
+    for (icol=0;icol<ncols_;icol++) {
+      if (prohibited[icol])
+	setColProhibited(icol);
+    }
+  } else {
+    anyProhibited_ = false;
+  }
+  // Any rows special?
+  if (rowProhibited) {
+    anyProhibited_ = true;
+    for (int irow=0;irow<nrows_;irow++) {
+      if (rowProhibited[irow])
+	setRowProhibited(irow);
+    }
+  }
+  // Go to minimization
+  if (maxmin<0.0) {
+    for (int i=0;i<ncols_;i++)
+      cost_[i]=-cost_[i];
+    maxmin_=1.0;
+  }
+  if (doStatus) {
+    // allow for status and solution
+    sol_ = new double[ncols_];
+    const double *presol ;
+    presol = si->getColSolution() ;
+    memcpy(sol_,presol,ncols_*sizeof(double));;
+    acts_ = new double [nrows_];
+    memcpy(acts_,si->getRowActivity(),nrows_*sizeof(double));
+    CoinWarmStartBasis * basis  = 
+    dynamic_cast<CoinWarmStartBasis*>(si->getWarmStart());
+    colstat_ = new unsigned char [nrows_+ncols_];
+    rowstat_ = colstat_+ncols_;
+    // If basis is NULL then put in all slack basis
+    if (basis&&basis->getNumStructural()==ncols_) {
+      int i;
+      for (i=0;i<ncols_;i++) {
+	colstat_[i] = basis->getStructStatus(i);
+      }
+      for (i=0;i<nrows_;i++) {
+	rowstat_[i] = basis->getArtifStatus(i);
+      }
+    } else {
+      int i;
+      // no basis
+      for (i=0;i<ncols_;i++) {
+	colstat_[i] = 3;
+      }
+      for (i=0;i<nrows_;i++) {
+	rowstat_[i] = 1;
+      }
+    }
+    delete basis;
+  } 
+
+# if 0
+  for (i=0; i<nrows; ++i)
+    printf("NR: %6d\n", hinrow[i]);
+  for (int i=0; i<ncols; ++i)
+    printf("NC: %6d\n", hincol[i]);
+# endif
+
+/*
+  For building against CoinUtils 2.6, this #if 1 need to be changed into an
+  #if 0
+*/
+# if 0
+  presolve_make_memlists(mcstrt_, hincol_, clink_, ncols_);
+  presolve_make_memlists(mrstrt_, hinrow_, rlink_, nrows_);
+# else
+  presolve_make_memlists(/*mcstrt_,*/ hincol_, clink_, ncols_);
+  presolve_make_memlists(/*mrstrt_,*/ hinrow_, rlink_, nrows_);
+# endif
+
+  // this allows last col/row to expand up to bufsize-1 (22);
+  // this must come after the calls to presolve_prefix
+  mcstrt_[ncols_] = bufsize-1;
+  mrstrt_[nrows_] = bufsize-1;
+  // Allocate useful arrays
+  initializeStuff();
+
+# if PRESOLVE_CONSISTENCY > 0
+  presolve_consistent(this) ;
+# endif
+}
+
+// avoid compiler warnings about unused variables
+#if PRESOLVE_SUMMARY > 0
+void CoinPresolveMatrix::update_model(OsiSolverInterface * si,
+				      int nrows0, int ncols0,
+				      CoinBigIndex nelems0)
+#else
+void CoinPresolveMatrix::update_model(OsiSolverInterface * si,
+				      int /*nrows0*/, int /*ncols0*/,
+				      CoinBigIndex /*nelems0*/)
+#endif
+{
+  int nels=0;
+  int i;
+  if (si->getObjSense() < 0.0) {
+    for (int i=0;i<ncols_;i++)
+      cost_[i]=-cost_[i];
+    dobias_=-dobias_;
+    maxmin_ = -1.0;
+  }
+  for ( i=0; i<ncols_; i++) 
+    nels += hincol_[i];
+  CoinPackedMatrix m(true,nrows_,ncols_,nels, colels_, hrow_,mcstrt_,hincol_);
+  si->loadProblem(m, clo_, cup_, cost_, rlo_, rup_);
+
+  for ( i=0; i<ncols_; i++) {
+    if (integerType_[i])
+      si->setInteger(i);
+    else
+      si->setContinuous(i);
+  }
+  si->setDblParam(OsiObjOffset,originalOffset_-dobias_);
+
+# if PRESOLVE_SUMMARY > 0
+  std::cout
+    << "New ncol/nrow/nels: "
+    << ncols_ << "(-" << ncols0-ncols_ << ") "
+    << nrows_ << "(-" << nrows0-nrows_ << ") "
+    << si->getNumElements() << "(-" << nelems0-si->getNumElements() << ") "
+    << std::endl ;
+# endif
+}
+
+
+
+
+
+
+
+
+
+
+
+////////////////  POSTSOLVE
+
+CoinPostsolveMatrix::CoinPostsolveMatrix(OsiSolverInterface*  si,
+				       int ncols0_in,
+				       int nrows0_in,
+				       CoinBigIndex nelems0,
+				   
+				       double maxmin,
+				       // end prepost members
+
+				       double *sol_in,
+				       double *acts_in,
+
+				       unsigned char *colstat_in,
+				       unsigned char *rowstat_in) :
+
+  CoinPrePostsolveMatrix(si, ncols0_in, nrows0_in, nelems0),
+/*
+  Used only to mark processed columns and rows so that debugging routines know
+  what to check.
+*/
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  cdone_(new char[ncols0_in]),
+  rdone_(new char[nrows0_in])
+# else
+  cdone_(0),
+  rdone_(0)
+# endif
+
+{
+/*
+  The CoinPrePostsolveMatrix constructor will set bulk0_ to bulkRatio_*nelems0.
+  By default, bulkRatio_ is 2. This is certainly larger than absolutely
+  necessary, but good for efficiency (minimises the need to compress the bulk
+  store). The main storage arrays for the threaded column-major representation
+  (hrow_, colels_, link_) should be allocated to this size.
+*/
+  free_list_ = 0 ;
+  maxlink_ = bulk0_ ;
+  link_ = new int[maxlink_] ;
+
+  nrows_ = si->getNumRows() ;
+  ncols_ = si->getNumCols() ;
+
+  sol_=sol_in;
+  rowduals_=NULL;
+  acts_=acts_in;
+
+  rcosts_=NULL;
+  colstat_=colstat_in;
+  rowstat_=rowstat_in;
+
+  // this is the *reduced* model, which is probably smaller
+  int ncols1 = ncols_ ;
+  int nrows1 = nrows_ ;
+
+  const CoinPackedMatrix * m = si->getMatrixByCol();
+#if 0
+  if (! isGapFree(*m)) {
+    CoinPresolveAction::throwCoinError("Matrix not gap free",
+				      "CoinPostsolveMatrix");
+  }
+#endif
+  const CoinBigIndex nelemsr = m->getNumElements();
+
+  if (isGapFree(*m)) {
+    CoinDisjointCopyN(m->getVectorStarts(), ncols1, mcstrt_);
+    CoinZeroN(mcstrt_+ncols1,ncols0_-ncols1);
+    mcstrt_[ncols_] = nelems0;	// points to end of bulk store
+    CoinDisjointCopyN(m->getVectorLengths(),ncols1,  hincol_);
+    CoinDisjointCopyN(m->getIndices(),      nelemsr, hrow_);
+    CoinDisjointCopyN(m->getElements(),     nelemsr, colels_);
+  }
+  else
+  {
+    CoinPackedMatrix* mm = new CoinPackedMatrix(*m);
+    if( mm->hasGaps())
+      mm->removeGaps();
+    assert(nelemsr == mm->getNumElements());
+    CoinDisjointCopyN(mm->getVectorStarts(), ncols1, mcstrt_);
+    CoinZeroN(mcstrt_+ncols1,ncols0_-ncols1);
+    mcstrt_[ncols_] = nelems0;  // points to end of bulk store
+    CoinDisjointCopyN(mm->getVectorLengths(),ncols1,  hincol_);
+    CoinDisjointCopyN(mm->getIndices(),      nelemsr, hrow_);
+    CoinDisjointCopyN(mm->getElements(),     nelemsr, colels_);
+  }
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+  memset(cdone_, -1, ncols0_);
+  memset(rdone_, -1, nrows0_);
+# endif
+
+  rowduals_ = new double[nrows0_];
+  CoinDisjointCopyN(si->getRowPrice(), nrows1, rowduals_);
+  rcosts_ = new double[ncols0_];
+  CoinDisjointCopyN(si->getReducedCost(), ncols1, rcosts_);
+
+#if PRESOLVE_DEBUG > 0
+  // check accuracy of reduced costs (rcosts_ is recalculated reduced costs)
+  si->getMatrixByCol()->transposeTimes(rowduals_,rcosts_) ;
+  const double *obj = si->getObjCoefficients() ;
+  const double *dj = si->getReducedCost() ;
+  {
+    int i;
+    for (i=0;i<ncols1;i++) {
+      double newDj = obj[i]-rcosts_[i];
+      rcosts_[i]=newDj;
+      assert (fabs(newDj-dj[i])<1.0e-1);
+    }
+  }
+  // check reduced costs are 0 for basic variables
+  {
+    int i;
+    for (i=0;i<ncols1;i++)
+      if (columnIsBasic(i))
+	assert (fabs(rcosts_[i])<1.0e-5);
+    for (i=0;i<nrows1;i++)
+      if (rowIsBasic(i))
+	assert (fabs(rowduals_[i])<1.0e-5);
+  }
+#endif
+/*
+  CoinPresolve may, once, have handled both minimisation and maximisation,
+  but hard-wired minimisation has crept in.
+*/
+  if (maxmin<0.0) {
+    for (int i = 0 ; i < nrows1 ; i++)
+      rowduals_[i] = -rowduals_[i] ;
+    for (int j = 0 ; j < ncols1 ; j++) {
+      rcosts_[j] = -rcosts_[j] ;
+    }
+  }
+
+/*
+  CoinPresolve requires both column solution and row activity for correct
+  operation.
+*/
+  CoinDisjointCopyN(si->getColSolution(), ncols1, sol_);
+  CoinDisjointCopyN(si->getRowActivity(), nrows1, acts_) ;
+  si->setDblParam(OsiObjOffset,originalOffset_);
+
+  for (int j=0; j<ncols1; j++) {
+    CoinBigIndex kcs = mcstrt_[j];
+    CoinBigIndex kce = kcs + hincol_[j];
+    for (CoinBigIndex k=kcs; k<kce; ++k) {
+      link_[k] = k+1;
+    }
+    if (kce>0)
+      link_[kce-1] = NO_LINK ;
+  }
+  if (maxlink_>0) {
+    int ml = maxlink_;
+    for (CoinBigIndex k=nelemsr; k<ml; ++k)
+      link_[k] = k+1;
+    link_[ml-1] = NO_LINK;
+  }
+  free_list_ = nelemsr;
+
+# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
+/*
+  These are used to track the action of postsolve transforms during debugging.
+*/
+  CoinFillN(cdone_,ncols1,PRESENT_IN_REDUCED) ;
+  CoinZeroN(cdone_+ncols1,ncols0_in-ncols1) ;
+  CoinFillN(rdone_,nrows1,PRESENT_IN_REDUCED) ;
+  CoinZeroN(rdone_+nrows1,nrows0_in-nrows1) ;
+# endif
+}
+
+
diff --git a/cbits/coin/OsiPresolve.hpp b/cbits/coin/OsiPresolve.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiPresolve.hpp
@@ -0,0 +1,252 @@
+// Copyright (C) 2003, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiPresolve_H
+#define OsiPresolve_H
+#include "OsiSolverInterface.hpp"
+
+class CoinPresolveAction;
+#include "CoinPresolveMatrix.hpp"
+
+
+/*! \class OsiPresolve
+    \brief OSI interface to COIN problem simplification capabilities
+
+  COIN provides a number of classes which implement problem simplification
+  algorithms (CoinPresolveAction, CoinPrePostsolveMatrix, and derived
+  classes). The model of operation is as follows:
+  <ul>
+    <li>
+      Create a copy of the original problem.
+    </li>
+    <li>
+      Subject the copy to a series of transformations (the <i>presolve</i>
+      methods) to produce a presolved model. Each transformation is also
+      expected to provide a method to reverse the transformation (the
+      <i>postsolve</i> method). The postsolve methods are collected in a
+      linked list; the postsolve method for the final presolve transformation
+      is at the head of the list.
+    </li>
+    <li>
+      Hand the presolved problem to the solver for optimization.
+    </li>
+    <li>
+      Apply the collected postsolve methods to the presolved problem
+      and solution, restating the solution in terms of the original problem.
+    </li>
+  </ul>
+
+  The COIN presolve algorithms are unaware of OSI. The OsiPresolve class takes
+  care of the interface. Given an OsiSolverInterface \c origModel, it will take
+  care of creating a clone properly loaded with the presolved problem and ready
+  for optimization. After optimization, it will apply postsolve
+  transformations and load the result back into \c origModel.
+  
+  Assuming a problem has been loaded into an
+  \c OsiSolverInterface \c origModel, a bare-bones application looks like this:
+  \code
+  OsiPresolve pinfo ;
+  OsiSolverInterface *presolvedModel ;
+  // Return an OsiSolverInterface loaded with the presolved problem.
+  presolvedModel = pinfo.presolvedModel(*origModel,1.0e-8,false,numberPasses) ;
+  presolvedModel->initialSolve() ;
+  // Restate the solution and load it back into origModel.
+  pinfo.postsolve(true) ;
+  delete presolvedModel ;
+  \endcode
+*/
+
+
+
+class OsiPresolve {
+public:
+  /// Default constructor (empty object)
+  OsiPresolve();
+
+  /// Virtual destructor
+  virtual ~OsiPresolve();
+
+  /*! \brief Create a new OsiSolverInterface loaded with the presolved problem.
+
+    This method implements the first two steps described in the class
+    documentation.  It clones \c origModel and applies presolve
+    transformations, storing the resulting list of postsolve
+    transformations.  It returns a pointer to a new OsiSolverInterface loaded
+    with the presolved problem, or NULL if the problem is infeasible or
+    unbounded.  If \c keepIntegers is true then bounds may be tightened in
+    the original. Bounds will be moved by up to \c feasibilityTolerance to
+    try and stay feasible. When \c doStatus is true, the current solution will
+    be transformed to match the presolved model.
+
+    This should be paired with postsolve(). It is up to the client to
+    destroy the returned OsiSolverInterface, <i>after</i> calling postsolve().
+    
+    This method is virtual. Override this method if you need to customize
+    the steps of creating a model to apply presolve transformations.
+
+    In some sense, a wrapper for presolve(CoinPresolveMatrix*).
+  */
+  virtual OsiSolverInterface *presolvedModel(OsiSolverInterface & origModel,
+					     double feasibilityTolerance=0.0,
+					     bool keepIntegers=true,
+					     int numberPasses=5,
+                                             const char * prohibited=NULL,
+					     bool doStatus=true,
+					     const char * rowProhibited=NULL);
+
+  /*! \brief Restate the solution to the presolved problem in terms of the
+	     original problem and load it into the original model.
+  
+    postsolve() restates the solution in terms of the original problem and
+    updates the original OsiSolverInterface supplied to presolvedModel().  If
+    the problem has not been solved to optimality, there are no guarantees.
+    If you are using an algorithm like simplex that has a concept of a basic
+    solution, then set updateStatus
+
+    The advantage of going back to the original problem is that it
+    will be exactly as it was, <i>i.e.</i>, 0.0 will not become 1.0e-19.
+
+    Note that if you modified the original problem after presolving, then you
+    must ``undo'' these modifications before calling postsolve().
+
+    In some sense, a wrapper for postsolve(CoinPostsolveMatrix&).
+  */
+  virtual void postsolve(bool updateStatus=true);
+
+  /*! \brief Return a pointer to the presolved model. */
+  OsiSolverInterface * model() const;
+
+  /// Return a pointer to the original model
+  OsiSolverInterface * originalModel() const;
+
+  /// Set the pointer to the original model
+  void setOriginalModel(OsiSolverInterface *model);
+
+  /// Return a pointer to the original columns
+  const int * originalColumns() const;
+
+  /// Return a pointer to the original rows
+  const int * originalRows() const;
+
+  /// Return number of rows in original model
+  inline int getNumRows() const
+  { return nrows_;}
+
+  /// Return number of columns in original model
+  inline int getNumCols() const
+  { return ncols_;}
+
+  /** "Magic" number. If this is non-zero then any elements with this value
+      may change and so presolve is very limited in what can be done
+      to the row and column.  This is for non-linear problems.
+  */
+  inline void setNonLinearValue(double value)
+  { nonLinearValue_ = value;}
+  inline double nonLinearValue() const
+    { return nonLinearValue_;}
+  /*! \brief Fine control over presolve actions
+  
+    Set/clear the following bits to allow or suppress actions:
+      - 0x01 allow duplicate column processing on integer columns
+	     and dual stuff on integers
+      - 0x02 switch off actions which can change +1 to something else
+      	     (doubleton, tripleton, implied free)
+      - 0x04 allow transfer of costs from singletons and between integer
+      	     variables (when advantageous)
+      - 0x08 do not allow x+y+z=1 transform
+      - 0x10 allow actions that don't easily unroll
+      - 0x20 allow dubious gub element reduction
+
+    GUB element reduction is only partially implemented in CoinPresolve (see
+    gubrow_action) and willl cause an abort at postsolve. It's not clear
+    what's meant by `dual stuff on integers'.
+    -- lh, 110605 --
+  */
+  inline void setPresolveActions(int action)
+  { presolveActions_  = (presolveActions_&0xffff0000)|(action&0xffff);}
+
+private:
+  /*! Original model (solver interface loaded with the original problem).
+
+      Must not be destroyed until after postsolve().
+  */
+  OsiSolverInterface * originalModel_;
+
+  /*! Presolved  model (solver interface loaded with the presolved problem)
+  
+    Must be destroyed by the client (using delete) after postsolve().
+  */
+  OsiSolverInterface * presolvedModel_;
+
+  /*! "Magic" number. If this is non-zero then any elements with this value
+      may change and so presolve is very limited in what can be done
+      to the row and column.  This is for non-linear problems.
+      One could also allow for cases where sign of coefficient is known.
+  */
+  double nonLinearValue_;
+
+  /// Original column numbers
+  int * originalColumn_;
+
+  /// Original row numbers
+  int * originalRow_;
+
+  /// The list of transformations applied.
+  const CoinPresolveAction *paction_;
+
+  /*! \brief Number of columns in original model.
+
+    The problem will expand back to its former size as postsolve
+    transformations are applied. It is efficient to allocate data structures
+    for the final size of the problem rather than expand them as needed.
+  */
+  int ncols_;
+
+  /*! \brief Number of rows in original model. */
+  int nrows_;
+
+  /*! \brief Number of nonzero matrix coefficients in the original model. */
+  CoinBigIndex nelems_;
+
+  /** Whether we want to skip dual part of presolve etc.
+      1 bit allows duplicate column processing on integer columns
+      and dual stuff on integers
+      4 transfers costs to integer variables
+  */
+  int presolveActions_;
+  /// Number of major passes
+  int numberPasses_;
+
+protected:
+  /*! \brief Apply presolve transformations to the problem.
+  
+    Handles the core activity of applying presolve transformations.
+    
+    If you want to apply the individual presolve routines differently, or
+    perhaps add your own to the mix, define a derived class and override
+    this method
+  */
+  virtual const CoinPresolveAction *presolve(CoinPresolveMatrix *prob);
+
+  /*! \brief Reverse presolve transformations to recover the solution
+	     to the original problem.
+
+    Handles the core activity of applying postsolve transformations.
+
+    Postsolving is pretty generic; just apply the transformations in reverse
+    order. You will probably only be interested in overriding this method if
+    you want to add code to test for consistency while debugging new presolve
+    techniques.
+  */
+  virtual void postsolve(CoinPostsolveMatrix &prob);
+
+  /*! \brief Destroys queued postsolve actions.
+  
+    <i>E.g.</i>, when presolve() determines the problem is infeasible, so that
+    it will not be necessary to actually solve the presolved problem and
+    convert the result back to the original problem.
+  */
+  void gutsOfDestroy();
+};
+#endif
diff --git a/cbits/coin/OsiRowCut.cpp b/cbits/coin/OsiRowCut.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiRowCut.cpp
@@ -0,0 +1,303 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cfloat>
+#include <cstdlib>
+#include <cstdio>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinFinite.hpp"
+#include "OsiRowCut.hpp"
+
+#ifndef OSI_INLINE_ROWCUT_METHODS
+
+//  //-------------------------------------------------------------------
+//  // Set/Get lower & upper bounds
+//  //-------------------------------------------------------------------
+double OsiRowCut::lb() const { return lb_; }
+
+void OsiRowCut::setLb(double lb) { lb_ = lb; }
+
+double OsiRowCut::ub() const { return ub_; }
+
+void OsiRowCut::setUb(double ub) { ub_ = ub; }
+
+//-------------------------------------------------------------------
+// Set row elements
+//------------------------------------------------------------------- 
+void OsiRowCut::setRow(int size, 
+		       const int* colIndices, const double* elements,
+		       bool testForDuplicateIndex)
+{
+   row_.setVector(size, colIndices, elements, testForDuplicateIndex);
+}
+
+void OsiRowCut::setRow( const CoinPackedVector & v )
+{
+   row_ = v;
+}
+
+//-------------------------------------------------------------------
+// Get the row
+//-------------------------------------------------------------------
+const CoinPackedVector & OsiRowCut::row() const 
+{ 
+   return row_; 
+}
+
+//-------------------------------------------------------------------
+// Get the row for changing
+//-------------------------------------------------------------------
+CoinPackedVector & OsiRowCut::mutableRow()
+{ 
+   return row_; 
+}
+
+//----------------------------------------------------------------
+// == operator 
+//-------------------------------------------------------------------
+bool
+OsiRowCut::operator==(const OsiRowCut& rhs) const
+{
+   if ( this->OsiCut::operator!=(rhs) ) return false;
+   if ( row() != rhs.row() )            return false;
+   if ( lb() != rhs.lb() )              return false;
+   if ( ub() != rhs.ub() )              return false;
+
+   return true;
+}
+
+bool
+OsiRowCut::operator!=(const OsiRowCut& rhs) const
+{
+   return !( (*this)==rhs );
+}
+
+
+//----------------------------------------------------------------
+// consistent & infeasible 
+//-------------------------------------------------------------------
+bool OsiRowCut::consistent() const
+{
+   const CoinPackedVector& r = row();
+   r.duplicateIndex("consistent", "OsiRowCut");
+   if ( r.getMinIndex() < 0 ) return false;
+   return true;
+}
+
+bool OsiRowCut::consistent(const OsiSolverInterface& im) const
+{  
+   const CoinPackedVector& r = row();
+   if ( r.getMaxIndex() >= im.getNumCols() ) return false;
+
+   return true;
+}
+
+bool OsiRowCut::infeasible(const OsiSolverInterface &) const
+{
+   if ( lb() > ub() ) return true;
+
+   return false;
+}
+
+#endif
+/* Returns infeasibility of the cut with respect to solution 
+    passed in i.e. is positive if cuts off that solution.  
+    solution is getNumCols() long..
+*/
+double 
+OsiRowCut::violated(const double * solution) const
+{
+   int i;
+   double sum = 0.0;
+   const int* column = row_.getIndices();
+   int number = row_.getNumElements();
+   const double* element = row_.getElements();
+   for ( i = 0;  i < number;  i++ ) {
+      int colIndx = column[i];
+      sum += solution[colIndx] * element[i];
+   }
+   if ( sum > ub_ )
+      return sum-ub_;
+   else if ( sum < lb_ )
+      return lb_-sum;
+   else
+      return 0.0;
+}
+
+//-------------------------------------------------------------------
+// Row sense, rhs, range
+//-------------------------------------------------------------------
+char OsiRowCut::sense() const
+{
+   if      ( lb_ == ub_ )                        return 'E';
+   else if ( lb_ == -COIN_DBL_MAX && ub_ == COIN_DBL_MAX ) return 'N';
+   else if ( lb_ == -COIN_DBL_MAX )                   return 'L';
+   else if ( ub_ == COIN_DBL_MAX )                    return 'G';
+   else                                          return 'R';
+}
+
+double OsiRowCut::rhs() const
+{
+   if      ( lb_ == ub_ )                                  return ub_;
+   else if ( lb_ == -COIN_DBL_MAX && ub_ == COIN_DBL_MAX ) return 0.0;
+   else if ( lb_ == -COIN_DBL_MAX )                        return ub_;
+   else if ( ub_ == COIN_DBL_MAX )                         return lb_;
+   else                                                     return ub_;
+}
+
+double OsiRowCut::range() const
+{
+   if      ( lb_ == ub_ )                                  return 0.0;
+   else if ( lb_ == -COIN_DBL_MAX && ub_ == COIN_DBL_MAX ) return 0.0;
+   else if ( lb_ == -COIN_DBL_MAX )                        return 0.0;
+   else if ( ub_ == COIN_DBL_MAX )                         return 0.0;
+   else                                                    return ub_ - lb_;
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiRowCut::OsiRowCut () : OsiCut(),
+			  row_(),
+			  lb_(-COIN_DBL_MAX),
+			  ub_( COIN_DBL_MAX)
+{
+   //#ifdef NDEBUG
+   //row_.setTestForDuplicateIndex(false);
+   //#endif
+}
+
+//-------------------------------------------------------------------
+// Ownership constructor 
+//-------------------------------------------------------------------
+
+OsiRowCut::OsiRowCut(double cutlb, double cutub,
+ 		     int capacity, int size,
+ 		     int *&colIndices, double *&elements):
+   OsiCut(),
+   row_(capacity, size, colIndices, elements),
+   lb_(cutlb),
+   ub_(cutub)
+{}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiRowCut::OsiRowCut (const OsiRowCut & source) :
+   OsiCut(source),
+   row_(source.row_),
+   lb_(source.lb_),
+   ub_(source.ub_)
+{
+   // Nothing to do here
+}
+
+
+//----------------------------------------------------------------
+// Clone
+//----------------------------------------------------------------
+OsiRowCut * OsiRowCut::clone() const
+{ return (new OsiRowCut(*this)); }
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiRowCut::~OsiRowCut ()
+{
+   // Nothing to do here
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiRowCut &
+OsiRowCut::operator=(const OsiRowCut& rhs)
+{
+   if ( this != &rhs ) {
+      OsiCut::operator=(rhs);
+      row_ = rhs.row_;
+      lb_ = rhs.lb_;
+      ub_ = rhs.ub_;
+   }
+   return *this;
+}
+
+//----------------------------------------------------------------
+// Print
+//-------------------------------------------------------------------
+
+void
+OsiRowCut::print() const
+{
+   int i;
+   std::cout << "Row cut has " << row_.getNumElements()
+	     << " elements";
+   if ( lb_ < -1.0e20 && ub_<1.0e20 ) 
+      std::cout << " with upper rhs of " << ub_;
+   else if ( lb_ > -1.0e20 && ub_ > 1.0e20 ) 
+      std::cout << " with lower rhs of " << lb_;
+   else
+      std::cout << " !!! with lower, upper rhs of " << lb_ << " and " << ub_;
+   std::cout << std::endl;
+   for ( i = 0;  i < row_.getNumElements();  i++ ) {
+      int colIndx = row_.getIndices()[i];
+      double element = row_.getElements()[i];
+      if ( i > 0 && element > 0 )
+	 std::cout << " +";
+      std::cout << element << " * x" << colIndx << " ";
+   }
+   std::cout << std::endl;
+}
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiRowCut2::OsiRowCut2(int row) :
+   OsiRowCut(),
+   whichRow_(row)
+{
+  // nothing to do here
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiRowCut2::OsiRowCut2(const OsiRowCut2 & source) :
+   OsiRowCut(source),
+   whichRow_(source.whichRow_)
+{  
+  // Nothing to do here
+}
+
+
+//----------------------------------------------------------------
+// Clone
+//----------------------------------------------------------------
+OsiRowCut * OsiRowCut2::clone() const
+{ return (new OsiRowCut2(*this)); }
+
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiRowCut2::~OsiRowCut2 ()
+{
+   // Nothing to do here
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiRowCut2 &
+OsiRowCut2::operator=(const OsiRowCut2& rhs)
+{
+   if ( this != &rhs ) {
+      OsiRowCut::operator = (rhs);
+      whichRow_ = rhs.whichRow_;
+   }
+   return *this;
+}
diff --git a/cbits/coin/OsiRowCut.hpp b/cbits/coin/OsiRowCut.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiRowCut.hpp
@@ -0,0 +1,331 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiRowCut_H
+#define OsiRowCut_H
+
+#include "CoinPackedVector.hpp"
+
+#include "OsiCollections.hpp"
+#include "OsiCut.hpp"
+
+//#define OSI_INLINE_ROWCUT_METHODS
+#ifdef OSI_INLINE_ROWCUT_METHODS
+#define OsiRowCut_inline inline
+#else
+#define OsiRowCut_inline
+#endif
+
+/** Row Cut Class
+
+A row cut has:
+  <ul>
+  <li>a lower bound<br>
+  <li>an upper bound<br>
+  <li>a vector of row elements
+  </ul>
+*/
+class OsiRowCut : public OsiCut {
+   friend void OsiRowCutUnitTest(const OsiSolverInterface * baseSiP,    
+				 const std::string & mpsDir);
+
+public:
+  
+  /**@name Row bounds */
+  //@{
+    /// Get lower bound
+    OsiRowCut_inline double lb() const;
+    /// Set lower bound
+    OsiRowCut_inline void setLb(double lb);
+    /// Get upper bound
+    OsiRowCut_inline double ub() const;
+    /// Set upper bound
+    OsiRowCut_inline void setUb(double ub);
+  //@}
+
+  /**@name Row rhs, sense, range */
+  //@{
+    /// Get sense ('E', 'G', 'L', 'N', 'R')
+    char sense() const;
+    /// Get right-hand side
+    double rhs() const;
+    /// Get range (ub - lb for 'R' rows, 0 otherwise)
+    double range() const;
+  //@}
+
+  //-------------------------------------------------------------------
+  /**@name Row elements  */
+  //@{
+    /// Set row elements
+    OsiRowCut_inline void setRow( 
+      int size, 
+      const int * colIndices, 
+      const double * elements,
+      bool testForDuplicateIndex = COIN_DEFAULT_VALUE_FOR_DUPLICATE);
+    /// Set row elements from a packed vector
+    OsiRowCut_inline void setRow( const CoinPackedVector & v );
+    /// Get row elements
+    OsiRowCut_inline const CoinPackedVector & row() const;
+    /// Get row elements for changing
+    OsiRowCut_inline CoinPackedVector & mutableRow() ;
+  //@}
+
+  /**@name Comparison operators  */
+  //@{
+#if __GNUC__ != 2 
+    using OsiCut::operator== ;
+#endif
+    /** equal - true if lower bound, upper bound, row elements,
+        and OsiCut are equal.
+    */
+    OsiRowCut_inline bool operator==(const OsiRowCut& rhs) const; 
+
+#if __GNUC__ != 2 
+    using OsiCut::operator!= ;
+#endif
+    /// not equal
+    OsiRowCut_inline bool operator!=(const OsiRowCut& rhs) const; 
+  //@}
+  
+    
+  //----------------------------------------------------------------
+  /**@name Sanity checks on cut */
+  //@{
+    /** Returns true if the cut is consistent.
+        This checks to ensure that:
+        <ul>
+        <li>The row element vector does not have duplicate indices
+        <li>The row element vector indices are >= 0
+        </ul>
+    */
+    OsiRowCut_inline bool consistent() const; 
+
+    /** Returns true if cut is consistent with respect to the solver
+        interface's model.
+        This checks to ensure that
+        <ul>
+        <li>The row element vector indices are < the number of columns
+            in the model
+        </ul>
+    */
+    OsiRowCut_inline bool consistent(const OsiSolverInterface& im) const;
+
+    /** Returns true if the row cut itself is infeasible and cannot be satisfied.       
+        This checks whether
+        <ul>
+        <li>the lower bound is strictly greater than the
+            upper bound.
+        </ul>
+    */
+    OsiRowCut_inline bool infeasible(const OsiSolverInterface &im) const;
+    /** Returns infeasibility of the cut with respect to solution 
+	passed in i.e. is positive if cuts off that solution.  
+	solution is getNumCols() long..
+    */
+    virtual double violated(const double * solution) const;
+  //@}
+
+  /**@name Arithmetic operators. Apply CoinPackedVector methods to the vector */
+  //@{
+    /// add <code>value</code> to every vector entry
+    void operator+=(double value)
+	{ row_ += value; }
+
+    /// subtract <code>value</code> from every vector entry
+    void operator-=(double value)
+	{ row_ -= value; }
+
+    /// multiply every vector entry by <code>value</code>
+    void operator*=(double value)
+	{ row_ *= value; }
+
+    /// divide every vector entry by <code>value</code>
+    void operator/=(double value)
+	{ row_ /= value; }
+  //@}
+
+  /// Allow access row sorting function
+  void sortIncrIndex()
+	{row_.sortIncrIndex();}
+
+  /**@name Constructors and destructors */
+  //@{
+    /// Assignment operator
+    OsiRowCut & operator=( const OsiRowCut& rhs);
+  
+    /// Copy constructor 
+    OsiRowCut ( const OsiRowCut &);  
+
+    /// Clone
+    virtual OsiRowCut * clone() const;
+  
+    /// Default Constructor 
+    OsiRowCut ();
+
+    /** \brief Ownership Constructor
+
+      This constructor assumes ownership of the vectors passed as parameters
+      for indices and elements. \p colIndices and \p elements will be NULL
+      on return.
+    */
+    OsiRowCut(double cutlb, double cutub,
+ 		     int capacity, int size,
+ 		     int *&colIndices, double *&elements);
+  
+    /// Destructor 
+    virtual ~OsiRowCut ();
+  //@}
+
+  /**@name Debug stuff */
+  //@{
+    /// Print cuts in collection
+  virtual void print() const ;
+  //@}
+   
+private:
+  
+ 
+  /**@name Private member data */
+  //@{
+    /// Row elements
+    CoinPackedVector row_;
+    /// Row lower bound
+    double lb_;
+    /// Row upper bound
+    double ub_;
+  //@}
+};
+
+#ifdef OSI_INLINE_ROWCUT_METHODS
+
+//-------------------------------------------------------------------
+// Set/Get lower & upper bounds
+//-------------------------------------------------------------------
+double OsiRowCut::lb() const { return lb_; }
+void OsiRowCut::setLb(double lb) { lb_ = lb; }
+double OsiRowCut::ub() const { return ub_; }
+void OsiRowCut::setUb(double ub) { ub_ = ub; }
+
+//-------------------------------------------------------------------
+// Set row elements
+//------------------------------------------------------------------- 
+void OsiRowCut::setRow(int size, 
+		       const int * colIndices, const double * elements)
+{
+  row_.setVector(size,colIndices,elements);
+}
+void OsiRowCut::setRow( const CoinPackedVector & v )
+{
+  row_ = v;
+}
+
+//-------------------------------------------------------------------
+// Get the row
+//-------------------------------------------------------------------
+const CoinPackedVector & OsiRowCut::row() const 
+{ 
+  return row_; 
+}
+
+//-------------------------------------------------------------------
+// Get the row so we can change
+//-------------------------------------------------------------------
+CoinPackedVector & OsiRowCut::mutableRow() 
+{ 
+  return row_; 
+}
+
+//----------------------------------------------------------------
+// == operator 
+//-------------------------------------------------------------------
+bool
+OsiRowCut::operator==(const OsiRowCut& rhs) const
+{
+  if ( this->OsiCut::operator!=(rhs) ) return false;
+  if ( row() != rhs.row() ) return false;
+  if ( lb() != rhs.lb() ) return false;
+  if ( ub() != rhs.ub() ) return false;
+  return true;
+}
+bool
+OsiRowCut::operator!=(const OsiRowCut& rhs) const
+{
+  return !( (*this)==rhs );
+}
+
+
+//----------------------------------------------------------------
+// consistent & infeasible 
+//-------------------------------------------------------------------
+bool OsiRowCut::consistent() const
+{
+  const CoinPackedVector & r=row();
+  r.duplicateIndex("consistent", "OsiRowCut");
+  if ( r.getMinIndex() < 0 ) return false;
+  return true;
+}
+bool OsiRowCut::consistent(const OsiSolverInterface& im) const
+{  
+  const CoinPackedVector & r=row();
+  if ( r.getMaxIndex() >= im.getNumCols() ) return false;
+
+  return true;
+}
+bool OsiRowCut::infeasible(const OsiSolverInterface &im) const
+{
+  if ( lb() > ub() ) return true;
+
+  return false;
+}
+
+#endif
+
+/** Row Cut Class which refers back to row which created it.
+    It may be useful to strengthen a row rather than add a cut.  To do this
+    we need to know which row is strengthened.  This trivial extension
+    to OsiRowCut does that.
+
+*/
+class OsiRowCut2 : public OsiRowCut {
+
+public:
+  
+  /**@name Which row */
+  //@{
+  /// Get row
+  inline int whichRow() const
+  { return whichRow_;}
+  /// Set row
+  inline void setWhichRow(int row)
+  { whichRow_=row;}
+  //@}
+  
+  /**@name Constructors and destructors */
+  //@{
+  /// Assignment operator
+  OsiRowCut2 & operator=( const OsiRowCut2& rhs);
+  
+  /// Copy constructor 
+  OsiRowCut2 ( const OsiRowCut2 &);  
+  
+  /// Clone
+  virtual OsiRowCut * clone() const;
+  
+  /// Default Constructor 
+  OsiRowCut2 (int row=-1);
+  
+  /// Destructor 
+  virtual ~OsiRowCut2 ();
+  //@}
+
+private:
+  
+ 
+  /**@name Private member data */
+  //@{
+  /// Which row
+  int whichRow_;
+  //@}
+};
+#endif
diff --git a/cbits/coin/OsiRowCutDebugger.cpp b/cbits/coin/OsiRowCutDebugger.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiRowCutDebugger.cpp
@@ -0,0 +1,1635 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <cstdlib>
+#include <cstdio>
+#include <cassert>
+#include <cmath>
+#include <cfloat>
+#include <string>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinPackedVector.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinWarmStartBasis.hpp"
+
+#include "OsiRowCutDebugger.hpp"
+
+/*
+  Check if any cuts cut off the known solution.
+   
+   If so then print offending cuts and return non-zero code
+*/
+
+
+int OsiRowCutDebugger::validateCuts (const OsiCuts & cs, 
+				     int first, int last) const
+{
+  int nbad=0; 
+  int i;
+  const double epsilon=1.0e-8;
+  const int nRowCuts = CoinMin(cs.sizeRowCuts(),last);
+  
+  for (i=first; i<nRowCuts; i++){
+    
+    OsiRowCut rcut = cs.rowCut(i);
+    CoinPackedVector rpv = rcut.row();
+    const int n = rpv.getNumElements();
+    const int * indices = rpv.getIndices();
+    const double * elements = rpv.getElements();
+    int k;
+    double lb=rcut.lb();
+    double ub=rcut.ub();
+    
+    double sum=0.0;
+    
+    for (k=0; k<n; k++){
+      int column=indices[k];
+      sum += knownSolution_[column]*elements[k];
+    }
+    // is it violated
+    if (sum >ub + epsilon ||sum < lb - epsilon) {
+      double violation=CoinMax(sum-ub,lb-sum);
+      std::cout<<"Cut "<<i<<" with "<<n
+	  <<" coefficients, cuts off known solution by "<<violation
+          <<", lo="<<lb<<", ub="<<ub<<std::endl;
+      for (k=0; k<n; k++){
+	int column=indices[k];
+        std::cout<<"( "<<column<<" , "<<elements[k]<<" ) ";
+	if ((k%4)==3)
+	  std::cout <<std::endl;
+      }
+      std::cout <<std::endl;
+      std::cout <<"Non zero solution values are"<<std::endl;
+      int j=0;
+      for (k=0; k<n; k++){
+	int column=indices[k];
+	if (fabs(knownSolution_[column])>1.0e-9) {
+	  std::cout<<"( "<<column<<" , "<<knownSolution_[column]<<" ) ";
+	  if ((j%4)==3)
+	    std::cout <<std::endl;
+	  j++;
+	}
+      }
+      std::cout <<std::endl;
+      nbad++;
+    }
+  }
+  return nbad;
+}
+
+
+/* If we are on the path to the known integer solution then
+   check out if generated cut cuts off the known solution!
+   
+   If so then print offending cut and return non-zero code
+*/
+
+bool OsiRowCutDebugger::invalidCut(const OsiRowCut & rcut) const 
+{
+  bool bad=false; 
+  const double epsilon=1.0e-6;
+  
+  CoinPackedVector rpv = rcut.row();
+  const int n = rpv.getNumElements();
+  const int * indices = rpv.getIndices();
+  const double * elements = rpv.getElements();
+  int k;
+  
+  double lb=rcut.lb();
+  double ub=rcut.ub();
+  double sum=0.0;
+  
+  for (k=0; k<n; k++){
+    int column=indices[k];
+    sum += knownSolution_[column]*elements[k];
+  }
+  // is it violated
+  if (sum >ub + epsilon ||sum < lb - epsilon) {
+    double violation=CoinMax(sum-ub,lb-sum);
+    std::cout<<"Cut with "<<n
+	<<" coefficients, cuts off known solutions by "<<violation
+        <<", lo="<<lb<<", ub="<<ub<<std::endl;
+    for (k=0; k<n; k++){
+      int column=indices[k];
+      std::cout<<"( "<<column<<" , "<<elements[k]<<" ) ";
+      if ((k%4)==3)
+	std::cout <<std::endl;
+    }
+    std::cout <<std::endl;
+    std::cout <<"Non zero solution values are"<<std::endl;
+    int j=0;
+    for (k=0; k<n; k++){
+      int column=indices[k];
+      if (fabs(knownSolution_[column])>1.0e-9) {
+	std::cout<<"( "<<column<<" , "<<knownSolution_[column]<<" ) ";
+	if ((j%4)==3)
+	  std::cout <<std::endl;
+	j++;
+      }
+    }
+    std::cout <<std::endl;
+    bad=true;
+  }
+  return bad;
+}
+
+/*
+  Returns true if the column bounds in the solver do not exclude the
+  solution held by the debugger, false otherwise
+
+  Inspects only the integer variables.
+*/
+bool OsiRowCutDebugger::onOptimalPath(const OsiSolverInterface & si) const
+{
+  if (integerVariable_) {
+    int nCols=si.getNumCols(); 
+    if (nCols!=numberColumns_)
+      return false; // check user has not modified problem
+    int i;
+    const double * collower = si.getColLower();
+    const double * colupper = si.getColUpper();
+    bool onOptimalPath=true;
+    for (i=0;i<numberColumns_;i++) {
+      if (collower[i]>colupper[i]+1.0e-12) {
+	printf("Infeasible bounds for %d - %g, %g\n",
+	       i,collower[i],colupper[i]);
+      }
+      if (si.isInteger(i)) {
+	// value of integer variable in solution
+	double value=knownSolution_[i]; 
+	if (value>colupper[i]+1.0e-3 || value<collower[i]-1.0e-3) {
+	  onOptimalPath=false;
+	  break;
+	}
+      }
+    }
+    return onOptimalPath;
+  } else {
+    // no information
+    return false;
+  }
+}
+/*
+  Returns true if the debugger is active (i.e., if the debugger holds a
+  known solution).
+*/
+bool OsiRowCutDebugger::active() const
+{
+  return (integerVariable_!=NULL);
+}
+
+/*
+  Print known solution
+
+  Generally, prints the nonzero values of the known solution. Any incorrect
+  values are flagged with an `*'. Zeros are printed if they are incorrect.
+  As an aid to finding the output when there's something wrong, the first two
+  incorrect values are printed again, flagged with `BAD'.
+
+  Inspects only the integer variables.
+
+  Returns the number of incorrect variables, or -1 if no solution is
+  available. A mismatch in the number of columns between the debugger's
+  solution and the solver qualifies as `no solution'.
+*/
+int
+OsiRowCutDebugger::printOptimalSolution(const OsiSolverInterface & si) const
+{
+  int nCols = si.getNumCols() ; 
+  if (integerVariable_ && nCols == numberColumns_) {
+
+    const double *collower = si.getColLower() ;
+    const double *colupper = si.getColUpper() ;
+/*
+  Dump the nonzeros of the optimal solution. Print zeros if there's a problem.
+*/
+    int bad[2] = {-1,-1} ;
+    int badVars = 0 ;
+    for (int j = 0 ; j < numberColumns_ ; j++) {
+      if (integerVariable_[j]) {
+	double value = knownSolution_[j] ;
+	bool ok = true ;
+	if (value > colupper[j]+1.0e-3 || value < collower[j]-1.0e-3) {
+	  if (bad[0] < 0) {
+	    bad[0] = j ;
+	  } else {
+	    bad[1] = j ;
+	  }
+	  ok = false ;
+	  std::cout << "* " ;
+	}
+	if (value || !ok) std::cout << j << " " << value << std::endl ;
+      }
+    }
+    for (int i = 0 ; i < 2 ; i++) {
+      if (bad[i] >= 0) {
+	int j = bad[i] ;
+	std::cout
+	  << "BAD " << j << " " << collower[j] << " <= "
+	  << knownSolution_[j] << " <= " << colupper[j]  << std::endl ;
+      }
+    }
+    return (badVars) ;
+  } else {
+    // no information
+    return -1;
+  }
+}
+/*
+  Activate a row cut debugger using the name of the model. A known optimal
+  solution will be used to validate cuts. See the source below for the set of
+  known problems. Most are miplib3.
+
+  Returns true if the debugger is successfully activated.
+*/
+bool OsiRowCutDebugger::activate( const OsiSolverInterface & si, 
+				   const char * model)
+{
+  // set to true to print an activation message
+  const bool printActivationNotice = false ;
+  int i;
+  //get rid of any arrays
+  delete [] integerVariable_;
+  delete [] knownSolution_;
+  numberColumns_ = 0;
+  int expectedNumberColumns = 0;
+
+
+  enum {undefined, pure0_1, continuousWith0_1, generalMip } probType;
+
+
+  // Convert input parameter model to be lowercase and 
+  // only consider characters between '/' and '.'
+  std::string modelL; //name in lowercase 
+  for (i=0;i<static_cast<int> (strlen(model));i++) {
+    char value=static_cast<char>(tolower(model[i]));
+    if (value=='/') {
+      modelL.erase();
+    } else if (value=='.') {
+      break;
+    } else {
+      modelL.append(1,value);
+    }
+  }
+
+
+  CoinPackedVector intSoln;
+  probType = undefined;
+
+  //--------------------------------------------------------
+  //
+  // Define additional problems by adding it as an additional
+  // "else if ( modelL == '???' ) { ... }" 
+  // stanza below.
+  //
+  // Assign values to probType and intSoln.
+  //
+  // probType - pure0_1, continuousWith0_1, or generalMip
+  // 
+  // intSoln -
+  //    when probType is pure0_1
+  //       intSoln contains the indices of the variables
+  //       at 1 in the optimal solution
+  //    when probType is continuousWith0_1
+  //       intSoln contains the indices of integer
+  //       variables at one in the optimal solution
+  //    when probType is generalMip
+  //       intSoln contains the the indices of the integer
+  //       variables and their value in the optimal solution
+  //--------------------------------------------------------
+
+  // exmip1
+  if ( modelL == "exmip1" ) {
+    probType=continuousWith0_1;
+    intSoln.insert(2,1.);
+    intSoln.insert(3,1.);
+    expectedNumberColumns=8;
+  }
+
+  // p0033
+  else if ( modelL == "p0033" ) {
+    probType=pure0_1;
+    // Alternate solution -- 21,23 replace 22.
+    // int intIndicesAt1[]={ 0,6,7,9,13,17,18,21,23,24,25,26,27,28,29 };
+    int intIndicesAt1[]={ 0,6,7,9,13,17,18,22,24,25,26,27,28,29 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=33;
+  }
+
+  // flugpl
+  else if ( modelL == "flugpl" ) {
+    probType=generalMip;
+    int intIndicesV[] = { 1 , 3 , 4 , 6 , 7 , 9 ,10 ,12 ,13 ,15 };
+    double intSolnV[] = { 6.,60., 6.,60.,16.,70., 7.,70.,12.,75.};
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=18;
+  }
+
+  // enigma
+  else if ( modelL == "enigma" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={ 0,18,25,36,44,59,61,77,82,93 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=100;
+  }
+
+  // mod011
+  else if ( modelL == "mod011" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={ 10,29,32,40,58,77,80,88 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=10958;
+  }
+
+  // probing
+  else if ( modelL == "probing" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={ 1, 18, 33, 59 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=149;
+  }
+
+  // mas76
+  else if ( modelL == "mas76" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={ 4,11,13,18,42,46,48,52,85,93,114,119,123,128,147}; 
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=151;
+  }
+
+  // ltw3
+  else if ( modelL == "ltw3" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={ 20,23,24,26,32,33,40,47 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=48;
+  }
+
+  // mod008
+  else if ( modelL == "mod008" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={1,59,83,116,123};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=319;
+  }
+
+  // mod010
+  else if ( modelL == "mod010" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={2,9,16,22,26,50,65,68,82,86,102,145,
+	149,158,181,191,266,296,376,479,555,625,725,851,981,
+	1030,1095,1260,1321,1339,1443,1459,1568,1602,1780,1856,
+	1951,2332,2352,2380,2471,2555,2577,2610,2646,2647};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=2655;
+  }
+
+  // modglob
+  else if ( modelL == "modglob" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={204,206,208,212,216,218,220,222,230,232,
+	234,236,244,248,250,254,256,258,260,262,264,266,268,274,
+	278,282,284,286,288};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=422;
+  }
+
+  // p0201
+  else if ( modelL == "p0201" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={8,10,21,38,39,56,60,74,79,92,94,110,111,
+	128,132,146,151,164,166,182,183,200};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=201;
+  }
+
+  // p0282
+  else if ( modelL == "p0282" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={3,11,91,101,103,117,155,169,191,199,215,
+	223,225,237,240,242,243,244,246,248,251,254,256,257,260,
+	262,263,273,275,276,277,280,281};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=282;
+  }
+
+  // p0548
+  else if ( modelL == "p0548" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={2,3,13,14,17,23,24,43,44,47,61,62,74,75,
+	81,82,92,93,96,98,105,120,126,129,140,141,153,154,161,162,
+	165,177,182,184,189,192,193,194,199,200,209,214,215,218,222,
+	226,234,239,247,256,257,260,274,286,301,305,306,314,317,318,
+	327,330,332,334,336,340,347,349,354,358,368,369,379,380,385,
+	388,389,390,393,394,397,401,402,406,407,417,419,420,423,427,
+	428,430,437,439,444,446,447,450,451,452,472,476,477,480,488,
+	491,494,500,503,508,509,510,511,512,515,517,518,519,521,522,
+	523,525,526,527,528,529,530,531,532,533,536,537,538,539,541,
+	542,545,547};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=548;
+  }
+
+  // p2756
+  else if ( modelL == "p2756" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={7,25,50,63,69,71,81,124,164,208,210,212,214,
+	220,266,268,285,299,301,322,362,399,455,464,468,475,518,574,
+	588,590,612,632,652,679,751,767,794,819,838,844,892,894,913,
+	919,954,966,996,998,1021,1027,1044,1188,1230,1248,1315,1348,
+	1366,1367,1420,1436,1473,1507,1509,1521,1555,1558,1607,1659,
+	1715,1746,1761,1789,1800,1844,1885,1913,1916,1931,1992,2002,
+	2050,2091,2155,2158,2159,2197,2198,2238,2264,2292,2318,2481,
+	2496,2497,2522,2531,2573,2583,2587,2588,2596,2635,2637,2639,
+	2643,2645,2651,2653,2672,2675,2680,2683,2708,2727,2730,2751};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=2756;
+  }
+
+  /* nw04
+     It turns out that the NAME line in nw04.mps distributed in miplib is
+     actually NW-capital O-4. Who'd a thunk it?  -- lh, 110402 --
+  */
+  else if ( modelL == "nw04" || modelL == "nwo4" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={
+      231 ,1792 ,1980 ,7548 ,21051 ,28514 ,53087 ,53382 ,76917 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=87482;
+  }
+
+  // bell3a
+  else if ( modelL == "bell3a" ) {
+    probType=generalMip;
+    int intIndicesV[]={61,62,65,66,67,68,69,70};
+    double intSolnV[] = {4.,21.,4.,4.,6.,1.,25.,8.};
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=133;
+  }
+
+  // 10teams
+  else if ( modelL == "10teams" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={236,298,339,379,443,462,520,576,616,646,690,
+	749,778,850,878,918,986,996,1065,1102,1164,1177,1232,1281,1338,
+	1358,1421,1474,1522,1533,1607,1621,1708,1714,1775,1835,1887,
+	1892,1945,1989};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=2025;
+  }
+
+  // rentacar
+  else if ( modelL == "rentacar" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={
+      9502 ,9505 ,9507 ,9511 ,9512 ,9513 ,9514 ,9515 ,9516 ,9521 ,
+      9522 ,9526 ,9534 ,9535 ,9536 ,9537 ,9542 ,9543 ,9544 ,9548 ,
+      9550 ,9554 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=9557;
+  }
+
+  // qiu
+  else if ( modelL == "qiu" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={
+      0 ,5 ,8 ,9 ,11 ,13 ,16 ,17 ,19 ,20 ,
+      24 ,28 ,32 ,33 ,35 ,37 ,40 ,47 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=840;
+  }
+
+  // pk1
+  else if ( modelL == "pk1" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={
+      1 ,4 ,5 ,6 ,7 ,11 ,13 ,16 ,17 ,23 ,
+      24 ,27 ,28 ,34 ,35 ,37 ,43 ,44 ,45 ,46 ,
+      47 ,51 ,52 ,54 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=86;
+  }
+
+  // pp08a
+  else if ( modelL == "pp08a" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={
+      177 ,179 ,181 ,183 ,185 ,190 ,193 ,195 ,197 ,199 ,
+      202 ,204 ,206 ,208 ,216 ,220 ,222 ,229 ,235 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=240;
+  }
+
+  // pp08aCUTS
+  else if ( modelL == "pp08acuts" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={
+      177 ,179 ,181 ,183 ,185 ,190 ,193 ,195 ,197 ,199 ,
+      202 ,204 ,206 ,208 ,216 ,220 ,222 ,229 ,235 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=240;
+  }
+
+  // danoint
+  else if ( modelL == "danoint" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={3,5,8,11,15,21,24,25,31,34,37,42,46,48,51,56};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=521;
+  }
+
+  // dcmulti
+  else if ( modelL == "dcmulti" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={2,3,11,14,15,16,21,24,28,34,35,36,39,40,41,42,
+	45,52,53,60,61,64,65,66,67};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=548;
+  }
+
+  // egout
+  else if ( modelL == "egout" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={0,3,5,7,8,9,11,12,13,15,16,17,18,20,21,22,
+	23,24,25,26,27,28,29,32,34,36,37,38,39,40,42,43,44,45,46,47,
+	48,49,52,53,54};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=141;
+  }
+
+  // fixnet6
+  else if ( modelL == "fixnet6" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={1,16,23,31,37,51,64,179,200,220,243,287,
+	375,413,423,533,537,574,688,690,693,712,753,773,778,783,847};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=878;
+  }
+
+  // khb05250
+  else if ( modelL == "khb05250" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={1,3,8,11,12,15,16,17,18,21,22,23};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=1350;
+  }
+
+  // lseu
+  else if ( modelL == "lseu" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={0,1,6,13,26,33,38,43,50,52,63,65,85};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=89;
+  }
+
+  // air03
+  else if ( modelL == "air03" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={
+      1, 3, 5, 13, 14, 28, 38, 49, 75, 76, 
+      151, 185, 186, 271, 370, 466, 570, 614, 732, 819, 
+      1151, 1257, 1490, 2303, 2524, 3301, 3616, 4129, 4390, 4712, 
+      5013, 5457, 5673, 6436, 7623, 8122, 8929, 10689, 10694, 10741, 
+      10751
+    };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=10757;
+  }
+
+  // air04
+  else if ( modelL == "air04" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={
+      0, 1, 3, 4, 5, 6, 7, 9, 11, 12, 
+      13, 17, 19, 20, 21, 25, 26, 27, 28, 29, 
+      32, 35, 36, 39, 40, 42, 44, 45, 47, 48, 
+      49, 50, 51, 52, 53, 56, 57, 58, 60, 63, 
+      64, 66, 67, 68, 73, 74, 80, 81, 83, 85, 
+      87, 92, 93, 94, 95, 99, 101, 102, 105, 472, 
+      616, 680, 902, 1432, 1466, 1827, 2389, 2535, 2551, 2883, 
+      3202, 3215, 3432, 3438, 3505, 3517, 3586, 3811, 3904, 4092, 
+      4685, 4700, 4834, 4847, 4892, 5189, 5211, 5394, 5878, 6045, 
+      6143, 6493, 6988, 7511, 7664, 7730, 7910, 8041, 8350, 8615, 
+      8635, 8670
+    };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=8904;
+  }
+
+  // air05
+  else if ( modelL == "air05" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={
+      2, 4, 5, 6, 7, 8, 9, 10, 14, 15, 
+      19, 20, 25, 34, 35, 37, 39, 40, 41, 42, 
+      43, 44, 45, 47, 48, 50, 52, 55, 57, 58, 
+      66, 72, 105, 218, 254, 293, 381, 695, 1091, 1209, 
+      1294, 1323, 1348, 1580, 1769, 2067, 2156, 2162, 2714, 2732, 
+      3113, 3131, 3145, 3323, 3398, 3520, 3579, 4295, 5025, 5175, 
+      5317, 5340, 6324, 6504, 6645, 6809
+    };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=7195;
+  }
+
+  // seymour
+  else if ( modelL == "seymour" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]=
+      {
+	1, 2, 3, 5, 6, 7, 9, 11, 12, 16, 
+	18, 22, 23, 25, 27, 31, 32, 34, 35, 36, 
+	38, 39, 40, 42, 44, 45, 46, 49, 50, 51, 
+	52, 54, 55, 56, 58, 61, 63, 65, 67, 68, 
+	69, 70, 71, 75, 79, 81, 82, 84, 85, 86, 
+	87, 88, 89, 91, 93, 95, 97, 98, 99, 100, 
+	101, 102, 103, 106, 108, 112, 116, 118, 119, 120, 
+	122, 123, 124, 125, 126, 129, 130, 132, 135, 137, 
+	140, 141, 142, 143, 144, 148, 150, 151, 154, 156, 
+	159, 160, 162, 163, 164, 165, 167, 169, 170, 174, 
+	177, 178, 180, 181, 182, 183, 188, 189, 192, 194, 
+	200, 201, 202, 203, 204, 211, 214, 218, 226, 227, 
+	228, 231, 232, 237, 240, 242, 244, 247, 248, 249, 
+	251, 253, 256, 257, 259, 261, 264, 265, 266, 268, 
+	270, 272, 278, 280, 284, 286, 288, 289, 291, 292, 
+	296, 299, 302, 305, 307, 308, 311, 312, 313, 314, 
+	315, 316, 317, 319, 321, 325, 328, 332, 334, 335, 
+	337, 338, 339, 340, 343, 346, 355, 357, 358, 365, 
+	369, 372, 373, 374, 375, 376, 378, 381, 383, 386, 
+	392, 396, 399, 402, 403, 412, 416, 419, 424, 425, 
+	426, 427, 430, 431, 432, 436, 437, 438, 440, 441, 
+	443, 450, 451, 452, 453, 456, 460, 461, 462, 467, 
+	469, 475, 476, 477, 478, 479, 485, 486, 489, 491, 
+	493, 498, 500, 501, 508, 513, 515, 516, 518, 519, 
+	520, 524, 527, 541, 545, 547, 548, 559, 562, 563, 
+	564, 566, 567, 570, 572, 575, 576, 582, 583, 587, 
+	589, 595, 599, 602, 610, 611, 615, 622, 631, 646, 
+	647, 649, 652, 658, 662, 665, 667, 671, 676, 679, 
+	683, 685, 686, 688, 689, 691, 699, 705, 709, 711, 
+	712, 716, 721, 722, 724, 726, 729, 732, 738, 739, 
+	741, 745, 746, 747, 749, 752, 757, 765, 767, 768, 
+	775, 779, 780, 791, 796, 798, 808, 809, 812, 813, 
+	817, 819, 824, 825, 837, 839, 849, 851, 852, 857, 
+	865, 874, 883, 885, 890, 897, 902, 907, 913, 915, 
+	923, 924, 927, 931, 933, 936, 938, 941, 945, 949, 
+	961, 970, 971, 978, 984, 985, 995, 997, 999, 1001, 
+	1010, 1011, 1012, 1025, 1027, 1035, 1043, 1055, 1056, 1065, 
+	1077, 1089, 1091, 1096, 1100, 1104, 1112, 1126, 1130, 1131, 
+	1132, 1134, 1136, 1143, 1149, 1162, 1163, 1164, 1183, 1184, 
+	1191, 1200, 1201, 1209, 1215, 1220, 1226, 1228, 1229, 1233, 
+	1241, 1243, 1244, 1258, 1277, 1279, 1285, 1291, 1300, 1303, 
+	1306, 1311, 1320, 1323, 1333, 1344, 1348, 1349, 1351, 1356, 
+	1363, 1364, 1365, 1366};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=1372;
+  }
+
+  // stein27
+  else if ( modelL == "stein27" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={0,1,3,4,5,6,7,8,9,11,13,16,17,19,21,22,25,26};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=27;
+  }
+
+  // stein45
+  else if ( modelL == "stein45" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={0,1,4,5,6,7,8,9,10,11,14,17,18,19,21,23,24,25,26,28,
+    31,32,33,36,37,39,40,42,43,44};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=45;
+  }
+
+  // misc03
+  else if ( modelL == "misc03" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={4,40,62,75,99,114,127,134,147,148,150,
+	152,154,155,157};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=160;
+  }
+
+  // misc06
+  else if ( modelL == "misc06" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={
+      1557 ,1560 ,1561 ,1580 ,1585 ,1588 ,1589 ,1614 ,1615 ,1616 ,
+      1617 ,1626 ,1630 ,1631 ,1642 ,1643 ,1644 ,1645 ,1650 ,1654 ,
+      1658 ,1659 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=1808;
+  }
+
+  // misc07
+  else if ( modelL == "misc07" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={21,27,57,103,118,148,185,195,205,209,243,
+	245,247,249,251,253,255,257};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=260;
+  }
+
+  // rgn
+  else if ( modelL == "rgn" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={16 ,49 ,72 ,92 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=180;
+  }
+
+  // mitre
+  else if ( modelL == "mitre" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={
+      4,37,67,93,124,154,177,209,240,255,287,319,340,
+      372,403,425,455,486,516,547,579,596,628,661,676,
+      713,744,758,795,825,851,881,910,933,963,993,1021,
+      1052,1082,1111,1141,1172,1182,1212,1242,1272,1303,
+      1332,1351,1382,1414,1445,1478,1508,1516,1546,1576,
+      1601,1632,1662,1693,1716,1749,1781,1795,1828,1860,
+      1876,1909,1940,1962,1994,2027,2058,2091,2122,2128,
+      2161,2192,2226,2261,2290,2304,2339,2369,2393,2426,
+      2457,2465,2500,2529,2555,2590,2619,2633,2665,2696,
+      2728,2760,2792,2808,2838,2871,2896,2928,2960,2981,
+      3014,3045,3065,3098,3127,3139,3170,3200,3227,3260,
+      3292,3310,3345,3375,3404,3437,3467,3482,3513,3543,
+      3558,3593,3623,3653,3686,3717,3730,3762,3794,3814,
+      3845,3877,3901,3936,3966,3988,4019,4049,4063,4096,
+      4126,4153,4186,4216,4245,4276,4306,4318,4350,4383,
+      4402,4435,4464,4486,4519,4550,4578,4611,4641,4663,
+      4695,4726,4738,4768,4799,4830,4863,4892,4919,4950,
+      4979,4991,5024,5054,5074,5107,5137,5165,5198,5228,
+      5244,5275,5307,5325,5355,5384,5406,5436,5469,5508,
+      5538,5568,5585,5615,5646,5675,5705,5734,5745,5774,
+      5804,5836,5865,5895,5924,5954,5987,6001,6033,6064,
+      6096,6126,6155,6172,6202,6232,6250,6280,6309,6328,
+      6361,6392,6420,6450,6482,6500,6531,6561,6598,6629,
+      6639,6669,6699,6731,6762,6784,6814,6844,6861,6894,
+      6924,6955,6988,7018,7042,7075,7105,7116,7149,7179,
+      7196,7229,7258,7282,7312,7345,7376,7409,7438,7457,
+      7487,7520,7534,7563,7593,7624,7662,7692,7701,7738,
+      7769,7794,7827,7857,7872,7904,7935,7960,7990,8022,
+      8038,8071,8101,8137,8167,8199,8207,8240,8269,8301,
+      8334,8363,8387,8420,8450,8470,8502,8534,8550,8580,
+      8610,8639,8669,8699,8709,8741,8772,8803,8834,8867,
+      8883,8912,8942,8973,9002,9032,9061,9094,9124,9128,
+      9159,9201,9232,9251,9280,9310,9333,9338,9405,9419,
+      9423,9428,9465,9472,9482,9526,9639,9644,9666,9673,
+      9729,9746,9751,9819,9832,9833,9894,9911,9934,9990,
+      10007,10012,10083,10090,10095,10137,10176,10177,
+      10271,10279,10280,10288,10292,10298,10299,10319,
+      10351,10490,10505,10553,10571,10579,10600,10612,
+      10683,10688};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=10724;
+  }
+
+
+  // cap6000
+  else if ( modelL == "cap6000" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={
+46 ,141 ,238 ,250 ,253 ,257 ,260 ,261 ,266 ,268 ,
+270 ,274 ,277 ,280 ,289 ,292 ,296 ,297 ,300 ,305 ,
+306 ,310 ,314 ,317 ,319 ,321 ,324 ,329 ,332 ,333 ,
+336 ,339 ,343 ,345 ,350 ,353 ,354 ,357 ,361 ,364 ,
+367 ,370 ,372 ,376 ,379 ,381 ,386 ,387 ,392 ,395 ,
+397 ,400 ,402 ,405 ,410 ,413 ,416 ,419 ,420 ,425 ,
+427 ,430 ,434 ,436 ,441 ,444 ,447 ,451 ,454 ,456 ,
+459 ,463 ,467 ,468 ,473 ,474 ,479 ,480 ,483 ,488 ,
+490 ,493 ,496 ,499 ,501 ,506 ,509 ,511 ,522 ,536 ,
+537 ,552 ,563 ,565 ,569 ,571 ,574 ,576 ,580 ,582 ,
+588 ,591 ,596 ,597 ,601 ,607 ,609 ,613 ,616 ,618 ,
+621 ,626 ,632 ,634 ,644 ,647 ,648 ,658 ,661 ,663 ,
+668 ,670 ,680 ,688 ,691 ,695 ,698 ,699 ,703 ,713 ,
+721 ,723 ,730 ,740 ,742 ,746 ,751 ,755 ,757 ,760 ,
+765 ,770 ,775 ,777 ,781 ,785 ,792 ,796 ,801 ,804 ,
+812 ,821 ,826 ,834 ,838 ,840 ,844 ,872 ,881 ,883 ,
+887 ,888 ,899 ,904 ,906 ,917 ,919 ,931 ,938 ,945 ,
+948 ,953 ,958 ,962 ,963 ,970 ,976 ,979 ,981 ,997 ,
+1000 ,1004 ,1005 ,1009 ,1013 ,1014 ,1024 ,1026 ,1034 ,1039 ,
+1055 ,1061 ,1069 ,1076 ,1078 ,1084 ,1089 ,1099 ,1101 ,1104 ,
+1109 ,1111 ,1124 ,1127 ,1129 ,1133 ,1138 ,1140 ,1145 ,1148 ,
+1149 ,1159 ,1166 ,1167 ,1171 ,1180 ,1187 ,1194 ,1197 ,1205 ,
+1224 ,1228 ,1246 ,1255 ,1261 ,1269 ,1275 ,1286 ,1289 ,1291 ,
+1311 ,1390 ,1406 ,1410 ,1413 ,1418 ,1427 ,1435 ,1440 ,1446 ,
+1453 ,1455 ,1468 ,1477 ,1479 ,1486 ,1492 ,1502 ,1508 ,1509 ,
+1525 ,1551 ,1559 ,1591 ,1643 ,1657 ,1660 ,1662 ,1677 ,1710 ,
+1719 ,1752 ,1840 ,1862 ,1870 ,1891 ,1936 ,1986 ,2087 ,2178 ,
+2203 ,2212 ,2311 ,2503 ,2505 ,2530 ,2532 ,2557 ,2561 ,2564 ,
+2567 ,2571 ,2578 ,2581 ,2588 ,2591 ,2594 ,2595 ,2598 ,2603 ,
+2605 ,2616 ,2620 ,2624 ,2630 ,2637 ,2643 ,2647 ,2654 ,2656 ,
+2681 ,2689 ,2699 ,2703 ,2761 ,2764 ,2867 ,2871 ,2879 ,2936 ,
+2971 ,3024 ,3076 ,3094 ,3119 ,3378 ,3435 ,3438 ,3446 ,3476 ,
+3570 ,3605 ,3646 ,3702 ,3725 ,3751 ,3755 ,3758 ,3760 ,3764 ,
+3765 ,3770 ,3773 ,3776 ,3779 ,3782 ,3784 ,3788 ,3791 ,3792 ,
+3796 ,3799 ,3803 ,3804 ,3807 ,3811 ,3814 ,3816 ,3821 ,3823 ,
+3826 ,3830 ,3831 ,3836 ,3838 ,3840 ,3844 ,3847 ,3851 ,3852 ,
+3855 ,3859 ,3863 ,3864 ,3867 ,3895 ,3921 ,3948 ,3960 ,3970 ,
+3988 ,4026 ,4032 ,4035 ,4036 ,4038 ,4041 ,4042 ,4045 ,4046 ,
+4048 ,4050 ,4053 ,4055 ,4057 ,4058 ,4060 ,4063 ,4065 ,4067 ,
+4069 ,4071 ,4072 ,4075 ,4076 ,4079 ,4081 ,4082 ,4085 ,4087 ,
+4088 ,4090 ,4092 ,4094 ,4097 ,4099 ,4100 ,4102 ,4104 ,4107 ,
+4109 ,4111 ,4113 ,4114 ,4207 ,4209 ,4213 ,4216 ,4220 ,4227 ,
+4233 ,4238 ,4240 ,4248 ,4253 ,4259 ,4260 ,4267 ,4268 ,4273 ,
+4280 ,4284 ,4290 ,4292 ,4295 ,4301 ,4303 ,4311 ,4319 ,4326 ,
+4329 ,4332 ,4335 ,4336 ,4344 ,4349 ,4351 ,4355 ,4363 ,4371 ,
+4372 ,4378 ,4388 ,4401 ,4409 ,4413 ,4417 ,4420 ,4435 ,4441 ,
+4451 ,4458 ,4463 ,4468 ,4474 ,4478 ,4482 ,4483 ,4488 ,4497 ,
+4499 ,4522 ,4614 ,4626 ,4645 ,4648 ,4751 ,4755 ,4758 ,4759 ,
+4763 ,4840 ,4846 ,4859 ,4865 ,4883 ,4943 ,4970 ,5030 ,5084 ,
+5124 ,5181 ,5224 ,5236 ,5238 ,5328 ,5362 ,5375 ,5378 ,5434 ,
+5478 ,5483 ,5562 ,5581 ,5586 ,5591 ,5644 ,5684 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=6000;
+  }
+
+  // gen
+  else if ( modelL == "gen" ) {
+    probType=generalMip;
+    int intIndicesV[]={15,34,35,36,37,38,39,40,41,42,43,44,45,57,58,
+	59,60,61,62,63,64,65,66,67,68,69,84,85,86,87,88,89,90,91,92,
+	93,107,108,109,110,111,112,113,114,120,121,122,123,124,125,
+	126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,
+		       141,142,143,432,433,434,435,436};
+    double intSolnV[] = {1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,
+	1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,
+	1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,
+	1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,23.,12.,11.,14.,16.};
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=870;
+  }
+
+  // dsbmip
+  else if ( modelL == "dsbmip" ) {
+    probType=generalMip;
+    int intIndicesV[]={
+1694 ,1695 ,1696 ,1697 ,1698 ,1699 ,1700 ,1701 ,1702 ,1703 ,
+1729 ,1745 ,1748 ,1751 ,1753 ,1754 ,1758 ,1760 ,1766 ,1771 ,
+1774 ,1777 ,1781 ,1787 ,1792 ,1796 ,1800 ,1805 ,1811 ,1817 ,
+1819 ,1821 ,1822 ,1824 ,1828 ,1835 ,1839 ,1841 ,1844 ,1845 ,
+1851 ,1856 ,1860 ,1862 ,1864 ,1869 ,1875 ,1883 };
+	double intSolnV[]={
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. };
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=1886;
+  }
+
+
+  // gesa2
+  else if ( modelL == "gesa2" ) {
+    probType=generalMip;
+    int intIndicesV[]={
+323 ,324 ,336 ,337 ,349 ,350 ,362 ,363 ,375 ,376 ,
+388 ,389 ,401 ,402 ,414 ,415 ,423 ,424 ,426 ,427 ,
+428 ,436 ,437 ,439 ,440 ,441 ,449 ,450 ,452 ,453 ,
+454 ,462 ,463 ,465 ,466 ,467 ,475 ,476 ,478 ,479 ,
+480 ,489 ,491 ,492 ,493 ,502 ,504 ,505 ,506 ,514 ,
+515 ,517 ,518 ,519 ,527 ,528 ,530 ,531 ,532 ,537 ,
+538 ,540 ,541 ,543 ,544 ,545 ,550 ,551 ,553 ,554 ,
+556 ,557 ,558 ,563 ,564 ,566 ,567 ,569 ,570 ,571 ,
+573 ,577 ,579 ,580 ,582 ,583 ,584 ,592 ,593 ,595 ,
+596 ,597 ,605 ,606 ,608 ,609 ,610 ,622 ,623 ,1130 ,
+1131 ,1134 ,1135 ,1138 ,1139 ,1142 ,1143 ,1146 ,1147 ,1150 ,
+1151 ,1154 ,1155 ,1158 ,1159 ,1161 ,1162 ,1165 ,1166 ,1169 ,
+1170 ,1173 ,1174 ,1177 ,1178 ,1182 ,1183 ,1185 ,1186 ,1189 ,
+1190 ,1193 ,1194 ,1196 ,1197 ,1200 ,1201 ,1204 ,1205 ,1209 ,
+1210 ,1213 ,1214 ,1218 ,1222 ,1223 };
+	double intSolnV[]={
+1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,
+1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,2. ,1. ,
+2. ,3. ,2. ,2. ,1. ,2. ,3. ,2. ,2. ,1. ,
+2. ,3. ,2. ,2. ,1. ,2. ,2. ,2. ,2. ,1. ,
+2. ,2. ,2. ,1. ,2. ,2. ,2. ,1. ,2. ,1. ,
+2. ,2. ,1. ,2. ,2. ,2. ,2. ,1. ,2. ,1. ,
+4. ,3. ,3. ,2. ,1. ,2. ,1. ,4. ,3. ,3. ,
+2. ,1. ,2. ,1. ,4. ,3. ,3. ,2. ,1. ,2. ,
+1. ,4. ,3. ,3. ,2. ,1. ,2. ,3. ,3. ,2. ,
+1. ,2. ,1. ,2. ,2. ,1. ,2. ,1. ,2. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. };
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=1224;
+  }
+
+  // gesa2_o
+  else if ( modelL == "gesa2_o" ) {
+    probType=generalMip;
+	int intIndicesV[]={
+315 ,316 ,328 ,329 ,341 ,342 ,354 ,355 ,367 ,368 ,
+380 ,381 ,393 ,394 ,406 ,407 ,419 ,420 ,423 ,427 ,
+428 ,432 ,433 ,436 ,440 ,441 ,445 ,446 ,449 ,453 ,
+454 ,458 ,459 ,462 ,466 ,467 ,471 ,472 ,475 ,479 ,
+480 ,484 ,485 ,492 ,493 ,497 ,498 ,505 ,506 ,510 ,
+511 ,514 ,518 ,519 ,523 ,524 ,527 ,531 ,532 ,536 ,
+537 ,539 ,540 ,543 ,544 ,545 ,549 ,550 ,552 ,553 ,
+556 ,557 ,558 ,562 ,563 ,565 ,566 ,569 ,570 ,571 ,
+575 ,576 ,577 ,579 ,582 ,583 ,584 ,588 ,589 ,592 ,
+596 ,597 ,601 ,602 ,605 ,609 ,610 ,614 ,615 ,735 ,
+739 ,740 ,748 ,826 ,839 ,851 ,852 ,855 ,856 ,889 ,
+1136 ,1137 ,1138 ,1139 ,1140 ,1142 ,1143 ,1144 ,1145 ,1146 ,
+1147 ,1148 ,1149 ,1152 ,1153 ,1154 ,1155 ,1156 ,1157 ,1158 ,
+1159 ,1165 ,1175 ,1193 ,1194 ,1195 ,1200 ,1201 ,1202 ,1203 ,
+1204 ,1205 ,1206 ,1207 ,1208 ,1209 ,1210 ,1211 ,1212 ,1213 ,
+1214 ,1215 ,1216 ,1220 ,1221 ,1222 ,1223 };
+	double intSolnV[]={
+1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,
+1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,
+2. ,1. ,2. ,3. ,2. ,2. ,1. ,2. ,3. ,2. ,
+2. ,1. ,2. ,3. ,2. ,2. ,1. ,2. ,2. ,2. ,
+2. ,1. ,2. ,2. ,2. ,1. ,2. ,2. ,2. ,1. ,
+2. ,1. ,2. ,2. ,1. ,2. ,2. ,2. ,2. ,1. ,
+2. ,1. ,3. ,4. ,3. ,2. ,1. ,2. ,1. ,3. ,
+4. ,3. ,2. ,1. ,2. ,1. ,3. ,4. ,3. ,2. ,
+1. ,2. ,1. ,3. ,4. ,3. ,2. ,1. ,2. ,3. ,
+3. ,2. ,1. ,2. ,1. ,2. ,2. ,1. ,2. ,1. ,
+2. ,2. ,2. ,1. ,1. ,1. ,1. ,4. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. };
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=1224;
+  }
+
+  // gesa3
+  else if ( modelL == "gesa3" ) {
+    probType=generalMip;
+    int intIndicesV[]={
+298 ,299 ,310 ,311 ,322 ,323 ,334 ,335 ,346 ,347 ,
+358 ,359 ,365 ,370 ,371 ,377 ,378 ,380 ,382 ,383 ,
+389 ,390 ,392 ,394 ,395 ,401 ,402 ,404 ,405 ,406 ,
+407 ,413 ,414 ,416 ,417 ,418 ,419 ,425 ,426 ,428 ,
+429 ,430 ,431 ,437 ,438 ,440 ,441 ,442 ,443 ,449 ,
+450 ,452 ,454 ,455 ,461 ,462 ,464 ,466 ,467 ,473 ,
+474 ,476 ,478 ,479 ,485 ,486 ,488 ,490 ,491 ,497 ,
+498 ,500 ,502 ,503 ,509 ,510 ,512 ,514 ,515 ,521 ,
+522 ,524 ,526 ,527 ,533 ,534 ,536 ,538 ,539 ,545 ,
+546 ,548 ,550 ,551 ,557 ,558 ,560 ,562 ,563 ,569 ,
+572 ,574 ,575 ,1058 ,1059 ,1062 ,1063 ,1066 ,1067 ,1070 ,
+1071 ,1074 ,1075 ,1078 ,1079 ,1082 ,1083 ,1086 ,1087 ,1090 ,
+1091 ,1094 ,1095 ,1098 ,1099 ,1102 ,1103 ,1106 ,1107 ,1110 ,
+1111 ,1114 ,1115 ,1118 ,1119 ,1122 ,1123 ,1126 ,1127 ,1130 ,
+1131 ,1134 ,1135 ,1138 ,1139 ,1142 ,1143 ,1146 ,1147 ,1150 ,
+1151 };
+	double intSolnV[]={
+1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,
+1. ,2. ,1. ,1. ,2. ,2. ,1. ,1. ,1. ,2. ,
+2. ,1. ,2. ,1. ,2. ,2. ,1. ,2. ,2. ,1. ,
+2. ,2. ,1. ,2. ,2. ,1. ,2. ,2. ,1. ,2. ,
+2. ,1. ,2. ,2. ,1. ,2. ,1. ,1. ,2. ,2. ,
+1. ,2. ,1. ,2. ,2. ,1. ,2. ,1. ,2. ,2. ,
+1. ,2. ,1. ,2. ,4. ,1. ,2. ,1. ,2. ,4. ,
+2. ,4. ,1. ,2. ,4. ,2. ,4. ,1. ,2. ,4. ,
+2. ,4. ,1. ,2. ,4. ,1. ,4. ,1. ,2. ,3. ,
+1. ,3. ,1. ,2. ,2. ,1. ,2. ,1. ,2. ,1. ,
+1. ,1. ,2. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. };
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=1152;
+  }
+
+  // gesa3_o
+  else if ( modelL == "gesa3_o" ) {
+    probType=generalMip;
+    int intIndicesV[]={
+291 ,292 ,303 ,304 ,315 ,316 ,327 ,328 ,339 ,340 ,
+351 ,352 ,361 ,363 ,364 ,373 ,374 ,375 ,376 ,379 ,
+385 ,386 ,387 ,388 ,391 ,397 ,398 ,399 ,400 ,403 ,
+407 ,409 ,410 ,411 ,412 ,415 ,419 ,421 ,422 ,423 ,
+424 ,427 ,431 ,433 ,434 ,435 ,436 ,439 ,443 ,445 ,
+446 ,447 ,448 ,451 ,457 ,458 ,459 ,460 ,463 ,469 ,
+470 ,471 ,472 ,475 ,481 ,482 ,483 ,484 ,487 ,493 ,
+494 ,495 ,496 ,499 ,505 ,506 ,507 ,508 ,511 ,517 ,
+518 ,519 ,520 ,523 ,529 ,530 ,531 ,532 ,535 ,541 ,
+542 ,543 ,544 ,547 ,553 ,554 ,555 ,556 ,559 ,565 ,
+566 ,567 ,568 ,578 ,590 ,602 ,614 ,626 ,638 ,649 ,
+650 ,661 ,662 ,667 ,674 ,686 ,695 ,698 ,710 ,722 ,
+734 ,746 ,758 ,769 ,770 ,782 ,787 ,794 ,806 ,818 ,
+830 ,842 ,854 ,1080 ,1081 ,1082 ,1083 ,1084 ,1085 ,1086 ,
+1087 ,1088 ,1089 ,1090 ,1091 ,1092 ,1093 ,1094 ,1095 ,1096 ,
+1097 ,1098 ,1099 ,1100 ,1101 ,1102 ,1103 ,1128 ,1129 ,1130 ,
+1131 ,1132 ,1133 ,1134 ,1135 ,1136 ,1137 ,1138 ,1139 ,1140 ,
+1141 ,1142 ,1143 ,1144 ,1145 ,1146 ,1147 ,1148 ,1149 ,1150 ,
+1151 };
+	double intSolnV[]={
+1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,1. ,2. ,
+1. ,2. ,1. ,1. ,2. ,2. ,1. ,1. ,2. ,1. ,
+2. ,2. ,1. ,2. ,1. ,2. ,2. ,1. ,2. ,1. ,
+2. ,2. ,2. ,1. ,2. ,1. ,2. ,2. ,2. ,1. ,
+2. ,1. ,2. ,2. ,2. ,1. ,2. ,1. ,1. ,2. ,
+2. ,1. ,2. ,1. ,2. ,2. ,1. ,2. ,1. ,2. ,
+2. ,1. ,2. ,1. ,4. ,2. ,1. ,2. ,1. ,4. ,
+4. ,1. ,2. ,2. ,4. ,4. ,1. ,2. ,2. ,4. ,
+4. ,1. ,2. ,2. ,4. ,4. ,1. ,2. ,1. ,3. ,
+3. ,1. ,2. ,1. ,2. ,2. ,1. ,2. ,1. ,1. ,
+1. ,1. ,2. ,4. ,4. ,4. ,4. ,4. ,4. ,1. ,
+4. ,1. ,4. ,1. ,4. ,4. ,2. ,4. ,4. ,4. ,
+4. ,4. ,4. ,2. ,4. ,4. ,1. ,4. ,4. ,4. ,
+4. ,4. ,4. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+1. };
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=1152;
+  }
+
+  // noswot
+  else if ( modelL == "noswot_z" ) {
+    probType=generalMip;
+    int intIndicesV[]={1};
+    double intSolnV[]={1.0};
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=128;
+  }
+
+
+  // qnet1
+  else if ( modelL == "qnet1" ) {
+    probType=generalMip;
+    int intIndicesV[]={
+      61 ,69 ,79 ,81 ,101 ,104 ,111 ,115 ,232 ,265 ,
+      267 ,268 ,269 ,285 ,398 ,412 ,546 ,547 ,556 ,642 ,
+      709 ,718 ,721 ,741 ,760 ,1073 ,1077 ,1084 ,1097 ,1100 ,
+      1104 ,1106 ,1109 ,1248 ,1259 ,1260 ,1263 ,1265 ,1273 ,1274 ,
+      1276 ,1286 ,1291 ,1302 ,1306 ,1307 ,1316 ,1350 ,1351 ,1363 ,
+      1366 ,1368 ,1371 ,1372 ,1380 ,1381 ,1385 ,1409 };
+    double intSolnV[]={
+      1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+      1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+      1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+      1. ,1. ,1. ,1. ,2. ,1. ,1. ,1. ,1. ,3. ,
+      1. ,2. ,1. ,1. ,1. ,1. ,6. ,3. ,1. ,1. ,
+      5. ,2. ,1. ,2. ,2. ,1. ,2. ,1. };
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=1541;
+  }
+
+  // qnet1_o (? marginally different from qnet1)
+  else if ( modelL == "qnet1_o" ) {
+    probType=generalMip;
+    int intIndicesV[]={
+      61 ,69 ,79 ,81 ,101 ,106 ,111 ,114 ,115 ,232 ,
+      266 ,267 ,268 ,269 ,277 ,285 ,398 ,412 ,546 ,547 ,
+      556 ,642 ,709 ,718 ,721 ,741 ,760 ,1073 ,1077 ,1084 ,
+      1097 ,1100 ,1104 ,1106 ,1109 ,1248 ,1259 ,1260 ,1263 ,1265 ,
+      1273 ,1274 ,1276 ,1286 ,1291 ,1302 ,1306 ,1307 ,1316 ,1350 ,
+      1351 ,1363 ,1366 ,1368 ,1371 ,1372 ,1380 ,1381 ,1385 ,1409 };
+    double intSolnV[]={
+      1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+      1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+      1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,
+      1. ,1. ,1. ,1. ,1. ,1. ,2. ,1. ,1. ,1. ,
+      1. ,3. ,1. ,2. ,1. ,1. ,1. ,1. ,6. ,3. ,
+      1. ,1. ,5. ,2. ,1. ,2. ,2. ,1. ,2. ,1. };
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=1541;
+  }
+
+  // gt2
+  else if ( modelL == "gt2" ) {
+    probType=generalMip;
+    int intIndicesV[]={82,85,88,92,94,95,102,103,117,121,122,128,
+		       141,146,151,152,165,166,176,179};
+    double intSolnV[] = {1.,3.,1.,5.,2.,1.,1.,2.,2.,2.,1.,2.,1.,1.,
+	2.,1.,1.,6.,1.,1.};
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=188;
+  }
+
+  // fiber
+  else if ( modelL == "fiber" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]={36,111,190,214,235,270,338,346,372,386,
+	421,424,441,470,473,483,484,498,580,594,597,660,689,735,
+	742,761,762,776,779,817,860,1044,1067,1122,1238};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=1298;
+  }
+
+  // vpm1
+  else if ( modelL == "vpm1" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]=
+      { 180,181,182,185,195,211,214,226,231,232,244,251,263,269,
+	285,294,306,307,314,  319};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=378;
+  }
+
+  // vpm2
+  else if ( modelL == "vpm2" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]=
+      {170,173,180,181,182,185,193,194,196,213,219,220,226,
+       245,251,262,263,267,269,273,288,289,294,319,320};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=378;
+  }
+  // markshare1
+  else if ( modelL == "markshare1" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]=
+      {12 ,13 ,17 ,18 ,22 ,27 ,28 ,29 ,33 ,34 ,35 ,36 ,
+       39 ,42 ,43 ,44 ,46 ,47 ,49 ,51 ,52 ,53 ,54 ,55 ,59 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=62;
+  }
+
+  // markshare2
+  else if ( modelL == "markshare2" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]=
+      {16 ,21 ,25 ,26 ,29 ,30 ,31 ,32 ,34 ,35 ,
+       37 ,40 ,42 ,44 ,45 ,47 ,48 ,52 ,53 ,57 ,
+       58 ,59 ,60 ,61 ,62 ,63 ,65 ,71 ,73 };
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=74;
+  }
+
+  // l152lav
+  else if ( modelL == "l152lav" ) {
+    probType=pure0_1;
+    int intIndicesAt1[]={1,16,30,33,67,111,165,192,198,321,411,449,
+	906,961,981,1052,1075,1107,1176,1231,1309,1415,1727,1847,
+	1902,1917,1948,1950};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    expectedNumberColumns=1989;
+  }
+
+  // bell5
+  else if ( modelL == "bell5" ) {
+    probType=generalMip;
+    int intIndicesV[]={
+      0 ,1 ,2 ,3 ,4 ,6 ,33 ,34 ,36 ,47 ,
+      48 ,49 ,50 ,51 ,52 ,53 ,54 ,56 };
+    double intSolnV[]={
+      1. ,1. ,1. ,1. ,1. ,1. ,1. ,1. ,11. ,2. ,
+      38. ,2. ,498. ,125. ,10. ,17. ,41. ,19. };
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=104;
+  }
+
+  // blend2
+  else if ( modelL == "blend2" ) {
+    probType=generalMip;
+    int intIndicesV[]={24,35,44,45,46,52,63,64,70,71,76,84,85,
+	132,134,151,152,159,164,172,173,289,300,309,310,311,
+		       317,328,329,335,336,341,349,350};
+    double intSolnV[] = {2.,1.,1.,1.,1.,1.,1.,1.,2.,1.,1.,1.,
+	2.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,
+	1.,1.,1.,1.,1.,1.,1.,1.,1.};
+    int vecLen = sizeof(intIndicesV)/sizeof(int);
+    intSoln.setVector(vecLen,intIndicesV,intSolnV);
+    expectedNumberColumns=353;
+  }
+
+  // seymour1
+  else if ( modelL == "seymour_1" ) {
+    probType=continuousWith0_1;
+    int intIndicesAt1[]=
+  {0,2,3,4,6,7,8,11,12,15,18,22,23,25,27,31,32,34,35,36,37,39,40,41,42,44,45,46,49,51,54,55,56,58,61,62,63,65,67,68,69,70,71,75,79,81,82,84,85,86,87,88,89,91,93,94,95,97,98,99,101,102,103,104,106,108,110,111,112,116,118,119,120,122,123,125,126,128,129,130,131,135,140,141,142,143,144,148,149,151,152,153,156,158,160,162,163,164,165,167,169,170,173,177,178,179,181,182,186,188,189,192,193,200,201,202,203,204,211,214,218,226,227,228,231,233,234,235,238,242,244,246,249,251,252,254,257,259,260,263,266,268,270,271,276,278,284,286,288,289,291,292,299,305,307,308,311,313,315,316,317,319,321,325,328,332,334,335,337,338,340,343,346,347,354,355,357,358,365,369,372,373,374,375,376,379,381,383,386,392,396,399,402,403,412,416,423,424,425,427,430,431,432,436,437,438,440,441,443,449,450,451,452};
+    int numIndices = sizeof(intIndicesAt1)/sizeof(int);
+    intSoln.setConstant(numIndices,intIndicesAt1,1.0);
+    probType=generalMip;
+    expectedNumberColumns=1372;
+  }
+
+  // check to see if the model parameter is 
+  // a known problem.
+  if ( probType != undefined && si.getNumCols() == expectedNumberColumns) {
+
+    // Specified model is a known problem
+    
+    numberColumns_ = si.getNumCols();
+
+    integerVariable_= new bool[numberColumns_];
+    knownSolution_=new double[numberColumns_];
+    //CoinFillN(integerVariable_, numberColumns_,0);
+    //CoinFillN(knownSolution_,numberColumns_,0.0);
+
+    if ( probType == pure0_1 ) {
+      
+      // mark all variables as integer
+      CoinFillN(integerVariable_,numberColumns_,true);
+      // set solution to 0.0 for all not mentioned
+      CoinFillN(knownSolution_,numberColumns_,0.0);
+
+      // mark column solution that have value 1
+      for ( i=0; i<intSoln.getNumElements(); i++ ) {
+        int col = intSoln.getIndices()[i];
+        knownSolution_[col] = intSoln.getElements()[i];
+        assert( knownSolution_[col]==1. );
+      }
+
+    }
+    else {
+      // Probtype is continuousWith0_1 or generalMip 
+      assert( probType==continuousWith0_1 || probType==generalMip );
+
+      OsiSolverInterface * siCopy = si.clone();
+      assert(siCopy->getMatrixByCol()->isEquivalent(*si.getMatrixByCol()));
+
+      // Loop once for each column looking for integer variables
+      for (i=0;i<numberColumns_;i++) {
+
+        // Is the this an integer variable?
+        if(siCopy->isInteger(i)) {
+
+          // integer variable found
+          integerVariable_[i]=true;
+
+    
+          // Determine optimal solution value for integer i
+          // from values saved in intSoln and probType.
+          double soln;
+          if ( probType==continuousWith0_1 ) {
+
+            // Since 0_1 problem, had better be binary
+            assert( siCopy->isBinary(i) );
+
+            // intSoln only contains integers with optimal value of 1
+            if ( intSoln.isExistingIndex(i) ) {
+              soln = 1.0;
+              assert( intSoln[i]==1. );
+            }
+            else {
+              soln = 0.0;
+            }
+
+          } else {
+            // intSoln only contains integers with nonzero optimal values
+            if ( intSoln.isExistingIndex(i) ) {
+              soln = intSoln[i];
+              assert( intSoln[i]>=1. );
+            }
+            else {
+              soln = 0.0;
+            }
+          }
+          
+          // Set bounds in copyied problem to fix variable to its solution     
+          siCopy->setColUpper(i,soln);
+          siCopy->setColLower(i,soln);
+          
+        }
+        else {
+          // this is not an integer variable
+          integerVariable_[i]=false;
+        }
+      }
+ 
+      // All integers have been fixed at optimal value.
+      // Now solve to get continuous values
+#if 0
+      assert( siCopy->getNumRows()==5);        
+      assert( siCopy->getNumCols()==8); 
+      int r,c;
+      for ( r=0; r<siCopy->getNumRows(); r++ ) {
+        std::cerr <<"rhs[" <<r <<"]=" <<(si.rhs())[r] <<" " <<(siCopy->rhs())[r] <<std::endl;
+      }
+      for ( c=0; c<siCopy->getNumCols(); c++ ) {
+        std::cerr <<"collower[" <<c <<"]=" <<(si.collower())[c] <<" " <<(siCopy->collower())[c] <<std::endl;
+        std::cerr <<"colupper[" <<c <<"]=" <<(si.colupper())[c] <<" " <<(siCopy->colupper())[c] <<std::endl;
+      }
+#endif
+      // make sure all slack basis
+      //CoinWarmStartBasis allSlack;
+      //siCopy->setWarmStart(&allSlack);
+      siCopy->setHintParam(OsiDoScale,false);
+      siCopy->initialSolve();
+#if 0
+      for ( c=0; c<siCopy->getNumCols(); c++ ) {
+        std::cerr <<"colsol[" <<c <<"]=" <<knownSolution_[c] <<" " <<(siCopy->colsol())[c] <<std::endl;
+      }
+      OsiRelFltEq eq;
+      assert( eq(siCopy->getObjValue(),3.2368421052632));
+#endif
+      assert (siCopy->isProvenOptimal());
+      knownValue_ = siCopy->getObjValue();
+      // Save column solution
+      CoinCopyN(siCopy->getColSolution(),numberColumns_,knownSolution_);
+
+      delete siCopy;
+    }
+  } else if (printActivationNotice) {
+    if (probType != undefined &&
+  	     si.getNumCols() != expectedNumberColumns) {
+      std::cout
+	<< std::endl
+	<< "  OsiRowCutDebugger::activate: expected " << expectedNumberColumns
+	<< " cols but see " << si.getNumCols() << "; cannot activate."
+	<< std::endl ;
+    } else {
+      std::cout
+	<< "  OsiRowCutDebugger::activate: unrecognised problem "
+	<< model << "; cannot activate." << std::endl ;
+    }
+  }
+ 
+  //if (integerVariable_!=NULL) si.rowCutDebugger_=this;
+
+  return (integerVariable_!=NULL);
+}
+
+/*
+  Activate a row cut debugger using a full solution array. It's up to the user
+  to get it correct. Returns true if the debugger is activated.
+
+  The solution array must be getNumCols() in length, but only the entries for
+  integer variables need to be correct.
+
+  keepContinuous defaults to false, but in some uses (nonlinear solvers, for
+  example) it's useful to keep the given values, as they reflect constraints
+  that are not present in the linear relaxation.
+*/
+bool 
+OsiRowCutDebugger::activate (const OsiSolverInterface &si,
+			     const double *solution,
+			     bool keepContinuous)
+{
+  // set true to get a debug message about activation
+  const bool printActivationNotice = false ;
+  int i ;
+  //get rid of any arrays
+  delete [] integerVariable_ ;
+  delete [] knownSolution_ ;
+  OsiSolverInterface *siCopy = si.clone() ;
+  numberColumns_ = siCopy->getNumCols() ;
+  integerVariable_ = new bool[numberColumns_] ;
+  knownSolution_ = new double[numberColumns_] ;
+  
+/*
+  Fix the integer variables from the supplied solution (making sure that the
+  values are integer).
+*/
+  for (i = 0 ; i < numberColumns_ ; i++) {
+    if (siCopy->isInteger(i)) {
+      integerVariable_[i] = true ;
+      double soln = floor(solution[i]+0.5) ;
+      siCopy->setColUpper(i,soln) ;
+      siCopy->setColLower(i,soln) ;
+    } else {
+      integerVariable_[i] = false ;
+    }
+  }
+/*
+  Solve the lp relaxation, then cache the primal solution and objective. If
+  we're preserving the values of the given continuous variables, we can't
+  trust the solver's calculation of the objective; it may well be using
+  different values for the continuous variables.
+*/
+  siCopy->setHintParam(OsiDoScale,false);
+  //siCopy->writeMps("bad.mps") ;
+  siCopy->initialSolve() ;
+  if (keepContinuous == false) {
+    if (siCopy->isProvenOptimal()) {
+      CoinCopyN(siCopy->getColSolution(),numberColumns_,knownSolution_) ;
+      knownValue_ = siCopy->getObjValue() ;
+      if (printActivationNotice) {
+	std::cout
+	  << std::endl << "OsiRowCutDebugger::activate: activated (opt), z = "
+	  << knownValue_ << std::endl ;
+      }
+    } else {
+      if (printActivationNotice) {
+	std::cout
+	  << std::endl
+	  << "OsiRowCutDebugger::activate: solution was not optimal; "
+	  << "cannot activate." << std::endl ;
+      }
+      delete [] integerVariable_ ;
+      delete [] knownSolution_ ;
+      integerVariable_ = NULL ;
+      knownSolution_ = NULL ;
+      knownValue_ = COIN_DBL_MAX ;
+    }
+  } else {
+    CoinCopyN(solution,numberColumns_,knownSolution_) ;
+    const double *c = siCopy->getObjCoefficients() ;
+    knownValue_ = 0.0 ;
+    for (int j = 0 ; j < numberColumns_ ; j++) {
+      knownValue_ += c[j]*solution[j] ;
+    }
+    knownValue_ = knownValue_*siCopy->getObjSense() ;
+    if (printActivationNotice) {
+      std::cout
+	<< std::endl
+	<< "OsiRowCutDebugger::activate: activated, z = " << knownValue_
+	<< std::endl ;
+    }
+  }
+  delete siCopy;
+  return (integerVariable_ != NULL) ;
+}
+
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiRowCutDebugger::OsiRowCutDebugger ()
+  :knownValue_(COIN_DBL_MAX),
+  numberColumns_(0),
+  integerVariable_(NULL),
+  knownSolution_(NULL)
+{
+  // nothing to do here
+}
+
+//-------------------------------------------------------------------
+// Alternate Constructor with model name
+//-------------------------------------------------------------------
+// Constructor with name of model
+OsiRowCutDebugger::OsiRowCutDebugger ( 
+        const OsiSolverInterface & si, 
+        const char * model)
+  :knownValue_(COIN_DBL_MAX),
+   numberColumns_(0),
+  integerVariable_(NULL),
+  knownSolution_(NULL)
+{
+  activate(si,model);
+}
+// Constructor with full solution (only integers need be correct)
+OsiRowCutDebugger::OsiRowCutDebugger (const OsiSolverInterface &si, 
+                                      const double *solution,
+				      bool enforceOptimality)
+  :knownValue_(COIN_DBL_MAX),
+   numberColumns_(0),
+  integerVariable_(NULL),
+  knownSolution_(NULL)
+{
+  activate(si,solution,enforceOptimality);
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiRowCutDebugger::OsiRowCutDebugger (const OsiRowCutDebugger & source)
+: knownValue_(COIN_DBL_MAX), numberColumns_(0), integerVariable_(NULL), knownSolution_(NULL)
+{  
+  // copy
+	if (source.active()) {
+		assert(source.integerVariable_ != NULL);
+		assert(source.knownSolution_ != NULL);
+		knownValue_ = source.knownValue_;
+		numberColumns_=source.numberColumns_;
+		integerVariable_=new bool[numberColumns_];
+		knownSolution_=new double[numberColumns_];
+		CoinCopyN(source.integerVariable_,  numberColumns_, integerVariable_ );
+		CoinCopyN(source.knownSolution_, numberColumns_, knownSolution_);
+	}
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiRowCutDebugger::~OsiRowCutDebugger ()
+{
+  // free memory
+  delete [] integerVariable_;
+  delete [] knownSolution_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiRowCutDebugger &
+OsiRowCutDebugger::operator=(const OsiRowCutDebugger& rhs)
+{
+  if (this != &rhs) {
+    delete [] integerVariable_;
+    delete [] knownSolution_;
+    knownValue_ = COIN_DBL_MAX;
+    // copy 
+    if (rhs.active()) {
+      assert(rhs.integerVariable_ != NULL);
+      assert(rhs.knownSolution_ != NULL);
+      knownValue_ = rhs.knownValue_;
+      numberColumns_ = rhs.numberColumns_;
+      integerVariable_ = new bool[numberColumns_];
+      knownSolution_ = new double[numberColumns_];
+      CoinCopyN(rhs.integerVariable_,numberColumns_,integerVariable_ );
+      CoinCopyN(rhs.knownSolution_,numberColumns_,knownSolution_);
+    }
+  }
+  return *this;
+}
+
+/*
+  Edit a solution after column changes (typically column deletion and/or
+  transposition due to preprocessing).
+
+  Given an array which translates current column indices to original column
+  indices, shrink the solution to match. The transform is irreversible
+  (in the sense that the debugger doesn't keep a record of the changes).
+*/
+void 
+OsiRowCutDebugger::redoSolution(int numberColumns,const int * originalColumns)
+{
+  const bool printRecalcMessage = false ;
+  assert (numberColumns<=numberColumns_);
+  if (numberColumns<numberColumns_) {
+    char * mark = new char[numberColumns_];
+    memset (mark,0,numberColumns_);
+    int i;
+    for (i=0;i<numberColumns;i++)
+      mark[originalColumns[i]]=1;
+    numberColumns=0;
+    for (i=0;i<numberColumns_;i++) {
+      if (mark[i]) {
+        integerVariable_[numberColumns]=integerVariable_[i];
+        knownSolution_[numberColumns++]=knownSolution_[i];
+      }
+    }
+    delete [] mark;
+    numberColumns_=numberColumns;
+    if (printRecalcMessage) {
+#     if 0
+      FILE * fp = fopen("xx.xx","wb");
+      assert (fp);
+      fwrite(&numberColumns,sizeof(int),1,fp);
+      fwrite(knownSolution_,sizeof(double),numberColumns,fp);
+      fclose(fp);
+      exit(0);
+#     endif
+      printf("debug solution - recalculated\n");
+    }
+  }
+}
diff --git a/cbits/coin/OsiRowCutDebugger.hpp b/cbits/coin/OsiRowCutDebugger.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiRowCutDebugger.hpp
@@ -0,0 +1,187 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiRowCutDebugger_H
+#define OsiRowCutDebugger_H
+
+/*! \file OsiRowCutDebugger.hpp
+
+  \brief Provides a facility to validate cut constraints to ensure that they
+  	 do not cut off a given solution.
+*/
+
+#include <string>
+
+#include "OsiCuts.hpp"
+#include "OsiSolverInterface.hpp"
+
+/*! \brief Validate cuts against a known solution
+
+  OsiRowCutDebugger provides a facility for validating cuts against a known
+  solution for a problem. The debugger knows an optimal solution for many of
+  the miplib3 problems. Check the source for
+  #activate(const OsiSolverInterface&,const char*)
+  in OsiRowCutDebugger.cpp for the full set of known problems.
+
+  A full solution vector can be supplied as a parameter with
+  (#activate(const OsiSolverInterface&,const double*,bool)).
+  Only the integer values need to be valid.
+  The default behaviour is to solve an lp relaxation with the integer
+  variables fixed to the specified values and use the optimal solution to fill
+  in the continuous variables in the solution.
+  The debugger can be instructed to preserve the continuous variables (useful
+  when debugging solvers where the linear relaxation doesn't capture all the
+  constraints).
+
+  Note that the solution must match the problem held in the solver interface.
+  If you want to use the row cut debugger on a problem after applying presolve
+  transformations, your solution must match the presolved problem. (But see
+  #redoSolution().)
+*/
+class OsiRowCutDebugger {
+  friend void OsiRowCutDebuggerUnitTest(const OsiSolverInterface * siP,    
+					const std::string & mpsDir);
+
+public:
+  
+  /*! @name Validate Row Cuts
+  
+    Check that the specified cuts do not cut off the known solution.
+  */
+  //@{
+  /*! \brief Check that the set of cuts does not cut off the solution known
+  	     to the debugger.
+
+    Check if any generated cuts cut off the solution known to the debugger!
+    If so then print offending cuts.  Return the number of invalid cuts.
+  */
+  virtual int validateCuts(const OsiCuts & cs, int first, int last) const;
+
+  /*! \brief Check that the cut does not cut off the solution known to the
+  	     debugger.
+  
+    Return true if cut is invalid
+  */
+  virtual bool invalidCut(const OsiRowCut & rowcut) const;
+
+  /*! \brief Returns true if the solution held in the solver is compatible
+  	     with the known solution.
+
+    More specifically, returns true if the known solution satisfies the column
+    bounds held in the solver.
+  */
+  bool onOptimalPath(const OsiSolverInterface &si) const;
+  //@}
+
+  /*! @name Activate the Debugger
+  
+    The debugger is considered to be active when it holds a known solution.
+  */
+  //@{
+  /*! \brief Activate a debugger using the name of a problem.
+
+    The debugger knows an optimal solution for most of miplib3. Check the
+    source code for the full list.  Returns true if the debugger is
+    successfully activated.
+  */
+  bool activate(const OsiSolverInterface &si, const char *model) ;
+
+  /*! \brief Activate a debugger using a full solution array.
+
+    The solution must have one entry for every variable, but only the entries
+    for integer values are used. By default the debugger will solve an lp
+    relaxation with the integer variables fixed and fill in values for the
+    continuous variables from this solution. If the debugger should preserve
+    the given values for the continuous variables, set \p keepContinuous to
+    \c true.
+
+    Returns true if debugger activates successfully.
+  */
+  bool activate(const OsiSolverInterface &si, const double* solution,
+  		bool keepContinuous = false) ;
+
+  /// Returns true if the debugger is active 
+  bool active() const;
+  //@}
+
+  /*! @name Query or Manipulate the Known Solution */
+  //@{
+  /// Return the known solution
+  inline const double * optimalSolution() const
+  { return knownSolution_;}
+
+  /// Return the number of columns in the known solution
+  inline int numberColumns() const { return (numberColumns_) ; }
+
+  /// Return the value of the objective for the known solution
+  inline double optimalValue() const { return knownValue_;}
+
+  /*! \brief Edit the known solution to reflect column changes
+
+    Given a translation array \p originalColumns[numberColumns] which can
+    translate current column indices to original column indices, this method
+    will edit the solution held in the debugger so that it matches the current
+    set of columns.
+
+    Useful when the original problem is preprocessed prior to cut generation.
+    The debugger does keep a record of the changes.
+  */
+  void redoSolution(int numberColumns, const int *originalColumns);
+
+  /// Print optimal solution (returns -1 bad debug, 0 on optimal, 1 not)
+  int printOptimalSolution(const OsiSolverInterface & si) const;
+  //@}
+
+  /**@name Constructors and Destructors */
+  //@{
+  /// Default constructor - no checking 
+  OsiRowCutDebugger ();
+
+  /*! \brief Constructor with name of model.
+
+    See #activate(const OsiSolverInterface&,const char*).
+  */
+  OsiRowCutDebugger(const OsiSolverInterface &si, const char *model) ;
+
+  /*! \brief Constructor with full solution.
+
+    See #activate(const OsiSolverInterface&,const double*,bool).
+  */
+  OsiRowCutDebugger(const OsiSolverInterface &si, const double *solution,
+  		    bool enforceOptimality = false) ;
+ 
+  /// Copy constructor 
+  OsiRowCutDebugger(const OsiRowCutDebugger &);
+
+  /// Assignment operator 
+  OsiRowCutDebugger& operator=(const OsiRowCutDebugger& rhs);
+  
+  /// Destructor 
+  virtual ~OsiRowCutDebugger ();
+  //@}
+      
+private:
+  
+  // Private member data
+
+  /**@name Private member data */
+  //@{
+  /// Value of known solution
+  double knownValue_;
+
+  /*! \brief Number of columns in known solution
+  
+    This must match the number of columns reported by the solver.
+  */
+  int numberColumns_;
+
+  /// array specifying integer variables
+  bool * integerVariable_;
+
+  /// array specifying known solution
+  double * knownSolution_;
+  //@}
+};
+  
+#endif
diff --git a/cbits/coin/OsiSolverBranch.cpp b/cbits/coin/OsiSolverBranch.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiSolverBranch.cpp
@@ -0,0 +1,423 @@
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#if defined(_MSC_VER)
+// Turn off compiler warning about long names
+#  pragma warning(disable:4786)
+#endif
+
+#include "CoinHelperFunctions.hpp"
+#include "CoinWarmStartBasis.hpp"
+
+#include "OsiConfig.h"
+#include "CoinFinite.hpp"
+
+#include "OsiSolverInterface.hpp"
+#include "OsiSolverBranch.hpp"
+#include <cassert>
+#include <cmath>
+#include <cfloat>
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiSolverBranch::OsiSolverBranch () :
+  indices_(NULL), 
+  bound_(NULL)
+{
+  memset(start_,0,sizeof(start_));
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiSolverBranch::OsiSolverBranch (const OsiSolverBranch & rhs) 
+{  
+  memcpy(start_,rhs.start_,sizeof(start_));
+  int size = start_[4];
+  if (size) {
+    indices_ = CoinCopyOfArray(rhs.indices_,size);
+    bound_ = CoinCopyOfArray(rhs.bound_,size);
+  } else {
+    indices_=NULL;
+    bound_=NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiSolverBranch::~OsiSolverBranch ()
+{
+  delete [] indices_;
+  delete [] bound_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiSolverBranch &
+OsiSolverBranch::operator=(const OsiSolverBranch& rhs)
+{
+  if (this != &rhs) {
+    delete [] indices_;
+    delete [] bound_;
+    memcpy(start_,rhs.start_,sizeof(start_));
+    int size = start_[4];
+    if (size) {
+      indices_ = CoinCopyOfArray(rhs.indices_,size);
+      bound_ = CoinCopyOfArray(rhs.bound_,size);
+    } else {
+      indices_=NULL;
+      bound_=NULL;
+    }
+  }
+  return *this;
+}
+
+//-----------------------------------------------------------------------------
+// add simple branch
+//-----------------------------------------------------------------------------
+
+void
+OsiSolverBranch::addBranch(int iColumn, double value)
+{
+  delete [] indices_;
+  delete [] bound_;
+  indices_ = new int[2];
+  bound_ = new double[2];
+  indices_[0]=iColumn;
+  indices_[1]=iColumn;
+  start_[0]=0;
+  start_[1]=0;
+  start_[2]=1;
+  bound_[0]=floor(value);
+  start_[3]=2;
+  bound_[1]=ceil(value);
+  start_[4]=2;
+  assert (bound_[0]!=bound_[1]);
+}
+//-----------------------------------------------------------------------------
+// Add bounds - way =-1 is first , +1 is second 
+//-----------------------------------------------------------------------------
+
+void
+OsiSolverBranch::addBranch(int way,int numberTighterLower, const int * whichLower, 
+                           const double * newLower,
+                           int numberTighterUpper, const int * whichUpper, const double * newUpper)
+{
+  assert (way==-1||way==1);
+  int numberNew = numberTighterLower+numberTighterUpper;
+  int base = way+1; // will be 0 or 2
+  int numberNow = start_[4-base]-start_[2-base];
+  int * tempI = new int[numberNow+numberNew];
+  double * tempD = new double[numberNow+numberNew];
+  int putNew = (way==-1) ? 0 : start_[2];
+  int putNow = (way==-1) ? numberNew : 0;
+  memcpy(tempI+putNow,indices_+start_[2-base],numberNow*sizeof(int));
+  memcpy(tempD+putNow,bound_+start_[2-base],numberNow*sizeof(double));
+  memcpy(tempI+putNew,whichLower,numberTighterLower*sizeof(int));
+  memcpy(tempD+putNew,newLower,numberTighterLower*sizeof(double));
+  putNew += numberTighterLower;
+  memcpy(tempI+putNew,whichUpper,numberTighterUpper*sizeof(int));
+  memcpy(tempD+putNew,newUpper,numberTighterUpper*sizeof(double));
+  delete [] indices_;
+  indices_ = tempI;
+  delete [] bound_;
+  bound_ = tempD;
+  int numberOldLower = start_[3-base]-start_[2-base];
+  int numberOldUpper = start_[4-base]-start_[3-base];
+  start_[0]=0;
+  if (way==-1) {
+    start_[1] = numberTighterLower;
+    start_[2] = start_[1] + numberTighterUpper;
+    start_[3] = start_[2] + numberOldLower;
+    start_[4] = start_[3] + numberOldUpper;
+  } else {
+    start_[1] = numberOldLower;
+    start_[2] = start_[1] + numberOldUpper;
+    start_[3] = start_[2] + numberTighterLower;
+    start_[4] = start_[3] + numberTighterUpper;
+  }
+}
+//-----------------------------------------------------------------------------
+// Add bounds - way =-1 is first , +1 is second 
+//-----------------------------------------------------------------------------
+
+void
+OsiSolverBranch::addBranch(int way,int numberColumns, const double * oldLower, 
+                           const double * newLower2,
+                           const double * oldUpper, const double * newUpper2)
+{
+  assert (way==-1||way==1);
+  // find
+  int i;
+  int * whichLower = new int[numberColumns];
+  double * newLower = new double[numberColumns];
+  int numberTighterLower=0;
+  for (i=0;i<numberColumns;i++) {
+    if (newLower2[i]>oldLower[i]) {
+      whichLower[numberTighterLower]=i;
+      newLower[numberTighterLower++]=newLower2[i];
+    }
+  }
+  int * whichUpper = new int[numberColumns];
+  double * newUpper = new double[numberColumns];
+  int numberTighterUpper=0;
+  for (i=0;i<numberColumns;i++) {
+    if (newUpper2[i]<oldUpper[i]) {
+      whichUpper[numberTighterUpper]=i;
+      newUpper[numberTighterUpper++]=newUpper2[i];
+    }
+  }
+  int numberNew = numberTighterLower+numberTighterUpper;
+  int base = way+1; // will be 0 or 2
+  int numberNow = start_[4-base]-start_[2-base];
+  int * tempI = new int[numberNow+numberNew];
+  double * tempD = new double[numberNow+numberNew];
+  int putNew = (way==-1) ? 0 : start_[2];
+  int putNow = (way==-1) ? numberNew : 0;
+  memcpy(tempI+putNow,indices_+start_[2-base],numberNow*sizeof(int));
+  memcpy(tempD+putNow,bound_+start_[2-base],numberNow*sizeof(double));
+  memcpy(tempI+putNew,whichLower,numberTighterLower*sizeof(int));
+  memcpy(tempD+putNew,newLower,numberTighterLower*sizeof(double));
+  putNew += numberTighterLower;
+  memcpy(tempI+putNew,whichUpper,numberTighterUpper*sizeof(int));
+  memcpy(tempD+putNew,newUpper,numberTighterUpper*sizeof(double));
+  delete [] indices_;
+  indices_ = tempI;
+  delete [] bound_;
+  bound_ = tempD;
+  int numberOldLower = start_[3-base]-start_[2-base];
+  int numberOldUpper = start_[4-base]-start_[3-base];
+  start_[0]=0;
+  if (way==-1) {
+    start_[1] = numberTighterLower;
+    start_[2] = start_[1] + numberTighterUpper;
+    start_[3] = start_[2] + numberOldLower;
+    start_[4] = start_[3] + numberOldUpper;
+  } else {
+    start_[1] = numberOldLower;
+    start_[2] = start_[1] + numberOldUpper;
+    start_[3] = start_[2] + numberTighterLower;
+    start_[4] = start_[3] + numberTighterUpper;
+  }
+  delete [] whichLower;
+  delete [] newLower;
+  delete [] whichUpper;
+  delete [] newUpper;
+}
+// Apply bounds
+void 
+OsiSolverBranch::applyBounds(OsiSolverInterface & solver,int way) const
+{
+  int base = way+1;
+  assert (way==-1||way==1);
+  int numberColumns = solver.getNumCols();
+  const double * columnLower = solver.getColLower();
+  int i;
+  for (i=start_[base];i<start_[base+1];i++) {
+    int iColumn = indices_[i];
+    if (iColumn<numberColumns) {
+      double value = CoinMax(bound_[i],columnLower[iColumn]);
+      solver.setColLower(iColumn,value);
+    } else {
+      int iRow = iColumn-numberColumns;
+      const double * rowLower = solver.getRowLower();
+      double value = CoinMax(bound_[i],rowLower[iRow]);
+      solver.setRowLower(iRow,value);
+    }
+  }
+  const double * columnUpper = solver.getColUpper();
+  for (i=start_[base+1];i<start_[base+2];i++) {
+    int iColumn = indices_[i];
+    if (iColumn<numberColumns) {
+      double value = CoinMin(bound_[i],columnUpper[iColumn]);
+      solver.setColUpper(iColumn,value);
+    } else {
+      int iRow = iColumn-numberColumns;
+      const double * rowUpper = solver.getRowUpper();
+      double value = CoinMin(bound_[i],rowUpper[iRow]);
+      solver.setRowUpper(iRow,value);
+    }
+  }
+}
+// Returns true if current solution satsifies one side of branch
+bool 
+OsiSolverBranch::feasibleOneWay(const OsiSolverInterface & solver) const
+{
+  bool feasible = false;
+  int numberColumns = solver.getNumCols();
+  const double * columnLower = solver.getColLower();
+  const double * columnUpper = solver.getColUpper();
+  const double * columnSolution = solver.getColSolution();
+  double primalTolerance;
+  solver.getDblParam(OsiPrimalTolerance,primalTolerance);
+  for (int base = 0; base<4; base +=2) {
+    feasible=true;
+    int i;
+    for (i=start_[base];i<start_[base+1];i++) {
+      int iColumn = indices_[i];
+      if (iColumn<numberColumns) {
+        double value = CoinMax(bound_[i],columnLower[iColumn]);
+        if (columnSolution[iColumn]<value-primalTolerance) {
+          feasible=false;
+          break;
+        }
+      } else {
+        abort(); // do later (other stuff messed up anyway - e.g. CBC)
+      }
+    }
+    if (!feasible)
+      break;
+    for (i=start_[base+1];i<start_[base+2];i++) {
+      int iColumn = indices_[i];
+      if (iColumn<numberColumns) {
+        double value = CoinMin(bound_[i],columnUpper[iColumn]);
+        if (columnSolution[iColumn]>value+primalTolerance) {
+          feasible=false;
+          break;
+        }
+      } else {
+        abort(); // do later (other stuff messed up anyway - e.g. CBC)
+      }
+    }
+    if (feasible)
+      break; // OK this way
+  }
+  return feasible;
+}
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiSolverResult::OsiSolverResult () :
+  objectiveValue_(COIN_DBL_MAX),
+  primalSolution_(NULL), 
+  dualSolution_(NULL)
+ {
+}
+
+//-------------------------------------------------------------------
+// Constructor from solver
+//-------------------------------------------------------------------
+OsiSolverResult::OsiSolverResult (const OsiSolverInterface & solver,const double * lowerBefore,
+                                  const double * upperBefore) :
+  objectiveValue_(COIN_DBL_MAX),
+  primalSolution_(NULL), 
+  dualSolution_(NULL)
+{
+  if (solver.isProvenOptimal()&&!solver.isDualObjectiveLimitReached()) {
+    objectiveValue_ = solver.getObjValue()*solver.getObjSense();
+    CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (solver.getWarmStart());
+    assert (basis);
+    basis_ = * basis;
+    delete basis;
+    int numberRows = basis_.getNumArtificial();
+    int numberColumns = basis_.getNumStructural();
+    assert (numberColumns==solver.getNumCols());
+    assert (numberRows==solver.getNumRows());
+    primalSolution_ = CoinCopyOfArray(solver.getColSolution(),numberColumns);
+    dualSolution_ = CoinCopyOfArray(solver.getRowPrice(),numberRows);
+    fixed_.addBranch(-1,numberColumns,lowerBefore,solver.getColLower(),
+                     upperBefore,solver.getColUpper());
+  }
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiSolverResult::OsiSolverResult (const OsiSolverResult & rhs) 
+{  
+  objectiveValue_ = rhs.objectiveValue_;
+  basis_ = rhs.basis_;
+  fixed_ = rhs.fixed_;
+  int numberRows = basis_.getNumArtificial();
+  int numberColumns = basis_.getNumStructural();
+  if (numberColumns) {
+    primalSolution_ = CoinCopyOfArray(rhs.primalSolution_,numberColumns);
+    dualSolution_ = CoinCopyOfArray(rhs.dualSolution_,numberRows);
+  } else {
+    primalSolution_=NULL;
+    dualSolution_=NULL;
+  }
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiSolverResult::~OsiSolverResult ()
+{
+  delete [] primalSolution_;
+  delete [] dualSolution_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiSolverResult &
+OsiSolverResult::operator=(const OsiSolverResult& rhs)
+{
+  if (this != &rhs) {
+    delete [] primalSolution_;
+    delete [] dualSolution_;
+    objectiveValue_ = rhs.objectiveValue_;
+    basis_ = rhs.basis_;
+    fixed_ = rhs.fixed_;
+    int numberRows = basis_.getNumArtificial();
+    int numberColumns = basis_.getNumStructural();
+    if (numberColumns) {
+      primalSolution_ = CoinCopyOfArray(rhs.primalSolution_,numberColumns);
+      dualSolution_ = CoinCopyOfArray(rhs.dualSolution_,numberRows);
+    } else {
+      primalSolution_=NULL;
+      dualSolution_=NULL;
+    }
+  }
+  return *this;
+}
+// Create result
+void 
+OsiSolverResult::createResult(const OsiSolverInterface & solver, const double * lowerBefore,
+                              const double * upperBefore)
+{
+  delete [] primalSolution_;
+  delete [] dualSolution_;
+  if (solver.isProvenOptimal()&&!solver.isDualObjectiveLimitReached()) {
+    objectiveValue_ = solver.getObjValue()*solver.getObjSense();
+    CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (solver.getWarmStart());
+    assert (basis);
+    basis_ = * basis;
+    int numberRows = basis_.getNumArtificial();
+    int numberColumns = basis_.getNumStructural();
+    assert (numberColumns==solver.getNumCols());
+    assert (numberRows==solver.getNumRows());
+    primalSolution_ = CoinCopyOfArray(solver.getColSolution(),numberColumns);
+    dualSolution_ = CoinCopyOfArray(solver.getRowPrice(),numberRows);
+    fixed_.addBranch(-1,numberColumns,lowerBefore,solver.getColLower(),
+                     upperBefore,solver.getColUpper());
+  } else {
+    // infeasible
+    objectiveValue_ = COIN_DBL_MAX;
+    basis_ = CoinWarmStartBasis();;
+    primalSolution_=NULL;
+    dualSolution_=NULL;
+  }
+}
+// Restore result
+void 
+OsiSolverResult::restoreResult(OsiSolverInterface & solver) const
+{
+  //solver.setObjValue(objectiveValue_)*solver.getObjSense();
+  solver.setWarmStart(&basis_);
+  solver.setColSolution(primalSolution_);
+  solver.setRowPrice(dualSolution_);
+  fixed_.applyBounds(solver,-1);
+}
diff --git a/cbits/coin/OsiSolverBranch.hpp b/cbits/coin/OsiSolverBranch.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiSolverBranch.hpp
@@ -0,0 +1,152 @@
+// Copyright (C) 2005, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiSolverBranch_H
+#define OsiSolverBranch_H
+
+class OsiSolverInterface;
+#include "CoinWarmStartBasis.hpp"
+
+//#############################################################################
+
+/** Solver Branch Class
+
+    This provides information on a branch as a set of tighter bounds on both ways
+*/
+
+class OsiSolverBranch  {
+  
+public:
+  ///@name Add and Get methods 
+  //@{
+  /// Add a simple branch (i.e. first sets ub of floor(value), second lb of ceil(value))
+  void addBranch(int iColumn, double value); 
+  
+  /// Add bounds - way =-1 is first , +1 is second 
+  void addBranch(int way,int numberTighterLower, const int * whichLower, const double * newLower,
+                 int numberTighterUpper, const int * whichUpper, const double * newUpper);
+  /// Add bounds - way =-1 is first , +1 is second 
+  void addBranch(int way,int numberColumns,const double * oldLower, const double * newLower,
+                 const double * oldUpper, const double * newUpper);
+  
+  /// Apply bounds
+  void applyBounds(OsiSolverInterface & solver,int way) const;
+  /// Returns true if current solution satsifies one side of branch
+  bool feasibleOneWay(const OsiSolverInterface & solver) const;
+  /// Starts
+  inline const int * starts() const
+  { return start_;}
+  /// Which variables
+  inline const int * which() const
+  { return indices_;}
+  /// Bounds
+  inline const double * bounds() const
+  { return bound_;}
+  //@}
+  
+  
+  ///@name Constructors and destructors
+  //@{
+  /// Default Constructor
+  OsiSolverBranch(); 
+  
+  /// Copy constructor 
+  OsiSolverBranch(const OsiSolverBranch & rhs);
+  
+  /// Assignment operator 
+  OsiSolverBranch & operator=(const OsiSolverBranch & rhs);
+  
+  /// Destructor 
+  ~OsiSolverBranch ();
+  
+  //@}
+  
+private:
+  ///@name Private member data 
+  //@{
+  /// Start of lower first, upper first, lower second, upper second
+  int start_[5];
+  /// Column numbers (if >= numberColumns treat as rows)
+  int * indices_;
+  /// New bounds
+  double * bound_;
+ //@}
+};
+//#############################################################################
+
+/** Solver Result Class
+
+    This provides information on a result as a set of tighter bounds on both ways
+*/
+
+class OsiSolverResult  {
+  
+public:
+  ///@name Add and Get methods 
+  //@{
+  /// Create result
+  void createResult(const OsiSolverInterface & solver,const double * lowerBefore,
+                    const double * upperBefore);
+  
+  /// Restore result
+  void restoreResult(OsiSolverInterface & solver) const;
+  
+  /// Get basis
+  inline const CoinWarmStartBasis & basis() const
+  { return basis_;}
+  
+  /// Objective value (as minimization)
+  inline double objectiveValue() const
+  { return objectiveValue_;}
+
+  /// Primal solution
+  inline const double * primalSolution() const
+  { return primalSolution_;}
+
+  /// Dual solution
+  inline const double * dualSolution() const
+  { return dualSolution_;}
+
+  /// Extra fixed
+  inline const OsiSolverBranch & fixed() const
+  { return fixed_;}
+  //@}
+  
+  
+  ///@name Constructors and destructors
+  //@{
+  /// Default Constructor
+  OsiSolverResult(); 
+  
+  /// Constructor from solver
+  OsiSolverResult(const OsiSolverInterface & solver,const double * lowerBefore,
+                  const double * upperBefore); 
+  
+  /// Copy constructor 
+  OsiSolverResult(const OsiSolverResult & rhs);
+  
+  /// Assignment operator 
+  OsiSolverResult & operator=(const OsiSolverResult & rhs);
+  
+  /// Destructor 
+  ~OsiSolverResult ();
+  
+  //@}
+  
+private:
+  ///@name Private member data 
+  //@{
+  /// Value of objective (if >= OsiSolverInterface::getInfinity() then infeasible) 
+  double objectiveValue_;
+  /// Warm start information
+  CoinWarmStartBasis basis_;
+  /// Primal solution (numberColumns)
+  double * primalSolution_;
+  /// Dual solution (numberRows)
+  double * dualSolution_;
+  /// Which extra variables have been fixed (only way==-1 counts)
+  OsiSolverBranch fixed_;
+ //@}
+};
+#endif
diff --git a/cbits/coin/OsiSolverInterface.cpp b/cbits/coin/OsiSolverInterface.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiSolverInterface.cpp
@@ -0,0 +1,2457 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#include <stddef.h>
+#include <iostream>
+
+#include "CoinPragma.hpp"
+#include "CoinHelperFunctions.hpp"
+#include "CoinMpsIO.hpp"
+#include "CoinMessage.hpp"
+#include "CoinWarmStart.hpp"
+#ifdef COIN_SNAPSHOT
+#include "CoinSnapshot.hpp"
+#endif
+
+#include "OsiSolverInterface.hpp"
+#ifdef CBC_NEXT_VERSION
+#include "OsiSolverBranch.hpp"
+#endif
+#include "OsiCuts.hpp"
+#include "OsiRowCut.hpp"
+#include "OsiColCut.hpp"
+#include "OsiRowCutDebugger.hpp"
+#include "OsiAuxInfo.hpp"
+#include "OsiBranchingObject.hpp"
+#include <cassert>
+#include "CoinFinite.hpp"
+#include "CoinBuild.hpp"
+#include "CoinModel.hpp"
+#include "CoinLpIO.hpp"
+//#############################################################################
+// Hotstart related methods (primarily used in strong branching)
+// It is assumed that only bounds (on vars/constraints) can change between
+// markHotStart() and unmarkHotStart()
+//#############################################################################
+
+void OsiSolverInterface::markHotStart()
+{
+  delete ws_;
+  ws_ = getWarmStart();
+}
+
+void OsiSolverInterface::solveFromHotStart()
+{
+  setWarmStart(ws_);
+  resolve();
+}
+
+void OsiSolverInterface::unmarkHotStart()
+{
+  delete ws_;
+  ws_ = NULL;
+}
+
+//#############################################################################
+// Get indices of solution vector which are integer variables presently at
+// fractional values
+//#############################################################################
+
+OsiVectorInt
+OsiSolverInterface::getFractionalIndices(const double etol) const
+{
+   const int colnum = getNumCols();
+   OsiVectorInt frac;
+   CoinAbsFltEq eq(etol);
+   for (int i = 0; i < colnum; ++i) {
+      if (isInteger(i)) {
+	 const double ci = getColSolution()[i];
+	 const double distanceFromInteger = ci - floor(ci + 0.5);
+	 if (! eq(distanceFromInteger, 0.0))
+	    frac.push_back(i);
+      }
+   }
+   return frac;
+}
+
+
+int OsiSolverInterface::getNumElements() const
+{
+  return getMatrixByRow()->getNumElements();
+}
+
+//#############################################################################
+// Methods for determining the type of column variable.
+// The method isContinuous() is presently implemented in the derived classes.
+// The methods below depend on isContinuous and the values
+// stored in the column bounds.
+//#############################################################################
+
+bool 
+OsiSolverInterface::isBinary(int colIndex) const
+{
+  if ( isContinuous(colIndex) ) return false; 
+  const double * cu = getColUpper();
+  const double * cl = getColLower();
+  if (
+    (cu[colIndex]== 1 || cu[colIndex]== 0) && 
+    (cl[colIndex]== 0 || cl[colIndex]==1)
+    ) return true;
+  else return false;
+}
+
+
+//#############################################################################
+// Method for getting a column solution that is guaranteed to be
+// between the column lower and upper bounds. 
+// 
+// This method is was introduced for Cgl. Osi developers can
+// improve performance for their favorite solvers by 
+// overriding this method and providing an implementation that caches
+// strictColSolution_.
+//#############################################################################
+
+const double * 
+OsiSolverInterface::getStrictColSolution()
+{
+  const double * colSolution = getColSolution();
+  const double * colLower = getColLower();
+  const double * colUpper = getColUpper();
+  const int numCols = getNumCols();
+
+  strictColSolution_.clear();
+  strictColSolution_.insert(strictColSolution_.end(),colSolution, colSolution+numCols);
+
+  for (int i=numCols-1; i> 0; --i){
+    if (colSolution[i] <= colUpper[i]){
+      if (colSolution[i] >= colLower[i]){
+	continue;
+      } else {
+	strictColSolution_[i] = colLower[i];
+      }
+    } else {
+      strictColSolution_[i] = colUpper[i];
+    }
+  }
+  return &strictColSolution_[0];
+}
+
+
+//-----------------------------------------------------------------------------
+bool 
+OsiSolverInterface::isInteger(int colIndex) const
+{
+   return !isContinuous(colIndex);
+}
+//-----------------------------------------------------------------------------
+/*
+  Return number of integer variables. OSI implementors really should replace
+  this one, it's generally trivial from within the OSI, but this is the only
+  safe way to do it generically.
+*/
+int
+OsiSolverInterface::getNumIntegers () const
+{
+  if (numberIntegers_>=0) {
+    // we already know
+    return numberIntegers_;
+  } else {
+    // work out
+    const int numCols = getNumCols() ;
+    int numIntegers = 0 ;
+    for (int i = 0 ; i < numCols ; ++i) {
+      if (!isContinuous(i)) {
+	numIntegers++ ;
+      }
+    }
+    return (numIntegers) ;
+  }
+}
+//-----------------------------------------------------------------------------
+bool 
+OsiSolverInterface::isIntegerNonBinary(int colIndex) const
+{
+  if ( isInteger(colIndex) && !isBinary(colIndex) )
+    return true; 
+  else return false;
+}
+//-----------------------------------------------------------------------------
+bool 
+OsiSolverInterface::isFreeBinary(int colIndex) const
+{
+  if ( isContinuous(colIndex) ) return false;
+  const double * cu = getColUpper();
+  const double * cl = getColLower();
+  if (
+    (cu[colIndex]== 1) &&
+    (cl[colIndex]== 0)
+    ) return true;
+  else return false;
+}
+/*  Return array of column length
+    0 - continuous
+    1 - binary (may get fixed later)
+    2 - general integer (may get fixed later)
+*/
+const char * 
+OsiSolverInterface::getColType(bool refresh) const
+{
+  if (!columnType_||refresh) {
+    const int numCols = getNumCols() ;
+    if (!columnType_)
+      columnType_ = new char [numCols];
+    const double * cu = getColUpper();
+    const double * cl = getColLower();
+    for (int i = 0 ; i < numCols ; ++i) {
+      if (!isContinuous(i)) {
+	if ((cu[i]== 1 || cu[i]== 0) && 
+	    (cl[i]== 0 || cl[i]==1))
+	  columnType_[i]=1;
+	else
+	  columnType_[i]=2;
+      } else {
+	columnType_[i]=0;
+      }
+    }
+  }
+  return columnType_;
+}
+
+/*
+###############################################################################
+
+  Built-in methods for problem modification
+
+  Some of these can surely be reimplemented more efficiently given knowledge of
+  the derived OsiXXX data structures, but we can't make assumptions here. For
+  others, it's less clear. Given standard vector data structures in the
+  underlying OsiXXX, likely the only possible gain is avoiding a method call.
+
+###############################################################################
+*/
+
+void
+OsiSolverInterface::setObjCoeffSet(const int* indexFirst,
+				  const int* indexLast,
+				  const double* coeffList)
+{
+   const std::ptrdiff_t cnt = indexLast - indexFirst;
+   for (std::ptrdiff_t i = 0; i < cnt; ++i) {
+      setObjCoeff(indexFirst[i], coeffList[i]);
+   }
+}
+//-----------------------------------------------------------------------------
+void
+OsiSolverInterface::setColSetBounds(const int* indexFirst,
+				    const int* indexLast,
+				    const double* boundList)
+{
+  while (indexFirst != indexLast) {
+    setColBounds(*indexFirst, boundList[0], boundList[1]);
+    ++indexFirst;
+    boundList += 2;
+  }
+}
+//-----------------------------------------------------------------------------
+void
+OsiSolverInterface::setRowSetBounds(const int* indexFirst,
+				    const int* indexLast,
+				    const double* boundList)
+{
+  while (indexFirst != indexLast) {
+    setRowBounds(*indexFirst, boundList[0], boundList[1]);
+    ++indexFirst;
+    boundList += 2;
+  }
+}
+//-----------------------------------------------------------------------------
+void
+OsiSolverInterface::setRowSetTypes(const int* indexFirst,
+				   const int* indexLast,
+				   const char* senseList,
+				   const double* rhsList,
+				   const double* rangeList)
+{
+  while (indexFirst != indexLast) {
+    setRowType(*indexFirst++, *senseList++, *rhsList++, *rangeList++);
+  }
+}
+//-----------------------------------------------------------------------------
+void
+OsiSolverInterface::setContinuous(const int* indices, int len)
+{
+  for (int i = 0; i < len; ++i) {
+    setContinuous(indices[i]);
+  }
+}
+//-----------------------------------------------------------------------------
+void
+OsiSolverInterface::setInteger(const int* indices, int len)
+{
+  for (int i = 0; i < len; ++i) {
+    setInteger(indices[i]);
+  }
+}
+//-----------------------------------------------------------------------------
+/* Set the objective coefficients for all columns
+    array [getNumCols()] is an array of values for the objective.
+    This defaults to a series of set operations and is here for speed.
+*/
+void OsiSolverInterface::setObjective(const double * array)
+{
+  int n=getNumCols();
+  for (int i=0;i<n;i++)
+    setObjCoeff(i,array[i]);
+}
+//-----------------------------------------------------------------------------
+/* Set the lower bounds for all columns
+    array [getNumCols()] is an array of values for the objective.
+    This defaults to a series of set operations and is here for speed.
+*/
+void OsiSolverInterface::setColLower(const double * array)
+{
+  int n=getNumCols();
+  for (int i=0;i<n;i++)
+    setColLower(i,array[i]);
+}
+//-----------------------------------------------------------------------------
+/* Set the upper bounds for all columns
+    array [getNumCols()] is an array of values for the objective.
+    This defaults to a series of set operations and is here for speed.
+*/
+void OsiSolverInterface::setColUpper(const double * array)
+{
+  int n=getNumCols();
+  for (int i=0;i<n;i++)
+    setColUpper(i,array[i]);
+}
+//-----------------------------------------------------------------------------
+/*
+  Add a named column. Less than efficient, because the underlying solver almost
+  surely generates an internal name when creating the column, which is then
+  replaced.
+*/
+void OsiSolverInterface::addCol(const CoinPackedVectorBase& vec,
+				const double collb, const double colub,
+				const double obj, std::string name)
+{
+  int ndx = getNumCols() ;
+  addCol(vec,collb,colub,obj) ;
+  setColName(ndx,name) ;
+}
+
+void OsiSolverInterface::addCol(int numberElements,
+				const int* rows, const double* elements,
+				const double collb, const double colub,
+				const double obj, std::string name)
+{
+  int ndx = getNumCols() ;
+  addCol(numberElements,rows,elements,collb,colub,obj) ;
+  setColName(ndx,name) ;
+}
+
+/* Convenience alias for addCol */
+void 
+OsiSolverInterface::addCol(int numberElements,
+			   const int* rows, const double* elements,
+			   const double collb, const double colub,   
+			   const double obj) 
+{
+  CoinPackedVector column(numberElements, rows, elements);
+  addCol(column,collb,colub,obj);
+}
+//-----------------------------------------------------------------------------
+/* Add a set of columns (primal variables) to the problem.
+   
+  Default implementation simply makes repeated calls to addCol().
+*/
+void
+OsiSolverInterface::addCols(const int numcols,
+			    const CoinPackedVectorBase* const* cols,
+			    const double* collb, const double* colub,   
+			    const double* obj)
+{
+  for (int i = 0; i < numcols; ++i) {
+    addCol(*cols[i], collb[i], colub[i], obj[i]);
+  }
+}
+
+void OsiSolverInterface::addCols(const int numcols, const int* columnStarts,
+				 const int* rows, const double* elements,
+				 const double* collb, const double* colub,   
+				 const double* obj)
+{
+  double infinity = getInfinity();
+  for (int i = 0; i < numcols; ++i) {
+    int start = columnStarts[i];
+    int number = columnStarts[i+1]-start;
+    assert (number>=0);
+    addCol(number, rows+start, elements+start, collb ? collb[i] : 0.0, 
+	   colub ? colub[i] : infinity, 
+	   obj ? obj[i] : 0.0);
+  }
+}
+//-----------------------------------------------------------------------------
+// Add columns from a build object
+void 
+OsiSolverInterface::addCols(const CoinBuild & buildObject)
+{
+  assert (buildObject.type()==1); // check correct
+  int number = buildObject.numberColumns();
+  if (number) {
+    CoinPackedVectorBase ** columns=
+      new CoinPackedVectorBase * [number];
+    int iColumn;
+    double * objective = new double [number];
+    double * lower = new double [number];
+    double * upper = new double [number];
+    for (iColumn=0;iColumn<number;iColumn++) {
+      const int * rows;
+      const double * elements;
+      int numberElements = buildObject.column(iColumn,lower[iColumn],
+                                              upper[iColumn],objective[iColumn],
+                                              rows,elements);
+      columns[iColumn] = 
+	new CoinPackedVector(numberElements,
+			     rows,elements);
+    }
+    addCols(number, columns, lower, upper,objective);
+    for (iColumn=0;iColumn<number;iColumn++) 
+      delete columns[iColumn];
+    delete [] columns;
+    delete [] objective;
+    delete [] lower;
+    delete [] upper;
+  }
+  return;
+}
+// Add columns from a model object
+int 
+OsiSolverInterface::addCols( CoinModel & modelObject)
+{
+  bool goodState=true;
+  if (modelObject.rowLowerArray()) {
+    // some row information exists
+    int numberRows2 = modelObject.numberRows();
+    const double * rowLower = modelObject.rowLowerArray();
+    const double * rowUpper = modelObject.rowUpperArray();
+    for (int i=0;i<numberRows2;i++) {
+      if (rowLower[i]!=-COIN_DBL_MAX) 
+        goodState=false;
+      if (rowUpper[i]!=COIN_DBL_MAX) 
+        goodState=false;
+    }
+  }
+  if (goodState) {
+    // can do addColumns
+    int numberErrors = 0;
+    // Set arrays for normal use
+    double * rowLower = modelObject.rowLowerArray();
+    double * rowUpper = modelObject.rowUpperArray();
+    double * columnLower = modelObject.columnLowerArray();
+    double * columnUpper = modelObject.columnUpperArray();
+    double * objective = modelObject.objectiveArray();
+    int * integerType = modelObject.integerTypeArray();
+    double * associated = modelObject.associatedArray();
+    // If strings then do copies
+    if (modelObject.stringsExist()) {
+      numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                 objective, integerType,associated);
+    }
+    CoinPackedMatrix matrix;
+    modelObject.createPackedMatrix(matrix,associated);
+    int numberColumns = getNumCols(); // save number of columns
+    int numberColumns2 = modelObject.numberColumns();
+    if (numberColumns2&&!numberErrors) {
+      // Clean up infinity
+      double infinity = getInfinity();
+      int iColumn;
+      for (iColumn=0;iColumn<numberColumns2;iColumn++) {
+	if (columnUpper[iColumn]>1.0e30)
+	  columnUpper[iColumn]=infinity;
+	if (columnLower[iColumn]<-1.0e30)
+	  columnLower[iColumn]=-infinity;
+      }
+      const int * row = matrix.getIndices();
+      const int * columnLength = matrix.getVectorLengths();
+      const CoinBigIndex * columnStart = matrix.getVectorStarts();
+      const double * element = matrix.getElements();
+      CoinPackedVectorBase ** columns=
+        new CoinPackedVectorBase * [numberColumns2];
+      assert (columnLower);
+      for (iColumn=0;iColumn<numberColumns2;iColumn++) {
+        int start = columnStart[iColumn];
+        columns[iColumn] = 
+          new CoinPackedVector(columnLength[iColumn],
+                               row+start,element+start);
+      }
+      addCols(numberColumns2, columns, columnLower, columnUpper,objective);
+      for (iColumn=0;iColumn<numberColumns2;iColumn++) 
+        delete columns[iColumn];
+      delete [] columns;
+      // Do integers if wanted
+      assert(integerType);
+      for (iColumn=0;iColumn<numberColumns2;iColumn++) {
+        if (integerType[iColumn])
+          setInteger(iColumn+numberColumns);
+      }
+    }
+    if (columnLower!=modelObject.columnLowerArray()) {
+      delete [] rowLower;
+      delete [] rowUpper;
+      delete [] columnLower;
+      delete [] columnUpper;
+      delete [] objective;
+      delete [] integerType;
+      delete [] associated;
+      //if (numberErrors)
+      //handler_->message(CLP_BAD_STRING_VALUES,messages_)
+      //  <<numberErrors
+      //  <<CoinMessageEol;
+    }
+    return numberErrors;
+  } else {
+    // not suitable for addColumns
+    //handler_->message(CLP_COMPLICATED_MODEL,messages_)
+    //<<modelObject.numberRows()
+    //<<modelObject.numberColumns()
+    //<<CoinMessageEol;
+    return -1;
+  }
+}
+//-----------------------------------------------------------------------------
+/*
+  Add a named row. Less than efficient, because the underlying solver almost
+  surely generates an internal name when creating the row, which is then
+  replaced.
+*/
+void OsiSolverInterface::addRow(const CoinPackedVectorBase& vec,
+				const double rowlb, const double rowub,
+				std::string name)
+{
+  int ndx = getNumRows() ;
+  addRow(vec,rowlb,rowub) ;
+  setRowName(ndx,name) ;
+}
+
+void OsiSolverInterface::addRow(const CoinPackedVectorBase& vec,
+				const char rowsen, const double rowrhs,
+				const double rowrng, std::string name)
+{
+  int ndx = getNumRows() ;
+  addRow(vec,rowsen,rowrhs,rowrng) ;
+  setRowName(ndx,name) ;
+}
+
+/* Convenience alias for addRow. */
+void 
+OsiSolverInterface::addRow(int numberElements,
+			   const int *columns, const double *elements,
+			   const double rowlb, const double rowub) 
+{
+  CoinPackedVector row(numberElements,columns,elements);
+  addRow(row,rowlb,rowub);
+}
+//-----------------------------------------------------------------------------
+/* Add a set of rows (constraints) to the problem.
+   
+  The default implementation simply makes repeated calls to addRow().
+*/
+void 
+OsiSolverInterface::addRows(const int numrows, const int* rowStarts,
+			    const int* columns, const double* elements,
+			    const double* rowlb, const double* rowub)
+{
+  double infinity = getInfinity();
+  for (int i = 0; i < numrows; ++i) {
+    int start = rowStarts[i];
+    int number = rowStarts[i+1]-start;
+    assert (number>=0);
+    addRow(number, columns+start, elements+start, rowlb ? rowlb[i] : -infinity, 
+	   rowub ? rowub[i] : infinity);
+  }
+}
+
+void
+OsiSolverInterface::addRows(const int numrows,
+			    const CoinPackedVectorBase* const* rows,
+			    const double* rowlb, const double* rowub)
+{
+  for (int i = 0; i < numrows; ++i) {
+    addRow(*rows[i], rowlb[i], rowub[i]);
+  }
+}
+
+void
+OsiSolverInterface::addRows(const int numrows,
+			    const CoinPackedVectorBase* const* rows,
+			    const char* rowsen, const double* rowrhs,   
+			    const double* rowrng)
+{
+  for (int i = 0; i < numrows; ++i) {
+    addRow(*rows[i], rowsen[i], rowrhs[i], rowrng[i]);
+  }
+}
+//-----------------------------------------------------------------------------
+void
+OsiSolverInterface::addRows(const CoinBuild & buildObject)
+{
+  int number = buildObject.numberRows();
+  if (number) {
+    CoinPackedVectorBase ** rows=
+      new CoinPackedVectorBase * [number];
+    int iRow;
+    double * lower = new double [number];
+    double * upper = new double [number];
+    for (iRow=0;iRow<number;iRow++) {
+      const int * columns;
+      const double * elements;
+      int numberElements = buildObject.row(iRow,lower[iRow],upper[iRow],
+                                           columns,elements);
+      rows[iRow] = 
+	new CoinPackedVector(numberElements,
+			     columns,elements);
+    }
+    addRows(number, rows, lower, upper);
+    for (iRow=0;iRow<number;iRow++) 
+      delete rows[iRow];
+    delete [] rows;
+    delete [] lower;
+    delete [] upper;
+  }
+}
+//-----------------------------------------------------------------------------
+int
+OsiSolverInterface::addRows( CoinModel & modelObject)
+{
+  bool goodState=true;
+  if (modelObject.columnLowerArray()) {
+    // some column information exists
+    int numberColumns2 = modelObject.numberColumns();
+    const double * columnLower = modelObject.columnLowerArray();
+    const double * columnUpper = modelObject.columnUpperArray();
+    const double * objective = modelObject.objectiveArray();
+    const int * integerType = modelObject.integerTypeArray();
+    for (int i=0;i<numberColumns2;i++) {
+      if (columnLower[i]!=0.0) 
+        goodState=false;
+      if (columnUpper[i]!=COIN_DBL_MAX) 
+        goodState=false;
+      if (objective[i]!=0.0) 
+        goodState=false;
+      if (integerType[i]!=0)
+        goodState=false;
+    }
+  }
+  if (goodState) {
+    // can do addRows
+    int numberErrors = 0;
+    // Set arrays for normal use
+    double * rowLower = modelObject.rowLowerArray();
+    double * rowUpper = modelObject.rowUpperArray();
+    double * columnLower = modelObject.columnLowerArray();
+    double * columnUpper = modelObject.columnUpperArray();
+    double * objective = modelObject.objectiveArray();
+    int * integerType = modelObject.integerTypeArray();
+    double * associated = modelObject.associatedArray();
+    // If strings then do copies
+    if (modelObject.stringsExist()) {
+      numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                 objective, integerType,associated);
+    }
+    CoinPackedMatrix matrix;
+    modelObject.createPackedMatrix(matrix,associated);
+    int numberRows2 = modelObject.numberRows();
+    if (numberRows2&&!numberErrors) {
+      // Clean up infinity
+      double infinity = getInfinity();
+      int iRow;
+      for (iRow=0;iRow<numberRows2;iRow++) {
+	if (rowUpper[iRow]>1.0e30)
+	  rowUpper[iRow]=infinity;
+	if (rowLower[iRow]<-1.0e30)
+	  rowLower[iRow]=-infinity;
+      }
+      // matrix by rows
+      matrix.reverseOrdering();
+      const int * column = matrix.getIndices();
+      const int * rowLength = matrix.getVectorLengths();
+      const CoinBigIndex * rowStart = matrix.getVectorStarts();
+      const double * element = matrix.getElements();
+      CoinPackedVectorBase ** rows=
+        new CoinPackedVectorBase * [numberRows2];
+      assert (rowLower);
+      for (iRow=0;iRow<numberRows2;iRow++) {
+        int start = rowStart[iRow];
+        rows[iRow] = 
+          new CoinPackedVector(rowLength[iRow],
+                               column+start,element+start);
+      }
+      addRows(numberRows2, rows, rowLower, rowUpper);
+      for (iRow=0;iRow<numberRows2;iRow++) 
+        delete rows[iRow];
+      delete [] rows;
+    }
+    if (rowLower!=modelObject.rowLowerArray()) {
+      delete [] rowLower;
+      delete [] rowUpper;
+      delete [] columnLower;
+      delete [] columnUpper;
+      delete [] objective;
+      delete [] integerType;
+      delete [] associated;
+      //if (numberErrors)
+      //handler_->message(CLP_BAD_STRING_VALUES,messages_)
+      //  <<numberErrors
+      //  <<CoinMessageEol;
+    }
+    return numberErrors;
+  } else {
+    // not suitable for addRows
+    //handler_->message(CLP_COMPLICATED_MODEL,messages_)
+    //<<modelObject.numberRows()
+    //<<modelObject.numberColumns()
+    //<<CoinMessageEol;
+    return -1;
+  }
+}
+/*  Strip off rows to get to this number of rows.
+    If solver wants it can restore a copy of "base" (continuous) model here
+*/
+void 
+OsiSolverInterface::restoreBaseModel(int numberRows)
+{
+  int currentNumberCuts = getNumRows()-numberRows;
+  int *which = new int[currentNumberCuts];
+  for (int i = 0 ; i < currentNumberCuts ; i++)
+    which[i] = i+numberRows;
+  deleteRows(currentNumberCuts,which);
+  delete [] which;
+}
+  
+// This loads a model from a coinModel object - returns number of errors
+int 
+OsiSolverInterface::loadFromCoinModel (  CoinModel & modelObject, bool keepSolution)
+{
+  int numberErrors = 0;
+  // Set arrays for normal use
+  double * rowLower = modelObject.rowLowerArray();
+  double * rowUpper = modelObject.rowUpperArray();
+  double * columnLower = modelObject.columnLowerArray();
+  double * columnUpper = modelObject.columnUpperArray();
+  double * objective = modelObject.objectiveArray();
+  int * integerType = modelObject.integerTypeArray();
+  double * associated = modelObject.associatedArray();
+  // If strings then do copies
+  if (modelObject.stringsExist()) {
+    numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
+                                            objective, integerType,associated);
+  }
+  CoinPackedMatrix matrix;
+  modelObject.createPackedMatrix(matrix,associated);
+  int numberRows = modelObject.numberRows();
+  int numberColumns = modelObject.numberColumns();
+  // Clean up infinity
+  double infinity = getInfinity();
+  int iColumn,iRow;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (columnUpper[iColumn]>1.0e30)
+      columnUpper[iColumn]=infinity;
+    if (columnLower[iColumn]<-1.0e30)
+      columnLower[iColumn]=-infinity;
+  }
+  for (iRow=0;iRow<numberRows;iRow++) {
+    if (rowUpper[iRow]>1.0e30)
+      rowUpper[iRow]=infinity;
+    if (rowLower[iRow]<-1.0e30)
+      rowLower[iRow]=-infinity;
+  }
+  CoinWarmStart * ws = getWarmStart();
+  bool restoreBasis = keepSolution && numberRows&&numberRows==getNumRows()&&
+    numberColumns==getNumCols();
+  loadProblem(matrix, 
+              columnLower, columnUpper, objective, rowLower, rowUpper);
+  setRowColNames(modelObject) ;
+  if (restoreBasis)
+    setWarmStart(ws);
+  delete ws;
+  // Do integers if wanted
+  assert(integerType);
+  for (int iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (integerType[iColumn])
+      setInteger(iColumn);
+  }
+  if (rowLower!=modelObject.rowLowerArray()||
+      columnLower!=modelObject.columnLowerArray()) {
+    delete [] rowLower;
+    delete [] rowUpper;
+    delete [] columnLower;
+    delete [] columnUpper;
+    delete [] objective;
+    delete [] integerType;
+    delete [] associated;
+    //if (numberErrors)
+    //  handler_->message(CLP_BAD_STRING_VALUES,messages_)
+    //    <<numberErrors
+    //    <<CoinMessageEol;
+  }
+  return numberErrors;
+}
+//-----------------------------------------------------------------------------
+
+//#############################################################################
+// Implement getObjValue in a simple way that the derived solver interfaces
+// can use if the choose.
+//#############################################################################
+double OsiSolverInterface::getObjValue() const
+{
+  int nc = getNumCols();
+  const double * objCoef = getObjCoefficients();
+  const double * colSol  = getColSolution();
+  double objOffset=0.0;
+  getDblParam(OsiObjOffset,objOffset);
+  
+  // Compute dot product of objCoef and colSol and then adjust by offset
+  // Jean-Sebastien pointed out this is overkill - lets just do it simply
+  //double retVal = CoinPackedVector(nc,objCoef).dotProduct(colSol)-objOffset;
+  double retVal = -objOffset;
+  for ( int i=0 ; i<nc ; i++ )
+    retVal += objCoef[i]*colSol[i];
+  return retVal;
+}
+
+//#############################################################################
+// Apply Cuts
+//#############################################################################
+
+OsiSolverInterface::ApplyCutsReturnCode
+OsiSolverInterface::applyCuts( const OsiCuts & cs, double effectivenessLb ) 
+{
+  OsiSolverInterface::ApplyCutsReturnCode retVal;
+  int i;
+
+  // Loop once for each column cut
+  for ( i=0; i<cs.sizeColCuts(); i ++ ) {
+    if ( cs.colCut(i).effectiveness() < effectivenessLb ) {
+      retVal.incrementIneffective();
+      continue;
+    }
+    if ( !cs.colCut(i).consistent() ) {
+      retVal.incrementInternallyInconsistent();
+      continue;
+    }
+    if ( !cs.colCut(i).consistent(*this) ) {
+      retVal.incrementExternallyInconsistent();
+      continue;
+    }
+    if ( cs.colCut(i).infeasible(*this) ) {
+      retVal.incrementInfeasible();
+      continue;
+    }
+    applyColCut( cs.colCut(i) );
+    retVal.incrementApplied();
+  }
+
+  // Loop once for each row cut
+  for ( i=0; i<cs.sizeRowCuts(); i ++ ) {
+    if ( cs.rowCut(i).effectiveness() < effectivenessLb ) {
+      retVal.incrementIneffective();
+      continue;
+    }
+    if ( !cs.rowCut(i).consistent() ) {
+      retVal.incrementInternallyInconsistent();
+      continue;
+    }
+    if ( !cs.rowCut(i).consistent(*this) ) {
+      retVal.incrementExternallyInconsistent();
+      continue;
+    }
+    if ( cs.rowCut(i).infeasible(*this) ) {
+      retVal.incrementInfeasible();
+      continue;
+    }
+    applyRowCut( cs.rowCut(i) );
+    retVal.incrementApplied();
+  }
+  
+  return retVal;
+}
+/* Apply a collection of row cuts which are all effective.
+   applyCuts seems to do one at a time which seems inefficient.
+   The default does slowly, but solvers can override.
+*/
+void 
+OsiSolverInterface::applyRowCuts(int numberCuts, const OsiRowCut * cuts)
+{
+  int i;
+  for (i=0;i<numberCuts;i++) {
+    applyRowCut(cuts[i]);
+  }
+}
+// And alternatively
+void 
+OsiSolverInterface::applyRowCuts(int numberCuts, const OsiRowCut ** cuts)
+{
+  int i;
+  for (i=0;i<numberCuts;i++) {
+    applyRowCut(*cuts[i]);
+  }
+}
+//#############################################################################
+// Set/Get Application Data
+// This is a pointer that the application can store into and retrieve
+// from the solverInterface.
+// This field is the application to optionally define and use.
+//#############################################################################
+
+void OsiSolverInterface::setApplicationData(void * appData)
+{
+  delete appDataEtc_;
+  appDataEtc_ = new OsiAuxInfo(appData);
+}
+//-----------------------------------------------------------------------------
+void * OsiSolverInterface::getApplicationData() const
+{
+  return appDataEtc_->getApplicationData();
+}
+void 
+OsiSolverInterface::setAuxiliaryInfo(OsiAuxInfo * auxiliaryInfo)
+{ 
+  delete appDataEtc_;
+  appDataEtc_ = auxiliaryInfo->clone();
+}
+// Get pointer to auxiliary info object
+OsiAuxInfo * 
+OsiSolverInterface::getAuxiliaryInfo() const
+{
+  return appDataEtc_;
+}
+
+//#############################################################################
+// Methods related to Row Cut Debuggers
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Activate Row Cut Debugger<br>
+// If the model name passed is on list of known models
+// then all cuts are checked to see that they do NOT cut
+// off the known optimal solution.  
+
+void OsiSolverInterface::activateRowCutDebugger (const char * modelName)
+{
+  delete rowCutDebugger_;
+  rowCutDebugger_=NULL; // so won't use in new
+  rowCutDebugger_ = new OsiRowCutDebugger(*this,modelName);
+}
+/* Activate debugger using full solution array.
+   Only integer values need to be correct.
+   Up to user to get it correct.
+*/
+void OsiSolverInterface::activateRowCutDebugger (const double * solution,
+						 bool keepContinuous)
+{
+  delete rowCutDebugger_;
+  rowCutDebugger_=NULL; // so won't use in new
+  rowCutDebugger_ = new OsiRowCutDebugger(*this,solution,keepContinuous);
+}
+//-------------------------------------------------------------------
+// Get Row Cut Debugger<br>
+// If there is a row cut debugger object associated with
+// model AND if the known optimal solution is within the
+// current feasible region then a pointer to the object is
+// returned which may be used to test validity of cuts.
+// Otherwise NULL is returned
+
+const OsiRowCutDebugger * OsiSolverInterface::getRowCutDebugger() const
+{
+  if (rowCutDebugger_&&rowCutDebugger_->onOptimalPath(*this)) {
+    return rowCutDebugger_;
+  } else {
+    return NULL;
+  }
+}
+// If you want to get debugger object even if not on optimal path then use this
+OsiRowCutDebugger * OsiSolverInterface::getRowCutDebuggerAlways() const
+{
+  if (rowCutDebugger_&&rowCutDebugger_->active()) {
+    return rowCutDebugger_;
+  } else {
+    return NULL;
+  }
+}
+
+//#############################################################################
+// Constructors / Destructor / Assignment
+//#############################################################################
+
+//-------------------------------------------------------------------
+// Default Constructor 
+//-------------------------------------------------------------------
+OsiSolverInterface::OsiSolverInterface () :
+  rowCutDebugger_(NULL),
+  handler_(NULL),
+  defaultHandler_(true),
+  columnType_(NULL),
+  appDataEtc_(NULL),
+  ws_(NULL)
+{
+  setInitialData();
+}
+// Set data for default constructor
+void 
+OsiSolverInterface::setInitialData()
+{
+  delete rowCutDebugger_;
+  rowCutDebugger_ = NULL;
+  delete ws_;
+  ws_ = NULL;
+  delete appDataEtc_;
+  appDataEtc_ = new OsiAuxInfo(); 
+  if (defaultHandler_) {
+    delete handler_;
+    handler_ = NULL;
+  }
+  defaultHandler_=true;
+  delete [] columnType_;
+  columnType_ = NULL;
+  intParam_[OsiMaxNumIteration] = 9999999;
+  intParam_[OsiMaxNumIterationHotStart] = 9999999;
+  intParam_[OsiNameDiscipline] = 0;
+
+  // Dual objective limit is acceptable `badness'; for minimisation, COIN_DBL_MAX
+  dblParam_[OsiDualObjectiveLimit] = COIN_DBL_MAX;
+  // Primal objective limit is desired `goodness'; for minimisation, -COIN_DBL_MAX
+  dblParam_[OsiPrimalObjectiveLimit] = -COIN_DBL_MAX;
+  dblParam_[OsiDualTolerance] = 1e-6;
+  dblParam_[OsiPrimalTolerance] = 1e-6;
+  dblParam_[OsiObjOffset] = 0.0;
+
+  strParam_[OsiProbName] = "OsiDefaultName";
+  strParam_[OsiSolverName] = "Unknown Solver";
+  handler_ = new CoinMessageHandler();
+  messages_ = CoinMessage();
+
+  // initialize all hints
+  int hint;
+  for (hint=OsiDoPresolveInInitial;hint<OsiLastHintParam;hint++) {
+    hintParam_[hint] = false;
+    hintStrength_[hint] = OsiHintIgnore;
+  }
+  // objects
+  numberObjects_=0;
+  numberIntegers_=-1;
+  object_=NULL;
+
+  // names
+  rowNames_ = OsiNameVec(0) ;
+  colNames_ = OsiNameVec(0) ;
+  objName_ = "" ;
+}
+
+//-------------------------------------------------------------------
+// Copy constructor 
+//-------------------------------------------------------------------
+OsiSolverInterface::OsiSolverInterface (const OsiSolverInterface & rhs) :
+  rowCutDebugger_(NULL),
+  ws_(NULL)
+{  
+  appDataEtc_ = rhs.appDataEtc_->clone();
+  if ( rhs.rowCutDebugger_!=NULL )
+    rowCutDebugger_ = new OsiRowCutDebugger(*rhs.rowCutDebugger_);
+  defaultHandler_ = rhs.defaultHandler_;
+  if (defaultHandler_) {
+    handler_ = new CoinMessageHandler(*rhs.handler_);
+  } else {
+    handler_ = rhs.handler_;
+  }
+  messages_ = CoinMessages(rhs.messages_);
+  CoinDisjointCopyN(rhs.intParam_, OsiLastIntParam, intParam_);
+  CoinDisjointCopyN(rhs.dblParam_, OsiLastDblParam, dblParam_);
+  CoinDisjointCopyN(rhs.strParam_, OsiLastStrParam, strParam_);
+  CoinDisjointCopyN(rhs.hintParam_, OsiLastHintParam, hintParam_);
+  CoinDisjointCopyN(rhs.hintStrength_, OsiLastHintParam, hintStrength_);
+  // objects
+  numberObjects_=rhs.numberObjects_;
+  numberIntegers_=rhs.numberIntegers_;
+  if (numberObjects_) {
+    object_ = new OsiObject * [numberObjects_];
+    for (int i=0;i<numberObjects_;i++) 
+      object_[i] = rhs.object_[i]->clone();
+  } else {
+    object_=NULL;
+  }
+  // names
+  rowNames_ = rhs.rowNames_ ;
+  colNames_ = rhs.colNames_ ;
+  objName_ = rhs.objName_ ;
+  // NULL as number of columns not known
+  columnType_ = NULL;
+}
+
+//-------------------------------------------------------------------
+// Destructor 
+//-------------------------------------------------------------------
+OsiSolverInterface::~OsiSolverInterface ()
+{
+  // delete debugger - should be safe as only ever returned const
+  delete rowCutDebugger_;
+  rowCutDebugger_ = NULL;
+  delete ws_;
+  ws_ = NULL;
+  delete appDataEtc_;
+  if (defaultHandler_) {
+    delete handler_;
+    handler_ = NULL;
+  }
+  for (int i=0;i<numberObjects_;i++) 
+    delete object_[i];
+  delete [] object_;
+  delete [] columnType_;
+}
+
+//----------------------------------------------------------------
+// Assignment operator 
+//-------------------------------------------------------------------
+OsiSolverInterface &
+OsiSolverInterface::operator=(const OsiSolverInterface& rhs)
+{
+  if (this != &rhs) {
+    delete appDataEtc_;
+    appDataEtc_ = rhs.appDataEtc_->clone();
+    delete rowCutDebugger_;
+    if ( rhs.rowCutDebugger_!=NULL )
+      rowCutDebugger_ = new OsiRowCutDebugger(*rhs.rowCutDebugger_);
+    else
+      rowCutDebugger_ = NULL;
+    CoinDisjointCopyN(rhs.intParam_, OsiLastIntParam, intParam_);
+    CoinDisjointCopyN(rhs.dblParam_, OsiLastDblParam, dblParam_);
+    CoinDisjointCopyN(rhs.strParam_, OsiLastStrParam, strParam_);
+    CoinDisjointCopyN(rhs.hintParam_, OsiLastHintParam, hintParam_);
+    CoinDisjointCopyN(rhs.hintStrength_, OsiLastHintParam, hintStrength_);
+    delete ws_;
+    ws_ = NULL;
+    if (defaultHandler_) {
+      delete handler_;
+      handler_ = NULL;
+    }
+    defaultHandler_ = rhs.defaultHandler_;
+    if (defaultHandler_) {
+      handler_ = new CoinMessageHandler(*rhs.handler_);
+    } else {
+      handler_ = rhs.handler_;
+    }
+    // objects
+    int i;
+    for (i=0;i<numberObjects_;i++) 
+      delete object_[i];
+    delete [] object_;
+    numberObjects_=rhs.numberObjects_;
+    numberIntegers_=rhs.numberIntegers_;
+    if (numberObjects_) {
+      object_ = new OsiObject * [numberObjects_];
+      for (i=0;i<numberObjects_;i++) 
+	object_[i] = rhs.object_[i]->clone();
+    } else {
+      object_=NULL;
+    }
+    // names
+    rowNames_ = rhs.rowNames_ ;
+    colNames_ = rhs.colNames_ ;
+    objName_ = rhs.objName_ ;
+    delete [] columnType_;
+    // NULL as number of columns not known
+    columnType_ = NULL;
+  }
+  return *this;
+}
+
+//-----------------------------------------------------------------------------
+// Read mps files
+//-----------------------------------------------------------------------------
+
+int OsiSolverInterface::readMps(const char * filename,
+    const char * extension)
+{
+  CoinMpsIO m;
+
+  int logLvl = handler_->logLevel() ;
+  if (logLvl > 1)
+  { m.messageHandler()->setLogLevel(handler_->logLevel()) ; }
+  else
+  { m.messageHandler()->setLogLevel(0) ; }
+  m.setInfinity(getInfinity());
+  
+  int numberErrors = m.readMps(filename,extension);
+  handler_->message(COIN_SOLVER_MPS,messages_)
+    <<m.getProblemName()<< numberErrors <<CoinMessageEol;
+  if (!numberErrors) {
+
+    // set objective function offest
+    setDblParam(OsiObjOffset,m.objectiveOffset());
+
+    // set problem name
+    setStrParam(OsiProbName,m.getProblemName());
+
+    // no errors --- load problem, set names and integrality
+    loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
+		m.getObjCoefficients(),m.getRowSense(),m.getRightHandSide(),
+		m.getRowRange());
+    setRowColNames(m) ;
+    const char * integer = m.integerColumns();
+    if (integer) {
+      int i,n=0;
+      int nCols=m.getNumCols();
+      int * index = new int [nCols];
+      for (i=0;i<nCols;i++) {
+	if (integer[i]) {
+	  index[n++]=i;
+	}
+      }
+      setInteger(index,n);
+      delete [] index;
+    }
+  }
+  return numberErrors;
+}
+/* Read a problem in GMPL format from the given filenames.
+   
+  Will only work if glpk installed
+*/
+int 
+OsiSolverInterface::readGMPL(const char *filename, const char * dataname)
+{
+  CoinMpsIO m;
+  m.setInfinity(getInfinity());
+  m.passInMessageHandler(handler_);
+
+  int numberErrors = m.readGMPL(filename,dataname,false);
+  handler_->message(COIN_SOLVER_MPS,messages_)
+    <<m.getProblemName()<< numberErrors <<CoinMessageEol;
+  if (!numberErrors) {
+
+    // set objective function offest
+    setDblParam(OsiObjOffset,m.objectiveOffset());
+
+    // set problem name
+    setStrParam(OsiProbName,m.getProblemName());
+
+    // no errors --- load problem, set names and integrality
+    loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
+		m.getObjCoefficients(),m.getRowSense(),m.getRightHandSide(),
+		m.getRowRange());
+    setRowColNames(m) ;
+    const char * integer = m.integerColumns();
+    if (integer) {
+      int i,n=0;
+      int nCols=m.getNumCols();
+      int * index = new int [nCols];
+      for (i=0;i<nCols;i++) {
+	if (integer[i]) {
+	  index[n++]=i;
+	}
+      }
+      setInteger(index,n);
+      delete [] index;
+    }
+  }
+  return numberErrors;
+}
+ /* Read a problem in MPS format from the given full filename.
+   
+This uses CoinMpsIO::readMps() to read
+the MPS file and returns the number of errors encountered.
+It also may return an array of set information
+*/
+int 
+OsiSolverInterface::readMps(const char *filename, const char*extension,
+			    int & numberSets, CoinSet ** & sets)
+{
+  CoinMpsIO m;
+  m.setInfinity(getInfinity());
+  
+  int numberErrors = m.readMps(filename,extension,numberSets,sets);
+  handler_->message(COIN_SOLVER_MPS,messages_)
+    <<m.getProblemName()<< numberErrors <<CoinMessageEol;
+  if (!numberErrors) {
+    // set objective function offset
+    setDblParam(OsiObjOffset,m.objectiveOffset());
+
+    // set problem name
+    setStrParam(OsiProbName,m.getProblemName());
+
+    // no errors --- load problem, set names and integrality
+    loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
+		m.getObjCoefficients(),m.getRowSense(),m.getRightHandSide(),
+		m.getRowRange());
+    setRowColNames(m) ;
+    const char * integer = m.integerColumns();
+    if (integer) {
+      int i,n=0;
+      int nCols=m.getNumCols();
+      int * index = new int [nCols];
+      for (i=0;i<nCols;i++) {
+	if (integer[i]) {
+	  index[n++]=i;
+	}
+      }
+      setInteger(index,n);
+      delete [] index;
+    }
+  }
+  return numberErrors;
+}
+
+int 
+OsiSolverInterface::writeMpsNative(const char *filename, 
+				   const char ** rowNames, 
+				   const char ** columnNames,
+				   int formatType,
+				   int numberAcross,
+				   double objSense,
+				   int numberSOS,
+				   const CoinSet * setInfo ) const
+{
+   const int numcols = getNumCols();
+   char* integrality = new char[numcols];
+   bool hasInteger = false;
+   for (int i = 0; i < numcols; ++i) {
+      if (isInteger(i)) {
+	 integrality[i] = 1;
+	 hasInteger = true;
+      } else {
+	 integrality[i] = 0;
+      }
+   }
+
+   // Get multiplier for objective function - default 1.0
+   double * objective = new double[numcols];
+   memcpy(objective,getObjCoefficients(),numcols*sizeof(double));
+   //if (objSense*getObjSense()<0.0) {
+   double locObjSense = (objSense == 0 ? 1 : objSense);
+   if(getObjSense() * locObjSense < 0.0) {
+     for (int i = 0; i < numcols; ++i) 
+       objective [i] = - objective[i];
+   }
+
+   CoinMpsIO writer;
+   writer.setInfinity(getInfinity());
+   writer.passInMessageHandler(handler_);
+   writer.setMpsData(*getMatrixByCol(), getInfinity(),
+		     getColLower(), getColUpper(),
+		     objective, hasInteger ? integrality : 0,
+		     getRowLower(), getRowUpper(),
+		     columnNames,rowNames);
+   double objOffset=0.0;
+   getDblParam(OsiObjOffset,objOffset);
+   writer.setObjectiveOffset(objOffset);
+   delete [] objective;
+   delete[] integrality;
+   return writer.writeMps(filename, 1 /*gzip it*/, formatType, numberAcross,
+			  NULL,numberSOS,setInfo);
+}
+/***********************************************************************/
+void OsiSolverInterface::writeLp(const char * filename,
+				 const char * extension,
+				  double epsilon,
+				  int numberAcross,
+				  int decimals,
+				  double objSense,
+				  bool useRowNames) const
+{
+  std::string f(filename);
+  std::string e(extension);
+  std::string fullname;
+  if (e!="") {
+    fullname = f + "." + e;
+  } else {
+    // no extension so no trailing period
+    fullname = f;
+  }
+
+	char** colnames;
+	char** rownames;
+  int nameDiscipline;
+  if (!getIntParam(OsiNameDiscipline,nameDiscipline))
+     nameDiscipline = 0;
+	if (useRowNames && nameDiscipline==2) {
+		colnames = new char*[getNumCols()];
+		rownames = new char*[getNumRows()+1];
+		for (int i = 0; i < getNumCols(); ++i)
+			colnames[i] = strdup(getColName(i).c_str());
+		for (int i = 0; i < getNumRows(); ++i)
+			rownames[i] = strdup(getRowName(i).c_str());
+		rownames[getNumRows()] = strdup(getObjName().c_str());
+	} else {
+		colnames = NULL;
+		rownames = NULL;
+	}
+
+  // Fall back on Osi version
+  OsiSolverInterface::writeLpNative(fullname.c_str(), 
+				    rownames, colnames, epsilon, numberAcross,
+				    decimals, objSense, useRowNames);
+
+	if (useRowNames && nameDiscipline==2) {
+		for (int i = 0; i < getNumCols(); ++i)
+			free(colnames[i]);
+		for (int i = 0; i < getNumRows()+1; ++i)
+			free(rownames[i]);
+		delete[] colnames;
+		delete[] rownames;
+	}
+}
+
+/*************************************************************************/
+void OsiSolverInterface::writeLp(FILE *fp,
+				  double epsilon,
+				  int numberAcross,
+				  int decimals,
+				  double objSense,
+				  bool useRowNames) const
+{
+	char** colnames;
+	char** rownames;
+  int nameDiscipline;
+  getIntParam(OsiNameDiscipline,nameDiscipline) ;
+	if (useRowNames && nameDiscipline==2) {
+		colnames = new char*[getNumCols()];
+		rownames = new char*[getNumRows()+1];
+		for (int i = 0; i < getNumCols(); ++i)
+			colnames[i] = strdup(getColName(i).c_str());
+		for (int i = 0; i < getNumRows(); ++i)
+			rownames[i] = strdup(getRowName(i).c_str());
+      rownames[getNumRows()] = strdup(getObjName().c_str());
+	} else {
+		colnames = NULL;
+		rownames = NULL;
+	}
+
+  // Fall back on Osi version
+  OsiSolverInterface::writeLpNative(fp, 
+				    rownames, colnames, epsilon, numberAcross,
+				    decimals, objSense, useRowNames);
+
+	if (useRowNames && nameDiscipline==2) {
+		for (int i = 0; i < getNumCols(); ++i)
+			free(colnames[i]);
+		for (int i = 0; i < getNumRows()+1; ++i)
+			free(rownames[i]);
+		delete[] colnames;
+		delete[] rownames;
+	}
+}
+
+/***********************************************************************/
+int
+OsiSolverInterface::writeLpNative(const char *filename,
+				  char const * const * const rowNames,
+				  char const * const * const columnNames,
+				  const double epsilon,
+			 	  const int numberAcross,
+				  const int decimals,
+				  const double objSense,
+				  const bool useRowNames) const
+{
+  FILE *fp = NULL;
+  fp = fopen(filename,"w");
+  if (!fp) {
+    printf("### ERROR: in OsiSolverInterface::writeLpNative(): unable to open file %s\n",
+	   filename);
+    exit(1);
+  }
+  int nerr = writeLpNative(fp,rowNames, columnNames,
+			   epsilon, numberAcross, decimals, 
+			   objSense, useRowNames);
+  fclose(fp);
+  return(nerr);
+}
+
+/***********************************************************************/
+int
+OsiSolverInterface::writeLpNative(FILE *fp,
+				  char const * const * const rowNames,
+				  char const * const * const columnNames,
+				  const double epsilon,
+				  const int numberAcross,
+				  const int decimals,
+				  const double objSense,
+				  const bool useRowNames) const
+{
+   const int numcols = getNumCols();
+   char *integrality = new char[numcols];
+   bool hasInteger = false;
+
+   for (int i=0; i<numcols; i++) {
+     if (isInteger(i)) {
+       integrality[i] = 1;
+       hasInteger = true;
+     } else {
+       integrality[i] = 0;
+     }
+   }
+
+   // Get multiplier for objective function - default 1.0
+   double *objective = new double[numcols];
+   const double *curr_obj = getObjCoefficients();
+
+   //if(getObjSense() * objSense < 0.0) {
+   double locObjSense = (objSense == 0 ? 1 : objSense);
+   if(getObjSense() * locObjSense < 0.0) {
+     for (int i=0; i<numcols; i++) {
+       objective[i] = - curr_obj[i];
+     }
+   }
+   else {
+     for (int i=0; i<numcols; i++) {
+       objective[i] = curr_obj[i];
+     }
+   }
+
+   CoinLpIO writer;
+   writer.setInfinity(getInfinity());
+   writer.setEpsilon(epsilon);
+   writer.setNumberAcross(numberAcross);
+   writer.setDecimals(decimals);
+
+   writer.setLpDataWithoutRowAndColNames(*getMatrixByRow(),
+		     getColLower(), getColUpper(),
+		     objective, hasInteger ? integrality : 0,
+		     getRowLower(), getRowUpper());
+
+   writer.setLpDataRowAndColNames(rowNames, columnNames);
+
+   //writer.print();
+   delete [] objective;
+   delete[] integrality;
+   return writer.writeLp(fp, epsilon, numberAcross, decimals, 
+			 useRowNames);
+
+} /*writeLpNative */
+
+/*************************************************************************/
+int OsiSolverInterface::readLp(const char * filename, const double epsilon) {
+  FILE *fp = fopen(filename, "r");
+
+  if(!fp) {
+    printf("### ERROR: OsiSolverInterface::readLp():  Unable to open file %s for reading\n",
+	   filename);
+    return(1);
+  }
+
+  int nerr = readLp(fp, epsilon);
+  fclose(fp);
+  return(nerr);
+}
+
+/*************************************************************************/
+int OsiSolverInterface::readLp(FILE *fp, const double epsilon) {
+  CoinLpIO m;
+  m.readLp(fp, epsilon);
+
+  // set objective function offest
+  setDblParam(OsiObjOffset, 0);
+
+  // set problem name
+  setStrParam(OsiProbName, m.getProblemName());
+
+  // no errors --- load problem, set names and integrality
+  loadProblem(*m.getMatrixByRow(), m.getColLower(), m.getColUpper(),
+	      m.getObjCoefficients(), m.getRowLower(), m.getRowUpper());
+  setRowColNames(m) ;
+  const char *integer = m.integerColumns();
+  if (integer) {
+    int i, n = 0;
+    int nCols = m.getNumCols();
+    int *index = new int [nCols];
+    for (i=0; i<nCols; i++) {
+      if (integer[i]) {
+	index[n++] = i;
+      }
+    }
+    setInteger(index, n);
+    delete [] index;
+  }
+  setObjSense(1);
+  return(0);
+} /* readLp */
+
+/*************************************************************************/
+
+// Pass in Message handler (not deleted at end)
+void 
+OsiSolverInterface::passInMessageHandler(CoinMessageHandler * handler)
+{
+  if (defaultHandler_) {
+    delete handler_;
+    handler_ = NULL;
+  }
+  defaultHandler_=false;
+  handler_=handler;
+}
+// Set language
+void 
+OsiSolverInterface::newLanguage(CoinMessages::Language language)
+{
+  messages_ = CoinMessage(language);
+}
+// Is the given primal objective limit reached?
+bool
+OsiSolverInterface::isPrimalObjectiveLimitReached() const
+{
+  double primalobjlimit;
+  if (getDblParam(OsiPrimalObjectiveLimit, primalobjlimit))
+    return getObjSense() * getObjValue() < getObjSense() * primalobjlimit;
+  else
+    return false;
+}
+// Is the given dual objective limit reached?
+bool
+OsiSolverInterface::isDualObjectiveLimitReached() const
+{
+  double dualobjlimit;
+  if (getDblParam(OsiDualObjectiveLimit, dualobjlimit))
+    return getObjSense() * getObjValue() > getObjSense() * dualobjlimit;
+  else
+    return false;
+}
+// copy all parameters in this section from one solver to another
+void 
+OsiSolverInterface::copyParameters(OsiSolverInterface & rhs)
+{
+  /*
+    We should think about this block of code. appData, rowCutDebugger,
+    and handler_ are not part of the standard parameter data. Arguably copy
+    actions for them belong in the base Osi.clone() or as separate methods.
+    -lh, 091021-
+  */
+  delete appDataEtc_;
+  appDataEtc_ = rhs.appDataEtc_->clone();
+  delete rowCutDebugger_;
+  if ( rhs.rowCutDebugger_!=NULL )
+    rowCutDebugger_ = new OsiRowCutDebugger(*rhs.rowCutDebugger_);
+  else
+    rowCutDebugger_ = NULL;
+  if (defaultHandler_) {
+    delete handler_;
+  }
+  /*
+    Is this correct? Shouldn't we clone a non-default handler instead of
+    simply assigning the pointer?  -lh, 091021-
+  */
+  defaultHandler_ = rhs.defaultHandler_;
+  if (defaultHandler_) {
+    handler_ = new CoinMessageHandler(*rhs.handler_);
+  } else {
+    handler_ = rhs.handler_;
+  }
+  CoinDisjointCopyN(rhs.intParam_, OsiLastIntParam, intParam_);
+  CoinDisjointCopyN(rhs.dblParam_, OsiLastDblParam, dblParam_);
+  CoinDisjointCopyN(rhs.strParam_, OsiLastStrParam, strParam_);
+  CoinDisjointCopyN(rhs.hintParam_, OsiLastHintParam, hintParam_);
+  CoinDisjointCopyN(rhs.hintStrength_, OsiLastHintParam, hintStrength_);
+}
+// Resets as if default constructor
+void 
+OsiSolverInterface::reset()
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "reset",
+		  "OsiSolverInterface");
+}
+/*Enables normal operation of subsequent functions.
+  This method is supposed to ensure that all typical things (like
+  reduced costs, etc.) are updated when individual pivots are executed
+  and can be queried by other methods.  says whether will be
+  doing primal or dual
+*/
+void 
+OsiSolverInterface::enableSimplexInterface(bool ) {}
+
+//Undo whatever setting changes the above method had to make
+void 
+OsiSolverInterface::disableSimplexInterface() {}
+/* Returns 1 if can just do getBInv etc
+   2 if has all OsiSimplex methods
+   and 0 if it has none */
+int 
+OsiSolverInterface::canDoSimplexInterface() const
+{
+  return 0;
+}
+
+/* Tells solver that calls to getBInv etc are about to take place.
+   Underlying code may need mutable as this may be called from 
+   CglCut:;generateCuts which is const.  If that is too horrific then
+   each solver e.g. BCP or CBC will have to do something outside
+   main loop.
+*/
+void 
+OsiSolverInterface::enableFactorization() const
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "enableFactorization",
+		  "OsiSolverInterface");
+}
+// and stop
+void 
+OsiSolverInterface::disableFactorization() const
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "disableFactorization",
+		  "OsiSolverInterface");
+}
+
+//Returns true if a basis is available
+bool 
+OsiSolverInterface::basisIsAvailable() const 
+{
+  return false;
+}
+
+/* (JJF ?date?) The following two methods may be replaced by the
+   methods of OsiSolverInterface using OsiWarmStartBasis if:
+   1. OsiWarmStartBasis resize operation is implemented
+   more efficiently and
+   2. It is ensured that effects on the solver are the same
+ 
+   (lh 100818)
+   1. CoinWarmStartBasis is the relevant resize, and John's right, it needs
+      to be reworked. The problem is that when new columns or rows are added,
+      the new space is initialised two bits at a time. It needs to be done
+      in bulk. There are other problems with CoinWarmStartBasis that should
+      be addressed at the same time.
+   2. setWarmStart followed by resolve should do it.
+*/
+void 
+OsiSolverInterface::getBasisStatus(int* , int* ) const 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "getBasisStatus",
+		  "OsiSolverInterface");
+}
+
+/* Set the status of structural/artificial variables and
+   factorize, update solution etc 
+   
+   NOTE  artificials are treated as +1 elements so for <= rhs
+   artificial will be at lower bound if constraint is tight
+*/
+int 
+OsiSolverInterface::setBasisStatus(const int* , const int* ) 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "setBasisStatus",
+		  "OsiSolverInterface");
+}
+
+/* Perform a pivot by substituting a colIn for colOut in the basis. 
+   The status of the leaving variable is given in statOut. Where
+   1 is to upper bound, -1 to lower bound
+*/
+int 
+OsiSolverInterface::pivot(int , int , int ) 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "pivot",
+		  "OsiSolverInterface");
+}
+
+/* Obtain a result of the primal pivot 
+   Outputs: colOut -- leaving column, outStatus -- its status,
+   t -- step size, and, if dx!=NULL, *dx -- primal ray direction.
+   Inputs: colIn -- entering column, sign -- direction of its change (+/-1).
+   Both for colIn and colOut, artificial variables are index by
+   the negative of the row index minus 1.
+   Return code (for now): 0 -- leaving variable found, 
+   -1 -- everything else?
+   Clearly, more informative set of return values is required 
+   Primal and dual solutions are updated
+*/
+int 
+OsiSolverInterface::primalPivotResult(int, int , 
+                                      int& , int& , 
+                                      double& , CoinPackedVector* )
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "primalPivotResult",
+		  "OsiSolverInterface");
+}
+
+/* Obtain a result of the dual pivot (similar to the previous method)
+   Differences: entering variable and a sign of its change are now
+   the outputs, the leaving variable and its statuts -- the inputs
+   If dx!=NULL, then *dx contains dual ray
+   Return code: same
+*/
+int 
+OsiSolverInterface::dualPivotResult(int& , int& , 
+                                    int , int , 
+                                    double& , CoinPackedVector* ) 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "dualPivotResult",
+		  "OsiSolverInterface");
+}
+
+//Get the reduced gradient for the cost vector c 
+void 
+OsiSolverInterface::getReducedGradient(double* , 
+                                       double * ,
+                                       const double * ) const
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "getReducedGradient",
+		  "OsiSolverInterface");
+}
+
+//Get a row of the tableau (slack part in slack if not NULL)
+void 
+OsiSolverInterface::getBInvARow(int , double* , double * ) const 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "getBInvARow",
+		  "OsiSolverInterface");
+}
+
+//Get a row of the basis inverse
+void OsiSolverInterface::getBInvRow(int , double* ) const 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "getBInvRow",
+		  "OsiSolverInterface");
+}
+
+//Get a column of the tableau
+void 
+OsiSolverInterface::getBInvACol(int , double* ) const 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "getBInvACol",
+		  "OsiSolverInterface");
+}
+
+//Get a column of the basis inverse
+void 
+OsiSolverInterface::getBInvCol(int , double* ) const 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "getBInvCol",
+		  "OsiSolverInterface");
+}
+/* Get warm start information.
+   Return warm start information for the current state of the solver
+   interface. If there is no valid warm start information, an empty warm
+   start object wil be returned.  This does not necessarily create an 
+   object - may just point to one.  must Delete set true if user
+   should delete returned object.
+   OsiClp version always returns pointer and false.
+*/
+CoinWarmStart* 
+OsiSolverInterface::getPointerToWarmStart(bool & mustDelete) 
+{
+  mustDelete = true;
+  return getWarmStart();
+}
+
+/* Get basic indices (order of indices corresponds to the
+   order of elements in a vector retured by getBInvACol() and
+   getBInvCol()).
+*/
+void 
+OsiSolverInterface::getBasics(int* ) const 
+{
+  // Throw an exception
+  throw CoinError("Needs coding for this interface", "getBasics",
+		  "OsiSolverInterface");
+}
+#ifdef COIN_SNAPSHOT
+// Fill in a CoinSnapshot
+CoinSnapshot *
+OsiSolverInterface::snapshot(bool createArrays) const
+{
+  CoinSnapshot * snap = new CoinSnapshot();
+  // scalars
+  snap->setObjSense(getObjSense());
+  snap->setInfinity(getInfinity());
+  snap->setObjValue(getObjValue());
+  double objOffset=0.0;
+  getDblParam(OsiObjOffset,objOffset);
+  snap->setObjOffset(objOffset);
+  snap->setDualTolerance(dblParam_[OsiDualTolerance]);
+  snap->setPrimalTolerance(dblParam_[OsiPrimalTolerance]);
+  snap->setIntegerTolerance(getIntegerTolerance());
+  snap->setIntegerUpperBound(dblParam_[OsiDualObjectiveLimit]);
+  if (createArrays) {
+    snap->loadProblem(*getMatrixByCol(),getColLower(),getColUpper(),
+		      getObjCoefficients(),getRowLower(),
+		      getRowUpper());
+    snap->createRightHandSide();
+    // Solution 
+    snap->setColSolution(getColSolution(),true);
+    snap->setRowPrice(getRowPrice(),true);
+    snap->setReducedCost(getReducedCost(),true);
+    snap->setRowActivity(getRowActivity(),true);
+  } else {
+    snap->setNumCols(getNumCols());
+    snap->setNumRows(getNumRows());
+    snap->setNumElements(getNumElements());
+    snap->setMatrixByCol(getMatrixByCol(),false);
+    snap->setColLower(getColLower(),false);
+    snap->setColUpper(getColUpper(),false);
+    snap->setObjCoefficients(getObjCoefficients(),false);
+    snap->setRowLower(getRowLower(),false);
+    snap->setRowUpper(getRowUpper(),false);
+    // Solution 
+    snap->setColSolution(getColSolution(),false);
+    snap->setRowPrice(getRowPrice(),false);
+    snap->setReducedCost(getReducedCost(),false);
+    snap->setRowActivity(getRowActivity(),false);
+  }
+  // If integer then create array (which snapshot has to own);
+  int numberColumns = getNumCols();
+  char * type = new char[numberColumns];
+  int numberIntegers=0;
+  for (int i=0;i<numberColumns;i++) {
+    if (isInteger(i)) {
+      numberIntegers++;
+      if (isBinary(i))
+	type[i]='B';
+      else
+	type[i]='I';
+    } else {
+      type[i]='C';
+    }
+  }
+  if (numberIntegers) 
+    snap->setColType(type,true);
+  else
+    snap->setNumIntegers(0);
+  delete [] type;
+  return snap;
+}
+#endif
+/* Identify integer variables and create corresponding objects.
+  
+   Record integer variables and create an OsiSimpleInteger object for each
+   one.  All existing OsiSimpleInteger objects will be destroyed.
+   New 
+*/
+void 
+OsiSolverInterface::findIntegers(bool justCount)
+{
+  numberIntegers_=0;
+  int numberColumns = getNumCols();
+  int iColumn;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    if (isInteger(iColumn)) 
+      numberIntegers_++;
+  }
+  if (justCount) {
+    assert (!numberObjects_);
+    assert (!object_);
+    return;
+  }
+  int numberIntegers=0;
+  int iObject;
+  for (iObject = 0;iObject<numberObjects_;iObject++) {
+    OsiSimpleInteger * obj =
+      dynamic_cast <OsiSimpleInteger *>(object_[iObject]) ;
+    if (obj) 
+      numberIntegers++;
+  }
+  // if same number return
+  if (numberIntegers_==numberIntegers)
+    return;
+  // space for integers
+  int * marked = new int[numberColumns];
+  for (iColumn=0;iColumn<numberColumns;iColumn++)
+    marked[iColumn]=-1;
+  // mark simple integers
+  OsiObject ** oldObject = object_;
+  int nObjects=numberObjects_;
+  for (iObject = 0;iObject<nObjects;iObject++) {
+    OsiSimpleInteger * obj =
+      dynamic_cast <OsiSimpleInteger *>(oldObject[iObject]) ;
+    if (obj) {
+      iColumn = obj->columnNumber();
+      assert (iColumn>=0&&iColumn<numberColumns);
+      marked[iColumn]=iObject;
+    }
+  }
+  // make a large enough array for new objects
+  numberObjects_ += numberIntegers_-numberIntegers;
+  if (numberObjects_)
+    object_ = new OsiObject * [numberObjects_];
+  else
+    object_=NULL;
+  /*
+    Walk the variables again, filling in the indices and creating objects for
+    the integer variables. Initially, the objects hold the index and upper &
+    lower bounds.
+  */
+  numberObjects_=0;
+  for (iColumn=0;iColumn<numberColumns;iColumn++) {
+    if(isInteger(iColumn)) {
+      iObject=marked[iColumn];
+      if (iObject>=0) 
+	object_[numberObjects_++] = oldObject[iObject];
+      else
+	object_[numberObjects_++] =
+	  new OsiSimpleInteger(this,iColumn);
+    }
+  }
+  // Now append other objects
+  for (iObject = 0;iObject<nObjects;iObject++) {
+    OsiSimpleInteger * obj =
+      dynamic_cast <OsiSimpleInteger *>(oldObject[iObject]) ;
+    if (!obj) 
+      object_[numberObjects_++] = oldObject[iObject];
+  }
+  // Delete old array (just array)
+  delete [] oldObject;
+  delete [] marked;
+}
+/* Identify integer variables and SOS and create corresponding objects.
+  
+      Record integer variables and create an OsiSimpleInteger object for each
+      one.  All existing OsiSimpleInteger objects will be destroyed.
+      If the solver supports SOS then do the same for SOS.
+
+      If justCount then no objects created and we just store numberIntegers_
+      Returns number of SOS
+*/
+int 
+OsiSolverInterface::findIntegersAndSOS(bool justCount)
+{
+  findIntegers(justCount);
+  return 0;
+}
+// Delete all object information
+void 
+OsiSolverInterface::deleteObjects()
+{
+  for (int i=0;i<numberObjects_;i++) 
+    delete object_[i];
+  delete [] object_;
+  object_=NULL;
+  numberObjects_=0;
+}
+
+/* Add in object information.
+  
+   Objects are cloned; the owner can delete the originals.
+*/
+void 
+OsiSolverInterface::addObjects(int numberObjects, OsiObject ** objects)
+{
+  // Create integers if first time
+  if (!numberObjects_)
+    findIntegers(false);
+  /* But if incoming objects inherit from simple integer we just want
+     to replace */
+  int numberColumns = getNumCols();
+  /** mark is -1 if not integer, >=0 if using existing simple integer and
+      >=numberColumns if using new integer */
+  int * mark = new int[numberColumns];
+  int i;
+  for (i=0;i<numberColumns;i++)
+    mark[i]=-1;
+  int newNumberObjects = numberObjects;
+  int newIntegers=0;
+  for (i=0;i<numberObjects;i++) { 
+    OsiSimpleInteger * obj =
+      dynamic_cast <OsiSimpleInteger *>(objects[i]) ;
+    if (obj) {
+      int iColumn = obj->columnNumber();
+      mark[iColumn]=i+numberColumns;
+      newIntegers++;
+    }
+  }
+  // and existing
+  for (i=0;i<numberObjects_;i++) { 
+    OsiSimpleInteger * obj =
+      dynamic_cast <OsiSimpleInteger *>(object_[i]) ;
+    if (obj) {
+      int iColumn = obj->columnNumber();
+      if (mark[iColumn]<0) {
+        newIntegers++;
+        newNumberObjects++;
+        mark[iColumn]=i;
+      } else {
+	// But delete existing
+	delete object_[i];
+	object_[i]=NULL;
+      }
+    } else {
+      newNumberObjects++;
+    }
+  } 
+  numberIntegers_ = newIntegers;
+  OsiObject ** temp  = new OsiObject * [newNumberObjects];
+  // Put integers first
+  newIntegers=0;
+  numberIntegers_=0;
+  for (i=0;i<numberColumns;i++) {
+    int which = mark[i];
+    if (which>=0) {
+      if (!isInteger(i)) {
+        newIntegers++;
+        setInteger(i);
+      }
+      if (which<numberColumns) {
+        temp[numberIntegers_]=object_[which];
+      } else {
+        temp[numberIntegers_]=objects[which-numberColumns]->clone();
+      }
+      numberIntegers_++;
+    }
+  }
+  int n=numberIntegers_;
+  // Now rest of old
+  for (i=0;i<numberObjects_;i++) { 
+    if (object_[i]) {
+      OsiSimpleInteger * obj =
+        dynamic_cast <OsiSimpleInteger *>(object_[i]) ;
+      if (!obj) {
+        temp[n++]=object_[i];
+      }
+    }
+  }
+  // and rest of new
+  for (i=0;i<numberObjects;i++) { 
+    OsiSimpleInteger * obj =
+      dynamic_cast <OsiSimpleInteger *>(objects[i]) ;
+    if (!obj) {
+      temp[n++]=objects[i]->clone();
+    }
+  }
+  delete [] mark;
+  delete [] object_;
+  object_ = temp;
+  numberObjects_ = newNumberObjects;
+}
+// Deletes branching information before columns deleted
+void 
+OsiSolverInterface::deleteBranchingInfo(int numberDeleted, const int * which)
+{
+  if (numberObjects_) {
+    int numberColumns = getNumCols();
+    // mark is -1 if deleted and new number if not deleted 
+    int * mark = new int[numberColumns];
+    int i;
+    int iColumn;
+    for (i=0;i<numberColumns;i++)
+      mark[i]=0;
+    for (i=0;i<numberDeleted;i++) {
+      iColumn = which[i];
+      if (iColumn>=0&&iColumn<numberColumns)
+	mark[iColumn]=-1;
+    }
+    iColumn = 0;
+    for (i=0;i<numberColumns;i++) {
+      if (mark[i]>=0) {
+	mark[i]=iColumn;
+	iColumn++;
+      }
+    }
+    int oldNumberObjects = numberObjects_;
+    numberIntegers_=0;
+    numberObjects_=0;
+    for (i=0;i<oldNumberObjects;i++) { 
+      OsiSimpleInteger * obj =
+	dynamic_cast <OsiSimpleInteger *>(object_[i]) ;
+      if (obj) {
+	iColumn = obj->columnNumber();
+	int jColumn = mark[iColumn];
+	if (jColumn>=0) {
+	  obj->setColumnNumber(jColumn);
+	  object_[numberObjects_++]=obj;
+	  numberIntegers_++;
+	} else {
+	  delete obj;
+	}
+      } else {
+	// not integer - all I know about is SOS
+	OsiSOS * obj =
+	  dynamic_cast <OsiSOS *>(object_[i]) ;
+	if (obj) {
+	  int oldNumberMembers=obj->numberMembers();
+	  int numberMembers=0;
+	  double * weight = obj->mutableWeights();
+	  int * members = obj->mutableMembers();
+	  for (int k=0;k<oldNumberMembers;k++) {
+	    iColumn = members[k];
+	    int jColumn = mark[iColumn];
+	    if (jColumn>=0) {
+	      members[numberMembers]=jColumn;
+	      weight[numberMembers++]=weight[k];
+	    }
+	  }
+	  if (numberMembers) {
+	    obj->setNumberMembers(numberMembers);
+	    object_[numberObjects_++]=obj;
+	  }
+	}
+      }
+    }
+    delete [] mark;
+  } else {
+    findIntegers(false);
+  }
+}
+/* Use current solution to set bounds so current integer feasible solution will stay feasible.
+   Only feasible bounds will be used, even if current solution outside bounds.  The amount of
+   such violation will be returned (and if small can be ignored)
+*/
+double 
+OsiSolverInterface::forceFeasible()
+{
+  /*
+    Run through the objects and use feasibleRegion() to set variable bounds
+    so as to fix the variables specified in the objects at their value in this
+    solution. Since the object list contains (at least) one object for every
+    integer variable, this has the effect of fixing all integer variables.
+  */
+  int i;
+  // Can't guarantee has matrix
+  const OsiBranchingInformation info(this,false,false);
+  double infeasibility=0.0;
+  for (i=0;i<numberObjects_;i++)
+    infeasibility += object_[i]->feasibleRegion(this,&info);
+  return infeasibility;
+}
+/* 
+   For variables currently at bound, fix at bound if reduced cost >= gap
+   Returns number fixed
+*/
+int 
+OsiSolverInterface::reducedCostFix(double gap, bool justInteger)
+{
+  double direction = getObjSense() ;
+  double tolerance;
+  getDblParam(OsiPrimalTolerance,tolerance) ;
+  if (gap<=0.0)
+    return 0;
+
+  const double *lower = getColLower() ;
+  const double *upper = getColUpper() ;
+  const double *solution = getColSolution() ;
+  const double *reducedCost = getReducedCost() ;
+
+  int numberFixed = 0 ;
+  int numberColumns = getNumCols();
+
+  for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) {
+    if (isInteger(iColumn)||!justInteger) {
+      double djValue = direction*reducedCost[iColumn] ;
+      if (upper[iColumn]-lower[iColumn] > tolerance) {
+	if (solution[iColumn] < lower[iColumn]+tolerance && djValue > gap) {
+	  setColUpper(iColumn,lower[iColumn]) ;
+	  numberFixed++ ; 
+	} else if (solution[iColumn] > upper[iColumn]-tolerance && -djValue > gap) {
+	  setColLower(iColumn,upper[iColumn]) ;
+	  numberFixed++ ;
+	}
+      }
+    }
+  }
+  
+  return numberFixed;
+}
+#ifdef COIN_FACTORIZATION_INFO
+// Return number of entries in L part of current factorization
+CoinBigIndex 
+OsiSolverInterface::getSizeL() const
+{
+  return -1;
+}
+// Return number of entries in U part of current factorization
+CoinBigIndex 
+OsiSolverInterface::getSizeU() const
+{
+  return -1;
+}
+#endif
+#ifdef CBC_NEXT_VERSION
+/*
+  Solve 2**N (N==depth) problems and return solutions and bases.
+  There are N branches each of which changes bounds on both sides
+  as given by branch.  The user should provide an array of (empty)
+  results which will be filled in.  See OsiSolveResult for more details
+  (in OsiSolveBranch.?pp) but it will include a basis and primal solution.
+  
+  The order of results is left to right at feasible leaf nodes so first one
+  is down, down, .....
+  
+  Returns number of feasible leaves.  Also sets number of solves done and number
+  of iterations.
+  
+  This is provided so a solver can do faster.
+  
+  If forceBranch true then branch done even if satisfied
+*/
+int 
+OsiSolverInterface::solveBranches(int depth,const OsiSolverBranch * branch,
+                                  OsiSolverResult * result,
+                                  int & numberSolves, int & numberIterations,
+                                  bool forceBranch)
+{
+  int * stack = new int [depth];
+  CoinWarmStart ** basis = new CoinWarmStart * [depth];
+  int iDepth;
+  for (iDepth=0;iDepth<depth;iDepth++) {
+    stack[iDepth]=-1;
+    basis[iDepth]=NULL;
+  }
+  //#define PRINTALL
+#ifdef PRINTALL
+  int seq[10];
+  double val[10];
+  assert (iDepth<=10);
+  for (iDepth=0;iDepth<depth;iDepth++) {
+    assert (branch[iDepth].starts()[4]==2);
+    assert (branch[iDepth].which()[0]==branch[iDepth].which()[1]);
+    assert (branch[iDepth].bounds()[0]==branch[iDepth].bounds()[1]-1.0);
+    seq[iDepth]=branch[iDepth].which()[0];
+    val[iDepth]=branch[iDepth].bounds()[0];
+    printf("depth %d seq %d nominal value %g\n",iDepth,seq[iDepth],val[iDepth]+0.5);
+  }
+#endif  
+  int numberColumns = getNumCols();
+  double * lowerBefore = CoinCopyOfArray(getColLower(),numberColumns);
+  double * upperBefore = CoinCopyOfArray(getColUpper(),numberColumns);
+  iDepth=0;
+  int numberFeasible=0;
+  bool finished=false;
+  bool backTrack=false;
+  bool iterated=false;
+  numberIterations=0;
+  numberSolves=0;
+  int nFeas=0;
+  while (!finished) {
+    bool feasible = true;
+    if (stack[iDepth]==-1) {
+      delete basis[iDepth];
+      basis[iDepth]=getWarmStart();
+    } else {
+      setWarmStart(basis[iDepth]);
+    }
+    // may be a faster way
+    setColLower(lowerBefore);
+    setColUpper(upperBefore);
+    for (int i=0;i<iDepth;i++) {
+      // skip if values feasible and not forceBranch
+      if (stack[i])
+        branch[i].applyBounds(*this,stack[i]);
+    }
+    bool doBranch = true;
+    if (!forceBranch&&!backTrack) {
+      // see if feasible on one side
+      if (!branch[iDepth].feasibleOneWay(*this)) {
+        branch[iDepth].applyBounds(*this,stack[iDepth]);
+      } else {
+        doBranch=false;
+        stack[iDepth]=0;
+      }
+    } else {
+      branch[iDepth].applyBounds(*this,stack[iDepth]);
+    }
+    if (doBranch) {
+      resolve();
+      numberIterations += getIterationCount();
+      numberSolves++;
+      iterated=true;
+      if (!isProvenOptimal()||isDualObjectiveLimitReached()) {
+        feasible=false;
+#ifdef PRINTALL
+        const double * columnLower = getColLower();
+        const double * columnUpper = getColUpper();
+        const double * columnSolution = getColSolution();
+        printf("infeas depth %d ",iDepth);
+        for (int jDepth=0;jDepth<=iDepth;jDepth++) {
+          int iColumn=seq[jDepth];
+          printf(" (%d %g, %g, %g (nom %g))",iColumn,columnLower[iColumn],
+                 columnSolution[iColumn],columnUpper[iColumn],val[jDepth]+0.5);
+        }
+        printf("\n");
+#endif
+      }
+    } else {
+      // must be feasible
+      nFeas++;
+#ifdef PRINTALL
+      const double * columnLower = getColLower();
+      const double * columnUpper = getColUpper();
+      const double * columnSolution = getColSolution();
+      printf("feas depth %d ",iDepth);
+      int iColumn=seq[iDepth];
+      printf(" (%d %g, %g, %g (nom %g))",iColumn,columnLower[iColumn],
+             columnSolution[iColumn],columnUpper[iColumn],val[iDepth]+0.5);
+      printf("\n");
+#endif
+    }
+    backTrack=false;
+    iDepth++;
+    if (iDepth==depth||!feasible) {
+      if (feasible&&iterated) {
+        result[numberFeasible++]=OsiSolverResult(*this,lowerBefore,upperBefore);
+#ifdef PRINTALL
+        const double * columnLower = getColLower();
+        const double * columnUpper = getColUpper();
+        const double * columnSolution = getColSolution();
+        printf("sol obj %g",getObjValue());
+        for (int jDepth=0;jDepth<depth;jDepth++) {
+          int iColumn=seq[jDepth];
+          printf(" (%d %g, %g, %g (nom %g))",iColumn,columnLower[iColumn],
+                 columnSolution[iColumn],columnUpper[iColumn],val[jDepth]+0.5);
+        }
+        printf("\n");
+#endif
+      }
+      // on to next
+      iDepth--;
+      iterated=false;
+      backTrack=true;
+      while (stack[iDepth]>=0) {
+        if (iDepth==0) {
+          // finished
+          finished=true;
+          break;
+        }
+        stack[iDepth]=-1;
+        iDepth--;
+      }
+      if (!finished) {
+        stack[iDepth]=1;
+      }
+    }
+  }
+  delete [] stack;
+  for (iDepth=0;iDepth<depth;iDepth++)
+    delete basis[iDepth];
+  delete [] basis;
+  // restore bounds
+  setColLower(lowerBefore);
+  setColUpper(upperBefore);
+  delete [] lowerBefore;
+  delete [] upperBefore;
+#if 0
+  static int xxxxxx=0;
+  static int yyyyyy=0;
+  static int zzzzzz=0;
+  zzzzzz += nFeas;
+  for (int j=0;j<(1<<depth);j++) {
+    xxxxxx++;
+    if ((xxxxxx%10000)==0)
+      printf("%d implicit %d feas %d sent back\n",xxxxxx,zzzzzz,yyyyyy);
+  }
+  for (int j=0;j<numberFeasible;j++) {
+    yyyyyy++;
+    if ((yyyyyy%10000)==0)
+      printf("%d implicit %d feas %d sent back\n",xxxxxx,zzzzzz,yyyyyy);
+  }
+#endif
+  return numberFeasible;
+}
+#endif
diff --git a/cbits/coin/OsiSolverInterface.hpp b/cbits/coin/OsiSolverInterface.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiSolverInterface.hpp
@@ -0,0 +1,2136 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiSolverInterface_H
+#define OsiSolverInterface_H
+
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "CoinTypes.hpp"
+#include "CoinMessageHandler.hpp"
+#include "CoinPackedVectorBase.hpp"
+#include "CoinPackedMatrix.hpp"
+#include "CoinWarmStart.hpp"
+#include "CoinFinite.hpp"
+#include "CoinError.hpp"
+
+#include "OsiCollections.hpp"
+#include "OsiSolverParameters.hpp"
+
+class CoinSnapshot;
+class CoinLpIO;
+class CoinMpsIO;
+
+class OsiCuts;
+class OsiAuxInfo;
+class OsiRowCut;
+class OsiRowCutDebugger;
+class CoinSet;
+class CoinBuild;
+class CoinModel;
+class OsiSolverBranch;
+class OsiSolverResult;
+class OsiObject;
+
+
+//#############################################################################
+
+/*! \brief Abstract Base Class for describing an interface to a solver.
+
+  Many OsiSolverInterface query methods return a const pointer to the
+  requested read-only data. If the model data is changed or the solver
+  is called, these pointers may no longer be valid and should be 
+  refreshed by invoking the member function to obtain an updated copy
+  of the pointer.
+  For example:
+  \code
+      OsiSolverInterface solverInterfacePtr ;
+      const double * ruBnds = solverInterfacePtr->getRowUpper();
+      solverInterfacePtr->applyCuts(someSetOfCuts);
+      // ruBnds is no longer a valid pointer and must be refreshed
+      ruBnds = solverInterfacePtr->getRowUpper();
+  \endcode
+
+  Querying a problem that has no data associated with it will result in
+  zeros for the number of rows and columns, and NULL pointers from
+  the methods that return vectors.
+*/
+
+class OsiSolverInterface  {
+   friend void OsiSolverInterfaceCommonUnitTest(
+      const OsiSolverInterface* emptySi,
+      const std::string & mpsDir,
+      const std::string & netlibDir);
+   friend void OsiSolverInterfaceMpsUnitTest(
+      const std::vector<OsiSolverInterface*> & vecSiP,
+      const std::string & mpsDir);
+
+public:
+
+  /// Internal class for obtaining status from the applyCuts method 
+  class ApplyCutsReturnCode {
+    friend class OsiSolverInterface;
+    friend class OsiClpSolverInterface;
+    friend class OsiGrbSolverInterface;
+
+  public:
+    ///@name Constructors and desctructors
+    //@{
+      /// Default constructor
+      ApplyCutsReturnCode():
+	 intInconsistent_(0),
+	 extInconsistent_(0),
+	 infeasible_(0),
+	 ineffective_(0),
+	 applied_(0) {} 
+      /// Copy constructor
+      ApplyCutsReturnCode(const ApplyCutsReturnCode & rhs):
+	 intInconsistent_(rhs.intInconsistent_),
+	 extInconsistent_(rhs.extInconsistent_),
+	 infeasible_(rhs.infeasible_),
+	 ineffective_(rhs.ineffective_),
+	 applied_(rhs.applied_) {} 
+      /// Assignment operator
+      ApplyCutsReturnCode & operator=(const ApplyCutsReturnCode& rhs)
+      { 
+	if (this != &rhs) { 
+	  intInconsistent_ = rhs.intInconsistent_;
+	  extInconsistent_ = rhs.extInconsistent_;
+	  infeasible_      = rhs.infeasible_;
+	  ineffective_     = rhs.ineffective_;
+	  applied_         = rhs.applied_;
+	}
+	return *this;
+      }
+      /// Destructor
+      ~ApplyCutsReturnCode(){}
+    //@}
+
+    /**@name Accessing return code attributes */
+    //@{
+      /// Number of logically inconsistent cuts
+      inline int getNumInconsistent() const
+      {return intInconsistent_;}
+      /// Number of cuts inconsistent with the current model
+      inline int getNumInconsistentWrtIntegerModel() const
+      {return extInconsistent_;}
+      /// Number of cuts that cause obvious infeasibility
+      inline int getNumInfeasible() const
+      {return infeasible_;}
+      /// Number of redundant or ineffective cuts
+      inline int getNumIneffective() const
+      {return ineffective_;}
+      /// Number of cuts applied
+      inline int getNumApplied() const
+      {return applied_;}
+    //@}
+
+  private: 
+    /**@name Private methods */
+    //@{
+      /// Increment logically inconsistent cut counter 
+      inline void incrementInternallyInconsistent(){intInconsistent_++;}
+      /// Increment model-inconsistent counter
+      inline void incrementExternallyInconsistent(){extInconsistent_++;}
+      /// Increment infeasible cut counter
+      inline void incrementInfeasible(){infeasible_++;}
+      /// Increment ineffective cut counter
+      inline void incrementIneffective(){ineffective_++;}
+      /// Increment applied cut counter
+      inline void incrementApplied(){applied_++;}
+    //@}
+
+    ///@name Private member data
+    //@{
+      /// Counter for logically inconsistent cuts
+      int intInconsistent_;
+      /// Counter for model-inconsistent cuts
+      int extInconsistent_;
+      /// Counter for infeasible cuts
+      int infeasible_;
+      /// Counter for ineffective cuts
+      int ineffective_;
+      /// Counter for applied cuts
+      int applied_;
+    //@}
+  };
+
+  //---------------------------------------------------------------------------
+
+  ///@name Solve methods 
+  //@{
+    /// Solve initial LP relaxation 
+    virtual void initialSolve() = 0; 
+
+    /*! \brief Resolve an LP relaxation after problem modification
+
+      Note the `re-' in `resolve'. initialSolve() should be used to solve the
+      problem for the first time.
+    */
+    virtual void resolve() = 0;
+
+    /// Invoke solver's built-in enumeration algorithm
+    virtual void branchAndBound() = 0;
+
+#ifdef CBC_NEXT_VERSION
+    /*
+      Would it make sense to collect all of these routines in a `MIP Helper'
+      section? It'd make it easier for users and implementors to find them.
+    */
+    /**
+       Solve 2**N (N==depth) problems and return solutions and bases.
+       There are N branches each of which changes bounds on both sides
+       as given by branch.  The user should provide an array of (empty)
+       results which will be filled in.  See OsiSolveResult for more details
+       (in OsiSolveBranch.?pp) but it will include a basis and primal solution.
+
+       The order of results is left to right at feasible leaf nodes so first one
+       is down, down, .....
+
+       Returns number of feasible leaves.  Also sets number of solves done and number
+       of iterations.
+
+       This is provided so a solver can do faster.
+
+       If forceBranch true then branch done even if satisfied
+    */
+    virtual int solveBranches(int depth,const OsiSolverBranch * branch,
+			      OsiSolverResult * result,
+			      int & numberSolves, int & numberIterations,
+			      bool forceBranch=false);
+#endif
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Parameter set/get methods
+
+     The set methods return true if the parameter was set to the given value,
+     false otherwise. When a set method returns false, the original value (if
+     any) should be unchanged.  There can be various reasons for failure: the
+     given parameter is not applicable for the solver (e.g., refactorization
+     frequency for the volume algorithm), the parameter is not yet
+     implemented for the solver or simply the value of the parameter is out
+     of the range the solver accepts. If a parameter setting call returns
+     false check the details of your solver.
+
+     The get methods return true if the given parameter is applicable for the
+     solver and is implemented. In this case the value of the parameter is
+     returned in the second argument. Otherwise they return false.
+
+     \note
+     There is a default implementation of the set/get
+     methods, namely to store/retrieve the given value using an array in the
+     base class. A specific solver implementation can use this feature, for
+     example, to store parameters that should be used later on. Implementors
+     of a solver interface should overload these functions to provide the
+     proper interface to and accurately reflect the capabilities of a
+     specific solver.
+
+     The format for hints is slightly different in that a boolean specifies
+     the sense of the hint and an enum specifies the strength of the hint.
+     Hints should be initialised when a solver is instantiated.
+     (See OsiSolverParameters.hpp for defined hint parameters and strength.)
+     When specifying the sense of the hint, a value of true means to work with
+     the hint, false to work against it.  For example,
+     <ul>
+       <li> \code setHintParam(OsiDoScale,true,OsiHintTry) \endcode
+	    is a mild suggestion to the solver to scale the constraint
+	    system.
+       <li> \code setHintParam(OsiDoScale,false,OsiForceDo) \endcode
+	    tells the solver to disable scaling, or throw an exception if
+	    it cannot comply.
+     </ul>
+     As another example, a solver interface could use the value and strength
+     of the \c OsiDoReducePrint hint to adjust the amount of information
+     printed by the interface and/or solver.  The extent to which a solver
+     obeys hints is left to the solver.  The value and strength returned by
+     \c getHintParam will match the most recent call to \c setHintParam,
+     and will not necessarily reflect the solver's ability to comply with the
+     hint.  If the hint strength is \c OsiForceDo, the solver is required to
+     throw an exception if it cannot perform the specified action.
+
+     \note
+     As with the other set/get methods, there is a default implementation
+     which maintains arrays in the base class for hint sense and strength.
+     The default implementation does not store the \c otherInformation
+     pointer, and always throws an exception for strength \c OsiForceDo.
+     Implementors of a solver interface should override these functions to
+     provide the proper interface to and accurately reflect the capabilities
+     of a specific solver.
+  */
+  //@{
+    //! Set an integer parameter
+    virtual bool setIntParam(OsiIntParam key, int value) {
+      if (key == OsiLastIntParam) return (false) ;
+      intParam_[key] = value;
+      return true;
+    }
+    //! Set a double parameter
+    virtual bool setDblParam(OsiDblParam key, double value) {
+      if (key == OsiLastDblParam) return (false) ;
+      dblParam_[key] = value;
+      return true;
+    }
+    //! Set a string parameter
+    virtual bool setStrParam(OsiStrParam key, const std::string & value) {
+      if (key == OsiLastStrParam) return (false) ;
+      strParam_[key] = value;
+      return true;
+    }
+    /*! \brief Set a hint parameter
+
+      The \c otherInformation parameter can be used to pass in an arbitrary
+      block of information which is interpreted by the OSI and the underlying
+      solver.  Users are cautioned that this hook is solver-specific.
+
+      Implementors:
+      The default implementation completely ignores \c otherInformation and
+      always throws an exception for OsiForceDo. This is almost certainly not
+      the behaviour you want; you really should override this method.
+    */
+    virtual bool setHintParam(OsiHintParam key, bool yesNo=true,
+			      OsiHintStrength strength=OsiHintTry,
+			      void * /*otherInformation*/ = NULL) {
+      if (key==OsiLastHintParam)
+	return false; 
+      hintParam_[key] = yesNo;
+      hintStrength_[key] = strength;
+      if (strength == OsiForceDo)
+	throw CoinError("OsiForceDo illegal",
+			"setHintParam", "OsiSolverInterface");
+      return true;
+    }
+    //! Get an integer parameter
+    virtual bool getIntParam(OsiIntParam key, int& value) const {
+      if (key == OsiLastIntParam) return (false) ;
+      value = intParam_[key];
+      return true;
+    }
+    //! Get a double parameter
+    virtual bool getDblParam(OsiDblParam key, double& value) const {
+      if (key == OsiLastDblParam) return (false) ;
+      value = dblParam_[key];
+      return true;
+    }
+    //! Get a string parameter
+    virtual bool getStrParam(OsiStrParam key, std::string& value) const {
+      if (key == OsiLastStrParam) return (false) ;
+      value = strParam_[key];
+      return true;
+    }
+    /*! \brief Get a hint parameter (all information)
+
+	Return all available information for the hint: sense, strength,
+	and any extra information associated with the hint.
+
+	Implementors: The default implementation will always set
+	\c otherInformation to NULL. This is almost certainly not the
+	behaviour you want; you really should override this method.
+    */
+    virtual bool getHintParam(OsiHintParam key, bool& yesNo,
+			      OsiHintStrength& strength,
+			      void *& otherInformation) const {
+      if (key==OsiLastHintParam)
+	return false; 
+      yesNo = hintParam_[key];
+      strength = hintStrength_[key];
+      otherInformation=NULL;
+      return true;
+    }
+    /*! \brief Get a hint parameter (sense and strength only)
+
+	Return only the sense and strength of the hint.
+    */
+    virtual bool getHintParam(OsiHintParam key, bool& yesNo,
+			      OsiHintStrength& strength) const {
+      if (key==OsiLastHintParam)
+	return false; 
+      yesNo = hintParam_[key];
+      strength = hintStrength_[key];
+      return true;
+    }
+    /*! \brief Get a hint parameter (sense only)
+
+	Return only the sense (true/false) of the hint.
+    */
+    virtual bool getHintParam(OsiHintParam key, bool& yesNo) const {
+      if (key==OsiLastHintParam)
+	return false; 
+      yesNo = hintParam_[key];
+      return true;
+    }
+    /*! \brief Copy all parameters in this section from one solver to another
+
+      Note that the current implementation also copies the appData block,
+      message handler, and rowCutDebugger. Arguably these should have
+      independent copy methods.
+    */
+    void copyParameters(OsiSolverInterface & rhs);
+
+    /** \brief Return the integrality tolerance of the underlying solver.
+    
+	We should be able to get an integrality tolerance, but
+        until that time just use the primal tolerance
+
+	\todo
+	This method should be replaced; it's architecturally wrong.  This
+	should be an honest dblParam with a keyword. Underlying solvers
+	that do not support integer variables should return false for set and
+	get on this parameter.  Underlying solvers that support integrality
+	should add this to the parameters they support, using whatever
+	tolerance is appropriate.  -lh, 091021-
+    */
+    inline double getIntegerTolerance() const
+    { return dblParam_[OsiPrimalTolerance];}
+  //@}
+
+  //---------------------------------------------------------------------------
+  ///@name Methods returning info on how the solution process terminated
+  //@{
+    /// Are there numerical difficulties?
+    virtual bool isAbandoned() const = 0;
+    /// Is optimality proven?
+    virtual bool isProvenOptimal() const = 0;
+    /// Is primal infeasibility proven?
+    virtual bool isProvenPrimalInfeasible() const = 0;
+    /// Is dual infeasibility proven?
+    virtual bool isProvenDualInfeasible() const = 0;
+    /// Is the given primal objective limit reached?
+    virtual bool isPrimalObjectiveLimitReached() const;
+    /// Is the given dual objective limit reached?
+    virtual bool isDualObjectiveLimitReached() const;
+    /// Iteration limit reached?
+    virtual bool isIterationLimitReached() const = 0;
+  //@}
+
+  //---------------------------------------------------------------------------
+  /** \name Warm start methods
+
+    Note that the warm start methods return a generic CoinWarmStart object.
+    The precise characteristics of this object are solver-dependent. Clients
+    who wish to maintain a maximum degree of solver independence should take
+    care to avoid unnecessary assumptions about the properties of a warm start
+    object.
+  */
+  //@{
+    /*! \brief Get an empty warm start object
+      
+      This routine returns an empty warm start object. Its purpose is
+      to provide a way for a client to acquire a warm start object of the
+      appropriate type for the solver, which can then be resized and modified
+      as desired.
+    */
+
+    virtual CoinWarmStart *getEmptyWarmStart () const = 0 ;
+
+    /** \brief Get warm start information.
+
+      Return warm start information for the current state of the solver
+      interface. If there is no valid warm start information, an empty warm
+      start object wil be returned.
+    */
+    virtual CoinWarmStart* getWarmStart() const = 0;
+    /** \brief Get warm start information.
+
+      Return warm start information for the current state of the solver
+      interface. If there is no valid warm start information, an empty warm
+      start object wil be returned.  This does not necessarily create an 
+      object - may just point to one.  must Delete set true if user
+      should delete returned object.
+    */
+    virtual CoinWarmStart* getPointerToWarmStart(bool & mustDelete) ;
+
+    /** \brief Set warm start information.
+    
+      Return true or false depending on whether the warm start information was
+      accepted or not.
+      By definition, a call to setWarmStart with a null parameter should
+      cause the solver interface to refresh its warm start information
+      from the underlying solver.
+   */
+    virtual bool setWarmStart(const CoinWarmStart* warmstart) = 0;
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Hot start methods
+  
+     Primarily used in strong branching. The user can create a hot start
+     object --- a snapshot of the optimization process --- then reoptimize
+     over and over again, starting from the same point.
+
+     \note
+     <ul>
+     <li> Between hot started optimizations only bound changes are allowed.
+     <li> The copy constructor and assignment operator should NOT copy any
+          hot start information.
+     <li> The default implementation simply extracts a warm start object in
+          \c markHotStart, resets to the warm start object in
+	  \c solveFromHotStart, and deletes the warm start object in
+	  \c unmarkHotStart.
+	  <em>Actual solver implementations are encouraged to do better.</em>
+     </ul>
+
+  */
+  //@{
+    /// Create a hot start snapshot of the optimization process.
+    virtual void markHotStart();
+    /// Optimize starting from the hot start snapshot.
+    virtual void solveFromHotStart();
+    /// Delete the hot start snapshot.
+    virtual void unmarkHotStart();
+  //@}
+
+  //---------------------------------------------------------------------------
+  /**@name Problem query methods
+
+   Querying a problem that has no data associated with it will result in
+   zeros for the number of rows and columns, and NULL pointers from the
+   methods that return vectors.
+
+   Const pointers returned from any data-query method are valid as long as
+   the data is unchanged and the solver is not called.
+  */
+  //@{
+    /// Get the number of columns
+    virtual int getNumCols() const = 0;
+
+    /// Get the number of rows
+    virtual int getNumRows() const = 0;
+
+    /// Get the number of nonzero elements
+    virtual int getNumElements() const = 0;
+
+    /// Get the number of integer variables
+    virtual int getNumIntegers() const ;
+
+    /// Get a pointer to an array[getNumCols()] of column lower bounds
+    virtual const double * getColLower() const = 0;
+
+    /// Get a pointer to an array[getNumCols()] of column upper bounds
+    virtual const double * getColUpper() const = 0;
+
+    /*! \brief Get a pointer to an array[getNumRows()] of row constraint senses.
+
+      <ul>
+      <li>'L': <= constraint
+      <li>'E': =  constraint
+      <li>'G': >= constraint
+      <li>'R': ranged constraint
+      <li>'N': free constraint
+      </ul>
+    */
+    virtual const char * getRowSense() const = 0;
+
+    /*! \brief Get a pointer to an array[getNumRows()] of row right-hand sides
+
+      <ul>
+	<li> if getRowSense()[i] == 'L' then
+	     getRightHandSide()[i] == getRowUpper()[i]
+	<li> if getRowSense()[i] == 'G' then
+	     getRightHandSide()[i] == getRowLower()[i]
+	<li> if getRowSense()[i] == 'R' then
+	     getRightHandSide()[i] == getRowUpper()[i]
+	<li> if getRowSense()[i] == 'N' then
+	     getRightHandSide()[i] == 0.0
+      </ul>
+    */
+    virtual const double * getRightHandSide() const = 0;
+
+    /*! \brief Get a pointer to an array[getNumRows()] of row ranges.
+
+      <ul>
+	  <li> if getRowSense()[i] == 'R' then
+		  getRowRange()[i] == getRowUpper()[i] - getRowLower()[i]
+	  <li> if getRowSense()[i] != 'R' then
+		  getRowRange()[i] is 0.0
+	</ul>
+    */
+    virtual const double * getRowRange() const = 0;
+
+    /// Get a pointer to an array[getNumRows()] of row lower bounds
+    virtual const double * getRowLower() const = 0;
+
+    /// Get a pointer to an array[getNumRows()] of row upper bounds
+    virtual const double * getRowUpper() const = 0;
+
+    /*! \brief Get a pointer to an array[getNumCols()] of objective
+	       function coefficients.
+    */
+    virtual const double * getObjCoefficients() const = 0;
+
+    /*! \brief Get the objective function sense
+    
+      -  1 for minimisation (default)
+      - -1 for maximisation
+    */
+    virtual double getObjSense() const = 0;
+
+    /// Return true if the variable is continuous
+    virtual bool isContinuous(int colIndex) const = 0;
+
+    /// Return true if the variable is binary
+    virtual bool isBinary(int colIndex) const;
+
+    /*! \brief Return true if the variable is integer.
+
+      This method returns true if the variable is binary or general integer.
+    */
+    virtual bool isInteger(int colIndex) const;
+
+    /// Return true if the variable is general integer
+    virtual bool isIntegerNonBinary(int colIndex) const;
+
+    /// Return true if the variable is binary and not fixed
+    virtual bool isFreeBinary(int colIndex) const; 
+
+    /*! \brief Return an array[getNumCols()] of column types
+
+      \deprecated See #getColType
+    */
+    inline const char *columnType(bool refresh=false) const
+    { return getColType(refresh); }
+
+    /*! \brief Return an array[getNumCols()] of column types
+
+       - 0 - continuous
+       - 1 - binary
+       - 2 - general integer
+      
+      If \p refresh is true, the classification of integer variables as
+      binary or general integer will be reevaluated. If the current bounds
+      are [0,1], or if the variable is fixed at 0 or 1, it will be classified
+      as binary, otherwise it will be classified as general integer.
+    */
+    virtual const char * getColType(bool refresh=false) const;
+  
+    /// Get a pointer to a row-wise copy of the matrix
+    virtual const CoinPackedMatrix * getMatrixByRow() const = 0;
+
+    /// Get a pointer to a column-wise copy of the matrix
+    virtual const CoinPackedMatrix * getMatrixByCol() const = 0;
+
+    /*! \brief Get a pointer to a mutable row-wise copy of the matrix.
+    
+      Returns NULL if the request is not meaningful (i.e., the OSI will not
+      recognise any modifications to the matrix).
+    */
+    virtual CoinPackedMatrix * getMutableMatrixByRow() const {return NULL;}
+
+    /*! \brief Get a pointer to a mutable column-wise copy of the matrix
+    
+      Returns NULL if the request is not meaningful (i.e., the OSI will not
+      recognise any modifications to the matrix).
+    */
+    virtual CoinPackedMatrix * getMutableMatrixByCol() const {return NULL;}
+
+    /// Get the solver's value for infinity
+    virtual double getInfinity() const = 0;
+  //@}
+    
+  /**@name Solution query methods */
+  //@{
+    /// Get a pointer to an array[getNumCols()] of primal variable values
+    virtual const double * getColSolution() const = 0;
+
+    /** Get a pointer to an array[getNumCols()] of primal variable values
+	guaranteed to be between the column lower and upper bounds.
+    */
+    virtual const double * getStrictColSolution();
+
+    /// Get pointer to array[getNumRows()] of dual variable values
+    virtual const double * getRowPrice() const = 0;
+
+    /// Get a pointer to an array[getNumCols()] of reduced costs
+    virtual const double * getReducedCost() const = 0;
+
+    /** Get a pointer to array[getNumRows()] of row activity levels.
+    
+      The row activity for a row is the left-hand side evaluated at the
+      current solution.
+    */
+    virtual const double * getRowActivity() const = 0;
+
+    /// Get the objective function value.
+    virtual double getObjValue() const = 0;
+
+    /** Get the number of iterations it took to solve the problem (whatever
+	`iteration' means to the solver).
+    */
+    virtual int getIterationCount() const = 0;
+
+    /** Get as many dual rays as the solver can provide. In case of proven
+	primal infeasibility there should (with high probability) be at least
+	one.
+
+	The first getNumRows() ray components will always be associated with
+	the row duals (as returned by getRowPrice()). If \c fullRay is true,
+	the final getNumCols() entries will correspond to the ray components
+	associated with the nonbasic variables. If the full ray is requested
+	and the method cannot provide it, it will throw an exception.
+
+	\note
+	Implementors of solver interfaces note that the double pointers in
+	the vector should point to arrays of length getNumRows() (fullRay =
+	false) or (getNumRows()+getNumCols()) (fullRay = true) and they should
+	be allocated with new[].
+
+	\note
+	Clients of solver interfaces note that it is the client's
+	responsibility to free the double pointers in the vector using
+	delete[]. Clients are reminded that a problem can be dual and primal
+	infeasible.
+    */
+    virtual std::vector<double*> getDualRays(int maxNumRays,
+					     bool fullRay = false) const = 0;
+
+    /** Get as many primal rays as the solver can provide. In case of proven
+	dual infeasibility there should (with high probability) be at least
+	one.
+   
+	\note
+	Implementors of solver interfaces note that the double pointers in
+	the vector should point to arrays of length getNumCols() and they
+	should be allocated with new[].
+
+	\note
+	Clients of solver interfaces note that it is the client's
+	responsibility to free the double pointers in the vector using
+	delete[]. Clients are reminded that a problem can be dual and primal
+	infeasible.
+    */
+    virtual std::vector<double*> getPrimalRays(int maxNumRays) const = 0;
+
+    /** Get vector of indices of primal variables which are integer variables 
+	but have fractional values in the current solution. */
+    virtual OsiVectorInt getFractionalIndices(const double etol=1.e-05)
+      const;
+  //@}
+
+  //-------------------------------------------------------------------------
+  /**@name Methods to modify the objective, bounds, and solution
+
+     For functions which take a set of indices as parameters
+     (\c setObjCoeffSet(), \c setColSetBounds(), \c setRowSetBounds(),
+     \c setRowSetTypes()), the parameters follow the C++ STL iterator
+     convention: \c indexFirst points to the first index in the
+     set, and \c indexLast points to a position one past the last index
+     in the set.
+  
+  */
+  //@{
+    /** Set an objective function coefficient */
+    virtual void setObjCoeff( int elementIndex, double elementValue ) = 0;
+
+    /** Set a set of objective function coefficients */
+    virtual void setObjCoeffSet(const int* indexFirst,
+				const int* indexLast,
+				const double* coeffList);
+
+    /** Set the objective coefficients for all columns.
+
+	array [getNumCols()] is an array of values for the objective.
+	This defaults to a series of set operations and is here for speed.
+    */
+    virtual void setObjective(const double * array);
+
+    /** Set the objective function sense.
+
+        Use 1 for minimisation (default), -1 for maximisation.
+
+	\note
+	Implementors note that objective function sense is a parameter of
+	the OSI, not a property of the problem. Objective sense can be
+	set prior to problem load and should not be affected by loading a
+	new problem.
+    */
+    virtual void setObjSense(double s) = 0;
+  
+
+    /** Set a single column lower bound.
+	Use -getInfinity() for -infinity. */
+    virtual void setColLower( int elementIndex, double elementValue ) = 0;
+    
+    /** Set the lower bounds for all columns.
+
+	array [getNumCols()] is an array of values for the lower bounds.
+	This defaults to a series of set operations and is here for speed.
+    */
+    virtual void setColLower(const double * array);
+
+    /** Set a single column upper bound.
+	Use getInfinity() for infinity. */
+    virtual void setColUpper( int elementIndex, double elementValue ) = 0;
+
+    /** Set the upper bounds for all columns.
+
+	array [getNumCols()] is an array of values for the upper bounds.
+	This defaults to a series of set operations and is here for speed.
+    */
+    virtual void setColUpper(const double * array);
+    
+    
+    /** Set a single column lower and upper bound.
+	The default implementation just invokes setColLower() and
+	setColUpper() */
+    virtual void setColBounds( int elementIndex,
+			       double lower, double upper ) {
+       setColLower(elementIndex, lower);
+       setColUpper(elementIndex, upper);
+    }
+  
+    /** Set the upper and lower bounds of a set of columns.
+
+	The default implementation just invokes setColBounds() over and over
+	again.  For each column, boundList must contain both a lower and
+	upper bound, in that order.
+    */
+    virtual void setColSetBounds(const int* indexFirst,
+				 const int* indexLast,
+				 const double* boundList);
+
+    /** Set a single row lower bound.
+	Use -getInfinity() for -infinity. */
+    virtual void setRowLower( int elementIndex, double elementValue ) = 0;
+    
+    /** Set a single row upper bound.
+	Use getInfinity() for infinity. */
+    virtual void setRowUpper( int elementIndex, double elementValue ) = 0;
+  
+    /** Set a single row lower and upper bound.
+	The default implementation just invokes setRowLower() and
+	setRowUpper() */
+    virtual void setRowBounds( int elementIndex,
+			       double lower, double upper ) {
+       setRowLower(elementIndex, lower);
+       setRowUpper(elementIndex, upper);
+    }
+
+    /** Set the bounds on a set of rows.
+
+	The default implementation just invokes setRowBounds() over and over
+	again.  For each row, boundList must contain both a lower and
+	upper bound, in that order.
+    */
+    virtual void setRowSetBounds(const int* indexFirst,
+				 const int* indexLast,
+				 const double* boundList);
+  
+  
+    /** Set the type of a single row */
+    virtual void setRowType(int index, char sense, double rightHandSide,
+			    double range) = 0;
+  
+    /** Set the type of a set of rows.
+	The default implementation just invokes setRowType()
+	over and over again.
+    */
+    virtual void setRowSetTypes(const int* indexFirst,
+				const int* indexLast,
+				const char* senseList,
+				const double* rhsList,
+				const double* rangeList);
+
+    /** Set the primal solution variable values
+
+	colsol[getNumCols()] is an array of values for the primal variables.
+	These values are copied to memory owned by the solver interface
+	object or the solver.  They will be returned as the result of
+	getColSolution() until changed by another call to setColSolution() or
+	by a call to any solver routine.  Whether the solver makes use of the
+	solution in any way is solver-dependent.
+    */
+    virtual void setColSolution(const double *colsol) = 0;
+
+    /** Set dual solution variable values
+
+	rowprice[getNumRows()] is an array of values for the dual variables.
+	These values are copied to memory owned by the solver interface
+	object or the solver.  They will be returned as the result of
+	getRowPrice() until changed by another call to setRowPrice() or by a
+	call to any solver routine.  Whether the solver makes use of the
+	solution in any way is solver-dependent.
+    */
+    virtual void setRowPrice(const double * rowprice) = 0;
+
+    /** Fix variables at bound based on reduced cost
+    
+	For variables currently at bound, fix the variable at bound if the
+	reduced cost exceeds the gap. Return the number of variables fixed.
+
+	If justInteger is set to false, the routine will also fix continuous
+	variables, but the test still assumes a delta of 1.0.
+    */
+    virtual int reducedCostFix(double gap, bool justInteger=true);
+  //@}
+
+  //-------------------------------------------------------------------------
+  /**@name Methods to set variable type */
+  //@{
+    /** Set the index-th variable to be a continuous variable */
+    virtual void setContinuous(int index) = 0;
+    /** Set the index-th variable to be an integer variable */
+    virtual void setInteger(int index) = 0;
+    /** Set the variables listed in indices (which is of length len) to be
+	continuous variables */
+    virtual void setContinuous(const int* indices, int len);
+    /** Set the variables listed in indices (which is of length len) to be
+	integer variables */
+    virtual void setInteger(const int* indices, int len);
+  //@}
+  //-------------------------------------------------------------------------
+
+  //-------------------------------------------------------------------------
+
+    /*! \brief Data type for name vectors. */
+    typedef std::vector<std::string> OsiNameVec ;
+
+  /*! \name Methods for row and column names
+
+    Osi defines three name management disciplines: `auto names' (0), `lazy
+    names' (1), and `full names' (2). See the description of
+    #OsiNameDiscipline for details. Changing the name discipline (via
+    setIntParam()) will not automatically add or remove name information,
+    but setting the discipline to auto will make existing information
+    inaccessible until the discipline is reset to lazy or full.
+
+    By definition, a row index of getNumRows() (<i>i.e.</i>, one larger than
+    the largest valid row index) refers to the objective function.
+
+    OSI users and implementors: While the OSI base class can define an
+    interface and provide rudimentary support, use of names really depends
+    on support by the OsiXXX class to ensure that names are managed
+    correctly.  If an OsiXXX class does not support names, it should return
+    false for calls to getIntParam() or setIntParam() that reference
+    OsiNameDiscipline.
+  */
+  //@{
+
+    /*! \brief Generate a standard name of the form Rnnnnnnn or Cnnnnnnn
+    
+      Set \p rc to 'r' for a row name, 'c' for a column name.
+      The `nnnnnnn' part is generated from ndx and will contain 7 digits
+      by default, padded with zeros if necessary. As a special case,
+      ndx = getNumRows() is interpreted as a request for the name of the
+      objective function. OBJECTIVE is returned, truncated to digits+1
+      characters to match the row and column names.
+    */
+    virtual std::string dfltRowColName(char rc,
+				 int ndx, unsigned digits = 7) const ;
+
+    /*! \brief Return the name of the objective function */
+
+  virtual std::string getObjName (unsigned maxLen = static_cast<unsigned>(std::string::npos)) const ;
+
+    /*! \brief Set the name of the objective function */
+
+    virtual inline void setObjName (std::string name)
+    { objName_ = name ; }
+
+    /*! \brief Return the name of the row.
+
+      The routine will <i>always</i> return some name, regardless of the name
+      discipline or the level of support by an OsiXXX derived class. Use
+      maxLen to limit the length.
+    */
+    virtual std::string getRowName(int rowIndex,
+				   unsigned maxLen = static_cast<unsigned>(std::string::npos)) const ;
+
+    /*! \brief Return a pointer to a vector of row names
+
+      If the name discipline (#OsiNameDiscipline) is auto, the return value
+      will be a vector of length zero. If the name discipline is lazy, the
+      vector will contain only names supplied by the client and will be no
+      larger than needed to hold those names; entries not supplied will be
+      null strings. In particular, the objective name is <i>not</i>
+      included in the vector for lazy names. If the name discipline is
+      full, the vector will have getNumRows() names, either supplied or
+      generated, plus one additional entry for the objective name.
+    */
+    virtual const OsiNameVec &getRowNames() ;
+
+    /*! \brief Set a row name
+
+      Quietly does nothing if the name discipline (#OsiNameDiscipline) is
+      auto. Quietly fails if the row index is invalid.
+    */
+    virtual void setRowName(int ndx, std::string name) ;
+
+    /*! \brief Set multiple row names
+
+      The run of len entries starting at srcNames[srcStart] are installed as
+      row names starting at row index tgtStart. The base class implementation
+      makes repeated calls to setRowName.
+    */
+    virtual void setRowNames(OsiNameVec &srcNames,
+		     int srcStart, int len, int tgtStart) ;
+
+    /*! \brief Delete len row names starting at index tgtStart
+
+      The specified row names are removed and the remaining row names are
+      copied down to close the gap.
+    */
+    virtual void deleteRowNames(int tgtStart, int len) ;
+  
+    /*! \brief Return the name of the column
+
+      The routine will <i>always</i> return some name, regardless of the name
+      discipline or the level of support by an OsiXXX derived class. Use
+      maxLen to limit the length.
+    */
+    virtual std::string getColName(int colIndex,
+				   unsigned maxLen = static_cast<unsigned>(std::string::npos)) const ;
+
+    /*! \brief Return a pointer to a vector of column names
+
+      If the name discipline (#OsiNameDiscipline) is auto, the return value
+      will be a vector of length zero. If the name discipline is lazy, the
+      vector will contain only names supplied by the client and will be no
+      larger than needed to hold those names; entries not supplied will be
+      null strings. If the name discipline is full, the vector will have
+      getNumCols() names, either supplied or generated.
+    */
+    virtual const OsiNameVec &getColNames() ;
+
+    /*! \brief Set a column name
+
+      Quietly does nothing if the name discipline (#OsiNameDiscipline) is
+      auto. Quietly fails if the column index is invalid.
+    */
+    virtual void setColName(int ndx, std::string name) ;
+
+    /*! \brief Set multiple column names
+
+      The run of len entries starting at srcNames[srcStart] are installed as
+      column names starting at column index tgtStart. The base class
+      implementation makes repeated calls to setColName.
+    */
+    virtual void setColNames(OsiNameVec &srcNames,
+		     int srcStart, int len, int tgtStart) ;
+
+    /*! \brief Delete len column names starting at index tgtStart
+
+      The specified column names are removed and the remaining column names
+      are copied down to close the gap.
+    */
+    virtual void deleteColNames(int tgtStart, int len) ;
+  
+
+    /*! \brief Set row and column names from a CoinMpsIO object.
+    
+      Also sets the name of the objective function. If the name discipline
+      is auto, you get what you asked for. This routine does not use
+      setRowName or setColName.
+    */
+    void setRowColNames(const CoinMpsIO &mps) ;
+
+    /*! \brief Set row and column names from a CoinModel object.
+
+      If the name discipline is auto, you get what you asked for.
+      This routine does not use setRowName or setColName.
+    */
+    void setRowColNames(CoinModel &mod) ;
+
+    /*! \brief Set row and column names from a CoinLpIO object.
+
+      Also sets the name of the objective function. If the name discipline is
+      auto, you get what you asked for. This routine does not use setRowName
+      or setColName.
+    */
+    void setRowColNames(CoinLpIO &mod) ;
+
+  //@}
+  //-------------------------------------------------------------------------
+    
+  //-------------------------------------------------------------------------
+  /**@name Methods to modify the constraint system.
+
+     Note that new columns are added as continuous variables.
+  */
+  //@{
+
+    /** Add a column (primal variable) to the problem. */
+    virtual void addCol(const CoinPackedVectorBase& vec,
+			const double collb, const double colub,   
+			const double obj) = 0;
+
+    /*! \brief Add a named column (primal variable) to the problem.
+
+      The default implementation adds the column, then changes the name. This
+      can surely be made more efficient within an OsiXXX class.
+    */
+    virtual void addCol(const CoinPackedVectorBase& vec,
+			const double collb, const double colub,   
+			const double obj, std::string name) ;
+
+    /** Add a column (primal variable) to the problem. */
+    virtual void addCol(int numberElements,
+			const int* rows, const double* elements,
+			const double collb, const double colub,   
+			const double obj) ;
+
+    /*! \brief Add a named column (primal variable) to the problem.
+
+      The default implementation adds the column, then changes the name. This
+      can surely be made more efficient within an OsiXXX class.
+    */
+    virtual void addCol(int numberElements,
+			const int* rows, const double* elements,
+			const double collb, const double colub,   
+			const double obj, std::string name) ;
+
+    /** Add a set of columns (primal variables) to the problem.
+    
+      The default implementation simply makes repeated calls to
+      addCol().
+    */
+    virtual void addCols(const int numcols,
+			 const CoinPackedVectorBase * const * cols,
+			 const double* collb, const double* colub,   
+			 const double* obj);
+
+    /** Add a set of columns (primal variables) to the problem.
+    
+      The default implementation simply makes repeated calls to
+      addCol().
+    */
+    virtual void addCols(const int numcols, const int* columnStarts,
+			 const int* rows, const double* elements,
+			 const double* collb, const double* colub,   
+			 const double* obj);
+
+    /// Add columns using a CoinBuild object
+    void addCols(const CoinBuild & buildObject);
+
+    /** Add columns from a model object.  returns
+       -1 if object in bad state (i.e. has row information)
+       otherwise number of errors
+       modelObject non const as can be regularized as part of build
+    */
+    int addCols(CoinModel & modelObject);
+
+#if 0
+    /** */
+    virtual void addCols(const CoinPackedMatrix& matrix,
+			 const double* collb, const double* colub,   
+			 const double* obj);
+#endif
+
+    /** \brief Remove a set of columns (primal variables) from the
+	       problem.
+
+      The solver interface for a basis-oriented solver will maintain valid
+      warm start information if all deleted variables are nonbasic.
+    */
+    virtual void deleteCols(const int num, const int * colIndices) = 0;
+  
+    /*! \brief Add a row (constraint) to the problem. */
+    virtual void addRow(const CoinPackedVectorBase& vec,
+			const double rowlb, const double rowub) = 0;
+
+    /*! \brief Add a named row (constraint) to the problem.
+    
+      The default implementation adds the row, then changes the name. This
+      can surely be made more efficient within an OsiXXX class.
+    */
+    virtual void addRow(const CoinPackedVectorBase& vec,
+			const double rowlb, const double rowub,
+			std::string name) ;
+
+    /*! \brief Add a row (constraint) to the problem. */
+    virtual void addRow(const CoinPackedVectorBase& vec,
+			const char rowsen, const double rowrhs,   
+			const double rowrng) = 0;
+
+    /*! \brief Add a named row (constraint) to the problem.
+
+      The default implementation adds the row, then changes the name. This
+      can surely be made more efficient within an OsiXXX class.
+    */
+    virtual void addRow(const CoinPackedVectorBase& vec,
+			const char rowsen, const double rowrhs,   
+			const double rowrng, std::string name) ;
+
+    /*! Add a row (constraint) to the problem.
+    
+      Converts to addRow(CoinPackedVectorBase&,const double,const double).
+    */
+    virtual void addRow(int numberElements,
+			const int *columns, const double *element,
+			const double rowlb, const double rowub) ;
+
+    /*! Add a set of rows (constraints) to the problem.
+    
+      The default implementation simply makes repeated calls to
+      addRow().
+    */
+    virtual void addRows(const int numrows,
+			 const CoinPackedVectorBase * const * rows,
+			 const double* rowlb, const double* rowub);
+
+    /** Add a set of rows (constraints) to the problem.
+    
+      The default implementation simply makes repeated calls to
+      addRow().
+    */
+    virtual void addRows(const int numrows,
+			 const CoinPackedVectorBase * const * rows,
+			 const char* rowsen, const double* rowrhs,   
+			 const double* rowrng);
+
+    /** Add a set of rows (constraints) to the problem.
+    
+      The default implementation simply makes repeated calls to
+      addRow().
+    */
+    virtual void addRows(const int numrows, const int *rowStarts,
+			 const int *columns, const double *element,
+			 const double *rowlb, const double *rowub);
+
+    /// Add rows using a CoinBuild object
+    void addRows(const CoinBuild &buildObject);
+
+    /*! Add rows from a CoinModel object.
+    
+      Returns -1 if the object is in the wrong state (<i>i.e.</i>, has
+      column-major information), otherwise the number of errors.
+
+      The modelObject is not const as it can be regularized as part of
+      the build.
+    */
+    int addRows(CoinModel &modelObject);
+
+#if 0
+    /** */
+    virtual void addRows(const CoinPackedMatrix& matrix,
+			 const double* rowlb, const double* rowub);
+    /** */
+    virtual void addRows(const CoinPackedMatrix& matrix,
+			 const char* rowsen, const double* rowrhs,   
+			 const double* rowrng);
+#endif
+
+    /** \brief Delete a set of rows (constraints) from the problem.
+
+      The solver interface for a basis-oriented solver will maintain valid
+      warm start information if all deleted rows are loose.
+    */
+    virtual void deleteRows(const int num, const int * rowIndices) = 0;
+
+    /** \brief Replace the constraint matrix
+
+      I (JJF) am getting annoyed because I can't just replace a matrix.
+      The default behavior of this is do nothing so only use where that would
+      not matter, e.g. strengthening a matrix for MIP.
+    */
+    virtual void replaceMatrixOptional(const CoinPackedMatrix & ) {}
+
+    /** \brief Replace the constraint matrix
+    
+      And if it does matter (not used at present)
+    */
+    virtual void replaceMatrix(const CoinPackedMatrix & ) {abort();}
+
+    /** \brief Save a copy of the base model
+    
+      If solver wants it can save a copy of "base" (continuous) model here.
+    */
+    virtual void saveBaseModel() {}
+
+    /** \brief Reduce the constraint system to the specified number of
+    	       constraints.
+
+       If solver wants it can restore a copy of "base" (continuous) model
+       here.
+
+       \note
+       The name is somewhat misleading. Implementors should consider
+       the opportunity to optimise behaviour in the common case where
+       \p numberRows is exactly the number of original constraints. Do not,
+       however, neglect the possibility that \p numberRows does not equal
+       the number of original constraints.
+     */
+    virtual void restoreBaseModel(int numberRows);
+    //-----------------------------------------------------------------------
+    /** Apply a collection of cuts.
+
+	Only cuts which have an <code>effectiveness >= effectivenessLb</code>
+	are applied.
+	<ul>
+	  <li> ReturnCode.getNumineffective() -- number of cuts which were
+	       not applied because they had an
+	       <code>effectiveness < effectivenessLb</code>
+	  <li> ReturnCode.getNuminconsistent() -- number of invalid cuts
+	  <li> ReturnCode.getNuminconsistentWrtIntegerModel() -- number of
+	       cuts that are invalid with respect to this integer model
+	  <li> ReturnCode.getNuminfeasible() -- number of cuts that would
+	       make this integer model infeasible
+	  <li> ReturnCode.getNumApplied() -- number of integer cuts which
+	       were applied to the integer model
+	  <li> cs.size() == getNumineffective() +
+			    getNuminconsistent() +
+			    getNuminconsistentWrtIntegerModel() +
+			    getNuminfeasible() +
+			    getNumApplied()
+	</ul>
+    */
+    virtual ApplyCutsReturnCode applyCuts(const OsiCuts & cs,
+					  double effectivenessLb = 0.0);
+
+    /** Apply a collection of row cuts which are all effective.
+	applyCuts seems to do one at a time which seems inefficient.
+	Would be even more efficient to pass an array of pointers.
+    */
+    virtual void applyRowCuts(int numberCuts, const OsiRowCut * cuts);
+
+    /** Apply a collection of row cuts which are all effective.
+	This is passed in as an array of pointers.
+    */
+    virtual void applyRowCuts(int numberCuts, const OsiRowCut ** cuts);
+
+    /// Deletes branching information before columns deleted
+    void deleteBranchingInfo(int numberDeleted, const int * which);
+
+  //@}
+
+  //---------------------------------------------------------------------------
+
+  /**@name Methods for problem input and output */
+  //@{
+    /*! \brief Load in a problem by copying the arguments. The constraints on
+	    the rows are given by lower and upper bounds.
+	
+	If a pointer is 0 then the following values are the default:
+        <ul>
+          <li> <code>colub</code>: all columns have upper bound infinity
+          <li> <code>collb</code>: all columns have lower bound 0 
+          <li> <code>rowub</code>: all rows have upper bound infinity
+          <li> <code>rowlb</code>: all rows have lower bound -infinity
+	  <li> <code>obj</code>: all variables have 0 objective coefficient
+        </ul>
+
+	Note that the default values for rowub and rowlb produce the
+	constraint -infty <= ax <= infty. This is probably not what you want.
+    */
+    virtual void loadProblem (const CoinPackedMatrix& matrix,
+			      const double* collb, const double* colub,   
+			      const double* obj,
+			      const double* rowlb, const double* rowub) = 0;
+			    
+    /*! \brief Load in a problem by assuming ownership of the arguments.
+	    The constraints on the rows are given by lower and upper bounds.
+
+	For default argument values see the matching loadProblem method.
+
+	\warning
+	The arguments passed to this method will be freed using the
+	C++ <code>delete</code> and <code>delete[]</code> functions. 
+    */
+    virtual void assignProblem (CoinPackedMatrix*& matrix,
+			        double*& collb, double*& colub, double*& obj,
+			        double*& rowlb, double*& rowub) = 0;
+
+    /*! \brief Load in a problem by copying the arguments.
+	    The constraints on the rows are given by sense/rhs/range triplets.
+	    
+	If a pointer is 0 then the following values are the default:
+	<ul>
+          <li> <code>colub</code>: all columns have upper bound infinity
+          <li> <code>collb</code>: all columns have lower bound 0 
+	  <li> <code>obj</code>: all variables have 0 objective coefficient
+          <li> <code>rowsen</code>: all rows are >=
+          <li> <code>rowrhs</code>: all right hand sides are 0
+          <li> <code>rowrng</code>: 0 for the ranged rows
+        </ul>
+
+	Note that the default values for rowsen, rowrhs, and rowrng produce the
+	constraint ax >= 0.
+    */
+    virtual void loadProblem (const CoinPackedMatrix& matrix,
+			      const double* collb, const double* colub,
+			      const double* obj,
+			      const char* rowsen, const double* rowrhs,   
+			      const double* rowrng) = 0;
+
+    /*! \brief Load in a problem by assuming ownership of the arguments.
+	    The constraints on the rows are given by sense/rhs/range triplets.
+	
+	For default argument values see the matching loadProblem method.
+
+	\warning
+	The arguments passed to this method will be freed using the
+	C++ <code>delete</code> and <code>delete[]</code> functions. 
+    */
+    virtual void assignProblem (CoinPackedMatrix*& matrix,
+			        double*& collb, double*& colub, double*& obj,
+			        char*& rowsen, double*& rowrhs,
+			        double*& rowrng) = 0;
+
+    /*! \brief Load in a problem by copying the arguments. The constraint
+	    matrix is is specified with standard column-major
+	    column starts / row indices / coefficients vectors. 
+	    The constraints on the rows are given by lower and upper bounds.
+    
+      The matrix vectors must be gap-free. Note that <code>start</code> must
+      have <code>numcols+1</code> entries so that the length of the last column
+      can be calculated as <code>start[numcols]-start[numcols-1]</code>.
+
+      See the previous loadProblem method using rowlb and rowub for default
+      argument values.
+    */
+    virtual void loadProblem (const int numcols, const int numrows,
+			      const CoinBigIndex * start, const int* index,
+			      const double* value,
+			      const double* collb, const double* colub,   
+			      const double* obj,
+			      const double* rowlb, const double* rowub) = 0;
+
+    /*! \brief Load in a problem by copying the arguments. The constraint
+	    matrix is is specified with standard column-major
+	    column starts / row indices / coefficients vectors. 
+	    The constraints on the rows are given by sense/rhs/range triplets.
+    
+      The matrix vectors must be gap-free. Note that <code>start</code> must
+      have <code>numcols+1</code> entries so that the length of the last column
+      can be calculated as <code>start[numcols]-start[numcols-1]</code>.
+
+      See the previous loadProblem method using sense/rhs/range for default
+      argument values.
+    */
+    virtual void loadProblem (const int numcols, const int numrows,
+			      const CoinBigIndex * start, const int* index,
+			      const double* value,
+			      const double* collb, const double* colub,   
+			      const double* obj,
+			      const char* rowsen, const double* rowrhs,   
+  			      const double* rowrng) = 0;
+
+    /*! \brief Load a model from a CoinModel object. Return the number of
+	    errors encountered.
+
+      The modelObject parameter cannot be const as it may be changed as part
+      of process. If keepSolution is true will try and keep warmStart.
+    */
+    virtual int loadFromCoinModel (CoinModel & modelObject,
+				   bool keepSolution=false);
+
+    /*! \brief Read a problem in MPS format from the given filename.
+    
+      The default implementation uses CoinMpsIO::readMps() to read
+      the MPS file and returns the number of errors encountered.
+    */
+    virtual int readMps (const char *filename,
+			 const char *extension = "mps") ;
+
+    /*! \brief Read a problem in MPS format from the given full filename.
+    
+      This uses CoinMpsIO::readMps() to read the MPS file and returns the
+      number of errors encountered. It also may return an array of set
+      information
+    */
+    virtual int readMps (const char *filename, const char*extension,
+			int & numberSets, CoinSet ** & sets);
+
+    /*! \brief Read a problem in GMPL format from the given filenames.
+    
+      The default implementation uses CoinMpsIO::readGMPL(). This capability
+      is available only if the third-party package Glpk is installed.
+    */
+    virtual int readGMPL (const char *filename, const char *dataname=NULL);
+
+    /*! \brief Write the problem in MPS format to the specified file.
+
+      If objSense is non-zero, a value of -1.0 causes the problem to be
+      written with a maximization objective; +1.0 forces a minimization
+      objective. If objSense is zero, the choice is left to the implementation.
+    */
+    virtual void writeMps (const char *filename,
+			   const char *extension = "mps",
+			   double objSense=0.0) const = 0;
+
+    /*! \brief Write the problem in MPS format to the specified file with
+	    more control over the output.
+
+	Row and column names may be null.
+	formatType is
+	<ul>
+	  <li> 0 - normal
+	  <li> 1 - extra accuracy 
+	  <li> 2 - IEEE hex
+	</ul>
+
+	Returns non-zero on I/O error
+    */
+    int writeMpsNative (const char *filename, 
+		        const char ** rowNames, const char ** columnNames,
+		        int formatType=0,int numberAcross=2,
+		        double objSense=0.0, int numberSOS=0,
+		        const CoinSet * setInfo=NULL) const ;
+
+/***********************************************************************/
+// Lp files 
+
+  /** Write the problem into an Lp file of the given filename with the 
+      specified extension.
+      Coefficients with value less than epsilon away from an integer value
+      are written as integers.
+      Write at most numberAcross monomials on a line.
+      Write non integer numbers with decimals digits after the decimal point.
+
+      The written problem is always a minimization problem.
+      If the current problem is a maximization problem, the 
+      intended objective function for the written problem is the current
+      objective function multiplied by -1. If the current problem is a
+      minimization problem, the intended objective function for the
+      written problem is the current objective function.
+      If objSense < 0, the intended objective function is multiplied by -1
+      before writing the problem. It is left unchanged otherwise.
+
+      Write objective function name and constraint names if useRowNames is 
+      true. This version calls writeLpNative().
+  */
+  virtual void writeLp(const char *filename,
+               const char *extension = "lp",
+                double epsilon = 1e-5,
+                int numberAcross = 10,
+                int decimals = 5,
+                double objSense = 0.0,
+	        bool useRowNames = true) const;
+
+  /** Write the problem into the file pointed to by the parameter fp. 
+      Other parameters are similar to 
+      those of writeLp() with first parameter filename.
+  */
+  virtual void writeLp(FILE *fp,
+                double epsilon = 1e-5,
+                int numberAcross = 10,
+                int decimals = 5,
+                double objSense = 0.0,
+	        bool useRowNames = true) const;
+
+  /** Write the problem into an Lp file. Parameters are similar to 
+      those of writeLp(), but in addition row names and column names
+      may be given. 
+
+      Parameter rowNames may be NULL, in which case default row names 
+      are used. If rowNames is not NULL, it must have exactly one entry
+      per row in the problem and one additional
+      entry (rowNames[getNumRows()] with the objective function name.
+      These getNumRows()+1 entries must be distinct. If this is not the 
+      case, default row names
+      are used. In addition, format restrictions are imposed on names
+      (see CoinLpIO::is_invalid_name() for details).
+
+      Similar remarks can be made for the parameter columnNames which
+      must either be NULL or have exactly getNumCols() distinct entries.
+
+      Write objective function name and constraint names if 
+      useRowNames is true. */
+  int writeLpNative(const char *filename,
+		    char const * const * const rowNames,
+		    char const * const * const columnNames,
+		    const double epsilon = 1.0e-5,
+                    const int numberAcross = 10,
+                    const int decimals = 5,
+                    const double objSense = 0.0,
+		    const bool useRowNames = true) const;
+
+  /** Write the problem into the file pointed to by the parameter fp. 
+      Other parameters are similar to 
+      those of writeLpNative() with first parameter filename.
+  */
+  int writeLpNative(FILE *fp,
+		    char const * const * const rowNames,
+		    char const * const * const columnNames,
+		    const double epsilon = 1.0e-5,
+                    const int numberAcross = 10,
+                    const int decimals = 5,
+                    const double objSense = 0.0,
+		    const bool useRowNames = true) const;
+
+  /// Read file in LP format from file with name filename. 
+  /// See class CoinLpIO for description of this format.
+  virtual int readLp(const char *filename, const double epsilon = 1e-5);
+
+  /// Read file in LP format from the file pointed to by fp. 
+  /// See class CoinLpIO for description of this format.
+  int readLp(FILE *fp, const double epsilon = 1e-5);
+
+  //@}
+
+  //---------------------------------------------------------------------------
+
+  /**@name Miscellaneous */
+  //@{
+#ifdef COIN_SNAPSHOT
+  /// Return a CoinSnapshot
+  virtual CoinSnapshot * snapshot(bool createArrays=true) const;
+#endif
+#ifdef COIN_FACTORIZATION_INFO
+  /// Return number of entries in L part of current factorization
+  virtual CoinBigIndex getSizeL() const;
+  /// Return number of entries in U part of current factorization
+  virtual CoinBigIndex getSizeU() const;
+#endif
+  //@}
+
+  //---------------------------------------------------------------------------
+
+  /**@name Setting/Accessing application data */
+  //@{
+    /** Set application data.
+
+	This is a pointer that the application can store into and
+	retrieve from the solver interface.
+	This field is available for the application to optionally
+	define and use.
+    */
+    void setApplicationData (void * appData);
+    /** Create a clone of an Auxiliary Information object.
+        The base class just stores an application data pointer
+        but can be more general.  Application data pointer is
+        designed for one user while this can be extended to cope
+        with more general extensions.
+    */
+    void setAuxiliaryInfo(OsiAuxInfo * auxiliaryInfo);
+
+    /// Get application data
+    void * getApplicationData() const;
+    /// Get pointer to auxiliary info object
+    OsiAuxInfo * getAuxiliaryInfo() const;
+  //@}
+  //---------------------------------------------------------------------------
+
+  /**@name Message handling
+  
+    See the COIN library documentation for additional information about
+    COIN message facilities.
+  
+  */
+  //@{
+  /** Pass in a message handler
+  
+    It is the client's responsibility to destroy a message handler installed
+    by this routine; it will not be destroyed when the solver interface is
+    destroyed. 
+  */
+  virtual void passInMessageHandler(CoinMessageHandler * handler);
+  /// Set language
+  void newLanguage(CoinMessages::Language language);
+  inline void setLanguage(CoinMessages::Language language)
+  {newLanguage(language);}
+  /// Return a pointer to the current message handler
+  inline CoinMessageHandler * messageHandler() const
+  {return handler_;}
+  /// Return the current set of messages
+  inline CoinMessages messages() 
+  {return messages_;}
+  /// Return a pointer to the current set of messages
+  inline CoinMessages * messagesPointer() 
+  {return &messages_;}
+  /// Return true if default handler
+  inline bool defaultHandler() const
+  { return defaultHandler_;}
+  //@}
+  //---------------------------------------------------------------------------
+  /**@name Methods for dealing with discontinuities other than integers.
+  
+     Osi should be able to know about SOS and other types.  This is an optional
+     section where such information can be stored.
+
+  */
+  //@{
+    /** \brief Identify integer variables and create corresponding objects.
+  
+      Record integer variables and create an OsiSimpleInteger object for each
+      one.  All existing OsiSimpleInteger objects will be destroyed.
+      If justCount then no objects created and we just store numberIntegers_
+    */
+
+    void findIntegers(bool justCount);
+    /** \brief Identify integer variables and SOS and create corresponding objects.
+  
+      Record integer variables and create an OsiSimpleInteger object for each
+      one.  All existing OsiSimpleInteger objects will be destroyed.
+      If the solver supports SOS then do the same for SOS.
+
+      If justCount then no objects created and we just store numberIntegers_
+      Returns number of SOS
+    */
+
+    virtual int findIntegersAndSOS(bool justCount);
+    /// Get the number of objects
+    inline int numberObjects() const { return numberObjects_;}
+    /// Set the number of objects
+    inline void setNumberObjects(int number) 
+    {  numberObjects_=number;}
+
+    /// Get the array of objects
+    inline OsiObject ** objects() const { return object_;}
+
+    /// Get the specified object
+    const inline OsiObject * object(int which) const { return object_[which];}
+    /// Get the specified object
+    inline OsiObject * modifiableObject(int which) const { return object_[which];}
+
+    /// Delete all object information
+    void deleteObjects();
+
+    /** Add in object information.
+  
+      Objects are cloned; the owner can delete the originals.
+    */
+    void addObjects(int numberObjects, OsiObject ** objects);
+    /** Use current solution to set bounds so current integer feasible solution will stay feasible.
+        Only feasible bounds will be used, even if current solution outside bounds.  The amount of
+        such violation will be returned (and if small can be ignored)
+    */
+    double forceFeasible();
+  //@}
+  //---------------------------------------------------------------------------
+
+  /*! @name Methods related to testing generated cuts
+  
+    See the documentation for OsiRowCutDebugger for additional details.
+  */
+  //@{
+    /*! \brief Activate the row cut debugger.
+
+      If \p modelName is in the set of known models then all cuts are
+      checked to see that they do NOT cut off the optimal solution known
+      to the debugger.
+    */
+    virtual void activateRowCutDebugger (const char *modelName);
+
+    /*! \brief Activate the row cut debugger using a full solution array.
+
+
+      Activate the debugger for a model not included in the debugger's
+      internal database.  Cuts will be checked to see that they do NOT
+      cut off the given solution.
+
+      \p solution must be a full solution vector, but only the integer
+      variables need to be correct. The debugger will fill in the continuous
+      variables by solving an lp relaxation with the integer variables
+      fixed as specified. If the given values for the continuous variables
+      should be preserved, set \p keepContinuous to true.
+    */
+    virtual void activateRowCutDebugger(const double *solution,
+    					bool enforceOptimality = true);
+
+    /*! \brief Get the row cut debugger provided the solution known to the
+    	       debugger is within the feasible region held in the solver.
+
+      If there is a row cut debugger object associated with model AND if
+      the solution known to the debugger is within the solver's current
+      feasible region (i.e., the column bounds held in the solver are
+      compatible with the known solution) then a pointer to the debugger
+      is returned which may be used to test validity of cuts.
+
+      Otherwise NULL is returned
+    */
+    const OsiRowCutDebugger *getRowCutDebugger() const;
+
+    /*! \brief Get the row cut debugger object
+
+      Return the row cut debugger object if it exists. One common usage of
+      this method is to obtain a debugger object in order to execute
+      OsiRowCutDebugger::redoSolution (so that the stored solution is again
+      compatible with the problem held in the solver).
+    */
+    OsiRowCutDebugger * getRowCutDebuggerAlways() const;
+  //@} 
+  
+  /*! \name OsiSimplexInterface
+      \brief Simplex Interface
+
+    Methods for an advanced interface to a simplex solver. The interface
+    comprises two groups of methods. Group 1 contains methods for tableau
+    access. Group 2 contains methods for dictating individual simplex pivots.
+  */
+  //@{
+
+  /*! \brief Return the simplex implementation level.
+  
+      The return codes are:
+      - 0: the simplex interface is not implemented.
+      - 1: the Group 1 (tableau access) methods are implemented.
+      - 2: the Group 2 (pivoting) methods are implemented
+
+      The codes are cumulative - a solver which implements Group 2 also
+      implements Group 1.
+  */
+  virtual int canDoSimplexInterface() const ;
+  //@}
+
+  /*! \name OsiSimplex Group 1
+      \brief Tableau access methods.
+
+      This group of methods provides access to rows and columns of the basis
+      inverse and to rows and columns of the tableau.
+  */
+  //@{
+
+  /*! \brief Prepare the solver for the use of tableau access methods.
+  
+    Prepares the solver for the use of the tableau access methods, if
+    any such preparation is required.
+
+    The \c const attribute is required due to the places this method
+    may be called (e.g., within CglCutGenerator::generateCuts()).
+  */
+  virtual void enableFactorization() const ;
+
+  /*! \brief Undo the effects of #enableFactorization. */
+  virtual void disableFactorization() const ;
+
+  /*! \brief Check if an optimal basis is available.
+  
+    Returns true if the problem has been solved to optimality and a
+    basis is available. This should be used to see if the tableau access
+    operations are possible and meaningful.
+    
+    \note
+    Implementors please note that this method may be called
+    before #enableFactorization.
+  */
+  virtual bool basisIsAvailable() const ;
+
+  /// Synonym for #basisIsAvailable
+  inline bool optimalBasisIsAvailable() const { return basisIsAvailable() ; }
+
+  /*! \brief Retrieve status information for column and row variables.
+ 
+    This method returns status as integer codes:
+    <ul>
+      <li> 0: free
+      <li> 1: basic
+      <li> 2: nonbasic at upper bound
+      <li> 3: nonbasic at lower bound
+    </ul>
+
+    The #getWarmStart method provides essentially the same functionality
+    for a simplex-oriented solver, but the implementation details are very
+    different.
+
+    \note
+    Logical variables associated with rows are all assumed to have +1
+    coefficients, so for a <= constraint the logical will be at lower
+    bound if the constraint is tight.
+
+    \note
+    Implementors may choose to implement this method as a wrapper which
+    converts a CoinWarmStartBasis to the requested representation.
+  */
+  virtual void getBasisStatus(int* cstat, int* rstat) const ;
+
+  /*! \brief Set the status of column and row variables and update
+             the basis factorization and solution.
+
+    Status information should be coded as documented for #getBasisStatus.
+    Returns 0 if all goes well, 1 if something goes wrong.
+
+    This method differs from #setWarmStart in the format of the input
+    and in its immediate effect. Think of it as #setWarmStart immediately
+    followed by #resolve, but no pivots are allowed.
+
+    \note
+    Implementors may choose to implement this method as a wrapper that calls
+    #setWarmStart and #resolve if the no pivot requirement can be satisfied.
+  */
+  virtual int setBasisStatus(const int* cstat, const int* rstat) ;
+
+  /*! \brief Calculate duals and reduced costs for the given objective
+	     coefficients.
+
+    The solver's objective coefficient vector is not changed.
+  */
+  virtual void getReducedGradient(double* columnReducedCosts, 
+				  double* duals, const double* c) const ;
+
+  /*! \brief Get a row of the tableau
+  
+    If \p slack is not null, it will be loaded with the coefficients for
+    the artificial (logical) variables (i.e., the row of the basis inverse).
+  */
+  virtual void getBInvARow(int row, double* z, double* slack = NULL) const ;
+
+  /*! \brief Get a row of the basis inverse */
+  virtual void getBInvRow(int row, double* z) const ;
+
+  /*! \brief Get a column of the tableau */
+  virtual void getBInvACol(int col, double* vec) const ;
+
+  /*! \brief Get a column of the basis inverse */
+  virtual void getBInvCol(int col, double* vec) const ;
+
+  /*! \brief Get indices of basic variables
+  
+    If the logical (artificial) for row i is basic, the index should be coded
+    as (#getNumCols + i).
+    The order of indices must match the order of elements in the vectors
+    returned by #getBInvACol and #getBInvCol.
+  */
+  virtual void getBasics(int* index) const ;
+
+  //@}
+
+  /*! \name OsiSimplex Group 2
+      \brief Pivoting methods
+
+      This group of methods provides for control of individual pivots by a
+      simplex solver.
+  */
+  //@{
+
+  /**Enables normal operation of subsequent functions.
+     This method is supposed to ensure that all typical things (like
+     reduced costs, etc.) are updated when individual pivots are executed
+     and can be queried by other methods.  says whether will be
+     doing primal or dual
+  */
+  virtual void enableSimplexInterface(bool doingPrimal) ;
+
+  ///Undo whatever setting changes the above method had to make
+  virtual void disableSimplexInterface() ;
+  /** Perform a pivot by substituting a colIn for colOut in the basis. 
+     The status of the leaving variable is given in outStatus. Where
+     1 is to upper bound, -1 to lower bound
+     Return code was undefined - now for OsiClp is 0 for okay,
+     1 if inaccuracy forced re-factorization (should be okay) and
+     -1 for singular factorization
+  */
+  virtual int pivot(int colIn, int colOut, int outStatus) ;
+
+  /** Obtain a result of the primal pivot 
+      Outputs: colOut -- leaving column, outStatus -- its status,
+      t -- step size, and, if dx!=NULL, *dx -- primal ray direction.
+      Inputs: colIn -- entering column, sign -- direction of its change (+/-1).
+      Both for colIn and colOut, artificial variables are index by
+      the negative of the row index minus 1.
+      Return code (for now): 0 -- leaving variable found, 
+      -1 -- everything else?
+      Clearly, more informative set of return values is required 
+      Primal and dual solutions are updated
+  */
+  virtual int primalPivotResult(int colIn, int sign, 
+				int& colOut, int& outStatus, 
+				double& t, CoinPackedVector* dx);
+
+  /** Obtain a result of the dual pivot (similar to the previous method)
+      Differences: entering variable and a sign of its change are now
+      the outputs, the leaving variable and its statuts -- the inputs
+      If dx!=NULL, then *dx contains dual ray
+      Return code: same
+  */
+  virtual int dualPivotResult(int& colIn, int& sign, 
+			      int colOut, int outStatus, 
+			      double& t, CoinPackedVector* dx) ;
+  //@}
+   
+  //---------------------------------------------------------------------------
+
+  ///@name Constructors and destructors
+  //@{
+    /// Default Constructor
+    OsiSolverInterface(); 
+    
+    /** Clone
+
+      The result of calling clone(false) is defined to be equivalent to
+      calling the default constructor OsiSolverInterface().
+    */
+    virtual OsiSolverInterface * clone(bool copyData = true) const = 0;
+  
+    /// Copy constructor 
+    OsiSolverInterface(const OsiSolverInterface &);
+  
+    /// Assignment operator 
+    OsiSolverInterface & operator=(const OsiSolverInterface& rhs);
+  
+    /// Destructor 
+    virtual ~OsiSolverInterface ();
+
+    /** Reset the solver interface.
+
+    A call to reset() returns the solver interface to the same state as
+    it would have if it had just been constructed by calling the default
+    constructor OsiSolverInterface().
+    */
+    virtual void reset();
+  //@}
+
+  //---------------------------------------------------------------------------
+
+protected:
+  ///@name Protected methods
+  //@{
+    /** Apply a row cut (append to the constraint matrix). */
+    virtual void applyRowCut( const OsiRowCut & rc ) = 0;
+
+    /** Apply a column cut (adjust the bounds of one or more variables). */
+    virtual void applyColCut( const OsiColCut & cc ) = 0;
+
+    /** A quick inlined function to convert from the lb/ub style of
+	constraint definition to the sense/rhs/range style */
+    inline void
+    convertBoundToSense(const double lower, const double upper,
+			char& sense, double& right, double& range) const;
+    /** A quick inlined function to convert from the sense/rhs/range style
+	of constraint definition to the lb/ub style */
+    inline void
+    convertSenseToBound(const char sense, const double right,
+			const double range,
+			double& lower, double& upper) const;
+    /** A quick inlined function to force a value to be between a minimum and
+	a maximum value */
+    template <class T> inline T
+    forceIntoRange(const T value, const T lower, const T upper) const {
+      return value < lower ? lower : (value > upper ? upper : value);
+    }
+    /** Set OsiSolverInterface object state for default constructor
+
+      This routine establishes the initial values of data fields in the
+      OsiSolverInterface object when the object is created using the
+      default constructor.
+    */
+    void setInitialData();
+  //@}
+
+  ///@name Protected member data
+  //@{
+    /*! \brief Pointer to row cut debugger object
+
+      Mutable so that we can update the solution held in the debugger while
+      maintaining const'ness for the Osi object.
+    */
+    mutable OsiRowCutDebugger * rowCutDebugger_;
+   // Why not just make useful stuff protected?
+   /// Message handler
+  CoinMessageHandler * handler_;
+  /** Flag to say if the currrent handler is the default handler.
+      Indicates if the solver interface object is responsible
+      for destruction of the handler (true) or if the client is
+      responsible (false).
+  */
+  bool defaultHandler_;
+  /// Messages
+  CoinMessages messages_;
+  /// Number of integers
+  int numberIntegers_;
+  /// Total number of objects
+  int numberObjects_;
+
+  /// Integer and ... information (integer info normally at beginning)
+  OsiObject ** object_;
+  /** Column type
+      0 - continuous
+      1 - binary (may get fixed later)
+      2 - general integer (may get fixed later)
+  */
+  mutable char * columnType_;
+
+  //@}
+  
+  //---------------------------------------------------------------------------
+
+private:
+  ///@name Private member data 
+  //@{
+    /// Pointer to user-defined data structure - and more if user wants
+    OsiAuxInfo * appDataEtc_;
+    /// Array of integer parameters
+    int intParam_[OsiLastIntParam];
+    /// Array of double parameters
+    double dblParam_[OsiLastDblParam];
+    /// Array of string parameters
+    std::string strParam_[OsiLastStrParam];
+    /// Array of hint parameters
+    bool hintParam_[OsiLastHintParam];
+    /// Array of hint strengths
+    OsiHintStrength hintStrength_[OsiLastHintParam];
+    /** Warm start information used for hot starts when the default
+       hot start implementation is used. */
+    CoinWarmStart* ws_;
+    /// Column solution satisfying lower and upper column bounds
+    std::vector<double> strictColSolution_;
+
+    /// Row names
+    OsiNameVec rowNames_ ;
+    /// Column names
+    OsiNameVec colNames_ ;
+    /// Objective name
+    std::string objName_ ;
+
+ //@}
+};
+
+//#############################################################################
+/** A quick inlined function to convert from the lb/ub style of constraint
+    definition to the sense/rhs/range style */
+inline void
+OsiSolverInterface::convertBoundToSense(const double lower, const double upper,
+					char& sense, double& right,
+					double& range) const
+{
+  double inf = getInfinity();
+  range = 0.0;
+  if (lower > -inf) {
+    if (upper < inf) {
+      right = upper;
+      if (upper==lower) {
+        sense = 'E';
+      } else {
+        sense = 'R';
+        range = upper - lower;
+      }
+    } else {
+      sense = 'G';
+      right = lower;
+    }
+  } else {
+    if (upper < inf) {
+      sense = 'L';
+      right = upper;
+    } else {
+      sense = 'N';
+      right = 0.0;
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+/** A quick inlined function to convert from the sense/rhs/range style of
+    constraint definition to the lb/ub style */
+inline void
+OsiSolverInterface::convertSenseToBound(const char sense, const double right,
+					const double range,
+					double& lower, double& upper) const
+{
+  double inf=getInfinity();
+  switch (sense) {
+  case 'E':
+    lower = upper = right;
+    break;
+  case 'L':
+    lower = -inf;
+    upper = right;
+    break;
+  case 'G':
+    lower = right;
+    upper = inf;
+    break;
+  case 'R':
+    lower = right - range;
+    upper = right;
+    break;
+  case 'N':
+    lower = -inf;
+    upper = inf;
+    break;
+  }
+}
+
+#endif
diff --git a/cbits/coin/OsiSolverParameters.hpp b/cbits/coin/OsiSolverParameters.hpp
new file mode 100644
--- /dev/null
+++ b/cbits/coin/OsiSolverParameters.hpp
@@ -0,0 +1,142 @@
+// Copyright (C) 2000, International Business Machines
+// Corporation and others.  All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+#ifndef OsiSolverParameters_H
+#define OsiSolverParameters_H
+
+enum OsiIntParam {
+  /*! \brief Iteration limit for initial solve and resolve.
+  
+    The maximum number of iterations (whatever that means for the given
+    solver) the solver can execute in the OsiSolverinterface::initialSolve()
+    and OsiSolverinterface::resolve() methods before terminating.
+  */
+  OsiMaxNumIteration = 0,
+  /*! \brief Iteration limit for hot start
+  
+    The maximum number of iterations (whatever that means for the given
+    solver) the solver can execute in the
+    OsiSolverinterface::solveFromHotStart() method before terminating.
+  */
+  OsiMaxNumIterationHotStart,
+  /*! \brief Handling of row and column names.
+  
+    The name discipline specifies how the solver will handle row and column
+    names:
+    - 0: Auto names: Names cannot be set by the client. Names of the form
+	 Rnnnnnnn or Cnnnnnnn are generated on demand when a name for a
+	 specific row or column is requested; nnnnnnn is derived from the row
+	 or column index. Requests for a vector of names return a vector with
+	 zero entries.
+    - 1: Lazy names: Names supplied by the client are retained. Names of the
+	 form Rnnnnnnn or Cnnnnnnn are generated on demand if no name has been
+	 supplied by the client. Requests for a vector of names return a
+	 vector sized to the largest index of a name supplied by the client;
+	 some entries in the vector may be null strings.
+    - 2: Full names: Names supplied by the client are retained. Names of the
+	 form Rnnnnnnn or Cnnnnnnn are generated on demand if no name has been
+	 supplied by the client. Requests for a vector of names return a
+	 vector sized to match the constraint system, and all entries will
+	 contain either the name specified by the client or a generated name.
+  */
+  OsiNameDiscipline,
+  /*! \brief End marker.
+  
+    Used by OsiSolverInterface to allocate a fixed-sized array to store
+    integer parameters.
+  */
+  OsiLastIntParam
+} ;
+
+enum OsiDblParam {
+  /*! \brief Dual objective limit.
+  
+    This is to be used as a termination criteria in algorithms where the dual
+    objective changes monotonically (e.g., dual simplex, volume algorithm).
+  */
+  OsiDualObjectiveLimit = 0,
+  /*! \brief Primal objective limit.
+  
+    This is to be used as a termination criteria in algorithms where the
+    primal objective changes monotonically (e.g., primal simplex)
+  */
+  OsiPrimalObjectiveLimit,
+  /*! \brief Dual feasibility tolerance.
+  
+    The maximum amount a dual constraint can be violated and still be
+    considered feasible.
+  */
+  OsiDualTolerance,
+  /*! \brief Primal feasibility tolerance.
+  
+    The maximum amount a primal constraint can be violated and still be
+    considered feasible.
+  */
+  OsiPrimalTolerance,
+  /** The value of any constant term in the objective function. */
+  OsiObjOffset,
+  /*! \brief End marker.
+  
+    Used by OsiSolverInterface to allocate a fixed-sized array to store
+    double parameters.
+  */
+  OsiLastDblParam
+};
+
+
+enum OsiStrParam {
+  /*! \brief The name of the loaded problem.
+  
+    This is the string specified on the Name card of an mps file.
+  */
+  OsiProbName = 0,
+  /*! \brief The name of the solver.
+  
+    This parameter is read-only.
+  */
+  OsiSolverName,
+  /*! \brief End marker.
+  
+    Used by OsiSolverInterface to allocate a fixed-sized array to store
+    string parameters.
+  */
+  OsiLastStrParam
+};
+
+enum OsiHintParam {
+  /** Whether to do a presolve in initialSolve */
+  OsiDoPresolveInInitial = 0,
+  /** Whether to use a dual algorithm in initialSolve.
+      The reverse is to use a primal algorithm */
+  OsiDoDualInInitial,
+  /** Whether to do a presolve in resolve */
+  OsiDoPresolveInResolve,
+  /** Whether to use a dual algorithm in resolve.
+      The reverse is to use a primal algorithm */
+  OsiDoDualInResolve,
+  /** Whether to scale problem */
+  OsiDoScale,
+  /** Whether to create a non-slack basis (only in initialSolve) */
+  OsiDoCrash,
+  /** Whether to reduce amount of printout, e.g., for branch and cut */
+  OsiDoReducePrint,
+  /** Whether we are in branch and cut - so can modify behavior */
+  OsiDoInBranchAndCut,
+  /** Just a marker, so that OsiSolverInterface can allocate a static sized
+      array to store parameters. */
+  OsiLastHintParam
+};
+
+enum OsiHintStrength {
+  /** Ignore hint (default) */
+  OsiHintIgnore = 0,
+  /** This means it is only a hint */
+  OsiHintTry,
+  /** This means do hint if at all possible */
+  OsiHintDo,
+  /** And this means throw an exception if not possible */
+  OsiForceDo
+};
+
+#endif
diff --git a/cbits/coin/config_cbc_default.h b/cbits/coin/config_cbc_default.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/config_cbc_default.h
@@ -0,0 +1,17 @@
+
+/***************************************************************************/
+/*           HERE DEFINE THE PROJECT SPECIFIC PUBLIC MACROS                */
+/*    These are only in effect in a setting that doesn't use configure     */
+/***************************************************************************/
+
+/* Version number of project */
+#define CBC_VERSION "2.8.6"
+
+/* Major Version number of project */
+#define CBC_VERSION_MAJOR 2
+
+/* Minor Version number of project */
+#define CBC_VERSION_MINOR 8
+
+/* Release Version number of project */
+#define CBC_VERSION_RELEASE 6
diff --git a/cbits/coin/config_cgl_default.h b/cbits/coin/config_cgl_default.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/config_cgl_default.h
@@ -0,0 +1,17 @@
+
+/***************************************************************************/
+/*           HERE DEFINE THE PROJECT SPECIFIC PUBLIC MACROS                */
+/*    These are only in effect in a setting that doesn't use configure     */
+/***************************************************************************/
+
+/* Version number of project */
+#define CGL_VERSION "0.58.3"
+
+/* Major Version number of project */
+#define CGL_VERSION_MAJOR 0
+
+/* Minor Version number of project */
+#define CGL_VERSION_MINOR 58
+
+/* Release Version number of project */
+#define CGL_VERSION_RELEASE 3
diff --git a/cbits/coin/config_clp_default.h b/cbits/coin/config_clp_default.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/config_clp_default.h
@@ -0,0 +1,17 @@
+
+/***************************************************************************/
+/*           HERE DEFINE THE PROJECT SPECIFIC PUBLIC MACROS                */
+/*    These are only in effect in a setting that doesn't use configure     */
+/***************************************************************************/
+
+/* Version number of project */
+#define CLP_VERSION "1.15.4"
+
+/* Major Version number of project */
+#define CLP_VERSION_MAJOR 1
+
+/* Minor Version number of project */
+#define CLP_VERSION_MINOR 15
+
+/* Release Version number of project */
+#define CLP_VERSION_RELEASE 4
diff --git a/cbits/coin/config_coinutils_default.h b/cbits/coin/config_coinutils_default.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/config_coinutils_default.h
@@ -0,0 +1,39 @@
+
+/***************************************************************************/
+/*           HERE DEFINE THE PROJECT SPECIFIC PUBLIC MACROS                */
+/*    These are only in effect in a setting that doesn't use configure     */
+/***************************************************************************/
+
+/* Version number of project */
+#define COINUTILS_VERSION "2.9.8"
+
+/* Major Version number of project */
+#define COINUTILS_VERSION_MAJOR 2
+
+/* Minor Version number of project */
+#define COINUTILS_VERSION_MINOR 9
+
+/* Release Version number of project */
+#define COINUTILS_VERSION_RELEASE 8
+
+/*
+  Define to 64bit integer types. Note that MS does not provide __uint64.
+
+  Microsoft defines types in BaseTsd.h, part of the Windows SDK. Given
+  that this file only gets used in the Visual Studio environment, it
+  seems to me we'll be better off simply including it and using the
+  types MS defines. But since I have no idea of history here, I'll leave
+  all of this inside the guard for MSC_VER >= 1200. If you're reading this
+  and have been developing in MSVS long enough to know, fix it.  -- lh, 100915 --
+*/
+#if _MSC_VER >= 1200
+# include <BaseTsd.h>
+# define COIN_INT64_T INT64
+# define COIN_UINT64_T UINT64
+  /* Define to integer type capturing pointer */
+# define COIN_INTPTR_T ULONG_PTR
+#else
+# define COIN_INT64_T long long
+# define COIN_UINT64_T unsigned long long
+# define COIN_INTPTR_T int*
+#endif
diff --git a/cbits/coin/config_osi_default.h b/cbits/coin/config_osi_default.h
new file mode 100644
--- /dev/null
+++ b/cbits/coin/config_osi_default.h
@@ -0,0 +1,17 @@
+
+/***************************************************************************/
+/*           HERE DEFINE THE PROJECT SPECIFIC PUBLIC MACROS                */
+/*    These are only in effect in a setting that doesn't use configure     */
+/***************************************************************************/
+
+/* Version number of project */
+#define OSI_VERSION "0.106.3"
+
+/* Major Version number of project */
+#define OSI_VERSION_MAJOR 0
+
+/* Minor Version number of project */
+#define OSI_VERSION_MINOR 106
+
+/* Release Version number of project */
+#define OSI_VERSION_RELEASE 3
diff --git a/limp-cbc.cabal b/limp-cbc.cabal
--- a/limp-cbc.cabal
+++ b/limp-cbc.cabal
@@ -1,5 +1,5 @@
 name:                limp-cbc
-version:             0.3.1.0
+version:             0.3.2.0
 synopsis:            bindings for integer linear programming solver Coin/CBC
 description:         very simple binding to external solver, CBC.
                      CBC is somewhat faster than GLPK, and also has a more permissive licence.
@@ -14,11 +14,259 @@
 cabal-version:       >=1.10
 homepage:            https://github.com/amosr/limp-cbc
 
+extra-source-files:
+  cbits/Cbc.h
+  cbits/coin/Cbc_ampl.h
+  cbits/coin/Cbc_C_Interface.h
+  cbits/coin/CbcConfig.h
+  cbits/coin/CglConfig.h
+  cbits/coin/Clp_C_Interface.h
+  cbits/coin/ClpConfig.h
+  cbits/coin/Coin_C_defines.h
+  cbits/coin/CoinOslC.h
+  cbits/coin/CoinUtilsConfig.h
+  cbits/coin/config_cbc_default.h
+  cbits/coin/config_cgl_default.h
+  cbits/coin/config_clp_default.h
+  cbits/coin/config_coinutils_default.h
+  cbits/coin/config_osi_default.h
+  cbits/coin/OsiConfig.h
+  cbits/coin/AbcCommon.hpp
+  cbits/coin/CbcBranchActual.hpp
+  cbits/coin/CbcBranchAllDifferent.hpp
+  cbits/coin/CbcBranchBase.hpp
+  cbits/coin/CbcBranchCut.hpp
+  cbits/coin/CbcBranchDecision.hpp
+  cbits/coin/CbcBranchDefaultDecision.hpp
+  cbits/coin/CbcBranchDynamic.hpp
+  cbits/coin/CbcBranchingObject.hpp
+  cbits/coin/CbcBranchLotsize.hpp
+  cbits/coin/CbcBranchToFixLots.hpp
+  cbits/coin/CbcClique.hpp
+  cbits/coin/CbcCompare.hpp
+  cbits/coin/CbcCompareActual.hpp
+  cbits/coin/CbcCompareBase.hpp
+  cbits/coin/CbcCompareDefault.hpp
+  cbits/coin/CbcCompareDepth.hpp
+  cbits/coin/CbcCompareEstimate.hpp
+  cbits/coin/CbcCompareObjective.hpp
+  cbits/coin/CbcConsequence.hpp
+  cbits/coin/CbcCountRowCut.hpp
+  cbits/coin/CbcCutGenerator.hpp
+  cbits/coin/CbcCutModifier.hpp
+  cbits/coin/CbcCutSubsetModifier.hpp
+  cbits/coin/CbcDummyBranchingObject.hpp
+  cbits/coin/CbcEventHandler.hpp
+  cbits/coin/CbcFathom.hpp
+  cbits/coin/CbcFathomDynamicProgramming.hpp
+  cbits/coin/CbcFeasibilityBase.hpp
+  cbits/coin/CbcFixVariable.hpp
+  cbits/coin/CbcFollowOn.hpp
+  cbits/coin/CbcFullNodeInfo.hpp
+  cbits/coin/CbcGeneral.hpp
+  cbits/coin/CbcGeneralDepth.hpp
+  cbits/coin/CbcHeuristic.hpp
+  cbits/coin/CbcHeuristicDINS.hpp
+  cbits/coin/CbcHeuristicDive.hpp
+  cbits/coin/CbcHeuristicDiveCoefficient.hpp
+  cbits/coin/CbcHeuristicDiveFractional.hpp
+  cbits/coin/CbcHeuristicDiveGuided.hpp
+  cbits/coin/CbcHeuristicDiveLineSearch.hpp
+  cbits/coin/CbcHeuristicDivePseudoCost.hpp
+  cbits/coin/CbcHeuristicDiveVectorLength.hpp
+  cbits/coin/CbcHeuristicFPump.hpp
+  cbits/coin/CbcHeuristicGreedy.hpp
+  cbits/coin/CbcHeuristicLocal.hpp
+  cbits/coin/CbcHeuristicPivotAndFix.hpp
+  cbits/coin/CbcHeuristicRandRound.hpp
+  cbits/coin/CbcHeuristicRENS.hpp
+  cbits/coin/CbcHeuristicRINS.hpp
+  cbits/coin/CbcHeuristicVND.hpp
+  cbits/coin/CbcLinked.hpp
+  cbits/coin/CbcMessage.hpp
+  cbits/coin/CbcMipStartIO.hpp
+  cbits/coin/CbcModel.hpp
+  cbits/coin/CbcNode.hpp
+  cbits/coin/CbcNodeInfo.hpp
+  cbits/coin/CbcNWay.hpp
+  cbits/coin/CbcObject.hpp
+  cbits/coin/CbcObjectUpdateData.hpp
+  cbits/coin/CbcOrClpParam.hpp
+  cbits/coin/CbcOrClpParam.cpp
+  cbits/coin/CbcPartialNodeInfo.hpp
+  cbits/coin/CbcSimpleInteger.hpp
+  cbits/coin/CbcSimpleIntegerDynamicPseudoCost.hpp
+  cbits/coin/CbcSimpleIntegerPseudoCost.hpp
+  cbits/coin/CbcSolver.hpp
+  cbits/coin/CbcSolverAnalyze.hpp
+  cbits/coin/CbcSolverExpandKnapsack.hpp
+  cbits/coin/CbcSolverHeuristics.hpp
+  cbits/coin/CbcSOS.hpp
+  cbits/coin/CbcStatistics.hpp
+  cbits/coin/CbcStrategy.hpp
+  cbits/coin/CbcSubProblem.hpp
+  cbits/coin/CbcThread.hpp
+  cbits/coin/CbcTree.hpp
+  cbits/coin/CbcTreeLocal.hpp
+  cbits/coin/Cgl012cut.hpp
+  cbits/coin/CglAllDifferent.hpp
+  cbits/coin/CglClique.hpp
+  cbits/coin/CglCutGenerator.hpp
+  cbits/coin/CglDuplicateRow.hpp
+  cbits/coin/CglFlowCover.hpp
+  cbits/coin/CglGMI.hpp
+  cbits/coin/CglGMIParam.hpp
+  cbits/coin/CglGomory.hpp
+  cbits/coin/CglKnapsackCover.hpp
+  cbits/coin/CglLandP.hpp
+  cbits/coin/CglLandPMessages.hpp
+  cbits/coin/CglLandPSimplex.hpp
+  cbits/coin/CglLandPTabRow.hpp
+  cbits/coin/CglLandPUtils.hpp
+  cbits/coin/CglLandPValidator.hpp
+  cbits/coin/CglLiftAndProject.hpp
+  cbits/coin/CglMessage.hpp
+  cbits/coin/CglMixedIntegerRounding.hpp
+  cbits/coin/CglMixedIntegerRounding2.hpp
+  cbits/coin/CglOddHole.hpp
+  cbits/coin/CglParam.hpp
+  cbits/coin/CglPreProcess.hpp
+  cbits/coin/CglProbing.hpp
+  cbits/coin/CglRedSplit.hpp
+  cbits/coin/CglRedSplit2.hpp
+  cbits/coin/CglRedSplit2Param.hpp
+  cbits/coin/CglRedSplitParam.hpp
+  cbits/coin/CglResidualCapacity.hpp
+  cbits/coin/CglSimpleRounding.hpp
+  cbits/coin/CglStored.hpp
+  cbits/coin/CglTreeInfo.hpp
+  cbits/coin/CglTwomir.hpp
+  cbits/coin/CglZeroHalf.hpp
+  cbits/coin/ClpCholeskyBase.hpp
+  cbits/coin/ClpCholeskyDense.hpp
+  cbits/coin/ClpCholeskyWssmp.hpp
+  cbits/coin/ClpConstraint.hpp
+  cbits/coin/ClpConstraintLinear.hpp
+  cbits/coin/ClpConstraintQuadratic.hpp
+  cbits/coin/ClpDualRowDantzig.hpp
+  cbits/coin/ClpDualRowPivot.hpp
+  cbits/coin/ClpDualRowSteepest.hpp
+  cbits/coin/ClpDummyMatrix.hpp
+  cbits/coin/ClpDynamicExampleMatrix.hpp
+  cbits/coin/ClpDynamicMatrix.hpp
+  cbits/coin/ClpEventHandler.hpp
+  cbits/coin/ClpFactorization.hpp
+  cbits/coin/ClpGubDynamicMatrix.hpp
+  cbits/coin/ClpGubMatrix.hpp
+  cbits/coin/ClpHelperFunctions.hpp
+  cbits/coin/ClpInterior.hpp
+  cbits/coin/ClpLinearObjective.hpp
+  cbits/coin/ClpLsqr.hpp
+  cbits/coin/ClpMatrixBase.hpp
+  cbits/coin/ClpMessage.hpp
+  cbits/coin/ClpModel.hpp
+  cbits/coin/ClpNetworkBasis.hpp
+  cbits/coin/ClpNetworkMatrix.hpp
+  cbits/coin/ClpNode.hpp
+  cbits/coin/ClpNonLinearCost.hpp
+  cbits/coin/ClpObjective.hpp
+  cbits/coin/ClpPackedMatrix.hpp
+  cbits/coin/ClpParameters.hpp
+  cbits/coin/ClpPdco.hpp
+  cbits/coin/ClpPdcoBase.hpp
+  cbits/coin/ClpPlusMinusOneMatrix.hpp
+  cbits/coin/ClpPredictorCorrector.hpp
+  cbits/coin/ClpPresolve.hpp
+  cbits/coin/ClpPrimalColumnDantzig.hpp
+  cbits/coin/ClpPrimalColumnPivot.hpp
+  cbits/coin/ClpPrimalColumnSteepest.hpp
+  cbits/coin/ClpQuadraticObjective.hpp
+  cbits/coin/ClpSimplex.hpp
+  cbits/coin/ClpSimplexDual.hpp
+  cbits/coin/ClpSimplexNonlinear.hpp
+  cbits/coin/ClpSimplexOther.hpp
+  cbits/coin/ClpSimplexPrimal.hpp
+  cbits/coin/ClpSolve.hpp
+  cbits/coin/CoinAlloc.hpp
+  cbits/coin/CoinBuild.hpp
+  cbits/coin/CoinDenseFactorization.hpp
+  cbits/coin/CoinDenseVector.hpp
+  cbits/coin/CoinDistance.hpp
+  cbits/coin/CoinError.hpp
+  cbits/coin/CoinFactorization.hpp
+  cbits/coin/CoinFileIO.hpp
+  cbits/coin/CoinFinite.hpp
+  cbits/coin/CoinFloatEqual.hpp
+  cbits/coin/CoinHelperFunctions.hpp
+  cbits/coin/CoinIndexedVector.hpp
+  cbits/coin/CoinLpIO.hpp
+  cbits/coin/CoinMessage.hpp
+  cbits/coin/CoinMessageHandler.hpp
+  cbits/coin/CoinModel.hpp
+  cbits/coin/CoinModelUseful.hpp
+  cbits/coin/CoinMpsIO.hpp
+  cbits/coin/CoinOslFactorization.hpp
+  cbits/coin/CoinPackedMatrix.hpp
+  cbits/coin/CoinPackedVector.hpp
+  cbits/coin/CoinPackedVectorBase.hpp
+  cbits/coin/CoinParam.hpp
+  cbits/coin/CoinPragma.hpp
+  cbits/coin/CoinPresolveDoubleton.hpp
+  cbits/coin/CoinPresolveDual.hpp
+  cbits/coin/CoinPresolveDupcol.hpp
+  cbits/coin/CoinPresolveEmpty.hpp
+  cbits/coin/CoinPresolveFixed.hpp
+  cbits/coin/CoinPresolveForcing.hpp
+  cbits/coin/CoinPresolveImpliedFree.hpp
+  cbits/coin/CoinPresolveIsolated.hpp
+  cbits/coin/CoinPresolveMatrix.hpp
+  cbits/coin/CoinPresolveMonitor.hpp
+  cbits/coin/CoinPresolvePsdebug.hpp
+  cbits/coin/CoinPresolveSingleton.hpp
+  cbits/coin/CoinPresolveSubst.hpp
+  cbits/coin/CoinPresolveTighten.hpp
+  cbits/coin/CoinPresolveTripleton.hpp
+  cbits/coin/CoinPresolveUseless.hpp
+  cbits/coin/CoinPresolveZeros.hpp
+  cbits/coin/CoinSearchTree.hpp
+  cbits/coin/CoinShallowPackedVector.hpp
+  cbits/coin/CoinSignal.hpp
+  cbits/coin/CoinSimpFactorization.hpp
+  cbits/coin/CoinSnapshot.hpp
+  cbits/coin/CoinSort.hpp
+  cbits/coin/CoinStructuredModel.hpp
+  cbits/coin/CoinTime.hpp
+  cbits/coin/CoinTypes.hpp
+  cbits/coin/CoinWarmStart.hpp
+  cbits/coin/CoinWarmStartBasis.hpp
+  cbits/coin/CoinWarmStartDual.hpp
+  cbits/coin/CoinWarmStartPrimalDual.hpp
+  cbits/coin/CoinWarmStartVector.hpp
+  cbits/coin/Idiot.hpp
+  cbits/coin/OsiAuxInfo.hpp
+  cbits/coin/OsiBranchingObject.hpp
+  cbits/coin/OsiCbcSolverInterface.hpp
+  cbits/coin/OsiChooseVariable.hpp
+  cbits/coin/OsiClpSolverInterface.hpp
+  cbits/coin/OsiColCut.hpp
+  cbits/coin/OsiCollections.hpp
+  cbits/coin/OsiCut.hpp
+  cbits/coin/OsiCuts.hpp
+  cbits/coin/OsiPresolve.hpp
+  cbits/coin/OsiRowCut.hpp
+  cbits/coin/OsiRowCutDebugger.hpp
+  cbits/coin/OsiSolverBranch.hpp
+  cbits/coin/OsiSolverInterface.hpp
+  cbits/coin/OsiSolverParameters.hpp
 
 source-repository head
     type: git
     location: git://github.com/amosr/limp-cbc.git
 
+flag embedded
+  description: Use the embedded Coin/CBC solver instead of linking to the installed one.
+  default:     True
+
 library
   hs-source-dirs: src
   exposed-modules:
@@ -27,14 +275,14 @@
         Numeric.Limp.Solvers.Cbc.Error
         Numeric.Limp.Solvers.Cbc.MatrixRepr
 
-  other-modules:       
+  other-modules:
         Numeric.Limp.Solvers.Cbc.Internal.Foreign
         Numeric.Limp.Solvers.Cbc.Internal.Wrapper
   build-depends:
         base        < 5,
         containers  == 0.5.*,
         vector      == 0.10.*,
-        limp        == 0.3.1.*
+        limp        == 0.3.2.*
 
   ghc-options: -Wall -fno-warn-orphans
   default-language: Haskell2010
@@ -42,11 +290,242 @@
 
   build-tools:      c2hs
 
-  extra-libraries:  Cbc Clp CbcSolver Cgl Osi OsiCbc OsiClp OsiCommonTests CoinUtils CoinMP stdc++
-  Include-dirs:     cbits
-  includes:         Cbc.h coin/Cbc_C_Interface.h
-  C-sources:        cbits/Cbc.cpp
-  install-includes: cbits/Cbc.h
+  if !flag(embedded)
+    extra-libraries:  Cbc Clp CbcSolver Cgl Osi OsiCbc OsiClp OsiCommonTests CoinUtils CoinMP stdc++
+    include-dirs:     cbits
+    includes:         Cbc.h
+  else
+    extra-libraries:  stdc++
+    include-dirs:     cbits, cbits/coin
+    includes:         Cbc.h
+    cc-options:       -w -DCOIN_HAS_CLP=1 -DHAVE_CMATH=1 -DHAVE_CFLOAT=1
+
+    c-sources:
+      cbits/Cbc.cpp
+      cbits/coin/Cbc_ampl.cpp
+      cbits/coin/Cbc_C_Interface.cpp
+      cbits/coin/CbcBranchAllDifferent.cpp
+      cbits/coin/CbcBranchCut.cpp
+      cbits/coin/CbcBranchDecision.cpp
+      cbits/coin/CbcBranchDefaultDecision.cpp
+      cbits/coin/CbcBranchDynamic.cpp
+      cbits/coin/CbcBranchingObject.cpp
+      cbits/coin/CbcBranchLotsize.cpp
+      cbits/coin/CbcBranchToFixLots.cpp
+      cbits/coin/CbcCbcParam.cpp
+      cbits/coin/CbcClique.cpp
+      cbits/coin/CbcCompareDefault.cpp
+      cbits/coin/CbcCompareDepth.cpp
+      cbits/coin/CbcCompareEstimate.cpp
+      cbits/coin/CbcCompareObjective.cpp
+      cbits/coin/CbcConsequence.cpp
+      cbits/coin/CbcCountRowCut.cpp
+      cbits/coin/CbcCutGenerator.cpp
+      cbits/coin/CbcCutModifier.cpp
+      cbits/coin/CbcCutSubsetModifier.cpp
+      cbits/coin/CbcDummyBranchingObject.cpp
+      cbits/coin/CbcEventHandler.cpp
+      cbits/coin/CbcFathom.cpp
+      cbits/coin/CbcFathomDynamicProgramming.cpp
+      cbits/coin/CbcFixVariable.cpp
+      cbits/coin/CbcFollowOn.cpp
+      cbits/coin/CbcFullNodeInfo.cpp
+      cbits/coin/CbcGeneral.cpp
+      cbits/coin/CbcGeneralDepth.cpp
+      cbits/coin/CbcHeuristic.cpp
+      cbits/coin/CbcHeuristicDINS.cpp
+      cbits/coin/CbcHeuristicDive.cpp
+      cbits/coin/CbcHeuristicDiveCoefficient.cpp
+      cbits/coin/CbcHeuristicDiveFractional.cpp
+      cbits/coin/CbcHeuristicDiveGuided.cpp
+      cbits/coin/CbcHeuristicDiveLineSearch.cpp
+      cbits/coin/CbcHeuristicDivePseudoCost.cpp
+      cbits/coin/CbcHeuristicDiveVectorLength.cpp
+      cbits/coin/CbcHeuristicFPump.cpp
+      cbits/coin/CbcHeuristicGreedy.cpp
+      cbits/coin/CbcHeuristicLocal.cpp
+      cbits/coin/CbcHeuristicPivotAndFix.cpp
+      cbits/coin/CbcHeuristicRandRound.cpp
+      cbits/coin/CbcHeuristicRENS.cpp
+      cbits/coin/CbcHeuristicRINS.cpp
+      cbits/coin/CbcHeuristicVND.cpp
+      cbits/coin/CbcLinked.cpp
+      cbits/coin/CbcLinkedUtils.cpp
+      cbits/coin/CbcMessage.cpp
+      cbits/coin/CbcMipStartIO.cpp
+      cbits/coin/CbcModel.cpp
+      cbits/coin/CbcNode.cpp
+      cbits/coin/CbcNodeInfo.cpp
+      cbits/coin/CbcNWay.cpp
+      cbits/coin/CbcObject.cpp
+      cbits/coin/CbcObjectUpdateData.cpp
+      cbits/coin/CbcPartialNodeInfo.cpp
+      cbits/coin/CbcSimpleInteger.cpp
+      cbits/coin/CbcSimpleIntegerDynamicPseudoCost.cpp
+      cbits/coin/CbcSimpleIntegerPseudoCost.cpp
+      cbits/coin/CbcSolver.cpp
+      cbits/coin/CbcSolverAnalyze.cpp
+      cbits/coin/CbcSolverExpandKnapsack.cpp
+      cbits/coin/CbcSolverHeuristics.cpp
+      cbits/coin/CbcSOS.cpp
+      cbits/coin/CbcStatistics.cpp
+      cbits/coin/CbcStrategy.cpp
+      cbits/coin/CbcSubProblem.cpp
+      cbits/coin/CbcThread.cpp
+      cbits/coin/CbcTree.cpp
+      cbits/coin/CbcTreeLocal.cpp
+      cbits/coin/Cgl012cut.cpp
+      cbits/coin/CglAllDifferent.cpp
+      cbits/coin/CglClique.cpp
+      cbits/coin/CglCliqueHelper.cpp
+      cbits/coin/CglCutGenerator.cpp
+      cbits/coin/CglDuplicateRow.cpp
+      cbits/coin/CglFlowCover.cpp
+      cbits/coin/CglGMI.cpp
+      cbits/coin/CglGMIParam.cpp
+      cbits/coin/CglGomory.cpp
+      cbits/coin/CglKnapsackCover.cpp
+      cbits/coin/CglLandP.cpp
+      cbits/coin/CglLandPMessages.cpp
+      cbits/coin/CglLandPSimplex.cpp
+      cbits/coin/CglLandPTabRow.cpp
+      cbits/coin/CglLandPTest.cpp
+      cbits/coin/CglLandPUtils.cpp
+      cbits/coin/CglLandPValidator.cpp
+      cbits/coin/CglLiftAndProject.cpp
+      cbits/coin/CglMessage.cpp
+      cbits/coin/CglMixedIntegerRounding.cpp
+      cbits/coin/CglMixedIntegerRounding2.cpp
+      cbits/coin/CglOddHole.cpp
+      cbits/coin/CglParam.cpp
+      cbits/coin/CglPreProcess.cpp
+      cbits/coin/CglProbing.cpp
+      cbits/coin/CglRedSplit.cpp
+      cbits/coin/CglRedSplit2.cpp
+      cbits/coin/CglRedSplit2Param.cpp
+      cbits/coin/CglRedSplitParam.cpp
+      cbits/coin/CglResidualCapacity.cpp
+      cbits/coin/CglSimpleRounding.cpp
+      cbits/coin/CglStored.cpp
+      cbits/coin/CglTreeInfo.cpp
+      cbits/coin/CglTwomir.cpp
+      cbits/coin/CglZeroHalf.cpp
+      cbits/coin/Clp_C_Interface.cpp
+      cbits/coin/ClpCholeskyBase.cpp
+      cbits/coin/ClpCholeskyDense.cpp
+      cbits/coin/ClpConstraint.cpp
+      cbits/coin/ClpConstraintLinear.cpp
+      cbits/coin/ClpConstraintQuadratic.cpp
+      cbits/coin/ClpDualRowDantzig.cpp
+      cbits/coin/ClpDualRowPivot.cpp
+      cbits/coin/ClpDualRowSteepest.cpp
+      cbits/coin/ClpDummyMatrix.cpp
+      cbits/coin/ClpDynamicExampleMatrix.cpp
+      cbits/coin/ClpDynamicMatrix.cpp
+      cbits/coin/ClpEventHandler.cpp
+      cbits/coin/ClpFactorization.cpp
+      cbits/coin/ClpGubDynamicMatrix.cpp
+      cbits/coin/ClpGubMatrix.cpp
+      cbits/coin/ClpHelperFunctions.cpp
+      cbits/coin/ClpInterior.cpp
+      cbits/coin/ClpLinearObjective.cpp
+      cbits/coin/ClpLsqr.cpp
+      cbits/coin/ClpMatrixBase.cpp
+      cbits/coin/ClpMessage.cpp
+      cbits/coin/ClpModel.cpp
+      cbits/coin/ClpNetworkBasis.cpp
+      cbits/coin/ClpNetworkMatrix.cpp
+      cbits/coin/ClpNode.cpp
+      cbits/coin/ClpNonLinearCost.cpp
+      cbits/coin/ClpObjective.cpp
+      cbits/coin/ClpPackedMatrix.cpp
+      cbits/coin/ClpPdco.cpp
+      cbits/coin/ClpPdcoBase.cpp
+      cbits/coin/ClpPlusMinusOneMatrix.cpp
+      cbits/coin/ClpPredictorCorrector.cpp
+      cbits/coin/ClpPresolve.cpp
+      cbits/coin/ClpPrimalColumnDantzig.cpp
+      cbits/coin/ClpPrimalColumnPivot.cpp
+      cbits/coin/ClpPrimalColumnSteepest.cpp
+      cbits/coin/ClpQuadraticObjective.cpp
+      cbits/coin/ClpSimplex.cpp
+      cbits/coin/ClpSimplexDual.cpp
+      cbits/coin/ClpSimplexNonlinear.cpp
+      cbits/coin/ClpSimplexOther.cpp
+      cbits/coin/ClpSimplexPrimal.cpp
+      cbits/coin/ClpSolve.cpp
+      cbits/coin/CoinAlloc.cpp
+      cbits/coin/CoinBuild.cpp
+      cbits/coin/CoinDenseFactorization.cpp
+      cbits/coin/CoinDenseVector.cpp
+      cbits/coin/CoinError.cpp
+      cbits/coin/CoinFactorization1.cpp
+      cbits/coin/CoinFactorization2.cpp
+      cbits/coin/CoinFactorization3.cpp
+      cbits/coin/CoinFactorization4.cpp
+      cbits/coin/CoinFileIO.cpp
+      cbits/coin/CoinFinite.cpp
+      cbits/coin/CoinIndexedVector.cpp
+      cbits/coin/CoinLpIO.cpp
+      cbits/coin/CoinMessage.cpp
+      cbits/coin/CoinMessageHandler.cpp
+      cbits/coin/CoinModel.cpp
+      cbits/coin/CoinModelUseful.cpp
+      cbits/coin/CoinModelUseful2.cpp
+      cbits/coin/CoinMpsIO.cpp
+      cbits/coin/CoinOslFactorization.cpp
+      cbits/coin/CoinOslFactorization2.cpp
+      cbits/coin/CoinOslFactorization3.cpp
+      cbits/coin/CoinPackedMatrix.cpp
+      cbits/coin/CoinPackedVector.cpp
+      cbits/coin/CoinPackedVectorBase.cpp
+      cbits/coin/CoinParam.cpp
+      cbits/coin/CoinParamUtils.cpp
+      cbits/coin/CoinPostsolveMatrix.cpp
+      cbits/coin/CoinPrePostsolveMatrix.cpp
+      cbits/coin/CoinPresolveDoubleton.cpp
+      cbits/coin/CoinPresolveDual.cpp
+      cbits/coin/CoinPresolveDupcol.cpp
+      cbits/coin/CoinPresolveEmpty.cpp
+      cbits/coin/CoinPresolveFixed.cpp
+      cbits/coin/CoinPresolveForcing.cpp
+      cbits/coin/CoinPresolveHelperFunctions.cpp
+      cbits/coin/CoinPresolveImpliedFree.cpp
+      cbits/coin/CoinPresolveIsolated.cpp
+      cbits/coin/CoinPresolveMatrix.cpp
+      cbits/coin/CoinPresolveMonitor.cpp
+      cbits/coin/CoinPresolvePsdebug.cpp
+      cbits/coin/CoinPresolveSingleton.cpp
+      cbits/coin/CoinPresolveSubst.cpp
+      cbits/coin/CoinPresolveTighten.cpp
+      cbits/coin/CoinPresolveTripleton.cpp
+      cbits/coin/CoinPresolveUseless.cpp
+      cbits/coin/CoinPresolveZeros.cpp
+      cbits/coin/CoinSearchTree.cpp
+      cbits/coin/CoinShallowPackedVector.cpp
+      cbits/coin/CoinSimpFactorization.cpp
+      cbits/coin/CoinSnapshot.cpp
+      cbits/coin/CoinStructuredModel.cpp
+      cbits/coin/CoinWarmStartBasis.cpp
+      cbits/coin/CoinWarmStartDual.cpp
+      cbits/coin/CoinWarmStartPrimalDual.cpp
+      cbits/coin/CoinWarmStartVector.cpp
+      cbits/coin/Idiot.cpp
+      cbits/coin/IdiSolve.cpp
+      cbits/coin/OsiAuxInfo.cpp
+      cbits/coin/OsiBranchingObject.cpp
+      cbits/coin/OsiCbcSolverInterface.cpp
+      cbits/coin/OsiChooseVariable.cpp
+      cbits/coin/OsiClpSolverInterface.cpp
+      cbits/coin/OsiColCut.cpp
+      cbits/coin/OsiCut.cpp
+      cbits/coin/OsiCuts.cpp
+      cbits/coin/OsiNames.cpp
+      cbits/coin/OsiPresolve.cpp
+      cbits/coin/OsiRowCut.cpp
+      cbits/coin/OsiRowCutDebugger.cpp
+      cbits/coin/OsiSolverBranch.cpp
+      cbits/coin/OsiSolverInterface.cpp
 
 test-suite test
   type:     exitcode-stdio-1.0
